summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordim <dim@FreeBSD.org>2013-04-08 18:45:10 +0000
committerdim <dim@FreeBSD.org>2013-04-08 18:45:10 +0000
commitc72c57c9e9b69944e3e009cd5e209634839581d3 (patch)
tree4fc2f184c499d106f29a386c452b49e5197bf63d
parent5b20025c30d23d521e12c1f33ec8fa6b821952cd (diff)
downloadFreeBSD-src-c72c57c9e9b69944e3e009cd5e209634839581d3.zip
FreeBSD-src-c72c57c9e9b69944e3e009cd5e209634839581d3.tar.gz
Vendor import of clang trunk r178860:
http://llvm.org/svn/llvm-project/cfe/trunk@178860
-rw-r--r--.arcconfig4
-rw-r--r--.gitignore3
-rw-r--r--CMakeLists.txt27
-rw-r--r--CODE_OWNERS.TXT40
-rw-r--r--INSTALL.txt2
-rw-r--r--LICENSE.TXT2
-rw-r--r--NOTES.txt3
-rw-r--r--bindings/python/clang/cindex.py74
-rw-r--r--bindings/python/tests/cindex/test_cursor.py9
-rw-r--r--bindings/python/tests/cindex/test_translation_unit.py17
-rw-r--r--bindings/xml/comment-xml-schema.rng55
-rw-r--r--docs/AddressSanitizer.html171
-rw-r--r--docs/AddressSanitizer.rst163
-rw-r--r--docs/AnalyzerRegions.html260
-rw-r--r--docs/AutomaticReferenceCounting.html2226
-rw-r--r--docs/AutomaticReferenceCounting.rst2283
-rw-r--r--docs/Block-ABI-Apple.rst935
-rw-r--r--docs/Block-ABI-Apple.txt670
-rw-r--r--docs/BlockLanguageSpec.rst361
-rw-r--r--docs/BlockLanguageSpec.txt171
-rw-r--r--docs/ClangCheck.rst36
-rw-r--r--docs/ClangFormat.rst93
-rw-r--r--docs/ClangPlugins.html170
-rw-r--r--docs/ClangPlugins.rst150
-rw-r--r--docs/ClangTools.html110
-rw-r--r--docs/ClangTools.rst152
-rw-r--r--docs/DriverInternals.html523
-rw-r--r--docs/DriverInternals.rst400
-rw-r--r--docs/ExternalClangExamples.rst80
-rw-r--r--docs/FAQ.rst64
-rw-r--r--docs/HowToSetupToolingForLLVM.html212
-rw-r--r--docs/HowToSetupToolingForLLVM.rst199
-rw-r--r--docs/InternalsManual.html2019
-rw-r--r--docs/InternalsManual.rst1810
-rw-r--r--docs/IntroductionToTheClangAST.html139
-rw-r--r--docs/IntroductionToTheClangAST.rst135
-rw-r--r--docs/JSONCompilationDatabase.html89
-rw-r--r--docs/JSONCompilationDatabase.rst88
-rw-r--r--docs/LanguageExtensions.html2082
-rw-r--r--docs/LanguageExtensions.rst2000
-rw-r--r--docs/LibASTMatchers.html130
-rw-r--r--docs/LibASTMatchers.rst134
-rw-r--r--docs/LibASTMatchersReference.html1704
-rw-r--r--docs/LibASTMatchersTutorial.rst538
-rw-r--r--docs/LibFormat.rst56
-rw-r--r--docs/LibTooling.html212
-rw-r--r--docs/LibTooling.rst192
-rw-r--r--docs/Makefile.sphinx163
-rw-r--r--docs/MemorySanitizer.rst178
-rw-r--r--docs/Modules.rst713
-rw-r--r--docs/ObjectiveCLiterals.html423
-rw-r--r--docs/ObjectiveCLiterals.rst554
-rw-r--r--docs/PCHInternals.html658
-rw-r--r--docs/PCHInternals.rst561
-rw-r--r--docs/PTHInternals.html179
-rw-r--r--docs/PTHInternals.rst163
-rw-r--r--docs/RAVFrontendAction.html224
-rw-r--r--docs/RAVFrontendAction.rst216
-rw-r--r--docs/README.txt1
-rw-r--r--docs/ReleaseNotes.html325
-rw-r--r--docs/ReleaseNotes.rst147
-rw-r--r--docs/ThreadSanitizer.html126
-rw-r--r--docs/ThreadSanitizer.rst126
-rw-r--r--docs/Tooling.html120
-rw-r--r--docs/Tooling.rst97
-rw-r--r--docs/UsersManual.html1309
-rw-r--r--docs/UsersManual.rst1313
-rw-r--r--docs/analyzer/DebugChecks.rst134
-rw-r--r--docs/analyzer/IPA.txt105
-rw-r--r--docs/analyzer/Makefile155
-rw-r--r--docs/analyzer/RegionStore.txt171
-rw-r--r--docs/analyzer/conf.py246
-rw-r--r--docs/analyzer/debug-checks.txt89
-rw-r--r--docs/analyzer/index.rst23
-rw-r--r--docs/analyzer/make.bat190
-rw-r--r--docs/conf.py242
-rw-r--r--docs/index.rst73
-rw-r--r--docs/make.bat190
-rw-r--r--docs/tools/dump_ast_matchers.py44
-rw-r--r--examples/PrintFunctionNames/PrintFunctionNames.cpp2
-rw-r--r--examples/analyzer-plugin/MainCallChecker.cpp4
-rw-r--r--examples/clang-interpreter/CMakeLists.txt1
-rw-r--r--examples/clang-interpreter/main.cpp20
-rw-r--r--include/clang-c/CXCompilationDatabase.h6
-rw-r--r--include/clang-c/CXString.h2
-rw-r--r--include/clang-c/Index.h165
-rw-r--r--include/clang/ARCMigrate/ARCMT.h2
-rw-r--r--include/clang/ARCMigrate/ARCMTActions.h2
-rw-r--r--include/clang/ARCMigrate/FileRemapper.h2
-rw-r--r--include/clang/AST/APValue.h2
-rw-r--r--include/clang/AST/AST.h2
-rw-r--r--include/clang/AST/ASTConsumer.h15
-rw-r--r--include/clang/AST/ASTContext.h253
-rw-r--r--include/clang/AST/ASTImporter.h3
-rw-r--r--include/clang/AST/ASTMutationListener.h9
-rw-r--r--include/clang/AST/ASTTypeTraits.h (renamed from include/clang/ASTMatchers/ASTTypeTraits.h)14
-rw-r--r--include/clang/AST/ASTUnresolvedSet.h86
-rw-r--r--include/clang/AST/ASTVector.h12
-rw-r--r--include/clang/AST/Attr.h171
-rw-r--r--include/clang/AST/AttrIterator.h142
-rw-r--r--include/clang/AST/BuiltinTypes.def14
-rw-r--r--include/clang/AST/CMakeLists.txt13
-rw-r--r--include/clang/AST/CXXInheritance.h4
-rw-r--r--include/clang/AST/CanonicalType.h69
-rw-r--r--include/clang/AST/CharUnits.h11
-rw-r--r--include/clang/AST/Comment.h87
-rw-r--r--include/clang/AST/CommentCommandTraits.h34
-rw-r--r--include/clang/AST/CommentCommands.td92
-rw-r--r--include/clang/AST/CommentHTMLNamedCharacterReferences.td177
-rw-r--r--include/clang/AST/CommentLexer.h13
-rw-r--r--include/clang/AST/CommentParser.h9
-rw-r--r--include/clang/AST/CommentSema.h31
-rw-r--r--include/clang/AST/CommentVisitor.h4
-rw-r--r--include/clang/AST/Decl.h327
-rw-r--r--include/clang/AST/DeclAccessPair.h1
-rw-r--r--include/clang/AST/DeclBase.h129
-rw-r--r--include/clang/AST/DeclCXX.h587
-rw-r--r--include/clang/AST/DeclContextInternals.h24
-rw-r--r--include/clang/AST/DeclFriend.h50
-rw-r--r--include/clang/AST/DeclLookups.h1
-rw-r--r--include/clang/AST/DeclObjC.h339
-rw-r--r--include/clang/AST/DeclOpenMP.h83
-rw-r--r--include/clang/AST/DeclTemplate.h114
-rw-r--r--include/clang/AST/DeclVisitor.h43
-rw-r--r--include/clang/AST/DeclarationName.h85
-rw-r--r--include/clang/AST/DependentDiagnostic.h22
-rw-r--r--include/clang/AST/EvaluatedExprVisitor.h23
-rw-r--r--include/clang/AST/Expr.h367
-rw-r--r--include/clang/AST/ExprCXX.h257
-rw-r--r--include/clang/AST/ExprObjC.h126
-rw-r--r--include/clang/AST/ExternalASTSource.h28
-rw-r--r--include/clang/AST/LambdaMangleContext.h4
-rw-r--r--include/clang/AST/Makefile25
-rw-r--r--include/clang/AST/Mangle.h2
-rw-r--r--include/clang/AST/NSAPI.h14
-rw-r--r--include/clang/AST/NestedNameSpecifier.h2
-rw-r--r--include/clang/AST/OperationKinds.h5
-rw-r--r--include/clang/AST/PrettyPrinter.h19
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h36
-rw-r--r--include/clang/AST/Stmt.h229
-rw-r--r--include/clang/AST/StmtCXX.h38
-rw-r--r--include/clang/AST/StmtGraphTraits.h2
-rw-r--r--include/clang/AST/StmtObjC.h37
-rw-r--r--include/clang/AST/TemplateBase.h87
-rw-r--r--include/clang/AST/TemplateName.h24
-rw-r--r--include/clang/AST/Type.h200
-rw-r--r--include/clang/AST/TypeLoc.h93
-rw-r--r--include/clang/AST/TypeLocVisitor.h2
-rw-r--r--include/clang/AST/TypeOrdering.h2
-rw-r--r--include/clang/AST/UnresolvedSet.h11
-rw-r--r--include/clang/AST/VTTBuilder.h9
-rw-r--r--include/clang/AST/VTableBuilder.h23
-rw-r--r--include/clang/ASTMatchers/ASTMatchFinder.h85
-rw-r--r--include/clang/ASTMatchers/ASTMatchers.h573
-rw-r--r--include/clang/ASTMatchers/ASTMatchersInternal.h241
-rw-r--r--include/clang/ASTMatchers/ASTMatchersMacros.h284
-rw-r--r--include/clang/Analysis/Analyses/Dominators.h7
-rw-r--r--include/clang/Analysis/Analyses/FormatString.h4
-rw-r--r--include/clang/Analysis/Analyses/LiveVariables.h2
-rw-r--r--include/clang/Analysis/Analyses/ThreadSafety.h23
-rw-r--r--include/clang/Analysis/Analyses/UninitializedValues.h5
-rw-r--r--include/clang/Analysis/AnalysisContext.h25
-rw-r--r--include/clang/Analysis/CFG.h117
-rw-r--r--include/clang/Analysis/CallGraph.h40
-rw-r--r--include/clang/Analysis/FlowSensitive/DataflowSolver.h4
-rw-r--r--include/clang/Analysis/ProgramPoint.h230
-rw-r--r--include/clang/Analysis/Support/BlkExprDeclBitVector.h2
-rw-r--r--include/clang/Analysis/Support/BumpVector.h4
-rw-r--r--include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h6
-rw-r--r--include/clang/Basic/Attr.td243
-rw-r--r--include/clang/Basic/AttrKinds.h1
-rw-r--r--include/clang/Basic/Builtins.def41
-rw-r--r--include/clang/Basic/Builtins.h6
-rw-r--r--include/clang/Basic/BuiltinsX86.def6
-rw-r--r--include/clang/Basic/CharInfo.h198
-rw-r--r--include/clang/Basic/CommentOptions.h34
-rw-r--r--include/clang/Basic/ConvertUTF.h203
-rw-r--r--include/clang/Basic/DeclNodes.td2
-rw-r--r--include/clang/Basic/Diagnostic.h34
-rw-r--r--include/clang/Basic/DiagnosticASTKinds.td6
-rw-r--r--include/clang/Basic/DiagnosticCommentKinds.td41
-rw-r--r--include/clang/Basic/DiagnosticCommonKinds.td14
-rw-r--r--include/clang/Basic/DiagnosticDriverKinds.td20
-rw-r--r--include/clang/Basic/DiagnosticFrontendKinds.td24
-rw-r--r--include/clang/Basic/DiagnosticGroups.td58
-rw-r--r--include/clang/Basic/DiagnosticIDs.h14
-rw-r--r--include/clang/Basic/DiagnosticLexKinds.td89
-rw-r--r--include/clang/Basic/DiagnosticOptions.def2
-rw-r--r--include/clang/Basic/DiagnosticOptions.h15
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td51
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td519
-rw-r--r--include/clang/Basic/DiagnosticSerializationKinds.td15
-rw-r--r--include/clang/Basic/FileManager.h18
-rw-r--r--include/clang/Basic/FileSystemStatCache.h21
-rw-r--r--include/clang/Basic/IdentifierTable.h9
-rw-r--r--include/clang/Basic/LLVM.h13
-rw-r--r--include/clang/Basic/LangOptions.def23
-rw-r--r--include/clang/Basic/LangOptions.h21
-rw-r--r--include/clang/Basic/Linkage.h8
-rw-r--r--include/clang/Basic/MacroBuilder.h1
-rw-r--r--include/clang/Basic/Module.h124
-rw-r--r--include/clang/Basic/ObjCRuntime.h16
-rw-r--r--include/clang/Basic/OnDiskHashTable.h3
-rw-r--r--include/clang/Basic/OpenMPKinds.def23
-rw-r--r--include/clang/Basic/OpenMPKinds.h37
-rw-r--r--include/clang/Basic/OperatorPrecedence.h52
-rw-r--r--include/clang/Basic/PartialDiagnostic.h24
-rw-r--r--include/clang/Basic/Sanitizers.def57
-rw-r--r--include/clang/Basic/SourceLocation.h22
-rw-r--r--include/clang/Basic/SourceManager.h158
-rw-r--r--include/clang/Basic/Specifiers.h13
-rw-r--r--include/clang/Basic/TargetCXXABI.h261
-rw-r--r--include/clang/Basic/TargetInfo.h80
-rw-r--r--include/clang/Basic/TargetOptions.h1
-rw-r--r--include/clang/Basic/TokenKinds.def92
-rw-r--r--include/clang/Basic/TokenKinds.h18
-rw-r--r--include/clang/Basic/TypeTraits.h3
-rw-r--r--include/clang/Basic/Version.h3
-rw-r--r--include/clang/Basic/VersionTuple.h8
-rw-r--r--include/clang/Basic/Visibility.h76
-rw-r--r--include/clang/CodeGen/ModuleBuilder.h2
-rw-r--r--include/clang/Driver/Arg.h7
-rw-r--r--include/clang/Driver/ArgList.h5
-rw-r--r--include/clang/Driver/CC1AsOptions.td8
-rw-r--r--include/clang/Driver/CC1Options.td47
-rw-r--r--include/clang/Driver/Compilation.h43
-rw-r--r--include/clang/Driver/Driver.h14
-rw-r--r--include/clang/Driver/Job.h2
-rw-r--r--include/clang/Driver/OptSpecifier.h4
-rw-r--r--include/clang/Driver/Option.h2
-rw-r--r--include/clang/Driver/Options.td107
-rw-r--r--include/clang/Driver/Phases.h4
-rw-r--r--include/clang/Driver/Tool.h1
-rw-r--r--include/clang/Driver/ToolChain.h36
-rw-r--r--include/clang/Driver/Types.def3
-rw-r--r--include/clang/Driver/Types.h13
-rw-r--r--include/clang/Driver/Util.h5
-rw-r--r--include/clang/Edit/Commit.h8
-rw-r--r--include/clang/Edit/EditedSource.h12
-rw-r--r--include/clang/Edit/Rewriters.h4
-rw-r--r--include/clang/Format/Format.h131
-rw-r--r--include/clang/Frontend/ASTUnit.h42
-rw-r--r--include/clang/Frontend/ChainedIncludesSource.h4
-rw-r--r--include/clang/Frontend/CodeGenOptions.def21
-rw-r--r--include/clang/Frontend/CodeGenOptions.h17
-rw-r--r--include/clang/Frontend/CompilerInstance.h52
-rw-r--r--include/clang/Frontend/CompilerInvocation.h14
-rw-r--r--include/clang/Frontend/DiagnosticRenderer.h49
-rw-r--r--include/clang/Frontend/FrontendAction.h102
-rw-r--r--include/clang/Frontend/FrontendActions.h17
-rw-r--r--include/clang/Frontend/FrontendOptions.h29
-rw-r--r--include/clang/Frontend/LangStandard.h6
-rw-r--r--include/clang/Frontend/LangStandards.def12
-rw-r--r--include/clang/Frontend/LayoutOverrideSource.h5
-rw-r--r--include/clang/Frontend/LogDiagnosticPrinter.h4
-rw-r--r--include/clang/Frontend/MultiplexConsumer.h1
-rw-r--r--include/clang/Frontend/PreprocessorOutputOptions.h2
-rw-r--r--include/clang/Frontend/SerializedDiagnosticPrinter.h3
-rw-r--r--include/clang/Frontend/TextDiagnostic.h20
-rw-r--r--include/clang/Frontend/TextDiagnosticPrinter.h4
-rw-r--r--include/clang/Frontend/Utils.h3
-rw-r--r--include/clang/Lex/DirectoryLookup.h34
-rw-r--r--include/clang/Lex/ExternalPreprocessorSource.h4
-rw-r--r--include/clang/Lex/HeaderSearch.h30
-rw-r--r--include/clang/Lex/HeaderSearchOptions.h67
-rw-r--r--include/clang/Lex/Lexer.h50
-rw-r--r--include/clang/Lex/LiteralSupport.h8
-rw-r--r--include/clang/Lex/MacroInfo.h471
-rw-r--r--include/clang/Lex/ModuleLoader.h41
-rw-r--r--include/clang/Lex/ModuleMap.h55
-rw-r--r--include/clang/Lex/PPCallbacks.h66
-rw-r--r--include/clang/Lex/PPConditionalDirectiveRecord.h102
-rw-r--r--include/clang/Lex/PPMutationListener.h43
-rw-r--r--include/clang/Lex/PTHManager.h6
-rw-r--r--include/clang/Lex/PreprocessingRecord.h97
-rw-r--r--include/clang/Lex/Preprocessor.h184
-rw-r--r--include/clang/Lex/PreprocessorOptions.h52
-rw-r--r--include/clang/Lex/Token.h12
-rw-r--r--include/clang/Parse/Parser.h147
-rw-r--r--include/clang/Rewrite/Core/RewriteRope.h3
-rw-r--r--include/clang/Rewrite/Core/Rewriter.h8
-rw-r--r--include/clang/Rewrite/Frontend/ASTConsumers.h3
-rw-r--r--include/clang/Rewrite/Frontend/FixItRewriter.h2
-rw-r--r--include/clang/Sema/AttributeList.h123
-rw-r--r--include/clang/Sema/CMakeLists.txt7
-rw-r--r--include/clang/Sema/CXXFieldCollector.h1
-rw-r--r--include/clang/Sema/CodeCompleteConsumer.h37
-rw-r--r--include/clang/Sema/CodeCompleteOptions.h8
-rw-r--r--include/clang/Sema/DeclSpec.h216
-rw-r--r--include/clang/Sema/DelayedDiagnostic.h39
-rw-r--r--include/clang/Sema/ExternalSemaSource.h10
-rw-r--r--include/clang/Sema/IdentifierResolver.h3
-rw-r--r--include/clang/Sema/Initialization.h93
-rw-r--r--include/clang/Sema/Lookup.h25
-rw-r--r--include/clang/Sema/Makefile9
-rw-r--r--include/clang/Sema/MultiplexExternalSemaSource.h59
-rw-r--r--include/clang/Sema/Overload.h9
-rw-r--r--include/clang/Sema/Ownership.h3
-rw-r--r--include/clang/Sema/Scope.h64
-rw-r--r--include/clang/Sema/ScopeInfo.h17
-rw-r--r--include/clang/Sema/Sema.h551
-rw-r--r--include/clang/Sema/SemaInternal.h2
-rw-r--r--include/clang/Sema/Template.h13
-rw-r--r--include/clang/Sema/TemplateDeduction.h18
-rw-r--r--include/clang/Sema/TypoCorrection.h15
-rw-r--r--include/clang/Serialization/ASTBitCodes.h103
-rw-r--r--include/clang/Serialization/ASTReader.h347
-rw-r--r--include/clang/Serialization/ASTWriter.h62
-rw-r--r--include/clang/Serialization/ContinuousRangeMap.h1
-rw-r--r--include/clang/Serialization/GlobalModuleIndex.h194
-rw-r--r--include/clang/Serialization/Module.h53
-rw-r--r--include/clang/Serialization/ModuleManager.h148
-rw-r--r--include/clang/StaticAnalyzer/Core/Analyses.def14
-rw-r--r--include/clang/StaticAnalyzer/Core/AnalyzerOptions.h215
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h28
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h125
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugType.h1
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h32
-rw-r--r--include/clang/StaticAnalyzer/Core/Checker.h87
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerManager.h81
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerOptInfo.h1
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerRegistry.h2
-rw-r--r--include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h24
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h9
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h2
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h3
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h38
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h12
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h14
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h12
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h10
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h64
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h143
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h96
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h61
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h105
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h19
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h5
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h242
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Store.h40
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h22
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h8
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h6
-rw-r--r--include/clang/Tooling/CommonOptionsParser.h10
-rw-r--r--include/clang/Tooling/CompilationDatabase.h13
-rw-r--r--include/clang/Tooling/FileMatchTrie.h3
-rw-r--r--include/clang/Tooling/JSONCompilationDatabase.h10
-rw-r--r--include/clang/Tooling/Refactoring.h62
-rw-r--r--include/clang/Tooling/Tooling.h17
-rw-r--r--lib/ARCMigrate/ARCMT.cpp48
-rw-r--r--lib/ARCMigrate/CMakeLists.txt5
-rw-r--r--lib/ARCMigrate/FileRemapper.cpp6
-rw-r--r--lib/ARCMigrate/Internals.h8
-rw-r--r--lib/ARCMigrate/ObjCMT.cpp69
-rw-r--r--lib/ARCMigrate/PlistReporter.cpp4
-rw-r--r--lib/ARCMigrate/TransAPIUses.cpp2
-rw-r--r--lib/ARCMigrate/TransARCAssign.cpp2
-rw-r--r--lib/ARCMigrate/TransAutoreleasePool.cpp4
-rw-r--r--lib/ARCMigrate/TransBlockObjCVariable.cpp3
-rw-r--r--lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp2
-rw-r--r--lib/ARCMigrate/TransGCAttrs.cpp28
-rw-r--r--lib/ARCMigrate/TransGCCalls.cpp2
-rw-r--r--lib/ARCMigrate/TransProperties.cpp32
-rw-r--r--lib/ARCMigrate/TransProtectedScope.cpp202
-rw-r--r--lib/ARCMigrate/TransRetainReleaseDealloc.cpp125
-rw-r--r--lib/ARCMigrate/TransUnbridgedCasts.cpp108
-rw-r--r--lib/ARCMigrate/TransUnusedInitDelegate.cpp2
-rw-r--r--lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp2
-rw-r--r--lib/ARCMigrate/TransformActions.cpp2
-rw-r--r--lib/ARCMigrate/Transforms.cpp27
-rw-r--r--lib/ARCMigrate/Transforms.h10
-rw-r--r--lib/AST/APValue.cpp4
-rw-r--r--lib/AST/ASTConsumer.cpp2
-rw-r--r--lib/AST/ASTContext.cpp767
-rw-r--r--lib/AST/ASTDiagnostic.cpp567
-rw-r--r--lib/AST/ASTDumper.cpp1996
-rw-r--r--lib/AST/ASTImporter.cpp163
-rw-r--r--lib/AST/AttrImpl.cpp4
-rw-r--r--lib/AST/CMakeLists.txt7
-rw-r--r--lib/AST/CXXABI.h6
-rw-r--r--lib/AST/CXXInheritance.cpp43
-rw-r--r--lib/AST/Comment.cpp40
-rw-r--r--lib/AST/CommentBriefParser.cpp2
-rw-r--r--lib/AST/CommentCommandTraits.cpp34
-rw-r--r--lib/AST/CommentDumper.cpp257
-rw-r--r--lib/AST/CommentLexer.cpp127
-rw-r--r--lib/AST/CommentParser.cpp66
-rw-r--r--lib/AST/CommentSema.cpp269
-rw-r--r--lib/AST/Decl.cpp1305
-rw-r--r--lib/AST/DeclBase.cpp141
-rw-r--r--lib/AST/DeclCXX.cpp828
-rw-r--r--lib/AST/DeclFriend.cpp21
-rw-r--r--lib/AST/DeclGroup.cpp2
-rw-r--r--lib/AST/DeclObjC.cpp428
-rw-r--r--lib/AST/DeclOpenMP.cpp60
-rw-r--r--lib/AST/DeclPrinter.cpp193
-rw-r--r--lib/AST/DeclTemplate.cpp61
-rw-r--r--lib/AST/DeclarationName.cpp15
-rw-r--r--lib/AST/DumpXML.cpp28
-rw-r--r--lib/AST/Expr.cpp168
-rw-r--r--lib/AST/ExprCXX.cpp76
-rw-r--r--lib/AST/ExprClassification.cpp37
-rw-r--r--lib/AST/ExprConstant.cpp306
-rw-r--r--lib/AST/ExternalASTSource.cpp4
-rw-r--r--lib/AST/InheritViz.cpp2
-rw-r--r--lib/AST/ItaniumCXXABI.cpp15
-rw-r--r--lib/AST/ItaniumMangle.cpp80
-rw-r--r--lib/AST/LambdaMangleContext.cpp9
-rw-r--r--lib/AST/Mangle.cpp2
-rw-r--r--lib/AST/MicrosoftCXXABI.cpp136
-rw-r--r--lib/AST/MicrosoftMangle.cpp218
-rw-r--r--lib/AST/NSAPI.cpp39
-rw-r--r--lib/AST/NestedNameSpecifier.cpp15
-rw-r--r--lib/AST/RawCommentList.cpp6
-rw-r--r--lib/AST/RecordLayout.cpp7
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp135
-rw-r--r--lib/AST/Stmt.cpp156
-rw-r--r--lib/AST/StmtDumper.cpp760
-rw-r--r--lib/AST/StmtPrinter.cpp214
-rw-r--r--lib/AST/TemplateBase.cpp21
-rw-r--r--lib/AST/TemplateName.cpp14
-rw-r--r--lib/AST/Type.cpp249
-rw-r--r--lib/AST/TypeLoc.cpp30
-rw-r--r--lib/AST/TypePrinter.cpp140
-rw-r--r--lib/AST/VTableBuilder.cpp126
-rw-r--r--lib/ASTMatchers/ASTMatchFinder.cpp236
-rw-r--r--lib/ASTMatchers/ASTMatchersInternal.cpp7
-rw-r--r--lib/ASTMatchers/CMakeLists.txt6
-rw-r--r--lib/Analysis/AnalysisDeclContext.cpp68
-rw-r--r--lib/Analysis/BodyFarm.cpp18
-rw-r--r--lib/Analysis/BodyFarm.h5
-rw-r--r--lib/Analysis/CFG.cpp166
-rw-r--r--lib/Analysis/CFGStmtMap.cpp2
-rw-r--r--lib/Analysis/CallGraph.cpp112
-rw-r--r--lib/Analysis/CocoaConventions.cpp8
-rw-r--r--lib/Analysis/FormatString.cpp11
-rw-r--r--lib/Analysis/FormatStringParsing.h2
-rw-r--r--lib/Analysis/LiveVariables.cpp38
-rw-r--r--lib/Analysis/PrintfFormatString.cpp34
-rw-r--r--lib/Analysis/ReachableCode.cpp14
-rw-r--r--lib/Analysis/ScanfFormatString.cpp4
-rw-r--r--lib/Analysis/ThreadSafety.cpp290
-rw-r--r--lib/Analysis/UninitializedValues.cpp160
-rw-r--r--lib/Basic/Builtins.cpp2
-rw-r--r--lib/Basic/CMakeLists.txt30
-rw-r--r--lib/Basic/CharInfo.cpp81
-rw-r--r--lib/Basic/ConvertUTF.c571
-rw-r--r--lib/Basic/ConvertUTFWrapper.cpp76
-rw-r--r--lib/Basic/Diagnostic.cpp66
-rw-r--r--lib/Basic/DiagnosticIDs.cpp72
-rw-r--r--lib/Basic/FileManager.cpp50
-rw-r--r--lib/Basic/FileSystemStatCache.cpp20
-rw-r--r--lib/Basic/IdentifierTable.cpp21
-rw-r--r--lib/Basic/LangOptions.cpp10
-rw-r--r--lib/Basic/Module.cpp134
-rw-r--r--lib/Basic/OpenMPKinds.cpp43
-rw-r--r--lib/Basic/OperatorPrecedence.cpp76
-rw-r--r--lib/Basic/SourceLocation.cpp2
-rw-r--r--lib/Basic/SourceManager.cpp90
-rw-r--r--lib/Basic/TargetInfo.cpp24
-rw-r--r--lib/Basic/Targets.cpp810
-rw-r--r--lib/Basic/TokenKinds.cpp1
-rw-r--r--lib/Basic/Version.cpp10
-rw-r--r--lib/Basic/VersionTuple.cpp4
-rw-r--r--lib/CMakeLists.txt1
-rw-r--r--lib/CodeGen/ABIInfo.h21
-rw-r--r--lib/CodeGen/BackendUtil.cpp153
-rw-r--r--lib/CodeGen/CGAtomic.cpp942
-rw-r--r--lib/CodeGen/CGBlocks.cpp306
-rw-r--r--lib/CodeGen/CGBlocks.h35
-rw-r--r--lib/CodeGen/CGBuilder.h2
-rw-r--r--lib/CodeGen/CGBuiltin.cpp141
-rw-r--r--lib/CodeGen/CGCUDANV.cpp13
-rw-r--r--lib/CodeGen/CGCUDARuntime.cpp4
-rw-r--r--lib/CodeGen/CGCXX.cpp10
-rw-r--r--lib/CodeGen/CGCXXABI.cpp27
-rw-r--r--lib/CodeGen/CGCXXABI.h57
-rw-r--r--lib/CodeGen/CGCall.cpp617
-rw-r--r--lib/CodeGen/CGCall.h36
-rw-r--r--lib/CodeGen/CGClass.cpp627
-rw-r--r--lib/CodeGen/CGCleanup.cpp12
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp905
-rw-r--r--lib/CodeGen/CGDebugInfo.h72
-rw-r--r--lib/CodeGen/CGDecl.cpp339
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp32
-rw-r--r--lib/CodeGen/CGException.cpp273
-rw-r--r--lib/CodeGen/CGExpr.cpp1301
-rw-r--r--lib/CodeGen/CGExprAgg.cpp215
-rw-r--r--lib/CodeGen/CGExprCXX.cpp159
-rw-r--r--lib/CodeGen/CGExprComplex.cpp126
-rw-r--r--lib/CodeGen/CGExprConstant.cpp40
-rw-r--r--lib/CodeGen/CGExprScalar.cpp478
-rw-r--r--lib/CodeGen/CGObjC.cpp265
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp275
-rw-r--r--lib/CodeGen/CGObjCMac.cpp687
-rw-r--r--lib/CodeGen/CGObjCRuntime.cpp34
-rw-r--r--lib/CodeGen/CGObjCRuntime.h29
-rw-r--r--lib/CodeGen/CGOpenCLRuntime.cpp38
-rw-r--r--lib/CodeGen/CGOpenCLRuntime.h6
-rw-r--r--lib/CodeGen/CGRTTI.cpp20
-rw-r--r--lib/CodeGen/CGRecordLayout.h182
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp431
-rw-r--r--lib/CodeGen/CGStmt.cpp94
-rw-r--r--lib/CodeGen/CGVTables.cpp224
-rw-r--r--lib/CodeGen/CGVTables.h24
-rw-r--r--lib/CodeGen/CGValue.h80
-rw-r--r--lib/CodeGen/CMakeLists.txt2
-rw-r--r--lib/CodeGen/CodeGenAction.cpp20
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp382
-rw-r--r--lib/CodeGen/CodeGenFunction.h276
-rw-r--r--lib/CodeGen/CodeGenModule.cpp598
-rw-r--r--lib/CodeGen/CodeGenModule.h99
-rw-r--r--lib/CodeGen/CodeGenTBAA.cpp96
-rw-r--r--lib/CodeGen/CodeGenTBAA.h57
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp86
-rw-r--r--lib/CodeGen/CodeGenTypes.h6
-rw-r--r--lib/CodeGen/ItaniumCXXABI.cpp221
-rw-r--r--lib/CodeGen/MicrosoftCXXABI.cpp278
-rw-r--r--lib/CodeGen/ModuleBuilder.cpp20
-rw-r--r--lib/CodeGen/TargetInfo.cpp696
-rw-r--r--lib/CodeGen/TargetInfo.h13
-rw-r--r--lib/Driver/Action.cpp1
-rw-r--r--lib/Driver/ArgList.cpp10
-rw-r--r--lib/Driver/CC1AsOptions.cpp2
-rw-r--r--lib/Driver/Compilation.cpp128
-rw-r--r--lib/Driver/Driver.cpp247
-rw-r--r--lib/Driver/InputInfo.h2
-rw-r--r--lib/Driver/Job.cpp2
-rw-r--r--lib/Driver/OptTable.cpp2
-rw-r--r--lib/Driver/Option.cpp7
-rw-r--r--lib/Driver/Phases.cpp1
-rw-r--r--lib/Driver/SanitizerArgs.h130
-rw-r--r--lib/Driver/ToolChain.cpp100
-rw-r--r--lib/Driver/ToolChains.cpp931
-rw-r--r--lib/Driver/ToolChains.h172
-rw-r--r--lib/Driver/Tools.cpp1920
-rw-r--r--lib/Driver/Tools.h90
-rw-r--r--lib/Driver/Types.cpp76
-rw-r--r--lib/Driver/WindowsToolChain.cpp60
-rw-r--r--lib/Edit/Commit.cpp6
-rw-r--r--lib/Edit/EditedSource.cpp80
-rw-r--r--lib/Edit/RewriteObjCFoundationAPI.cpp180
-rw-r--r--lib/Format/CMakeLists.txt26
-rw-r--r--lib/Format/Format.cpp1763
-rw-r--r--lib/Format/Makefile13
-rw-r--r--lib/Format/TokenAnnotator.cpp1187
-rw-r--r--lib/Format/TokenAnnotator.h262
-rw-r--r--lib/Format/UnwrappedLineParser.cpp858
-rw-r--r--lib/Format/UnwrappedLineParser.h201
-rw-r--r--lib/Frontend/ASTConsumers.cpp26
-rw-r--r--lib/Frontend/ASTMerge.cpp4
-rw-r--r--lib/Frontend/ASTUnit.cpp117
-rw-r--r--lib/Frontend/CacheTokens.cpp6
-rw-r--r--lib/Frontend/ChainedIncludesSource.cpp19
-rw-r--r--lib/Frontend/CompilerInstance.cpp545
-rw-r--r--lib/Frontend/CompilerInvocation.cpp275
-rw-r--r--lib/Frontend/CreateInvocationFromCommandLine.cpp14
-rw-r--r--lib/Frontend/DependencyFile.cpp8
-rw-r--r--lib/Frontend/DependencyGraph.cpp15
-rw-r--r--lib/Frontend/DiagnosticRenderer.cpp326
-rw-r--r--lib/Frontend/FrontendAction.cpp40
-rw-r--r--lib/Frontend/FrontendActions.cpp157
-rw-r--r--lib/Frontend/FrontendOptions.cpp2
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp228
-rw-r--r--lib/Frontend/InitPreprocessor.cpp36
-rw-r--r--lib/Frontend/LayoutOverrideSource.cpp21
-rw-r--r--lib/Frontend/LogDiagnosticPrinter.cpp2
-rw-r--r--lib/Frontend/MultiplexConsumer.cpp1
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp60
-rw-r--r--lib/Frontend/SerializedDiagnosticPrinter.cpp214
-rw-r--r--lib/Frontend/TextDiagnostic.cpp381
-rw-r--r--lib/Frontend/TextDiagnosticBuffer.cpp26
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp4
-rw-r--r--lib/Frontend/VerifyDiagnosticConsumer.cpp8
-rw-r--r--lib/Frontend/Warnings.cpp18
-rw-r--r--lib/FrontendTool/ExecuteCompilerInvocation.cpp75
-rw-r--r--lib/FrontendTool/Makefile15
-rw-r--r--lib/Headers/CMakeLists.txt10
-rw-r--r--lib/Headers/altivec.h7850
-rw-r--r--lib/Headers/avx2intrin.h384
-rw-r--r--lib/Headers/avxintrin.h715
-rw-r--r--lib/Headers/cpuid.h9
-rw-r--r--lib/Headers/emmintrin.h860
-rw-r--r--lib/Headers/f16cintrin.h10
-rw-r--r--lib/Headers/immintrin.h9
-rw-r--r--lib/Headers/mm3dnow.h1
-rw-r--r--lib/Headers/mm_malloc.h28
-rw-r--r--lib/Headers/module.map2
-rw-r--r--lib/Headers/pmmintrin.h48
-rw-r--r--lib/Headers/prfchwintrin.h34
-rw-r--r--lib/Headers/rdseedintrin.h48
-rw-r--r--lib/Headers/smmintrin.h6
-rw-r--r--lib/Headers/stdalign.h5
-rw-r--r--lib/Headers/stddef.h28
-rw-r--r--lib/Headers/stdnoreturn.h30
-rw-r--r--lib/Headers/tmmintrin.h120
-rw-r--r--lib/Headers/unwind.h63
-rw-r--r--lib/Headers/x86intrin.h8
-rw-r--r--lib/Headers/xmmintrin.h618
-rw-r--r--lib/Lex/CMakeLists.txt1
-rw-r--r--lib/Lex/HeaderMap.cpp4
-rw-r--r--lib/Lex/HeaderSearch.cpp311
-rw-r--r--lib/Lex/Lexer.cpp797
-rw-r--r--lib/Lex/LiteralSupport.cpp54
-rw-r--r--lib/Lex/MacroArgs.cpp18
-rw-r--r--lib/Lex/MacroArgs.h4
-rw-r--r--lib/Lex/MacroInfo.cpp119
-rw-r--r--lib/Lex/ModuleMap.cpp428
-rw-r--r--lib/Lex/PPConditionalDirectiveRecord.cpp120
-rw-r--r--lib/Lex/PPDirectives.cpp229
-rw-r--r--lib/Lex/PPExpressions.cpp28
-rw-r--r--lib/Lex/PPLexerChange.cpp53
-rw-r--r--lib/Lex/PPMacroExpansion.cpp456
-rw-r--r--lib/Lex/PTHLexer.cpp11
-rw-r--r--lib/Lex/Pragma.cpp220
-rw-r--r--lib/Lex/PreprocessingRecord.cpp189
-rw-r--r--lib/Lex/Preprocessor.cpp185
-rw-r--r--lib/Lex/PreprocessorLexer.cpp4
-rw-r--r--lib/Lex/TokenConcatenation.cpp36
-rw-r--r--lib/Lex/TokenLexer.cpp18
-rw-r--r--lib/Lex/UnicodeCharSets.h496
-rwxr-xr-xlib/Makefile18
-rw-r--r--lib/Parse/CMakeLists.txt1
-rw-r--r--lib/Parse/ParseAST.cpp61
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp55
-rw-r--r--lib/Parse/ParseDecl.cpp450
-rw-r--r--lib/Parse/ParseDeclCXX.cpp373
-rw-r--r--lib/Parse/ParseExpr.cpp139
-rw-r--r--lib/Parse/ParseExprCXX.cpp74
-rw-r--r--lib/Parse/ParseInit.cpp4
-rw-r--r--lib/Parse/ParseObjc.cpp125
-rw-r--r--lib/Parse/ParseOpenMP.cpp118
-rw-r--r--lib/Parse/ParsePragma.cpp46
-rw-r--r--lib/Parse/ParsePragma.h15
-rw-r--r--lib/Parse/ParseStmt.cpp114
-rw-r--r--lib/Parse/ParseTemplate.cpp197
-rw-r--r--lib/Parse/ParseTentative.cpp53
-rw-r--r--lib/Parse/Parser.cpp105
-rw-r--r--lib/Parse/RAIIObjectsForParser.h2
-rw-r--r--lib/Rewrite/Core/DeltaTree.cpp2
-rw-r--r--lib/Rewrite/Core/HTMLRewrite.cpp9
-rw-r--r--lib/Rewrite/Core/Rewriter.cpp8
-rw-r--r--lib/Rewrite/Core/TokenRewriter.cpp2
-rw-r--r--lib/Rewrite/Frontend/CMakeLists.txt1
-rw-r--r--lib/Rewrite/Frontend/FixItRewriter.cpp8
-rw-r--r--lib/Rewrite/Frontend/FrontendActions.cpp14
-rw-r--r--lib/Rewrite/Frontend/InclusionRewriter.cpp4
-rw-r--r--lib/Rewrite/Frontend/RewriteMacros.cpp8
-rw-r--r--lib/Rewrite/Frontend/RewriteModernObjC.cpp568
-rw-r--r--lib/Rewrite/Frontend/RewriteObjC.cpp172
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp144
-rw-r--r--lib/Sema/AttributeList.cpp13
-rw-r--r--lib/Sema/CMakeLists.txt2
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp61
-rw-r--r--lib/Sema/DeclSpec.cpp84
-rw-r--r--lib/Sema/IdentifierResolver.cpp14
-rw-r--r--lib/Sema/JumpDiagnostics.cpp14
-rw-r--r--lib/Sema/MultiplexExternalSemaSource.cpp28
-rw-r--r--lib/Sema/Sema.cpp272
-rw-r--r--lib/Sema/SemaAccess.cpp271
-rw-r--r--lib/Sema/SemaAttr.cpp5
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp45
-rw-r--r--lib/Sema/SemaCast.cpp132
-rw-r--r--lib/Sema/SemaChecking.cpp922
-rw-r--r--lib/Sema/SemaCodeComplete.cpp540
-rw-r--r--lib/Sema/SemaDecl.cpp2272
-rw-r--r--lib/Sema/SemaDeclAttr.cpp1240
-rw-r--r--lib/Sema/SemaDeclCXX.cpp2314
-rw-r--r--lib/Sema/SemaDeclObjC.cpp359
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp116
-rw-r--r--lib/Sema/SemaExpr.cpp976
-rw-r--r--lib/Sema/SemaExprCXX.cpp395
-rw-r--r--lib/Sema/SemaExprMember.cpp110
-rw-r--r--lib/Sema/SemaExprObjC.cpp340
-rw-r--r--lib/Sema/SemaFixItUtils.cpp4
-rw-r--r--lib/Sema/SemaInit.cpp439
-rw-r--r--lib/Sema/SemaLambda.cpp294
-rw-r--r--lib/Sema/SemaLookup.cpp233
-rw-r--r--lib/Sema/SemaObjCProperty.cpp468
-rw-r--r--lib/Sema/SemaOpenMP.cpp181
-rw-r--r--lib/Sema/SemaOverload.cpp448
-rw-r--r--lib/Sema/SemaPseudoObject.cpp27
-rw-r--r--lib/Sema/SemaStmt.cpp201
-rw-r--r--lib/Sema/SemaStmtAsm.cpp99
-rw-r--r--lib/Sema/SemaStmtAttr.cpp4
-rw-r--r--lib/Sema/SemaTemplate.cpp208
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp104
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp120
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp334
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp57
-rw-r--r--lib/Sema/SemaType.cpp860
-rw-r--r--lib/Sema/TargetAttributesSema.cpp76
-rw-r--r--lib/Sema/TreeTransform.h316
-rw-r--r--lib/Sema/TypeLocBuilder.h8
-rw-r--r--lib/Serialization/ASTCommon.cpp134
-rw-r--r--lib/Serialization/ASTCommon.h17
-rw-r--r--lib/Serialization/ASTReader.cpp2238
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp200
-rw-r--r--lib/Serialization/ASTReaderInternals.h128
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp55
-rw-r--r--lib/Serialization/ASTWriter.cpp974
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp78
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp13
-rw-r--r--lib/Serialization/CMakeLists.txt3
-rw-r--r--lib/Serialization/GeneratePCH.cpp10
-rw-r--r--lib/Serialization/GlobalModuleIndex.cpp820
-rw-r--r--lib/Serialization/Module.cpp6
-rw-r--r--lib/Serialization/ModuleManager.cpp316
-rw-r--r--lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp18
-rw-r--r--lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp35
-rw-r--r--lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp130
-rw-r--r--lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp176
-rw-r--r--lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp22
-rw-r--r--lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp5
-rw-r--r--lib/StaticAnalyzer/Checkers/CMakeLists.txt4
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringChecker.cpp166
-rw-r--r--lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp61
-rw-r--r--lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp13
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp9
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp11
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp45
-rw-r--r--lib/StaticAnalyzer/Checkers/Checkers.td38
-rw-r--r--lib/StaticAnalyzer/Checkers/ChrootChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/ClangSACheckers.h4
-rw-r--r--lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp12
-rw-r--r--lib/StaticAnalyzer/Checkers/DebugCheckers.cpp6
-rw-r--r--lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp22
-rw-r--r--lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp102
-rw-r--r--lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp66
-rw-r--r--lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp5
-rw-r--r--lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp9
-rw-r--r--lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp38
-rw-r--r--lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp431
-rw-r--r--lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp5
-rw-r--r--lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp139
-rw-r--r--lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp8
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp1096
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp18
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp7
-rw-r--r--lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp8
-rw-r--r--lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp34
-rw-r--r--lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp12
-rw-r--r--lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp193
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp6
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp9
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp166
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp25
-rw-r--r--lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp20
-rw-r--r--lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp243
-rw-r--r--lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp98
-rw-r--r--lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp107
-rw-r--r--lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp33
-rw-r--r--lib/StaticAnalyzer/Checkers/StreamChecker.cpp61
-rw-r--r--lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/TraversalChecker.cpp33
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp4
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp16
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp3
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp36
-rw-r--r--lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp2
-rw-r--r--lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp21
-rw-r--r--lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp16
-rw-r--r--lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp19
-rw-r--r--lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp7
-rw-r--r--lib/StaticAnalyzer/Core/APSIntType.cpp31
-rw-r--r--lib/StaticAnalyzer/Core/AnalysisManager.cpp3
-rw-r--r--lib/StaticAnalyzer/Core/AnalyzerOptions.cpp134
-rw-r--r--lib/StaticAnalyzer/Core/BugReporter.cpp651
-rw-r--r--lib/StaticAnalyzer/Core/BugReporterVisitors.cpp858
-rw-r--r--lib/StaticAnalyzer/Core/CallEvent.cpp129
-rw-r--r--lib/StaticAnalyzer/Core/CheckerManager.cpp60
-rw-r--r--lib/StaticAnalyzer/Core/CheckerRegistry.cpp3
-rw-r--r--lib/StaticAnalyzer/Core/CoreEngine.cpp54
-rw-r--r--lib/StaticAnalyzer/Core/Environment.cpp78
-rw-r--r--lib/StaticAnalyzer/Core/ExplodedGraph.cpp130
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp665
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineC.cpp123
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCXX.cpp230
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp572
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineObjC.cpp15
-rw-r--r--lib/StaticAnalyzer/Core/FunctionSummary.cpp14
-rw-r--r--lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp13
-rw-r--r--lib/StaticAnalyzer/Core/MemRegion.cpp228
-rw-r--r--lib/StaticAnalyzer/Core/PathDiagnostic.cpp219
-rw-r--r--lib/StaticAnalyzer/Core/PlistDiagnostics.cpp63
-rw-r--r--lib/StaticAnalyzer/Core/ProgramState.cpp167
-rw-r--r--lib/StaticAnalyzer/Core/RangeConstraintManager.cpp24
-rw-r--r--lib/StaticAnalyzer/Core/RegionStore.cpp1506
-rw-r--r--lib/StaticAnalyzer/Core/SValBuilder.cpp70
-rw-r--r--lib/StaticAnalyzer/Core/SVals.cpp64
-rw-r--r--lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp101
-rw-r--r--lib/StaticAnalyzer/Core/SimpleConstraintManager.h9
-rw-r--r--lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp161
-rw-r--r--lib/StaticAnalyzer/Core/Store.cpp66
-rw-r--r--lib/StaticAnalyzer/Core/SymbolManager.cpp53
-rw-r--r--lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp5
-rw-r--r--lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp257
-rw-r--r--lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp12
-rw-r--r--lib/StaticAnalyzer/Frontend/FrontendActions.cpp2
-rw-r--r--lib/Tooling/CommonOptionsParser.cpp4
-rw-r--r--lib/Tooling/CompilationDatabase.cpp11
-rw-r--r--lib/Tooling/FileMatchTrie.cpp4
-rw-r--r--lib/Tooling/JSONCompilationDatabase.cpp94
-rw-r--r--lib/Tooling/Refactoring.cpp75
-rw-r--r--lib/Tooling/Tooling.cpp43
-rw-r--r--runtime/compiler-rt/Makefile17
-rw-r--r--test/ARCMT/Common.h6
-rw-r--r--test/ARCMT/autoreleases.m10
-rw-r--r--test/ARCMT/autoreleases.m.result8
-rw-r--r--test/ARCMT/block_copy_release.m17
-rw-r--r--test/ARCMT/block_copy_release.m.result15
-rw-r--r--test/ARCMT/check-with-pch.m16
-rw-r--r--test/ARCMT/checking.m8
-rw-r--r--test/ARCMT/migrate-with-pch.m7
-rw-r--r--test/ARCMT/nonobjc-to-objc-cast-2.m9
-rw-r--r--test/ARCMT/objcmt-subscripting-literals-in-arc.m2
-rw-r--r--test/ARCMT/objcmt-subscripting-literals-in-arc.m.result2
-rw-r--r--test/ARCMT/objcmt-subscripting-literals.m4
-rw-r--r--test/ARCMT/objcmt-subscripting-literals.m.result4
-rw-r--r--test/ARCMT/objcmt-with-pch.m16
-rw-r--r--test/ARCMT/objcmt-with-pch.m.result16
-rw-r--r--test/ARCMT/protected-scope.m37
-rw-r--r--test/ARCMT/protected-scope.m.result39
-rw-r--r--test/ASTMerge/Inputs/class1.cpp4
-rw-r--r--test/ASTMerge/Inputs/class2.cpp4
-rw-r--r--test/ASTMerge/class.cpp5
-rw-r--r--test/Analysis/Inputs/system-header-simulator-cxx.h36
-rw-r--r--test/Analysis/Inputs/system-header-simulator-for-malloc.h34
-rw-r--r--test/Analysis/Inputs/system-header-simulator-for-simple-stream.h12
-rw-r--r--test/Analysis/Inputs/system-header-simulator-objc.h5
-rw-r--r--test/Analysis/Inputs/system-header-simulator.h13
-rw-r--r--test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp71
-rw-r--r--test/Analysis/Malloc+MismatchedDeallocator_intersections.cpp28
-rw-r--r--test/Analysis/Malloc+NewDelete_intersections.cpp14
-rw-r--r--test/Analysis/NSContainers.m200
-rw-r--r--test/Analysis/NSString.m25
-rw-r--r--test/Analysis/NewDelete+MismatchedDeallocator_intersections.cpp28
-rw-r--r--test/Analysis/NewDelete-checker-test.cpp145
-rw-r--r--test/Analysis/NewDelete-custom.cpp57
-rw-r--r--test/Analysis/NewDelete-intersections.mm64
-rw-r--r--test/Analysis/NewDelete-path-notes.cpp323
-rw-r--r--test/Analysis/NewDelete-variadic.cpp19
-rw-r--r--test/Analysis/NoReturn.m39
-rw-r--r--test/Analysis/PR3991.m17
-rw-r--r--test/Analysis/additive-folding-range-constraints.c132
-rw-r--r--test/Analysis/additive-folding.cpp20
-rw-r--r--test/Analysis/alloc-match-dealloc.mm221
-rw-r--r--test/Analysis/analyzer-config.c9
-rw-r--r--test/Analysis/analyzer-config.cpp11
-rw-r--r--test/Analysis/analyzer-stats.c2
-rw-r--r--test/Analysis/array-struct-region.c65
-rw-r--r--test/Analysis/auto-obj-dtors-cfg-output.cpp1
-rw-r--r--test/Analysis/base-init.cpp2
-rw-r--r--test/Analysis/blocks-no-inline.c29
-rw-r--r--test/Analysis/blocks.m31
-rw-r--r--test/Analysis/call-invalidation.cpp91
-rw-r--r--test/Analysis/casts.c11
-rw-r--r--test/Analysis/cfg.cpp37
-rw-r--r--test/Analysis/conditional-operator-path-notes.c24
-rw-r--r--test/Analysis/coverage.c24
-rw-r--r--test/Analysis/ctor-inlining.mm385
-rw-r--r--test/Analysis/dead-stores.cpp29
-rw-r--r--test/Analysis/debug-CallGraph.c18
-rw-r--r--test/Analysis/default-diagnostic-visitors.c2
-rw-r--r--test/Analysis/derived-to-base.cpp230
-rw-r--r--test/Analysis/diagnostics/Inputs/include/sys/queue.h5
-rw-r--r--test/Analysis/diagnostics/deref-track-symbolic-region.c625
-rw-r--r--test/Analysis/diagnostics/deref-track-symbolic-region.cpp29
-rw-r--r--test/Analysis/diagnostics/explicit-suppression.cpp80
-rw-r--r--test/Analysis/diagnostics/false-positive-suppression.c23
-rw-r--r--test/Analysis/diagnostics/no-prune-paths.c21
-rw-r--r--test/Analysis/diagnostics/shortest-path-suppression.c19
-rw-r--r--test/Analysis/diagnostics/undef-value-caller.c298
-rw-r--r--test/Analysis/diagnostics/undef-value-param.c314
-rw-r--r--test/Analysis/diagnostics/undef-value-param.m1313
-rw-r--r--test/Analysis/dtor.cpp102
-rw-r--r--test/Analysis/dtors-in-dtor-cfg-output.cpp1
-rw-r--r--test/Analysis/dynamic-cast.cpp2
-rw-r--r--test/Analysis/engine/replay-without-inlining.c2
-rw-r--r--test/Analysis/fields.c87
-rw-r--r--test/Analysis/free.c2
-rw-r--r--test/Analysis/global-region-invalidation.c44
-rw-r--r--test/Analysis/global_region_invalidation.mm45
-rw-r--r--test/Analysis/html-diags-multifile.c1
-rw-r--r--test/Analysis/html-diags.c2
-rw-r--r--test/Analysis/initializer.cpp35
-rw-r--r--test/Analysis/initializers-cfg-output.cpp1
-rw-r--r--test/Analysis/inline-plist.c30
-rw-r--r--test/Analysis/inline-unique-reports.c2
-rw-r--r--test/Analysis/inline.cpp56
-rw-r--r--test/Analysis/inlining/DynDispatchBifurcate.m2
-rw-r--r--test/Analysis/inlining/InlineObjCClassMethod.m2
-rw-r--r--test/Analysis/inlining/ObjCDynTypePopagation.m19
-rw-r--r--test/Analysis/inlining/ObjCImproperDynamictallyDetectableCast.m2
-rw-r--r--test/Analysis/inlining/RetainCountExamples.m2
-rw-r--r--test/Analysis/inlining/assume-super-init-does-not-return-nil.m2
-rw-r--r--test/Analysis/inlining/containers.cpp234
-rw-r--r--test/Analysis/inlining/dyn-dispatch-bifurcate.cpp2
-rw-r--r--test/Analysis/inlining/eager-reclamation-path-notes.c16
-rw-r--r--test/Analysis/inlining/eager-reclamation-path-notes.cpp419
-rw-r--r--test/Analysis/inlining/false-positive-suppression.c85
-rw-r--r--test/Analysis/inlining/false-positive-suppression.cpp212
-rw-r--r--test/Analysis/inlining/inline-defensive-checks.c99
-rw-r--r--test/Analysis/inlining/inline-defensive-checks.cpp55
-rw-r--r--test/Analysis/inlining/inline-defensive-checks.m129
-rw-r--r--test/Analysis/inlining/path-notes.c1050
-rw-r--r--test/Analysis/inlining/path-notes.cpp3711
-rw-r--r--test/Analysis/inlining/path-notes.m716
-rw-r--r--test/Analysis/inlining/retain-count-self-init.m2
-rw-r--r--test/Analysis/inlining/stl.cpp4
-rw-r--r--test/Analysis/inlining/test_objc_inlining_option.m2
-rw-r--r--test/Analysis/keychainAPI.m23
-rw-r--r--test/Analysis/malloc-annotations.c8
-rw-r--r--test/Analysis/malloc-interprocedural.c20
-rw-r--r--test/Analysis/malloc-plist.c190
-rw-r--r--test/Analysis/malloc.c228
-rw-r--r--test/Analysis/malloc.cpp46
-rw-r--r--test/Analysis/malloc.mm42
-rw-r--r--test/Analysis/method-arg-decay.m6
-rw-r--r--test/Analysis/method-call-path-notes.cpp34
-rw-r--r--test/Analysis/method-call.cpp2
-rw-r--r--test/Analysis/misc-ps-region-store.cpp116
-rw-r--r--test/Analysis/misc-ps-region-store.m4
-rw-r--r--test/Analysis/misc-ps.c12
-rw-r--r--test/Analysis/new.cpp86
-rw-r--r--test/Analysis/null-deref-path-notes.m264
-rw-r--r--test/Analysis/objc-method-coverage.m6
-rw-r--r--test/Analysis/objc/direct-ivar-assignment-in-annotated-functions.m63
-rw-r--r--test/Analysis/objc_invalidation.m199
-rw-r--r--test/Analysis/operator-calls.cpp2
-rw-r--r--test/Analysis/plist-output-alternate.m89
-rw-r--r--test/Analysis/plist-output.m2794
-rw-r--r--test/Analysis/pointer-to-member.cpp2
-rw-r--r--test/Analysis/pr4209.m8
-rw-r--r--test/Analysis/ptr-arith.c113
-rw-r--r--test/Analysis/refcnt_naming.m2
-rw-r--r--test/Analysis/reference.cpp85
-rw-r--r--test/Analysis/reference.mm17
-rw-r--r--test/Analysis/region-store.c36
-rw-r--r--test/Analysis/region-store.cpp28
-rw-r--r--test/Analysis/reinterpret-cast.cpp70
-rw-r--r--test/Analysis/retain-release-cf-audited.m33
-rw-r--r--test/Analysis/retain-release-inline.m32
-rw-r--r--test/Analysis/retain-release-path-notes-gc.m10
-rw-r--r--test/Analysis/retain-release-path-notes.m87
-rw-r--r--test/Analysis/retain-release.m6745
-rw-r--r--test/Analysis/retain-release.mm23
-rw-r--r--test/Analysis/self-init.m27
-rw-r--r--test/Analysis/shallow-mode.m29
-rw-r--r--test/Analysis/simple-stream-checks.c17
-rw-r--r--test/Analysis/stack-addr-ps.cpp14
-rw-r--r--test/Analysis/stackaddrleak.c12
-rw-r--r--test/Analysis/stats.c1
-rw-r--r--test/Analysis/string.c48
-rw-r--r--test/Analysis/superclass.m (renamed from test/Analysis/viewcontroller.m)95
-rw-r--r--test/Analysis/taint-generic.c11
-rw-r--r--test/Analysis/temp-obj-dtors-cfg-output.cpp170
-rw-r--r--test/Analysis/temporaries.cpp54
-rw-r--r--test/Analysis/traversal-path-unification.c4
-rw-r--r--test/Analysis/uninit-sometimes.cpp4
-rw-r--r--test/Analysis/uninit-vals.m113
-rw-r--r--test/Analysis/unix-fns.c172
-rw-r--r--test/CMakeLists.txt45
-rw-r--r--test/CXX/basic/basic.link/p6.cpp43
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp92
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.unqual/p14.cpp30
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp2
-rw-r--r--test/CXX/basic/basic.start/basic.start.main/p2.cpp101
-rw-r--r--test/CXX/basic/basic.start/basic.start.main/p2a.cpp9
-rw-r--r--test/CXX/basic/basic.start/basic.start.main/p2b.cpp9
-rw-r--r--test/CXX/basic/basic.start/basic.start.main/p2c.cpp5
-rw-r--r--test/CXX/basic/basic.start/basic.start.main/p2d.cpp4
-rw-r--r--test/CXX/basic/basic.start/basic.start.main/p2e.cpp4
-rw-r--r--test/CXX/basic/basic.start/basic.start.main/p2f.cpp7
-rw-r--r--test/CXX/basic/basic.start/basic.start.main/p2g.cpp5
-rw-r--r--test/CXX/basic/basic.start/basic.start.main/p2h.cpp5
-rw-r--r--test/CXX/basic/basic.start/basic.start.main/p2i.cpp6
-rw-r--r--test/CXX/basic/basic.types/p10.cpp2
-rw-r--r--test/CXX/class.access/class.access.base/p5.cpp23
-rw-r--r--test/CXX/class.access/class.friend/p3-cxx0x.cpp7
-rw-r--r--test/CXX/class.access/class.protected/p1.cpp7
-rw-r--r--test/CXX/class.derived/class.abstract/p16.cpp26
-rw-r--r--test/CXX/class.derived/class.virtual/p3-0x.cpp30
-rw-r--r--test/CXX/class/class.static/class.static.data/p3.cpp2
-rw-r--r--test/CXX/class/class.union/p1.cpp59
-rw-r--r--test/CXX/class/class.union/p2-0x.cpp2
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp101
-rw-r--r--test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p10.cpp9
-rw-r--r--test/CXX/dcl.dcl/dcl.attr/dcl.align/p5.cpp74
-rw-r--r--test/CXX/dcl.dcl/dcl.attr/dcl.align/p6.cpp86
-rw-r--r--test/CXX/dcl.dcl/dcl.attr/dcl.align/p7.cpp16
-rw-r--r--test/CXX/dcl.dcl/dcl.attr/dcl.align/p8.cpp6
-rw-r--r--test/CXX/dcl.dcl/dcl.attr/dcl.attr.depend/p1.cpp32
-rw-r--r--test/CXX/dcl.dcl/dcl.attr/dcl.attr.depend/p2.cpp14
-rw-r--r--test/CXX/dcl.dcl/dcl.attr/dcl.attr.noreturn/p1.cpp44
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp3
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp3
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp22
-rw-r--r--test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp22
-rw-r--r--test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p1.cpp25
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp33
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp8
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp14
-rw-r--r--test/CXX/dcl.decl/dcl.init/p5.cpp48
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp5
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p2.cpp4
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct/p8.cpp6
-rw-r--r--test/CXX/except/except.spec/p14-ir.cpp12
-rw-r--r--test/CXX/except/except.spec/p14.cpp11
-rw-r--r--test/CXX/except/except.spec/p9-noexcept.cpp7
-rw-r--r--test/CXX/expr/expr.const/p2-0x.cpp13
-rw-r--r--test/CXX/expr/expr.post/expr.call/p7-0x.cpp15
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp37
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p19.cpp2
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp3
-rw-r--r--test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp5
-rw-r--r--test/CXX/lex/lex.literal/lex.ext/p5.cpp7
-rw-r--r--test/CXX/lex/lex.pptoken/p3-0x.cpp4
-rw-r--r--test/CXX/over/over.oper/over.literal/p8.cpp3
-rw-r--r--test/CXX/special/class.copy/implicit-move.cpp2
-rw-r--r--test/CXX/special/class.copy/p12-0x.cpp216
-rw-r--r--test/CXX/special/class.copy/p18-cxx11.cpp62
-rw-r--r--test/CXX/special/class.copy/p23-cxx11.cpp2
-rw-r--r--test/CXX/special/class.copy/p25-0x.cpp202
-rw-r--r--test/CXX/special/class.copy/p28-cxx11.cpp19
-rw-r--r--test/CXX/special/class.ctor/p1.cpp14
-rw-r--r--test/CXX/special/class.ctor/p5-0x.cpp47
-rw-r--r--test/CXX/special/class.dtor/p3-0x.cpp6
-rw-r--r--test/CXX/special/class.dtor/p5-0x.cpp5
-rw-r--r--test/CXX/special/class.inhctor/elsewhere.cpp20
-rw-r--r--test/CXX/special/class.inhctor/p1.cpp31
-rw-r--r--test/CXX/special/class.inhctor/p2.cpp87
-rw-r--r--test/CXX/special/class.inhctor/p3.cpp12
-rw-r--r--test/CXX/special/class.inhctor/p4.cpp70
-rw-r--r--test/CXX/special/class.inhctor/p7.cpp12
-rw-r--r--test/CXX/special/class.inhctor/p8.cpp21
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/p5.cpp9
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/p5.mm9
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.arg.explicit/p3-0x.cpp21
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp21
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp3
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp13
-rw-r--r--test/CXX/temp/temp.res/temp.dep/p3.cpp47
-rw-r--r--test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp5
-rw-r--r--test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp2
-rw-r--r--test/CodeCompletion/constexpr.cpp13
-rw-r--r--test/CodeGen/2006-01-13-StackSave.c4
-rw-r--r--test/CodeGen/2007-06-18-SextAttrAggregate.c8
-rw-r--r--test/CodeGen/2008-01-07-UnusualIntSize.c7
-rw-r--r--test/CodeGen/2008-04-08-NoExceptions.c6
-rw-r--r--test/CodeGen/2008-07-30-implicit-initialization.c14
-rw-r--r--test/CodeGen/2008-07-31-promotion-of-compound-pointer-arithmetic.c8
-rw-r--r--test/CodeGen/2009-10-20-GlobalDebug.c4
-rw-r--r--test/CodeGen/2010-02-16-DbgScopes.c6
-rw-r--r--test/CodeGen/2010-03-5-LexicalScope.c4
-rw-r--r--test/CodeGen/PR4611-bitfield-layout.c5
-rw-r--r--test/CodeGen/a5.c5
-rw-r--r--test/CodeGen/aarch64-arguments.c194
-rw-r--r--test/CodeGen/aarch64-inline-asm.c56
-rw-r--r--test/CodeGen/aarch64-type-sizes.c90
-rw-r--r--test/CodeGen/aarch64-varargs.c238
-rw-r--r--test/CodeGen/address-safety-attr.cpp83
-rw-r--r--test/CodeGen/address-space-field1.c4
-rw-r--r--test/CodeGen/alias.c14
-rw-r--r--test/CodeGen/always-inline.c5
-rw-r--r--test/CodeGen/arm-asm-warn.c23
-rw-r--r--test/CodeGen/arm-neon-fma.c19
-rw-r--r--test/CodeGen/atomic_ops.c5
-rw-r--r--test/CodeGen/atomics-inlining.c49
-rw-r--r--test/CodeGen/attr-coldhot.c4
-rw-r--r--test/CodeGen/attr-minsize.cpp40
-rw-r--r--test/CodeGen/attr-naked.c6
-rw-r--r--test/CodeGen/attributes.c23
-rw-r--r--test/CodeGen/bitfield-2.c46
-rw-r--r--test/CodeGen/blocks-seq.c18
-rw-r--r--test/CodeGen/bool_test.c16
-rw-r--r--test/CodeGen/bounds-checking.c2
-rw-r--r--test/CodeGen/builtin-attributes.c4
-rw-r--r--test/CodeGen/builtins-arm.c7
-rw-r--r--test/CodeGen/builtins-mips.c7
-rw-r--r--test/CodeGen/builtins-multiprecision.c150
-rw-r--r--test/CodeGen/builtins-ppc-altivec.c28
-rw-r--r--test/CodeGen/builtins-ppc.c9
-rw-r--r--test/CodeGen/builtinshufflevector2.c8
-rw-r--r--test/CodeGen/c-strings.c33
-rw-r--r--test/CodeGen/c11atomics-ios.c214
-rw-r--r--test/CodeGen/c11atomics.c344
-rw-r--r--test/CodeGen/catch-undef-behavior.c253
-rw-r--r--test/CodeGen/code-coverage.c30
-rw-r--r--test/CodeGen/complex-convert.c717
-rw-r--r--test/CodeGen/compound-assign-overflow.c36
-rw-r--r--test/CodeGen/compound-literal.c34
-rw-r--r--test/CodeGen/debug-info-args.c4
-rw-r--r--test/CodeGen/debug-info-line.c6
-rw-r--r--test/CodeGen/debug-info-scope.c4
-rw-r--r--test/CodeGen/debug-info-static.c2
-rw-r--r--test/CodeGen/debug-info-vector.c7
-rw-r--r--test/CodeGen/exceptions.c9
-rw-r--r--test/CodeGen/fast-math.c11
-rw-r--r--test/CodeGen/finite-math.c11
-rw-r--r--test/CodeGen/frame-pointer-elim.c40
-rw-r--r--test/CodeGen/function-attributes.c51
-rw-r--r--test/CodeGen/functions.c2
-rw-r--r--test/CodeGen/global-blocks-lines.c45
-rw-r--r--test/CodeGen/incomplete-function-type-2.c19
-rw-r--r--test/CodeGen/init.c2
-rw-r--r--test/CodeGen/inline.c94
-rw-r--r--test/CodeGen/intel_ocl_bicc.c11
-rw-r--r--test/CodeGen/le32-regparm.c2
-rw-r--r--test/CodeGen/libcall-declarations.c208
-rw-r--r--test/CodeGen/libcalls-complex.c46
-rw-r--r--test/CodeGen/libcalls.c77
-rw-r--r--test/CodeGen/lifetime2.c17
-rw-r--r--test/CodeGen/linkage-redecl.c10
-rw-r--r--test/CodeGen/mips-constraint-regs.c12
-rw-r--r--test/CodeGen/mips-constraints-mem.c26
-rw-r--r--test/CodeGen/mips-target-data.c14
-rw-r--r--test/CodeGen/mips-vector-arg.c11
-rw-r--r--test/CodeGen/mips16-attr.c17
-rw-r--r--test/CodeGen/mips64-padding-arg.c32
-rw-r--r--test/CodeGen/mrtd.c4
-rw-r--r--test/CodeGen/ms-declspecs.c14
-rw-r--r--test/CodeGen/ms-inline-asm-64.c8
-rw-r--r--test/CodeGen/ms-inline-asm.c260
-rw-r--r--test/CodeGen/ms-inline-asm.cpp26
-rw-r--r--test/CodeGen/mult-alt-generic.c1
-rw-r--r--test/CodeGen/no-opt-volatile-memcpy.c40
-rw-r--r--test/CodeGen/nvptx-cpus.c11
-rw-r--r--test/CodeGen/packed-nest-unpacked.c2
-rw-r--r--test/CodeGen/packed-structure.c1
-rw-r--r--test/CodeGen/parameter-passing.c12
-rw-r--r--test/CodeGen/ppc-atomics.c35
-rw-r--r--test/CodeGen/ppc64-complex-parms.c184
-rw-r--r--test/CodeGen/ppc64-complex-return.c129
-rw-r--r--test/CodeGen/ppc64-extend.c9
-rw-r--r--test/CodeGen/ppc64-varargs-complex.c73
-rw-r--r--test/CodeGen/pr2394.c3
-rw-r--r--test/CodeGen/pragma-weak.c9
-rw-r--r--test/CodeGen/prefetchw-builtins.c12
-rw-r--r--test/CodeGen/r5.c5
-rw-r--r--test/CodeGen/rdrand-builtins.c25
-rw-r--r--test/CodeGen/regparm.c2
-rw-r--r--test/CodeGen/rtm-builtins.c5
-rw-r--r--test/CodeGen/sanitize-init-order.cpp24
-rw-r--r--test/CodeGen/sanitize-recover.c17
-rw-r--r--test/CodeGen/sanitize-thread-attr.cpp61
-rw-r--r--test/CodeGen/sanitize-use-after-scope.c22
-rw-r--r--test/CodeGen/split-debug-filename.c7
-rw-r--r--test/CodeGen/stack-protector.c16
-rw-r--r--test/CodeGen/string-literal.c75
-rw-r--r--test/CodeGen/struct-passing.c7
-rw-r--r--test/CodeGen/tbaa-struct.cpp29
-rw-r--r--test/CodeGen/tbaa.cpp217
-rw-r--r--test/CodeGen/ubsan-blacklist.c31
-rw-r--r--test/CodeGen/ucn-identifiers.c14
-rw-r--r--test/CodeGen/unreachable.c4
-rw-r--r--test/CodeGen/unsigned-overflow.c125
-rw-r--r--test/CodeGen/unsigned-promotion.c143
-rw-r--r--test/CodeGen/unsigned-trapv.c38
-rw-r--r--test/CodeGen/unwind-attr.c17
-rw-r--r--test/CodeGen/visibility.c7
-rw-r--r--test/CodeGen/vla.c6
-rw-r--r--test/CodeGen/volatile.c123
-rw-r--r--test/CodeGen/x86_32-arguments-darwin.c9
-rw-r--r--test/CodeGen/x86_32-arguments-linux.c4
-rw-r--r--test/CodeGen/x86_32-inline-asm.c24
-rw-r--r--test/CodeGen/x86_64-arguments.c38
-rw-r--r--test/CodeGenCUDA/ptx-kernels.cu10
-rw-r--r--test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp18
-rw-r--r--test/CodeGenCXX/2009-12-23-MissingSext.cpp10
-rw-r--r--test/CodeGenCXX/2010-07-23-DeclLoc.cpp4
-rw-r--r--test/CodeGenCXX/aarch64-arguments.cpp5
-rw-r--r--test/CodeGenCXX/aarch64-cxxabi.cpp96
-rw-r--r--test/CodeGenCXX/arm.cpp70
-rw-r--r--test/CodeGenCXX/assign-operator.cpp26
-rw-r--r--test/CodeGenCXX/attr.cpp12
-rw-r--r--test/CodeGenCXX/bitfield.cpp428
-rw-r--r--test/CodeGenCXX/blocks-cxx11.cpp30
-rw-r--r--test/CodeGenCXX/blocks.cpp33
-rw-r--r--test/CodeGenCXX/bool-bitfield.cpp14
-rw-r--r--test/CodeGenCXX/builtins.cpp2
-rw-r--r--test/CodeGenCXX/c-linkage.cpp20
-rw-r--r--test/CodeGenCXX/catch-undef-behavior.cpp210
-rw-r--r--test/CodeGenCXX/constructor-alias.cpp12
-rw-r--r--test/CodeGenCXX/constructor-destructor-return-this.cpp60
-rw-r--r--test/CodeGenCXX/copy-assign-synthesis-1.cpp6
-rw-r--r--test/CodeGenCXX/coverage.cpp7
-rw-r--r--test/CodeGenCXX/cp-blocks-linetables.cpp61
-rw-r--r--test/CodeGenCXX/cxx0x-delegating-ctors.cpp38
-rw-r--r--test/CodeGenCXX/cxx0x-initializer-array.cpp103
-rw-r--r--test/CodeGenCXX/cxx11-exception-spec.cpp71
-rw-r--r--test/CodeGenCXX/cxx11-noreturn.cpp10
-rw-r--r--test/CodeGenCXX/cxx11-trivial-initializer-struct.cpp21
-rw-r--r--test/CodeGenCXX/debug-info-artificial-arg.cpp11
-rw-r--r--test/CodeGenCXX/debug-info-byval.cpp2
-rw-r--r--test/CodeGenCXX/debug-info-char16.cpp2
-rw-r--r--test/CodeGenCXX/debug-info-class.cpp44
-rw-r--r--test/CodeGenCXX/debug-info-dup-fwd-decl.cpp6
-rw-r--r--test/CodeGenCXX/debug-info-enum-class.cpp8
-rw-r--r--test/CodeGenCXX/debug-info-flex-member.cpp2
-rw-r--r--test/CodeGenCXX/debug-info-fwd-ref.cpp9
-rw-r--r--test/CodeGenCXX/debug-info-method.cpp25
-rw-r--r--test/CodeGenCXX/debug-info-namespace.cpp21
-rw-r--r--test/CodeGenCXX/debug-info-nullptr.cpp2
-rw-r--r--test/CodeGenCXX/debug-info-pubtypes.cpp4
-rw-r--r--test/CodeGenCXX/debug-info-rvalue-ref.cpp2
-rw-r--r--test/CodeGenCXX/debug-info-same-line.cpp98
-rw-r--r--test/CodeGenCXX/debug-info-static-fns.cpp2
-rw-r--r--test/CodeGenCXX/debug-info-static-member.cpp41
-rw-r--r--test/CodeGenCXX/debug-info-template-member.cpp6
-rw-r--r--test/CodeGenCXX/debug-info-template-quals.cpp20
-rw-r--r--test/CodeGenCXX/debug-info-union-template.cpp15
-rw-r--r--test/CodeGenCXX/debug-info-union.cpp8
-rw-r--r--test/CodeGenCXX/debug-info-use-after-free.cpp3
-rw-r--r--test/CodeGenCXX/debug-info-zero-length-arrays.cpp12
-rw-r--r--test/CodeGenCXX/debug-lambda-expressions.cpp50
-rw-r--r--test/CodeGenCXX/debug-lambda-this.cpp2
-rw-r--r--test/CodeGenCXX/default-destructor-synthesis.cpp4
-rw-r--r--test/CodeGenCXX/delete.cpp4
-rw-r--r--test/CodeGenCXX/derived-to-base.cpp6
-rw-r--r--test/CodeGenCXX/destructors.cpp10
-rw-r--r--test/CodeGenCXX/dynamic-cast-always-null.cpp4
-rw-r--r--test/CodeGenCXX/dynamic-cast-hint.cpp53
-rw-r--r--test/CodeGenCXX/dynamic-cast.cpp7
-rw-r--r--test/CodeGenCXX/eh.cpp23
-rw-r--r--test/CodeGenCXX/exception-spec-decay.cpp33
-rw-r--r--test/CodeGenCXX/exceptions.cpp82
-rw-r--r--test/CodeGenCXX/extern-c.cpp32
-rw-r--r--test/CodeGenCXX/global-array-destruction.cpp17
-rw-r--r--test/CodeGenCXX/global-dtor-no-atexit.cpp10
-rw-r--r--test/CodeGenCXX/global-init.cpp4
-rw-r--r--test/CodeGenCXX/implicit-copy-assign-operator.cpp2
-rw-r--r--test/CodeGenCXX/implicit-copy-constructor.cpp5
-rw-r--r--test/CodeGenCXX/inheriting-constructor.cpp11
-rw-r--r--test/CodeGenCXX/key-function-vtable.cpp3
-rw-r--r--test/CodeGenCXX/lambda-expressions.cpp33
-rw-r--r--test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp4
-rw-r--r--test/CodeGenCXX/mangle-ms-templates.cpp13
-rw-r--r--test/CodeGenCXX/mangle-ms-vector-types.cpp33
-rw-r--r--test/CodeGenCXX/mangle-ms.cpp11
-rw-r--r--test/CodeGenCXX/mangle.cpp25
-rw-r--r--test/CodeGenCXX/member-functions.cpp63
-rw-r--r--test/CodeGenCXX/member-initializers.cpp5
-rw-r--r--test/CodeGenCXX/microsoft-abi-array-cookies.cpp4
-rw-r--r--test/CodeGenCXX/microsoft-abi-constructors.cpp24
-rw-r--r--test/CodeGenCXX/microsoft-abi-default-cc.cpp4
-rwxr-xr-xtest/CodeGenCXX/microsoft-abi-member-pointers.cpp51
-rw-r--r--test/CodeGenCXX/microsoft-abi-static-initializers.cpp10
-rw-r--r--test/CodeGenCXX/microsoft-abi-structors.cpp215
-rw-r--r--test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp113
-rw-r--r--test/CodeGenCXX/no-exceptions.cpp4
-rw-r--r--test/CodeGenCXX/no-opt-volatile-memcpy.cpp50
-rw-r--r--test/CodeGenCXX/noinline-template.cpp4
-rw-r--r--test/CodeGenCXX/nrvo.cpp7
-rw-r--r--test/CodeGenCXX/pod-member-memcpys.cpp256
-rw-r--r--test/CodeGenCXX/pointers-to-data-members.cpp6
-rw-r--r--test/CodeGenCXX/pragma-weak.cpp31
-rw-r--r--test/CodeGenCXX/predefined-expr.cpp2
-rw-r--r--test/CodeGenCXX/reference-cast.cpp4
-rw-r--r--test/CodeGenCXX/references.cpp9
-rw-r--r--test/CodeGenCXX/runtimecc.cpp53
-rw-r--r--test/CodeGenCXX/sizeof-unwind-exception.cpp15
-rw-r--r--test/CodeGenCXX/temp-order.cpp2
-rw-r--r--test/CodeGenCXX/template-anonymous-types.cpp16
-rw-r--r--test/CodeGenCXX/template-linkage.cpp20
-rw-r--r--test/CodeGenCXX/temporaries.cpp21
-rw-r--r--test/CodeGenCXX/threadsafe-statics.cpp8
-rw-r--r--test/CodeGenCXX/thunks.cpp4
-rw-r--r--test/CodeGenCXX/trivial-constructor-init.cpp18
-rw-r--r--test/CodeGenCXX/type_visibility.cpp170
-rw-r--r--test/CodeGenCXX/typeid.cpp4
-rw-r--r--test/CodeGenCXX/value-init.cpp6
-rw-r--r--test/CodeGenCXX/virtual-base-cast.cpp8
-rw-r--r--test/CodeGenCXX/virtual-function-calls.cpp15
-rw-r--r--test/CodeGenCXX/visibility-inlines-hidden.cpp29
-rw-r--r--test/CodeGenCXX/visibility-ms-compat.cpp112
-rw-r--r--test/CodeGenCXX/visibility.cpp217
-rw-r--r--test/CodeGenCXX/vtable-available-externally.cpp9
-rw-r--r--test/CodeGenCXX/vtable-key-function-arm.cpp307
-rw-r--r--test/CodeGenCXX/vtable-key-function-ios.cpp189
-rw-r--r--test/CodeGenCXX/vtable-linkage.cpp26
-rw-r--r--test/CodeGenObjC/arc-arm.m4
-rw-r--r--test/CodeGenObjC/arc-block-copy-escape.m6
-rw-r--r--test/CodeGenObjC/arc-blocks.m63
-rw-r--r--test/CodeGenObjC/arc-captured-32bit-block-var-layout-2.m50
-rw-r--r--test/CodeGenObjC/arc-captured-32bit-block-var-layout.m59
-rw-r--r--test/CodeGenObjC/arc-captured-block-var-inlined-layout.m68
-rw-r--r--test/CodeGenObjC/arc-captured-block-var-layout.m66
-rw-r--r--test/CodeGenObjC/arc-exceptions.m14
-rw-r--r--test/CodeGenObjC/arc-foreach.m16
-rw-r--r--test/CodeGenObjC/arc-literals.m91
-rw-r--r--test/CodeGenObjC/arc-loadweakretained-release.m77
-rw-r--r--test/CodeGenObjC/arc-no-arc-exceptions.m6
-rw-r--r--test/CodeGenObjC/arc-precise-lifetime.m120
-rw-r--r--test/CodeGenObjC/arc-property.m55
-rw-r--r--test/CodeGenObjC/arc-related-result-type.m4
-rw-r--r--test/CodeGenObjC/arc-ternary-op.m138
-rw-r--r--test/CodeGenObjC/arc-unopt.m4
-rw-r--r--test/CodeGenObjC/arc-unoptimized-byref-var.m16
-rw-r--r--test/CodeGenObjC/arc-weak-property.m2
-rw-r--r--test/CodeGenObjC/arc-with-atthrow.m4
-rw-r--r--test/CodeGenObjC/arc.m307
-rw-r--r--test/CodeGenObjC/attr-exception.m27
-rw-r--r--test/CodeGenObjC/bitfield-access.m16
-rw-r--r--test/CodeGenObjC/bitfield-ivar-offsets.m1
-rw-r--r--test/CodeGenObjC/block-byref-variable-layout.m49
-rw-r--r--test/CodeGenObjC/block-var-layout.m20
-rw-r--r--test/CodeGenObjC/blocks.m39
-rw-r--r--test/CodeGenObjC/boxing.m12
-rw-r--r--test/CodeGenObjC/catch-lexical-block.m3
-rw-r--r--test/CodeGenObjC/complex-double-abi.m9
-rw-r--r--test/CodeGenObjC/debug-info-block-captured-self.m70
-rw-r--r--test/CodeGenObjC/debug-info-block-helper.m2
-rw-r--r--test/CodeGenObjC/debug-info-block-line.m89
-rw-r--r--test/CodeGenObjC/debug-info-blocks.m20
-rw-r--r--test/CodeGenObjC/debug-info-fwddecl.m2
-rw-r--r--test/CodeGenObjC/debug-info-id-with-protocol.m41
-rw-r--r--test/CodeGenObjC/debug-info-impl.m2
-rw-r--r--test/CodeGenObjC/debug-info-ivars-extension.m33
-rw-r--r--test/CodeGenObjC/debug-info-ivars-indirect.m32
-rw-r--r--test/CodeGenObjC/debug-info-ivars-private.m36
-rw-r--r--test/CodeGenObjC/debug-info-ivars.m14
-rw-r--r--test/CodeGenObjC/debug-info-property3.m2
-rw-r--r--test/CodeGenObjC/debug-info-pubtypes.m2
-rw-r--r--test/CodeGenObjC/debug-info-self.m13
-rw-r--r--test/CodeGenObjC/debug-info-static-var.m10
-rw-r--r--test/CodeGenObjC/debug-info-synthesis.m4
-rw-r--r--test/CodeGenObjC/encode-test-6.m18
-rw-r--r--test/CodeGenObjC/encode-test.m4
-rw-r--r--test/CodeGenObjC/exceptions.m4
-rw-r--r--test/CodeGenObjC/extended-block-signature-encode.m15
-rw-r--r--test/CodeGenObjC/externally-initialized-selectors.m8
-rw-r--r--test/CodeGenObjC/gc.m4
-rw-r--r--test/CodeGenObjC/gnu-exceptions.m7
-rw-r--r--test/CodeGenObjC/interface-layout-64.m1
-rw-r--r--test/CodeGenObjC/ivar-invariant.m68
-rw-r--r--test/CodeGenObjC/metadata-symbols-32.m3
-rw-r--r--test/CodeGenObjC/metadata-symbols-64.m3
-rw-r--r--test/CodeGenObjC/mrr-captured-block-var-inlined-layout.m36
-rw-r--r--test/CodeGenObjC/non-lazy-classes.m1
-rw-r--r--test/CodeGenObjC/nonlazy-msgSend.m6
-rw-r--r--test/CodeGenObjC/ns_consume_null_check.m79
-rw-r--r--test/CodeGenObjC/objc-align.m1
-rw-r--r--test/CodeGenObjC/objc-arc-container-subscripting.m5
-rw-r--r--test/CodeGenObjC/objc-literal-debugger-test.m4
-rw-r--r--test/CodeGenObjC/objc-literal-tests.m4
-rw-r--r--test/CodeGenObjC/optimized-setter.m1
-rw-r--r--test/CodeGenObjC/property.m3
-rw-r--r--test/CodeGenObjC/protocols-lazy.m1
-rw-r--r--test/CodeGenObjC/reorder-synthesized-ivars.m58
-rw-r--r--test/CodeGenObjCXX/address-safety-attr.mm17
-rw-r--r--test/CodeGenObjCXX/arc-attrs.mm48
-rw-r--r--test/CodeGenObjCXX/arc-blocks.mm49
-rw-r--r--test/CodeGenObjCXX/arc-exceptions.mm67
-rw-r--r--test/CodeGenObjCXX/arc-new-delete.mm5
-rw-r--r--test/CodeGenObjCXX/arc.mm9
-rw-r--r--test/CodeGenObjCXX/block-var-layout.mm21
-rw-r--r--test/CodeGenObjCXX/exceptions-legacy.mm80
-rw-r--r--test/CodeGenObjCXX/exceptions.mm20
-rw-r--r--test/CodeGenObjCXX/externally-initialized-selectors.mm8
-rw-r--r--test/CodeGenObjCXX/lambda-expressions.mm8
-rw-r--r--test/CodeGenObjCXX/message.mm24
-rw-r--r--test/CodeGenObjCXX/pr14474-gline-tables-only.mm25
-rw-r--r--test/CodeGenObjCXX/property-object-reference-2.mm4
-rw-r--r--test/CodeGenObjCXX/unknown-anytype.mm20
-rw-r--r--test/CodeGenOpenCL/addr-space-struct-arg.cl23
-rw-r--r--test/CodeGenOpenCL/event_t.cl12
-rw-r--r--test/CodeGenOpenCL/half.cl15
-rw-r--r--test/CodeGenOpenCL/kernel-arg-info.cl19
-rw-r--r--test/CodeGenOpenCL/kernel-attributes.cl12
-rw-r--r--test/CodeGenOpenCL/local.cl5
-rw-r--r--test/CodeGenOpenCL/logical-ops.cl56
-rw-r--r--test/CodeGenOpenCL/opencl_types.cl37
-rw-r--r--test/CodeGenOpenCL/ptx-calls.cl7
-rw-r--r--test/CodeGenOpenCL/ptx-kernels.cl5
-rw-r--r--test/CodeGenOpenCL/shifts.cl57
-rw-r--r--test/CodeGenOpenCL/spir32_target.cl22
-rw-r--r--test/CodeGenOpenCL/spir64_target.cl21
-rw-r--r--test/Coverage/objc-language-features.inc1
-rw-r--r--test/Driver/Inputs/basic_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtbeginT.o0
-rwxr-xr-xtest/Driver/Inputs/hexagon_tree/gnu/bin/hexagon-as1
-rwxr-xr-xtest/Driver/Inputs/hexagon_tree/gnu/bin/hexagon-gcc1
-rwxr-xr-xtest/Driver/Inputs/hexagon_tree/gnu/bin/hexagon-ld1
-rw-r--r--test/Driver/Inputs/hexagon_tree/gnu/hexagon/include/c++/4.4.0/ios1
-rw-r--r--test/Driver/Inputs/hexagon_tree/gnu/hexagon/include/stdio.h1
-rw-r--r--test/Driver/Inputs/hexagon_tree/gnu/lib/gcc/hexagon/4.4.0/include-fixed/limits.h1
-rw-r--r--test/Driver/Inputs/hexagon_tree/gnu/lib/gcc/hexagon/4.4.0/include/stddef.h1
-rw-r--r--test/Driver/Inputs/hexagon_tree/qc/bin/placeholder1
-rw-r--r--test/Driver/Inputs/lit.local.cfg1
-rw-r--r--test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.asan-i386.a.syms0
-rw-r--r--test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.asan-x86_64.a.syms0
-rw-r--r--test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.msan-x86_64.a.syms0
-rw-r--r--test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.tsan-x86_64.a.syms0
-rw-r--r--test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.ubsan-i386.a.syms0
-rw-r--r--test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.ubsan-x86_64.a.syms0
-rw-r--r--test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.ubsan_cxx-i386.a.syms0
-rw-r--r--test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.ubsan_cxx-x86_64.a.syms0
-rw-r--r--test/Driver/Inputs/ubuntu_13.04_multiarch_tree/lib/x86_64-linux-gnu/.keep0
-rw-r--r--test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/include/c++/4.7/backward/.keep0
-rw-r--r--test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/include/x86_64-linux-gnu/c++/4.7/.keep0
-rw-r--r--test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/include/x86_64-linux-gnu/c++/4.7/32/.keep0
-rw-r--r--test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/lib/gcc/x86_64-linux-gnu/4.7/32/.keep0
-rw-r--r--test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/lib/gcc/x86_64-linux-gnu/4.7/32/crtbegin.o0
-rw-r--r--test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/lib/gcc/x86_64-linux-gnu/4.7/crtbegin.o0
-rw-r--r--test/Driver/aarch64-features.c5
-rw-r--r--test/Driver/altivec.cpp15
-rw-r--r--test/Driver/apple-kext-mkernel.c3
-rw-r--r--test/Driver/arm-cortex-cpus.c8
-rw-r--r--test/Driver/asan-ld.c50
-rw-r--r--test/Driver/bounds-checking.c16
-rw-r--r--test/Driver/claim-unused.c3
-rw-r--r--test/Driver/clang-g-opts.c14
-rw-r--r--test/Driver/clang-translation.c102
-rw-r--r--test/Driver/clang_f_opts.c32
-rw-r--r--test/Driver/constructors.c50
-rw-r--r--test/Driver/crash-report.c2
-rw-r--r--test/Driver/darwin-debug-flags.c4
-rw-r--r--test/Driver/darwin-iphone-defaults.m3
-rw-r--r--test/Driver/darwin-sanitizer-ld.c52
-rw-r--r--test/Driver/darwin-sdkroot.c15
-rw-r--r--test/Driver/debug-comp-dir.S11
-rw-r--r--test/Driver/debug-main-file.S12
-rw-r--r--test/Driver/debug-options-as.c17
-rw-r--r--test/Driver/fast-math.c2
-rw-r--r--test/Driver/fcomment-block-commands.c8
-rw-r--r--test/Driver/flags.c11
-rw-r--r--test/Driver/frame-pointer-elim.c30
-rw-r--r--test/Driver/freebsd-mips-as.c18
-rw-r--r--test/Driver/freebsd.c11
-rw-r--r--test/Driver/fsanitize-blacklist.c18
-rw-r--r--test/Driver/fsanitize.c115
-rw-r--r--test/Driver/gold-lto.c25
-rw-r--r--test/Driver/hexagon-toolchain-elf.c564
-rw-r--r--test/Driver/hexagon-toolchain.c564
-rw-r--r--test/Driver/inhibit-downstream-commands.c6
-rw-r--r--test/Driver/integrated-as.c7
-rw-r--r--test/Driver/integrated-as.s6
-rw-r--r--test/Driver/linker-opts.c3
-rw-r--r--test/Driver/linux-header-search.cpp28
-rw-r--r--test/Driver/linux-ld.c57
-rw-r--r--test/Driver/lit.local.cfg1
-rw-r--r--test/Driver/mips-as.c18
-rw-r--r--test/Driver/mips-eleb.c31
-rw-r--r--test/Driver/mips-features.c12
-rw-r--r--test/Driver/mips-float.c41
-rw-r--r--test/Driver/mips-long-double.c19
-rw-r--r--test/Driver/modules.m6
-rw-r--r--test/Driver/modules_integrated_as.c6
-rw-r--r--test/Driver/ms-inline-asm.c15
-rw-r--r--test/Driver/no-integrated-as-win.c3
-rw-r--r--test/Driver/nodefaultlib.c4
-rw-r--r--test/Driver/objc++-cpp-output.mm6
-rw-r--r--test/Driver/objc_default_synth.m6
-rw-r--r--test/Driver/openbsd.c20
-rw-r--r--test/Driver/output-file-cleanup.c43
-rw-r--r--test/Driver/output-file-is-dir.c7
-rw-r--r--test/Driver/pic.c6
-rw-r--r--test/Driver/ppc-features.cpp88
-rw-r--r--test/Driver/qa_override.c10
-rw-r--r--test/Driver/r600-mcpu.cl50
-rw-r--r--test/Driver/sanitizer-ld.c151
-rw-r--r--test/Driver/split-debug.c25
-rw-r--r--test/Driver/target-as.s8
-rw-r--r--test/Driver/ubsan-ld.c10
-rw-r--r--test/Driver/unknown-arg.c4
-rw-r--r--test/Driver/unknown-gcc-arch.c40
-rw-r--r--test/Driver/visibility.cpp34
-rw-r--r--test/Driver/warning-options.cpp10
-rw-r--r--test/Driver/warning-options_pedantic.cpp2
-rw-r--r--test/Driver/x86_64-nacl-defines.cpp2
-rw-r--r--test/FixIt/auto-isa-fixit.m66
-rw-r--r--test/FixIt/bridge-cast-in-arc.mm19
-rw-r--r--test/FixIt/bridge-in-non-arc.m12
-rw-r--r--test/FixIt/fixit-c90.c2
-rw-r--r--test/FixIt/fixit-cxx0x.cpp14
-rw-r--r--test/FixIt/fixit-cxx11-attributes.cpp51
-rw-r--r--test/FixIt/fixit-errors-1.c1
-rw-r--r--test/FixIt/fixit-errors.c6
-rw-r--r--test/FixIt/fixit-newline-style.c11
-rw-r--r--test/FixIt/fixit-nsstring-compare.m22
-rw-r--r--test/FixIt/fixit-objc.m2
-rw-r--r--test/FixIt/fixit-unicode.c13
-rw-r--r--test/FixIt/fixit.cpp8
-rw-r--r--test/FixIt/format-darwin.m116
-rw-r--r--test/FixIt/format.m135
-rw-r--r--test/FixIt/format.mm30
-rw-r--r--test/FixIt/typo.c10
-rw-r--r--test/Format/basic.cpp6
-rw-r--r--test/Format/diagnostic.cpp4
-rw-r--r--test/Format/ranges.cpp11
-rw-r--r--test/Frontend/ast-main.cpp22
-rw-r--r--test/Frontend/dependency-gen-escaping.c17
-rw-r--r--test/Frontend/hexagon-target-basic.c9
-rw-r--r--test/Frontend/warning-options.cpp5
-rw-r--r--test/Headers/c11.c19
-rw-r--r--test/Headers/cxx11.cpp15
-rw-r--r--test/Headers/stdbool.cpp5
-rw-r--r--test/Index/IBOutletCollection.m6
-rw-r--r--test/Index/Inputs/CommentXML/invalid-para-kind-01.xml9
-rw-r--r--test/Index/Inputs/CommentXML/invalid-para-kind-02.xml9
-rw-r--r--test/Index/Inputs/CommentXML/valid-para-kind-01.xml27
-rw-r--r--test/Index/annotate-comments-availability-attrs.cpp25
-rw-r--r--test/Index/annotate-comments-property-accessor.m62
-rw-r--r--test/Index/annotate-comments-typedef.m49
-rw-r--r--test/Index/annotate-comments.cpp647
-rw-r--r--test/Index/annotate-context-sensitive.cpp2
-rw-r--r--test/Index/annotate-deep-statements.cpp3
-rw-r--r--test/Index/annotate-module.m12
-rw-r--r--test/Index/annotate-nested-name-specifier.cpp10
-rw-r--r--test/Index/annotate-tokens-cxx0x.cpp27
-rw-r--r--test/Index/annotate-tokens-pp.c37
-rw-r--r--test/Index/annotate-tokens.c94
-rw-r--r--test/Index/annotate-tokens.m2
-rw-r--r--test/Index/c-index-api-loadTU-test.m38
-rw-r--r--test/Index/c-index-getCursor-pp.c22
-rw-r--r--test/Index/c-index-getCursor-test.m2
-rw-r--r--test/Index/code-completion-skip-bodies.cpp12
-rw-r--r--test/Index/codecompletion-chained.cpp33
-rw-r--r--test/Index/comment-c-decls.c104
-rw-r--r--test/Index/comment-cplus-decls.cpp171
-rw-r--r--test/Index/comment-cplus-template-decls.cpp69
-rw-r--r--test/Index/comment-custom-block-command.cpp38
-rw-r--r--test/Index/comment-objc-decls.m175
-rw-r--r--test/Index/comment-to-html-xml-conversion.cpp797
-rw-r--r--test/Index/comment-xml-schema.c5
-rw-r--r--test/Index/complete-declarators.m17
-rw-r--r--test/Index/complete-documentation-properties.m92
-rw-r--r--test/Index/complete-driver-errors.c24
-rw-r--r--test/Index/complete-exprs.c2
-rw-r--r--test/Index/complete-lambdas.mm2
-rw-r--r--test/Index/complete-macro-args.c36
-rw-r--r--test/Index/complete-modules.m9
-rw-r--r--test/Index/complete-objc-message.m19
-rw-r--r--test/Index/complete-stmt.c11
-rw-r--r--test/Index/complete-super.m3
-rw-r--r--test/Index/crash-recovery-code-complete.c4
-rw-r--r--test/Index/crash-recovery-modules.m8
-rw-r--r--test/Index/crash-recovery-reparse.c1
-rw-r--r--test/Index/file-includes.c24
-rw-r--r--test/Index/fix-its.c2
-rw-r--r--test/Index/fix-its.m28
-rw-r--r--test/Index/format-comment-cdecls.c99
-rw-r--r--test/Index/getcursor-preamble.h8
-rw-r--r--test/Index/getcursor-preamble.m23
-rw-r--r--test/Index/headerfile-comment-to-html.m111
-rw-r--r--test/Index/index-file.cpp4
-rw-r--r--test/Index/index-module.m5
-rw-r--r--test/Index/index-pch-with-module.m4
-rw-r--r--test/Index/index-pch.cpp6
-rw-r--r--test/Index/index-suppress-refs.m2
-rw-r--r--test/Index/linkage.c8
-rw-r--r--test/Index/modules-objc-categories.m10
-rw-r--r--test/Index/overriding-ftemplate-comments.cpp47
-rw-r--r--test/Index/overriding-method-comments.mm73
-rw-r--r--test/Index/preamble_macro_template.cpp4
-rw-r--r--test/Index/print-bitwidth.c25
-rw-r--r--test/Index/print-type.c44
-rw-r--r--test/Index/print-type.cpp61
-rw-r--r--test/Index/print-type.m10
-rw-r--r--test/Index/print-typekind.c28
-rw-r--r--test/Index/print-typekind.m10
-rw-r--r--test/Index/recursive-cxx-member-calls.cpp52
-rw-r--r--test/Index/skip-parsed-bodies/compile_commands.json71
-rw-r--r--test/Index/skip-parsed-bodies/imported.h5
-rw-r--r--test/Index/skip-parsed-bodies/lit.local.cfg1
-rw-r--r--test/Index/skip-parsed-bodies/pragma_once.h10
-rw-r--r--test/Index/skip-parsed-bodies/t.h30
-rw-r--r--test/Index/skip-parsed-bodies/t1.cpp1
-rw-r--r--test/Index/skip-parsed-bodies/t2.cpp3
-rw-r--r--test/Index/skip-parsed-bodies/t3.cpp3
-rw-r--r--test/Index/usrs.cpp6
-rw-r--r--test/Index/vector-types.c6
-rw-r--r--test/Lexer/badstring_in_if0.c3
-rw-r--r--test/Lexer/builtin_redef.c19
-rw-r--r--test/Lexer/c90.c9
-rw-r--r--test/Lexer/char-literal.cpp18
-rw-r--r--test/Lexer/counter.c13
-rw-r--r--test/Lexer/cxx0x_raw_string_directives.cpp9
-rw-r--r--test/Lexer/has_feature_memory_sanitizer.cpp11
-rw-r--r--test/Lexer/has_feature_thread_sanitizer.cpp11
-rw-r--r--test/Lexer/pragma-message.c2
-rw-r--r--test/Lexer/pragma-operators.cpp20
-rw-r--r--test/Lexer/pragma-region.c33
-rw-r--r--test/Lexer/string_concat.cpp15
-rw-r--r--test/Lexer/token-concat-2.c4
-rw-r--r--test/Lexer/token-concat.c11
-rw-r--r--test/Lexer/unicode-strings.c21
-rw-r--r--test/Lexer/unicode.c26
-rw-r--r--test/Lexer/unknown-char.c4
-rw-r--r--test/Lexer/utf8-char-literal.cpp1
-rw-r--r--test/Lexer/utf8-invalid.c15
-rw-r--r--test/Misc/ast-dump-attr.cpp97
-rw-r--r--test/Misc/ast-dump-color.cpp87
-rw-r--r--test/Misc/ast-dump-comment.cpp69
-rw-r--r--test/Misc/ast-dump-decl.c152
-rw-r--r--test/Misc/ast-dump-decl.cpp457
-rw-r--r--test/Misc/ast-dump-decl.m136
-rw-r--r--test/Misc/ast-dump-decl.mm23
-rw-r--r--test/Misc/ast-dump-stmt.c24
-rw-r--r--test/Misc/ast-dump-stmt.cpp14
-rw-r--r--test/Misc/ast-dump-stmt.m14
-rw-r--r--test/Misc/ast-dump-templates.cpp6
-rw-r--r--test/Misc/ast-dump-wchar.cpp8
-rw-r--r--test/Misc/caret-diags-macros.c108
-rw-r--r--test/Misc/dev-fd-fs.c32
-rw-r--r--test/Misc/diag-line-wrapping.cpp12
-rw-r--r--test/Misc/diag-macro-backtrace.c17
-rw-r--r--test/Misc/diag-presumed.c36
-rw-r--r--test/Misc/diag-template-diffing-color.cpp42
-rw-r--r--test/Misc/diag-template-diffing-cxx98.cpp49
-rw-r--r--test/Misc/diag-template-diffing.cpp258
-rw-r--r--test/Misc/diagnostic-crash.cpp39
-rw-r--r--test/Misc/freebsd-arm-size_t.c9
-rw-r--r--test/Misc/integer-literal-printing.cpp68
-rw-r--r--test/Misc/serialized-diags-frontend.c2
-rw-r--r--test/Misc/serialized-diags-no-category.c2
-rw-r--r--test/Misc/serialized-diags.c2
-rw-r--r--test/Misc/serialized-diags.m30
-rw-r--r--test/Misc/warning-flags.c7
-rw-r--r--test/Modules/Inputs/Conflicts/conflict_a.h1
-rw-r--r--test/Modules/Inputs/Conflicts/conflict_b.h1
-rw-r--r--test/Modules/Inputs/Conflicts/module.map10
-rw-r--r--test/Modules/Inputs/DependsOnModule.framework/DependsOnModule0
-rw-r--r--test/Modules/Inputs/HasSubModules.framework/Frameworks/Sub.framework/Headers/Sub.h1
-rw-r--r--test/Modules/Inputs/HasSubModules.framework/Frameworks/Sub.framework/Headers/Types.h4
-rw-r--r--test/Modules/Inputs/HasSubModules.framework/Frameworks/Sub.framework/PrivateHeaders/SubPriv.h3
-rw-r--r--test/Modules/Inputs/HasSubModules.framework/Headers/HasSubModules.h1
-rw-r--r--test/Modules/Inputs/HasSubModules.framework/PrivateHeaders/HasSubModulesPriv.h2
-rw-r--r--test/Modules/Inputs/MethodPoolA.h6
-rw-r--r--test/Modules/Inputs/MethodPoolASub.h6
-rw-r--r--test/Modules/Inputs/MethodPoolASub2.h3
-rw-r--r--test/Modules/Inputs/MethodPoolBSub.h4
-rw-r--r--test/Modules/Inputs/Modified/B.h3
-rw-r--r--test/Modules/Inputs/Modified/module.map7
-rw-r--r--test/Modules/Inputs/Module.framework/Module0
-rw-r--r--test/Modules/Inputs/MutuallyRecursive1.framework/Headers/MutuallyRecursive1.h2
-rw-r--r--test/Modules/Inputs/MutuallyRecursive2.framework/Headers/MutuallyRecursive2.h2
-rw-r--r--test/Modules/Inputs/NoUmbrella.framework/NoUmbrella0
-rw-r--r--test/Modules/Inputs/StdDef/module.map11
-rw-r--r--test/Modules/Inputs/StdDef/other.h2
-rw-r--r--test/Modules/Inputs/StdDef/size_t.h4
-rw-r--r--test/Modules/Inputs/autolink-sub.h1
-rw-r--r--test/Modules/Inputs/autolink-sub2.h1
-rw-r--r--test/Modules/Inputs/autolink.h1
-rw-r--r--test/Modules/Inputs/builtin.h3
-rw-r--r--test/Modules/Inputs/builtin_sub.h4
-rw-r--r--test/Modules/Inputs/category_bottom.h4
-rw-r--r--test/Modules/Inputs/category_left.h2
-rw-r--r--test/Modules/Inputs/category_left_sub.h11
-rw-r--r--test/Modules/Inputs/category_other.h2
-rw-r--r--test/Modules/Inputs/category_right.h2
-rw-r--r--test/Modules/Inputs/category_right_sub.h17
-rw-r--r--test/Modules/Inputs/category_top.h9
-rw-r--r--test/Modules/Inputs/config.h7
-rw-r--r--test/Modules/Inputs/cxx-inline-namespace.h11
-rw-r--r--test/Modules/Inputs/cxx-linkage-cache.h11
-rw-r--r--test/Modules/Inputs/cxx-many-overloads.h2004
-rw-r--r--test/Modules/Inputs/def.h9
-rw-r--r--test/Modules/Inputs/diag_pragma.h3
-rw-r--r--test/Modules/Inputs/diamond.h2
-rw-r--r--test/Modules/Inputs/diamond_bottom.h4
-rw-r--r--test/Modules/Inputs/diamond_left.h2
-rw-r--r--test/Modules/Inputs/diamond_right.h2
-rw-r--r--test/Modules/Inputs/ignored_macros.h8
-rw-r--r--test/Modules/Inputs/linkage-merge-bar.h3
-rw-r--r--test/Modules/Inputs/linkage-merge-foo.h2
-rw-r--r--test/Modules/Inputs/linkage-merge-sub.h11
-rw-r--r--test/Modules/Inputs/macros_left.h4
-rw-r--r--test/Modules/Inputs/macros_right.h4
-rw-r--r--test/Modules/Inputs/macros_top.h4
-rw-r--r--test/Modules/Inputs/module.map92
-rw-r--r--test/Modules/Inputs/namespaces-left.h9
-rw-r--r--test/Modules/Inputs/namespaces-right.h9
-rw-r--r--test/Modules/Inputs/oldname/module.map4
-rw-r--r--test/Modules/Inputs/oldname/new_name.h1
-rw-r--r--test/Modules/Inputs/redecl-merge-bottom-prefix.h4
-rw-r--r--test/Modules/Inputs/redecl-merge-bottom.h9
-rw-r--r--test/Modules/Inputs/redecl-merge-left-left.h2
-rw-r--r--test/Modules/Inputs/redecl-merge-left.h11
-rw-r--r--test/Modules/Inputs/redecl-merge-right.h7
-rw-r--r--test/Modules/Inputs/redecl-merge-top.h2
-rw-r--r--test/Modules/Inputs/templates-left.h2
-rw-r--r--test/Modules/Inputs/templates-right.h2
-rw-r--r--test/Modules/Inputs/weird_objc.h1
-rw-r--r--test/Modules/Inputs/wildcard-submodule-exports/C_one.h4
-rw-r--r--test/Modules/Inputs/wildcard-submodule-exports/C_two.h4
-rw-r--r--test/Modules/auto-module-import.m2
-rw-r--r--test/Modules/autolink.m40
-rw-r--r--test/Modules/build-fail-notes.m31
-rw-r--r--test/Modules/builtins.m16
-rw-r--r--test/Modules/compiler_builtins.m9
-rw-r--r--test/Modules/config_macros.m28
-rw-r--r--test/Modules/conflicts.m7
-rw-r--r--test/Modules/cstd.m10
-rw-r--r--test/Modules/cxx-inline-namespace.cpp6
-rw-r--r--test/Modules/cxx-linkage-cache.cpp8
-rw-r--r--test/Modules/cxx-many-overloads.cpp9
-rw-r--r--test/Modules/cycles.c17
-rw-r--r--test/Modules/decldef.m28
-rw-r--r--test/Modules/decldef.mm32
-rw-r--r--test/Modules/diag-pragma.c13
-rw-r--r--test/Modules/diamond-pch.c12
-rw-r--r--test/Modules/diamond.c12
-rw-r--r--test/Modules/direct-module-import.m2
-rw-r--r--test/Modules/driver.c8
-rw-r--r--test/Modules/epic-fail.m13
-rw-r--r--test/Modules/global_index.m19
-rw-r--r--test/Modules/header-import.m4
-rw-r--r--test/Modules/ignored_macros.m49
-rw-r--r--test/Modules/import-decl.cpp4
-rw-r--r--test/Modules/inferred-frameworks.m4
-rw-r--r--test/Modules/inferred-submodules.m6
-rw-r--r--test/Modules/irgen.c6
-rw-r--r--test/Modules/linkage-merge.cpp13
-rw-r--r--test/Modules/linkage-merge.m27
-rw-r--r--test/Modules/load_failure.c12
-rw-r--r--test/Modules/lookup.cpp12
-rw-r--r--test/Modules/lookup.m12
-rw-r--r--test/Modules/macros.c48
-rw-r--r--test/Modules/method_pool.m50
-rw-r--r--test/Modules/modify-module.m20
-rw-r--r--test/Modules/module-private.cpp10
-rw-r--r--test/Modules/module_file_info.m34
-rw-r--r--test/Modules/namespaces.cpp31
-rw-r--r--test/Modules/normal-module-map.cpp14
-rw-r--r--test/Modules/objc-categories.m72
-rw-r--r--test/Modules/objc_redef.m13
-rw-r--r--test/Modules/on-demand-build-warnings.m5
-rw-r--r--test/Modules/on-demand-build.m10
-rw-r--r--test/Modules/on-demand-macros.m6
-rw-r--r--test/Modules/prune.m46
-rw-r--r--test/Modules/redecl-merge.m33
-rw-r--r--test/Modules/redecl-merge2.m8
-rw-r--r--test/Modules/redecl-namespaces.mm10
-rw-r--r--test/Modules/redeclarations.m10
-rw-r--r--test/Modules/renamed.m8
-rw-r--r--test/Modules/requires.m4
-rw-r--r--test/Modules/stddef.m7
-rw-r--r--test/Modules/subframeworks.m17
-rw-r--r--test/Modules/submodules-preprocess.cpp12
-rw-r--r--test/Modules/submodules.cpp12
-rw-r--r--test/Modules/submodules.m4
-rw-r--r--test/Modules/templates.mm8
-rw-r--r--test/Modules/wildcard-submodule-exports.cpp8
-rw-r--r--test/OpenMP/linking.c16
-rw-r--r--test/OpenMP/no_option.c6
-rw-r--r--test/OpenMP/no_option_no_warn.c6
-rw-r--r--test/OpenMP/openmp_common.c9
-rw-r--r--test/OpenMP/option_warn.c5
-rw-r--r--test/OpenMP/predefined_macro.c34
-rw-r--r--test/OpenMP/threadprivate_ast_print.cpp43
-rw-r--r--test/OpenMP/threadprivate_messages.cpp119
-rw-r--r--test/PCH/Inputs/cxx-method.h3
-rw-r--r--test/PCH/chain-late-anonymous-namespace.cpp2
-rw-r--r--test/PCH/crash-12631281.cpp40
-rw-r--r--test/PCH/cxx-constexpr.cpp3
-rw-r--r--test/PCH/cxx-method.cpp6
-rw-r--r--test/PCH/cxx-templates.cpp8
-rw-r--r--test/PCH/cxx-templates.h49
-rw-r--r--test/PCH/cxx0x-default-delete.cpp12
-rw-r--r--test/PCH/floating-literal.c18
-rw-r--r--test/PCH/irgen-rdar13114142.mm39
-rw-r--r--test/PCH/macro-redef.c28
-rw-r--r--test/PCH/missing-file.cpp1
-rw-r--r--test/PCH/modified-header-crash.c5
-rw-r--r--test/PCH/modified-header-error.c2
-rw-r--r--test/PCH/multiple-include-pch.c18
-rw-r--r--test/PCH/objc_container.m5
-rw-r--r--test/PCH/objc_stmts.m10
-rw-r--r--test/PCH/ocl_types.cl26
-rw-r--r--test/PCH/ocl_types.h25
-rw-r--r--test/PCH/thread-safety-attrs.cpp317
-rw-r--r--test/PCH/undefined-internal.c15
-rw-r--r--test/Parser/MicrosoftExtensions.c5
-rw-r--r--test/Parser/asm.c6
-rw-r--r--test/Parser/atomic.c35
-rw-r--r--test/Parser/attr-availability.c2
-rw-r--r--test/Parser/attributes.mm25
-rw-r--r--test/Parser/c11-noreturn.c18
-rw-r--r--test/Parser/c1x-alignas.c2
-rw-r--r--test/Parser/crash-report.c9
-rw-r--r--test/Parser/cxx-casting.cpp6
-rw-r--r--test/Parser/cxx-class.cpp11
-rw-r--r--test/Parser/cxx-decl.cpp65
-rw-r--r--test/Parser/cxx-undeclared-identifier.cpp2
-rw-r--r--test/Parser/cxx0x-ambig.cpp24
-rw-r--r--test/Parser/cxx0x-attributes.cpp81
-rw-r--r--test/Parser/cxx0x-decl.cpp40
-rw-r--r--test/Parser/cxx11-base-spec-attributes.cpp10
-rw-r--r--test/Parser/cxx11-brace-initializers.cpp11
-rw-r--r--test/Parser/cxx11-stmt-attributes.cpp40
-rw-r--r--test/Parser/missing-closing-rbrace.m3
-rw-r--r--test/Parser/ms-inline-asm.c31
-rw-r--r--test/Parser/objcxx0x-lambda-expressions.mm2
-rw-r--r--test/Parser/objcxx11-attributes.mm12
-rw-r--r--test/Parser/objcxx11-protocol-in-template.mm15
-rw-r--r--test/Parser/opencl-image-access.cl2
-rw-r--r--test/Parser/parser_overflow.c14
-rw-r--r--test/Parser/placeholder-recovery.m2
-rw-r--r--test/Parser/prefix-attributes.m8
-rw-r--r--test/Parser/recovery.cpp7
-rw-r--r--test/Parser/warn-semicolon-before-method-body.m22
-rw-r--r--test/Preprocessor/_Pragma-dependency.c5
-rw-r--r--test/Preprocessor/_Pragma-physloc.c5
-rw-r--r--test/Preprocessor/aarch64-target-features.c30
-rw-r--r--test/Preprocessor/builtin_line.c6
-rw-r--r--test/Preprocessor/c90.c5
-rw-r--r--test/Preprocessor/disabled-cond-diags.c3
-rw-r--r--test/Preprocessor/feature_tests.c20
-rw-r--r--test/Preprocessor/first-line-indent.c7
-rw-r--r--test/Preprocessor/has_include.c66
-rw-r--r--test/Preprocessor/hash_line.c9
-rw-r--r--test/Preprocessor/init.c195
-rw-r--r--test/Preprocessor/invalid-__has_warning1.c5
-rw-r--r--test/Preprocessor/invalid-__has_warning2.c5
-rw-r--r--test/Preprocessor/iwithprefix.c17
-rw-r--r--test/Preprocessor/line-directive-output.c4
-rw-r--r--test/Preprocessor/macro-multiline.c.ignoreme (renamed from test/Preprocessor/macro-multiline.c)0
-rw-r--r--test/Preprocessor/macro_arg_slocentry_merge.c7
-rw-r--r--test/Preprocessor/macro_arg_slocentry_merge.h7
-rw-r--r--test/Preprocessor/macro_expand.c8
-rw-r--r--test/Preprocessor/macro_expandloc.c9
-rw-r--r--test/Preprocessor/macro_expandloc2.c6
-rw-r--r--test/Preprocessor/macro_fn.c12
-rw-r--r--test/Preprocessor/macro_misc.c14
-rw-r--r--test/Preprocessor/macro_rescan.c14
-rw-r--r--test/Preprocessor/macro_space.c3
-rw-r--r--test/Preprocessor/macro_variadic.cl3
-rw-r--r--test/Preprocessor/microsoft-import.c11
-rw-r--r--test/Preprocessor/output_paste_avoid.c33
-rw-r--r--test/Preprocessor/output_paste_avoid.cpp47
-rw-r--r--test/Preprocessor/pp-record.c11
-rw-r--r--test/Preprocessor/pragma_diagnostic.c2
-rw-r--r--test/Preprocessor/pragma_microsoft.c7
-rw-r--r--test/Preprocessor/pragma_unknown.c3
-rw-r--r--test/Preprocessor/predefined-arch-macros.c161
-rw-r--r--test/Preprocessor/predefined-macros.c18
-rw-r--r--test/Preprocessor/print_line_count.c5
-rw-r--r--test/Preprocessor/print_line_include.c6
-rw-r--r--test/Preprocessor/print_line_include.h1
-rw-r--r--test/Preprocessor/skipping_unclean.c3
-rw-r--r--test/Preprocessor/stringize_space.c12
-rw-r--r--test/Preprocessor/stringize_space2.c6
-rw-r--r--test/Preprocessor/traditional-cpp.c82
-rw-r--r--test/Preprocessor/ucn-allowed-chars.c78
-rw-r--r--test/Preprocessor/ucn-pp-identifier.c106
-rw-r--r--test/Preprocessor/utf8-allowed-chars.c68
-rw-r--r--test/Preprocessor/warn-disabled-macro-expansion.c10
-rw-r--r--test/Preprocessor/warning_tests.c27
-rw-r--r--test/Rewriter/line-generation-test.m40
-rw-r--r--test/Rewriter/modern-write-bf-abi.mm120
-rw-r--r--test/Rewriter/objc-modern-property-bitfield.m43
-rw-r--r--test/Rewriter/rewrite-line-directive.m18
-rw-r--r--test/Rewriter/rewrite-modern-qualified-type.mm11
-rw-r--r--test/Rewriter/rewrite-modern-throw.m26
-rw-r--r--test/Rewriter/unnamed-bf-modern-write.mm16
-rw-r--r--test/Sema/128bitint.c14
-rw-r--r--test/Sema/address_spaces.c19
-rw-r--r--test/Sema/alignas.c17
-rw-r--r--test/Sema/alloc_size.c3
-rw-r--r--test/Sema/anonymous-struct-union.c2
-rw-r--r--test/Sema/asm.c7
-rw-r--r--test/Sema/ast-print.c14
-rw-r--r--test/Sema/atomic-ops.c8
-rw-r--r--test/Sema/attr-availability.c13
-rw-r--r--test/Sema/attr-cleanup.c4
-rw-r--r--test/Sema/attr-mode.c2
-rw-r--r--test/Sema/attr-print.c21
-rw-r--r--test/Sema/attr-regparm.c2
-rw-r--r--test/Sema/attr-used.c2
-rw-r--r--test/Sema/attr-visibility.c4
-rw-r--r--test/Sema/attr-weak.c6
-rw-r--r--test/Sema/block-return.c11
-rw-r--r--test/Sema/builtins.c15
-rw-r--r--test/Sema/callingconv.c4
-rw-r--r--test/Sema/compare.c16
-rw-r--r--test/Sema/complex-imag.c4
-rw-r--r--test/Sema/decl-invalid.c4
-rw-r--r--test/Sema/declspec.c2
-rw-r--r--test/Sema/expr-address-of.c12
-rw-r--r--test/Sema/expr-comma-c99.c2
-rw-r--r--test/Sema/expr-comma.c2
-rw-r--r--test/Sema/exprs.c2
-rw-r--r--test/Sema/extern-redecl.c13
-rw-r--r--test/Sema/format-strings-fixit.c8
-rw-r--r--test/Sema/format-strings.c3
-rw-r--r--test/Sema/function-redecl.c2
-rw-r--r--test/Sema/gnu89.c2
-rw-r--r--test/Sema/i-c-e.c2
-rw-r--r--test/Sema/implicit-cast-dump.c15
-rw-r--r--test/Sema/inline.c10
-rw-r--r--test/Sema/invalid-cast.cpp11
-rw-r--r--test/Sema/invalid-decl.c8
-rw-r--r--test/Sema/memset-invalid-1.c15
-rw-r--r--test/Sema/merge-decls.c54
-rw-r--r--test/Sema/mips16_attr_allowed.c27
-rw-r--r--test/Sema/mips16_attr_not_allowed.c7
-rw-r--r--test/Sema/ms-inline-asm-invalid-arch.c5
-rw-r--r--test/Sema/ms-inline-asm.c11
-rw-r--r--test/Sema/nowarn-documentation-property.m15
-rw-r--r--test/Sema/parentheses.cpp12
-rw-r--r--test/Sema/pid_t.c11
-rw-r--r--test/Sema/ppc-bool.c4
-rw-r--r--test/Sema/private-extern.c1
-rw-r--r--test/Sema/return-noreturn.c5
-rw-r--r--test/Sema/return.c5
-rw-r--r--test/Sema/static-assert.c35
-rw-r--r--test/Sema/struct-decl.c2
-rw-r--r--test/Sema/switch-1.c22
-rw-r--r--test/Sema/types.c2
-rw-r--r--test/Sema/ucn-cstring.c2
-rw-r--r--test/Sema/ucn-identifiers.c35
-rw-r--r--test/Sema/uninit-det-order.c13
-rw-r--r--test/Sema/unused-expr-system-header.c6
-rw-r--r--test/Sema/unused-expr.c29
-rw-r--r--test/Sema/varargs.c2
-rw-r--r--test/Sema/varargs_unreachable.c14
-rw-r--r--test/Sema/variadic-promotion.c13
-rw-r--r--test/Sema/warn-documentation-crlf.c13
-rw-r--r--test/Sema/warn-documentation.cpp114
-rw-r--r--test/Sema/warn-documentation.m74
-rw-r--r--test/Sema/warn-duplicate-enum.c92
-rw-r--r--test/Sema/warn-main-return-type.c49
-rw-r--r--test/Sema/warn-main.c33
-rw-r--r--test/Sema/warn-missing-prototypes.c8
-rw-r--r--test/Sema/warn-sizeof-array-decay.c18
-rw-r--r--test/Sema/warn-type-safety-mpi-hdf5.c10
-rw-r--r--test/Sema/warn-unreachable.c8
-rw-r--r--test/Sema/warn-unused-variables-werror.c6
-rw-r--r--test/Sema/warn-vla.c12
-rw-r--r--test/Sema/wchar.c2
-rw-r--r--test/SemaCXX/MicrosoftExtensions.cpp4
-rw-r--r--test/SemaCXX/address-of-temporary.cpp7
-rw-r--r--test/SemaCXX/address-of.cpp14
-rw-r--r--test/SemaCXX/address-space-initialize.cpp25
-rw-r--r--test/SemaCXX/alias-template.cpp4
-rw-r--r--test/SemaCXX/alignof-sizeof-reference.cpp6
-rw-r--r--test/SemaCXX/altivec.cpp2
-rw-r--r--test/SemaCXX/anonymous-struct.cpp4
-rw-r--r--test/SemaCXX/anonymous-union.cpp12
-rw-r--r--test/SemaCXX/array-bound-merge.cpp3
-rw-r--r--test/SemaCXX/array-bounds.cpp4
-rw-r--r--test/SemaCXX/ast-print.cpp56
-rw-r--r--test/SemaCXX/atomic-type.cxx25
-rw-r--r--test/SemaCXX/attr-cxx0x.cpp45
-rw-r--r--test/SemaCXX/attr-deprecated.cpp13
-rw-r--r--test/SemaCXX/attr-no-sanitize-address.cpp37
-rw-r--r--test/SemaCXX/attr-no-sanitize-memory.cpp37
-rw-r--r--test/SemaCXX/attr-no-sanitize-thread.cpp37
-rw-r--r--test/SemaCXX/attr-nonnull.cpp21
-rw-r--r--test/SemaCXX/attr-print.cpp18
-rw-r--r--test/SemaCXX/attr-regparm.cpp4
-rw-r--r--test/SemaCXX/attr-weak.cpp7
-rw-r--r--test/SemaCXX/attr-weakref.cpp5
-rw-r--r--test/SemaCXX/auto-pragma.cpp12
-rw-r--r--test/SemaCXX/blocks.cpp35
-rw-r--r--test/SemaCXX/borland-extensions.cpp12
-rw-r--r--test/SemaCXX/builtins.cpp4
-rw-r--r--test/SemaCXX/c99-variable-length-array-cxx11.cpp26
-rw-r--r--test/SemaCXX/c99-variable-length-array.cpp5
-rw-r--r--test/SemaCXX/class-base-member-init.cpp8
-rw-r--r--test/SemaCXX/compare.cpp150
-rw-r--r--test/SemaCXX/condition.cpp11
-rw-r--r--test/SemaCXX/conditional-expr.cpp4
-rw-r--r--test/SemaCXX/constant-expression-cxx11.cpp4
-rw-r--r--test/SemaCXX/constructor-initializer.cpp12
-rw-r--r--test/SemaCXX/conversion.cpp10
-rw-r--r--test/SemaCXX/copy-constructor-error.cpp40
-rw-r--r--test/SemaCXX/crash-lambda-12645424.cpp43
-rw-r--r--test/SemaCXX/cxx0x-class.cpp6
-rw-r--r--test/SemaCXX/cxx0x-cursory-default-delete.cpp18
-rw-r--r--test/SemaCXX/cxx0x-defaulted-functions.cpp41
-rw-r--r--test/SemaCXX/cxx0x-initializer-aggregates.cpp16
-rw-r--r--test/SemaCXX/cxx0x-initializer-constructor.cpp59
-rw-r--r--test/SemaCXX/cxx0x-initializer-references.cpp7
-rw-r--r--test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp17
-rw-r--r--test/SemaCXX/cxx11-ast-print.cpp6
-rw-r--r--test/SemaCXX/cxx11-attr-print.cpp77
-rw-r--r--test/SemaCXX/cxx11-gnu-attrs.cpp55
-rw-r--r--test/SemaCXX/cxx11-user-defined-literals.cpp6
-rw-r--r--test/SemaCXX/cxx98-compat.cpp29
-rw-r--r--test/SemaCXX/decl-microsoft-call-conv.cpp86
-rw-r--r--test/SemaCXX/default-arg-special-member.cpp12
-rw-r--r--test/SemaCXX/empty-class-layout.cpp15
-rw-r--r--test/SemaCXX/enum-scoped.cpp14
-rw-r--r--test/SemaCXX/exceptions.cpp25
-rw-r--r--test/SemaCXX/extern-c.cpp58
-rw-r--r--test/SemaCXX/friend.cpp16
-rw-r--r--test/SemaCXX/function-extern-c.cpp58
-rw-r--r--test/SemaCXX/implicit-member-functions.cpp69
-rw-r--r--test/SemaCXX/lambda-expressions.cpp4
-rw-r--r--test/SemaCXX/linkage-spec.cpp4
-rw-r--r--test/SemaCXX/linkage2.cpp154
-rw-r--r--test/SemaCXX/member-expr.cpp5
-rw-r--r--test/SemaCXX/member-init.cpp16
-rw-r--r--test/SemaCXX/member-pointer-ms.cpp175
-rw-r--r--test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp2
-rw-r--r--test/SemaCXX/new-delete.cpp11
-rw-r--r--test/SemaCXX/nullptr.cpp2
-rw-r--r--test/SemaCXX/overload-decl.cpp3
-rw-r--r--test/SemaCXX/overload-member-call.cpp8
-rw-r--r--test/SemaCXX/overloaded-builtin-operators.cpp3
-rw-r--r--test/SemaCXX/overloaded-operator.cpp25
-rw-r--r--test/SemaCXX/pragma-weak.cpp8
-rw-r--r--test/SemaCXX/pseudo-destructors.cpp7
-rw-r--r--test/SemaCXX/qualified-names-print.cpp15
-rw-r--r--test/SemaCXX/return.cpp24
-rw-r--r--test/SemaCXX/scope-check.cpp12
-rw-r--r--test/SemaCXX/sourceranges.cpp5
-rw-r--r--test/SemaCXX/storage-class.cpp2
-rw-r--r--test/SemaCXX/switch-implicit-fallthrough.cpp94
-rw-r--r--test/SemaCXX/type-traits.cpp122
-rw-r--r--test/SemaCXX/typo-correction.cpp24
-rw-r--r--test/SemaCXX/undefined-inline.cpp57
-rw-r--r--test/SemaCXX/undefined-internal.cpp142
-rw-r--r--test/SemaCXX/uninitialized.cpp55
-rw-r--r--test/SemaCXX/virtual-override-x64.cpp36
-rw-r--r--test/SemaCXX/virtual-override-x86.cpp33
-rw-r--r--test/SemaCXX/visibility.cpp12
-rw-r--r--test/SemaCXX/warn-bad-memaccess.cpp5
-rw-r--r--test/SemaCXX/warn-enum-compare.cpp4
-rw-r--r--test/SemaCXX/warn-func-not-needed.cpp44
-rw-r--r--test/SemaCXX/warn-reinterpret-base-class.cpp323
-rw-r--r--test/SemaCXX/warn-reorder-ctor-initialization.cpp11
-rw-r--r--test/SemaCXX/warn-static-const-float.cpp21
-rw-r--r--test/SemaCXX/warn-thread-safety-analysis.cpp205
-rw-r--r--test/SemaCXX/warn-unsequenced.cpp103
-rw-r--r--test/SemaCXX/warn-unused-filescoped.cpp41
-rw-r--r--test/SemaCXX/warn-unused-result.cpp38
-rw-r--r--test/SemaCXX/warn-variable-not-needed.cpp27
-rw-r--r--test/SemaCXX/warn-vla.cpp27
-rw-r--r--test/SemaObjC/arc-decls.m8
-rw-r--r--test/SemaObjC/arc-objc-lifetime.m62
-rw-r--r--test/SemaObjC/arc-property-lifetime.m43
-rw-r--r--test/SemaObjC/arc-property.m20
-rw-r--r--test/SemaObjC/arc.m39
-rw-r--r--test/SemaObjC/attr-availability.m13
-rw-r--r--test/SemaObjC/attr-deprecated.m19
-rw-r--r--test/SemaObjC/bad-receiver-1.m3
-rw-r--r--test/SemaObjC/blocks.m24
-rw-r--r--test/SemaObjC/boxing-illegal.m (renamed from test/SemaObjC/boxing-illegal-types.m)17
-rw-r--r--test/SemaObjC/builtin_objc_lib_functions.m2
-rw-r--r--test/SemaObjC/builtin_objc_msgSend.m16
-rw-r--r--test/SemaObjC/category-1.m3
-rw-r--r--test/SemaObjC/compare-qualified-id.m3
-rw-r--r--test/SemaObjC/conditional-expr.m4
-rw-r--r--test/SemaObjC/crash-on-objc-bool-literal.m9
-rw-r--r--test/SemaObjC/debugger-cast-result-to-id.m2
-rw-r--r--test/SemaObjC/default-synthesize-3.m72
-rw-r--r--test/SemaObjC/enum-fixed-type.m12
-rw-r--r--test/SemaObjC/error-missing-getter.m31
-rw-r--r--test/SemaObjC/error-outof-scope-property-use.m29
-rw-r--r--test/SemaObjC/format-strings-objc.m6
-rw-r--r--test/SemaObjC/forward-protocol-incomplete-impl-warn.m20
-rw-r--r--test/SemaObjC/gcc-cast-ext.m7
-rw-r--r--test/SemaObjC/generic-selection.m17
-rw-r--r--test/SemaObjC/iboutlet.m31
-rw-r--r--test/SemaObjC/illegal-nonarc-bridged-cast.m11
-rw-r--r--test/SemaObjC/incomplete-implementation.m9
-rw-r--r--test/SemaObjC/instancetype.m38
-rw-r--r--test/SemaObjC/message.m10
-rw-r--r--test/SemaObjC/method-undef-category-warn-1.m16
-rw-r--r--test/SemaObjC/method-undef-extension-warn-1.m6
-rw-r--r--test/SemaObjC/method-undefined-warn-1.m20
-rw-r--r--test/SemaObjC/no-protocol-option-tests.m4
-rw-r--r--test/SemaObjC/no-warning-unavail-unimp.m4
-rw-r--r--test/SemaObjC/objc-literal-comparison.m3
-rw-r--r--test/SemaObjC/property-3.m21
-rw-r--r--test/SemaObjC/property-4.m2
-rw-r--r--test/SemaObjC/property-category-3.m2
-rw-r--r--test/SemaObjC/property-category-impl.m29
-rw-r--r--test/SemaObjC/property-in-class-extension.m7
-rw-r--r--test/SemaObjC/property-noninherited-availability-attr.m32
-rw-r--r--test/SemaObjC/property-user-setter.m4
-rw-r--r--test/SemaObjC/protocol-archane.m6
-rw-r--r--test/SemaObjC/related-result-type-inference.m2
-rw-r--r--test/SemaObjC/selector-3.m29
-rw-r--r--test/SemaObjC/super-property-notation.m25
-rw-r--r--test/SemaObjC/super.m3
-rw-r--r--test/SemaObjC/typo-correction.m21
-rw-r--r--test/SemaObjC/undef-protocol-methods-1.m5
-rw-r--r--test/SemaObjC/warn-cast-of-sel-expr.m3
-rw-r--r--test/SemaObjC/warn-deprecated-implementations.m13
-rw-r--r--test/SemaObjC/warn-direct-ivar-access.m28
-rw-r--r--test/SemaObjC/warn-isa-ref.m24
-rw-r--r--test/SemaObjC/warn-retain-block-property.m43
-rw-r--r--test/SemaObjC/warning-missing-selector-name.m4
-rw-r--r--test/SemaObjC/weak-property.m4
-rw-r--r--test/SemaObjCXX/arc-0x.mm8
-rw-r--r--test/SemaObjCXX/arc-nsconsumed-errors.mm32
-rw-r--r--test/SemaObjCXX/arc-templates.mm9
-rw-r--r--test/SemaObjCXX/arc-unbridged-cast.mm9
-rw-r--r--test/SemaObjCXX/capturing-flexible-array-in-block.mm8
-rw-r--r--test/SemaObjCXX/debugger-cast-result-to-id.mm34
-rw-r--r--test/SemaObjCXX/instancetype.mm216
-rw-r--r--test/SemaObjCXX/instantiate-expr.mm4
-rw-r--r--test/SemaObjCXX/parameters.mm3
-rw-r--r--test/SemaObjCXX/properties.mm37
-rw-r--r--test/SemaObjCXX/unknown-anytype.mm45
-rw-r--r--test/SemaOpenCL/endian-attr.cl9
-rw-r--r--test/SemaOpenCL/event_t.cl17
-rw-r--r--test/SemaOpenCL/event_t_overload.cl11
-rw-r--r--test/SemaOpenCL/half.cl40
-rw-r--r--test/SemaOpenCL/invalid-kernel-attrs.cl16
-rw-r--r--test/SemaOpenCL/invalid-kernel.cl7
-rw-r--r--test/SemaOpenCL/invalid-logical-ops-1.1.cl57
-rw-r--r--test/SemaOpenCL/invalid-logical-ops-1.2.cl57
-rw-r--r--test/SemaOpenCL/sampler_t.cl13
-rw-r--r--test/SemaOpenCL/sampler_t_overload.cl12
-rw-r--r--test/SemaOpenCL/shifts.cl17
-rw-r--r--test/SemaOpenCL/storageclass.cl2
-rw-r--r--test/SemaOpenCL/unsupported.cl9
-rw-r--r--test/SemaTemplate/alignas.cpp23
-rw-r--r--test/SemaTemplate/class-template-id.cpp2
-rw-r--r--test/SemaTemplate/default-expr-arguments-2.cpp4
-rw-r--r--test/SemaTemplate/default-expr-arguments.cpp19
-rw-r--r--test/SemaTemplate/dependent-names.cpp23
-rw-r--r--test/SemaTemplate/derived.cpp18
-rw-r--r--test/SemaTemplate/destructor-template.cpp19
-rw-r--r--test/SemaTemplate/example-dynarray.cpp1
-rw-r--r--test/SemaTemplate/friend-template.cpp20
-rw-r--r--test/SemaTemplate/fun-template-def.cpp8
-rw-r--r--test/SemaTemplate/instantiate-init.cpp4
-rw-r--r--test/SemaTemplate/instantiate-member-initializers.cpp16
-rw-r--r--test/SemaTemplate/instantiate-type.cpp13
-rw-r--r--test/SemaTemplate/operator-template.cpp2
-rw-r--r--test/SemaTemplate/recursive-template-instantiation.cpp2
-rw-r--r--test/SemaTemplate/temp_arg.cpp2
-rw-r--r--test/SemaTemplate/temp_arg_nontype.cpp16
-rw-r--r--test/SemaTemplate/temp_arg_nontype_cxx11.cpp10
-rw-r--r--test/SemaTemplate/temp_arg_type.cpp4
-rw-r--r--test/TableGen/DiagnosticBase.inc35
-rw-r--r--test/TableGen/anonymous-groups.td42
-rw-r--r--test/TableGen/lit.local.cfg1
-rw-r--r--test/TableGen/tg-fixits.td41
-rw-r--r--test/Tooling/auto-detect-from-source-parent-of-cwd.cpp2
-rw-r--r--test/Tooling/auto-detect-from-source-parent.cpp2
-rw-r--r--test/Tooling/auto-detect-from-source.cpp2
-rw-r--r--test/Tooling/clang-check-ast-dump.cpp29
-rw-r--r--test/Tooling/clang-check-autodetect-dir.cpp2
-rw-r--r--test/Tooling/clang-check-pwd.cpp2
-rw-r--r--test/Tooling/pch.cpp12
-rw-r--r--test/Unit/lit.cfg5
-rw-r--r--test/lit.cfg24
-rw-r--r--test/lit.site.cfg.in1
-rw-r--r--tools/CMakeLists.txt1
-rw-r--r--tools/Makefile2
-rw-r--r--tools/arcmt-test/CMakeLists.txt1
-rw-r--r--tools/arcmt-test/Makefile2
-rw-r--r--tools/arcmt-test/arcmt-test.cpp4
-rw-r--r--tools/c-arcmt-test/Makefile4
-rw-r--r--tools/c-index-test/CMakeLists.txt3
-rw-r--r--tools/c-index-test/Makefile9
-rw-r--r--tools/c-index-test/c-index-test.c456
-rw-r--r--tools/clang-check/CMakeLists.txt1
-rw-r--r--tools/clang-check/ClangCheck.cpp6
-rw-r--r--tools/clang-check/Makefile2
-rw-r--r--tools/clang-format/CMakeLists.txt17
-rw-r--r--tools/clang-format/ClangFormat.cpp152
-rw-r--r--tools/clang-format/Makefile24
-rwxr-xr-xtools/clang-format/clang-format-diff.py115
-rw-r--r--tools/clang-format/clang-format.py60
-rw-r--r--tools/diagtool/CMakeLists.txt1
-rw-r--r--tools/diagtool/DiagTool.cpp2
-rw-r--r--tools/diagtool/DiagTool.h2
-rw-r--r--tools/diagtool/ListWarnings.cpp6
-rw-r--r--tools/diagtool/Makefile2
-rw-r--r--tools/diagtool/ShowEnabledWarnings.cpp3
-rw-r--r--tools/diagtool/TreeView.cpp8
-rw-r--r--tools/driver/CMakeLists.txt2
-rw-r--r--tools/driver/Makefile29
-rw-r--r--tools/driver/cc1_main.cpp20
-rw-r--r--tools/driver/cc1as_main.cpp33
-rw-r--r--tools/driver/driver.cpp119
-rw-r--r--tools/libclang/ARCMigrate.cpp11
-rw-r--r--tools/libclang/CIndex.cpp1826
-rw-r--r--tools/libclang/CIndexCXX.cpp25
-rw-r--r--tools/libclang/CIndexCodeCompletion.cpp108
-rw-r--r--tools/libclang/CIndexDiagnostic.cpp35
-rw-r--r--tools/libclang/CIndexHigh.cpp254
-rw-r--r--tools/libclang/CIndexInclusionStack.cpp7
-rw-r--r--tools/libclang/CIndexUSRs.cpp174
-rw-r--r--tools/libclang/CIndexer.cpp6
-rw-r--r--tools/libclang/CIndexer.h33
-rw-r--r--tools/libclang/CLog.h101
-rw-r--r--tools/libclang/CMakeLists.txt7
-rw-r--r--tools/libclang/CXComment.cpp212
-rw-r--r--tools/libclang/CXComment.h7
-rw-r--r--tools/libclang/CXCompilationDatabase.cpp24
-rw-r--r--tools/libclang/CXCursor.cpp255
-rw-r--r--tools/libclang/CXCursor.h100
-rw-r--r--tools/libclang/CXLoadedDiagnostic.cpp129
-rw-r--r--tools/libclang/CXLoadedDiagnostic.h4
-rw-r--r--tools/libclang/CXSourceLocation.cpp99
-rw-r--r--tools/libclang/CXSourceLocation.h6
-rw-r--r--tools/libclang/CXStoredDiagnostic.cpp17
-rw-r--r--tools/libclang/CXString.cpp147
-rw-r--r--tools/libclang/CXString.h82
-rw-r--r--tools/libclang/CXTranslationUnit.h30
-rw-r--r--tools/libclang/CXType.cpp110
-rw-r--r--tools/libclang/CursorVisitor.h29
-rw-r--r--tools/libclang/IndexBody.cpp1
-rw-r--r--tools/libclang/IndexDecl.cpp75
-rw-r--r--tools/libclang/IndexTypeSourceInfo.cpp1
-rw-r--r--tools/libclang/Indexing.cpp340
-rw-r--r--tools/libclang/IndexingContext.cpp79
-rw-r--r--tools/libclang/IndexingContext.h9
-rw-r--r--tools/libclang/Makefile15
-rw-r--r--tools/libclang/RecursiveASTVisitor.h16
-rw-r--r--tools/libclang/SimpleFormatContext.h75
-rw-r--r--tools/libclang/libclang.exports7
-rwxr-xr-xtools/scan-build/ccc-analyzer25
-rwxr-xr-xtools/scan-build/scan-build162
-rwxr-xr-xtools/scan-build/set-xcode-analyzer10
-rw-r--r--unittests/AST/ASTContextParentMapTest.cpp71
-rw-r--r--unittests/AST/CMakeLists.txt1
-rw-r--r--unittests/AST/CommentLexer.cpp168
-rw-r--r--unittests/AST/CommentParser.cpp18
-rw-r--r--unittests/AST/DeclPrinterTest.cpp47
-rw-r--r--unittests/AST/Makefile6
-rw-r--r--unittests/AST/MatchVerifier.h196
-rw-r--r--unittests/AST/SourceLocationTest.cpp202
-rw-r--r--unittests/AST/StmtPrinterTest.cpp11
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.cpp549
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.h2
-rw-r--r--unittests/ASTMatchers/CMakeLists.txt1
-rw-r--r--unittests/ASTMatchers/Makefile6
-rw-r--r--unittests/Basic/CMakeLists.txt1
-rw-r--r--unittests/Basic/CharInfoTest.cpp499
-rw-r--r--unittests/Basic/FileManagerTest.cpp5
-rw-r--r--unittests/Basic/SourceManagerTest.cpp30
-rw-r--r--unittests/CMakeLists.txt1
-rw-r--r--unittests/Format/CMakeLists.txt18
-rw-r--r--unittests/Format/FormatTest.cpp3590
-rw-r--r--unittests/Format/Makefile19
-rw-r--r--unittests/Frontend/CMakeLists.txt1
-rw-r--r--unittests/Frontend/FrontendActionTest.cpp10
-rw-r--r--unittests/Frontend/Makefile2
-rw-r--r--unittests/Lex/CMakeLists.txt2
-rw-r--r--unittests/Lex/LexerTest.cpp28
-rw-r--r--unittests/Lex/PPCallbacksTest.cpp22
-rw-r--r--unittests/Lex/PPConditionalDirectiveRecordTest.cpp (renamed from unittests/Lex/PreprocessingRecordTest.cpp)70
-rw-r--r--unittests/Makefile16
-rw-r--r--unittests/Tooling/CMakeLists.txt1
-rw-r--r--unittests/Tooling/CompilationDatabaseTest.cpp67
-rw-r--r--unittests/Tooling/Makefile2
-rw-r--r--unittests/Tooling/RecursiveASTVisitorTest.cpp5
-rw-r--r--unittests/Tooling/RefactoringCallbacksTest.cpp6
-rw-r--r--unittests/Tooling/RefactoringTest.cpp8
-rw-r--r--unittests/Tooling/RewriterTestContext.h8
-rw-r--r--unittests/Tooling/TestVisitor.h7
-rw-r--r--unittests/Tooling/ToolingTest.cpp36
-rw-r--r--utils/C++Tests/Clang-Code-Compile/lit.local.cfg26
-rw-r--r--utils/C++Tests/Clang-Code-Syntax/lit.local.cfg25
-rw-r--r--utils/C++Tests/Clang-Syntax/lit.local.cfg24
-rw-r--r--utils/C++Tests/LLVM-Code-Compile/lit.local.cfg48
-rwxr-xr-xutils/C++Tests/LLVM-Code-Symbols/check-symbols54
-rw-r--r--utils/C++Tests/LLVM-Code-Symbols/lit.local.cfg48
-rw-r--r--utils/C++Tests/LLVM-Code-Syntax/lit.local.cfg46
-rw-r--r--utils/C++Tests/LLVM-Syntax/lit.local.cfg24
-rw-r--r--utils/C++Tests/lit.cfg27
-rw-r--r--utils/C++Tests/stdc++-Syntax/lit.local.cfg17
-rw-r--r--utils/ClangDataFormat.py58
-rw-r--r--utils/OptionalTests/Extra/README.txt3
-rw-r--r--utils/OptionalTests/Extra/Runtime/darwin-clang_rt.c338
-rw-r--r--utils/OptionalTests/README.txt4
-rw-r--r--utils/OptionalTests/lit.cfg26
-rwxr-xr-xutils/SummarizeErrors117
-rw-r--r--utils/TableGen/CMakeLists.txt1
-rw-r--r--utils/TableGen/ClangASTNodesEmitter.cpp4
-rw-r--r--utils/TableGen/ClangAttrEmitter.cpp431
-rw-r--r--utils/TableGen/ClangCommentCommandInfoEmitter.cpp54
-rw-r--r--utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp85
-rw-r--r--utils/TableGen/ClangCommentHTMLTagsEmitter.cpp5
-rw-r--r--utils/TableGen/ClangDiagnosticsEmitter.cpp127
-rw-r--r--utils/TableGen/OptParserEmitter.cpp7
-rw-r--r--utils/TableGen/TableGen.cpp30
-rw-r--r--utils/TableGen/TableGenBackends.h4
-rwxr-xr-xutils/analyzer/CmpRuns.py72
-rw-r--r--utils/analyzer/SATestBuild.py8
-rw-r--r--utils/find-unused-diagnostics.sh18
-rw-r--r--utils/valgrind/x86_64-pc-linux-gnu_gcc-4.3.3.supp7
-rw-r--r--www/OpenProjects.html32
-rw-r--r--www/analyzer/annotations.html72
-rw-r--r--www/analyzer/available_checks.html3
-rw-r--r--www/analyzer/checker_dev_manual.html38
-rw-r--r--www/analyzer/content.css1
-rw-r--r--www/analyzer/dev_cxx.html37
-rw-r--r--www/analyzer/faq.html16
-rw-r--r--www/analyzer/index.html29
-rw-r--r--www/analyzer/latest_checker.html.incl2
-rw-r--r--www/analyzer/potential_checkers.html183
-rw-r--r--www/analyzer/release_notes.html41
-rw-r--r--www/analyzer/xcode.html44
-rw-r--r--www/comparison.html1
-rw-r--r--www/compatibility.html101
-rw-r--r--www/cxx_status.html40
-rw-r--r--www/get_started.html14
-rw-r--r--www/hacking.html4
-rw-r--r--www/menu.html.incl2
-rw-r--r--www/performance-2008-10-31.html132
-rw-r--r--www/performance-2009-03-02.html110
-rw-r--r--www/performance.html104
2316 files changed, 146869 insertions, 60669 deletions
diff --git a/.arcconfig b/.arcconfig
new file mode 100644
index 0000000..7f45342
--- /dev/null
+++ b/.arcconfig
@@ -0,0 +1,4 @@
+{
+ "project_id" : "clang",
+ "conduit_uri" : "http://llvm-reviews.chandlerc.com/"
+}
diff --git a/.gitignore b/.gitignore
index 6be9976..6c34e37 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,3 +30,6 @@ cscope.out
#==============================================================================#
# Clang extra user tools, which is tracked independently (clang-tools-extra).
tools/extra
+# Sphinx build products
+docs/_build
+docs/analyzer/_build
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 53d4165..6efcd4a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -66,6 +66,11 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR )
set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
set( CLANG_BUILT_STANDALONE 1 )
+
+ find_package(LibXml2)
+ if (LIBXML2_FOUND)
+ set(CLANG_HAVE_LIBXML 1)
+ endif ()
endif()
set(CLANG_RESOURCE_DIR "" CACHE STRING
@@ -133,16 +138,17 @@ configure_file(
# Add appropriate flags for GCC
if (LLVM_COMPILER_IS_GCC_COMPATIBLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-common -Woverloaded-virtual -Wcast-qual -fno-strict-aliasing -pedantic -Wno-long-long -Wall -W -Wno-unused-parameter -Wwrite-strings")
+
+ check_cxx_compiler_flag("-Werror -Wnested-anon-types" CXX_SUPPORTS_NO_NESTED_ANON_TYPES_FLAG)
+ if( CXX_SUPPORTS_NO_NESTED_ANON_TYPES_FLAG )
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-nested-anon-types" )
+ endif()
endif ()
if (APPLE)
set(CMAKE_MODULE_LINKER_FLAGS "-Wl,-flat_namespace -Wl,-undefined -Wl,suppress")
endif ()
-# libxml2 is an optional dependency, required only to run validation
-# tests on XML output.
-find_package(LibXml2)
-
configure_file(
${CLANG_SOURCE_DIR}/include/clang/Config/config.h.cmake
${CLANG_BINARY_DIR}/include/clang/Config/config.h)
@@ -253,6 +259,9 @@ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/
add_definitions( -D_GNU_SOURCE )
+# FIXME: They should be options.
+add_definitions(-DCLANG_ENABLE_ARCMT -DCLANG_ENABLE_REWRITER -DCLANG_ENABLE_STATIC_ANALYZER)
+
# Clang version information
set(CLANG_EXECUTABLE_VERSION
"${CLANG_VERSION_MAJOR}.${CLANG_VERSION_MINOR}" CACHE STRING
@@ -272,13 +281,15 @@ add_subdirectory(runtime)
option(CLANG_BUILD_EXAMPLES "Build CLANG example programs by default." OFF)
add_subdirectory(examples)
+option(CLANG_INCLUDE_TESTS
+ "Generate build targets for the Clang unit tests."
+ ${LLVM_INCLUDE_TESTS})
+
# TODO: docs.
add_subdirectory(test)
-if( LLVM_INCLUDE_TESTS )
- if( NOT CLANG_BUILT_STANDALONE )
- add_subdirectory(unittests)
- endif()
+if( CLANG_INCLUDE_TESTS )
+ add_subdirectory(unittests)
endif()
# Workaround for MSVS10 to avoid the Dialog Hell
diff --git a/CODE_OWNERS.TXT b/CODE_OWNERS.TXT
new file mode 100644
index 0000000..13c0a9b
--- /dev/null
+++ b/CODE_OWNERS.TXT
@@ -0,0 +1,40 @@
+This file is a list of the people responsible for ensuring that patches for a
+particular part of Clang are reviewed, either by themself or by someone else.
+They are also the gatekeepers for their part of Clang, with the final word on
+what goes in or not.
+
+The list is sorted by surname and formatted to allow easy grepping and
+beautification by scripts. The fields are: name (N), email (E), web-address
+(W), PGP key ID and fingerprint (P), description (D), and snail-mail address
+(S).
+
+N: Chandler Carruth
+E: chandlerc@gmail.com
+E: chandlerc@google.com
+D: CMake, library layering
+
+N: Eric Christopher
+E: echristo@gmail.com
+D: Debug Information, autotools/configure/make build, inline assembly
+
+N: Doug Gregor
+D: All parts of Clang not covered by someone else
+
+N: Anton Korobeynikov
+E: anton@korobeynikov.info
+D: Exception handling, Windows codegen, ARM EABI
+
+N: Ted Kremenek
+D: Clang Static Analyzer
+
+N: John McCall
+E: rjmccall@apple.com
+D: Clang LLVM IR generation
+
+N: Chad Rosier
+E: mcrosier@apple.com
+D: MS-inline asm, and the compiler driver
+
+N: Richard Smith
+E: richard@metafoo.co.uk
+D: Clang Semantic Analysis (tools/clang/lib/Sema/* tools/clang/include/clang/Sema/*)
diff --git a/INSTALL.txt b/INSTALL.txt
index e8e3209..bd2f4fe 100644
--- a/INSTALL.txt
+++ b/INSTALL.txt
@@ -44,6 +44,6 @@ From inside the Clang build directory, run 'make install' to install the Clang
compiler and header files into the prefix directory selected when LLVM was
configured.
-The Clang compiler is available as 'clang' and supports a gcc like command line
+The Clang compiler is available as 'clang' and 'clang++'. It supports a gcc like command line
interface. See the man page for clang (installed into $prefix/share/man/man1)
for more information.
diff --git a/LICENSE.TXT b/LICENSE.TXT
index 6c224f8..e31223a 100644
--- a/LICENSE.TXT
+++ b/LICENSE.TXT
@@ -4,7 +4,7 @@ LLVM Release License
University of Illinois/NCSA
Open Source License
-Copyright (c) 2007-2012 University of Illinois at Urbana-Champaign.
+Copyright (c) 2007-2013 University of Illinois at Urbana-Champaign.
All rights reserved.
Developed by:
diff --git a/NOTES.txt b/NOTES.txt
index 1c89d68..107ec5a 100644
--- a/NOTES.txt
+++ b/NOTES.txt
@@ -2,9 +2,6 @@
// Random Notes
//===---------------------------------------------------------------------===//
-C90/C99/C++ Comparisons:
-http://david.tribble.com/text/cdiffs.htm
-
//===---------------------------------------------------------------------===//
To time GCC preprocessing speed without output, use:
diff --git a/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py
index 5e162c0..70f4f36 100644
--- a/bindings/python/clang/cindex.py
+++ b/bindings/python/clang/cindex.py
@@ -1271,6 +1271,17 @@ class Cursor(Structure):
# created.
return self._tu
+ @property
+ def referenced(self):
+ """
+ For a cursor that is a reference, returns a cursor
+ representing the entity that it references.
+ """
+ if not hasattr(self, '_referenced'):
+ self._referenced = conf.lib.clang_getCursorReferenced(self)
+
+ return self._referenced
+
def get_arguments(self):
"""Return an iterator for accessing the arguments of this cursor."""
num_args = conf.lib.clang_Cursor_getNumArguments(self)
@@ -1634,6 +1645,33 @@ class _CXUnsavedFile(Structure):
"""Helper for passing unsaved file arguments."""
_fields_ = [("name", c_char_p), ("contents", c_char_p), ('length', c_ulong)]
+# Functions calls through the python interface are rather slow. Fortunately,
+# for most symboles, we do not need to perform a function call. Their spelling
+# never changes and is consequently provided by this spelling cache.
+SpellingCache = {
+ # 0: CompletionChunk.Kind("Optional"),
+ # 1: CompletionChunk.Kind("TypedText"),
+ # 2: CompletionChunk.Kind("Text"),
+ # 3: CompletionChunk.Kind("Placeholder"),
+ # 4: CompletionChunk.Kind("Informative"),
+ # 5 : CompletionChunk.Kind("CurrentParameter"),
+ 6: '(', # CompletionChunk.Kind("LeftParen"),
+ 7: ')', # CompletionChunk.Kind("RightParen"),
+ 8: ']', # CompletionChunk.Kind("LeftBracket"),
+ 9: ']', # CompletionChunk.Kind("RightBracket"),
+ 10: '{', # CompletionChunk.Kind("LeftBrace"),
+ 11: '}', # CompletionChunk.Kind("RightBrace"),
+ 12: '<', # CompletionChunk.Kind("LeftAngle"),
+ 13: '>', # CompletionChunk.Kind("RightAngle"),
+ 14: ', ', # CompletionChunk.Kind("Comma"),
+ # 15: CompletionChunk.Kind("ResultType"),
+ 16: ':', # CompletionChunk.Kind("Colon"),
+ 17: ';', # CompletionChunk.Kind("SemiColon"),
+ 18: '=', # CompletionChunk.Kind("Equal"),
+ 19: ' ', # CompletionChunk.Kind("HorizontalSpace"),
+ # 20: CompletionChunk.Kind("VerticalSpace")
+}
+
class CompletionChunk:
class Kind:
def __init__(self, name):
@@ -1648,18 +1686,30 @@ class CompletionChunk:
def __init__(self, completionString, key):
self.cs = completionString
self.key = key
+ self.__kindNumberCache = -1
def __repr__(self):
return "{'" + self.spelling + "', " + str(self.kind) + "}"
@CachedProperty
def spelling(self):
+ if self.__kindNumber in SpellingCache:
+ return SpellingCache[self.__kindNumber]
return conf.lib.clang_getCompletionChunkText(self.cs, self.key).spelling
+ # We do not use @CachedProperty here, as the manual implementation is
+ # apparently still significantly faster. Please profile carefully if you
+ # would like to add CachedProperty back.
+ @property
+ def __kindNumber(self):
+ if self.__kindNumberCache == -1:
+ self.__kindNumberCache = \
+ conf.lib.clang_getCompletionChunkKind(self.cs, self.key)
+ return self.__kindNumberCache
+
@CachedProperty
def kind(self):
- res = conf.lib.clang_getCompletionChunkKind(self.cs, self.key)
- return completionChunkKindMap[res]
+ return completionChunkKindMap[self.__kindNumber]
@CachedProperty
def string(self):
@@ -1672,19 +1722,19 @@ class CompletionChunk:
None
def isKindOptional(self):
- return self.kind == completionChunkKindMap[0]
+ return self.__kindNumber == 0
def isKindTypedText(self):
- return self.kind == completionChunkKindMap[1]
+ return self.__kindNumber == 1
def isKindPlaceHolder(self):
- return self.kind == completionChunkKindMap[3]
+ return self.__kindNumber == 3
def isKindInformative(self):
- return self.kind == completionChunkKindMap[4]
+ return self.__kindNumber == 4
def isKindResultType(self):
- return self.kind == completionChunkKindMap[15]
+ return self.__kindNumber == 15
completionChunkKindMap = {
0: CompletionChunk.Kind("Optional"),
@@ -1965,7 +2015,7 @@ class TranslationUnit(ClangObject):
len(args), unsaved_array,
len(unsaved_files), options)
- if ptr is None:
+ if not ptr:
raise TranslationUnitLoadError("Error parsing translation unit.")
return cls(ptr, index=index)
@@ -1987,7 +2037,7 @@ class TranslationUnit(ClangObject):
index = Index.create()
ptr = conf.lib.clang_createTranslationUnit(index, filename)
- if ptr is None:
+ if not ptr:
raise TranslationUnitLoadError(filename)
return cls(ptr=ptr, index=index)
@@ -3046,13 +3096,13 @@ class Config:
Config.library_path = path
@staticmethod
- def set_library_file(file):
- """Set the exact location of libclang from"""
+ def set_library_file(filename):
+ """Set the exact location of libclang"""
if Config.loaded:
raise Exception("library file must be set before before using " \
"any other functionalities in libclang.")
- Config.library_file = path
+ Config.library_file = filename
@staticmethod
def set_compatibility_check(check_status):
diff --git a/bindings/python/tests/cindex/test_cursor.py b/bindings/python/tests/cindex/test_cursor.py
index edb209b..a27525c 100644
--- a/bindings/python/tests/cindex/test_cursor.py
+++ b/bindings/python/tests/cindex/test_cursor.py
@@ -250,3 +250,12 @@ def test_get_arguments():
assert len(arguments) == 2
assert arguments[0].spelling == "i"
assert arguments[1].spelling == "j"
+
+def test_referenced():
+ tu = get_tu('void foo(); void bar() { foo(); }')
+ foo = get_cursor(tu, 'foo')
+ bar = get_cursor(tu, 'bar')
+ for c in bar.get_children():
+ if c.kind == CursorKind.CALL_EXPR:
+ assert c.referenced.spelling == foo.spelling
+ break
diff --git a/bindings/python/tests/cindex/test_translation_unit.py b/bindings/python/tests/cindex/test_translation_unit.py
index c91f126..f77998e 100644
--- a/bindings/python/tests/cindex/test_translation_unit.py
+++ b/bindings/python/tests/cindex/test_translation_unit.py
@@ -8,6 +8,7 @@ from clang.cindex import Index
from clang.cindex import SourceLocation
from clang.cindex import SourceRange
from clang.cindex import TranslationUnitSaveError
+from clang.cindex import TranslationUnitLoadError
from clang.cindex import TranslationUnit
from .util import get_cursor
from .util import get_tu
@@ -239,3 +240,19 @@ def test_get_tokens_gc():
del tokens
gc.collect()
gc.collect() # Just in case.
+
+def test_fail_from_source():
+ path = os.path.join(kInputsDir, 'non-existent.cpp')
+ try:
+ tu = TranslationUnit.from_source(path)
+ except TranslationUnitLoadError:
+ tu = None
+ assert tu == None
+
+def test_fail_from_ast_file():
+ path = os.path.join(kInputsDir, 'non-existent.ast')
+ try:
+ tu = TranslationUnit.from_ast_file(path)
+ except TranslationUnitLoadError:
+ tu = None
+ assert tu == None
diff --git a/bindings/xml/comment-xml-schema.rng b/bindings/xml/comment-xml-schema.rng
index d98f405..22371df 100644
--- a/bindings/xml/comment-xml-schema.rng
+++ b/bindings/xml/comment-xml-schema.rng
@@ -25,6 +25,9 @@
<ref name="USR" />
</optional>
<optional>
+ <ref name="Headerfile" />
+ </optional>
+ <optional>
<ref name="Declaration" />
</optional>
<optional>
@@ -74,6 +77,9 @@
</optional>
<!-- TODO: Add exception specification. -->
<optional>
+ <ref name="Headerfile" />
+ </optional>
+ <optional>
<ref name="Declaration" />
</optional>
<optional>
@@ -121,6 +127,9 @@
<ref name="USR" />
</optional>
<optional>
+ <ref name="Headerfile" />
+ </optional>
+ <optional>
<ref name="Declaration" />
</optional>
<optional>
@@ -153,6 +162,9 @@
<ref name="USR" />
</optional>
<optional>
+ <ref name="Headerfile" />
+ </optional>
+ <optional>
<ref name="Declaration" />
</optional>
<optional>
@@ -186,6 +198,9 @@
<ref name="USR" />
</optional>
<optional>
+ <ref name="Headerfile" />
+ </optional>
+ <optional>
<ref name="Declaration" />
</optional>
<optional>
@@ -219,6 +234,9 @@
<ref name="USR" />
</optional>
<optional>
+ <ref name="Headerfile" />
+ </optional>
+ <optional>
<ref name="Declaration" />
</optional>
<optional>
@@ -252,6 +270,9 @@
<ref name="USR" />
</optional>
<optional>
+ <ref name="Headerfile" />
+ </optional>
+ <optional>
<ref name="Declaration" />
</optional>
<optional>
@@ -329,6 +350,14 @@
</element>
</define>
+ <define name="Headerfile">
+ <element name="Headerfile">
+ <oneOrMore>
+ <ref name="TextBlockContent" />
+ </oneOrMore>
+ </element>
+ </define>
+
<define name="Discussion">
<element name="Discussion">
<zeroOrMore>
@@ -409,7 +438,7 @@
<define name="Availability">
<element name="Availability">
<attribute name="distribution">
- <data type="string" />
+ <data type="string" />
</attribute>
<optional>
<element name="IntroducedInVersion">
@@ -470,6 +499,30 @@
<define name="TextBlockContent">
<choice>
<element name="Para">
+ <optional>
+ <attribute name="kind">
+ <choice>
+ <value>attention</value>
+ <value>author</value>
+ <value>authors</value>
+ <value>bug</value>
+ <value>copyright</value>
+ <value>date</value>
+ <value>invariant</value>
+ <value>note</value>
+ <value>post</value>
+ <value>pre</value>
+ <value>remark</value>
+ <value>remarks</value>
+ <value>sa</value>
+ <value>see</value>
+ <value>since</value>
+ <value>todo</value>
+ <value>version</value>
+ <value>warning</value>
+ </choice>
+ </attribute>
+ </optional>
<zeroOrMore>
<ref name="TextInlineContent" />
</zeroOrMore>
diff --git a/docs/AddressSanitizer.html b/docs/AddressSanitizer.html
deleted file mode 100644
index 397eafc..0000000
--- a/docs/AddressSanitizer.html
+++ /dev/null
@@ -1,171 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
-<html>
-<head>
- <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
- <title>AddressSanitizer, a fast memory error detector</title>
- <link type="text/css" rel="stylesheet" href="../menu.css">
- <link type="text/css" rel="stylesheet" href="../content.css">
- <style type="text/css">
- td {
- vertical-align: top;
- }
- </style>
-</head>
-<body>
-
-<!--#include virtual="../menu.html.incl"-->
-
-<div id="content">
-
-<h1>AddressSanitizer</h1>
-<ul>
- <li> <a href="#intro">Introduction</a>
- <li> <a href="#howtobuild">How to Build</a>
- <li> <a href="#usage">Usage</a>
- <ul><li> <a href="#has_feature">__has_feature(address_sanitizer)</a></ul>
- <ul><li> <a href="#no_address_safety_analysis">
- __attribute__((no_address_safety_analysis))</a></ul>
- <li> <a href="#platforms">Supported Platforms</a>
- <li> <a href="#limitations">Limitations</a>
- <li> <a href="#status">Current Status</a>
- <li> <a href="#moreinfo">More Information</a>
-</ul>
-
-<h2 id="intro">Introduction</h2>
-AddressSanitizer is a fast memory error detector.
-It consists of a compiler instrumentation module and a run-time library.
-The tool can detect the following types of bugs:
-<ul> <li> Out-of-bounds accesses to heap, stack and globals
- <li> Use-after-free
- <li> Use-after-return (to some extent)
- <li> Double-free, invalid free
-</ul>
-Typical slowdown introduced by AddressSanitizer is <b>2x</b>.
-
-<h2 id="howtobuild">How to build</h2>
-Follow the <a href="../get_started.html">clang build instructions</a>.
-CMake build is supported.<BR>
-
-<h2 id="usage">Usage</h2>
-Simply compile and link your program with <tt>-fsanitize=address</tt> flag. <BR>
-The AddressSanitizer run-time library should be linked to the final executable,
-so make sure to use <tt>clang</tt> (not <tt>ld</tt>) for the final link step.<BR>
-When linking shared libraries, the AddressSanitizer run-time is not linked,
-so <tt>-Wl,-z,defs</tt> may cause link errors (don't use it with AddressSanitizer). <BR>
-
-To get a reasonable performance add <tt>-O1</tt> or higher. <BR>
-To get nicer stack traces in error messages add
-<tt>-fno-omit-frame-pointer</tt>. <BR>
-To get perfect stack traces you may need to disable inlining (just use <tt>-O1</tt>) and tail call
-elimination (<tt>-fno-optimize-sibling-calls</tt>).
-
-<pre>
-% cat example_UseAfterFree.cc
-int main(int argc, char **argv) {
- int *array = new int[100];
- delete [] array;
- return array[argc]; // BOOM
-}
-</pre>
-
-<pre>
-# Compile and link
-% clang -O1 -g -fsanitize=address -fno-omit-frame-pointer example_UseAfterFree.cc
-</pre>
-OR
-<pre>
-# Compile
-% clang -O1 -g -fsanitize=address -fno-omit-frame-pointer -c example_UseAfterFree.cc
-# Link
-% clang -g -fsanitize=address example_UseAfterFree.o
-</pre>
-
-If a bug is detected, the program will print an error message to stderr and exit with a
-non-zero exit code.
-Currently, AddressSanitizer does not symbolize its output, so you may need to use a
-separate script to symbolize the result offline (this will be fixed in future).
-<pre>
-% ./a.out 2> log
-% projects/compiler-rt/lib/asan/scripts/asan_symbolize.py / < log | c++filt
-==9442== ERROR: AddressSanitizer heap-use-after-free on address 0x7f7ddab8c084 at pc 0x403c8c bp 0x7fff87fb82d0 sp 0x7fff87fb82c8
-READ of size 4 at 0x7f7ddab8c084 thread T0
- #0 0x403c8c in main example_UseAfterFree.cc:4
- #1 0x7f7ddabcac4d in __libc_start_main ??:0
-0x7f7ddab8c084 is located 4 bytes inside of 400-byte region [0x7f7ddab8c080,0x7f7ddab8c210)
-freed by thread T0 here:
- #0 0x404704 in operator delete[](void*) ??:0
- #1 0x403c53 in main example_UseAfterFree.cc:4
- #2 0x7f7ddabcac4d in __libc_start_main ??:0
-previously allocated by thread T0 here:
- #0 0x404544 in operator new[](unsigned long) ??:0
- #1 0x403c43 in main example_UseAfterFree.cc:2
- #2 0x7f7ddabcac4d in __libc_start_main ??:0
-==9442== ABORTING
-</pre>
-
-AddressSanitizer exits on the first detected error. This is by design.
-One reason: it makes the generated code smaller and faster (both by ~5%).
-Another reason: this makes fixing bugs unavoidable. With Valgrind, it is often
-the case that users treat Valgrind warnings as false positives
-(which they are not) and don't fix them.
-
-
-<h3 id="has_feature">__has_feature(address_sanitizer)</h3>
-In some cases one may need to execute different code depending on whether
-AddressSanitizer is enabled.
-<a href="LanguageExtensions.html#__has_feature_extension">__has_feature</a>
-can be used for this purpose.
-<pre>
-#if defined(__has_feature)
-# if __has_feature(address_sanitizer)
- code that builds only under AddressSanitizer
-# endif
-#endif
-</pre>
-
-<h3 id="no_address_safety_analysis">__attribute__((no_address_safety_analysis))</h3>
-Some code should not be instrumented by AddressSanitizer.
-One may use the function attribute
-<a href="LanguageExtensions.html#address_sanitizer">
- <tt>no_address_safety_analysis</tt></a>
-to disable instrumentation of a particular function.
-This attribute may not be supported by other compilers, so we suggest to
-use it together with <tt>__has_feature(address_sanitizer)</tt>.
-Note: currently, this attribute will be lost if the function is inlined.
-
-<h2 id="platforms">Supported Platforms</h2>
-AddressSanitizer is supported on
-<ul><li>Linux i386/x86_64 (tested on Ubuntu 10.04 and 12.04).
-<li>MacOS 10.6, 10.7 and 10.8 (i386/x86_64).
-</ul>
-Support for Linux ARM (and Android ARM) is in progress
-(it may work, but is not guaranteed too).
-
-
-<h2 id="limitations">Limitations</h2>
-<ul>
-<li> AddressSanitizer uses more real memory than a native run.
-Exact overhead depends on the allocations sizes. The smaller the
-allocations you make the bigger the overhead is.
-<li> AddressSanitizer uses more stack memory. We have seen up to 3x increase.
-<li> On 64-bit platforms AddressSanitizer maps (but not reserves)
-16+ Terabytes of virtual address space.
-This means that tools like <tt>ulimit</tt> may not work as usually expected.
-<li> Static linking is not supported.
-</ul>
-
-
-<h2 id="status">Current Status</h2>
-AddressSanitizer is fully functional on supported platforms starting from LLVM 3.1.
-The test suite is integrated into CMake build and can be run with
-<tt>make check-asan</tt> command.
-
-<h2 id="moreinfo">More Information</h2>
-<a href="http://code.google.com/p/address-sanitizer/">http://code.google.com/p/address-sanitizer</a>.
-
-
-</div>
-</body>
-</html>
diff --git a/docs/AddressSanitizer.rst b/docs/AddressSanitizer.rst
new file mode 100644
index 0000000..89e8644
--- /dev/null
+++ b/docs/AddressSanitizer.rst
@@ -0,0 +1,163 @@
+================
+AddressSanitizer
+================
+
+.. contents::
+ :local:
+
+Introduction
+============
+
+AddressSanitizer is a fast memory error detector. It consists of a compiler
+instrumentation module and a run-time library. The tool can detect the
+following types of bugs:
+
+* Out-of-bounds accesses to heap, stack and globals
+* Use-after-free
+* Use-after-return (to some extent)
+* Double-free, invalid free
+
+Typical slowdown introduced by AddressSanitizer is **2x**.
+
+How to build
+============
+
+Follow the `clang build instructions <../get_started.html>`_. CMake build is
+supported.
+
+Usage
+=====
+
+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``).
+
+.. code-block:: console
+
+ % cat example_UseAfterFree.cc
+ int main(int argc, char **argv) {
+ int *array = new int[100];
+ delete [] array;
+ return array[argc]; // BOOM
+ }
+
+ # Compile and link
+ % clang -O1 -g -fsanitize=address -fno-omit-frame-pointer example_UseAfterFree.cc
+
+or:
+
+.. code-block:: console
+
+ # 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 non-zero exit code. Currently, AddressSanitizer does not symbolize
+its output, so you may need to use a separate script to symbolize the result
+offline (this will be fixed in future).
+
+.. code-block:: console
+
+ % ./a.out 2> log
+ % projects/compiler-rt/lib/asan/scripts/asan_symbolize.py / < log | c++filt
+ ==9442== ERROR: AddressSanitizer heap-use-after-free on address 0x7f7ddab8c084 at pc 0x403c8c bp 0x7fff87fb82d0 sp 0x7fff87fb82c8
+ READ of size 4 at 0x7f7ddab8c084 thread T0
+ #0 0x403c8c in main example_UseAfterFree.cc:4
+ #1 0x7f7ddabcac4d in __libc_start_main ??:0
+ 0x7f7ddab8c084 is located 4 bytes inside of 400-byte region [0x7f7ddab8c080,0x7f7ddab8c210)
+ freed by thread T0 here:
+ #0 0x404704 in operator delete[](void*) ??:0
+ #1 0x403c53 in main example_UseAfterFree.cc:4
+ #2 0x7f7ddabcac4d in __libc_start_main ??:0
+ previously allocated by thread T0 here:
+ #0 0x404544 in operator new[](unsigned long) ??:0
+ #1 0x403c43 in main example_UseAfterFree.cc:2
+ #2 0x7f7ddabcac4d in __libc_start_main ??:0
+ ==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.
+:ref:`\_\_has\_feature <langext-__has_feature-__has_extension>` can be used for
+this purpose.
+
+.. code-block:: c
+
+ #if defined(__has_feature)
+ # if __has_feature(address_sanitizer)
+ // code that builds only under AddressSanitizer
+ # endif
+ #endif
+
+``__attribute__((no_sanitize_address))``
+-----------------------------------------------
+
+Some code should not be instrumented by AddressSanitizer. One may use the
+function attribute
+:ref:`no_sanitize_address <langext-address_sanitizer>`
+(or a deprecated synonym `no_address_safety_analysis`)
+to disable instrumentation of a particular function. This attribute may not be
+supported by other compilers, so we suggest to use it together with
+``__has_feature(address_sanitizer)``. Note: currently, this attribute will be
+lost if the function is inlined.
+
+Initialization order checking
+-----------------------------
+
+AddressSanitizer can optionally detect dynamic initialization order problems,
+when initialization of globals defined in one translation unit uses
+globals defined in another translation unit. To enable this check at runtime,
+you should set environment variable
+``ASAN_OPTIONS=check_initialization_order=1``.
+
+Supported Platforms
+===================
+
+AddressSanitizer is supported on
+
+* 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 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. 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. This means that tools like ``ulimit`` may not work as
+ usually expected.
+* Static linking is not supported.
+
+Current Status
+==============
+
+AddressSanitizer is fully functional on supported platforms starting from LLVM
+3.1. 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 <http://code.google.com/p/address-sanitizer/>`_
+
diff --git a/docs/AnalyzerRegions.html b/docs/AnalyzerRegions.html
deleted file mode 100644
index f9d3337..0000000
--- a/docs/AnalyzerRegions.html
+++ /dev/null
@@ -1,260 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
-<title>Static Analyzer Design Document: Memory Regions</title>
-</head>
-<body>
-
-<h1>Static Analyzer Design Document: Memory Regions</h1>
-
-<h3>Authors</h3>
-
-<p>Ted Kremenek, <tt>kremenek at apple</tt><br>
-Zhongxing Xu, <tt>xuzhongzhing at gmail</tt></p>
-
-<h2 id="intro">Introduction</h2>
-
-<p>The path-sensitive analysis engine in libAnalysis employs an extensible API
-for abstractly modeling the memory of an analyzed program. This API employs the
-concept of "memory regions" to abstractly model chunks of program memory such as
-program variables and dynamically allocated memory such as those returned from
-'malloc' and 'alloca'. Regions are hierarchical, with subregions modeling
-subtyping relationships, field and array offsets into larger chunks of memory,
-and so on.</p>
-
-<p>The region API consists of two components:</p>
-
-<ul> <li>A taxonomy and representation of regions themselves within the analyzer
-engine. The primary definitions and interfaces are described in <tt><a
-href="http://clang.llvm.org/doxygen/MemRegion_8h-source.html">MemRegion.h</a></tt>.
-At the root of the region hierarchy is the class <tt>MemRegion</tt> with
-specific subclasses refining the region concept for variables, heap allocated
-memory, and so forth.</li> <li>The modeling of binding of values to regions. For
-example, modeling the value stored to a local variable <tt>x</tt> consists of
-recording the binding between the region for <tt>x</tt> (which represents the
-raw memory associated with <tt>x</tt>) and the value stored to <tt>x</tt>. This
-binding relationship is captured with the notion of &quot;symbolic
-stores.&quot;</li> </ul>
-
-<p>Symbolic stores, which can be thought of as representing the relation
-<tt>regions -> values</tt>, are implemented by subclasses of the
-<tt>StoreManager</tt> class (<tt><a
-href="http://clang.llvm.org/doxygen/Store_8h-source.html">Store.h</a></tt>). A
-particular StoreManager implementation has complete flexibility concerning the
-following:
-
-<ul>
-<li><em>How</em> to model the binding between regions and values</li>
-<li><em>What</em> bindings are recorded
-</ul>
-
-<p>Together, both points allow different StoreManagers to tradeoff between
-different levels of analysis precision and scalability concerning the reasoning
-of program memory. Meanwhile, the core path-sensitive engine makes no
-assumptions about either points, and queries a StoreManager about the bindings
-to a memory region through a generic interface that all StoreManagers share. If
-a particular StoreManager cannot reason about the potential bindings of a given
-memory region (e.g., '<tt>BasicStoreManager</tt>' does not reason about fields
-of structures) then the StoreManager can simply return 'unknown' (represented by
-'<tt>UnknownVal</tt>') for a particular region-binding. This separation of
-concerns not only isolates the core analysis engine from the details of
-reasoning about program memory but also facilities the option of a client of the
-path-sensitive engine to easily swap in different StoreManager implementations
-that internally reason about program memory in very different ways.</p>
-
-<p>The rest of this document is divided into two parts. We first discuss region
-taxonomy and the semantics of regions. We then discuss the StoreManager
-interface, and details of how the currently available StoreManager classes
-implement region bindings.</p>
-
-<h2 id="regions">Memory Regions and Region Taxonomy</h2>
-
-<h3>Pointers</h3>
-
-<p>Before talking about the memory regions, we would talk about the pointers
-since memory regions are essentially used to represent pointer values.</p>
-
-<p>The pointer is a type of values. Pointer values have two semantic aspects.
-One is its physical value, which is an address or location. The other is the
-type of the memory object residing in the address.</p>
-
-<p>Memory regions are designed to abstract these two properties of the pointer.
-The physical value of a pointer is represented by MemRegion pointers. The rvalue
-type of the region corresponds to the type of the pointee object.</p>
-
-<p>One complication is that we could have different view regions on the same
-memory chunk. They represent the same memory location, but have different
-abstract location, i.e., MemRegion pointers. Thus we need to canonicalize the
-abstract locations to get a unique abstract location for one physical
-location.</p>
-
-<p>Furthermore, these different view regions may or may not represent memory
-objects of different types. Some different types are semantically the same,
-for example, 'struct s' and 'my_type' are the same type.</p>
-
-<pre>
-struct s;
-typedef struct s my_type;
-</pre>
-
-<p>But <tt>char</tt> and <tt>int</tt> are not the same type in the code below:</p>
-
-<pre>
-void *p;
-int *q = (int*) p;
-char *r = (char*) p;
-</pre>
-
-<p>Thus we need to canonicalize the MemRegion which is used in binding and
-retrieving.</p>
-
-<h3>Regions</h3>
-<p>Region is the entity used to model pointer values. A Region has the following
-properties:</p>
-
-<ul>
-<li>Kind</li>
-
-<li>ObjectType: the type of the object residing on the region.</li>
-
-<li>LocationType: the type of the pointer value that the region corresponds to.
- Usually this is the pointer to the ObjectType. But sometimes we want to cache
- this type explicitly, for example, for a CodeTextRegion.</li>
-
-<li>StartLocation</li>
-
-<li>EndLocation</li>
-</ul>
-
-<h3>Symbolic Regions</h3>
-
-<p>A symbolic region is a map of the concept of symbolic values into the domain
-of regions. It is the way that we represent symbolic pointers. Whenever a
-symbolic pointer value is needed, a symbolic region is created to represent
-it.</p>
-
-<p>A symbolic region has no type. It wraps a SymbolData. But sometimes we have
-type information associated with a symbolic region. For this case, a
-TypedViewRegion is created to layer the type information on top of the symbolic
-region. The reason we do not carry type information with the symbolic region is
-that the symbolic regions can have no type. To be consistent, we don't let them
-to carry type information.</p>
-
-<p>Like a symbolic pointer, a symbolic region may be NULL, has unknown extent,
-and represents a generic chunk of memory.</p>
-
-<p><em><b>NOTE</b>: We plan not to use loc::SymbolVal in RegionStore and remove it
- gradually.</em></p>
-
-<p>Symbolic regions get their rvalue types through the following ways:</p>
-
-<ul>
-<li>Through the parameter or global variable that points to it, e.g.:
-<pre>
-void f(struct s* p) {
- ...
-}
-</pre>
-
-<p>The symbolic region pointed to by <tt>p</tt> has type <tt>struct
-s</tt>.</p></li>
-
-<li>Through explicit or implicit casts, e.g.:
-<pre>
-void f(void* p) {
- struct s* q = (struct s*) p;
- ...
-}
-</pre>
-</li>
-</ul>
-
-<p>We attach the type information to the symbolic region lazily. For the first
-case above, we create the <tt>TypedViewRegion</tt> only when the pointer is
-actually used to access the pointee memory object, that is when the element or
-field region is created. For the cast case, the <tt>TypedViewRegion</tt> is
-created when visiting the <tt>CastExpr</tt>.</p>
-
-<p>The reason for doing lazy typing is that symbolic regions are sometimes only
-used to do location comparison.</p>
-
-<h3>Pointer Casts</h3>
-
-<p>Pointer casts allow people to impose different 'views' onto a chunk of
-memory.</p>
-
-<p>Usually we have two kinds of casts. One kind of casts cast down with in the
-type hierarchy. It imposes more specific views onto more generic memory regions.
-The other kind of casts cast up with in the type hierarchy. It strips away more
-specific views on top of the more generic memory regions.</p>
-
-<p>We simulate the down casts by layering another <tt>TypedViewRegion</tt> on
-top of the original region. We simulate the up casts by striping away the top
-<tt>TypedViewRegion</tt>. Down casts is usually simple. For up casts, if the
-there is no <tt>TypedViewRegion</tt> to be stripped, we return the original
-region. If the underlying region is of the different type than the cast-to type,
-we flag an error state.</p>
-
-<p>For toll-free bridging casts, we return the original region.</p>
-
-<p>We can set up a partial order for pointer types, with the most general type
-<tt>void*</tt> at the top. The partial order forms a tree with <tt>void*</tt> as
-its root node.</p>
-
-<p>Every <tt>MemRegion</tt> has a root position in the type tree. For example,
-the pointee region of <tt>void *p</tt> has its root position at the root node of
-the tree. <tt>VarRegion</tt> of <tt>int x</tt> has its root position at the 'int
-type' node.</p>
-
-<p><tt>TypedViewRegion</tt> is used to move the region down or up in the tree.
-Moving down in the tree adds a <tt>TypedViewRegion</tt>. Moving up in the tree
-removes a <Tt>TypedViewRegion</tt>.</p>
-
-<p>Do we want to allow moving up beyond the root position? This happens
-when:</p> <pre> int x; void *p = &amp;x; </pre>
-
-<p>The region of <tt>x</tt> has its root position at 'int*' node. the cast to
-void* moves that region up to the 'void*' node. I propose to not allow such
-casts, and assign the region of <tt>x</tt> for <tt>p</tt>.</p>
-
-<p>Another non-ideal case is that people might cast to a non-generic pointer
-from another non-generic pointer instead of first casting it back to the generic
-pointer. Direct handling of this case would result in multiple layers of
-TypedViewRegions. This enforces an incorrect semantic view to the region,
-because we can only have one typed view on a region at a time. To avoid this
-inconsistency, before casting the region, we strip the TypedViewRegion, then do
-the cast. In summary, we only allow one layer of TypedViewRegion.</p>
-
-<h3>Region Bindings</h3>
-
-<p>The following region kinds are boundable: VarRegion, CompoundLiteralRegion,
-StringRegion, ElementRegion, FieldRegion, and ObjCIvarRegion.</p>
-
-<p>When binding regions, we perform canonicalization on element regions and field
-regions. This is because we can have different views on the same region, some
-of which are essentially the same view with different sugar type names.</p>
-
-<p>To canonicalize a region, we get the canonical types for all TypedViewRegions
-along the way up to the root region, and make new TypedViewRegions with those
-canonical types.</p>
-
-<p>For Objective-C and C++, perhaps another canonicalization rule should be
-added: for FieldRegion, the least derived class that has the field is used as
-the type of the super region of the FieldRegion.</p>
-
-<p>All bindings and retrievings are done on the canonicalized regions.</p>
-
-<p>Canonicalization is transparent outside the region store manager, and more
-specifically, unaware outside the Bind() and Retrieve() method. We don't need to
-consider region canonicalization when doing pointer cast.</p>
-
-<h3>Constraint Manager</h3>
-
-<p>The constraint manager reasons about the abstract location of memory objects.
-We can have different views on a region, but none of these views changes the
-location of that object. Thus we should get the same abstract location for those
-regions.</p>
-
-</body>
-</html>
diff --git a/docs/AutomaticReferenceCounting.html b/docs/AutomaticReferenceCounting.html
deleted file mode 100644
index 5354f8a..0000000
--- a/docs/AutomaticReferenceCounting.html
+++ /dev/null
@@ -1,2226 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
-<title>Objective-C Automatic Reference Counting (ARC)</title>
-<link type="text/css" rel="stylesheet" href="../menu.css">
-<link type="text/css" rel="stylesheet" href="../content.css">
-<style type="text/css">
-/* Collapse the items in the ToC to the left. */
-div#toc ul {
- padding-left: 0
-}
-
-/* Rationales appear in italic. */
-div.rationale {
- font-style: italic
-}
-
-div.rationale em {
- font-style: normal
-}
-
-/* Revisions are also italicized. */
-span.revision {
- font-style: italic
-}
-
-span.whenRevised {
- font-weight: bold;
- font-style: normal
-}
-
-div h1 { font-size: 2em; margin: .67em 0 }
-div div h1 { font-size: 1.5em; margin: .75em 0 }
-div div div h1 { font-size: 1.17em; margin: .83em 0 }
-div div div div h1 { margin: 1.12em 0 }
-
-span.term { font-style: italic; font-weight: bold }
-</style>
-
-<script type="text/javascript">
-/// A little script to recursively build a table of contents.
-function buildTOC(div, toc, ancestry) {
- var children = div.childNodes;
- var len = children.length;
-
- var childNumber = 0;
-
- var list = null;
- for (var i = 0; i < len; ++i) {
- var child = children[i];
- if (child.nodeName != "DIV") continue;
- if (child.getAttribute("class") == "rationale") continue;
- if (child.id == "toc") continue;
-
- // Okay, we're actually going to build a list node.
- if (list === null) list = document.createElement("ul");
-
- var childAncestry = ancestry + ++childNumber + ".";
-
- var headerNode = child.childNodes[1];
- var title = headerNode.innerHTML;
- headerNode.insertBefore(document.createTextNode(childAncestry + " "),
- headerNode.firstChild);
-
- var item = document.createElement("li");
- item.appendChild(document.createTextNode(childAncestry + " "));
-
- var anchor = document.createElement("a");
- anchor.href = "#" + child.id;
- anchor.innerHTML = title;
- item.appendChild(anchor);
-
- buildTOC(child, item, childAncestry);
-
- list.appendChild(item);
- }
- if (list) toc.appendChild(list);
-}
-
-function onLoad() {
- var toc = document.getElementById("toc");
- var content = document.getElementById("content");
- buildTOC(content, toc, "");
-}
-window.onload = onLoad;
-
-</script>
-</head>
-<body>
-
-<!--#include virtual="../menu.html.incl"-->
-
-<div id="content">
-<h1>Automatic Reference Counting</h1>
-
-<div id="toc">
-</div>
-
-<div id="meta">
-<h1>About this document</h1>
-
-<div id="meta.purpose">
-<h1>Purpose</h1>
-
-<p>The first and primary purpose of this document is to serve as a
-complete technical specification of Automatic Reference Counting.
-Given a core Objective-C compiler and runtime, it should be possible
-to write a compiler and runtime which implements these new
-semantics.</p>
-
-<p>The secondary purpose is to act as a rationale for why ARC was
-designed in this way. This should remain tightly focused on the
-technical design and should not stray into marketing speculation.</p>
-
-</div> <!-- meta.purpose -->
-
-<div id="meta.background">
-<h1>Background</h1>
-
-<p>This document assumes a basic familiarity with C.</p>
-
-<p><span class="term">Blocks</span> are a C language extension for
-creating anonymous functions. Users interact with and transfer block
-objects using <span class="term">block pointers</span>, which are
-represented like a normal pointer. A block may capture values from
-local variables; when this occurs, memory must be dynamically
-allocated. The initial allocation is done on the stack, but the
-runtime provides a <tt>Block_copy</tt> function which, given a block
-pointer, either copies the underlying block object to the heap,
-setting its reference count to 1 and returning the new block pointer,
-or (if the block object is already on the heap) increases its
-reference count by 1. The paired function is <tt>Block_release</tt>,
-which decreases the reference count by 1 and destroys the object if
-the count reaches zero and is on the heap.</p>
-
-<p>Objective-C is a set of language extensions, significant enough to
-be considered a different language. It is a strict superset of C.
-The extensions can also be imposed on C++, producing a language called
-Objective-C++. The primary feature is a single-inheritance object
-system; we briefly describe the modern dialect.</p>
-
-<p>Objective-C defines a new type kind, collectively called
-the <span class="term">object pointer types</span>. This kind has two
-notable builtin members, <tt>id</tt> and <tt>Class</tt>; <tt>id</tt>
-is the final supertype of all object pointers. The validity of
-conversions between object pointer types is not checked at runtime.
-Users may define <span class="term">classes</span>; each class is a
-type, and the pointer to that type is an object pointer type. A class
-may have a superclass; its pointer type is a subtype of its
-superclass's pointer type. A class has a set
-of <span class="term">ivars</span>, fields which appear on all
-instances of that class. For every class <i>T</i> there's an
-associated metaclass; it has no fields, its superclass is the
-metaclass of <i>T</i>'s superclass, and its metaclass is a global
-class. Every class has a global object whose class is the
-class's metaclass; metaclasses have no associated type, so pointers to
-this object have type <tt>Class</tt>.</p>
-
-<p>A class declaration (<tt>@interface</tt>) declares a set
-of <span class="term">methods</span>. A method has a return type, a
-list of argument types, and a <span class="term">selector</span>: a
-name like <tt>foo:bar:baz:</tt>, where the number of colons
-corresponds to the number of formal arguments. A method may be an
-instance method, in which case it can be invoked on objects of the
-class, or a class method, in which case it can be invoked on objects
-of the metaclass. A method may be invoked by providing an object
-(called the <span class="term">receiver</span>) and a list of formal
-arguments interspersed with the selector, like so:</p>
-
-<pre>[receiver foo: fooArg bar: barArg baz: bazArg]</pre>
-
-<p>This looks in the dynamic class of the receiver for a method with
-this name, then in that class's superclass, etc., until it finds
-something it can execute. The receiver <q>expression</q> may also be
-the name of a class, in which case the actual receiver is the class
-object for that class, or (within method definitions) it may
-be <tt>super</tt>, in which case the lookup algorithm starts with the
-static superclass instead of the dynamic class. The actual methods
-dynamically found in a class are not those declared in the
-<tt>@interface</tt>, but those defined in a separate
-<tt>@implementation</tt> declaration; however, when compiling a
-call, typechecking is done based on the methods declared in the
-<tt>@interface</tt>.</p>
-
-<p>Method declarations may also be grouped into
-<span class="term">protocols</span>, which are not inherently
-associated with any class, but which classes may claim to follow.
-Object pointer types may be qualified with additional protocols that
-the object is known to support.</p>
-
-<p><span class="term">Class extensions</span> are collections of ivars
-and methods, designed to allow a class's <tt>@interface</tt> to be
-split across multiple files; however, there is still a primary
-implementation file which must see the <tt>@interface</tt>s of all
-class extensions.
-<span class="term">Categories</span> allow methods (but not ivars) to
-be declared <i>post hoc</i> on an arbitrary class; the methods in the
-category's <tt>@implementation</tt> will be dynamically added to that
-class's method tables which the category is loaded at runtime,
-replacing those methods in case of a collision.</p>
-
-<p>In the standard environment, objects are allocated on the heap, and
-their lifetime is manually managed using a reference count. This is
-done using two instance methods which all classes are expected to
-implement: <tt>retain</tt> increases the object's reference count by
-1, whereas <tt>release</tt> decreases it by 1 and calls the instance
-method <tt>dealloc</tt> if the count reaches 0. To simplify certain
-operations, there is also an <span class="term">autorelease
-pool</span>, a thread-local list of objects to call <tt>release</tt>
-on later; an object can be added to this pool by
-calling <tt>autorelease</tt> on it.</p>
-
-<p>Block pointers may be converted to type <tt>id</tt>; block objects
-are laid out in a way that makes them compatible with Objective-C
-objects. There is a builtin class that all block objects are
-considered to be objects of; this class implements <tt>retain</tt> by
-adjusting the reference count, not by calling <tt>Block_copy</tt>.</p>
-
-</div> <!-- meta.background -->
-
-<div id="meta.evolution">
-<h1>Evolution</h1>
-
-<p>ARC is under continual evolution, and this document must be updated
-as the language progresses.</p>
-
-<p>If a change increases the expressiveness of the language, for
-example by lifting a restriction or by adding new syntax, the change
-will be annotated with a revision marker, like so:</p>
-
-<blockquote>
- ARC applies to Objective-C pointer types, block pointer types, and
- <span class="revision"><span class="whenRevised">[beginning Apple
- 8.0, LLVM 3.8]</span> BPTRs declared within <code>extern
- "BCPL"</code> blocks</span>.
-</blockquote>
-
-<p>For now, it is sensible to version this document by the releases of
-its sole implementation (and its host project), clang.
-<q>LLVM X.Y</q> refers to an open-source release of clang from the
-LLVM project. <q>Apple X.Y</q> refers to an Apple-provided release of
-the Apple LLVM Compiler. Other organizations that prepare their own,
-separately-versioned clang releases and wish to maintain similar
-information in this document should send requests to cfe-dev.</p>
-
-<p>If a change decreases the expressiveness of the language, for
-example by imposing a new restriction, this should be taken as an
-oversight in the original specification and something to be avoided
-in all versions. Such changes are generally to be avoided.</p>
-
-</div> <!-- meta.evolution -->
-
-</div> <!-- meta -->
-
-<div id="general">
-<h1>General</h1>
-
-<p>Automatic Reference Counting implements automatic memory management
-for Objective-C objects and blocks, freeing the programmer from the
-need to explicitly insert retains and releases. It does not provide a
-cycle collector; users must explicitly manage the lifetime of their
-objects, breaking cycles manually or with weak or unsafe
-references.</p>
-
-<p>ARC may be explicitly enabled with the compiler
-flag <tt>-fobjc-arc</tt>. It may also be explicitly disabled with the
-compiler flag <tt>-fno-objc-arc</tt>. The last of these two flags
-appearing on the compile line <q>wins</q>.</p>
-
-<p>If ARC is enabled, <tt>__has_feature(objc_arc)</tt> will expand to
-1 in the preprocessor. For more information about <tt>__has_feature</tt>,
-see the <a href="LanguageExtensions.html#__has_feature_extension">language
-extensions</a> document.</p>
-
-</div> <!-- general -->
-
-<div id="objects">
-<h1>Retainable object pointers</h1>
-
-<p>This section describes retainable object pointers, their basic
-operations, and the restrictions imposed on their use under ARC. Note
-in particular that it covers the rules for pointer <em>values</em>
-(patterns of bits indicating the location of a pointed-to object), not
-pointer
-<em>objects</em> (locations in memory which store pointer values).
-The rules for objects are covered in the next section.</p>
-
-<p>A <span class="term">retainable object pointer</span>
-(or <q>retainable pointer</q>) is a value of
-a <span class="term">retainable object pointer type</span>
-(<q>retainable type</q>). There are three kinds of retainable object
-pointer types:</p>
-<ul>
-<li>block pointers (formed by applying the caret (<tt>^</tt>)
-declarator sigil to a function type)</li>
-<li>Objective-C object pointers (<tt>id</tt>, <tt>Class</tt>, <tt>NSFoo*</tt>, etc.)</li>
-<li>typedefs marked with <tt>__attribute__((NSObject))</tt></li>
-</ul>
-
-<p>Other pointer types, such as <tt>int*</tt> and <tt>CFStringRef</tt>,
-are not subject to ARC's semantics and restrictions.</p>
-
-<div class="rationale">
-
-<p>Rationale: We are not at liberty to require
-all code to be recompiled with ARC; therefore, ARC must interoperate
-with Objective-C code which manages retains and releases manually. In
-general, there are three requirements in order for a
-compiler-supported reference-count system to provide reliable
-interoperation:</p>
-
-<ul>
-<li>The type system must reliably identify which objects are to be
-managed. An <tt>int*</tt> might be a pointer to a <tt>malloc</tt>'ed
-array, or it might be an interior pointer to such an array, or it might
-point to some field or local variable. In contrast, values of the
-retainable object pointer types are never interior.</li>
-<li>The type system must reliably indicate how to
-manage objects of a type. This usually means that the type must imply
-a procedure for incrementing and decrementing retain counts.
-Supporting single-ownership objects requires a lot more explicit
-mediation in the language.</li>
-<li>There must be reliable conventions for whether and
-when <q>ownership</q> is passed between caller and callee, for both
-arguments and return values. Objective-C methods follow such a
-convention very reliably, at least for system libraries on Mac OS X,
-and functions always pass objects at +0. The C-based APIs for Core
-Foundation objects, on the other hand, have much more varied transfer
-semantics.</li>
-</ul>
-</div> <!-- rationale -->
-
-<p>The use of <tt>__attribute__((NSObject))</tt> typedefs is not
-recommended. If it's absolutely necessary to use this attribute, be
-very explicit about using the typedef, and do not assume that it will
-be preserved by language features like <tt>__typeof</tt> and C++
-template argument substitution.</p>
-
-<div class="rationale"><p>Rationale: any compiler operation which
-incidentally strips type <q>sugar</q> from a type will yield a type
-without the attribute, which may result in unexpected
-behavior.</p></div>
-
-<div id="objects.retains">
-<h1>Retain count semantics</h1>
-
-<p>A retainable object pointer is either a <span class="term">null
-pointer</span> or a pointer to a valid object. Furthermore, if it has
-block pointer type and is not <tt>null</tt> then it must actually be a
-pointer to a block object, and if it has <tt>Class</tt> type (possibly
-protocol-qualified) then it must actually be a pointer to a class
-object. Otherwise ARC does not enforce the Objective-C type system as
-long as the implementing methods follow the signature of the static
-type. It is undefined behavior if ARC is exposed to an invalid
-pointer.</p>
-
-<p>For ARC's purposes, a valid object is one with <q>well-behaved</q>
-retaining operations. Specifically, the object must be laid out such
-that the Objective-C message send machinery can successfully send it
-the following messages:</p>
-
-<ul>
-<li><tt>retain</tt>, taking no arguments and returning a pointer to
-the object.</li>
-<li><tt>release</tt>, taking no arguments and returning <tt>void</tt>.</li>
-<li><tt>autorelease</tt>, taking no arguments and returning a pointer
-to the object.</li>
-</ul>
-
-<p>The behavior of these methods is constrained in the following ways.
-The term <span class="term">high-level semantics</span> is an
-intentionally vague term; the intent is that programmers must
-implement these methods in a way such that the compiler, modifying
-code in ways it deems safe according to these constraints, will not
-violate their requirements. For example, if the user puts logging
-statements in <tt>retain</tt>, they should not be surprised if those
-statements are executed more or less often depending on optimization
-settings. These constraints are not exhaustive of the optimization
-opportunities: values held in local variables are subject to
-additional restrictions, described later in this document.</p>
-
-<p>It is undefined behavior if a computation history featuring a send
-of <tt>retain</tt> followed by a send of <tt>release</tt> to the same
-object, with no intervening <tt>release</tt> on that object, is not
-equivalent under the high-level semantics to a computation
-history in which these sends are removed. Note that this implies that
-these methods may not raise exceptions.</p>
-
-<p>It is undefined behavior if a computation history features any use
-whatsoever of an object following the completion of a send
-of <tt>release</tt> that is not preceded by a send of <tt>retain</tt>
-to the same object.</p>
-
-<p>The behavior of <tt>autorelease</tt> must be equivalent to sending
-<tt>release</tt> when one of the autorelease pools currently in scope
-is popped. It may not throw an exception.</p>
-
-<p>When the semantics call for performing one of these operations on a
-retainable object pointer, if that pointer is <tt>null</tt> then the
-effect is a no-op.</p>
-
-<p>All of the semantics described in this document are subject to
-additional <a href="#optimization">optimization rules</a> which permit
-the removal or optimization of operations based on local knowledge of
-data flow. The semantics describe the high-level behaviors that the
-compiler implements, not an exact sequence of operations that a
-program will be compiled into.</p>
-
-</div> <!-- objects.retains -->
-
-<div id="objects.operands">
-<h1>Retainable object pointers as operands and arguments</h1>
-
-<p>In general, ARC does not perform retain or release operations when
-simply using a retainable object pointer as an operand within an
-expression. This includes:</p>
-<ul>
-<li>loading a retainable pointer from an object with non-weak
-<a href="#ownership">ownership</a>,</li>
-<li>passing a retainable pointer as an argument to a function or
-method, and</li>
-<li>receiving a retainable pointer as the result of a function or
-method call.</li>
-</ul>
-
-<div class="rationale"><p>Rationale: while this might seem
-uncontroversial, it is actually unsafe when multiple expressions are
-evaluated in <q>parallel</q>, as with binary operators and calls,
-because (for example) one expression might load from an object while
-another writes to it. However, C and C++ already call this undefined
-behavior because the evaluations are unsequenced, and ARC simply
-exploits that here to avoid needing to retain arguments across a large
-number of calls.</p></div>
-
-<p>The remainder of this section describes exceptions to these rules,
-how those exceptions are detected, and what those exceptions imply
-semantically.</p>
-
-<div id="objects.operands.consumed">
-<h1>Consumed parameters</h1>
-
-<p>A function or method parameter of retainable object pointer type
-may be marked as <span class="term">consumed</span>, signifying that
-the callee expects to take ownership of a +1 retain count. This is
-done by adding the <tt>ns_consumed</tt> attribute to the parameter
-declaration, like so:</p>
-
-<pre>void foo(__attribute((ns_consumed)) id x);
-- (void) foo: (id) __attribute((ns_consumed)) x;</pre>
-
-<p>This attribute is part of the type of the function or method, not
-the type of the parameter. It controls only how the argument is
-passed and received.</p>
-
-<p>When passing such an argument, ARC retains the argument prior to
-making the call.</p>
-
-<p>When receiving such an argument, ARC releases the argument at the
-end of the function, subject to the usual optimizations for local
-values.</p>
-
-<div class="rationale"><p>Rationale: this formalizes direct transfers
-of ownership from a caller to a callee. The most common scenario here
-is passing the <tt>self</tt> parameter to <tt>init</tt>, but it is
-useful to generalize. Typically, local optimization will remove any
-extra retains and releases: on the caller side the retain will be
-merged with a +1 source, and on the callee side the release will be
-rolled into the initialization of the parameter.</p></div>
-
-<p>The implicit <tt>self</tt> parameter of a method may be marked as
-consumed by adding <tt>__attribute__((ns_consumes_self))</tt> to the
-method declaration. Methods in the <tt>init</tt>
-<a href="#family">family</a> are treated as if they were implicitly
-marked with this attribute.</p>
-
-<p>It is undefined behavior if an Objective-C message send to a method
-with <tt>ns_consumed</tt> parameters (other than self) is made with a
-null receiver. It is undefined behavior if the method to which an
-Objective-C message send statically resolves to has a different set
-of <tt>ns_consumed</tt> parameters than the method it dynamically
-resolves to. It is undefined behavior if a block or function call is
-made through a static type with a different set of <tt>ns_consumed</tt>
-parameters than the implementation of the called block or function.</p>
-
-<div class="rationale"><p>Rationale: consumed parameters with null
-receiver are a guaranteed leak. Mismatches with consumed parameters
-will cause over-retains or over-releases, depending on the direction.
-The rule about function calls is really just an application of the
-existing C/C++ rule about calling functions through an incompatible
-function type, but it's useful to state it explicitly.</p></div>
-
-</div> <!-- objects.operands.consumed -->
-
-<div id="objects.operands.retained-returns">
-<h1>Retained return values</h1>
-
-<p>A function or method which returns a retainable object pointer type
-may be marked as returning a retained value, signifying that the
-caller expects to take ownership of a +1 retain count. This is done
-by adding the <tt>ns_returns_retained</tt> attribute to the function or
-method declaration, like so:</p>
-
-<pre>id foo(void) __attribute((ns_returns_retained));
-- (id) foo __attribute((ns_returns_retained));</pre>
-
-<p>This attribute is part of the type of the function or method.</p>
-
-<p>When returning from such a function or method, ARC retains the
-value at the point of evaluation of the return statement, before
-leaving all local scopes.</p>
-
-<p>When receiving a return result from such a function or method, ARC
-releases the value at the end of the full-expression it is contained
-within, subject to the usual optimizations for local values.</p>
-
-<div class="rationale"><p>Rationale: this formalizes direct transfers of
-ownership from a callee to a caller. The most common scenario this
-models is the retained return from <tt>init</tt>, <tt>alloc</tt>,
-<tt>new</tt>, and <tt>copy</tt> methods, but there are other cases in
-the frameworks. After optimization there are typically no extra
-retains and releases required.</p></div>
-
-<p>Methods in
-the <tt>alloc</tt>, <tt>copy</tt>, <tt>init</tt>, <tt>mutableCopy</tt>,
-and <tt>new</tt> <a href="#family">families</a> are implicitly marked
-<tt>__attribute__((ns_returns_retained))</tt>. This may be suppressed
-by explicitly marking the
-method <tt>__attribute__((ns_returns_not_retained))</tt>.</p>
-
-<p>It is undefined behavior if the method to which an Objective-C
-message send statically resolves has different retain semantics on its
-result from the method it dynamically resolves to. It is undefined
-behavior if a block or function call is made through a static type
-with different retain semantics on its result from the implementation
-of the called block or function.</p>
-
-<div class="rationale"><p>Rationale: Mismatches with returned results
-will cause over-retains or over-releases, depending on the direction.
-Again, the rule about function calls is really just an application of
-the existing C/C++ rule about calling functions through an
-incompatible function type.</p></div>
-
-</div> <!-- objects.operands.retained-returns -->
-
-<div id="objects.operands.other-returns">
-<h1>Unretained return values</h1>
-
-<p>A method or function which returns a retainable object type but
-does not return a retained value must ensure that the object is
-still valid across the return boundary.</p>
-
-<p>When returning from such a function or method, ARC retains the
-value at the point of evaluation of the return statement, then leaves
-all local scopes, and then balances out the retain while ensuring that
-the value lives across the call boundary. In the worst case, this may
-involve an <tt>autorelease</tt>, but callers must not assume that the
-value is actually in the autorelease pool.</p>
-
-<p>ARC performs no extra mandatory work on the caller side, although
-it may elect to do something to shorten the lifetime of the returned
-value.</p>
-
-<div class="rationale"><p>Rationale: it is common in non-ARC code to not
-return an autoreleased value; therefore the convention does not force
-either path. It is convenient to not be required to do unnecessary
-retains and autoreleases; this permits optimizations such as eliding
-retain/autoreleases when it can be shown that the original pointer
-will still be valid at the point of return.</p></div>
-
-<p>A method or function may be marked
-with <tt>__attribute__((ns_returns_autoreleased))</tt> to indicate
-that it returns a pointer which is guaranteed to be valid at least as
-long as the innermost autorelease pool. There are no additional
-semantics enforced in the definition of such a method; it merely
-enables optimizations in callers.</p>
-
-</div> <!-- objects.operands.other-returns -->
-
-<div id="objects.operands.casts">
-<h1>Bridged casts</h1>
-
-<p>A <span class="term">bridged cast</span> is a C-style cast
-annotated with one of three keywords:</p>
-
-<ul>
-<li><tt>(__bridge T) op</tt> casts the operand to the destination
-type <tt>T</tt>. If <tt>T</tt> is a retainable object pointer type,
-then <tt>op</tt> must have a non-retainable pointer type.
-If <tt>T</tt> is a non-retainable pointer type, then <tt>op</tt> must
-have a retainable object pointer type. Otherwise the cast is
-ill-formed. There is no transfer of ownership, and ARC inserts
-no retain operations.</li>
-
-<li><tt>(__bridge_retained T) op</tt> casts the operand, which must
-have retainable object pointer type, to the destination type, which
-must be a non-retainable pointer type. ARC retains the value, subject
-to the usual optimizations on local values, and the recipient is
-responsible for balancing that +1.</li>
-
-<li><tt>(__bridge_transfer T) op</tt> casts the operand, which must
-have non-retainable pointer type, to the destination type, which must
-be a retainable object pointer type. ARC will release the value at
-the end of the enclosing full-expression, subject to the usual
-optimizations on local values.</li>
-</ul>
-
-<p>These casts are required in order to transfer objects in and out of
-ARC control; see the rationale in the section
-on <a href="#objects.restrictions.conversion">conversion of retainable
-object pointers</a>.</p>
-
-<p>Using a <tt>__bridge_retained</tt> or <tt>__bridge_transfer</tt>
-cast purely to convince ARC to emit an unbalanced retain or release,
-respectively, is poor form.</p>
-
-</div> <!-- objects.operands.casts -->
-
-</div> <!-- objects.operands -->
-
-<div id="objects.restrictions">
-<h1>Restrictions</h1>
-
-<div id="objects.restrictions.conversion">
-<h1>Conversion of retainable object pointers</h1>
-
-<p>In general, a program which attempts to implicitly or explicitly
-convert a value of retainable object pointer type to any
-non-retainable type, or vice-versa, is ill-formed. For example, an
-Objective-C object pointer shall not be converted to <tt>void*</tt>.
-As an exception, cast to <tt>intptr_t</tt> is allowed because such
-casts are not transferring ownership. The <a href="#objects.operands.casts">bridged
-casts</a> may be used to perform these conversions where
-necessary.</p>
-
-<div class="rationale"><p>Rationale: we cannot ensure the correct
-management of the lifetime of objects if they may be freely passed
-around as unmanaged types. The bridged casts are provided so that the
-programmer may explicitly describe whether the cast transfers control
-into or out of ARC.</p></div>
-
-<p>However, the following exceptions apply.</p>
-
-</div> <!-- objects.restrictions.conversion -->
-
-<div id="objects.restrictions.conversion-exception-known">
-<h1>Conversion to retainable object pointer type of
- expressions with known semantics</h1>
-
-<p><span class="revision"><span class="whenRevised">[beginning Apple
- 4.0, LLVM 3.1]</span> These exceptions have been greatly expanded;
- they previously applied only to a much-reduced subset which is
- difficult to categorize but which included null pointers, message
- sends (under the given rules), and the various global constants.</span></p>
-
-<p>An unbridged conversion to a retainable object pointer type from a
-type other than a retainable object pointer type is ill-formed, as
-discussed above, unless the operand of the cast has a syntactic form
-which is known retained, known unretained, or known
-retain-agnostic.</p>
-
-<p>An expression is <span class="term">known retain-agnostic</span> if
-it is:</p>
-<ul>
-<li>an Objective-C string literal,</li>
-<li>a load from a <tt>const</tt> system global variable of
-<a href="#misc.c-retainable">C retainable pointer type</a>, or</li>
-<li>a null pointer constant.</li>
-</ul>
-
-<p>An expression is <span class="term">known unretained</span> if it
-is an rvalue of <a href="#misc.c-retainable">C retainable
-pointer type</a> and it is:</p>
-<ul>
-<li>a direct call to a function, and either that function has the
- <tt>cf_returns_not_retained</tt> attribute or it is an
- <a href="#misc.c-retainable.audit">audited</a> function that does not
- have the <tt>cf_returns_retained</tt> attribute and does not follow
- the create/copy naming convention,</li>
-<li>a message send, and the declared method either has
- the <tt>cf_returns_not_retained</tt> attribute or it has neither
- the <tt>cf_returns_retained</tt> attribute nor a
- <a href="#family">selector family</a> that implies a retained
- result.</li>
-</ul>
-
-<p>An expression is <span class="term">known retained</span> if it is
-an rvalue of <a href="#misc.c-retainable">C retainable pointer type</a>
-and it is:</p>
-<ul>
-<li>a message send, and the declared method either has the
- <tt>cf_returns_retained</tt> attribute, or it does not have
- the <tt>cf_returns_not_retained</tt> attribute but it does have a
- <a href="#family">selector family</a> that implies a retained
- result.</li>
-</ul>
-
-<p>Furthermore:</p>
-<ul>
-<li>a comma expression is classified according to its right-hand side,</li>
-<li>a statement expression is classified according to its result
-expression, if it has one,</li>
-<li>an lvalue-to-rvalue conversion applied to an Objective-C property
-lvalue is classified according to the underlying message send, and</li>
-<li>a conditional operator is classified according to its second and
-third operands, if they agree in classification, or else the other
-if one is known retain-agnostic.</li>
-</ul>
-
-<p>If the cast operand is known retained, the conversion is treated as
-a <tt>__bridge_transfer</tt> cast. If the cast operand is known
-unretained or known retain-agnostic, the conversion is treated as
-a <tt>__bridge</tt> cast.</p>
-
-<div class="rationale"><p>Rationale: Bridging casts are annoying.
-Absent the ability to completely automate the management of CF
-objects, however, we are left with relatively poor attempts to reduce
-the need for a glut of explicit bridges. Hence these rules.</p>
-
-<p>We've so far consciously refrained from implicitly turning retained
-CF results from function calls into <tt>__bridge_transfer</tt> casts.
-The worry is that some code patterns &mdash; for example, creating a
-CF value, assigning it to an ObjC-typed local, and then
-calling <tt>CFRelease</tt> when done &mdash; are a bit too likely to
-be accidentally accepted, leading to mysterious behavior.</p></div>
-
-</div> <!-- objects.restrictions.conversion-exception-known -->
-
-<div id="objects.restrictions.conversion-exception-contextual">
-<h1>Conversion from retainable object pointer type in certain contexts</h1>
-
-<p><span class="revision"><span class="whenRevised">[beginning Apple
- 4.0, LLVM 3.1]</span></span></p>
-
-<p>If an expression of retainable object pointer type is explicitly
-cast to a <a href="#misc.c-retainable">C retainable pointer type</a>,
-the program is ill-formed as discussed above unless the result is
-immediately used:</p>
-
-<ul>
-<li>to initialize a parameter in an Objective-C message send where the
-parameter is not marked with the <tt>cf_consumed</tt> attribute, or</li>
-<li>to initialize a parameter in a direct call to
-an <a href="#misc.c-retainable.audit">audited</a> function where the
-parameter is not marked with the <tt>cf_consumed</tt> attribute.</li>
-</ul>
-
-<div class="rationale"><p>Rationale: Consumed parameters are left out
-because ARC would naturally balance them with a retain, which was
-judged too treacherous. This is in part because several of the most
-common consuming functions are in the <tt>Release</tt> family, and it
-would be quite unfortunate for explicit releases to be silently
-balanced out in this way.</p></div>
-
-</div> <!-- objects.restrictions.conversion-exception-contextual -->
-
-</div> <!-- objects.restrictions -->
-
-</div> <!-- objects -->
-
-<div id="ownership">
-<h1>Ownership qualification</h1>
-
-<p>This section describes the behavior of <em>objects</em> of
-retainable object pointer type; that is, locations in memory which
-store retainable object pointers.</p>
-
-<p>A type is a <span class="term">retainable object owner type</span>
-if it is a retainable object pointer type or an array type whose
-element type is a retainable object owner type.</p>
-
-<p>An <span class="term">ownership qualifier</span> is a type
-qualifier which applies only to retainable object owner types. An array type is
-ownership-qualified according to its element type, and adding an ownership
-qualifier to an array type so qualifies its element type.</p>
-
-<p>A program is ill-formed if it attempts to apply an ownership qualifier
-to a type which is already ownership-qualified, even if it is the same
-qualifier. There is a single exception to this rule: an ownership qualifier
-may be applied to a substituted template type parameter, which overrides the
-ownership qualifier provided by the template argument.</p>
-
-<p>Except as described under
-the <a href="#ownership.inference">inference rules</a>, a program is
-ill-formed if it attempts to form a pointer or reference type to a
-retainable object owner type which lacks an ownership qualifier.</p>
-
-<div class="rationale"><p>Rationale: these rules, together with the
-inference rules, ensure that all objects and lvalues of retainable
-object pointer type have an ownership qualifier. The ability to override an ownership qualifier during template substitution is required to counteract the <a href="#ownership.inference.template_arguments">inference of <tt>__strong</tt> for template type arguments</a>. </p></div>
-
-<p>There are four ownership qualifiers:</p>
-
-<ul>
-<li><tt>__autoreleasing</tt></li>
-<li><tt>__strong</tt></li>
-<li><tt>__unsafe_unretained</tt></li>
-<li><tt>__weak</tt></li>
-</ul>
-
-<p>A type is <span class="term">nontrivially ownership-qualified</span>
-if it is qualified with <tt>__autoreleasing</tt>, <tt>__strong</tt>, or
-<tt>__weak</tt>.</p>
-
-<div id="ownership.spelling">
-<h1>Spelling</h1>
-
-<p>The names of the ownership qualifiers are reserved for the
-implementation. A program may not assume that they are or are not
-implemented with macros, or what those macros expand to.</p>
-
-<p>An ownership qualifier may be written anywhere that any other type
-qualifier may be written.</p>
-
-<p>If an ownership qualifier appears in
-the <i>declaration-specifiers</i>, the following rules apply:</p>
-
-<ul>
-<li>if the type specifier is a retainable object owner type, the
-qualifier applies to that type;</li>
-<li>if the outermost non-array part of the declarator is a pointer or
-block pointer, the qualifier applies to that type;</li>
-<li>otherwise the program is ill-formed.</li>
-</ul>
-
-<p>If an ownership qualifier appears on the declarator name, or on the
-declared object, it is applied to outermost pointer or block-pointer
-type.</p>
-
-<p>If an ownership qualifier appears anywhere else in a declarator, it
-applies to the type there.</p>
-
-<div id="ownership.spelling.property">
-<h1>Property declarations</h1>
-
-<p>A property of retainable object pointer type may have ownership.
-If the property's type is ownership-qualified, then the property has
-that ownership. If the property has one of the following modifiers,
-then the property has the corresponding ownership. A property is
-ill-formed if it has conflicting sources of ownership, or if it has
-redundant ownership modifiers, or if it has <tt>__autoreleasing</tt>
-ownership.</p>
-
-<ul>
-<li><tt>assign</tt> implies <tt>__unsafe_unretained</tt> ownership.</li>
-<li><tt>copy</tt> implies <tt>__strong</tt> ownership, as well as the
- usual behavior of copy semantics on the setter.</li>
-<li><tt>retain</tt> implies <tt>__strong</tt> ownership.</li>
-<li><tt>strong</tt> implies <tt>__strong</tt> ownership.</li>
-<li><tt>unsafe_unretained</tt> implies <tt>__unsafe_unretained</tt>
- ownership.</li>
-<li><tt>weak</tt> implies <tt>__weak</tt> ownership.</li>
-</ul>
-
-<p>With the exception of <tt>weak</tt>, these modifiers are available
-in non-ARC modes.</p>
-
-<p>A property's specified ownership is preserved in its metadata, but
-otherwise the meaning is purely conventional unless the property is
-synthesized. If a property is synthesized, then the
-<span class="term">associated instance variable</span> is the
-instance variable which is named, possibly implicitly, by the
-<tt>@synthesize</tt> declaration. If the associated instance variable
-already exists, then its ownership qualification must equal the
-ownership of the property; otherwise, the instance variable is created
-with that ownership qualification.</p>
-
-<p>A property of retainable object pointer type which is synthesized
-without a source of ownership has the ownership of its associated
-instance variable, if it already exists; otherwise,
-<span class="revision"><span class="whenRevised">[beginning Apple 3.1,
-LLVM 3.1]</span> its ownership is implicitly <tt>strong</tt></span>.
-Prior to this revision, it was ill-formed to synthesize such a
-property.</p>
-
-<div class="rationale"><p>Rationale: using <tt>strong</tt> by default
-is safe and consistent with the generic ARC rule about
-<a href="#ownership.inference.variables">inferring ownership</a>. It
-is, unfortunately, inconsistent with the non-ARC rule which states
-that such properties are implicitly <tt>assign</tt>. However, that
-rule is clearly untenable in ARC, since it leads to default-unsafe
-code. The main merit to banning the properties is to avoid confusion
-with non-ARC practice, which did not ultimately strike us as
-sufficient to justify requiring extra syntax and (more importantly)
-forcing novices to understand ownership rules just to declare a
-property when the default is so reasonable. Changing the rule away
-from non-ARC practice was acceptable because we had conservatively
-banned the synthesis in order to give ourselves exactly this
-leeway.</p></div>
-
-<p>Applying <tt>__attribute__((NSObject))</tt> to a property not of
-retainable object pointer type has the same behavior it does outside
-of ARC: it requires the property type to be some sort of pointer and
-permits the use of modifiers other than <tt>assign</tt>. These
-modifiers only affect the synthesized getter and setter; direct
-accesses to the ivar (even if synthesized) still have primitive
-semantics, and the value in the ivar will not be automatically
-released during deallocation.</p>
-
-</div> <!-- ownership.spelling.property -->
-
-</div> <!-- ownership.spelling -->
-
-<div id="ownership.semantics">
-<h1>Semantics</h1>
-
-<p>There are five <span class="term">managed operations</span> which
-may be performed on an object of retainable object pointer type. Each
-qualifier specifies different semantics for each of these operations.
-It is still undefined behavior to access an object outside of its
-lifetime.</p>
-
-<p>A load or store with <q>primitive semantics</q> has the same
-semantics as the respective operation would have on an <tt>void*</tt>
-lvalue with the same alignment and non-ownership qualification.</p>
-
-<p><span class="term">Reading</span> occurs when performing a
-lvalue-to-rvalue conversion on an object lvalue.</p>
-
-<ul>
-<li>For <tt>__weak</tt> objects, the current pointee is retained and
-then released at the end of the current full-expression. This must
-execute atomically with respect to assignments and to the final
-release of the pointee.</li>
-<li>For all other objects, the lvalue is loaded with primitive
-semantics.</li>
-</ul>
-
-<p><span class="term">Assignment</span> occurs when evaluating
-an assignment operator. The semantics vary based on the qualification:</p>
-<ul>
-<li>For <tt>__strong</tt> objects, the new pointee is first retained;
-second, the lvalue is loaded with primitive semantics; third, the new
-pointee is stored into the lvalue with primitive semantics; and
-finally, the old pointee is released. This is not performed
-atomically; external synchronization must be used to make this safe in
-the face of concurrent loads and stores.</li>
-<li>For <tt>__weak</tt> objects, the lvalue is updated to point to the
-new pointee, unless the new pointee is an object currently undergoing
-deallocation, in which case the lvalue is updated to a null pointer.
-This must execute atomically with respect to other assignments to the
-object, to reads from the object, and to the final release of the new
-pointee.</li>
-<li>For <tt>__unsafe_unretained</tt> objects, the new pointee is
-stored into the lvalue using primitive semantics.</li>
-<li>For <tt>__autoreleasing</tt> objects, the new pointee is retained,
-autoreleased, and stored into the lvalue using primitive semantics.</li>
-</ul>
-
-<p><span class="term">Initialization</span> occurs when an object's
-lifetime begins, which depends on its storage duration.
-Initialization proceeds in two stages:</p>
-<ol>
-<li>First, a null pointer is stored into the lvalue using primitive
-semantics. This step is skipped if the object
-is <tt>__unsafe_unretained</tt>.</li>
-<li>Second, if the object has an initializer, that expression is
-evaluated and then assigned into the object using the usual assignment
-semantics.</li>
-</ol>
-
-<p><span class="term">Destruction</span> occurs when an object's
-lifetime ends. In all cases it is semantically equivalent to
-assigning a null pointer to the object, with the proviso that of
-course the object cannot be legally read after the object's lifetime
-ends.</p>
-
-<p><span class="term">Moving</span> occurs in specific situations
-where an lvalue is <q>moved from</q>, meaning that its current pointee
-will be used but the object may be left in a different (but still
-valid) state. This arises with <tt>__block</tt> variables and rvalue
-references in C++. For <tt>__strong</tt> lvalues, moving is equivalent
-to loading the lvalue with primitive semantics, writing a null pointer
-to it with primitive semantics, and then releasing the result of the
-load at the end of the current full-expression. For all other
-lvalues, moving is equivalent to reading the object.</p>
-
-</div> <!-- ownership.semantics -->
-
-<div id="ownership.restrictions">
-<h1>Restrictions</h1>
-
-<div id="ownership.restrictions.weak">
-<h1>Weak-unavailable types</h1>
-
-<p>It is explicitly permitted for Objective-C classes to not
-support <tt>__weak</tt> references. It is undefined behavior to
-perform an operation with weak assignment semantics with a pointer to
-an Objective-C object whose class does not support <tt>__weak</tt>
-references.</p>
-
-<div class="rationale"><p>Rationale: historically, it has been
-possible for a class to provide its own reference-count implementation
-by overriding <tt>retain</tt>, <tt>release</tt>, etc. However, weak
-references to an object require coordination with its class's
-reference-count implementation because, among other things, weak loads
-and stores must be atomic with respect to the final release.
-Therefore, existing custom reference-count implementations will
-generally not support weak references without additional effort. This
-is unavoidable without breaking binary compatibility.</p></div>
-
-<p>A class may indicate that it does not support weak references by
-providing the <tt>objc_arc_weak_unavailable</tt> attribute on the
-class's interface declaration. A retainable object pointer type
-is <span class="term">weak-unavailable</span> if is a pointer to an
-(optionally protocol-qualified) Objective-C class <tt>T</tt>
-where <tt>T</tt> or one of its superclasses has
-the <tt>objc_arc_weak_unavailable</tt> attribute. A program is
-ill-formed if it applies the <tt>__weak</tt> ownership qualifier to a
-weak-unavailable type or if the value operand of a weak assignment
-operation has a weak-unavailable type.</p>
-</div> <!-- ownership.restrictions.weak -->
-
-<div id="ownership.restrictions.autoreleasing">
-<h1>Storage duration of <tt>__autoreleasing</tt> objects</h1>
-
-<p>A program is ill-formed if it declares an <tt>__autoreleasing</tt>
-object of non-automatic storage duration. A program is ill-formed
-if it captures an <tt>__autoreleasing</tt> object in a block or,
-unless by reference, in a C++11 lambda.</p>
-
-<div class="rationale"><p>Rationale: autorelease pools are tied to the
-current thread and scope by their nature. While it is possible to
-have temporary objects whose instance variables are filled with
-autoreleased objects, there is no way that ARC can provide any sort of
-safety guarantee there.</p></div>
-
-<p>It is undefined behavior if a non-null pointer is assigned to
-an <tt>__autoreleasing</tt> object while an autorelease pool is in
-scope and then that object is read after the autorelease pool's scope
-is left.</p>
-
-</div>
-
-<div id="ownership.restrictions.conversion.indirect">
-<h1>Conversion of pointers to ownership-qualified types</h1>
-
-<p>A program is ill-formed if an expression of type <tt>T*</tt> is
-converted, explicitly or implicitly, to the type <tt>U*</tt>,
-where <tt>T</tt> and <tt>U</tt> have different ownership
-qualification, unless:</p>
-<ul>
-<li><tt>T</tt> is qualified with <tt>__strong</tt>,
- <tt>__autoreleasing</tt>, or <tt>__unsafe_unretained</tt>, and
- <tt>U</tt> is qualified with both <tt>const</tt> and
- <tt>__unsafe_unretained</tt>; or</li>
-<li>either <tt>T</tt> or <tt>U</tt> is <tt>cv void</tt>, where
-<tt>cv</tt> is an optional sequence of non-ownership qualifiers; or</li>
-<li>the conversion is requested with a <tt>reinterpret_cast</tt> in
- Objective-C++; or</li>
-<li>the conversion is a
-well-formed <a href="#ownership.restrictions.pass_by_writeback">pass-by-writeback</a>.</li>
-</ul>
-
-<p>The analogous rule applies to <tt>T&amp;</tt> and <tt>U&amp;</tt> in
-Objective-C++.</p>
-
-<div class="rationale"><p>Rationale: these rules provide a reasonable
-level of type-safety for indirect pointers, as long as the underlying
-memory is not deallocated. The conversion to <tt>const
-__unsafe_unretained</tt> is permitted because the semantics of reads
-are equivalent across all these ownership semantics, and that's a very
-useful and common pattern. The interconversion with <tt>void*</tt> is
-useful for allocating memory or otherwise escaping the type system,
-but use it carefully. <tt>reinterpret_cast</tt> is considered to be
-an obvious enough sign of taking responsibility for any
-problems.</p></div>
-
-<p>It is undefined behavior to access an ownership-qualified object
-through an lvalue of a differently-qualified type, except that any
-non-<tt>__weak</tt> object may be read through
-an <tt>__unsafe_unretained</tt> lvalue.</p>
-
-<p>It is undefined behavior if a managed operation is performed on
-a <tt>__strong</tt> or <tt>__weak</tt> object without a guarantee that
-it contains a primitive zero bit-pattern, or if the storage for such
-an object is freed or reused without the object being first assigned a
-null pointer.</p>
-
-<div class="rationale"><p>Rationale: ARC cannot differentiate between
-an assignment operator which is intended to <q>initialize</q> dynamic
-memory and one which is intended to potentially replace a value.
-Therefore the object's pointer must be valid before letting ARC at it.
-Similarly, C and Objective-C do not provide any language hooks for
-destroying objects held in dynamic memory, so it is the programmer's
-responsibility to avoid leaks (<tt>__strong</tt> objects) and
-consistency errors (<tt>__weak</tt> objects).</p>
-
-<p>These requirements are followed automatically in Objective-C++ when
-creating objects of retainable object owner type with <tt>new</tt>
-or <tt>new[]</tt> and destroying them with <tt>delete</tt>,
-<tt>delete[]</tt>, or a pseudo-destructor expression. Note that
-arrays of nontrivially-ownership-qualified type are not ABI compatible
-with non-ARC code because the element type is non-POD: such arrays
-that are <tt>new[]</tt>'d in ARC translation units cannot
-be <tt>delete[]</tt>'d in non-ARC translation units and
-vice-versa.</p></div>
-
-</div>
-
-<div id="ownership.restrictions.pass_by_writeback">
-<h1>Passing to an out parameter by writeback</h1>
-
-<p>If the argument passed to a parameter of type
-<tt>T __autoreleasing *</tt> has type <tt>U oq *</tt>,
-where <tt>oq</tt> is an ownership qualifier, then the argument is a
-candidate for <span class="term">pass-by-writeback</span> if:</p>
-
-<ul>
-<li><tt>oq</tt> is <tt>__strong</tt> or <tt>__weak</tt>, and</li>
-<li>it would be legal to initialize a <tt>T __strong *</tt> with
-a <tt>U __strong *</tt>.</li>
-</ul>
-
-<p>For purposes of overload resolution, an implicit conversion
-sequence requiring a pass-by-writeback is always worse than an
-implicit conversion sequence not requiring a pass-by-writeback.</p>
-
-<p>The pass-by-writeback is ill-formed if the argument expression does
-not have a legal form:</p>
-
-<ul>
-<li><tt>&amp;var</tt>, where <tt>var</tt> is a scalar variable of
-automatic storage duration with retainable object pointer type</li>
-<li>a conditional expression where the second and third operands are
-both legal forms</li>
-<li>a cast whose operand is a legal form</li>
-<li>a null pointer constant</li>
-</ul>
-
-<div class="rationale"><p>Rationale: the restriction in the form of
-the argument serves two purposes. First, it makes it impossible to
-pass the address of an array to the argument, which serves to protect
-against an otherwise serious risk of mis-inferring an <q>array</q>
-argument as an out-parameter. Second, it makes it much less likely
-that the user will see confusing aliasing problems due to the
-implementation, below, where their store to the writeback temporary is
-not immediately seen in the original argument variable.</p></div>
-
-<p>A pass-by-writeback is evaluated as follows:</p>
-<ol>
-<li>The argument is evaluated to yield a pointer <tt>p</tt> of
- type <tt>U oq *</tt>.</li>
-<li>If <tt>p</tt> is a null pointer, then a null pointer is passed as
- the argument, and no further work is required for the pass-by-writeback.</li>
-<li>Otherwise, a temporary of type <tt>T __autoreleasing</tt> is
- created and initialized to a null pointer.</li>
-<li>If the parameter is not an Objective-C method parameter marked
- <tt>out</tt>, then <tt>*p</tt> is read, and the result is written
- into the temporary with primitive semantics.</li>
-<li>The address of the temporary is passed as the argument to the
- actual call.</li>
-<li>After the call completes, the temporary is loaded with primitive
- semantics, and that value is assigned into <tt>*p</tt>.</li>
-</ol>
-
-<div class="rationale"><p>Rationale: this is all admittedly
-convoluted. In an ideal world, we would see that a local variable is
-being passed to an out-parameter and retroactively modify its type to
-be <tt>__autoreleasing</tt> rather than <tt>__strong</tt>. This would
-be remarkably difficult and not always well-founded under the C type
-system. However, it was judged unacceptably invasive to require
-programmers to write <tt>__autoreleasing</tt> on all the variables
-they intend to use for out-parameters. This was the least bad
-solution.</p></div>
-
-</div>
-
-<div id="ownership.restrictions.records">
-<h1>Ownership-qualified fields of structs and unions</h1>
-
-<p>A program is ill-formed if it declares a member of a C struct or
-union to have a nontrivially ownership-qualified type.</p>
-
-<div class="rationale"><p>Rationale: the resulting type would be
-non-POD in the C++ sense, but C does not give us very good language
-tools for managing the lifetime of aggregates, so it is more
-convenient to simply forbid them. It is still possible to manage this
-with a <tt>void*</tt> or an <tt>__unsafe_unretained</tt>
-object.</p></div>
-
-<p>This restriction does not apply in Objective-C++. However,
-nontrivally ownership-qualified types are considered non-POD: in C++11
-terms, they are not trivially default constructible, copy
-constructible, move constructible, copy assignable, move assignable,
-or destructible. It is a violation of C++'s One Definition Rule to use
-a class outside of ARC that, under ARC, would have a nontrivially
-ownership-qualified member.</p>
-
-<div class="rationale"><p>Rationale: unlike in C, we can express all
-the necessary ARC semantics for ownership-qualified subobjects as
-suboperations of the (default) special member functions for the class.
-These functions then become non-trivial. This has the non-obvious
-result that the class will have a non-trivial copy constructor and
-non-trivial destructor; if this would not normally be true outside of
-ARC, objects of the type will be passed and returned in an
-ABI-incompatible manner.</p></div>
-
-</div>
-
-</div>
-
-<div id="ownership.inference">
-<h1>Ownership inference</h1>
-
-<div id="ownership.inference.variables">
-<h1>Objects</h1>
-
-<p>If an object is declared with retainable object owner type, but
-without an explicit ownership qualifier, its type is implicitly
-adjusted to have <tt>__strong</tt> qualification.</p>
-
-<p>As a special case, if the object's base type is <tt>Class</tt>
-(possibly protocol-qualified), the type is adjusted to
-have <tt>__unsafe_unretained</tt> qualification instead.</p>
-
-</div>
-
-<div id="ownership.inference.indirect_parameters">
-<h1>Indirect parameters</h1>
-
-<p>If a function or method parameter has type <tt>T*</tt>, where
-<tt>T</tt> is an ownership-unqualified retainable object pointer type,
-then:</p>
-
-<ul>
-<li>if <tt>T</tt> is <tt>const</tt>-qualified or <tt>Class</tt>, then
-it is implicitly qualified with <tt>__unsafe_unretained</tt>;</li>
-<li>otherwise, it is implicitly qualified
-with <tt>__autoreleasing</tt>.</li>
-</ul>
-
-<div class="rationale"><p>Rationale: <tt>__autoreleasing</tt> exists
-mostly for this case, the Cocoa convention for out-parameters. Since
-a pointer to <tt>const</tt> is obviously not an out-parameter, we
-instead use a type more useful for passing arrays. If the user
-instead intends to pass in a <em>mutable</em> array, inferring
-<tt>__autoreleasing</tt> is the wrong thing to do; this directs some
-of the caution in the following rules about writeback.</p></div>
-
-<p>Such a type written anywhere else would be ill-formed by the
-general rule requiring ownership qualifiers.</p>
-
-<p>This rule does not apply in Objective-C++ if a parameter's type is
-dependent in a template pattern and is only <em>instantiated</em> to
-a type which would be a pointer to an unqualified retainable object
-pointer type. Such code is still ill-formed.</p>
-
-<div class="rationale"><p>Rationale: the convention is very unlikely
-to be intentional in template code.</p></div>
-
-</div> <!-- ownership.inference.indirect_parameters -->
-
-<div id="ownership.inference.template_arguments">
-<h1>Template arguments</h1>
-
-<p>If a template argument for a template type parameter is an
-retainable object owner type that does not have an explicit ownership
-qualifier, it is adjusted to have <tt>__strong</tt>
-qualification. This adjustment occurs regardless of whether the
-template argument was deduced or explicitly specified. </p>
-
-<div class="rationale"><p>Rationale: <tt>__strong</tt> is a useful default for containers (e.g., <tt>std::vector&lt;id&gt;</tt>), which would otherwise require explicit qualification. Moreover, unqualified retainable object pointer types are unlikely to be useful within templates, since they generally need to have a qualifier applied to the before being used.</p></div>
-
-</div> <!-- ownership.inference.template_arguments -->
-</div> <!-- ownership.inference -->
-</div> <!-- ownership -->
-
-
-<div id="family">
-<h1>Method families</h1>
-
-<p>An Objective-C method may fall into a <span class="term">method
-family</span>, which is a conventional set of behaviors ascribed to it
-by the Cocoa conventions.</p>
-
-<p>A method is in a certain method family if:</p>
-<ul>
-<li>it has a <tt>objc_method_family</tt> attribute placing it in that
- family; or if not that,</li>
-<li>it does not have an <tt>objc_method_family</tt> attribute placing
- it in a different or no family, and</li>
-<li>its selector falls into the corresponding selector family, and</li>
-<li>its signature obeys the added restrictions of the method family.</li>
-</ul>
-
-<p>A selector is in a certain selector family if, ignoring any leading
-underscores, the first component of the selector either consists
-entirely of the name of the method family or it begins with that name
-followed by a character other than a lowercase letter. For
-example, <tt>_perform:with:</tt> and <tt>performWith:</tt> would fall
-into the <tt>perform</tt> family (if we recognized one),
-but <tt>performing:with</tt> would not.</p>
-
-<p>The families and their added restrictions are:</p>
-
-<ul>
-<li><tt>alloc</tt> methods must return a retainable object pointer type.</li>
-<li><tt>copy</tt> methods must return a retainable object pointer type.</li>
-<li><tt>mutableCopy</tt> methods must return a retainable object pointer type.</li>
-<li><tt>new</tt> methods must return a retainable object pointer type.</li>
-<li><tt>init</tt> methods must be instance methods and must return an
-Objective-C pointer type. Additionally, a program is ill-formed if it
-declares or contains a call to an <tt>init</tt> method whose return
-type is neither <tt>id</tt> nor a pointer to a super-class or
-sub-class of the declaring class (if the method was declared on
-a class) or the static receiver type of the call (if it was declared
-on a protocol).
-
-<div class="rationale"><p>Rationale: there are a fair number of existing
-methods with <tt>init</tt>-like selectors which nonetheless don't
-follow the <tt>init</tt> conventions. Typically these are either
-accidental naming collisions or helper methods called during
-initialization. Because of the peculiar retain/release behavior
-of <tt>init</tt> methods, it's very important not to treat these
-methods as <tt>init</tt> methods if they aren't meant to be. It was
-felt that implicitly defining these methods out of the family based on
-the exact relationship between the return type and the declaring class
-would be much too subtle and fragile. Therefore we identify a small
-number of legitimate-seeming return types and call everything else an
-error. This serves the secondary purpose of encouraging programmers
-not to accidentally give methods names in the <tt>init</tt> family.</p>
-
-<p>Note that a method with an <tt>init</tt>-family selector which
-returns a non-Objective-C type (e.g. <tt>void</tt>) is perfectly
-well-formed; it simply isn't in the <tt>init</tt> family.</p></div>
-</li>
-</ul>
-
-<p>A program is ill-formed if a method's declarations,
-implementations, and overrides do not all have the same method
-family.</p>
-
-<div id="family.attribute">
-<h1>Explicit method family control</h1>
-
-<p>A method may be annotated with the <tt>objc_method_family</tt>
-attribute to precisely control which method family it belongs to. If
-a method in an <tt>@implementation</tt> does not have this attribute,
-but there is a method declared in the corresponding <tt>@interface</tt>
-that does, then the attribute is copied to the declaration in the
-<tt>@implementation</tt>. The attribute is available outside of ARC,
-and may be tested for with the preprocessor query
-<tt>__has_attribute(objc_method_family)</tt>.</p>
-
-<p>The attribute is spelled
-<tt>__attribute__((objc_method_family(<i>family</i>)))</tt>.
-If <i>family</i> is <tt>none</tt>, the method has no family, even if
-it would otherwise be considered to have one based on its selector and
-type. Otherwise, <i>family</i> must be one
-of <tt>alloc</tt>, <tt>copy</tt>, <tt>init</tt>,
-<tt>mutableCopy</tt>, or <tt>new</tt>, in which case the method is
-considered to belong to the corresponding family regardless of its
-selector. It is an error if a method that is explicitly added to a
-family in this way does not meet the requirements of the family other
-than the selector naming convention.</p>
-
-<div class="rationale"><p>Rationale: the rules codified in this document
-describe the standard conventions of Objective-C. However, as these
-conventions have not heretofore been enforced by an unforgiving
-mechanical system, they are only imperfectly kept, especially as they
-haven't always even been precisely defined. While it is possible to
-define low-level ownership semantics with attributes like
-<tt>ns_returns_retained</tt>, this attribute allows the user to
-communicate semantic intent, which is of use both to ARC (which, e.g.,
-treats calls to <tt>init</tt> specially) and the static analyzer.</p></div>
-</div>
-
-<div id="family.semantics">
-<h1>Semantics of method families</h1>
-
-<p>A method's membership in a method family may imply non-standard
-semantics for its parameters and return type.</p>
-
-<p>Methods in the <tt>alloc</tt>, <tt>copy</tt>, <tt>mutableCopy</tt>,
-and <tt>new</tt> families &mdash; that is, methods in all the
-currently-defined families except <tt>init</tt> &mdash; implicitly
-<a href="#objects.operands.retained_returns">return a retained
-object</a> as if they were annotated with
-the <tt>ns_returns_retained</tt> attribute. This can be overridden by
-annotating the method with either of
-the <tt>ns_returns_autoreleased</tt> or
-<tt>ns_returns_not_retained</tt> attributes.</p>
-
-<p>Properties also follow same naming rules as methods. This means that
-those in the <tt>alloc</tt>, <tt>copy</tt>, <tt>mutableCopy</tt>,
-and <tt>new</tt> families provide access to
-<a href="#objects.operands.retained_returns">retained objects</a>.
-This can be overridden by annotating the property with
-<tt>ns_returns_not_retained</tt> attribute.</p>
-
-<div id="family.semantics.init">
-<h1>Semantics of <tt>init</tt></h1>
-<p>Methods in the <tt>init</tt> family implicitly
-<a href="#objects.operands.consumed">consume</a> their <tt>self</tt>
-parameter and <a href="#objects.operands.retained_returns">return a
-retained object</a>. Neither of these properties can be altered
-through attributes.</p>
-
-<p>A call to an <tt>init</tt> method with a receiver that is either
-<tt>self</tt> (possibly parenthesized or casted) or <tt>super</tt> is
-called a <span class="term">delegate init call</span>. It is an error
-for a delegate init call to be made except from an <tt>init</tt>
-method, and excluding blocks within such methods.</p>
-
-<p>As an exception to the <a href="misc.self">usual rule</a>, the
-variable <tt>self</tt> is mutable in an <tt>init</tt> method and has
-the usual semantics for a <tt>__strong</tt> variable. However, it is
-undefined behavior and the program is ill-formed, no diagnostic
-required, if an <tt>init</tt> method attempts to use the previous
-value of <tt>self</tt> after the completion of a delegate init call.
-It is conventional, but not required, for an <tt>init</tt> method to
-return <tt>self</tt>.</p>
-
-<p>It is undefined behavior for a program to cause two or more calls
-to <tt>init</tt> methods on the same object, except that
-each <tt>init</tt> method invocation may perform at most one delegate
-init call.</p>
-
-</div> <!-- family.semantics.init -->
-
-<div id="family.semantics.result_type">
-<h1>Related result types</h1>
-
-<p>Certain methods are candidates to have <span class="term">related
-result types</span>:</p>
-<ul>
-<li>class methods in the <tt>alloc</tt> and <tt>new</tt> method families</li>
-<li>instance methods in the <tt>init</tt> family</li>
-<li>the instance method <tt>self</tt></li>
-<li>outside of ARC, the instance methods <tt>retain</tt> and <tt>autorelease</tt></li>
-</ul>
-
-<p>If the formal result type of such a method is <tt>id</tt> or
-protocol-qualified <tt>id</tt>, or a type equal to the declaring class
-or a superclass, then it is said to have a related result type. In
-this case, when invoked in an explicit message send, it is assumed to
-return a type related to the type of the receiver:</p>
-
-<ul>
-<li>if it is a class method, and the receiver is a class
-name <tt>T</tt>, the message send expression has type <tt>T*</tt>;
-otherwise</li>
-<li>if it is an instance method, and the receiver has type <tt>T</tt>,
-the message send expression has type <tt>T</tt>; otherwise</li>
-<li>the message send expression has the normal result type of the
-method.</li>
-</ul>
-
-<p>This is a new rule of the Objective-C language and applies outside
-of ARC.</p>
-
-<div class="rationale"><p>Rationale: ARC's automatic code emission is
-more prone than most code to signature errors, i.e. errors where a
-call was emitted against one method signature, but the implementing
-method has an incompatible signature. Having more precise type
-information helps drastically lower this risk, as well as catching
-a number of latent bugs.</p></div>
-
-</div> <!-- family.semantics.result_type -->
-</div> <!-- family.semantics -->
-</div> <!-- family -->
-
-<div id="optimization">
-<h1>Optimization</h1>
-
-<p>ARC applies aggressive rules for the optimization of local
-behavior. These rules are based around a core assumption of
-<span class="term">local balancing</span>: that other code will
-perform retains and releases as necessary (and only as necessary) for
-its own safety, and so the optimizer does not need to consider global
-properties of the retain and release sequence. For example, if a
-retain and release immediately bracket a call, the optimizer can
-delete the retain and release on the assumption that the called
-function will not do a constant number of unmotivated releases
-followed by a constant number of <q>balancing</q> retains, such that
-the local retain/release pair is the only thing preventing the called
-function from ending up with a dangling reference.</p>
-
-<p>The optimizer assumes that when a new value enters local control,
-e.g. from a load of a non-local object or as the result of a function
-call, it is instaneously valid. Subsequently, a retain and release of
-a value are necessary on a computation path only if there is a use of
-that value before the release and after any operation which might
-cause a release of the value (including indirectly or non-locally),
-and only if the value is not demonstrably already retained.</p>
-
-<p>The complete optimization rules are quite complicated, but it would
-still be useful to document them here.</p>
-
-<div id="optimization.precise">
-<h1>Precise lifetime semantics</h1>
-
-<p>In general, ARC maintains an invariant that a retainable object
-pointer held in a <tt>__strong</tt> object will be retained for the
-full formal lifetime of the object. Objects subject to this invariant
-have <span class="term">precise lifetime semantics</span>.</p>
-
-<p>By default, local variables of automatic storage duration do not
-have precise lifetime semantics. Such objects are simply strong
-references which hold values of retainable object pointer type, and
-these values are still fully subject to the optimizations on values
-under local control.</p>
-
-<div class="rationale"><p>Rationale: applying these precise-lifetime
-semantics strictly would be prohibitive. Many useful optimizations
-that might theoretically decrease the lifetime of an object would be
-rendered impossible. Essentially, it promises too much.</p></div>
-
-<p>A local variable of retainable object owner type and automatic
-storage duration may be annotated with the <tt>objc_precise_lifetime</tt>
-attribute to indicate that it should be considered to be an object
-with precise lifetime semantics.</p>
-
-<div class="rationale"><p>Rationale: nonetheless, it is sometimes
-useful to be able to force an object to be released at a precise time,
-even if that object does not appear to be used. This is likely to be
-uncommon enough that the syntactic weight of explicitly requesting
-these semantics will not be burdensome, and may even make the code
-clearer.</p></div>
-
-</div> <!-- optimization.precise -->
-
-</div> <!-- optimization -->
-
-<div id="misc">
-<h1>Miscellaneous</h1>
-
-<div id="misc.special_methods">
-<h1>Special methods</h1>
-
-<div id="misc.special_methods.retain">
-<h1>Memory management methods</h1>
-
-<p>A program is ill-formed if it contains a method definition, message
-send, or <tt>@selector</tt> expression for any of the following
-selectors:</p>
-<ul>
-<li><tt>autorelease</tt></li>
-<li><tt>release</tt></li>
-<li><tt>retain</tt></li>
-<li><tt>retainCount</tt></li>
-</ul>
-
-<div class="rationale"><p>Rationale: <tt>retainCount</tt> is banned
-because ARC robs it of consistent semantics. The others were banned
-after weighing three options for how to deal with message sends:</p>
-
-<p><b>Honoring</b> them would work out very poorly if a programmer
-naively or accidentally tried to incorporate code written for manual
-retain/release code into an ARC program. At best, such code would do
-twice as much work as necessary; quite frequently, however, ARC and
-the explicit code would both try to balance the same retain, leading
-to crashes. The cost is losing the ability to perform <q>unrooted</q>
-retains, i.e. retains not logically corresponding to a strong
-reference in the object graph.</p>
-
-<p><b>Ignoring</b> them would badly violate user expectations about their
-code. While it <em>would</em> make it easier to develop code simultaneously
-for ARC and non-ARC, there is very little reason to do so except for
-certain library developers. ARC and non-ARC translation units share
-an execution model and can seamlessly interoperate. Within a
-translation unit, a developer who faithfully maintains their code in
-non-ARC mode is suffering all the restrictions of ARC for zero
-benefit, while a developer who isn't testing the non-ARC mode is
-likely to be unpleasantly surprised if they try to go back to it.</p>
-
-<p><b>Banning</b> them has the disadvantage of making it very awkward
-to migrate existing code to ARC. The best answer to that, given a
-number of other changes and restrictions in ARC, is to provide a
-specialized tool to assist users in that migration.</p>
-
-<p>Implementing these methods was banned because they are too integral
-to the semantics of ARC; many tricks which worked tolerably under
-manual reference counting will misbehave if ARC performs an ephemeral
-extra retain or two. If absolutely required, it is still possible to
-implement them in non-ARC code, for example in a category; the
-implementations must obey the <a href="#objects.retains">semantics</a>
-laid out elsewhere in this document.</p>
-
-</div>
-</div> <!-- misc.special_methods.retain -->
-
-<div id="misc.special_methods.dealloc">
-<h1><tt>dealloc</tt></h1>
-
-<p>A program is ill-formed if it contains a message send
-or <tt>@selector</tt> expression for the selector <tt>dealloc</tt>.</p>
-
-<div class="rationale"><p>Rationale: there are no legitimate reasons
-to call <tt>dealloc</tt> directly.</p></div>
-
-<p>A class may provide a method definition for an instance method
-named <tt>dealloc</tt>. This method will be called after the final
-<tt>release</tt> of the object but before it is deallocated or any of
-its instance variables are destroyed. The superclass's implementation
-of <tt>dealloc</tt> will be called automatically when the method
-returns.</p>
-
-<div class="rationale"><p>Rationale: even though ARC destroys instance
-variables automatically, there are still legitimate reasons to write
-a <tt>dealloc</tt> method, such as freeing non-retainable resources.
-Failing to call <tt>[super&nbsp;dealloc]</tt> in such a method is nearly
-always a bug. Sometimes, the object is simply trying to prevent
-itself from being destroyed, but <tt>dealloc</tt> is really far too
-late for the object to be raising such objections. Somewhat more
-legitimately, an object may have been pool-allocated and should not be
-deallocated with <tt>free</tt>; for now, this can only be supported
-with a <tt>dealloc</tt> implementation outside of ARC. Such an
-implementation must be very careful to do all the other work
-that <tt>NSObject</tt>'s <tt>dealloc</tt> would, which is outside the
-scope of this document to describe.</p></div>
-
-<p>The instance variables for an ARC-compiled class will be destroyed
-at some point after control enters the <tt>dealloc</tt> method for the
-root class of the class. The ordering of the destruction of instance
-variables is unspecified, both within a single class and between
-subclasses and superclasses.</p>
-
-<div class="rationale"><p>Rationale: the traditional, non-ARC pattern
-for destroying instance variables is to destroy them immediately
-before calling <tt>[super&nbsp;dealloc]</tt>. Unfortunately, message
-sends from the superclass are quite capable of reaching methods in the
-subclass, and those methods may well read or write to those instance
-variables. Making such message sends from dealloc is generally
-discouraged, since the subclass may well rely on other invariants that
-were broken during <tt>dealloc</tt>, but it's not so inescapably
-dangerous that we felt comfortable calling it undefined behavior.
-Therefore we chose to delay destroying the instance variables to a
-point at which message sends are clearly disallowed: the point at
-which the root class's deallocation routines take over.</p>
-
-<p>In most code, the difference is not observable. It can, however,
-be observed if an instance variable holds a strong reference to an
-object whose deallocation will trigger a side-effect which must be
-carefully ordered with respect to the destruction of the super class.
-Such code violates the design principle that semantically important
-behavior should be explicit. A simple fix is to clear the instance
-variable manually during <tt>dealloc</tt>; a more holistic solution is
-to move semantically important side-effects out of
-<tt>dealloc</tt> and into a separate teardown phase which can rely on
-working with well-formed objects.</p></div>
-
-</div>
-
-</div> <!-- misc.special_methods -->
-
-<div id="autoreleasepool">
-<h1><tt>@autoreleasepool</tt></h1>
-
-<p>To simplify the use of autorelease pools, and to bring them under
-the control of the compiler, a new kind of statement is available in
-Objective-C. It is written <tt>@autoreleasepool</tt> followed by
-a <i>compound-statement</i>, i.e. by a new scope delimited by curly
-braces. Upon entry to this block, the current state of the
-autorelease pool is captured. When the block is exited normally,
-whether by fallthrough or directed control flow (such
-as <tt>return</tt> or <tt>break</tt>), the autorelease pool is
-restored to the saved state, releasing all the objects in it. When
-the block is exited with an exception, the pool is not drained.</p>
-
-<p><tt>@autoreleasepool</tt> may be used in non-ARC translation units,
-with equivalent semantics.</p>
-
-<p>A program is ill-formed if it refers to the
-<tt>NSAutoreleasePool</tt> class.</p>
-
-<div class="rationale"><p>Rationale: autorelease pools are clearly
-important for the compiler to reason about, but it is far too much to
-expect the compiler to accurately reason about control dependencies
-between two calls. It is also very easy to accidentally forget to
-drain an autorelease pool when using the manual API, and this can
-significantly inflate the process's high-water-mark. The introduction
-of a new scope is unfortunate but basically required for sane
-interaction with the rest of the language. Not draining the pool
-during an unwind is apparently required by the Objective-C exceptions
-implementation.</p></div>
-
-</div> <!-- autoreleasepool -->
-
-<div id="misc.self">
-<h1><tt>self</tt></h1>
-
-<p>The <tt>self</tt> parameter variable of an Objective-C method is
-never actually retained by the implementation. It is undefined
-behavior, or at least dangerous, to cause an object to be deallocated
-during a message send to that object.</p>
-
-<p>To make this safe, for Objective-C instance methods <tt>self</tt> is
-implicitly <tt>const</tt> unless the method is in the <a
-href="#family.semantics.init"><tt>init</tt> family</a>. Further, <tt>self</tt>
-is <b>always</b> implicitly <tt>const</tt> within a class method.</p>
-
-<div class="rationale"><p>Rationale: the cost of
-retaining <tt>self</tt> in all methods was found to be prohibitive, as
-it tends to be live across calls, preventing the optimizer from
-proving that the retain and release are unnecessary &mdash; for good
-reason, as it's quite possible in theory to cause an object to be
-deallocated during its execution without this retain and release.
-Since it's extremely uncommon to actually do so, even unintentionally,
-and since there's no natural way for the programmer to remove this
-retain/release pair otherwise (as there is for other parameters by,
-say, making the variable <tt>__unsafe_unretained</tt>), we chose to
-make this optimizing assumption and shift some amount of risk to the
-user.</p></div>
-
-</div> <!-- misc.self -->
-
-<div id="misc.enumeration">
-<h1>Fast enumeration iteration variables</h1>
-
-<p>If a variable is declared in the condition of an Objective-C fast
-enumeration loop, and the variable has no explicit ownership
-qualifier, then it is qualified with <tt>const __strong</tt> and
-objects encountered during the enumeration are not actually
-retained.</p>
-
-<div class="rationale"><p>Rationale: this is an optimization made
-possible because fast enumeration loops promise to keep the objects
-retained during enumeration, and the collection itself cannot be
-synchronously modified. It can be overridden by explicitly qualifying
-the variable with <tt>__strong</tt>, which will make the variable
-mutable again and cause the loop to retain the objects it
-encounters.</p></div>
-
-</div> <!-- misc.enumeration -->
-
-<div id="misc.blocks">
-<h1>Blocks</h1>
-
-<p>The implicit <tt>const</tt> capture variables created when
-evaluating a block literal expression have the same ownership
-semantics as the local variables they capture. The capture is
-performed by reading from the captured variable and initializing the
-capture variable with that value; the capture variable is destroyed
-when the block literal is, i.e. at the end of the enclosing scope.</p>
-
-<p>The <a href="#ownership.inference">inference</a> rules apply
-equally to <tt>__block</tt> variables, which is a shift in semantics
-from non-ARC, where <tt>__block</tt> variables did not implicitly
-retain during capture.</p>
-
-<p><tt>__block</tt> variables of retainable object owner type are
-moved off the stack by initializing the heap copy with the result of
-moving from the stack copy.</p>
-
-<p>With the exception of retains done as part of initializing
-a <tt>__strong</tt> parameter variable or reading a <tt>__weak</tt>
-variable, whenever these semantics call for retaining a value of
-block-pointer type, it has the effect of a <tt>Block_copy</tt>. The
-optimizer may remove such copies when it sees that the result is
-used only as an argument to a call.</p>
-
-</div> <!-- misc.blocks -->
-
-<div id="misc.exceptions">
-<h1>Exceptions</h1>
-
-<p>By default in Objective C, ARC is not exception-safe for normal
-releases:</p>
-<ul>
-<li>It does not end the lifetime of <tt>__strong</tt> variables when
-their scopes are abnormally terminated by an exception.</li>
-<li>It does not perform releases which would occur at the end of
-a full-expression if that full-expression throws an exception.</li>
-</ul>
-
-<p>A program may be compiled with the option
-<tt>-fobjc-arc-exceptions</tt> in order to enable these, or with the
-option <tt>-fno-objc-arc-exceptions</tt> to explicitly disable them,
-with the last such argument <q>winning</q>.</p>
-
-<div class="rationale"><p>Rationale: the standard Cocoa convention is
-that exceptions signal programmer error and are not intended to be
-recovered from. Making code exceptions-safe by default would impose
-severe runtime and code size penalties on code that typically does not
-actually care about exceptions safety. Therefore, ARC-generated code
-leaks by default on exceptions, which is just fine if the process is
-going to be immediately terminated anyway. Programs which do care
-about recovering from exceptions should enable the option.</p></div>
-
-<p>In Objective-C++, <tt>-fobjc-arc-exceptions</tt> is enabled by
-default.</p>
-
-<div class="rationale"><p>Rationale: C++ already introduces pervasive
-exceptions-cleanup code of the sort that ARC introduces. C++
-programmers who have not already disabled exceptions are much more
-likely to actual require exception-safety.</p></div>
-
-<p>ARC does end the lifetimes of <tt>__weak</tt> objects when an
-exception terminates their scope unless exceptions are disabled in the
-compiler.</p>
-
-<div class="rationale"><p>Rationale: the consequence of a
-local <tt>__weak</tt> object not being destroyed is very likely to be
-corruption of the Objective-C runtime, so we want to be safer here.
-Of course, potentially massive leaks are about as likely to take down
-the process as this corruption is if the program does try to recover
-from exceptions.</p></div>
-
-</div> <!-- misc.exceptions -->
-
-<div id="misc.interior">
-<h1>Interior pointers</h1>
-
-<p>An Objective-C method returning a non-retainable pointer may be
-annotated with the <tt>objc_returns_inner_pointer</tt> attribute to
-indicate that it returns a handle to the internal data of an object,
-and that this reference will be invalidated if the object is
-destroyed. When such a message is sent to an object, the object's
-lifetime will be extended until at least the earliest of:</p>
-
-<ul>
-<li>the last use of the returned pointer, or any pointer derived from
-it, in the calling function or</li>
-<li>the autorelease pool is restored to a previous state.</li>
-</ul>
-
-<div class="rationale"><p>Rationale: not all memory and resources are
-managed with reference counts; it is common for objects to manage
-private resources in their own, private way. Typically these
-resources are completely encapsulated within the object, but some
-classes offer their users direct access for efficiency. If ARC is not
-aware of methods that return such <q>interior</q> pointers, its
-optimizations can cause the owning object to be reclaimed too soon.
-This attribute informs ARC that it must tread lightly.</p>
-
-<p>The extension rules are somewhat intentionally vague. The
-autorelease pool limit is there to permit a simple implementation to
-simply retain and autorelease the receiver. The other limit permits
-some amount of optimization. The phrase <q>derived from</q> is
-intended to encompass the results both of pointer transformations,
-such as casts and arithmetic, and of loading from such derived
-pointers; furthermore, it applies whether or not such derivations are
-applied directly in the calling code or by other utility code (for
-example, the C library routine <tt>strchr</tt>). However, the
-implementation never need account for uses after a return from the
-code which calls the method returning an interior pointer.</p></div>
-
-<p>As an exception, no extension is required if the receiver is loaded
-directly from a <tt>__strong</tt> object
-with <a href="#optimization.precise">precise lifetime semantics</a>.</p>
-
-<div class="rationale"><p>Rationale: implicit autoreleases carry the
-risk of significantly inflating memory use, so it's important to
-provide users a way of avoiding these autoreleases. Tying this to
-precise lifetime semantics is ideal, as for local variables this
-requires a very explicit annotation, which allows ARC to trust the
-user with good cheer.</p></div>
-
-</div> <!-- misc.interior -->
-
-<div id="misc.c-retainable">
-<h1>C retainable pointer types</h1>
-
-<p>A type is a <span class="term">C retainable pointer type</span>
-if it is a pointer to (possibly qualified) <tt>void</tt> or a
-pointer to a (possibly qualifier) <tt>struct</tt> or <tt>class</tt>
-type.</p>
-
-<div class="rationale"><p>Rationale: ARC does not manage pointers of
-CoreFoundation type (or any of the related families of retainable C
-pointers which interoperate with Objective-C for retain/release
-operation). In fact, ARC does not even know how to distinguish these
-types from arbitrary C pointer types. The intent of this concept is
-to filter out some obviously non-object types while leaving a hook for
-later tightening if a means of exhaustively marking CF types is made
-available.</p></div>
-
-<div id="misc.c-retainable.audit">
-<h1>Auditing of C retainable pointer interfaces</h1>
-
-<p><span class="revision"><span class="whenRevised">[beginning Apple 4.0, LLVM 3.1]</span></span></p>
-
-<p>A C function may be marked with the <tt>cf_audited_transfer</tt>
-attribute to express that, except as otherwise marked with attributes,
-it obeys the parameter (consuming vs. non-consuming) and return
-(retained vs. non-retained) conventions for a C function of its name,
-namely:</p>
-
-<ul>
-<li>A parameter of C retainable pointer type is assumed to not be
-consumed unless it is marked with the <tt>cf_consumed</tt> attribute, and</li>
-<li>A result of C retainable pointer type is assumed to not be
-returned retained unless the function is either
-marked <tt>cf_returns_retained</tt> or it follows
-the create/copy naming convention and is not
-marked <tt>cf_returns_not_retained</tt>.</li>
-</ul>
-
-<p>A function obeys the <span class="term">create/copy</span> naming
-convention if its name contains as a substring:</p>
-<ul>
-<li>either <q>Create</q> or <q>Copy</q> not followed by a lowercase letter, or</li>
-<li>either <q>create</q> or <q>copy</q> not followed by a lowercase
-letter and not preceded by any letter, whether uppercase or lowercase.</li>
-</ul>
-
-<p>A second attribute, <tt>cf_unknown_transfer</tt>, signifies that a
-function's transfer semantics cannot be accurately captured using any
-of these annotations. A program is ill-formed if it annotates the
-same function with both <tt>cf_audited_transfer</tt>
-and <tt>cf_unknown_transfer</tt>.</p>
-
-<p>A pragma is provided to facilitate the mass annotation of interfaces:</p>
-
-<pre>#pragma clang arc_cf_code_audited begin
-...
-#pragma clang arc_cf_code_audited end</pre>
-
-<p>All C functions declared within the extent of this pragma are
-treated as if annotated with the <tt>cf_audited_transfer</tt>
-attribute unless they otherwise have the <tt>cf_unknown_transfer</tt>
-attribute. The pragma is accepted in all language modes. A program
-is ill-formed if it attempts to change files, whether by including a
-file or ending the current file, within the extent of this pragma.</p>
-
-<p>It is possible to test for all the features in this section with
-<tt>__has_feature(arc_cf_code_audited)</tt>.</p>
-
-<div class="rationale"><p>Rationale: A significant inconvenience in
-ARC programming is the necessity of interacting with APIs based around
-C retainable pointers. These features are designed to make it
-relatively easy for API authors to quickly review and annotate their
-interfaces, in turn improving the fidelity of tools such as the static
-analyzer and ARC. The single-file restriction on the pragma is
-designed to eliminate the risk of accidentally annotating some other
-header's interfaces.</p></div>
-
-</div> <!-- misc.c-retainable.audit -->
-
-</div> <!-- misc.c-retainable -->
-
-</div> <!-- misc -->
-
-<div id="runtime">
-<h1>Runtime support</h1>
-
-<p>This section describes the interaction between the ARC runtime and
-the code generated by the ARC compiler. This is not part of the ARC
-language specification; instead, it is effectively a language-specific
-ABI supplement, akin to the <q>Itanium</q> generic ABI for C++.</p>
-
-<p>Ownership qualification does not alter the storage requirements for
-objects, except that it is undefined behavior if a <tt>__weak</tt>
-object is inadequately aligned for an object of type <tt>id</tt>. The
-other qualifiers may be used on explicitly under-aligned memory.</p>
-
-<p>The runtime tracks <tt>__weak</tt> objects which holds non-null
-values. It is undefined behavior to direct modify a <tt>__weak</tt>
-object which is being tracked by the runtime except through an
-<a href="#runtime.objc_storeWeak"><tt>objc_storeWeak</tt></a>,
-<a href="#runtime.objc_destroyWeak"><tt>objc_destroyWeak</tt></a>,
-or <a href="#runtime.objc_moveWeak"><tt>objc_moveWeak</tt></a>
-call.</p>
-
-<p>The runtime must provide a number of new entrypoints which the
-compiler may emit, which are described in the remainder of this
-section.</p>
-
-<div class="rationale"><p>Rationale: Several of these functions are
-semantically equivalent to a message send; we emit calls to C
-functions instead because:</p>
-<ul>
-<li>the machine code to do so is significantly smaller,</li>
-<li>it is much easier to recognize the C functions in the ARC optimizer, and</li>
-<li>a sufficient sophisticated runtime may be able to avoid the
-message send in common cases.</li>
-</ul>
-
-<p>Several other of these functions are <q>fused</q> operations which
-can be described entirely in terms of other operations. We use the
-fused operations primarily as a code-size optimization, although in
-some cases there is also a real potential for avoiding redundant
-operations in the runtime.</p>
-
-</div>
-
-<div id="runtime.objc_autorelease">
-<h1><tt>id objc_autorelease(id value);</tt></h1>
-<p><i>Precondition:</i> <tt>value</tt> is null or a pointer to a
-valid object.</p>
-<p>If <tt>value</tt> is null, this call has no effect. Otherwise, it
-adds the object to the innermost autorelease pool exactly as if the
-object had been sent the <tt>autorelease</tt> message.</p>
-<p>Always returns <tt>value</tt>.</p>
-</div> <!-- runtime.objc_autorelease -->
-
-<div id="runtime.objc_autoreleasePoolPop">
-<h1><tt>void objc_autoreleasePoolPop(void *pool);</tt></h1>
-<p><i>Precondition:</i> <tt>pool</tt> is the result of a previous call to
-<a href="runtime.objc_autoreleasePoolPush"><tt>objc_autoreleasePoolPush</tt></a>
-on the current thread, where neither <tt>pool</tt> nor any enclosing
-pool have previously been popped.</p>
-<p>Releases all the objects added to the given autorelease pool and
-any autorelease pools it encloses, then sets the current autorelease
-pool to the pool directly enclosing <tt>pool</tt>.</p>
-</div> <!-- runtime.objc_autoreleasePoolPop -->
-
-<div id="runtime.objc_autoreleasePoolPush">
-<h1><tt>void *objc_autoreleasePoolPush(void);</tt></h1>
-<p>Creates a new autorelease pool that is enclosed by the current
-pool, makes that the current pool, and returns an opaque <q>handle</q>
-to it.</p>
-
-<div class="rationale"><p>Rationale: while the interface is described
-as an explicit hierarchy of pools, the rules allow the implementation
-to just keep a stack of objects, using the stack depth as the opaque
-pool handle.</p></div>
-
-</div> <!-- runtime.objc_autoreleasePoolPush -->
-
-<div id="runtime.objc_autoreleaseReturnValue">
-<h1><tt>id objc_autoreleaseReturnValue(id value);</tt></h1>
-<p><i>Precondition:</i> <tt>value</tt> is null or a pointer to a
-valid object.</p>
-<p>If <tt>value</tt> is null, this call has no effect. Otherwise, it
-makes a best effort to hand off ownership of a retain count on the
-object to a call
-to <a href="runtime.objc_retainAutoreleasedReturnValue"><tt>objc_retainAutoreleasedReturnValue</tt></a>
-for the same object in an enclosing call frame. If this is not
-possible, the object is autoreleased as above.</p>
-<p>Always returns <tt>value</tt>.</p>
-</div> <!-- runtime.objc_autoreleaseReturnValue -->
-
-<div id="runtime.objc_copyWeak">
-<h1><tt>void objc_copyWeak(id *dest, id *src);</tt></h1>
-<p><i>Precondition:</i> <tt>src</tt> is a valid pointer which either
-contains a null pointer or has been registered as a <tt>__weak</tt>
-object. <tt>dest</tt> is a valid pointer which has not been
-registered as a <tt>__weak</tt> object.</p>
-<p><tt>dest</tt> is initialized to be equivalent to <tt>src</tt>,
-potentially registering it with the runtime. Equivalent to the
-following code:</p>
-<pre>void objc_copyWeak(id *dest, id *src) {
- objc_release(objc_initWeak(dest, objc_loadWeakRetained(src)));
-}</pre>
-<p>Must be atomic with respect to calls to <tt>objc_storeWeak</tt>
-on <tt>src</tt>.</p>
-</div> <!-- runtime.objc_copyWeak -->
-
-<div id="runtime.objc_destroyWeak">
-<h1><tt>void objc_destroyWeak(id *object);</tt></h1>
-<p><i>Precondition:</i> <tt>object</tt> is a valid pointer which
-either contains a null pointer or has been registered as
-a <tt>__weak</tt> object.</p>
-<p><tt>object</tt> is unregistered as a weak object, if it ever was.
-The current value of <tt>object</tt> is left unspecified; otherwise,
-equivalent to the following code:</p>
-<pre>void objc_destroyWeak(id *object) {
- objc_storeWeak(object, nil);
-}</pre>
-<p>Does not need to be atomic with respect to calls
-to <tt>objc_storeWeak</tt> on <tt>object</tt>.</p>
-</div> <!-- runtime.objc_destroyWeak -->
-
-<div id="runtime.objc_initWeak">
-<h1><tt>id objc_initWeak(id *object, id value);</tt></h1>
-<p><i>Precondition:</i> <tt>object</tt> is a valid pointer which has
-not been registered as a <tt>__weak</tt> object. <tt>value</tt> is
-null or a pointer to a valid object.</p>
-<p>If <tt>value</tt> is a null pointer or the object to which it
-points has begun deallocation, <tt>object</tt> is zero-initialized.
-Otherwise, <tt>object</tt> is registered as a <tt>__weak</tt> object
-pointing to <tt>value</tt>. Equivalent to the following code:</p>
-<pre>id objc_initWeak(id *object, id value) {
- *object = nil;
- return objc_storeWeak(object, value);
-}</pre>
-<p>Returns the value of <tt>object</tt> after the call.</p>
-<p>Does not need to be atomic with respect to calls
-to <tt>objc_storeWeak</tt> on <tt>object</tt>.</p>
-</div> <!-- runtime.objc_initWeak -->
-
-<div id="runtime.objc_loadWeak">
-<h1><tt>id objc_loadWeak(id *object);</tt></h1>
-<p><i>Precondition:</i> <tt>object</tt> is a valid pointer which
-either contains a null pointer or has been registered as
-a <tt>__weak</tt> object.</p>
-<p>If <tt>object</tt> is registered as a <tt>__weak</tt> object, and
-the last value stored into <tt>object</tt> has not yet been
-deallocated or begun deallocation, retains and autoreleases that value
-and returns it. Otherwise returns null. Equivalent to the following
-code:</p>
-<pre>id objc_loadWeak(id *object) {
- return objc_autorelease(objc_loadWeakRetained(object));
-}</pre>
-<p>Must be atomic with respect to calls to <tt>objc_storeWeak</tt>
-on <tt>object</tt>.</p>
-<div class="rationale">Rationale: loading weak references would be
-inherently prone to race conditions without the retain.</div>
-</div> <!-- runtime.objc_loadWeak -->
-
-<div id="runtime.objc_loadWeakRetained">
-<h1><tt>id objc_loadWeakRetained(id *object);</tt></h1>
-<p><i>Precondition:</i> <tt>object</tt> is a valid pointer which
-either contains a null pointer or has been registered as
-a <tt>__weak</tt> object.</p>
-<p>If <tt>object</tt> is registered as a <tt>__weak</tt> object, and
-the last value stored into <tt>object</tt> has not yet been
-deallocated or begun deallocation, retains that value and returns it.
-Otherwise returns null.</p>
-<p>Must be atomic with respect to calls to <tt>objc_storeWeak</tt>
-on <tt>object</tt>.</p>
-</div> <!-- runtime.objc_loadWeakRetained -->
-
-<div id="runtime.objc_moveWeak">
-<h1><tt>void objc_moveWeak(id *dest, id *src);</tt></h1>
-<p><i>Precondition:</i> <tt>src</tt> is a valid pointer which either
-contains a null pointer or has been registered as a <tt>__weak</tt>
-object. <tt>dest</tt> is a valid pointer which has not been
-registered as a <tt>__weak</tt> object.</p>
-<p><tt>dest</tt> is initialized to be equivalent to <tt>src</tt>,
-potentially registering it with the runtime. <tt>src</tt> may then be
-left in its original state, in which case this call is equivalent
-to <a href="#runtime.objc_copyWeak"><tt>objc_copyWeak</tt></a>, or it
-may be left as null.</p>
-<p>Must be atomic with respect to calls to <tt>objc_storeWeak</tt>
-on <tt>src</tt>.</p>
-</div> <!-- runtime.objc_moveWeak -->
-
-<div id="runtime.objc_release">
-<h1><tt>void objc_release(id value);</tt></h1>
-<p><i>Precondition:</i> <tt>value</tt> is null or a pointer to a
-valid object.</p>
-<p>If <tt>value</tt> is null, this call has no effect. Otherwise, it
-performs a release operation exactly as if the object had been sent
-the <tt>release</tt> message.</p>
-</div> <!-- runtime.objc_release -->
-
-<div id="runtime.objc_retain">
-<h1><tt>id objc_retain(id value);</tt></h1>
-<p><i>Precondition:</i> <tt>value</tt> is null or a pointer to a
-valid object.</p>
-<p>If <tt>value</tt> is null, this call has no effect. Otherwise, it
-performs a retain operation exactly as if the object had been sent
-the <tt>retain</tt> message.</p>
-<p>Always returns <tt>value</tt>.</p>
-</div> <!-- runtime.objc_retain -->
-
-<div id="runtime.objc_retainAutorelease">
-<h1><tt>id objc_retainAutorelease(id value);</tt></h1>
-<p><i>Precondition:</i> <tt>value</tt> is null or a pointer to a
-valid object.</p>
-<p>If <tt>value</tt> is null, this call has no effect. Otherwise, it
-performs a retain operation followed by an autorelease operation.
-Equivalent to the following code:</p>
-<pre>id objc_retainAutorelease(id value) {
- return objc_autorelease(objc_retain(value));
-}</pre>
-<p>Always returns <tt>value</tt>.</p>
-</div> <!-- runtime.objc_retainAutorelease -->
-
-<div id="runtime.objc_retainAutoreleaseReturnValue">
-<h1><tt>id objc_retainAutoreleaseReturnValue(id value);</tt></h1>
-<p><i>Precondition:</i> <tt>value</tt> is null or a pointer to a
-valid object.</p>
-<p>If <tt>value</tt> is null, this call has no effect. Otherwise, it
-performs a retain operation followed by the operation described in
-<a href="#runtime.objc_autoreleaseReturnValue"><tt>objc_autoreleaseReturnValue</tt></a>.
-Equivalent to the following code:</p>
-<pre>id objc_retainAutoreleaseReturnValue(id value) {
- return objc_autoreleaseReturnValue(objc_retain(value));
-}</pre>
-<p>Always returns <tt>value</tt>.</p>
-</div> <!-- runtime.objc_retainAutoreleaseReturnValue -->
-
-<div id="runtime.objc_retainAutoreleasedReturnValue">
-<h1><tt>id objc_retainAutoreleasedReturnValue(id value);</tt></h1>
-<p><i>Precondition:</i> <tt>value</tt> is null or a pointer to a
-valid object.</p>
-<p>If <tt>value</tt> is null, this call has no effect. Otherwise, it
-attempts to accept a hand off of a retain count from a call to
-<a href="#runtime.objc_autoreleaseReturnValue"><tt>objc_autoreleaseReturnValue</tt></a>
-on <tt>value</tt> in a recently-called function or something it
-calls. If that fails, it performs a retain operation exactly
-like <a href="#runtime.objc_retain"><tt>objc_retain</tt></a>.</p>
-<p>Always returns <tt>value</tt>.</p>
-</div> <!-- runtime.objc_retainAutoreleasedReturnValue -->
-
-<div id="runtime.objc_retainBlock">
-<h1><tt>id objc_retainBlock(id value);</tt></h1>
-<p><i>Precondition:</i> <tt>value</tt> is null or a pointer to a
-valid block object.</p>
-<p>If <tt>value</tt> is null, this call has no effect. Otherwise, if
-the block pointed to by <tt>value</tt> is still on the stack, it is
-copied to the heap and the address of the copy is returned. Otherwise
-a retain operation is performed on the block exactly as if it had been
-sent the <tt>retain</tt> message.</p>
-</div> <!-- runtime.objc_retainBlock -->
-
-<div id="runtime.objc_storeStrong">
-<h1><tt>id objc_storeStrong(id *object, id value);</tt></h1>
-<p><i>Precondition:</i> <tt>object</tt> is a valid pointer to
-a <tt>__strong</tt> object which is adequately aligned for a
-pointer. <tt>value</tt> is null or a pointer to a valid object.</p>
-<p>Performs the complete sequence for assigning to a <tt>__strong</tt>
-object of non-block type. Equivalent to the following code:</p>
-<pre>id objc_storeStrong(id *object, id value) {
- value = [value retain];
- id oldValue = *object;
- *object = value;
- [oldValue release];
- return value;
-}</pre>
-<p>Always returns <tt>value</tt>.</p>
-</div> <!-- runtime.objc_storeStrong -->
-
-<div id="runtime.objc_storeWeak">
-<h1><tt>id objc_storeWeak(id *object, id value);</tt></h1>
-<p><i>Precondition:</i> <tt>object</tt> is a valid pointer which
-either contains a null pointer or has been registered as
-a <tt>__weak</tt> object. <tt>value</tt> is null or a pointer to a
-valid object.</p>
-<p>If <tt>value</tt> is a null pointer or the object to which it
-points has begun deallocation, <tt>object</tt> is assigned null
-and unregistered as a <tt>__weak</tt> object. Otherwise,
-<tt>object</tt> is registered as a <tt>__weak</tt> object or has its
-registration updated to point to <tt>value</tt>.</p>
-<p>Returns the value of <tt>object</tt> after the call.</p>
-</div> <!-- runtime.objc_storeWeak -->
-
-</div> <!-- runtime -->
-</div> <!-- root -->
-</body>
-</html>
diff --git a/docs/AutomaticReferenceCounting.rst b/docs/AutomaticReferenceCounting.rst
new file mode 100644
index 0000000..1457b60
--- /dev/null
+++ b/docs/AutomaticReferenceCounting.rst
@@ -0,0 +1,2283 @@
+.. FIXME: move to the stylesheet or Sphinx plugin
+
+.. raw:: html
+
+ <style>
+ .arc-term { font-style: italic; font-weight: bold; }
+ .revision { font-style: italic; }
+ .when-revised { font-weight: bold; font-style: normal; }
+
+ /*
+ * Automatic numbering is described in this article:
+ * http://dev.opera.com/articles/view/automatic-numbering-with-css-counters/
+ */
+ /*
+ * Automatic numbering for the TOC.
+ * This is wrong from the semantics point of view, since it is an ordered
+ * list, but uses "ul" tag.
+ */
+ div#contents.contents.local ul {
+ counter-reset: toc-section;
+ list-style-type: none;
+ }
+ div#contents.contents.local ul li {
+ counter-increment: toc-section;
+ background: none; // Remove bullets
+ }
+ div#contents.contents.local ul li a.reference:before {
+ content: counters(toc-section, ".") " ";
+ }
+
+ /* Automatic numbering for the body. */
+ body {
+ counter-reset: section subsection subsubsection;
+ }
+ .section h2 {
+ counter-reset: subsection subsubsection;
+ counter-increment: section;
+ }
+ .section h2 a.toc-backref:before {
+ content: counter(section) " ";
+ }
+ .section h3 {
+ counter-reset: subsubsection;
+ counter-increment: subsection;
+ }
+ .section h3 a.toc-backref:before {
+ content: counter(section) "." counter(subsection) " ";
+ }
+ .section h4 {
+ counter-increment: subsubsection;
+ }
+ .section h4 a.toc-backref:before {
+ content: counter(section) "." counter(subsection) "." counter(subsubsection) " ";
+ }
+ </style>
+
+.. role:: arc-term
+.. role:: revision
+.. role:: when-revised
+
+==============================================
+Objective-C Automatic Reference Counting (ARC)
+==============================================
+
+.. contents::
+ :local:
+
+.. _arc.meta:
+
+About this document
+===================
+
+.. _arc.meta.purpose:
+
+Purpose
+-------
+
+The first and primary purpose of this document is to serve as a complete
+technical specification of Automatic Reference Counting. Given a core
+Objective-C compiler and runtime, it should be possible to write a compiler and
+runtime which implements these new semantics.
+
+The secondary purpose is to act as a rationale for why ARC was designed in this
+way. This should remain tightly focused on the technical design and should not
+stray into marketing speculation.
+
+.. _arc.meta.background:
+
+Background
+----------
+
+This document assumes a basic familiarity with C.
+
+:arc-term:`Blocks` are a C language extension for creating anonymous functions.
+Users interact with and transfer block objects using :arc-term:`block
+pointers`, which are represented like a normal pointer. A block may capture
+values from local variables; when this occurs, memory must be dynamically
+allocated. The initial allocation is done on the stack, but the runtime
+provides a ``Block_copy`` function which, given a block pointer, either copies
+the underlying block object to the heap, setting its reference count to 1 and
+returning the new block pointer, or (if the block object is already on the
+heap) increases its reference count by 1. The paired function is
+``Block_release``, which decreases the reference count by 1 and destroys the
+object if the count reaches zero and is on the heap.
+
+Objective-C is a set of language extensions, significant enough to be
+considered a different language. It is a strict superset of C. The extensions
+can also be imposed on C++, producing a language called Objective-C++. The
+primary feature is a single-inheritance object system; we briefly describe the
+modern dialect.
+
+Objective-C defines a new type kind, collectively called the :arc-term:`object
+pointer types`. This kind has two notable builtin members, ``id`` and
+``Class``; ``id`` is the final supertype of all object pointers. The validity
+of conversions between object pointer types is not checked at runtime. Users
+may define :arc-term:`classes`; each class is a type, and the pointer to that
+type is an object pointer type. A class may have a superclass; its pointer
+type is a subtype of its superclass's pointer type. A class has a set of
+:arc-term:`ivars`, fields which appear on all instances of that class. For
+every class *T* there's an associated metaclass; it has no fields, its
+superclass is the metaclass of *T*'s superclass, and its metaclass is a global
+class. Every class has a global object whose class is the class's metaclass;
+metaclasses have no associated type, so pointers to this object have type
+``Class``.
+
+A class declaration (``@interface``) declares a set of :arc-term:`methods`. A
+method has a return type, a list of argument types, and a :arc-term:`selector`:
+a name like ``foo:bar:baz:``, where the number of colons corresponds to the
+number of formal arguments. A method may be an instance method, in which case
+it can be invoked on objects of the class, or a class method, in which case it
+can be invoked on objects of the metaclass. A method may be invoked by
+providing an object (called the :arc-term:`receiver`) and a list of formal
+arguments interspersed with the selector, like so:
+
+.. code-block:: objc
+
+ [receiver foo: fooArg bar: barArg baz: bazArg]
+
+This looks in the dynamic class of the receiver for a method with this name,
+then in that class's superclass, etc., until it finds something it can execute.
+The receiver "expression" may also be the name of a class, in which case the
+actual receiver is the class object for that class, or (within method
+definitions) it may be ``super``, in which case the lookup algorithm starts
+with the static superclass instead of the dynamic class. The actual methods
+dynamically found in a class are not those declared in the ``@interface``, but
+those defined in a separate ``@implementation`` declaration; however, when
+compiling a call, typechecking is done based on the methods declared in the
+``@interface``.
+
+Method declarations may also be grouped into :arc-term:`protocols`, which are not
+inherently associated with any class, but which classes may claim to follow.
+Object pointer types may be qualified with additional protocols that the object
+is known to support.
+
+:arc-term:`Class extensions` are collections of ivars and methods, designed to
+allow a class's ``@interface`` to be split across multiple files; however,
+there is still a primary implementation file which must see the
+``@interface``\ s of all class extensions. :arc-term:`Categories` allow
+methods (but not ivars) to be declared *post hoc* on an arbitrary class; the
+methods in the category's ``@implementation`` will be dynamically added to that
+class's method tables which the category is loaded at runtime, replacing those
+methods in case of a collision.
+
+In the standard environment, objects are allocated on the heap, and their
+lifetime is manually managed using a reference count. This is done using two
+instance methods which all classes are expected to implement: ``retain``
+increases the object's reference count by 1, whereas ``release`` decreases it
+by 1 and calls the instance method ``dealloc`` if the count reaches 0. To
+simplify certain operations, there is also an :arc-term:`autorelease pool`, a
+thread-local list of objects to call ``release`` on later; an object can be
+added to this pool by calling ``autorelease`` on it.
+
+Block pointers may be converted to type ``id``; block objects are laid out in a
+way that makes them compatible with Objective-C objects. There is a builtin
+class that all block objects are considered to be objects of; this class
+implements ``retain`` by adjusting the reference count, not by calling
+``Block_copy``.
+
+.. _arc.meta.evolution:
+
+Evolution
+---------
+
+ARC is under continual evolution, and this document must be updated as the
+language progresses.
+
+If a change increases the expressiveness of the language, for example by
+lifting a restriction or by adding new syntax, the change will be annotated
+with a revision marker, like so:
+
+ ARC applies to Objective-C pointer types, block pointer types, and
+ :when-revised:`[beginning Apple 8.0, LLVM 3.8]` :revision:`BPTRs declared
+ within` ``extern "BCPL"`` blocks.
+
+For now, it is sensible to version this document by the releases of its sole
+implementation (and its host project), clang. "LLVM X.Y" refers to an
+open-source release of clang from the LLVM project. "Apple X.Y" refers to an
+Apple-provided release of the Apple LLVM Compiler. Other organizations that
+prepare their own, separately-versioned clang releases and wish to maintain
+similar information in this document should send requests to cfe-dev.
+
+If a change decreases the expressiveness of the language, for example by
+imposing a new restriction, this should be taken as an oversight in the
+original specification and something to be avoided in all versions. Such
+changes are generally to be avoided.
+
+.. _arc.general:
+
+General
+=======
+
+Automatic Reference Counting implements automatic memory management for
+Objective-C objects and blocks, freeing the programmer from the need to
+explicitly insert retains and releases. It does not provide a cycle collector;
+users must explicitly manage the lifetime of their objects, breaking cycles
+manually or with weak or unsafe references.
+
+ARC may be explicitly enabled with the compiler flag ``-fobjc-arc``. It may
+also be explicitly disabled with the compiler flag ``-fno-objc-arc``. The last
+of these two flags appearing on the compile line "wins".
+
+If ARC is enabled, ``__has_feature(objc_arc)`` will expand to 1 in the
+preprocessor. For more information about ``__has_feature``, see the
+:ref:`language extensions <langext-__has_feature-__has_extension>` document.
+
+.. _arc.objects:
+
+Retainable object pointers
+==========================
+
+This section describes retainable object pointers, their basic operations, and
+the restrictions imposed on their use under ARC. Note in particular that it
+covers the rules for pointer *values* (patterns of bits indicating the location
+of a pointed-to object), not pointer *objects* (locations in memory which store
+pointer values). The rules for objects are covered in the next section.
+
+A :arc-term:`retainable object pointer` (or "retainable pointer") is a value of
+a :arc-term:`retainable object pointer type` ("retainable type"). There are
+three kinds of retainable object pointer types:
+
+* block pointers (formed by applying the caret (``^``) declarator sigil to a
+ function type)
+* Objective-C object pointers (``id``, ``Class``, ``NSFoo*``, etc.)
+* typedefs marked with ``__attribute__((NSObject))``
+
+Other pointer types, such as ``int*`` and ``CFStringRef``, are not subject to
+ARC's semantics and restrictions.
+
+.. admonition:: Rationale
+
+ We are not at liberty to require all code to be recompiled with ARC;
+ therefore, ARC must interoperate with Objective-C code which manages retains
+ and releases manually. In general, there are three requirements in order for
+ a compiler-supported reference-count system to provide reliable
+ interoperation:
+
+ * The type system must reliably identify which objects are to be managed. An
+ ``int*`` might be a pointer to a ``malloc``'ed array, or it might be an
+ interior pointer to such an array, or it might point to some field or local
+ variable. In contrast, values of the retainable object pointer types are
+ never interior.
+
+ * The type system must reliably indicate how to manage objects of a type.
+ This usually means that the type must imply a procedure for incrementing
+ and decrementing retain counts. Supporting single-ownership objects
+ requires a lot more explicit mediation in the language.
+
+ * There must be reliable conventions for whether and when "ownership" is
+ passed between caller and callee, for both arguments and return values.
+ Objective-C methods follow such a convention very reliably, at least for
+ system libraries on Mac OS X, and functions always pass objects at +0. The
+ C-based APIs for Core Foundation objects, on the other hand, have much more
+ varied transfer semantics.
+
+The use of ``__attribute__((NSObject))`` typedefs is not recommended. If it's
+absolutely necessary to use this attribute, be very explicit about using the
+typedef, and do not assume that it will be preserved by language features like
+``__typeof`` and C++ template argument substitution.
+
+.. admonition:: Rationale
+
+ Any compiler operation which incidentally strips type "sugar" from a type
+ will yield a type without the attribute, which may result in unexpected
+ behavior.
+
+.. _arc.objects.retains:
+
+Retain count semantics
+----------------------
+
+A retainable object pointer is either a :arc-term:`null pointer` or a pointer
+to a valid object. Furthermore, if it has block pointer type and is not
+``null`` then it must actually be a pointer to a block object, and if it has
+``Class`` type (possibly protocol-qualified) then it must actually be a pointer
+to a class object. Otherwise ARC does not enforce the Objective-C type system
+as long as the implementing methods follow the signature of the static type.
+It is undefined behavior if ARC is exposed to an invalid pointer.
+
+For ARC's purposes, a valid object is one with "well-behaved" retaining
+operations. Specifically, the object must be laid out such that the
+Objective-C message send machinery can successfully send it the following
+messages:
+
+* ``retain``, taking no arguments and returning a pointer to the object.
+* ``release``, taking no arguments and returning ``void``.
+* ``autorelease``, taking no arguments and returning a pointer to the object.
+
+The behavior of these methods is constrained in the following ways. The term
+:arc-term:`high-level semantics` is an intentionally vague term; the intent is
+that programmers must implement these methods in a way such that the compiler,
+modifying code in ways it deems safe according to these constraints, will not
+violate their requirements. For example, if the user puts logging statements
+in ``retain``, they should not be surprised if those statements are executed
+more or less often depending on optimization settings. These constraints are
+not exhaustive of the optimization opportunities: values held in local
+variables are subject to additional restrictions, described later in this
+document.
+
+It is undefined behavior if a computation history featuring a send of
+``retain`` followed by a send of ``release`` to the same object, with no
+intervening ``release`` on that object, is not equivalent under the high-level
+semantics to a computation history in which these sends are removed. Note that
+this implies that these methods may not raise exceptions.
+
+It is undefined behavior if a computation history features any use whatsoever
+of an object following the completion of a send of ``release`` that is not
+preceded by a send of ``retain`` to the same object.
+
+The behavior of ``autorelease`` must be equivalent to sending ``release`` when
+one of the autorelease pools currently in scope is popped. It may not throw an
+exception.
+
+When the semantics call for performing one of these operations on a retainable
+object pointer, if that pointer is ``null`` then the effect is a no-op.
+
+All of the semantics described in this document are subject to additional
+:ref:`optimization rules <arc.optimization>` which permit the removal or
+optimization of operations based on local knowledge of data flow. The
+semantics describe the high-level behaviors that the compiler implements, not
+an exact sequence of operations that a program will be compiled into.
+
+.. _arc.objects.operands:
+
+Retainable object pointers as operands and arguments
+----------------------------------------------------
+
+In general, ARC does not perform retain or release operations when simply using
+a retainable object pointer as an operand within an expression. This includes:
+
+* loading a retainable pointer from an object with non-weak :ref:`ownership
+ <arc.ownership>`,
+* passing a retainable pointer as an argument to a function or method, and
+* receiving a retainable pointer as the result of a function or method call.
+
+.. admonition:: Rationale
+
+ While this might seem uncontroversial, it is actually unsafe when multiple
+ expressions are evaluated in "parallel", as with binary operators and calls,
+ because (for example) one expression might load from an object while another
+ writes to it. However, C and C++ already call this undefined behavior
+ because the evaluations are unsequenced, and ARC simply exploits that here to
+ avoid needing to retain arguments across a large number of calls.
+
+The remainder of this section describes exceptions to these rules, how those
+exceptions are detected, and what those exceptions imply semantically.
+
+.. _arc.objects.operands.consumed:
+
+Consumed parameters
+^^^^^^^^^^^^^^^^^^^
+
+A function or method parameter of retainable object pointer type may be marked
+as :arc-term:`consumed`, signifying that the callee expects to take ownership
+of a +1 retain count. This is done by adding the ``ns_consumed`` attribute to
+the parameter declaration, like so:
+
+.. code-block:: objc
+
+ void foo(__attribute((ns_consumed)) id x);
+ - (void) foo: (id) __attribute((ns_consumed)) x;
+
+This attribute is part of the type of the function or method, not the type of
+the parameter. It controls only how the argument is passed and received.
+
+When passing such an argument, ARC retains the argument prior to making the
+call.
+
+When receiving such an argument, ARC releases the argument at the end of the
+function, subject to the usual optimizations for local values.
+
+.. admonition:: Rationale
+
+ This formalizes direct transfers of ownership from a caller to a callee. The
+ most common scenario here is passing the ``self`` parameter to ``init``, but
+ it is useful to generalize. Typically, local optimization will remove any
+ extra retains and releases: on the caller side the retain will be merged with
+ a +1 source, and on the callee side the release will be rolled into the
+ initialization of the parameter.
+
+The implicit ``self`` parameter of a method may be marked as consumed by adding
+``__attribute__((ns_consumes_self))`` to the method declaration. Methods in
+the ``init`` :ref:`family <arc.method-families>` are treated as if they were
+implicitly marked with this attribute.
+
+It is undefined behavior if an Objective-C message send to a method with
+``ns_consumed`` parameters (other than self) is made with a null receiver. It
+is undefined behavior if the method to which an Objective-C message send
+statically resolves to has a different set of ``ns_consumed`` parameters than
+the method it dynamically resolves to. It is undefined behavior if a block or
+function call is made through a static type with a different set of
+``ns_consumed`` parameters than the implementation of the called block or
+function.
+
+.. admonition:: Rationale
+
+ Consumed parameters with null receiver are a guaranteed leak. Mismatches
+ with consumed parameters will cause over-retains or over-releases, depending
+ on the direction. The rule about function calls is really just an
+ application of the existing C/C++ rule about calling functions through an
+ incompatible function type, but it's useful to state it explicitly.
+
+.. _arc.object.operands.retained-return-values:
+
+Retained return values
+^^^^^^^^^^^^^^^^^^^^^^
+
+A function or method which returns a retainable object pointer type may be
+marked as returning a retained value, signifying that the caller expects to take
+ownership of a +1 retain count. This is done by adding the
+``ns_returns_retained`` attribute to the function or method declaration, like
+so:
+
+.. code-block:: objc
+
+ id foo(void) __attribute((ns_returns_retained));
+ - (id) foo __attribute((ns_returns_retained));
+
+This attribute is part of the type of the function or method.
+
+When returning from such a function or method, ARC retains the value at the
+point of evaluation of the return statement, before leaving all local scopes.
+
+When receiving a return result from such a function or method, ARC releases the
+value at the end of the full-expression it is contained within, subject to the
+usual optimizations for local values.
+
+.. admonition:: Rationale
+
+ This formalizes direct transfers of ownership from a callee to a caller. The
+ most common scenario this models is the retained return from ``init``,
+ ``alloc``, ``new``, and ``copy`` methods, but there are other cases in the
+ frameworks. After optimization there are typically no extra retains and
+ releases required.
+
+Methods in the ``alloc``, ``copy``, ``init``, ``mutableCopy``, and ``new``
+:ref:`families <arc.method-families>` are implicitly marked
+``__attribute__((ns_returns_retained))``. This may be suppressed by explicitly
+marking the method ``__attribute__((ns_returns_not_retained))``.
+
+It is undefined behavior if the method to which an Objective-C message send
+statically resolves has different retain semantics on its result from the
+method it dynamically resolves to. It is undefined behavior if a block or
+function call is made through a static type with different retain semantics on
+its result from the implementation of the called block or function.
+
+.. admonition:: Rationale
+
+ Mismatches with returned results will cause over-retains or over-releases,
+ depending on the direction. Again, the rule about function calls is really
+ just an application of the existing C/C++ rule about calling functions
+ through an incompatible function type.
+
+.. _arc.objects.operands.unretained-returns:
+
+Unretained return values
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+A method or function which returns a retainable object type but does not return
+a retained value must ensure that the object is still valid across the return
+boundary.
+
+When returning from such a function or method, ARC retains the value at the
+point of evaluation of the return statement, then leaves all local scopes, and
+then balances out the retain while ensuring that the value lives across the
+call boundary. In the worst case, this may involve an ``autorelease``, but
+callers must not assume that the value is actually in the autorelease pool.
+
+ARC performs no extra mandatory work on the caller side, although it may elect
+to do something to shorten the lifetime of the returned value.
+
+.. admonition:: Rationale
+
+ It is common in non-ARC code to not return an autoreleased value; therefore
+ the convention does not force either path. It is convenient to not be
+ required to do unnecessary retains and autoreleases; this permits
+ optimizations such as eliding retain/autoreleases when it can be shown that
+ the original pointer will still be valid at the point of return.
+
+A method or function may be marked with
+``__attribute__((ns_returns_autoreleased))`` to indicate that it returns a
+pointer which is guaranteed to be valid at least as long as the innermost
+autorelease pool. There are no additional semantics enforced in the definition
+of such a method; it merely enables optimizations in callers.
+
+.. _arc.objects.operands.casts:
+
+Bridged casts
+^^^^^^^^^^^^^
+
+A :arc-term:`bridged cast` is a C-style cast annotated with one of three
+keywords:
+
+* ``(__bridge T) op`` casts the operand to the destination type ``T``. If
+ ``T`` is a retainable object pointer type, then ``op`` must have a
+ non-retainable pointer type. If ``T`` is a non-retainable pointer type,
+ then ``op`` must have a retainable object pointer type. Otherwise the cast
+ is ill-formed. There is no transfer of ownership, and ARC inserts no retain
+ operations.
+* ``(__bridge_retained T) op`` casts the operand, which must have retainable
+ object pointer type, to the destination type, which must be a non-retainable
+ pointer type. ARC retains the value, subject to the usual optimizations on
+ local values, and the recipient is responsible for balancing that +1.
+* ``(__bridge_transfer T) op`` casts the operand, which must have
+ non-retainable pointer type, to the destination type, which must be a
+ retainable object pointer type. ARC will release the value at the end of
+ the enclosing full-expression, subject to the usual optimizations on local
+ values.
+
+These casts are required in order to transfer objects in and out of ARC
+control; see the rationale in the section on :ref:`conversion of retainable
+object pointers <arc.objects.restrictions.conversion>`.
+
+Using a ``__bridge_retained`` or ``__bridge_transfer`` cast purely to convince
+ARC to emit an unbalanced retain or release, respectively, is poor form.
+
+.. _arc.objects.restrictions:
+
+Restrictions
+------------
+
+.. _arc.objects.restrictions.conversion:
+
+Conversion of retainable object pointers
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In general, a program which attempts to implicitly or explicitly convert a
+value of retainable object pointer type to any non-retainable type, or
+vice-versa, is ill-formed. For example, an Objective-C object pointer shall
+not be converted to ``void*``. As an exception, cast to ``intptr_t`` is
+allowed because such casts are not transferring ownership. The :ref:`bridged
+casts <arc.objects.operands.casts>` may be used to perform these conversions
+where necessary.
+
+.. admonition:: Rationale
+
+ We cannot ensure the correct management of the lifetime of objects if they
+ may be freely passed around as unmanaged types. The bridged casts are
+ provided so that the programmer may explicitly describe whether the cast
+ transfers control into or out of ARC.
+
+However, the following exceptions apply.
+
+.. _arc.objects.restrictions.conversion.with.known.semantics:
+
+Conversion to retainable object pointer type of expressions with known semantics
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+:when-revised:`[beginning Apple 4.0, LLVM 3.1]`
+:revision:`These exceptions have been greatly expanded; they previously applied
+only to a much-reduced subset which is difficult to categorize but which
+included null pointers, message sends (under the given rules), and the various
+global constants.`
+
+An unbridged conversion to a retainable object pointer type from a type other
+than a retainable object pointer type is ill-formed, as discussed above, unless
+the operand of the cast has a syntactic form which is known retained, known
+unretained, or known retain-agnostic.
+
+An expression is :arc-term:`known retain-agnostic` if it is:
+
+* an Objective-C string literal,
+* a load from a ``const`` system global variable of :ref:`C retainable pointer
+ type <arc.misc.c-retainable>`, or
+* a null pointer constant.
+
+An expression is :arc-term:`known unretained` if it is an rvalue of :ref:`C
+retainable pointer type <arc.misc.c-retainable>` and it is:
+
+* a direct call to a function, and either that function has the
+ ``cf_returns_not_retained`` attribute or it is an :ref:`audited
+ <arc.misc.c-retainable.audit>` function that does not have the
+ ``cf_returns_retained`` attribute and does not follow the create/copy naming
+ convention,
+* a message send, and the declared method either has the
+ ``cf_returns_not_retained`` attribute or it has neither the
+ ``cf_returns_retained`` attribute nor a :ref:`selector family
+ <arc.method-families>` that implies a retained result.
+
+An expression is :arc-term:`known retained` if it is an rvalue of :ref:`C
+retainable pointer type <arc.misc.c-retainable>` and it is:
+
+* a message send, and the declared method either has the
+ ``cf_returns_retained`` attribute, or it does not have the
+ ``cf_returns_not_retained`` attribute but it does have a :ref:`selector
+ family <arc.method-families>` that implies a retained result.
+
+Furthermore:
+
+* a comma expression is classified according to its right-hand side,
+* a statement expression is classified according to its result expression, if
+ it has one,
+* an lvalue-to-rvalue conversion applied to an Objective-C property lvalue is
+ classified according to the underlying message send, and
+* a conditional operator is classified according to its second and third
+ operands, if they agree in classification, or else the other if one is known
+ retain-agnostic.
+
+If the cast operand is known retained, the conversion is treated as a
+``__bridge_transfer`` cast. If the cast operand is known unretained or known
+retain-agnostic, the conversion is treated as a ``__bridge`` cast.
+
+.. admonition:: Rationale
+
+ Bridging casts are annoying. Absent the ability to completely automate the
+ management of CF objects, however, we are left with relatively poor attempts
+ to reduce the need for a glut of explicit bridges. Hence these rules.
+
+ We've so far consciously refrained from implicitly turning retained CF
+ results from function calls into ``__bridge_transfer`` casts. The worry is
+ that some code patterns --- for example, creating a CF value, assigning it
+ to an ObjC-typed local, and then calling ``CFRelease`` when done --- are a
+ bit too likely to be accidentally accepted, leading to mysterious behavior.
+
+.. _arc.objects.restrictions.conversion-exception-contextual:
+
+Conversion from retainable object pointer type in certain contexts
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+:when-revised:`[beginning Apple 4.0, LLVM 3.1]`
+
+If an expression of retainable object pointer type is explicitly cast to a
+:ref:`C retainable pointer type <arc.misc.c-retainable>`, the program is
+ill-formed as discussed above unless the result is immediately used:
+
+* to initialize a parameter in an Objective-C message send where the parameter
+ is not marked with the ``cf_consumed`` attribute, or
+* to initialize a parameter in a direct call to an
+ :ref:`audited <arc.misc.c-retainable.audit>` function where the parameter is
+ not marked with the ``cf_consumed`` attribute.
+
+.. admonition:: Rationale
+
+ Consumed parameters are left out because ARC would naturally balance them
+ with a retain, which was judged too treacherous. This is in part because
+ several of the most common consuming functions are in the ``Release`` family,
+ and it would be quite unfortunate for explicit releases to be silently
+ balanced out in this way.
+
+.. _arc.ownership:
+
+Ownership qualification
+=======================
+
+This section describes the behavior of *objects* of retainable object pointer
+type; that is, locations in memory which store retainable object pointers.
+
+A type is a :arc-term:`retainable object owner type` if it is a retainable
+object pointer type or an array type whose element type is a retainable object
+owner type.
+
+An :arc-term:`ownership qualifier` is a type qualifier which applies only to
+retainable object owner types. An array type is ownership-qualified according
+to its element type, and adding an ownership qualifier to an array type so
+qualifies its element type.
+
+A program is ill-formed if it attempts to apply an ownership qualifier to a
+type which is already ownership-qualified, even if it is the same qualifier.
+There is a single exception to this rule: an ownership qualifier may be applied
+to a substituted template type parameter, which overrides the ownership
+qualifier provided by the template argument.
+
+When forming a function type, the result type is adjusted so that any
+top-level ownership qualifier is deleted.
+
+Except as described under the :ref:`inference rules <arc.ownership.inference>`,
+a program is ill-formed if it attempts to form a pointer or reference type to a
+retainable object owner type which lacks an ownership qualifier.
+
+.. admonition:: Rationale
+
+ These rules, together with the inference rules, ensure that all objects and
+ lvalues of retainable object pointer type have an ownership qualifier. The
+ ability to override an ownership qualifier during template substitution is
+ required to counteract the :ref:`inference of __strong for template type
+ arguments <arc.ownership.inference.template.arguments>`. Ownership qualifiers
+ on return types are dropped because they serve no purpose there except to
+ cause spurious problems with overloading and templates.
+
+There are four ownership qualifiers:
+
+* ``__autoreleasing``
+* ``__strong``
+* ``__unsafe_unretained``
+* ``__weak``
+
+A type is :arc-term:`nontrivially ownership-qualified` if it is qualified with
+``__autoreleasing``, ``__strong``, or ``__weak``.
+
+.. _arc.ownership.spelling:
+
+Spelling
+--------
+
+The names of the ownership qualifiers are reserved for the implementation. A
+program may not assume that they are or are not implemented with macros, or
+what those macros expand to.
+
+An ownership qualifier may be written anywhere that any other type qualifier
+may be written.
+
+If an ownership qualifier appears in the *declaration-specifiers*, the
+following rules apply:
+
+* if the type specifier is a retainable object owner type, the qualifier
+ initially applies to that type;
+
+* otherwise, if the outermost non-array declarator is a pointer
+ or block pointer declarator, the qualifier initially applies to
+ that type;
+
+* otherwise the program is ill-formed.
+
+* If the qualifier is so applied at a position in the declaration
+ where the next-innermost declarator is a function declarator, and
+ there is an block declarator within that function declarator, then
+ the qualifier applies instead to that block declarator and this rule
+ is considered afresh beginning from the new position.
+
+If an ownership qualifier appears on the declarator name, or on the declared
+object, it is applied to the innermost pointer or block-pointer type.
+
+If an ownership qualifier appears anywhere else in a declarator, it applies to
+the type there.
+
+.. admonition:: Rationale
+
+ Ownership qualifiers are like ``const`` and ``volatile`` in the sense
+ that they may sensibly apply at multiple distinct positions within a
+ declarator. However, unlike those qualifiers, there are many
+ situations where they are not meaningful, and so we make an effort
+ to "move" the qualifier to a place where it will be meaningful. The
+ general goal is to allow the programmer to write, say, ``__strong``
+ before the entire declaration and have it apply in the leftmost
+ sensible place.
+
+.. _arc.ownership.spelling.property:
+
+Property declarations
+^^^^^^^^^^^^^^^^^^^^^
+
+A property of retainable object pointer type may have ownership. If the
+property's type is ownership-qualified, then the property has that ownership.
+If the property has one of the following modifiers, then the property has the
+corresponding ownership. A property is ill-formed if it has conflicting
+sources of ownership, or if it has redundant ownership modifiers, or if it has
+``__autoreleasing`` ownership.
+
+* ``assign`` implies ``__unsafe_unretained`` ownership.
+* ``copy`` implies ``__strong`` ownership, as well as the usual behavior of
+ copy semantics on the setter.
+* ``retain`` implies ``__strong`` ownership.
+* ``strong`` implies ``__strong`` ownership.
+* ``unsafe_unretained`` implies ``__unsafe_unretained`` ownership.
+* ``weak`` implies ``__weak`` ownership.
+
+With the exception of ``weak``, these modifiers are available in non-ARC
+modes.
+
+A property's specified ownership is preserved in its metadata, but otherwise
+the meaning is purely conventional unless the property is synthesized. If a
+property is synthesized, then the :arc-term:`associated instance variable` is
+the instance variable which is named, possibly implicitly, by the
+``@synthesize`` declaration. If the associated instance variable already
+exists, then its ownership qualification must equal the ownership of the
+property; otherwise, the instance variable is created with that ownership
+qualification.
+
+A property of retainable object pointer type which is synthesized without a
+source of ownership has the ownership of its associated instance variable, if it
+already exists; otherwise, :when-revised:`[beginning Apple 3.1, LLVM 3.1]`
+:revision:`its ownership is implicitly` ``strong``. Prior to this revision, it
+was ill-formed to synthesize such a property.
+
+.. admonition:: Rationale
+
+ Using ``strong`` by default is safe and consistent with the generic ARC rule
+ about :ref:`inferring ownership <arc.ownership.inference.variables>`. It is,
+ unfortunately, inconsistent with the non-ARC rule which states that such
+ properties are implicitly ``assign``. However, that rule is clearly
+ untenable in ARC, since it leads to default-unsafe code. The main merit to
+ banning the properties is to avoid confusion with non-ARC practice, which did
+ not ultimately strike us as sufficient to justify requiring extra syntax and
+ (more importantly) forcing novices to understand ownership rules just to
+ declare a property when the default is so reasonable. Changing the rule away
+ 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.
+
+.. _arc.ownership.semantics:
+
+Semantics
+---------
+
+There are five :arc-term:`managed operations` which may be performed on an
+object of retainable object pointer type. Each qualifier specifies different
+semantics for each of these operations. It is still undefined behavior to
+access an object outside of its lifetime.
+
+A load or store with "primitive semantics" has the same semantics as the
+respective operation would have on an ``void*`` lvalue with the same alignment
+and non-ownership qualification.
+
+:arc-term:`Reading` occurs when performing a lvalue-to-rvalue conversion on an
+object lvalue.
+
+* For ``__weak`` objects, the current pointee is retained and then released at
+ the end of the current full-expression. This must execute atomically with
+ respect to assignments and to the final release of the pointee.
+* For all other objects, the lvalue is loaded with primitive semantics.
+
+:arc-term:`Assignment` occurs when evaluating an assignment operator. The
+semantics vary based on the qualification:
+
+* For ``__strong`` objects, the new pointee is first retained; second, the
+ lvalue is loaded with primitive semantics; third, the new pointee is stored
+ into the lvalue with primitive semantics; and finally, the old pointee is
+ released. This is not performed atomically; external synchronization must be
+ used to make this safe in the face of concurrent loads and stores.
+* For ``__weak`` objects, the lvalue is updated to point to the new pointee,
+ unless the new pointee is an object currently undergoing deallocation, in
+ which case the lvalue is updated to a null pointer. This must execute
+ atomically with respect to other assignments to the object, to reads from the
+ object, and to the final release of the new pointee.
+* For ``__unsafe_unretained`` objects, the new pointee is stored into the
+ lvalue using primitive semantics.
+* For ``__autoreleasing`` objects, the new pointee is retained, autoreleased,
+ and stored into the lvalue using primitive semantics.
+
+:arc-term:`Initialization` occurs when an object's lifetime begins, which
+depends on its storage duration. Initialization proceeds in two stages:
+
+#. First, a null pointer is stored into the lvalue using primitive semantics.
+ This step is skipped if the object is ``__unsafe_unretained``.
+#. Second, if the object has an initializer, that expression is evaluated and
+ then assigned into the object using the usual assignment semantics.
+
+:arc-term:`Destruction` occurs when an object's lifetime ends. In all cases it
+is semantically equivalent to assigning a null pointer to the object, with the
+proviso that of course the object cannot be legally read after the object's
+lifetime ends.
+
+:arc-term:`Moving` occurs in specific situations where an lvalue is "moved
+from", meaning that its current pointee will be used but the object may be left
+in a different (but still valid) state. This arises with ``__block`` variables
+and rvalue references in C++. For ``__strong`` lvalues, moving is equivalent
+to loading the lvalue with primitive semantics, writing a null pointer to it
+with primitive semantics, and then releasing the result of the load at the end
+of the current full-expression. For all other lvalues, moving is equivalent to
+reading the object.
+
+.. _arc.ownership.restrictions:
+
+Restrictions
+------------
+
+.. _arc.ownership.restrictions.weak:
+
+Weak-unavailable types
+^^^^^^^^^^^^^^^^^^^^^^
+
+It is explicitly permitted for Objective-C classes to not support ``__weak``
+references. It is undefined behavior to perform an operation with weak
+assignment semantics with a pointer to an Objective-C object whose class does
+not support ``__weak`` references.
+
+.. admonition:: Rationale
+
+ Historically, it has been possible for a class to provide its own
+ reference-count implementation by overriding ``retain``, ``release``, etc.
+ However, weak references to an object require coordination with its class's
+ reference-count implementation because, among other things, weak loads and
+ stores must be atomic with respect to the final release. Therefore, existing
+ custom reference-count implementations will generally not support weak
+ references without additional effort. This is unavoidable without breaking
+ binary compatibility.
+
+A class may indicate that it does not support weak references by providing the
+``objc_arc_weak_unavailable`` attribute on the class's interface declaration. A
+retainable object pointer type is **weak-unavailable** if
+is a pointer to an (optionally protocol-qualified) Objective-C class ``T`` where
+``T`` or one of its superclasses has the ``objc_arc_weak_unavailable``
+attribute. A program is ill-formed if it applies the ``__weak`` ownership
+qualifier to a weak-unavailable type or if the value operand of a weak
+assignment operation has a weak-unavailable type.
+
+.. _arc.ownership.restrictions.autoreleasing:
+
+Storage duration of ``__autoreleasing`` objects
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A program is ill-formed if it declares an ``__autoreleasing`` object of
+non-automatic storage duration. A program is ill-formed if it captures an
+``__autoreleasing`` object in a block or, unless by reference, in a C++11
+lambda.
+
+.. admonition:: Rationale
+
+ Autorelease pools are tied to the current thread and scope by their nature.
+ While it is possible to have temporary objects whose instance variables are
+ filled with autoreleased objects, there is no way that ARC can provide any
+ sort of safety guarantee there.
+
+It is undefined behavior if a non-null pointer is assigned to an
+``__autoreleasing`` object while an autorelease pool is in scope and then that
+object is read after the autorelease pool's scope is left.
+
+.. _arc.ownership.restrictions.conversion.indirect:
+
+Conversion of pointers to ownership-qualified types
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A program is ill-formed if an expression of type ``T*`` is converted,
+explicitly or implicitly, to the type ``U*``, where ``T`` and ``U`` have
+different ownership qualification, unless:
+
+* ``T`` is qualified with ``__strong``, ``__autoreleasing``, or
+ ``__unsafe_unretained``, and ``U`` is qualified with both ``const`` and
+ ``__unsafe_unretained``; or
+* either ``T`` or ``U`` is ``cv void``, where ``cv`` is an optional sequence
+ of non-ownership qualifiers; or
+* the conversion is requested with a ``reinterpret_cast`` in Objective-C++; or
+* the conversion is a well-formed :ref:`pass-by-writeback
+ <arc.ownership.restrictions.pass_by_writeback>`.
+
+The analogous rule applies to ``T&`` and ``U&`` in Objective-C++.
+
+.. admonition:: Rationale
+
+ These rules provide a reasonable level of type-safety for indirect pointers,
+ as long as the underlying memory is not deallocated. The conversion to
+ ``const __unsafe_unretained`` is permitted because the semantics of reads are
+ equivalent across all these ownership semantics, and that's a very useful and
+ common pattern. The interconversion with ``void*`` is useful for allocating
+ memory or otherwise escaping the type system, but use it carefully.
+ ``reinterpret_cast`` is considered to be an obvious enough sign of taking
+ responsibility for any problems.
+
+It is undefined behavior to access an ownership-qualified object through an
+lvalue of a differently-qualified type, except that any non-``__weak`` object
+may be read through an ``__unsafe_unretained`` lvalue.
+
+It is undefined behavior if a managed operation is performed on a ``__strong``
+or ``__weak`` object without a guarantee that it contains a primitive zero
+bit-pattern, or if the storage for such an object is freed or reused without the
+object being first assigned a null pointer.
+
+.. admonition:: Rationale
+
+ ARC cannot differentiate between an assignment operator which is intended to
+ "initialize" dynamic memory and one which is intended to potentially replace
+ a value. Therefore the object's pointer must be valid before letting ARC at
+ it. Similarly, C and Objective-C do not provide any language hooks for
+ destroying objects held in dynamic memory, so it is the programmer's
+ responsibility to avoid leaks (``__strong`` objects) and consistency errors
+ (``__weak`` objects).
+
+These requirements are followed automatically in Objective-C++ when creating
+objects of retainable object owner type with ``new`` or ``new[]`` and destroying
+them with ``delete``, ``delete[]``, or a pseudo-destructor expression. Note
+that arrays of nontrivially-ownership-qualified type are not ABI compatible with
+non-ARC code because the element type is non-POD: such arrays that are
+``new[]``'d in ARC translation units cannot be ``delete[]``'d in non-ARC
+translation units and vice-versa.
+
+.. _arc.ownership.restrictions.pass_by_writeback:
+
+Passing to an out parameter by writeback
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If the argument passed to a parameter of type ``T __autoreleasing *`` has type
+``U oq *``, where ``oq`` is an ownership qualifier, then the argument is a
+candidate for :arc-term:`pass-by-writeback`` if:
+
+* ``oq`` is ``__strong`` or ``__weak``, and
+* it would be legal to initialize a ``T __strong *`` with a ``U __strong *``.
+
+For purposes of overload resolution, an implicit conversion sequence requiring
+a pass-by-writeback is always worse than an implicit conversion sequence not
+requiring a pass-by-writeback.
+
+The pass-by-writeback is ill-formed if the argument expression does not have a
+legal form:
+
+* ``&var``, where ``var`` is a scalar variable of automatic storage duration
+ with retainable object pointer type
+* a conditional expression where the second and third operands are both legal
+ forms
+* a cast whose operand is a legal form
+* a null pointer constant
+
+.. admonition:: Rationale
+
+ The restriction in the form of the argument serves two purposes. First, it
+ makes it impossible to pass the address of an array to the argument, which
+ serves to protect against an otherwise serious risk of mis-inferring an
+ "array" argument as an out-parameter. Second, it makes it much less likely
+ that the user will see confusing aliasing problems due to the implementation,
+ below, where their store to the writeback temporary is not immediately seen
+ in the original argument variable.
+
+A pass-by-writeback is evaluated as follows:
+
+#. The argument is evaluated to yield a pointer ``p`` of type ``U oq *``.
+#. If ``p`` is a null pointer, then a null pointer is passed as the argument,
+ and no further work is required for the pass-by-writeback.
+#. Otherwise, a temporary of type ``T __autoreleasing`` is created and
+ initialized to a null pointer.
+#. If the parameter is not an Objective-C method parameter marked ``out``,
+ then ``*p`` is read, and the result is written into the temporary with
+ primitive semantics.
+#. The address of the temporary is passed as the argument to the actual call.
+#. After the call completes, the temporary is loaded with primitive
+ semantics, and that value is assigned into ``*p``.
+
+.. admonition:: Rationale
+
+ This is all admittedly convoluted. In an ideal world, we would see that a
+ local variable is being passed to an out-parameter and retroactively modify
+ its type to be ``__autoreleasing`` rather than ``__strong``. This would be
+ remarkably difficult and not always well-founded under the C type system.
+ However, it was judged unacceptably invasive to require programmers to write
+ ``__autoreleasing`` on all the variables they intend to use for
+ out-parameters. This was the least bad solution.
+
+.. _arc.ownership.restrictions.records:
+
+Ownership-qualified fields of structs and unions
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A program is ill-formed if it declares a member of a C struct or union to have
+a nontrivially ownership-qualified type.
+
+.. admonition:: Rationale
+
+ The resulting type would be non-POD in the C++ sense, but C does not give us
+ very good language tools for managing the lifetime of aggregates, so it is
+ more convenient to simply forbid them. It is still possible to manage this
+ with a ``void*`` or an ``__unsafe_unretained`` object.
+
+This restriction does not apply in Objective-C++. However, nontrivally
+ownership-qualified types are considered non-POD: in C++11 terms, they are not
+trivially default constructible, copy constructible, move constructible, copy
+assignable, move assignable, or destructible. It is a violation of C++'s One
+Definition Rule to use a class outside of ARC that, under ARC, would have a
+nontrivially ownership-qualified member.
+
+.. admonition:: Rationale
+
+ Unlike in C, we can express all the necessary ARC semantics for
+ ownership-qualified subobjects as suboperations of the (default) special
+ member functions for the class. These functions then become non-trivial.
+ This has the non-obvious result that the class will have a non-trivial copy
+ constructor and non-trivial destructor; if this would not normally be true
+ outside of ARC, objects of the type will be passed and returned in an
+ ABI-incompatible manner.
+
+.. _arc.ownership.inference:
+
+Ownership inference
+-------------------
+
+.. _arc.ownership.inference.variables:
+
+Objects
+^^^^^^^
+
+If an object is declared with retainable object owner type, but without an
+explicit ownership qualifier, its type is implicitly adjusted to have
+``__strong`` qualification.
+
+As a special case, if the object's base type is ``Class`` (possibly
+protocol-qualified), the type is adjusted to have ``__unsafe_unretained``
+qualification instead.
+
+.. _arc.ownership.inference.indirect_parameters:
+
+Indirect parameters
+^^^^^^^^^^^^^^^^^^^
+
+If a function or method parameter has type ``T*``, where ``T`` is an
+ownership-unqualified retainable object pointer type, then:
+
+* if ``T`` is ``const``-qualified or ``Class``, then it is implicitly
+ qualified with ``__unsafe_unretained``;
+* otherwise, it is implicitly qualified with ``__autoreleasing``.
+
+.. admonition:: Rationale
+
+ ``__autoreleasing`` exists mostly for this case, the Cocoa convention for
+ out-parameters. Since a pointer to ``const`` is obviously not an
+ out-parameter, we instead use a type more useful for passing arrays. If the
+ user instead intends to pass in a *mutable* array, inferring
+ ``__autoreleasing`` is the wrong thing to do; this directs some of the
+ caution in the following rules about writeback.
+
+Such a type written anywhere else would be ill-formed by the general rule
+requiring ownership qualifiers.
+
+This rule does not apply in Objective-C++ if a parameter's type is dependent in
+a template pattern and is only *instantiated* to a type which would be a
+pointer to an unqualified retainable object pointer type. Such code is still
+ill-formed.
+
+.. admonition:: Rationale
+
+ The convention is very unlikely to be intentional in template code.
+
+.. _arc.ownership.inference.template.arguments:
+
+Template arguments
+^^^^^^^^^^^^^^^^^^
+
+If a template argument for a template type parameter is an retainable object
+owner type that does not have an explicit ownership qualifier, it is adjusted
+to have ``__strong`` qualification. This adjustment occurs regardless of
+whether the template argument was deduced or explicitly specified.
+
+.. admonition:: Rationale
+
+ ``__strong`` is a useful default for containers (e.g., ``std::vector<id>``),
+ which would otherwise require explicit qualification. Moreover, unqualified
+ retainable object pointer types are unlikely to be useful within templates,
+ since they generally need to have a qualifier applied to the before being
+ used.
+
+.. _arc.method-families:
+
+Method families
+===============
+
+An Objective-C method may fall into a :arc-term:`method family`, which is a
+conventional set of behaviors ascribed to it by the Cocoa conventions.
+
+A method is in a certain method family if:
+
+* it has a ``objc_method_family`` attribute placing it in that family; or if
+ not that,
+* it does not have an ``objc_method_family`` attribute placing it in a
+ different or no family, and
+* its selector falls into the corresponding selector family, and
+* its signature obeys the added restrictions of the method family.
+
+A selector is in a certain selector family if, ignoring any leading
+underscores, the first component of the selector either consists entirely of
+the name of the method family or it begins with that name followed by a
+character other than a lowercase letter. For example, ``_perform:with:`` and
+``performWith:`` would fall into the ``perform`` family (if we recognized one),
+but ``performing:with`` would not.
+
+The families and their added restrictions are:
+
+* ``alloc`` methods must return a retainable object pointer type.
+* ``copy`` methods must return a retainable object pointer type.
+* ``mutableCopy`` methods must return a retainable object pointer type.
+* ``new`` methods must return a retainable object pointer type.
+* ``init`` methods must be instance methods and must return an Objective-C
+ pointer type. Additionally, a program is ill-formed if it declares or
+ contains a call to an ``init`` method whose return type is neither ``id`` nor
+ a pointer to a super-class or sub-class of the declaring class (if the method
+ was declared on a class) or the static receiver type of the call (if it was
+ declared on a protocol).
+
+ .. admonition:: Rationale
+
+ There are a fair number of existing methods with ``init``-like selectors
+ which nonetheless don't follow the ``init`` conventions. Typically these
+ are either accidental naming collisions or helper methods called during
+ initialization. Because of the peculiar retain/release behavior of
+ ``init`` methods, it's very important not to treat these methods as
+ ``init`` methods if they aren't meant to be. It was felt that implicitly
+ defining these methods out of the family based on the exact relationship
+ between the return type and the declaring class would be much too subtle
+ and fragile. Therefore we identify a small number of legitimate-seeming
+ return types and call everything else an error. This serves the secondary
+ purpose of encouraging programmers not to accidentally give methods names
+ in the ``init`` family.
+
+ Note that a method with an ``init``-family selector which returns a
+ non-Objective-C type (e.g. ``void``) is perfectly well-formed; it simply
+ isn't in the ``init`` family.
+
+A program is ill-formed if a method's declarations, implementations, and
+overrides do not all have the same method family.
+
+.. _arc.family.attribute:
+
+Explicit method family control
+------------------------------
+
+A method may be annotated with the ``objc_method_family`` attribute to
+precisely control which method family it belongs to. If a method in an
+``@implementation`` does not have this attribute, but there is a method
+declared in the corresponding ``@interface`` that does, then the attribute is
+copied to the declaration in the ``@implementation``. The attribute is
+available outside of ARC, and may be tested for with the preprocessor query
+``__has_attribute(objc_method_family)``.
+
+The attribute is spelled
+``__attribute__((objc_method_family(`` *family* ``)))``. If *family* is
+``none``, the method has no family, even if it would otherwise be considered to
+have one based on its selector and type. Otherwise, *family* must be one of
+``alloc``, ``copy``, ``init``, ``mutableCopy``, or ``new``, in which case the
+method is considered to belong to the corresponding family regardless of its
+selector. It is an error if a method that is explicitly added to a family in
+this way does not meet the requirements of the family other than the selector
+naming convention.
+
+.. admonition:: Rationale
+
+ The rules codified in this document describe the standard conventions of
+ Objective-C. However, as these conventions have not heretofore been enforced
+ by an unforgiving mechanical system, they are only imperfectly kept,
+ especially as they haven't always even been precisely defined. While it is
+ possible to define low-level ownership semantics with attributes like
+ ``ns_returns_retained``, this attribute allows the user to communicate
+ semantic intent, which is of use both to ARC (which, e.g., treats calls to
+ ``init`` specially) and the static analyzer.
+
+.. _arc.family.semantics:
+
+Semantics of method families
+----------------------------
+
+A method's membership in a method family may imply non-standard semantics for
+its parameters and return type.
+
+Methods in the ``alloc``, ``copy``, ``mutableCopy``, and ``new`` families ---
+that is, methods in all the currently-defined families except ``init`` ---
+implicitly :ref:`return a retained object
+<arc.object.operands.retained-return-values>` as if they were annotated with
+the ``ns_returns_retained`` attribute. This can be overridden by annotating
+the method with either of the ``ns_returns_autoreleased`` or
+``ns_returns_not_retained`` attributes.
+
+Properties also follow same naming rules as methods. This means that those in
+the ``alloc``, ``copy``, ``mutableCopy``, and ``new`` families provide access
+to :ref:`retained objects <arc.object.operands.retained-return-values>`. This
+can be overridden by annotating the property with ``ns_returns_not_retained``
+attribute.
+
+.. _arc.family.semantics.init:
+
+Semantics of ``init``
+^^^^^^^^^^^^^^^^^^^^^
+
+Methods in the ``init`` family implicitly :ref:`consume
+<arc.objects.operands.consumed>` their ``self`` parameter and :ref:`return a
+retained object <arc.object.operands.retained-return-values>`. Neither of
+these properties can be altered through attributes.
+
+A call to an ``init`` method with a receiver that is either ``self`` (possibly
+parenthesized or casted) or ``super`` is called a :arc-term:`delegate init
+call`. It is an error for a delegate init call to be made except from an
+``init`` method, and excluding blocks within such methods.
+
+As an exception to the :ref:`usual rule <arc.misc.self>`, the variable ``self``
+is mutable in an ``init`` method and has the usual semantics for a ``__strong``
+variable. However, it is undefined behavior and the program is ill-formed, no
+diagnostic required, if an ``init`` method attempts to use the previous value
+of ``self`` after the completion of a delegate init call. It is conventional,
+but not required, for an ``init`` method to return ``self``.
+
+It is undefined behavior for a program to cause two or more calls to ``init``
+methods on the same object, except that each ``init`` method invocation may
+perform at most one delegate init call.
+
+.. _arc.family.semantics.result_type:
+
+Related result types
+^^^^^^^^^^^^^^^^^^^^
+
+Certain methods are candidates to have :arc-term:`related result types`:
+
+* class methods in the ``alloc`` and ``new`` method families
+* instance methods in the ``init`` family
+* the instance method ``self``
+* outside of ARC, the instance methods ``retain`` and ``autorelease``
+
+If the formal result type of such a method is ``id`` or protocol-qualified
+``id``, or a type equal to the declaring class or a superclass, then it is said
+to have a related result type. In this case, when invoked in an explicit
+message send, it is assumed to return a type related to the type of the
+receiver:
+
+* if it is a class method, and the receiver is a class name ``T``, the message
+ send expression has type ``T*``; otherwise
+* if it is an instance method, and the receiver has type ``T``, the message
+ send expression has type ``T``; otherwise
+* the message send expression has the normal result type of the method.
+
+This is a new rule of the Objective-C language and applies outside of ARC.
+
+.. admonition:: Rationale
+
+ ARC's automatic code emission is more prone than most code to signature
+ errors, i.e. errors where a call was emitted against one method signature,
+ but the implementing method has an incompatible signature. Having more
+ precise type information helps drastically lower this risk, as well as
+ catching a number of latent bugs.
+
+.. _arc.optimization:
+
+Optimization
+============
+
+Within this section, the word :arc-term:`function` will be used to
+refer to any structured unit of code, be it a C function, an
+Objective-C method, or a block.
+
+This specification describes ARC as performing specific ``retain`` and
+``release`` operations on retainable object pointers at specific
+points during the execution of a program. These operations make up a
+non-contiguous subsequence of the computation history of the program.
+The portion of this sequence for a particular retainable object
+pointer for which a specific function execution is directly
+responsible is the :arc-term:`formal local retain history` of the
+object pointer. The corresponding actual sequence executed is the
+`dynamic local retain history`.
+
+However, under certain circumstances, ARC is permitted to re-order and
+eliminate operations in a manner which may alter the overall
+computation history beyond what is permitted by the general "as if"
+rule of C/C++ and the :ref:`restrictions <arc.objects.retains>` on
+the implementation of ``retain`` and ``release``.
+
+.. admonition:: Rationale
+
+ Specifically, ARC is sometimes permitted to optimize ``release``
+ operations in ways which might cause an object to be deallocated
+ before it would otherwise be. Without this, it would be almost
+ impossible to eliminate any ``retain``/``release`` pairs. For
+ example, consider the following code:
+
+ .. code-block:: objc
+
+ id x = _ivar;
+ [x foo];
+
+ If we were not permitted in any event to shorten the lifetime of the
+ object in ``x``, then we would not be able to eliminate this retain
+ and release unless we could prove that the message send could not
+ modify ``_ivar`` (or deallocate ``self``). Since message sends are
+ opaque to the optimizer, this is not possible, and so ARC's hands
+ would be almost completely tied.
+
+ARC makes no guarantees about the execution of a computation history
+which contains undefined behavior. In particular, ARC makes no
+guarantees in the presence of race conditions.
+
+ARC may assume that any retainable object pointers it receives or
+generates are instantaneously valid from that point until a point
+which, by the concurrency model of the host language, happens-after
+the generation of the pointer and happens-before a release of that
+object (possibly via an aliasing pointer or indirectly due to
+destruction of a different object).
+
+.. admonition:: Rationale
+
+ There is very little point in trying to guarantee correctness in the
+ presence of race conditions. ARC does not have a stack-scanning
+ garbage collector, and guaranteeing the atomicity of every load and
+ store operation would be prohibitive and preclude a vast amount of
+ optimization.
+
+ARC may assume that non-ARC code engages in sensible balancing
+behavior and does not rely on exact or minimum retain count values
+except as guaranteed by ``__strong`` object invariants or +1 transfer
+conventions. For example, if an object is provably double-retained
+and double-released, ARC may eliminate the inner retain and release;
+it does not need to guard against code which performs an unbalanced
+release followed by a "balancing" retain.
+
+.. _arc.optimization.liveness:
+
+Object liveness
+---------------
+
+ARC may not allow a retainable object ``X`` to be deallocated at a
+time ``T`` in a computation history if:
+
+* ``X`` is the value stored in a ``__strong`` object ``S`` with
+ :ref:`precise lifetime semantics <arc.optimization.precise>`, or
+
+* ``X`` is the value stored in a ``__strong`` object ``S`` with
+ imprecise lifetime semantics and, at some point after ``T`` but
+ before the next store to ``S``, the computation history features a
+ load from ``S`` and in some way depends on the value loaded, or
+
+* ``X`` is a value described as being released at the end of the
+ current full-expression and, at some point after ``T`` but before
+ the end of the full-expression, the computation history depends
+ on that value.
+
+.. admonition:: Rationale
+
+ The intent of the second rule is to say that objects held in normal
+ ``__strong`` local variables may be released as soon as the value in
+ the variable is no longer being used: either the variable stops
+ being used completely or a new value is stored in the variable.
+
+ The intent of the third rule is to say that return values may be
+ released after they've been used.
+
+A computation history depends on a pointer value ``P`` if it:
+
+* performs a pointer comparison with ``P``,
+* loads from ``P``,
+* stores to ``P``,
+* depends on a pointer value ``Q`` derived via pointer arithmetic
+ from ``P`` (including an instance-variable or field access), or
+* depends on a pointer value ``Q`` loaded from ``P``.
+
+Dependency applies only to values derived directly or indirectly from
+a particular expression result and does not occur merely because a
+separate pointer value dynamically aliases ``P``. Furthermore, this
+dependency is not carried by values that are stored to objects.
+
+.. admonition:: Rationale
+
+ The restrictions on dependency are intended to make this analysis
+ feasible by an optimizer with only incomplete information about a
+ program. Essentially, dependence is carried to "obvious" uses of a
+ pointer. Merely passing a pointer argument to a function does not
+ itself cause dependence, but since generally the optimizer will not
+ be able to prove that the function doesn't depend on that parameter,
+ it will be forced to conservatively assume it does.
+
+ Dependency propagates to values loaded from a pointer because those
+ values might be invalidated by deallocating the object. For
+ example, given the code ``__strong id x = p->ivar;``, ARC must not
+ move the release of ``p`` to between the load of ``p->ivar`` and the
+ retain of that value for storing into ``x``.
+
+ Dependency does not propagate through stores of dependent pointer
+ values because doing so would allow dependency to outlive the
+ full-expression which produced the original value. For example, the
+ address of an instance variable could be written to some global
+ location and then freely accessed during the lifetime of the local,
+ or a function could return an inner pointer of an object and store
+ it to a local. These cases would be potentially impossible to
+ reason about and so would basically prevent any optimizations based
+ on imprecise lifetime. There are also uncommon enough to make it
+ reasonable to require the precise-lifetime annotation if someone
+ really wants to rely on them.
+
+ Dependency does propagate through return values of pointer type.
+ The compelling source of need for this rule is a property accessor
+ which returns an un-autoreleased result; the calling function must
+ have the chance to operate on the value, e.g. to retain it, before
+ ARC releases the original pointer. Note again, however, that
+ dependence does not survive a store, so ARC does not guarantee the
+ continued validity of the return value past the end of the
+ full-expression.
+
+.. _arc.optimization.object_lifetime:
+
+No object lifetime extension
+----------------------------
+
+If, in the formal computation history of the program, an object ``X``
+has been deallocated by the time of an observable side-effect, then
+ARC must cause ``X`` to be deallocated by no later than the occurrence
+of that side-effect, except as influenced by the re-ordering of the
+destruction of objects.
+
+.. admonition:: Rationale
+
+ This rule is intended to prohibit ARC from observably extending the
+ lifetime of a retainable object, other than as specified in this
+ document. Together with the rule limiting the transformation of
+ releases, this rule requires ARC to eliminate retains and release
+ only in pairs.
+
+ ARC's power to reorder the destruction of objects is critical to its
+ ability to do any optimization, for essentially the same reason that
+ it must retain the power to decrease the lifetime of an object.
+ Unfortunately, while it's generally poor style for the destruction
+ of objects to have arbitrary side-effects, it's certainly possible.
+ Hence the caveat.
+
+.. _arc.optimization.precise:
+
+Precise lifetime semantics
+--------------------------
+
+In general, ARC maintains an invariant that a retainable object pointer held in
+a ``__strong`` object will be retained for the full formal lifetime of the
+object. Objects subject to this invariant have :arc-term:`precise lifetime
+semantics`.
+
+By default, local variables of automatic storage duration do not have precise
+lifetime semantics. Such objects are simply strong references which hold
+values of retainable object pointer type, and these values are still fully
+subject to the optimizations on values under local control.
+
+.. admonition:: Rationale
+
+ Applying these precise-lifetime semantics strictly would be prohibitive.
+ Many useful optimizations that might theoretically decrease the lifetime of
+ an object would be rendered impossible. Essentially, it promises too much.
+
+A local variable of retainable object owner type and automatic storage duration
+may be annotated with the ``objc_precise_lifetime`` attribute to indicate that
+it should be considered to be an object with precise lifetime semantics.
+
+.. admonition:: Rationale
+
+ Nonetheless, it is sometimes useful to be able to force an object to be
+ released at a precise time, even if that object does not appear to be used.
+ This is likely to be uncommon enough that the syntactic weight of explicitly
+ requesting these semantics will not be burdensome, and may even make the code
+ clearer.
+
+.. _arc.misc:
+
+Miscellaneous
+=============
+
+.. _arc.misc.special_methods:
+
+Special methods
+---------------
+
+.. _arc.misc.special_methods.retain:
+
+Memory management methods
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A program is ill-formed if it contains a method definition, message send, or
+``@selector`` expression for any of the following selectors:
+
+* ``autorelease``
+* ``release``
+* ``retain``
+* ``retainCount``
+
+.. admonition:: Rationale
+
+ ``retainCount`` is banned because ARC robs it of consistent semantics. The
+ others were banned after weighing three options for how to deal with message
+ sends:
+
+ **Honoring** them would work out very poorly if a programmer naively or
+ accidentally tried to incorporate code written for manual retain/release code
+ into an ARC program. At best, such code would do twice as much work as
+ necessary; quite frequently, however, ARC and the explicit code would both
+ try to balance the same retain, leading to crashes. The cost is losing the
+ ability to perform "unrooted" retains, i.e. retains not logically
+ corresponding to a strong reference in the object graph.
+
+ **Ignoring** them would badly violate user expectations about their code.
+ While it *would* make it easier to develop code simultaneously for ARC and
+ non-ARC, there is very little reason to do so except for certain library
+ developers. ARC and non-ARC translation units share an execution model and
+ can seamlessly interoperate. Within a translation unit, a developer who
+ faithfully maintains their code in non-ARC mode is suffering all the
+ restrictions of ARC for zero benefit, while a developer who isn't testing the
+ non-ARC mode is likely to be unpleasantly surprised if they try to go back to
+ it.
+
+ **Banning** them has the disadvantage of making it very awkward to migrate
+ existing code to ARC. The best answer to that, given a number of other
+ changes and restrictions in ARC, is to provide a specialized tool to assist
+ users in that migration.
+
+ Implementing these methods was banned because they are too integral to the
+ semantics of ARC; many tricks which worked tolerably under manual reference
+ counting will misbehave if ARC performs an ephemeral extra retain or two. If
+ absolutely required, it is still possible to implement them in non-ARC code,
+ for example in a category; the implementations must obey the :ref:`semantics
+ <arc.objects.retains>` laid out elsewhere in this document.
+
+.. _arc.misc.special_methods.dealloc:
+
+``dealloc``
+^^^^^^^^^^^
+
+A program is ill-formed if it contains a message send or ``@selector``
+expression for the selector ``dealloc``.
+
+.. admonition:: Rationale
+
+ There are no legitimate reasons to call ``dealloc`` directly.
+
+A class may provide a method definition for an instance method named
+``dealloc``. This method will be called after the final ``release`` of the
+object but before it is deallocated or any of its instance variables are
+destroyed. The superclass's implementation of ``dealloc`` will be called
+automatically when the method returns.
+
+.. admonition:: Rationale
+
+ Even though ARC destroys instance variables automatically, there are still
+ legitimate reasons to write a ``dealloc`` method, such as freeing
+ non-retainable resources. Failing to call ``[super dealloc]`` in such a
+ method is nearly always a bug. Sometimes, the object is simply trying to
+ prevent itself from being destroyed, but ``dealloc`` is really far too late
+ for the object to be raising such objections. Somewhat more legitimately, an
+ object may have been pool-allocated and should not be deallocated with
+ ``free``; for now, this can only be supported with a ``dealloc``
+ implementation outside of ARC. Such an 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.
+
+.. admonition:: 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.
+
+.. _arc.misc.autoreleasepool:
+
+``@autoreleasepool``
+--------------------
+
+To simplify the use of autorelease pools, and to bring them under the control
+of the compiler, a new kind of statement is available in Objective-C. It is
+written ``@autoreleasepool`` followed by a *compound-statement*, i.e. by a new
+scope delimited by curly braces. Upon entry to this block, the current state
+of the autorelease pool is captured. When the block is exited normally,
+whether by fallthrough or directed control flow (such as ``return`` or
+``break``), the autorelease pool is restored to the saved state, releasing all
+the objects in it. When the block is exited with an exception, the pool is not
+drained.
+
+``@autoreleasepool`` may be used in non-ARC translation units, with equivalent
+semantics.
+
+A program is ill-formed if it refers to the ``NSAutoreleasePool`` class.
+
+.. admonition:: Rationale
+
+ Autorelease pools are clearly important for the compiler to reason about, but
+ it is far too much to expect the compiler to accurately reason about control
+ dependencies between two calls. It is also very easy to accidentally forget
+ to drain an autorelease pool when using the manual API, and this can
+ significantly inflate the process's high-water-mark. The introduction of a
+ new scope is unfortunate but basically required for sane interaction with the
+ rest of the language. Not draining the pool during an unwind is apparently
+ required by the Objective-C exceptions implementation.
+
+.. _arc.misc.self:
+
+``self``
+--------
+
+The ``self`` parameter variable of an Objective-C method is never actually
+retained by the implementation. It is undefined behavior, or at least
+dangerous, to cause an object to be deallocated during a message send to that
+object.
+
+To make this safe, for Objective-C instance methods ``self`` is implicitly
+``const`` unless the method is in the :ref:`init family
+<arc.family.semantics.init>`. Further, ``self`` is **always** implicitly
+``const`` within a class method.
+
+.. admonition:: Rationale
+
+ The cost of retaining ``self`` in all methods was found to be prohibitive, as
+ it tends to be live across calls, preventing the optimizer from proving that
+ the retain and release are unnecessary --- for good reason, as it's quite
+ possible in theory to cause an object to be deallocated during its execution
+ without this retain and release. Since it's extremely uncommon to actually
+ do so, even unintentionally, and since there's no natural way for the
+ programmer to remove this retain/release pair otherwise (as there is for
+ other parameters by, say, making the variable ``__unsafe_unretained``), we
+ chose to make this optimizing assumption and shift some amount of risk to the
+ user.
+
+.. _arc.misc.enumeration:
+
+Fast enumeration iteration variables
+------------------------------------
+
+If a variable is declared in the condition of an Objective-C fast enumeration
+loop, and the variable has no explicit ownership qualifier, then it is
+qualified with ``const __strong`` and objects encountered during the
+enumeration are not actually retained.
+
+.. admonition:: Rationale
+
+ This is an optimization made possible because fast enumeration loops promise
+ to keep the objects retained during enumeration, and the collection itself
+ cannot be synchronously modified. It can be overridden by explicitly
+ qualifying the variable with ``__strong``, which will make the variable
+ mutable again and cause the loop to retain the objects it encounters.
+
+.. _arc.misc.blocks:
+
+Blocks
+------
+
+The implicit ``const`` capture variables created when evaluating a block
+literal expression have the same ownership semantics as the local variables
+they capture. The capture is performed by reading from the captured variable
+and initializing the capture variable with that value; the capture variable is
+destroyed when the block literal is, i.e. at the end of the enclosing scope.
+
+The :ref:`inference <arc.ownership.inference>` rules apply equally to
+``__block`` variables, which is a shift in semantics from non-ARC, where
+``__block`` variables did not implicitly retain during capture.
+
+``__block`` variables of retainable object owner type are moved off the stack
+by initializing the heap copy with the result of moving from the stack copy.
+
+With the exception of retains done as part of initializing a ``__strong``
+parameter variable or reading a ``__weak`` variable, whenever these semantics
+call for retaining a value of block-pointer type, it has the effect of a
+``Block_copy``. The optimizer may remove such copies when it sees that the
+result is used only as an argument to a call.
+
+.. _arc.misc.exceptions:
+
+Exceptions
+----------
+
+By default in Objective C, ARC is not exception-safe for normal releases:
+
+* It does not end the lifetime of ``__strong`` variables when their scopes are
+ abnormally terminated by an exception.
+* It does not perform releases which would occur at the end of a
+ full-expression if that full-expression throws an exception.
+
+A program may be compiled with the option ``-fobjc-arc-exceptions`` in order to
+enable these, or with the option ``-fno-objc-arc-exceptions`` to explicitly
+disable them, with the last such argument "winning".
+
+.. admonition:: Rationale
+
+ The standard Cocoa convention is that exceptions signal programmer error and
+ are not intended to be recovered from. Making code exceptions-safe by
+ default would impose severe runtime and code size penalties on code that
+ typically does not actually care about exceptions safety. Therefore,
+ ARC-generated code leaks by default on exceptions, which is just fine if the
+ process is going to be immediately terminated anyway. Programs which do care
+ about recovering from exceptions should enable the option.
+
+In Objective-C++, ``-fobjc-arc-exceptions`` is enabled by default.
+
+.. admonition:: Rationale
+
+ C++ already introduces pervasive exceptions-cleanup code of the sort that ARC
+ introduces. C++ programmers who have not already disabled exceptions are
+ much more likely to actual require exception-safety.
+
+ARC does end the lifetimes of ``__weak`` objects when an exception terminates
+their scope unless exceptions are disabled in the compiler.
+
+.. admonition:: Rationale
+
+ The consequence of a local ``__weak`` object not being destroyed is very
+ likely to be corruption of the Objective-C runtime, so we want to be safer
+ here. Of course, potentially massive leaks are about as likely to take down
+ the process as this corruption is if the program does try to recover from
+ exceptions.
+
+.. _arc.misc.interior:
+
+Interior pointers
+-----------------
+
+An Objective-C method returning a non-retainable pointer may be annotated with
+the ``objc_returns_inner_pointer`` attribute to indicate that it returns a
+handle to the internal data of an object, and that this reference will be
+invalidated if the object is destroyed. When such a message is sent to an
+object, the object's lifetime will be extended until at least the earliest of:
+
+* the last use of the returned pointer, or any pointer derived from it, in the
+ calling function or
+* the autorelease pool is restored to a previous state.
+
+.. admonition:: Rationale
+
+ Rationale: not all memory and resources are managed with reference counts; it
+ is common for objects to manage private resources in their own, private way.
+ Typically these resources are completely encapsulated within the object, but
+ some classes offer their users direct access for efficiency. If ARC is not
+ aware of methods that return such "interior" pointers, its optimizations can
+ cause the owning object to be reclaimed too soon. This attribute informs ARC
+ that it must tread lightly.
+
+ The extension rules are somewhat intentionally vague. The autorelease pool
+ limit is there to permit a simple implementation to simply retain and
+ autorelease the receiver. The other limit permits some amount of
+ optimization. The phrase "derived from" is intended to encompass the results
+ both of pointer transformations, such as casts and arithmetic, and of loading
+ from such derived pointers; furthermore, it applies whether or not such
+ derivations are applied directly in the calling code or by other utility code
+ (for example, the C library routine ``strchr``). However, the implementation
+ never need account for uses after a return from the code which calls the
+ method returning an interior pointer.
+
+As an exception, no extension is required if the receiver is loaded directly
+from a ``__strong`` object with :ref:`precise lifetime semantics
+<arc.optimization.precise>`.
+
+.. admonition:: Rationale
+
+ Implicit autoreleases carry the risk of significantly inflating memory use,
+ so it's important to provide users a way of avoiding these autoreleases.
+ Tying this to precise lifetime semantics is ideal, as for local variables
+ this requires a very explicit annotation, which allows ARC to trust the user
+ with good cheer.
+
+.. _arc.misc.c-retainable:
+
+C retainable pointer types
+--------------------------
+
+A type is a :arc-term:`C retainable pointer type` if it is a pointer to
+(possibly qualified) ``void`` or a pointer to a (possibly qualifier) ``struct``
+or ``class`` type.
+
+.. admonition:: Rationale
+
+ ARC does not manage pointers of CoreFoundation type (or any of the related
+ families of retainable C pointers which interoperate with Objective-C for
+ retain/release operation). In fact, ARC does not even know how to
+ distinguish these types from arbitrary C pointer types. The intent of this
+ concept is to filter out some obviously non-object types while leaving a hook
+ for later tightening if a means of exhaustively marking CF types is made
+ available.
+
+.. _arc.misc.c-retainable.audit:
+
+Auditing of C retainable pointer interfaces
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+:when-revised:`[beginning Apple 4.0, LLVM 3.1]`
+
+A C function may be marked with the ``cf_audited_transfer`` attribute to
+express that, except as otherwise marked with attributes, it obeys the
+parameter (consuming vs. non-consuming) and return (retained vs. non-retained)
+conventions for a C function of its name, namely:
+
+* A parameter of C retainable pointer type is assumed to not be consumed
+ unless it is marked with the ``cf_consumed`` attribute, and
+* A result of C retainable pointer type is assumed to not be returned retained
+ unless the function is either marked ``cf_returns_retained`` or it follows
+ the create/copy naming convention and is not marked
+ ``cf_returns_not_retained``.
+
+A function obeys the :arc-term:`create/copy` naming convention if its name
+contains as a substring:
+
+* either "Create" or "Copy" not followed by a lowercase letter, or
+* either "create" or "copy" not followed by a lowercase letter and
+ not preceded by any letter, whether uppercase or lowercase.
+
+A second attribute, ``cf_unknown_transfer``, signifies that a function's
+transfer semantics cannot be accurately captured using any of these
+annotations. A program is ill-formed if it annotates the same function with
+both ``cf_audited_transfer`` and ``cf_unknown_transfer``.
+
+A pragma is provided to facilitate the mass annotation of interfaces:
+
+.. code-block:: objc
+
+ #pragma clang arc_cf_code_audited begin
+ ...
+ #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`` attribute unless they otherwise have
+the ``cf_unknown_transfer`` attribute. The pragma is accepted in all language
+modes. A program is ill-formed if it attempts to change files, whether by
+including a file or ending the current file, within the extent of this pragma.
+
+It is possible to test for all the features in this section with
+``__has_feature(arc_cf_code_audited)``.
+
+.. admonition:: Rationale
+
+ A significant inconvenience in ARC programming is the necessity of
+ interacting with APIs based around C retainable pointers. These features are
+ designed to make it relatively easy for API authors to quickly review and
+ annotate their interfaces, in turn improving the fidelity of tools such as
+ the static analyzer and ARC. The single-file restriction on the pragma is
+ designed to eliminate the risk of accidentally annotating some other header's
+ interfaces.
+
+.. _arc.runtime:
+
+Runtime support
+===============
+
+This section describes the interaction between the ARC runtime and the code
+generated by the ARC compiler. This is not part of the ARC language
+specification; instead, it is effectively a language-specific ABI supplement,
+akin to the "Itanium" generic ABI for C++.
+
+Ownership qualification does not alter the storage requirements for objects,
+except that it is undefined behavior if a ``__weak`` object is inadequately
+aligned for an object of type ``id``. The other qualifiers may be used on
+explicitly under-aligned memory.
+
+The runtime tracks ``__weak`` objects which holds non-null values. It is
+undefined behavior to direct modify a ``__weak`` object which is being tracked
+by the runtime except through an
+:ref:`objc_storeWeak <arc.runtime.objc_storeWeak>`,
+:ref:`objc_destroyWeak <arc.runtime.objc_destroyWeak>`, or
+:ref:`objc_moveWeak <arc.runtime.objc_moveWeak>` call.
+
+The runtime must provide a number of new entrypoints which the compiler may
+emit, which are described in the remainder of this section.
+
+.. admonition:: Rationale
+
+ Several of these functions are semantically equivalent to a message send; we
+ emit calls to C functions instead because:
+
+ * the machine code to do so is significantly smaller,
+ * it is much easier to recognize the C functions in the ARC optimizer, and
+ * a sufficient sophisticated runtime may be able to avoid the message send in
+ common cases.
+
+ Several other of these functions are "fused" operations which can be
+ described entirely in terms of other operations. We use the fused operations
+ primarily as a code-size optimization, although in some cases there is also a
+ real potential for avoiding redundant operations in the runtime.
+
+.. _arc.runtime.objc_autorelease:
+
+``id objc_autorelease(id value);``
+----------------------------------
+
+*Precondition:* ``value`` is null or a pointer to a valid object.
+
+If ``value`` is null, this call has no effect. Otherwise, it adds the object
+to the innermost autorelease pool exactly as if the object had been sent the
+``autorelease`` message.
+
+Always returns ``value``.
+
+.. _arc.runtime.objc_autoreleasePoolPop:
+
+``void objc_autoreleasePoolPop(void *pool);``
+---------------------------------------------
+
+*Precondition:* ``pool`` is the result of a previous call to
+:ref:`objc_autoreleasePoolPush <arc.runtime.objc_autoreleasePoolPush>` on the
+current thread, where neither ``pool`` nor any enclosing pool have previously
+been popped.
+
+Releases all the objects added to the given autorelease pool and any
+autorelease pools it encloses, then sets the current autorelease pool to the
+pool directly enclosing ``pool``.
+
+.. _arc.runtime.objc_autoreleasePoolPush:
+
+``void *objc_autoreleasePoolPush(void);``
+-----------------------------------------
+
+Creates a new autorelease pool that is enclosed by the current pool, makes that
+the current pool, and returns an opaque "handle" to it.
+
+.. admonition:: Rationale
+
+ While the interface is described as an explicit hierarchy of pools, the rules
+ allow the implementation to just keep a stack of objects, using the stack
+ depth as the opaque pool handle.
+
+.. _arc.runtime.objc_autoreleaseReturnValue:
+
+``id objc_autoreleaseReturnValue(id value);``
+---------------------------------------------
+
+*Precondition:* ``value`` is null or a pointer to a valid object.
+
+If ``value`` is null, this call has no effect. Otherwise, it makes a best
+effort to hand off ownership of a retain count on the object to a call to
+:ref:`objc_retainAutoreleasedReturnValue
+<arc.runtime.objc_retainAutoreleasedReturnValue>` for the same object in an
+enclosing call frame. If this is not possible, the object is autoreleased as
+above.
+
+Always returns ``value``.
+
+.. _arc.runtime.objc_copyWeak:
+
+``void objc_copyWeak(id *dest, id *src);``
+------------------------------------------
+
+*Precondition:* ``src`` is a valid pointer which either contains a null pointer
+or has been registered as a ``__weak`` object. ``dest`` is a valid pointer
+which has not been registered as a ``__weak`` object.
+
+``dest`` is initialized to be equivalent to ``src``, potentially registering it
+with the runtime. Equivalent to the following code:
+
+.. code-block:: objc
+
+ void objc_copyWeak(id *dest, id *src) {
+ objc_release(objc_initWeak(dest, objc_loadWeakRetained(src)));
+ }
+
+Must be atomic with respect to calls to ``objc_storeWeak`` on ``src``.
+
+.. _arc.runtime.objc_destroyWeak:
+
+``void objc_destroyWeak(id *object);``
+--------------------------------------
+
+*Precondition:* ``object`` is a valid pointer which either contains a null
+pointer or has been registered as a ``__weak`` object.
+
+``object`` is unregistered as a weak object, if it ever was. The current value
+of ``object`` is left unspecified; otherwise, equivalent to the following code:
+
+.. code-block:: objc
+
+ void objc_destroyWeak(id *object) {
+ objc_storeWeak(object, nil);
+ }
+
+Does not need to be atomic with respect to calls to ``objc_storeWeak`` on
+``object``.
+
+.. _arc.runtime.objc_initWeak:
+
+``id objc_initWeak(id *object, id value);``
+-------------------------------------------
+
+*Precondition:* ``object`` is a valid pointer which has not been registered as
+a ``__weak`` object. ``value`` is null or a pointer to a valid object.
+
+If ``value`` is a null pointer or the object to which it points has begun
+deallocation, ``object`` is zero-initialized. Otherwise, ``object`` is
+registered as a ``__weak`` object pointing to ``value``. Equivalent to the
+following code:
+
+.. code-block:: objc
+
+ id objc_initWeak(id *object, id value) {
+ *object = nil;
+ return objc_storeWeak(object, value);
+ }
+
+Returns the value of ``object`` after the call.
+
+Does not need to be atomic with respect to calls to ``objc_storeWeak`` on
+``object``.
+
+.. _arc.runtime.objc_loadWeak:
+
+``id objc_loadWeak(id *object);``
+---------------------------------
+
+*Precondition:* ``object`` is a valid pointer which either contains a null
+pointer or has been registered as a ``__weak`` object.
+
+If ``object`` is registered as a ``__weak`` object, and the last value stored
+into ``object`` has not yet been deallocated or begun deallocation, retains and
+autoreleases that value and returns it. Otherwise returns null. Equivalent to
+the following code:
+
+.. code-block:: objc
+
+ id objc_loadWeak(id *object) {
+ return objc_autorelease(objc_loadWeakRetained(object));
+ }
+
+Must be atomic with respect to calls to ``objc_storeWeak`` on ``object``.
+
+.. admonition:: Rationale
+
+ Loading weak references would be inherently prone to race conditions without
+ the retain.
+
+.. _arc.runtime.objc_loadWeakRetained:
+
+``id objc_loadWeakRetained(id *object);``
+-----------------------------------------
+
+*Precondition:* ``object`` is a valid pointer which either contains a null
+pointer or has been registered as a ``__weak`` object.
+
+If ``object`` is registered as a ``__weak`` object, and the last value stored
+into ``object`` has not yet been deallocated or begun deallocation, retains
+that value and returns it. Otherwise returns null.
+
+Must be atomic with respect to calls to ``objc_storeWeak`` on ``object``.
+
+.. _arc.runtime.objc_moveWeak:
+
+``void objc_moveWeak(id *dest, id *src);``
+------------------------------------------
+
+*Precondition:* ``src`` is a valid pointer which either contains a null pointer
+or has been registered as a ``__weak`` object. ``dest`` is a valid pointer
+which has not been registered as a ``__weak`` object.
+
+``dest`` is initialized to be equivalent to ``src``, potentially registering it
+with the runtime. ``src`` may then be left in its original state, in which
+case this call is equivalent to :ref:`objc_copyWeak
+<arc.runtime.objc_copyWeak>`, or it may be left as null.
+
+Must be atomic with respect to calls to ``objc_storeWeak`` on ``src``.
+
+.. _arc.runtime.objc_release:
+
+``void objc_release(id value);``
+--------------------------------
+
+*Precondition:* ``value`` is null or a pointer to a valid object.
+
+If ``value`` is null, this call has no effect. Otherwise, it performs a
+release operation exactly as if the object had been sent the ``release``
+message.
+
+.. _arc.runtime.objc_retain:
+
+``id objc_retain(id value);``
+-----------------------------
+
+*Precondition:* ``value`` is null or a pointer to a valid object.
+
+If ``value`` is null, this call has no effect. Otherwise, it performs a retain
+operation exactly as if the object had been sent the ``retain`` message.
+
+Always returns ``value``.
+
+.. _arc.runtime.objc_retainAutorelease:
+
+``id objc_retainAutorelease(id value);``
+----------------------------------------
+
+*Precondition:* ``value`` is null or a pointer to a valid object.
+
+If ``value`` is null, this call has no effect. Otherwise, it performs a retain
+operation followed by an autorelease operation. Equivalent to the following
+code:
+
+.. code-block:: objc
+
+ id objc_retainAutorelease(id value) {
+ return objc_autorelease(objc_retain(value));
+ }
+
+Always returns ``value``.
+
+.. _arc.runtime.objc_retainAutoreleaseReturnValue:
+
+``id objc_retainAutoreleaseReturnValue(id value);``
+---------------------------------------------------
+
+*Precondition:* ``value`` is null or a pointer to a valid object.
+
+If ``value`` is null, this call has no effect. Otherwise, it performs a retain
+operation followed by the operation described in
+:ref:`objc_autoreleaseReturnValue <arc.runtime.objc_autoreleaseReturnValue>`.
+Equivalent to the following code:
+
+.. code-block:: objc
+
+ id objc_retainAutoreleaseReturnValue(id value) {
+ return objc_autoreleaseReturnValue(objc_retain(value));
+ }
+
+Always returns ``value``.
+
+.. _arc.runtime.objc_retainAutoreleasedReturnValue:
+
+``id objc_retainAutoreleasedReturnValue(id value);``
+----------------------------------------------------
+
+*Precondition:* ``value`` is null or a pointer to a valid object.
+
+If ``value`` is null, this call has no effect. Otherwise, it attempts to
+accept a hand off of a retain count from a call to
+:ref:`objc_autoreleaseReturnValue <arc.runtime.objc_autoreleaseReturnValue>` on
+``value`` in a recently-called function or something it calls. If that fails,
+it performs a retain operation exactly like :ref:`objc_retain
+<arc.runtime.objc_retain>`.
+
+Always returns ``value``.
+
+.. _arc.runtime.objc_retainBlock:
+
+``id objc_retainBlock(id value);``
+----------------------------------
+
+*Precondition:* ``value`` is null or a pointer to a valid block object.
+
+If ``value`` is null, this call has no effect. Otherwise, if the block pointed
+to by ``value`` is still on the stack, it is copied to the heap and the address
+of the copy is returned. Otherwise a retain operation is performed on the
+block exactly as if it had been sent the ``retain`` message.
+
+.. _arc.runtime.objc_storeStrong:
+
+``id objc_storeStrong(id *object, id value);``
+----------------------------------------------
+
+*Precondition:* ``object`` is a valid pointer to a ``__strong`` object which is
+adequately aligned for a pointer. ``value`` is null or a pointer to a valid
+object.
+
+Performs the complete sequence for assigning to a ``__strong`` object of
+non-block type [*]_. Equivalent to the following code:
+
+.. code-block:: objc
+
+ id objc_storeStrong(id *object, id value) {
+ value = [value retain];
+ id oldValue = *object;
+ *object = value;
+ [oldValue release];
+ return value;
+ }
+
+Always returns ``value``.
+
+.. [*] This does not imply that a ``__strong`` object of block type is an
+ invalid argument to this function. Rather it implies that an ``objc_retain``
+ and not an ``objc_retainBlock`` operation will be emitted if the argument is
+ a block.
+
+.. _arc.runtime.objc_storeWeak:
+
+``id objc_storeWeak(id *object, id value);``
+--------------------------------------------
+
+*Precondition:* ``object`` is a valid pointer which either contains a null
+pointer or has been registered as a ``__weak`` object. ``value`` is null or a
+pointer to a valid object.
+
+If ``value`` is a null pointer or the object to which it points has begun
+deallocation, ``object`` is assigned null and unregistered as a ``__weak``
+object. Otherwise, ``object`` is registered as a ``__weak`` object or has its
+registration updated to point to ``value``.
+
+Returns the value of ``object`` after the call.
+
diff --git a/docs/Block-ABI-Apple.rst b/docs/Block-ABI-Apple.rst
new file mode 100644
index 0000000..08f3464
--- /dev/null
+++ b/docs/Block-ABI-Apple.rst
@@ -0,0 +1,935 @@
+==================================
+Block Implementation Specification
+==================================
+
+.. contents::
+ :local:
+
+History
+=======
+
+* 2008/7/14 - created.
+* 2008/8/21 - revised, C++.
+* 2008/9/24 - add ``NULL`` ``isa`` field to ``__block`` storage.
+* 2008/10/1 - revise block layout to use a ``static`` descriptor structure.
+* 2008/10/6 - revise block layout to use an unsigned long int flags.
+* 2008/10/28 - specify use of ``_Block_object_assign`` and
+ ``_Block_object_dispose`` for all "Object" types in helper functions.
+* 2008/10/30 - revise new layout to have invoke function in same place.
+* 2008/10/30 - add ``__weak`` support.
+* 2010/3/16 - rev for stret return, signature field.
+* 2010/4/6 - improved wording.
+* 2013/1/6 - improved wording and converted to rst.
+
+This document describes the Apple ABI implementation specification of Blocks.
+
+The first shipping version of this ABI is found in Mac OS X 10.6, and shall be
+referred to as 10.6.ABI. As of 2010/3/16, the following describes the ABI
+contract with the runtime and the compiler, and, as necessary, will be referred
+to as ABI.2010.3.16.
+
+Since the Apple ABI references symbols from other elements of the system, any
+attempt to use this ABI on systems prior to SnowLeopard is undefined.
+
+High Level
+==========
+
+The ABI of ``Blocks`` consist of their layout and the runtime functions required
+by the compiler. A ``Block`` consists of a structure of the following form:
+
+.. code-block:: c
+
+ struct Block_literal_1 {
+ void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
+ int flags;
+ int reserved;
+ void (*invoke)(void *, ...);
+ struct Block_descriptor_1 {
+ unsigned long int reserved; // NULL
+ unsigned long int size; // sizeof(struct Block_literal_1)
+ // optional helper functions
+ void (*copy_helper)(void *dst, void *src); // IFF (1<<25)
+ void (*dispose_helper)(void *src); // IFF (1<<25)
+ // required ABI.2010.3.16
+ const char *signature; // IFF (1<<30)
+ } *descriptor;
+ // imported variables
+ };
+
+The following flags bits are in use thusly for a possible ABI.2010.3.16:
+
+.. code-block:: c
+
+ enum {
+ BLOCK_HAS_COPY_DISPOSE = (1 << 25),
+ BLOCK_HAS_CTOR = (1 << 26), // helpers have C++ code
+ BLOCK_IS_GLOBAL = (1 << 28),
+ BLOCK_HAS_STRET = (1 << 29), // IFF BLOCK_HAS_SIGNATURE
+ BLOCK_HAS_SIGNATURE = (1 << 30),
+ };
+
+In 10.6.ABI the (1<<29) was usually set and was always ignored by the runtime -
+it had been a transitional marker that did not get deleted after the
+transition. This bit is now paired with (1<<30), and represented as the pair
+(3<<30), for the following combinations of valid bit settings, and their
+meanings:
+
+.. code-block:: c
+
+ switch (flags & (3<<29)) {
+ case (0<<29): 10.6.ABI, no signature field available
+ case (1<<29): 10.6.ABI, no signature field available
+ case (2<<29): ABI.2010.3.16, regular calling convention, presence of signature field
+ case (3<<29): ABI.2010.3.16, stret calling convention, presence of signature field,
+ }
+
+The signature field is not always populated.
+
+The following discussions are presented as 10.6.ABI otherwise.
+
+``Block`` literals may occur within functions where the structure is created in
+stack local memory. They may also appear as initialization expressions for
+``Block`` variables of global or ``static`` local variables.
+
+When a ``Block`` literal expression is evaluated the stack based structure is
+initialized as follows:
+
+1. A ``static`` descriptor structure is declared and initialized as follows:
+
+ a. The ``invoke`` function pointer is set to a function that takes the
+ ``Block`` structure as its first argument and the rest of the arguments (if
+ any) to the ``Block`` and executes the ``Block`` compound statement.
+
+ b. The ``size`` field is set to the size of the following ``Block`` literal
+ structure.
+
+ c. The ``copy_helper`` and ``dispose_helper`` function pointers are set to
+ respective helper functions if they are required by the ``Block`` literal.
+
+2. A stack (or global) ``Block`` literal data structure is created and
+ initialized as follows:
+
+ a. The ``isa`` field is set to the address of the external
+ ``_NSConcreteStackBlock``, which is a block of uninitialized memory supplied
+ in ``libSystem``, or ``_NSConcreteGlobalBlock`` if this is a static or file
+ level ``Block`` literal.
+
+ b. The ``flags`` field is set to zero unless there are variables imported
+ into the ``Block`` that need helper functions for program level
+ ``Block_copy()`` and ``Block_release()`` operations, in which case the
+ (1<<25) flags bit is set.
+
+As an example, the ``Block`` literal expression:
+
+.. code-block:: c
+
+ ^ { printf("hello world\n"); }
+
+would cause the following to be created on a 32-bit system:
+
+.. code-block:: c
+
+ struct __block_literal_1 {
+ void *isa;
+ int flags;
+ int reserved;
+ void (*invoke)(struct __block_literal_1 *);
+ struct __block_descriptor_1 *descriptor;
+ };
+
+ void __block_invoke_1(struct __block_literal_1 *_block) {
+ printf("hello world\n");
+ }
+
+ static struct __block_descriptor_1 {
+ unsigned long int reserved;
+ unsigned long int Block_size;
+ } __block_descriptor_1 = { 0, sizeof(struct __block_literal_1), __block_invoke_1 };
+
+and where the ``Block`` literal itself appears:
+
+.. code-block:: c
+
+ struct __block_literal_1 _block_literal = {
+ &_NSConcreteStackBlock,
+ (1<<29), <uninitialized>,
+ __block_invoke_1,
+ &__block_descriptor_1
+ };
+
+A ``Block`` imports other ``Block`` references, ``const`` copies of other
+variables, and variables marked ``__block``. In Objective-C, variables may
+additionally be objects.
+
+When a ``Block`` literal expression is used as the initial value of a global
+or ``static`` local variable, it is initialized as follows:
+
+.. code-block:: c
+
+ struct __block_literal_1 __block_literal_1 = {
+ &_NSConcreteGlobalBlock,
+ (1<<28)|(1<<29), <uninitialized>,
+ __block_invoke_1,
+ &__block_descriptor_1
+ };
+
+that is, a different address is provided as the first value and a particular
+(1<<28) bit is set in the ``flags`` field, and otherwise it is the same as for
+stack based ``Block`` literals. This is an optimization that can be used for
+any ``Block`` literal that imports no ``const`` or ``__block`` storage
+variables.
+
+Imported Variables
+==================
+
+Variables of ``auto`` storage class are imported as ``const`` copies. Variables
+of ``__block`` storage class are imported as a pointer to an enclosing data
+structure. Global variables are simply referenced and not considered as
+imported.
+
+Imported ``const`` copy variables
+---------------------------------
+
+Automatic storage variables not marked with ``__block`` are imported as
+``const`` copies.
+
+The simplest example is that of importing a variable of type ``int``:
+
+.. code-block:: c
+
+ int x = 10;
+ void (^vv)(void) = ^{ printf("x is %d\n", x); }
+ x = 11;
+ vv();
+
+which would be compiled to:
+
+.. code-block:: c
+
+ struct __block_literal_2 {
+ void *isa;
+ int flags;
+ int reserved;
+ void (*invoke)(struct __block_literal_2 *);
+ struct __block_descriptor_2 *descriptor;
+ const int x;
+ };
+
+ void __block_invoke_2(struct __block_literal_2 *_block) {
+ printf("x is %d\n", _block->x);
+ }
+
+ static struct __block_descriptor_2 {
+ unsigned long int reserved;
+ unsigned long int Block_size;
+ } __block_descriptor_2 = { 0, sizeof(struct __block_literal_2) };
+
+and:
+
+.. code-block:: c
+
+ struct __block_literal_2 __block_literal_2 = {
+ &_NSConcreteStackBlock,
+ (1<<29), <uninitialized>,
+ __block_invoke_2,
+ &__block_descriptor_2,
+ x
+ };
+
+In summary, scalars, structures, unions, and function pointers are generally
+imported as ``const`` copies with no need for helper functions.
+
+Imported ``const`` copy of ``Block`` reference
+----------------------------------------------
+
+The first case where copy and dispose helper functions are required is for the
+case of when a ``Block`` itself is imported. In this case both a
+``copy_helper`` function and a ``dispose_helper`` function are needed. The
+``copy_helper`` function is passed both the existing stack based pointer and the
+pointer to the new heap version and should call back into the runtime to
+actually do the copy operation on the imported fields within the ``Block``. The
+runtime functions are all described in :ref:`RuntimeHelperFunctions`.
+
+A quick example:
+
+.. code-block:: c
+
+ void (^existingBlock)(void) = ...;
+ void (^vv)(void) = ^{ existingBlock(); }
+ vv();
+
+ struct __block_literal_3 {
+ ...; // existing block
+ };
+
+ struct __block_literal_4 {
+ void *isa;
+ int flags;
+ int reserved;
+ void (*invoke)(struct __block_literal_4 *);
+ struct __block_literal_3 *const existingBlock;
+ };
+
+ void __block_invoke_4(struct __block_literal_2 *_block) {
+ __block->existingBlock->invoke(__block->existingBlock);
+ }
+
+ void __block_copy_4(struct __block_literal_4 *dst, struct __block_literal_4 *src) {
+ //_Block_copy_assign(&dst->existingBlock, src->existingBlock, 0);
+ _Block_object_assign(&dst->existingBlock, src->existingBlock, BLOCK_FIELD_IS_BLOCK);
+ }
+
+ void __block_dispose_4(struct __block_literal_4 *src) {
+ // was _Block_destroy
+ _Block_object_dispose(src->existingBlock, BLOCK_FIELD_IS_BLOCK);
+ }
+
+ static struct __block_descriptor_4 {
+ unsigned long int reserved;
+ unsigned long int Block_size;
+ void (*copy_helper)(struct __block_literal_4 *dst, struct __block_literal_4 *src);
+ void (*dispose_helper)(struct __block_literal_4 *);
+ } __block_descriptor_4 = {
+ 0,
+ sizeof(struct __block_literal_4),
+ __block_copy_4,
+ __block_dispose_4,
+ };
+
+and where said ``Block`` is used:
+
+.. code-block:: c
+
+ struct __block_literal_4 _block_literal = {
+ &_NSConcreteStackBlock,
+ (1<<25)|(1<<29), <uninitialized>
+ __block_invoke_4,
+ & __block_descriptor_4
+ existingBlock,
+ };
+
+Importing ``__attribute__((NSObject))`` variables
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+GCC introduces ``__attribute__((NSObject))`` on structure pointers to mean "this
+is an object". This is useful because many low level data structures are
+declared as opaque structure pointers, e.g. ``CFStringRef``, ``CFArrayRef``,
+etc. When used from C, however, these are still really objects and are the
+second case where that requires copy and dispose helper functions to be
+generated. The copy helper functions generated by the compiler should use the
+``_Block_object_assign`` runtime helper function and in the dispose helper the
+``_Block_object_dispose`` runtime helper function should be called.
+
+For example, ``Block`` foo in the following:
+
+.. code-block:: c
+
+ struct Opaque *__attribute__((NSObject)) objectPointer = ...;
+ ...
+ void (^foo)(void) = ^{ CFPrint(objectPointer); };
+
+would have the following helper functions generated:
+
+.. code-block:: c
+
+ void __block_copy_foo(struct __block_literal_5 *dst, struct __block_literal_5 *src) {
+ _Block_object_assign(&dst->objectPointer, src-> objectPointer, BLOCK_FIELD_IS_OBJECT);
+ }
+
+ void __block_dispose_foo(struct __block_literal_5 *src) {
+ _Block_object_dispose(src->objectPointer, BLOCK_FIELD_IS_OBJECT);
+ }
+
+Imported ``__block`` marked variables
+-------------------------------------
+
+Layout of ``__block`` marked variables
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The compiler must embed variables that are marked ``__block`` in a specialized
+structure of the form:
+
+.. code-block:: c
+
+ struct _block_byref_foo {
+ void *isa;
+ struct Block_byref *forwarding;
+ int flags; //refcount;
+ int size;
+ typeof(marked_variable) marked_variable;
+ };
+
+Variables of certain types require helper functions for when ``Block_copy()``
+and ``Block_release()`` are performed upon a referencing ``Block``. At the "C"
+level only variables that are of type ``Block`` or ones that have
+``__attribute__((NSObject))`` marked require helper functions. In Objective-C
+objects require helper functions and in C++ stack based objects require helper
+functions. Variables that require helper functions use the form:
+
+.. code-block:: c
+
+ struct _block_byref_foo {
+ void *isa;
+ struct _block_byref_foo *forwarding;
+ int flags; //refcount;
+ int size;
+ // helper functions called via Block_copy() and Block_release()
+ void (*byref_keep)(void *dst, void *src);
+ void (*byref_dispose)(void *);
+ typeof(marked_variable) marked_variable;
+ };
+
+The structure is initialized such that:
+
+ a. The ``forwarding`` pointer is set to the beginning of its enclosing
+ structure.
+
+ b. The ``size`` field is initialized to the total size of the enclosing
+ structure.
+
+ c. The ``flags`` field is set to either 0 if no helper functions are needed
+ or (1<<25) if they are.
+
+ d. The helper functions are initialized (if present).
+
+ e. The variable itself is set to its initial value.
+
+ f. The ``isa`` field is set to ``NULL``.
+
+Access to ``__block`` variables from within its lexical scope
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In order to "move" the variable to the heap upon a ``copy_helper`` operation the
+compiler must rewrite access to such a variable to be indirect through the
+structures ``forwarding`` pointer. For example:
+
+.. code-block:: c
+
+ int __block i = 10;
+ i = 11;
+
+would be rewritten to be:
+
+.. code-block:: c
+
+ struct _block_byref_i {
+ void *isa;
+ struct _block_byref_i *forwarding;
+ int flags; //refcount;
+ int size;
+ int captured_i;
+ } i = { NULL, &i, 0, sizeof(struct _block_byref_i), 10 };
+
+ i.forwarding->captured_i = 11;
+
+In the case of a ``Block`` reference variable being marked ``__block`` the
+helper code generated must use the ``_Block_object_assign`` and
+``_Block_object_dispose`` routines supplied by the runtime to make the
+copies. For example:
+
+.. code-block:: c
+
+ __block void (voidBlock)(void) = blockA;
+ voidBlock = blockB;
+
+would translate into:
+
+.. code-block:: c
+
+ struct _block_byref_voidBlock {
+ void *isa;
+ struct _block_byref_voidBlock *forwarding;
+ int flags; //refcount;
+ int size;
+ void (*byref_keep)(struct _block_byref_voidBlock *dst, struct _block_byref_voidBlock *src);
+ void (*byref_dispose)(struct _block_byref_voidBlock *);
+ void (^captured_voidBlock)(void);
+ };
+
+ void _block_byref_keep_helper(struct _block_byref_voidBlock *dst, struct _block_byref_voidBlock *src) {
+ //_Block_copy_assign(&dst->captured_voidBlock, src->captured_voidBlock, 0);
+ _Block_object_assign(&dst->captured_voidBlock, src->captured_voidBlock, BLOCK_FIELD_IS_BLOCK | BLOCK_BYREF_CALLER);
+ }
+
+ void _block_byref_dispose_helper(struct _block_byref_voidBlock *param) {
+ //_Block_destroy(param->captured_voidBlock, 0);
+ _Block_object_dispose(param->captured_voidBlock, BLOCK_FIELD_IS_BLOCK | BLOCK_BYREF_CALLER)}
+
+and:
+
+.. code-block:: c
+
+ struct _block_byref_voidBlock voidBlock = {( .forwarding=&voidBlock, .flags=(1<<25), .size=sizeof(struct _block_byref_voidBlock *),
+ .byref_keep=_block_byref_keep_helper, .byref_dispose=_block_byref_dispose_helper,
+ .captured_voidBlock=blockA )};
+
+ voidBlock.forwarding->captured_voidBlock = blockB;
+
+Importing ``__block`` variables into ``Blocks``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A ``Block`` that uses a ``__block`` variable in its compound statement body must
+import the variable and emit ``copy_helper`` and ``dispose_helper`` helper
+functions that, in turn, call back into the runtime to actually copy or release
+the ``byref`` data block using the functions ``_Block_object_assign`` and
+``_Block_object_dispose``.
+
+For example:
+
+.. code-block:: c
+
+ int __block i = 2;
+ functioncall(^{ i = 10; });
+
+would translate to:
+
+.. code-block:: c
+
+ struct _block_byref_i {
+ void *isa; // set to NULL
+ struct _block_byref_voidBlock *forwarding;
+ int flags; //refcount;
+ int size;
+ void (*byref_keep)(struct _block_byref_i *dst, struct _block_byref_i *src);
+ void (*byref_dispose)(struct _block_byref_i *);
+ int captured_i;
+ };
+
+
+ struct __block_literal_5 {
+ void *isa;
+ int flags;
+ int reserved;
+ void (*invoke)(struct __block_literal_5 *);
+ struct __block_descriptor_5 *descriptor;
+ struct _block_byref_i *i_holder;
+ };
+
+ void __block_invoke_5(struct __block_literal_5 *_block) {
+ _block->forwarding->captured_i = 10;
+ }
+
+ void __block_copy_5(struct __block_literal_5 *dst, struct __block_literal_5 *src) {
+ //_Block_byref_assign_copy(&dst->captured_i, src->captured_i);
+ _Block_object_assign(&dst->captured_i, src->captured_i, BLOCK_FIELD_IS_BYREF | BLOCK_BYREF_CALLER);
+ }
+
+ void __block_dispose_5(struct __block_literal_5 *src) {
+ //_Block_byref_release(src->captured_i);
+ _Block_object_dispose(src->captured_i, BLOCK_FIELD_IS_BYREF | BLOCK_BYREF_CALLER);
+ }
+
+ static struct __block_descriptor_5 {
+ unsigned long int reserved;
+ unsigned long int Block_size;
+ void (*copy_helper)(struct __block_literal_5 *dst, struct __block_literal_5 *src);
+ void (*dispose_helper)(struct __block_literal_5 *);
+ } __block_descriptor_5 = { 0, sizeof(struct __block_literal_5) __block_copy_5, __block_dispose_5 };
+
+and:
+
+.. code-block:: c
+
+ struct _block_byref_i i = {( .forwarding=&i, .flags=0, .size=sizeof(struct _block_byref_i) )};
+ struct __block_literal_5 _block_literal = {
+ &_NSConcreteStackBlock,
+ (1<<25)|(1<<29), <uninitialized>,
+ __block_invoke_5,
+ &__block_descriptor_5,
+ 2,
+ };
+
+Importing ``__attribute__((NSObject))`` ``__block`` variables
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A ``__block`` variable that is also marked ``__attribute__((NSObject))`` should
+have ``byref_keep`` and ``byref_dispose`` helper functions that use
+``_Block_object_assign`` and ``_Block_object_dispose``.
+
+``__block`` escapes
+^^^^^^^^^^^^^^^^^^^
+
+Because ``Blocks`` referencing ``__block`` variables may have ``Block_copy()``
+performed upon them the underlying storage for the variables may move to the
+heap. In Objective-C Garbage Collection Only compilation environments the heap
+used is the garbage collected one and no further action is required. Otherwise
+the compiler must issue a call to potentially release any heap storage for
+``__block`` variables at all escapes or terminations of their scope. The call
+should be:
+
+.. code-block:: c
+
+ _Block_object_dispose(&_block_byref_foo, BLOCK_FIELD_IS_BYREF);
+
+Nesting
+^^^^^^^
+
+``Blocks`` may contain ``Block`` literal expressions. Any variables used within
+inner blocks are imported into all enclosing ``Block`` scopes even if the
+variables are not used. This includes ``const`` imports as well as ``__block``
+variables.
+
+Objective C Extensions to ``Blocks``
+====================================
+
+Importing Objects
+-----------------
+
+Objects should be treated as ``__attribute__((NSObject))`` variables; all
+``copy_helper``, ``dispose_helper``, ``byref_keep``, and ``byref_dispose``
+helper functions should use ``_Block_object_assign`` and
+``_Block_object_dispose``. There should be no code generated that uses
+``*-retain`` or ``*-release`` methods.
+
+``Blocks`` as Objects
+---------------------
+
+The compiler will treat ``Blocks`` as objects when synthesizing property setters
+and getters, will characterize them as objects when generating garbage
+collection strong and weak layout information in the same manner as objects, and
+will issue strong and weak write-barrier assignments in the same manner as
+objects.
+
+``__weak __block`` Support
+--------------------------
+
+Objective-C (and Objective-C++) support the ``__weak`` attribute on ``__block``
+variables. Under normal circumstances the compiler uses the Objective-C runtime
+helper support functions ``objc_assign_weak`` and ``objc_read_weak``. Both
+should continue to be used for all reads and writes of ``__weak __block``
+variables:
+
+.. code-block:: c
+
+ objc_read_weak(&block->byref_i->forwarding->i)
+
+The ``__weak`` variable is stored in a ``_block_byref_foo`` structure and the
+``Block`` has copy and dispose helpers for this structure that call:
+
+.. code-block:: c
+
+ _Block_object_assign(&dest->_block_byref_i, src-> _block_byref_i, BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_BYREF);
+
+and:
+
+.. code-block:: c
+
+ _Block_object_dispose(src->_block_byref_i, BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_BYREF);
+
+In turn, the ``block_byref`` copy support helpers distinguish between whether
+the ``__block`` variable is a ``Block`` or not and should either call:
+
+.. code-block:: c
+
+ _Block_object_assign(&dest->_block_byref_i, src->_block_byref_i, BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_OBJECT | BLOCK_BYREF_CALLER);
+
+for something declared as an object or:
+
+.. code-block:: c
+
+ _Block_object_assign(&dest->_block_byref_i, src->_block_byref_i, BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_BLOCK | BLOCK_BYREF_CALLER);
+
+for something declared as a ``Block``.
+
+A full example follows:
+
+.. code-block:: c
+
+ __block __weak id obj = <initialization expression>;
+ functioncall(^{ [obj somemessage]; });
+
+would translate to:
+
+.. code-block:: c
+
+ struct _block_byref_obj {
+ void *isa; // uninitialized
+ struct _block_byref_obj *forwarding;
+ int flags; //refcount;
+ int size;
+ void (*byref_keep)(struct _block_byref_i *dst, struct _block_byref_i *src);
+ void (*byref_dispose)(struct _block_byref_i *);
+ id captured_obj;
+ };
+
+ void _block_byref_obj_keep(struct _block_byref_voidBlock *dst, struct _block_byref_voidBlock *src) {
+ //_Block_copy_assign(&dst->captured_obj, src->captured_obj, 0);
+ _Block_object_assign(&dst->captured_obj, src->captured_obj, BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_WEAK | BLOCK_BYREF_CALLER);
+ }
+
+ void _block_byref_obj_dispose(struct _block_byref_voidBlock *param) {
+ //_Block_destroy(param->captured_obj, 0);
+ _Block_object_dispose(param->captured_obj, BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_WEAK | BLOCK_BYREF_CALLER);
+ };
+
+for the block ``byref`` part and:
+
+.. code-block:: c
+
+ struct __block_literal_5 {
+ void *isa;
+ int flags;
+ int reserved;
+ void (*invoke)(struct __block_literal_5 *);
+ struct __block_descriptor_5 *descriptor;
+ struct _block_byref_obj *byref_obj;
+ };
+
+ void __block_invoke_5(struct __block_literal_5 *_block) {
+ [objc_read_weak(&_block->byref_obj->forwarding->captured_obj) somemessage];
+ }
+
+ void __block_copy_5(struct __block_literal_5 *dst, struct __block_literal_5 *src) {
+ //_Block_byref_assign_copy(&dst->byref_obj, src->byref_obj);
+ _Block_object_assign(&dst->byref_obj, src->byref_obj, BLOCK_FIELD_IS_BYREF | BLOCK_FIELD_IS_WEAK);
+ }
+
+ void __block_dispose_5(struct __block_literal_5 *src) {
+ //_Block_byref_release(src->byref_obj);
+ _Block_object_dispose(src->byref_obj, BLOCK_FIELD_IS_BYREF | BLOCK_FIELD_IS_WEAK);
+ }
+
+ static struct __block_descriptor_5 {
+ unsigned long int reserved;
+ unsigned long int Block_size;
+ void (*copy_helper)(struct __block_literal_5 *dst, struct __block_literal_5 *src);
+ void (*dispose_helper)(struct __block_literal_5 *);
+ } __block_descriptor_5 = { 0, sizeof(struct __block_literal_5), __block_copy_5, __block_dispose_5 };
+
+and within the compound statement:
+
+.. code-block:: c
+
+ truct _block_byref_obj obj = {( .forwarding=&obj, .flags=(1<<25), .size=sizeof(struct _block_byref_obj),
+ .byref_keep=_block_byref_obj_keep, .byref_dispose=_block_byref_obj_dispose,
+ .captured_obj = <initialization expression> )};
+
+ truct __block_literal_5 _block_literal = {
+ &_NSConcreteStackBlock,
+ (1<<25)|(1<<29), <uninitialized>,
+ __block_invoke_5,
+ &__block_descriptor_5,
+ &obj, // a reference to the on-stack structure containing "captured_obj"
+ };
+
+
+ functioncall(_block_literal->invoke(&_block_literal));
+
+C++ Support
+===========
+
+Within a block stack based C++ objects are copied into ``const`` copies using
+the copy constructor. It is an error if a stack based C++ object is used within
+a block if it does not have a copy constructor. In addition both copy and
+destroy helper routines must be synthesized for the block to support the
+``Block_copy()`` operation, and the flags work marked with the (1<<26) bit in
+addition to the (1<<25) bit. The copy helper should call the constructor using
+appropriate offsets of the variable within the supplied stack based block source
+and heap based destination for all ``const`` constructed copies, and similarly
+should call the destructor in the destroy routine.
+
+As an example, suppose a C++ class ``FOO`` existed with a copy constructor.
+Within a code block a stack version of a ``FOO`` object is declared and used
+within a ``Block`` literal expression:
+
+.. code-block:: c++
+
+ {
+ FOO foo;
+ void (^block)(void) = ^{ printf("%d\n", foo.value()); };
+ }
+
+The compiler would synthesize:
+
+.. code-block:: c++
+
+ struct __block_literal_10 {
+ void *isa;
+ int flags;
+ int reserved;
+ void (*invoke)(struct __block_literal_10 *);
+ struct __block_descriptor_10 *descriptor;
+ const FOO foo;
+ };
+
+ void __block_invoke_10(struct __block_literal_10 *_block) {
+ printf("%d\n", _block->foo.value());
+ }
+
+ void __block_literal_10(struct __block_literal_10 *dst, struct __block_literal_10 *src) {
+ FOO_ctor(&dst->foo, &src->foo);
+ }
+
+ void __block_dispose_10(struct __block_literal_10 *src) {
+ FOO_dtor(&src->foo);
+ }
+
+ static struct __block_descriptor_10 {
+ unsigned long int reserved;
+ unsigned long int Block_size;
+ void (*copy_helper)(struct __block_literal_10 *dst, struct __block_literal_10 *src);
+ void (*dispose_helper)(struct __block_literal_10 *);
+ } __block_descriptor_10 = { 0, sizeof(struct __block_literal_10), __block_copy_10, __block_dispose_10 };
+
+and the code would be:
+
+.. code-block:: c++
+
+ {
+ FOO foo;
+ comp_ctor(&foo); // default constructor
+ struct __block_literal_10 _block_literal = {
+ &_NSConcreteStackBlock,
+ (1<<25)|(1<<26)|(1<<29), <uninitialized>,
+ __block_invoke_10,
+ &__block_descriptor_10,
+ };
+ comp_ctor(&_block_literal->foo, &foo); // const copy into stack version
+ struct __block_literal_10 &block = &_block_literal; // assign literal to block variable
+ block->invoke(block); // invoke block
+ comp_dtor(&_block_literal->foo); // destroy stack version of const block copy
+ comp_dtor(&foo); // destroy original version
+ }
+
+
+C++ objects stored in ``__block`` storage start out on the stack in a
+``block_byref`` data structure as do other variables. Such objects (if not
+``const`` objects) must support a regular copy constructor. The ``block_byref``
+data structure will have copy and destroy helper routines synthesized by the
+compiler. The copy helper will have code created to perform the copy
+constructor based on the initial stack ``block_byref`` data structure, and will
+also set the (1<<26) bit in addition to the (1<<25) bit. The destroy helper
+will have code to do the destructor on the object stored within the supplied
+``block_byref`` heap data structure. For example,
+
+.. code-block:: c++
+
+ __block FOO blockStorageFoo;
+
+requires the normal constructor for the embedded ``blockStorageFoo`` object:
+
+.. code-block:: c++
+
+ FOO_ctor(& _block_byref_blockStorageFoo->blockStorageFoo);
+
+and at scope termination the destructor:
+
+.. code-block:: c++
+
+ FOO_dtor(& _block_byref_blockStorageFoo->blockStorageFoo);
+
+Note that the forwarding indirection is *NOT* used.
+
+The compiler would need to generate (if used from a block literal) the following
+copy/dispose helpers:
+
+.. code-block:: c++
+
+ void _block_byref_obj_keep(struct _block_byref_blockStorageFoo *dst, struct _block_byref_blockStorageFoo *src) {
+ FOO_ctor(&dst->blockStorageFoo, &src->blockStorageFoo);
+ }
+
+ void _block_byref_obj_dispose(struct _block_byref_blockStorageFoo *src) {
+ FOO_dtor(&src->blockStorageFoo);
+ }
+
+for the appropriately named constructor and destructor for the class/struct
+``FOO``.
+
+To support member variable and function access the compiler will synthesize a
+``const`` pointer to a block version of the ``this`` pointer.
+
+.. _RuntimeHelperFunctions:
+
+Runtime Helper Functions
+========================
+
+The runtime helper functions are described in
+``/usr/local/include/Block_private.h``. To summarize their use, a ``Block``
+requires copy/dispose helpers if it imports any block variables, ``__block``
+storage variables, ``__attribute__((NSObject))`` variables, or C++ ``const``
+copied objects with constructor/destructors. The (1<<26) bit is set and
+functions are generated.
+
+The block copy helper function should, for each of the variables of the type
+mentioned above, call:
+
+.. code-block:: c
+
+ _Block_object_assign(&dst->target, src->target, BLOCK_FIELD_<appropo>);
+
+in the copy helper and:
+
+.. code-block:: c
+
+ _Block_object_dispose(->target, BLOCK_FIELD_<appropo>);
+
+in the dispose helper where ``<appropo>`` is:
+
+.. code-block:: c
+
+ 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
+
+ BLOCK_BYREF_CALLER = 128, // called from byref copy/dispose helpers
+ };
+
+and of course the constructors/destructors for ``const`` copied C++ objects.
+
+The ``block_byref`` data structure similarly requires copy/dispose helpers for
+block variables, ``__attribute__((NSObject))`` variables, or C++ ``const``
+copied objects with constructor/destructors, and again the (1<<26) bit is set
+and functions are generated in the same manner.
+
+Under ObjC we allow ``__weak`` as an attribute on ``__block`` variables, and
+this causes the addition of ``BLOCK_FIELD_IS_WEAK`` orred onto the
+``BLOCK_FIELD_IS_BYREF`` flag when copying the ``block_byref`` structure in the
+``Block`` copy helper, and onto the ``BLOCK_FIELD_<appropo>`` field within the
+``block_byref`` copy/dispose helper calls.
+
+The prototypes, and summary, of the helper functions are:
+
+.. code-block:: c
+
+ /* Certain field types require runtime assistance when being copied to the
+ heap. The following function is used to copy fields of types: blocks,
+ pointers to byref structures, and objects (including
+ __attribute__((NSObject)) pointers. BLOCK_FIELD_IS_WEAK is orthogonal to
+ the other choices which are mutually exclusive. Only in a Block copy
+ helper will one see BLOCK_FIELD_IS_BYREF.
+ */
+ void _Block_object_assign(void *destAddr, const void *object, const int flags);
+
+ /* Similarly a compiler generated dispose helper needs to call back for each
+ field of the byref data structure. (Currently the implementation only
+ packs one field into the byref structure but in principle there could be
+ more). The same flags used in the copy helper should be used for each
+ call generated to this function:
+ */
+ void _Block_object_dispose(const void *object, const int flags);
+
+Copyright
+=========
+
+Copyright 2008-2010 Apple, Inc.
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/docs/Block-ABI-Apple.txt b/docs/Block-ABI-Apple.txt
index 917059b..94a4d18 100644
--- a/docs/Block-ABI-Apple.txt
+++ b/docs/Block-ABI-Apple.txt
@@ -1,669 +1 @@
-Block Implementation Specification
-
-Copyright 2008-2010 Apple, Inc.
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-
-0. History
-
-2008/7/14 - created
-2008/8/21 - revised, C++
-2008/9/24 - add NULL isa field to __block storage
-2008/10/1 - revise block layout to use a static descriptor structure
-2008/10/6 - revise block layout to use an unsigned long int flags
-2008/10/28 - specify use of _Block_object_assign/dispose for all "Object" types in helper functions
-2008/10/30 - revise new layout to have invoke function in same place
-2008/10/30 - add __weak support
-
-2010/3/16 - rev for stret return, signature field
-2010/4/6 - improved wording
-
-This document describes the Apple ABI implementation specification of Blocks.
-
-The first shipping version of this ABI is found in Mac OS X 10.6, and shall be referred to as 10.6.ABI. As of 2010/3/16, the following describes the ABI contract with the runtime and the compiler, and, as necessary, will be referred to as ABI.2010.3.16.
-
-Since the Apple ABI references symbols from other elements of the system, any attempt to use this ABI on systems prior to SnowLeopard is undefined.
-
-1. High Level
-
-The ABI of blocks consist of their layout and the runtime functions required by the compiler.
-A Block consists of a structure of the following form:
-
-struct Block_literal_1 {
- void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock
- int flags;
- int reserved;
- void (*invoke)(void *, ...);
- struct Block_descriptor_1 {
- unsigned long int reserved; // NULL
- unsigned long int size; // sizeof(struct Block_literal_1)
- // optional helper functions
- void (*copy_helper)(void *dst, void *src); // IFF (1<<25)
- void (*dispose_helper)(void *src); // IFF (1<<25)
- // required ABI.2010.3.16
- const char *signature; // IFF (1<<30)
- } *descriptor;
- // imported variables
-};
-
-The following flags bits are in use thusly for a possible ABI.2010.3.16:
-
-enum {
- BLOCK_HAS_COPY_DISPOSE = (1 << 25),
- BLOCK_HAS_CTOR = (1 << 26), // helpers have C++ code
- BLOCK_IS_GLOBAL = (1 << 28),
- BLOCK_HAS_STRET = (1 << 29), // IFF BLOCK_HAS_SIGNATURE
- BLOCK_HAS_SIGNATURE = (1 << 30),
-};
-
-In 10.6.ABI the (1<<29) was usually set and was always ignored by the runtime - it had been a transitional marker that did not get deleted after the transition. This bit is now paired with (1<<30), and represented as the pair (3<<30), for the following combinations of valid bit settings, and their meanings.
-
-switch (flags & (3<<29)) {
- case (0<<29): 10.6.ABI, no signature field available
- case (1<<29): 10.6.ABI, no signature field available
- case (2<<29): ABI.2010.3.16, regular calling convention, presence of signature field
- case (3<<29): ABI.2010.3.16, stret calling convention, presence of signature field,
-}
-
-The signature field is not always populated.
-
-The following discussions are presented as 10.6.ABI otherwise.
-
-Block literals may occur within functions where the structure is created in stack local memory. They may also appear as initialization expressions for Block variables of global or static local variables.
-
-When a Block literal expression is evaluated the stack based structure is initialized as follows:
-
-1) static descriptor structure is declared and initialized as follows:
-1a) the invoke function pointer is set to a function that takes the Block structure as its first argument and the rest of the arguments (if any) to the Block and executes the Block compound statement.
-1b) the size field is set to the size of the following Block literal structure.
-1c) the copy_helper and dispose_helper function pointers are set to respective helper functions if they are required by the Block literal
-2) a stack (or global) Block literal data structure is created and initialized as follows:
-2a) the isa field is set to the address of the external _NSConcreteStackBlock, which is a block of uninitialized memory supplied in libSystem, or _NSConcreteGlobalBlock if this is a static or file level block literal.
-2) The flags field is set to zero unless there are variables imported into the block that need helper functions for program level Block_copy() and Block_release() operations, in which case the (1<<25) flags bit is set.
-
-
-As an example, the Block literal expression
- ^ { printf("hello world\n"); }
-would cause to be created on a 32-bit system:
-
-struct __block_literal_1 {
- void *isa;
- int flags;
- int reserved;
- void (*invoke)(struct __block_literal_1 *);
- struct __block_descriptor_1 *descriptor;
-};
-
-void __block_invoke_1(struct __block_literal_1 *_block) {
- printf("hello world\n");
-}
-
-static struct __block_descriptor_1 {
- unsigned long int reserved;
- unsigned long int Block_size;
-} __block_descriptor_1 = { 0, sizeof(struct __block_literal_1), __block_invoke_1 };
-
-and where the block literal appeared
-
- struct __block_literal_1 _block_literal = {
- &_NSConcreteStackBlock,
- (1<<29), <uninitialized>,
- __block_invoke_1,
- &__block_descriptor_1
- };
-
-Blocks import other Block references, const copies of other variables, and variables marked __block. In Objective-C variables may additionally be objects.
-
-When a Block literal expression used as the initial value of a global or static local variable it is initialized as follows:
- struct __block_literal_1 __block_literal_1 = {
- &_NSConcreteGlobalBlock,
- (1<<28)|(1<<29), <uninitialized>,
- __block_invoke_1,
- &__block_descriptor_1
- };
-that is, a different address is provided as the first value and a particular (1<<28) bit is set in the flags field, and otherwise it is the same as for stack based Block literals. This is an optimization that can be used for any Block literal that imports no const or __block storage variables.
-
-
-2. Imported Variables
-
-Variables of "auto" storage class are imported as const copies. Variables of "__block" storage class are imported as a pointer to an enclosing data structure. Global variables are simply referenced and not considered as imported.
-
-2.1 Imported const copy variables
-
-Automatic storage variables not marked with __block are imported as const copies.
-
-The simplest example is that of importing a variable of type int.
-
- int x = 10;
- void (^vv)(void) = ^{ printf("x is %d\n", x); }
- x = 11;
- vv();
-
-would be compiled
-
-struct __block_literal_2 {
- void *isa;
- int flags;
- int reserved;
- void (*invoke)(struct __block_literal_2 *);
- struct __block_descriptor_2 *descriptor;
- const int x;
-};
-
-void __block_invoke_2(struct __block_literal_2 *_block) {
- printf("x is %d\n", _block->x);
-}
-
-static struct __block_descriptor_2 {
- unsigned long int reserved;
- unsigned long int Block_size;
-} __block_descriptor_2 = { 0, sizeof(struct __block_literal_2) };
-
-and
-
- struct __block_literal_2 __block_literal_2 = {
- &_NSConcreteStackBlock,
- (1<<29), <uninitialized>,
- __block_invoke_2,
- &__block_descriptor_2,
- x
- };
-
-In summary, scalars, structures, unions, and function pointers are generally imported as const copies with no need for helper functions.
-
-2.2 Imported const copy of Block reference
-
-The first case where copy and dispose helper functions are required is for the case of when a block itself is imported. In this case both a copy_helper function and a dispose_helper function are needed. The copy_helper function is passed both the existing stack based pointer and the pointer to the new heap version and should call back into the runtime to actually do the copy operation on the imported fields within the block. The runtime functions are all described in Section 5.0 Runtime Helper Functions.
-
-An example:
-
- void (^existingBlock)(void) = ...;
- void (^vv)(void) = ^{ existingBlock(); }
- vv();
-
-struct __block_literal_3 {
- ...; // existing block
-};
-
-struct __block_literal_4 {
- void *isa;
- int flags;
- int reserved;
- void (*invoke)(struct __block_literal_4 *);
- struct __block_literal_3 *const existingBlock;
-};
-
-void __block_invoke_4(struct __block_literal_2 *_block) {
- __block->existingBlock->invoke(__block->existingBlock);
-}
-
-void __block_copy_4(struct __block_literal_4 *dst, struct __block_literal_4 *src) {
- //_Block_copy_assign(&dst->existingBlock, src->existingBlock, 0);
- _Block_object_assign(&dst->existingBlock, src->existingBlock, BLOCK_FIELD_IS_BLOCK);
-}
-
-void __block_dispose_4(struct __block_literal_4 *src) {
- // was _Block_destroy
- _Block_object_dispose(src->existingBlock, BLOCK_FIELD_IS_BLOCK);
-}
-
-static struct __block_descriptor_4 {
- unsigned long int reserved;
- unsigned long int Block_size;
- void (*copy_helper)(struct __block_literal_4 *dst, struct __block_literal_4 *src);
- void (*dispose_helper)(struct __block_literal_4 *);
-} __block_descriptor_4 = {
- 0,
- sizeof(struct __block_literal_4),
- __block_copy_4,
- __block_dispose_4,
-};
-
-and where it is used
-
- struct __block_literal_4 _block_literal = {
- &_NSConcreteStackBlock,
- (1<<25)|(1<<29), <uninitialized>
- __block_invoke_4,
- & __block_descriptor_4
- existingBlock,
- };
-
-2.2.1 Importing __attribute__((NSObject)) variables.
-
-GCC introduces __attribute__((NSObject)) on structure pointers to mean "this is an object". This is useful because many low level data structures are declared as opaque structure pointers, e.g. CFStringRef, CFArrayRef, etc. When used from C, however, these are still really objects and are the second case where that requires copy and dispose helper functions to be generated. The copy helper functions generated by the compiler should use the _Block_object_assign runtime helper function and in the dispose helper the _Block_object_dispose runtime helper function should be called.
-
-For example, block xyzzy in the following
-
- struct Opaque *__attribute__((NSObject)) objectPointer = ...;
- ...
- void (^xyzzy)(void) = ^{ CFPrint(objectPointer); };
-
-would have helper functions
-
-void __block_copy_xyzzy(struct __block_literal_5 *dst, struct __block_literal_5 *src) {
- _Block_object_assign(&dst->objectPointer, src-> objectPointer, BLOCK_FIELD_IS_OBJECT);
-}
-
-void __block_dispose_xyzzy(struct __block_literal_5 *src) {
- _Block_object_dispose(src->objectPointer, BLOCK_FIELD_IS_OBJECT);
-}
-
-generated.
-
-
-2.3 Imported __block marked variables.
-
-2.3.1 Layout of __block marked variables
-
-The compiler must embed variables that are marked __block in a specialized structure of the form:
-
-struct _block_byref_xxxx {
- void *isa;
- struct Block_byref *forwarding;
- int flags; //refcount;
- int size;
- typeof(marked_variable) marked_variable;
-};
-
-Variables of certain types require helper functions for when Block_copy() and Block_release() are performed upon a referencing Block. At the "C" level only variables that are of type Block or ones that have __attribute__((NSObject)) marked require helper functions. In Objective-C objects require helper functions and in C++ stack based objects require helper functions. Variables that require helper functions use the form:
-
-struct _block_byref_xxxx {
- void *isa;
- struct _block_byref_xxxx *forwarding;
- int flags; //refcount;
- int size;
- // helper functions called via Block_copy() and Block_release()
- void (*byref_keep)(void *dst, void *src);
- void (*byref_dispose)(void *);
- typeof(marked_variable) marked_variable;
-};
-
-The structure is initialized such that
- a) the forwarding pointer is set to the beginning of its enclosing structure,
- b) the size field is initialized to the total size of the enclosing structure,
- c) the flags field is set to either 0 if no helper functions are needed or (1<<25) if they are,
- d) the helper functions are initialized (if present)
- e) the variable itself is set to its initial value.
- f) the isa field is set to NULL
-
-2.3.2 Access to __block variables from within its lexical scope.
-
-In order to "move" the variable to the heap upon a copy_helper operation the compiler must rewrite access to such a variable to be indirect through the structures forwarding pointer. For example:
-
- int __block i = 10;
- i = 11;
-
-would be rewritten to be:
-
- struct _block_byref_i {
- void *isa;
- struct _block_byref_i *forwarding;
- int flags; //refcount;
- int size;
- int captured_i;
- } i = { NULL, &i, 0, sizeof(struct _block_byref_i), 10 };
-
- i.forwarding->captured_i = 11;
-
-In the case of a Block reference variable being marked __block the helper code generated must use the _Block_object_assign and _Block_object_dispose routines supplied by the runtime to make the copies. For example:
-
- __block void (voidBlock)(void) = blockA;
- voidBlock = blockB;
-
-would translate into
-
-struct _block_byref_voidBlock {
- void *isa;
- struct _block_byref_voidBlock *forwarding;
- int flags; //refcount;
- int size;
- void (*byref_keep)(struct _block_byref_voidBlock *dst, struct _block_byref_voidBlock *src);
- void (*byref_dispose)(struct _block_byref_voidBlock *);
- void (^captured_voidBlock)(void);
-};
-
-void _block_byref_keep_helper(struct _block_byref_voidBlock *dst, struct _block_byref_voidBlock *src) {
- //_Block_copy_assign(&dst->captured_voidBlock, src->captured_voidBlock, 0);
- _Block_object_assign(&dst->captured_voidBlock, src->captured_voidBlock, BLOCK_FIELD_IS_BLOCK | BLOCK_BYREF_CALLER);
-}
-
-void _block_byref_dispose_helper(struct _block_byref_voidBlock *param) {
- //_Block_destroy(param->captured_voidBlock, 0);
- _Block_object_dispose(param->captured_voidBlock, BLOCK_FIELD_IS_BLOCK | BLOCK_BYREF_CALLER)}
-
-and
- struct _block_byref_voidBlock voidBlock = {( .forwarding=&voidBlock, .flags=(1<<25), .size=sizeof(struct _block_byref_voidBlock *),
- .byref_keep=_block_byref_keep_helper, .byref_dispose=_block_byref_dispose_helper,
- .captured_voidBlock=blockA )};
-
- voidBlock.forwarding->captured_voidBlock = blockB;
-
-
-2.3.3 Importing __block variables into Blocks
-
-A Block that uses a __block variable in its compound statement body must import the variable and emit copy_helper and dispose_helper helper functions that, in turn, call back into the runtime to actually copy or release the byref data block using the functions _Block_object_assign and _Block_object_dispose.
-
-For example:
-
- int __block i = 2;
- functioncall(^{ i = 10; });
-
-would translate to
-
-struct _block_byref_i {
- void *isa; // set to NULL
- struct _block_byref_voidBlock *forwarding;
- int flags; //refcount;
- int size;
- void (*byref_keep)(struct _block_byref_i *dst, struct _block_byref_i *src);
- void (*byref_dispose)(struct _block_byref_i *);
- int captured_i;
-};
-
-
-struct __block_literal_5 {
- void *isa;
- int flags;
- int reserved;
- void (*invoke)(struct __block_literal_5 *);
- struct __block_descriptor_5 *descriptor;
- struct _block_byref_i *i_holder;
-};
-
-void __block_invoke_5(struct __block_literal_5 *_block) {
- _block->forwarding->captured_i = 10;
-}
-
-void __block_copy_5(struct __block_literal_5 *dst, struct __block_literal_5 *src) {
- //_Block_byref_assign_copy(&dst->captured_i, src->captured_i);
- _Block_object_assign(&dst->captured_i, src->captured_i, BLOCK_FIELD_IS_BYREF | BLOCK_BYREF_CALLER);
-}
-
-void __block_dispose_5(struct __block_literal_5 *src) {
- //_Block_byref_release(src->captured_i);
- _Block_object_dispose(src->captured_i, BLOCK_FIELD_IS_BYREF | BLOCK_BYREF_CALLER);
-}
-
-static struct __block_descriptor_5 {
- unsigned long int reserved;
- unsigned long int Block_size;
- void (*copy_helper)(struct __block_literal_5 *dst, struct __block_literal_5 *src);
- void (*dispose_helper)(struct __block_literal_5 *);
-} __block_descriptor_5 = { 0, sizeof(struct __block_literal_5) __block_copy_5, __block_dispose_5 };
-
-and
-
- struct _block_byref_i i = {( .forwarding=&i, .flags=0, .size=sizeof(struct _block_byref_i) )};
- struct __block_literal_5 _block_literal = {
- &_NSConcreteStackBlock,
- (1<<25)|(1<<29), <uninitialized>,
- __block_invoke_5,
- &__block_descriptor_5,
- 2,
- };
-
-2.3.4 Importing __attribute__((NSObject)) __block variables
-
-A __block variable that is also marked __attribute__((NSObject)) should have byref_keep and byref_dispose helper functions that use _Block_object_assign and _Block_object_dispose.
-
-2.3.5 __block escapes
-
-Because Blocks referencing __block variables may have Block_copy() performed upon them the underlying storage for the variables may move to the heap. In Objective-C Garbage Collection Only compilation environments the heap used is the garbage collected one and no further action is required. Otherwise the compiler must issue a call to potentially release any heap storage for __block variables at all escapes or terminations of their scope. The call should be:
-
- _Block_object_dispose(&_block_byref_xxx, BLOCK_FIELD_IS_BYREF);
-
-
-2.3.6 Nesting
-
-Blocks may contain Block literal expressions. Any variables used within inner blocks are imported into all enclosing Block scopes even if the variables are not used. This includes const imports as well as __block variables.
-
-3. Objective C Extensions to Blocks
-
-3.1 Importing Objects
-
-Objects should be treated as __attribute__((NSObject)) variables; all copy_helper, dispose_helper, byref_keep, and byref_dispose helper functions should use _Block_object_assign and _Block_object_dispose. There should be no code generated that uses -retain or -release methods.
-
-
-3.2 Blocks as Objects
-
-The compiler will treat Blocks as objects when synthesizing property setters and getters, will characterize them as objects when generating garbage collection strong and weak layout information in the same manner as objects, and will issue strong and weak write-barrier assignments in the same manner as objects.
-
-3.3 __weak __block Support
-
-Objective-C (and Objective-C++) support the __weak attribute on __block variables. Under normal circumstances the compiler uses the Objective-C runtime helper support functions objc_assign_weak and objc_read_weak. Both should continue to be used for all reads and writes of __weak __block variables:
- objc_read_weak(&block->byref_i->forwarding->i)
-
-The __weak variable is stored in a _block_byref_xxxx structure and the Block has copy and dispose helpers for this structure that call:
- _Block_object_assign(&dest->_block_byref_i, src-> _block_byref_i, BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_BYREF);
-and
- _Block_object_dispose(src->_block_byref_i, BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_BYREF);
-
-
-In turn, the block_byref copy support helpers distinguish between whether the __block variable is a Block or not and should either call:
- _Block_object_assign(&dest->_block_byref_i, src->_block_byref_i, BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_OBJECT | BLOCK_BYREF_CALLER);
-for something declared as an object or
- _Block_object_assign(&dest->_block_byref_i, src->_block_byref_i, BLOCK_FIELD_IS_WEAK | BLOCK_FIELD_IS_BLOCK | BLOCK_BYREF_CALLER);
-for something declared as a Block.
-
-A full example follows:
-
-
- __block __weak id obj = <initialization expression>;
- functioncall(^{ [obj somemessage]; });
-
-would translate to
-
-struct _block_byref_obj {
- void *isa; // uninitialized
- struct _block_byref_obj *forwarding;
- int flags; //refcount;
- int size;
- void (*byref_keep)(struct _block_byref_i *dst, struct _block_byref_i *src);
- void (*byref_dispose)(struct _block_byref_i *);
- id captured_obj;
-};
-
-void _block_byref_obj_keep(struct _block_byref_voidBlock *dst, struct _block_byref_voidBlock *src) {
- //_Block_copy_assign(&dst->captured_obj, src->captured_obj, 0);
- _Block_object_assign(&dst->captured_obj, src->captured_obj, BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_WEAK | BLOCK_BYREF_CALLER);
-}
-
-void _block_byref_obj_dispose(struct _block_byref_voidBlock *param) {
- //_Block_destroy(param->captured_obj, 0);
- _Block_object_dispose(param->captured_obj, BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_WEAK | BLOCK_BYREF_CALLER);
-};
-
-for the block byref part and
-
-struct __block_literal_5 {
- void *isa;
- int flags;
- int reserved;
- void (*invoke)(struct __block_literal_5 *);
- struct __block_descriptor_5 *descriptor;
- struct _block_byref_obj *byref_obj;
-};
-
-void __block_invoke_5(struct __block_literal_5 *_block) {
- [objc_read_weak(&_block->byref_obj->forwarding->captured_obj) somemessage];
-}
-
-void __block_copy_5(struct __block_literal_5 *dst, struct __block_literal_5 *src) {
- //_Block_byref_assign_copy(&dst->byref_obj, src->byref_obj);
- _Block_object_assign(&dst->byref_obj, src->byref_obj, BLOCK_FIELD_IS_BYREF | BLOCK_FIELD_IS_WEAK);
-}
-
-void __block_dispose_5(struct __block_literal_5 *src) {
- //_Block_byref_release(src->byref_obj);
- _Block_object_dispose(src->byref_obj, BLOCK_FIELD_IS_BYREF | BLOCK_FIELD_IS_WEAK);
-}
-
-static struct __block_descriptor_5 {
- unsigned long int reserved;
- unsigned long int Block_size;
- void (*copy_helper)(struct __block_literal_5 *dst, struct __block_literal_5 *src);
- void (*dispose_helper)(struct __block_literal_5 *);
-} __block_descriptor_5 = { 0, sizeof(struct __block_literal_5), __block_copy_5, __block_dispose_5 };
-
-and within the compound statement:
-
- struct _block_byref_obj obj = {( .forwarding=&obj, .flags=(1<<25), .size=sizeof(struct _block_byref_obj),
- .byref_keep=_block_byref_obj_keep, .byref_dispose=_block_byref_obj_dispose,
- .captured_obj = <initialization expression> )};
-
- struct __block_literal_5 _block_literal = {
- &_NSConcreteStackBlock,
- (1<<25)|(1<<29), <uninitialized>,
- __block_invoke_5,
- &__block_descriptor_5,
- &obj, // a reference to the on-stack structure containing "captured_obj"
- };
-
-
- functioncall(_block_literal->invoke(&_block_literal));
-
-
-4.0 C++ Support
-
-Within a block stack based C++ objects are copied into const copies using the copy constructor. It is an error if a stack based C++ object is used within a block if it does not have a copy constructor. In addition both copy and destroy helper routines must be synthesized for the block to support the Block_copy() operation, and the flags work marked with the (1<<26) bit in addition to the (1<<25) bit. The copy helper should call the constructor using appropriate offsets of the variable within the supplied stack based block source and heap based destination for all const constructed copies, and similarly should call the destructor in the destroy routine.
-
-As an example, suppose a C++ class FOO existed with a copy constructor. Within a code block a stack version of a FOO object is declared and used within a Block literal expression:
-
-{
- FOO foo;
- void (^block)(void) = ^{ printf("%d\n", foo.value()); };
-}
-
-The compiler would synthesize
-
-struct __block_literal_10 {
- void *isa;
- int flags;
- int reserved;
- void (*invoke)(struct __block_literal_10 *);
- struct __block_descriptor_10 *descriptor;
- const FOO foo;
-};
-
-void __block_invoke_10(struct __block_literal_10 *_block) {
- printf("%d\n", _block->foo.value());
-}
-
-void __block_literal_10(struct __block_literal_10 *dst, struct __block_literal_10 *src) {
- FOO_ctor(&dst->foo, &src->foo);
-}
-
-void __block_dispose_10(struct __block_literal_10 *src) {
- FOO_dtor(&src->foo);
-}
-
-static struct __block_descriptor_10 {
- unsigned long int reserved;
- unsigned long int Block_size;
- void (*copy_helper)(struct __block_literal_10 *dst, struct __block_literal_10 *src);
- void (*dispose_helper)(struct __block_literal_10 *);
-} __block_descriptor_10 = { 0, sizeof(struct __block_literal_10), __block_copy_10, __block_dispose_10 };
-
-and the code would be:
-{
- FOO foo;
- comp_ctor(&foo); // default constructor
- struct __block_literal_10 _block_literal = {
- &_NSConcreteStackBlock,
- (1<<25)|(1<<26)|(1<<29), <uninitialized>,
- __block_invoke_10,
- &__block_descriptor_10,
- };
- comp_ctor(&_block_literal->foo, &foo); // const copy into stack version
- struct __block_literal_10 &block = &_block_literal; // assign literal to block variable
- block->invoke(block); // invoke block
- comp_dtor(&_block_literal->foo); // destroy stack version of const block copy
- comp_dtor(&foo); // destroy original version
-}
-
-
-C++ objects stored in __block storage start out on the stack in a block_byref data structure as do other variables. Such objects (if not const objects) must support a regular copy constructor. The block_byref data structure will have copy and destroy helper routines synthesized by the compiler. The copy helper will have code created to perform the copy constructor based on the initial stack block_byref data structure, and will also set the (1<<26) bit in addition to the (1<<25) bit. The destroy helper will have code to do the destructor on the object stored within the supplied block_byref heap data structure. For example,
-
- __block FOO blockStorageFoo;
-
-requires the normal constructor for the embedded blockStorageFoo object
-
- FOO_ctor(& _block_byref_blockStorageFoo->blockStorageFoo);
-
-and at scope termination the destructor:
-
- FOO_dtor(& _block_byref_blockStorageFoo->blockStorageFoo);
-
-Note that the forwarding indirection is NOT used.
-
-The compiler would need to generate (if used from a block literal) the following copy/dispose helpers:
-
-void _block_byref_obj_keep(struct _block_byref_blockStorageFoo *dst, struct _block_byref_blockStorageFoo *src) {
- FOO_ctor(&dst->blockStorageFoo, &src->blockStorageFoo);
-}
-
-void _block_byref_obj_dispose(struct _block_byref_blockStorageFoo *src) {
- FOO_dtor(&src->blockStorageFoo);
-}
-
-for the appropriately named constructor and destructor for the class/struct FOO.
-
-To support member variable and function access the compiler will synthesize a const pointer to a block version of the "this" pointer.
-
-5.0 Runtime Helper Functions
-
-The runtime helper functions are described in /usr/local/include/Block_private.h. To summarize their use, a block requires copy/dispose helpers if it imports any block variables, __block storage variables, __attribute__((NSObject)) variables, or C++ const copied objects with constructor/destructors. The (1<<26) bit is set and functions are generated.
-
-The block copy helper function should, for each of the variables of the type mentioned above, call
- _Block_object_assign(&dst->target, src->target, BLOCK_FIELD_<appropo>);
-in the copy helper and
- _Block_object_dispose(->target, BLOCK_FIELD_<appropo>);
-in the dispose helper where
- <appropo> is
-
-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
-
- BLOCK_BYREF_CALLER = 128, // called from byref copy/dispose helpers
-};
-
-and of course the CTORs/DTORs for const copied C++ objects.
-
-The block_byref data structure similarly requires copy/dispose helpers for block variables, __attribute__((NSObject)) variables, or C++ const copied objects with constructor/destructors, and again the (1<<26) bit is set and functions are generated in the same manner.
-
-Under ObjC we allow __weak as an attribute on __block variables, and this causes the addition of BLOCK_FIELD_IS_WEAK orred onto the BLOCK_FIELD_IS_BYREF flag when copying the block_byref structure in the block copy helper, and onto the BLOCK_FIELD_<appropo> field within the block_byref copy/dispose helper calls.
-
-The prototypes, and summary, of the helper functions are
-
-/* Certain field types require runtime assistance when being copied to the heap. The following function is used
- to copy fields of types: blocks, pointers to byref structures, and objects (including __attribute__((NSObject)) pointers.
- BLOCK_FIELD_IS_WEAK is orthogonal to the other choices which are mutually exclusive.
- Only in a Block copy helper will one see BLOCK_FIELD_IS_BYREF.
- */
-void _Block_object_assign(void *destAddr, const void *object, const int flags);
-
-/* Similarly a compiler generated dispose helper needs to call back for each field of the byref data structure.
- (Currently the implementation only packs one field into the byref structure but in principle there could be more).
- The same flags used in the copy helper should be used for each call generated to this function:
- */
-void _Block_object_dispose(const void *object, const int flags);
+*NOTE* This document has moved to http://clang.llvm.org/docs/Block-ABI-Apple.html.
diff --git a/docs/BlockLanguageSpec.rst b/docs/BlockLanguageSpec.rst
new file mode 100644
index 0000000..3632d56
--- /dev/null
+++ b/docs/BlockLanguageSpec.rst
@@ -0,0 +1,361 @@
+
+.. role:: block-term
+
+=================================
+Language Specification for Blocks
+=================================
+
+.. contents::
+ :local:
+
+Revisions
+=========
+
+- 2008/2/25 --- created
+- 2008/7/28 --- revised, ``__block`` syntax
+- 2008/8/13 --- revised, Block globals
+- 2008/8/21 --- revised, C++ elaboration
+- 2008/11/1 --- revised, ``__weak`` support
+- 2009/1/12 --- revised, explicit return types
+- 2009/2/10 --- revised, ``__block`` objects need retain
+
+Overview
+========
+
+A new derived type is introduced to C and, by extension, Objective-C,
+C++, and Objective-C++
+
+The Block Type
+==============
+
+Like function types, the :block-term:`Block type` is a pair consisting
+of a result value type and a list of parameter types very similar to a
+function type. Blocks are intended to be used much like functions with
+the key distinction being that in addition to executable code they
+also contain various variable bindings to automatic (stack) or managed
+(heap) memory.
+
+The abstract declarator,
+
+.. code-block:: c
+
+ int (^)(char, float)
+
+describes a reference to a Block that, when invoked, takes two
+parameters, the first of type char and the second of type float, and
+returns a value of type int. The Block referenced is of opaque data
+that may reside in automatic (stack) memory, global memory, or heap
+memory.
+
+Block Variable Declarations
+===========================
+
+A :block-term:`variable with Block type` is declared using function
+pointer style notation substituting ``^`` for ``*``. The following are
+valid Block variable declarations:
+
+.. code-block:: c
+
+ void (^blockReturningVoidWithVoidArgument)(void);
+ int (^blockReturningIntWithIntAndCharArguments)(int, char);
+ void (^arrayOfTenBlocksReturningVoidWithIntArgument[10])(int);
+
+Variadic ``...`` arguments are supported. [variadic.c] A Block that
+takes no arguments must specify void in the argument list [voidarg.c].
+An empty parameter list does not represent, as K&R provide, an
+unspecified argument list. Note: both gcc and clang support K&R style
+as a convenience.
+
+A Block reference may be cast to a pointer of arbitrary type and vice
+versa. [cast.c] A Block reference may not be dereferenced via the
+pointer dereference operator ``*``, and thus a Block's size may not be
+computed at compile time. [sizeof.c]
+
+Block Literal Expressions
+=========================
+
+A :block-term:`Block literal expression` produces a reference to a
+Block. It is introduced by the use of the ``^`` token as a unary
+operator.
+
+.. code-block:: c
+
+ Block_literal_expression ::= ^ block_decl compound_statement_body
+ block_decl ::=
+ block_decl ::= parameter_list
+ block_decl ::= type_expression
+
+where type expression is extended to allow ``^`` as a Block reference
+(pointer) where ``*`` is allowed as a function reference (pointer).
+
+The following Block literal:
+
+.. code-block:: c
+
+ ^ void (void) { printf("hello world\n"); }
+
+produces a reference to a Block with no arguments with no return value.
+
+The return type is optional and is inferred from the return
+statements. If the return statements return a value, they all must
+return a value of the same type. If there is no value returned the
+inferred type of the Block is void; otherwise it is the type of the
+return statement value.
+
+If the return type is omitted and the argument list is ``( void )``,
+the ``( void )`` argument list may also be omitted.
+
+So:
+
+.. code-block:: c
+
+ ^ ( void ) { printf("hello world\n"); }
+
+and:
+
+.. code-block:: c
+
+ ^ { printf("hello world\n"); }
+
+are exactly equivalent constructs for the same expression.
+
+The type_expression extends C expression parsing to accommodate Block
+reference declarations as it accommodates function pointer
+declarations.
+
+Given:
+
+.. code-block:: c
+
+ typedef int (*pointerToFunctionThatReturnsIntWithCharArg)(char);
+ pointerToFunctionThatReturnsIntWithCharArg functionPointer;
+ ^ pointerToFunctionThatReturnsIntWithCharArg (float x) { return functionPointer; }
+
+and:
+
+.. code-block:: c
+
+ ^ int ((*)(float x))(char) { return functionPointer; }
+
+are equivalent expressions, as is:
+
+.. code-block:: c
+
+ ^(float x) { return functionPointer; }
+
+[returnfunctionptr.c]
+
+The compound statement body establishes a new lexical scope within
+that of its parent. Variables used within the scope of the compound
+statement are bound to the Block in the normal manner with the
+exception of those in automatic (stack) storage. Thus one may access
+functions and global variables as one would expect, as well as static
+local variables. [testme]
+
+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:
+
+.. code-block:: c
+
+ (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.
+
+A Block literal expression may be used as the initialization value for
+Block variables at global or local static scope.
+
+The Invoke Operator
+===================
+
+Blocks are :block-term:`invoked` using function call syntax with a
+list of expression parameters of types corresponding to the
+declaration and returning a result type also according to the
+declaration. Given:
+
+.. code-block:: c
+
+ int (^x)(char);
+ void (^z)(void);
+ int (^(*y))(char) = &x;
+
+the following are all legal Block invocations:
+
+.. code-block:: c
+
+ x('a');
+ (*y)('a');
+ (true ? x : *y)('a')
+
+The Copy and Release Operations
+===============================
+
+The compiler and runtime provide :block-term:`copy` and
+:block-term:`release` operations for Block references that create and,
+in matched use, release allocated storage for referenced Blocks.
+
+The copy operation ``Block_copy()`` is styled as a function that takes
+an arbitrary Block reference and returns a Block reference of the same
+type. The release operation, ``Block_release()``, is styled as a
+function that takes an arbitrary Block reference and, if dynamically
+matched to a Block copy operation, allows recovery of the referenced
+allocated memory.
+
+
+The ``__block`` Storage Qualifier
+=================================
+
+In addition to the new Block type we also introduce a new storage
+qualifier, :block-term:`__block`, for local variables. [testme: a
+__block declaration within a block literal] The ``__block`` storage
+qualifier is mutually exclusive to the existing local storage
+qualifiers auto, register, and static. [testme] Variables qualified by
+``__block`` act as if they were in allocated storage and this storage
+is automatically recovered after last use of said variable. An
+implementation may choose an optimization where the storage is
+initially automatic and only "moved" to allocated (heap) storage upon
+a Block_copy of a referencing Block. Such variables may be mutated as
+normal variables are.
+
+In the case where a ``__block`` variable is a Block one must assume
+that the ``__block`` variable resides in allocated storage and as such
+is assumed to reference a Block that is also in allocated storage
+(that it is the result of a ``Block_copy`` operation). Despite this
+there is no provision to do a ``Block_copy`` or a ``Block_release`` if
+an implementation provides initial automatic storage for Blocks. This
+is due to the inherent race condition of potentially several threads
+trying to update the shared variable and the need for synchronization
+around disposing of older values and copying new ones. Such
+synchronization is beyond the scope of this language specification.
+
+
+Control Flow
+============
+
+The compound statement of a Block is treated much like a function body
+with respect to control flow in that goto, break, and continue do not
+escape the Block. Exceptions are treated *normally* in that when
+thrown they pop stack frames until a catch clause is found.
+
+
+Objective-C Extensions
+======================
+
+Objective-C extends the definition of a Block reference type to be
+that also of id. A variable or expression of Block type may be
+messaged or used as a parameter wherever an id may be. The converse is
+also true. Block references may thus appear as properties and are
+subject to the assign, retain, and copy attribute logic that is
+reserved for objects.
+
+All Blocks are constructed to be Objective-C objects regardless of
+whether the Objective-C runtime is operational in the program or
+not. Blocks using automatic (stack) memory are objects and may be
+messaged, although they may not be assigned into ``__weak`` locations
+if garbage collection is enabled.
+
+Within a Block literal expression within a method definition
+references to instance variables are also imported into the lexical
+scope of the compound statement. These variables are implicitly
+qualified as references from self, and so self is imported as a const
+copy. The net effect is that instance variables can be mutated.
+
+The :block-term:`Block_copy` operator retains all objects held in
+variables of automatic storage referenced within the Block expression
+(or form strong references if running under garbage collection).
+Object variables of ``__block`` storage type are assumed to hold
+normal pointers with no provision for retain and release messages.
+
+Foundation defines (and supplies) ``-copy`` and ``-release`` methods for
+Blocks.
+
+In the Objective-C and Objective-C++ languages, we allow the
+``__weak`` specifier for ``__block`` variables of object type. If
+garbage collection is not enabled, this qualifier causes these
+variables to be kept without retain messages being sent. This
+knowingly leads to dangling pointers if the Block (or a copy) outlives
+the lifetime of this object.
+
+In garbage collected environments, the ``__weak`` variable is set to
+nil when the object it references is collected, as long as the
+``__block`` variable resides in the heap (either by default or via
+``Block_copy()``). The initial Apple implementation does in fact
+start ``__block`` variables on the stack and migrate them to the heap
+only as a result of a ``Block_copy()`` operation.
+
+It is a runtime error to attempt to assign a reference to a
+stack-based Block into any storage marked ``__weak``, including
+``__weak`` ``__block`` variables.
+
+
+C++ Extensions
+==============
+
+Block literal expressions within functions are extended to allow const
+use of C++ objects, pointers, or references held in automatic storage.
+
+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:
+
+.. code-block:: c
+
+ Foo foo;
+ Foo &fooRef = foo;
+ Foo *fooPtr = &foo;
+
+A Block that referenced these variables would import the variables as
+const variations:
+
+.. code-block:: c
+
+ const Foo block_foo = foo;
+ Foo &block_fooRef = fooRef;
+ Foo *const block_fooPtr = fooPtr;
+
+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.
+
+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, ``__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.
+
+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/BlockLanguageSpec.txt b/docs/BlockLanguageSpec.txt
deleted file mode 100644
index 4cdf75a..0000000
--- a/docs/BlockLanguageSpec.txt
+++ /dev/null
@@ -1,171 +0,0 @@
-Language Specification for Blocks
-
-2008/2/25 — created
-2008/7/28 — revised, __block syntax
-2008/8/13 — revised, Block globals
-2008/8/21 — revised, C++ elaboration
-2008/11/1 — revised, __weak support
-2009/1/12 — revised, explicit return types
-2009/2/10 — revised, __block objects need retain
-
-Copyright 2008-2009 Apple, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-The Block Type
-
-A new derived type is introduced to C and, by extension, Objective-C, C++, and Objective-C++. Like function types, the Block type is a pair consisting of a result value type and a list of parameter types very similar to a function type. Blocks are intended to be used much like functions with the key distinction being that in addition to executable code they also contain various variable bindings to automatic (stack) or managed (heap) memory.
-
-The abstract declarator int (^)(char, float) describes a reference to a Block that, when invoked, takes two parameters, the first of type char and the second of type float, and returns a value of type int. The Block referenced is of opaque data that may reside in automatic (stack) memory, global memory, or heap memory.
-
-
-Block Variable Declarations
-
-A variable with Block type is declared using function pointer style notation substituting ^ for *. The following are valid Block variable declarations:
- void (^blockReturningVoidWithVoidArgument)(void);
- int (^blockReturningIntWithIntAndCharArguments)(int, char);
- void (^arrayOfTenBlocksReturningVoidWithIntArgument[10])(int);
-
-Variadic ... arguments are supported. [variadic.c] A Block that takes no arguments must specify void in the argument list [voidarg.c]. An empty parameter list does not represent, as K&R provide, an unspecified argument list. Note: both gcc and clang support K&R style as a convenience.
-
-A Block reference may be cast to a pointer of arbitrary type and vice versa. [cast.c] A Block reference may not be dereferenced via the pointer dereference operator *, and thus a Block's size may not be computed at compile time. [sizeof.c]
-
-
-Block Literal Expressions
-
-A Block literal expression produces a reference to a Block. It is introduced by the use of the ^ token as a unary operator.
- Block_literal_expression ::= ^ block_decl compound_statement_body
- block_decl ::=
- block_decl ::= parameter_list
- block_decl ::= type_expression
-
-...where type expression is extended to allow ^ as a Block reference (pointer) where * is allowed as a function reference (pointer).
-
-The following Block literal:
- ^ void (void) { printf("hello world\n"); }
-
-...produces a reference to a Block with no arguments with no return value.
-
-The return type is optional and is inferred from the return statements. If the return statements return a value, they all must return a value of the same type. If there is no value returned the inferred type of the Block is void; otherwise it is the type of the return statement value.
-
-If the return type is omitted and the argument list is ( void ), the ( void ) argument list may also be omitted.
-
-So:
- ^ ( void ) { printf("hello world\n"); }
-
-...and:
- ^ { printf("hello world\n"); }
-
-...are exactly equivalent constructs for the same expression.
-
-The type_expression extends C expression parsing to accommodate Block reference declarations as it accommodates function pointer declarations.
-
-Given:
- typedef int (*pointerToFunctionThatReturnsIntWithCharArg)(char);
- pointerToFunctionThatReturnsIntWithCharArg functionPointer;
-
- ^ pointerToFunctionThatReturnsIntWithCharArg (float x) { return functionPointer; }
-
-...and:
- ^ int ((*)(float x))(char) { return functionPointer; }
-
-...are equivalent expressions, as is:
-
- ^(float x) { return functionPointer; }
-
-[returnfunctionptr.c]
-
-The compound statement body establishes a new lexical scope within that of its parent. Variables used within the scope of the compound statement are bound to the Block in the normal manner with the exception of those in automatic (stack) storage. Thus one may access functions and global variables as one would expect, as well as static local variables. [testme]
-
-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.
-
-A Block literal expression may be used as the initialization value for Block variables at global or local static scope.
-
-
-The Invoke Operator
-
-Blocks are invoked using function call syntax with a list of expression parameters of types corresponding to the declaration and returning a result type also according to the declaration. Given:
- int (^x)(char);
- void (^z)(void);
- int (^(*y))(char) = &x;
-
-...the following are all legal Block invocations:
- x('a');
- (*y)('a');
- (true ? x : *y)('a')
-
-
-The Copy and Release Operations
-
-The compiler and runtime provide copy and release operations for Block references that create and, in matched use, release allocated storage for referenced Blocks.
-
-The copy operation Block_copy() is styled as a function that takes an arbitrary Block reference and returns a Block reference of the same type. The release operation, Block_release(), is styled as a function that takes an arbitrary Block reference and, if dynamically matched to a Block copy operation, allows recovery of the referenced allocated memory.
-
-
-The __block Storage Qualifier
-
-In addition to the new Block type we also introduce a new storage qualifier, __block, for local variables. [testme: a __block declaration within a block literal] The __block storage qualifier is mutually exclusive to the existing local storage qualifiers auto, register, and static.[testme] Variables qualified by __block act as if they were in allocated storage and this storage is automatically recovered after last use of said variable. An implementation may choose an optimization where the storage is initially automatic and only "moved" to allocated (heap) storage upon a Block_copy of a referencing Block. Such variables may be mutated as normal variables are.
-
-In the case where a __block variable is a Block one must assume that the __block variable resides in allocated storage and as such is assumed to reference a Block that is also in allocated storage (that it is the result of a Block_copy operation). Despite this there is no provision to do a Block_copy or a Block_release if an implementation provides initial automatic storage for Blocks. This is due to the inherent race condition of potentially several threads trying to update the shared variable and the need for synchronization around disposing of older values and copying new ones. Such synchronization is beyond the scope of this language specification.
-
-
-Control Flow
-
-The compound statement of a Block is treated much like a function body with respect to control flow in that goto, break, and continue do not escape the Block. Exceptions are treated "normally" in that when thrown they pop stack frames until a catch clause is found.
-
-
-Objective-C Extensions
-
-Objective-C extends the definition of a Block reference type to be that also of id. A variable or expression of Block type may be messaged or used as a parameter wherever an id may be. The converse is also true. Block references may thus appear as properties and are subject to the assign, retain, and copy attribute logic that is reserved for objects.
-
-All Blocks are constructed to be Objective-C objects regardless of whether the Objective-C runtime is operational in the program or not. Blocks using automatic (stack) memory are objects and may be messaged, although they may not be assigned into __weak locations if garbage collection is enabled.
-
-Within a Block literal expression within a method definition references to instance variables are also imported into the lexical scope of the compound statement. These variables are implicitly qualified as references from self, and so self is imported as a const copy. The net effect is that instance variables can be mutated.
-
-The Block_copy operator retains all objects held in variables of automatic storage referenced within the Block expression (or form strong references if running under garbage collection). Object variables of __block storage type are assumed to hold normal pointers with no provision for retain and release messages.
-
-Foundation defines (and supplies) -copy and -release methods for Blocks.
-
-In the Objective-C and Objective-C++ languages, we allow the __weak specifier for __block variables of object type. If garbage collection is not enabled, this qualifier causes these variables to be kept without retain messages being sent. This knowingly leads to dangling pointers if the Block (or a copy) outlives the lifetime of this object.
-
-In garbage collected environments, the __weak variable is set to nil when the object it references is collected, as long as the __block variable resides in the heap (either by default or via Block_copy()). The initial Apple implementation does in fact start __block variables on the stack and migrate them to the heap only as a result of a Block_copy() operation.
-
-It is a runtime error to attempt to assign a reference to a stack-based Block into any storage marked __weak, including __weak __block variables.
-
-
-C++ Extensions
-
-Block literal expressions within functions are extended to allow const use of C++ objects, pointers, or references held in automatic storage.
-
-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 referenced these variables would import the variables as const variations:
- const Foo block_foo = foo;
- Foo &block_fooRef = fooRef;
- Foo *const block_fooPtr = fooPtr;
-
-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.
-
-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, __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.
-
-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/ClangCheck.rst b/docs/ClangCheck.rst
new file mode 100644
index 0000000..4650049
--- /dev/null
+++ b/docs/ClangCheck.rst
@@ -0,0 +1,36 @@
+==========
+ClangCheck
+==========
+
+`ClangCheck` is a small wrapper around :doc:`LibTooling` which can be used to
+do basic error checking and AST dumping.
+
+.. code-block:: console
+
+ $ cat <<EOF > snippet.cc
+ > void f() {
+ > int a = 0
+ > }
+ > EOF
+ $ ~/clang/build/bin/clang-check snippet.cc -ast-dump --
+ Processing: /Users/danieljasper/clang/llvm/tools/clang/docs/snippet.cc.
+ /Users/danieljasper/clang/llvm/tools/clang/docs/snippet.cc:2:12: error: expected ';' at end of
+ declaration
+ int a = 0
+ ^
+ ;
+ (TranslationUnitDecl 0x7ff3a3029ed0 <<invalid sloc>>
+ (TypedefDecl 0x7ff3a302a410 <<invalid sloc>> __int128_t '__int128')
+ (TypedefDecl 0x7ff3a302a470 <<invalid sloc>> __uint128_t 'unsigned __int128')
+ (TypedefDecl 0x7ff3a302a830 <<invalid sloc>> __builtin_va_list '__va_list_tag [1]')
+ (FunctionDecl 0x7ff3a302a8d0 </Users/danieljasper/clang/llvm/tools/clang/docs/snippet.cc:1:1, line:3:1> f 'void (void)'
+ (CompoundStmt 0x7ff3a302aa10 <line:1:10, line:3:1>
+ (DeclStmt 0x7ff3a302a9f8 <line:2:3, line:3:1>
+ (VarDecl 0x7ff3a302a980 <line:2:3, col:11> a 'int'
+ (IntegerLiteral 0x7ff3a302a9d8 <col:11> 'int' 0))))))
+ 1 error generated.
+ Error while processing snippet.cc.
+
+The '--' at the end is important as it prevents `clang-check` from search for a
+compilation database. For more information on how to setup and use `clang-check`
+in a project, see :doc:`HowToSetupToolingForLLVM`.
diff --git a/docs/ClangFormat.rst b/docs/ClangFormat.rst
new file mode 100644
index 0000000..92d7fc3
--- /dev/null
+++ b/docs/ClangFormat.rst
@@ -0,0 +1,93 @@
+===========
+ClangFormat
+===========
+
+`ClangFormat` describes a set of tools that are built on top of
+:doc:`LibFormat`. It can support your workflow in a variety of ways including a
+standalone tool and editor integrations.
+
+
+Standalone Tool
+===============
+
+:program:`clang-format` is located in `clang/tools/clang-format` and can be used
+to format C/C++/Obj-C code.
+
+.. code-block:: console
+
+ $ clang-format --help
+ OVERVIEW: A tool to format C/C++/Obj-C code.
+
+ Currently supports LLVM and Google style guides.
+ If no arguments are specified, it formats the code from standard input
+ and writes the result to the standard output.
+ If <file> is given, it reformats the file. If -i is specified together
+ with <file>, the file is edited in-place. Otherwise, the result is
+ written to the standard output.
+
+ USAGE: clang-format [options] [<file>]
+
+ OPTIONS:
+ -fatal-assembler-warnings - Consider warnings as error
+ -help - Display available options (-help-hidden for more)
+ -i - Inplace edit <file>, if specified.
+ -length=<int> - Format a range of this length, -1 for end of file.
+ -offset=<int> - Format a range starting at this file offset.
+ -stats - Enable statistics output from program
+ -style=<string> - Coding style, currently supports: LLVM, Google, Chromium.
+ -version - Display the version of this program
+
+
+Vim Integration
+===============
+
+There is an integration for :program:`vim` which lets you run the
+:program:`clang-format` standalone tool on your current buffer, optionally
+selecting regions to reformat. The integration has the form of a `python`-file
+which can be found under `clang/tools/clang-format/clang-format.py`.
+
+This can be integrated by adding the following to your `.vimrc`:
+
+.. code-block:: vim
+
+ map <C-K> :pyf <path-to-this-file>/clang-format.py<CR>
+ imap <C-K> <ESC>:pyf <path-to-this-file>/clang-format.py<CR>i
+
+The first line enables :program:`clang-format` for NORMAL and VISUAL mode, the
+second line adds support for INSERT mode. Change "C-K" to another binding if
+you need :program:`clang-format` on a different key (C-K stands for Ctrl+k).
+
+With this integration you can press the bound key and clang-format will
+format the current line in NORMAL and INSERT mode or the selected region in
+VISUAL mode. The line or region is extended to the next bigger syntactic
+entity.
+
+It operates on the current, potentially unsaved buffer and does not create
+or save any files. To revert a formatting, just undo.
+
+
+Script for patch reformatting
+=============================
+
+The python script `clang/tools/clang-format-diff.py` parses the output of
+a unified diff and reformats all contained lines with :program:`clang-format`.
+
+.. code-block:: console
+
+ usage: clang-format-diff.py [-h] [-p P] [-style STYLE]
+
+ Reformat changed lines in diff
+
+ optional arguments:
+ -h, --help show this help message and exit
+ -p P strip the smallest prefix containing P slashes
+ -style STYLE formatting style to apply (LLVM, Google)
+
+So to reformat all the lines in the latest :program:`git` commit, just do:
+
+.. code-block:: console
+
+ git diff -U0 HEAD^ | clang-format-diff.py
+
+The :option:`-U0` will create a diff without context lines (the script would format
+those as well).
diff --git a/docs/ClangPlugins.html b/docs/ClangPlugins.html
deleted file mode 100644
index ed560fe..0000000
--- a/docs/ClangPlugins.html
+++ /dev/null
@@ -1,170 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
-<title>Clang Plugins</title>
-<link type="text/css" rel="stylesheet" href="../menu.css">
-<link type="text/css" rel="stylesheet" href="../content.css">
-</head>
-<body>
-
-<!--#include virtual="../menu.html.incl"-->
-
-<div id="content">
-
-<h1>Clang Plugins</h1>
-<p>Clang Plugins make it possible to run extra user defined actions during
-a compilation. This document will provide a basic walkthrough of how to write
-and run a Clang Plugin.</p>
-
-<!-- ======================================================================= -->
-<h2 id="intro">Introduction</h2>
-<!-- ======================================================================= -->
-
-<p>Clang Plugins run FrontendActions over code. See the
-<a href="RAVFrontendAction.html">FrontendAction tutorial</a> on how to write a
-FrontendAction using the RecursiveASTVisitor. In this tutorial, we'll
-demonstrate how to write a simple clang plugin.
-</p>
-
-<!-- ======================================================================= -->
-<h2 id="pluginactions">Writing a PluginASTAction</h2>
-<!-- ======================================================================= -->
-
-<p>The main difference from writing normal FrontendActions is that you can
-handle plugin command line options. The
-PluginASTAction base class declares a ParseArgs method which you have to
-implement in your plugin.
-</p>
-<pre>
- bool ParseArgs(const CompilerInstance &amp;CI,
- const std::vector&lt;std::string>&amp; args) {
- for (unsigned i = 0, e = args.size(); i != e; ++i) {
- if (args[i] == "-some-arg") {
- // Handle the command line argument.
- }
- }
- return true;
- }
-</pre>
-
-<!-- ======================================================================= -->
-<h2 id="registerplugin">Registering a plugin</h2>
-<!-- ======================================================================= -->
-
-<p>A plugin is loaded from a dynamic library at runtime by the compiler. To register
-a plugin in a library, use FrontendPluginRegistry::Add:</p>
-<pre>
- static FrontendPluginRegistry::Add&lt;MyPlugin> X("my-plugin-name", "my plugin description");
-</pre>
-
-<!-- ======================================================================= -->
-<h2 id="example">Putting it all together</h2>
-<!-- ======================================================================= -->
-
-<p>Let's look at an example plugin that prints top-level function names.
-This example is also checked into the clang repository; please also take a look
-at the latest <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/examples/PrintFunctionNames/PrintFunctionNames.cpp?view=markup">checked in version of PrintFunctionNames.cpp</a>.</p>
-<pre>
-#include "clang/Frontend/FrontendPluginRegistry.h"
-#include "clang/AST/ASTConsumer.h"
-#include "clang/AST/AST.h"
-#include "clang/Frontend/CompilerInstance.h"
-#include "llvm/Support/raw_ostream.h"
-using namespace clang;
-
-namespace {
-
-class PrintFunctionsConsumer : public ASTConsumer {
-public:
- virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
- for (DeclGroupRef::iterator i = DG.begin(), e = DG.end(); i != e; ++i) {
- const Decl *D = *i;
- if (const NamedDecl *ND = dyn_cast&lt;NamedDecl>(D))
- llvm::errs() &lt;&lt; "top-level-decl: \"" &lt;&lt; ND->getNameAsString() &lt;&lt; "\"\n";
- }
-
- return true;
- }
-};
-
-class PrintFunctionNamesAction : public PluginASTAction {
-protected:
- ASTConsumer *CreateASTConsumer(CompilerInstance &amp;CI, llvm::StringRef) {
- return new PrintFunctionsConsumer();
- }
-
- bool ParseArgs(const CompilerInstance &amp;CI,
- const std::vector&lt;std::string>&amp; args) {
- for (unsigned i = 0, e = args.size(); i != e; ++i) {
- llvm::errs() &lt;&lt; "PrintFunctionNames arg = " &lt;&lt; args[i] &lt;&lt; "\n";
-
- // Example error handling.
- if (args[i] == "-an-error") {
- DiagnosticsEngine &amp;D = CI.getDiagnostics();
- unsigned DiagID = D.getCustomDiagID(
- DiagnosticsEngine::Error, "invalid argument '" + args[i] + "'");
- D.Report(DiagID);
- return false;
- }
- }
- if (args.size() &amp;&amp; args[0] == "help")
- PrintHelp(llvm::errs());
-
- return true;
- }
- void PrintHelp(llvm::raw_ostream&amp; ros) {
- ros &lt;&lt; "Help for PrintFunctionNames plugin goes here\n";
- }
-
-};
-
-}
-
-static FrontendPluginRegistry::Add&lt;PrintFunctionNamesAction>
-X("print-fns", "print function names");
-</pre>
-
-<!-- ======================================================================= -->
-<h2 id="running">Running the plugin</h2>
-<!-- ======================================================================= -->
-
-<p>To run a plugin, the dynamic library containing the plugin registry must be
-loaded via the -load command line option. This will load all plugins that are
-registered, and you can select the plugins to run by specifying the -plugin
-option. Additional parameters for the plugins can be passed with -plugin-arg-&lt;plugin-name>.</p>
-
-<p>Note that those options must reach clang's cc1 process. There are two
-ways to do so:</p>
-<ul>
-<li>
-Directly call the parsing process by using the -cc1 option; this has the
-downside of not configuring the default header search paths, so you'll need to
-specify the full system path configuration on the command line.
-</li>
-<li>
-Use clang as usual, but prefix all arguments to the cc1 process with -Xclang.
-</li>
-</ul>
-<p>For example, to run the print-function-names plugin over a source file in clang,
-first build the plugin, and then call clang with the plugin from the source tree:</p>
-<pre>
- $ export BD=/path/to/build/directory
- $ (cd $BD &amp;&amp; make PrintFunctionNames )
- $ clang++ -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS \
- -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D_GNU_SOURCE \
- -I$BD/tools/clang/include -Itools/clang/include -I$BD/include -Iinclude \
- tools/clang/tools/clang-check/ClangCheck.cpp -fsyntax-only \
- -Xclang -load -Xclang $BD/lib/PrintFunctionNames.so -Xclang \
- -plugin -Xclang print-fns
-</pre>
-
-<p>Also see the print-function-name plugin example's
-<a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/examples/PrintFunctionNames/README.txt?view=markup">README</a></p>
-
-
-
-</div>
-</body>
-</html>
-
diff --git a/docs/ClangPlugins.rst b/docs/ClangPlugins.rst
new file mode 100644
index 0000000..7c5c65c
--- /dev/null
+++ b/docs/ClangPlugins.rst
@@ -0,0 +1,150 @@
+=============
+Clang Plugins
+=============
+
+Clang Plugins make it possible to run extra user defined actions during a
+compilation. This document will provide a basic walkthrough of how to write and
+run a Clang Plugin.
+
+Introduction
+============
+
+Clang Plugins run FrontendActions over code. See the :doc:`FrontendAction
+tutorial <RAVFrontendAction>` on how to write a ``FrontendAction`` using the
+``RecursiveASTVisitor``. In this tutorial, we'll demonstrate how to write a
+simple clang plugin.
+
+Writing a ``PluginASTAction``
+=============================
+
+The main difference from writing normal ``FrontendActions`` is that you can
+handle plugin command line options. The ``PluginASTAction`` base class declares
+a ``ParseArgs`` method which you have to implement in your plugin.
+
+.. code-block:: c++
+
+ bool ParseArgs(const CompilerInstance &CI,
+ const std::vector<std::string>& args) {
+ for (unsigned i = 0, e = args.size(); i != e; ++i) {
+ if (args[i] == "-some-arg") {
+ // Handle the command line argument.
+ }
+ }
+ return true;
+ }
+
+Registering a plugin
+====================
+
+A plugin is loaded from a dynamic library at runtime by the compiler. To
+register a plugin in a library, use ``FrontendPluginRegistry::Add<>``:
+
+.. code-block:: c++
+
+ static FrontendPluginRegistry::Add<MyPlugin> X("my-plugin-name", "my plugin description");
+
+Putting it all together
+=======================
+
+Let's look at an example plugin that prints top-level function names. This
+example is also checked into the clang repository; please also take a look at
+the latest `checked in version of PrintFunctionNames.cpp
+<http://llvm.org/viewvc/llvm-project/cfe/trunk/examples/PrintFunctionNames/PrintFunctionNames.cpp?view=markup>`_.
+
+.. code-block:: c++
+
+ #include "clang/Frontend/FrontendPluginRegistry.h"
+ #include "clang/AST/ASTConsumer.h"
+ #include "clang/AST/AST.h"
+ #include "clang/Frontend/CompilerInstance.h"
+ #include "llvm/Support/raw_ostream.h"
+ using namespace clang;
+
+ namespace {
+
+ class PrintFunctionsConsumer : public ASTConsumer {
+ public:
+ virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
+ for (DeclGroupRef::iterator i = DG.begin(), e = DG.end(); i != e; ++i) {
+ const Decl *D = *i;
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
+ llvm::errs() << "top-level-decl: \"" << ND->getNameAsString() << "\"\n";
+ }
+
+ return true;
+ }
+ };
+
+ class PrintFunctionNamesAction : public PluginASTAction {
+ protected:
+ ASTConsumer *CreateASTConsumer(CompilerInstance &CI, llvm::StringRef) {
+ return new PrintFunctionsConsumer();
+ }
+
+ bool ParseArgs(const CompilerInstance &CI,
+ const std::vector<std::string>& args) {
+ for (unsigned i = 0, e = args.size(); i != e; ++i) {
+ llvm::errs() << "PrintFunctionNames arg = " << args[i] << "\n";
+
+ // Example error handling.
+ if (args[i] == "-an-error") {
+ DiagnosticsEngine &D = CI.getDiagnostics();
+ unsigned DiagID = D.getCustomDiagID(
+ DiagnosticsEngine::Error, "invalid argument '" + args[i] + "'");
+ D.Report(DiagID);
+ return false;
+ }
+ }
+ if (args.size() && args[0] == "help")
+ PrintHelp(llvm::errs());
+
+ return true;
+ }
+ void PrintHelp(llvm::raw_ostream& ros) {
+ ros << "Help for PrintFunctionNames plugin goes here\n";
+ }
+
+ };
+
+ }
+
+ static FrontendPluginRegistry::Add<PrintFunctionNamesAction>
+ X("print-fns", "print function names");
+
+Running the plugin
+==================
+
+To run a plugin, the dynamic library containing the plugin registry must be
+loaded via the :option:`-load` command line option. This will load all plugins
+that are registered, and you can select the plugins to run by specifying the
+:option:`-plugin` option. Additional parameters for the plugins can be passed with
+:option:`-plugin-arg-<plugin-name>`.
+
+Note that those options must reach clang's cc1 process. There are two
+ways to do so:
+
+* Directly call the parsing process by using the :option:`-cc1` option; this
+ has the downside of not configuring the default header search paths, so
+ you'll need to specify the full system path configuration on the command
+ line.
+* Use clang as usual, but prefix all arguments to the cc1 process with
+ :option:`-Xclang`.
+
+For example, to run the ``print-function-names`` plugin over a source file in
+clang, first build the plugin, and then call clang with the plugin from the
+source tree:
+
+.. code-block:: console
+
+ $ export BD=/path/to/build/directory
+ $ (cd $BD && make PrintFunctionNames )
+ $ clang++ -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS \
+ -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D_GNU_SOURCE \
+ -I$BD/tools/clang/include -Itools/clang/include -I$BD/include -Iinclude \
+ tools/clang/tools/clang-check/ClangCheck.cpp -fsyntax-only \
+ -Xclang -load -Xclang $BD/lib/PrintFunctionNames.so -Xclang \
+ -plugin -Xclang print-fns
+
+Also see the print-function-name plugin example's
+`README <http://llvm.org/viewvc/llvm-project/cfe/trunk/examples/PrintFunctionNames/README.txt?view=markup>`_
+
diff --git a/docs/ClangTools.html b/docs/ClangTools.html
deleted file mode 100644
index 4de57bd..0000000
--- a/docs/ClangTools.html
+++ /dev/null
@@ -1,110 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
-<title>Clang Tools</title>
-<link type="text/css" rel="stylesheet" href="../menu.css">
-<link type="text/css" rel="stylesheet" href="../content.css">
-</head>
-<body>
-
-<!--#include virtual="../menu.html.incl"-->
-
-<div id="content">
-
-<h1>Clang Tools</h1>
-<p>Clang Tools are standalone command line (and potentially GUI) tools design
-for use by C++ developers who are already using and enjoying Clang as their
-compiler. These tools provide developer-oriented functionality such as fast
-syntax checking, automatic formatting, refactoring, etc.</p>
-
-<p>Only a couple of the most basic and fundamental tools are kept in the primary
-Clang Subversion project. The rest of the tools are kept in a side-project so
-that developers who don't want or need to build them don't. If you want to get
-access to the extra Clang Tools repository, simply check it out into the tools
-tree of your Clang checkout and follow the usual process for building and
-working with a combined LLVM/Clang checkout:</p>
-<ul>
- <li>With Subversion:
- <ul>
- <li><tt>cd llvm/tools/clang/tools</tt></li>
- <li><tt>svn co http://llvm.org/svn/llvm-project/clang-tools-extra/trunk
- extra</tt></li>
- </ul>
- </li>
- <li>Or with Git:
- <ul>
- <li><tt>cd llvm/tools/clang/tools</tt></li>
- <li><tt>git clone http://llvm.org/git/clang-tools-extra.git extra</tt></li>
- </ul>
- </li>
-</ul>
-
-<p>This document describes a high-level overview of the organization of Clang
-Tools within the project as well as giving an introduction to some of the more
-important tools. However, it should be noted that this document is currently
-focused on Clang and Clang Tool developers, not on end users of these tools.</p>
-
-<!-- ======================================================================= -->
-<h2 id="org">Clang Tools Organization</h2>
-<!-- ======================================================================= -->
-
-<p>Clang Tools are CLI or GUI programs that are intended to be directly used by
-C++ developers. That is they are <em>not</em> primarily for use by Clang
-developers, although they are hopefully useful to C++ developers who happen to
-work on Clang, and we try to actively dogfood their functionality. They are
-developed in three components: the underlying infrastructure for building
-a standalone tool based on Clang, core shared logic used by many different tools
-in the form of refactoring and rewriting libraries, and the tools
-themselves.</p>
-
-<p>The underlying infrastructure for Clang Tools is the
-<a href="LibTooling.html">LibTooling</a> platform. See its documentation for
-much more detailed information about how this infrastructure works. The common
-refactoring and rewriting toolkit-style library is also part of LibTooling
-organizationally.</p>
-
-<p>A few Clang Tools are developed along side the core Clang libraries as
-examples and test cases of fundamental functionality. However, most of the tools
-are developed in a side repository to provide easy separation from the core
-libraries. We intentionally do not support public libraries in the side
-repository, as we want to carefully review and find good APIs for libraries as
-they are lifted out of a few tools and into the core Clang library set.</p>
-
-<p>Regardless of which repository Clang Tools' code resides in, the development
-process and practices for all Clang Tools are exactly those of Clang itself.
-They are entirely within the Clang <em>project</em>, regardless of the version
-control scheme.</p>
-
-
-<!-- ======================================================================= -->
-<h2 id="coretools">Core Clang Tools</h2>
-<!-- ======================================================================= -->
-
-<p>The core set of Clang tools that are within the main repository are tools
-that very specifically compliment, and allow use and testing of <em>Clang</em>
-specific functionality.</p>
-
-<h3 id="clang-check"><tt>clang-check</tt></h3>
-<p>This tool combines the LibTooling framework for running a Clang tool with the
-basic Clang diagnostics by syntax checking specific files in a fast, command
-line interface. It can also accept flags to re-display the diagnostics in
-different formats with different flags, suitable for use driving an IDE or
-editor. Furthermore, it can be used in fixit-mode to directly apply fixit-hints
-offered by clang.</p>
-
-<p>FIXME: Link to user-oriented clang-check documentation.</p>
-
-<!-- ======================================================================= -->
-<h2 id="registerplugin">Extra Clang Tools</h2>
-<!-- ======================================================================= -->
-
-<p>As various categories of Clang Tools are added to the extra repository,
-they'll be tracked here. The focus of this documentation is on the scope and
-features of the tools for other tool developers; each tool should provide its
-own user-focused documentation.</p>
-
-</div>
-</body>
-</html>
-
diff --git a/docs/ClangTools.rst b/docs/ClangTools.rst
new file mode 100644
index 0000000..b7f7c7b
--- /dev/null
+++ b/docs/ClangTools.rst
@@ -0,0 +1,152 @@
+========
+Overview
+========
+
+Clang Tools are standalone command line (and potentially GUI) tools
+designed for use by C++ developers who are already using and enjoying
+Clang as their compiler. These tools provide developer-oriented
+functionality such as fast syntax checking, automatic formatting,
+refactoring, etc.
+
+Only a couple of the most basic and fundamental tools are kept in the
+primary Clang Subversion project. The rest of the tools are kept in a
+side-project so that developers who don't want or need to build them
+don't. If you want to get access to the extra Clang Tools repository,
+simply check it out into the tools tree of your Clang checkout and
+follow the usual process for building and working with a combined
+LLVM/Clang checkout:
+
+- With Subversion:
+
+ - ``cd llvm/tools/clang/tools``
+ - ``svn co http://llvm.org/svn/llvm-project/clang-tools-extra/trunk extra``
+
+- Or with Git:
+
+ - ``cd llvm/tools/clang/tools``
+ - ``git clone http://llvm.org/git/clang-tools-extra.git extra``
+
+This document describes a high-level overview of the organization of
+Clang Tools within the project as well as giving an introduction to some
+of the more important tools. However, it should be noted that this
+document is currently focused on Clang and Clang Tool developers, not on
+end users of these tools.
+
+Clang Tools Organization
+========================
+
+Clang Tools are CLI or GUI programs that are intended to be directly
+used by C++ developers. That is they are *not* primarily for use by
+Clang developers, although they are hopefully useful to C++ developers
+who happen to work on Clang, and we try to actively dogfood their
+functionality. They are developed in three components: the underlying
+infrastructure for building a standalone tool based on Clang, core
+shared logic used by many different tools in the form of refactoring and
+rewriting libraries, and the tools themselves.
+
+The underlying infrastructure for Clang Tools is the
+:doc:`LibTooling <LibTooling>` platform. See its documentation for much
+more detailed information about how this infrastructure works. The
+common refactoring and rewriting toolkit-style library is also part of
+LibTooling organizationally.
+
+A few Clang Tools are developed along side the core Clang libraries as
+examples and test cases of fundamental functionality. However, most of
+the tools are developed in a side repository to provide easy separation
+from the core libraries. We intentionally do not support public
+libraries in the side repository, as we want to carefully review and
+find good APIs for libraries as they are lifted out of a few tools and
+into the core Clang library set.
+
+Regardless of which repository Clang Tools' code resides in, the
+development process and practices for all Clang Tools are exactly those
+of Clang itself. They are entirely within the Clang *project*,
+regardless of the version control scheme.
+
+Core Clang Tools
+================
+
+The core set of Clang tools that are within the main repository are
+tools that very specifically complement, and allow use and testing of
+*Clang* specific functionality.
+
+``clang-check``
+---------------
+
+:doc:`ClangCheck` 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. Furthermore, it can be used in fixit-mode to directly apply
+fixit-hints offered by clang. See :doc:`HowToSetupToolingForLLVM` for
+instructions on how to setup and used `clang-check`.
+
+``clang-format``
+~~~~~~~~~~~~~~~~
+
+Clang-format is both a :doc:`library <LibFormat>` and a :doc:`stand-alone tool
+<ClangFormat>` with the goal of automatically reformatting C++ sources files
+according to configurable style guides. To do so, clang-format uses Clang's
+``Lexer`` to transform an input file into a token stream and then changes all
+the whitespace around those tokens. The goal is for clang-format to both serve
+both as a user tool (ideally with powerful IDE integrations) and part of other
+refactoring tools, e.g. to do a reformatting of all the lines changed during a
+renaming.
+
+``cpp11-migrate``
+~~~~~~~~~~~~~~~~~
+``cpp11-migrate`` migrates C++ code to use C++11 features where appropriate.
+Currently it can:
+
+* convert loops to range-based for loops;
+
+* convert null pointer constants (like ``NULL`` or ``0``) to C++11 ``nullptr``.
+
+Extra Clang Tools
+=================
+
+As various categories of Clang Tools are added to the extra repository,
+they'll be tracked here. The focus of this documentation is on the scope
+and features of the tools for other tool developers; each tool should
+provide its own user-focused documentation.
+
+Ideas for new Tools
+===================
+
+* C++ cast conversion tool. Will convert C-style casts (``(type) value``) to
+ appropriate C++ cast (``static_cast``, ``const_cast`` or
+ ``reinterpret_cast``).
+* Non-member ``begin()`` and ``end()`` conversion tool. Will convert
+ ``foo.begin()`` into ``begin(foo)`` and similarly for ``end()``, where
+ ``foo`` is a standard container. We could also detect similar patterns for
+ arrays.
+* ``tr1`` removal tool. Will migrate source code from using TR1 library
+ features to C++11 library. For example:
+
+ .. code-block:: c++
+
+ #include <tr1/unordered_map>
+ int main()
+ {
+ std::tr1::unordered_map <int, int> ma;
+ std::cout << ma.size () << std::endl;
+ return 0;
+ }
+
+ should be rewritten to:
+
+ .. code-block:: c++
+
+ #include <unordered_map>
+ int main()
+ {
+ std::unordered_map <int, int> ma;
+ std::cout << ma.size () << std::endl;
+ return 0;
+ }
+
+* A tool to remove ``auto``. Will convert ``auto`` to an explicit type or add
+ comments with deduced types. The motivation is that there are developers
+ that don't want to use ``auto`` because they are afraid that they might lose
+ control over their code.
+
diff --git a/docs/DriverInternals.html b/docs/DriverInternals.html
deleted file mode 100644
index ce707b9..0000000
--- a/docs/DriverInternals.html
+++ /dev/null
@@ -1,523 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-<html>
- <head>
- <title>Clang Driver Manual</title>
- <link type="text/css" rel="stylesheet" href="../menu.css">
- <link type="text/css" rel="stylesheet" href="../content.css">
- <style type="text/css">
- td {
- vertical-align: top;
- }
- </style>
- </head>
- <body>
-
- <!--#include virtual="../menu.html.incl"-->
-
- <div id="content">
-
- <h1>Driver Design &amp; Internals</h1>
-
- <ul>
- <li><a href="#intro">Introduction</a></li>
- <li><a href="#features">Features and Goals</a>
- <ul>
- <li><a href="#gcccompat">GCC Compatibility</a></li>
- <li><a href="#components">Flexible</a></li>
- <li><a href="#performance">Low Overhead</a></li>
- <li><a href="#simple">Simple</a></li>
- </ul>
- </li>
- <li><a href="#design">Design</a>
- <ul>
- <li><a href="#int_intro">Internals Introduction</a></li>
- <li><a href="#int_overview">Design Overview</a></li>
- <li><a href="#int_notes">Additional Notes</a>
- <ul>
- <li><a href="#int_compilation">The Compilation Object</a></li>
- <li><a href="#int_unified_parsing">Unified Parsing &amp; Pipelining</a></li>
- <li><a href="#int_toolchain_translation">ToolChain Argument Translation</a></li>
- <li><a href="#int_unused_warnings">Unused Argument Warnings</a></li>
- </ul>
- </li>
- <li><a href="#int_gcc_concepts">Relation to GCC Driver Concepts</a></li>
- </ul>
- </li>
- </ul>
-
-
- <!-- ======================================================================= -->
- <h2 id="intro">Introduction</h2>
- <!-- ======================================================================= -->
-
- <p>This document describes the Clang driver. The purpose of this
- document is to describe both the motivation and design goals
- for the driver, as well as details of the internal
- implementation.</p>
-
- <!-- ======================================================================= -->
- <h2 id="features">Features and Goals</h2>
- <!-- ======================================================================= -->
-
- <p>The Clang driver is intended to be a production quality
- compiler driver providing access to the Clang compiler and
- tools, with a command line interface which is compatible with
- the gcc driver.</p>
-
- <p>Although the driver is part of and driven by the Clang
- project, it is logically a separate tool which shares many of
- the same goals as Clang:</p>
-
- <p><b>Features</b>:</p>
- <ul>
- <li><a href="#gcccompat">GCC Compatibility</a></li>
- <li><a href="#components">Flexible</a></li>
- <li><a href="#performance">Low Overhead</a></li>
- <li><a href="#simple">Simple</a></li>
- </ul>
-
- <!--=======================================================================-->
- <h3 id="gcccompat">GCC Compatibility</h3>
- <!--=======================================================================-->
-
- <p>The number one goal of the driver is to ease the adoption of
- Clang by allowing users to drop Clang into a build system
- which was designed to call GCC. Although this makes the driver
- much more complicated than might otherwise be necessary, we
- decided that being very compatible with the gcc command line
- interface was worth it in order to allow users to quickly test
- clang on their projects.</p>
-
- <!--=======================================================================-->
- <h3 id="components">Flexible</h3>
- <!--=======================================================================-->
-
- <p>The driver was designed to be flexible and easily accommodate
- new uses as we grow the clang and LLVM infrastructure. As one
- example, the driver can easily support the introduction of
- tools which have an integrated assembler; something we hope to
- add to LLVM in the future.</p>
-
- <p>Similarly, most of the driver functionality is kept in a
- library which can be used to build other tools which want to
- implement or accept a gcc like interface. </p>
-
- <!--=======================================================================-->
- <h3 id="performance">Low Overhead</h3>
- <!--=======================================================================-->
-
- <p>The driver should have as little overhead as possible. In
- practice, we found that the gcc driver by itself incurred a
- small but meaningful overhead when compiling many small
- files. The driver doesn't do much work compared to a
- compilation, but we have tried to keep it as efficient as
- possible by following a few simple principles:</p>
- <ul>
- <li>Avoid memory allocation and string copying when
- possible.</li>
-
- <li>Don't parse arguments more than once.</li>
-
- <li>Provide a few simple interfaces for efficiently searching
- arguments.</li>
- </ul>
-
- <!--=======================================================================-->
- <h3 id="simple">Simple</h3>
- <!--=======================================================================-->
-
- <p>Finally, the driver was designed to be "as simple as
- possible", given the other goals. Notably, trying to be
- completely compatible with the gcc driver adds a significant
- amount of complexity. However, the design of the driver
- attempts to mitigate this complexity by dividing the process
- into a number of independent stages instead of a single
- monolithic task.</p>
-
- <!-- ======================================================================= -->
- <h2 id="design">Internal Design and Implementation</h2>
- <!-- ======================================================================= -->
-
- <ul>
- <li><a href="#int_intro">Internals Introduction</a></li>
- <li><a href="#int_overview">Design Overview</a></li>
- <li><a href="#int_notes">Additional Notes</a></li>
- <li><a href="#int_gcc_concepts">Relation to GCC Driver Concepts</a></li>
- </ul>
-
- <!--=======================================================================-->
- <h3><a name="int_intro">Internals Introduction</a></h3>
- <!--=======================================================================-->
-
- <p>In order to satisfy the stated goals, the driver was designed
- to completely subsume the functionality of the gcc executable;
- that is, the driver should not need to delegate to gcc to
- perform subtasks. On Darwin, this implies that the Clang
- driver also subsumes the gcc driver-driver, which is used to
- implement support for building universal images (binaries and
- object files). This also implies that the driver should be
- able to call the language specific compilers (e.g. cc1)
- directly, which means that it must have enough information to
- forward command line arguments to child processes
- correctly.</p>
-
- <!--=======================================================================-->
- <h3><a name="int_overview">Design Overview</a></h3>
- <!--=======================================================================-->
-
- <p>The diagram below shows the significant components of the
- driver architecture and how they relate to one another. The
- orange components represent concrete data structures built by
- the driver, the green components indicate conceptually
- distinct stages which manipulate these data structures, and
- the blue components are important helper classes. </p>
-
- <div style="text-align:center">
- <a href="DriverArchitecture.png">
- <img width=400 src="DriverArchitecture.png"
- alt="Driver Architecture Diagram">
- </a>
- </div>
-
- <!--=======================================================================-->
- <h3><a name="int_stages">Driver Stages</a></h3>
- <!--=======================================================================-->
-
- <p>The driver functionality is conceptually divided into five stages:</p>
-
- <ol>
- <li>
- <b>Parse: Option Parsing</b>
-
- <p>The command line argument strings are decomposed into
- arguments (<tt>Arg</tt> instances). The driver expects to
- understand all available options, although there is some
- facility for just passing certain classes of options
- through (like <tt>-Wl,</tt>).</p>
-
- <p>Each argument corresponds to exactly one
- abstract <tt>Option</tt> definition, which describes how
- the option is parsed along with some additional
- metadata. The Arg instances themselves are lightweight and
- merely contain enough information for clients to determine
- which option they correspond to and their values (if they
- have additional parameters).</p>
-
- <p>For example, a command line like "-Ifoo -I foo" would
- parse to two Arg instances (a JoinedArg and a SeparateArg
- instance), but each would refer to the same Option.</p>
-
- <p>Options are lazily created in order to avoid populating
- all Option classes when the driver is loaded. Most of the
- driver code only needs to deal with options by their
- unique ID (e.g., <tt>options::OPT_I</tt>),</p>
-
- <p>Arg instances themselves do not generally store the
- values of parameters. In many cases, this would
- simply result in creating unnecessary string
- copies. Instead, Arg instances are always embedded inside
- an ArgList structure, which contains the original vector
- of argument strings. Each Arg itself only needs to contain
- an index into this vector instead of storing its values
- directly.</p>
-
- <p>The clang driver can dump the results of this
- stage using the <tt>-ccc-print-options</tt> flag (which
- must precede any actual command line arguments). For
- example:</p>
- <pre>
- $ <b>clang -ccc-print-options -Xarch_i386 -fomit-frame-pointer -Wa,-fast -Ifoo -I foo t.c</b>
- Option 0 - Name: "-Xarch_", Values: {"i386", "-fomit-frame-pointer"}
- Option 1 - Name: "-Wa,", Values: {"-fast"}
- Option 2 - Name: "-I", Values: {"foo"}
- Option 3 - Name: "-I", Values: {"foo"}
- Option 4 - Name: "&lt;input&gt;", Values: {"t.c"}
- </pre>
-
- <p>After this stage is complete the command line should be
- broken down into well defined option objects with their
- appropriate parameters. Subsequent stages should rarely,
- if ever, need to do any string processing.</p>
- </li>
-
- <li>
- <b>Pipeline: Compilation Job Construction</b>
-
- <p>Once the arguments are parsed, the tree of subprocess
- jobs needed for the desired compilation sequence are
- constructed. This involves determining the input files and
- their types, what work is to be done on them (preprocess,
- compile, assemble, link, etc.), and constructing a list of
- Action instances for each task. The result is a list of
- one or more top-level actions, each of which generally
- corresponds to a single output (for example, an object or
- linked executable).</p>
-
- <p>The majority of Actions correspond to actual tasks,
- however there are two special Actions. The first is
- InputAction, which simply serves to adapt an input
- argument for use as an input to other Actions. The second
- is BindArchAction, which conceptually alters the
- architecture to be used for all of its input Actions.</p>
-
- <p>The clang driver can dump the results of this
- stage using the <tt>-ccc-print-phases</tt> flag. For
- example:</p>
- <pre>
- $ <b>clang -ccc-print-phases -x c t.c -x assembler t.s</b>
- 0: input, "t.c", c
- 1: preprocessor, {0}, cpp-output
- 2: compiler, {1}, assembler
- 3: assembler, {2}, object
- 4: input, "t.s", assembler
- 5: assembler, {4}, object
- 6: linker, {3, 5}, image
- </pre>
- <p>Here the driver is constructing seven distinct actions,
- four to compile the "t.c" input into an object file, two to
- assemble the "t.s" input, and one to link them together.</p>
-
- <p>A rather different compilation pipeline is shown here; in
- this example there are two top level actions to compile
- the input files into two separate object files, where each
- object file is built using <tt>lipo</tt> to merge results
- built for two separate architectures.</p>
- <pre>
- $ <b>clang -ccc-print-phases -c -arch i386 -arch x86_64 t0.c t1.c</b>
- 0: input, "t0.c", c
- 1: preprocessor, {0}, cpp-output
- 2: compiler, {1}, assembler
- 3: assembler, {2}, object
- 4: bind-arch, "i386", {3}, object
- 5: bind-arch, "x86_64", {3}, object
- 6: lipo, {4, 5}, object
- 7: input, "t1.c", c
- 8: preprocessor, {7}, cpp-output
- 9: compiler, {8}, assembler
- 10: assembler, {9}, object
- 11: bind-arch, "i386", {10}, object
- 12: bind-arch, "x86_64", {10}, object
- 13: lipo, {11, 12}, object
- </pre>
-
- <p>After this stage is complete the compilation process is
- divided into a simple set of actions which need to be
- performed to produce intermediate or final outputs (in
- some cases, like <tt>-fsyntax-only</tt>, there is no
- "real" final output). Phases are well known compilation
- steps, such as "preprocess", "compile", "assemble",
- "link", etc.</p>
- </li>
-
- <li>
- <b>Bind: Tool &amp; Filename Selection</b>
-
- <p>This stage (in conjunction with the Translate stage)
- turns the tree of Actions into a list of actual subprocess
- to run. Conceptually, the driver performs a top down
- matching to assign Action(s) to Tools. The ToolChain is
- responsible for selecting the tool to perform a particular
- action; once selected the driver interacts with the tool
- to see if it can match additional actions (for example, by
- having an integrated preprocessor).
-
- <p>Once Tools have been selected for all actions, the driver
- determines how the tools should be connected (for example,
- using an inprocess module, pipes, temporary files, or user
- provided filenames). If an output file is required, the
- driver also computes the appropriate file name (the suffix
- and file location depend on the input types and options
- such as <tt>-save-temps</tt>).
-
- <p>The driver interacts with a ToolChain to perform the Tool
- bindings. Each ToolChain contains information about all
- the tools needed for compilation for a particular
- architecture, platform, and operating system. A single
- driver invocation may query multiple ToolChains during one
- compilation in order to interact with tools for separate
- architectures.</p>
-
- <p>The results of this stage are not computed directly, but
- the driver can print the results via
- the <tt>-ccc-print-bindings</tt> option. For example:</p>
- <pre>
- $ <b>clang -ccc-print-bindings -arch i386 -arch ppc t0.c</b>
- # "i386-apple-darwin9" - "clang", inputs: ["t0.c"], output: "/tmp/cc-Sn4RKF.s"
- # "i386-apple-darwin9" - "darwin::Assemble", inputs: ["/tmp/cc-Sn4RKF.s"], output: "/tmp/cc-gvSnbS.o"
- # "i386-apple-darwin9" - "darwin::Link", inputs: ["/tmp/cc-gvSnbS.o"], output: "/tmp/cc-jgHQxi.out"
- # "ppc-apple-darwin9" - "gcc::Compile", inputs: ["t0.c"], output: "/tmp/cc-Q0bTox.s"
- # "ppc-apple-darwin9" - "gcc::Assemble", inputs: ["/tmp/cc-Q0bTox.s"], output: "/tmp/cc-WCdicw.o"
- # "ppc-apple-darwin9" - "gcc::Link", inputs: ["/tmp/cc-WCdicw.o"], output: "/tmp/cc-HHBEBh.out"
- # "i386-apple-darwin9" - "darwin::Lipo", inputs: ["/tmp/cc-jgHQxi.out", "/tmp/cc-HHBEBh.out"], output: "a.out"
- </pre>
-
- <p>This shows the tool chain, tool, inputs and outputs which
- have been bound for this compilation sequence. Here clang
- is being used to compile t0.c on the i386 architecture and
- darwin specific versions of the tools are being used to
- assemble and link the result, but generic gcc versions of
- the tools are being used on PowerPC.</p>
- </li>
-
- <li>
- <b>Translate: Tool Specific Argument Translation</b>
-
- <p>Once a Tool has been selected to perform a particular
- Action, the Tool must construct concrete Jobs which will be
- executed during compilation. The main work is in translating
- from the gcc style command line options to whatever options
- the subprocess expects.</p>
-
- <p>Some tools, such as the assembler, only interact with a
- handful of arguments and just determine the path of the
- executable to call and pass on their input and output
- arguments. Others, like the compiler or the linker, may
- translate a large number of arguments in addition.</p>
-
- <p>The ArgList class provides a number of simple helper
- methods to assist with translating arguments; for example,
- to pass on only the last of arguments corresponding to some
- option, or all arguments for an option.</p>
-
- <p>The result of this stage is a list of Jobs (executable
- paths and argument strings) to execute.</p>
- </li>
-
- <li>
- <b>Execute</b>
- <p>Finally, the compilation pipeline is executed. This is
- mostly straightforward, although there is some interaction
- with options
- like <tt>-pipe</tt>, <tt>-pass-exit-codes</tt>
- and <tt>-time</tt>.</p>
- </li>
-
- </ol>
-
- <!--=======================================================================-->
- <h3><a name="int_notes">Additional Notes</a></h3>
- <!--=======================================================================-->
-
- <h4 id="int_compilation">The Compilation Object</h4>
-
- <p>The driver constructs a Compilation object for each set of
- command line arguments. The Driver itself is intended to be
- invariant during construction of a Compilation; an IDE should be
- able to construct a single long lived driver instance to use
- for an entire build, for example.</p>
-
- <p>The Compilation object holds information that is particular
- to each compilation sequence. For example, the list of used
- temporary files (which must be removed once compilation is
- finished) and result files (which should be removed if
- compilation fails).</p>
-
- <h4 id="int_unified_parsing">Unified Parsing &amp; Pipelining</h4>
-
- <p>Parsing and pipelining both occur without reference to a
- Compilation instance. This is by design; the driver expects that
- both of these phases are platform neutral, with a few very well
- defined exceptions such as whether the platform uses a driver
- driver.</p>
-
- <h4 id="int_toolchain_translation">ToolChain Argument Translation</h4>
-
- <p>In order to match gcc very closely, the clang driver
- currently allows tool chains to perform their own translation of
- the argument list (into a new ArgList data structure). Although
- this allows the clang driver to match gcc easily, it also makes
- the driver operation much harder to understand (since the Tools
- stop seeing some arguments the user provided, and see new ones
- instead).</p>
-
- <p>For example, on Darwin <tt>-gfull</tt> gets translated into two
- separate arguments, <tt>-g</tt>
- and <tt>-fno-eliminate-unused-debug-symbols</tt>. Trying to write Tool
- logic to do something with <tt>-gfull</tt> will not work, because Tool
- argument translation is done after the arguments have been
- translated.</p>
-
- <p>A long term goal is to remove this tool chain specific
- translation, and instead force each tool to change its own logic
- to do the right thing on the untranslated original arguments.</p>
-
- <h4 id="int_unused_warnings">Unused Argument Warnings</h4>
- <p>The driver operates by parsing all arguments but giving Tools
- the opportunity to choose which arguments to pass on. One
- downside of this infrastructure is that if the user misspells
- some option, or is confused about which options to use, some
- command line arguments the user really cared about may go
- unused. This problem is particularly important when using
- clang as a compiler, since the clang compiler does not support
- anywhere near all the options that gcc does, and we want to make
- sure users know which ones are being used.</p>
-
- <p>To support this, the driver maintains a bit associated with
- each argument of whether it has been used (at all) during the
- compilation. This bit usually doesn't need to be set by hand,
- as the key ArgList accessors will set it automatically.</p>
-
- <p>When a compilation is successful (there are no errors), the
- driver checks the bit and emits an "unused argument" warning for
- any arguments which were never accessed. This is conservative
- (the argument may not have been used to do what the user wanted)
- but still catches the most obvious cases.</p>
-
- <!--=======================================================================-->
- <h3><a name="int_gcc_concepts">Relation to GCC Driver Concepts</a></h3>
- <!--=======================================================================-->
-
- <p>For those familiar with the gcc driver, this section provides
- a brief overview of how things from the gcc driver map to the
- clang driver.</p>
-
- <ul>
- <li>
- <b>Driver Driver</b>
- <p>The driver driver is fully integrated into the clang
- driver. The driver simply constructs additional Actions to
- bind the architecture during the <i>Pipeline</i>
- phase. The tool chain specific argument translation is
- responsible for handling <tt>-Xarch_</tt>.</p>
-
- <p>The one caveat is that this approach
- requires <tt>-Xarch_</tt> not be used to alter the
- compilation itself (for example, one cannot
- provide <tt>-S</tt> as an <tt>-Xarch_</tt> argument). The
- driver attempts to reject such invocations, and overall
- there isn't a good reason to abuse <tt>-Xarch_</tt> to
- that end in practice.</p>
-
- <p>The upside is that the clang driver is more efficient and
- does little extra work to support universal builds. It also
- provides better error reporting and UI consistency.</p>
- </li>
-
- <li>
- <b>Specs</b>
- <p>The clang driver has no direct correspondent for
- "specs". The majority of the functionality that is
- embedded in specs is in the Tool specific argument
- translation routines. The parts of specs which control the
- compilation pipeline are generally part of
- the <i>Pipeline</i> stage.</p>
- </li>
-
- <li>
- <b>Toolchains</b>
- <p>The gcc driver has no direct understanding of tool
- chains. Each gcc binary roughly corresponds to the
- information which is embedded inside a single
- ToolChain.</p>
-
- <p>The clang driver is intended to be portable and support
- complex compilation environments. All platform and tool
- chain specific code should be protected behind either
- abstract or well defined interfaces (such as whether the
- platform supports use as a driver driver).</p>
- </li>
- </ul>
- </div>
- </body>
-</html>
diff --git a/docs/DriverInternals.rst b/docs/DriverInternals.rst
new file mode 100644
index 0000000..c779555
--- /dev/null
+++ b/docs/DriverInternals.rst
@@ -0,0 +1,400 @@
+=========================
+Driver Design & Internals
+=========================
+
+.. contents::
+ :local:
+
+Introduction
+============
+
+This document describes the Clang driver. The purpose of this document
+is to describe both the motivation and design goals for the driver, as
+well as details of the internal implementation.
+
+Features and Goals
+==================
+
+The Clang driver is intended to be a production quality compiler driver
+providing access to the Clang compiler and tools, with a command line
+interface which is compatible with the gcc driver.
+
+Although the driver is part of and driven by the Clang project, it is
+logically a separate tool which shares many of the same goals as Clang:
+
+.. contents:: Features
+ :local:
+
+GCC Compatibility
+-----------------
+
+The number one goal of the driver is to ease the adoption of Clang by
+allowing users to drop Clang into a build system which was designed to
+call GCC. Although this makes the driver much more complicated than
+might otherwise be necessary, we decided that being very compatible with
+the gcc command line interface was worth it in order to allow users to
+quickly test clang on their projects.
+
+Flexible
+--------
+
+The driver was designed to be flexible and easily accommodate new uses
+as we grow the clang and LLVM infrastructure. As one example, the driver
+can easily support the introduction of tools which have an integrated
+assembler; something we hope to add to LLVM in the future.
+
+Similarly, most of the driver functionality is kept in a library which
+can be used to build other tools which want to implement or accept a gcc
+like interface.
+
+Low Overhead
+------------
+
+The driver should have as little overhead as possible. In practice, we
+found that the gcc driver by itself incurred a small but meaningful
+overhead when compiling many small files. The driver doesn't do much
+work compared to a compilation, but we have tried to keep it as
+efficient as possible by following a few simple principles:
+
+- Avoid memory allocation and string copying when possible.
+- Don't parse arguments more than once.
+- Provide a few simple interfaces for efficiently searching arguments.
+
+Simple
+------
+
+Finally, the driver was designed to be "as simple as possible", given
+the other goals. Notably, trying to be completely compatible with the
+gcc driver adds a significant amount of complexity. However, the design
+of the driver attempts to mitigate this complexity by dividing the
+process into a number of independent stages instead of a single
+monolithic task.
+
+Internal Design and Implementation
+==================================
+
+.. contents::
+ :local:
+ :depth: 1
+
+Internals Introduction
+----------------------
+
+In order to satisfy the stated goals, the driver was designed to
+completely subsume the functionality of the gcc executable; that is, the
+driver should not need to delegate to gcc to perform subtasks. On
+Darwin, this implies that the Clang driver also subsumes the gcc
+driver-driver, which is used to implement support for building universal
+images (binaries and object files). This also implies that the driver
+should be able to call the language specific compilers (e.g. cc1)
+directly, which means that it must have enough information to forward
+command line arguments to child processes correctly.
+
+Design Overview
+---------------
+
+The diagram below shows the significant components of the driver
+architecture and how they relate to one another. The orange components
+represent concrete data structures built by the driver, the green
+components indicate conceptually distinct stages which manipulate these
+data structures, and the blue components are important helper classes.
+
+.. image:: DriverArchitecture.png
+ :align: center
+ :alt: Driver Architecture Diagram
+
+Driver Stages
+-------------
+
+The driver functionality is conceptually divided into five stages:
+
+#. **Parse: Option Parsing**
+
+ The command line argument strings are decomposed into arguments
+ (``Arg`` instances). The driver expects to understand all available
+ options, although there is some facility for just passing certain
+ classes of options through (like ``-Wl,``).
+
+ Each argument corresponds to exactly one abstract ``Option``
+ definition, which describes how the option is parsed along with some
+ additional metadata. The Arg instances themselves are lightweight and
+ merely contain enough information for clients to determine which
+ option they correspond to and their values (if they have additional
+ parameters).
+
+ For example, a command line like "-Ifoo -I foo" would parse to two
+ Arg instances (a JoinedArg and a SeparateArg instance), but each
+ would refer to the same Option.
+
+ Options are lazily created in order to avoid populating all Option
+ classes when the driver is loaded. Most of the driver code only needs
+ to deal with options by their unique ID (e.g., ``options::OPT_I``),
+
+ Arg instances themselves do not generally store the values of
+ parameters. In many cases, this would simply result in creating
+ unnecessary string copies. Instead, Arg instances are always embedded
+ inside an ArgList structure, which contains the original vector of
+ argument strings. Each Arg itself only needs to contain an index into
+ this vector instead of storing its values directly.
+
+ The clang driver can dump the results of this stage using the
+ ``-ccc-print-options`` flag (which must precede any actual command
+ line arguments). For example:
+
+ .. code-block:: console
+
+ $ clang -ccc-print-options -Xarch_i386 -fomit-frame-pointer -Wa,-fast -Ifoo -I foo t.c
+ Option 0 - Name: "-Xarch_", Values: {"i386", "-fomit-frame-pointer"}
+ Option 1 - Name: "-Wa,", Values: {"-fast"}
+ Option 2 - Name: "-I", Values: {"foo"}
+ Option 3 - Name: "-I", Values: {"foo"}
+ Option 4 - Name: "<input>", Values: {"t.c"}
+
+ After this stage is complete the command line should be broken down
+ into well defined option objects with their appropriate parameters.
+ Subsequent stages should rarely, if ever, need to do any string
+ processing.
+
+#. **Pipeline: Compilation Job Construction**
+
+ Once the arguments are parsed, the tree of subprocess jobs needed for
+ the desired compilation sequence are constructed. This involves
+ determining the input files and their types, what work is to be done
+ on them (preprocess, compile, assemble, link, etc.), and constructing
+ a list of Action instances for each task. The result is a list of one
+ or more top-level actions, each of which generally corresponds to a
+ single output (for example, an object or linked executable).
+
+ The majority of Actions correspond to actual tasks, however there are
+ two special Actions. The first is InputAction, which simply serves to
+ adapt an input argument for use as an input to other Actions. The
+ second is BindArchAction, which conceptually alters the architecture
+ to be used for all of its input Actions.
+
+ The clang driver can dump the results of this stage using the
+ ``-ccc-print-phases`` flag. For example:
+
+ .. code-block:: console
+
+ $ clang -ccc-print-phases -x c t.c -x assembler t.s
+ 0: input, "t.c", c
+ 1: preprocessor, {0}, cpp-output
+ 2: compiler, {1}, assembler
+ 3: assembler, {2}, object
+ 4: input, "t.s", assembler
+ 5: assembler, {4}, object
+ 6: linker, {3, 5}, image
+
+ Here the driver is constructing seven distinct actions, four to
+ compile the "t.c" input into an object file, two to assemble the
+ "t.s" input, and one to link them together.
+
+ A rather different compilation pipeline is shown here; in this
+ example there are two top level actions to compile the input files
+ into two separate object files, where each object file is built using
+ ``lipo`` to merge results built for two separate architectures.
+
+ .. code-block:: console
+
+ $ clang -ccc-print-phases -c -arch i386 -arch x86_64 t0.c t1.c
+ 0: input, "t0.c", c
+ 1: preprocessor, {0}, cpp-output
+ 2: compiler, {1}, assembler
+ 3: assembler, {2}, object
+ 4: bind-arch, "i386", {3}, object
+ 5: bind-arch, "x86_64", {3}, object
+ 6: lipo, {4, 5}, object
+ 7: input, "t1.c", c
+ 8: preprocessor, {7}, cpp-output
+ 9: compiler, {8}, assembler
+ 10: assembler, {9}, object
+ 11: bind-arch, "i386", {10}, object
+ 12: bind-arch, "x86_64", {10}, object
+ 13: lipo, {11, 12}, object
+
+ After this stage is complete the compilation process is divided into
+ a simple set of actions which need to be performed to produce
+ intermediate or final outputs (in some cases, like ``-fsyntax-only``,
+ there is no "real" final output). Phases are well known compilation
+ steps, such as "preprocess", "compile", "assemble", "link", etc.
+
+#. **Bind: Tool & Filename Selection**
+
+ This stage (in conjunction with the Translate stage) turns the tree
+ of Actions into a list of actual subprocess to run. Conceptually, the
+ driver performs a top down matching to assign Action(s) to Tools. The
+ ToolChain is responsible for selecting the tool to perform a
+ particular action; once selected the driver interacts with the tool
+ to see if it can match additional actions (for example, by having an
+ integrated preprocessor).
+
+ Once Tools have been selected for all actions, the driver determines
+ how the tools should be connected (for example, using an inprocess
+ module, pipes, temporary files, or user provided filenames). If an
+ output file is required, the driver also computes the appropriate
+ file name (the suffix and file location depend on the input types and
+ options such as ``-save-temps``).
+
+ The driver interacts with a ToolChain to perform the Tool bindings.
+ Each ToolChain contains information about all the tools needed for
+ compilation for a particular architecture, platform, and operating
+ system. A single driver invocation may query multiple ToolChains
+ during one compilation in order to interact with tools for separate
+ architectures.
+
+ The results of this stage are not computed directly, but the driver
+ can print the results via the ``-ccc-print-bindings`` option. For
+ example:
+
+ .. code-block:: console
+
+ $ clang -ccc-print-bindings -arch i386 -arch ppc t0.c
+ # "i386-apple-darwin9" - "clang", inputs: ["t0.c"], output: "/tmp/cc-Sn4RKF.s"
+ # "i386-apple-darwin9" - "darwin::Assemble", inputs: ["/tmp/cc-Sn4RKF.s"], output: "/tmp/cc-gvSnbS.o"
+ # "i386-apple-darwin9" - "darwin::Link", inputs: ["/tmp/cc-gvSnbS.o"], output: "/tmp/cc-jgHQxi.out"
+ # "ppc-apple-darwin9" - "gcc::Compile", inputs: ["t0.c"], output: "/tmp/cc-Q0bTox.s"
+ # "ppc-apple-darwin9" - "gcc::Assemble", inputs: ["/tmp/cc-Q0bTox.s"], output: "/tmp/cc-WCdicw.o"
+ # "ppc-apple-darwin9" - "gcc::Link", inputs: ["/tmp/cc-WCdicw.o"], output: "/tmp/cc-HHBEBh.out"
+ # "i386-apple-darwin9" - "darwin::Lipo", inputs: ["/tmp/cc-jgHQxi.out", "/tmp/cc-HHBEBh.out"], output: "a.out"
+
+ This shows the tool chain, tool, inputs and outputs which have been
+ bound for this compilation sequence. Here clang is being used to
+ compile t0.c on the i386 architecture and darwin specific versions of
+ the tools are being used to assemble and link the result, but generic
+ gcc versions of the tools are being used on PowerPC.
+
+#. **Translate: Tool Specific Argument Translation**
+
+ Once a Tool has been selected to perform a particular Action, the
+ Tool must construct concrete Jobs which will be executed during
+ compilation. The main work is in translating from the gcc style
+ command line options to whatever options the subprocess expects.
+
+ Some tools, such as the assembler, only interact with a handful of
+ arguments and just determine the path of the executable to call and
+ pass on their input and output arguments. Others, like the compiler
+ or the linker, may translate a large number of arguments in addition.
+
+ The ArgList class provides a number of simple helper methods to
+ assist with translating arguments; for example, to pass on only the
+ last of arguments corresponding to some option, or all arguments for
+ an option.
+
+ The result of this stage is a list of Jobs (executable paths and
+ argument strings) to execute.
+
+#. **Execute**
+
+ Finally, the compilation pipeline is executed. This is mostly
+ straightforward, although there is some interaction with options like
+ ``-pipe``, ``-pass-exit-codes`` and ``-time``.
+
+Additional Notes
+----------------
+
+The Compilation Object
+^^^^^^^^^^^^^^^^^^^^^^
+
+The driver constructs a Compilation object for each set of command line
+arguments. The Driver itself is intended to be invariant during
+construction of a Compilation; an IDE should be able to construct a
+single long lived driver instance to use for an entire build, for
+example.
+
+The Compilation object holds information that is particular to each
+compilation sequence. For example, the list of used temporary files
+(which must be removed once compilation is finished) and result files
+(which should be removed if compilation fails).
+
+Unified Parsing & Pipelining
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Parsing and pipelining both occur without reference to a Compilation
+instance. This is by design; the driver expects that both of these
+phases are platform neutral, with a few very well defined exceptions
+such as whether the platform uses a driver driver.
+
+ToolChain Argument Translation
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In order to match gcc very closely, the clang driver currently allows
+tool chains to perform their own translation of the argument list (into
+a new ArgList data structure). Although this allows the clang driver to
+match gcc easily, it also makes the driver operation much harder to
+understand (since the Tools stop seeing some arguments the user
+provided, and see new ones instead).
+
+For example, on Darwin ``-gfull`` gets translated into two separate
+arguments, ``-g`` and ``-fno-eliminate-unused-debug-symbols``. Trying to
+write Tool logic to do something with ``-gfull`` will not work, because
+Tool argument translation is done after the arguments have been
+translated.
+
+A long term goal is to remove this tool chain specific translation, and
+instead force each tool to change its own logic to do the right thing on
+the untranslated original arguments.
+
+Unused Argument Warnings
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+The driver operates by parsing all arguments but giving Tools the
+opportunity to choose which arguments to pass on. One downside of this
+infrastructure is that if the user misspells some option, or is confused
+about which options to use, some command line arguments the user really
+cared about may go unused. This problem is particularly important when
+using clang as a compiler, since the clang compiler does not support
+anywhere near all the options that gcc does, and we want to make sure
+users know which ones are being used.
+
+To support this, the driver maintains a bit associated with each
+argument of whether it has been used (at all) during the compilation.
+This bit usually doesn't need to be set by hand, as the key ArgList
+accessors will set it automatically.
+
+When a compilation is successful (there are no errors), the driver
+checks the bit and emits an "unused argument" warning for any arguments
+which were never accessed. This is conservative (the argument may not
+have been used to do what the user wanted) but still catches the most
+obvious cases.
+
+Relation to GCC Driver Concepts
+-------------------------------
+
+For those familiar with the gcc driver, this section provides a brief
+overview of how things from the gcc driver map to the clang driver.
+
+- **Driver Driver**
+
+ The driver driver is fully integrated into the clang driver. The
+ driver simply constructs additional Actions to bind the architecture
+ during the *Pipeline* phase. The tool chain specific argument
+ translation is responsible for handling ``-Xarch_``.
+
+ The one caveat is that this approach requires ``-Xarch_`` not be used
+ to alter the compilation itself (for example, one cannot provide
+ ``-S`` as an ``-Xarch_`` argument). The driver attempts to reject
+ such invocations, and overall there isn't a good reason to abuse
+ ``-Xarch_`` to that end in practice.
+
+ The upside is that the clang driver is more efficient and does little
+ extra work to support universal builds. It also provides better error
+ reporting and UI consistency.
+
+- **Specs**
+
+ The clang driver has no direct correspondent for "specs". The
+ majority of the functionality that is embedded in specs is in the
+ Tool specific argument translation routines. The parts of specs which
+ control the compilation pipeline are generally part of the *Pipeline*
+ stage.
+
+- **Toolchains**
+
+ The gcc driver has no direct understanding of tool chains. Each gcc
+ binary roughly corresponds to the information which is embedded
+ inside a single ToolChain.
+
+ The clang driver is intended to be portable and support complex
+ compilation environments. All platform and tool chain specific code
+ should be protected behind either abstract or well defined interfaces
+ (such as whether the platform supports use as a driver driver).
diff --git a/docs/ExternalClangExamples.rst b/docs/ExternalClangExamples.rst
new file mode 100644
index 0000000..c7fd4c5
--- /dev/null
+++ b/docs/ExternalClangExamples.rst
@@ -0,0 +1,80 @@
+=======================
+External Clang Examples
+=======================
+
+Introduction
+============
+
+This page provides some examples of the kinds of things that people have
+done with Clang that might serve as useful guides (or starting points) from
+which to develop your own tools. They may be helpful even for something as
+banal (but necessary) as how to set up your build to integrate Clang.
+
+Clang's library-based design is deliberately aimed at facilitating use by
+external projects, and we are always interested in improving Clang to
+better serve our external users. Some typical categories of applications
+where Clang is used are:
+
+- Static analysis.
+- Documentation/cross-reference generation.
+
+If you know of (or wrote!) a tool or project using Clang, please send an
+email to Clang's `development discussion mailing list
+<http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev>`_ to have it added.
+(or if you are already a Clang contributor, feel free to directly commit
+additions). Since the primary purpose of this page is to provide examples
+that can help developers, generally they must have code available.
+
+List of projects and tools
+==========================
+
+`<https://github.com/Andersbakken/rtags/>`_
+ "RTags is a client/server application that indexes c/c++ code and keeps
+ a persistent in-memory database of references, symbolnames, completions
+ etc."
+
+`<http://rprichard.github.com/sourceweb/>`_
+ "A C/C++ source code indexer and navigator"
+
+`<https://github.com/etaoins/qconnectlint>`_
+ "qconnectlint is a Clang tool for statically verifying the consistency
+ of signal and slot connections made with Qt's ``QObject::connect``."
+
+`<https://github.com/woboq/woboq_codebrowser>`_
+ "The Woboq Code Browser is a web-based code browser for C/C++ projects.
+ Check out `<http://code.woboq.org/>`_ for an example!"
+
+`<https://github.com/mozilla/dxr>`_
+ "DXR is a source code cross-reference tool that uses static analysis
+ data collected by instrumented compilers."
+
+`<https://github.com/eschulte/clang-mutate>`_
+ "This tool performs a number of operations on C-language source files."
+
+`<https://github.com/gmarpons/Crisp>`_
+ "A coding rule validation add-on for LLVM/clang. Crisp rules are written
+ in Prolog. A high-level declarative DSL to easily write new rules is under
+ development. It will be called CRISP, an acronym for *Coding Rules in
+ Sugared Prolog*."
+
+`<https://github.com/drothlis/clang-ctags>`_
+ "Generate tag file for C++ source code."
+
+`<https://github.com/exclipy/clang_indexer>`_
+ "This is an indexer for C and C++ based on the libclang library."
+
+`<https://github.com/holtgrewe/linty>`_
+ "Linty - C/C++ Style Checking with Python & libclang."
+
+`<https://github.com/axw/cmonster>`_
+ "cmonster is a Python wrapper for the Clang C++ parser."
+
+`<https://github.com/rizsotto/Constantine>`_
+ "Constantine is a toy project to learn how to write clang plugin.
+ Implements pseudo const analysis. Generates warnings about variables,
+ which were declared without const qualifier."
+
+`<https://github.com/jessevdk/cldoc>`_
+ "cldoc is a Clang based documentation generator for C and C++.
+ cldoc tries to solve the issue of writing C/C++ software documentation
+ with a modern, non-intrusive and robust approach."
diff --git a/docs/FAQ.rst b/docs/FAQ.rst
new file mode 100644
index 0000000..4c4f8a8
--- /dev/null
+++ b/docs/FAQ.rst
@@ -0,0 +1,64 @@
+================================
+Frequently Asked Questions (FAQ)
+================================
+
+.. contents::
+ :local:
+
+Driver
+======
+
+I run ``clang -cc1 ...`` and get weird errors about missing headers
+-------------------------------------------------------------------
+
+Given this source file:
+
+.. code-block:: c
+
+ #include <stdio.h>
+
+ int main() {
+ printf("Hello world\n");
+ }
+
+
+If you run:
+
+.. code-block:: console
+
+ $ clang -cc1 hello.c
+ hello.c:1:10: fatal error: 'stdio.h' file not found
+ #include <stdio.h>
+ ^
+ 1 error generated.
+
+``clang -cc1`` is the frontend, ``clang`` is the :doc:`driver
+<DriverInternals>`. The driver invokes the frontend with options appropriate
+for your system. To see these options, run:
+
+.. code-block:: console
+
+ $ clang -### -c hello.c
+
+Some clang command line options are driver-only options, some are frontend-only
+options. Frontend-only options are intended to be used only by clang developers.
+Users should not run ``clang -cc1`` directly, because ``-cc1`` options are not
+guaranteed to be stable.
+
+If you want to use a frontend-only option ("a ``-cc1`` option"), for example
+``-ast-dump``, then you need to take the ``clang -cc1`` line generated by the
+driver and add the option you need. Alternatively, you can run
+``clang -Xclang <option> ...`` to force the driver pass ``<option>`` to
+``clang -cc1``.
+
+I get errors about some headers being missing (``stddef.h``, ``stdarg.h``)
+--------------------------------------------------------------------------
+
+Some header files (``stddef.h``, ``stdarg.h``, and others) are shipped with
+Clang --- these are called builtin includes. Clang searches for them in a
+directory relative to the location of the ``clang`` binary. If you moved the
+``clang`` binary, you need to move the builtin headers, too.
+
+More information can be found in the :ref:`libtooling_builtin_includes`
+section.
+
diff --git a/docs/HowToSetupToolingForLLVM.html b/docs/HowToSetupToolingForLLVM.html
deleted file mode 100644
index 022ed9c..0000000
--- a/docs/HowToSetupToolingForLLVM.html
+++ /dev/null
@@ -1,212 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
-<title>How To Setup Clang Tooling For LLVM</title>
-<link type="text/css" rel="stylesheet" href="../menu.css">
-<link type="text/css" rel="stylesheet" href="../content.css">
-</head>
-<body>
-
-<!--#include virtual="../menu.html.incl"-->
-
-<div id="content">
-
-<h1>How To Setup Clang Tooling For LLVM</h1>
-<p>Clang Tooling provides infrastructure to write tools that need syntactic and
-semantic infomation about a program. This term also relates to a set of specific
-tools using this infrastructure (e.g. <code>clang-check</code>). This document
-provides information on how to set up and use Clang Tooling for the LLVM source
-code.</p>
-
-
-<!-- ======================================================================= -->
-<h2><a name="introduction">Introduction</a></h2>
-<!-- ======================================================================= -->
-
-<p>Clang Tooling needs a compilation database to figure out specific build
-options for each file. Currently it can create a compilation database from the
-<code>compilation_commands.json</code> file, generated by CMake. When invoking
-clang tools, you can either specify a path to a build directory using a command
-line parameter <code>-p</code> or let Clang Tooling find this file in your
-source tree. In either case you need to configure your build using CMake to use
-clang tools.</p>
-
-<!-- ======================================================================= -->
-<h2><a name="using-make">Setup Clang Tooling Using CMake and Make</a></h2>
-<!-- ======================================================================= -->
-
-<p>If you intend to use make to build LLVM, you should have CMake 2.8.6 or later
-installed (can be found <a href="http://cmake.org">here</a>).</p>
-<p>First, you need to generate Makefiles for LLVM with CMake. You need to make
-a build directory and run CMake from it:</p>
-<pre>
- mkdir your/build/directory
- cd your/build/directory
- cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON path/to/llvm/sources
-</pre>
-
-<p>If you want to use clang instead of GCC, you can add
-<code>-DCMAKE_C_COMPILER=/path/to/clang
- -DCMAKE_CXX_COMPILER=/path/to/clang++</code>.
-You can also use ccmake, which provides a curses interface to configure CMake
-variables for lazy people.</p>
-
-<p>As a result, the new <code>compile_commands.json</code> file should appear in
-the current directory. You should link it to the LLVM source tree so that Clang
-Tooling is able to use it:</p>
-<pre>
- ln -s $PWD/compile_commands.json path/to/llvm/source/
-</pre>
-
-<p>Now you are ready to build and test LLVM using make:</p>
-<pre>
- make check-all
-</pre>
-
-<!-- ======================================================================= -->
-<h2><a name="using-tools">Using Clang Tools</a></h2>
-<!-- ======================================================================= -->
-
-<p>After you completed the previous steps, you are ready to run clang tools. If
-you have a recent clang installed, you should have <code>clang-check</code> in
-$PATH. Try to run it on any .cpp file inside the LLVM source tree:</p>
-<pre>
- clang-check tools/clang/lib/Tooling/CompilationDatabase.cpp
-</pre>
-<p>If you're using vim, it's convenient to have clang-check integrated. Put this
-into your .vimrc:</p>
-<pre>
-function! ClangCheckImpl(cmd)
- if &amp;autowrite | wall | endif
- echo "Running " . a:cmd . " ..."
- let l:output = system(a:cmd)
- cexpr l:output
- cwindow
- let w:quickfix_title = a:cmd
- if v:shell_error != 0
- cc
- endif
- let g:clang_check_last_cmd = a:cmd
-endfunction
-
-function! ClangCheck()
- let l:filename = expand('%')
- if l:filename =~ '\.\(cpp\|cxx\|cc\|c\)$'
- call ClangCheckImpl("clang-check " . l:filename)
- elseif exists("g:clang_check_last_cmd")
- call ClangCheckImpl(g:clang_check_last_cmd)
- else
- echo "Can't detect file's compilation arguments and no previous clang-check invocation!"
- endif
-endfunction
-
-nmap &lt;silent&gt; &lt;F5&gt; :call ClangCheck()&lt;CR&gt;&lt;CR&gt;
-</pre>
-
-<p>When editing a .cpp/.cxx/.cc/.c file, hit F5 to reparse the file. In case
-the current file has a different extension (for example, .h), F5 will re-run
-the last clang-check invocation made from this vim instance (if any). The
-output will go into the error window, which is opened automatically when
-clang-check finds errors, and can be re-opened with <code>:cope</code>.</p>
-
-<p>Other <code>clang-check</code> options that can be useful when working with
-clang AST:</p>
-<ul>
- <li><code>-ast-print</code> - Build ASTs and then pretty-print them.</li>
- <li><code>-ast-dump</code> - Build ASTs and then debug dump them.</li>
- <li><code>-ast-dump-filter=&lt;string&gt;</code> - Use with
- <code>-ast-dump</code> or <code>-ast-print</code> to dump/print
- only AST declaration nodes having a certain substring in a qualified name.
- Use <code>-ast-list</code> to list all filterable declaration node
- names.</li>
- <li><code>-ast-list</code> - Build ASTs and print the list of declaration
- node qualified names.</li>
-</ul>
-<p>Examples:</p>
-<pre>
-<b>$ clang-check tools/clang/tools/clang-check/ClangCheck.cpp -ast-dump -ast-dump-filter ActionFactory::newASTConsumer</b>
-Processing: tools/clang/tools/clang-check/ClangCheck.cpp.
-Dumping <anonymous namespace>::ActionFactory::newASTConsumer:
-clang::ASTConsumer *newASTConsumer() (CompoundStmt 0x44da290 &lt;/home/alexfh/local/llvm/tools/clang/tools/clang-check/ClangCheck.cpp:64:40, line:72:3&gt;
- (IfStmt 0x44d97c8 &lt;line:65:5, line:66:45&gt;
- &lt;&lt;&lt;NULL&gt;&gt;&gt;
- (ImplicitCastExpr 0x44d96d0 &lt;line:65:9&gt; '_Bool':'_Bool' &lt;UserDefinedConversion&gt;
-...
-<b>$ clang-check tools/clang/tools/clang-check/ClangCheck.cpp -ast-print -ast-dump-filter ActionFactory::newASTConsumer</b>
-Processing: tools/clang/tools/clang-check/ClangCheck.cpp.
-Printing &lt;anonymous namespace&gt;::ActionFactory::newASTConsumer:
-clang::ASTConsumer *newASTConsumer() {
- if (this-&gt;ASTList.operator _Bool())
- return clang::CreateASTDeclNodeLister();
- if (this-&gt;ASTDump.operator _Bool())
- return clang::CreateASTDumper(this-&gt;ASTDumpFilter);
- if (this-&gt;ASTPrint.operator _Bool())
- return clang::CreateASTPrinter(&amp;llvm::outs(), this-&gt;ASTDumpFilter);
- return new clang::ASTConsumer();
-}
-</pre>
-
-<!-- ======================================================================= -->
-<h2><a name="using-ninja">(Experimental) Using Ninja Build System</a></h2>
-<!-- ======================================================================= -->
-
-<p>Optionally you can use the <a
- href="https://github.com/martine/ninja">Ninja</a> build system instead of
-make. It is aimed at making your builds faster. Currently this step will require
-building Ninja from sources and using a development version of CMake.</p>
-<p>To take advantage of using Clang Tools along with Ninja build you need at
-least CMake 2.8.9. At the moment CMake 2.8.9 is still under development, so you
-can get latest development sources and build it yourself:</p>
-<pre>
- git clone git://cmake.org/cmake.git
- cd cmake
- ./bootstrap
- make
- sudo make install
-</pre>
-
-<p>Having the correct version of CMake, you can clone the Ninja git repository
-and build Ninja from sources:</p>
-<pre>
- git clone git://github.com/martine/ninja.git
- cd ninja/
- ./bootstrap.py
-</pre>
-<p>This will result in a single binary <code>ninja</code> in the current
-directory. It doesn't require installation and can just be copied to any
-location inside <code>$PATH</code>, say <code>/usr/local/bin/</code>:</p>
-<pre>
- sudo cp ninja /usr/local/bin/
- sudo chmod a+rx /usr/local/bin/ninja
-</pre>
-<p>After doing all of this, you'll need to generate Ninja build files for LLVM
-with CMake. You need to make a build directory and run CMake from it:</p>
-<pre>
- mkdir your/build/directory
- cd your/build/directory
- cmake -G Ninja -DCMAKE_EXPORT_COMPILE_COMMANDS=ON path/to/llvm/sources
-</pre>
-
-<p>If you want to use clang instead of GCC, you can add
-<code>-DCMAKE_C_COMPILER=/path/to/clang
- -DCMAKE_CXX_COMPILER=/path/to/clang++</code>.
-You can also use ccmake, which provides a curses interface to configure CMake
-variables in an interactive manner.</p>
-
-<p>As a result, the new <code>compile_commands.json</code> file should appear in
-the current directory. You should link it to the LLVM source tree so that Clang
-Tooling is able to use it:</p>
-<pre>
- ln -s $PWD/compile_commands.json path/to/llvm/source/
-</pre>
-
-<p>Now you are ready to build and test LLVM using Ninja:</p>
-<pre>
- ninja check-all
-</pre>
-<p>Other target names can be used in the same way as with make.</p>
-</div>
-</body>
-</html>
-
diff --git a/docs/HowToSetupToolingForLLVM.rst b/docs/HowToSetupToolingForLLVM.rst
new file mode 100644
index 0000000..9247742
--- /dev/null
+++ b/docs/HowToSetupToolingForLLVM.rst
@@ -0,0 +1,199 @@
+===================================
+How To Setup Clang Tooling For LLVM
+===================================
+
+Clang Tooling provides infrastructure to write tools that need syntactic
+and semantic information about a program. This term also relates to a set
+of specific tools using this infrastructure (e.g. ``clang-check``). This
+document provides information on how to set up and use Clang Tooling for
+the LLVM source code.
+
+Introduction
+============
+
+Clang Tooling needs a compilation database to figure out specific build
+options for each file. Currently it can create a compilation database
+from the ``compilation_commands.json`` file, generated by CMake. When
+invoking clang tools, you can either specify a path to a build directory
+using a command line parameter ``-p`` or let Clang Tooling find this
+file in your source tree. In either case you need to configure your
+build using CMake to use clang tools.
+
+Setup Clang Tooling Using CMake and Make
+========================================
+
+If you intend to use make to build LLVM, you should have CMake 2.8.6 or
+later installed (can be found `here <http://cmake.org>`_).
+
+First, you need to generate Makefiles for LLVM with CMake. You need to
+make a build directory and run CMake from it:
+
+.. code-block:: console
+
+ $ mkdir your/build/directory
+ $ cd your/build/directory
+ $ cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON path/to/llvm/sources
+
+If you want to use clang instead of GCC, you can add
+``-DCMAKE_C_COMPILER=/path/to/clang -DCMAKE_CXX_COMPILER=/path/to/clang++``.
+You can also use ``ccmake``, which provides a curses interface to configure
+CMake variables for lazy people.
+
+As a result, the new ``compile_commands.json`` file should appear in the
+current directory. You should link it to the LLVM source tree so that
+Clang Tooling is able to use it:
+
+.. code-block:: console
+
+ $ ln -s $PWD/compile_commands.json path/to/llvm/source/
+
+Now you are ready to build and test LLVM using make:
+
+.. code-block:: console
+
+ $ make check-all
+
+Using Clang Tools
+=================
+
+After you completed the previous steps, you are ready to run clang tools. If
+you have a recent clang installed, you should have ``clang-check`` in
+``$PATH``. Try to run it on any ``.cpp`` file inside the LLVM source tree:
+
+.. code-block:: console
+
+ $ clang-check tools/clang/lib/Tooling/CompilationDatabase.cpp
+
+If you're using vim, it's convenient to have clang-check integrated. Put
+this into your ``.vimrc``:
+
+::
+
+ 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 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:
+
+* ``-ast-print`` --- Build ASTs and then pretty-print them.
+* ``-ast-dump`` --- Build ASTs and then debug dump them.
+* ``-ast-dump-filter=<string>`` --- Use with ``-ast-dump`` or ``-ast-print`` to
+ dump/print only AST declaration nodes having a certain substring in a
+ qualified name. Use ``-ast-list`` to list all filterable declaration node
+ names.
+* ``-ast-list`` --- Build ASTs and print the list of declaration node qualified
+ names.
+
+Examples:
+
+.. code-block:: console
+
+ $ clang-check tools/clang/tools/clang-check/ClangCheck.cpp -ast-dump -ast-dump-filter ActionFactory::newASTConsumer
+ Processing: tools/clang/tools/clang-check/ClangCheck.cpp.
+ Dumping ::ActionFactory::newASTConsumer:
+ clang::ASTConsumer *newASTConsumer() (CompoundStmt 0x44da290 </home/alexfh/local/llvm/tools/clang/tools/clang-check/ClangCheck.cpp:64:40, line:72:3>
+ (IfStmt 0x44d97c8 <line:65:5, line:66:45>
+ <<<NULL>>>
+ (ImplicitCastExpr 0x44d96d0 <line:65:9> '_Bool':'_Bool' <UserDefinedConversion>
+ ...
+ $ clang-check tools/clang/tools/clang-check/ClangCheck.cpp -ast-print -ast-dump-filter ActionFactory::newASTConsumer
+ Processing: tools/clang/tools/clang-check/ClangCheck.cpp.
+ Printing <anonymous namespace>::ActionFactory::newASTConsumer:
+ clang::ASTConsumer *newASTConsumer() {
+ if (this->ASTList.operator _Bool())
+ return clang::CreateASTDeclNodeLister();
+ if (this->ASTDump.operator _Bool())
+ return clang::CreateASTDumper(this->ASTDumpFilter);
+ if (this->ASTPrint.operator _Bool())
+ return clang::CreateASTPrinter(&llvm::outs(), this->ASTDumpFilter);
+ return new clang::ASTConsumer();
+ }
+
+(Experimental) Using Ninja Build System
+=======================================
+
+Optionally you can use the `Ninja <https://github.com/martine/ninja>`_
+build system instead of make. It is aimed at making your builds faster.
+Currently this step will require building Ninja from sources.
+
+To take advantage of using Clang Tools along with Ninja build you need
+at least CMake 2.8.9.
+
+Clone the Ninja git repository and build Ninja from sources:
+
+.. code-block:: console
+
+ $ git clone git://github.com/martine/ninja.git
+ $ cd ninja/
+ $ ./bootstrap.py
+
+This will result in a single binary ``ninja`` in the current directory.
+It doesn't require installation and can just be copied to any location
+inside ``$PATH``, say ``/usr/local/bin/``:
+
+.. code-block:: console
+
+ $ sudo cp ninja /usr/local/bin/
+ $ sudo chmod a+rx /usr/local/bin/ninja
+
+After doing all of this, you'll need to generate Ninja build files for
+LLVM with CMake. You need to make a build directory and run CMake from
+it:
+
+.. code-block:: console
+
+ $ mkdir your/build/directory
+ $ cd your/build/directory
+ $ cmake -G Ninja -DCMAKE_EXPORT_COMPILE_COMMANDS=ON path/to/llvm/sources
+
+If you want to use clang instead of GCC, you can add
+``-DCMAKE_C_COMPILER=/path/to/clang -DCMAKE_CXX_COMPILER=/path/to/clang++``.
+You can also use ``ccmake``, which provides a curses interface to configure
+CMake variables in an interactive manner.
+
+As a result, the new ``compile_commands.json`` file should appear in the
+current directory. You should link it to the LLVM source tree so that
+Clang Tooling is able to use it:
+
+.. code-block:: console
+
+ $ ln -s $PWD/compile_commands.json path/to/llvm/source/
+
+Now you are ready to build and test LLVM using Ninja:
+
+.. code-block:: console
+
+ $ ninja check-all
+
+Other target names can be used in the same way as with make.
+
diff --git a/docs/InternalsManual.html b/docs/InternalsManual.html
deleted file mode 100644
index 57f0631..0000000
--- a/docs/InternalsManual.html
+++ /dev/null
@@ -1,2019 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
-<title>"Clang" CFE Internals Manual</title>
-<link type="text/css" rel="stylesheet" href="../menu.css">
-<link type="text/css" rel="stylesheet" href="../content.css">
-<style type="text/css">
-td {
- vertical-align: top;
-}
-</style>
-</head>
-<body>
-
-<!--#include virtual="../menu.html.incl"-->
-
-<div id="content">
-
-<h1>"Clang" CFE Internals Manual</h1>
-
-<ul>
-<li><a href="#intro">Introduction</a></li>
-<li><a href="#libsupport">LLVM Support Library</a></li>
-<li><a href="#libbasic">The Clang 'Basic' Library</a>
- <ul>
- <li><a href="#Diagnostics">The Diagnostics Subsystem</a></li>
- <li><a href="#SourceLocation">The SourceLocation and SourceManager
- classes</a></li>
- <li><a href="#SourceRange">SourceRange and CharSourceRange</a></li>
- </ul>
-</li>
-<li><a href="#libdriver">The Driver Library</a>
-</li>
-<li><a href="#pch">Precompiled Headers</a>
-<li><a href="#libfrontend">The Frontend Library</a>
-</li>
-<li><a href="#liblex">The Lexer and Preprocessor Library</a>
- <ul>
- <li><a href="#Token">The Token class</a></li>
- <li><a href="#Lexer">The Lexer class</a></li>
- <li><a href="#AnnotationToken">Annotation Tokens</a></li>
- <li><a href="#TokenLexer">The TokenLexer class</a></li>
- <li><a href="#MultipleIncludeOpt">The MultipleIncludeOpt class</a></li>
- </ul>
-</li>
-<li><a href="#libparse">The Parser Library</a>
-</li>
-<li><a href="#libast">The AST Library</a>
- <ul>
- <li><a href="#Type">The Type class and its subclasses</a></li>
- <li><a href="#QualType">The QualType class</a></li>
- <li><a href="#DeclarationName">Declaration names</a></li>
- <li><a href="#DeclContext">Declaration contexts</a>
- <ul>
- <li><a href="#Redeclarations">Redeclarations and Overloads</a></li>
- <li><a href="#LexicalAndSemanticContexts">Lexical and Semantic
- Contexts</a></li>
- <li><a href="#TransparentContexts">Transparent Declaration Contexts</a></li>
- <li><a href="#MultiDeclContext">Multiply-Defined Declaration Contexts</a></li>
- </ul>
- </li>
- <li><a href="#CFG">The CFG class</a></li>
- <li><a href="#Constants">Constant Folding in the Clang AST</a></li>
- </ul>
-</li>
-<li><a href="#Howtos">Howto guides</a>
- <ul>
- <li><a href="#AddingAttributes">How to add an attribute</a></li>
- <li><a href="#AddingExprStmt">How to add a new expression or statement</a></li>
- </ul>
-</li>
-</ul>
-
-
-<!-- ======================================================================= -->
-<h2 id="intro">Introduction</h2>
-<!-- ======================================================================= -->
-
-<p>This document describes some of the more important APIs and internal design
-decisions made in the Clang C front-end. The purpose of this document is to
-both capture some of this high level information and also describe some of the
-design decisions behind it. This is meant for people interested in hacking on
-Clang, not for end-users. The description below is categorized by
-libraries, and does not describe any of the clients of the libraries.</p>
-
-<!-- ======================================================================= -->
-<h2 id="libsupport">LLVM Support Library</h2>
-<!-- ======================================================================= -->
-
-<p>The LLVM libsupport library provides many underlying libraries and
-<a href="http://llvm.org/docs/ProgrammersManual.html">data-structures</a>,
-including command line option processing, various containers and a system
-abstraction layer, which is used for file system access.</p>
-
-<!-- ======================================================================= -->
-<h2 id="libbasic">The Clang 'Basic' Library</h2>
-<!-- ======================================================================= -->
-
-<p>This library certainly needs a better name. The 'basic' library contains a
-number of low-level utilities for tracking and manipulating source buffers,
-locations within the source buffers, diagnostics, tokens, target abstraction,
-and information about the subset of the language being compiled for.</p>
-
-<p>Part of this infrastructure is specific to C (such as the TargetInfo class),
-other parts could be reused for other non-C-based languages (SourceLocation,
-SourceManager, Diagnostics, FileManager). When and if there is future demand
-we can figure out if it makes sense to introduce a new library, move the general
-classes somewhere else, or introduce some other solution.</p>
-
-<p>We describe the roles of these classes in order of their dependencies.</p>
-
-
-<!-- ======================================================================= -->
-<h3 id="Diagnostics">The Diagnostics Subsystem</h3>
-<!-- ======================================================================= -->
-
-<p>The Clang Diagnostics subsystem is an important part of how the compiler
-communicates with the human. Diagnostics are the warnings and errors produced
-when the code is incorrect or dubious. In Clang, each diagnostic produced has
-(at the minimum) a unique ID, an English translation associated with it, a <a
-href="#SourceLocation">SourceLocation</a> to "put the caret", and a severity (e.g.
-<tt>WARNING</tt> or <tt>ERROR</tt>). They can also optionally include a number
-of arguments to the dianostic (which fill in "%0"'s in the string) as well as a
-number of source ranges that related to the diagnostic.</p>
-
-<p>In this section, we'll be giving examples produced by the Clang command line
-driver, but diagnostics can be <a href="#DiagnosticClient">rendered in many
-different ways</a> depending on how the DiagnosticClient interface is
-implemented. A representative example of a diagnostic is:</p>
-
-<pre>
-t.c:38:15: error: invalid operands to binary expression ('int *' and '_Complex float')
- <span style="color:darkgreen">P = (P-42) + Gamma*4;</span>
- <span style="color:blue">~~~~~~ ^ ~~~~~~~</span>
-</pre>
-
-<p>In this example, you can see the English translation, the severity (error),
-you can see the source location (the caret ("^") and file/line/column info),
-the source ranges "~~~~", arguments to the diagnostic ("int*" and "_Complex
-float"). You'll have to believe me that there is a unique ID backing the
-diagnostic :).</p>
-
-<p>Getting all of this to happen has several steps and involves many moving
-pieces, this section describes them and talks about best practices when adding
-a new diagnostic.</p>
-
-<!-- ============================= -->
-<h4>The Diagnostic*Kinds.td files</h4>
-<!-- ============================= -->
-
-<p>Diagnostics are created by adding an entry to one of the <tt>
-clang/Basic/Diagnostic*Kinds.td</tt> files, depending on what library will
-be using it. From this file, tblgen generates the unique ID of the diagnostic,
-the severity of the diagnostic and the English translation + format string.</p>
-
-<p>There is little sanity with the naming of the unique ID's right now. Some
-start with err_, warn_, ext_ to encode the severity into the name. Since the
-enum is referenced in the C++ code that produces the diagnostic, it is somewhat
-useful for it to be reasonably short.</p>
-
-<p>The severity of the diagnostic comes from the set {<tt>NOTE</tt>,
-<tt>WARNING</tt>, <tt>EXTENSION</tt>, <tt>EXTWARN</tt>, <tt>ERROR</tt>}. The
-<tt>ERROR</tt> severity is used for diagnostics indicating the program is never
-acceptable under any circumstances. When an error is emitted, the AST for the
-input code may not be fully built. The <tt>EXTENSION</tt> and <tt>EXTWARN</tt>
-severities are used for extensions to the language that Clang accepts. This
-means that Clang fully understands and can represent them in the AST, but we
-produce diagnostics to tell the user their code is non-portable. The difference
-is that the former are ignored by default, and the later warn by default. The
-<tt>WARNING</tt> severity is used for constructs that are valid in the currently
-selected source language but that are dubious in some way. The <tt>NOTE</tt>
-level is used to staple more information onto previous diagnostics.</p>
-
-<p>These <em>severities</em> are mapped into a smaller set (the
-Diagnostic::Level enum, {<tt>Ignored</tt>, <tt>Note</tt>, <tt>Warning</tt>,
-<tt>Error</tt>, <tt>Fatal</tt> }) of output <em>levels</em> by the diagnostics
-subsystem based on various configuration options. Clang internally supports a
-fully fine grained mapping mechanism that allows you to map almost any
-diagnostic to the output level that you want. The only diagnostics that cannot
-be mapped are <tt>NOTE</tt>s, which always follow the severity of the previously
-emitted diagnostic and <tt>ERROR</tt>s, which can only be mapped to
-<tt>Fatal</tt> (it is not possible to turn an error into a warning,
-for example).</p>
-
-<p>Diagnostic mappings are used in many ways. For example, if the user
-specifies <tt>-pedantic</tt>, <tt>EXTENSION</tt> maps to <tt>Warning</tt>, if
-they specify <tt>-pedantic-errors</tt>, it turns into <tt>Error</tt>. This is
-used to implement options like <tt>-Wunused_macros</tt>, <tt>-Wundef</tt> etc.
-</p>
-
-<p>
-Mapping to <tt>Fatal</tt> should only be used for diagnostics that are
-considered so severe that error recovery won't be able to recover sensibly from
-them (thus spewing a ton of bogus errors). One example of this class of error
-are failure to #include a file.
-</p>
-
-<!-- ================= -->
-<h4>The Format String</h4>
-<!-- ================= -->
-
-<p>The format string for the diagnostic is very simple, but it has some power.
-It takes the form of a string in English with markers that indicate where and
-how arguments to the diagnostic are inserted and formatted. For example, here
-are some simple format strings:</p>
-
-<pre>
- "binary integer literals are an extension"
- "format string contains '\\0' within the string body"
- "more '<b>%%</b>' conversions than data arguments"
- "invalid operands to binary expression (<b>%0</b> and <b>%1</b>)"
- "overloaded '<b>%0</b>' must be a <b>%select{unary|binary|unary or binary}2</b> operator"
- " (has <b>%1</b> parameter<b>%s1</b>)"
-</pre>
-
-<p>These examples show some important points of format strings. You can use any
- plain ASCII character in the diagnostic string except "%" without a problem,
- but these are C strings, so you have to use and be aware of all the C escape
- sequences (as in the second example). If you want to produce a "%" in the
- output, use the "%%" escape sequence, like the third diagnostic. Finally,
- Clang uses the "%...[digit]" sequences to specify where and how arguments to
- the diagnostic are formatted.</p>
-
-<p>Arguments to the diagnostic are numbered according to how they are specified
- by the C++ code that <a href="#producingdiag">produces them</a>, and are
- referenced by <tt>%0</tt> .. <tt>%9</tt>. If you have more than 10 arguments
- to your diagnostic, you are doing something wrong :). Unlike printf, there
- is no requirement that arguments to the diagnostic end up in the output in
- the same order as they are specified, you could have a format string with
- <tt>"%1 %0"</tt> that swaps them, for example. The text in between the
- percent and digit are formatting instructions. If there are no instructions,
- the argument is just turned into a string and substituted in.</p>
-
-<p>Here are some "best practices" for writing the English format string:</p>
-
-<ul>
-<li>Keep the string short. It should ideally fit in the 80 column limit of the
- <tt>DiagnosticKinds.td</tt> file. This avoids the diagnostic wrapping when
- printed, and forces you to think about the important point you are conveying
- with the diagnostic.</li>
-<li>Take advantage of location information. The user will be able to see the
- line and location of the caret, so you don't need to tell them that the
- problem is with the 4th argument to the function: just point to it.</li>
-<li>Do not capitalize the diagnostic string, and do not end it with a
- period.</li>
-<li>If you need to quote something in the diagnostic string, use single
- quotes.</li>
-</ul>
-
-<p>Diagnostics should never take random English strings as arguments: you
-shouldn't use <tt>"you have a problem with %0"</tt> and pass in things like
-<tt>"your argument"</tt> or <tt>"your return value"</tt> as arguments. Doing
-this prevents <a href="#translation">translating</a> the Clang diagnostics to
-other languages (because they'll get random English words in their otherwise
-localized diagnostic). The exceptions to this are C/C++ language keywords
-(e.g. auto, const, mutable, etc) and C/C++ operators (<tt>/=</tt>). Note
-that things like "pointer" and "reference" are not keywords. On the other
-hand, you <em>can</em> include anything that comes from the user's source code,
-including variable names, types, labels, etc. The 'select' format can be
-used to achieve this sort of thing in a localizable way, see below.</p>
-
-<!-- ==================================== -->
-<h4>Formatting a Diagnostic Argument</h4>
-<!-- ==================================== -->
-
-<p>Arguments to diagnostics are fully typed internally, and come from a couple
-different classes: integers, types, names, and random strings. Depending on
-the class of the argument, it can be optionally formatted in different ways.
-This gives the DiagnosticClient information about what the argument means
-without requiring it to use a specific presentation (consider this MVC for
-Clang :).</p>
-
-<p>Here are the different diagnostic argument formats currently supported by
-Clang:</p>
-
-<table>
-<tr><td colspan="2"><b>"s" format</b></td></tr>
-<tr><td>Example:</td><td><tt>"requires %1 parameter%s1"</tt></td></tr>
-<tr><td>Class:</td><td>Integers</td></tr>
-<tr><td>Description:</td><td>This is a simple formatter for integers that is
- useful when producing English diagnostics. When the integer is 1, it prints
- as nothing. When the integer is not 1, it prints as "s". This allows some
- simple grammatical forms to be to be handled correctly, and eliminates the
- need to use gross things like <tt>"requires %1 parameter(s)"</tt>.</td></tr>
-
-<tr><td colspan="2"><b>"select" format</b></td></tr>
-<tr><td>Example:</td><td><tt>"must be a %select{unary|binary|unary or binary}2
- operator"</tt></td></tr>
-<tr><td>Class:</td><td>Integers</td></tr>
-<tr><td>Description:</td><td><p>This format specifier is used to merge multiple
- related diagnostics together into one common one, without requiring the
- difference to be specified as an English string argument. Instead of
- specifying the string, the diagnostic gets an integer argument and the
- format string selects the numbered option. In this case, the "%2" value
- must be an integer in the range [0..2]. If it is 0, it prints 'unary', if
- it is 1 it prints 'binary' if it is 2, it prints 'unary or binary'. This
- allows other language translations to substitute reasonable words (or entire
- phrases) based on the semantics of the diagnostic instead of having to do
- things textually.</p>
- <p>The selected string does undergo formatting.</p></td></tr>
-
-<tr><td colspan="2"><b>"plural" format</b></td></tr>
-<tr><td>Example:</td><td><tt>"you have %1 %plural{1:mouse|:mice}1 connected to
- your computer"</tt></td></tr>
-<tr><td>Class:</td><td>Integers</td></tr>
-<tr><td>Description:</td><td><p>This is a formatter for complex plural forms.
- It is designed to handle even the requirements of languages with very
- complex plural forms, as many Baltic languages have. The argument consists
- of a series of expression/form pairs, separated by ':', where the first form
- whose expression evaluates to true is the result of the modifier.</p>
- <p>An expression can be empty, in which case it is always true. See the
- example at the top. Otherwise, it is a series of one or more numeric
- conditions, separated by ','. If any condition matches, the expression
- matches. Each numeric condition can take one of three forms.</p>
- <ul>
- <li>number: A simple decimal number matches if the argument is the same
- as the number. Example: <tt>"%plural{1:mouse|:mice}4"</tt></li>
- <li>range: A range in square brackets matches if the argument is within
- the range. Then range is inclusive on both ends. Example:
- <tt>"%plural{0:none|1:one|[2,5]:some|:many}2"</tt></li>
- <li>modulo: A modulo operator is followed by a number, and
- equals sign and either a number or a range. The tests are the
- same as for plain
- numbers and ranges, but the argument is taken modulo the number first.
- Example: <tt>"%plural{%100=0:even hundred|%100=[1,50]:lower half|:everything
- else}1"</tt></li>
- </ul>
- <p>The parser is very unforgiving. A syntax error, even whitespace, will
- abort, as will a failure to match the argument against any
- expression.</p></td></tr>
-
-<tr><td colspan="2"><b>"ordinal" format</b></td></tr>
-<tr><td>Example:</td><td><tt>"ambiguity in %ordinal0 argument"</tt></td></tr>
-<tr><td>Class:</td><td>Integers</td></tr>
-<tr><td>Description:</td><td><p>This is a formatter which represents the
- argument number as an ordinal: the value <tt>1</tt> becomes <tt>1st</tt>,
- <tt>3</tt> becomes <tt>3rd</tt>, and so on. Values less than <tt>1</tt>
- are not supported.</p>
- <p>This formatter is currently hard-coded to use English ordinals.</p></td></tr>
-
-<tr><td colspan="2"><b>"objcclass" format</b></td></tr>
-<tr><td>Example:</td><td><tt>"method %objcclass0 not found"</tt></td></tr>
-<tr><td>Class:</td><td>DeclarationName</td></tr>
-<tr><td>Description:</td><td><p>This is a simple formatter that indicates the
- DeclarationName corresponds to an Objective-C class method selector. As
- such, it prints the selector with a leading '+'.</p></td></tr>
-
-<tr><td colspan="2"><b>"objcinstance" format</b></td></tr>
-<tr><td>Example:</td><td><tt>"method %objcinstance0 not found"</tt></td></tr>
-<tr><td>Class:</td><td>DeclarationName</td></tr>
-<tr><td>Description:</td><td><p>This is a simple formatter that indicates the
- DeclarationName corresponds to an Objective-C instance method selector. As
- such, it prints the selector with a leading '-'.</p></td></tr>
-
-<tr><td colspan="2"><b>"q" format</b></td></tr>
-<tr><td>Example:</td><td><tt>"candidate found by name lookup is %q0"</tt></td></tr>
-<tr><td>Class:</td><td>NamedDecl*</td></tr>
-<tr><td>Description</td><td><p>This formatter indicates that the fully-qualified name of the declaration should be printed, e.g., "std::vector" rather than "vector".</p></td></tr>
-
-<tr><td colspan="2"><b>"diff" format</b></td></tr>
-<tr><td>Example:</td><td><tt>"no known conversion %diff{from | to | }1,2"</tt></td></tr>
-<tr><td>Class:</td><td>QualType</td></tr>
-<tr><td>Description</td><td><p>This formatter takes two QualTypes and attempts to print a template difference between the two. If tree printing is off, the text inside the braces before the pipe is printed, with the formatted text replacing the $. If tree printing is on, the text after the pipe is printed and a type tree is printed after the diagnostic message.
-</p></td></tr>
-
-</table>
-
-<p>It is really easy to add format specifiers to the Clang diagnostics system,
-but they should be discussed before they are added. If you are creating a lot
-of repetitive diagnostics and/or have an idea for a useful formatter, please
-bring it up on the cfe-dev mailing list.</p>
-
-<!-- ===================================================== -->
-<h4 id="producingdiag">Producing the Diagnostic</h4>
-<!-- ===================================================== -->
-
-<p>Now that you've created the diagnostic in the DiagnosticKinds.td file, you
-need to write the code that detects the condition in question and emits the
-new diagnostic. Various components of Clang (e.g. the preprocessor, Sema,
-etc) provide a helper function named "Diag". It creates a diagnostic and
-accepts the arguments, ranges, and other information that goes along with
-it.</p>
-
-<p>For example, the binary expression error comes from code like this:</p>
-
-<pre>
- if (various things that are bad)
- Diag(Loc, diag::err_typecheck_invalid_operands)
- &lt;&lt; lex-&gt;getType() &lt;&lt; rex-&gt;getType()
- &lt;&lt; lex-&gt;getSourceRange() &lt;&lt; rex-&gt;getSourceRange();
-</pre>
-
-<p>This shows that use of the Diag method: they take a location (a <a
-href="#SourceLocation">SourceLocation</a> object) and a diagnostic enum value
-(which matches the name from DiagnosticKinds.td). If the diagnostic takes
-arguments, they are specified with the &lt;&lt; operator: the first argument
-becomes %0, the second becomes %1, etc. The diagnostic interface allows you to
-specify arguments of many different types, including <tt>int</tt> and
-<tt>unsigned</tt> for integer arguments, <tt>const char*</tt> and
-<tt>std::string</tt> for string arguments, <tt>DeclarationName</tt> and
-<tt>const IdentifierInfo*</tt> for names, <tt>QualType</tt> for types, etc.
-SourceRanges are also specified with the &lt;&lt; operator, but do not have a
-specific ordering requirement.</p>
-
-<p>As you can see, adding and producing a diagnostic is pretty straightforward.
-The hard part is deciding exactly what you need to say to help the user, picking
-a suitable wording, and providing the information needed to format it correctly.
-The good news is that the call site that issues a diagnostic should be
-completely independent of how the diagnostic is formatted and in what language
-it is rendered.
-</p>
-
-<!-- ==================================================== -->
-<h4 id="fix-it-hints">Fix-It Hints</h4>
-<!-- ==================================================== -->
-
-<p>In some cases, the front end emits diagnostics when it is clear
-that some small change to the source code would fix the problem. For
-example, a missing semicolon at the end of a statement or a use of
-deprecated syntax that is easily rewritten into a more modern form.
-Clang tries very hard to emit the diagnostic and recover gracefully
-in these and other cases.</p>
-
-<p>However, for these cases where the fix is obvious, the diagnostic
-can be annotated with a hint (referred to as a "fix-it hint") that
-describes how to change the code referenced by the diagnostic to fix
-the problem. For example, it might add the missing semicolon at the
-end of the statement or rewrite the use of a deprecated construct
-into something more palatable. Here is one such example from the C++
-front end, where we warn about the right-shift operator changing
-meaning from C++98 to C++11:</p>
-
-<pre>
-test.cpp:3:7: warning: use of right-shift operator ('&gt;&gt;') in template argument will require parentheses in C++11
-A&lt;100 &gt;&gt; 2&gt; *a;
- ^
- ( )
-</pre>
-
-<p>Here, the fix-it hint is suggesting that parentheses be added,
-and showing exactly where those parentheses would be inserted into the
-source code. The fix-it hints themselves describe what changes to make
-to the source code in an abstract manner, which the text diagnostic
-printer renders as a line of "insertions" below the caret line. <a
-href="#DiagnosticClient">Other diagnostic clients</a> might choose
-to render the code differently (e.g., as markup inline) or even give
-the user the ability to automatically fix the problem.</p>
-
-<p>Fix-it hints on errors and warnings need to obey these rules:</p>
-
-<ul>
-<li>Since they are automatically applied if <code>-Xclang -fixit</code>
-is passed to the driver, they should only be used when it's very likely they
-match the user's intent.</li>
-<li>Clang must recover from errors as if the fix-it had been applied.</li>
-</ul>
-
-<p>If a fix-it can't obey these rules, put the fix-it on a note. Fix-its on
-notes are not applied automatically.</p>
-
-<p>All fix-it hints are described by the <code>FixItHint</code> class,
-instances of which should be attached to the diagnostic using the
-&lt;&lt; operator in the same way that highlighted source ranges and
-arguments are passed to the diagnostic. Fix-it hints can be created
-with one of three constructors:</p>
-
-<dl>
- <dt><code>FixItHint::CreateInsertion(Loc, Code)</code></dt>
- <dd>Specifies that the given <code>Code</code> (a string) should be inserted
- before the source location <code>Loc</code>.</dd>
-
- <dt><code>FixItHint::CreateRemoval(Range)</code></dt>
- <dd>Specifies that the code in the given source <code>Range</code>
- should be removed.</dd>
-
- <dt><code>FixItHint::CreateReplacement(Range, Code)</code></dt>
- <dd>Specifies that the code in the given source <code>Range</code>
- should be removed, and replaced with the given <code>Code</code> string.</dd>
-</dl>
-
-<!-- ============================================================= -->
-<h4><a name="DiagnosticClient">The DiagnosticClient Interface</a></h4>
-<!-- ============================================================= -->
-
-<p>Once code generates a diagnostic with all of the arguments and the rest of
-the relevant information, Clang needs to know what to do with it. As previously
-mentioned, the diagnostic machinery goes through some filtering to map a
-severity onto a diagnostic level, then (assuming the diagnostic is not mapped to
-"<tt>Ignore</tt>") it invokes an object that implements the DiagnosticClient
-interface with the information.</p>
-
-<p>It is possible to implement this interface in many different ways. For
-example, the normal Clang DiagnosticClient (named 'TextDiagnosticPrinter') turns
-the arguments into strings (according to the various formatting rules), prints
-out the file/line/column information and the string, then prints out the line of
-code, the source ranges, and the caret. However, this behavior isn't required.
-</p>
-
-<p>Another implementation of the DiagnosticClient interface is the
-'TextDiagnosticBuffer' class, which is used when Clang is in -verify mode.
-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. Full documentation for the -verify mode can be
-found in the Clang API documentation for VerifyDiagnosticConsumer, <a
-href="/doxygen/classclang_1_1VerifyDiagnosticConsumer.html#details">here</a>.
-</p>
-
-<p>There are many other possible implementations of this interface, and this is
-why we prefer diagnostics to pass down rich structured information in arguments.
-For example, an HTML output might want declaration names be linkified to where
-they come from in the source. Another example is that a GUI might let you click
-on typedefs to expand them. This application would want to pass significantly
-more information about types through to the GUI than a simple flat string. The
-interface allows this to happen.</p>
-
-<!-- ====================================================== -->
-<h4><a name="translation">Adding Translations to Clang</a></h4>
-<!-- ====================================================== -->
-
-<p>Not possible yet! Diagnostic strings should be written in UTF-8, the client
-can translate to the relevant code page if needed. Each translation completely
-replaces the format string for the diagnostic.</p>
-
-
-<!-- ======================================================================= -->
-<h3 id="SourceLocation">The SourceLocation and SourceManager classes</h3>
-<!-- ======================================================================= -->
-
-<p>Strangely enough, the SourceLocation class represents a location within the
-source code of the program. Important design points include:</p>
-
-<ol>
-<li>sizeof(SourceLocation) must be extremely small, as these are embedded into
- many AST nodes and are passed around often. Currently it is 32 bits.</li>
-<li>SourceLocation must be a simple value object that can be efficiently
- copied.</li>
-<li>We should be able to represent a source location for any byte of any input
- file. This includes in the middle of tokens, in whitespace, in trigraphs,
- etc.</li>
-<li>A SourceLocation must encode the current #include stack that was active when
- the location was processed. For example, if the location corresponds to a
- token, it should contain the set of #includes active when the token was
- lexed. This allows us to print the #include stack for a diagnostic.</li>
-<li>SourceLocation must be able to describe macro expansions, capturing both
- the ultimate instantiation point and the source of the original character
- data.</li>
-</ol>
-
-<p>In practice, the SourceLocation works together with the SourceManager class
-to encode two pieces of information about a location: its spelling location
-and its instantiation location. For most tokens, these will be the same.
-However, for a macro expansion (or tokens that came from a _Pragma directive)
-these will describe the location of the characters corresponding to the token
-and the location where the token was used (i.e. the macro instantiation point
-or the location of the _Pragma itself).</p>
-
-<p>The Clang front-end inherently depends on the location of a token being
-tracked correctly. If it is ever incorrect, the front-end may get confused and
-die. The reason for this is that the notion of the 'spelling' of a Token in
-Clang depends on being able to find the original input characters for the token.
-This concept maps directly to the "spelling location" for the token.</p>
-
-
-<!-- ======================================================================= -->
-<h3 id="SourceRange">SourceRange and CharSourceRange</h3>
-<!-- ======================================================================= -->
-<!-- mostly taken from
- http://lists.cs.uiuc.edu/pipermail/cfe-dev/2010-August/010595.html -->
-
-<p>Clang represents most source ranges by [first, last], where first and last
-each point to the beginning of their respective tokens. For example
-consider the SourceRange of the following statement:</p>
-<pre>
-x = foo + bar;
-^first ^last
-</pre>
-
-<p>To map from this representation to a character-based
-representation, the 'last' location needs to be adjusted to point to
-(or past) the end of that token with either
-<code>Lexer::MeasureTokenLength()</code> or
-<code>Lexer::getLocForEndOfToken()</code>. For the rare cases
-where character-level source ranges information is needed we use
-the <code>CharSourceRange</code> class.</p>
-
-
-<!-- ======================================================================= -->
-<h2 id="libdriver">The Driver Library</h2>
-<!-- ======================================================================= -->
-
-<p>The clang Driver and library are documented <a
-href="DriverInternals.html">here</a>.<p>
-
-<!-- ======================================================================= -->
-<h2 id="pch">Precompiled Headers</h2>
-<!-- ======================================================================= -->
-
-<p>Clang supports two implementations of precompiled headers. The
- default implementation, precompiled headers (<a
- href="PCHInternals.html">PCH</a>) uses a serialized representation
- of Clang's internal data structures, encoded with the <a
- href="http://llvm.org/docs/BitCodeFormat.html">LLVM bitstream
- format</a>. Pretokenized headers (<a
- href="PTHInternals.html">PTH</a>), on the other hand, contain a
- serialized representation of the tokens encountered when
- preprocessing a header (and anything that header includes).</p>
-
-
-<!-- ======================================================================= -->
-<h2 id="libfrontend">The Frontend Library</h2>
-<!-- ======================================================================= -->
-
-<p>The Frontend library contains functionality useful for building
-tools on top of the clang libraries, for example several methods for
-outputting diagnostics.</p>
-
-<!-- ======================================================================= -->
-<h2 id="liblex">The Lexer and Preprocessor Library</h2>
-<!-- ======================================================================= -->
-
-<p>The Lexer library contains several tightly-connected classes that are involved
-with the nasty process of lexing and preprocessing C source code. The main
-interface to this library for outside clients is the large <a
-href="#Preprocessor">Preprocessor</a> class.
-It contains the various pieces of state that are required to coherently read
-tokens out of a translation unit.</p>
-
-<p>The core interface to the Preprocessor object (once it is set up) is the
-Preprocessor::Lex method, which returns the next <a href="#Token">Token</a> from
-the preprocessor stream. There are two types of token providers that the
-preprocessor is capable of reading from: a buffer lexer (provided by the <a
-href="#Lexer">Lexer</a> class) and a buffered token stream (provided by the <a
-href="#TokenLexer">TokenLexer</a> class).
-
-
-<!-- ======================================================================= -->
-<h3 id="Token">The Token class</h3>
-<!-- ======================================================================= -->
-
-<p>The Token class is used to represent a single lexed token. Tokens are
-intended to be used by the lexer/preprocess and parser libraries, but are not
-intended to live beyond them (for example, they should not live in the ASTs).<p>
-
-<p>Tokens most often live on the stack (or some other location that is efficient
-to access) as the parser is running, but occasionally do get buffered up. For
-example, macro definitions are stored as a series of tokens, and the C++
-front-end periodically needs to buffer tokens up for tentative parsing and
-various pieces of look-ahead. As such, the size of a Token matter. On a 32-bit
-system, sizeof(Token) is currently 16 bytes.</p>
-
-<p>Tokens occur in two forms: "<a href="#AnnotationToken">Annotation
-Tokens</a>" and normal tokens. Normal tokens are those returned by the lexer,
-annotation tokens represent semantic information and are produced by the parser,
-replacing normal tokens in the token stream. Normal tokens contain the
-following information:</p>
-
-<ul>
-<li><b>A SourceLocation</b> - This indicates the location of the start of the
-token.</li>
-
-<li><b>A length</b> - This stores the length of the token as stored in the
-SourceBuffer. For tokens that include them, this length includes trigraphs and
-escaped newlines which are ignored by later phases of the compiler. By pointing
-into the original source buffer, it is always possible to get the original
-spelling of a token completely accurately.</li>
-
-<li><b>IdentifierInfo</b> - If a token takes the form of an identifier, and if
-identifier lookup was enabled when the token was lexed (e.g. the lexer was not
-reading in 'raw' mode) this contains a pointer to the unique hash value for the
-identifier. Because the lookup happens before keyword identification, this
-field is set even for language keywords like 'for'.</li>
-
-<li><b>TokenKind</b> - This indicates the kind of token as classified by the
-lexer. This includes things like <tt>tok::starequal</tt> (for the "*="
-operator), <tt>tok::ampamp</tt> for the "&amp;&amp;" token, and keyword values
-(e.g. <tt>tok::kw_for</tt>) for identifiers that correspond to keywords. Note
-that some tokens can be spelled multiple ways. For example, C++ supports
-"operator keywords", where things like "and" are treated exactly like the
-"&amp;&amp;" operator. In these cases, the kind value is set to
-<tt>tok::ampamp</tt>, which is good for the parser, which doesn't have to
-consider both forms. For something that cares about which form is used (e.g.
-the preprocessor 'stringize' operator) the spelling indicates the original
-form.</li>
-
-<li><b>Flags</b> - There are currently four flags tracked by the
-lexer/preprocessor system on a per-token basis:
-
- <ol>
- <li><b>StartOfLine</b> - This was the first token that occurred on its input
- source line.</li>
- <li><b>LeadingSpace</b> - There was a space character either immediately
- before the token or transitively before the token as it was expanded
- through a macro. The definition of this flag is very closely defined by
- the stringizing requirements of the preprocessor.</li>
- <li><b>DisableExpand</b> - This flag is used internally to the preprocessor to
- represent identifier tokens which have macro expansion disabled. This
- prevents them from being considered as candidates for macro expansion ever
- in the future.</li>
- <li><b>NeedsCleaning</b> - This flag is set if the original spelling for the
- token includes a trigraph or escaped newline. Since this is uncommon,
- many pieces of code can fast-path on tokens that did not need cleaning.
- </ol>
-</li>
-</ul>
-
-<p>One interesting (and somewhat unusual) aspect of normal tokens is that they
-don't contain any semantic information about the lexed value. For example, if
-the token was a pp-number token, we do not represent the value of the number
-that was lexed (this is left for later pieces of code to decide). Additionally,
-the lexer library has no notion of typedef names vs variable names: both are
-returned as identifiers, and the parser is left to decide whether a specific
-identifier is a typedef or a variable (tracking this requires scope information
-among other things). The parser can do this translation by replacing tokens
-returned by the preprocessor with "Annotation Tokens".</p>
-
-<!-- ======================================================================= -->
-<h3 id="AnnotationToken">Annotation Tokens</h3>
-<!-- ======================================================================= -->
-
-<p>Annotation Tokens are tokens that are synthesized by the parser and injected
-into the preprocessor's token stream (replacing existing tokens) to record
-semantic information found by the parser. For example, if "foo" is found to be
-a typedef, the "foo" <tt>tok::identifier</tt> token is replaced with an
-<tt>tok::annot_typename</tt>. This is useful for a couple of reasons: 1) this
-makes it easy to handle qualified type names (e.g. "foo::bar::baz&lt;42&gt;::t")
-in C++ as a single "token" in the parser. 2) if the parser backtracks, the
-reparse does not need to redo semantic analysis to determine whether a token
-sequence is a variable, type, template, etc.</p>
-
-<p>Annotation Tokens are created by the parser and reinjected into the parser's
-token stream (when backtracking is enabled). Because they can only exist in
-tokens that the preprocessor-proper is done with, it doesn't need to keep around
-flags like "start of line" that the preprocessor uses to do its job.
-Additionally, an annotation token may "cover" a sequence of preprocessor tokens
-(e.g. <tt>a::b::c</tt> is five preprocessor tokens). As such, the valid fields
-of an annotation token are different than the fields for a normal token (but
-they are multiplexed into the normal Token fields):</p>
-
-<ul>
-<li><b>SourceLocation "Location"</b> - The SourceLocation for the annotation
-token indicates the first token replaced by the annotation token. In the example
-above, it would be the location of the "a" identifier.</li>
-
-<li><b>SourceLocation "AnnotationEndLoc"</b> - This holds the location of the
-last token replaced with the annotation token. In the example above, it would
-be the location of the "c" identifier.</li>
-
-<li><b>void* "AnnotationValue"</b> - This contains an opaque object
-that the parser gets from Sema. The parser merely preserves the
-information for Sema to later interpret based on the annotation token
-kind.</li>
-
-<li><b>TokenKind "Kind"</b> - This indicates the kind of Annotation token this
-is. See below for the different valid kinds.</li>
-</ul>
-
-<p>Annotation tokens currently come in three kinds:</p>
-
-<ol>
-<li><b>tok::annot_typename</b>: This annotation token represents a
-resolved typename token that is potentially qualified. The
-AnnotationValue field contains the <tt>QualType</tt> returned by
-Sema::getTypeName(), possibly with source location information
-attached.</li>
-
-<li><b>tok::annot_cxxscope</b>: This annotation token represents a C++
-scope specifier, such as "A::B::". This corresponds to the grammar
-productions "::" and ":: [opt] nested-name-specifier". The
-AnnotationValue pointer is a <tt>NestedNameSpecifier*</tt> returned by
-the Sema::ActOnCXXGlobalScopeSpecifier and
-Sema::ActOnCXXNestedNameSpecifier callbacks.</li>
-
-<li><b>tok::annot_template_id</b>: This annotation token represents a
-C++ template-id such as "foo&lt;int, 4&gt;", where "foo" is the name
-of a template. The AnnotationValue pointer is a pointer to a malloc'd
-TemplateIdAnnotation object. Depending on the context, a parsed
-template-id that names a type might become a typename annotation token
-(if all we care about is the named type, e.g., because it occurs in a
-type specifier) or might remain a template-id token (if we want to
-retain more source location information or produce a new type, e.g.,
-in a declaration of a class template specialization). template-id
-annotation tokens that refer to a type can be "upgraded" to typename
-annotation tokens by the parser.</li>
-
-</ol>
-
-<p>As mentioned above, annotation tokens are not returned by the preprocessor,
-they are formed on demand by the parser. This means that the parser has to be
-aware of cases where an annotation could occur and form it where appropriate.
-This is somewhat similar to how the parser handles Translation Phase 6 of C99:
-String Concatenation (see C99 5.1.1.2). In the case of string concatenation,
-the preprocessor just returns distinct tok::string_literal and
-tok::wide_string_literal tokens and the parser eats a sequence of them wherever
-the grammar indicates that a string literal can occur.</p>
-
-<p>In order to do this, whenever the parser expects a tok::identifier or
-tok::coloncolon, it should call the TryAnnotateTypeOrScopeToken or
-TryAnnotateCXXScopeToken methods to form the annotation token. These methods
-will maximally form the specified annotation tokens and replace the current
-token with them, if applicable. If the current tokens is not valid for an
-annotation token, it will remain an identifier or :: token.</p>
-
-
-
-<!-- ======================================================================= -->
-<h3 id="Lexer">The Lexer class</h3>
-<!-- ======================================================================= -->
-
-<p>The Lexer class provides the mechanics of lexing tokens out of a source
-buffer and deciding what they mean. The Lexer is complicated by the fact that
-it operates on raw buffers that have not had spelling eliminated (this is a
-necessity to get decent performance), but this is countered with careful coding
-as well as standard performance techniques (for example, the comment handling
-code is vectorized on X86 and PowerPC hosts).</p>
-
-<p>The lexer has a couple of interesting modal features:</p>
-
-<ul>
-<li>The lexer can operate in 'raw' mode. This mode has several features that
- make it possible to quickly lex the file (e.g. it stops identifier lookup,
- doesn't specially handle preprocessor tokens, handles EOF differently, etc).
- This mode is used for lexing within an "<tt>#if 0</tt>" block, for
- example.</li>
-<li>The lexer can capture and return comments as tokens. This is required to
- support the -C preprocessor mode, which passes comments through, and is
- used by the diagnostic checker to identifier expect-error annotations.</li>
-<li>The lexer can be in ParsingFilename mode, which happens when preprocessing
- after reading a #include directive. This mode changes the parsing of '&lt;'
- to return an "angled string" instead of a bunch of tokens for each thing
- within the filename.</li>
-<li>When parsing a preprocessor directive (after "<tt>#</tt>") the
- ParsingPreprocessorDirective mode is entered. This changes the parser to
- return EOD at a newline.</li>
-<li>The Lexer uses a LangOptions object to know whether trigraphs are enabled,
- whether C++ or ObjC keywords are recognized, etc.</li>
-</ul>
-
-<p>In addition to these modes, the lexer keeps track of a couple of other
- features that are local to a lexed buffer, which change as the buffer is
- lexed:</p>
-
-<ul>
-<li>The Lexer uses BufferPtr to keep track of the current character being
- lexed.</li>
-<li>The Lexer uses IsAtStartOfLine to keep track of whether the next lexed token
- will start with its "start of line" bit set.</li>
-<li>The Lexer keeps track of the current #if directives that are active (which
- can be nested).</li>
-<li>The Lexer keeps track of an <a href="#MultipleIncludeOpt">
- MultipleIncludeOpt</a> object, which is used to
- detect whether the buffer uses the standard "<tt>#ifndef XX</tt> /
- <tt>#define XX</tt>" idiom to prevent multiple inclusion. If a buffer does,
- subsequent includes can be ignored if the XX macro is defined.</li>
-</ul>
-
-<!-- ======================================================================= -->
-<h3 id="TokenLexer">The TokenLexer class</h3>
-<!-- ======================================================================= -->
-
-<p>The TokenLexer class is a token provider that returns tokens from a list
-of tokens that came from somewhere else. It typically used for two things: 1)
-returning tokens from a macro definition as it is being expanded 2) returning
-tokens from an arbitrary buffer of tokens. The later use is used by _Pragma and
-will most likely be used to handle unbounded look-ahead for the C++ parser.</p>
-
-<!-- ======================================================================= -->
-<h3 id="MultipleIncludeOpt">The MultipleIncludeOpt class</h3>
-<!-- ======================================================================= -->
-
-<p>The MultipleIncludeOpt class implements a really simple little state machine
-that is used to detect the standard "<tt>#ifndef XX</tt> / <tt>#define XX</tt>"
-idiom that people typically use to prevent multiple inclusion of headers. If a
-buffer uses this idiom and is subsequently #include'd, the preprocessor can
-simply check to see whether the guarding condition is defined or not. If so,
-the preprocessor can completely ignore the include of the header.</p>
-
-
-
-<!-- ======================================================================= -->
-<h2 id="libparse">The Parser Library</h2>
-<!-- ======================================================================= -->
-
-<!-- ======================================================================= -->
-<h2 id="libast">The AST Library</h2>
-<!-- ======================================================================= -->
-
-<!-- ======================================================================= -->
-<h3 id="Type">The Type class and its subclasses</h3>
-<!-- ======================================================================= -->
-
-<p>The Type class (and its subclasses) are an important part of the AST. Types
-are accessed through the ASTContext class, which implicitly creates and uniques
-them as they are needed. Types have a couple of non-obvious features: 1) they
-do not capture type qualifiers like const or volatile (See
-<a href="#QualType">QualType</a>), and 2) they implicitly capture typedef
-information. Once created, types are immutable (unlike decls).</p>
-
-<p>Typedefs in C make semantic analysis a bit more complex than it would
-be without them. The issue is that we want to capture typedef information
-and represent it in the AST perfectly, but the semantics of operations need to
-"see through" typedefs. For example, consider this code:</p>
-
-<code>
-void func() {<br>
-&nbsp;&nbsp;typedef int foo;<br>
-&nbsp;&nbsp;foo X, *Y;<br>
-&nbsp;&nbsp;typedef foo* bar;<br>
-&nbsp;&nbsp;bar Z;<br>
-&nbsp;&nbsp;*X; <i>// error</i><br>
-&nbsp;&nbsp;**Y; <i>// error</i><br>
-&nbsp;&nbsp;**Z; <i>// error</i><br>
-}<br>
-</code>
-
-<p>The code above is illegal, and thus we expect there to be diagnostics emitted
-on the annotated lines. In this example, we expect to get:</p>
-
-<pre>
-<b>test.c:6:1: error: indirection requires pointer operand ('foo' invalid)</b>
-*X; // error
-<span style="color:blue">^~</span>
-<b>test.c:7:1: error: indirection requires pointer operand ('foo' invalid)</b>
-**Y; // error
-<span style="color:blue">^~~</span>
-<b>test.c:8:1: error: indirection requires pointer operand ('foo' invalid)</b>
-**Z; // error
-<span style="color:blue">^~~</span>
-</pre>
-
-<p>While this example is somewhat silly, it illustrates the point: we want to
-retain typedef information where possible, so that we can emit errors about
-"<tt>std::string</tt>" instead of "<tt>std::basic_string&lt;char, std:...</tt>".
-Doing this requires properly keeping typedef information (for example, the type
-of "X" is "foo", not "int"), and requires properly propagating it through the
-various operators (for example, the type of *Y is "foo", not "int"). In order
-to retain this information, the type of these expressions is an instance of the
-TypedefType class, which indicates that the type of these expressions is a
-typedef for foo.
-</p>
-
-<p>Representing types like this is great for diagnostics, because the
-user-specified type is always immediately available. There are two problems
-with this: first, various semantic checks need to make judgements about the
-<em>actual structure</em> of a type, ignoring typedefs. Second, we need an
-efficient way to query whether two types are structurally identical to each
-other, ignoring typedefs. The solution to both of these problems is the idea of
-canonical types.</p>
-
-<!-- =============== -->
-<h4>Canonical Types</h4>
-<!-- =============== -->
-
-<p>Every instance of the Type class contains a canonical type pointer. For
-simple types with no typedefs involved (e.g. "<tt>int</tt>", "<tt>int*</tt>",
-"<tt>int**</tt>"), the type just points to itself. For types that have a
-typedef somewhere in their structure (e.g. "<tt>foo</tt>", "<tt>foo*</tt>",
-"<tt>foo**</tt>", "<tt>bar</tt>"), the canonical type pointer points to their
-structurally equivalent type without any typedefs (e.g. "<tt>int</tt>",
-"<tt>int*</tt>", "<tt>int**</tt>", and "<tt>int*</tt>" respectively).</p>
-
-<p>This design provides a constant time operation (dereferencing the canonical
-type pointer) that gives us access to the structure of types. For example,
-we can trivially tell that "bar" and "foo*" are the same type by dereferencing
-their canonical type pointers and doing a pointer comparison (they both point
-to the single "<tt>int*</tt>" type).</p>
-
-<p>Canonical types and typedef types bring up some complexities that must be
-carefully managed. Specifically, the "isa/cast/dyncast" operators generally
-shouldn't be used in code that is inspecting the AST. For example, when type
-checking the indirection operator (unary '*' on a pointer), the type checker
-must verify that the operand has a pointer type. It would not be correct to
-check that with "<tt>isa&lt;PointerType&gt;(SubExpr-&gt;getType())</tt>",
-because this predicate would fail if the subexpression had a typedef type.</p>
-
-<p>The solution to this problem are a set of helper methods on Type, used to
-check their properties. In this case, it would be correct to use
-"<tt>SubExpr-&gt;getType()-&gt;isPointerType()</tt>" to do the check. This
-predicate will return true if the <em>canonical type is a pointer</em>, which is
-true any time the type is structurally a pointer type. The only hard part here
-is remembering not to use the <tt>isa/cast/dyncast</tt> operations.</p>
-
-<p>The second problem we face is how to get access to the pointer type once we
-know it exists. To continue the example, the result type of the indirection
-operator is the pointee type of the subexpression. In order to determine the
-type, we need to get the instance of PointerType that best captures the typedef
-information in the program. If the type of the expression is literally a
-PointerType, we can return that, otherwise we have to dig through the
-typedefs to find the pointer type. For example, if the subexpression had type
-"<tt>foo*</tt>", we could return that type as the result. If the subexpression
-had type "<tt>bar</tt>", we want to return "<tt>foo*</tt>" (note that we do
-<em>not</em> want "<tt>int*</tt>"). In order to provide all of this, Type has
-a getAsPointerType() method that checks whether the type is structurally a
-PointerType and, if so, returns the best one. If not, it returns a null
-pointer.</p>
-
-<p>This structure is somewhat mystical, but after meditating on it, it will
-make sense to you :).</p>
-
-<!-- ======================================================================= -->
-<h3 id="QualType">The QualType class</h3>
-<!-- ======================================================================= -->
-
-<p>The QualType class is designed as a trivial value class that is
-small, passed by-value and is efficient to query. The idea of
-QualType is that it stores the type qualifiers (const, volatile,
-restrict, plus some extended qualifiers required by language
-extensions) separately from the types themselves. QualType is
-conceptually a pair of "Type*" and the bits for these type qualifiers.</p>
-
-<p>By storing the type qualifiers as bits in the conceptual pair, it is
-extremely efficient to get the set of qualifiers on a QualType (just return the
-field of the pair), add a type qualifier (which is a trivial constant-time
-operation that sets a bit), and remove one or more type qualifiers (just return
-a QualType with the bitfield set to empty).</p>
-
-<p>Further, because the bits are stored outside of the type itself, we do not
-need to create duplicates of types with different sets of qualifiers (i.e. there
-is only a single heap allocated "int" type: "const int" and "volatile const int"
-both point to the same heap allocated "int" type). This reduces the heap size
-used to represent bits and also means we do not have to consider qualifiers when
-uniquing types (<a href="#Type">Type</a> does not even contain qualifiers).</p>
-
-<p>In practice, the two most common type qualifiers (const and
-restrict) are stored in the low bits of the pointer to the Type
-object, together with a flag indicating whether extended qualifiers
-are present (which must be heap-allocated). This means that QualType
-is exactly the same size as a pointer.</p>
-
-<!-- ======================================================================= -->
-<h3 id="DeclarationName">Declaration names</h3>
-<!-- ======================================================================= -->
-
-<p>The <tt>DeclarationName</tt> class represents the name of a
- declaration in Clang. Declarations in the C family of languages can
- take several different forms. Most declarations are named by
- simple identifiers, e.g., "<code>f</code>" and "<code>x</code>" in
- the function declaration <code>f(int x)</code>. In C++, declaration
- names can also name class constructors ("<code>Class</code>"
- in <code>struct Class { Class(); }</code>), class destructors
- ("<code>~Class</code>"), overloaded operator names ("operator+"),
- and conversion functions ("<code>operator void const *</code>"). In
- Objective-C, declaration names can refer to the names of Objective-C
- methods, which involve the method name and the parameters,
- collectively called a <i>selector</i>, e.g.,
- "<code>setWidth:height:</code>". Since all of these kinds of
- entities - variables, functions, Objective-C methods, C++
- constructors, destructors, and operators - are represented as
- subclasses of Clang's common <code>NamedDecl</code>
- class, <code>DeclarationName</code> is designed to efficiently
- represent any kind of name.</p>
-
-<p>Given
- a <code>DeclarationName</code> <code>N</code>, <code>N.getNameKind()</code>
- will produce a value that describes what kind of name <code>N</code>
- stores. There are 8 options (all of the names are inside
- the <code>DeclarationName</code> class)</p>
-<dl>
- <dt>Identifier</dt>
- <dd>The name is a simple
- identifier. Use <code>N.getAsIdentifierInfo()</code> to retrieve the
- corresponding <code>IdentifierInfo*</code> pointing to the actual
- identifier. Note that C++ overloaded operators (e.g.,
- "<code>operator+</code>") are represented as special kinds of
- identifiers. Use <code>IdentifierInfo</code>'s <code>getOverloadedOperatorID</code>
- function to determine whether an identifier is an overloaded
- operator name.</dd>
-
- <dt>ObjCZeroArgSelector, ObjCOneArgSelector,
- ObjCMultiArgSelector</dt>
- <dd>The name is an Objective-C selector, which can be retrieved as a
- <code>Selector</code> instance
- via <code>N.getObjCSelector()</code>. The three possible name
- kinds for Objective-C reflect an optimization within
- the <code>DeclarationName</code> class: both zero- and
- one-argument selectors are stored as a
- masked <code>IdentifierInfo</code> pointer, and therefore require
- very little space, since zero- and one-argument selectors are far
- more common than multi-argument selectors (which use a different
- structure).</dd>
-
- <dt>CXXConstructorName</dt>
- <dd>The name is a C++ constructor
- name. Use <code>N.getCXXNameType()</code> to retrieve
- the <a href="#QualType">type</a> that this constructor is meant to
- construct. The type is always the canonical type, since all
- constructors for a given type have the same name.</dd>
-
- <dt>CXXDestructorName</dt>
- <dd>The name is a C++ destructor
- name. Use <code>N.getCXXNameType()</code> to retrieve
- the <a href="#QualType">type</a> whose destructor is being
- named. This type is always a canonical type.</dd>
-
- <dt>CXXConversionFunctionName</dt>
- <dd>The name is a C++ conversion function. Conversion functions are
- named according to the type they convert to, e.g., "<code>operator void
- const *</code>". Use <code>N.getCXXNameType()</code> to retrieve
- the type that this conversion function converts to. This type is
- always a canonical type.</dd>
-
- <dt>CXXOperatorName</dt>
- <dd>The name is a C++ overloaded operator name. Overloaded operators
- are named according to their spelling, e.g.,
- "<code>operator+</code>" or "<code>operator new
- []</code>". Use <code>N.getCXXOverloadedOperator()</code> to
- retrieve the overloaded operator (a value of
- type <code>OverloadedOperatorKind</code>).</dd>
-</dl>
-
-<p><code>DeclarationName</code>s are cheap to create, copy, and
- compare. They require only a single pointer's worth of storage in
- the common cases (identifiers, zero-
- and one-argument Objective-C selectors) and use dense, uniqued
- storage for the other kinds of
- names. Two <code>DeclarationName</code>s can be compared for
- equality (<code>==</code>, <code>!=</code>) using a simple bitwise
- comparison, can be ordered
- with <code>&lt;</code>, <code>&gt;</code>, <code>&lt;=</code>,
- and <code>&gt;=</code> (which provide a lexicographical ordering for
- normal identifiers but an unspecified ordering for other kinds of
- names), and can be placed into LLVM <code>DenseMap</code>s
- and <code>DenseSet</code>s.</p>
-
-<p><code>DeclarationName</code> instances can be created in different
- ways depending on what kind of name the instance will store. Normal
- identifiers (<code>IdentifierInfo</code> pointers) and Objective-C selectors
- (<code>Selector</code>) can be implicitly converted
- to <code>DeclarationName</code>s. Names for C++ constructors,
- destructors, conversion functions, and overloaded operators can be retrieved from
- the <code>DeclarationNameTable</code>, an instance of which is
- available as <code>ASTContext::DeclarationNames</code>. The member
- functions <code>getCXXConstructorName</code>, <code>getCXXDestructorName</code>,
- <code>getCXXConversionFunctionName</code>, and <code>getCXXOperatorName</code>, respectively,
- return <code>DeclarationName</code> instances for the four kinds of
- C++ special function names.</p>
-
-<!-- ======================================================================= -->
-<h3 id="DeclContext">Declaration contexts</h3>
-<!-- ======================================================================= -->
-<p>Every declaration in a program exists within some <i>declaration
- context</i>, such as a translation unit, namespace, class, or
- function. Declaration contexts in Clang are represented by
- the <code>DeclContext</code> class, from which the various
- declaration-context AST nodes
- (<code>TranslationUnitDecl</code>, <code>NamespaceDecl</code>, <code>RecordDecl</code>, <code>FunctionDecl</code>,
- etc.) will derive. The <code>DeclContext</code> class provides
- several facilities common to each declaration context:</p>
-<dl>
- <dt>Source-centric vs. Semantics-centric View of Declarations</dt>
- <dd><code>DeclContext</code> provides two views of the declarations
- stored within a declaration context. The source-centric view
- accurately represents the program source code as written, including
- multiple declarations of entities where present (see the
- section <a href="#Redeclarations">Redeclarations and
- Overloads</a>), while the semantics-centric view represents the
- program semantics. The two views are kept synchronized by semantic
- analysis while the ASTs are being constructed.</dd>
-
- <dt>Storage of declarations within that context</dt>
- <dd>Every declaration context can contain some number of
- declarations. For example, a C++ class (represented
- by <code>RecordDecl</code>) contains various member functions,
- fields, nested types, and so on. All of these declarations will be
- stored within the <code>DeclContext</code>, and one can iterate
- over the declarations via
- [<code>DeclContext::decls_begin()</code>,
- <code>DeclContext::decls_end()</code>). This mechanism provides
- the source-centric view of declarations in the context.</dd>
-
- <dt>Lookup of declarations within that context</dt>
- <dd>The <code>DeclContext</code> structure provides efficient name
- lookup for names within that declaration context. For example,
- if <code>N</code> is a namespace we can look for the
- name <code>N::f</code>
- using <code>DeclContext::lookup</code>. The lookup itself is
- based on a lazily-constructed array (for declaration contexts
- with a small number of declarations) or hash table (for
- declaration contexts with more declarations). The lookup
- operation provides the semantics-centric view of the declarations
- in the context.</dd>
-
- <dt>Ownership of declarations</dt>
- <dd>The <code>DeclContext</code> owns all of the declarations that
- were declared within its declaration context, and is responsible
- for the management of their memory as well as their
- (de-)serialization.</dd>
-</dl>
-
-<p>All declarations are stored within a declaration context, and one
- can query
- information about the context in which each declaration lives. One
- can retrieve the <code>DeclContext</code> that contains a
- particular <code>Decl</code>
- using <code>Decl::getDeclContext</code>. However, see the
- section <a href="#LexicalAndSemanticContexts">Lexical and Semantic
- Contexts</a> for more information about how to interpret this
- context information.</p>
-
-<h4 id="Redeclarations">Redeclarations and Overloads</h4>
-<p>Within a translation unit, it is common for an entity to be
-declared several times. For example, we might declare a function "f"
- and then later re-declare it as part of an inlined definition:</p>
-
-<pre>
-void f(int x, int y, int z = 1);
-
-inline void f(int x, int y, int z) { /* ... */ }
-</pre>
-
-<p>The representation of "f" differs in the source-centric and
- semantics-centric views of a declaration context. In the
- source-centric view, all redeclarations will be present, in the
- order they occurred in the source code, making
- this view suitable for clients that wish to see the structure of
- the source code. In the semantics-centric view, only the most recent "f"
- will be found by the lookup, since it effectively replaces the first
- declaration of "f".</p>
-
-<p>In the semantics-centric view, overloading of functions is
- represented explicitly. For example, given two declarations of a
- function "g" that are overloaded, e.g.,</p>
-<pre>
-void g();
-void g(int);
-</pre>
-<p>the <code>DeclContext::lookup</code> operation will return
- a <code>DeclContext::lookup_result</code> that contains a range of iterators
- over declarations of "g". Clients that perform semantic analysis on a
- program that is not concerned with the actual source code will
- primarily use this semantics-centric view.</p>
-
-<h4 id="LexicalAndSemanticContexts">Lexical and Semantic Contexts</h4>
-<p>Each declaration has two potentially different
- declaration contexts: a <i>lexical</i> context, which corresponds to
- the source-centric view of the declaration context, and
- a <i>semantic</i> context, which corresponds to the
- semantics-centric view. The lexical context is accessible
- via <code>Decl::getLexicalDeclContext</code> while the
- semantic context is accessible
- via <code>Decl::getDeclContext</code>, both of which return
- <code>DeclContext</code> pointers. For most declarations, the two
- contexts are identical. For example:</p>
-
-<pre>
-class X {
-public:
- void f(int x);
-};
-</pre>
-
-<p>Here, the semantic and lexical contexts of <code>X::f</code> are
- the <code>DeclContext</code> associated with the
- class <code>X</code> (itself stored as a <code>RecordDecl</code> AST
- node). However, we can now define <code>X::f</code> out-of-line:</p>
-
-<pre>
-void X::f(int x = 17) { /* ... */ }
-</pre>
-
-<p>This definition of has different lexical and semantic
- contexts. The lexical context corresponds to the declaration
- context in which the actual declaration occurred in the source
- code, e.g., the translation unit containing <code>X</code>. Thus,
- this declaration of <code>X::f</code> can be found by traversing
- the declarations provided by
- [<code>decls_begin()</code>, <code>decls_end()</code>) in the
- translation unit.</p>
-
-<p>The semantic context of <code>X::f</code> corresponds to the
- class <code>X</code>, since this member function is (semantically) a
- member of <code>X</code>. Lookup of the name <code>f</code> into
- the <code>DeclContext</code> associated with <code>X</code> will
- then return the definition of <code>X::f</code> (including
- information about the default argument).</p>
-
-<h4 id="TransparentContexts">Transparent Declaration Contexts</h4>
-<p>In C and C++, there are several contexts in which names that are
- logically declared inside another declaration will actually "leak"
- out into the enclosing scope from the perspective of name
- lookup. The most obvious instance of this behavior is in
- enumeration types, e.g.,</p>
-<pre>
-enum Color {
- Red,
- Green,
- Blue
-};
-</pre>
-
-<p>Here, <code>Color</code> is an enumeration, which is a declaration
- context that contains the
- enumerators <code>Red</code>, <code>Green</code>,
- and <code>Blue</code>. Thus, traversing the list of declarations
- contained in the enumeration <code>Color</code> will
- yield <code>Red</code>, <code>Green</code>,
- and <code>Blue</code>. However, outside of the scope
- of <code>Color</code> one can name the enumerator <code>Red</code>
- without qualifying the name, e.g.,</p>
-
-<pre>
-Color c = Red;
-</pre>
-
-<p>There are other entities in C++ that provide similar behavior. For
- example, linkage specifications that use curly braces:</p>
-
-<pre>
-extern "C" {
- void f(int);
- void g(int);
-}
-// f and g are visible here
-</pre>
-
-<p>For source-level accuracy, we treat the linkage specification and
- enumeration type as a
- declaration context in which its enclosed declarations ("Red",
- "Green", and "Blue"; "f" and "g")
- are declared. However, these declarations are visible outside of the
- scope of the declaration context.</p>
-
-<p>These language features (and several others, described below) have
- roughly the same set of
- requirements: declarations are declared within a particular lexical
- context, but the declarations are also found via name lookup in
- scopes enclosing the declaration itself. This feature is implemented
- via <i>transparent</i> declaration contexts
- (see <code>DeclContext::isTransparentContext()</code>), whose
- declarations are visible in the nearest enclosing non-transparent
- declaration context. This means that the lexical context of the
- declaration (e.g., an enumerator) will be the
- transparent <code>DeclContext</code> itself, as will the semantic
- context, but the declaration will be visible in every outer context
- up to and including the first non-transparent declaration context (since
- transparent declaration contexts can be nested).</p>
-
-<p>The transparent <code>DeclContexts</code> are:</p>
-<ul>
- <li>Enumerations (but not C++11 "scoped enumerations"):
- <pre>
-enum Color {
- Red,
- Green,
- Blue
-};
-// Red, Green, and Blue are in scope
- </pre></li>
- <li>C++ linkage specifications:
- <pre>
-extern "C" {
- void f(int);
- void g(int);
-}
-// f and g are in scope
- </pre></li>
- <li>Anonymous unions and structs:
- <pre>
-struct LookupTable {
- bool IsVector;
- union {
- std::vector&lt;Item&gt; *Vector;
- std::set&lt;Item&gt; *Set;
- };
-};
-
-LookupTable LT;
-LT.Vector = 0; // Okay: finds Vector inside the unnamed union
- </pre>
- </li>
- <li>C++11 inline namespaces:
-<pre>
-namespace mylib {
- inline namespace debug {
- class X;
- }
-}
-mylib::X *xp; // okay: mylib::X refers to mylib::debug::X
-</pre>
-</li>
-</ul>
-
-
-<h4 id="MultiDeclContext">Multiply-Defined Declaration Contexts</h4>
-<p>C++ namespaces have the interesting--and, so far, unique--property that
-the namespace can be defined multiple times, and the declarations
-provided by each namespace definition are effectively merged (from
-the semantic point of view). For example, the following two code
-snippets are semantically indistinguishable:</p>
-<pre>
-// Snippet #1:
-namespace N {
- void f();
-}
-namespace N {
- void f(int);
-}
-
-// Snippet #2:
-namespace N {
- void f();
- void f(int);
-}
-</pre>
-
-<p>In Clang's representation, the source-centric view of declaration
- contexts will actually have two separate <code>NamespaceDecl</code>
- nodes in Snippet #1, each of which is a declaration context that
- contains a single declaration of "f". However, the semantics-centric
- view provided by name lookup into the namespace <code>N</code> for
- "f" will return a <code>DeclContext::lookup_result</code> that contains
- a range of iterators over declarations of "f".</p>
-
-<p><code>DeclContext</code> manages multiply-defined declaration
- contexts internally. The
- function <code>DeclContext::getPrimaryContext</code> retrieves the
- "primary" context for a given <code>DeclContext</code> instance,
- which is the <code>DeclContext</code> responsible for maintaining
- the lookup table used for the semantics-centric view. Given the
- primary context, one can follow the chain
- of <code>DeclContext</code> nodes that define additional
- declarations via <code>DeclContext::getNextContext</code>. Note that
- these functions are used internally within the lookup and insertion
- methods of the <code>DeclContext</code>, so the vast majority of
- clients can ignore them.</p>
-
-<!-- ======================================================================= -->
-<h3 id="CFG">The <tt>CFG</tt> class</h3>
-<!-- ======================================================================= -->
-
-<p>The <tt>CFG</tt> class is designed to represent a source-level
-control-flow graph for a single statement (<tt>Stmt*</tt>). Typically
-instances of <tt>CFG</tt> are constructed for function bodies (usually
-an instance of <tt>CompoundStmt</tt>), but can also be instantiated to
-represent the control-flow of any class that subclasses <tt>Stmt</tt>,
-which includes simple expressions. Control-flow graphs are especially
-useful for performing
-<a href="http://en.wikipedia.org/wiki/Data_flow_analysis#Sensitivities">flow-
-or path-sensitive</a> program analyses on a given function.</p>
-
-<!-- ============ -->
-<h4>Basic Blocks</h4>
-<!-- ============ -->
-
-<p>Concretely, an instance of <tt>CFG</tt> is a collection of basic
-blocks. Each basic block is an instance of <tt>CFGBlock</tt>, which
-simply contains an ordered sequence of <tt>Stmt*</tt> (each referring
-to statements in the AST). The ordering of statements within a block
-indicates unconditional flow of control from one statement to the
-next. <a href="#ConditionalControlFlow">Conditional control-flow</a>
-is represented using edges between basic blocks. The statements
-within a given <tt>CFGBlock</tt> can be traversed using
-the <tt>CFGBlock::*iterator</tt> interface.</p>
-
-<p>
-A <tt>CFG</tt> object owns the instances of <tt>CFGBlock</tt> within
-the control-flow graph it represents. Each <tt>CFGBlock</tt> within a
-CFG is also uniquely numbered (accessible
-via <tt>CFGBlock::getBlockID()</tt>). Currently the number is
-based on the ordering the blocks were created, but no assumptions
-should be made on how <tt>CFGBlock</tt>s are numbered other than their
-numbers are unique and that they are numbered from 0..N-1 (where N is
-the number of basic blocks in the CFG).</p>
-
-<!-- ===================== -->
-<h4>Entry and Exit Blocks</h4>
-<!-- ===================== -->
-
-Each instance of <tt>CFG</tt> contains two special blocks:
-an <i>entry</i> block (accessible via <tt>CFG::getEntry()</tt>), which
-has no incoming edges, and an <i>exit</i> block (accessible
-via <tt>CFG::getExit()</tt>), which has no outgoing edges. Neither
-block contains any statements, and they serve the role of providing a
-clear entrance and exit for a body of code such as a function body.
-The presence of these empty blocks greatly simplifies the
-implementation of many analyses built on top of CFGs.
-
-<!-- ===================================================== -->
-<h4 id ="ConditionalControlFlow">Conditional Control-Flow</h4>
-<!-- ===================================================== -->
-
-<p>Conditional control-flow (such as those induced by if-statements
-and loops) is represented as edges between <tt>CFGBlock</tt>s.
-Because different C language constructs can induce control-flow,
-each <tt>CFGBlock</tt> also records an extra <tt>Stmt*</tt> that
-represents the <i>terminator</i> of the block. A terminator is simply
-the statement that caused the control-flow, and is used to identify
-the nature of the conditional control-flow between blocks. For
-example, in the case of an if-statement, the terminator refers to
-the <tt>IfStmt</tt> object in the AST that represented the given
-branch.</p>
-
-<p>To illustrate, consider the following code example:</p>
-
-<code>
-int foo(int x) {<br>
-&nbsp;&nbsp;x = x + 1;<br>
-<br>
-&nbsp;&nbsp;if (x > 2) x++;<br>
-&nbsp;&nbsp;else {<br>
-&nbsp;&nbsp;&nbsp;&nbsp;x += 2;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;x *= 2;<br>
-&nbsp;&nbsp;}<br>
-<br>
-&nbsp;&nbsp;return x;<br>
-}
-</code>
-
-<p>After invoking the parser+semantic analyzer on this code fragment,
-the AST of the body of <tt>foo</tt> is referenced by a
-single <tt>Stmt*</tt>. We can then construct an instance
-of <tt>CFG</tt> representing the control-flow graph of this function
-body by single call to a static class method:</p>
-
-<code>
-&nbsp;&nbsp;Stmt* FooBody = ...<br>
-&nbsp;&nbsp;CFG* FooCFG = <b>CFG::buildCFG</b>(FooBody);
-</code>
-
-<p>It is the responsibility of the caller of <tt>CFG::buildCFG</tt>
-to <tt>delete</tt> the returned <tt>CFG*</tt> when the CFG is no
-longer needed.</p>
-
-<p>Along with providing an interface to iterate over
-its <tt>CFGBlock</tt>s, the <tt>CFG</tt> class also provides methods
-that are useful for debugging and visualizing CFGs. For example, the
-method
-<tt>CFG::dump()</tt> dumps a pretty-printed version of the CFG to
-standard error. This is especially useful when one is using a
-debugger such as gdb. For example, here is the output
-of <tt>FooCFG->dump()</tt>:</p>
-
-<code>
-&nbsp;[ B5 (ENTRY) ]<br>
-&nbsp;&nbsp;&nbsp;&nbsp;Predecessors (0):<br>
-&nbsp;&nbsp;&nbsp;&nbsp;Successors (1): B4<br>
-<br>
-&nbsp;[ B4 ]<br>
-&nbsp;&nbsp;&nbsp;&nbsp;1: x = x + 1<br>
-&nbsp;&nbsp;&nbsp;&nbsp;2: (x > 2)<br>
-&nbsp;&nbsp;&nbsp;&nbsp;<b>T: if [B4.2]</b><br>
-&nbsp;&nbsp;&nbsp;&nbsp;Predecessors (1): B5<br>
-&nbsp;&nbsp;&nbsp;&nbsp;Successors (2): B3 B2<br>
-<br>
-&nbsp;[ B3 ]<br>
-&nbsp;&nbsp;&nbsp;&nbsp;1: x++<br>
-&nbsp;&nbsp;&nbsp;&nbsp;Predecessors (1): B4<br>
-&nbsp;&nbsp;&nbsp;&nbsp;Successors (1): B1<br>
-<br>
-&nbsp;[ B2 ]<br>
-&nbsp;&nbsp;&nbsp;&nbsp;1: x += 2<br>
-&nbsp;&nbsp;&nbsp;&nbsp;2: x *= 2<br>
-&nbsp;&nbsp;&nbsp;&nbsp;Predecessors (1): B4<br>
-&nbsp;&nbsp;&nbsp;&nbsp;Successors (1): B1<br>
-<br>
-&nbsp;[ B1 ]<br>
-&nbsp;&nbsp;&nbsp;&nbsp;1: return x;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;Predecessors (2): B2 B3<br>
-&nbsp;&nbsp;&nbsp;&nbsp;Successors (1): B0<br>
-<br>
-&nbsp;[ B0 (EXIT) ]<br>
-&nbsp;&nbsp;&nbsp;&nbsp;Predecessors (1): B1<br>
-&nbsp;&nbsp;&nbsp;&nbsp;Successors (0):
-</code>
-
-<p>For each block, the pretty-printed output displays for each block
-the number of <i>predecessor</i> blocks (blocks that have outgoing
-control-flow to the given block) and <i>successor</i> blocks (blocks
-that have control-flow that have incoming control-flow from the given
-block). We can also clearly see the special entry and exit blocks at
-the beginning and end of the pretty-printed output. For the entry
-block (block B5), the number of predecessor blocks is 0, while for the
-exit block (block B0) the number of successor blocks is 0.</p>
-
-<p>The most interesting block here is B4, whose outgoing control-flow
-represents the branching caused by the sole if-statement
-in <tt>foo</tt>. Of particular interest is the second statement in
-the block, <b><tt>(x > 2)</tt></b>, and the terminator, printed
-as <b><tt>if [B4.2]</tt></b>. The second statement represents the
-evaluation of the condition of the if-statement, which occurs before
-the actual branching of control-flow. Within the <tt>CFGBlock</tt>
-for B4, the <tt>Stmt*</tt> for the second statement refers to the
-actual expression in the AST for <b><tt>(x > 2)</tt></b>. Thus
-pointers to subclasses of <tt>Expr</tt> can appear in the list of
-statements in a block, and not just subclasses of <tt>Stmt</tt> that
-refer to proper C statements.</p>
-
-<p>The terminator of block B4 is a pointer to the <tt>IfStmt</tt>
-object in the AST. The pretty-printer outputs <b><tt>if
-[B4.2]</tt></b> because the condition expression of the if-statement
-has an actual place in the basic block, and thus the terminator is
-essentially
-<i>referring</i> to the expression that is the second statement of
-block B4 (i.e., B4.2). In this manner, conditions for control-flow
-(which also includes conditions for loops and switch statements) are
-hoisted into the actual basic block.</p>
-
-<!-- ===================== -->
-<!-- <h4>Implicit Control-Flow</h4> -->
-<!-- ===================== -->
-
-<!--
-<p>A key design principle of the <tt>CFG</tt> class was to not require
-any transformations to the AST in order to represent control-flow.
-Thus the <tt>CFG</tt> does not perform any "lowering" of the
-statements in an AST: loops are not transformed into guarded gotos,
-short-circuit operations are not converted to a set of if-statements,
-and so on.</p>
--->
-
-
-<!-- ======================================================================= -->
-<h3 id="Constants">Constant Folding in the Clang AST</h3>
-<!-- ======================================================================= -->
-
-<p>There are several places where constants and constant folding matter a lot to
-the Clang front-end. First, in general, we prefer the AST to retain the source
-code as close to how the user wrote it as possible. This means that if they
-wrote "5+4", we want to keep the addition and two constants in the AST, we don't
-want to fold to "9". This means that constant folding in various ways turns
-into a tree walk that needs to handle the various cases.</p>
-
-<p>However, there are places in both C and C++ that require constants to be
-folded. For example, the C standard defines what an "integer constant
-expression" (i-c-e) is with very precise and specific requirements. The
-language then requires i-c-e's in a lot of places (for example, the size of a
-bitfield, the value for a case statement, etc). For these, we have to be able
-to constant fold the constants, to do semantic checks (e.g. verify bitfield size
-is non-negative and that case statements aren't duplicated). We aim for Clang
-to be very pedantic about this, diagnosing cases when the code does not use an
-i-c-e where one is required, but accepting the code unless running with
-<tt>-pedantic-errors</tt>.</p>
-
-<p>Things get a little bit more tricky when it comes to compatibility with
-real-world source code. Specifically, GCC has historically accepted a huge
-superset of expressions as i-c-e's, and a lot of real world code depends on this
-unfortuate accident of history (including, e.g., the glibc system headers). GCC
-accepts anything its "fold" optimizer is capable of reducing to an integer
-constant, which means that the definition of what it accepts changes as its
-optimizer does. One example is that GCC accepts things like "case X-X:" even
-when X is a variable, because it can fold this to 0.</p>
-
-<p>Another issue are how constants interact with the extensions we support, such
-as __builtin_constant_p, __builtin_inf, __extension__ and many others. C99
-obviously does not specify the semantics of any of these extensions, and the
-definition of i-c-e does not include them. However, these extensions are often
-used in real code, and we have to have a way to reason about them.</p>
-
-<p>Finally, this is not just a problem for semantic analysis. The code
-generator and other clients have to be able to fold constants (e.g. to
-initialize global variables) and has to handle a superset of what C99 allows.
-Further, these clients can benefit from extended information. For example, we
-know that "foo()||1" always evaluates to true, but we can't replace the
-expression with true because it has side effects.</p>
-
-<!-- ======================= -->
-<h4>Implementation Approach</h4>
-<!-- ======================= -->
-
-<p>After trying several different approaches, we've finally converged on a
-design (Note, at the time of this writing, not all of this has been implemented,
-consider this a design goal!). Our basic approach is to define a single
-recursive method evaluation method (<tt>Expr::Evaluate</tt>), which is
-implemented in <tt>AST/ExprConstant.cpp</tt>. Given an expression with 'scalar'
-type (integer, fp, complex, or pointer) this method returns the following
-information:</p>
-
-<ul>
-<li>Whether the expression is an integer constant expression, a general
- constant that was folded but has no side effects, a general constant that
- was folded but that does have side effects, or an uncomputable/unfoldable
- value.
-</li>
-<li>If the expression was computable in any way, this method returns the APValue
- for the result of the expression.</li>
-<li>If the expression is not evaluatable at all, this method returns
- information on one of the problems with the expression. This includes a
- SourceLocation for where the problem is, and a diagnostic ID that explains
- the problem. The diagnostic should be have ERROR type.</li>
-<li>If the expression is not an integer constant expression, this method returns
- information on one of the problems with the expression. This includes a
- SourceLocation for where the problem is, and a diagnostic ID that explains
- the problem. The diagnostic should be have EXTENSION type.</li>
-</ul>
-
-<p>This information gives various clients the flexibility that they want, and we
-will eventually have some helper methods for various extensions. For example,
-Sema should have a <tt>Sema::VerifyIntegerConstantExpression</tt> method, which
-calls Evaluate on the expression. If the expression is not foldable, the error
-is emitted, and it would return true. If the expression is not an i-c-e, the
-EXTENSION diagnostic is emitted. Finally it would return false to indicate that
-the AST is ok.</p>
-
-<p>Other clients can use the information in other ways, for example, codegen can
-just use expressions that are foldable in any way.</p>
-
-<!-- ========== -->
-<h4>Extensions</h4>
-<!-- ========== -->
-
-<p>This section describes how some of the various extensions Clang supports
-interacts with constant evaluation:</p>
-
-<ul>
-<li><b><tt>__extension__</tt></b>: The expression form of this extension causes
- any evaluatable subexpression to be accepted as an integer constant
- expression.</li>
-<li><b><tt>__builtin_constant_p</tt></b>: This returns true (as an integer
- constant expression) if the operand evaluates to either a numeric value
- (that is, not a pointer cast to integral type) of integral, enumeration,
- floating or complex type, or if it evaluates to the address of the first
- character of a string literal (possibly cast to some other type). As a
- special case, if <tt>__builtin_constant_p</tt> is the (potentially
- parenthesized) condition of a conditional operator expression ("?:"), only
- the true side of the conditional operator is considered, and it is evaluated
- with full constant folding.</li>
-<li><b><tt>__builtin_choose_expr</tt></b>: The condition is required to be an
- integer constant expression, but we accept any constant as an "extension of
- an extension". This only evaluates one operand depending on which way the
- condition evaluates.</li>
-<li><b><tt>__builtin_classify_type</tt></b>: This always returns an integer
- constant expression.</li>
-<li><b><tt>__builtin_inf,nan,..</tt></b>: These are treated just like a
- floating-point literal.</li>
-<li><b><tt>__builtin_abs,copysign,..</tt></b>: These are constant folded as
- general constant expressions.</li>
-<li><b><tt>__builtin_strlen</tt></b> and <b><tt>strlen</tt></b>: These are
- constant folded as integer constant expressions if the argument is a string
- literal.</li>
-</ul>
-
-
-<!-- ======================================================================= -->
-<h2 id="Howtos">How to change Clang</h2>
-<!-- ======================================================================= -->
-
-<!-- ======================================================================= -->
-<h3 id="AddingAttributes">How to add an attribute</h3>
-<!-- ======================================================================= -->
-
-<p>To add an attribute, you'll have to add it to the list of attributes, add it
-to the parsing phase, and look for it in the AST scan.
-<a href="http://llvm.org/viewvc/llvm-project?view=rev&amp;revision=124217">r124217</a>
-has a good example of adding a warning attribute.</p>
-
-<p>(Beware that this hasn't been reviewed/fixed by the people who designed the
-attributes system yet.)</p>
-
-<h4><a
-href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?view=markup">include/clang/Basic/Attr.td</a></h4>
-
-<p>Each attribute gets a <tt>def</tt> inheriting from <tt>Attr</tt> or one of
-its subclasses. <tt>InheritableAttr</tt> means that the attribute also applies
-to subsequent declarations of the same name.</p>
-
-<p><tt>Spellings</tt> lists the strings that can appear in
-<tt>__attribute__((here))</tt> or <tt>[[here]]</tt>. All such strings
-will be synonymous. If you want to allow the <tt>[[]]</tt> C++11
-syntax, you have to define a list of <tt>Namespaces</tt>, which will
-let users write <tt>[[namespace:spelling]]</tt>. Using the empty
-string for a namespace will allow users to write just the spelling
-with no "<tt>:</tt>".</p>
-
-<p><tt>Subjects</tt> restricts what kinds of AST node to which this attribute
-can appertain (roughly, attach).</p>
-
-<p><tt>Args</tt> names the arguments the attribute takes, in order. If
-<tt>Args</tt> is <tt>[StringArgument&lt;"Arg1">, IntArgument&lt;"Arg2">]</tt>
-then <tt>__attribute__((myattribute("Hello", 3)))</tt> will be a valid use.</p>
-
-<h4>Boilerplate</h4>
-
-<p>Write a new <tt>HandleYourAttr()</tt> function in <a
-href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?view=markup">lib/Sema/SemaDeclAttr.cpp</a>,
-and add a case to the switch in <tt>ProcessNonInheritableDeclAttr()</tt> or
-<tt>ProcessInheritableDeclAttr()</tt> forwarding to it.</p>
-
-<p>If your attribute causes extra warnings to fire, define a <tt>DiagGroup</tt>
-in <a
-href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?view=markup">include/clang/Basic/DiagnosticGroups.td</a>
-named after the attribute's <tt>Spelling</tt> with "_"s replaced by "-"s. If
-you're only defining one diagnostic, you can skip <tt>DiagnosticGroups.td</tt>
-and use <tt>InGroup&lt;DiagGroup&lt;"your-attribute">></tt> directly in <a
-href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?view=markup">DiagnosticSemaKinds.td</a></p>
-
-<h4>The meat of your attribute</h4>
-
-<p>Find an appropriate place in Clang to do whatever your attribute needs to do.
-Check for the attribute's presence using <tt>Decl::getAttr&lt;YourAttr>()</tt>.</p>
-
-<p>Update the <a href="LanguageExtensions.html">Clang Language Extensions</a>
-document to describe your new attribute.</p>
-
-<!-- ======================================================================= -->
-<h3 id="AddingExprStmt">How to add an expression or statement</h3>
-<!-- ======================================================================= -->
-
-<p>Expressions and statements are one of the most fundamental constructs within a
-compiler, because they interact with many different parts of the AST,
-semantic analysis, and IR generation. Therefore, adding a new
-expression or statement kind into Clang requires some care. The following list
-details the various places in Clang where an expression or statement needs to be
-introduced, along with patterns to follow to ensure that the new
-expression or statement works well across all of the C languages. We
-focus on expressions, but statements are similar.</p>
-
-<ol>
- <li>Introduce parsing actions into the parser. Recursive-descent
- parsing is mostly self-explanatory, but there are a few things that
- are worth keeping in mind:
- <ul>
- <li>Keep as much source location information as possible! You'll
- want it later to produce great diagnostics and support Clang's
- various features that map between source code and the AST.</li>
- <li>Write tests for all of the "bad" parsing cases, to make sure
- your recovery is good. If you have matched delimiters (e.g.,
- parentheses, square brackets, etc.), use
- <tt>Parser::BalancedDelimiterTracker</tt> to give nice diagnostics when
- things go wrong.</li>
- </ul>
- </li>
-
- <li>Introduce semantic analysis actions into <tt>Sema</tt>. Semantic
- analysis should always involve two functions: an <tt>ActOnXXX</tt>
- function that will be called directly from the parser, and a
- <tt>BuildXXX</tt> function that performs the actual semantic
- analysis and will (eventually!) build the AST node. It's fairly
- common for the <tt>ActOnCXX</tt> function to do very little (often
- just some minor translation from the parser's representation to
- <tt>Sema</tt>'s representation of the same thing), but the separation
- is still important: C++ template instantiation, for example,
- should always call the <tt>BuildXXX</tt> variant. Several notes on
- semantic analysis before we get into construction of the AST:
- <ul>
- <li>Your expression probably involves some types and some
- subexpressions. Make sure to fully check that those types, and the
- types of those subexpressions, meet your expectations. Add
- implicit conversions where necessary to make sure that all of the
- types line up exactly the way you want them. Write extensive tests
- to check that you're getting good diagnostics for mistakes and
- that you can use various forms of subexpressions with your
- expression.</li>
- <li>When type-checking a type or subexpression, make sure to first
- check whether the type is "dependent"
- (<tt>Type::isDependentType()</tt>) or whether a subexpression is
- type-dependent (<tt>Expr::isTypeDependent()</tt>). If any of these
- return true, then you're inside a template and you can't do much
- type-checking now. That's normal, and your AST node (when you get
- there) will have to deal with this case. At this point, you can
- write tests that use your expression within templates, but don't
- try to instantiate the templates.</li>
- <li>For each subexpression, be sure to call
- <tt>Sema::CheckPlaceholderExpr()</tt> to deal with "weird"
- expressions that don't behave well as subexpressions. Then,
- determine whether you need to perform
- lvalue-to-rvalue conversions
- (<tt>Sema::DefaultLvalueConversion</tt>e) or
- the usual unary conversions
- (<tt>Sema::UsualUnaryConversions</tt>), for places where the
- subexpression is producing a value you intend to use.</li>
- <li>Your <tt>BuildXXX</tt> function will probably just return
- <tt>ExprError()</tt> at this point, since you don't have an AST.
- That's perfectly fine, and shouldn't impact your testing.</li>
- </ul>
- </li>
-
- <li>Introduce an AST node for your new expression. This starts with
- declaring the node in <tt>include/Basic/StmtNodes.td</tt> and
- creating a new class for your expression in the appropriate
- <tt>include/AST/Expr*.h</tt> header. It's best to look at the class
- for a similar expression to get ideas, and there are some specific
- things to watch for:
- <ul>
- <li>If you need to allocate memory, use the <tt>ASTContext</tt>
- allocator to allocate memory. Never use raw <tt>malloc</tt> or
- <tt>new</tt>, and never hold any resources in an AST node, because
- the destructor of an AST node is never called.</li>
-
- <li>Make sure that <tt>getSourceRange()</tt> covers the exact
- source range of your expression. This is needed for diagnostics
- and for IDE support.</li>
-
- <li>Make sure that <tt>children()</tt> visits all of the
- subexpressions. This is important for a number of features (e.g., IDE
- support, C++ variadic templates). If you have sub-types, you'll
- also need to visit those sub-types in the
- <tt>RecursiveASTVisitor</tt>.</li>
-
- <li>Add printing support (<tt>StmtPrinter.cpp</tt>) and dumping
- support (<tt>StmtDumper.cpp</tt>) for your expression.</li>
-
- <li>Add profiling support (<tt>StmtProfile.cpp</tt>) for your AST
- node, noting the distinguishing (non-source location)
- characteristics of an instance of your expression. Omitting this
- step will lead to hard-to-diagnose failures regarding matching of
- template declarations.</li>
- </ul>
- </li>
-
- <li>Teach semantic analysis to build your AST node! At this point,
- you can wire up your <tt>Sema::BuildXXX</tt> function to actually
- create your AST. A few things to check at this point:
- <ul>
- <li>If your expression can construct a new C++ class or return a
- new Objective-C object, be sure to update and then call
- <tt>Sema::MaybeBindToTemporary</tt> for your just-created AST node
- to be sure that the object gets properly destructed. An easy way
- to test this is to return a C++ class with a private destructor:
- semantic analysis should flag an error here with the attempt to
- call the destructor.</li>
- <li>Inspect the generated AST by printing it using <tt>clang -cc1
- -ast-print</tt>, to make sure you're capturing all of the
- important information about how the AST was written.</li>
- <li>Inspect the generated AST under <tt>clang -cc1 -ast-dump</tt>
- to verify that all of the types in the generated AST line up the
- way you want them. Remember that clients of the AST should never
- have to "think" to understand what's going on. For example, all
- implicit conversions should show up explicitly in the AST.</li>
- <li>Write tests that use your expression as a subexpression of
- other, well-known expressions. Can you call a function using your
- expression as an argument? Can you use the ternary operator?</li>
- </ul>
- </li>
-
- <li>Teach code generation to create IR to your AST node. This step
- is the first (and only) that requires knowledge of LLVM IR. There
- are several things to keep in mind:
- <ul>
- <li>Code generation is separated into scalar/aggregate/complex and
- lvalue/rvalue paths, depending on what kind of result your
- expression produces. On occasion, this requires some careful
- factoring of code to avoid duplication.</li>
-
- <li><tt>CodeGenFunction</tt> contains functions
- <tt>ConvertType</tt> and <tt>ConvertTypeForMem</tt> that convert
- Clang's types (<tt>clang::Type*</tt> or <tt>clang::QualType</tt>)
- to LLVM types.
- Use the former for values, and the later for memory locations:
- test with the C++ "bool" type to check this. If you find
- that you are having to use LLVM bitcasts to make
- the subexpressions of your expression have the type that your
- expression expects, STOP! Go fix semantic analysis and the AST so
- that you don't need these bitcasts.</li>
-
- <li>The <tt>CodeGenFunction</tt> class has a number of helper
- functions to make certain operations easy, such as generating code
- to produce an lvalue or an rvalue, or to initialize a memory
- location with a given value. Prefer to use these functions rather
- than directly writing loads and stores, because these functions
- take care of some of the tricky details for you (e.g., for
- exceptions).</li>
-
- <li>If your expression requires some special behavior in the event
- of an exception, look at the <tt>push*Cleanup</tt> functions in
- <tt>CodeGenFunction</tt> to introduce a cleanup. You shouldn't
- have to deal with exception-handling directly.</li>
-
- <li>Testing is extremely important in IR generation. Use <tt>clang
- -cc1 -emit-llvm</tt> and <a
- href="http://llvm.org/cmds/FileCheck.html">FileCheck</a> to verify
- that you're generating the right IR.</li>
- </ul>
- </li>
-
- <li>Teach template instantiation how to cope with your AST
- node, which requires some fairly simple code:
- <ul>
- <li>Make sure that your expression's constructor properly
- computes the flags for type dependence (i.e., the type your
- expression produces can change from one instantiation to the
- next), value dependence (i.e., the constant value your expression
- produces can change from one instantiation to the next),
- instantiation dependence (i.e., a template parameter occurs
- anywhere in your expression), and whether your expression contains
- a parameter pack (for variadic templates). Often, computing these
- flags just means combining the results from the various types and
- subexpressions.</li>
-
- <li>Add <tt>TransformXXX</tt> and <tt>RebuildXXX</tt> functions to
- the
- <tt>TreeTransform</tt> class template in <tt>Sema</tt>.
- <tt>TransformXXX</tt> should (recursively) transform all of the
- subexpressions and types
- within your expression, using <tt>getDerived().TransformYYY</tt>.
- If all of the subexpressions and types transform without error, it
- will then call the <tt>RebuildXXX</tt> function, which will in
- turn call <tt>getSema().BuildXXX</tt> to perform semantic analysis
- and build your expression.</li>
-
- <li>To test template instantiation, take those tests you wrote to
- make sure that you were type checking with type-dependent
- expressions and dependent types (from step #2) and instantiate
- those templates with various types, some of which type-check and
- some that don't, and test the error messages in each case.</li>
- </ul>
- </li>
-
- <li>There are some "extras" that make other features work better.
- It's worth handling these extras to give your expression complete
- integration into Clang:
- <ul>
- <li>Add code completion support for your expression in
- <tt>SemaCodeComplete.cpp</tt>.</li>
-
- <li>If your expression has types in it, or has any "interesting"
- features other than subexpressions, extend libclang's
- <tt>CursorVisitor</tt> to provide proper visitation for your
- expression, enabling various IDE features such as syntax
- highlighting, cross-referencing, and so on. The
- <tt>c-index-test</tt> helper program can be used to test these
- features.</li>
- </ul>
- </li>
-</ol>
-
-</div>
-</body>
-</html>
diff --git a/docs/InternalsManual.rst b/docs/InternalsManual.rst
new file mode 100644
index 0000000..59dd2f9
--- /dev/null
+++ b/docs/InternalsManual.rst
@@ -0,0 +1,1810 @@
+============================
+"Clang" CFE Internals Manual
+============================
+
+.. contents::
+ :local:
+
+Introduction
+============
+
+This document describes some of the more important APIs and internal design
+decisions made in the Clang C front-end. The purpose of this document is to
+both capture some of this high level information and also describe some of the
+design decisions behind it. This is meant for people interested in hacking on
+Clang, not for end-users. The description below is categorized by libraries,
+and does not describe any of the clients of the libraries.
+
+LLVM Support Library
+====================
+
+The LLVM ``libSupport`` library provides many underlying libraries and
+`data-structures <http://llvm.org/docs/ProgrammersManual.html>`_, including
+command line option processing, various containers and a system abstraction
+layer, which is used for file system access.
+
+The Clang "Basic" Library
+=========================
+
+This library certainly needs a better name. The "basic" library contains a
+number of low-level utilities for tracking and manipulating source buffers,
+locations within the source buffers, diagnostics, tokens, target abstraction,
+and information about the subset of the language being compiled for.
+
+Part of this infrastructure is specific to C (such as the ``TargetInfo``
+class), other parts could be reused for other non-C-based languages
+(``SourceLocation``, ``SourceManager``, ``Diagnostics``, ``FileManager``).
+When and if there is future demand we can figure out if it makes sense to
+introduce a new library, move the general classes somewhere else, or introduce
+some other solution.
+
+We describe the roles of these classes in order of their dependencies.
+
+The Diagnostics Subsystem
+-------------------------
+
+The Clang Diagnostics subsystem is an important part of how the compiler
+communicates with the human. Diagnostics are the warnings and errors produced
+when the code is incorrect or dubious. In Clang, each diagnostic produced has
+(at the minimum) a unique ID, an English translation associated with it, a
+:ref:`SourceLocation <SourceLocation>` to "put the caret", and a severity
+(e.g., ``WARNING`` or ``ERROR``). They can also optionally include a number of
+arguments to the dianostic (which fill in "%0"'s in the string) as well as a
+number of source ranges that related to the diagnostic.
+
+In this section, we'll be giving examples produced by the Clang command line
+driver, but diagnostics can be :ref:`rendered in many different ways
+<DiagnosticClient>` depending on how the ``DiagnosticClient`` interface is
+implemented. A representative example of a diagnostic is:
+
+.. code-block:: c++
+
+ t.c:38:15: error: invalid operands to binary expression ('int *' and '_Complex float')
+ P = (P-42) + Gamma*4;
+ ~~~~~~ ^ ~~~~~~~
+
+In this example, you can see the English translation, the severity (error), you
+can see the source location (the caret ("``^``") and file/line/column info),
+the source ranges "``~~~~``", arguments to the diagnostic ("``int*``" and
+"``_Complex float``"). You'll have to believe me that there is a unique ID
+backing the diagnostic :).
+
+Getting all of this to happen has several steps and involves many moving
+pieces, this section describes them and talks about best practices when adding
+a new diagnostic.
+
+The ``Diagnostic*Kinds.td`` files
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Diagnostics are created by adding an entry to one of the
+``clang/Basic/Diagnostic*Kinds.td`` files, depending on what library will be
+using it. From this file, :program:`tblgen` generates the unique ID of the
+diagnostic, the severity of the diagnostic and the English translation + format
+string.
+
+There is little sanity with the naming of the unique ID's right now. Some
+start with ``err_``, ``warn_``, ``ext_`` to encode the severity into the name.
+Since the enum is referenced in the C++ code that produces the diagnostic, it
+is somewhat useful for it to be reasonably short.
+
+The severity of the diagnostic comes from the set {``NOTE``, ``WARNING``,
+``EXTENSION``, ``EXTWARN``, ``ERROR``}. The ``ERROR`` severity is used for
+diagnostics indicating the program is never acceptable under any circumstances.
+When an error is emitted, the AST for the input code may not be fully built.
+The ``EXTENSION`` and ``EXTWARN`` severities are used for extensions to the
+language that Clang accepts. This means that Clang fully understands and can
+represent them in the AST, but we produce diagnostics to tell the user their
+code is non-portable. The difference is that the former are ignored by
+default, and the later warn by default. The ``WARNING`` severity is used for
+constructs that are valid in the currently selected source language but that
+are dubious in some way. The ``NOTE`` level is used to staple more information
+onto previous diagnostics.
+
+These *severities* are mapped into a smaller set (the ``Diagnostic::Level``
+enum, {``Ignored``, ``Note``, ``Warning``, ``Error``, ``Fatal``}) of output
+*levels* by the diagnostics subsystem based on various configuration options.
+Clang internally supports a fully fine grained mapping mechanism that allows
+you to map almost any diagnostic to the output level that you want. The only
+diagnostics that cannot be mapped are ``NOTE``\ s, which always follow the
+severity of the previously emitted diagnostic and ``ERROR``\ s, which can only
+be mapped to ``Fatal`` (it is not possible to turn an error into a warning, for
+example).
+
+Diagnostic mappings are used in many ways. For example, if the user specifies
+``-pedantic``, ``EXTENSION`` maps to ``Warning``, if they specify
+``-pedantic-errors``, it turns into ``Error``. This is used to implement
+options like ``-Wunused_macros``, ``-Wundef`` etc.
+
+Mapping to ``Fatal`` should only be used for diagnostics that are considered so
+severe that error recovery won't be able to recover sensibly from them (thus
+spewing a ton of bogus errors). One example of this class of error are failure
+to ``#include`` a file.
+
+The Format String
+^^^^^^^^^^^^^^^^^
+
+The format string for the diagnostic is very simple, but it has some power. It
+takes the form of a string in English with markers that indicate where and how
+arguments to the diagnostic are inserted and formatted. For example, here are
+some simple format strings:
+
+.. code-block:: c++
+
+ "binary integer literals are an extension"
+ "format string contains '\\0' within the string body"
+ "more '%%' conversions than data arguments"
+ "invalid operands to binary expression (%0 and %1)"
+ "overloaded '%0' must be a %select{unary|binary|unary or binary}2 operator"
+ " (has %1 parameter%s1)"
+
+These examples show some important points of format strings. You can use any
+plain ASCII character in the diagnostic string except "``%``" without a
+problem, but these are C strings, so you have to use and be aware of all the C
+escape sequences (as in the second example). If you want to produce a "``%``"
+in the output, use the "``%%``" escape sequence, like the third diagnostic.
+Finally, Clang uses the "``%...[digit]``" sequences to specify where and how
+arguments to the diagnostic are formatted.
+
+Arguments to the diagnostic are numbered according to how they are specified by
+the C++ code that :ref:`produces them <internals-producing-diag>`, and are
+referenced by ``%0`` .. ``%9``. If you have more than 10 arguments to your
+diagnostic, you are doing something wrong :). Unlike ``printf``, there is no
+requirement that arguments to the diagnostic end up in the output in the same
+order as they are specified, you could have a format string with "``%1 %0``"
+that swaps them, for example. The text in between the percent and digit are
+formatting instructions. If there are no instructions, the argument is just
+turned into a string and substituted in.
+
+Here are some "best practices" for writing the English format string:
+
+* Keep the string short. It should ideally fit in the 80 column limit of the
+ ``DiagnosticKinds.td`` file. This avoids the diagnostic wrapping when
+ printed, and forces you to think about the important point you are conveying
+ with the diagnostic.
+* Take advantage of location information. The user will be able to see the
+ line and location of the caret, so you don't need to tell them that the
+ problem is with the 4th argument to the function: just point to it.
+* Do not capitalize the diagnostic string, and do not end it with a period.
+* If you need to quote something in the diagnostic string, use single quotes.
+
+Diagnostics should never take random English strings as arguments: you
+shouldn't use "``you have a problem with %0``" and pass in things like "``your
+argument``" or "``your return value``" as arguments. Doing this prevents
+:ref:`translating <internals-diag-translation>` the Clang diagnostics to other
+languages (because they'll get random English words in their otherwise
+localized diagnostic). The exceptions to this are C/C++ language keywords
+(e.g., ``auto``, ``const``, ``mutable``, etc) and C/C++ operators (``/=``).
+Note that things like "pointer" and "reference" are not keywords. On the other
+hand, you *can* include anything that comes from the user's source code,
+including variable names, types, labels, etc. The "``select``" format can be
+used to achieve this sort of thing in a localizable way, see below.
+
+Formatting a Diagnostic Argument
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Arguments to diagnostics are fully typed internally, and come from a couple
+different classes: integers, types, names, and random strings. Depending on
+the class of the argument, it can be optionally formatted in different ways.
+This gives the ``DiagnosticClient`` information about what the argument means
+without requiring it to use a specific presentation (consider this MVC for
+Clang :).
+
+Here are the different diagnostic argument formats currently supported by
+Clang:
+
+**"s" format**
+
+Example:
+ ``"requires %1 parameter%s1"``
+Class:
+ Integers
+Description:
+ This is a simple formatter for integers that is useful when producing English
+ diagnostics. When the integer is 1, it prints as nothing. When the integer
+ is not 1, it prints as "``s``". This allows some simple grammatical forms to
+ be to be handled correctly, and eliminates the need to use gross things like
+ ``"requires %1 parameter(s)"``.
+
+**"select" format**
+
+Example:
+ ``"must be a %select{unary|binary|unary or binary}2 operator"``
+Class:
+ Integers
+Description:
+ This format specifier is used to merge multiple related diagnostics together
+ into one common one, without requiring the difference to be specified as an
+ English string argument. Instead of specifying the string, the diagnostic
+ gets an integer argument and the format string selects the numbered option.
+ In this case, the "``%2``" value must be an integer in the range [0..2]. If
+ it is 0, it prints "unary", if it is 1 it prints "binary" if it is 2, it
+ prints "unary or binary". This allows other language translations to
+ substitute reasonable words (or entire phrases) based on the semantics of the
+ diagnostic instead of having to do things textually. The selected string
+ does undergo formatting.
+
+**"plural" format**
+
+Example:
+ ``"you have %1 %plural{1:mouse|:mice}1 connected to your computer"``
+Class:
+ Integers
+Description:
+ This is a formatter for complex plural forms. It is designed to handle even
+ the requirements of languages with very complex plural forms, as many Baltic
+ languages have. The argument consists of a series of expression/form pairs,
+ separated by ":", where the first form whose expression evaluates to true is
+ the result of the modifier.
+
+ An expression can be empty, in which case it is always true. See the example
+ at the top. Otherwise, it is a series of one or more numeric conditions,
+ separated by ",". If any condition matches, the expression matches. Each
+ numeric condition can take one of three forms.
+
+ * number: A simple decimal number matches if the argument is the same as the
+ number. Example: ``"%plural{1:mouse|:mice}4"``
+ * range: A range in square brackets matches if the argument is within the
+ range. Then range is inclusive on both ends. Example:
+ ``"%plural{0:none|1:one|[2,5]:some|:many}2"``
+ * modulo: A modulo operator is followed by a number, and equals sign and
+ either a number or a range. The tests are the same as for plain numbers
+ and ranges, but the argument is taken modulo the number first. Example:
+ ``"%plural{%100=0:even hundred|%100=[1,50]:lower half|:everything else}1"``
+
+ The parser is very unforgiving. A syntax error, even whitespace, will abort,
+ as will a failure to match the argument against any expression.
+
+**"ordinal" format**
+
+Example:
+ ``"ambiguity in %ordinal0 argument"``
+Class:
+ Integers
+Description:
+ This is a formatter which represents the argument number as an ordinal: the
+ value ``1`` becomes ``1st``, ``3`` becomes ``3rd``, and so on. Values less
+ than ``1`` are not supported. This formatter is currently hard-coded to use
+ English ordinals.
+
+**"objcclass" format**
+
+Example:
+ ``"method %objcclass0 not found"``
+Class:
+ ``DeclarationName``
+Description:
+ This is a simple formatter that indicates the ``DeclarationName`` corresponds
+ to an Objective-C class method selector. As such, it prints the selector
+ with a leading "``+``".
+
+**"objcinstance" format**
+
+Example:
+ ``"method %objcinstance0 not found"``
+Class:
+ ``DeclarationName``
+Description:
+ This is a simple formatter that indicates the ``DeclarationName`` corresponds
+ to an Objective-C instance method selector. As such, it prints the selector
+ with a leading "``-``".
+
+**"q" format**
+
+Example:
+ ``"candidate found by name lookup is %q0"``
+Class:
+ ``NamedDecl *``
+Description:
+ This formatter indicates that the fully-qualified name of the declaration
+ should be printed, e.g., "``std::vector``" rather than "``vector``".
+
+**"diff" format**
+
+Example:
+ ``"no known conversion %diff{from $ to $|from argument type to parameter type}1,2"``
+Class:
+ ``QualType``
+Description:
+ This formatter takes two ``QualType``\ s and attempts to print a template
+ difference between the two. If tree printing is off, the text inside the
+ braces before the pipe is printed, with the formatted text replacing the $.
+ If tree printing is on, the text after the pipe is printed and a type tree is
+ printed after the diagnostic message.
+
+It is really easy to add format specifiers to the Clang diagnostics system, but
+they should be discussed before they are added. If you are creating a lot of
+repetitive diagnostics and/or have an idea for a useful formatter, please bring
+it up on the cfe-dev mailing list.
+
+.. _internals-producing-diag:
+
+Producing the Diagnostic
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+Now that you've created the diagnostic in the ``Diagnostic*Kinds.td`` file, you
+need to write the code that detects the condition in question and emits the new
+diagnostic. Various components of Clang (e.g., the preprocessor, ``Sema``,
+etc.) provide a helper function named "``Diag``". It creates a diagnostic and
+accepts the arguments, ranges, and other information that goes along with it.
+
+For example, the binary expression error comes from code like this:
+
+.. code-block:: c++
+
+ if (various things that are bad)
+ Diag(Loc, diag::err_typecheck_invalid_operands)
+ << lex->getType() << rex->getType()
+ << lex->getSourceRange() << rex->getSourceRange();
+
+This shows that use of the ``Diag`` method: it takes a location (a
+:ref:`SourceLocation <SourceLocation>` object) and a diagnostic enum value
+(which matches the name from ``Diagnostic*Kinds.td``). If the diagnostic takes
+arguments, they are specified with the ``<<`` operator: the first argument
+becomes ``%0``, the second becomes ``%1``, etc. The diagnostic interface
+allows you to specify arguments of many different types, including ``int`` and
+``unsigned`` for integer arguments, ``const char*`` and ``std::string`` for
+string arguments, ``DeclarationName`` and ``const IdentifierInfo *`` for names,
+``QualType`` for types, etc. ``SourceRange``\ s are also specified with the
+``<<`` operator, but do not have a specific ordering requirement.
+
+As you can see, adding and producing a diagnostic is pretty straightforward.
+The hard part is deciding exactly what you need to say to help the user,
+picking a suitable wording, and providing the information needed to format it
+correctly. The good news is that the call site that issues a diagnostic should
+be completely independent of how the diagnostic is formatted and in what
+language it is rendered.
+
+Fix-It Hints
+^^^^^^^^^^^^
+
+In some cases, the front end emits diagnostics when it is clear that some small
+change to the source code would fix the problem. For example, a missing
+semicolon at the end of a statement or a use of deprecated syntax that is
+easily rewritten into a more modern form. Clang tries very hard to emit the
+diagnostic and recover gracefully in these and other cases.
+
+However, for these cases where the fix is obvious, the diagnostic can be
+annotated with a hint (referred to as a "fix-it hint") that describes how to
+change the code referenced by the diagnostic to fix the problem. For example,
+it might add the missing semicolon at the end of the statement or rewrite the
+use of a deprecated construct into something more palatable. Here is one such
+example from the C++ front end, where we warn about the right-shift operator
+changing meaning from C++98 to C++11:
+
+.. code-block:: c++
+
+ test.cpp:3:7: warning: use of right-shift operator ('>>') in template argument
+ will require parentheses in C++11
+ A<100 >> 2> *a;
+ ^
+ ( )
+
+Here, the fix-it hint is suggesting that parentheses be added, and showing
+exactly where those parentheses would be inserted into the source code. The
+fix-it hints themselves describe what changes to make to the source code in an
+abstract manner, which the text diagnostic printer renders as a line of
+"insertions" below the caret line. :ref:`Other diagnostic clients
+<DiagnosticClient>` might choose to render the code differently (e.g., as
+markup inline) or even give the user the ability to automatically fix the
+problem.
+
+Fix-it hints on errors and warnings need to obey these rules:
+
+* Since they are automatically applied if ``-Xclang -fixit`` is passed to the
+ driver, they should only be used when it's very likely they match the user's
+ intent.
+* Clang must recover from errors as if the fix-it had been applied.
+
+If a fix-it can't obey these rules, put the fix-it on a note. Fix-its on notes
+are not applied automatically.
+
+All fix-it hints are described by the ``FixItHint`` class, instances of which
+should be attached to the diagnostic using the ``<<`` operator in the same way
+that highlighted source ranges and arguments are passed to the diagnostic.
+Fix-it hints can be created with one of three constructors:
+
+* ``FixItHint::CreateInsertion(Loc, Code)``
+
+ Specifies that the given ``Code`` (a string) should be inserted before the
+ source location ``Loc``.
+
+* ``FixItHint::CreateRemoval(Range)``
+
+ Specifies that the code in the given source ``Range`` should be removed.
+
+* ``FixItHint::CreateReplacement(Range, Code)``
+
+ Specifies that the code in the given source ``Range`` should be removed,
+ and replaced with the given ``Code`` string.
+
+.. _DiagnosticClient:
+
+The ``DiagnosticClient`` Interface
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Once code generates a diagnostic with all of the arguments and the rest of the
+relevant information, Clang needs to know what to do with it. As previously
+mentioned, the diagnostic machinery goes through some filtering to map a
+severity onto a diagnostic level, then (assuming the diagnostic is not mapped
+to "``Ignore``") it invokes an object that implements the ``DiagnosticClient``
+interface with the information.
+
+It is possible to implement this interface in many different ways. For
+example, the normal Clang ``DiagnosticClient`` (named
+``TextDiagnosticPrinter``) turns the arguments into strings (according to the
+various formatting rules), prints out the file/line/column information and the
+string, then prints out the line of code, the source ranges, and the caret.
+However, this behavior isn't required.
+
+Another implementation of the ``DiagnosticClient`` interface is the
+``TextDiagnosticBuffer`` class, which is used when Clang is in ``-verify``
+mode. 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. Full
+documentation for the ``-verify`` mode can be found in the Clang API
+documentation for `VerifyDiagnosticConsumer
+</doxygen/classclang_1_1VerifyDiagnosticConsumer.html#details>`_.
+
+There are many other possible implementations of this interface, and this is
+why we prefer diagnostics to pass down rich structured information in
+arguments. For example, an HTML output might want declaration names be
+linkified to where they come from in the source. Another example is that a GUI
+might let you click on typedefs to expand them. This application would want to
+pass significantly more information about types through to the GUI than a
+simple flat string. The interface allows this to happen.
+
+.. _internals-diag-translation:
+
+Adding Translations to Clang
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Not possible yet! Diagnostic strings should be written in UTF-8, the client can
+translate to the relevant code page if needed. Each translation completely
+replaces the format string for the diagnostic.
+
+.. _SourceLocation:
+.. _SourceManager:
+
+The ``SourceLocation`` and ``SourceManager`` classes
+----------------------------------------------------
+
+Strangely enough, the ``SourceLocation`` class represents a location within the
+source code of the program. Important design points include:
+
+#. ``sizeof(SourceLocation)`` must be extremely small, as these are embedded
+ into many AST nodes and are passed around often. Currently it is 32 bits.
+#. ``SourceLocation`` must be a simple value object that can be efficiently
+ copied.
+#. We should be able to represent a source location for any byte of any input
+ file. This includes in the middle of tokens, in whitespace, in trigraphs,
+ etc.
+#. A ``SourceLocation`` must encode the current ``#include`` stack that was
+ active when the location was processed. For example, if the location
+ corresponds to a token, it should contain the set of ``#include``\ s active
+ when the token was lexed. This allows us to print the ``#include`` stack
+ for a diagnostic.
+#. ``SourceLocation`` must be able to describe macro expansions, capturing both
+ the ultimate instantiation point and the source of the original character
+ data.
+
+In practice, the ``SourceLocation`` works together with the ``SourceManager``
+class to encode two pieces of information about a location: its spelling
+location and its instantiation location. For most tokens, these will be the
+same. However, for a macro expansion (or tokens that came from a ``_Pragma``
+directive) these will describe the location of the characters corresponding to
+the token and the location where the token was used (i.e., the macro
+instantiation point or the location of the ``_Pragma`` itself).
+
+The Clang front-end inherently depends on the location of a token being tracked
+correctly. If it is ever incorrect, the front-end may get confused and die.
+The reason for this is that the notion of the "spelling" of a ``Token`` in
+Clang depends on being able to find the original input characters for the
+token. This concept maps directly to the "spelling location" for the token.
+
+``SourceRange`` and ``CharSourceRange``
+---------------------------------------
+
+.. mostly taken from http://lists.cs.uiuc.edu/pipermail/cfe-dev/2010-August/010595.html
+
+Clang represents most source ranges by [first, last], where "first" and "last"
+each point to the beginning of their respective tokens. For example consider
+the ``SourceRange`` of the following statement:
+
+.. code-block:: c++
+
+ x = foo + bar;
+ ^first ^last
+
+To map from this representation to a character-based representation, the "last"
+location needs to be adjusted to point to (or past) the end of that token with
+either ``Lexer::MeasureTokenLength()`` or ``Lexer::getLocForEndOfToken()``. For
+the rare cases where character-level source ranges information is needed we use
+the ``CharSourceRange`` class.
+
+The Driver Library
+==================
+
+The clang Driver and library are documented :doc:`here <DriverInternals>`.
+
+Precompiled Headers
+===================
+
+Clang supports two implementations of precompiled headers. The default
+implementation, precompiled headers (:doc:`PCH <PCHInternals>`) uses a
+serialized representation of Clang's internal data structures, encoded with the
+`LLVM bitstream format <http://llvm.org/docs/BitCodeFormat.html>`_.
+Pretokenized headers (:doc:`PTH <PTHInternals>`), on the other hand, contain a
+serialized representation of the tokens encountered when preprocessing a header
+(and anything that header includes).
+
+The Frontend Library
+====================
+
+The Frontend library contains functionality useful for building tools on top of
+the Clang libraries, for example several methods for outputting diagnostics.
+
+The Lexer and Preprocessor Library
+==================================
+
+The Lexer library contains several tightly-connected classes that are involved
+with the nasty process of lexing and preprocessing C source code. The main
+interface to this library for outside clients is the large ``Preprocessor``
+class. It contains the various pieces of state that are required to coherently
+read tokens out of a translation unit.
+
+The core interface to the ``Preprocessor`` object (once it is set up) is the
+``Preprocessor::Lex`` method, which returns the next :ref:`Token <Token>` from
+the preprocessor stream. There are two types of token providers that the
+preprocessor is capable of reading from: a buffer lexer (provided by the
+:ref:`Lexer <Lexer>` class) and a buffered token stream (provided by the
+:ref:`TokenLexer <TokenLexer>` class).
+
+.. _Token:
+
+The Token class
+---------------
+
+The ``Token`` class is used to represent a single lexed token. Tokens are
+intended to be used by the lexer/preprocess and parser libraries, but are not
+intended to live beyond them (for example, they should not live in the ASTs).
+
+Tokens most often live on the stack (or some other location that is efficient
+to access) as the parser is running, but occasionally do get buffered up. For
+example, macro definitions are stored as a series of tokens, and the C++
+front-end periodically needs to buffer tokens up for tentative parsing and
+various pieces of look-ahead. As such, the size of a ``Token`` matters. On a
+32-bit system, ``sizeof(Token)`` is currently 16 bytes.
+
+Tokens occur in two forms: :ref:`annotation tokens <AnnotationToken>` and
+normal tokens. Normal tokens are those returned by the lexer, annotation
+tokens represent semantic information and are produced by the parser, replacing
+normal tokens in the token stream. Normal tokens contain the following
+information:
+
+* **A SourceLocation** --- This indicates the location of the start of the
+ token.
+
+* **A length** --- This stores the length of the token as stored in the
+ ``SourceBuffer``. For tokens that include them, this length includes
+ trigraphs and escaped newlines which are ignored by later phases of the
+ compiler. By pointing into the original source buffer, it is always possible
+ to get the original spelling of a token completely accurately.
+
+* **IdentifierInfo** --- If a token takes the form of an identifier, and if
+ identifier lookup was enabled when the token was lexed (e.g., the lexer was
+ not reading in "raw" mode) this contains a pointer to the unique hash value
+ for the identifier. Because the lookup happens before keyword
+ identification, this field is set even for language keywords like "``for``".
+
+* **TokenKind** --- This indicates the kind of token as classified by the
+ lexer. This includes things like ``tok::starequal`` (for the "``*=``"
+ operator), ``tok::ampamp`` for the "``&&``" token, and keyword values (e.g.,
+ ``tok::kw_for``) for identifiers that correspond to keywords. Note that
+ some tokens can be spelled multiple ways. For example, C++ supports
+ "operator keywords", where things like "``and``" are treated exactly like the
+ "``&&``" operator. In these cases, the kind value is set to ``tok::ampamp``,
+ which is good for the parser, which doesn't have to consider both forms. For
+ something that cares about which form is used (e.g., the preprocessor
+ "stringize" operator) the spelling indicates the original form.
+
+* **Flags** --- There are currently four flags tracked by the
+ lexer/preprocessor system on a per-token basis:
+
+ #. **StartOfLine** --- This was the first token that occurred on its input
+ source line.
+ #. **LeadingSpace** --- There was a space character either immediately before
+ the token or transitively before the token as it was expanded through a
+ macro. The definition of this flag is very closely defined by the
+ stringizing requirements of the preprocessor.
+ #. **DisableExpand** --- This flag is used internally to the preprocessor to
+ represent identifier tokens which have macro expansion disabled. This
+ prevents them from being considered as candidates for macro expansion ever
+ in the future.
+ #. **NeedsCleaning** --- This flag is set if the original spelling for the
+ token includes a trigraph or escaped newline. Since this is uncommon,
+ many pieces of code can fast-path on tokens that did not need cleaning.
+
+One interesting (and somewhat unusual) aspect of normal tokens is that they
+don't contain any semantic information about the lexed value. For example, if
+the token was a pp-number token, we do not represent the value of the number
+that was lexed (this is left for later pieces of code to decide).
+Additionally, the lexer library has no notion of typedef names vs variable
+names: both are returned as identifiers, and the parser is left to decide
+whether a specific identifier is a typedef or a variable (tracking this
+requires scope information among other things). The parser can do this
+translation by replacing tokens returned by the preprocessor with "Annotation
+Tokens".
+
+.. _AnnotationToken:
+
+Annotation Tokens
+-----------------
+
+Annotation tokens are tokens that are synthesized by the parser and injected
+into the preprocessor's token stream (replacing existing tokens) to record
+semantic information found by the parser. For example, if "``foo``" is found
+to be a typedef, the "``foo``" ``tok::identifier`` token is replaced with an
+``tok::annot_typename``. This is useful for a couple of reasons: 1) this makes
+it easy to handle qualified type names (e.g., "``foo::bar::baz<42>::t``") in
+C++ as a single "token" in the parser. 2) if the parser backtracks, the
+reparse does not need to redo semantic analysis to determine whether a token
+sequence is a variable, type, template, etc.
+
+Annotation tokens are created by the parser and reinjected into the parser's
+token stream (when backtracking is enabled). Because they can only exist in
+tokens that the preprocessor-proper is done with, it doesn't need to keep
+around flags like "start of line" that the preprocessor uses to do its job.
+Additionally, an annotation token may "cover" a sequence of preprocessor tokens
+(e.g., "``a::b::c``" is five preprocessor tokens). As such, the valid fields
+of an annotation token are different than the fields for a normal token (but
+they are multiplexed into the normal ``Token`` fields):
+
+* **SourceLocation "Location"** --- The ``SourceLocation`` for the annotation
+ token indicates the first token replaced by the annotation token. In the
+ example above, it would be the location of the "``a``" identifier.
+* **SourceLocation "AnnotationEndLoc"** --- This holds the location of the last
+ token replaced with the annotation token. In the example above, it would be
+ the location of the "``c``" identifier.
+* **void* "AnnotationValue"** --- This contains an opaque object that the
+ parser gets from ``Sema``. The parser merely preserves the information for
+ ``Sema`` to later interpret based on the annotation token kind.
+* **TokenKind "Kind"** --- This indicates the kind of Annotation token this is.
+ See below for the different valid kinds.
+
+Annotation tokens currently come in three kinds:
+
+#. **tok::annot_typename**: This annotation token represents a resolved
+ typename token that is potentially qualified. The ``AnnotationValue`` field
+ contains the ``QualType`` returned by ``Sema::getTypeName()``, possibly with
+ source location information attached.
+#. **tok::annot_cxxscope**: This annotation token represents a C++ scope
+ specifier, such as "``A::B::``". This corresponds to the grammar
+ productions "*::*" and "*:: [opt] nested-name-specifier*". The
+ ``AnnotationValue`` pointer is a ``NestedNameSpecifier *`` returned by the
+ ``Sema::ActOnCXXGlobalScopeSpecifier`` and
+ ``Sema::ActOnCXXNestedNameSpecifier`` callbacks.
+#. **tok::annot_template_id**: This annotation token represents a C++
+ template-id such as "``foo<int, 4>``", where "``foo``" is the name of a
+ template. The ``AnnotationValue`` pointer is a pointer to a ``malloc``'d
+ ``TemplateIdAnnotation`` object. Depending on the context, a parsed
+ template-id that names a type might become a typename annotation token (if
+ all we care about is the named type, e.g., because it occurs in a type
+ specifier) or might remain a template-id token (if we want to retain more
+ source location information or produce a new type, e.g., in a declaration of
+ a class template specialization). template-id annotation tokens that refer
+ to a type can be "upgraded" to typename annotation tokens by the parser.
+
+As mentioned above, annotation tokens are not returned by the preprocessor,
+they are formed on demand by the parser. This means that the parser has to be
+aware of cases where an annotation could occur and form it where appropriate.
+This is somewhat similar to how the parser handles Translation Phase 6 of C99:
+String Concatenation (see C99 5.1.1.2). In the case of string concatenation,
+the preprocessor just returns distinct ``tok::string_literal`` and
+``tok::wide_string_literal`` tokens and the parser eats a sequence of them
+wherever the grammar indicates that a string literal can occur.
+
+In order to do this, whenever the parser expects a ``tok::identifier`` or
+``tok::coloncolon``, it should call the ``TryAnnotateTypeOrScopeToken`` or
+``TryAnnotateCXXScopeToken`` methods to form the annotation token. These
+methods will maximally form the specified annotation tokens and replace the
+current token with them, if applicable. If the current tokens is not valid for
+an annotation token, it will remain an identifier or "``::``" token.
+
+.. _Lexer:
+
+The ``Lexer`` class
+-------------------
+
+The ``Lexer`` class provides the mechanics of lexing tokens out of a source
+buffer and deciding what they mean. The ``Lexer`` is complicated by the fact
+that it operates on raw buffers that have not had spelling eliminated (this is
+a necessity to get decent performance), but this is countered with careful
+coding as well as standard performance techniques (for example, the comment
+handling code is vectorized on X86 and PowerPC hosts).
+
+The lexer has a couple of interesting modal features:
+
+* The lexer can operate in "raw" mode. This mode has several features that
+ make it possible to quickly lex the file (e.g., it stops identifier lookup,
+ doesn't specially handle preprocessor tokens, handles EOF differently, etc).
+ This mode is used for lexing within an "``#if 0``" block, for example.
+* The lexer can capture and return comments as tokens. This is required to
+ support the ``-C`` preprocessor mode, which passes comments through, and is
+ used by the diagnostic checker to identifier expect-error annotations.
+* The lexer can be in ``ParsingFilename`` mode, which happens when
+ preprocessing after reading a ``#include`` directive. This mode changes the
+ parsing of "``<``" to return an "angled string" instead of a bunch of tokens
+ for each thing within the filename.
+* When parsing a preprocessor directive (after "``#``") the
+ ``ParsingPreprocessorDirective`` mode is entered. This changes the parser to
+ return EOD at a newline.
+* The ``Lexer`` uses a ``LangOptions`` object to know whether trigraphs are
+ enabled, whether C++ or ObjC keywords are recognized, etc.
+
+In addition to these modes, the lexer keeps track of a couple of other features
+that are local to a lexed buffer, which change as the buffer is lexed:
+
+* The ``Lexer`` uses ``BufferPtr`` to keep track of the current character being
+ lexed.
+* The ``Lexer`` uses ``IsAtStartOfLine`` to keep track of whether the next
+ lexed token will start with its "start of line" bit set.
+* The ``Lexer`` keeps track of the current "``#if``" directives that are active
+ (which can be nested).
+* The ``Lexer`` keeps track of an :ref:`MultipleIncludeOpt
+ <MultipleIncludeOpt>` object, which is used to detect whether the buffer uses
+ the standard "``#ifndef XX`` / ``#define XX``" idiom to prevent multiple
+ inclusion. If a buffer does, subsequent includes can be ignored if the
+ "``XX``" macro is defined.
+
+.. _TokenLexer:
+
+The ``TokenLexer`` class
+------------------------
+
+The ``TokenLexer`` class is a token provider that returns tokens from a list of
+tokens that came from somewhere else. It typically used for two things: 1)
+returning tokens from a macro definition as it is being expanded 2) returning
+tokens from an arbitrary buffer of tokens. The later use is used by
+``_Pragma`` and will most likely be used to handle unbounded look-ahead for the
+C++ parser.
+
+.. _MultipleIncludeOpt:
+
+The ``MultipleIncludeOpt`` class
+--------------------------------
+
+The ``MultipleIncludeOpt`` class implements a really simple little state
+machine that is used to detect the standard "``#ifndef XX`` / ``#define XX``"
+idiom that people typically use to prevent multiple inclusion of headers. If a
+buffer uses this idiom and is subsequently ``#include``'d, the preprocessor can
+simply check to see whether the guarding condition is defined or not. If so,
+the preprocessor can completely ignore the include of the header.
+
+The Parser Library
+==================
+
+The AST Library
+===============
+
+.. _Type:
+
+The ``Type`` class and its subclasses
+-------------------------------------
+
+The ``Type`` class (and its subclasses) are an important part of the AST.
+Types are accessed through the ``ASTContext`` class, which implicitly creates
+and uniques them as they are needed. Types have a couple of non-obvious
+features: 1) they do not capture type qualifiers like ``const`` or ``volatile``
+(see :ref:`QualType <QualType>`), and 2) they implicitly capture typedef
+information. Once created, types are immutable (unlike decls).
+
+Typedefs in C make semantic analysis a bit more complex than it would be without
+them. The issue is that we want to capture typedef information and represent it
+in the AST perfectly, but the semantics of operations need to "see through"
+typedefs. For example, consider this code:
+
+.. code-block:: c++
+
+ void func() {
+ typedef int foo;
+ foo X, *Y;
+ typedef foo *bar;
+ bar Z;
+ *X; // error
+ **Y; // error
+ **Z; // error
+ }
+
+The code above is illegal, and thus we expect there to be diagnostics emitted
+on the annotated lines. In this example, we expect to get:
+
+.. code-block:: c++
+
+ test.c:6:1: error: indirection requires pointer operand ('foo' invalid)
+ *X; // error
+ ^~
+ test.c:7:1: error: indirection requires pointer operand ('foo' invalid)
+ **Y; // error
+ ^~~
+ test.c:8:1: error: indirection requires pointer operand ('foo' invalid)
+ **Z; // error
+ ^~~
+
+While this example is somewhat silly, it illustrates the point: we want to
+retain typedef information where possible, so that we can emit errors about
+"``std::string``" instead of "``std::basic_string<char, std:...``". Doing this
+requires properly keeping typedef information (for example, the type of ``X``
+is "``foo``", not "``int``"), and requires properly propagating it through the
+various operators (for example, the type of ``*Y`` is "``foo``", not
+"``int``"). In order to retain this information, the type of these expressions
+is an instance of the ``TypedefType`` class, which indicates that the type of
+these expressions is a typedef for "``foo``".
+
+Representing types like this is great for diagnostics, because the
+user-specified type is always immediately available. There are two problems
+with this: first, various semantic checks need to make judgements about the
+*actual structure* of a type, ignoring typedefs. Second, we need an efficient
+way to query whether two types are structurally identical to each other,
+ignoring typedefs. The solution to both of these problems is the idea of
+canonical types.
+
+Canonical Types
+^^^^^^^^^^^^^^^
+
+Every instance of the ``Type`` class contains a canonical type pointer. For
+simple types with no typedefs involved (e.g., "``int``", "``int*``",
+"``int**``"), the type just points to itself. For types that have a typedef
+somewhere in their structure (e.g., "``foo``", "``foo*``", "``foo**``",
+"``bar``"), the canonical type pointer points to their structurally equivalent
+type without any typedefs (e.g., "``int``", "``int*``", "``int**``", and
+"``int*``" respectively).
+
+This design provides a constant time operation (dereferencing the canonical type
+pointer) that gives us access to the structure of types. For example, we can
+trivially tell that "``bar``" and "``foo*``" are the same type by dereferencing
+their canonical type pointers and doing a pointer comparison (they both point
+to the single "``int*``" type).
+
+Canonical types and typedef types bring up some complexities that must be
+carefully managed. Specifically, the ``isa``/``cast``/``dyn_cast`` operators
+generally shouldn't be used in code that is inspecting the AST. For example,
+when type checking the indirection operator (unary "``*``" on a pointer), the
+type checker must verify that the operand has a pointer type. It would not be
+correct to check that with "``isa<PointerType>(SubExpr->getType())``", because
+this predicate would fail if the subexpression had a typedef type.
+
+The solution to this problem are a set of helper methods on ``Type``, used to
+check their properties. In this case, it would be correct to use
+"``SubExpr->getType()->isPointerType()``" to do the check. This predicate will
+return true if the *canonical type is a pointer*, which is true any time the
+type is structurally a pointer type. The only hard part here is remembering
+not to use the ``isa``/``cast``/``dyn_cast`` operations.
+
+The second problem we face is how to get access to the pointer type once we
+know it exists. To continue the example, the result type of the indirection
+operator is the pointee type of the subexpression. In order to determine the
+type, we need to get the instance of ``PointerType`` that best captures the
+typedef information in the program. If the type of the expression is literally
+a ``PointerType``, we can return that, otherwise we have to dig through the
+typedefs to find the pointer type. For example, if the subexpression had type
+"``foo*``", we could return that type as the result. If the subexpression had
+type "``bar``", we want to return "``foo*``" (note that we do *not* want
+"``int*``"). In order to provide all of this, ``Type`` has a
+``getAsPointerType()`` method that checks whether the type is structurally a
+``PointerType`` and, if so, returns the best one. If not, it returns a null
+pointer.
+
+This structure is somewhat mystical, but after meditating on it, it will make
+sense to you :).
+
+.. _QualType:
+
+The ``QualType`` class
+----------------------
+
+The ``QualType`` class is designed as a trivial value class that is small,
+passed by-value and is efficient to query. The idea of ``QualType`` is that it
+stores the type qualifiers (``const``, ``volatile``, ``restrict``, plus some
+extended qualifiers required by language extensions) separately from the types
+themselves. ``QualType`` is conceptually a pair of "``Type*``" and the bits
+for these type qualifiers.
+
+By storing the type qualifiers as bits in the conceptual pair, it is extremely
+efficient to get the set of qualifiers on a ``QualType`` (just return the field
+of the pair), add a type qualifier (which is a trivial constant-time operation
+that sets a bit), and remove one or more type qualifiers (just return a
+``QualType`` with the bitfield set to empty).
+
+Further, because the bits are stored outside of the type itself, we do not need
+to create duplicates of types with different sets of qualifiers (i.e. there is
+only a single heap allocated "``int``" type: "``const int``" and "``volatile
+const int``" both point to the same heap allocated "``int``" type). This
+reduces the heap size used to represent bits and also means we do not have to
+consider qualifiers when uniquing types (:ref:`Type <Type>` does not even
+contain qualifiers).
+
+In practice, the two most common type qualifiers (``const`` and ``restrict``)
+are stored in the low bits of the pointer to the ``Type`` object, together with
+a flag indicating whether extended qualifiers are present (which must be
+heap-allocated). This means that ``QualType`` is exactly the same size as a
+pointer.
+
+.. _DeclarationName:
+
+Declaration names
+-----------------
+
+The ``DeclarationName`` class represents the name of a declaration in Clang.
+Declarations in the C family of languages can take several different forms.
+Most declarations are named by simple identifiers, e.g., "``f``" and "``x``" in
+the function declaration ``f(int x)``. In C++, declaration names can also name
+class constructors ("``Class``" in ``struct Class { Class(); }``), class
+destructors ("``~Class``"), overloaded operator names ("``operator+``"), and
+conversion functions ("``operator void const *``"). In Objective-C,
+declaration names can refer to the names of Objective-C methods, which involve
+the method name and the parameters, collectively called a *selector*, e.g.,
+"``setWidth:height:``". Since all of these kinds of entities --- variables,
+functions, Objective-C methods, C++ constructors, destructors, and operators
+--- are represented as subclasses of Clang's common ``NamedDecl`` class,
+``DeclarationName`` is designed to efficiently represent any kind of name.
+
+Given a ``DeclarationName`` ``N``, ``N.getNameKind()`` will produce a value
+that describes what kind of name ``N`` stores. There are 8 options (all of the
+names are inside the ``DeclarationName`` class).
+
+``Identifier``
+
+ The name is a simple identifier. Use ``N.getAsIdentifierInfo()`` to retrieve
+ the corresponding ``IdentifierInfo*`` pointing to the actual identifier.
+ Note that C++ overloaded operators (e.g., "``operator+``") are represented as
+ special kinds of identifiers. Use ``IdentifierInfo``'s
+ ``getOverloadedOperatorID`` function to determine whether an identifier is an
+ overloaded operator name.
+
+``ObjCZeroArgSelector``, ``ObjCOneArgSelector``, ``ObjCMultiArgSelector``
+
+ The name is an Objective-C selector, which can be retrieved as a ``Selector``
+ instance via ``N.getObjCSelector()``. The three possible name kinds for
+ Objective-C reflect an optimization within the ``DeclarationName`` class:
+ both zero- and one-argument selectors are stored as a masked
+ ``IdentifierInfo`` pointer, and therefore require very little space, since
+ zero- and one-argument selectors are far more common than multi-argument
+ selectors (which use a different structure).
+
+``CXXConstructorName``
+
+ The name is a C++ constructor name. Use ``N.getCXXNameType()`` to retrieve
+ the :ref:`type <QualType>` that this constructor is meant to construct. The
+ type is always the canonical type, since all constructors for a given type
+ have the same name.
+
+``CXXDestructorName``
+
+ The name is a C++ destructor name. Use ``N.getCXXNameType()`` to retrieve
+ the :ref:`type <QualType>` whose destructor is being named. This type is
+ always a canonical type.
+
+``CXXConversionFunctionName``
+
+ The name is a C++ conversion function. Conversion functions are named
+ according to the type they convert to, e.g., "``operator void const *``".
+ Use ``N.getCXXNameType()`` to retrieve the type that this conversion function
+ converts to. This type is always a canonical type.
+
+``CXXOperatorName``
+
+ The name is a C++ overloaded operator name. Overloaded operators are named
+ according to their spelling, e.g., "``operator+``" or "``operator new []``".
+ Use ``N.getCXXOverloadedOperator()`` to retrieve the overloaded operator (a
+ value of type ``OverloadedOperatorKind``).
+
+``DeclarationName``\ s are cheap to create, copy, and compare. They require
+only a single pointer's worth of storage in the common cases (identifiers,
+zero- and one-argument Objective-C selectors) and use dense, uniqued storage
+for the other kinds of names. Two ``DeclarationName``\ s can be compared for
+equality (``==``, ``!=``) using a simple bitwise comparison, can be ordered
+with ``<``, ``>``, ``<=``, and ``>=`` (which provide a lexicographical ordering
+for normal identifiers but an unspecified ordering for other kinds of names),
+and can be placed into LLVM ``DenseMap``\ s and ``DenseSet``\ s.
+
+``DeclarationName`` instances can be created in different ways depending on
+what kind of name the instance will store. Normal identifiers
+(``IdentifierInfo`` pointers) and Objective-C selectors (``Selector``) can be
+implicitly converted to ``DeclarationNames``. Names for C++ constructors,
+destructors, conversion functions, and overloaded operators can be retrieved
+from the ``DeclarationNameTable``, an instance of which is available as
+``ASTContext::DeclarationNames``. The member functions
+``getCXXConstructorName``, ``getCXXDestructorName``,
+``getCXXConversionFunctionName``, and ``getCXXOperatorName``, respectively,
+return ``DeclarationName`` instances for the four kinds of C++ special function
+names.
+
+.. _DeclContext:
+
+Declaration contexts
+--------------------
+
+Every declaration in a program exists within some *declaration context*, such
+as a translation unit, namespace, class, or function. Declaration contexts in
+Clang are represented by the ``DeclContext`` class, from which the various
+declaration-context AST nodes (``TranslationUnitDecl``, ``NamespaceDecl``,
+``RecordDecl``, ``FunctionDecl``, etc.) will derive. The ``DeclContext`` class
+provides several facilities common to each declaration context:
+
+Source-centric vs. Semantics-centric View of Declarations
+
+ ``DeclContext`` provides two views of the declarations stored within a
+ declaration context. The source-centric view accurately represents the
+ program source code as written, including multiple declarations of entities
+ where present (see the section :ref:`Redeclarations and Overloads
+ <Redeclarations>`), while the semantics-centric view represents the program
+ semantics. The two views are kept synchronized by semantic analysis while
+ the ASTs are being constructed.
+
+Storage of declarations within that context
+
+ Every declaration context can contain some number of declarations. For
+ example, a C++ class (represented by ``RecordDecl``) contains various member
+ functions, fields, nested types, and so on. All of these declarations will
+ be stored within the ``DeclContext``, and one can iterate over the
+ declarations via [``DeclContext::decls_begin()``,
+ ``DeclContext::decls_end()``). This mechanism provides the source-centric
+ view of declarations in the context.
+
+Lookup of declarations within that context
+
+ The ``DeclContext`` structure provides efficient name lookup for names within
+ that declaration context. For example, if ``N`` is a namespace we can look
+ for the name ``N::f`` using ``DeclContext::lookup``. The lookup itself is
+ based on a lazily-constructed array (for declaration contexts with a small
+ number of declarations) or hash table (for declaration contexts with more
+ declarations). The lookup operation provides the semantics-centric view of
+ the declarations in the context.
+
+Ownership of declarations
+
+ The ``DeclContext`` owns all of the declarations that were declared within
+ its declaration context, and is responsible for the management of their
+ memory as well as their (de-)serialization.
+
+All declarations are stored within a declaration context, and one can query
+information about the context in which each declaration lives. One can
+retrieve the ``DeclContext`` that contains a particular ``Decl`` using
+``Decl::getDeclContext``. However, see the section
+:ref:`LexicalAndSemanticContexts` for more information about how to interpret
+this context information.
+
+.. _Redeclarations:
+
+Redeclarations and Overloads
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Within a translation unit, it is common for an entity to be declared several
+times. For example, we might declare a function "``f``" and then later
+re-declare it as part of an inlined definition:
+
+.. code-block:: c++
+
+ void f(int x, int y, int z = 1);
+
+ inline void f(int x, int y, int z) { /* ... */ }
+
+The representation of "``f``" differs in the source-centric and
+semantics-centric views of a declaration context. In the source-centric view,
+all redeclarations will be present, in the order they occurred in the source
+code, making this view suitable for clients that wish to see the structure of
+the source code. In the semantics-centric view, only the most recent "``f``"
+will be found by the lookup, since it effectively replaces the first
+declaration of "``f``".
+
+In the semantics-centric view, overloading of functions is represented
+explicitly. For example, given two declarations of a function "``g``" that are
+overloaded, e.g.,
+
+.. code-block:: c++
+
+ void g();
+ void g(int);
+
+the ``DeclContext::lookup`` operation will return a
+``DeclContext::lookup_result`` that contains a range of iterators over
+declarations of "``g``". Clients that perform semantic analysis on a program
+that is not concerned with the actual source code will primarily use this
+semantics-centric view.
+
+.. _LexicalAndSemanticContexts:
+
+Lexical and Semantic Contexts
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Each declaration has two potentially different declaration contexts: a
+*lexical* context, which corresponds to the source-centric view of the
+declaration context, and a *semantic* context, which corresponds to the
+semantics-centric view. The lexical context is accessible via
+``Decl::getLexicalDeclContext`` while the semantic context is accessible via
+``Decl::getDeclContext``, both of which return ``DeclContext`` pointers. For
+most declarations, the two contexts are identical. For example:
+
+.. code-block:: c++
+
+ class X {
+ public:
+ void f(int x);
+ };
+
+Here, the semantic and lexical contexts of ``X::f`` are the ``DeclContext``
+associated with the class ``X`` (itself stored as a ``RecordDecl`` AST node).
+However, we can now define ``X::f`` out-of-line:
+
+.. code-block:: c++
+
+ void X::f(int x = 17) { /* ... */ }
+
+This definition of "``f``" has different lexical and semantic contexts. The
+lexical context corresponds to the declaration context in which the actual
+declaration occurred in the source code, e.g., the translation unit containing
+``X``. Thus, this declaration of ``X::f`` can be found by traversing the
+declarations provided by [``decls_begin()``, ``decls_end()``) in the
+translation unit.
+
+The semantic context of ``X::f`` corresponds to the class ``X``, since this
+member function is (semantically) a member of ``X``. Lookup of the name ``f``
+into the ``DeclContext`` associated with ``X`` will then return the definition
+of ``X::f`` (including information about the default argument).
+
+Transparent Declaration Contexts
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In C and C++, there are several contexts in which names that are logically
+declared inside another declaration will actually "leak" out into the enclosing
+scope from the perspective of name lookup. The most obvious instance of this
+behavior is in enumeration types, e.g.,
+
+.. code-block:: c++
+
+ enum Color {
+ Red,
+ Green,
+ Blue
+ };
+
+Here, ``Color`` is an enumeration, which is a declaration context that contains
+the enumerators ``Red``, ``Green``, and ``Blue``. Thus, traversing the list of
+declarations contained in the enumeration ``Color`` will yield ``Red``,
+``Green``, and ``Blue``. However, outside of the scope of ``Color`` one can
+name the enumerator ``Red`` without qualifying the name, e.g.,
+
+.. code-block:: c++
+
+ Color c = Red;
+
+There are other entities in C++ that provide similar behavior. For example,
+linkage specifications that use curly braces:
+
+.. code-block:: c++
+
+ extern "C" {
+ void f(int);
+ void g(int);
+ }
+ // f and g are visible here
+
+For source-level accuracy, we treat the linkage specification and enumeration
+type as a declaration context in which its enclosed declarations ("``Red``",
+"``Green``", and "``Blue``"; "``f``" and "``g``") are declared. However, these
+declarations are visible outside of the scope of the declaration context.
+
+These language features (and several others, described below) have roughly the
+same set of requirements: declarations are declared within a particular lexical
+context, but the declarations are also found via name lookup in scopes
+enclosing the declaration itself. This feature is implemented via
+*transparent* declaration contexts (see
+``DeclContext::isTransparentContext()``), whose declarations are visible in the
+nearest enclosing non-transparent declaration context. This means that the
+lexical context of the declaration (e.g., an enumerator) will be the
+transparent ``DeclContext`` itself, as will the semantic context, but the
+declaration will be visible in every outer context up to and including the
+first non-transparent declaration context (since transparent declaration
+contexts can be nested).
+
+The transparent ``DeclContext``\ s are:
+
+* Enumerations (but not C++11 "scoped enumerations"):
+
+ .. code-block:: c++
+
+ enum Color {
+ Red,
+ Green,
+ Blue
+ };
+ // Red, Green, and Blue are in scope
+
+* C++ linkage specifications:
+
+ .. code-block:: c++
+
+ extern "C" {
+ void f(int);
+ void g(int);
+ }
+ // f and g are in scope
+
+* Anonymous unions and structs:
+
+ .. code-block:: c++
+
+ struct LookupTable {
+ bool IsVector;
+ union {
+ std::vector<Item> *Vector;
+ std::set<Item> *Set;
+ };
+ };
+
+ LookupTable LT;
+ LT.Vector = 0; // Okay: finds Vector inside the unnamed union
+
+* C++11 inline namespaces:
+
+ .. code-block:: c++
+
+ namespace mylib {
+ inline namespace debug {
+ class X;
+ }
+ }
+ mylib::X *xp; // okay: mylib::X refers to mylib::debug::X
+
+.. _MultiDeclContext:
+
+Multiply-Defined Declaration Contexts
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+C++ namespaces have the interesting --- and, so far, unique --- property that
+the namespace can be defined multiple times, and the declarations provided by
+each namespace definition are effectively merged (from the semantic point of
+view). For example, the following two code snippets are semantically
+indistinguishable:
+
+.. code-block:: c++
+
+ // Snippet #1:
+ namespace N {
+ void f();
+ }
+ namespace N {
+ void f(int);
+ }
+
+ // Snippet #2:
+ namespace N {
+ void f();
+ void f(int);
+ }
+
+In Clang's representation, the source-centric view of declaration contexts will
+actually have two separate ``NamespaceDecl`` nodes in Snippet #1, each of which
+is a declaration context that contains a single declaration of "``f``".
+However, the semantics-centric view provided by name lookup into the namespace
+``N`` for "``f``" will return a ``DeclContext::lookup_result`` that contains a
+range of iterators over declarations of "``f``".
+
+``DeclContext`` manages multiply-defined declaration contexts internally. The
+function ``DeclContext::getPrimaryContext`` retrieves the "primary" context for
+a given ``DeclContext`` instance, which is the ``DeclContext`` responsible for
+maintaining the lookup table used for the semantics-centric view. Given the
+primary context, one can follow the chain of ``DeclContext`` nodes that define
+additional declarations via ``DeclContext::getNextContext``. Note that these
+functions are used internally within the lookup and insertion methods of the
+``DeclContext``, so the vast majority of clients can ignore them.
+
+.. _CFG:
+
+The ``CFG`` class
+-----------------
+
+The ``CFG`` class is designed to represent a source-level control-flow graph
+for a single statement (``Stmt*``). Typically instances of ``CFG`` are
+constructed for function bodies (usually an instance of ``CompoundStmt``), but
+can also be instantiated to represent the control-flow of any class that
+subclasses ``Stmt``, which includes simple expressions. Control-flow graphs
+are especially useful for performing `flow- or path-sensitive
+<http://en.wikipedia.org/wiki/Data_flow_analysis#Sensitivities>`_ program
+analyses on a given function.
+
+Basic Blocks
+^^^^^^^^^^^^
+
+Concretely, an instance of ``CFG`` is a collection of basic blocks. Each basic
+block is an instance of ``CFGBlock``, which simply contains an ordered sequence
+of ``Stmt*`` (each referring to statements in the AST). The ordering of
+statements within a block indicates unconditional flow of control from one
+statement to the next. :ref:`Conditional control-flow
+<ConditionalControlFlow>` is represented using edges between basic blocks. The
+statements within a given ``CFGBlock`` can be traversed using the
+``CFGBlock::*iterator`` interface.
+
+A ``CFG`` object owns the instances of ``CFGBlock`` within the control-flow
+graph it represents. Each ``CFGBlock`` within a CFG is also uniquely numbered
+(accessible via ``CFGBlock::getBlockID()``). Currently the number is based on
+the ordering the blocks were created, but no assumptions should be made on how
+``CFGBlocks`` are numbered other than their numbers are unique and that they
+are numbered from 0..N-1 (where N is the number of basic blocks in the CFG).
+
+Entry and Exit Blocks
+^^^^^^^^^^^^^^^^^^^^^
+
+Each instance of ``CFG`` contains two special blocks: an *entry* block
+(accessible via ``CFG::getEntry()``), which has no incoming edges, and an
+*exit* block (accessible via ``CFG::getExit()``), which has no outgoing edges.
+Neither block contains any statements, and they serve the role of providing a
+clear entrance and exit for a body of code such as a function body. The
+presence of these empty blocks greatly simplifies the implementation of many
+analyses built on top of CFGs.
+
+.. _ConditionalControlFlow:
+
+Conditional Control-Flow
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+Conditional control-flow (such as those induced by if-statements and loops) is
+represented as edges between ``CFGBlocks``. Because different C language
+constructs can induce control-flow, each ``CFGBlock`` also records an extra
+``Stmt*`` that represents the *terminator* of the block. A terminator is
+simply the statement that caused the control-flow, and is used to identify the
+nature of the conditional control-flow between blocks. For example, in the
+case of an if-statement, the terminator refers to the ``IfStmt`` object in the
+AST that represented the given branch.
+
+To illustrate, consider the following code example:
+
+.. code-block:: c++
+
+ int foo(int x) {
+ x = x + 1;
+ if (x > 2)
+ x++;
+ else {
+ x += 2;
+ x *= 2;
+ }
+
+ return x;
+ }
+
+After invoking the parser+semantic analyzer on this code fragment, the AST of
+the body of ``foo`` is referenced by a single ``Stmt*``. We can then construct
+an instance of ``CFG`` representing the control-flow graph of this function
+body by single call to a static class method:
+
+.. code-block:: c++
+
+ Stmt *FooBody = ...
+ CFG *FooCFG = CFG::buildCFG(FooBody);
+
+It is the responsibility of the caller of ``CFG::buildCFG`` to ``delete`` the
+returned ``CFG*`` when the CFG is no longer needed.
+
+Along with providing an interface to iterate over its ``CFGBlocks``, the
+``CFG`` class also provides methods that are useful for debugging and
+visualizing CFGs. For example, the method ``CFG::dump()`` dumps a
+pretty-printed version of the CFG to standard error. This is especially useful
+when one is using a debugger such as gdb. For example, here is the output of
+``FooCFG->dump()``:
+
+.. code-block:: c++
+
+ [ B5 (ENTRY) ]
+ Predecessors (0):
+ Successors (1): B4
+
+ [ B4 ]
+ 1: x = x + 1
+ 2: (x > 2)
+ T: if [B4.2]
+ Predecessors (1): B5
+ Successors (2): B3 B2
+
+ [ B3 ]
+ 1: x++
+ Predecessors (1): B4
+ Successors (1): B1
+
+ [ B2 ]
+ 1: x += 2
+ 2: x *= 2
+ Predecessors (1): B4
+ Successors (1): B1
+
+ [ B1 ]
+ 1: return x;
+ Predecessors (2): B2 B3
+ Successors (1): B0
+
+ [ B0 (EXIT) ]
+ Predecessors (1): B1
+ Successors (0):
+
+For each block, the pretty-printed output displays for each block the number of
+*predecessor* blocks (blocks that have outgoing control-flow to the given
+block) and *successor* blocks (blocks that have control-flow that have incoming
+control-flow from the given block). We can also clearly see the special entry
+and exit blocks at the beginning and end of the pretty-printed output. For the
+entry block (block B5), the number of predecessor blocks is 0, while for the
+exit block (block B0) the number of successor blocks is 0.
+
+The most interesting block here is B4, whose outgoing control-flow represents
+the branching caused by the sole if-statement in ``foo``. Of particular
+interest is the second statement in the block, ``(x > 2)``, and the terminator,
+printed as ``if [B4.2]``. The second statement represents the evaluation of
+the condition of the if-statement, which occurs before the actual branching of
+control-flow. Within the ``CFGBlock`` for B4, the ``Stmt*`` for the second
+statement refers to the actual expression in the AST for ``(x > 2)``. Thus
+pointers to subclasses of ``Expr`` can appear in the list of statements in a
+block, and not just subclasses of ``Stmt`` that refer to proper C statements.
+
+The terminator of block B4 is a pointer to the ``IfStmt`` object in the AST.
+The pretty-printer outputs ``if [B4.2]`` because the condition expression of
+the if-statement has an actual place in the basic block, and thus the
+terminator is essentially *referring* to the expression that is the second
+statement of block B4 (i.e., B4.2). In this manner, conditions for
+control-flow (which also includes conditions for loops and switch statements)
+are hoisted into the actual basic block.
+
+.. Implicit Control-Flow
+.. ^^^^^^^^^^^^^^^^^^^^^
+
+.. A key design principle of the ``CFG`` class was to not require any
+.. transformations to the AST in order to represent control-flow. Thus the
+.. ``CFG`` does not perform any "lowering" of the statements in an AST: loops
+.. are not transformed into guarded gotos, short-circuit operations are not
+.. converted to a set of if-statements, and so on.
+
+Constant Folding in the Clang AST
+---------------------------------
+
+There are several places where constants and constant folding matter a lot to
+the Clang front-end. First, in general, we prefer the AST to retain the source
+code as close to how the user wrote it as possible. This means that if they
+wrote "``5+4``", we want to keep the addition and two constants in the AST, we
+don't want to fold to "``9``". This means that constant folding in various
+ways turns into a tree walk that needs to handle the various cases.
+
+However, there are places in both C and C++ that require constants to be
+folded. For example, the C standard defines what an "integer constant
+expression" (i-c-e) is with very precise and specific requirements. The
+language then requires i-c-e's in a lot of places (for example, the size of a
+bitfield, the value for a case statement, etc). For these, we have to be able
+to constant fold the constants, to do semantic checks (e.g., verify bitfield
+size is non-negative and that case statements aren't duplicated). We aim for
+Clang to be very pedantic about this, diagnosing cases when the code does not
+use an i-c-e where one is required, but accepting the code unless running with
+``-pedantic-errors``.
+
+Things get a little bit more tricky when it comes to compatibility with
+real-world source code. Specifically, GCC has historically accepted a huge
+superset of expressions as i-c-e's, and a lot of real world code depends on
+this unfortuate accident of history (including, e.g., the glibc system
+headers). GCC accepts anything its "fold" optimizer is capable of reducing to
+an integer constant, which means that the definition of what it accepts changes
+as its optimizer does. One example is that GCC accepts things like "``case
+X-X:``" even when ``X`` is a variable, because it can fold this to 0.
+
+Another issue are how constants interact with the extensions we support, such
+as ``__builtin_constant_p``, ``__builtin_inf``, ``__extension__`` and many
+others. C99 obviously does not specify the semantics of any of these
+extensions, and the definition of i-c-e does not include them. However, these
+extensions are often used in real code, and we have to have a way to reason
+about them.
+
+Finally, this is not just a problem for semantic analysis. The code generator
+and other clients have to be able to fold constants (e.g., to initialize global
+variables) and has to handle a superset of what C99 allows. Further, these
+clients can benefit from extended information. For example, we know that
+"``foo() || 1``" always evaluates to ``true``, but we can't replace the
+expression with ``true`` because it has side effects.
+
+Implementation Approach
+^^^^^^^^^^^^^^^^^^^^^^^
+
+After trying several different approaches, we've finally converged on a design
+(Note, at the time of this writing, not all of this has been implemented,
+consider this a design goal!). Our basic approach is to define a single
+recursive method evaluation method (``Expr::Evaluate``), which is implemented
+in ``AST/ExprConstant.cpp``. Given an expression with "scalar" type (integer,
+fp, complex, or pointer) this method returns the following information:
+
+* Whether the expression is an integer constant expression, a general constant
+ that was folded but has no side effects, a general constant that was folded
+ but that does have side effects, or an uncomputable/unfoldable value.
+* If the expression was computable in any way, this method returns the
+ ``APValue`` for the result of the expression.
+* If the expression is not evaluatable at all, this method returns information
+ on one of the problems with the expression. This includes a
+ ``SourceLocation`` for where the problem is, and a diagnostic ID that explains
+ the problem. The diagnostic should have ``ERROR`` type.
+* If the expression is not an integer constant expression, this method returns
+ information on one of the problems with the expression. This includes a
+ ``SourceLocation`` for where the problem is, and a diagnostic ID that
+ explains the problem. The diagnostic should have ``EXTENSION`` type.
+
+This information gives various clients the flexibility that they want, and we
+will eventually have some helper methods for various extensions. For example,
+``Sema`` should have a ``Sema::VerifyIntegerConstantExpression`` method, which
+calls ``Evaluate`` on the expression. If the expression is not foldable, the
+error is emitted, and it would return ``true``. If the expression is not an
+i-c-e, the ``EXTENSION`` diagnostic is emitted. Finally it would return
+``false`` to indicate that the AST is OK.
+
+Other clients can use the information in other ways, for example, codegen can
+just use expressions that are foldable in any way.
+
+Extensions
+^^^^^^^^^^
+
+This section describes how some of the various extensions Clang supports
+interacts with constant evaluation:
+
+* ``__extension__``: The expression form of this extension causes any
+ evaluatable subexpression to be accepted as an integer constant expression.
+* ``__builtin_constant_p``: This returns true (as an integer constant
+ expression) if the operand evaluates to either a numeric value (that is, not
+ a pointer cast to integral type) of integral, enumeration, floating or
+ complex type, or if it evaluates to the address of the first character of a
+ string literal (possibly cast to some other type). As a special case, if
+ ``__builtin_constant_p`` is the (potentially parenthesized) condition of a
+ conditional operator expression ("``?:``"), only the true side of the
+ conditional operator is considered, and it is evaluated with full constant
+ folding.
+* ``__builtin_choose_expr``: The condition is required to be an integer
+ constant expression, but we accept any constant as an "extension of an
+ extension". This only evaluates one operand depending on which way the
+ condition evaluates.
+* ``__builtin_classify_type``: This always returns an integer constant
+ expression.
+* ``__builtin_inf, nan, ...``: These are treated just like a floating-point
+ literal.
+* ``__builtin_abs, copysign, ...``: These are constant folded as general
+ constant expressions.
+* ``__builtin_strlen`` and ``strlen``: These are constant folded as integer
+ constant expressions if the argument is a string literal.
+
+How to change Clang
+===================
+
+How to add an attribute
+-----------------------
+
+To add an attribute, you'll have to add it to the list of attributes, add it to
+the parsing phase, and look for it in the AST scan.
+`r124217 <http://llvm.org/viewvc/llvm-project?view=rev&revision=124217>`_
+has a good example of adding a warning attribute.
+
+(Beware that this hasn't been reviewed/fixed by the people who designed the
+attributes system yet.)
+
+
+``include/clang/Basic/Attr.td``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+First, add your attribute to the `include/clang/Basic/Attr.td file
+<http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?view=markup>`_.
+
+Each attribute gets a ``def`` inheriting from ``Attr`` or one of its
+subclasses. ``InheritableAttr`` means that the attribute also applies to
+subsequent declarations of the same name.
+
+``Spellings`` lists the strings that can appear in ``__attribute__((here))`` or
+``[[here]]``. All such strings will be synonymous. If you want to allow the
+``[[]]`` C++11 syntax, you have to define a list of ``Namespaces``, which will
+let users write ``[[namespace::spelling]]``. Using the empty string for a
+namespace will allow users to write just the spelling with no "``::``".
+Attributes which g++-4.8 accepts should also have a
+``CXX11<"gnu", "spelling">`` spelling.
+
+``Subjects`` restricts what kinds of AST node to which this attribute can
+appertain (roughly, attach).
+
+``Args`` names the arguments the attribute takes, in order. If ``Args`` is
+``[StringArgument<"Arg1">, IntArgument<"Arg2">]`` then
+``__attribute__((myattribute("Hello", 3)))`` will be a valid use.
+
+Boilerplate
+^^^^^^^^^^^
+
+Write a new ``HandleYourAttr()`` function in `lib/Sema/SemaDeclAttr.cpp
+<http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?view=markup>`_,
+and add a case to the switch in ``ProcessNonInheritableDeclAttr()`` or
+``ProcessInheritableDeclAttr()`` forwarding to it.
+
+If your attribute causes extra warnings to fire, define a ``DiagGroup`` in
+`include/clang/Basic/DiagnosticGroups.td
+<http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?view=markup>`_
+named after the attribute's ``Spelling`` with "_"s replaced by "-"s. If you're
+only defining one diagnostic, you can skip ``DiagnosticGroups.td`` and use
+``InGroup<DiagGroup<"your-attribute">>`` directly in `DiagnosticSemaKinds.td
+<http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?view=markup>`_
+
+The meat of your attribute
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Find an appropriate place in Clang to do whatever your attribute needs to do.
+Check for the attribute's presence using ``Decl::getAttr<YourAttr>()``.
+
+Update the :doc:`LanguageExtensions` document to describe your new attribute.
+
+How to add an expression or statement
+-------------------------------------
+
+Expressions and statements are one of the most fundamental constructs within a
+compiler, because they interact with many different parts of the AST, semantic
+analysis, and IR generation. Therefore, adding a new expression or statement
+kind into Clang requires some care. The following list details the various
+places in Clang where an expression or statement needs to be introduced, along
+with patterns to follow to ensure that the new expression or statement works
+well across all of the C languages. We focus on expressions, but statements
+are similar.
+
+#. Introduce parsing actions into the parser. Recursive-descent parsing is
+ mostly self-explanatory, but there are a few things that are worth keeping
+ in mind:
+
+ * Keep as much source location information as possible! You'll want it later
+ to produce great diagnostics and support Clang's various features that map
+ between source code and the AST.
+ * Write tests for all of the "bad" parsing cases, to make sure your recovery
+ is good. If you have matched delimiters (e.g., parentheses, square
+ brackets, etc.), use ``Parser::BalancedDelimiterTracker`` to give nice
+ diagnostics when things go wrong.
+
+#. Introduce semantic analysis actions into ``Sema``. Semantic analysis should
+ always involve two functions: an ``ActOnXXX`` function that will be called
+ directly from the parser, and a ``BuildXXX`` function that performs the
+ actual semantic analysis and will (eventually!) build the AST node. It's
+ fairly common for the ``ActOnCXX`` function to do very little (often just
+ some minor translation from the parser's representation to ``Sema``'s
+ representation of the same thing), but the separation is still important:
+ C++ template instantiation, for example, should always call the ``BuildXXX``
+ variant. Several notes on semantic analysis before we get into construction
+ of the AST:
+
+ * Your expression probably involves some types and some subexpressions.
+ Make sure to fully check that those types, and the types of those
+ subexpressions, meet your expectations. Add implicit conversions where
+ necessary to make sure that all of the types line up exactly the way you
+ want them. Write extensive tests to check that you're getting good
+ diagnostics for mistakes and that you can use various forms of
+ subexpressions with your expression.
+ * When type-checking a type or subexpression, make sure to first check
+ whether the type is "dependent" (``Type::isDependentType()``) or whether a
+ subexpression is type-dependent (``Expr::isTypeDependent()``). If any of
+ these return ``true``, then you're inside a template and you can't do much
+ type-checking now. That's normal, and your AST node (when you get there)
+ will have to deal with this case. At this point, you can write tests that
+ use your expression within templates, but don't try to instantiate the
+ templates.
+ * For each subexpression, be sure to call ``Sema::CheckPlaceholderExpr()``
+ to deal with "weird" expressions that don't behave well as subexpressions.
+ Then, determine whether you need to perform lvalue-to-rvalue conversions
+ (``Sema::DefaultLvalueConversions``) or the usual unary conversions
+ (``Sema::UsualUnaryConversions``), for places where the subexpression is
+ producing a value you intend to use.
+ * Your ``BuildXXX`` function will probably just return ``ExprError()`` at
+ this point, since you don't have an AST. That's perfectly fine, and
+ shouldn't impact your testing.
+
+#. Introduce an AST node for your new expression. This starts with declaring
+ the node in ``include/Basic/StmtNodes.td`` and creating a new class for your
+ expression in the appropriate ``include/AST/Expr*.h`` header. It's best to
+ look at the class for a similar expression to get ideas, and there are some
+ specific things to watch for:
+
+ * If you need to allocate memory, use the ``ASTContext`` allocator to
+ allocate memory. Never use raw ``malloc`` or ``new``, and never hold any
+ resources in an AST node, because the destructor of an AST node is never
+ called.
+ * Make sure that ``getSourceRange()`` covers the exact source range of your
+ expression. This is needed for diagnostics and for IDE support.
+ * Make sure that ``children()`` visits all of the subexpressions. This is
+ important for a number of features (e.g., IDE support, C++ variadic
+ templates). If you have sub-types, you'll also need to visit those
+ sub-types in the ``RecursiveASTVisitor``.
+ * Add printing support (``StmtPrinter.cpp``) and dumping support
+ (``StmtDumper.cpp``) for your expression.
+ * Add profiling support (``StmtProfile.cpp``) for your AST node, noting the
+ distinguishing (non-source location) characteristics of an instance of
+ your expression. Omitting this step will lead to hard-to-diagnose
+ failures regarding matching of template declarations.
+
+#. Teach semantic analysis to build your AST node. At this point, you can wire
+ up your ``Sema::BuildXXX`` function to actually create your AST. A few
+ things to check at this point:
+
+ * If your expression can construct a new C++ class or return a new
+ Objective-C object, be sure to update and then call
+ ``Sema::MaybeBindToTemporary`` for your just-created AST node to be sure
+ that the object gets properly destructed. An easy way to test this is to
+ return a C++ class with a private destructor: semantic analysis should
+ flag an error here with the attempt to call the destructor.
+ * Inspect the generated AST by printing it using ``clang -cc1 -ast-print``,
+ to make sure you're capturing all of the important information about how
+ the AST was written.
+ * Inspect the generated AST under ``clang -cc1 -ast-dump`` to verify that
+ all of the types in the generated AST line up the way you want them.
+ Remember that clients of the AST should never have to "think" to
+ understand what's going on. For example, all implicit conversions should
+ show up explicitly in the AST.
+ * Write tests that use your expression as a subexpression of other,
+ well-known expressions. Can you call a function using your expression as
+ an argument? Can you use the ternary operator?
+
+#. Teach code generation to create IR to your AST node. This step is the first
+ (and only) that requires knowledge of LLVM IR. There are several things to
+ keep in mind:
+
+ * Code generation is separated into scalar/aggregate/complex and
+ lvalue/rvalue paths, depending on what kind of result your expression
+ produces. On occasion, this requires some careful factoring of code to
+ avoid duplication.
+ * ``CodeGenFunction`` contains functions ``ConvertType`` and
+ ``ConvertTypeForMem`` that convert Clang's types (``clang::Type*`` or
+ ``clang::QualType``) to LLVM types. Use the former for values, and the
+ later for memory locations: test with the C++ "``bool``" type to check
+ this. If you find that you are having to use LLVM bitcasts to make the
+ subexpressions of your expression have the type that your expression
+ expects, STOP! Go fix semantic analysis and the AST so that you don't
+ need these bitcasts.
+ * The ``CodeGenFunction`` class has a number of helper functions to make
+ certain operations easy, such as generating code to produce an lvalue or
+ an rvalue, or to initialize a memory location with a given value. Prefer
+ to use these functions rather than directly writing loads and stores,
+ because these functions take care of some of the tricky details for you
+ (e.g., for exceptions).
+ * If your expression requires some special behavior in the event of an
+ exception, look at the ``push*Cleanup`` functions in ``CodeGenFunction``
+ to introduce a cleanup. You shouldn't have to deal with
+ exception-handling directly.
+ * Testing is extremely important in IR generation. Use ``clang -cc1
+ -emit-llvm`` and `FileCheck
+ <http://llvm.org/docs/CommandGuide/FileCheck.html>`_ to verify that you're
+ generating the right IR.
+
+#. Teach template instantiation how to cope with your AST node, which requires
+ some fairly simple code:
+
+ * Make sure that your expression's constructor properly computes the flags
+ for type dependence (i.e., the type your expression produces can change
+ from one instantiation to the next), value dependence (i.e., the constant
+ value your expression produces can change from one instantiation to the
+ next), instantiation dependence (i.e., a template parameter occurs
+ anywhere in your expression), and whether your expression contains a
+ parameter pack (for variadic templates). Often, computing these flags
+ just means combining the results from the various types and
+ subexpressions.
+ * Add ``TransformXXX`` and ``RebuildXXX`` functions to the ``TreeTransform``
+ class template in ``Sema``. ``TransformXXX`` should (recursively)
+ transform all of the subexpressions and types within your expression,
+ using ``getDerived().TransformYYY``. If all of the subexpressions and
+ types transform without error, it will then call the ``RebuildXXX``
+ function, which will in turn call ``getSema().BuildXXX`` to perform
+ semantic analysis and build your expression.
+ * To test template instantiation, take those tests you wrote to make sure
+ that you were type checking with type-dependent expressions and dependent
+ types (from step #2) and instantiate those templates with various types,
+ some of which type-check and some that don't, and test the error messages
+ in each case.
+
+#. There are some "extras" that make other features work better. It's worth
+ handling these extras to give your expression complete integration into
+ Clang:
+
+ * Add code completion support for your expression in
+ ``SemaCodeComplete.cpp``.
+ * If your expression has types in it, or has any "interesting" features
+ other than subexpressions, extend libclang's ``CursorVisitor`` to provide
+ proper visitation for your expression, enabling various IDE features such
+ as syntax highlighting, cross-referencing, and so on. The
+ ``c-index-test`` helper program can be used to test these features.
+
diff --git a/docs/IntroductionToTheClangAST.html b/docs/IntroductionToTheClangAST.html
deleted file mode 100644
index 28175dd..0000000
--- a/docs/IntroductionToTheClangAST.html
+++ /dev/null
@@ -1,139 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
-<title>Introduction to the Clang AST</title>
-<link type="text/css" rel="stylesheet" href="../menu.css" />
-<link type="text/css" rel="stylesheet" href="../content.css" />
-</head>
-<body>
-
-<!--#include virtual="../menu.html.incl"-->
-
-<div id="content">
-
-<h1>Introduction to the Clang AST</h1>
-<p>This document gives a gentle introduction to the mysteries of the Clang AST.
-It is targeted at developers who either want to contribute to Clang, or use
-tools that work based on Clang's AST, like the AST matchers.</p>
-<!-- FIXME: Add link once we have an AST matcher document -->
-
-<!-- ======================================================================= -->
-<h2 id="intro">Introduction</h2>
-<!-- ======================================================================= -->
-
-<p>Clang's AST is different from ASTs produced by some other compilers in that it closely
-resembles both the written C++ code and the C++ standard. For example,
-parenthesis expressions and compile time constants are available in an unreduced
-form in the AST. This makes Clang's AST a good fit for refactoring tools.</p>
-
-<p>Documentation for all Clang AST nodes is available via the generated
-<a href="http://clang.llvm.org/doxygen">Doxygen</a>. The doxygen online
-documentation is also indexed by your favorite search engine, which will make
-a search for clang and the AST node's class name usually turn up the doxygen
-of the class you're looking for (for example, search for: clang ParenExpr).</p>
-
-<!-- ======================================================================= -->
-<h2 id="examine">Examining the AST</h2>
-<!-- ======================================================================= -->
-
-<p>A good way to familarize yourself with the Clang AST is to actually look
-at it on some simple example code. Clang has a builtin AST-dump modes, which
-can be enabled with the flags -ast-dump and -ast-dump-xml. Note that -ast-dump-xml
-currently only works with debug-builds of clang.</p>
-
-<p>Let's look at a simple example AST:</p>
-<pre>
-# cat test.cc
-int f(int x) {
- int result = (x / 42);
- return result;
-}
-
-# Clang by default is a frontend for many tools; -cc1 tells it to directly
-# use the C++ compiler mode. -undef leaves out some internal declarations.
-$ clang -cc1 -undef -ast-dump-xml test.cc
-... cutting out internal declarations of clang ...
-&lt;TranslationUnit ptr="0x4871160">
- &lt;Function ptr="0x48a5800" name="f" prototype="true">
- &lt;FunctionProtoType ptr="0x4871de0" canonical="0x4871de0">
- &lt;BuiltinType ptr="0x4871250" canonical="0x4871250"/>
- &lt;parameters>
- &lt;BuiltinType ptr="0x4871250" canonical="0x4871250"/>
- &lt;/parameters>
- &lt;/FunctionProtoType>
- &lt;ParmVar ptr="0x4871d80" name="x" initstyle="c">
- &lt;BuiltinType ptr="0x4871250" canonical="0x4871250"/>
- &lt;/ParmVar>
- &lt;Stmt>
-(CompoundStmt 0x48a5a38 &lt;t2.cc:1:14, line:4:1>
- (DeclStmt 0x48a59c0 &lt;line:2:3, col:24>
- 0x48a58c0 "int result =
- (ParenExpr 0x48a59a0 &lt;col:16, col:23> 'int'
- (BinaryOperator 0x48a5978 &lt;col:17, col:21> 'int' '/'
- (ImplicitCastExpr 0x48a5960 &lt;col:17> 'int' &lt;LValueToRValue>
- (DeclRefExpr 0x48a5918 &lt;col:17> 'int' lvalue ParmVar 0x4871d80 'x' 'int'))
- (IntegerLiteral 0x48a5940 &lt;col:21> 'int' 42)))")
- (ReturnStmt 0x48a5a18 &lt;line:3:3, col:10>
- (ImplicitCastExpr 0x48a5a00 &lt;col:10> 'int' &lt;LValueToRValue>
- (DeclRefExpr 0x48a59d8 &lt;col:10> 'int' lvalue Var 0x48a58c0 'result' 'int'))))
-
- &lt;/Stmt>
- &lt;/Function>
-&lt;/TranslationUnit>
-</pre>
-<p>In general, -ast-dump-xml dumps declarations in an XML-style format and
-statements in an S-expression-style format.
-The toplevel declaration in a translation unit is always the
-<a href="http://clang.llvm.org/doxygen/classclang_1_1TranslationUnitDecl.html">translation unit declaration</a>.
-In this example, our first user written declaration is the
-<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">function declaration</a>
-of 'f'. The body of 'f' is a <a href="http://clang.llvm.org/doxygen/classclang_1_1CompoundStmt.html">compound statement</a>,
-whose child nodes are a <a href="http://clang.llvm.org/doxygen/classclang_1_1DeclStmt.html">declaration statement</a>
-that declares our result variable, and the
-<a href="http://clang.llvm.org/doxygen/classclang_1_1ReturnStmt.html">return statement</a>.</p>
-
-<!-- ======================================================================= -->
-<h2 id="context">AST Context</h2>
-<!-- ======================================================================= -->
-
-<p>All information about the AST for a translation unit is bundled up in the class
-<a href="http://clang.llvm.org/doxygen/classclang_1_1ASTContext.html">ASTContext</a>.
-It allows traversal of the whole translation unit starting from
-<a href="http://clang.llvm.org/doxygen/classclang_1_1ASTContext.html#abd909fb01ef10cfd0244832a67b1dd64">getTranslationUnitDecl</a>,
-or to access Clang's <a href="http://clang.llvm.org/doxygen/classclang_1_1ASTContext.html#a4f95adb9958e22fbe55212ae6482feb4">table of identifiers</a>
-for the parsed translation unit.</p>
-
-<!-- ======================================================================= -->
-<h2 id="nodes">AST Nodes</h2>
-<!-- ======================================================================= -->
-
-<p>Clang's AST nodes are modeled on a class hierarchy that does not have a common
-ancestor. Instead, there are multiple larger hierarchies for basic node types like
-<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a> and
-<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>. Many
-important AST nodes derive from <a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>,
-<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>,
-<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclContext.html">DeclContext</a> or
-<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>,
-with some classes deriving from both Decl and DeclContext.</p>
-<p>There are also a multitude of nodes in the AST that are not part of a
-larger hierarchy, and are only reachable from specific other nodes,
-like <a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>.
-</p>
-
-<p>Thus, to traverse the full AST, one starts from the <a href="http://clang.llvm.org/doxygen/classclang_1_1TranslationUnitDecl.html">TranslationUnitDecl</a>
-and then recursively traverses everything that can be reached from that node
-- this information has to be encoded for each specific node type. This algorithm
-is encoded in the <a href="http://clang.llvm.org/doxygen/classclang_1_1RecursiveASTVisitor.html">RecursiveASTVisitor</a>.
-See the <a href="http://clang.llvm.org/docs/RAVFrontendAction.html">RecursiveASTVisitor tutorial</a>.</p>
-
-<p>The two most basic nodes in the Clang AST are statements (<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>)
-and declarations (<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>).
-Note that expressions (<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>)
-are also statements in Clang's AST.</p>
-
-</div>
-</body>
-</html>
-
diff --git a/docs/IntroductionToTheClangAST.rst b/docs/IntroductionToTheClangAST.rst
new file mode 100644
index 0000000..81eb7ed
--- /dev/null
+++ b/docs/IntroductionToTheClangAST.rst
@@ -0,0 +1,135 @@
+=============================
+Introduction to the Clang AST
+=============================
+
+This document gives a gentle introduction to the mysteries of the Clang
+AST. It is targeted at developers who either want to contribute to
+Clang, or use tools that work based on Clang's AST, like the AST
+matchers.
+
+Introduction
+============
+
+Clang's AST is different from ASTs produced by some other compilers in
+that it closely resembles both the written C++ code and the C++
+standard. For example, parenthesis expressions and compile time
+constants are available in an unreduced form in the AST. This makes
+Clang's AST a good fit for refactoring tools.
+
+Documentation for all Clang AST nodes is available via the generated
+`Doxygen <http://clang.llvm.org/doxygen>`_. The doxygen online
+documentation is also indexed by your favorite search engine, which will
+make a search for clang and the AST node's class name usually turn up
+the doxygen of the class you're looking for (for example, search for:
+clang ParenExpr).
+
+Examining the AST
+=================
+
+A good way to familarize yourself with the Clang AST is to actually look
+at it on some simple example code. Clang has a builtin AST-dump modes,
+which can be enabled with the flags ``-ast-dump`` and ``-ast-dump-xml``. Note
+that ``-ast-dump-xml`` currently only works with debug builds of clang.
+
+Let's look at a simple example AST:
+
+::
+
+ $ cat test.cc
+ int f(int x) {
+ int result = (x / 42);
+ return result;
+ }
+
+ # Clang by default is a frontend for many tools; -cc1 tells it to directly
+ # use the C++ compiler mode. -undef leaves out some internal declarations.
+ $ clang -cc1 -undef -ast-dump-xml test.cc
+ ... cutting out internal declarations of clang ...
+ <TranslationUnit ptr="0x4871160">
+ <Function ptr="0x48a5800" name="f" prototype="true">
+ <FunctionProtoType ptr="0x4871de0" canonical="0x4871de0">
+ <BuiltinType ptr="0x4871250" canonical="0x4871250"/>
+ <parameters>
+ <BuiltinType ptr="0x4871250" canonical="0x4871250"/>
+ </parameters>
+ </FunctionProtoType>
+ <ParmVar ptr="0x4871d80" name="x" initstyle="c">
+ <BuiltinType ptr="0x4871250" canonical="0x4871250"/>
+ </ParmVar>
+ <Stmt>
+ (CompoundStmt 0x48a5a38 <t2.cc:1:14, line:4:1>
+ (DeclStmt 0x48a59c0 <line:2:3, col:24>
+ 0x48a58c0 "int result =
+ (ParenExpr 0x48a59a0 <col:16, col:23> 'int'
+ (BinaryOperator 0x48a5978 <col:17, col:21> 'int' '/'
+ (ImplicitCastExpr 0x48a5960 <col:17> 'int' <LValueToRValue>
+ (DeclRefExpr 0x48a5918 <col:17> 'int' lvalue ParmVar 0x4871d80 'x' 'int'))
+ (IntegerLiteral 0x48a5940 <col:21> 'int' 42)))")
+ (ReturnStmt 0x48a5a18 <line:3:3, col:10>
+ (ImplicitCastExpr 0x48a5a00 <col:10> 'int' <LValueToRValue>
+ (DeclRefExpr 0x48a59d8 <col:10> 'int' lvalue Var 0x48a58c0 'result' 'int'))))
+
+ </Stmt>
+ </Function>
+ </TranslationUnit>
+
+In general, ``-ast-dump-xml`` dumps declarations in an XML-style format and
+statements in an S-expression-style format. The toplevel declaration in
+a translation unit is always the `translation unit
+declaration <http://clang.llvm.org/doxygen/classclang_1_1TranslationUnitDecl.html>`_.
+In this example, our first user written declaration is the `function
+declaration <http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html>`_
+of "``f``". The body of "``f``" is a `compound
+statement <http://clang.llvm.org/doxygen/classclang_1_1CompoundStmt.html>`_,
+whose child nodes are a `declaration
+statement <http://clang.llvm.org/doxygen/classclang_1_1DeclStmt.html>`_
+that declares our result variable, and the `return
+statement <http://clang.llvm.org/doxygen/classclang_1_1ReturnStmt.html>`_.
+
+AST Context
+===========
+
+All information about the AST for a translation unit is bundled up in
+the class
+`ASTContext <http://clang.llvm.org/doxygen/classclang_1_1ASTContext.html>`_.
+It allows traversal of the whole translation unit starting from
+`getTranslationUnitDecl <http://clang.llvm.org/doxygen/classclang_1_1ASTContext.html#abd909fb01ef10cfd0244832a67b1dd64>`_,
+or to access Clang's `table of
+identifiers <http://clang.llvm.org/doxygen/classclang_1_1ASTContext.html#a4f95adb9958e22fbe55212ae6482feb4>`_
+for the parsed translation unit.
+
+AST Nodes
+=========
+
+Clang's AST nodes are modeled on a class hierarchy that does not have a
+common ancestor. Instead, there are multiple larger hierarchies for
+basic node types like
+`Decl <http://clang.llvm.org/doxygen/classclang_1_1Decl.html>`_ and
+`Stmt <http://clang.llvm.org/doxygen/classclang_1_1Stmt.html>`_. Many
+important AST nodes derive from
+`Type <http://clang.llvm.org/doxygen/classclang_1_1Type.html>`_,
+`Decl <http://clang.llvm.org/doxygen/classclang_1_1Decl.html>`_,
+`DeclContext <http://clang.llvm.org/doxygen/classclang_1_1DeclContext.html>`_
+or `Stmt <http://clang.llvm.org/doxygen/classclang_1_1Stmt.html>`_, with
+some classes deriving from both Decl and DeclContext.
+
+There are also a multitude of nodes in the AST that are not part of a
+larger hierarchy, and are only reachable from specific other nodes, like
+`CXXBaseSpecifier <http://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html>`_.
+
+Thus, to traverse the full AST, one starts from the
+`TranslationUnitDecl <http://clang.llvm.org/doxygen/classclang_1_1TranslationUnitDecl.html>`_
+and then recursively traverses everything that can be reached from that
+node - this information has to be encoded for each specific node type.
+This algorithm is encoded in the
+`RecursiveASTVisitor <http://clang.llvm.org/doxygen/classclang_1_1RecursiveASTVisitor.html>`_.
+See the `RecursiveASTVisitor
+tutorial <http://clang.llvm.org/docs/RAVFrontendAction.html>`_.
+
+The two most basic nodes in the Clang AST are statements
+(`Stmt <http://clang.llvm.org/doxygen/classclang_1_1Stmt.html>`_) and
+declarations
+(`Decl <http://clang.llvm.org/doxygen/classclang_1_1Decl.html>`_). Note
+that expressions
+(`Expr <http://clang.llvm.org/doxygen/classclang_1_1Expr.html>`_) are
+also statements in Clang's AST.
diff --git a/docs/JSONCompilationDatabase.html b/docs/JSONCompilationDatabase.html
deleted file mode 100644
index 2907194..0000000
--- a/docs/JSONCompilationDatabase.html
+++ /dev/null
@@ -1,89 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
-<title>JSON Compilation Database Format Specification</title>
-<link type="text/css" rel="stylesheet" href="../menu.css">
-<link type="text/css" rel="stylesheet" href="../content.css">
-</head>
-<body>
-
-<!--#include virtual="../menu.html.incl"-->
-
-<div id="content">
-
-<h1>JSON Compilation Database Format Specification</h1>
-<p>This document describes a format for specifying how to replay
-single compilations independently of the build system.</p>
-
-<h2>Background</h2>
-<p>Tools based on the C++ Abstract Syntax Tree need full information how to
-parse a translation unit. Usually this information is implicitly
-available in the build system, but running tools as part of
-the build system is not necessarily the best solution:
-<ul>
-<li>Build systems are inherently change driven, so running multiple
-tools over the same code base without changing the code does not fit
-into the architecture of many build systems.</li>
-<li>Figuring out whether things have changed is often an IO bound
-process; this makes it hard to build low latency end user tools based
-on the build system.</li>
-<li>Build systems are inherently sequential in the build graph, for example
-due to generated source code. While tools that run independently of the
-build still need the generated source code to exist, running tools multiple
-times over unchanging source does not require serialization of the runs
-according to the build dependency graph.</li>
-</ul>
-</p>
-
-<h2>Supported Systems</h2>
-<p>Currently <a href="http://cmake.org">CMake</a> (since 2.8.5) supports generation of compilation
-databases for Unix Makefile builds (Ninja builds in the works) with the option
-CMAKE_EXPORT_COMPILE_COMMANDS.</p>
-<p>Clang's tooling interface supports reading compilation databases; see
-the <a href="LibTooling.html">LibTooling documentation</a>. libclang and its
-python bindings also support this (since clang 3.2); see
-<a href="/doxygen/group__COMPILATIONDB.html">CXCompilationDatabase.h</a>.</p>
-
-<h2>Format</h2>
-<p>A compilation database is a JSON file, which consist of an array of
-"command objects", where each command object specifies one way a translation unit
-is compiled in the project.</p>
-<p>Each command object contains the translation unit's main file, the working
-directory of the compile run and the actual compile command.</p>
-<p>Example:
-<pre>
-[
- { "directory": "/home/user/llvm/build",
- "command": "/usr/bin/clang++ -Irelative -DSOMEDEF='\"With spaces and quotes.\"' -c -o file.o file.cc",
- "file": "file.cc" },
- ...
-]
-</pre>
-The contracts for each field in the command object are:
-<ul>
-<li><b>directory:</b> The working directory of the compilation. All paths specified
-in the <b>command</b> or <b>file</b> fields must be either absolute or relative to
-this directory.</li>
-<li><b>file:</b> The main translation unit source processed by this compilation step.
-This is used by tools as the key into the compilation database. There can be multiple
-command objects for the same file, for example if the same source file is
-compiled with different configurations.</li>
-<li><b>command:</b> The compile command executed. After JSON unescaping, this must
-be a valid command to rerun the exact compilation step for the translation unit in
-the environment the build system uses. Parameters use shell quoting and shell escaping
-of quotes, with '"' and '\' being the only special characters. Shell expansion is
-not supported.</li>
-</ul>
-</p>
-
-<h2>Build System Integration</h2>
-<p>The convention is to name the file compile_commands.json and put it at the top
-of the build directory. Clang tools are pointed to the top of the build directory
-to detect the file and use the compilation database to parse C++ code in the source
-tree.</p>
-
-</div>
-</body>
-</html>
-
diff --git a/docs/JSONCompilationDatabase.rst b/docs/JSONCompilationDatabase.rst
new file mode 100644
index 0000000..926dcba
--- /dev/null
+++ b/docs/JSONCompilationDatabase.rst
@@ -0,0 +1,88 @@
+==============================================
+JSON Compilation Database Format Specification
+==============================================
+
+This document describes a format for specifying how to replay single
+compilations independently of the build system.
+
+Background
+==========
+
+Tools based on the C++ Abstract Syntax Tree need full information how to
+parse a translation unit. Usually this information is implicitly
+available in the build system, but running tools as part of the build
+system is not necessarily the best solution:
+
+- Build systems are inherently change driven, so running multiple tools
+ over the same code base without changing the code does not fit into
+ the architecture of many build systems.
+- Figuring out whether things have changed is often an IO bound
+ process; this makes it hard to build low latency end user tools based
+ on the build system.
+- Build systems are inherently sequential in the build graph, for
+ example due to generated source code. While tools that run
+ independently of the build still need the generated source code to
+ exist, running tools multiple times over unchanging source does not
+ require serialization of the runs according to the build dependency
+ graph.
+
+Supported Systems
+=================
+
+Currently `CMake <http://cmake.org>`_ (since 2.8.5) supports generation
+of compilation databases for Unix Makefile builds (Ninja builds in the
+works) with the option ``CMAKE_EXPORT_COMPILE_COMMANDS``.
+
+For projects on Linux, there is an alternative to intercept compiler
+calls with a tool called `Bear <https://github.com/rizsotto/Bear>`_.
+
+Clang's tooling interface supports reading compilation databases; see
+the :doc:`LibTooling documentation <LibTooling>`. libclang and its
+python bindings also support this (since clang 3.2); see
+`CXCompilationDatabase.h </doxygen/group__COMPILATIONDB.html>`_.
+
+Format
+======
+
+A compilation database is a JSON file, which consist of an array of
+"command objects", where each command object specifies one way a
+translation unit is compiled in the project.
+
+Each command object contains the translation unit's main file, the
+working directory of the compile run and the actual compile command.
+
+Example:
+
+::
+
+ [
+ { "directory": "/home/user/llvm/build",
+ "command": "/usr/bin/clang++ -Irelative -DSOMEDEF=\"With spaces, quotes and \\-es.\" -c -o file.o file.cc",
+ "file": "file.cc" },
+ ...
+ ]
+
+The contracts for each field in the command object are:
+
+- **directory:** The working directory of the compilation. All paths
+ specified in the **command** or **file** fields must be either
+ absolute or relative to this directory.
+- **file:** The main translation unit source processed by this
+ compilation step. This is used by tools as the key into the
+ compilation database. There can be multiple command objects for the
+ same file, for example if the same source file is compiled with
+ different configurations.
+- **command:** The compile command executed. After JSON unescaping,
+ this must be a valid command to rerun the exact compilation step for
+ the translation unit in the environment the build system uses.
+ Parameters use shell quoting and shell escaping of quotes, with '``"``'
+ and '``\``' being the only special characters. Shell expansion is not
+ supported.
+
+Build System Integration
+========================
+
+The convention is to name the file compile\_commands.json and put it at
+the top of the build directory. Clang tools are pointed to the top of
+the build directory to detect the file and use the compilation database
+to parse C++ code in the source tree.
diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html
deleted file mode 100644
index 8c0e5b7..0000000
--- a/docs/LanguageExtensions.html
+++ /dev/null
@@ -1,2082 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
-<html>
-<head>
- <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
- <title>Clang Language Extensions</title>
- <link type="text/css" rel="stylesheet" href="../menu.css">
- <link type="text/css" rel="stylesheet" href="../content.css">
- <style type="text/css">
- td {
- vertical-align: top;
- }
- th { background-color: #ffddaa; }
- </style>
-</head>
-<body>
-
-<!--#include virtual="../menu.html.incl"-->
-
-<div id="content">
-
-<h1>Clang Language Extensions</h1>
-
-<ul>
-<li><a href="#intro">Introduction</a></li>
-<li><a href="#feature_check">Feature Checking Macros</a></li>
-<li><a href="#has_include">Include File Checking Macros</a></li>
-<li><a href="#builtinmacros">Builtin Macros</a></li>
-<li><a href="#vectors">Vectors and Extended Vectors</a></li>
-<li><a href="#deprecated">Messages on <tt>deprecated</tt> and <tt>unavailable</tt> attributes</a></li>
-<li><a href="#attributes-on-enumerators">Attributes on enumerators</a></li>
-<li><a href="#user_specified_system_framework">'User-Specified' System Frameworks</a></li>
-<li><a href="#availability">Availability attribute</a></li>
-<li><a href="#checking_language_features">Checks for Standard Language Features</a>
- <ul>
- <li><a href="#cxx98">C++98</a>
- <ul>
- <li><a href="#cxx_exceptions">C++ exceptions</a></li>
- <li><a href="#cxx_rtti">C++ RTTI</a></li>
- </ul></li>
- <li><a href="#cxx11">C++11</a>
- <ul>
- <li><a href="#cxx_access_control_sfinae">C++11 SFINAE includes access control</a></li>
- <li><a href="#cxx_alias_templates">C++11 alias templates</a></li>
- <li><a href="#cxx_alignas">C++11 alignment specifiers</a></li>
- <li><a href="#cxx_attributes">C++11 attributes</a></li>
- <li><a href="#cxx_constexpr">C++11 generalized constant expressions</a></li>
- <li><a href="#cxx_decltype">C++11 <tt>decltype()</tt></a></li>
- <li><a href="#cxx_default_function_template_args">C++11 default template arguments in function templates</a></li>
- <li><a href="#cxx_defaulted_functions">C++11 defaulted functions</a></li>
- <li><a href="#cxx_delegating_constructor">C++11 delegating constructors</a></li>
- <li><a href="#cxx_deleted_functions">C++11 deleted functions</a></li>
- <li><a href="#cxx_explicit_conversions">C++11 explicit conversion functions</a></li>
- <li><a href="#cxx_generalized_initializers">C++11 generalized initializers</a></li>
- <li><a href="#cxx_implicit_moves">C++11 implicit move constructors/assignment operators</a></li>
- <li><a href="#cxx_inheriting_constructors">C++11 inheriting constructors</a></li>
- <li><a href="#cxx_inline_namespaces">C++11 inline namespaces</a></li>
- <li><a href="#cxx_lambdas">C++11 lambdas</a></li>
- <li><a href="#cxx_local_type_template_args">C++11 local and unnamed types as template arguments</a></li>
- <li><a href="#cxx_noexcept">C++11 noexcept specification</a></li>
- <li><a href="#cxx_nonstatic_member_init">C++11 in-class non-static data member initialization</a></li>
- <li><a href="#cxx_nullptr">C++11 nullptr</a></li>
- <li><a href="#cxx_override_control">C++11 override control</a></li>
- <li><a href="#cxx_range_for">C++11 range-based for loop</a></li>
- <li><a href="#cxx_raw_string_literals">C++11 raw string literals</a></li>
- <li><a href="#cxx_rvalue_references">C++11 rvalue references</a></li>
- <li><a href="#cxx_reference_qualified_functions">C++11 reference-qualified functions</a></li>
- <li><a href="#cxx_static_assert">C++11 <tt>static_assert()</tt></a></li>
- <li><a href="#cxx_auto_type">C++11 type inference</a></li>
- <li><a href="#cxx_strong_enums">C++11 strongly-typed enumerations</a></li>
- <li><a href="#cxx_trailing_return">C++11 trailing return type</a></li>
- <li><a href="#cxx_unicode_literals">C++11 Unicode string literals</a></li>
- <li><a href="#cxx_unrestricted_unions">C++11 unrestricted unions</a></li>
- <li><a href="#cxx_user_literals">C++11 user-defined literals</a></li>
- <li><a href="#cxx_variadic_templates">C++11 variadic templates</a></li>
- </ul></li>
- <li><a href="#c11">C11</a>
- <ul>
- <li><a href="#c_alignas">C11 alignment specifiers</a></li>
- <li><a href="#c_atomic">C11 atomic operations</a></li>
- <li><a href="#c_generic_selections">C11 generic selections</a></li>
- <li><a href="#c_static_assert">C11 <tt>_Static_assert()</tt></a></li>
- </ul></li>
-</ul></li>
-<li><a href="#checking_type_traits">Checks for Type Traits</a></li>
-<li><a href="#blocks">Blocks</a></li>
-<li><a href="#objc_features">Objective-C Features</a>
- <ul>
- <li><a href="#objc_instancetype">Related result types</a></li>
- <li><a href="#objc_arc">Automatic reference counting</a></li>
- <li><a href="#objc_fixed_enum">Enumerations with a fixed underlying type</a></li>
- <li><a href="#objc_lambdas">Interoperability with C++11 lambdas</a></li>
- <li><a href="#objc_object_literals_subscripting">Object Literals and Subscripting</a></li>
- </ul>
-</li>
-<li><a href="#overloading-in-c">Function Overloading in C</a></li>
-<li><a href="#complex-list-init">Initializer lists for complex numbers in C</a></li>
-<li><a href="#builtins">Builtin Functions</a>
- <ul>
- <li><a href="#__builtin_readcyclecounter">__builtin_readcyclecounter</a></li>
- <li><a href="#__builtin_shufflevector">__builtin_shufflevector</a></li>
- <li><a href="#__builtin_unreachable">__builtin_unreachable</a></li>
- <li><a href="#__sync_swap">__sync_swap</a></li>
- </ul>
-</li>
-<li><a href="#non-standard-attributes">Non-standard C++11 Attributes</a>
-<ul>
- <li><a href="#clang__fallthrough">The <tt>clang::fallthrough</tt> attribute</a></li>
-</ul>
-</li>
-<li><a href="#targetspecific">Target-Specific Extensions</a>
- <ul>
- <li><a href="#x86-specific">X86/X86-64 Language Extensions</a></li>
- </ul>
-</li>
-<li><a href="#analyzerspecific">Static Analysis-Specific Extensions</a></li>
-<li><a href="#dynamicanalyzerspecific">Dynamic Analysis-Specific Extensions</a>
- <ul>
- <li><a href="#address_sanitizer">AddressSanitizer</a></li>
- </ul>
-</li>
-<li><a href="#threadsafety">Thread Safety Annotation Checking</a>
- <ul>
- <li><a href="#ts_noanal"><tt>no_thread_safety_analysis</tt></a></li>
- <li><a href="#ts_lockable"><tt>lockable</tt></a></li>
- <li><a href="#ts_scopedlockable"><tt>scoped_lockable</tt></a></li>
- <li><a href="#ts_guardedvar"><tt>guarded_var</tt></a></li>
- <li><a href="#ts_ptguardedvar"><tt>pt_guarded_var</tt></a></li>
- <li><a href="#ts_guardedby"><tt>guarded_by(l)</tt></a></li>
- <li><a href="#ts_ptguardedby"><tt>pt_guarded_by(l)</tt></a></li>
- <li><a href="#ts_acquiredbefore"><tt>acquired_before(...)</tt></a></li>
- <li><a href="#ts_acquiredafter"><tt>acquired_after(...)</tt></a></li>
- <li><a href="#ts_elf"><tt>exclusive_lock_function(...)</tt></a></li>
- <li><a href="#ts_slf"><tt>shared_lock_function(...)</tt></a></li>
- <li><a href="#ts_etf"><tt>exclusive_trylock_function(...)</tt></a></li>
- <li><a href="#ts_stf"><tt>shared_trylock_function(...)</tt></a></li>
- <li><a href="#ts_uf"><tt>unlock_function(...)</tt></a></li>
- <li><a href="#ts_lr"><tt>lock_returned(l)</tt></a></li>
- <li><a href="#ts_le"><tt>locks_excluded(...)</tt></a></li>
- <li><a href="#ts_elr"><tt>exclusive_locks_required(...)</tt></a></li>
- <li><a href="#ts_slr"><tt>shared_locks_required(...)</tt></a></li>
- </ul>
-</li>
-<li><a href="#type_safety">Type Safety Checking</a>
- <ul>
- <li><a href="#argument_with_type_tag"><tt>argument_with_type_tag(...)</tt></a></li>
- <li><a href="#pointer_with_type_tag"><tt>pointer_with_type_tag(...)</tt></a></li>
- <li><a href="#type_tag_for_datatype"><tt>type_tag_for_datatype(...)</tt></a></li>
- </ul>
-</li>
-</ul>
-
-<!-- ======================================================================= -->
-<h2 id="intro">Introduction</h2>
-<!-- ======================================================================= -->
-
-<p>This document describes the language extensions provided by Clang. In
-addition to the language extensions listed here, Clang aims to support a broad
-range of GCC extensions. Please see the <a
-href="http://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html">GCC manual</a> for
-more information on these extensions.</p>
-
-<!-- ======================================================================= -->
-<h2 id="feature_check">Feature Checking Macros</h2>
-<!-- ======================================================================= -->
-
-<p>Language extensions can be very useful, but only if you know you can depend
-on them. In order to allow fine-grain features checks, we support three builtin
-function-like macros. This allows you to directly test for a feature in your
-code without having to resort to something like autoconf or fragile "compiler
-version checks".</p>
-
-<!-- ======================================================================= -->
-<h3><a name="__has_builtin">__has_builtin</a></h3>
-<!-- ======================================================================= -->
-
-<p>This function-like macro takes a single identifier argument that is the name
-of a builtin function. It evaluates to 1 if the builtin is supported or 0 if
-not. It can be used like this:</p>
-
-<blockquote>
-<pre>
-#ifndef __has_builtin // Optional of course.
- #define __has_builtin(x) 0 // Compatibility with non-clang compilers.
-#endif
-
-...
-#if __has_builtin(__builtin_trap)
- __builtin_trap();
-#else
- abort();
-#endif
-...
-</pre>
-</blockquote>
-
-
-<!-- ======================================================================= -->
-<h3><a name="__has_feature_extension"> __has_feature and __has_extension</a></h3>
-<!-- ======================================================================= -->
-
-<p>These function-like macros take a single identifier argument that is the
-name of a feature. <code>__has_feature</code> evaluates to 1 if the feature
-is both supported by Clang and standardized in the current language standard
-or 0 if not (but see <a href="#has_feature_back_compat">below</a>), while
-<code>__has_extension</code> evaluates to 1 if the feature is supported by
-Clang in the current language (either as a language extension or a standard
-language feature) or 0 if not. They can be used like this:</p>
-
-<blockquote>
-<pre>
-#ifndef __has_feature // Optional of course.
- #define __has_feature(x) 0 // Compatibility with non-clang compilers.
-#endif
-#ifndef __has_extension
- #define __has_extension __has_feature // Compatibility with pre-3.0 compilers.
-#endif
-
-...
-#if __has_feature(cxx_rvalue_references)
-// This code will only be compiled with the -std=c++11 and -std=gnu++11
-// options, because rvalue references are only standardized in C++11.
-#endif
-
-#if __has_extension(cxx_rvalue_references)
-// This code will be compiled with the -std=c++11, -std=gnu++11, -std=c++98
-// and -std=gnu++98 options, because rvalue references are supported as a
-// language extension in C++98.
-#endif
-</pre>
-</blockquote>
-
-<p id="has_feature_back_compat">For backwards compatibility reasons,
-<code>__has_feature</code> can also be used to test for support for
-non-standardized features, i.e. features not prefixed <code>c_</code>,
-<code>cxx_</code> or <code>objc_</code>.</p>
-
-<p id="has_feature_for_non_language_features">
-Another use of <code>__has_feature</code> is to check for compiler features
-not related to the language standard, such as e.g.
-<a href="AddressSanitizer.html">AddressSanitizer</a>.
-
-<p>If the <code>-pedantic-errors</code> option is given,
-<code>__has_extension</code> is equivalent to <code>__has_feature</code>.</p>
-
-<p>The feature tag is described along with the language feature below.</p>
-
-<p>The feature name or extension name can also be specified with a preceding and
-following <code>__</code> (double underscore) to avoid interference from a macro
-with the same name. For instance, <code>__cxx_rvalue_references__</code> can be
-used instead of <code>cxx_rvalue_references</code>.</p>
-
-<!-- ======================================================================= -->
-<h3><a name="__has_attribute">__has_attribute</a></h3>
-<!-- ======================================================================= -->
-
-<p>This function-like macro takes a single identifier argument that is the name
-of an attribute. It evaluates to 1 if the attribute is supported or 0 if not. It
-can be used like this:</p>
-
-<blockquote>
-<pre>
-#ifndef __has_attribute // Optional of course.
- #define __has_attribute(x) 0 // Compatibility with non-clang compilers.
-#endif
-
-...
-#if __has_attribute(always_inline)
-#define ALWAYS_INLINE __attribute__((always_inline))
-#else
-#define ALWAYS_INLINE
-#endif
-...
-</pre>
-</blockquote>
-
-<p>The attribute name can also be specified with a preceding and
-following <code>__</code> (double underscore) to avoid interference from a macro
-with the same name. For instance, <code>__always_inline__</code> can be used
-instead of <code>always_inline</code>.</p>
-
-<!-- ======================================================================= -->
-<h2 id="has_include">Include File Checking Macros</h2>
-<!-- ======================================================================= -->
-
-<p>Not all developments systems have the same include files.
-The <a href="#__has_include">__has_include</a> and
-<a href="#__has_include_next">__has_include_next</a> macros allow you to
-check for the existence of an include file before doing
-a possibly failing #include directive.</p>
-
-<!-- ======================================================================= -->
-<h3><a name="__has_include">__has_include</a></h3>
-<!-- ======================================================================= -->
-
-<p>This function-like macro takes a single file name string argument that
-is the name of an include file. It evaluates to 1 if the file can
-be found using the include paths, or 0 otherwise:</p>
-
-<blockquote>
-<pre>
-// Note the two possible file name string formats.
-#if __has_include("myinclude.h") &amp;&amp; __has_include(&lt;stdint.h&gt;)
-# include "myinclude.h"
-#endif
-
-// To avoid problem with non-clang compilers not having this macro.
-#if defined(__has_include) &amp;&amp; __has_include("myinclude.h")
-# include "myinclude.h"
-#endif
-</pre>
-</blockquote>
-
-<p>To test for this feature, use #if defined(__has_include).</p>
-
-<!-- ======================================================================= -->
-<h3><a name="__has_include_next">__has_include_next</a></h3>
-<!-- ======================================================================= -->
-
-<p>This function-like macro takes a single file name string argument that
-is the name of an include file. It is like __has_include except that it
-looks for the second instance of the given file found in the include
-paths. It evaluates to 1 if the second instance of the file can
-be found using the include paths, or 0 otherwise:</p>
-
-<blockquote>
-<pre>
-// Note the two possible file name string formats.
-#if __has_include_next("myinclude.h") &amp;&amp; __has_include_next(&lt;stdint.h&gt;)
-# include_next "myinclude.h"
-#endif
-
-// To avoid problem with non-clang compilers not having this macro.
-#if defined(__has_include_next) &amp;&amp; __has_include_next("myinclude.h")
-# include_next "myinclude.h"
-#endif
-</pre>
-</blockquote>
-
-<p>Note that __has_include_next, like the GNU extension
-#include_next directive, is intended for use in headers only,
-and will issue a warning if used in the top-level compilation
-file. A warning will also be issued if an absolute path
-is used in the file argument.</p>
-
-
-<!-- ======================================================================= -->
-<h3><a name="__has_warning">__has_warning</a></h3>
-<!-- ======================================================================= -->
-
-<p>This function-like macro takes a string literal that represents a command
- line option for a warning and returns true if that is a valid warning
- option.</p>
-
-<blockquote>
-<pre>
-#if __has_warning("-Wformat")
-...
-#endif
-</pre>
-</blockquote>
-
-<!-- ======================================================================= -->
-<h2 id="builtinmacros">Builtin Macros</h2>
-<!-- ======================================================================= -->
-
-<dl>
- <dt><code>__BASE_FILE__</code></dt>
- <dd>Defined to a string that contains the name of the main input
- file passed to Clang.</dd>
-
- <dt><code>__COUNTER__</code></dt>
- <dd>Defined to an integer value that starts at zero and is
- incremented each time the <code>__COUNTER__</code> macro is
- expanded.</dd>
-
- <dt><code>__INCLUDE_LEVEL__</code></dt>
- <dd>Defined to an integral value that is the include depth of the
- file currently being translated. For the main file, this value is
- zero.</dd>
-
- <dt><code>__TIMESTAMP__</code></dt>
- <dd>Defined to the date and time of the last modification of the
- current source file.</dd>
-
- <dt><code>__clang__</code></dt>
- <dd>Defined when compiling with Clang</dd>
-
- <dt><code>__clang_major__</code></dt>
- <dd>Defined to the major marketing version number of Clang (e.g., the
- 2 in 2.0.1). Note that marketing version numbers should not be used to
- check for language features, as different vendors use different numbering
- schemes. Instead, use the <a href="#feature_check">feature checking
- macros</a>.</dd>
-
- <dt><code>__clang_minor__</code></dt>
- <dd>Defined to the minor version number of Clang (e.g., the 0 in
- 2.0.1). Note that marketing version numbers should not be used to
- check for language features, as different vendors use different numbering
- schemes. Instead, use the <a href="#feature_check">feature checking
- macros</a>.</dd>
-
- <dt><code>__clang_patchlevel__</code></dt>
- <dd>Defined to the marketing patch level of Clang (e.g., the 1 in 2.0.1).</dd>
-
- <dt><code>__clang_version__</code></dt>
- <dd>Defined to a string that captures the Clang marketing version, including
- the Subversion tag or revision number, e.g., "1.5 (trunk 102332)".</dd>
-</dl>
-
-<!-- ======================================================================= -->
-<h2 id="vectors">Vectors and Extended Vectors</h2>
-<!-- ======================================================================= -->
-
-<p>Supports the GCC, OpenCL, AltiVec and NEON vector extensions.</p>
-
-<p>OpenCL vector types are created using <tt>ext_vector_type</tt> attribute. It
-support for <tt>V.xyzw</tt> syntax and other tidbits as seen in OpenCL. An
-example is:</p>
-
-<blockquote>
-<pre>
-typedef float float4 <b>__attribute__((ext_vector_type(4)))</b>;
-typedef float float2 <b>__attribute__((ext_vector_type(2)))</b>;
-
-float4 foo(float2 a, float2 b) {
- float4 c;
- c.xz = a;
- c.yw = b;
- return c;
-}
-</pre>
-</blockquote>
-
-<p>Query for this feature with
-<tt>__has_extension(attribute_ext_vector_type)</tt>.</p>
-
-<p>Giving <tt>-faltivec</tt> option to clang enables support for AltiVec vector
-syntax and functions. For example:</p>
-
-<blockquote>
-<pre>
-vector float foo(vector int a) {
- vector int b;
- b = vec_add(a, a) + a;
- return (vector float)b;
-}
-</pre>
-</blockquote>
-
-<p>NEON vector types are created using <tt>neon_vector_type</tt> and
-<tt>neon_polyvector_type</tt> attributes. For example:</p>
-
-<blockquote>
-<pre>
-typedef <b>__attribute__((neon_vector_type(8)))</b> int8_t int8x8_t;
-typedef <b>__attribute__((neon_polyvector_type(16)))</b> poly8_t poly8x16_t;
-
-int8x8_t foo(int8x8_t a) {
- int8x8_t v;
- v = a;
- return v;
-}
-</pre>
-</blockquote>
-
-<!-- ======================================================================= -->
-<h3><a name="vector_literals">Vector Literals</a></h3>
-<!-- ======================================================================= -->
-
-<p>Vector literals can be used to create vectors from a set of scalars, or
-vectors. Either parentheses or braces form can be used. In the parentheses form
-the number of literal values specified must be one, i.e. referring to a scalar
-value, or must match the size of the vector type being created. If a single
-scalar literal value is specified, the scalar literal value will be replicated
-to all the components of the vector type. In the brackets form any number of
-literals can be specified. For example:</p>
-
-<blockquote>
-<pre>
-typedef int v4si __attribute__((__vector_size__(16)));
-typedef float float4 __attribute__((ext_vector_type(4)));
-typedef float float2 __attribute__((ext_vector_type(2)));
-
-v4si vsi = (v4si){1, 2, 3, 4};
-float4 vf = (float4)(1.0f, 2.0f, 3.0f, 4.0f);
-vector int vi1 = (vector int)(1); // vi1 will be (1, 1, 1, 1).
-vector int vi2 = (vector int){1}; // vi2 will be (1, 0, 0, 0).
-vector int vi3 = (vector int)(1, 2); // error
-vector int vi4 = (vector int){1, 2}; // vi4 will be (1, 2, 0, 0).
-vector int vi5 = (vector int)(1, 2, 3, 4);
-float4 vf = (float4)((float2)(1.0f, 2.0f), (float2)(3.0f, 4.0f));
-</pre>
-</blockquote>
-
-<!-- ======================================================================= -->
-<h3><a name="vector_operations">Vector Operations</a></h3>
-<!-- ======================================================================= -->
-
-<p>The table below shows the support for each operation by vector extension.
-A dash indicates that an operation is not accepted according to a corresponding
-specification.</p>
-
-<table width="500" border="1" cellspacing="0">
- <tr>
- <th>Operator</th>
- <th>OpenCL</th>
- <th>AltiVec</th>
- <th>GCC</th>
- <th>NEON</th>
- </tr>
- <tr>
- <td>[]</td>
- <td align="center">yes</td>
- <td align="center">yes</td>
- <td align="center">yes</td>
- <td align="center">-</td>
- </tr>
- <tr>
- <td>unary operators +, -</td>
- <td align="center">yes</td>
- <td align="center">yes</td>
- <td align="center">yes</td>
- <td align="center">-</td>
- </tr>
- <tr>
- <td>++, --</td>
- <td align="center">yes</td>
- <td align="center">yes</td>
- <td align="center">-</td>
- <td align="center">-</td>
- </tr>
- <tr>
- <td>+, -, *, /, %</td>
- <td align="center">yes</td>
- <td align="center">yes</td>
- <td align="center">yes</td>
- <td align="center">-</td>
- </tr>
- <tr>
- <td>bitwise operators &, |, ^, ~</td>
- <td align="center">yes</td>
- <td align="center">yes</td>
- <td align="center">yes</td>
- <td align="center">-</td>
- </tr>
- <tr>
- <td>&gt&gt, &lt&lt</td>
- <td align="center">yes</td>
- <td align="center">yes</td>
- <td align="center">yes</td>
- <td align="center">-</td>
- </tr>
- <tr>
- <td>!, &&,||</td>
- <td align="center">no</td>
- <td align="center">-</td>
- <td align="center">-</td>
- <td align="center">-</td>
- </tr>
- <tr>
- <td>==,!=, >, <, >=, <=</td>
- <td align="center">yes</td>
- <td align="center">yes</td>
- <td align="center">-</td>
- <td align="center">-</td>
- </tr>
- <tr>
- <td>=</td>
- <td align="center">yes</td>
- <td align="center">yes</td>
- <td align="center">yes</td>
- <td align="center">yes</td>
- </tr>
- <tr>
- <td>:?</td>
- <td align="center">yes</td>
- <td align="center">-</td>
- <td align="center">-</td>
- <td align="center">-</td>
- </tr>
- <tr>
- <td>sizeof</td>
- <td align="center">yes</td>
- <td align="center">yes</td>
- <td align="center">yes</td>
- <td align="center">yes</td>
- </tr>
-</table>
-
-<p>See also <a href="#__builtin_shufflevector">__builtin_shufflevector</a>.</p>
-
-<!-- ======================================================================= -->
-<h2 id="deprecated">Messages on <tt>deprecated</tt> and <tt>unavailable</tt> Attributes</h2>
-<!-- ======================================================================= -->
-
-<p>An optional string message can be added to the <tt>deprecated</tt>
-and <tt>unavailable</tt> attributes. For example:</p>
-
-<blockquote>
-<pre>void explode(void) __attribute__((deprecated("extremely unsafe, use 'combust' instead!!!")));</pre>
-</blockquote>
-
-<p>If the deprecated or unavailable declaration is used, the message
-will be incorporated into the appropriate diagnostic:</p>
-
-<blockquote>
-<pre>harmless.c:4:3: warning: 'explode' is deprecated: extremely unsafe, use 'combust' instead!!!
- [-Wdeprecated-declarations]
- explode();
- ^</pre>
-</blockquote>
-
-<p>Query for this feature
-with <tt>__has_extension(attribute_deprecated_with_message)</tt>
-and <tt>__has_extension(attribute_unavailable_with_message)</tt>.</p>
-
-<!-- ======================================================================= -->
-<h2 id="attributes-on-enumerators">Attributes on Enumerators</h2>
-<!-- ======================================================================= -->
-
-<p>Clang allows attributes to be written on individual enumerators.
-This allows enumerators to be deprecated, made unavailable, etc. The
-attribute must appear after the enumerator name and before any
-initializer, like so:</p>
-
-<blockquote>
-<pre>enum OperationMode {
- OM_Invalid,
- OM_Normal,
- OM_Terrified __attribute__((deprecated)),
- OM_AbortOnError __attribute__((deprecated)) = 4
-};</pre>
-</blockquote>
-
-<p>Attributes on the <tt>enum</tt> declaration do not apply to
-individual enumerators.</p>
-
-<p>Query for this feature with <tt>__has_extension(enumerator_attributes)</tt>.</p>
-
-<!-- ======================================================================= -->
-<h2 id="user_specified_system_framework">'User-Specified' System Frameworks</h2>
-<!-- ======================================================================= -->
-
-<p>Clang provides a mechanism by which frameworks can be built in such a way
-that they will always be treated as being 'system frameworks', even if they are
-not present in a system framework directory. This can be useful to system
-framework developers who want to be able to test building other applications
-with development builds of their framework, including the manner in which the
-compiler changes warning behavior for system headers.</p>
-
-<p>Framework developers can opt-in to this mechanism by creating a
-'.system_framework' file at the top-level of their framework. That is, the
-framework should have contents like:</p>
-
-<pre>
- .../TestFramework.framework
- .../TestFramework.framework/.system_framework
- .../TestFramework.framework/Headers
- .../TestFramework.framework/Headers/TestFramework.h
- ...
-</pre>
-
-<p>Clang will treat the presence of this file as an indicator that the framework
-should be treated as a system framework, regardless of how it was found in the
-framework search path. For consistency, we recommend that such files never be
-included in installed versions of the framework.</p>
-
-<!-- ======================================================================= -->
-<h2 id="availability">Availability attribute</h2>
-<!-- ======================================================================= -->
-
-<p>Clang introduces the <code>availability</code> attribute, which can
-be placed on declarations to describe the lifecycle of that
-declaration relative to operating system versions. Consider the function declaration for a hypothetical function <code>f</code>:</p>
-
-<pre>
-void f(void) __attribute__((availability(macosx,introduced=10.4,deprecated=10.6,obsoleted=10.7)));
-</pre>
-
-<p>The availability attribute states that <code>f</code> was introduced in Mac OS X 10.4, deprecated in Mac OS X 10.6, and obsoleted in Mac OS X 10.7. This information is used by Clang to determine when it is safe to use <code>f</code>: for example, if Clang is instructed to compile code for Mac OS X 10.5, a call to <code>f()</code> succeeds. If Clang is instructed to compile code for Mac OS X 10.6, the call succeeds but Clang emits a warning specifying that the function is deprecated. Finally, if Clang is instructed to compile code for Mac OS X 10.7, the call fails because <code>f()</code> is no longer available.</p>
-
-<p>The availablility attribute is a comma-separated list starting with the platform name and then including clauses specifying important milestones in the declaration's lifetime (in any order) along with additional information. Those clauses can be:</p>
-
-<dl>
- <dt>introduced=<i>version</i></dt>
- <dd>The first version in which this declaration was introduced.</dd>
-
- <dt>deprecated=<i>version</i></dt>
- <dd>The first version in which this declaration was deprecated, meaning that users should migrate away from this API.</dd>
-
- <dt>obsoleted=<i>version</i></dt>
- <dd>The first version in which this declaration was obsoleted, meaning that it was removed completely and can no longer be used.</dd>
-
- <dt>unavailable</dt>
- <dd>This declaration is never available on this platform.</dd>
-
- <dt>message=<i>string-literal</i></dt>
- <dd>Additional message text that Clang will provide when emitting a warning or error about use of a deprecated or obsoleted declaration. Useful to direct users to replacement APIs.</dd>
-</dl>
-
-<p>Multiple availability attributes can be placed on a declaration, which may correspond to different platforms. Only the availability attribute with the platform corresponding to the target platform will be used; any others will be ignored. If no availability attribute specifies availability for the current target platform, the availability attributes are ignored. Supported platforms are:</p>
-
-<dl>
- <dt>ios</dt>
- <dd>Apple's iOS operating system. The minimum deployment target is specified by the <code>-mios-version-min=<i>version</i></code> or <code>-miphoneos-version-min=<i>version</i></code> command-line arguments.</dd>
-
- <dt>macosx</dt>
- <dd>Apple's Mac OS X operating system. The minimum deployment target is specified by the <code>-mmacosx-version-min=<i>version</i></code> command-line argument.</dd>
-</dl>
-
-<p>A declaration can be used even when deploying back to a platform
-version prior to when the declaration was introduced. When this
-happens, the declaration is <a
- href="https://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPFrameworks/Concepts/WeakLinking.html">weakly
-linked</a>, as if the <code>weak_import</code> attribute were added to the declaration. A weakly-linked declaration may or may not be present a run-time, and a program can determine whether the declaration is present by checking whether the address of that declaration is non-NULL.</p>
-
-<!-- ======================================================================= -->
-<h2 id="checking_language_features">Checks for Standard Language Features</h2>
-<!-- ======================================================================= -->
-
-<p>The <tt>__has_feature</tt> macro can be used to query if certain standard
-language features are enabled. The <tt>__has_extension</tt> macro can be used
-to query if language features are available as an extension when compiling for
-a standard which does not provide them. The features which can be tested are
-listed here.</p>
-
-<h3 id="cxx98">C++98</h3>
-
-<p>The features listed below are part of the C++98 standard. These features are
-enabled by default when compiling C++ code.</p>
-
-<h4 id="cxx_exceptions">C++ exceptions</h4>
-
-<p>Use <tt>__has_feature(cxx_exceptions)</tt> to determine if C++ exceptions have been enabled. For
-example, compiling code with <tt>-fno-exceptions</tt> disables C++ exceptions.</p>
-
-<h4 id="cxx_rtti">C++ RTTI</h4>
-
-<p>Use <tt>__has_feature(cxx_rtti)</tt> to determine if C++ RTTI has been enabled. For example,
-compiling code with <tt>-fno-rtti</tt> disables the use of RTTI.</p>
-
-<h3 id="cxx11">C++11</h3>
-
-<p>The features listed below are part of the C++11 standard. As a result, all
-these features are enabled with the <tt>-std=c++11</tt> or <tt>-std=gnu++11</tt>
-option when compiling C++ code.</p>
-
-<h4 id="cxx_access_control_sfinae">C++11 SFINAE includes access control</h4>
-
-<p>Use <tt>__has_feature(cxx_access_control_sfinae)</tt> or <tt>__has_extension(cxx_access_control_sfinae)</tt> to determine whether access-control errors (e.g., calling a private constructor) are considered to be template argument deduction errors (aka SFINAE errors), per <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1170">C++ DR1170</a>.</p>
-
-<h4 id="cxx_alias_templates">C++11 alias templates</h4>
-
-<p>Use <tt>__has_feature(cxx_alias_templates)</tt> or
-<tt>__has_extension(cxx_alias_templates)</tt> to determine if support for
-C++11's alias declarations and alias templates is enabled.</p>
-
-<h4 id="cxx_alignas">C++11 alignment specifiers</h4>
-
-<p>Use <tt>__has_feature(cxx_alignas)</tt> or
-<tt>__has_extension(cxx_alignas)</tt> to determine if support for alignment
-specifiers using <tt>alignas</tt> is enabled.</p>
-
-<h4 id="cxx_attributes">C++11 attributes</h4>
-
-<p>Use <tt>__has_feature(cxx_attributes)</tt> or
-<tt>__has_extension(cxx_attributes)</tt> to determine if support for attribute
-parsing with C++11's square bracket notation is enabled.</p>
-
-<h4 id="cxx_constexpr">C++11 generalized constant expressions</h4>
-
-<p>Use <tt>__has_feature(cxx_constexpr)</tt> to determine if support
-for generalized constant expressions (e.g., <tt>constexpr</tt>) is
-enabled.</p>
-
-<h4 id="cxx_decltype">C++11 <tt>decltype()</tt></h4>
-
-<p>Use <tt>__has_feature(cxx_decltype)</tt> or
-<tt>__has_extension(cxx_decltype)</tt> to determine if support for the
-<tt>decltype()</tt> specifier is enabled. C++11's <tt>decltype</tt>
-does not require type-completeness of a function call expression.
-Use <tt>__has_feature(cxx_decltype_incomplete_return_types)</tt>
-or <tt>__has_extension(cxx_decltype_incomplete_return_types)</tt>
-to determine if support for this feature is enabled.</p>
-
-<h4 id="cxx_default_function_template_args">C++11 default template arguments in function templates</h4>
-
-<p>Use <tt>__has_feature(cxx_default_function_template_args)</tt> or
-<tt>__has_extension(cxx_default_function_template_args)</tt> to determine
-if support for default template arguments in function templates is enabled.</p>
-
-<h4 id="cxx_defaulted_functions">C++11 <tt>default</tt>ed functions</h4>
-
-<p>Use <tt>__has_feature(cxx_defaulted_functions)</tt> or
-<tt>__has_extension(cxx_defaulted_functions)</tt> to determine if support for
-defaulted function definitions (with <tt>= default</tt>) is enabled.</p>
-
-<h4 id="cxx_delegating_constructors">C++11 delegating constructors</h4>
-
-<p>Use <tt>__has_feature(cxx_delegating_constructors)</tt> to determine if
-support for delegating constructors is enabled.</p>
-
-<h4 id="cxx_deleted_functions">C++11 <tt>delete</tt>d functions</h4>
-
-<p>Use <tt>__has_feature(cxx_deleted_functions)</tt> or
-<tt>__has_extension(cxx_deleted_functions)</tt> to determine if support for
-deleted function definitions (with <tt>= delete</tt>) is enabled.</p>
-
-<h4 id="cxx_explicit_conversions">C++11 explicit conversion functions</h4>
-<p>Use <tt>__has_feature(cxx_explicit_conversions)</tt> to determine if support for <tt>explicit</tt> conversion functions is enabled.</p>
-
-<h4 id="cxx_generalized_initializers">C++11 generalized initializers</h4>
-
-<p>Use <tt>__has_feature(cxx_generalized_initializers)</tt> to determine if
-support for generalized initializers (using braced lists and
-<tt>std::initializer_list</tt>) is enabled.</p>
-
-<h4 id="cxx_implicit_moves">C++11 implicit move constructors/assignment operators</h4>
-
-<p>Use <tt>__has_feature(cxx_implicit_moves)</tt> to determine if Clang will
-implicitly generate move constructors and move assignment operators where needed.</p>
-
-<h4 id="cxx_inheriting_constructors">C++11 inheriting constructors</h4>
-
-<p>Use <tt>__has_feature(cxx_inheriting_constructors)</tt> to determine if support for inheriting constructors is enabled. Clang does not currently implement this feature.</p>
-
-<h4 id="cxx_inline_namespaces">C++11 inline namespaces</h4>
-
-<p>Use <tt>__has_feature(cxx_inline_namespaces)</tt> or
-<tt>__has_extension(cxx_inline_namespaces)</tt> to determine if support for
-inline namespaces is enabled.</p>
-
-<h4 id="cxx_lambdas">C++11 lambdas</h4>
-
-<p>Use <tt>__has_feature(cxx_lambdas)</tt> or
-<tt>__has_extension(cxx_lambdas)</tt> to determine if support for lambdas
-is enabled. </p>
-
-<h4 id="cxx_local_type_template_args">C++11 local and unnamed types as template arguments</h4>
-
-<p>Use <tt>__has_feature(cxx_local_type_template_args)</tt> or
-<tt>__has_extension(cxx_local_type_template_args)</tt> to determine if
-support for local and unnamed types as template arguments is enabled.</p>
-
-<h4 id="cxx_noexcept">C++11 noexcept</h4>
-
-<p>Use <tt>__has_feature(cxx_noexcept)</tt> or
-<tt>__has_extension(cxx_noexcept)</tt> to determine if support for noexcept
-exception specifications is enabled.</p>
-
-<h4 id="cxx_nonstatic_member_init">C++11 in-class non-static data member initialization</h4>
-
-<p>Use <tt>__has_feature(cxx_nonstatic_member_init)</tt> to determine whether in-class initialization of non-static data members is enabled.</p>
-
-<h4 id="cxx_nullptr">C++11 <tt>nullptr</tt></h4>
-
-<p>Use <tt>__has_feature(cxx_nullptr)</tt> or
-<tt>__has_extension(cxx_nullptr)</tt> to determine if support for
-<tt>nullptr</tt> is enabled.</p>
-
-<h4 id="cxx_override_control">C++11 <tt>override control</tt></h4>
-
-<p>Use <tt>__has_feature(cxx_override_control)</tt> or
-<tt>__has_extension(cxx_override_control)</tt> to determine if support for
-the override control keywords is enabled.</p>
-
-<h4 id="cxx_reference_qualified_functions">C++11 reference-qualified functions</h4>
-<p>Use <tt>__has_feature(cxx_reference_qualified_functions)</tt> or
-<tt>__has_extension(cxx_reference_qualified_functions)</tt> to determine
-if support for reference-qualified functions (e.g., member functions with
-<code>&amp;</code> or <code>&amp;&amp;</code> applied to <code>*this</code>)
-is enabled.</p>
-
-<h4 id="cxx_range_for">C++11 range-based <tt>for</tt> loop</h4>
-
-<p>Use <tt>__has_feature(cxx_range_for)</tt> or
-<tt>__has_extension(cxx_range_for)</tt> to determine if support for the
-range-based for loop is enabled. </p>
-
-<h4 id="cxx_raw_string_literals">C++11 raw string literals</h4>
-<p>Use <tt>__has_feature(cxx_raw_string_literals)</tt> to determine if support
-for raw string literals (e.g., <tt>R"x(foo\bar)x"</tt>) is enabled.</p>
-
-<h4 id="cxx_rvalue_references">C++11 rvalue references</h4>
-
-<p>Use <tt>__has_feature(cxx_rvalue_references)</tt> or
-<tt>__has_extension(cxx_rvalue_references)</tt> to determine if support for
-rvalue references is enabled. </p>
-
-<h4 id="cxx_static_assert">C++11 <tt>static_assert()</tt></h4>
-
-<p>Use <tt>__has_feature(cxx_static_assert)</tt> or
-<tt>__has_extension(cxx_static_assert)</tt> to determine if support for
-compile-time assertions using <tt>static_assert</tt> is enabled.</p>
-
-<h4 id="cxx_auto_type">C++11 type inference</h4>
-
-<p>Use <tt>__has_feature(cxx_auto_type)</tt> or
-<tt>__has_extension(cxx_auto_type)</tt> to determine C++11 type inference is
-supported using the <tt>auto</tt> specifier. If this is disabled, <tt>auto</tt>
-will instead be a storage class specifier, as in C or C++98.</p>
-
-<h4 id="cxx_strong_enums">C++11 strongly typed enumerations</h4>
-
-<p>Use <tt>__has_feature(cxx_strong_enums)</tt> or
-<tt>__has_extension(cxx_strong_enums)</tt> to determine if support for
-strongly typed, scoped enumerations is enabled.</p>
-
-<h4 id="cxx_trailing_return">C++11 trailing return type</h4>
-
-<p>Use <tt>__has_feature(cxx_trailing_return)</tt> or
-<tt>__has_extension(cxx_trailing_return)</tt> to determine if support for the
-alternate function declaration syntax with trailing return type is enabled.</p>
-
-<h4 id="cxx_unicode_literals">C++11 Unicode string literals</h4>
-<p>Use <tt>__has_feature(cxx_unicode_literals)</tt> to determine if
-support for Unicode string literals is enabled.</p>
-
-<h4 id="cxx_unrestricted_unions">C++11 unrestricted unions</h4>
-
-<p>Use <tt>__has_feature(cxx_unrestricted_unions)</tt> to determine if support for unrestricted unions is enabled.</p>
-
-<h4 id="cxx_user_literals">C++11 user-defined literals</h4>
-
-<p>Use <tt>__has_feature(cxx_user_literals)</tt> to determine if support for user-defined literals is enabled.</p>
-
-<h4 id="cxx_variadic_templates">C++11 variadic templates</h4>
-
-<p>Use <tt>__has_feature(cxx_variadic_templates)</tt> or
-<tt>__has_extension(cxx_variadic_templates)</tt> to determine if support
-for variadic templates is enabled.</p>
-
-<h3 id="c11">C11</h3>
-
-<p>The features listed below are part of the C11 standard. As a result, all
-these features are enabled with the <tt>-std=c11</tt> or <tt>-std=gnu11</tt>
-option when compiling C code. Additionally, because these features are all
-backward-compatible, they are available as extensions in all language modes.</p>
-
-<h4 id="c_alignas">C11 alignment specifiers</h4>
-
-<p>Use <tt>__has_feature(c_alignas)</tt> or <tt>__has_extension(c_alignas)</tt>
-to determine if support for alignment specifiers using <tt>_Alignas</tt>
-is enabled.</p>
-
-<h4 id="c_atomic">C11 atomic operations</h4>
-
-<p>Use <tt>__has_feature(c_atomic)</tt> or <tt>__has_extension(c_atomic)</tt>
-to determine if support for atomic types using <tt>_Atomic</tt> is enabled.
-Clang also provides <a href="#__c11_atomic">a set of builtins</a> which can be
-used to implement the <tt>&lt;stdatomic.h&gt;</tt> operations on
-<tt>_Atomic</tt> types.</p>
-
-<h4 id="c_generic_selections">C11 generic selections</h4>
-
-<p>Use <tt>__has_feature(c_generic_selections)</tt> or
-<tt>__has_extension(c_generic_selections)</tt> to determine if support for
-generic selections is enabled.</p>
-
-<p>As an extension, the C11 generic selection expression is available in all
-languages supported by Clang. The syntax is the same as that given in the
-C11 standard.</p>
-
-<p>In C, type compatibility is decided according to the rules given in the
-appropriate standard, but in C++, which lacks the type compatibility rules
-used in C, types are considered compatible only if they are equivalent.</p>
-
-<h4 id="c_static_assert">C11 <tt>_Static_assert()</tt></h4>
-
-<p>Use <tt>__has_feature(c_static_assert)</tt> or
-<tt>__has_extension(c_static_assert)</tt> to determine if support for
-compile-time assertions using <tt>_Static_assert</tt> is enabled.</p>
-
-<!-- ======================================================================= -->
-<h2 id="checking_type_traits">Checks for Type Traits</h2>
-<!-- ======================================================================= -->
-
-<p>Clang supports the <a href="http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html">GNU C++ type traits</a> and a subset of the <a href="http://msdn.microsoft.com/en-us/library/ms177194(v=VS.100).aspx">Microsoft Visual C++ Type traits</a>. For each supported type trait <code>__X</code>, <code>__has_extension(X)</code> indicates the presence of the type trait. For example:
-<blockquote>
-<pre>
-#if __has_extension(is_convertible_to)
-template&lt;typename From, typename To&gt;
-struct is_convertible_to {
- static const bool value = __is_convertible_to(From, To);
-};
-#else
-// Emulate type trait
-#endif
-</pre>
-</blockquote>
-
-<p>The following type traits are supported by Clang:</p>
-<ul>
- <li><code>__has_nothrow_assign</code> (GNU, Microsoft)</li>
- <li><code>__has_nothrow_copy</code> (GNU, Microsoft)</li>
- <li><code>__has_nothrow_constructor</code> (GNU, Microsoft)</li>
- <li><code>__has_trivial_assign</code> (GNU, Microsoft)</li>
- <li><code>__has_trivial_copy</code> (GNU, Microsoft)</li>
- <li><code>__has_trivial_constructor</code> (GNU, Microsoft)</li>
- <li><code>__has_trivial_destructor</code> (GNU, Microsoft)</li>
- <li><code>__has_virtual_destructor</code> (GNU, Microsoft)</li>
- <li><code>__is_abstract</code> (GNU, Microsoft)</li>
- <li><code>__is_base_of</code> (GNU, Microsoft)</li>
- <li><code>__is_class</code> (GNU, Microsoft)</li>
- <li><code>__is_convertible_to</code> (Microsoft)</li>
- <li><code>__is_empty</code> (GNU, Microsoft)</li>
- <li><code>__is_enum</code> (GNU, Microsoft)</li>
- <li><code>__is_interface_class</code> (Microsoft)</li>
- <li><code>__is_pod</code> (GNU, Microsoft)</li>
- <li><code>__is_polymorphic</code> (GNU, Microsoft)</li>
- <li><code>__is_union</code> (GNU, Microsoft)</li>
- <li><code>__is_literal(type)</code>: Determines whether the given type is a literal type</li>
- <li><code>__is_final</code>: Determines whether the given type is declared with a <code>final</code> class-virt-specifier.</li>
- <li><code>__underlying_type(type)</code>: Retrieves the underlying type for a given <code>enum</code> type. This trait is required to implement the C++11 standard library.</li>
- <li><code>__is_trivially_assignable(totype, fromtype)</code>: Determines whether a value of type <tt>totype</tt> can be assigned to from a value of type <tt>fromtype</tt> such that no non-trivial functions are called as part of that assignment. This trait is required to implement the C++11 standard library.</li>
- <li><code>__is_trivially_constructible(type, argtypes...)</code>: Determines whether a value of type <tt>type</tt> can be direct-initialized with arguments of types <tt>argtypes...</tt> such that no non-trivial functions are called as part of that initialization. This trait is required to implement the C++11 standard library.</li>
-</ul>
-
-<!-- ======================================================================= -->
-<h2 id="blocks">Blocks</h2>
-<!-- ======================================================================= -->
-
-<p>The syntax and high level language feature description is in <a
-href="BlockLanguageSpec.txt">BlockLanguageSpec.txt</a>. Implementation and ABI
-details for the clang implementation are in <a
-href="Block-ABI-Apple.txt">Block-ABI-Apple.txt</a>.</p>
-
-
-<p>Query for this feature with __has_extension(blocks).</p>
-
-<!-- ======================================================================= -->
-<h2 id="objc_features">Objective-C Features</h2>
-<!-- ======================================================================= -->
-
-<h3 id="objc_instancetype">Related result types</h3>
-
-<p>According to Cocoa conventions, Objective-C methods with certain names ("init", "alloc", etc.) always return objects that are an instance of the receiving class's type. Such methods are said to have a "related result type", meaning that a message send to one of these methods will have the same static type as an instance of the receiver class. For example, given the following classes:</p>
-
-<blockquote>
-<pre>
-@interface NSObject
-+ (id)alloc;
-- (id)init;
-@end
-
-@interface NSArray : NSObject
-@end
-</pre>
-</blockquote>
-
-<p>and this common initialization pattern</p>
-
-<blockquote>
-<pre>
-NSArray *array = [[NSArray alloc] init];
-</pre>
-</blockquote>
-
-<p>the type of the expression <code>[NSArray alloc]</code> is
-<code>NSArray*</code> because <code>alloc</code> implicitly has a
-related result type. Similarly, the type of the expression
-<code>[[NSArray alloc] init]</code> is <code>NSArray*</code>, since
-<code>init</code> has a related result type and its receiver is known
-to have the type <code>NSArray *</code>. If neither <code>alloc</code> nor <code>init</code> had a related result type, the expressions would have had type <code>id</code>, as declared in the method signature.</p>
-
-<p>A method with a related result type can be declared by using the
-type <tt>instancetype</tt> as its result type. <tt>instancetype</tt>
-is a contextual keyword that is only permitted in the result type of
-an Objective-C method, e.g.</p>
-
-<pre>
-@interface A
-+ (<b>instancetype</b>)constructAnA;
-@end
-</pre>
-
-<p>The related result type can also be inferred for some methods.
-To determine whether a method has an inferred related result type, the first
-word in the camel-case selector (e.g., "init" in "initWithObjects") is
-considered, and the method will have a related result type if its return
-type is compatible with the type of its class and if</p>
-
-<ul>
-
- <li>the first word is "alloc" or "new", and the method is a class
- method, or</li>
-
- <li>the first word is "autorelease", "init", "retain", or "self",
- and the method is an instance method.</li>
-
-</ul>
-
-<p>If a method with a related result type is overridden by a subclass
-method, the subclass method must also return a type that is compatible
-with the subclass type. For example:</p>
-
-<blockquote>
-<pre>
-@interface NSString : NSObject
-- (NSUnrelated *)init; // incorrect usage: NSUnrelated is not NSString or a superclass of NSString
-@end
-</pre>
-</blockquote>
-
-<p>Related result types only affect the type of a message send or
-property access via the given method. In all other respects, a method
-with a related result type is treated the same way as method that
-returns <tt>id</tt>.</p>
-
-<p>Use <tt>__has_feature(objc_instancetype)</tt> to determine whether
-the <tt>instancetype</tt> contextual keyword is available.</p>
-
-<!-- ======================================================================= -->
-<h2 id="objc_arc">Automatic reference counting </h2>
-<!-- ======================================================================= -->
-
-<p>Clang provides support for <a href="AutomaticReferenceCounting.html">automated reference counting</a> in Objective-C, which eliminates the need for manual retain/release/autorelease message sends. There are two feature macros associated with automatic reference counting: <code>__has_feature(objc_arc)</code> indicates the availability of automated reference counting in general, while <code>__has_feature(objc_arc_weak)</code> indicates that automated reference counting also includes support for <code>__weak</code> pointers to Objective-C objects.</p>
-
-<!-- ======================================================================= -->
-<h2 id="objc_fixed_enum">Enumerations with a fixed underlying type</h2>
-<!-- ======================================================================= -->
-
-<p>Clang provides support for C++11 enumerations with a fixed
-underlying type within Objective-C. For example, one can write an
-enumeration type as:</p>
-
-<pre>
-typedef enum : unsigned char { Red, Green, Blue } Color;
-</pre>
-
-<p>This specifies that the underlying type, which is used to store the
-enumeration value, is <tt>unsigned char</tt>.</p>
-
-<p>Use <tt>__has_feature(objc_fixed_enum)</tt> to determine whether
-support for fixed underlying types is available in Objective-C.</p>
-
-<!-- ======================================================================= -->
-<h2 id="objc_lambdas">Interoperability with C++11 lambdas</h2>
-<!-- ======================================================================= -->
-
-<p>Clang provides interoperability between C++11 lambdas and
-blocks-based APIs, by permitting a lambda to be implicitly converted
-to a block pointer with the corresponding signature. For example,
-consider an API such as <code>NSArray</code>'s array-sorting
-method:</p>
-
-<pre> - (NSArray *)sortedArrayUsingComparator:(NSComparator)cmptr; </pre>
-
-<p><code>NSComparator</code> is simply a typedef for the block pointer
-<code>NSComparisonResult (^)(id, id)</code>, and parameters of this
-type are generally provided with block literals as arguments. However,
-one can also use a C++11 lambda so long as it provides the same
-signature (in this case, accepting two parameters of type
-<code>id</code> and returning an <code>NSComparisonResult</code>):</p>
-
-<pre>
- NSArray *array = @[@"string 1", @"string 21", @"string 12", @"String 11",
- @"String 02"];
- const NSStringCompareOptions comparisonOptions
- = NSCaseInsensitiveSearch | NSNumericSearch |
- NSWidthInsensitiveSearch | NSForcedOrderingSearch;
- NSLocale *currentLocale = [NSLocale currentLocale];
- NSArray *sorted
- = [array sortedArrayUsingComparator:<b>[=](id s1, id s2) -&gt; NSComparisonResult {
- NSRange string1Range = NSMakeRange(0, [s1 length]);
- return [s1 compare:s2 options:comparisonOptions
- range:string1Range locale:currentLocale];
- }</b>];
- NSLog(@"sorted: %@", sorted);
-</pre>
-
-<p>This code relies on an implicit conversion from the type of the
-lambda expression (an unnamed, local class type called the <i>closure
-type</i>) to the corresponding block pointer type. The conversion
-itself is expressed by a conversion operator in that closure type
-that produces a block pointer with the same signature as the lambda
-itself, e.g.,</p>
-
-<pre>
- operator NSComparisonResult (^)(id, id)() const;
-</pre>
-
-<p>This conversion function returns a new block that simply forwards
-the two parameters to the lambda object (which it captures by copy),
-then returns the result. The returned block is first copied (with
-<tt>Block_copy</tt>) and then autoreleased. As an optimization, if a
-lambda expression is immediately converted to a block pointer (as in
-the first example, above), then the block is not copied and
-autoreleased: rather, it is given the same lifetime as a block literal
-written at that point in the program, which avoids the overhead of
-copying a block to the heap in the common case.</p>
-
-<p>The conversion from a lambda to a block pointer is only available
-in Objective-C++, and not in C++ with blocks, due to its use of
-Objective-C memory management (autorelease).</p>
-
-<!-- ======================================================================= -->
-<h2 id="objc_object_literals_subscripting">Object Literals and Subscripting</h2>
-<!-- ======================================================================= -->
-
-<p>Clang provides support for <a href="ObjectiveCLiterals.html">Object Literals
-and Subscripting</a> in Objective-C, which simplifies common Objective-C
-programming patterns, makes programs more concise, and improves the safety of
-container creation. There are several feature macros associated with object
-literals and subscripting: <code>__has_feature(objc_array_literals)</code>
-tests the availability of array literals;
-<code>__has_feature(objc_dictionary_literals)</code> tests the availability of
-dictionary literals; <code>__has_feature(objc_subscripting)</code> tests the
-availability of object subscripting.</p>
-
-<!-- ======================================================================= -->
-<h2 id="objc_default_synthesize_properties">Objective-C Autosynthesis of Properties</h2>
-<!-- ======================================================================= -->
-
-<p> Clang provides support for autosynthesis of declared properties. Using this
-feature, clang provides default synthesis of those properties not declared @dynamic
-and not having user provided backing getter and setter methods.
-<code>__has_feature(objc_default_synthesize_properties)</code> checks for availability
-of this feature in version of clang being used.</p>
-
-<!-- ======================================================================= -->
-<h2 id="overloading-in-c">Function Overloading in C</h2>
-<!-- ======================================================================= -->
-
-<p>Clang provides support for C++ function overloading in C. Function
-overloading in C is introduced using the <tt>overloadable</tt> attribute. For
-example, one might provide several overloaded versions of a <tt>tgsin</tt>
-function that invokes the appropriate standard function computing the sine of a
-value with <tt>float</tt>, <tt>double</tt>, or <tt>long double</tt>
-precision:</p>
-
-<blockquote>
-<pre>
-#include &lt;math.h&gt;
-float <b>__attribute__((overloadable))</b> tgsin(float x) { return sinf(x); }
-double <b>__attribute__((overloadable))</b> tgsin(double x) { return sin(x); }
-long double <b>__attribute__((overloadable))</b> tgsin(long double x) { return sinl(x); }
-</pre>
-</blockquote>
-
-<p>Given these declarations, one can call <tt>tgsin</tt> with a
-<tt>float</tt> value to receive a <tt>float</tt> result, with a
-<tt>double</tt> to receive a <tt>double</tt> result, etc. Function
-overloading in C follows the rules of C++ function overloading to pick
-the best overload given the call arguments, with a few C-specific
-semantics:</p>
-<ul>
- <li>Conversion from <tt>float</tt> or <tt>double</tt> to <tt>long
- double</tt> is ranked as a floating-point promotion (per C99) rather
- than as a floating-point conversion (as in C++).</li>
-
- <li>A conversion from a pointer of type <tt>T*</tt> to a pointer of type
- <tt>U*</tt> is considered a pointer conversion (with conversion
- rank) if <tt>T</tt> and <tt>U</tt> are compatible types.</li>
-
- <li>A conversion from type <tt>T</tt> to a value of type <tt>U</tt>
- is permitted if <tt>T</tt> and <tt>U</tt> are compatible types. This
- conversion is given "conversion" rank.</li>
-</ul>
-
-<p>The declaration of <tt>overloadable</tt> functions is restricted to
-function declarations and definitions. Most importantly, if any
-function with a given name is given the <tt>overloadable</tt>
-attribute, then all function declarations and definitions with that
-name (and in that scope) must have the <tt>overloadable</tt>
-attribute. This rule even applies to redeclarations of functions whose original
-declaration had the <tt>overloadable</tt> attribute, e.g.,</p>
-
-<blockquote>
-<pre>
-int f(int) __attribute__((overloadable));
-float f(float); <i>// error: declaration of "f" must have the "overloadable" attribute</i>
-
-int g(int) __attribute__((overloadable));
-int g(int) { } <i>// error: redeclaration of "g" must also have the "overloadable" attribute</i>
-</pre>
-</blockquote>
-
-<p>Functions marked <tt>overloadable</tt> must have
-prototypes. Therefore, the following code is ill-formed:</p>
-
-<blockquote>
-<pre>
-int h() __attribute__((overloadable)); <i>// error: h does not have a prototype</i>
-</pre>
-</blockquote>
-
-<p>However, <tt>overloadable</tt> functions are allowed to use a
-ellipsis even if there are no named parameters (as is permitted in C++). This feature is particularly useful when combined with the <tt>unavailable</tt> attribute:</p>
-
-<blockquote>
-<pre>
-void honeypot(...) __attribute__((overloadable, unavailable)); <i>// calling me is an error</i>
-</pre>
-</blockquote>
-
-<p>Functions declared with the <tt>overloadable</tt> attribute have
-their names mangled according to the same rules as C++ function
-names. For example, the three <tt>tgsin</tt> functions in our
-motivating example get the mangled names <tt>_Z5tgsinf</tt>,
-<tt>_Z5tgsind</tt>, and <tt>_Z5tgsine</tt>, respectively. There are two
-caveats to this use of name mangling:</p>
-
-<ul>
-
- <li>Future versions of Clang may change the name mangling of
- functions overloaded in C, so you should not depend on an specific
- mangling. To be completely safe, we strongly urge the use of
- <tt>static inline</tt> with <tt>overloadable</tt> functions.</li>
-
- <li>The <tt>overloadable</tt> attribute has almost no meaning when
- used in C++, because names will already be mangled and functions are
- already overloadable. However, when an <tt>overloadable</tt>
- function occurs within an <tt>extern "C"</tt> linkage specification,
- it's name <i>will</i> be mangled in the same way as it would in
- C.</li>
-</ul>
-
-<p>Query for this feature with __has_extension(attribute_overloadable).</p>
-
-<!-- ======================================================================= -->
-<h2 id="complex-list-init">Initializer lists for complex numbers in C</h2>
-<!-- ======================================================================= -->
-
-<p>clang supports an extension which allows the following in C:</p>
-
-<blockquote>
-<pre>
-#include &lt;math.h&gt;
-#include &lt;complex.h&gt;
-complex float x = { 1.0f, INFINITY }; // Init to (1, Inf)
-</pre>
-</blockquote>
-
-<p>This construct is useful because there is no way to separately
-initialize the real and imaginary parts of a complex variable in
-standard C, given that clang does not support <code>_Imaginary</code>.
-(clang also supports the <code>__real__</code> and <code>__imag__</code>
-extensions from gcc, which help in some cases, but are not usable in
-static initializers.)
-
-<p>Note that this extension does not allow eliding the braces; the
-meaning of the following two lines is different:</p>
-
-<blockquote>
-<pre>
-complex float x[] = { { 1.0f, 1.0f } }; // [0] = (1, 1)
-complex float x[] = { 1.0f, 1.0f }; // [0] = (1, 0), [1] = (1, 0)
-</pre>
-</blockquote>
-
-<p>This extension also works in C++ mode, as far as that goes, but does not
- apply to the C++ <code>std::complex</code>. (In C++11, list
- initialization allows the same syntax to be used with
- <code>std::complex</code> with the same meaning.)
-
-<!-- ======================================================================= -->
-<h2 id="builtins">Builtin Functions</h2>
-<!-- ======================================================================= -->
-
-<p>Clang supports a number of builtin library functions with the same syntax as
-GCC, including things like <tt>__builtin_nan</tt>,
-<tt>__builtin_constant_p</tt>, <tt>__builtin_choose_expr</tt>,
-<tt>__builtin_types_compatible_p</tt>, <tt>__sync_fetch_and_add</tt>, etc. In
-addition to the GCC builtins, Clang supports a number of builtins that GCC does
-not, which are listed here.</p>
-
-<p>Please note that Clang does not and will not support all of the GCC builtins
-for vector operations. Instead of using builtins, you should use the functions
-defined in target-specific header files like <tt>&lt;xmmintrin.h&gt;</tt>, which
-define portable wrappers for these. Many of the Clang versions of these
-functions are implemented directly in terms of <a href="#vectors">extended
-vector support</a> instead of builtins, in order to reduce the number of
-builtins that we need to implement.</p>
-
-<!-- ======================================================================= -->
-<h3><a name="__builtin_readcyclecounter">__builtin_readcyclecounter</a></h3>
-<!-- ======================================================================= -->
-
-<p><tt>__builtin_readcyclecounter</tt> is used to access the cycle counter
-register (or a similar low-latency, high-accuracy clock) on those targets that
-support it.
-</p>
-
-<p><b>Syntax:</b></p>
-
-<pre>
-__builtin_readcyclecounter()
-</pre>
-
-<p><b>Example of Use:</b></p>
-
-<pre>
-unsigned long long t0 = __builtin_readcyclecounter();
-do_something();
-unsigned long long t1 = __builtin_readcyclecounter();
-unsigned long long cycles_to_do_something = t1 - t0; // assuming no overflow
-</pre>
-
-<p><b>Description:</b></p>
-
-<p>The __builtin_readcyclecounter() builtin returns the cycle counter value,
-which may be either global or process/thread-specific depending on the target.
-As the backing counters often overflow quickly (on the order of
-seconds) this should only be used for timing small intervals. When not
-supported by the target, the return value is always zero. This builtin
-takes no arguments and produces an unsigned long long result.
-</p>
-
-<p>Query for this feature with __has_builtin(__builtin_readcyclecounter).</p>
-
-<!-- ======================================================================= -->
-<h3><a name="__builtin_shufflevector">__builtin_shufflevector</a></h3>
-<!-- ======================================================================= -->
-
-<p><tt>__builtin_shufflevector</tt> is used to express generic vector
-permutation/shuffle/swizzle operations. This builtin is also very important for
-the implementation of various target-specific header files like
-<tt>&lt;xmmintrin.h&gt;</tt>.
-</p>
-
-<p><b>Syntax:</b></p>
-
-<pre>
-__builtin_shufflevector(vec1, vec2, index1, index2, ...)
-</pre>
-
-<p><b>Examples:</b></p>
-
-<pre>
- // Identity operation - return 4-element vector V1.
- __builtin_shufflevector(V1, V1, 0, 1, 2, 3)
-
- // "Splat" element 0 of V1 into a 4-element result.
- __builtin_shufflevector(V1, V1, 0, 0, 0, 0)
-
- // Reverse 4-element vector V1.
- __builtin_shufflevector(V1, V1, 3, 2, 1, 0)
-
- // Concatenate every other element of 4-element vectors V1 and V2.
- __builtin_shufflevector(V1, V2, 0, 2, 4, 6)
-
- // Concatenate every other element of 8-element vectors V1 and V2.
- __builtin_shufflevector(V1, V2, 0, 2, 4, 6, 8, 10, 12, 14)
-</pre>
-
-<p><b>Description:</b></p>
-
-<p>The first two arguments to __builtin_shufflevector are vectors that have the
-same element type. The remaining arguments are a list of integers that specify
-the elements indices of the first two vectors that should be extracted and
-returned in a new vector. These element indices are numbered sequentially
-starting with the first vector, continuing into the second vector. Thus, if
-vec1 is a 4-element vector, index 5 would refer to the second element of vec2.
-</p>
-
-<p>The result of __builtin_shufflevector is a vector
-with the same element type as vec1/vec2 but that has an element count equal to
-the number of indices specified.
-</p>
-
-<p>Query for this feature with __has_builtin(__builtin_shufflevector).</p>
-
-<!-- ======================================================================= -->
-<h3><a name="__builtin_unreachable">__builtin_unreachable</a></h3>
-<!-- ======================================================================= -->
-
-<p><tt>__builtin_unreachable</tt> is used to indicate that a specific point in
-the program cannot be reached, even if the compiler might otherwise think it
-can. This is useful to improve optimization and eliminates certain warnings.
-For example, without the <tt>__builtin_unreachable</tt> in the example below,
-the compiler assumes that the inline asm can fall through and prints a "function
-declared 'noreturn' should not return" warning.
-</p>
-
-<p><b>Syntax:</b></p>
-
-<pre>
-__builtin_unreachable()
-</pre>
-
-<p><b>Example of Use:</b></p>
-
-<pre>
-void myabort(void) __attribute__((noreturn));
-void myabort(void) {
- asm("int3");
- __builtin_unreachable();
-}
-</pre>
-
-<p><b>Description:</b></p>
-
-<p>The __builtin_unreachable() builtin has completely undefined behavior. Since
-it has undefined behavior, it is a statement that it is never reached and the
-optimizer can take advantage of this to produce better code. This builtin takes
-no arguments and produces a void result.
-</p>
-
-<p>Query for this feature with __has_builtin(__builtin_unreachable).</p>
-
-<!-- ======================================================================= -->
-<h3><a name="__sync_swap">__sync_swap</a></h3>
-<!-- ======================================================================= -->
-
-<p><tt>__sync_swap</tt> is used to atomically swap integers or pointers in
-memory.
-</p>
-
-<p><b>Syntax:</b></p>
-
-<pre>
-<i>type</i> __sync_swap(<i>type</i> *ptr, <i>type</i> value, ...)
-</pre>
-
-<p><b>Example of Use:</b></p>
-
-<pre>
-int old_value = __sync_swap(&amp;value, new_value);
-</pre>
-
-<p><b>Description:</b></p>
-
-<p>The __sync_swap() builtin extends the existing __sync_*() family of atomic
-intrinsics to allow code to atomically swap the current value with the new
-value. More importantly, it helps developers write more efficient and correct
-code by avoiding expensive loops around __sync_bool_compare_and_swap() or
-relying on the platform specific implementation details of
-__sync_lock_test_and_set(). The __sync_swap() builtin is a full barrier.
-</p>
-
-<!-- ======================================================================= -->
-<h3><a name="__c11_atomic">__c11_atomic builtins</a></h3>
-<!-- ======================================================================= -->
-
-<p>Clang provides a set of builtins which are intended to be used to implement
-C11's <tt>&lt;stdatomic.h&gt;</tt> header. These builtins provide the semantics
-of the <tt>_explicit</tt> form of the corresponding C11 operation, and are named
-with a <tt>__c11_</tt> prefix. The supported operations are:</p>
-
-<ul>
- <li><tt>__c11_atomic_init</tt></li>
- <li><tt>__c11_atomic_thread_fence</tt></li>
- <li><tt>__c11_atomic_signal_fence</tt></li>
- <li><tt>__c11_atomic_is_lock_free</tt></li>
- <li><tt>__c11_atomic_store</tt></li>
- <li><tt>__c11_atomic_load</tt></li>
- <li><tt>__c11_atomic_exchange</tt></li>
- <li><tt>__c11_atomic_compare_exchange_strong</tt></li>
- <li><tt>__c11_atomic_compare_exchange_weak</tt></li>
- <li><tt>__c11_atomic_fetch_add</tt></li>
- <li><tt>__c11_atomic_fetch_sub</tt></li>
- <li><tt>__c11_atomic_fetch_and</tt></li>
- <li><tt>__c11_atomic_fetch_or</tt></li>
- <li><tt>__c11_atomic_fetch_xor</tt></li>
-</ul>
-
-<!-- ======================================================================= -->
-<h2 id="non-standard-attributes">Non-standard C++11 Attributes</h2>
-<!-- ======================================================================= -->
-
-<p>Clang supports one non-standard C++11 attribute. It resides in the
-<tt>clang</tt> attribute namespace.</p>
-
-<!-- ======================================================================= -->
-<h3 id="clang__fallthrough">The <tt>clang::fallthrough</tt> attribute</h3>
-<!-- ======================================================================= -->
-
-<p>The <tt>clang::fallthrough</tt> attribute is used along with the
-<tt>-Wimplicit-fallthrough</tt> argument to annotate intentional fall-through
-between switch labels. It can only be applied to a null statement placed at a
-point of execution between any statement and the next switch label. It is common
-to mark these places with a specific comment, but this attribute is meant to
-replace comments with a more strict annotation, which can be checked by the
-compiler. This attribute doesn't change semantics of the code and can be used
-wherever an intended fall-through occurs. It is designed to mimic
-control-flow statements like <tt>break;</tt>, so it can be placed in most places
-where <tt>break;</tt> can, but only if there are no statements on the execution
-path between it and the next switch label.</p>
-<p>Here is an example:</p>
-<pre>
-// compile with -Wimplicit-fallthrough
-switch (n) {
-case 22:
-case 33: // no warning: no statements between case labels
- f();
-case 44: // warning: unannotated fall-through
- g();
- <b>[[clang::fallthrough]];</b>
-case 55: // no warning
- if (x) {
- h();
- break;
- }
- else {
- i();
- <b>[[clang::fallthrough]];</b>
- }
-case 66: // no warning
- p();
- <b>[[clang::fallthrough]];</b> // warning: fallthrough annotation does not directly precede case label
- q();
-case 77: // warning: unannotated fall-through
- r();
-}
-</pre>
-
-<!-- ======================================================================= -->
-<h2 id="targetspecific">Target-Specific Extensions</h2>
-<!-- ======================================================================= -->
-
-<p>Clang supports some language features conditionally on some targets.</p>
-
-<!-- ======================================================================= -->
-<h3 id="x86-specific">X86/X86-64 Language Extensions</h3>
-<!-- ======================================================================= -->
-
-<p>The X86 backend has these language extensions:</p>
-
-<!-- ======================================================================= -->
-<h4 id="x86-gs-segment">Memory references off the GS segment</h4>
-<!-- ======================================================================= -->
-
-<p>Annotating a pointer with address space #256 causes it to be code generated
-relative to the X86 GS segment register, and address space #257 causes it to be
-relative to the X86 FS segment. Note that this is a very very low-level
-feature that should only be used if you know what you're doing (for example in
-an OS kernel).</p>
-
-<p>Here is an example:</p>
-
-<pre>
-#define GS_RELATIVE __attribute__((address_space(256)))
-int foo(int GS_RELATIVE *P) {
- return *P;
-}
-</pre>
-
-<p>Which compiles to (on X86-32):</p>
-
-<pre>
-_foo:
- movl 4(%esp), %eax
- movl %gs:(%eax), %eax
- ret
-</pre>
-
-<!-- ======================================================================= -->
-<h2 id="analyzerspecific">Static Analysis-Specific Extensions</h2>
-<!-- ======================================================================= -->
-
-<p>Clang supports additional attributes that are useful for documenting program
-invariants and rules for static analysis tools. The extensions documented here
-are used by the <a
-href="http://clang.llvm.org/StaticAnalysis.html">path-sensitive static analyzer
-engine</a> that is part of Clang's Analysis library.</p>
-
-<h3 id="attr_analyzer_noreturn">The <tt>analyzer_noreturn</tt> attribute</h3>
-
-<p>Clang's static analysis engine understands the standard <tt>noreturn</tt>
-attribute. This attribute, which is typically affixed to a function prototype,
-indicates that a call to a given function never returns. Function prototypes for
-common functions like <tt>exit</tt> are typically annotated with this attribute,
-as well as a variety of common assertion handlers. Users can educate the static
-analyzer about their own custom assertion handles (thus cutting down on false
-positives due to false paths) by marking their own &quot;panic&quot; functions
-with this attribute.</p>
-
-<p>While useful, <tt>noreturn</tt> is not applicable in all cases. Sometimes
-there are special functions that for all intents and purposes should be
-considered panic functions (i.e., they are only called when an internal program
-error occurs) but may actually return so that the program can fail gracefully.
-The <tt>analyzer_noreturn</tt> attribute allows one to annotate such functions
-as being interpreted as &quot;no return&quot; functions by the analyzer (thus
-pruning bogus paths) but will not affect compilation (as in the case of
-<tt>noreturn</tt>).</p>
-
-<p><b>Usage</b>: The <tt>analyzer_noreturn</tt> attribute can be placed in the
-same places where the <tt>noreturn</tt> attribute can be placed. It is commonly
-placed at the end of function prototypes:</p>
-
-<pre>
- void foo() <b>__attribute__((analyzer_noreturn))</b>;
-</pre>
-
-<p>Query for this feature with
-<tt>__has_attribute(analyzer_noreturn)</tt>.</p>
-
-<h3 id="attr_method_family">The <tt>objc_method_family</tt> attribute</h3>
-
-<p>Many methods in Objective-C have conventional meanings determined
-by their selectors. For the purposes of static analysis, it is
-sometimes useful to be able to mark a method as having a particular
-conventional meaning despite not having the right selector, or as not
-having the conventional meaning that its selector would suggest.
-For these use cases, we provide an attribute to specifically describe
-the <q>method family</q> that a method belongs to.</p>
-
-<p><b>Usage</b>: <tt>__attribute__((objc_method_family(X)))</tt>,
-where <tt>X</tt> is one of <tt>none</tt>, <tt>alloc</tt>, <tt>copy</tt>,
-<tt>init</tt>, <tt>mutableCopy</tt>, or <tt>new</tt>. This attribute
-can only be placed at the end of a method declaration:</p>
-
-<pre>
- - (NSString*) initMyStringValue <b>__attribute__((objc_method_family(none)))</b>;
-</pre>
-
-<p>Users who do not wish to change the conventional meaning of a
-method, and who merely want to document its non-standard retain and
-release semantics, should use the
-<a href="#attr_retain_release">retaining behavior attributes</a>
-described below.</p>
-
-<p>Query for this feature with
-<tt>__has_attribute(objc_method_family)</tt>.</p>
-
-<h3 id="attr_retain_release">Objective-C retaining behavior attributes</h3>
-
-<p>In Objective-C, functions and methods are generally assumed to take
-and return objects with +0 retain counts, with some exceptions for
-special methods like <tt>+alloc</tt> and <tt>init</tt>. However,
-there are exceptions, and so Clang provides attributes to allow these
-exceptions to be documented, which helps the analyzer find leaks (and
-ignore non-leaks). Some exceptions may be better described using
-the <a href="#attr_method_family"><tt>objc_method_family</tt></a>
-attribute instead.</p>
-
-<p><b>Usage</b>: The <tt>ns_returns_retained</tt>, <tt>ns_returns_not_retained</tt>,
-<tt>ns_returns_autoreleased</tt>, <tt>cf_returns_retained</tt>,
-and <tt>cf_returns_not_retained</tt> attributes can be placed on
-methods and functions that return Objective-C or CoreFoundation
-objects. They are commonly placed at the end of a function prototype
-or method declaration:</p>
-
-<pre>
- id foo() <b>__attribute__((ns_returns_retained))</b>;
-
- - (NSString*) bar: (int) x <b>__attribute__((ns_returns_retained))</b>;
-</pre>
-
-<p>The <tt>*_returns_retained</tt> attributes specify that the
-returned object has a +1 retain count.
-The <tt>*_returns_not_retained</tt> attributes specify that the return
-object has a +0 retain count, even if the normal convention for its
-selector would be +1. <tt>ns_returns_autoreleased</tt> specifies that the
-returned object is +0, but is guaranteed to live at least as long as the
-next flush of an autorelease pool.</p>
-
-<p><b>Usage</b>: The <tt>ns_consumed</tt> and <tt>cf_consumed</tt>
-attributes can be placed on an parameter declaration; they specify
-that the argument is expected to have a +1 retain count, which will be
-balanced in some way by the function or method.
-The <tt>ns_consumes_self</tt> attribute can only be placed on an
-Objective-C method; it specifies that the method expects
-its <tt>self</tt> parameter to have a +1 retain count, which it will
-balance in some way.</p>
-
-<pre>
- void <b>foo(__attribute__((ns_consumed))</b> NSString *string);
-
- - (void) bar <b>__attribute__((ns_consumes_self))</b>;
- - (void) baz: (id) <b>__attribute__((ns_consumed))</b> x;
-</pre>
-
-<p>Query for these features with <tt>__has_attribute(ns_consumed)</tt>,
-<tt>__has_attribute(ns_returns_retained)</tt>, etc.</p>
-
-<!-- ======================================================================= -->
-<h2 id="dynamicanalyzerspecific">Dynamic Analysis-Specific Extensions</h2>
-<!-- ======================================================================= -->
-<h3 id="address_sanitizer">AddressSanitizer</h3>
-<p> Use <code>__has_feature(address_sanitizer)</code>
-to check if the code is being built with <a
- href="AddressSanitizer.html">AddressSanitizer</a>.
-</p>
-<p>Use <tt>__attribute__((no_address_safety_analysis))</tt> on a function
-declaration to specify that address safety instrumentation (e.g.
-AddressSanitizer) should not be applied to that function.
-</p>
-
-<!-- ======================================================================= -->
-<h2 id="threadsafety">Thread-Safety Annotation Checking</h2>
-<!-- ======================================================================= -->
-
-<p>Clang supports additional attributes for checking basic locking policies in
-multithreaded programs.
-Clang currently parses the following list of attributes, although
-<b>the implementation for these annotations is currently in development.</b>
-For more details, see the
-<a href="http://gcc.gnu.org/wiki/ThreadSafetyAnnotation">GCC implementation</a>.
-</p>
-
-<h4 id="ts_noanal">no_thread_safety_analysis</h4>
-
-<p>Use <tt>__attribute__((no_thread_safety_analysis))</tt> on a function
-declaration to specify that the thread safety analysis should not be run on that
-function. This attribute provides an escape hatch (e.g. for situations when it
-is difficult to annotate the locking policy). </p>
-
-<h4 id="ts_lockable">lockable</h4>
-
-<p>Use <tt>__attribute__((lockable))</tt> on a class definition to specify
-that it has a lockable type (e.g. a Mutex class). This annotation is primarily
-used to check consistency.</p>
-
-<h4 id="ts_scopedlockable">scoped_lockable</h4>
-
-<p>Use <tt>__attribute__((scoped_lockable))</tt> on a class definition to
-specify that it has a "scoped" lockable type. Objects of this type will acquire
-the lock upon construction and release it upon going out of scope.
- This annotation is primarily used to check
-consistency.</p>
-
-<h4 id="ts_guardedvar">guarded_var</h4>
-
-<p>Use <tt>__attribute__((guarded_var))</tt> on a variable declaration to
-specify that the variable must be accessed while holding some lock.</p>
-
-<h4 id="ts_ptguardedvar">pt_guarded_var</h4>
-
-<p>Use <tt>__attribute__((pt_guarded_var))</tt> on a pointer declaration to
-specify that the pointer must be dereferenced while holding some lock.</p>
-
-<h4 id="ts_guardedby">guarded_by(l)</h4>
-
-<p>Use <tt>__attribute__((guarded_by(l)))</tt> on a variable declaration to
-specify that the variable must be accessed while holding lock <tt>l</tt>.</p>
-
-<h4 id="ts_ptguardedby">pt_guarded_by(l)</h4>
-
-<p>Use <tt>__attribute__((pt_guarded_by(l)))</tt> on a pointer declaration to
-specify that the pointer must be dereferenced while holding lock <tt>l</tt>.</p>
-
-<h4 id="ts_acquiredbefore">acquired_before(...)</h4>
-
-<p>Use <tt>__attribute__((acquired_before(...)))</tt> on a declaration
-of a lockable variable to specify that the lock must be acquired before all
-attribute arguments. Arguments must be lockable type, and there must be at
-least one argument.</p>
-
-<h4 id="ts_acquiredafter">acquired_after(...)</h4>
-
-<p>Use <tt>__attribute__((acquired_after(...)))</tt> on a declaration
-of a lockable variable to specify that the lock must be acquired after all
-attribute arguments. Arguments must be lockable type, and there must be at
-least one argument.</p>
-
-<h4 id="ts_elf">exclusive_lock_function(...)</h4>
-
-<p>Use <tt>__attribute__((exclusive_lock_function(...)))</tt> on a function
-declaration to specify that the function acquires all listed locks
-exclusively. This attribute takes zero or more arguments: either of lockable
-type or integers indexing into function parameters of lockable type. If no
-arguments are given, the acquired lock is implicitly <tt>this</tt> of the
-enclosing object.</p>
-
-<h4 id="ts_slf">shared_lock_function(...)</h4>
-
-<p>Use <tt>__attribute__((shared_lock_function(...)))</tt> on a function
-declaration to specify that the function acquires all listed locks, although
- the locks may be shared (e.g. read locks). This attribute takes zero or more
-arguments: either of lockable type or integers indexing into function
-parameters of lockable type. If no arguments are given, the acquired lock is
-implicitly <tt>this</tt> of the enclosing object.</p>
-
-<h4 id="ts_etf">exclusive_trylock_function(...)</h4>
-
-<p>Use <tt>__attribute__((exclusive_lock_function(...)))</tt> on a function
-declaration to specify that the function will try (without blocking) to acquire
-all listed locks exclusively. This attribute takes one or more arguments. The
-first argument is an integer or boolean value specifying the return value of a
-successful lock acquisition. The remaining arugments are either of lockable type
-or integers indexing into function parameters of lockable type. If only one
-argument is given, the acquired lock is implicitly <tt>this</tt> of the
-enclosing object.</p>
-
-<h4 id="ts_stf">shared_trylock_function(...)</h4>
-
-<p>Use <tt>__attribute__((shared_lock_function(...)))</tt> on a function
-declaration to specify that the function will try (without blocking) to acquire
-all listed locks, although the locks may be shared (e.g. read locks). This
-attribute takes one or more arguments. The first argument is an integer or
-boolean value specifying the return value of a successful lock acquisition. The
-remaining arugments are either of lockable type or integers indexing into
-function parameters of lockable type. If only one argument is given, the
-acquired lock is implicitly <tt>this</tt> of the enclosing object.</p>
-
-<h4 id="ts_uf">unlock_function(...)</h4>
-
-<p>Use <tt>__attribute__((unlock_function(...)))</tt> on a function
-declaration to specify that the function release all listed locks. This
-attribute takes zero or more arguments: either of lockable type or integers
-indexing into function parameters of lockable type. If no arguments are given,
-the acquired lock is implicitly <tt>this</tt> of the enclosing object.</p>
-
-<h4 id="ts_lr">lock_returned(l)</h4>
-
-<p>Use <tt>__attribute__((lock_returned(l)))</tt> on a function
-declaration to specify that the function returns lock <tt>l</tt> (<tt>l</tt>
-must be of lockable type). This annotation is used to aid in resolving lock
-expressions.</p>
-
-<h4 id="ts_le">locks_excluded(...)</h4>
-
-<p>Use <tt>__attribute__((locks_excluded(...)))</tt> on a function declaration
-to specify that the function must not be called with the listed locks. Arguments
-must be lockable type, and there must be at least one argument.</p>
-
-<h4 id="ts_elr">exclusive_locks_required(...)</h4>
-
-<p>Use <tt>__attribute__((exclusive_locks_required(...)))</tt> on a function
-declaration to specify that the function must be called while holding the listed
-exclusive locks. Arguments must be lockable type, and there must be at
-least one argument.</p>
-
-<h4 id="ts_slr">shared_locks_required(...)</h4>
-
-<p>Use <tt>__attribute__((shared_locks_required(...)))</tt> on a function
-declaration to specify that the function must be called while holding the listed
-shared locks. Arguments must be lockable type, and there must be at
-least one argument.</p>
-
-<!-- ======================================================================= -->
-<h2 id="type_safety">Type Safety Checking</h2>
-<!-- ======================================================================= -->
-
-<p>Clang supports additional attributes to enable checking type safety
-properties that can't be enforced by C type system. Usecases include:</p>
-<ul>
-<li>MPI library implementations, where these attributes enable checking that
- buffer type matches the passed <tt>MPI_Datatype</tt>;</li>
-<li>for HDF5 library there is a similar usecase as MPI;</li>
-<li>checking types of variadic functions' arguments for functions like
- <tt>fcntl()</tt> and <tt>ioctl()</tt>.</li>
-</ul>
-
-<p>You can detect support for these attributes with __has_attribute(). For
-example:</p>
-
-<blockquote>
-<pre>
-#if defined(__has_attribute)
-# if __has_attribute(argument_with_type_tag) &amp;&amp; \
- __has_attribute(pointer_with_type_tag) &amp;&amp; \
- __has_attribute(type_tag_for_datatype)
-# define ATTR_MPI_PWT(buffer_idx, type_idx) __attribute__((pointer_with_type_tag(mpi,buffer_idx,type_idx)))
-/* ... other macros ... */
-# endif
-#endif
-
-#if !defined(ATTR_MPI_PWT)
-#define ATTR_MPI_PWT(buffer_idx, type_idx)
-#endif
-
-int MPI_Send(void *buf, int count, MPI_Datatype datatype /*, other args omitted */)
- ATTR_MPI_PWT(1,3);
-</pre>
-</blockquote>
-
-<h3 id="argument_with_type_tag"><tt>argument_with_type_tag(...)</tt></h3>
-
-<p>Use <tt>__attribute__((argument_with_type_tag(arg_kind, arg_idx,
-type_tag_idx)))</tt> on a function declaration to specify that the function
-accepts a type tag that determines the type of some other argument.
-<tt>arg_kind</tt> is an identifier that should be used when annotating all
-applicable type tags.</p>
-
-<p>This attribute is primarily useful for checking arguments of variadic
-functions (<tt>pointer_with_type_tag</tt> can be used in most of non-variadic
-cases).</p>
-
-<p>For example:</p>
-<blockquote>
-<pre>
-int fcntl(int fd, int cmd, ...)
- __attribute__(( argument_with_type_tag(fcntl,3,2) ));
-</pre>
-</blockquote>
-
-<h3 id="pointer_with_type_tag"><tt>pointer_with_type_tag(...)</tt></h3>
-
-<p>Use <tt>__attribute__((pointer_with_type_tag(ptr_kind, ptr_idx,
-type_tag_idx)))</tt> on a function declaration to specify that the
-function accepts a type tag that determines the pointee type of some other
-pointer argument.</p>
-
-<p>For example:</p>
-<blockquote>
-<pre>
-int MPI_Send(void *buf, int count, MPI_Datatype datatype /*, other args omitted */)
- __attribute__(( pointer_with_type_tag(mpi,1,3) ));
-</pre>
-</blockquote>
-
-<h3 id="type_tag_for_datatype"><tt>type_tag_for_datatype(...)</tt></h3>
-
-<p>Clang supports annotating type tags of two forms.</p>
-
-<ul>
-<li><b>Type tag that is an expression containing a reference to some declared
-identifier.</b> Use <tt>__attribute__((type_tag_for_datatype(kind, type)))</tt>
-on a declaration with that identifier:
-
-<blockquote>
-<pre>
-extern struct mpi_datatype mpi_datatype_int
- __attribute__(( type_tag_for_datatype(mpi,int) ));
-#define MPI_INT ((MPI_Datatype) &amp;mpi_datatype_int)
-</pre>
-</blockquote></li>
-
-<li><b>Type tag that is an integral literal.</b> Introduce a <tt>static
-const</tt> variable with a corresponding initializer value and attach
-<tt>__attribute__((type_tag_for_datatype(kind, type)))</tt> on that
-declaration, for example:
-
-<blockquote>
-<pre>
-#define MPI_INT ((MPI_Datatype) 42)
-static const MPI_Datatype mpi_datatype_int
- __attribute__(( type_tag_for_datatype(mpi,int) )) = 42
-</pre>
-</blockquote></li>
-</ul>
-
-<p>The attribute also accepts an optional third argument that determines how
-the expression is compared to the type tag. There are two supported flags:</p>
-
-<ul><li><tt>layout_compatible</tt> will cause types to be compared according to
-layout-compatibility rules (C++11 [class.mem] p&nbsp;17, 18). This is
-implemented to support annotating types like <tt>MPI_DOUBLE_INT</tt>.
-
-<p>For example:</p>
-<blockquote>
-<pre>
-/* In mpi.h */
-struct internal_mpi_double_int { double d; int i; };
-extern struct mpi_datatype mpi_datatype_double_int
- __attribute__(( type_tag_for_datatype(mpi, struct internal_mpi_double_int,
- layout_compatible) ));
-
-#define MPI_DOUBLE_INT ((MPI_Datatype) &amp;mpi_datatype_double_int)
-
-/* In user code */
-struct my_pair { double a; int b; };
-struct my_pair *buffer;
-MPI_Send(buffer, 1, MPI_DOUBLE_INT /*, ... */); // no warning
-
-struct my_int_pair { int a; int b; }
-struct my_int_pair *buffer2;
-MPI_Send(buffer2, 1, MPI_DOUBLE_INT /*, ... */); // warning: actual buffer element
- // type 'struct my_int_pair'
- // doesn't match specified MPI_Datatype
-</pre>
-</blockquote>
-</li>
-
-<li><tt>must_be_null</tt> specifies that the expression should be a null
-pointer constant, for example:
-
-<blockquote>
-<pre>
-/* In mpi.h */
-extern struct mpi_datatype mpi_datatype_null
- __attribute__(( type_tag_for_datatype(mpi, void, must_be_null) ));
-
-#define MPI_DATATYPE_NULL ((MPI_Datatype) &amp;mpi_datatype_null)
-
-/* In user code */
-MPI_Send(buffer, 1, MPI_DATATYPE_NULL /*, ... */); // warning: MPI_DATATYPE_NULL
- // was specified but buffer
- // is not a null pointer
-</pre>
-</blockquote>
-</li>
-</ul>
-
-</div>
-</body>
-</html>
diff --git a/docs/LanguageExtensions.rst b/docs/LanguageExtensions.rst
new file mode 100644
index 0000000..c870d20
--- /dev/null
+++ b/docs/LanguageExtensions.rst
@@ -0,0 +1,2000 @@
+=========================
+Clang Language Extensions
+=========================
+
+.. contents::
+ :local:
+ :depth: 1
+
+.. toctree::
+ :hidden:
+
+ ObjectiveCLiterals
+ BlockLanguageSpec
+ Block-ABI-Apple
+ AutomaticReferenceCounting
+
+Introduction
+============
+
+This document describes the language extensions provided by Clang. In addition
+to the language extensions listed here, Clang aims to support a broad range of
+GCC extensions. Please see the `GCC manual
+<http://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html>`_ for more information on
+these extensions.
+
+.. _langext-feature_check:
+
+Feature Checking Macros
+=======================
+
+Language extensions can be very useful, but only if you know you can depend on
+them. In order to allow fine-grain features checks, we support three builtin
+function-like macros. This allows you to directly test for a feature in your
+code without having to resort to something like autoconf or fragile "compiler
+version checks".
+
+``__has_builtin``
+-----------------
+
+This function-like macro takes a single identifier argument that is the name of
+a builtin function. It evaluates to 1 if the builtin is supported or 0 if not.
+It can be used like this:
+
+.. code-block:: c++
+
+ #ifndef __has_builtin // Optional of course.
+ #define __has_builtin(x) 0 // Compatibility with non-clang compilers.
+ #endif
+
+ ...
+ #if __has_builtin(__builtin_trap)
+ __builtin_trap();
+ #else
+ abort();
+ #endif
+ ...
+
+.. _langext-__has_feature-__has_extension:
+
+``__has_feature`` and ``__has_extension``
+-----------------------------------------
+
+These function-like macros take a single identifier argument that is the name
+of a feature. ``__has_feature`` evaluates to 1 if the feature is both
+supported by Clang and standardized in the current language standard or 0 if
+not (but see :ref:`below <langext-has-feature-back-compat>`), while
+``__has_extension`` evaluates to 1 if the feature is supported by Clang in the
+current language (either as a language extension or a standard language
+feature) or 0 if not. They can be used like this:
+
+.. code-block:: c++
+
+ #ifndef __has_feature // Optional of course.
+ #define __has_feature(x) 0 // Compatibility with non-clang compilers.
+ #endif
+ #ifndef __has_extension
+ #define __has_extension __has_feature // Compatibility with pre-3.0 compilers.
+ #endif
+
+ ...
+ #if __has_feature(cxx_rvalue_references)
+ // This code will only be compiled with the -std=c++11 and -std=gnu++11
+ // options, because rvalue references are only standardized in C++11.
+ #endif
+
+ #if __has_extension(cxx_rvalue_references)
+ // This code will be compiled with the -std=c++11, -std=gnu++11, -std=c++98
+ // and -std=gnu++98 options, because rvalue references are supported as a
+ // language extension in C++98.
+ #endif
+
+.. _langext-has-feature-back-compat:
+
+For backwards compatibility reasons, ``__has_feature`` can also be used to test
+for support for non-standardized features, i.e. features not prefixed ``c_``,
+``cxx_`` or ``objc_``.
+
+Another use of ``__has_feature`` is to check for compiler features not related
+to the language standard, such as e.g. :doc:`AddressSanitizer
+<AddressSanitizer>`.
+
+If the ``-pedantic-errors`` option is given, ``__has_extension`` is equivalent
+to ``__has_feature``.
+
+The feature tag is described along with the language feature below.
+
+The feature name or extension name can also be specified with a preceding and
+following ``__`` (double underscore) to avoid interference from a macro with
+the same name. For instance, ``__cxx_rvalue_references__`` can be used instead
+of ``cxx_rvalue_references``.
+
+``__has_attribute``
+-------------------
+
+This function-like macro takes a single identifier argument that is the name of
+an attribute. It evaluates to 1 if the attribute is supported or 0 if not. It
+can be used like this:
+
+.. code-block:: c++
+
+ #ifndef __has_attribute // Optional of course.
+ #define __has_attribute(x) 0 // Compatibility with non-clang compilers.
+ #endif
+
+ ...
+ #if __has_attribute(always_inline)
+ #define ALWAYS_INLINE __attribute__((always_inline))
+ #else
+ #define ALWAYS_INLINE
+ #endif
+ ...
+
+The attribute name can also be specified with a preceding and following ``__``
+(double underscore) to avoid interference from a macro with the same name. For
+instance, ``__always_inline__`` can be used instead of ``always_inline``.
+
+Include File Checking Macros
+============================
+
+Not all developments systems have the same include files. The
+:ref:`langext-__has_include` and :ref:`langext-__has_include_next` macros allow
+you to check for the existence of an include file before doing a possibly
+failing ``#include`` directive. Include file checking macros must be used
+as expressions in ``#if`` or ``#elif`` preprocessing directives.
+
+.. _langext-__has_include:
+
+``__has_include``
+-----------------
+
+This function-like macro takes a single file name string argument that is the
+name of an include file. It evaluates to 1 if the file can be found using the
+include paths, or 0 otherwise:
+
+.. code-block:: c++
+
+ // Note the two possible file name string formats.
+ #if __has_include("myinclude.h") && __has_include(<stdint.h>)
+ # include "myinclude.h"
+ #endif
+
+ // To avoid problem with non-clang compilers not having this macro.
+ #if defined(__has_include) && __has_include("myinclude.h")
+ # include "myinclude.h"
+ #endif
+
+To test for this feature, use ``#if defined(__has_include)``.
+
+.. _langext-__has_include_next:
+
+``__has_include_next``
+----------------------
+
+This function-like macro takes a single file name string argument that is the
+name of an include file. It is like ``__has_include`` except that it looks for
+the second instance of the given file found in the include paths. It evaluates
+to 1 if the second instance of the file can be found using the include paths,
+or 0 otherwise:
+
+.. code-block:: c++
+
+ // Note the two possible file name string formats.
+ #if __has_include_next("myinclude.h") && __has_include_next(<stdint.h>)
+ # include_next "myinclude.h"
+ #endif
+
+ // To avoid problem with non-clang compilers not having this macro.
+ #if defined(__has_include_next) && __has_include_next("myinclude.h")
+ # include_next "myinclude.h"
+ #endif
+
+Note that ``__has_include_next``, like the GNU extension ``#include_next``
+directive, is intended for use in headers only, and will issue a warning if
+used in the top-level compilation file. A warning will also be issued if an
+absolute path is used in the file argument.
+
+``__has_warning``
+-----------------
+
+This function-like macro takes a string literal that represents a command line
+option for a warning and returns true if that is a valid warning option.
+
+.. code-block:: c++
+
+ #if __has_warning("-Wformat")
+ ...
+ #endif
+
+Builtin Macros
+==============
+
+``__BASE_FILE__``
+ Defined to a string that contains the name of the main input file passed to
+ Clang.
+
+``__COUNTER__``
+ Defined to an integer value that starts at zero and is incremented each time
+ the ``__COUNTER__`` macro is expanded.
+
+``__INCLUDE_LEVEL__``
+ Defined to an integral value that is the include depth of the file currently
+ being translated. For the main file, this value is zero.
+
+``__TIMESTAMP__``
+ Defined to the date and time of the last modification of the current source
+ file.
+
+``__clang__``
+ Defined when compiling with Clang
+
+``__clang_major__``
+ Defined to the major marketing version number of Clang (e.g., the 2 in
+ 2.0.1). Note that marketing version numbers should not be used to check for
+ language features, as different vendors use different numbering schemes.
+ Instead, use the :ref:`langext-feature_check`.
+
+``__clang_minor__``
+ Defined to the minor version number of Clang (e.g., the 0 in 2.0.1). Note
+ that marketing version numbers should not be used to check for language
+ features, as different vendors use different numbering schemes. Instead, use
+ the :ref:`langext-feature_check`.
+
+``__clang_patchlevel__``
+ Defined to the marketing patch level of Clang (e.g., the 1 in 2.0.1).
+
+``__clang_version__``
+ Defined to a string that captures the Clang marketing version, including the
+ Subversion tag or revision number, e.g., "``1.5 (trunk 102332)``".
+
+.. _langext-vectors:
+
+Vectors and Extended Vectors
+============================
+
+Supports the GCC, OpenCL, AltiVec and NEON vector extensions.
+
+OpenCL vector types are created using ``ext_vector_type`` attribute. It
+support for ``V.xyzw`` syntax and other tidbits as seen in OpenCL. An example
+is:
+
+.. code-block:: c++
+
+ typedef float float4 __attribute__((ext_vector_type(4)));
+ typedef float float2 __attribute__((ext_vector_type(2)));
+
+ float4 foo(float2 a, float2 b) {
+ float4 c;
+ c.xz = a;
+ c.yw = b;
+ return c;
+ }
+
+Query for this feature with ``__has_extension(attribute_ext_vector_type)``.
+
+Giving ``-faltivec`` option to clang enables support for AltiVec vector syntax
+and functions. For example:
+
+.. code-block:: c++
+
+ vector float foo(vector int a) {
+ vector int b;
+ b = vec_add(a, a) + a;
+ return (vector float)b;
+ }
+
+NEON vector types are created using ``neon_vector_type`` and
+``neon_polyvector_type`` attributes. For example:
+
+.. code-block:: c++
+
+ typedef __attribute__((neon_vector_type(8))) int8_t int8x8_t;
+ typedef __attribute__((neon_polyvector_type(16))) poly8_t poly8x16_t;
+
+ int8x8_t foo(int8x8_t a) {
+ int8x8_t v;
+ v = a;
+ return v;
+ }
+
+Vector Literals
+---------------
+
+Vector literals can be used to create vectors from a set of scalars, or
+vectors. Either parentheses or braces form can be used. In the parentheses
+form the number of literal values specified must be one, i.e. referring to a
+scalar value, or must match the size of the vector type being created. If a
+single scalar literal value is specified, the scalar literal value will be
+replicated to all the components of the vector type. In the brackets form any
+number of literals can be specified. For example:
+
+.. code-block:: c++
+
+ typedef int v4si __attribute__((__vector_size__(16)));
+ typedef float float4 __attribute__((ext_vector_type(4)));
+ typedef float float2 __attribute__((ext_vector_type(2)));
+
+ v4si vsi = (v4si){1, 2, 3, 4};
+ float4 vf = (float4)(1.0f, 2.0f, 3.0f, 4.0f);
+ vector int vi1 = (vector int)(1); // vi1 will be (1, 1, 1, 1).
+ vector int vi2 = (vector int){1}; // vi2 will be (1, 0, 0, 0).
+ vector int vi3 = (vector int)(1, 2); // error
+ vector int vi4 = (vector int){1, 2}; // vi4 will be (1, 2, 0, 0).
+ vector int vi5 = (vector int)(1, 2, 3, 4);
+ float4 vf = (float4)((float2)(1.0f, 2.0f), (float2)(3.0f, 4.0f));
+
+Vector Operations
+-----------------
+
+The table below shows the support for each operation by vector extension. A
+dash indicates that an operation is not accepted according to a corresponding
+specification.
+
+============================== ====== ======= === ====
+ Opeator OpenCL AltiVec GCC NEON
+============================== ====== ======= === ====
+[] yes yes yes --
+unary operators +, -- yes yes yes --
+++, -- -- yes yes yes --
++,--,*,/,% yes yes yes --
+bitwise operators &,|,^,~ yes yes yes --
+>>,<< yes yes yes --
+!, &&, || no -- -- --
+==, !=, >, <, >=, <= yes yes -- --
+= yes yes yes yes
+:? yes -- -- --
+sizeof yes yes yes yes
+============================== ====== ======= === ====
+
+See also :ref:`langext-__builtin_shufflevector`.
+
+Messages on ``deprecated`` and ``unavailable`` Attributes
+=========================================================
+
+An optional string message can be added to the ``deprecated`` and
+``unavailable`` attributes. For example:
+
+.. code-block:: c++
+
+ void explode(void) __attribute__((deprecated("extremely unsafe, use 'combust' instead!!!")));
+
+If the deprecated or unavailable declaration is used, the message will be
+incorporated into the appropriate diagnostic:
+
+.. code-block:: c++
+
+ harmless.c:4:3: warning: 'explode' is deprecated: extremely unsafe, use 'combust' instead!!!
+ [-Wdeprecated-declarations]
+ explode();
+ ^
+
+Query for this feature with
+``__has_extension(attribute_deprecated_with_message)`` and
+``__has_extension(attribute_unavailable_with_message)``.
+
+Attributes on Enumerators
+=========================
+
+Clang allows attributes to be written on individual enumerators. This allows
+enumerators to be deprecated, made unavailable, etc. The attribute must appear
+after the enumerator name and before any initializer, like so:
+
+.. code-block:: c++
+
+ enum OperationMode {
+ OM_Invalid,
+ OM_Normal,
+ OM_Terrified __attribute__((deprecated)),
+ OM_AbortOnError __attribute__((deprecated)) = 4
+ };
+
+Attributes on the ``enum`` declaration do not apply to individual enumerators.
+
+Query for this feature with ``__has_extension(enumerator_attributes)``.
+
+'User-Specified' System Frameworks
+==================================
+
+Clang provides a mechanism by which frameworks can be built in such a way that
+they will always be treated as being "system frameworks", even if they are not
+present in a system framework directory. This can be useful to system
+framework developers who want to be able to test building other applications
+with development builds of their framework, including the manner in which the
+compiler changes warning behavior for system headers.
+
+Framework developers can opt-in to this mechanism by creating a
+"``.system_framework``" file at the top-level of their framework. That is, the
+framework should have contents like:
+
+.. code-block:: none
+
+ .../TestFramework.framework
+ .../TestFramework.framework/.system_framework
+ .../TestFramework.framework/Headers
+ .../TestFramework.framework/Headers/TestFramework.h
+ ...
+
+Clang will treat the presence of this file as an indicator that the framework
+should be treated as a system framework, regardless of how it was found in the
+framework search path. For consistency, we recommend that such files never be
+included in installed versions of the framework.
+
+Availability attribute
+======================
+
+Clang introduces the ``availability`` attribute, which can be placed on
+declarations to describe the lifecycle of that declaration relative to
+operating system versions. Consider the function declaration for a
+hypothetical function ``f``:
+
+.. code-block:: c++
+
+ void f(void) __attribute__((availability(macosx,introduced=10.4,deprecated=10.6,obsoleted=10.7)));
+
+The availability attribute states that ``f`` was introduced in Mac OS X 10.4,
+deprecated in Mac OS X 10.6, and obsoleted in Mac OS X 10.7. This information
+is used by Clang to determine when it is safe to use ``f``: for example, if
+Clang is instructed to compile code for Mac OS X 10.5, a call to ``f()``
+succeeds. If Clang is instructed to compile code for Mac OS X 10.6, the call
+succeeds but Clang emits a warning specifying that the function is deprecated.
+Finally, if Clang is instructed to compile code for Mac OS X 10.7, the call
+fails because ``f()`` is no longer available.
+
+The availability attribute is a comma-separated list starting with the
+platform name and then including clauses specifying important milestones in the
+declaration's lifetime (in any order) along with additional information. Those
+clauses can be:
+
+introduced=\ *version*
+ The first version in which this declaration was introduced.
+
+deprecated=\ *version*
+ The first version in which this declaration was deprecated, meaning that
+ users should migrate away from this API.
+
+obsoleted=\ *version*
+ The first version in which this declaration was obsoleted, meaning that it
+ was removed completely and can no longer be used.
+
+unavailable
+ This declaration is never available on this platform.
+
+message=\ *string-literal*
+ Additional message text that Clang will provide when emitting a warning or
+ error about use of a deprecated or obsoleted declaration. Useful to direct
+ users to replacement APIs.
+
+Multiple availability attributes can be placed on a declaration, which may
+correspond to different platforms. Only the availability attribute with the
+platform corresponding to the target platform will be used; any others will be
+ignored. If no availability attribute specifies availability for the current
+target platform, the availability attributes are ignored. Supported platforms
+are:
+
+``ios``
+ Apple's iOS operating system. The minimum deployment target is specified by
+ the ``-mios-version-min=*version*`` or ``-miphoneos-version-min=*version*``
+ command-line arguments.
+
+``macosx``
+ Apple's Mac OS X operating system. The minimum deployment target is
+ specified by the ``-mmacosx-version-min=*version*`` command-line argument.
+
+A declaration can be used even when deploying back to a platform version prior
+to when the declaration was introduced. When this happens, the declaration is
+`weakly linked
+<https://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPFrameworks/Concepts/WeakLinking.html>`_,
+as if the ``weak_import`` attribute were added to the declaration. A
+weakly-linked declaration may or may not be present a run-time, and a program
+can determine whether the declaration is present by checking whether the
+address of that declaration is non-NULL.
+
+If there are multiple declarations of the same entity, the availability
+attributes must either match on a per-platform basis or later
+declarations must not have availability attributes for that
+platform. For example:
+
+.. code-block:: c
+
+ void g(void) __attribute__((availability(macosx,introduced=10.4)));
+ void g(void) __attribute__((availability(macosx,introduced=10.4))); // okay, matches
+ void g(void) __attribute__((availability(ios,introduced=4.0))); // okay, adds a new platform
+ void g(void); // okay, inherits both macosx and ios availability from above.
+ void g(void) __attribute__((availability(macosx,introduced=10.5))); // error: mismatch
+
+When one method overrides another, the overriding method can be more widely available than the overridden method, e.g.,:
+
+.. code-block:: objc
+
+ @interface A
+ - (id)method __attribute__((availability(macosx,introduced=10.4)));
+ - (id)method2 __attribute__((availability(macosx,introduced=10.4)));
+ @end
+
+ @interface B : A
+ - (id)method __attribute__((availability(macosx,introduced=10.3))); // okay: method moved into base class later
+ - (id)method __attribute__((availability(macosx,introduced=10.5))); // error: this method was available via the base class in 10.4
+ @end
+
+Checks for Standard Language Features
+=====================================
+
+The ``__has_feature`` macro can be used to query if certain standard language
+features are enabled. The ``__has_extension`` macro can be used to query if
+language features are available as an extension when compiling for a standard
+which does not provide them. The features which can be tested are listed here.
+
+C++98
+-----
+
+The features listed below are part of the C++98 standard. These features are
+enabled by default when compiling C++ code.
+
+C++ exceptions
+^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_exceptions)`` to determine if C++ exceptions have been
+enabled. For example, compiling code with ``-fno-exceptions`` disables C++
+exceptions.
+
+C++ RTTI
+^^^^^^^^
+
+Use ``__has_feature(cxx_rtti)`` to determine if C++ RTTI has been enabled. For
+example, compiling code with ``-fno-rtti`` disables the use of RTTI.
+
+C++11
+-----
+
+The features listed below are part of the C++11 standard. As a result, all
+these features are enabled with the ``-std=c++11`` or ``-std=gnu++11`` option
+when compiling C++ code.
+
+C++11 SFINAE includes access control
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_access_control_sfinae)`` or
+``__has_extension(cxx_access_control_sfinae)`` to determine whether
+access-control errors (e.g., calling a private constructor) are considered to
+be template argument deduction errors (aka SFINAE errors), per `C++ DR1170
+<http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1170>`_.
+
+C++11 alias templates
+^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_alias_templates)`` or
+``__has_extension(cxx_alias_templates)`` to determine if support for C++11's
+alias declarations and alias templates is enabled.
+
+C++11 alignment specifiers
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_alignas)`` or ``__has_extension(cxx_alignas)`` to
+determine if support for alignment specifiers using ``alignas`` is enabled.
+
+C++11 attributes
+^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_attributes)`` or ``__has_extension(cxx_attributes)`` to
+determine if support for attribute parsing with C++11's square bracket notation
+is enabled.
+
+C++11 generalized constant expressions
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_constexpr)`` to determine if support for generalized
+constant expressions (e.g., ``constexpr``) is enabled.
+
+C++11 ``decltype()``
+^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_decltype)`` or ``__has_extension(cxx_decltype)`` to
+determine if support for the ``decltype()`` specifier is enabled. C++11's
+``decltype`` does not require type-completeness of a function call expression.
+Use ``__has_feature(cxx_decltype_incomplete_return_types)`` or
+``__has_extension(cxx_decltype_incomplete_return_types)`` to determine if
+support for this feature is enabled.
+
+C++11 default template arguments in function templates
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_default_function_template_args)`` or
+``__has_extension(cxx_default_function_template_args)`` to determine if support
+for default template arguments in function templates is enabled.
+
+C++11 ``default``\ ed functions
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_defaulted_functions)`` or
+``__has_extension(cxx_defaulted_functions)`` to determine if support for
+defaulted function definitions (with ``= default``) is enabled.
+
+C++11 delegating constructors
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_delegating_constructors)`` to determine if support for
+delegating constructors is enabled.
+
+C++11 ``deleted`` functions
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_deleted_functions)`` or
+``__has_extension(cxx_deleted_functions)`` to determine if support for deleted
+function definitions (with ``= delete``) is enabled.
+
+C++11 explicit conversion functions
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_explicit_conversions)`` to determine if support for
+``explicit`` conversion functions is enabled.
+
+C++11 generalized initializers
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_generalized_initializers)`` to determine if support for
+generalized initializers (using braced lists and ``std::initializer_list``) is
+enabled.
+
+C++11 implicit move constructors/assignment operators
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_implicit_moves)`` to determine if Clang will implicitly
+generate move constructors and move assignment operators where needed.
+
+C++11 inheriting constructors
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_inheriting_constructors)`` to determine if support for
+inheriting constructors is enabled. Clang does not currently implement this
+feature.
+
+C++11 inline namespaces
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_inline_namespaces)`` or
+``__has_extension(cxx_inline_namespaces)`` to determine if support for inline
+namespaces is enabled.
+
+C++11 lambdas
+^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_lambdas)`` or ``__has_extension(cxx_lambdas)`` to
+determine if support for lambdas is enabled.
+
+C++11 local and unnamed types as template arguments
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_local_type_template_args)`` or
+``__has_extension(cxx_local_type_template_args)`` to determine if support for
+local and unnamed types as template arguments is enabled.
+
+C++11 noexcept
+^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_noexcept)`` or ``__has_extension(cxx_noexcept)`` to
+determine if support for noexcept exception specifications is enabled.
+
+C++11 in-class non-static data member initialization
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_nonstatic_member_init)`` to determine whether in-class
+initialization of non-static data members is enabled.
+
+C++11 ``nullptr``
+^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_nullptr)`` or ``__has_extension(cxx_nullptr)`` to
+determine if support for ``nullptr`` is enabled.
+
+C++11 ``override control``
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_override_control)`` or
+``__has_extension(cxx_override_control)`` to determine if support for the
+override control keywords is enabled.
+
+C++11 reference-qualified functions
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_reference_qualified_functions)`` or
+``__has_extension(cxx_reference_qualified_functions)`` to determine if support
+for reference-qualified functions (e.g., member functions with ``&`` or ``&&``
+applied to ``*this``) is enabled.
+
+C++11 range-based ``for`` loop
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_range_for)`` or ``__has_extension(cxx_range_for)`` to
+determine if support for the range-based for loop is enabled.
+
+C++11 raw string literals
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_raw_string_literals)`` to determine if support for raw
+string literals (e.g., ``R"x(foo\bar)x"``) is enabled.
+
+C++11 rvalue references
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_rvalue_references)`` or
+``__has_extension(cxx_rvalue_references)`` to determine if support for rvalue
+references is enabled.
+
+C++11 ``static_assert()``
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_static_assert)`` or
+``__has_extension(cxx_static_assert)`` to determine if support for compile-time
+assertions using ``static_assert`` is enabled.
+
+C++11 type inference
+^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_auto_type)`` or ``__has_extension(cxx_auto_type)`` to
+determine C++11 type inference is supported using the ``auto`` specifier. If
+this is disabled, ``auto`` will instead be a storage class specifier, as in C
+or C++98.
+
+C++11 strongly typed enumerations
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_strong_enums)`` or
+``__has_extension(cxx_strong_enums)`` to determine if support for strongly
+typed, scoped enumerations is enabled.
+
+C++11 trailing return type
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_trailing_return)`` or
+``__has_extension(cxx_trailing_return)`` to determine if support for the
+alternate function declaration syntax with trailing return type is enabled.
+
+C++11 Unicode string literals
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_unicode_literals)`` to determine if support for Unicode
+string literals is enabled.
+
+C++11 unrestricted unions
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_unrestricted_unions)`` to determine if support for
+unrestricted unions is enabled.
+
+C++11 user-defined literals
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_user_literals)`` to determine if support for
+user-defined literals is enabled.
+
+C++11 variadic templates
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(cxx_variadic_templates)`` or
+``__has_extension(cxx_variadic_templates)`` to determine if support for
+variadic templates is enabled.
+
+C11
+---
+
+The features listed below are part of the C11 standard. As a result, all these
+features are enabled with the ``-std=c11`` or ``-std=gnu11`` option when
+compiling C code. Additionally, because these features are all
+backward-compatible, they are available as extensions in all language modes.
+
+C11 alignment specifiers
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(c_alignas)`` or ``__has_extension(c_alignas)`` to determine
+if support for alignment specifiers using ``_Alignas`` is enabled.
+
+C11 atomic operations
+^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(c_atomic)`` or ``__has_extension(c_atomic)`` to determine
+if support for atomic types using ``_Atomic`` is enabled. Clang also provides
+:ref:`a set of builtins <langext-__c11_atomic>` which can be used to implement
+the ``<stdatomic.h>`` operations on ``_Atomic`` types.
+
+C11 generic selections
+^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(c_generic_selections)`` or
+``__has_extension(c_generic_selections)`` to determine if support for generic
+selections is enabled.
+
+As an extension, the C11 generic selection expression is available in all
+languages supported by Clang. The syntax is the same as that given in the C11
+standard.
+
+In C, type compatibility is decided according to the rules given in the
+appropriate standard, but in C++, which lacks the type compatibility rules used
+in C, types are considered compatible only if they are equivalent.
+
+C11 ``_Static_assert()``
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+Use ``__has_feature(c_static_assert)`` or ``__has_extension(c_static_assert)``
+to determine if support for compile-time assertions using ``_Static_assert`` is
+enabled.
+
+Checks for Type Traits
+======================
+
+Clang supports the `GNU C++ type traits
+<http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html>`_ and a subset of the
+`Microsoft Visual C++ Type traits
+<http://msdn.microsoft.com/en-us/library/ms177194(v=VS.100).aspx>`_. For each
+supported type trait ``__X``, ``__has_extension(X)`` indicates the presence of
+the type trait. For example:
+
+.. code-block:: c++
+
+ #if __has_extension(is_convertible_to)
+ template<typename From, typename To>
+ struct is_convertible_to {
+ static const bool value = __is_convertible_to(From, To);
+ };
+ #else
+ // Emulate type trait
+ #endif
+
+The following type traits are supported by Clang:
+
+* ``__has_nothrow_assign`` (GNU, Microsoft)
+* ``__has_nothrow_copy`` (GNU, Microsoft)
+* ``__has_nothrow_constructor`` (GNU, Microsoft)
+* ``__has_trivial_assign`` (GNU, Microsoft)
+* ``__has_trivial_copy`` (GNU, Microsoft)
+* ``__has_trivial_constructor`` (GNU, Microsoft)
+* ``__has_trivial_destructor`` (GNU, Microsoft)
+* ``__has_virtual_destructor`` (GNU, Microsoft)
+* ``__is_abstract`` (GNU, Microsoft)
+* ``__is_base_of`` (GNU, Microsoft)
+* ``__is_class`` (GNU, Microsoft)
+* ``__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)
+* ``__is_literal(type)``: Determines whether the given type is a literal type
+* ``__is_final``: Determines whether the given type is declared with a
+ ``final`` class-virt-specifier.
+* ``__underlying_type(type)``: Retrieves the underlying type for a given
+ ``enum`` type. This trait is required to implement the C++11 standard
+ library.
+* ``__is_trivially_assignable(totype, fromtype)``: Determines whether a value
+ of type ``totype`` can be assigned to from a value of type ``fromtype`` such
+ that no non-trivial functions are called as part of that assignment. This
+ trait is required to implement the C++11 standard library.
+* ``__is_trivially_constructible(type, argtypes...)``: Determines whether a
+ value of type ``type`` can be direct-initialized with arguments of types
+ ``argtypes...`` such that no non-trivial functions are called as part of
+ that initialization. This trait is required to implement the C++11 standard
+ library.
+
+Blocks
+======
+
+The syntax and high level language feature description is in
+:doc:`BlockLanguageSpec<BlockLanguageSpec>`. Implementation and ABI details for
+the clang implementation are in :doc:`Block-ABI-Apple<Block-ABI-Apple>`.
+
+Query for this feature with ``__has_extension(blocks)``.
+
+Objective-C Features
+====================
+
+Related result types
+--------------------
+
+According to Cocoa conventions, Objective-C methods with certain names
+("``init``", "``alloc``", etc.) always return objects that are an instance of
+the receiving class's type. Such methods are said to have a "related result
+type", meaning that a message send to one of these methods will have the same
+static type as an instance of the receiver class. For example, given the
+following classes:
+
+.. code-block:: objc
+
+ @interface NSObject
+ + (id)alloc;
+ - (id)init;
+ @end
+
+ @interface NSArray : NSObject
+ @end
+
+and this common initialization pattern
+
+.. code-block:: objc
+
+ NSArray *array = [[NSArray alloc] init];
+
+the type of the expression ``[NSArray alloc]`` is ``NSArray*`` because
+``alloc`` implicitly has a related result type. Similarly, the type of the
+expression ``[[NSArray alloc] init]`` is ``NSArray*``, since ``init`` has a
+related result type and its receiver is known to have the type ``NSArray *``.
+If neither ``alloc`` nor ``init`` had a related result type, the expressions
+would have had type ``id``, as declared in the method signature.
+
+A method with a related result type can be declared by using the type
+``instancetype`` as its result type. ``instancetype`` is a contextual keyword
+that is only permitted in the result type of an Objective-C method, e.g.
+
+.. code-block:: objc
+
+ @interface A
+ + (instancetype)constructAnA;
+ @end
+
+The related result type can also be inferred for some methods. To determine
+whether a method has an inferred related result type, the first word in the
+camel-case selector (e.g., "``init``" in "``initWithObjects``") is considered,
+and the method will have a related result type if its return type is compatible
+with the type of its class and if:
+
+* the first word is "``alloc``" or "``new``", and the method is a class method,
+ or
+
+* the first word is "``autorelease``", "``init``", "``retain``", or "``self``",
+ and the method is an instance method.
+
+If a method with a related result type is overridden by a subclass method, the
+subclass method must also return a type that is compatible with the subclass
+type. For example:
+
+.. code-block:: objc
+
+ @interface NSString : NSObject
+ - (NSUnrelated *)init; // incorrect usage: NSUnrelated is not NSString or a superclass of NSString
+ @end
+
+Related result types only affect the type of a message send or property access
+via the given method. In all other respects, a method with a related result
+type is treated the same way as method that returns ``id``.
+
+Use ``__has_feature(objc_instancetype)`` to determine whether the
+``instancetype`` contextual keyword is available.
+
+Automatic reference counting
+----------------------------
+
+Clang provides support for :doc:`automated reference counting
+<AutomaticReferenceCounting>` in Objective-C, which eliminates the need
+for manual ``retain``/``release``/``autorelease`` message sends. There are two
+feature macros associated with automatic reference counting:
+``__has_feature(objc_arc)`` indicates the availability of automated reference
+counting in general, while ``__has_feature(objc_arc_weak)`` indicates that
+automated reference counting also includes support for ``__weak`` pointers to
+Objective-C objects.
+
+.. _objc-fixed-enum:
+
+Enumerations with a fixed underlying type
+-----------------------------------------
+
+Clang provides support for C++11 enumerations with a fixed underlying type
+within Objective-C. For example, one can write an enumeration type as:
+
+.. code-block:: c++
+
+ typedef enum : unsigned char { Red, Green, Blue } Color;
+
+This specifies that the underlying type, which is used to store the enumeration
+value, is ``unsigned char``.
+
+Use ``__has_feature(objc_fixed_enum)`` to determine whether support for fixed
+underlying types is available in Objective-C.
+
+Interoperability with C++11 lambdas
+-----------------------------------
+
+Clang provides interoperability between C++11 lambdas and blocks-based APIs, by
+permitting a lambda to be implicitly converted to a block pointer with the
+corresponding signature. For example, consider an API such as ``NSArray``'s
+array-sorting method:
+
+.. code-block:: objc
+
+ - (NSArray *)sortedArrayUsingComparator:(NSComparator)cmptr;
+
+``NSComparator`` is simply a typedef for the block pointer ``NSComparisonResult
+(^)(id, id)``, and parameters of this type are generally provided with block
+literals as arguments. However, one can also use a C++11 lambda so long as it
+provides the same signature (in this case, accepting two parameters of type
+``id`` and returning an ``NSComparisonResult``):
+
+.. code-block:: objc
+
+ NSArray *array = @[@"string 1", @"string 21", @"string 12", @"String 11",
+ @"String 02"];
+ const NSStringCompareOptions comparisonOptions
+ = NSCaseInsensitiveSearch | NSNumericSearch |
+ NSWidthInsensitiveSearch | NSForcedOrderingSearch;
+ NSLocale *currentLocale = [NSLocale currentLocale];
+ NSArray *sorted
+ = [array sortedArrayUsingComparator:[=](id s1, id s2) -> NSComparisonResult {
+ NSRange string1Range = NSMakeRange(0, [s1 length]);
+ return [s1 compare:s2 options:comparisonOptions
+ range:string1Range locale:currentLocale];
+ }];
+ NSLog(@"sorted: %@", sorted);
+
+This code relies on an implicit conversion from the type of the lambda
+expression (an unnamed, local class type called the *closure type*) to the
+corresponding block pointer type. The conversion itself is expressed by a
+conversion operator in that closure type that produces a block pointer with the
+same signature as the lambda itself, e.g.,
+
+.. code-block:: objc
+
+ operator NSComparisonResult (^)(id, id)() const;
+
+This conversion function returns a new block that simply forwards the two
+parameters to the lambda object (which it captures by copy), then returns the
+result. The returned block is first copied (with ``Block_copy``) and then
+autoreleased. As an optimization, if a lambda expression is immediately
+converted to a block pointer (as in the first example, above), then the block
+is not copied and autoreleased: rather, it is given the same lifetime as a
+block literal written at that point in the program, which avoids the overhead
+of copying a block to the heap in the common case.
+
+The conversion from a lambda to a block pointer is only available in
+Objective-C++, and not in C++ with blocks, due to its use of Objective-C memory
+management (autorelease).
+
+Object Literals and Subscripting
+--------------------------------
+
+Clang provides support for :doc:`Object Literals and Subscripting
+<ObjectiveCLiterals>` in Objective-C, which simplifies common Objective-C
+programming patterns, makes programs more concise, and improves the safety of
+container creation. There are several feature macros associated with object
+literals and subscripting: ``__has_feature(objc_array_literals)`` tests the
+availability of array literals; ``__has_feature(objc_dictionary_literals)``
+tests the availability of dictionary literals;
+``__has_feature(objc_subscripting)`` tests the availability of object
+subscripting.
+
+Objective-C Autosynthesis of Properties
+---------------------------------------
+
+Clang provides support for autosynthesis of declared properties. Using this
+feature, clang provides default synthesis of those properties not declared
+@dynamic and not having user provided backing getter and setter methods.
+``__has_feature(objc_default_synthesize_properties)`` checks for availability
+of this feature in version of clang being used.
+
+.. _langext-objc_method_family:
+
+The ``objc_method_family`` attribute
+------------------------------------
+
+Many methods in Objective-C have conventional meanings determined by their
+selectors. It is sometimes useful to be able to mark a method as having a
+particular conventional meaning despite not having the right selector, or as
+not having the conventional meaning that its selector would suggest. For these
+use cases, we provide an attribute to specifically describe the "method family"
+that a method belongs to.
+
+**Usage**: ``__attribute__((objc_method_family(X)))``, where ``X`` is one of
+``none``, ``alloc``, ``copy``, ``init``, ``mutableCopy``, or ``new``. This
+attribute can only be placed at the end of a method declaration:
+
+.. code-block:: objc
+
+ - (NSString *)initMyStringValue __attribute__((objc_method_family(none)));
+
+Users who do not wish to change the conventional meaning of a method, and who
+merely want to document its non-standard retain and release semantics, should
+use the :ref:`retaining behavior attributes <langext-objc-retain-release>`
+described below.
+
+Query for this feature with ``__has_attribute(objc_method_family)``.
+
+.. _langext-objc-retain-release:
+
+Objective-C retaining behavior attributes
+-----------------------------------------
+
+In Objective-C, functions and methods are generally assumed to follow the
+`Cocoa Memory Management
+<http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html>`_
+conventions for ownership of object arguments and
+return values. However, there are exceptions, and so Clang provides attributes
+to allow these exceptions to be documented. This are used by ARC and the
+`static analyzer <http://clang-analyzer.llvm.org>`_ Some exceptions may be
+better described using the :ref:`objc_method_family
+<langext-objc_method_family>` attribute instead.
+
+**Usage**: The ``ns_returns_retained``, ``ns_returns_not_retained``,
+``ns_returns_autoreleased``, ``cf_returns_retained``, and
+``cf_returns_not_retained`` attributes can be placed on methods and functions
+that return Objective-C or CoreFoundation objects. They are commonly placed at
+the end of a function prototype or method declaration:
+
+.. code-block:: objc
+
+ id foo() __attribute__((ns_returns_retained));
+
+ - (NSString *)bar:(int)x __attribute__((ns_returns_retained));
+
+The ``*_returns_retained`` attributes specify that the returned object has a +1
+retain count. The ``*_returns_not_retained`` attributes specify that the return
+object has a +0 retain count, even if the normal convention for its selector
+would be +1. ``ns_returns_autoreleased`` specifies that the returned object is
++0, but is guaranteed to live at least as long as the next flush of an
+autorelease pool.
+
+**Usage**: The ``ns_consumed`` and ``cf_consumed`` attributes can be placed on
+an parameter declaration; they specify that the argument is expected to have a
++1 retain count, which will be balanced in some way by the function or method.
+The ``ns_consumes_self`` attribute can only be placed on an Objective-C
+method; it specifies that the method expects its ``self`` parameter to have a
++1 retain count, which it will balance in some way.
+
+.. code-block:: objc
+
+ void foo(__attribute__((ns_consumed)) NSString *string);
+
+ - (void) bar __attribute__((ns_consumes_self));
+ - (void) baz:(id) __attribute__((ns_consumed)) x;
+
+Further examples of these attributes are available in the static analyzer's `list of annotations for analysis
+<http://clang-analyzer.llvm.org/annotations.html#cocoa_mem>`_.
+
+Query for these features with ``__has_attribute(ns_consumed)``,
+``__has_attribute(ns_returns_retained)``, etc.
+
+
+Function Overloading in C
+=========================
+
+Clang provides support for C++ function overloading in C. Function overloading
+in C is introduced using the ``overloadable`` attribute. For example, one
+might provide several overloaded versions of a ``tgsin`` function that invokes
+the appropriate standard function computing the sine of a value with ``float``,
+``double``, or ``long double`` precision:
+
+.. code-block:: c
+
+ #include <math.h>
+ float __attribute__((overloadable)) tgsin(float x) { return sinf(x); }
+ double __attribute__((overloadable)) tgsin(double x) { return sin(x); }
+ long double __attribute__((overloadable)) tgsin(long double x) { return sinl(x); }
+
+Given these declarations, one can call ``tgsin`` with a ``float`` value to
+receive a ``float`` result, with a ``double`` to receive a ``double`` result,
+etc. Function overloading in C follows the rules of C++ function overloading
+to pick the best overload given the call arguments, with a few C-specific
+semantics:
+
+* Conversion from ``float`` or ``double`` to ``long double`` is ranked as a
+ floating-point promotion (per C99) rather than as a floating-point conversion
+ (as in C++).
+
+* A conversion from a pointer of type ``T*`` to a pointer of type ``U*`` is
+ considered a pointer conversion (with conversion rank) if ``T`` and ``U`` are
+ compatible types.
+
+* A conversion from type ``T`` to a value of type ``U`` is permitted if ``T``
+ and ``U`` are compatible types. This conversion is given "conversion" rank.
+
+The declaration of ``overloadable`` functions is restricted to function
+declarations and definitions. Most importantly, if any function with a given
+name is given the ``overloadable`` attribute, then all function declarations
+and definitions with that name (and in that scope) must have the
+``overloadable`` attribute. This rule even applies to redeclarations of
+functions whose original declaration had the ``overloadable`` attribute, e.g.,
+
+.. code-block:: c
+
+ int f(int) __attribute__((overloadable));
+ float f(float); // error: declaration of "f" must have the "overloadable" attribute
+
+ int g(int) __attribute__((overloadable));
+ int g(int) { } // error: redeclaration of "g" must also have the "overloadable" attribute
+
+Functions marked ``overloadable`` must have prototypes. Therefore, the
+following code is ill-formed:
+
+.. code-block:: c
+
+ int h() __attribute__((overloadable)); // error: h does not have a prototype
+
+However, ``overloadable`` functions are allowed to use a ellipsis even if there
+are no named parameters (as is permitted in C++). This feature is particularly
+useful when combined with the ``unavailable`` attribute:
+
+.. code-block:: c++
+
+ void honeypot(...) __attribute__((overloadable, unavailable)); // calling me is an error
+
+Functions declared with the ``overloadable`` attribute have their names mangled
+according to the same rules as C++ function names. For example, the three
+``tgsin`` functions in our motivating example get the mangled names
+``_Z5tgsinf``, ``_Z5tgsind``, and ``_Z5tgsine``, respectively. There are two
+caveats to this use of name mangling:
+
+* Future versions of Clang may change the name mangling of functions overloaded
+ in C, so you should not depend on an specific mangling. To be completely
+ safe, we strongly urge the use of ``static inline`` with ``overloadable``
+ functions.
+
+* The ``overloadable`` attribute has almost no meaning when used in C++,
+ because names will already be mangled and functions are already overloadable.
+ However, when an ``overloadable`` function occurs within an ``extern "C"``
+ linkage specification, it's name *will* be mangled in the same way as it
+ would in C.
+
+Query for this feature with ``__has_extension(attribute_overloadable)``.
+
+Initializer lists for complex numbers in C
+==========================================
+
+clang supports an extension which allows the following in C:
+
+.. code-block:: c++
+
+ #include <math.h>
+ #include <complex.h>
+ complex float x = { 1.0f, INFINITY }; // Init to (1, Inf)
+
+This construct is useful because there is no way to separately initialize the
+real and imaginary parts of a complex variable in standard C, given that clang
+does not support ``_Imaginary``. (Clang also supports the ``__real__`` and
+``__imag__`` extensions from gcc, which help in some cases, but are not usable
+in static initializers.)
+
+Note that this extension does not allow eliding the braces; the meaning of the
+following two lines is different:
+
+.. code-block:: c++
+
+ complex float x[] = { { 1.0f, 1.0f } }; // [0] = (1, 1)
+ complex float x[] = { 1.0f, 1.0f }; // [0] = (1, 0), [1] = (1, 0)
+
+This extension also works in C++ mode, as far as that goes, but does not apply
+to the C++ ``std::complex``. (In C++11, list initialization allows the same
+syntax to be used with ``std::complex`` with the same meaning.)
+
+Builtin Functions
+=================
+
+Clang supports a number of builtin library functions with the same syntax as
+GCC, including things like ``__builtin_nan``, ``__builtin_constant_p``,
+``__builtin_choose_expr``, ``__builtin_types_compatible_p``,
+``__sync_fetch_and_add``, etc. In addition to the GCC builtins, Clang supports
+a number of builtins that GCC does not, which are listed here.
+
+Please note that Clang does not and will not support all of the GCC builtins
+for vector operations. Instead of using builtins, you should use the functions
+defined in target-specific header files like ``<xmmintrin.h>``, which define
+portable wrappers for these. Many of the Clang versions of these functions are
+implemented directly in terms of :ref:`extended vector support
+<langext-vectors>` instead of builtins, in order to reduce the number of
+builtins that we need to implement.
+
+``__builtin_readcyclecounter``
+------------------------------
+
+``__builtin_readcyclecounter`` is used to access the cycle counter register (or
+a similar low-latency, high-accuracy clock) on those targets that support it.
+
+**Syntax**:
+
+.. code-block:: c++
+
+ __builtin_readcyclecounter()
+
+**Example of Use**:
+
+.. code-block:: c++
+
+ unsigned long long t0 = __builtin_readcyclecounter();
+ do_something();
+ unsigned long long t1 = __builtin_readcyclecounter();
+ unsigned long long cycles_to_do_something = t1 - t0; // assuming no overflow
+
+**Description**:
+
+The ``__builtin_readcyclecounter()`` builtin returns the cycle counter value,
+which may be either global or process/thread-specific depending on the target.
+As the backing counters often overflow quickly (on the order of seconds) this
+should only be used for timing small intervals. When not supported by the
+target, the return value is always zero. This builtin takes no arguments and
+produces an unsigned long long result.
+
+Query for this feature with ``__has_builtin(__builtin_readcyclecounter)``.
+
+.. _langext-__builtin_shufflevector:
+
+``__builtin_shufflevector``
+---------------------------
+
+``__builtin_shufflevector`` is used to express generic vector
+permutation/shuffle/swizzle operations. This builtin is also very important
+for the implementation of various target-specific header files like
+``<xmmintrin.h>``.
+
+**Syntax**:
+
+.. code-block:: c++
+
+ __builtin_shufflevector(vec1, vec2, index1, index2, ...)
+
+**Examples**:
+
+.. code-block:: c++
+
+ // Identity operation - return 4-element vector V1.
+ __builtin_shufflevector(V1, V1, 0, 1, 2, 3)
+
+ // "Splat" element 0 of V1 into a 4-element result.
+ __builtin_shufflevector(V1, V1, 0, 0, 0, 0)
+
+ // Reverse 4-element vector V1.
+ __builtin_shufflevector(V1, V1, 3, 2, 1, 0)
+
+ // Concatenate every other element of 4-element vectors V1 and V2.
+ __builtin_shufflevector(V1, V2, 0, 2, 4, 6)
+
+ // Concatenate every other element of 8-element vectors V1 and V2.
+ __builtin_shufflevector(V1, V2, 0, 2, 4, 6, 8, 10, 12, 14)
+
+**Description**:
+
+The first two arguments to ``__builtin_shufflevector`` are vectors that have
+the same element type. The remaining arguments are a list of integers that
+specify the elements indices of the first two vectors that should be extracted
+and returned in a new vector. These element indices are numbered sequentially
+starting with the first vector, continuing into the second vector. Thus, if
+``vec1`` is a 4-element vector, index 5 would refer to the second element of
+``vec2``.
+
+The result of ``__builtin_shufflevector`` is a vector with the same element
+type as ``vec1``/``vec2`` but that has an element count equal to the number of
+indices specified.
+
+Query for this feature with ``__has_builtin(__builtin_shufflevector)``.
+
+``__builtin_unreachable``
+-------------------------
+
+``__builtin_unreachable`` is used to indicate that a specific point in the
+program cannot be reached, even if the compiler might otherwise think it can.
+This is useful to improve optimization and eliminates certain warnings. For
+example, without the ``__builtin_unreachable`` in the example below, the
+compiler assumes that the inline asm can fall through and prints a "function
+declared '``noreturn``' should not return" warning.
+
+**Syntax**:
+
+.. code-block:: c++
+
+ __builtin_unreachable()
+
+**Example of use**:
+
+.. code-block:: c++
+
+ void myabort(void) __attribute__((noreturn));
+ void myabort(void) {
+ asm("int3");
+ __builtin_unreachable();
+ }
+
+**Description**:
+
+The ``__builtin_unreachable()`` builtin has completely undefined behavior.
+Since it has undefined behavior, it is a statement that it is never reached and
+the optimizer can take advantage of this to produce better code. This builtin
+takes no arguments and produces a void result.
+
+Query for this feature with ``__has_builtin(__builtin_unreachable)``.
+
+``__sync_swap``
+---------------
+
+``__sync_swap`` is used to atomically swap integers or pointers in memory.
+
+**Syntax**:
+
+.. code-block:: c++
+
+ type __sync_swap(type *ptr, type value, ...)
+
+**Example of Use**:
+
+.. code-block:: c++
+
+ int old_value = __sync_swap(&value, new_value);
+
+**Description**:
+
+The ``__sync_swap()`` builtin extends the existing ``__sync_*()`` family of
+atomic intrinsics to allow code to atomically swap the current value with the
+new value. More importantly, it helps developers write more efficient and
+correct code by avoiding expensive loops around
+``__sync_bool_compare_and_swap()`` or relying on the platform specific
+implementation details of ``__sync_lock_test_and_set()``. The
+``__sync_swap()`` builtin is a full barrier.
+
+Multiprecision Arithmetic Builtins
+----------------------------------
+
+Clang provides a set of builtins which expose multiprecision arithmetic in a
+manner amenable to C. They all have the following form:
+
+.. code-block:: c
+
+ unsigned x = ..., y = ..., carryin = ..., carryout;
+ unsigned sum = __builtin_addc(x, y, carryin, &carryout);
+
+Thus one can form a multiprecision addition chain in the following manner:
+
+.. code-block:: c
+
+ unsigned *x, *y, *z, carryin=0, carryout;
+ z[0] = __builtin_addc(x[0], y[0], carryin, &carryout);
+ carryin = carryout;
+ z[1] = __builtin_addc(x[1], y[1], carryin, &carryout);
+ carryin = carryout;
+ z[2] = __builtin_addc(x[2], y[2], carryin, &carryout);
+ carryin = carryout;
+ z[3] = __builtin_addc(x[3], y[3], carryin, &carryout);
+
+The complete list of builtins are:
+
+.. code-block:: c
+
+ unsigned short __builtin_addcs (unsigned short x, unsigned short y, unsigned short carryin, unsigned short *carryout);
+ unsigned __builtin_addc (unsigned x, unsigned y, unsigned carryin, unsigned *carryout);
+ unsigned long __builtin_addcl (unsigned long x, unsigned long y, unsigned long carryin, unsigned long *carryout);
+ unsigned long long __builtin_addcll(unsigned long long x, unsigned long long y, unsigned long long carryin, unsigned long long *carryout);
+ unsigned short __builtin_subcs (unsigned short x, unsigned short y, unsigned short carryin, unsigned short *carryout);
+ unsigned __builtin_subc (unsigned x, unsigned y, unsigned carryin, unsigned *carryout);
+ unsigned long __builtin_subcl (unsigned long x, unsigned long y, unsigned long carryin, unsigned long *carryout);
+ unsigned long long __builtin_subcll(unsigned long long x, unsigned long long y, unsigned long long carryin, unsigned long long *carryout);
+
+.. _langext-__c11_atomic:
+
+__c11_atomic builtins
+---------------------
+
+Clang provides a set of builtins which are intended to be used to implement
+C11's ``<stdatomic.h>`` header. These builtins provide the semantics of the
+``_explicit`` form of the corresponding C11 operation, and are named with a
+``__c11_`` prefix. The supported operations are:
+
+* ``__c11_atomic_init``
+* ``__c11_atomic_thread_fence``
+* ``__c11_atomic_signal_fence``
+* ``__c11_atomic_is_lock_free``
+* ``__c11_atomic_store``
+* ``__c11_atomic_load``
+* ``__c11_atomic_exchange``
+* ``__c11_atomic_compare_exchange_strong``
+* ``__c11_atomic_compare_exchange_weak``
+* ``__c11_atomic_fetch_add``
+* ``__c11_atomic_fetch_sub``
+* ``__c11_atomic_fetch_and``
+* ``__c11_atomic_fetch_or``
+* ``__c11_atomic_fetch_xor``
+
+Non-standard C++11 Attributes
+=============================
+
+Clang's non-standard C++11 attributes live in the ``clang`` attribute
+namespace.
+
+The ``clang::fallthrough`` attribute
+------------------------------------
+
+The ``clang::fallthrough`` attribute is used along with the
+``-Wimplicit-fallthrough`` argument to annotate intentional fall-through
+between switch labels. It can only be applied to a null statement placed at a
+point of execution between any statement and the next switch label. It is
+common to mark these places with a specific comment, but this attribute is
+meant to replace comments with a more strict annotation, which can be checked
+by the compiler. This attribute doesn't change semantics of the code and can
+be used wherever an intended fall-through occurs. It is designed to mimic
+control-flow statements like ``break;``, so it can be placed in most places
+where ``break;`` can, but only if there are no statements on the execution path
+between it and the next switch label.
+
+Here is an example:
+
+.. code-block:: c++
+
+ // compile with -Wimplicit-fallthrough
+ switch (n) {
+ case 22:
+ case 33: // no warning: no statements between case labels
+ f();
+ case 44: // warning: unannotated fall-through
+ g();
+ [[clang::fallthrough]];
+ case 55: // no warning
+ if (x) {
+ h();
+ break;
+ }
+ else {
+ i();
+ [[clang::fallthrough]];
+ }
+ case 66: // no warning
+ p();
+ [[clang::fallthrough]]; // warning: fallthrough annotation does not
+ // directly precede case label
+ q();
+ case 77: // warning: unannotated fall-through
+ r();
+ }
+
+``gnu::`` attributes
+--------------------
+
+Clang also supports GCC's ``gnu`` attribute namespace. All GCC attributes which
+are accepted with the ``__attribute__((foo))`` syntax are also accepted as
+``[[gnu::foo]]``. This only extends to attributes which are specified by GCC
+(see the list of `GCC function attributes
+<http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`_, `GCC variable
+attributes <http://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html>`_, and
+`GCC type attributes
+<http://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html>`_. As with the GCC
+implementation, these attributes must appertain to the *declarator-id* in a
+declaration, which means they must go either at the start of the declaration or
+immediately after the name being declared.
+
+For example, this applies the GNU ``unused`` attribute to ``a`` and ``f``, and
+also applies the GNU ``noreturn`` attribute to ``f``.
+
+.. code-block:: c++
+
+ [[gnu::unused]] int a, f [[gnu::noreturn]] ();
+
+Target-Specific Extensions
+==========================
+
+Clang supports some language features conditionally on some targets.
+
+X86/X86-64 Language Extensions
+------------------------------
+
+The X86 backend has these language extensions:
+
+Memory references off the GS segment
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Annotating a pointer with address space #256 causes it to be code generated
+relative to the X86 GS segment register, and address space #257 causes it to be
+relative to the X86 FS segment. Note that this is a very very low-level
+feature that should only be used if you know what you're doing (for example in
+an OS kernel).
+
+Here is an example:
+
+.. code-block:: c++
+
+ #define GS_RELATIVE __attribute__((address_space(256)))
+ int foo(int GS_RELATIVE *P) {
+ return *P;
+ }
+
+Which compiles to (on X86-32):
+
+.. code-block:: gas
+
+ _foo:
+ movl 4(%esp), %eax
+ movl %gs:(%eax), %eax
+ ret
+
+Extensions for Static Analysis
+==============================
+
+Clang supports additional attributes that are useful for documenting program
+invariants and rules for static analysis tools, such as the `Clang Static
+Analyzer <http://clang-analyzer.llvm.org/>`_. These attributes are documented
+in the analyzer's `list of source-level annotations
+<http://clang-analyzer.llvm.org/annotations.html>`_.
+
+
+Extensions for Dynamic Analysis
+===============================
+
+.. _langext-address_sanitizer:
+
+AddressSanitizer
+----------------
+
+Use ``__has_feature(address_sanitizer)`` to check if the code is being built
+with :doc:`AddressSanitizer`.
+
+Use ``__attribute__((no_sanitize_address))``
+on a function declaration
+to specify that address safety instrumentation (e.g. AddressSanitizer) should
+not be applied to that function.
+
+.. _langext-thread_sanitizer:
+
+ThreadSanitizer
+----------------
+
+Use ``__has_feature(thread_sanitizer)`` to check if the code is being built
+with :doc:`ThreadSanitizer`.
+
+Use ``__attribute__((no_sanitize_thread))`` on a function declaration
+to specify that checks for data races on plain (non-atomic) memory accesses
+should not be inserted by ThreadSanitizer.
+The function may still be instrumented by the tool
+to avoid false positives in other places.
+
+.. _langext-memory_sanitizer:
+
+MemorySanitizer
+----------------
+Use ``__has_feature(memory_sanitizer)`` to check if the code is being built
+with :doc:`MemorySanitizer`.
+
+Use ``__attribute__((no_sanitize_memory))`` on a function declaration
+to specify that checks for uninitialized memory should not be inserted
+(e.g. by MemorySanitizer). The function may still be instrumented by the tool
+to avoid false positives in other places.
+
+
+Thread-Safety Annotation Checking
+=================================
+
+Clang supports additional attributes for checking basic locking policies in
+multithreaded programs. Clang currently parses the following list of
+attributes, although **the implementation for these annotations is currently in
+development.** For more details, see the `GCC implementation
+<http://gcc.gnu.org/wiki/ThreadSafetyAnnotation>`_.
+
+``no_thread_safety_analysis``
+-----------------------------
+
+Use ``__attribute__((no_thread_safety_analysis))`` on a function declaration to
+specify that the thread safety analysis should not be run on that function.
+This attribute provides an escape hatch (e.g. for situations when it is
+difficult to annotate the locking policy).
+
+``lockable``
+------------
+
+Use ``__attribute__((lockable))`` on a class definition to specify that it has
+a lockable type (e.g. a Mutex class). This annotation is primarily used to
+check consistency.
+
+``scoped_lockable``
+-------------------
+
+Use ``__attribute__((scoped_lockable))`` on a class definition to specify that
+it has a "scoped" lockable type. Objects of this type will acquire the lock
+upon construction and release it upon going out of scope. This annotation is
+primarily used to check consistency.
+
+``guarded_var``
+---------------
+
+Use ``__attribute__((guarded_var))`` on a variable declaration to specify that
+the variable must be accessed while holding some lock.
+
+``pt_guarded_var``
+------------------
+
+Use ``__attribute__((pt_guarded_var))`` on a pointer declaration to specify
+that the pointer must be dereferenced while holding some lock.
+
+``guarded_by(l)``
+-----------------
+
+Use ``__attribute__((guarded_by(l)))`` on a variable declaration to specify
+that the variable must be accessed while holding lock ``l``.
+
+``pt_guarded_by(l)``
+--------------------
+
+Use ``__attribute__((pt_guarded_by(l)))`` on a pointer declaration to specify
+that the pointer must be dereferenced while holding lock ``l``.
+
+``acquired_before(...)``
+------------------------
+
+Use ``__attribute__((acquired_before(...)))`` on a declaration of a lockable
+variable to specify that the lock must be acquired before all attribute
+arguments. Arguments must be lockable type, and there must be at least one
+argument.
+
+``acquired_after(...)``
+-----------------------
+
+Use ``__attribute__((acquired_after(...)))`` on a declaration of a lockable
+variable to specify that the lock must be acquired after all attribute
+arguments. Arguments must be lockable type, and there must be at least one
+argument.
+
+``exclusive_lock_function(...)``
+--------------------------------
+
+Use ``__attribute__((exclusive_lock_function(...)))`` on a function declaration
+to specify that the function acquires all listed locks exclusively. This
+attribute takes zero or more arguments: either of lockable type or integers
+indexing into function parameters of lockable type. If no arguments are given,
+the acquired lock is implicitly ``this`` of the enclosing object.
+
+``shared_lock_function(...)``
+-----------------------------
+
+Use ``__attribute__((shared_lock_function(...)))`` on a function declaration to
+specify that the function acquires all listed locks, although the locks may be
+shared (e.g. read locks). This attribute takes zero or more arguments: either
+of lockable type or integers indexing into function parameters of lockable
+type. If no arguments are given, the acquired lock is implicitly ``this`` of
+the enclosing object.
+
+``exclusive_trylock_function(...)``
+-----------------------------------
+
+Use ``__attribute__((exclusive_lock_function(...)))`` on a function declaration
+to specify that the function will try (without blocking) to acquire all listed
+locks exclusively. This attribute takes one or more arguments. The first
+argument is an integer or boolean value specifying the return value of a
+successful lock acquisition. The remaining arugments are either of lockable
+type or integers indexing into function parameters of lockable type. If only
+one argument is given, the acquired lock is implicitly ``this`` of the
+enclosing object.
+
+``shared_trylock_function(...)``
+--------------------------------
+
+Use ``__attribute__((shared_lock_function(...)))`` on a function declaration to
+specify that the function will try (without blocking) to acquire all listed
+locks, although the locks may be shared (e.g. read locks). This attribute
+takes one or more arguments. The first argument is an integer or boolean value
+specifying the return value of a successful lock acquisition. The remaining
+arugments are either of lockable type or integers indexing into function
+parameters of lockable type. If only one argument is given, the acquired lock
+is implicitly ``this`` of the enclosing object.
+
+``unlock_function(...)``
+------------------------
+
+Use ``__attribute__((unlock_function(...)))`` on a function declaration to
+specify that the function release all listed locks. This attribute takes zero
+or more arguments: either of lockable type or integers indexing into function
+parameters of lockable type. If no arguments are given, the acquired lock is
+implicitly ``this`` of the enclosing object.
+
+``lock_returned(l)``
+--------------------
+
+Use ``__attribute__((lock_returned(l)))`` on a function declaration to specify
+that the function returns lock ``l`` (``l`` must be of lockable type). This
+annotation is used to aid in resolving lock expressions.
+
+``locks_excluded(...)``
+-----------------------
+
+Use ``__attribute__((locks_excluded(...)))`` on a function declaration to
+specify that the function must not be called with the listed locks. Arguments
+must be lockable type, and there must be at least one argument.
+
+``exclusive_locks_required(...)``
+---------------------------------
+
+Use ``__attribute__((exclusive_locks_required(...)))`` on a function
+declaration to specify that the function must be called while holding the
+listed exclusive locks. Arguments must be lockable type, and there must be at
+least one argument.
+
+``shared_locks_required(...)``
+------------------------------
+
+Use ``__attribute__((shared_locks_required(...)))`` on a function declaration
+to specify that the function must be called while holding the listed shared
+locks. Arguments must be lockable type, and there must be at least one
+argument.
+
+Type Safety Checking
+====================
+
+Clang supports additional attributes to enable checking type safety properties
+that can't be enforced by C type system. Usecases include:
+
+* MPI library implementations, where these attributes enable checking that
+ buffer type matches the passed ``MPI_Datatype``;
+* for HDF5 library there is a similar usecase as MPI;
+* checking types of variadic functions' arguments for functions like
+ ``fcntl()`` and ``ioctl()``.
+
+You can detect support for these attributes with ``__has_attribute()``. For
+example:
+
+.. code-block:: c++
+
+ #if defined(__has_attribute)
+ # if __has_attribute(argument_with_type_tag) && \
+ __has_attribute(pointer_with_type_tag) && \
+ __has_attribute(type_tag_for_datatype)
+ # define ATTR_MPI_PWT(buffer_idx, type_idx) __attribute__((pointer_with_type_tag(mpi,buffer_idx,type_idx)))
+ /* ... other macros ... */
+ # endif
+ #endif
+
+ #if !defined(ATTR_MPI_PWT)
+ # define ATTR_MPI_PWT(buffer_idx, type_idx)
+ #endif
+
+ int MPI_Send(void *buf, int count, MPI_Datatype datatype /*, other args omitted */)
+ ATTR_MPI_PWT(1,3);
+
+``argument_with_type_tag(...)``
+-------------------------------
+
+Use ``__attribute__((argument_with_type_tag(arg_kind, arg_idx,
+type_tag_idx)))`` on a function declaration to specify that the function
+accepts a type tag that determines the type of some other argument.
+``arg_kind`` is an identifier that should be used when annotating all
+applicable type tags.
+
+This attribute is primarily useful for checking arguments of variadic functions
+(``pointer_with_type_tag`` can be used in most of non-variadic cases).
+
+For example:
+
+.. code-block:: c++
+
+ int fcntl(int fd, int cmd, ...)
+ __attribute__(( argument_with_type_tag(fcntl,3,2) ));
+
+``pointer_with_type_tag(...)``
+------------------------------
+
+Use ``__attribute__((pointer_with_type_tag(ptr_kind, ptr_idx, type_tag_idx)))``
+on a function declaration to specify that the function accepts a type tag that
+determines the pointee type of some other pointer argument.
+
+For example:
+
+.. code-block:: c++
+
+ int MPI_Send(void *buf, int count, MPI_Datatype datatype /*, other args omitted */)
+ __attribute__(( pointer_with_type_tag(mpi,1,3) ));
+
+``type_tag_for_datatype(...)``
+------------------------------
+
+Clang supports annotating type tags of two forms.
+
+* **Type tag that is an expression containing a reference to some declared
+ identifier.** Use ``__attribute__((type_tag_for_datatype(kind, type)))`` on a
+ declaration with that identifier:
+
+ .. code-block:: c++
+
+ extern struct mpi_datatype mpi_datatype_int
+ __attribute__(( type_tag_for_datatype(mpi,int) ));
+ #define MPI_INT ((MPI_Datatype) &mpi_datatype_int)
+
+* **Type tag that is an integral literal.** Introduce a ``static const``
+ variable with a corresponding initializer value and attach
+ ``__attribute__((type_tag_for_datatype(kind, type)))`` on that declaration,
+ for example:
+
+ .. code-block:: c++
+
+ #define MPI_INT ((MPI_Datatype) 42)
+ static const MPI_Datatype mpi_datatype_int
+ __attribute__(( type_tag_for_datatype(mpi,int) )) = 42
+
+The attribute also accepts an optional third argument that determines how the
+expression is compared to the type tag. There are two supported flags:
+
+* ``layout_compatible`` will cause types to be compared according to
+ layout-compatibility rules (C++11 [class.mem] p 17, 18). This is
+ implemented to support annotating types like ``MPI_DOUBLE_INT``.
+
+ For example:
+
+ .. code-block:: c++
+
+ /* In mpi.h */
+ struct internal_mpi_double_int { double d; int i; };
+ extern struct mpi_datatype mpi_datatype_double_int
+ __attribute__(( type_tag_for_datatype(mpi, struct internal_mpi_double_int, layout_compatible) ));
+
+ #define MPI_DOUBLE_INT ((MPI_Datatype) &mpi_datatype_double_int)
+
+ /* In user code */
+ struct my_pair { double a; int b; };
+ struct my_pair *buffer;
+ MPI_Send(buffer, 1, MPI_DOUBLE_INT /*, ... */); // no warning
+
+ struct my_int_pair { int a; int b; }
+ struct my_int_pair *buffer2;
+ MPI_Send(buffer2, 1, MPI_DOUBLE_INT /*, ... */); // warning: actual buffer element
+ // type 'struct my_int_pair'
+ // doesn't match specified MPI_Datatype
+
+* ``must_be_null`` specifies that the expression should be a null pointer
+ constant, for example:
+
+ .. code-block:: c++
+
+ /* In mpi.h */
+ extern struct mpi_datatype mpi_datatype_null
+ __attribute__(( type_tag_for_datatype(mpi, void, must_be_null) ));
+
+ #define MPI_DATATYPE_NULL ((MPI_Datatype) &mpi_datatype_null)
+
+ /* In user code */
+ MPI_Send(buffer, 1, MPI_DATATYPE_NULL /*, ... */); // warning: MPI_DATATYPE_NULL
+ // was specified but buffer
+ // is not a null pointer
+
+Format String Checking
+======================
+
+Clang supports the ``format`` attribute, which indicates that the function
+accepts a ``printf`` or ``scanf``-like format string and corresponding
+arguments or a ``va_list`` that contains these arguments.
+
+Please see `GCC documentation about format attribute
+<http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`_ to find details
+about attribute syntax.
+
+Clang implements two kinds of checks with this attribute.
+
+#. Clang checks that the function with the ``format`` attribute is called with
+ a format string that uses format specifiers that are allowed, and that
+ arguments match the format string. This is the ``-Wformat`` warning, it is
+ on by default.
+
+#. Clang checks that the format string argument is a literal string. This is
+ the ``-Wformat-nonliteral`` warning, it is off by default.
+
+ Clang implements this mostly the same way as GCC, but there is a difference
+ for functions that accept a ``va_list`` argument (for example, ``vprintf``).
+ GCC does not emit ``-Wformat-nonliteral`` warning for calls to such
+ fuctions. Clang does not warn if the format string comes from a function
+ parameter, where the function is annotated with a compatible attribute,
+ otherwise it warns. For example:
+
+ .. code-block:: c
+
+ __attribute__((__format__ (__scanf__, 1, 3)))
+ void foo(const char* s, char *buf, ...) {
+ va_list ap;
+ va_start(ap, buf);
+
+ vprintf(s, ap); // warning: format string is not a string literal
+ }
+
+ In this case we warn because ``s`` contains a format string for a
+ ``scanf``-like function, but it is passed to a ``printf``-like function.
+
+ If the attribute is removed, clang still warns, because the format string is
+ not a string literal.
+
+ Another example:
+
+ .. code-block:: c
+
+ __attribute__((__format__ (__printf__, 1, 3)))
+ void foo(const char* s, char *buf, ...) {
+ va_list ap;
+ va_start(ap, buf);
+
+ vprintf(s, ap); // warning
+ }
+
+ In this case Clang does not warn because the format string ``s`` and
+ the corresponding arguments are annotated. If the arguments are
+ incorrect, the caller of ``foo`` will receive a warning.
diff --git a/docs/LibASTMatchers.html b/docs/LibASTMatchers.html
deleted file mode 100644
index 8142c19..0000000
--- a/docs/LibASTMatchers.html
+++ /dev/null
@@ -1,130 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
-<title>Matching the Clang AST</title>
-<link type="text/css" rel="stylesheet" href="../menu.css" />
-<link type="text/css" rel="stylesheet" href="../content.css" />
-</head>
-<body>
-
-<!--#include virtual="../menu.html.incl"-->
-
-<div id="content">
-
-<h1>Matching the Clang AST</h1>
-<p>This document explains how to use Clang's LibASTMatchers to match interesting
-nodes of the AST and execute code that uses the matched nodes. Combined with
-<a href="LibTooling.html">LibTooling</a>, LibASTMatchers helps to write
-code-to-code transformation tools or query tools.</p>
-
-<p>We assume basic knowledge about the Clang AST. See the
-<a href="IntroductionToTheClangAST.html">Introduction to the Clang AST</a> if
-you want to learn more about how the AST is structured.</p>
-
-<!-- FIXME: create tutorial and link to the tutorial -->
-
-<!-- ======================================================================= -->
-<h2 id="intro">Introduction</h2>
-<!-- ======================================================================= -->
-
-<p>LibASTMatchers provides a domain specific language to create predicates on Clang's
-AST. This DSL is written in and can be used from C++, allowing users to write
-a single program to both match AST nodes and access the node's C++ interface
-to extract attributes, source locations, or any other information provided on
-the AST level.</p>
-
-<p>AST matchers are predicates on nodes in the AST. Matchers are created
-by calling creator functions that allow building up a tree of matchers, where
-inner matchers are used to make the match more specific.</p>
-
-</p>For example, to create a matcher that matches all class or union declarations
-in the AST of a translation unit, you can call
-<a href="LibASTMatchersReference.html#recordDecl0Anchor">recordDecl()</a>.
-To narrow the match down, for example to find all class or union declarations with the name "Foo",
-insert a <a href="LibASTMatchersReference.html#hasName0Anchor">hasName</a>
-matcher: the call recordDecl(hasName("Foo")) returns a matcher that matches classes
-or unions that are named "Foo", in any namespace. By default, matchers that accept
-multiple inner matchers use an implicit <a href="LibASTMatchersReference.html#allOf0Anchor">allOf()</a>.
-This allows further narrowing down the match, for example to match all classes
-that are derived from "Bar": recordDecl(hasName("Foo"), isDerivedFrom("Bar")).</p>
-
-<!-- ======================================================================= -->
-<h2 id="writing">How to create a matcher</h2>
-<!-- ======================================================================= -->
-
-<p>With more than a thousand classes in the Clang AST, one can quickly get lost
-when trying to figure out how to create a matcher for a specific pattern. This
-section will teach you how to use a rigorous step-by-step pattern to build the
-matcher you are interested in. Note that there will always be matchers missing
-for some part of the AST. See the section about <a href="#writing">how to write
-your own AST matchers</a> later in this document.</p>
-
-<p>The precondition to using the matchers is to understand how the AST
-for what you want to match looks like. The <a href="IntroductionToTheClangAST.html">Introduction to the Clang AST</a>
-teaches you how to dump a translation unit's AST into a human readable format.</p>
-
-<!-- FIXME: Introduce link to ASTMatchersTutorial.html -->
-<!-- FIXME: Introduce link to ASTMatchersCookbook.html -->
-
-<p>In general, the strategy to create the right matchers is:</p>
-<ol>
-<li>Find the outermost class in Clang's AST you want to match.</li>
-<li>Look at the <a href="LibASTMatchersReference.html">AST Matcher Reference</a> for matchers that either match the
-node you're interested in or narrow down attributes on the node.</li>
-<li>Create your outer match expression. Verify that it works as expected.</li>
-<li>Examine the matchers for what the next inner node you want to match is.</li>
-<li>Repeat until the matcher is finished.</li>
-</ol>
-
-<!-- ======================================================================= -->
-<h2 id="binding">Binding nodes in match expressions</h2>
-<!-- ======================================================================= -->
-
-<p>Matcher expressions allow you to specify which parts of the AST are interesting
-for a certain task. Often you will want to then do something with the nodes
-that were matched, like building source code transformations.</p>
-
-<p>To that end, matchers that match specific AST nodes (so called node matchers)
-are bindable; for example, recordDecl(hasName("MyClass")).bind("id") will bind
-the matched recordDecl node to the string "id", to be later retrieved in the
-<a href="http://clang.llvm.org/doxygen/classclang_1_1ast__matchers_1_1MatchFinder_1_1MatchCallback.html">match callback</a>.</p>
-
-<!-- FIXME: Introduce link to ASTMatchersTutorial.html -->
-<!-- FIXME: Introduce link to ASTMatchersCookbook.html -->
-
-<!-- ======================================================================= -->
-<h2 id="writing">Writing your own matchers</h2>
-<!-- ======================================================================= -->
-
-<p>There are multiple different ways to define a matcher, depending on its
-type and flexibility.</p>
-<ul>
-<li><b>VariadicDynCastAllOfMatcher&ltBase, Derived></b><p>Those match all nodes
-of type <i>Base</i> if they can be dynamically casted to <i>Derived</i>. The
-names of those matchers are nouns, which closely resemble <i>Derived</i>.
-VariadicDynCastAllOfMatchers are the backbone of the matcher hierarchy. Most
-often, your match expression will start with one of them, and you can
-<a href="#binding">bind</a> the node they represent to ids for later processing.</p>
-<p>VariadicDynCastAllOfMatchers are callable classes that model variadic
-template functions in C++03. They take an aribtrary number of Matcher&lt;Derived>
-and return a Matcher&lt;Base>.</p></li>
-<li><b>AST_MATCHER_P(Type, Name, ParamType, Param)</b><p> Most matcher definitions
-use the matcher creation macros. Those define both the matcher of type Matcher&lt;Type>
-itself, and a matcher-creation function named <i>Name</i> that takes a parameter
-of type <i>ParamType</i> and returns the corresponding matcher.</p>
-<p>There are multiple matcher definition macros that deal with polymorphic return
-values and different parameter counts. See <a href="http://clang.llvm.org/doxygen/ASTMatchersMacros_8h.html">ASTMatchersMacros.h</a>.
-</p></li>
-<li><b>Matcher creation functions</b><p>Matchers are generated by nesting
-calls to matcher creation functions. Most of the time those functions are either
-created by using VariadicDynCastAllOfMatcher or the matcher creation macros
-(see below). The free-standing functions are an indication that this matcher
-is just a combination of other matchers, as is for example the case with
-<a href="LibASTMatchersReference.html#callee1Anchor">callee</a>.</p></li>
-</ul>
-
-</div>
-</body>
-</html>
-
diff --git a/docs/LibASTMatchers.rst b/docs/LibASTMatchers.rst
new file mode 100644
index 0000000..738de79
--- /dev/null
+++ b/docs/LibASTMatchers.rst
@@ -0,0 +1,134 @@
+======================
+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
+:doc:`LibTooling`, LibASTMatchers helps to write code-to-code transformation
+tools or query tools.
+
+We assume basic knowledge about the Clang AST. See the :doc:`Introduction
+to the Clang AST <IntroductionToTheClangAST>` if you want to learn more
+about how the AST is structured.
+
+.. FIXME: create tutorial and link to the tutorial
+
+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()
+<LibASTMatchersReference.html#recordDecl0Anchor>`_. To narrow the match down,
+for example to find all class or union declarations with the name "``Foo``",
+insert a `hasName <LibASTMatchersReference.html#hasName0Anchor>`_ 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()
+<LibASTMatchersReference.html#allOf0Anchor>`_. 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 :ref:`how to write your own
+AST matchers <astmatchers-writing>` later in this document.
+
+.. FIXME: why is it linking back to the same section?!
+
+The precondition to using the matchers is to understand how the AST for what you
+want to match looks like. The
+:doc:`Introduction to the Clang AST <IntroductionToTheClangAST>` teaches you
+how to dump a translation unit's AST into a human readable format.
+
+.. FIXME: Introduce link to ASTMatchersTutorial.html
+.. FIXME: Introduce link to ASTMatchersCookbook.html
+
+In general, the strategy to create the right matchers is:
+
+#. Find the outermost class in Clang's AST you want to match.
+#. Look at the `AST Matcher Reference <LibASTMatchersReference.html>`_ for
+ matchers that either match the node you're interested in or narrow down
+ attributes on the node.
+#. Create your outer match expression. Verify that it works as expected.
+#. Examine the matchers for what the next inner node you want to match is.
+#. Repeat until the matcher is finished.
+
+.. _astmatchers-bind:
+
+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
+<http://clang.llvm.org/doxygen/classclang_1_1ast__matchers_1_1MatchFinder_1_1MatchCallback.html>`_.
+
+.. FIXME: Introduce link to ASTMatchersTutorial.html
+.. FIXME: Introduce link to ASTMatchersCookbook.html
+
+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 :ref:`bind <astmatchers-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
+<http://clang.llvm.org/doxygen/ASTMatchersMacros_8h.html>`_.
+
+.. _astmatchers-writing:
+
+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
+<LibASTMatchersReference.html#callee1Anchor>`_.
+
+.. FIXME: "... macros (see below)" --- there isn't anything below
+
diff --git a/docs/LibASTMatchersReference.html b/docs/LibASTMatchersReference.html
index ea038e3..b476065 100644
--- a/docs/LibASTMatchersReference.html
+++ b/docs/LibASTMatchersReference.html
@@ -77,6 +77,19 @@ match callback.</p>
<tr style="text-align:left"><th>Return type</th><th>Name</th><th>Parameters</th></tr>
<!-- START_DECL_MATCHERS -->
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('accessSpecDecl0')"><a name="accessSpecDecl0Anchor">accessSpecDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1AccessSpecDecl.html">AccessSpecDecl</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="accessSpecDecl0"><pre>Matches C++ access specifier declarations.
+
+Given
+ class C {
+ public:
+ int a;
+ };
+accessSpecDecl()
+ matches 'public:'
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('classTemplateDecl0')"><a name="classTemplateDecl0Anchor">classTemplateDecl</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ClassTemplateDecl.html">ClassTemplateDecl</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="classTemplateDecl0"><pre>Matches C++ class template declarations.
@@ -229,180 +242,143 @@ Example matches a
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt;</td><td class="name" onclick="toggle('boolLiteral0')"><a name="boolLiteral0Anchor">boolLiteral</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html">CXXBoolLiteralExpr</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="boolLiteral0"><pre>Matches bool literals.
-
-Example matches true
- true
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>&gt;</td><td class="name" onclick="toggle('nestedNameSpecifierLoc0')"><a name="nestedNameSpecifierLoc0Anchor">nestedNameSpecifierLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="nestedNameSpecifierLoc0"><pre>Same as nestedNameSpecifier but matches NestedNameSpecifierLoc.
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt;</td><td class="name" onclick="toggle('castExpr0')"><a name="castExpr0Anchor">castExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CastExpr.html">CastExpr</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="castExpr0"><pre>Matches any cast nodes of Clang's AST.
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>&gt;</td><td class="name" onclick="toggle('nestedNameSpecifier0')"><a name="nestedNameSpecifier0Anchor">nestedNameSpecifier</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="nestedNameSpecifier0"><pre>Matches nested name specifiers.
-Example: castExpr() matches each of the following:
- (int) 3;
- const_cast&lt;Expr *&gt;(SubExpr);
- char c = 0;
-but does not match
- int i = (0);
- int k = 0;
+Given
+ namespace ns {
+ struct A { static void f(); };
+ void A::f() {}
+ void g() { A::f(); }
+ }
+ ns::A a;
+nestedNameSpecifier()
+ matches "ns::" and both "A::"
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt;</td><td class="name" onclick="toggle('characterLiteral0')"><a name="characterLiteral0Anchor">characterLiteral</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="characterLiteral0"><pre>Matches character literals (also matches wchar_t).
-
-Not matching Hex-encoded chars (e.g. 0x1234, which is a IntegerLiteral),
-though.
-
-Example matches 'a', L'a'
- char ch = 'a'; wchar_t chw = L'a';
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;</td><td class="name" onclick="toggle('qualType0')"><a name="qualType0Anchor">qualType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="qualType0"><pre>Matches QualTypes in the clang AST.
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt;</td><td class="name" onclick="toggle('constCastExpr0')"><a name="constCastExpr0Anchor">constCastExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstCastExpr.html">CXXConstCastExpr</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="constCastExpr0"><pre>Matches a const_cast expression.
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('arraySubscriptExpr0')"><a name="arraySubscriptExpr0Anchor">arraySubscriptExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ArraySubscriptExpr.html">ArraySubscriptExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="arraySubscriptExpr0"><pre>Matches array subscript expressions.
-Example: Matches const_cast&lt;int*&gt;(&amp;r) in
- int n = 42;
- const int &amp;r(n);
- int* p = const_cast&lt;int*&gt;(&amp;r);
+Given
+ int i = a[1];
+arraySubscriptExpr()
+ matches "a[1]"
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt;</td><td class="name" onclick="toggle('dynamicCastExpr0')"><a name="dynamicCastExpr0Anchor">dynamicCastExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXDynamicCastExpr.html">CXXDynamicCastExpr</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="dynamicCastExpr0"><pre>Matches a dynamic_cast expression.
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('asmStmt0')"><a name="asmStmt0Anchor">asmStmt</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1AsmStmt.html">AsmStmt</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="asmStmt0"><pre>Matches asm statements.
-Example:
- dynamicCastExpr()
-matches
- dynamic_cast&lt;D*&gt;(&amp;b);
-in
- struct B { virtual ~B() {} }; struct D : B {};
- B b;
- D* p = dynamic_cast&lt;D*&gt;(&amp;b);
+ int i = 100;
+ __asm("mov al, 2");
+asmStmt()
+ matches '__asm("mov al, 2")'
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt;</td><td class="name" onclick="toggle('explicitCastExpr0')"><a name="explicitCastExpr0Anchor">explicitCastExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ExplicitCastExpr.html">ExplicitCastExpr</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="explicitCastExpr0"><pre>Matches explicit cast expressions.
-
-Matches any cast expression written in user code, whether it be a
-C-style cast, a functional-style cast, or a keyword cast.
-
-Does not match implicit conversions.
-
-Note: the name "explicitCast" is chosen to match Clang's terminology, as
-Clang uses the term "cast" to apply to implicit conversions as well as to
-actual cast expressions.
-
-hasDestinationType.
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('binaryOperator0')"><a name="binaryOperator0Anchor">binaryOperator</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="binaryOperator0"><pre>Matches binary operator expressions.
-Example: matches all five of the casts in
- int((int)(reinterpret_cast&lt;int&gt;(static_cast&lt;int&gt;(const_cast&lt;int&gt;(42)))))
-but does not match the implicit conversion in
- long ell = 42;
+Example matches a || b
+ !(a || b)
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt;</td><td class="name" onclick="toggle('functionalCastExpr0')"><a name="functionalCastExpr0Anchor">functionalCastExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXFunctionalCastExpr.html">CXXFunctionalCastExpr</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="functionalCastExpr0"><pre>Matches functional cast expressions
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('bindTemporaryExpr0')"><a name="bindTemporaryExpr0Anchor">bindTemporaryExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBindTemporaryExpr.html">CXXBindTemporaryExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="bindTemporaryExpr0"><pre>Matches nodes where temporaries are created.
-Example: Matches Foo(bar);
- Foo f = bar;
- Foo g = (Foo) bar;
- Foo h = Foo(bar);
+Example matches FunctionTakesString(GetStringByValue())
+ (matcher = bindTemporaryExpr())
+ FunctionTakesString(GetStringByValue());
+ FunctionTakesStringByPointer(GetStringPointer());
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt;</td><td class="name" onclick="toggle('implicitCastExpr0')"><a name="implicitCastExpr0Anchor">implicitCastExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ImplicitCastExpr.html">ImplicitCastExpr</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="implicitCastExpr0"><pre>Matches the implicit cast nodes of Clang's AST.
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('boolLiteral0')"><a name="boolLiteral0Anchor">boolLiteral</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html">CXXBoolLiteralExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="boolLiteral0"><pre>Matches bool literals.
-This matches many different places, including function call return value
-eliding, as well as any type conversions.
+Example matches true
+ true
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt;</td><td class="name" onclick="toggle('integerLiteral0')"><a name="integerLiteral0Anchor">integerLiteral</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="integerLiteral0"><pre>Matches integer literals of all sizes encodings.
-
-Not matching character-encoded integers such as L'a'.
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('breakStmt0')"><a name="breakStmt0Anchor">breakStmt</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BreakStmt.html">BreakStmt</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="breakStmt0"><pre>Matches break statements.
-Example matches 1, 1L, 0x1, 1U
+Given
+ while (true) { break; }
+breakStmt()
+ matches 'break'
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt;</td><td class="name" onclick="toggle('reinterpretCastExpr0')"><a name="reinterpretCastExpr0Anchor">reinterpretCastExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXReinterpretCastExpr.html">CXXReinterpretCastExpr</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="reinterpretCastExpr0"><pre>Matches a reinterpret_cast expression.
-
-Either the source expression or the destination type can be matched
-using has(), but hasDestinationType() is more specific and can be
-more readable.
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('cStyleCastExpr0')"><a name="cStyleCastExpr0Anchor">cStyleCastExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CStyleCastExpr.html">CStyleCastExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="cStyleCastExpr0"><pre>Matches a C-style cast expression.
-Example matches reinterpret_cast&lt;char*&gt;(&amp;p) in
- void* p = reinterpret_cast&lt;char*&gt;(&amp;p);
+Example: Matches (int*) 2.2f in
+ int i = (int) 2.2f;
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt;</td><td class="name" onclick="toggle('staticCastExpr0')"><a name="staticCastExpr0Anchor">staticCastExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXStaticCastExpr.html">CXXStaticCastExpr</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="staticCastExpr0"><pre>Matches a C++ static_cast expression.
-
-hasDestinationType
-reinterpretCast
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('callExpr0')"><a name="callExpr0Anchor">callExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="callExpr0"><pre>Matches call expressions.
-Example:
- staticCastExpr()
-matches
- static_cast&lt;long&gt;(8)
-in
- long eight(static_cast&lt;long&gt;(8));
+Example matches x.y() and y()
+ X x;
+ x.y();
+ y();
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt;</td><td class="name" onclick="toggle('stringLiteral0')"><a name="stringLiteral0Anchor">stringLiteral</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1StringLiteral.html">StringLiteral</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="stringLiteral0"><pre>Matches string literals (also matches wide string literals).
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('castExpr0')"><a name="castExpr0Anchor">castExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CastExpr.html">CastExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="castExpr0"><pre>Matches any cast nodes of Clang's AST.
-Example matches "abcd", L"abcd"
- char *s = "abcd"; wchar_t *ws = L"abcd"
+Example: castExpr() matches each of the following:
+ (int) 3;
+ const_cast&lt;Expr *&gt;(SubExpr);
+ char c = 0;
+but does not match
+ int i = (0);
+ int k = 0;
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('arraySubscriptExpr0')"><a name="arraySubscriptExpr0Anchor">arraySubscriptExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ArraySubscriptExpr.html">ArraySubscriptExpr</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="arraySubscriptExpr0"><pre>Matches array subscript expressions.
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('catchStmt0')"><a name="catchStmt0Anchor">catchStmt</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXCatchStmt.html">CXXCatchStmt</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="catchStmt0"><pre>Matches catch statements.
-Given
- int i = a[1];
-arraySubscriptExpr()
- matches "a[1]"
+ try {} catch(int i) {}
+catchStmt()
+ matches 'catch(int i)'
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('binaryOperator0')"><a name="binaryOperator0Anchor">binaryOperator</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="binaryOperator0"><pre>Matches binary operator expressions.
-
-Example matches a || b
- !(a || b)
-</pre></td></tr>
-
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('characterLiteral0')"><a name="characterLiteral0Anchor">characterLiteral</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="characterLiteral0"><pre>Matches character literals (also matches wchar_t).
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('bindTemporaryExpr0')"><a name="bindTemporaryExpr0Anchor">bindTemporaryExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBindTemporaryExpr.html">CXXBindTemporaryExpr</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="bindTemporaryExpr0"><pre>Matches nodes where temporaries are created.
+Not matching Hex-encoded chars (e.g. 0x1234, which is a IntegerLiteral),
+though.
-Example matches FunctionTakesString(GetStringByValue())
- (matcher = bindTemporaryExpr())
- FunctionTakesString(GetStringByValue());
- FunctionTakesStringByPointer(GetStringPointer());
+Example matches 'a', L'a'
+ char ch = 'a'; wchar_t chw = L'a';
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('callExpr0')"><a name="callExpr0Anchor">callExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;...</td></tr>
-<tr><td colspan="4" class="doc" id="callExpr0"><pre>Matches call expressions.
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('compoundLiteralExpr0')"><a name="compoundLiteralExpr0Anchor">compoundLiteralExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CompoundLiteralExpr.html">CompoundLiteralExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="compoundLiteralExpr0"><pre>Matches compound (i.e. non-scalar) literals
-Example matches x.y() and y()
- X x;
- x.y();
- y();
+Example match: {1}, (1, 2)
+ int array[4] = {1}; vector int myvec = (vector int)(1, 2);
</pre></td></tr>
@@ -422,6 +398,16 @@ Example matches a ? b : c
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('constCastExpr0')"><a name="constCastExpr0Anchor">constCastExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstCastExpr.html">CXXConstCastExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="constCastExpr0"><pre>Matches a const_cast expression.
+
+Example: Matches const_cast&lt;int*&gt;(&amp;r) in
+ int n = 42;
+ const int &amp;r(n);
+ int* p = const_cast&lt;int*&gt;(&amp;r);
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('constructExpr0')"><a name="constructExpr0Anchor">constructExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="constructExpr0"><pre>Matches constructor call expressions (including implicit ones).
@@ -434,6 +420,16 @@ Example matches string(ptr, n) and ptr within arguments of f
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('continueStmt0')"><a name="continueStmt0Anchor">continueStmt</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ContinueStmt.html">ContinueStmt</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="continueStmt0"><pre>Matches continue statements.
+
+Given
+ while (true) { continue; }
+continueStmt()
+ matches 'continue'
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('declRefExpr0')"><a name="declRefExpr0Anchor">declRefExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclRefExpr.html">DeclRefExpr</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="declRefExpr0"><pre>Matches expressions that refer to declarations.
@@ -484,6 +480,41 @@ doStmt()
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('dynamicCastExpr0')"><a name="dynamicCastExpr0Anchor">dynamicCastExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXDynamicCastExpr.html">CXXDynamicCastExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="dynamicCastExpr0"><pre>Matches a dynamic_cast expression.
+
+Example:
+ dynamicCastExpr()
+matches
+ dynamic_cast&lt;D*&gt;(&amp;b);
+in
+ struct B { virtual ~B() {} }; struct D : B {};
+ B b;
+ D* p = dynamic_cast&lt;D*&gt;(&amp;b);
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('explicitCastExpr0')"><a name="explicitCastExpr0Anchor">explicitCastExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ExplicitCastExpr.html">ExplicitCastExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="explicitCastExpr0"><pre>Matches explicit cast expressions.
+
+Matches any cast expression written in user code, whether it be a
+C-style cast, a functional-style cast, or a keyword cast.
+
+Does not match implicit conversions.
+
+Note: the name "explicitCast" is chosen to match Clang's terminology, as
+Clang uses the term "cast" to apply to implicit conversions as well as to
+actual cast expressions.
+
+hasDestinationType.
+
+Example: matches all five of the casts in
+ int((int)(reinterpret_cast&lt;int&gt;(static_cast&lt;int&gt;(const_cast&lt;int&gt;(42)))))
+but does not match the implicit conversion in
+ long ell = 42;
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('expr0')"><a name="expr0Anchor">expr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="expr0"><pre>Matches expressions.
@@ -492,11 +523,42 @@ Example matches x()
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('forRangeStmt0')"><a name="forRangeStmt0Anchor">forRangeStmt</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXForRangeStmt.html">CXXForRangeStmt</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="forRangeStmt0"><pre>Matches range-based for statements.
+
+forRangeStmt() matches 'for (auto a : i)'
+ int i[] = {1, 2, 3}; for (auto a : i);
+ for(int j = 0; j &lt; 5; ++j);
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('forStmt0')"><a name="forStmt0Anchor">forStmt</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ForStmt.html">ForStmt</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="forStmt0"><pre>Matches for statements.
Example matches 'for (;;) {}'
for (;;) {}
+ int i[] = {1, 2, 3}; for (auto a : i);
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('functionalCastExpr0')"><a name="functionalCastExpr0Anchor">functionalCastExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXFunctionalCastExpr.html">CXXFunctionalCastExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="functionalCastExpr0"><pre>Matches functional cast expressions
+
+Example: Matches Foo(bar);
+ Foo f = bar;
+ Foo g = (Foo) bar;
+ Foo h = Foo(bar);
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('gotoStmt0')"><a name="gotoStmt0Anchor">gotoStmt</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1GotoStmt.html">GotoStmt</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="gotoStmt0"><pre>Matches goto statements.
+
+Given
+ goto FOO;
+ FOO: bar();
+gotoStmt()
+ matches 'goto FOO'
</pre></td></tr>
@@ -508,6 +570,14 @@ Example matches 'if (x) {}'
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('implicitCastExpr0')"><a name="implicitCastExpr0Anchor">implicitCastExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ImplicitCastExpr.html">ImplicitCastExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="implicitCastExpr0"><pre>Matches the implicit cast nodes of Clang's AST.
+
+This matches many different places, including function call return value
+eliding, as well as any type conversions.
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('initListExpr0')"><a name="initListExpr0Anchor">initListExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1InitListExpr.html">InitListExpr</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="initListExpr0"><pre>Matches init list expressions.
@@ -520,6 +590,34 @@ initList()
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('integerLiteral0')"><a name="integerLiteral0Anchor">integerLiteral</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="integerLiteral0"><pre>Matches integer literals of all sizes encodings.
+
+Not matching character-encoded integers such as L'a'.
+
+Example matches 1, 1L, 0x1, 1U
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('labelStmt0')"><a name="labelStmt0Anchor">labelStmt</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1LabelStmt.html">LabelStmt</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="labelStmt0"><pre>Matches label statements.
+
+Given
+ goto FOO;
+ FOO: bar();
+labelStmt()
+ matches 'FOO:'
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('lambdaExpr0')"><a name="lambdaExpr0Anchor">lambdaExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1LambdaExpr.html">LambdaExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="lambdaExpr0"><pre>Matches lambda expressions.
+
+Example matches [&amp;](){return 5;}
+ [&amp;](){return 5;}
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('materializeTemporaryExpr0')"><a name="materializeTemporaryExpr0Anchor">materializeTemporaryExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MaterializeTemporaryExpr.html">MaterializeTemporaryExpr</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="materializeTemporaryExpr0"><pre>Matches nodes where temporaries are materialized.
@@ -568,6 +666,20 @@ newExpr()
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('nullPtrLiteralExpr0')"><a name="nullPtrLiteralExpr0Anchor">nullPtrLiteralExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXNullPtrLiteralExpr.html">CXXNullPtrLiteralExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="nullPtrLiteralExpr0"><pre>Matches nullptr literal.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('nullStmt0')"><a name="nullStmt0Anchor">nullStmt</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NullStmt.html">NullStmt</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="nullStmt0"><pre>Matches null statements.
+
+ foo();;
+nullStmt()
+ matches the second ';'
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('operatorCallExpr0')"><a name="operatorCallExpr0Anchor">operatorCallExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="operatorCallExpr0"><pre>Matches overloaded operator calls.
@@ -584,6 +696,43 @@ Example matches both operator&lt;&lt;((o &lt;&lt; b), c) and operator&lt;&lt;(o,
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('reinterpretCastExpr0')"><a name="reinterpretCastExpr0Anchor">reinterpretCastExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXReinterpretCastExpr.html">CXXReinterpretCastExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="reinterpretCastExpr0"><pre>Matches a reinterpret_cast expression.
+
+Either the source expression or the destination type can be matched
+using has(), but hasDestinationType() is more specific and can be
+more readable.
+
+Example matches reinterpret_cast&lt;char*&gt;(&amp;p) in
+ void* p = reinterpret_cast&lt;char*&gt;(&amp;p);
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('returnStmt0')"><a name="returnStmt0Anchor">returnStmt</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ReturnStmt.html">ReturnStmt</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="returnStmt0"><pre>Matches return statements.
+
+Given
+ return 1;
+returnStmt()
+ matches 'return 1'
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('staticCastExpr0')"><a name="staticCastExpr0Anchor">staticCastExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXStaticCastExpr.html">CXXStaticCastExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="staticCastExpr0"><pre>Matches a C++ static_cast expression.
+
+hasDestinationType
+reinterpretCast
+
+Example:
+ staticCastExpr()
+matches
+ static_cast&lt;long&gt;(8)
+in
+ long eight(static_cast&lt;long&gt;(8));
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('stmt0')"><a name="stmt0Anchor">stmt</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="stmt0"><pre>Matches statements.
@@ -594,6 +743,14 @@ stmt()
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('stringLiteral0')"><a name="stringLiteral0Anchor">stringLiteral</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1StringLiteral.html">StringLiteral</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="stringLiteral0"><pre>Matches string literals (also matches wide string literals).
+
+Example matches "abcd", L"abcd"
+ char *s = "abcd"; wchar_t *ws = L"abcd"
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('switchCase0')"><a name="switchCase0Anchor">switchCase</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1SwitchCase.html">SwitchCase</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="switchCase0"><pre>Matches case and default statements inside switch statements.
@@ -604,6 +761,46 @@ switchCase()
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('switchStmt0')"><a name="switchStmt0Anchor">switchStmt</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1SwitchStmt.html">SwitchStmt</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="switchStmt0"><pre>Matches switch statements.
+
+Given
+ switch(a) { case 42: break; default: break; }
+switchStmt()
+ matches 'switch(a)'.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('thisExpr0')"><a name="thisExpr0Anchor">thisExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXThisExpr.html">CXXThisExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="thisExpr0"><pre>Matches implicit and explicit this expressions.
+
+Example matches the implicit this expression in "return i".
+ (matcher = thisExpr())
+struct foo {
+ int i;
+ int f() { return i; }
+};
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('throwExpr0')"><a name="throwExpr0Anchor">throwExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXThrowExpr.html">CXXThrowExpr</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="throwExpr0"><pre>Matches throw expressions.
+
+ try { throw 5; } catch(int i) {}
+throwExpr()
+ matches 'throw 5'
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('tryStmt0')"><a name="tryStmt0Anchor">tryStmt</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXTryStmt.html">CXXTryStmt</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="tryStmt0"><pre>Matches try statements.
+
+ try {} catch(int i) {}
+tryStmt()
+ matches 'try {}'
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('unaryExprOrTypeTraitExpr0')"><a name="unaryExprOrTypeTraitExpr0Anchor">unaryExprOrTypeTraitExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryExprOrTypeTraitExpr.html">UnaryExprOrTypeTraitExpr</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="unaryExprOrTypeTraitExpr0"><pre>Matches sizeof (C99), alignof (C++11) and vec_step (OpenCL)
@@ -623,6 +820,13 @@ Example matches !a
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('userDefinedLiteral0')"><a name="userDefinedLiteral0Anchor">userDefinedLiteral</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UserDefinedLiteral.html">UserDefinedLiteral</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="userDefinedLiteral0"><pre>Matches user defined literal operator call.
+
+Example match: "foo"_suffix
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('whileStmt0')"><a name="whileStmt0Anchor">whileStmt</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1WhileStmt.html">WhileStmt</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="whileStmt0"><pre>Matches while statements.
@@ -632,6 +836,564 @@ whileStmt()
matches 'while (true) {}'.
</pre></td></tr>
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('arrayTypeLoc0')"><a name="arrayTypeLoc0Anchor">arrayTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayTypeLoc.html">ArrayTypeLoc</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="arrayTypeLoc0"><pre>Matches all kinds of arrays.
+
+Given
+ int a[] = { 2, 3 };
+ int b[4];
+ void f() { int c[a[0]]; }
+arrayType()
+ matches "int a[]", "int b[4]" and "int c[a[0]]";
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('atomicTypeLoc0')"><a name="atomicTypeLoc0Anchor">atomicTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1AtomicTypeLoc.html">AtomicTypeLoc</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="atomicTypeLoc0"><pre>Matches atomic types.
+
+Given
+ _Atomic(int) i;
+atomicType()
+ matches "_Atomic(int) i"
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('autoTypeLoc0')"><a name="autoTypeLoc0Anchor">autoTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1AutoTypeLoc.html">AutoTypeLoc</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="autoTypeLoc0"><pre>Matches types nodes representing C++11 auto types.
+
+Given:
+ auto n = 4;
+ int v[] = { 2, 3 }
+ for (auto i : v) { }
+autoType()
+ matches "auto n" and "auto i"
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('blockPointerTypeLoc0')"><a name="blockPointerTypeLoc0Anchor">blockPointerTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerTypeLoc.html">BlockPointerTypeLoc</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="blockPointerTypeLoc0"><pre>Matches block pointer types, i.e. types syntactically represented as
+"void (^)(int)".
+
+The pointee is always required to be a FunctionType.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('builtinTypeLoc0')"><a name="builtinTypeLoc0Anchor">builtinTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BuiltinTypeLoc.html">BuiltinTypeLoc</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="builtinTypeLoc0"><pre>Matches builtin Types.
+
+Given
+ struct A {};
+ A a;
+ int b;
+ float c;
+ bool d;
+builtinType()
+ matches "int b", "float c" and "bool d"
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('complexTypeLoc0')"><a name="complexTypeLoc0Anchor">complexTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexTypeLoc.html">ComplexTypeLoc</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="complexTypeLoc0"><pre>Matches C99 complex types.
+
+Given
+ _Complex float f;
+complexType()
+ matches "_Complex float f"
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('constantArrayTypeLoc0')"><a name="constantArrayTypeLoc0Anchor">constantArrayTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ConstantArrayTypeLoc.html">ConstantArrayTypeLoc</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="constantArrayTypeLoc0"><pre>Matches C arrays with a specified constant size.
+
+Given
+ void() {
+ int a[2];
+ int b[] = { 2, 3 };
+ int c[b[0]];
+ }
+constantArrayType()
+ matches "int a[2]"
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('dependentSizedArrayTypeLoc0')"><a name="dependentSizedArrayTypeLoc0Anchor">dependentSizedArrayTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DependentSizedArrayTypeLoc.html">DependentSizedArrayTypeLoc</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="dependentSizedArrayTypeLoc0"><pre>Matches C++ arrays whose size is a value-dependent expression.
+
+Given
+ template&lt;typename T, int Size&gt;
+ class array {
+ T data[Size];
+ };
+dependentSizedArrayType
+ matches "T data[Size]"
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('elaboratedTypeLoc0')"><a name="elaboratedTypeLoc0Anchor">elaboratedTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ElaboratedTypeLoc.html">ElaboratedTypeLoc</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="elaboratedTypeLoc0"><pre>Matches types specified with an elaborated type keyword or with a
+qualified name.
+
+Given
+ namespace N {
+ namespace M {
+ class D {};
+ }
+ }
+ class C {};
+
+ class C c;
+ N::M::D d;
+
+elaboratedType() matches the type of the variable declarations of both
+c and d.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('functionTypeLoc0')"><a name="functionTypeLoc0Anchor">functionTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionTypeLoc.html">FunctionTypeLoc</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="functionTypeLoc0"><pre>Matches FunctionType nodes.
+
+Given
+ int (*f)(int);
+ void g();
+functionType()
+ matches "int (*f)(int)" and the type of "g".
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('incompleteArrayTypeLoc0')"><a name="incompleteArrayTypeLoc0Anchor">incompleteArrayTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1IncompleteArrayTypeLoc.html">IncompleteArrayTypeLoc</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="incompleteArrayTypeLoc0"><pre>Matches C arrays with unspecified size.
+
+Given
+ int a[] = { 2, 3 };
+ int b[42];
+ void f(int c[]) { int d[a[0]]; };
+incompleteArrayType()
+ matches "int a[]" and "int c[]"
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('lValueReferenceTypeLoc0')"><a name="lValueReferenceTypeLoc0Anchor">lValueReferenceTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1LValueReferenceTypeLoc.html">LValueReferenceTypeLoc</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="lValueReferenceTypeLoc0"><pre>Matches lvalue reference types.
+
+Given:
+ int *a;
+ int &amp;b = *a;
+ int &amp;&amp;c = 1;
+ auto &amp;d = b;
+ auto &amp;&amp;e = c;
+ auto &amp;&amp;f = 2;
+ int g = 5;
+
+lValueReferenceType() matches the types of b, d, and e. e is
+matched since the type is deduced as int&amp; by reference collapsing rules.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('memberPointerTypeLoc0')"><a name="memberPointerTypeLoc0Anchor">memberPointerTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerTypeLoc.html">MemberPointerTypeLoc</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="memberPointerTypeLoc0"><pre>Matches member pointer types.
+Given
+ struct A { int i; }
+ A::* ptr = A::i;
+memberPointerType()
+ matches "A::* ptr"
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('parenTypeLoc0')"><a name="parenTypeLoc0Anchor">parenTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ParenTypeLoc.html">ParenTypeLoc</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="parenTypeLoc0"><pre>Matches ParenType nodes.
+
+Given
+ int (*ptr_to_array)[4];
+ int *array_of_ptrs[4];
+
+varDecl(hasType(pointsTo(parenType()))) matches ptr_to_array but not
+array_of_ptrs.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('pointerTypeLoc0')"><a name="pointerTypeLoc0Anchor">pointerTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerTypeLoc.html">PointerTypeLoc</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="pointerTypeLoc0"><pre>Matches pointer types.
+
+Given
+ int *a;
+ int &amp;b = *a;
+ int c = 5;
+pointerType()
+ matches "int *a"
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('rValueReferenceTypeLoc0')"><a name="rValueReferenceTypeLoc0Anchor">rValueReferenceTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1RValueReferenceTypeLoc.html">RValueReferenceTypeLoc</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="rValueReferenceTypeLoc0"><pre>Matches rvalue reference types.
+
+Given:
+ int *a;
+ int &amp;b = *a;
+ int &amp;&amp;c = 1;
+ auto &amp;d = b;
+ auto &amp;&amp;e = c;
+ auto &amp;&amp;f = 2;
+ int g = 5;
+
+rValueReferenceType() matches the types of c and f. e is not
+matched as it is deduced to int&amp; by reference collapsing rules.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('recordTypeLoc0')"><a name="recordTypeLoc0Anchor">recordTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordTypeLoc.html">RecordTypeLoc</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="recordTypeLoc0"><pre>Matches record types (e.g. structs, classes).
+
+Given
+ class C {};
+ struct S {};
+
+ C c;
+ S s;
+
+recordType() matches the type of the variable declarations of both c
+and s.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('referenceTypeLoc0')"><a name="referenceTypeLoc0Anchor">referenceTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceTypeLoc.html">ReferenceTypeLoc</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="referenceTypeLoc0"><pre>Matches both lvalue and rvalue reference types.
+
+Given
+ int *a;
+ int &amp;b = *a;
+ int &amp;&amp;c = 1;
+ auto &amp;d = b;
+ auto &amp;&amp;e = c;
+ auto &amp;&amp;f = 2;
+ int g = 5;
+
+referenceType() matches the types of b, c, d, e, and f.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('templateSpecializationTypeLoc0')"><a name="templateSpecializationTypeLoc0Anchor">templateSpecializationTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationTypeLoc.html">TemplateSpecializationTypeLoc</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="templateSpecializationTypeLoc0"><pre>Matches template specialization types.
+
+Given
+ template &lt;typename T&gt;
+ class C { };
+
+ template class C&lt;int&gt;; A
+ C&lt;char&gt; var; B
+
+templateSpecializationType() matches the type of the explicit
+instantiation in A and the type of the variable declaration in B.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('typeLoc0')"><a name="typeLoc0Anchor">typeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="typeLoc0"><pre>Matches TypeLocs in the clang AST.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('typedefTypeLoc0')"><a name="typedefTypeLoc0Anchor">typedefTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefTypeLoc.html">TypedefTypeLoc</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="typedefTypeLoc0"><pre>Matches typedef types.
+
+Given
+ typedef int X;
+typedefType()
+ matches "typedef int X"
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('variableArrayTypeLoc0')"><a name="variableArrayTypeLoc0Anchor">variableArrayTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1VariableArrayTypeLoc.html">VariableArrayTypeLoc</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="variableArrayTypeLoc0"><pre>Matches C arrays with a specified size that is not an
+integer-constant-expression.
+
+Given
+ void f() {
+ int a[] = { 2, 3 }
+ int b[42];
+ int c[a[0]];
+variableArrayType()
+ matches "int c[a[0]]"
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('arrayType0')"><a name="arrayType0Anchor">arrayType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayType.html">ArrayType</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="arrayType0"><pre>Matches all kinds of arrays.
+
+Given
+ int a[] = { 2, 3 };
+ int b[4];
+ void f() { int c[a[0]]; }
+arrayType()
+ matches "int a[]", "int b[4]" and "int c[a[0]]";
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('atomicType0')"><a name="atomicType0Anchor">atomicType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1AtomicType.html">AtomicType</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="atomicType0"><pre>Matches atomic types.
+
+Given
+ _Atomic(int) i;
+atomicType()
+ matches "_Atomic(int) i"
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('autoType0')"><a name="autoType0Anchor">autoType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1AutoType.html">AutoType</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="autoType0"><pre>Matches types nodes representing C++11 auto types.
+
+Given:
+ auto n = 4;
+ int v[] = { 2, 3 }
+ for (auto i : v) { }
+autoType()
+ matches "auto n" and "auto i"
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('blockPointerType0')"><a name="blockPointerType0Anchor">blockPointerType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="blockPointerType0"><pre>Matches block pointer types, i.e. types syntactically represented as
+"void (^)(int)".
+
+The pointee is always required to be a FunctionType.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('builtinType0')"><a name="builtinType0Anchor">builtinType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BuiltinType.html">BuiltinType</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="builtinType0"><pre>Matches builtin Types.
+
+Given
+ struct A {};
+ A a;
+ int b;
+ float c;
+ bool d;
+builtinType()
+ matches "int b", "float c" and "bool d"
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('complexType0')"><a name="complexType0Anchor">complexType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexType.html">ComplexType</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="complexType0"><pre>Matches C99 complex types.
+
+Given
+ _Complex float f;
+complexType()
+ matches "_Complex float f"
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('constantArrayType0')"><a name="constantArrayType0Anchor">constantArrayType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ConstantArrayType.html">ConstantArrayType</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="constantArrayType0"><pre>Matches C arrays with a specified constant size.
+
+Given
+ void() {
+ int a[2];
+ int b[] = { 2, 3 };
+ int c[b[0]];
+ }
+constantArrayType()
+ matches "int a[2]"
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('dependentSizedArrayType0')"><a name="dependentSizedArrayType0Anchor">dependentSizedArrayType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DependentSizedArrayType.html">DependentSizedArrayType</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="dependentSizedArrayType0"><pre>Matches C++ arrays whose size is a value-dependent expression.
+
+Given
+ template&lt;typename T, int Size&gt;
+ class array {
+ T data[Size];
+ };
+dependentSizedArrayType
+ matches "T data[Size]"
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('elaboratedType0')"><a name="elaboratedType0Anchor">elaboratedType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ElaboratedType.html">ElaboratedType</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="elaboratedType0"><pre>Matches types specified with an elaborated type keyword or with a
+qualified name.
+
+Given
+ namespace N {
+ namespace M {
+ class D {};
+ }
+ }
+ class C {};
+
+ class C c;
+ N::M::D d;
+
+elaboratedType() matches the type of the variable declarations of both
+c and d.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('functionType0')"><a name="functionType0Anchor">functionType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionType.html">FunctionType</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="functionType0"><pre>Matches FunctionType nodes.
+
+Given
+ int (*f)(int);
+ void g();
+functionType()
+ matches "int (*f)(int)" and the type of "g".
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('incompleteArrayType0')"><a name="incompleteArrayType0Anchor">incompleteArrayType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1IncompleteArrayType.html">IncompleteArrayType</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="incompleteArrayType0"><pre>Matches C arrays with unspecified size.
+
+Given
+ int a[] = { 2, 3 };
+ int b[42];
+ void f(int c[]) { int d[a[0]]; };
+incompleteArrayType()
+ matches "int a[]" and "int c[]"
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('lValueReferenceType0')"><a name="lValueReferenceType0Anchor">lValueReferenceType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1LValueReferenceType.html">LValueReferenceType</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="lValueReferenceType0"><pre>Matches lvalue reference types.
+
+Given:
+ int *a;
+ int &amp;b = *a;
+ int &amp;&amp;c = 1;
+ auto &amp;d = b;
+ auto &amp;&amp;e = c;
+ auto &amp;&amp;f = 2;
+ int g = 5;
+
+lValueReferenceType() matches the types of b, d, and e. e is
+matched since the type is deduced as int&amp; by reference collapsing rules.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('memberPointerType0')"><a name="memberPointerType0Anchor">memberPointerType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="memberPointerType0"><pre>Matches member pointer types.
+Given
+ struct A { int i; }
+ A::* ptr = A::i;
+memberPointerType()
+ matches "A::* ptr"
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('parenType0')"><a name="parenType0Anchor">parenType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ParenType.html">ParenType</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="parenType0"><pre>Matches ParenType nodes.
+
+Given
+ int (*ptr_to_array)[4];
+ int *array_of_ptrs[4];
+
+varDecl(hasType(pointsTo(parenType()))) matches ptr_to_array but not
+array_of_ptrs.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('pointerType0')"><a name="pointerType0Anchor">pointerType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="pointerType0"><pre>Matches pointer types.
+
+Given
+ int *a;
+ int &amp;b = *a;
+ int c = 5;
+pointerType()
+ matches "int *a"
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('rValueReferenceType0')"><a name="rValueReferenceType0Anchor">rValueReferenceType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1RValueReferenceType.html">RValueReferenceType</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="rValueReferenceType0"><pre>Matches rvalue reference types.
+
+Given:
+ int *a;
+ int &amp;b = *a;
+ int &amp;&amp;c = 1;
+ auto &amp;d = b;
+ auto &amp;&amp;e = c;
+ auto &amp;&amp;f = 2;
+ int g = 5;
+
+rValueReferenceType() matches the types of c and f. e is not
+matched as it is deduced to int&amp; by reference collapsing rules.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('recordType0')"><a name="recordType0Anchor">recordType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1RecordType.html">RecordType</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="recordType0"><pre>Matches record types (e.g. structs, classes).
+
+Given
+ class C {};
+ struct S {};
+
+ C c;
+ S s;
+
+recordType() matches the type of the variable declarations of both c
+and s.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('referenceType0')"><a name="referenceType0Anchor">referenceType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="referenceType0"><pre>Matches both lvalue and rvalue reference types.
+
+Given
+ int *a;
+ int &amp;b = *a;
+ int &amp;&amp;c = 1;
+ auto &amp;d = b;
+ auto &amp;&amp;e = c;
+ auto &amp;&amp;f = 2;
+ int g = 5;
+
+referenceType() matches the types of b, c, d, e, and f.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('templateSpecializationType0')"><a name="templateSpecializationType0Anchor">templateSpecializationType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="templateSpecializationType0"><pre>Matches template specialization types.
+
+Given
+ template &lt;typename T&gt;
+ class C { };
+
+ template class C&lt;int&gt;; A
+ C&lt;char&gt; var; B
+
+templateSpecializationType() matches the type of the explicit
+instantiation in A and the type of the variable declaration in B.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('type0')"><a name="type0Anchor">type</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="type0"><pre>Matches Types in the clang AST.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('typedefType0')"><a name="typedefType0Anchor">typedefType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="typedefType0"><pre>Matches typedef types.
+
+Given
+ typedef int X;
+typedefType()
+ matches "typedef int X"
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td><td class="name" onclick="toggle('variableArrayType0')"><a name="variableArrayType0Anchor">variableArrayType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1VariableArrayType.html">VariableArrayType</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="variableArrayType0"><pre>Matches C arrays with a specified size that is not an
+integer-constant-expression.
+
+Given
+ void f() {
+ int a[] = { 2, 3 }
+ int b[42];
+ int c[a[0]];
+variableArrayType()
+ matches "int c[a[0]]"
+</pre></td></tr>
+
<!--END_DECL_MATCHERS -->
</table>
@@ -731,22 +1493,43 @@ constructorDecl(hasAnyConstructorInitializer(isWritten()))
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>&gt;</td><td class="name" onclick="toggle('hasOverloadedOperatorName0')"><a name="hasOverloadedOperatorName0Anchor">hasOverloadedOperatorName</a></td><td>std::string Name</td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>&gt;</td><td class="name" onclick="toggle('hasOverloadedOperatorName0')"><a name="hasOverloadedOperatorName0Anchor">hasOverloadedOperatorName</a></td><td>StringRef Name</td></tr>
<tr><td colspan="4" class="doc" id="hasOverloadedOperatorName0"><pre>Matches overloaded operator names.
Matches overloaded operator names specified in strings without the
-"operator" prefix, such as "&lt;&lt;", for OverloadedOperatorCall's.
+"operator" prefix: e.g. "&lt;&lt;".
+
+Given:
+ class A { int operator*(); };
+ const A &amp;operator&lt;&lt;(const A &amp;a, const A &amp;b);
+ A a;
+ a &lt;&lt; a; &lt;-- This matches
-Example matches a &lt;&lt; b
- (matcher == operatorCallExpr(hasOverloadedOperatorName("&lt;&lt;")))
- a &lt;&lt; b;
- c &amp;&amp; d; assuming both operator&lt;&lt;
- and operator&amp;&amp; are overloaded somewhere.
+operatorCallExpr(hasOverloadedOperatorName("&lt;&lt;"))) matches the specified
+line and recordDecl(hasMethod(hasOverloadedOperatorName("*"))) matches
+the declaration of A.
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>&gt;
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;</td><td class="name" onclick="toggle('isA1')"><a name="isA1Anchor">isA</a></td><td>StringRef BaseName</td></tr>
-<tr><td colspan="4" class="doc" id="isA1"><pre>Overloaded method as shortcut for isA(hasName(...)).
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>&gt;</td><td class="name" onclick="toggle('hasOverloadedOperatorName1')"><a name="hasOverloadedOperatorName1Anchor">hasOverloadedOperatorName</a></td><td>StringRef Name</td></tr>
+<tr><td colspan="4" class="doc" id="hasOverloadedOperatorName1"><pre>Matches overloaded operator names.
+
+Matches overloaded operator names specified in strings without the
+"operator" prefix: e.g. "&lt;&lt;".
+
+Given:
+ class A { int operator*(); };
+ const A &amp;operator&lt;&lt;(const A &amp;a, const A &amp;b);
+ A a;
+ a &lt;&lt; a; &lt;-- This matches
+
+operatorCallExpr(hasOverloadedOperatorName("&lt;&lt;"))) matches the specified
+line and recordDecl(hasMethod(hasOverloadedOperatorName("*"))) matches
+the declaration of A.
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>&gt;
</pre></td></tr>
@@ -755,8 +1538,8 @@ Example matches a &lt;&lt; b
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;</td><td class="name" onclick="toggle('isExplicitTemplateSpecialization0')"><a name="isExplicitTemplateSpecialization0Anchor">isExplicitTemplateSpecialization</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isExplicitTemplateSpecialization0"><pre>Matches explicit template specializations of function, class, or
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;</td><td class="name" onclick="toggle('isExplicitTemplateSpecialization2')"><a name="isExplicitTemplateSpecialization2Anchor">isExplicitTemplateSpecialization</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isExplicitTemplateSpecialization2"><pre>Matches explicit template specializations of function, class, or
static member variable template instantiations.
Given
@@ -769,8 +1552,14 @@ Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Functi
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;</td><td class="name" onclick="toggle('isTemplateInstantiation0')"><a name="isTemplateInstantiation0Anchor">isTemplateInstantiation</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isTemplateInstantiation0"><pre>Matches template instantiations of function, class, or static
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;</td><td class="name" onclick="toggle('isSameOrDerivedFrom1')"><a name="isSameOrDerivedFrom1Anchor">isSameOrDerivedFrom</a></td><td>StringRef BaseName</td></tr>
+<tr><td colspan="4" class="doc" id="isSameOrDerivedFrom1"><pre>Overloaded method as shortcut for
+isSameOrDerivedFrom(hasName(...)).
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;</td><td class="name" onclick="toggle('isTemplateInstantiation2')"><a name="isTemplateInstantiation2Anchor">isTemplateInstantiation</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isTemplateInstantiation2"><pre>Matches template instantiations of function, class, or static
member variable template instantiations.
Given
@@ -823,6 +1612,18 @@ compoundStmt(statementCountIs(0)))
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ConstantArrayType.html">ConstantArrayType</a>&gt;</td><td class="name" onclick="toggle('hasSize0')"><a name="hasSize0Anchor">hasSize</a></td><td>unsigned N</td></tr>
+<tr><td colspan="4" class="doc" id="hasSize0"><pre>Matches ConstantArrayType nodes that have the specified size.
+
+Given
+ int a[42];
+ int b[2 * 21];
+ int c[41], d[43];
+constantArrayType(hasSize(42))
+ matches "int a[42]" and "int b[2 * 21]"
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DeclStmt.html">DeclStmt</a>&gt;</td><td class="name" onclick="toggle('declCountIs0')"><a name="declCountIs0Anchor">declCountIs</a></td><td>unsigned N</td></tr>
<tr><td colspan="4" class="doc" id="declCountIs0"><pre>Matches declaration statements that contain a specific number of
declarations.
@@ -836,6 +1637,55 @@ declCountIs(2)
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('equalsNode0')"><a name="equalsNode0Anchor">equalsNode</a></td><td>Decl* Other</td></tr>
+<tr><td colspan="4" class="doc" id="equalsNode0"><pre>Matches if a node equals another node.
+
+Decl has pointer identity in the AST.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('isPrivate0')"><a name="isPrivate0Anchor">isPrivate</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isPrivate0"><pre>Matches private C++ declarations.
+
+Given
+ class C {
+ public: int a;
+ protected: int b;
+ private: int c;
+ };
+fieldDecl(isPrivate())
+ matches 'int c;'
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('isProtected0')"><a name="isProtected0Anchor">isProtected</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isProtected0"><pre>Matches protected C++ declarations.
+
+Given
+ class C {
+ public: int a;
+ protected: int b;
+ private: int c;
+ };
+fieldDecl(isProtected())
+ matches 'int b;'
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('isPublic0')"><a name="isPublic0Anchor">isPublic</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isPublic0"><pre>Matches public C++ declarations.
+
+Given
+ class C {
+ public: int a;
+ protected: int b;
+ private: int c;
+ };
+fieldDecl(isPublic())
+ matches 'int a;'
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>&gt;</td><td class="name" onclick="toggle('equals1')"><a name="equals1Anchor">equals</a></td><td>ValueT Value</td></tr>
<tr><td colspan="4" class="doc" id="equals1"><pre>Matches literals that are equal to the given value.
@@ -847,8 +1697,8 @@ Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Charac
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;</td><td class="name" onclick="toggle('isDefinition0')"><a name="isDefinition0Anchor">isDefinition</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isDefinition0"><pre>Matches if a declaration has a body attached.
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;</td><td class="name" onclick="toggle('isDefinition2')"><a name="isDefinition2Anchor">isDefinition</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isDefinition2"><pre>Matches if a declaration has a body attached.
Example matches A, va, fa
class A {};
@@ -862,8 +1712,8 @@ Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TagDec
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;</td><td class="name" onclick="toggle('isExplicitTemplateSpecialization2')"><a name="isExplicitTemplateSpecialization2Anchor">isExplicitTemplateSpecialization</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isExplicitTemplateSpecialization2"><pre>Matches explicit template specializations of function, class, or
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;</td><td class="name" onclick="toggle('isExplicitTemplateSpecialization0')"><a name="isExplicitTemplateSpecialization0Anchor">isExplicitTemplateSpecialization</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isExplicitTemplateSpecialization0"><pre>Matches explicit template specializations of function, class, or
static member variable template instantiations.
Given
@@ -888,8 +1738,8 @@ functionDecl(isExternC())
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;</td><td class="name" onclick="toggle('isTemplateInstantiation2')"><a name="isTemplateInstantiation2Anchor">isTemplateInstantiation</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isTemplateInstantiation2"><pre>Matches template instantiations of function, class, or static
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;</td><td class="name" onclick="toggle('isTemplateInstantiation0')"><a name="isTemplateInstantiation0Anchor">isTemplateInstantiation</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isTemplateInstantiation0"><pre>Matches template instantiations of function, class, or static
member variable template instantiations.
Given
@@ -909,6 +1759,17 @@ Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Functi
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt;</td><td class="name" onclick="toggle('parameterCountIs0')"><a name="parameterCountIs0Anchor">parameterCountIs</a></td><td>unsigned N</td></tr>
+<tr><td colspan="4" class="doc" id="parameterCountIs0"><pre>Matches FunctionDecls that have a specific parameter count.
+
+Given
+ void f(int i) {}
+ void g(int i, int j) {}
+functionDecl(parameterCountIs(2))
+ matches g(int i, int j) {}
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>&gt;</td><td class="name" onclick="toggle('equals0')"><a name="equals0Anchor">equals</a></td><td>ValueT Value</td></tr>
<tr><td colspan="4" class="doc" id="equals0"><pre>Matches literals that are equal to the given value.
@@ -953,8 +1814,8 @@ Example matches X (Name is one of "::a::b::X", "a::b::X", "b::X", "X")
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>&gt;</td><td class="name" onclick="toggle('matchesName0')"><a name="matchesName0Anchor">matchesName</a></td><td>std::string RegExp</td></tr>
-<tr><td colspan="4" class="doc" id="matchesName0"><pre>Matches NamedDecl nodes whose full names partially match the
-given RegExp.
+<tr><td colspan="4" class="doc" id="matchesName0"><pre>Matches NamedDecl nodes whose fully qualified names contain
+a substring matched by the given RegExp.
Supports specifying enclosing namespaces or classes by
prefixing the name with '&lt;enclosing&gt;::'. Does not match typedefs
@@ -979,6 +1840,21 @@ callExpr(on(hasType(asString("class Y *"))))
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;</td><td class="name" onclick="toggle('hasLocalQualifiers0')"><a name="hasLocalQualifiers0Anchor">hasLocalQualifiers</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="hasLocalQualifiers0"><pre>Matches QualType nodes that have local CV-qualifiers attached to
+the node, not hidden within a typedef.
+
+Given
+ typedef const int const_int;
+ const_int i;
+ int *const j;
+ int *volatile k;
+ int m;
+varDecl(hasType(hasLocalQualifiers())) matches only j and k.
+i is const-qualified but the qualifier is not local.
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;</td><td class="name" onclick="toggle('isConstQualified0')"><a name="isConstQualified0Anchor">isConstQualified</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isConstQualified0"><pre>Matches QualType nodes that are const-qualified, i.e., that
include "top-level" const.
@@ -1008,8 +1884,16 @@ matches "a(int)", "b(long)", but not "c(double)".
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>&gt;</td><td class="name" onclick="toggle('isDefinition2')"><a name="isDefinition2Anchor">isDefinition</a></td><td></td></tr>
-<tr><td colspan="4" class="doc" id="isDefinition2"><pre>Matches if a declaration has a body attached.
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('equalsNode1')"><a name="equalsNode1Anchor">equalsNode</a></td><td>Stmt* Other</td></tr>
+<tr><td colspan="4" class="doc" id="equalsNode1"><pre>Matches if a node equals another node.
+
+Stmt has pointer identity in the AST.
+
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>&gt;</td><td class="name" onclick="toggle('isDefinition0')"><a name="isDefinition0Anchor">isDefinition</a></td><td></td></tr>
+<tr><td colspan="4" class="doc" id="isDefinition0"><pre>Matches if a declaration has a body attached.
Example matches A, va, fa
class A {};
@@ -1110,6 +1994,40 @@ match expressions.</p>
<tr style="text-align:left"><th>Return type</th><th>Name</th><th>Parameters</th></tr>
<!-- START_TRAVERSAL_MATCHERS -->
+<tr><td>Matcher&lt;*&gt;</td><td class="name" onclick="toggle('eachOf0')"><a name="eachOf0Anchor">eachOf</a></td><td>Matcher&lt;*&gt; P1, Matcher&lt;*&gt; P2</td></tr>
+<tr><td colspan="4" class="doc" id="eachOf0"><pre>Matches if any of the given matchers matches.
+
+Unlike anyOf, eachOf will generate a match result for each
+matching submatcher.
+
+For example, in:
+ class A { int a; int b; };
+The matcher:
+ recordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")),
+ has(fieldDecl(hasName("b")).bind("v"))))
+will generate two results binding "v", the first of which binds
+the field declaration of a, the second the field declaration of
+b.
+
+Usable as: Any Matcher
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt;*&gt;</td><td class="name" onclick="toggle('findAll0')"><a name="findAll0Anchor">findAll</a></td><td>Matcher&lt;T&gt; Matcher</td></tr>
+<tr><td colspan="4" class="doc" id="findAll0"><pre>Matches if the node or any descendant matches.
+
+Generates results for each match.
+
+For example, in:
+ class A { class B {}; class C {}; };
+The matcher:
+ recordDecl(hasName("::A"), findAll(recordDecl(isDefinition()).bind("m")))
+will generate results for A, B and C.
+
+Usable as: Any Matcher
+</pre></td></tr>
+
+
<tr><td>Matcher&lt;*&gt;</td><td class="name" onclick="toggle('forEach0')"><a name="forEach0Anchor">forEach</a></td><td>Matcher&lt;ChildT&gt; ChildMatcher</td></tr>
<tr><td colspan="4" class="doc" id="forEach0"><pre>Matches AST nodes that have child AST nodes that match the
provided matcher.
@@ -1174,7 +2092,7 @@ matcher.
Given
void f() { if (true) { int x = 42; } }
void g() { for (;;) { int x = 43; } }
-expr(integerLiteral(hasAncsestor(ifStmt()))) matches 42, but not 43.
+expr(integerLiteral(hasAncestor(ifStmt()))) matches 42, but not 43.
Usable as: Any Matcher
</pre></td></tr>
@@ -1196,6 +2114,18 @@ Usable as: Any Matcher
</pre></td></tr>
+<tr><td>Matcher&lt;*&gt;</td><td class="name" onclick="toggle('hasParent0')"><a name="hasParent0Anchor">hasParent</a></td><td>Matcher&lt;ParentT&gt; ParentMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasParent0"><pre>Matches AST nodes that have a parent that matches the provided
+matcher.
+
+Given
+void f() { for (;;) { int x = 42; if (true) { int x = 43; } } }
+compoundStmt(hasParent(ifStmt())) matches "{ int x = 43; }".
+
+Usable as: Any Matcher
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ArraySubscriptExpr.html">ArraySubscriptExpr</a>&gt;</td><td class="name" onclick="toggle('hasBase0')"><a name="hasBase0Anchor">hasBase</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasBase0"><pre>Matches the base expression of an array subscript expression.
@@ -1219,6 +2149,78 @@ arraySubscriptExpression(hasIndex(integerLiteral()))
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayTypeLoc.html">ArrayTypeLoc</a>&gt;</td><td class="name" onclick="toggle('hasElementTypeLoc1')"><a name="hasElementTypeLoc1Anchor">hasElementTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" id="hasElementTypeLoc1"><pre>Matches arrays and C99 complex types that have a specific element
+type.
+
+Given
+ struct A {};
+ A a[7];
+ int b[7];
+arrayType(hasElementType(builtinType()))
+ matches "int b[7]"
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayType.html">ArrayType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexType.html">ComplexType</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayType.html">ArrayType</a>&gt;</td><td class="name" onclick="toggle('hasElementType1')"><a name="hasElementType1Anchor">hasElementType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" id="hasElementType1"><pre>Matches arrays and C99 complex types that have a specific element
+type.
+
+Given
+ struct A {};
+ A a[7];
+ int b[7];
+arrayType(hasElementType(builtinType()))
+ matches "int b[7]"
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayType.html">ArrayType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexType.html">ComplexType</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1AtomicTypeLoc.html">AtomicTypeLoc</a>&gt;</td><td class="name" onclick="toggle('hasValueTypeLoc0')"><a name="hasValueTypeLoc0Anchor">hasValueTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" id="hasValueTypeLoc0"><pre>Matches atomic types with a specific value type.
+
+Given
+ _Atomic(int) i;
+ _Atomic(float) f;
+atomicType(hasValueType(isInteger()))
+ matches "_Atomic(int) i"
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1AtomicType.html">AtomicType</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1AtomicType.html">AtomicType</a>&gt;</td><td class="name" onclick="toggle('hasValueType0')"><a name="hasValueType0Anchor">hasValueType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" id="hasValueType0"><pre>Matches atomic types with a specific value type.
+
+Given
+ _Atomic(int) i;
+ _Atomic(float) f;
+atomicType(hasValueType(isInteger()))
+ matches "_Atomic(int) i"
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1AtomicType.html">AtomicType</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1AutoType.html">AutoType</a>&gt;</td><td class="name" onclick="toggle('hasDeducedType0')"><a name="hasDeducedType0Anchor">hasDeducedType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeducedType0"><pre>Matches AutoType nodes where the deduced type is a specific type.
+
+Note: There is no TypeLoc for the deduced type and thus no
+getDeducedLoc() matcher.
+
+Given
+ auto a = 1;
+ auto b = 2.0;
+autoType(hasDeducedType(isInteger()))
+ matches "auto a"
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1AutoType.html">AutoType</a>&gt;
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>&gt;</td><td class="name" onclick="toggle('hasEitherOperand0')"><a name="hasEitherOperand0Anchor">hasEitherOperand</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasEitherOperand0"><pre>Matches if either the left hand side or the right hand side of a
binary operator matches.
@@ -1241,11 +2243,49 @@ Example matches b (matcher = binaryOperator(hasRHS()))
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration0')"><a name="hasDeclaration0Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasDeclaration0"><pre>Matches a type if the declaration of the type matches the given
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerTypeLoc.html">BlockPointerTypeLoc</a>&gt;</td><td class="name" onclick="toggle('pointeeLoc3')"><a name="pointeeLoc3Anchor">pointeeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" id="pointeeLoc3"><pre>Narrows PointerType (and similar) matchers to those where the
+pointee matches a given matcher.
+
+Given
+ int *a;
+ int const *b;
+ float const *f;
+pointerType(pointee(isConstQualified(), isInteger()))
+ matches "int const *b"
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>&gt;</td><td class="name" onclick="toggle('pointee3')"><a name="pointee3Anchor">pointee</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" id="pointee3"><pre>Narrows PointerType (and similar) matchers to those where the
+pointee matches a given matcher.
+
+Given
+ int *a;
+ int const *b;
+ float const *f;
+pointerType(pointee(isConstQualified(), isInteger()))
+ matches "int const *b"
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration3')"><a name="hasDeclaration3Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration3"><pre>Matches a type if the declaration of the type matches the given
matcher.
-Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;
+In addition to being usable as Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;, also usable as
+Matcher&lt;T&gt; for any T supporting the getDecl() member function. e.g. various
+subtypes of clang::Type.
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;
</pre></td></tr>
@@ -1331,9 +2371,15 @@ Example matches A() in the last line
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;</td><td class="name" onclick="toggle('isA0')"><a name="isA0Anchor">isA</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>&gt; Base</td></tr>
-<tr><td colspan="4" class="doc" id="isA0"><pre>Similar to isDerivedFrom(), but also matches classes that directly
-match Base.
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;</td><td class="name" onclick="toggle('hasMethod0')"><a name="hasMethod0Anchor">hasMethod</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasMethod0"><pre>Matches the first method of a class or struct that satisfies InnerMatcher.
+
+Given:
+ class A { void func(); };
+ class B { void member(); };
+
+recordDecl(hasMethod(hasName("func"))) matches the declaration of A
+but not B.
</pre></td></tr>
@@ -1358,6 +2404,12 @@ In the following example, Bar matches isDerivedFrom(hasName("X")):
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;</td><td class="name" onclick="toggle('isSameOrDerivedFrom0')"><a name="isSameOrDerivedFrom0Anchor">isSameOrDerivedFrom</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>&gt; Base</td></tr>
+<tr><td colspan="4" class="doc" id="isSameOrDerivedFrom0"><pre>Similar to isDerivedFrom(), but also matches classes that directly
+match Base.
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;</td><td class="name" onclick="toggle('callee1')"><a name="callee1Anchor">callee</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="callee1"><pre>Matches if the call expression's callee's declaration matches the
given matcher.
@@ -1391,11 +2443,17 @@ Example matches y in x(y)
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration1')"><a name="hasDeclaration1Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasDeclaration1"><pre>Matches a type if the declaration of the type matches the given
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration4')"><a name="hasDeclaration4Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration4"><pre>Matches a type if the declaration of the type matches the given
matcher.
-Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;
+In addition to being usable as Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;, also usable as
+Matcher&lt;T&gt; for any T supporting the getDecl() member function. e.g. various
+subtypes of clang::Type.
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;
</pre></td></tr>
@@ -1437,6 +2495,36 @@ classTemplateSpecializationDecl(hasTemplateArgument(
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexTypeLoc.html">ComplexTypeLoc</a>&gt;</td><td class="name" onclick="toggle('hasElementTypeLoc0')"><a name="hasElementTypeLoc0Anchor">hasElementTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" id="hasElementTypeLoc0"><pre>Matches arrays and C99 complex types that have a specific element
+type.
+
+Given
+ struct A {};
+ A a[7];
+ int b[7];
+arrayType(hasElementType(builtinType()))
+ matches "int b[7]"
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayType.html">ArrayType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexType.html">ComplexType</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexType.html">ComplexType</a>&gt;</td><td class="name" onclick="toggle('hasElementType0')"><a name="hasElementType0Anchor">hasElementType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" id="hasElementType0"><pre>Matches arrays and C99 complex types that have a specific element
+type.
+
+Given
+ struct A {};
+ A a[7];
+ int b[7];
+arrayType(hasElementType(builtinType()))
+ matches "int b[7]"
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayType.html">ArrayType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexType.html">ComplexType</a>&gt;
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CompoundStmt.html">CompoundStmt</a>&gt;</td><td class="name" onclick="toggle('hasAnySubstatement0')"><a name="hasAnySubstatement0Anchor">hasAnySubstatement</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasAnySubstatement0"><pre>Matches compound statements where at least one substatement matches
a given matcher.
@@ -1534,6 +2622,22 @@ declStmt(hasSingleDecl(anything()))
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('hasDeclContext0')"><a name="hasDeclContext0Anchor">hasDeclContext</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclContext0"><pre>Matches declarations whose declaration context, interpreted as a
+Decl, matches InnerMatcher.
+
+Given
+ namespace N {
+ namespace M {
+ class D {};
+ }
+ }
+
+recordDecl(hasDeclContext(namedDecl(hasName("M")))) matches the
+declaration of class D.
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1DoStmt.html">DoStmt</a>&gt;</td><td class="name" onclick="toggle('hasBody0')"><a name="hasBody0Anchor">hasBody</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasBody0"><pre>Matches a 'for', 'while', or 'do while' statement that has
a given body.
@@ -1556,6 +2660,40 @@ Example matches true (matcher = hasCondition(boolLiteral(equals(true))))
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ElaboratedType.html">ElaboratedType</a>&gt;</td><td class="name" onclick="toggle('hasQualifier0')"><a name="hasQualifier0Anchor">hasQualifier</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasQualifier0"><pre>Matches ElaboratedTypes whose qualifier, a NestedNameSpecifier,
+matches InnerMatcher if the qualifier exists.
+
+Given
+ namespace N {
+ namespace M {
+ class D {};
+ }
+ }
+ N::M::D d;
+
+elaboratedType(hasQualifier(hasPrefix(specifiesNamespace(hasName("N"))))
+matches the type of the variable declaration of d.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ElaboratedType.html">ElaboratedType</a>&gt;</td><td class="name" onclick="toggle('namesType0')"><a name="namesType0Anchor">namesType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="namesType0"><pre>Matches ElaboratedTypes whose named type matches InnerMatcher.
+
+Given
+ namespace N {
+ namespace M {
+ class D {};
+ }
+ }
+ N::M::D d;
+
+elaboratedType(namesType(recordType(
+hasDeclaration(namedDecl(hasName("D")))))) matches the type of the variable
+declaration of d.
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ExplicitCastExpr.html">ExplicitCastExpr</a>&gt;</td><td class="name" onclick="toggle('hasDestinationType0')"><a name="hasDestinationType0Anchor">hasDestinationType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasDestinationType0"><pre>Matches casts whose destination type matches a given matcher.
@@ -1753,6 +2891,20 @@ FIXME: Unit test this matcher
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration2')"><a name="hasDeclaration2Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration2"><pre>Matches a type if the declaration of the type matches the given
+matcher.
+
+In addition to being usable as Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;, also usable as
+Matcher&lt;T&gt; for any T supporting the getDecl() member function. e.g. various
+subtypes of clang::Type.
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;</td><td class="name" onclick="toggle('hasObjectExpression0')"><a name="hasObjectExpression0Anchor">hasObjectExpression</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasObjectExpression0"><pre>Matches a member expression where the object expression is
matched by a given matcher.
@@ -1781,11 +2933,173 @@ memberExpr(member(hasName("first")))
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration2')"><a name="hasDeclaration2Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasDeclaration2"><pre>Matches a type if the declaration of the type matches the given
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerTypeLoc.html">MemberPointerTypeLoc</a>&gt;</td><td class="name" onclick="toggle('pointeeLoc2')"><a name="pointeeLoc2Anchor">pointeeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" id="pointeeLoc2"><pre>Narrows PointerType (and similar) matchers to those where the
+pointee matches a given matcher.
+
+Given
+ int *a;
+ int const *b;
+ float const *f;
+pointerType(pointee(isConstQualified(), isInteger()))
+ matches "int const *b"
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>&gt;</td><td class="name" onclick="toggle('pointee2')"><a name="pointee2Anchor">pointee</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" id="pointee2"><pre>Narrows PointerType (and similar) matchers to those where the
+pointee matches a given matcher.
+
+Given
+ int *a;
+ int const *b;
+ float const *f;
+pointerType(pointee(isConstQualified(), isInteger()))
+ matches "int const *b"
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>&gt;</td><td class="name" onclick="toggle('hasPrefix1')"><a name="hasPrefix1Anchor">hasPrefix</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasPrefix1"><pre>Matches on the prefix of a NestedNameSpecifierLoc.
+
+Given
+ struct A { struct B { struct C {}; }; };
+ A::B::C c;
+nestedNameSpecifierLoc(hasPrefix(loc(specifiesType(asString("struct A")))))
+ matches "A::"
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>&gt;</td><td class="name" onclick="toggle('loc1')"><a name="loc1Anchor">loc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="loc1"><pre>Matches NestedNameSpecifierLocs for which the given inner
+NestedNameSpecifier-matcher matches.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>&gt;</td><td class="name" onclick="toggle('specifiesTypeLoc0')"><a name="specifiesTypeLoc0Anchor">specifiesTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="specifiesTypeLoc0"><pre>Matches nested name specifier locs that specify a type matching the
+given TypeLoc.
+
+Given
+ struct A { struct B { struct C {}; }; };
+ A::B::C c;
+nestedNameSpecifierLoc(specifiesTypeLoc(loc(type(
+ hasDeclaration(recordDecl(hasName("A")))))))
+ matches "A::"
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>&gt;</td><td class="name" onclick="toggle('hasPrefix0')"><a name="hasPrefix0Anchor">hasPrefix</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasPrefix0"><pre>Matches on the prefix of a NestedNameSpecifier.
+
+Given
+ struct A { struct B { struct C {}; }; };
+ A::B::C c;
+nestedNameSpecifier(hasPrefix(specifiesType(asString("struct A")))) and
+ matches "A::"
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>&gt;</td><td class="name" onclick="toggle('specifiesNamespace0')"><a name="specifiesNamespace0Anchor">specifiesNamespace</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NamespaceDecl.html">NamespaceDecl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="specifiesNamespace0"><pre>Matches nested name specifiers that specify a namespace matching the
+given namespace matcher.
+
+Given
+ namespace ns { struct A {}; }
+ ns::A a;
+nestedNameSpecifier(specifiesNamespace(hasName("ns")))
+ matches "ns::"
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>&gt;</td><td class="name" onclick="toggle('specifiesType0')"><a name="specifiesType0Anchor">specifiesType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="specifiesType0"><pre>Matches nested name specifiers that specify a type matching the
+given QualType matcher without qualifiers.
+
+Given
+ struct A { struct B { struct C {}; }; };
+ A::B::C c;
+nestedNameSpecifier(specifiesType(hasDeclaration(recordDecl(hasName("A")))))
+ matches "A::"
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ParenType.html">ParenType</a>&gt;</td><td class="name" onclick="toggle('innerType0')"><a name="innerType0Anchor">innerType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" id="innerType0"><pre>Matches ParenType nodes where the inner type is a specific type.
+
+Given
+ int (*ptr_to_array)[4];
+ int (*ptr_to_func)(int);
+
+varDecl(hasType(pointsTo(parenType(innerType(functionType()))))) matches
+ptr_to_func but not ptr_to_array.
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ParenType.html">ParenType</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerTypeLoc.html">PointerTypeLoc</a>&gt;</td><td class="name" onclick="toggle('pointeeLoc1')"><a name="pointeeLoc1Anchor">pointeeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" id="pointeeLoc1"><pre>Narrows PointerType (and similar) matchers to those where the
+pointee matches a given matcher.
+
+Given
+ int *a;
+ int const *b;
+ float const *f;
+pointerType(pointee(isConstQualified(), isInteger()))
+ matches "int const *b"
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>&gt;</td><td class="name" onclick="toggle('pointee1')"><a name="pointee1Anchor">pointee</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" id="pointee1"><pre>Narrows PointerType (and similar) matchers to those where the
+pointee matches a given matcher.
+
+Given
+ int *a;
+ int const *b;
+ float const *f;
+pointerType(pointee(isConstQualified(), isInteger()))
+ matches "int const *b"
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;</td><td class="name" onclick="toggle('hasCanonicalType0')"><a name="hasCanonicalType0Anchor">hasCanonicalType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasCanonicalType0"><pre>Matches QualTypes whose canonical type matches InnerMatcher.
+
+Given:
+ typedef int &amp;int_ref;
+ int a;
+ int_ref b = a;
+
+varDecl(hasType(qualType(referenceType()))))) will not match the
+declaration of b but varDecl(hasType(qualType(hasCanonicalType(referenceType())))))) does.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration5')"><a name="hasDeclaration5Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration5"><pre>Matches a type if the declaration of the type matches the given
matcher.
-Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;
+In addition to being usable as Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;, also usable as
+Matcher&lt;T&gt; for any T supporting the getDecl() member function. e.g. various
+subtypes of clang::Type.
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;
</pre></td></tr>
@@ -1799,6 +3113,38 @@ Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualTy
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceTypeLoc.html">ReferenceTypeLoc</a>&gt;</td><td class="name" onclick="toggle('pointeeLoc0')"><a name="pointeeLoc0Anchor">pointeeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" id="pointeeLoc0"><pre>Narrows PointerType (and similar) matchers to those where the
+pointee matches a given matcher.
+
+Given
+ int *a;
+ int const *b;
+ float const *f;
+pointerType(pointee(isConstQualified(), isInteger()))
+ matches "int const *b"
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>&gt;</td><td class="name" onclick="toggle('pointee0')"><a name="pointee0Anchor">pointee</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" id="pointee0"><pre>Narrows PointerType (and similar) matchers to those where the
+pointee matches a given matcher.
+
+Given
+ int *a;
+ int const *b;
+ float const *f;
+pointerType(pointee(isConstQualified(), isInteger()))
+ matches "int const *b"
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>&gt;
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('alignOfExpr0')"><a name="alignOfExpr0Anchor">alignOfExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryExprOrTypeTraitExpr.html">UnaryExprOrTypeTraitExpr</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="alignOfExpr0"><pre>Same as unaryExprOrTypeTraitExpr, but only matching
alignof.
@@ -1838,6 +3184,40 @@ classTemplateSpecializationDecl(hasAnyTemplateArgument(
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration0')"><a name="hasDeclaration0Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration0"><pre>Matches a type if the declaration of the type matches the given
+matcher.
+
+In addition to being usable as Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;, also usable as
+Matcher&lt;T&gt; for any T supporting the getDecl() member function. e.g. various
+subtypes of clang::Type.
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('loc0')"><a name="loc0Anchor">loc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="loc0"><pre>Matches TypeLocs for which the given inner
+QualType-matcher matches.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration1')"><a name="hasDeclaration1Anchor">hasDeclaration</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasDeclaration1"><pre>Matches a type if the declaration of the type matches the given
+matcher.
+
+In addition to being usable as Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;, also usable as
+Matcher&lt;T&gt; for any T supporting the getDecl() member function. e.g. various
+subtypes of clang::Type.
+
+Usable as: Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXConstructExpr.html">CXXConstructExpr</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>&gt;, Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;,
+ Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TemplateSpecializationType.html">TemplateSpecializationType</a>&gt;
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryExprOrTypeTraitExpr.html">UnaryExprOrTypeTraitExpr</a>&gt;</td><td class="name" onclick="toggle('hasArgumentOfType0')"><a name="hasArgumentOfType0Anchor">hasArgumentOfType</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasArgumentOfType0"><pre>Matches unary expressions that have a specific type of argument.
@@ -1851,7 +3231,7 @@ unaryExprOrTypeTraitExpr(hasArgumentOfType(asString("int"))
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryOperator.html">UnaryOperator</a>&gt;</td><td class="name" onclick="toggle('hasUnaryOperand0')"><a name="hasUnaryOperand0Anchor">hasUnaryOperand</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasUnaryOperand0"><pre>Matches if the operand of a unary operator matches.
-Example matches true (matcher = hasOperand(boolLiteral(equals(true))))
+Example matches true (matcher = hasUnaryOperand(boolLiteral(equals(true))))
!true
</pre></td></tr>
@@ -1907,6 +3287,20 @@ Example matches x (matcher = varDecl(hasInitializer(callExpr())))
</pre></td></tr>
+<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1VariableArrayType.html">VariableArrayType</a>&gt;</td><td class="name" onclick="toggle('hasSizeExpr0')"><a name="hasSizeExpr0Anchor">hasSizeExpr</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasSizeExpr0"><pre>Matches VariableArrayType nodes that have a specific size
+expression.
+
+Given
+ void f(int b) {
+ int a[b];
+ }
+variableArrayType(hasSizeExpr(ignoringImpCasts(declRefExpr(to(
+ varDecl(hasName("b")))))))
+ matches "int a[b]"
+</pre></td></tr>
+
+
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1WhileStmt.html">WhileStmt</a>&gt;</td><td class="name" onclick="toggle('hasBody2')"><a name="hasBody2Anchor">hasBody</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasBody2"><pre>Matches a 'for', 'while', or 'do while' statement that has
a given body.
diff --git a/docs/LibASTMatchersTutorial.rst b/docs/LibASTMatchersTutorial.rst
new file mode 100644
index 0000000..ba568e3
--- /dev/null
+++ b/docs/LibASTMatchersTutorial.rst
@@ -0,0 +1,538 @@
+===============================================================
+Tutorial for building tools using LibTooling and LibASTMatchers
+===============================================================
+
+This document is intended to show how to build a useful source-to-source
+translation tool based on Clang's `LibTooling <LibTooling.html>`_. It is
+explicitly aimed at people who are new to Clang, so all you should need
+is a working knowledge of C++ and the command line.
+
+In order to work on the compiler, you need some basic knowledge of the
+abstract syntax tree (AST). To this end, the reader is incouraged to
+skim the :doc:`Introduction to the Clang
+AST <IntroductionToTheClangAST>`
+
+Step 0: Obtaining Clang
+=======================
+
+As Clang is part of the LLVM project, you'll need to download LLVM's
+source code first. Both Clang and LLVM are maintained as Subversion
+repositories, but we'll be accessing them through the git mirror. For
+further information, see the `getting started
+guide <http://llvm.org/docs/GettingStarted.html>`_.
+
+.. code-block:: console
+
+ mkdir ~/clang-llvm && cd ~/clang-llvm
+ git clone http://llvm.org/git/llvm.git
+ cd llvm/tools
+ git clone http://llvm.org/git/clang.git
+
+Next you need to obtain the CMake build system and Ninja build tool. You
+may already have CMake installed, but current binary versions of CMake
+aren't built with Ninja support.
+
+.. code-block:: console
+
+ cd ~/clang-llvm
+ git clone https://github.com/martine/ninja.git
+ cd ninja
+ git checkout release
+ ./bootstrap.py
+ sudo cp ninja /usr/bin/
+
+ cd ~/clang-llvm
+ git clone git://cmake.org/stage/cmake.git
+ cd cmake
+ git checkout next
+ ./bootstrap
+ make
+ sudo make install
+
+Okay. Now we'll build Clang!
+
+.. code-block:: console
+
+ cd ~/clang-llvm
+ mkdir build && cd build
+ cmake -G Ninja ../llvm -DLLVM_BUILD_TESTS=ON # Enable tests; default is off.
+ ninja
+ ninja check # Test LLVM only.
+ ninja clang-test # Test Clang only.
+ ninja install
+
+And we're live.
+
+All of the tests should pass, though there is a (very) small chance that
+you can catch LLVM and Clang out of sync. Running ``'git svn rebase'``
+in both the llvm and clang directories should fix any problems.
+
+Finally, we want to set Clang as its own compiler.
+
+.. code-block:: console
+
+ cd ~/clang-llvm/build
+ ccmake ../llvm
+
+The second command will bring up a GUI for configuring Clang. You need
+to set the entry for ``CMAKE_CXX_COMPILER``. Press ``'t'`` to turn on
+advanced mode. Scroll down to ``CMAKE_CXX_COMPILER``, and set it to
+``/usr/bin/clang++``, or wherever you installed it. Press ``'c'`` to
+configure, then ``'g'`` to generate CMake's files.
+
+Finally, run ninja one last time, and you're done.
+
+Step 1: Create a ClangTool
+==========================
+
+Now that we have enough background knowledge, it's time to create the
+simplest productive ClangTool in existence: a syntax checker. While this
+already exists as ``clang-check``, it's important to understand what's
+going on.
+
+First, we'll need to create a new directory for our tool and tell CMake
+that it exists. As this is not going to be a core clang tool, it will
+live in the ``tools/extra`` repository.
+
+.. code-block:: console
+
+ cd ~/clang-llvm/llvm/tools/clang
+ mkdir tools/extra/loop-convert
+ echo 'add_subdirectory(loop-convert)' >> tools/extra/CMakeLists.txt
+ vim tools/extra/loop-convert/CMakeLists.txt
+
+CMakeLists.txt should have the following contents:
+
+::
+
+ set(LLVM_LINK_COMPONENTS support)
+ set(LLVM_USED_LIBS clangTooling clangBasic clangAST)
+
+ add_clang_executable(loop-convert
+ LoopConvert.cpp
+ )
+ target_link_libraries(loop-convert
+ clangTooling
+ clangBasic
+ clangASTMatchers
+ )
+
+With that done, Ninja will be able to compile our tool. Let's give it
+something to compile! Put the following into
+``tools/extra/loop-convert/LoopConvert.cpp``. A detailed explanation of
+why the different parts are needed can be found in the `LibTooling
+documentation <LibTooling.html>`_.
+
+.. code-block:: c++
+
+ // Declares clang::SyntaxOnlyAction.
+ #include "clang/Frontend/FrontendActions.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;
+
+ // 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);
+
+ // 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) {
+ CommonOptionsParser OptionsParser(argc, argv);
+ ClangTool Tool(OptionsParser.getCompilations(),
+ OptionsParser.getSourcePathList());
+ return Tool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>());
+ }
+
+And that's it! You can compile our new tool by running ninja from the
+``build`` directory.
+
+.. code-block:: console
+
+ cd ~/clang-llvm/build
+ ninja
+
+You should now be able to run the syntax checker, which is located in
+``~/clang-llvm/build/bin``, on any source file. Try it!
+
+.. code-block:: console
+
+ cat "void main() {}" > test.cpp
+ bin/loop-convert test.cpp --
+
+Note the two dashes after we specify the source file. The additional
+options for the compiler are passed after the dashes rather than loading
+them from a compilation database - there just aren't any options needed
+right now.
+
+Intermezzo: Learn AST matcher basics
+====================================
+
+Clang recently introduced the :doc:`ASTMatcher
+library <LibASTMatchers>` to provide a simple, powerful, and
+concise way to describe specific patterns in the AST. Implemented as a
+DSL powered by macros and templates (see
+`ASTMatchers.h <../doxygen/ASTMatchers_8h_source.html>`_ if you're
+curious), matchers offer the feel of algebraic data types common to
+functional programming languages.
+
+For example, suppose you wanted to examine only binary operators. There
+is a matcher to do exactly that, conveniently named ``binaryOperator``.
+I'll give you one guess what this matcher does:
+
+.. code-block:: c++
+
+ binaryOperator(hasOperatorName("+"), hasLHS(integerLiteral(equals(0))))
+
+Shockingly, it will match against addition expressions whose left hand
+side is exactly the literal 0. It will not match against other forms of
+0, such as ``'\0'`` or ``NULL``, but it will match against macros that
+expand to 0. The matcher will also not match against calls to the
+overloaded operator ``'+'``, as there is a separate ``operatorCallExpr``
+matcher to handle overloaded operators.
+
+There are AST matchers to match all the different nodes of the AST,
+narrowing matchers to only match AST nodes fulfilling specific criteria,
+and traversal matchers to get from one kind of AST node to another. For
+a complete list of AST matchers, take a look at the `AST Matcher
+References <LibASTMatchersReference.html>`_
+
+All matcher that are nouns describe entities in the AST and can be
+bound, so that they can be referred to whenever a match is found. To do
+so, simply call the method ``bind`` on these matchers, e.g.:
+
+.. code-block:: c++
+
+ variable(hasType(isInteger())).bind("intvar")
+
+Step 2: Using AST matchers
+==========================
+
+Okay, on to using matchers for real. Let's start by defining a matcher
+which will capture all ``for`` statements that define a new variable
+initialized to zero. Let's start with matching all ``for`` loops:
+
+.. code-block:: c++
+
+ forStmt()
+
+Next, we want to specify that a single variable is declared in the first
+portion of the loop, so we can extend the matcher to
+
+.. code-block:: c++
+
+ forStmt(hasLoopInit(declStmt(hasSingleDecl(varDecl()))))
+
+Finally, we can add the condition that the variable is initialized to
+zero.
+
+.. code-block:: c++
+
+ forStmt(hasLoopInit(declStmt(hasSingleDecl(varDecl(
+ hasInitializer(integerLiteral(equals(0))))))))
+
+It is fairly easy to read and understand the matcher definition ("match
+loops whose init portion declares a single variable which is initialized
+to the integer literal 0"), but deciding that every piece is necessary
+is more difficult. Note that this matcher will not match loops whose
+variables are initialized to ``'\0'``, ``0.0``, ``NULL``, or any form of
+zero besides the integer 0.
+
+The last step is giving the matcher a name and binding the ``ForStmt``
+as we will want to do something with it:
+
+.. code-block:: c++
+
+ StatementMatcher LoopMatcher =
+ forStmt(hasLoopInit(declStmt(hasSingleDecl(varDecl(
+ hasInitializer(integerLiteral(equals(0)))))))).bind("forLoop");
+
+Once you have defined your matchers, you will need to add a little more
+scaffolding in order to run them. Matchers are paired with a
+``MatchCallback`` and registered with a ``MatchFinder`` object, then run
+from a ``ClangTool``. More code!
+
+Add the following to ``LoopConvert.cpp``:
+
+.. code-block:: c++
+
+ #include "clang/ASTMatchers/ASTMatchers.h"
+ #include "clang/ASTMatchers/ASTMatchFinder.h"
+
+ using namespace clang;
+ using namespace clang::ast_matchers;
+
+ StatementMatcher LoopMatcher =
+ forStmt(hasLoopInit(declStmt(hasSingleDecl(varDecl(
+ hasInitializer(integerLiteral(equals(0)))))))).bind("forLoop");
+
+ class LoopPrinter : public MatchFinder::MatchCallback {
+ public :
+ virtual void run(const MatchFinder::MatchResult &Result) {
+ if (const ForStmt *FS = Result.Nodes.getNodeAs<clang::ForStmt>("forLoop"))
+ FS->dump();
+ };
+
+And change ``main()`` to:
+
+.. code-block:: c++
+
+ int main(int argc, const char **argv) {
+ CommonOptionsParser OptionsParser(argc, argv);
+ ClangTool Tool(OptionsParser.getCompilations(),
+ OptionsParser.getSourcePathList());
+
+ LoopPrinter Printer;
+ MatchFinder Finder;
+ Finder.addMatcher(LoopMatcher, &Printer);
+
+ return Tool.run(newFrontendActionFactory(&Finder));
+ }
+
+Now, you should be able to recompile and run the code to discover for
+loops. Create a new file with a few examples, and test out our new
+handiwork:
+
+.. code-block:: console
+
+ cd ~/clang-llvm/llvm/llvm_build/
+ ninja loop-convert
+ vim ~/test-files/simple-loops.cc
+ bin/loop-convert ~/test-files/simple-loops.cc
+
+Step 3.5: More Complicated Matchers
+===================================
+
+Our simple matcher is capable of discovering for loops, but we would
+still need to filter out many more ourselves. We can do a good portion
+of the remaining work with some cleverly chosen matchers, but first we
+need to decide exactly which properties we want to allow.
+
+How can we characterize for loops over arrays which would be eligible
+for translation to range-based syntax? Range based loops over arrays of
+size ``N`` that:
+
+- start at index ``0``
+- iterate consecutively
+- end at index ``N-1``
+
+We already check for (1), so all we need to add is a check to the loop's
+condition to ensure that the loop's index variable is compared against
+``N`` and another check to ensure that the increment step just
+increments this same variable. The matcher for (2) is straightforward:
+require a pre- or post-increment of the same variable declared in the
+init portion.
+
+Unfortunately, such a matcher is impossible to write. Matchers contain
+no logic for comparing two arbitrary AST nodes and determining whether
+or not they are equal, so the best we can do is matching more than we
+would like to allow, and punting extra comparisons to the callback.
+
+In any case, we can start building this sub-matcher. We can require that
+the increment step be a unary increment like this:
+
+.. code-block:: c++
+
+ hasIncrement(unaryOperator(hasOperatorName("++")))
+
+Specifying what is incremented introduces another quirk of Clang's AST:
+Usages of variables are represented as ``DeclRefExpr``'s ("declaration
+reference expressions") because they are expressions which refer to
+variable declarations. To find a ``unaryOperator`` that refers to a
+specific declaration, we can simply add a second condition to it:
+
+.. code-block:: c++
+
+ hasIncrement(unaryOperator(
+ hasOperatorName("++"),
+ hasUnaryOperand(declRefExpr())))
+
+Furthermore, we can restrict our matcher to only match if the
+incremented variable is an integer:
+
+.. code-block:: c++
+
+ hasIncrement(unaryOperator(
+ hasOperatorName("++"),
+ hasUnaryOperand(declRefExpr(to(varDecl(hasType(isInteger())))))))
+
+And the last step will be to attach an identifier to this variable, so
+that we can retrieve it in the callback:
+
+.. code-block:: c++
+
+ hasIncrement(unaryOperator(
+ hasOperatorName("++"),
+ hasUnaryOperand(declRefExpr(to(
+ varDecl(hasType(isInteger())).bind("incrementVariable"))))))
+
+We can add this code to the definition of ``LoopMatcher`` and make sure
+that our program, outfitted with the new matcher, only prints out loops
+that declare a single variable initialized to zero and have an increment
+step consisting of a unary increment of some variable.
+
+Now, we just need to add a matcher to check if the condition part of the
+``for`` loop compares a variable against the size of the array. There is
+only one problem - we don't know which array we're iterating over
+without looking at the body of the loop! We are again restricted to
+approximating the result we want with matchers, filling in the details
+in the callback. So we start with:
+
+.. code-block:: c++
+
+ hasCondition(binaryOperator(hasOperatorName("<"))
+
+It makes sense to ensure that the left-hand side is a reference to a
+variable, and that the right-hand side has integer type.
+
+.. code-block:: c++
+
+ hasCondition(binaryOperator(
+ hasOperatorName("<"),
+ hasLHS(declRefExpr(to(varDecl(hasType(isInteger()))))),
+ hasRHS(expr(hasType(isInteger())))))
+
+Why? Because it doesn't work. Of the three loops provided in
+``test-files/simple.cpp``, zero of them have a matching condition. A
+quick look at the AST dump of the first for loop, produced by the
+previous iteration of loop-convert, shows us the answer:
+
+::
+
+ (ForStmt 0x173b240
+ (DeclStmt 0x173afc8
+ 0x173af50 "int i =
+ (IntegerLiteral 0x173afa8 'int' 0)")
+ <<>>
+ (BinaryOperator 0x173b060 '_Bool' '<'
+ (ImplicitCastExpr 0x173b030 'int'
+ (DeclRefExpr 0x173afe0 'int' lvalue Var 0x173af50 'i' 'int'))
+ (ImplicitCastExpr 0x173b048 'int'
+ (DeclRefExpr 0x173b008 'const int' lvalue Var 0x170fa80 'N' 'const int')))
+ (UnaryOperator 0x173b0b0 'int' lvalue prefix '++'
+ (DeclRefExpr 0x173b088 'int' lvalue Var 0x173af50 'i' 'int'))
+ (CompoundStatement …
+
+We already know that the declaration and increments both match, or this
+loop wouldn't have been dumped. The culprit lies in the implicit cast
+applied to the first operand (i.e. the LHS) of the less-than operator,
+an L-value to R-value conversion applied to the expression referencing
+``i``. Thankfully, the matcher library offers a solution to this problem
+in the form of ``ignoringParenImpCasts``, which instructs the matcher to
+ignore implicit casts and parentheses before continuing to match.
+Adjusting the condition operator will restore the desired match.
+
+.. code-block:: c++
+
+ hasCondition(binaryOperator(
+ hasOperatorName("<"),
+ hasLHS(ignoringParenImpCasts(declRefExpr(
+ to(varDecl(hasType(isInteger())))))),
+ hasRHS(expr(hasType(isInteger())))))
+
+After adding binds to the expressions we wished to capture and
+extracting the identifier strings into variables, we have array-step-2
+completed.
+
+Step 4: Retrieving Matched Nodes
+================================
+
+So far, the matcher callback isn't very interesting: it just dumps the
+loop's AST. At some point, we will need to make changes to the input
+source code. Next, we'll work on using the nodes we bound in the
+previous step.
+
+The ``MatchFinder::run()`` callback takes a
+``MatchFinder::MatchResult&`` as its parameter. We're most interested in
+its ``Context`` and ``Nodes`` members. Clang uses the ``ASTContext``
+class to represent contextual information about the AST, as the name
+implies, though the most functionally important detail is that several
+operations require an ``ASTContext*`` parameter. More immediately useful
+is the set of matched nodes, and how we retrieve them.
+
+Since we bind three variables (identified by ConditionVarName,
+InitVarName, and IncrementVarName), we can obtain the matched nodes by
+using the ``getNodeAs()`` member function.
+
+In ``LoopActions.cpp``:
+
+.. code-block:: c++
+
+ #include "clang/AST/ASTContext.h"
+
+ void LoopPrinter::run(const MatchFinder::MatchResult &Result) {
+ ASTContext *Context = Result.Context;
+ const ForStmt *FS = Result.Nodes.getStmtAs<ForStmt>(LoopName);
+ // We do not want to convert header files!
+ if (!FS || !Context->getSourceManager().isFromMainFile(FS->getForLoc()))
+ return;
+ const VarDecl *IncVar = Result.Nodes.getNodeAs<VarDecl>(IncrementVarName);
+ const VarDecl *CondVar = Result.Nodes.getNodeAs<VarDecl>(ConditionVarName);
+ const VarDecl *InitVar = Result.Nodes.getNodeAs<VarDecl>(InitVarName);
+
+Now that we have the three variables, represented by their respective
+declarations, let's make sure that they're all the same, using a helper
+function I call ``areSameVariable()``.
+
+.. code-block:: c++
+
+ if (!areSameVariable(IncVar, CondVar) || !areSameVariable(IncVar, InitVar))
+ return;
+ llvm::outs() << "Potential array-based loop discovered.\n";
+ }
+
+If execution reaches the end of ``LoopPrinter::run()``, we know that the
+loop shell that looks like
+
+.. code-block:: c++
+
+ for (int i= 0; i < expr(); ++i) { ... }
+
+For now, we will just print a message explaining that we found a loop.
+The next section will deal with recursively traversing the AST to
+discover all changes needed.
+
+As a side note, here is the implementation of ``areSameVariable``. Clang
+associates a ``VarDecl`` with each variable to represent the variable's
+declaration. Since the "canonical" form of each declaration is unique by
+address, all we need to do is make sure neither ``ValueDecl`` (base
+class of ``VarDecl``) is ``NULL`` and compare the canonical Decls.
+
+.. code-block:: c++
+
+ static bool areSameVariable(const ValueDecl *First, const ValueDecl *Second) {
+ return First && Second &&
+ First->getCanonicalDecl() == Second->getCanonicalDecl();
+ }
+
+It's not as trivial to test if two expressions are the same, though
+Clang has already done the hard work for us by providing a way to
+canonicalize expressions:
+
+.. code-block:: c++
+
+ static bool areSameExpr(ASTContext *Context, const Expr *First,
+ const Expr *Second) {
+ if (!First || !Second)
+ return false;
+ llvm::FoldingSetNodeID FirstID, SecondID;
+ First->Profile(FirstID, *Context, true);
+ Second->Profile(SecondID, *Context, true);
+ return FirstID == SecondID;
+ }
+
+This code relies on the comparison between two
+``llvm::FoldingSetNodeIDs``. As the documentation for
+``Stmt::Profile()`` indicates, the ``Profile()`` member function builds
+a description of a node in the AST, based on its properties, along with
+those of its children. ``FoldingSetNodeID`` then serves as a hash we can
+use to compare expressions. We will need ``areSameExpr`` later. Before
+you run the new code on the additional loops added to
+test-files/simple.cpp, try to figure out which ones will be considered
+potentially convertible.
diff --git a/docs/LibFormat.rst b/docs/LibFormat.rst
new file mode 100644
index 0000000..eacdc16
--- /dev/null
+++ b/docs/LibFormat.rst
@@ -0,0 +1,56 @@
+=========
+LibFormat
+=========
+
+LibFormat is a library that implements automatic source code formatting based
+on Clang. This documents describes the LibFormat interface and design as well
+as some basic style discussions.
+
+If you just want to use `clang-format` as a tool or integrated into an editor,
+checkout :doc:`ClangFormat`.
+
+Design
+------
+
+FIXME: Write up design.
+
+
+Interface
+---------
+
+The core routine of LibFormat is ``reformat()``:
+
+.. code-block:: c++
+
+ tooling::Replacements reformat(const FormatStyle &Style, Lexer &Lex,
+ SourceManager &SourceMgr,
+ std::vector<CharSourceRange> Ranges);
+
+This reads a token stream out of the lexer ``Lex`` and reformats all the code
+ranges in ``Ranges``. The ``FormatStyle`` controls basic decisions made during
+formatting. A list of options can be found under :ref:`style-options`.
+
+
+.. _style-options:
+
+Style Options
+-------------
+
+The style options describe specific formatting options that can be used in
+order to make `ClangFormat` comply with different style guides. Currently,
+two style guides are hard-coded:
+
+.. code-block:: c++
+
+ /// \brief Returns a format style complying with the LLVM coding standards:
+ /// http://llvm.org/docs/CodingStandards.html.
+ FormatStyle getLLVMStyle();
+
+ /// \brief Returns a format style complying with Google's C++ style guide:
+ /// http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml.
+ FormatStyle getGoogleStyle();
+
+These options are also exposed in the :doc:`standalone tools <ClangFormat>`
+through the `-style` option.
+
+In the future, we plan on making this configurable.
diff --git a/docs/LibTooling.html b/docs/LibTooling.html
deleted file mode 100644
index 163d24a..0000000
--- a/docs/LibTooling.html
+++ /dev/null
@@ -1,212 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
-<title>LibTooling</title>
-<link type="text/css" rel="stylesheet" href="../menu.css">
-<link type="text/css" rel="stylesheet" href="../content.css">
-</head>
-<body>
-
-<!--#include virtual="../menu.html.incl"-->
-
-<div id="content">
-
-<h1>LibTooling</h1>
-<p>LibTooling is a library to support writing standalone tools based on
-Clang. This document will provide a basic walkthrough of how to write
-a tool using LibTooling.</p>
-<p>For the information on how to setup Clang Tooling for LLVM see
-<a href="HowToSetupToolingForLLVM.html">HowToSetupToolingForLLVM.html</a></p>
-
-<!-- ======================================================================= -->
-<h2 id="intro">Introduction</h2>
-<!-- ======================================================================= -->
-
-<p>Tools built with LibTooling, like Clang Plugins, run
-<code>FrontendActions</code> over code.
-<!-- See FIXME for a tutorial on how to write FrontendActions. -->
-In this tutorial, we'll demonstrate the different ways of running clang's
-<code>SyntaxOnlyAction</code>, which runs a quick syntax check, over a bunch of
-code.</p>
-
-<!-- ======================================================================= -->
-<h2 id="runoncode">Parsing a code snippet in memory.</h2>
-<!-- ======================================================================= -->
-
-<p>If you ever wanted to run a <code>FrontendAction</code> over some sample
-code, for example to unit test parts of the Clang AST,
-<code>runToolOnCode</code> is what you looked for. Let me give you an example:
-<pre>
- #include "clang/Tooling/Tooling.h"
-
- TEST(runToolOnCode, CanSyntaxCheckCode) {
- // runToolOnCode returns whether the action was correctly run over the
- // given code.
- EXPECT_TRUE(runToolOnCode(new clang::SyntaxOnlyAction, "class X {};"));
- }
-</pre>
-
-<!-- ======================================================================= -->
-<h2 id="standalonetool">Writing a standalone tool.</h2>
-<!-- ======================================================================= -->
-
-<p>Once you unit tested your <code>FrontendAction</code> to the point where it
-cannot possibly break, it's time to create a standalone tool. For a standalone
-tool to run clang, it first needs to figure out what command line arguments to
-use for a specified file. To that end we create a
-<code>CompilationDatabase</code>. There are different ways to create a
-compilation database, and we need to support all of them depending on
-command-line options. There's the <code>CommonOptionsParser</code> class
-that takes the responsibility to parse command-line parameters related to
-compilation databases and inputs, so that all tools share the implementation.
-</p>
-
-<h3 id="parsingcommonoptions">Parsing common tools options.</h3>
-<p><code>CompilationDatabase</code> can be read from a build directory or the
-command line. Using <code>CommonOptionsParser</code> allows for explicit
-specification of a compile command line, specification of build path using the
-<code>-p</code> command-line option, and automatic location of the compilation
-database using source files paths.
-<pre>
-#include "clang/Tooling/CommonOptionsParser.h"
-
-using namespace clang::tooling;
-
-int main(int argc, const char **argv) {
- // CommonOptionsParser constructor will parse arguments and create a
- // CompilationDatabase. In case of error it will terminate the program.
- CommonOptionsParser OptionsParser(argc, argv);
-
- // Use OptionsParser.GetCompilations() and OptionsParser.GetSourcePathList()
- // to retrieve CompilationDatabase and the list of input file paths.
-}
-</pre>
-</p>
-
-<h3 id="tool">Creating and running a ClangTool.</h3>
-<p>Once we have a <code>CompilationDatabase</code>, we can create a
-<code>ClangTool</code> and run our <code>FrontendAction</code> over some code.
-For example, to run the <code>SyntaxOnlyAction</code> over the files "a.cc" and
-"b.cc" one would write:
-<pre>
- // A clang tool can run over a number of sources in the same process...
- std::vector&lt;std::string> Sources;
- Sources.push_back("a.cc");
- Sources.push_back("b.cc");
-
- // We hand the CompilationDatabase we created and the sources to run over into
- // the tool constructor.
- 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
- // FrontendActionFactory from a given FrontendAction type, we call
- // newFrontendActionFactory&lt;clang::SyntaxOnlyAction>().
- int result = Tool.run(newFrontendActionFactory&lt;clang::SyntaxOnlyAction>());
-</pre>
-</p>
-
-<h3 id="main">Putting it together - the first tool.</h3>
-<p>Now we combine the two previous steps into our first real tool. This example
-tool is also checked into the clang tree at tools/clang-check/ClangCheck.cpp.
-<pre>
-// Declares clang::SyntaxOnlyAction.
-#include "clang/Frontend/FrontendActions.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;
-
-// 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);
-
-// 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) {
- CommonOptionsParser OptionsParser(argc, argv);
- ClangTool Tool(OptionsParser.GetCompilations(),
- OptionsParser.GetSourcePathList());
- return Tool.run(newFrontendActionFactory&lt;clang::SyntaxOnlyAction&gt;());
-}
-</pre>
-</p>
-
-<h3 id="running">Running the tool on some code.</h3>
-<p>When you check out and build clang, clang-check is already built and
-available to you in bin/clang-check inside your build directory.</p>
-<p>You can run clang-check on a file in the llvm repository by specifying
-all the needed parameters after a "--" separator:
-<pre>
- $ cd /path/to/source/llvm
- $ export BD=/path/to/build/llvm
- $ $BD/bin/clang-check tools/clang/tools/clang-check/ClangCheck.cpp -- \
- clang++ -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS \
- -Itools/clang/include -I$BD/include -Iinclude -Itools/clang/lib/Headers -c
-</pre>
-</p>
-
-<p>As an alternative, you can also configure cmake to output a compile command
-database into its build directory:
-<pre>
- # Alternatively to calling cmake, use ccmake, toggle to advanced mode and
- # set the parameter CMAKE_EXPORT_COMPILE_COMMANDS from the UI.
- $ cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .
-</pre>
-</p>
-<p>
-This creates a file called compile_commands.json in the build directory. Now
-you can run clang-check over files in the project by specifying the build path
-as first argument and some source files as further positional arguments:
-<pre>
- $ cd /path/to/source/llvm
- $ export BD=/path/to/build/llvm
- $ $BD/bin/clang-check -p $BD tools/clang/tools/clang-check/ClangCheck.cpp
-</pre>
-</p>
-
-<h3 id="builtin">Builtin includes.</h3>
-<p>Clang tools need their builtin headers and search for them the same way clang
-does. Thus, the default location to look for builtin headers is in a path
-$(dirname /path/to/tool)/../lib/clang/3.2/include relative to the tool
-binary. This works out-of-the-box for tools running from llvm's toplevel
-binary directory after building clang-headers, or if the tool is running
-from the binary directory of a clang install next to the clang binary.</p>
-
-<p>Tips: if your tool fails to find stddef.h or similar headers, call
-the tool with -v and look at the search paths it looks through.</p>
-
-<h3 id="linking">Linking.</h3>
-<p>Please note that this presents the linking requirements at the time of this
-writing. For the most up-to-date information, look at one of the tools'
-Makefiles (for example
-<a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-check/Makefile?view=markup">clang-check/Makefile</a>).
-</p>
-
-<p>To link a binary using the tooling infrastructure, link in the following
-libraries:
-<ul>
-<li>Tooling</li>
-<li>Frontend</li>
-<li>Driver</li>
-<li>Serialization</li>
-<li>Parse</li>
-<li>Sema</li>
-<li>Analysis</li>
-<li>Edit</li>
-<li>AST</li>
-<li>Lex</li>
-<li>Basic</li>
-</ul>
-</p>
-
-</div>
-</body>
-</html>
-
diff --git a/docs/LibTooling.rst b/docs/LibTooling.rst
new file mode 100644
index 0000000..a9c24c3
--- /dev/null
+++ b/docs/LibTooling.rst
@@ -0,0 +1,192 @@
+==========
+LibTooling
+==========
+
+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
+:doc:`HowToSetupToolingForLLVM`
+
+Introduction
+------------
+
+Tools built with LibTooling, like Clang Plugins, run ``FrontendActions`` over
+code.
+
+.. See FIXME for a tutorial on how to write FrontendActions.
+
+In this tutorial, we'll demonstrate the different ways of running Clang's
+``SyntaxOnlyAction``, which runs a quick syntax check, over a bunch of code.
+
+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:
+
+.. code-block:: c++
+
+ #include "clang/Tooling/Tooling.h"
+
+ TEST(runToolOnCode, CanSyntaxCheckCode) {
+ // runToolOnCode returns whether the action was correctly run over the
+ // given code.
+ EXPECT_TRUE(runToolOnCode(new clang::SyntaxOnlyAction, "class X {};"));
+ }
+
+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``. 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.
+
+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.
+
+.. code-block:: c++
+
+ #include "clang/Tooling/CommonOptionsParser.h"
+
+ using namespace clang::tooling;
+
+ int main(int argc, const char **argv) {
+ // 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:
+
+.. code-block:: c++
+
+ // A clang tool can run over a number of sources in the same process...
+ std::vector<std::string> Sources;
+ Sources.push_back("a.cc");
+ Sources.push_back("b.cc");
+
+ // We hand the CompilationDatabase we created and the sources to run over into
+ // the tool constructor.
+ 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
+ // FrontendActionFactory from a given FrontendAction type, we call
+ // newFrontendActionFactory<clang::SyntaxOnlyAction>().
+ int result = Tool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>());
+
+Putting it together --- the first tool
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+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``.
+
+.. code-block:: c++
+
+ // Declares clang::SyntaxOnlyAction.
+ #include "clang/Frontend/FrontendActions.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;
+
+ // 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);
+
+ // 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) {
+ CommonOptionsParser OptionsParser(argc, argv);
+ ClangTool Tool(OptionsParser.getCompilations(),
+ OptionsParser.getSourcePathList());
+ return Tool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>());
+ }
+
+Running the tool on some code
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When you check out and build clang, clang-check is already built and available
+to you in bin/clang-check inside your build directory.
+
+You can run clang-check on a file in the llvm repository by specifying all the
+needed parameters after a "``--``" separator:
+
+.. code-block:: bash
+
+ $ cd /path/to/source/llvm
+ $ export BD=/path/to/build/llvm
+ $ $BD/bin/clang-check tools/clang/tools/clang-check/ClangCheck.cpp -- \
+ clang++ -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS \
+ -Itools/clang/include -I$BD/include -Iinclude \
+ -Itools/clang/lib/Headers -c
+
+As an alternative, you can also configure cmake to output a compile command
+database into its build directory:
+
+.. code-block:: bash
+
+ # Alternatively to calling cmake, use ccmake, toggle to advanced mode and
+ # set the parameter CMAKE_EXPORT_COMPILE_COMMANDS from the UI.
+ $ cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .
+
+This creates a file called ``compile_commands.json`` in the build directory.
+Now you can run :program:`clang-check` over files in the project by specifying
+the build path as first argument and some source files as further positional
+arguments:
+
+.. code-block:: bash
+
+ $ cd /path/to/source/llvm
+ $ export BD=/path/to/build/llvm
+ $ $BD/bin/clang-check -p $BD tools/clang/tools/clang-check/ClangCheck.cpp
+
+
+.. _libtooling_builtin_includes:
+
+Builtin includes
+^^^^^^^^^^^^^^^^
+
+Clang tools need their builtin headers and search for them the same way Clang
+does. Thus, the default location to look for builtin headers is in a path
+``$(dirname /path/to/tool)/../lib/clang/3.3/include`` relative to the tool
+binary. This works out-of-the-box for tools running from llvm's toplevel
+binary directory after building clang-headers, or if the tool is running from
+the binary directory of a clang install next to the clang binary.
+
+Tips: if your tool fails to find ``stddef.h`` or similar headers, call the tool
+with ``-v`` and look at the search paths it looks through.
+
+Linking
+^^^^^^^
+
+For a list of libraries to link, look at one of the tools' Makefiles (for
+example `clang-check/Makefile
+<http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-check/Makefile?view=markup>`_).
diff --git a/docs/Makefile.sphinx b/docs/Makefile.sphinx
new file mode 100644
index 0000000..7949e39
--- /dev/null
+++ b/docs/Makefile.sphinx
@@ -0,0 +1,163 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+BUILDDIR = _build
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext default
+
+default: html
+
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " singlehtml to make a single large HTML file"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " devhelp to make HTML files and a Devhelp project"
+ @echo " epub to make an epub"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
+ @echo " text to make text files"
+ @echo " man to make manual pages"
+ @echo " texinfo to make Texinfo files"
+ @echo " info to make Texinfo files and run them through makeinfo"
+ @echo " gettext to make PO message catalogs"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+ -rm -rf $(BUILDDIR)/*
+
+html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ @echo
+ @# FIXME: Remove this `cp` once HTML->Sphinx transition is completed.
+ @# Kind of a hack, but HTML-formatted docs are on the way out anyway.
+ @echo "Copying legacy HTML-formatted docs into $(BUILDDIR)/html"
+ @cp -a *.html $(BUILDDIR)/html
+ @# FIXME: What we really need is a way to specify redirects, so that
+ @# we can just redirect to a reST'ified version of this document.
+ @# PR14714 is tracking the issue of redirects.
+ @cp -a Block-ABI-Apple.txt $(BUILDDIR)/html
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ @echo
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Clang.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Clang.qhc"
+
+devhelp:
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+ @echo
+ @echo "Build finished."
+ @echo "To view the help file:"
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/Clang"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Clang"
+ @echo "# devhelp"
+
+epub:
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ @echo
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
+ "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through pdflatex..."
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ @echo
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ @echo
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo
+ @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+ @echo "Run \`make' in that directory to run these through makeinfo" \
+ "(use \`make info' here to do that automatically)."
+
+info:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo "Running Texinfo files through makeinfo..."
+ make -C $(BUILDDIR)/texinfo info
+ @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+ $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+ @echo
+ @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/docs/MemorySanitizer.rst b/docs/MemorySanitizer.rst
new file mode 100644
index 0000000..fdb8a81
--- /dev/null
+++ b/docs/MemorySanitizer.rst
@@ -0,0 +1,178 @@
+================
+MemorySanitizer
+================
+
+.. contents::
+ :local:
+
+Introduction
+============
+
+MemorySanitizer is a detector of uninitialized reads. It consists of a
+compiler instrumentation module and a run-time library.
+
+Typical slowdown introduced by MemorySanitizer is **3x**.
+
+How to build
+============
+
+Follow the `clang build instructions <../get_started.html>`_. CMake
+build is supported.
+
+Usage
+=====
+
+Simply compile and link your program with ``-fsanitize=memory`` flag.
+The MemorySanitizer 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 MemorySanitizer run-time
+is not linked, so ``-Wl,-z,defs`` may cause link errors (don't use it
+with MemorySanitizer). To get a reasonable performance add ``-O1`` or
+higher. To get meaninful stack traces in error messages add
+``-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``).
+
+.. code-block:: console
+
+ % cat umr.cc
+ #include <stdio.h>
+
+ int main(int argc, char** argv) {
+ int* a = new int[10];
+ a[5] = 0;
+ if (a[argc])
+ printf("xx\n");
+ return 0;
+ }
+
+ % clang -fsanitize=memory -fPIE -pie -fno-omit-frame-pointer -g -O2 umr.cc
+
+If a bug is detected, the program will print an error message to
+stderr and exit with a non-zero exit code. Currently, MemorySanitizer
+does not symbolize its output by default, so you may need to use a
+separate script to symbolize the result offline (this will be fixed in
+future).
+
+.. code-block:: console
+
+ % ./a.out 2>log
+ % projects/compiler-rt/lib/asan/scripts/asan_symbolize.py / < log | c++filt
+ ==30106== WARNING: MemorySanitizer: UMR (uninitialized-memory-read)
+ #0 0x7f45944b418a in main umr.cc:6
+ #1 0x7f45938b676c in __libc_start_main libc-start.c:226
+ Exiting
+
+By default, MemorySanitizer exits on the first detected error.
+
+``__has_feature(memory_sanitizer)``
+------------------------------------
+
+In some cases one may need to execute different code depending on
+whether MemorySanitizer is enabled. :ref:`\_\_has\_feature
+<langext-__has_feature-__has_extension>` can be used for this purpose.
+
+.. code-block:: c
+
+ #if defined(__has_feature)
+ # if __has_feature(memory_sanitizer)
+ // code that builds only under MemorySanitizer
+ # endif
+ #endif
+
+``__attribute__((no_sanitize_memory))``
+-----------------------------------------------
+
+Some code should not be checked by MemorySanitizer.
+One may use the function attribute
+:ref:`no_sanitize_memory <langext-memory_sanitizer>`
+to disable uninitialized checks in a particular function.
+MemorySanitizer may still instrument such functions to avoid false positives.
+This attribute may not be
+supported by other compilers, so we suggest to use it together with
+``__has_feature(memory_sanitizer)``. Note: currently, this attribute will be
+lost if the function is inlined.
+
+Origin Tracking
+===============
+
+MemorySanitizer can track origins of unitialized values, similar to
+Valgrind's --track-origins option. This feature is enabled by
+``-fsanitize-memory-track-origins`` Clang option. With the code from
+the example above,
+
+.. code-block:: console
+
+ % clang -fsanitize=memory -fsanitize-memory-track-origins -fPIE -pie -fno-omit-frame-pointer -g -O2 umr.cc
+ % ./a.out 2>log
+ % projects/compiler-rt/lib/asan/scripts/asan_symbolize.py / < log | c++filt
+ ==14425== WARNING: MemorySanitizer: UMR (uninitialized-memory-read)
+ ==14425== WARNING: Trying to symbolize code, but external symbolizer is not initialized!
+ #0 0x7f8bdda3824b in main umr.cc:6
+ #1 0x7f8bdce3a76c in __libc_start_main libc-start.c:226
+ raw origin id: 2030043137
+ ORIGIN: heap allocation:
+ #0 0x7f8bdda4034b in operator new[](unsigned long) msan_new_delete.cc:39
+ #1 0x7f8bdda3814d in main umr.cc:4
+ #2 0x7f8bdce3a76c in __libc_start_main libc-start.c:226
+ Exiting
+
+Origin tracking has proved to be very useful for debugging UMR
+reports. It slows down program execution by a factor of 1.5x-2x on top
+of the usual MemorySanitizer slowdown.
+
+Handling external code
+============================
+
+MemorySanitizer requires that all program code is instrumented. This
+also includes any libraries that the program depends on, even libc.
+Failing to achieve this may result in false UMR reports.
+
+Full MemorySanitizer instrumentation is very difficult to achieve. To
+make it easier, MemorySanitizer runtime library includes 70+
+interceptors for the most common libc functions. They make it possible
+to run MemorySanitizer-instrumented programs linked with
+uninstrumented libc. For example, the authors were able to bootstrap
+MemorySanitizer-instrumented Clang compiler by linking it with
+self-built instrumented libcxx (as a replacement for libstdc++).
+
+In the case when rebuilding all program dependencies with
+MemorySanitizer is problematic, an experimental MSanDR tool can be
+used. It is a DynamoRio-based tool that uses dynamic instrumentation
+to avoid false positives due to uninstrumented code. The tool simply
+marks memory from instrumented libraries as fully initialized. See
+`http://code.google.com/p/memory-sanitizer/wiki/Running#Running_with_the_dynamic_tool`
+for more information.
+
+Supported Platforms
+===================
+
+MemorySanitizer is supported on
+
+* Linux x86\_64 (tested on Ubuntu 10.04 and 12.04);
+
+Limitations
+===========
+
+* MemorySanitizer uses 2x more real memory than a native run, 3x with
+ origin tracking.
+* MemorySanitizer maps (but not reserves) 64 Terabytes of virtual
+ address space. This means that tools like ``ulimit`` may not work as
+ usually expected.
+* Static linking is not supported.
+* Non-position-independent executables are not supported.
+* Depending on the version of Linux kernel, running without ASLR may
+ be not supported. Note that GDB disables ASLR by default. To debug
+ instrumented programs, use "set disable-randomization off".
+
+Current Status
+==============
+
+MemorySanitizer is an experimental tool. It is known to work on large
+real-world programs, like Clang/LLVM itself.
+
+More Information
+================
+
+`http://code.google.com/p/memory-sanitizer <http://code.google.com/p/memory-sanitizer/>`_
+
diff --git a/docs/Modules.rst b/docs/Modules.rst
new file mode 100644
index 0000000..8a6b8b6
--- /dev/null
+++ b/docs/Modules.rst
@@ -0,0 +1,713 @@
+=======
+Modules
+=======
+
+.. contents::
+ :local:
+
+.. warning::
+ The functionality described on this page is still experimental! Please
+ try it out and send us bug reports!
+
+Introduction
+============
+Most software is built using a number of software libraries, including libraries supplied by the platform, internal libraries built as part of the software itself to provide structure, and third-party libraries. For each library, one needs to access both its interface (API) and its implementation. In the C family of languages, the interface to a library is accessed by including the appropriate header files(s):
+
+.. code-block:: c
+
+ #include <SomeLib.h>
+
+The implementation is handled separately by linking against the appropriate library. For example, by passing ``-lSomeLib`` to the linker.
+
+Modules provide an alternative, simpler way to use software libraries that provides better compile-time scalability and eliminates many of the problems inherent to using the C preprocessor to access the API of a library.
+
+Problems with the current model
+-------------------------------
+The ``#include`` mechanism provided by the C preprocessor is a very poor way to access the API of a library, for a number of reasons:
+
+* **Compile-time scalability**: Each time a header is included, the
+ compiler must preprocess and parse the text in that header and every
+ header it includes, transitively. This process must be repeated for
+ every translation unit in the application, which involves a huge
+ amount of redundant work. In a project with *N* translation units
+ and *M* headers included in each translation unit, the compiler is
+ performing *M x N* work even though most of the *M* headers are
+ shared among multiple translation units. C++ is particularly bad,
+ because the compilation model for templates forces a huge amount of
+ code into headers.
+
+* **Fragility**: ``#include`` directives are treated as textual
+ inclusion by the preprocessor, and are therefore subject to any
+ active macro definitions at the time of inclusion. If any of the
+ active macro definitions happens to collide with a name in the
+ library, it can break the library API or cause compilation failures
+ in the library header itself. For an extreme example,
+ ``#define std "The C++ Standard"`` and then include a standard
+ library header: the result is a horrific cascade of failures in the
+ C++ Standard Library's implementation. More subtle real-world
+ problems occur when the headers for two different libraries interact
+ due to macro collisions, and users are forced to reorder
+ ``#include`` directives or introduce ``#undef`` directives to break
+ the (unintended) dependency.
+
+* **Conventional workarounds**: C programmers have
+ adopted a number of conventions to work around the fragility of the
+ C preprocessor model. Include guards, for example, are required for
+ the vast majority of headers to ensure that multiple inclusion
+ doesn't break the compile. Macro names are written with
+ ``LONG_PREFIXED_UPPERCASE_IDENTIFIERS`` to avoid collisions, and some
+ library/framework developers even use ``__underscored`` names
+ in headers to avoid collisions with "normal" names that (by
+ convention) shouldn't even be macros. These conventions are a
+ barrier to entry for developers coming from non-C languages, are
+ boilerplate for more experienced developers, and make our headers
+ far uglier than they should be.
+
+* **Tool confusion**: In a C-based language, it is hard to build tools
+ that work well with software libraries, because the boundaries of
+ the libraries are not clear. Which headers belong to a particular
+ library, and in what order should those headers be included to
+ guarantee that they compile correctly? Are the headers C, C++,
+ Objective-C++, or one of the variants of these languages? What
+ declarations in those headers are actually meant to be part of the
+ API, and what declarations are present only because they had to be
+ written as part of the header file?
+
+Semantic import
+---------------
+Modules improve access to the API of software libraries by replacing the textual preprocessor inclusion model with a more robust, more efficient semantic model. From the user's perspective, the code looks only slightly different, because one uses an ``import`` declaration rather than a ``#include`` preprocessor directive:
+
+.. code-block:: c
+
+ import std.io; // pseudo-code; see below for syntax discussion
+
+However, this module import behaves quite differently from the corresponding ``#include <stdio.h>``: when the compiler sees the module import above, it loads a binary representation of the ``std.io`` module and makes its API available to the application directly. Preprocessor definitions that precede the import declaration have no impact on the API provided by ``std.io``, because the module itself was compiled as a separate, standalone module. Additionally, any linker flags required to use the ``std.io`` module will automatically be provided when the module is imported [#]_
+This semantic import model addresses many of the problems of the preprocessor inclusion model:
+
+* **Compile-time scalability**: The ``std.io`` module is only compiled once, and importing the module into a translation unit is a constant-time operation (independent of module system). Thus, the API of each software library is only parsed once, reducing the *M x N* compilation problem to an *M + N* problem.
+
+* **Fragility**: Each module is parsed as a standalone entity, so it has a consistent preprocessor environment. This completely eliminates the need for ``__underscored`` names and similarly defensive tricks. Moreover, the current preprocessor definitions when an import declaration is encountered are ignored, so one software library can not affect how another software library is compiled, eliminating include-order dependencies.
+
+* **Tool confusion**: Modules describe the API of software libraries, and tools can reason about and present a module as a representation of that API. Because modules can only be built standalone, tools can rely on the module definition to ensure that they get the complete API for the library. Moreover, modules can specify which languages they work with, so, e.g., one can not accidentally attempt to load a C++ module into a C program.
+
+Problems modules do not solve
+-----------------------------
+Many programming languages have a module or package system, and because of the variety of features provided by these languages it is important to define what modules do *not* do. In particular, all of the following are considered out-of-scope for modules:
+
+* **Rewrite the world's code**: It is not realistic to require applications or software libraries to make drastic or non-backward-compatible changes, nor is it feasible to completely eliminate headers. Modules must interoperate with existing software libraries and allow a gradual transition.
+
+* **Versioning**: Modules have no notion of version information. Programmers must still rely on the existing versioning mechanisms of the underlying language (if any exist) to version software libraries.
+
+* **Namespaces**: Unlike in some languages, modules do not imply any notion of namespaces. Thus, a struct declared in one module will still conflict with a struct of the same name declared in a different module, just as they would if declared in two different headers. This aspect is important for backward compatibility, because (for example) the mangled names of entities in software libraries must not change when introducing modules.
+
+* **Binary distribution of modules**: Headers (particularly C++ headers) expose the full complexity of the language. Maintaining a stable binary module format across architectures, compiler versions, and compiler vendors is technically infeasible.
+
+Using Modules
+=============
+To enable modules, pass the command-line flag ``-fmodules`` [#]_. This will make any modules-enabled software libraries available as modules as well as introducing any modules-specific syntax. Additional `command-line parameters`_ are described in a separate section later.
+
+Import declaration
+------------------
+The most direct way to import a module is with an *import declaration*, which imports the named module:
+
+.. parsed-literal::
+
+ import std;
+
+The import declaration above imports the entire contents of the ``std`` module (which would contain, e.g., the entire C or C++ standard library) and make its API available within the current translation unit. To import only part of a module, one may use dot syntax to specific a particular submodule, e.g.,
+
+.. parsed-literal::
+
+ import std.io;
+
+Redundant import declarations are ignored, and one is free to import modules at any point within the translation unit, so long as the import declaration is at global scope.
+
+.. warning::
+ The import declaration syntax described here does not actually exist. Rather, it is a straw man proposal that may very well change when modules are discussed in the C and C++ committees. See the section `Includes as imports`_ to see how modules get imported today.
+
+Includes as imports
+-------------------
+The primary user-level feature of modules is the import operation, which provides access to the API of software libraries. However, today's programs make extensive use of ``#include``, and it is unrealistic to assume that all of this code will change overnight. Instead, modules automatically translate ``#include`` directives into the corresponding module import. For example, the include directive
+
+.. code-block:: c
+
+ #include <stdio.h>
+
+will be automatically mapped to an import of the module ``std.io``. Even with specific ``import`` syntax in the language, this particular feature is important for both adoption and backward compatibility: automatic translation of ``#include`` to ``import`` allows an application to get the benefits of modules (for all modules-enabled libraries) without any changes to the application itself. Thus, users can easily use modules with one compiler while falling back to the preprocessor-inclusion mechanism with other compilers.
+
+.. note::
+
+ The automatic mapping of ``#include`` to ``import`` also solves an implementation problem: importing a module with a definition of some entity (say, a ``struct Point``) and then parsing a header containing another definition of ``struct Point`` would cause a redefinition error, even if it is the same ``struct Point``. By mapping ``#include`` to ``import``, the compiler can guarantee that it always sees just the already-parsed definition from the module.
+
+Module maps
+-----------
+The crucial link between modules and headers is described by a *module map*, which describes how a collection of existing headers maps on to the (logical) structure of a module. For example, one could imagine a module ``std`` covering the C standard library. Each of the C standard library headers (``<stdio.h>``, ``<stdlib.h>``, ``<math.h>``, etc.) would contribute to the ``std`` module, by placing their respective APIs into the corresponding submodule (``std.io``, ``std.lib``, ``std.math``, etc.). Having a list of the headers that are part of the ``std`` module allows the compiler to build the ``std`` module as a standalone entity, and having the mapping from header names to (sub)modules allows the automatic translation of ``#include`` directives to module imports.
+
+Module maps are specified as separate files (each named ``module.map``) alongside the headers they describe, which allows them to be added to existing software libraries without having to change the library headers themselves (in most cases [#]_). The actual `Module map language`_ is described in a later section.
+
+.. note::
+
+ To actually see any benefits from modules, one first has to introduce module maps for the underlying C standard library and the libraries and headers on which it depends. The section `Modularizing a Platform`_ describes the steps one must take to write these module maps.
+
+Compilation model
+-----------------
+The binary representation of modules is automatically generated by the compiler on an as-needed basis. When a module is imported (e.g., by an ``#include`` of one of the module's headers), the compiler will spawn a second instance of itself [#]_, with a fresh preprocessing context [#]_, to parse just the headers in that module. The resulting Abstract Syntax Tree (AST) is then persisted into the binary representation of the module that is then loaded into translation unit where the module import was encountered.
+
+The binary representation of modules is persisted in the *module cache*. Imports of a module will first query the module cache and, if a binary representation of the required module is already available, will load that representation directly. Thus, a module's headers will only be parsed once per language configuration, rather than once per translation unit that uses the module.
+
+Modules maintain references to each of the headers that were part of the module build. If any of those headers changes, or if any of the modules on which a module depends change, then the module will be (automatically) recompiled. The process should never require any user intervention.
+
+Command-line parameters
+-----------------------
+``-fmodules``
+ Enable the modules feature (EXPERIMENTAL).
+
+``-fcxx-modules``
+ Enable the modules feature for C++ (EXPERIMENTAL and VERY BROKEN).
+
+``-fmodules-cache-path=<directory>``
+ Specify the path to the modules cache. If not provided, Clang will select a system-appropriate default.
+
+``-f[no-]modules-autolink``
+ Enable of disable automatic linking against the libraries associated with imported modules.
+
+``-fmodules-ignore-macro=macroname``
+ Instruct modules to ignore the named macro when selecting an appropriate module variant. Use this for macros defined on the command line that don't affect how modules are built, to improve sharing of compiled module files.
+
+``-fmodules-prune-interval=seconds``
+ Specify the minimum delay (in seconds) between attempts to prune the module cache. Module cache pruning attempts to clear out old, unused module files so that the module cache itself does not grow without bound. The default delay is large (604,800 seconds, or 7 days) because this is an expensive operation. Set this value to 0 to turn off pruning.
+
+``-fmodules-prune-after=seconds``
+ Specify the minimum time (in seconds) for which a file in the module cache must be unused (according to access time) before module pruning will remove it. The default delay is large (2,678,400 seconds, or 31 days) to avoid excessive module rebuilding.
+
+``-module-file-info <module file name>``
+ Debugging aid that prints information about a given module file (with a ``.pcm`` extension), including the language and preprocessor options that particular module variant was built with.
+
+Module Map Language
+===================
+
+The module map language describes the mapping from header files to the
+logical structure of modules. To enable support for using a library as
+a module, one must write a ``module.map`` file for that library. The
+``module.map`` file is placed alongside the header files themselves,
+and is written in the module map language described below.
+
+As an example, the module map file for the C standard library might look a bit like this:
+
+.. parsed-literal::
+
+ module std [system] {
+ module complex {
+ header "complex.h"
+ export *
+ }
+
+ module ctype {
+ header "ctype.h"
+ export *
+ }
+
+ module errno {
+ header "errno.h"
+ header "sys/errno.h"
+ export *
+ }
+
+ module fenv {
+ header "fenv.h"
+ export *
+ }
+
+ // ...more headers follow...
+ }
+
+Here, the top-level module ``std`` encompasses the whole C standard library. It has a number of submodules containing different parts of the standard library: ``complex`` for complex numbers, ``ctype`` for character types, etc. Each submodule lists one of more headers that provide the contents for that submodule. Finally, the ``export *`` command specifies that anything included by that submodule will be automatically re-exported.
+
+Lexical structure
+-----------------
+Module map files use a simplified form of the C99 lexer, with the same rules for identifiers, tokens, string literals, ``/* */`` and ``//`` comments. The module map language has the following reserved words; all other C identifiers are valid identifiers.
+
+.. parsed-literal::
+
+ ``config_macros`` ``export`` ``module``
+ ``conflict`` ``framework`` ``requires``
+ ``exclude`` ``header`` ``umbrella``
+ ``explicit`` ``link``
+
+Module map file
+---------------
+A module map file consists of a series of module declarations:
+
+.. parsed-literal::
+
+ *module-map-file*:
+ *module-declaration**
+
+Within a module map file, modules are referred to by a *module-id*, which uses periods to separate each part of a module's name:
+
+.. parsed-literal::
+
+ *module-id*:
+ *identifier* ('.' *identifier*)*
+
+Module declaration
+------------------
+A module declaration describes a module, including the headers that contribute to that module, its submodules, and other aspects of the module.
+
+.. parsed-literal::
+
+ *module-declaration*:
+ ``explicit``:sub:`opt` ``framework``:sub:`opt` ``module`` *module-id* *attributes*:sub:`opt` '{' *module-member** '}'
+
+The *module-id* should consist of only a single *identifier*, which provides the name of the module being defined. Each module shall have a single definition.
+
+The ``explicit`` qualifier can only be applied to a submodule, i.e., a module that is nested within another module. The contents of explicit submodules are only made available when the submodule itself was explicitly named in an import declaration or was re-exported from an imported module.
+
+The ``framework`` qualifier specifies that this module corresponds to a Darwin-style framework. A Darwin-style framework (used primarily on Mac OS X and iOS) is contained entirely in directory ``Name.framework``, where ``Name`` is the name of the framework (and, therefore, the name of the module). That directory has the following layout:
+
+.. parsed-literal::
+
+ Name.framework/
+ module.map Module map for the framework
+ Headers/ Subdirectory containing framework headers
+ Frameworks/ Subdirectory containing embedded frameworks
+ Resources/ Subdirectory containing additional resources
+ Name Symbolic link to the shared library for the framework
+
+The ``system`` attribute specifies that the module is a system module. When a system module is rebuilt, all of the module's header will be considered system headers, which suppresses warnings. This is equivalent to placing ``#pragma GCC system_header`` in each of the module's headers. The form of attributes is described in the section Attributes_, below.
+
+Modules can have a number of different kinds of members, each of which is described below:
+
+.. parsed-literal::
+
+ *module-member*:
+ *requires-declaration*
+ *header-declaration*
+ *umbrella-dir-declaration*
+ *submodule-declaration*
+ *export-declaration*
+ *link-declaration*
+ *config-macros-declaration*
+ *conflict-declaration*
+
+Requires declaration
+~~~~~~~~~~~~~~~~~~~~
+A *requires-declaration* specifies the requirements that an importing translation unit must satisfy to use the module.
+
+.. parsed-literal::
+
+ *requires-declaration*:
+ ``requires`` *feature-list*
+
+ *feature-list*:
+ *identifier* (',' *identifier*)*
+
+The requirements clause allows specific modules or submodules to specify that they are only accessible with certain language dialects or on certain platforms. The feature list is a set of identifiers, defined below. If any of the features is not available in a given translation unit, that translation unit shall not import the module.
+
+The following features are defined:
+
+altivec
+ The target supports AltiVec.
+
+blocks
+ The "blocks" language feature is available.
+
+cplusplus
+ C++ support is available.
+
+cplusplus11
+ C++11 support is available.
+
+objc
+ Objective-C support is available.
+
+objc_arc
+ Objective-C Automatic Reference Counting (ARC) is available
+
+opencl
+ OpenCL is available
+
+tls
+ Thread local storage is available.
+
+*target feature*
+ A specific target feature (e.g., ``sse4``, ``avx``, ``neon``) is available.
+
+
+**Example**: The ``std`` module can be extended to also include C++ and C++11 headers using a *requires-declaration*:
+
+.. parsed-literal::
+
+ module std {
+ // C standard library...
+
+ module vector {
+ requires cplusplus
+ header "vector"
+ }
+
+ module type_traits {
+ requires cplusplus11
+ header "type_traits"
+ }
+ }
+
+Header declaration
+~~~~~~~~~~~~~~~~~~
+A header declaration specifies that a particular header is associated with the enclosing module.
+
+.. parsed-literal::
+
+ *header-declaration*:
+ ``umbrella``:sub:`opt` ``header`` *string-literal*
+ ``exclude`` ``header`` *string-literal*
+
+A header declaration that does not contain ``exclude`` specifies a header that contributes to the enclosing module. Specifically, when the module is built, the named header will be parsed and its declarations will be (logically) placed into the enclosing submodule.
+
+A header with the ``umbrella`` specifier is called an umbrella header. An umbrella header includes all of the headers within its directory (and any subdirectories), and is typically used (in the ``#include`` world) to easily access the full API provided by a particular library. With modules, an umbrella header is a convenient shortcut that eliminates the need to write out ``header`` declarations for every library header. A given directory can only contain a single umbrella header.
+
+.. note::
+ Any headers not included by the umbrella header should have
+ explicit ``header`` declarations. Use the
+ ``-Wincomplete-umbrella`` warning option to ask Clang to complain
+ about headers not covered by the umbrella header or the module map.
+
+A header with the ``exclude`` specifier is excluded from the module. It will not be included when the module is built, nor will it be considered to be part of the module.
+
+**Example**: The C header ``assert.h`` is an excellent candidate for an excluded header, because it is meant to be included multiple times (possibly with different ``NDEBUG`` settings).
+
+.. parsed-literal::
+
+ module std [system] {
+ exclude header "assert.h"
+ }
+
+A given header shall not be referenced by more than one *header-declaration*.
+
+Umbrella directory declaration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+An umbrella directory declaration specifies that all of the headers in the specified directory should be included within the module.
+
+.. parsed-literal::
+
+ *umbrella-dir-declaration*:
+ ``umbrella`` *string-literal*
+
+The *string-literal* refers to a directory. When the module is built, all of the header files in that directory (and its subdirectories) are included in the module.
+
+An *umbrella-dir-declaration* shall not refer to the same directory as the location of an umbrella *header-declaration*. In other words, only a single kind of umbrella can be specified for a given directory.
+
+.. note::
+
+ Umbrella directories are useful for libraries that have a large number of headers but do not have an umbrella header.
+
+
+Submodule declaration
+~~~~~~~~~~~~~~~~~~~~~
+Submodule declarations describe modules that are nested within their enclosing module.
+
+.. parsed-literal::
+
+ *submodule-declaration*:
+ *module-declaration*
+ *inferred-submodule-declaration*
+
+A *submodule-declaration* that is a *module-declaration* is a nested module. If the *module-declaration* has a ``framework`` specifier, the enclosing module shall have a ``framework`` specifier; the submodule's contents shall be contained within the subdirectory ``Frameworks/SubName.framework``, where ``SubName`` is the name of the submodule.
+
+A *submodule-declaration* that is an *inferred-submodule-declaration* describes a set of submodules that correspond to any headers that are part of the module but are not explicitly described by a *header-declaration*.
+
+.. parsed-literal::
+
+ *inferred-submodule-declaration*:
+ ``explicit``:sub:`opt` ``framework``:sub:`opt` ``module`` '*' *attributes*:sub:`opt` '{' *inferred-submodule-member** '}'
+
+ *inferred-submodule-member*:
+ ``export`` '*'
+
+A module containing an *inferred-submodule-declaration* shall have either an umbrella header or an umbrella directory. The headers to which the *inferred-submodule-declaration* applies are exactly those headers included by the umbrella header (transitively) or included in the module because they reside within the umbrella directory (or its subdirectories).
+
+For each header included by the umbrella header or in the umbrella directory that is not named by a *header-declaration*, a module declaration is implicitly generated from the *inferred-submodule-declaration*. The module will:
+
+* Have the same name as the header (without the file extension)
+* Have the ``explicit`` specifier, if the *inferred-submodule-declaration* has the ``explicit`` specifier
+* Have the ``framework`` specifier, if the
+ *inferred-submodule-declaration* has the ``framework`` specifier
+* Have the attributes specified by the \ *inferred-submodule-declaration*
+* Contain a single *header-declaration* naming that header
+* Contain a single *export-declaration* ``export *``, if the \ *inferred-submodule-declaration* contains the \ *inferred-submodule-member* ``export *``
+
+**Example**: If the subdirectory "MyLib" contains the headers ``A.h`` and ``B.h``, then the following module map:
+
+.. parsed-literal::
+
+ module MyLib {
+ umbrella "MyLib"
+ explicit module * {
+ export *
+ }
+ }
+
+is equivalent to the (more verbose) module map:
+
+.. parsed-literal::
+
+ module MyLib {
+ explicit module A {
+ header "A.h"
+ export *
+ }
+
+ explicit module B {
+ header "B.h"
+ export *
+ }
+ }
+
+Export declaration
+~~~~~~~~~~~~~~~~~~
+An *export-declaration* specifies which imported modules will automatically be re-exported as part of a given module's API.
+
+.. parsed-literal::
+
+ *export-declaration*:
+ ``export`` *wildcard-module-id*
+
+ *wildcard-module-id*:
+ *identifier*
+ '*'
+ *identifier* '.' *wildcard-module-id*
+
+The *export-declaration* names a module or a set of modules that will be re-exported to any translation unit that imports the enclosing module. Each imported module that matches the *wildcard-module-id* up to, but not including, the first ``*`` will be re-exported.
+
+**Example**:: In the following example, importing ``MyLib.Derived`` also provides the API for ``MyLib.Base``:
+
+.. parsed-literal::
+
+ module MyLib {
+ module Base {
+ header "Base.h"
+ }
+
+ module Derived {
+ header "Derived.h"
+ export Base
+ }
+ }
+
+Note that, if ``Derived.h`` includes ``Base.h``, one can simply use a wildcard export to re-export everything ``Derived.h`` includes:
+
+.. parsed-literal::
+
+ module MyLib {
+ module Base {
+ header "Base.h"
+ }
+
+ module Derived {
+ header "Derived.h"
+ export *
+ }
+ }
+
+.. note::
+
+ The wildcard export syntax ``export *`` re-exports all of the
+ modules that were imported in the actual header file. Because
+ ``#include`` directives are automatically mapped to module imports,
+ ``export *`` provides the same transitive-inclusion behavior
+ provided by the C preprocessor, e.g., importing a given module
+ implicitly imports all of the modules on which it depends.
+ Therefore, liberal use of ``export *`` provides excellent backward
+ compatibility for programs that rely on transitive inclusion (i.e.,
+ all of them).
+
+Link declaration
+~~~~~~~~~~~~~~~~
+A *link-declaration* specifies a library or framework against which a program should be linked if the enclosing module is imported in any translation unit in that program.
+
+.. parsed-literal::
+
+ *link-declaration*:
+ ``link`` ``framework``:sub:`opt` *string-literal*
+
+The *string-literal* specifies the name of the library or framework against which the program should be linked. For example, specifying "clangBasic" would instruct the linker to link with ``-lclangBasic`` for a Unix-style linker.
+
+A *link-declaration* with the ``framework`` specifies that the linker should link against the named framework, e.g., with ``-framework MyFramework``.
+
+.. note::
+
+ Automatic linking with the ``link`` directive is not yet widely
+ implemented, because it requires support from both the object file
+ format and the linker. The notion is similar to Microsoft Visual
+ Studio's ``#pragma comment(lib...)``.
+
+Configuration macros declaration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The *config-macros-declaration* specifies the set of configuration macros that have an effect on the the API of the enclosing module.
+
+.. parsed-literal::
+
+ *config-macros-declaration*:
+ ``config_macros`` *attributes*:sub:`opt` *config-macro-list*:sub:`opt`
+
+ *config-macro-list*:
+ *identifier* (',' *identifier*)*
+
+Each *identifier* in the *config-macro-list* specifies the name of a macro. The compiler is required to maintain different variants of the given module for differing definitions of any of the named macros.
+
+A *config-macros-declaration* shall only be present on a top-level module, i.e., a module that is not nested within an enclosing module.
+
+The ``exhaustive`` attribute specifies that the list of macros in the *config-macros-declaration* is exhaustive, meaning that no other macro definition is intended to have an effect on the API of that module.
+
+.. note::
+
+ The ``exhaustive`` attribute implies that any macro definitions
+ for macros not listed as configuration macros should be ignored
+ completely when building the module. As an optimization, the
+ compiler could reduce the number of unique module variants by not
+ considering these non-configuration macros. This optimization is not
+ yet implemented in Clang.
+
+A translation unit shall not import the same module under different definitions of the configuration macros.
+
+.. note::
+
+ Clang implements a weak form of this requirement: the definitions
+ used for configuration macros are fixed based on the definitions
+ provided by the command line. If an import occurs and the definition
+ of any configuration macro has changed, the compiler will produce a
+ warning (under the control of ``-Wconfig-macros``).
+
+**Example:** A logging library might provide different API (e.g., in the form of different definitions for a logging macro) based on the ``NDEBUG`` macro setting:
+
+.. parsed-literal::
+
+ module MyLogger {
+ umbrella header "MyLogger.h"
+ config_macros [exhaustive] NDEBUG
+ }
+
+Conflict declarations
+~~~~~~~~~~~~~~~~~~~~~
+A *conflict-declaration* describes a case where the presence of two different modules in the same translation unit is likely to cause a problem. For example, two modules may provide similar-but-incompatible functionality.
+
+.. parsed-literal::
+
+ *conflict-declaration*:
+ ``conflict`` *module-id* ',' *string-literal*
+
+The *module-id* of the *conflict-declaration* specifies the module with which the enclosing module conflicts. The specified module shall not have been imported in the translation unit when the enclosing module is imported.
+
+The *string-literal* provides a message to be provided as part of the compiler diagnostic when two modules conflict.
+
+.. note::
+
+ Clang emits a warning (under the control of ``-Wmodule-conflict``)
+ when a module conflict is discovered.
+
+**Example:**
+
+.. parsed-literal::
+
+ module Conflicts {
+ explicit module A {
+ header "conflict_a.h"
+ conflict B, "we just don't like B"
+ }
+
+ module B {
+ header "conflict_b.h"
+ }
+ }
+
+
+Attributes
+----------
+Attributes are used in a number of places in the grammar to describe specific behavior of other declarations. The format of attributes is fairly simple.
+
+.. parsed-literal::
+
+ *attributes*:
+ *attribute* *attributes*:sub:`opt`
+
+ *attribute*:
+ '[' *identifier* ']'
+
+Any *identifier* can be used as an attribute, and each declaration specifies what attributes can be applied to it.
+
+Modularizing a Platform
+=======================
+To get any benefit out of modules, one needs to introduce module maps for software libraries starting at the bottom of the stack. This typically means introducing a module map covering the operating system's headers and the C standard library headers (in ``/usr/include``, for a Unix system).
+
+The module maps will be written using the `module map language`_, which provides the tools necessary to describe the mapping between headers and modules. Because the set of headers differs from one system to the next, the module map will likely have to be somewhat customized for, e.g., a particular distribution and version of the operating system. Moreover, the system headers themselves may require some modification, if they exhibit any anti-patterns that break modules. Such common patterns are described below.
+
+**Macro-guarded copy-and-pasted definitions**
+ System headers vend core types such as ``size_t`` for users. These types are often needed in a number of system headers, and are almost trivial to write. Hence, it is fairly common to see a definition such as the following copy-and-pasted throughout the headers:
+
+ .. parsed-literal::
+
+ #ifndef _SIZE_T
+ #define _SIZE_T
+ typedef __SIZE_TYPE__ size_t;
+ #endif
+
+ Unfortunately, when modules compiles all of the C library headers together into a single module, only the first actual type definition of ``size_t`` will be visible, and then only in the submodule corresponding to the lucky first header. Any other headers that have copy-and-pasted versions of this pattern will *not* have a definition of ``size_t``. Importing the submodule corresponding to one of those headers will therefore not yield ``size_t`` as part of the API, because it wasn't there when the header was parsed. The fix for this problem is either to pull the copied declarations into a common header that gets included everywhere ``size_t`` is part of the API, or to eliminate the ``#ifndef`` and redefine the ``size_t`` type. The latter works for C++ headers and C11, but will cause an error for non-modules C90/C99, where redefinition of ``typedefs`` is not permitted.
+
+**Conflicting definitions**
+ Different system headers may provide conflicting definitions for various macros, functions, or types. These conflicting definitions don't tend to cause problems in a pre-modules world unless someone happens to include both headers in one translation unit. Since the fix is often simply "don't do that", such problems persist. Modules requires that the conflicting definitions be eliminated or that they be placed in separate modules (the former is generally the better answer).
+
+**Missing includes**
+ Headers are often missing ``#include`` directives for headers that they actually depend on. As with the problem of conflicting definitions, this only affects unlucky users who don't happen to include headers in the right order. With modules, the headers of a particular module will be parsed in isolation, so the module may fail to build if there are missing includes.
+
+**Headers that vend multiple APIs at different times**
+ Some systems have headers that contain a number of different kinds of API definitions, only some of which are made available with a given include. For example, the header may vend ``size_t`` only when the macro ``__need_size_t`` is defined before that header is included, and also vend ``wchar_t`` only when the macro ``__need_wchar_t`` is defined. Such headers are often included many times in a single translation unit, and will have no include guards. There is no sane way to map this header to a submodule. One can either eliminate the header (e.g., by splitting it into separate headers, one per actual API) or simply ``exclude`` it in the module map.
+
+To detect and help address some of these problems, the ``clang-tools-extra`` repository contains a ``modularize`` tool that parses a set of given headers and attempts to detect these problems and produce a report. See the tool's in-source documentation for information on how to check your system or library headers.
+
+Future Directions
+=================
+Modules is an experimental feature, and there is much work left to do to make it both real and useful. Here are a few ideas:
+
+**Detect unused module imports**
+ Unlike with ``#include`` directives, it should be fairly simple to track whether a directly-imported module has ever been used. By doing so, Clang can emit ``unused import`` or ``unused #include`` diagnostics, including Fix-Its to remove the useless imports/includes.
+
+**Fix-Its for missing imports**
+ It's fairly common for one to make use of some API while writing code, only to get a compiler error about "unknown type" or "no function named" because the corresponding header has not been included. Clang should detect such cases and auto-import the required module (with a Fix-It!).
+
+**Improve modularize**
+ The modularize tool is both extremely important (for deployment) and extremely crude. It needs better UI, better detection of problems (especially for C++), and perhaps an assistant mode to help write module maps for you.
+
+**C++ Support**
+ Modules clearly has to work for C++, or we'll never get to use it for the Clang code base.
+
+Where To Learn More About Modules
+=================================
+The Clang source code provides additional information about modules:
+
+``clang/lib/Headers/module.map``
+ Module map for Clang's compiler-specific header files.
+
+``clang/test/Modules/``
+ Tests specifically related to modules functionality.
+
+``clang/include/clang/Basic/Module.h``
+ The ``Module`` class in this header describes a module, and is used throughout the compiler to implement modules.
+
+``clang/include/clang/Lex/ModuleMap.h``
+ The ``ModuleMap`` class in this header describes the full module map, consisting of all of the module map files that have been parsed, and providing facilities for looking up module maps and mapping between modules and headers (in both directions).
+
+PCHInternals_
+ Information about the serialized AST format used for precompiled headers and modules. The actual implementation is in the ``clangSerialization`` library.
+
+.. [#] Automatic linking against the libraries of modules requires specific linker support, which is not widely available.
+
+.. [#] Modules are only available in C and Objective-C; a separate flag ``-fcxx-modules`` enables modules support for C++, which is even more experimental and broken.
+
+.. [#] There are certain anti-patterns that occur in headers, particularly system headers, that cause problems for modules. The section `Modularizing a Platform`_ describes some of them.
+
+.. [#] The second instance is actually a new thread within the current process, not a separate process. However, the original compiler instance is blocked on the execution of this thread.
+
+.. [#] The preprocessing context in which the modules are parsed is actually dependent on the command-line options provided to the compiler, including the language dialect and any ``-D`` options. However, the compiled modules for different command-line options are kept distinct, and any preprocessor directives that occur within the translation unit are ignored. See the section on the `Configuration macros declaration`_ for more information.
+
+.. _PCHInternals: PCHInternals.html
+
diff --git a/docs/ObjectiveCLiterals.html b/docs/ObjectiveCLiterals.html
deleted file mode 100644
index d5a8a9e..0000000
--- a/docs/ObjectiveCLiterals.html
+++ /dev/null
@@ -1,423 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
-<html>
-<head>
- <META http-equiv="Content-Type" content="text/html; charset=UTF8">
- <title>Objective-C Literals</title>
- <link type="text/css" rel="stylesheet" href="../menu.css">
- <link type="text/css" rel="stylesheet" href="../content.css">
- <style type="text/css">
- td {
- vertical-align: top;
- }
- th { background-color: #ffddaa; }
- </style>
-</head>
-<body>
-
-<!--#include virtual="../menu.html.incl"-->
-
-<div id="content">
-
-<h1>Objective-C Literals</h1>
-
-<h2>Introduction</h2>
-
-<p>Three new features were introduced into clang at the same time: <i>NSNumber Literals</i> provide a syntax for creating <code>NSNumber</code> from scalar literal expressions; <i>Collection Literals</i> provide a short-hand for creating arrays and dictionaries; <i>Object Subscripting</i> provides a way to use subscripting with Objective-C objects. Users of Apple compiler releases can use these features starting with the Apple LLVM Compiler 4.0. Users of open-source LLVM.org compiler releases can use these features starting with clang v3.1.</p>
-
-<p>These language additions simplify common Objective-C programming patterns, make programs more concise, and improve the safety of container creation.</p>
-
-<p>This document describes how the features are implemented in clang, and how to use them in your own programs.</p>
-
-<h2>NSNumber Literals</h2>
-
-<p>The framework class <code>NSNumber</code> is used to wrap scalar values inside objects: signed and unsigned integers (<code>char</code>, <code>short</code>, <code>int</code>, <code>long</code>, <code>long long</code>), floating point numbers (<code>float</code>, <code>double</code>), and boolean values (<code>BOOL</code>, C++ <code>bool</code>). Scalar values wrapped in objects are also known as <i>boxed</i> values.</p>
-
-<p>In Objective-C, any character, numeric or boolean literal prefixed with the <code>'@'</code> character will evaluate to a pointer to an <code>NSNumber</code> object initialized with that value. C's type suffixes may be used to control the size of numeric literals.</p>
-
-<h3>Examples</h3>
-
-<p>The following program illustrates the rules for <code>NSNumber</code> literals:</p>
-
-<pre>
-void main(int argc, const char *argv[]) {
- // character literals.
- NSNumber *theLetterZ = @'Z'; // equivalent to [NSNumber numberWithChar:'Z']
-
- // integral literals.
- NSNumber *fortyTwo = @42; // equivalent to [NSNumber numberWithInt:42]
- NSNumber *fortyTwoUnsigned = @42U; // equivalent to [NSNumber numberWithUnsignedInt:42U]
- NSNumber *fortyTwoLong = @42L; // equivalent to [NSNumber numberWithLong:42L]
- NSNumber *fortyTwoLongLong = @42LL; // equivalent to [NSNumber numberWithLongLong:42LL]
-
- // floating point literals.
- NSNumber *piFloat = @3.141592654F; // equivalent to [NSNumber numberWithFloat:3.141592654F]
- NSNumber *piDouble = @3.1415926535; // equivalent to [NSNumber numberWithDouble:3.1415926535]
-
- // BOOL literals.
- NSNumber *yesNumber = @YES; // equivalent to [NSNumber numberWithBool:YES]
- NSNumber *noNumber = @NO; // equivalent to [NSNumber numberWithBool:NO]
-
-#ifdef __cplusplus
- NSNumber *trueNumber = @true; // equivalent to [NSNumber numberWithBool:(BOOL)true]
- NSNumber *falseNumber = @false; // equivalent to [NSNumber numberWithBool:(BOOL)false]
-#endif
-}
-</pre>
-
-<h3>Discussion</h3>
-
-<p>NSNumber literals only support literal scalar values after the <code>'@'</code>. Consequently, <code>@INT_MAX</code> works, but <code>@INT_MIN</code> does not, because they are defined like this:</p>
-
-<pre>
-#define INT_MAX 2147483647 /* max value for an int */
-#define INT_MIN (-2147483647-1) /* min value for an int */
-</pre>
-
-<p>The definition of <code>INT_MIN</code> is not a simple literal, but a parenthesized expression. Parenthesized
-expressions are supported using the <a href="#objc_boxed_expressions">boxed expression</a> syntax, which is described in the next section.</p>
-
-<p>Because <code>NSNumber</code> does not currently support wrapping <code>long double</code> values, the use of a <code>long double NSNumber</code> literal (e.g. <code>@123.23L</code>) will be rejected by the compiler.</p>
-
-<p>Previously, the <code>BOOL</code> type was simply a typedef for <code>signed char</code>, and <code>YES</code> and <code>NO</code> were macros that expand to <code>(BOOL)1</code> and <code>(BOOL)0</code> respectively. To support <code>@YES</code> and <code>@NO</code> expressions, these macros are now defined using new language keywords in <code>&LT;objc/objc.h&GT;</code>:</p>
-
-<pre>
-#if __has_feature(objc_bool)
-#define YES __objc_yes
-#define NO __objc_no
-#else
-#define YES ((BOOL)1)
-#define NO ((BOOL)0)
-#endif
-</pre>
-
-<p>The compiler implicitly converts <code>__objc_yes</code> and <code>__objc_no</code> to <code>(BOOL)1</code> and <code>(BOOL)0</code>. The keywords are used to disambiguate <code>BOOL</code> and integer literals.</p>
-
-<p>Objective-C++ also supports <code>@true</code> and <code>@false</code> expressions, which are equivalent to <code>@YES</code> and <code>@NO</code>.</p>
-
-<!-- ======================================================================= -->
-<h2 id="objc_boxed_expressions">Boxed Expressions</h2>
-<!-- ======================================================================= -->
-
-<p>Objective-C provides a new syntax for boxing C expressions:</p>
-
-<pre>
-<code>@( <em>expression</em> )</code>
-</pre>
-
-<p>Expressions of scalar (numeric, enumerated, BOOL) and C string pointer types
-are supported:</p>
-
-<pre>
-// numbers.
-NSNumber *smallestInt = @(-INT_MAX - 1); // [NSNumber numberWithInt:(-INT_MAX - 1)]
-NSNumber *piOverTwo = @(M_PI / 2); // [NSNumber numberWithDouble:(M_PI / 2)]
-
-// enumerated types.
-typedef enum { Red, Green, Blue } Color;
-NSNumber *favoriteColor = @(Green); // [NSNumber numberWithInt:((int)Green)]
-
-// strings.
-NSString *path = @(getenv("PATH")); // [NSString stringWithUTF8String:(getenv("PATH"))]
-NSArray *pathComponents = [path componentsSeparatedByString:@":"];
-</pre>
-
-<h3>Boxed Enums</h3>
-
-<p>
-Cocoa frameworks frequently define constant values using <em>enums.</em> Although enum values are integral, they may not be used directly as boxed literals (this avoids conflicts with future <code>'@'</code>-prefixed Objective-C keywords). Instead, an enum value must be placed inside a boxed expression. The following example demonstrates configuring an <code>AVAudioRecorder</code> using a dictionary that contains a boxed enumeration value:
-</p>
-
-<pre>
-enum {
- AVAudioQualityMin = 0,
- AVAudioQualityLow = 0x20,
- AVAudioQualityMedium = 0x40,
- AVAudioQualityHigh = 0x60,
- AVAudioQualityMax = 0x7F
-};
-
-- (AVAudioRecorder *)recordToFile:(NSURL *)fileURL {
- NSDictionary *settings = @{ AVEncoderAudioQualityKey : @(AVAudioQualityMax) };
- return [[AVAudioRecorder alloc] initWithURL:fileURL settings:settings error:NULL];
-}
-</pre>
-
-<p>
-The expression <code>@(AVAudioQualityMax)</code> converts <code>AVAudioQualityMax</code> to an integer type, and boxes the value accordingly. If the enum has a <a href="http://clang.llvm.org/docs/LanguageExtensions.html#objc_fixed_enum">fixed underlying type</a> as in:
-</p>
-
-<pre>
-typedef enum : unsigned char { Red, Green, Blue } Color;
-NSNumber *red = @(Red), *green = @(Green), *blue = @(Blue); // => [NSNumber numberWithUnsignedChar:]
-</pre>
-
-<p>
-then the fixed underlying type will be used to select the correct <code>NSNumber</code> creation method.
-</p>
-
-<p>
-Boxing a value of enum type will result in a <code>NSNumber</code> pointer with a creation method according to the underlying type of the enum,
-which can be a <a href="http://clang.llvm.org/docs/LanguageExtensions.html#objc_fixed_enum">fixed underlying type</a> or a compiler-defined
-integer type capable of representing the values of all the members of the enumeration:
-</p>
-
-<pre>
-typedef enum : unsigned char { Red, Green, Blue } Color;
-Color col = Red;
-NSNumber *nsCol = @(col); // => [NSNumber numberWithUnsignedChar:]
-</pre>
-
-<h3>Boxed C Strings</h3>
-
-<p>
-A C string literal prefixed by the <code>'@'</code> token denotes an <code>NSString</code> literal in the same way a numeric literal prefixed by the <code>'@'</code> token denotes an <code>NSNumber</code> literal. When the type of the parenthesized expression is <code>(char *)</code> or <code>(const char *)</code>, the result of the boxed expression is a pointer to an <code>NSString</code> object containing equivalent character data, which is assumed to be '\0'-terminated and UTF-8 encoded. The following example converts C-style command line arguments into <code>NSString</code> objects.
-</p>
-
-<pre>
-// Partition command line arguments into positional and option arguments.
-NSMutableArray *args = [NSMutableArray new];
-NSMutableDictionary *options = [NSMutableDictionary new];
-while (--argc) {
- const char *arg = *++argv;
- if (strncmp(arg, "--", 2) == 0) {
- options[@(arg + 2)] = @(*++argv); // --key value
- } else {
- [args addObject:@(arg)]; // positional argument
- }
-}
-</pre>
-
-<p>
-As with all C pointers, character pointer expressions can involve arbitrary pointer arithmetic, therefore programmers must ensure that the character data is valid. Passing <code>NULL</code> as the character pointer will raise an exception at runtime. When possible, the compiler will reject <code>NULL</code> character pointers used in boxed expressions.
-</p>
-
-<h3>Availability</h3>
-
-<p>Boxed expressions will be available in clang 3.2. It is not currently available in any Apple compiler.</p>
-
-<h2>Container Literals</h2>
-
-<p>Objective-C now supports a new expression syntax for creating immutable array and dictionary container objects.</p>
-
-<h3>Examples</h3>
-
-<p>Immutable array expression:</p>
-
-<pre>
-NSArray *array = @[ @"Hello", NSApp, [NSNumber numberWithInt:42] ];
-</pre>
-
-<p>This creates an <code>NSArray</code> with 3 elements. The comma-separated sub-expressions of an array literal can be any Objective-C object pointer typed expression.</p>
-
-<p>Immutable dictionary expression:</p>
-
-<pre>
-NSDictionary *dictionary = @{
- @"name" : NSUserName(),
- @"date" : [NSDate date],
- @"processInfo" : [NSProcessInfo processInfo]
-};
-</pre>
-
-<p>This creates an <code>NSDictionary</code> with 3 key/value pairs. Value sub-expressions of a dictionary literal must be Objective-C object pointer typed, as in array literals. Key sub-expressions must be of an Objective-C object pointer type that implements the <code>&LT;NSCopying&GT;</code> protocol.</p>
-
-<h3>Discussion</h3>
-
-<p>Neither keys nor values can have the value <code>nil</code> in containers. If the compiler can prove that a key or value is <code>nil</code> at compile time, then a warning will be emitted. Otherwise, a runtime error will occur.</p>
-
-<p>Using array and dictionary literals is safer than the variadic creation forms commonly in use today. Array literal expressions expand to calls to <code>+[NSArray arrayWithObjects:count:]</code>, which validates that all objects are non-<code>nil</code>. The variadic form, <code>+[NSArray arrayWithObjects:]</code> uses <code>nil</code> as an argument list terminator, which can lead to malformed array objects. Dictionary literals are similarly created with <code>+[NSDictionary dictionaryWithObjects:forKeys:count:]</code> which validates all objects and keys, unlike <code>+[NSDictionary dictionaryWithObjectsAndKeys:]</code> which also uses a <code>nil</code> parameter as an argument list terminator.</p>
-
-<h2>Object Subscripting</h2>
-
-<p>Objective-C object pointer values can now be used with C's subscripting operator.</p>
-
-<h3>Examples</h3>
-
-<p>The following code demonstrates the use of object subscripting syntax with <code>NSMutableArray</code> and <code>NSMutableDictionary</code> objects:</p>
-
-<pre>
-NSMutableArray *array = ...;
-NSUInteger idx = ...;
-id newObject = ...;
-id oldObject = array[idx];
-array[idx] = newObject; // replace oldObject with newObject
-
-NSMutableDictionary *dictionary = ...;
-NSString *key = ...;
-oldObject = dictionary[key];
-dictionary[key] = newObject; // replace oldObject with newObject
-</pre>
-
-<p>The next section explains how subscripting expressions map to accessor methods.</p>
-
-<h3>Subscripting Methods</h3>
-
-<p>Objective-C supports two kinds of subscript expressions: <i>array-style</i> subscript expressions use integer typed subscripts; <i>dictionary-style</i> subscript expressions use Objective-C object pointer typed subscripts. Each type of subscript expression is mapped to a message send using a predefined selector. The advantage of this design is flexibility: class designers are free to introduce subscripting by declaring methods or by adopting protocols. Moreover, because the method names are selected by the type of the subscript, an object can be subscripted using both array and dictionary styles.</p>
-
-<h4>Array-Style Subscripting</h4>
-
-<p>When the subscript operand has an integral type, the expression is rewritten to use one of two different selectors, depending on whether the element is being read or written. When an expression reads an element using an integral index, as in the following example:</p>
-
-<pre>
-NSUInteger idx = ...;
-id value = object[idx];
-</pre>
-
-<p>it is translated into a call to <code>objectAtIndexedSubscript:</code></p>
-
-<pre>
-id value = [object objectAtIndexedSubscript:idx];
-</pre>
-
-<p>When an expression writes an element using an integral index:</p>
-
-<pre>
-object[idx] = newValue;
-</pre>
-
-<p>it is translated to a call to <code>setObject:atIndexedSubscript:</code></p>
-
-<pre>
-[object setObject:newValue atIndexedSubscript:idx];
-</pre>
-
-<p>These message sends are then type-checked and performed just like explicit message sends. The method used for objectAtIndexedSubscript: must be declared with an argument of integral type and a return value of some Objective-C object pointer type. The method used for setObject:atIndexedSubscript: must be declared with its first argument having some Objective-C pointer type and its second argument having integral type.</p>
-
-<p>The meaning of indexes is left up to the declaring class. The compiler will coerce the index to the appropriate argument type of the method it uses for type-checking. For an instance of <code>NSArray</code>, reading an element using an index outside the range <code>[0, array.count)</code> will raise an exception. For an instance of <code>NSMutableArray</code>, assigning to an element using an index within this range will replace that element, but assigning to an element using an index outside this range will raise an exception; no syntax is provided for inserting, appending, or removing elements for mutable arrays.</p>
-
-<p>A class need not declare both methods in order to take advantage of this language feature. For example, the class <code>NSArray</code> declares only <code>objectAtIndexedSubscript:</code>, so that assignments to elements will fail to type-check; moreover, its subclass <code>NSMutableArray</code> declares <code>setObject:atIndexedSubscript:</code>.</p>
-
-<h4>Dictionary-Style Subscripting</h4>
-
-<p>When the subscript operand has an Objective-C object pointer type, the expression is rewritten to use one of two different selectors, depending on whether the element is being read from or written to. When an expression reads an element using an Objective-C object pointer subscript operand, as in the following example:</p>
-
-<pre>
-id key = ...;
-id value = object[key];
-</pre>
-
-<p>it is translated into a call to the <code>objectForKeyedSubscript:</code> method:</p>
-
-<pre>
-id value = [object objectForKeyedSubscript:key];
-</pre>
-
-<p>When an expression writes an element using an Objective-C object pointer subscript:</p>
-
-<pre>
-object[key] = newValue;
-</pre>
-
-<p>it is translated to a call to <code>setObject:forKeyedSubscript:</code></p>
-
-<pre>
-[object setObject:newValue forKeyedSubscript:key];
-</pre>
-
-<p>The behavior of <code>setObject:forKeyedSubscript:</code> is class-specific; but in general it should replace an existing value if one is already associated with a key, otherwise it should add a new value for the key. No syntax is provided for removing elements from mutable dictionaries.</p>
-
-<h3>Discussion</h3>
-
-<p>An Objective-C subscript expression occurs when the base operand of the C subscript operator has an Objective-C object pointer type. Since this potentially collides with pointer arithmetic on the value, these expressions are only supported under the modern Objective-C runtime, which categorically forbids such arithmetic.</p>
-
-<p>Currently, only subscripts of integral or Objective-C object pointer type are supported. In C++, a class type can be used if it has a single conversion function to an integral or Objective-C pointer type, in which case that conversion is applied and analysis continues as appropriate. Otherwise, the expression is ill-formed.</p>
-
-<p>An Objective-C object subscript expression is always an l-value. If the expression appears on the left-hand side of a simple assignment operator (=), the element is written as described below. If the expression appears on the left-hand side of a compound assignment operator (e.g. +=), the program is ill-formed, because the result of reading an element is always an Objective-C object pointer and no binary operators are legal on such pointers. If the expression appears in any other position, the element is read as described below. It is an error to take the address of a subscript expression, or (in C++) to bind a reference to it.</p>
-
-<p>Programs can use object subscripting with Objective-C object pointers of type <code>id</code>. Normal dynamic message send rules apply; the compiler must see <i>some</i> declaration of the subscripting methods, and will pick the declaration seen first.</p>
-
-<h2>Caveats</h2>
-
-<p>Objects created using the literal or boxed expression syntax are not guaranteed to be uniqued by the runtime, but nor are they guaranteed to be newly-allocated. As such, the result of performing direct comparisons against the location of an object literal (using <code>==</code>, <code>!=</code>, <code>&lt;</code>, <code>&lt;=</code>, <code>&gt;</code>, or <code>&gt;=</code>) is not well-defined. This is usually a simple mistake in code that intended to call the <code>isEqual:</code> method (or the <code>compare:</code> method).</p>
-
-<p>This caveat applies to compile-time string literals as well. Historically, string literals (using the <code>@"..."</code> syntax) have been uniqued across translation units during linking. This is an implementation detail of the compiler and should not be relied upon. If you are using such code, please use global string constants instead (<code>NSString * const MyConst = @"..."</code>) or use <code>isEqual:</code>.</p>
-
-<h2>Grammar Additions</h2>
-
-<p>To support the new syntax described above, the Objective-C <code>@</code>-expression grammar has the following new productions:</p>
-
-<pre>
-objc-at-expression : '@' (string-literal | encode-literal | selector-literal | protocol-literal | object-literal)
- ;
-
-object-literal : ('+' | '-')? numeric-constant
- | character-constant
- | boolean-constant
- | array-literal
- | dictionary-literal
- ;
-
-boolean-constant : '__objc_yes' | '__objc_no' | 'true' | 'false' /* boolean keywords. */
- ;
-
-array-literal : '[' assignment-expression-list ']'
- ;
-
-assignment-expression-list : assignment-expression (',' assignment-expression-list)?
- | /* empty */
- ;
-
-dictionary-literal : '{' key-value-list '}'
- ;
-
-key-value-list : key-value-pair (',' key-value-list)?
- | /* empty */
- ;
-
-key-value-pair : assignment-expression ':' assignment-expression
- ;
-</pre>
-
-<p>Note: <code>@true</code> and <code>@false</code> are only supported in Objective-C++.</p>
-
-<h2>Availability Checks</h2>
-
-<p>Programs test for the new features by using clang's __has_feature checks. Here are examples of their use:</p>
-
-<pre>
-#if __has_feature(objc_array_literals)
- // new way.
- NSArray *elements = @[ @"H", @"He", @"O", @"C" ];
-#else
- // old way (equivalent).
- id objects[] = { @"H", @"He", @"O", @"C" };
- NSArray *elements = [NSArray arrayWithObjects:objects count:4];
-#endif
-
-#if __has_feature(objc_dictionary_literals)
- // new way.
- NSDictionary *masses = @{ @"H" : @1.0078, @"He" : @4.0026, @"O" : @15.9990, @"C" : @12.0096 };
-#else
- // old way (equivalent).
- id keys[] = { @"H", @"He", @"O", @"C" };
- id values[] = { [NSNumber numberWithDouble:1.0078], [NSNumber numberWithDouble:4.0026],
- [NSNumber numberWithDouble:15.9990], [NSNumber numberWithDouble:12.0096] };
- NSDictionary *masses = [NSDictionary dictionaryWithObjects:objects forKeys:keys count:4];
-#endif
-
-#if __has_feature(objc_subscripting)
- NSUInteger i, count = elements.count;
- for (i = 0; i < count; ++i) {
- NSString *element = elements[i];
- NSNumber *mass = masses[element];
- NSLog(@"the mass of %@ is %@", element, mass);
- }
-#else
- NSUInteger i, count = [elements count];
- for (i = 0; i < count; ++i) {
- NSString *element = [elements objectAtIndex:i];
- NSNumber *mass = [masses objectForKey:element];
- NSLog(@"the mass of %@ is %@", element, mass);
- }
-#endif
-</pre>
-
-<p>Code can use also <code>__has_feature(objc_bool)</code> to check for the availability of numeric literals support. This checks for the new <code>__objc_yes / __objc_no</code> keywords, which enable the use of <code>@YES / @NO</code> literals.</p>
-
-<p>To check whether boxed expressions are supported, use <code>__has_feature(objc_boxed_expressions)</code> feature macro.</p>
-
-</div>
-</body>
-</html>
diff --git a/docs/ObjectiveCLiterals.rst b/docs/ObjectiveCLiterals.rst
new file mode 100644
index 0000000..92e4fb65
--- /dev/null
+++ b/docs/ObjectiveCLiterals.rst
@@ -0,0 +1,554 @@
+====================
+Objective-C Literals
+====================
+
+Introduction
+============
+
+Three new features were introduced into clang at the same time:
+*NSNumber Literals* provide a syntax for creating ``NSNumber`` from
+scalar literal expressions; *Collection Literals* provide a short-hand
+for creating arrays and dictionaries; *Object Subscripting* provides a
+way to use subscripting with Objective-C objects. Users of Apple
+compiler releases can use these features starting with the Apple LLVM
+Compiler 4.0. Users of open-source LLVM.org compiler releases can use
+these features starting with clang v3.1.
+
+These language additions simplify common Objective-C programming
+patterns, make programs more concise, and improve the safety of
+container creation.
+
+This document describes how the features are implemented in clang, and
+how to use them in your own programs.
+
+NSNumber Literals
+=================
+
+The framework class ``NSNumber`` is used to wrap scalar values inside
+objects: signed and unsigned integers (``char``, ``short``, ``int``,
+``long``, ``long long``), floating point numbers (``float``,
+``double``), and boolean values (``BOOL``, C++ ``bool``). Scalar values
+wrapped in objects are also known as *boxed* values.
+
+In Objective-C, any character, numeric or boolean literal prefixed with
+the ``'@'`` character will evaluate to a pointer to an ``NSNumber``
+object initialized with that value. C's type suffixes may be used to
+control the size of numeric literals.
+
+Examples
+--------
+
+The following program illustrates the rules for ``NSNumber`` literals:
+
+.. code-block:: objc
+
+ void main(int argc, const char *argv[]) {
+ // character literals.
+ NSNumber *theLetterZ = @'Z'; // equivalent to [NSNumber numberWithChar:'Z']
+
+ // integral literals.
+ NSNumber *fortyTwo = @42; // equivalent to [NSNumber numberWithInt:42]
+ NSNumber *fortyTwoUnsigned = @42U; // equivalent to [NSNumber numberWithUnsignedInt:42U]
+ NSNumber *fortyTwoLong = @42L; // equivalent to [NSNumber numberWithLong:42L]
+ NSNumber *fortyTwoLongLong = @42LL; // equivalent to [NSNumber numberWithLongLong:42LL]
+
+ // floating point literals.
+ NSNumber *piFloat = @3.141592654F; // equivalent to [NSNumber numberWithFloat:3.141592654F]
+ NSNumber *piDouble = @3.1415926535; // equivalent to [NSNumber numberWithDouble:3.1415926535]
+
+ // BOOL literals.
+ NSNumber *yesNumber = @YES; // equivalent to [NSNumber numberWithBool:YES]
+ NSNumber *noNumber = @NO; // equivalent to [NSNumber numberWithBool:NO]
+
+ #ifdef __cplusplus
+ NSNumber *trueNumber = @true; // equivalent to [NSNumber numberWithBool:(BOOL)true]
+ NSNumber *falseNumber = @false; // equivalent to [NSNumber numberWithBool:(BOOL)false]
+ #endif
+ }
+
+Discussion
+----------
+
+NSNumber literals only support literal scalar values after the ``'@'``.
+Consequently, ``@INT_MAX`` works, but ``@INT_MIN`` does not, because
+they are defined like this:
+
+.. code-block:: objc
+
+ #define INT_MAX 2147483647 /* max value for an int */
+ #define INT_MIN (-2147483647-1) /* min value for an int */
+
+The definition of ``INT_MIN`` is not a simple literal, but a
+parenthesized expression. Parenthesized expressions are supported using
+the `boxed expression <#objc_boxed_expressions>`_ syntax, which is
+described in the next section.
+
+Because ``NSNumber`` does not currently support wrapping ``long double``
+values, the use of a ``long double NSNumber`` literal (e.g.
+``@123.23L``) will be rejected by the compiler.
+
+Previously, the ``BOOL`` type was simply a typedef for ``signed char``,
+and ``YES`` and ``NO`` were macros that expand to ``(BOOL)1`` and
+``(BOOL)0`` respectively. To support ``@YES`` and ``@NO`` expressions,
+these macros are now defined using new language keywords in
+``&LT;objc/objc.h&GT;``:
+
+.. code-block:: objc
+
+ #if __has_feature(objc_bool)
+ #define YES __objc_yes
+ #define NO __objc_no
+ #else
+ #define YES ((BOOL)1)
+ #define NO ((BOOL)0)
+ #endif
+
+The compiler implicitly converts ``__objc_yes`` and ``__objc_no`` to
+``(BOOL)1`` and ``(BOOL)0``. The keywords are used to disambiguate
+``BOOL`` and integer literals.
+
+Objective-C++ also supports ``@true`` and ``@false`` expressions, which
+are equivalent to ``@YES`` and ``@NO``.
+
+Boxed Expressions
+=================
+
+Objective-C provides a new syntax for boxing C expressions:
+
+.. code-block:: objc
+
+ @( <expression> )
+
+Expressions of scalar (numeric, enumerated, BOOL) and C string pointer
+types are supported:
+
+.. code-block:: objc
+
+ // numbers.
+ NSNumber *smallestInt = @(-INT_MAX - 1); // [NSNumber numberWithInt:(-INT_MAX - 1)]
+ NSNumber *piOverTwo = @(M_PI / 2); // [NSNumber numberWithDouble:(M_PI / 2)]
+
+ // enumerated types.
+ typedef enum { Red, Green, Blue } Color;
+ NSNumber *favoriteColor = @(Green); // [NSNumber numberWithInt:((int)Green)]
+
+ // strings.
+ NSString *path = @(getenv("PATH")); // [NSString stringWithUTF8String:(getenv("PATH"))]
+ NSArray *pathComponents = [path componentsSeparatedByString:@":"];
+
+Boxed Enums
+-----------
+
+Cocoa frameworks frequently define constant values using *enums.*
+Although enum values are integral, they may not be used directly as
+boxed literals (this avoids conflicts with future ``'@'``-prefixed
+Objective-C keywords). Instead, an enum value must be placed inside a
+boxed expression. The following example demonstrates configuring an
+``AVAudioRecorder`` using a dictionary that contains a boxed enumeration
+value:
+
+.. code-block:: objc
+
+ enum {
+ AVAudioQualityMin = 0,
+ AVAudioQualityLow = 0x20,
+ AVAudioQualityMedium = 0x40,
+ AVAudioQualityHigh = 0x60,
+ AVAudioQualityMax = 0x7F
+ };
+
+ - (AVAudioRecorder *)recordToFile:(NSURL *)fileURL {
+ NSDictionary *settings = @{ AVEncoderAudioQualityKey : @(AVAudioQualityMax) };
+ return [[AVAudioRecorder alloc] initWithURL:fileURL settings:settings error:NULL];
+ }
+
+The expression ``@(AVAudioQualityMax)`` converts ``AVAudioQualityMax``
+to an integer type, and boxes the value accordingly. If the enum has a
+:ref:`fixed underlying type <objc-fixed-enum>` as in:
+
+.. code-block:: objc
+
+ typedef enum : unsigned char { Red, Green, Blue } Color;
+ NSNumber *red = @(Red), *green = @(Green), *blue = @(Blue); // => [NSNumber numberWithUnsignedChar:]
+
+then the fixed underlying type will be used to select the correct
+``NSNumber`` creation method.
+
+Boxing a value of enum type will result in a ``NSNumber`` pointer with a
+creation method according to the underlying type of the enum, which can
+be a :ref:`fixed underlying type <objc-fixed-enum>`
+or a compiler-defined integer type capable of representing the values of
+all the members of the enumeration:
+
+.. code-block:: objc
+
+ typedef enum : unsigned char { Red, Green, Blue } Color;
+ Color col = Red;
+ NSNumber *nsCol = @(col); // => [NSNumber numberWithUnsignedChar:]
+
+Boxed C Strings
+---------------
+
+A C string literal prefixed by the ``'@'`` token denotes an ``NSString``
+literal in the same way a numeric literal prefixed by the ``'@'`` token
+denotes an ``NSNumber`` literal. When the type of the parenthesized
+expression is ``(char *)`` or ``(const char *)``, the result of the
+boxed expression is a pointer to an ``NSString`` object containing
+equivalent character data, which is assumed to be '\\0'-terminated and
+UTF-8 encoded. The following example converts C-style command line
+arguments into ``NSString`` objects.
+
+.. code-block:: objc
+
+ // Partition command line arguments into positional and option arguments.
+ NSMutableArray *args = [NSMutableArray new];
+ NSMutableDictionary *options = [NSMutableDictionary new];
+ while (--argc) {
+ const char *arg = *++argv;
+ if (strncmp(arg, "--", 2) == 0) {
+ options[@(arg + 2)] = @(*++argv); // --key value
+ } else {
+ [args addObject:@(arg)]; // positional argument
+ }
+ }
+
+As with all C pointers, character pointer expressions can involve
+arbitrary pointer arithmetic, therefore programmers must ensure that the
+character data is valid. Passing ``NULL`` as the character pointer will
+raise an exception at runtime. When possible, the compiler will reject
+``NULL`` character pointers used in boxed expressions.
+
+Availability
+------------
+
+Boxed expressions will be available in clang 3.2. It is not currently
+available in any Apple compiler.
+
+Container Literals
+==================
+
+Objective-C now supports a new expression syntax for creating immutable
+array and dictionary container objects.
+
+Examples
+--------
+
+Immutable array expression:
+
+.. code-block:: objc
+
+ NSArray *array = @[ @"Hello", NSApp, [NSNumber numberWithInt:42] ];
+
+This creates an ``NSArray`` with 3 elements. The comma-separated
+sub-expressions of an array literal can be any Objective-C object
+pointer typed expression.
+
+Immutable dictionary expression:
+
+.. code-block:: objc
+
+ NSDictionary *dictionary = @{
+ @"name" : NSUserName(),
+ @"date" : [NSDate date],
+ @"processInfo" : [NSProcessInfo processInfo]
+ };
+
+This creates an ``NSDictionary`` with 3 key/value pairs. Value
+sub-expressions of a dictionary literal must be Objective-C object
+pointer typed, as in array literals. Key sub-expressions must be of an
+Objective-C object pointer type that implements the
+``&LT;NSCopying&GT;`` protocol.
+
+Discussion
+----------
+
+Neither keys nor values can have the value ``nil`` in containers. If the
+compiler can prove that a key or value is ``nil`` at compile time, then
+a warning will be emitted. Otherwise, a runtime error will occur.
+
+Using array and dictionary literals is safer than the variadic creation
+forms commonly in use today. Array literal expressions expand to calls
+to ``+[NSArray arrayWithObjects:count:]``, which validates that all
+objects are non-``nil``. The variadic form,
+``+[NSArray arrayWithObjects:]`` uses ``nil`` as an argument list
+terminator, which can lead to malformed array objects. Dictionary
+literals are similarly created with
+``+[NSDictionary dictionaryWithObjects:forKeys:count:]`` which validates
+all objects and keys, unlike
+``+[NSDictionary dictionaryWithObjectsAndKeys:]`` which also uses a
+``nil`` parameter as an argument list terminator.
+
+Object Subscripting
+===================
+
+Objective-C object pointer values can now be used with C's subscripting
+operator.
+
+Examples
+--------
+
+The following code demonstrates the use of object subscripting syntax
+with ``NSMutableArray`` and ``NSMutableDictionary`` objects:
+
+.. code-block:: objc
+
+ NSMutableArray *array = ...;
+ NSUInteger idx = ...;
+ id newObject = ...;
+ id oldObject = array[idx];
+ array[idx] = newObject; // replace oldObject with newObject
+
+ NSMutableDictionary *dictionary = ...;
+ NSString *key = ...;
+ oldObject = dictionary[key];
+ dictionary[key] = newObject; // replace oldObject with newObject
+
+The next section explains how subscripting expressions map to accessor
+methods.
+
+Subscripting Methods
+--------------------
+
+Objective-C supports two kinds of subscript expressions: *array-style*
+subscript expressions use integer typed subscripts; *dictionary-style*
+subscript expressions use Objective-C object pointer typed subscripts.
+Each type of subscript expression is mapped to a message send using a
+predefined selector. The advantage of this design is flexibility: class
+designers are free to introduce subscripting by declaring methods or by
+adopting protocols. Moreover, because the method names are selected by
+the type of the subscript, an object can be subscripted using both array
+and dictionary styles.
+
+Array-Style Subscripting
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+When the subscript operand has an integral type, the expression is
+rewritten to use one of two different selectors, depending on whether
+the element is being read or written. When an expression reads an
+element using an integral index, as in the following example:
+
+.. code-block:: objc
+
+ NSUInteger idx = ...;
+ id value = object[idx];
+
+it is translated into a call to ``objectAtIndexedSubscript:``
+
+.. code-block:: objc
+
+ id value = [object objectAtIndexedSubscript:idx];
+
+When an expression writes an element using an integral index:
+
+.. code-block:: objc
+
+ object[idx] = newValue;
+
+it is translated to a call to ``setObject:atIndexedSubscript:``
+
+.. code-block:: objc
+
+ [object setObject:newValue atIndexedSubscript:idx];
+
+These message sends are then type-checked and performed just like
+explicit message sends. The method used for objectAtIndexedSubscript:
+must be declared with an argument of integral type and a return value of
+some Objective-C object pointer type. The method used for
+setObject:atIndexedSubscript: must be declared with its first argument
+having some Objective-C pointer type and its second argument having
+integral type.
+
+The meaning of indexes is left up to the declaring class. The compiler
+will coerce the index to the appropriate argument type of the method it
+uses for type-checking. For an instance of ``NSArray``, reading an
+element using an index outside the range ``[0, array.count)`` will raise
+an exception. For an instance of ``NSMutableArray``, assigning to an
+element using an index within this range will replace that element, but
+assigning to an element using an index outside this range will raise an
+exception; no syntax is provided for inserting, appending, or removing
+elements for mutable arrays.
+
+A class need not declare both methods in order to take advantage of this
+language feature. For example, the class ``NSArray`` declares only
+``objectAtIndexedSubscript:``, so that assignments to elements will fail
+to type-check; moreover, its subclass ``NSMutableArray`` declares
+``setObject:atIndexedSubscript:``.
+
+Dictionary-Style Subscripting
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When the subscript operand has an Objective-C object pointer type, the
+expression is rewritten to use one of two different selectors, depending
+on whether the element is being read from or written to. When an
+expression reads an element using an Objective-C object pointer
+subscript operand, as in the following example:
+
+.. code-block:: objc
+
+ id key = ...;
+ id value = object[key];
+
+it is translated into a call to the ``objectForKeyedSubscript:`` method:
+
+.. code-block:: objc
+
+ id value = [object objectForKeyedSubscript:key];
+
+When an expression writes an element using an Objective-C object pointer
+subscript:
+
+.. code-block:: objc
+
+ object[key] = newValue;
+
+it is translated to a call to ``setObject:forKeyedSubscript:``
+
+.. code-block:: objc
+
+ [object setObject:newValue forKeyedSubscript:key];
+
+The behavior of ``setObject:forKeyedSubscript:`` is class-specific; but
+in general it should replace an existing value if one is already
+associated with a key, otherwise it should add a new value for the key.
+No syntax is provided for removing elements from mutable dictionaries.
+
+Discussion
+----------
+
+An Objective-C subscript expression occurs when the base operand of the
+C subscript operator has an Objective-C object pointer type. Since this
+potentially collides with pointer arithmetic on the value, these
+expressions are only supported under the modern Objective-C runtime,
+which categorically forbids such arithmetic.
+
+Currently, only subscripts of integral or Objective-C object pointer
+type are supported. In C++, a class type can be used if it has a single
+conversion function to an integral or Objective-C pointer type, in which
+case that conversion is applied and analysis continues as appropriate.
+Otherwise, the expression is ill-formed.
+
+An Objective-C object subscript expression is always an l-value. If the
+expression appears on the left-hand side of a simple assignment operator
+(=), the element is written as described below. If the expression
+appears on the left-hand side of a compound assignment operator (e.g.
++=), the program is ill-formed, because the result of reading an element
+is always an Objective-C object pointer and no binary operators are
+legal on such pointers. If the expression appears in any other position,
+the element is read as described below. It is an error to take the
+address of a subscript expression, or (in C++) to bind a reference to
+it.
+
+Programs can use object subscripting with Objective-C object pointers of
+type ``id``. Normal dynamic message send rules apply; the compiler must
+see *some* declaration of the subscripting methods, and will pick the
+declaration seen first.
+
+Caveats
+=======
+
+Objects created using the literal or boxed expression syntax are not
+guaranteed to be uniqued by the runtime, but nor are they guaranteed to
+be newly-allocated. As such, the result of performing direct comparisons
+against the location of an object literal (using ``==``, ``!=``, ``<``,
+``<=``, ``>``, or ``>=``) is not well-defined. This is usually a simple
+mistake in code that intended to call the ``isEqual:`` method (or the
+``compare:`` method).
+
+This caveat applies to compile-time string literals as well.
+Historically, string literals (using the ``@"..."`` syntax) have been
+uniqued across translation units during linking. This is an
+implementation detail of the compiler and should not be relied upon. If
+you are using such code, please use global string constants instead
+(``NSString * const MyConst = @"..."``) or use ``isEqual:``.
+
+Grammar Additions
+=================
+
+To support the new syntax described above, the Objective-C
+``@``-expression grammar has the following new productions:
+
+::
+
+ objc-at-expression : '@' (string-literal | encode-literal | selector-literal | protocol-literal | object-literal)
+ ;
+
+ object-literal : ('+' | '-')? numeric-constant
+ | character-constant
+ | boolean-constant
+ | array-literal
+ | dictionary-literal
+ ;
+
+ boolean-constant : '__objc_yes' | '__objc_no' | 'true' | 'false' /* boolean keywords. */
+ ;
+
+ array-literal : '[' assignment-expression-list ']'
+ ;
+
+ assignment-expression-list : assignment-expression (',' assignment-expression-list)?
+ | /* empty */
+ ;
+
+ dictionary-literal : '{' key-value-list '}'
+ ;
+
+ key-value-list : key-value-pair (',' key-value-list)?
+ | /* empty */
+ ;
+
+ key-value-pair : assignment-expression ':' assignment-expression
+ ;
+
+Note: ``@true`` and ``@false`` are only supported in Objective-C++.
+
+Availability Checks
+===================
+
+Programs test for the new features by using clang's \_\_has\_feature
+checks. Here are examples of their use:
+
+.. code-block:: objc
+
+ #if __has_feature(objc_array_literals)
+ // new way.
+ NSArray *elements = @[ @"H", @"He", @"O", @"C" ];
+ #else
+ // old way (equivalent).
+ id objects[] = { @"H", @"He", @"O", @"C" };
+ NSArray *elements = [NSArray arrayWithObjects:objects count:4];
+ #endif
+
+ #if __has_feature(objc_dictionary_literals)
+ // new way.
+ NSDictionary *masses = @{ @"H" : @1.0078, @"He" : @4.0026, @"O" : @15.9990, @"C" : @12.0096 };
+ #else
+ // old way (equivalent).
+ id keys[] = { @"H", @"He", @"O", @"C" };
+ id values[] = { [NSNumber numberWithDouble:1.0078], [NSNumber numberWithDouble:4.0026],
+ [NSNumber numberWithDouble:15.9990], [NSNumber numberWithDouble:12.0096] };
+ NSDictionary *masses = [NSDictionary dictionaryWithObjects:objects forKeys:keys count:4];
+ #endif
+
+ #if __has_feature(objc_subscripting)
+ NSUInteger i, count = elements.count;
+ for (i = 0; i < count; ++i) {
+ NSString *element = elements[i];
+ NSNumber *mass = masses[element];
+ NSLog(@"the mass of %@ is %@", element, mass);
+ }
+ #else
+ NSUInteger i, count = [elements count];
+ for (i = 0; i < count; ++i) {
+ NSString *element = [elements objectAtIndex:i];
+ NSNumber *mass = [masses objectForKey:element];
+ NSLog(@"the mass of %@ is %@", element, mass);
+ }
+ #endif
+
+Code can use also ``__has_feature(objc_bool)`` to check for the
+availability of numeric literals support. This checks for the new
+``__objc_yes / __objc_no`` keywords, which enable the use of
+``@YES / @NO`` literals.
+
+To check whether boxed expressions are supported, use
+``__has_feature(objc_boxed_expressions)`` feature macro.
diff --git a/docs/PCHInternals.html b/docs/PCHInternals.html
deleted file mode 100644
index 7fed5ba..0000000
--- a/docs/PCHInternals.html
+++ /dev/null
@@ -1,658 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <title>Precompiled Header and Modules Internals</title>
- <link type="text/css" rel="stylesheet" href="../menu.css">
- <link type="text/css" rel="stylesheet" href="../content.css">
- <style type="text/css">
- td {
- vertical-align: top;
- }
- </style>
-</head>
-
-<body>
-
-<!--#include virtual="../menu.html.incl"-->
-
-<div id="content">
-
-<h1>Precompiled Header and Modules Internals</h1>
-
- <p>This document describes the design and implementation of Clang's
- precompiled headers (PCH) and modules. If you are interested in the end-user
- view, please see the <a
- href="UsersManual.html#precompiledheaders">User's Manual</a>.</p>
-
- <p><b>Table of Contents</b></p>
- <ul>
- <li><a href="#usage">Using Precompiled Headers with
- <tt>clang</tt></a></li>
- <li><a href="#philosophy">Design Philosophy</a></li>
- <li><a href="#contents">Serialized AST File Contents</a>
- <ul>
- <li><a href="#metadata">Metadata Block</a></li>
- <li><a href="#sourcemgr">Source Manager Block</a></li>
- <li><a href="#preprocessor">Preprocessor Block</a></li>
- <li><a href="#types">Types Block</a></li>
- <li><a href="#decls">Declarations Block</a></li>
- <li><a href="#stmt">Statements and Expressions</a></li>
- <li><a href="#idtable">Identifier Table Block</a></li>
- <li><a href="#method-pool">Method Pool Block</a></li>
- </ul>
- </li>
- <li><a href="#tendrils">AST Reader Integration Points</a></li>
- <li><a href="#chained">Chained precompiled headers</a></li>
- <li><a href="#modules">Modules</a></li>
-</ul>
-
-<h2 id="usage">Using Precompiled Headers with <tt>clang</tt></h2>
-
-<p>The Clang compiler frontend, <tt>clang -cc1</tt>, supports two command line
-options for generating and using PCH files.<p>
-
-<p>To generate PCH files using <tt>clang -cc1</tt>, use the option
-<b><tt>-emit-pch</tt></b>:
-
-<pre> $ clang -cc1 test.h -emit-pch -o test.h.pch </pre>
-
-<p>This option is transparently used by <tt>clang</tt> when generating
-PCH files. The resulting PCH file contains the serialized form of the
-compiler's internal representation after it has completed parsing and
-semantic analysis. The PCH file can then be used as a prefix header
-with the <b><tt>-include-pch</tt></b> option:</p>
-
-<pre>
- $ clang -cc1 -include-pch test.h.pch test.c -o test.s
-</pre>
-
-<h2 id="philosophy">Design Philosophy</h2>
-
-<p>Precompiled headers are meant to improve overall compile times for
- projects, so the design of precompiled headers is entirely driven by
- performance concerns. The use case for precompiled headers is
- relatively simple: when there is a common set of headers that is
- included in nearly every source file in the project, we
- <i>precompile</i> that bundle of headers into a single precompiled
- header (PCH file). Then, when compiling the source files in the
- project, we load the PCH file first (as a prefix header), which acts
- as a stand-in for that bundle of headers.</p>
-
-<p>A precompiled header implementation improves performance when:</p>
-<ul>
- <li>Loading the PCH file is significantly faster than re-parsing the
- bundle of headers stored within the PCH file. Thus, a precompiled
- header design attempts to minimize the cost of reading the PCH
- file. Ideally, this cost should not vary with the size of the
- precompiled header file.</li>
-
- <li>The cost of generating the PCH file initially is not so large
- that it counters the per-source-file performance improvement due to
- eliminating the need to parse the bundled headers in the first
- place. This is particularly important on multi-core systems, because
- PCH file generation serializes the build when all compilations
- require the PCH file to be up-to-date.</li>
-</ul>
-
-<p>Modules, as implemented in Clang, use the same mechanisms as
-precompiled headers to save a serialized AST file (one per module) and
-use those AST modules. From an implementation standpoint, modules are
-a generalization of precompiled headers, lifting a number of
-restrictions placed on precompiled headers. In particular, there can
-only be one precompiled header and it must be included at the
-beginning of the translation unit. The extensions to the AST file
-format required for modules are discussed in the section on <a href="#modules">modules</a>.</p>
-
-<p>Clang's AST files are designed with a compact on-disk
-representation, which minimizes both creation time and the time
-required to initially load the AST file. The AST file itself contains
-a serialized representation of Clang's abstract syntax trees and
-supporting data structures, stored using the same compressed bitstream
-as <a href="http://llvm.org/docs/BitCodeFormat.html">LLVM's bitcode
-file format</a>.</p>
-
-<p>Clang's AST files are loaded "lazily" from disk. When an
-AST file is initially loaded, Clang reads only a small amount of data
-from the AST file to establish where certain important data structures
-are stored. The amount of data read in this initial load is
-independent of the size of the AST file, such that a larger AST file
-does not lead to longer AST load times. The actual header data in the
-AST file--macros, functions, variables, types, etc.--is loaded only
-when it is referenced from the user's code, at which point only that
-entity (and those entities it depends on) are deserialized from the
-AST file. With this approach, the cost of using an AST file
-for a translation unit is proportional to the amount of code actually
-used from the AST file, rather than being proportional to the size of
-the AST file itself.</p>
-
-<p>When given the <code>-print-stats</code> option, Clang produces
-statistics describing how much of the AST file was actually
-loaded from disk. For a simple "Hello, World!" program that includes
-the Apple <code>Cocoa.h</code> header (which is built as a precompiled
-header), this option illustrates how little of the actual precompiled
-header is required:</p>
-
-<pre>
-*** PCH Statistics:
- 933 stat cache hits
- 4 stat cache misses
- 895/39981 source location entries read (2.238563%)
- 19/15315 types read (0.124061%)
- 20/82685 declarations read (0.024188%)
- 154/58070 identifiers read (0.265197%)
- 0/7260 selectors read (0.000000%)
- 0/30842 statements read (0.000000%)
- 4/8400 macros read (0.047619%)
- 1/4995 lexical declcontexts read (0.020020%)
- 0/4413 visible declcontexts read (0.000000%)
- 0/7230 method pool entries read (0.000000%)
- 0 method pool misses
-</pre>
-
-<p>For this small program, only a tiny fraction of the source
-locations, types, declarations, identifiers, and macros were actually
-deserialized from the precompiled header. These statistics can be
-useful to determine whether the AST file implementation can
-be improved by making more of the implementation lazy.</p>
-
-<p>Precompiled headers can be chained. When you create a PCH while
-including an existing PCH, Clang can create the new PCH by referencing
-the original file and only writing the new data to the new file. For
-example, you could create a PCH out of all the headers that are very
-commonly used throughout your project, and then create a PCH for every
-single source file in the project that includes the code that is
-specific to that file, so that recompiling the file itself is very fast,
-without duplicating the data from the common headers for every
-file. The mechanisms behind chained precompiled headers are discussed
-in a <a href="#chained">later section</a>.
-
-<h2 id="contents">AST File Contents</h2>
-
-<img src="PCHLayout.png" style="float:right" alt="Precompiled header layout">
-
-<p>Clang's AST files are organized into several different
-blocks, each of which contains the serialized representation of a part
-of Clang's internal representation. Each of the blocks corresponds to
-either a block or a record within <a
- href="http://llvm.org/docs/BitCodeFormat.html">LLVM's bitstream
-format</a>. The contents of each of these logical blocks are described
-below.</p>
-
-<p>For a given AST file, the <a
-href="http://llvm.org/cmds/llvm-bcanalyzer.html"><code>llvm-bcanalyzer</code></a>
-utility can be used to examine the actual structure of the bitstream
-for the AST file. This information can be used both to help
-understand the structure of the AST file and to isolate
-areas where AST files can still be optimized, e.g., through
-the introduction of abbreviations.</p>
-
-<h3 id="metadata">Metadata Block</h3>
-
-<p>The metadata block contains several records that provide
-information about how the AST file was built. This metadata
-is primarily used to validate the use of an AST file. For
-example, a precompiled header built for a 32-bit x86 target cannot be used
-when compiling for a 64-bit x86 target. The metadata block contains
-information about:</p>
-
-<dl>
- <dt>Language options</dt>
- <dd>Describes the particular language dialect used to compile the
-AST file, including major options (e.g., Objective-C support) and more
-minor options (e.g., support for "//" comments). The contents of this
-record correspond to the <code>LangOptions</code> class.</dd>
-
- <dt>Target architecture</dt>
- <dd>The target triple that describes the architecture, platform, and
-ABI for which the AST file was generated, e.g.,
-<code>i386-apple-darwin9</code>.</dd>
-
- <dt>AST version</dt>
- <dd>The major and minor version numbers of the AST file
-format. Changes in the minor version number should not affect backward
-compatibility, while changes in the major version number imply that a
-newer compiler cannot read an older precompiled header (and
-vice-versa).</dd>
-
- <dt>Original file name</dt>
- <dd>The full path of the header that was used to generate the
-AST file.</dd>
-
- <dt>Predefines buffer</dt>
- <dd>Although not explicitly stored as part of the metadata, the
-predefines buffer is used in the validation of the AST file.
-The predefines buffer itself contains code generated by the compiler
-to initialize the preprocessor state according to the current target,
-platform, and command-line options. For example, the predefines buffer
-will contain "<code>#define __STDC__ 1</code>" when we are compiling C
-without Microsoft extensions. The predefines buffer itself is stored
-within the <a href="#sourcemgr">source manager block</a>, but its
-contents are verified along with the rest of the metadata.</dd>
-
-</dl>
-
-<p>A chained PCH file (that is, one that references another PCH) and a
-module (which may import other modules) have additional metadata
-containing the list of all AST files that this AST file depends
-on. Each of those files will be loaded along with this AST file.</p>
-
-<p>For chained precompiled headers, the language options, target
-architecture and predefines buffer data is taken from the end of the
-chain, since they have to match anyway.</p>
-
-<h3 id="sourcemgr">Source Manager Block</h3>
-
-<p>The source manager block contains the serialized representation of
-Clang's <a
- href="InternalsManual.html#SourceLocation">SourceManager</a> class,
-which handles the mapping from source locations (as represented in
-Clang's abstract syntax tree) into actual column/line positions within
-a source file or macro instantiation. The AST file's
-representation of the source manager also includes information about
-all of the headers that were (transitively) included when building the
-AST file.</p>
-
-<p>The bulk of the source manager block is dedicated to information
-about the various files, buffers, and macro instantiations into which
-a source location can refer. Each of these is referenced by a numeric
-"file ID", which is a unique number (allocated starting at 1) stored
-in the source location. Clang serializes the information for each kind
-of file ID, along with an index that maps file IDs to the position
-within the AST file where the information about that file ID is
-stored. The data associated with a file ID is loaded only when
-required by the front end, e.g., to emit a diagnostic that includes a
-macro instantiation history inside the header itself.</p>
-
-<p>The source manager block also contains information about all of the
-headers that were included when building the AST file. This
-includes information about the controlling macro for the header (e.g.,
-when the preprocessor identified that the contents of the header
-dependent on a macro like <code>LLVM_CLANG_SOURCEMANAGER_H</code>)
-along with a cached version of the results of the <code>stat()</code>
-system calls performed when building the AST file. The
-latter is particularly useful in reducing system time when searching
-for include files.</p>
-
-<h3 id="preprocessor">Preprocessor Block</h3>
-
-<p>The preprocessor block contains the serialized representation of
-the preprocessor. Specifically, it contains all of the macros that
-have been defined by the end of the header used to build the
-AST file, along with the token sequences that comprise each
-macro. The macro definitions are only read from the AST file when the
-name of the macro first occurs in the program. This lazy loading of
-macro definitions is triggered by lookups into the <a
- href="#idtable">identifier table</a>.</p>
-
-<h3 id="types">Types Block</h3>
-
-<p>The types block contains the serialized representation of all of
-the types referenced in the translation unit. Each Clang type node
-(<code>PointerType</code>, <code>FunctionProtoType</code>, etc.) has a
-corresponding record type in the AST file. When types are deserialized
-from the AST file, the data within the record is used to
-reconstruct the appropriate type node using the AST context.</p>
-
-<p>Each type has a unique type ID, which is an integer that uniquely
-identifies that type. Type ID 0 represents the NULL type, type IDs
-less than <code>NUM_PREDEF_TYPE_IDS</code> represent predefined types
-(<code>void</code>, <code>float</code>, etc.), while other
-"user-defined" type IDs are assigned consecutively from
-<code>NUM_PREDEF_TYPE_IDS</code> upward as the types are encountered.
-The AST file has an associated mapping from the user-defined types
-block to the location within the types block where the serialized
-representation of that type resides, enabling lazy deserialization of
-types. When a type is referenced from within the AST file, that
-reference is encoded using the type ID shifted left by 3 bits. The
-lower three bits are used to represent the <code>const</code>,
-<code>volatile</code>, and <code>restrict</code> qualifiers, as in
-Clang's <a
- href="http://clang.llvm.org/docs/InternalsManual.html#Type">QualType</a>
-class.</p>
-
-<h3 id="decls">Declarations Block</h3>
-
-<p>The declarations block contains the serialized representation of
-all of the declarations referenced in the translation unit. Each Clang
-declaration node (<code>VarDecl</code>, <code>FunctionDecl</code>,
-etc.) has a corresponding record type in the AST file. When
-declarations are deserialized from the AST file, the data
-within the record is used to build and populate a new instance of the
-corresponding <code>Decl</code> node. As with types, each declaration
-node has a numeric ID that is used to refer to that declaration within
-the AST file. In addition, a lookup table provides a mapping from that
-numeric ID to the offset within the precompiled header where that
-declaration is described.</p>
-
-<p>Declarations in Clang's abstract syntax trees are stored
-hierarchically. At the top of the hierarchy is the translation unit
-(<code>TranslationUnitDecl</code>), which contains all of the
-declarations in the translation unit but is not actually written as a
-specific declaration node. Its child declarations (such as
-functions or struct types) may also contain other declarations inside
-them, and so on. Within Clang, each declaration is stored within a <a
-href="http://clang.llvm.org/docs/InternalsManual.html#DeclContext">declaration
-context</a>, as represented by the <code>DeclContext</code> class.
-Declaration contexts provide the mechanism to perform name lookup
-within a given declaration (e.g., find the member named <code>x</code>
-in a structure) and iterate over the declarations stored within a
-context (e.g., iterate over all of the fields of a structure for
-structure layout).</p>
-
-<p>In Clang's AST file format, deserializing a declaration
-that is a <code>DeclContext</code> is a separate operation from
-deserializing all of the declarations stored within that declaration
-context. Therefore, Clang will deserialize the translation unit
-declaration without deserializing the declarations within that
-translation unit. When required, the declarations stored within a
-declaration context will be deserialized. There are two representations
-of the declarations within a declaration context, which correspond to
-the name-lookup and iteration behavior described above:</p>
-
-<ul>
- <li>When the front end performs name lookup to find a name
- <code>x</code> within a given declaration context (for example,
- during semantic analysis of the expression <code>p-&gt;x</code>,
- where <code>p</code>'s type is defined in the precompiled header),
- Clang refers to an on-disk hash table that maps from the names
- within that declaration context to the declaration IDs that
- represent each visible declaration with that name. The actual
- declarations will then be deserialized to provide the results of
- name lookup.</li>
-
- <li>When the front end performs iteration over all of the
- declarations within a declaration context, all of those declarations
- are immediately de-serialized. For large declaration contexts (e.g.,
- the translation unit), this operation is expensive; however, large
- declaration contexts are not traversed in normal compilation, since
- such a traversal is unnecessary. However, it is common for the code
- generator and semantic analysis to traverse declaration contexts for
- structs, classes, unions, and enumerations, although those contexts
- contain relatively few declarations in the common case.</li>
-</ul>
-
-<h3 id="stmt">Statements and Expressions</h3>
-
-<p>Statements and expressions are stored in the AST file in
-both the <a href="#types">types</a> and the <a
- href="#decls">declarations</a> blocks, because every statement or
-expression will be associated with either a type or declaration. The
-actual statement and expression records are stored immediately
-following the declaration or type that owns the statement or
-expression. For example, the statement representing the body of a
-function will be stored directly following the declaration of the
-function.</p>
-
-<p>As with types and declarations, each statement and expression kind
-in Clang's abstract syntax tree (<code>ForStmt</code>,
-<code>CallExpr</code>, etc.) has a corresponding record type in the
-AST file, which contains the serialized representation of
-that statement or expression. Each substatement or subexpression
-within an expression is stored as a separate record (which keeps most
-records to a fixed size). Within the AST file, the
-subexpressions of an expression are stored, in reverse order, prior to the expression
-that owns those expression, using a form of <a
-href="http://en.wikipedia.org/wiki/Reverse_Polish_notation">Reverse
-Polish Notation</a>. For example, an expression <code>3 - 4 + 5</code>
-would be represented as follows:</p>
-
-<table border="1">
- <tr><td><code>IntegerLiteral(5)</code></td></tr>
- <tr><td><code>IntegerLiteral(4)</code></td></tr>
- <tr><td><code>IntegerLiteral(3)</code></td></tr>
- <tr><td><code>BinaryOperator(-)</code></td></tr>
- <tr><td><code>BinaryOperator(+)</code></td></tr>
- <tr><td>STOP</td></tr>
-</table>
-
-<p>When reading this representation, Clang evaluates each expression
-record it encounters, builds the appropriate abstract syntax tree node,
-and then pushes that expression on to a stack. When a record contains <i>N</i>
-subexpressions--<code>BinaryOperator</code> has two of them--those
-expressions are popped from the top of the stack. The special STOP
-code indicates that we have reached the end of a serialized expression
-or statement; other expression or statement records may follow, but
-they are part of a different expression.</p>
-
-<h3 id="idtable">Identifier Table Block</h3>
-
-<p>The identifier table block contains an on-disk hash table that maps
-each identifier mentioned within the AST file to the
-serialized representation of the identifier's information (e.g, the
-<code>IdentifierInfo</code> structure). The serialized representation
-contains:</p>
-
-<ul>
- <li>The actual identifier string.</li>
- <li>Flags that describe whether this identifier is the name of a
- built-in, a poisoned identifier, an extension token, or a
- macro.</li>
- <li>If the identifier names a macro, the offset of the macro
- definition within the <a href="#preprocessor">preprocessor
- block</a>.</li>
- <li>If the identifier names one or more declarations visible from
- translation unit scope, the <a href="#decls">declaration IDs</a> of these
- declarations.</li>
-</ul>
-
-<p>When an AST file is loaded, the AST file reader
-mechanism introduces itself into the identifier table as an external
-lookup source. Thus, when the user program refers to an identifier
-that has not yet been seen, Clang will perform a lookup into the
-identifier table. If an identifier is found, its contents (macro
-definitions, flags, top-level declarations, etc.) will be
-deserialized, at which point the corresponding
-<code>IdentifierInfo</code> structure will have the same contents it
-would have after parsing the headers in the AST file.</p>
-
-<p>Within the AST file, the identifiers used to name declarations are represented with an integral value. A separate table provides a mapping from this integral value (the identifier ID) to the location within the on-disk
-hash table where that identifier is stored. This mapping is used when
-deserializing the name of a declaration, the identifier of a token, or
-any other construct in the AST file that refers to a name.</p>
-
-<h3 id="method-pool">Method Pool Block</h3>
-
-<p>The method pool block is represented as an on-disk hash table that
-serves two purposes: it provides a mapping from the names of
-Objective-C selectors to the set of Objective-C instance and class
-methods that have that particular selector (which is required for
-semantic analysis in Objective-C) and also stores all of the selectors
-used by entities within the AST file. The design of the
-method pool is similar to that of the <a href="#idtable">identifier
-table</a>: the first time a particular selector is formed during the
-compilation of the program, Clang will search in the on-disk hash
-table of selectors; if found, Clang will read the Objective-C methods
-associated with that selector into the appropriate front-end data
-structure (<code>Sema::InstanceMethodPool</code> and
-<code>Sema::FactoryMethodPool</code> for instance and class methods,
-respectively).</p>
-
-<p>As with identifiers, selectors are represented by numeric values
-within the AST file. A separate index maps these numeric selector
-values to the offset of the selector within the on-disk hash table,
-and will be used when de-serializing an Objective-C method declaration
-(or other Objective-C construct) that refers to the selector.</p>
-
-<h2 id="tendrils">AST Reader Integration Points</h2>
-
-<p>The "lazy" deserialization behavior of AST files requires
-their integration into several completely different submodules of
-Clang. For example, lazily deserializing the declarations during name
-lookup requires that the name-lookup routines be able to query the
-AST file to find entities stored there.</p>
-
-<p>For each Clang data structure that requires direct interaction with
-the AST reader logic, there is an abstract class that provides
-the interface between the two modules. The <code>ASTReader</code>
-class, which handles the loading of an AST file, inherits
-from all of these abstract classes to provide lazy deserialization of
-Clang's data structures. <code>ASTReader</code> implements the
-following abstract classes:</p>
-
-<dl>
- <dt><code>StatSysCallCache</code></dt>
- <dd>This abstract interface is associated with the
- <code>FileManager</code> class, and is used whenever the file
- manager is going to perform a <code>stat()</code> system call.</dd>
-
- <dt><code>ExternalSLocEntrySource</code></dt>
- <dd>This abstract interface is associated with the
- <code>SourceManager</code> class, and is used whenever the
- <a href="#sourcemgr">source manager</a> needs to load the details
- of a file, buffer, or macro instantiation.</dd>
-
- <dt><code>IdentifierInfoLookup</code></dt>
- <dd>This abstract interface is associated with the
- <code>IdentifierTable</code> class, and is used whenever the
- program source refers to an identifier that has not yet been seen.
- In this case, the AST reader searches for
- this identifier within its <a href="#idtable">identifier table</a>
- to load any top-level declarations or macros associated with that
- identifier.</dd>
-
- <dt><code>ExternalASTSource</code></dt>
- <dd>This abstract interface is associated with the
- <code>ASTContext</code> class, and is used whenever the abstract
- syntax tree nodes need to loaded from the AST file. It
- provides the ability to de-serialize declarations and types
- identified by their numeric values, read the bodies of functions
- when required, and read the declarations stored within a
- declaration context (either for iteration or for name lookup).</dd>
-
- <dt><code>ExternalSemaSource</code></dt>
- <dd>This abstract interface is associated with the <code>Sema</code>
- class, and is used whenever semantic analysis needs to read
- information from the <a href="#methodpool">global method
- pool</a>.</dd>
-</dl>
-
-<h2 id="chained">Chained precompiled headers</h2>
-
-<p>Chained precompiled headers were initially intended to improve the
-performance of IDE-centric operations such as syntax highlighting and
-code completion while a particular source file is being edited by the
-user. To minimize the amount of reparsing required after a change to
-the file, a form of precompiled header--called a precompiled
-<i>preamble</i>--is automatically generated by parsing all of the
-headers in the source file, up to and including the last
-#include. When only the source file changes (and none of the headers
-it depends on), reparsing of that source file can use the precompiled
-preamble and start parsing after the #includes, so parsing time is
-proportional to the size of the source file (rather than all of its
-includes). However, the compilation of that translation unit
-may already use a precompiled header: in this case, Clang will create
-the precompiled preamble as a chained precompiled header that refers
-to the original precompiled header. This drastically reduces the time
-needed to serialize the precompiled preamble for use in reparsing.</p>
-
-<p>Chained precompiled headers get their name because each precompiled header
-can depend on one other precompiled header, forming a chain of
-dependencies. A translation unit will then include the precompiled
-header that starts the chain (i.e., nothing depends on it). This
-linearity of dependencies is important for the semantic model of
-chained precompiled headers, because the most-recent precompiled
-header can provide information that overrides the information provided
-by the precompiled headers it depends on, just like a header file
-<code>B.h</code> that includes another header <code>A.h</code> can
-modify the state produced by parsing <code>A.h</code>, e.g., by
-<code>#undef</code>'ing a macro defined in <code>A.h</code>.</p>
-
-<p>There are several ways in which chained precompiled headers
-generalize the AST file model:</p>
-
-<dl>
- <dt>Numbering of IDs</dt>
- <dd>Many different kinds of entities--identifiers, declarations,
- types, etc.---have ID numbers that start at 1 or some other
- predefined constant and grow upward. Each precompiled header records
- the maximum ID number it has assigned in each category. Then, when a
- new precompiled header is generated that depends on (chains to)
- another precompiled header, it will start counting at the next
- available ID number. This way, one can determine, given an ID
- number, which AST file actually contains the entity.</dd>
-
- <dt>Name lookup</dt>
- <dd>When writing a chained precompiled header, Clang attempts to
- write only information that has changed from the precompiled header
- on which it is based. This changes the lookup algorithm for the
- various tables, such as the <a href="#idtable">identifier table</a>:
- the search starts at the most-recent precompiled header. If no entry
- is found, lookup then proceeds to the identifier table in the
- precompiled header it depends on, and so one. Once a lookup
- succeeds, that result is considered definitive, overriding any
- results from earlier precompiled headers.</dd>
-
- <dt>Update records</dt>
- <dd>There are various ways in which a later precompiled header can
- modify the entities described in an earlier precompiled header. For
- example, later precompiled headers can add entries into the various
- name-lookup tables for the translation unit or namespaces, or add
- new categories to an Objective-C class. Each of these updates is
- captured in an "update record" that is stored in the chained
- precompiled header file and will be loaded along with the original
- entity.</dd>
-</dl>
-
-<h2 id="modules">Modules</h2>
-
-<p>Modules generalize the chained precompiled header model yet
-further, from a linear chain of precompiled headers to an arbitrary
-directed acyclic graph (DAG) of AST files. All of the same techniques
-used to make chained precompiled headers work---ID number, name
-lookup, update records---are shared with modules. However, the DAG
-nature of modules introduce a number of additional complications to
-the model:
-
-<dl>
- <dt>Numbering of IDs</dt>
- <dd>The simple, linear numbering scheme used in chained precompiled
- headers falls apart with the module DAG, because different modules
- may end up with different numbering schemes for entities they
- imported from common shared modules. To account for this, each
- module file provides information about which modules it depends on
- and which ID numbers it assigned to the entities in those modules,
- as well as which ID numbers it took for its own new entities. The
- AST reader then maps these "local" ID numbers into a "global" ID
- number space for the current translation unit, providing a 1-1
- mapping between entities (in whatever AST file they inhabit) and
- global ID numbers. If that translation unit is then serialized into
- an AST file, this mapping will be stored for use when the AST file
- is imported.</dd>
-
- <dt>Declaration merging</dt>
- <dd>It is possible for a given entity (from the language's
- perspective) to be declared multiple times in different places. For
- example, two different headers can have the declaration of
- <tt>printf</tt> or could forward-declare <tt>struct stat</tt>. If
- each of those headers is included in a module, and some third party
- imports both of those modules, there is a potentially serious
- problem: name lookup for <tt>printf</tt> or <tt>struct stat</tt> will
- find both declarations, but the AST nodes are unrelated. This would
- result in a compilation error, due to an ambiguity in name
- lookup. Therefore, the AST reader performs declaration merging
- according to the appropriate language semantics, ensuring that the
- two disjoint declarations are merged into a single redeclaration
- chain (with a common canonical declaration), so that it is as if one
- of the headers had been included before the other.</dd>
-
- <dt>Name Visibility</dt>
- <dd>Modules allow certain names that occur during module creation to
- be "hidden", so that they are not part of the public interface of
- the module and are not visible to its clients. The AST reader
- maintains a "visible" bit on various AST nodes (declarations, macros,
- etc.) to indicate whether that particular AST node is currently
- visible; the various name lookup mechanisms in Clang inspect the
- visible bit to determine whether that entity, which is still in the
- AST (because other, visible AST nodes may depend on it), can
- actually be found by name lookup. When a new (sub)module is
- imported, it may make existing, non-visible, already-deserialized
- AST nodes visible; it is the responsibility of the AST reader to
- find and update these AST nodes when it is notified of the import.</dd>
-
-</dl>
-
-</div>
-
-</body>
-</html>
diff --git a/docs/PCHInternals.rst b/docs/PCHInternals.rst
new file mode 100644
index 0000000..a36e65c
--- /dev/null
+++ b/docs/PCHInternals.rst
@@ -0,0 +1,561 @@
+========================================
+Precompiled Header and Modules Internals
+========================================
+
+.. contents::
+ :local:
+
+This document describes the design and implementation of Clang's precompiled
+headers (PCH) and modules. If you are interested in the end-user view, please
+see the :ref:`User's Manual <usersmanual-precompiled-headers>`.
+
+Using Precompiled Headers with ``clang``
+----------------------------------------
+
+The Clang compiler frontend, ``clang -cc1``, supports two command line options
+for generating and using PCH files.
+
+To generate PCH files using ``clang -cc1``, use the option :option:`-emit-pch`:
+
+.. code-block:: bash
+
+ $ clang -cc1 test.h -emit-pch -o test.h.pch
+
+This option is transparently used by ``clang`` when generating PCH files. The
+resulting PCH file contains the serialized form of the compiler's internal
+representation after it has completed parsing and semantic analysis. The PCH
+file can then be used as a prefix header with the :option:`-include-pch`
+option:
+
+.. code-block:: bash
+
+ $ clang -cc1 -include-pch test.h.pch test.c -o test.s
+
+Design Philosophy
+-----------------
+
+Precompiled headers are meant to improve overall compile times for projects, so
+the design of precompiled headers is entirely driven by performance concerns.
+The use case for precompiled headers is relatively simple: when there is a
+common set of headers that is included in nearly every source file in the
+project, we *precompile* that bundle of headers into a single precompiled
+header (PCH file). Then, when compiling the source files in the project, we
+load the PCH file first (as a prefix header), which acts as a stand-in for that
+bundle of headers.
+
+A precompiled header implementation improves performance when:
+
+* Loading the PCH file is significantly faster than re-parsing the bundle of
+ headers stored within the PCH file. Thus, a precompiled header design
+ attempts to minimize the cost of reading the PCH file. Ideally, this cost
+ should not vary with the size of the precompiled header file.
+
+* The cost of generating the PCH file initially is not so large that it
+ counters the per-source-file performance improvement due to eliminating the
+ need to parse the bundled headers in the first place. This is particularly
+ important on multi-core systems, because PCH file generation serializes the
+ build when all compilations require the PCH file to be up-to-date.
+
+Modules, as implemented in Clang, use the same mechanisms as precompiled
+headers to save a serialized AST file (one per module) and use those AST
+modules. From an implementation standpoint, modules are a generalization of
+precompiled headers, lifting a number of restrictions placed on precompiled
+headers. In particular, there can only be one precompiled header and it must
+be included at the beginning of the translation unit. The extensions to the
+AST file format required for modules are discussed in the section on
+:ref:`modules <pchinternals-modules>`.
+
+Clang's AST files are designed with a compact on-disk representation, which
+minimizes both creation time and the time required to initially load the AST
+file. The AST file itself contains a serialized representation of Clang's
+abstract syntax trees and supporting data structures, stored using the same
+compressed bitstream as `LLVM's bitcode file format
+<http://llvm.org/docs/BitCodeFormat.html>`_.
+
+Clang's AST files are loaded "lazily" from disk. When an AST file is initially
+loaded, Clang reads only a small amount of data from the AST file to establish
+where certain important data structures are stored. The amount of data read in
+this initial load is independent of the size of the AST file, such that a
+larger AST file does not lead to longer AST load times. The actual header data
+in the AST file --- macros, functions, variables, types, etc. --- is loaded
+only when it is referenced from the user's code, at which point only that
+entity (and those entities it depends on) are deserialized from the AST file.
+With this approach, the cost of using an AST file for a translation unit is
+proportional to the amount of code actually used from the AST file, rather than
+being proportional to the size of the AST file itself.
+
+When given the :option:`-print-stats` option, Clang produces statistics
+describing how much of the AST file was actually loaded from disk. For a
+simple "Hello, World!" program that includes the Apple ``Cocoa.h`` header
+(which is built as a precompiled header), this option illustrates how little of
+the actual precompiled header is required:
+
+.. code-block:: none
+
+ *** AST File Statistics:
+ 895/39981 source location entries read (2.238563%)
+ 19/15315 types read (0.124061%)
+ 20/82685 declarations read (0.024188%)
+ 154/58070 identifiers read (0.265197%)
+ 0/7260 selectors read (0.000000%)
+ 0/30842 statements read (0.000000%)
+ 4/8400 macros read (0.047619%)
+ 1/4995 lexical declcontexts read (0.020020%)
+ 0/4413 visible declcontexts read (0.000000%)
+ 0/7230 method pool entries read (0.000000%)
+ 0 method pool misses
+
+For this small program, only a tiny fraction of the source locations, types,
+declarations, identifiers, and macros were actually deserialized from the
+precompiled header. These statistics can be useful to determine whether the
+AST file implementation can be improved by making more of the implementation
+lazy.
+
+Precompiled headers can be chained. When you create a PCH while including an
+existing PCH, Clang can create the new PCH by referencing the original file and
+only writing the new data to the new file. For example, you could create a PCH
+out of all the headers that are very commonly used throughout your project, and
+then create a PCH for every single source file in the project that includes the
+code that is specific to that file, so that recompiling the file itself is very
+fast, without duplicating the data from the common headers for every file. The
+mechanisms behind chained precompiled headers are discussed in a :ref:`later
+section <pchinternals-chained>`.
+
+AST File Contents
+-----------------
+
+Clang's AST files are organized into several different blocks, each of which
+contains the serialized representation of a part of Clang's internal
+representation. Each of the blocks corresponds to either a block or a record
+within `LLVM's bitstream format <http://llvm.org/docs/BitCodeFormat.html>`_.
+The contents of each of these logical blocks are described below.
+
+.. image:: PCHLayout.png
+
+For a given AST file, the `llvm-bcanalyzer
+<http://llvm.org/docs/CommandGuide/llvm-bcanalyzer.html>`_ utility can be used
+to examine the actual structure of the bitstream for the AST file. This
+information can be used both to help understand the structure of the AST file
+and to isolate areas where AST files can still be optimized, e.g., through the
+introduction of abbreviations.
+
+Metadata Block
+^^^^^^^^^^^^^^
+
+The metadata block contains several records that provide information about how
+the AST file was built. This metadata is primarily used to validate the use of
+an AST file. For example, a precompiled header built for a 32-bit x86 target
+cannot be used when compiling for a 64-bit x86 target. The metadata block
+contains information about:
+
+Language options
+ Describes the particular language dialect used to compile the AST file,
+ including major options (e.g., Objective-C support) and more minor options
+ (e.g., support for "``//``" comments). The contents of this record correspond to
+ the ``LangOptions`` class.
+
+Target architecture
+ The target triple that describes the architecture, platform, and ABI for
+ which the AST file was generated, e.g., ``i386-apple-darwin9``.
+
+AST version
+ The major and minor version numbers of the AST file format. Changes in the
+ minor version number should not affect backward compatibility, while changes
+ in the major version number imply that a newer compiler cannot read an older
+ precompiled header (and vice-versa).
+
+Original file name
+ The full path of the header that was used to generate the AST file.
+
+Predefines buffer
+ Although not explicitly stored as part of the metadata, the predefines buffer
+ is used in the validation of the AST file. The predefines buffer itself
+ contains code generated by the compiler to initialize the preprocessor state
+ according to the current target, platform, and command-line options. For
+ example, the predefines buffer will contain "``#define __STDC__ 1``" when we
+ are compiling C without Microsoft extensions. The predefines buffer itself
+ is stored within the :ref:`pchinternals-sourcemgr`, but its contents are
+ verified along with the rest of the metadata.
+
+A chained PCH file (that is, one that references another PCH) and a module
+(which may import other modules) have additional metadata containing the list
+of all AST files that this AST file depends on. Each of those files will be
+loaded along with this AST file.
+
+For chained precompiled headers, the language options, target architecture and
+predefines buffer data is taken from the end of the chain, since they have to
+match anyway.
+
+.. _pchinternals-sourcemgr:
+
+Source Manager Block
+^^^^^^^^^^^^^^^^^^^^
+
+The source manager block contains the serialized representation of Clang's
+:ref:`SourceManager <SourceManager>` class, which handles the mapping from
+source locations (as represented in Clang's abstract syntax tree) into actual
+column/line positions within a source file or macro instantiation. The AST
+file's representation of the source manager also includes information about all
+of the headers that were (transitively) included when building the AST file.
+
+The bulk of the source manager block is dedicated to information about the
+various files, buffers, and macro instantiations into which a source location
+can refer. Each of these is referenced by a numeric "file ID", which is a
+unique number (allocated starting at 1) stored in the source location. Clang
+serializes the information for each kind of file ID, along with an index that
+maps file IDs to the position within the AST file where the information about
+that file ID is stored. The data associated with a file ID is loaded only when
+required by the front end, e.g., to emit a diagnostic that includes a macro
+instantiation history inside the header itself.
+
+The source manager block also contains information about all of the headers
+that were included when building the AST file. This includes information about
+the controlling macro for the header (e.g., when the preprocessor identified
+that the contents of the header dependent on a macro like
+``LLVM_CLANG_SOURCEMANAGER_H``).
+
+.. _pchinternals-preprocessor:
+
+Preprocessor Block
+^^^^^^^^^^^^^^^^^^
+
+The preprocessor block contains the serialized representation of the
+preprocessor. Specifically, it contains all of the macros that have been
+defined by the end of the header used to build the AST file, along with the
+token sequences that comprise each macro. The macro definitions are only read
+from the AST file when the name of the macro first occurs in the program. This
+lazy loading of macro definitions is triggered by lookups into the
+:ref:`identifier table <pchinternals-ident-table>`.
+
+.. _pchinternals-types:
+
+Types Block
+^^^^^^^^^^^
+
+The types block contains the serialized representation of all of the types
+referenced in the translation unit. Each Clang type node (``PointerType``,
+``FunctionProtoType``, etc.) has a corresponding record type in the AST file.
+When types are deserialized from the AST file, the data within the record is
+used to reconstruct the appropriate type node using the AST context.
+
+Each type has a unique type ID, which is an integer that uniquely identifies
+that type. Type ID 0 represents the NULL type, type IDs less than
+``NUM_PREDEF_TYPE_IDS`` represent predefined types (``void``, ``float``, etc.),
+while other "user-defined" type IDs are assigned consecutively from
+``NUM_PREDEF_TYPE_IDS`` upward as the types are encountered. The AST file has
+an associated mapping from the user-defined types block to the location within
+the types block where the serialized representation of that type resides,
+enabling lazy deserialization of types. When a type is referenced from within
+the AST file, that reference is encoded using the type ID shifted left by 3
+bits. The lower three bits are used to represent the ``const``, ``volatile``,
+and ``restrict`` qualifiers, as in Clang's :ref:`QualType <QualType>` class.
+
+.. _pchinternals-decls:
+
+Declarations Block
+^^^^^^^^^^^^^^^^^^
+
+The declarations block contains the serialized representation of all of the
+declarations referenced in the translation unit. Each Clang declaration node
+(``VarDecl``, ``FunctionDecl``, etc.) has a corresponding record type in the
+AST file. When declarations are deserialized from the AST file, the data
+within the record is used to build and populate a new instance of the
+corresponding ``Decl`` node. As with types, each declaration node has a
+numeric ID that is used to refer to that declaration within the AST file. In
+addition, a lookup table provides a mapping from that numeric ID to the offset
+within the precompiled header where that declaration is described.
+
+Declarations in Clang's abstract syntax trees are stored hierarchically. At
+the top of the hierarchy is the translation unit (``TranslationUnitDecl``),
+which contains all of the declarations in the translation unit but is not
+actually written as a specific declaration node. Its child declarations (such
+as functions or struct types) may also contain other declarations inside them,
+and so on. Within Clang, each declaration is stored within a :ref:`declaration
+context <DeclContext>`, as represented by the ``DeclContext`` class.
+Declaration contexts provide the mechanism to perform name lookup within a
+given declaration (e.g., find the member named ``x`` in a structure) and
+iterate over the declarations stored within a context (e.g., iterate over all
+of the fields of a structure for structure layout).
+
+In Clang's AST file format, deserializing a declaration that is a
+``DeclContext`` is a separate operation from deserializing all of the
+declarations stored within that declaration context. Therefore, Clang will
+deserialize the translation unit declaration without deserializing the
+declarations within that translation unit. When required, the declarations
+stored within a declaration context will be deserialized. There are two
+representations of the declarations within a declaration context, which
+correspond to the name-lookup and iteration behavior described above:
+
+* When the front end performs name lookup to find a name ``x`` within a given
+ declaration context (for example, during semantic analysis of the expression
+ ``p->x``, where ``p``'s type is defined in the precompiled header), Clang
+ refers to an on-disk hash table that maps from the names within that
+ declaration context to the declaration IDs that represent each visible
+ declaration with that name. The actual declarations will then be
+ deserialized to provide the results of name lookup.
+* When the front end performs iteration over all of the declarations within a
+ declaration context, all of those declarations are immediately
+ de-serialized. For large declaration contexts (e.g., the translation unit),
+ this operation is expensive; however, large declaration contexts are not
+ traversed in normal compilation, since such a traversal is unnecessary.
+ However, it is common for the code generator and semantic analysis to
+ traverse declaration contexts for structs, classes, unions, and
+ enumerations, although those contexts contain relatively few declarations in
+ the common case.
+
+Statements and Expressions
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Statements and expressions are stored in the AST file in both the :ref:`types
+<pchinternals-types>` and the :ref:`declarations <pchinternals-decls>` blocks,
+because every statement or expression will be associated with either a type or
+declaration. The actual statement and expression records are stored
+immediately following the declaration or type that owns the statement or
+expression. For example, the statement representing the body of a function
+will be stored directly following the declaration of the function.
+
+As with types and declarations, each statement and expression kind in Clang's
+abstract syntax tree (``ForStmt``, ``CallExpr``, etc.) has a corresponding
+record type in the AST file, which contains the serialized representation of
+that statement or expression. Each substatement or subexpression within an
+expression is stored as a separate record (which keeps most records to a fixed
+size). Within the AST file, the subexpressions of an expression are stored, in
+reverse order, prior to the expression that owns those expression, using a form
+of `Reverse Polish Notation
+<http://en.wikipedia.org/wiki/Reverse_Polish_notation>`_. For example, an
+expression ``3 - 4 + 5`` would be represented as follows:
+
++-----------------------+
+| ``IntegerLiteral(5)`` |
++-----------------------+
+| ``IntegerLiteral(4)`` |
++-----------------------+
+| ``IntegerLiteral(3)`` |
++-----------------------+
+| ``IntegerLiteral(-)`` |
++-----------------------+
+| ``IntegerLiteral(+)`` |
++-----------------------+
+| ``STOP`` |
++-----------------------+
+
+When reading this representation, Clang evaluates each expression record it
+encounters, builds the appropriate abstract syntax tree node, and then pushes
+that expression on to a stack. When a record contains *N* subexpressions ---
+``BinaryOperator`` has two of them --- those expressions are popped from the
+top of the stack. The special STOP code indicates that we have reached the end
+of a serialized expression or statement; other expression or statement records
+may follow, but they are part of a different expression.
+
+.. _pchinternals-ident-table:
+
+Identifier Table Block
+^^^^^^^^^^^^^^^^^^^^^^
+
+The identifier table block contains an on-disk hash table that maps each
+identifier mentioned within the AST file to the serialized representation of
+the identifier's information (e.g, the ``IdentifierInfo`` structure). The
+serialized representation contains:
+
+* The actual identifier string.
+* Flags that describe whether this identifier is the name of a built-in, a
+ poisoned identifier, an extension token, or a macro.
+* If the identifier names a macro, the offset of the macro definition within
+ the :ref:`pchinternals-preprocessor`.
+* If the identifier names one or more declarations visible from translation
+ unit scope, the :ref:`declaration IDs <pchinternals-decls>` of these
+ declarations.
+
+When an AST file is loaded, the AST file reader mechanism introduces itself
+into the identifier table as an external lookup source. Thus, when the user
+program refers to an identifier that has not yet been seen, Clang will perform
+a lookup into the identifier table. If an identifier is found, its contents
+(macro definitions, flags, top-level declarations, etc.) will be deserialized,
+at which point the corresponding ``IdentifierInfo`` structure will have the
+same contents it would have after parsing the headers in the AST file.
+
+Within the AST file, the identifiers used to name declarations are represented
+with an integral value. A separate table provides a mapping from this integral
+value (the identifier ID) to the location within the on-disk hash table where
+that identifier is stored. This mapping is used when deserializing the name of
+a declaration, the identifier of a token, or any other construct in the AST
+file that refers to a name.
+
+.. _pchinternals-method-pool:
+
+Method Pool Block
+^^^^^^^^^^^^^^^^^
+
+The method pool block is represented as an on-disk hash table that serves two
+purposes: it provides a mapping from the names of Objective-C selectors to the
+set of Objective-C instance and class methods that have that particular
+selector (which is required for semantic analysis in Objective-C) and also
+stores all of the selectors used by entities within the AST file. The design
+of the method pool is similar to that of the :ref:`identifier table
+<pchinternals-ident-table>`: the first time a particular selector is formed
+during the compilation of the program, Clang will search in the on-disk hash
+table of selectors; if found, Clang will read the Objective-C methods
+associated with that selector into the appropriate front-end data structure
+(``Sema::InstanceMethodPool`` and ``Sema::FactoryMethodPool`` for instance and
+class methods, respectively).
+
+As with identifiers, selectors are represented by numeric values within the AST
+file. A separate index maps these numeric selector values to the offset of the
+selector within the on-disk hash table, and will be used when de-serializing an
+Objective-C method declaration (or other Objective-C construct) that refers to
+the selector.
+
+AST Reader Integration Points
+-----------------------------
+
+The "lazy" deserialization behavior of AST files requires their integration
+into several completely different submodules of Clang. For example, lazily
+deserializing the declarations during name lookup requires that the name-lookup
+routines be able to query the AST file to find entities stored there.
+
+For each Clang data structure that requires direct interaction with the AST
+reader logic, there is an abstract class that provides the interface between
+the two modules. The ``ASTReader`` class, which handles the loading of an AST
+file, inherits from all of these abstract classes to provide lazy
+deserialization of Clang's data structures. ``ASTReader`` implements the
+following abstract classes:
+
+``ExternalSLocEntrySource``
+ This abstract interface is associated with the ``SourceManager`` class, and
+ is used whenever the :ref:`source manager <pchinternals-sourcemgr>` needs to
+ load the details of a file, buffer, or macro instantiation.
+
+``IdentifierInfoLookup``
+ This abstract interface is associated with the ``IdentifierTable`` class, and
+ is used whenever the program source refers to an identifier that has not yet
+ been seen. In this case, the AST reader searches for this identifier within
+ its :ref:`identifier table <pchinternals-ident-table>` to load any top-level
+ declarations or macros associated with that identifier.
+
+``ExternalASTSource``
+ This abstract interface is associated with the ``ASTContext`` class, and is
+ used whenever the abstract syntax tree nodes need to loaded from the AST
+ file. It provides the ability to de-serialize declarations and types
+ identified by their numeric values, read the bodies of functions when
+ required, and read the declarations stored within a declaration context
+ (either for iteration or for name lookup).
+
+``ExternalSemaSource``
+ This abstract interface is associated with the ``Sema`` class, and is used
+ whenever semantic analysis needs to read information from the :ref:`global
+ method pool <pchinternals-method-pool>`.
+
+.. _pchinternals-chained:
+
+Chained precompiled headers
+---------------------------
+
+Chained precompiled headers were initially intended to improve the performance
+of IDE-centric operations such as syntax highlighting and code completion while
+a particular source file is being edited by the user. To minimize the amount
+of reparsing required after a change to the file, a form of precompiled header
+--- called a precompiled *preamble* --- is automatically generated by parsing
+all of the headers in the source file, up to and including the last
+``#include``. When only the source file changes (and none of the headers it
+depends on), reparsing of that source file can use the precompiled preamble and
+start parsing after the ``#include``\ s, so parsing time is proportional to the
+size of the source file (rather than all of its includes). However, the
+compilation of that translation unit may already use a precompiled header: in
+this case, Clang will create the precompiled preamble as a chained precompiled
+header that refers to the original precompiled header. This drastically
+reduces the time needed to serialize the precompiled preamble for use in
+reparsing.
+
+Chained precompiled headers get their name because each precompiled header can
+depend on one other precompiled header, forming a chain of dependencies. A
+translation unit will then include the precompiled header that starts the chain
+(i.e., nothing depends on it). This linearity of dependencies is important for
+the semantic model of chained precompiled headers, because the most-recent
+precompiled header can provide information that overrides the information
+provided by the precompiled headers it depends on, just like a header file
+``B.h`` that includes another header ``A.h`` can modify the state produced by
+parsing ``A.h``, e.g., by ``#undef``'ing a macro defined in ``A.h``.
+
+There are several ways in which chained precompiled headers generalize the AST
+file model:
+
+Numbering of IDs
+ Many different kinds of entities --- identifiers, declarations, types, etc.
+ --- have ID numbers that start at 1 or some other predefined constant and
+ grow upward. Each precompiled header records the maximum ID number it has
+ assigned in each category. Then, when a new precompiled header is generated
+ that depends on (chains to) another precompiled header, it will start
+ counting at the next available ID number. This way, one can determine, given
+ an ID number, which AST file actually contains the entity.
+
+Name lookup
+ When writing a chained precompiled header, Clang attempts to write only
+ information that has changed from the precompiled header on which it is
+ based. This changes the lookup algorithm for the various tables, such as the
+ :ref:`identifier table <pchinternals-ident-table>`: the search starts at the
+ most-recent precompiled header. If no entry is found, lookup then proceeds
+ to the identifier table in the precompiled header it depends on, and so one.
+ Once a lookup succeeds, that result is considered definitive, overriding any
+ results from earlier precompiled headers.
+
+Update records
+ There are various ways in which a later precompiled header can modify the
+ entities described in an earlier precompiled header. For example, later
+ precompiled headers can add entries into the various name-lookup tables for
+ the translation unit or namespaces, or add new categories to an Objective-C
+ class. Each of these updates is captured in an "update record" that is
+ stored in the chained precompiled header file and will be loaded along with
+ the original entity.
+
+.. _pchinternals-modules:
+
+Modules
+-------
+
+Modules generalize the chained precompiled header model yet further, from a
+linear chain of precompiled headers to an arbitrary directed acyclic graph
+(DAG) of AST files. All of the same techniques used to make chained
+precompiled headers work --- ID number, name lookup, update records --- are
+shared with modules. However, the DAG nature of modules introduce a number of
+additional complications to the model:
+
+Numbering of IDs
+ The simple, linear numbering scheme used in chained precompiled headers falls
+ apart with the module DAG, because different modules may end up with
+ different numbering schemes for entities they imported from common shared
+ modules. To account for this, each module file provides information about
+ which modules it depends on and which ID numbers it assigned to the entities
+ in those modules, as well as which ID numbers it took for its own new
+ entities. The AST reader then maps these "local" ID numbers into a "global"
+ ID number space for the current translation unit, providing a 1-1 mapping
+ between entities (in whatever AST file they inhabit) and global ID numbers.
+ If that translation unit is then serialized into an AST file, this mapping
+ will be stored for use when the AST file is imported.
+
+Declaration merging
+ It is possible for a given entity (from the language's perspective) to be
+ declared multiple times in different places. For example, two different
+ headers can have the declaration of ``printf`` or could forward-declare
+ ``struct stat``. If each of those headers is included in a module, and some
+ third party imports both of those modules, there is a potentially serious
+ problem: name lookup for ``printf`` or ``struct stat`` will find both
+ declarations, but the AST nodes are unrelated. This would result in a
+ compilation error, due to an ambiguity in name lookup. Therefore, the AST
+ reader performs declaration merging according to the appropriate language
+ semantics, ensuring that the two disjoint declarations are merged into a
+ single redeclaration chain (with a common canonical declaration), so that it
+ is as if one of the headers had been included before the other.
+
+Name Visibility
+ Modules allow certain names that occur during module creation to be "hidden",
+ so that they are not part of the public interface of the module and are not
+ visible to its clients. The AST reader maintains a "visible" bit on various
+ AST nodes (declarations, macros, etc.) to indicate whether that particular
+ AST node is currently visible; the various name lookup mechanisms in Clang
+ inspect the visible bit to determine whether that entity, which is still in
+ the AST (because other, visible AST nodes may depend on it), can actually be
+ found by name lookup. When a new (sub)module is imported, it may make
+ existing, non-visible, already-deserialized AST nodes visible; it is the
+ responsibility of the AST reader to find and update these AST nodes when it
+ is notified of the import.
+
diff --git a/docs/PTHInternals.html b/docs/PTHInternals.html
deleted file mode 100644
index b15f681..0000000
--- a/docs/PTHInternals.html
+++ /dev/null
@@ -1,179 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-<html>
- <head>
- <title>Pretokenized Headers (PTH)</title>
- <link type="text/css" rel="stylesheet" href="../menu.css">
- <link type="text/css" rel="stylesheet" href="../content.css">
- <style type="text/css">
- td {
- vertical-align: top;
- }
- </style>
-</head>
-<body>
-
-<!--#include virtual="../menu.html.incl"-->
-
-<div id="content">
-
-<h1>Pretokenized Headers (PTH)</h1>
-
-<p>This document first describes the low-level
-interface for using PTH and then briefly elaborates on its design and
-implementation. If you are interested in the end-user view, please see the
-<a href="UsersManual.html#precompiledheaders">User's Manual</a>.</p>
-
-
-<h2>Using Pretokenized Headers with <tt>clang</tt> (Low-level Interface)</h2>
-
-<p>The Clang compiler frontend, <tt>clang -cc1</tt>, supports three command line
-options for generating and using PTH files.<p>
-
-<p>To generate PTH files using <tt>clang -cc1</tt>, use the option
-<b><tt>-emit-pth</tt></b>:
-
-<pre> $ clang -cc1 test.h -emit-pth -o test.h.pth </pre>
-
-<p>This option is transparently used by <tt>clang</tt> when generating PTH
-files. Similarly, PTH files can be used as prefix headers using the
-<b><tt>-include-pth</tt></b> option:</p>
-
-<pre>
- $ clang -cc1 -include-pth test.h.pth test.c -o test.s
-</pre>
-
-<p>Alternatively, Clang's PTH files can be used as a raw &quot;token-cache&quot;
-(or &quot;content&quot; cache) of the source included by the original header
-file. This means that the contents of the PTH file are searched as substitutes
-for <em>any</em> source files that are used by <tt>clang -cc1</tt> to process a
-source file. This is done by specifying the <b><tt>-token-cache</tt></b>
-option:</p>
-
-<pre>
- $ cat test.h
- #include &lt;stdio.h&gt;
- $ clang -cc1 -emit-pth test.h -o test.h.pth
- $ cat test.c
- #include "test.h"
- $ clang -cc1 test.c -o test -token-cache test.h.pth
-</pre>
-
-<p>In this example the contents of <tt>stdio.h</tt> (and the files it includes)
-will be retrieved from <tt>test.h.pth</tt>, as the PTH file is being used in
-this case as a raw cache of the contents of <tt>test.h</tt>. This is a low-level
-interface used to both implement the high-level PTH interface as well as to
-provide alternative means to use PTH-style caching.</p>
-
-<h2>PTH Design and Implementation</h2>
-
-<p>Unlike GCC's precompiled headers, which cache the full ASTs and preprocessor
-state of a header file, Clang's pretokenized header files mainly cache the raw
-lexer <em>tokens</em> that are needed to segment the stream of characters in a
-source file into keywords, identifiers, and operators. Consequently, PTH serves
-to mainly directly speed up the lexing and preprocessing of a source file, while
-parsing and type-checking must be completely redone every time a PTH file is
-used.</p>
-
-<h3>Basic Design Tradeoffs</h3>
-
-<p>In the long term there are plans to provide an alternate PCH implementation
-for Clang that also caches the work for parsing and type checking the contents
-of header files. The current implementation of PCH in Clang as pretokenized
-header files was motivated by the following factors:<p>
-
-<ul>
-
-<li><p><b>Language independence</b>: PTH files work with any language that
-Clang's lexer can handle, including C, Objective-C, and (in the early stages)
-C++. This means development on language features at the parsing level or above
-(which is basically almost all interesting pieces) does not require PTH to be
-modified.</p></li>
-
-<li><b>Simple design</b>: Relatively speaking, PTH has a simple design and
-implementation, making it easy to test. Further, because the machinery for PTH
-resides at the lower-levels of the Clang library stack it is fairly
-straightforward to profile and optimize.</li>
-</ul>
-
-<p>Further, compared to GCC's PCH implementation (which is the dominate
-precompiled header file implementation that Clang can be directly compared
-against) the PTH design in Clang yields several attractive features:</p>
-
-<ul>
-
-<li><p><b>Architecture independence</b>: In contrast to GCC's PCH files (and
-those of several other compilers), Clang's PTH files are architecture
-independent, requiring only a single PTH file when building an program for
-multiple architectures.</p>
-
-<p>For example, on Mac OS X one may wish to
-compile a &quot;universal binary&quot; that runs on PowerPC, 32-bit Intel
-(i386), and 64-bit Intel architectures. In contrast, GCC requires a PCH file for
-each architecture, as the definitions of types in the AST are
-architecture-specific. Since a Clang PTH file essentially represents a lexical
-cache of header files, a single PTH file can be safely used when compiling for
-multiple architectures. This can also reduce compile times because only a single
-PTH file needs to be generated during a build instead of several.</p></li>
-
-<li><p><b>Reduced memory pressure</b>: Similar to GCC,
-Clang reads PTH files via the use of memory mapping (i.e., <tt>mmap</tt>).
-Clang, however, memory maps PTH files as read-only, meaning that multiple
-invocations of <tt>clang -cc1</tt> can share the same pages in memory from a
-memory-mapped PTH file. In comparison, GCC also memory maps its PCH files but
-also modifies those pages in memory, incurring the copy-on-write costs. The
-read-only nature of PTH can greatly reduce memory pressure for builds involving
-multiple cores, thus improving overall scalability.</p></li>
-
-<li><p><b>Fast generation</b>: PTH files can be generated in a small fraction
-of the time needed to generate GCC's PCH files. Since PTH/PCH generation is a
-serial operation that typically blocks progress during a build, faster
-generation time leads to improved processor utilization with parallel builds on
-multicore machines.</p></li>
-
-</ul>
-
-<p>Despite these strengths, PTH's simple design suffers some algorithmic
-handicaps compared to other PCH strategies such as those used by GCC. While PTH
-can greatly speed up the processing time of a header file, the amount of work
-required to process a header file is still roughly linear in the size of the
-header file. In contrast, the amount of work done by GCC to process a
-precompiled header is (theoretically) constant (the ASTs for the header are
-literally memory mapped into the compiler). This means that only the pieces of
-the header file that are referenced by the source file including the header are
-the only ones the compiler needs to process during actual compilation. While
-GCC's particular implementation of PCH mitigates some of these algorithmic
-strengths via the use of copy-on-write pages, the approach itself can
-fundamentally dominate at an algorithmic level, especially when one considers
-header files of arbitrary size.</p>
-
-<p>There are plans to potentially implement an complementary PCH implementation
-for Clang based on the lazy deserialization of ASTs. This approach would
-theoretically have the same constant-time algorithmic advantages just mentioned
-but would also retain some of the strengths of PTH such as reduced memory
-pressure (ideal for multi-core builds).</p>
-
-<h3>Internal PTH Optimizations</h3>
-
-<p>While the main optimization employed by PTH is to reduce lexing time of
-header files by caching pre-lexed tokens, PTH also employs several other
-optimizations to speed up the processing of header files:</p>
-
-<ul>
-
-<li><p><em><tt>stat</tt> caching</em>: PTH files cache information obtained via
-calls to <tt>stat</tt> that <tt>clang -cc1</tt> uses to resolve which files are
-included by <tt>#include</tt> directives. This greatly reduces the overhead
-involved in context-switching to the kernel to resolve included files.</p></li>
-
-<li><p><em>Fasting skipping of <tt>#ifdef</tt>...<tt>#endif</tt> chains</em>:
-PTH files record the basic structure of nested preprocessor blocks. When the
-condition of the preprocessor block is false, all of its tokens are immediately
-skipped instead of requiring them to be handled by Clang's
-preprocessor.</p></li>
-
-</ul>
-
-</div>
-</body>
-</html>
diff --git a/docs/PTHInternals.rst b/docs/PTHInternals.rst
new file mode 100644
index 0000000..10dda61
--- /dev/null
+++ b/docs/PTHInternals.rst
@@ -0,0 +1,163 @@
+==========================
+Pretokenized Headers (PTH)
+==========================
+
+This document first describes the low-level interface for using PTH and
+then briefly elaborates on its design and implementation. If you are
+interested in the end-user view, please see the :ref:`User's Manual
+<usersmanual-precompiled-headers>`.
+
+Using Pretokenized Headers with ``clang`` (Low-level Interface)
+===============================================================
+
+The Clang compiler frontend, ``clang -cc1``, supports three command line
+options for generating and using PTH files.
+
+To generate PTH files using ``clang -cc1``, use the option ``-emit-pth``:
+
+.. code-block:: console
+
+ $ clang -cc1 test.h -emit-pth -o test.h.pth
+
+This option is transparently used by ``clang`` when generating PTH
+files. Similarly, PTH files can be used as prefix headers using the
+``-include-pth`` option:
+
+.. code-block:: console
+
+ $ clang -cc1 -include-pth test.h.pth test.c -o test.s
+
+Alternatively, Clang's PTH files can be used as a raw "token-cache" (or
+"content" cache) of the source included by the original header file.
+This means that the contents of the PTH file are searched as substitutes
+for *any* source files that are used by ``clang -cc1`` to process a
+source file. This is done by specifying the ``-token-cache`` option:
+
+.. code-block:: console
+
+ $ cat test.h
+ #include <stdio.h>
+ $ clang -cc1 -emit-pth test.h -o test.h.pth
+ $ cat test.c
+ #include "test.h"
+ $ clang -cc1 test.c -o test -token-cache test.h.pth
+
+In this example the contents of ``stdio.h`` (and the files it includes)
+will be retrieved from ``test.h.pth``, as the PTH file is being used in
+this case as a raw cache of the contents of ``test.h``. This is a
+low-level interface used to both implement the high-level PTH interface
+as well as to provide alternative means to use PTH-style caching.
+
+PTH Design and Implementation
+=============================
+
+Unlike GCC's precompiled headers, which cache the full ASTs and
+preprocessor state of a header file, Clang's pretokenized header files
+mainly cache the raw lexer *tokens* that are needed to segment the
+stream of characters in a source file into keywords, identifiers, and
+operators. Consequently, PTH serves to mainly directly speed up the
+lexing and preprocessing of a source file, while parsing and
+type-checking must be completely redone every time a PTH file is used.
+
+Basic Design Tradeoffs
+----------------------
+
+In the long term there are plans to provide an alternate PCH
+implementation for Clang that also caches the work for parsing and type
+checking the contents of header files. The current implementation of PCH
+in Clang as pretokenized header files was motivated by the following
+factors:
+
+**Language independence**
+ PTH files work with any language that
+ Clang's lexer can handle, including C, Objective-C, and (in the early
+ stages) C++. This means development on language features at the
+ parsing level or above (which is basically almost all interesting
+ pieces) does not require PTH to be modified.
+
+**Simple design**
+ Relatively speaking, PTH has a simple design and
+ implementation, making it easy to test. Further, because the
+ machinery for PTH resides at the lower-levels of the Clang library
+ stack it is fairly straightforward to profile and optimize.
+
+Further, compared to GCC's PCH implementation (which is the dominate
+precompiled header file implementation that Clang can be directly
+compared against) the PTH design in Clang yields several attractive
+features:
+
+**Architecture independence**
+ In contrast to GCC's PCH files (and
+ those of several other compilers), Clang's PTH files are architecture
+ independent, requiring only a single PTH file when building a
+ program for multiple architectures.
+
+ For example, on Mac OS X one may wish to compile a "universal binary"
+ that runs on PowerPC, 32-bit Intel (i386), and 64-bit Intel
+ architectures. In contrast, GCC requires a PCH file for each
+ architecture, as the definitions of types in the AST are
+ architecture-specific. Since a Clang PTH file essentially represents
+ a lexical cache of header files, a single PTH file can be safely used
+ when compiling for multiple architectures. This can also reduce
+ compile times because only a single PTH file needs to be generated
+ during a build instead of several.
+
+**Reduced memory pressure**
+ Similar to GCC, Clang reads PTH files
+ via the use of memory mapping (i.e., ``mmap``). Clang, however,
+ memory maps PTH files as read-only, meaning that multiple invocations
+ of ``clang -cc1`` can share the same pages in memory from a
+ memory-mapped PTH file. In comparison, GCC also memory maps its PCH
+ files but also modifies those pages in memory, incurring the
+ copy-on-write costs. The read-only nature of PTH can greatly reduce
+ memory pressure for builds involving multiple cores, thus improving
+ overall scalability.
+
+**Fast generation**
+ PTH files can be generated in a small fraction
+ of the time needed to generate GCC's PCH files. Since PTH/PCH
+ generation is a serial operation that typically blocks progress
+ during a build, faster generation time leads to improved processor
+ utilization with parallel builds on multicore machines.
+
+Despite these strengths, PTH's simple design suffers some algorithmic
+handicaps compared to other PCH strategies such as those used by GCC.
+While PTH can greatly speed up the processing time of a header file, the
+amount of work required to process a header file is still roughly linear
+in the size of the header file. In contrast, the amount of work done by
+GCC to process a precompiled header is (theoretically) constant (the
+ASTs for the header are literally memory mapped into the compiler). This
+means that only the pieces of the header file that are referenced by the
+source file including the header are the only ones the compiler needs to
+process during actual compilation. While GCC's particular implementation
+of PCH mitigates some of these algorithmic strengths via the use of
+copy-on-write pages, the approach itself can fundamentally dominate at
+an algorithmic level, especially when one considers header files of
+arbitrary size.
+
+There are plans to potentially implement an complementary PCH
+implementation for Clang based on the lazy deserialization of ASTs. This
+approach would theoretically have the same constant-time algorithmic
+advantages just mentioned but would also retain some of the strengths of
+PTH such as reduced memory pressure (ideal for multi-core builds).
+
+Internal PTH Optimizations
+--------------------------
+
+While the main optimization employed by PTH is to reduce lexing time of
+header files by caching pre-lexed tokens, PTH also employs several other
+optimizations to speed up the processing of header files:
+
+- ``stat`` caching: PTH files cache information obtained via calls to
+ ``stat`` that ``clang -cc1`` uses to resolve which files are included
+ by ``#include`` directives. This greatly reduces the overhead
+ involved in context-switching to the kernel to resolve included
+ files.
+
+- Fast skipping of ``#ifdef`` ... ``#endif`` chains: PTH files
+ record the basic structure of nested preprocessor blocks. When the
+ condition of the preprocessor block is false, all of its tokens are
+ immediately skipped instead of requiring them to be handled by
+ Clang's preprocessor.
+
+
diff --git a/docs/RAVFrontendAction.html b/docs/RAVFrontendAction.html
deleted file mode 100644
index b30cd57..0000000
--- a/docs/RAVFrontendAction.html
+++ /dev/null
@@ -1,224 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
-<title>How to write RecursiveASTVisitor based ASTFrontendActions.</title>
-<link type="text/css" rel="stylesheet" href="../menu.css">
-<link type="text/css" rel="stylesheet" href="../content.css">
-</head>
-<body>
-
-<!--#include virtual="../menu.html.incl"-->
-
-<div id="content">
-
-<h1>How to write RecursiveASTVisitor based ASTFrontendActions.</h1>
-
-<!-- ======================================================================= -->
-<h2 id="intro">Introduction</h2>
-<!-- ======================================================================= -->
-
-In this tutorial you will learn how to create a FrontendAction that uses
-a RecursiveASTVisitor to find CXXRecordDecl AST nodes with a specified name.
-
-<!-- ======================================================================= -->
-<h2 id="action">Creating a FrontendAction</h2>
-<!-- ======================================================================= -->
-
-<p>When writing a clang based tool like a Clang Plugin or a standalone tool
-based on LibTooling, the common entry point is the FrontendAction.
-FrontendAction is an interface that allows execution of user specific actions
-as part of the compilation. To run tools over the AST clang provides the
-convenience interface ASTFrontendAction, which takes care of executing the
-action. The only part left is to implement the CreateASTConsumer method that
-returns an ASTConsumer per translation unit.</p>
-<pre>
- class FindNamedClassAction : public clang::ASTFrontendAction {
- public:
- virtual clang::ASTConsumer *CreateASTConsumer(
- clang::CompilerInstance &amp;Compiler, llvm::StringRef InFile) {
- return new FindNamedClassConsumer;
- }
- };
-</pre>
-
-<!-- ======================================================================= -->
-<h2 id="consumer">Creating an ASTConsumer</h2>
-<!-- ======================================================================= -->
-
-<p>ASTConsumer is an interface used to write generic actions on an AST,
-regardless of how the AST was produced. ASTConsumer provides many different
-entry points, but for our use case the only one needed is HandleTranslationUnit,
-which is called with the ASTContext for the translation unit.</p>
-<pre>
- class FindNamedClassConsumer : public clang::ASTConsumer {
- public:
- virtual void HandleTranslationUnit(clang::ASTContext &amp;Context) {
- // Traversing the translation unit decl via a RecursiveASTVisitor
- // will visit all nodes in the AST.
- Visitor.TraverseDecl(Context.getTranslationUnitDecl());
- }
- private:
- // A RecursiveASTVisitor implementation.
- FindNamedClassVisitor Visitor;
- };
-</pre>
-
-<!-- ======================================================================= -->
-<h2 id="rav">Using the RecursiveASTVisitor</h2>
-<!-- ======================================================================= -->
-
-<p>Now that everything is hooked up, the next step is to implement a
-RecursiveASTVisitor to extract the relevant information from the AST.</p>
-<p>The RecursiveASTVisitor provides hooks of the form
-bool VisitNodeType(NodeType *) for most AST nodes; the exception are TypeLoc
-nodes, which are passed by-value. We only need to implement the methods for the
-relevant node types.
-</p>
-<p>Let's start by writing a RecursiveASTVisitor that visits all CXXRecordDecl's.
-<pre>
- class FindNamedClassVisitor
- : public RecursiveASTVisitor&lt;FindNamedClassVisitor> {
- public:
- bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {
- // For debugging, dumping the AST nodes will show which nodes are already
- // being visited.
- Declaration->dump();
-
- // The return value indicates whether we want the visitation to proceed.
- // Return false to stop the traversal of the AST.
- return true;
- }
- };
-</pre>
-</p>
-<p>In the methods of our RecursiveASTVisitor we can now use the full power of
-the Clang AST to drill through to the parts that are interesting for us. For
-example, to find all class declaration with a certain name, we can check for a
-specific qualified name:
-<pre>
- bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {
- if (Declaration->getQualifiedNameAsString() == "n::m::C")
- Declaration->dump();
- return true;
- }
-</pre>
-</p>
-
-<!-- ======================================================================= -->
-<h2 id="context">Accessing the SourceManager and ASTContext</h2>
-<!-- ======================================================================= -->
-
-<p>Some of the information about the AST, like source locations and global
-identifier information, are not stored in the AST nodes themselves, but in
-the ASTContext and its associated source manager. To retrieve them we need to
-hand the ASTContext into our RecursiveASTVisitor implementation.</p>
-<p>The ASTContext is available from the CompilerInstance during the call
-to CreateASTConsumer. We can thus extract it there and hand it into our
-freshly created FindNamedClassConsumer:</p>
-<pre>
- virtual clang::ASTConsumer *CreateASTConsumer(
- clang::CompilerInstance &amp;Compiler, llvm::StringRef InFile) {
- return new FindNamedClassConsumer(<b>&amp;Compiler.getASTContext()</b>);
- }
-</pre>
-
-<p>Now that the ASTContext is available in the RecursiveASTVisitor, we can do
-more interesting things with AST nodes, like looking up their source
-locations:</p>
-<pre>
- bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {
- if (Declaration->getQualifiedNameAsString() == "n::m::C") {
- // getFullLoc uses the ASTContext's SourceManager to resolve the source
- // location and break it up into its line and column parts.
- FullSourceLoc FullLocation = Context->getFullLoc(Declaration->getLocStart());
- if (FullLocation.isValid())
- llvm::outs() &lt;&lt; "Found declaration at "
- &lt;&lt; FullLocation.getSpellingLineNumber() &lt;&lt; ":"
- &lt;&lt; FullLocation.getSpellingColumnNumber() &lt;&lt; "\n";
- }
- return true;
- }
-</pre>
-
-<!-- ======================================================================= -->
-<h2 id="full">Putting it all together</h2>
-<!-- ======================================================================= -->
-
-<p>Now we can combine all of the above into a small example program:</p>
-<pre>
- #include "clang/AST/ASTConsumer.h"
- #include "clang/AST/RecursiveASTVisitor.h"
- #include "clang/Frontend/CompilerInstance.h"
- #include "clang/Frontend/FrontendAction.h"
- #include "clang/Tooling/Tooling.h"
-
- using namespace clang;
-
- class FindNamedClassVisitor
- : public RecursiveASTVisitor&lt;FindNamedClassVisitor> {
- public:
- explicit FindNamedClassVisitor(ASTContext *Context)
- : Context(Context) {}
-
- bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {
- if (Declaration->getQualifiedNameAsString() == "n::m::C") {
- FullSourceLoc FullLocation = Context->getFullLoc(Declaration->getLocStart());
- if (FullLocation.isValid())
- llvm::outs() &lt;&lt; "Found declaration at "
- &lt;&lt; FullLocation.getSpellingLineNumber() &lt;&lt; ":"
- &lt;&lt; FullLocation.getSpellingColumnNumber() &lt;&lt; "\n";
- }
- return true;
- }
-
- private:
- ASTContext *Context;
- };
-
- class FindNamedClassConsumer : public clang::ASTConsumer {
- public:
- explicit FindNamedClassConsumer(ASTContext *Context)
- : Visitor(Context) {}
-
- virtual void HandleTranslationUnit(clang::ASTContext &amp;Context) {
- Visitor.TraverseDecl(Context.getTranslationUnitDecl());
- }
- private:
- FindNamedClassVisitor Visitor;
- };
-
- class FindNamedClassAction : public clang::ASTFrontendAction {
- public:
- virtual clang::ASTConsumer *CreateASTConsumer(
- clang::CompilerInstance &amp;Compiler, llvm::StringRef InFile) {
- return new FindNamedClassConsumer(&amp;Compiler.getASTContext());
- }
- };
-
- int main(int argc, char **argv) {
- if (argc > 1) {
- clang::tooling::runToolOnCode(new FindNamedClassAction, argv[1]);
- }
- }
-</pre>
-
-<p>We store this into a file called FindClassDecls.cpp and create the following
-CMakeLists.txt to link it:</p>
-<pre>
-set(LLVM_USED_LIBS clangTooling)
-
-add_clang_executable(find-class-decls FindClassDecls.cpp)
-</pre>
-
-<p>When running this tool over a small code snippet it will output all
-declarations of a class n::m::C it found:</p>
-<pre>
- $ ./bin/find-class-decls "namespace n { namespace m { class C {}; } }"
- Found declaration at 1:29
-</pre>
-
-</div>
-</body>
-</html>
-
diff --git a/docs/RAVFrontendAction.rst b/docs/RAVFrontendAction.rst
new file mode 100644
index 0000000..2f60ce9
--- /dev/null
+++ b/docs/RAVFrontendAction.rst
@@ -0,0 +1,216 @@
+==========================================================
+How to write RecursiveASTVisitor based ASTFrontendActions.
+==========================================================
+
+Introduction
+============
+
+In this tutorial you will learn how to create a FrontendAction that uses
+a RecursiveASTVisitor to find CXXRecordDecl AST nodes with a specified
+name.
+
+Creating a FrontendAction
+=========================
+
+When writing a clang based tool like a Clang Plugin or a standalone tool
+based on LibTooling, the common entry point is the FrontendAction.
+FrontendAction is an interface that allows execution of user specific
+actions as part of the compilation. To run tools over the AST clang
+provides the convenience interface ASTFrontendAction, which takes care
+of executing the action. The only part left is to implement the
+CreateASTConsumer method that returns an ASTConsumer per translation
+unit.
+
+::
+
+ class FindNamedClassAction : public clang::ASTFrontendAction {
+ public:
+ virtual clang::ASTConsumer *CreateASTConsumer(
+ clang::CompilerInstance &Compiler, llvm::StringRef InFile) {
+ return new FindNamedClassConsumer;
+ }
+ };
+
+Creating an ASTConsumer
+=======================
+
+ASTConsumer is an interface used to write generic actions on an AST,
+regardless of how the AST was produced. ASTConsumer provides many
+different entry points, but for our use case the only one needed is
+HandleTranslationUnit, which is called with the ASTContext for the
+translation unit.
+
+::
+
+ class FindNamedClassConsumer : public clang::ASTConsumer {
+ public:
+ virtual void HandleTranslationUnit(clang::ASTContext &Context) {
+ // Traversing the translation unit decl via a RecursiveASTVisitor
+ // will visit all nodes in the AST.
+ Visitor.TraverseDecl(Context.getTranslationUnitDecl());
+ }
+ private:
+ // A RecursiveASTVisitor implementation.
+ FindNamedClassVisitor Visitor;
+ };
+
+Using the RecursiveASTVisitor
+=============================
+
+Now that everything is hooked up, the next step is to implement a
+RecursiveASTVisitor to extract the relevant information from the AST.
+
+The RecursiveASTVisitor provides hooks of the form bool
+VisitNodeType(NodeType \*) for most AST nodes; the exception are TypeLoc
+nodes, which are passed by-value. We only need to implement the methods
+for the relevant node types.
+
+Let's start by writing a RecursiveASTVisitor that visits all
+CXXRecordDecl's.
+
+::
+
+ class FindNamedClassVisitor
+ : public RecursiveASTVisitor<FindNamedClassVisitor> {
+ public:
+ bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {
+ // For debugging, dumping the AST nodes will show which nodes are already
+ // being visited.
+ Declaration->dump();
+
+ // The return value indicates whether we want the visitation to proceed.
+ // Return false to stop the traversal of the AST.
+ return true;
+ }
+ };
+
+In the methods of our RecursiveASTVisitor we can now use the full power
+of the Clang AST to drill through to the parts that are interesting for
+us. For example, to find all class declaration with a certain name, we
+can check for a specific qualified name:
+
+::
+
+ bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {
+ if (Declaration->getQualifiedNameAsString() == "n::m::C")
+ Declaration->dump();
+ return true;
+ }
+
+Accessing the SourceManager and ASTContext
+==========================================
+
+Some of the information about the AST, like source locations and global
+identifier information, are not stored in the AST nodes themselves, but
+in the ASTContext and its associated source manager. To retrieve them we
+need to hand the ASTContext into our RecursiveASTVisitor implementation.
+
+The ASTContext is available from the CompilerInstance during the call to
+CreateASTConsumer. We can thus extract it there and hand it into our
+freshly created FindNamedClassConsumer:
+
+::
+
+ virtual clang::ASTConsumer *CreateASTConsumer(
+ clang::CompilerInstance &Compiler, llvm::StringRef InFile) {
+ return new FindNamedClassConsumer(&Compiler.getASTContext());
+ }
+
+Now that the ASTContext is available in the RecursiveASTVisitor, we can
+do more interesting things with AST nodes, like looking up their source
+locations:
+
+::
+
+ bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {
+ if (Declaration->getQualifiedNameAsString() == "n::m::C") {
+ // getFullLoc uses the ASTContext's SourceManager to resolve the source
+ // location and break it up into its line and column parts.
+ FullSourceLoc FullLocation = Context->getFullLoc(Declaration->getLocStart());
+ if (FullLocation.isValid())
+ llvm::outs() << "Found declaration at "
+ << FullLocation.getSpellingLineNumber() << ":"
+ << FullLocation.getSpellingColumnNumber() << "\n";
+ }
+ return true;
+ }
+
+Putting it all together
+=======================
+
+Now we can combine all of the above into a small example program:
+
+::
+
+ #include "clang/AST/ASTConsumer.h"
+ #include "clang/AST/RecursiveASTVisitor.h"
+ #include "clang/Frontend/CompilerInstance.h"
+ #include "clang/Frontend/FrontendAction.h"
+ #include "clang/Tooling/Tooling.h"
+
+ using namespace clang;
+
+ class FindNamedClassVisitor
+ : public RecursiveASTVisitor<FindNamedClassVisitor> {
+ public:
+ explicit FindNamedClassVisitor(ASTContext *Context)
+ : Context(Context) {}
+
+ bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {
+ if (Declaration->getQualifiedNameAsString() == "n::m::C") {
+ FullSourceLoc FullLocation = Context->getFullLoc(Declaration->getLocStart());
+ if (FullLocation.isValid())
+ llvm::outs() << "Found declaration at "
+ << FullLocation.getSpellingLineNumber() << ":"
+ << FullLocation.getSpellingColumnNumber() << "\n";
+ }
+ return true;
+ }
+
+ private:
+ ASTContext *Context;
+ };
+
+ class FindNamedClassConsumer : public clang::ASTConsumer {
+ public:
+ explicit FindNamedClassConsumer(ASTContext *Context)
+ : Visitor(Context) {}
+
+ virtual void HandleTranslationUnit(clang::ASTContext &Context) {
+ Visitor.TraverseDecl(Context.getTranslationUnitDecl());
+ }
+ private:
+ FindNamedClassVisitor Visitor;
+ };
+
+ class FindNamedClassAction : public clang::ASTFrontendAction {
+ public:
+ virtual clang::ASTConsumer *CreateASTConsumer(
+ clang::CompilerInstance &Compiler, llvm::StringRef InFile) {
+ return new FindNamedClassConsumer(&Compiler.getASTContext());
+ }
+ };
+
+ int main(int argc, char **argv) {
+ if (argc > 1) {
+ clang::tooling::runToolOnCode(new FindNamedClassAction, argv[1]);
+ }
+ }
+
+We store this into a file called FindClassDecls.cpp and create the
+following CMakeLists.txt to link it:
+
+::
+
+ set(LLVM_USED_LIBS clangTooling)
+
+ add_clang_executable(find-class-decls FindClassDecls.cpp)
+
+When running this tool over a small code snippet it will output all
+declarations of a class n::m::C it found:
+
+::
+
+ $ ./bin/find-class-decls "namespace n { namespace m { class C {}; } }"
+ Found declaration at 1:29
+
diff --git a/docs/README.txt b/docs/README.txt
new file mode 100644
index 0000000..c4e565f
--- /dev/null
+++ b/docs/README.txt
@@ -0,0 +1 @@
+See llvm/docs/README.txt
diff --git a/docs/ReleaseNotes.html b/docs/ReleaseNotes.html
deleted file mode 100644
index a1ba15c..0000000
--- a/docs/ReleaseNotes.html
+++ /dev/null
@@ -1,325 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
-<title>Clang 3.2 Release Notes</title>
-<link type="text/css" rel="stylesheet" href="../menu.css">
-<link type="text/css" rel="stylesheet" href="../content.css">
-<style type="text/css">
-td {
- vertical-align: top;
-}
-</style>
-</head>
-<body>
-
-<!--#include virtual="../menu.html.incl"-->
-
-<div id="content">
-
-<h1>Clang 3.2 Release Notes</h1>
-
-<img style="float:right" src="http://llvm.org/img/DragonSmall.png"
- width="136" height="136" alt="LLVM Dragon Logo">
-
-<ul>
- <li><a href="#intro">Introduction</a></li>
- <li><a href="#whatsnew">What's New in Clang 3.2?</a>
- <ul>
- <li><a href="#majorfeatures">Major New Features</a></li>
- <li><a href="#newflags">New Compiler Flags</a></li>
- <li><a href="#cchanges">C Language Changes</a></li>
- <li><a href="#cxxchanges">C++ Language Changes</a></li>
- <li><a href="#objcchanges">Objective-C Language Changes</a></li>
- <li><a href="#apichanges">Internal API Changes</a></li>
- <li><a href="#pythonchanges">Python Binding Changes</a></li>
- </ul>
- </li>
- <li><a href="#knownproblems">Known Problems</a></li>
- <li><a href="#additionalinfo">Additional Information</a></li>
-</ul>
-
-<div class="doc_author">
- <p>Written by the <a href="http://llvm.org/">LLVM Team</a></p>
-</div>
-
-<!-- ======================================================================= -->
-<h2 id="intro">Introduction</h2>
-<!-- ======================================================================= -->
-
-<p>This document contains the release notes for the Clang C/C++/Objective-C
- frontend, part of the LLVM Compiler Infrastructure, release 3.2. Here we
- describe the status of Clang in some detail, including major improvements
- from the previous release and new feature work. For the general LLVM release
- notes, see <a href="http://llvm.org/docs/ReleaseNotes.html">the LLVM
- documentation</a>. All LLVM releases may be downloaded from the
- <a href="http://llvm.org/releases/">LLVM releases web site</a>.</p>
-
-<p>For more information about Clang or LLVM, including information about the
- latest release, please check out the main please see the
- <a href="http://clang.llvm.org">Clang Web Site</a> or the
- <a href="http://llvm.org">LLVM Web Site</a>.
-
-<p>Note that if you are reading this file from a Subversion checkout or the main
- Clang web page, this document applies to the <i>next</i> release, not the
- current one. To see the release notes for a specific release, please see the
- <a href="http://llvm.org/releases/">releases page</a>.</p>
-
-<!-- ======================================================================= -->
-<h2 id="whatsnew">What's New in Clang 3.2?</h2>
-<!-- ======================================================================= -->
-
-<p>Some of the major new features and improvements to Clang are listed here.
- Generic improvements to Clang as a whole or to its underlying infrastructure
- are described first, followed by language-specific sections with improvements
- to Clang's support for those languages.</p>
-
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-<h3 id="majorfeatures">Major New Features</h3>
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-
-<h4 id="diagnostics">Improvements to Clang's diagnostics</h4>
-
-<p>Clang's diagnostics are constantly being improved to catch more issues,
-explain them more clearly, and provide more accurate source information about
-them. The improvements since the 3.1 release include:</p>
-
-<ul>
- <li><tt>-Wuninitialized</tt> has been taught to recognize uninitialized uses
- which always occur when an explicitly-written non-constant condition is either
- <tt>true</tt> or <tt>false</tt>. For example:
-
-<pre>
-int f(bool b) {
- int n;
- if (b)
- n = 1;
- return n;
-}
-
-<b>sometimes-uninit.cpp:3:7: <span class="warning">warning:</span> variable 'n' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized]</b>
- if (b)
- <span class="caret">^</span>
-<b>sometimes-uninit.cpp:5:10: <span class="note">note:</span></b> uninitialized use occurs here
- return n;
- <span class="caret">^</span>
-<b>sometimes-uninit.cpp:3:3: <span class="note">note:</span></b> remove the 'if' if its condition is always true
- if (b)
- <span class="caret">^~~~~~</span>
-<b>sometimes-uninit.cpp:2:8: <span class="note">note:</span></b> initialize the variable 'n' to silence this warning
- int n;
- <span class="caret">^</span>
- <span class="caret"> = 0</span>
-</pre>
-
- This functionality can be enabled or disabled separately from
- <tt>-Wuninitialized</tt> with the <tt>-Wsometimes-uninitialized</tt> warning
- flag.</li>
-
- <li>Template type diffing improves the display of diagnostics with templated
- types in them.
-
-<pre>
-int f(vector&lt;map&lt;int, double&gt;&gt;);
-int x = f(vector&lt;map&lt;int, float&gt;&gt;());
-</pre>
- The error message is the same, but the note is different based on the options selected.
-<pre>
-<b>template-diff.cpp:5:9: <span class="error">error:</span> no matching function for call to 'f'</b>
-int x = f(vector&lt;map&lt;int, float&gt;&gt;());
- <span class="caret">^</span>
-</pre>
- Templated type diffing with type elision (default):
-<pre>
-<b>template-diff.cpp:4:5: <span class="note">note:</span></b> candidate function not viable: no known conversion from 'vector&lt;map&lt;[...], <span class="template-highlight">float</span>&gt;&gt;' to 'vector&lt;map&lt;[...], <span class="template-highlight">double</span>&gt;&gt;' for 1st argument;
-int f(vector&lt;map&lt;int, double&gt;&gt;);
- <span class="caret">^</span>
-</pre>
- Templated type diffing without type elision (-fno-elide-type):
-<pre>
-<b>template-diff.cpp:4:5: <span class="note">note:</span></b> candidate function not viable: no known conversion from 'vector&lt;map&lt;int, <span class="template-highlight">float</span>&gt;&gt;' to 'vector&lt;map&lt;int, <span class="template-highlight">double</span>&gt;&gt;' for 1st argument;
-int f(vector&lt;map&lt;int, double&gt;&gt;);
- <span class="caret">^</span>
-</pre>
- Templated tree printing with type elision (-fdiagnostics-show-template-tree):
-<pre>
-<b>template-diff.cpp:4:5: <span class="note">note:</span></b> candidate function not viable: no known conversion for 1st argument;
- vector&lt;
- map&lt;
- [...],
- [<span class="template-highlight">float</span> != <span class="template-highlight">double</span>]&gt;&gt;
-int f(vector&lt;map&lt;int, double&gt;&gt;);
- <span class="caret">^</span>
-</pre>
- Templated tree printing without type elision (-fdiagnostics-show-template-tree -fno-elide-type):
-<pre>
-<b>template-diff.cpp:4:5: <span class="note">note:</span></b> candidate function not viable: no known conversion for 1st argument;
- vector&lt;
- map&lt;
- int,
- [<span class="template-highlight">float</span> != <span class="template-highlight">double</span>]&gt;&gt;
-int f(vector&lt;map&lt;int, double&gt;&gt;);
- <span class="caret">^</span>
-</pre>
-
- </li>
-
- <li>The Address Sanitizer feature and Clang's <tt>-fcatch-undefined-behavior</tt> option have been moved to a unified flag set:
- <tt>-fsanitize</tt>. This flag can be used to enable the different dynamic checking tools when building. For example,
- <tt>-faddress-sanitizer</tt> is now <tt>-fsanitize=address</tt>, and <tt>-fcatch-undefined-behavior</tt> is now
- <tt>-fsanitize=undefined</tt>. With this release the set of checks available continues to grow, see the Clang
- documentation and specific sanitizer notes below for details.
- </li>
-
-</ul>
-
-<h4 id="tlsmodel">Support for <code>tls_model</code> attribute</h4>
-
-<p>Clang now supports the <code>tls_model</code> attribute, allowing code that
-uses thread-local storage to explicitly select which model to use. The available
-models are <code>"global-dynamic"</code>, <code>"local-dynamic"</code>,
-<code>"initial-exec"</code> and <code>"local-exec"</code>. See
-<a href="http://www.akkadia.org/drepper/tls.pdf">ELF Handling For Thread-Local
- Storage</a> for more information.</p>
-
-<p>The compiler is free to choose a different model if the specified model is not
-supported by the target, or if the compiler determines that a more specific
-model can be used.
-</p>
-
-<h4>Type safety attributes</h4>
-<p>Clang now supports type safety attributes that allow checking during compile
-time that 'void *' function arguments and arguments for variadic functions are
-of a particular type which is determined by some other argument to the same
-function call.</p>
-
-<p>Usecases include:</p>
-<ul>
-<li>MPI library implementations, where these attributes enable checking that
- buffer type matches the passed <code>MPI_Datatype</code>;</li>
-<li> HDF5 library -- similar usecase as for MPI;</li>
-<li> checking types of variadic functions' arguments for functions like
-<code>fcntl()</code> and <code>ioctl()</code>.</li>
-</ul>
-
-<p>See entries for <code>argument_with_type_tag</code>,
-<code>pointer_with_type_tag</code> and <code>type_tag_for_datatype</code>
-attributes in Clang language extensions documentation.</p>
-
-<h4>Documentation comment support</h4>
-<p>Clang now supports documentation comments written in a Doxygen-like syntax.
-Clang parses the comments and can detect syntactic and semantic errors in
-comments. These warnings are off by default. Pass <tt>-Wdocumentation</tt>
-flag to enable warnings about documentation comments.</p>
-
-<p>For example, given:</p>
-
-<pre>/// \param [in] Str the string.
-/// \returns a modified string.
-void do_something(const std::string &amp;str);</pre>
-
-<p><tt>clang -Wdocumentation</tt> will emit two warnings:</p>
-
-<pre><b>doc-test.cc:3:6: <span class="warning">warning:</span></b> '\returns' command used in a comment that is attached to a function returning void [-Wdocumentation]
-/// \returns a modified string.
- <span class="caret">~^~~~~~~~~~~~~~~~~~~~~~~~~~</span>
-<b>doc-test.cc:2:17: <span class="warning">warning:</span></b> parameter 'Str' not found in the function declaration [-Wdocumentation]
-/// \param [in] Str the string.
- <span class="caret">^~~</span>
-<b>doc-test.cc:2:17: <span class="note">note:</span></b> did you mean 'str'?
-/// \param [in] Str the string.
- <span class="caret">^~~</span>
- <span class="caret">str</span></pre>
-
-<p>libclang includes a new API, <tt>clang_FullComment_getAsXML</tt>, to convert
-comments to XML documents. This API can be used to build documentation
-extraction tools.</p>
-
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-<h3 id="newflags">New Compiler Flags</h3>
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-<ul>
- <li><tt>-gline-tables-only</tt> controls the
- <a href="http://clang.llvm.org/docs/UsersManual.html#debuginfosize">size of debug information</a>.
- This flag tells Clang to emit debug info which is just enough to obtain stack traces with
- function names, file names and line numbers (by such tools as gdb or addr2line).
- Debug info for variables or function parameters is not produced, which reduces
- the size of the resulting binary.
-
- <li><tt>-ftls-model</tt> controls which TLS model to use for thread-local
- variables. This can be overridden per variable using the
- <a href="#tlsmodel"><tt>tls_model</tt> attribute</a> mentioned above.
- For more details, see the <a href="UsersManual.html#opt_ftls-model">User's
- Manual</a>.</li>
-</ul>
-
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-<h3 id="cchanges">C Language Changes in Clang</h3>
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-
-<h4 id="c11changes">C11 Feature Support</h4>
-
-<p>Clang 3.2 adds support for the C11 <code>_Alignof</code> keyword, pedantic warning through option
- <code>-Wempty-translation-unit</code> (C11 6.9p1) </p>
-
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-<h3 id="cxxchanges">C++ Language Changes in Clang</h3>
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-
-<h4 id="cxx11changes">C++11 Feature Support</h4>
-
-<p>Clang 3.2 supports <a href="http://clang.llvm.org/cxx_status.html#cxx11">most of the language features</a>
- added in the latest ISO C++ standard,<a href="http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=50372">C++ 2011</a>.
- Use <code>-std=c++11</code> or <code>-std=gnu++11</code> to enable support for these features. In addition to the features supported by Clang 3.1, the
- following features have been added:</p>
-
-<ul>
- <li>Implemented the C++11 discarded value expression rules for volatile lvalues.</li>
- <li>Support for the C++11 enum forward declarations.</li>
- <li>Handling of C++11 attribute namespaces (automatically).</li>
- <li>Implemented C++11 [conv.prom]p4: an enumeration with a fixed underlying type has integral promotions
- to both its underlying type and to its underlying type's promoted type.</li>
-</ul>
-
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-<h3 id="objcchanges">Objective-C Language Changes in Clang</h3>
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-
-<p>Bug-fixes, no functionality changes.</p>
-
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-<h3 id="pythonchanges">Python Binding Changes</h3>
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-
-The following classes and methods have been added:
-<ul>
- <li>class CompilationDatabaseError(Exception)</li>
- <li>class CompileCommand(object)</li>
- <li>class CompileCommands(object)</li>
- <li>class CompilationDatabase(ClangObject)</li>
- <li>Cursor.is_static_method</li>
- <li>Cursor.is_static_method</li>
- <li>SourceLocation.from_offset</li>
- <li>Cursor.is_static_method</li>
-</ul>
-
-<!-- ======================================================================= -->
-<h2 id="additionalinfo">Additional Information</h2>
-<!-- ======================================================================= -->
-
-<p>A wide variety of additional information is available on the
- <a href="http://clang.llvm.org/">Clang web page</a>. The web page contains
- versions of the API documentation which are up-to-date with the Subversion
- version of the source code. You can access versions of these documents
- specific to this release by going into the "<tt>clang/doc/</tt>" directory in
- the Clang tree.</p>
-
-<p>If you have any questions or comments about Clang, please feel free to
- contact us via
- the <a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev"> mailing
- list</a>.</p>
-
-
-</div>
-</body>
-</html>
diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst
new file mode 100644
index 0000000..d9a3364
--- /dev/null
+++ b/docs/ReleaseNotes.rst
@@ -0,0 +1,147 @@
+=====================================
+Clang 3.3 (In-Progress) Release Notes
+=====================================
+
+.. contents::
+ :local:
+ :depth: 2
+
+Written by the `LLVM Team <http://llvm.org/>`_
+
+.. warning::
+
+ These are in-progress notes for the upcoming Clang 3.3 release. You may
+ prefer the `Clang 3.2 Release Notes
+ <http://llvm.org/releases/3.2/docs/ClangReleaseNotes.html>`_.
+
+Introduction
+============
+
+This document contains the release notes for the Clang C/C++/Objective-C
+frontend, part of the LLVM Compiler Infrastructure, release 3.3. Here we
+describe the status of Clang in some detail, including major
+improvements from the previous release and new feature work. For the
+general LLVM release notes, see `the LLVM
+documentation <http://llvm.org/docs/ReleaseNotes.html>`_. All LLVM
+releases may be downloaded from the `LLVM releases web
+site <http://llvm.org/releases/>`_.
+
+For more information about Clang or LLVM, including information about
+the latest release, please check out the main please see the `Clang Web
+Site <http://clang.llvm.org>`_ or the `LLVM Web
+Site <http://llvm.org>`_.
+
+Note that if you are reading this file from a Subversion checkout or the
+main Clang web page, this document applies to the *next* release, not
+the current one. To see the release notes for a specific release, please
+see the `releases page <http://llvm.org/releases/>`_.
+
+What's New in Clang 3.3?
+========================
+
+Some of the major new features and improvements to Clang are listed
+here. Generic improvements to Clang as a whole or to its underlying
+infrastructure are described first, followed by language-specific
+sections with improvements to Clang's support for those languages.
+
+Major New Features
+------------------
+
+Improvements to Clang's diagnostics
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Clang's diagnostics are constantly being improved to catch more issues,
+explain them more clearly, and provide more accurate source information
+about them. The improvements since the 3.2 release include:
+
+- ...
+
+Extended Identifiers: Unicode Support and Universal Character Names
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Clang 3.3 includes support for *extended identifiers* in C99 and C++.
+This feature allows identifiers to contain certain Unicode characters, as
+specified by the active language standard; these characters can be written
+directly in the source file using the UTF-8 encoding, or referred to using
+*universal character names* (``\u00E0``, ``\U000000E0``).
+
+New Compiler Flags
+------------------
+
+- ...
+
+C Language Changes in Clang
+---------------------------
+
+C11 Feature Support
+^^^^^^^^^^^^^^^^^^^
+
+...
+
+C++ Language Changes in Clang
+-----------------------------
+
+C++11 Feature Support
+^^^^^^^^^^^^^^^^^^^^^
+
+...
+
+Objective-C Language Changes in Clang
+-------------------------------------
+
+...
+
+Internal API Changes
+--------------------
+
+These are major API changes that have happened since the 3.2 release of
+Clang. If upgrading an external codebase that uses Clang as a library,
+this section should help get you past the largest hurdles of upgrading.
+
+Value Casting
+^^^^^^^^^^^^^
+
+Certain type hierarchies (TypeLoc, CFGElement, ProgramPoint, and SVal) were
+misusing the llvm::cast machinery to perform undefined operations. Their APIs
+have been changed to use two member function templates that return values
+instead of pointers or references - "T castAs" and "Optional<T> getAs" (in the
+case of the TypeLoc hierarchy the latter is "T getAs" and you can use the
+boolean testability of a TypeLoc (or its 'validity') to verify that the cast
+succeeded). Essentially all previous 'cast' usage should be replaced with
+'castAs' and 'dyn_cast' should be replaced with 'getAs'. See r175462 for the
+first example of such a change along with many examples of how code was
+migrated to the new API.
+
+Storage Class
+^^^^^^^^^^^^^
+
+For each variable and function Clang used to keep the storage class as written
+in the source, the linkage and a semantic storage class. This was a bit
+redundant and the semantic storage class has been removed. The method
+getStorageClass now returns what is written it the source code for that decl.
+
+...
+
+Python Binding Changes
+----------------------
+
+The following methods have been added:
+
+- ...
+
+Significant Known Problems
+==========================
+
+Additional Information
+======================
+
+A wide variety of additional information is available on the `Clang web
+page <http://clang.llvm.org/>`_. The web page contains versions of the
+API documentation which are up-to-date with the Subversion version of
+the source code. You can access versions of these documents specific to
+this release by going into the "``clang/docs/``" directory in the Clang
+tree.
+
+If you have any questions or comments about Clang, please feel free to
+contact us via the `mailing
+list <http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev>`_.
diff --git a/docs/ThreadSanitizer.html b/docs/ThreadSanitizer.html
deleted file mode 100644
index aa251c1..0000000
--- a/docs/ThreadSanitizer.html
+++ /dev/null
@@ -1,126 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-<!-- Material used from: HTML 4.01 specs: http://www.w3.org/TR/html401/ -->
-<html>
-<head>
- <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
- <title>ThreadSanitizer, a race detector</title>
- <link type="text/css" rel="stylesheet" href="../menu.css">
- <link type="text/css" rel="stylesheet" href="../content.css">
- <style type="text/css">
- td {
- vertical-align: top;
- }
- </style>
-</head>
-<body>
-
-<!--#include virtual="../menu.html.incl"-->
-
-<div id="content">
-
-<h1>ThreadSanitizer</h1>
-<ul>
- <li> <a href="#intro">Introduction</a>
- <li> <a href="#howtobuild">How to Build</a>
- <li> <a href="#platforms">Supported Platforms</a>
- <li> <a href="#usage">Usage</a>
- <li> <a href="#limitations">Limitations</a>
- <li> <a href="#status">Current Status</a>
- <li> <a href="#moreinfo">More Information</a>
-</ul>
-
-<h2 id="intro">Introduction</h2>
-ThreadSanitizer is a tool that detects data races. <BR>
-It consists of a compiler instrumentation module and a run-time library. <BR>
-Typical slowdown introduced by ThreadSanitizer is <b>5x-15x</b> (TODO: these numbers are
-approximate so far).
-
-<h2 id="howtobuild">How to build</h2>
-Follow the <a href="../get_started.html">clang build instructions</a>.
-CMake build is supported.<BR>
-
-<h2 id="platforms">Supported Platforms</h2>
-ThreadSanitizer is supported on Linux x86_64 (tested on Ubuntu 10.04). <BR>
-Support for MacOS 10.7 (64-bit only) is planned for late 2012. <BR>
-Support for 32-bit platforms is problematic and not yet planned.
-
-
-
-<h2 id="usage">Usage</h2>
-Simply compile your program with <tt>-fsanitize=thread -fPIE</tt> and link it
-with <tt>-fsanitize=thread -pie</tt>.<BR>
-To get a reasonable performance add <tt>-O1</tt> or higher. <BR>
-Use <tt>-g</tt> to get file names and line numbers in the warning messages. <BR>
-
-Example:
-<pre>
-% cat projects/compiler-rt/lib/tsan/output_tests/tiny_race.c
-#include <pthread.h>
-int Global;
-void *Thread1(void *x) {
- Global = 42;
- return x;
-}
-int main() {
- pthread_t t;
- pthread_create(&t, NULL, Thread1, NULL);
- Global = 43;
- pthread_join(t, NULL);
- return Global;
-}
-</pre>
-
-<pre>
-% clang -fsanitize=thread -g -O1 tiny_race.c -fPIE -pie
-</pre>
-
-If a bug is detected, the program will print an error message to stderr.
-Currently, ThreadSanitizer symbolizes its output using an external
-<tt>addr2line</tt>
-process (this will be fixed in future).
-<pre>
-% TSAN_OPTIONS=strip_path_prefix=`pwd`/ # Don't print full paths.
-% ./a.out 2> log
-% cat log
-WARNING: ThreadSanitizer: data race (pid=19219)
- Write of size 4 at 0x7fcf47b21bc0 by thread 1:
- #0 Thread1 tiny_race.c:4 (exe+0x00000000a360)
- Previous write of size 4 at 0x7fcf47b21bc0 by main thread:
- #0 main tiny_race.c:10 (exe+0x00000000a3b4)
- Thread 1 (running) created at:
- #0 pthread_create ??:0 (exe+0x00000000c790)
- #1 main tiny_race.c:9 (exe+0x00000000a3a4)
-</pre>
-
-
-<h2 id="limitations">Limitations</h2>
-<ul>
-<li> ThreadSanitizer uses more real memory than a native run.
-At the default settings the memory overhead is 9x plus 9Mb per each thread.
-Settings with 5x and 3x overhead (but less accurate analysis) are also available.
-<li> ThreadSanitizer maps (but does not reserve) a lot of virtual address space.
-This means that tools like <tt>ulimit</tt> may not work as usually expected.
-<li> Static linking is not supported.
-<li> ThreadSanitizer requires <tt>-fPIE -pie</tt>
-</ul>
-
-
-<h2 id="status">Current Status</h2>
-ThreadSanitizer is in alpha stage.
-It is known to work on large C++ programs using pthreads, but we do not promise
-anything (yet). <BR>
-C++11 threading is not yet supported. <BR>
-The test suite is integrated into CMake build and can be run with
-<tt>make check-tsan</tt> command. <BR>
-
-We are actively working on enhancing the tool -- stay tuned.
-Any help, especially in the form of minimized standalone tests is more than welcome.
-
-<h2 id="moreinfo">More Information</h2>
-<a href="http://code.google.com/p/thread-sanitizer/">http://code.google.com/p/thread-sanitizer</a>.
-
-
-</div>
-</body>
-</html>
diff --git a/docs/ThreadSanitizer.rst b/docs/ThreadSanitizer.rst
new file mode 100644
index 0000000..c0c576b
--- /dev/null
+++ b/docs/ThreadSanitizer.rst
@@ -0,0 +1,126 @@
+ThreadSanitizer
+===============
+
+Introduction
+------------
+
+ThreadSanitizer is a tool that detects data races. It consists of a compiler
+instrumentation module and a run-time library. Typical slowdown introduced by
+ThreadSanitizer is about **5x-15x**. Typical memory overhead introduced by
+ThreadSanitizer is about **5x-10x**.
+
+How to build
+------------
+
+Follow the `Clang build instructions <../get_started.html>`_. CMake build is
+supported.
+
+Supported Platforms
+-------------------
+
+ThreadSanitizer is supported on Linux x86_64 (tested on Ubuntu 10.04 and 12.04).
+Support for MacOS 10.7 (64-bit only) is planned for 2013. Support for 32-bit
+platforms is problematic and not yet planned.
+
+Usage
+-----
+
+Simply compile your program with ``-fsanitize=thread -fPIE`` and link it with
+``-fsanitize=thread -pie``. To get a reasonable performance add ``-O1`` or
+higher. Use ``-g`` to get file names and line numbers in the warning messages.
+
+Example:
+
+.. code-block:: c++
+
+ % cat projects/compiler-rt/lib/tsan/lit_tests/tiny_race.c
+ #include <pthread.h>
+ int Global;
+ void *Thread1(void *x) {
+ Global = 42;
+ return x;
+ }
+ int main() {
+ pthread_t t;
+ pthread_create(&t, NULL, Thread1, NULL);
+ Global = 43;
+ pthread_join(t, NULL);
+ return Global;
+ }
+
+ $ clang -fsanitize=thread -g -O1 tiny_race.c -fPIE -pie
+
+If a bug is detected, the program will print an error message to stderr.
+Currently, ThreadSanitizer symbolizes its output using an external
+``addr2line`` process (this will be fixed in future).
+
+.. code-block:: bash
+
+ % ./a.out
+ WARNING: ThreadSanitizer: data race (pid=19219)
+ Write of size 4 at 0x7fcf47b21bc0 by thread T1:
+ #0 Thread1 tiny_race.c:4 (exe+0x00000000a360)
+
+ Previous write of size 4 at 0x7fcf47b21bc0 by main thread:
+ #0 main tiny_race.c:10 (exe+0x00000000a3b4)
+
+ Thread T1 (running) created at:
+ #0 pthread_create tsan_interceptors.cc:705 (exe+0x00000000c790)
+ #1 main tiny_race.c:9 (exe+0x00000000a3a4)
+
+``__has_feature(thread_sanitizer)``
+------------------------------------
+
+In some cases one may need to execute different code depending on whether
+ThreadSanitizer is enabled.
+:ref:`\_\_has\_feature <langext-__has_feature-__has_extension>` can be used for
+this purpose.
+
+.. code-block:: c
+
+ #if defined(__has_feature)
+ # if __has_feature(thread_sanitizer)
+ // code that builds only under ThreadSanitizer
+ # endif
+ #endif
+
+``__attribute__((no_sanitize_thread))``
+-----------------------------------------------
+
+Some code should not be instrumented by ThreadSanitizer.
+One may use the function attribute
+:ref:`no_sanitize_thread <langext-thread_sanitizer>`
+to disable instrumentation of plain (non-atomic) loads/stores in a particular function.
+ThreadSanitizer may still instrument such functions to avoid false positives.
+This attribute may not be
+supported by other compilers, so we suggest to use it together with
+``__has_feature(thread_sanitizer)``. Note: currently, this attribute will be
+lost if the function is inlined.
+
+Limitations
+-----------
+
+* ThreadSanitizer uses more real memory than a native run. At the default
+ settings the memory overhead is 5x plus 1Mb per each thread. Settings with 3x
+ (less accurate analysis) and 9x (more accurate analysis) overhead are also
+ available.
+* ThreadSanitizer maps (but does not reserve) a lot of virtual address space.
+ This means that tools like ``ulimit`` may not work as usually expected.
+* Libc/libstdc++ static linking is not supported.
+* ThreadSanitizer requires ``-fPIE -pie`` compiler flags.
+
+Current Status
+--------------
+
+ThreadSanitizer is in beta stage. It is known to work on large C++ programs
+using pthreads, but we do not promise anything (yet). C++11 threading is
+supported with llvm libc++. The test suite is integrated into CMake build
+and can be run with ``make check-tsan`` command.
+
+We are actively working on enhancing the tool --- stay tuned. Any help,
+especially in the form of minimized standalone tests is more than welcome.
+
+More Information
+----------------
+`http://code.google.com/p/thread-sanitizer <http://code.google.com/p/thread-sanitizer/>`_.
+
diff --git a/docs/Tooling.html b/docs/Tooling.html
deleted file mode 100644
index 74837f4..0000000
--- a/docs/Tooling.html
+++ /dev/null
@@ -1,120 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
-<title>Writing Clang Tools</title>
-<link type="text/css" rel="stylesheet" href="../menu.css">
-<link type="text/css" rel="stylesheet" href="../content.css">
-</head>
-<body>
-
-<!--#include virtual="../menu.html.incl"-->
-
-<div id="content">
-
-<h1>Writing Clang Tools</h1>
-<p>Clang provides infrastructure to write tools that need syntactic and semantic
-information about a program. This document will give a short introduction of the
-different ways to write clang tools, and their pros and cons.</p>
-
-<!-- ======================================================================= -->
-<h2 id="libclang"><a href="http://clang.llvm.org/doxygen/group__CINDEX.html">LibClang</a></h2>
-<!-- ======================================================================= -->
-
-<p>LibClang is a stable high level C interface to clang. When in doubt LibClang
-is probably the interface you want to use. Consider the other interfaces only
-when you have a good reason not to use LibClang.</p>
-<p>Canonical examples of when to use LibClang:</p>
-<ul>
- <li>Xcode</li>
- <li>Clang Python Bindings</li>
-</ul>
-<p>Use LibClang when you...</p>
-<ul>
- <li>want to interface with clang from other languages than C++</li>
- <li>need a stable interface that takes care to be backwards compatible</li>
- <li>want powerful high-level abstractions, like iterating through an AST
-with a cursor, and don't want to learn all the nitty gritty details of Clang's
-AST.</li>
-</ul>
-<p>Do not use LibClang when you...</p>
-<ul>
- <li>want full control over the Clang AST</li>
-</ul>
-
-<!-- ======================================================================= -->
-<h2 id="clang-plugins"><a href="ClangPlugins.html">Clang Plugins</a></h2>
-<!-- ======================================================================= -->
-
-<p>Clang Plugins allow you to run additional actions on the AST as part of
-a compilation. Plugins are dynamic libraries that are loaded at runtime by
-the compiler, and they're easy to integrate into your build environment.</p>
-<p>Canonical examples of when to use Clang Plugins:</p>
-<ul>
- <li>special lint-style warnings or errors for your project</li>
- <li>creating additional build artifacts from a single compile step</li>
-</ul>
-<p>Use Clang Plugins when you...</p>
-<ul>
- <li>need your tool to rerun if any of the dependencies change</li>
- <li>want your tool to make or break a build</li>
- <li>need full control over the Clang AST</li>
-</ul>
-<p>Do not use Clang Plugins when you...</p>
-<ul>
- <li>want to run tools outside of your build environment</li>
- <li>want full control on how Clang is set up, including mapping of in-memory
- virtual files</li>
- <li>need to run over a specific subset of files in your project which is not
- necessarily related to any changes which would trigger rebuilds</li>
-</ul>
-
-<!-- ======================================================================= -->
-<h2 id="libtooling"><a href="LibTooling.html">LibTooling</a></h2>
-<!-- ======================================================================= -->
-
-<p>LibTooling is a C++ interface aimed at writing standalone tools, as well as
-integrating into services that run clang tools.</p>
-<p>Canonical examples of when to use LibTooling:</p>
-<ul>
- <li>a simple syntax checker</li>
- <li>refactoring tools</li>
-</ul>
-<p>Use LibTooling when you...</p>
-<ul>
- <li>want to run tools over a single file, or a specific subset of files,
- independently of the build system</li>
- <li>want full control over the Clang AST</li>
- <li>want to share code with Clang Plugins</li>
-</ul>
-<p>Do not use LibTooling when you...</p>
-<ul>
- <li>want to run as part of the build triggered by dependency changes</li>
- <li>want a stable interface so you don't need to change your code when the
- AST API changes</li>
- <li>want high level abstractions like cursors and code completion out of the
- box</li>
- <li>do not want to write your tools in C++</li>
-</ul>
-
-<!-- ======================================================================= -->
-<h2 id="clang-tools"><a href="ClangTools.html">Clang Tools</a></h2>
-<!-- ======================================================================= -->
-
-<p>These are a collection of specific developer tools built on top of the
-LibTooling infrastructure as part of the Clang project. They are targeted at
-automating and improving core development activities of C/C++ developers.</p>
-<p>Examples of tools we are building or planning as part of the Clang
-project:</p>
-<ul>
- <li>Syntax checking (clang-check)</li>
- <li>Automatic fixing of compile errors (clangc-fixit)</li>
- <li>Automatic code formatting</li>
- <li>Migration tools for new features in new language standards</li>
- <li>Core refactoring tools</li>
-</ul>
-
-</div>
-</body>
-</html>
-
diff --git a/docs/Tooling.rst b/docs/Tooling.rst
new file mode 100644
index 0000000..25ee215
--- /dev/null
+++ b/docs/Tooling.rst
@@ -0,0 +1,97 @@
+=================================================
+Choosing the Right Interface for Your Application
+=================================================
+
+Clang provides infrastructure to write tools that need syntactic and semantic
+information about a program. This document will give a short introduction of
+the different ways to write clang tools, and their pros and cons.
+
+LibClang
+--------
+
+`LibClang <http://clang.llvm.org/doxygen/group__CINDEX.html>`_ is a stable high
+level C interface to clang. When in doubt LibClang is probably the interface
+you want to use. Consider the other interfaces only when you have a good
+reason not to use LibClang.
+
+Canonical examples of when to use LibClang:
+
+* Xcode
+* Clang Python Bindings
+
+Use LibClang when you...:
+
+* want to interface with clang from other languages than C++
+* need a stable interface that takes care to be backwards compatible
+* want powerful high-level abstractions, like iterating through an AST with a
+ cursor, and don't want to learn all the nitty gritty details of Clang's AST.
+
+Do not use LibClang when you...:
+
+* want full control over the Clang AST
+
+Clang Plugins
+-------------
+
+:doc:`Clang Plugins <ClangPlugins>` allow you to run additional actions on the
+AST as part of a compilation. Plugins are dynamic libraries that are loaded at
+runtime by the compiler, and they're easy to integrate into your build
+environment.
+
+Canonical examples of when to use Clang Plugins:
+
+* special lint-style warnings or errors for your project
+* creating additional build artifacts from a single compile step
+
+Use Clang Plugins when you...:
+
+* need your tool to rerun if any of the dependencies change
+* want your tool to make or break a build
+* need full control over the Clang AST
+
+Do not use Clang Plugins when you...:
+
+* want to run tools outside of your build environment
+* want full control on how Clang is set up, including mapping of in-memory
+ virtual files
+* need to run over a specific subset of files in your project which is not
+ necessarily related to any changes which would trigger rebuilds
+
+LibTooling
+----------
+
+:doc:`LibTooling <LibTooling>` is a C++ interface aimed at writing standalone
+tools, as well as integrating into services that run clang tools. Canonical
+examples of when to use LibTooling:
+
+* a simple syntax checker
+* refactoring tools
+
+Use LibTooling when you...:
+
+* want to run tools over a single file, or a specific subset of files,
+ independently of the build system
+* want full control over the Clang AST
+* want to share code with Clang Plugins
+
+Do not use LibTooling when you...:
+
+* want to run as part of the build triggered by dependency changes
+* want a stable interface so you don't need to change your code when the AST API
+ changes
+* want high level abstractions like cursors and code completion out of the box
+* do not want to write your tools in C++
+
+:doc:`Clang tools <ClangTools>` are a collection of specific developer tools
+built on top of the LibTooling infrastructure as part of the Clang project.
+They are targeted at automating and improving core development activities of
+C/C++ developers.
+
+Examples of tools we are building or planning as part of the Clang project:
+
+* Syntax checking (:program:`clang-check`)
+* Automatic fixing of compile errors (:program:`clang-fixit`)
+* Automatic code formatting (:program:`clang-format`)
+* Migration tools for new features in new language standards
+* Core refactoring tools
+
diff --git a/docs/UsersManual.html b/docs/UsersManual.html
deleted file mode 100644
index 35fc5dc..0000000
--- a/docs/UsersManual.html
+++ /dev/null
@@ -1,1309 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
-<title>Clang Compiler User's Manual</title>
-<link type="text/css" rel="stylesheet" href="../menu.css">
-<link type="text/css" rel="stylesheet" href="../content.css">
-<style type="text/css">
-td {
- vertical-align: top;
-}
-</style>
-</head>
-<body>
-
-<!--#include virtual="../menu.html.incl"-->
-
-<div id="content">
-
-<h1>Clang Compiler User's Manual</h1>
-
-<ul>
-<li><a href="#intro">Introduction</a>
- <ul>
- <li><a href="#terminology">Terminology</a></li>
- <li><a href="#basicusage">Basic Usage</a></li>
- </ul>
-</li>
-<li><a href="#commandline">Command Line Options</a>
- <ul>
- <li><a href="#cl_diagnostics">Options to Control Error and Warning
- Messages</a></li>
- <li><a href="#cl_crash_diagnostics">Options to Control Clang Crash
- Diagnostics</a></li>
- </ul>
-</li>
-<li><a href="#general_features">Language and Target-Independent Features</a>
- <ul>
- <li><a href="#diagnostics">Controlling Errors and Warnings</a>
- <ul>
- <li><a href="#diagnostics_display">Controlling How Clang Displays Diagnostics</a></li>
- <li><a href="#diagnostics_mappings">Diagnostic Mappings</a></li>
- <li><a href="#diagnostics_categories">Diagnostic Categories</a></li>
- <li><a href="#diagnostics_commandline">Controlling Diagnostics via Command Line Flags</a></li>
- <li><a href="#diagnostics_pragmas">Controlling Diagnostics via Pragmas</a></li>
- <li><a href="#diagnostics_systemheader">Controlling Diagnostics in System Headers</a></li>
- <li><a href="#diagnostics_enable_everything">Enabling All Warnings</a></li>
- <li><a href="#analyzer_diagnositics">Controlling Static Analyzer Diagnostics</a></li>
- </ul>
- </li>
- <li><a href="#precompiledheaders">Precompiled Headers</a></li>
- <li><a href="#codegen">Controlling Code Generation</a></li>
- <li><a href="#debuginfosize">Controlling Size of Debug Information</a></li>
- </ul>
-</li>
-<li><a href="#c">C Language Features</a>
- <ul>
- <li><a href="#c_ext">Extensions supported by clang</a></li>
- <li><a href="#c_modes">Differences between various standard modes</a></li>
- <li><a href="#c_unimpl_gcc">GCC extensions not implemented yet</a></li>
- <li><a href="#c_unsupp_gcc">Intentionally unsupported GCC extensions</a></li>
- <li><a href="#c_ms">Microsoft extensions</a></li>
- </ul>
-</li>
-<li><a href="#cxx">C++ Language Features</a>
- <ul>
- <li><a href="#cxx_implimits">Controlling implementation limits</a></li>
- </ul>
-</li>
-<li><a href="#target_features">Target-Specific Features and Limitations</a>
- <ul>
- <li><a href="#target_arch">CPU Architectures Features and Limitations</a>
- <ul>
- <li><a href="#target_arch_x86">X86</a></li>
- <li><a href="#target_arch_arm">ARM</a></li>
- <li><a href="#target_arch_other">Other platforms</a></li>
- </ul>
- </li>
- <li><a href="#target_os">Operating System Features and Limitations</a>
- <ul>
- <li><a href="#target_os_darwin">Darwin (Mac OS/X)</a></li>
- <li>Linux, etc.</li>
- <li><a href="#target_os_win32">Windows</a></li>
- </ul>
- </li>
- </ul>
-</li>
-</ul>
-
-
-<!-- ======================================================================= -->
-<h2 id="intro">Introduction</h2>
-<!-- ======================================================================= -->
-
-<p>The Clang Compiler is an open-source compiler for the C family of programming
-languages, aiming to be the best in class implementation of these languages.
-Clang builds on the LLVM optimizer and code generator, allowing it to provide
-high-quality optimization and code generation support for many targets. For
-more general information, please see the <a href="http://clang.llvm.org">Clang
-Web Site</a> or the <a href="http://llvm.org">LLVM Web Site</a>.</p>
-
-<p>This document describes important notes about using Clang as a compiler for
-an end-user, documenting the supported features, command line options, etc. If
-you are interested in using Clang to build a tool that processes code, please
-see <a href="InternalsManual.html">the Clang Internals Manual</a>. If you are
-interested in the <a href="http://clang-analyzer.llvm.org">Clang
-Static Analyzer</a>, please see its web page.</p>
-
-<p>Clang is designed to support the C family of programming languages, which
-includes <a href="#c">C</a>, <a href="#objc">Objective-C</a>, <a
-href="#cxx">C++</a>, and <a href="#objcxx">Objective-C++</a> as well as many
-dialects of those. For language-specific information, please see the
-corresponding language specific section:</p>
-
-<ul>
-<li><a href="#c">C Language</a>: K&amp;R C, ANSI C89, ISO C90, ISO C94
- (C89+AMD1), ISO C99 (+TC1, TC2, TC3). </li>
-<li><a href="#objc">Objective-C Language</a>: ObjC 1, ObjC 2, ObjC 2.1, plus
- variants depending on base language.</li>
-<li><a href="#cxx">C++ Language</a></li>
-<li><a href="#objcxx">Objective C++ Language</a></li>
-</ul>
-
-<p>In addition to these base languages and their dialects, Clang supports a
-broad variety of language extensions, which are documented in the corresponding
-language section. These extensions are provided to be compatible with the GCC,
-Microsoft, and other popular compilers as well as to improve functionality
-through Clang-specific features. The Clang driver and language features are
-intentionally designed to be as compatible with the GNU GCC compiler as
-reasonably possible, easing migration from GCC to Clang. In most cases, code
-"just works".</p>
-
-<p>In addition to language specific features, Clang has a variety of features
-that depend on what CPU architecture or operating system is being compiled for.
-Please see the <a href="#target_features">Target-Specific Features and
-Limitations</a> section for more details.</p>
-
-<p>The rest of the introduction introduces some basic <a
-href="#terminology">compiler terminology</a> that is used throughout this manual
-and contains a basic <a href="#basicusage">introduction to using Clang</a>
-as a command line compiler.</p>
-
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-<h3 id="terminology">Terminology</h3>
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-
-<p>Front end, parser, backend, preprocessor, undefined behavior, diagnostic,
- optimizer</p>
-
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-<h3 id="basicusage">Basic Usage</h3>
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-
-<p>Intro to how to use a C compiler for newbies.</p>
-<p>
-compile + link
-
-compile then link
-
-debug info
-
-enabling optimizations
-
-picking a language to use, defaults to C99 by default. Autosenses based on
-extension.
-
-using a makefile
-</p>
-
-
-<!-- ======================================================================= -->
-<h2 id="commandline">Command Line Options</h2>
-<!-- ======================================================================= -->
-
-<p>
-This section is generally an index into other sections. It does not go into
-depth on the ones that are covered by other sections. However, the first part
-introduces the language selection and other high level options like -c, -g, etc.
-</p>
-
-
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-<h3 id="cl_diagnostics">Options to Control Error and Warning Messages</h3>
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-
-<p><b>-Werror</b>: Turn warnings into errors.</p>
-<p><b>-Werror=foo</b>: Turn warning "foo" into an error.</p>
-<p><b>-Wno-error=foo</b>: Turn warning "foo" into an warning even if -Werror is
- specified.</p>
-<p><b>-Wfoo</b>: Enable warning "foo".</p>
-<p><b>-Wno-foo</b>: Disable warning "foo".</p>
-<p><b>-w</b>: Disable all warnings.</p>
-<p><b>-Weverything</b>: <a href="#diagnostics_enable_everything">Enable <b>all</b> warnings.</a></p>
-<p><b>-pedantic</b>: Warn on language extensions.</p>
-<p><b>-pedantic-errors</b>: Error on language extensions.</p>
-<p><b>-Wsystem-headers</b>: Enable warnings from system headers.</p>
-
-<p><b>-ferror-limit=123</b>: Stop emitting diagnostics after 123 errors have
- been produced. The default is 20, and the error limit can be disabled with
- -ferror-limit=0.</p>
-
-<p><b>-ftemplate-backtrace-limit=123</b>: Only emit up to 123 template instantiation notes within the template instantiation backtrace for a single warning or error. The default is 10, and the limit can be disabled with -ftemplate-backtrace-limit=0.</p>
-
-<!-- ================================================= -->
-<h4 id="cl_diag_formatting">Formatting of Diagnostics</h4>
-<!-- ================================================= -->
-
-<p>Clang aims to produce beautiful diagnostics by default, particularly for new
-users that first come to Clang. However, different people have different
-preferences, and sometimes Clang is driven by another program that wants to
-parse simple and consistent output, not a person. For these cases, Clang
-provides a wide range of options to control the exact output format of the
-diagnostics that it generates.</p>
-
-<dl>
-
-<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-<dt id="opt_fshow-column"><b>-f[no-]show-column</b>: Print column number in
-diagnostic.</dt>
-<dd>This option, which defaults to on, controls whether or not Clang prints the
-column number of a diagnostic. For example, when this is enabled, Clang will
-print something like:
-
-<pre>
- test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
- #endif bad
- ^
- //
-</pre>
-
-<p>When this is disabled, Clang will print "test.c:28: warning..." with no
-column number.</p>
-
-<p>The printed column numbers count bytes from the beginning of the line; take
-care if your source contains multibyte characters.</p>
-</dd>
-
-<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-<dt id="opt_fshow-source-location"><b>-f[no-]show-source-location</b>: Print
-source file/line/column information in diagnostic.</dt>
-<dd>This option, which defaults to on, controls whether or not Clang prints the
-filename, line number and column number of a diagnostic. For example,
-when this is enabled, Clang will print something like:
-
-<pre>
- test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
- #endif bad
- ^
- //
-</pre>
-
-<p>When this is disabled, Clang will not print the "test.c:28:8: " part.</p>
-</dd>
-
-<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-<dt id="opt_fcaret-diagnostics"><b>-f[no-]caret-diagnostics</b>: Print source
-line and ranges from source code in diagnostic.</dt>
-<dd>This option, which defaults to on, controls whether or not Clang prints the
-source line, source ranges, and caret when emitting a diagnostic. For example,
-when this is enabled, Clang will print something like:
-
-<pre>
- test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
- #endif bad
- ^
- //
-</pre>
-</dd>
-<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-<dt id="opt_fcolor_diagnostics"><b>-f[no-]color-diagnostics</b>: </dt>
-<dd>This option, which defaults to on when a color-capable terminal is
- detected, controls whether or not Clang prints diagnostics in color.
- When this option is enabled, Clang will use colors to highlight
- specific parts of the diagnostic, e.g.,
- <pre>
- <b><span style="color:black">test.c:28:8: <span style="color:magenta">warning</span>: extra tokens at end of #endif directive [-Wextra-tokens]</span></b>
- #endif bad
- <span style="color:green">^</span>
- <span style="color:green">//</span>
-</pre>
-
-<p>When this is disabled, Clang will just print:</p>
-
-<pre>
- test.c:2:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
- #endif bad
- ^
- //
-</pre>
-</dd>
-<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-<dt id="opt_fdiagnostics-format"><b>-fdiagnostics-format=clang/msvc/vi</b>:
-Changes diagnostic output format to better match IDEs and command line tools.</dt>
-<dd>This option controls the output format of the filename, line number, and column printed in diagnostic messages. The options, and their affect on formatting a simple conversion diagnostic, follow:
-
- <dl>
- <dt><b>clang</b> (default)</dt>
- <dd>
- <pre>t.c:3:11: warning: conversion specifies type 'char *' but the argument has type 'int'</pre>
- </dd>
-
- <dt><b>msvc</b></dt>
- <dd>
- <pre>t.c(3,11) : warning: conversion specifies type 'char *' but the argument has type 'int'</pre>
- </dd>
-
- <dt><b>vi</b></dt>
- <dd>
- <pre>t.c +3:11: warning: conversion specifies type 'char *' but the argument has type 'int'</pre>
- </dd>
- </dl>
-</dd>
-
-<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-<dt id="opt_fdiagnostics-show-name"><b>-f[no-]diagnostics-show-name</b>:
-Enable the display of the diagnostic name.</dt>
-<dd>This option, which defaults to off, controls whether or not
-Clang prints the associated name.<p></p></dd>
-<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-<dt id="opt_fdiagnostics-show-option"><b>-f[no-]diagnostics-show-option</b>:
-Enable <tt>[-Woption]</tt> information in diagnostic line.</dt>
-<dd>This option, which defaults to on,
-controls whether or not Clang prints the associated <A
-href="#cl_diag_warning_groups">warning group</a> option name when outputting
-a warning diagnostic. For example, in this output:
-
-<pre>
- test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
- #endif bad
- ^
- //
-</pre>
-
-<p>Passing <b>-fno-diagnostics-show-option</b> will prevent Clang from printing
-the [<a href="#opt_Wextra-tokens">-Wextra-tokens</a>] information in the
-diagnostic. This information tells you the flag needed to enable or disable the
-diagnostic, either from the command line or through <a
-href="#pragma_GCC_diagnostic">#pragma GCC diagnostic</a>.</dd>
-
-<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-<dt id="opt_fdiagnostics-show-category"><b>-fdiagnostics-show-category=none/id/name</b>:
-Enable printing category information in diagnostic line.</dt>
-<dd>This option, which defaults to "none",
-controls whether or not Clang prints the category associated with a diagnostic
-when emitting it. Each diagnostic may or many not have an associated category,
-if it has one, it is listed in the diagnostic categorization field of the
-diagnostic line (in the []'s).
-
-<p>For example, a format string warning will produce these three renditions
-based on the setting of this option:</p>
-
-<pre>
- t.c:3:11: warning: conversion specifies type 'char *' but the argument has type 'int' [-Wformat]
- t.c:3:11: warning: conversion specifies type 'char *' but the argument has type 'int' [-Wformat<b>,1</b>]
- t.c:3:11: warning: conversion specifies type 'char *' but the argument has type 'int' [-Wformat<b>,Format String</b>]
-</pre>
-
-<p>This category can be used by clients that want to group diagnostics by
-category, so it should be a high level category. We want dozens of these, not
-hundreds or thousands of them.</p>
-</dd>
-
-
-
-<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-<dt id="opt_fdiagnostics-fixit-info"><b>-f[no-]diagnostics-fixit-info</b>:
-Enable "FixIt" information in the diagnostics output.</dt>
-<dd>This option, which defaults to on, controls whether or not Clang prints the
-information on how to fix a specific diagnostic underneath it when it knows.
-For example, in this output:
-
-<pre>
- test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
- #endif bad
- ^
- //
-</pre>
-
-<p>Passing <b>-fno-diagnostics-fixit-info</b> will prevent Clang from printing
-the "//" line at the end of the message. This information is useful for users
-who may not understand what is wrong, but can be confusing for machine
-parsing.</p>
-</dd>
-
-<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-<dt id="opt_fdiagnostics-print-source-range-info">
-<b>-f[no-]diagnostics-print-source-range-info</b>:
-Print machine parsable information about source ranges.</dt>
-<dd>This option, which defaults to off, controls whether or not Clang prints
-information about source ranges in a machine parsable format after the
-file/line/column number information. The information is a simple sequence of
-brace enclosed ranges, where each range lists the start and end line/column
-locations. For example, in this output:
-
-<pre>
-exprs.c:47:15:{47:8-47:14}{47:17-47:24}: error: invalid operands to binary expression ('int *' and '_Complex float')
- P = (P-42) + Gamma*4;
- ~~~~~~ ^ ~~~~~~~
-</pre>
-
-<p>The {}'s are generated by -fdiagnostics-print-source-range-info.</p>
-
-<p>The printed column numbers count bytes from the beginning of the line; take
-care if your source contains multibyte characters.</p>
-</dd>
-
-<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-<dt id="opt_fdiagnostics-parseable-fixits">
-<b>-fdiagnostics-parseable-fixits</b>:
-Print Fix-Its in a machine parseable form.</dt>
-<dd><p>This option makes Clang print available Fix-Its in a machine parseable format at the end of diagnostics. The following example illustrates the format:</p>
-
-<pre>
- fix-it:"t.cpp":{7:25-7:29}:"Gamma"
-</pre>
-
-<p>The range printed is a half-open range, so in this example the characters at
-column 25 up to but not including column 29 on line 7 in t.cpp should be
-replaced with the string &quot;Gamma&quot;. Either the range or the replacement
-string may be empty (representing strict insertions and strict erasures,
-respectively). Both the file name and the insertion string escape backslash (as
-&quot;\\&quot;), tabs (as &quot;\t&quot;), newlines (as &quot;\n&quot;), double
-quotes(as &quot;\&quot;&quot;) and non-printable characters (as octal
-&quot;\xxx&quot;).</p>
-
-<p>The printed column numbers count bytes from the beginning of the line; take
-care if your source contains multibyte characters.</p>
-</dd>
-
-<dt id="opt_fno-elide-type">
-<b>-fno-elide-type</b>:
-Turns off elision in template type printing.</dt>
-<dd><p>The default for template type printing is to elide as many template
-arguments as possible, removing those which are the same in both template types,
-leaving only the differences. Adding this flag will print all the template
-arguments. If supported by the terminal, highlighting will still appear on
-differing arguments.</p>
-
-Default:
-<pre>
-t.cc:4:5: <span class="note">note</span>: candidate function not viable: no known conversion from 'vector&lt;map&lt;[...], map&lt;<span class="template-highlight">float</span>, [...]&gt;&gt;&gt;' to 'vector&lt;map&lt;[...], map&lt;<span class="template-highlight">double</span>, [...]&gt;&gt;&gt;' for 1st argument;
-</pre>
--fno-elide-type:
-<pre>
-t.cc:4:5: <span class="note">note</span>: candidate function not viable: no known conversion from 'vector&lt;map&lt;int, map&lt;<span class="template-highlight">float</span>, int&gt;&gt;&gt;' to 'vector&lt;map&lt;int, map&lt;<span class="template-highlight">double</span>, int&gt;&gt;&gt;' for 1st argument;
-</pre>
-</dd>
-
-<dt id="opt_fdiagnostics-show-template-tree">
-<b>-fdiagnostics-show-template-tree</b>:
-Template type diffing prints a text tree.</dt>
-<dd><p>For diffing large templated types, this option will cause Clang to
-display the templates as an indented text tree, one argument per line, with
-differences marked inline. This is compatible with -fno-elide-type.</p>
-
-Default:
-<pre>
-t.cc:4:5: <span class="note">note</span>: candidate function not viable: no known conversion from 'vector&lt;map&lt;[...], map&lt;<span class="template-highlight">float</span>, [...]&gt;&gt;&gt;' to 'vector&lt;map&lt;[...], map&lt;<span class="template-highlight">double</span>, [...]&gt;&gt;&gt;' for 1st argument;
-</pre>
--fdiagnostics-show-template-tree
-<pre>
-t.cc:4:5: <span class="note">note</span>: candidate function not viable: no known conversion for 1st argument;
- vector&lt;
- map&lt;
- [...],
- map&lt;
- [<span class="template-highlight">float</span> != <span class="template-highlight">float</span>],
- [...]&gt;&gt;&gt;
-</pre>
-</dd>
-
-</dl>
-
-
-
-<!-- ===================================================== -->
-<h4 id="cl_diag_warning_groups">Individual Warning Groups</h4>
-<!-- ===================================================== -->
-
-<p>TODO: Generate this from tblgen. Define one anchor per warning group.</p>
-
-
-<dl>
-
-
-<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-<dt id="opt_Wextra-tokens"><b>-Wextra-tokens</b>: Warn about excess tokens at
- the end of a preprocessor directive.</dt>
-<dd>This option, which defaults to on, enables warnings about extra tokens at
-the end of preprocessor directives. For example:
-
-<pre>
- test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
- #endif bad
- ^
-</pre>
-
-<p>These extra tokens are not strictly conforming, and are usually best handled
-by commenting them out.</p>
-</dd>
-
-<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-<dt id="opt_Wambiguous-member-template"><b>-Wambiguous-member-template</b>:
-Warn about unqualified uses of a member template whose name resolves
-to another template at the location of the use.</dt>
-<dd>This option, which defaults to on, enables a warning in the
-following code:
-
-<pre>
-template&lt;typename T> struct set{};
-template&lt;typename T> struct trait { typedef const T& type; };
-struct Value {
- template&lt;typename T> void set(typename trait&lt;T>::type value) {}
-};
-void foo() {
- Value v;
- v.set&lt;double>(3.2);
-}
-</pre>
-
-<p>C++ [basic.lookup.classref] requires this to be an error, but,
-because it's hard to work around, Clang downgrades it to a warning as
-an extension.</p>
-</dd>
-
-<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-<dt id="opt_Wbind-to-temporary-copy"><b>-Wbind-to-temporary-copy</b>: Warn about
-an unusable copy constructor when binding a reference to a temporary.</dt>
-<dd>This option, which defaults to on, enables warnings about binding a
-reference to a temporary when the temporary doesn't have a usable copy
-constructor. For example:
-
-<pre>
- struct NonCopyable {
- NonCopyable();
- private:
- NonCopyable(const NonCopyable&);
- };
- void foo(const NonCopyable&);
- void bar() {
- foo(NonCopyable()); // Disallowed in C++98; allowed in C++11.
- }
-</pre>
-<pre>
- struct NonCopyable2 {
- NonCopyable2();
- NonCopyable2(NonCopyable2&);
- };
- void foo(const NonCopyable2&);
- void bar() {
- foo(NonCopyable2()); // Disallowed in C++98; allowed in C++11.
- }
-</pre>
-
-<p>Note that if <tt>NonCopyable2::NonCopyable2()</tt> has a default
-argument whose instantiation produces a compile error, that error will
-still be a hard error in C++98 mode even if this warning is turned
-off.</p>
-
-</dd>
-
-</dl>
-
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-<h3 id="cl_crash_diagnostics">Options to Control Clang Crash Diagnostics</h3>
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-
-<p>As unbelievable as it may sound, Clang does crash from time to time.
-Generally, this only occurs to those living on the
-<a href="http://llvm.org/releases/download.html#svn">bleeding edge</a>. Clang
-goes to great lengths to assist you in filing a bug report. Specifically, Clang
-generates preprocessed source file(s) and associated run script(s) upon a
-crash. These files should be attached to a bug report to ease reproducibility
-of the failure. Below are the command line options to control the crash
-diagnostics.
-</p>
-
-<p><b>-fno-crash-diagnostics</b>: Disable auto-generation of preprocessed
-source files during a clang crash.</p>
-
-<p>The -fno-crash-diagnostics flag can be helpful for speeding the process of
-generating a delta reduced test case.</p>
-
-
-<!-- ======================================================================= -->
-<h2 id="general_features">Language and Target-Independent Features</h2>
-<!-- ======================================================================= -->
-
-
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-<h3 id="diagnostics">Controlling Errors and Warnings</h3>
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-
-<p>Clang provides a number of ways to control which code constructs cause it to
-emit errors and warning messages, and how they are displayed to the console.</p>
-
-<h4 id="diagnostics_display">Controlling How Clang Displays Diagnostics</h4>
-
-<p>When Clang emits a diagnostic, it includes rich information in the output,
-and gives you fine-grain control over which information is printed. Clang has
-the ability to print this information, and these are the options that control
-it:</p>
-
-<ol>
-<li>A file/line/column indicator that shows exactly where the diagnostic occurs
- in your code [<a href="#opt_fshow-column">-fshow-column</a>, <a
- href="#opt_fshow-source-location">-fshow-source-location</a>].</li>
-<li>A categorization of the diagnostic as a note, warning, error, or fatal
- error.</li>
-<li>A text string that describes what the problem is.</li>
-<li>An option that indicates how to control the diagnostic (for diagnostics that
- support it) [<a
- href="#opt_fdiagnostics-show-option">-fdiagnostics-show-option</a>].</li>
-<li>A <a href="#diagnostics_categories">high-level category</a> for the
- diagnostic for clients that want to group diagnostics by class (for
- diagnostics that support it) [<a
- href="#opt_fdiagnostics-show-category">-fdiagnostics-show-category</a>].</li>
-<li>The line of source code that the issue occurs on, along with a caret and
- ranges that indicate the important locations [<a
- href="opt_fcaret-diagnostics">-fcaret-diagnostics</a>].</li>
-<li>"FixIt" information, which is a concise explanation of how to fix the
- problem (when Clang is certain it knows) [<a
- href="opt_fdiagnostics-fixit-info">-fdiagnostics-fixit-info</a>].</li>
-<li>A machine-parsable representation of the ranges involved (off by
- default) [<a
- href="opt_fdiagnostics-print-source-range-info">-fdiagnostics-print-source-range-info</a>].</li>
-</ol>
-
-<p>For more information please see <a href="#cl_diag_formatting">Formatting of
-Diagnostics</a>.</p>
-
-
-<h4 id="diagnostics_mappings">Diagnostic Mappings</h4>
-
-<p>All diagnostics are mapped into one of these 5 classes:</p>
-
-<ul>
-<li>Ignored</li>
-<li>Note</li>
-<li>Warning</li>
-<li>Error</li>
-<li>Fatal</li>
-</ul>
-
-<h4 id="diagnostics_categories">Diagnostic Categories</h4>
-
-<p>Though not shown by default, diagnostics may each be associated with a
- high-level category. This category is intended to make it possible to triage
- builds that produce a large number of errors or warnings in a grouped way.
-</p>
-
-<p>Categories are not shown by default, but they can be turned on with the
-<a href="#opt_fdiagnostics-show-category">-fdiagnostics-show-category</a> option.
-When set to "<tt>name</tt>", the category is printed textually in the diagnostic
-output. When it is set to "<tt>id</tt>", a category number is printed. The
-mapping of category names to category id's can be obtained by running '<tt>clang
- --print-diagnostic-categories</tt>'.
-</p>
-
-<h4 id="diagnostics_commandline">Controlling Diagnostics via Command Line
- Flags</h4>
-
-<p>TODO: -W flags, -pedantic, etc</p>
-
-<h4 id="diagnostics_pragmas">Controlling Diagnostics via Pragmas</h4>
-
-<p>Clang can also control what diagnostics are enabled through the use of
-pragmas in the source code. This is useful for turning off specific warnings
-in a section of source code. Clang supports GCC's pragma for compatibility
-with existing source code, as well as several extensions. </p>
-
-<p>The pragma may control any warning that can be used from the command line.
-Warnings may be set to ignored, warning, error, or fatal. The following
-example code will tell Clang or GCC to ignore the -Wall warnings:</p>
-
-<pre>
-#pragma GCC diagnostic ignored "-Wall"
-</pre>
-
-<p>In addition to all of the functionality provided by GCC's pragma, Clang
-also allows you to push and pop the current warning state. This is particularly
-useful when writing a header file that will be compiled by other people, because
-you don't know what warning flags they build with.</p>
-
-<p>In the below example
--Wmultichar is ignored for only a single line of code, after which the
-diagnostics return to whatever state had previously existed.</p>
-
-<pre>
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wmultichar"
-
-char b = 'df'; // no warning.
-
-#pragma clang diagnostic pop
-</pre>
-
-<p>The push and pop pragmas will save and restore the full diagnostic state of
-the compiler, regardless of how it was set. That means that it is possible to
-use push and pop around GCC compatible diagnostics and Clang will push and pop
-them appropriately, while GCC will ignore the pushes and pops as unknown
-pragmas. It should be noted that while Clang supports the GCC pragma, Clang and
-GCC do not support the exact same set of warnings, so even when using GCC
-compatible #pragmas there is no guarantee that they will have identical behaviour
-on both compilers. </p>
-
-<h4 id="diagnostics_systemheader">Controlling Diagnostics in System Headers</h4>
-
-<p>Warnings are suppressed when they occur in system headers. By default, an
-included file is treated as a system header if it is found in an include path
-specified by <tt>-isystem</tt>, but this can be overridden in several ways.</p>
-
-<p>The <tt>system_header</tt> pragma can be used to mark the current file as
-being a system header. No warnings will be produced from the location of the
-pragma onwards within the same file.</p>
-
-<pre>
-char a = 'xy'; // warning
-
-#pragma clang system_header
-
-char b = 'ab'; // no warning
-</pre>
-
-<p>The <tt>-isystem-prefix</tt> and <tt>-ino-system-prefix</tt> command-line
-arguments can be used to override whether subsets of an include path are treated
-as system headers. When the name in a <tt>#include</tt> directive is found
-within a header search path and starts with a system prefix, the header is
-treated as a system header. The last prefix on the command-line which matches
-the specified header name takes precedence. For instance:</p>
-
-<pre>
-clang -Ifoo -isystem bar -isystem-prefix x/ -ino-system-prefix x/y/
-</pre>
-
-<p>Here, <tt>#include "x/a.h"</tt> is treated as including a system header, even
-if the header is found in <tt>foo</tt>, and <tt>#include "x/y/b.h"</tt> is
-treated as not including a system header, even if the header is found in
-<tt>bar</tt>.
-</p>
-
-<p>A <tt>#include</tt> directive which finds a file relative to the current
-directory is treated as including a system header if the including file is
-treated as a system header.</p>
-
-<h4 id="diagnostics_enable_everything">Enabling All Warnings</h4>
-
-<p>In addition to the traditional <tt>-W</tt> flags, one can enable <b>all</b>
- warnings by passing <tt>-Weverything</tt>.
- This works as expected with <tt>-Werror</tt>,
- and also includes the warnings from <tt>-pedantic</tt>.</p>
-
-<p>Note that when combined with <tt>-w</tt> (which disables all warnings), that
- flag wins.</p>
-
-<h4 id="analyzer_diagnositics">Controlling Static Analyzer Diagnostics</h4>
-
-<p>While not strictly part of the compiler, the diagnostics from Clang's <a
-href="http://clang-analyzer.llvm.org">static analyzer</a> can also be influenced
-by the user via changes to the source code. See the available
-<a href = "http://clang-analyzer.llvm.org/annotations.html" >annotations</a> and
-the analyzer's
-<a href= "http://clang-analyzer.llvm.org/faq.html#exclude_code" >FAQ page</a> for
-more information.
-
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-<h3 id="precompiledheaders">Precompiled Headers</h3>
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-
-<p><a href="http://en.wikipedia.org/wiki/Precompiled_header">Precompiled
-headers</a> are a general approach employed by many compilers to reduce
-compilation time. The underlying motivation of the approach is that it is
-common for the same (and often large) header files to be included by
-multiple source files. Consequently, compile times can often be greatly improved
-by caching some of the (redundant) work done by a compiler to process headers.
-Precompiled header files, which represent one of many ways to implement
-this optimization, are literally files that represent an on-disk cache that
-contains the vital information necessary to reduce some of the work
-needed to process a corresponding header file. While details of precompiled
-headers vary between compilers, precompiled headers have been shown to be
-highly effective at speeding up program compilation on systems with very large
-system headers (e.g., Mac OS/X).</p>
-
-<h4>Generating a PCH File</h4>
-
-<p>To generate a PCH file using Clang, one invokes Clang with
-the <b><tt>-x <i>&lt;language&gt;</i>-header</tt></b> option. This mirrors the
-interface in GCC for generating PCH files:</p>
-
-<pre>
- $ gcc -x c-header test.h -o test.h.gch
- $ clang -x c-header test.h -o test.h.pch
-</pre>
-
-<h4>Using a PCH File</h4>
-
-<p>A PCH file can then be used as a prefix header when a
-<b><tt>-include</tt></b> option is passed to <tt>clang</tt>:</p>
-
-<pre>
- $ clang -include test.h test.c -o test
-</pre>
-
-<p>The <tt>clang</tt> driver will first check if a PCH file for <tt>test.h</tt>
-is available; if so, the contents of <tt>test.h</tt> (and the files it includes)
-will be processed from the PCH file. Otherwise, Clang falls back to
-directly processing the content of <tt>test.h</tt>. This mirrors the behavior of
-GCC.</p>
-
-<p><b>NOTE:</b> Clang does <em>not</em> automatically use PCH files
-for headers that are directly included within a source file. For example:</p>
-
-<pre>
- $ clang -x c-header test.h -o test.h.pch
- $ cat test.c
- #include "test.h"
- $ clang test.c -o test
-</pre>
-
-<p>In this example, <tt>clang</tt> will not automatically use the PCH file for
-<tt>test.h</tt> since <tt>test.h</tt> was included directly in the source file
-and not specified on the command line using <tt>-include</tt>.</p>
-
-<h4>Relocatable PCH Files</h4>
-<p>It is sometimes necessary to build a precompiled header from headers that
-are not yet in their final, installed locations. For example, one might build a
-precompiled header within the build tree that is then meant to be installed
-alongside the headers. Clang permits the creation of "relocatable" precompiled
-headers, which are built with a given path (into the build directory) and can
-later be used from an installed location.</p>
-
-<p>To build a relocatable precompiled header, place your headers into a
-subdirectory whose structure mimics the installed location. For example, if you
-want to build a precompiled header for the header <code>mylib.h</code> that
-will be installed into <code>/usr/include</code>, create a subdirectory
-<code>build/usr/include</code> and place the header <code>mylib.h</code> into
-that subdirectory. If <code>mylib.h</code> depends on other headers, then
-they can be stored within <code>build/usr/include</code> in a way that mimics
-the installed location.</p>
-
-<p>Building a relocatable precompiled header requires two additional arguments.
-First, pass the <code>--relocatable-pch</code> flag to indicate that the
-resulting PCH file should be relocatable. Second, pass
-<code>-isysroot /path/to/build</code>, which makes all includes for your
-library relative to the build directory. For example:</p>
-
-<pre>
- # clang -x c-header --relocatable-pch -isysroot /path/to/build /path/to/build/mylib.h mylib.h.pch
-</pre>
-
-<p>When loading the relocatable PCH file, the various headers used in the PCH
-file are found from the system header root. For example, <code>mylib.h</code>
-can be found in <code>/usr/include/mylib.h</code>. If the headers are installed
-in some other system root, the <code>-isysroot</code> option can be used provide
-a different system root from which the headers will be based. For example,
-<code>-isysroot /Developer/SDKs/MacOSX10.4u.sdk</code> will look for
-<code>mylib.h</code> in
-<code>/Developer/SDKs/MacOSX10.4u.sdk/usr/include/mylib.h</code>.</p>
-
-<p>Relocatable precompiled headers are intended to be used in a limited number
-of cases where the compilation environment is tightly controlled and the
-precompiled header cannot be generated after headers have been installed.
-Relocatable precompiled headers also have some performance impact, because
-the difference in location between the header locations at PCH build time vs.
-at the time of PCH use requires one of the PCH optimizations,
-<code>stat()</code> caching, to be disabled. However, this change is only
-likely to affect PCH files that reference a large number of headers.</p>
-
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-<h3 id="codegen">Controlling Code Generation</h3>
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-
-<p>Clang provides a number of ways to control code generation. The options are listed below.</p>
-
-<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-<dl>
-<dt id="opt_fsanitize"><b>-fsanitize=check1,check2</b>: Turn on runtime checks
-for various forms of undefined behavior.</dt>
-
-<dd>This option controls whether Clang adds runtime checks for various forms of
-undefined behavior, and is disabled by default. If a check fails, a diagnostic
-message is produced at runtime explaining the problem. The main checks are:
-
-<ul>
-<li id="opt_fsanitize_address"><tt>-fsanitize=address</tt>:
- <a href="AddressSanitizer.html">AddressSanitizer</a>, a memory error
- detector.</li>
-<li id="opt_fsanitize_thread"><tt>-fsanitize=thread</tt>:
- <a href="ThreadSanitizer.html">ThreadSanitizer</a>, an <em>experimental</em>
- data race detector. Not ready for widespread use.</li>
-<li id="opt_fsanitize_undefined"><tt>-fsanitize=undefined</tt>:
- Enables all the checks listed below.</li>
-</ul>
-
-The following more fine-grained checks are also available:
-
-<ul>
-<li id="opt_fsanitize_alignment"><tt>-fsanitize=alignment</tt>:
- Use of a misaligned pointer or creation of a misaligned reference.</li>
-<li id="opt_fsanitize_divide-by-zero"><tt>-fsanitize=divide-by-zero</tt>:
- Division by zero.</li>
-<li id="opt_fsanitize_float-cast-overflow"><tt>-fsanitize=float-cast-overflow</tt>:
- Conversion to, from, or between floating-point types which would overflow
- the destination.</li>
-<li id="opt_fsanitize_null"><tt>-fsanitize=null</tt>:
- Use of a null pointer or creation of a null reference.</li>
-<li id="opt_fsanitize_object-size"><tt>-fsanitize=object-size</tt>:
- An attempt to use bytes which the optimizer can determine are not part of
- the object being accessed.
- The sizes of objects are determined using <tt>__builtin_object_size</tt>, and
- consequently may be able to detect more problems at higher optimization
- levels.</li>
-<li id="opt_fsanitize_return"><tt>-fsanitize=return</tt>:
- In C++, reaching the end of a value-returning function without returning a
- value.</li>
-<li id="opt_fsanitize_shift"><tt>-fsanitize=shift</tt>:
- Shift operators where the amount shifted is greater or equal to the
- promoted bit-width of the left hand side or less than zero, or where
- the left hand side is negative. For a signed left shift, also checks
- for signed overflow in C, and for unsigned overflow in C++.</li>
-<li id="opt_fsanitize_signed-integer-overflow"><tt>-fsanitize=signed-integer-overflow</tt>:
- Signed integer overflow, including all the checks added by <tt>-ftrapv</tt>,
- and checking for overflow in signed division (<tt>INT_MIN / -1</tt>).</li>
-<li id="opt_fsanitize_unreachable"><tt>-fsanitize=unreachable</tt>:
- If control flow reaches __builtin_unreachable.</li>
-<li id="opt_fsanitize_vla-bound"><tt>-fsanitize=vla-bound</tt>:
- A variable-length array whose bound does not evaluate to a positive value.</li>
-<li id="opt_fsanitize_vptr"><tt>-fsanitize=vptr</tt>:
- Use of an object whose vptr indicates that it is of the wrong dynamic type,
- or that its lifetime has not begun or has ended. Incompatible with
- <tt>-fno-rtti</tt>.</li>
-</ul>
-
-The <tt>-fsanitize=</tt> argument must also be provided when linking, in order
-to link to the appropriate runtime library. It is not possible to combine the
-<tt>-fsanitize=address</tt> and <tt>-fsanitize=thread</tt> checkers in the same
-program.
-</dd>
-
-<dt id="opt_faddress-sanitizer"><b>-f[no-]address-sanitizer</b>:
-Deprecated synonym for <a href="#opt_fsanitize_address"><tt>-f[no-]sanitize=address</tt></a>.
-
-<dt id="opt_fthread-sanitizer"><b>-f[no-]thread-sanitizer</b>:
-Deprecated synonym for <a href="#opt_fsanitize_address"><tt>-f[no-]sanitize=thread</tt></a>.
-
-<dt id="opt_fcatch-undefined-behavior"><b>-fcatch-undefined-behavior</b>:
-Deprecated synonym for <a href="#opt_fsanitize_undefined"><tt>-fsanitize=undefined</tt></a>.
-
-<dt id="opt_fno-assume-sane-operator-new"><b>-fno-assume-sane-operator-new</b>:
-Don't assume that the C++'s new operator is sane.</dt>
-<dd>This option tells the compiler to do not assume that C++'s global new
-operator will always return a pointer that does not
-alias any other pointer when the function returns.</dd>
-
-<dt id="opt_ftrap-function"><b>-ftrap-function=[name]</b>: Instruct code
-generator to emit a function call to the specified function name for
-<tt>__builtin_trap()</tt>.</dt>
-
-<dd>LLVM code generator translates <tt>__builtin_trap()</tt> to a trap
-instruction if it is supported by the target ISA. Otherwise, the builtin is
-translated into a call to <tt>abort</tt>. If this option is set, then the code
-generator will always lower the builtin to a call to the specified function
-regardless of whether the target ISA has a trap instruction. This option is
-useful for environments (e.g. deeply embedded) where a trap cannot be properly
-handled, or when some custom behavior is desired.</dd>
-
-<dt id="opt_ftls-model"><b>-ftls-model=[model]</b>: Select which TLS model to
-use.</dt>
-<dd>Valid values are: <tt>global-dynamic</tt>, <tt>local-dynamic</tt>,
-<tt>initial-exec</tt> and <tt>local-exec</tt>. The default value is
-<tt>global-dynamic</tt>. The compiler may use a different model if the selected
-model is not supported by the target, or if a more efficient model can be used.
-The TLS model can be overridden per variable using the <tt>tls_model</tt>
-attribute.
-</dd>
-</dl>
-
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-<h3 id="debuginfosize">Controlling Size of Debug Information</h3>
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-
-<p>Debug info kind generated by Clang can be set by one of the flags listed
-below. If multiple flags are present, the last one is used.</p>
-
-<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
-<dl>
-<dt id="opt_g0"><b>-g0</b>: Don't generate any debug info (default).
-
-<dt id="opt_gline-tables-only"><b>-gline-tables-only</b>:
-Generate line number tables only.
-<dd>
-This kind of debug info allows to obtain stack traces with function
-names, file names and line numbers (by such tools as
-gdb or addr2line). It doesn't contain any other data (e.g.
-description of local variables or function parameters).
-</dd>
-
-<dt id="opt_g"><b>-g</b>: Generate complete debug info.
-</dl>
-
-<!-- ======================================================================= -->
-<h2 id="c">C Language Features</h2>
-<!-- ======================================================================= -->
-
-<p>The support for standard C in clang is feature-complete except for the C99
-floating-point pragmas.</p>
-
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-<h3 id="c_ext">Extensions supported by clang</h3>
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-
-<p>See <a href="LanguageExtensions.html">clang language extensions</a>.</p>
-
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-<h3 id="c_modes">Differences between various standard modes</h3>
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-
-<p>clang supports the -std option, which changes what language mode clang uses.
-The supported modes for C are c89, gnu89, c94, c99, gnu99 and various aliases
-for those modes. If no -std option is specified, clang defaults to gnu99 mode.
-</p>
-
-<p>Differences between all c* and gnu* modes:</p>
-<ul>
-<li>c* modes define "__STRICT_ANSI__".</li>
-<li>Target-specific defines not prefixed by underscores, like "linux", are
-defined in gnu* modes.</li>
-<li>Trigraphs default to being off in gnu* modes; they can be enabled by the
--trigraphs option.</li>
-<li>The parser recognizes "asm" and "typeof" as keywords in gnu* modes; the
-variants "__asm__" and "__typeof__" are recognized in all modes.</li>
-<li>The Apple "blocks" extension is recognized by default in gnu* modes
-on some platforms; it can be enabled in any mode with the "-fblocks"
-option.</li>
-<li>Arrays that are VLA's according to the standard, but which can be constant
- folded by the frontend are treated as fixed size arrays. This occurs for
- things like "int X[(1, 2)];", which is technically a VLA. c* modes are
- strictly compliant and treat these as VLAs.</li>
-</ul>
-
-<p>Differences between *89 and *99 modes:</p>
-<ul>
-<li>The *99 modes default to implementing "inline" as specified in C99, while
-the *89 modes implement the GNU version. This can be overridden for individual
-functions with the __gnu_inline__ attribute.</li>
-<li>Digraphs are not recognized in c89 mode.</li>
-<li>The scope of names defined inside a "for", "if", "switch", "while", or "do"
-statement is different. (example: "if ((struct x {int x;}*)0) {}".)</li>
-<li>__STDC_VERSION__ is not defined in *89 modes.</li>
-<li>"inline" is not recognized as a keyword in c89 mode.</li>
-<li>"restrict" is not recognized as a keyword in *89 modes.</li>
-<li>Commas are allowed in integer constant expressions in *99 modes.</li>
-<li>Arrays which are not lvalues are not implicitly promoted to pointers in
-*89 modes.</li>
-<li>Some warnings are different.</li>
-</ul>
-
-<p>c94 mode is identical to c89 mode except that digraphs are enabled in
-c94 mode (FIXME: And __STDC_VERSION__ should be defined!).</p>
-
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-<h3 id="c_unimpl_gcc">GCC extensions not implemented yet</h3>
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-
-<p>clang tries to be compatible with gcc as much as possible, but some gcc
-extensions are not implemented yet:</p>
-
-<ul>
-
-<li>clang does not support #pragma weak
-(<a href="http://llvm.org/bugs/show_bug.cgi?id=3679">bug 3679</a>). Due to
-the uses described in the bug, this is likely to be implemented at some
-point, at least partially.</li>
-
-<li>clang does not support decimal floating point types (_Decimal32 and
-friends) or fixed-point types (_Fract and friends); nobody has expressed
-interest in these features yet, so it's hard to say when they will be
-implemented.</li>
-
-<li>clang does not support nested functions; this is a complex feature which
-is infrequently used, so it is unlikely to be implemented anytime soon. In C++11
-it can be emulated by assigning lambda functions to local variables, e.g:
-<pre>
- auto const local_function = [&](int parameter) {
- // Do something
- };
- ...
- local_function(1);
-</pre>
-</li>
-
-<li>clang does not support global register variables; this is unlikely
-to be implemented soon because it requires additional LLVM backend support.
-</li>
-
-<li>clang does not support static initialization of flexible array
-members. This appears to be a rarely used extension, but could be
-implemented pending user demand.</li>
-
-<li>clang does not support __builtin_va_arg_pack/__builtin_va_arg_pack_len.
-This is used rarely, but in some potentially interesting places, like the
-glibc headers, so it may be implemented pending user demand. Note that
-because clang pretends to be like GCC 4.2, and this extension was introduced
-in 4.3, the glibc headers will not try to use this extension with clang at
-the moment.</li>
-
-<li>clang does not support the gcc extension for forward-declaring function
-parameters; this has not shown up in any real-world code yet, though, so it
-might never be implemented.</li>
-
-</ul>
-
-<p>This is not a complete list; if you find an unsupported extension
-missing from this list, please send an e-mail to cfe-dev. This list
-currently excludes C++; see <a href="#cxx">C++ Language Features</a>.
-Also, this list does not include bugs in mostly-implemented features; please
-see the <a href="http://llvm.org/bugs/buglist.cgi?quicksearch=product%3Aclang+component%3A-New%2BBugs%2CAST%2CBasic%2CDriver%2CHeaders%2CLLVM%2BCodeGen%2Cparser%2Cpreprocessor%2CSemantic%2BAnalyzer">
-bug tracker</a> for known existing bugs (FIXME: Is there a section for
-bug-reporting guidelines somewhere?).</p>
-
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-<h3 id="c_unsupp_gcc">Intentionally unsupported GCC extensions</h3>
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-
-<ul>
-
-<li>clang does not support the gcc extension that allows variable-length arrays
-in structures. This is for a few reasons: one, it is tricky
-to implement, two, the extension is completely undocumented, and three, the
-extension appears to be rarely used. Note that clang <em>does</em> support
-flexible array members (arrays with a zero or unspecified size at the end of
-a structure).</li>
-
-<li>clang does not have an equivalent to gcc's "fold"; this means that
-clang doesn't accept some constructs gcc might accept in contexts where a
-constant expression is required, like "x-x" where x is a variable.</li>
-
-<li>clang does not support __builtin_apply and friends; this extension is
-extremely obscure and difficult to implement reliably.</li>
-
-</ul>
-
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-<h3 id="c_ms">Microsoft extensions</h3>
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-
-<p>clang has some experimental support for extensions from
-Microsoft Visual C++; to enable it, use the -fms-extensions command-line
-option. This is the default for Windows targets. Note that the
-support is incomplete; enabling Microsoft extensions will silently drop
-certain constructs (including __declspec and Microsoft-style asm statements).
-</p>
-
-<p>clang has a -fms-compatibility flag that makes clang accept enough
-invalid C++ to be able to parse most Microsoft headers. This flag is enabled by
-default for Windows targets.</p>
-
-<p>-fdelayed-template-parsing lets clang delay all template instantiation until
-the end of a translation unit. This flag is enabled by default for Windows
-targets.</p>
-
-<ul>
-<li>clang allows setting _MSC_VER with -fmsc-version=. It defaults to 1300 which
-is the same as Visual C/C++ 2003. Any number is supported and can greatly affect
-what Windows SDK and c++stdlib headers clang can compile. This option will be
-removed when clang supports the full set of MS extensions required for these
-headers.</li>
-
-<li>clang does not support the Microsoft extension where anonymous
-record members can be declared using user defined typedefs.</li>
-
-<li>clang supports the Microsoft "#pragma pack" feature for
-controlling record layout. GCC also contains support for this feature,
-however where MSVC and GCC are incompatible clang follows the MSVC
-definition.</li>
-
-<li>clang defaults to C++11 for Windows targets.</li>
-</ul>
-
-<!-- ======================================================================= -->
-<h2 id="cxx">C++ Language Features</h2>
-<!-- ======================================================================= -->
-
-<p>clang fully implements all of standard C++98 except for exported templates
-(which were removed in C++11), and
-<a href="http://clang.llvm.org/cxx_status.html">many C++11 features</a> are also
-implemented.</p>
-
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-<h3 id="cxx_implimits">Controlling implementation limits</h3>
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-
-<p><b>-fconstexpr-depth=N</b>: Sets the limit for recursive constexpr function
-invocations to N. The default is 512.</p>
-
-<p><b>-ftemplate-depth=N</b>: Sets the limit for recursively nested template
-instantiations to N. The default is 1024.</p>
-
-<!-- ======================================================================= -->
-<h2 id="target_features">Target-Specific Features and Limitations</h2>
-<!-- ======================================================================= -->
-
-
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-<h3 id="target_arch">CPU Architectures Features and Limitations</h3>
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-
-<!-- ======================== -->
-<h4 id="target_arch_x86">X86</h4>
-<!-- ======================== -->
-
-<p>The support for X86 (both 32-bit and 64-bit) is considered stable on Darwin
-(Mac OS/X), Linux, FreeBSD, and Dragonfly BSD: it has been tested to correctly
-compile many large C, C++, Objective-C, and Objective-C++ codebases.</p>
-
-<p>On x86_64-mingw32, passing i128(by value) is incompatible to Microsoft x64
-calling conversion. You might need to tweak WinX86_64ABIInfo::classify()
-in lib/CodeGen/TargetInfo.cpp.</p>
-
-<!-- ======================== -->
-<h4 id="target_arch_arm">ARM</h4>
-<!-- ======================== -->
-
-<p>The support for ARM (specifically ARMv6 and ARMv7) is considered stable on
-Darwin (iOS): it has been tested to correctly compile many large C, C++,
-Objective-C, and Objective-C++ codebases. Clang only supports a limited number
-of ARM architectures. It does not yet fully support ARMv5, for example.</p>
-
-<!-- ======================== -->
-<h4 id="target_arch_other">Other platforms</h4>
-<!-- ======================== -->
-clang currently contains some support for PPC and Sparc; however, significant
-pieces of code generation are still missing, and they haven't undergone
-significant testing.
-
-<p>clang contains limited support for the MSP430 embedded processor, but both
-the clang support and the LLVM backend support are highly experimental.
-
-<p>Other platforms are completely unsupported at the moment. Adding the
-minimal support needed for parsing and semantic analysis on a new platform
-is quite easy; see lib/Basic/Targets.cpp in the clang source tree. This level
-of support is also sufficient for conversion to LLVM IR for simple programs.
-Proper support for conversion to LLVM IR requires adding code to
-lib/CodeGen/CGCall.cpp at the moment; this is likely to change soon, though.
-Generating assembly requires a suitable LLVM backend.
-
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-<h3 id="target_os">Operating System Features and Limitations</h3>
-<!-- = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = -->
-
-<!-- ======================================= -->
-<h4 id="target_os_darwin">Darwin (Mac OS/X)</h4>
-<!-- ======================================= -->
-
-<p>None</p>
-
-<!-- ======================================= -->
-<h4 id="target_os_win32">Windows</h4>
-<!-- ======================================= -->
-
-<p>Experimental supports are on Cygming.</p>
-
-<p>See also <a href="#c_ms">Microsoft Extensions</a>.</p>
-
-<h5>Cygwin</h5>
-
-<p>Clang works on Cygwin-1.7.</p>
-
-<h5>MinGW32</h5>
-
-<p>Clang works on some mingw32 distributions.
-Clang assumes directories as below;</p>
-
-<ul>
-<li><tt>C:/mingw/include</tt></li>
-<li><tt>C:/mingw/lib</tt></li>
-<li><tt>C:/mingw/lib/gcc/mingw32/4.[3-5].0/include/c++</tt></li>
-</ul>
-
-<p>On MSYS, a few tests might fail.</p>
-
-<h5>MinGW-w64</h5>
-
-<p>For 32-bit (i686-w64-mingw32), and 64-bit (x86_64-w64-mingw32), Clang assumes as below;<p>
-
-<ul>
-<li><tt>GCC versions 4.5.0 to 4.5.3, 4.6.0 to 4.6.2, or 4.7.0 (for the C++ header search path)</tt></li>
-<li><tt>some_directory/bin/gcc.exe</tt></li>
-<li><tt>some_directory/bin/clang.exe</tt></li>
-<li><tt>some_directory/bin/clang++.exe</tt></li>
-<li><tt>some_directory/bin/../include/c++/GCC_version</tt></li>
-<li><tt>some_directory/bin/../include/c++/GCC_version/x86_64-w64-mingw32</tt></li>
-<li><tt>some_directory/bin/../include/c++/GCC_version/i686-w64-mingw32</tt></li>
-<li><tt>some_directory/bin/../include/c++/GCC_version/backward</tt></li>
-<li><tt>some_directory/bin/../x86_64-w64-mingw32/include</tt></li>
-<li><tt>some_directory/bin/../i686-w64-mingw32/include</tt></li>
-<li><tt>some_directory/bin/../include</tt></li>
-</ul>
-
-<p>This directory layout is standard for any toolchain you will find on the official <a href="http://mingw-w64.sourceforge.net">MinGW-w64 website</a>.
-
-<p>Clang expects the GCC executable &quot;gcc.exe&quot; compiled for i686-w64-mingw32 (or x86_64-w64-mingw32) to be present on PATH.</p>
-
-<p><a href="http://llvm.org/bugs/show_bug.cgi?id=9072">Some tests might fail</a>
-on x86_64-w64-mingw32.</p>
-
-</div>
-</body>
-</html>
diff --git a/docs/UsersManual.rst b/docs/UsersManual.rst
new file mode 100644
index 0000000..6cc8361
--- /dev/null
+++ b/docs/UsersManual.rst
@@ -0,0 +1,1313 @@
+============================
+Clang Compiler User's Manual
+============================
+
+.. contents::
+ :local:
+
+Introduction
+============
+
+The Clang Compiler is an open-source compiler for the C family of
+programming languages, aiming to be the best in class implementation of
+these languages. Clang builds on the LLVM optimizer and code generator,
+allowing it to provide high-quality optimization and code generation
+support for many targets. For more general information, please see the
+`Clang Web Site <http://clang.llvm.org>`_ or the `LLVM Web
+Site <http://llvm.org>`_.
+
+This document describes important notes about using Clang as a compiler
+for an end-user, documenting the supported features, command line
+options, etc. If you are interested in using Clang to build a tool that
+processes code, please see :doc:`InternalsManual`. If you are interested in the
+`Clang Static Analyzer <http://clang-analyzer.llvm.org>`_, please see its web
+page.
+
+Clang is designed to support the C family of programming languages,
+which includes :ref:`C <c>`, :ref:`Objective-C <objc>`, :ref:`C++ <cxx>`, and
+:ref:`Objective-C++ <objcxx>` as well as many dialects of those. For
+language-specific information, please see the corresponding language
+specific section:
+
+- :ref:`C Language <c>`: K&R C, ANSI C89, ISO C90, ISO C94 (C89+AMD1), ISO
+ C99 (+TC1, TC2, TC3).
+- :ref:`Objective-C Language <objc>`: ObjC 1, ObjC 2, ObjC 2.1, plus
+ variants depending on base language.
+- :ref:`C++ Language <cxx>`
+- :ref:`Objective C++ Language <objcxx>`
+
+In addition to these base languages and their dialects, Clang supports a
+broad variety of language extensions, which are documented in the
+corresponding language section. These extensions are provided to be
+compatible with the GCC, Microsoft, and other popular compilers as well
+as to improve functionality through Clang-specific features. The Clang
+driver and language features are intentionally designed to be as
+compatible with the GNU GCC compiler as reasonably possible, easing
+migration from GCC to Clang. In most cases, code "just works".
+
+In addition to language specific features, Clang has a variety of
+features that depend on what CPU architecture or operating system is
+being compiled for. Please see the :ref:`Target-Specific Features and
+Limitations <target_features>` section for more details.
+
+The rest of the introduction introduces some basic :ref:`compiler
+terminology <terminology>` that is used throughout this manual and
+contains a basic :ref:`introduction to using Clang <basicusage>` as a
+command line compiler.
+
+.. _terminology:
+
+Terminology
+-----------
+
+Front end, parser, backend, preprocessor, undefined behavior,
+diagnostic, optimizer
+
+.. _basicusage:
+
+Basic Usage
+-----------
+
+Intro to how to use a C compiler for newbies.
+
+compile + link compile then link debug info enabling optimizations
+picking a language to use, defaults to C99 by default. Autosenses based
+on extension. using a makefile
+
+Command Line Options
+====================
+
+This section is generally an index into other sections. It does not go
+into depth on the ones that are covered by other sections. However, the
+first part introduces the language selection and other high level
+options like :option:`-c`, :option:`-g`, etc.
+
+Options to Control Error and Warning Messages
+---------------------------------------------
+
+.. option:: -Werror
+
+ Turn warnings into errors.
+
+.. This is in plain monospaced font because it generates the same label as
+.. -Werror, and Sphinx complains.
+
+``-Werror=foo``
+
+ Turn warning "foo" into an error.
+
+.. option:: -Wno-error=foo
+
+ Turn warning "foo" into an warning even if :option:`-Werror` is specified.
+
+.. option:: -Wfoo
+
+ Enable warning "foo".
+
+.. option:: -Wno-foo
+
+ Disable warning "foo".
+
+.. option:: -w
+
+ Disable all warnings.
+
+.. option:: -Weverything
+
+ :ref:`Enable all warnings. <diagnostics_enable_everything>`
+
+.. option:: -pedantic
+
+ Warn on language extensions.
+
+.. option:: -pedantic-errors
+
+ Error on language extensions.
+
+.. option:: -Wsystem-headers
+
+ Enable warnings from system headers.
+
+.. option:: -ferror-limit=123
+
+ Stop emitting diagnostics after 123 errors have been produced. The default is
+ 20, and the error limit can be disabled with :option:`-ferror-limit=0`.
+
+.. option:: -ftemplate-backtrace-limit=123
+
+ Only emit up to 123 template instantiation notes within the template
+ instantiation backtrace for a single warning or error. The default is 10, and
+ the limit can be disabled with :option:`-ftemplate-backtrace-limit=0`.
+
+.. _cl_diag_formatting:
+
+Formatting of Diagnostics
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Clang aims to produce beautiful diagnostics by default, particularly for
+new users that first come to Clang. However, different people have
+different preferences, and sometimes Clang is driven by another program
+that wants to parse simple and consistent output, not a person. For
+these cases, Clang provides a wide range of options to control the exact
+output format of the diagnostics that it generates.
+
+.. _opt_fshow-column:
+
+**-f[no-]show-column**
+ Print column number in diagnostic.
+
+ This option, which defaults to on, controls whether or not Clang
+ prints the column number of a diagnostic. For example, when this is
+ enabled, Clang will print something like:
+
+ ::
+
+ test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
+ #endif bad
+ ^
+ //
+
+ When this is disabled, Clang will print "test.c:28: warning..." with
+ no column number.
+
+ The printed column numbers count bytes from the beginning of the
+ line; take care if your source contains multibyte characters.
+
+.. _opt_fshow-source-location:
+
+**-f[no-]show-source-location**
+ Print source file/line/column information in diagnostic.
+
+ This option, which defaults to on, controls whether or not Clang
+ prints the filename, line number and column number of a diagnostic.
+ For example, when this is enabled, Clang will print something like:
+
+ ::
+
+ test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
+ #endif bad
+ ^
+ //
+
+ When this is disabled, Clang will not print the "test.c:28:8: "
+ part.
+
+.. _opt_fcaret-diagnostics:
+
+**-f[no-]caret-diagnostics**
+ Print source line and ranges from source code in diagnostic.
+ This option, which defaults to on, controls whether or not Clang
+ prints the source line, source ranges, and caret when emitting a
+ diagnostic. For example, when this is enabled, Clang will print
+ something like:
+
+ ::
+
+ test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
+ #endif bad
+ ^
+ //
+
+**-f[no-]color-diagnostics**
+ This option, which defaults to on when a color-capable terminal is
+ detected, controls whether or not Clang prints diagnostics in color.
+
+ When this option is enabled, Clang will use colors to highlight
+ specific parts of the diagnostic, e.g.,
+
+ .. nasty hack to not lose our dignity
+
+ .. raw:: html
+
+ <pre>
+ <b><span style="color:black">test.c:28:8: <span style="color:magenta">warning</span>: extra tokens at end of #endif directive [-Wextra-tokens]</span></b>
+ #endif bad
+ <span style="color:green">^</span>
+ <span style="color:green">//</span>
+ </pre>
+
+ When this is disabled, Clang will just print:
+
+ ::
+
+ test.c:2:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
+ #endif bad
+ ^
+ //
+
+.. option:: -fdiagnostics-format=clang/msvc/vi
+
+ Changes diagnostic output format to better match IDEs and command line tools.
+
+ This option controls the output format of the filename, line number,
+ and column printed in diagnostic messages. The options, and their
+ affect on formatting a simple conversion diagnostic, follow:
+
+ **clang** (default)
+ ::
+
+ t.c:3:11: warning: conversion specifies type 'char *' but the argument has type 'int'
+
+ **msvc**
+ ::
+
+ t.c(3,11) : warning: conversion specifies type 'char *' but the argument has type 'int'
+
+ **vi**
+ ::
+
+ t.c +3:11: warning: conversion specifies type 'char *' but the argument has type 'int'
+
+**-f[no-]diagnostics-show-name**
+ Enable the display of the diagnostic name.
+ This option, which defaults to off, controls whether or not Clang
+ prints the associated name.
+
+.. _opt_fdiagnostics-show-option:
+
+**-f[no-]diagnostics-show-option**
+ Enable ``[-Woption]`` information in diagnostic line.
+
+ This option, which defaults to on, controls whether or not Clang
+ prints the associated :ref:`warning group <cl_diag_warning_groups>`
+ option name when outputting a warning diagnostic. For example, in
+ this output:
+
+ ::
+
+ test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
+ #endif bad
+ ^
+ //
+
+ Passing **-fno-diagnostics-show-option** will prevent Clang from
+ printing the [:ref:`-Wextra-tokens <opt_Wextra-tokens>`] information in
+ the diagnostic. This information tells you the flag needed to enable
+ or disable the diagnostic, either from the command line or through
+ :ref:`#pragma GCC diagnostic <pragma_GCC_diagnostic>`.
+
+.. _opt_fdiagnostics-show-category:
+
+.. option:: -fdiagnostics-show-category=none/id/name
+
+ Enable printing category information in diagnostic line.
+
+ This option, which defaults to "none", controls whether or not Clang
+ prints the category associated with a diagnostic when emitting it.
+ Each diagnostic may or many not have an associated category, if it
+ has one, it is listed in the diagnostic categorization field of the
+ diagnostic line (in the []'s).
+
+ For example, a format string warning will produce these three
+ renditions based on the setting of this option:
+
+ ::
+
+ t.c:3:11: warning: conversion specifies type 'char *' but the argument has type 'int' [-Wformat]
+ t.c:3:11: warning: conversion specifies type 'char *' but the argument has type 'int' [-Wformat,1]
+ t.c:3:11: warning: conversion specifies type 'char *' but the argument has type 'int' [-Wformat,Format String]
+
+ This category can be used by clients that want to group diagnostics
+ by category, so it should be a high level category. We want dozens
+ of these, not hundreds or thousands of them.
+
+.. _opt_fdiagnostics-fixit-info:
+
+**-f[no-]diagnostics-fixit-info**
+ Enable "FixIt" information in the diagnostics output.
+
+ This option, which defaults to on, controls whether or not Clang
+ prints the information on how to fix a specific diagnostic
+ underneath it when it knows. For example, in this output:
+
+ ::
+
+ test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
+ #endif bad
+ ^
+ //
+
+ Passing **-fno-diagnostics-fixit-info** will prevent Clang from
+ printing the "//" line at the end of the message. This information
+ is useful for users who may not understand what is wrong, but can be
+ confusing for machine parsing.
+
+.. _opt_fdiagnostics-print-source-range-info:
+
+**-fdiagnostics-print-source-range-info**
+ Print machine parsable information about source ranges.
+ This option makes Clang print information about source ranges in a machine
+ parsable format after the file/line/column number information. The
+ information is a simple sequence of brace enclosed ranges, where each range
+ lists the start and end line/column locations. For example, in this output:
+
+ ::
+
+ exprs.c:47:15:{47:8-47:14}{47:17-47:24}: error: invalid operands to binary expression ('int *' and '_Complex float')
+ P = (P-42) + Gamma*4;
+ ~~~~~~ ^ ~~~~~~~
+
+ The {}'s are generated by -fdiagnostics-print-source-range-info.
+
+ The printed column numbers count bytes from the beginning of the
+ line; take care if your source contains multibyte characters.
+
+.. option:: -fdiagnostics-parseable-fixits
+
+ Print Fix-Its in a machine parseable form.
+
+ This option makes Clang print available Fix-Its in a machine
+ parseable format at the end of diagnostics. The following example
+ illustrates the format:
+
+ ::
+
+ fix-it:"t.cpp":{7:25-7:29}:"Gamma"
+
+ The range printed is a half-open range, so in this example the
+ characters at column 25 up to but not including column 29 on line 7
+ in t.cpp should be replaced with the string "Gamma". Either the
+ range or the replacement string may be empty (representing strict
+ insertions and strict erasures, respectively). Both the file name
+ and the insertion string escape backslash (as "\\\\"), tabs (as
+ "\\t"), newlines (as "\\n"), double quotes(as "\\"") and
+ non-printable characters (as octal "\\xxx").
+
+ The printed column numbers count bytes from the beginning of the
+ line; take care if your source contains multibyte characters.
+
+.. option:: -fno-elide-type
+
+ Turns off elision in template type printing.
+
+ The default for template type printing is to elide as many template
+ arguments as possible, removing those which are the same in both
+ template types, leaving only the differences. Adding this flag will
+ print all the template arguments. If supported by the terminal,
+ highlighting will still appear on differing arguments.
+
+ Default:
+
+ ::
+
+ t.cc:4:5: note: candidate function not viable: no known conversion from 'vector<map<[...], map<float, [...]>>>' to 'vector<map<[...], map<double, [...]>>>' for 1st argument;
+
+ -fno-elide-type:
+
+ ::
+
+ t.cc:4:5: note: candidate function not viable: no known conversion from 'vector<map<int, map<float, int>>>' to 'vector<map<int, map<double, int>>>' for 1st argument;
+
+.. option:: -fdiagnostics-show-template-tree
+
+ Template type diffing prints a text tree.
+
+ For diffing large templated types, this option will cause Clang to
+ display the templates as an indented text tree, one argument per
+ line, with differences marked inline. This is compatible with
+ -fno-elide-type.
+
+ Default:
+
+ ::
+
+ t.cc:4:5: note: candidate function not viable: no known conversion from 'vector<map<[...], map<float, [...]>>>' to 'vector<map<[...], map<double, [...]>>>' for 1st argument;
+
+ With :option:`-fdiagnostics-show-template-tree`:
+
+ ::
+
+ t.cc:4:5: note: candidate function not viable: no known conversion for 1st argument;
+ vector<
+ map<
+ [...],
+ map<
+ [float != float],
+ [...]>>>
+
+.. _cl_diag_warning_groups:
+
+Individual Warning Groups
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+TODO: Generate this from tblgen. Define one anchor per warning group.
+
+.. _opt_wextra-tokens:
+
+.. option:: -Wextra-tokens
+
+ Warn about excess tokens at the end of a preprocessor directive.
+
+ This option, which defaults to on, enables warnings about extra
+ tokens at the end of preprocessor directives. For example:
+
+ ::
+
+ test.c:28:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]
+ #endif bad
+ ^
+
+ These extra tokens are not strictly conforming, and are usually best
+ handled by commenting them out.
+
+.. option:: -Wambiguous-member-template
+
+ Warn about unqualified uses of a member template whose name resolves to
+ another template at the location of the use.
+
+ This option, which defaults to on, enables a warning in the
+ following code:
+
+ ::
+
+ template<typename T> struct set{};
+ template<typename T> struct trait { typedef const T& type; };
+ struct Value {
+ template<typename T> void set(typename trait<T>::type value) {}
+ };
+ void foo() {
+ Value v;
+ v.set<double>(3.2);
+ }
+
+ C++ [basic.lookup.classref] requires this to be an error, but,
+ because it's hard to work around, Clang downgrades it to a warning
+ as an extension.
+
+.. option:: -Wbind-to-temporary-copy
+
+ Warn about an unusable copy constructor when binding a reference to a
+ temporary.
+
+ This option, which defaults to on, enables warnings about binding a
+ reference to a temporary when the temporary doesn't have a usable
+ copy constructor. For example:
+
+ ::
+
+ struct NonCopyable {
+ NonCopyable();
+ private:
+ NonCopyable(const NonCopyable&);
+ };
+ void foo(const NonCopyable&);
+ void bar() {
+ foo(NonCopyable()); // Disallowed in C++98; allowed in C++11.
+ }
+
+ ::
+
+ struct NonCopyable2 {
+ NonCopyable2();
+ NonCopyable2(NonCopyable2&);
+ };
+ void foo(const NonCopyable2&);
+ void bar() {
+ foo(NonCopyable2()); // Disallowed in C++98; allowed in C++11.
+ }
+
+ Note that if ``NonCopyable2::NonCopyable2()`` has a default argument
+ whose instantiation produces a compile error, that error will still
+ be a hard error in C++98 mode even if this warning is turned off.
+
+Options to Control Clang Crash Diagnostics
+------------------------------------------
+
+As unbelievable as it may sound, Clang does crash from time to time.
+Generally, this only occurs to those living on the `bleeding
+edge <http://llvm.org/releases/download.html#svn>`_. Clang goes to great
+lengths to assist you in filing a bug report. Specifically, Clang
+generates preprocessed source file(s) and associated run script(s) upon
+a crash. These files should be attached to a bug report to ease
+reproducibility of the failure. Below are the command line options to
+control the crash diagnostics.
+
+.. option:: -fno-crash-diagnostics
+
+ Disable auto-generation of preprocessed source files during a clang crash.
+
+The -fno-crash-diagnostics flag can be helpful for speeding the process
+of generating a delta reduced test case.
+
+Language and Target-Independent Features
+========================================
+
+Controlling Errors and Warnings
+-------------------------------
+
+Clang provides a number of ways to control which code constructs cause
+it to emit errors and warning messages, and how they are displayed to
+the console.
+
+Controlling How Clang Displays Diagnostics
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When Clang emits a diagnostic, it includes rich information in the
+output, and gives you fine-grain control over which information is
+printed. Clang has the ability to print this information, and these are
+the options that control it:
+
+#. A file/line/column indicator that shows exactly where the diagnostic
+ occurs in your code [:ref:`-fshow-column <opt_fshow-column>`,
+ :ref:`-fshow-source-location <opt_fshow-source-location>`].
+#. A categorization of the diagnostic as a note, warning, error, or
+ fatal error.
+#. A text string that describes what the problem is.
+#. An option that indicates how to control the diagnostic (for
+ diagnostics that support it)
+ [:ref:`-fdiagnostics-show-option <opt_fdiagnostics-show-option>`].
+#. A :ref:`high-level category <diagnostics_categories>` for the diagnostic
+ for clients that want to group diagnostics by class (for diagnostics
+ that support it)
+ [:ref:`-fdiagnostics-show-category <opt_fdiagnostics-show-category>`].
+#. The line of source code that the issue occurs on, along with a caret
+ and ranges that indicate the important locations
+ [:ref:`-fcaret-diagnostics <opt_fcaret-diagnostics>`].
+#. "FixIt" information, which is a concise explanation of how to fix the
+ problem (when Clang is certain it knows)
+ [:ref:`-fdiagnostics-fixit-info <opt_fdiagnostics-fixit-info>`].
+#. A machine-parsable representation of the ranges involved (off by
+ default)
+ [:ref:`-fdiagnostics-print-source-range-info <opt_fdiagnostics-print-source-range-info>`].
+
+For more information please see :ref:`Formatting of
+Diagnostics <cl_diag_formatting>`.
+
+Diagnostic Mappings
+^^^^^^^^^^^^^^^^^^^
+
+All diagnostics are mapped into one of these 5 classes:
+
+- Ignored
+- Note
+- Warning
+- Error
+- Fatal
+
+.. _diagnostics_categories:
+
+Diagnostic Categories
+^^^^^^^^^^^^^^^^^^^^^
+
+Though not shown by default, diagnostics may each be associated with a
+high-level category. This category is intended to make it possible to
+triage builds that produce a large number of errors or warnings in a
+grouped way.
+
+Categories are not shown by default, but they can be turned on with the
+:ref:`-fdiagnostics-show-category <opt_fdiagnostics-show-category>` option.
+When set to "``name``", the category is printed textually in the
+diagnostic output. When it is set to "``id``", a category number is
+printed. The mapping of category names to category id's can be obtained
+by running '``clang --print-diagnostic-categories``'.
+
+Controlling Diagnostics via Command Line Flags
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+TODO: -W flags, -pedantic, etc
+
+.. _pragma_gcc_diagnostic:
+
+Controlling Diagnostics via Pragmas
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Clang can also control what diagnostics are enabled through the use of
+pragmas in the source code. This is useful for turning off specific
+warnings in a section of source code. Clang supports GCC's pragma for
+compatibility with existing source code, as well as several extensions.
+
+The pragma may control any warning that can be used from the command
+line. Warnings may be set to ignored, warning, error, or fatal. The
+following example code will tell Clang or GCC to ignore the -Wall
+warnings:
+
+.. code-block:: c
+
+ #pragma GCC diagnostic ignored "-Wall"
+
+In addition to all of the functionality provided by GCC's pragma, Clang
+also allows you to push and pop the current warning state. This is
+particularly useful when writing a header file that will be compiled by
+other people, because you don't know what warning flags they build with.
+
+In the below example :option:`-Wmultichar` is ignored for only a single line of
+code, after which the diagnostics return to whatever state had previously
+existed.
+
+.. code-block:: c
+
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wmultichar"
+
+ char b = 'df'; // no warning.
+
+ #pragma clang diagnostic pop
+
+The push and pop pragmas will save and restore the full diagnostic state
+of the compiler, regardless of how it was set. That means that it is
+possible to use push and pop around GCC compatible diagnostics and Clang
+will push and pop them appropriately, while GCC will ignore the pushes
+and pops as unknown pragmas. It should be noted that while Clang
+supports the GCC pragma, Clang and GCC do not support the exact same set
+of warnings, so even when using GCC compatible #pragmas there is no
+guarantee that they will have identical behaviour on both compilers.
+
+Controlling Diagnostics in System Headers
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Warnings are suppressed when they occur in system headers. By default,
+an included file is treated as a system header if it is found in an
+include path specified by ``-isystem``, but this can be overridden in
+several ways.
+
+The ``system_header`` pragma can be used to mark the current file as
+being a system header. No warnings will be produced from the location of
+the pragma onwards within the same file.
+
+.. code-block:: c
+
+ char a = 'xy'; // warning
+
+ #pragma clang system_header
+
+ char b = 'ab'; // no warning
+
+The :option:`-isystem-prefix` and :option:`-ino-system-prefix` command-line
+arguments can be used to override whether subsets of an include path are
+treated as system headers. When the name in a ``#include`` directive is
+found within a header search path and starts with a system prefix, the
+header is treated as a system header. The last prefix on the
+command-line which matches the specified header name takes precedence.
+For instance:
+
+.. code-block:: console
+
+ $ clang -Ifoo -isystem bar -isystem-prefix x/ -ino-system-prefix x/y/
+
+Here, ``#include "x/a.h"`` is treated as including a system header, even
+if the header is found in ``foo``, and ``#include "x/y/b.h"`` is treated
+as not including a system header, even if the header is found in
+``bar``.
+
+A ``#include`` directive which finds a file relative to the current
+directory is treated as including a system header if the including file
+is treated as a system header.
+
+.. _diagnostics_enable_everything:
+
+Enabling All Warnings
+^^^^^^^^^^^^^^^^^^^^^
+
+In addition to the traditional ``-W`` flags, one can enable **all**
+warnings by passing :option:`-Weverything`. This works as expected with
+:option:`-Werror`, and also includes the warnings from :option:`-pedantic`.
+
+Note that when combined with :option:`-w` (which disables all warnings), that
+flag wins.
+
+Controlling Static Analyzer Diagnostics
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+While not strictly part of the compiler, the diagnostics from Clang's
+`static analyzer <http://clang-analyzer.llvm.org>`_ can also be
+influenced by the user via changes to the source code. See the available
+`annotations <http://clang-analyzer.llvm.org/annotations.html>`_ and the
+analyzer's `FAQ
+page <http://clang-analyzer.llvm.org/faq.html#exclude_code>`_ for more
+information.
+
+.. _usersmanual-precompiled-headers:
+
+Precompiled Headers
+-------------------
+
+`Precompiled headers <http://en.wikipedia.org/wiki/Precompiled_header>`__
+are a general approach employed by many compilers to reduce compilation
+time. The underlying motivation of the approach is that it is common for
+the same (and often large) header files to be included by multiple
+source files. Consequently, compile times can often be greatly improved
+by caching some of the (redundant) work done by a compiler to process
+headers. Precompiled header files, which represent one of many ways to
+implement this optimization, are literally files that represent an
+on-disk cache that contains the vital information necessary to reduce
+some of the work needed to process a corresponding header file. While
+details of precompiled headers vary between compilers, precompiled
+headers have been shown to be highly effective at speeding up program
+compilation on systems with very large system headers (e.g., Mac OS/X).
+
+Generating a PCH File
+^^^^^^^^^^^^^^^^^^^^^
+
+To generate a PCH file using Clang, one invokes Clang with the
+:option:`-x <language>-header` option. This mirrors the interface in GCC
+for generating PCH files:
+
+.. code-block:: console
+
+ $ gcc -x c-header test.h -o test.h.gch
+ $ clang -x c-header test.h -o test.h.pch
+
+Using a PCH File
+^^^^^^^^^^^^^^^^
+
+A PCH file can then be used as a prefix header when a :option:`-include`
+option is passed to ``clang``:
+
+.. code-block:: console
+
+ $ clang -include test.h test.c -o test
+
+The ``clang`` driver will first check if a PCH file for ``test.h`` is
+available; if so, the contents of ``test.h`` (and the files it includes)
+will be processed from the PCH file. Otherwise, Clang falls back to
+directly processing the content of ``test.h``. This mirrors the behavior
+of GCC.
+
+.. note::
+
+ Clang does *not* automatically use PCH files for headers that are directly
+ included within a source file. For example:
+
+ .. code-block:: console
+
+ $ clang -x c-header test.h -o test.h.pch
+ $ cat test.c
+ #include "test.h"
+ $ clang test.c -o test
+
+ In this example, ``clang`` will not automatically use the PCH file for
+ ``test.h`` since ``test.h`` was included directly in the source file and not
+ specified on the command line using :option:`-include`.
+
+Relocatable PCH Files
+^^^^^^^^^^^^^^^^^^^^^
+
+It is sometimes necessary to build a precompiled header from headers
+that are not yet in their final, installed locations. For example, one
+might build a precompiled header within the build tree that is then
+meant to be installed alongside the headers. Clang permits the creation
+of "relocatable" precompiled headers, which are built with a given path
+(into the build directory) and can later be used from an installed
+location.
+
+To build a relocatable precompiled header, place your headers into a
+subdirectory whose structure mimics the installed location. For example,
+if you want to build a precompiled header for the header ``mylib.h``
+that will be installed into ``/usr/include``, create a subdirectory
+``build/usr/include`` and place the header ``mylib.h`` into that
+subdirectory. If ``mylib.h`` depends on other headers, then they can be
+stored within ``build/usr/include`` in a way that mimics the installed
+location.
+
+Building a relocatable precompiled header requires two additional
+arguments. First, pass the ``--relocatable-pch`` flag to indicate that
+the resulting PCH file should be relocatable. Second, pass
+:option:`-isysroot /path/to/build`, which makes all includes for your library
+relative to the build directory. For example:
+
+.. code-block:: console
+
+ # clang -x c-header --relocatable-pch -isysroot /path/to/build /path/to/build/mylib.h mylib.h.pch
+
+When loading the relocatable PCH file, the various headers used in the
+PCH file are found from the system header root. For example, ``mylib.h``
+can be found in ``/usr/include/mylib.h``. If the headers are installed
+in some other system root, the :option:`-isysroot` option can be used provide
+a different system root from which the headers will be based. For
+example, :option:`-isysroot /Developer/SDKs/MacOSX10.4u.sdk` will look for
+``mylib.h`` in ``/Developer/SDKs/MacOSX10.4u.sdk/usr/include/mylib.h``.
+
+Relocatable precompiled headers are intended to be used in a limited
+number of cases where the compilation environment is tightly controlled
+and the precompiled header cannot be generated after headers have been
+installed.
+
+Controlling Code Generation
+---------------------------
+
+Clang provides a number of ways to control code generation. The options
+are listed below.
+
+**-fsanitize=check1,check2,...**
+ Turn on runtime checks for various forms of undefined or suspicious
+ behavior.
+
+ This option controls whether Clang adds runtime checks for various
+ forms of undefined or suspicious behavior, and is disabled by
+ default. If a check fails, a diagnostic message is produced at
+ runtime explaining the problem. The main checks are:
+
+ - .. _opt_fsanitize_address:
+
+ ``-fsanitize=address``:
+ :doc:`AddressSanitizer`, a memory error
+ detector.
+ - ``-fsanitize=init-order``: Make AddressSanitizer check for
+ dynamic initialization order problems. Implied by ``-fsanitize=address``.
+ - ``-fsanitize=address-full``: AddressSanitizer with all the
+ experimental features listed below.
+ - ``-fsanitize=integer``: Enables checks for undefined or
+ suspicious integer behavior.
+ - .. _opt_fsanitize_thread:
+
+ ``-fsanitize=thread``: :doc:`ThreadSanitizer`, a data race detector.
+ - .. _opt_fsanitize_memory:
+
+ ``-fsanitize=memory``: :doc:`MemorySanitizer`,
+ an *experimental* detector of uninitialized reads. Not ready for
+ widespread use.
+ - .. _opt_fsanitize_undefined:
+
+ ``-fsanitize=undefined``: Fast and compatible undefined behavior
+ checker. Enables the undefined behavior checks that have small
+ runtime cost and no impact on address space layout or ABI. This
+ includes all of the checks listed below other than
+ ``unsigned-integer-overflow``.
+
+ ``-fsanitize=undefined-trap``: This includes all sanitizers
+ included by ``-fsanitize=undefined``, except those that require
+ runtime support. This group of sanitizers are generally used
+ in conjunction with the ``-fsanitize-undefined-trap-on-error``
+ flag, which causes traps to be emitted, rather than calls to
+ runtime libraries. This includes all of the checks listed below
+ other than ``unsigned-integer-overflow`` and ``vptr``.
+
+ The following more fine-grained checks are also available:
+
+ - ``-fsanitize=alignment``: Use of a misaligned pointer or creation
+ of a misaligned reference.
+ - ``-fsanitize=bool``: Load of a ``bool`` value which is neither
+ ``true`` nor ``false``.
+ - ``-fsanitize=bounds``: Out of bounds array indexing, in cases
+ where the array bound can be statically determined.
+ - ``-fsanitize=enum``: Load of a value of an enumerated type which
+ is not in the range of representable values for that enumerated
+ type.
+ - ``-fsanitize=float-cast-overflow``: Conversion to, from, or
+ between floating-point types which would overflow the
+ destination.
+ - ``-fsanitize=float-divide-by-zero``: Floating point division by
+ zero.
+ - ``-fsanitize=integer-divide-by-zero``: Integer division by zero.
+ - ``-fsanitize=null``: Use of a null pointer or creation of a null
+ reference.
+ - ``-fsanitize=object-size``: An attempt to use bytes which the
+ optimizer can determine are not part of the object being
+ accessed. The sizes of objects are determined using
+ ``__builtin_object_size``, and consequently may be able to detect
+ more problems at higher optimization levels.
+ - ``-fsanitize=return``: In C++, reaching the end of a
+ value-returning function without returning a value.
+ - ``-fsanitize=shift``: Shift operators where the amount shifted is
+ greater or equal to the promoted bit-width of the left hand side
+ or less than zero, or where the left hand side is negative. For a
+ signed left shift, also checks for signed overflow in C, and for
+ unsigned overflow in C++.
+ - ``-fsanitize=signed-integer-overflow``: Signed integer overflow,
+ including all the checks added by ``-ftrapv``, and checking for
+ overflow in signed division (``INT_MIN / -1``).
+ - ``-fsanitize=unreachable``: If control flow reaches
+ ``__builtin_unreachable``.
+ - ``-fsanitize=unsigned-integer-overflow``: Unsigned integer
+ overflows.
+ - ``-fsanitize=vla-bound``: A variable-length array whose bound
+ does not evaluate to a positive value.
+ - ``-fsanitize=vptr``: Use of an object whose vptr indicates that
+ it is of the wrong dynamic type, or that its lifetime has not
+ begun or has ended. Incompatible with ``-fno-rtti``.
+
+ Experimental features of AddressSanitizer (not ready for widespread
+ use, require explicit ``-fsanitize=address``):
+
+ - ``-fsanitize=use-after-return``: Check for use-after-return
+ errors (accessing local variable after the function exit).
+ - ``-fsanitize=use-after-scope``: Check for use-after-scope errors
+ (accesing local variable after it went out of scope).
+
+ Extra features of MemorySanitizer (require explicit
+ ``-fsanitize=memory``):
+
+ - ``-fsanitize-memory-track-origins``: Enables origin tracking in
+ MemorySanitizer. Adds a second section to MemorySanitizer
+ reports pointing to the heap or stack allocation the
+ uninitialized bits came from. Slows down execution by additional
+ 1.5x-2x.
+
+ The ``-fsanitize=`` argument must also be provided when linking, in
+ order to link to the appropriate runtime library. It is not possible
+ to combine the ``-fsanitize=address`` and ``-fsanitize=thread``
+ checkers in the same program.
+**-f[no-]address-sanitizer**
+ Deprecated synonym for :ref:`-f[no-]sanitize=address
+ <opt_fsanitize_address>`.
+**-f[no-]thread-sanitizer**
+ Deprecated synonym for :ref:`-f[no-]sanitize=thread
+ <opt_fsanitize_thread>`.
+
+.. option:: -fcatch-undefined-behavior
+
+ Deprecated synonym for :ref:`-fsanitize=undefined
+ <opt_fsanitize_undefined>`.
+
+.. option:: -fno-assume-sane-operator-new
+
+ Don't assume that the C++'s new operator is sane.
+
+ This option tells the compiler to do not assume that C++'s global
+ new operator will always return a pointer that does not alias any
+ other pointer when the function returns.
+
+.. option:: -ftrap-function=[name]
+
+ Instruct code generator to emit a function call to the specified
+ function name for ``__builtin_trap()``.
+
+ LLVM code generator translates ``__builtin_trap()`` to a trap
+ instruction if it is supported by the target ISA. Otherwise, the
+ builtin is translated into a call to ``abort``. If this option is
+ set, then the code generator will always lower the builtin to a call
+ to the specified function regardless of whether the target ISA has a
+ trap instruction. This option is useful for environments (e.g.
+ deeply embedded) where a trap cannot be properly handled, or when
+ some custom behavior is desired.
+
+.. option:: -ftls-model=[model]
+
+ Select which TLS model to use.
+
+ Valid values are: ``global-dynamic``, ``local-dynamic``,
+ ``initial-exec`` and ``local-exec``. The default value is
+ ``global-dynamic``. The compiler may use a different model if the
+ selected model is not supported by the target, or if a more
+ efficient model can be used. The TLS model can be overridden per
+ variable using the ``tls_model`` attribute.
+
+Controlling Size of Debug Information
+-------------------------------------
+
+Debug info kind generated by Clang can be set by one of the flags listed
+below. If multiple flags are present, the last one is used.
+
+.. option:: -g0
+
+ Don't generate any debug info (default).
+
+.. option:: -gline-tables-only
+
+ Generate line number tables only.
+
+ This kind of debug info allows to obtain stack traces with function names,
+ file names and line numbers (by such tools as ``gdb`` or ``addr2line``). It
+ doesn't contain any other data (e.g. description of local variables or
+ function parameters).
+
+.. option:: -g
+
+ Generate complete debug info.
+
+.. _c:
+
+C Language Features
+===================
+
+The support for standard C in clang is feature-complete except for the
+C99 floating-point pragmas.
+
+Extensions supported by clang
+-----------------------------
+
+See :doc:`LanguageExtensions`.
+
+Differences between various standard modes
+------------------------------------------
+
+clang supports the -std option, which changes what language mode clang
+uses. The supported modes for C are c89, gnu89, c94, c99, gnu99 and
+various aliases for those modes. If no -std option is specified, clang
+defaults to gnu99 mode.
+
+Differences between all ``c*`` and ``gnu*`` modes:
+
+- ``c*`` modes define "``__STRICT_ANSI__``".
+- Target-specific defines not prefixed by underscores, like "linux",
+ are defined in ``gnu*`` modes.
+- Trigraphs default to being off in ``gnu*`` modes; they can be enabled by
+ the -trigraphs option.
+- The parser recognizes "asm" and "typeof" as keywords in ``gnu*`` modes;
+ the variants "``__asm__``" and "``__typeof__``" are recognized in all
+ modes.
+- The Apple "blocks" extension is recognized by default in ``gnu*`` modes
+ on some platforms; it can be enabled in any mode with the "-fblocks"
+ option.
+- Arrays that are VLA's according to the standard, but which can be
+ constant folded by the frontend are treated as fixed size arrays.
+ This occurs for things like "int X[(1, 2)];", which is technically a
+ VLA. ``c*`` modes are strictly compliant and treat these as VLAs.
+
+Differences between ``*89`` and ``*99`` modes:
+
+- The ``*99`` modes default to implementing "inline" as specified in C99,
+ while the ``*89`` modes implement the GNU version. This can be
+ overridden for individual functions with the ``__gnu_inline__``
+ attribute.
+- Digraphs are not recognized in c89 mode.
+- The scope of names defined inside a "for", "if", "switch", "while",
+ or "do" statement is different. (example: "``if ((struct x {int
+ x;}*)0) {}``".)
+- ``__STDC_VERSION__`` is not defined in ``*89`` modes.
+- "inline" is not recognized as a keyword in c89 mode.
+- "restrict" is not recognized as a keyword in ``*89`` modes.
+- Commas are allowed in integer constant expressions in ``*99`` modes.
+- Arrays which are not lvalues are not implicitly promoted to pointers
+ in ``*89`` modes.
+- Some warnings are different.
+
+c94 mode is identical to c89 mode except that digraphs are enabled in
+c94 mode (FIXME: And ``__STDC_VERSION__`` should be defined!).
+
+GCC extensions not implemented yet
+----------------------------------
+
+clang tries to be compatible with gcc as much as possible, but some gcc
+extensions are not implemented yet:
+
+- clang does not support #pragma weak (`bug
+ 3679 <http://llvm.org/bugs/show_bug.cgi?id=3679>`_). Due to the uses
+ described in the bug, this is likely to be implemented at some point,
+ at least partially.
+- clang does not support decimal floating point types (``_Decimal32`` and
+ friends) or fixed-point types (``_Fract`` and friends); nobody has
+ expressed interest in these features yet, so it's hard to say when
+ they will be implemented.
+- clang does not support nested functions; this is a complex feature
+ which is infrequently used, so it is unlikely to be implemented
+ anytime soon. In C++11 it can be emulated by assigning lambda
+ functions to local variables, e.g:
+
+ .. code-block:: cpp
+
+ auto const local_function = [&](int parameter) {
+ // Do something
+ };
+ ...
+ local_function(1);
+
+- clang does not support global register variables; this is unlikely to
+ be implemented soon because it requires additional LLVM backend
+ support.
+- clang does not support static initialization of flexible array
+ members. This appears to be a rarely used extension, but could be
+ implemented pending user demand.
+- clang does not support
+ ``__builtin_va_arg_pack``/``__builtin_va_arg_pack_len``. This is
+ used rarely, but in some potentially interesting places, like the
+ glibc headers, so it may be implemented pending user demand. Note
+ that because clang pretends to be like GCC 4.2, and this extension
+ was introduced in 4.3, the glibc headers will not try to use this
+ extension with clang at the moment.
+- clang does not support the gcc extension for forward-declaring
+ function parameters; this has not shown up in any real-world code
+ yet, though, so it might never be implemented.
+
+This is not a complete list; if you find an unsupported extension
+missing from this list, please send an e-mail to cfe-dev. This list
+currently excludes C++; see :ref:`C++ Language Features <cxx>`. Also, this
+list does not include bugs in mostly-implemented features; please see
+the `bug
+tracker <http://llvm.org/bugs/buglist.cgi?quicksearch=product%3Aclang+component%3A-New%2BBugs%2CAST%2CBasic%2CDriver%2CHeaders%2CLLVM%2BCodeGen%2Cparser%2Cpreprocessor%2CSemantic%2BAnalyzer>`_
+for known existing bugs (FIXME: Is there a section for bug-reporting
+guidelines somewhere?).
+
+Intentionally unsupported GCC extensions
+----------------------------------------
+
+- clang does not support the gcc extension that allows variable-length
+ arrays in structures. This is for a few reasons: one, it is tricky to
+ implement, two, the extension is completely undocumented, and three,
+ the extension appears to be rarely used. Note that clang *does*
+ support flexible array members (arrays with a zero or unspecified
+ size at the end of a structure).
+- clang does not have an equivalent to gcc's "fold"; this means that
+ clang doesn't accept some constructs gcc might accept in contexts
+ where a constant expression is required, like "x-x" where x is a
+ variable.
+- clang does not support ``__builtin_apply`` and friends; this extension
+ is extremely obscure and difficult to implement reliably.
+
+.. _c_ms:
+
+Microsoft extensions
+--------------------
+
+clang has some experimental support for extensions from Microsoft Visual
+C++; to enable it, use the -fms-extensions command-line option. This is
+the default for Windows targets. Note that the support is incomplete;
+enabling Microsoft extensions will silently drop certain constructs
+(including ``__declspec`` and Microsoft-style asm statements).
+
+clang has a -fms-compatibility flag that makes clang accept enough
+invalid C++ to be able to parse most Microsoft headers. This flag is
+enabled by default for Windows targets.
+
+-fdelayed-template-parsing lets clang delay all template instantiation
+until the end of a translation unit. This flag is enabled by default for
+Windows targets.
+
+- clang allows setting ``_MSC_VER`` with ``-fmsc-version=``. It defaults to
+ 1300 which is the same as Visual C/C++ 2003. Any number is supported
+ and can greatly affect what Windows SDK and c++stdlib headers clang
+ can compile. This option will be removed when clang supports the full
+ set of MS extensions required for these headers.
+- clang does not support the Microsoft extension where anonymous record
+ members can be declared using user defined typedefs.
+- clang supports the Microsoft "#pragma pack" feature for controlling
+ record layout. GCC also contains support for this feature, however
+ where MSVC and GCC are incompatible clang follows the MSVC
+ definition.
+- clang defaults to C++11 for Windows targets.
+
+.. _cxx:
+
+C++ Language Features
+=====================
+
+clang fully implements all of standard C++98 except for exported
+templates (which were removed in C++11), and `many C++11
+features <http://clang.llvm.org/cxx_status.html>`_ are also implemented.
+
+Controlling implementation limits
+---------------------------------
+
+.. option:: -fbracket-depth=N
+
+ Sets the limit for nested parentheses, brackets, and braces to N. The
+ default is 256.
+
+.. option:: -fconstexpr-depth=N
+
+ Sets the limit for recursive constexpr function invocations to N. The
+ default is 512.
+
+.. option:: -ftemplate-depth=N
+
+ Sets the limit for recursively nested template instantiations to N. The
+ default is 1024.
+
+.. _objc:
+
+Objective-C Language Features
+=============================
+
+.. _objcxx:
+
+Objective-C++ Language Features
+===============================
+
+
+.. _target_features:
+
+Target-Specific Features and Limitations
+========================================
+
+CPU Architectures Features and Limitations
+------------------------------------------
+
+X86
+^^^
+
+The support for X86 (both 32-bit and 64-bit) is considered stable on
+Darwin (Mac OS/X), Linux, FreeBSD, and Dragonfly BSD: it has been tested
+to correctly compile many large C, C++, Objective-C, and Objective-C++
+codebases.
+
+On ``x86_64-mingw32``, passing i128(by value) is incompatible to Microsoft
+x64 calling conversion. You might need to tweak
+``WinX86_64ABIInfo::classify()`` in lib/CodeGen/TargetInfo.cpp.
+
+ARM
+^^^
+
+The support for ARM (specifically ARMv6 and ARMv7) is considered stable
+on Darwin (iOS): it has been tested to correctly compile many large C,
+C++, Objective-C, and Objective-C++ codebases. Clang only supports a
+limited number of ARM architectures. It does not yet fully support
+ARMv5, for example.
+
+Other platforms
+^^^^^^^^^^^^^^^
+
+clang currently contains some support for PPC and Sparc; however,
+significant pieces of code generation are still missing, and they
+haven't undergone significant testing.
+
+clang contains limited support for the MSP430 embedded processor, but
+both the clang support and the LLVM backend support are highly
+experimental.
+
+Other platforms are completely unsupported at the moment. Adding the
+minimal support needed for parsing and semantic analysis on a new
+platform is quite easy; see ``lib/Basic/Targets.cpp`` in the clang source
+tree. This level of support is also sufficient for conversion to LLVM IR
+for simple programs. Proper support for conversion to LLVM IR requires
+adding code to ``lib/CodeGen/CGCall.cpp`` at the moment; this is likely to
+change soon, though. Generating assembly requires a suitable LLVM
+backend.
+
+Operating System Features and Limitations
+-----------------------------------------
+
+Darwin (Mac OS/X)
+^^^^^^^^^^^^^^^^^
+
+None
+
+Windows
+^^^^^^^
+
+Experimental supports are on Cygming.
+
+See also `Microsoft Extensions <c_ms>`.
+
+Cygwin
+""""""
+
+Clang works on Cygwin-1.7.
+
+MinGW32
+"""""""
+
+Clang works on some mingw32 distributions. Clang assumes directories as
+below;
+
+- ``C:/mingw/include``
+- ``C:/mingw/lib``
+- ``C:/mingw/lib/gcc/mingw32/4.[3-5].0/include/c++``
+
+On MSYS, a few tests might fail.
+
+MinGW-w64
+"""""""""
+
+For 32-bit (i686-w64-mingw32), and 64-bit (x86\_64-w64-mingw32), Clang
+assumes as below;
+
+- ``GCC versions 4.5.0 to 4.5.3, 4.6.0 to 4.6.2, or 4.7.0 (for the C++ header search path)``
+- ``some_directory/bin/gcc.exe``
+- ``some_directory/bin/clang.exe``
+- ``some_directory/bin/clang++.exe``
+- ``some_directory/bin/../include/c++/GCC_version``
+- ``some_directory/bin/../include/c++/GCC_version/x86_64-w64-mingw32``
+- ``some_directory/bin/../include/c++/GCC_version/i686-w64-mingw32``
+- ``some_directory/bin/../include/c++/GCC_version/backward``
+- ``some_directory/bin/../x86_64-w64-mingw32/include``
+- ``some_directory/bin/../i686-w64-mingw32/include``
+- ``some_directory/bin/../include``
+
+This directory layout is standard for any toolchain you will find on the
+official `MinGW-w64 website <http://mingw-w64.sourceforge.net>`_.
+
+Clang expects the GCC executable "gcc.exe" compiled for
+``i686-w64-mingw32`` (or ``x86_64-w64-mingw32``) to be present on PATH.
+
+`Some tests might fail <http://llvm.org/bugs/show_bug.cgi?id=9072>`_ on
+``x86_64-w64-mingw32``.
diff --git a/docs/analyzer/DebugChecks.rst b/docs/analyzer/DebugChecks.rst
new file mode 100644
index 0000000..f8e6f82
--- /dev/null
+++ b/docs/analyzer/DebugChecks.rst
@@ -0,0 +1,134 @@
+============
+Debug Checks
+============
+
+.. contents::
+ :local:
+
+The analyzer contains a number of checkers which can aid in debugging. Enable
+them by using the "-analyzer-checker=" flag, followed by the name of the
+checker.
+
+
+General Analysis Dumpers
+========================
+
+These checkers are used to dump the results of various infrastructural analyses
+to stderr. Some checkers also have "view" variants, which will display a graph
+using a 'dot' format viewer (such as Graphviz on OS X) instead.
+
+- debug.DumpCallGraph, debug.ViewCallGraph: Show the call graph generated for
+ the current translation unit. This is used to determine the order in which to
+ analyze functions when inlining is enabled.
+
+- debug.DumpCFG, debug.ViewCFG: Show the CFG generated for each top-level
+ function being analyzed.
+
+- debug.DumpDominators: Shows the dominance tree for the CFG of each top-level
+ function.
+
+- debug.DumpLiveVars: Show the results of live variable analysis for each
+ top-level function being analyzed.
+
+
+Path Tracking
+=============
+
+These checkers print information about the path taken by the analyzer engine.
+
+- debug.DumpCalls: Prints out every function or method call encountered during a
+ path traversal. This is indented to show the call stack, but does NOT do any
+ special handling of branches, meaning different paths could end up
+ interleaved.
+
+- debug.DumpTraversal: Prints the name of each branch statement encountered
+ during a path traversal ("IfStmt", "WhileStmt", etc). Currently used to check
+ whether the analysis engine is doing BFS or DFS.
+
+
+State Checking
+==============
+
+These checkers will print out information about the analyzer state in the form
+of analysis warnings. They are intended for use with the -verify functionality
+in regression tests.
+
+- debug.TaintTest: Prints out the word "tainted" for every expression that
+ carries taint. At the time of this writing, taint was only introduced by the
+ checks under experimental.security.taint.TaintPropagation; this checker may
+ eventually move to the security.taint package.
+
+- debug.ExprInspection: Responds to certain function calls, which are modeled
+ after builtins. These function calls should affect the program state other
+ than the evaluation of their arguments; to use them, you will need to declare
+ them within your test file. The available functions are described below.
+
+(FIXME: debug.ExprInspection should probably be renamed, since it no longer only
+inspects expressions.)
+
+
+ExprInspection checks
+---------------------
+
+- void clang_analyzer_eval(bool);
+
+ Prints TRUE if the argument is known to have a non-zero value, FALSE if the
+ argument is known to have a zero or null value, and UNKNOWN if the argument
+ isn't sufficiently constrained on this path. You can use this to test other
+ values by using expressions like "x == 5". Note that this functionality is
+ currently DISABLED in inlined functions, since different calls to the same
+ inlined function could provide different information, making it difficult to
+ write proper -verify directives.
+
+ In C, the argument can be typed as 'int' or as '_Bool'.
+
+ Example usage::
+
+ clang_analyzer_eval(x); // expected-warning{{UNKNOWN}}
+ if (!x) return;
+ clang_analyzer_eval(x); // expected-warning{{TRUE}}
+
+
+- void clang_analyzer_checkInlined(bool);
+
+ If a call occurs within an inlined function, prints TRUE or FALSE according to
+ the value of its argument. If a call occurs outside an inlined function,
+ nothing is printed.
+
+ The intended use of this checker is to assert that a function is inlined at
+ least once (by passing 'true' and expecting a warning), or to assert that a
+ function is never inlined (by passing 'false' and expecting no warning). The
+ argument is technically unnecessary but is intended to clarify intent.
+
+ You might wonder why we can't print TRUE if a function is ever inlined and
+ FALSE if it is not. The problem is that any inlined function could conceivably
+ also be analyzed as a top-level function (in which case both TRUE and FALSE
+ would be printed), depending on the value of the -analyzer-inlining option.
+
+ In C, the argument can be typed as 'int' or as '_Bool'.
+
+ Example usage::
+
+ int inlined() {
+ clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
+ return 42;
+ }
+
+ void topLevel() {
+ clang_analyzer_checkInlined(false); // no-warning (not inlined)
+ int value = inlined();
+ // This assertion will not be valid if the previous call was not inlined.
+ clang_analyzer_eval(value == 42); // expected-warning{{TRUE}}
+ }
+
+
+Statistics
+==========
+
+The debug.Stats checker collects various information about the analysis of each
+function, such as how many blocks were reached and if the analyzer timed out.
+
+There is also an additional -analyzer-stats flag, which enables various
+statistics within the analyzer engine. Note the Stats checker (which produces at
+least one bug report per function) may actually change the values reported by
+-analyzer-stats.
diff --git a/docs/analyzer/IPA.txt b/docs/analyzer/IPA.txt
index 016cea9..01e73ce 100644
--- a/docs/analyzer/IPA.txt
+++ b/docs/analyzer/IPA.txt
@@ -2,36 +2,37 @@ Inlining
========
There are several options that control which calls the analyzer will consider for
-inlining. The major one is -analyzer-ipa:
+inlining. The major one is -analyzer-config ipa:
- -analyzer-ipa=none - All inlining is disabled. This is the only mode available
- in LLVM 3.1 and earlier and in Xcode 4.3 and earlier.
+ -analyzer-config ipa=none - All inlining is disabled. This is the only mode
+ available in LLVM 3.1 and earlier and in Xcode 4.3 and earlier.
- -analyzer-ipa=basic-inlining - Turns on inlining for C functions, C++ static
- member functions, and blocks -- essentially, the calls that behave like
- simple C function calls. This is essentially the mode used in Xcode 4.4.
+ -analyzer-config ipa=basic-inlining - Turns on inlining for C functions, C++
+ static member functions, and blocks -- essentially, the calls that behave
+ like simple C function calls. This is essentially the mode used in
+ Xcode 4.4.
- -analyzer-ipa=inlining - Turns on inlining when we can confidently find the
- function/method body corresponding to the call. (C functions, static
+ -analyzer-config ipa=inlining - Turns on inlining when we can confidently find
+ the function/method body corresponding to the call. (C functions, static
functions, devirtualized C++ methods, Objective-C class methods, Objective-C
instance methods when ExprEngine is confident about the dynamic type of the
instance).
- -analyzer-ipa=dynamic - Inline instance methods for which the type is
+ -analyzer-config ipa=dynamic - Inline instance methods for which the type is
determined at runtime and we are not 100% sure that our type info is
correct. For virtual calls, inline the most plausible definition.
- -analyzer-ipa=dynamic-bifurcate - Same as -analyzer-ipa=dynamic, but the path
- is split. We inline on one branch and do not inline on the other. This mode
- does not drop the coverage in cases when the parent class has code that is
- only exercised when some of its methods are overridden.
+ -analyzer-config ipa=dynamic-bifurcate - Same as -analyzer-config ipa=dynamic,
+ but the path is split. We inline on one branch and do not inline on the
+ other. This mode does not drop the coverage in cases when the parent class
+ has code that is only exercised when some of its methods are overridden.
-Currently, -analyzer-ipa=dynamic-bifurcate is the default mode.
+Currently, -analyzer-config ipa=dynamic-bifurcate is the default mode.
-While -analyzer-ipa determines in general how aggressively the analyzer will try to
-inline functions, several additional options control which types of functions can
-inlined, in an all-or-nothing way. These options use the analyzer's configuration
-table, so they are all specified as follows:
+While -analyzer-config ipa determines in general how aggressively the analyzer
+will try to inline functions, several additional options control which types of
+functions can inlined, in an all-or-nothing way. These options use the
+analyzer's configuration table, so they are all specified as follows:
-analyzer-config OPTION=VALUE
@@ -45,10 +46,14 @@ Each of these modes implies that all the previous member function kinds will be
inlined as well; it doesn't make sense to inline destructors without inlining
constructors, for example.
-The default c++-inlining mode is 'methods', meaning only regular member
-functions and overloaded operators will be inlined. Note that no C++ member
-functions will be inlined under -analyzer-ipa=none or
--analyzer-ipa=basic-inlining.
+The default c++-inlining mode is 'destructors', meaning that all member
+functions with visible definitions will be considered for inlining. In some
+cases the analyzer may still choose not to inline the function.
+
+Note that under 'constructors', constructors for types with non-trivial
+destructors will not be inlined. Additionally, no C++ member functions will be
+inlined under -analyzer-config ipa=none or -analyzer-config ipa=basic-inlining,
+regardless of the setting of the c++-inlining mode.
### c++-template-inlining ###
@@ -71,7 +76,8 @@ considered for inlining.
-analyzer-config c++-template-inlining=[true | false]
-Currently, C++ standard library functions are NOT considered for inlining by default.
+Currently, C++ standard library functions are considered for inlining by
+default.
The standard library functions and the STL in particular are used ubiquitously
enough that our tolerance for false positives is even lower here. A false
@@ -79,6 +85,31 @@ positive due to poor modeling of the STL leads to a poor user experience, since
most users would not be comfortable adding assertions to system headers in order
to silence analyzer warnings.
+### c++-container-inlining ###
+
+This option controls whether constructors and destructors of "container" types
+should be considered for inlining.
+
+ -analyzer-config c++-container-inlining=[true | false]
+
+Currently, these constructors and destructors are NOT considered for inlining
+by default.
+
+The current implementation of this setting checks whether a type has a member
+named 'iterator' or a member named 'begin'; these names are idiomatic in C++,
+with the latter specified in the C++11 standard. The analyzer currently does a
+fairly poor job of modeling certain data structure invariants of container-like
+objects. For example, these three expressions should be equivalent:
+
+ std::distance(c.begin(), c.end()) == 0
+ c.begin() == c.end()
+ c.empty())
+
+Many of these issues are avoided if containers always have unknown, symbolic
+state, which is what happens when their constructors are treated as opaque.
+In the future, we may decide specific containers are "safe" to model through
+inlining, or choose to model them directly using checkers instead.
+
Basics of Implementation
-----------------------
@@ -229,31 +260,31 @@ inlined.
== Inlining Dynamic Calls ==
-The -analyzer-ipa option has five different modes: none, basic-inlining,
-inlining, dynamic, and dynamic-bifurcate. Under -analyzer-ipa=dynamic, all
-dynamic calls are inlined, whether we are certain or not that this will actually
-be the definition used at runtime. Under -analyzer-ipa=inlining, only
-"near-perfect" devirtualized calls are inlined*, and other dynamic calls are
-evaluated conservatively (as if no definition were available).
+The -analyzer-config ipa option has five different modes: none, basic-inlining,
+inlining, dynamic, and dynamic-bifurcate. Under -analyzer-config ipa=dynamic,
+all dynamic calls are inlined, whether we are certain or not that this will
+actually be the definition used at runtime. Under -analyzer-config ipa=inlining,
+only "near-perfect" devirtualized calls are inlined*, and other dynamic calls
+are evaluated conservatively (as if no definition were available).
* Currently, no Objective-C messages are not inlined under
- -analyzer-ipa=inlining, even if we are reasonably confident of the type of the
- receiver. We plan to enable this once we have tested our heuristics more
- thoroughly.
+ -analyzer-config ipa=inlining, even if we are reasonably confident of the type
+ of the receiver. We plan to enable this once we have tested our heuristics
+ more thoroughly.
-The last option, -analyzer-ipa=dynamic-bifurcate, behaves similarly to
+The last option, -analyzer-config ipa=dynamic-bifurcate, behaves similarly to
"dynamic", but performs a conservative invalidation in the general virtual case
in *addition* to inlining. The details of this are discussed below.
-As stated above, -analyzer-ipa=basic-inlining does not inline any C++ member
-functions or Objective-C method calls, even if they are non-virtual or can be
-safely devirtualized.
+As stated above, -analyzer-config ipa=basic-inlining does not inline any C++
+member functions or Objective-C method calls, even if they are non-virtual or
+can be safely devirtualized.
Bifurcation
-----------
-ExprEngine::BifurcateCall implements the -analyzer-ipa=dynamic-bifurcate
+ExprEngine::BifurcateCall implements the -analyzer-config ipa=dynamic-bifurcate
mode.
When a call is made on an object with imprecise dynamic type information
diff --git a/docs/analyzer/Makefile b/docs/analyzer/Makefile
new file mode 100644
index 0000000..14f5e60
--- /dev/null
+++ b/docs/analyzer/Makefile
@@ -0,0 +1,155 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+BUILDDIR = _build
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
+
+default: html
+
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " singlehtml to make a single large HTML file"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " devhelp to make HTML files and a Devhelp project"
+ @echo " epub to make an epub"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
+ @echo " text to make text files"
+ @echo " man to make manual pages"
+ @echo " texinfo to make Texinfo files"
+ @echo " info to make Texinfo files and run them through makeinfo"
+ @echo " gettext to make PO message catalogs"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+ -rm -rf $(BUILDDIR)/*
+
+html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ @echo
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/ClangStaticAnalyzer.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/ClangStaticAnalyzer.qhc"
+
+devhelp:
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+ @echo
+ @echo "Build finished."
+ @echo "To view the help file:"
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/ClangStaticAnalyzer"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/ClangStaticAnalyzer"
+ @echo "# devhelp"
+
+epub:
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ @echo
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
+ "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through pdflatex..."
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ @echo
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ @echo
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+texinfo:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo
+ @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+ @echo "Run \`make' in that directory to run these through makeinfo" \
+ "(use \`make info' here to do that automatically)."
+
+info:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo "Running Texinfo files through makeinfo..."
+ make -C $(BUILDDIR)/texinfo info
+ @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+gettext:
+ $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+ @echo
+ @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/docs/analyzer/RegionStore.txt b/docs/analyzer/RegionStore.txt
new file mode 100644
index 0000000..5d37cf7
--- /dev/null
+++ b/docs/analyzer/RegionStore.txt
@@ -0,0 +1,171 @@
+The analyzer "Store" represents the contents of memory regions. It is an opaque
+functional data structure stored in each ProgramState; the only class that can
+modify the store is its associated StoreManager.
+
+Currently (Feb. 2013), the only StoreManager implementation being used is
+RegionStoreManager. This store records bindings to memory regions using a "base
+region + offset" key. (This allows `*p` and `p[0]` to map to the same location,
+among other benefits.)
+
+Regions are grouped into "clusters", which roughly correspond to "regions with
+the same base region". This allows certain operations to be more efficient,
+such as invalidation.
+
+Regions that do not have a known offset use a special "symbolic" offset. These
+keys store both the original region, and the "concrete offset region" -- the
+last region whose offset is entirely concrete. (For example, in the expression
+`foo.bar[1][i].baz`, the concrete offset region is the array `foo.bar[1]`,
+since that has a known offset from the start of the top-level `foo` struct.)
+
+
+Binding Invalidation
+====================
+
+Supporting both concrete and symbolic offsets makes things a bit tricky. Here's
+an example:
+
+ foo[0] = 0;
+ foo[1] = 1;
+ foo[i] = i;
+
+After the third assignment, nothing can be said about the value of `foo[0]`,
+because `foo[i]` may have overwritten it! Thus, *binding to a region with a
+symbolic offset invalidates the entire concrete offset region.* We know
+`foo[i]` is somewhere within `foo`, so we don't have to invalidate anything
+else, but we do have to be conservative about all other bindings within `foo`.
+
+Continuing the example:
+
+ foo[i] = i;
+ foo[0] = 0;
+
+After this latest assignment, nothing can be said about the value of `foo[i]`,
+because `foo[0]` may have overwritten it! *Binding to a region R with a
+concrete offset invalidates any symbolic offset bindings whose concrete offset
+region is a super-region **or** sub-region of R.* All we know about `foo[i]` is
+that it is somewhere within `foo`, so changing *anything* within `foo` might
+change `foo[i]`, and changing *all* of `foo` (or its base region) will
+*definitely* change `foo[i]`.
+
+This logic could be improved by using the current constraints on `i`, at the
+cost of speed. The latter case could also be improved by matching region kinds,
+i.e. changing `foo[0].a` is unlikely to affect `foo[i].b`, no matter what `i`
+is.
+
+For more detail, read through RegionStoreManager::removeSubRegionBindings in
+RegionStore.cpp.
+
+
+ObjCIvarRegions
+===============
+
+Objective-C instance variables require a bit of special handling. Like struct
+fields, they are not base regions, and when their parent object region is
+invalidated, all the instance variables must be invalidated as well. However,
+they have no concrete compile-time offsets (in the modern, "non-fragile"
+runtime), and so cannot easily be represented as an offset from the start of
+the object in the analyzer. Moreover, this means that invalidating a single
+instance variable should *not* invalidate the rest of the object, since unlike
+struct fields or array elements there is no way to perform pointer arithmetic
+to access another instance variable.
+
+Consequently, although the base region of an ObjCIvarRegion is the entire
+object, RegionStore offsets are computed from the start of the instance
+variable. Thus it is not valid to assume that all bindings with non-symbolic
+offsets start from the base region!
+
+
+Region Invalidation
+===================
+
+Unlike binding invalidation, region invalidation occurs when the entire
+contents of a region may have changed---say, because it has been passed to a
+function the analyzer can model, like memcpy, or because its address has
+escaped, usually as an argument to an opaque function call. In these cases we
+need to throw away not just all bindings within the region itself, but within
+its entire cluster, since neighboring regions may be accessed via pointer
+arithmetic.
+
+Region invalidation typically does even more than this, however. Because it
+usually represents the complete escape of a region from the analyzer's model,
+its *contents* must also be transitively invalidated. (For example, if a region
+'p' of type 'int **' is invalidated, the contents of '*p' and '**p' may have
+changed as well.) The algorithm that traverses this transitive closure of
+accessible regions is known as ClusterAnalysis, and is also used for finding
+all live bindings in the store (in order to throw away the dead ones). The name
+"ClusterAnalysis" predates the cluster-based organization of bindings, but
+refers to the same concept: during invalidation and liveness analysis, all
+bindings within a cluster must be treated in the same way for a conservative
+model of program behavior.
+
+
+Default Bindings
+================
+
+Most bindings in RegionStore are simple scalar values -- integers and pointers.
+These are known as "Direct" bindings. However, RegionStore supports a second
+type of binding called a "Default" binding. These are used to provide values to
+all the elements of an aggregate type (struct or array) without having to
+explicitly specify a binding for each individual element.
+
+When there is no Direct binding for a particular region, the store manager
+looks at each super-region in turn to see if there is a Default binding. If so,
+this value is used as the value of the original region. The search ends when
+the base region is reached, at which point the RegionStore will pick an
+appropriate default value for the region (usually a symbolic value, but
+sometimes zero, for static data, or "uninitialized", for stack variables).
+
+ int manyInts[10];
+ manyInts[1] = 42; // Creates a Direct binding for manyInts[1].
+ print(manyInts[1]); // Retrieves the Direct binding for manyInts[1];
+ print(manyInts[0]); // There is no Direct binding for manyInts[1].
+ // Is there a Default binding for the entire array?
+ // There is not, but it is a stack variable, so we use
+ // "uninitialized" as the default value (and emit a
+ // diagnostic!).
+
+NOTE: The fact that bindings are stored as a base region plus an offset limits
+the Default Binding strategy, because in C aggregates can contain other
+aggregates. In the current implementation of RegionStore, there is no way to
+distinguish a Default binding for an entire aggregate from a Default binding
+for the sub-aggregate at offset 0.
+
+
+Lazy Bindings (LazyCompoundVal)
+===============================
+
+RegionStore implements an optimization for copying aggregates (structs and
+arrays) called "lazy bindings", implemented using a special SVal called
+LazyCompoundVal. When the store is asked for the "binding" for an entire
+aggregate (i.e. for an lvalue-to-rvalue conversion), it returns a
+LazyCompoundVal instead. When this value is then stored into a variable, it is
+bound as a Default value. This makes copying arrays and structs much cheaper
+than if they had required memberwise access.
+
+Under the hood, a LazyCompoundVal is implemented as a uniqued pair of (region,
+store), representing "the value of the region during this 'snapshot' of the
+store". This has important implications for any sort of liveness or
+reachability analysis, which must take the bindings in the old store into
+account.
+
+Retrieving a value from a lazy binding happens in the same way as any other
+Default binding: since there is no direct binding, the store manager falls back
+to super-regions to look for an appropriate default binding. LazyCompoundVal
+differs from a normal default binding, however, in that it contains several
+different values, instead of one value that will appear several times. Because
+of this, the store manager has to reconstruct the subregion chain on top of the
+LazyCompoundVal region, and look up *that* region in the previous store.
+
+Here's a concrete example:
+
+ CGPoint p;
+ p.x = 42; // A Direct binding is made to the FieldRegion 'p.x'.
+ CGPoint p2 = p; // A LazyCompoundVal is created for 'p', along with a
+ // snapshot of the current store state. This value is then
+ // used as a Default binding for the VarRegion 'p2'.
+ return p2.x; // The binding for FieldRegion 'p2.x' is requested.
+ // There is no Direct binding, so we look for a Default
+ // binding to 'p2' and find the LCV.
+ // Because it's an LCV, we look at our requested region
+ // and see that it's the '.x' field. We ask for the value
+ // of 'p.x' within the snapshot, and get back 42.
diff --git a/docs/analyzer/conf.py b/docs/analyzer/conf.py
new file mode 100644
index 0000000..dff9610
--- /dev/null
+++ b/docs/analyzer/conf.py
@@ -0,0 +1,246 @@
+# -*- coding: utf-8 -*-
+#
+# Clang Static Analyzer documentation build configuration file, created by
+# sphinx-quickstart on Wed Jan 2 15:54:28 2013.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.todo', 'sphinx.ext.mathjax']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'Clang Static Analyzer'
+copyright = u'2013, Analyzer Team'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '3.3'
+# The full version, including alpha/beta/rc tags.
+release = '3.3'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'haiku'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = []
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'ClangStaticAnalyzerdoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('index', 'ClangStaticAnalyzer.tex', u'Clang Static Analyzer Documentation',
+ u'Analyzer Team', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('index', 'clangstaticanalyzer', u'Clang Static Analyzer Documentation',
+ [u'Analyzer Team'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output ------------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ ('index', 'ClangStaticAnalyzer', u'Clang Static Analyzer Documentation',
+ u'Analyzer Team', 'ClangStaticAnalyzer', 'One line description of project.',
+ 'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+
+# Example configuration for intersphinx: refer to the Python standard library.
+intersphinx_mapping = {'http://docs.python.org/': None}
diff --git a/docs/analyzer/debug-checks.txt b/docs/analyzer/debug-checks.txt
deleted file mode 100644
index 6ac451f..0000000
--- a/docs/analyzer/debug-checks.txt
+++ /dev/null
@@ -1,89 +0,0 @@
-The analyzer contains a number of checkers which can aid in debugging. Enable them by using the "-analyzer-checker=" flag, followed by the name of the checker.
-
-General Analysis Dumpers
-========================
-These checkers are used to dump the results of various infrastructural analyses to stderr. Some checkers also have "view" variants, which will display a graph using a 'dot' format viewer (such as Graphviz on OS X) instead.
-
-- debug.DumpCallGraph, debug.ViewCallGraph: Show the call graph generated for the current translation unit. This is used to determine the order in which to analyze functions when inlining is enabled.
-- debug.DumpCFG, debug.ViewCFG: Show the CFG generated for each top-level function being analyzed.
-- debug.DumpDominators: Shows the dominance tree for the CFG of each top-level function.
-- debug.DumpLiveVars: Show the results of live variable analysis for each top-level function being analyzed.
-
-
-Path Tracking
-=============
-These checkers print information about the path taken by the analyzer engine.
-
-- debug.DumpCalls: Prints out every function or method call encountered during a path traversal. This is indented to show the call stack, but does NOT do any special handling of branches, meaning different paths could end up interleaved.
-- debug.DumpTraversal: Prints the name of each branch statement encountered during a path traversal ("IfStmt", "WhileStmt", etc). Currently used to check whether the analysis engine is doing BFS or DFS.
-
-
-State Checking
-==============
-These checkers will print out information about the analyzer state in the form of analysis warnings. They are intended for use with the -verify functionality in regression tests.
-
-- debug.TaintTest: Prints out the word "tainted" for every expression that carries taint. At the time of this writing, taint was only introduced by the checks under experimental.security.taint.TaintPropagation; this checker may eventually move to the security.taint package.
-- debug.ExprInspection: Responds to certain function calls, which are modeled after builtins. These function calls should affect the program state other than the evaluation of their arguments; to use them, you will need to declare them within your test file. The available functions are described below.
-
-(FIXME: debug.ExprInspection should probably be renamed, since it no longer only inspects expressions.)
-
-
-ExprInspection checks
----------------------
-
-- void clang_analyzer_eval(bool);
-
-Prints TRUE if the argument is known to have a non-zero value,
- FALSE if the argument is known to have a zero or null value, and
- UNKNOWN if the argument isn't sufficiently constrained on this path.
-You can use this to test other values by using expressions like "x == 5".
-Note that this functionality is currently DISABLED in inlined functions,
-since different calls to the same inlined function could provide different
-information, making it difficult to write proper -verify directives.
-
-In C, the argument can be typed as 'int' or as '_Bool'.
-
-Example usage:
- clang_analyzer_eval(x); // expected-warning{{UNKNOWN}}
- if (!x) return;
- clang_analyzer_eval(x); // expected-warning{{TRUE}}
-
-
-- void clang_analyzer_checkInlined(bool);
-
-If a call occurs within an inlined function, prints TRUE or FALSE according to
-the value of its argument. If a call occurs outside an inlined function,
-nothing is printed.
-
-The intended use of this checker is to assert that a function is inlined at
-least once (by passing 'true' and expecting a warning), or to assert that a
-function is never inlined (by passing 'false' and expecting no warning). The
-argument is technically unnecessary but is intended to clarify intent.
-
-You might wonder why we can't print TRUE if a function is ever inlined and
-FALSE if it is not. The problem is that any inlined function could conceivably
-also be analyzed as a top-level function (in which case both TRUE and FALSE
-would be printed), depending on the value of the -analyzer-inlining option.
-
-In C, the argument can be typed as 'int' or as '_Bool'.
-
-Example usage:
- int inlined() {
- clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
- return 42;
- }
-
- void topLevel() {
- clang_analyzer_checkInlined(false); // no-warning (not inlined)
- int value = inlined();
- // This assertion will not be valid if the previous call was not inlined.
- clang_analyzer_eval(value == 42); // expected-warning{{TRUE}}
- }
-
-
-
-Statistics
-==========
-The debug.Stats checker collects various information about the analysis of each function, such as how many blocks were reached and if the analyzer timed out.
-
-There is also an additional -analyzer-stats flag, which enables various statistics within the analyzer engine. Note the Stats checker (which produces at least one bug report per function) may actually change the values reported by -analyzer-stats.
diff --git a/docs/analyzer/index.rst b/docs/analyzer/index.rst
new file mode 100644
index 0000000..767567f
--- /dev/null
+++ b/docs/analyzer/index.rst
@@ -0,0 +1,23 @@
+.. Clang Static Analyzer documentation master file, created by
+ sphinx-quickstart on Wed Jan 2 15:54:28 2013.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+Welcome to Clang Static Analyzer's documentation!
+=================================================
+
+Contents:
+
+.. toctree::
+ :maxdepth: 2
+
+ DebugChecks
+
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
diff --git a/docs/analyzer/make.bat b/docs/analyzer/make.bat
new file mode 100644
index 0000000..6c2c63d
--- /dev/null
+++ b/docs/analyzer/make.bat
@@ -0,0 +1,190 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+set I18NSPHINXOPTS=%SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+ set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+ set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+ :help
+ echo.Please use `make ^<target^>` where ^<target^> is one of
+ echo. html to make standalone HTML files
+ echo. dirhtml to make HTML files named index.html in directories
+ echo. singlehtml to make a single large HTML file
+ echo. pickle to make pickle files
+ echo. json to make JSON files
+ echo. htmlhelp to make HTML files and a HTML help project
+ echo. qthelp to make HTML files and a qthelp project
+ echo. devhelp to make HTML files and a Devhelp project
+ echo. epub to make an epub
+ echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+ echo. text to make text files
+ echo. man to make manual pages
+ echo. texinfo to make Texinfo files
+ echo. gettext to make PO message catalogs
+ echo. changes to make an overview over all changed/added/deprecated items
+ echo. linkcheck to check all external links for integrity
+ echo. doctest to run all doctests embedded in the documentation if enabled
+ goto end
+)
+
+if "%1" == "clean" (
+ for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+ del /q /s %BUILDDIR%\*
+ goto end
+)
+
+if "%1" == "html" (
+ %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+ goto end
+)
+
+if "%1" == "dirhtml" (
+ %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+ goto end
+)
+
+if "%1" == "singlehtml" (
+ %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+ goto end
+)
+
+if "%1" == "pickle" (
+ %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the pickle files.
+ goto end
+)
+
+if "%1" == "json" (
+ %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the JSON files.
+ goto end
+)
+
+if "%1" == "htmlhelp" (
+ %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+ goto end
+)
+
+if "%1" == "qthelp" (
+ %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+ echo.^> qcollectiongenerator %BUILDDIR%\qthelp\ClangStaticAnalyzer.qhcp
+ echo.To view the help file:
+ echo.^> assistant -collectionFile %BUILDDIR%\qthelp\ClangStaticAnalyzer.ghc
+ goto end
+)
+
+if "%1" == "devhelp" (
+ %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished.
+ goto end
+)
+
+if "%1" == "epub" (
+ %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The epub file is in %BUILDDIR%/epub.
+ goto end
+)
+
+if "%1" == "latex" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "text" (
+ %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The text files are in %BUILDDIR%/text.
+ goto end
+)
+
+if "%1" == "man" (
+ %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The manual pages are in %BUILDDIR%/man.
+ goto end
+)
+
+if "%1" == "texinfo" (
+ %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
+ goto end
+)
+
+if "%1" == "gettext" (
+ %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
+ goto end
+)
+
+if "%1" == "changes" (
+ %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.The overview file is in %BUILDDIR%/changes.
+ goto end
+)
+
+if "%1" == "linkcheck" (
+ %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+ goto end
+)
+
+if "%1" == "doctest" (
+ %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+ goto end
+)
+
+:end
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644
index 0000000..92741d2
--- /dev/null
+++ b/docs/conf.py
@@ -0,0 +1,242 @@
+# -*- coding: utf-8 -*-
+#
+# Clang documentation build configuration file, created by
+# sphinx-quickstart on Sun Dec 9 20:01:55 2012.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.todo', 'sphinx.ext.mathjax']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'Clang'
+copyright = u'2007-2013, The Clang Team'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '3.3'
+# The full version, including alpha/beta/rc tags.
+release = '3.3'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build', 'analyzer']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'friendly'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'haiku'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = []
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'Clangdoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('index', 'Clang.tex', u'Clang Documentation',
+ u'The Clang Team', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('index', 'clang', u'Clang Documentation',
+ [u'The Clang Team'], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output ------------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ ('index', 'Clang', u'Clang Documentation',
+ u'The Clang Team', 'Clang', 'One line description of project.',
+ 'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644
index 0000000..5cdfb6b
--- /dev/null
+++ b/docs/index.rst
@@ -0,0 +1,73 @@
+.. Clang documentation master file, created by
+ sphinx-quickstart on Sun Dec 9 20:01:55 2012.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+.. title:: Welcome to Clang's documentation!
+
+.. toctree::
+ :maxdepth: 1
+
+ ReleaseNotes
+
+Using Clang as a Compiler
+=========================
+
+.. toctree::
+ :maxdepth: 1
+
+ UsersManual
+ LanguageExtensions
+ AddressSanitizer
+ ThreadSanitizer
+ MemorySanitizer
+ Modules
+ FAQ
+
+Using Clang as a Library
+========================
+
+.. toctree::
+ :maxdepth: 1
+
+ Tooling
+ ExternalClangExamples
+ IntroductionToTheClangAST
+ LibTooling
+ LibFormat
+ ClangPlugins
+ RAVFrontendAction
+ LibASTMatchersTutorial
+ LibASTMatchers
+ HowToSetupToolingForLLVM
+ JSONCompilationDatabase
+
+Using Clang Tools
+=================
+
+.. toctree::
+ :maxdepth: 1
+
+ ClangTools
+ ClangCheck
+ ClangFormat
+
+Design Documents
+================
+
+.. toctree::
+ :maxdepth: 1
+
+ InternalsManual
+ DriverInternals
+ PTHInternals
+ PCHInternals
+
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
diff --git a/docs/make.bat b/docs/make.bat
new file mode 100644
index 0000000..f284258
--- /dev/null
+++ b/docs/make.bat
@@ -0,0 +1,190 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+set I18NSPHINXOPTS=%SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+ set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+ set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+ :help
+ echo.Please use `make ^<target^>` where ^<target^> is one of
+ echo. html to make standalone HTML files
+ echo. dirhtml to make HTML files named index.html in directories
+ echo. singlehtml to make a single large HTML file
+ echo. pickle to make pickle files
+ echo. json to make JSON files
+ echo. htmlhelp to make HTML files and a HTML help project
+ echo. qthelp to make HTML files and a qthelp project
+ echo. devhelp to make HTML files and a Devhelp project
+ echo. epub to make an epub
+ echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+ echo. text to make text files
+ echo. man to make manual pages
+ echo. texinfo to make Texinfo files
+ echo. gettext to make PO message catalogs
+ echo. changes to make an overview over all changed/added/deprecated items
+ echo. linkcheck to check all external links for integrity
+ echo. doctest to run all doctests embedded in the documentation if enabled
+ goto end
+)
+
+if "%1" == "clean" (
+ for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+ del /q /s %BUILDDIR%\*
+ goto end
+)
+
+if "%1" == "html" (
+ %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+ goto end
+)
+
+if "%1" == "dirhtml" (
+ %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+ goto end
+)
+
+if "%1" == "singlehtml" (
+ %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+ goto end
+)
+
+if "%1" == "pickle" (
+ %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the pickle files.
+ goto end
+)
+
+if "%1" == "json" (
+ %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the JSON files.
+ goto end
+)
+
+if "%1" == "htmlhelp" (
+ %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+ goto end
+)
+
+if "%1" == "qthelp" (
+ %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+ echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Clang.qhcp
+ echo.To view the help file:
+ echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Clang.ghc
+ goto end
+)
+
+if "%1" == "devhelp" (
+ %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished.
+ goto end
+)
+
+if "%1" == "epub" (
+ %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The epub file is in %BUILDDIR%/epub.
+ goto end
+)
+
+if "%1" == "latex" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "text" (
+ %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The text files are in %BUILDDIR%/text.
+ goto end
+)
+
+if "%1" == "man" (
+ %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The manual pages are in %BUILDDIR%/man.
+ goto end
+)
+
+if "%1" == "texinfo" (
+ %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
+ goto end
+)
+
+if "%1" == "gettext" (
+ %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
+ goto end
+)
+
+if "%1" == "changes" (
+ %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.The overview file is in %BUILDDIR%/changes.
+ goto end
+)
+
+if "%1" == "linkcheck" (
+ %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+ goto end
+)
+
+if "%1" == "doctest" (
+ %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+ goto end
+)
+
+:end
diff --git a/docs/tools/dump_ast_matchers.py b/docs/tools/dump_ast_matchers.py
index bc5f1a6..4ed6822 100644
--- a/docs/tools/dump_ast_matchers.py
+++ b/docs/tools/dump_ast_matchers.py
@@ -133,24 +133,56 @@ def act_on_decl(declaration, comment, allowed_types):
if declaration.strip():
# Node matchers are defined by writing:
# VariadicDynCastAllOfMatcher<ResultType, ArgumentType> name;
- m = re.match(r""".*VariadicDynCastAllOfMatcher\s*<
- \s*([^\s,]+)\s*,
- \s*([^\s>]+)\s*>
+ m = re.match(r""".*Variadic(?:DynCast)?AllOfMatcher\s*<
+ \s*([^\s,]+)\s*(?:,
+ \s*([^\s>]+)\s*)?>
\s*([^\s;]+)\s*;\s*$""", declaration, flags=re.X)
if m:
result, inner, name = m.groups()
+ if not inner:
+ inner = result
add_matcher(result, name, 'Matcher<%s>...' % inner,
comment, is_dyncast=True)
return
# Parse the various matcher definition macros.
- m = re.match(r"""^\s*AST_(POLYMORPHIC_)?MATCHER(_P)?(.?)\(
+ m = re.match(""".*AST_TYPE_MATCHER\(
+ \s*([^\s,]+\s*),
+ \s*([^\s,]+\s*)
+ \)\s*;\s*$""", declaration, flags=re.X)
+ if m:
+ inner, name = m.groups()
+ add_matcher('Type', name, 'Matcher<%s>...' % inner,
+ comment, is_dyncast=True)
+ add_matcher('TypeLoc', '%sLoc' % name, 'Matcher<%sLoc>...' % inner,
+ comment, is_dyncast=True)
+ return
+
+ m = re.match(""".*AST_TYPE(LOC)?_TRAVERSE_MATCHER\(
+ \s*([^\s,]+\s*),
+ \s*(?:[^\s,]+\s*)
+ \)\s*;\s*$""", declaration, flags=re.X)
+ if m:
+ loc = m.group(1)
+ name = m.group(2)
+ result_types = extract_result_types(comment)
+ if not result_types:
+ raise Exception('Did not find allowed result types for: %s' % name)
+ for result_type in result_types:
+ add_matcher(result_type, name, 'Matcher<Type>', comment)
+ if loc:
+ add_matcher('%sLoc' % result_type, '%sLoc' % name, 'Matcher<TypeLoc>',
+ comment)
+ return
+
+ m = re.match(r"""^\s*AST_(POLYMORPHIC_)?MATCHER(_P)?(.?)(?:_OVERLOAD)?\(
(?:\s*([^\s,]+)\s*,)?
\s*([^\s,]+)\s*
(?:,\s*([^\s,]+)\s*
,\s*([^\s,]+)\s*)?
(?:,\s*([^\s,]+)\s*
,\s*([^\s,]+)\s*)?
+ (?:,\s*\d+\s*)?
\)\s*{\s*$""", declaration, flags=re.X)
if m:
p, n, result, name = m.groups()[1:5]
@@ -178,9 +210,9 @@ def act_on_decl(declaration, comment, allowed_types):
if m:
result, name, args = m.groups()
args = ', '.join(p.strip() for p in args.split(','))
- m = re.match(r'.*\s+internal::Matcher<([^>]+)>$', result)
+ m = re.match(r'.*\s+internal::(Bindable)?Matcher<([^>]+)>$', result)
if m:
- result_types = [m.group(1)]
+ result_types = [m.group(2)]
else:
result_types = extract_result_types(comment)
if not result_types:
diff --git a/examples/PrintFunctionNames/PrintFunctionNames.cpp b/examples/PrintFunctionNames/PrintFunctionNames.cpp
index ce8f208..f6e75cc 100644
--- a/examples/PrintFunctionNames/PrintFunctionNames.cpp
+++ b/examples/PrintFunctionNames/PrintFunctionNames.cpp
@@ -13,8 +13,8 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/FrontendPluginRegistry.h"
-#include "clang/AST/ASTConsumer.h"
#include "clang/AST/AST.h"
+#include "clang/AST/ASTConsumer.h"
#include "clang/Frontend/CompilerInstance.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
diff --git a/examples/analyzer-plugin/MainCallChecker.cpp b/examples/analyzer-plugin/MainCallChecker.cpp
index 0b3c0cf..8801f9a 100644
--- a/examples/analyzer-plugin/MainCallChecker.cpp
+++ b/examples/analyzer-plugin/MainCallChecker.cpp
@@ -1,7 +1,7 @@
#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/CheckerRegistry.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/CheckerRegistry.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
using namespace clang;
using namespace ento;
diff --git a/examples/clang-interpreter/CMakeLists.txt b/examples/clang-interpreter/CMakeLists.txt
index 06d3d03..451b4b8 100644
--- a/examples/clang-interpreter/CMakeLists.txt
+++ b/examples/clang-interpreter/CMakeLists.txt
@@ -5,6 +5,7 @@ set(LLVM_LINK_COMPONENTS
asmparser
bitreader
bitwriter
+ irreader
codegen
ipo
linker
diff --git a/examples/clang-interpreter/main.cpp b/examples/clang-interpreter/main.cpp
index 84e4c71..3d0d640 100644
--- a/examples/clang-interpreter/main.cpp
+++ b/examples/clang-interpreter/main.cpp
@@ -8,25 +8,24 @@
//===----------------------------------------------------------------------===//
#include "clang/CodeGen/CodeGenAction.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Tool.h"
-#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
-#include "clang/Basic/DiagnosticOptions.h"
-
-#include "llvm/Module.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
-#include "llvm/Support/ManagedStatic.h"
-#include "llvm/Support/raw_ostream.h"
+#include "llvm/ExecutionEngine/JIT.h"
+#include "llvm/IR/Module.h"
#include "llvm/Support/Host.h"
+#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace clang::driver;
@@ -75,14 +74,13 @@ int main(int argc, const char **argv, char * const *envp) {
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
- Driver TheDriver(Path.str(), llvm::sys::getDefaultTargetTriple(),
- "a.out", /*IsProduction=*/false, Diags);
+ Driver TheDriver(Path.str(), llvm::sys::getProcessTriple(), "a.out", Diags);
TheDriver.setTitle("clang interpreter");
// FIXME: This is a hack to try to force the driver to do something we can
// recognize. We need to extend the driver library to support this use model
// (basically, exactly one input, and the operation mode is hard wired).
- llvm::SmallVector<const char *, 16> Args(argv, argv + argc);
+ SmallVector<const char *, 16> Args(argv, argv + argc);
Args.push_back("-fsyntax-only");
OwningPtr<Compilation> C(TheDriver.BuildCompilation(Args));
if (!C)
@@ -130,7 +128,7 @@ int main(int argc, const char **argv, char * const *envp) {
Clang.setInvocation(CI.take());
// Create the compilers actual diagnostics engine.
- Clang.createDiagnostics(int(CCArgs.size()),const_cast<char**>(CCArgs.data()));
+ Clang.createDiagnostics();
if (!Clang.hasDiagnostics())
return 1;
diff --git a/include/clang-c/CXCompilationDatabase.h b/include/clang-c/CXCompilationDatabase.h
index d11133c..ff1ec63 100644
--- a/include/clang-c/CXCompilationDatabase.h
+++ b/include/clang-c/CXCompilationDatabase.h
@@ -95,6 +95,12 @@ clang_CompilationDatabase_getCompileCommands(CXCompilationDatabase,
const char *CompleteFileName);
/**
+ * \brief Get all the compile commands in the given compilation database.
+ */
+CINDEX_LINKAGE CXCompileCommands
+clang_CompilationDatabase_getAllCompileCommands(CXCompilationDatabase);
+
+/**
* \brief Free the given CompileCommands
*/
CINDEX_LINKAGE void clang_CompileCommands_dispose(CXCompileCommands);
diff --git a/include/clang-c/CXString.h b/include/clang-c/CXString.h
index 74c3166..34cab5e 100644
--- a/include/clang-c/CXString.h
+++ b/include/clang-c/CXString.h
@@ -36,7 +36,7 @@ extern "C" {
* with the string data, call \c clang_disposeString() to free the string.
*/
typedef struct {
- void *data;
+ const void *data;
unsigned private_flags;
} CXString;
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index aa3403c..787c44a 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -32,7 +32,7 @@
* compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
*/
#define CINDEX_VERSION_MAJOR 0
-#define CINDEX_VERSION_MINOR 6
+#define CINDEX_VERSION_MINOR 15
#define CINDEX_VERSION_ENCODE(major, minor) ( \
((major) * 10000) \
@@ -297,6 +297,24 @@ CINDEX_LINKAGE CXString clang_getFileName(CXFile SFile);
CINDEX_LINKAGE time_t clang_getFileTime(CXFile SFile);
/**
+ * \brief Uniquely identifies a CXFile, that refers to the same underlying file,
+ * across an indexing session.
+ */
+typedef struct {
+ unsigned long long data[3];
+} CXFileUniqueID;
+
+/**
+ * \brief Retrieve the unique ID for the given \c file.
+ *
+ * \param file the file to get the ID for.
+ * \param outID stores the returned CXFileUniqueID.
+ * \returns If there was a failure getting the unique ID, returns non-zero,
+ * otherwise returns 0.
+*/
+CINDEX_LINKAGE int clang_getFileUniqueID(CXFile file, CXFileUniqueID *outID);
+
+/**
* \brief Determine whether the given header is guarded against
* multiple inclusions, either with the conventional
* \#ifndef/\#define/\#endif macro guards or with \#pragma once.
@@ -342,7 +360,7 @@ CINDEX_LINKAGE CXFile clang_getFile(CXTranslationUnit tu,
* to map a source location to a particular file, line, and column.
*/
typedef struct {
- void *ptr_data[2];
+ const void *ptr_data[2];
unsigned int_data;
} CXSourceLocation;
@@ -353,7 +371,7 @@ typedef struct {
* starting and end locations from a source range, respectively.
*/
typedef struct {
- void *ptr_data[2];
+ const void *ptr_data[2];
unsigned begin_int_data;
unsigned end_int_data;
} CXSourceRange;
@@ -361,7 +379,7 @@ typedef struct {
/**
* \brief Retrieve a NULL (invalid) source location.
*/
-CINDEX_LINKAGE CXSourceLocation clang_getNullLocation();
+CINDEX_LINKAGE CXSourceLocation clang_getNullLocation(void);
/**
* \brief Determine whether two source locations, which must refer into
@@ -393,7 +411,7 @@ CINDEX_LINKAGE CXSourceLocation clang_getLocationForOffset(CXTranslationUnit tu,
/**
* \brief Retrieve a NULL (invalid) source range.
*/
-CINDEX_LINKAGE CXSourceRange clang_getNullRange();
+CINDEX_LINKAGE CXSourceRange clang_getNullRange(void);
/**
* \brief Retrieve a source range given the beginning and ending source
@@ -531,6 +549,35 @@ CINDEX_LINKAGE void clang_getSpellingLocation(CXSourceLocation location,
unsigned *offset);
/**
+ * \brief Retrieve the file, line, column, and offset represented by
+ * the given source location.
+ *
+ * If the location refers into a macro expansion, return where the macro was
+ * expanded or where the macro argument was written, if the location points at
+ * a macro argument.
+ *
+ * \param location the location within a source file that will be decomposed
+ * into its parts.
+ *
+ * \param file [out] if non-NULL, will be set to the file to which the given
+ * source location points.
+ *
+ * \param line [out] if non-NULL, will be set to the line to which the given
+ * source location points.
+ *
+ * \param column [out] if non-NULL, will be set to the column to which the given
+ * source location points.
+ *
+ * \param offset [out] if non-NULL, will be set to the offset into the
+ * buffer to which the given source location points.
+ */
+CINDEX_LINKAGE void clang_getFileLocation(CXSourceLocation location,
+ CXFile *file,
+ unsigned *line,
+ unsigned *column,
+ unsigned *offset);
+
+/**
* \brief Retrieve a source location representing the first character within a
* source range.
*/
@@ -2072,7 +2119,7 @@ enum CXCursorKind {
typedef struct {
enum CXCursorKind kind;
int xdata;
- void *data[3];
+ const void *data[3];
} CXCursor;
/**
@@ -2330,7 +2377,7 @@ typedef struct CXCursorSetImpl *CXCursorSet;
/**
* \brief Creates an empty CXCursorSet.
*/
-CINDEX_LINKAGE CXCursorSet clang_createCXCursorSet();
+CINDEX_LINKAGE CXCursorSet clang_createCXCursorSet(void);
/**
* \brief Disposes a CXCursorSet and releases its associated memory.
@@ -2626,6 +2673,7 @@ enum CXCallingConv {
CXCallingConv_AAPCS = 6,
CXCallingConv_AAPCS_VFP = 7,
CXCallingConv_PnaclCall = 8,
+ CXCallingConv_IntelOclBicc = 9,
CXCallingConv_Invalid = 100,
CXCallingConv_Unexposed = 200
@@ -2647,6 +2695,14 @@ typedef struct {
CINDEX_LINKAGE CXType clang_getCursorType(CXCursor C);
/**
+ * \brief Pretty-print the underlying type using the rules of the
+ * language of the translation unit from which it came.
+ *
+ * If the type is invalid, an empty string is returned.
+ */
+CINDEX_LINKAGE CXString clang_getTypeSpelling(CXType CT);
+
+/**
* \brief Retrieve the underlying type of a typedef declaration.
*
* If the cursor does not reference a typedef declaration, an invalid type is
@@ -2683,18 +2739,27 @@ CINDEX_LINKAGE long long clang_getEnumConstantDeclValue(CXCursor C);
CINDEX_LINKAGE unsigned long long clang_getEnumConstantDeclUnsignedValue(CXCursor C);
/**
+ * \brief Retrieve the bit width of a bit field declaration as an integer.
+ *
+ * If a cursor that is not a bit field declaration is passed in, -1 is returned.
+ */
+CINDEX_LINKAGE int clang_getFieldDeclBitWidth(CXCursor C);
+
+/**
* \brief Retrieve the number of non-variadic arguments associated with a given
* cursor.
*
- * If a cursor that is not a function or method is passed in, -1 is returned.
+ * The number of arguments can be determined for calls as well as for
+ * declarations of functions or methods. For other cursors -1 is returned.
*/
CINDEX_LINKAGE int clang_Cursor_getNumArguments(CXCursor C);
/**
* \brief Retrieve the argument cursor of a function or method.
*
- * If a cursor that is not a function or method is passed in or the index
- * exceeds the number of arguments, an invalid cursor is returned.
+ * The argument cursor can be determined for calls as well as for declarations
+ * of functions or methods. For other cursors and for invalid indices, an
+ * invalid cursor is returned.
*/
CINDEX_LINKAGE CXCursor clang_Cursor_getArgument(CXCursor C, unsigned i);
@@ -3284,7 +3349,8 @@ CINDEX_LINKAGE CXString clang_Module_getFullName(CXModule Module);
*
* \returns the number of top level headers associated with this module.
*/
-CINDEX_LINKAGE unsigned clang_Module_getNumTopLevelHeaders(CXModule Module);
+CINDEX_LINKAGE unsigned clang_Module_getNumTopLevelHeaders(CXTranslationUnit,
+ CXModule Module);
/**
* \param Module a module object.
@@ -3294,7 +3360,8 @@ CINDEX_LINKAGE unsigned clang_Module_getNumTopLevelHeaders(CXModule Module);
* \returns the specified top level header associated with the module.
*/
CINDEX_LINKAGE
-CXFile clang_Module_getTopLevelHeader(CXModule Module, unsigned Index);
+CXFile clang_Module_getTopLevelHeader(CXTranslationUnit,
+ CXModule Module, unsigned Index);
/**
* @}
@@ -4828,7 +4895,7 @@ CXString clang_codeCompleteGetObjCSelector(CXCodeCompleteResults *Results);
* \brief Return a version string, suitable for showing to a user, but not
* intended to be parsed (the format is not guaranteed to be stable).
*/
-CINDEX_LINKAGE CXString clang_getClangVersion();
+CINDEX_LINKAGE CXString clang_getClangVersion(void);
/**
@@ -4943,6 +5010,23 @@ typedef struct {
enum CXVisitorResult (*visit)(void *context, CXCursor, CXSourceRange);
} CXCursorAndRangeVisitor;
+typedef enum {
+ /**
+ * \brief Function returned successfully.
+ */
+ CXResult_Success = 0,
+ /**
+ * \brief One of the parameters was invalid for the function.
+ */
+ CXResult_Invalid = 1,
+ /**
+ * \brief The function was terminated by a callback (e.g. it returned
+ * CXVisit_Break)
+ */
+ CXResult_VisitBreak = 2
+
+} CXResult;
+
/**
* \brief Find references of a declaration in a specific file.
*
@@ -4954,10 +5038,28 @@ typedef struct {
* each reference found.
* The CXSourceRange will point inside the file; if the reference is inside
* a macro (and not a macro argument) the CXSourceRange will be invalid.
+ *
+ * \returns one of the CXResult enumerators.
*/
-CINDEX_LINKAGE void clang_findReferencesInFile(CXCursor cursor, CXFile file,
+CINDEX_LINKAGE CXResult clang_findReferencesInFile(CXCursor cursor, CXFile file,
CXCursorAndRangeVisitor visitor);
+/**
+ * \brief Find #import/#include directives in a specific file.
+ *
+ * \param TU translation unit containing the file to query.
+ *
+ * \param file to search for #import/#include directives.
+ *
+ * \param visitor callback that will receive pairs of CXCursor/CXSourceRange for
+ * each directive found.
+ *
+ * \returns one of the CXResult enumerators.
+ */
+CINDEX_LINKAGE CXResult clang_findIncludesInFile(CXTranslationUnit TU,
+ CXFile file,
+ CXCursorAndRangeVisitor visitor);
+
#ifdef __has_feature
# if __has_feature(blocks)
@@ -4965,8 +5067,12 @@ typedef enum CXVisitorResult
(^CXCursorAndRangeVisitorBlock)(CXCursor, CXSourceRange);
CINDEX_LINKAGE
-void clang_findReferencesInFileWithBlock(CXCursor, CXFile,
- CXCursorAndRangeVisitorBlock);
+CXResult clang_findReferencesInFileWithBlock(CXCursor, CXFile,
+ CXCursorAndRangeVisitorBlock);
+
+CINDEX_LINKAGE
+CXResult clang_findIncludesInFileWithBlock(CXTranslationUnit, CXFile,
+ CXCursorAndRangeVisitorBlock);
# endif
#endif
@@ -5144,6 +5250,10 @@ typedef struct {
CXIdxLoc classLoc;
} CXIdxIBOutletCollectionAttrInfo;
+typedef enum {
+ CXIdxDeclFlag_Skipped = 0x1
+} CXIdxDeclInfoFlags;
+
typedef struct {
const CXIdxEntityInfo *entityInfo;
CXCursor cursor;
@@ -5165,6 +5275,9 @@ typedef struct {
int isImplicit;
const CXIdxAttrInfo *const *attributes;
unsigned numAttributes;
+
+ unsigned flags;
+
} CXIdxDeclInfo;
typedef enum {
@@ -5372,16 +5485,14 @@ CINDEX_LINKAGE void
clang_index_setClientEntity(const CXIdxEntityInfo *, CXIdxClientEntity);
/**
- * \brief An indexing action, to be applied to one or multiple translation units
- * but not on concurrent threads. If there are threads doing indexing
- * concurrently, they should use different CXIndexAction objects.
+ * \brief An indexing action/session, to be applied to one or multiple
+ * translation units.
*/
typedef void *CXIndexAction;
/**
- * \brief An indexing action, to be applied to one or multiple translation units
- * but not on concurrent threads. If there are threads doing indexing
- * concurrently, they should use different CXIndexAction objects.
+ * \brief An indexing action/session, to be applied to one or multiple
+ * translation units.
*
* \param CIdx The index object with which the index action will be associated.
*/
@@ -5423,7 +5534,15 @@ typedef enum {
/**
* \brief Suppress all compiler warnings when parsing for indexing.
*/
- CXIndexOpt_SuppressWarnings = 0x8
+ CXIndexOpt_SuppressWarnings = 0x8,
+
+ /**
+ * \brief Skip a function/method body that was already parsed during an
+ * indexing session assosiated with a \c CXIndexAction object.
+ * Bodies in system headers are always skipped.
+ */
+ CXIndexOpt_SkipParsedBodiesInSession = 0x10
+
} CXIndexOptFlags;
/**
diff --git a/include/clang/ARCMigrate/ARCMT.h b/include/clang/ARCMigrate/ARCMT.h
index cce8661..c167d3c 100644
--- a/include/clang/ARCMigrate/ARCMT.h
+++ b/include/clang/ARCMigrate/ARCMT.h
@@ -11,8 +11,8 @@
#define LLVM_CLANG_ARCMIGRATE_ARCMT_H
#include "clang/ARCMigrate/FileRemapper.h"
-#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Basic/SourceLocation.h"
+#include "clang/Frontend/CompilerInvocation.h"
namespace clang {
class ASTContext;
diff --git a/include/clang/ARCMigrate/ARCMTActions.h b/include/clang/ARCMigrate/ARCMTActions.h
index e075252..2daaf73 100644
--- a/include/clang/ARCMigrate/ARCMTActions.h
+++ b/include/clang/ARCMigrate/ARCMTActions.h
@@ -10,8 +10,8 @@
#ifndef LLVM_CLANG_ARCMIGRATE_ARCMT_ACTION_H
#define LLVM_CLANG_ARCMIGRATE_ARCMT_ACTION_H
-#include "clang/Frontend/FrontendAction.h"
#include "clang/ARCMigrate/FileRemapper.h"
+#include "clang/Frontend/FrontendAction.h"
#include "llvm/ADT/OwningPtr.h"
namespace clang {
diff --git a/include/clang/ARCMigrate/FileRemapper.h b/include/clang/ARCMigrate/FileRemapper.h
index fe7cfad..94c9e8f 100644
--- a/include/clang/ARCMigrate/FileRemapper.h
+++ b/include/clang/ARCMigrate/FileRemapper.h
@@ -11,9 +11,9 @@
#define LLVM_CLANG_ARCMIGRATE_FILEREMAPPER_H
#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/PointerUnion.h"
-#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringRef.h"
namespace llvm {
diff --git a/include/clang/AST/APValue.h b/include/clang/AST/APValue.h
index 1b6e90c..ec8faa4 100644
--- a/include/clang/AST/APValue.h
+++ b/include/clang/AST/APValue.h
@@ -15,8 +15,8 @@
#define LLVM_CLANG_AST_APVALUE_H
#include "clang/Basic/LLVM.h"
-#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/PointerUnion.h"
diff --git a/include/clang/AST/AST.h b/include/clang/AST/AST.h
index 164c5fb..6db351d 100644
--- a/include/clang/AST/AST.h
+++ b/include/clang/AST/AST.h
@@ -22,7 +22,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
-#include "clang/AST/Type.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/Type.h"
#endif
diff --git a/include/clang/AST/ASTConsumer.h b/include/clang/AST/ASTConsumer.h
index 37b0740..ae77943 100644
--- a/include/clang/AST/ASTConsumer.h
+++ b/include/clang/AST/ASTConsumer.h
@@ -17,9 +17,9 @@
namespace clang {
class ASTContext;
class CXXRecordDecl;
+ class Decl;
class DeclGroupRef;
class HandleTagDeclDefinition;
- class PPMutationListener;
class ASTMutationListener;
class ASTDeserializationListener; // layering violation because void* is ugly
class SemaConsumer; // layering violation required for safe SemaConsumer
@@ -112,11 +112,6 @@ public:
/// it was actually used.
virtual void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) {}
- /// \brief If the consumer is interested in preprocessor entities getting
- /// modified after their initial creation, it should return a pointer to
- /// a PPMutationListener here.
- virtual PPMutationListener *GetPPMutationListener() { return 0; }
-
/// \brief If the consumer is interested in entities getting modified after
/// their initial creation, it should return a pointer to
/// an ASTMutationListener here.
@@ -130,6 +125,14 @@ public:
/// PrintStats - If desired, print any statistics.
virtual void PrintStats() {}
+
+ /// \brief This callback is called for each function if the Parser was
+ /// initialized with \c SkipFunctionBodies set to \c true.
+ ///
+ /// \return \c true if the function's body should be skipped. The function
+ /// body may be parsed anyway if it is needed (for instance, if it contains
+ /// the code completion point or is constexpr).
+ virtual bool shouldSkipFunctionBody(Decl *D) { return true; }
};
} // end namespace clang.
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index f0934b7..d4878a9 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -15,21 +15,23 @@
#ifndef LLVM_CLANG_AST_ASTCONTEXT_H
#define LLVM_CLANG_AST_ASTCONTEXT_H
-#include "clang/Basic/AddressSpaces.h"
-#include "clang/Basic/IdentifierTable.h"
-#include "clang/Basic/LangOptions.h"
-#include "clang/Basic/OperatorKinds.h"
-#include "clang/Basic/PartialDiagnostic.h"
-#include "clang/Basic/VersionTuple.h"
+#include "clang/AST/ASTTypeTraits.h"
+#include "clang/AST/CanonicalType.h"
+#include "clang/AST/CommentCommandTraits.h"
#include "clang/AST/Decl.h"
#include "clang/AST/LambdaMangleContext.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/RawCommentList.h"
+#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
-#include "clang/AST/CanonicalType.h"
-#include "clang/AST/RawCommentList.h"
-#include "clang/AST/CommentCommandTraits.h"
+#include "clang/Basic/AddressSpaces.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/OperatorKinds.h"
+#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/VersionTuple.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
@@ -57,28 +59,12 @@ namespace clang {
class TargetInfo;
class CXXABI;
// Decls
- class DeclContext;
- class CXXConversionDecl;
- class CXXMethodDecl;
- class CXXRecordDecl;
- class Decl;
- class FieldDecl;
class MangleContext;
class ObjCIvarDecl;
- class ObjCIvarRefExpr;
class ObjCPropertyDecl;
- class ParmVarDecl;
- class RecordDecl;
- class StoredDeclsMap;
- class TagDecl;
- class TemplateTemplateParmDecl;
- class TemplateTypeParmDecl;
- class TranslationUnitDecl;
- class TypeDecl;
- class TypedefNameDecl;
+ class UnresolvedSetIterator;
class UsingDecl;
class UsingShadowDecl;
- class UnresolvedSetIterator;
namespace Builtin { class Context; }
@@ -91,7 +77,7 @@ namespace clang {
class ASTContext : public RefCountedBase<ASTContext> {
ASTContext &this_() { return *this; }
- mutable std::vector<Type*> Types;
+ mutable SmallVector<Type *, 0> Types;
mutable llvm::FoldingSet<ExtQuals> ExtQualNodes;
mutable llvm::FoldingSet<ComplexType> ComplexTypes;
mutable llvm::FoldingSet<PointerType> PointerTypes;
@@ -233,6 +219,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
QualType ObjCConstantStringType;
mutable RecordDecl *CFConstantStringTypeDecl;
+ mutable QualType ObjCSuperType;
+
QualType ObjCNSStringType;
/// \brief The typedef declaration for the Objective-C "instancetype" type.
@@ -343,7 +331,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// \brief Mapping from each declaration context to its corresponding lambda
/// mangling context.
llvm::DenseMap<const DeclContext *, LambdaMangleContext> LambdaMangleContexts;
-
+
+ llvm::DenseMap<const DeclContext *, unsigned> UnnamedMangleContexts;
+ llvm::DenseMap<const TagDecl *, unsigned> UnnamedMangleNumbers;
+
/// \brief Mapping that stores parameterIndex values for ParmVarDecls when
/// that value exceeds the bitfield size of ParmVarDeclBits.ParameterIndex.
typedef llvm::DenseMap<const VarDecl *, unsigned> ParameterIndexTable;
@@ -393,6 +384,58 @@ public:
OwningPtr<ExternalASTSource> ExternalSource;
ASTMutationListener *Listener;
+ /// \brief Contains parents of a node.
+ typedef llvm::SmallVector<ast_type_traits::DynTypedNode, 1> ParentVector;
+
+ /// \brief Maps from a node to its parents.
+ typedef llvm::DenseMap<const void *, ParentVector> ParentMap;
+
+ /// \brief Returns the parents of the given node.
+ ///
+ /// Note that this will lazily compute the parents of all nodes
+ /// and store them for later retrieval. Thus, the first call is O(n)
+ /// in the number of AST nodes.
+ ///
+ /// Caveats and FIXMEs:
+ /// Calculating the parent map over all AST nodes will need to load the
+ /// full AST. This can be undesirable in the case where the full AST is
+ /// expensive to create (for example, when using precompiled header
+ /// preambles). Thus, there are good opportunities for optimization here.
+ /// One idea is to walk the given node downwards, looking for references
+ /// to declaration contexts - once a declaration context is found, compute
+ /// the parent map for the declaration context; if that can satisfy the
+ /// request, loading the whole AST can be avoided. Note that this is made
+ /// more complex by statements in templates having multiple parents - those
+ /// problems can be solved by building closure over the templated parts of
+ /// the AST, which also avoids touching large parts of the AST.
+ /// Additionally, we will want to add an interface to already give a hint
+ /// where to search for the parents, for example when looking at a statement
+ /// inside a certain function.
+ ///
+ /// 'NodeT' can be one of Decl, Stmt, Type, TypeLoc,
+ /// NestedNameSpecifier or NestedNameSpecifierLoc.
+ template <typename NodeT>
+ ParentVector getParents(const NodeT &Node) {
+ return getParents(ast_type_traits::DynTypedNode::create(Node));
+ }
+
+ ParentVector getParents(const ast_type_traits::DynTypedNode &Node) {
+ assert(Node.getMemoizationData() &&
+ "Invariant broken: only nodes that support memoization may be "
+ "used in the parent map.");
+ if (!AllParents) {
+ // We always need to run over the whole translation unit, as
+ // hasAncestor can escape any subtree.
+ AllParents.reset(
+ ParentMapASTVisitor::buildMap(*getTranslationUnitDecl()));
+ }
+ ParentMap::const_iterator I = AllParents->find(Node.getMemoizationData());
+ if (I == AllParents->end()) {
+ return ParentVector();
+ }
+ return I->second;
+ }
+
const clang::PrintingPolicy &getPrintingPolicy() const {
return PrintingPolicy;
}
@@ -713,6 +756,10 @@ public:
CanQualType PseudoObjectTy, ARCUnbridgedCastTy;
CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy;
CanQualType ObjCBuiltinBoolTy;
+ CanQualType OCLImage1dTy, OCLImage1dArrayTy, OCLImage1dBufferTy;
+ CanQualType OCLImage2dTy, OCLImage2dArrayTy;
+ CanQualType OCLImage3dTy;
+ CanQualType OCLSamplerTy, OCLEventTy;
// Types for deductions in C++0x [stmt.ranged]'s desugaring. Built on demand.
mutable QualType AutoDeductTy; // Deduction against 'auto'.
@@ -755,7 +802,7 @@ public:
ASTMutationListener *getASTMutationListener() const { return Listener; }
void PrintStats() const;
- const std::vector<Type*>& getTypes() const { return Types; }
+ const SmallVectorImpl<Type *>& getTypes() const { return Types; }
/// \brief Retrieve the declaration for the 128-bit signed integer type.
TypedefDecl *getInt128Decl() const;
@@ -857,12 +904,17 @@ public:
return cudaConfigureCallDecl;
}
- /// Builds the struct used for __block variables.
- QualType BuildByRefType(StringRef DeclName, QualType Ty) const;
-
/// Returns true iff we need copy/dispose helpers for the given type.
- bool BlockRequiresCopying(QualType Ty) const;
-
+ bool BlockRequiresCopying(QualType Ty, const VarDecl *D);
+
+
+ /// Returns true, if given type has a known lifetime. HasByrefExtendedLayout is set
+ /// to false in this case. If HasByrefExtendedLayout returns true, byref variable
+ /// has extended lifetime.
+ bool getByrefLifetime(QualType Ty,
+ Qualifiers::ObjCLifetime &Lifetime,
+ bool &HasByrefExtendedLayout) const;
+
/// \brief Return the uniqued reference to the type for an lvalue reference
/// to the specified type.
QualType getLValueReferenceType(QualType T, bool SpelledAsLValue = true)
@@ -941,8 +993,7 @@ public:
}
/// \brief Return a normal function type with a typed argument list.
- QualType getFunctionType(QualType ResultTy,
- const QualType *Args, unsigned NumArgs,
+ QualType getFunctionType(QualType ResultTy, ArrayRef<QualType> Args,
const FunctionProtoType::ExtProtoInfo &EPI) const;
/// \brief Return the unique reference to the type for the specified type
@@ -1025,7 +1076,7 @@ public:
const TemplateArgument *Args) const;
QualType getPackExpansionType(QualType Pattern,
- llvm::Optional<unsigned> NumExpansions);
+ Optional<unsigned> NumExpansions);
QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl,
ObjCInterfaceDecl *PrevDecl = 0) const;
@@ -1094,6 +1145,14 @@ public:
/// defined in <stddef.h> as defined by the target.
QualType getWIntType() const { return WIntTy; }
+ /// \brief Return a type compatible with "intptr_t" (C99 7.18.1.4),
+ /// as defined by the target.
+ QualType getIntPtrType() const;
+
+ /// \brief Return a type compatible with "uintptr_t" (C99 7.18.1.4),
+ /// as defined by the target.
+ QualType getUIntPtrType() const;
+
/// \brief Return the unique type for "ptrdiff_t" (C99 7.17) defined in
/// <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9).
QualType getPointerDiffType() const;
@@ -1104,7 +1163,11 @@ public:
/// \brief Return the C structure type used to represent constant CFStrings.
QualType getCFConstantStringType() const;
-
+
+ /// \brief Returns the C struct type for objc_super
+ QualType getObjCSuperType() const;
+ void setObjCSuperType(QualType ST) { ObjCSuperType = ST; }
+
/// Get the structure type used to representation CFStrings, or NULL
/// if it hasn't yet been built.
QualType getRawCFConstantStringType() const {
@@ -1545,14 +1608,27 @@ public:
const ASTRecordLayout &
getASTObjCImplementationLayout(const ObjCImplementationDecl *D) const;
- /// \brief Get the key function for the given record decl, or NULL if there
- /// isn't one.
+ /// \brief Get our current best idea for the key function of the
+ /// given record decl, or NULL if there isn't one.
///
/// The key function is, according to the Itanium C++ ABI section 5.2.3:
+ /// ...the first non-pure virtual function that is not inline at the
+ /// point of class definition.
///
- /// ...the first non-pure virtual function that is not inline at the point
- /// of class definition.
- const CXXMethodDecl *getKeyFunction(const CXXRecordDecl *RD);
+ /// Other ABIs use the same idea. However, the ARM C++ ABI ignores
+ /// virtual functions that are defined 'inline', which means that
+ /// the result of this computation can change.
+ const CXXMethodDecl *getCurrentKeyFunction(const CXXRecordDecl *RD);
+
+ /// \brief Observe that the given method cannot be a key function.
+ /// Checks the key-function cache for the method's class and clears it
+ /// if matches the given declaration.
+ ///
+ /// This is used in ABIs where out-of-line definitions marked
+ /// inline are not considered to be key functions.
+ ///
+ /// \param method should be the declaration from the class definition
+ void setNonKeyFunction(const CXXMethodDecl *method);
/// Get the offset of a FieldDecl or IndirectFieldDecl, in bits.
uint64_t getFieldOffset(const ValueDecl *FD) const;
@@ -1885,8 +1961,8 @@ public:
// Type Iterators.
//===--------------------------------------------------------------------===//
- typedef std::vector<Type*>::iterator type_iterator;
- typedef std::vector<Type*>::const_iterator const_type_iterator;
+ typedef SmallVectorImpl<Type *>::iterator type_iterator;
+ typedef SmallVectorImpl<Type *>::const_iterator const_type_iterator;
type_iterator types_begin() { return Types.begin(); }
type_iterator types_end() { return Types.end(); }
@@ -1943,7 +2019,7 @@ public:
/// \brief Returns the Objective-C interface that \p ND belongs to if it is
/// an Objective-C method/property/ivar etc. that is part of an interface,
/// otherwise returns null.
- ObjCInterfaceDecl *getObjContainingInterface(NamedDecl *ND) const;
+ const ObjCInterfaceDecl *getObjContainingInterface(const NamedDecl *ND) const;
/// \brief Set the copy inialization expression of a block var decl.
void setBlockVarCopyInits(VarDecl*VD, Expr* Init);
@@ -1993,6 +2069,9 @@ public:
/// it is not used.
bool DeclMustBeEmitted(const Decl *D);
+ void addUnnamedTag(const TagDecl *Tag);
+ int getUnnamedTagManglingNumber(const TagDecl *Tag) const;
+
/// \brief Retrieve the lambda mangling number for a lambda expression.
unsigned getLambdaManglingNumber(CXXMethodDecl *CallOperator);
@@ -2077,7 +2156,8 @@ private:
bool EncodingProperty = false,
bool StructField = false,
bool EncodeBlockParameters = false,
- bool EncodeClassNames = false) const;
+ bool EncodeClassNames = false,
+ bool EncodePointerToObjCTypedef = false) const;
// Adds the encoding of the structure's members.
void getObjCEncodingForStructureImpl(RecordDecl *RD, std::string &S,
@@ -2109,8 +2189,81 @@ private:
friend class DeclContext;
friend class DeclarationNameTable;
void ReleaseDeclContextMaps();
+
+ /// \brief A \c RecursiveASTVisitor that builds a map from nodes to their
+ /// parents as defined by the \c RecursiveASTVisitor.
+ ///
+ /// Note that the relationship described here is purely in terms of AST
+ /// traversal - there are other relationships (for example declaration context)
+ /// in the AST that are better modeled by special matchers.
+ ///
+ /// FIXME: Currently only builds up the map using \c Stmt and \c Decl nodes.
+ class ParentMapASTVisitor : public RecursiveASTVisitor<ParentMapASTVisitor> {
+ public:
+ /// \brief Builds and returns the translation unit's parent map.
+ ///
+ /// The caller takes ownership of the returned \c ParentMap.
+ static ParentMap *buildMap(TranslationUnitDecl &TU) {
+ ParentMapASTVisitor Visitor(new ParentMap);
+ Visitor.TraverseDecl(&TU);
+ return Visitor.Parents;
+ }
+
+ private:
+ typedef RecursiveASTVisitor<ParentMapASTVisitor> VisitorBase;
+
+ ParentMapASTVisitor(ParentMap *Parents) : Parents(Parents) {
+ }
+
+ bool shouldVisitTemplateInstantiations() const {
+ return true;
+ }
+ bool shouldVisitImplicitCode() const {
+ return true;
+ }
+ // Disables data recursion. We intercept Traverse* methods in the RAV, which
+ // are not triggered during data recursion.
+ bool shouldUseDataRecursionFor(clang::Stmt *S) const {
+ return false;
+ }
+
+ template <typename T>
+ bool TraverseNode(T *Node, bool(VisitorBase:: *traverse) (T *)) {
+ if (Node == NULL)
+ return true;
+ if (ParentStack.size() > 0)
+ // FIXME: Currently we add the same parent multiple times, for example
+ // when we visit all subexpressions of template instantiations; this is
+ // suboptimal, bug benign: the only way to visit those is with
+ // hasAncestor / hasParent, and those do not create new matches.
+ // The plan is to enable DynTypedNode to be storable in a map or hash
+ // map. The main problem there is to implement hash functions /
+ // comparison operators for all types that DynTypedNode supports that
+ // do not have pointer identity.
+ (*Parents)[Node].push_back(ParentStack.back());
+ ParentStack.push_back(ast_type_traits::DynTypedNode::create(*Node));
+ bool Result = (this ->* traverse) (Node);
+ ParentStack.pop_back();
+ return Result;
+ }
+
+ bool TraverseDecl(Decl *DeclNode) {
+ return TraverseNode(DeclNode, &VisitorBase::TraverseDecl);
+ }
+
+ bool TraverseStmt(Stmt *StmtNode) {
+ return TraverseNode(StmtNode, &VisitorBase::TraverseStmt);
+ }
+
+ ParentMap *Parents;
+ llvm::SmallVector<ast_type_traits::DynTypedNode, 16> ParentStack;
+
+ friend class RecursiveASTVisitor<ParentMapASTVisitor>;
+ };
+
+ llvm::OwningPtr<ParentMap> AllParents;
};
-
+
/// \brief Utility function for constructing a nullary selector.
static inline Selector GetNullarySelector(StringRef name, ASTContext& Ctx) {
IdentifierInfo* II = &Ctx.Idents.get(name);
@@ -2132,8 +2285,8 @@ static inline Selector GetUnarySelector(StringRef name, ASTContext& Ctx) {
/// This placement form of operator new uses the ASTContext's allocator for
/// obtaining memory.
///
-/// IMPORTANT: These are also declared in clang/AST/Attr.h! Any changes here
-/// need to also be made there.
+/// IMPORTANT: These are also declared in clang/AST/AttrIterator.h! Any changes
+/// here need to also be made there.
///
/// We intentionally avoid using a nothrow specification here so that the calls
/// to this operator will not perform a null check on the result -- the
diff --git a/include/clang/AST/ASTImporter.h b/include/clang/AST/ASTImporter.h
index 46a9881..1672ab2 100644
--- a/include/clang/AST/ASTImporter.h
+++ b/include/clang/AST/ASTImporter.h
@@ -48,6 +48,9 @@ namespace clang {
/// \brief Whether to perform a minimal import.
bool Minimal;
+
+ /// \brief Whether the last diagnostic came from the "from" context.
+ bool LastDiagFromFrom;
/// \brief Mapping from the already-imported types in the "from" context
/// to the corresponding types in the "to" context.
diff --git a/include/clang/AST/ASTMutationListener.h b/include/clang/AST/ASTMutationListener.h
index 56d1526..6b70285 100644
--- a/include/clang/AST/ASTMutationListener.h
+++ b/include/clang/AST/ASTMutationListener.h
@@ -16,18 +16,19 @@
#include "clang/Basic/SourceLocation.h"
namespace clang {
- class Decl;
- class DeclContext;
- class TagDecl;
class CXXRecordDecl;
class ClassTemplateDecl;
class ClassTemplateSpecializationDecl;
+ class Decl;
+ class DeclContext;
class FunctionDecl;
class FunctionTemplateDecl;
class ObjCCategoryDecl;
- class ObjCInterfaceDecl;
class ObjCContainerDecl;
+ class ObjCInterfaceDecl;
class ObjCPropertyDecl;
+ class TagDecl;
+ class VarDecl;
/// \brief An abstract interface that should be implemented by listeners
/// that want to be notified when an AST entity gets modified after its
diff --git a/include/clang/ASTMatchers/ASTTypeTraits.h b/include/clang/AST/ASTTypeTraits.h
index bda53ea..4688b12 100644
--- a/include/clang/ASTMatchers/ASTTypeTraits.h
+++ b/include/clang/AST/ASTTypeTraits.h
@@ -1,4 +1,4 @@
-//===--- ASTMatchersTypeTraits.h --------------------------------*- C++ -*-===//
+//===--- ASTTypeTraits.h ----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -12,11 +12,12 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H
-#define LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H
+#ifndef LLVM_CLANG_AST_AST_TYPE_TRAITS_H
+#define LLVM_CLANG_AST_AST_TYPE_TRAITS_H
#include "clang/AST/Decl.h"
#include "clang/AST/Stmt.h"
+#include "clang/AST/TypeLoc.h"
#include "llvm/Support/AlignOf.h"
namespace clang {
@@ -87,8 +88,9 @@ private:
/// guaranteed to be unique pointers pointing to dedicated storage in the
/// AST. \c QualTypes on the other hand do not have storage or unique
/// pointers and thus need to be stored by value.
- llvm::AlignedCharArrayUnion<Decl*, QualType, TypeLoc, NestedNameSpecifierLoc>
- Storage;
+ llvm::AlignedCharArrayUnion<Decl *, Stmt *, NestedNameSpecifier,
+ NestedNameSpecifierLoc, QualType, Type,
+ TypeLoc> Storage;
};
// FIXME: Pull out abstraction for the following.
@@ -206,4 +208,4 @@ inline const void *DynTypedNode::getMemoizationData() const {
} // end namespace ast_type_traits
} // end namespace clang
-#endif // LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H
+#endif // LLVM_CLANG_AST_AST_TYPE_TRAITS_H
diff --git a/include/clang/AST/ASTUnresolvedSet.h b/include/clang/AST/ASTUnresolvedSet.h
new file mode 100644
index 0000000..c709895
--- /dev/null
+++ b/include/clang/AST/ASTUnresolvedSet.h
@@ -0,0 +1,86 @@
+//===-- ASTUnresolvedSet.h - Unresolved sets of declarations ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides an UnresolvedSet-like class, whose contents are
+// allocated using the allocator associated with an ASTContext.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_ASTUNRESOLVEDSET_H
+#define LLVM_CLANG_AST_ASTUNRESOLVEDSET_H
+
+#include "clang/AST/ASTVector.h"
+#include "clang/AST/UnresolvedSet.h"
+
+namespace clang {
+
+/// \brief An UnresolvedSet-like class which uses the ASTContext's allocator.
+class ASTUnresolvedSet {
+ typedef ASTVector<DeclAccessPair> DeclsTy;
+ DeclsTy Decls;
+
+ ASTUnresolvedSet(const ASTUnresolvedSet &) LLVM_DELETED_FUNCTION;
+ void operator=(const ASTUnresolvedSet &) LLVM_DELETED_FUNCTION;
+
+public:
+ ASTUnresolvedSet() {}
+ ASTUnresolvedSet(ASTContext &C, unsigned N) : Decls(C, N) {}
+
+ typedef UnresolvedSetIterator iterator;
+ typedef UnresolvedSetIterator const_iterator;
+
+ iterator begin() { return iterator(Decls.begin()); }
+ iterator end() { return iterator(Decls.end()); }
+
+ const_iterator begin() const { return const_iterator(Decls.begin()); }
+ const_iterator end() const { return const_iterator(Decls.end()); }
+
+ void addDecl(ASTContext &C, NamedDecl *D) {
+ addDecl(C, D, AS_none);
+ }
+
+ void addDecl(ASTContext &C, NamedDecl *D, AccessSpecifier AS) {
+ Decls.push_back(DeclAccessPair::make(D, AS), C);
+ }
+
+ /// Replaces the given declaration with the new one, once.
+ ///
+ /// \return true if the set changed
+ bool replace(const NamedDecl* Old, NamedDecl *New) {
+ for (DeclsTy::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I)
+ if (I->getDecl() == Old)
+ return (I->setDecl(New), true);
+ return false;
+ }
+
+ void erase(unsigned I) {
+ Decls[I] = Decls.back();
+ Decls.pop_back();
+ }
+
+ void clear() { Decls.clear(); }
+
+ bool empty() const { return Decls.empty(); }
+ unsigned size() const { return Decls.size(); }
+
+ void reserve(ASTContext &C, unsigned N) {
+ Decls.reserve(C, N);
+ }
+
+ void append(ASTContext &C, iterator I, iterator E) {
+ Decls.append(C, I.ir, E.ir);
+ }
+
+ DeclAccessPair &operator[](unsigned I) { return Decls[I]; }
+ const DeclAccessPair &operator[](unsigned I) const { return Decls[I]; }
+};
+
+} // namespace clang
+
+#endif
diff --git a/include/clang/AST/ASTVector.h b/include/clang/AST/ASTVector.h
index 4ff5ea3..669e50d 100644
--- a/include/clang/AST/ASTVector.h
+++ b/include/clang/AST/ASTVector.h
@@ -18,12 +18,13 @@
#ifndef LLVM_CLANG_AST_VECTOR
#define LLVM_CLANG_AST_VECTOR
-#include "llvm/Support/type_traits.h"
-#include "llvm/Support/Allocator.h"
+#include "clang/AST/AttrIterator.h"
#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/type_traits.h"
#include <algorithm>
-#include <memory>
#include <cstring>
+#include <memory>
#ifdef _MSC_VER
namespace std {
@@ -50,6 +51,7 @@ namespace std {
#endif
namespace clang {
+ class ASTContext;
template<typename T>
class ASTVector {
@@ -59,7 +61,9 @@ class ASTVector {
public:
// Default ctor - Initialize to empty.
- explicit ASTVector(ASTContext &C, unsigned N = 0)
+ ASTVector() : Begin(NULL), End(NULL), Capacity(NULL) { }
+
+ ASTVector(ASTContext &C, unsigned N)
: Begin(NULL), End(NULL), Capacity(NULL) {
reserve(C, N);
}
diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h
index 12a9855..27dcef2 100644
--- a/include/clang/AST/Attr.h
+++ b/include/clang/AST/Attr.h
@@ -14,9 +14,10 @@
#ifndef LLVM_CLANG_AST_ATTR_H
#define LLVM_CLANG_AST_ATTR_H
-#include "clang/Basic/LLVM.h"
-#include "clang/Basic/AttrKinds.h"
+#include "clang/AST/AttrIterator.h"
#include "clang/AST/Type.h"
+#include "clang/Basic/AttrKinds.h"
+#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/VersionTuple.h"
#include "llvm/ADT/SmallVector.h"
@@ -26,7 +27,6 @@
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <cstring>
-#include <algorithm>
namespace clang {
class ASTContext;
@@ -36,23 +36,6 @@ namespace clang {
class QualType;
class FunctionDecl;
class TypeSourceInfo;
-}
-
-// Defined in ASTContext.h
-void *operator new(size_t Bytes, const clang::ASTContext &C,
- size_t Alignment = 16);
-// FIXME: Being forced to not have a default argument here due to redeclaration
-// rules on default arguments sucks
-void *operator new[](size_t Bytes, const clang::ASTContext &C,
- size_t Alignment);
-
-// It is good practice to pair new/delete operators. Also, MSVC gives many
-// warnings if a matching delete overload is not declared, even though the
-// throw() spec guarantees it will not be implicitly called.
-void operator delete(void *Ptr, const clang::ASTContext &C, size_t);
-void operator delete[](void *Ptr, const clang::ASTContext &C, size_t);
-
-namespace clang {
/// Attr - This represents one attribute.
class Attr {
@@ -61,10 +44,16 @@ private:
unsigned AttrKind : 16;
protected:
+ /// An index into the spelling list of an
+ /// attribute defined in Attr.td file.
+ unsigned SpellingListIndex : 4;
+
bool Inherited : 1;
+ bool IsPackExpansion : 1;
+
virtual ~Attr();
-
+
void* operator new(size_t bytes) throw() {
llvm_unreachable("Attrs cannot be allocated with regular 'new'.");
}
@@ -84,14 +73,17 @@ public:
}
protected:
- Attr(attr::Kind AK, SourceRange R)
- : Range(R), AttrKind(AK), Inherited(false) {}
+ Attr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex = 0)
+ : Range(R), AttrKind(AK), SpellingListIndex(SpellingListIndex),
+ Inherited(false), IsPackExpansion(false) {}
public:
attr::Kind getKind() const {
return static_cast<attr::Kind>(AttrKind);
}
+
+ unsigned getSpellingListIndex() const { return SpellingListIndex; }
SourceLocation getLocation() const { return Range.getBegin(); }
SourceRange getRange() const { return Range; }
@@ -99,21 +91,24 @@ public:
bool isInherited() const { return Inherited; }
+ void setPackExpansion(bool PE) { IsPackExpansion = PE; }
+ bool isPackExpansion() const { return IsPackExpansion; }
+
// Clone this attribute.
- virtual Attr* clone(ASTContext &C) const = 0;
+ virtual Attr *clone(ASTContext &C) const = 0;
virtual bool isLateParsed() const { return false; }
// Pretty print this attribute.
- virtual void printPretty(llvm::raw_ostream &OS,
+ virtual void printPretty(raw_ostream &OS,
const PrintingPolicy &Policy) const = 0;
};
class InheritableAttr : public Attr {
virtual void anchor();
protected:
- InheritableAttr(attr::Kind AK, SourceRange R)
- : Attr(AK, R) {}
+ InheritableAttr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex = 0)
+ : Attr(AK, R, SpellingListIndex) {}
public:
void setInherited(bool I) { Inherited = I; }
@@ -127,125 +122,35 @@ public:
class InheritableParamAttr : public InheritableAttr {
virtual void anchor();
protected:
- InheritableParamAttr(attr::Kind AK, SourceRange R)
- : InheritableAttr(AK, R) {}
+ InheritableParamAttr(attr::Kind AK, SourceRange R,
+ unsigned SpellingListIndex = 0)
+ : InheritableAttr(AK, R, SpellingListIndex) {}
public:
// Implement isa/cast/dyncast/etc.
static bool classof(const Attr *A) {
+ // Relies on relative order of enum emission with respect to MS inheritance
+ // attrs.
return A->getKind() <= attr::LAST_INHERITABLE_PARAM;
}
};
-#include "clang/AST/Attrs.inc"
-
-/// AttrVec - A vector of Attr, which is how they are stored on the AST.
-typedef SmallVector<Attr*, 2> AttrVec;
-typedef SmallVector<const Attr*, 2> ConstAttrVec;
-
-/// specific_attr_iterator - Iterates over a subrange of an AttrVec, only
-/// providing attributes that are of a specifc type.
-template <typename SpecificAttr, typename Container = AttrVec>
-class specific_attr_iterator {
- typedef typename Container::const_iterator Iterator;
-
- /// Current - The current, underlying iterator.
- /// In order to ensure we don't dereference an invalid iterator unless
- /// specifically requested, we don't necessarily advance this all the
- /// way. Instead, we advance it when an operation is requested; if the
- /// operation is acting on what should be a past-the-end iterator,
- /// then we offer no guarantees, but this way we do not dererence a
- /// past-the-end iterator when we move to a past-the-end position.
- mutable Iterator Current;
-
- void AdvanceToNext() const {
- while (!isa<SpecificAttr>(*Current))
- ++Current;
- }
-
- void AdvanceToNext(Iterator I) const {
- while (Current != I && !isa<SpecificAttr>(*Current))
- ++Current;
- }
+class MSInheritanceAttr : public InheritableAttr {
+ virtual void anchor();
+protected:
+ MSInheritanceAttr(attr::Kind AK, SourceRange R, unsigned SpellingListIndex = 0)
+ : InheritableAttr(AK, R, SpellingListIndex) {}
public:
- typedef SpecificAttr* value_type;
- typedef SpecificAttr* reference;
- typedef SpecificAttr* pointer;
- typedef std::forward_iterator_tag iterator_category;
- typedef std::ptrdiff_t difference_type;
-
- specific_attr_iterator() : Current() { }
- explicit specific_attr_iterator(Iterator i) : Current(i) { }
-
- reference operator*() const {
- AdvanceToNext();
- return cast<SpecificAttr>(*Current);
- }
- pointer operator->() const {
- AdvanceToNext();
- return cast<SpecificAttr>(*Current);
- }
-
- specific_attr_iterator& operator++() {
- ++Current;
- return *this;
- }
- specific_attr_iterator operator++(int) {
- specific_attr_iterator Tmp(*this);
- ++(*this);
- return Tmp;
- }
-
- friend bool operator==(specific_attr_iterator Left,
- specific_attr_iterator Right) {
- if (Left.Current < Right.Current)
- Left.AdvanceToNext(Right.Current);
- else
- Right.AdvanceToNext(Left.Current);
- return Left.Current == Right.Current;
- }
- friend bool operator!=(specific_attr_iterator Left,
- specific_attr_iterator Right) {
- return !(Left == Right);
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Attr *A) {
+ // Relies on relative order of enum emission with respect to param attrs.
+ return (A->getKind() <= attr::LAST_MS_INHERITABLE &&
+ A->getKind() > attr::LAST_INHERITABLE_PARAM);
}
};
-template <typename SpecificAttr, typename Container>
-inline specific_attr_iterator<SpecificAttr, Container>
- specific_attr_begin(const Container& container) {
- return specific_attr_iterator<SpecificAttr, Container>(container.begin());
-}
-template <typename SpecificAttr, typename Container>
-inline specific_attr_iterator<SpecificAttr, Container>
- specific_attr_end(const Container& container) {
- return specific_attr_iterator<SpecificAttr, Container>(container.end());
-}
-
-template <typename SpecificAttr, typename Container>
-inline bool hasSpecificAttr(const Container& container) {
- return specific_attr_begin<SpecificAttr>(container) !=
- specific_attr_end<SpecificAttr>(container);
-}
-template <typename SpecificAttr, typename Container>
-inline SpecificAttr *getSpecificAttr(const Container& container) {
- specific_attr_iterator<SpecificAttr, Container> i =
- specific_attr_begin<SpecificAttr>(container);
- if (i != specific_attr_end<SpecificAttr>(container))
- return *i;
- else
- return 0;
-}
-
-/// getMaxAlignment - Returns the highest alignment value found among
-/// AlignedAttrs in an AttrVec, or 0 if there are none.
-inline unsigned getMaxAttrAlignment(const AttrVec& V, ASTContext &Ctx) {
- unsigned Align = 0;
- specific_attr_iterator<AlignedAttr> i(V.begin()), e(V.end());
- for(; i != e; ++i)
- Align = std::max(Align, i->getAlignment(Ctx));
- return Align;
-}
+#include "clang/AST/Attrs.inc"
} // end namespace clang
diff --git a/include/clang/AST/AttrIterator.h b/include/clang/AST/AttrIterator.h
new file mode 100644
index 0000000..8bd8fbe
--- /dev/null
+++ b/include/clang/AST/AttrIterator.h
@@ -0,0 +1,142 @@
+//===--- AttrIterator.h - Classes for attribute iteration -------*- 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 Attr vector and specific_attr_iterator interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_ATTRITERATOR_H
+#define LLVM_CLANG_AST_ATTRITERATOR_H
+
+#include "clang/Basic/LLVM.h"
+#include <iterator>
+
+namespace clang {
+ class ASTContext;
+ class Attr;
+}
+
+// Defined in ASTContext.h
+void *operator new(size_t Bytes, const clang::ASTContext &C,
+ size_t Alignment = 16);
+// FIXME: Being forced to not have a default argument here due to redeclaration
+// rules on default arguments sucks
+void *operator new[](size_t Bytes, const clang::ASTContext &C,
+ size_t Alignment);
+
+// It is good practice to pair new/delete operators. Also, MSVC gives many
+// warnings if a matching delete overload is not declared, even though the
+// throw() spec guarantees it will not be implicitly called.
+void operator delete(void *Ptr, const clang::ASTContext &C, size_t);
+void operator delete[](void *Ptr, const clang::ASTContext &C, size_t);
+
+namespace clang {
+
+/// AttrVec - A vector of Attr, which is how they are stored on the AST.
+typedef SmallVector<Attr*, 2> AttrVec;
+typedef SmallVector<const Attr*, 2> ConstAttrVec;
+
+/// specific_attr_iterator - Iterates over a subrange of an AttrVec, only
+/// providing attributes that are of a specifc type.
+template <typename SpecificAttr, typename Container = AttrVec>
+class specific_attr_iterator {
+ typedef typename Container::const_iterator Iterator;
+
+ /// Current - The current, underlying iterator.
+ /// In order to ensure we don't dereference an invalid iterator unless
+ /// specifically requested, we don't necessarily advance this all the
+ /// way. Instead, we advance it when an operation is requested; if the
+ /// operation is acting on what should be a past-the-end iterator,
+ /// then we offer no guarantees, but this way we do not dererence a
+ /// past-the-end iterator when we move to a past-the-end position.
+ mutable Iterator Current;
+
+ void AdvanceToNext() const {
+ while (!isa<SpecificAttr>(*Current))
+ ++Current;
+ }
+
+ void AdvanceToNext(Iterator I) const {
+ while (Current != I && !isa<SpecificAttr>(*Current))
+ ++Current;
+ }
+
+public:
+ typedef SpecificAttr* value_type;
+ typedef SpecificAttr* reference;
+ typedef SpecificAttr* pointer;
+ typedef std::forward_iterator_tag iterator_category;
+ typedef std::ptrdiff_t difference_type;
+
+ specific_attr_iterator() : Current() { }
+ explicit specific_attr_iterator(Iterator i) : Current(i) { }
+
+ reference operator*() const {
+ AdvanceToNext();
+ return cast<SpecificAttr>(*Current);
+ }
+ pointer operator->() const {
+ AdvanceToNext();
+ return cast<SpecificAttr>(*Current);
+ }
+
+ specific_attr_iterator& operator++() {
+ ++Current;
+ return *this;
+ }
+ specific_attr_iterator operator++(int) {
+ specific_attr_iterator Tmp(*this);
+ ++(*this);
+ return Tmp;
+ }
+
+ friend bool operator==(specific_attr_iterator Left,
+ specific_attr_iterator Right) {
+ assert((Left.Current == 0) == (Right.Current == 0));
+ if (Left.Current < Right.Current)
+ Left.AdvanceToNext(Right.Current);
+ else
+ Right.AdvanceToNext(Left.Current);
+ return Left.Current == Right.Current;
+ }
+ friend bool operator!=(specific_attr_iterator Left,
+ specific_attr_iterator Right) {
+ return !(Left == Right);
+ }
+};
+
+template <typename SpecificAttr, typename Container>
+inline specific_attr_iterator<SpecificAttr, Container>
+ specific_attr_begin(const Container& container) {
+ return specific_attr_iterator<SpecificAttr, Container>(container.begin());
+}
+template <typename SpecificAttr, typename Container>
+inline specific_attr_iterator<SpecificAttr, Container>
+ specific_attr_end(const Container& container) {
+ return specific_attr_iterator<SpecificAttr, Container>(container.end());
+}
+
+template <typename SpecificAttr, typename Container>
+inline bool hasSpecificAttr(const Container& container) {
+ return specific_attr_begin<SpecificAttr>(container) !=
+ specific_attr_end<SpecificAttr>(container);
+}
+template <typename SpecificAttr, typename Container>
+inline SpecificAttr *getSpecificAttr(const Container& container) {
+ specific_attr_iterator<SpecificAttr, Container> i =
+ specific_attr_begin<SpecificAttr>(container);
+ if (i != specific_attr_end<SpecificAttr>(container))
+ return *i;
+ else
+ return 0;
+}
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/AST/BuiltinTypes.def b/include/clang/AST/BuiltinTypes.def
index ba322fb..488cace 100644
--- a/include/clang/AST/BuiltinTypes.def
+++ b/include/clang/AST/BuiltinTypes.def
@@ -154,6 +154,20 @@ BUILTIN_TYPE(ObjCClass, ObjCBuiltinClassTy)
// type is a typedef of a PointerType to this.
BUILTIN_TYPE(ObjCSel, ObjCBuiltinSelTy)
+// OpenCL image types.
+BUILTIN_TYPE(OCLImage1d, OCLImage1dTy)
+BUILTIN_TYPE(OCLImage1dArray, OCLImage1dArrayTy)
+BUILTIN_TYPE(OCLImage1dBuffer, OCLImage1dBufferTy)
+BUILTIN_TYPE(OCLImage2d, OCLImage2dTy)
+BUILTIN_TYPE(OCLImage2dArray, OCLImage2dArrayTy)
+BUILTIN_TYPE(OCLImage3d, OCLImage3dTy)
+
+// OpenCL sampler_t.
+BUILTIN_TYPE(OCLSampler, OCLSamplerTy)
+
+// OpenCL event_t.
+BUILTIN_TYPE(OCLEvent, OCLEventTy)
+
// This represents the type of an expression whose type is
// totally unknown, e.g. 'T::foo'. It is permitted for this to
// appear in situations where the structure of the type is
diff --git a/include/clang/AST/CMakeLists.txt b/include/clang/AST/CMakeLists.txt
index 4c4c0fb..ba54fa2 100644
--- a/include/clang/AST/CMakeLists.txt
+++ b/include/clang/AST/CMakeLists.txt
@@ -8,6 +8,11 @@ clang_tablegen(AttrImpl.inc -gen-clang-attr-impl
SOURCE ../Basic/Attr.td
TARGET ClangAttrImpl)
+clang_tablegen(AttrDump.inc -gen-clang-attr-dump
+ -I ${CMAKE_CURRENT_SOURCE_DIR}/../../
+ SOURCE ../Basic/Attr.td
+ TARGET ClangAttrDump)
+
clang_tablegen(StmtNodes.inc -gen-clang-stmt-nodes
SOURCE ../Basic/StmtNodes.td
TARGET ClangStmtNodes)
@@ -28,7 +33,15 @@ clang_tablegen(CommentHTMLTagsProperties.inc -gen-clang-comment-html-tags-proper
SOURCE CommentHTMLTags.td
TARGET ClangCommentHTMLTagsProperties)
+clang_tablegen(CommentHTMLNamedCharacterReferences.inc -gen-clang-comment-html-named-character-references
+ SOURCE CommentHTMLNamedCharacterReferences.td
+ TARGET ClangCommentHTMLNamedCharacterReferences)
+
clang_tablegen(CommentCommandInfo.inc -gen-clang-comment-command-info
SOURCE CommentCommands.td
TARGET ClangCommentCommandInfo)
+clang_tablegen(CommentCommandList.inc -gen-clang-comment-command-list
+ SOURCE CommentCommands.td
+ TARGET ClangCommentCommandList)
+
diff --git a/include/clang/AST/CXXInheritance.h b/include/clang/AST/CXXInheritance.h
index 87bdbe0..2983e04 100644
--- a/include/clang/AST/CXXInheritance.h
+++ b/include/clang/AST/CXXInheritance.h
@@ -14,17 +14,17 @@
#ifndef LLVM_CLANG_AST_CXXINHERITANCE_H
#define LLVM_CLANG_AST_CXXINHERITANCE_H
-#include "clang/AST/DeclarationName.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclarationName.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeOrdering.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
+#include <cassert>
#include <list>
#include <map>
-#include <cassert>
namespace clang {
diff --git a/include/clang/AST/CanonicalType.h b/include/clang/AST/CanonicalType.h
index ea307bf..9460757 100644
--- a/include/clang/AST/CanonicalType.h
+++ b/include/clang/AST/CanonicalType.h
@@ -351,15 +351,12 @@ namespace llvm {
/// CanQual<T> to a specific Type class. We're prefer isa/dyn_cast/cast/etc.
/// to return smart pointer (proxies?).
template<typename T>
-struct simplify_type<const ::clang::CanQual<T> > {
+struct simplify_type< ::clang::CanQual<T> > {
typedef const T *SimpleType;
- static SimpleType getSimplifiedValue(const ::clang::CanQual<T> &Val) {
+ static SimpleType getSimplifiedValue(::clang::CanQual<T> Val) {
return Val.getTypePtr();
}
};
-template<typename T>
-struct simplify_type< ::clang::CanQual<T> >
-: public simplify_type<const ::clang::CanQual<T> > {};
// Teach SmallPtrSet that CanQual<T> is "basically a pointer".
template<typename T>
@@ -514,55 +511,13 @@ struct CanProxyAdaptor<MemberPointerType>
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const Type *, getClass)
};
-template<>
-struct CanProxyAdaptor<ArrayType> : public CanProxyBase<ArrayType> {
- LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier,
- getSizeModifier)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers)
-};
-
-template<>
-struct CanProxyAdaptor<ConstantArrayType>
- : public CanProxyBase<ConstantArrayType> {
- LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier,
- getSizeModifier)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const llvm::APInt &, getSize)
-};
-
-template<>
-struct CanProxyAdaptor<IncompleteArrayType>
- : public CanProxyBase<IncompleteArrayType> {
- LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier,
- getSizeModifier)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers)
-};
-
-template<>
-struct CanProxyAdaptor<VariableArrayType>
- : public CanProxyBase<VariableArrayType> {
- LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier,
- getSizeModifier)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Expr *, getSizeExpr)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceRange, getBracketsRange)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getLBracketLoc)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getRBracketLoc)
-};
-
-template<>
-struct CanProxyAdaptor<DependentSizedArrayType>
- : public CanProxyBase<DependentSizedArrayType> {
- LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Expr *, getSizeExpr)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceRange, getBracketsRange)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getLBracketLoc)
- LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getRBracketLoc)
-};
+// CanProxyAdaptors for arrays are intentionally unimplemented because
+// they are not safe.
+template<> struct CanProxyAdaptor<ArrayType>;
+template<> struct CanProxyAdaptor<ConstantArrayType>;
+template<> struct CanProxyAdaptor<IncompleteArrayType>;
+template<> struct CanProxyAdaptor<VariableArrayType>;
+template<> struct CanProxyAdaptor<DependentSizedArrayType>;
template<>
struct CanProxyAdaptor<DependentSizedExtVectorType>
@@ -746,6 +701,9 @@ CanQual<T> CanQual<T>::CreateUnsafe(QualType Other) {
template<typename T>
template<typename U>
CanProxy<U> CanQual<T>::getAs() const {
+ ArrayType_cannot_be_used_with_getAs<U> at;
+ (void)at;
+
if (Stored.isNull())
return CanProxy<U>();
@@ -758,6 +716,9 @@ CanProxy<U> CanQual<T>::getAs() const {
template<typename T>
template<typename U>
CanProxy<U> CanQual<T>::castAs() const {
+ ArrayType_cannot_be_used_with_getAs<U> at;
+ (void)at;
+
assert(!Stored.isNull() && isa<U>(Stored.getTypePtr()));
return CanQual<U>::CreateUnsafe(Stored);
}
diff --git a/include/clang/AST/CharUnits.h b/include/clang/AST/CharUnits.h
index 12e74b3..082c672 100644
--- a/include/clang/AST/CharUnits.h
+++ b/include/clang/AST/CharUnits.h
@@ -171,6 +171,17 @@ namespace clang {
Align.Quantity));
}
+ /// Given that this is a non-zero alignment value, what is the
+ /// alignment at the given offset?
+ CharUnits alignmentAtOffset(CharUnits offset) {
+ // alignment: 0010000
+ // offset: 1011100
+ // lowBits: 0001011
+ // result: 0000100
+ QuantityType lowBits = (Quantity-1) & (offset.Quantity-1);
+ return CharUnits((lowBits + 1) & ~lowBits);
+ }
+
}; // class CharUnit
} // namespace clang
diff --git a/include/clang/AST/Comment.h b/include/clang/AST/Comment.h
index 316a180..c02a82f 100644
--- a/include/clang/AST/Comment.h
+++ b/include/clang/AST/Comment.h
@@ -14,10 +14,10 @@
#ifndef LLVM_CLANG_AST_COMMENT_H
#define LLVM_CLANG_AST_COMMENT_H
-#include "clang/Basic/SourceLocation.h"
-#include "clang/AST/Type.h"
#include "clang/AST/CommentCommandTraits.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
@@ -28,6 +28,26 @@ class TemplateParameterList;
namespace comments {
class FullComment;
+
+/// Describes the syntax that was used in a documentation command.
+///
+/// Exact values of this enumeration are important because they used to select
+/// parts of diagnostic messages. Audit diagnostics before changing or adding
+/// a new value.
+enum CommandMarkerKind {
+ /// Command started with a backslash character:
+ /// \code
+ /// \foo
+ /// \endcode
+ CMK_Backslash = 0,
+
+ /// Command started with an 'at' character:
+ /// \code
+ /// @foo
+ /// \endcode
+ CMK_At = 1
+};
+
/// Any part of the comment.
/// Abstract class.
class Comment {
@@ -110,8 +130,12 @@ protected:
unsigned : NumCommentBits;
unsigned CommandID : 8;
+
+ /// Describes the syntax that was used in a documentation command.
+ /// Contains values from CommandMarkerKind enum.
+ unsigned CommandMarker : 1;
};
- enum { NumBlockCommandCommentBits = NumCommentBits + 8 };
+ enum { NumBlockCommandCommentBits = NumCommentBits + 9 };
class ParamCommandCommentBitfields {
friend class ParamCommandComment;
@@ -171,8 +195,9 @@ public:
const char *getCommentKindName() const;
LLVM_ATTRIBUTE_USED void dump() const;
+ LLVM_ATTRIBUTE_USED void dumpColor() const;
LLVM_ATTRIBUTE_USED void dump(const ASTContext &Context) const;
- void dump(llvm::raw_ostream &OS, const CommandTraits *Traits,
+ void dump(raw_ostream &OS, const CommandTraits *Traits,
const SourceManager *SM) const;
SourceRange getSourceRange() const LLVM_READONLY { return Range; }
@@ -282,14 +307,14 @@ public:
protected:
/// Command arguments.
- llvm::ArrayRef<Argument> Args;
+ ArrayRef<Argument> Args;
public:
InlineCommandComment(SourceLocation LocBegin,
SourceLocation LocEnd,
unsigned CommandID,
RenderKind RK,
- llvm::ArrayRef<Argument> Args) :
+ ArrayRef<Argument> Args) :
InlineContentComment(InlineCommandCommentKind, LocBegin, LocEnd),
Args(Args) {
InlineCommandCommentBits.RenderKind = RK;
@@ -504,10 +529,10 @@ public:
/// A single paragraph that contains inline content.
class ParagraphComment : public BlockContentComment {
- llvm::ArrayRef<InlineContentComment *> Content;
+ ArrayRef<InlineContentComment *> Content;
public:
- ParagraphComment(llvm::ArrayRef<InlineContentComment *> Content) :
+ ParagraphComment(ArrayRef<InlineContentComment *> Content) :
BlockContentComment(ParagraphCommentKind,
SourceLocation(),
SourceLocation()),
@@ -565,7 +590,7 @@ public:
protected:
/// Word-like arguments.
- llvm::ArrayRef<Argument> Args;
+ ArrayRef<Argument> Args;
/// Paragraph argument.
ParagraphComment *Paragraph;
@@ -573,21 +598,25 @@ protected:
BlockCommandComment(CommentKind K,
SourceLocation LocBegin,
SourceLocation LocEnd,
- unsigned CommandID) :
+ unsigned CommandID,
+ CommandMarkerKind CommandMarker) :
BlockContentComment(K, LocBegin, LocEnd),
Paragraph(NULL) {
setLocation(getCommandNameBeginLoc());
BlockCommandCommentBits.CommandID = CommandID;
+ BlockCommandCommentBits.CommandMarker = CommandMarker;
}
public:
BlockCommandComment(SourceLocation LocBegin,
SourceLocation LocEnd,
- unsigned CommandID) :
+ unsigned CommandID,
+ CommandMarkerKind CommandMarker) :
BlockContentComment(BlockCommandCommentKind, LocBegin, LocEnd),
Paragraph(NULL) {
setLocation(getCommandNameBeginLoc());
BlockCommandCommentBits.CommandID = CommandID;
+ BlockCommandCommentBits.CommandMarker = CommandMarker;
}
static bool classof(const Comment *C) {
@@ -633,7 +662,7 @@ public:
return Args[Idx].Range;
}
- void setArgs(llvm::ArrayRef<Argument> A) {
+ void setArgs(ArrayRef<Argument> A) {
Args = A;
if (Args.size() > 0) {
SourceLocation NewLocEnd = Args.back().Range.getEnd();
@@ -656,6 +685,11 @@ public:
if (NewLocEnd.isValid())
setSourceRange(SourceRange(getLocStart(), NewLocEnd));
}
+
+ CommandMarkerKind getCommandMarker() const LLVM_READONLY {
+ return static_cast<CommandMarkerKind>(
+ BlockCommandCommentBits.CommandMarker);
+ }
};
/// Doxygen \\param command.
@@ -669,9 +703,10 @@ public:
ParamCommandComment(SourceLocation LocBegin,
SourceLocation LocEnd,
- unsigned CommandID) :
+ unsigned CommandID,
+ CommandMarkerKind CommandMarker) :
BlockCommandComment(ParamCommandCommentKind, LocBegin, LocEnd,
- CommandID),
+ CommandID, CommandMarker),
ParamIndex(InvalidParamIndex) {
ParamCommandCommentBits.Direction = In;
ParamCommandCommentBits.IsDirectionExplicit = false;
@@ -746,13 +781,15 @@ private:
/// For C: Position = { 0 }
/// For TT: Position = { 1 }
/// For T: Position = { 1, 0 }
- llvm::ArrayRef<unsigned> Position;
+ ArrayRef<unsigned> Position;
public:
TParamCommandComment(SourceLocation LocBegin,
SourceLocation LocEnd,
- unsigned CommandID) :
- BlockCommandComment(TParamCommandCommentKind, LocBegin, LocEnd, CommandID)
+ unsigned CommandID,
+ CommandMarkerKind CommandMarker) :
+ BlockCommandComment(TParamCommandCommentKind, LocBegin, LocEnd, CommandID,
+ CommandMarker)
{ }
static bool classof(const Comment *C) {
@@ -826,14 +863,15 @@ class VerbatimBlockComment : public BlockCommandComment {
protected:
StringRef CloseName;
SourceLocation CloseNameLocBegin;
- llvm::ArrayRef<VerbatimBlockLineComment *> Lines;
+ ArrayRef<VerbatimBlockLineComment *> Lines;
public:
VerbatimBlockComment(SourceLocation LocBegin,
SourceLocation LocEnd,
unsigned CommandID) :
BlockCommandComment(VerbatimBlockCommentKind,
- LocBegin, LocEnd, CommandID)
+ LocBegin, LocEnd, CommandID,
+ CMK_At) // FIXME: improve source fidelity.
{ }
static bool classof(const Comment *C) {
@@ -853,7 +891,7 @@ public:
CloseNameLocBegin = LocBegin;
}
- void setLines(llvm::ArrayRef<VerbatimBlockLineComment *> L) {
+ void setLines(ArrayRef<VerbatimBlockLineComment *> L) {
Lines = L;
}
@@ -886,7 +924,8 @@ public:
StringRef Text) :
BlockCommandComment(VerbatimLineCommentKind,
LocBegin, LocEnd,
- CommandID),
+ CommandID,
+ CMK_At), // FIXME: improve source fidelity.
Text(Text),
TextBegin(TextBegin)
{ }
@@ -1021,11 +1060,11 @@ struct DeclInfo {
/// A full comment attached to a declaration, contains block content.
class FullComment : public Comment {
- llvm::ArrayRef<BlockContentComment *> Blocks;
+ ArrayRef<BlockContentComment *> Blocks;
DeclInfo *ThisDeclInfo;
public:
- FullComment(llvm::ArrayRef<BlockContentComment *> Blocks, DeclInfo *D) :
+ FullComment(ArrayRef<BlockContentComment *> Blocks, DeclInfo *D) :
Comment(FullCommentKind, SourceLocation(), SourceLocation()),
Blocks(Blocks), ThisDeclInfo(D) {
if (Blocks.empty())
@@ -1062,7 +1101,7 @@ public:
return ThisDeclInfo;
}
- llvm::ArrayRef<BlockContentComment *> getBlocks() const { return Blocks; }
+ ArrayRef<BlockContentComment *> getBlocks() const { return Blocks; }
};
} // end namespace comments
diff --git a/include/clang/AST/CommentCommandTraits.h b/include/clang/AST/CommentCommandTraits.h
index 6d44c70..d1f5209 100644
--- a/include/clang/AST/CommentCommandTraits.h
+++ b/include/clang/AST/CommentCommandTraits.h
@@ -16,9 +16,10 @@
#ifndef LLVM_CLANG_AST_COMMENT_COMMAND_TRAITS_H
#define LLVM_CLANG_AST_COMMENT_COMMAND_TRAITS_H
+#include "clang/Basic/CommentOptions.h"
#include "clang/Basic/LLVM.h"
-#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/ErrorHandling.h"
@@ -69,6 +70,9 @@ struct CommandInfo {
/// True if this command is \\deprecated or an alias.
unsigned IsDeprecatedCommand : 1;
+ /// \brief True if this is a \\headerfile-like command.
+ unsigned IsHeaderfileCommand : 1;
+
/// True if we don't want to warn about this command being passed an empty
/// paragraph. Meaningful only for block commands.
unsigned IsEmptyParagraphAllowed : 1;
@@ -96,7 +100,17 @@ struct CommandInfo {
/// \fn void f(int a);
/// \endcode
unsigned IsDeclarationCommand : 1;
-
+
+ /// \brief True if verbatim-like line command is a function declaration.
+ unsigned IsFunctionDeclarationCommand : 1;
+
+ /// \brief True if block command is further describing a container API; such
+ /// as \@coclass, \@classdesign, etc.
+ unsigned IsRecordLikeDetailCommand : 1;
+
+ /// \brief True if block command is a container API; such as \@interface.
+ unsigned IsRecordLikeDeclarationCommand : 1;
+
/// \brief True if this command is unknown. This \c CommandInfo object was
/// created during parsing.
unsigned IsUnknownCommand : 1;
@@ -106,7 +120,17 @@ struct CommandInfo {
/// in comments.
class CommandTraits {
public:
- CommandTraits(llvm::BumpPtrAllocator &Allocator);
+ enum KnownCommandIDs {
+#define COMMENT_COMMAND(NAME) KCI_##NAME,
+#include "clang/AST/CommentCommandList.inc"
+#undef COMMENT_COMMAND
+ KCI_Last
+ };
+
+ CommandTraits(llvm::BumpPtrAllocator &Allocator,
+ const CommentOptions &CommentOptions);
+
+ void registerCommentOptions(const CommentOptions &CommentOptions);
/// \returns a CommandInfo object for a given command name or
/// NULL if no CommandInfo object exists for this command.
@@ -122,6 +146,8 @@ public:
const CommandInfo *registerUnknownCommand(StringRef CommandName);
+ const CommandInfo *registerBlockCommand(StringRef CommandName);
+
/// \returns a CommandInfo object for a given command name or
/// NULL if \c Name is not a builtin command.
static const CommandInfo *getBuiltinCommandInfo(StringRef Name);
@@ -137,6 +163,8 @@ private:
const CommandInfo *getRegisteredCommandInfo(StringRef Name) const;
const CommandInfo *getRegisteredCommandInfo(unsigned CommandID) const;
+ CommandInfo *createCommandInfoWithName(StringRef CommandName);
+
unsigned NextID;
/// Allocator for CommandInfo objects.
diff --git a/include/clang/AST/CommentCommands.td b/include/clang/AST/CommentCommands.td
index 3d8bad8..9587ace 100644
--- a/include/clang/AST/CommentCommands.td
+++ b/include/clang/AST/CommentCommands.td
@@ -1,3 +1,7 @@
+//===----------------------------------------------------------------------===//
+// Define command classes.
+//===----------------------------------------------------------------------===//
+
class Command<string name> {
string Name = name;
string EndCommandName = "";
@@ -12,6 +16,7 @@ class Command<string name> {
bit IsParamCommand = 0;
bit IsTParamCommand = 0;
bit IsDeprecatedCommand = 0;
+ bit IsHeaderfileCommand = 0;
bit IsEmptyParagraphAllowed = 0;
@@ -19,6 +24,9 @@ class Command<string name> {
bit IsVerbatimBlockEndCommand = 0;
bit IsVerbatimLineCommand = 0;
bit IsDeclarationCommand = 0;
+ bit IsFunctionDeclarationCommand = 0;
+ bit IsRecordLikeDetailCommand = 0;
+ bit IsRecordLikeDeclarationCommand = 0;
}
class InlineCommand<string name> : Command<name> {
@@ -29,6 +37,10 @@ class BlockCommand<string name> : Command<name> {
let IsBlockCommand = 1;
}
+class RecordLikeDetailCommand<string name> : BlockCommand<name> {
+ let IsRecordLikeDetailCommand = 1;
+}
+
class VerbatimBlockCommand<string name> : Command<name> {
let EndCommandName = name;
let IsVerbatimBlockCommand = 1;
@@ -54,6 +66,22 @@ class DeclarationVerbatimLineCommand<string name> :
let IsDeclarationCommand = 1;
}
+class FunctionDeclarationVerbatimLineCommand<string name> :
+ VerbatimLineCommand<name> {
+ let IsDeclarationCommand = 1;
+ let IsFunctionDeclarationCommand = 1;
+}
+
+class RecordLikeDeclarationVerbatimLineCommand<string name> :
+ VerbatimLineCommand<name> {
+ let IsDeclarationCommand = 1;
+ let IsRecordLikeDeclarationCommand = 1;
+}
+
+//===----------------------------------------------------------------------===//
+// InlineCommand
+//===----------------------------------------------------------------------===//
+
def B : InlineCommand<"b">;
def C : InlineCommand<"c">;
def P : InlineCommand<"p">;
@@ -61,19 +89,26 @@ def A : InlineCommand<"a">;
def E : InlineCommand<"e">;
def Em : InlineCommand<"em">;
+//===----------------------------------------------------------------------===//
+// BlockCommand
+//===----------------------------------------------------------------------===//
+
def Brief : BlockCommand<"brief"> { let IsBriefCommand = 1; }
def Short : BlockCommand<"short"> { let IsBriefCommand = 1; }
+// Opposite of \brief, it is the default in our implementation.
+def Details : BlockCommand<"details">;
+
def Returns : BlockCommand<"returns"> { let IsReturnsCommand = 1; }
def Return : BlockCommand<"return"> { let IsReturnsCommand = 1; }
def Result : BlockCommand<"result"> { let IsReturnsCommand = 1; }
def Param : BlockCommand<"param"> { let IsParamCommand = 1; }
-// Doxygen
+// Doxygen command for template parameter documentation.
def Tparam : BlockCommand<"tparam"> { let IsTParamCommand = 1; }
-// HeaderDoc
+// HeaderDoc command for template parameter documentation.
def Templatefield : BlockCommand<"templatefield"> { let IsTParamCommand = 1; }
def Deprecated : BlockCommand<"deprecated"> {
@@ -81,12 +116,17 @@ def Deprecated : BlockCommand<"deprecated"> {
let IsDeprecatedCommand = 1;
}
+def Headerfile : BlockCommand<"headerfile"> { let IsHeaderfileCommand = 1; }
+
+// We don't do any additional semantic analysis for the following
+// BlockCommands. It might be a good idea to do something extra for them, but
+// for now we model them as plain BlockCommands.
+def Attention : BlockCommand<"attention">;
def Author : BlockCommand<"author">;
def Authors : BlockCommand<"authors">;
def Bug : BlockCommand<"bug">;
def Copyright : BlockCommand<"copyright">;
def Date : BlockCommand<"date">;
-def Details : BlockCommand<"details">;
def Invariant : BlockCommand<"invariant">;
def Note : BlockCommand<"note">;
def Post : BlockCommand<"post">;
@@ -99,6 +139,22 @@ def Since : BlockCommand<"since">;
def Todo : BlockCommand<"todo">;
def Version : BlockCommand<"version">;
def Warning : BlockCommand<"warning">;
+// HeaderDoc commands
+def ClassDesign : RecordLikeDetailCommand<"classdesign">;
+def CoClass : RecordLikeDetailCommand<"coclass">;
+def Dependency : RecordLikeDetailCommand<"dependency">;
+def Helper : RecordLikeDetailCommand<"helper">;
+def HelperClass : RecordLikeDetailCommand<"helperclass">;
+def Helps : RecordLikeDetailCommand<"helps">;
+def InstanceSize : RecordLikeDetailCommand<"instancesize">;
+def Ownership : RecordLikeDetailCommand<"ownership">;
+def Performance : RecordLikeDetailCommand<"performance">;
+def Security : RecordLikeDetailCommand<"security">;
+def SuperClass : RecordLikeDetailCommand<"superclass">;
+
+//===----------------------------------------------------------------------===//
+// VerbatimBlockCommand
+//===----------------------------------------------------------------------===//
defm Code : VerbatimBlockCommand<"code", "endcode">;
defm Verbatim : VerbatimBlockCommand<"verbatim", "endverbatim">;
@@ -111,11 +167,16 @@ defm Rtfonly : VerbatimBlockCommand<"rtfonly", "endrtfonly">;
defm Dot : VerbatimBlockCommand<"dot", "enddot">;
defm Msc : VerbatimBlockCommand<"msc", "endmsc">;
-// These commands have special support in lexer.
+// These three commands have special support in CommentLexer to recognize their
+// names.
def FDollar : VerbatimBlockCommand<"f$">; // Inline LaTeX formula
defm FBracket : VerbatimBlockCommand<"f[", "f]">; // Displayed LaTeX formula
defm FBrace : VerbatimBlockCommand<"f{", "f}">; // LaTeX environment
+//===----------------------------------------------------------------------===//
+// VerbatimLineCommand
+//===----------------------------------------------------------------------===//
+
def Defgroup : VerbatimLineCommand<"defgroup">;
def Ingroup : VerbatimLineCommand<"ingroup">;
def Addtogroup : VerbatimLineCommand<"addtogroup">;
@@ -131,6 +192,10 @@ def Mainpage : VerbatimLineCommand<"mainpage">;
def Subpage : VerbatimLineCommand<"subpage">;
def Ref : VerbatimLineCommand<"ref">;
+//===----------------------------------------------------------------------===//
+// DeclarationVerbatimLineCommand
+//===----------------------------------------------------------------------===//
+
// Doxygen commands.
def Fn : DeclarationVerbatimLineCommand<"fn">;
def Namespace : DeclarationVerbatimLineCommand<"namespace">;
@@ -140,17 +205,18 @@ def Typedef : DeclarationVerbatimLineCommand<"typedef">;
def Var : DeclarationVerbatimLineCommand<"var">;
// HeaderDoc commands.
-def Class : DeclarationVerbatimLineCommand<"class">;
-def Interface : DeclarationVerbatimLineCommand<"interface">;
-def Protocol : DeclarationVerbatimLineCommand<"protocol">;
+def Class : RecordLikeDeclarationVerbatimLineCommand<"class">;
+def Interface : RecordLikeDeclarationVerbatimLineCommand<"interface">;
+def Protocol : RecordLikeDeclarationVerbatimLineCommand<"protocol">;
+def Struct : RecordLikeDeclarationVerbatimLineCommand<"struct">;
+def Union : RecordLikeDeclarationVerbatimLineCommand<"union">;
def Category : DeclarationVerbatimLineCommand<"category">;
def Template : DeclarationVerbatimLineCommand<"template">;
-def Function : DeclarationVerbatimLineCommand<"function">;
-def Method : DeclarationVerbatimLineCommand<"method">;
-def Callback : DeclarationVerbatimLineCommand<"callback">;
+def Function : FunctionDeclarationVerbatimLineCommand<"function">;
+def FunctionGroup : FunctionDeclarationVerbatimLineCommand<"functiongroup">;
+def Method : FunctionDeclarationVerbatimLineCommand<"method">;
+def MethodGroup : FunctionDeclarationVerbatimLineCommand<"methodgroup">;
+def Callback : FunctionDeclarationVerbatimLineCommand<"callback">;
def Const : DeclarationVerbatimLineCommand<"const">;
def Constant : DeclarationVerbatimLineCommand<"constant">;
-def Struct : DeclarationVerbatimLineCommand<"struct">;
-def Union : DeclarationVerbatimLineCommand<"union">;
def Enum : DeclarationVerbatimLineCommand<"enum">;
-
diff --git a/include/clang/AST/CommentHTMLNamedCharacterReferences.td b/include/clang/AST/CommentHTMLNamedCharacterReferences.td
new file mode 100644
index 0000000..4493108
--- /dev/null
+++ b/include/clang/AST/CommentHTMLNamedCharacterReferences.td
@@ -0,0 +1,177 @@
+// HTML Named Character Reference
+class NCR<string spelling, int codePoint> {
+ string Spelling = spelling;
+ int CodePoint = codePoint;
+}
+
+// The list below includes named character references supported by Doxygen:
+// http://www.stack.nl/~dimitri/doxygen/manual/htmlcmds.html
+//
+// It does not include all HTML 5 named character references.
+//
+// Corresponding code point values can be found here:
+// http://www.w3.org/TR/2011/WD-html5-20110113/named-character-references.html
+
+def : NCR<"copy", 0x000A9>;
+def : NCR<"COPY", 0x000A9>;
+def : NCR<"trade", 0x02122>;
+def : NCR<"TRADE", 0x02122>;
+def : NCR<"reg", 0x000AE>;
+def : NCR<"REG", 0x000AE>;
+def : NCR<"lt", 0x0003C>;
+def : NCR<"Lt", 0x0003C>;
+def : NCR<"LT", 0x0003C>;
+def : NCR<"gt", 0x0003E>;
+def : NCR<"Gt", 0x0003E>;
+def : NCR<"GT", 0x0003E>;
+def : NCR<"amp", 0x00026>;
+def : NCR<"AMP", 0x00026>;
+def : NCR<"apos", 0x00027>;
+def : NCR<"quot", 0x00022>;
+def : NCR<"QUOT", 0x00022>;
+def : NCR<"lsquo", 0x02018>;
+def : NCR<"rsquo", 0x02019>;
+def : NCR<"ldquo", 0x0201C>;
+def : NCR<"rdquo", 0x0201D>;
+def : NCR<"ndash", 0x02013>;
+def : NCR<"mdash", 0x02014>;
+
+def : NCR<"Auml", 0x000C4>;
+def : NCR<"Euml", 0x000CB>;
+def : NCR<"Iuml", 0x000CF>;
+def : NCR<"Ouml", 0x000D6>;
+def : NCR<"Uuml", 0x000DC>;
+def : NCR<"Yuml", 0x00178>;
+def : NCR<"auml", 0x000E4>;
+def : NCR<"euml", 0x000EB>;
+def : NCR<"iuml", 0x000EF>;
+def : NCR<"ouml", 0x000F6>;
+def : NCR<"uuml", 0x000FC>;
+def : NCR<"yuml", 0x000FF>;
+
+def : NCR<"Aacute", 0x000C1>;
+def : NCR<"Eacute", 0x000C9>;
+def : NCR<"Iacute", 0x000CD>;
+def : NCR<"Oacute", 0x000D3>;
+def : NCR<"Uacute", 0x000DA>;
+def : NCR<"Yacute", 0x000DD>;
+def : NCR<"aacute", 0x000E1>;
+def : NCR<"eacute", 0x000E9>;
+def : NCR<"iacute", 0x000ED>;
+def : NCR<"oacute", 0x000F3>;
+def : NCR<"uacute", 0x000FA>;
+def : NCR<"yacute", 0x000FD>;
+
+def : NCR<"Agrave", 0x000C0>;
+def : NCR<"Egrave", 0x000C8>;
+def : NCR<"Igrave", 0x000CC>;
+def : NCR<"Ograve", 0x000D2>;
+def : NCR<"Ugrave", 0x000D9>;
+// def : NCR<"Ygrave", 0x01EF2>; // Defined neither in Doxygen, nor in HTML5.
+def : NCR<"agrave", 0x000E0>;
+def : NCR<"egrave", 0x000E8>;
+def : NCR<"igrave", 0x000EC>;
+def : NCR<"ograve", 0x000F2>;
+def : NCR<"ugrave", 0x000F9>;
+def : NCR<"ygrave", 0x01EF3>; // Defined in Doxygen, not defined in HTML5.
+
+def : NCR<"Acirc", 0x000C2>;
+def : NCR<"Ecirc", 0x000CA>;
+def : NCR<"Icirc", 0x000CE>;
+def : NCR<"Ocirc", 0x000D4>;
+def : NCR<"Ucirc", 0x000DB>;
+def : NCR<"Ycirc", 0x00176>; // Not defined in Doxygen, defined in HTML5.
+def : NCR<"acirc", 0x000E2>;
+def : NCR<"ecirc", 0x000EA>;
+def : NCR<"icirc", 0x000EE>;
+def : NCR<"ocirc", 0x000F4>;
+def : NCR<"ucirc", 0x000FB>;
+def : NCR<"ycirc", 0x00177>;
+
+def : NCR<"Atilde", 0x000C3>;
+def : NCR<"Ntilde", 0x000D1>;
+def : NCR<"Otilde", 0x000D5>;
+def : NCR<"atilde", 0x000E3>;
+def : NCR<"ntilde", 0x000F1>;
+def : NCR<"otilde", 0x000F5>;
+
+def : NCR<"szlig", 0x000DF>;
+
+def : NCR<"ccedil", 0x000E7>;
+def : NCR<"Ccedil", 0x000C7>;
+
+def : NCR<"aring", 0x000E5>;
+def : NCR<"Aring", 0x000C5>;
+
+def : NCR<"nbsp", 0x000A0>;
+
+def : NCR<"Gamma", 0x00393>;
+def : NCR<"Delta", 0x00394>;
+def : NCR<"Theta", 0x00398>;
+def : NCR<"Lambda", 0x0039B>;
+def : NCR<"Xi", 0x0039E>;
+def : NCR<"Pi", 0x003A0>;
+def : NCR<"Sigma", 0x003A3>;
+def : NCR<"Upsilon", 0x003A5>;
+def : NCR<"Phi", 0x003A6>;
+def : NCR<"Psi", 0x003A8>;
+def : NCR<"Omega", 0x003A9>;
+
+def : NCR<"alpha", 0x003B1>;
+def : NCR<"beta", 0x003B2>;
+def : NCR<"gamma", 0x003B3>;
+def : NCR<"delta", 0x003B4>;
+def : NCR<"epsilon", 0x003B5>;
+def : NCR<"zeta", 0x003B6>;
+def : NCR<"eta", 0x003B7>;
+def : NCR<"theta", 0x003B8>;
+def : NCR<"iota", 0x003B9>;
+def : NCR<"kappa", 0x003BA>;
+def : NCR<"lambda", 0x003BB>;
+def : NCR<"mu", 0x003BC>;
+def : NCR<"nu", 0x003BD>;
+def : NCR<"xi", 0x003BE>;
+def : NCR<"pi", 0x003C0>;
+def : NCR<"rho", 0x003C1>;
+def : NCR<"sigma", 0x003C3>;
+def : NCR<"tau", 0x003C4>;
+def : NCR<"upsilon", 0x003C5>;
+def : NCR<"phi", 0x003C6>;
+def : NCR<"chi", 0x003C7>;
+def : NCR<"psi", 0x003C8>;
+def : NCR<"omega", 0x003C9>;
+def : NCR<"sigmaf", 0x003C2>;
+
+def : NCR<"sect", 0x000A7>;
+def : NCR<"deg", 0x000B0>;
+def : NCR<"prime", 0x02032>;
+def : NCR<"Prime", 0x02033>;
+def : NCR<"infin", 0x0221E>;
+def : NCR<"empty", 0x02205>;
+def : NCR<"plusmn", 0x000B1>;
+def : NCR<"times", 0x000D7>;
+def : NCR<"minus", 0x02212>;
+def : NCR<"sdot", 0x022C5>;
+def : NCR<"part", 0x02202>;
+def : NCR<"nabla", 0x02207>;
+def : NCR<"radic", 0x0221A>;
+def : NCR<"perp", 0x022A5>;
+def : NCR<"sum", 0x02211>;
+def : NCR<"int", 0x0222B>;
+def : NCR<"prod", 0x0220F>;
+def : NCR<"sim", 0x0223C>;
+def : NCR<"asymp", 0x02248>;
+def : NCR<"ne", 0x02260>;
+def : NCR<"equiv", 0x02261>;
+def : NCR<"prop", 0x0221D>;
+def : NCR<"le", 0x02264>;
+def : NCR<"ge", 0x02265>;
+def : NCR<"larr", 0x02190>;
+def : NCR<"rarr", 0x02192>;
+def : NCR<"isin", 0x02208>;
+def : NCR<"notin", 0x02209>;
+def : NCR<"lceil", 0x02308>;
+def : NCR<"rceil", 0x02309>;
+def : NCR<"lfloor", 0x0230A>;
+def : NCR<"rfloor", 0x0230B>;
+
diff --git a/include/clang/AST/CommentLexer.h b/include/clang/AST/CommentLexer.h
index f263697..4179f45 100644
--- a/include/clang/AST/CommentLexer.h
+++ b/include/clang/AST/CommentLexer.h
@@ -15,9 +15,9 @@
#define LLVM_CLANG_AST_COMMENT_LEXER_H
#include "clang/Basic/SourceManager.h"
-#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/raw_ostream.h"
@@ -34,8 +34,9 @@ enum TokenKind {
eof,
newline,
text,
- unknown_command, // Command that does not have an ID.
- command, // Command with an ID.
+ unknown_command, // Command that does not have an ID.
+ backslash_command, // Command with an ID, that used backslash marker.
+ at_command, // Command with an ID, that used 'at' marker.
verbatim_block_begin,
verbatim_block_line,
verbatim_block_end,
@@ -75,7 +76,7 @@ class Token {
/// unused (command spelling can be found with CommandTraits). Otherwise,
/// contains the length of the string that starts at TextPtr.
unsigned IntVal;
-
+
public:
SourceLocation getLocation() const LLVM_READONLY { return Loc; }
void setLocation(SourceLocation SL) { Loc = SL; }
@@ -118,12 +119,12 @@ public:
}
unsigned getCommandID() const LLVM_READONLY {
- assert(is(tok::command));
+ assert(is(tok::backslash_command) || is(tok::at_command));
return IntVal;
}
void setCommandID(unsigned ID) {
- assert(is(tok::command));
+ assert(is(tok::backslash_command) || is(tok::at_command));
IntVal = ID;
}
diff --git a/include/clang/AST/CommentParser.h b/include/clang/AST/CommentParser.h
index 19e1d57..d6a1072 100644
--- a/include/clang/AST/CommentParser.h
+++ b/include/clang/AST/CommentParser.h
@@ -14,10 +14,10 @@
#ifndef LLVM_CLANG_AST_COMMENT_PARSER_H
#define LLVM_CLANG_AST_COMMENT_PARSER_H
-#include "clang/Basic/Diagnostic.h"
-#include "clang/AST/CommentLexer.h"
#include "clang/AST/Comment.h"
+#include "clang/AST/CommentLexer.h"
#include "clang/AST/CommentSema.h"
+#include "clang/Basic/Diagnostic.h"
#include "llvm/Support/Allocator.h"
namespace clang {
@@ -86,6 +86,11 @@ class Parser {
Tok = Toks[0];
}
+ bool isTokBlockCommand() {
+ return (Tok.is(tok::backslash_command) || Tok.is(tok::at_command)) &&
+ Traits.getCommandInfo(Tok.getCommandID())->IsBlockCommand;
+ }
+
public:
Parser(Lexer &L, Sema &S, llvm::BumpPtrAllocator &Allocator,
const SourceManager &SourceMgr, DiagnosticsEngine &Diags,
diff --git a/include/clang/AST/CommentSema.h b/include/clang/AST/CommentSema.h
index 0340b3c..15e454d 100644
--- a/include/clang/AST/CommentSema.h
+++ b/include/clang/AST/CommentSema.h
@@ -14,12 +14,12 @@
#ifndef LLVM_CLANG_AST_COMMENT_SEMA_H
#define LLVM_CLANG_AST_COMMENT_SEMA_H
+#include "clang/AST/Comment.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceLocation.h"
-#include "clang/AST/Comment.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Allocator.h"
namespace clang {
@@ -60,6 +60,9 @@ class Sema {
/// AST node for the \\returns command and its aliases.
const BlockCommandComment *ReturnsCommand;
+
+ /// AST node for the \\headerfile command.
+ const BlockCommandComment *HeaderfileCommand;
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) {
return Diags.Report(Loc, DiagID);
@@ -93,7 +96,8 @@ public:
BlockCommandComment *actOnBlockCommandStart(SourceLocation LocBegin,
SourceLocation LocEnd,
- unsigned CommandID);
+ unsigned CommandID,
+ CommandMarkerKind CommandMarker);
void actOnBlockCommandArgs(BlockCommandComment *Command,
ArrayRef<BlockCommandComment::Argument> Args);
@@ -103,7 +107,8 @@ public:
ParamCommandComment *actOnParamCommandStart(SourceLocation LocBegin,
SourceLocation LocEnd,
- unsigned CommandID);
+ unsigned CommandID,
+ CommandMarkerKind CommandMarker);
void actOnParamCommandDirectionArg(ParamCommandComment *Command,
SourceLocation ArgLocBegin,
@@ -120,7 +125,8 @@ public:
TParamCommandComment *actOnTParamCommandStart(SourceLocation LocBegin,
SourceLocation LocEnd,
- unsigned CommandID);
+ unsigned CommandID,
+ CommandMarkerKind CommandMarker);
void actOnTParamCommandParamNameArg(TParamCommandComment *Command,
SourceLocation ArgLocBegin,
@@ -192,13 +198,28 @@ public:
void checkBlockCommandDuplicate(const BlockCommandComment *Command);
void checkDeprecatedCommand(const BlockCommandComment *Comment);
+
+ void checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment);
+
+ void checkContainerDeclVerbatimLine(const BlockCommandComment *Comment);
+
+ void checkContainerDecl(const BlockCommandComment *Comment);
/// Resolve parameter names to parameter indexes in function declaration.
/// Emit diagnostics about unknown parametrs.
void resolveParamCommandIndexes(const FullComment *FC);
bool isFunctionDecl();
+ bool isAnyFunctionDecl();
+ bool isFunctionPointerVarDecl();
+ bool isObjCMethodDecl();
+ bool isObjCPropertyDecl();
bool isTemplateOrSpecialization();
+ bool isRecordLikeDecl();
+ bool isClassOrStructDecl();
+ bool isUnionDecl();
+ bool isObjCInterfaceDecl();
+ bool isObjCProtocolDecl();
ArrayRef<const ParmVarDecl *> getParamVars();
diff --git a/include/clang/AST/CommentVisitor.h b/include/clang/AST/CommentVisitor.h
index 47867a6..21641bf 100644
--- a/include/clang/AST/CommentVisitor.h
+++ b/include/clang/AST/CommentVisitor.h
@@ -7,6 +7,9 @@
//
//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_AST_COMMENTVISITOR_H
+#define LLVM_CLANG_AST_COMMENTVISITOR_H
+
#include "clang/AST/Comment.h"
#include "llvm/Support/ErrorHandling.h"
@@ -64,3 +67,4 @@ class ConstCommentVisitor :
} // end namespace comments
} // end namespace clang
+#endif
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 087a585..7927279 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -16,33 +16,34 @@
#include "clang/AST/APValue.h"
#include "clang/AST/DeclBase.h"
-#include "clang/AST/Redeclarable.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/ExternalASTSource.h"
+#include "clang/AST/Redeclarable.h"
+#include "clang/AST/Type.h"
#include "clang/Basic/Linkage.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
#include "llvm/Support/Compiler.h"
namespace clang {
+struct ASTTemplateArgumentListInfo;
class CXXTemporary;
+class CompoundStmt;
+class DependentFunctionTemplateSpecializationInfo;
class Expr;
class FunctionTemplateDecl;
+class FunctionTemplateSpecializationInfo;
+class LabelStmt;
+class MemberSpecializationInfo;
+class Module;
+class NestedNameSpecifier;
class Stmt;
-class CompoundStmt;
class StringLiteral;
-class NestedNameSpecifier;
-class TemplateParameterList;
class TemplateArgumentList;
-struct ASTTemplateArgumentListInfo;
-class MemberSpecializationInfo;
-class FunctionTemplateSpecializationInfo;
-class DependentFunctionTemplateSpecializationInfo;
+class TemplateParameterList;
class TypeLoc;
class UnresolvedSetImpl;
-class LabelStmt;
-class Module;
-
+
/// \brief A container of type source information.
///
/// A client can read the relevant info using TypeLoc wrappers, e.g:
@@ -108,6 +109,7 @@ class NamedDecl : public Decl {
private:
NamedDecl *getUnderlyingDeclImpl();
+ void verifyLinkage() const;
protected:
NamedDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName N)
@@ -149,32 +151,29 @@ public:
/// \brief Set the name of this declaration.
void setDeclName(DeclarationName N) { Name = N; }
- /// getQualifiedNameAsString - Returns human-readable qualified name for
+ /// printQualifiedName - Returns human-readable qualified name for
/// declaration, like A::B::i, for i being member of namespace A::B.
/// If declaration is not member of context which can be named (record,
- /// namespace), it will return same result as getNameAsString().
+ /// namespace), it will return same result as printName().
/// Creating this name is expensive, so it should be called only when
/// performance doesn't matter.
+ void printQualifiedName(raw_ostream &OS) const;
+ void printQualifiedName(raw_ostream &OS, const PrintingPolicy &Policy) const;
+
+ // FIXME: Remove string versions.
std::string getQualifiedNameAsString() const;
std::string getQualifiedNameAsString(const PrintingPolicy &Policy) const;
/// getNameForDiagnostic - Appends a human-readable name for this
- /// declaration into the given string.
+ /// declaration into the given stream.
///
/// This is the method invoked by Sema when displaying a NamedDecl
/// in a diagnostic. It does not necessarily produce the same
- /// result as getNameAsString(); for example, class template
+ /// result as printName(); for example, class template
/// specializations are printed with their template arguments.
- ///
- /// TODO: use an API that doesn't require so many temporary strings
- virtual void getNameForDiagnostic(std::string &S,
+ virtual void getNameForDiagnostic(raw_ostream &OS,
const PrintingPolicy &Policy,
- bool Qualified) const {
- if (Qualified)
- S += getQualifiedNameAsString(Policy);
- else
- S += getNameAsString();
- }
+ bool Qualified) const;
/// declarationReplaces - Determine whether this declaration, if
/// known to be well-formed within its context, will replace the
@@ -212,117 +211,40 @@ public:
/// a C++ class.
bool isCXXInstanceMember() const;
- class LinkageInfo {
- uint8_t linkage_ : 2;
- uint8_t visibility_ : 2;
- uint8_t explicit_ : 1;
-
- void setVisibility(Visibility V, bool E) { visibility_ = V; explicit_ = E; }
- public:
- LinkageInfo() : linkage_(ExternalLinkage), visibility_(DefaultVisibility),
- explicit_(false) {}
- LinkageInfo(Linkage L, Visibility V, bool E)
- : linkage_(L), visibility_(V), explicit_(E) {
- assert(linkage() == L && visibility() == V && visibilityExplicit() == E &&
- "Enum truncated!");
- }
-
- static LinkageInfo external() {
- return LinkageInfo();
- }
- static LinkageInfo internal() {
- return LinkageInfo(InternalLinkage, DefaultVisibility, false);
- }
- static LinkageInfo uniqueExternal() {
- return LinkageInfo(UniqueExternalLinkage, DefaultVisibility, false);
- }
- static LinkageInfo none() {
- return LinkageInfo(NoLinkage, DefaultVisibility, false);
- }
-
- Linkage linkage() const { return (Linkage)linkage_; }
- Visibility visibility() const { return (Visibility)visibility_; }
- bool visibilityExplicit() const { return explicit_; }
-
- void setLinkage(Linkage L) { linkage_ = L; }
- void mergeLinkage(Linkage L) {
- setLinkage(minLinkage(linkage(), L));
- }
- void mergeLinkage(LinkageInfo Other) {
- mergeLinkage(Other.linkage());
- }
-
- // Merge the visibility V giving preference to explicit ones.
- // This is used, for example, when merging the visibility of a class
- // down to one of its members. If the member has no explicit visibility,
- // the class visibility wins.
- void mergeVisibility(Visibility V, bool E = false) {
- // Never increase the visibility
- if (visibility() < V)
- return;
-
- // If we have an explicit visibility, keep it
- if (visibilityExplicit())
- return;
-
- setVisibility(V, E);
- }
- // Merge the visibility V, keeping the most restrictive one.
- // This is used for cases like merging the visibility of a template
- // argument to an instantiation. If we already have a hidden class,
- // no argument should give it default visibility.
- void mergeVisibilityWithMin(Visibility V, bool E = false) {
- // Never increase the visibility
- if (visibility() < V)
- return;
-
- // FIXME: this
- // If this visibility is explicit, keep it.
- if (visibilityExplicit() && !E)
- return;
-
- // should be replaced with this
- // Don't lose the explicit bit for nothing
- // if (visibility() == V && visibilityExplicit())
- // return;
-
- setVisibility(V, E);
- }
- void mergeVisibility(LinkageInfo Other) {
- mergeVisibility(Other.visibility(), Other.visibilityExplicit());
- }
- void mergeVisibilityWithMin(LinkageInfo Other) {
- mergeVisibilityWithMin(Other.visibility(), Other.visibilityExplicit());
- }
-
- void merge(LinkageInfo Other) {
- mergeLinkage(Other);
- mergeVisibility(Other);
- }
- void mergeWithMin(LinkageInfo Other) {
- mergeLinkage(Other);
- mergeVisibilityWithMin(Other);
- }
- };
-
/// \brief Determine what kind of linkage this entity has.
Linkage getLinkage() const;
+ /// \brief True if this decl has external linkage.
+ bool hasExternalLinkage() const {
+ return getLinkage() == ExternalLinkage;
+ }
+
+ /// \brief True if this decl has external linkage. Don't cache the linkage,
+ /// because we are not finished setting up the redecl chain for the decl.
+ bool hasExternalLinkageUncached() const;
+
/// \brief Determines the visibility of this entity.
Visibility getVisibility() const {
- return getLinkageAndVisibility().visibility();
+ return getLinkageAndVisibility().getVisibility();
}
/// \brief Determines the linkage and visibility of this entity.
LinkageInfo getLinkageAndVisibility() const;
+ /// Kinds of explicit visibility.
+ enum ExplicitVisibilityKind {
+ VisibilityForType,
+ VisibilityForValue
+ };
+
/// \brief If visibility was explicitly specified for this
/// declaration, return that visibility.
- llvm::Optional<Visibility> getExplicitVisibility() const;
+ Optional<Visibility>
+ getExplicitVisibility(ExplicitVisibilityKind kind) const;
- /// \brief Clear the linkage cache in response to a change
- /// to the declaration.
- void ClearLinkageCache();
+ /// \brief True if the computed linkage is valid. Used for consistency
+ /// checking. Should always return true.
+ bool isLinkageValid() const;
/// \brief Looks through UsingDecls and ObjCCompatibleAliasDecls for
/// the underlying named decl.
@@ -538,9 +460,7 @@ public:
/// \brief Determine whether this symbol is weakly-imported,
/// or declared with the weak or weak-ref attr.
- bool isWeak() const {
- return hasAttr<WeakAttr>() || hasAttr<WeakRefAttr>() || isWeakImported();
- }
+ bool isWeak() const;
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
@@ -744,7 +664,6 @@ private:
friend class ASTDeclReader;
unsigned SClass : 3;
- unsigned SClassAsWritten : 3;
unsigned ThreadSpecified : 1;
unsigned InitStyle : 2;
@@ -811,14 +730,12 @@ protected:
VarDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
- QualType T, TypeSourceInfo *TInfo, StorageClass SC,
- StorageClass SCAsWritten)
+ QualType T, TypeSourceInfo *TInfo, StorageClass SC)
: DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), Init() {
assert(sizeof(VarDeclBitfields) <= sizeof(unsigned));
assert(sizeof(ParmVarDeclBitfields) <= sizeof(unsigned));
AllBits = 0;
VarDeclBits.SClass = SC;
- VarDeclBits.SClassAsWritten = SCAsWritten;
// Everything else is implicitly initialized to false.
}
@@ -841,23 +758,18 @@ public:
static VarDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
- StorageClass S, StorageClass SCAsWritten);
+ StorageClass S);
static VarDecl *CreateDeserialized(ASTContext &C, unsigned ID);
virtual SourceRange getSourceRange() const LLVM_READONLY;
+ /// \brief Returns the storage class as written in the source. For the
+ /// computed linkage of symbol, see getLinkage.
StorageClass getStorageClass() const {
return (StorageClass) VarDeclBits.SClass;
}
- StorageClass getStorageClassAsWritten() const {
- return (StorageClass) VarDeclBits.SClassAsWritten;
- }
void setStorageClass(StorageClass SC);
- void setStorageClassAsWritten(StorageClass SC) {
- assert(isLegalForVariable(SC));
- VarDeclBits.SClassAsWritten = SC;
- }
void setThreadSpecified(bool T) { VarDeclBits.ThreadSpecified = T; }
bool isThreadSpecified() const {
@@ -882,8 +794,8 @@ public:
return getStorageClass() == SC_Static && !isFileVarDecl();
}
- /// hasExternStorage - Returns true if a variable has extern or
- /// __private_extern__ storage.
+ /// \brief Returns true if a variable has extern or __private_extern__
+ /// storage.
bool hasExternalStorage() const {
return getStorageClass() == SC_Extern ||
getStorageClass() == SC_PrivateExtern;
@@ -894,6 +806,9 @@ public:
/// as static variables declared within a function.
bool hasGlobalStorage() const { return !hasLocalStorage(); }
+ /// Compute the language linkage.
+ LanguageLinkage getLanguageLinkage() const;
+
/// \brief Determines whether this variable is a variable with
/// external, C linkage.
bool isExternC() const;
@@ -1087,8 +1002,7 @@ public:
/// not a constant expression. Returns a pointer to the value if evaluation
/// succeeded, 0 otherwise.
APValue *evaluateValue() const;
- APValue *evaluateValue(
- llvm::SmallVectorImpl<PartialDiagnosticAt> &Notes) const;
+ APValue *evaluateValue(SmallVectorImpl<PartialDiagnosticAt> &Notes) const;
/// \brief Return the already-evaluated value of this variable's
/// initializer, or NULL if the value is not yet known. Returns pointer
@@ -1220,7 +1134,7 @@ public:
ImplicitParamDecl(DeclContext *DC, SourceLocation IdLoc,
IdentifierInfo *Id, QualType Type)
: VarDecl(ImplicitParam, DC, IdLoc, IdLoc, Id, Type,
- /*tinfo*/ 0, SC_None, SC_None) {
+ /*tinfo*/ 0, SC_None) {
setImplicit();
}
@@ -1239,8 +1153,8 @@ protected:
ParmVarDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo,
- StorageClass S, StorageClass SCAsWritten, Expr *DefArg)
- : VarDecl(DK, DC, StartLoc, IdLoc, Id, T, TInfo, S, SCAsWritten) {
+ StorageClass S, Expr *DefArg)
+ : VarDecl(DK, DC, StartLoc, IdLoc, Id, T, TInfo, S) {
assert(ParmVarDeclBits.HasInheritedDefaultArg == false);
assert(ParmVarDeclBits.IsKNRPromoted == false);
assert(ParmVarDeclBits.IsObjCMethodParam == false);
@@ -1252,8 +1166,7 @@ public:
SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo,
- StorageClass S, StorageClass SCAsWritten,
- Expr *DefArg);
+ StorageClass S, Expr *DefArg);
static ParmVarDecl *CreateDeserialized(ASTContext &C, unsigned ID);
@@ -1451,14 +1364,13 @@ private:
/// DeclsInPrototypeScope - Array of pointers to NamedDecls for
/// decls defined in the function prototype that are not parameters. E.g.
/// 'enum Y' in 'void f(enum Y {AA} x) {}'.
- llvm::ArrayRef<NamedDecl*> DeclsInPrototypeScope;
+ ArrayRef<NamedDecl *> DeclsInPrototypeScope;
LazyDeclStmtPtr Body;
// FIXME: This can be packed into the bitfields in Decl.
// NOTE: VC++ treats enums as signed, avoid using the StorageClass enum
unsigned SClass : 2;
- unsigned SClassAsWritten : 2;
bool IsInline : 1;
bool IsInlineSpecified : 1;
bool IsVirtualAsWritten : 1;
@@ -1473,6 +1385,10 @@ private:
bool IsLateTemplateParsed : 1;
bool IsConstexpr : 1;
+ /// \brief Indicates if the function was a definition but its body was
+ /// skipped.
+ unsigned HasSkippedBody : 1;
+
/// \brief End part of this FunctionDecl's source range.
///
/// We could compute the full range in getSourceRange(). However, when we're
@@ -1538,25 +1454,26 @@ private:
void setInstantiationOfMemberFunction(ASTContext &C, FunctionDecl *FD,
TemplateSpecializationKind TSK);
- void setParams(ASTContext &C, llvm::ArrayRef<ParmVarDecl *> NewParamInfo);
+ void setParams(ASTContext &C, ArrayRef<ParmVarDecl *> NewParamInfo);
protected:
FunctionDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
- StorageClass S, StorageClass SCAsWritten, bool isInlineSpecified,
+ StorageClass S, bool isInlineSpecified,
bool isConstexprSpecified)
: DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo,
StartLoc),
DeclContext(DK),
ParamInfo(0), Body(),
- SClass(S), SClassAsWritten(SCAsWritten),
+ SClass(S),
IsInline(isInlineSpecified), IsInlineSpecified(isInlineSpecified),
IsVirtualAsWritten(false), IsPure(false), HasInheritedPrototype(false),
HasWrittenPrototype(true), IsDeleted(false), IsTrivial(false),
IsDefaulted(false), IsExplicitlyDefaulted(false),
HasImplicitReturnZero(false), IsLateTemplateParsed(false),
- IsConstexpr(isConstexprSpecified), EndRangeLoc(NameInfo.getEndLoc()),
+ IsConstexpr(isConstexprSpecified), HasSkippedBody(false),
+ EndRangeLoc(NameInfo.getEndLoc()),
TemplateOrSpecialization(),
DNLoc(NameInfo.getInfo()) {}
@@ -1580,14 +1497,13 @@ public:
SourceLocation StartLoc, SourceLocation NLoc,
DeclarationName N, QualType T,
TypeSourceInfo *TInfo,
- StorageClass SC = SC_None,
- StorageClass SCAsWritten = SC_None,
+ StorageClass SC,
bool isInlineSpecified = false,
bool hasWrittenPrototype = true,
bool isConstexprSpecified = false) {
DeclarationNameInfo NameInfo(N, NLoc);
return FunctionDecl::Create(C, DC, StartLoc, NameInfo, T, TInfo,
- SC, SCAsWritten,
+ SC,
isInlineSpecified, hasWrittenPrototype,
isConstexprSpecified);
}
@@ -1596,10 +1512,9 @@ public:
SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
- StorageClass SC = SC_None,
- StorageClass SCAsWritten = SC_None,
- bool isInlineSpecified = false,
- bool hasWrittenPrototype = true,
+ StorageClass SC,
+ bool isInlineSpecified,
+ bool hasWrittenPrototype,
bool isConstexprSpecified = false);
static FunctionDecl *CreateDeserialized(ASTContext &C, unsigned ID);
@@ -1608,7 +1523,7 @@ public:
return DeclarationNameInfo(getDeclName(), getLocation(), DNLoc);
}
- virtual void getNameForDiagnostic(std::string &S,
+ virtual void getNameForDiagnostic(raw_ostream &OS,
const PrintingPolicy &Policy,
bool Qualified) const;
@@ -1732,7 +1647,7 @@ public:
/// Whether this is a (C++11) constexpr function or constexpr constructor.
bool isConstexpr() const { return IsConstexpr; }
- void setConstexpr(bool IC);
+ void setConstexpr(bool IC) { IsConstexpr = IC; }
/// \brief Whether this function has been deleted.
///
@@ -1776,6 +1691,9 @@ public:
/// This function must be an allocation or deallocation function.
bool isReservedGlobalPlacementOperator() const;
+ /// Compute the language linkage.
+ LanguageLinkage getLanguageLinkage() const;
+
/// \brief Determines whether this function is a function with
/// external, C linkage.
bool isExternC() const;
@@ -1783,6 +1701,14 @@ public:
/// \brief Determines whether this is a global function.
bool isGlobal() const;
+ /// \brief Determines whether this function is known to be 'noreturn', through
+ /// an attribute on its declaration or its type.
+ bool isNoReturn() const;
+
+ /// \brief True if the function was a definition but its body was skipped.
+ bool hasSkippedBody() const { return HasSkippedBody; }
+ void setHasSkippedBody(bool Skipped = true) { HasSkippedBody = Skipped; }
+
void setPreviousDeclaration(FunctionDecl * PrevDecl);
virtual const FunctionDecl *getCanonicalDecl() const;
@@ -1814,14 +1740,14 @@ public:
assert(i < getNumParams() && "Illegal param #");
return ParamInfo[i];
}
- void setParams(llvm::ArrayRef<ParmVarDecl *> NewParamInfo) {
+ void setParams(ArrayRef<ParmVarDecl *> NewParamInfo) {
setParams(getASTContext(), NewParamInfo);
}
- const llvm::ArrayRef<NamedDecl*> &getDeclsInPrototypeScope() const {
+ const ArrayRef<NamedDecl *> &getDeclsInPrototypeScope() const {
return DeclsInPrototypeScope;
}
- void setDeclsInPrototypeScope(llvm::ArrayRef<NamedDecl *> NewDecls);
+ void setDeclsInPrototypeScope(ArrayRef<NamedDecl *> NewDecls);
/// getMinRequiredArguments - Returns the minimum number of arguments
/// needed to call this function. This may be fewer than the number of
@@ -1838,12 +1764,9 @@ public:
return getType()->getAs<FunctionType>()->getCallResultType(getASTContext());
}
+ /// \brief Returns the storage class as written in the source. For the
+ /// computed linkage of symbol, see getLinkage.
StorageClass getStorageClass() const { return StorageClass(SClass); }
- void setStorageClass(StorageClass SC);
-
- StorageClass getStorageClassAsWritten() const {
- return StorageClass(SClassAsWritten);
- }
/// \brief Determine whether the "inline" keyword was specified for this
/// function.
@@ -1863,7 +1786,7 @@ public:
/// \brief Determine whether this function should be inlined, because it is
/// either marked "inline" or "constexpr" or is a member function of a class
/// that was defined in the class body.
- bool isInlined() const;
+ bool isInlined() const { return IsInline; }
bool isInlineDefinitionExternallyVisible() const;
@@ -1908,7 +1831,9 @@ public:
/// \brief If this function is an instantiation of a member function of a
/// class template specialization, retrieves the member specialization
/// information.
- MemberSpecializationInfo *getMemberSpecializationInfo() const;
+ MemberSpecializationInfo *getMemberSpecializationInfo() const {
+ return TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>();
+ }
/// \brief Specify that this record is an instantiation of the
/// member function FD.
@@ -2472,6 +2397,12 @@ protected:
/// possible in C++11 or Microsoft extensions mode.
bool IsFixed : 1;
+ /// \brief Indicates whether it is possible for declarations of this kind
+ /// to have an out-of-date definition.
+ ///
+ /// This option is only enabled when modules are enabled.
+ bool MayHaveOutOfDateDef : 1;
+
private:
SourceLocation RBraceLoc;
@@ -2616,6 +2547,25 @@ public:
bool isUnion() const { return getTagKind() == TTK_Union; }
bool isEnum() const { return getTagKind() == TTK_Enum; }
+ /// Is this tag type named, either directly or via being defined in
+ /// a typedef of this type?
+ ///
+ /// C++11 [basic.link]p8:
+ /// A type is said to have linkage if and only if:
+ /// - it is a class or enumeration type that is named (or has a
+ /// name for linkage purposes) and the name has linkage; ...
+ /// C++11 [dcl.typedef]p9:
+ /// If the typedef declaration defines an unnamed class (or enum),
+ /// the first typedef-name declared by the declaration to be that
+ /// class type (or enum type) is used to denote the class type (or
+ /// enum type) for linkage purposes only.
+ ///
+ /// C does not have an analogous rule, but the same concept is
+ /// nonetheless useful in some places.
+ bool hasNameForLinkage() const {
+ return (getDeclName() || getTypedefNameForAnonDecl());
+ }
+
TypedefNameDecl *getTypedefNameForAnonDecl() const {
return hasExtInfo() ? 0 :
TypedefNameDeclOrQualifier.get<TypedefNameDecl*>();
@@ -2906,6 +2856,10 @@ class RecordDecl : public TagDecl {
/// HasObjectMember - This is true if this struct has at least one member
/// containing an Objective-C object pointer type.
bool HasObjectMember : 1;
+
+ /// HasVolatileMember - This is true if struct has at least one member of
+ /// 'volatile' type.
+ bool HasVolatileMember : 1;
/// \brief Whether the field declarations of this record have been loaded
/// from external storage. To avoid unnecessary deserialization of
@@ -2962,6 +2916,9 @@ public:
bool hasObjectMember() const { return HasObjectMember; }
void setHasObjectMember (bool val) { HasObjectMember = val; }
+ bool hasVolatileMember() const { return HasVolatileMember; }
+ void setHasVolatileMember (bool val) { HasVolatileMember = val; }
+
/// \brief Determines whether this declaration represents the
/// injected class name.
///
@@ -3161,7 +3118,7 @@ public:
assert(i < getNumParams() && "Illegal param #");
return ParamInfo[i];
}
- void setParams(llvm::ArrayRef<ParmVarDecl *> NewParamInfo);
+ void setParams(ArrayRef<ParmVarDecl *> NewParamInfo);
/// hasCaptures - True if this block (or its nested blocks) captures
/// anything of local storage from its enclosing scopes.
@@ -3210,7 +3167,7 @@ public:
///
/// An import declaration imports the named module (or submodule). For example:
/// \code
-/// @__experimental_modules_import std.vector;
+/// @import std.vector;
/// \endcode
///
/// Import declarations can also be implicitly generated from
@@ -3271,7 +3228,21 @@ public:
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == Import; }
};
-
+
+/// \brief Represents an empty-declaration.
+class EmptyDecl : public Decl {
+ virtual void anchor();
+ EmptyDecl(DeclContext *DC, SourceLocation L)
+ : Decl(Empty, DC, L) { }
+
+public:
+ static EmptyDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L);
+ static EmptyDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classofKind(Kind K) { return K == Empty; }
+};
/// Insertion operator for diagnostics. This allows sending NamedDecl's
/// into a diagnostic with <<.
@@ -3299,10 +3270,10 @@ void Redeclarable<decl_type>::setPreviousDeclaration(decl_type *PrevDecl) {
// Point to previous. Make sure that this is actually the most recent
// redeclaration, or we can build invalid chains. If the most recent
// redeclaration is invalid, it won't be PrevDecl, but we want it anyway.
- RedeclLink = PreviousDeclLink(
- llvm::cast<decl_type>(PrevDecl->getMostRecentDecl()));
First = PrevDecl->getFirstDeclaration();
assert(First->RedeclLink.NextIsLatest() && "Expected first");
+ decl_type *MostRecent = First->RedeclLink.getNext();
+ RedeclLink = PreviousDeclLink(cast<decl_type>(MostRecent));
} else {
// Make this first.
First = static_cast<decl_type*>(this);
@@ -3310,8 +3281,8 @@ void Redeclarable<decl_type>::setPreviousDeclaration(decl_type *PrevDecl) {
// First one will point to this one as latest.
First->RedeclLink = LatestDeclLink(static_cast<decl_type*>(this));
- if (NamedDecl *ND = dyn_cast<NamedDecl>(static_cast<decl_type*>(this)))
- ND->ClearLinkageCache();
+ assert(!isa<NamedDecl>(static_cast<decl_type*>(this)) ||
+ cast<NamedDecl>(static_cast<decl_type*>(this))->isLinkageValid());
}
// Inline function definitions.
diff --git a/include/clang/AST/DeclAccessPair.h b/include/clang/AST/DeclAccessPair.h
index 7ecd8f8..5731308 100644
--- a/include/clang/AST/DeclAccessPair.h
+++ b/include/clang/AST/DeclAccessPair.h
@@ -19,6 +19,7 @@
#define LLVM_CLANG_AST_DECLACCESSPAIR_H
#include "clang/Basic/Specifiers.h"
+#include "llvm/Support/DataTypes.h"
namespace clang {
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index 50e2027..852bb9a 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -14,38 +14,40 @@
#ifndef LLVM_CLANG_AST_DECLBASE_H
#define LLVM_CLANG_AST_DECLBASE_H
-#include "clang/AST/Attr.h"
+#include "clang/AST/AttrIterator.h"
#include "clang/AST/DeclarationName.h"
-#include "clang/AST/Type.h"
#include "clang/Basic/Specifiers.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/PrettyStackTrace.h"
namespace clang {
-class DeclContext;
-class TranslationUnitDecl;
-class NamespaceDecl;
-class UsingDirectiveDecl;
-class NamedDecl;
-class FunctionDecl;
+class ASTMutationListener;
+class BlockDecl;
class CXXRecordDecl;
+class CompoundStmt;
+class DeclContext;
+class DeclarationName;
+class DependentDiagnostic;
class EnumDecl;
-class ObjCMethodDecl;
-class ObjCContainerDecl;
-class ObjCInterfaceDecl;
+class FunctionDecl;
+class LinkageSpecDecl;
+class Module;
+class NamedDecl;
+class NamespaceDecl;
class ObjCCategoryDecl;
-class ObjCProtocolDecl;
-class ObjCImplementationDecl;
class ObjCCategoryImplDecl;
+class ObjCContainerDecl;
class ObjCImplDecl;
-class LinkageSpecDecl;
-class BlockDecl;
-class DeclarationName;
-class CompoundStmt;
+class ObjCImplementationDecl;
+class ObjCInterfaceDecl;
+class ObjCMethodDecl;
+class ObjCProtocolDecl;
+struct PrintingPolicy;
+class Stmt;
class StoredDeclsMap;
-class DependentDiagnostic;
-class ASTMutationListener;
+class TranslationUnitDecl;
+class UsingDirectiveDecl;
}
namespace llvm {
@@ -133,7 +135,7 @@ public:
/// or member ends up here.
IDNS_Ordinary = 0x0020,
- /// Objective C @protocol.
+ /// Objective C \@protocol.
IDNS_ObjCProtocol = 0x0040,
/// This declaration is a friend function. A friend function
@@ -335,7 +337,10 @@ protected:
static void *AllocateDeserializedDecl(const ASTContext &Context,
unsigned ID,
unsigned Size);
-
+
+ /// \brief Update a potentially out-of-date declaration.
+ void updateOutOfDate(IdentifierInfo &II) const;
+
public:
/// \brief Source range that this declaration covers.
@@ -455,9 +460,7 @@ public:
/// getMaxAlignment - return the maximum alignment specified by attributes
/// on this decl, 0 if there are none.
- unsigned getMaxAlignment() const {
- return hasAttrs() ? getMaxAttrAlignment(getAttrs(), getASTContext()) : 0;
- }
+ unsigned getMaxAlignment() const;
/// setInvalidDecl - Indicates the Decl had a semantic error. This
/// allows for graceful error recovery.
@@ -593,7 +596,18 @@ public:
return 0;
}
-
+
+private:
+ Module *getOwningModuleSlow() const;
+
+public:
+ Module *getOwningModule() const {
+ if (!isFromASTFile())
+ return 0;
+
+ return getOwningModuleSlow();
+ }
+
unsigned getIdentifierNamespace() const {
return IdentifierNamespace;
}
@@ -851,6 +865,8 @@ public:
unsigned Indentation = 0);
// Debuggers don't usually respect default arguments.
LLVM_ATTRIBUTE_USED void dump() const;
+ // Same as dump(), but forces color printing.
+ LLVM_ATTRIBUTE_USED void dumpColor() const;
void dump(raw_ostream &Out) const;
// Debuggers don't usually respect default arguments.
LLVM_ATTRIBUTE_USED void dumpXML() const;
@@ -891,29 +907,9 @@ public:
virtual void print(raw_ostream &OS) const;
};
-class DeclContextLookupResult
- : public std::pair<NamedDecl**,NamedDecl**> {
-public:
- DeclContextLookupResult(NamedDecl **I, NamedDecl **E)
- : std::pair<NamedDecl**,NamedDecl**>(I, E) {}
- DeclContextLookupResult()
- : std::pair<NamedDecl**,NamedDecl**>() {}
+typedef llvm::MutableArrayRef<NamedDecl*> DeclContextLookupResult;
- using std::pair<NamedDecl**,NamedDecl**>::operator=;
-};
-
-class DeclContextLookupConstResult
- : public std::pair<NamedDecl*const*, NamedDecl*const*> {
-public:
- DeclContextLookupConstResult(std::pair<NamedDecl**,NamedDecl**> R)
- : std::pair<NamedDecl*const*, NamedDecl*const*>(R) {}
- DeclContextLookupConstResult(NamedDecl * const *I, NamedDecl * const *E)
- : std::pair<NamedDecl*const*, NamedDecl*const*>(I, E) {}
- DeclContextLookupConstResult()
- : std::pair<NamedDecl*const*, NamedDecl*const*>() {}
-
- using std::pair<NamedDecl*const*,NamedDecl*const*>::operator=;
-};
+typedef ArrayRef<NamedDecl *> DeclContextLookupConstResult;
/// DeclContext - This is used only as base class of specific decl types that
/// can act as declaration contexts. These decls are (only the top classes
@@ -935,19 +931,26 @@ class DeclContext {
/// \brief Whether this declaration context also has some external
/// storage that contains additional declarations that are lexically
/// part of this context.
- mutable unsigned ExternalLexicalStorage : 1;
+ mutable bool ExternalLexicalStorage : 1;
/// \brief Whether this declaration context also has some external
/// storage that contains additional declarations that are visible
/// in this context.
- mutable unsigned ExternalVisibleStorage : 1;
+ mutable bool ExternalVisibleStorage : 1;
+
+ /// \brief Whether this declaration context has had external visible
+ /// storage added since the last lookup. In this case, \c LookupPtr's
+ /// invariant may not hold and needs to be fixed before we perform
+ /// another lookup.
+ mutable bool NeedToReconcileExternalVisibleStorage : 1;
/// \brief Pointer to the data structure used to lookup declarations
/// within this context (or a DependentStoredDeclsMap if this is a
/// dependent context), and a bool indicating whether we have lazily
/// omitted any declarations from the map. We maintain the invariant
- /// that, if the map contains an entry for a DeclarationName, then it
- /// contains all relevant entries for that name.
+ /// that, if the map contains an entry for a DeclarationName (and we
+ /// haven't lazily omitted anything), then it contains all relevant
+ /// entries for that name.
mutable llvm::PointerIntPair<StoredDeclsMap*, 1, bool> LookupPtr;
protected:
@@ -970,10 +973,11 @@ protected:
static std::pair<Decl *, Decl *>
BuildDeclChain(ArrayRef<Decl*> Decls, bool FieldsAlreadyLoaded);
- DeclContext(Decl::Kind K)
- : DeclKind(K), ExternalLexicalStorage(false),
- ExternalVisibleStorage(false), LookupPtr(0, false), FirstDecl(0),
- LastDecl(0) { }
+ DeclContext(Decl::Kind K)
+ : DeclKind(K), ExternalLexicalStorage(false),
+ ExternalVisibleStorage(false),
+ NeedToReconcileExternalVisibleStorage(false), LookupPtr(0, false),
+ FirstDecl(0), LastDecl(0) {}
public:
~DeclContext();
@@ -1086,6 +1090,10 @@ public:
/// a C++ extern "C" linkage spec.
bool isExternCContext() const;
+ /// \brief Determines whether this context is, or is nested within,
+ /// a C++ extern "C++" linkage spec.
+ bool isExternCXXContext() const;
+
/// \brief Determine whether this declaration context is equivalent
/// to the declaration context DC.
bool Equals(const DeclContext *DC) const {
@@ -1160,7 +1168,7 @@ public:
/// contexts that are semanticaly connected to this declaration context,
/// in source order, including this context (which may be the only result,
/// for non-namespace contexts).
- void collectAllContexts(llvm::SmallVectorImpl<DeclContext *> &Contexts);
+ void collectAllContexts(SmallVectorImpl<DeclContext *> &Contexts);
/// decl_iterator - Iterates through the declarations stored
/// within this context.
@@ -1423,7 +1431,7 @@ public:
/// usual relationship between a DeclContext and the external source.
/// See the ASTImporter for the (few, but important) use cases.
void localUncachedLookup(DeclarationName Name,
- llvm::SmallVectorImpl<NamedDecl *> &Results);
+ SmallVectorImpl<NamedDecl *> &Results);
/// @brief Makes a declaration visible within this context.
///
@@ -1473,9 +1481,9 @@ public:
// Low-level accessors
/// \brief Mark the lookup table as needing to be built. This should be
- /// used only if setHasExternalLexicalStorage() has been called.
+ /// used only if setHasExternalLexicalStorage() has been called on any
+ /// decl context for which this is the primary context.
void setMustBuildLookupTable() {
- assert(ExternalLexicalStorage && "Requires external lexical storage");
LookupPtr.setInt(true);
}
@@ -1504,6 +1512,8 @@ public:
/// declarations visible in this context.
void setHasExternalVisibleStorage(bool ES = true) {
ExternalVisibleStorage = ES;
+ if (ES && LookupPtr.getPointer())
+ NeedToReconcileExternalVisibleStorage = true;
}
/// \brief Determine whether the given declaration is stored in the list of
@@ -1519,6 +1529,7 @@ public:
LLVM_ATTRIBUTE_USED void dumpDeclContext() const;
private:
+ void reconcileExternalVisibleStorage();
void LoadLexicalDeclsFromExternalStorage() const;
/// @brief Makes a declaration visible within this context, but
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 9cb56e2..05ff49c 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -15,11 +15,11 @@
#ifndef LLVM_CLANG_AST_DECLCXX_H
#define LLVM_CLANG_AST_DECLCXX_H
+#include "clang/AST/ASTUnresolvedSet.h"
+#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
-#include "clang/AST/Decl.h"
#include "clang/AST/TypeLoc.h"
-#include "clang/AST/UnresolvedSet.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -69,17 +69,6 @@ public:
} // end namespace clang
namespace llvm {
- /// Implement simplify_type for AnyFunctionDecl, so that we can dyn_cast from
- /// AnyFunctionDecl to any function or function template declaration.
- template<> struct simplify_type<const ::clang::AnyFunctionDecl> {
- typedef ::clang::NamedDecl* SimpleType;
- static SimpleType getSimplifiedValue(const ::clang::AnyFunctionDecl &Val) {
- return Val;
- }
- };
- template<> struct simplify_type< ::clang::AnyFunctionDecl>
- : public simplify_type<const ::clang::AnyFunctionDecl> {};
-
// Provide PointerLikeTypeTraits for non-cvr pointers.
template<>
class PointerLikeTypeTraits< ::clang::AnyFunctionDecl> {
@@ -272,32 +261,25 @@ class CXXRecordDecl : public RecordDecl {
friend void TagDecl::startDefinition();
+ /// Values used in DefinitionData fields to represent special members.
+ enum SpecialMemberFlags {
+ SMF_DefaultConstructor = 0x1,
+ SMF_CopyConstructor = 0x2,
+ SMF_MoveConstructor = 0x4,
+ SMF_CopyAssignment = 0x8,
+ SMF_MoveAssignment = 0x10,
+ SMF_Destructor = 0x20,
+ SMF_All = 0x3f
+ };
+
struct DefinitionData {
DefinitionData(CXXRecordDecl *D);
- /// UserDeclaredConstructor - True when this class has a
- /// user-declared constructor.
+ /// \brief True if this class has any user-declared constructors.
bool UserDeclaredConstructor : 1;
- /// UserDeclaredCopyConstructor - True when this class has a
- /// user-declared copy constructor.
- bool UserDeclaredCopyConstructor : 1;
-
- /// UserDeclareMoveConstructor - True when this class has a
- /// user-declared move constructor.
- bool UserDeclaredMoveConstructor : 1;
-
- /// UserDeclaredCopyAssignment - True when this class has a
- /// user-declared copy assignment operator.
- bool UserDeclaredCopyAssignment : 1;
-
- /// UserDeclareMoveAssignment - True when this class has a
- /// user-declared move assignment.
- bool UserDeclaredMoveAssignment : 1;
-
- /// UserDeclaredDestructor - True when this class has a
- /// user-declared destructor.
- bool UserDeclaredDestructor : 1;
+ /// The user-declared special members which this class has.
+ unsigned UserDeclaredSpecialMembers : 6;
/// Aggregate - True when this class is an aggregate.
bool Aggregate : 1;
@@ -360,21 +342,46 @@ class CXXRecordDecl : public RecordDecl {
/// \brief True if any field has an in-class initializer.
bool HasInClassInitializer : 1;
- /// HasTrivialDefaultConstructor - True when, if this class has a default
- /// constructor, this default constructor is trivial.
+ /// \brief True if any field is of reference type, and does not have an
+ /// in-class initializer. In this case, value-initialization of this class
+ /// is illegal in C++98 even if the class has a trivial default constructor.
+ bool HasUninitializedReferenceMember : 1;
+
+ /// \brief These flags are \c true if a defaulted corresponding special
+ /// member can't be fully analyzed without performing overload resolution.
+ /// @{
+ bool NeedOverloadResolutionForMoveConstructor : 1;
+ bool NeedOverloadResolutionForMoveAssignment : 1;
+ bool NeedOverloadResolutionForDestructor : 1;
+ /// @}
+
+ /// \brief These flags are \c true if an implicit defaulted corresponding
+ /// special member would be defined as deleted.
+ /// @{
+ bool DefaultedMoveConstructorIsDeleted : 1;
+ bool DefaultedMoveAssignmentIsDeleted : 1;
+ bool DefaultedDestructorIsDeleted : 1;
+ /// @}
+
+ /// \brief The trivial special members which this class has, per
+ /// C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25,
+ /// C++11 [class.dtor]p5, or would have if the member were not suppressed.
+ ///
+ /// This excludes any user-declared but not user-provided special members
+ /// which have been declared but not yet defined.
+ unsigned HasTrivialSpecialMembers : 6;
+
+ /// \brief The declared special members of this class which are known to be
+ /// non-trivial.
///
- /// C++0x [class.ctor]p5
- /// A default constructor is trivial if it is not user-provided and if
- /// -- its class has no virtual functions and no virtual base classes,
- /// and
- /// -- no non-static data member of its class has a
- /// brace-or-equal-initializer, and
- /// -- all the direct base classes of its class have trivial
- /// default constructors, and
- /// -- for all the nonstatic data members of its class that are of class
- /// type (or array thereof), each such class has a trivial
- /// default constructor.
- bool HasTrivialDefaultConstructor : 1;
+ /// This excludes any user-declared but not user-provided special members
+ /// which have been declared but not yet defined, and any implicit special
+ /// members which have not yet been declared.
+ unsigned DeclaredNonTrivialSpecialMembers : 6;
+
+ /// HasIrrelevantDestructor - True when this class has a destructor with no
+ /// semantic effect.
+ bool HasIrrelevantDestructor : 1;
/// HasConstexprNonCopyMoveConstructor - True when this class has at least
/// one user-declared constexpr constructor which is neither the copy nor
@@ -389,80 +396,6 @@ class CXXRecordDecl : public RecordDecl {
/// default constructor (either user-declared or implicitly declared).
bool HasConstexprDefaultConstructor : 1;
- /// HasTrivialCopyConstructor - True when this class has a trivial copy
- /// constructor.
- ///
- /// C++0x [class.copy]p13:
- /// A copy/move constructor for class X is trivial if it is neither
- /// user-provided and if
- /// -- class X has no virtual functions and no virtual base classes, and
- /// -- the constructor selected to copy/move each direct base class
- /// subobject is trivial, and
- /// -- for each non-static data member of X that is of class type (or an
- /// array thereof), the constructor selected to copy/move that member
- /// is trivial;
- /// otherwise the copy/move constructor is non-trivial.
- bool HasTrivialCopyConstructor : 1;
-
- /// HasTrivialMoveConstructor - True when this class has a trivial move
- /// constructor.
- ///
- /// C++0x [class.copy]p13:
- /// A copy/move constructor for class X is trivial if it is neither
- /// user-provided and if
- /// -- class X has no virtual functions and no virtual base classes, and
- /// -- the constructor selected to copy/move each direct base class
- /// subobject is trivial, and
- /// -- for each non-static data member of X that is of class type (or an
- /// array thereof), the constructor selected to copy/move that member
- /// is trivial;
- /// otherwise the copy/move constructor is non-trivial.
- bool HasTrivialMoveConstructor : 1;
-
- /// HasTrivialCopyAssignment - True when this class has a trivial copy
- /// assignment operator.
- ///
- /// C++0x [class.copy]p27:
- /// A copy/move assignment operator for class X is trivial if it is
- /// neither user-provided nor deleted and if
- /// -- class X has no virtual functions and no virtual base classes, and
- /// -- the assignment operator selected to copy/move each direct base
- /// class subobject is trivial, and
- /// -- for each non-static data member of X that is of class type (or an
- /// array thereof), the assignment operator selected to copy/move
- /// that member is trivial;
- /// otherwise the copy/move assignment operator is non-trivial.
- bool HasTrivialCopyAssignment : 1;
-
- /// HasTrivialMoveAssignment - True when this class has a trivial move
- /// assignment operator.
- ///
- /// C++0x [class.copy]p27:
- /// A copy/move assignment operator for class X is trivial if it is
- /// neither user-provided nor deleted and if
- /// -- class X has no virtual functions and no virtual base classes, and
- /// -- the assignment operator selected to copy/move each direct base
- /// class subobject is trivial, and
- /// -- for each non-static data member of X that is of class type (or an
- /// array thereof), the assignment operator selected to copy/move
- /// that member is trivial;
- /// otherwise the copy/move assignment operator is non-trivial.
- bool HasTrivialMoveAssignment : 1;
-
- /// HasTrivialDestructor - True when this class has a trivial destructor.
- ///
- /// C++ [class.dtor]p3. A destructor is trivial if it is an
- /// implicitly-declared destructor and if:
- /// * all of the direct base classes of its class have trivial destructors
- /// and
- /// * for all of the non-static data members of its class that are of class
- /// type (or array thereof), each such class has a trivial destructor.
- bool HasTrivialDestructor : 1;
-
- /// HasIrrelevantDestructor - True when this class has a destructor with no
- /// semantic effect.
- bool HasIrrelevantDestructor : 1;
-
/// HasNonLiteralTypeFieldsOrBases - True when this class contains at least
/// one non-static data member or base class of non-literal or volatile
/// type.
@@ -472,27 +405,29 @@ class CXXRecordDecl : public RecordDecl {
/// already computed and are available.
bool ComputedVisibleConversions : 1;
- /// \brief Whether we have a C++0x user-provided default constructor (not
+ /// \brief Whether we have a C++11 user-provided default constructor (not
/// explicitly deleted or defaulted).
bool UserProvidedDefaultConstructor : 1;
- /// \brief Whether we have already declared the default constructor.
- bool DeclaredDefaultConstructor : 1;
+ /// \brief The special members which have been declared for this class,
+ /// either by the user or implicitly.
+ unsigned DeclaredSpecialMembers : 6;
- /// \brief Whether we have already declared the copy constructor.
- bool DeclaredCopyConstructor : 1;
+ /// \brief Whether an implicit copy constructor would have a const-qualified
+ /// parameter.
+ bool ImplicitCopyConstructorHasConstParam : 1;
- /// \brief Whether we have already declared the move constructor.
- bool DeclaredMoveConstructor : 1;
+ /// \brief Whether an implicit copy assignment operator would have a
+ /// const-qualified parameter.
+ bool ImplicitCopyAssignmentHasConstParam : 1;
- /// \brief Whether we have already declared the copy-assignment operator.
- bool DeclaredCopyAssignment : 1;
+ /// \brief Whether any declared copy constructor has a const-qualified
+ /// parameter.
+ bool HasDeclaredCopyConstructorWithConstParam : 1;
- /// \brief Whether we have already declared the move-assignment operator.
- bool DeclaredMoveAssignment : 1;
-
- /// \brief Whether we have already declared a destructor within the class.
- bool DeclaredDestructor : 1;
+ /// \brief Whether any declared copy assignment operator has either a
+ /// const-qualified reference parameter or a non-reference parameter.
+ bool HasDeclaredCopyAssignmentWithConstParam : 1;
/// \brief Whether an implicit move constructor was attempted to be declared
/// but would have been deleted.
@@ -522,14 +457,14 @@ class CXXRecordDecl : public RecordDecl {
/// of this C++ class (but not its inherited conversion
/// functions). Each of the entries in this overload set is a
/// CXXConversionDecl.
- UnresolvedSet<4> Conversions;
+ ASTUnresolvedSet Conversions;
/// VisibleConversions - Overload set containing the conversion
/// functions of this C++ class and all those inherited conversion
/// functions that are visible in this class. Each of the entries
/// in this overload set is a CXXConversionDecl or a
/// FunctionTemplateDecl.
- UnresolvedSet<4> VisibleConversions;
+ ASTUnresolvedSet VisibleConversions;
/// Definition - The declaration which defines this record.
CXXRecordDecl *Definition;
@@ -636,6 +571,10 @@ class CXXRecordDecl : public RecordDecl {
friend class DeclContext;
friend class LambdaExpr;
+ /// \brief Called from setBases and addedMember to notify the class that a
+ /// direct or virtual base class or a member of class type has been added.
+ void addedClassSubobject(CXXRecordDecl *Base);
+
/// \brief Notify the class that member has been added.
///
/// This routine helps maintain information about the class based on which
@@ -646,9 +585,6 @@ class CXXRecordDecl : public RecordDecl {
void markedVirtualFunctionPure();
friend void FunctionDecl::setPure(bool);
- void markedConstructorConstexpr(CXXConstructorDecl *CD);
- friend void FunctionDecl::setConstexpr(bool);
-
friend class ASTNodeImporter;
protected:
@@ -765,7 +701,8 @@ public:
return reverse_base_class_const_iterator(vbases_begin());
}
- /// \brief Determine whether this class has any dependent base classes.
+ /// \brief Determine whether this class has any dependent base classes which
+ /// are not the current instantiation.
bool hasAnyDependentBases() const;
/// Iterator access to method members. The method iterator visits
@@ -805,47 +742,38 @@ public:
return data().FirstFriend != 0;
}
+ /// \brief \c true if we know for sure that this class has a single,
+ /// accessible, unambiguous move constructor that is not deleted.
+ bool hasSimpleMoveConstructor() const {
+ return !hasUserDeclaredMoveConstructor() && hasMoveConstructor();
+ }
+ /// \brief \c true if we know for sure that this class has a single,
+ /// accessible, unambiguous move assignment operator that is not deleted.
+ bool hasSimpleMoveAssignment() const {
+ return !hasUserDeclaredMoveAssignment() && hasMoveAssignment();
+ }
+ /// \brief \c true if we know for sure that this class has an accessible
+ /// destructor that is not deleted.
+ bool hasSimpleDestructor() const {
+ return !hasUserDeclaredDestructor() &&
+ !data().DefaultedDestructorIsDeleted;
+ }
+
+ /// \brief Determine whether this class has any default constructors.
+ bool hasDefaultConstructor() const {
+ return (data().DeclaredSpecialMembers & SMF_DefaultConstructor) ||
+ needsImplicitDefaultConstructor();
+ }
+
/// \brief Determine if we need to declare a default constructor for
/// this class.
///
/// This value is used for lazy creation of default constructors.
bool needsImplicitDefaultConstructor() const {
return !data().UserDeclaredConstructor &&
- !data().DeclaredDefaultConstructor;
- }
-
- /// hasDeclaredDefaultConstructor - Whether this class's default constructor
- /// has been declared (either explicitly or implicitly).
- bool hasDeclaredDefaultConstructor() const {
- return data().DeclaredDefaultConstructor;
+ !(data().DeclaredSpecialMembers & SMF_DefaultConstructor);
}
- /// hasConstCopyConstructor - Determines whether this class has a
- /// copy constructor that accepts a const-qualified argument.
- bool hasConstCopyConstructor() const;
-
- /// getCopyConstructor - Returns the copy constructor for this class
- CXXConstructorDecl *getCopyConstructor(unsigned TypeQuals) const;
-
- /// getMoveConstructor - Returns the move constructor for this class
- CXXConstructorDecl *getMoveConstructor() const;
-
- /// \brief Retrieve the copy-assignment operator for this class, if available.
- ///
- /// This routine attempts to find the copy-assignment operator for this
- /// class, using a simplistic form of overload resolution.
- ///
- /// \param ArgIsConst Whether the argument to the copy-assignment operator
- /// is const-qualified.
- ///
- /// \returns The copy-assignment operator that can be invoked, or NULL if
- /// a unique copy-assignment operator could not be found.
- CXXMethodDecl *getCopyAssignmentOperator(bool ArgIsConst) const;
-
- /// getMoveAssignmentOperator - Returns the move assignment operator for this
- /// class
- CXXMethodDecl *getMoveAssignmentOperator() const;
-
/// hasUserDeclaredConstructor - Whether this class has any
/// user-declared constructors. When true, a default constructor
/// will not be implicitly declared.
@@ -863,35 +791,53 @@ public:
/// user-declared copy constructor. When false, a copy constructor
/// will be implicitly declared.
bool hasUserDeclaredCopyConstructor() const {
- return data().UserDeclaredCopyConstructor;
+ return data().UserDeclaredSpecialMembers & SMF_CopyConstructor;
}
- /// \brief Determine whether this class has had its copy constructor
- /// declared, either via the user or via an implicit declaration.
- ///
- /// This value is used for lazy creation of copy constructors.
- bool hasDeclaredCopyConstructor() const {
- return data().DeclaredCopyConstructor;
+ /// \brief Determine whether this class needs an implicit copy
+ /// constructor to be lazily declared.
+ bool needsImplicitCopyConstructor() const {
+ return !(data().DeclaredSpecialMembers & SMF_CopyConstructor);
+ }
+
+ /// \brief Determine whether we need to eagerly declare a defaulted copy
+ /// constructor for this class.
+ bool needsOverloadResolutionForCopyConstructor() const {
+ return data().HasMutableFields;
+ }
+
+ /// \brief Determine whether an implicit copy constructor for this type
+ /// would have a parameter with a const-qualified reference type.
+ bool implicitCopyConstructorHasConstParam() const {
+ return data().ImplicitCopyConstructorHasConstParam;
+ }
+
+ /// \brief Determine whether this class has a copy constructor with
+ /// a parameter type which is a reference to a const-qualified type.
+ bool hasCopyConstructorWithConstParam() const {
+ return data().HasDeclaredCopyConstructorWithConstParam ||
+ (needsImplicitCopyConstructor() &&
+ implicitCopyConstructorHasConstParam());
}
/// hasUserDeclaredMoveOperation - Whether this class has a user-
/// declared move constructor or assignment operator. When false, a
/// move constructor and assignment operator may be implicitly declared.
bool hasUserDeclaredMoveOperation() const {
- return data().UserDeclaredMoveConstructor ||
- data().UserDeclaredMoveAssignment;
+ return data().UserDeclaredSpecialMembers &
+ (SMF_MoveConstructor | SMF_MoveAssignment);
}
/// \brief Determine whether this class has had a move constructor
/// declared by the user.
bool hasUserDeclaredMoveConstructor() const {
- return data().UserDeclaredMoveConstructor;
+ return data().UserDeclaredSpecialMembers & SMF_MoveConstructor;
}
- /// \brief Determine whether this class has had a move constructor
- /// declared.
- bool hasDeclaredMoveConstructor() const {
- return data().DeclaredMoveConstructor;
+ /// \brief Determine whether this class has a move constructor.
+ bool hasMoveConstructor() const {
+ return (data().DeclaredSpecialMembers & SMF_MoveConstructor) ||
+ needsImplicitMoveConstructor();
}
/// \brief Determine whether implicit move constructor generation for this
@@ -908,44 +854,66 @@ public:
/// \brief Determine whether this class should get an implicit move
/// constructor or if any existing special member function inhibits this.
- ///
- /// Covers all bullets of C++0x [class.copy]p9 except the last, that the
- /// constructor wouldn't be deleted, which is only looked up from a cached
- /// result.
bool needsImplicitMoveConstructor() const {
return !hasFailedImplicitMoveConstructor() &&
- !hasDeclaredMoveConstructor() &&
+ !(data().DeclaredSpecialMembers & SMF_MoveConstructor) &&
!hasUserDeclaredCopyConstructor() &&
!hasUserDeclaredCopyAssignment() &&
!hasUserDeclaredMoveAssignment() &&
- !hasUserDeclaredDestructor();
+ !hasUserDeclaredDestructor() &&
+ !data().DefaultedMoveConstructorIsDeleted;
+ }
+
+ /// \brief Determine whether we need to eagerly declare a defaulted move
+ /// constructor for this class.
+ bool needsOverloadResolutionForMoveConstructor() const {
+ return data().NeedOverloadResolutionForMoveConstructor;
}
/// hasUserDeclaredCopyAssignment - Whether this class has a
/// user-declared copy assignment operator. When false, a copy
/// assigment operator will be implicitly declared.
bool hasUserDeclaredCopyAssignment() const {
- return data().UserDeclaredCopyAssignment;
+ return data().UserDeclaredSpecialMembers & SMF_CopyAssignment;
}
- /// \brief Determine whether this class has had its copy assignment operator
- /// declared, either via the user or via an implicit declaration.
- ///
- /// This value is used for lazy creation of copy assignment operators.
- bool hasDeclaredCopyAssignment() const {
- return data().DeclaredCopyAssignment;
+ /// \brief Determine whether this class needs an implicit copy
+ /// assignment operator to be lazily declared.
+ bool needsImplicitCopyAssignment() const {
+ return !(data().DeclaredSpecialMembers & SMF_CopyAssignment);
+ }
+
+ /// \brief Determine whether we need to eagerly declare a defaulted copy
+ /// assignment operator for this class.
+ bool needsOverloadResolutionForCopyAssignment() const {
+ return data().HasMutableFields;
+ }
+
+ /// \brief Determine whether an implicit copy assignment operator for this
+ /// type would have a parameter with a const-qualified reference type.
+ bool implicitCopyAssignmentHasConstParam() const {
+ return data().ImplicitCopyAssignmentHasConstParam;
+ }
+
+ /// \brief Determine whether this class has a copy assignment operator with
+ /// a parameter type which is a reference to a const-qualified type or is not
+ /// a reference..
+ bool hasCopyAssignmentWithConstParam() const {
+ return data().HasDeclaredCopyAssignmentWithConstParam ||
+ (needsImplicitCopyAssignment() &&
+ implicitCopyAssignmentHasConstParam());
}
/// \brief Determine whether this class has had a move assignment
/// declared by the user.
bool hasUserDeclaredMoveAssignment() const {
- return data().UserDeclaredMoveAssignment;
+ return data().UserDeclaredSpecialMembers & SMF_MoveAssignment;
}
- /// hasDeclaredMoveAssignment - Whether this class has a
- /// declared move assignment operator.
- bool hasDeclaredMoveAssignment() const {
- return data().DeclaredMoveAssignment;
+ /// \brief Determine whether this class has a move assignment operator.
+ bool hasMoveAssignment() const {
+ return (data().DeclaredSpecialMembers & SMF_MoveAssignment) ||
+ needsImplicitMoveAssignment();
}
/// \brief Determine whether implicit move assignment generation for this
@@ -963,34 +931,44 @@ public:
/// \brief Determine whether this class should get an implicit move
/// assignment operator or if any existing special member function inhibits
/// this.
- ///
- /// Covers all bullets of C++0x [class.copy]p20 except the last, that the
- /// constructor wouldn't be deleted.
bool needsImplicitMoveAssignment() const {
return !hasFailedImplicitMoveAssignment() &&
- !hasDeclaredMoveAssignment() &&
+ !(data().DeclaredSpecialMembers & SMF_MoveAssignment) &&
!hasUserDeclaredCopyConstructor() &&
!hasUserDeclaredCopyAssignment() &&
!hasUserDeclaredMoveConstructor() &&
- !hasUserDeclaredDestructor();
+ !hasUserDeclaredDestructor() &&
+ !data().DefaultedMoveAssignmentIsDeleted;
+ }
+
+ /// \brief Determine whether we need to eagerly declare a move assignment
+ /// operator for this class.
+ bool needsOverloadResolutionForMoveAssignment() const {
+ return data().NeedOverloadResolutionForMoveAssignment;
}
/// hasUserDeclaredDestructor - Whether this class has a
/// user-declared destructor. When false, a destructor will be
/// implicitly declared.
bool hasUserDeclaredDestructor() const {
- return data().UserDeclaredDestructor;
+ return data().UserDeclaredSpecialMembers & SMF_Destructor;
}
- /// \brief Determine whether this class has had its destructor declared,
- /// either via the user or via an implicit declaration.
- ///
- /// This value is used for lazy creation of destructors.
- bool hasDeclaredDestructor() const { return data().DeclaredDestructor; }
+ /// \brief Determine whether this class needs an implicit destructor to
+ /// be lazily declared.
+ bool needsImplicitDestructor() const {
+ return !(data().DeclaredSpecialMembers & SMF_Destructor);
+ }
+
+ /// \brief Determine whether we need to eagerly declare a destructor for this
+ /// class.
+ bool needsOverloadResolutionForDestructor() const {
+ return data().NeedOverloadResolutionForDestructor;
+ }
/// \brief Determine whether this class describes a lambda function object.
bool isLambda() const { return hasDefinition() && data().IsLambda; }
-
+
/// \brief For a closure type, retrieve the mapping from captured
/// variables and this to the non-static data members that store the
/// values or references of the captures.
@@ -1011,21 +989,12 @@ public:
return isLambda() ? captures_begin() + getLambdaData().NumCaptures : NULL;
}
- /// getConversions - Retrieve the overload set containing all of the
- /// conversion functions in this class.
- UnresolvedSetImpl *getConversionFunctions() {
- return &data().Conversions;
- }
- const UnresolvedSetImpl *getConversionFunctions() const {
- return &data().Conversions;
- }
-
- typedef UnresolvedSetImpl::iterator conversion_iterator;
+ typedef UnresolvedSetIterator conversion_iterator;
conversion_iterator conversion_begin() const {
- return getConversionFunctions()->begin();
+ return data().Conversions.begin();
}
conversion_iterator conversion_end() const {
- return getConversionFunctions()->end();
+ return data().Conversions.end();
}
/// Removes a conversion function from this class. The conversion
@@ -1035,7 +1004,8 @@ public:
/// getVisibleConversionFunctions - get all conversion functions visible
/// in current class; including conversion function templates.
- const UnresolvedSetImpl *getVisibleConversionFunctions();
+ std::pair<conversion_iterator, conversion_iterator>
+ getVisibleConversionFunctions();
/// isAggregate - Whether this class is an aggregate (C++
/// [dcl.init.aggr]), which is a class with no user-declared
@@ -1047,10 +1017,26 @@ public:
/// for non-static data members.
bool hasInClassInitializer() const { return data().HasInClassInitializer; }
+ /// \brief Whether this class or any of its subobjects has any members of
+ /// reference type which would make value-initialization ill-formed, per
+ /// C++03 [dcl.init]p5:
+ /// -- if T is a non-union class type without a user-declared constructor,
+ /// then every non-static data member and base-class component of T is
+ /// value-initialized
+ /// [...]
+ /// A program that calls for [...] value-initialization of an entity of
+ /// reference type is ill-formed.
+ bool hasUninitializedReferenceMember() const {
+ return !isUnion() && !hasUserDeclaredConstructor() &&
+ data().HasUninitializedReferenceMember;
+ }
+
/// isPOD - Whether this class is a POD-type (C++ [class]p4), which is a class
/// that is an aggregate that has no non-static non-POD data members, no
/// reference data members, no user-defined copy assignment operator and no
/// user-defined destructor.
+ ///
+ /// Note that this is the C++ TR1 definition of POD.
bool isPOD() const { return data().PlainOldData; }
/// \brief True if this class is C-like, without C++-specific features, e.g.
@@ -1079,64 +1065,110 @@ public:
/// mutable field.
bool hasMutableFields() const { return data().HasMutableFields; }
- /// hasTrivialDefaultConstructor - Whether this class has a trivial default
- /// constructor (C++11 [class.ctor]p5).
+ /// \brief Determine whether this class has a trivial default constructor
+ /// (C++11 [class.ctor]p5).
bool hasTrivialDefaultConstructor() const {
- return data().HasTrivialDefaultConstructor &&
- (!data().UserDeclaredConstructor ||
- data().DeclaredDefaultConstructor);
+ return hasDefaultConstructor() &&
+ (data().HasTrivialSpecialMembers & SMF_DefaultConstructor);
+ }
+
+ /// \brief Determine whether this class has a non-trivial default constructor
+ /// (C++11 [class.ctor]p5).
+ bool hasNonTrivialDefaultConstructor() const {
+ return (data().DeclaredNonTrivialSpecialMembers & SMF_DefaultConstructor) ||
+ (needsImplicitDefaultConstructor() &&
+ !(data().HasTrivialSpecialMembers & SMF_DefaultConstructor));
}
- /// hasConstexprNonCopyMoveConstructor - Whether this class has at least one
- /// constexpr constructor other than the copy or move constructors.
+ /// \brief Determine whether this class has at least one constexpr constructor
+ /// other than the copy or move constructors.
bool hasConstexprNonCopyMoveConstructor() const {
return data().HasConstexprNonCopyMoveConstructor ||
- (!hasUserDeclaredConstructor() &&
+ (needsImplicitDefaultConstructor() &&
defaultedDefaultConstructorIsConstexpr());
}
- /// defaultedDefaultConstructorIsConstexpr - Whether a defaulted default
- /// constructor for this class would be constexpr.
+ /// \brief Determine whether a defaulted default constructor for this class
+ /// would be constexpr.
bool defaultedDefaultConstructorIsConstexpr() const {
return data().DefaultedDefaultConstructorIsConstexpr &&
(!isUnion() || hasInClassInitializer());
}
- /// hasConstexprDefaultConstructor - Whether this class has a constexpr
- /// default constructor.
+ /// \brief Determine whether this class has a constexpr default constructor.
bool hasConstexprDefaultConstructor() const {
return data().HasConstexprDefaultConstructor ||
- (!data().UserDeclaredConstructor &&
+ (needsImplicitDefaultConstructor() &&
defaultedDefaultConstructorIsConstexpr());
}
- // hasTrivialCopyConstructor - Whether this class has a trivial copy
- // constructor (C++ [class.copy]p6, C++0x [class.copy]p13)
+ /// \brief Determine whether this class has a trivial copy constructor
+ /// (C++ [class.copy]p6, C++11 [class.copy]p12)
bool hasTrivialCopyConstructor() const {
- return data().HasTrivialCopyConstructor;
+ return data().HasTrivialSpecialMembers & SMF_CopyConstructor;
+ }
+
+ /// \brief Determine whether this class has a non-trivial copy constructor
+ /// (C++ [class.copy]p6, C++11 [class.copy]p12)
+ bool hasNonTrivialCopyConstructor() const {
+ return data().DeclaredNonTrivialSpecialMembers & SMF_CopyConstructor ||
+ !hasTrivialCopyConstructor();
}
- // hasTrivialMoveConstructor - Whether this class has a trivial move
- // constructor (C++0x [class.copy]p13)
+ /// \brief Determine whether this class has a trivial move constructor
+ /// (C++11 [class.copy]p12)
bool hasTrivialMoveConstructor() const {
- return data().HasTrivialMoveConstructor;
+ return hasMoveConstructor() &&
+ (data().HasTrivialSpecialMembers & SMF_MoveConstructor);
}
- // hasTrivialCopyAssignment - Whether this class has a trivial copy
- // assignment operator (C++ [class.copy]p11, C++0x [class.copy]p27)
+ /// \brief Determine whether this class has a non-trivial move constructor
+ /// (C++11 [class.copy]p12)
+ bool hasNonTrivialMoveConstructor() const {
+ return (data().DeclaredNonTrivialSpecialMembers & SMF_MoveConstructor) ||
+ (needsImplicitMoveConstructor() &&
+ !(data().HasTrivialSpecialMembers & SMF_MoveConstructor));
+ }
+
+ /// \brief Determine whether this class has a trivial copy assignment operator
+ /// (C++ [class.copy]p11, C++11 [class.copy]p25)
bool hasTrivialCopyAssignment() const {
- return data().HasTrivialCopyAssignment;
+ return data().HasTrivialSpecialMembers & SMF_CopyAssignment;
+ }
+
+ /// \brief Determine whether this class has a non-trivial copy assignment
+ /// operator (C++ [class.copy]p11, C++11 [class.copy]p25)
+ bool hasNonTrivialCopyAssignment() const {
+ return data().DeclaredNonTrivialSpecialMembers & SMF_CopyAssignment ||
+ !hasTrivialCopyAssignment();
}
- // hasTrivialMoveAssignment - Whether this class has a trivial move
- // assignment operator (C++0x [class.copy]p27)
+ /// \brief Determine whether this class has a trivial move assignment operator
+ /// (C++11 [class.copy]p25)
bool hasTrivialMoveAssignment() const {
- return data().HasTrivialMoveAssignment;
+ return hasMoveAssignment() &&
+ (data().HasTrivialSpecialMembers & SMF_MoveAssignment);
+ }
+
+ /// \brief Determine whether this class has a non-trivial move assignment
+ /// operator (C++11 [class.copy]p25)
+ bool hasNonTrivialMoveAssignment() const {
+ return (data().DeclaredNonTrivialSpecialMembers & SMF_MoveAssignment) ||
+ (needsImplicitMoveAssignment() &&
+ !(data().HasTrivialSpecialMembers & SMF_MoveAssignment));
}
- // hasTrivialDestructor - Whether this class has a trivial destructor
- // (C++ [class.dtor]p3)
- bool hasTrivialDestructor() const { return data().HasTrivialDestructor; }
+ /// \brief Determine whether this class has a trivial destructor
+ /// (C++ [class.dtor]p3)
+ bool hasTrivialDestructor() const {
+ return data().HasTrivialSpecialMembers & SMF_Destructor;
+ }
+
+ /// \brief Determine whether this class has a non-trivial destructor
+ /// (C++ [class.dtor]p3)
+ bool hasNonTrivialDestructor() const {
+ return !(data().HasTrivialSpecialMembers & SMF_Destructor);
+ }
// hasIrrelevantDestructor - Whether this class has a destructor which has no
// semantic effect. Any such destructor will be trivial, public, defaulted
@@ -1210,7 +1242,9 @@ public:
/// \brief If this class is an instantiation of a member class of a
/// class template specialization, retrieves the member specialization
/// information.
- MemberSpecializationInfo *getMemberSpecializationInfo() const;
+ MemberSpecializationInfo *getMemberSpecializationInfo() const {
+ return TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>();
+ }
/// \brief Specify that this record is an instantiation of the
/// member class RD.
@@ -1256,6 +1290,10 @@ public:
return dyn_cast<FunctionDecl>(getDeclContext());
}
+ /// \brief Determine whether this dependent class is a current instantiation,
+ /// when viewed from within the given context.
+ bool isCurrentInstantiation(const DeclContext *CurContext) const;
+
/// \brief Determine whether this class is derived from the class \p Base.
///
/// This routine only determines whether this class is derived from \p Base,
@@ -1437,6 +1475,10 @@ public:
return (PathAccess > DeclAccess ? PathAccess : DeclAccess);
}
+ /// \brief Indicates that the declaration of a defaulted or deleted special
+ /// member function is now complete.
+ void finishedDefaultedOrDeletedMember(CXXMethodDecl *MD);
+
/// \brief Indicates that the definition of this class is now complete.
virtual void completeDefinition();
@@ -1490,6 +1532,9 @@ public:
getLambdaData().ContextDecl = ContextDecl;
}
+ /// \brief Returns the inheritance model used for this record.
+ MSInheritanceModel getMSInheritanceModel() const;
+
/// \brief Determine whether this lambda expression was known to be dependent
/// at the time it was created, even if its context does not appear to be
/// dependent.
@@ -1528,11 +1573,10 @@ protected:
CXXMethodDecl(Kind DK, CXXRecordDecl *RD, SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
- bool isStatic, StorageClass SCAsWritten, bool isInline,
+ StorageClass SC, bool isInline,
bool isConstexpr, SourceLocation EndLocation)
: FunctionDecl(DK, RD, StartLoc, NameInfo, T, TInfo,
- (isStatic ? SC_Static : SC_None),
- SCAsWritten, isInline, isConstexpr) {
+ SC, isInline, isConstexpr) {
if (EndLocation.isValid())
setRangeEnd(EndLocation);
}
@@ -1542,15 +1586,14 @@ public:
SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
- bool isStatic,
- StorageClass SCAsWritten,
+ StorageClass SC,
bool isInline,
bool isConstexpr,
SourceLocation EndLocation);
static CXXMethodDecl *CreateDeserialized(ASTContext &C, unsigned ID);
-
- bool isStatic() const { return getStorageClass() == SC_Static; }
+
+ bool isStatic() const;
bool isInstance() const { return !isStatic(); }
bool isConst() const { return getType()->castAs<FunctionType>()->isConst(); }
@@ -1958,7 +2001,7 @@ class CXXConstructorDecl : public CXXMethodDecl {
QualType T, TypeSourceInfo *TInfo,
bool isExplicitSpecified, bool isInline,
bool isImplicitlyDeclared, bool isConstexpr)
- : CXXMethodDecl(CXXConstructor, RD, StartLoc, NameInfo, T, TInfo, false,
+ : CXXMethodDecl(CXXConstructor, RD, StartLoc, NameInfo, T, TInfo,
SC_None, isInline, isConstexpr, SourceLocation()),
IsExplicitSpecified(isExplicitSpecified), ImplicitlyDefined(false),
CtorInitializers(0), NumCtorInitializers(0) {
@@ -2077,7 +2120,7 @@ public:
/// constructor (C++ [class.copy]p2, which can be used to copy the
/// class. @p TypeQuals will be set to the qualifiers on the
/// argument type. For example, @p TypeQuals would be set to @c
- /// QualType::Const for the following copy constructor:
+ /// Qualifiers::Const for the following copy constructor:
///
/// @code
/// class X {
@@ -2177,7 +2220,7 @@ class CXXDestructorDecl : public CXXMethodDecl {
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
bool isInline, bool isImplicitlyDeclared)
- : CXXMethodDecl(CXXDestructor, RD, StartLoc, NameInfo, T, TInfo, false,
+ : CXXMethodDecl(CXXDestructor, RD, StartLoc, NameInfo, T, TInfo,
SC_None, isInline, /*isConstexpr=*/false, SourceLocation()),
ImplicitlyDefined(false), OperatorDelete(0) {
setImplicit(isImplicitlyDeclared);
@@ -2244,7 +2287,7 @@ class CXXConversionDecl : public CXXMethodDecl {
QualType T, TypeSourceInfo *TInfo,
bool isInline, bool isExplicitSpecified,
bool isConstexpr, SourceLocation EndLocation)
- : CXXMethodDecl(CXXConversion, RD, StartLoc, NameInfo, T, TInfo, false,
+ : CXXMethodDecl(CXXConversion, RD, StartLoc, NameInfo, T, TInfo,
SC_None, isInline, isConstexpr, EndLocation),
IsExplicitSpecified(isExplicitSpecified) { }
diff --git a/include/clang/AST/DeclContextInternals.h b/include/clang/AST/DeclContextInternals.h
index 39f04c6..84f3698 100644
--- a/include/clang/AST/DeclContextInternals.h
+++ b/include/clang/AST/DeclContextInternals.h
@@ -15,10 +15,10 @@
#define LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H
#include "clang/AST/Decl.h"
-#include "clang/AST/DeclarationName.h"
#include "clang/AST/DeclCXX.h"
-#include "llvm/ADT/PointerUnion.h"
+#include "clang/AST/DeclarationName.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/SmallVector.h"
#include <algorithm>
@@ -97,6 +97,22 @@ public:
== Vec.end() && "list still contains decl");
}
+ /// \brief Remove any declarations which were imported from an external
+ /// AST source.
+ void removeExternalDecls() {
+ if (isNull()) {
+ // Nothing to do.
+ } else if (NamedDecl *Singleton = getAsDecl()) {
+ if (Singleton->isFromASTFile())
+ *this = StoredDeclsList();
+ } else {
+ DeclsTy &Vec = *getAsVector();
+ Vec.erase(std::remove_if(Vec.begin(), Vec.end(),
+ std::mem_fun(&Decl::isFromASTFile)),
+ Vec.end());
+ }
+ }
+
/// getLookupResult - Return an array of all the decls that this list
/// represents.
DeclContext::lookup_result getLookupResult() {
@@ -117,7 +133,7 @@ public:
DeclsTy &Vector = *getAsVector();
// Otherwise, we have a range result.
- return DeclContext::lookup_result(&Vector[0], &Vector[0]+Vector.size());
+ return DeclContext::lookup_result(Vector.begin(), Vector.end());
}
/// HandleRedeclaration - If this is a redeclaration of an existing decl,
@@ -186,7 +202,7 @@ public:
// All other declarations go at the end of the list, but before any
// tag declarations. But we can be clever about tag declarations
// because there can only ever be one in a scope.
- } else if (Vec.back()->hasTagIdentifierNamespace()) {
+ } else if (!Vec.empty() && Vec.back()->hasTagIdentifierNamespace()) {
NamedDecl *TagD = Vec.back();
Vec.back() = D;
Vec.push_back(TagD);
diff --git a/include/clang/AST/DeclFriend.h b/include/clang/AST/DeclFriend.h
index 37e4586..253c23c 100644
--- a/include/clang/AST/DeclFriend.h
+++ b/include/clang/AST/DeclFriend.h
@@ -54,22 +54,40 @@ private:
/// True if this 'friend' declaration is unsupported. Eventually we
/// will support every possible friend declaration, but for now we
/// silently ignore some and set this flag to authorize all access.
- bool UnsupportedFriend;
+ bool UnsupportedFriend : 1;
+
+ // The number of "outer" template parameter lists in non-templatic
+ // (currently unsupported) friend type declarations, such as
+ // template <class T> friend class A<T>::B;
+ unsigned NumTPLists : 31;
+
+ // The tail-allocated friend type template parameter lists (if any).
+ TemplateParameterList* const *getTPLists() const {
+ return reinterpret_cast<TemplateParameterList* const *>(this + 1);
+ }
+ TemplateParameterList **getTPLists() {
+ return reinterpret_cast<TemplateParameterList**>(this + 1);
+ }
friend class CXXRecordDecl::friend_iterator;
friend class CXXRecordDecl;
FriendDecl(DeclContext *DC, SourceLocation L, FriendUnion Friend,
- SourceLocation FriendL)
+ SourceLocation FriendL,
+ ArrayRef<TemplateParameterList*> FriendTypeTPLists)
: Decl(Decl::Friend, DC, L),
Friend(Friend),
NextFriend(),
FriendLoc(FriendL),
- UnsupportedFriend(false) {
+ UnsupportedFriend(false),
+ NumTPLists(FriendTypeTPLists.size()) {
+ for (unsigned i = 0; i < NumTPLists; ++i)
+ getTPLists()[i] = FriendTypeTPLists[i];
}
- explicit FriendDecl(EmptyShell Empty)
- : Decl(Decl::Friend, Empty), NextFriend() { }
+ FriendDecl(EmptyShell Empty, unsigned NumFriendTypeTPLists)
+ : Decl(Decl::Friend, Empty), NextFriend(),
+ NumTPLists(NumFriendTypeTPLists) { }
FriendDecl *getNextFriend() {
if (!NextFriend.isOffset())
@@ -81,8 +99,11 @@ private:
public:
static FriendDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, FriendUnion Friend_,
- SourceLocation FriendL);
- static FriendDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+ SourceLocation FriendL,
+ ArrayRef<TemplateParameterList*> FriendTypeTPLists
+ = ArrayRef<TemplateParameterList*>());
+ static FriendDecl *CreateDeserialized(ASTContext &C, unsigned ID,
+ unsigned FriendTypeNumTPLists);
/// If this friend declaration names an (untemplated but possibly
/// dependent) type, return the type; otherwise return null. This
@@ -91,6 +112,13 @@ public:
TypeSourceInfo *getFriendType() const {
return Friend.dyn_cast<TypeSourceInfo*>();
}
+ unsigned getFriendTypeNumTemplateParameterLists() const {
+ return NumTPLists;
+ }
+ TemplateParameterList *getFriendTypeTemplateParameterList(unsigned N) const {
+ assert(N < NumTPLists);
+ return getTPLists()[N];
+ }
/// If this friend declaration doesn't name a type, return the inner
/// declaration.
@@ -114,8 +142,12 @@ public:
}
return SourceRange(getFriendLoc(), ND->getLocEnd());
}
- else if (TypeSourceInfo *TInfo = getFriendType())
- return SourceRange(getFriendLoc(), TInfo->getTypeLoc().getEndLoc());
+ else if (TypeSourceInfo *TInfo = getFriendType()) {
+ SourceLocation StartL = (NumTPLists == 0)
+ ? getFriendLoc()
+ : getTPLists()[0]->getTemplateLoc();
+ return SourceRange(StartL, TInfo->getTypeLoc().getEndLoc());
+ }
else
return SourceRange(getFriendLoc(), getLocation());
}
diff --git a/include/clang/AST/DeclLookups.h b/include/clang/AST/DeclLookups.h
index 867b465..4477c25 100644
--- a/include/clang/AST/DeclLookups.h
+++ b/include/clang/AST/DeclLookups.h
@@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_AST_DECLLOOKUPS_H
#define LLVM_CLANG_AST_DECLLOOKUPS_H
+#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclContextInternals.h"
#include "clang/AST/DeclarationName.h"
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index 8b27dd8..c294922 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -159,6 +159,9 @@ private:
/// method in the interface or its categories.
unsigned IsOverriding : 1;
+ /// \brief Indicates if the method was a definition but its body was skipped.
+ unsigned HasSkippedBody : 1;
+
// Result type of this method.
QualType MethodDeclType;
@@ -238,7 +241,7 @@ private:
IsDefined(isDefined), IsRedeclaration(0), HasRedeclaration(0),
DeclImplementation(impControl), objcDeclQualifier(OBJC_TQ_None),
RelatedResultType(HasRelatedResultType),
- SelLocsKind(SelLoc_StandardNoSpace), IsOverriding(0),
+ SelLocsKind(SelLoc_StandardNoSpace), IsOverriding(0), HasSkippedBody(0),
MethodDeclType(T), ResultTInfo(ResultTInfo),
ParamsAndSelLocs(0), NumParams(0),
DeclEndLoc(endLoc), Body(), SelfDecl(0), CmdDecl(0) {
@@ -429,6 +432,10 @@ public:
void getOverriddenMethods(
SmallVectorImpl<const ObjCMethodDecl *> &Overridden) const;
+ /// \brief True if the method was a definition but its body was skipped.
+ bool hasSkippedBody() const { return HasSkippedBody; }
+ void setHasSkippedBody(bool Skipped = true) { HasSkippedBody = Skipped; }
+
/// \brief Returns the property associated with this method's selector.
///
/// Note that even if this particular method is not marked as a property
@@ -530,23 +537,29 @@ public:
}
// Get the local instance/class method declared in this interface.
- ObjCMethodDecl *getMethod(Selector Sel, bool isInstance) const;
- ObjCMethodDecl *getInstanceMethod(Selector Sel) const {
- return getMethod(Sel, true/*isInstance*/);
+ ObjCMethodDecl *getMethod(Selector Sel, bool isInstance,
+ bool AllowHidden = false) const;
+ ObjCMethodDecl *getInstanceMethod(Selector Sel,
+ bool AllowHidden = false) const {
+ return getMethod(Sel, true/*isInstance*/, AllowHidden);
}
- ObjCMethodDecl *getClassMethod(Selector Sel) const {
- return getMethod(Sel, false/*isInstance*/);
+ ObjCMethodDecl *getClassMethod(Selector Sel, bool AllowHidden = false) const {
+ return getMethod(Sel, false/*isInstance*/, AllowHidden);
}
+ bool HasUserDeclaredSetterMethod(const ObjCPropertyDecl *P) const;
ObjCIvarDecl *getIvarDecl(IdentifierInfo *Id) const;
ObjCPropertyDecl *FindPropertyDeclaration(IdentifierInfo *PropertyId) const;
typedef llvm::DenseMap<IdentifierInfo*, ObjCPropertyDecl*> PropertyMap;
-
+
+ typedef llvm::SmallVector<ObjCPropertyDecl*, 8> PropertyDeclOrder;
+
/// This routine collects list of properties to be implemented in the class.
/// This includes, class's and its conforming protocols' properties.
/// Note, the superclass's properties are not included in the list.
- virtual void collectPropertiesToImplement(PropertyMap &PM) const {}
+ virtual void collectPropertiesToImplement(PropertyMap &PM,
+ PropertyDeclOrder &PO) const {}
SourceLocation getAtStartLoc() const { return AtStart; }
void setAtStartLoc(SourceLocation Loc) { AtStart = Loc; }
@@ -641,6 +654,10 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
/// completed by the external AST source when required.
mutable bool ExternallyCompleted : 1;
+ /// \brief Indicates that the ivar cache does not yet include ivars
+ /// declared in the implementation.
+ mutable bool IvarListMissingImplementation : 1;
+
/// \brief The location of the superclass, if any.
SourceLocation SuperClassLoc;
@@ -650,7 +667,8 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
SourceLocation EndLoc;
DefinitionData() : Definition(), SuperClass(), CategoryList(), IvarList(),
- ExternallyCompleted() { }
+ ExternallyCompleted(),
+ IvarListMissingImplementation(true) { }
};
ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id,
@@ -661,11 +679,14 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
/// \brief Contains a pointer to the data associated with this class,
/// which will be NULL if this class has not yet been defined.
- DefinitionData *Data;
+ ///
+ /// The bit indicates when we don't need to check for out-of-date
+ /// declarations. It will be set unless modules are enabled.
+ llvm::PointerIntPair<DefinitionData *, 1, bool> Data;
DefinitionData &data() const {
- assert(Data != 0 && "Declaration has no definition!");
- return *Data;
+ assert(Data.getPointer() && "Declaration has no definition!");
+ return *Data.getPointer();
}
/// \brief Allocate the definition data for this class.
@@ -673,7 +694,7 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
typedef Redeclarable<ObjCInterfaceDecl> redeclarable_base;
virtual ObjCInterfaceDecl *getNextRedeclaration() {
- return RedeclLink.getNext();
+ return RedeclLink.getNext();
}
virtual ObjCInterfaceDecl *getPreviousDeclImpl() {
return getPreviousDecl();
@@ -846,24 +867,38 @@ public:
/// \brief Determine whether this particular declaration of this class is
/// actually also a definition.
bool isThisDeclarationADefinition() const {
- return Data && Data->Definition == this;
+ return getDefinition() == this;
}
/// \brief Determine whether this class has been defined.
- bool hasDefinition() const { return Data; }
+ bool hasDefinition() const {
+ // If the name of this class is out-of-date, bring it up-to-date, which
+ // might bring in a definition.
+ // Note: a null value indicates that we don't have a definition and that
+ // modules are enabled.
+ if (!Data.getOpaqueValue()) {
+ if (IdentifierInfo *II = getIdentifier()) {
+ if (II->isOutOfDate()) {
+ updateOutOfDate(*II);
+ }
+ }
+ }
+
+ return Data.getPointer();
+ }
/// \brief Retrieve the definition of this class, or NULL if this class
/// has been forward-declared (with \@class) but not yet defined (with
/// \@interface).
ObjCInterfaceDecl *getDefinition() {
- return hasDefinition()? Data->Definition : 0;
+ return hasDefinition()? Data.getPointer()->Definition : 0;
}
/// \brief Retrieve the definition of this class, or NULL if this class
/// has been forward-declared (with \@class) but not yet defined (with
/// \@interface).
const ObjCInterfaceDecl *getDefinition() const {
- return hasDefinition()? Data->Definition : 0;
+ return hasDefinition()? Data.getPointer()->Definition : 0;
}
/// \brief Starts the definition of this Objective-C class, taking it from
@@ -887,7 +922,166 @@ public:
: superCls;
}
- ObjCCategoryDecl* getCategoryList() const {
+ /// \brief Iterator that walks over the list of categories, filtering out
+ /// those that do not meet specific criteria.
+ ///
+ /// This class template is used for the various permutations of category
+ /// and extension iterators.
+ template<bool (*Filter)(ObjCCategoryDecl *)>
+ class filtered_category_iterator {
+ ObjCCategoryDecl *Current;
+
+ void findAcceptableCategory();
+
+ public:
+ typedef ObjCCategoryDecl * value_type;
+ typedef value_type reference;
+ typedef value_type pointer;
+ typedef std::ptrdiff_t difference_type;
+ typedef std::input_iterator_tag iterator_category;
+
+ filtered_category_iterator() : Current(0) { }
+ explicit filtered_category_iterator(ObjCCategoryDecl *Current)
+ : Current(Current)
+ {
+ findAcceptableCategory();
+ }
+
+ reference operator*() const { return Current; }
+ pointer operator->() const { return Current; }
+
+ filtered_category_iterator &operator++();
+
+ filtered_category_iterator operator++(int) {
+ filtered_category_iterator Tmp = *this;
+ ++(*this);
+ return Tmp;
+ }
+
+ friend bool operator==(filtered_category_iterator X,
+ filtered_category_iterator Y) {
+ return X.Current == Y.Current;
+ }
+
+ friend bool operator!=(filtered_category_iterator X,
+ filtered_category_iterator Y) {
+ return X.Current != Y.Current;
+ }
+ };
+
+private:
+ /// \brief Test whether the given category is visible.
+ ///
+ /// Used in the \c visible_categories_iterator.
+ static bool isVisibleCategory(ObjCCategoryDecl *Cat);
+
+public:
+ /// \brief Iterator that walks over the list of categories and extensions
+ /// that are visible, i.e., not hidden in a non-imported submodule.
+ typedef filtered_category_iterator<isVisibleCategory>
+ visible_categories_iterator;
+
+ /// \brief Retrieve an iterator to the beginning of the visible-categories
+ /// list.
+ visible_categories_iterator visible_categories_begin() const {
+ return visible_categories_iterator(getCategoryListRaw());
+ }
+
+ /// \brief Retrieve an iterator to the end of the visible-categories list.
+ visible_categories_iterator visible_categories_end() const {
+ return visible_categories_iterator();
+ }
+
+ /// \brief Determine whether the visible-categories list is empty.
+ bool visible_categories_empty() const {
+ return visible_categories_begin() == visible_categories_end();
+ }
+
+private:
+ /// \brief Test whether the given category... is a category.
+ ///
+ /// Used in the \c known_categories_iterator.
+ static bool isKnownCategory(ObjCCategoryDecl *) { return true; }
+
+public:
+ /// \brief Iterator that walks over all of the known categories and
+ /// extensions, including those that are hidden.
+ typedef filtered_category_iterator<isKnownCategory> known_categories_iterator;
+
+ /// \brief Retrieve an iterator to the beginning of the known-categories
+ /// list.
+ known_categories_iterator known_categories_begin() const {
+ return known_categories_iterator(getCategoryListRaw());
+ }
+
+ /// \brief Retrieve an iterator to the end of the known-categories list.
+ known_categories_iterator known_categories_end() const {
+ return known_categories_iterator();
+ }
+
+ /// \brief Determine whether the known-categories list is empty.
+ bool known_categories_empty() const {
+ return known_categories_begin() == known_categories_end();
+ }
+
+private:
+ /// \brief Test whether the given category is a visible extension.
+ ///
+ /// Used in the \c visible_extensions_iterator.
+ static bool isVisibleExtension(ObjCCategoryDecl *Cat);
+
+public:
+ /// \brief Iterator that walks over all of the visible extensions, skipping
+ /// any that are known but hidden.
+ typedef filtered_category_iterator<isVisibleExtension>
+ visible_extensions_iterator;
+
+ /// \brief Retrieve an iterator to the beginning of the visible-extensions
+ /// list.
+ visible_extensions_iterator visible_extensions_begin() const {
+ return visible_extensions_iterator(getCategoryListRaw());
+ }
+
+ /// \brief Retrieve an iterator to the end of the visible-extensions list.
+ visible_extensions_iterator visible_extensions_end() const {
+ return visible_extensions_iterator();
+ }
+
+ /// \brief Determine whether the visible-extensions list is empty.
+ bool visible_extensions_empty() const {
+ return visible_extensions_begin() == visible_extensions_end();
+ }
+
+private:
+ /// \brief Test whether the given category is an extension.
+ ///
+ /// Used in the \c known_extensions_iterator.
+ static bool isKnownExtension(ObjCCategoryDecl *Cat);
+
+public:
+ /// \brief Iterator that walks over all of the known extensions.
+ typedef filtered_category_iterator<isKnownExtension>
+ known_extensions_iterator;
+
+ /// \brief Retrieve an iterator to the beginning of the known-extensions
+ /// list.
+ known_extensions_iterator known_extensions_begin() const {
+ return known_extensions_iterator(getCategoryListRaw());
+ }
+
+ /// \brief Retrieve an iterator to the end of the known-extensions list.
+ known_extensions_iterator known_extensions_end() const {
+ return known_extensions_iterator();
+ }
+
+ /// \brief Determine whether the known-extensions list is empty.
+ bool known_extensions_empty() const {
+ return known_extensions_begin() == known_extensions_end();
+ }
+
+ /// \brief Retrieve the raw pointer to the start of the category/extension
+ /// list.
+ ObjCCategoryDecl* getCategoryListRaw() const {
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return 0;
@@ -898,16 +1092,17 @@ public:
return data().CategoryList;
}
- void setCategoryList(ObjCCategoryDecl *category) {
+ /// \brief Set the raw pointer to the start of the category/extension
+ /// list.
+ void setCategoryListRaw(ObjCCategoryDecl *category) {
data().CategoryList = category;
}
- ObjCCategoryDecl* getFirstClassExtension() const;
-
ObjCPropertyDecl
*FindPropertyVisibleInPrimaryClass(IdentifierInfo *PropertyId) const;
- virtual void collectPropertiesToImplement(PropertyMap &PM) const;
+ virtual void collectPropertiesToImplement(PropertyMap &PM,
+ PropertyDeclOrder &PO) const;
/// isSuperClassOf - Return true if this class is the specified class or is a
/// super class of the specified interface class.
@@ -924,28 +1119,12 @@ public:
/// isArcWeakrefUnavailable - Checks for a class or one of its super classes
/// to be incompatible with __weak references. Returns true if it is.
- bool isArcWeakrefUnavailable() const {
- const ObjCInterfaceDecl *Class = this;
- while (Class) {
- if (Class->hasAttr<ArcWeakrefUnavailableAttr>())
- return true;
- Class = Class->getSuperClass();
- }
- return false;
- }
+ bool isArcWeakrefUnavailable() const;
/// isObjCRequiresPropertyDefs - Checks that a class or one of its super
/// classes must not be auto-synthesized. Returns class decl. if it must not
/// be; 0, otherwise.
- const ObjCInterfaceDecl *isObjCRequiresPropertyDefs() const {
- const ObjCInterfaceDecl *Class = this;
- while (Class) {
- if (Class->hasAttr<ObjCRequiresPropertyDefsAttr>())
- return Class;
- Class = Class->getSuperClass();
- }
- return 0;
- }
+ const ObjCInterfaceDecl *isObjCRequiresPropertyDefs() const;
ObjCIvarDecl *lookupInstanceVariable(IdentifierInfo *IVarName,
ObjCInterfaceDecl *&ClassDeclared);
@@ -992,7 +1171,7 @@ public:
/// ObjCInterfaceDecl node. This is for legacy objective-c \@implementation
/// declaration without an \@interface declaration.
bool isImplicitInterfaceDecl() const {
- return hasDefinition() ? Data->Definition->isImplicit() : isImplicit();
+ return hasDefinition() ? data().Definition->isImplicit() : isImplicit();
}
/// ClassImplementsProtocol - Checks that 'lProto' protocol
@@ -1169,12 +1348,17 @@ class ObjCProtocolDecl : public ObjCContainerDecl,
/// \brief Referenced protocols
ObjCProtocolList ReferencedProtocols;
};
-
- DefinitionData *Data;
+
+ /// \brief Contains a pointer to the data associated with this class,
+ /// which will be NULL if this class has not yet been defined.
+ ///
+ /// The bit indicates when we don't need to check for out-of-date
+ /// declarations. It will be set unless modules are enabled.
+ llvm::PointerIntPair<DefinitionData *, 1, bool> Data;
DefinitionData &data() const {
- assert(Data && "Objective-C protocol has no definition!");
- return *Data;
+ assert(Data.getPointer() && "Objective-C protocol has no definition!");
+ return *Data.getPointer();
}
ObjCProtocolDecl(DeclContext *DC, IdentifierInfo *Id,
@@ -1193,7 +1377,7 @@ class ObjCProtocolDecl : public ObjCContainerDecl,
virtual ObjCProtocolDecl *getMostRecentDeclImpl() {
return getMostRecentDecl();
}
-
+
public:
static ObjCProtocolDecl *Create(ASTContext &C, DeclContext *DC,
IdentifierInfo *Id,
@@ -1244,7 +1428,7 @@ public:
/// implements.
void setProtocolList(ObjCProtocolDecl *const*List, unsigned Num,
const SourceLocation *Locs, ASTContext &C) {
- assert(Data && "Protocol is not defined");
+ assert(hasDefinition() && "Protocol is not defined");
data().ReferencedProtocols.set(List, Num, Locs, C);
}
@@ -1261,16 +1445,30 @@ public:
}
/// \brief Determine whether this protocol has a definition.
- bool hasDefinition() const { return Data != 0; }
+ bool hasDefinition() const {
+ // If the name of this protocol is out-of-date, bring it up-to-date, which
+ // might bring in a definition.
+ // Note: a null value indicates that we don't have a definition and that
+ // modules are enabled.
+ if (!Data.getOpaqueValue()) {
+ if (IdentifierInfo *II = getIdentifier()) {
+ if (II->isOutOfDate()) {
+ updateOutOfDate(*II);
+ }
+ }
+ }
+
+ return Data.getPointer();
+ }
/// \brief Retrieve the definition of this protocol, if any.
ObjCProtocolDecl *getDefinition() {
- return Data? Data->Definition : 0;
+ return hasDefinition()? Data.getPointer()->Definition : 0;
}
/// \brief Retrieve the definition of this protocol, if any.
const ObjCProtocolDecl *getDefinition() const {
- return Data? Data->Definition : 0;
+ return hasDefinition()? Data.getPointer()->Definition : 0;
}
/// \brief Determine whether this particular declaration is also the
@@ -1303,7 +1501,8 @@ public:
return getFirstDeclaration();
}
- virtual void collectPropertiesToImplement(PropertyMap &PM) const;
+ virtual void collectPropertiesToImplement(PropertyMap &PM,
+ PropertyDeclOrder &PO) const;
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == ObjCProtocol; }
@@ -1360,6 +1559,7 @@ class ObjCCategoryDecl : public ObjCContainerDecl {
CategoryNameLoc(CategoryNameLoc),
IvarLBraceLoc(IvarLBraceLoc), IvarRBraceLoc(IvarRBraceLoc) {
}
+
public:
static ObjCCategoryDecl *Create(ASTContext &C, DeclContext *DC,
@@ -1403,8 +1603,13 @@ public:
ObjCCategoryDecl *getNextClassCategory() const { return NextClassCategory; }
+ /// \brief Retrieve the pointer to the next stored category (or extension),
+ /// which may be hidden.
+ ObjCCategoryDecl *getNextClassCategoryRaw() const {
+ return NextClassCategory;
+ }
+
bool IsClassExtension() const { return getIdentifier() == 0; }
- const ObjCCategoryDecl *getNextClassExtension() const;
typedef specific_decl_iterator<ObjCIvarDecl> ivar_iterator;
ivar_iterator ivar_begin() const {
@@ -1847,7 +2052,7 @@ public:
PropertyAttributesAsWritten = PRVal;
}
- void makeitReadWriteAttribute(void) {
+ void makeitReadWriteAttribute() {
PropertyAttributes &= ~OBJC_PR_readonly;
PropertyAttributes |= OBJC_PR_readwrite;
}
@@ -2039,5 +2244,33 @@ public:
friend class ASTDeclReader;
};
+template<bool (*Filter)(ObjCCategoryDecl *)>
+void
+ObjCInterfaceDecl::filtered_category_iterator<Filter>::
+findAcceptableCategory() {
+ while (Current && !Filter(Current))
+ Current = Current->getNextClassCategoryRaw();
+}
+
+template<bool (*Filter)(ObjCCategoryDecl *)>
+inline ObjCInterfaceDecl::filtered_category_iterator<Filter> &
+ObjCInterfaceDecl::filtered_category_iterator<Filter>::operator++() {
+ Current = Current->getNextClassCategoryRaw();
+ findAcceptableCategory();
+ return *this;
+}
+
+inline bool ObjCInterfaceDecl::isVisibleCategory(ObjCCategoryDecl *Cat) {
+ return !Cat->isHidden();
+}
+
+inline bool ObjCInterfaceDecl::isVisibleExtension(ObjCCategoryDecl *Cat) {
+ return Cat->IsClassExtension() && !Cat->isHidden();
+}
+
+inline bool ObjCInterfaceDecl::isKnownExtension(ObjCCategoryDecl *Cat) {
+ return Cat->IsClassExtension();
+}
+
} // end namespace clang
#endif
diff --git a/include/clang/AST/DeclOpenMP.h b/include/clang/AST/DeclOpenMP.h
new file mode 100644
index 0000000..ca92040
--- /dev/null
+++ b/include/clang/AST/DeclOpenMP.h
@@ -0,0 +1,83 @@
+//===--- OpenMP.h - Classes for representing OpenMP directives ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file defines OpenMP nodes.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_OPENMP_H
+#define LLVM_CLANG_AST_OPENMP_H
+
+#include "clang/AST/DeclBase.h"
+#include "llvm/ADT/ArrayRef.h"
+
+namespace clang {
+
+class DeclRefExpr;
+
+/// \brief This represents '#pragma omp threadprivate ...' directive.
+/// For example, in the following, both 'a' and 'A::b' are threadprivate:
+///
+/// \code
+/// int a;
+/// #pragma omp threadprivate(a)
+/// struct A {
+/// static int b;
+/// #pragma omp threadprivate(b)
+/// };
+/// \endcode
+///
+class OMPThreadPrivateDecl : public Decl {
+ friend class ASTDeclReader;
+ unsigned NumVars;
+
+ virtual void anchor();
+
+ OMPThreadPrivateDecl(Kind DK, DeclContext *DC, SourceLocation L) :
+ Decl(DK, DC, L), NumVars(0) { }
+
+ ArrayRef<const DeclRefExpr *> getVars() const {
+ return ArrayRef<const DeclRefExpr *>(
+ reinterpret_cast<const DeclRefExpr * const *>(this + 1),
+ NumVars);
+ }
+
+ llvm::MutableArrayRef<DeclRefExpr *> getVars() {
+ return llvm::MutableArrayRef<DeclRefExpr *>(
+ reinterpret_cast<DeclRefExpr **>(this + 1),
+ NumVars);
+ }
+
+ void setVars(ArrayRef<DeclRefExpr *> VL);
+
+public:
+ static OMPThreadPrivateDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L,
+ ArrayRef<DeclRefExpr *> VL);
+ static OMPThreadPrivateDecl *CreateDeserialized(ASTContext &C,
+ unsigned ID, unsigned N);
+
+ typedef llvm::MutableArrayRef<DeclRefExpr *>::iterator varlist_iterator;
+ typedef ArrayRef<const DeclRefExpr *>::iterator varlist_const_iterator;
+
+ unsigned varlist_size() const { return NumVars; }
+ bool varlist_empty() const { return NumVars == 0; }
+ varlist_iterator varlist_begin() { return getVars().begin(); }
+ varlist_iterator varlist_end() { return getVars().end(); }
+ varlist_const_iterator varlist_begin() const { return getVars().begin(); }
+ varlist_const_iterator varlist_end() const { return getVars().end(); }
+
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classofKind(Kind K) { return K == OMPThreadPrivate; }
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index 8620116..425a617 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -84,6 +84,13 @@ public:
unsigned size() const { return NumParams; }
+ llvm::ArrayRef<NamedDecl*> asArray() {
+ return llvm::ArrayRef<NamedDecl*>(begin(), size());
+ }
+ llvm::ArrayRef<const NamedDecl*> asArray() const {
+ return llvm::ArrayRef<const NamedDecl*>(begin(), size());
+ }
+
NamedDecl* getParam(unsigned Idx) {
assert(Idx < size() && "Template parameter index out-of-range");
return begin()[Idx];
@@ -193,6 +200,11 @@ public:
/// \brief Retrieve the template argument at a given index.
const TemplateArgument &operator[](unsigned Idx) const { return get(Idx); }
+ /// \brief Produce this as an array ref.
+ llvm::ArrayRef<TemplateArgument> asArray() const {
+ return llvm::ArrayRef<TemplateArgument>(data(), size());
+ }
+
/// \brief Retrieve the number of template arguments in this
/// template argument list.
unsigned size() const { return NumArguments; }
@@ -324,6 +336,23 @@ public:
return getTemplateSpecializationKind() == TSK_ExplicitSpecialization;
}
+ /// \brief True if this declaration is an explicit specialization,
+ /// explicit instantiation declaration, or explicit instantiation
+ /// definition.
+ bool isExplicitInstantiationOrSpecialization() const {
+ switch (getTemplateSpecializationKind()) {
+ case TSK_ExplicitSpecialization:
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ExplicitInstantiationDefinition:
+ return true;
+
+ case TSK_Undeclared:
+ case TSK_ImplicitInstantiation:
+ return false;
+ }
+ llvm_unreachable("bad template specialization kind");
+ }
+
/// \brief Set the template specialization kind.
void setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
assert(TSK != TSK_Undeclared &&
@@ -390,6 +419,10 @@ public:
return (TemplateSpecializationKind)(MemberAndTSK.getInt() + 1);
}
+ bool isExplicitSpecialization() const {
+ return getTemplateSpecializationKind() == TSK_ExplicitSpecialization;
+ }
+
/// \brief Set the template specialization kind.
void setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
assert(TSK != TSK_Undeclared &&
@@ -425,18 +458,19 @@ public:
/// };
/// \endcode
class DependentFunctionTemplateSpecializationInfo {
+ struct CA {
+ /// The number of potential template candidates.
+ unsigned NumTemplates;
+
+ /// The number of template arguments.
+ unsigned NumArgs;
+ };
+
union {
// Force sizeof to be a multiple of sizeof(void*) so that the
// trailing data is aligned.
void *Aligner;
-
- struct {
- /// The number of potential template candidates.
- unsigned NumTemplates;
-
- /// The number of template arguments.
- unsigned NumArgs;
- } d;
+ struct CA d;
};
/// The locations of the left and right angle brackets.
@@ -552,7 +586,7 @@ protected:
};
template <typename EntryType>
- SpecIterator<EntryType>
+ static SpecIterator<EntryType>
makeSpecIterator(llvm::FoldingSetVector<EntryType> &Specs, bool isEnd) {
return SpecIterator<EntryType>(isEnd ? Specs.end() : Specs.begin());
}
@@ -576,14 +610,14 @@ protected:
/// \brief Pointer to the common data shared by all declarations of this
/// template.
- CommonBase *Common;
+ mutable CommonBase *Common;
/// \brief Retrieves the "common" pointer shared by all (re-)declarations of
/// the same template. Calling this routine may implicitly allocate memory
/// for the common pointer.
- CommonBase *getCommonPtr();
+ CommonBase *getCommonPtr() const;
- virtual CommonBase *newCommon(ASTContext &C) = 0;
+ virtual CommonBase *newCommon(ASTContext &C) const = 0;
// Construct a template decl with name, parameters, and templated element.
RedeclarableTemplateDecl(Kind DK, DeclContext *DC, SourceLocation L,
@@ -618,7 +652,7 @@ public:
/// template<> template<typename T>
/// struct X<int>::Inner { /* ... */ };
/// \endcode
- bool isMemberSpecialization() {
+ bool isMemberSpecialization() const {
return getCommonPtr()->InstantiatedFromMember.getInt();
}
@@ -665,7 +699,7 @@ public:
/// template<typename U>
/// void X<T>::f(T, U);
/// \endcode
- RedeclarableTemplateDecl *getInstantiatedFromMemberTemplate() {
+ RedeclarableTemplateDecl *getInstantiatedFromMemberTemplate() const {
return getCommonPtr()->InstantiatedFromMember.getPointer();
}
@@ -729,9 +763,9 @@ protected:
TemplateParameterList *Params, NamedDecl *Decl)
: RedeclarableTemplateDecl(FunctionTemplate, DC, L, Name, Params, Decl) { }
- CommonBase *newCommon(ASTContext &C);
+ CommonBase *newCommon(ASTContext &C) const;
- Common *getCommonPtr() {
+ Common *getCommonPtr() const {
return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr());
}
@@ -740,7 +774,7 @@ protected:
/// \brief Retrieve the set of function template specializations of this
/// function template.
llvm::FoldingSetVector<FunctionTemplateSpecializationInfo> &
- getSpecializations() {
+ getSpecializations() const {
return getCommonPtr()->Specializations;
}
@@ -798,11 +832,11 @@ public:
typedef SpecIterator<FunctionTemplateSpecializationInfo> spec_iterator;
- spec_iterator spec_begin() {
+ spec_iterator spec_begin() const {
return makeSpecIterator(getSpecializations(), false);
}
- spec_iterator spec_end() {
+ spec_iterator spec_end() const {
return makeSpecIterator(getSpecializations(), true);
}
@@ -1205,7 +1239,7 @@ public:
unsigned P,
IdentifierInfo *Id,
TemplateParameterList *Params,
- llvm::ArrayRef<TemplateParameterList*> Expansions);
+ ArrayRef<TemplateParameterList *> Expansions);
static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C,
unsigned ID);
@@ -1399,7 +1433,7 @@ public:
static ClassTemplateSpecializationDecl *
CreateDeserialized(ASTContext &C, unsigned ID);
- virtual void getNameForDiagnostic(std::string &S,
+ virtual void getNameForDiagnostic(raw_ostream &OS,
const PrintingPolicy &Policy,
bool Qualified) const;
@@ -1433,6 +1467,23 @@ public:
return getSpecializationKind() == TSK_ExplicitSpecialization;
}
+ /// \brief True if this declaration is an explicit specialization,
+ /// explicit instantiation declaration, or explicit instantiation
+ /// definition.
+ bool isExplicitInstantiationOrSpecialization() const {
+ switch (getTemplateSpecializationKind()) {
+ case TSK_ExplicitSpecialization:
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ExplicitInstantiationDefinition:
+ return true;
+
+ case TSK_Undeclared:
+ case TSK_ImplicitInstantiation:
+ return false;
+ }
+ llvm_unreachable("bad template specialization kind");
+ }
+
void setSpecializationKind(TemplateSpecializationKind TSK) {
SpecializationKind = TSK;
}
@@ -1464,8 +1515,7 @@ public:
= SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>())
return PartialSpec->PartialSpecialization;
- return const_cast<ClassTemplateDecl*>(
- SpecializedTemplate.get<ClassTemplateDecl*>());
+ return SpecializedTemplate.get<ClassTemplateDecl*>();
}
/// \brief Retrieve the class template or class template partial
@@ -1477,8 +1527,7 @@ public:
= SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>())
return PartialSpec->PartialSpecialization;
- return const_cast<ClassTemplateDecl*>(
- SpecializedTemplate.get<ClassTemplateDecl*>());
+ return SpecializedTemplate.get<ClassTemplateDecl*>();
}
/// \brief Retrieve the set of template arguments that should be used
@@ -1780,10 +1829,11 @@ protected:
};
/// \brief Load any lazily-loaded specializations from the external source.
- void LoadLazySpecializations();
+ void LoadLazySpecializations() const;
/// \brief Retrieve the set of specializations of this class template.
- llvm::FoldingSetVector<ClassTemplateSpecializationDecl> &getSpecializations();
+ llvm::FoldingSetVector<ClassTemplateSpecializationDecl> &
+ getSpecializations() const;
/// \brief Retrieve the set of partial specializations of this class
/// template.
@@ -1798,9 +1848,9 @@ protected:
: RedeclarableTemplateDecl(ClassTemplate, 0, SourceLocation(),
DeclarationName(), 0, 0) { }
- CommonBase *newCommon(ASTContext &C);
+ CommonBase *newCommon(ASTContext &C) const;
- Common *getCommonPtr() {
+ Common *getCommonPtr() const {
return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr());
}
@@ -1925,11 +1975,11 @@ public:
typedef SpecIterator<ClassTemplateSpecializationDecl> spec_iterator;
- spec_iterator spec_begin() {
+ spec_iterator spec_begin() const {
return makeSpecIterator(getSpecializations(), false);
}
- spec_iterator spec_end() {
+ spec_iterator spec_end() const {
return makeSpecIterator(getSpecializations(), true);
}
@@ -2063,7 +2113,7 @@ protected:
TemplateParameterList *Params, NamedDecl *Decl)
: RedeclarableTemplateDecl(TypeAliasTemplate, DC, L, Name, Params, Decl) { }
- CommonBase *newCommon(ASTContext &C);
+ CommonBase *newCommon(ASTContext &C) const;
Common *getCommonPtr() {
return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr());
diff --git a/include/clang/AST/DeclVisitor.h b/include/clang/AST/DeclVisitor.h
index 62654b8..4eaae35 100644
--- a/include/clang/AST/DeclVisitor.h
+++ b/include/clang/AST/DeclVisitor.h
@@ -14,21 +14,28 @@
#define LLVM_CLANG_AST_DECLVISITOR_H
#include "clang/AST/Decl.h"
-#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclFriend.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/DeclTemplate.h"
namespace clang {
+namespace declvisitor {
-#define DISPATCH(NAME, CLASS) \
- return static_cast<ImplClass*>(this)-> Visit##NAME(static_cast<CLASS*>(D))
+template <typename T> struct make_ptr { typedef T *type; };
+template <typename T> struct make_const_ptr { typedef const T *type; };
/// \brief A simple visitor class that helps create declaration visitors.
-template<typename ImplClass, typename RetTy=void>
-class DeclVisitor {
+template<template <typename> class Ptr, typename ImplClass, typename RetTy=void>
+class Base {
public:
- RetTy Visit(Decl *D) {
+
+#define PTR(CLASS) typename Ptr<CLASS>::type
+#define DISPATCH(NAME, CLASS) \
+ return static_cast<ImplClass*>(this)->Visit##NAME(static_cast<PTR(CLASS)>(D))
+
+ RetTy Visit(PTR(Decl) D) {
switch (D->getKind()) {
#define DECL(DERIVED, BASE) \
case Decl::DERIVED: DISPATCH(DERIVED##Decl, DERIVED##Decl);
@@ -41,13 +48,31 @@ public:
// If the implementation chooses not to implement a certain visit
// method, fall back to the parent.
#define DECL(DERIVED, BASE) \
- RetTy Visit##DERIVED##Decl(DERIVED##Decl *D) { DISPATCH(BASE, BASE); }
+ RetTy Visit##DERIVED##Decl(PTR(DERIVED##Decl) D) { DISPATCH(BASE, BASE); }
#include "clang/AST/DeclNodes.inc"
- RetTy VisitDecl(Decl *D) { return RetTy(); }
-};
+ RetTy VisitDecl(PTR(Decl) D) { return RetTy(); }
+#undef PTR
#undef DISPATCH
+};
+
+} // end namespace declvisitor
+
+/// \brief A simple visitor class that helps create declaration visitors.
+///
+/// This class does not preserve constness of Decl pointers (see also
+/// ConstDeclVisitor).
+template<typename ImplClass, typename RetTy=void>
+class DeclVisitor
+ : public declvisitor::Base<declvisitor::make_ptr, ImplClass, RetTy> {};
+
+/// \brief A simple visitor class that helps create declaration visitors.
+///
+/// This class preserves constness of Decl pointers (see also DeclVisitor).
+template<typename ImplClass, typename RetTy=void>
+class ConstDeclVisitor
+ : public declvisitor::Base<declvisitor::make_const_ptr, ImplClass, RetTy> {};
} // end namespace clang
diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h
index d991c73..f28882b 100644
--- a/include/clang/AST/DeclarationName.h
+++ b/include/clang/AST/DeclarationName.h
@@ -14,8 +14,6 @@
#define LLVM_CLANG_AST_DECLARATIONNAME_H
#include "clang/Basic/IdentifierTable.h"
-#include "clang/AST/Type.h"
-#include "clang/AST/CanonicalType.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "llvm/Support/Compiler.h"
@@ -24,14 +22,20 @@ namespace llvm {
}
namespace clang {
- class CXXSpecialName;
- class CXXOperatorIdName;
+ class ASTContext;
class CXXLiteralOperatorIdName;
+ class CXXOperatorIdName;
+ class CXXSpecialName;
class DeclarationNameExtra;
class IdentifierInfo;
class MultiKeywordSelector;
- class UsingDirectiveDecl;
+ class QualType;
+ class Type;
class TypeSourceInfo;
+ class UsingDirectiveDecl;
+
+ template <typename> class CanQual;
+ typedef CanQual<Type> CanQualType;
/// DeclarationName - The name of a declaration. In the common case,
/// this just stores an IdentifierInfo pointer to a normal
@@ -349,23 +353,15 @@ public:
/// getCXXConstructorName - Returns the name of a C++ constructor
/// for the given Type.
- DeclarationName getCXXConstructorName(CanQualType Ty) {
- return getCXXSpecialName(DeclarationName::CXXConstructorName,
- Ty.getUnqualifiedType());
- }
+ DeclarationName getCXXConstructorName(CanQualType Ty);
/// getCXXDestructorName - Returns the name of a C++ destructor
/// for the given Type.
- DeclarationName getCXXDestructorName(CanQualType Ty) {
- return getCXXSpecialName(DeclarationName::CXXDestructorName,
- Ty.getUnqualifiedType());
- }
+ DeclarationName getCXXDestructorName(CanQualType Ty);
/// getCXXConversionFunctionName - Returns the name of a C++
/// conversion function for the given Type.
- DeclarationName getCXXConversionFunctionName(CanQualType Ty) {
- return getCXXSpecialName(DeclarationName::CXXConversionFunctionName, Ty);
- }
+ DeclarationName getCXXConversionFunctionName(CanQualType Ty);
/// getCXXSpecialName - Returns a declaration name for special kind
/// of C++ name, e.g., for a constructor, destructor, or conversion
@@ -386,32 +382,35 @@ public:
/// for a declaration name. Needs a DeclarationName in order
/// to be interpreted correctly.
struct DeclarationNameLoc {
+ // The source location for identifier stored elsewhere.
+ // struct {} Identifier;
+
+ // Type info for constructors, destructors and conversion functions.
+ // Locations (if any) for the tilde (destructor) or operator keyword
+ // (conversion) are stored elsewhere.
+ struct NT {
+ TypeSourceInfo* TInfo;
+ };
+
+ // The location (if any) of the operator keyword is stored elsewhere.
+ struct CXXOpName {
+ unsigned BeginOpNameLoc;
+ unsigned EndOpNameLoc;
+ };
+
+ // The location (if any) of the operator keyword is stored elsewhere.
+ struct CXXLitOpName {
+ unsigned OpNameLoc;
+ };
+
+ // struct {} CXXUsingDirective;
+ // struct {} ObjCZeroArgSelector;
+ // struct {} ObjCOneArgSelector;
+ // struct {} ObjCMultiArgSelector;
union {
- // The source location for identifier stored elsewhere.
- // struct {} Identifier;
-
- // Type info for constructors, destructors and conversion functions.
- // Locations (if any) for the tilde (destructor) or operator keyword
- // (conversion) are stored elsewhere.
- struct {
- TypeSourceInfo* TInfo;
- } NamedType;
-
- // The location (if any) of the operator keyword is stored elsewhere.
- struct {
- unsigned BeginOpNameLoc;
- unsigned EndOpNameLoc;
- } CXXOperatorName;
-
- // The location (if any) of the operator keyword is stored elsewhere.
- struct {
- unsigned OpNameLoc;
- } CXXLiteralOperatorName;
-
- // struct {} CXXUsingDirective;
- // struct {} ObjCZeroArgSelector;
- // struct {} ObjCOneArgSelector;
- // struct {} ObjCMultiArgSelector;
+ struct NT NamedType;
+ struct CXXOpName CXXOperatorName;
+ struct CXXLitOpName CXXLiteralOperatorName;
};
DeclarationNameLoc(DeclarationName Name);
@@ -525,9 +524,7 @@ public:
SourceLocation getEndLoc() const;
/// getSourceRange - The range of the declaration name.
SourceRange getSourceRange() const LLVM_READONLY {
- SourceLocation BeginLoc = getBeginLoc();
- SourceLocation EndLoc = getEndLoc();
- return SourceRange(BeginLoc, EndLoc.isValid() ? EndLoc : BeginLoc);
+ return SourceRange(getLocStart(), getLocEnd());
}
SourceLocation getLocStart() const LLVM_READONLY {
return getBeginLoc();
diff --git a/include/clang/AST/DependentDiagnostic.h b/include/clang/AST/DependentDiagnostic.h
index 948dcb4..004b45d 100644
--- a/include/clang/AST/DependentDiagnostic.h
+++ b/include/clang/AST/DependentDiagnostic.h
@@ -18,11 +18,11 @@
#ifndef LLVM_CLANG_AST_DEPENDENT_DIAGNOSTIC_H
#define LLVM_CLANG_AST_DEPENDENT_DIAGNOSTIC_H
-#include "clang/Basic/PartialDiagnostic.h"
-#include "clang/Basic/SourceLocation.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclContextInternals.h"
#include "clang/AST/Type.h"
+#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/SourceLocation.h"
namespace clang {
@@ -108,16 +108,14 @@ private:
PartialDiagnostic Diag;
- union {
- struct {
- unsigned Loc;
- unsigned Access : 2;
- unsigned IsMember : 1;
- NamedDecl *TargetDecl;
- CXXRecordDecl *NamingClass;
- void *BaseObjectType;
- } AccessData;
- };
+ struct {
+ unsigned Loc;
+ unsigned Access : 2;
+ unsigned IsMember : 1;
+ NamedDecl *TargetDecl;
+ CXXRecordDecl *NamingClass;
+ void *BaseObjectType;
+ } AccessData;
};
///
diff --git a/include/clang/AST/EvaluatedExprVisitor.h b/include/clang/AST/EvaluatedExprVisitor.h
index d5e9c8c..eb186c2 100644
--- a/include/clang/AST/EvaluatedExprVisitor.h
+++ b/include/clang/AST/EvaluatedExprVisitor.h
@@ -15,10 +15,10 @@
#ifndef LLVM_CLANG_AST_EVALUATEDEXPRVISITOR_H
#define LLVM_CLANG_AST_EVALUATEDEXPRVISITOR_H
-#include "clang/AST/StmtVisitor.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/StmtVisitor.h"
namespace clang {
@@ -49,6 +49,9 @@ public:
}
void VisitChooseExpr(ChooseExpr *E) {
+ // Don't visit either child expression if the condition is dependent.
+ if (E->getCond()->isValueDependent())
+ return;
// Only the selected subexpression matters; the other one is not evaluated.
return this->Visit(E->getChosenSubExpr(Context));
}
@@ -58,17 +61,17 @@ public:
// expressions.
return this->Visit(E->getInit());
}
-
+
void VisitCXXTypeidExpr(CXXTypeidExpr *E) {
- // typeid(expression) is potentially evaluated when the argument is
- // a glvalue of polymorphic type. (C++ 5.2.8p2-3)
- if (!E->isTypeOperand() && E->Classify(Context).isGLValue())
- if (const RecordType *Record
- = E->getExprOperand()->getType()->template getAs<RecordType>())
- if (cast<CXXRecordDecl>(Record->getDecl())->isPolymorphic())
- return this->Visit(E->getExprOperand());
+ if (E->isPotentiallyEvaluated())
+ return this->Visit(E->getExprOperand());
}
-
+
+ void VisitCallExpr(CallExpr *CE) {
+ if (!CE->isUnevaluatedBuiltinCall(Context))
+ return static_cast<ImplClass*>(this)->VisitExpr(CE);
+ }
+
/// \brief The basis case walks all of the children of the statement or
/// expression, assuming they are all potentially evaluated.
void VisitStmt(Stmt *S) {
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index dc83654..36d70d8 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -15,38 +15,38 @@
#define LLVM_CLANG_AST_EXPR_H
#include "clang/AST/APValue.h"
+#include "clang/AST/ASTVector.h"
#include "clang/AST/Decl.h"
-#include "clang/AST/Stmt.h"
-#include "clang/AST/Type.h"
#include "clang/AST/DeclAccessPair.h"
#include "clang/AST/OperationKinds.h"
-#include "clang/AST/ASTVector.h"
+#include "clang/AST/Stmt.h"
#include "clang/AST/TemplateBase.h"
-#include "clang/Basic/TargetInfo.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/TypeTraits.h"
-#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Compiler.h"
-#include <cctype>
namespace clang {
- class ASTContext;
class APValue;
- class CastExpr;
- class Decl;
- class IdentifierInfo;
- class ParmVarDecl;
- class NamedDecl;
- class ValueDecl;
+ class ASTContext;
class BlockDecl;
class CXXBaseSpecifier;
+ class CXXMemberCallExpr;
class CXXOperatorCallExpr;
+ class CastExpr;
+ class Decl;
+ class IdentifierInfo;
class MaterializeTemporaryExpr;
- class CXXMemberCallExpr;
+ class NamedDecl;
class ObjCPropertyRefExpr;
class OpaqueValueExpr;
+ class ParmVarDecl;
+ class TargetInfo;
+ class ValueDecl;
/// \brief A simple array of base specifiers.
typedef SmallVector<CXXBaseSpecifier*, 4> CXXCastPath;
@@ -60,18 +60,21 @@ struct SubobjectAdjustment {
MemberPointerAdjustment
} Kind;
- union {
- struct {
- const CastExpr *BasePath;
- const CXXRecordDecl *DerivedClass;
- } DerivedToBase;
- FieldDecl *Field;
+ struct DTB {
+ const CastExpr *BasePath;
+ const CXXRecordDecl *DerivedClass;
+ };
- struct {
- const MemberPointerType *MPT;
- Expr *RHS;
- } Ptr;
+ struct P {
+ const MemberPointerType *MPT;
+ Expr *RHS;
+ };
+
+ union {
+ struct DTB DerivedToBase;
+ FieldDecl *Field;
+ struct P Ptr;
};
SubobjectAdjustment(const CastExpr *BasePath,
@@ -196,7 +199,7 @@ public:
}
/// \brief Whether this expression contains an unexpanded parameter
- /// pack (for C++0x variadic templates).
+ /// pack (for C++11 variadic templates).
///
/// Given the following function template:
///
@@ -238,7 +241,7 @@ public:
/// result of an r-value expression is a value detached from any
/// specific storage.
///
- /// C++0x divides the concept of "r-value" into pure r-values
+ /// C++11 divides the concept of "r-value" into pure r-values
/// ("pr-values") and so-called expiring values ("x-values"), which
/// identify specific objects that can be safely cannibalized for
/// their resources. This is an unfortunate abuse of terminology on
@@ -294,7 +297,7 @@ public:
isModifiableLvalueResult isModifiableLvalue(ASTContext &Ctx,
SourceLocation *Loc = 0) const;
- /// \brief The return type of classify(). Represents the C++0x expression
+ /// \brief The return type of classify(). Represents the C++11 expression
/// taxonomy.
class Classification {
public:
@@ -357,10 +360,10 @@ public:
}
};
- /// \brief Classify - Classify this expression according to the C++0x
+ /// \brief Classify - Classify this expression according to the C++11
/// expression taxonomy.
///
- /// C++0x defines ([basic.lval]) a new taxonomy of expressions to replace the
+ /// C++11 defines ([basic.lval]) a new taxonomy of expressions to replace the
/// old lvalue vs rvalue. This function determines the type of expression this
/// is. There are three expression types:
/// - lvalues are classical lvalues as in C++03.
@@ -374,7 +377,7 @@ public:
}
/// \brief ClassifyModifiable - Classify this expression according to the
- /// C++0x expression taxonomy, and see if it is valid on the left side
+ /// C++11 expression taxonomy, and see if it is valid on the left side
/// of an assignment.
///
/// This function extends classify in that it also tests whether the
@@ -490,7 +493,7 @@ public:
/// constexpr. Return false if the function can never produce a constant
/// expression, along with diagnostics describing why not.
static bool isPotentialConstantExpr(const FunctionDecl *FD,
- llvm::SmallVectorImpl<
+ SmallVectorImpl<
PartialDiagnosticAt> &Diags);
/// isConstantInitializer - Returns true if this expression can be emitted to
@@ -510,7 +513,7 @@ public:
/// foldable. If the expression is foldable, but not a constant expression,
/// the notes will describes why it isn't a constant expression. If the
/// expression *is* a constant expression, no notes will be produced.
- llvm::SmallVectorImpl<PartialDiagnosticAt> *Diag;
+ SmallVectorImpl<PartialDiagnosticAt> *Diag;
EvalStatus() : HasSideEffects(false), Diag(0) {}
@@ -568,7 +571,11 @@ public:
/// EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded
/// integer. This must be called on an expression that constant folds to an
/// integer.
- llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx) const;
+ llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx,
+ SmallVectorImpl<PartialDiagnosticAt> *Diag=0) const;
+
+ void EvaluateForOverflow(const ASTContext &Ctx,
+ SmallVectorImpl<PartialDiagnosticAt> *Diag) const;
/// EvaluateAsLValue - Evaluate an expression to see if we can fold it to an
/// lvalue with link time known address, with no side-effects.
@@ -580,7 +587,7 @@ public:
/// notes will be produced if the expression is not a constant expression.
bool EvaluateAsInitializer(APValue &Result, const ASTContext &Ctx,
const VarDecl *VD,
- llvm::SmallVectorImpl<PartialDiagnosticAt> &Notes) const;
+ SmallVectorImpl<PartialDiagnosticAt> &Notes) const;
/// \brief Enumeration used to describe the kind of Null pointer constant
/// returned from \c isNullPointerConstant().
@@ -598,8 +605,8 @@ public:
/// \brief Expression is a Null pointer constant built from a literal zero.
NPCK_ZeroLiteral,
- /// \brief Expression is a C++0X nullptr.
- NPCK_CXX0X_nullptr,
+ /// \brief Expression is a C++11 nullptr.
+ NPCK_CXX11_nullptr,
/// \brief Expression is a GNU-style __null constant.
NPCK_GNUNull
@@ -728,7 +735,7 @@ public:
return const_cast<Expr*>(this)->IgnoreParenNoopCasts(Ctx);
}
- static bool hasAnyTypeDependentArguments(llvm::ArrayRef<Expr *> Exprs);
+ static bool hasAnyTypeDependentArguments(ArrayRef<Expr *> Exprs);
/// \brief For an expression of class type or pointer to class type,
/// return the most derived class decl the expression is known to refer to.
@@ -796,9 +803,11 @@ public:
/// \brief Retrieve the location of this expression.
SourceLocation getLocation() const { return Loc; }
- SourceRange getSourceRange() const LLVM_READONLY {
- if (SourceExpr) return SourceExpr->getSourceRange();
- return Loc;
+ SourceLocation getLocStart() const LLVM_READONLY {
+ return SourceExpr ? SourceExpr->getLocStart() : Loc;
+ }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ return SourceExpr ? SourceExpr->getLocEnd() : Loc;
}
SourceLocation getExprLoc() const LLVM_READONLY {
if (SourceExpr) return SourceExpr->getExprLoc();
@@ -954,7 +963,6 @@ public:
SourceLocation getLocation() const { return Loc; }
void setLocation(SourceLocation L) { Loc = L; }
- SourceRange getSourceRange() const LLVM_READONLY;
SourceLocation getLocStart() const LLVM_READONLY;
SourceLocation getLocEnd() const LLVM_READONLY;
@@ -1160,7 +1168,8 @@ public:
static std::string ComputeName(IdentType IT, const Decl *CurrentDecl);
- SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc); }
+ SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return Loc; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == PredefinedExprClass;
@@ -1211,8 +1220,8 @@ public:
class APFloatStorage : private APNumericStorage {
public:
- llvm::APFloat getValue(bool IsIEEE) const {
- return llvm::APFloat(getIntValue(), IsIEEE);
+ llvm::APFloat getValue(const llvm::fltSemantics &Semantics) const {
+ return llvm::APFloat(Semantics, getIntValue());
}
void setValue(ASTContext &C, const llvm::APFloat &Val) {
setIntValue(C, Val.bitcastToAPInt());
@@ -1241,7 +1250,8 @@ public:
/// \brief Returns a new empty integer literal.
static IntegerLiteral *Create(ASTContext &C, EmptyShell Empty);
- SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc); }
+ SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return Loc; }
/// \brief Retrieve the location of the literal.
SourceLocation getLocation() const { return Loc; }
@@ -1286,7 +1296,8 @@ public:
return static_cast<CharacterKind>(CharacterLiteralBits.Kind);
}
- SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc); }
+ SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return Loc; }
unsigned getValue() const { return Value; }
@@ -1317,12 +1328,31 @@ public:
static FloatingLiteral *Create(ASTContext &C, EmptyShell Empty);
llvm::APFloat getValue() const {
- return APFloatStorage::getValue(FloatingLiteralBits.IsIEEE);
+ return APFloatStorage::getValue(getSemantics());
}
void setValue(ASTContext &C, const llvm::APFloat &Val) {
+ assert(&getSemantics() == &Val.getSemantics() && "Inconsistent semantics");
APFloatStorage::setValue(C, Val);
}
+ /// Get a raw enumeration value representing the floating-point semantics of
+ /// this literal (32-bit IEEE, x87, ...), suitable for serialisation.
+ APFloatSemantics getRawSemantics() const {
+ return static_cast<APFloatSemantics>(FloatingLiteralBits.Semantics);
+ }
+
+ /// Set the raw enumeration value representing the floating-point semantics of
+ /// this literal (32-bit IEEE, x87, ...), suitable for serialisation.
+ void setRawSemantics(APFloatSemantics Sem) {
+ FloatingLiteralBits.Semantics = Sem;
+ }
+
+ /// Return the APFloat semantics this literal uses.
+ const llvm::fltSemantics &getSemantics() const;
+
+ /// Set the APFloat semantics this literal uses.
+ void setSemantics(const llvm::fltSemantics &Sem);
+
bool isExact() const { return FloatingLiteralBits.IsExact; }
void setExact(bool E) { FloatingLiteralBits.IsExact = E; }
@@ -1334,7 +1364,8 @@ public:
SourceLocation getLocation() const { return Loc; }
void setLocation(SourceLocation L) { Loc = L; }
- SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc); }
+ SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return Loc; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == FloatingLiteralClass;
@@ -1365,7 +1396,9 @@ public:
Expr *getSubExpr() { return cast<Expr>(Val); }
void setSubExpr(Expr *E) { Val = E; }
- SourceRange getSourceRange() const LLVM_READONLY { return Val->getSourceRange(); }
+ SourceLocation getLocStart() const LLVM_READONLY { return Val->getLocStart(); }
+ SourceLocation getLocEnd() const LLVM_READONLY { return Val->getLocEnd(); }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == ImaginaryLiteralClass;
}
@@ -1458,7 +1491,7 @@ public:
getByteLength());
}
- void outputString(raw_ostream &OS);
+ void outputString(raw_ostream &OS) const;
uint32_t getCodeUnit(size_t i) const {
assert(i < Length && "out of bounds access");
@@ -1491,7 +1524,7 @@ public:
bool containsNonAsciiOrNull() const {
StringRef Str = getString();
for (unsigned i = 0, e = Str.size(); i != e; ++i)
- if (!isascii(Str[i]) || !Str[i])
+ if (!isASCII(Str[i]) || !Str[i])
return true;
return false;
}
@@ -1524,9 +1557,11 @@ public:
tokloc_iterator tokloc_begin() const { return TokLocs; }
tokloc_iterator tokloc_end() const { return TokLocs+NumConcatenated; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(TokLocs[0], TokLocs[NumConcatenated-1]);
+ SourceLocation getLocStart() const LLVM_READONLY { return TokLocs[0]; }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ return TokLocs[NumConcatenated - 1];
}
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == StringLiteralClass;
}
@@ -1557,7 +1592,8 @@ public:
Expr *getSubExpr() { return cast<Expr>(Val); }
void setSubExpr(Expr *E) { Val = E; }
- SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(L, R); }
+ SourceLocation getLocStart() const LLVM_READONLY { return L; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return R; }
/// \brief Get the location of the left parentheses '('.
SourceLocation getLParen() const { return L; }
@@ -1669,11 +1705,11 @@ public:
/// the given unary opcode.
static OverloadedOperatorKind getOverloadedOperator(Opcode Opc);
- SourceRange getSourceRange() const LLVM_READONLY {
- if (isPostfix())
- return SourceRange(Val->getLocStart(), Loc);
- else
- return SourceRange(Loc, Val->getLocEnd());
+ SourceLocation getLocStart() const LLVM_READONLY {
+ return isPostfix() ? Val->getLocStart() : Loc;
+ }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ return isPostfix() ? Loc : Val->getLocEnd();
}
SourceLocation getExprLoc() const LLVM_READONLY { return Loc; }
@@ -1791,6 +1827,8 @@ public:
/// contains the location of the period (if there is one) and the
/// identifier.
SourceRange getSourceRange() const LLVM_READONLY { return Range; }
+ SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); }
+ SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); }
};
private:
@@ -1870,9 +1908,8 @@ public:
return NumExprs;
}
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(OperatorLoc, RParenLoc);
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return OperatorLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == OffsetOfExprClass;
@@ -1974,9 +2011,8 @@ public:
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(OpLoc, RParenLoc);
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return OpLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == UnaryExprOrTypeTraitExprClass;
@@ -2048,14 +2084,17 @@ public:
return cast<Expr>(getRHS()->getType()->isIntegerType() ? getRHS():getLHS());
}
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(getLHS()->getLocStart(), RBracketLoc);
+ SourceLocation getLocStart() const LLVM_READONLY {
+ return getLHS()->getLocStart();
}
+ SourceLocation getLocEnd() const LLVM_READONLY { return RBracketLoc; }
SourceLocation getRBracketLoc() const { return RBracketLoc; }
void setRBracketLoc(SourceLocation L) { RBracketLoc = L; }
- SourceLocation getExprLoc() const LLVM_READONLY { return getBase()->getExprLoc(); }
+ SourceLocation getExprLoc() const LLVM_READONLY {
+ return getBase()->getExprLoc();
+ }
static bool classof(const Stmt *T) {
return T->getStmtClass() == ArraySubscriptExprClass;
@@ -2171,6 +2210,15 @@ public:
return SubExprs+PREARGS_START+getNumPreArgs()+getNumArgs();
}
+ /// This method provides fast access to all the subexpressions of
+ /// a CallExpr without going through the slower virtual child_iterator
+ /// interface. This provides efficient reverse iteration of the
+ /// subexpressions. This is currently used for CFG construction.
+ ArrayRef<Stmt*> getRawSubExprs() {
+ return ArrayRef<Stmt*>(SubExprs,
+ getNumPreArgs() + PREARGS_START + getNumArgs());
+ }
+
/// getNumCommas - Return the number of commas that must have been present in
/// this function call.
unsigned getNumCommas() const { return NumArgs ? NumArgs - 1 : 0; }
@@ -2179,6 +2227,10 @@ public:
/// not, return 0.
unsigned isBuiltinCall() const;
+ /// \brief Returns \c true if this is a call to a builtin which does not
+ /// evaluate side-effects within its arguments.
+ bool isUnevaluatedBuiltinCall(ASTContext &Ctx) const;
+
/// getCallReturnType - Get the return type of the call expr. This is not
/// always the type of the expr itself, if the return type is a reference
/// type.
@@ -2187,7 +2239,6 @@ public:
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- SourceRange getSourceRange() const LLVM_READONLY;
SourceLocation getLocStart() const LLVM_READONLY;
SourceLocation getLocEnd() const LLVM_READONLY;
@@ -2455,7 +2506,6 @@ public:
SourceLocation getMemberLoc() const { return MemberLoc; }
void setMemberLoc(SourceLocation L) { MemberLoc = L; }
- SourceRange getSourceRange() const LLVM_READONLY;
SourceLocation getLocStart() const LLVM_READONLY;
SourceLocation getLocEnd() const LLVM_READONLY;
@@ -2534,13 +2584,19 @@ public:
TInfoAndScope.setPointer(tinfo);
}
- SourceRange getSourceRange() const LLVM_READONLY {
+ SourceLocation getLocStart() const LLVM_READONLY {
// FIXME: Init should never be null.
if (!Init)
- return SourceRange();
+ return SourceLocation();
if (LParenLoc.isInvalid())
- return Init->getSourceRange();
- return SourceRange(LParenLoc, Init->getLocEnd());
+ return Init->getLocStart();
+ return LParenLoc;
+ }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ // FIXME: Init should never be null.
+ if (!Init)
+ return SourceLocation();
+ return Init->getLocEnd();
}
static bool classof(const Stmt *T) {
@@ -2686,9 +2742,6 @@ public:
static ImplicitCastExpr *CreateEmpty(ASTContext &Context, unsigned PathSize);
- SourceRange getSourceRange() const LLVM_READONLY {
- return getSubExpr()->getSourceRange();
- }
SourceLocation getLocStart() const LLVM_READONLY {
return getSubExpr()->getLocStart();
}
@@ -2787,9 +2840,11 @@ public:
SourceLocation getRParenLoc() const { return RPLoc; }
void setRParenLoc(SourceLocation L) { RPLoc = L; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(LPLoc, getSubExpr()->getSourceRange().getEnd());
+ SourceLocation getLocStart() const LLVM_READONLY { return LPLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ return getSubExpr()->getLocEnd();
}
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == CStyleCastExprClass;
}
@@ -2845,7 +2900,7 @@ public:
SubExprs[LHS] = lhs;
SubExprs[RHS] = rhs;
assert(!isCompoundAssignmentOp() &&
- "Use ArithAssignBinaryOperator for compound assignments");
+ "Use CompoundAssignOperator for compound assignments");
}
/// \brief Construct an empty binary operator.
@@ -2864,8 +2919,11 @@ public:
Expr *getRHS() const { return cast<Expr>(SubExprs[RHS]); }
void setRHS(Expr *E) { SubExprs[RHS] = E; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(getLHS()->getLocStart(), getRHS()->getLocEnd());
+ SourceLocation getLocStart() const LLVM_READONLY {
+ return getLHS()->getLocStart();
+ }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ return getRHS()->getLocEnd();
}
/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
@@ -2902,6 +2960,33 @@ public:
static bool isComparisonOp(Opcode Opc) { return Opc >= BO_LT && Opc<=BO_NE; }
bool isComparisonOp() const { return isComparisonOp(getOpcode()); }
+ static Opcode negateComparisonOp(Opcode Opc) {
+ switch (Opc) {
+ default:
+ llvm_unreachable("Not a comparsion operator.");
+ case BO_LT: return BO_GE;
+ case BO_GT: return BO_LE;
+ case BO_LE: return BO_GT;
+ case BO_GE: return BO_LT;
+ case BO_EQ: return BO_NE;
+ case BO_NE: return BO_EQ;
+ }
+ }
+
+ static Opcode reverseComparisonOp(Opcode Opc) {
+ switch (Opc) {
+ default:
+ llvm_unreachable("Not a comparsion operator.");
+ case BO_LT: return BO_GT;
+ case BO_GT: return BO_LT;
+ case BO_LE: return BO_GE;
+ case BO_GE: return BO_LE;
+ case BO_EQ:
+ case BO_NE:
+ return Opc;
+ }
+ }
+
static bool isLogicalOp(Opcode Opc) { return Opc == BO_LAnd || Opc==BO_LOr; }
bool isLogicalOp() const { return isLogicalOp(getOpcode()); }
@@ -3101,9 +3186,13 @@ public:
Expr *getLHS() const { return cast<Expr>(SubExprs[LHS]); }
Expr *getRHS() const { return cast<Expr>(SubExprs[RHS]); }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(getCond()->getLocStart(), getRHS()->getLocEnd());
+ SourceLocation getLocStart() const LLVM_READONLY {
+ return getCond()->getLocStart();
+ }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ return getRHS()->getLocEnd();
}
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == ConditionalOperatorClass;
}
@@ -3182,9 +3271,13 @@ public:
return cast<Expr>(SubExprs[RHS]);
}
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(getCommon()->getLocStart(), getFalseExpr()->getLocEnd());
+ SourceLocation getLocStart() const LLVM_READONLY {
+ return getCommon()->getLocStart();
}
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ return getFalseExpr()->getLocEnd();
+ }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == BinaryConditionalOperatorClass;
}
@@ -3233,9 +3326,8 @@ public:
SourceLocation getLabelLoc() const { return LabelLoc; }
void setLabelLoc(SourceLocation L) { LabelLoc = L; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(AmpAmpLoc, LabelLoc);
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return AmpAmpLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return LabelLoc; }
LabelDecl *getLabel() const { return Label; }
void setLabel(LabelDecl *L) { Label = L; }
@@ -3274,9 +3366,8 @@ public:
const CompoundStmt *getSubStmt() const { return cast<CompoundStmt>(SubStmt); }
void setSubStmt(CompoundStmt *S) { SubStmt = S; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(LParenLoc, RParenLoc);
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return LParenLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
SourceLocation getLParenLoc() const { return LParenLoc; }
void setLParenLoc(SourceLocation L) { LParenLoc = L; }
@@ -3322,9 +3413,9 @@ public:
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(BuiltinLoc, RParenLoc);
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return BuiltinLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == ShuffleVectorExprClass;
}
@@ -3416,9 +3507,9 @@ public:
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(BuiltinLoc, RParenLoc);
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return BuiltinLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == ChooseExprClass;
}
@@ -3452,9 +3543,9 @@ public:
SourceLocation getTokenLocation() const { return TokenLoc; }
void setTokenLocation(SourceLocation L) { TokenLoc = L; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(TokenLoc);
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return TokenLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return TokenLoc; }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == GNUNullExprClass;
}
@@ -3497,9 +3588,9 @@ public:
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(BuiltinLoc, RParenLoc);
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return BuiltinLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == VAArgExprClass;
}
@@ -3580,8 +3671,8 @@ public:
ArrayRef<Expr*> initExprs, SourceLocation rbraceloc);
/// \brief Build an empty initializer list.
- explicit InitListExpr(ASTContext &C, EmptyShell Empty)
- : Expr(InitListExprClass, Empty), InitExprs(C) { }
+ explicit InitListExpr(EmptyShell Empty)
+ : Expr(InitListExprClass, Empty) { }
unsigned getNumInits() const { return InitExprs.size(); }
@@ -3698,7 +3789,8 @@ public:
InitListExprBits.InitializesStdInitializerList = ISIL;
}
- SourceRange getSourceRange() const LLVM_READONLY;
+ SourceLocation getLocStart() const LLVM_READONLY;
+ SourceLocation getLocEnd() const LLVM_READONLY;
static bool classof(const Stmt *T) {
return T->getStmtClass() == InitListExprClass;
@@ -3923,17 +4015,17 @@ public:
return ArrayOrRange.Index;
}
- SourceLocation getStartLocation() const {
+ SourceLocation getLocStart() const LLVM_READONLY {
if (Kind == FieldDesignator)
return getDotLoc().isInvalid()? getFieldLoc() : getDotLoc();
else
return getLBracketLoc();
}
- SourceLocation getEndLocation() const {
+ SourceLocation getLocEnd() const LLVM_READONLY {
return Kind == FieldDesignator ? getFieldLoc() : getRBracketLoc();
}
SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(getStartLocation(), getEndLocation());
+ return SourceRange(getLocStart(), getLocEnd());
}
};
@@ -3984,9 +4076,9 @@ public:
void setDesignators(ASTContext &C, const Designator *Desigs,
unsigned NumDesigs);
- Expr *getArrayIndex(const Designator& D);
- Expr *getArrayRangeStart(const Designator& D);
- Expr *getArrayRangeEnd(const Designator& D);
+ Expr *getArrayIndex(const Designator &D) const;
+ Expr *getArrayRangeStart(const Designator &D) const;
+ Expr *getArrayRangeEnd(const Designator &D) const;
/// @brief Retrieve the location of the '=' that precedes the
/// initializer value itself, if present.
@@ -4034,7 +4126,8 @@ public:
SourceRange getDesignatorsSourceRange() const;
- SourceRange getSourceRange() const LLVM_READONLY;
+ SourceLocation getLocStart() const LLVM_READONLY;
+ SourceLocation getLocEnd() const LLVM_READONLY;
static bool classof(const Stmt *T) {
return T->getStmtClass() == DesignatedInitExprClass;
@@ -4069,9 +4162,8 @@ public:
return T->getStmtClass() == ImplicitValueInitExprClass;
}
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange();
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return SourceLocation(); }
+ SourceLocation getLocEnd() const LLVM_READONLY { return SourceLocation(); }
// Iterators
child_range children() { return child_range(); }
@@ -4107,9 +4199,9 @@ public:
SourceLocation getLParenLoc() const { return LParenLoc; }
SourceLocation getRParenLoc() const { return RParenLoc; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(LParenLoc, RParenLoc);
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return LParenLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == ParenListExprClass;
}
@@ -4221,9 +4313,9 @@ public:
const Expr *getResultExpr() const { return getAssocExpr(getResultIndex()); }
Expr *getResultExpr() { return getAssocExpr(getResultIndex()); }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(GenericLoc, RParenLoc);
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return GenericLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == GenericSelectionExprClass;
}
@@ -4286,9 +4378,10 @@ public:
/// aggregate Constant of ConstantInt(s).
void getEncodedElementAccess(SmallVectorImpl<unsigned> &Elts) const;
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(getBase()->getLocStart(), AccessorLoc);
+ SourceLocation getLocStart() const LLVM_READONLY {
+ return getBase()->getLocStart();
}
+ SourceLocation getLocEnd() const LLVM_READONLY { return AccessorLoc; }
/// isArrow - Return true if the base expression is a pointer to vector,
/// return false if the base expression is a vector.
@@ -4328,9 +4421,8 @@ public:
const Stmt *getBody() const;
Stmt *getBody();
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(getCaretLocation(), getBody()->getLocEnd());
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return getCaretLocation(); }
+ SourceLocation getLocEnd() const LLVM_READONLY { return getBody()->getLocEnd(); }
/// getFunctionType - Return the underlying function type for this block.
const FunctionProtoType *getFunctionType() const;
@@ -4377,9 +4469,8 @@ public:
/// getRParenLoc - Return the location of final right parenthesis.
SourceLocation getRParenLoc() const { return RParenLoc; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(BuiltinLoc, RParenLoc);
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return BuiltinLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == AsTypeExprClass;
@@ -4508,8 +4599,12 @@ public:
SourceLocation getExprLoc() const LLVM_READONLY {
return getSyntacticForm()->getExprLoc();
}
- SourceRange getSourceRange() const LLVM_READONLY {
- return getSyntacticForm()->getSourceRange();
+
+ SourceLocation getLocStart() const LLVM_READONLY {
+ return getSyntacticForm()->getLocStart();
+ }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ return getSyntacticForm()->getLocEnd();
}
child_range children() {
@@ -4603,9 +4698,9 @@ public:
SourceLocation getBuiltinLoc() const { return BuiltinLoc; }
SourceLocation getRParenLoc() const { return RParenLoc; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(BuiltinLoc, RParenLoc);
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return BuiltinLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == AtomicExprClass;
}
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 9c759db..04f6fb6 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -16,8 +16,8 @@
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
-#include "clang/AST/UnresolvedSet.h"
#include "clang/AST/TemplateBase.h"
+#include "clang/AST/UnresolvedSet.h"
#include "clang/Basic/ExpressionTraits.h"
#include "clang/Basic/Lambda.h"
#include "clang/Basic/TypeTraits.h"
@@ -30,6 +30,7 @@ class CXXDestructorDecl;
class CXXMethodDecl;
class CXXTemporary;
class TemplateArgumentListInfo;
+class UuidAttr;
//===--------------------------------------------------------------------===//
// C++ Expressions.
@@ -83,6 +84,8 @@ public:
/// bracket.
SourceLocation getOperatorLoc() const { return getRParenLoc(); }
+ SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); }
+ SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); }
SourceRange getSourceRange() const { return Range; }
static bool classof(const Stmt *T) {
@@ -176,14 +179,16 @@ class CXXNamedCastExpr : public ExplicitCastExpr {
private:
SourceLocation Loc; // the location of the casting op
SourceLocation RParenLoc; // the location of the right parenthesis
+ SourceRange AngleBrackets; // range for '<' '>'
protected:
CXXNamedCastExpr(StmtClass SC, QualType ty, ExprValueKind VK,
CastKind kind, Expr *op, unsigned PathSize,
TypeSourceInfo *writtenTy, SourceLocation l,
- SourceLocation RParenLoc)
+ SourceLocation RParenLoc,
+ SourceRange AngleBrackets)
: ExplicitCastExpr(SC, ty, VK, kind, op, PathSize, writtenTy), Loc(l),
- RParenLoc(RParenLoc) {}
+ RParenLoc(RParenLoc), AngleBrackets(AngleBrackets) {}
explicit CXXNamedCastExpr(StmtClass SC, EmptyShell Shell, unsigned PathSize)
: ExplicitCastExpr(SC, Shell, PathSize) { }
@@ -200,9 +205,10 @@ public:
/// \brief Retrieve the location of the closing parenthesis.
SourceLocation getRParenLoc() const { return RParenLoc; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(Loc, RParenLoc);
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
+ SourceRange getAngleBrackets() const LLVM_READONLY { return AngleBrackets; }
+
static bool classof(const Stmt *T) {
switch (T->getStmtClass()) {
case CXXStaticCastExprClass:
@@ -224,9 +230,10 @@ public:
class CXXStaticCastExpr : public CXXNamedCastExpr {
CXXStaticCastExpr(QualType ty, ExprValueKind vk, CastKind kind, Expr *op,
unsigned pathSize, TypeSourceInfo *writtenTy,
- SourceLocation l, SourceLocation RParenLoc)
+ SourceLocation l, SourceLocation RParenLoc,
+ SourceRange AngleBrackets)
: CXXNamedCastExpr(CXXStaticCastExprClass, ty, vk, kind, op, pathSize,
- writtenTy, l, RParenLoc) {}
+ writtenTy, l, RParenLoc, AngleBrackets) {}
explicit CXXStaticCastExpr(EmptyShell Empty, unsigned PathSize)
: CXXNamedCastExpr(CXXStaticCastExprClass, Empty, PathSize) { }
@@ -236,7 +243,8 @@ public:
ExprValueKind VK, CastKind K, Expr *Op,
const CXXCastPath *Path,
TypeSourceInfo *Written, SourceLocation L,
- SourceLocation RParenLoc);
+ SourceLocation RParenLoc,
+ SourceRange AngleBrackets);
static CXXStaticCastExpr *CreateEmpty(ASTContext &Context,
unsigned PathSize);
@@ -254,9 +262,10 @@ public:
class CXXDynamicCastExpr : public CXXNamedCastExpr {
CXXDynamicCastExpr(QualType ty, ExprValueKind VK, CastKind kind,
Expr *op, unsigned pathSize, TypeSourceInfo *writtenTy,
- SourceLocation l, SourceLocation RParenLoc)
+ SourceLocation l, SourceLocation RParenLoc,
+ SourceRange AngleBrackets)
: CXXNamedCastExpr(CXXDynamicCastExprClass, ty, VK, kind, op, pathSize,
- writtenTy, l, RParenLoc) {}
+ writtenTy, l, RParenLoc, AngleBrackets) {}
explicit CXXDynamicCastExpr(EmptyShell Empty, unsigned pathSize)
: CXXNamedCastExpr(CXXDynamicCastExprClass, Empty, pathSize) { }
@@ -266,7 +275,8 @@ public:
ExprValueKind VK, CastKind Kind, Expr *Op,
const CXXCastPath *Path,
TypeSourceInfo *Written, SourceLocation L,
- SourceLocation RParenLoc);
+ SourceLocation RParenLoc,
+ SourceRange AngleBrackets);
static CXXDynamicCastExpr *CreateEmpty(ASTContext &Context,
unsigned pathSize);
@@ -288,9 +298,10 @@ class CXXReinterpretCastExpr : public CXXNamedCastExpr {
CXXReinterpretCastExpr(QualType ty, ExprValueKind vk, CastKind kind,
Expr *op, unsigned pathSize,
TypeSourceInfo *writtenTy, SourceLocation l,
- SourceLocation RParenLoc)
+ SourceLocation RParenLoc,
+ SourceRange AngleBrackets)
: CXXNamedCastExpr(CXXReinterpretCastExprClass, ty, vk, kind, op,
- pathSize, writtenTy, l, RParenLoc) {}
+ pathSize, writtenTy, l, RParenLoc, AngleBrackets) {}
CXXReinterpretCastExpr(EmptyShell Empty, unsigned pathSize)
: CXXNamedCastExpr(CXXReinterpretCastExprClass, Empty, pathSize) { }
@@ -300,7 +311,8 @@ public:
ExprValueKind VK, CastKind Kind,
Expr *Op, const CXXCastPath *Path,
TypeSourceInfo *WrittenTy, SourceLocation L,
- SourceLocation RParenLoc);
+ SourceLocation RParenLoc,
+ SourceRange AngleBrackets);
static CXXReinterpretCastExpr *CreateEmpty(ASTContext &Context,
unsigned pathSize);
@@ -317,9 +329,9 @@ public:
class CXXConstCastExpr : public CXXNamedCastExpr {
CXXConstCastExpr(QualType ty, ExprValueKind VK, Expr *op,
TypeSourceInfo *writtenTy, SourceLocation l,
- SourceLocation RParenLoc)
+ SourceLocation RParenLoc, SourceRange AngleBrackets)
: CXXNamedCastExpr(CXXConstCastExprClass, ty, VK, CK_NoOp, op,
- 0, writtenTy, l, RParenLoc) {}
+ 0, writtenTy, l, RParenLoc, AngleBrackets) {}
explicit CXXConstCastExpr(EmptyShell Empty)
: CXXNamedCastExpr(CXXConstCastExprClass, Empty, 0) { }
@@ -328,7 +340,8 @@ public:
static CXXConstCastExpr *Create(ASTContext &Context, QualType T,
ExprValueKind VK, Expr *Op,
TypeSourceInfo *WrittenTy, SourceLocation L,
- SourceLocation RParenLoc);
+ SourceLocation RParenLoc,
+ SourceRange AngleBrackets);
static CXXConstCastExpr *CreateEmpty(ASTContext &Context);
static bool classof(const Stmt *T) {
@@ -386,9 +399,6 @@ public:
return getArg(0)->getLocStart();
}
SourceLocation getLocEnd() const { return getRParenLoc(); }
- SourceRange getSourceRange() const {
- return SourceRange(getLocStart(), getLocEnd());
- }
/// getUDSuffixLoc - Returns the location of a ud-suffix in the expression.
@@ -424,7 +434,8 @@ public:
bool getValue() const { return Value; }
void setValue(bool V) { Value = V; }
- SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc); }
+ SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return Loc; }
SourceLocation getLocation() const { return Loc; }
void setLocation(SourceLocation L) { Loc = L; }
@@ -449,7 +460,8 @@ public:
explicit CXXNullPtrLiteralExpr(EmptyShell Empty)
: Expr(CXXNullPtrLiteralExprClass, Empty) { }
- SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc); }
+ SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return Loc; }
SourceLocation getLocation() const { return Loc; }
void setLocation(SourceLocation L) { Loc = L; }
@@ -531,6 +543,8 @@ public:
Operand = E;
}
+ SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); }
+ SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); }
SourceRange getSourceRange() const LLVM_READONLY { return Range; }
void setSourceRange(SourceRange R) { Range = R; }
@@ -605,6 +619,8 @@ public:
Operand = E;
}
+ SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); }
+ SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); }
SourceRange getSourceRange() const LLVM_READONLY { return Range; }
void setSourceRange(SourceRange R) { Range = R; }
@@ -653,7 +669,8 @@ public:
SourceLocation getLocation() const { return Loc; }
void setLocation(SourceLocation L) { Loc = L; }
- SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc); }
+ SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return Loc; }
bool isImplicit() const { return Implicit; }
void setImplicit(bool I) { Implicit = I; }
@@ -702,10 +719,11 @@ public:
/// this variable.
bool isThrownVariableInScope() const { return IsThrownVariableInScope; }
- SourceRange getSourceRange() const LLVM_READONLY {
+ SourceLocation getLocStart() const LLVM_READONLY { return ThrowLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY {
if (getSubExpr() == 0)
- return SourceRange(ThrowLoc, ThrowLoc);
- return SourceRange(ThrowLoc, getSubExpr()->getSourceRange().getEnd());
+ return ThrowLoc;
+ return getSubExpr()->getLocEnd();
}
static bool classof(const Stmt *T) {
@@ -789,11 +807,12 @@ public:
/// used.
SourceLocation getUsedLocation() const { return Loc; }
- SourceRange getSourceRange() const LLVM_READONLY {
- // Default argument expressions have no representation in the
- // source, so they have an empty source range.
- return SourceRange();
- }
+ // Default argument expressions have no representation in the
+ // source, so they have an empty source range.
+ SourceLocation getLocStart() const LLVM_READONLY { return SourceLocation(); }
+ SourceLocation getLocEnd() const LLVM_READONLY { return SourceLocation(); }
+
+ SourceLocation getExprLoc() const LLVM_READONLY { return Loc; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXDefaultArgExprClass;
@@ -866,9 +885,10 @@ public:
Expr *getSubExpr() { return cast<Expr>(SubExpr); }
void setSubExpr(Expr *E) { SubExpr = E; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SubExpr->getSourceRange();
+ SourceLocation getLocStart() const LLVM_READONLY {
+ return SubExpr->getLocStart();
}
+ SourceLocation getLocEnd() const LLVM_READONLY { return SubExpr->getLocEnd();}
// Implement isa/cast/dyncast/etc.
static bool classof(const Stmt *T) {
@@ -1001,7 +1021,8 @@ public:
Args[Arg] = ArgExpr;
}
- SourceRange getSourceRange() const LLVM_READONLY;
+ SourceLocation getLocStart() const LLVM_READONLY;
+ SourceLocation getLocEnd() const LLVM_READONLY;
SourceRange getParenRange() const { return ParenRange; }
void setParenRange(SourceRange Range) { ParenRange = Range; }
@@ -1057,9 +1078,9 @@ public:
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(TyBeginLoc, RParenLoc);
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return TyBeginLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXFunctionalCastExprClass;
}
@@ -1089,13 +1110,15 @@ public:
ArrayRef<Expr *> Args,
SourceRange parenRange,
bool HadMultipleCandidates,
- bool ZeroInitialization = false);
+ bool ListInitialization,
+ bool ZeroInitialization);
explicit CXXTemporaryObjectExpr(EmptyShell Empty)
: CXXConstructExpr(CXXTemporaryObjectExprClass, Empty), Type() { }
TypeSourceInfo *getTypeSourceInfo() const { return Type; }
- SourceRange getSourceRange() const LLVM_READONLY;
+ SourceLocation getLocStart() const LLVM_READONLY;
+ SourceLocation getLocEnd() const LLVM_READONLY;
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXTemporaryObjectExprClass;
@@ -1111,7 +1134,7 @@ public:
/// \code
/// void low_pass_filter(std::vector<double> &values, double cutoff) {
/// values.erase(std::remove_if(values.begin(), values.end(),
-// [=](double value) { return value > cutoff; });
+/// [=](double value) { return value > cutoff; });
/// }
/// \endcode
///
@@ -1393,9 +1416,10 @@ public:
return T->getStmtClass() == LambdaExprClass;
}
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(IntroducerRange.getBegin(), ClosingBrace);
+ SourceLocation getLocStart() const LLVM_READONLY {
+ return IntroducerRange.getBegin();
}
+ SourceLocation getLocEnd() const LLVM_READONLY { return ClosingBrace; }
child_range children() {
return child_range(getStoredStmts(), getStoredStmts() + NumCaptures + 1);
@@ -1434,7 +1458,8 @@ public:
SourceLocation getRParenLoc() const { return RParenLoc; }
- SourceRange getSourceRange() const LLVM_READONLY;
+ SourceLocation getLocStart() const LLVM_READONLY;
+ SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXScalarValueInitExprClass;
@@ -1621,6 +1646,8 @@ public:
SourceRange getSourceRange() const LLVM_READONLY {
return Range;
}
+ SourceLocation getLocStart() const LLVM_READONLY { return getStartLoc(); }
+ SourceLocation getLocEnd() const LLVM_READONLY { return getEndLoc(); }
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXNewExprClass;
@@ -1688,9 +1715,8 @@ public:
/// return an invalid type.
QualType getDestroyedType() const;
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(Loc, Argument->getLocEnd());
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
+ SourceLocation getLocEnd() const LLVM_READONLY {return Argument->getLocEnd();}
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXDeleteExprClass;
@@ -1878,7 +1904,8 @@ public:
DestroyedType = PseudoDestructorTypeStorage(Info);
}
- SourceRange getSourceRange() const LLVM_READONLY;
+ SourceLocation getLocStart() const LLVM_READONLY {return Base->getLocStart();}
+ SourceLocation getLocEnd() const LLVM_READONLY;
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXPseudoDestructorExprClass;
@@ -1925,7 +1952,8 @@ public:
: Expr(UnaryTypeTraitExprClass, Empty), UTT(0), Value(false),
QueriedType() { }
- SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc, RParen);}
+ SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return RParen; }
UnaryTypeTrait getTrait() const { return static_cast<UnaryTypeTrait>(UTT); }
@@ -1990,9 +2018,8 @@ public:
: Expr(BinaryTypeTraitExprClass, Empty), BTT(0), Value(false),
LhsType(), RhsType() { }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(Loc, RParen);
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return RParen; }
BinaryTypeTrait getTrait() const {
return static_cast<BinaryTypeTrait>(BTT);
@@ -2097,8 +2124,9 @@ public:
return getTypeSourceInfos() + getNumArgs();
}
- SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc, RParenLoc); }
-
+ SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == TypeTraitExprClass;
}
@@ -2159,9 +2187,8 @@ public:
virtual ~ArrayTypeTraitExpr() { }
- virtual SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(Loc, RParen);
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return RParen; }
ArrayTypeTrait getTrait() const { return static_cast<ArrayTypeTrait>(ATT); }
@@ -2221,9 +2248,8 @@ public:
: Expr(ExpressionTraitExprClass, Empty), ET(0), Value(false),
QueriedExpression() { }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(Loc, RParen);
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return RParen; }
ExpressionTrait getTrait() const { return static_cast<ExpressionTrait>(ET); }
@@ -2411,7 +2437,7 @@ public:
///
/// This points to the same data as getExplicitTemplateArgs(), but
/// returns null if there are no explicit template arguments.
- const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() {
+ const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() const {
if (!hasExplicitTemplateArgs()) return 0;
return &getExplicitTemplateArgs();
}
@@ -2512,13 +2538,15 @@ public:
/// that was looked in to find these results.
CXXRecordDecl *getNamingClass() const { return NamingClass; }
- SourceRange getSourceRange() const LLVM_READONLY {
- SourceRange Range(getNameInfo().getSourceRange());
- if (getQualifierLoc())
- Range.setBegin(getQualifierLoc().getBeginLoc());
+ SourceLocation getLocStart() const LLVM_READONLY {
+ if (NestedNameSpecifierLoc l = getQualifierLoc())
+ return l.getBeginLoc();
+ return getNameInfo().getLocStart();
+ }
+ SourceLocation getLocEnd() const LLVM_READONLY {
if (hasExplicitTemplateArgs())
- Range.setEnd(getRAngleLoc());
- return Range;
+ return getRAngleLoc();
+ return getNameInfo().getLocEnd();
}
child_range children() { return child_range(); }
@@ -2647,7 +2675,7 @@ public:
/// \brief Retrieves the optional explicit template arguments.
/// This points to the same data as getExplicitTemplateArgs(), but
/// returns null if there are no explicit template arguments.
- const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() {
+ const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() const {
if (!hasExplicitTemplateArgs()) return 0;
return &getExplicitTemplateArgs();
}
@@ -2666,11 +2694,13 @@ public:
return getExplicitTemplateArgs().NumTemplateArgs;
}
- SourceRange getSourceRange() const LLVM_READONLY {
- SourceRange Range(QualifierLoc.getBeginLoc(), getLocation());
+ SourceLocation getLocStart() const LLVM_READONLY {
+ return QualifierLoc.getBeginLoc();
+ }
+ SourceLocation getLocEnd() const LLVM_READONLY {
if (hasExplicitTemplateArgs())
- Range.setEnd(getRAngleLoc());
- return Range;
+ return getRAngleLoc();
+ return getLocation();
}
static bool classof(const Stmt *T) {
@@ -2740,9 +2770,10 @@ public:
/// when modifying an existing AST to preserve its invariants.
void setSubExpr(Expr *E) { SubExpr = E; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SubExpr->getSourceRange();
+ SourceLocation getLocStart() const LLVM_READONLY {
+ return SubExpr->getLocStart();
}
+ SourceLocation getLocEnd() const LLVM_READONLY { return SubExpr->getLocEnd();}
// Implement isa/cast/dyncast/etc.
static bool classof(const Stmt *T) {
@@ -2855,7 +2886,8 @@ public:
*(arg_begin() + I) = E;
}
- SourceRange getSourceRange() const LLVM_READONLY;
+ SourceLocation getLocStart() const LLVM_READONLY;
+ SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXUnresolvedConstructExprClass;
@@ -3061,7 +3093,7 @@ public:
/// \brief Retrieves the optional explicit template arguments.
/// This points to the same data as getExplicitTemplateArgs(), but
/// returns null if there are no explicit template arguments.
- const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() {
+ const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() const {
if (!hasExplicitTemplateArgs()) return 0;
return &getExplicitTemplateArgs();
}
@@ -3089,20 +3121,18 @@ public:
return getExplicitTemplateArgs().NumTemplateArgs;
}
- SourceRange getSourceRange() const LLVM_READONLY {
- SourceRange Range;
+ SourceLocation getLocStart() const LLVM_READONLY {
if (!isImplicitAccess())
- Range.setBegin(Base->getSourceRange().getBegin());
- else if (getQualifier())
- Range.setBegin(getQualifierLoc().getBeginLoc());
- else
- Range.setBegin(MemberNameInfo.getBeginLoc());
+ return Base->getLocStart();
+ if (getQualifier())
+ return getQualifierLoc().getBeginLoc();
+ return MemberNameInfo.getBeginLoc();
+ }
+ SourceLocation getLocEnd() const LLVM_READONLY {
if (hasExplicitTemplateArgs())
- Range.setEnd(getRAngleLoc());
- else
- Range.setEnd(MemberNameInfo.getEndLoc());
- return Range;
+ return getRAngleLoc();
+ return MemberNameInfo.getEndLoc();
}
static bool classof(const Stmt *T) {
@@ -3226,16 +3256,17 @@ public:
// expression refers to.
SourceLocation getMemberLoc() const { return getNameLoc(); }
- SourceRange getSourceRange() const LLVM_READONLY {
- SourceRange Range = getMemberNameInfo().getSourceRange();
+ SourceLocation getLocStart() const LLVM_READONLY {
if (!isImplicitAccess())
- Range.setBegin(Base->getSourceRange().getBegin());
- else if (getQualifierLoc())
- Range.setBegin(getQualifierLoc().getBeginLoc());
-
+ return Base->getLocStart();
+ if (NestedNameSpecifierLoc l = getQualifierLoc())
+ return l.getBeginLoc();
+ return getMemberNameInfo().getLocStart();
+ }
+ SourceLocation getLocEnd() const LLVM_READONLY {
if (hasExplicitTemplateArgs())
- Range.setEnd(getRAngleLoc());
- return Range;
+ return getRAngleLoc();
+ return getMemberNameInfo().getLocEnd();
}
static bool classof(const Stmt *T) {
@@ -3277,6 +3308,8 @@ public:
Expr *getOperand() const { return static_cast<Expr*>(Operand); }
+ SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); }
+ SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); }
SourceRange getSourceRange() const LLVM_READONLY { return Range; }
bool getValue() const { return Value; }
@@ -3323,7 +3356,7 @@ class PackExpansionExpr : public Expr {
public:
PackExpansionExpr(QualType T, Expr *Pattern, SourceLocation EllipsisLoc,
- llvm::Optional<unsigned> NumExpansions)
+ Optional<unsigned> NumExpansions)
: Expr(PackExpansionExprClass, T, Pattern->getValueKind(),
Pattern->getObjectKind(), /*TypeDependent=*/true,
/*ValueDependent=*/true, /*InstantiationDependent=*/true,
@@ -3346,16 +3379,17 @@ public:
/// \brief Determine the number of expansions that will be produced when
/// this pack expansion is instantiated, if already known.
- llvm::Optional<unsigned> getNumExpansions() const {
+ Optional<unsigned> getNumExpansions() const {
if (NumExpansions)
return NumExpansions - 1;
- return llvm::Optional<unsigned>();
+ return None;
}
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(Pattern->getLocStart(), EllipsisLoc);
+ SourceLocation getLocStart() const LLVM_READONLY {
+ return Pattern->getLocStart();
}
+ SourceLocation getLocEnd() const LLVM_READONLY { return EllipsisLoc; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == PackExpansionExprClass;
@@ -3458,9 +3492,8 @@ public:
return Length;
}
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(OperatorLoc, RParenLoc);
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return OperatorLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == SizeOfPackExprClass;
@@ -3500,7 +3533,8 @@ public:
Param(param), Replacement(replacement), NameLoc(loc) {}
SourceLocation getNameLoc() const { return NameLoc; }
- SourceRange getSourceRange() const LLVM_READONLY { return NameLoc; }
+ SourceLocation getLocStart() const LLVM_READONLY { return NameLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return NameLoc; }
Expr *getReplacement() const { return cast<Expr>(Replacement); }
@@ -3561,7 +3595,8 @@ public:
/// template arguments.
TemplateArgument getArgumentPack() const;
- SourceRange getSourceRange() const LLVM_READONLY { return NameLoc; }
+ SourceLocation getLocStart() const LLVM_READONLY { return NameLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return NameLoc; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == SubstNonTypeTemplateParmPackExprClass;
@@ -3606,7 +3641,7 @@ public:
static FunctionParmPackExpr *Create(ASTContext &Context, QualType T,
ParmVarDecl *ParamPack,
SourceLocation NameLoc,
- llvm::ArrayRef<Decl*> Params);
+ ArrayRef<Decl *> Params);
static FunctionParmPackExpr *CreateEmpty(ASTContext &Context,
unsigned NumParams);
@@ -3628,7 +3663,8 @@ public:
/// \brief Get an expansion of the parameter pack by index.
ParmVarDecl *getExpansion(unsigned I) const { return begin()[I]; }
- SourceRange getSourceRange() const LLVM_READONLY { return NameLoc; }
+ SourceLocation getLocStart() const LLVM_READONLY { return NameLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return NameLoc; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == FunctionParmPackExprClass;
@@ -3684,8 +3720,11 @@ public:
return getValueKind() == VK_LValue;
}
- SourceRange getSourceRange() const LLVM_READONLY {
- return Temporary->getSourceRange();
+ SourceLocation getLocStart() const LLVM_READONLY {
+ return Temporary->getLocStart();
+ }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ return Temporary->getLocEnd();
}
static bool classof(const Stmt *T) {
diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h
index 27f5da0..dfd4527 100644
--- a/include/clang/AST/ExprObjC.h
+++ b/include/clang/AST/ExprObjC.h
@@ -44,9 +44,8 @@ public:
SourceLocation getAtLoc() const { return AtLoc; }
void setAtLoc(SourceLocation L) { AtLoc = L; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(AtLoc, String->getLocEnd());
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return AtLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return String->getLocEnd(); }
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCStringLiteralClass;
@@ -72,8 +71,9 @@ public:
bool getValue() const { return Value; }
void setValue(bool V) { Value = V; }
- SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc); }
-
+ SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return Loc; }
+
SourceLocation getLocation() const { return Loc; }
void setLocation(SourceLocation L) { Loc = L; }
@@ -112,6 +112,8 @@ public:
SourceLocation getAtLoc() const { return Range.getBegin(); }
+ SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); }
+ SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); }
SourceRange getSourceRange() const LLVM_READONLY {
return Range;
}
@@ -133,7 +135,7 @@ class ObjCArrayLiteral : public Expr {
SourceRange Range;
ObjCMethodDecl *ArrayWithObjectsMethod;
- ObjCArrayLiteral(llvm::ArrayRef<Expr *> Elements,
+ ObjCArrayLiteral(ArrayRef<Expr *> Elements,
QualType T, ObjCMethodDecl * Method,
SourceRange SR);
@@ -142,12 +144,14 @@ class ObjCArrayLiteral : public Expr {
public:
static ObjCArrayLiteral *Create(ASTContext &C,
- llvm::ArrayRef<Expr *> Elements,
+ ArrayRef<Expr *> Elements,
QualType T, ObjCMethodDecl * Method,
SourceRange SR);
static ObjCArrayLiteral *CreateEmpty(ASTContext &C, unsigned NumElements);
+ SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); }
+ SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); }
SourceRange getSourceRange() const LLVM_READONLY { return Range; }
static bool classof(const Stmt *T) {
@@ -202,12 +206,18 @@ struct ObjCDictionaryElement {
/// \brief The number of elements this pack expansion will expand to, if
/// this is a pack expansion and is known.
- llvm::Optional<unsigned> NumExpansions;
+ Optional<unsigned> NumExpansions;
/// \brief Determines whether this dictionary element is a pack expansion.
bool isPackExpansion() const { return EllipsisLoc.isValid(); }
};
+} // end namespace clang
+
+namespace llvm {
+template <> struct isPodLike<clang::ObjCDictionaryElement> : llvm::true_type {};
+}
+namespace clang {
/// ObjCDictionaryLiteral - AST node to represent objective-c dictionary
/// literals; as in: @{@"name" : NSUserName(), @"date" : [NSDate date] };
class ObjCDictionaryLiteral : public Expr {
@@ -296,8 +306,7 @@ public:
ObjCDictionaryElement getKeyValueElement(unsigned Index) const {
assert((Index < NumElements) && "Arg access out of range!");
const KeyValuePair &KV = getKeyValues()[Index];
- ObjCDictionaryElement Result = { KV.Key, KV.Value, SourceLocation(),
- llvm::Optional<unsigned>() };
+ ObjCDictionaryElement Result = { KV.Key, KV.Value, SourceLocation(), None };
if (HasPackExpansions) {
const ExpansionData &Expansion = getExpansionData()[Index];
Result.EllipsisLoc = Expansion.EllipsisLoc;
@@ -310,6 +319,8 @@ public:
ObjCMethodDecl *getDictWithObjectsMethod() const
{ return DictWithObjectsMethod; }
+ SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); }
+ SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); }
SourceRange getSourceRange() const LLVM_READONLY { return Range; }
static bool classof(const Stmt *T) {
@@ -360,9 +371,8 @@ public:
EncodedType = EncType;
}
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(AtLoc, RParenLoc);
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return AtLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCEncodeExprClass;
@@ -393,9 +403,8 @@ public:
void setAtLoc(SourceLocation L) { AtLoc = L; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(AtLoc, RParenLoc);
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return AtLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
/// getNumArgs - Return the number of actual arguments to this call.
unsigned getNumArgs() const { return SelName.getNumArgs(); }
@@ -408,9 +417,13 @@ public:
child_range children() { return child_range(); }
};
-/// ObjCProtocolExpr used for protocol expression in Objective-C. This is used
-/// as: @protocol(foo), as in:
-/// obj conformsToProtocol:@protocol(foo)]
+/// ObjCProtocolExpr used for protocol expression in Objective-C.
+///
+/// This is used as: \@protocol(foo), as in:
+/// \code
+/// [obj conformsToProtocol:@protocol(foo)]
+/// \endcode
+///
/// The return type is "Protocol*".
class ObjCProtocolExpr : public Expr {
ObjCProtocolDecl *TheProtocol;
@@ -433,9 +446,8 @@ public:
void setAtLoc(SourceLocation L) { AtLoc = L; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(AtLoc, RParenLoc);
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return AtLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCProtocolExprClass;
@@ -453,18 +465,23 @@ class ObjCIvarRefExpr : public Expr {
ObjCIvarDecl *D;
Stmt *Base;
SourceLocation Loc;
+ /// OpLoc - This is the location of '.' or '->'
+ SourceLocation OpLoc;
+
bool IsArrow:1; // True if this is "X->F", false if this is "X.F".
bool IsFreeIvar:1; // True if ivar reference has no base (self assumed).
public:
ObjCIvarRefExpr(ObjCIvarDecl *d, QualType t,
- SourceLocation l, Expr *base,
+ SourceLocation l, SourceLocation oploc,
+ Expr *base,
bool arrow = false, bool freeIvar = false) :
Expr(ObjCIvarRefExprClass, t, VK_LValue, OK_Ordinary,
/*TypeDependent=*/false, base->isValueDependent(),
base->isInstantiationDependent(),
base->containsUnexpandedParameterPack()),
- D(d), Base(base), Loc(l), IsArrow(arrow), IsFreeIvar(freeIvar) {}
+ D(d), Base(base), Loc(l), OpLoc(oploc),
+ IsArrow(arrow), IsFreeIvar(freeIvar) {}
explicit ObjCIvarRefExpr(EmptyShell Empty)
: Expr(ObjCIvarRefExprClass, Empty) {}
@@ -485,10 +502,13 @@ public:
SourceLocation getLocation() const { return Loc; }
void setLocation(SourceLocation L) { Loc = L; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return isFreeIvar() ? SourceRange(Loc)
- : SourceRange(getBase()->getLocStart(), Loc);
+ SourceLocation getLocStart() const LLVM_READONLY {
+ return isFreeIvar() ? Loc : getBase()->getLocStart();
}
+ SourceLocation getLocEnd() const LLVM_READONLY { return Loc; }
+
+ SourceLocation getOpLoc() const { return OpLoc; }
+ void setOpLoc(SourceLocation L) { OpLoc = L; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCIvarRefExprClass;
@@ -697,11 +717,10 @@ public:
bool isSuperReceiver() const { return Receiver.is<const Type*>(); }
bool isClassReceiver() const { return Receiver.is<ObjCInterfaceDecl*>(); }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange((isObjectReceiver() ? getBase()->getLocStart()
- : getReceiverLocation()),
- IdLoc);
+ SourceLocation getLocStart() const LLVM_READONLY {
+ return isObjectReceiver() ? getBase()->getLocStart() :getReceiverLocation();
}
+ SourceLocation getLocEnd() const LLVM_READONLY { return IdLoc; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCPropertyRefExprClass;
@@ -796,10 +815,12 @@ public:
SourceLocation getRBracket() const { return RBracket; }
void setRBracket(SourceLocation RB) { RBracket = RB; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(SubExprs[BASE]->getLocStart(), RBracket);
+
+ SourceLocation getLocStart() const LLVM_READONLY {
+ return SubExprs[BASE]->getLocStart();
}
-
+ SourceLocation getLocEnd() const LLVM_READONLY { return RBracket; }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCSubscriptRefExprClass;
}
@@ -1335,9 +1356,8 @@ public:
LBracLoc = R.getBegin();
RBracLoc = R.getEnd();
}
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(LBracLoc, RBracLoc);
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return LBracLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return RBracLoc; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCMessageExprClass;
@@ -1372,16 +1392,20 @@ class ObjCIsaExpr : public Expr {
/// IsaMemberLoc - This is the location of the 'isa'.
SourceLocation IsaMemberLoc;
+
+ /// OpLoc - This is the location of '.' or '->'
+ SourceLocation OpLoc;
/// IsArrow - True if this is "X->F", false if this is "X.F".
bool IsArrow;
public:
- ObjCIsaExpr(Expr *base, bool isarrow, SourceLocation l, QualType ty)
+ ObjCIsaExpr(Expr *base, bool isarrow, SourceLocation l, SourceLocation oploc,
+ QualType ty)
: Expr(ObjCIsaExprClass, ty, VK_LValue, OK_Ordinary,
/*TypeDependent=*/false, base->isValueDependent(),
base->isInstantiationDependent(),
/*ContainsUnexpandedParameterPack=*/false),
- Base(base), IsaMemberLoc(l), IsArrow(isarrow) {}
+ Base(base), IsaMemberLoc(l), OpLoc(oploc), IsArrow(isarrow) {}
/// \brief Build an empty expression.
explicit ObjCIsaExpr(EmptyShell Empty) : Expr(ObjCIsaExprClass, Empty) { }
@@ -1396,10 +1420,19 @@ public:
/// location of 'F'.
SourceLocation getIsaMemberLoc() const { return IsaMemberLoc; }
void setIsaMemberLoc(SourceLocation L) { IsaMemberLoc = L; }
+
+ SourceLocation getOpLoc() const { return OpLoc; }
+ void setOpLoc(SourceLocation L) { OpLoc = L; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(getBase()->getLocStart(), IsaMemberLoc);
+ SourceLocation getLocStart() const LLVM_READONLY {
+ return getBase()->getLocStart();
+ }
+
+ SourceLocation getBaseLocEnd() const LLVM_READONLY {
+ return getBase()->getLocEnd();
}
+
+ SourceLocation getLocEnd() const LLVM_READONLY { return IsaMemberLoc; }
SourceLocation getExprLoc() const LLVM_READONLY { return IsaMemberLoc; }
@@ -1469,9 +1502,11 @@ public:
child_range children() { return child_range(&Operand, &Operand+1); }
// Source locations are determined by the subexpression.
- SourceRange getSourceRange() const LLVM_READONLY {
- return Operand->getSourceRange();
+ SourceLocation getLocStart() const LLVM_READONLY {
+ return Operand->getLocStart();
}
+ SourceLocation getLocEnd() const LLVM_READONLY { return Operand->getLocEnd();}
+
SourceLocation getExprLoc() const LLVM_READONLY {
return getSubExpr()->getExprLoc();
}
@@ -1520,8 +1555,9 @@ public:
/// \brief The location of the bridge keyword.
SourceLocation getBridgeKeywordLoc() const { return BridgeKeywordLoc; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(LParenLoc, getSubExpr()->getLocEnd());
+ SourceLocation getLocStart() const LLVM_READONLY { return LParenLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ return getSubExpr()->getLocEnd();
}
static bool classof(const Stmt *T) {
diff --git a/include/clang/AST/ExternalASTSource.h b/include/clang/AST/ExternalASTSource.h
index db2bddb..81fcf24 100644
--- a/include/clang/AST/ExternalASTSource.h
+++ b/include/clang/AST/ExternalASTSource.h
@@ -14,8 +14,8 @@
#ifndef LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
#define LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H
-#include "clang/AST/DeclBase.h"
#include "clang/AST/CharUnits.h"
+#include "clang/AST/DeclBase.h"
#include "llvm/ADT/DenseMap.h"
namespace clang {
@@ -24,7 +24,10 @@ class ASTConsumer;
class CXXBaseSpecifier;
class DeclarationName;
class ExternalSemaSource; // layering violation required for downcasting
+class FieldDecl;
+class Module;
class NamedDecl;
+class RecordDecl;
class Selector;
class Stmt;
class TagDecl;
@@ -115,23 +118,28 @@ public:
/// The default implementation of this method is a no-op.
virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset);
- /// \brief Finds all declarations with the given name in the
- /// given context.
- ///
- /// Generally the final step of this method is either to call
- /// SetExternalVisibleDeclsForName or to recursively call lookup on
- /// the DeclContext after calling SetExternalVisibleDecls.
+ /// \brief Update an out-of-date identifier.
+ virtual void updateOutOfDateIdentifier(IdentifierInfo &II) { }
+
+ /// \brief Find all declarations with the given name in the given context,
+ /// and add them to the context by calling SetExternalVisibleDeclsForName
+ /// or SetNoExternalVisibleDeclsForName.
+ /// \return \c true if any declarations might have been found, \c false if
+ /// we definitely have no declarations with tbis name.
///
- /// The default implementation of this method is a no-op.
- virtual DeclContextLookupResult
+ /// The default implementation of this method is a no-op returning \c false.
+ virtual bool
FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name);
/// \brief Ensures that the table of all visible declarations inside this
/// context is up to date.
///
- /// The default implementation of this functino is a no-op.
+ /// The default implementation of this function is a no-op.
virtual void completeVisibleDeclsMap(const DeclContext *DC);
+ /// \brief Retrieve the module that corresponds to the given module ID.
+ virtual Module *getModule(unsigned ID) { return 0; }
+
/// \brief Finds all declarations lexically contained within the given
/// DeclContext, after applying an optional filter predicate.
///
diff --git a/include/clang/AST/LambdaMangleContext.h b/include/clang/AST/LambdaMangleContext.h
index 3e2fbad..bbaee26 100644
--- a/include/clang/AST/LambdaMangleContext.h
+++ b/include/clang/AST/LambdaMangleContext.h
@@ -14,7 +14,9 @@
#ifndef LLVM_CLANG_LAMBDAMANGLECONTEXT_H
#define LLVM_CLANG_LAMBDAMANGLECONTEXT_H
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
namespace clang {
@@ -23,7 +25,7 @@ class FunctionProtoType;
/// \brief Keeps track of the mangled names of lambda expressions within a
/// particular context.
-class LambdaMangleContext {
+class LambdaMangleContext : public RefCountedBase<LambdaMangleContext> {
llvm::DenseMap<const FunctionProtoType *, unsigned> ManglingNumbers;
public:
diff --git a/include/clang/AST/Makefile b/include/clang/AST/Makefile
index 7fb33f2..ae84bcf 100644
--- a/include/clang/AST/Makefile
+++ b/include/clang/AST/Makefile
@@ -1,8 +1,12 @@
CLANG_LEVEL := ../../..
TD_SRC_DIR = $(PROJ_SRC_DIR)/../Basic
-BUILT_SOURCES = Attrs.inc AttrImpl.inc StmtNodes.inc DeclNodes.inc \
+BUILT_SOURCES = Attrs.inc AttrImpl.inc AttrDump.inc \
+ StmtNodes.inc DeclNodes.inc \
CommentNodes.inc CommentHTMLTags.inc \
- CommentHTMLTagsProperties.inc CommentCommandInfo.inc
+ CommentHTMLTagsProperties.inc \
+ CommentHTMLNamedCharacterReferences.inc \
+ CommentCommandInfo.inc \
+ CommentCommandList.inc
TABLEGEN_INC_FILES_COMMON = 1
@@ -20,6 +24,12 @@ $(ObjDir)/AttrImpl.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \
$(Verb) $(ClangTableGen) -gen-clang-attr-impl -o $(call SYSPATH, $@) \
-I $(PROJ_SRC_DIR)/../../ $<
+$(ObjDir)/AttrDump.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \
+ $(ObjDir)/.dir
+ $(Echo) "Building Clang attribute dumper with tblgen"
+ $(Verb) $(ClangTableGen) -gen-clang-attr-dump -o $(call SYSPATH, $@) \
+ -I $(PROJ_SRC_DIR)/../../ $<
+
$(ObjDir)/StmtNodes.inc.tmp : $(TD_SRC_DIR)/StmtNodes.td $(CLANG_TBLGEN) \
$(ObjDir)/.dir
$(Echo) "Building Clang statement node tables with tblgen"
@@ -45,8 +55,19 @@ $(ObjDir)/CommentHTMLTagsProperties.inc.tmp : $(PROJ_SRC_DIR)/CommentHTMLTags.td
$(Echo) "Building Clang comment HTML tag properties with tblgen"
$(Verb) $(ClangTableGen) -gen-clang-comment-html-tags-properties -o $(call SYSPATH, $@) $<
+$(ObjDir)/CommentHTMLNamedCharacterReferences.inc.tmp : \
+ $(PROJ_SRC_DIR)/CommentHTMLNamedCharacterReferences.td \
+ $(CLANG_TBLGEN) $(ObjDir)/.dir
+ $(Echo) "Building Clang named character reference translation function with tblgen"
+ $(Verb) $(ClangTableGen) -gen-clang-comment-html-named-character-references -o $(call SYSPATH, $@) $<
+
$(ObjDir)/CommentCommandInfo.inc.tmp : $(PROJ_SRC_DIR)/CommentCommands.td \
$(CLANG_TBLGEN) $(ObjDir)/.dir
$(Echo) "Building Clang comment command info with tblgen"
$(Verb) $(ClangTableGen) -gen-clang-comment-command-info -o $(call SYSPATH, $@) $<
+$(ObjDir)/CommentCommandList.inc.tmp : $(PROJ_SRC_DIR)/CommentCommands.td \
+ $(CLANG_TBLGEN) $(ObjDir)/.dir
+ $(Echo) "Building Clang list of comment commands with tblgen"
+ $(Verb) $(ClangTableGen) -gen-clang-comment-command-list -o $(call SYSPATH, $@) $<
+
diff --git a/include/clang/AST/Mangle.h b/include/clang/AST/Mangle.h
index a0dffb9..94faa19 100644
--- a/include/clang/AST/Mangle.h
+++ b/include/clang/AST/Mangle.h
@@ -17,8 +17,8 @@
#include "clang/AST/Type.h"
#include "clang/Basic/ABI.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/raw_ostream.h"
namespace clang {
diff --git a/include/clang/AST/NSAPI.h b/include/clang/AST/NSAPI.h
index f9fd1f9..0b21b03 100644
--- a/include/clang/AST/NSAPI.h
+++ b/include/clang/AST/NSAPI.h
@@ -52,7 +52,7 @@ public:
Selector getNSStringSelector(NSStringMethodKind MK) const;
/// \brief Return NSStringMethodKind if \param Sel is such a selector.
- llvm::Optional<NSStringMethodKind> getNSStringMethodKind(Selector Sel) const;
+ Optional<NSStringMethodKind> getNSStringMethodKind(Selector Sel) const;
/// \brief Returns true if the expression \param E is a reference of
/// "NSUTF8StringEncoding" enum constant.
@@ -84,7 +84,7 @@ public:
Selector getNSArraySelector(NSArrayMethodKind MK) const;
/// \brief Return NSArrayMethodKind if \p Sel is such a selector.
- llvm::Optional<NSArrayMethodKind> getNSArrayMethodKind(Selector Sel);
+ Optional<NSArrayMethodKind> getNSArrayMethodKind(Selector Sel);
/// \brief Enumerates the NSDictionary methods used to generate literals.
enum NSDictionaryMethodKind {
@@ -96,17 +96,17 @@ public:
NSDict_dictionaryWithObjectsAndKeys,
NSDict_initWithDictionary,
NSDict_initWithObjectsAndKeys,
+ NSDict_initWithObjectsForKeys,
NSDict_objectForKey,
NSMutableDict_setObjectForKey
};
- static const unsigned NumNSDictionaryMethods = 10;
+ static const unsigned NumNSDictionaryMethods = 11;
/// \brief The Objective-C NSDictionary selectors.
Selector getNSDictionarySelector(NSDictionaryMethodKind MK) const;
/// \brief Return NSDictionaryMethodKind if \p Sel is such a selector.
- llvm::Optional<NSDictionaryMethodKind>
- getNSDictionaryMethodKind(Selector Sel);
+ Optional<NSDictionaryMethodKind> getNSDictionaryMethodKind(Selector Sel);
/// \brief Returns selector for "objectForKeyedSubscript:".
Selector getObjectForKeyedSubscriptSelector() const {
@@ -170,12 +170,12 @@ public:
}
/// \brief Return NSNumberLiteralMethodKind if \p Sel is such a selector.
- llvm::Optional<NSNumberLiteralMethodKind>
+ Optional<NSNumberLiteralMethodKind>
getNSNumberLiteralMethodKind(Selector Sel) const;
/// \brief Determine the appropriate NSNumber factory method kind for a
/// literal of the given type.
- llvm::Optional<NSNumberLiteralMethodKind>
+ Optional<NSNumberLiteralMethodKind>
getNSNumberFactoryMethodKind(QualType T) const;
/// \brief Returns true if \param T is a typedef of "BOOL" in objective-c.
diff --git a/include/clang/AST/NestedNameSpecifier.h b/include/clang/AST/NestedNameSpecifier.h
index bf9e1cb..58f3986 100644
--- a/include/clang/AST/NestedNameSpecifier.h
+++ b/include/clang/AST/NestedNameSpecifier.h
@@ -117,7 +117,7 @@ public:
/// \brief Builds a nested name specifier that names a namespace.
static NestedNameSpecifier *Create(const ASTContext &Context,
NestedNameSpecifier *Prefix,
- NamespaceDecl *NS);
+ const NamespaceDecl *NS);
/// \brief Builds a nested name specifier that names a namespace alias.
static NestedNameSpecifier *Create(const ASTContext &Context,
diff --git a/include/clang/AST/OperationKinds.h b/include/clang/AST/OperationKinds.h
index 18169fd..5e41d95 100644
--- a/include/clang/AST/OperationKinds.h
+++ b/include/clang/AST/OperationKinds.h
@@ -292,7 +292,10 @@ enum CastKind {
// Convert a builtin function to a function pointer; only allowed in the
// callee of a call expression.
- CK_BuiltinFnToFnPtr
+ CK_BuiltinFnToFnPtr,
+
+ // Convert a zero value for OpenCL event_t initialization.
+ CK_ZeroToOCLEvent
};
static const CastKind CK_Invalid = static_cast<CastKind>(-1);
diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h
index 7babc1b..e3c09e7 100644
--- a/include/clang/AST/PrettyPrinter.h
+++ b/include/clang/AST/PrettyPrinter.h
@@ -14,14 +14,15 @@
#ifndef LLVM_CLANG_AST_PRETTY_PRINTER_H
#define LLVM_CLANG_AST_PRETTY_PRINTER_H
-#include "clang/Basic/LangOptions.h"
#include "clang/Basic/LLVM.h"
+#include "clang/Basic/LangOptions.h"
namespace clang {
+class LangOptions;
+class SourceManager;
class Stmt;
class TagDecl;
-class LangOptions;
class PrinterHelper {
public:
@@ -39,8 +40,7 @@ struct PrintingPolicy {
SuppressUnwrittenScope(false), SuppressInitializers(false),
ConstantArraySizeAsWritten(false), AnonymousTagLocations(true),
SuppressStrongLifetime(false), Bool(LO.Bool),
- TerseOutput(false), SuppressAttributes(false),
- DumpSourceManager(0) { }
+ TerseOutput(false), PolishForDeclaration(false) { }
/// \brief What language we're printing.
LangOptions LangOpts;
@@ -142,15 +142,10 @@ struct PrintingPolicy {
/// only the requested declaration.
unsigned TerseOutput : 1;
- /// \brief When true, do not print attributes attached to the declaration.
+ /// \brief When true, do certain refinement needed for producing proper
+ /// declaration tag; such as, do not print attributes attached to the declaration.
///
- unsigned SuppressAttributes : 1;
-
- /// \brief If we are "dumping" rather than "pretty-printing", this points to
- /// a SourceManager which will be used to dump SourceLocations. Dumping
- /// involves printing the internal details of the AST and pretty-printing
- /// involves printing something similar to source code.
- SourceManager *DumpSourceManager;
+ unsigned PolishForDeclaration : 1;
};
} // end namespace clang
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index f96e067..0191964 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -18,6 +18,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
@@ -464,20 +465,15 @@ template<typename Derived>
bool RecursiveASTVisitor<Derived>::dataTraverseNode(Stmt *S,
bool &EnqueueChildren) {
-// The cast for DISPATCH_WALK is needed for older versions of g++, but causes
-// problems for MSVC. So we'll skip the cast entirely for MSVC.
-#if defined(_MSC_VER)
- #define GCC_CAST(CLASS)
-#else
- #define GCC_CAST(CLASS) (bool (RecursiveASTVisitor::*)(CLASS*))
-#endif
-
// Dispatch to the corresponding WalkUpFrom* function only if the derived
// class didn't override Traverse* (and thus the traversal is trivial).
#define DISPATCH_WALK(NAME, CLASS, VAR) \
- if (&RecursiveASTVisitor::Traverse##NAME == \
- GCC_CAST(CLASS)&Derived::Traverse##NAME) \
- return getDerived().WalkUpFrom##NAME(static_cast<CLASS*>(VAR)); \
+ { \
+ bool (Derived::*DerivedFn)(CLASS*) = &Derived::Traverse##NAME; \
+ bool (Derived::*BaseFn)(CLASS*) = &RecursiveASTVisitor::Traverse##NAME; \
+ if (DerivedFn == BaseFn) \
+ return getDerived().WalkUpFrom##NAME(static_cast<CLASS*>(VAR)); \
+ } \
EnqueueChildren = false; \
return getDerived().Traverse##NAME(static_cast<CLASS*>(VAR));
@@ -516,7 +512,6 @@ bool RecursiveASTVisitor<Derived>::dataTraverseNode(Stmt *S,
}
#undef DISPATCH_WALK
-#undef GCC_CAST
return true;
}
@@ -600,7 +595,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTypeLoc(TypeLoc TL) {
#define ABSTRACT_TYPELOC(CLASS, BASE)
#define TYPELOC(CLASS, BASE) \
case TypeLoc::CLASS: \
- return getDerived().Traverse##CLASS##TypeLoc(*cast<CLASS##TypeLoc>(&TL));
+ return getDerived().Traverse##CLASS##TypeLoc(TL.castAs<CLASS##TypeLoc>());
#include "clang/AST/TypeLocNodes.def"
}
@@ -1263,6 +1258,8 @@ DEF_TRAVERSE_DECL(BlockDecl, {
return true;
})
+DEF_TRAVERSE_DECL(EmptyDecl, { })
+
DEF_TRAVERSE_DECL(FileScopeAsmDecl, {
TRY_TO(TraverseStmt(D->getAsmString()));
})
@@ -1393,6 +1390,14 @@ DEF_TRAVERSE_DECL(UsingDirectiveDecl, {
DEF_TRAVERSE_DECL(UsingShadowDecl, { })
+DEF_TRAVERSE_DECL(OMPThreadPrivateDecl, {
+ for (OMPThreadPrivateDecl::varlist_iterator I = D->varlist_begin(),
+ E = D->varlist_end();
+ I != E; ++I) {
+ TRY_TO(TraverseStmt(*I));
+ }
+ })
+
// A helper method for TemplateDecl's children.
template<typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseTemplateParameterListHelper(
@@ -1716,7 +1721,7 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) {
// FunctionNoProtoType or FunctionProtoType, or a typedef. This
// also covers the return type and the function parameters,
// including exception specifications.
- if (clang::TypeSourceInfo *TSI = D->getTypeSourceInfo()) {
+ if (TypeSourceInfo *TSI = D->getTypeSourceInfo()) {
TRY_TO(TraverseTypeLoc(TSI->getTypeLoc()));
}
@@ -2106,8 +2111,7 @@ bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) {
if (S->hasExplicitParameters() && S->hasExplicitResultType()) {
// Visit the whole type.
TRY_TO(TraverseTypeLoc(TL));
- } else if (isa<FunctionProtoTypeLoc>(TL)) {
- FunctionProtoTypeLoc Proto = cast<FunctionProtoTypeLoc>(TL);
+ } else if (FunctionProtoTypeLoc Proto = TL.getAs<FunctionProtoTypeLoc>()) {
if (S->hasExplicitParameters()) {
// Visit parameters.
for (unsigned I = 0, N = Proto.getNumArgs(); I != N; ++I) {
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h
index a9bbb48..cf8fc24 100644
--- a/include/clang/AST/Stmt.h
+++ b/include/clang/AST/Stmt.h
@@ -14,16 +14,14 @@
#ifndef LLVM_CLANG_AST_STMT_H
#define LLVM_CLANG_AST_STMT_H
+#include "clang/AST/DeclGroup.h"
+#include "clang/AST/StmtIterator.h"
+#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
-#include "clang/AST/PrettyPrinter.h"
-#include "clang/AST/StmtIterator.h"
-#include "clang/AST/DeclGroup.h"
-#include "clang/AST/Attr.h"
-#include "clang/Lex/Token.h"
-#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/Compiler.h"
-#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/ErrorHandling.h"
#include <string>
namespace llvm {
@@ -32,15 +30,19 @@ namespace llvm {
namespace clang {
class ASTContext;
- class Expr;
+ class Attr;
class Decl;
- class ParmVarDecl;
- class QualType;
+ class Expr;
class IdentifierInfo;
class LabelDecl;
+ class ParmVarDecl;
+ class PrinterHelper;
+ struct PrintingPolicy;
+ class QualType;
class SourceManager;
class StringLiteral;
class SwitchStmt;
+ class Token;
class VarDecl;
//===--------------------------------------------------------------------===//
@@ -172,11 +174,20 @@ protected:
unsigned Kind : 2;
};
+ enum APFloatSemantics {
+ IEEEhalf,
+ IEEEsingle,
+ IEEEdouble,
+ x87DoubleExtended,
+ IEEEquad,
+ PPCDoubleDouble
+ };
+
class FloatingLiteralBitfields {
friend class FloatingLiteral;
unsigned : NumExprBits;
- unsigned IsIEEE : 1; // Distinguishes between PPC128 and IEEE128.
+ unsigned Semantics : 3; // Provides semantics for APFloat construction
unsigned IsExact : 1;
};
@@ -302,14 +313,10 @@ public:
// Only allow allocation of Stmts using the allocator in ASTContext
// or by doing a placement new.
void* operator new(size_t bytes, ASTContext& C,
- unsigned alignment = 8) throw() {
- return ::operator new(bytes, C, alignment);
- }
+ unsigned alignment = 8) throw();
void* operator new(size_t bytes, ASTContext* C,
- unsigned alignment = 8) throw() {
- return ::operator new(bytes, *C, alignment);
- }
+ unsigned alignment = 8) throw();
void* operator new(size_t bytes, void* mem) throw() {
return mem;
@@ -360,16 +367,14 @@ public:
static void EnableStatistics();
static void PrintStats();
- /// dump - This does a local dump of the specified AST fragment. It dumps the
- /// specified node and a few nodes underneath it, but not the whole subtree.
- /// This is useful in a debugger.
+ /// \brief Dumps the specified AST fragment and all subtrees to
+ /// \c llvm::errs().
LLVM_ATTRIBUTE_USED void dump() const;
LLVM_ATTRIBUTE_USED void dump(SourceManager &SM) const;
void dump(raw_ostream &OS, SourceManager &SM) const;
- /// dumpAll - This does a dump of the specified AST fragment and all subtrees.
- void dumpAll() const;
- void dumpAll(SourceManager &SM) const;
+ /// dumpColor - same as dump(), but forces color highlighting.
+ LLVM_ATTRIBUTE_USED void dumpColor() const;
/// dumpPretty/printPretty - These two methods do a "pretty print" of the AST
/// back to its original source language syntax.
@@ -470,9 +475,8 @@ public:
SourceLocation getEndLoc() const { return EndLoc; }
void setEndLoc(SourceLocation L) { EndLoc = L; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(StartLoc, EndLoc);
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return StartLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return EndLoc; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == DeclStmtClass;
@@ -526,7 +530,8 @@ public:
bool hasLeadingEmptyMacro() const { return HasLeadingEmptyMacro; }
- SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(SemiLoc); }
+ SourceLocation getLocStart() const LLVM_READONLY { return SemiLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return SemiLoc; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == NullStmtClass;
@@ -544,7 +549,7 @@ class CompoundStmt : public Stmt {
Stmt** Body;
SourceLocation LBracLoc, RBracLoc;
public:
- CompoundStmt(ASTContext &C, Stmt **StmtStart, unsigned NumStmts,
+ CompoundStmt(ASTContext &C, ArrayRef<Stmt*> Stmts,
SourceLocation LB, SourceLocation RB);
// \brief Build an empty compound statment with a location.
@@ -598,9 +603,8 @@ public:
return const_reverse_body_iterator(body_begin());
}
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(LBracLoc, RBracLoc);
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return LBracLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return RBracLoc; }
SourceLocation getLBracLoc() const { return LBracLoc; }
void setLBracLoc(SourceLocation L) { LBracLoc = L; }
@@ -627,8 +631,14 @@ protected:
// A pointer to the following CaseStmt or DefaultStmt class,
// used by SwitchStmt.
SwitchCase *NextSwitchCase;
+ SourceLocation KeywordLoc;
+ SourceLocation ColonLoc;
- SwitchCase(StmtClass SC) : Stmt(SC), NextSwitchCase(0) {}
+ SwitchCase(StmtClass SC, SourceLocation KWLoc, SourceLocation ColonLoc)
+ : Stmt(SC), NextSwitchCase(0), KeywordLoc(KWLoc), ColonLoc(ColonLoc) {}
+
+ SwitchCase(StmtClass SC, EmptyShell)
+ : Stmt(SC), NextSwitchCase(0) {}
public:
const SwitchCase *getNextSwitchCase() const { return NextSwitchCase; }
@@ -637,12 +647,18 @@ public:
void setNextSwitchCase(SwitchCase *SC) { NextSwitchCase = SC; }
+ SourceLocation getKeywordLoc() const { return KeywordLoc; }
+ void setKeywordLoc(SourceLocation L) { KeywordLoc = L; }
+ SourceLocation getColonLoc() const { return ColonLoc; }
+ void setColonLoc(SourceLocation L) { ColonLoc = L; }
+
Stmt *getSubStmt();
const Stmt *getSubStmt() const {
return const_cast<SwitchCase*>(this)->getSubStmt();
}
- SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(); }
+ SourceLocation getLocStart() const LLVM_READONLY { return KeywordLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY;
static bool classof(const Stmt *T) {
return T->getStmtClass() == CaseStmtClass ||
@@ -654,26 +670,22 @@ class CaseStmt : public SwitchCase {
enum { LHS, RHS, SUBSTMT, END_EXPR };
Stmt* SubExprs[END_EXPR]; // The expression for the RHS is Non-null for
// GNU "case 1 ... 4" extension
- SourceLocation CaseLoc;
SourceLocation EllipsisLoc;
- SourceLocation ColonLoc;
public:
CaseStmt(Expr *lhs, Expr *rhs, SourceLocation caseLoc,
SourceLocation ellipsisLoc, SourceLocation colonLoc)
- : SwitchCase(CaseStmtClass) {
+ : SwitchCase(CaseStmtClass, caseLoc, colonLoc) {
SubExprs[SUBSTMT] = 0;
SubExprs[LHS] = reinterpret_cast<Stmt*>(lhs);
SubExprs[RHS] = reinterpret_cast<Stmt*>(rhs);
- CaseLoc = caseLoc;
EllipsisLoc = ellipsisLoc;
- ColonLoc = colonLoc;
}
/// \brief Build an empty switch case statement.
- explicit CaseStmt(EmptyShell Empty) : SwitchCase(CaseStmtClass) { }
+ explicit CaseStmt(EmptyShell Empty) : SwitchCase(CaseStmtClass, Empty) { }
- SourceLocation getCaseLoc() const { return CaseLoc; }
- void setCaseLoc(SourceLocation L) { CaseLoc = L; }
+ SourceLocation getCaseLoc() const { return KeywordLoc; }
+ void setCaseLoc(SourceLocation L) { KeywordLoc = L; }
SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
void setEllipsisLoc(SourceLocation L) { EllipsisLoc = L; }
SourceLocation getColonLoc() const { return ColonLoc; }
@@ -695,15 +707,16 @@ public:
void setLHS(Expr *Val) { SubExprs[LHS] = reinterpret_cast<Stmt*>(Val); }
void setRHS(Expr *Val) { SubExprs[RHS] = reinterpret_cast<Stmt*>(Val); }
-
- SourceRange getSourceRange() const LLVM_READONLY {
+ SourceLocation getLocStart() const LLVM_READONLY { return KeywordLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY {
// Handle deeply nested case statements with iteration instead of recursion.
const CaseStmt *CS = this;
while (const CaseStmt *CS2 = dyn_cast<CaseStmt>(CS->getSubStmt()))
CS = CS2;
- return SourceRange(CaseLoc, CS->getSubStmt()->getLocEnd());
+ return CS->getSubStmt()->getLocEnd();
}
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == CaseStmtClass;
}
@@ -716,28 +729,26 @@ public:
class DefaultStmt : public SwitchCase {
Stmt* SubStmt;
- SourceLocation DefaultLoc;
- SourceLocation ColonLoc;
public:
DefaultStmt(SourceLocation DL, SourceLocation CL, Stmt *substmt) :
- SwitchCase(DefaultStmtClass), SubStmt(substmt), DefaultLoc(DL),
- ColonLoc(CL) {}
+ SwitchCase(DefaultStmtClass, DL, CL), SubStmt(substmt) {}
/// \brief Build an empty default statement.
- explicit DefaultStmt(EmptyShell) : SwitchCase(DefaultStmtClass) { }
+ explicit DefaultStmt(EmptyShell Empty)
+ : SwitchCase(DefaultStmtClass, Empty) { }
Stmt *getSubStmt() { return SubStmt; }
const Stmt *getSubStmt() const { return SubStmt; }
void setSubStmt(Stmt *S) { SubStmt = S; }
- SourceLocation getDefaultLoc() const { return DefaultLoc; }
- void setDefaultLoc(SourceLocation L) { DefaultLoc = L; }
+ SourceLocation getDefaultLoc() const { return KeywordLoc; }
+ void setDefaultLoc(SourceLocation L) { KeywordLoc = L; }
SourceLocation getColonLoc() const { return ColonLoc; }
void setColonLoc(SourceLocation L) { ColonLoc = L; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(DefaultLoc, SubStmt->getLocEnd());
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return KeywordLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return SubStmt->getLocEnd();}
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == DefaultStmtClass;
}
@@ -746,6 +757,11 @@ public:
child_range children() { return child_range(&SubStmt, &SubStmt+1); }
};
+inline SourceLocation SwitchCase::getLocEnd() const {
+ if (const CaseStmt *CS = dyn_cast<CaseStmt>(this))
+ return CS->getLocEnd();
+ return cast<DefaultStmt>(this)->getLocEnd();
+}
/// LabelStmt - Represents a label, which has a substatement. For example:
/// foo: return;
@@ -771,9 +787,9 @@ public:
void setIdentLoc(SourceLocation L) { IdentLoc = L; }
void setSubStmt(Stmt *SS) { SubStmt = SS; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(IdentLoc, SubStmt->getLocEnd());
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return IdentLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return SubStmt->getLocEnd();}
+
child_range children() { return child_range(&SubStmt, &SubStmt+1); }
static bool classof(const Stmt *T) {
@@ -819,9 +835,9 @@ public:
Stmt *getSubStmt() { return SubStmt; }
const Stmt *getSubStmt() const { return SubStmt; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(AttrLoc, SubStmt->getLocEnd());
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return AttrLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return SubStmt->getLocEnd();}
+
child_range children() { return child_range(&SubStmt, &SubStmt + 1); }
static bool classof(const Stmt *T) {
@@ -879,11 +895,12 @@ public:
SourceLocation getElseLoc() const { return ElseLoc; }
void setElseLoc(SourceLocation L) { ElseLoc = L; }
- SourceRange getSourceRange() const LLVM_READONLY {
+ SourceLocation getLocStart() const LLVM_READONLY { return IfLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY {
if (SubExprs[ELSE])
- return SourceRange(IfLoc, SubExprs[ELSE]->getLocEnd());
+ return SubExprs[ELSE]->getLocEnd();
else
- return SourceRange(IfLoc, SubExprs[THEN]->getLocEnd());
+ return SubExprs[THEN]->getLocEnd();
}
// Iterators over subexpressions. The iterators will include iterating
@@ -977,9 +994,11 @@ public:
return (bool) AllEnumCasesCovered;
}
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(SwitchLoc, SubExprs[BODY]->getLocEnd());
+ SourceLocation getLocStart() const LLVM_READONLY { return SwitchLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ return SubExprs[BODY]->getLocEnd();
}
+
// Iterators
child_range children() {
return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR);
@@ -1031,9 +1050,11 @@ public:
SourceLocation getWhileLoc() const { return WhileLoc; }
void setWhileLoc(SourceLocation L) { WhileLoc = L; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(WhileLoc, SubExprs[BODY]->getLocEnd());
+ SourceLocation getLocStart() const LLVM_READONLY { return WhileLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ return SubExprs[BODY]->getLocEnd();
}
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == WhileStmtClass;
}
@@ -1079,9 +1100,9 @@ public:
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(DoLoc, RParenLoc);
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return DoLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == DoStmtClass;
}
@@ -1150,9 +1171,11 @@ public:
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd());
+ SourceLocation getLocStart() const LLVM_READONLY { return ForLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ return SubExprs[BODY]->getLocEnd();
}
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == ForStmtClass;
}
@@ -1184,9 +1207,9 @@ public:
SourceLocation getLabelLoc() const { return LabelLoc; }
void setLabelLoc(SourceLocation L) { LabelLoc = L; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(GotoLoc, LabelLoc);
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return GotoLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return LabelLoc; }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == GotoStmtClass;
}
@@ -1227,9 +1250,8 @@ public:
return const_cast<IndirectGotoStmt*>(this)->getConstantTarget();
}
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(GotoLoc, Target->getLocEnd());
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return GotoLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return Target->getLocEnd(); }
static bool classof(const Stmt *T) {
return T->getStmtClass() == IndirectGotoStmtClass;
@@ -1253,9 +1275,8 @@ public:
SourceLocation getContinueLoc() const { return ContinueLoc; }
void setContinueLoc(SourceLocation L) { ContinueLoc = L; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(ContinueLoc);
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return ContinueLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return ContinueLoc; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == ContinueStmtClass;
@@ -1278,7 +1299,8 @@ public:
SourceLocation getBreakLoc() const { return BreakLoc; }
void setBreakLoc(SourceLocation L) { BreakLoc = L; }
- SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(BreakLoc); }
+ SourceLocation getLocStart() const LLVM_READONLY { return BreakLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return BreakLoc; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == BreakStmtClass;
@@ -1329,7 +1351,10 @@ public:
const VarDecl *getNRVOCandidate() const { return NRVOCandidate; }
void setNRVOCandidate(const VarDecl *Var) { NRVOCandidate = Var; }
- SourceRange getSourceRange() const LLVM_READONLY;
+ SourceLocation getLocStart() const LLVM_READONLY { return RetLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ return RetExpr ? RetExpr->getLocEnd() : RetLoc;
+ }
static bool classof(const Stmt *T) {
return T->getStmtClass() == ReturnStmtClass;
@@ -1381,7 +1406,8 @@ public:
bool isVolatile() const { return IsVolatile; }
void setVolatile(bool V) { IsVolatile = V; }
- SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(); }
+ SourceLocation getLocStart() const LLVM_READONLY { return SourceLocation(); }
+ SourceLocation getLocEnd() const LLVM_READONLY { return SourceLocation(); }
//===--- Asm String Analysis ---===//
@@ -1636,9 +1662,8 @@ public:
return Clobbers[i];
}
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(AsmLoc, RParenLoc);
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return AsmLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return RParenLoc; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == GCCAsmStmtClass;
@@ -1648,7 +1673,7 @@ public:
/// This represents a Microsoft inline-assembly statement extension.
///
class MSAsmStmt : public AsmStmt {
- SourceLocation AsmLoc, LBraceLoc, EndLoc;
+ SourceLocation LBraceLoc, EndLoc;
std::string AsmStr;
unsigned NumAsmToks;
@@ -1717,9 +1742,9 @@ public:
StringRef getClobber(unsigned i) const { return Clobbers[i]; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(AsmLoc, EndLoc);
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return AsmLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return EndLoc; }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == MSAsmStmtClass;
}
@@ -1748,9 +1773,9 @@ public:
SourceLocation ExceptLoc,
Expr *FilterExpr,
Stmt *Block);
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(getExceptLoc(), getEndLoc());
- }
+
+ SourceLocation getLocStart() const LLVM_READONLY { return getExceptLoc(); }
+ SourceLocation getLocEnd() const LLVM_READONLY { return getEndLoc(); }
SourceLocation getExceptLoc() const { return Loc; }
SourceLocation getEndLoc() const { return getBlock()->getLocEnd(); }
@@ -1760,7 +1785,7 @@ public:
}
CompoundStmt *getBlock() const {
- return llvm::cast<CompoundStmt>(Children[BLOCK]);
+ return cast<CompoundStmt>(Children[BLOCK]);
}
child_range children() {
@@ -1789,14 +1814,13 @@ public:
SourceLocation FinallyLoc,
Stmt *Block);
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(getFinallyLoc(), getEndLoc());
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return getFinallyLoc(); }
+ SourceLocation getLocEnd() const LLVM_READONLY { return getEndLoc(); }
SourceLocation getFinallyLoc() const { return Loc; }
SourceLocation getEndLoc() const { return Block->getLocEnd(); }
- CompoundStmt *getBlock() const { return llvm::cast<CompoundStmt>(Block); }
+ CompoundStmt *getBlock() const { return cast<CompoundStmt>(Block); }
child_range children() {
return child_range(&Block,&Block+1);
@@ -1831,9 +1855,8 @@ public:
Stmt *TryBlock,
Stmt *Handler);
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(getTryLoc(), getEndLoc());
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return getTryLoc(); }
+ SourceLocation getLocEnd() const LLVM_READONLY { return getEndLoc(); }
SourceLocation getTryLoc() const { return TryLoc; }
SourceLocation getEndLoc() const { return Children[HANDLER]->getLocEnd(); }
@@ -1841,7 +1864,7 @@ public:
bool getIsCXXTry() const { return IsCXXTry; }
CompoundStmt* getTryBlock() const {
- return llvm::cast<CompoundStmt>(Children[TRY]);
+ return cast<CompoundStmt>(Children[TRY]);
}
Stmt *getHandler() const { return Children[HANDLER]; }
diff --git a/include/clang/AST/StmtCXX.h b/include/clang/AST/StmtCXX.h
index f4e4dcd..0112bef 100644
--- a/include/clang/AST/StmtCXX.h
+++ b/include/clang/AST/StmtCXX.h
@@ -14,6 +14,9 @@
#ifndef LLVM_CLANG_AST_STMTCXX_H
#define LLVM_CLANG_AST_STMTCXX_H
+#include "clang/AST/DeclarationName.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/Stmt.h"
#include "llvm/Support/Compiler.h"
@@ -38,8 +41,9 @@ public:
CXXCatchStmt(EmptyShell Empty)
: Stmt(CXXCatchStmtClass), ExceptionDecl(0), HandlerBlock(0) {}
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(CatchLoc, HandlerBlock->getLocEnd());
+ SourceLocation getLocStart() const LLVM_READONLY { return CatchLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ return HandlerBlock->getLocEnd();
}
SourceLocation getCatchLoc() const { return CatchLoc; }
@@ -62,8 +66,7 @@ class CXXTryStmt : public Stmt {
SourceLocation TryLoc;
unsigned NumHandlers;
- CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock, Stmt **handlers,
- unsigned numHandlers);
+ CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock, ArrayRef<Stmt*> handlers);
CXXTryStmt(EmptyShell Empty, unsigned numHandlers)
: Stmt(CXXTryStmtClass), NumHandlers(numHandlers) { }
@@ -77,15 +80,13 @@ class CXXTryStmt : public Stmt {
public:
static CXXTryStmt *Create(ASTContext &C, SourceLocation tryLoc,
- Stmt *tryBlock, Stmt **handlers,
- unsigned numHandlers);
+ Stmt *tryBlock, ArrayRef<Stmt*> handlers);
static CXXTryStmt *Create(ASTContext &C, EmptyShell Empty,
unsigned numHandlers);
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(getTryLoc(), getEndLoc());
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return getTryLoc(); }
+ SourceLocation getLocEnd() const LLVM_READONLY { return getEndLoc(); }
SourceLocation getTryLoc() const { return TryLoc; }
SourceLocation getEndLoc() const {
@@ -93,18 +94,18 @@ public:
}
CompoundStmt *getTryBlock() {
- return llvm::cast<CompoundStmt>(getStmts()[0]);
+ return cast<CompoundStmt>(getStmts()[0]);
}
const CompoundStmt *getTryBlock() const {
- return llvm::cast<CompoundStmt>(getStmts()[0]);
+ return cast<CompoundStmt>(getStmts()[0]);
}
unsigned getNumHandlers() const { return NumHandlers; }
CXXCatchStmt *getHandler(unsigned i) {
- return llvm::cast<CXXCatchStmt>(getStmts()[i + 1]);
+ return cast<CXXCatchStmt>(getStmts()[i + 1]);
}
const CXXCatchStmt *getHandler(unsigned i) const {
- return llvm::cast<CXXCatchStmt>(getStmts()[i + 1]);
+ return cast<CXXCatchStmt>(getStmts()[i + 1]);
}
static bool classof(const Stmt *T) {
@@ -188,9 +189,11 @@ public:
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd());
+ SourceLocation getLocStart() const LLVM_READONLY { return ForLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ return SubExprs[BODY]->getLocEnd();
}
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXForRangeStmtClass;
}
@@ -272,9 +275,8 @@ public:
return reinterpret_cast<CompoundStmt *>(SubStmt);
}
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(KeywordLoc, SubStmt->getLocEnd());
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return KeywordLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return SubStmt->getLocEnd();}
child_range children() {
return child_range(&SubStmt, &SubStmt+1);
diff --git a/include/clang/AST/StmtGraphTraits.h b/include/clang/AST/StmtGraphTraits.h
index 25d0152..a3e9e1e 100644
--- a/include/clang/AST/StmtGraphTraits.h
+++ b/include/clang/AST/StmtGraphTraits.h
@@ -16,8 +16,8 @@
#define LLVM_CLANG_AST_STMT_GRAPHTRAITS_H
#include "clang/AST/Stmt.h"
-#include "llvm/ADT/GraphTraits.h"
#include "llvm/ADT/DepthFirstIterator.h"
+#include "llvm/ADT/GraphTraits.h"
namespace llvm {
diff --git a/include/clang/AST/StmtObjC.h b/include/clang/AST/StmtObjC.h
index d7a73a7..e97c1a5 100644
--- a/include/clang/AST/StmtObjC.h
+++ b/include/clang/AST/StmtObjC.h
@@ -55,9 +55,11 @@ public:
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd());
+ SourceLocation getLocStart() const LLVM_READONLY { return ForLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ return SubExprs[BODY]->getLocEnd();
}
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCForCollectionStmtClass;
}
@@ -102,9 +104,8 @@ public:
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(AtCatchLoc, Body->getLocEnd());
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return AtCatchLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return Body->getLocEnd(); }
bool hasEllipsis() const { return getCatchParamDecl() == 0; }
@@ -131,8 +132,9 @@ public:
Stmt *getFinallyBody() { return AtFinallyStmt; }
void setFinallyBody(Stmt *S) { AtFinallyStmt = S; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(AtFinallyLoc, AtFinallyStmt->getLocEnd());
+ SourceLocation getLocStart() const LLVM_READONLY { return AtFinallyLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ return AtFinallyStmt->getLocEnd();
}
SourceLocation getAtFinallyLoc() const { return AtFinallyLoc; }
@@ -236,7 +238,8 @@ public:
getStmts()[1 + NumCatchStmts] = S;
}
- SourceRange getSourceRange() const LLVM_READONLY;
+ SourceLocation getLocStart() const LLVM_READONLY { return AtTryLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY;
static bool classof(const Stmt *T) {
return T->getStmtClass() == ObjCAtTryStmtClass;
@@ -292,8 +295,9 @@ public:
}
void setSynchExpr(Stmt *S) { SubStmts[SYNC_EXPR] = S; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(AtSynchronizedLoc, getSynchBody()->getLocEnd());
+ SourceLocation getLocStart() const LLVM_READONLY { return AtSynchronizedLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ return getSynchBody()->getLocEnd();
}
static bool classof(const Stmt *T) {
@@ -324,11 +328,9 @@ public:
SourceLocation getThrowLoc() { return AtThrowLoc; }
void setThrowLoc(SourceLocation Loc) { AtThrowLoc = Loc; }
- SourceRange getSourceRange() const LLVM_READONLY {
- if (Throw)
- return SourceRange(AtThrowLoc, Throw->getLocEnd());
- else
- return SourceRange(AtThrowLoc);
+ SourceLocation getLocStart() const LLVM_READONLY { return AtThrowLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ return Throw ? Throw->getLocEnd() : AtThrowLoc;
}
static bool classof(const Stmt *T) {
@@ -355,9 +357,8 @@ public:
Stmt *getSubStmt() { return SubStmt; }
void setSubStmt(Stmt *S) { SubStmt = S; }
- SourceRange getSourceRange() const LLVM_READONLY {
- return SourceRange(AtLoc, SubStmt->getLocEnd());
- }
+ SourceLocation getLocStart() const LLVM_READONLY { return AtLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return SubStmt->getLocEnd();}
SourceLocation getAtLoc() const { return AtLoc; }
void setAtLoc(SourceLocation Loc) { AtLoc = Loc; }
diff --git a/include/clang/AST/TemplateBase.h b/include/clang/AST/TemplateBase.h
index 1c0abde..70b934f 100644
--- a/include/clang/AST/TemplateBase.h
+++ b/include/clang/AST/TemplateBase.h
@@ -15,8 +15,8 @@
#ifndef LLVM_CLANG_AST_TEMPLATEBASE_H
#define LLVM_CLANG_AST_TEMPLATEBASE_H
-#include "clang/AST/Type.h"
#include "clang/AST/TemplateName.h"
+#include "clang/AST/Type.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Compiler.h"
@@ -72,35 +72,39 @@ private:
/// \brief The kind of template argument we're storing.
unsigned Kind;
+ struct DA {
+ ValueDecl *D;
+ bool ForRefParam;
+ };
+ struct I {
+ // We store a decomposed APSInt with the data allocated by ASTContext if
+ // BitWidth > 64. The memory may be shared between multiple
+ // TemplateArgument instances.
+ union {
+ uint64_t VAL; ///< Used to store the <= 64 bits integer value.
+ const uint64_t *pVal; ///< Used to store the >64 bits integer value.
+ };
+ unsigned BitWidth : 31;
+ unsigned IsUnsigned : 1;
+ void *Type;
+ };
+ struct A {
+ const TemplateArgument *Args;
+ unsigned NumArgs;
+ };
+ struct TA {
+ void *Name;
+ unsigned NumExpansions;
+ };
union {
+ struct DA DeclArg;
+ struct I Integer;
+ struct A Args;
+ struct TA TemplateArg;
uintptr_t TypeOrValue;
- struct {
- ValueDecl *D;
- bool ForRefParam;
- } DeclArg;
- struct {
- // We store a decomposed APSInt with the data allocated by ASTContext if
- // BitWidth > 64. The memory may be shared between multiple
- // TemplateArgument instances.
- union {
- uint64_t VAL; ///< Used to store the <= 64 bits integer value.
- const uint64_t *pVal; ///< Used to store the >64 bits integer value.
- };
- unsigned BitWidth : 31;
- unsigned IsUnsigned : 1;
- void *Type;
- } Integer;
- struct {
- const TemplateArgument *Args;
- unsigned NumArgs;
- } Args;
- struct {
- void *Name;
- unsigned NumExpansions;
- } TemplateArg;
};
- TemplateArgument(TemplateName, bool); // DO NOT USE
+ TemplateArgument(TemplateName, bool) LLVM_DELETED_FUNCTION;
public:
/// \brief Construct an empty, invalid template argument.
@@ -158,7 +162,7 @@ public:
///
/// \param NumExpansions The number of expansions that will be generated by
/// instantiating
- TemplateArgument(TemplateName Name, llvm::Optional<unsigned> NumExpansions)
+ TemplateArgument(TemplateName Name, Optional<unsigned> NumExpansions)
: Kind(TemplateExpansion)
{
TemplateArg.Name = Name.getAsVoidPointer();
@@ -261,7 +265,7 @@ public:
/// \brief Retrieve the number of expansions that a template template argument
/// expansion will produce, if known.
- llvm::Optional<unsigned> getNumTemplateExpansions() const;
+ Optional<unsigned> getNumTemplateExpansions() const;
/// \brief Retrieve the template argument as an integral value.
// FIXME: Provide a way to read the integral data without copying the value.
@@ -317,6 +321,12 @@ public:
return Args.NumArgs;
}
+ /// \brief Return the array of arguments in this template argument pack.
+ llvm::ArrayRef<TemplateArgument> getPackAsArray() const {
+ assert(Kind == Pack);
+ return llvm::ArrayRef<TemplateArgument>(Args.Args, Args.NumArgs);
+ }
+
/// \brief Determines whether two template arguments are superficially the
/// same.
bool structurallyEquals(const TemplateArgument &Other) const;
@@ -335,17 +345,20 @@ public:
/// Location information for a TemplateArgument.
struct TemplateArgumentLocInfo {
private:
+
+ struct T {
+ // FIXME: We'd like to just use the qualifier in the TemplateName,
+ // but template arguments get canonicalized too quickly.
+ NestedNameSpecifier *Qualifier;
+ void *QualifierLocData;
+ unsigned TemplateNameLoc;
+ unsigned EllipsisLoc;
+ };
+
union {
+ struct T Template;
Expr *Expression;
TypeSourceInfo *Declarator;
- struct {
- // FIXME: We'd like to just use the qualifier in the TemplateName,
- // but template arguments get canonicalized too quickly.
- NestedNameSpecifier *Qualifier;
- void *QualifierLocData;
- unsigned TemplateNameLoc;
- unsigned EllipsisLoc;
- } Template;
};
public:
@@ -490,7 +503,7 @@ public:
/// \param NumExpansions Will be set to the number of expansions that will
/// be generated from this pack expansion, if known a priori.
TemplateArgumentLoc getPackExpansionPattern(SourceLocation &Ellipsis,
- llvm::Optional<unsigned> &NumExpansions,
+ Optional<unsigned> &NumExpansions,
ASTContext &Context) const;
};
diff --git a/include/clang/AST/TemplateName.h b/include/clang/AST/TemplateName.h
index 7dc75b1..0b9d4c8 100644
--- a/include/clang/AST/TemplateName.h
+++ b/include/clang/AST/TemplateName.h
@@ -15,9 +15,9 @@
#define LLVM_CLANG_AST_TEMPLATENAME_H
#include "clang/Basic/LLVM.h"
+#include "clang/Basic/OperatorKinds.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/PointerUnion.h"
-#include "clang/Basic/OperatorKinds.h"
namespace clang {
@@ -46,16 +46,17 @@ protected:
SubstTemplateTemplateParmPack
};
- union {
- struct {
- /// \brief A Kind.
- unsigned Kind : 2;
-
- /// \brief The number of stored templates or template arguments,
- /// depending on which subclass we have.
- unsigned Size : 30;
- } Bits;
+ struct BitsTag {
+ /// \brief A Kind.
+ unsigned Kind : 2;
+ /// \brief The number of stored templates or template arguments,
+ /// depending on which subclass we have.
+ unsigned Size : 30;
+ };
+
+ union {
+ struct BitsTag Bits;
void *PointerAlignment;
};
@@ -308,6 +309,9 @@ public:
void print(raw_ostream &OS, const PrintingPolicy &Policy,
bool SuppressNNS = false) const;
+ /// \brief Debugging aid that dumps the template name.
+ void dump(raw_ostream &OS) const;
+
/// \brief Debugging aid that dumps the template name to standard
/// error.
void dump() const;
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 6900a7d..23fa3e8 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -14,24 +14,24 @@
#ifndef LLVM_CLANG_AST_TYPE_H
#define LLVM_CLANG_AST_TYPE_H
+#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/TemplateName.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/ExceptionSpecificationType.h"
#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/LLVM.h"
#include "clang/Basic/Linkage.h"
#include "clang/Basic/PartialDiagnostic.h"
-#include "clang/Basic/Visibility.h"
#include "clang/Basic/Specifiers.h"
-#include "clang/AST/NestedNameSpecifier.h"
-#include "clang/AST/TemplateName.h"
-#include "llvm/Support/type_traits.h"
-#include "llvm/Support/ErrorHandling.h"
+#include "clang/Basic/Visibility.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/Twine.h"
-#include "clang/Basic/LLVM.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/type_traits.h"
namespace clang {
enum {
@@ -784,8 +784,8 @@ public:
/// Executing \c getUnqualifiedType() on the type \c DifferenceType will
/// desugar until we hit the type \c Integer, which has no qualifiers on it.
///
- /// The resulting type might still be qualified if it's an array
- /// type. To strip qualifiers even from within an array type, use
+ /// The resulting type might still be qualified if it's sugar for an array
+ /// type. To strip qualifiers even from within a sugared array type, use
/// ASTContext::getUnqualifiedArrayType.
inline QualType getUnqualifiedType() const;
@@ -795,8 +795,8 @@ public:
/// Like getUnqualifiedType(), but also returns the set of
/// qualifiers that were built up.
///
- /// The resulting type might still be qualified if it's an array
- /// type. To strip qualifiers even from within an array type, use
+ /// The resulting type might still be qualified if it's sugar for an array
+ /// type. To strip qualifiers even from within a sugared array type, use
/// ASTContext::getUnqualifiedArrayType.
inline SplitQualType getSplitUnqualifiedType() const;
@@ -979,10 +979,6 @@ public:
/// type other than void.
bool isCForbiddenLValueType() const;
- /// \brief Determine whether this type has trivial copy/move-assignment
- /// semantics.
- bool hasTrivialAssignment(ASTContext &Context, bool Copying) const;
-
private:
// These methods are implemented in a separate translation unit;
// "static"-ize them to avoid creating temporary QualTypes in the
@@ -1002,14 +998,12 @@ private:
namespace llvm {
/// Implement simplify_type for QualType, so that we can dyn_cast from QualType
/// to a specific Type class.
-template<> struct simplify_type<const ::clang::QualType> {
+template<> struct simplify_type< ::clang::QualType> {
typedef const ::clang::Type *SimpleType;
- static SimpleType getSimplifiedValue(const ::clang::QualType &Val) {
+ static SimpleType getSimplifiedValue(::clang::QualType Val) {
return Val.getTypePtr();
}
};
-template<> struct simplify_type< ::clang::QualType>
- : public simplify_type<const ::clang::QualType> {};
// Teach SmallPtrSet that QualType is "basically a pointer".
template<>
@@ -1195,13 +1189,9 @@ private:
/// (for C++0x variadic templates).
unsigned ContainsUnexpandedParameterPack : 1;
- /// \brief Nonzero if the cache (i.e. the bitfields here starting
- /// with 'Cache') is valid. If so, then this is a
- /// LangOptions::VisibilityMode+1.
- mutable unsigned CacheValidAndVisibility : 2;
-
- /// \brief True if the visibility was set explicitly in the source code.
- mutable unsigned CachedExplicitVisibility : 1;
+ /// \brief True if the cache (i.e. the bitfields here starting with
+ /// 'Cache') is valid.
+ mutable unsigned CacheValid : 1;
/// \brief Linkage of this type.
mutable unsigned CachedLinkage : 2;
@@ -1213,15 +1203,7 @@ private:
mutable unsigned FromAST : 1;
bool isCacheValid() const {
- return (CacheValidAndVisibility != 0);
- }
- Visibility getVisibility() const {
- assert(isCacheValid() && "getting linkage from invalid cache");
- return static_cast<Visibility>(CacheValidAndVisibility-1);
- }
- bool isVisibilityExplicit() const {
- assert(isCacheValid() && "getting linkage from invalid cache");
- return CachedExplicitVisibility;
+ return CacheValid;
}
Linkage getLinkage() const {
assert(isCacheValid() && "getting linkage from invalid cache");
@@ -1278,11 +1260,6 @@ protected:
/// C++ 8.3.5p4: The return type, the parameter type list and the
/// cv-qualifier-seq, [...], are part of the function type.
unsigned TypeQuals : 3;
-
- /// \brief The ref-qualifier associated with a \c FunctionProtoType.
- ///
- /// This is a value of type \c RefQualifierKind.
- unsigned RefQualifier : 2;
};
class ObjCObjectTypeBitfields {
@@ -1382,8 +1359,7 @@ protected:
TypeBits.InstantiationDependent = Dependent || InstantiationDependent;
TypeBits.VariablyModified = VariablyModified;
TypeBits.ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack;
- TypeBits.CacheValidAndVisibility = 0;
- TypeBits.CachedExplicitVisibility = false;
+ TypeBits.CacheValid = false;
TypeBits.CachedLocalOrUnnamed = false;
TypeBits.CachedLinkage = NoLinkage;
TypeBits.FromAST = false;
@@ -1584,6 +1560,20 @@ public:
bool isNullPtrType() const; // C++0x nullptr_t
bool isAtomicType() const; // C11 _Atomic()
+ bool isImage1dT() const; // OpenCL image1d_t
+ bool isImage1dArrayT() const; // OpenCL image1d_array_t
+ bool isImage1dBufferT() const; // OpenCL image1d_buffer_t
+ bool isImage2dT() const; // OpenCL image2d_t
+ bool isImage2dArrayT() const; // OpenCL image2d_array_t
+ bool isImage3dT() const; // OpenCL image3d_t
+
+ bool isImageType() const; // Any OpenCL image type
+
+ bool isSamplerT() const; // OpenCL sampler_t
+ bool isEventT() const; // OpenCL event_t
+
+ bool isOpenCLSpecificType() const; // Any OpenCL specific type
+
/// Determines if this type, which must satisfy
/// isObjCLifetimeType(), is implicitly __unsafe_unretained rather
/// than implicitly __strong.
@@ -1770,16 +1760,21 @@ public:
Linkage getLinkage() const;
/// \brief Determine the visibility of this type.
- Visibility getVisibility() const;
+ Visibility getVisibility() const {
+ return getLinkageAndVisibility().getVisibility();
+ }
/// \brief Return true if the visibility was explicitly set is the code.
- bool isVisibilityExplicit() const;
+ bool isVisibilityExplicit() const {
+ return getLinkageAndVisibility().isVisibilityExplicit();
+ }
/// \brief Determine the linkage and visibility of this type.
- std::pair<Linkage,Visibility> getLinkageAndVisibility() const;
+ LinkageInfo getLinkageAndVisibility() const;
- /// \brief Note that the linkage is no longer known.
- void ClearLinkageCache();
+ /// \brief True if the computed linkage is valid. Used for consistency
+ /// checking. Should always return true.
+ bool isLinkageValid() const;
const char *getTypeClassName() const;
@@ -2097,6 +2092,14 @@ public:
}
};
+/// The inheritance model to use for this member pointer.
+enum MSInheritanceModel {
+ MSIM_Single,
+ MSIM_Multiple,
+ MSIM_Virtual,
+ MSIM_Unspecified
+};
+
/// MemberPointerType - C++ 8.3.3 - Pointers to members
///
class MemberPointerType : public Type, public llvm::FoldingSetNode {
@@ -2132,6 +2135,10 @@ public:
return !PointeeType->isFunctionProtoType();
}
+ /// Returns the number of pointer and integer slots used to represent this
+ /// member pointer in the MS C++ ABI.
+ std::pair<unsigned, unsigned> getMSMemberPointerSlots() const;
+
const Type *getClass() const { return Class; }
bool isSugared() const { return false; }
@@ -2686,8 +2693,7 @@ class FunctionType : public Type {
protected:
FunctionType(TypeClass tc, QualType res,
- unsigned typeQuals, RefQualifierKind RefQualifier,
- QualType Canonical, bool Dependent,
+ unsigned typeQuals, QualType Canonical, bool Dependent,
bool InstantiationDependent,
bool VariablyModified, bool ContainsUnexpandedParameterPack,
ExtInfo Info)
@@ -2696,20 +2702,18 @@ protected:
ResultType(res) {
FunctionTypeBits.ExtInfo = Info.Bits;
FunctionTypeBits.TypeQuals = typeQuals;
- FunctionTypeBits.RefQualifier = static_cast<unsigned>(RefQualifier);
}
unsigned getTypeQuals() const { return FunctionTypeBits.TypeQuals; }
- RefQualifierKind getRefQualifier() const {
- return static_cast<RefQualifierKind>(FunctionTypeBits.RefQualifier);
- }
-
public:
QualType getResultType() const { return ResultType; }
bool getHasRegParm() const { return getExtInfo().getHasRegParm(); }
unsigned getRegParmType() const { return getExtInfo().getRegParm(); }
+ /// \brief Determine whether this function type includes the GNU noreturn
+ /// attribute. The C++11 [[noreturn]] attribute does not affect the function
+ /// type.
bool getNoReturnAttr() const { return getExtInfo().getNoReturn(); }
CallingConv getCallConv() const { return getExtInfo().getCC(); }
ExtInfo getExtInfo() const { return ExtInfo(FunctionTypeBits.ExtInfo); }
@@ -2735,7 +2739,7 @@ public:
/// no information available about its arguments.
class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode {
FunctionNoProtoType(QualType Result, QualType Canonical, ExtInfo Info)
- : FunctionType(FunctionNoProto, Result, 0, RQ_None, Canonical,
+ : FunctionType(FunctionNoProto, Result, 0, Canonical,
/*Dependent=*/false, /*InstantiationDependent=*/false,
Result->isVariablyModifiedType(),
/*ContainsUnexpandedParameterPack=*/false, Info) {}
@@ -2804,11 +2808,11 @@ private:
return false;
}
- FunctionProtoType(QualType result, const QualType *args, unsigned numArgs,
+ FunctionProtoType(QualType result, ArrayRef<QualType> args,
QualType canonical, const ExtProtoInfo &epi);
/// NumArgs - The number of arguments this function has, not counting '...'.
- unsigned NumArgs : 17;
+ unsigned NumArgs : 15;
/// NumExceptions - The number of types in the exception spec, if any.
unsigned NumExceptions : 9;
@@ -2825,6 +2829,11 @@ private:
/// HasTrailingReturn - Whether this function has a trailing return type.
unsigned HasTrailingReturn : 1;
+ /// \brief The ref-qualifier associated with a \c FunctionProtoType.
+ ///
+ /// This is a value of type \c RefQualifierKind.
+ unsigned RefQualifier : 2;
+
// ArgInfo - There is an variable size array after the class in memory that
// holds the argument types.
@@ -2864,6 +2873,9 @@ public:
assert(i < NumArgs && "Invalid argument number!");
return arg_type_begin()[i];
}
+ ArrayRef<QualType> getArgTypes() const {
+ return ArrayRef<QualType>(arg_type_begin(), arg_type_end());
+ }
ExtProtoInfo getExtProtoInfo() const {
ExtProtoInfo EPI;
@@ -2972,7 +2984,7 @@ public:
/// \brief Retrieve the ref-qualifier associated with this function type.
RefQualifierKind getRefQualifier() const {
- return FunctionType::getRefQualifier();
+ return static_cast<RefQualifierKind>(RefQualifier);
}
typedef const QualType *arg_type_iterator;
@@ -3005,9 +3017,6 @@ public:
bool isSugared() const { return false; }
QualType desugar() const { return QualType(this, 0); }
- // FIXME: Remove the string version.
- void printExceptionSpecification(std::string &S,
- const PrintingPolicy &Policy) const;
void printExceptionSpecification(raw_ostream &OS,
const PrintingPolicy &Policy) const;
@@ -3323,7 +3332,8 @@ public:
attr_stdcall,
attr_thiscall,
attr_pascal,
- attr_pnaclcall
+ attr_pnaclcall,
+ attr_inteloclbicc
};
private:
@@ -3648,21 +3658,6 @@ public:
/// \brief Print a template argument list, including the '<' and '>'
/// enclosing the template arguments.
- // FIXME: remove the string ones.
- static std::string PrintTemplateArgumentList(const TemplateArgument *Args,
- unsigned NumArgs,
- const PrintingPolicy &Policy,
- bool SkipBrackets = false);
-
- static std::string PrintTemplateArgumentList(const TemplateArgumentLoc *Args,
- unsigned NumArgs,
- const PrintingPolicy &Policy);
-
- static std::string PrintTemplateArgumentList(const TemplateArgumentListInfo &,
- const PrintingPolicy &Policy);
-
- /// \brief Print a template argument list, including the '<' and '>'
- /// enclosing the template arguments.
static void PrintTemplateArgumentList(raw_ostream &OS,
const TemplateArgument *Args,
unsigned NumArgs,
@@ -4125,7 +4120,7 @@ class PackExpansionType : public Type, public llvm::FoldingSetNode {
unsigned NumExpansions;
PackExpansionType(QualType Pattern, QualType Canon,
- llvm::Optional<unsigned> NumExpansions)
+ Optional<unsigned> NumExpansions)
: Type(PackExpansion, Canon, /*Dependent=*/Pattern->isDependentType(),
/*InstantiationDependent=*/true,
/*VariableModified=*/Pattern->isVariablyModifiedType(),
@@ -4143,11 +4138,11 @@ public:
/// \brief Retrieve the number of expansions that this pack expansion will
/// generate, if known.
- llvm::Optional<unsigned> getNumExpansions() const {
+ Optional<unsigned> getNumExpansions() const {
if (NumExpansions)
return NumExpansions - 1;
- return llvm::Optional<unsigned>();
+ return None;
}
bool isSugared() const { return false; }
@@ -4158,9 +4153,9 @@ public:
}
static void Profile(llvm::FoldingSetNodeID &ID, QualType Pattern,
- llvm::Optional<unsigned> NumExpansions) {
+ Optional<unsigned> NumExpansions) {
ID.AddPointer(Pattern.getAsOpaquePtr());
- ID.AddBoolean(NumExpansions);
+ ID.AddBoolean(NumExpansions.hasValue());
if (NumExpansions)
ID.AddInteger(*NumExpansions);
}
@@ -4887,6 +4882,49 @@ inline bool Type::isObjCSelType() const {
inline bool Type::isObjCBuiltinType() const {
return isObjCIdType() || isObjCClassType() || isObjCSelType();
}
+
+inline bool Type::isImage1dT() const {
+ return isSpecificBuiltinType(BuiltinType::OCLImage1d);
+}
+
+inline bool Type::isImage1dArrayT() const {
+ return isSpecificBuiltinType(BuiltinType::OCLImage1dArray);
+}
+
+inline bool Type::isImage1dBufferT() const {
+ return isSpecificBuiltinType(BuiltinType::OCLImage1dBuffer);
+}
+
+inline bool Type::isImage2dT() const {
+ return isSpecificBuiltinType(BuiltinType::OCLImage2d);
+}
+
+inline bool Type::isImage2dArrayT() const {
+ return isSpecificBuiltinType(BuiltinType::OCLImage2dArray);
+}
+
+inline bool Type::isImage3dT() const {
+ return isSpecificBuiltinType(BuiltinType::OCLImage3d);
+}
+
+inline bool Type::isSamplerT() const {
+ return isSpecificBuiltinType(BuiltinType::OCLSampler);
+}
+
+inline bool Type::isEventT() const {
+ return isSpecificBuiltinType(BuiltinType::OCLEvent);
+}
+
+inline bool Type::isImageType() const {
+ return isImage3dT() ||
+ isImage2dT() || isImage2dArrayT() ||
+ isImage1dT() || isImage1dArrayT() || isImage1dBufferT();
+}
+
+inline bool Type::isOpenCLSpecificType() const {
+ return isSamplerT() || isEventT() || isImageType();
+}
+
inline bool Type::isTemplateTypeParmType() const {
return isa<TemplateTypeParmType>(CanonicalType);
}
diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h
index 8a04bd8..11cad9b 100644
--- a/include/clang/AST/TypeLoc.h
+++ b/include/clang/AST/TypeLoc.h
@@ -14,9 +14,9 @@
#ifndef LLVM_CLANG_AST_TYPELOC_H
#define LLVM_CLANG_AST_TYPELOC_H
-#include "clang/AST/Type.h"
#include "clang/AST/Decl.h"
#include "clang/AST/TemplateBase.h"
+#include "clang/AST/Type.h"
#include "clang/Basic/Specifiers.h"
#include "llvm/Support/Compiler.h"
@@ -44,6 +44,29 @@ protected:
void *Data;
public:
+ /// \brief Convert to the specified TypeLoc type, asserting that this TypeLoc
+ /// is of the desired type.
+ template<typename T>
+ T castAs() const {
+ assert(T::isKind(*this));
+ T t;
+ TypeLoc& tl = t;
+ tl = *this;
+ return t;
+ }
+
+ /// \brief Convert to the specified TypeLoc type, returning a null TypeLoc if
+ /// this TypeLoc is not of the desired type.
+ template<typename T>
+ T getAs() const {
+ if (!T::isKind(*this))
+ return T();
+ T t;
+ TypeLoc& tl = t;
+ tl = *this;
+ return t;
+ }
+
/// The kinds of TypeLocs. Equivalent to the Type::TypeClass enum,
/// except it also defines a Qualified enum that corresponds to the
/// QualifiedLoc class.
@@ -119,11 +142,7 @@ public:
/// \brief Skips past any qualifiers, if this is qualified.
UnqualTypeLoc getUnqualifiedLoc() const; // implemented in this header
- TypeLoc IgnoreParens() const {
- if (isa<ParenTypeLoc>(this))
- return IgnoreParensImpl(*this);
- return *this;
- }
+ TypeLoc IgnoreParens() const;
/// \brief Initializes this to state that every location in this
/// type is the given location.
@@ -160,6 +179,10 @@ public:
}
private:
+ static bool isKind(const TypeLoc&) {
+ return true;
+ }
+
static void initializeImpl(ASTContext &Context, TypeLoc TL,
SourceLocation Loc);
static TypeLoc getNextTypeLocImpl(TypeLoc TL);
@@ -187,8 +210,10 @@ public:
return (TypeLocClass) getTypePtr()->getTypeClass();
}
- static bool classof(const TypeLoc *TL) {
- return !TL->getType().hasLocalQualifiers();
+private:
+ friend class TypeLoc;
+ static bool isKind(const TypeLoc &TL) {
+ return !TL.getType().hasLocalQualifiers();
}
};
@@ -231,15 +256,17 @@ public:
getFullDataSizeForType(getType().getLocalUnqualifiedType());
}
- static bool classof(const TypeLoc *TL) {
- return TL->getType().hasLocalQualifiers();
+private:
+ friend class TypeLoc;
+ static bool isKind(const TypeLoc &TL) {
+ return TL.getType().hasLocalQualifiers();
}
};
inline UnqualTypeLoc TypeLoc::getUnqualifiedLoc() const {
- if (isa<QualifiedTypeLoc>(this))
- return cast<QualifiedTypeLoc>(this)->getUnqualifiedLoc();
- return cast<UnqualTypeLoc>(*this);
+ if (QualifiedTypeLoc Loc = getAs<QualifiedTypeLoc>())
+ return Loc.getUnqualifiedLoc();
+ return castAs<UnqualTypeLoc>();
}
/// A metaprogramming base class for TypeLoc classes which correspond
@@ -280,24 +307,22 @@ class ConcreteTypeLoc : public Base {
return static_cast<const Derived*>(this);
}
-public:
- unsigned getLocalDataSize() const {
- return sizeof(LocalData) + asDerived()->getExtraLocalDataSize();
- }
- // Give a default implementation that's useful for leaf types.
- unsigned getFullDataSize() const {
- return asDerived()->getLocalDataSize() + getInnerTypeSize();
+ friend class TypeLoc;
+ static bool isKind(const TypeLoc &TL) {
+ return Derived::classofType(TL.getTypePtr());
}
static bool classofType(const Type *Ty) {
return TypeClass::classof(Ty);
}
- static bool classof(const TypeLoc *TL) {
- return Derived::classofType(TL->getTypePtr());
+public:
+ unsigned getLocalDataSize() const {
+ return sizeof(LocalData) + asDerived()->getExtraLocalDataSize();
}
- static bool classof(const UnqualTypeLoc *TL) {
- return Derived::classofType(TL->getTypePtr());
+ // Give a default implementation that's useful for leaf types.
+ unsigned getFullDataSize() const {
+ return asDerived()->getLocalDataSize() + getInnerTypeSize();
}
TypeLoc getNextTypeLoc() const {
@@ -362,18 +387,19 @@ private:
/// information. See the note on ConcreteTypeLoc.
template <class Base, class Derived, class TypeClass>
class InheritingConcreteTypeLoc : public Base {
-public:
+ friend class TypeLoc;
static bool classofType(const Type *Ty) {
return TypeClass::classof(Ty);
}
- static bool classof(const TypeLoc *TL) {
- return Derived::classofType(TL->getTypePtr());
+ static bool isKind(const TypeLoc &TL) {
+ return Derived::classofType(TL.getTypePtr());
}
- static bool classof(const UnqualTypeLoc *TL) {
- return Derived::classofType(TL->getTypePtr());
+ static bool isKind(const UnqualTypeLoc &TL) {
+ return Derived::classofType(TL.getTypePtr());
}
+public:
const TypeClass *getTypePtr() const {
return cast<TypeClass>(Base::getTypePtr());
}
@@ -406,7 +432,9 @@ public:
setNameLoc(Loc);
}
- static bool classof(const TypeLoc *TL);
+private:
+ friend class TypeLoc;
+ static bool isKind(const TypeLoc &TL);
};
@@ -899,6 +927,11 @@ public:
}
};
+inline TypeLoc TypeLoc::IgnoreParens() const {
+ if (ParenTypeLoc::isKind(*this))
+ return IgnoreParensImpl(*this);
+ return *this;
+}
struct PointerLikeLocInfo {
SourceLocation StarLoc;
diff --git a/include/clang/AST/TypeLocVisitor.h b/include/clang/AST/TypeLocVisitor.h
index 50fc439..db5775a 100644
--- a/include/clang/AST/TypeLocVisitor.h
+++ b/include/clang/AST/TypeLocVisitor.h
@@ -21,7 +21,7 @@ namespace clang {
#define DISPATCH(CLASSNAME) \
return static_cast<ImplClass*>(this)-> \
- Visit##CLASSNAME(cast<CLASSNAME>(TyLoc))
+ Visit##CLASSNAME(TyLoc.castAs<CLASSNAME>())
template<typename ImplClass, typename RetTy=void>
class TypeLocVisitor {
diff --git a/include/clang/AST/TypeOrdering.h b/include/clang/AST/TypeOrdering.h
index 7cf0d5e..59b59f5 100644
--- a/include/clang/AST/TypeOrdering.h
+++ b/include/clang/AST/TypeOrdering.h
@@ -16,8 +16,8 @@
#ifndef LLVM_CLANG_TYPE_ORDERING_H
#define LLVM_CLANG_TYPE_ORDERING_H
-#include "clang/AST/Type.h"
#include "clang/AST/CanonicalType.h"
+#include "clang/AST/Type.h"
#include <functional>
namespace clang {
diff --git a/include/clang/AST/UnresolvedSet.h b/include/clang/AST/UnresolvedSet.h
index 9f11ee5..d26065e 100644
--- a/include/clang/AST/UnresolvedSet.h
+++ b/include/clang/AST/UnresolvedSet.h
@@ -15,9 +15,11 @@
#ifndef LLVM_CLANG_AST_UNRESOLVEDSET_H
#define LLVM_CLANG_AST_UNRESOLVEDSET_H
-#include <iterator>
-#include "llvm/ADT/SmallVector.h"
#include "clang/AST/DeclAccessPair.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include <iterator>
namespace clang {
@@ -25,12 +27,13 @@ namespace clang {
/// non-const iterator.
class UnresolvedSetIterator {
private:
- typedef SmallVectorImpl<DeclAccessPair> DeclsTy;
+ typedef llvm::MutableArrayRef<DeclAccessPair> DeclsTy;
typedef DeclsTy::iterator IteratorTy;
IteratorTy ir;
friend class UnresolvedSetImpl;
+ friend class ASTUnresolvedSet;
friend class OverloadExpr;
explicit UnresolvedSetIterator(DeclsTy::iterator ir) : ir(ir) {}
explicit UnresolvedSetIterator(DeclsTy::const_iterator ir) :
@@ -87,7 +90,7 @@ public:
/// UnresolvedSet - A set of unresolved declarations.
class UnresolvedSetImpl {
- typedef UnresolvedSetIterator::DeclsTy DeclsTy;
+ typedef SmallVectorImpl<DeclAccessPair> DeclsTy;
// Don't allow direct construction, and only permit subclassing by
// UnresolvedSet.
diff --git a/include/clang/AST/VTTBuilder.h b/include/clang/AST/VTTBuilder.h
index 6756dd1..f24bb3f 100644
--- a/include/clang/AST/VTTBuilder.h
+++ b/include/clang/AST/VTTBuilder.h
@@ -102,9 +102,6 @@ class VTTBuilder {
bool GenerateDefinition;
/// AddVTablePointer - Add a vtable pointer to the VTT currently being built.
- ///
- /// \param AddressPoints - If the vtable is a construction vtable, this has
- /// the address points for it.
void AddVTablePointer(BaseSubobject Base, uint64_t VTableIndex,
const CXXRecordDecl *VTableClass);
@@ -117,9 +114,6 @@ class VTTBuilder {
///
/// \param BaseIsMorallyVirtual whether the base subobject is a virtual base
/// or a direct or indirect base of a virtual base.
- ///
- /// \param AddressPoints - If the vtable is a construction vtable, this has
- /// the address points for it.
void LayoutSecondaryVirtualPointers(BaseSubobject Base,
bool BaseIsMorallyVirtual,
uint64_t VTableIndex,
@@ -128,9 +122,6 @@ class VTTBuilder {
/// LayoutSecondaryVirtualPointers - Lay out the secondary virtual pointers
/// for the given base subobject.
- ///
- /// \param AddressPoints - If the vtable is a construction vtable, this has
- /// the address points for it.
void LayoutSecondaryVirtualPointers(BaseSubobject Base,
uint64_t VTableIndex);
diff --git a/include/clang/AST/VTableBuilder.h b/include/clang/AST/VTableBuilder.h
index a6aa40b..bcbe875 100644
--- a/include/clang/AST/VTableBuilder.h
+++ b/include/clang/AST/VTableBuilder.h
@@ -215,12 +215,15 @@ private:
/// Address points - Address points for all vtables.
AddressPointsMapTy AddressPoints;
+ bool IsMicrosoftABI;
+
public:
VTableLayout(uint64_t NumVTableComponents,
const VTableComponent *VTableComponents,
uint64_t NumVTableThunks,
const VTableThunkTy *VTableThunks,
- const AddressPointsMapTy &AddressPoints);
+ const AddressPointsMapTy &AddressPoints,
+ bool IsMicrosoftABI);
~VTableLayout();
uint64_t getNumVTableComponents() const {
@@ -252,7 +255,8 @@ public:
"Did not find address point!");
uint64_t AddressPoint = AddressPoints.lookup(Base);
- assert(AddressPoint && "Address point must not be zero!");
+ assert(AddressPoint != 0 || IsMicrosoftABI);
+ (void)IsMicrosoftABI;
return AddressPoint;
}
@@ -271,6 +275,8 @@ public:
typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy;
private:
+ bool IsMicrosoftABI;
+
/// MethodVTableIndices - Contains the index (relative to the vtable address
/// point) where the function pointer for a virtual function is stored.
typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVTableIndicesTy;
@@ -306,10 +312,21 @@ private:
/// given record decl.
void ComputeVTableRelatedInformation(const CXXRecordDecl *RD);
+ /// ErrorUnsupported - Print out an error that the v-table layout code
+ /// doesn't support the particular C++ feature yet.
+ void ErrorUnsupported(StringRef Feature, SourceLocation Location);
+
public:
- VTableContext(ASTContext &Context) : Context(Context) {}
+ VTableContext(ASTContext &Context);
~VTableContext();
+ bool isMicrosoftABI() const {
+ // FIXME: Currently, this method is only used in the VTableContext and
+ // VTableBuilder code which is ABI-specific. Probably we can remove it
+ // when we add a layer of abstraction for vtable generation.
+ return IsMicrosoftABI;
+ }
+
const VTableLayout &getVTableLayout(const CXXRecordDecl *RD) {
ComputeVTableRelatedInformation(RD);
assert(VTableLayouts.count(RD) && "No layout for this record decl!");
diff --git a/include/clang/ASTMatchers/ASTMatchFinder.h b/include/clang/ASTMatchers/ASTMatchFinder.h
index 30b4050..870a39b 100644
--- a/include/clang/ASTMatchers/ASTMatchFinder.h
+++ b/include/clang/ASTMatchers/ASTMatchFinder.h
@@ -56,6 +56,10 @@ namespace ast_matchers {
/// that will trigger the callbacks specified via addMatcher(...) when a match
/// is found.
///
+/// The order of matches is guaranteed to be equivalent to doing a pre-order
+/// traversal on the AST, and applying the matchers in the order in which they
+/// were added to the MatchFinder.
+///
/// See ASTMatchers.h for more information about how to create matchers.
///
/// Not intended to be subclassed.
@@ -130,11 +134,17 @@ public:
/// \brief Creates a clang ASTConsumer that finds all matches.
clang::ASTConsumer *newASTConsumer();
- /// \brief Finds all matches on the given \c Node.
+ /// \brief Calls the registered callbacks on all matches on the given \p Node.
+ ///
+ /// Note that there can be multiple matches on a single node, for
+ /// example when using decl(forEachDescendant(stmt())).
///
/// @{
- void findAll(const Decl &Node, ASTContext &Context);
- void findAll(const Stmt &Node, ASTContext &Context);
+ template <typename T> void match(const T &Node, ASTContext &Context) {
+ match(clang::ast_type_traits::DynTypedNode::create(Node), Context);
+ }
+ void match(const clang::ast_type_traits::DynTypedNode &Node,
+ ASTContext &Context);
/// @}
/// \brief Registers a callback to notify the end of parsing.
@@ -154,6 +164,75 @@ private:
ParsingDoneTestCallback *ParsingDone;
};
+/// \brief Returns the results of matching \p Matcher on \p Node.
+///
+/// Collects the \c BoundNodes of all callback invocations when matching
+/// \p Matcher on \p Node and returns the collected results.
+///
+/// Multiple results occur when using matchers like \c forEachDescendant,
+/// which generate a result for each sub-match.
+///
+/// \see selectFirst
+/// @{
+template <typename MatcherT, typename NodeT>
+SmallVector<BoundNodes, 1>
+match(MatcherT Matcher, const NodeT &Node, ASTContext &Context);
+
+template <typename MatcherT>
+SmallVector<BoundNodes, 1>
+match(MatcherT Matcher, const ast_type_traits::DynTypedNode &Node,
+ ASTContext &Context);
+/// @}
+
+/// \brief Returns the first result of type \c NodeT bound to \p BoundTo.
+///
+/// Returns \c NULL if there is no match, or if the matching node cannot be
+/// casted to \c NodeT.
+///
+/// This is useful in combanation with \c match():
+/// \code
+/// Decl *D = selectFirst<Decl>("id", match(Matcher.bind("id"),
+/// Node, Context));
+/// \endcode
+template <typename NodeT>
+NodeT *
+selectFirst(StringRef BoundTo, const SmallVectorImpl<BoundNodes> &Results) {
+ for (SmallVectorImpl<BoundNodes>::const_iterator I = Results.begin(),
+ E = Results.end();
+ I != E; ++I) {
+ if (NodeT *Node = I->getNodeAs<NodeT>(BoundTo))
+ return Node;
+ }
+ return NULL;
+}
+
+namespace internal {
+class CollectMatchesCallback : public MatchFinder::MatchCallback {
+public:
+ virtual void run(const MatchFinder::MatchResult &Result) {
+ Nodes.push_back(Result.Nodes);
+ }
+ SmallVector<BoundNodes, 1> Nodes;
+};
+}
+
+template <typename MatcherT>
+SmallVector<BoundNodes, 1>
+match(MatcherT Matcher, const ast_type_traits::DynTypedNode &Node,
+ ASTContext &Context) {
+ internal::CollectMatchesCallback Callback;
+ MatchFinder Finder;
+ Finder.addMatcher(Matcher, &Callback);
+ Finder.match(Node, Context);
+ return Callback.Nodes;
+}
+
+template <typename MatcherT, typename NodeT>
+SmallVector<BoundNodes, 1>
+match(MatcherT Matcher, const NodeT &Node, ASTContext &Context) {
+ return match(Matcher, ast_type_traits::DynTypedNode::create(Node), Context);
+}
+
} // end namespace ast_matchers
} // end namespace clang
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h
index a70dd5c..f10addc 100644
--- a/include/clang/ASTMatchers/ASTMatchers.h
+++ b/include/clang/ASTMatchers/ASTMatchers.h
@@ -142,7 +142,7 @@ inline internal::PolymorphicMatcherWithParam0<internal::TrueMatcher> anything()
/// friend X;
/// };
/// \endcode
-const internal::VariadicDynCastAllOfMatcher<Decl, Decl> decl;
+const internal::VariadicAllOfMatcher<Decl> decl;
/// \brief Matches a declaration of anything that could have a name.
///
@@ -192,6 +192,69 @@ const internal::VariadicDynCastAllOfMatcher<
Decl,
ClassTemplateSpecializationDecl> classTemplateSpecializationDecl;
+/// \brief Matches C++ access specifier declarations.
+///
+/// Given
+/// \code
+/// class C {
+/// public:
+/// int a;
+/// };
+/// \endcode
+/// accessSpecDecl()
+/// matches 'public:'
+const internal::VariadicDynCastAllOfMatcher<
+ Decl,
+ AccessSpecDecl> accessSpecDecl;
+
+/// \brief Matches public C++ declarations.
+///
+/// Given
+/// \code
+/// class C {
+/// public: int a;
+/// protected: int b;
+/// private: int c;
+/// };
+/// \endcode
+/// fieldDecl(isPublic())
+/// matches 'int a;'
+AST_MATCHER(Decl, isPublic) {
+ return Node.getAccess() == AS_public;
+}
+
+/// \brief Matches protected C++ declarations.
+///
+/// Given
+/// \code
+/// class C {
+/// public: int a;
+/// protected: int b;
+/// private: int c;
+/// };
+/// \endcode
+/// fieldDecl(isProtected())
+/// matches 'int b;'
+AST_MATCHER(Decl, isProtected) {
+ return Node.getAccess() == AS_protected;
+}
+
+/// \brief Matches private C++ declarations.
+///
+/// Given
+/// \code
+/// class C {
+/// public: int a;
+/// protected: int b;
+/// private: int c;
+/// };
+/// \endcode
+/// fieldDecl(isPrivate())
+/// matches 'int c;'
+AST_MATCHER(Decl, isPrivate) {
+ return Node.getAccess() == AS_private;
+}
+
/// \brief Matches classTemplateSpecializations that have at least one
/// TemplateArgument matching the given InnerMatcher.
///
@@ -453,7 +516,7 @@ const internal::VariadicDynCastAllOfMatcher<
/// \endcode
/// stmt()
/// matches both the compound statement '{ ++a; }' and '++a'.
-const internal::VariadicDynCastAllOfMatcher<Stmt, Stmt> stmt;
+const internal::VariadicAllOfMatcher<Stmt> stmt;
/// \brief Matches declaration statements.
///
@@ -922,6 +985,16 @@ const internal::VariadicDynCastAllOfMatcher<
Stmt,
UserDefinedLiteral> userDefinedLiteral;
+/// \brief Matches compound (i.e. non-scalar) literals
+///
+/// Example match: {1}, (1, 2)
+/// \code
+/// int array[4] = {1}; vector int myvec = (vector int)(1, 2);
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Stmt,
+ CompoundLiteralExpr> compoundLiteralExpr;
+
/// \brief Matches nullptr literal.
const internal::VariadicDynCastAllOfMatcher<
Stmt,
@@ -1090,10 +1163,36 @@ const internal::VariadicDynCastAllOfMatcher<
const internal::VariadicAllOfMatcher<QualType> qualType;
/// \brief Matches \c Types in the clang AST.
-const internal::VariadicDynCastAllOfMatcher<Type, Type> type;
+const internal::VariadicAllOfMatcher<Type> type;
/// \brief Matches \c TypeLocs in the clang AST.
-const internal::VariadicDynCastAllOfMatcher<TypeLoc, TypeLoc> typeLoc;
+const internal::VariadicAllOfMatcher<TypeLoc> typeLoc;
+
+/// \brief Matches if any of the given matchers matches.
+///
+/// Unlike \c anyOf, \c eachOf will generate a match result for each
+/// matching submatcher.
+///
+/// For example, in:
+/// \code
+/// class A { int a; int b; };
+/// \endcode
+/// The matcher:
+/// \code
+/// recordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")),
+/// has(fieldDecl(hasName("b")).bind("v"))))
+/// \endcode
+/// will generate two results binding "v", the first of which binds
+/// the field declaration of \c a, the second the field declaration of
+/// \c b.
+///
+/// Usable as: Any Matcher
+template <typename M1, typename M2>
+internal::PolymorphicMatcherWithParam2<internal::EachOfMatcher, M1, M2>
+eachOf(const M1 &P1, const M2 &P2) {
+ return internal::PolymorphicMatcherWithParam2<internal::EachOfMatcher, M1,
+ M2>(P1, P2);
+}
/// \brief Various overloads for the anyOf matcher.
/// @{
@@ -1139,18 +1238,40 @@ anyOf(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4, const M5 &P5) {
/// \brief Matches if all given matchers match.
///
/// Usable as: Any Matcher
-template<typename M1, typename M2>
+template <typename M1, typename M2>
internal::PolymorphicMatcherWithParam2<internal::AllOfMatcher, M1, M2>
allOf(const M1 &P1, const M2 &P2) {
- return internal::PolymorphicMatcherWithParam2<internal::AllOfMatcher,
- M1, M2>(P1, P2);
+ return internal::PolymorphicMatcherWithParam2<internal::AllOfMatcher, M1, M2>(
+ P1, P2);
}
-template<typename M1, typename M2, typename M3>
-internal::PolymorphicMatcherWithParam2<internal::AllOfMatcher, M1,
+template <typename M1, typename M2, typename M3>
+internal::PolymorphicMatcherWithParam2<
+ internal::AllOfMatcher, M1,
internal::PolymorphicMatcherWithParam2<internal::AllOfMatcher, M2, M3> >
allOf(const M1 &P1, const M2 &P2, const M3 &P3) {
return allOf(P1, allOf(P2, P3));
}
+template <typename M1, typename M2, typename M3, typename M4>
+internal::PolymorphicMatcherWithParam2<
+ internal::AllOfMatcher, M1,
+ internal::PolymorphicMatcherWithParam2<
+ internal::AllOfMatcher, M2, internal::PolymorphicMatcherWithParam2<
+ internal::AllOfMatcher, M3, M4> > >
+allOf(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4) {
+ return allOf(P1, allOf(P2, P3, P4));
+}
+template <typename M1, typename M2, typename M3, typename M4, typename M5>
+internal::PolymorphicMatcherWithParam2<
+ internal::AllOfMatcher, M1,
+ internal::PolymorphicMatcherWithParam2<
+ internal::AllOfMatcher, M2,
+ internal::PolymorphicMatcherWithParam2<
+ internal::AllOfMatcher, M3,
+ internal::PolymorphicMatcherWithParam2<internal::AllOfMatcher, M4,
+ M5> > > >
+allOf(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4, const M5 &P5) {
+ return allOf(P1, allOf(P2, P3, P4, P5));
+}
/// @}
@@ -1198,7 +1319,7 @@ AST_MATCHER_P(UnaryExprOrTypeTraitExpr, ofKind, UnaryExprOrTypeTrait, Kind) {
/// alignof.
inline internal::Matcher<Stmt> alignOfExpr(
const internal::Matcher<UnaryExprOrTypeTraitExpr> &InnerMatcher) {
- return internal::Matcher<Stmt>(unaryExprOrTypeTraitExpr(allOf(
+ return stmt(unaryExprOrTypeTraitExpr(allOf(
ofKind(UETT_AlignOf), InnerMatcher)));
}
@@ -1206,8 +1327,8 @@ inline internal::Matcher<Stmt> alignOfExpr(
/// sizeof.
inline internal::Matcher<Stmt> sizeOfExpr(
const internal::Matcher<UnaryExprOrTypeTraitExpr> &InnerMatcher) {
- return internal::Matcher<Stmt>(unaryExprOrTypeTraitExpr(allOf(
- ofKind(UETT_SizeOf), InnerMatcher)));
+ return stmt(unaryExprOrTypeTraitExpr(
+ allOf(ofKind(UETT_SizeOf), InnerMatcher)));
}
/// \brief Matches NamedDecl nodes that have the specified name.
@@ -1228,8 +1349,8 @@ inline internal::Matcher<Stmt> sizeOfExpr(
AST_MATCHER_P(NamedDecl, hasName, std::string, Name) {
assert(!Name.empty());
const std::string FullNameString = "::" + Node.getQualifiedNameAsString();
- const llvm::StringRef FullName = FullNameString;
- const llvm::StringRef Pattern = Name;
+ const StringRef FullName = FullNameString;
+ const StringRef Pattern = Name;
if (Pattern.startswith("::")) {
return FullName == Pattern;
} else {
@@ -1237,8 +1358,8 @@ AST_MATCHER_P(NamedDecl, hasName, std::string, Name) {
}
}
-/// \brief Matches NamedDecl nodes whose full names partially match the
-/// given RegExp.
+/// \brief Matches NamedDecl nodes whose fully qualified names contain
+/// a substring matched by the given RegExp.
///
/// Supports specifying enclosing namespaces or classes by
/// prefixing the name with '<enclosing>::'. Does not match typedefs
@@ -1263,18 +1384,26 @@ AST_MATCHER_P(NamedDecl, matchesName, std::string, RegExp) {
/// \brief Matches overloaded operator names.
///
/// Matches overloaded operator names specified in strings without the
-/// "operator" prefix, such as "<<", for OverloadedOperatorCall's.
+/// "operator" prefix: e.g. "<<".
///
-/// Example matches a << b
-/// (matcher == operatorCallExpr(hasOverloadedOperatorName("<<")))
+/// Given:
/// \code
-/// a << b;
-/// c && d; // assuming both operator<<
-/// // and operator&& are overloaded somewhere.
+/// class A { int operator*(); };
+/// const A &operator<<(const A &a, const A &b);
+/// A a;
+/// a << a; // <-- This matches
/// \endcode
-AST_MATCHER_P(CXXOperatorCallExpr,
- hasOverloadedOperatorName, std::string, Name) {
- return getOperatorSpelling(Node.getOperator()) == Name;
+///
+/// \c operatorCallExpr(hasOverloadedOperatorName("<<"))) matches the specified
+/// line and \c recordDecl(hasMethod(hasOverloadedOperatorName("*"))) matches
+/// the declaration of \c A.
+///
+/// Usable as: Matcher<CXXOperatorCallExpr>, Matcher<CXXMethodDecl>
+inline internal::PolymorphicMatcherWithParam1<
+ internal::HasOverloadedOperatorNameMatcher, StringRef>
+hasOverloadedOperatorName(const StringRef Name) {
+ return internal::PolymorphicMatcherWithParam1<
+ internal::HasOverloadedOperatorNameMatcher, StringRef>(Name);
}
/// \brief Matches C++ classes that are directly or indirectly derived from
@@ -1324,6 +1453,27 @@ inline internal::Matcher<CXXRecordDecl> isSameOrDerivedFrom(
return isSameOrDerivedFrom(hasName(BaseName));
}
+/// \brief Matches the first method of a class or struct that satisfies \c
+/// InnerMatcher.
+///
+/// Given:
+/// \code
+/// class A { void func(); };
+/// class B { void member(); };
+/// \code
+///
+/// \c recordDecl(hasMethod(hasName("func"))) matches the declaration of \c A
+/// but not \c B.
+AST_MATCHER_P(CXXRecordDecl, hasMethod, internal::Matcher<CXXMethodDecl>,
+ InnerMatcher) {
+ for (CXXRecordDecl::method_iterator I = Node.method_begin(),
+ E = Node.method_end();
+ I != E; ++I)
+ if (InnerMatcher.matches(**I, Finder, Builder))
+ return true;
+ return false;
+}
+
/// \brief Matches AST nodes that have child AST nodes that match the
/// provided matcher.
///
@@ -1424,6 +1574,29 @@ forEachDescendant(
DescendantT>(DescendantMatcher);
}
+/// \brief Matches if the node or any descendant matches.
+///
+/// Generates results for each match.
+///
+/// For example, in:
+/// \code
+/// class A { class B {}; class C {}; };
+/// \endcode
+/// The matcher:
+/// \code
+/// recordDecl(hasName("::A"), findAll(recordDecl(isDefinition()).bind("m")))
+/// \endcode
+/// will generate results for \c A, \c B and \c C.
+///
+/// Usable as: Any Matcher
+template <typename T>
+internal::PolymorphicMatcherWithParam2<
+ internal::EachOfMatcher, internal::Matcher<T>,
+ internal::ArgumentAdaptingMatcher<internal::ForEachDescendantMatcher, T> >
+findAll(const internal::Matcher<T> &Matcher) {
+ return eachOf(Matcher, forEachDescendant(Matcher));
+}
+
/// \brief Matches AST nodes that have a parent that matches the provided
/// matcher.
///
@@ -1480,8 +1653,13 @@ unless(const M &InnerMatcher) {
/// \brief Matches a type if the declaration of the type matches the given
/// matcher.
///
+/// In addition to being usable as Matcher<TypedefType>, also usable as
+/// Matcher<T> for any T supporting the getDecl() member function. e.g. various
+/// subtypes of clang::Type.
+///
/// Usable as: Matcher<QualType>, Matcher<CallExpr>, Matcher<CXXConstructExpr>,
-/// Matcher<MemberExpr>
+/// Matcher<MemberExpr>, Matcher<TypedefType>,
+/// Matcher<TemplateSpecializationType>
inline internal::PolymorphicMatcherWithParam1< internal::HasDeclarationMatcher,
internal::Matcher<Decl> >
hasDeclaration(const internal::Matcher<Decl> &InnerMatcher) {
@@ -1501,9 +1679,8 @@ inline internal::PolymorphicMatcherWithParam1< internal::HasDeclarationMatcher,
/// FIXME: Overload to allow directly matching types?
AST_MATCHER_P(CXXMemberCallExpr, on, internal::Matcher<Expr>,
InnerMatcher) {
- const Expr *ExprNode = const_cast<CXXMemberCallExpr&>(Node)
- .getImplicitObjectArgument()
- ->IgnoreParenImpCasts();
+ const Expr *ExprNode = Node.getImplicitObjectArgument()
+ ->IgnoreParenImpCasts();
return (ExprNode != NULL &&
InnerMatcher.matches(*ExprNode, Finder, Builder));
}
@@ -1541,7 +1718,7 @@ AST_MATCHER_P(CallExpr, callee, internal::Matcher<Stmt>,
/// \endcode
inline internal::Matcher<CallExpr> callee(
const internal::Matcher<Decl> &InnerMatcher) {
- return internal::Matcher<CallExpr>(hasDeclaration(InnerMatcher));
+ return callExpr(hasDeclaration(InnerMatcher));
}
/// \brief Matches if the expression's or declaration's type matches a type
@@ -1579,11 +1756,10 @@ AST_POLYMORPHIC_MATCHER_P(hasType, internal::Matcher<QualType>,
///
/// Usable as: Matcher<Expr>, Matcher<ValueDecl>
inline internal::PolymorphicMatcherWithParam1<
- internal::matcher_hasTypeMatcher,
+ internal::matcher_hasType0Matcher,
internal::Matcher<QualType> >
hasType(const internal::Matcher<Decl> &InnerMatcher) {
- return hasType(internal::Matcher<QualType>(
- hasDeclaration(InnerMatcher)));
+ return hasType(qualType(hasDeclaration(InnerMatcher)));
}
/// \brief Matches if the matched type is represented by the given string.
@@ -1618,8 +1794,7 @@ AST_MATCHER_P(
/// \brief Overloaded to match the pointee type's declaration.
inline internal::Matcher<QualType> pointsTo(
const internal::Matcher<Decl> &InnerMatcher) {
- return pointsTo(internal::Matcher<QualType>(
- hasDeclaration(InnerMatcher)));
+ return pointsTo(qualType(hasDeclaration(InnerMatcher)));
}
/// \brief Matches if the matched type is a reference type and the referenced
@@ -1640,17 +1815,32 @@ AST_MATCHER_P(QualType, references, internal::Matcher<QualType>,
InnerMatcher.matches(Node->getPointeeType(), Finder, Builder));
}
+/// \brief Matches QualTypes whose canonical type matches InnerMatcher.
+///
+/// Given:
+/// \code
+/// typedef int &int_ref;
+/// int a;
+/// int_ref b = a;
+/// \code
+///
+/// \c varDecl(hasType(qualType(referenceType()))))) will not match the
+/// declaration of b but \c
+/// varDecl(hasType(qualType(hasCanonicalType(referenceType())))))) does.
+AST_MATCHER_P(QualType, hasCanonicalType, internal::Matcher<QualType>,
+ InnerMatcher) {
+ return InnerMatcher.matches(Node.getCanonicalType(), Finder, Builder);
+}
+
/// \brief Overloaded to match the referenced type's declaration.
inline internal::Matcher<QualType> references(
const internal::Matcher<Decl> &InnerMatcher) {
- return references(internal::Matcher<QualType>(
- hasDeclaration(InnerMatcher)));
+ return references(qualType(hasDeclaration(InnerMatcher)));
}
AST_MATCHER_P(CXXMemberCallExpr, onImplicitObjectArgument,
internal::Matcher<Expr>, InnerMatcher) {
- const Expr *ExprNode =
- const_cast<CXXMemberCallExpr&>(Node).getImplicitObjectArgument();
+ const Expr *ExprNode = Node.getImplicitObjectArgument();
return (ExprNode != NULL &&
InnerMatcher.matches(*ExprNode, Finder, Builder));
}
@@ -1705,8 +1895,7 @@ AST_MATCHER_P(DeclRefExpr, to, internal::Matcher<Decl>,
AST_MATCHER_P(DeclRefExpr, throughUsingDecl,
internal::Matcher<UsingShadowDecl>, InnerMatcher) {
const NamedDecl *FoundDecl = Node.getFoundDecl();
- if (const UsingShadowDecl *UsingDecl =
- llvm::dyn_cast<UsingShadowDecl>(FoundDecl))
+ if (const UsingShadowDecl *UsingDecl = dyn_cast<UsingShadowDecl>(FoundDecl))
return InnerMatcher.matches(*UsingDecl, Finder, Builder);
return false;
}
@@ -1974,6 +2163,19 @@ AST_MATCHER_P(FunctionDecl, hasAnyParameter,
return false;
}
+/// \brief Matches \c FunctionDecls that have a specific parameter count.
+///
+/// Given
+/// \code
+/// void f(int i) {}
+/// void g(int i, int j) {}
+/// \endcode
+/// functionDecl(parameterCountIs(2))
+/// matches g(int i, int j) {}
+AST_MATCHER_P(FunctionDecl, parameterCountIs, unsigned, N) {
+ return Node.getNumParams() == N;
+}
+
/// \brief Matches the return type of a function declaration.
///
/// Given:
@@ -2279,10 +2481,13 @@ AST_MATCHER_P(ConditionalOperator, hasFalseExpression,
/// \endcode
///
/// Usable as: Matcher<TagDecl>, Matcher<VarDecl>, Matcher<FunctionDecl>
-inline internal::PolymorphicMatcherWithParam0<internal::IsDefinitionMatcher>
-isDefinition() {
- return internal::PolymorphicMatcherWithParam0<
- internal::IsDefinitionMatcher>();
+AST_POLYMORPHIC_MATCHER(isDefinition) {
+ TOOLING_COMPILE_ASSERT(
+ (llvm::is_base_of<TagDecl, NodeType>::value) ||
+ (llvm::is_base_of<VarDecl, NodeType>::value) ||
+ (llvm::is_base_of<FunctionDecl, NodeType>::value),
+ is_definition_requires_isThisDeclarationADefinition_method);
+ return Node.isThisDeclarationADefinition();
}
/// \brief Matches the class declaration that the given method declaration
@@ -2324,8 +2529,8 @@ AST_MATCHER_P(CXXMethodDecl, ofClass,
/// \endcode
/// memberExpr(isArrow())
/// matches this->x, x, y.x, a, this->b
-inline internal::Matcher<MemberExpr> isArrow() {
- return makeMatcher(new internal::IsArrowMatcher());
+AST_MATCHER(MemberExpr, isArrow) {
+ return Node.isArrow();
}
/// \brief Matches QualType nodes that are of integer type.
@@ -2357,8 +2562,25 @@ AST_MATCHER(QualType, isInteger) {
/// 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 *".
-inline internal::Matcher<QualType> isConstQualified() {
- return makeMatcher(new internal::IsConstQualifiedMatcher());
+AST_MATCHER(QualType, isConstQualified) {
+ return Node.isConstQualified();
+}
+
+/// \brief Matches QualType nodes that have local CV-qualifiers attached to
+/// the node, not hidden within a typedef.
+///
+/// Given
+/// \code
+/// typedef const int const_int;
+/// const_int i;
+/// int *const j;
+/// int *volatile k;
+/// int m;
+/// \endcode
+/// \c varDecl(hasType(hasLocalQualifiers())) matches only \c j and \c k.
+/// \c i is const-qualified but the qualifier is not local.
+AST_MATCHER(QualType, hasLocalQualifiers) {
+ return Node.hasLocalQualifiers();
}
/// \brief Matches a member expression where the member is matched by a
@@ -2454,11 +2676,14 @@ AST_MATCHER_P(UsingShadowDecl, hasTargetDecl,
/// does not match, as X<A> is an explicit template specialization.
///
/// Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl>
-inline internal::PolymorphicMatcherWithParam0<
- internal::IsTemplateInstantiationMatcher>
-isTemplateInstantiation() {
- return internal::PolymorphicMatcherWithParam0<
- internal::IsTemplateInstantiationMatcher>();
+AST_POLYMORPHIC_MATCHER(isTemplateInstantiation) {
+ TOOLING_COMPILE_ASSERT((llvm::is_base_of<FunctionDecl, NodeType>::value) ||
+ (llvm::is_base_of<VarDecl, NodeType>::value) ||
+ (llvm::is_base_of<CXXRecordDecl, NodeType>::value),
+ requires_getTemplateSpecializationKind_method);
+ return (Node.getTemplateSpecializationKind() == TSK_ImplicitInstantiation ||
+ Node.getTemplateSpecializationKind() ==
+ TSK_ExplicitInstantiationDefinition);
}
/// \brief Matches explicit template specializations of function, class, or
@@ -2473,11 +2698,12 @@ isTemplateInstantiation() {
/// matches the specialization A<int>().
///
/// Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl>
-inline internal::PolymorphicMatcherWithParam0<
- internal::IsExplicitTemplateSpecializationMatcher>
-isExplicitTemplateSpecialization() {
- return internal::PolymorphicMatcherWithParam0<
- internal::IsExplicitTemplateSpecializationMatcher>();
+AST_POLYMORPHIC_MATCHER(isExplicitTemplateSpecialization) {
+ TOOLING_COMPILE_ASSERT((llvm::is_base_of<FunctionDecl, NodeType>::value) ||
+ (llvm::is_base_of<VarDecl, NodeType>::value) ||
+ (llvm::is_base_of<CXXRecordDecl, NodeType>::value),
+ requires_getTemplateSpecializationKind_method);
+ return (Node.getTemplateSpecializationKind() == TSK_ExplicitSpecialization);
}
/// \brief Matches \c TypeLocs for which the given inner
@@ -2685,6 +2911,32 @@ AST_TYPE_TRAVERSE_MATCHER(hasDeducedType, getDeducedType);
/// matches "int (*f)(int)" and the type of "g".
AST_TYPE_MATCHER(FunctionType, functionType);
+/// \brief Matches \c ParenType nodes.
+///
+/// Given
+/// \code
+/// int (*ptr_to_array)[4];
+/// int *array_of_ptrs[4];
+/// \endcode
+///
+/// \c varDecl(hasType(pointsTo(parenType()))) matches \c ptr_to_array but not
+/// \c array_of_ptrs.
+AST_TYPE_MATCHER(ParenType, parenType);
+
+/// \brief Matches \c ParenType nodes where the inner type is a specific type.
+///
+/// Given
+/// \code
+/// int (*ptr_to_array)[4];
+/// int (*ptr_to_func)(int);
+/// \endcode
+///
+/// \c varDecl(hasType(pointsTo(parenType(innerType(functionType()))))) matches
+/// \c ptr_to_func but not \c ptr_to_array.
+///
+/// Usable as: Matcher<ParenType>
+AST_TYPE_TRAVERSE_MATCHER(innerType, getInnerType);
+
/// \brief Matches block pointer types, i.e. types syntactically represented as
/// "void (^)(int)".
///
@@ -2713,18 +2965,56 @@ AST_TYPE_MATCHER(MemberPointerType, memberPointerType);
/// matches "int *a"
AST_TYPE_MATCHER(PointerType, pointerType);
-/// \brief Matches reference types.
+/// \brief Matches both lvalue and rvalue reference types.
///
/// Given
/// \code
/// int *a;
/// int &b = *a;
-/// int c = 5;
+/// int &&c = 1;
+/// auto &d = b;
+/// auto &&e = c;
+/// auto &&f = 2;
+/// int g = 5;
/// \endcode
-/// pointerType()
-/// matches "int &b"
+///
+/// \c referenceType() matches the types of \c b, \c c, \c d, \c e, and \c f.
AST_TYPE_MATCHER(ReferenceType, referenceType);
+/// \brief Matches lvalue reference types.
+///
+/// Given:
+/// \code
+/// int *a;
+/// int &b = *a;
+/// int &&c = 1;
+/// auto &d = b;
+/// auto &&e = c;
+/// auto &&f = 2;
+/// int g = 5;
+/// \endcode
+///
+/// \c lValueReferenceType() matches the types of \c b, \c d, and \c e. \c e is
+/// matched since the type is deduced as int& by reference collapsing rules.
+AST_TYPE_MATCHER(LValueReferenceType, lValueReferenceType);
+
+/// \brief Matches rvalue reference types.
+///
+/// Given:
+/// \code
+/// int *a;
+/// int &b = *a;
+/// int &&c = 1;
+/// auto &d = b;
+/// auto &&e = c;
+/// auto &&f = 2;
+/// int g = 5;
+/// \endcode
+///
+/// \c rValueReferenceType() matches the types of \c c and \c f. \c e is not
+/// matched as it is deduced to int& by reference collapsing rules.
+AST_TYPE_MATCHER(RValueReferenceType, rValueReferenceType);
+
/// \brief Narrows PointerType (and similar) matchers to those where the
/// \c pointee matches a given matcher.
///
@@ -2751,11 +3041,116 @@ AST_TYPELOC_TRAVERSE_MATCHER(pointee, getPointee);
/// matches "typedef int X"
AST_TYPE_MATCHER(TypedefType, typedefType);
-/// \brief Matches \c TypedefTypes referring to a specific
-/// \c TypedefNameDecl.
-AST_MATCHER_P(TypedefType, hasDecl,
- internal::Matcher<TypedefNameDecl>, InnerMatcher) {
- return InnerMatcher.matches(*Node.getDecl(), Finder, Builder);
+/// \brief Matches template specialization types.
+///
+/// Given
+/// \code
+/// template <typename T>
+/// class C { };
+///
+/// template class C<int>; // A
+/// C<char> var; // B
+/// \code
+///
+/// \c templateSpecializationType() matches the type of the explicit
+/// instantiation in \c A and the type of the variable declaration in \c B.
+AST_TYPE_MATCHER(TemplateSpecializationType, templateSpecializationType);
+
+/// \brief Matches record types (e.g. structs, classes).
+///
+/// Given
+/// \code
+/// class C {};
+/// struct S {};
+///
+/// C c;
+/// S s;
+/// \code
+///
+/// \c recordType() matches the type of the variable declarations of both \c c
+/// and \c s.
+AST_TYPE_MATCHER(RecordType, recordType);
+
+/// \brief Matches types specified with an elaborated type keyword or with a
+/// qualified name.
+///
+/// Given
+/// \code
+/// namespace N {
+/// namespace M {
+/// class D {};
+/// }
+/// }
+/// class C {};
+///
+/// class C c;
+/// N::M::D d;
+/// \code
+///
+/// \c elaboratedType() matches the type of the variable declarations of both
+/// \c c and \c d.
+AST_TYPE_MATCHER(ElaboratedType, elaboratedType);
+
+/// \brief Matches ElaboratedTypes whose qualifier, a NestedNameSpecifier,
+/// matches \c InnerMatcher if the qualifier exists.
+///
+/// Given
+/// \code
+/// namespace N {
+/// namespace M {
+/// class D {};
+/// }
+/// }
+/// N::M::D d;
+/// \code
+///
+/// \c elaboratedType(hasQualifier(hasPrefix(specifiesNamespace(hasName("N"))))
+/// matches the type of the variable declaration of \c d.
+AST_MATCHER_P(ElaboratedType, hasQualifier,
+ internal::Matcher<NestedNameSpecifier>, InnerMatcher) {
+ if (const NestedNameSpecifier *Qualifier = Node.getQualifier())
+ return InnerMatcher.matches(*Qualifier, Finder, Builder);
+
+ return false;
+}
+
+/// \brief Matches ElaboratedTypes whose named type matches \c InnerMatcher.
+///
+/// Given
+/// \code
+/// namespace N {
+/// namespace M {
+/// class D {};
+/// }
+/// }
+/// N::M::D d;
+/// \code
+///
+/// \c elaboratedType(namesType(recordType(
+/// hasDeclaration(namedDecl(hasName("D")))))) matches the type of the variable
+/// declaration of \c d.
+AST_MATCHER_P(ElaboratedType, namesType, internal::Matcher<QualType>,
+ InnerMatcher) {
+ return InnerMatcher.matches(Node.getNamedType(), Finder, Builder);
+}
+
+/// \brief Matches declarations whose declaration context, interpreted as a
+/// Decl, matches \c InnerMatcher.
+///
+/// Given
+/// \code
+/// namespace N {
+/// namespace M {
+/// class D {};
+/// }
+/// }
+/// \code
+///
+/// \c recordDecl(hasDeclContext(namedDecl(hasName("M")))) matches the
+/// declaration of \c class \c D.
+AST_MATCHER_P(Decl, hasDeclContext, internal::Matcher<Decl>, InnerMatcher) {
+ return InnerMatcher.matches(*Decl::castFromDeclContext(Node.getDeclContext()),
+ Finder, Builder);
}
/// \brief Matches nested name specifiers.
@@ -2828,10 +3223,13 @@ AST_MATCHER_P(NestedNameSpecifierLoc, specifiesTypeLoc,
/// \endcode
/// nestedNameSpecifier(hasPrefix(specifiesType(asString("struct A")))) and
/// matches "A::"
-inline internal::Matcher<NestedNameSpecifier> hasPrefix(
- const internal::Matcher<NestedNameSpecifier> &InnerMatcher) {
- return internal::makeMatcher(
- new internal::NestedNameSpecifierPrefixMatcher(InnerMatcher));
+AST_MATCHER_P_OVERLOAD(NestedNameSpecifier, hasPrefix,
+ internal::Matcher<NestedNameSpecifier>, InnerMatcher,
+ 0) {
+ NestedNameSpecifier *NextNode = Node.getPrefix();
+ if (NextNode == NULL)
+ return false;
+ return InnerMatcher.matches(*NextNode, Finder, Builder);
}
/// \brief Matches on the prefix of a \c NestedNameSpecifierLoc.
@@ -2843,10 +3241,13 @@ inline internal::Matcher<NestedNameSpecifier> hasPrefix(
/// \endcode
/// nestedNameSpecifierLoc(hasPrefix(loc(specifiesType(asString("struct A")))))
/// matches "A::"
-inline internal::Matcher<NestedNameSpecifierLoc> hasPrefix(
- const internal::Matcher<NestedNameSpecifierLoc> &InnerMatcher) {
- return internal::makeMatcher(
- new internal::NestedNameSpecifierLocPrefixMatcher(InnerMatcher));
+AST_MATCHER_P_OVERLOAD(NestedNameSpecifierLoc, hasPrefix,
+ internal::Matcher<NestedNameSpecifierLoc>, InnerMatcher,
+ 1) {
+ NestedNameSpecifierLoc NextNode = Node.getPrefix();
+ if (!NextNode)
+ return false;
+ return InnerMatcher.matches(NextNode, Finder, Builder);
}
/// \brief Matches nested name specifiers that specify a namespace matching the
@@ -2866,6 +3267,26 @@ AST_MATCHER_P(NestedNameSpecifier, specifiesNamespace,
return InnerMatcher.matches(*Node.getAsNamespace(), Finder, Builder);
}
+/// \brief Overloads for the \c equalsNode matcher.
+/// FIXME: Implement for other node types.
+/// @{
+
+/// \brief Matches if a node equals another node.
+///
+/// \c Decl has pointer identity in the AST.
+AST_MATCHER_P_OVERLOAD(Decl, equalsNode, Decl*, Other, 0) {
+ return &Node == Other;
+}
+/// \brief Matches if a node equals another node.
+///
+/// \c Stmt has pointer identity in the AST.
+///
+AST_MATCHER_P_OVERLOAD(Stmt, equalsNode, Stmt*, Other, 1) {
+ return &Node == Other;
+}
+
+/// @}
+
} // end namespace ast_matchers
} // end namespace clang
diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h
index e5365ff..30691ad 100644
--- a/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -35,13 +35,13 @@
#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_INTERNAL_H
#define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_INTERNAL_H
-#include "clang/AST/Decl.h"
+#include "clang/AST/ASTTypeTraits.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Decl.h"
#include "clang/AST/ExprCXX.h"
-#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/AST/Stmt.h"
#include "clang/AST/Type.h"
-#include "clang/ASTMatchers/ASTTypeTraits.h"
#include "llvm/ADT/VariadicFunction.h"
#include "llvm/Support/type_traits.h"
#include <map>
@@ -193,7 +193,7 @@ class ASTMatchFinder;
/// current node and doesn't care about its children or descendants,
/// implement SingleNodeMatcherInterface instead.
template <typename T>
-class MatcherInterface : public llvm::RefCountedBaseVPTR {
+class MatcherInterface : public RefCountedBaseVPTR {
public:
virtual ~MatcherInterface() {}
@@ -343,7 +343,7 @@ private:
const Matcher<Base> From;
};
- llvm::IntrusiveRefCntPtr< MatcherInterface<T> > Implementation;
+ IntrusiveRefCntPtr< MatcherInterface<T> > Implementation;
}; // class Matcher
/// \brief A convenient helper for creating a Matcher<T> without specifying
@@ -353,6 +353,61 @@ inline Matcher<T> makeMatcher(MatcherInterface<T> *Implementation) {
return Matcher<T>(Implementation);
}
+/// \brief Metafunction to determine if type T has a member called getDecl.
+template <typename T> struct has_getDecl {
+ struct Default { int getDecl; };
+ struct Derived : T, Default { };
+
+ template<typename C, C> struct CheckT;
+
+ // If T::getDecl exists, an ambiguity arises and CheckT will
+ // not be instantiable. This makes f(...) the only available
+ // overload.
+ template<typename C>
+ static char (&f(CheckT<int Default::*, &C::getDecl>*))[1];
+ template<typename C> static char (&f(...))[2];
+
+ static bool const value = sizeof(f<Derived>(0)) == 2;
+};
+
+/// \brief Matches overloaded operators with a specific name.
+///
+/// The type argument ArgT is not used by this matcher but is used by
+/// PolymorphicMatcherWithParam1 and should be StringRef.
+template <typename T, typename ArgT>
+class HasOverloadedOperatorNameMatcher : public SingleNodeMatcherInterface<T> {
+ TOOLING_COMPILE_ASSERT((llvm::is_same<T, CXXOperatorCallExpr>::value ||
+ llvm::is_same<T, CXXMethodDecl>::value),
+ unsupported_class_for_matcher);
+ TOOLING_COMPILE_ASSERT((llvm::is_same<ArgT, StringRef>::value),
+ argument_type_must_be_StringRef);
+public:
+ explicit HasOverloadedOperatorNameMatcher(const StringRef Name)
+ : SingleNodeMatcherInterface<T>(), Name(Name) {}
+
+ virtual bool matchesNode(const T &Node) const LLVM_OVERRIDE {
+ return matchesSpecialized(Node);
+ }
+
+private:
+
+ /// \brief CXXOperatorCallExpr exist only for calls to overloaded operators
+ /// so this function returns true if the call is to an operator of the given
+ /// name.
+ bool matchesSpecialized(const CXXOperatorCallExpr &Node) const {
+ return getOperatorSpelling(Node.getOperator()) == Name;
+ }
+
+ /// \brief Returns true only if CXXMethodDecl represents an overloaded
+ /// operator and has the given operator name.
+ bool matchesSpecialized(const CXXMethodDecl &Node) const {
+ return Node.isOverloadedOperator() &&
+ getOperatorSpelling(Node.getOverloadedOperator()) == Name;
+ }
+
+ std::string Name;
+};
+
/// \brief Matches declarations for QualType and CallExpr.
///
/// Type argument DeclMatcherT is required by PolymorphicMatcherWithParam1 but
@@ -373,16 +428,36 @@ public:
}
private:
- /// \brief Extracts the CXXRecordDecl of a QualType and returns whether the
- /// inner matcher matches on it.
+ /// \brief If getDecl exists as a member of U, returns whether the inner
+ /// matcher matches Node.getDecl().
+ template <typename U>
+ bool matchesSpecialized(
+ const U &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder,
+ typename llvm::enable_if<has_getDecl<U>, int>::type = 0) const {
+ return matchesDecl(Node.getDecl(), Finder, Builder);
+ }
+
+ /// \brief Extracts the CXXRecordDecl or EnumDecl of a QualType and returns
+ /// whether the inner matcher matches on it.
bool matchesSpecialized(const QualType &Node, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
/// FIXME: Add other ways to convert...
if (Node.isNull())
return false;
+ if (const EnumType *AsEnum = dyn_cast<EnumType>(Node.getTypePtr()))
+ return matchesDecl(AsEnum->getDecl(), Finder, Builder);
return matchesDecl(Node->getAsCXXRecordDecl(), Finder, Builder);
}
+ /// \brief Gets the TemplateDecl from a TemplateSpecializationType
+ /// and returns whether the inner matches on it.
+ bool matchesSpecialized(const TemplateSpecializationType &Node,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return matchesDecl(Node.getTemplateName().getAsTemplateDecl(),
+ Finder, Builder);
+ }
+
/// \brief Extracts the Decl of the callee of a CallExpr and returns whether
/// the inner matcher matches on it.
bool matchesSpecialized(const CallExpr &Node, ASTMatchFinder *Finder,
@@ -537,6 +612,8 @@ public:
Matcher, Builder, MatchMode);
}
+ virtual ASTContext &getASTContext() const = 0;
+
protected:
virtual bool matchesChildOf(const ast_type_traits::DynTypedNode &Node,
const DynTypedMatcher &Matcher,
@@ -672,7 +749,7 @@ public:
virtual bool matches(const T &Node,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
- const To *InnerMatchValue = llvm::dyn_cast<To>(&Node);
+ const To *InnerMatchValue = dyn_cast<To>(&Node);
return InnerMatchValue != NULL &&
InnerMatcher.matches(*InnerMatchValue, Finder, Builder);
}
@@ -828,21 +905,56 @@ private:
/// used. They will always be instantiated with types convertible to
/// Matcher<T>.
template <typename T, typename MatcherT1, typename MatcherT2>
+class EachOfMatcher : public MatcherInterface<T> {
+public:
+ EachOfMatcher(const Matcher<T> &InnerMatcher1,
+ const Matcher<T> &InnerMatcher2)
+ : InnerMatcher1(InnerMatcher1), InnerMatcher2(InnerMatcher2) {
+ }
+
+ virtual bool matches(const T &Node, ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ BoundNodesTreeBuilder Builder1;
+ bool Matched1 = InnerMatcher1.matches(Node, Finder, &Builder1);
+ if (Matched1)
+ Builder->addMatch(Builder1.build());
+
+ BoundNodesTreeBuilder Builder2;
+ bool Matched2 = InnerMatcher2.matches(Node, Finder, &Builder2);
+ if (Matched2)
+ Builder->addMatch(Builder2.build());
+
+ return Matched1 || Matched2;
+ }
+
+private:
+ const Matcher<T> InnerMatcher1;
+ const Matcher<T> InnerMatcher2;
+};
+
+/// \brief Matches nodes of type T for which at least one of the two provided
+/// matchers matches.
+///
+/// Type arguments MatcherT1 and MatcherT2 are
+/// required by PolymorphicMatcherWithParam2 but not actually
+/// used. They will always be instantiated with types convertible to
+/// Matcher<T>.
+template <typename T, typename MatcherT1, typename MatcherT2>
class AnyOfMatcher : public MatcherInterface<T> {
public:
AnyOfMatcher(const Matcher<T> &InnerMatcher1, const Matcher<T> &InnerMatcher2)
- : InnerMatcher1(InnerMatcher1), InnertMatcher2(InnerMatcher2) {}
+ : InnerMatcher1(InnerMatcher1), InnerMatcher2(InnerMatcher2) {}
virtual bool matches(const T &Node,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
return InnerMatcher1.matches(Node, Finder, Builder) ||
- InnertMatcher2.matches(Node, Finder, Builder);
+ InnerMatcher2.matches(Node, Finder, Builder);
}
private:
const Matcher<T> InnerMatcher1;
- const Matcher<T> InnertMatcher2;
+ const Matcher<T> InnerMatcher2;
};
/// \brief Creates a Matcher<T> that matches if all inner matchers match.
@@ -989,69 +1101,6 @@ private:
const ValueT ExpectedValue;
};
-template <typename T>
-class IsDefinitionMatcher : public SingleNodeMatcherInterface<T> {
- TOOLING_COMPILE_ASSERT(
- (llvm::is_base_of<TagDecl, T>::value) ||
- (llvm::is_base_of<VarDecl, T>::value) ||
- (llvm::is_base_of<FunctionDecl, T>::value),
- is_definition_requires_isThisDeclarationADefinition_method);
-public:
- virtual bool matchesNode(const T &Node) const {
- return Node.isThisDeclarationADefinition();
- }
-};
-
-/// \brief Matches on template instantiations for FunctionDecl, VarDecl or
-/// CXXRecordDecl nodes.
-template <typename T>
-class IsTemplateInstantiationMatcher : public MatcherInterface<T> {
- TOOLING_COMPILE_ASSERT((llvm::is_base_of<FunctionDecl, T>::value) ||
- (llvm::is_base_of<VarDecl, T>::value) ||
- (llvm::is_base_of<CXXRecordDecl, T>::value),
- requires_getTemplateSpecializationKind_method);
- public:
- virtual bool matches(const T& Node,
- ASTMatchFinder* Finder,
- BoundNodesTreeBuilder* Builder) const {
- return (Node.getTemplateSpecializationKind() ==
- TSK_ImplicitInstantiation ||
- Node.getTemplateSpecializationKind() ==
- TSK_ExplicitInstantiationDefinition);
- }
-};
-
-/// \brief Matches on explicit template specializations for FunctionDecl,
-/// VarDecl or CXXRecordDecl nodes.
-template <typename T>
-class IsExplicitTemplateSpecializationMatcher : public MatcherInterface<T> {
- TOOLING_COMPILE_ASSERT((llvm::is_base_of<FunctionDecl, T>::value) ||
- (llvm::is_base_of<VarDecl, T>::value) ||
- (llvm::is_base_of<CXXRecordDecl, T>::value),
- requires_getTemplateSpecializationKind_method);
- public:
- virtual bool matches(const T& Node,
- ASTMatchFinder* Finder,
- BoundNodesTreeBuilder* Builder) const {
- return (Node.getTemplateSpecializationKind() == TSK_ExplicitSpecialization);
- }
-};
-
-class IsArrowMatcher : public SingleNodeMatcherInterface<MemberExpr> {
-public:
- virtual bool matchesNode(const MemberExpr &Node) const {
- return Node.isArrow();
- }
-};
-
-class IsConstQualifiedMatcher
- : public SingleNodeMatcherInterface<QualType> {
- public:
- virtual bool matchesNode(const QualType& Node) const {
- return Node.isConstQualified();
- }
-};
-
/// \brief A VariadicDynCastAllOfMatcher<SourceT, TargetT> object is a
/// variadic functor that takes a number of Matcher<TargetT> and returns a
/// Matcher<SourceT> that matches TargetT nodes that are matched by all of the
@@ -1115,50 +1164,6 @@ private:
const Matcher<T> InnerMatcher;
};
-/// \brief Matches \c NestedNameSpecifiers with a prefix matching another
-/// \c Matcher<NestedNameSpecifier>.
-class NestedNameSpecifierPrefixMatcher
- : public MatcherInterface<NestedNameSpecifier> {
-public:
- explicit NestedNameSpecifierPrefixMatcher(
- const Matcher<NestedNameSpecifier> &InnerMatcher)
- : InnerMatcher(InnerMatcher) {}
-
- virtual bool matches(const NestedNameSpecifier &Node,
- ASTMatchFinder *Finder,
- BoundNodesTreeBuilder *Builder) const {
- NestedNameSpecifier *NextNode = Node.getPrefix();
- if (NextNode == NULL)
- return false;
- return InnerMatcher.matches(*NextNode, Finder, Builder);
- }
-
-private:
- const Matcher<NestedNameSpecifier> InnerMatcher;
-};
-
-/// \brief Matches \c NestedNameSpecifierLocs with a prefix matching another
-/// \c Matcher<NestedNameSpecifierLoc>.
-class NestedNameSpecifierLocPrefixMatcher
- : public MatcherInterface<NestedNameSpecifierLoc> {
-public:
- explicit NestedNameSpecifierLocPrefixMatcher(
- const Matcher<NestedNameSpecifierLoc> &InnerMatcher)
- : InnerMatcher(InnerMatcher) {}
-
- virtual bool matches(const NestedNameSpecifierLoc &Node,
- ASTMatchFinder *Finder,
- BoundNodesTreeBuilder *Builder) const {
- NestedNameSpecifierLoc NextNode = Node.getPrefix();
- if (!NextNode)
- return false;
- return InnerMatcher.matches(NextNode, Finder, Builder);
- }
-
-private:
- const Matcher<NestedNameSpecifierLoc> InnerMatcher;
-};
-
/// \brief Matches \c TypeLocs based on an inner matcher matching a certain
/// \c QualType.
///
diff --git a/include/clang/ASTMatchers/ASTMatchersMacros.h b/include/clang/ASTMatchers/ASTMatchersMacros.h
index 953abc2..f5ca26b 100644
--- a/include/clang/ASTMatchers/ASTMatchersMacros.h
+++ b/include/clang/ASTMatchers/ASTMatchersMacros.h
@@ -49,21 +49,23 @@
///
/// The code should return true if 'Node' matches.
#define AST_MATCHER(Type, DefineMatcher) \
+ AST_MATCHER_OVERLOAD(Type, DefineMatcher, 0)
+
+#define AST_MATCHER_OVERLOAD(Type, DefineMatcher, OverloadId) \
namespace internal { \
- class matcher_##DefineMatcher##Matcher \
+ class matcher_##DefineMatcher##OverloadId##Matcher \
: public MatcherInterface<Type> { \
- public: \
- explicit matcher_##DefineMatcher##Matcher() {} \
- virtual bool matches( \
- const Type &Node, ASTMatchFinder *Finder, \
- BoundNodesTreeBuilder *Builder) const; \
+ public: \
+ explicit matcher_##DefineMatcher##OverloadId##Matcher() {} \
+ virtual bool matches(const Type &Node, ASTMatchFinder *Finder, \
+ BoundNodesTreeBuilder *Builder) const; \
}; \
} \
inline internal::Matcher<Type> DefineMatcher() { \
return internal::makeMatcher( \
- new internal::matcher_##DefineMatcher##Matcher()); \
+ new internal::matcher_##DefineMatcher##OverloadId##Matcher()); \
} \
- inline bool internal::matcher_##DefineMatcher##Matcher::matches( \
+ inline bool internal::matcher_##DefineMatcher##OverloadId##Matcher::matches( \
const Type &Node, ASTMatchFinder *Finder, \
BoundNodesTreeBuilder *Builder) const
@@ -81,24 +83,29 @@
///
/// The code should return true if 'Node' matches.
#define AST_MATCHER_P(Type, DefineMatcher, ParamType, Param) \
+ AST_MATCHER_P_OVERLOAD(Type, DefineMatcher, ParamType, Param, 0)
+
+#define AST_MATCHER_P_OVERLOAD(Type, DefineMatcher, ParamType, Param, \
+ OverloadId) \
namespace internal { \
- class matcher_##DefineMatcher##Matcher \
+ class matcher_##DefineMatcher##OverloadId##Matcher \
: public MatcherInterface<Type> { \
- public: \
- explicit matcher_##DefineMatcher##Matcher( \
- const ParamType &A##Param) : Param(A##Param) {} \
- virtual bool matches( \
- const Type &Node, ASTMatchFinder *Finder, \
- BoundNodesTreeBuilder *Builder) const; \
- private: \
+ public: \
+ explicit matcher_##DefineMatcher##OverloadId##Matcher( \
+ const ParamType &A##Param) \
+ : Param(A##Param) { \
+ } \
+ virtual bool matches(const Type &Node, ASTMatchFinder *Finder, \
+ BoundNodesTreeBuilder *Builder) const; \
+ private: \
const ParamType Param; \
}; \
} \
inline internal::Matcher<Type> DefineMatcher(const ParamType &Param) { \
return internal::makeMatcher( \
- new internal::matcher_##DefineMatcher##Matcher(Param)); \
+ new internal::matcher_##DefineMatcher##OverloadId##Matcher(Param)); \
} \
- inline bool internal::matcher_##DefineMatcher##Matcher::matches( \
+ inline bool internal::matcher_##DefineMatcher##OverloadId##Matcher::matches( \
const Type &Node, ASTMatchFinder *Finder, \
BoundNodesTreeBuilder *Builder) const
@@ -116,33 +123,67 @@
/// Builder: a BoundNodesTreeBuilder*.
///
/// The code should return true if 'Node' matches.
-#define AST_MATCHER_P2( \
- Type, DefineMatcher, ParamType1, Param1, ParamType2, Param2) \
+#define AST_MATCHER_P2(Type, DefineMatcher, ParamType1, Param1, ParamType2, \
+ Param2) \
+ AST_MATCHER_P2_OVERLOAD(Type, DefineMatcher, ParamType1, Param1, ParamType2, \
+ Param2, 0)
+
+#define AST_MATCHER_P2_OVERLOAD(Type, DefineMatcher, ParamType1, Param1, \
+ ParamType2, Param2, OverloadId) \
namespace internal { \
- class matcher_##DefineMatcher##Matcher \
+ class matcher_##DefineMatcher##OverloadId##Matcher \
: public MatcherInterface<Type> { \
- public: \
- matcher_##DefineMatcher##Matcher( \
- const ParamType1 &A##Param1, const ParamType2 &A##Param2) \
- : Param1(A##Param1), Param2(A##Param2) {} \
- virtual bool matches( \
- const Type &Node, ASTMatchFinder *Finder, \
- BoundNodesTreeBuilder *Builder) const; \
- private: \
+ public: \
+ matcher_##DefineMatcher##OverloadId##Matcher(const ParamType1 &A##Param1, \
+ const ParamType2 &A##Param2) \
+ : Param1(A##Param1), Param2(A##Param2) { \
+ } \
+ virtual bool matches(const Type &Node, ASTMatchFinder *Finder, \
+ BoundNodesTreeBuilder *Builder) const; \
+ private: \
const ParamType1 Param1; \
const ParamType2 Param2; \
}; \
} \
- inline internal::Matcher<Type> DefineMatcher( \
- const ParamType1 &Param1, const ParamType2 &Param2) { \
+ inline internal::Matcher<Type> \
+ DefineMatcher(const ParamType1 &Param1, const ParamType2 &Param2) { \
return internal::makeMatcher( \
- new internal::matcher_##DefineMatcher##Matcher( \
- Param1, Param2)); \
+ new internal::matcher_##DefineMatcher##OverloadId##Matcher(Param1, \
+ Param2)); \
} \
- inline bool internal::matcher_##DefineMatcher##Matcher::matches( \
+ inline bool internal::matcher_##DefineMatcher##OverloadId##Matcher::matches( \
const Type &Node, ASTMatchFinder *Finder, \
BoundNodesTreeBuilder *Builder) const
+/// \brief AST_POLYMORPHIC_MATCHER(DefineMatcher) { ... }
+/// defines a single-parameter function named DefineMatcher() that is
+/// polymorphic in the return type.
+///
+/// The variables are the same as for AST_MATCHER, but NodeType will be deduced
+/// from the calling context.
+#define AST_POLYMORPHIC_MATCHER(DefineMatcher) \
+ AST_POLYMORPHIC_MATCHER_OVERLOAD(DefineMatcher, 0)
+
+#define AST_POLYMORPHIC_MATCHER_OVERLOAD(DefineMatcher, OverloadId) \
+ namespace internal { \
+ template <typename NodeType> \
+ class matcher_##DefineMatcher##OverloadId##Matcher \
+ : public MatcherInterface<NodeType> { \
+ public: \
+ virtual bool matches(const NodeType &Node, ASTMatchFinder *Finder, \
+ BoundNodesTreeBuilder *Builder) const; \
+ }; \
+ } \
+ inline internal::PolymorphicMatcherWithParam0< \
+ internal::matcher_##DefineMatcher##OverloadId##Matcher> DefineMatcher() {\
+ return internal::PolymorphicMatcherWithParam0< \
+ internal::matcher_##DefineMatcher##OverloadId##Matcher>(); \
+ } \
+ template <typename NodeType> \
+ bool internal::matcher_##DefineMatcher##OverloadId##Matcher< \
+ NodeType>::matches(const NodeType &Node, ASTMatchFinder *Finder, \
+ BoundNodesTreeBuilder *Builder) const
+
/// \brief AST_POLYMORPHIC_MATCHER_P(DefineMatcher, ParamType, Param) { ... }
/// defines a single-parameter function named DefineMatcher() that is
/// polymorphic in the return type.
@@ -153,32 +194,36 @@
///
/// FIXME: Pull out common code with above macro?
#define AST_POLYMORPHIC_MATCHER_P(DefineMatcher, ParamType, Param) \
+ AST_POLYMORPHIC_MATCHER_P_OVERLOAD(DefineMatcher, ParamType, Param, 0)
+
+#define AST_POLYMORPHIC_MATCHER_P_OVERLOAD(DefineMatcher, ParamType, Param, \
+ OverloadId) \
namespace internal { \
template <typename NodeType, typename ParamT> \
- class matcher_##DefineMatcher##Matcher \
+ class matcher_##DefineMatcher##OverloadId##Matcher \
: public MatcherInterface<NodeType> { \
- public: \
- explicit matcher_##DefineMatcher##Matcher( \
- const ParamType &A##Param) : Param(A##Param) {} \
- virtual bool matches( \
- const NodeType &Node, ASTMatchFinder *Finder, \
- BoundNodesTreeBuilder *Builder) const; \
- private: \
+ public: \
+ explicit matcher_##DefineMatcher##OverloadId##Matcher( \
+ const ParamType &A##Param) \
+ : Param(A##Param) { \
+ } \
+ virtual bool matches(const NodeType &Node, ASTMatchFinder *Finder, \
+ BoundNodesTreeBuilder *Builder) const; \
+ private: \
const ParamType Param; \
}; \
} \
inline internal::PolymorphicMatcherWithParam1< \
- internal::matcher_##DefineMatcher##Matcher, \
- ParamType > \
- DefineMatcher(const ParamType &Param) { \
+ internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType> \
+ DefineMatcher(const ParamType &Param) { \
return internal::PolymorphicMatcherWithParam1< \
- internal::matcher_##DefineMatcher##Matcher, \
- ParamType >(Param); \
+ internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType>( \
+ Param); \
} \
template <typename NodeType, typename ParamT> \
- bool internal::matcher_##DefineMatcher##Matcher<NodeType, ParamT>::matches( \
- const NodeType &Node, ASTMatchFinder *Finder, \
- BoundNodesTreeBuilder *Builder) const
+ bool internal::matcher_##DefineMatcher##OverloadId##Matcher< \
+ NodeType, ParamT>::matches(const NodeType &Node, ASTMatchFinder *Finder, \
+ BoundNodesTreeBuilder *Builder) const
/// \brief AST_POLYMORPHIC_MATCHER_P2(
/// DefineMatcher, ParamType1, Param1, ParamType2, Param2) { ... }
@@ -188,35 +233,39 @@
/// The variables are the same as for AST_MATCHER_P2, with the
/// addition of NodeType, which specifies the node type of the matcher
/// Matcher<NodeType> returned by the function DefineMatcher().
-#define AST_POLYMORPHIC_MATCHER_P2( \
- DefineMatcher, ParamType1, Param1, ParamType2, Param2) \
+#define AST_POLYMORPHIC_MATCHER_P2(DefineMatcher, ParamType1, Param1, \
+ ParamType2, Param2) \
+ AST_POLYMORPHIC_MATCHER_P2_OVERLOAD(DefineMatcher, ParamType1, Param1, \
+ ParamType2, Param2, 0)
+
+#define AST_POLYMORPHIC_MATCHER_P2_OVERLOAD(DefineMatcher, ParamType1, Param1, \
+ ParamType2, Param2, OverloadId) \
namespace internal { \
template <typename NodeType, typename ParamT1, typename ParamT2> \
- class matcher_##DefineMatcher##Matcher \
+ class matcher_##DefineMatcher##OverloadId##Matcher \
: public MatcherInterface<NodeType> { \
- public: \
- matcher_##DefineMatcher##Matcher( \
- const ParamType1 &A##Param1, const ParamType2 &A##Param2) \
- : Param1(A##Param1), Param2(A##Param2) {} \
- virtual bool matches( \
- const NodeType &Node, ASTMatchFinder *Finder, \
- BoundNodesTreeBuilder *Builder) const; \
- private: \
+ public: \
+ matcher_##DefineMatcher##OverloadId##Matcher(const ParamType1 &A##Param1, \
+ const ParamType2 &A##Param2) \
+ : Param1(A##Param1), Param2(A##Param2) { \
+ } \
+ virtual bool matches(const NodeType &Node, ASTMatchFinder *Finder, \
+ BoundNodesTreeBuilder *Builder) const; \
+ private: \
const ParamType1 Param1; \
const ParamType2 Param2; \
}; \
} \
inline internal::PolymorphicMatcherWithParam2< \
- internal::matcher_##DefineMatcher##Matcher, \
- ParamType1, ParamType2 > \
- DefineMatcher(const ParamType1 &Param1, const ParamType2 &Param2) { \
+ internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType1, \
+ ParamType2> \
+ DefineMatcher(const ParamType1 &Param1, const ParamType2 &Param2) { \
return internal::PolymorphicMatcherWithParam2< \
- internal::matcher_##DefineMatcher##Matcher, \
- ParamType1, ParamType2 >( \
- Param1, Param2); \
+ internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType1, \
+ ParamType2>(Param1, Param2); \
} \
template <typename NodeType, typename ParamT1, typename ParamT2> \
- bool internal::matcher_##DefineMatcher##Matcher< \
+ bool internal::matcher_##DefineMatcher##OverloadId##Matcher< \
NodeType, ParamT1, ParamT2>::matches( \
const NodeType &Node, ASTMatchFinder *Finder, \
BoundNodesTreeBuilder *Builder) const
@@ -224,9 +273,9 @@
/// \brief Creates a variadic matcher for both a specific \c Type as well as
/// the corresponding \c TypeLoc.
#define AST_TYPE_MATCHER(NodeType, MatcherName) \
- const internal::VariadicDynCastAllOfMatcher<Type, NodeType> MatcherName; \
- const internal::VariadicDynCastAllOfMatcher<TypeLoc, \
- NodeType##Loc> MatcherName##Loc
+ const internal::VariadicDynCastAllOfMatcher<Type, NodeType> MatcherName
+// FIXME: add a matcher for TypeLoc derived classes using its custom casting
+// API (no longer dyn_cast) if/when we need such matching
/// \brief AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName) defines
/// the matcher \c MatcherName that can be used to traverse from one \c Type
@@ -236,54 +285,61 @@
/// \c SpecificType::FunctionName. The existance of such a function determines
/// whether a corresponding matcher can be used on \c SpecificType.
#define AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName) \
-class Polymorphic##MatcherName##TypeMatcher { \
-public: \
- Polymorphic##MatcherName##TypeMatcher( \
- const internal::Matcher<QualType> &InnerMatcher) \
- : InnerMatcher(InnerMatcher) {} \
- template <typename T> operator internal::Matcher<T>() { \
- return internal::Matcher<T>(new internal::TypeTraverseMatcher<T>( \
- InnerMatcher, &T::FunctionName)); \
+ class Polymorphic##MatcherName##TypeMatcher { \
+ public: \
+ Polymorphic##MatcherName##TypeMatcher( \
+ const internal::Matcher<QualType> &InnerMatcher) \
+ : InnerMatcher(InnerMatcher) { \
+ } \
+ template <typename T> operator internal:: Matcher< T>() { \
+ return internal::Matcher<T>(new internal::TypeTraverseMatcher<T>( \
+ InnerMatcher, &T::FunctionName)); \
+ } \
+ private: \
+ const internal::Matcher<QualType> InnerMatcher; \
} \
-private: \
- const internal::Matcher<QualType> InnerMatcher; \
-}; \
-class Variadic##MatcherName##TypeTraverseMatcher \
- : public llvm::VariadicFunction< \
- Polymorphic##MatcherName##TypeMatcher, \
- internal::Matcher<QualType>, \
- internal::makeTypeAllOfComposite< \
- Polymorphic##MatcherName##TypeMatcher, QualType> > { \
-public: \
- Variadic##MatcherName##TypeTraverseMatcher() {} \
-}; \
-const Variadic##MatcherName##TypeTraverseMatcher MatcherName
+ ; \
+ class Variadic##MatcherName##TypeTraverseMatcher \
+ : public llvm::VariadicFunction< \
+ Polymorphic##MatcherName##TypeMatcher, internal::Matcher<QualType>, \
+ internal::makeTypeAllOfComposite< \
+ Polymorphic##MatcherName##TypeMatcher, QualType> > { \
+ public: \
+ Variadic##MatcherName##TypeTraverseMatcher() { \
+ } \
+ } \
+ ; \
+ const Variadic##MatcherName##TypeTraverseMatcher MatcherName
/// \brief AST_TYPELOC_TRAVERSE_MATCHER(MatcherName, FunctionName) works
/// identical to \c AST_TYPE_TRAVERSE_MATCHER but operates on \c TypeLocs.
#define AST_TYPELOC_TRAVERSE_MATCHER(MatcherName, FunctionName) \
-class Polymorphic##MatcherName##TypeLocMatcher { \
-public: \
- Polymorphic##MatcherName##TypeLocMatcher( \
- const internal::Matcher<TypeLoc> &InnerMatcher) \
- : InnerMatcher(InnerMatcher) {} \
- template <typename T> operator internal::Matcher<T>() { \
- return internal::Matcher<T>(new internal::TypeLocTraverseMatcher<T>( \
- InnerMatcher, &T::FunctionName##Loc)); \
+ class Polymorphic##MatcherName##TypeLocMatcher { \
+ public: \
+ Polymorphic##MatcherName##TypeLocMatcher( \
+ const internal::Matcher<TypeLoc> &InnerMatcher) \
+ : InnerMatcher(InnerMatcher) { \
+ } \
+ template <typename T> operator internal:: Matcher< T>() { \
+ return internal::Matcher<T>( \
+ new internal::TypeLocTraverseMatcher<T>(InnerMatcher, \
+ &T::FunctionName##Loc)); \
+ } \
+ private: \
+ const internal::Matcher<TypeLoc> InnerMatcher; \
+ } \
+ ; \
+ class Variadic##MatcherName##TypeLocTraverseMatcher \
+ : public llvm::VariadicFunction< \
+ Polymorphic##MatcherName##TypeLocMatcher, internal::Matcher<TypeLoc>,\
+ internal::makeTypeAllOfComposite< \
+ Polymorphic##MatcherName##TypeLocMatcher, TypeLoc> > { \
+ public: \
+ Variadic##MatcherName##TypeLocTraverseMatcher() { \
+ } \
} \
-private: \
- const internal::Matcher<TypeLoc> InnerMatcher; \
-}; \
-class Variadic##MatcherName##TypeLocTraverseMatcher \
- : public llvm::VariadicFunction< \
- Polymorphic##MatcherName##TypeLocMatcher, \
- internal::Matcher<TypeLoc>, \
- internal::makeTypeAllOfComposite< \
- Polymorphic##MatcherName##TypeLocMatcher, TypeLoc> > { \
-public: \
- Variadic##MatcherName##TypeLocTraverseMatcher() {} \
-}; \
-const Variadic##MatcherName##TypeLocTraverseMatcher MatcherName##Loc; \
-AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName##Type)
+ ; \
+ const Variadic##MatcherName##TypeLocTraverseMatcher MatcherName##Loc; \
+ AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName##Type)
#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H
diff --git a/include/clang/Analysis/Analyses/Dominators.h b/include/clang/Analysis/Analyses/Dominators.h
index e9a431a..2a806c8 100644
--- a/include/clang/Analysis/Analyses/Dominators.h
+++ b/include/clang/Analysis/Analyses/Dominators.h
@@ -15,12 +15,11 @@
#define LLVM_CLANG_DOMINATORS_H
#include "clang/Analysis/AnalysisContext.h"
-
-#include "llvm/Module.h"
-#include "llvm/ADT/GraphTraits.h"
#include "clang/Analysis/CFG.h"
-#include "llvm/Analysis/Dominators.h"
+#include "llvm/ADT/GraphTraits.h"
#include "llvm/Analysis/DominatorInternals.h"
+#include "llvm/Analysis/Dominators.h"
+#include "llvm/IR/Module.h"
namespace clang {
diff --git a/include/clang/Analysis/Analyses/FormatString.h b/include/clang/Analysis/Analyses/FormatString.h
index 5cb9731..4bd989c 100644
--- a/include/clang/Analysis/Analyses/FormatString.h
+++ b/include/clang/Analysis/Analyses/FormatString.h
@@ -201,7 +201,7 @@ public:
bool isPrintfKind() const { return IsPrintf; }
- llvm::Optional<ConversionSpecifier> getStandardSpecifier() const;
+ Optional<ConversionSpecifier> getStandardSpecifier() const;
protected:
bool IsPrintf;
@@ -361,7 +361,7 @@ public:
bool hasStandardLengthModifier() const;
- llvm::Optional<LengthModifier> getCorrectedLengthModifier() const;
+ Optional<LengthModifier> getCorrectedLengthModifier() const;
bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;
diff --git a/include/clang/Analysis/Analyses/LiveVariables.h b/include/clang/Analysis/Analyses/LiveVariables.h
index c9f39b4..bbd2b02 100644
--- a/include/clang/Analysis/Analyses/LiveVariables.h
+++ b/include/clang/Analysis/Analyses/LiveVariables.h
@@ -14,8 +14,8 @@
#ifndef LLVM_CLANG_LIVEVARIABLES_H
#define LLVM_CLANG_LIVEVARIABLES_H
-#include "clang/Analysis/AnalysisContext.h"
#include "clang/AST/Decl.h"
+#include "clang/Analysis/AnalysisContext.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/ImmutableSet.h"
diff --git a/include/clang/Analysis/Analyses/ThreadSafety.h b/include/clang/Analysis/Analyses/ThreadSafety.h
index ef6b821..8a888e6 100644
--- a/include/clang/Analysis/Analyses/ThreadSafety.h
+++ b/include/clang/Analysis/Analyses/ThreadSafety.h
@@ -29,24 +29,24 @@ namespace thread_safety {
/// This enum distinguishes between different kinds of operations that may
/// need to be protected by locks. We use this enum in error handling.
enum ProtectedOperationKind {
- POK_VarDereference, /// Dereferencing a variable (e.g. p in *p = 5;)
- POK_VarAccess, /// Reading or writing a variable (e.g. x in x = 5;)
- POK_FunctionCall /// Making a function call (e.g. fool())
+ POK_VarDereference, ///< Dereferencing a variable (e.g. p in *p = 5;)
+ POK_VarAccess, ///< Reading or writing a variable (e.g. x in x = 5;)
+ POK_FunctionCall ///< Making a function call (e.g. fool())
};
/// This enum distinguishes between different kinds of lock actions. For
/// example, it is an error to write a variable protected by shared version of a
/// mutex.
enum LockKind {
- LK_Shared, /// Shared/reader lock of a mutex
- LK_Exclusive /// Exclusive/writer lock of a mutex
+ LK_Shared, ///< Shared/reader lock of a mutex.
+ LK_Exclusive ///< Exclusive/writer lock of a mutex.
};
/// This enum distinguishes between different ways to access (read or write) a
/// variable.
enum AccessKind {
- AK_Read, /// Reading a variable
- AK_Written /// Writing a variable
+ AK_Read, ///< Reading a variable.
+ AK_Written ///< Writing a variable.
};
/// This enum distinguishes between different situations where we warn due to
@@ -67,7 +67,8 @@ enum LockErrorKind {
/// Handler class for thread safety warnings.
class ThreadSafetyHandler {
public:
- typedef llvm::StringRef Name;
+ typedef StringRef Name;
+ ThreadSafetyHandler() : IssueBetaWarnings(false) { }
virtual ~ThreadSafetyHandler();
/// Warn about lock expressions which fail to resolve to lockable objects.
@@ -143,6 +144,12 @@ public:
/// \param Loc -- The location of the function call.
virtual void handleFunExcludesLock(Name FunName, Name LockName,
SourceLocation Loc) {}
+
+ bool issueBetaWarnings() { return IssueBetaWarnings; }
+ void setIssueBetaWarnings(bool b) { IssueBetaWarnings = b; }
+
+private:
+ bool IssueBetaWarnings;
};
/// \brief Check a function's CFG for thread-safety violations.
diff --git a/include/clang/Analysis/Analyses/UninitializedValues.h b/include/clang/Analysis/Analyses/UninitializedValues.h
index 45ce4de..e8810c3 100644
--- a/include/clang/Analysis/Analyses/UninitializedValues.h
+++ b/include/clang/Analysis/Analyses/UninitializedValues.h
@@ -15,6 +15,7 @@
#ifndef LLVM_CLANG_UNINIT_VALS_H
#define LLVM_CLANG_UNINIT_VALS_H
+#include "clang/AST/Stmt.h"
#include "llvm/ADT/SmallVector.h"
namespace clang {
@@ -42,7 +43,7 @@ private:
/// This use is always uninitialized if it occurs after any of these branches
/// is taken.
- llvm::SmallVector<Branch, 2> UninitBranches;
+ SmallVector<Branch, 2> UninitBranches;
public:
UninitUse(const Expr *User, bool AlwaysUninit) :
@@ -71,7 +72,7 @@ public:
!branch_empty() ? Sometimes : Maybe;
}
- typedef llvm::SmallVectorImpl<Branch>::const_iterator branch_iterator;
+ typedef SmallVectorImpl<Branch>::const_iterator branch_iterator;
/// Branches which inevitably result in the variable being used uninitialized.
branch_iterator branch_begin() const { return UninitBranches.begin(); }
branch_iterator branch_end() const { return UninitBranches.end(); }
diff --git a/include/clang/Analysis/AnalysisContext.h b/include/clang/Analysis/AnalysisContext.h
index 5246678..46d7d07 100644
--- a/include/clang/Analysis/AnalysisContext.h
+++ b/include/clang/Analysis/AnalysisContext.h
@@ -18,11 +18,11 @@
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/Analysis/CFG.h"
-#include "llvm/ADT/OwningPtr.h"
-#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/PointerUnion.h"
-#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/Allocator.h"
namespace clang {
@@ -133,7 +133,21 @@ public:
void registerForcedBlockExpression(const Stmt *stmt);
const CFGBlock *getBlockForRegisteredExpression(const Stmt *stmt);
+ /// \brief Get the body of the Declaration.
Stmt *getBody() const;
+
+ /// \brief Get the body of the Declaration.
+ /// \param[out] IsAutosynthesized Specifies if the body is auto-generated
+ /// by the BodyFarm.
+ Stmt *getBody(bool &IsAutosynthesized) const;
+
+ /// \brief Checks if the body of the Decl is generated by the BodyFarm.
+ ///
+ /// Note, the lookup is not free. We are going to call getBody behind
+ /// the scenes.
+ /// \sa getBody
+ bool isBodyAutosynthesized() const;
+
CFG *getCFG();
CFGStmtMap *getCFGStmtMap();
@@ -242,6 +256,8 @@ public:
virtual void Profile(llvm::FoldingSetNodeID &ID) = 0;
+ LLVM_ATTRIBUTE_USED void dumpStack() const;
+
public:
static void ProfileCommon(llvm::FoldingSetNodeID &ID,
ContextKind ck,
@@ -396,7 +412,8 @@ public:
bool addImplicitDtors = false,
bool addInitializers = false,
bool addTemporaryDtors = false,
- bool synthesizeBodies = false);
+ bool synthesizeBodies = false,
+ bool addStaticInitBranches = false);
~AnalysisDeclContextManager();
diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h
index 8cc5d81..ee0be73 100644
--- a/include/clang/Analysis/CFG.h
+++ b/include/clang/Analysis/CFG.h
@@ -15,15 +15,16 @@
#ifndef LLVM_CLANG_CFG_H
#define LLVM_CLANG_CFG_H
-#include "llvm/ADT/PointerIntPair.h"
-#include "llvm/ADT/GraphTraits.h"
-#include "llvm/Support/Allocator.h"
-#include "llvm/Support/Casting.h"
-#include "llvm/ADT/OwningPtr.h"
-#include "llvm/ADT/DenseMap.h"
#include "clang/AST/Stmt.h"
#include "clang/Analysis/Support/BumpVector.h"
#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/GraphTraits.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Casting.h"
#include <bitset>
#include <cassert>
#include <iterator>
@@ -48,7 +49,6 @@ class CFGElement {
public:
enum Kind {
// main kind
- Invalid,
Statement,
Initializer,
// dtor kind
@@ -69,8 +69,31 @@ protected:
: Data1(const_cast<void*>(Ptr1), ((unsigned) kind) & 0x3),
Data2(const_cast<void*>(Ptr2), (((unsigned) kind) >> 2) & 0x3) {}
-public:
CFGElement() {}
+public:
+
+ /// \brief Convert to the specified CFGElement type, asserting that this
+ /// CFGElement is of the desired type.
+ template<typename T>
+ T castAs() const {
+ assert(T::isKind(*this));
+ T t;
+ CFGElement& e = t;
+ e = *this;
+ return t;
+ }
+
+ /// \brief Convert to the specified CFGElement type, returning None if this
+ /// CFGElement is not of the desired type.
+ template<typename T>
+ Optional<T> getAs() const {
+ if (!T::isKind(*this))
+ return None;
+ T t;
+ CFGElement& e = t;
+ e = *this;
+ return t;
+ }
Kind getKind() const {
unsigned x = Data2.getInt();
@@ -78,16 +101,6 @@ public:
x |= Data1.getInt();
return (Kind) x;
}
-
- bool isValid() const { return getKind() != Invalid; }
-
- operator bool() const { return isValid(); }
-
- template<class ElemTy> const ElemTy *getAs() const {
- if (llvm::isa<ElemTy>(this))
- return static_cast<const ElemTy*>(this);
- return 0;
- }
};
class CFGStmt : public CFGElement {
@@ -98,8 +111,11 @@ public:
return static_cast<const Stmt *>(Data1.getPointer());
}
- static bool classof(const CFGElement *E) {
- return E->getKind() == Statement;
+private:
+ friend class CFGElement;
+ CFGStmt() {}
+ static bool isKind(const CFGElement &E) {
+ return E.getKind() == Statement;
}
};
@@ -114,8 +130,11 @@ public:
return static_cast<CXXCtorInitializer*>(Data1.getPointer());
}
- static bool classof(const CFGElement *E) {
- return E->getKind() == Initializer;
+private:
+ friend class CFGElement;
+ CFGInitializer() {}
+ static bool isKind(const CFGElement &E) {
+ return E.getKind() == Initializer;
}
};
@@ -123,6 +142,7 @@ public:
/// by compiler on various occasions.
class CFGImplicitDtor : public CFGElement {
protected:
+ CFGImplicitDtor() {}
CFGImplicitDtor(Kind kind, const void *data1, const void *data2 = 0)
: CFGElement(kind, data1, data2) {
assert(kind >= DTOR_BEGIN && kind <= DTOR_END);
@@ -132,8 +152,10 @@ public:
const CXXDestructorDecl *getDestructorDecl(ASTContext &astContext) const;
bool isNoReturn(ASTContext &astContext) const;
- static bool classof(const CFGElement *E) {
- Kind kind = E->getKind();
+private:
+ friend class CFGElement;
+ static bool isKind(const CFGElement &E) {
+ Kind kind = E.getKind();
return kind >= DTOR_BEGIN && kind <= DTOR_END;
}
};
@@ -155,8 +177,11 @@ public:
return static_cast<Stmt*>(Data2.getPointer());
}
- static bool classof(const CFGElement *elem) {
- return elem->getKind() == AutomaticObjectDtor;
+private:
+ friend class CFGElement;
+ CFGAutomaticObjDtor() {}
+ static bool isKind(const CFGElement &elem) {
+ return elem.getKind() == AutomaticObjectDtor;
}
};
@@ -171,8 +196,11 @@ public:
return static_cast<const CXXBaseSpecifier*>(Data1.getPointer());
}
- static bool classof(const CFGElement *E) {
- return E->getKind() == BaseDtor;
+private:
+ friend class CFGElement;
+ CFGBaseDtor() {}
+ static bool isKind(const CFGElement &E) {
+ return E.getKind() == BaseDtor;
}
};
@@ -187,8 +215,11 @@ public:
return static_cast<const FieldDecl*>(Data1.getPointer());
}
- static bool classof(const CFGElement *E) {
- return E->getKind() == MemberDtor;
+private:
+ friend class CFGElement;
+ CFGMemberDtor() {}
+ static bool isKind(const CFGElement &E) {
+ return E.getKind() == MemberDtor;
}
};
@@ -203,8 +234,11 @@ public:
return static_cast<const CXXBindTemporaryExpr *>(Data1.getPointer());
}
- static bool classof(const CFGElement *E) {
- return E->getKind() == TemporaryDtor;
+private:
+ friend class CFGElement;
+ CFGTemporaryDtor() {}
+ static bool isKind(const CFGElement &E) {
+ return E.getKind() == TemporaryDtor;
}
};
@@ -535,7 +569,7 @@ public:
// the elements beginning at the last position in prepared space.
iterator beginAutomaticObjDtorsInsert(iterator I, size_t Cnt,
BumpVectorContext &C) {
- return iterator(Elements.insert(I.base(), Cnt, CFGElement(), C));
+ return iterator(Elements.insert(I.base(), Cnt, CFGAutomaticObjDtor(0, 0), C));
}
iterator insertAutomaticObjDtor(iterator I, VarDecl *VD, Stmt *S) {
*I = CFGAutomaticObjDtor(VD, S);
@@ -567,6 +601,7 @@ public:
bool AddInitializers;
bool AddImplicitDtors;
bool AddTemporaryDtors;
+ bool AddStaticInitBranches;
bool alwaysAdd(const Stmt *stmt) const {
return alwaysAddMask[stmt->getStmtClass()];
@@ -587,7 +622,8 @@ public:
,AddEHEdges(false)
,AddInitializers(false)
,AddImplicitDtors(false)
- ,AddTemporaryDtors(false) {}
+ ,AddTemporaryDtors(false)
+ ,AddStaticInitBranches(false) {}
};
/// \brief Provides a custom implementation of the iterator class to have the
@@ -718,7 +754,7 @@ public:
for (const_iterator I=begin(), E=end(); I != E; ++I)
for (CFGBlock::const_iterator BI=(*I)->begin(), BE=(*I)->end();
BI != BE; ++BI) {
- if (const CFGStmt *stmt = BI->getAs<CFGStmt>())
+ if (Optional<CFGStmt> stmt = BI->getAs<CFGStmt>())
O(const_cast<Stmt*>(stmt->getStmt()));
}
}
@@ -807,17 +843,10 @@ namespace llvm {
/// Implement simplify_type for CFGTerminator, so that we can dyn_cast from
/// CFGTerminator to a specific Stmt class.
-template <> struct simplify_type<const ::clang::CFGTerminator> {
- typedef const ::clang::Stmt *SimpleType;
- static SimpleType getSimplifiedValue(const ::clang::CFGTerminator &Val) {
- return Val.getStmt();
- }
-};
-
template <> struct simplify_type< ::clang::CFGTerminator> {
typedef ::clang::Stmt *SimpleType;
- static SimpleType getSimplifiedValue(const ::clang::CFGTerminator &Val) {
- return const_cast<SimpleType>(Val.getStmt());
+ static SimpleType getSimplifiedValue(::clang::CFGTerminator Val) {
+ return Val.getStmt();
}
};
diff --git a/include/clang/Analysis/CallGraph.h b/include/clang/Analysis/CallGraph.h
index 509de7b..5015eb6 100644
--- a/include/clang/Analysis/CallGraph.h
+++ b/include/clang/Analysis/CallGraph.h
@@ -39,15 +39,9 @@ class CallGraph : public RecursiveASTVisitor<CallGraph> {
/// FunctionMap owns all CallGraphNodes.
FunctionMapTy FunctionMap;
- /// This is a virtual root node that has edges to all the global functions -
- /// 'main' or functions accessible from other translation units.
+ /// This is a virtual root node that has edges to all the functions.
CallGraphNode *Root;
- /// The list of nodes that have no parent. These are unreachable from Root.
- /// Declarations can get to this list due to impressions in the graph, for
- /// example, we do not track functions whose addresses were taken.
- llvm::SetVector<CallGraphNode *> ParentlessNodes;
-
public:
CallGraph();
~CallGraph();
@@ -91,34 +85,35 @@ public:
/// failing to add a call edge due to the analysis imprecision.
typedef llvm::SetVector<CallGraphNode *>::iterator nodes_iterator;
typedef llvm::SetVector<CallGraphNode *>::const_iterator const_nodes_iterator;
- nodes_iterator parentless_begin() { return ParentlessNodes.begin(); }
- nodes_iterator parentless_end() { return ParentlessNodes.end(); }
- const_nodes_iterator
- parentless_begin() const { return ParentlessNodes.begin(); }
- const_nodes_iterator
- parentless_end() const { return ParentlessNodes.end(); }
void print(raw_ostream &os) const;
void dump() const;
void viewGraph() const;
+ void addNodesForBlocks(DeclContext *D);
+
/// Part of recursive declaration visitation. We recursively visit all the
- /// Declarations to collect the root functions.
+ /// declarations to collect the root functions.
bool VisitFunctionDecl(FunctionDecl *FD) {
// We skip function template definitions, as their semantics is
// only determined when they are instantiated.
- if (includeInGraph(FD))
+ if (includeInGraph(FD)) {
+ // Add all blocks declared inside this function to the graph.
+ addNodesForBlocks(FD);
// If this function has external linkage, anything could call it.
// Note, we are not precise here. For example, the function could have
// its address taken.
addNodeForDecl(FD, FD->isGlobal());
+ }
return true;
}
/// Part of recursive declaration visitation.
bool VisitObjCMethodDecl(ObjCMethodDecl *MD) {
- if (includeInGraph(MD))
+ if (includeInGraph(MD)) {
+ addNodesForBlocks(MD);
addNodeForDecl(MD, true);
+ }
return true;
}
@@ -144,15 +139,13 @@ private:
Decl *FD;
/// \brief The list of functions called from this node.
- // Small vector might be more efficient since we are only tracking functions
- // whose definition is in the current TU.
- llvm::SmallVector<CallRecord, 5> CalledFunctions;
+ SmallVector<CallRecord, 5> CalledFunctions;
public:
CallGraphNode(Decl *D) : FD(D) {}
- typedef llvm::SmallVector<CallRecord, 5>::iterator iterator;
- typedef llvm::SmallVector<CallRecord, 5>::const_iterator const_iterator;
+ typedef SmallVector<CallRecord, 5>::iterator iterator;
+ typedef SmallVector<CallRecord, 5>::const_iterator const_iterator;
/// Iterators through all the callees/children of the node.
inline iterator begin() { return CalledFunctions.begin(); }
@@ -165,13 +158,10 @@ public:
void addCallee(CallGraphNode *N, CallGraph *CG) {
CalledFunctions.push_back(N);
- CG->ParentlessNodes.remove(N);
}
Decl *getDecl() const { return FD; }
- StringRef getName() const;
-
void print(raw_ostream &os) const;
void dump() const;
};
@@ -203,7 +193,7 @@ template <> struct GraphTraits<const clang::CallGraphNode*> {
typedef NodeType::const_iterator ChildIteratorType;
static NodeType *getEntryNode(const clang::CallGraphNode *CGN) { return CGN; }
static inline ChildIteratorType child_begin(NodeType *N) { return N->begin();}
- static inline ChildIteratorType child_end (NodeType *N) { return N->end(); }
+ static inline ChildIteratorType child_end(NodeType *N) { return N->end(); }
};
template <> struct GraphTraits<clang::CallGraph*>
diff --git a/include/clang/Analysis/FlowSensitive/DataflowSolver.h b/include/clang/Analysis/FlowSensitive/DataflowSolver.h
index 017da63..0f5e7bf 100644
--- a/include/clang/Analysis/FlowSensitive/DataflowSolver.h
+++ b/include/clang/Analysis/FlowSensitive/DataflowSolver.h
@@ -14,12 +14,12 @@
#ifndef LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER
#define LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER
+#include "functional" // STL
#include "clang/Analysis/CFG.h"
-#include "clang/Analysis/ProgramPoint.h"
#include "clang/Analysis/FlowSensitive/DataflowValues.h"
+#include "clang/Analysis/ProgramPoint.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
-#include "functional" // STL
namespace clang {
diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h
index 9479978..333329d 100644
--- a/include/clang/Analysis/ProgramPoint.h
+++ b/include/clang/Analysis/ProgramPoint.h
@@ -17,15 +17,16 @@
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/CFG.h"
-#include "llvm/Support/DataTypes.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/Support/Casting.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/DataTypes.h"
#include <cassert>
-#include <utility>
#include <string>
+#include <utility>
namespace clang {
@@ -71,9 +72,8 @@ private:
llvm::PointerIntPair<const ProgramPointTag *, 2, unsigned> Tag;
- ProgramPoint();
-
protected:
+ ProgramPoint() {}
ProgramPoint(const void *P,
Kind k,
const LocationContext *l,
@@ -110,6 +110,29 @@ public:
getLocationContext(), tag);
}
+ /// \brief Convert to the specified ProgramPoint type, asserting that this
+ /// ProgramPoint is of the desired type.
+ template<typename T>
+ T castAs() const {
+ assert(T::isKind(*this));
+ T t;
+ ProgramPoint& PP = t;
+ PP = *this;
+ return t;
+ }
+
+ /// \brief Convert to the specified ProgramPoint type, returning None if this
+ /// ProgramPoint is not of the desired type.
+ template<typename T>
+ Optional<T> getAs() const {
+ if (!T::isKind(*this))
+ return None;
+ T t;
+ ProgramPoint& PP = t;
+ PP = *this;
+ return t;
+ }
+
Kind getKind() const {
unsigned x = Tag.getInt();
x <<= 2;
@@ -179,13 +202,16 @@ public:
return reinterpret_cast<const CFGBlock*>(getData1());
}
- const CFGElement getFirstElement() const {
+ Optional<CFGElement> getFirstElement() const {
const CFGBlock *B = getBlock();
- return B->empty() ? CFGElement() : B->front();
+ return B->empty() ? Optional<CFGElement>() : B->front();
}
- static bool classof(const ProgramPoint* Location) {
- return Location->getKind() == BlockEntranceKind;
+private:
+ friend class ProgramPoint;
+ BlockEntrance() {}
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == BlockEntranceKind;
}
};
@@ -202,8 +228,11 @@ public:
return getBlock()->getTerminator();
}
- static bool classof(const ProgramPoint* Location) {
- return Location->getKind() == BlockExitKind;
+private:
+ friend class ProgramPoint;
+ BlockExit() {}
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == BlockExitKind;
}
};
@@ -218,10 +247,14 @@ public:
const Stmt *getStmt() const { return (const Stmt*) getData1(); }
template <typename T>
- const T* getStmtAs() const { return llvm::dyn_cast<T>(getStmt()); }
+ const T* getStmtAs() const { return dyn_cast<T>(getStmt()); }
- static bool classof(const ProgramPoint* Location) {
- unsigned k = Location->getKind();
+protected:
+ StmtPoint() {}
+private:
+ friend class ProgramPoint;
+ static bool isKind(const ProgramPoint &Location) {
+ unsigned k = Location.getKind();
return k >= PreStmtKind && k <= MaxPostStmtKind;
}
};
@@ -235,13 +268,17 @@ public:
const Stmt *getSubStmt() const { return (const Stmt*) getData2(); }
- static bool classof(const ProgramPoint* Location) {
- return Location->getKind() == PreStmtKind;
+private:
+ friend class ProgramPoint;
+ PreStmt() {}
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == PreStmtKind;
}
};
class PostStmt : public StmtPoint {
protected:
+ PostStmt() {}
PostStmt(const Stmt *S, const void *data, Kind k, const LocationContext *L,
const ProgramPointTag *tag = 0)
: StmtPoint(S, data, k, L, tag) {}
@@ -255,8 +292,10 @@ public:
const ProgramPointTag *tag = 0)
: StmtPoint(S, NULL, PostStmtKind, L, tag) {}
- static bool classof(const ProgramPoint* Location) {
- unsigned k = Location->getKind();
+private:
+ friend class ProgramPoint;
+ static bool isKind(const ProgramPoint &Location) {
+ unsigned k = Location.getKind();
return k >= MinPostStmtKind && k <= MaxPostStmtKind;
}
};
@@ -268,19 +307,25 @@ public:
const ProgramPointTag *tag = 0)
: PostStmt(S, PostConditionKind, L, tag) {}
- static bool classof(const ProgramPoint* Location) {
- return Location->getKind() == PostConditionKind;
+private:
+ friend class ProgramPoint;
+ PostCondition() {}
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == PostConditionKind;
}
};
class LocationCheck : public StmtPoint {
protected:
+ LocationCheck() {}
LocationCheck(const Stmt *S, const LocationContext *L,
ProgramPoint::Kind K, const ProgramPointTag *tag)
: StmtPoint(S, NULL, K, L, tag) {}
- static bool classof(const ProgramPoint *location) {
- unsigned k = location->getKind();
+private:
+ friend class ProgramPoint;
+ static bool isKind(const ProgramPoint &location) {
+ unsigned k = location.getKind();
return k == PreLoadKind || k == PreStoreKind;
}
};
@@ -291,8 +336,11 @@ public:
const ProgramPointTag *tag = 0)
: LocationCheck(S, L, PreLoadKind, tag) {}
- static bool classof(const ProgramPoint *location) {
- return location->getKind() == PreLoadKind;
+private:
+ friend class ProgramPoint;
+ PreLoad() {}
+ static bool isKind(const ProgramPoint &location) {
+ return location.getKind() == PreLoadKind;
}
};
@@ -302,8 +350,11 @@ public:
const ProgramPointTag *tag = 0)
: LocationCheck(S, L, PreStoreKind, tag) {}
- static bool classof(const ProgramPoint *location) {
- return location->getKind() == PreStoreKind;
+private:
+ friend class ProgramPoint;
+ PreStore() {}
+ static bool isKind(const ProgramPoint &location) {
+ return location.getKind() == PreStoreKind;
}
};
@@ -313,8 +364,11 @@ public:
const ProgramPointTag *tag = 0)
: PostStmt(S, PostLoadKind, L, tag) {}
- static bool classof(const ProgramPoint* Location) {
- return Location->getKind() == PostLoadKind;
+private:
+ friend class ProgramPoint;
+ PostLoad() {}
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == PostLoadKind;
}
};
@@ -331,16 +385,18 @@ public:
setData2(Loc);
}
- static bool classof(const ProgramPoint* Location) {
- return Location->getKind() == PostStoreKind;
- }
-
/// \brief Returns the information about the location used in the store,
/// how it was uttered in the code.
const void *getLocationValue() const {
return getData2();
}
+private:
+ friend class ProgramPoint;
+ PostStore() {}
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == PostStoreKind;
+ }
};
class PostLValue : public PostStmt {
@@ -349,8 +405,11 @@ public:
const ProgramPointTag *tag = 0)
: PostStmt(S, PostLValueKind, L, tag) {}
- static bool classof(const ProgramPoint* Location) {
- return Location->getKind() == PostLValueKind;
+private:
+ friend class ProgramPoint;
+ PostLValue() {}
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == PostLValueKind;
}
};
@@ -362,8 +421,11 @@ public:
const ProgramPointTag *tag = 0)
: StmtPoint(S, 0, PreStmtPurgeDeadSymbolsKind, L, tag) { }
- static bool classof(const ProgramPoint* Location) {
- return Location->getKind() == PreStmtPurgeDeadSymbolsKind;
+private:
+ friend class ProgramPoint;
+ PreStmtPurgeDeadSymbols() {}
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == PreStmtPurgeDeadSymbolsKind;
}
};
@@ -375,8 +437,11 @@ public:
const ProgramPointTag *tag = 0)
: StmtPoint(S, 0, PostStmtPurgeDeadSymbolsKind, L, tag) { }
- static bool classof(const ProgramPoint* Location) {
- return Location->getKind() == PostStmtPurgeDeadSymbolsKind;
+private:
+ friend class ProgramPoint;
+ PostStmtPurgeDeadSymbols() {}
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == PostStmtPurgeDeadSymbolsKind;
}
};
@@ -396,19 +461,40 @@ public:
return static_cast<const CFGBlock*>(getData2());
}
- static bool classof(const ProgramPoint* Location) {
- return Location->getKind() == BlockEdgeKind;
+private:
+ friend class ProgramPoint;
+ BlockEdge() {}
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == BlockEdgeKind;
}
};
class PostInitializer : public ProgramPoint {
public:
- PostInitializer(const CXXCtorInitializer *I,
+ /// \brief Construct a PostInitializer point that represents a location after
+ /// CXXCtorInitializer expression evaluation.
+ ///
+ /// \param I The initializer.
+ /// \param Loc The location of the field being initialized.
+ PostInitializer(const CXXCtorInitializer *I,
+ const void *Loc,
const LocationContext *L)
- : ProgramPoint(I, PostInitializerKind, L) {}
+ : ProgramPoint(I, Loc, PostInitializerKind, L) {}
+
+ const CXXCtorInitializer *getInitializer() const {
+ return static_cast<const CXXCtorInitializer *>(getData1());
+ }
- static bool classof(const ProgramPoint *Location) {
- return Location->getKind() == PostInitializerKind;
+ /// \brief Returns the location of the field.
+ const void *getLocationValue() const {
+ return getData2();
+ }
+
+private:
+ friend class ProgramPoint;
+ PostInitializer() {}
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == PostInitializerKind;
}
};
@@ -426,9 +512,13 @@ public:
return SourceLocation::getFromPtrEncoding(getData1());
}
- static bool classof(const ProgramPoint *Location) {
- return Location->getKind() >= MinImplicitCallKind &&
- Location->getKind() <= MaxImplicitCallKind;
+protected:
+ ImplicitCallPoint() {}
+private:
+ friend class ProgramPoint;
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() >= MinImplicitCallKind &&
+ Location.getKind() <= MaxImplicitCallKind;
}
};
@@ -441,8 +531,11 @@ public:
const LocationContext *L, const ProgramPointTag *Tag = 0)
: ImplicitCallPoint(D, Loc, PreImplicitCallKind, L, Tag) {}
- static bool classof(const ProgramPoint *Location) {
- return Location->getKind() == PreImplicitCallKind;
+private:
+ friend class ProgramPoint;
+ PreImplicitCall() {}
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == PreImplicitCallKind;
}
};
@@ -455,8 +548,11 @@ public:
const LocationContext *L, const ProgramPointTag *Tag = 0)
: ImplicitCallPoint(D, Loc, PostImplicitCallKind, L, Tag) {}
- static bool classof(const ProgramPoint *Location) {
- return Location->getKind() == PostImplicitCallKind;
+private:
+ friend class ProgramPoint;
+ PostImplicitCall() {}
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == PostImplicitCallKind;
}
};
@@ -476,8 +572,11 @@ public:
return static_cast<const StackFrameContext *>(getData2());
}
- static bool classof(const ProgramPoint *Location) {
- return Location->getKind() == CallEnterKind;
+private:
+ friend class ProgramPoint;
+ CallEnter() {}
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == CallEnterKind;
}
};
@@ -496,8 +595,11 @@ public:
CallExitBegin(const StackFrameContext *L)
: ProgramPoint(0, CallExitBeginKind, L, 0) {}
- static bool classof(const ProgramPoint *Location) {
- return Location->getKind() == CallExitBeginKind;
+private:
+ friend class ProgramPoint;
+ CallExitBegin() {}
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == CallExitBeginKind;
}
};
@@ -514,8 +616,11 @@ public:
return static_cast<const StackFrameContext *>(getData1());
}
- static bool classof(const ProgramPoint *Location) {
- return Location->getKind() == CallExitEndKind;
+private:
+ friend class ProgramPoint;
+ CallExitEnd() {}
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == CallExitEndKind;
}
};
@@ -529,8 +634,11 @@ public:
const void *getData() const { return getData1(); }
- static bool classof(const ProgramPoint* Location) {
- return Location->getKind() == EpsilonKind;
+private:
+ friend class ProgramPoint;
+ EpsilonPoint() {}
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == EpsilonKind;
}
};
@@ -544,7 +652,7 @@ public:
virtual StringRef getTagDescription() const = 0;
protected:
- /// Used to implement 'classof' in subclasses.
+ /// Used to implement 'isKind' in subclasses.
const void *getTagKind() { return TagKind; }
private:
diff --git a/include/clang/Analysis/Support/BlkExprDeclBitVector.h b/include/clang/Analysis/Support/BlkExprDeclBitVector.h
index d25b848..35cc799 100644
--- a/include/clang/Analysis/Support/BlkExprDeclBitVector.h
+++ b/include/clang/Analysis/Support/BlkExprDeclBitVector.h
@@ -17,8 +17,8 @@
#ifndef LLVM_CLANG_STMTDECLBVDVAL_H
#define LLVM_CLANG_STMTDECLBVDVAL_H
-#include "clang/Analysis/CFG.h"
#include "clang/AST/Decl.h" // for Decl* -> NamedDecl* conversion
+#include "clang/Analysis/CFG.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
diff --git a/include/clang/Analysis/Support/BumpVector.h b/include/clang/Analysis/Support/BumpVector.h
index 83532e6..387e779 100644
--- a/include/clang/Analysis/Support/BumpVector.h
+++ b/include/clang/Analysis/Support/BumpVector.h
@@ -19,9 +19,9 @@
#ifndef LLVM_CLANG_BUMP_VECTOR
#define LLVM_CLANG_BUMP_VECTOR
-#include "llvm/Support/type_traits.h"
-#include "llvm/Support/Allocator.h"
#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/type_traits.h"
#include <algorithm>
#include <cstring>
#include <iterator>
diff --git a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h
index c510e20..2bf3eda 100644
--- a/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h
+++ b/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h
@@ -17,10 +17,10 @@
#ifndef LLVM_CLANG_ANALYSIS_CFG_REC_STMT_DECL_VISITOR_H
#define LLVM_CLANG_ANALYSIS_CFG_REC_STMT_DECL_VISITOR_H
-#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h"
#include "clang/AST/Decl.h"
-#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h"
#define DISPATCH_CASE(CLASS) \
case Decl::CLASS: \
@@ -63,6 +63,7 @@ public:
DISPATCH_CASE(ImplicitParam)
DISPATCH_CASE(EnumConstant)
DISPATCH_CASE(Typedef)
+ DISPATCH_CASE(TypeAlias)
DISPATCH_CASE(Record) // FIXME: Refine. VisitStructDecl?
DISPATCH_CASE(CXXRecord)
DISPATCH_CASE(Enum)
@@ -82,6 +83,7 @@ public:
DEFAULT_DISPATCH(ImplicitParam)
DEFAULT_DISPATCH(EnumConstant)
DEFAULT_DISPATCH(Typedef)
+ DEFAULT_DISPATCH(TypeAlias)
DEFAULT_DISPATCH(Record)
DEFAULT_DISPATCH(Enum)
DEFAULT_DISPATCH(Field)
diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
index bfe8093..37aa332 100644
--- a/include/clang/Basic/Attr.td
+++ b/include/clang/Basic/Attr.td
@@ -29,8 +29,8 @@ class SubsetSubject<AttrSubject base, string description, code check>
code CheckCode = check;
}
-// This is the type of a variable which C++0x defines [[aligned()]] as being
-// a possible subject.
+// This is the type of a variable which C++11 allows alignas(...) to appertain
+// to.
def NormalVar : SubsetSubject<Var, "non-register, non-parameter variable",
[{S->getStorageClass() != VarDecl::Register &&
S->getKind() != Decl::ImplicitParam &&
@@ -91,6 +91,12 @@ class Declspec<string name> : Spelling<name, "Declspec">;
class CXX11<string namespace, string name> : Spelling<name, "CXX11"> {
string Namespace = namespace;
}
+class Keyword<string name> : Spelling<name, "Keyword">;
+
+class Accessor<string name, list<Spelling> spellings> {
+ string Name = name;
+ list<Spelling> Spellings = spellings;
+}
class Attr {
// The various ways in which an attribute can be spelled in source
@@ -99,8 +105,10 @@ class Attr {
list<AttrSubject> Subjects;
// The arguments allowed on an attribute
list<Argument> Args = [];
- // Set to true for attributes with arguments which require delayed parsing.
- bit LateParsed = 0;
+ // Accessors which should be generated for the attribute.
+ list<Accessor> Accessors = [];
+ // Set to true for attributes with arguments which require delayed parsing.
+ bit LateParsed = 0;
// Set to false to prevent an attribute from being propagated from a template
// to the instantiation.
bit Clone = 1;
@@ -114,7 +122,7 @@ class Attr {
bit Ignored = 0;
// Set to true if each of the spellings is a distinct attribute.
bit DistinctSpellings = 0;
- // Any additional text that should be included verbatim in the class.
+ // Any additional text that should be included verbatim in the class.
code AdditionalMembers = [{}];
}
@@ -125,6 +133,13 @@ class InheritableAttr : Attr;
/// redeclarations, even when it's written on a parameter.
class InheritableParamAttr : InheritableAttr;
+/// An ignored attribute, which we parse but discard with no checking.
+class IgnoredAttr : Attr {
+ let Ignored = 1;
+ let ASTNode = 0;
+ let SemaHandler = 0;
+}
+
//
// Attributes begin here
//
@@ -132,18 +147,24 @@ class InheritableParamAttr : InheritableAttr;
def AddressSpace : Attr {
let Spellings = [GNU<"address_space">];
let Args = [IntArgument<"AddressSpace">];
- let ASTNode = 0;
+ let ASTNode = 0;
}
def Alias : InheritableAttr {
- let Spellings = [GNU<"alias">];
+ let Spellings = [GNU<"alias">, CXX11<"gnu", "alias">];
let Args = [StringArgument<"Aliasee">];
}
def Aligned : InheritableAttr {
- let Spellings = [GNU<"aligned">, GNU<"align">];
+ let Spellings = [GNU<"aligned">, Declspec<"align">, CXX11<"gnu", "aligned">,
+ Keyword<"alignas">, Keyword<"_Alignas">];
let Subjects = [NonBitField, NormalVar, Tag];
- let Args = [AlignedArgument<"Alignment">, BoolArgument<"IsMSDeclSpec">];
+ let Args = [AlignedArgument<"Alignment">];
+ let Accessors = [Accessor<"isGNU", [GNU<"aligned">, CXX11<"gnu","aligned">]>,
+ Accessor<"isC11", [Keyword<"_Alignas">]>,
+ Accessor<"isAlignas", [Keyword<"alignas">,
+ Keyword<"_Alignas">]>,
+ Accessor<"isDeclspec",[Declspec<"align">]>];
}
def AlignMac68k : InheritableAttr {
@@ -152,16 +173,16 @@ def AlignMac68k : InheritableAttr {
}
def AllocSize : Attr {
- let Spellings = [GNU<"alloc_size">];
+ let Spellings = [GNU<"alloc_size">, CXX11<"gnu", "alloc_size">];
let Args = [VariadicUnsignedArgument<"Args">];
}
def AlwaysInline : InheritableAttr {
- let Spellings = [GNU<"always_inline">];
+ let Spellings = [GNU<"always_inline">, CXX11<"gnu", "always_inline">];
}
def TLSModel : InheritableAttr {
- let Spellings = [GNU<"tls_model">];
+ let Spellings = [GNU<"tls_model">, CXX11<"gnu", "tls_model">];
let Subjects = [Var];
let Args = [StringArgument<"Model">];
}
@@ -200,11 +221,8 @@ def Blocks : InheritableAttr {
let Args = [EnumArgument<"Type", "BlockType", ["byref"], ["ByRef"]>];
}
-def Bounded : Attr {
+def Bounded : IgnoredAttr {
let Spellings = [GNU<"bounded">];
- let ASTNode = 0;
- let SemaHandler = 0;
- let Ignored = 1;
}
def CarriesDependency : InheritableParamAttr {
@@ -214,7 +232,8 @@ def CarriesDependency : InheritableParamAttr {
}
def CDecl : InheritableAttr {
- let Spellings = [GNU<"cdecl">, GNU<"__cdecl">];
+ let Spellings = [GNU<"cdecl">, CXX11<"gnu", "cdecl">, Keyword<"__cdecl">,
+ Keyword<"_cdecl">];
}
// cf_audited_transfer indicates that the given function has been
@@ -234,11 +253,6 @@ def CFUnknownTransfer : InheritableAttr {
let Subjects = [Function];
}
-def CFReturnsAutoreleased : Attr {
- let Spellings = [GNU<"cf_returns_autoreleased">];
- let ASTNode = 0;
-}
-
def CFReturnsRetained : InheritableAttr {
let Spellings = [GNU<"cf_returns_retained">];
let Subjects = [ObjCMethod, Function];
@@ -255,24 +269,24 @@ def CFConsumed : InheritableParamAttr {
}
def Cleanup : InheritableAttr {
- let Spellings = [GNU<"cleanup">];
+ let Spellings = [GNU<"cleanup">, CXX11<"gnu", "cleanup">];
let Args = [FunctionArgument<"FunctionDecl">];
}
def Cold : InheritableAttr {
- let Spellings = [GNU<"cold">];
+ let Spellings = [GNU<"cold">, CXX11<"gnu", "cold">];
}
def Common : InheritableAttr {
- let Spellings = [GNU<"common">];
+ let Spellings = [GNU<"common">, CXX11<"gnu", "common">];
}
def Const : InheritableAttr {
- let Spellings = [GNU<"const">, GNU<"__const">];
+ let Spellings = [GNU<"const">, GNU<"__const">, CXX11<"gnu", "const">];
}
def Constructor : InheritableAttr {
- let Spellings = [GNU<"constructor">];
+ let Spellings = [GNU<"constructor">, CXX11<"gnu", "constructor">];
let Args = [IntArgument<"Priority">];
}
@@ -301,23 +315,33 @@ def CUDAShared : InheritableAttr {
let Spellings = [GNU<"shared">];
}
+def C11NoReturn : InheritableAttr {
+ let Spellings = [Keyword<"_Noreturn">];
+ let Subjects = [Function];
+ let SemaHandler = 0;
+}
+
+def CXX11NoReturn : InheritableAttr {
+ let Spellings = [CXX11<"","noreturn">, CXX11<"std","noreturn">];
+ let Subjects = [Function];
+}
+
def OpenCLKernel : Attr {
- let Spellings = [GNU<"opencl_kernel_function">];
+ let Spellings = [Keyword<"__kernel">, Keyword<"kernel">];
}
def OpenCLImageAccess : Attr {
let Spellings = [GNU<"opencl_image_access">];
let Args = [IntArgument<"Access">];
- let ASTNode = 0;
}
def Deprecated : InheritableAttr {
- let Spellings = [GNU<"deprecated">];
+ let Spellings = [GNU<"deprecated">, CXX11<"gnu", "deprecated">];
let Args = [StringArgument<"Message">];
}
def Destructor : InheritableAttr {
- let Spellings = [GNU<"destructor">];
+ let Spellings = [GNU<"destructor">, CXX11<"gnu", "destructor">];
let Args = [IntArgument<"Priority">];
}
@@ -328,12 +352,13 @@ def ExtVectorType : Attr {
}
def FallThrough : Attr {
- let Spellings = [CXX11<"clang","fallthrough">];
+ let Spellings = [CXX11<"clang", "fallthrough">];
let Subjects = [NullStmt];
}
def FastCall : InheritableAttr {
- let Spellings = [GNU<"fastcall">, GNU<"__fastcall">];
+ let Spellings = [GNU<"fastcall">, CXX11<"gnu", "fastcall">,
+ Keyword<"__fastcall">, Keyword<"_fastcall">];
}
def Final : InheritableAttr {
@@ -347,22 +372,22 @@ def MinSize : InheritableAttr {
}
def Format : InheritableAttr {
- let Spellings = [GNU<"format">];
+ let Spellings = [GNU<"format">, CXX11<"gnu", "format">];
let Args = [StringArgument<"Type">, IntArgument<"FormatIdx">,
IntArgument<"FirstArg">];
}
def FormatArg : InheritableAttr {
- let Spellings = [GNU<"format_arg">];
+ let Spellings = [GNU<"format_arg">, CXX11<"gnu", "format_arg">];
let Args = [IntArgument<"FormatIdx">];
}
def GNUInline : InheritableAttr {
- let Spellings = [GNU<"gnu_inline">];
+ let Spellings = [GNU<"gnu_inline">, CXX11<"gnu", "gnu_inline">];
}
def Hot : InheritableAttr {
- let Spellings = [GNU<"hot">];
+ let Spellings = [GNU<"hot">, CXX11<"gnu", "hot">];
}
def IBAction : InheritableAttr {
@@ -379,7 +404,7 @@ def IBOutletCollection : InheritableAttr {
}
def Malloc : InheritableAttr {
- let Spellings = [GNU<"malloc">];
+ let Spellings = [GNU<"malloc">, CXX11<"gnu", "malloc">];
}
def MaxFieldAlignment : InheritableAttr {
@@ -389,7 +414,7 @@ def MaxFieldAlignment : InheritableAttr {
}
def MayAlias : InheritableAttr {
- let Spellings = [GNU<"may_alias">];
+ let Spellings = [GNU<"may_alias">, CXX11<"gnu", "may_alias">];
}
def MSP430Interrupt : InheritableAttr {
@@ -408,14 +433,19 @@ def MBlazeSaveVolatiles : InheritableAttr {
let SemaHandler = 0;
}
+def Mips16 : InheritableAttr {
+ let Spellings = [GNU<"mips16">, CXX11<"gnu", "mips16">];
+ let Subjects = [Function];
+}
+
def Mode : Attr {
- let Spellings = [GNU<"mode">];
+ let Spellings = [GNU<"mode">, CXX11<"gnu", "mode">];
let Args = [IdentifierArgument<"Mode">];
let ASTNode = 0;
}
def Naked : InheritableAttr {
- let Spellings = [GNU<"naked">];
+ let Spellings = [GNU<"naked">, CXX11<"gnu", "naked">];
}
def NeonPolyVectorType : Attr {
@@ -431,11 +461,11 @@ def NeonVectorType : Attr {
}
def ReturnsTwice : InheritableAttr {
- let Spellings = [GNU<"returns_twice">];
+ let Spellings = [GNU<"returns_twice">, CXX11<"gnu", "returns_twice">];
}
def NoCommon : InheritableAttr {
- let Spellings = [GNU<"nocommon">];
+ let Spellings = [GNU<"nocommon">, CXX11<"gnu", "nocommon">];
}
def NoDebug : InheritableAttr {
@@ -443,11 +473,16 @@ def NoDebug : InheritableAttr {
}
def NoInline : InheritableAttr {
- let Spellings = [GNU<"noinline">];
+ let Spellings = [GNU<"noinline">, CXX11<"gnu", "noinline">];
+}
+
+def NoMips16 : InheritableAttr {
+ let Spellings = [GNU<"nomips16">, CXX11<"gnu", "nomips16">];
+ let Subjects = [Function];
}
def NonNull : InheritableAttr {
- let Spellings = [GNU<"nonnull">];
+ let Spellings = [GNU<"nonnull">, CXX11<"gnu", "nonnull">];
let Args = [VariadicUnsignedArgument<"Args">];
let AdditionalMembers =
[{bool isNonNull(unsigned idx) const {
@@ -460,19 +495,19 @@ def NonNull : InheritableAttr {
}
def NoReturn : InheritableAttr {
- let Spellings = [GNU<"noreturn">, CXX11<"","noreturn">,
- CXX11<"std","noreturn">];
+ let Spellings = [GNU<"noreturn">, CXX11<"gnu", "noreturn">];
// FIXME: Does GCC allow this on the function instead?
let Subjects = [Function];
}
def NoInstrumentFunction : InheritableAttr {
- let Spellings = [GNU<"no_instrument_function">];
+ let Spellings = [GNU<"no_instrument_function">,
+ CXX11<"gnu", "no_instrument_function">];
let Subjects = [Function];
}
def NoThrow : InheritableAttr {
- let Spellings = [GNU<"nothrow">];
+ let Spellings = [GNU<"nothrow">, CXX11<"gnu", "nothrow">];
}
def NSBridged : InheritableAttr {
@@ -563,26 +598,30 @@ def Ownership : InheritableAttr {
}
def Packed : InheritableAttr {
- let Spellings = [GNU<"packed">];
+ let Spellings = [GNU<"packed">, CXX11<"gnu", "packed">];
}
def PnaclCall : InheritableAttr {
let Spellings = [GNU<"pnaclcall">];
}
+def IntelOclBicc : InheritableAttr {
+ let Spellings = [GNU<"intel_ocl_bicc">];
+}
+
def Pcs : InheritableAttr {
- let Spellings = [GNU<"pcs">];
+ let Spellings = [GNU<"pcs">, CXX11<"gnu", "pcs">];
let Args = [EnumArgument<"PCS", "PCSType",
["aapcs", "aapcs-vfp"],
["AAPCS", "AAPCS_VFP"]>];
}
def Pure : InheritableAttr {
- let Spellings = [GNU<"pure">];
+ let Spellings = [GNU<"pure">, CXX11<"gnu", "pure">];
}
def Regparm : InheritableAttr {
- let Spellings = [GNU<"regparm">];
+ let Spellings = [GNU<"regparm">, CXX11<"gnu", "regparm">];
let Args = [UnsignedArgument<"NumParams">];
}
@@ -592,6 +631,11 @@ def ReqdWorkGroupSize : InheritableAttr {
UnsignedArgument<"ZDim">];
}
+def Endian : InheritableAttr {
+ let Spellings = [GNU<"endian">];
+ let Args = [IdentifierArgument<"platform">];
+}
+
def WorkGroupSizeHint : InheritableAttr {
let Spellings = [GNU<"work_group_size_hint">];
let Args = [UnsignedArgument<"XDim">,
@@ -605,30 +649,32 @@ def InitPriority : InheritableAttr {
}
def Section : InheritableAttr {
- let Spellings = [GNU<"section">];
+ let Spellings = [GNU<"section">, CXX11<"gnu", "section">];
let Args = [StringArgument<"Name">];
}
def Sentinel : InheritableAttr {
- let Spellings = [GNU<"sentinel">];
+ let Spellings = [GNU<"sentinel">, CXX11<"gnu", "sentinel">];
let Args = [DefaultIntArgument<"Sentinel", 0>,
DefaultIntArgument<"NullPos", 0>];
}
def StdCall : InheritableAttr {
- let Spellings = [GNU<"stdcall">, GNU<"__stdcall">];
+ let Spellings = [GNU<"stdcall">, CXX11<"gnu", "stdcall">,
+ Keyword<"__stdcall">, Keyword<"_stdcall">];
}
def ThisCall : InheritableAttr {
- let Spellings = [GNU<"thiscall">, GNU<"__thiscall">];
+ let Spellings = [GNU<"thiscall">, CXX11<"gnu", "thiscall">,
+ Keyword<"__thiscall">, Keyword<"_thiscall">];
}
def Pascal : InheritableAttr {
- let Spellings = [GNU<"pascal">];
+ let Spellings = [GNU<"pascal">, Keyword<"__pascal">, Keyword<"_pascal">];
}
def TransparentUnion : InheritableAttr {
- let Spellings = [GNU<"transparent_union">];
+ let Spellings = [GNU<"transparent_union">, CXX11<"gnu", "transparent_union">];
}
def Unavailable : InheritableAttr {
@@ -659,11 +705,11 @@ def ObjCRequiresPropertyDefs : InheritableAttr {
}
def Unused : InheritableAttr {
- let Spellings = [GNU<"unused">];
+ let Spellings = [GNU<"unused">, CXX11<"gnu", "unused">];
}
def Used : InheritableAttr {
- let Spellings = [GNU<"used">];
+ let Spellings = [GNU<"used">, CXX11<"gnu", "used">];
}
def Uuid : InheritableAttr {
@@ -673,21 +719,27 @@ def Uuid : InheritableAttr {
}
def VectorSize : Attr {
- let Spellings = [GNU<"vector_size">];
+ let Spellings = [GNU<"vector_size">, CXX11<"gnu", "vector_size">];
let Args = [ExprArgument<"NumBytes">];
let ASTNode = 0;
}
-def VecTypeHint : Attr {
+def VecTypeHint : InheritableAttr {
let Spellings = [GNU<"vec_type_hint">];
- let ASTNode = 0;
- let SemaHandler = 0;
- let Ignored = 1;
+ let Args = [TypeArgument<"TypeHint">, SourceLocArgument<"TypeLoc">];
}
def Visibility : InheritableAttr {
let Clone = 0;
- let Spellings = [GNU<"visibility">];
+ let Spellings = [GNU<"visibility">, CXX11<"gnu", "visibility">];
+ let Args = [EnumArgument<"Visibility", "VisibilityType",
+ ["default", "hidden", "internal", "protected"],
+ ["Default", "Hidden", "Hidden", "Protected"]>];
+}
+
+def TypeVisibility : InheritableAttr {
+ let Clone = 0;
+ let Spellings = [GNU<"type_visibility">, CXX11<"clang", "type_visibility">];
let Args = [EnumArgument<"Visibility", "VisibilityType",
["default", "hidden", "internal", "protected"],
["Default", "Hidden", "Hidden", "Protected"]>];
@@ -699,11 +751,13 @@ def VecReturn : InheritableAttr {
}
def WarnUnusedResult : InheritableAttr {
- let Spellings = [GNU<"warn_unused_result">];
+ let Spellings = [GNU<"warn_unused_result">,
+ CXX11<"clang", "warn_unused_result">,
+ CXX11<"gnu", "warn_unused_result">];
}
def Weak : InheritableAttr {
- let Spellings = [GNU<"weak">];
+ let Spellings = [GNU<"weak">, CXX11<"gnu", "weak">];
}
def WeakImport : InheritableAttr {
@@ -711,16 +765,27 @@ def WeakImport : InheritableAttr {
}
def WeakRef : InheritableAttr {
- let Spellings = [GNU<"weakref">];
+ let Spellings = [GNU<"weakref">, CXX11<"gnu", "weakref">];
}
def X86ForceAlignArgPointer : InheritableAttr {
let Spellings = [];
}
-// AddressSafety attribute (e.g. for AddressSanitizer)
-def NoAddressSafetyAnalysis : InheritableAttr {
- let Spellings = [GNU<"no_address_safety_analysis">];
+// Attribute to disable AddressSanitizer (or equivalent) checks.
+def NoSanitizeAddress : InheritableAttr {
+ let Spellings = [GNU<"no_address_safety_analysis">,
+ GNU<"no_sanitize_address">];
+}
+
+// Attribute to disable ThreadSanitizer checks.
+def NoSanitizeThread : InheritableAttr {
+ let Spellings = [GNU<"no_sanitize_thread">];
+}
+
+// Attribute to disable MemorySanitizer checks.
+def NoSanitizeMemory : InheritableAttr {
+ let Spellings = [GNU<"no_sanitize_memory">];
}
// C/C++ Thread safety attributes (e.g. for deadlock, data race checking)
@@ -876,29 +941,41 @@ def DLLImport : InheritableAttr {
}
def ForceInline : InheritableAttr {
- let Spellings = [Declspec<"__forceinline">];
+ let Spellings = [Keyword<"__forceinline">];
}
def Win64 : InheritableAttr {
- let Spellings = [Declspec<"w64">];
+ let Spellings = [Keyword<"__w64">];
}
def Ptr32 : InheritableAttr {
- let Spellings = [Declspec<"__ptr32">];
+ let Spellings = [Keyword<"__ptr32">];
}
def Ptr64 : InheritableAttr {
- let Spellings = [Declspec<"__ptr64">];
+ let Spellings = [Keyword<"__ptr64">];
}
-def SingleInheritance : InheritableAttr {
- let Spellings = [Declspec<"__single_inheritance">];
+class MSInheritanceAttr : InheritableAttr;
+
+def SingleInheritance : MSInheritanceAttr {
+ let Spellings = [Keyword<"__single_inheritance">];
+}
+
+def MultipleInheritance : MSInheritanceAttr {
+ let Spellings = [Keyword<"__multiple_inheritance">];
}
-def MultipleInheritance : InheritableAttr {
- let Spellings = [Declspec<"__multiple_inheritance">];
+def VirtualInheritance : MSInheritanceAttr {
+ let Spellings = [Keyword<"__virtual_inheritance">];
+}
+
+// This attribute doesn't have any spellings, but we can apply it implicitly to
+// incomplete types that lack any of the other attributes.
+def UnspecifiedInheritance : MSInheritanceAttr {
+ let Spellings = [];
}
-def VirtualInheritance : InheritableAttr {
- let Spellings = [Declspec<"__virtual_inheritance">];
+def Unaligned : IgnoredAttr {
+ let Spellings = [Keyword<"__unaligned">];
}
diff --git a/include/clang/Basic/AttrKinds.h b/include/clang/Basic/AttrKinds.h
index 150a30e..bd090ec 100644
--- a/include/clang/Basic/AttrKinds.h
+++ b/include/clang/Basic/AttrKinds.h
@@ -24,6 +24,7 @@ enum Kind {
#define ATTR(X) X,
#define LAST_INHERITABLE_ATTR(X) X, LAST_INHERITABLE = X,
#define LAST_INHERITABLE_PARAM_ATTR(X) X, LAST_INHERITABLE_PARAM = X,
+#define LAST_MS_INHERITABLE_ATTR(X) X, LAST_MS_INHERITABLE = X,
#include "clang/Basic/AttrList.inc"
NUM_ATTRS
};
diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def
index d48eadc..0a513ef 100644
--- a/include/clang/Basic/Builtins.def
+++ b/include/clang/Basic/Builtins.def
@@ -31,6 +31,7 @@
// F -> constant CFString
// G -> id
// H -> SEL
+// M -> struct objc_super
// a -> __builtin_va_list
// A -> "reference" to __builtin_va_list
// V -> Vector, followed by the number of elements and the base type.
@@ -81,6 +82,7 @@
// through an ellipsis
// e -> const, but only when -fmath-errno=0
// j -> returns_twice (like setjmp)
+// u -> arguments are not evaluated for their side-effects
// FIXME: gcc has nonnull
#if defined(BUILTIN) && !defined(LIBBUILTIN)
@@ -394,8 +396,8 @@ BUILTIN(__builtin_bswap32, "UiUi", "nc")
BUILTIN(__builtin_bswap64, "ULLiULLi", "nc")
// Random GCC builtins
-BUILTIN(__builtin_constant_p, "i.", "nct")
-BUILTIN(__builtin_classify_type, "i.", "nct")
+BUILTIN(__builtin_constant_p, "i.", "nctu")
+BUILTIN(__builtin_classify_type, "i.", "nctu")
BUILTIN(__builtin___CFStringMakeConstantString, "FC*cC*", "nc")
BUILTIN(__builtin___NSStringMakeConstantString, "FC*cC*", "nc")
BUILTIN(__builtin_va_start, "vA.", "nt")
@@ -453,17 +455,17 @@ BUILTIN(__builtin_dwarf_sp_column, "Ui", "n")
BUILTIN(__builtin_extend_pointer, "ULLiv*", "n") // _Unwind_Word == uint64_t
// GCC Object size checking builtins
-BUILTIN(__builtin_object_size, "zvC*i", "n")
+BUILTIN(__builtin_object_size, "zvC*i", "nu")
BUILTIN(__builtin___memcpy_chk, "v*v*vC*zz", "nF")
-BUILTIN(__builtin___memccpy_chk, "v*v*vC*iz", "nF")
+BUILTIN(__builtin___memccpy_chk, "v*v*vC*izz", "nF")
BUILTIN(__builtin___memmove_chk, "v*v*vC*zz", "nF")
BUILTIN(__builtin___mempcpy_chk, "v*v*vC*zz", "nF")
BUILTIN(__builtin___memset_chk, "v*v*izz", "nF")
BUILTIN(__builtin___stpcpy_chk, "c*c*cC*z", "nF")
BUILTIN(__builtin___strcat_chk, "c*c*cC*z", "nF")
BUILTIN(__builtin___strcpy_chk, "c*c*cC*z", "nF")
-BUILTIN(__builtin___strlcat_chk, "c*c*cC*zz", "nF")
-BUILTIN(__builtin___strlcpy_chk, "c*c*cC*zz", "nF")
+BUILTIN(__builtin___strlcat_chk, "zc*cC*zz", "nF")
+BUILTIN(__builtin___strlcpy_chk, "zc*cC*zz", "nF")
BUILTIN(__builtin___strncat_chk, "c*c*cC*zz", "nF")
BUILTIN(__builtin___strncpy_chk, "c*c*cC*zz", "nF")
BUILTIN(__builtin___stpncpy_chk, "c*c*cC*zz", "nF")
@@ -760,17 +762,16 @@ LIBBUILTIN(strlcpy, "zc*cC*z", "f", "string.h", ALL_LANGUAGES)
LIBBUILTIN(strlcat, "zc*cC*z", "f", "string.h", ALL_LANGUAGES)
// id objc_msgSend(id, SEL, ...)
LIBBUILTIN(objc_msgSend, "GGH.", "f", "objc/message.h", OBJC_LANG)
-
// long double objc_msgSend_fpret(id self, SEL op, ...)
LIBBUILTIN(objc_msgSend_fpret, "LdGH.", "f", "objc/message.h", OBJC_LANG)
// _Complex long double objc_msgSend_fp2ret(id self, SEL op, ...)
LIBBUILTIN(objc_msgSend_fp2ret, "XLdGH.", "f", "objc/message.h", OBJC_LANG)
-// id objc_msgSend_stret (id, SEL, ...)
-LIBBUILTIN(objc_msgSend_stret, "GGH.", "f", "objc/message.h", OBJC_LANG)
+// void objc_msgSend_stret (id, SEL, ...)
+LIBBUILTIN(objc_msgSend_stret, "vGH.", "f", "objc/message.h", OBJC_LANG)
// id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
-LIBBUILTIN(objc_msgSendSuper, "Gv*H.", "f", "objc/message.h", OBJC_LANG)
+LIBBUILTIN(objc_msgSendSuper, "GM*H.", "f", "objc/message.h", OBJC_LANG)
// void objc_msgSendSuper_stret(struct objc_super *super, SEL op, ...)
-LIBBUILTIN(objc_msgSendSuper_stret, "vv*H.", "f", "objc/message.h", OBJC_LANG)
+LIBBUILTIN(objc_msgSendSuper_stret, "vM*H.", "f", "objc/message.h", OBJC_LANG)
// id objc_getClass(const char *name)
LIBBUILTIN(objc_getClass, "GcC*", "f", "objc/runtime.h", OBJC_LANG)
// id objc_getMetaClass(const char *name)
@@ -833,6 +834,14 @@ LIBBUILTIN(ceil, "dd", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(ceill, "LdLd", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(ceilf, "ff", "fc", "math.h", ALL_LANGUAGES)
+LIBBUILTIN(cimag, "dXd", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(cimagf, "fXf", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(cimagl, "LdXLd", "fnc", "complex.h", ALL_LANGUAGES)
+
+LIBBUILTIN(creal, "dXd", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(crealf, "fXf", "fnc", "complex.h", ALL_LANGUAGES)
+LIBBUILTIN(creall, "LdXLd", "fnc", "complex.h", ALL_LANGUAGES)
+
LIBBUILTIN(copysign, "ddd", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(copysignl, "LdLdLd", "fc", "math.h", ALL_LANGUAGES)
LIBBUILTIN(copysignf, "fff", "fc", "math.h", ALL_LANGUAGES)
@@ -917,5 +926,15 @@ LIBBUILTIN(_Block_object_dispose, "vvC*iC", "f", "Blocks.h", ALL_LANGUAGES)
// Annotation function
BUILTIN(__builtin_annotation, "v.", "tn")
+// Multiprecision Arithmetic Builtins.
+BUILTIN(__builtin_addcs, "UsUsCUsCUsCUs*", "n")
+BUILTIN(__builtin_addc, "UiUiCUiCUiCUi*", "n")
+BUILTIN(__builtin_addcl, "ULiULiCULiCULiCULi*", "n")
+BUILTIN(__builtin_addcll, "ULLiULLiCULLiCULLiCULLi*", "n")
+BUILTIN(__builtin_subcs, "UsUsCUsCUsCUs*", "n")
+BUILTIN(__builtin_subc, "UiUiCUiCUiCUi*", "n")
+BUILTIN(__builtin_subcl, "ULiULiCULiCULiCULi*", "n")
+BUILTIN(__builtin_subcll, "ULLiULLiCULLiCULLiCULLi*", "n")
+
#undef BUILTIN
#undef LIBBUILTIN
diff --git a/include/clang/Basic/Builtins.h b/include/clang/Basic/Builtins.h
index 257daf1..3b88e15 100644
--- a/include/clang/Basic/Builtins.h
+++ b/include/clang/Basic/Builtins.h
@@ -109,6 +109,12 @@ public:
return strchr(GetRecord(ID).Attributes, 'j') != 0;
}
+ /// \brief Returns true if this builtin does not perform the side-effects
+ /// of its arguments.
+ bool isUnevaluated(unsigned ID) const {
+ return strchr(GetRecord(ID).Attributes, 'u') != 0;
+ }
+
/// \brief Return true if this is a builtin for a libc/libm function,
/// with a "__builtin_" prefix (e.g. __builtin_abs).
bool isLibFunction(unsigned ID) const {
diff --git a/include/clang/Basic/BuiltinsX86.def b/include/clang/Basic/BuiltinsX86.def
index 5b46f8e..d536821 100644
--- a/include/clang/Basic/BuiltinsX86.def
+++ b/include/clang/Basic/BuiltinsX86.def
@@ -624,6 +624,11 @@ BUILTIN(__builtin_ia32_rdrand16_step, "UiUs*", "")
BUILTIN(__builtin_ia32_rdrand32_step, "UiUi*", "")
BUILTIN(__builtin_ia32_rdrand64_step, "UiULLi*", "")
+// RDSEED
+BUILTIN(__builtin_ia32_rdseed16_step, "UiUs*", "")
+BUILTIN(__builtin_ia32_rdseed32_step, "UiUi*", "")
+BUILTIN(__builtin_ia32_rdseed64_step, "UiULLi*", "")
+
// BMI
BUILTIN(__builtin_ia32_bextr_u32, "UiUiUi", "")
BUILTIN(__builtin_ia32_bextr_u64, "ULLiULLiULLi", "")
@@ -739,5 +744,6 @@ BUILTIN(__builtin_ia32_vfrczpd256, "V4dV4d", "")
BUILTIN(__builtin_ia32_xbegin, "i", "")
BUILTIN(__builtin_ia32_xend, "v", "")
BUILTIN(__builtin_ia32_xabort, "vIc", "")
+BUILTIN(__builtin_ia32_xtest, "i", "")
#undef BUILTIN
diff --git a/include/clang/Basic/CharInfo.h b/include/clang/Basic/CharInfo.h
new file mode 100644
index 0000000..d0afda4
--- /dev/null
+++ b/include/clang/Basic/CharInfo.h
@@ -0,0 +1,198 @@
+//===--- clang/Basic/CharInfo.h - Classifying ASCII Characters ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_BASIC_CHARINFO_H
+#define CLANG_BASIC_CHARINFO_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/DataTypes.h"
+
+namespace clang {
+namespace charinfo {
+ extern const uint16_t InfoTable[256];
+
+ enum {
+ CHAR_HORZ_WS = 0x0001, // '\t', '\f', '\v'. Note, no '\0'
+ CHAR_VERT_WS = 0x0002, // '\r', '\n'
+ CHAR_SPACE = 0x0004, // ' '
+ CHAR_DIGIT = 0x0008, // 0-9
+ CHAR_XLETTER = 0x0010, // a-f,A-F
+ CHAR_UPPER = 0x0020, // A-Z
+ CHAR_LOWER = 0x0040, // a-z
+ CHAR_UNDER = 0x0080, // _
+ CHAR_PERIOD = 0x0100, // .
+ CHAR_RAWDEL = 0x0200, // {}[]#<>%:;?*+-/^&|~!=,"'
+ CHAR_PUNCT = 0x0400 // `$@()
+ };
+
+ enum {
+ CHAR_XUPPER = CHAR_XLETTER | CHAR_UPPER,
+ CHAR_XLOWER = CHAR_XLETTER | CHAR_LOWER
+ };
+} // end namespace charinfo
+
+/// Returns true if this is an ASCII character.
+LLVM_READNONE static inline bool isASCII(char c) {
+ return static_cast<unsigned char>(c) <= 127;
+}
+
+/// Returns true if this is a valid first character of a C identifier,
+/// which is [a-zA-Z_].
+LLVM_READONLY static inline bool isIdentifierHead(unsigned char c,
+ bool AllowDollar = false) {
+ using namespace charinfo;
+ if (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_UNDER))
+ return true;
+ return AllowDollar && c == '$';
+}
+
+/// Returns true if this is a body character of a C identifier,
+/// which is [a-zA-Z0-9_].
+LLVM_READONLY static inline bool isIdentifierBody(unsigned char c,
+ bool AllowDollar = false) {
+ using namespace charinfo;
+ if (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_DIGIT|CHAR_UNDER))
+ return true;
+ return AllowDollar && c == '$';
+}
+
+/// Returns true if this character is horizontal ASCII whitespace:
+/// ' ', '\\t', '\\f', '\\v'.
+///
+/// Note that this returns false for '\\0'.
+LLVM_READONLY static inline bool isHorizontalWhitespace(unsigned char c) {
+ using namespace charinfo;
+ return (InfoTable[c] & (CHAR_HORZ_WS|CHAR_SPACE)) != 0;
+}
+
+/// Returns true if this character is vertical ASCII whitespace: '\\n', '\\r'.
+///
+/// Note that this returns false for '\\0'.
+LLVM_READONLY static inline bool isVerticalWhitespace(unsigned char c) {
+ using namespace charinfo;
+ return (InfoTable[c] & CHAR_VERT_WS) != 0;
+}
+
+/// Return true if this character is horizontal or vertical ASCII whitespace:
+/// ' ', '\\t', '\\f', '\\v', '\\n', '\\r'.
+///
+/// Note that this returns false for '\\0'.
+LLVM_READONLY static inline bool isWhitespace(unsigned char c) {
+ using namespace charinfo;
+ return (InfoTable[c] & (CHAR_HORZ_WS|CHAR_VERT_WS|CHAR_SPACE)) != 0;
+}
+
+/// Return true if this character is an ASCII digit: [0-9]
+LLVM_READONLY static inline bool isDigit(unsigned char c) {
+ using namespace charinfo;
+ return (InfoTable[c] & CHAR_DIGIT) != 0;
+}
+
+/// Return true if this character is a lowercase ASCII letter: [a-z]
+LLVM_READONLY static inline bool isLowercase(unsigned char c) {
+ using namespace charinfo;
+ return (InfoTable[c] & CHAR_LOWER) != 0;
+}
+
+/// Return true if this character is an uppercase ASCII letter: [A-Z]
+LLVM_READONLY static inline bool isUppercase(unsigned char c) {
+ using namespace charinfo;
+ return (InfoTable[c] & CHAR_UPPER) != 0;
+}
+
+/// Return true if this character is an ASCII letter: [a-zA-Z]
+LLVM_READONLY static inline bool isLetter(unsigned char c) {
+ using namespace charinfo;
+ return (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER)) != 0;
+}
+
+/// Return true if this character is an ASCII letter or digit: [a-zA-Z0-9]
+LLVM_READONLY static inline bool isAlphanumeric(unsigned char c) {
+ using namespace charinfo;
+ return (InfoTable[c] & (CHAR_DIGIT|CHAR_UPPER|CHAR_LOWER)) != 0;
+}
+
+/// Return true if this character is an ASCII hex digit: [0-9a-fA-F]
+LLVM_READONLY static inline bool isHexDigit(unsigned char c) {
+ using namespace charinfo;
+ return (InfoTable[c] & (CHAR_DIGIT|CHAR_XLETTER)) != 0;
+}
+
+/// Return true if this character is an ASCII punctuation character.
+///
+/// Note that '_' is both a punctuation character and an identifier character!
+LLVM_READONLY static inline bool isPunctuation(unsigned char c) {
+ using namespace charinfo;
+ return (InfoTable[c] & (CHAR_UNDER|CHAR_PERIOD|CHAR_RAWDEL|CHAR_PUNCT)) != 0;
+}
+
+/// Return true if this character is an ASCII printable character; that is, a
+/// character that should take exactly one column to print in a fixed-width
+/// terminal.
+LLVM_READONLY static inline bool isPrintable(unsigned char c) {
+ using namespace charinfo;
+ return (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_PERIOD|CHAR_PUNCT|
+ CHAR_DIGIT|CHAR_UNDER|CHAR_RAWDEL|CHAR_SPACE)) != 0;
+}
+
+/// Return true if this is the body character of a C preprocessing number,
+/// which is [a-zA-Z0-9_.].
+LLVM_READONLY static inline bool isPreprocessingNumberBody(unsigned char c) {
+ using namespace charinfo;
+ return (InfoTable[c] &
+ (CHAR_UPPER|CHAR_LOWER|CHAR_DIGIT|CHAR_UNDER|CHAR_PERIOD)) != 0;
+}
+
+/// Return true if this is the body character of a C++ raw string delimiter.
+LLVM_READONLY static inline bool isRawStringDelimBody(unsigned char c) {
+ using namespace charinfo;
+ return (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_PERIOD|
+ CHAR_DIGIT|CHAR_UNDER|CHAR_RAWDEL)) != 0;
+}
+
+
+/// Converts the given ASCII character to its lowercase equivalent.
+///
+/// If the character is not an uppercase character, it is returned as is.
+LLVM_READONLY static inline char toLowercase(char c) {
+ if (isUppercase(c))
+ return c + 'a' - 'A';
+ return c;
+}
+
+/// Converts the given ASCII character to its uppercase equivalent.
+///
+/// If the character is not a lowercase character, it is returned as is.
+LLVM_READONLY static inline char toUppercase(char c) {
+ if (isLowercase(c))
+ return c + 'A' - 'a';
+ return c;
+}
+
+
+/// Return true if this is a valid ASCII identifier.
+///
+/// Note that this is a very simple check; it does not accept '$' or UCNs as
+/// valid identifier characters.
+LLVM_READONLY static inline bool isValidIdentifier(StringRef S) {
+ if (S.empty() || !isIdentifierHead(S[0]))
+ return false;
+
+ for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I)
+ if (!isIdentifierBody(*I))
+ return false;
+
+ return true;
+}
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Basic/CommentOptions.h b/include/clang/Basic/CommentOptions.h
new file mode 100644
index 0000000..79b9a6b
--- /dev/null
+++ b/include/clang/Basic/CommentOptions.h
@@ -0,0 +1,34 @@
+//===--- CommentOptions.h - Options for parsing comments -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Defines the clang::CommentOptions interface.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_COMMENTOPTIONS_H
+#define LLVM_CLANG_COMMENTOPTIONS_H
+
+#include <string>
+#include <vector>
+
+namespace clang {
+
+/// \brief Options for controlling comment parsing.
+struct CommentOptions {
+ typedef std::vector<std::string> BlockCommandNamesTy;
+
+ /// \brief Command names to treat as block commands in comments.
+ /// Should not include the leading backslash.
+ BlockCommandNamesTy BlockCommandNames;
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Basic/ConvertUTF.h b/include/clang/Basic/ConvertUTF.h
deleted file mode 100644
index cdc4269..0000000
--- a/include/clang/Basic/ConvertUTF.h
+++ /dev/null
@@ -1,203 +0,0 @@
-/*===--- ConvertUTF.h - Universal Character Names conversions ---------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is distributed under the University of Illinois Open Source
- * License. See LICENSE.TXT for details.
- *
- *==------------------------------------------------------------------------==*/
-/*
- * Copyright 2001-2004 Unicode, Inc.
- *
- * Disclaimer
- *
- * This source code is provided as is by Unicode, Inc. No claims are
- * made as to fitness for any particular purpose. No warranties of any
- * kind are expressed or implied. The recipient agrees to determine
- * applicability of information provided. If this file has been
- * purchased on magnetic or optical media from Unicode, Inc., the
- * sole remedy for any claim will be exchange of defective media
- * within 90 days of receipt.
- *
- * Limitations on Rights to Redistribute This Code
- *
- * Unicode, Inc. hereby grants the right to freely use the information
- * supplied in this file in the creation of products supporting the
- * Unicode Standard, and to make copies of this file in any form
- * for internal or external distribution as long as this notice
- * remains attached.
- */
-
-/* ---------------------------------------------------------------------
-
- Conversions between UTF32, UTF-16, and UTF-8. Header file.
-
- Several funtions are included here, forming a complete set of
- conversions between the three formats. UTF-7 is not included
- here, but is handled in a separate source file.
-
- Each of these routines takes pointers to input buffers and output
- buffers. The input buffers are const.
-
- Each routine converts the text between *sourceStart and sourceEnd,
- putting the result into the buffer between *targetStart and
- targetEnd. Note: the end pointers are *after* the last item: e.g.
- *(sourceEnd - 1) is the last item.
-
- The return result indicates whether the conversion was successful,
- and if not, whether the problem was in the source or target buffers.
- (Only the first encountered problem is indicated.)
-
- After the conversion, *sourceStart and *targetStart are both
- updated to point to the end of last text successfully converted in
- the respective buffers.
-
- Input parameters:
- sourceStart - pointer to a pointer to the source buffer.
- The contents of this are modified on return so that
- it points at the next thing to be converted.
- targetStart - similarly, pointer to pointer to the target buffer.
- sourceEnd, targetEnd - respectively pointers to the ends of the
- two buffers, for overflow checking only.
-
- These conversion functions take a ConversionFlags argument. When this
- flag is set to strict, both irregular sequences and isolated surrogates
- will cause an error. When the flag is set to lenient, both irregular
- sequences and isolated surrogates are converted.
-
- Whether the flag is strict or lenient, all illegal sequences will cause
- an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>,
- or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code
- must check for illegal sequences.
-
- When the flag is set to lenient, characters over 0x10FFFF are converted
- to the replacement character; otherwise (when the flag is set to strict)
- they constitute an error.
-
- Output parameters:
- The value "sourceIllegal" is returned from some routines if the input
- sequence is malformed. When "sourceIllegal" is returned, the source
- value will point to the illegal value that caused the problem. E.g.,
- in UTF-8 when a sequence is malformed, it points to the start of the
- malformed sequence.
-
- Author: Mark E. Davis, 1994.
- Rev History: Rick McGowan, fixes & updates May 2001.
- Fixes & updates, Sept 2001.
-
------------------------------------------------------------------------- */
-
-#ifndef CLANG_BASIC_CONVERTUTF_H
-#define CLANG_BASIC_CONVERTUTF_H
-
-/* ---------------------------------------------------------------------
- The following 4 definitions are compiler-specific.
- The C standard does not guarantee that wchar_t has at least
- 16 bits, so wchar_t is no less portable than unsigned short!
- All should be unsigned values to avoid sign extension during
- bit mask & shift operations.
------------------------------------------------------------------------- */
-
-typedef unsigned int UTF32; /* at least 32 bits */
-typedef unsigned short UTF16; /* at least 16 bits */
-typedef unsigned char UTF8; /* typically 8 bits */
-typedef unsigned char Boolean; /* 0 or 1 */
-
-/* Some fundamental constants */
-#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
-#define UNI_MAX_BMP (UTF32)0x0000FFFF
-#define UNI_MAX_UTF16 (UTF32)0x0010FFFF
-#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
-#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF
-
-#define UNI_MAX_UTF8_BYTES_PER_CODE_POINT 4
-
-typedef enum {
- conversionOK, /* conversion successful */
- sourceExhausted, /* partial character in source, but hit end */
- targetExhausted, /* insuff. room in target for conversion */
- sourceIllegal /* source sequence is illegal/malformed */
-} ConversionResult;
-
-typedef enum {
- strictConversion = 0,
- lenientConversion
-} ConversionFlags;
-
-/* This is for C++ and does no harm in C */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-ConversionResult ConvertUTF8toUTF16 (
- const UTF8** sourceStart, const UTF8* sourceEnd,
- UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
-
-ConversionResult ConvertUTF8toUTF32 (
- const UTF8** sourceStart, const UTF8* sourceEnd,
- UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
-
-#ifdef CLANG_NEEDS_THESE_ONE_DAY
-ConversionResult ConvertUTF16toUTF8 (
- const UTF16** sourceStart, const UTF16* sourceEnd,
- UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
-#endif
-
-ConversionResult ConvertUTF32toUTF8 (
- const UTF32** sourceStart, const UTF32* sourceEnd,
- UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
-
-ConversionResult ConvertUTF16toUTF32 (
- const UTF16** sourceStart, const UTF16* sourceEnd,
- UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
-
-ConversionResult ConvertUTF32toUTF16 (
- const UTF32** sourceStart, const UTF32* sourceEnd,
- UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
-#endif
-
-Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
-
-Boolean isLegalUTF8String(const UTF8 **source, const UTF8 *sourceEnd);
-
-unsigned getNumBytesForUTF8(UTF8 firstByte);
-
-#ifdef __cplusplus
-}
-
-/*************************************************************************/
-/* Below are LLVM-specific wrappers of the functions above. */
-
-#include "llvm/ADT/StringRef.h"
-
-namespace clang {
-
-/**
- * Convert an UTF8 StringRef to UTF8, UTF16, or UTF32 depending on
- * WideCharWidth. The converted data is written to ResultPtr, which needs to
- * point to at least WideCharWidth * (Source.Size() + 1) bytes. On success,
- * ResultPtr will point one after the end of the copied string. On failure,
- * ResultPtr will not be changed, and ErrorPtr will be set to the location of
- * the first character which could not be converted.
- * \return true on success.
- */
-bool ConvertUTF8toWide(unsigned WideCharWidth, llvm::StringRef Source,
- char *&ResultPtr, const UTF8 *&ErrorPtr);
-
-/**
- * Convert an Unicode code point to UTF8 sequence.
- *
- * \param Source a Unicode code point.
- * \param [in,out] ResultPtr pointer to the output buffer, needs to be at least
- * \c UNI_MAX_UTF8_BYTES_PER_CODE_POINT bytes. On success \c ResultPtr is
- * updated one past end of the converted sequence.
- *
- * \returns true on success.
- */
-bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr);
-
-}
-
-#endif
-
-/* --------------------------------------------------------------------- */
diff --git a/include/clang/Basic/DeclNodes.td b/include/clang/Basic/DeclNodes.td
index 6f2bb35..45742bc 100644
--- a/include/clang/Basic/DeclNodes.td
+++ b/include/clang/Basic/DeclNodes.td
@@ -74,4 +74,6 @@ def StaticAssert : Decl;
def Block : Decl, DeclContext;
def ClassScopeFunctionSpecialization : Decl;
def Import : Decl;
+def OMPThreadPrivate : Decl;
+def Empty : Decl;
diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h
index e47f3e1..0327636 100644
--- a/include/clang/Basic/Diagnostic.h
+++ b/include/clang/Basic/Diagnostic.h
@@ -23,9 +23,8 @@
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/type_traits.h"
-
-#include <vector>
#include <list>
+#include <vector>
namespace clang {
class DiagnosticConsumer;
@@ -78,7 +77,7 @@ public:
bool BeforePreviousInsertions = false) {
FixItHint Hint;
Hint.RemoveRange =
- CharSourceRange(SourceRange(InsertionLoc, InsertionLoc), false);
+ CharSourceRange::getCharRange(InsertionLoc, InsertionLoc);
Hint.CodeToInsert = Code;
Hint.BeforePreviousInsertions = BeforePreviousInsertions;
return Hint;
@@ -91,7 +90,7 @@ public:
bool BeforePreviousInsertions = false) {
FixItHint Hint;
Hint.RemoveRange =
- CharSourceRange(SourceRange(InsertionLoc, InsertionLoc), false);
+ CharSourceRange::getCharRange(InsertionLoc, InsertionLoc);
Hint.InsertFromRange = FromRange;
Hint.BeforePreviousInsertions = BeforePreviousInsertions;
return Hint;
@@ -176,6 +175,7 @@ private:
bool SuppressAllDiagnostics; // Suppress all diagnostics.
bool ElideType; // Elide common types of templates.
bool PrintTemplateTree; // Print a tree when comparing templates.
+ bool WarnOnSpellCheck; // Emit warning when spellcheck is initiated.
bool ShowColors; // Color printing is enabled.
OverloadsShown ShowOverloads; // Which overload candidates to show.
unsigned ErrorLimit; // Cap of # errors emitted, 0 -> no limit.
@@ -280,6 +280,10 @@ private:
/// \brief Sticky flag set to \c true when an error is emitted.
bool ErrorOccurred;
+ /// \brief Sticky flag set to \c true when an "uncompilable error" occurs.
+ /// I.e. an error that was not upgraded from a warning by -Werror.
+ bool UncompilableErrorOccurred;
+
/// \brief Sticky flag set to \c true when a fatal error is emitted.
bool FatalErrorOccurred;
@@ -432,8 +436,8 @@ public:
///
/// If this and IgnoreAllWarnings are both set, then that one wins.
void setEnableAllWarnings(bool Val) { EnableAllWarnings = Val; }
- bool getEnableAllWarnngs() const { return EnableAllWarnings; }
-
+ bool getEnableAllWarnings() const { return EnableAllWarnings; }
+
/// \brief When set to true, any warnings reported are issued as errors.
void setWarningsAsErrors(bool Val) { WarningsAsErrors = Val; }
bool getWarningsAsErrors() const { return WarningsAsErrors; }
@@ -463,6 +467,10 @@ public:
/// tree format.
void setPrintTemplateTree(bool Val = false) { PrintTemplateTree = Val; }
bool getPrintTemplateTree() { return PrintTemplateTree; }
+
+ /// \brief Warn when spellchecking is initated, for testing.
+ void setWarnOnSpellCheck(bool Val = false) { WarnOnSpellCheck = Val; }
+ bool getWarnOnSpellCheck() { return WarnOnSpellCheck; }
/// \brief Set color printing, so the type diffing will inject color markers
/// into the output.
@@ -559,6 +567,12 @@ public:
SourceLocation Loc = SourceLocation());
bool hasErrorOccurred() const { return ErrorOccurred; }
+
+ /// \brief Errors that actually prevent compilation, not those that are
+ /// upgraded from a warning by -Werror.
+ bool hasUncompilableErrorOccurred() const {
+ return UncompilableErrorOccurred;
+ }
bool hasFatalErrorOccurred() const { return FatalErrorOccurred; }
/// \brief Determine whether any kind of unrecoverable error has occurred.
@@ -574,7 +588,7 @@ public:
/// \brief Return an ID for a diagnostic with the specified message and level.
///
- /// If this is the first request for this diagnosic, it is registered and
+ /// If this is the first request for this diagnostic, it is registered and
/// created, otherwise the existing ID is returned.
unsigned getCustomDiagID(Level L, StringRef Message) {
return Diags->getCustomDiagID((DiagnosticIDs::Level)L, Message);
@@ -598,6 +612,12 @@ public:
ArgToStringCookie = Cookie;
}
+ /// \brief Note that the prior diagnostic was emitted by some other
+ /// \c DiagnosticsEngine, and we may be attaching a note to that diagnostic.
+ void notePriorDiagnosticFrom(const DiagnosticsEngine &Other) {
+ LastDiagLevel = Other.LastDiagLevel;
+ }
+
/// \brief Reset the state of the diagnostic object to its initial
/// configuration.
void Reset();
diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td
index d869c99..9be32af 100644
--- a/include/clang/Basic/DiagnosticASTKinds.td
+++ b/include/clang/Basic/DiagnosticASTKinds.td
@@ -106,6 +106,9 @@ def note_constexpr_calls_suppressed : Note<
"(skipping %0 call%s0 in backtrace; use -fconstexpr-backtrace-limit=0 to "
"see all)">;
def note_constexpr_call_here : Note<"in call to '%0'">;
+def warn_integer_constant_overflow : Warning<
+ "overflow in expression; result is %0 with type %1">,
+ InGroup<DiagGroup<"integer-overflow">>;
// inline asm related.
let CategoryName = "Inline Assembly Issue" in {
@@ -135,7 +138,8 @@ def err_odr_function_type_inconsistent : Error<
"external function %0 declared with incompatible types in different "
"translation units (%1 vs. %2)">;
def warn_odr_tag_type_inconsistent : Warning<
- "type %0 has incompatible definitions in different translation units">;
+ "type %0 has incompatible definitions in different translation units">,
+ InGroup<DiagGroup<"odr">>;
def note_odr_tag_kind_here: Note<
"%0 is a %select{struct|interface|union|class|enum}1 here">;
def note_odr_field : Note<"field %0 has type %1 here">;
diff --git a/include/clang/Basic/DiagnosticCommentKinds.td b/include/clang/Basic/DiagnosticCommentKinds.td
index e6dfe5b..3880e0e 100644
--- a/include/clang/Basic/DiagnosticCommentKinds.td
+++ b/include/clang/Basic/DiagnosticCommentKinds.td
@@ -44,18 +44,18 @@ def note_doc_html_end_tag : Note<
// Commands
def warn_doc_block_command_empty_paragraph : Warning<
- "empty paragraph passed to '\\%0' command">,
+ "empty paragraph passed to '%select{\\|@}0%1' command">,
InGroup<Documentation>, DefaultIgnore;
def warn_doc_block_command_duplicate : Warning<
- "duplicated command '\\%0'">,
+ "duplicated command '%select{\\|@}0%1'">,
InGroup<Documentation>, DefaultIgnore;
def note_doc_block_command_previous : Note<
- "previous command '\\%0' here">;
+ "previous command '%select{\\|@}0%1' here">;
def note_doc_block_command_previous_alias : Note<
- "previous command '\\%0' (an alias of '\\%1') here">;
+ "previous command '%select{\\|@}0%1' (an alias of '\\%2') here">;
// \param command
@@ -69,10 +69,29 @@ def warn_doc_param_spaces_in_direction : Warning<
InGroup<DocumentationPedantic>, DefaultIgnore;
def warn_doc_param_not_attached_to_a_function_decl : Warning<
- "'\\param' command used in a comment that is not attached to "
+ "'%select{\\|@}0param' command used in a comment that is not attached to "
"a function declaration">,
InGroup<Documentation>, DefaultIgnore;
+def warn_doc_function_method_decl_mismatch : Warning<
+ "'%select{\\|@}0%select{function|functiongroup|method|methodgroup|callback}1' "
+ "command should be used in a comment attached to "
+ "%select{a function|a function|an Objective-C method|an Objective-C method|"
+ "a pointer to function}2 declaration">,
+ InGroup<Documentation>, DefaultIgnore;
+
+def warn_doc_api_container_decl_mismatch : Warning<
+ "'%select{\\|@}0%select{class|interface|protocol|struct|union}1' "
+ "command should not be used in a comment attached to a "
+ "non-%select{class|interface|protocol|struct|union}2 declaration">,
+ InGroup<Documentation>, DefaultIgnore;
+
+def warn_doc_container_decl_mismatch : Warning<
+ "'%select{\\|@}0%select{classdesign|coclass|dependency|helper"
+ "|helperclass|helps|instancesize|ownership|performance|security|superclass}1' "
+ "command should not be used in a comment attached to a non-container declaration">,
+ InGroup<Documentation>, DefaultIgnore;
+
def warn_doc_param_duplicate : Warning<
"parameter '%0' is already documented">,
InGroup<Documentation>, DefaultIgnore;
@@ -87,10 +106,10 @@ def warn_doc_param_not_found : Warning<
def note_doc_param_name_suggestion : Note<
"did you mean '%0'?">;
-// \tparam command
+// tparam command
def warn_doc_tparam_not_attached_to_a_template_decl : Warning<
- "'\\tparam' command used in a comment that is not attached to "
+ "'%select{\\|@}0tparam' command used in a comment that is not attached to "
"a template declaration">,
InGroup<Documentation>, DefaultIgnore;
@@ -111,14 +130,14 @@ def note_doc_tparam_name_suggestion : Note<
// \returns command
def warn_doc_returns_not_attached_to_a_function_decl : Warning<
- "'\\%0' command used in a comment that is not attached to "
+ "'%select{\\|@}0%1' command used in a comment that is not attached to "
"a function or method declaration">,
InGroup<Documentation>, DefaultIgnore;
def warn_doc_returns_attached_to_a_void_function : Warning<
- "'\\%0' command used in a comment that is attached to a "
+ "'%select{\\|@}0%1' command used in a comment that is attached to a "
"%select{function returning void|constructor|destructor|"
- "method returning void}1">,
+ "method returning void}2">,
InGroup<Documentation>, DefaultIgnore;
// \deprecated command
@@ -134,7 +153,7 @@ def note_add_deprecation_attr : Note<
// verbatim block commands
def warn_verbatim_block_end_without_start : Warning<
- "'\\%0' command does not terminate a verbatim text block">,
+ "'%select{\\|@}0%1' command does not terminate a verbatim text block">,
InGroup<Documentation>, DefaultIgnore;
} // end of documentation issue category
diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td
index a6ce9d4..7ff6ae1 100644
--- a/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/include/clang/Basic/DiagnosticCommonKinds.td
@@ -41,6 +41,9 @@ def err_expected_colon : Error<"expected ':'">;
def err_expected_colon_after_setter_name : Error<
"method name referenced in property setter attribute "
"must end with ':'">;
+def err_expected_string_literal : Error<"expected string literal "
+ "%select{in %1|for diagnostic message in static_assert|"
+ "for optional message in 'availability' attribute}0">;
def err_invalid_string_udl : Error<
"string literal with user-defined suffix cannot be used here">;
def err_invalid_character_udl : Error<
@@ -49,8 +52,6 @@ def err_invalid_numeric_udl : Error<
"numeric literal with user-defined suffix cannot be used here">;
// Parse && Sema
-def ext_no_declarators : ExtWarn<"declaration does not declare anything">,
- InGroup<MissingDeclarations>;
def err_param_redefinition : Error<"redefinition of parameter %0">;
def warn_method_param_redefinition : Warning<"redefinition of method parameter %0">;
def warn_method_param_declaration : Warning<"redeclaration of method parameter %0">,
@@ -71,11 +72,12 @@ def err_module_not_found : Error<"module '%0' not found">, DefaultFatal;
def err_module_not_built : Error<"could not build module '%0'">, DefaultFatal;
def err_module_cycle : Error<"cyclic dependency in module '%0': %1">,
DefaultFatal;
-def warn_module_build : Warning<"building module '%0' from source">,
- InGroup<ModuleBuild>, DefaultIgnore;
def note_pragma_entered_here : Note<"#pragma entered here">;
def note_decl_hiding_tag_type : Note<
"%1 %0 is hidden by a non-type declaration of %0 here">;
+def err_attribute_not_type_attr : Error<
+ "%0 attribute cannot be applied to types">;
+def err_enum_template : Error<"enumeration cannot be a template">;
// Sema && Lex
def ext_c99_longlong : Extension<
@@ -115,4 +117,8 @@ def err_unable_to_rename_temp : Error<
"unable to rename temporary '%0' to output file '%1': '%2'">;
def err_unable_to_make_temp : Error<
"unable to make temporary file: %0">;
+
+// Modules
+def err_module_file_conflict : Error<"module '%0' found in both '%1' and '%2'">;
+
}
diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td
index 4b43035..15b8948 100644
--- a/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/include/clang/Basic/DiagnosticDriverKinds.td
@@ -35,6 +35,8 @@ def err_drv_use_of_Z_option : Error<
"unsupported use of internal gcc -Z option '%0'">;
def err_drv_output_argument_with_multiple_files : Error<
"cannot specify -o when generating multiple output files">;
+def err_no_external_windows_assembler : Error<
+ "there is no external assembler we can use on windows">;
def err_drv_unable_to_remove_file : Error<
"unable to remove file: %0">;
def err_drv_command_failure : Error<
@@ -57,6 +59,8 @@ def err_drv_no_linker_llvm_support : Error<
"'%0': unable to pass LLVM bit-code files to linker">;
def err_drv_no_ast_support : Error<
"'%0': unable to use AST files with this tool">;
+def err_drv_no_module_support : Error<
+ "'%0': unable to use module files with this tool">;
def err_drv_clang_unsupported : Error<
"the clang compiler does not support '%0'">;
def err_drv_clang_unsupported_per_platform : Error<
@@ -67,6 +71,8 @@ def err_drv_command_failed : Error<
"%0 command failed with exit code %1 (use -v to see invocation)">;
def err_drv_command_signalled : Error<
"%0 command failed due to signal (use -v to see invocation)">;
+def err_drv_force_crash : Error<
+ "failing because environment variable '%0' is set">;
def err_drv_invalid_mfloat_abi : Error<
"invalid float ABI '%0'">;
def err_drv_invalid_libcxx_deployment : Error<
@@ -108,19 +114,21 @@ def warn_c_kext : Warning<
"ignoring -fapple-kext which is valid for C++ and Objective-C++ only">;
def warn_drv_input_file_unused : Warning<
"%0: '%1' input unused%select{ when '%3' is present|}2">,
- InGroup<DiagGroup<"unused-command-line-argument">>;
+ InGroup<UnusedCommandLineArgument>;
def warn_drv_input_file_unused_by_cpp : Warning<
"%0: '%1' input unused in cpp mode">,
- InGroup<DiagGroup<"unused-command-line-argument">>;
+ InGroup<UnusedCommandLineArgument>;
def warn_drv_preprocessed_input_file_unused : Warning<
"%0: previously preprocessed input%select{ unused when '%2' is present|}1">,
- InGroup<DiagGroup<"unused-command-line-argument">>;
+ InGroup<UnusedCommandLineArgument>;
def warn_drv_unused_argument : Warning<
"argument unused during compilation: '%0'">,
- InGroup<DiagGroup<"unused-command-line-argument">>;
+ InGroup<UnusedCommandLineArgument>;
def warn_drv_empty_joined_argument : Warning<
"joined argument expects additional value: '%0'">,
- InGroup<DiagGroup<"unused-command-line-argument">>;
+ InGroup<UnusedCommandLineArgument>;
+def warn_drv_unused_sanitizer : Warning<"'%0' is ignored in absence of '%1'">,
+ InGroup<UnusedSanitizeArgument>;
def warn_drv_clang_unsupported : Warning<
"the clang compiler does not support '%0'">;
def warn_drv_deprecated_arg : Warning<
@@ -136,6 +144,8 @@ def warn_drv_objc_gc_unsupported : Warning<
"Objective-C garbage collection is not supported on this platform, ignoring '%0'">;
def warn_drv_pch_not_first_include : Warning<
"precompiled header '%0' was ignored because '%1' is not first '-include'">;
+def warn_missing_sysroot : Warning<"no such sysroot directory: '%0'">,
+ InGroup<DiagGroup<"missing-sysroot">>;
def note_drv_command_failed_diag_msg : Note<
"diagnostic msg: %0">;
diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td
index b7a8476..111622e 100644
--- a/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -48,8 +48,6 @@ def err_fe_unable_to_interface_with_target : Error<
"unable to interface with target machine">;
def err_fe_unable_to_open_output : Error<
"unable to open output file '%0': '%1'">;
-def err_fe_unable_to_open_logfile : Error<
- "unable to open logfile file '%0': '%1'">;
def err_fe_pth_file_has_no_source_header : Error<
"PTH file '%0' does not designate an original source header file for -include-pth">;
def warn_fe_macro_contains_embedded_newline : Warning<
@@ -60,6 +58,8 @@ def warn_fe_cc_log_diagnostics_failure : Warning<
"unable to open CC_LOG_DIAGNOSTICS file: %0 (using stderr)">;
def err_fe_no_pch_in_dir : Error<
"no suitable precompiled header file found in directory '%0'">;
+def err_fe_action_not_available : Error<
+ "action %0 not compiled in">;
def warn_fe_serialized_diag_failure : Warning<
"unable to open file %0 for serializing diagnostics (%1)">,
@@ -100,19 +100,19 @@ def err_relocatable_without_isysroot : Error<
def warn_unknown_warning_option : Warning<
"unknown warning option '%0'">,
- InGroup<DiagGroup<"unknown-warning-option"> >;
+ InGroup<UnknownWarningOption>;
def warn_unknown_negative_warning_option : Warning<
"unknown warning option '%0'">,
- InGroup<DiagGroup<"unknown-warning-option"> >;
+ InGroup<UnknownWarningOption>;
def warn_unknown_warning_option_suggest : Warning<
"unknown warning option '%0'; did you mean '%1'?">,
- InGroup<DiagGroup<"unknown-warning-option"> >;
+ InGroup<UnknownWarningOption>;
def warn_unknown_negative_warning_option_suggest : Warning<
"unknown warning option '%0'; did you mean '%1'?">,
- InGroup<DiagGroup<"unknown-warning-option"> >;
+ InGroup<UnknownWarningOption>;
def warn_unknown_warning_specifier : Warning<
"unknown %0 warning specifier: '%1'">,
- InGroup<DiagGroup<"unknown-warning-option"> >;
+ InGroup<UnknownWarningOption>;
def err_unknown_analyzer_checker : Error<
"no analyzer checkers are associated with '%0'">;
@@ -129,8 +129,6 @@ def err_missing_module_name : Error<
DefaultFatal;
def err_missing_module : Error<
"no module named '%0' declared in module map file '%1'">, DefaultFatal;
-def err_missing_umbrella_header : Error<
- "cannot open umbrella header '%0': %1">, DefaultFatal;
def err_no_submodule : Error<"no submodule named %0 in module '%1'">;
def err_no_submodule_suggest : Error<
"no submodule named %0 in module '%1'; did you mean '%2'?">;
@@ -139,5 +137,11 @@ def warn_missing_submodule : Warning<"missing submodule '%0'">,
def err_module_map_temp_file : Error<
"unable to write temporary module map file '%0'">, DefaultFatal;
def err_module_unavailable : Error<"module '%0' requires feature '%1'">;
-
+def warn_module_config_macro_undef : Warning<
+ "%select{definition|#undef}0 of configuration macro '%1' has no effect on "
+ "the import of '%2'; pass '%select{-D%1=...|-U%1}0' on the command line "
+ "to configure the module">,
+ InGroup<ConfigMacros>;
+def note_module_def_undef_here : Note<
+ "macro was %select{defined|#undef'd}0 here">;
}
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index f9f9ec7..a12a4f9 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -22,6 +22,8 @@ def : DiagGroup<"address">;
def AddressOfTemporary : DiagGroup<"address-of-temporary">;
def : DiagGroup<"aggregate-return">;
def AmbigMemberTemplate : DiagGroup<"ambiguous-member-template">;
+def ArrayBounds : DiagGroup<"array-bounds">;
+def ArrayBoundsPointerArithmetic : DiagGroup<"array-bounds-pointer-arithmetic">;
def Availability : DiagGroup<"availability">;
def Section : DiagGroup<"section">;
def AutoImport : DiagGroup<"auto-import">;
@@ -36,14 +38,17 @@ def NonLiteralNullConversion : DiagGroup<"non-literal-null-conversion">;
def NullConversion : DiagGroup<"null-conversion">;
def ImplicitConversionFloatingPointToBool :
DiagGroup<"implicit-conversion-floating-point-to-bool">;
+def BadArrayNewLength : DiagGroup<"bad-array-new-length">;
+def BuiltinMacroRedefined : DiagGroup<"builtin-macro-redefined">;
def BuiltinRequiresHeader : DiagGroup<"builtin-requires-header">;
+def C99Compat : DiagGroup<"c99-compat">;
def CXXCompat: DiagGroup<"c++-compat">;
def CastAlign : DiagGroup<"cast-align">;
def : DiagGroup<"cast-qual">;
def : DiagGroup<"char-align">;
def Comment : DiagGroup<"comment">;
+def ConfigMacros : DiagGroup<"config-macros">;
def : DiagGroup<"ctor-dtor-privacy">;
-def DefaultArgSpecialMember : DiagGroup<"default-arg-special-member">;
def GNUDesignator : DiagGroup<"gnu-designator">;
def DeleteNonVirtualDtor : DiagGroup<"delete-non-virtual-dtor">;
@@ -118,10 +123,18 @@ def BitwiseOpParentheses: DiagGroup<"bitwise-op-parentheses">;
def LogicalOpParentheses: DiagGroup<"logical-op-parentheses">;
def ShiftOpParentheses: DiagGroup<"shift-op-parentheses">;
def DanglingElse: DiagGroup<"dangling-else">;
+def DanglingField : DiagGroup<"dangling-field">;
+def DistributedObjectModifiers : DiagGroup<"distributed-object-modifiers">;
def IgnoredQualifiers : DiagGroup<"ignored-qualifiers">;
def : DiagGroup<"import">;
-def IncompatiblePointerTypes : DiagGroup<"incompatible-pointer-types">;
+def IncompatiblePointerTypesDiscardsQualifiers
+ : DiagGroup<"incompatible-pointer-types-discards-qualifiers">;
+def IncompatiblePointerTypes
+ : DiagGroup<"incompatible-pointer-types",
+ [IncompatiblePointerTypesDiscardsQualifiers]>;
def IncompleteUmbrella : DiagGroup<"incomplete-umbrella">;
+def InvalidNoreturn : DiagGroup<"invalid-noreturn">;
+def InvalidSourceEncoding : DiagGroup<"invalid-source-encoding">;
def KNRPromotedParameter : DiagGroup<"knr-promoted-parameter">;
def : DiagGroup<"init-self">;
def : DiagGroup<"inline">;
@@ -136,19 +149,23 @@ def MissingBraces : DiagGroup<"missing-braces">;
def MissingDeclarations: DiagGroup<"missing-declarations">;
def : DiagGroup<"missing-format-attribute">;
def : DiagGroup<"missing-include-dirs">;
+def MissingNoreturn : DiagGroup<"missing-noreturn">;
def MultiChar : DiagGroup<"multichar">;
def : DiagGroup<"nested-externs">;
def CXX11LongLong : DiagGroup<"c++11-long-long">;
def LongLong : DiagGroup<"long-long", [CXX11LongLong]>;
+def MethodSignatures : DiagGroup<"method-signatures">;
def MismatchedParameterTypes : DiagGroup<"mismatched-parameter-types">;
def MismatchedReturnTypes : DiagGroup<"mismatched-return-types">;
def MismatchedTags : DiagGroup<"mismatched-tags">;
def MissingFieldInitializers : DiagGroup<"missing-field-initializers">;
-def ModuleBuild : DiagGroup<"module-build">;
+def ModuleConflict : DiagGroup<"module-conflict">;
+def NullArithmetic : DiagGroup<"null-arithmetic">;
def NullCharacter : DiagGroup<"null-character">;
def NullDereference : DiagGroup<"null-dereference">;
def InitializerOverrides : DiagGroup<"initializer-overrides">;
def NonNull : DiagGroup<"nonnull">;
+def NonPODVarargs : DiagGroup<"non-pod-varargs">;
def : DiagGroup<"nonportable-cfstrings">;
def NonVirtualDtor : DiagGroup<"non-virtual-dtor">;
def OveralignedType : DiagGroup<"over-aligned">;
@@ -170,6 +187,7 @@ def ObjCMissingSuperCalls : DiagGroup<"objc-missing-super-calls">;
def ObjCRetainBlockProperty : DiagGroup<"objc-noncopy-retain-block-property">;
def ObjCReadonlyPropertyHasSetter : DiagGroup<"objc-readonly-with-setter-property">;
def ObjCRootClass : DiagGroup<"objc-root-class">;
+def DeprecatedObjCIsaUsage : DiagGroup<"deprecated-objc-isa-usage">;
def Packed : DiagGroup<"packed">;
def Padded : DiagGroup<"padded">;
def PointerArith : DiagGroup<"pointer-arith">;
@@ -179,6 +197,7 @@ def PoundPragmaMessage : DiagGroup<"#pragma-messages">,
DiagCategory<"#pragma message Directive">;
def : DiagGroup<"pointer-to-int-cast">;
def : DiagGroup<"redundant-decls">;
+def ReturnStackAddress : DiagGroup<"return-stack-address">;
def ReturnTypeCLinkage : DiagGroup<"return-type-c-linkage">;
def ReturnType : DiagGroup<"return-type", [ReturnTypeCLinkage]>;
def BindToTemporaryCopy : DiagGroup<"bind-to-temporary-copy",
@@ -188,7 +207,6 @@ def SelfAssignment : DiagGroup<"self-assign", [SelfAssignmentField]>;
def SemiBeforeMethodBody : DiagGroup<"semicolon-before-method-body">;
def Sentinel : DiagGroup<"sentinel">;
def MissingMethodReturnType : DiagGroup<"missing-method-return-type">;
-def : DiagGroup<"sequence-point">;
def Shadow : DiagGroup<"shadow">;
def Shorten64To32 : DiagGroup<"shorten-64-to-32">;
def : DiagGroup<"sign-promo">;
@@ -197,6 +215,12 @@ def : DiagGroup<"stack-protector">;
def : DiagGroup<"switch-default">;
def : DiagGroup<"synth">;
def SizeofArrayArgument : DiagGroup<"sizeof-array-argument">;
+def SizeofArrayDecay : DiagGroup<"sizeof-array-decay">;
+def SizeofPointerMemaccess : DiagGroup<"sizeof-pointer-memaccess">;
+def StaticInInline : DiagGroup<"static-in-inline">;
+def StaticLocalInInline : DiagGroup<"static-local-in-inline">;
+def GNUStaticFloatInit : DiagGroup<"gnu-static-float-init">;
+def StaticFloatInit : DiagGroup<"static-float-init", [GNUStaticFloatInit]>;
def StringPlusInt : DiagGroup<"string-plus-int">;
def StrncatSize : DiagGroup<"strncat-size">;
def TautologicalOutOfRangeCompare : DiagGroup<"tautological-constant-out-of-range-compare">;
@@ -206,6 +230,10 @@ def HeaderHygiene : DiagGroup<"header-hygiene">;
def DuplicateDeclSpecifier : DiagGroup<"duplicate-decl-specifier">;
def CompareDistinctPointerType : DiagGroup<"compare-distinct-pointer-types">;
+def Unsequenced : DiagGroup<"unsequenced">;
+// GCC name for -Wunsequenced
+def : DiagGroup<"sequence-point", [Unsequenced]>;
+
// Preprocessor warnings.
def AmbiguousMacro : DiagGroup<"ambiguous-macro">;
@@ -240,17 +268,25 @@ def InvalidPPToken : DiagGroup<"invalid-pp-token">;
def Trigraphs : DiagGroup<"trigraphs">;
def : DiagGroup<"type-limits">;
+def UndefinedReinterpretCast : DiagGroup<"undefined-reinterpret-cast">;
+def ReinterpretBaseClass : DiagGroup<"reinterpret-base-class">;
def Unicode : DiagGroup<"unicode">;
def UninitializedMaybe : DiagGroup<"conditional-uninitialized">;
def UninitializedSometimes : DiagGroup<"sometimes-uninitialized">;
-def Uninitialized : DiagGroup<"uninitialized", [UninitializedSometimes]>;
+def UninitializedStaticSelfInit : DiagGroup<"static-self-init">;
+def Uninitialized : DiagGroup<"uninitialized", [UninitializedSometimes,
+ UninitializedStaticSelfInit]>;
def UnknownPragmas : DiagGroup<"unknown-pragmas">;
+def UnknownWarningOption : DiagGroup<"unknown-warning-option">;
def NSobjectAttribute : DiagGroup<"NSObject-attribute">;
def UnknownAttributes : DiagGroup<"attributes">;
def IgnoredAttributes : DiagGroup<"ignored-attributes">;
def UnnamedTypeTemplateArgs : DiagGroup<"unnamed-type-template-args",
[CXX98CompatUnnamedTypeTemplateArgs]>;
def UnusedArgument : DiagGroup<"unused-argument">;
+def UnusedSanitizeArgument : DiagGroup<"unused-sanitize-argument">;
+def UnusedCommandLineArgument : DiagGroup<"unused-command-line-argument",
+ [UnusedSanitizeArgument]>;
def UnusedComparison : DiagGroup<"unused-comparison">;
def UnusedExceptionParameter : DiagGroup<"unused-exception-parameter">;
def UnneededInternalDecl : DiagGroup<"unneeded-internal-declaration">;
@@ -293,6 +329,7 @@ def VariadicMacros : DiagGroup<"variadic-macros">;
def VectorConversion : DiagGroup<"vector-conversion">; // clang specific
def VexingParse : DiagGroup<"vexing-parse">;
def VLA : DiagGroup<"vla">;
+def VLAExtension : DiagGroup<"vla-extension">;
def VolatileRegisterVar : DiagGroup<"volatile-register-var">;
def Visibility : DiagGroup<"visibility">;
def ZeroLengthArray : DiagGroup<"zero-length-array">;
@@ -379,7 +416,6 @@ def Most : DiagGroup<"most", [
DeleteNonVirtualDtor,
Format,
Implicit,
- IntToPointerCast,
MismatchedTags,
MissingBraces,
MultiChar,
@@ -387,6 +423,7 @@ def Most : DiagGroup<"most", [
ReturnType,
SelfAssignment,
SizeofArrayArgument,
+ SizeofArrayDecay,
StringPlusInt,
Trigraphs,
Uninitialized,
@@ -407,6 +444,7 @@ def ThreadSafety : DiagGroup<"thread-safety",
[ThreadSafetyAttributes,
ThreadSafetyAnalysis,
ThreadSafetyPrecise]>;
+def ThreadSafetyBeta : DiagGroup<"thread-safety-beta">;
// Note that putting warnings in -Wall will not disable them by default. If a
// warning should be active _only_ when -Wall is passed in, mark it as
@@ -449,7 +487,8 @@ def C11 : DiagGroup<"c11-extensions">;
def C99 : DiagGroup<"c99-extensions">;
// A warning group for warnings about GCC extensions.
-def GNU : DiagGroup<"gnu", [GNUDesignator, VLA, ZeroLengthArray]>;
+def GNU : DiagGroup<"gnu", [GNUDesignator, VLAExtension,
+ ZeroLengthArray, GNUStaticFloatInit]>;
// A warning group for warnings about code that clang accepts but gcc doesn't.
def GccCompat : DiagGroup<"gcc-compat">;
@@ -460,6 +499,8 @@ def ObjCNonUnifiedException : DiagGroup<"objc-nonunified-exceptions">;
def ObjCProtocolMethodImpl : DiagGroup<"objc-protocol-method-implementation">;
+def ObjCNoPropertyAutoSynthesis : DiagGroup<"objc-property-synthesis">;
+
// ObjC API warning groups.
def ObjCRedundantLiteralUse : DiagGroup<"objc-redundant-literal-use">;
def ObjCRedundantAPIUse : DiagGroup<"objc-redundant-api-use", [
@@ -480,3 +521,6 @@ def ASMOperandWidths : DiagGroup<"asm-operand-widths">;
def ASM : DiagGroup<"asm", [
ASMOperandWidths
]>;
+
+// OpenMP warnings.
+def SourceUsesOpenMP : DiagGroup<"source-uses-openmp">;
diff --git a/include/clang/Basic/DiagnosticIDs.h b/include/clang/Basic/DiagnosticIDs.h
index 11552af..d35b907 100644
--- a/include/clang/Basic/DiagnosticIDs.h
+++ b/include/clang/Basic/DiagnosticIDs.h
@@ -15,13 +15,9 @@
#ifndef LLVM_CLANG_DIAGNOSTICIDS_H
#define LLVM_CLANG_DIAGNOSTICIDS_H
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/StringRef.h"
-#include "clang/Basic/LLVM.h"
-
-namespace llvm {
- template<typename T, unsigned> class SmallVector;
-}
namespace clang {
class DiagnosticsEngine;
@@ -128,7 +124,7 @@ public:
/// \brief Return an ID for a diagnostic with the specified message and level.
///
- /// If this is the first request for this diagnosic, it is registered and
+ /// If this is the first request for this diagnostic, it is registered and
/// created, otherwise the existing ID is returned.
unsigned getCustomDiagID(Level L, StringRef Message);
@@ -231,10 +227,10 @@ public:
/// \param Diags [out] - On return, the diagnostics in the group.
/// \returns True if the given group is unknown, false otherwise.
bool getDiagnosticsInGroup(StringRef Group,
- llvm::SmallVectorImpl<diag::kind> &Diags) const;
+ SmallVectorImpl<diag::kind> &Diags) const;
/// \brief Get the set of all diagnostic IDs.
- void getAllDiagnostics(llvm::SmallVectorImpl<diag::kind> &Diags) const;
+ void getAllDiagnostics(SmallVectorImpl<diag::kind> &Diags) const;
/// \brief Get the warning option with the closest edit distance to the given
/// group name.
@@ -245,7 +241,7 @@ private:
///
/// \param Diags [out] - On return, the diagnostics in the group.
void getDiagnosticsInGroup(const WarningOption *Group,
- llvm::SmallVectorImpl<diag::kind> &Diags) const;
+ SmallVectorImpl<diag::kind> &Diags) const;
/// \brief Based on the way the client configured the DiagnosticsEngine
/// object, classify the specified diagnostic ID into a Level, consumable by
diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td
index c6c50ab..339788b 100644
--- a/include/clang/Basic/DiagnosticLexKinds.td
+++ b/include/clang/Basic/DiagnosticLexKinds.td
@@ -93,26 +93,63 @@ def ext_multichar_character_literal : ExtWarn<
"multi-character character constant">, InGroup<MultiChar>;
def ext_four_char_character_literal : Extension<
"multi-character character constant">, InGroup<FourByteMultiChar>;
-
-// Literal
-def ext_nonstandard_escape : Extension<
- "use of non-standard escape character '\\%0'">;
-def ext_unknown_escape : ExtWarn<"unknown escape sequence '\\%0'">;
-def err_hex_escape_no_digits : Error<"\\x used with no following hex digits">;
-def err_ucn_escape_no_digits : Error<"\\u used with no following hex digits">;
-def err_ucn_escape_invalid : Error<"invalid universal character">;
-def err_ucn_escape_incomplete : Error<"incomplete universal character name">;
+
+// Unicode and UCNs
+def err_invalid_utf8 : Error<
+ "source file is not valid UTF-8">;
+def err_non_ascii : Error<
+ "non-ASCII characters are not allowed outside of literals and identifiers">;
+def ext_unicode_whitespace : ExtWarn<
+ "treating Unicode character as whitespace">,
+ InGroup<DiagGroup<"unicode-whitespace">>;
+
+def err_hex_escape_no_digits : Error<
+ "\\%0 used with no following hex digits">;
+def warn_ucn_escape_no_digits : Warning<
+ "\\%0 used with no following hex digits; "
+ "treating as '\\' followed by identifier">, InGroup<Unicode>;
+def err_ucn_escape_incomplete : Error<
+ "incomplete universal character name">;
+def warn_ucn_escape_incomplete : Warning<
+ "incomplete universal character name; "
+ "treating as '\\' followed by identifier">, InGroup<Unicode>;
+def note_ucn_four_not_eight : Note<"did you mean to use '\\u'?">;
+
def err_ucn_escape_basic_scs : Error<
"character '%0' cannot be specified by a universal character name">;
def err_ucn_control_character : Error<
"universal character name refers to a control character">;
+def err_ucn_escape_invalid : Error<"invalid universal character">;
+def warn_ucn_escape_surrogate : Warning<
+ "universal character name refers to a surrogate character">,
+ InGroup<Unicode>;
+
+def warn_c99_compat_unicode_id : Warning<
+ "%select{using this character in an identifier|starting an identifier with "
+ "this character}0 is incompatible with C99">,
+ InGroup<C99Compat>, DefaultIgnore;
+def warn_cxx98_compat_unicode_id : Warning<
+ "using this character in an identifier is incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
+
def warn_cxx98_compat_literal_ucn_escape_basic_scs : Warning<
"specifying character '%0' with a universal character name "
"is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
def warn_cxx98_compat_literal_ucn_control_character : Warning<
"universal character name referring to a control character "
"is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
+def warn_ucn_not_valid_in_c89 : Warning<
+ "universal character names are only valid in C99 or C++; "
+ "treating as '\\' followed by identifier">, InGroup<Unicode>;
+def warn_ucn_not_valid_in_c89_literal : ExtWarn<
+ "universal character names are only valid in C99 or C++">, InGroup<Unicode>;
+
+
+// Literal
+def ext_nonstandard_escape : Extension<
+ "use of non-standard escape character '\\%0'">;
+def ext_unknown_escape : ExtWarn<"unknown escape sequence '\\%0'">;
def err_invalid_decimal_digit : Error<"invalid digit '%0' in decimal constant">;
def err_invalid_binary_digit : Error<"invalid digit '%0' in binary constant">;
def err_invalid_octal_digit : Error<"invalid digit '%0' in octal constant">;
@@ -145,8 +182,9 @@ def ext_string_too_long : Extension<"string literal of length %0 exceeds "
"support">, InGroup<OverlengthStrings>;
def err_character_too_large : Error<
"character too large for enclosing character literal type">;
-def warn_ucn_not_valid_in_c89 : ExtWarn<
- "unicode escape sequences are only valid in C99 or C++">, InGroup<Unicode>;
+def warn_c99_compat_unicode_literal : Warning<
+ "unicode literals are incompatible with C99">,
+ InGroup<C99Compat>, DefaultIgnore;
def warn_cxx98_compat_unicode_literal : Warning<
"unicode literals are incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
@@ -175,12 +213,12 @@ def err_bad_string_encoding : Error<
"illegal character encoding in string literal">;
def warn_bad_string_encoding : ExtWarn<
"illegal character encoding in string literal">,
- InGroup<DiagGroup<"invalid-source-encoding">>;
+ InGroup<InvalidSourceEncoding>;
def err_bad_character_encoding : Error<
"illegal character encoding in character literal">;
def warn_bad_character_encoding : ExtWarn<
"illegal character encoding in character literal">,
- InGroup<DiagGroup<"invalid-source-encoding">>;
+ InGroup<InvalidSourceEncoding>;
def err_lexing_string : Error<"failure when lexing a string">;
@@ -218,9 +256,10 @@ def pp_pragma_sysheader_in_main_file : Warning<
def pp_poisoning_existing_macro : Warning<"poisoning existing macro">;
def pp_out_of_date_dependency : Warning<
"current file is older than dependency %0">;
-def pp_undef_builtin_macro : Warning<"undefining builtin macro">;
-def pp_redef_builtin_macro : Warning<"redefining builtin macro">,
- InGroup<DiagGroup<"builtin-macro-redefined">>;
+def ext_pp_undef_builtin_macro : ExtWarn<"undefining builtin macro">,
+ InGroup<BuiltinMacroRedefined>;
+def ext_pp_redef_builtin_macro : ExtWarn<"redefining builtin macro">,
+ InGroup<BuiltinMacroRedefined>;
def pp_disabled_macro_expansion : Warning<
"disabled expansion of recursive macro">, DefaultIgnore,
InGroup<DiagGroup<"disabled-macro-expansion">>;
@@ -284,7 +323,12 @@ def warn_cxx98_compat_empty_fnmacro_arg : Warning<
InGroup<CXX98CompatPedantic>, DefaultIgnore;
def note_macro_here : Note<"macro %0 defined here">;
+def err_pp_opencl_variadic_macros :
+ Error<"variadic macros not supported in OpenCL">;
+
def err_pp_invalid_directive : Error<"invalid preprocessing directive">;
+def err_pp_directive_required : Error<
+ "%0 must be used within a preprocessing directive">;
def err_pp_file_not_found : Error<"'%0' file not found">, DefaultFatal;
def err_pp_file_not_found_not_fatal : Error<
"'%0' file not found with <angled> include; use \"quotes\" instead">;
@@ -486,6 +530,16 @@ def err_mmap_umbrella_clash : Error<
"umbrella for module '%0' already covers this directory">;
def err_mmap_export_module_id : Error<
"expected an exported module name or '*'">;
+def err_mmap_expected_library_name : Error<
+ "expected %select{library|framework}0 name as a string">;
+def err_mmap_config_macro_submodule : Error<
+ "configuration macros are only allowed on top-level modules">;
+def err_mmap_expected_config_macro : Error<
+ "expected configuration macro name after ','">;
+def err_mmap_expected_conflicts_comma : Error<
+ "expected ',' after conflicting module name">;
+def err_mmap_expected_conflicts_message : Error<
+ "expected a message describing the conflict with '%0'">;
def err_mmap_missing_module_unqualified : Error<
"no module named '%0' visible from '%1'">;
def err_mmap_missing_module_qualified : Error<
@@ -521,7 +575,8 @@ def warn_auto_module_import : Warning<
"treating #%select{include|import|include_next|__include_macros}0 as an "
"import of module '%1'">, InGroup<AutoImport>, DefaultIgnore;
def warn_uncovered_module_header : Warning<
- "umbrella header does not include header '%0'">, InGroup<IncompleteUmbrella>;
+ "umbrella header for module '%0' does not include header '%1'">,
+ InGroup<IncompleteUmbrella>;
def err_expected_id_building_module : Error<
"expected a module name in '__building_module' expression">;
diff --git a/include/clang/Basic/DiagnosticOptions.def b/include/clang/Basic/DiagnosticOptions.def
index 476ac1e..8e5562c 100644
--- a/include/clang/Basic/DiagnosticOptions.def
+++ b/include/clang/Basic/DiagnosticOptions.def
@@ -54,6 +54,7 @@ DIAGOPT(ShowCarets, 1, 1) /// Show carets in diagnostics.
DIAGOPT(ShowFixits, 1, 1) /// Show fixit information.
DIAGOPT(ShowSourceRanges, 1, 0) /// Show source ranges in numeric form.
DIAGOPT(ShowParseableFixits, 1, 0) /// Show machine parseable fix-its.
+DIAGOPT(ShowPresumedLoc, 1, 0) /// Show presumed location for diagnostics.
DIAGOPT(ShowOptionNames, 1, 0) /// Show the option name for mappable
/// diagnostics.
DIAGOPT(ShowNoteIncludeStack, 1, 0) /// Show include stacks for notes.
@@ -71,6 +72,7 @@ DIAGOPT(VerifyDiagnostics, 1, 0) /// Check that diagnostics match the expected
DIAGOPT(ElideType, 1, 0) /// Elide identical types in template diffing
DIAGOPT(ShowTemplateTree, 1, 0) /// Print a template tree when diffing
+DIAGOPT(WarnOnSpellCheck, 1, 0) /// -fwarn-on-spellcheck
VALUE_DIAGOPT(ErrorLimit, 32, 0) /// Limit # errors emitted.
/// Limit depth of macro expansion backtrace.
diff --git a/include/clang/Basic/DiagnosticOptions.h b/include/clang/Basic/DiagnosticOptions.h
index b75cb0c..2fba384 100644
--- a/include/clang/Basic/DiagnosticOptions.h
+++ b/include/clang/Basic/DiagnosticOptions.h
@@ -10,8 +10,8 @@
#ifndef LLVM_CLANG_BASIC_DIAGNOSTICOPTIONS_H
#define LLVM_CLANG_BASIC_DIAGNOSTICOPTIONS_H
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
-
#include <string>
#include <vector>
@@ -24,9 +24,8 @@ enum OverloadsShown {
Ovl_Best ///< Show just the "best" overload candidates.
};
-/// DiagnosticOptions - Options for controlling the compiler diagnostics
-/// engine.
-class DiagnosticOptions : public llvm::RefCountedBase<DiagnosticOptions>{
+/// \brief Options for controlling the compiler diagnostics engine.
+class DiagnosticOptions : public RefCountedBase<DiagnosticOptions>{
public:
enum TextDiagnosticFormat { Clang, Msvc, Vi };
@@ -49,14 +48,10 @@ protected:
#include "clang/Basic/DiagnosticOptions.def"
public:
- /// If non-empty, a file to log extended build information to, for development
- /// testing and analysis.
- std::string DumpBuildInformation;
-
- /// The file to log diagnostic output to.
+ /// \brief The file to log diagnostic output to.
std::string DiagnosticLogFile;
- /// The file to serialize diagnostics to (non-appending).
+ /// \brief The file to serialize diagnostics to (non-appending).
std::string DiagnosticSerializationFile;
/// The list of -W... options used to alter the diagnostic mappings, with the
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 21eeccb..04a433c 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -18,9 +18,6 @@ def w_asm_qualifier_ignored : Warning<"ignored %0 qualifier on asm">,
def warn_file_asm_volatile : Warning<
"meaningless 'volatile' on asm outside function">, CatInlineAsm;
-def warn_unsupported_msasm : Warning<
- "MS-style inline assembly is not supported">, InGroup<Microsoft>;
-
let CategoryName = "Parse Issue" in {
def ext_empty_translation_unit : Extension<
@@ -98,6 +95,8 @@ def warn_cxx98_compat_enum_fixed_underlying_type : Warning<
def warn_cxx98_compat_alignof : Warning<
"alignof expressions are incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
+def ext_alignof_expr : ExtWarn<
+ "%0 applied to an expression is a GNU extension">, InGroup<GNU>;
def warn_microsoft_dependent_exists : Warning<
"dependent %select{__if_not_exists|__if_exists}0 declarations are ignored">,
@@ -113,6 +112,9 @@ def note_previous_default_assoc : Note<
def ext_c11_alignment : Extension<
"%0 is a C11-specific feature">, InGroup<C11>;
+def ext_c11_noreturn : Extension<
+ "_Noreturn functions are a C11-specific feature">, InGroup<C11>;
+
def ext_gnu_indirect_goto : Extension<
"use of GNU indirect-goto extension">, InGroup<GNU>;
def ext_gnu_address_of_label : Extension<
@@ -225,13 +227,10 @@ def note_missing_selector_name : Note<
def note_force_empty_selector_name : Note<
"or insert whitespace before ':' to use %0 as parameter name "
"and have an empty entry in the selector">;
-def note_missing_argument_name : Note<
- "did you mean to use %0 as the selector name instead of %1">;
def err_label_end_of_compound_statement : Error<
"label at end of compound statement: expected statement">;
def err_address_of_label_outside_fn : Error<
"use of address-of-label extension outside of a function body">;
-def err_expected_string_literal : Error<"expected string literal">;
def err_asm_operand_wide_string_literal : Error<
"cannot use %select{unicode|wide}0 string literal in 'asm'">;
def err_expected_selector_for_method : Error<
@@ -364,7 +363,7 @@ def note_objc_container_start : Note<
"%select{class|protocol|category|class extension|implementation"
"|category implementation}0 started here">;
def warn_objc_protocol_qualifier_missing_id : Warning<
- "protocol qualifiers without 'id' is archaic">;
+ "protocol has no object type specified; defaults to qualified 'id'">;
def err_objc_unknown_at : Error<"expected an Objective-C directive after '@'">;
def err_illegal_super_cast : Error<
"cannot cast 'super' (it isn't an expression)">;
@@ -400,6 +399,11 @@ def err_objc_properties_require_objc2 : Error<
"properties are an Objective-C 2 feature">;
def err_objc_unexpected_attr : Error<
"prefix attribute must be followed by an interface or protocol">;
+def err_objc_postfix_attribute : Error <
+ "postfix attributes are not allowed on Objective-C directives">;
+def err_objc_postfix_attribute_hint : Error <
+ "postfix attributes are not allowed on Objective-C directives, place"
+ " them in front of '%select{@interface|@protocol}0'">;
def err_objc_directive_only_in_protocol : Error<
"directive may only be specified in protocols only">;
def err_missing_catch_finally : Error<
@@ -407,6 +411,8 @@ def err_missing_catch_finally : Error<
def err_objc_concat_string : Error<"unexpected token after Objective-C string">;
def err_expected_objc_container : Error<
"'@end' must appear in an Objective-C context">;
+def err_objc_unexpected_atend : Error<
+ "'@end' appears where closing brace '}' is expected">;
def error_property_ivar_decl : Error<
"property synthesize requires specification of an ivar">;
def err_synthesized_property_name : Error<
@@ -425,6 +431,8 @@ def err_declaration_does_not_declare_param : Error<
def err_no_matching_param : Error<"parameter named %0 is missing">;
/// C++ parser diagnostics
+def err_invalid_operator_on_type : Error<
+ "cannot use %select{dot|arrow}0 operator on a type">;
def err_expected_unqualified_id : Error<
"expected %select{identifier|unqualified-id}0">;
def err_func_def_no_params : Error<
@@ -464,11 +472,16 @@ def err_destructor_template_id : Error<
"destructor name %0 does not refer to a template">;
def err_default_arg_unparsed : Error<
"unexpected end of default argument expression">;
-def err_parser_impl_limit_overflow : Error<
- "parser recursion limit reached, program too complex">, DefaultFatal;
+def err_bracket_depth_exceeded : Error<
+ "bracket nesting level exceeded maximum of %0">, DefaultFatal;
+def note_bracket_depth : Note<
+ "use -fbracket-depth=N to increase maximum nesting level">;
def err_misplaced_ellipsis_in_declaration : Error<
"'...' must %select{immediately precede declared identifier|"
"be innermost component of anonymous pack declaration}0">;
+def ext_abstract_pack_declarator_parens : ExtWarn<
+ "ISO C++11 requires a parenthesized pack declaration to have a name">,
+ InGroup<DiagGroup<"anonymous-pack-parens">>;
// C++ derived classes
def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">;
@@ -504,12 +517,12 @@ def err_cxx11_attribute_forbids_arguments : Error<
"attribute '%0' cannot have an argument list">;
def err_cxx11_attribute_forbids_ellipsis : Error<
"attribute '%0' cannot be used as an attribute pack">;
+def err_cxx11_attribute_repeated : Error<
+ "attribute %0 cannot appear multiple times in an attribute specifier">;
def err_attributes_not_allowed : Error<"an attribute list cannot appear here">;
def err_l_square_l_square_not_attribute : Error<
"C++11 only allows consecutive left square brackets when "
"introducing an attribute">;
-def err_alignas_pack_exp_unsupported : Error<
- "pack expansions in alignment specifiers are not supported yet">;
def err_ms_declspec_type : Error<
"__declspec attributes must be an identifier or string literal">;
def warn_ms_declspec_unknown : Warning<
@@ -548,7 +561,6 @@ def err_explicit_instantiation_with_definition : Error<
"explicit template instantiation cannot have a definition; if this "
"definition is meant to be an explicit specialization, add '<>' after the "
"'template' keyword">;
-def err_enum_template : Error<"enumeration cannot be a template">;
def err_explicit_instantiation_enum : Error<
"enumerations cannot be explicitly instantiated">;
def err_expected_template_parameter : Error<"expected template parameter">;
@@ -764,14 +776,25 @@ def err_seh___except_filter : Error<
def err_seh___finally_block : Error<
"%0 only allowed in __finally block">;
-
+
+// OpenMP support.
+def warn_pragma_omp_ignored : Warning <
+ "unexpected '#pragma omp ...' in program">, InGroup<SourceUsesOpenMP>, DefaultIgnore;
+def warn_omp_extra_tokens_at_eol : Warning <
+ "extra tokens at end of '#pragma omp %0' are ignored">,
+ InGroup<ExtraTokens>;
+def err_omp_unknown_directive : Error <
+ "expected an OpenMP directive">;
+def err_omp_unexpected_directive : Error <
+ "unexpected OpenMP directive '#pragma omp %0'">;
+
} // end of Parse Issue category.
let CategoryName = "Modules Issue" in {
def err_module_expected_ident : Error<
"expected a module name after module import">;
def err_module_expected_semi : Error<
- "expected a semicolon name after module name">;
+ "expected ';' after module name">;
}
} // end of Parser diagnostics
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 0d64bf3..c4815cd 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -20,6 +20,11 @@ def warn_variables_not_in_loop_body : Warning<
"used in loop condition not modified in loop body">,
InGroup<DiagGroup<"loop-analysis">>, DefaultIgnore;
+def warn_duplicate_enum_values : Warning<
+ "element %0 has been implicitly assigned %1 which another element has "
+ "been assigned">, InGroup<DiagGroup<"duplicate-enum">>, DefaultIgnore;
+def note_duplicate_element : Note<"element %0 also has value %1">;
+
// Constant expressions
def err_expr_not_ice : Error<
"expression is not an %select{integer|integral}0 constant expression">;
@@ -70,7 +75,9 @@ def warn_double_const_requires_fp64 : Warning<
// C99 variable-length arrays
def ext_vla : Extension<"variable length arrays are a C99 feature">,
- InGroup<VLA>;
+ InGroup<VLAExtension>;
+def warn_vla_used : Warning<"variable length array used">,
+ InGroup<VLA>, DefaultIgnore;
def err_vla_non_pod : Error<"variable length array of non-POD element type %0">;
def err_vla_in_sfinae : Error<
"variable length array cannot be formed during template argument deduction">;
@@ -209,6 +216,8 @@ def warn_use_out_of_scope_declaration : Warning<
"use of out-of-scope declaration of %0">;
def err_inline_non_function : Error<
"'inline' can only appear on functions">;
+def err_noreturn_non_function : Error<
+ "'_Noreturn' can only appear on functions">;
def warn_qual_return_type : Warning<
"'%0' type qualifier%s1 on return type %plural{1:has|:have}1 no effect">,
InGroup<IgnoredQualifiers>, DefaultIgnore;
@@ -245,19 +254,20 @@ def note_using_decl_constructor_conflict_previous_ctor : Note<
"previous constructor">;
def note_using_decl_constructor_conflict_previous_using : Note<
"previously inherited here">;
+def warn_using_decl_constructor_ellipsis : Warning<
+ "inheriting constructor does not inherit ellipsis">,
+ InGroup<DiagGroup<"inherited-variadic-ctor">>;
+def note_using_decl_constructor_ellipsis : Note<
+ "constructor declared with ellipsis here">;
def err_using_decl_can_not_refer_to_class_member : Error<
"using declaration can not refer to class member">;
def err_using_decl_can_not_refer_to_namespace : Error<
"using declaration can not refer to namespace">;
def err_using_decl_constructor : Error<
"using declaration can not refer to a constructor">;
-def err_using_decl_constructor_unsupported : Error<
- "inheriting constructors are not supported">;
-// FIXME: Replace the above error with this warning if support for
-// inheriting constructors is implemented.
-//def warn_cxx98_compat_using_decl_constructor : Warning<
-// "inheriting constructors are incompatible with C++98">,
-// InGroup<CXX98Compat>, DefaultIgnore;
+def warn_cxx98_compat_using_decl_constructor : Warning<
+ "inheriting constructors are incompatible with C++98">,
+ InGroup<CXX98Compat>, DefaultIgnore;
def err_using_decl_destructor : Error<
"using declaration can not refer to a destructor">;
def err_using_decl_template_id : Error<
@@ -304,10 +314,10 @@ def err_falloff_nonvoid_block : Error<
"control reaches end of non-void block">;
def warn_suggest_noreturn_function : Warning<
"%select{function|method}0 %1 could be declared with attribute 'noreturn'">,
- InGroup<DiagGroup<"missing-noreturn">>, DefaultIgnore;
+ InGroup<MissingNoreturn>, DefaultIgnore;
def warn_suggest_noreturn_block : Warning<
"block could be declared with attribute 'noreturn'">,
- InGroup<DiagGroup<"missing-noreturn">>, DefaultIgnore;
+ InGroup<MissingNoreturn>, DefaultIgnore;
def warn_unreachable : Warning<"will never be executed">,
InGroup<DiagGroup<"unreachable-code">>, DefaultIgnore;
@@ -331,7 +341,8 @@ def warn_implicit_decl_requires_ucontext : Warning<
"<ucontext.h>">,
InGroup<BuiltinRequiresHeader>;
def warn_redecl_library_builtin : Warning<
- "incompatible redeclaration of library function %0">;
+ "incompatible redeclaration of library function %0">,
+ InGroup<DiagGroup<"incompatible-library-redeclaration">>;
def err_builtin_definition : Error<"definition of builtin function %0">;
def err_types_compatible_p_in_cplusplus : Error<
"__builtin_types_compatible_p is not valid in C++">;
@@ -347,7 +358,7 @@ def note_bad_memaccess_silence : Note<
def warn_sizeof_pointer_expr_memaccess : Warning<
"'%0' call operates on objects of type %1 while the size is based on a "
"different type %2">,
- InGroup<DiagGroup<"sizeof-pointer-memaccess">>;
+ InGroup<SizeofPointerMemaccess>;
def warn_sizeof_pointer_expr_memaccess_note : Note<
"did you mean to %select{dereference the argument to 'sizeof' (and multiply "
"it by the number of elements)|remove the addressof in the argument to "
@@ -356,7 +367,7 @@ def warn_sizeof_pointer_expr_memaccess_note : Note<
def warn_sizeof_pointer_type_memaccess : Warning<
"argument to 'sizeof' in %0 call is the same pointer type %1 as the "
"%select{destination|source}2; expected %3 or an explicit length">,
- InGroup<DiagGroup<"sizeof-pointer-memaccess">>;
+ InGroup<SizeofPointerMemaccess>;
def warn_strlcpycat_wrong_size : Warning<
"size argument in %0 call appears to be size of the source; expected the size of "
"the destination">,
@@ -376,17 +387,21 @@ def note_strncat_wrong_size : Note<
"the terminating null byte">;
/// main()
-// static/inline main() are not errors in C, just in C++.
+// static main() is not an error in C, just in C++.
def warn_static_main : Warning<"'main' should not be declared static">,
InGroup<Main>;
def err_static_main : Error<"'main' is not allowed to be declared static">;
def err_inline_main : Error<"'main' is not allowed to be declared inline">;
+def ext_noreturn_main : ExtWarn<
+ "'main' is not allowed to be declared _Noreturn">, InGroup<Main>;
+def note_main_remove_noreturn : Note<"remove '_Noreturn'">;
def err_constexpr_main : Error<
"'main' is not allowed to be declared constexpr">;
def err_main_template_decl : Error<"'main' cannot be a template">;
def err_main_returns_nonint : Error<"'main' must return 'int'">;
def ext_main_returns_nonint : ExtWarn<"return type of 'main' is not 'int'">,
InGroup<MainReturnType>;
+def note_main_change_return_type : Note<"change return type to 'int'">;
def err_main_surplus_args : Error<"too many parameters (%0) for 'main': "
"must be 0, 2, or 3">;
def warn_main_one_arg : Warning<"only one parameter on 'main' declaration">,
@@ -396,6 +411,8 @@ def err_main_arg_wrong : Error<"%select{first|second|third|fourth}0 "
"platform-specific data}0) must be of type %1">;
/// parser diagnostics
+def ext_no_declarators : ExtWarn<"declaration does not declare anything">,
+ InGroup<MissingDeclarations>;
def ext_typedef_without_a_name : ExtWarn<"typedef requires a name">,
InGroup<MissingDeclarations>;
def err_typedef_not_identifier : Error<"typedef name must be an identifier">;
@@ -406,6 +423,15 @@ def err_object_cannot_be_passed_returned_by_value : Error<
"; did you forget * in %1?">;
def err_parameters_retval_cannot_have_fp16_type : Error<
"%select{parameters|function return value}0 cannot have __fp16 type; did you forget * ?">;
+def err_opencl_half_load_store : Error<
+ "%select{loading directly from|assigning directly to}0 pointer to type %1 is not allowed">;
+def err_opencl_cast_to_half : Error<"casting to type %0 is not allowed">;
+def err_opencl_half_declaration : Error<
+ "declaring variable of type %0 is not allowed">;
+def err_opencl_half_argument : Error<
+ "declaring function argument of type %0 is not allowed; did you forget * ?">;
+def err_opencl_half_return : Error<
+ "declaring function return value of type %0 is not allowed; did you forget * ?">;
def warn_enum_value_overflow : Warning<"overflow in enumeration value">;
def warn_pragma_options_align_reset_failed : Warning<
"#pragma options align=reset failed: %0">;
@@ -456,7 +482,7 @@ def warn_readonly_property : Warning<
"'readwrite' of property inherited from %1">;
def warn_property_attribute : Warning<
- "property %0 '%1' attribute does not match the property inherited from %2">;
+ "'%1' attribute on property %0 does not match the property inherited from %2">;
def warn_property_types_are_incompatible : Warning<
"property type %0 is incompatible with type %1 inherited from %2">;
def err_undef_interface : Error<"cannot find interface declaration for %0">;
@@ -499,9 +525,8 @@ def err_conflicting_ivar_name : Error<
"conflicting instance variable names: %0 vs %1">;
def err_inconsistant_ivar_count : Error<
"inconsistent number of instance variables specified">;
-def warn_incomplete_impl : Warning<"incomplete implementation">,
+def warn_undef_method_impl : Warning<"method definition for %0 not found">,
InGroup<DiagGroup<"incomplete-implementation">>;
-def note_undef_method_impl : Note<"method definition for %0 not found">;
def note_required_for_protocol_at :
Note<"required for direct or indirect protocol %0">;
@@ -523,7 +548,7 @@ def warn_conflicting_overriding_ret_type_modifiers : Warning<
def warn_conflicting_ret_type_modifiers : Warning<
"conflicting distributed object modifiers on return type "
"in implementation of %0">,
- InGroup<DiagGroup<"distributed-object-modifiers">>;
+ InGroup<DistributedObjectModifiers>;
def warn_non_covariant_overriding_ret_types : Warning<
"conflicting return type in "
@@ -533,7 +558,7 @@ def warn_non_covariant_overriding_ret_types : Warning<
def warn_non_covariant_ret_types : Warning<
"conflicting return type in "
"implementation of %0: %1 vs %2">,
- InGroup<DiagGroup<"method-signatures">>, DefaultIgnore;
+ InGroup<MethodSignatures>, DefaultIgnore;
def warn_conflicting_overriding_param_types : Warning<
"conflicting parameter types in "
@@ -548,7 +573,7 @@ def warn_conflicting_param_types : Warning<
def warn_conflicting_param_modifiers : Warning<
"conflicting distributed object modifiers on parameter type "
"in implementation of %0">,
- InGroup<DiagGroup<"distributed-object-modifiers">>;
+ InGroup<DistributedObjectModifiers>;
def warn_conflicting_overriding_param_modifiers : Warning<
"conflicting distributed object modifiers on parameter type "
@@ -563,7 +588,7 @@ def warn_non_contravariant_overriding_param_types : Warning<
def warn_non_contravariant_param_types : Warning<
"conflicting parameter types in "
"implementation of %0: %1 vs %2">,
- InGroup<DiagGroup<"method-signatures">>, DefaultIgnore;
+ InGroup<MethodSignatures>, DefaultIgnore;
def warn_conflicting_overriding_variadic :Warning<
"conflicting variadic declaration of method and its "
@@ -609,9 +634,11 @@ def warn_objc_property_no_assignment_attribute : Warning<
"'assign' is assumed">,
InGroup<ObjCPropertyNoAttribute>;
def warn_objc_isa_use : Warning<
- "direct access to objective-c's isa is deprecated "
- "in favor of object_setClass() and object_getClass()">,
- InGroup<DiagGroup<"deprecated-objc-isa-usage">>;
+ "direct access to Objective-C's isa is deprecated in favor of "
+ "object_getClass()">, InGroup<DeprecatedObjCIsaUsage>;
+def warn_objc_isa_assign : Warning<
+ "assignment to Objective-C's isa is deprecated in favor of "
+ "object_setClass()">, InGroup<DeprecatedObjCIsaUsage>;
def warn_objc_property_default_assign_on_object : Warning<
"default property attribute 'assign' not appropriate for non-GC object">,
InGroup<ObjCPropertyNoAttribute>;
@@ -643,6 +670,15 @@ def warn_auto_synthesizing_protocol_property :Warning<
"auto property synthesis will not synthesize property"
" declared in a protocol">,
InGroup<DiagGroup<"objc-protocol-property-synthesis">>;
+def warn_no_autosynthesis_shared_ivar_property : Warning <
+ "auto property synthesis will not synthesize property "
+ "'%0' because it cannot share an ivar with another synthesized property">,
+ InGroup<ObjCNoPropertyAutoSynthesis>;
+def warn_no_autosynthesis_property : Warning<
+ "auto property synthesis will not synthesize property "
+ "'%0' because it is 'readwrite' but it will be synthesized 'readonly' "
+ "via another property">,
+ InGroup<ObjCNoPropertyAutoSynthesis>;
def warn_autosynthesis_property_ivar_match :Warning<
"autosynthesized property %0 will use %select{|synthesized}1 instance variable "
"%2, not existing instance variable %3">,
@@ -684,6 +720,8 @@ def error_category_property : Error<
"class implementation">;
def note_property_declare : Note<
"property declared here">;
+def note_property_synthesize : Note<
+ "property synthesized here">;
def error_synthesize_category_decl : Error<
"@synthesize not allowed in a category's implementation">;
def error_reference_property : Error<
@@ -762,9 +800,9 @@ def warn_undeclared_selector : Warning<
def warn_implicit_atomic_property : Warning<
"property is assumed atomic by default">, InGroup<ImplicitAtomic>, DefaultIgnore;
def note_auto_readonly_iboutlet_fixup_suggest : Note<
- "readonly IBOutlet property should be changed to be readwrite">;
+ "property should be changed to be readwrite">;
def warn_auto_readonly_iboutlet_property : Warning<
- "readonly IBOutlet property when auto-synthesized may "
+ "readonly IBOutlet property '%0' when auto-synthesized may "
"not work correctly with 'nib' loader">,
InGroup<DiagGroup<"readonly-iboutlet-property">>;
def warn_auto_implicit_atomic_property : Warning<
@@ -829,6 +867,8 @@ def err_friend_def_in_local_class : Error<
"friend function cannot be defined in a local class">;
def err_friend_not_first_in_declaration : Error<
"'friend' must appear first in a non-function declaration">;
+def err_using_decl_friend : Error<
+ "cannot befriend target of using declaration">;
def err_invalid_member_in_interface : Error<
"%select{data member |non-public member function |static member function |"
@@ -892,6 +932,8 @@ def err_distant_exception_spec : Error<
def err_incomplete_in_exception_spec : Error<
"%select{|pointer to |reference to }0incomplete type %1 is not allowed "
"in exception specification">;
+def err_rref_in_exception_spec : Error<
+ "rvalue reference type %0 is not allowed in exception specification">;
def err_mismatched_exception_spec : Error<
"exception specification in declaration does not match previous declaration">;
def warn_mismatched_exception_spec : ExtWarn<
@@ -1063,14 +1105,18 @@ def note_field_decl : Note<"member is declared here">;
def note_ivar_decl : Note<"instance variable is declared here">;
def note_bitfield_decl : Note<"bit-field is declared here">;
def note_previous_decl : Note<"%0 declared here">;
+def note_implicit_param_decl : Note<"%0 is an implicit parameter">;
def note_member_synthesized_at : Note<
"implicit default %select{constructor|copy constructor|move constructor|copy "
"assignment operator|move assignment operator|destructor}0 for %1 first "
"required here">;
+def note_inhctor_synthesized_at : Note<
+ "inheriting constructor for %0 first required here">;
def err_missing_default_ctor : Error<
- "%select{|implicit default }0constructor for %1 must explicitly initialize "
- "the %select{base class|member}2 %3 which does not have a default "
+ "%select{|implicit default |inheriting }0constructor for %1 must explicitly "
+ "initialize the %select{base class|member}2 %3 which does not have a default "
"constructor">;
+
def err_illegal_union_or_anon_struct_member : Error<
"%select{anonymous struct|union}0 member %1 has a non-trivial "
"%select{constructor|copy constructor|move constructor|copy assignment "
@@ -1080,16 +1126,38 @@ def warn_cxx98_compat_nontrivial_union_or_anon_struct_member : Warning<
"%select{constructor|copy constructor|move constructor|copy assignment "
"operator|move assignment operator|destructor}2 is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
+
+def note_nontrivial_virtual_dtor : Note<
+ "destructor for %0 is not trivial because it is virtual">;
def note_nontrivial_has_virtual : Note<
"because type %0 has a virtual %select{member function|base class}1">;
-def note_nontrivial_has_nontrivial : Note<
- "because type %0 has a %select{member|base class}1 with a non-trivial "
- "%select{constructor|copy constructor|move constructor|copy assignment "
- "operator|move assignment operator|destructor}2">;
-def note_nontrivial_user_defined : Note<
- "because type %0 has a user-declared %select{constructor|copy constructor|"
- "move constructor|copy assignment operator|move assignment operator|"
- "destructor}1">;
+def note_nontrivial_no_def_ctor : Note<
+ "because %select{base class of |field of |}0type %1 has no "
+ "default constructor">;
+def note_user_declared_ctor : Note<
+ "implicit default constructor suppressed by user-declared constructor">;
+def note_nontrivial_no_copy : Note<
+ "because no %select{<<ERROR>>|constructor|constructor|assignment operator|"
+ "assignment operator|<<ERROR>>}2 can be used to "
+ "%select{<<ERROR>>|copy|move|copy|move|<<ERROR>>}2 "
+ "%select{base class|field|an object}0 of type %3">;
+def note_nontrivial_user_provided : Note<
+ "because %select{base class of |field of |}0type %1 has a user-provided "
+ "%select{default constructor|copy constructor|move constructor|"
+ "copy assignment operator|move assignment operator|destructor}2">;
+def note_nontrivial_in_class_init : Note<
+ "because field %0 has an initializer">;
+def note_nontrivial_param_type : Note<
+ "because its parameter is %diff{of type $, not $|of the wrong type}2,3">;
+def note_nontrivial_default_arg : Note<"because it has a default argument">;
+def note_nontrivial_variadic : Note<"because it is a variadic function">;
+def note_nontrivial_subobject : Note<
+ "because the function selected to %select{construct|copy|move|copy|move|"
+ "destroy}2 %select{base class|field}0 of type %1 is not trivial">;
+def note_nontrivial_objc_ownership : Note<
+ "because type %0 has a member with %select{no|no|__strong|__weak|"
+ "__autoreleasing}1 ownership">;
+
def err_static_data_member_not_allowed_in_anon_struct : Error<
"static data member %0 not allowed in anonymous struct">;
def ext_static_data_member_in_union : ExtWarn<
@@ -1100,14 +1168,17 @@ def warn_cxx98_compat_static_data_member_in_union : Warning<
def err_union_member_of_reference_type : Error<
"union member %0 has reference type %1">;
def ext_anonymous_struct_union_qualified : Extension<
- "anonymous %select{struct|union}0 cannot be '%select{const|volatile|"
- "restrict}1'">;
+ "anonymous %select{struct|union}0 cannot be '%1'">;
def err_different_return_type_for_overriding_virtual_function : Error<
"virtual function %0 has a different return type "
"%diff{($) than the function it overrides (which has return type $)|"
"than the function it overrides}1,2">;
def note_overridden_virtual_function : Note<
"overridden virtual function is here">;
+def err_conflicting_overriding_cc_attributes : Error<
+ "virtual function %0 has different calling convention attributes "
+ "%diff{($) than the function it overrides (which has calling convention $)|"
+ "than the function it overrides}1,2">;
def err_covariant_return_inaccessible_base : Error<
"invalid covariant return for virtual function: %1 is a "
@@ -1236,6 +1307,8 @@ def err_reference_var_requires_init : Error<
"declaration of reference variable %0 requires an initializer">;
def err_reference_without_init : Error<
"reference to type %0 requires an initializer">;
+def note_value_initialization_here : Note<
+ "in value-initialization of type %0 here">;
def err_reference_has_multiple_inits : Error<
"reference cannot be initialized with multiple values">;
def err_init_non_aggr_init_list : Error<
@@ -1249,6 +1322,9 @@ def warn_field_is_uninit : Warning<"field %0 is uninitialized when used here">,
def warn_reference_field_is_uninit : Warning<
"reference %0 is not yet bound to a value when used here">,
InGroup<Uninitialized>;
+def warn_static_self_reference_in_init : Warning<
+ "static variable %0 is suspiciously used within its own initialization">,
+ InGroup<UninitializedStaticSelfInit>;
def warn_uninit_self_reference_in_init : Warning<
"variable %0 is uninitialized when used within its own initialization">,
InGroup<Uninitialized>;
@@ -1284,6 +1360,11 @@ def note_uninit_fixit_remove_cond : Note<
"is always %select{false|true}2">;
def err_init_incomplete_type : Error<"initialization of incomplete type %0">;
+def warn_unsequenced_mod_mod : Warning<
+ "multiple unsequenced modifications to %0">, InGroup<Unsequenced>;
+def warn_unsequenced_mod_use : Warning<
+ "unsequenced modification and access to %0">, InGroup<Unsequenced>;
+
def err_temp_copy_no_viable : Error<
"no viable constructor %select{copying variable|copying parameter|"
"returning object|throwing object|copying member subobject|copying array "
@@ -1469,6 +1550,8 @@ def warn_cxx98_compat_constexpr : Warning<
def err_invalid_constexpr : Error<
"%select{function parameter|typedef|non-static data member}0 "
"cannot be constexpr">;
+def err_invalid_constexpr_member : Error<"non-static data member cannot be "
+ "constexpr%select{; did you intend to make it %select{const|static}0?|}1">;
def err_constexpr_tag : Error<
"%select{class|struct|interface|union|enum}0 cannot be marked constexpr">;
def err_constexpr_dtor : Error<"destructor cannot be marked constexpr">;
@@ -1509,7 +1592,7 @@ def err_constexpr_vla : Error<
"%select{function|constructor}1">;
def err_constexpr_var_declaration : Error<
"variables cannot be declared in a constexpr %select{function|constructor}0">;
-def err_constexpr_function_never_constant_expr : ExtWarn<
+def ext_constexpr_function_never_constant_expr : ExtWarn<
"constexpr %select{function|constructor}0 never produces a "
"constant expression">, InGroup<DiagGroup<"invalid-constexpr">>, DefaultError;
def err_constexpr_body_no_return : Error<
@@ -1584,8 +1667,19 @@ def err_attribute_argument_not_int : Error<
"'%0' attribute requires integer constant">;
def err_aligned_attribute_argument_not_int : Error<
"'aligned' attribute requires integer constant">;
-def err_attribute_argument_not_class : Error<
- "%0 attribute requires arguments that are class type or point to class type">;
+def err_alignas_attribute_wrong_decl_type : Error<
+ "'%select{alignas|_Alignas}0' attribute cannot be applied to a %select{"
+ "function parameter|variable with 'register' storage class|"
+ "'catch' variable|bit-field}1">;
+def err_alignas_missing_on_definition : Error<
+ "'%select{alignas|_Alignas}0' must be specified on definition if it is "
+ "specified on any declaration">;
+def note_alignas_on_declaration : Note<
+ "declared with '%select{alignas|_Alignas}0' attribute here">;
+def err_alignas_mismatch : Error<
+ "redeclaration has different alignment requirement (%1 vs %0)">;
+def err_alignas_underaligned : Error<
+ "requested alignment is less than minimum alignment of %1 for type %0">;
def err_attribute_first_argument_not_int_or_bool : Error<
"%0 attribute first argument must be of int or bool type">;
def err_attribute_argument_outof_range : Error<
@@ -1594,6 +1688,8 @@ def err_attribute_argument_outof_range : Error<
def err_init_priority_object_attr : Error<
"can only use 'init_priority' attribute on file-scope definitions "
"of objects of class type">;
+def err_attribute_argument_vec_type_hint : Error<
+ "invalid attribute argument %0 - expecting a vector or vectorizable scalar type">;
def err_attribute_argument_n_not_int : Error<
"'%0' attribute requires parameter %1 to be an integer constant">;
def err_attribute_argument_n_not_string : Error<
@@ -1651,6 +1747,8 @@ def err_as_qualified_auto_decl : Error<
"automatic variable qualified with an address space">;
def err_arg_with_address_space : Error<
"parameter may not be qualified with an address space">;
+def err_field_with_address_space : Error<
+ "field may not be qualified with an address space">;
def err_attr_objc_ownership_redundant : Error<
"the type %0 is already explicitly ownership-qualified">;
def err_attribute_not_string : Error<
@@ -1725,12 +1823,14 @@ def warn_attribute_after_definition_ignored : Warning<
InGroup<IgnoredAttributes>;
def warn_unknown_attribute_ignored : Warning<
"unknown attribute %0 ignored">, InGroup<UnknownAttributes>;
+def warn_cxx11_gnu_attribute_on_type : Warning<
+ "attribute %0 ignored, because it cannot be applied to a type">,
+ InGroup<IgnoredAttributes>;
def warn_unhandled_ms_attribute_ignored : Warning<
"__declspec attribute %0 is not supported">,
InGroup<IgnoredAttributes>;
-def warn_attribute_invalid_on_stmt : Warning<
- "attribute %0 cannot be specified on a statement">,
- InGroup<IgnoredAttributes>;
+def err_attribute_invalid_on_stmt : Error<
+ "%0 attribute cannot be applied to a statement">;
def warn_declspec_attribute_ignored : Warning<
"attribute %0 is ignored, place it after "
"\"%select{class|struct|union|interface|enum}1\" to apply attribute to "
@@ -1773,17 +1873,22 @@ def err_alias_not_supported_on_darwin : Error <
def warn_attribute_wrong_decl_type : Warning<
"%0 attribute only applies to %select{functions|unions|"
"variables and functions|functions and methods|parameters|"
- "functions, methods and blocks|functions, methods, and parameters|"
- "classes|variables|methods|variables, functions and labels|"
- "fields and global variables|structs|"
- "variables, functions and tag types|thread-local variables}1">,
+ "functions, methods and blocks|functions, methods, and classes|"
+ "functions, methods, and parameters|classes|variables|methods|"
+ "variables, functions and labels|fields and global variables|structs|"
+ "variables, functions and tag types|thread-local variables|"
+ "variables and fields|variables, data members and tag types|"
+ "types and namespaces}1">,
InGroup<IgnoredAttributes>;
def err_attribute_wrong_decl_type : Error<
"%0 attribute only applies to %select{functions|unions|"
"variables and functions|functions and methods|parameters|"
- "functions, methods and blocks|functions, methods, and parameters|"
- "classes|variables|methods|variables, functions and labels|"
- "fields and global variables|structs|thread-local variables}1">;
+ "functions, methods and blocks|functions, methods, and classes|"
+ "functions, methods, and parameters|classes|variables|methods|"
+ "variables, functions and labels|fields and global variables|structs|"
+ "variables, functions and tag types|thread-local variables|"
+ "variables and fields|variables, data members and tag types|"
+ "types and namespaces}1">;
def warn_function_attribute_wrong_type : Warning<
"'%0' only applies to function types; type here is %1">,
InGroup<IgnoredAttributes>;
@@ -1813,7 +1918,7 @@ def err_cconv_knr : Error<
"function with no prototype cannot use %0 calling convention">;
def err_cconv_varargs : Error<
"variadic function cannot use %0 calling convention">;
-def err_regparm_mismatch : Error<"function declared with with regparm(%0) "
+def err_regparm_mismatch : Error<"function declared with regparm(%0) "
"attribute was previously declared "
"%plural{0:without the regparm|:with the regparm(%1)}1 attribute">;
def err_returns_retained_mismatch : Error<
@@ -1824,11 +1929,13 @@ def err_objc_precise_lifetime_bad_type : Error<
def warn_objc_precise_lifetime_meaningless : Error<
"objc_precise_lifetime is not meaningful for "
"%select{__unsafe_unretained|__autoreleasing}0 objects">;
-def err_invalid_pcs : Error<"Invalid PCS type">;
+def err_invalid_pcs : Error<"invalid PCS type">;
def err_attribute_can_be_applied_only_to_value_decl : Error<
"%0 attribute can only be applied to value declarations">;
-def warn_attribute_not_on_decl : Error<
- "%0 attribute ignored when parsing type">;
+def warn_attribute_not_on_decl : Warning<
+ "%0 attribute ignored when parsing type">, InGroup<IgnoredAttributes>;
+def err_base_specifier_attribute : Error<
+ "%0 attribute cannot be applied to a base specifier">;
// Availability attribute
def warn_availability_unknown_platform : Warning<
@@ -1839,6 +1946,16 @@ def warn_availability_version_ordering : Warning<
"attribute ignored">, InGroup<Availability>;
def warn_mismatched_availability: Warning<
"availability does not match previous declaration">, InGroup<Availability>;
+def warn_mismatched_availability_override : Warning<
+ "overriding method %select{introduced after|"
+ "deprecated before|obsoleted before}0 overridden method on %1 (%2 vs. %3)">,
+ InGroup<Availability>;
+def warn_mismatched_availability_override_unavail : Warning<
+ "overriding method cannot be unavailable on %0 when its overridden method is "
+ "available">,
+ InGroup<Availability>;
+def note_overridden_method : Note<
+ "overridden method is here">;
// Thread Safety Attributes
def warn_thread_attribute_ignored : Warning<
@@ -1938,18 +2055,22 @@ def warn_fun_requires_lock_precise : Warning<
InGroup<ThreadSafetyPrecise>, DefaultIgnore;
def note_found_mutex_near_match : Note<"found near match '%0'">;
+// Dummy warning that will trigger "beta" warnings from the analysis if enabled.
+def warn_thread_safety_beta : Warning<
+ "Thread safety beta warning.">, InGroup<ThreadSafetyBeta>, DefaultIgnore;
+
def warn_impcast_vector_scalar : Warning<
"implicit conversion turns vector to scalar: %0 to %1">,
- InGroup<DiagGroup<"conversion">>, DefaultIgnore;
+ InGroup<Conversion>, DefaultIgnore;
def warn_impcast_complex_scalar : Warning<
"implicit conversion discards imaginary component: %0 to %1">,
- InGroup<DiagGroup<"conversion">>, DefaultIgnore;
+ InGroup<Conversion>, DefaultIgnore;
def warn_impcast_float_precision : Warning<
"implicit conversion loses floating-point precision: %0 to %1">,
- InGroup<DiagGroup<"conversion">>, DefaultIgnore;
+ InGroup<Conversion>, DefaultIgnore;
def warn_impcast_float_integer : Warning<
"implicit conversion turns floating-point number into integer: %0 to %1">,
- InGroup<DiagGroup<"conversion">>, DefaultIgnore;
+ InGroup<Conversion>, DefaultIgnore;
def warn_impcast_integer_sign : Warning<
"implicit conversion changes signedness: %0 to %1">,
InGroup<SignConversion>, DefaultIgnore;
@@ -1958,7 +2079,7 @@ def warn_impcast_integer_sign_conditional : Warning<
InGroup<SignConversion>, DefaultIgnore;
def warn_impcast_integer_precision : Warning<
"implicit conversion loses integer precision: %0 to %1">,
- InGroup<DiagGroup<"conversion">>, DefaultIgnore;
+ InGroup<Conversion>, DefaultIgnore;
def warn_impcast_integer_64_32 : Warning<
"implicit conversion loses integer precision: %0 to %1">,
InGroup<Shorten64To32>, DefaultIgnore;
@@ -2036,6 +2157,8 @@ def warn_attribute_protected_visibility :
Warning<"target does not support 'protected' visibility; using 'default'">,
InGroup<DiagGroup<"unsupported-visibility">>;
def err_mismatched_visibility: Error<"visibility does not match previous declaration">;
+def warn_attribute_unknown_endian : Warning<"unknown endian '%0'">,
+ InGroup<IgnoredAttributes>;
def note_previous_attribute : Note<"previous attribute is here">;
def err_unknown_machine_mode : Error<"unknown machine mode %0">;
def err_unsupported_machine_mode : Error<"unsupported machine mode %0">;
@@ -2158,15 +2281,11 @@ def err_uninitialized_member_for_assign : Error<
"non-static %select{reference|const}1 member %2 can't use default "
"assignment operator">;
def err_uninitialized_member_in_ctor : Error<
- "%select{|implicit default }0constructor for %1 must explicitly initialize "
- "the %select{reference|const}2 member %3">;
-def warn_default_arg_makes_ctor_special : Warning<
+ "%select{|implicit default |inheriting }0constructor for %1 must explicitly "
+ "initialize the %select{reference|const}2 member %3">;
+def err_default_arg_makes_ctor_special : Error<
"addition of default argument on redeclaration makes this constructor a "
- "%select{default|copy|move}0 constructor">, InGroup<DefaultArgSpecialMember>;
-def note_previous_declaration_special : Note<
- // The ERRORs are in hopes that if they occur, they'll get reported.
- "previous declaration was %select{*ERROR*|a copy constructor|a move "
- "constructor|*ERROR*|*ERROR*|*ERROR*|not a special member function}0">;
+ "%select{default|copy|move}0 constructor">;
def err_use_of_default_argument_to_function_declared_later : Error<
"use of default argument to function %0 that is declared later in class %1">;
@@ -2246,6 +2365,11 @@ def note_ovl_candidate_substitution_failure : Note<
"candidate template ignored: substitution failure%0%1">;
def note_ovl_candidate_disabled_by_enable_if : Note<
"candidate template ignored: disabled by %0%1">;
+def note_ovl_candidate_failed_overload_resolution : Note<
+ "candidate template ignored: couldn't resolve reference to overloaded "
+ "function %0">;
+def note_ovl_candidate_non_deduced_mismatch : Note<
+ "candidate template ignored: could not match %diff{$ against $|types}0,1">;
// Note that we don't treat templates differently for this diagnostic.
def note_ovl_candidate_arity : Note<"candidate "
@@ -2473,9 +2597,10 @@ def err_ovl_no_viable_oper : Error<"no viable overloaded '%0'">;
def err_ovl_deleted_oper : Error<
"overload resolution selected %select{unavailable|deleted}0 operator '%1'%2">;
def err_ovl_deleted_special_oper : Error<
- "overload resolution selected implicitly-deleted %select{default constructor|"
- "copy constructor|move constructor|copy assignment operator|move assignment "
- "operator|destructor|'%1'}0%2">;
+ "object of type %0 cannot be %select{constructed|copied|moved|assigned|"
+ "assigned|destroyed}1 because its %select{default constructor|"
+ "copy constructor|move constructor|copy assignment operator|"
+ "move assignment operator|destructor}1 is implicitly deleted">;
def err_ovl_no_viable_subscript :
Error<"no viable overloaded operator[] for type %0">;
def err_ovl_no_oper :
@@ -2597,7 +2722,7 @@ def err_template_arg_must_be_type_suggest : Error<
def err_template_arg_must_be_expr : Error<
"template argument for non-type template parameter must be an expression">;
def err_template_arg_nontype_ambig : Error<
- "template argument for non-type template parameter is treated as type %0">;
+ "template argument for non-type template parameter is treated as function type %0">;
def err_template_arg_must_be_template : Error<
"template argument for template template parameter must be a class template%select{| or type alias template}0">;
def ext_template_arg_local_type : ExtWarn<
@@ -3021,9 +3146,9 @@ def warn_cxx98_compat_template_outside_of_template : Warning<
InGroup<CXX98Compat>, DefaultIgnore;
def err_non_type_template_in_nested_name_specifier : Error<
- "qualified name refers into a specialization of function template '%0'">;
+ "qualified name refers into a specialization of function template %0">;
def err_template_id_not_a_type : Error<
- "template name refers to non-type template '%0'">;
+ "template name refers to non-type template %0">;
def note_template_declared_here : Note<
"%select{function template|class template|type alias template|template template parameter}0 "
"%1 declared here">;
@@ -3142,6 +3267,8 @@ def note_sentinel_here : Note<
def warn_missing_prototype : Warning<
"no previous prototype for function %0">,
InGroup<DiagGroup<"missing-prototypes">>, DefaultIgnore;
+def note_declaration_not_a_prototype : Note<
+ "this declaration is not a prototype; add 'void' to make it a prototype for a zero-parameter function">;
def warn_missing_variable_declarations : Warning<
"no previous extern declaration for non-static variable %0">,
InGroup<DiagGroup<"missing-variable-declarations">>, DefaultIgnore;
@@ -3189,18 +3316,23 @@ def note_deleted_assign_field : Note<
"%select{copy|move}0 assignment operator of %1 is implicitly deleted "
"because field %2 is of %select{reference|const-qualified}4 type %3">;
-// This should eventually be an error.
+// These should be errors.
def warn_undefined_internal : Warning<
"%select{function|variable}0 %q1 has internal linkage but is not defined">,
- DiagGroup<"undefined-internal">;
+ InGroup<DiagGroup<"undefined-internal">>;
+def warn_undefined_inline : Warning<"inline function %q0 is not defined">,
+ InGroup<DiagGroup<"undefined-inline">>;
def note_used_here : Note<"used here">;
def warn_internal_in_extern_inline : ExtWarn<
"static %select{function|variable}0 %1 is used in an inline function with "
- "external linkage">, InGroup<DiagGroup<"static-in-inline"> >;
+ "external linkage">, InGroup<StaticInInline>;
def ext_internal_in_extern_inline : Extension<
"static %select{function|variable}0 %1 is used in an inline function with "
- "external linkage">, InGroup<DiagGroup<"static-in-inline"> >;
+ "external linkage">, InGroup<StaticInInline>;
+def warn_static_local_in_extern_inline : Warning<
+ "non-constant static local variable in inline function may be different "
+ "in different files">, InGroup<StaticLocalInInline>;
def note_convert_inline_to_static : Note<
"use 'static' to give inline function %0 internal linkage">;
def note_internal_decl_declared_here : Note<
@@ -3216,6 +3348,8 @@ def err_inline_declaration_block_scope : Error<
"inline declaration of %0 not allowed in block scope">;
def err_static_non_static : Error<
"static declaration of %0 follows non-static declaration">;
+def err_different_language_linkage : Error<
+ "declaration of %0 has a different language linkage">;
def warn_weak_import : Warning <
"an already-declared variable is made a weak_import declaration %0">;
def warn_static_non_static : ExtWarn<
@@ -3304,7 +3438,7 @@ def err_array_too_large : Error<
"array is too large (%0 elements)">;
def warn_array_new_too_large : Warning<"array is too large (%0 elements)">,
// FIXME PR11644: ", will throw std::bad_array_new_length at runtime"
- InGroup<DiagGroup<"bad-array-new-length">>;
+ InGroup<BadArrayNewLength>;
// -Wpadded, -Wpacked
def warn_padded_struct_field : Warning<
@@ -3324,7 +3458,7 @@ def warn_unnecessary_packed : Warning<
def err_typecheck_negative_array_size : Error<"array size is negative">;
def warn_typecheck_negative_array_new_size : Warning<"array size is negative">,
// FIXME PR11644: ", will throw std::bad_array_new_length at runtime"
- InGroup<DiagGroup<"bad-array-new-length">>;
+ InGroup<BadArrayNewLength>;
def warn_typecheck_function_qualifiers : Warning<
"qualifier on function type %0 has unspecified behavior">;
def err_typecheck_invalid_restrict_not_pointer : Error<
@@ -3339,7 +3473,7 @@ def err_typecheck_zero_array_size : Error<
"zero-length arrays are not permitted in C++">;
def warn_typecheck_zero_static_array_size : Warning<
"'static' has no effect on zero-length arrays">,
- InGroup<DiagGroup<"array-bounds">>;
+ InGroup<ArrayBounds>;
def err_array_size_non_int : Error<"size of array has non-integer type %0">;
def err_init_element_not_constant : Error<
"initializer element is not a compile-time constant">;
@@ -3610,8 +3744,9 @@ def err_arc_mismatched_cast : Error<
" to %3 is disallowed with ARC">;
def err_arc_nolifetime_behavior : Error<
"explicit ownership qualifier on cast result has no effect">;
-def err_arc_objc_object_in_struct : Error<
- "ARC forbids %select{Objective-C objects|blocks}0 in structs or unions">;
+def err_arc_objc_object_in_tag : Error<
+ "ARC forbids %select{Objective-C objects|blocks}0 in "
+ "%select{struct|interface|union|<<ERROR>>|enum}1">;
def err_arc_objc_property_default_assign_on_object : Error<
"ARC forbids synthesizing a property of an Objective-C object "
"with unspecified ownership or storage attribute">;
@@ -3653,6 +3788,11 @@ def warn_arc_retained_property_assign : Warning<
"assigning retained object to unsafe property"
"; object will be released after assignment">,
InGroup<ARCUnsafeRetainedAssign>;
+def warn_arc_literal_assign : Warning<
+ "assigning %select{array literal|dictionary literal|numeric literal|boxed expression|<should not happen>|block literal}0"
+ " to a weak %select{property|variable}1"
+ "; object will be released after assignment">,
+ InGroup<ARCUnsafeRetainedAssign>;
def err_arc_new_array_without_ownership : Error<
"'new' cannot allocate an array of %0 with no explicit ownership">;
def err_arc_autoreleasing_var : Error<
@@ -3691,6 +3831,10 @@ def err_arc_collection_forward : Error<
def err_arc_multiple_method_decl : Error<
"multiple methods named %0 found with mismatched result, "
"parameter type or attributes">;
+def warn_arc_lifetime_result_type : Warning<
+ "ARC %select{unused|__unsafe_unretained|__strong|__weak|__autoreleasing}0 "
+ "lifetime qualifier on return type is ignored">,
+ InGroup<IgnoredQualifiers>;
let CategoryName = "ARC Retain Cycle" in {
@@ -3703,9 +3847,6 @@ def note_arc_retain_cycle_owner : Note<
} // end "ARC Retain Cycle" category
-def note_nontrivial_objc_ownership : Note<
- "because type %0 has %select{no|no|__strong|__weak|__autoreleasing}1 "
- "ownership">;
def warn_arc_object_memaccess : Warning<
"%select{destination for|source of}0 this %1 call is a pointer to "
"ownership-qualified type %2">, InGroup<ARCNonPodMemAccess>;
@@ -3743,12 +3884,20 @@ def err_arc_cast_requires_bridge : Error<
"requires a bridged cast">;
def note_arc_bridge : Note<
"use __bridge to convert directly (no change in ownership)">;
+def note_arc_cstyle_bridge : Note<
+ "use __bridge with C-style cast to convert directly (no change in ownership)">;
def note_arc_bridge_transfer : Note<
"use %select{__bridge_transfer|CFBridgingRelease call}1 to transfer "
"ownership of a +1 %0 into ARC">;
+def note_arc_cstyle_bridge_transfer : Note<
+ "use __bridge_transfer with C-style cast to transfer "
+ "ownership of a +1 %0 into ARC">;
def note_arc_bridge_retained : Note<
"use %select{__bridge_retained|CFBridgingRetain call}1 to make an "
"ARC object available as a +1 %0">;
+def note_arc_cstyle_bridge_retained : Note<
+ "use __bridge_retained with C-style cast to make an "
+ "ARC object available as a +1 %0">;
} // ARC Casting category
@@ -3796,16 +3945,17 @@ def err_atomic_specifier_bad_type : Error<
"%1 %select{||||||which is not trivially copyable}0">;
// Expressions.
-def ext_sizeof_function_type : Extension<
- "invalid application of 'sizeof' to a function type">, InGroup<PointerArith>;
-def ext_sizeof_void_type : Extension<
- "invalid application of '%select{sizeof|__alignof|vec_step}0' to a void "
+def ext_sizeof_alignof_function_type : Extension<
+ "invalid application of '%select{sizeof|alignof|vec_step}0' to a "
+ "function type">, InGroup<PointerArith>;
+def ext_sizeof_alignof_void_type : Extension<
+ "invalid application of '%select{sizeof|alignof|vec_step}0' to a void "
"type">, InGroup<PointerArith>;
def err_sizeof_alignof_incomplete_type : Error<
- "invalid application of '%select{sizeof|__alignof|vec_step}0' to an "
+ "invalid application of '%select{sizeof|alignof|vec_step}0' to an "
"incomplete type %1">;
def err_sizeof_alignof_bitfield : Error<
- "invalid application of '%select{sizeof|__alignof}0' to bit-field">;
+ "invalid application of '%select{sizeof|alignof}0' to bit-field">;
def err_vecstep_non_scalar_vector_type : Error<
"'vec_step' requires built-in scalar or vector type, %0 invalid">;
def err_offsetof_incomplete_type : Error<
@@ -3888,6 +4038,10 @@ def warn_sizeof_array_param : Warning<
"sizeof on array function parameter will return size of %0 instead of %1">,
InGroup<SizeofArrayArgument>;
+def warn_sizeof_array_decay : Warning<
+ "sizeof on pointer operation will return size of %0 instead of %1">,
+ InGroup<SizeofArrayDecay>;
+
def err_sizeof_nonfragile_interface : Error<
"application of '%select{alignof|sizeof}1' to interface %0 is "
"not supported on this architecture and platform">;
@@ -3912,6 +4066,8 @@ def err_subscript_function_type : Error<
"subscript of pointer to function type %0">;
def err_subscript_incomplete_type : Error<
"subscript of pointer to incomplete type %0">;
+def err_dereference_incomplete_type : Error<
+ "dereference of pointer to incomplete type %0">;
def ext_gnu_subscript_void_type : Extension<
"subscript of a pointer to void is a GNU extension">, InGroup<PointerArith>;
def err_typecheck_member_reference_struct_union : Error<
@@ -4038,7 +4194,13 @@ def err_typecheck_sclass_fscope : Error<
"illegal storage class on file-scoped variable">;
def err_unsupported_global_register : Error<
"global register variables are not supported">;
-def warn_standalone_specifier : Warning<"'%0' ignored on this declaration">;
+def warn_standalone_specifier : Warning<"'%0' ignored on this declaration">,
+ InGroup<MissingDeclarations>;
+def ext_standalone_specifier : ExtWarn<"'%0' is not permitted on a declaration "
+ "of a type">, InGroup<MissingDeclarations>;
+def err_standalone_class_nested_name_specifier : Error<
+ "forward declaration of %select{class|struct|interface|union|enum}0 cannot "
+ "have a nested name specifier">;
def err_typecheck_sclass_func : Error<"illegal storage class on function">;
def err_static_block_func : Error<
"function declared in block scope cannot have 'static' storage class">;
@@ -4052,12 +4214,14 @@ def err_invalid_form_pointer_member_function : Error<
"cannot create a non-constant pointer to member function">;
def err_parens_pointer_member_function : Error<
"cannot parenthesize the name of a method when forming a member pointer">;
+def err_typecheck_invalid_lvalue_addrof_addrof_function : Error<
+ "extra '&' taking address of overloaded function">;
def err_typecheck_invalid_lvalue_addrof : Error<
- "address expression must be an lvalue or a function designator">;
-def ext_typecheck_addrof_class_temporary : ExtWarn<
+ "cannot take the address of an rvalue of type %0">;
+def ext_typecheck_addrof_temporary : ExtWarn<
"taking the address of a temporary object of type %0">,
InGroup<DiagGroup<"address-of-temporary">>, DefaultError;
-def err_typecheck_addrof_class_temporary : Error<
+def err_typecheck_addrof_temporary : Error<
"taking the address of a temporary object of type %0">;
def err_typecheck_unary_expr : Error<
"invalid argument type %0 to unary expression">;
@@ -4070,7 +4234,7 @@ def note_indirection_through_null : Note<
def warn_pointer_indirection_from_incompatible_type : Warning<
"dereference of type %1 that was reinterpret_cast from type %0 has undefined "
"behavior">,
- InGroup<DiagGroup<"undefined-reinterpret-cast">>, DefaultIgnore;
+ InGroup<UndefinedReinterpretCast>, DefaultIgnore;
def err_objc_object_assignment : Error<
"cannot assign to class object (%0 invalid)">;
@@ -4127,11 +4291,11 @@ def warn_comparison_of_mixed_enum_types : Warning<
InGroup<DiagGroup<"enum-compare">>;
def warn_null_in_arithmetic_operation : Warning<
"use of NULL in arithmetic operation">,
- InGroup<DiagGroup<"null-arithmetic">>;
+ InGroup<NullArithmetic>;
def warn_null_in_comparison_operation : Warning<
"comparison between NULL and non-pointer "
"%select{(%1 and NULL)|(NULL and %1)}0">,
- InGroup<DiagGroup<"null-arithmetic">>;
+ InGroup<NullArithmetic>;
def err_invalid_this_use : Error<
"invalid use of 'this' outside of a non-static member function">;
@@ -4178,6 +4342,9 @@ def err_unexpected_interface : Error<
def err_ref_non_value : Error<"%0 does not refer to a value">;
def err_ref_vm_type : Error<
"cannot refer to declaration with a variably modified type inside block">;
+def err_ref_flexarray_type : Error<
+ "cannot refer to declaration of structure variable with flexible array member "
+ "inside block">;
def err_ref_array_type : Error<
"cannot refer to declaration with an array type inside block">;
def err_property_not_found : Error<
@@ -4185,7 +4352,7 @@ def err_property_not_found : Error<
def err_invalid_property_name : Error<
"%0 is not a valid property name (accessing an object of type %1)">;
def err_getter_not_found : Error<
- "expected getter method not found on object of type %0">;
+ "no getter method for read from property">;
def err_objc_subscript_method_not_found : Error<
"expected method to %select{read|write}1 %select{dictionary|array}2 element not "
"found on object of type %0">;
@@ -4276,8 +4443,6 @@ def error_no_super_class_message : Error<
"no @interface declaration found in class messaging of %0">;
def error_root_class_cannot_use_super : Error<
"%0 cannot use 'super' because it is a root class">;
-def err_invalid_receiver_to_message : Error<
- "invalid receiver to message expression">;
def err_invalid_receiver_to_message_super : Error<
"'super' is only valid in a method body">;
def err_invalid_receiver_class_message : Error<
@@ -4337,6 +4502,14 @@ def note_parameter_here : Note<
def err_bad_reinterpret_cast_overload : Error<
"reinterpret_cast cannot resolve overloaded function %0 to type %1">;
+def warn_reinterpret_different_from_static : Warning<
+ "'reinterpret_cast' %select{from|to}3 class %0 %select{to|from}3 its "
+ "%select{virtual base|base at non-zero offset}2 %1 behaves differently from "
+ "'static_cast'">, InGroup<ReinterpretBaseClass>;
+def note_reinterpret_updowncast_use_static: Note<
+ "use 'static_cast' to adjust the pointer correctly while "
+ "%select{upcasting|downcasting}0">;
+
def err_bad_static_cast_overload : Error<
"address of overloaded function %0 cannot be static_cast to type %1">;
@@ -4386,7 +4559,7 @@ def err_bad_reinterpret_cast_reference : Error<
"reinterpret_cast of a %0 to %1 needs its address which is not allowed">;
def warn_undefined_reinterpret_cast : Warning<
"reinterpret_cast from %0 to %1 has undefined behavior">,
- InGroup<DiagGroup<"undefined-reinterpret-cast">>, DefaultIgnore;
+ InGroup<UndefinedReinterpretCast>, DefaultIgnore;
// These messages don't adhere to the pattern.
// FIXME: Display the path somehow better.
@@ -4464,7 +4637,7 @@ def ext_delete_void_ptr_operand : ExtWarn<
def err_ambiguous_delete_operand : Error<"ambiguous conversion of delete "
"expression of type %0 to a pointer">;
def warn_delete_incomplete : Warning<
- "deleting pointer to incomplete type %0 may cause undefined behaviour">,
+ "deleting pointer to incomplete type %0 may cause undefined behavior">,
InGroup<DiagGroup<"delete-incomplete">>;
def err_delete_incomplete_class_type : Error<
"deleting incomplete class type %0; no conversions to pointer type">;
@@ -4563,6 +4736,9 @@ let CategoryName = "Lambda Issue" in {
def err_lambda_capture_vm_type : Error<
"variable %0 with variably modified type cannot be captured in "
"a lambda expression">;
+ def err_lambda_capture_flexarray_type : Error<
+ "variable %0 with flexible array member cannot be captured in "
+ "a lambda expression">;
def err_lambda_impcap : Error<
"variable %0 cannot be implicitly captured in a lambda with no "
"capture-default specified">;
@@ -4573,8 +4749,6 @@ let CategoryName = "Lambda Issue" in {
"cannot deduce lambda return type from initializer list">;
def err_lambda_capture_default_arg : Error<
"lambda expression in default argument cannot capture any entity">;
- def err_lambda_unexpanded_pack : Error<
- "unexpanded function parameter pack capture is unsupported">;
def err_lambda_incomplete_result : Error<
"incomplete result type %0 in lambda expression">;
def err_lambda_objc_object_result : Error<
@@ -4823,7 +4997,7 @@ def ext_typecheck_convert_discards_qualifiers : ExtWarn<
"sending to parameter of different type}0,1"
"|%diff{casting $ to type $|casting between types}0,1}2"
" discards qualifiers">,
- InGroup<IncompatiblePointerTypes>;
+ InGroup<IncompatiblePointerTypesDiscardsQualifiers>;
def ext_nested_pointer_qualifier_mismatch : ExtWarn<
"%select{%diff{assigning to $ from $|assigning to different types}0,1"
"|%diff{passing $ to parameter of type $|"
@@ -4837,7 +5011,7 @@ def ext_nested_pointer_qualifier_mismatch : ExtWarn<
"sending to parameter of different type}0,1"
"|%diff{casting $ to type $|casting between types}0,1}2"
" discards qualifiers in nested pointer types">,
- InGroup<IncompatiblePointerTypes>;
+ InGroup<IncompatiblePointerTypesDiscardsQualifiers>;
def warn_incompatible_vectors : Warning<
"incompatible vector types "
"%select{%diff{assigning to $ from $|assigning to different types}0,1"
@@ -5015,7 +5189,7 @@ def err_ref_bad_target : Error<
def warn_non_pod_vararg_with_format_string : Warning<
"cannot pass %select{non-POD|non-trivial}0 object of type %1 to variadic "
"%select{function|block|method|constructor}2; expected type from format "
- "string was %3">, InGroup<DiagGroup<"non-pod-varargs">>, DefaultError;
+ "string was %3">, InGroup<NonPODVarargs>, DefaultError;
// The arguments to this diagnostic should match the warning above.
def err_cannot_pass_objc_interface_to_vararg_format : Error<
"cannot pass object with interface type %1 by value to variadic "
@@ -5028,7 +5202,7 @@ def err_cannot_pass_objc_interface_to_vararg : Error<
def warn_cannot_pass_non_pod_arg_to_vararg : Warning<
"cannot pass object of %select{non-POD|non-trivial}0 type %1 through variadic"
" %select{function|block|method|constructor}2; call will abort at runtime">,
- InGroup<DiagGroup<"non-pod-varargs">>, DefaultError;
+ InGroup<NonPODVarargs>, DefaultError;
def warn_cxx98_compat_pass_non_pod_arg_to_vararg : Warning<
"passing object of trivial but non-POD type %0 through variadic"
" %select{function|block|method|constructor}1 is incompatible with C++98">,
@@ -5141,10 +5315,14 @@ let CategoryName = "Inline Assembly Issue" in {
"%diff{$ matching output with type $|}0,1">;
def err_asm_unknown_register_name : Error<"unknown register name '%0' in asm">;
def err_asm_empty : Error<"__asm used with no assembly instructions">;
+ def err_asm_invalid_input_size : Error<
+ "invalid input size for constraint '%0'">;
def err_invalid_asm_cast_lvalue : Error<
"invalid use of a cast in a inline asm context requiring an l-value: "
"remove the cast or build with -fheinous-gnu-extensions">;
def err_inline_ms_asm_parsing : Error<"%0">;
+ def err_msasm_unsupported_arch : Error<
+ "Unsupported architecture '%0' for MS-style inline assembly">;
def warn_asm_label_on_auto_decl : Warning<
"ignored asm label '%0' on automatic variable">;
@@ -5153,7 +5331,8 @@ let CategoryName = "Inline Assembly Issue" in {
"accepted due to -fheinous-gnu-extensions, but clang may remove support "
"for this in the future">;
def warn_asm_mismatched_size_modifier : Warning<
- "the size being stored is truncated, use a modifier to specify the size">,
+ "the value is truncated when put into register, "
+ "use a modifier to specify the size">,
InGroup<ASMOperandWidths>;
}
@@ -5205,9 +5384,11 @@ def err_in_class_initializer_bad_type : Error<
"static data member of type %0 must be initialized out of line">;
def ext_in_class_initializer_float_type : ExtWarn<
"in-class initializer for static data member of type %0 is a GNU extension">,
- InGroup<GNU>;
-def note_in_class_initializer_float_type_constexpr : Note<
- "use 'constexpr' specifier to silence this warning">;
+ InGroup<GNUStaticFloatInit>;
+def ext_in_class_initializer_float_type_cxx11 : ExtWarn<
+ "in-class initializer for static data member of type %0 requires "
+ "'constexpr' specifier">, InGroup<StaticFloatInit>, DefaultError;
+def note_in_class_initializer_float_type_cxx11 : Note<"add 'constexpr'">;
def err_in_class_initializer_literal_type : Error<
"in-class initializer for static data member of type %0 requires "
"'constexpr' specifier">;
@@ -5244,6 +5425,9 @@ def err_anonymous_record_with_type : Error<
def ext_anonymous_record_with_type : Extension<
"types declared in an anonymous %select{struct|union}0 are a Microsoft "
"extension">, InGroup<Microsoft>;
+def ext_anonymous_record_with_anonymous_type : Extension<
+ "anonymous types declared in an anonymous %select{struct|union}0 "
+ "are an extension">, InGroup<DiagGroup<"nested-anon-types">>;
def err_anonymous_record_with_function : Error<
"functions cannot be declared in an anonymous %select{struct|union}0">;
def err_anonymous_record_with_static : Error<
@@ -5403,6 +5587,9 @@ def warn_cxx98_compat_explicit_conversion_functions : Warning<
def err_defaulted_special_member_params : Error<
"an explicitly-defaulted %select{|copy |move }0constructor cannot "
"have default arguments">;
+def err_defaulted_special_member_variadic : Error<
+ "an explicitly-defaulted %select{|copy |move }0constructor cannot "
+ "be variadic">;
def err_defaulted_special_member_return_type : Error<
"explicitly-defaulted %select{copy|move}0 assignment operator must "
"return %1">;
@@ -5420,10 +5607,6 @@ def err_defaulted_special_member_copy_const_param : Error<
"the parameter for this explicitly-defaulted copy "
"%select{constructor|assignment operator}0 is const, but a member or base "
"requires it to be non-const">;
-def err_defaulted_special_member_copy_non_const_param : Error<
- "explicitly-defaulted copy %select{constructor|assignment operator}0 with "
- "a non-const parameter must be defaulted outside the class, unless a base or "
- "member requires the parameter to be non-const">;
def err_defaulted_copy_assign_not_ref : Error<
"the parameter for an explicitly-defaulted copy assignment operator must be an "
"lvalue reference type">;
@@ -5446,17 +5629,17 @@ def ext_implicit_exception_spec_mismatch : ExtWarn<
def warn_ptr_arith_precedes_bounds : Warning<
"the pointer decremented by %0 refers before the beginning of the array">,
- InGroup<DiagGroup<"array-bounds-pointer-arithmetic">>, DefaultIgnore;
+ InGroup<ArrayBoundsPointerArithmetic>, DefaultIgnore;
def warn_ptr_arith_exceeds_bounds : Warning<
"the pointer incremented by %0 refers past the end of the array (that "
"contains %1 element%s2)">,
- InGroup<DiagGroup<"array-bounds-pointer-arithmetic">>, DefaultIgnore;
+ InGroup<ArrayBoundsPointerArithmetic>, DefaultIgnore;
def warn_array_index_precedes_bounds : Warning<
"array index %0 is before the beginning of the array">,
- InGroup<DiagGroup<"array-bounds">>;
+ InGroup<ArrayBounds>;
def warn_array_index_exceeds_bounds : Warning<
"array index %0 is past the end of the array (which contains %1 "
- "element%s2)">, InGroup<DiagGroup<"array-bounds">>;
+ "element%s2)">, InGroup<ArrayBounds>;
def note_array_index_out_of_bounds : Note<
"array %0 declared here">;
@@ -5494,7 +5677,7 @@ def warn_format_mix_positional_nonpositional_args : Warning<
InGroup<Format>;
def warn_static_array_too_small : Warning<
"array argument is too small; contains %0 elements, callee requires at least %1">,
- InGroup<DiagGroup<"array-bounds">>;
+ InGroup<ArrayBounds>;
def note_callee_static_array : Note<
"callee declares array parameter as static here">;
def warn_empty_format_string : Warning<
@@ -5543,19 +5726,19 @@ def warn_null_arg : Warning<
// CHECK: returning address/reference of stack memory
def warn_ret_stack_addr : Warning<
"address of stack memory associated with local variable %0 returned">,
- InGroup<DiagGroup<"return-stack-address">>;
+ InGroup<ReturnStackAddress>;
def warn_ret_stack_ref : Warning<
"reference to stack memory associated with local variable %0 returned">,
- InGroup<DiagGroup<"return-stack-address">>;
+ InGroup<ReturnStackAddress>;
def warn_ret_local_temp_addr : Warning<
"returning address of local temporary object">,
- InGroup<DiagGroup<"return-stack-address">>;
+ InGroup<ReturnStackAddress>;
def warn_ret_local_temp_ref : Warning<
"returning reference to local temporary object">,
- InGroup<DiagGroup<"return-stack-address">>;
+ InGroup<ReturnStackAddress>;
def warn_ret_addr_label : Warning<
"returning address of label, which is local">,
- InGroup<DiagGroup<"return-stack-address">>;
+ InGroup<ReturnStackAddress>;
def err_ret_local_block : Error<
"returning block that lives on the local stack">;
def note_ref_var_local_bind : Note<
@@ -5565,13 +5748,13 @@ def note_ref_var_local_bind : Note<
// a constructor parameter.
def warn_bind_ref_member_to_parameter : Warning<
"binding reference member %0 to stack allocated parameter %1">,
- InGroup<DiagGroup<"dangling-field">>;
+ InGroup<DanglingField>;
def warn_init_ptr_member_to_parameter_addr : Warning<
"initializing pointer member %0 with the stack address of parameter %1">,
- InGroup<DiagGroup<"dangling-field">>;
+ InGroup<DanglingField>;
def warn_bind_ref_member_to_temporary : Warning<
"binding reference member %0 to a temporary value">,
- InGroup<DiagGroup<"dangling-field">>;
+ InGroup<DanglingField>;
def note_ref_or_ptr_member_declared_here : Note<
"%select{reference|pointer}0 member declared here">;
@@ -5657,7 +5840,7 @@ def warn_bool_switch_condition : Warning<
"switch condition has boolean value">;
def warn_case_value_overflow : Warning<
"overflow converting case value to switch condition type (%0 to %1)">,
- InGroup<DiagGroup<"switch">>;
+ InGroup<Switch>;
def err_duplicate_case : Error<"duplicate case value '%0'">;
def err_duplicate_case_differing_expr : Error<
"duplicate case value: '%0' and '%1' both equal '%2'">;
@@ -5760,10 +5943,10 @@ def err_second_parameter_to_va_arg_abstract: Error<
"second argument to 'va_arg' is of abstract type %0">;
def warn_second_parameter_to_va_arg_not_pod : Warning<
"second argument to 'va_arg' is of non-POD type %0">,
- InGroup<DiagGroup<"non-pod-varargs">>, DefaultError;
+ InGroup<NonPODVarargs>, DefaultError;
def warn_second_parameter_to_va_arg_ownership_qualified : Warning<
"second argument to 'va_arg' is of ARC ownership-qualified type %0">,
- InGroup<DiagGroup<"non-pod-varargs">>, DefaultError;
+ InGroup<NonPODVarargs>, DefaultError;
def warn_second_parameter_to_va_arg_never_compatible : Warning<
"second argument to 'va_arg' is of promotable type %0; this va_arg has "
"undefined behavior because arguments will be promoted to %1">;
@@ -5785,12 +5968,24 @@ def err_return_init_list : Error<
"must not return a value">;
def warn_noreturn_function_has_return_expr : Warning<
"function %0 declared 'noreturn' should not return">,
- InGroup<DiagGroup<"invalid-noreturn">>;
+ InGroup<InvalidNoreturn>;
def warn_falloff_noreturn_function : Warning<
"function declared 'noreturn' should not return">,
- InGroup<DiagGroup<"invalid-noreturn">>;
+ InGroup<InvalidNoreturn>;
def err_noreturn_block_has_return_expr : Error<
"block declared 'noreturn' should not return">;
+def err_noreturn_missing_on_first_decl : Error<
+ "function declared '[[noreturn]]' after its first declaration">;
+def note_noreturn_missing_first_decl : Note<
+ "declaration missing '[[noreturn]]' attribute is here">;
+def err_carries_dependency_missing_on_first_decl : Error<
+ "%select{function|parameter}0 declared '[[carries_dependency]]' "
+ "after its first declaration">;
+def note_carries_dependency_missing_first_decl : Note<
+ "declaration missing '[[carries_dependency]]' attribute is here">;
+def err_carries_dependency_param_not_function_decl : Error<
+ "'[[carries_dependency]]' attribute only allowed on parameter in a function "
+ "declaration or lambda">;
def err_block_on_nonlocal : Error<
"__block attribute not allowed, only allowed on local variables">;
def err_block_on_vm : Error<
@@ -5870,6 +6065,8 @@ def err_c99_array_usage_cxx : Error<
"feature, not permitted in C++">;
def err_double_requires_fp64 : Error<
"use of type 'double' requires cl_khr_fp64 extension to be enabled">;
+def err_int128_unsupported : Error<
+ "__int128 is not supported on this target">;
def err_nsconsumed_attribute_mismatch : Error<
"overriding method has mismatched ns_consumed attribute on its"
" parameter">;
@@ -5986,8 +6183,44 @@ def err_invalid_astype_of_different_size : Error<
"invalid reinterpretation: sizes of %0 and %1 must match">;
def err_static_kernel : Error<
"kernel functions cannot be declared static">;
+def err_opencl_ptrptr_kernel_arg : Error<
+ "kernel argument cannot be declared as a pointer to a pointer">;
def err_static_function_scope : Error<
"variables in function scope cannot be declared static">;
+def err_opencl_bitfields : Error<
+ "bitfields are not supported in OpenCL">;
+def err_opencl_vla : Error<
+ "variable length arrays are not supported in OpenCL">;
+def err_event_t_kernel_arg : Error<
+ "the event_t type cannot be used to declare a kernel function argument">;
+def err_event_t_global_var : Error<
+ "the event_t type cannot be used to declare a program scope variable">;
+def err_event_t_struct_field : Error<
+ "the event_t type cannot be used to declare a structure or union field">;
+def err_event_t_addr_space_qual : Error<
+ "the event_t type can only be used with __private address space qualifier">;
+def err_expected_kernel_void_return_type : Error<
+ "kernel must have void return type">;
+def err_sampler_argument_required : Error<
+ "sampler_t variable required - got %0">;
+def err_wrong_sampler_addressspace: Error<
+ "sampler type cannot be used with the __local and __global address space qualifiers">;
+
+// OpenMP support.
+def err_omp_expected_var_arg_suggest : Error<
+ "%0 is not a global variable, static local variable or static data member%select{|; did you mean %2?}1">;
+def err_omp_global_var_arg : Error<
+ "arguments of '#pragma omp %0' must have %select{global storage|static storage duration}1">;
+def err_omp_ref_type_arg : Error<
+ "arguments of '#pragma omp %0' cannot be of reference type %1">;
+def err_omp_var_scope : Error<
+ "'#pragma omp %0' must appear in the scope of the %1 variable declaration">;
+def err_omp_var_used : Error<
+ "'#pragma omp %0' must precede all references to variable %1">;
+def err_omp_var_thread_local : Error<
+ "variable %0 cannot be threadprivate because it is thread-local">;
+def err_omp_incomplete_type : Error<
+ "a threadprivate variable must not have incomplete type %0">;
} // end of sema category
@@ -6000,15 +6233,19 @@ def warn_related_result_type_compatibility_class : Warning<
def warn_related_result_type_compatibility_protocol : Warning<
"protocol method is expected to return an instance of the implementing "
"class, but is declared to return %0">;
-def note_related_result_type_overridden_family : Note<
- "overridden method is part of the '%select{|alloc|copy|init|mutableCopy|"
- "new|autorelease|dealloc|finalize|release|retain|retainCount|self}0' method "
- "family">;
+def note_related_result_type_family : Note<
+ "%select{overridden|current}0 method is part of the '%select{|alloc|copy|init|"
+ "mutableCopy|new|autorelease|dealloc|finalize|release|retain|retainCount|"
+ "self}1' method family%select{| and is expected to return an instance of its "
+ "class type}0">;
def note_related_result_type_overridden : Note<
"overridden method returns an instance of its class type">;
def note_related_result_type_inferred : Note<
"%select{class|instance}0 method %1 is assumed to return an instance of "
"its receiver type (%2)">;
+def note_related_result_type_explicit : Note<
+ "%select{overridden|current}0 method is explicitly declared 'instancetype'"
+ "%select{| and is expected to return an instance of its class type}0">;
}
@@ -6023,7 +6260,7 @@ def err_module_private_local_class : Error<
"local %select{struct|interface|union|class|enum}0 cannot be declared "
"__module_private__">;
def err_module_private_definition : Error<
- "definition of %0 must be imported before it is required">;
+ "definition of %0 must be imported from module '%1' before it is required">;
}
let CategoryName = "Documentation Issue" in {
diff --git a/include/clang/Basic/DiagnosticSerializationKinds.td b/include/clang/Basic/DiagnosticSerializationKinds.td
index e9df09d..7137404 100644
--- a/include/clang/Basic/DiagnosticSerializationKinds.td
+++ b/include/clang/Basic/DiagnosticSerializationKinds.td
@@ -17,10 +17,8 @@ def err_fe_pch_malformed : Error<
"malformed or corrupted PCH file: '%0'">, DefaultFatal;
def err_fe_pch_malformed_block : Error<
"malformed block record in PCH file: '%0'">, DefaultFatal;
-def err_fe_pch_error_at_end_block : Error<
- "error at end of module block in PCH file: '%0'">, DefaultFatal;
def err_fe_pch_file_modified : Error<
- "file '%0' has been modified since the precompiled header was built">,
+ "file '%0' has been modified since the precompiled header '%1' was built">,
DefaultFatal;
def err_fe_pch_file_overridden : Error<
"file '%0' from the precompiled header has been overridden">;
@@ -46,19 +44,16 @@ def warn_pch_different_branch : Error<
def err_pch_with_compiler_errors : Error<
"PCH file contains compiler errors">;
-
+def warn_module_conflict : Warning<
+ "module '%0' conflicts with already-imported module '%1': %2">,
+ InGroup<ModuleConflict>;
+
def err_pch_macro_def_undef : Error<
"macro '%0' was %select{defined|undef'd}1 in the precompiled header but "
"%select{undef'd|defined}1 on the command line">;
def err_pch_macro_def_conflict : Error<
"definition of macro '%0' differs between the precompiled header ('%1') "
"and the command line ('%2')">;
-def err_pch_include_opt_missing : Error<
- "precompiled header depends on '%select{-include|-imacros}0 %1' option "
- "that is missing from the command line">;
-def err_pch_include_opt_conflict : Error<
- "precompiled header option '%select{-include|-imacros}0 %1' conflicts with "
- "corresponding option '%select{-include|-imacros}0 %2' on command line">;
def err_pch_undef : Error<
"%select{command line contains|precompiled header was built with}0 "
"'-undef' but %select{precompiled header was not built with it|"
diff --git a/include/clang/Basic/FileManager.h b/include/clang/Basic/FileManager.h
index b2f578d..6d9e53b 100644
--- a/include/clang/Basic/FileManager.h
+++ b/include/clang/Basic/FileManager.h
@@ -17,11 +17,12 @@
#include "clang/Basic/FileSystemOptions.h"
#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/Allocator.h"
// FIXME: Enhance libsystem to support inode and other fields in stat.
#include <sys/types.h>
@@ -152,6 +153,12 @@ class FileManager : public RefCountedBase<FileManager> {
/// \see SeenDirEntries
llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator> SeenFileEntries;
+ /// \brief The canonical names of directories.
+ llvm::DenseMap<const DirectoryEntry *, llvm::StringRef> CanonicalDirNames;
+
+ /// \brief Storage for canonical names that we have computed.
+ llvm::BumpPtrAllocator CanonicalNameStorage;
+
/// \brief Each FileEntry we create is assigned a unique ID #.
///
unsigned NextFileUID;
@@ -164,7 +171,7 @@ class FileManager : public RefCountedBase<FileManager> {
OwningPtr<FileSystemStatCache> StatCache;
bool getStatValue(const char *Path, struct stat &StatBuf,
- int *FileDescriptor);
+ bool isFile, int *FileDescriptor);
/// Add all ancestors of the given path (pointing to either a file
/// or a directory) as virtual directories.
@@ -257,6 +264,13 @@ public:
static void modifyFileEntry(FileEntry *File, off_t Size,
time_t ModificationTime);
+ /// \brief Retrieve the canonical name for a given directory.
+ ///
+ /// This is a very expensive operation, despite its results being cached,
+ /// and should only be used when the physical layout of the file system is
+ /// required, which is (almost) never.
+ StringRef getCanonicalName(const DirectoryEntry *Dir);
+
void PrintStats() const;
};
diff --git a/include/clang/Basic/FileSystemStatCache.h b/include/clang/Basic/FileSystemStatCache.h
index a802c7c..ff70373 100644
--- a/include/clang/Basic/FileSystemStatCache.h
+++ b/include/clang/Basic/FileSystemStatCache.h
@@ -18,8 +18,8 @@
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/StringMap.h"
-#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/types.h>
namespace clang {
@@ -44,13 +44,13 @@ public:
///
/// \returns \c true if the path does not exist or \c false if it exists.
///
- /// If FileDescriptor is non-null, then this lookup should only return success
- /// for files (not directories). If it is null this lookup should only return
+ /// If isFile is true, then this lookup should only return success for files
+ /// (not directories). If it is false this lookup should only return
/// success for directories (not files). On a successful file lookup, the
/// implementation can optionally fill in FileDescriptor with a valid
/// descriptor and the client guarantees that it will close it.
- static bool get(const char *Path, struct stat &StatBuf, int *FileDescriptor,
- FileSystemStatCache *Cache);
+ static bool get(const char *Path, struct stat &StatBuf,
+ bool isFile, int *FileDescriptor, FileSystemStatCache *Cache);
/// \brief Sets the next stat call cache in the chain of stat caches.
@@ -69,16 +69,17 @@ public:
protected:
virtual LookupResult getStat(const char *Path, struct stat &StatBuf,
- int *FileDescriptor) = 0;
+ bool isFile, int *FileDescriptor) = 0;
LookupResult statChained(const char *Path, struct stat &StatBuf,
- int *FileDescriptor) {
+ bool isFile, int *FileDescriptor) {
if (FileSystemStatCache *Next = getNextStatCache())
- return Next->getStat(Path, StatBuf, FileDescriptor);
+ return Next->getStat(Path, StatBuf, isFile, FileDescriptor);
// If we hit the end of the list of stat caches to try, just compute and
// return it without a cache.
- return get(Path, StatBuf, FileDescriptor, 0) ? CacheMissing : CacheExists;
+ return get(Path, StatBuf,
+ isFile, FileDescriptor, 0) ? CacheMissing : CacheExists;
}
};
@@ -97,7 +98,7 @@ public:
iterator end() const { return StatCalls.end(); }
virtual LookupResult getStat(const char *Path, struct stat &StatBuf,
- int *FileDescriptor);
+ bool isFile, int *FileDescriptor);
};
} // end namespace clang
diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h
index 76242ec..c04a893 100644
--- a/include/clang/Basic/IdentifierTable.h
+++ b/include/clang/Basic/IdentifierTable.h
@@ -16,9 +16,9 @@
#ifndef LLVM_CLANG_BASIC_IDENTIFIERTABLE_H
#define LLVM_CLANG_BASIC_IDENTIFIERTABLE_H
+#include "clang/Basic/LLVM.h"
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/TokenKinds.h"
-#include "clang/Basic/LLVM.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
@@ -146,9 +146,6 @@ public:
bool hadMacroDefinition() const {
return HadMacro;
}
- void setHadMacroDefinition(bool Val) {
- HadMacro = Val;
- }
/// getTokenID - If this is a source-language token (e.g. 'for'), this API
/// can be used to cause the lexer to map identifiers to source-language
@@ -297,11 +294,11 @@ public:
}
/// \brief Determine whether this is the contextual keyword
- /// '__experimental_modules_import'.
+ /// 'import'.
bool isModulesImport() const { return IsModulesImport; }
/// \brief Set whether this identifier is the contextual keyword
- /// '__experimental_modules_import'.
+ /// 'import'.
void setModulesImport(bool I) {
IsModulesImport = I;
if (I)
diff --git a/include/clang/Basic/LLVM.h b/include/clang/Basic/LLVM.h
index 13c5b44..306c75e 100644
--- a/include/clang/Basic/LLVM.h
+++ b/include/clang/Basic/LLVM.h
@@ -16,19 +16,24 @@
#ifndef CLANG_BASIC_LLVM_H
#define CLANG_BASIC_LLVM_H
-// This should be the only #include, force #includes of all the others on
-// clients.
+// Do not proliferate #includes here, require clients to #include their
+// dependencies.
+// Casting.h has complex templates that cannot be easily forward declared.
#include "llvm/Support/Casting.h"
+// None.h includes an enumerator that is desired & cannot be forward declared
+// without a definition of NoneType.
+#include "llvm/ADT/None.h"
namespace llvm {
// ADT's.
class StringRef;
class Twine;
template<typename T> class ArrayRef;
- template<class T> class OwningPtr;
+ template<typename T> class OwningPtr;
template<unsigned InternalLen> class SmallString;
template<typename T, unsigned N> class SmallVector;
template<typename T> class SmallVectorImpl;
+ template<typename T> class Optional;
template<typename T>
struct SaveAndRestore;
@@ -53,6 +58,8 @@ namespace clang {
using llvm::cast_or_null;
// ADT's.
+ using llvm::None;
+ using llvm::Optional;
using llvm::StringRef;
using llvm::Twine;
using llvm::ArrayRef;
diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def
index dbc08c7..3de0107 100644
--- a/include/clang/Basic/LangOptions.def
+++ b/include/clang/Basic/LangOptions.def
@@ -45,9 +45,10 @@ LANGOPT(C99 , 1, 0, "C99")
LANGOPT(C11 , 1, 0, "C11")
LANGOPT(MicrosoftExt , 1, 0, "Microsoft extensions")
LANGOPT(MicrosoftMode , 1, 0, "Microsoft compatibility mode")
+LANGOPT(AsmBlocks , 1, 0, "Microsoft inline asm blocks")
LANGOPT(Borland , 1, 0, "Borland extensions")
LANGOPT(CPlusPlus , 1, 0, "C++")
-LANGOPT(CPlusPlus0x , 1, 0, "C++0x")
+LANGOPT(CPlusPlus11 , 1, 0, "C++0x")
LANGOPT(CPlusPlus1y , 1, 0, "C++1y")
LANGOPT(ObjC1 , 1, 0, "Objective-C 1")
LANGOPT(ObjC2 , 1, 0, "Objective-C 2")
@@ -115,7 +116,9 @@ LANGOPT(ShortEnums , 1, 0, "short enum types")
LANGOPT(OpenCL , 1, 0, "OpenCL")
LANGOPT(OpenCLVersion , 32, 0, "OpenCL version")
+LANGOPT(NativeHalfType , 1, 0, "Native half type support")
LANGOPT(CUDA , 1, 0, "CUDA")
+LANGOPT(OpenMP , 1, 0, "OpenMP support")
LANGOPT(AssumeSaneOperatorNew , 1, 1, "implicit __attribute__((malloc)) for C++'s new operators")
BENIGN_LANGOPT(ElideConstructors , 1, 1, "C++ copy constructor elision")
@@ -144,18 +147,21 @@ BENIGN_LANGOPT(DelayedTemplateParsing , 1, 0, "delayed template parsing")
LANGOPT(BlocksRuntimeOptional , 1, 0, "optional blocks runtime")
ENUM_LANGOPT(GC, GCMode, 2, NonGC, "Objective-C Garbage Collection mode")
-ENUM_LANGOPT(VisibilityMode, Visibility, 3, DefaultVisibility,
- "symbol visibility")
+ENUM_LANGOPT(ValueVisibilityMode, Visibility, 3, DefaultVisibility,
+ "value symbol visibility")
+ENUM_LANGOPT(TypeVisibilityMode, Visibility, 3, DefaultVisibility,
+ "type symbol visibility")
ENUM_LANGOPT(StackProtector, StackProtectorMode, 2, SSPOff,
"stack protector mode")
ENUM_LANGOPT(SignedOverflowBehavior, SignedOverflowBehaviorTy, 2, SOB_Undefined,
"signed integer overflow handling")
-ENUM_LANGOPT(FPContractMode, FPContractModeKind, 2, FPC_On, "FP_CONTRACT mode")
BENIGN_LANGOPT(InstantiationDepth, 32, 512,
"maximum template instantiation depth")
BENIGN_LANGOPT(ConstexprCallDepth, 32, 512,
"maximum constexpr call depth")
+BENIGN_LANGOPT(BracketDepth, 32, 256,
+ "maximum bracket nesting depth")
BENIGN_LANGOPT(NumLargeByValueCopy, 32, 0,
"if non-zero, warn about parameter or return Warn if parameter/return value is larger in bytes than this setting. 0 is no check.")
VALUE_LANGOPT(MSCVersion, 32, 0,
@@ -163,17 +169,8 @@ VALUE_LANGOPT(MSCVersion, 32, 0,
LANGOPT(ApplePragmaPack, 1, 0, "Apple gcc-compatible #pragma pack handling")
-BENIGN_LANGOPT(EmitMicrosoftInlineAsm , 1, 0,
- "Enable emission of MS-style inline assembly.")
-
-
BENIGN_LANGOPT(RetainCommentsFromSystemHeaders, 1, 0, "retain documentation comments from system headers in the AST")
-/// Runtime sanitizers.
-#define SANITIZER(NAME, ID) \
-BENIGN_LANGOPT(Sanitize##ID, 1, 0, NAME " sanitizer")
-#include "clang/Basic/Sanitizers.def"
-
#undef LANGOPT
#undef VALUE_LANGOPT
#undef BENIGN_LANGOPT
diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h
index fbb014e..21ca7eb 100644
--- a/include/clang/Basic/LangOptions.h
+++ b/include/clang/Basic/LangOptions.h
@@ -15,14 +15,23 @@
#ifndef LLVM_CLANG_LANGOPTIONS_H
#define LLVM_CLANG_LANGOPTIONS_H
-#include <string>
+#include "clang/Basic/CommentOptions.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/ObjCRuntime.h"
#include "clang/Basic/Visibility.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include <string>
namespace clang {
+struct SanitizerOptions {
+#define SANITIZER(NAME, ID) unsigned ID : 1;
+#include "clang/Basic/Sanitizers.def"
+
+ /// \brief Cached set of sanitizer options with all sanitizers disabled.
+ static const SanitizerOptions Disabled;
+};
+
/// Bitfields of LangOptions, split out from LangOptions in order to ensure that
/// this large collection of bitfields is a trivial class type.
class LangOptionsBase {
@@ -32,6 +41,7 @@ public:
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description)
#include "clang/Basic/LangOptions.def"
+ SanitizerOptions Sanitize;
protected:
// Define language options of enumeration type. These are private, and will
// have accessors (below).
@@ -56,12 +66,6 @@ public:
SOB_Trapping // -ftrapv
};
- enum FPContractModeKind {
- FPC_Off, // Form fused FP ops only where result will not be affected.
- FPC_On, // Form fused FP ops according to FP_CONTRACT rules.
- FPC_Fast // Aggressively fuse FP ops (E.g. FMA).
- };
-
public:
clang::ObjCRuntime ObjCRuntime;
@@ -75,6 +79,9 @@ public:
/// \brief The name of the current module.
std::string CurrentModule;
+
+ /// \brief Options for parsing comments.
+ CommentOptions CommentOpts;
LangOptions();
diff --git a/include/clang/Basic/Linkage.h b/include/clang/Basic/Linkage.h
index 6bc1f5d..01b8db1 100644
--- a/include/clang/Basic/Linkage.h
+++ b/include/clang/Basic/Linkage.h
@@ -42,6 +42,14 @@ enum Linkage {
ExternalLinkage
};
+/// \brief Describes the different kinds of language linkage
+/// (C++ [dcl.link]) that an entity may have.
+enum LanguageLinkage {
+ CLanguageLinkage,
+ CXXLanguageLinkage,
+ NoLanguageLinkage
+};
+
/// \brief A more specific kind of linkage than enum Linkage.
///
/// This is relevant to CodeGen and AST file reading.
diff --git a/include/clang/Basic/MacroBuilder.h b/include/clang/Basic/MacroBuilder.h
index 6df3a38..9a9eaa2 100644
--- a/include/clang/Basic/MacroBuilder.h
+++ b/include/clang/Basic/MacroBuilder.h
@@ -15,6 +15,7 @@
#ifndef LLVM_CLANG_BASIC_MACROBUILDER_H
#define LLVM_CLANG_BASIC_MACROBUILDER_H
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/include/clang/Basic/Module.h b/include/clang/Basic/Module.h
index b6b088c..d2a43f0 100644
--- a/include/clang/Basic/Module.h
+++ b/include/clang/Basic/Module.h
@@ -18,10 +18,10 @@
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/SetVector.h"
#include <string>
#include <utility>
#include <vector>
@@ -34,12 +34,12 @@ namespace clang {
class DirectoryEntry;
class FileEntry;
+class FileManager;
class LangOptions;
class TargetInfo;
/// \brief Describes the name of a module.
-typedef llvm::SmallVector<std::pair<std::string, SourceLocation>, 2>
- ModuleId;
+typedef SmallVector<std::pair<std::string, SourceLocation>, 2> ModuleId;
/// \brief Describes a module or submodule.
class Module {
@@ -68,23 +68,26 @@ private:
/// \brief The AST file if this is a top-level module which has a
/// corresponding serialized AST file, or null otherwise.
const FileEntry *ASTFile;
-
+
+ /// \brief The top-level headers associated with this module.
+ llvm::SmallSetVector<const FileEntry *, 2> TopHeaders;
+
+ /// \brief top-level header filenames that aren't resolved to FileEntries yet.
+ std::vector<std::string> TopHeaderNames;
+
public:
/// \brief The headers that are part of this module.
- llvm::SmallVector<const FileEntry *, 2> Headers;
+ SmallVector<const FileEntry *, 2> Headers;
/// \brief The headers that are explicitly excluded from this module.
- llvm::SmallVector<const FileEntry *, 2> ExcludedHeaders;
-
- /// \brief The top-level headers associated with this module.
- llvm::SmallSetVector<const FileEntry *, 2> TopHeaders;
+ SmallVector<const FileEntry *, 2> ExcludedHeaders;
/// \brief The set of language features required to use this module.
///
/// If any of these features is not present, the \c IsAvailable bit
/// will be false to indicate that this (sub)module is not
/// available.
- llvm::SmallVector<std::string, 2> Requires;
+ SmallVector<std::string, 2> Requires;
/// \brief Whether this module is available in the current
/// translation unit.
@@ -116,7 +119,14 @@ public:
/// \brief Whether, when inferring submodules, the inferr submodules should
/// export all modules they import (e.g., the equivalent of "export *").
unsigned InferExportWildcard : 1;
-
+
+ /// \brief Whether the set of configuration macros is exhaustive.
+ ///
+ /// When the set of configuration macros is exhaustive, meaning
+ /// that no identifier not in this list should affect how the module is
+ /// built.
+ unsigned ConfigMacrosExhaustive : 1;
+
/// \brief Describes the visibility of the various names within a
/// particular module.
enum NameVisibilityKind {
@@ -137,7 +147,7 @@ public:
/// \brief The set of modules imported by this module, and on which this
/// module depends.
- llvm::SmallVector<Module *, 2> Imports;
+ SmallVector<Module *, 2> Imports;
/// \brief Describes an exported module.
///
@@ -146,7 +156,7 @@ public:
typedef llvm::PointerIntPair<Module *, 1, bool> ExportDecl;
/// \brief The set of export declarations.
- llvm::SmallVector<ExportDecl, 2> Exports;
+ SmallVector<ExportDecl, 2> Exports;
/// \brief Describes an exported module that has not yet been resolved
/// (perhaps because the module it refers to has not yet been loaded).
@@ -164,8 +174,58 @@ public:
};
/// \brief The set of export declarations that have yet to be resolved.
- llvm::SmallVector<UnresolvedExportDecl, 2> UnresolvedExports;
-
+ SmallVector<UnresolvedExportDecl, 2> UnresolvedExports;
+
+ /// \brief A library or framework to link against when an entity from this
+ /// module is used.
+ struct LinkLibrary {
+ LinkLibrary() : IsFramework(false) { }
+ LinkLibrary(const std::string &Library, bool IsFramework)
+ : Library(Library), IsFramework(IsFramework) { }
+
+ /// \brief The library to link against.
+ ///
+ /// This will typically be a library or framework name, but can also
+ /// be an absolute path to the library or framework.
+ std::string Library;
+
+ /// \brief Whether this is a framework rather than a library.
+ bool IsFramework;
+ };
+
+ /// \brief The set of libraries or frameworks to link against when
+ /// an entity from this module is used.
+ llvm::SmallVector<LinkLibrary, 2> LinkLibraries;
+
+ /// \brief The set of "configuration macros", which are macros that
+ /// (intentionally) change how this module is built.
+ std::vector<std::string> ConfigMacros;
+
+ /// \brief An unresolved conflict with another module.
+ struct UnresolvedConflict {
+ /// \brief The (unresolved) module id.
+ ModuleId Id;
+
+ /// \brief The message provided to the user when there is a conflict.
+ std::string Message;
+ };
+
+ /// \brief The list of conflicts for which the module-id has not yet been
+ /// resolved.
+ std::vector<UnresolvedConflict> UnresolvedConflicts;
+
+ /// \brief A conflict between two modules.
+ struct Conflict {
+ /// \brief The module that this module conflicts with.
+ Module *Other;
+
+ /// \brief The message provided to the user when there is a conflict.
+ std::string Message;
+ };
+
+ /// \brief The list of conflicts.
+ std::vector<Conflict> Conflicts;
+
/// \brief Construct a top-level module.
explicit Module(StringRef Name, SourceLocation DefinitionLoc,
bool IsFramework)
@@ -173,7 +233,8 @@ public:
IsAvailable(true), IsFromModuleFile(false), IsFramework(IsFramework),
IsExplicit(false), IsSystem(false),
InferSubmodules(false), InferExplicitSubmodules(false),
- InferExportWildcard(false), NameVisibility(Hidden) { }
+ InferExportWildcard(false), ConfigMacrosExhaustive(false),
+ NameVisibility(Hidden) { }
/// \brief Construct a new module or submodule.
Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
@@ -217,7 +278,13 @@ public:
return false;
}
-
+
+ /// \brief Determine whether this module is a subframework of another
+ /// framework.
+ bool isSubFramework() const {
+ return IsFramework && Parent && Parent->isPartOfFramework();
+ }
+
/// \brief Retrieve the full name of this module, including the path from
/// its top-level module.
std::string getFullModuleName() const;
@@ -266,6 +333,20 @@ public:
return Umbrella && Umbrella.is<const DirectoryEntry *>();
}
+ /// \brief Add a top-level header associated with this module.
+ void addTopHeader(const FileEntry *File) {
+ assert(File);
+ TopHeaders.insert(File);
+ }
+
+ /// \brief Add a top-level header filename associated with this module.
+ void addTopHeaderFilename(StringRef Filename) {
+ TopHeaderNames.push_back(Filename);
+ }
+
+ /// \brief The top-level headers associated with this module.
+ ArrayRef<const FileEntry *> getTopHeaders(FileManager &FileMgr);
+
/// \brief Add the given feature requirement to the list of features
/// required by this module.
///
@@ -284,7 +365,7 @@ public:
///
/// \returns The submodule if found, or NULL otherwise.
Module *findSubmodule(StringRef Name) const;
-
+
typedef std::vector<Module *>::iterator submodule_iterator;
typedef std::vector<Module *>::const_iterator submodule_const_iterator;
@@ -292,14 +373,17 @@ public:
submodule_const_iterator submodule_begin() const {return SubModules.begin();}
submodule_iterator submodule_end() { return SubModules.end(); }
submodule_const_iterator submodule_end() const { return SubModules.end(); }
-
+
+ /// \brief Returns the exported modules based on the wildcard restrictions.
+ void getExportedModules(SmallVectorImpl<Module *> &Exported) const;
+
static StringRef getModuleInputBufferName() {
return "<module-includes>";
}
/// \brief Print the module map for this module to the given stream.
///
- void print(llvm::raw_ostream &OS, unsigned Indent = 0) const;
+ void print(raw_ostream &OS, unsigned Indent = 0) const;
/// \brief Dump the contents of this module to the given output stream.
void dump() const;
diff --git a/include/clang/Basic/ObjCRuntime.h b/include/clang/Basic/ObjCRuntime.h
index d543b76..18ef64a 100644
--- a/include/clang/Basic/ObjCRuntime.h
+++ b/include/clang/Basic/ObjCRuntime.h
@@ -104,7 +104,7 @@ public:
return true;
}
- /// \brief Is this runtime basically of the GNUstep family of runtimes?
+ /// \brief Is this runtime basically of the GNU family of runtimes?
bool isGNUFamily() const {
switch (getKind()) {
case FragileMacOSX:
@@ -164,6 +164,8 @@ public:
return getVersion() >= VersionTuple(10, 8);
case iOS:
return (getVersion() >= VersionTuple(6));
+ case GNUstep:
+ return getVersion() >= VersionTuple(1, 7);
default:
return false;
@@ -272,6 +274,18 @@ public:
llvm_unreachable("bad kind");
}
+ bool hasAtomicCopyHelper() const {
+ switch (getKind()) {
+ case FragileMacOSX:
+ case MacOSX:
+ case iOS:
+ return true;
+ case GNUstep:
+ return getVersion() >= VersionTuple(1, 7);
+ default: return false;
+ }
+ }
+
/// \brief Try to parse an Objective-C runtime specification from the given
/// string.
///
diff --git a/include/clang/Basic/OnDiskHashTable.h b/include/clang/Basic/OnDiskHashTable.h
index cc9ca9f..06cb143 100644
--- a/include/clang/Basic/OnDiskHashTable.h
+++ b/include/clang/Basic/OnDiskHashTable.h
@@ -14,11 +14,12 @@
#ifndef LLVM_CLANG_BASIC_ON_DISK_HASH_TABLE_H
#define LLVM_CLANG_BASIC_ON_DISK_HASH_TABLE_H
+#include "clang/Basic/LLVM.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/Host.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/Host.h"
#include <cassert>
#include <cstdlib>
diff --git a/include/clang/Basic/OpenMPKinds.def b/include/clang/Basic/OpenMPKinds.def
new file mode 100644
index 0000000..f968977
--- /dev/null
+++ b/include/clang/Basic/OpenMPKinds.def
@@ -0,0 +1,23 @@
+//===--- OpenMPKinds.def - OpenMP directives and clauses list ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// \brief This file defines the list of supported OpenMP directives and
+/// clauses.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef OPENMP_DIRECTIVE
+# define OPENMP_DIRECTIVE(Name)
+#endif
+
+// OpenMP directives.
+OPENMP_DIRECTIVE(threadprivate)
+OPENMP_DIRECTIVE(parallel)
+
+#undef OPENMP_DIRECTIVE
diff --git a/include/clang/Basic/OpenMPKinds.h b/include/clang/Basic/OpenMPKinds.h
new file mode 100644
index 0000000..c90e9a0
--- /dev/null
+++ b/include/clang/Basic/OpenMPKinds.h
@@ -0,0 +1,37 @@
+//===--- OpenMPKinds.h - OpenMP enums ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Defines some OpenMP-specific enums and functions.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_OPENMPKINDS_H
+#define LLVM_CLANG_BASIC_OPENMPKINDS_H
+
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+
+/// \brief OpenMP directives.
+enum OpenMPDirectiveKind {
+ OMPD_unknown = 0,
+#define OPENMP_DIRECTIVE(Name) \
+ OMPD_##Name,
+#include "clang/Basic/OpenMPKinds.def"
+ NUM_OPENMP_DIRECTIVES
+};
+
+OpenMPDirectiveKind getOpenMPDirectiveKind(llvm::StringRef Str);
+const char *getOpenMPDirectiveName(OpenMPDirectiveKind Kind);
+
+}
+
+#endif
+
diff --git a/include/clang/Basic/OperatorPrecedence.h b/include/clang/Basic/OperatorPrecedence.h
new file mode 100644
index 0000000..b68d577
--- /dev/null
+++ b/include/clang/Basic/OperatorPrecedence.h
@@ -0,0 +1,52 @@
+//===--- OperatorPrecedence.h - Operator precedence levels ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Defines and computes precedence levels for binary/ternary operators.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_OPERATOR_PRECEDENCE_H
+#define LLVM_CLANG_OPERATOR_PRECEDENCE_H
+
+#include "clang/Basic/TokenKinds.h"
+
+namespace clang {
+
+/// PrecedenceLevels - These are precedences for the binary/ternary
+/// operators in the C99 grammar. These have been named to relate
+/// with the C99 grammar productions. Low precedences numbers bind
+/// more weakly than high numbers.
+namespace prec {
+ enum Level {
+ Unknown = 0, // Not binary operator.
+ Comma = 1, // ,
+ Assignment = 2, // =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=
+ Conditional = 3, // ?
+ LogicalOr = 4, // ||
+ LogicalAnd = 5, // &&
+ InclusiveOr = 6, // |
+ ExclusiveOr = 7, // ^
+ And = 8, // &
+ Equality = 9, // ==, !=
+ Relational = 10, // >=, <=, >, <
+ Shift = 11, // <<, >>
+ Additive = 12, // -, +
+ Multiplicative = 13, // *, /, %
+ PointerToMember = 14 // .*, ->*
+ };
+}
+
+/// \brief Return the precedence of the specified binary operator token.
+prec::Level getBinOpPrecedence(tok::TokenKind Kind, bool GreaterThanIsOperator,
+ bool CPlusPlus11);
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_OPERATOR_PRECEDENCE_H
diff --git a/include/clang/Basic/PartialDiagnostic.h b/include/clang/Basic/PartialDiagnostic.h
index 3f4626e..3f68160 100644
--- a/include/clang/Basic/PartialDiagnostic.h
+++ b/include/clang/Basic/PartialDiagnostic.h
@@ -19,6 +19,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Compiler.h"
#include "llvm/Support/DataTypes.h"
#include <cassert>
@@ -200,6 +201,14 @@ public:
}
}
+#if LLVM_HAS_RVALUE_REFERENCES
+ PartialDiagnostic(PartialDiagnostic &&Other)
+ : DiagID(Other.DiagID), DiagStorage(Other.DiagStorage),
+ Allocator(Other.Allocator) {
+ Other.DiagStorage = 0;
+ }
+#endif
+
PartialDiagnostic(const PartialDiagnostic &Other, Storage *DiagStorage)
: DiagID(Other.DiagID), DiagStorage(DiagStorage),
Allocator(reinterpret_cast<StorageAllocator *>(~uintptr_t(0)))
@@ -242,6 +251,19 @@ public:
return *this;
}
+#if LLVM_HAS_RVALUE_REFERENCES
+ PartialDiagnostic &operator=(PartialDiagnostic &&Other) {
+ freeStorage();
+
+ DiagID = Other.DiagID;
+ DiagStorage = Other.DiagStorage;
+ Allocator = Other.Allocator;
+
+ Other.DiagStorage = 0;
+ return *this;
+ }
+#endif
+
~PartialDiagnostic() {
freeStorage();
}
@@ -299,7 +321,7 @@ public:
}
void EmitToString(DiagnosticsEngine &Diags,
- llvm::SmallVectorImpl<char> &Buf) const {
+ SmallVectorImpl<char> &Buf) const {
// FIXME: It should be possible to render a diagnostic to a string without
// messing with the state of the diagnostics engine.
DiagnosticBuilder DB(Diags.Report(getDiagID()));
diff --git a/include/clang/Basic/Sanitizers.def b/include/clang/Basic/Sanitizers.def
index 085ca16..709ec8d 100644
--- a/include/clang/Basic/Sanitizers.def
+++ b/include/clang/Basic/Sanitizers.def
@@ -40,30 +40,61 @@
// AddressSanitizer
SANITIZER("address", Address)
+// More features of AddressSanitizer that should be turned on explicitly.
+SANITIZER("init-order", InitOrder)
+SANITIZER("use-after-return", UseAfterReturn)
+SANITIZER("use-after-scope", UseAfterScope)
+
+SANITIZER_GROUP("address-full", AddressFull,
+ Address | InitOrder | UseAfterReturn | UseAfterScope)
+
+// MemorySanitizer
+SANITIZER("memory", Memory)
// ThreadSanitizer
SANITIZER("thread", Thread)
// UndefinedBehaviorSanitizer
-SANITIZER("signed-integer-overflow", SignedIntegerOverflow)
-SANITIZER("divide-by-zero", DivideByZero)
+SANITIZER("alignment", Alignment)
+SANITIZER("bool", Bool)
+SANITIZER("bounds", Bounds)
+SANITIZER("enum", Enum)
+SANITIZER("float-cast-overflow", FloatCastOverflow)
+SANITIZER("float-divide-by-zero", FloatDivideByZero)
+SANITIZER("integer-divide-by-zero", IntegerDivideByZero)
+SANITIZER("null", Null)
+SANITIZER("object-size", ObjectSize)
+SANITIZER("return", Return)
SANITIZER("shift", Shift)
+SANITIZER("signed-integer-overflow", SignedIntegerOverflow)
SANITIZER("unreachable", Unreachable)
-SANITIZER("return", Return)
SANITIZER("vla-bound", VLABound)
-SANITIZER("alignment", Alignment)
-SANITIZER("null", Null)
SANITIZER("vptr", Vptr)
-SANITIZER("object-size", ObjectSize)
-SANITIZER("float-cast-overflow", FloatCastOverflow)
-// -fsanitize=undefined (and its alias -fcatch-undefined-behavior). This should
-// include all the sanitizers which have low overhead, no ABI or address space
-// layout implications, and only catch undefined behavior.
+// IntegerSanitizer
+SANITIZER("unsigned-integer-overflow", UnsignedIntegerOverflow)
+
+// -fsanitize=undefined includes all the sanitizers which have low overhead, no
+// ABI or address space layout implications, and only catch undefined behavior.
SANITIZER_GROUP("undefined", Undefined,
- SignedIntegerOverflow | DivideByZero | Shift | Unreachable |
- Return | VLABound | Alignment | Null | Vptr | ObjectSize |
- FloatCastOverflow)
+ Alignment | Bool | Bounds | Enum | FloatCastOverflow |
+ FloatDivideByZero | IntegerDivideByZero | Null | ObjectSize |
+ Return | Shift | SignedIntegerOverflow | Unreachable |
+ VLABound | Vptr)
+
+// -fsanitize=undefined-trap (and its alias -fcatch-undefined-behavior) includes
+// all sanitizers included by -fsanitize=undefined, except those that require
+// runtime support. This group is generally used in conjunction with the
+// -fsanitize-undefined-trap-on-error flag.
+SANITIZER_GROUP("undefined-trap", UndefinedTrap,
+ Alignment | Bool | Bounds | Enum | FloatCastOverflow |
+ FloatDivideByZero | IntegerDivideByZero | Null | ObjectSize |
+ Return | Shift | SignedIntegerOverflow | Unreachable |
+ VLABound)
+
+SANITIZER_GROUP("integer", Integer,
+ SignedIntegerOverflow | UnsignedIntegerOverflow | Shift |
+ IntegerDivideByZero)
#undef SANITIZER
#undef SANITIZER_GROUP
diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h
index cfcf468..143beb6 100644
--- a/include/clang/Basic/SourceLocation.h
+++ b/include/clang/Basic/SourceLocation.h
@@ -16,12 +16,12 @@
#define LLVM_CLANG_SOURCELOCATION_H
#include "clang/Basic/LLVM.h"
-#include "llvm/Support/PointerLikeTypeTraits.h"
#include "llvm/Support/Compiler.h"
-#include <utility>
-#include <functional>
+#include "llvm/Support/PointerLikeTypeTraits.h"
#include <cassert>
+#include <functional>
#include <string>
+#include <utility>
namespace llvm {
class MemoryBuffer;
@@ -165,7 +165,7 @@ public:
return (void*)(uintptr_t)getRawEncoding();
}
- /// getFromPtrEncoding - Turn a pointer encoding of a SourceLocation object
+ /// \brief Turn a pointer encoding of a SourceLocation object back
/// into a real SourceLocation.
static SourceLocation getFromPtrEncoding(const void *Encoding) {
return getFromRawEncoding((unsigned)(uintptr_t)Encoding);
@@ -218,7 +218,7 @@ public:
/// \brief Represents a character-granular source range.
///
/// The underlying SourceRange can either specify the starting/ending character
-/// of the range, or it can specify the start or the range and the start of the
+/// of the range, or it can specify the start of the range and the start of the
/// last token of the range (a "token range"). In the token range case, the
/// size of the last token must be measured to determine the actual end of the
/// range.
@@ -227,20 +227,14 @@ class CharSourceRange {
bool IsTokenRange;
public:
CharSourceRange() : IsTokenRange(false) {}
- CharSourceRange(SourceRange R, bool ITR) : Range(R),IsTokenRange(ITR){}
+ CharSourceRange(SourceRange R, bool ITR) : Range(R), IsTokenRange(ITR) {}
static CharSourceRange getTokenRange(SourceRange R) {
- CharSourceRange Result;
- Result.Range = R;
- Result.IsTokenRange = true;
- return Result;
+ return CharSourceRange(R, true);
}
static CharSourceRange getCharRange(SourceRange R) {
- CharSourceRange Result;
- Result.Range = R;
- Result.IsTokenRange = false;
- return Result;
+ return CharSourceRange(R, false);
}
static CharSourceRange getTokenRange(SourceLocation B, SourceLocation E) {
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h
index db6bfd2..00c96c3 100644
--- a/include/clang/Basic/SourceManager.h
+++ b/include/clang/Basic/SourceManager.h
@@ -10,7 +10,7 @@
/// \file
/// \brief Defines the SourceManager interface.
///
-/// There are three different types of locations in a file: a spelling
+/// There are three different types of locations in a %file: a spelling
/// location, an expansion location, and a presumed location.
///
/// Given an example of:
@@ -35,21 +35,22 @@
#ifndef LLVM_CLANG_SOURCEMANAGER_H
#define LLVM_CLANG_SOURCEMANAGER_H
-#include "clang/Basic/LLVM.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
-#include "llvm/Support/Allocator.h"
-#include "llvm/Support/DataTypes.h"
-#include "llvm/ADT/PointerIntPair.h"
-#include "llvm/ADT/PointerUnion.h"
-#include "llvm/ADT/IntrusiveRefCntPtr.h"
-#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/DataTypes.h"
#include "llvm/Support/MemoryBuffer.h"
+#include <cassert>
#include <map>
#include <vector>
-#include <cassert>
namespace clang {
@@ -78,7 +79,7 @@ namespace SrcMgr {
};
/// \brief One instance of this struct is kept for every file loaded or used.
- ////
+ ///
/// This object owns the MemoryBuffer object.
class ContentCache {
enum CCFlags {
@@ -270,7 +271,7 @@ namespace SrcMgr {
return SourceLocation::getFromRawEncoding(IncludeLoc);
}
const ContentCache* getContentCache() const {
- return reinterpret_cast<const ContentCache*>(Data & ~7UL);
+ return reinterpret_cast<const ContentCache*>(Data & ~uintptr_t(7));
}
/// \brief Return whether this is a system header or not.
@@ -328,6 +329,11 @@ namespace SrcMgr {
SourceLocation::getFromRawEncoding(ExpansionLocEnd).isInvalid();
}
+ bool isMacroBodyExpansion() const {
+ return getExpansionLocStart().isValid() &&
+ SourceLocation::getFromRawEncoding(ExpansionLocEnd).isValid();
+ }
+
bool isFunctionMacroExpansion() const {
return getExpansionLocStart().isValid() &&
getExpansionLocStart() != getExpansionLocEnd();
@@ -429,6 +435,11 @@ public:
/// \returns true if an error occurred that prevented the source-location
/// entry from being loaded.
virtual bool ReadSLocEntry(int ID) = 0;
+
+ /// \brief Retrieve the module import location and name for the given ID, if
+ /// in fact it was loaded from a module (rather than, say, a precompiled
+ /// header).
+ virtual std::pair<SourceLocation, StringRef> getModuleImportLoc(int ID) = 0;
};
@@ -436,7 +447,7 @@ public:
///
/// The cache structure is complex enough to be worth breaking out of
/// SourceManager.
-class IsBeforeInTranslationUnitCache {
+class InBeforeInTUCacheEntry {
/// \brief The FileID's of the cached query.
///
/// If these match up with a subsequent query, the result can be reused.
@@ -458,7 +469,6 @@ class IsBeforeInTranslationUnitCache {
/// random token in the parent.
unsigned LCommonOffset, RCommonOffset;
public:
-
/// \brief Return true if the currently cached values match up with
/// the specified LHS/RHS query.
///
@@ -508,6 +518,11 @@ public:
};
+/// \brief The stack used when building modules on demand, which is used
+/// to provide a link between the source managers of the different compiler
+/// instances.
+typedef ArrayRef<std::pair<std::string, FullSourceLoc> > ModuleBuildStack;
+
/// \brief This class handles loading and caching of source files into memory.
///
/// This object owns the MemoryBuffer objects for all of the loaded
@@ -572,13 +587,13 @@ class SourceManager : public RefCountedBase<SourceManager> {
///
/// Positive FileIDs are indexes into this table. Entry 0 indicates an invalid
/// expansion.
- std::vector<SrcMgr::SLocEntry> LocalSLocEntryTable;
+ SmallVector<SrcMgr::SLocEntry, 0> LocalSLocEntryTable;
/// \brief The table of SLocEntries that are loaded from other modules.
///
/// Negative FileIDs are indexes into this table. To get from ID to an index,
/// use (-ID - 2).
- mutable std::vector<SrcMgr::SLocEntry> LoadedSLocEntryTable;
+ mutable SmallVector<SrcMgr::SLocEntry, 0> LoadedSLocEntryTable;
/// \brief The starting offset of the next local SLocEntry.
///
@@ -631,8 +646,21 @@ class SourceManager : public RefCountedBase<SourceManager> {
// Statistics for -print-stats.
mutable unsigned NumLinearScans, NumBinaryProbes;
- // Cache results for the isBeforeInTranslationUnit method.
- mutable IsBeforeInTranslationUnitCache IsBeforeInTUCache;
+ /// The key value into the IsBeforeInTUCache table.
+ typedef std::pair<FileID, FileID> IsBeforeInTUCacheKey;
+
+ /// The IsBeforeInTranslationUnitCache is a mapping from FileID pairs
+ /// to cache results.
+ typedef llvm::DenseMap<IsBeforeInTUCacheKey, InBeforeInTUCacheEntry>
+ InBeforeInTUCache;
+
+ /// Cache results for the isBeforeInTranslationUnit method.
+ mutable InBeforeInTUCache IBTUCache;
+ mutable InBeforeInTUCacheEntry IBTUCacheOverflow;
+
+ /// Return the cache entry for comparing the given file IDs
+ /// for isBeforeInTranslationUnit.
+ InBeforeInTUCacheEntry &getInBeforeInTUCache(FileID LFID, FileID RFID) const;
// Cache for the "fake" buffer used for error-recovery purposes.
mutable llvm::MemoryBuffer *FakeBufferForRecovery;
@@ -645,6 +673,15 @@ class SourceManager : public RefCountedBase<SourceManager> {
mutable llvm::DenseMap<FileID, MacroArgsMap *> MacroArgsCacheMap;
+ /// \brief The stack of modules being built, which is used to detect
+ /// cycles in the module dependency graph as modules are being built, as
+ /// well as to describe why we're rebuilding a particular module.
+ ///
+ /// There is no way to set this value from the command line. If we ever need
+ /// to do so (e.g., if on-demand module construction moves out-of-process),
+ /// we can add a cc1-level option to do so.
+ SmallVector<std::pair<std::string, FullSourceLoc>, 2> StoredModuleBuildStack;
+
// SourceManager doesn't support copy construction.
explicit SourceManager(const SourceManager&) LLVM_DELETED_FUNCTION;
void operator=(const SourceManager&) LLVM_DELETED_FUNCTION;
@@ -669,6 +706,22 @@ public:
/// (likely to change while trying to use them).
bool userFilesAreVolatile() const { return UserFilesAreVolatile; }
+ /// \brief Retrieve the module build stack.
+ ModuleBuildStack getModuleBuildStack() const {
+ return StoredModuleBuildStack;
+ }
+
+ /// \brief Set the module build stack.
+ void setModuleBuildStack(ModuleBuildStack stack) {
+ StoredModuleBuildStack.clear();
+ StoredModuleBuildStack.append(stack.begin(), stack.end());
+ }
+
+ /// \brief Push an entry to the module build stack.
+ void pushModuleBuildStack(StringRef moduleName, FullSourceLoc importLoc) {
+ StoredModuleBuildStack.push_back(std::make_pair(moduleName.str(),importLoc));
+ }
+
/// \brief Create the FileID for a memory buffer that will represent the
/// FileID for the main source.
///
@@ -959,6 +1012,21 @@ public:
return Entry.getFile().getIncludeLoc();
}
+ // \brief Returns the import location if the given source location is
+ // located within a module, or an invalid location if the source location
+ // is within the current translation unit.
+ std::pair<SourceLocation, StringRef>
+ getModuleImportLoc(SourceLocation Loc) const {
+ FileID FID = getFileID(Loc);
+
+ // Positive file IDs are in the current translation unit, and -1 is a
+ // placeholder.
+ if (FID.ID >= -1)
+ return std::make_pair(SourceLocation(), "");
+
+ return ExternalSLocEntries->getModuleImportLoc(FID.ID);
+ }
+
/// \brief Given a SourceLocation object \p Loc, return the expansion
/// location referenced by the ID.
SourceLocation getExpansionLoc(SourceLocation Loc) const {
@@ -1075,6 +1143,13 @@ public:
/// expanded.
bool isMacroArgExpansion(SourceLocation Loc) const;
+ /// \brief Tests whether the given source location represents the expansion of
+ /// a macro body.
+ ///
+ /// This is equivalent to testing whether the location is part of a macro
+ /// expansion but not the expansion of an argument to a function-like macro.
+ bool isMacroBodyExpansion(SourceLocation Loc) const;
+
/// \brief Returns true if \p Loc is inside the [\p Start, +\p Length)
/// chunk of the source location address space.
///
@@ -1187,7 +1262,8 @@ public:
/// presumed location cannot be calculate (e.g., because \p Loc is invalid
/// or the file containing \p Loc has changed on disk), returns an invalid
/// presumed location.
- PresumedLoc getPresumedLoc(SourceLocation Loc) const;
+ PresumedLoc getPresumedLoc(SourceLocation Loc,
+ bool UseLineDirectives = true) const;
/// \brief Returns true if both SourceLocations correspond to the same file.
bool isFromSameFile(SourceLocation Loc1, SourceLocation Loc2) const {
@@ -1421,40 +1497,13 @@ public:
return !isLoadedFileID(FID);
}
- /// Get a presumed location suitable for displaying in a diagnostic message,
- /// taking into account macro arguments and expansions.
- PresumedLoc getPresumedLocForDisplay(SourceLocation Loc) const {
- // This is a condensed form of the algorithm used by emitCaretDiagnostic to
- // walk to the top of the macro call stack.
- while (Loc.isMacroID()) {
- Loc = skipToMacroArgExpansion(Loc);
- Loc = getImmediateMacroCallerLoc(Loc);
- }
-
- return getPresumedLoc(Loc);
- }
-
- /// Look through spelling locations for a macro argument expansion, and if
- /// found skip to it so that we can trace the argument rather than the macros
- /// in which that argument is used. If no macro argument expansion is found,
- /// don't skip anything and return the starting location.
- SourceLocation skipToMacroArgExpansion(SourceLocation StartLoc) const {
- for (SourceLocation L = StartLoc; L.isMacroID();
- L = getImmediateSpellingLoc(L)) {
- if (isMacroArgExpansion(L))
- return L;
- }
- // Otherwise just return initial location, there's nothing to skip.
- return StartLoc;
- }
-
/// Gets the location of the immediate macro caller, one level up the stack
/// toward the initial macro typed into the source.
SourceLocation getImmediateMacroCallerLoc(SourceLocation Loc) const {
if (!Loc.isMacroID()) return Loc;
// When we have the location of (part of) an expanded parameter, its
- // spelling location points to the argument as typed into the macro call,
+ // spelling location points to the argument as expanded in the macro call,
// and therefore is used to locate the macro caller.
if (isMacroArgExpansion(Loc))
return getImmediateSpellingLoc(Loc);
@@ -1464,22 +1513,6 @@ public:
return getImmediateExpansionRange(Loc).first;
}
- /// Gets the location of the immediate macro callee, one level down the stack
- /// toward the leaf macro.
- SourceLocation getImmediateMacroCalleeLoc(SourceLocation Loc) const {
- if (!Loc.isMacroID()) return Loc;
-
- // When we have the location of (part of) an expanded parameter, its
- // expansion location points to the unexpanded parameter reference within
- // the macro definition (or callee).
- if (isMacroArgExpansion(Loc))
- return getImmediateExpansionRange(Loc).first;
-
- // Otherwise, the callee of the macro is located where this location was
- // spelled inside the macro definition.
- return getImmediateSpellingLoc(Loc);
- }
-
private:
const llvm::MemoryBuffer *getFakeBufferForRecovery() const;
const SrcMgr::ContentCache *getFakeContentCacheForRecovery() const;
@@ -1599,4 +1632,5 @@ public:
} // end namespace clang
+
#endif
diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h
index c82b8cb..8706179 100644
--- a/include/clang/Basic/Specifiers.h
+++ b/include/clang/Basic/Specifiers.h
@@ -62,13 +62,21 @@ namespace clang {
TST_auto, // C++0x auto
TST_unknown_anytype, // __unknown_anytype extension
TST_atomic, // C11 _Atomic
+ TST_image1d_t, // OpenCL image1d_t
+ TST_image1d_array_t, // OpenCL image1d_array_t
+ TST_image1d_buffer_t, // OpenCL image1d_buffer_t
+ TST_image2d_t, // OpenCL image2d_t
+ TST_image2d_array_t, // OpenCL image2d_array_t
+ TST_image3d_t, // OpenCL image3d_t
+ TST_sampler_t, // OpenCL sampler_t
+ TST_event_t, // OpenCL event_t
TST_error // erroneous type
};
/// \brief Structure that packs information about the type specifiers that
/// were written in a particular type specifier sequence.
struct WrittenBuiltinSpecs {
- /*DeclSpec::TST*/ unsigned Type : 5;
+ /*DeclSpec::TST*/ unsigned Type : 6;
/*DeclSpec::TSS*/ unsigned Sign : 2;
/*DeclSpec::TSW*/ unsigned Width : 2;
bool ModeAttr : 1;
@@ -186,7 +194,8 @@ namespace clang {
CC_X86Pascal, // __attribute__((pascal))
CC_AAPCS, // __attribute__((pcs("aapcs")))
CC_AAPCS_VFP, // __attribute__((pcs("aapcs-vfp")))
- CC_PnaclCall // __attribute__((pnaclcall))
+ CC_PnaclCall, // __attribute__((pnaclcall))
+ CC_IntelOclBicc // __attribute__((intel_ocl_bicc))
};
} // end namespace clang
diff --git a/include/clang/Basic/TargetCXXABI.h b/include/clang/Basic/TargetCXXABI.h
new file mode 100644
index 0000000..c9d28f8
--- /dev/null
+++ b/include/clang/Basic/TargetCXXABI.h
@@ -0,0 +1,261 @@
+//===--- TargetCXXABI.h - C++ ABI Target Configuration ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Defines the TargetCXXABI class, which abstracts details of the
+/// C++ ABI that we're targeting.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TARGETCXXABI_H
+#define LLVM_CLANG_TARGETCXXABI_H
+
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/ErrorHandling.h"
+
+namespace clang {
+
+/// \brief The basic abstraction for the target C++ ABI.
+class TargetCXXABI {
+public:
+ /// \brief The basic C++ ABI kind.
+ enum Kind {
+ /// The generic Itanium ABI is the standard ABI of most open-source
+ /// and Unix-like platforms. It is the primary ABI targeted by
+ /// many compilers, including Clang and GCC.
+ ///
+ /// It is documented here:
+ /// http://www.codesourcery.com/public/cxx-abi/
+ GenericItanium,
+
+ /// The generic ARM ABI is a modified version of the Itanium ABI
+ /// proposed by ARM for use on ARM-based platforms.
+ ///
+ /// These changes include:
+ /// - the representation of member function pointers is adjusted
+ /// to not conflict with the 'thumb' bit of ARM function pointers;
+ /// - constructors and destructors return 'this';
+ /// - guard variables are smaller;
+ /// - inline functions are never key functions;
+ /// - array cookies have a slightly different layout;
+ /// - additional convenience functions are specified;
+ /// - and more!
+ ///
+ /// It is documented here:
+ /// http://infocenter.arm.com
+ /// /help/topic/com.arm.doc.ihi0041c/IHI0041C_cppabi.pdf
+ GenericARM,
+
+ /// The iOS ABI is a partial implementation of the ARM ABI.
+ /// Several of the features of the ARM ABI were not fully implemented
+ /// in the compilers that iOS was launched with.
+ ///
+ /// Essentially, the iOS ABI includes the ARM changes to:
+ /// - member function pointers,
+ /// - guard variables,
+ /// - array cookies, and
+ /// - constructor/destructor signatures.
+ iOS,
+
+ /// The generic AArch64 ABI is also a modified version of the Itanium ABI,
+ /// but it has fewer divergences than the 32-bit ARM ABI.
+ ///
+ /// The relevant changes from the generic ABI in this case are:
+ /// - representation of member function pointers adjusted as in ARM.
+ /// - guard variables are smaller.
+ GenericAArch64,
+
+ /// The Microsoft ABI is the ABI used by Microsoft Visual Studio (and
+ /// compatible compilers).
+ ///
+ /// FIXME: should this be split into Win32 and Win64 variants?
+ ///
+ /// Only scattered and incomplete official documentation exists.
+ Microsoft
+ };
+
+private:
+ // Right now, this class is passed around as a cheap value type.
+ // If you add more members, especially non-POD members, please
+ // audit the users to pass it by reference instead.
+ Kind TheKind;
+
+public:
+ /// A bogus initialization of the platform ABI.
+ TargetCXXABI() : TheKind(GenericItanium) {}
+
+ TargetCXXABI(Kind kind) : TheKind(kind) {}
+
+ void set(Kind kind) {
+ TheKind = kind;
+ }
+
+ Kind getKind() const { return TheKind; }
+
+ /// \brief Does this ABI generally fall into the Itanium family of ABIs?
+ bool isItaniumFamily() const {
+ switch (getKind()) {
+ case GenericAArch64:
+ case GenericItanium:
+ case GenericARM:
+ case iOS:
+ return true;
+
+ case Microsoft:
+ return false;
+ }
+ llvm_unreachable("bad ABI kind");
+ }
+
+ /// \brief Is this ABI an MSVC-compatible ABI?
+ bool isMicrosoft() const {
+ switch (getKind()) {
+ case GenericAArch64:
+ case GenericItanium:
+ case GenericARM:
+ case iOS:
+ return false;
+
+ case Microsoft:
+ return true;
+ }
+ llvm_unreachable("bad ABI kind");
+ }
+
+ /// \brief Is the default C++ member function calling convention
+ /// the same as the default calling convention?
+ bool isMemberFunctionCCDefault() const {
+ // Right now, this is always true for Microsoft.
+ return !isMicrosoft();
+ }
+
+ /// \brief Does this ABI have different entrypoints for complete-object
+ /// and base-subobject constructors?
+ bool hasConstructorVariants() const {
+ return isItaniumFamily();
+ }
+
+ /// \brief Does this ABI have different entrypoints for complete-object
+ /// and base-subobject destructors?
+ bool hasDestructorVariants() const {
+ return isItaniumFamily();
+ }
+
+ /// \brief Does this ABI allow virtual bases to be primary base classes?
+ bool hasPrimaryVBases() const {
+ return isItaniumFamily();
+ }
+
+ /// \brief Can an out-of-line inline function serve as a key function?
+ ///
+ /// This flag is only useful in ABIs where type data (for example,
+ /// v-tables and type_info objects) are emitted only after processing
+ /// the definition of a special "key" virtual function. (This is safe
+ /// because the ODR requires that every virtual function be defined
+ /// somewhere in a program.) This usually permits such data to be
+ /// emitted in only a single object file, as opposed to redundantly
+ /// in every object file that requires it.
+ ///
+ /// One simple and common definition of "key function" is the first
+ /// virtual function in the class definition which is not defined there.
+ /// This rule works very well when that function has a non-inline
+ /// definition in some non-header file. Unfortunately, when that
+ /// function is defined inline, this rule requires the type data
+ /// to be emitted weakly, as if there were no key function.
+ ///
+ /// The ARM ABI observes that the ODR provides an additional guarantee:
+ /// a virtual function is always ODR-used, so if it is defined inline,
+ /// that definition must appear in every translation unit that defines
+ /// the class. Therefore, there is no reason to allow such functions
+ /// to serve as key functions.
+ ///
+ /// Because this changes the rules for emitting type data,
+ /// it can cause type data to be emitted with both weak and strong
+ /// linkage, which is not allowed on all platforms. Therefore,
+ /// exploiting this observation requires an ABI break and cannot be
+ /// done on a generic Itanium platform.
+ bool canKeyFunctionBeInline() const {
+ switch (getKind()) {
+ case GenericARM:
+ return false;
+
+ case GenericAArch64:
+ case GenericItanium:
+ case iOS: // old iOS compilers did not follow this rule
+ case Microsoft:
+ return true;
+ }
+ llvm_unreachable("bad ABI kind");
+ }
+
+ /// When is record layout allowed to allocate objects in the tail
+ /// padding of a base class?
+ ///
+ /// This decision cannot be changed without breaking platform ABI
+ /// compatibility, and yet it is tied to language guarantees which
+ /// the committee has so far seen fit to strengthen no less than
+ /// three separate times:
+ /// - originally, there were no restrictions at all;
+ /// - C++98 declared that objects could not be allocated in the
+ /// tail padding of a POD type;
+ /// - C++03 extended the definition of POD to include classes
+ /// containing member pointers; and
+ /// - C++11 greatly broadened the definition of POD to include
+ /// all trivial standard-layout classes.
+ /// Each of these changes technically took several existing
+ /// platforms and made them permanently non-conformant.
+ enum TailPaddingUseRules {
+ /// The tail-padding of a base class is always theoretically
+ /// available, even if it's POD. This is not strictly conforming
+ /// in any language mode.
+ AlwaysUseTailPadding,
+
+ /// Only allocate objects in the tail padding of a base class if
+ /// the base class is not POD according to the rules of C++ TR1.
+ /// This is non strictly conforming in C++11 mode.
+ UseTailPaddingUnlessPOD03,
+
+ /// Only allocate objects in the tail padding of a base class if
+ /// the base class is not POD according to the rules of C++11.
+ UseTailPaddingUnlessPOD11
+ };
+ TailPaddingUseRules getTailPaddingUseRules() const {
+ switch (getKind()) {
+ // To preserve binary compatibility, the generic Itanium ABI has
+ // permanently locked the definition of POD to the rules of C++ TR1,
+ // and that trickles down to all the derived ABIs.
+ case GenericItanium:
+ case GenericAArch64:
+ case GenericARM:
+ case iOS:
+ return UseTailPaddingUnlessPOD03;
+
+ // MSVC always allocates fields in the tail-padding of a base class
+ // subobject, even if they're POD.
+ case Microsoft:
+ return AlwaysUseTailPadding;
+ }
+ llvm_unreachable("bad ABI kind");
+ }
+
+ /// Try to parse an ABI name, returning false on error.
+ bool tryParse(llvm::StringRef name);
+
+ friend bool operator==(const TargetCXXABI &left, const TargetCXXABI &right) {
+ return left.getKind() == right.getKind();
+ }
+
+ friend bool operator!=(const TargetCXXABI &left, const TargetCXXABI &right) {
+ return !(left == right);
+ }
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h
index 2d26783..c05f062 100644
--- a/include/clang/Basic/TargetInfo.h
+++ b/include/clang/Basic/TargetInfo.h
@@ -15,20 +15,21 @@
#ifndef LLVM_CLANG_BASIC_TARGETINFO_H
#define LLVM_CLANG_BASIC_TARGETINFO_H
+#include "clang/Basic/AddressSpaces.h"
+#include "clang/Basic/TargetCXXABI.h"
#include "clang/Basic/LLVM.h"
+#include "clang/Basic/Specifiers.h"
+#include "clang/Basic/TargetOptions.h"
+#include "clang/Basic/VersionTuple.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/DataTypes.h"
-#include "clang/Basic/AddressSpaces.h"
-#include "clang/Basic/TargetOptions.h"
-#include "clang/Basic/VersionTuple.h"
-#include "clang/Basic/Specifiers.h"
#include <cassert>
-#include <vector>
#include <string>
+#include <vector>
namespace llvm {
struct fltSemantics;
@@ -43,26 +44,10 @@ class SourceManager;
namespace Builtin { struct Info; }
-/// \brief The types of C++ ABIs for which we can generate code.
-enum TargetCXXABI {
- /// The generic ("Itanium") C++ ABI, documented at:
- /// http://www.codesourcery.com/public/cxx-abi/
- CXXABI_Itanium,
-
- /// The ARM C++ ABI, based largely on the Itanium ABI but with
- /// significant differences.
- /// http://infocenter.arm.com
- /// /help/topic/com.arm.doc.ihi0041c/IHI0041C_cppabi.pdf
- CXXABI_ARM,
-
- /// The Visual Studio ABI. Only scattered official documentation exists.
- CXXABI_Microsoft
-};
-
/// \brief Exposes information about the current target.
///
class TargetInfo : public RefCountedBase<TargetInfo> {
- llvm::IntrusiveRefCntPtr<TargetOptions> TargetOpts;
+ IntrusiveRefCntPtr<TargetOptions> TargetOpts;
llvm::Triple Triple;
protected:
// Target values set by the ctor of the actual target implementation. Default
@@ -89,7 +74,7 @@ protected:
const llvm::fltSemantics *HalfFormat, *FloatFormat, *DoubleFormat,
*LongDoubleFormat;
unsigned char RegParmMax, SSERegParmMax;
- TargetCXXABI CXXABI;
+ TargetCXXABI TheCXXABI;
const LangAS::Map *AddrSpaceMap;
mutable StringRef PlatformName;
@@ -109,7 +94,7 @@ public:
/// modify the options to canonicalize the target feature information to match
/// what the backend expects.
static TargetInfo* CreateTargetInfo(DiagnosticsEngine &Diags,
- TargetOptions &Opts);
+ TargetOptions *Opts);
virtual ~TargetInfo();
@@ -119,8 +104,8 @@ public:
return *TargetOpts;
}
- void setTargetOpts(TargetOptions &TargetOpts) {
- this->TargetOpts = &TargetOpts;
+ void setTargetOpts(TargetOptions *TargetOpts) {
+ this->TargetOpts = TargetOpts;
}
///===---- Target Data Type Query Methods -------------------------------===//
@@ -151,6 +136,10 @@ public:
/// typedef void* __builtin_va_list;
VoidPtrBuiltinVaList,
+ /// __builtin_va_list as defind by the AArch64 ABI
+ /// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055a/IHI0055A_aapcs64.pdf
+ AArch64ABIBuiltinVaList,
+
/// __builtin_va_list as defined by the PNaCl ABI:
/// http://www.chromium.org/nativeclient/pnacl/bitcode-abi#TOC-Machine-Types
PNaClABIBuiltinVaList,
@@ -270,6 +259,9 @@ public:
unsigned getLongLongWidth() const { return LongLongWidth; }
unsigned getLongLongAlign() const { return LongLongAlign; }
+ /// \brief Determine whether the __int128 type is supported on this target.
+ bool hasInt128Type() const { return getPointerWidth(0) >= 64; } // FIXME
+
/// \brief Return the alignment that is suitable for storing any
/// object with a fundamental alignment requirement.
unsigned getSuitableAlign() const { return SuitableAlign; }
@@ -335,6 +327,9 @@ public:
return getTypeWidth(IntMaxType);
}
+ // Return the size of unwind_word for this target.
+ unsigned getUnwindWordWidth() const { return getPointerWidth(0); }
+
/// \brief Return the "preferred" register width on this target.
uint64_t getRegisterWidth() const {
// Currently we assume the register width on the target matches the pointer
@@ -518,6 +513,10 @@ public:
bool validateInputConstraint(ConstraintInfo *OutputConstraints,
unsigned NumOutputs,
ConstraintInfo &info) const;
+ virtual bool validateInputSize(StringRef /*Constraint*/,
+ unsigned /*Size*/) const {
+ return true;
+ }
virtual bool validateConstraintModifier(StringRef /*Constraint*/,
const char /*Modifier*/,
unsigned /*Size*/) const {
@@ -572,8 +571,6 @@ public:
/// either; the entire thing is pretty badly mangled.
virtual bool hasProtectedVisibility() const { return true; }
- virtual bool useGlobalsForAutomaticVariables() const { return false; }
-
/// \brief Return the section to use for CFString literals, or 0 if no
/// special section is used.
virtual const char *getCFStringSection() const {
@@ -624,8 +621,8 @@ public:
}
/// \brief Get the C++ ABI currently in use.
- virtual TargetCXXABI getCXXABI() const {
- return CXXABI;
+ TargetCXXABI getCXXABI() const {
+ return TheCXXABI;
}
/// \brief Target the specified CPU.
@@ -645,14 +642,9 @@ public:
/// \brief Use this specified C++ ABI.
///
/// \return False on error (invalid C++ ABI name).
- bool setCXXABI(const std::string &Name) {
- static const TargetCXXABI Unknown = static_cast<TargetCXXABI>(-1);
- TargetCXXABI ABI = llvm::StringSwitch<TargetCXXABI>(Name)
- .Case("arm", CXXABI_ARM)
- .Case("itanium", CXXABI_Itanium)
- .Case("microsoft", CXXABI_Microsoft)
- .Default(Unknown);
- if (ABI == Unknown) return false;
+ bool setCXXABI(llvm::StringRef name) {
+ TargetCXXABI ABI;
+ if (!ABI.tryParse(name)) return false;
return setCXXABI(ABI);
}
@@ -660,7 +652,7 @@ public:
///
/// \return False on error (ABI not valid on this target)
virtual bool setCXXABI(TargetCXXABI ABI) {
- CXXABI = ABI;
+ TheCXXABI = ABI;
return true;
}
@@ -735,13 +727,19 @@ public:
bool isBigEndian() const { return BigEndian; }
+ enum CallingConvMethodType {
+ CCMT_Unknown,
+ CCMT_Member,
+ CCMT_NonMember
+ };
+
/// \brief Gets the default calling convention for the given target and
/// declaration context.
- virtual CallingConv getDefaultCallingConv() const {
+ virtual CallingConv getDefaultCallingConv(CallingConvMethodType MT) const {
// Not all targets will specify an explicit calling convention that we can
// express. This will always do the right thing, even though it's not
// an explicit calling convention.
- return CC_Default;
+ return CC_C;
}
enum CallingConvCheckResult {
diff --git a/include/clang/Basic/TargetOptions.h b/include/clang/Basic/TargetOptions.h
index d6deb02..c2183fd 100644
--- a/include/clang/Basic/TargetOptions.h
+++ b/include/clang/Basic/TargetOptions.h
@@ -15,6 +15,7 @@
#ifndef LLVM_CLANG_FRONTEND_TARGETOPTIONS_H
#define LLVM_CLANG_FRONTEND_TARGETOPTIONS_H
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include <string>
#include <vector>
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index 25e8d5a..a254fae 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -121,7 +121,7 @@ TOK(numeric_constant) // 0x123
TOK(char_constant) // 'a'
TOK(wide_char_constant) // L'b'
-// C++0x Character Constants
+// C++11 Character Constants
TOK(utf16_char_constant) // u'a'
TOK(utf32_char_constant) // U'a'
@@ -130,7 +130,7 @@ TOK(string_literal) // "foo"
TOK(wide_string_literal) // L"foo"
TOK(angle_string_literal)// <foo>
-// C++0x String Literals.
+// C++11 String Literals.
TOK(utf8_string_literal) // u8"foo"
TOK(utf16_string_literal)// u"foo"
TOK(utf32_string_literal)// U"foo"
@@ -208,7 +208,7 @@ PUNCTUATOR(greatergreatergreater, ">>>")
// KEYCXX - This is a C++ keyword, or a C++-specific keyword in the
// implementation namespace
// KEYNOCXX - This is a keyword in every non-C++ dialect.
-// KEYCXX0X - This is a C++ keyword introduced to C++ in C++0x
+// KEYCXX11 - This is a C++ keyword introduced to C++ in C++11
// KEYGNU - This is a keyword if GNU extensions are enabled
// KEYMS - This is a keyword if Microsoft extensions are enabled
// KEYNOMS - This is a keyword that must never be enabled under
@@ -260,6 +260,7 @@ KEYWORD(_Bool , KEYNOCXX)
KEYWORD(_Complex , KEYALL)
KEYWORD(_Generic , KEYALL)
KEYWORD(_Imaginary , KEYALL)
+KEYWORD(_Noreturn , KEYALL)
KEYWORD(_Static_assert , KEYALL)
KEYWORD(__func__ , KEYALL)
KEYWORD(__objc_yes , KEYALL)
@@ -311,17 +312,17 @@ CXX_KEYWORD_OPERATOR(or_eq , pipeequal)
CXX_KEYWORD_OPERATOR(xor , caret)
CXX_KEYWORD_OPERATOR(xor_eq , caretequal)
-// C++0x keywords
-KEYWORD(alignas , KEYCXX0X)
-KEYWORD(alignof , KEYCXX0X)
-KEYWORD(char16_t , KEYCXX0X|KEYNOMS)
-KEYWORD(char32_t , KEYCXX0X|KEYNOMS)
-KEYWORD(constexpr , KEYCXX0X)
-KEYWORD(decltype , KEYCXX0X)
-KEYWORD(noexcept , KEYCXX0X)
-KEYWORD(nullptr , KEYCXX0X)
-KEYWORD(static_assert , KEYCXX0X)
-KEYWORD(thread_local , KEYCXX0X)
+// C++11 keywords
+KEYWORD(alignas , KEYCXX11)
+KEYWORD(alignof , KEYCXX11)
+KEYWORD(char16_t , KEYCXX11|KEYNOMS)
+KEYWORD(char32_t , KEYCXX11|KEYNOMS)
+KEYWORD(constexpr , KEYCXX11)
+KEYWORD(decltype , KEYCXX11)
+KEYWORD(noexcept , KEYCXX11)
+KEYWORD(nullptr , KEYCXX11)
+KEYWORD(static_assert , KEYCXX11)
+KEYWORD(thread_local , KEYCXX11)
// GNU Extensions (in impl-reserved namespace)
KEYWORD(_Decimal32 , KEYALL)
@@ -350,31 +351,34 @@ KEYWORD(typeof , KEYGNU)
KEYWORD(L__FUNCTION__ , KEYMS)
// GNU and MS Type Traits
-KEYWORD(__has_nothrow_assign , KEYCXX)
-KEYWORD(__has_nothrow_copy , KEYCXX)
-KEYWORD(__has_nothrow_constructor , KEYCXX)
-KEYWORD(__has_trivial_assign , KEYCXX)
-KEYWORD(__has_trivial_copy , KEYCXX)
-KEYWORD(__has_trivial_constructor , KEYCXX)
-KEYWORD(__has_trivial_destructor , KEYCXX)
-KEYWORD(__has_virtual_destructor , KEYCXX)
-KEYWORD(__is_abstract , KEYCXX)
-KEYWORD(__is_base_of , KEYCXX)
-KEYWORD(__is_class , KEYCXX)
-KEYWORD(__is_convertible_to , KEYCXX)
-KEYWORD(__is_empty , KEYCXX)
-KEYWORD(__is_enum , KEYCXX)
-KEYWORD(__is_final , KEYCXX)
-KEYWORD(__is_interface_class , KEYCXX)
+KEYWORD(__has_nothrow_assign , KEYCXX)
+KEYWORD(__has_nothrow_move_assign , KEYCXX)
+KEYWORD(__has_nothrow_copy , KEYCXX)
+KEYWORD(__has_nothrow_constructor , KEYCXX)
+KEYWORD(__has_trivial_assign , KEYCXX)
+KEYWORD(__has_trivial_move_assign , KEYCXX)
+KEYWORD(__has_trivial_copy , KEYCXX)
+KEYWORD(__has_trivial_constructor , KEYCXX)
+KEYWORD(__has_trivial_move_constructor, KEYCXX)
+KEYWORD(__has_trivial_destructor , KEYCXX)
+KEYWORD(__has_virtual_destructor , KEYCXX)
+KEYWORD(__is_abstract , KEYCXX)
+KEYWORD(__is_base_of , KEYCXX)
+KEYWORD(__is_class , KEYCXX)
+KEYWORD(__is_convertible_to , KEYCXX)
+KEYWORD(__is_empty , KEYCXX)
+KEYWORD(__is_enum , KEYCXX)
+KEYWORD(__is_final , KEYCXX)
+KEYWORD(__is_interface_class , KEYCXX)
// Tentative name - there's no implementation of std::is_literal_type yet.
-KEYWORD(__is_literal , KEYCXX)
+KEYWORD(__is_literal , KEYCXX)
// Name for GCC 4.6 compatibility - people have already written libraries using
// this name unfortunately.
-KEYWORD(__is_literal_type , KEYCXX)
-KEYWORD(__is_pod , KEYCXX)
-KEYWORD(__is_polymorphic , KEYCXX)
-KEYWORD(__is_trivial , KEYCXX)
-KEYWORD(__is_union , KEYCXX)
+KEYWORD(__is_literal_type , KEYCXX)
+KEYWORD(__is_pod , KEYCXX)
+KEYWORD(__is_polymorphic , KEYCXX)
+KEYWORD(__is_trivial , KEYCXX)
+KEYWORD(__is_union , KEYCXX)
// Clang-only C++ Type Traits
KEYWORD(__is_trivially_constructible, KEYCXX)
@@ -448,6 +452,14 @@ ALIAS("read_only", __read_only , KEYOPENCL)
ALIAS("write_only", __write_only , KEYOPENCL)
ALIAS("read_write", __read_write , KEYOPENCL)
KEYWORD(__builtin_astype , KEYOPENCL)
+KEYWORD(image1d_t , KEYOPENCL)
+KEYWORD(image1d_array_t , KEYOPENCL)
+KEYWORD(image1d_buffer_t , KEYOPENCL)
+KEYWORD(image2d_t , KEYOPENCL)
+KEYWORD(image2d_array_t , KEYOPENCL)
+KEYWORD(image3d_t , KEYOPENCL)
+KEYWORD(sampler_t , KEYOPENCL)
+KEYWORD(event_t , KEYOPENCL)
// Borland Extensions.
KEYWORD(__pascal , KEYALL)
@@ -566,7 +578,7 @@ OBJC2_AT_KEYWORD(required)
OBJC2_AT_KEYWORD(optional)
OBJC2_AT_KEYWORD(synthesize)
OBJC2_AT_KEYWORD(dynamic)
-OBJC2_AT_KEYWORD(__experimental_modules_import)
+OBJC2_AT_KEYWORD(import)
// TODO: What to do about context-sensitive keywords like:
// bycopy/byref/in/inout/oneway/out?
@@ -637,6 +649,12 @@ ANNOTATION(pragma_fp_contract)
// handles them.
ANNOTATION(pragma_opencl_extension)
+// Annotations for OpenMP pragma directives - #pragma omp ...
+// The lexer produces these so that they only take effect when the parser
+// handles #pragma omp ... directives.
+ANNOTATION(pragma_openmp)
+ANNOTATION(pragma_openmp_end)
+
#undef ANNOTATION
#undef TESTING_KEYWORD
#undef OBJC2_AT_KEYWORD
diff --git a/include/clang/Basic/TokenKinds.h b/include/clang/Basic/TokenKinds.h
index e850971..dcbe1da 100644
--- a/include/clang/Basic/TokenKinds.h
+++ b/include/clang/Basic/TokenKinds.h
@@ -68,15 +68,21 @@ inline bool isAnyIdentifier(TokenKind K) {
return (K == tok::identifier) || (K == tok::raw_identifier);
}
+/// \brief Return true if this is a C or C++ string-literal (or
+/// C++11 user-defined-string-literal) token.
+inline bool isStringLiteral(TokenKind K) {
+ return K == tok::string_literal || K == tok::wide_string_literal ||
+ K == tok::utf8_string_literal || K == tok::utf16_string_literal ||
+ K == tok::utf32_string_literal;
+}
+
/// \brief Return true if this is a "literal" kind, like a numeric
/// constant, string, etc.
inline bool isLiteral(TokenKind K) {
- return (K == tok::numeric_constant) || (K == tok::char_constant) ||
- (K == tok::wide_char_constant) || (K == tok::utf16_char_constant) ||
- (K == tok::utf32_char_constant) || (K == tok::string_literal) ||
- (K == tok::wide_string_literal) || (K == tok::utf8_string_literal) ||
- (K == tok::utf16_string_literal) || (K == tok::utf32_string_literal) ||
- (K == tok::angle_string_literal);
+ return K == tok::numeric_constant || K == tok::char_constant ||
+ K == tok::wide_char_constant || K == tok::utf16_char_constant ||
+ K == tok::utf32_char_constant || isStringLiteral(K) ||
+ K == tok::angle_string_literal;
}
/// \brief Return true if this is any of tok::annot_* kinds.
diff --git a/include/clang/Basic/TypeTraits.h b/include/clang/Basic/TypeTraits.h
index 882b52d..1645796 100644
--- a/include/clang/Basic/TypeTraits.h
+++ b/include/clang/Basic/TypeTraits.h
@@ -20,11 +20,14 @@ namespace clang {
/// \brief Names for the unary type traits.
enum UnaryTypeTrait {
UTT_HasNothrowAssign,
+ UTT_HasNothrowMoveAssign,
UTT_HasNothrowCopy,
UTT_HasNothrowConstructor,
UTT_HasTrivialAssign,
+ UTT_HasTrivialMoveAssign,
UTT_HasTrivialCopy,
UTT_HasTrivialDefaultConstructor,
+ UTT_HasTrivialMoveConstructor,
UTT_HasTrivialDestructor,
UTT_HasVirtualDestructor,
UTT_IsAbstract,
diff --git a/include/clang/Basic/Version.h b/include/clang/Basic/Version.h
index 3f1b4d8..7db8a2e 100644
--- a/include/clang/Basic/Version.h
+++ b/include/clang/Basic/Version.h
@@ -16,9 +16,8 @@
#ifndef LLVM_CLANG_BASIC_VERSION_H
#define LLVM_CLANG_BASIC_VERSION_H
-#include "llvm/ADT/StringRef.h"
-
#include "clang/Basic/Version.inc"
+#include "llvm/ADT/StringRef.h"
/// \brief Helper macro for CLANG_VERSION_STRING.
#define CLANG_MAKE_VERSION_STRING2(X) #X
diff --git a/include/clang/Basic/VersionTuple.h b/include/clang/Basic/VersionTuple.h
index a94f76c..ff06a5c 100644
--- a/include/clang/Basic/VersionTuple.h
+++ b/include/clang/Basic/VersionTuple.h
@@ -55,16 +55,16 @@ public:
unsigned getMajor() const { return Major; }
/// \brief Retrieve the minor version number, if provided.
- llvm::Optional<unsigned> getMinor() const {
+ Optional<unsigned> getMinor() const {
if (!HasMinor)
- return llvm::Optional<unsigned>();
+ return None;
return Minor;
}
/// \brief Retrieve the subminor version number, if provided.
- llvm::Optional<unsigned> getSubminor() const {
+ Optional<unsigned> getSubminor() const {
if (!HasSubminor)
- return llvm::Optional<unsigned>();
+ return None;
return Subminor;
}
diff --git a/include/clang/Basic/Visibility.h b/include/clang/Basic/Visibility.h
index e81ad91..b623b94 100644
--- a/include/clang/Basic/Visibility.h
+++ b/include/clang/Basic/Visibility.h
@@ -15,6 +15,8 @@
#ifndef LLVM_CLANG_BASIC_VISIBILITY_H
#define LLVM_CLANG_BASIC_VISIBILITY_H
+#include "clang/Basic/Linkage.h"
+
namespace clang {
/// \brief Describes the different kinds of visibility that a declaration
@@ -46,6 +48,80 @@ inline Visibility minVisibility(Visibility L, Visibility R) {
return L < R ? L : R;
}
+class LinkageInfo {
+ uint8_t linkage_ : 2;
+ uint8_t visibility_ : 2;
+ uint8_t explicit_ : 1;
+
+ void setVisibility(Visibility V, bool E) { visibility_ = V; explicit_ = E; }
+public:
+ LinkageInfo() : linkage_(ExternalLinkage), visibility_(DefaultVisibility),
+ explicit_(false) {}
+ LinkageInfo(Linkage L, Visibility V, bool E)
+ : linkage_(L), visibility_(V), explicit_(E) {
+ assert(getLinkage() == L && getVisibility() == V &&
+ isVisibilityExplicit() == E && "Enum truncated!");
+ }
+
+ static LinkageInfo external() {
+ return LinkageInfo();
+ }
+ static LinkageInfo internal() {
+ return LinkageInfo(InternalLinkage, DefaultVisibility, false);
+ }
+ static LinkageInfo uniqueExternal() {
+ return LinkageInfo(UniqueExternalLinkage, DefaultVisibility, false);
+ }
+ static LinkageInfo none() {
+ return LinkageInfo(NoLinkage, DefaultVisibility, false);
+ }
+
+ Linkage getLinkage() const { return (Linkage)linkage_; }
+ Visibility getVisibility() const { return (Visibility)visibility_; }
+ bool isVisibilityExplicit() const { return explicit_; }
+
+ void setLinkage(Linkage L) { linkage_ = L; }
+
+ void mergeLinkage(Linkage L) {
+ setLinkage(minLinkage(getLinkage(), L));
+ }
+ void mergeLinkage(LinkageInfo other) {
+ mergeLinkage(other.getLinkage());
+ }
+
+ /// Merge in the visibility 'newVis'.
+ void mergeVisibility(Visibility newVis, bool newExplicit) {
+ Visibility oldVis = getVisibility();
+
+ // Never increase visibility.
+ if (oldVis < newVis)
+ return;
+
+ // If the new visibility is the same as the old and the new
+ // visibility isn't explicit, we have nothing to add.
+ if (oldVis == newVis && !newExplicit)
+ return;
+
+ // Otherwise, we're either decreasing visibility or making our
+ // existing visibility explicit.
+ setVisibility(newVis, newExplicit);
+ }
+ void mergeVisibility(LinkageInfo other) {
+ mergeVisibility(other.getVisibility(), other.isVisibilityExplicit());
+ }
+
+ /// Merge both linkage and visibility.
+ void merge(LinkageInfo other) {
+ mergeLinkage(other);
+ mergeVisibility(other);
+ }
+
+ /// Merge linkage and conditionally merge visibility.
+ void mergeMaybeWithVisibility(LinkageInfo other, bool withVis) {
+ mergeLinkage(other);
+ if (withVis) mergeVisibility(other);
+ }
+};
}
#endif // LLVM_CLANG_BASIC_VISIBILITY_H
diff --git a/include/clang/CodeGen/ModuleBuilder.h b/include/clang/CodeGen/ModuleBuilder.h
index ba9d1f9..cda7863 100644
--- a/include/clang/CodeGen/ModuleBuilder.h
+++ b/include/clang/CodeGen/ModuleBuilder.h
@@ -26,6 +26,7 @@ namespace clang {
class DiagnosticsEngine;
class LangOptions;
class CodeGenOptions;
+ class TargetOptions;
class CodeGenerator : public ASTConsumer {
virtual void anchor();
@@ -40,6 +41,7 @@ namespace clang {
CodeGenerator *CreateLLVMCodeGen(DiagnosticsEngine &Diags,
const std::string &ModuleName,
const CodeGenOptions &CGO,
+ const TargetOptions &TO,
llvm::LLVMContext& C);
}
diff --git a/include/clang/Driver/Arg.h b/include/clang/Driver/Arg.h
index 3b3829a..662a2e2 100644
--- a/include/clang/Driver/Arg.h
+++ b/include/clang/Driver/Arg.h
@@ -15,9 +15,8 @@
#ifndef CLANG_DRIVER_ARG_H_
#define CLANG_DRIVER_ARG_H_
-#include "clang/Driver/Option.h"
-
#include "Util.h"
+#include "clang/Driver/Option.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include <string>
@@ -52,7 +51,7 @@ namespace driver {
/// ArgList.
unsigned Index;
- /// \brief Was this argument used to effect compilation?
+ /// \brief Was this argument used to affect compilation?
///
/// This is used for generating "argument unused" diagnostics.
mutable unsigned Claimed : 1;
@@ -72,7 +71,7 @@ namespace driver {
const char *Value0, const char *Value1, const Arg *BaseArg = 0);
~Arg();
- const Option getOption() const { return Opt; }
+ Option getOption() const { return Opt; }
StringRef getSpelling() const { return Spelling; }
unsigned getIndex() const { return Index; }
diff --git a/include/clang/Driver/ArgList.h b/include/clang/Driver/ArgList.h
index 72ed7bf..3967dcc 100644
--- a/include/clang/Driver/ArgList.h
+++ b/include/clang/Driver/ArgList.h
@@ -11,12 +11,11 @@
#define CLANG_DRIVER_ARGLIST_H_
#include "clang/Basic/LLVM.h"
-#include "clang/Driver/Option.h"
#include "clang/Driver/OptSpecifier.h"
+#include "clang/Driver/Option.h"
#include "clang/Driver/Util.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
-
#include <list>
#include <string>
#include <vector>
@@ -291,6 +290,8 @@ namespace driver {
StringRef RHS) const;
/// @}
+
+ void dump();
};
class InputArgList : public ArgList {
diff --git a/include/clang/Driver/CC1AsOptions.td b/include/clang/Driver/CC1AsOptions.td
index 9fd855a..2749bcd 100644
--- a/include/clang/Driver/CC1AsOptions.td
+++ b/include/clang/Driver/CC1AsOptions.td
@@ -37,6 +37,8 @@ def L : Flag<["-"], "L">,
HelpText<"Save temporary labels in the symbol table. "
"Note this may change .s semantics, it should almost never be used "
"on compiler generated code!">;
+def main_file_name : Separate<["-"], "main-file-name">,
+ HelpText<"Main file name to use for debug info">;
//===----------------------------------------------------------------------===//
// Frontend Options
@@ -86,5 +88,11 @@ def fatal_warnings : Flag<["--"], "fatal-warnings">,
def g : Flag<["-"], "g">, HelpText<"Generate source level debug information">;
+def fdebug_compilation_dir : Separate<["-"], "fdebug-compilation-dir">,
+ HelpText<"The compilation directory to embed in the debug info.">;
+
def dwarf_debug_flags : Separate<["-"], "dwarf-debug-flags">,
HelpText<"The string to embed in the Dwarf debug flags record.">;
+
+def dwarf_debug_producer : Separate<["-"], "dwarf-debug-producer">,
+ HelpText<"The string to embed in the Dwarf debug AT_producer record.">;
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index 3ff2549..e4dd345 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -81,15 +81,6 @@ def analyzer_inline_max_stack_depth : Separate<["-"], "analyzer-inline-max-stack
def analyzer_inline_max_stack_depth_EQ : Joined<["-"], "analyzer-inline-max-stack-depth=">,
Alias<analyzer_inline_max_stack_depth>;
-def analyzer_inline_max_function_size : Separate<["-"], "analyzer-inline-max-function-size">,
- HelpText<"Bound on the number of basic blocks in an inlined function (200 by default)">;
-def analyzer_inline_max_function_size_EQ : Joined<["-"], "analyzer-inline-max-function-size=">,
- Alias<analyzer_inline_max_function_size>;
-
-def analyzer_ipa : Separate<["-"], "analyzer-ipa">,
- HelpText<"Specify the inter-procedural analysis mode">;
-def analyzer_ipa_EQ : Joined<["-"], "analyzer-ipa=">, Alias<analyzer_ipa>;
-
def analyzer_inlining_mode : Separate<["-"], "analyzer-inlining-mode">,
HelpText<"Specify the function selection heuristic used during inlining">;
def analyzer_inlining_mode_EQ : Joined<["-"], "analyzer-inlining-mode=">, Alias<analyzer_inlining_mode>;
@@ -97,8 +88,6 @@ def analyzer_inlining_mode_EQ : Joined<["-"], "analyzer-inlining-mode=">, Alias<
def analyzer_disable_retry_exhausted : Flag<["-"], "analyzer-disable-retry-exhausted">,
HelpText<"Do not re-analyze paths leading to exhausted nodes with a different strategy (may decrease code coverage)">;
-def analyzer_max_nodes : Separate<["-"], "analyzer-max-nodes">,
- HelpText<"The maximum number of nodes the analyzer can generate (150000 default, 0 = no limit)">;
def analyzer_max_loop : Separate<["-"], "analyzer-max-loop">,
HelpText<"The maximum number of times the analyzer will go through a loop">;
def analyzer_stats : Flag<["-"], "analyzer-stats">,
@@ -145,6 +134,8 @@ def dwarf_debug_flags : Separate<["-"], "dwarf-debug-flags">,
HelpText<"The string to embed in the Dwarf debug flags record.">;
def dwarf_column_info : Flag<["-"], "dwarf-column-info">,
HelpText<"Turn on column location information.">;
+def split_dwarf : Flag<["-"], "split-dwarf">,
+ HelpText<"Split out the dwarf .dwo sections">;
def fforbid_guard_variables : Flag<["-"], "fforbid-guard-variables">,
HelpText<"Emit an error if a C++ static local initializer would need a guard variable">;
def no_implicit_float : Flag<["-"], "no-implicit-float">,
@@ -158,10 +149,20 @@ def femit_coverage_data: Flag<["-"], "femit-coverage-data">,
def coverage_file : Separate<["-"], "coverage-file">,
HelpText<"Emit coverage data to this filename. The extension will be replaced.">;
def coverage_file_EQ : Joined<["-"], "coverage-file=">, Alias<coverage_file>;
+def coverage_cfg_checksum : Flag<["-"], "coverage-cfg-checksum">,
+ HelpText<"Emit CFG checksum for functions in .gcno files.">;
+def coverage_no_function_names_in_data : Flag<["-"], "coverage-no-function-names-in-data">,
+ HelpText<"Emit function names in .gcda files.">;
+def coverage_version_EQ : Joined<["-"], "coverage-version=">,
+ HelpText<"Four-byte version string for gcov files.">;
+def test_coverage : Flag<["-"], "test-coverage">,
+ HelpText<"Do not generate coverage files or remove coverage changes from IR">;
def fuse_register_sized_bitfield_access: Flag<["-"], "fuse-register-sized-bitfield-access">,
HelpText<"Use register sized accesses to bit-fields, when possible.">;
def relaxed_aliasing : Flag<["-"], "relaxed-aliasing">,
HelpText<"Turn off Type Based Alias Analysis">;
+def struct_path_tbaa : Flag<["-"], "struct-path-tbaa">,
+ HelpText<"Turn on struct-path aware Type Based Alias Analysis">;
def masm_verbose : Flag<["-"], "masm-verbose">,
HelpText<"Generate verbose assembly output">;
def mcode_model : Separate<["-"], "mcode-model">,
@@ -185,6 +186,8 @@ def mlimit_float_precision : Separate<["-"], "mlimit-float-precision">,
HelpText<"Limit float precision to the given value">;
def mno_exec_stack : Flag<["-"], "mnoexecstack">,
HelpText<"Mark the file as not needing an executable stack">;
+def split_stacks : Flag<["-"], "split-stacks">,
+ HelpText<"Try to use a split stack if possible.">;
def mno_zero_initialized_in_bss : Flag<["-"], "mno-zero-initialized-in-bss">,
HelpText<"Do not put zero initialized data in the BSS">;
def backend_option : Separate<["-"], "backend-option">,
@@ -197,8 +200,6 @@ def mrelocation_model : Separate<["-"], "mrelocation-model">,
HelpText<"The relocation model to use">;
def munwind_tables : Flag<["-"], "munwind-tables">,
HelpText<"Generate unwinding tables for all functions">;
-def fuse_init_array : Flag<["-"], "fuse-init-array">,
- HelpText<"Use .init_array instead of .ctors">;
def mconstructor_aliases : Flag<["-"], "mconstructor-aliases">,
HelpText<"Emit complete constructors and destructors as aliases when possible">;
def mlink_bitcode_file : Separate<["-"], "mlink-bitcode-file">,
@@ -217,9 +218,6 @@ def header_include_file : Separate<["-"], "header-include-file">,
// Diagnostic Options
//===----------------------------------------------------------------------===//
-def dump_build_information : Separate<["-"], "dump-build-information">,
- MetaVarName<"<filename>">,
- HelpText<"output a dump of some build information to a file">;
def diagnostic_log_file : Separate<["-"], "diagnostic-log-file">,
HelpText<"Filename (or -) to log diagnostics to">;
def diagnostic_serialized_file : Separate<["-"], "serialize-diagnostic-file">,
@@ -230,6 +228,8 @@ def fdiagnostics_format : Separate<["-"], "fdiagnostics-format">,
HelpText<"Change diagnostic formatting to match IDE and command line tools">;
def fdiagnostics_show_category : Separate<["-"], "fdiagnostics-show-category">,
HelpText<"Print diagnostic category">;
+def fno_diagnostics_use_presumed_location : Flag<["-"], "fno-diagnostics-use-presumed-location">,
+ HelpText<"Ignore #line directives when displaying diagnostic locations">;
def ftabstop : Separate<["-"], "ftabstop">, MetaVarName<"<N>">,
HelpText<"Set the tab stop distance.">;
def ferror_limit : Separate<["-"], "ferror-limit">, MetaVarName<"<N>">,
@@ -245,6 +245,9 @@ def fmessage_length : Separate<["-"], "fmessage-length">, MetaVarName<"<N>">,
def Wno_rewrite_macros : Flag<["-"], "Wno-rewrite-macros">,
HelpText<"Silence ObjC rewriting warnings">;
+def fwarn_on_spellcheck : Flag<["-"], "fwarn-on-spellcheck">,
+ HelpText<"Emit warning if spell-check is initiated, for testing">;
+
//===----------------------------------------------------------------------===//
// Frontend Options
//===----------------------------------------------------------------------===//
@@ -283,8 +286,6 @@ def plugin_arg : JoinedAndSeparate<["-"], "plugin-arg-">,
HelpText<"Pass <arg> to plugin <name>">;
def add_plugin : Separate<["-"], "add-plugin">, MetaVarName<"<name>">,
HelpText<"Use the named plugin action in addition to the default action">;
-def resource_dir : Separate<["-"], "resource-dir">,
- HelpText<"The directory which holds the compiler resource files">;
def version : Flag<["-"], "version">,
HelpText<"Print the compiler version">;
def ast_dump_filter : Separate<["-"], "ast-dump-filter">,
@@ -292,6 +293,8 @@ def ast_dump_filter : Separate<["-"], "ast-dump-filter">,
HelpText<"Use with -ast-dump or -ast-print to dump/print only AST declaration"
" nodes having a certain substring in a qualified name. Use"
" -ast-list to list all filterable declaration node names.">;
+def fno_modules_global_index : Flag<["-"], "fno-modules-global-index">,
+ HelpText<"Do not automatically generate or update the global module index">;
let Group = Action_Group in {
@@ -389,6 +392,8 @@ def fhidden_weak_vtables : Flag<["-"], "fhidden-weak-vtables">,
HelpText<"Generate weak vtables and RTTI with hidden visibility">;
def main_file_name : Separate<["-"], "main-file-name">,
HelpText<"Main file name to use for debug info">;
+def split_dwarf_file : Separate<["-"], "split-dwarf-file">,
+ HelpText<"File name to use for split dwarf debug info output">;
def fno_signed_char : Flag<["-"], "fno-signed-char">,
HelpText<"Char is unsigned">;
def fno_wchar : Flag<["-"], "fno-wchar">,
@@ -425,11 +430,15 @@ def stack_protector : Separate<["-"], "stack-protector">,
def stack_protector_buffer_size : Separate<["-"], "stack-protector-buffer-size">,
HelpText<"Lower bound for a buffer to be considered for stack protection">;
def fvisibility : Separate<["-"], "fvisibility">,
- HelpText<"Default symbol visibility">;
+ HelpText<"Default type and symbol visibility">;
+def ftype_visibility : Separate<["-"], "ftype-visibility">,
+ HelpText<"Default type visibility">;
def ftemplate_depth : Separate<["-"], "ftemplate-depth">,
HelpText<"Maximum depth of recursive template instantiation">;
def fconstexpr_depth : Separate<["-"], "fconstexpr-depth">,
HelpText<"Maximum depth of recursive constexpr function calls">;
+def fbracket_depth : Separate<["-"], "fbracket-depth">,
+ HelpText<"Maximum nesting level for parentheses, brackets, and braces">;
def fconst_strings : Flag<["-"], "fconst-strings">,
HelpText<"Use a const qualified type for string literals in C and ObjC">;
def fno_const_strings : Flag<["-"], "fno-const-strings">,
diff --git a/include/clang/Driver/Compilation.h b/include/clang/Driver/Compilation.h
index 5f63aa7..15c5e40 100644
--- a/include/clang/Driver/Compilation.h
+++ b/include/clang/Driver/Compilation.h
@@ -20,6 +20,7 @@ namespace driver {
class DerivedArgList;
class Driver;
class InputArgList;
+ class JobAction;
class JobList;
class ToolChain;
@@ -54,11 +55,11 @@ class Compilation {
ArgStringList TempFiles;
/// Result files which should be removed on failure.
- ArgStringList ResultFiles;
+ ArgStringMap ResultFiles;
/// Result files which are generated correctly on failure, and which should
/// only be removed if we crash.
- ArgStringList FailureResultFiles;
+ ArgStringMap FailureResultFiles;
/// Redirection for stdout, stderr, etc.
const llvm::sys::Path **Redirects;
@@ -88,9 +89,9 @@ public:
const ArgStringList &getTempFiles() const { return TempFiles; }
- const ArgStringList &getResultFiles() const { return ResultFiles; }
+ const ArgStringMap &getResultFiles() const { return ResultFiles; }
- const ArgStringList &getFailureResultFiles() const {
+ const ArgStringMap &getFailureResultFiles() const {
return FailureResultFiles;
}
@@ -113,24 +114,40 @@ public:
/// addResultFile - Add a file to remove on failure, and returns its
/// argument.
- const char *addResultFile(const char *Name) {
- ResultFiles.push_back(Name);
+ const char *addResultFile(const char *Name, const JobAction *JA) {
+ ResultFiles[JA] = Name;
return Name;
}
/// addFailureResultFile - Add a file to remove if we crash, and returns its
/// argument.
- const char *addFailureResultFile(const char *Name) {
- FailureResultFiles.push_back(Name);
+ const char *addFailureResultFile(const char *Name, const JobAction *JA) {
+ FailureResultFiles[JA] = Name;
return Name;
}
+ /// CleanupFile - Delete a given file.
+ ///
+ /// \param IssueErrors - Report failures as errors.
+ /// \return Whether the file was removed successfully.
+ bool CleanupFile(const char *File, bool IssueErrors = false) const;
+
/// CleanupFileList - Remove the files in the given list.
///
/// \param IssueErrors - Report failures as errors.
/// \return Whether all files were removed successfully.
bool CleanupFileList(const ArgStringList &Files,
- bool IssueErrors=false) const;
+ bool IssueErrors = false) const;
+
+ /// CleanupFileMap - Remove the files in the given map.
+ ///
+ /// \param JA - If specified, only delete the files associated with this
+ /// JobAction. Otherwise, delete all files in the map.
+ /// \param IssueErrors - Report failures as errors.
+ /// \return Whether all files were removed successfully.
+ bool CleanupFileMap(const ArgStringMap &Files,
+ const JobAction *JA,
+ bool IssueErrors = false) const;
/// PrintJob - Print one job in -### format.
///
@@ -158,10 +175,10 @@ public:
/// ExecuteJob - Execute a single job.
///
- /// \param FailingCommand - For non-zero results, this will be set to the
- /// Command which failed.
- /// \return The accumulated result code of the job.
- int ExecuteJob(const Job &J, const Command *&FailingCommand) const;
+ /// \param FailingCommands - For non-zero results, this will be a vector of
+ /// failing commands and their associated result code.
+ void ExecuteJob(const Job &J,
+ SmallVectorImpl< std::pair<int, const Command *> > &FailingCommands) const;
/// initCompilationForDiagnostics - Remove stale state and suppress output
/// so compilation can be reexecuted to generate additional diagnostic
diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h
index b752ce6..1330e95 100644
--- a/include/clang/Driver/Driver.h
+++ b/include/clang/Driver/Driver.h
@@ -11,11 +11,10 @@
#define CLANG_DRIVER_DRIVER_H_
#include "clang/Basic/Diagnostic.h"
-
+#include "clang/Basic/LLVM.h"
#include "clang/Driver/Phases.h"
#include "clang/Driver/Types.h"
#include "clang/Driver/Util.h"
-
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
@@ -25,9 +24,6 @@
#include <set>
#include <string>
-namespace llvm {
- template<typename T> class ArrayRef;
-}
namespace clang {
namespace driver {
class Action;
@@ -178,7 +174,6 @@ public:
Driver(StringRef _ClangExecutable,
StringRef _DefaultTargetTriple,
StringRef _DefaultImageName,
- bool IsProduction,
DiagnosticsEngine &_Diags);
~Driver();
@@ -277,7 +272,7 @@ public:
/// to just running the subprocesses, for example reporting errors, removing
/// temporary files, etc.
int ExecuteCompilation(const Compilation &C,
- const Command *&FailingCommand) const;
+ SmallVectorImpl< std::pair<int, const Command *> > &FailingCommands) const;
/// generateCompilationDiagnostics - Generate diagnostics information
/// including preprocessed source file(s).
@@ -363,10 +358,9 @@ public:
/// GCC goes to extra lengths here to be a bit more robust.
std::string GetTemporaryPath(StringRef Prefix, const char *Suffix) const;
- /// ShouldUseClangCompilar - Should the clang compiler be used to
+ /// ShouldUseClangCompiler - Should the clang compiler be used to
/// handle this action.
- bool ShouldUseClangCompiler(const Compilation &C, const JobAction &JA,
- const llvm::Triple &ArchName) const;
+ bool ShouldUseClangCompiler(const JobAction &JA) const;
bool IsUsingLTO(const ArgList &Args) const;
diff --git a/include/clang/Driver/Job.h b/include/clang/Driver/Job.h
index 84f5ee1..045b5d8 100644
--- a/include/clang/Driver/Job.h
+++ b/include/clang/Driver/Job.h
@@ -10,9 +10,9 @@
#ifndef CLANG_DRIVER_JOB_H_
#define CLANG_DRIVER_JOB_H_
+#include "clang/Basic/LLVM.h"
#include "clang/Driver/Util.h"
#include "llvm/ADT/SmallVector.h"
-#include "clang/Basic/LLVM.h"
namespace clang {
namespace driver {
diff --git a/include/clang/Driver/OptSpecifier.h b/include/clang/Driver/OptSpecifier.h
index bb1cd17..e683ef3 100644
--- a/include/clang/Driver/OptSpecifier.h
+++ b/include/clang/Driver/OptSpecifier.h
@@ -10,6 +10,8 @@
#ifndef CLANG_DRIVER_OPTSPECIFIER_H
#define CLANG_DRIVER_OPTSPECIFIER_H
+#include "llvm/Support/Compiler.h"
+
namespace clang {
namespace driver {
class Option;
@@ -19,7 +21,7 @@ namespace driver {
unsigned ID;
private:
- explicit OptSpecifier(bool); // DO NOT IMPLEMENT
+ explicit OptSpecifier(bool) LLVM_DELETED_FUNCTION;
public:
OptSpecifier() : ID(0) {}
diff --git a/include/clang/Driver/Option.h b/include/clang/Driver/Option.h
index c3db773..764934f 100644
--- a/include/clang/Driver/Option.h
+++ b/include/clang/Driver/Option.h
@@ -10,10 +10,10 @@
#ifndef CLANG_DRIVER_OPTION_H_
#define CLANG_DRIVER_OPTION_H_
+#include "clang/Basic/LLVM.h"
#include "clang/Driver/OptTable.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ErrorHandling.h"
-#include "clang/Basic/LLVM.h"
namespace clang {
namespace driver {
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 77ba17a..112feb7 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -152,7 +152,8 @@ def E : Flag<["-"], "E">, Flags<[DriverOption,CC1Option]>, Group<Action_Group>,
HelpText<"Only run the preprocessor">;
def F : JoinedOrSeparate<["-"], "F">, Flags<[RenderJoined,CC1Option]>,
HelpText<"Add directory to framework include search path">;
-def G : Separate<["-"], "G">, Flags<[DriverOption]>;
+def G : JoinedOrSeparate<["-"], "G">, Flags<[DriverOption]>;
+def G_EQ : Joined<["-"], "G=">, Flags<[DriverOption]>;
def H : Flag<["-"], "H">, Flags<[CC1Option]>,
HelpText<"Show header includes and nesting depth">;
def I_ : Flag<["-"], "I-">, Group<I_Group>;
@@ -290,6 +291,7 @@ def faccess_control : Flag<["-"], "faccess-control">, Group<f_Group>;
def fallow_unsupported : Flag<["-"], "fallow-unsupported">, Group<f_Group>;
def faltivec : Flag<["-"], "faltivec">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Enable AltiVec vector initializer syntax">;
+def fno_altivec : Flag<["-"], "fno-altivec">, Group<f_Group>, Flags<[CC1Option]>;
def fapple_kext : Flag<["-"], "fapple-kext">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Use Apple's kernel extensions ABI">;
def fapple_pragma_pack : Flag<["-"], "fapple-pragma-pack">, Group<f_Group>, Flags<[CC1Option]>,
@@ -300,7 +302,7 @@ def fthread_sanitizer : Flag<["-"], "fthread-sanitizer">, Group<f_Group>;
def fno_thread_sanitizer : Flag<["-"], "fno-thread-sanitizer">, Group<f_Group>;
def fasm : Flag<["-"], "fasm">, Group<f_Group>;
-def fasm_blocks : Flag<["-"], "fasm-blocks">, Group<f_Group>;
+def fasm_blocks : Flag<["-"], "fasm-blocks">, Group<f_Group>, Flags<[CC1Option]>;
def fno_asm_blocks : Flag<["-"], "fno-asm-blocks">, Group<f_Group>;
def fassume_sane_operator_new : Flag<["-"], "fassume-sane-operator-new">, Group<f_Group>;
@@ -325,6 +327,9 @@ def fcatch_undefined_behavior : Flag<["-"], "fcatch-undefined-behavior">, Group<
def fclasspath_EQ : Joined<["-"], "fclasspath=">, Group<f_Group>;
def fcolor_diagnostics : Flag<["-"], "fcolor-diagnostics">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Use colors in diagnostics">;
+def fcomment_block_commands : CommaJoined<["-"], "fcomment-block-commands=">, Group<f_clang_Group>, Flags<[CC1Option]>,
+ HelpText<"Treat each comma separated argument in <arg> as a documentation comment block command">,
+ MetaVarName<"<arg>">;
def fcommon : Flag<["-"], "fcommon">, Group<f_Group>;
def fcompile_resource_EQ : Joined<["-"], "fcompile-resource=">, Group<f_Group>;
def fconstant_cfstrings : Flag<["-"], "fconstant-cfstrings">, Group<f_Group>;
@@ -374,6 +379,10 @@ def ferror_limit_EQ : Joined<["-"], "ferror-limit=">, Group<f_Group>;
def fexceptions : Flag<["-"], "fexceptions">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Enable support for exception handling">;
def fextdirs_EQ : Joined<["-"], "fextdirs=">, Group<f_Group>;
+def fextended_identifiers : Flag<["-"], "fextended-identifiers">,
+ Group<clang_ignored_f_Group>;
+def fno_extended_identifiers : Flag<["-"], "fno-extended-identifiers">,
+ Group<f_Group>, Flags<[Unsupported]>;
def fhosted : Flag<["-"], "fhosted">, Group<f_Group>;
def ffast_math : Flag<["-"], "ffast-math">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Enable the *frontend*'s 'fast-math' mode. This has no effect on "
@@ -383,6 +392,7 @@ def fno_fast_math : Flag<["-"], "fno-fast-math">, Group<f_Group>;
def fmath_errno : Flag<["-"], "fmath-errno">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Require math functions to indicate errors by setting errno">;
def fno_math_errno : Flag<["-"], "fno-math-errno">, Group<f_Group>;
+def fbracket_depth_EQ : Joined<["-"], "fbracket-depth=">, Group<f_Group>;
def fsignaling_math : Flag<["-"], "fsignaling-math">, Group<f_Group>;
def fno_signaling_math : Flag<["-"], "fno-signaling-math">, Group<f_Group>;
def fsanitize_EQ : CommaJoined<["-"], "fsanitize=">, Group<f_clang_Group>,
@@ -391,6 +401,32 @@ def fsanitize_EQ : CommaJoined<["-"], "fsanitize=">, Group<f_clang_Group>,
"address (memory errors) | thread (race detection) | "
"undefined (miscellaneous undefined behavior)">;
def fno_sanitize_EQ : CommaJoined<["-"], "fno-sanitize=">, Group<f_clang_Group>;
+def fsanitize_address_zero_base_shadow : Flag<["-"], "fsanitize-address-zero-base-shadow">,
+ Group<f_clang_Group>, Flags<[CC1Option]>,
+ HelpText<"Make AddressSanitizer map shadow memory"
+ "at zero offset">;
+def fno_sanitize_address_zero_base_shadow : Flag<["-"], "fno-sanitize-address-zero-base-shadow">,
+ Group<f_clang_Group>;
+def fsanitize_blacklist : Joined<["-"], "fsanitize-blacklist=">,
+ Group<f_clang_Group>, Flags<[CC1Option]>,
+ HelpText<"Path to blacklist file for sanitizers">;
+def fno_sanitize_blacklist : Flag<["-"], "fno-sanitize-blacklist">,
+ Group<f_clang_Group>,
+ HelpText<"Don't use blacklist file for sanitizers">;
+def fsanitize_memory_track_origins : Flag<["-"], "fsanitize-memory-track-origins">,
+ Group<f_clang_Group>, Flags<[CC1Option]>,
+ HelpText<"Enable origins tracking in MemorySanitizer">;
+def fno_sanitize_memory_track_origins : Flag<["-"], "fno-sanitize-memory-track-origins">,
+ Group<f_clang_Group>;
+def fsanitize_recover : Flag<["-"], "fsanitize-recover">,
+ Group<f_clang_Group>;
+def fno_sanitize_recover : Flag<["-"], "fno-sanitize-recover">,
+ Group<f_clang_Group>, Flags<[CC1Option]>,
+ HelpText<"Disable sanitizer check recovery">;
+def fsanitize_undefined_trap_on_error : Flag<["-"], "fsanitize-undefined-trap-on-error">,
+ Group<f_clang_Group>, Flags<[CC1Option]>;
+def fno_sanitize_undefined_trap_on_error : Flag<["-"], "fno-sanitize-undefined-trap-on-error">,
+ Group<f_clang_Group>;
def funsafe_math_optimizations : Flag<["-"], "funsafe-math-optimizations">,
Group<f_Group>;
def fno_unsafe_math_optimizations : Flag<["-"], "fno-unsafe-math-optimizations">,
@@ -453,8 +489,6 @@ def fmerge_all_constants : Flag<["-"], "fmerge-all-constants">, Group<f_Group>;
def fmessage_length_EQ : Joined<["-"], "fmessage-length=">, Group<f_Group>;
def fms_extensions : Flag<["-"], "fms-extensions">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Accept some non-standard constructs supported by the Microsoft compiler">;
-def fenable_experimental_ms_inline_asm : Flag<["-"], "fenable-experimental-ms-inline-asm">, Group<f_Group>, Flags<[CC1Option]>,
- HelpText<"Enable support for Microsoft style inine assembly">;
def fms_compatibility : Flag<["-"], "fms-compatibility">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Enable Microsoft compatibility mode">;
def fmsc_version : Joined<["-"], "fmsc-version=">, Group<f_Group>, Flags<[CC1Option]>,
@@ -462,11 +496,23 @@ def fmsc_version : Joined<["-"], "fmsc-version=">, Group<f_Group>, Flags<[CC1Opt
def fdelayed_template_parsing : Flag<["-"], "fdelayed-template-parsing">, Group<f_Group>,
HelpText<"Parse templated function definitions at the end of the "
"translation unit ">, Flags<[CC1Option]>;
-def fmodule_cache_path : Separate<["-"], "fmodule-cache-path">, Group<i_Group>,
+def fmodules_cache_path : Joined<["-"], "fmodules-cache-path=">, Group<i_Group>,
Flags<[NoForward,CC1Option]>, MetaVarName<"<directory>">,
HelpText<"Specify the module cache path">;
+def fmodules_prune_interval : Joined<["-"], "fmodules-prune-interval=">, Group<i_Group>,
+ Flags<[CC1Option]>, MetaVarName<"<seconds>">,
+ HelpText<"Specify the interval (in seconds) between attempts to prune the module cache">;
+def fmodules_prune_after : Joined<["-"], "fmodules-prune-after=">, Group<i_Group>,
+ Flags<[CC1Option]>, MetaVarName<"<seconds>">,
+ HelpText<"Specify the interval (in seconds) after which a module file will be considered unused">;
def fmodules : Flag <["-"], "fmodules">, Group<f_Group>, Flags<[NoForward,CC1Option]>,
HelpText<"Enable the 'modules' language feature">;
+def fmodules_autolink : Flag <["-"], "fmodules-autolink">, Group<f_Group>, Flags<[NoForward,CC1Option]>,
+ HelpText<"Enable autolinking of the libraries for imported modules">;
+def fno_modules_autolink : Flag <["-"], "fno-modules-autolink">, Group<f_Group>,
+ HelpText<"Disable autolinking of the libraries for imported modules">;
+def fmodules_ignore_macro : Joined<["-"], "fmodules-ignore-macro=">, Group<f_Group>, Flags<[CC1Option]>,
+ HelpText<"Ignore the definition of the given macro when building and loading modules">;
def fretain_comments_from_system_headers : Flag<["-"], "fretain-comments-from-system-headers">, Group<f_Group>, Flags<[CC1Option]>;
def fmudflapth : Flag<["-"], "fmudflapth">, Group<f_Group>;
@@ -541,12 +587,15 @@ def fno_spell_checking : Flag<["-"], "fno-spell-checking">, Group<f_Group>,
Flags<[CC1Option]>, HelpText<"Disable spell-checking">;
def fno_stack_protector : Flag<["-"], "fno-stack-protector">, Group<f_Group>;
def fno_strict_aliasing : Flag<["-"], "fno-strict-aliasing">, Group<f_Group>;
+def fstruct_path_tbaa : Flag<["-"], "fstruct-path-tbaa">, Group<f_Group>;
def fno_strict_enums : Flag<["-"], "fno-strict-enums">, Group<f_Group>;
def fno_strict_overflow : Flag<["-"], "fno-strict-overflow">, Group<f_Group>;
def fno_threadsafe_statics : Flag<["-"], "fno-threadsafe-statics">, Group<f_Group>,
Flags<[CC1Option]>, HelpText<"Do not emit code to make initialization of local statics thread safe">;
def fno_use_cxa_atexit : Flag<["-"], "fno-use-cxa-atexit">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Don't use __cxa_atexit for calling destructors">;
+def fno_use_init_array : Flag<["-"], "fno-use-init-array">, Group<f_Group>, Flags<[CC1Option]>,
+ HelpText<"Don't use .init_array instead of .ctors">;
def fno_unit_at_a_time : Flag<["-"], "fno-unit-at-a-time">, Group<f_Group>;
def fno_unwind_tables : Flag<["-"], "fno-unwind-tables">, Group<f_Group>;
def fno_verbose_asm : Flag<["-"], "fno-verbose-asm">, Group<f_Group>;
@@ -590,7 +639,7 @@ def fno_objc_nonfragile_abi : Flag<["-"], "fno-objc-nonfragile-abi">, Group<f_Gr
def fobjc_sender_dependent_dispatch : Flag<["-"], "fobjc-sender-dependent-dispatch">, Group<f_Group>;
def fobjc : Flag<["-"], "fobjc">, Group<f_Group>;
def fomit_frame_pointer : Flag<["-"], "fomit-frame-pointer">, Group<f_Group>;
-def fopenmp : Flag<["-"], "fopenmp">, Group<f_Group>;
+def fopenmp : Flag<["-"], "fopenmp">, Group<f_Group>, Flags<[CC1Option]>;
def fno_optimize_sibling_calls : Flag<["-"], "fno-optimize-sibling-calls">, Group<f_Group>;
def foptimize_sibling_calls : Flag<["-"], "foptimize-sibling-calls">, Group<f_Group>;
def force__cpusubtype__ALL : Flag<["-"], "force_cpusubtype_ALL">;
@@ -627,6 +676,7 @@ def fshow_source_location : Flag<["-"], "fshow-source-location">, Group<f_Group>
def fspell_checking : Flag<["-"], "fspell-checking">, Group<f_Group>;
def fsigned_bitfields : Flag<["-"], "fsigned-bitfields">, Group<f_Group>;
def fsigned_char : Flag<["-"], "fsigned-char">, Group<f_Group>;
+def fsplit_stack : Flag<["-"], "fsplit-stack">, Group<f_Group>;
def fstack_protector_all : Flag<["-"], "fstack-protector-all">, Group<f_Group>;
def fstack_protector : Flag<["-"], "fstack-protector">, Group<f_Group>;
def fstrict_aliasing : Flag<["-"], "fstrict-aliasing">, Group<f_Group>;
@@ -641,6 +691,16 @@ def ftemplate_depth_ : Joined<["-"], "ftemplate-depth-">, Group<f_Group>;
def ftemplate_backtrace_limit_EQ : Joined<["-"], "ftemplate-backtrace-limit=">,
Group<f_Group>;
def ftest_coverage : Flag<["-"], "ftest-coverage">, Group<f_Group>;
+def fvectorize : Flag<["-"], "fvectorize">, Group<f_Group>,
+ HelpText<"Enable the loop vectorization passes">;
+def fno_vectorize : Flag<["-"], "fno-vectorize">, Group<f_Group>;
+def ftree_vectorize : Flag<["-"], "ftree-vectorize">, Alias<fvectorize>;
+def fno_tree_vectorize : Flag<["-"], "fno-tree-vectorize">, Alias<fno_vectorize>;
+def fslp_vectorize : Flag<["-"], "fslp-vectorize">, Group<f_Group>,
+ HelpText<"Enable the superword-level parallelism vectorization passes">;
+def fno_slp_vectorize : Flag<["-"], "fno-slp-vectorize">, Group<f_Group>;
+def ftree_slp_vectorize : Flag<["-"], "ftree-slp-vectorize">, Alias<fslp_vectorize>;
+def fno_tree_slp_vectorize : Flag<["-"], "fno-tree-slp-vectorize">, Alias<fno_slp_vectorize>;
def Wlarge_by_value_copy_def : Flag<["-"], "Wlarge-by-value-copy">,
HelpText<"Warn if a function definition returns or accepts an object larger "
"in bytes than a given value">, Flags<[HelpHidden]>;
@@ -672,11 +732,17 @@ def funsigned_bitfields : Flag<["-"], "funsigned-bitfields">, Group<f_Group>;
def funsigned_char : Flag<["-"], "funsigned-char">, Group<f_Group>;
def funwind_tables : Flag<["-"], "funwind-tables">, Group<f_Group>;
def fuse_cxa_atexit : Flag<["-"], "fuse-cxa-atexit">, Group<f_Group>;
+def fuse_init_array : Flag<["-"], "fuse-init-array">, Group<f_Group>, Flags<[CC1Option]>,
+ HelpText<"Use .init_array instead of .ctors">;
def fverbose_asm : Flag<["-"], "fverbose-asm">, Group<f_Group>;
-def fvisibility_EQ : Joined<["-"], "fvisibility=">, Group<f_Group>;
+def fvisibility_EQ : Joined<["-"], "fvisibility=">, Group<f_Group>,
+ HelpText<"Set the default symbol visibility for all global declarations">;
def fvisibility_inlines_hidden : Flag<["-"], "fvisibility-inlines-hidden">, Group<f_Group>,
HelpText<"Give inline C++ member functions default visibility by default">,
Flags<[CC1Option]>;
+def fvisibility_ms_compat : Flag<["-"], "fvisibility-ms-compat">, Group<f_Group>,
+ HelpText<"Give global types 'default' visibility and global functions and "
+ "variables 'hidden' visibility by default">;
def fwrapv : Flag<["-"], "fwrapv">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Treat signed integer overflow as two's complement">;
def fwritable_strings : Flag<["-"], "fwritable-strings">, Group<f_Group>, Flags<[CC1Option]>,
@@ -716,6 +782,7 @@ def gno_record_gcc_switches : Flag<["-"], "gno-record-gcc-switches">,
def gstrict_dwarf : Flag<["-"], "gstrict-dwarf">, Group<g_flags_Group>;
def gno_strict_dwarf : Flag<["-"], "gno-strict-dwarf">, Group<g_flags_Group>;
def gcolumn_info : Flag<["-"], "gcolumn-info">, Group<g_flags_Group>;
+def gsplit_dwarf : Flag<["-"], "gsplit-dwarf">, Group<g_flags_Group>;
def headerpad__max__install__names : Joined<["-"], "headerpad_max_install_names">;
def help : Flag<["-", "--"], "help">, Flags<[CC1Option]>,
HelpText<"Display available options">;
@@ -757,6 +824,8 @@ def keep__private__externs : Flag<["-"], "keep_private_externs">;
def l : JoinedOrSeparate<["-"], "l">, Flags<[LinkerInput, RenderJoined]>;
def lazy__framework : Separate<["-"], "lazy_framework">, Flags<[LinkerInput]>;
def lazy__library : Separate<["-"], "lazy_library">, Flags<[LinkerInput]>;
+def EL : Flag<["-"], "EL">, Flags<[DriverOption]>;
+def EB : Flag<["-"], "EB">, Flags<[DriverOption]>;
def m32 : Flag<["-"], "m32">, Group<m_Group>, Flags<[DriverOption]>;
def mqdsp6_compat : Flag<["-"], "mqdsp6-compat">, Group<m_Group>, Flags<[DriverOption,CC1Option]>,
HelpText<"Enable hexagon-qdsp6 backward compatibility">;
@@ -766,6 +835,15 @@ def m64 : Flag<["-"], "m64">, Group<m_Group>, Flags<[DriverOption]>;
def mabi_EQ : Joined<["-"], "mabi=">, Group<m_Group>;
def march_EQ : Joined<["-"], "march=">, Group<m_Group>;
def maltivec : Flag<["-"], "maltivec">, Alias<faltivec>;
+def mno_altivec : Flag<["-"], "mno-altivec">, Alias<fno_altivec>;
+def mfprnd : Flag<["-"], "mfprnd">, Group<m_Group>;
+def mno_fprnd : Flag<["-"], "mno-fprnd">, Group<m_Group>;
+def mmfcrf : Flag<["-"], "mmfcrf">, Group<m_Group>;
+def mno_mfcrf : Flag<["-"], "mno-mfcrf">, Group<m_Group>;
+def mpopcntd : Flag<["-"], "mpopcntd">, Group<m_Group>;
+def mno_popcntd : Flag<["-"], "mno-popcntd">, Group<m_Group>;
+def mqpx : Flag<["-"], "mqpx">, Group<m_Group>;
+def mno_qpx : Flag<["-"], "mno-qpx">, Group<m_Group>;
def mcmodel_EQ : Joined<["-"], "mcmodel=">, Group<m_Group>;
def mconstant_cfstrings : Flag<["-"], "mconstant-cfstrings">, Group<clang_ignored_m_Group>;
def mcpu_EQ : Joined<["-"], "mcpu=">, Group<m_Group>;
@@ -827,6 +905,8 @@ def mno_fma : Flag<["-"], "mno-fma">, Group<m_x86_Features_Group>;
def mno_xop : Flag<["-"], "mno-xop">, Group<m_x86_Features_Group>;
def mno_f16c : Flag<["-"], "mno-f16c">, Group<m_x86_Features_Group>;
def mno_rtm : Flag<["-"], "mno-rtm">, Group<m_x86_Features_Group>;
+def mno_prfchw : Flag<["-"], "mno-prfchw">, Group<m_x86_Features_Group>;
+def mno_rdseed : Flag<["-"], "mno-rdseed">, Group<m_x86_Features_Group>;
def mno_thumb : Flag<["-"], "mno-thumb">, Group<m_Group>;
def marm : Flag<["-"], "marm">, Alias<mno_thumb>;
@@ -835,6 +915,7 @@ def mno_warn_nonportable_cfstrings : Flag<["-"], "mno-warn-nonportable-cfstrings
def mno_omit_leaf_frame_pointer : Flag<["-"], "mno-omit-leaf-frame-pointer">, Group<m_Group>;
def momit_leaf_frame_pointer : Flag<["-"], "momit-leaf-frame-pointer">, Group<m_Group>,
HelpText<"Omit frame pointer setup for leaf functions">, Flags<[CC1Option]>;
+def moslib_EQ : Joined<["-"], "moslib=">, Group<m_Group>;
def mpascal_strings : Flag<["-"], "mpascal-strings">, Group<m_Group>;
def mred_zone : Flag<["-"], "mred-zone">, Group<m_Group>;
def mregparm_EQ : Joined<["-"], "mregparm=">, Group<m_Group>;
@@ -869,8 +950,12 @@ def mfma : Flag<["-"], "mfma">, Group<m_x86_Features_Group>;
def mxop : Flag<["-"], "mxop">, Group<m_x86_Features_Group>;
def mf16c : Flag<["-"], "mf16c">, Group<m_x86_Features_Group>;
def mrtm : Flag<["-"], "mrtm">, Group<m_x86_Features_Group>;
+def mprfchw : Flag<["-"], "mprfchw">, Group<m_x86_Features_Group>;
+def mrdseed : Flag<["-"], "mrdseed">, Group<m_x86_Features_Group>;
def mips16 : Flag<["-"], "mips16">, Group<m_Group>;
def mno_mips16 : Flag<["-"], "mno-mips16">, Group<m_Group>;
+def mxgot : Flag<["-"], "mxgot">, Group<m_Group>;
+def mno_xgot : Flag<["-"], "mno-xgot">, Group<m_Group>;
def mdsp : Flag<["-"], "mdsp">, Group<m_Group>;
def mno_dsp : Flag<["-"], "mno-dsp">, Group<m_Group>;
def mdspr2 : Flag<["-"], "mdspr2">, Group<m_Group>;
@@ -883,6 +968,7 @@ def mips64 : Flag<["-"], "mips64">, Group<mips_CPUs_Group>,
HelpText<"Equivalent to -march=mips64">, Flags<[HelpHidden]>;
def mips64r2 : Flag<["-"], "mips64r2">, Group<mips_CPUs_Group>,
HelpText<"Equivalent to -march=mips64r2">, Flags<[HelpHidden]>;
+def module_file_info : Flag<["-"], "module-file-info">, Flags<[DriverOption,CC1Option]>, Group<Action_Group>;
def mthumb : Flag<["-"], "mthumb">, Group<m_Group>;
def mtune_EQ : Joined<["-"], "mtune=">, Group<m_Group>;
def multi__module : Flag<["-"], "multi_module">;
@@ -951,6 +1037,11 @@ def rewrite_objc : Flag<["-"], "rewrite-objc">, Flags<[DriverOption,CC1Option]>,
def rewrite_legacy_objc : Flag<["-"], "rewrite-legacy-objc">, Flags<[DriverOption]>,
HelpText<"Rewrite Legacy Objective-C source to C++">;
def rdynamic : Flag<["-"], "rdynamic">;
+def resource_dir : Separate<["-"], "resource-dir">,
+ Flags<[DriverOption, CC1Option, HelpHidden]>,
+ HelpText<"The directory which holds the compiler resource files">;
+def resource_dir_EQ : Joined<["-"], "resource-dir=">, Flags<[DriverOption]>,
+ Alias<resource_dir>;
def rpath : Separate<["-"], "rpath">, Flags<[LinkerInput]>;
def rtlib_EQ : Joined<["-", "--"], "rtlib=">;
def r : Flag<["-"], "r">;
@@ -1100,7 +1191,7 @@ def _output_class_directory_EQ : Joined<["--"], "output-class-directory=">, Alia
def _output_class_directory : Separate<["--"], "output-class-directory">, Alias<foutput_class_dir_EQ>;
def _output_EQ : Joined<["--"], "output=">, Alias<o>;
def _output : Separate<["--"], "output">, Alias<o>;
-def _param : Separate<["--"], "param">;
+def _param : Separate<["--"], "param">, Group<CompileOnly_Group>;
def _param_EQ : Joined<["--"], "param=">, Alias<_param>;
def _prefix_EQ : Joined<["--"], "prefix=">, Alias<B>;
def _prefix : Separate<["--"], "prefix">, Alias<B>;
diff --git a/include/clang/Driver/Phases.h b/include/clang/Driver/Phases.h
index a0c42ea..4e0f40c 100644
--- a/include/clang/Driver/Phases.h
+++ b/include/clang/Driver/Phases.h
@@ -23,6 +23,10 @@ namespace phases {
Link
};
+ enum {
+ MaxNumberOfPhases = Link + 1
+ };
+
const char *getPhaseName(ID Id);
} // end namespace phases
diff --git a/include/clang/Driver/Tool.h b/include/clang/Driver/Tool.h
index c62e756..4c05d0a 100644
--- a/include/clang/Driver/Tool.h
+++ b/include/clang/Driver/Tool.h
@@ -50,6 +50,7 @@ public:
virtual bool hasIntegratedAssembler() const { return false; }
virtual bool hasIntegratedCPP() const = 0;
virtual bool isLinkJob() const { return false; }
+ virtual bool isDsymutilJob() const { return false; }
/// \brief Does this tool have "good" standardized diagnostics, or should the
/// driver add an additional "command failed" diagnostic on failures.
diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h
index 509e08d..ae9e397 100644
--- a/include/clang/Driver/ToolChain.h
+++ b/include/clang/Driver/ToolChain.h
@@ -10,8 +10,10 @@
#ifndef CLANG_DRIVER_TOOLCHAIN_H_
#define CLANG_DRIVER_TOOLCHAIN_H_
-#include "clang/Driver/Util.h"
+#include "clang/Driver/Action.h"
#include "clang/Driver/Types.h"
+#include "clang/Driver/Util.h"
+#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/Path.h"
@@ -47,6 +49,7 @@ public:
private:
const Driver &D;
const llvm::Triple Triple;
+ const ArgList &Args;
/// The list of toolchain specific path prefixes to search for
/// files.
@@ -56,8 +59,20 @@ private:
/// programs.
path_list ProgramPaths;
+ mutable OwningPtr<Tool> Clang;
+ mutable OwningPtr<Tool> Assemble;
+ mutable OwningPtr<Tool> Link;
+ Tool *getClang() const;
+ Tool *getAssemble() const;
+ Tool *getLink() const;
+ Tool *getClangAs() const;
+
protected:
- ToolChain(const Driver &D, const llvm::Triple &T);
+ ToolChain(const Driver &D, const llvm::Triple &T, const ArgList &Args);
+
+ virtual Tool *buildAssembler() const;
+ virtual Tool *buildLinker() const;
+ virtual Tool *getTool(Action::ActionClass AC) const;
/// \name Utilities for implementing subclasses.
///@{
@@ -111,10 +126,8 @@ public:
return 0;
}
- /// SelectTool - Choose a tool to use to handle the action \p JA with the
- /// given \p Inputs.
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const = 0;
+ /// Choose a tool to use to handle the action \p JA.
+ Tool *SelectTool(const JobAction &JA) const;
// Helper methods
@@ -138,6 +151,9 @@ public:
/// by default.
virtual bool IsIntegratedAssemblerDefault() const { return false; }
+ /// \brief Check if the toolchain should use the integrated assembler.
+ bool useIntegratedAs() const;
+
/// IsStrictAliasingDefault - Does this tool chain use -fstrict-aliasing by
/// default.
virtual bool IsStrictAliasingDefault() const { return true; }
@@ -147,7 +163,7 @@ public:
/// IsObjCDefaultSynthPropertiesDefault - Does this tool chain enable
/// -fobjc-default-synthesize-properties by default.
- virtual bool IsObjCDefaultSynthPropertiesDefault() const { return false; }
+ virtual bool IsObjCDefaultSynthPropertiesDefault() const { return true; }
/// IsEncodeExtendedBlockSignatureDefault - Does this tool chain enable
/// -fencode-extended-block-signature by default.
@@ -233,9 +249,9 @@ public:
virtual void AddClangSystemIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const;
- // addClangTargetOptions - Add options that need to be passed to cc1 for
- // this target.
- virtual void addClangTargetOptions(ArgStringList &CC1Args) const;
+ /// \brief Add options that need to be passed to cc1 for this target.
+ virtual void addClangTargetOptions(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const;
// GetRuntimeLibType - Determine the runtime library type to use with the
// given compilation arguments.
diff --git a/include/clang/Driver/Types.def b/include/clang/Driver/Types.def
index 318c55a..42f0709 100644
--- a/include/clang/Driver/Types.def
+++ b/include/clang/Driver/Types.def
@@ -30,7 +30,7 @@
// The fourth value is the suffix to use when creating temporary files
// of this type, or null if unspecified.
-// The fifth value is a string containt option flags. Valid values:
+// The fifth value is a string containing option flags. Valid values:
// a - The type should only be assembled.
// p - The type should only be precompiled.
// u - The type can be user specified (with -x).
@@ -80,6 +80,7 @@ TYPE("lto-bc", LTO_BC, INVALID, "o", "")
// Misc.
TYPE("ast", AST, INVALID, "ast", "u")
+TYPE("pcm", ModuleFile, INVALID, "pcm", "u")
TYPE("plist", Plist, INVALID, "plist", "")
TYPE("rewritten-objc", RewrittenObjC,INVALID, "cpp", "")
TYPE("rewritten-legacy-objc", RewrittenLegacyObjC,INVALID, "cpp", "")
diff --git a/include/clang/Driver/Types.h b/include/clang/Driver/Types.h
index d28ca88..18cd2d5 100644
--- a/include/clang/Driver/Types.h
+++ b/include/clang/Driver/Types.h
@@ -11,6 +11,7 @@
#define CLANG_DRIVER_TYPES_H_
#include "clang/Driver/Phases.h"
+#include "llvm/ADT/SmallVector.h"
namespace clang {
namespace driver {
@@ -73,14 +74,12 @@ namespace types {
/// specified type name.
ID lookupTypeForTypeSpecifier(const char *Name);
- /// getNumCompilationPhases - Return the complete number of phases
- /// to be done for this type.
- unsigned getNumCompilationPhases(ID Id);
+ /// getCompilationPhases - Get the list of compilation phases ('Phases') to be
+ /// done for type 'Id'.
+ void getCompilationPhases(
+ ID Id,
+ llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> &Phases);
- /// getCompilationPhase - Return the \p N th compilation phase to
- /// be done for this type.
- phases::ID getCompilationPhase(ID Id, unsigned N);
-
/// lookupCXXTypeForCType - Lookup CXX input type that corresponds to given
/// C type (used for clang++ emulation of g++ behaviour)
ID lookupCXXTypeForCType(ID Id);
diff --git a/include/clang/Driver/Util.h b/include/clang/Driver/Util.h
index 65aef4b..06b82b9 100644
--- a/include/clang/Driver/Util.h
+++ b/include/clang/Driver/Util.h
@@ -11,14 +11,19 @@
#define CLANG_DRIVER_UTIL_H_
#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/DenseMap.h"
namespace clang {
namespace driver {
class Action;
+ class JobAction;
/// ArgStringList - Type used for constructing argv lists for subprocesses.
typedef SmallVector<const char*, 16> ArgStringList;
+ /// ArgStringMap - Type used to map a JobAction to its result file.
+ typedef llvm::DenseMap<const JobAction*, const char*> ArgStringMap;
+
/// ActionList - Type used for lists of actions.
typedef SmallVector<Action*, 3> ActionList;
diff --git a/include/clang/Edit/Commit.h b/include/clang/Edit/Commit.h
index aaf6b18..48e3d59 100644
--- a/include/clang/Edit/Commit.h
+++ b/include/clang/Edit/Commit.h
@@ -11,12 +11,12 @@
#define LLVM_CLANG_EDIT_COMMIT_H
#include "clang/Edit/FileOffset.h"
-#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
namespace clang {
class LangOptions;
- class PreprocessingRecord;
+ class PPConditionalDirectiveRecord;
namespace edit {
class EditedSource;
@@ -46,7 +46,7 @@ public:
private:
const SourceManager &SourceMgr;
const LangOptions &LangOpts;
- const PreprocessingRecord *PPRec;
+ const PPConditionalDirectiveRecord *PPRec;
EditedSource *Editor;
bool IsCommitable;
@@ -55,7 +55,7 @@ private:
public:
explicit Commit(EditedSource &Editor);
Commit(const SourceManager &SM, const LangOptions &LangOpts,
- const PreprocessingRecord *PPRec = 0)
+ const PPConditionalDirectiveRecord *PPRec = 0)
: SourceMgr(SM), LangOpts(LangOpts), PPRec(PPRec), Editor(0),
IsCommitable(true) { }
diff --git a/include/clang/Edit/EditedSource.h b/include/clang/Edit/EditedSource.h
index c685753..733ad40 100644
--- a/include/clang/Edit/EditedSource.h
+++ b/include/clang/Edit/EditedSource.h
@@ -11,14 +11,14 @@
#define LLVM_CLANG_EDIT_EDITEDSOURCE_H
#include "clang/Edit/FileOffset.h"
-#include "llvm/Support/Allocator.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Allocator.h"
#include <map>
namespace clang {
class LangOptions;
- class PreprocessingRecord;
+ class PPConditionalDirectiveRecord;
namespace edit {
class Commit;
@@ -27,7 +27,7 @@ namespace edit {
class EditedSource {
const SourceManager &SourceMgr;
const LangOptions &LangOpts;
- const PreprocessingRecord *PPRec;
+ const PPConditionalDirectiveRecord *PPRec;
struct FileEdit {
StringRef Text;
@@ -45,13 +45,15 @@ class EditedSource {
public:
EditedSource(const SourceManager &SM, const LangOptions &LangOpts,
- const PreprocessingRecord *PPRec = 0)
+ const PPConditionalDirectiveRecord *PPRec = 0)
: SourceMgr(SM), LangOpts(LangOpts), PPRec(PPRec),
StrAlloc(/*size=*/512) { }
const SourceManager &getSourceManager() const { return SourceMgr; }
const LangOptions &getLangOpts() const { return LangOpts; }
- const PreprocessingRecord *getPreprocessingRecord() const { return PPRec; }
+ const PPConditionalDirectiveRecord *getPPCondDirectiveRecord() const {
+ return PPRec;
+ }
bool canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs);
diff --git a/include/clang/Edit/Rewriters.h b/include/clang/Edit/Rewriters.h
index aa7a5b2..292878e 100644
--- a/include/clang/Edit/Rewriters.h
+++ b/include/clang/Edit/Rewriters.h
@@ -13,6 +13,7 @@
namespace clang {
class ObjCMessageExpr;
class NSAPI;
+ class ParentMap;
namespace edit {
class Commit;
@@ -21,7 +22,8 @@ bool rewriteObjCRedundantCallWithLiteral(const ObjCMessageExpr *Msg,
const NSAPI &NS, Commit &commit);
bool rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
- const NSAPI &NS, Commit &commit);
+ const NSAPI &NS, Commit &commit,
+ const ParentMap *PMap);
bool rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg,
const NSAPI &NS, Commit &commit);
diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h
new file mode 100644
index 0000000..d6cc114e
--- /dev/null
+++ b/include/clang/Format/Format.h
@@ -0,0 +1,131 @@
+//===--- Format.h - Format C++ code -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Various functions to configurably format source code.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FORMAT_FORMAT_H
+#define LLVM_CLANG_FORMAT_FORMAT_H
+
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Tooling/Refactoring.h"
+
+namespace clang {
+
+class Lexer;
+class SourceManager;
+class DiagnosticConsumer;
+
+namespace format {
+
+/// \brief The \c FormatStyle is used to configure the formatting to follow
+/// specific guidelines.
+struct FormatStyle {
+ /// \brief The column limit.
+ unsigned ColumnLimit;
+
+ /// \brief The penalty for each character outside of the column limit.
+ unsigned PenaltyExcessCharacter;
+
+ /// \brief The maximum number of consecutive empty lines to keep.
+ unsigned MaxEmptyLinesToKeep;
+
+ /// \brief Set whether & and * bind to the type as opposed to the variable.
+ bool PointerBindsToType;
+
+ /// \brief If \c true, analyze the formatted file for the most common binding.
+ bool DerivePointerBinding;
+
+ /// \brief The extra indent or outdent of access modifiers (e.g.: public:).
+ int AccessModifierOffset;
+
+ enum LanguageStandard {
+ LS_Cpp03,
+ LS_Cpp11,
+ LS_Auto
+ };
+
+ /// \brief Format compatible with this standard, e.g. use \c A<A<int> >
+ /// instead of \c A<A<int>> for LS_Cpp03.
+ LanguageStandard Standard;
+
+ /// \brief If \c true, analyze the formatted file for C++03 compatibility.
+ bool DeriveBackwardsCompatibility;
+
+ /// \brief Indent case labels one level from the switch statement.
+ ///
+ /// When false, use the same indentation level as for the switch statement.
+ /// Switch statement body is always indented one level more than case labels.
+ bool IndentCaseLabels;
+
+ /// \brief The number of spaces to before trailing line comments.
+ unsigned SpacesBeforeTrailingComments;
+
+ /// \brief If false, a function call's or function definition's parameters
+ /// will either all be on the same line or will have one line each.
+ bool BinPackParameters;
+
+ /// \brief Allow putting all parameters of a function declaration onto
+ /// the next line even if \c BinPackParameters is \c false.
+ bool AllowAllParametersOfDeclarationOnNextLine;
+
+ /// \brief Penalty for putting the return type of a function onto its own
+ /// line.
+ unsigned PenaltyReturnTypeOnItsOwnLine;
+
+ /// \brief If the constructor initializers don't fit on a line, put each
+ /// initializer on its own line.
+ bool ConstructorInitializerAllOnOneLineOrOnePerLine;
+
+ /// \brief If true, "if (a) return;" can be put on a single line.
+ bool AllowShortIfStatementsOnASingleLine;
+
+ /// \brief Add a space in front of an Objective-C protocol list, i.e. use
+ /// Foo <Protocol> instead of Foo<Protocol>.
+ bool ObjCSpaceBeforeProtocolList;
+};
+
+/// \brief Returns a format style complying with the LLVM coding standards:
+/// http://llvm.org/docs/CodingStandards.html.
+FormatStyle getLLVMStyle();
+
+/// \brief Returns a format style complying with Google's C++ style guide:
+/// http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml.
+FormatStyle getGoogleStyle();
+
+/// \brief Returns a format style complying with Chromium's style guide:
+/// http://www.chromium.org/developers/coding-style.
+FormatStyle getChromiumStyle();
+
+/// \brief Reformats the given \p Ranges in the token stream coming out of
+/// \c Lex.
+///
+/// Each range is extended on either end to its next bigger logic unit, i.e.
+/// everything that might influence its formatting or might be influenced by its
+/// formatting.
+///
+/// \param DiagClient A custom DiagnosticConsumer. Can be 0, in this case
+/// diagnostic is output to llvm::errs().
+///
+/// Returns the \c Replacements necessary to make all \p Ranges comply with
+/// \p Style.
+tooling::Replacements reformat(const FormatStyle &Style, Lexer &Lex,
+ SourceManager &SourceMgr,
+ std::vector<CharSourceRange> Ranges,
+ DiagnosticConsumer *DiagClient = 0);
+
+/// \brief Returns the \c LangOpts that the formatter expects you to set.
+LangOptions getFormattingLangOpts();
+
+} // end namespace format
+} // end namespace clang
+
+#endif // LLVM_CLANG_FORMAT_FORMAT_H
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index 5e409bd..02c57d7 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -14,30 +14,30 @@
#ifndef LLVM_CLANG_FRONTEND_ASTUNIT_H
#define LLVM_CLANG_FRONTEND_ASTUNIT_H
-#include "clang/Serialization/ASTBitCodes.h"
-#include "clang/Sema/Sema.h"
-#include "clang/Sema/CodeCompleteConsumer.h"
-#include "clang/Lex/ModuleLoader.h"
-#include "clang/Lex/PreprocessingRecord.h"
-#include "clang/Lex/HeaderSearchOptions.h"
+#include "clang-c/Index.h"
#include "clang/AST/ASTContext.h"
-#include "clang/Basic/LangOptions.h"
-#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemOptions.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetOptions.h"
-#include "clang-c/Index.h"
+#include "clang/Lex/HeaderSearchOptions.h"
+#include "clang/Lex/ModuleLoader.h"
+#include "clang/Lex/PreprocessingRecord.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Serialization/ASTBitCodes.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/Path.h"
+#include <cassert>
#include <map>
#include <string>
-#include <vector>
-#include <cassert>
-#include <utility>
#include <sys/types.h>
+#include <utility>
+#include <vector>
namespace llvm {
class MemoryBuffer;
@@ -485,6 +485,9 @@ public:
StringRef getMainFileName() const;
+ /// \brief If this ASTUnit came from an AST file, returns the filename for it.
+ StringRef getASTFileName() const;
+
typedef std::vector<Decl *>::iterator top_level_iterator;
top_level_iterator top_level_begin() {
@@ -830,12 +833,19 @@ public:
/// \returns True if an error occurred, false otherwise.
bool serialize(raw_ostream &OS);
- virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
- Module::NameVisibilityKind Visibility,
- bool IsInclusionDirective) {
+ virtual ModuleLoadResult loadModule(SourceLocation ImportLoc,
+ ModuleIdPath Path,
+ Module::NameVisibilityKind Visibility,
+ bool IsInclusionDirective) {
// ASTUnit doesn't know how to load modules (not that this matters).
- return 0;
+ return ModuleLoadResult();
}
+
+ virtual void makeModuleVisible(Module *Mod,
+ Module::NameVisibilityKind Visibility,
+ SourceLocation ImportLoc,
+ bool Complain) { }
+
};
} // namespace clang
diff --git a/include/clang/Frontend/ChainedIncludesSource.h b/include/clang/Frontend/ChainedIncludesSource.h
index d7119e9..e14580e 100644
--- a/include/clang/Frontend/ChainedIncludesSource.h
+++ b/include/clang/Frontend/ChainedIncludesSource.h
@@ -44,8 +44,8 @@ protected:
virtual uint32_t GetNumExternalSelectors();
virtual Stmt *GetExternalDeclStmt(uint64_t Offset);
virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset);
- virtual DeclContextLookupResult
- FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name);
+ virtual bool FindExternalVisibleDeclsByName(const DeclContext *DC,
+ DeclarationName Name);
virtual ExternalLoadResult FindExternalLexicalDecls(const DeclContext *DC,
bool (*isKindWeWant)(Decl::Kind),
SmallVectorImpl<Decl*> &Result);
diff --git a/include/clang/Frontend/CodeGenOptions.def b/include/clang/Frontend/CodeGenOptions.def
index 558e6f1..1c0b9fa 100644
--- a/include/clang/Frontend/CodeGenOptions.def
+++ b/include/clang/Frontend/CodeGenOptions.def
@@ -30,6 +30,8 @@ CODEGENOPT(Name, Bits, Default)
CODEGENOPT(AsmVerbose , 1, 0) ///< -dA, -fverbose-asm.
CODEGENOPT(ObjCAutoRefCountExceptions , 1, 0) ///< Whether ARC should be EH-safe.
+CODEGENOPT(CoverageExtraChecksum, 1, 0) ///< Whether we need a second checksum for functions in GCNO files.
+CODEGENOPT(CoverageNoFunctionNamesInData, 1, 0) ///< Do not include function names in GCDA files.
CODEGENOPT(CUDAIsDevice , 1, 0) ///< Set when compiling for CUDA device.
CODEGENOPT(CXAAtExit , 1, 1) ///< Use __cxa_atexit for calling destructors.
CODEGENOPT(CXXCtorDtorAliases, 1, 0) ///< Emit complete ctors/dtors as linker
@@ -40,6 +42,7 @@ CODEGENOPT(DisableLLVMOpts , 1, 0) ///< Don't run any optimizations, for use i
///< getting .bc files that correspond to the
///< internal state before optimizations are
///< done.
+CODEGENOPT(DisableGCov , 1, 0) ///< Don't run the GCov pass, for testing.
CODEGENOPT(DisableRedZone , 1, 0) ///< Set when -mno-red-zone is enabled.
CODEGENOPT(DisableTailCalls , 1, 0) ///< Do not emit tail calls.
CODEGENOPT(EmitDeclMetadata , 1, 0) ///< Emit special metadata indicating what
@@ -49,6 +52,8 @@ CODEGENOPT(EmitDeclMetadata , 1, 0) ///< Emit special metadata indicating what
CODEGENOPT(EmitGcovArcs , 1, 0) ///< Emit coverage data files, aka. GCDA.
CODEGENOPT(EmitGcovNotes , 1, 0) ///< Emit coverage "notes" files, aka GCNO.
CODEGENOPT(EmitOpenCLArgMetadata , 1, 0) ///< Emit OpenCL kernel arg metadata.
+/// \brief FP_CONTRACT mode (on/off/fast).
+ENUM_CODEGENOPT(FPContractMode, FPContractModeKind, 2, FPC_On)
CODEGENOPT(ForbidGuardVariables , 1, 0) ///< Issue errors if C++ guard variables
///< are required.
CODEGENOPT(FunctionSections , 1, 0) ///< Set when -ffunction-sections is enabled.
@@ -65,6 +70,7 @@ CODEGENOPT(NoDwarf2CFIAsm , 1, 0) ///< Set when -fno-dwarf2-cfi-asm is enable
CODEGENOPT(NoDwarfDirectoryAsm , 1, 0) ///< Set when -fno-dwarf-directory-asm is
///< enabled.
CODEGENOPT(NoExecStack , 1, 0) ///< Set when -Wa,--noexecstack is enabled.
+CODEGENOPT(EnableSegmentedStacks , 1, 0) ///< Set when -fsplit-stack is enabled.
CODEGENOPT(NoGlobalMerge , 1, 0) ///< Set when -mno-global-merge is enabled.
CODEGENOPT(NoImplicitFloat , 1, 0) ///< Set when -mno-implicit-float is enabled.
CODEGENOPT(NoInfsFPMath , 1, 0) ///< Assume FP arguments, results not +-Inf.
@@ -80,7 +86,14 @@ VALUE_CODEGENOPT(OptimizationLevel, 3, 0) ///< The -O[0-4] option specified.
VALUE_CODEGENOPT(OptimizeSize, 2, 0) ///< If -Os (==1) or -Oz (==2) is specified.
CODEGENOPT(RelaxAll , 1, 0) ///< Relax all machine code instructions.
CODEGENOPT(RelaxedAliasing , 1, 0) ///< Set when -fno-strict-aliasing is enabled.
+CODEGENOPT(StructPathTBAA , 1, 0) ///< Whether or not to use struct-path TBAA.
CODEGENOPT(SaveTempLabels , 1, 0) ///< Save temporary labels.
+CODEGENOPT(SanitizeAddressZeroBaseShadow , 1, 0) ///< Map shadow memory at zero
+ ///< offset in AddressSanitizer.
+CODEGENOPT(SanitizeMemoryTrackOrigins, 1, 0) ///< Enable tracking origins in
+ ///< MemorySanitizer
+CODEGENOPT(SanitizeUndefinedTrapOnError, 1, 0) ///< Set on
+ /// -fsanitize-undefined-trap-on-error
CODEGENOPT(SimplifyLibCalls , 1, 1) ///< Set when -fbuiltin is enabled.
CODEGENOPT(SoftFloat , 1, 0) ///< -soft-float.
CODEGENOPT(StrictEnums , 1, 0) ///< Optimize based on strict enum definition.
@@ -107,13 +120,12 @@ VALUE_CODEGENOPT(StackAlignment , 32, 0) ///< Overrides default stack
CODEGENOPT(DebugColumnInfo, 1, 0) ///< Whether or not to use column information
///< in debug info.
+CODEGENOPT(ModulesAutolink, 1, 0) ///< Whether to auto-link imported modules
+
/// The user specified number of registers to be used for integral arguments,
/// or 0 if unspecified.
VALUE_CODEGENOPT(NumRegisterParameters, 32, 0)
-/// The run-time penalty for bounds checking, or 0 to disable.
-VALUE_CODEGENOPT(BoundsChecking, 8, 0)
-
/// The lower bound for a buffer to be considered for stack protection.
VALUE_CODEGENOPT(SSPBufferSize, 32, 0)
@@ -126,6 +138,9 @@ ENUM_CODEGENOPT(Inlining, InliningMethod, 2, NoInlining)
/// The default TLS model to use.
ENUM_CODEGENOPT(DefaultTLSModel, TLSModel, 2, GeneralDynamicTLSModel)
+CODEGENOPT(SanitizeRecover, 1, 1) ///< Attempt to recover from sanitizer checks
+ ///< by continuing execution when possible
+
#undef CODEGENOPT
#undef ENUM_CODEGENOPT
#undef VALUE_CODEGENOPT
diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h
index 3567187..d0bbf30 100644
--- a/include/clang/Frontend/CodeGenOptions.h
+++ b/include/clang/Frontend/CodeGenOptions.h
@@ -65,6 +65,12 @@ public:
LocalExecTLSModel
};
+ enum FPContractModeKind {
+ FPC_Off, // Form fused FP ops only where result will not be affected.
+ FPC_On, // Form fused FP ops according to FP_CONTRACT rules.
+ FPC_Fast // Aggressively fuse FP ops (E.g. FMA).
+ };
+
/// The code model to use (-mcmodel).
std::string CodeModel;
@@ -72,6 +78,9 @@ public:
/// replaced.
std::string CoverageFile;
+ /// The version string to put into coverage files.
+ char CoverageVersion[4];
+
/// Enable additional debugging information.
std::string DebugPass;
@@ -96,9 +105,16 @@ public:
/// file, for example with -save-temps.
std::string MainFileName;
+ /// The name for the split debug info file that we'll break out. This is used
+ /// in the backend for setting the name in the skeleton cu.
+ std::string SplitDwarfFile;
+
/// The name of the relocation model to use.
std::string RelocationModel;
+ /// Path to blacklist file for sanitizers.
+ std::string SanitizerBlacklistFile;
+
/// If not an empty string, trap intrinsics are lowered to calls to this
/// function instead of to trap instructions.
std::string TrapFuncName;
@@ -121,6 +137,7 @@ public:
#include "clang/Frontend/CodeGenOptions.def"
RelocationModel = "pic";
+ memcpy(CoverageVersion, "*204", 4);
}
};
diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h
index 2f3dc3f..0d67462 100644
--- a/include/clang/Frontend/CompilerInstance.h
+++ b/include/clang/Frontend/CompilerInstance.h
@@ -10,15 +10,15 @@
#ifndef LLVM_CLANG_FRONTEND_COMPILERINSTANCE_H_
#define LLVM_CLANG_FRONTEND_COMPILERINSTANCE_H_
-#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Lex/ModuleLoader.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
-#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/StringRef.h"
#include <cassert>
#include <list>
#include <string>
@@ -94,7 +94,7 @@ class CompilerInstance : public ModuleLoader {
/// \brief The semantic analysis object.
OwningPtr<Sema> TheSema;
-
+
/// \brief The frontend timer
OwningPtr<llvm::Timer> FrontendTimer;
@@ -111,8 +111,15 @@ class CompilerInstance : public ModuleLoader {
/// \brief The result of the last module import.
///
- Module *LastModuleImportResult;
-
+ ModuleLoadResult LastModuleImportResult;
+
+ /// \brief Whether we should (re)build the global module index once we
+ /// have finished with this translation unit.
+ bool BuildGlobalModuleIndex;
+
+ /// \brief One or more modules failed to build.
+ bool ModuleBuildFailed;
+
/// \brief Holds information about the output file.
///
/// If TempFilename is not empty we must rename it to Filename at the end.
@@ -186,6 +193,15 @@ public:
/// setInvocation - Replace the current invocation.
void setInvocation(CompilerInvocation *Value);
+ /// \brief Indicates whether we should (re)build the global module index.
+ bool shouldBuildGlobalModuleIndex() const;
+
+ /// \brief Set the flag indicating whether we should (re)build the global
+ /// module index.
+ void setBuildGlobalModuleIndex(bool Build) {
+ BuildGlobalModuleIndex = Build;
+ }
+
/// }
/// @name Forwarding Methods
/// {
@@ -479,17 +495,12 @@ public:
///
/// \param ShouldCloneClient If Client is non-NULL, specifies whether that
/// client should be cloned.
- void createDiagnostics(int Argc, const char* const *Argv,
- DiagnosticConsumer *Client = 0,
+ void createDiagnostics(DiagnosticConsumer *Client = 0,
bool ShouldOwnClient = true,
bool ShouldCloneClient = true);
/// Create a DiagnosticsEngine object with a the TextDiagnosticPrinter.
///
- /// The \p Argc and \p Argv arguments are used only for logging purposes,
- /// when the diagnostic options indicate that the compiler should output
- /// logging information.
- ///
/// If no diagnostic client is provided, this creates a
/// DiagnosticConsumer that is owned by the returned diagnostic
/// object, if using directly the caller is responsible for
@@ -507,8 +518,7 @@ public:
///
/// \return The new object on success, or null on failure.
static IntrusiveRefCntPtr<DiagnosticsEngine>
- createDiagnostics(DiagnosticOptions *Opts, int Argc,
- const char* const *Argv,
+ createDiagnostics(DiagnosticOptions *Opts,
DiagnosticConsumer *Client = 0,
bool ShouldOwnClient = true,
bool ShouldCloneClient = true,
@@ -542,7 +552,8 @@ public:
bool DisablePCHValidation,
bool AllowPCHWithCompilerErrors,
Preprocessor &PP, ASTContext &Context,
- void *DeserializationListener, bool Preamble);
+ void *DeserializationListener, bool Preamble,
+ bool UseGlobalModuleIndex);
/// Create a code completion consumer using the invocation; note that this
/// will cause the source manager to truncate the input source file at the
@@ -645,9 +656,16 @@ public:
/// }
- virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
- Module::NameVisibilityKind Visibility,
- bool IsInclusionDirective);
+ virtual ModuleLoadResult loadModule(SourceLocation ImportLoc,
+ ModuleIdPath Path,
+ Module::NameVisibilityKind Visibility,
+ bool IsInclusionDirective);
+
+ virtual void makeModuleVisible(Module *Mod,
+ Module::NameVisibilityKind Visibility,
+ SourceLocation ImportLoc,
+ bool Complain);
+
};
} // end namespace clang
diff --git a/include/clang/Frontend/CompilerInvocation.h b/include/clang/Frontend/CompilerInvocation.h
index 1314956..fac05c5 100644
--- a/include/clang/Frontend/CompilerInvocation.h
+++ b/include/clang/Frontend/CompilerInvocation.h
@@ -10,22 +10,22 @@
#ifndef LLVM_CLANG_FRONTEND_COMPILERINVOCATION_H_
#define LLVM_CLANG_FRONTEND_COMPILERINVOCATION_H_
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/FileSystemOptions.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetOptions.h"
-#include "clang/Basic/FileSystemOptions.h"
-#include "clang/Basic/DiagnosticOptions.h"
-#include "clang/Lex/HeaderSearchOptions.h"
-#include "clang/Lex/PreprocessorOptions.h"
-#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
-#include "clang/Frontend/MigratorOptions.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "clang/Frontend/DependencyOutputOptions.h"
#include "clang/Frontend/FrontendOptions.h"
#include "clang/Frontend/LangStandard.h"
+#include "clang/Frontend/MigratorOptions.h"
#include "clang/Frontend/PreprocessorOutputOptions.h"
+#include "clang/Lex/HeaderSearchOptions.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
-#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
#include <string>
#include <vector>
diff --git a/include/clang/Frontend/DiagnosticRenderer.h b/include/clang/Frontend/DiagnosticRenderer.h
index 086bb13..f3cd054 100644
--- a/include/clang/Frontend/DiagnosticRenderer.h
+++ b/include/clang/Frontend/DiagnosticRenderer.h
@@ -19,6 +19,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PointerUnion.h"
namespace clang {
@@ -31,7 +32,8 @@ typedef llvm::PointerUnion<const Diagnostic *,
const StoredDiagnostic *> DiagOrStoredDiag;
/// \brief Class to encapsulate the logic for formatting a diagnostic message.
-/// Actual "printing" logic is implemented by subclasses.
+///
+/// Actual "printing" logic is implemented by subclasses.
///
/// This class provides an interface for building and emitting
/// diagnostic, including all of the macro backtraces, caret diagnostics, FixIt
@@ -55,7 +57,7 @@ protected:
/// \brief The location of the last include whose stack was printed if known.
///
- /// Same restriction as \see LastLoc essentially, but tracking include stack
+ /// Same restriction as LastLoc essentially, but tracking include stack
/// root locations rather than diagnostic locations.
SourceLocation LastIncludeLoc;
@@ -92,7 +94,13 @@ protected:
virtual void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc,
const SourceManager &SM) = 0;
-
+ virtual void emitImportLocation(SourceLocation Loc, PresumedLoc PLoc,
+ StringRef ModuleName,
+ const SourceManager &SM) = 0;
+ virtual void emitBuildingModuleLocation(SourceLocation Loc, PresumedLoc PLoc,
+ StringRef ModuleName,
+ const SourceManager &SM) = 0;
+
virtual void beginDiagnostic(DiagOrStoredDiag D,
DiagnosticsEngine::Level Level) {}
virtual void endDiagnostic(DiagOrStoredDiag D,
@@ -100,16 +108,23 @@ protected:
private:
- void emitIncludeStack(SourceLocation Loc, DiagnosticsEngine::Level Level,
- const SourceManager &SM);
+ void emitIncludeStack(SourceLocation Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level, const SourceManager &SM);
void emitIncludeStackRecursively(SourceLocation Loc, const SourceManager &SM);
- void emitMacroExpansionsAndCarets(SourceLocation Loc,
- DiagnosticsEngine::Level Level,
- SmallVectorImpl<CharSourceRange>& Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM,
- unsigned &MacroDepth,
- unsigned OnMacroInst = 0);
+ void emitImportStack(SourceLocation Loc, const SourceManager &SM);
+ void emitImportStackRecursively(SourceLocation Loc, StringRef ModuleName,
+ const SourceManager &SM);
+ void emitModuleBuildStack(const SourceManager &SM);
+ void emitCaret(SourceLocation Loc, DiagnosticsEngine::Level Level,
+ ArrayRef<CharSourceRange> Ranges, ArrayRef<FixItHint> Hints,
+ const SourceManager &SM);
+ void emitMacroExpansions(SourceLocation Loc,
+ DiagnosticsEngine::Level Level,
+ ArrayRef<CharSourceRange> Ranges,
+ ArrayRef<FixItHint> Hints,
+ const SourceManager &SM,
+ unsigned &MacroDepth,
+ unsigned OnMacroInst = 0);
public:
/// \brief Emit a diagnostic.
///
@@ -149,7 +164,15 @@ public:
virtual void emitIncludeLocation(SourceLocation Loc,
PresumedLoc PLoc,
const SourceManager &SM);
-
+
+ virtual void emitImportLocation(SourceLocation Loc, PresumedLoc PLoc,
+ StringRef ModuleName,
+ const SourceManager &SM);
+
+ virtual void emitBuildingModuleLocation(SourceLocation Loc, PresumedLoc PLoc,
+ StringRef ModuleName,
+ const SourceManager &SM);
+
virtual void emitNote(SourceLocation Loc, StringRef Message,
const SourceManager *SM) = 0;
};
diff --git a/include/clang/Frontend/FrontendAction.h b/include/clang/Frontend/FrontendAction.h
index 3283444..c67be92 100644
--- a/include/clang/Frontend/FrontendAction.h
+++ b/include/clang/Frontend/FrontendAction.h
@@ -6,6 +6,14 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Defines the clang::FrontendAction interface and various convenience
+/// abstract classes (clang::ASTFrontendAction, clang::PluginASTAction,
+/// clang::PreprocessorFrontendAction, and clang::WrapperFrontendAction)
+/// derived from it.
+///
+//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_FRONTEND_FRONTENDACTION_H
#define LLVM_CLANG_FRONTEND_FRONTENDACTION_H
@@ -13,8 +21,8 @@
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Frontend/FrontendOptions.h"
-#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/StringRef.h"
#include <string>
#include <vector>
@@ -24,8 +32,7 @@ class ASTMergeAction;
class ASTUnit;
class CompilerInstance;
-/// FrontendAction - Abstract base class for actions which can be performed by
-/// the frontend.
+/// Abstract base class for actions which can be performed by the frontend.
class FrontendAction {
FrontendInputFile CurrentInput;
OwningPtr<ASTUnit> CurrentASTUnit;
@@ -41,20 +48,19 @@ protected:
/// @name Implementation Action Interface
/// @{
- /// CreateASTConsumer - Create the AST consumer object for this action, if
- /// supported.
+ /// \brief Create the AST consumer object for this action, if supported.
///
- /// This routine is called as part of \see BeginSourceAction(), which will
+ /// This routine is called as part of BeginSourceFile(), which will
/// fail if the AST consumer cannot be created. This will not be called if the
/// action has indicated that it only uses the preprocessor.
///
- /// \param CI - The current compiler instance, provided as a convenience, \see
+ /// \param CI - The current compiler instance, provided as a convenience, see
/// getCompilerInstance().
///
- /// \param InFile - The current input file, provided as a convenience, \see
+ /// \param InFile - The current input file, provided as a convenience, see
/// getCurrentFile().
///
- /// \return The new AST consumer, or 0 on failure.
+ /// \return The new AST consumer, or null on failure.
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) = 0;
@@ -62,29 +68,29 @@ protected:
/// opportunity to modify the CompilerInvocation or do some other action
/// before BeginSourceFileAction is called.
///
- /// \return True on success; on failure \see BeginSourceFileAction() and
- /// ExecutionAction() and EndSourceFileAction() will not be called.
+ /// \return True on success; on failure BeginSourceFileAction(),
+ /// ExecuteAction() and EndSourceFileAction() will not be called.
virtual bool BeginInvocation(CompilerInstance &CI) { return true; }
- /// BeginSourceFileAction - Callback at the start of processing a single
- /// input.
+ /// \brief Callback at the start of processing a single input.
///
- /// \return True on success; on failure \see ExecutionAction() and
+ /// \return True on success; on failure ExecutionAction() and
/// EndSourceFileAction() will not be called.
virtual bool BeginSourceFileAction(CompilerInstance &CI,
StringRef Filename) {
return true;
}
- /// ExecuteAction - Callback to run the program action, using the initialized
+ /// \brief Callback to run the program action, using the initialized
/// compiler instance.
///
- /// This routine is guaranteed to only be called between \see
- /// BeginSourceFileAction() and \see EndSourceFileAction().
+ /// This is guaranteed to only be called between BeginSourceFileAction()
+ /// and EndSourceFileAction().
virtual void ExecuteAction() = 0;
- /// EndSourceFileAction - Callback at the end of processing a single input;
- /// this is guaranteed to only be called following a successful call to
+ /// \brief Callback at the end of processing a single input.
+ ///
+ /// This is guaranteed to only be called following a successful call to
/// BeginSourceFileAction (and BeginSourceFile).
virtual void EndSourceFileAction() {}
@@ -142,34 +148,35 @@ public:
/// @name Supported Modes
/// @{
- /// usesPreprocessorOnly - Does this action only use the preprocessor? If so
- /// no AST context will be created and this action will be invalid with AST
- /// file inputs.
+ /// \brief Does this action only use the preprocessor?
+ ///
+ /// If so no AST context will be created and this action will be invalid
+ /// with AST file inputs.
virtual bool usesPreprocessorOnly() const = 0;
/// \brief For AST-based actions, the kind of translation unit we're handling.
virtual TranslationUnitKind getTranslationUnitKind() { return TU_Complete; }
- /// hasPCHSupport - Does this action support use with PCH?
+ /// \brief Does this action support use with PCH?
virtual bool hasPCHSupport() const { return !usesPreprocessorOnly(); }
- /// hasASTFileSupport - Does this action support use with AST files?
+ /// \brief Does this action support use with AST files?
virtual bool hasASTFileSupport() const { return !usesPreprocessorOnly(); }
- /// hasIRSupport - Does this action support use with IR files?
+ /// \brief Does this action support use with IR files?
virtual bool hasIRSupport() const { return false; }
- /// hasCodeCompletionSupport - Does this action support use with code
- /// completion?
+ /// \brief Does this action support use with code completion?
virtual bool hasCodeCompletionSupport() const { return false; }
/// @}
/// @name Public Action Interface
/// @{
- /// BeginSourceFile - Prepare the action for processing the input file
- /// \p Input; this is run after the options and frontend have been
- /// initialized, but prior to executing any per-file processing.
+ /// \brief Prepare the action for processing the input file \p Input.
+ ///
+ /// This is run after the options and frontend have been initialized,
+ /// but prior to executing any per-file processing.
///
/// \param CI - The compiler instance this action is being run from. The
/// action may store and use this object up until the matching EndSourceFile
@@ -180,29 +187,28 @@ public:
/// several objects which would normally be owned by the
/// CompilerInstance. When processing AST input files, these objects should
/// generally not be initialized in the CompilerInstance -- they will
- /// automatically be shared with the AST file in between \see
- /// BeginSourceFile() and \see EndSourceFile().
+ /// automatically be shared with the AST file in between
+ /// BeginSourceFile() and EndSourceFile().
///
/// \return True on success; on failure the compilation of this file should
- /// be aborted and neither Execute nor EndSourceFile should be called.
+ /// be aborted and neither Execute() nor EndSourceFile() should be called.
bool BeginSourceFile(CompilerInstance &CI, const FrontendInputFile &Input);
- /// Execute - Set the source managers main input file, and run the action.
+ /// \brief Set the source manager's main input file, and run the action.
bool Execute();
- /// EndSourceFile - Perform any per-file post processing, deallocate per-file
+ /// \brief Perform any per-file post processing, deallocate per-file
/// objects, and run statistics and output file cleanup code.
void EndSourceFile();
/// @}
};
-/// ASTFrontendAction - Abstract base class to use for AST consumer based
-/// frontend actions.
+/// \brief Abstract base class to use for AST consumer-based frontend actions.
class ASTFrontendAction : public FrontendAction {
protected:
- /// ExecuteAction - Implement the ExecuteAction interface by running Sema on
- /// the already initialized AST consumer.
+ /// \brief Implement the ExecuteAction interface by running Sema on
+ /// the already-initialized AST consumer.
///
/// This will also take care of instantiating a code completion consumer if
/// the user requested it and the action supports it.
@@ -219,7 +225,7 @@ protected:
StringRef InFile) = 0;
public:
- /// ParseArgs - Parse the given plugin command line arguments.
+ /// \brief Parse the given plugin command line arguments.
///
/// \param CI - The compiler instance, for use in reporting diagnostics.
/// \return True if the parsing succeeded; otherwise the plugin will be
@@ -229,11 +235,10 @@ public:
const std::vector<std::string> &arg) = 0;
};
-/// PreprocessorFrontendAction - Abstract base class to use for preprocessor
-/// based frontend actions.
+/// \brief Abstract base class to use for preprocessor-based frontend actions.
class PreprocessorFrontendAction : public FrontendAction {
protected:
- /// CreateASTConsumer - Provide a default implementation which returns aborts,
+ /// \brief Provide a default implementation which returns aborts;
/// this method should never be called by FrontendAction clients.
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
StringRef InFile);
@@ -242,11 +247,12 @@ public:
virtual bool usesPreprocessorOnly() const { return true; }
};
-/// WrapperFrontendAction - A frontend action which simply wraps some other
-/// runtime specified frontend action. Deriving from this class allows an
-/// action to inject custom logic around some existing action's behavior. It
-/// implements every virtual method in the FrontendAction interface by
-/// forwarding to the wrapped action.
+/// \brief A frontend action which simply wraps some other runtime-specified
+/// frontend action.
+///
+/// Deriving from this class allows an action to inject custom logic around
+/// some existing action's behavior. It implements every virtual method in
+/// the FrontendAction interface by forwarding to the wrapped action.
class WrapperFrontendAction : public FrontendAction {
OwningPtr<FrontendAction> WrappedAction;
diff --git a/include/clang/Frontend/FrontendActions.h b/include/clang/Frontend/FrontendActions.h
index 477ac45..1786190 100644
--- a/include/clang/Frontend/FrontendActions.h
+++ b/include/clang/Frontend/FrontendActions.h
@@ -123,7 +123,7 @@ public:
std::string &OutputFile,
raw_ostream *&OS);
};
-
+
class SyntaxOnlyAction : public ASTFrontendAction {
protected:
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
@@ -133,6 +133,21 @@ public:
virtual bool hasCodeCompletionSupport() const { return true; }
};
+/// \brief Dump information about the given module file, to be used for
+/// basic debugging and discovery.
+class DumpModuleInfoAction : public ASTFrontendAction {
+protected:
+ virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile);
+ virtual void ExecuteAction();
+
+public:
+ virtual bool hasPCHSupport() const { return false; }
+ virtual bool hasASTFileSupport() const { return true; }
+ virtual bool hasIRSupport() const { return false; }
+ virtual bool hasCodeCompletionSupport() const { return false; }
+};
+
/**
* \brief Frontend action adaptor that merges ASTs together.
*
diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h
index db2f5a5..234e344 100644
--- a/include/clang/Frontend/FrontendOptions.h
+++ b/include/clang/Frontend/FrontendOptions.h
@@ -43,6 +43,7 @@ namespace frontend {
GeneratePCH, ///< Generate pre-compiled header.
GeneratePTH, ///< Generate pre-tokenized header.
InitOnly, ///< Only execute frontend initialization.
+ ModuleFileInfo, ///< Dump information about a module file.
ParseSyntaxOnly, ///< Parse and perform semantic analysis.
PluginAction, ///< Run a plugin action, \see ActionName.
PrintDeclContext, ///< Print DeclContext and their Decls.
@@ -137,6 +138,10 @@ public:
/// speed up parsing in cases you do
/// not need them (e.g. with code
/// completion).
+ unsigned UseGlobalModuleIndex : 1; ///< Whether we can use the
+ ///< global module index if available.
+ unsigned GenerateGlobalModuleIndex : 1; ///< Whether we can generate the
+ ///< global module index if needed.
CodeCompleteOptions CodeCompleteOpts;
@@ -204,20 +209,16 @@ public:
std::string OverrideRecordLayoutsFile;
public:
- FrontendOptions() {
- DisableFree = 0;
- ProgramAction = frontend::ParseSyntaxOnly;
- ActionName = "";
- RelocatablePCH = 0;
- ShowHelp = 0;
- ShowStats = 0;
- ShowTimers = 0;
- ShowVersion = 0;
- ARCMTAction = ARCMT_None;
- ARCMTMigrateEmitARCErrors = 0;
- SkipFunctionBodies = 0;
- ObjCMTAction = ObjCMT_None;
- }
+ FrontendOptions() :
+ DisableFree(false), RelocatablePCH(false), ShowHelp(false),
+ ShowStats(false), ShowTimers(false), ShowVersion(false),
+ FixWhatYouCan(false), FixOnlyWarnings(false), FixAndRecompile(false),
+ FixToTemporaries(false), ARCMTMigrateEmitARCErrors(false),
+ SkipFunctionBodies(false), UseGlobalModuleIndex(true),
+ GenerateGlobalModuleIndex(true),
+ ARCMTAction(ARCMT_None), ObjCMTAction(ObjCMT_None),
+ ProgramAction(frontend::ParseSyntaxOnly)
+ {}
/// getInputKindForExtension - Return the appropriate input kind for a file
/// extension. For example, "c" would return IK_C.
diff --git a/include/clang/Frontend/LangStandard.h b/include/clang/Frontend/LangStandard.h
index f07cb02..1124d53 100644
--- a/include/clang/Frontend/LangStandard.h
+++ b/include/clang/Frontend/LangStandard.h
@@ -23,7 +23,7 @@ enum LangFeatures {
C99 = (1 << 2),
C11 = (1 << 3),
CPlusPlus = (1 << 4),
- CPlusPlus0x = (1 << 5),
+ CPlusPlus11 = (1 << 5),
CPlusPlus1y = (1 << 6),
Digraphs = (1 << 7),
GNUMode = (1 << 8),
@@ -69,8 +69,8 @@ public:
/// isCPlusPlus - Language is a C++ variant.
bool isCPlusPlus() const { return Flags & frontend::CPlusPlus; }
- /// isCPlusPlus0x - Language is a C++0x variant.
- bool isCPlusPlus0x() const { return Flags & frontend::CPlusPlus0x; }
+ /// isCPlusPlus11 - Language is a C++0x variant.
+ bool isCPlusPlus11() const { return Flags & frontend::CPlusPlus11; }
/// isCPlusPlus1y - Language is a C++1y variant.
bool isCPlusPlus1y() const { return Flags & frontend::CPlusPlus1y; }
diff --git a/include/clang/Frontend/LangStandards.def b/include/clang/Frontend/LangStandards.def
index 10807b7..7b2516b 100644
--- a/include/clang/Frontend/LangStandards.def
+++ b/include/clang/Frontend/LangStandards.def
@@ -96,23 +96,23 @@ LANGSTANDARD(gnucxx98, "gnu++98",
LANGSTANDARD(cxx0x, "c++0x",
"ISO C++ 2011 with amendments",
- LineComment | CPlusPlus | CPlusPlus0x | Digraphs)
+ LineComment | CPlusPlus | CPlusPlus11 | Digraphs)
LANGSTANDARD(cxx11, "c++11",
"ISO C++ 2011 with amendments",
- LineComment | CPlusPlus | CPlusPlus0x | Digraphs)
+ LineComment | CPlusPlus | CPlusPlus11 | Digraphs)
LANGSTANDARD(gnucxx0x, "gnu++0x",
"ISO C++ 2011 with amendments and GNU extensions",
- LineComment | CPlusPlus | CPlusPlus0x | Digraphs | GNUMode)
+ LineComment | CPlusPlus | CPlusPlus11 | Digraphs | GNUMode)
LANGSTANDARD(gnucxx11, "gnu++11",
"ISO C++ 2011 with amendments and GNU extensions",
- LineComment | CPlusPlus | CPlusPlus0x | Digraphs | GNUMode)
+ LineComment | CPlusPlus | CPlusPlus11 | Digraphs | GNUMode)
LANGSTANDARD(cxx1y, "c++1y",
"Working draft for ISO C++ 2014",
- LineComment | CPlusPlus | CPlusPlus0x | CPlusPlus1y | Digraphs)
+ LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus1y | Digraphs)
LANGSTANDARD(gnucxx1y, "gnu++1y",
"Working draft for ISO C++ 2014 with GNU extensions",
- LineComment | CPlusPlus | CPlusPlus0x | CPlusPlus1y | Digraphs |
+ LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus1y | Digraphs |
GNUMode)
// OpenCL
diff --git a/include/clang/Frontend/LayoutOverrideSource.h b/include/clang/Frontend/LayoutOverrideSource.h
index 225efe6..ec34e14 100644
--- a/include/clang/Frontend/LayoutOverrideSource.h
+++ b/include/clang/Frontend/LayoutOverrideSource.h
@@ -11,6 +11,7 @@
#define LLVM_CLANG_FRONTEND_LAYOUTOVERRIDESOURCE_H
#include "clang/AST/ExternalASTSource.h"
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
@@ -31,7 +32,7 @@ namespace clang {
uint64_t Align;
/// \brief The offsets of the fields, in source order.
- llvm::SmallVector<uint64_t, 8> FieldOffsets;
+ SmallVector<uint64_t, 8> FieldOffsets;
};
/// \brief The set of layouts that will be overridden.
@@ -42,7 +43,7 @@ namespace clang {
/// set of record types.
///
/// The file is the result of passing -fdump-record-layouts to a file.
- explicit LayoutOverrideSource(llvm::StringRef Filename);
+ explicit LayoutOverrideSource(StringRef Filename);
/// \brief If this particular record type has an overridden layout,
/// return that layout.
diff --git a/include/clang/Frontend/LogDiagnosticPrinter.h b/include/clang/Frontend/LogDiagnosticPrinter.h
index f4fa876..0c700a7 100644
--- a/include/clang/Frontend/LogDiagnosticPrinter.h
+++ b/include/clang/Frontend/LogDiagnosticPrinter.h
@@ -12,8 +12,8 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceLocation.h"
-#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
namespace clang {
class DiagnosticOptions;
@@ -42,7 +42,7 @@ class LogDiagnosticPrinter : public DiagnosticConsumer {
raw_ostream &OS;
const LangOptions *LangOpts;
- llvm::IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
SourceLocation LastWarningLoc;
FullSourceLoc LastLoc;
diff --git a/include/clang/Frontend/MultiplexConsumer.h b/include/clang/Frontend/MultiplexConsumer.h
index 539f2c5..6ea7547 100644
--- a/include/clang/Frontend/MultiplexConsumer.h
+++ b/include/clang/Frontend/MultiplexConsumer.h
@@ -17,7 +17,6 @@
#include "clang/Basic/LLVM.h"
#include "clang/Sema/SemaConsumer.h"
-#include "clang/Basic/LLVM.h"
#include "llvm/ADT/OwningPtr.h"
#include <vector>
diff --git a/include/clang/Frontend/PreprocessorOutputOptions.h b/include/clang/Frontend/PreprocessorOutputOptions.h
index 9793aa6..e273dd6 100644
--- a/include/clang/Frontend/PreprocessorOutputOptions.h
+++ b/include/clang/Frontend/PreprocessorOutputOptions.h
@@ -25,7 +25,7 @@ public:
public:
PreprocessorOutputOptions() {
- ShowCPP = 1;
+ ShowCPP = 0;
ShowComments = 0;
ShowLineMarkers = 1;
ShowMacroComments = 0;
diff --git a/include/clang/Frontend/SerializedDiagnosticPrinter.h b/include/clang/Frontend/SerializedDiagnosticPrinter.h
index ab70afd..117771d 100644
--- a/include/clang/Frontend/SerializedDiagnosticPrinter.h
+++ b/include/clang/Frontend/SerializedDiagnosticPrinter.h
@@ -10,6 +10,7 @@
#ifndef LLVM_CLANG_FRONTEND_SERIALIZE_DIAGNOSTIC_PRINTER_H_
#define LLVM_CLANG_FRONTEND_SERIALIZE_DIAGNOSTIC_PRINTER_H_
+#include "clang/Basic/LLVM.h"
#include "llvm/Bitcode/BitstreamWriter.h"
namespace llvm {
@@ -53,7 +54,7 @@ enum RecordIDs {
/// This allows wrapper tools for Clang to get diagnostics from Clang
/// (via libclang) without needing to parse Clang's command line output.
///
-DiagnosticConsumer *create(llvm::raw_ostream *OS,
+DiagnosticConsumer *create(raw_ostream *OS,
DiagnosticOptions *diags);
} // end serialized_diags namespace
diff --git a/include/clang/Frontend/TextDiagnostic.h b/include/clang/Frontend/TextDiagnostic.h
index 51f841d..656aa57 100644
--- a/include/clang/Frontend/TextDiagnostic.h
+++ b/include/clang/Frontend/TextDiagnostic.h
@@ -18,8 +18,6 @@
#include "clang/Frontend/DiagnosticRenderer.h"
-struct SourceColumnMap;
-
namespace clang {
/// \brief Class to encapsulate the logic for formatting and printing a textual
@@ -103,6 +101,14 @@ protected:
virtual void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc,
const SourceManager &SM);
+ virtual void emitImportLocation(SourceLocation Loc, PresumedLoc PLoc,
+ StringRef ModuleName,
+ const SourceManager &SM);
+
+ virtual void emitBuildingModuleLocation(SourceLocation Loc, PresumedLoc PLoc,
+ StringRef ModuleName,
+ const SourceManager &SM);
+
private:
void emitSnippetAndCaret(SourceLocation Loc, DiagnosticsEngine::Level Level,
SmallVectorImpl<CharSourceRange>& Ranges,
@@ -111,16 +117,6 @@ private:
void emitSnippet(StringRef SourceLine);
- void highlightRange(const CharSourceRange &R,
- unsigned LineNo, FileID FID,
- const SourceColumnMap &map,
- std::string &CaretLine,
- const SourceManager &SM);
-
- std::string buildFixItInsertionLine(unsigned LineNo,
- const SourceColumnMap &map,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM);
void emitParseableFixits(ArrayRef<FixItHint> Hints, const SourceManager &SM);
};
diff --git a/include/clang/Frontend/TextDiagnosticPrinter.h b/include/clang/Frontend/TextDiagnosticPrinter.h
index 91ac3c8..470438e 100644
--- a/include/clang/Frontend/TextDiagnosticPrinter.h
+++ b/include/clang/Frontend/TextDiagnosticPrinter.h
@@ -17,8 +17,8 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LLVM.h"
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/OwningPtr.h"
namespace clang {
class DiagnosticOptions;
@@ -27,7 +27,7 @@ class TextDiagnostic;
class TextDiagnosticPrinter : public DiagnosticConsumer {
raw_ostream &OS;
- llvm::IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
/// \brief Handle to the currently active text diagnostic emitter.
OwningPtr<TextDiagnostic> TextDiag;
diff --git a/include/clang/Frontend/Utils.h b/include/clang/Frontend/Utils.h
index 6b1fc63..8830dce 100644
--- a/include/clang/Frontend/Utils.h
+++ b/include/clang/Frontend/Utils.h
@@ -60,7 +60,8 @@ void InitializePreprocessor(Preprocessor &PP,
/// ProcessWarningOptions - Initialize the diagnostic client and process the
/// warning options specified on the command line.
void ProcessWarningOptions(DiagnosticsEngine &Diags,
- const DiagnosticOptions &Opts);
+ const DiagnosticOptions &Opts,
+ bool ReportDiags = true);
/// DoPrintPreprocessedInput - Implement -E mode.
void DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream* OS,
diff --git a/include/clang/Lex/DirectoryLookup.h b/include/clang/Lex/DirectoryLookup.h
index d773fc6..261dfab 100644
--- a/include/clang/Lex/DirectoryLookup.h
+++ b/include/clang/Lex/DirectoryLookup.h
@@ -50,34 +50,34 @@ private:
/// SrcMgr::CharacteristicKind.
unsigned DirCharacteristic : 2;
- /// UserSupplied - True if this is a user-supplied directory.
- ///
- bool UserSupplied : 1;
-
/// LookupType - This indicates whether this DirectoryLookup object is a
/// normal directory, a framework, or a headermap.
unsigned LookupType : 2;
/// \brief Whether this is a header map used when building a framework.
unsigned IsIndexHeaderMap : 1;
+
+ /// \brief Whether we've performed an exhaustive search for module maps
+ /// within the subdirectories of this directory.
+ unsigned SearchedAllModuleMaps : 1;
public:
/// DirectoryLookup ctor - Note that this ctor *does not take ownership* of
/// 'dir'.
DirectoryLookup(const DirectoryEntry *dir, SrcMgr::CharacteristicKind DT,
- bool isUser, bool isFramework)
- : DirCharacteristic(DT), UserSupplied(isUser),
+ bool isFramework)
+ : DirCharacteristic(DT),
LookupType(isFramework ? LT_Framework : LT_NormalDir),
- IsIndexHeaderMap(false) {
+ IsIndexHeaderMap(false), SearchedAllModuleMaps(false) {
u.Dir = dir;
}
/// DirectoryLookup ctor - Note that this ctor *does not take ownership* of
/// 'map'.
DirectoryLookup(const HeaderMap *map, SrcMgr::CharacteristicKind DT,
- bool isUser, bool isIndexHeaderMap)
- : DirCharacteristic(DT), UserSupplied(isUser), LookupType(LT_HeaderMap),
- IsIndexHeaderMap(isIndexHeaderMap) {
+ bool isIndexHeaderMap)
+ : DirCharacteristic(DT), LookupType(LT_HeaderMap),
+ IsIndexHeaderMap(isIndexHeaderMap), SearchedAllModuleMaps(false) {
u.Map = map;
}
@@ -113,16 +113,22 @@ public:
/// isHeaderMap - Return true if this is a header map, not a normal directory.
bool isHeaderMap() const { return getLookupType() == LT_HeaderMap; }
+ /// \brief Determine whether we have already searched this entire
+ /// directory for module maps.
+ bool haveSearchedAllModuleMaps() const { return SearchedAllModuleMaps; }
+
+ /// \brief Specify whether we have already searched all of the subdirectories
+ /// for module maps.
+ void setSearchedAllModuleMaps(bool SAMM) {
+ SearchedAllModuleMaps = SAMM;
+ }
+
/// DirCharacteristic - The type of directory this is, one of the DirType enum
/// values.
SrcMgr::CharacteristicKind getDirCharacteristic() const {
return (SrcMgr::CharacteristicKind)DirCharacteristic;
}
- /// isUserSupplied - True if this is a user-supplied directory.
- ///
- bool isUserSupplied() const { return UserSupplied; }
-
/// \brief Whether this header map is building a framework or not.
bool isIndexHeaderMap() const {
return isHeaderMap() && IsIndexHeaderMap;
diff --git a/include/clang/Lex/ExternalPreprocessorSource.h b/include/clang/Lex/ExternalPreprocessorSource.h
index d2e2412..d9a4de4 100644
--- a/include/clang/Lex/ExternalPreprocessorSource.h
+++ b/include/clang/Lex/ExternalPreprocessorSource.h
@@ -15,7 +15,9 @@
#define LLVM_CLANG_LEX_EXTERNAL_PREPROCESSOR_SOURCE_H
namespace clang {
-
+
+class IdentifierInfo;
+
/// \brief Abstract interface for external sources of preprocessor
/// information.
///
diff --git a/include/clang/Lex/HeaderSearch.h b/include/clang/Lex/HeaderSearch.h
index 4334db7..8a5a798 100644
--- a/include/clang/Lex/HeaderSearch.h
+++ b/include/clang/Lex/HeaderSearch.h
@@ -18,10 +18,10 @@
#include "clang/Lex/ModuleMap.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Allocator.h"
-#include "llvm/ADT/OwningPtr.h"
#include <vector>
namespace clang {
@@ -50,6 +50,9 @@ struct HeaderFileInfo {
/// \brief Whether this header file info was supplied by an external source.
unsigned External : 1;
+
+ /// \brief Whether this header is part of a module.
+ unsigned isModuleHeader : 1;
/// \brief Whether this structure is considered to already have been
/// "resolved", meaning that it was loaded from the external source.
@@ -90,7 +93,8 @@ struct HeaderFileInfo {
HeaderFileInfo()
: isImport(false), isPragmaOnce(false), DirInfo(SrcMgr::C_User),
- External(false), Resolved(false), IndexHeaderMapHeader(false),
+ External(false), isModuleHeader(false), Resolved(false),
+ IndexHeaderMapHeader(false),
NumIncludes(0), ControllingMacroID(0), ControllingMacro(0) {}
/// \brief Retrieve the controlling macro for this header file, if
@@ -134,7 +138,7 @@ class HeaderSearch {
};
/// \brief Header-search options used to initialize this header search.
- llvm::IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts;
+ IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts;
FileManager &FileMgr;
/// \#include search path information. Requests for \#include "x" search the
@@ -189,7 +193,7 @@ class HeaderSearch {
std::vector<std::pair<const FileEntry*, const HeaderMap*> > HeaderMaps;
/// \brief The mapping between modules and headers.
- ModuleMap ModMap;
+ mutable ModuleMap ModMap;
/// \brief Describes whether a given directory has a module map in it.
llvm::DenseMap<const DirectoryEntry *, bool> DirectoryHasModuleMap;
@@ -217,7 +221,7 @@ class HeaderSearch {
friend class DirectoryLookup;
public:
- HeaderSearch(llvm::IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts,
+ HeaderSearch(IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts,
FileManager &FM, DiagnosticsEngine &Diags,
const LangOptions &LangOpts, const TargetInfo *Target);
~HeaderSearch();
@@ -363,7 +367,8 @@ public:
StringRef Filename,
const FileEntry *RelativeFileEnt,
SmallVectorImpl<char> *SearchPath,
- SmallVectorImpl<char> *RelativePath);
+ SmallVectorImpl<char> *RelativePath,
+ Module **SuggestedModule);
/// \brief Look up the specified framework name in our framework cache.
/// \returns The DirectoryEntry it is in if we know, null otherwise.
@@ -399,6 +404,9 @@ public:
getFileInfo(File).DirInfo = SrcMgr::C_System;
}
+ /// \brief Mark the specified file as part of a module.
+ void MarkFileModuleHeader(const FileEntry *File);
+
/// \brief Increment the count for the number of times the specified
/// FileEntry has been entered.
void IncrementIncludeCount(const FileEntry *File) {
@@ -468,7 +476,7 @@ public:
/// \brief Retrieve the module that corresponds to the given file, if any.
///
/// \param File The header that we wish to map to a module.
- Module *findModuleForHeader(const FileEntry *File);
+ Module *findModuleForHeader(const FileEntry *File) const;
/// \brief Read the contents of the given module map file.
///
@@ -480,7 +488,7 @@ public:
/// \brief Collect the set of all known, top-level modules.
///
/// \param Modules Will be filled with the set of known, top-level modules.
- void collectAllModules(llvm::SmallVectorImpl<Module *> &Modules);
+ void collectAllModules(SmallVectorImpl<Module *> &Modules);
private:
/// \brief Retrieve a module with the given name, which may be part of the
@@ -497,7 +505,11 @@ private:
Module *loadFrameworkModule(StringRef Name,
const DirectoryEntry *Dir,
bool IsSystem);
-
+
+ /// \brief Load all of the module maps within the immediate subdirectories
+ /// of the given search directory.
+ void loadSubdirectoryModuleMaps(DirectoryLookup &SearchDir);
+
public:
/// \brief Retrieve the module map.
ModuleMap &getModuleMap() { return ModMap; }
diff --git a/include/clang/Lex/HeaderSearchOptions.h b/include/clang/Lex/HeaderSearchOptions.h
index 468fefa..afce5ba 100644
--- a/include/clang/Lex/HeaderSearchOptions.h
+++ b/include/clang/Lex/HeaderSearchOptions.h
@@ -10,8 +10,11 @@
#ifndef LLVM_CLANG_LEX_HEADERSEARCHOPTIONS_H
#define LLVM_CLANG_LEX_HEADERSEARCHOPTIONS_H
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/StringRef.h"
+#include <string>
#include <vector>
namespace clang {
@@ -27,6 +30,8 @@ namespace frontend {
IndexHeaderMap, ///< Like Angled, but marks header maps used when
/// building frameworks.
System, ///< Like Angled, but marks system directories.
+ ExternCSystem, ///< Like System, but headers are implicitly wrapped in
+ /// extern "C".
CSystem, ///< Like System, but only used for C.
CXXSystem, ///< Like System, but only used for C++.
ObjCSystem, ///< Like System, but only used for ObjC.
@@ -37,12 +42,11 @@ namespace frontend {
/// HeaderSearchOptions - Helper class for storing options related to the
/// initialization of the HeaderSearch object.
-class HeaderSearchOptions : public llvm::RefCountedBase<HeaderSearchOptions> {
+class HeaderSearchOptions : public RefCountedBase<HeaderSearchOptions> {
public:
struct Entry {
std::string Path;
frontend::IncludeDirGroup Group;
- unsigned IsUserSupplied : 1;
unsigned IsFramework : 1;
/// IgnoreSysRoot - This is false if an absolute path should be treated
@@ -50,24 +54,10 @@ public:
/// path.
unsigned IgnoreSysRoot : 1;
- /// \brief True if this entry is an internal search path.
- ///
- /// This typically indicates that users didn't directly provide it, but
- /// instead it was provided by a compatibility layer for a particular
- /// system. This isn't redundant with IsUserSupplied (even though perhaps
- /// it should be) because that is false for user provided '-iwithprefix'
- /// header search entries.
- unsigned IsInternal : 1;
-
- /// \brief True if this entry's headers should be wrapped in extern "C".
- unsigned ImplicitExternC : 1;
-
- Entry(StringRef path, frontend::IncludeDirGroup group,
- bool isUserSupplied, bool isFramework, bool ignoreSysRoot,
- bool isInternal, bool implicitExternC)
- : Path(path), Group(group), IsUserSupplied(isUserSupplied),
- IsFramework(isFramework), IgnoreSysRoot(ignoreSysRoot),
- IsInternal(isInternal), ImplicitExternC(implicitExternC) {}
+ Entry(StringRef path, frontend::IncludeDirGroup group, bool isFramework,
+ bool ignoreSysRoot)
+ : Path(path), Group(group), IsFramework(isFramework),
+ IgnoreSysRoot(ignoreSysRoot) {}
};
struct SystemHeaderPrefix {
@@ -98,13 +88,35 @@ public:
/// \brief The directory used for the module cache.
std::string ModuleCachePath;
-
+
/// \brief Whether we should disable the use of the hash string within the
/// module cache.
///
/// Note: Only used for testing!
unsigned DisableModuleHash : 1;
-
+
+ /// \brief The interval (in seconds) between pruning operations.
+ ///
+ /// This operation is expensive, because it requires Clang to walk through
+ /// the directory structure of the module cache, stat()'ing and removing
+ /// files.
+ ///
+ /// The default value is large, e.g., the operation runs once a week.
+ unsigned ModuleCachePruneInterval;
+
+ /// \brief The time (in seconds) after which an unused module file will be
+ /// considered unused and will, therefore, be pruned.
+ ///
+ /// When the module cache is pruned, any module file that has not been
+ /// accessed in this many seconds will be removed. The default value is
+ /// large, e.g., a month, to avoid forcing infrequently-used modules to be
+ /// regenerated often.
+ unsigned ModuleCachePruneAfter;
+
+ /// \brief The set of macro names that should be ignored for the purposes
+ /// of computing the module hash.
+ llvm::SetVector<std::string> ModulesIgnoreMacros;
+
/// Include the compiler builtin includes.
unsigned UseBuiltinIncludes : 1;
@@ -122,16 +134,17 @@ public:
public:
HeaderSearchOptions(StringRef _Sysroot = "/")
- : Sysroot(_Sysroot), DisableModuleHash(0), UseBuiltinIncludes(true),
+ : Sysroot(_Sysroot), DisableModuleHash(0),
+ ModuleCachePruneInterval(7*24*60*60),
+ ModuleCachePruneAfter(31*24*60*60),
+ UseBuiltinIncludes(true),
UseStandardSystemIncludes(true), UseStandardCXXIncludes(true),
UseLibcxx(false), Verbose(false) {}
/// AddPath - Add the \p Path path to the specified \p Group list.
void AddPath(StringRef Path, frontend::IncludeDirGroup Group,
- bool IsUserSupplied, bool IsFramework, bool IgnoreSysRoot,
- bool IsInternal = false, bool ImplicitExternC = false) {
- UserEntries.push_back(Entry(Path, Group, IsUserSupplied, IsFramework,
- IgnoreSysRoot, IsInternal, ImplicitExternC));
+ bool IsFramework, bool IgnoreSysRoot) {
+ UserEntries.push_back(Entry(Path, Group, IsFramework, IgnoreSysRoot));
}
/// AddSystemHeaderPrefix - Override whether \#include directives naming a
diff --git a/include/clang/Lex/Lexer.h b/include/clang/Lex/Lexer.h
index 407b644..cb4f57f 100644
--- a/include/clang/Lex/Lexer.h
+++ b/include/clang/Lex/Lexer.h
@@ -14,11 +14,11 @@
#ifndef LLVM_CLANG_LEXER_H
#define LLVM_CLANG_LEXER_H
-#include "clang/Lex/PreprocessorLexer.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Lex/PreprocessorLexer.h"
#include "llvm/ADT/SmallVector.h"
-#include <string>
#include <cassert>
+#include <string>
namespace clang {
class DiagnosticsEngine;
@@ -174,8 +174,8 @@ public:
/// SetKeepWhitespaceMode - This method lets clients enable or disable
/// whitespace retention mode.
void SetKeepWhitespaceMode(bool Val) {
- assert((!Val || LexingRawMode) &&
- "Can only enable whitespace retention in raw mode");
+ assert((!Val || LexingRawMode || LangOpts.TraditionalCPP) &&
+ "Can only retain whitespace in raw mode or -traditional-cpp");
ExtendedTokenMode = Val ? 2 : 0;
}
@@ -194,6 +194,14 @@ public:
ExtendedTokenMode = Mode ? 1 : 0;
}
+ /// Sets the extended token mode back to its initial value, according to the
+ /// language options and preprocessor. This controls whether the lexer
+ /// produces comment and whitespace tokens.
+ ///
+ /// This requires the lexer to have an associated preprocessor. A standalone
+ /// lexer has nothing to reset to.
+ void resetExtendedTokenMode();
+
const char *getBufferStart() const { return BufferStart; }
/// ReadToEndOfLine - Read the rest of the current preprocessor line as an
@@ -260,10 +268,10 @@ public:
/// location and does not jump to the expansion or spelling
/// location.
static StringRef getSpelling(SourceLocation loc,
- SmallVectorImpl<char> &buffer,
- const SourceManager &SourceMgr,
- const LangOptions &LangOpts,
- bool *invalid = 0);
+ SmallVectorImpl<char> &buffer,
+ const SourceManager &SourceMgr,
+ const LangOptions &LangOpts,
+ bool *invalid = 0);
/// MeasureTokenLength - Relex the token at the specified location and return
/// its length in bytes in the input file. If the token needs cleaning (e.g.
@@ -273,6 +281,12 @@ public:
const SourceManager &SM,
const LangOptions &LangOpts);
+ /// \brief Relex the token at the specified location.
+ /// \returns true if there was a failure, false on success.
+ static bool getRawToken(SourceLocation Loc, Token &Result,
+ const SourceManager &SM,
+ const LangOptions &LangOpts);
+
/// \brief Given a location any where in a source buffer, find the location
/// that corresponds to the beginning of the token in which the original
/// source location lands.
@@ -431,6 +445,11 @@ private:
///
void LexTokenInternal(Token &Result);
+ /// Given that a token begins with the Unicode character \p C, figure out
+ /// what kind of token it is and dispatch to the appropriate lexing helper
+ /// function.
+ void LexUnicode(Token &Result, uint32_t C, const char *CurPtr);
+
/// FormTokenWithChars - When we lex a token, we have identified a span
/// starting at BufferPtr, going to TokEnd that forms the token. This method
/// takes that range and assigns it to the token as its location and size. In
@@ -573,6 +592,21 @@ private:
void cutOffLexing() { BufferPtr = BufferEnd; }
bool isHexaLiteral(const char *Start, const LangOptions &LangOpts);
+
+
+ /// Read a universal character name.
+ ///
+ /// \param CurPtr The position in the source buffer after the initial '\'.
+ /// If the UCN is syntactically well-formed (but not necessarily
+ /// valid), this parameter will be updated to point to the
+ /// character after the UCN.
+ /// \param SlashLoc The position in the source buffer of the '\'.
+ /// \param Tok The token being formed. Pass \c NULL to suppress diagnostics
+ /// and handle token formation in the caller.
+ ///
+ /// \return The Unicode codepoint specified by the UCN, or 0 if the UCN is
+ /// invalid.
+ uint32_t tryReadUCN(const char *&CurPtr, const char *SlashLoc, Token *Tok);
};
diff --git a/include/clang/Lex/LiteralSupport.h b/include/clang/Lex/LiteralSupport.h
index 3b68d1b..b1430cc 100644
--- a/include/clang/Lex/LiteralSupport.h
+++ b/include/clang/Lex/LiteralSupport.h
@@ -15,13 +15,13 @@
#ifndef CLANG_LITERALSUPPORT_H
#define CLANG_LITERALSUPPORT_H
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/LLVM.h"
+#include "clang/Basic/TokenKinds.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/DataTypes.h"
-#include "clang/Basic/TokenKinds.h"
-#include <cctype>
namespace clang {
@@ -101,7 +101,7 @@ private:
/// SkipHexDigits - Read and skip over any hex digits, up to End.
/// Return a pointer to the first non-hex digit or End.
const char *SkipHexDigits(const char *ptr) {
- while (ptr != ThisTokEnd && isxdigit(*ptr))
+ while (ptr != ThisTokEnd && isHexDigit(*ptr))
ptr++;
return ptr;
}
@@ -117,7 +117,7 @@ private:
/// SkipDigits - Read and skip over any digits, up to End.
/// Return a pointer to the first non-hex digit or End.
const char *SkipDigits(const char *ptr) {
- while (ptr != ThisTokEnd && isdigit(*ptr))
+ while (ptr != ThisTokEnd && isDigit(*ptr))
ptr++;
return ptr;
}
diff --git a/include/clang/Lex/MacroInfo.h b/include/clang/Lex/MacroInfo.h
index aba77d5..64323b7 100644
--- a/include/clang/Lex/MacroInfo.h
+++ b/include/clang/Lex/MacroInfo.h
@@ -6,9 +6,10 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-//
-// This file defines the MacroInfo interface.
-//
+///
+/// \file
+/// \brief Defines the clang::MacroInfo and clang::MacroDirective classes.
+///
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_MACROINFO_H
@@ -22,34 +23,28 @@
namespace clang {
class Preprocessor;
-/// MacroInfo - Each identifier that is \#define'd has an instance of this class
-/// associated with it, used to implement macro expansion.
+/// \brief Encapsulates the data about a macro definition (e.g. its tokens).
+///
+/// There's an instance of this class for every #define.
class MacroInfo {
//===--------------------------------------------------------------------===//
// State set when the macro is defined.
- /// Location - This is the place the macro is defined.
+ /// \brief The location the macro is defined.
SourceLocation Location;
- /// EndLocation - The location of the last token in the macro.
+ /// \brief The location of the last token in the macro.
SourceLocation EndLocation;
- /// \brief The location where the macro was #undef'd, or an invalid location
- /// for macros that haven't been undefined.
- SourceLocation UndefLocation;
- /// \brief Previous definition, the identifier of this macro was defined to,
- /// or NULL.
- MacroInfo *PreviousDefinition;
- /// Arguments - The list of arguments for a function-like macro. This can be
- /// empty, for, e.g. "#define X()". In a C99-style variadic macro, this
+ /// \brief The list of arguments for a function-like macro.
+ ///
+ /// ArgumentList points to the first of NumArguments pointers.
+ ///
+ /// This can be empty, for, e.g. "#define X()". In a C99-style variadic macro, this
/// includes the \c __VA_ARGS__ identifier on the list.
IdentifierInfo **ArgumentList;
- unsigned NumArguments;
- /// \brief The location at which this macro was either explicitly exported
- /// from its module or marked as private.
- ///
- /// If invalid, this macro has not been explicitly given any visibility.
- SourceLocation VisibilityLocation;
+ /// \see ArgumentList
+ unsigned NumArguments;
/// \brief This is the list of tokens that the macro is defined to.
SmallVector<Token, 8> ReplacementTokens;
@@ -58,119 +53,88 @@ class MacroInfo {
mutable unsigned DefinitionLength;
mutable bool IsDefinitionLengthCached : 1;
- /// \brief True if this macro is a function-like macro, false if it
- /// is an object-like macro.
+ /// \brief True if this macro is function-like, false if it is object-like.
bool IsFunctionLike : 1;
- /// IsC99Varargs - True if this macro is of the form "#define X(...)" or
- /// "#define X(Y,Z,...)". The __VA_ARGS__ token should be replaced with the
- /// contents of "..." in an invocation.
+ /// \brief True if this macro is of the form "#define X(...)" or
+ /// "#define X(Y,Z,...)".
+ ///
+ /// The __VA_ARGS__ token should be replaced with the contents of "..." in an
+ /// invocation.
bool IsC99Varargs : 1;
- /// IsGNUVarargs - True if this macro is of the form "#define X(a...)". The
- /// "a" identifier in the replacement list will be replaced with all arguments
+ /// \brief True if this macro is of the form "#define X(a...)".
+ ///
+ /// The "a" identifier in the replacement list will be replaced with all arguments
/// of the macro starting with the specified one.
bool IsGNUVarargs : 1;
- /// IsBuiltinMacro - True if this is a builtin macro, such as __LINE__, and if
- /// it has not yet been redefined or undefined.
+ /// \brief True if this macro requires processing before expansion.
+ ///
+ /// This is the case for builtin macros such as __LINE__, so long as they have
+ /// not been redefined, but not for regular predefined macros from the "<built-in>"
+ /// memory buffer (see Preprocessing::getPredefinesFileID).
bool IsBuiltinMacro : 1;
- /// \brief True if this macro was loaded from an AST file.
- bool IsFromAST : 1;
-
- /// \brief Whether this macro changed after it was loaded from an AST file.
- bool ChangedAfterLoad : 1;
+ /// \brief Whether this macro contains the sequence ", ## __VA_ARGS__"
+ bool HasCommaPasting : 1;
private:
//===--------------------------------------------------------------------===//
// State that changes as the macro is used.
- /// IsDisabled - True if we have started an expansion of this macro already.
+ /// \brief True if we have started an expansion of this macro already.
+ ///
/// This disables recursive expansion, which would be quite bad for things
/// like \#define A A.
bool IsDisabled : 1;
- /// IsUsed - True if this macro is either defined in the main file and has
- /// been used, or if it is not defined in the main file. This is used to
- /// emit -Wunused-macros diagnostics.
+ /// \brief True if this macro is either defined in the main file and has
+ /// been used, or if it is not defined in the main file.
+ ///
+ /// This is used to emit -Wunused-macros diagnostics.
bool IsUsed : 1;
- /// AllowRedefinitionsWithoutWarning - True if this macro can be redefined
- /// without emitting a warning.
+ /// \brief True if this macro can be redefined without emitting a warning.
bool IsAllowRedefinitionsWithoutWarning : 1;
/// \brief Must warn if the macro is unused at the end of translation unit.
bool IsWarnIfUnused : 1;
-
- /// \brief Whether the macro has public (when described in a module).
- bool IsPublic : 1;
- /// \brief Whether the macro definition is currently "hidden".
- /// Note that this is transient state that is never serialized to the AST
- /// file.
- bool IsHidden : 1;
+ /// \brief Whether this macro info was loaded from an AST file.
+ unsigned FromASTFile : 1;
- /// \brief Whether the definition of this macro is ambiguous, due to
- /// multiple definitions coming in from multiple modules.
- bool IsAmbiguous : 1;
-
- ~MacroInfo() {
+ ~MacroInfo() {
assert(ArgumentList == 0 && "Didn't call destroy before dtor!");
}
public:
MacroInfo(SourceLocation DefLoc);
- MacroInfo(const MacroInfo &MI, llvm::BumpPtrAllocator &PPAllocator);
- /// FreeArgumentList - Free the argument list of the macro, restoring it to a
- /// state where it can be reused for other devious purposes.
+ /// \brief Free the argument list of the macro.
+ ///
+ /// This restores this MacroInfo to a state where it can be reused for other
+ /// devious purposes.
void FreeArgumentList() {
ArgumentList = 0;
NumArguments = 0;
}
- /// Destroy - destroy this MacroInfo object.
+ /// \brief Destroy this MacroInfo object.
void Destroy() {
FreeArgumentList();
this->~MacroInfo();
}
- /// getDefinitionLoc - Return the location that the macro was defined at.
- ///
+ /// \brief Return the location that the macro was defined at.
SourceLocation getDefinitionLoc() const { return Location; }
- /// setDefinitionEndLoc - Set the location of the last token in the macro.
- ///
+ /// \brief Set the location of the last token in the macro.
void setDefinitionEndLoc(SourceLocation EndLoc) { EndLocation = EndLoc; }
- /// getDefinitionEndLoc - Return the location of the last token in the macro.
- ///
+ /// \brief Return the location of the last token in the macro.
SourceLocation getDefinitionEndLoc() const { return EndLocation; }
- /// \brief Set the location where macro was undefined. Can only be set once.
- void setUndefLoc(SourceLocation UndefLoc) {
- assert(UndefLocation.isInvalid() && "UndefLocation is already set!");
- assert(UndefLoc.isValid() && "Invalid UndefLoc!");
- UndefLocation = UndefLoc;
- }
-
- /// \brief Get the location where macro was undefined.
- SourceLocation getUndefLoc() const { return UndefLocation; }
-
- /// \brief Set previous definition of the macro with the same name.
- void setPreviousDefinition(MacroInfo *PreviousDef) {
- PreviousDefinition = PreviousDef;
- }
-
- /// \brief Get previous definition of the macro with the same name.
- MacroInfo *getPreviousDefinition() { return PreviousDefinition; }
-
- /// \brief Find macro definition active in the specified source location. If
- /// this macro was not defined there, return NULL.
- const MacroInfo *findDefinitionAtLoc(SourceLocation L,
- SourceManager &SM) const;
-
/// \brief Get length in characters of the macro definition.
unsigned getDefinitionLength(SourceManager &SM) const {
if (IsDefinitionLengthCached)
@@ -178,25 +142,27 @@ public:
return getDefinitionLengthSlow(SM);
}
- /// isIdenticalTo - Return true if the specified macro definition is equal to
- /// this macro in spelling, arguments, and whitespace. This is used to emit
- /// duplicate definition warnings. This implements the rules in C99 6.10.3.
- bool isIdenticalTo(const MacroInfo &Other, Preprocessor &PP) const;
-
- /// setIsBuiltinMacro - Set or clear the isBuiltinMacro flag.
+ /// \brief Return true if the specified macro definition is equal to
+ /// this macro in spelling, arguments, and whitespace.
///
+ /// \param Syntactically if true, the macro definitions can be identical even
+ /// if they use different identifiers for the function macro parameters.
+ /// Otherwise the comparison is lexical and this implements the rules in
+ /// C99 6.10.3.
+ bool isIdenticalTo(const MacroInfo &Other, Preprocessor &PP,
+ bool Syntactically) const;
+
+ /// \brief Set or clear the isBuiltinMacro flag.
void setIsBuiltinMacro(bool Val = true) {
IsBuiltinMacro = Val;
}
- /// setIsUsed - Set the value of the IsUsed flag.
- ///
+ /// \brief Set the value of the IsUsed flag.
void setIsUsed(bool Val) {
IsUsed = Val;
}
- /// setIsAllowRedefinitionsWithoutWarning - Set the value of the
- /// IsAllowRedefinitionsWithoutWarning flag.
+ /// \brief Set the value of the IsAllowRedefinitionsWithoutWarning flag.
void setIsAllowRedefinitionsWithoutWarning(bool Val) {
IsAllowRedefinitionsWithoutWarning = Val;
}
@@ -206,8 +172,8 @@ public:
IsWarnIfUnused = val;
}
- /// setArgumentList - Set the specified list of identifiers as the argument
- /// list for this macro.
+ /// \brief Set the specified list of identifiers as the argument list for
+ /// this macro.
void setArgumentList(IdentifierInfo* const *List, unsigned NumArgs,
llvm::BumpPtrAllocator &PPAllocator) {
assert(ArgumentList == 0 && NumArguments == 0 &&
@@ -228,7 +194,7 @@ public:
arg_iterator arg_end() const { return ArgumentList+NumArguments; }
unsigned getNumArgs() const { return NumArguments; }
- /// getArgumentNum - Return the argument number of the specified identifier,
+ /// \brief Return the argument number of the specified identifier,
/// or -1 if the identifier is not a formal argument identifier.
int getArgumentNum(IdentifierInfo *Arg) const {
for (arg_iterator I = arg_begin(), E = arg_end(); I != E; ++I)
@@ -249,30 +215,22 @@ public:
bool isGNUVarargs() const { return IsGNUVarargs; }
bool isVariadic() const { return IsC99Varargs | IsGNUVarargs; }
- /// isBuiltinMacro - Return true if this macro is a builtin macro, such as
- /// __LINE__, which requires processing before expansion.
+ /// \brief Return true if this macro requires processing before expansion.
+ ///
+ /// This is true only for builtin macro, such as \__LINE__, whose values
+ /// are not given by fixed textual expansions. Regular predefined macros
+ /// from the "<built-in>" buffer are not reported as builtins by this
+ /// function.
bool isBuiltinMacro() const { return IsBuiltinMacro; }
- /// isFromAST - Return true if this macro was loaded from an AST file.
- bool isFromAST() const { return IsFromAST; }
-
- /// setIsFromAST - Set whether this macro was loaded from an AST file.
- void setIsFromAST(bool FromAST = true) { IsFromAST = FromAST; }
+ bool hasCommaPasting() const { return HasCommaPasting; }
+ void setHasCommaPasting() { HasCommaPasting = true; }
- /// \brief Determine whether this macro has changed since it was loaded from
- /// an AST file.
- bool hasChangedAfterLoad() const { return ChangedAfterLoad; }
-
- /// \brief Note whether this macro has changed after it was loaded from an
- /// AST file.
- void setChangedAfterLoad(bool CAL = true) { ChangedAfterLoad = CAL; }
-
- /// isUsed - Return false if this macro is defined in the main file and has
+ /// \brief Return false if this macro is defined in the main file and has
/// not yet been used.
bool isUsed() const { return IsUsed; }
- /// isAllowRedefinitionsWithoutWarning - Return true if this macro can be
- /// redefined without warning.
+ /// \brief Return true if this macro can be redefined without warning.
bool isAllowRedefinitionsWithoutWarning() const {
return IsAllowRedefinitionsWithoutWarning;
}
@@ -282,7 +240,7 @@ public:
return IsWarnIfUnused;
}
- /// getNumTokens - Return the number of tokens that this macro expands to.
+ /// \brief Return the number of tokens that this macro expands to.
///
unsigned getNumTokens() const {
return ReplacementTokens.size();
@@ -298,16 +256,16 @@ public:
tokens_iterator tokens_end() const { return ReplacementTokens.end(); }
bool tokens_empty() const { return ReplacementTokens.empty(); }
- /// AddTokenToBody - Add the specified token to the replacement text for the
- /// macro.
+ /// \brief Add the specified token to the replacement text for the macro.
void AddTokenToBody(const Token &Tok) {
assert(!IsDefinitionLengthCached &&
"Changing replacement tokens after definition length got calculated");
ReplacementTokens.push_back(Tok);
}
- /// isEnabled - Return true if this macro is enabled: in other words, that we
- /// are not currently in an expansion of this macro.
+ /// \brief Return true if this macro is enabled.
+ ///
+ /// In other words, that we are not currently in an expansion of this macro.
bool isEnabled() const { return !IsDisabled; }
void EnableMacro() {
@@ -320,41 +278,272 @@ public:
IsDisabled = true;
}
- /// \brief Set the export location for this macro.
- void setVisibility(bool Public, SourceLocation Loc) {
- VisibilityLocation = Loc;
- IsPublic = Public;
+ /// \brief Determine whether this macro info came from an AST file (such as
+ /// a precompiled header or module) rather than having been parsed.
+ bool isFromASTFile() const { return FromASTFile; }
+
+ /// \brief Retrieve the global ID of the module that owns this particular
+ /// macro info.
+ unsigned getOwningModuleID() const {
+ if (isFromASTFile())
+ return *(const unsigned*)(this+1);
+
+ return 0;
}
- /// \brief Determine whether this macro is part of the public API of its
- /// module.
- bool isPublic() const { return IsPublic; }
-
- /// \brief Determine the location where this macro was explicitly made
- /// public or private within its module.
- SourceLocation getVisibilityLocation() { return VisibilityLocation; }
+private:
+ unsigned getDefinitionLengthSlow(SourceManager &SM) const;
+
+ void setOwningModuleID(unsigned ID) {
+ assert(isFromASTFile());
+ *(unsigned*)(this+1) = ID;
+ }
+
+ friend class Preprocessor;
+};
+
+class DefMacroDirective;
+
+/// \brief Encapsulates changes to the "macros namespace" (the location where
+/// the macro name became active, the location where it was undefined, etc.).
+///
+/// MacroDirectives, associated with an identifier, are used to model the macro
+/// history. Usually a macro definition (MacroInfo) is where a macro name
+/// becomes active (MacroDirective) but modules can have their own macro
+/// history, separate from the local (current translation unit) macro history.
+///
+/// For example, if "@import A;" imports macro FOO, there will be a new local
+/// MacroDirective created to indicate that "FOO" became active at the import
+/// location. Module "A" itself will contain another MacroDirective in its macro
+/// history (at the point of the definition of FOO) and both MacroDirectives
+/// will point to the same MacroInfo object.
+///
+class MacroDirective {
+public:
+ enum Kind {
+ MD_Define,
+ MD_Undefine,
+ MD_Visibility
+ };
+
+protected:
+ /// \brief Previous macro directive for the same identifier, or NULL.
+ MacroDirective *Previous;
+
+ SourceLocation Loc;
+
+ /// \brief MacroDirective kind.
+ unsigned MDKind : 2;
+
+ /// \brief True if the macro directive was loaded from a PCH file.
+ bool IsFromPCH : 1;
- /// \brief Determine whether this macro is currently defined (and has not
- /// been #undef'd) or has been hidden.
- bool isDefined() const { return UndefLocation.isInvalid() && !IsHidden; }
+ /// \brief Whether the macro directive is currently "hidden".
+ ///
+ /// Note that this is transient state that is never serialized to the AST
+ /// file.
+ bool IsHidden : 1;
+
+ // Used by DefMacroDirective -----------------------------------------------//
- /// \brief Determine whether this macro definition is hidden.
+ /// \brief True if this macro was imported from a module.
+ bool IsImported : 1;
+
+ /// \brief Whether the definition of this macro is ambiguous, due to
+ /// multiple definitions coming in from multiple modules.
+ bool IsAmbiguous : 1;
+
+ // Used by VisibilityMacroDirective ----------------------------------------//
+
+ /// \brief Whether the macro has public visibility (when described in a
+ /// module).
+ bool IsPublic : 1;
+
+ MacroDirective(Kind K, SourceLocation Loc)
+ : Previous(0), Loc(Loc), MDKind(K), IsFromPCH(false), IsHidden(false),
+ IsImported(false), IsAmbiguous(false),
+ IsPublic(true) {
+ }
+
+public:
+ Kind getKind() const { return Kind(MDKind); }
+
+ SourceLocation getLocation() const { return Loc; }
+
+ /// \brief Set previous definition of the macro with the same name.
+ void setPrevious(MacroDirective *Prev) {
+ Previous = Prev;
+ }
+
+ /// \brief Get previous definition of the macro with the same name.
+ const MacroDirective *getPrevious() const { return Previous; }
+
+ /// \brief Get previous definition of the macro with the same name.
+ MacroDirective *getPrevious() { return Previous; }
+
+ /// \brief Return true if the macro directive was loaded from a PCH file.
+ bool isFromPCH() const { return IsFromPCH; }
+
+ void setIsFromPCH() { IsFromPCH = true; }
+
+ /// \brief Determine whether this macro directive is hidden.
bool isHidden() const { return IsHidden; }
- /// \brief Set whether this macro definition is hidden.
+ /// \brief Set whether this macro directive is hidden.
void setHidden(bool Val) { IsHidden = Val; }
+ class DefInfo {
+ DefMacroDirective *DefDirective;
+ SourceLocation UndefLoc;
+ bool IsPublic;
+
+ public:
+ DefInfo() : DefDirective(0) { }
+
+ DefInfo(DefMacroDirective *DefDirective, SourceLocation UndefLoc,
+ bool isPublic)
+ : DefDirective(DefDirective), UndefLoc(UndefLoc), IsPublic(isPublic) { }
+
+ const DefMacroDirective *getDirective() const { return DefDirective; }
+ DefMacroDirective *getDirective() { return DefDirective; }
+
+ inline SourceLocation getLocation() const;
+ inline MacroInfo *getMacroInfo();
+ const MacroInfo *getMacroInfo() const {
+ return const_cast<DefInfo*>(this)->getMacroInfo();
+ }
+
+ SourceLocation getUndefLocation() const { return UndefLoc; }
+ bool isUndefined() const { return UndefLoc.isValid(); }
+
+ bool isPublic() const { return IsPublic; }
+
+ bool isValid() const { return DefDirective != 0; }
+ bool isInvalid() const { return !isValid(); }
+
+ operator bool() const { return isValid(); }
+
+ inline DefInfo getPreviousDefinition(bool AllowHidden = false);
+ const DefInfo getPreviousDefinition(bool AllowHidden = false) const {
+ return const_cast<DefInfo*>(this)->getPreviousDefinition(AllowHidden);
+ }
+ };
+
+ /// \brief Traverses the macro directives history and returns the next
+ /// macro definition directive along with info about its undefined location
+ /// (if there is one) and if it is public or private.
+ DefInfo getDefinition(bool AllowHidden = false);
+ const DefInfo getDefinition(bool AllowHidden = false) const {
+ return const_cast<MacroDirective*>(this)->getDefinition(AllowHidden);
+ }
+
+ bool isDefined(bool AllowHidden = false) const {
+ if (const DefInfo Def = getDefinition(AllowHidden))
+ return !Def.isUndefined();
+ return false;
+ }
+
+ const MacroInfo *getMacroInfo(bool AllowHidden = false) const {
+ return getDefinition(AllowHidden).getMacroInfo();
+ }
+ MacroInfo *getMacroInfo(bool AllowHidden = false) {
+ return getDefinition(AllowHidden).getMacroInfo();
+ }
+
+ /// \brief Find macro definition active in the specified source location. If
+ /// this macro was not defined there, return NULL.
+ const DefInfo findDirectiveAtLoc(SourceLocation L, SourceManager &SM) const;
+
+ static bool classof(const MacroDirective *) { return true; }
+};
+
+/// \brief A directive for a defined macro or a macro imported from a module.
+class DefMacroDirective : public MacroDirective {
+ MacroInfo *Info;
+
+public:
+ explicit DefMacroDirective(MacroInfo *MI)
+ : MacroDirective(MD_Define, MI->getDefinitionLoc()), Info(MI) {
+ assert(MI && "MacroInfo is null");
+ }
+
+ DefMacroDirective(MacroInfo *MI, SourceLocation Loc, bool isImported)
+ : MacroDirective(MD_Define, Loc), Info(MI) {
+ assert(MI && "MacroInfo is null");
+ IsImported = isImported;
+ }
+
+ /// \brief The data for the macro definition.
+ const MacroInfo *getInfo() const { return Info; }
+ MacroInfo *getInfo() { return Info; }
+
+ /// \brief True if this macro was imported from a module.
+ bool isImported() const { return IsImported; }
+
/// \brief Determine whether this macro definition is ambiguous with
/// other macro definitions.
bool isAmbiguous() const { return IsAmbiguous; }
/// \brief Set whether this macro definition is ambiguous.
void setAmbiguous(bool Val) { IsAmbiguous = Val; }
-
-private:
- unsigned getDefinitionLengthSlow(SourceManager &SM) const;
+
+ static bool classof(const MacroDirective *MD) {
+ return MD->getKind() == MD_Define;
+ }
+ static bool classof(const DefMacroDirective *) { return true; }
+};
+
+/// \brief A directive for an undefined macro.
+class UndefMacroDirective : public MacroDirective {
+public:
+ explicit UndefMacroDirective(SourceLocation UndefLoc)
+ : MacroDirective(MD_Undefine, UndefLoc) {
+ assert(UndefLoc.isValid() && "Invalid UndefLoc!");
+ }
+
+ static bool classof(const MacroDirective *MD) {
+ return MD->getKind() == MD_Undefine;
+ }
+ static bool classof(const UndefMacroDirective *) { return true; }
+};
+
+/// \brief A directive for setting the module visibility of a macro.
+class VisibilityMacroDirective : public MacroDirective {
+public:
+ explicit VisibilityMacroDirective(SourceLocation Loc, bool Public)
+ : MacroDirective(MD_Visibility, Loc) {
+ IsPublic = Public;
+ }
+
+ /// \brief Determine whether this macro is part of the public API of its
+ /// module.
+ bool isPublic() const { return IsPublic; }
+
+ static bool classof(const MacroDirective *MD) {
+ return MD->getKind() == MD_Visibility;
+ }
+ static bool classof(const VisibilityMacroDirective *) { return true; }
};
+inline SourceLocation MacroDirective::DefInfo::getLocation() const {
+ if (isInvalid())
+ return SourceLocation();
+ return DefDirective->getLocation();
+}
+
+inline MacroInfo *MacroDirective::DefInfo::getMacroInfo() {
+ if (isInvalid())
+ return 0;
+ return DefDirective->getInfo();
+}
+
+inline MacroDirective::DefInfo
+MacroDirective::DefInfo::getPreviousDefinition(bool AllowHidden) {
+ if (isInvalid() || DefDirective->getPrevious() == 0)
+ return DefInfo();
+ return DefDirective->getPrevious()->getDefinition(AllowHidden);
+}
+
} // end namespace clang
#endif
diff --git a/include/clang/Lex/ModuleLoader.h b/include/clang/Lex/ModuleLoader.h
index 36d03c0..3acf915 100644
--- a/include/clang/Lex/ModuleLoader.h
+++ b/include/clang/Lex/ModuleLoader.h
@@ -17,16 +17,36 @@
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/PointerIntPair.h"
namespace clang {
class IdentifierInfo;
-
+class Module;
+
/// \brief A sequence of identifier/location pairs used to describe a particular
/// module or submodule, e.g., std.vector.
-typedef llvm::ArrayRef<std::pair<IdentifierInfo*, SourceLocation> >
- ModuleIdPath;
-
+typedef ArrayRef<std::pair<IdentifierInfo *, SourceLocation> > ModuleIdPath;
+
+/// \brief Describes the result of attempting to load a module.
+class ModuleLoadResult {
+ llvm::PointerIntPair<Module *, 1, bool> Storage;
+
+public:
+ ModuleLoadResult() : Storage() { }
+
+ ModuleLoadResult(Module *module, bool missingExpected)
+ : Storage(module, missingExpected) { }
+
+ operator Module *() const { return Storage.getPointer(); }
+
+ /// \brief Determines whether the module, which failed to load, was
+ /// actually a submodule that we expected to see (based on implying the
+ /// submodule from header structure), but didn't materialize in the actual
+ /// module.
+ bool isMissingExpected() const { return Storage.getInt(); }
+};
+
/// \brief Abstract interface for a module loader.
///
/// This abstract interface describes a module loader, which is responsible
@@ -55,9 +75,16 @@ public:
///
/// \returns If successful, returns the loaded module. Otherwise, returns
/// NULL to indicate that the module could not be loaded.
- virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
- Module::NameVisibilityKind Visibility,
- bool IsInclusionDirective) = 0;
+ virtual ModuleLoadResult loadModule(SourceLocation ImportLoc,
+ ModuleIdPath Path,
+ Module::NameVisibilityKind Visibility,
+ bool IsInclusionDirective) = 0;
+
+ /// \brief Make the given module visible.
+ virtual void makeModuleVisible(Module *Mod,
+ Module::NameVisibilityKind Visibility,
+ SourceLocation ImportLoc,
+ bool Complain) = 0;
};
}
diff --git a/include/clang/Lex/ModuleMap.h b/include/clang/Lex/ModuleMap.h
index 082408d..1c9c673 100644
--- a/include/clang/Lex/ModuleMap.h
+++ b/include/clang/Lex/ModuleMap.h
@@ -22,8 +22,8 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
#include <string>
namespace clang {
@@ -33,6 +33,7 @@ class FileEntry;
class FileManager;
class DiagnosticConsumer;
class DiagnosticsEngine;
+class HeaderSearch;
class ModuleMapParser;
class ModuleMap {
@@ -40,6 +41,7 @@ class ModuleMap {
IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
const LangOptions &LangOpts;
const TargetInfo *Target;
+ HeaderSearch &HeaderInfo;
/// \brief The directory used for Clang-supplied, builtin include headers,
/// such as "stdint.h".
@@ -104,13 +106,17 @@ class ModuleMap {
/// \brief The names of modules that cannot be inferred within this
/// directory.
- llvm::SmallVector<std::string, 2> ExcludedModules;
+ SmallVector<std::string, 2> ExcludedModules;
};
/// \brief A mapping from directories to information about inferring
/// framework modules from within those directories.
llvm::DenseMap<const DirectoryEntry *, InferredDirectory> InferredDirectories;
+ /// \brief Describes whether we haved parsed a particular file as a module
+ /// map.
+ llvm::DenseMap<const FileEntry *, bool> ParsedModuleMap;
+
friend class ModuleMapParser;
/// \brief Resolve the given export declaration into an actual export
@@ -127,8 +133,21 @@ class ModuleMap {
/// if the export could not be resolved.
Module::ExportDecl
resolveExport(Module *Mod, const Module::UnresolvedExportDecl &Unresolved,
- bool Complain);
-
+ bool Complain) const;
+
+ /// \brief Resolve the given module id to an actual module.
+ ///
+ /// \param Id The module-id to resolve.
+ ///
+ /// \param Mod The module in which we're resolving the module-id.
+ ///
+ /// \param Complain Whether this routine should complain about unresolvable
+ /// module-ids.
+ ///
+ /// \returns The resolved module, or null if the module-id could not be
+ /// resolved.
+ Module *resolveModuleId(const ModuleId &Id, Module *Mod, bool Complain) const;
+
public:
/// \brief Construct a new module map.
///
@@ -143,7 +162,8 @@ public:
///
/// \param Target The target for this translation unit.
ModuleMap(FileManager &FileMgr, const DiagnosticConsumer &DC,
- const LangOptions &LangOpts, const TargetInfo *Target);
+ const LangOptions &LangOpts, const TargetInfo *Target,
+ HeaderSearch &HeaderInfo);
/// \brief Destroy the module map.
///
@@ -157,6 +177,7 @@ public:
void setBuiltinIncludeDir(const DirectoryEntry *Dir) {
BuiltinIncludeDir = Dir;
}
+ const DirectoryEntry *getBuiltinIncludeDir() { return BuiltinIncludeDir; }
/// \brief Retrieve the module that owns the given header file, if any.
///
@@ -168,14 +189,14 @@ public:
/// \brief Determine whether the given header is part of a module
/// marked 'unavailable'.
- bool isHeaderInUnavailableModule(const FileEntry *Header);
+ bool isHeaderInUnavailableModule(const FileEntry *Header) const;
/// \brief Retrieve a module with the given name.
///
/// \param Name The name of the module to look up.
///
/// \returns The named module, if known; otherwise, returns null.
- Module *findModule(StringRef Name);
+ Module *findModule(StringRef Name) const;
/// \brief Retrieve a module with the given name using lexical name lookup,
/// starting at the given context.
@@ -186,7 +207,7 @@ public:
/// name lookup.
///
/// \returns The named module, if known; otherwise, returns null.
- Module *lookupModuleUnqualified(StringRef Name, Module *Context);
+ Module *lookupModuleUnqualified(StringRef Name, Module *Context) const;
/// \brief Retrieve a module with the given name within the given context,
/// using direct (qualified) name lookup.
@@ -197,7 +218,7 @@ public:
/// null, we will look for a top-level module.
///
/// \returns The named submodule, if known; otherwose, returns null.
- Module *lookupModuleQualified(StringRef Name, Module *Context);
+ Module *lookupModuleQualified(StringRef Name, Module *Context) const;
/// \brief Find a new module or submodule, or create it if it does not already
/// exist.
@@ -231,7 +252,7 @@ public:
/// \returns true if we are allowed to infer a framework module, and false
/// otherwise.
bool canInferFrameworkModule(const DirectoryEntry *ParentDir,
- StringRef Name, bool &IsSystem);
+ StringRef Name, bool &IsSystem) const;
/// \brief Infer the contents of a framework module map from the given
/// framework directory.
@@ -246,7 +267,7 @@ public:
///
/// \returns The file entry for the module map file containing the given
/// module, or NULL if the module definition was inferred.
- const FileEntry *getContainingModuleMapFile(Module *Module);
+ const FileEntry *getContainingModuleMapFile(Module *Module) const;
/// \brief Resolve all of the unresolved exports in the given module.
///
@@ -258,7 +279,17 @@ public:
/// false otherwise.
bool resolveExports(Module *Mod, bool Complain);
- /// \brief Infers the (sub)module based on the given source location and
+ /// \brief Resolve all of the unresolved conflicts in the given module.
+ ///
+ /// \param Mod The module whose conflicts should be resolved.
+ ///
+ /// \param Complain Whether to emit diagnostics for failures.
+ ///
+ /// \returns true if any errors were encountered while resolving conflicts,
+ /// false otherwise.
+ bool resolveConflicts(Module *Mod, bool Complain);
+
+ /// \brief Infers the (sub)module based on the given source location and
/// source manager.
///
/// \param Loc The location within the source that we are querying, along
diff --git a/include/clang/Lex/PPCallbacks.h b/include/clang/Lex/PPCallbacks.h
index 8ba02cc..96359a2 100644
--- a/include/clang/Lex/PPCallbacks.h
+++ b/include/clang/Lex/PPCallbacks.h
@@ -15,10 +15,10 @@
#ifndef LLVM_CLANG_LEX_PPCALLBACKS_H
#define LLVM_CLANG_LEX_PPCALLBACKS_H
+#include "clang/Basic/DiagnosticIDs.h"
+#include "clang/Basic/SourceLocation.h"
#include "clang/Lex/DirectoryLookup.h"
#include "clang/Lex/ModuleLoader.h"
-#include "clang/Basic/SourceLocation.h"
-#include "clang/Basic/DiagnosticIDs.h"
#include "llvm/ADT/StringRef.h"
#include <string>
@@ -26,7 +26,7 @@ namespace clang {
class SourceLocation;
class Token;
class IdentifierInfo;
- class MacroInfo;
+ class MacroDirective;
/// \brief This interface provides a way to observe the actions of the
/// preprocessor as it does its thing.
@@ -184,22 +184,25 @@ public:
/// \brief Called by Preprocessor::HandleMacroExpandedIdentifier when a
/// macro invocation is found.
- virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo* MI,
+ virtual void MacroExpands(const Token &MacroNameTok, const MacroDirective *MD,
SourceRange Range) {
}
/// \brief Hook called whenever a macro definition is seen.
- virtual void MacroDefined(const Token &MacroNameTok, const MacroInfo *MI) {
+ virtual void MacroDefined(const Token &MacroNameTok,
+ const MacroDirective *MD) {
}
/// \brief Hook called whenever a macro \#undef is seen.
///
- /// MI is released immediately following this callback.
- virtual void MacroUndefined(const Token &MacroNameTok, const MacroInfo *MI) {
+ /// MD is released immediately following this callback.
+ virtual void MacroUndefined(const Token &MacroNameTok,
+ const MacroDirective *MD) {
}
/// \brief Hook called whenever the 'defined' operator is seen.
- virtual void Defined(const Token &MacroNameTok) {
+ /// \param MD The MacroDirective if the name was a macro, null otherwise.
+ virtual void Defined(const Token &MacroNameTok, const MacroDirective *MD) {
}
/// \brief Hook called when a source range is skipped.
@@ -228,13 +231,17 @@ public:
/// \brief Hook called whenever an \#ifdef is seen.
/// \param Loc the source location of the directive.
/// \param MacroNameTok Information on the token being tested.
- virtual void Ifdef(SourceLocation Loc, const Token &MacroNameTok) {
+ /// \param MD The MacroDirective if the name was a macro, null otherwise.
+ virtual void Ifdef(SourceLocation Loc, const Token &MacroNameTok,
+ const MacroDirective *MD) {
}
/// \brief Hook called whenever an \#ifndef is seen.
/// \param Loc the source location of the directive.
/// \param MacroNameTok Information on the token being tested.
- virtual void Ifndef(SourceLocation Loc, const Token &MacroNameTok) {
+ /// \param MD The MacroDirective if the name was a macro, null otherwise.
+ virtual void Ifndef(SourceLocation Loc, const Token &MacroNameTok,
+ const MacroDirective *MD) {
}
/// \brief Hook called whenever an \#else is seen.
@@ -346,25 +353,26 @@ public:
Second->PragmaDiagnostic(Loc, Namespace, mapping, Str);
}
- virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo* MI,
+ virtual void MacroExpands(const Token &MacroNameTok, const MacroDirective *MD,
SourceRange Range) {
- First->MacroExpands(MacroNameTok, MI, Range);
- Second->MacroExpands(MacroNameTok, MI, Range);
+ First->MacroExpands(MacroNameTok, MD, Range);
+ Second->MacroExpands(MacroNameTok, MD, Range);
}
- virtual void MacroDefined(const Token &MacroNameTok, const MacroInfo *MI) {
- First->MacroDefined(MacroNameTok, MI);
- Second->MacroDefined(MacroNameTok, MI);
+ virtual void MacroDefined(const Token &MacroNameTok, const MacroDirective *MD) {
+ First->MacroDefined(MacroNameTok, MD);
+ Second->MacroDefined(MacroNameTok, MD);
}
- virtual void MacroUndefined(const Token &MacroNameTok, const MacroInfo *MI) {
- First->MacroUndefined(MacroNameTok, MI);
- Second->MacroUndefined(MacroNameTok, MI);
+ virtual void MacroUndefined(const Token &MacroNameTok,
+ const MacroDirective *MD) {
+ First->MacroUndefined(MacroNameTok, MD);
+ Second->MacroUndefined(MacroNameTok, MD);
}
- virtual void Defined(const Token &MacroNameTok) {
- First->Defined(MacroNameTok);
- Second->Defined(MacroNameTok);
+ virtual void Defined(const Token &MacroNameTok, const MacroDirective *MD) {
+ First->Defined(MacroNameTok, MD);
+ Second->Defined(MacroNameTok, MD);
}
virtual void SourceRangeSkipped(SourceRange Range) {
@@ -386,15 +394,17 @@ public:
}
/// \brief Hook called whenever an \#ifdef is seen.
- virtual void Ifdef(SourceLocation Loc, const Token &MacroNameTok) {
- First->Ifdef(Loc, MacroNameTok);
- Second->Ifdef(Loc, MacroNameTok);
+ virtual void Ifdef(SourceLocation Loc, const Token &MacroNameTok,
+ const MacroDirective *MD) {
+ First->Ifdef(Loc, MacroNameTok, MD);
+ Second->Ifdef(Loc, MacroNameTok, MD);
}
/// \brief Hook called whenever an \#ifndef is seen.
- virtual void Ifndef(SourceLocation Loc, const Token &MacroNameTok) {
- First->Ifndef(Loc, MacroNameTok);
- Second->Ifndef(Loc, MacroNameTok);
+ virtual void Ifndef(SourceLocation Loc, const Token &MacroNameTok,
+ const MacroDirective *MD) {
+ First->Ifndef(Loc, MacroNameTok, MD);
+ Second->Ifndef(Loc, MacroNameTok, MD);
}
/// \brief Hook called whenever an \#else is seen.
diff --git a/include/clang/Lex/PPConditionalDirectiveRecord.h b/include/clang/Lex/PPConditionalDirectiveRecord.h
new file mode 100644
index 0000000..b9a2252
--- /dev/null
+++ b/include/clang/Lex/PPConditionalDirectiveRecord.h
@@ -0,0 +1,102 @@
+//===--- PPConditionalDirectiveRecord.h - Preprocessing Directives-*- 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 PPConditionalDirectiveRecord class, which maintains
+// a record of conditional directive regions.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_LEX_PPCONDITIONALDIRECTIVERECORD_H
+#define LLVM_CLANG_LEX_PPCONDITIONALDIRECTIVERECORD_H
+
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "llvm/ADT/SmallVector.h"
+#include <vector>
+
+namespace clang {
+
+/// \brief Records preprocessor conditional directive regions and allows
+/// querying in which region source locations belong to.
+class PPConditionalDirectiveRecord : public PPCallbacks {
+ SourceManager &SourceMgr;
+
+ SmallVector<SourceLocation, 6> CondDirectiveStack;
+
+ class CondDirectiveLoc {
+ SourceLocation Loc;
+ SourceLocation RegionLoc;
+
+ public:
+ CondDirectiveLoc(SourceLocation Loc, SourceLocation RegionLoc)
+ : Loc(Loc), RegionLoc(RegionLoc) {}
+
+ SourceLocation getLoc() const { return Loc; }
+ SourceLocation getRegionLoc() const { return RegionLoc; }
+
+ class Comp {
+ SourceManager &SM;
+ public:
+ explicit Comp(SourceManager &SM) : SM(SM) {}
+ bool operator()(const CondDirectiveLoc &LHS,
+ const CondDirectiveLoc &RHS) {
+ return SM.isBeforeInTranslationUnit(LHS.getLoc(), RHS.getLoc());
+ }
+ bool operator()(const CondDirectiveLoc &LHS, SourceLocation RHS) {
+ return SM.isBeforeInTranslationUnit(LHS.getLoc(), RHS);
+ }
+ bool operator()(SourceLocation LHS, const CondDirectiveLoc &RHS) {
+ return SM.isBeforeInTranslationUnit(LHS, RHS.getLoc());
+ }
+ };
+ };
+
+ typedef std::vector<CondDirectiveLoc> CondDirectiveLocsTy;
+ /// \brief The locations of conditional directives in source order.
+ CondDirectiveLocsTy CondDirectiveLocs;
+
+ void addCondDirectiveLoc(CondDirectiveLoc DirLoc);
+
+public:
+ /// \brief Construct a new preprocessing record.
+ explicit PPConditionalDirectiveRecord(SourceManager &SM);
+
+ size_t getTotalMemory() const;
+
+ SourceManager &getSourceManager() const { return SourceMgr; }
+
+ /// \brief Returns true if the given range intersects with a conditional
+ /// directive. if a \#if/\#endif block is fully contained within the range,
+ /// this function will return false.
+ bool rangeIntersectsConditionalDirective(SourceRange Range) const;
+
+ /// \brief Returns true if the given locations are in different regions,
+ /// separated by conditional directive blocks.
+ bool areInDifferentConditionalDirectiveRegion(SourceLocation LHS,
+ SourceLocation RHS) const {
+ return findConditionalDirectiveRegionLoc(LHS) !=
+ findConditionalDirectiveRegionLoc(RHS);
+ }
+
+ SourceLocation findConditionalDirectiveRegionLoc(SourceLocation Loc) const;
+
+private:
+ virtual void If(SourceLocation Loc, SourceRange ConditionRange);
+ virtual void Elif(SourceLocation Loc, SourceRange ConditionRange,
+ SourceLocation IfLoc);
+ virtual void Ifdef(SourceLocation Loc, const Token &MacroNameTok,
+ const MacroDirective *MD);
+ virtual void Ifndef(SourceLocation Loc, const Token &MacroNameTok,
+ const MacroDirective *MD);
+ virtual void Else(SourceLocation Loc, SourceLocation IfLoc);
+ virtual void Endif(SourceLocation Loc, SourceLocation IfLoc);
+};
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_LEX_PPCONDITIONALDIRECTIVERECORD_H
diff --git a/include/clang/Lex/PPMutationListener.h b/include/clang/Lex/PPMutationListener.h
deleted file mode 100644
index 5319c66..0000000
--- a/include/clang/Lex/PPMutationListener.h
+++ /dev/null
@@ -1,43 +0,0 @@
-//===--- PPMutationListener.h - Preprocessor Mutation Interface -*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the PPMutationListener interface.
-//
-//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_LEX_PPTMUTATIONLISTENER_H
-#define LLVM_CLANG_LEX_PPTMUTATIONLISTENER_H
-
-#include "clang/Basic/SourceLocation.h"
-
-namespace clang {
-
-class MacroInfo;
-
-/// \brief A record that describes an update to a macro that was
-/// originally loaded to an AST file and has been modified within the
-/// current translation unit.
-struct MacroUpdate {
- /// \brief The source location at which this macro was #undef'd.
- SourceLocation UndefLoc;
-};
-
-/// \brief An abstract interface that should be implemented by
-/// listeners that want to be notified when a preprocessor entity gets
-/// modified after its initial creation.
-class PPMutationListener {
-public:
- virtual ~PPMutationListener();
-
- /// \brief A macro has been #undef'd.
- virtual void UndefinedMacro(MacroInfo *MI) { }
-};
-
-} // end namespace clang
-
-#endif
diff --git a/include/clang/Lex/PTHManager.h b/include/clang/Lex/PTHManager.h
index e64dbd8..fad0806 100644
--- a/include/clang/Lex/PTHManager.h
+++ b/include/clang/Lex/PTHManager.h
@@ -14,10 +14,10 @@
#ifndef LLVM_CLANG_PTHMANAGER_H
#define LLVM_CLANG_PTHMANAGER_H
-#include "clang/Lex/PTHLexer.h"
-#include "clang/Basic/LangOptions.h"
-#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Lex/PTHLexer.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/Allocator.h"
#include <string>
diff --git a/include/clang/Lex/PreprocessingRecord.h b/include/clang/Lex/PreprocessingRecord.h
index 57e51b7..b13b2be 100644
--- a/include/clang/Lex/PreprocessingRecord.h
+++ b/include/clang/Lex/PreprocessingRecord.h
@@ -14,18 +14,19 @@
#ifndef LLVM_CLANG_LEX_PREPROCESSINGRECORD_H
#define LLVM_CLANG_LEX_PREPROCESSINGRECORD_H
-#include "clang/Lex/PPCallbacks.h"
-#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/IdentifierTable.h"
-#include "llvm/ADT/SmallVector.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/PPCallbacks.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Compiler.h"
#include <vector>
namespace clang {
class IdentifierInfo;
+ class MacroInfo;
class PreprocessingRecord;
}
@@ -277,9 +278,9 @@ namespace clang {
/// \brief Optionally returns true or false if the preallocated preprocessed
/// entity with index \p Index came from file \p FID.
- virtual llvm::Optional<bool> isPreprocessedEntityInFileID(unsigned Index,
- FileID FID) {
- return llvm::Optional<bool>();
+ virtual Optional<bool> isPreprocessedEntityInFileID(unsigned Index,
+ FileID FID) {
+ return None;
}
};
@@ -303,44 +304,6 @@ namespace clang {
/// and are referenced by the iterator using negative indices.
std::vector<PreprocessedEntity *> LoadedPreprocessedEntities;
- bool RecordCondDirectives;
- unsigned CondDirectiveNextIdx;
- SmallVector<unsigned, 6> CondDirectiveStack;
-
- class CondDirectiveLoc {
- SourceLocation Loc;
- unsigned Idx;
-
- public:
- CondDirectiveLoc(SourceLocation Loc, unsigned Idx) : Loc(Loc), Idx(Idx) {}
-
- SourceLocation getLoc() const { return Loc; }
- unsigned getIdx() const { return Idx; }
-
- class Comp {
- SourceManager &SM;
- public:
- explicit Comp(SourceManager &SM) : SM(SM) {}
- bool operator()(const CondDirectiveLoc &LHS,
- const CondDirectiveLoc &RHS) {
- return SM.isBeforeInTranslationUnit(LHS.getLoc(), RHS.getLoc());
- }
- bool operator()(const CondDirectiveLoc &LHS, SourceLocation RHS) {
- return SM.isBeforeInTranslationUnit(LHS.getLoc(), RHS);
- }
- bool operator()(SourceLocation LHS, const CondDirectiveLoc &RHS) {
- return SM.isBeforeInTranslationUnit(LHS, RHS.getLoc());
- }
- };
- };
-
- typedef std::vector<CondDirectiveLoc> CondDirectiveLocsTy;
- /// \brief The locations of conditional directives in source order.
- CondDirectiveLocsTy CondDirectiveLocs;
-
- void addCondDirectiveLoc(CondDirectiveLoc DirLoc);
- unsigned findCondDirectiveIdx(SourceLocation Loc) const;
-
/// \brief Global (loaded or local) ID for a preprocessed entity.
/// Negative values are used to indicate preprocessed entities
/// loaded from the external source while non-negative values are used to
@@ -363,7 +326,7 @@ namespace clang {
}
/// \brief Mapping from MacroInfo structures to their definitions.
- llvm::DenseMap<const MacroInfo *, PPEntityID> MacroDefinitions;
+ llvm::DenseMap<const MacroInfo *, MacroDefinition *> MacroDefinitions;
/// \brief External source of preprocessed entities.
ExternalPreprocessingRecordSource *ExternalSource;
@@ -394,11 +357,11 @@ namespace clang {
unsigned allocateLoadedEntities(unsigned NumEntities);
/// \brief Register a new macro definition.
- void RegisterMacroDefinition(MacroInfo *Macro, PPEntityID PPID);
+ void RegisterMacroDefinition(MacroInfo *Macro, MacroDefinition *Def);
public:
/// \brief Construct a new preprocessing record.
- PreprocessingRecord(SourceManager &SM, bool RecordConditionalDirectives);
+ explicit PreprocessingRecord(SourceManager &SM);
/// \brief Allocate memory in the preprocessing record.
void *Allocate(unsigned Size, unsigned Align = 8) {
@@ -582,24 +545,6 @@ namespace clang {
/// \brief Add a new preprocessed entity to this record.
PPEntityID addPreprocessedEntity(PreprocessedEntity *Entity);
- /// \brief Returns true if this PreprocessingRecord is keeping track of
- /// conditional directives locations.
- bool isRecordingConditionalDirectives() const {
- return RecordCondDirectives;
- }
-
- /// \brief Returns true if the given range intersects with a conditional
- /// directive. if a \#if/\#endif block is fully contained within the range,
- /// this function will return false.
- bool rangeIntersectsConditionalDirective(SourceRange Range) const;
-
- /// \brief Returns true if the given locations are in different regions,
- /// separated by conditional directive blocks.
- bool areInDifferentConditionalDirectiveRegion(SourceLocation LHS,
- SourceLocation RHS) const {
- return findCondDirectiveIdx(LHS) != findCondDirectiveIdx(RHS);
- }
-
/// \brief Set the external source for preprocessed entities.
void SetExternalSource(ExternalPreprocessingRecordSource &Source);
@@ -613,10 +558,10 @@ namespace clang {
MacroDefinition *findMacroDefinition(const MacroInfo *MI);
private:
- virtual void MacroExpands(const Token &Id, const MacroInfo* MI,
+ virtual void MacroExpands(const Token &Id, const MacroDirective *MD,
SourceRange Range);
- virtual void MacroDefined(const Token &Id, const MacroInfo *MI);
- virtual void MacroUndefined(const Token &Id, const MacroInfo *MI);
+ virtual void MacroDefined(const Token &Id, const MacroDirective *MD);
+ virtual void MacroUndefined(const Token &Id, const MacroDirective *MD);
virtual void InclusionDirective(SourceLocation HashLoc,
const Token &IncludeTok,
StringRef FileName,
@@ -626,13 +571,15 @@ namespace clang {
StringRef SearchPath,
StringRef RelativePath,
const Module *Imported);
- virtual void If(SourceLocation Loc, SourceRange ConditionRange);
- virtual void Elif(SourceLocation Loc, SourceRange ConditionRange,
- SourceLocation IfLoc);
- virtual void Ifdef(SourceLocation Loc, const Token &MacroNameTok);
- virtual void Ifndef(SourceLocation Loc, const Token &MacroNameTok);
- virtual void Else(SourceLocation Loc, SourceLocation IfLoc);
- virtual void Endif(SourceLocation Loc, SourceLocation IfLoc);
+ virtual void Ifdef(SourceLocation Loc, const Token &MacroNameTok,
+ const MacroDirective *MD);
+ virtual void Ifndef(SourceLocation Loc, const Token &MacroNameTok,
+ const MacroDirective *MD);
+ /// \brief Hook called whenever the 'defined' operator is seen.
+ virtual void Defined(const Token &MacroNameTok, const MacroDirective *MD);
+
+ void addMacroExpansion(const Token &Id, const MacroInfo *MI,
+ SourceRange Range);
/// \brief Cached result of the last \see getPreprocessedEntitiesInRange
/// query.
diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h
index e9095fb..7a912ec 100644
--- a/include/clang/Lex/Preprocessor.h
+++ b/include/clang/Lex/Preprocessor.h
@@ -14,23 +14,22 @@
#ifndef LLVM_CLANG_LEX_PREPROCESSOR_H
#define LLVM_CLANG_LEX_PREPROCESSOR_H
-#include "clang/Lex/MacroInfo.h"
-#include "clang/Lex/Lexer.h"
-#include "clang/Lex/PTHLexer.h"
-#include "clang/Lex/PPCallbacks.h"
-#include "clang/Lex/PPMutationListener.h"
-#include "clang/Lex/TokenLexer.h"
-#include "clang/Lex/PTHManager.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/PTHLexer.h"
+#include "clang/Lex/PTHManager.h"
+#include "clang/Lex/TokenLexer.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
-#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/Allocator.h"
#include <vector>
@@ -84,7 +83,7 @@ public:
/// like the \#include stack, token expansion, etc.
///
class Preprocessor : public RefCountedBase<Preprocessor> {
- llvm::IntrusiveRefCntPtr<PreprocessorOptions> PPOpts;
+ IntrusiveRefCntPtr<PreprocessorOptions> PPOpts;
DiagnosticsEngine *Diags;
LangOptions &LangOpts;
const TargetInfo *Target;
@@ -160,6 +159,12 @@ class Preprocessor : public RefCountedBase<Preprocessor> {
/// \brief True if pragmas are enabled.
bool PragmasEnabled : 1;
+ /// \brief True if the current build action is a preprocessing action.
+ bool PreprocessedOutput : 1;
+
+ /// \brief True if we are currently preprocessing a #if or #elif directive
+ bool ParsingIfOrElifDirective;
+
/// \brief True if we are pre-expanding macro arguments.
bool InMacroArgPreExpansion;
@@ -215,8 +220,7 @@ class Preprocessor : public RefCountedBase<Preprocessor> {
SourceLocation ModuleImportLoc;
/// \brief The module import path that we're currently processing.
- llvm::SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2>
- ModuleImportPath;
+ SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> ModuleImportPath;
/// \brief Whether the module import expectes an identifier next. Otherwise,
/// it expects a '.' or ';'.
@@ -291,24 +295,19 @@ class Preprocessor : public RefCountedBase<Preprocessor> {
/// encountered (e.g. a file is \#included, etc).
PPCallbacks *Callbacks;
- /// \brief Listener whose actions are invoked when an entity in the
- /// preprocessor (e.g., a macro) that was loaded from an AST file is
- /// later mutated.
- PPMutationListener *Listener;
-
struct MacroExpandsInfo {
Token Tok;
- MacroInfo *MI;
+ MacroDirective *MD;
SourceRange Range;
- MacroExpandsInfo(Token Tok, MacroInfo *MI, SourceRange Range)
- : Tok(Tok), MI(MI), Range(Range) { }
+ MacroExpandsInfo(Token Tok, MacroDirective *MD, SourceRange Range)
+ : Tok(Tok), MD(MD), Range(Range) { }
};
SmallVector<MacroExpandsInfo, 2> DelayedMacroExpandsCallbacks;
/// Macros - For each IdentifierInfo that was associated with a macro, we
/// keep a mapping to the history of all macro definitions and #undefs in
/// the reverse order (the latest one is in the head of the list).
- llvm::DenseMap<IdentifierInfo*, MacroInfo*> Macros;
+ llvm::DenseMap<const IdentifierInfo*, MacroDirective*> Macros;
friend class ASTReader;
/// \brief Macros that we want to warn because they are not used at the end
@@ -343,6 +342,9 @@ class Preprocessor : public RefCountedBase<Preprocessor> {
/// should use from the command line etc.
std::string Predefines;
+ /// \brief The file ID for the preprocessor predefines.
+ FileID PredefinesFileID;
+
/// TokenLexerCache - Cache macro expanders to reduce malloc traffic.
enum { TokenLexerCacheSize = 8 };
unsigned NumCachedTokenLexers;
@@ -396,7 +398,7 @@ private: // Cached tokens state.
MacroInfoChain *MICache;
public:
- Preprocessor(llvm::IntrusiveRefCntPtr<PreprocessorOptions> PPOpts,
+ Preprocessor(IntrusiveRefCntPtr<PreprocessorOptions> PPOpts,
DiagnosticsEngine &diags, LangOptions &opts,
const TargetInfo *target,
SourceManager &SM, HeaderSearch &Headers,
@@ -447,6 +449,11 @@ public:
/// \brief Retrieve the module loader associated with this preprocessor.
ModuleLoader &getModuleLoader() const { return TheModuleLoader; }
+ /// \brief True if we are currently preprocessing a #if or #elif directive
+ bool isParsingIfOrElifDirective() const {
+ return ParsingIfOrElifDirective;
+ }
+
/// SetCommentRetentionState - Control whether or not the preprocessor retains
/// comments in output.
void SetCommentRetentionState(bool KeepComments, bool KeepMacroComments) {
@@ -467,6 +474,16 @@ public:
return SuppressIncludeNotFoundError;
}
+ /// Sets whether the preprocessor is responsible for producing output or if
+ /// it is producing tokens to be consumed by Parse and Sema.
+ void setPreprocessedOutput(bool IsPreprocessedOutput) {
+ PreprocessedOutput = IsPreprocessedOutput;
+ }
+
+ /// Returns true if the preprocessor is responsible for generating output,
+ /// false if it is producing tokens to be consumed by Parse and Sema.
+ bool isPreprocessedOutput() const { return PreprocessedOutput; }
+
/// isCurrentLexer - Return true if we are lexing directly from the specified
/// lexer.
bool isCurrentLexer(const PreprocessorLexer *L) const {
@@ -483,6 +500,9 @@ public:
/// expansions going on at the time.
PreprocessorLexer *getCurrentFileLexer() const;
+ /// \brief Returns the file ID for the preprocessor predefines.
+ FileID getPredefinesFileID() const { return PredefinesFileID; }
+
/// getPPCallbacks/addPPCallbacks - Accessors for preprocessor callbacks.
/// Note that this class takes ownership of any PPCallbacks object given to
/// it.
@@ -493,53 +513,54 @@ public:
Callbacks = C;
}
- /// \brief Attach an preprocessor mutation listener to the preprocessor.
- ///
- /// The preprocessor mutation listener provides the ability to track
- /// modifications to the preprocessor entities committed after they were
- /// initially created.
- void setPPMutationListener(PPMutationListener *Listener) {
- this->Listener = Listener;
- }
-
- /// \brief Retrieve a pointer to the preprocessor mutation listener
- /// associated with this preprocessor, if any.
- PPMutationListener *getPPMutationListener() const { return Listener; }
-
- /// \brief Given an identifier, return the MacroInfo it is \#defined to
- /// or null if it isn't \#define'd.
- MacroInfo *getMacroInfo(IdentifierInfo *II) const {
+ /// \brief Given an identifier, return its latest MacroDirective if it is
+ // \#defined or null if it isn't \#define'd.
+ MacroDirective *getMacroDirective(IdentifierInfo *II) const {
if (!II->hasMacroDefinition())
return 0;
- MacroInfo *MI = getMacroInfoHistory(II);
- assert(MI->getUndefLoc().isInvalid() && "Macro is undefined!");
- return MI;
+ MacroDirective *MD = getMacroDirectiveHistory(II);
+ assert(MD->isDefined() && "Macro is undefined!");
+ return MD;
+ }
+
+ const MacroInfo *getMacroInfo(IdentifierInfo *II) const {
+ return const_cast<Preprocessor*>(this)->getMacroInfo(II);
+ }
+
+ MacroInfo *getMacroInfo(IdentifierInfo *II) {
+ if (MacroDirective *MD = getMacroDirective(II))
+ return MD->getMacroInfo();
+ return 0;
}
/// \brief Given an identifier, return the (probably #undef'd) MacroInfo
/// representing the most recent macro definition. One can iterate over all
/// previous macro definitions from it. This method should only be called for
/// identifiers that hadMacroDefinition().
- MacroInfo *getMacroInfoHistory(IdentifierInfo *II) const;
-
- /// \brief Specify a macro for this identifier.
- void setMacroInfo(IdentifierInfo *II, MacroInfo *MI);
- /// \brief Add a MacroInfo that was loaded from an AST file.
- void addLoadedMacroInfo(IdentifierInfo *II, MacroInfo *MI,
- MacroInfo *Hint = 0);
- /// \brief Make the given MacroInfo, that was loaded from an AST file and
- /// previously hidden, visible.
- void makeLoadedMacroInfoVisible(IdentifierInfo *II, MacroInfo *MI);
- /// \brief Undefine a macro for this identifier.
- void clearMacroInfo(IdentifierInfo *II);
+ MacroDirective *getMacroDirectiveHistory(const IdentifierInfo *II) const;
+
+ /// \brief Add a directive to the macro directive history for this identifier.
+ void appendMacroDirective(IdentifierInfo *II, MacroDirective *MD);
+ DefMacroDirective *appendDefMacroDirective(IdentifierInfo *II, MacroInfo *MI,
+ SourceLocation Loc,
+ bool isImported) {
+ DefMacroDirective *MD = AllocateDefMacroDirective(MI, Loc, isImported);
+ appendMacroDirective(II, MD);
+ return MD;
+ }
+ DefMacroDirective *appendDefMacroDirective(IdentifierInfo *II, MacroInfo *MI){
+ return appendDefMacroDirective(II, MI, MI->getDefinitionLoc(), false);
+ }
+ /// \brief Set a MacroDirective that was loaded from a PCH file.
+ void setLoadedMacroDirective(IdentifierInfo *II, MacroDirective *MD);
/// macro_iterator/macro_begin/macro_end - This allows you to walk the macro
/// history table. Currently defined macros have
/// IdentifierInfo::hasMacroDefinition() set and an empty
/// MacroInfo::getUndefLoc() at the head of the list.
- typedef llvm::DenseMap<IdentifierInfo*,
- MacroInfo*>::const_iterator macro_iterator;
+ typedef llvm::DenseMap<const IdentifierInfo *,
+ MacroDirective*>::const_iterator macro_iterator;
macro_iterator macro_begin(bool IncludeExternalMacros = true) const;
macro_iterator macro_end(bool IncludeExternalMacros = true) const;
@@ -611,7 +632,7 @@ public:
/// \brief Create a new preprocessing record, which will keep track of
/// all macro expansions, macro definitions, etc.
- void createPreprocessingRecord(bool RecordConditionalDirectives);
+ void createPreprocessingRecord();
/// EnterMainSourceFile - Enter the specified FileID as the main source file,
/// which implicitly adds the builtin defines etc.
@@ -696,6 +717,25 @@ public:
void LexAfterModuleImport(Token &Result);
+ /// \brief Lex a string literal, which may be the concatenation of multiple
+ /// string literals and may even come from macro expansion.
+ /// \returns true on success, false if a error diagnostic has been generated.
+ bool LexStringLiteral(Token &Result, std::string &String,
+ const char *DiagnosticTag, bool AllowMacroExpansion) {
+ if (AllowMacroExpansion)
+ Lex(Result);
+ else
+ LexUnexpandedToken(Result);
+ return FinishLexStringLiteral(Result, String, DiagnosticTag,
+ AllowMacroExpansion);
+ }
+
+ /// \brief Complete the lexing of a string literal where the first token has
+ /// already been lexed (see LexStringLiteral).
+ bool FinishLexStringLiteral(Token &Result, std::string &String,
+ const char *DiagnosticTag,
+ bool AllowMacroExpansion);
+
/// LexNonComment - Lex a token. If it's a comment, keep lexing until we get
/// something not a comment. This is useful in -E -C mode where comments
/// would foul up preprocessor directive handling.
@@ -901,8 +941,8 @@ public:
/// "cleaning", e.g. if it contains trigraphs or escaped newlines
/// \param invalid If non-null, will be set \c true if an error occurs.
StringRef getSpelling(SourceLocation loc,
- SmallVectorImpl<char> &buffer,
- bool *invalid = 0) const {
+ SmallVectorImpl<char> &buffer,
+ bool *invalid = 0) const {
return Lexer::getSpelling(loc, buffer, SourceMgr, LangOpts, invalid);
}
@@ -939,6 +979,12 @@ public:
SmallVectorImpl<char> &Buffer,
bool *Invalid = 0) const;
+ /// \brief Relex the token at the specified location.
+ /// \returns true if there was a failure, false on success.
+ bool getRawToken(SourceLocation Loc, Token &Result) {
+ return Lexer::getRawToken(Loc, Result, SourceMgr, LangOpts);
+ }
+
/// getSpellingOfSingleCharacterNumericConstant - Tok is a numeric constant
/// with length 1, return the character.
char getSpellingOfSingleCharacterNumericConstant(const Token &Tok,
@@ -1143,8 +1189,9 @@ public:
/// \brief Allocate a new MacroInfo object with the provided SourceLocation.
MacroInfo *AllocateMacroInfo(SourceLocation L);
- /// \brief Allocate a new MacroInfo object which is clone of \p MI.
- MacroInfo *CloneMacroInfo(const MacroInfo &MI);
+ /// \brief Allocate a new MacroInfo object loaded from an AST file.
+ MacroInfo *AllocateDeserializedMacroInfo(SourceLocation L,
+ unsigned SubModuleID);
/// \brief Turn the specified lexer token into a fully checked and spelled
/// filename, e.g. as an operand of \#include.
@@ -1221,6 +1268,13 @@ private:
/// \brief Allocate a new MacroInfo object.
MacroInfo *AllocateMacroInfo();
+ DefMacroDirective *AllocateDefMacroDirective(MacroInfo *MI,
+ SourceLocation Loc,
+ bool isImported);
+ UndefMacroDirective *AllocateUndefMacroDirective(SourceLocation UndefLoc);
+ VisibilityMacroDirective *AllocateVisibilityMacroDirective(SourceLocation Loc,
+ bool isPublic);
+
/// \brief Release the specified MacroInfo for re-use.
///
/// This memory will be reused for allocating new MacroInfo objects.
@@ -1268,7 +1322,7 @@ private:
/// HandleMacroExpandedIdentifier - If an identifier token is read that is to
/// be expanded as a macro, handle it and return the next token as 'Tok'. If
/// the macro should not be expanded return true, otherwise return false.
- bool HandleMacroExpandedIdentifier(Token &Tok, MacroInfo *MI);
+ bool HandleMacroExpandedIdentifier(Token &Tok, MacroDirective *MD);
/// \brief Cache macro expanded tokens for TokenLexers.
//
@@ -1312,6 +1366,12 @@ private:
/// start getting tokens from it using the PTH cache.
void EnterSourceFileWithPTH(PTHLexer *PL, const DirectoryLookup *Dir);
+ /// \brief Set the file ID for the preprocessor predefines.
+ void setPredefinesFileID(FileID FID) {
+ assert(PredefinesFileID.isInvalid() && "PredefinesFileID already set!");
+ PredefinesFileID = FID;
+ }
+
/// IsFileLexer - Returns true if we are lexing from a file and not a
/// pragma or a macro.
static bool IsFileLexer(const Lexer* L, const PreprocessorLexer* P) {
@@ -1367,8 +1427,6 @@ private:
// Macro handling.
void HandleDefineDirective(Token &Tok);
void HandleUndefDirective(Token &Tok);
- void UndefineMacro(IdentifierInfo *II, MacroInfo *MI,
- SourceLocation UndefLoc);
// Conditional Inclusion.
void HandleIfdefDirective(Token &Tok, bool isIfndef,
diff --git a/include/clang/Lex/PreprocessorOptions.h b/include/clang/Lex/PreprocessorOptions.h
index e5fe373..eba2a13 100644
--- a/include/clang/Lex/PreprocessorOptions.h
+++ b/include/clang/Lex/PreprocessorOptions.h
@@ -10,14 +10,16 @@
#ifndef LLVM_CLANG_LEX_PREPROCESSOROPTIONS_H_
#define LLVM_CLANG_LEX_PREPROCESSOROPTIONS_H_
+#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
#include <cassert>
+#include <set>
#include <string>
#include <utility>
#include <vector>
-#include <set>
namespace llvm {
class MemoryBuffer;
@@ -39,23 +41,20 @@ enum ObjCXXARCStandardLibraryKind {
/// PreprocessorOptions - This class is used for passing the various options
/// used in preprocessor initialization to InitializePreprocessor().
-class PreprocessorOptions : public llvm::RefCountedBase<PreprocessorOptions> {
+class PreprocessorOptions : public RefCountedBase<PreprocessorOptions> {
public:
std::vector<std::pair<std::string, bool/*isUndef*/> > Macros;
std::vector<std::string> Includes;
std::vector<std::string> MacroIncludes;
- unsigned UsePredefines : 1; /// Initialize the preprocessor with the compiler
- /// and target specific predefines.
+ /// \brief Initialize the preprocessor with the compiler and target specific
+ /// predefines.
+ unsigned UsePredefines : 1;
+
+ /// \brief Whether we should maintain a detailed record of all macro
+ /// definitions and expansions.
+ unsigned DetailedRecord : 1;
- unsigned DetailedRecord : 1; /// Whether we should maintain a detailed
- /// record of all macro definitions and
- /// expansions.
- unsigned DetailedRecordConditionalDirectives : 1; /// Whether in the
- /// preprocessing record we should also keep
- /// track of locations of conditional directives
- /// in non-system files.
-
/// The implicit PCH included at the start of the translation unit, or empty.
std::string ImplicitPCHInclude;
@@ -119,14 +118,28 @@ public:
/// with support for lifetime-qualified pointers.
ObjCXXARCStandardLibraryKind ObjCXXARCStandardLibrary;
- /// \brief The path of modules being build, which is used to detect
- /// cycles in the module dependency graph as modules are being built.
- ///
- /// There is no way to set this value from the command line. If we ever need
- /// to do so (e.g., if on-demand module construction moves out-of-process),
- /// we can add a cc1-level option to do so.
- SmallVector<std::string, 2> ModuleBuildPath;
+ /// \brief Records the set of modules
+ class FailedModulesSet : public RefCountedBase<FailedModulesSet> {
+ llvm::StringSet<> Failed;
+
+ public:
+ bool hasAlreadyFailed(StringRef module) {
+ return Failed.count(module) > 0;
+ }
+
+ void addFailed(StringRef module) {
+ Failed.insert(module);
+ }
+ };
+ /// \brief The set of modules that failed to build.
+ ///
+ /// This pointer will be shared among all of the compiler instances created
+ /// to (re)build modules, so that once a module fails to build anywhere,
+ /// other instances will see that the module has failed and won't try to
+ /// build it again.
+ IntrusiveRefCntPtr<FailedModulesSet> FailedModules;
+
typedef std::vector<std::pair<std::string, std::string> >::iterator
remapped_file_iterator;
typedef std::vector<std::pair<std::string, std::string> >::const_iterator
@@ -163,7 +176,6 @@ public:
public:
PreprocessorOptions() : UsePredefines(true), DetailedRecord(false),
- DetailedRecordConditionalDirectives(false),
DisablePCHValidation(false),
AllowPCHWithCompilerErrors(false),
DumpDeserializedPCHDecls(false),
diff --git a/include/clang/Lex/Token.h b/include/clang/Lex/Token.h
index 50b86c8..bcbe9c9 100644
--- a/include/clang/Lex/Token.h
+++ b/include/clang/Lex/Token.h
@@ -14,10 +14,10 @@
#ifndef LLVM_CLANG_TOKEN_H
#define LLVM_CLANG_TOKEN_H
+#include "clang/Basic/OperatorKinds.h"
+#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/TemplateKinds.h"
#include "clang/Basic/TokenKinds.h"
-#include "clang/Basic/SourceLocation.h"
-#include "clang/Basic/OperatorKinds.h"
#include <cstdlib>
namespace clang {
@@ -74,9 +74,10 @@ public:
StartOfLine = 0x01, // At start of line or only after whitespace.
LeadingSpace = 0x02, // Whitespace exists before this token.
DisableExpand = 0x04, // This identifier may never be macro expanded.
- NeedsCleaning = 0x08, // Contained an escaped newline or trigraph.
+ NeedsCleaning = 0x08, // Contained an escaped newline or trigraph.
LeadingEmptyMacro = 0x10, // Empty macro exists before this token.
- HasUDSuffix = 0x20 // This string or character literal has a ud-suffix.
+ HasUDSuffix = 0x20, // This string or character literal has a ud-suffix.
+ HasUCN = 0x40 // This identifier contains a UCN.
};
tok::TokenKind getKind() const { return (tok::TokenKind)Kind; }
@@ -257,6 +258,9 @@ public:
/// \brief Return true if this token is a string or character literal which
/// has a ud-suffix.
bool hasUDSuffix() const { return (Flags & HasUDSuffix) ? true : false; }
+
+ /// Returns true if this token contains a universal character name.
+ bool hasUCN() const { return (Flags & HasUCN) ? true : false; }
};
/// \brief Information about the conditional stack (\#if directives)
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index c433344..8cc60a2 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -14,11 +14,13 @@
#ifndef LLVM_CLANG_PARSE_PARSER_H
#define LLVM_CLANG_PARSE_PARSER_H
+#include "clang/Basic/OpenMPKinds.h"
+#include "clang/Basic/OperatorPrecedence.h"
#include "clang/Basic/Specifiers.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/CodeCompletionHandler.h"
-#include "clang/Sema/Sema.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/Sema.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Compiler.h"
@@ -44,39 +46,6 @@ namespace clang {
class PoisonSEHIdentifiersRAIIObject;
class VersionTuple;
-/// PrettyStackTraceParserEntry - If a crash happens while the parser is active,
-/// an entry is printed for it.
-class PrettyStackTraceParserEntry : public llvm::PrettyStackTraceEntry {
- const Parser &P;
-public:
- PrettyStackTraceParserEntry(const Parser &p) : P(p) {}
- virtual void print(raw_ostream &OS) const;
-};
-
-/// PrecedenceLevels - These are precedences for the binary/ternary
-/// operators in the C99 grammar. These have been named to relate
-/// with the C99 grammar productions. Low precedences numbers bind
-/// more weakly than high numbers.
-namespace prec {
- enum Level {
- Unknown = 0, // Not binary operator.
- Comma = 1, // ,
- Assignment = 2, // =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=
- Conditional = 3, // ?
- LogicalOr = 4, // ||
- LogicalAnd = 5, // &&
- InclusiveOr = 6, // |
- ExclusiveOr = 7, // ^
- And = 8, // &
- Equality = 9, // ==, !=
- Relational = 10, // >=, <=, >, <
- Shift = 11, // <<, >>
- Additive = 12, // -, +
- Multiplicative = 13, // *, /, %
- PointerToMember = 14 // .*, ->*
- };
-}
-
/// Parser - This implements a parser for the C family of languages. After
/// parsing units of the grammar, productions are invoked to handle whatever has
/// been read.
@@ -179,6 +148,7 @@ class Parser : public CodeCompletionHandler {
OwningPtr<PragmaHandler> FPContractHandler;
OwningPtr<PragmaHandler> OpenCLExtensionHandler;
OwningPtr<CommentHandler> CommentSemaHandler;
+ OwningPtr<PragmaHandler> OpenMPHandler;
/// Whether the '>' token acts as an operator or not. This will be
/// true except when we are parsing an expression within a C++
@@ -255,15 +225,6 @@ public:
typedef llvm::MutableArrayRef<Stmt*> MultiStmtArg;
typedef Sema::FullExprArg FullExprArg;
- /// Adorns a ExprResult with Actions to make it an ExprResult
- ExprResult Owned(ExprResult res) {
- return ExprResult(res);
- }
- /// Adorns a StmtResult with Actions to make it an StmtResult
- StmtResult Owned(StmtResult res) {
- return StmtResult(res);
- }
-
ExprResult ExprError() { return ExprResult(true); }
StmtResult StmtError() { return StmtResult(true); }
@@ -274,10 +235,6 @@ public:
// Parsing methods.
- /// ParseTranslationUnit - All in one method that initializes parses, and
- /// shuts down the parser.
- void ParseTranslationUnit();
-
/// Initialize - Warm up the parser.
///
void Initialize();
@@ -290,12 +247,12 @@ public:
/// This does not work with all kinds of tokens: strings and specific other
/// tokens must be consumed with custom methods below. This returns the
/// location of the consumed token.
- SourceLocation ConsumeToken() {
+ SourceLocation ConsumeToken(bool ConsumeCodeCompletionTok = false) {
assert(!isTokenStringLiteral() && !isTokenParen() && !isTokenBracket() &&
!isTokenBrace() &&
"Should consume special tokens with Consume*Token");
- if (Tok.is(tok::code_completion))
+ if (!ConsumeCodeCompletionTok && Tok.is(tok::code_completion))
return handleUnexpectedCodeCompletionToken();
PrevTokLocation = Tok.getLocation();
@@ -324,11 +281,7 @@ private:
/// isTokenStringLiteral - True if this token is a string-literal.
///
bool isTokenStringLiteral() const {
- return Tok.getKind() == tok::string_literal ||
- Tok.getKind() == tok::wide_string_literal ||
- Tok.getKind() == tok::utf8_string_literal ||
- Tok.getKind() == tok::utf16_string_literal ||
- Tok.getKind() == tok::utf32_string_literal;
+ return tok::isStringLiteral(Tok.getKind());
}
/// \brief Returns true if the current token is '=' or is a type of '='.
@@ -338,7 +291,7 @@ private:
/// ConsumeAnyToken - Dispatch to the right Consume* method based on the
/// current token type. This should only be used in cases where the type of
/// the token really isn't known, e.g. in error recovery.
- SourceLocation ConsumeAnyToken() {
+ SourceLocation ConsumeAnyToken(bool ConsumeCodeCompletionTok = false) {
if (isTokenParen())
return ConsumeParen();
else if (isTokenBracket())
@@ -348,7 +301,7 @@ private:
else if (isTokenStringLiteral())
return ConsumeStringToken();
else
- return ConsumeToken();
+ return ConsumeToken(ConsumeCodeCompletionTok);
}
/// ConsumeParen - This consume method keeps the paren count up-to-date.
@@ -849,7 +802,7 @@ private:
};
// A list of late-parsed attributes. Used by ParseGNUAttributes.
- class LateParsedAttrList: public llvm::SmallVector<LateParsedAttribute*, 2> {
+ class LateParsedAttrList: public SmallVector<LateParsedAttribute *, 2> {
public:
LateParsedAttrList(bool PSoon = false) : ParseSoon(PSoon) { }
@@ -869,7 +822,7 @@ private:
/// \brief Whether this member function had an associated template
/// scope. When true, D is a template declaration.
- /// othewise, it is a member function declaration.
+ /// otherwise, it is a member function declaration.
bool TemplateScope;
explicit LexedMethod(Parser* P, Decl *MD)
@@ -1097,7 +1050,8 @@ private:
void DeallocateParsedClasses(ParsingClass *Class);
void PopParsingClass(Sema::ParsingClassState);
- Decl *ParseCXXInlineMethodDef(AccessSpecifier AS, AttributeList *AccessAttrs,
+ NamedDecl *ParseCXXInlineMethodDef(AccessSpecifier AS,
+ AttributeList *AccessAttrs,
ParsingDeclarator &D,
const ParsedTemplateInfo &TemplateInfo,
const VirtSpecifiers& VS,
@@ -1159,10 +1113,15 @@ private:
ExprResult ParseAsmStringLiteral();
// Objective-C External Declarations
+ void MaybeSkipAttributes(tok::ObjCKeywordKind Kind);
DeclGroupPtrTy ParseObjCAtDirectives();
DeclGroupPtrTy ParseObjCAtClassDeclaration(SourceLocation atLoc);
Decl *ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
ParsedAttributes &prefixAttrs);
+ void HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc,
+ BalancedDelimiterTracker &T,
+ SmallVectorImpl<Decl *> &AllIvarDecls,
+ bool RBraceMissing);
void ParseObjCClassInstanceVariables(Decl *interfaceDecl,
tok::ObjCKeywordKind visibility,
SourceLocation atLoc);
@@ -1289,7 +1248,7 @@ private:
SmallVectorImpl<SourceLocation> &CommaLocs,
void (Sema::*Completer)(Scope *S,
Expr *Data,
- llvm::ArrayRef<Expr *> Args) = 0,
+ ArrayRef<Expr *> Args) = 0,
Expr *Data = 0);
/// ParenParseOption - Control what ParseParenExpression will parse.
@@ -1332,7 +1291,8 @@ private:
ParsedType ObjectType,
bool EnteringContext,
bool *MayBePseudoDestructor = 0,
- bool IsTypename = false);
+ bool IsTypename = false,
+ IdentifierInfo **LastII = 0);
void CheckForLParenAfterColonColon();
@@ -1342,7 +1302,7 @@ private:
// [...] () -> type {...}
ExprResult ParseLambdaExpression();
ExprResult TryParseLambdaExpression();
- llvm::Optional<unsigned> ParseLambdaIntroducer(LambdaIntroducer &Intro);
+ Optional<unsigned> ParseLambdaIntroducer(LambdaIntroducer &Intro);
bool TryParseLambdaIntroducer(LambdaIntroducer &Intro);
ExprResult ParseLambdaExpressionAfterIntroducer(
LambdaIntroducer &Intro);
@@ -1637,7 +1597,8 @@ private:
bool ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
const ParsedTemplateInfo &TemplateInfo,
- AccessSpecifier AS, DeclSpecContext DSC);
+ AccessSpecifier AS, DeclSpecContext DSC,
+ ParsedAttributesWithRange &Attrs);
DeclSpecContext getDeclSpecContextFromDeclaratorContext(unsigned Context);
void ParseDeclarationSpecifiers(DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
@@ -1843,7 +1804,8 @@ public:
Declarator::TheContext Context
= Declarator::TypeNameContext,
AccessSpecifier AS = AS_none,
- Decl **OwnedType = 0);
+ Decl **OwnedType = 0,
+ ParsedAttributes *Attrs = 0);
private:
void ParseBlockId(SourceLocation CaretLoc);
@@ -1852,11 +1814,22 @@ private:
// an attribute is not allowed.
bool CheckProhibitedCXX11Attribute() {
assert(Tok.is(tok::l_square));
- if (!getLangOpts().CPlusPlus0x || NextToken().isNot(tok::l_square))
+ if (!getLangOpts().CPlusPlus11 || NextToken().isNot(tok::l_square))
return false;
return DiagnoseProhibitedCXX11Attribute();
}
bool DiagnoseProhibitedCXX11Attribute();
+ void CheckMisplacedCXX11Attribute(ParsedAttributesWithRange &Attrs,
+ SourceLocation CorrectLocation) {
+ if (!getLangOpts().CPlusPlus11)
+ return;
+ if ((Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) &&
+ Tok.isNot(tok::kw_alignas))
+ return;
+ DiagnoseMisplacedCXX11Attribute(Attrs, CorrectLocation);
+ }
+ void DiagnoseMisplacedCXX11Attribute(ParsedAttributesWithRange &Attrs,
+ SourceLocation CorrectLocation);
void ProhibitAttributes(ParsedAttributesWithRange &attrs) {
if (!attrs.Range.isValid()) return;
@@ -1896,26 +1869,26 @@ private:
SourceLocation ScopeLoc,
AttributeList::Syntax Syntax);
- void MaybeParseCXX0XAttributes(Declarator &D) {
- if (getLangOpts().CPlusPlus0x && isCXX11AttributeSpecifier()) {
+ void MaybeParseCXX11Attributes(Declarator &D) {
+ if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) {
ParsedAttributesWithRange attrs(AttrFactory);
SourceLocation endLoc;
ParseCXX11Attributes(attrs, &endLoc);
D.takeAttributes(attrs, endLoc);
}
}
- void MaybeParseCXX0XAttributes(ParsedAttributes &attrs,
+ void MaybeParseCXX11Attributes(ParsedAttributes &attrs,
SourceLocation *endLoc = 0) {
- if (getLangOpts().CPlusPlus0x && isCXX11AttributeSpecifier()) {
+ if (getLangOpts().CPlusPlus11 && isCXX11AttributeSpecifier()) {
ParsedAttributesWithRange attrsWithRange(AttrFactory);
ParseCXX11Attributes(attrsWithRange, endLoc);
attrs.takeAllFrom(attrsWithRange);
}
}
- void MaybeParseCXX0XAttributes(ParsedAttributesWithRange &attrs,
+ void MaybeParseCXX11Attributes(ParsedAttributesWithRange &attrs,
SourceLocation *endLoc = 0,
bool OuterMightBeMessageSend = false) {
- if (getLangOpts().CPlusPlus0x &&
+ if (getLangOpts().CPlusPlus11 &&
isCXX11AttributeSpecifier(false, OuterMightBeMessageSend))
ParseCXX11Attributes(attrs, endLoc);
}
@@ -1954,7 +1927,7 @@ private:
ParsedAttributes &attrs,
SourceLocation *endLoc);
- bool IsThreadSafetyAttribute(llvm::StringRef AttrName);
+ bool IsThreadSafetyAttribute(StringRef AttrName);
void ParseThreadSafetyAttribute(IdentifierInfo &AttrName,
SourceLocation AttrNameLoc,
ParsedAttributes &Attrs,
@@ -1978,13 +1951,13 @@ private:
void ParseAlignmentSpecifier(ParsedAttributes &Attrs,
SourceLocation *endLoc = 0);
- VirtSpecifiers::Specifier isCXX0XVirtSpecifier(const Token &Tok) const;
- VirtSpecifiers::Specifier isCXX0XVirtSpecifier() const {
- return isCXX0XVirtSpecifier(Tok);
+ VirtSpecifiers::Specifier isCXX11VirtSpecifier(const Token &Tok) const;
+ VirtSpecifiers::Specifier isCXX11VirtSpecifier() const {
+ return isCXX11VirtSpecifier(Tok);
}
- void ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS, bool IsInterface);
+ void ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS, bool IsInterface);
- bool isCXX0XFinalKeyword() const;
+ bool isCXX11FinalKeyword() const;
/// DeclaratorScopeObj - RAII object used in Parser::ParseDirectDeclarator to
/// enter a new C++ declarator scope and exit it when the function is
@@ -2027,7 +2000,8 @@ private:
DirectDeclParseFunction DirectDeclParser);
void ParseTypeQualifierListOpt(DeclSpec &DS, bool GNUAttributesAllowed = true,
- bool CXX0XAttributesAllowed = true);
+ bool CXX11AttributesAllowed = true,
+ bool AtomicAllowed = true);
void ParseDirectDeclarator(Declarator &D);
void ParseParenDeclarator(Declarator &D);
void ParseFunctionDeclarator(Declarator &D,
@@ -2098,8 +2072,12 @@ private:
void ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation TagLoc,
DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo,
AccessSpecifier AS, bool EnteringContext,
- DeclSpecContext DSC);
- void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType,
+ DeclSpecContext DSC,
+ ParsedAttributesWithRange &Attributes);
+ void ParseCXXMemberSpecification(SourceLocation StartLoc,
+ SourceLocation AttrFixitLoc,
+ ParsedAttributesWithRange &Attrs,
+ unsigned TagType,
Decl *TagDecl);
ExprResult ParseCXXMemberInitializer(Decl *D, bool IsFunction,
SourceLocation &EqualLoc);
@@ -2131,6 +2109,11 @@ private:
ParsedType ObjectType,
UnqualifiedId &Result);
+ //===--------------------------------------------------------------------===//
+ // OpenMP: Directives and clauses.
+ DeclGroupPtrTy ParseOpenMPDeclarativeDirective();
+ bool ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,
+ SmallVectorImpl<DeclarationNameInfo> &IdList);
public:
bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
bool AllowDestructorName,
@@ -2173,6 +2156,8 @@ private:
// C++ 14.3: Template arguments [temp.arg]
typedef SmallVector<ParsedTemplateArgument, 16> TemplateArgList;
+ bool ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc,
+ bool ConsumeLastToken);
bool ParseTemplateIdAfterTemplateName(TemplateTy Template,
SourceLocation TemplateNameLoc,
const CXXScopeSpec &SS,
diff --git a/include/clang/Rewrite/Core/RewriteRope.h b/include/clang/Rewrite/Core/RewriteRope.h
index 9f1bbe5..a5192ef 100644
--- a/include/clang/Rewrite/Core/RewriteRope.h
+++ b/include/clang/Rewrite/Core/RewriteRope.h
@@ -15,10 +15,9 @@
#define LLVM_CLANG_REWRITEROPE_H
#include "llvm/Support/Compiler.h"
-
-#include <cstring>
#include <cassert>
#include <cstddef>
+#include <cstring>
#include <iterator>
namespace clang {
diff --git a/include/clang/Rewrite/Core/Rewriter.h b/include/clang/Rewrite/Core/Rewriter.h
index a33ea13..cb044ae 100644
--- a/include/clang/Rewrite/Core/Rewriter.h
+++ b/include/clang/Rewrite/Core/Rewriter.h
@@ -52,7 +52,11 @@ public:
iterator end() const { return Buffer.end(); }
unsigned size() const { return Buffer.size(); }
- raw_ostream &write(raw_ostream &) const;
+ /// \brief Write to \p Stream the result of applying all changes to the
+ /// original buffer.
+ ///
+ /// The original buffer is not actually changed.
+ raw_ostream &write(raw_ostream &Stream) const;
/// RemoveText - Remove the specified text.
void RemoveText(unsigned OrigOffset, unsigned Size,
@@ -279,7 +283,7 @@ public:
buffer_iterator buffer_begin() { return RewriteBuffers.begin(); }
buffer_iterator buffer_end() { return RewriteBuffers.end(); }
- /// SaveFiles - Save all changed files to disk.
+ /// overwriteChangedFiles - Save all changed files to disk.
///
/// Returns whether not all changes were saved successfully.
/// Outputs diagnostics via the source manager's diagnostic engine
diff --git a/include/clang/Rewrite/Frontend/ASTConsumers.h b/include/clang/Rewrite/Frontend/ASTConsumers.h
index c9c92e3..584af3f 100644
--- a/include/clang/Rewrite/Frontend/ASTConsumers.h
+++ b/include/clang/Rewrite/Frontend/ASTConsumers.h
@@ -35,7 +35,8 @@ ASTConsumer *CreateModernObjCRewriter(const std::string &InFile,
raw_ostream *OS,
DiagnosticsEngine &Diags,
const LangOptions &LOpts,
- bool SilenceRewriteMacroWarning);
+ bool SilenceRewriteMacroWarning,
+ bool LineInfo);
/// CreateHTMLPrinter - Create an AST consumer which rewrites source code to
/// HTML with syntax highlighting suitable for viewing in a web-browser.
diff --git a/include/clang/Rewrite/Frontend/FixItRewriter.h b/include/clang/Rewrite/Frontend/FixItRewriter.h
index f12a034..04c04a2 100644
--- a/include/clang/Rewrite/Frontend/FixItRewriter.h
+++ b/include/clang/Rewrite/Frontend/FixItRewriter.h
@@ -17,8 +17,8 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceLocation.h"
-#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Edit/EditedSource.h"
+#include "clang/Rewrite/Core/Rewriter.h"
namespace clang {
diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h
index 2e8b0c0..0f0d218 100644
--- a/include/clang/Sema/AttributeList.h
+++ b/include/clang/Sema/AttributeList.h
@@ -15,11 +15,11 @@
#ifndef LLVM_CLANG_SEMA_ATTRLIST_H
#define LLVM_CLANG_SEMA_ATTRLIST_H
-#include "llvm/Support/Allocator.h"
-#include "llvm/ADT/SmallVector.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/VersionTuple.h"
#include "clang/Sema/Ownership.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Allocator.h"
#include <cassert>
namespace clang {
@@ -44,8 +44,9 @@ struct AvailabilityChange {
bool isValid() const { return !Version.empty(); }
};
-/// AttributeList - Represents GCC's __attribute__ declaration. There are
-/// 4 forms of this construct...they are:
+/// AttributeList - Represents a syntactic attribute.
+///
+/// For a GNU attribute, there are four forms of this construct:
///
/// 1: __attribute__(( const )). ParmName/Args/NumArgs will all be unused.
/// 2: __attribute__(( mode(byte) )). ParmName used, Args/NumArgs unused.
@@ -56,12 +57,14 @@ class AttributeList { // TODO: This should really be called ParsedAttribute
public:
/// The style used to specify an attribute.
enum Syntax {
+ /// __attribute__((...))
AS_GNU,
+ /// [[...]]
AS_CXX11,
+ /// __declspec(...)
AS_Declspec,
- // eg) __w64, __ptr32, etc. It is implied that an MSTypespec is also
- // a declspec.
- AS_MSTypespec
+ /// __ptr16, alignas(...), etc.
+ AS_Keyword
};
private:
IdentifierInfo *AttrName;
@@ -70,6 +73,7 @@ private:
SourceRange AttrRange;
SourceLocation ScopeLoc;
SourceLocation ParmLoc;
+ SourceLocation EllipsisLoc;
/// The number of expression arguments this attribute has.
/// The expressions themselves are stored after the object.
@@ -140,6 +144,14 @@ private:
return *reinterpret_cast<const TypeTagForDatatypeData *>(this + 1);
}
+ ParsedType &getTypeBuffer() {
+ return *reinterpret_cast<ParsedType *>(this + 1);
+ }
+
+ const ParsedType &getTypeBuffer() const {
+ return *reinterpret_cast<const ParsedType *>(this + 1);
+ }
+
AttributeList(const AttributeList &) LLVM_DELETED_FUNCTION;
void operator=(const AttributeList &) LLVM_DELETED_FUNCTION;
void operator delete(void *) LLVM_DELETED_FUNCTION;
@@ -152,11 +164,11 @@ private:
IdentifierInfo *scopeName, SourceLocation scopeLoc,
IdentifierInfo *parmName, SourceLocation parmLoc,
Expr **args, unsigned numArgs,
- Syntax syntaxUsed)
+ Syntax syntaxUsed, SourceLocation ellipsisLoc)
: AttrName(attrName), ScopeName(scopeName), ParmName(parmName),
AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc),
- NumArgs(numArgs), SyntaxUsed(syntaxUsed), Invalid(false),
- UsedAsTypeAttr(false), IsAvailability(false),
+ EllipsisLoc(ellipsisLoc), NumArgs(numArgs), SyntaxUsed(syntaxUsed),
+ Invalid(false), UsedAsTypeAttr(false), IsAvailability(false),
IsTypeTagForDatatype(false), NextInPosition(0), NextInPool(0) {
if (numArgs) memcpy(getArgsBuffer(), args, numArgs * sizeof(Expr*));
AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
@@ -173,7 +185,7 @@ private:
const Expr *messageExpr,
Syntax syntaxUsed)
: AttrName(attrName), ScopeName(scopeName), ParmName(parmName),
- AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc),
+ AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc), EllipsisLoc(),
NumArgs(0), SyntaxUsed(syntaxUsed),
Invalid(false), UsedAsTypeAttr(false), IsAvailability(true),
IsTypeTagForDatatype(false),
@@ -194,7 +206,7 @@ private:
bool mustBeNull, Syntax syntaxUsed)
: AttrName(attrName), ScopeName(scopeName), ParmName(argumentKindName),
AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(argumentKindLoc),
- NumArgs(0), SyntaxUsed(syntaxUsed),
+ EllipsisLoc(), NumArgs(0), SyntaxUsed(syntaxUsed),
Invalid(false), UsedAsTypeAttr(false), IsAvailability(false),
IsTypeTagForDatatype(true), NextInPosition(NULL), NextInPool(NULL) {
TypeTagForDatatypeData &ExtraData = getTypeTagForDatatypeDataSlot();
@@ -204,6 +216,20 @@ private:
AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
}
+ /// Constructor for attributes with a single type argument.
+ AttributeList(IdentifierInfo *attrName, SourceRange attrRange,
+ IdentifierInfo *scopeName, SourceLocation scopeLoc,
+ IdentifierInfo *parmName, SourceLocation parmLoc,
+ ParsedType typeArg, Syntax syntaxUsed)
+ : AttrName(attrName), ScopeName(scopeName), ParmName(parmName),
+ AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc),
+ EllipsisLoc(), NumArgs(1), SyntaxUsed(syntaxUsed), Invalid(false),
+ UsedAsTypeAttr(false), IsAvailability(false),
+ IsTypeTagForDatatype(false), NextInPosition(0), NextInPool(0) {
+ new (&getTypeBuffer()) ParsedType(typeArg);
+ AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
+ }
+
friend class AttributePool;
friend class AttributeFactory;
@@ -227,12 +253,16 @@ public:
IdentifierInfo *getParameterName() const { return ParmName; }
SourceLocation getParameterLoc() const { return ParmLoc; }
- /// Returns true if the attribute is a pure __declspec or a synthesized
- /// declspec representing a type specification (like __w64 or __ptr32).
- bool isDeclspecAttribute() const { return SyntaxUsed == AS_Declspec ||
- SyntaxUsed == AS_MSTypespec; }
- bool isCXX0XAttribute() const { return SyntaxUsed == AS_CXX11; }
- bool isMSTypespecAttribute() const { return SyntaxUsed == AS_MSTypespec; }
+ bool isAlignasAttribute() const {
+ // FIXME: Use a better mechanism to determine this.
+ return getKind() == AT_Aligned && SyntaxUsed == AS_Keyword;
+ }
+
+ bool isDeclspecAttribute() const { return SyntaxUsed == AS_Declspec; }
+ bool isCXX11Attribute() const {
+ return SyntaxUsed == AS_CXX11 || isAlignasAttribute();
+ }
+ bool isKeywordAttribute() const { return SyntaxUsed == AS_Keyword; }
bool isInvalid() const { return Invalid; }
void setInvalid(bool b = true) const { Invalid = b; }
@@ -240,6 +270,9 @@ public:
bool isUsedAsTypeAttr() const { return UsedAsTypeAttr; }
void setUsedAsTypeAttr() { UsedAsTypeAttr = true; }
+ bool isPackExpansion() const { return EllipsisLoc.isValid(); }
+ SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
+
Kind getKind() const { return Kind(AttrKind); }
static Kind getKind(const IdentifierInfo *Name, const IdentifierInfo *Scope,
Syntax SyntaxUsed);
@@ -340,6 +373,16 @@ public:
"Not a type_tag_for_datatype attribute");
return getTypeTagForDatatypeDataSlot().MustBeNull;
}
+
+ const ParsedType &getTypeArg() const {
+ assert(getKind() == AT_VecTypeHint && "Not a type attribute");
+ return getTypeBuffer();
+ }
+
+ /// \brief Get an index into the attribute spelling list
+ /// defined in Attr.td. This index is used by an attribute
+ /// to pretty print itself.
+ unsigned getAttributeSpellingListIndex() const;
};
/// A factory, from which one makes pools, from which one creates
@@ -448,13 +491,15 @@ public:
IdentifierInfo *scopeName, SourceLocation scopeLoc,
IdentifierInfo *parmName, SourceLocation parmLoc,
Expr **args, unsigned numArgs,
- AttributeList::Syntax syntax) {
+ AttributeList::Syntax syntax,
+ SourceLocation ellipsisLoc = SourceLocation()) {
void *memory = allocate(sizeof(AttributeList)
+ numArgs * sizeof(Expr*));
return add(new (memory) AttributeList(attrName, attrRange,
scopeName, scopeLoc,
parmName, parmLoc,
- args, numArgs, syntax));
+ args, numArgs, syntax,
+ ellipsisLoc));
}
AttributeList *create(IdentifierInfo *attrName, SourceRange attrRange,
@@ -491,6 +536,18 @@ public:
matchingCType, layoutCompatible,
mustBeNull, syntax));
}
+
+ AttributeList *createTypeAttribute(
+ IdentifierInfo *attrName, SourceRange attrRange,
+ IdentifierInfo *scopeName, SourceLocation scopeLoc,
+ IdentifierInfo *parmName, SourceLocation parmLoc,
+ ParsedType typeArg, AttributeList::Syntax syntaxUsed) {
+ void *memory = allocate(sizeof(AttributeList) + sizeof(void *));
+ return add(new (memory) AttributeList(attrName, attrRange,
+ scopeName, scopeLoc,
+ parmName, parmLoc,
+ typeArg, syntaxUsed));
+ }
};
/// addAttributeLists - Add two AttributeLists together
@@ -511,18 +568,18 @@ inline AttributeList *addAttributeLists(AttributeList *Left,
return Left;
}
-/// CXX0XAttributeList - A wrapper around a C++0x attribute list.
+/// CXX11AttributeList - A wrapper around a C++11 attribute list.
/// Stores, in addition to the list proper, whether or not an actual list was
/// (as opposed to an empty list, which may be ill-formed in some places) and
/// the source range of the list.
-struct CXX0XAttributeList {
+struct CXX11AttributeList {
AttributeList *AttrList;
SourceRange Range;
bool HasAttr;
- CXX0XAttributeList (AttributeList *attrList, SourceRange range, bool hasAttr)
+ CXX11AttributeList (AttributeList *attrList, SourceRange range, bool hasAttr)
: AttrList(attrList), Range(range), HasAttr (hasAttr) {
}
- CXX0XAttributeList ()
+ CXX11AttributeList ()
: AttrList(0), Range(), HasAttr(false) {
}
};
@@ -588,10 +645,11 @@ public:
IdentifierInfo *scopeName, SourceLocation scopeLoc,
IdentifierInfo *parmName, SourceLocation parmLoc,
Expr **args, unsigned numArgs,
- AttributeList::Syntax syntax) {
+ AttributeList::Syntax syntax,
+ SourceLocation ellipsisLoc = SourceLocation()) {
AttributeList *attr =
pool.create(attrName, attrRange, scopeName, scopeLoc, parmName, parmLoc,
- args, numArgs, syntax);
+ args, numArgs, syntax, ellipsisLoc);
add(attr);
return attr;
}
@@ -632,6 +690,19 @@ public:
return attr;
}
+ /// Add an attribute with a single type argument.
+ AttributeList *
+ addNewTypeAttr(IdentifierInfo *attrName, SourceRange attrRange,
+ IdentifierInfo *scopeName, SourceLocation scopeLoc,
+ IdentifierInfo *parmName, SourceLocation parmLoc,
+ ParsedType typeArg, AttributeList::Syntax syntaxUsed) {
+ AttributeList *attr =
+ pool.createTypeAttribute(attrName, attrRange, scopeName, scopeLoc,
+ parmName, parmLoc, typeArg, syntaxUsed);
+ add(attr);
+ return attr;
+ }
+
AttributeList *addNewInteger(ASTContext &C, IdentifierInfo *name,
SourceLocation loc, int arg) {
AttributeList *attr =
diff --git a/include/clang/Sema/CMakeLists.txt b/include/clang/Sema/CMakeLists.txt
index 03f99a3..6b5d222 100644
--- a/include/clang/Sema/CMakeLists.txt
+++ b/include/clang/Sema/CMakeLists.txt
@@ -11,4 +11,9 @@ clang_tablegen(AttrParsedAttrList.inc -gen-clang-attr-parsed-attr-list
clang_tablegen(AttrParsedAttrKinds.inc -gen-clang-attr-parsed-attr-kinds
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
SOURCE ../Basic/Attr.td
- TARGET ClangAttrParsedAttrKinds) \ No newline at end of file
+ TARGET ClangAttrParsedAttrKinds)
+
+clang_tablegen(AttrSpellingListIndex.inc -gen-clang-attr-spelling-index
+ -I ${CMAKE_CURRENT_SOURCE_DIR}/../../
+ SOURCE ../Basic/Attr.td
+ TARGET ClangAttrSpellingListIndex)
diff --git a/include/clang/Sema/CXXFieldCollector.h b/include/clang/Sema/CXXFieldCollector.h
index 6f3c0b4..6685751 100644
--- a/include/clang/Sema/CXXFieldCollector.h
+++ b/include/clang/Sema/CXXFieldCollector.h
@@ -15,6 +15,7 @@
#ifndef LLVM_CLANG_SEMA_CXXFIELDCOLLECTOR_H
#define LLVM_CLANG_SEMA_CXXFIELDCOLLECTOR_H
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/SmallVector.h"
namespace clang {
diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h
index b128bd8..a1ddec7 100644
--- a/include/clang/Sema/CodeCompleteConsumer.h
+++ b/include/clang/Sema/CodeCompleteConsumer.h
@@ -13,13 +13,13 @@
#ifndef LLVM_CLANG_SEMA_CODECOMPLETECONSUMER_H
#define LLVM_CLANG_SEMA_CODECOMPLETECONSUMER_H
-#include "clang/AST/Type.h"
+#include "clang-c/Index.h"
#include "clang/AST/CanonicalType.h"
+#include "clang/AST/Type.h"
#include "clang/Sema/CodeCompleteOptions.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Allocator.h"
-#include "clang-c/Index.h"
#include <string>
namespace clang {
@@ -121,7 +121,7 @@ SimplifiedTypeClass getSimplifiedTypeClass(CanQualType T);
/// \brief Determine the type that this declaration will have if it is used
/// as a type or in an expression.
-QualType getDeclUsageType(ASTContext &C, NamedDecl *ND);
+QualType getDeclUsageType(ASTContext &C, const NamedDecl *ND);
/// \brief Determine the priority to be given to a macro code completion result
/// with the given name.
@@ -138,7 +138,7 @@ unsigned getMacroUsagePriority(StringRef MacroName,
/// \brief Determine the libclang cursor kind associated with the given
/// declaration.
-CXCursorKind getCursorKindForDecl(Decl *D);
+CXCursorKind getCursorKindForDecl(const Decl *D);
class FunctionDecl;
class FunctionType;
@@ -245,7 +245,8 @@ public:
/// \brief Code completion in a parenthesized expression, which means that
/// we may also have types here in C and Objective-C (as well as in C++).
CCC_ParenthesizedExpression,
- /// \brief Code completion where an Objective-C instance message is expcted.
+ /// \brief Code completion where an Objective-C instance message is
+ /// expected.
CCC_ObjCInstanceMessage,
/// \brief Code completion where an Objective-C class message is expected.
CCC_ObjCClassMessage,
@@ -530,7 +531,7 @@ class GlobalCodeCompletionAllocator
};
class CodeCompletionTUInfo {
- llvm::DenseMap<DeclContext *, StringRef> ParentNames;
+ llvm::DenseMap<const DeclContext *, StringRef> ParentNames;
IntrusiveRefCntPtr<GlobalCodeCompletionAllocator> AllocatorRef;
public:
@@ -546,7 +547,7 @@ public:
return *AllocatorRef;
}
- StringRef getParentName(DeclContext *DC);
+ StringRef getParentName(const DeclContext *DC);
};
} // end namespace clang
@@ -629,8 +630,9 @@ public:
void AddAnnotation(const char *A) { Annotations.push_back(A); }
/// \brief Add the parent context information to this code completion.
- void addParentContext(DeclContext *DC);
+ void addParentContext(const DeclContext *DC);
+ const char *getBriefComment() const { return BriefComment; }
void addBriefComment(StringRef Comment);
StringRef getParentName() const { return ParentName; }
@@ -649,7 +651,7 @@ public:
/// \brief When Kind == RK_Declaration or RK_Pattern, the declaration we are
/// referring to. In the latter case, the declaration might be NULL.
- NamedDecl *Declaration;
+ const NamedDecl *Declaration;
union {
/// \brief When Kind == RK_Keyword, the string representing the keyword
@@ -661,7 +663,7 @@ public:
CodeCompletionString *Pattern;
/// \brief When Kind == RK_Macro, the identifier that refers to a macro.
- IdentifierInfo *Macro;
+ const IdentifierInfo *Macro;
};
/// \brief The priority of this particular code-completion result.
@@ -704,11 +706,12 @@ public:
NestedNameSpecifier *Qualifier;
/// \brief Build a result that refers to a declaration.
- CodeCompletionResult(NamedDecl *Declaration,
+ CodeCompletionResult(const NamedDecl *Declaration,
+ unsigned Priority,
NestedNameSpecifier *Qualifier = 0,
bool QualifierIsInformative = false,
bool Accessible = true)
- : Declaration(Declaration), Priority(getPriorityFromDecl(Declaration)),
+ : Declaration(Declaration), Priority(Priority),
StartParameter(0), Kind(RK_Declaration),
Availability(CXAvailability_Available), Hidden(false),
QualifierIsInformative(QualifierIsInformative),
@@ -728,7 +731,8 @@ public:
}
/// \brief Build a result that refers to a macro.
- CodeCompletionResult(IdentifierInfo *Macro, unsigned Priority = CCP_Macro)
+ CodeCompletionResult(const IdentifierInfo *Macro,
+ unsigned Priority = CCP_Macro)
: Declaration(0), Macro(Macro), Priority(Priority), StartParameter(0),
Kind(RK_Macro), CursorKind(CXCursor_MacroDefinition),
Availability(CXAvailability_Available), Hidden(false),
@@ -742,7 +746,7 @@ public:
unsigned Priority = CCP_CodePattern,
CXCursorKind CursorKind = CXCursor_NotImplemented,
CXAvailabilityKind Availability = CXAvailability_Available,
- NamedDecl *D = 0)
+ const NamedDecl *D = 0)
: Declaration(D), Pattern(Pattern), Priority(Priority), StartParameter(0),
Kind(RK_Pattern), CursorKind(CursorKind), Availability(Availability),
Hidden(false), QualifierIsInformative(0),
@@ -763,7 +767,7 @@ public:
}
/// \brief Retrieve the declaration stored in this result.
- NamedDecl *getDeclaration() const {
+ const NamedDecl *getDeclaration() const {
assert(Kind == RK_Declaration && "Not a declaration result");
return Declaration;
}
@@ -791,9 +795,6 @@ public:
CodeCompletionTUInfo &CCTUInfo,
bool IncludeBriefComments);
- /// \brief Determine a base priority for the given declaration.
- static unsigned getPriorityFromDecl(NamedDecl *ND);
-
private:
void computeCursorKindAndAvailability(bool Accessible = true);
};
diff --git a/include/clang/Sema/CodeCompleteOptions.h b/include/clang/Sema/CodeCompleteOptions.h
index 30712db..e43496f 100644
--- a/include/clang/Sema/CodeCompleteOptions.h
+++ b/include/clang/Sema/CodeCompleteOptions.h
@@ -13,16 +13,16 @@
/// Options controlling the behavior of code completion.
class CodeCompleteOptions {
public:
- ///< Show macros in code completion results.
+ /// Show macros in code completion results.
unsigned IncludeMacros : 1;
- ///< Show code patterns in code completion results.
+ /// Show code patterns in code completion results.
unsigned IncludeCodePatterns : 1;
- ///< Show top-level decls in code completion results.
+ /// Show top-level decls in code completion results.
unsigned IncludeGlobals : 1;
- ///< Show brief documentation comments in code completion results.
+ /// Show brief documentation comments in code completion results.
unsigned IncludeBriefComments : 1;
CodeCompleteOptions() :
diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h
index 0728e87..5b90784 100644
--- a/include/clang/Sema/DeclSpec.h
+++ b/include/clang/Sema/DeclSpec.h
@@ -23,14 +23,14 @@
#ifndef LLVM_CLANG_SEMA_DECLSPEC_H
#define LLVM_CLANG_SEMA_DECLSPEC_H
-#include "clang/Sema/AttributeList.h"
-#include "clang/Sema/Ownership.h"
#include "clang/AST/NestedNameSpecifier.h"
-#include "clang/Lex/Token.h"
#include "clang/Basic/ExceptionSpecificationType.h"
#include "clang/Basic/Lambda.h"
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/Specifiers.h"
+#include "clang/Lex/Token.h"
+#include "clang/Sema/AttributeList.h"
+#include "clang/Sema/Ownership.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
@@ -276,6 +276,14 @@ public:
static const TST TST_auto = clang::TST_auto;
static const TST TST_unknown_anytype = clang::TST_unknown_anytype;
static const TST TST_atomic = clang::TST_atomic;
+ static const TST TST_image1d_t = clang::TST_image1d_t;
+ static const TST TST_image1d_array_t = clang::TST_image1d_array_t;
+ static const TST TST_image1d_buffer_t = clang::TST_image1d_buffer_t;
+ static const TST TST_image2d_t = clang::TST_image2d_t;
+ static const TST TST_image2d_array_t = clang::TST_image2d_array_t;
+ static const TST TST_image3d_t = clang::TST_image3d_t;
+ static const TST TST_sampler_t = clang::TST_sampler_t;
+ static const TST TST_event_t = clang::TST_event_t;
static const TST TST_error = clang::TST_error;
// type-qualifiers
@@ -283,7 +291,10 @@ public:
TQ_unspecified = 0,
TQ_const = 1,
TQ_restrict = 2,
- TQ_volatile = 4
+ TQ_volatile = 4,
+ // This has no corresponding Qualifiers::TQ value, because it's not treated
+ // as a qualifier in our type system.
+ TQ_atomic = 8
};
/// ParsedSpecifiers - Flags to query which specifiers were applied. This is
@@ -306,19 +317,20 @@ private:
/*TSW*/unsigned TypeSpecWidth : 2;
/*TSC*/unsigned TypeSpecComplex : 2;
/*TSS*/unsigned TypeSpecSign : 2;
- /*TST*/unsigned TypeSpecType : 5;
+ /*TST*/unsigned TypeSpecType : 6;
unsigned TypeAltiVecVector : 1;
unsigned TypeAltiVecPixel : 1;
unsigned TypeAltiVecBool : 1;
unsigned TypeSpecOwned : 1;
// type-qualifiers
- unsigned TypeQualifiers : 3; // Bitwise OR of TQ.
+ unsigned TypeQualifiers : 4; // Bitwise OR of TQ.
// function-specifier
unsigned FS_inline_specified : 1;
unsigned FS_virtual_specified : 1;
unsigned FS_explicit_specified : 1;
+ unsigned FS_noreturn_specified : 1;
// friend-specifier
unsigned Friend_specified : 1;
@@ -326,8 +338,6 @@ private:
// constexpr-specifier
unsigned Constexpr_specified : 1;
- /*SCS*/unsigned StorageClassSpecAsWritten : 3;
-
union {
UnionParsedType TypeRep;
Decl *DeclRep;
@@ -360,13 +370,12 @@ private:
/// TSTNameLoc provides source range info for tag types.
SourceLocation TSTNameLoc;
SourceRange TypeofParensRange;
- SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc;
- SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc;
+ SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc, TQ_atomicLoc;
+ SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc, FS_noreturnLoc;
SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc;
WrittenBuiltinSpecs writtenBS;
void SaveWrittenBuiltinSpecs();
- void SaveStorageSpecifierAsWritten();
ObjCDeclSpec *ObjCQualifiers;
@@ -377,16 +386,16 @@ private:
static bool isExprRep(TST T) {
return (T == TST_typeofExpr || T == TST_decltype);
}
+
+ DeclSpec(const DeclSpec &) LLVM_DELETED_FUNCTION;
+ void operator=(const DeclSpec &) LLVM_DELETED_FUNCTION;
+public:
static bool isDeclRep(TST T) {
return (T == TST_enum || T == TST_struct ||
T == TST_interface || T == TST_union ||
T == TST_class);
}
- DeclSpec(const DeclSpec &) LLVM_DELETED_FUNCTION;
- void operator=(const DeclSpec &) LLVM_DELETED_FUNCTION;
-public:
-
DeclSpec(AttributeFactory &attrFactory)
: StorageClassSpec(SCS_unspecified),
SCS_thread_specified(false),
@@ -403,9 +412,9 @@ public:
FS_inline_specified(false),
FS_virtual_specified(false),
FS_explicit_specified(false),
+ FS_noreturn_specified(false),
Friend_specified(false),
Constexpr_specified(false),
- StorageClassSpecAsWritten(SCS_unspecified),
Attrs(attrFactory),
ProtocolQualifiers(0),
NumProtocolQualifiers(0),
@@ -493,6 +502,7 @@ public:
SourceLocation getConstSpecLoc() const { return TQ_constLoc; }
SourceLocation getRestrictSpecLoc() const { return TQ_restrictLoc; }
SourceLocation getVolatileSpecLoc() const { return TQ_volatileLoc; }
+ SourceLocation getAtomicSpecLoc() const { return TQ_atomicLoc; }
/// \brief Clear out all of the type qualifiers.
void ClearTypeQualifiers() {
@@ -500,6 +510,7 @@ public:
TQ_constLoc = SourceLocation();
TQ_restrictLoc = SourceLocation();
TQ_volatileLoc = SourceLocation();
+ TQ_atomicLoc = SourceLocation();
}
// function-specifier
@@ -512,6 +523,9 @@ public:
bool isExplicitSpecified() const { return FS_explicit_specified; }
SourceLocation getExplicitSpecLoc() const { return FS_explicitLoc; }
+ bool isNoreturnSpecified() const { return FS_noreturn_specified; }
+ SourceLocation getNoreturnSpecLoc() const { return FS_noreturnLoc; }
+
void ClearFunctionSpecs() {
FS_inline_specified = false;
FS_inlineLoc = SourceLocation();
@@ -519,6 +533,8 @@ public:
FS_virtualLoc = SourceLocation();
FS_explicit_specified = false;
FS_explicitLoc = SourceLocation();
+ FS_noreturn_specified = false;
+ FS_noreturnLoc = SourceLocation();
}
/// \brief Return true if any type-specifier has been found.
@@ -533,10 +549,6 @@ public:
/// DeclSpec includes.
unsigned getParsedSpecifiers() const;
- SCS getStorageClassSpecAsWritten() const {
- return (SCS)StorageClassSpecAsWritten;
- }
-
/// isEmpty - Return true if this declaration specifier is completely empty:
/// no tokens were parsed in the production of it.
bool isEmpty() const {
@@ -602,12 +614,10 @@ public:
bool SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID, const LangOptions &Lang);
- bool SetFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec,
- unsigned &DiagID);
- bool SetFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec,
- unsigned &DiagID);
- bool SetFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec,
- unsigned &DiagID);
+ bool setFunctionSpecInline(SourceLocation Loc);
+ bool setFunctionSpecVirtual(SourceLocation Loc);
+ bool setFunctionSpecExplicit(SourceLocation Loc);
+ bool setFunctionSpecNoreturn(SourceLocation Loc);
bool SetFriendSpec(SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID);
@@ -808,6 +818,20 @@ public:
IK_ImplicitSelfParam
} Kind;
+ struct OFI {
+ /// \brief The kind of overloaded operator.
+ OverloadedOperatorKind Operator;
+
+ /// \brief The source locations of the individual tokens that name
+ /// the operator, e.g., the "new", "[", and "]" tokens in
+ /// operator new [].
+ ///
+ /// Different operators have different numbers of tokens in their name,
+ /// up to three. Any remaining source locations in this array will be
+ /// set to an invalid value for operators with fewer than three tokens.
+ unsigned SymbolLocations[3];
+ };
+
/// \brief Anonymous union that holds extra data associated with the
/// parsed unqualified-id.
union {
@@ -817,19 +841,7 @@ public:
/// \brief When Kind == IK_OperatorFunctionId, the overloaded operator
/// that we parsed.
- struct {
- /// \brief The kind of overloaded operator.
- OverloadedOperatorKind Operator;
-
- /// \brief The source locations of the individual tokens that name
- /// the operator, e.g., the "new", "[", and "]" tokens in
- /// operator new [].
- ///
- /// Different operators have different numbers of tokens in their name,
- /// up to three. Any remaining source locations in this array will be
- /// set to an invalid value for operators with fewer than three tokens.
- unsigned SymbolLocations[3];
- } OperatorFunctionId;
+ struct OFI OperatorFunctionId;
/// \brief When Kind == IK_ConversionFunctionId, the type that the
/// conversion function names.
@@ -1010,8 +1022,8 @@ struct DeclaratorChunk {
};
struct PointerTypeInfo : TypeInfoCommon {
- /// The type qualifiers: const/volatile/restrict.
- unsigned TypeQuals : 3;
+ /// The type qualifiers: const/volatile/restrict/atomic.
+ unsigned TypeQuals : 4;
/// The location of the const-qualifier, if any.
unsigned ConstQualLoc;
@@ -1022,6 +1034,9 @@ struct DeclaratorChunk {
/// The location of the restrict-qualifier, if any.
unsigned RestrictQualLoc;
+ /// The location of the _Atomic-qualifier, if any.
+ unsigned AtomicQualLoc;
+
void destroy() {
}
};
@@ -1036,8 +1051,8 @@ struct DeclaratorChunk {
};
struct ArrayTypeInfo : TypeInfoCommon {
- /// The type qualifiers for the array: const/volatile/restrict.
- unsigned TypeQuals : 3;
+ /// The type qualifiers for the array: const/volatile/restrict/_Atomic.
+ unsigned TypeQuals : 4;
/// True if this dimension included the 'static' keyword.
bool hasStatic : 1;
@@ -1259,16 +1274,16 @@ struct DeclaratorChunk {
struct BlockPointerTypeInfo : TypeInfoCommon {
/// For now, sema will catch these as invalid.
- /// The type qualifiers: const/volatile/restrict.
- unsigned TypeQuals : 3;
+ /// The type qualifiers: const/volatile/restrict/_Atomic.
+ unsigned TypeQuals : 4;
void destroy() {
}
};
struct MemberPointerTypeInfo : TypeInfoCommon {
- /// The type qualifiers: const/volatile/restrict.
- unsigned TypeQuals : 3;
+ /// The type qualifiers: const/volatile/restrict/_Atomic.
+ unsigned TypeQuals : 4;
// CXXScopeSpec has a constructor, so it can't be a direct member.
// So we need some pointer-aligned storage and a bit of trickery.
union {
@@ -1422,6 +1437,9 @@ struct DeclaratorChunk {
return I;
}
+ bool isParen() const {
+ return Kind == Paren;
+ }
};
/// \brief Described the kind of function definition (if any) provided for
@@ -1783,33 +1801,41 @@ public:
return DeclTypeInfo[i];
}
- void DropFirstTypeObject()
- {
+ void DropFirstTypeObject() {
assert(!DeclTypeInfo.empty() && "No type chunks to drop.");
DeclTypeInfo.front().destroy();
DeclTypeInfo.erase(DeclTypeInfo.begin());
}
+ /// Return the innermost (closest to the declarator) chunk of this
+ /// declarator that is not a parens chunk, or null if there are no
+ /// non-parens chunks.
+ const DeclaratorChunk *getInnermostNonParenChunk() const {
+ for (unsigned i = 0, i_end = DeclTypeInfo.size(); i < i_end; ++i) {
+ if (!DeclTypeInfo[i].isParen())
+ return &DeclTypeInfo[i];
+ }
+ return 0;
+ }
+
+ /// Return the outermost (furthest from the declarator) chunk of
+ /// this declarator that is not a parens chunk, or null if there are
+ /// no non-parens chunks.
+ const DeclaratorChunk *getOutermostNonParenChunk() const {
+ for (unsigned i = DeclTypeInfo.size(), i_end = 0; i != i_end; --i) {
+ if (!DeclTypeInfo[i-1].isParen())
+ return &DeclTypeInfo[i-1];
+ }
+ return 0;
+ }
+
/// isArrayOfUnknownBound - This method returns true if the declarator
/// is a declarator for an array of unknown bound (looking through
/// parentheses).
bool isArrayOfUnknownBound() const {
- for (unsigned i = 0, i_end = DeclTypeInfo.size(); i < i_end; ++i) {
- switch (DeclTypeInfo[i].Kind) {
- case DeclaratorChunk::Paren:
- continue;
- case DeclaratorChunk::Function:
- case DeclaratorChunk::Pointer:
- case DeclaratorChunk::Reference:
- case DeclaratorChunk::BlockPointer:
- case DeclaratorChunk::MemberPointer:
- return false;
- case DeclaratorChunk::Array:
- return !DeclTypeInfo[i].Arr.NumElts;
- }
- llvm_unreachable("Invalid type chunk");
- }
- return false;
+ const DeclaratorChunk *chunk = getInnermostNonParenChunk();
+ return (chunk && chunk->Kind == DeclaratorChunk::Array &&
+ !chunk->Arr.NumElts);
}
/// isFunctionDeclarator - This method returns true if the declarator
@@ -1866,7 +1892,54 @@ public:
/// isn't a function declarator, if the type specifier refers to a function
/// type. This routine checks for both cases.
bool isDeclarationOfFunction() const;
+
+ /// \brief Return true if this declaration appears in a context where a
+ /// function declarator would be a function declaration.
+ bool isFunctionDeclarationContext() const {
+ if (getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef)
+ return false;
+
+ switch (Context) {
+ case FileContext:
+ case MemberContext:
+ case BlockContext:
+ return true;
+
+ case ForContext:
+ case ConditionContext:
+ case KNRTypeListContext:
+ case TypeNameContext:
+ case AliasDeclContext:
+ case AliasTemplateContext:
+ case PrototypeContext:
+ case ObjCParameterContext:
+ case ObjCResultContext:
+ case TemplateParamContext:
+ case CXXNewContext:
+ case CXXCatchContext:
+ case ObjCCatchContext:
+ case BlockLiteralContext:
+ case LambdaExprContext:
+ case TemplateTypeArgContext:
+ case TrailingReturnContext:
+ return false;
+ }
+ llvm_unreachable("unknown context kind!");
+ }
+ /// \brief Return true if a function declarator at this position would be a
+ /// function declaration.
+ bool isFunctionDeclaratorAFunctionDeclaration() const {
+ if (!isFunctionDeclarationContext())
+ return false;
+
+ for (unsigned I = 0, N = getNumTypeObjects(); I != N; ++I)
+ if (getTypeObject(I).Kind != DeclaratorChunk::Paren)
+ return false;
+
+ return true;
+ }
+
/// takeAttributes - Takes attributes from the given parsed-attributes
/// set and add them to this declarator.
///
@@ -1897,6 +1970,17 @@ public:
return false;
}
+ /// \brief Return a source range list of C++11 attributes associated
+ /// with the declarator.
+ void getCXX11AttributeRanges(SmallVector<SourceRange, 4> &Ranges) {
+ AttributeList *AttrList = Attrs.getList();
+ while (AttrList) {
+ if (AttrList->isCXX11Attribute())
+ Ranges.push_back(AttrList->getRange());
+ AttrList = AttrList->getNext();
+ }
+ }
+
void setAsmLabel(Expr *E) { AsmLabel = E; }
Expr *getAsmLabel() const { return AsmLabel; }
@@ -1996,7 +2080,7 @@ struct LambdaIntroducer {
SourceRange Range;
SourceLocation DefaultLoc;
LambdaCaptureDefault Default;
- llvm::SmallVector<LambdaCapture, 4> Captures;
+ SmallVector<LambdaCapture, 4> Captures;
LambdaIntroducer()
: Default(LCD_None) {}
diff --git a/include/clang/Sema/DelayedDiagnostic.h b/include/clang/Sema/DelayedDiagnostic.h
index a20480c..3704e09 100644
--- a/include/clang/Sema/DelayedDiagnostic.h
+++ b/include/clang/Sema/DelayedDiagnostic.h
@@ -199,21 +199,25 @@ public:
}
private:
+
+ struct DD {
+ const NamedDecl *Decl;
+ const ObjCInterfaceDecl *UnknownObjCClass;
+ const ObjCPropertyDecl *ObjCProperty;
+ const char *Message;
+ size_t MessageLen;
+ };
+
+ struct FTD {
+ unsigned Diagnostic;
+ unsigned Argument;
+ void *OperandType;
+ };
+
union {
- /// Deprecation.
- struct {
- const NamedDecl *Decl;
- const ObjCInterfaceDecl *UnknownObjCClass;
- const ObjCPropertyDecl *ObjCProperty;
- const char *Message;
- size_t MessageLen;
- } DeprecationData;
-
- struct {
- unsigned Diagnostic;
- unsigned Argument;
- void *OperandType;
- } ForbiddenTypeData;
+ /// Deprecation
+ struct DD DeprecationData;
+ struct FTD ForbiddenTypeData;
/// Access control.
char AccessData[sizeof(AccessedEntity)];
@@ -224,14 +228,14 @@ private:
/// delayed.
class DelayedDiagnosticPool {
const DelayedDiagnosticPool *Parent;
- llvm::SmallVector<DelayedDiagnostic, 4> Diagnostics;
+ SmallVector<DelayedDiagnostic, 4> Diagnostics;
DelayedDiagnosticPool(const DelayedDiagnosticPool &) LLVM_DELETED_FUNCTION;
void operator=(const DelayedDiagnosticPool &) LLVM_DELETED_FUNCTION;
public:
DelayedDiagnosticPool(const DelayedDiagnosticPool *parent) : Parent(parent) {}
~DelayedDiagnosticPool() {
- for (llvm::SmallVectorImpl<DelayedDiagnostic>::iterator
+ for (SmallVectorImpl<DelayedDiagnostic>::iterator
i = Diagnostics.begin(), e = Diagnostics.end(); i != e; ++i)
i->Destroy();
}
@@ -260,8 +264,7 @@ public:
pool.Diagnostics.clear();
}
- typedef llvm::SmallVectorImpl<DelayedDiagnostic>::const_iterator
- pool_iterator;
+ typedef SmallVectorImpl<DelayedDiagnostic>::const_iterator pool_iterator;
pool_iterator pool_begin() const { return Diagnostics.begin(); }
pool_iterator pool_end() const { return Diagnostics.end(); }
bool pool_empty() const { return Diagnostics.empty(); }
diff --git a/include/clang/Sema/ExternalSemaSource.h b/include/clang/Sema/ExternalSemaSource.h
index 7a59849..cbce757 100644
--- a/include/clang/Sema/ExternalSemaSource.h
+++ b/include/clang/Sema/ExternalSemaSource.h
@@ -15,6 +15,7 @@
#include "clang/AST/ExternalASTSource.h"
#include "clang/Sema/Weak.h"
+#include "llvm/ADT/MapVector.h"
#include <utility>
namespace clang {
@@ -65,7 +66,12 @@ public:
/// which will be used during typo correction.
virtual void ReadKnownNamespaces(
SmallVectorImpl<NamespaceDecl *> &Namespaces);
-
+
+ /// \brief Load the set of used but not defined functions or variables with
+ /// internal linkage, or used but not defined internal functions.
+ virtual void ReadUndefinedButUsed(
+ llvm::DenseMap<NamedDecl*, SourceLocation> &Undefined);
+
/// \brief Do last resort, unqualified lookup on a LookupResult that
/// Sema cannot find.
///
@@ -130,7 +136,7 @@ public:
/// declarations to the given vector of declarations. Note that this routine
/// may be invoked multiple times; the external source should take care not
/// to introduce the same declarations repeatedly.
- virtual void ReadLocallyScopedExternalDecls(
+ virtual void ReadLocallyScopedExternCDecls(
SmallVectorImpl<NamedDecl *> &Decls) {}
/// \brief Read the set of referenced selectors known to the
diff --git a/include/clang/Sema/IdentifierResolver.h b/include/clang/Sema/IdentifierResolver.h
index dff0134..0b1b74a 100644
--- a/include/clang/Sema/IdentifierResolver.h
+++ b/include/clang/Sema/IdentifierResolver.h
@@ -158,8 +158,7 @@ public:
/// \param ExplicitInstantiationOrSpecialization When true, we are checking
/// whether the declaration is in scope for the purposes of explicit template
/// instantiation or specialization. The default is false.
- bool isDeclInScope(Decl *D, DeclContext *Ctx, ASTContext &Context,
- Scope *S = 0,
+ bool isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S = 0,
bool ExplicitInstantiationOrSpecialization = false) const;
/// AddDecl - Link the decl to its shadowed decl chain.
diff --git a/include/clang/Sema/Initialization.h b/include/clang/Sema/Initialization.h
index 0b0af0c..8459be1 100644
--- a/include/clang/Sema/Initialization.h
+++ b/include/clang/Sema/Initialization.h
@@ -13,12 +13,13 @@
#ifndef LLVM_CLANG_SEMA_INITIALIZATION_H
#define LLVM_CLANG_SEMA_INITIALIZATION_H
-#include "clang/Sema/Ownership.h"
-#include "clang/Sema/Overload.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Type.h"
#include "clang/AST/UnresolvedSet.h"
#include "clang/Basic/SourceLocation.h"
+#include "clang/Sema/Overload.h"
+#include "clang/Sema/Ownership.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/SmallVector.h"
#include <cassert>
@@ -87,7 +88,27 @@ private:
/// \brief The type of the object or reference being initialized.
QualType Type;
-
+
+ struct LN {
+ /// \brief When Kind == EK_Result, EK_Exception, EK_New, the
+ /// location of the 'return', 'throw', or 'new' keyword,
+ /// respectively. When Kind == EK_Temporary, the location where
+ /// the temporary is being created.
+ unsigned Location;
+
+ /// \brief Whether the entity being initialized may end up using the
+ /// named return value optimization (NRVO).
+ bool NRVO;
+ };
+
+ struct C {
+ /// \brief The variable being captured by an EK_LambdaCapture.
+ VarDecl *Var;
+
+ /// \brief The source location at which the capture occurs.
+ unsigned Location;
+ };
+
union {
/// \brief When Kind == EK_Variable, or EK_Member, the VarDecl or
/// FieldDecl, respectively.
@@ -100,18 +121,8 @@ private:
/// \brief When Kind == EK_Temporary, the type source information for
/// the temporary.
TypeSourceInfo *TypeInfo;
-
- struct {
- /// \brief When Kind == EK_Result, EK_Exception, EK_New, the
- /// location of the 'return', 'throw', or 'new' keyword,
- /// respectively. When Kind == EK_Temporary, the location where
- /// the temporary is being created.
- unsigned Location;
-
- /// \brief Whether the entity being initialized may end up using the
- /// named return value optimization (NRVO).
- bool NRVO;
- } LocAndNRVO;
+
+ struct LN LocAndNRVO;
/// \brief When Kind == EK_Base, the base specifier that provides the
/// base class. The lower bit specifies whether the base is an inherited
@@ -122,14 +133,8 @@ private:
/// EK_ComplexElement, the index of the array or vector element being
/// initialized.
unsigned Index;
-
- struct {
- /// \brief The variable being captured by an EK_LambdaCapture.
- VarDecl *Var;
-
- /// \brief The source location at which the capture occurs.
- unsigned Location;
- } Capture;
+
+ struct C Capture;
};
InitializedEntity() { }
@@ -172,17 +177,25 @@ public:
static InitializedEntity InitializeVariable(VarDecl *Var) {
return InitializedEntity(Var);
}
-
+
/// \brief Create the initialization entity for a parameter.
static InitializedEntity InitializeParameter(ASTContext &Context,
ParmVarDecl *Parm) {
+ return InitializeParameter(Context, Parm, Parm->getType());
+ }
+
+ /// \brief Create the initialization entity for a parameter, but use
+ /// another type.
+ static InitializedEntity InitializeParameter(ASTContext &Context,
+ ParmVarDecl *Parm,
+ QualType Type) {
bool Consumed = (Context.getLangOpts().ObjCAutoRefCount &&
Parm->hasAttr<NSConsumedAttr>());
InitializedEntity Entity;
Entity.Kind = EK_Parameter;
- Entity.Type = Context.getVariableArrayDecayedType(
- Parm->getType().getUnqualifiedType());
+ Entity.Type =
+ Context.getVariableArrayDecayedType(Type.getUnqualifiedType());
Entity.Parent = 0;
Entity.Parameter
= (static_cast<uintptr_t>(Consumed) | reinterpret_cast<uintptr_t>(Parm));
@@ -615,7 +628,11 @@ public:
/// \brief Produce an Objective-C object pointer.
SK_ProduceObjCObject,
/// \brief Construct a std::initializer_list from an initializer list.
- SK_StdInitializerList
+ SK_StdInitializerList,
+ /// \brief Initialize an OpenCL sampler from an integer.
+ SK_OCLSamplerInit,
+ /// \brief Passing zero to a function where OpenCL event_t is expected.
+ SK_OCLZeroEvent
};
/// \brief A single step in the initialization sequence.
@@ -626,7 +643,13 @@ public:
// \brief The type that results from this initialization.
QualType Type;
-
+
+ struct F {
+ bool HadMultipleCandidates;
+ FunctionDecl *Function;
+ DeclAccessPair FoundDecl;
+ };
+
union {
/// \brief When Kind == SK_ResolvedOverloadedFunction or Kind ==
/// SK_UserConversion, the function that the expression should be
@@ -638,11 +661,7 @@ public:
/// selected from an overloaded set having size greater than 1.
/// For conversion decls, the naming class is the source type.
/// For construct decls, the naming class is the target type.
- struct {
- bool HadMultipleCandidates;
- FunctionDecl *Function;
- DeclAccessPair FoundDecl;
- } Function;
+ struct F Function;
/// \brief When Kind = SK_ConversionSequence, the implicit conversion
/// sequence.
@@ -944,6 +963,14 @@ public:
/// initializer list.
void AddStdInitializerListConstructionStep(QualType T);
+ /// \brief Add a step to initialize an OpenCL sampler from an integer
+ /// constant.
+ void AddOCLSamplerInitStep(QualType T);
+
+ /// \brief Add a step to initialize an OpenCL event_t from a NULL
+ /// constant.
+ void AddOCLZeroEventStep(QualType T);
+
/// \brief Add steps to unwrap a initializer list for a reference around a
/// single element and rewrap it at the end.
void RewrapReferenceInitList(QualType T, InitListExpr *Syntactic);
diff --git a/include/clang/Sema/Lookup.h b/include/clang/Sema/Lookup.h
index fe5d262..3e7e3a1 100644
--- a/include/clang/Sema/Lookup.h
+++ b/include/clang/Sema/Lookup.h
@@ -15,8 +15,8 @@
#ifndef LLVM_CLANG_SEMA_LOOKUP_H
#define LLVM_CLANG_SEMA_LOOKUP_H
-#include "clang/Sema/Sema.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/Sema/Sema.h"
namespace clang {
@@ -138,7 +138,8 @@ public:
IDNS(0),
Redecl(Redecl != Sema::NotForRedeclaration),
HideTags(true),
- Diagnose(Redecl == Sema::NotForRedeclaration)
+ Diagnose(Redecl == Sema::NotForRedeclaration),
+ AllowHidden(Redecl == Sema::ForRedeclaration)
{
configure();
}
@@ -158,7 +159,8 @@ public:
IDNS(0),
Redecl(Redecl != Sema::NotForRedeclaration),
HideTags(true),
- Diagnose(Redecl == Sema::NotForRedeclaration)
+ Diagnose(Redecl == Sema::NotForRedeclaration),
+ AllowHidden(Redecl == Sema::ForRedeclaration)
{
configure();
}
@@ -176,7 +178,8 @@ public:
IDNS(Other.IDNS),
Redecl(Other.Redecl),
HideTags(Other.HideTags),
- Diagnose(false)
+ Diagnose(false),
+ AllowHidden(Other.AllowHidden)
{}
~LookupResult() {
@@ -214,10 +217,16 @@ public:
return Redecl;
}
+ /// \brief Specify whether hidden declarations are visible, e.g.,
+ /// for recovery reasons.
+ void setAllowHidden(bool AH) {
+ AllowHidden = AH;
+ }
+
/// \brief Determine whether this lookup is permitted to see hidden
/// declarations, such as those in modules that have not yet been imported.
bool isHiddenDeclarationVisible() const {
- return Redecl || LookupKind == Sema::LookupTagName;
+ return AllowHidden || LookupKind == Sema::LookupTagName;
}
/// Sets whether tag declarations should be hidden by non-tag
@@ -483,6 +492,7 @@ public:
/// \brief Change this lookup's redeclaration kind.
void setRedeclarationKind(Sema::RedeclarationKind RK) {
Redecl = RK;
+ AllowHidden = (RK == Sema::ForRedeclaration);
configure();
}
@@ -615,7 +625,7 @@ private:
bool sanityCheckUnresolved() const {
for (iterator I = begin(), E = end(); I != E; ++I)
- if (isa<UnresolvedUsingValueDecl>(*I))
+ if (isa<UnresolvedUsingValueDecl>((*I)->getUnderlyingDecl()))
return true;
return false;
}
@@ -644,6 +654,9 @@ private:
bool HideTags;
bool Diagnose;
+
+ /// \brief True if we should allow hidden declarations to be 'visible'.
+ bool AllowHidden;
};
/// \brief Consumes visible declarations found when searching for
diff --git a/include/clang/Sema/Makefile b/include/clang/Sema/Makefile
index f6662d6..7d658a7 100644
--- a/include/clang/Sema/Makefile
+++ b/include/clang/Sema/Makefile
@@ -1,6 +1,7 @@
CLANG_LEVEL := ../../..
TD_SRC_DIR = $(PROJ_SRC_DIR)/../Basic
-BUILT_SOURCES = AttrTemplateInstantiate.inc AttrParsedAttrList.inc AttrParsedAttrKinds.inc
+BUILT_SOURCES = AttrTemplateInstantiate.inc AttrParsedAttrList.inc AttrParsedAttrKinds.inc \
+ AttrSpellingListIndex.inc
TABLEGEN_INC_FILES_COMMON = 1
@@ -24,4 +25,10 @@ $(ObjDir)/AttrParsedAttrKinds.inc.tmp : $(TD_SRC_DIR)/Attr.td \
$(Verb) $(ClangTableGen) -gen-clang-attr-parsed-attr-kinds -o \
$(call SYSPATH, $@) -I $(PROJ_SRC_DIR)/../../ $<
+$(ObjDir)/AttrSpellingListIndex.inc.tmp : $(TD_SRC_DIR)/Attr.td \
+ $(CLANG_TBLGEN) $(ObjDir)/.dir
+ $(Echo) "Building Clang attribute spelling list index with tablegen"
+ $(Verb) $(ClangTableGen) -gen-clang-attr-spelling-index -o \
+ $(call SYSPATH, $@) -I $(PROJ_SRC_DIR)/../../ $<
+
diff --git a/include/clang/Sema/MultiplexExternalSemaSource.h b/include/clang/Sema/MultiplexExternalSemaSource.h
index 1513aeb..ff87d05 100644
--- a/include/clang/Sema/MultiplexExternalSemaSource.h
+++ b/include/clang/Sema/MultiplexExternalSemaSource.h
@@ -15,9 +15,7 @@
#include "clang/Sema/ExternalSemaSource.h"
#include "clang/Sema/Weak.h"
-
#include "llvm/ADT/SmallVector.h"
-
#include <utility>
namespace clang {
@@ -41,7 +39,7 @@ namespace clang {
class MultiplexExternalSemaSource : public ExternalSemaSource {
private:
- llvm::SmallVector<ExternalSemaSource*, 2> Sources; // doesn't own them.
+ SmallVector<ExternalSemaSource *, 2> Sources; // doesn't own them.
public:
@@ -67,58 +65,30 @@ public:
/// \brief Resolve a declaration ID into a declaration, potentially
/// building a new declaration.
- ///
- /// This method only needs to be implemented if the AST source ever
- /// passes back decl sets as VisibleDeclaration objects.
- ///
- /// The default implementation of this method is a no-op.
virtual Decl *GetExternalDecl(uint32_t ID);
/// \brief Resolve a selector ID into a selector.
- ///
- /// This operation only needs to be implemented if the AST source
- /// returns non-zero for GetNumKnownSelectors().
- ///
- /// The default implementation of this method is a no-op.
virtual Selector GetExternalSelector(uint32_t ID);
/// \brief Returns the number of selectors known to the external AST
/// source.
- ///
- /// The default implementation of this method is a no-op.
virtual uint32_t GetNumExternalSelectors();
/// \brief Resolve the offset of a statement in the decl stream into
/// a statement.
- ///
- /// This operation is meant to be used via a LazyOffsetPtr. It only
- /// needs to be implemented if the AST source uses methods like
- /// FunctionDecl::setLazyBody when building decls.
- ///
- /// The default implementation of this method is a no-op.
virtual Stmt *GetExternalDeclStmt(uint64_t Offset);
/// \brief Resolve the offset of a set of C++ base specifiers in the decl
/// stream into an array of specifiers.
- ///
- /// The default implementation of this method is a no-op.
virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset);
- /// \brief Finds all declarations with the given name in the
+ /// \brief Find all declarations with the given name in the
/// given context.
- ///
- /// Generally the final step of this method is either to call
- /// SetExternalVisibleDeclsForName or to recursively call lookup on
- /// the DeclContext after calling SetExternalVisibleDecls.
- ///
- /// The default implementation of this method is a no-op.
- virtual DeclContextLookupResult
+ virtual bool
FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name);
/// \brief Ensures that the table of all visible declarations inside this
/// context is up to date.
- ///
- /// The default implementation of this functino is a no-op.
virtual void completeVisibleDeclsMap(const DeclContext *DC);
/// \brief Finds all declarations lexically contained within the given
@@ -129,8 +99,6 @@ public:
/// are returned.
///
/// \return an indication of whether the load succeeded or failed.
- ///
- /// The default implementation of this method is a no-op.
virtual ExternalLoadResult FindExternalLexicalDecls(const DeclContext *DC,
bool (*isKindWeWant)(Decl::Kind),
SmallVectorImpl<Decl*> &Result);
@@ -174,26 +142,18 @@ public:
/// \brief Notify ExternalASTSource that we started deserialization of
/// a decl or type so until FinishedDeserializing is called there may be
/// decls that are initializing. Must be paired with FinishedDeserializing.
- ///
- /// The default implementation of this method is a no-op.
virtual void StartedDeserializing();
/// \brief Notify ExternalASTSource that we finished the deserialization of
/// a decl or type. Must be paired with StartedDeserializing.
- ///
- /// The default implementation of this method is a no-op.
virtual void FinishedDeserializing();
/// \brief Function that will be invoked when we begin parsing a new
/// translation unit involving this external AST source.
- ///
- /// The default implementation of this method is a no-op.
virtual void StartTranslationUnit(ASTConsumer *Consumer);
/// \brief Print any statistics that have been gathered regarding
/// the external AST source.
- ///
- /// The default implementation of this method is a no-op.
virtual void PrintStats();
@@ -254,6 +214,11 @@ public:
/// \brief Load the set of namespaces that are known to the external source,
/// which will be used during typo correction.
virtual void ReadKnownNamespaces(SmallVectorImpl<NamespaceDecl*> &Namespaces);
+
+ /// \brief Load the set of used but not defined functions or variables with
+ /// internal linkage, or used but not defined inline functions.
+ virtual void ReadUndefinedButUsed(
+ llvm::DenseMap<NamedDecl*, SourceLocation> &Undefined);
/// \brief Do last resort, unqualified lookup on a LookupResult that
/// Sema cannot find.
@@ -311,14 +276,14 @@ public:
/// introduce the same declarations repeatedly.
virtual void ReadDynamicClasses(SmallVectorImpl<CXXRecordDecl*> &Decls);
- /// \brief Read the set of locally-scoped external declarations known to the
+ /// \brief Read the set of locally-scoped extern "C" declarations known to the
/// external Sema source.
///
/// The external source should append its own locally-scoped external
- /// declarations to the given vector of declarations. Note that this routine
- /// may be invoked multiple times; the external source should take care not
+ /// declarations to the given vector of declarations. Note that this routine
+ /// may be invoked multiple times; the external source should take care not
/// to introduce the same declarations repeatedly.
- virtual void ReadLocallyScopedExternalDecls(SmallVectorImpl<NamedDecl*>&Decls);
+ virtual void ReadLocallyScopedExternCDecls(SmallVectorImpl<NamedDecl*>&Decls);
/// \brief Read the set of referenced selectors known to the
/// external Sema source.
diff --git a/include/clang/Sema/Overload.h b/include/clang/Sema/Overload.h
index 65ed781..c685843 100644
--- a/include/clang/Sema/Overload.h
+++ b/include/clang/Sema/Overload.h
@@ -78,8 +78,9 @@ namespace clang {
ICK_Vector_Splat, ///< A vector splat from an arithmetic type
ICK_Complex_Real, ///< Complex-real conversions (C99 6.3.1.7)
ICK_Block_Pointer_Conversion, ///< Block Pointer conversions
- ICK_TransparentUnionConversion, /// Transparent Union Conversions
+ ICK_TransparentUnionConversion, ///< Transparent Union Conversions
ICK_Writeback_Conversion, ///< Objective-C ARC writeback conversion
+ ICK_Zero_Event_Conversion, ///< Zero constant to event (OpenCL1.2 6.12.10)
ICK_Num_Conversion_Kinds ///< The number of conversion kinds
};
@@ -694,6 +695,10 @@ namespace clang {
/// \brief Return the second template argument this deduction failure
/// refers to, if any.
const TemplateArgument *getSecondArg();
+
+ /// \brief Return the expression this deduction failure refers to,
+ /// if any.
+ Expr *getExpr();
/// \brief Free any memory associated with this deduction failure.
void Destroy();
@@ -809,7 +814,7 @@ namespace clang {
void NoteCandidates(Sema &S,
OverloadCandidateDisplayKind OCD,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
StringRef Opc = "",
SourceLocation Loc = SourceLocation());
};
diff --git a/include/clang/Sema/Ownership.h b/include/clang/Sema/Ownership.h
index e59fb3f..e064b91 100644
--- a/include/clang/Sema/Ownership.h
+++ b/include/clang/Sema/Ownership.h
@@ -23,13 +23,10 @@
//===----------------------------------------------------------------------===//
namespace clang {
- class Attr;
class CXXCtorInitializer;
class CXXBaseSpecifier;
class Decl;
- class DeclGroupRef;
class Expr;
- class NestedNameSpecifier;
class ParsedTemplateArgument;
class QualType;
class Stmt;
diff --git a/include/clang/Sema/Scope.h b/include/clang/Sema/Scope.h
index 1329f97..d016b9b 100644
--- a/include/clang/Sema/Scope.h
+++ b/include/clang/Sema/Scope.h
@@ -32,70 +32,66 @@ public:
/// ScopeFlags - These are bitfields that are or'd together when creating a
/// scope, which defines the sorts of things the scope contains.
enum ScopeFlags {
- /// FnScope - This indicates that the scope corresponds to a function, which
+ /// \brief This indicates that the scope corresponds to a function, which
/// means that labels are set here.
FnScope = 0x01,
- /// BreakScope - This is a while,do,switch,for, etc that can have break
- /// stmts embedded into it.
+ /// \brief This is a while, do, switch, for, etc that can have break
+ /// statements embedded into it.
BreakScope = 0x02,
- /// ContinueScope - This is a while,do,for, which can have continue
- /// stmt embedded into it.
+ /// \brief This is a while, do, for, which can have continue statements
+ /// embedded into it.
ContinueScope = 0x04,
- /// DeclScope - This is a scope that can contain a declaration. Some scopes
+ /// \brief This is a scope that can contain a declaration. Some scopes
/// just contain loop constructs but don't contain decls.
DeclScope = 0x08,
- /// ControlScope - The controlling scope in a if/switch/while/for statement.
+ /// \brief The controlling scope in a if/switch/while/for statement.
ControlScope = 0x10,
- /// ClassScope - The scope of a struct/union/class definition.
+ /// \brief The scope of a struct/union/class definition.
ClassScope = 0x20,
- /// BlockScope - This is a scope that corresponds to a block/closure object.
+ /// \brief This is a scope that corresponds to a block/closure object.
/// Blocks serve as top-level scopes for some objects like labels, they
/// also prevent things like break and continue. BlockScopes always have
/// the FnScope and DeclScope flags set as well.
BlockScope = 0x40,
- /// TemplateParamScope - This is a scope that corresponds to the
+ /// \brief This is a scope that corresponds to the
/// template parameters of a C++ template. Template parameter
/// scope starts at the 'template' keyword and ends when the
/// template declaration ends.
TemplateParamScope = 0x80,
- /// FunctionPrototypeScope - This is a scope that corresponds to the
+ /// \brief This is a scope that corresponds to the
/// parameters within a function prototype.
FunctionPrototypeScope = 0x100,
- /// AtCatchScope - This is a scope that corresponds to the Objective-C
+ /// \brief This is a scope that corresponds to the parameters within
+ /// a function prototype for a function declaration (as opposed to any
+ /// other kind of function declarator). Always has FunctionPrototypeScope
+ /// set as well.
+ FunctionDeclarationScope = 0x200,
+
+ /// \brief This is a scope that corresponds to the Objective-C
/// \@catch statement.
- AtCatchScope = 0x200,
+ AtCatchScope = 0x400,
- /// ObjCMethodScope - This scope corresponds to an Objective-C method body.
+ /// \brief This scope corresponds to an Objective-C method body.
/// It always has FnScope and DeclScope set as well.
- ObjCMethodScope = 0x400,
-
- /// SwitchScope - This is a scope that corresponds to a switch statement.
- SwitchScope = 0x800,
-
- /// TryScope - This is the scope of a C++ try statement.
- TryScope = 0x1000,
-
- /// CatchScope - This is the scope of a C++ catch statement.
- CatchScope = 0x2000,
+ ObjCMethodScope = 0x800,
- /// FnTryCatchScope - This is the scope for a function-level C++ try or
- /// catch scope.
- FnTryCatchScope = 0x4000,
+ /// \brief This is a scope that corresponds to a switch statement.
+ SwitchScope = 0x1000,
- /// FnTryScope - This is the scope of a function-level C++ try scope.
- FnTryScope = TryScope | FnTryCatchScope,
+ /// \brief This is the scope of a C++ try statement.
+ TryScope = 0x2000,
- /// FnCatchScope - This is the scope of a function-level C++ catch scope.
- FnCatchScope = CatchScope | FnTryCatchScope
+ /// \brief This is the scope for a function-level C++ try or catch scope.
+ FnTryCatchScope = 0x4000
};
private:
/// The parent scope for this scope. This is null for the translation-unit
@@ -244,7 +240,11 @@ public:
void setEntity(void *E) { Entity = E; }
bool hasErrorOccurred() const { return ErrorTrap.hasErrorOccurred(); }
-
+
+ bool hasUnrecoverableErrorOccurred() const {
+ return ErrorTrap.hasUnrecoverableErrorOccurred();
+ }
+
/// isClassScope - Return true if this scope is a class/struct/union scope.
bool isClassScope() const {
return (getFlags() & Scope::ClassScope);
diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h
index feda9c9..2295bf4 100644
--- a/include/clang/Sema/ScopeInfo.h
+++ b/include/clang/Sema/ScopeInfo.h
@@ -91,6 +91,9 @@ public:
/// \brief Whether this function contains any indirect gotos.
bool HasIndirectGoto;
+ /// \brief Whether a statement was dropped because it was invalid.
+ bool HasDroppedStmt;
+
/// A flag that is set when parsing a method that must call super's
/// implementation, such as \c -dealloc, \c -finalize, or any method marked
/// with \c __attribute__((objc_requires_super)).
@@ -287,9 +290,14 @@ public:
HasIndirectGoto = true;
}
+ void setHasDroppedStmt() {
+ HasDroppedStmt = true;
+ }
+
bool NeedsScopeChecking() const {
- return HasIndirectGoto ||
- (HasBranchProtectedScope && HasBranchIntoScope);
+ return !HasDroppedStmt &&
+ (HasIndirectGoto ||
+ (HasBranchProtectedScope && HasBranchIntoScope));
}
FunctionScopeInfo(DiagnosticsEngine &Diag)
@@ -297,6 +305,7 @@ public:
HasBranchProtectedScope(false),
HasBranchIntoScope(false),
HasIndirectGoto(false),
+ HasDroppedStmt(false),
ObjCShouldCallSuper(false),
ErrorTrap(Diag) { }
@@ -511,11 +520,11 @@ public:
bool ContainsUnexpandedParameterPack;
/// \brief Variables used to index into by-copy array captures.
- llvm::SmallVector<VarDecl *, 4> ArrayIndexVars;
+ SmallVector<VarDecl *, 4> ArrayIndexVars;
/// \brief Offsets into the ArrayIndexVars array at which each capture starts
/// its list of array index variables.
- llvm::SmallVector<unsigned, 4> ArrayIndexStarts;
+ SmallVector<unsigned, 4> ArrayIndexStarts;
LambdaScopeInfo(DiagnosticsEngine &Diag, CXXRecordDecl *Lambda,
CXXMethodDecl *CallOperator)
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 9b572d8..5b93e51 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -15,27 +15,30 @@
#ifndef LLVM_CLANG_SEMA_SEMA_H
#define LLVM_CLANG_SEMA_SEMA_H
-#include "clang/Sema/Ownership.h"
-#include "clang/Sema/AnalysisBasedWarnings.h"
-#include "clang/Sema/IdentifierResolver.h"
-#include "clang/Sema/ObjCMethodList.h"
-#include "clang/Sema/DeclSpec.h"
-#include "clang/Sema/ExternalSemaSource.h"
-#include "clang/Sema/LocInfoType.h"
-#include "clang/Sema/TypoCorrection.h"
-#include "clang/Sema/Weak.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/DeclarationName.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
-#include "clang/AST/DeclarationName.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/LambdaMangleContext.h"
-#include "clang/AST/TypeLoc.h"
#include "clang/AST/NSAPI.h"
-#include "clang/Lex/ModuleLoader.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/TypeLoc.h"
+#include "clang/Basic/ExpressionTraits.h"
+#include "clang/Basic/LangOptions.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/TemplateKinds.h"
#include "clang/Basic/TypeTraits.h"
-#include "clang/Basic/ExpressionTraits.h"
+#include "clang/Lex/ModuleLoader.h"
+#include "clang/Sema/AnalysisBasedWarnings.h"
+#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/ExternalSemaSource.h"
+#include "clang/Sema/IdentifierResolver.h"
+#include "clang/Sema/LocInfoType.h"
+#include "clang/Sema/ObjCMethodList.h"
+#include "clang/Sema/Ownership.h"
+#include "clang/Sema/TypoCorrection.h"
+#include "clang/Sema/Weak.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/OwningPtr.h"
@@ -129,6 +132,7 @@ namespace clang {
class ObjCMethodDecl;
class ObjCPropertyDecl;
class ObjCProtocolDecl;
+ class OMPThreadPrivateDecl;
class OverloadCandidateSet;
class OverloadExpr;
class ParenListExpr;
@@ -197,6 +201,8 @@ class Sema {
///\brief Whether Sema has generated a multiplexer and has to delete it.
bool isMultiplexExternalSource;
+ static bool mightHaveNonExternalLinkage(const DeclaratorDecl *FD);
+
public:
typedef OpaquePtr<DeclGroupRef> DeclGroupPtrTy;
typedef OpaquePtr<TemplateName> TemplateTy;
@@ -253,7 +259,7 @@ public:
/// element type here is ExprWithCleanups::Object.
SmallVector<BlockDecl*, 8> ExprCleanupObjects;
- llvm::SmallPtrSet<Expr*, 8> MaybeODRUseExprs;
+ llvm::SmallPtrSet<Expr*, 2> MaybeODRUseExprs;
/// \brief Stack containing information about each of the nested
/// function, block, and method scopes that are currently active.
@@ -272,12 +278,6 @@ public:
/// This is only necessary for issuing pretty diagnostics.
ExtVectorDeclsType ExtVectorDecls;
- /// \brief The set of types for which we have already complained about the
- /// definitions being hidden.
- ///
- /// This set is used to suppress redundant diagnostics.
- llvm::SmallPtrSet<NamedDecl *, 4> HiddenDefinitions;
-
/// FieldCollector - Collects CXXFieldDecls during parsing of C++ classes.
OwningPtr<CXXFieldCollector> FieldCollector;
@@ -298,35 +298,35 @@ public:
llvm::SmallPtrSet<const Decl*, 4> ParsingInitForAutoVars;
/// \brief A mapping from external names to the most recent
- /// locally-scoped external declaration with that name.
+ /// locally-scoped extern "C" declaration with that name.
///
/// This map contains external declarations introduced in local
- /// scoped, e.g.,
+ /// scopes, e.g.,
///
/// \code
- /// void f() {
+ /// extern "C" void f() {
/// void foo(int, int);
/// }
/// \endcode
///
- /// Here, the name "foo" will be associated with the declaration on
+ /// Here, the name "foo" will be associated with the declaration of
/// "foo" within f. This name is not visible outside of
/// "f". However, we still find it in two cases:
///
- /// - If we are declaring another external with the name "foo", we
- /// can find "foo" as a previous declaration, so that the types
- /// of this external declaration can be checked for
- /// compatibility.
+ /// - If we are declaring another global or extern "C" entity with
+ /// the name "foo", we can find "foo" as a previous declaration,
+ /// so that the types of this external declaration can be checked
+ /// for compatibility.
///
/// - If we would implicitly declare "foo" (e.g., due to a call to
/// "foo" in C when no prototype or definition is visible), then
/// we find this declaration of "foo" and complain that it is
/// not visible.
- llvm::DenseMap<DeclarationName, NamedDecl *> LocallyScopedExternalDecls;
+ llvm::DenseMap<DeclarationName, NamedDecl *> LocallyScopedExternCDecls;
- /// \brief Look for a locally scoped external declaration by the given name.
+ /// \brief Look for a locally scoped extern "C" declaration by the given name.
llvm::DenseMap<DeclarationName, NamedDecl *>::iterator
- findLocallyScopedExternalDecl(DeclarationName Name);
+ findLocallyScopedExternCDecl(DeclarationName Name);
typedef LazyVector<VarDecl *, ExternalSemaSource,
&ExternalSemaSource::ReadTentativeDefinitions, 2, 2>
@@ -363,6 +363,16 @@ public:
const CXXDestructorDecl*>, 2>
DelayedDestructorExceptionSpecChecks;
+ /// \brief All the members seen during a class definition which were both
+ /// explicitly defaulted and had explicitly-specified exception
+ /// specifications, along with the function type containing their
+ /// user-specified exception specification. Those exception specifications
+ /// were overridden with the default specifications, but we still need to
+ /// check whether they are compatible with the default specification, and
+ /// we can't do that until the nesting set of class definitions is complete.
+ SmallVector<std::pair<CXXMethodDecl*, const FunctionProtoType*>, 2>
+ DelayedDefaultedMemberExceptionSpecs;
+
/// \brief Callback to the parser to parse templated functions when needed.
typedef void LateTemplateParserCB(void *P, const FunctionDecl *FD);
LateTemplateParserCB *LateTemplateParser;
@@ -533,7 +543,7 @@ public:
RecordDecl *MSVCGuidDecl;
/// \brief Caches identifiers/selectors for NSFoundation APIs.
- llvm::OwningPtr<NSAPI> NSAPIObj;
+ OwningPtr<NSAPI> NSAPIObj;
/// \brief The declaration of the Objective-C NSNumber class.
ObjCInterfaceDecl *NSNumberDecl;
@@ -568,6 +578,9 @@ public:
/// \brief id<NSCopying> type.
QualType QIDNSCopying;
+ /// \brief will hold 'respondsToSelector:'
+ Selector RespondsToSelectorSel;
+
/// A flag to remember whether the implicit forms of operator new and delete
/// have been declared.
bool GlobalNewDeleteDeclared;
@@ -619,11 +632,11 @@ public:
/// this expression evaluation context.
unsigned NumCleanupObjects;
- llvm::SmallPtrSet<Expr*, 8> SavedMaybeODRUseExprs;
+ llvm::SmallPtrSet<Expr*, 2> SavedMaybeODRUseExprs;
/// \brief The lambdas that are present within this context, if it
/// is indeed an unevaluated context.
- llvm::SmallVector<LambdaExpr *, 2> Lambdas;
+ SmallVector<LambdaExpr *, 2> Lambdas;
/// \brief The declaration that provides context for the lambda expression
/// if the normal declaration context does not suffice, e.g., in a
@@ -635,15 +648,15 @@ public:
///
/// This mangling information is allocated lazily, since most contexts
/// do not have lambda expressions.
- LambdaMangleContext *LambdaMangle;
+ IntrusiveRefCntPtr<LambdaMangleContext> LambdaMangle;
/// \brief If we are processing a decltype type, a set of call expressions
/// for which we have deferred checking the completeness of the return type.
- llvm::SmallVector<CallExpr*, 8> DelayedDecltypeCalls;
+ SmallVector<CallExpr *, 8> DelayedDecltypeCalls;
/// \brief If we are processing a decltype type, a set of temporary binding
/// expressions for which we have deferred checking the destructor.
- llvm::SmallVector<CXXBindTemporaryExpr*, 8> DelayedDecltypeBinds;
+ SmallVector<CXXBindTemporaryExpr *, 8> DelayedDecltypeBinds;
ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context,
unsigned NumCleanupObjects,
@@ -654,10 +667,6 @@ public:
IsDecltype(IsDecltype), NumCleanupObjects(NumCleanupObjects),
LambdaContextDecl(LambdaContextDecl), LambdaMangle() { }
- ~ExpressionEvaluationContextRecord() {
- delete LambdaMangle;
- }
-
/// \brief Retrieve the mangling context for lambdas.
LambdaMangleContext &getLambdaMangleContext() {
assert(LambdaContextDecl && "Need to have a lambda context declaration");
@@ -730,11 +739,15 @@ public:
// Contains the locations of the beginning of unparsed default
// argument locations.
- llvm::DenseMap<ParmVarDecl *,SourceLocation> UnparsedDefaultArgLocs;
+ llvm::DenseMap<ParmVarDecl *, SourceLocation> UnparsedDefaultArgLocs;
+
+ /// UndefinedInternals - all the used, undefined objects which require a
+ /// definition in this translation unit.
+ llvm::DenseMap<NamedDecl *, SourceLocation> UndefinedButUsed;
- /// UndefinedInternals - all the used, undefined objects with
- /// internal linkage in this translation unit.
- llvm::DenseMap<NamedDecl*, SourceLocation> UndefinedInternals;
+ /// Obtain a sorted list of functions that are undefined but ODR-used.
+ void getUndefinedButUsed(
+ llvm::SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> > &Undefined);
typedef std::pair<ObjCMethodList, ObjCMethodList> GlobalMethods;
typedef llvm::DenseMap<Selector, GlobalMethods> GlobalMethodPool;
@@ -749,6 +762,24 @@ public:
/// of -Wselector.
llvm::DenseMap<Selector, SourceLocation> ReferencedSelectors;
+ /// Kinds of C++ special members.
+ enum CXXSpecialMember {
+ CXXDefaultConstructor,
+ CXXCopyConstructor,
+ CXXMoveConstructor,
+ CXXCopyAssignment,
+ CXXMoveAssignment,
+ CXXDestructor,
+ CXXInvalid
+ };
+
+ typedef std::pair<CXXRecordDecl*, CXXSpecialMember> SpecialMemberDecl;
+
+ /// The C++ special members which we are currently in the process of
+ /// declaring. If this process recursively triggers the declaration of the
+ /// same special member, we should act as if it is not yet declared.
+ llvm::SmallSet<SpecialMemberDecl, 4> SpecialMembersBeingDeclared;
+
void ReadMethodPool(Selector Sel);
/// Private Helper predicate to check for 'self'.
@@ -903,10 +934,10 @@ public:
// Type Analysis / Processing: SemaType.cpp.
//
- QualType BuildQualifiedType(QualType T, SourceLocation Loc, Qualifiers Qs);
- QualType BuildQualifiedType(QualType T, SourceLocation Loc, unsigned CVR) {
- return BuildQualifiedType(T, Loc, Qualifiers::fromCVRMask(CVR));
- }
+ QualType BuildQualifiedType(QualType T, SourceLocation Loc, Qualifiers Qs,
+ const DeclSpec *DS = 0);
+ QualType BuildQualifiedType(QualType T, SourceLocation Loc, unsigned CVRA,
+ const DeclSpec *DS = 0);
QualType BuildPointerType(QualType T,
SourceLocation Loc, DeclarationName Entity);
QualType BuildReferenceType(QualType T, bool LValueRef,
@@ -916,12 +947,39 @@ public:
SourceRange Brackets, DeclarationName Entity);
QualType BuildExtVectorType(QualType T, Expr *ArraySize,
SourceLocation AttrLoc);
+
+ /// \brief Build a function type.
+ ///
+ /// This routine checks the function type according to C++ rules and
+ /// under the assumption that the result type and parameter types have
+ /// just been instantiated from a template. It therefore duplicates
+ /// some of the behavior of GetTypeForDeclarator, but in a much
+ /// simpler form that is only suitable for this narrow use case.
+ ///
+ /// \param T The return type of the function.
+ ///
+ /// \param ParamTypes The parameter types of the function. This array
+ /// will be modified to account for adjustments to the types of the
+ /// function parameters.
+ ///
+ /// \param Loc The location of the entity whose type involves this
+ /// function type or, if there is no such entity, the location of the
+ /// type that will have function type.
+ ///
+ /// \param Entity The name of the entity that involves the function
+ /// type, if known.
+ ///
+ /// \param EPI Extra information about the function type. Usually this will
+ /// be taken from an existing function with the same prototype.
+ ///
+ /// \returns A suitable function type, if there are no errors. The
+ /// unqualified type will always be a FunctionProtoType.
+ /// Otherwise, returns a NULL type.
QualType BuildFunctionType(QualType T,
- QualType *ParamTypes, unsigned NumParamTypes,
- bool Variadic, bool HasTrailingReturn,
- unsigned Quals, RefQualifierKind RefQualifier,
+ llvm::MutableArrayRef<QualType> ParamTypes,
SourceLocation Loc, DeclarationName Entity,
- FunctionType::ExtInfo Info);
+ const FunctionProtoType::ExtProtoInfo &EPI);
+
QualType BuildMemberPointerType(QualType T, QualType Class,
SourceLocation Loc,
DeclarationName Entity);
@@ -943,7 +1001,7 @@ public:
CanThrowResult canThrow(const Expr *E);
const FunctionProtoType *ResolveExceptionSpec(SourceLocation Loc,
const FunctionProtoType *FPT);
- bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range);
+ bool CheckSpecifiedExceptionType(QualType &T, const SourceRange &Range);
bool CheckDistantExceptionSpec(QualType T);
bool CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New);
bool CheckEquivalentExceptionSpec(
@@ -1291,8 +1349,8 @@ public:
Decl *ActOnDeclarator(Scope *S, Declarator &D);
- Decl *HandleDeclarator(Scope *S, Declarator &D,
- MultiTemplateParamsArg TemplateParameterLists);
+ NamedDecl *HandleDeclarator(Scope *S, Declarator &D,
+ MultiTemplateParamsArg TemplateParameterLists);
void RegisterLocallyScopedExternCDecl(NamedDecl *ND,
const LookupResult &Previous,
Scope *S);
@@ -1300,7 +1358,7 @@ public:
bool diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC,
DeclarationName Name,
SourceLocation Loc);
- void DiagnoseFunctionSpecifiers(Declarator& D);
+ void DiagnoseFunctionSpecifiers(const DeclSpec &DS);
void CheckShadow(Scope *S, VarDecl *D, const LookupResult& R);
void CheckShadow(Scope *S, VarDecl *D);
void CheckCastAlign(Expr *Op, QualType T, SourceRange TRange);
@@ -1317,6 +1375,7 @@ public:
// Returns true if the variable declaration is a redeclaration
bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous);
void CheckCompleteVariableDeclaration(VarDecl *var);
+ void MaybeSuggestAddingStaticToDecl(const FunctionDecl *D);
void ActOnStartFunctionDeclarator();
void ActOnEndFunctionDeclarator();
NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
@@ -1343,7 +1402,7 @@ public:
ParmVarDecl *CheckParameter(DeclContext *DC, SourceLocation StartLoc,
SourceLocation NameLoc, IdentifierInfo *Name,
QualType T, TypeSourceInfo *TSInfo,
- StorageClass SC, StorageClass SCAsWritten);
+ StorageClass SC);
void ActOnParamDefaultArgument(Decl *param,
SourceLocation EqualLoc,
Expr *defarg);
@@ -1383,9 +1442,19 @@ public:
return D && isa<ObjCMethodDecl>(D);
}
+ /// \brief Determine whether we can skip parsing the body of a function
+ /// definition, assuming we don't care about analyzing its body or emitting
+ /// code for that function.
+ ///
+ /// This will be \c false only if we may need the body of the function in
+ /// order to parse the rest of the program (for instance, if it is
+ /// \c constexpr in C++11 or has an 'auto' return type in C++14).
+ bool canSkipFunctionBody(Decl *D);
+
void computeNRVO(Stmt *Body, sema::FunctionScopeInfo *Scope);
Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body);
Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body, bool IsInstantiation);
+ Decl *ActOnSkippedFunctionBody(Decl *Decl);
/// ActOnFinishDelayedAttribute - Invoked when we have finished parsing an
/// attribute for which parsing is delayed.
@@ -1409,6 +1478,11 @@ public:
SourceLocation AsmLoc,
SourceLocation RParenLoc);
+ /// \brief Handle a C++11 empty-declaration and attribute-declaration.
+ Decl *ActOnEmptyDeclaration(Scope *S,
+ AttributeList *AttrList,
+ SourceLocation SemiLoc);
+
/// \brief The parser has processed a module import declaration.
///
/// \param AtLoc The location of the '@' symbol, if any.
@@ -1419,6 +1493,14 @@ public:
DeclResult ActOnModuleImport(SourceLocation AtLoc, SourceLocation ImportLoc,
ModuleIdPath Path);
+ /// \brief Create an implicit import of the given module at the given
+ /// source location.
+ ///
+ /// This routine is typically used for error recovery, when the entity found
+ /// by name lookup is actually hidden within a module that we know about but
+ /// the user has forgotten to import.
+ void createImplicitModuleImport(SourceLocation Loc, Module *Mod);
+
/// \brief Retrieve a suitable printing policy.
PrintingPolicy getPrintingPolicy() const {
return getPrintingPolicy(Context, PP);
@@ -1436,7 +1518,8 @@ public:
DeclSpec &DS);
Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
DeclSpec &DS,
- MultiTemplateParamsArg TemplateParams);
+ MultiTemplateParamsArg TemplateParams,
+ bool IsExplicitInstantiation = false);
Decl *BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
AccessSpecifier AS,
@@ -1502,17 +1585,10 @@ public:
AccessSpecifier AS, NamedDecl *PrevDecl,
Declarator *D = 0);
- enum CXXSpecialMember {
- CXXDefaultConstructor,
- CXXCopyConstructor,
- CXXMoveConstructor,
- CXXCopyAssignment,
- CXXMoveAssignment,
- CXXDestructor,
- CXXInvalid
- };
bool CheckNontrivialField(FieldDecl *FD);
- void DiagnoseNontrivial(const RecordType* Record, CXXSpecialMember mem);
+ void DiagnoseNontrivial(const CXXRecordDecl *Record, CXXSpecialMember CSM);
+ bool SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM,
+ bool Diagnose = false);
CXXSpecialMember getSpecialMember(const CXXMethodDecl *MD);
void ActOnLastBitfield(SourceLocation DeclStart,
SmallVectorImpl<Decl *> &AllIvarDecls);
@@ -1522,7 +1598,7 @@ public:
// This is used for both record definitions and ObjC interface declarations.
void ActOnFields(Scope* S, SourceLocation RecLoc, Decl *TagDecl,
- llvm::ArrayRef<Decl *> Fields,
+ ArrayRef<Decl *> Fields,
SourceLocation LBrac, SourceLocation RBrac,
AttributeList *AttrList);
@@ -1639,30 +1715,54 @@ public:
bool isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New);
/// Attribute merging methods. Return true if a new attribute was added.
- AvailabilityAttr *mergeAvailabilityAttr(Decl *D, SourceRange Range,
+ AvailabilityAttr *mergeAvailabilityAttr(NamedDecl *D, SourceRange Range,
IdentifierInfo *Platform,
VersionTuple Introduced,
VersionTuple Deprecated,
VersionTuple Obsoleted,
bool IsUnavailable,
- StringRef Message);
+ StringRef Message,
+ bool Override,
+ unsigned AttrSpellingListIndex);
+ TypeVisibilityAttr *mergeTypeVisibilityAttr(Decl *D, SourceRange Range,
+ TypeVisibilityAttr::VisibilityType Vis,
+ unsigned AttrSpellingListIndex);
VisibilityAttr *mergeVisibilityAttr(Decl *D, SourceRange Range,
- VisibilityAttr::VisibilityType Vis);
- DLLImportAttr *mergeDLLImportAttr(Decl *D, SourceRange Range);
- DLLExportAttr *mergeDLLExportAttr(Decl *D, SourceRange Range);
+ VisibilityAttr::VisibilityType Vis,
+ unsigned AttrSpellingListIndex);
+ DLLImportAttr *mergeDLLImportAttr(Decl *D, SourceRange Range,
+ unsigned AttrSpellingListIndex);
+ DLLExportAttr *mergeDLLExportAttr(Decl *D, SourceRange Range,
+ unsigned AttrSpellingListIndex);
FormatAttr *mergeFormatAttr(Decl *D, SourceRange Range, StringRef Format,
- int FormatIdx, int FirstArg);
- SectionAttr *mergeSectionAttr(Decl *D, SourceRange Range, StringRef Name);
- bool mergeDeclAttribute(Decl *New, InheritableAttr *Attr);
+ int FormatIdx, int FirstArg,
+ unsigned AttrSpellingListIndex);
+ SectionAttr *mergeSectionAttr(Decl *D, SourceRange Range, StringRef Name,
+ unsigned AttrSpellingListIndex);
+
+ /// \brief Describes the kind of merge to perform for availability
+ /// attributes (including "deprecated", "unavailable", and "availability").
+ enum AvailabilityMergeKind {
+ /// \brief Don't merge availability attributes at all.
+ AMK_None,
+ /// \brief Merge availability attributes for a redeclaration, which requires
+ /// an exact match.
+ AMK_Redeclaration,
+ /// \brief Merge availability attributes for an override, which requires
+ /// an exact match or a weakening of constraints.
+ AMK_Override
+ };
- void mergeDeclAttributes(Decl *New, Decl *Old, bool MergeDeprecation = true);
+ void mergeDeclAttributes(NamedDecl *New, Decl *Old,
+ AvailabilityMergeKind AMK = AMK_Redeclaration);
void MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls);
bool MergeFunctionDecl(FunctionDecl *New, Decl *Old, Scope *S);
bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old,
Scope *S);
void mergeObjCMethodDecls(ObjCMethodDecl *New, ObjCMethodDecl *Old);
- void MergeVarDecl(VarDecl *New, LookupResult &OldDecls);
- void MergeVarDeclTypes(VarDecl *New, VarDecl *Old);
+ void MergeVarDecl(VarDecl *New, LookupResult &OldDecls,
+ bool OldDeclsWereHidden);
+ void MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool OldIsHidden);
void MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old);
bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Scope *S);
@@ -1841,6 +1941,19 @@ public:
};
ObjCSubscriptKind CheckSubscriptingKind(Expr *FromE);
+ // Note that LK_String is intentionally after the other literals, as
+ // this is used for diagnostics logic.
+ enum ObjCLiteralKind {
+ LK_Array,
+ LK_Dictionary,
+ LK_Numeric,
+ LK_Boxed,
+ LK_String,
+ LK_Block,
+ LK_None
+ };
+ ObjCLiteralKind CheckLiteralKind(Expr *FromE);
+
ExprResult PerformObjectMemberConversion(Expr *From,
NestedNameSpecifier *Qualifier,
NamedDecl *FoundDecl,
@@ -1853,13 +1966,13 @@ public:
void AddOverloadCandidate(FunctionDecl *Function,
DeclAccessPair FoundDecl,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
bool PartialOverloading = false,
bool AllowExplicit = false);
void AddFunctionCandidates(const UnresolvedSetImpl &Functions,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
TemplateArgumentListInfo *ExplicitTemplateArgs = 0);
@@ -1873,7 +1986,7 @@ public:
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, QualType ObjectType,
Expr::Classification ObjectClassification,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false);
void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
@@ -1882,13 +1995,13 @@ public:
TemplateArgumentListInfo *ExplicitTemplateArgs,
QualType ObjectType,
Expr::Classification ObjectClassification,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false);
void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
DeclAccessPair FoundDecl,
TemplateArgumentListInfo *ExplicitTemplateArgs,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false);
void AddConversionCandidate(CXXConversionDecl *Conversion,
@@ -1905,7 +2018,7 @@ public:
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
const FunctionProtoType *Proto,
- Expr *Object, llvm::ArrayRef<Expr*> Args,
+ Expr *Object, ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet);
void AddMemberOperatorCandidates(OverloadedOperatorKind Op,
SourceLocation OpLoc,
@@ -1923,7 +2036,7 @@ public:
OverloadCandidateSet& CandidateSet);
void AddArgumentDependentLookupCandidates(DeclarationName Name,
bool Operator, SourceLocation Loc,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
TemplateArgumentListInfo *ExplicitTemplateArgs,
OverloadCandidateSet& CandidateSet,
bool PartialOverloading = false);
@@ -1971,7 +2084,7 @@ public:
FunctionDecl *Fn);
void AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet,
bool PartialOverloading = false);
@@ -2164,7 +2277,7 @@ private:
//
// The boolean value will be true to indicate that the namespace was loaded
// from an AST/PCH file, or false otherwise.
- llvm::DenseMap<NamespaceDecl*, bool> KnownNamespaces;
+ llvm::MapVector<NamespaceDecl*, bool> KnownNamespaces;
/// \brief Whether we have already loaded known namespaces from an extenal
/// source.
@@ -2218,7 +2331,7 @@ public:
void ArgumentDependentLookup(DeclarationName Name, bool Operator,
SourceLocation Loc,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
ADLResult &Functions);
void LookupVisibleDecls(Scope *S, LookupNameKind Kind,
@@ -2237,7 +2350,7 @@ public:
const ObjCObjectPointerType *OPT = 0);
void FindAssociatedClassesAndNamespaces(SourceLocation InstantiationLoc,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
AssociatedNamespaceSet &AssociatedNamespaces,
AssociatedClassSet &AssociatedClasses);
@@ -2260,19 +2373,25 @@ public:
// More parsing and symbol table subroutines.
+ void ProcessPragmaWeak(Scope *S, Decl *D);
// Decl attributes - this routine is the top level dispatcher.
void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD,
- bool NonInheritable = true, bool Inheritable = true);
+ bool NonInheritable = true,
+ bool Inheritable = true);
void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AL,
- bool NonInheritable = true, bool Inheritable = true);
+ bool NonInheritable = true,
+ bool Inheritable = true,
+ bool IncludeCXX11Attributes = true);
bool ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl,
const AttributeList *AttrList);
void checkUnusedDeclAttributes(Declarator &D);
bool CheckRegparmAttr(const AttributeList &attr, unsigned &value);
- bool CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC);
+ bool CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
+ const FunctionDecl *FD = 0);
bool CheckNoReturnAttr(const AttributeList &attr);
+ void CheckAlignasUnderalignment(Decl *D);
/// \brief Stmt attributes - this routine is the top level dispatcher.
StmtResult ProcessStmtAttributes(Stmt *Stmt, AttributeList *Attrs,
@@ -2339,21 +2458,27 @@ public:
llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap,
llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& SuperPropMap);
+ /// IvarBacksCurrentMethodAccessor - This routine returns 'true' if 'IV' is
+ /// an ivar synthesized for 'Method' and 'Method' is a property accessor
+ /// declared in class 'IFace'.
+ bool IvarBacksCurrentMethodAccessor(ObjCInterfaceDecl *IFace,
+ ObjCMethodDecl *Method, ObjCIvarDecl *IV);
+
/// Called by ActOnProperty to handle \@property declarations in
/// class extensions.
- Decl *HandlePropertyInClassExtension(Scope *S,
- SourceLocation AtLoc,
- SourceLocation LParenLoc,
- FieldDeclarator &FD,
- Selector GetterSel,
- Selector SetterSel,
- const bool isAssign,
- const bool isReadWrite,
- const unsigned Attributes,
- const unsigned AttributesAsWritten,
- bool *isOverridingProperty,
- TypeSourceInfo *T,
- tok::ObjCKeywordKind MethodImplKind);
+ ObjCPropertyDecl *HandlePropertyInClassExtension(Scope *S,
+ SourceLocation AtLoc,
+ SourceLocation LParenLoc,
+ FieldDeclarator &FD,
+ Selector GetterSel,
+ Selector SetterSel,
+ const bool isAssign,
+ const bool isReadWrite,
+ const unsigned Attributes,
+ const unsigned AttributesAsWritten,
+ bool *isOverridingProperty,
+ TypeSourceInfo *T,
+ tok::ObjCKeywordKind MethodImplKind);
/// Called by ActOnProperty and HandlePropertyInClassExtension to
/// handle creating the ObjcPropertyDecl for a category or \@interface.
@@ -2507,8 +2632,15 @@ public:
FullExprArg MakeFullExpr(Expr *Arg, SourceLocation CC) {
return FullExprArg(ActOnFinishFullExpr(Arg, CC).release());
}
+ FullExprArg MakeFullDiscardedValueExpr(Expr *Arg) {
+ ExprResult FE =
+ ActOnFinishFullExpr(Arg, Arg ? Arg->getExprLoc() : SourceLocation(),
+ /*DiscardedValue*/ true);
+ return FullExprArg(FE.release());
+ }
- StmtResult ActOnExprStmt(FullExprArg Expr);
+ StmtResult ActOnExprStmt(ExprResult Arg);
+ StmtResult ActOnExprStmtError();
StmtResult ActOnNullStmt(SourceLocation SemiLoc,
bool HasLeadingEmptyMacro = false);
@@ -2616,7 +2748,7 @@ public:
SourceLocation StarLoc,
Expr *DestExp);
StmtResult ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope);
- StmtResult ActOnBreakStmt(SourceLocation GotoLoc, Scope *CurScope);
+ StmtResult ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope);
const VarDecl *getCopyElisionCandidate(QualType ReturnType, Expr *E,
bool AllowFunctionParameters);
@@ -2632,7 +2764,8 @@ public:
SourceLocation RParenLoc);
NamedDecl *LookupInlineAsmIdentifier(StringRef Name, SourceLocation Loc,
- unsigned &Size);
+ unsigned &Length, unsigned &Size,
+ unsigned &Type, bool &IsVarDecl);
bool LookupInlineAsmField(StringRef Base, StringRef Member,
unsigned &Offset, SourceLocation AsmLoc);
StmtResult ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
@@ -2766,7 +2899,7 @@ public:
void DiscardCleanupsInEvaluationContext();
- ExprResult TranformToPotentiallyEvaluated(Expr *E);
+ ExprResult TransformToPotentiallyEvaluated(Expr *E);
ExprResult HandleExprEvaluationContextForTypeof(Expr *E);
ExprResult ActOnConstantExpression(ExprResult Res);
@@ -2777,7 +2910,7 @@ public:
// for expressions referring to a decl; these exist because odr-use marking
// needs to be delayed for some constant variables when we build one of the
// named expressions.
- void MarkAnyDeclReferenced(SourceLocation Loc, Decl *D);
+ void MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, bool OdrUse);
void MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func);
void MarkVariableReferenced(SourceLocation Loc, VarDecl *Var);
void MarkDeclRefReferenced(DeclRefExpr *E);
@@ -2873,7 +3006,7 @@ public:
bool DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
CorrectionCandidateCallback &CCC,
TemplateArgumentListInfo *ExplicitTemplateArgs = 0,
- llvm::ArrayRef<Expr *> Args = llvm::ArrayRef<Expr *>());
+ ArrayRef<Expr *> Args = ArrayRef<Expr *>());
ExprResult LookupInObjCMethod(LookupResult &LookUp, Scope *S,
IdentifierInfo *II,
@@ -2892,7 +3025,8 @@ public:
ExprResult BuildDeclRefExpr(ValueDecl *D, QualType Ty,
ExprValueKind VK,
const DeclarationNameInfo &NameInfo,
- const CXXScopeSpec *SS = 0);
+ const CXXScopeSpec *SS = 0,
+ NamedDecl *FoundD = 0);
ExprResult
BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
SourceLocation nameLoc,
@@ -2925,7 +3059,7 @@ public:
bool NeedsADL);
ExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS,
const DeclarationNameInfo &NameInfo,
- NamedDecl *D);
+ NamedDecl *D, NamedDecl *FoundD = 0);
ExprResult BuildLiteralOperatorCall(LookupResult &R,
DeclarationNameInfo &SuffixInfo,
@@ -3334,15 +3468,9 @@ public:
MultiTemplateParamsArg TemplateParams,
SourceLocation UsingLoc,
UnqualifiedId &Name,
+ AttributeList *AttrList,
TypeResult Type);
- /// InitializeVarWithConstructor - Creates an CXXConstructExpr
- /// and sets it as the initializer for the passed in VarDecl.
- bool InitializeVarWithConstructor(VarDecl *VD,
- CXXConstructorDecl *Constructor,
- MultiExprArg Exprs,
- bool HadMultipleCandidates);
-
/// BuildCXXConstructExpr - Creates a complete call to a constructor,
/// including handling of its default argument expressions.
///
@@ -3350,8 +3478,9 @@ public:
ExprResult
BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CXXConstructorDecl *Constructor, MultiExprArg Exprs,
- bool HadMultipleCandidates, bool RequiresZeroInit,
- unsigned ConstructKind, SourceRange ParenRange);
+ bool HadMultipleCandidates, bool IsListInitialization,
+ bool RequiresZeroInit, unsigned ConstructKind,
+ SourceRange ParenRange);
// FIXME: Can re remove this and have the above BuildCXXConstructExpr check if
// the constructor can be elidable?
@@ -3359,8 +3488,8 @@ public:
BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CXXConstructorDecl *Constructor, bool Elidable,
MultiExprArg Exprs, bool HadMultipleCandidates,
- bool RequiresZeroInit, unsigned ConstructKind,
- SourceRange ParenRange);
+ bool IsListInitialization, bool RequiresZeroInit,
+ unsigned ConstructKind, SourceRange ParenRange);
/// BuildCXXDefaultArgExpr - Creates a CXXDefaultArgExpr, instantiating
/// the default expr if needed.
@@ -3395,7 +3524,7 @@ public:
public:
explicit ImplicitExceptionSpecification(Sema &Self)
: Self(&Self), ComputedEST(EST_BasicNoexcept) {
- if (!Self.getLangOpts().CPlusPlus0x)
+ if (!Self.getLangOpts().CPlusPlus11)
ComputedEST = EST_DynamicNone;
}
@@ -3474,6 +3603,11 @@ public:
ImplicitExceptionSpecification
ComputeDefaultedDtorExceptionSpec(CXXMethodDecl *MD);
+ /// \brief Determine what sort of exception specification an inheriting
+ /// constructor of a class will have.
+ ImplicitExceptionSpecification
+ ComputeInheritingCtorExceptionSpec(CXXMethodDecl *MD);
+
/// \brief Evaluate the implicit exception specification for a defaulted
/// special member function.
void EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD);
@@ -3484,7 +3618,7 @@ public:
ArrayRef<ParsedType> DynamicExceptions,
ArrayRef<SourceRange> DynamicExceptionRanges,
Expr *NoexceptExpr,
- llvm::SmallVectorImpl<QualType> &Exceptions,
+ SmallVectorImpl<QualType> &Exceptions,
FunctionProtoType::ExtProtoInfo &EPI);
/// \brief Determine if a special member function should have a deleted
@@ -3526,11 +3660,15 @@ public:
void AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl,
CXXDestructorDecl *Destructor);
- /// \brief Declare all inherited constructors for the given class.
+ /// \brief Declare all inheriting constructors for the given class.
///
- /// \param ClassDecl The class declaration into which the inherited
+ /// \param ClassDecl The class declaration into which the inheriting
/// constructors will be added.
- void DeclareInheritedConstructors(CXXRecordDecl *ClassDecl);
+ void DeclareInheritingConstructors(CXXRecordDecl *ClassDecl);
+
+ /// \brief Define the specified inheriting constructor.
+ void DefineInheritingConstructor(SourceLocation UseLoc,
+ CXXConstructorDecl *Constructor);
/// \brief Declare the implicit copy constructor for the given class.
///
@@ -3617,7 +3755,12 @@ public:
MultiExprArg ArgsPtr,
SourceLocation Loc,
SmallVectorImpl<Expr*> &ConvertedArgs,
- bool AllowExplicit = false);
+ bool AllowExplicit = false,
+ bool IsListInitialization = false);
+
+ ParsedType getInheritingConstructorName(CXXScopeSpec &SS,
+ SourceLocation NameLoc,
+ IdentifierInfo &Name);
ParsedType getDestructorName(SourceLocation TildeLoc,
IdentifierInfo &II, SourceLocation NameLoc,
@@ -3917,7 +4060,9 @@ public:
return ActOnFinishFullExpr(Expr, Expr ? Expr->getExprLoc()
: SourceLocation());
}
- ExprResult ActOnFinishFullExpr(Expr *Expr, SourceLocation CC);
+ ExprResult ActOnFinishFullExpr(Expr *Expr, SourceLocation CC,
+ bool DiscardedValue = false,
+ bool IsConstexpr = false);
StmtResult ActOnFinishFullStmt(Stmt *Stmt);
// Marks SS invalid if it represents an incomplete type.
@@ -3943,7 +4088,7 @@ public:
bool ActOnCXXGlobalScopeSpecifier(Scope *S, SourceLocation CCLoc,
CXXScopeSpec &SS);
- bool isAcceptableNestedNameSpecifier(NamedDecl *SD);
+ bool isAcceptableNestedNameSpecifier(const NamedDecl *SD);
NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS);
bool isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS,
@@ -4100,7 +4245,7 @@ public:
SourceRange IntroducerRange,
TypeSourceInfo *MethodType,
SourceLocation EndLoc,
- llvm::ArrayRef<ParmVarDecl *> Params);
+ ArrayRef<ParmVarDecl *> Params);
/// \brief Introduce the scope for a lambda expression.
sema::LambdaScopeInfo *enterLambdaScope(CXXMethodDecl *CallOperator,
@@ -4247,7 +4392,7 @@ public:
SourceLocation ColonLoc,
AttributeList *Attrs = 0);
- Decl *ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS,
+ NamedDecl *ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS,
Declarator &D,
MultiTemplateParamsArg TemplateParameterLists,
Expr *BitfieldWidth, const VirtSpecifiers &VS,
@@ -4304,9 +4449,9 @@ public:
bool SetDelegatingInitializer(CXXConstructorDecl *Constructor,
CXXCtorInitializer *Initializer);
- bool SetCtorInitializers(CXXConstructorDecl *Constructor,
- CXXCtorInitializer **Initializers,
- unsigned NumInitializers, bool AnyErrors);
+ bool SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
+ ArrayRef<CXXCtorInitializer *> Initializers =
+ ArrayRef<CXXCtorInitializer *>());
void SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation);
@@ -4369,8 +4514,7 @@ public:
void ActOnMemInitializers(Decl *ConstructorDecl,
SourceLocation ColonLoc,
- CXXCtorInitializer **MemInits,
- unsigned NumMemInits,
+ ArrayRef<CXXCtorInitializer*> MemInits,
bool AnyErrors);
void CheckCompletedCXXClass(CXXRecordDecl *Record);
@@ -4407,8 +4551,8 @@ public:
TypeSourceInfo *TSInfo);
Decl *ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
MultiTemplateParamsArg TemplateParams);
- Decl *ActOnFriendFunctionDecl(Scope *S, Declarator &D,
- MultiTemplateParamsArg TemplateParams);
+ NamedDecl *ActOnFriendFunctionDecl(Scope *S, Declarator &D,
+ MultiTemplateParamsArg TemplateParams);
QualType CheckConstructorDeclarator(Declarator &D, QualType R,
StorageClass& SC);
@@ -4420,8 +4564,10 @@ public:
StorageClass& SC);
Decl *ActOnConversionDeclarator(CXXConversionDecl *Conversion);
- void CheckExplicitlyDefaultedMethods(CXXRecordDecl *Record);
void CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD);
+ void CheckExplicitlyDefaultedMemberExceptionSpec(CXXMethodDecl *MD,
+ const FunctionProtoType *T);
+ void CheckDelayedExplicitlyDefaultedMemberExceptionSpecs();
//===--------------------------------------------------------------------===//
// C++ Derived Classes
@@ -4436,6 +4582,7 @@ public:
BaseResult ActOnBaseSpecifier(Decl *classdecl,
SourceRange SpecifierRange,
+ ParsedAttributes &Attrs,
bool Virtual, AccessSpecifier Access,
ParsedType basetype,
SourceLocation BaseLoc,
@@ -4467,6 +4614,9 @@ public:
std::string getAmbiguousPathsDisplayString(CXXBasePaths &Paths);
+ bool CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
+ const CXXMethodDecl *Old);
+
/// CheckOverridingFunctionReturnType - Checks whether the return types are
/// covariant, according to C++ [class.virtual]p5.
bool CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
@@ -5234,14 +5384,14 @@ public:
/// expansion.
TypeSourceInfo *CheckPackExpansion(TypeSourceInfo *Pattern,
SourceLocation EllipsisLoc,
- llvm::Optional<unsigned> NumExpansions);
+ Optional<unsigned> NumExpansions);
/// \brief Construct a pack expansion type from the pattern of the pack
/// expansion.
QualType CheckPackExpansion(QualType Pattern,
SourceRange PatternRange,
SourceLocation EllipsisLoc,
- llvm::Optional<unsigned> NumExpansions);
+ Optional<unsigned> NumExpansions);
/// \brief Invoked when parsing an expression followed by an ellipsis, which
/// creates a pack expansion.
@@ -5260,7 +5410,7 @@ public:
///
/// \param EllipsisLoc The location of the ellipsis.
ExprResult CheckPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc,
- llvm::Optional<unsigned> NumExpansions);
+ Optional<unsigned> NumExpansions);
/// \brief Determine whether we could expand a pack expansion with the
/// given set of parameter packs into separate arguments by repeatedly
@@ -5298,11 +5448,11 @@ public:
/// must be set.
bool CheckParameterPacksForExpansion(SourceLocation EllipsisLoc,
SourceRange PatternRange,
- llvm::ArrayRef<UnexpandedParameterPack> Unexpanded,
+ ArrayRef<UnexpandedParameterPack> Unexpanded,
const MultiLevelTemplateArgumentList &TemplateArgs,
bool &ShouldExpand,
bool &RetainExpansion,
- llvm::Optional<unsigned> &NumExpansions);
+ Optional<unsigned> &NumExpansions);
/// \brief Determine the number of arguments in the given pack expansion
/// type.
@@ -5311,8 +5461,8 @@ public:
/// consistent across all of the unexpanded parameter packs in its pattern.
///
/// Returns an empty Optional if the type can't be expanded.
- llvm::Optional<unsigned> getNumArgumentsInExpansion(QualType T,
- const MultiLevelTemplateArgumentList &TemplateArgs);
+ Optional<unsigned> getNumArgumentsInExpansion(QualType T,
+ const MultiLevelTemplateArgumentList &TemplateArgs);
/// \brief Determine whether the given declarator contains any unexpanded
/// parameter packs.
@@ -5366,10 +5516,8 @@ public:
/// \brief Substitution of the deduced template argument values
/// resulted in an error.
TDK_SubstitutionFailure,
- /// \brief Substitution of the deduced template argument values
- /// into a non-deduced context produced a type or value that
- /// produces a type that does not match the original template
- /// arguments provided.
+ /// \brief A non-depnedent component of the parameter did not match the
+ /// corresponding component of the argument.
TDK_NonDeducedMismatch,
/// \brief When performing template argument deduction for a function
/// template, there were too many call arguments.
@@ -5382,7 +5530,9 @@ public:
TDK_InvalidExplicitArguments,
/// \brief The arguments included an overloaded function name that could
/// not be resolved to a suitable function.
- TDK_FailedOverloadResolution
+ TDK_FailedOverloadResolution,
+ /// \brief Deduction failed; that's all we know.
+ TDK_MiscellaneousDeductionFailure
};
TemplateDeductionResult
@@ -5423,7 +5573,7 @@ public:
TemplateDeductionResult
DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
TemplateArgumentListInfo *ExplicitTemplateArgs,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
FunctionDecl *&Specialization,
sema::TemplateDeductionInfo &Info);
@@ -5483,13 +5633,14 @@ public:
bool OnlyDeduced,
unsigned Depth,
llvm::SmallBitVector &Used);
- void MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate,
- llvm::SmallBitVector &Deduced) {
+ void MarkDeducedTemplateParameters(
+ const FunctionTemplateDecl *FunctionTemplate,
+ llvm::SmallBitVector &Deduced) {
return MarkDeducedTemplateParameters(Context, FunctionTemplate, Deduced);
}
static void MarkDeducedTemplateParameters(ASTContext &Ctx,
- FunctionTemplateDecl *FunctionTemplate,
- llvm::SmallBitVector &Deduced);
+ const FunctionTemplateDecl *FunctionTemplate,
+ llvm::SmallBitVector &Deduced);
//===--------------------------------------------------------------------===//
// C++ Template Instantiation
@@ -5554,7 +5705,7 @@ public:
NamedDecl *Template;
/// \brief The entity that is being instantiated.
- uintptr_t Entity;
+ Decl *Entity;
/// \brief The list of template arguments we are substituting, if they
/// are not part of the entity.
@@ -5796,11 +5947,11 @@ public:
/// template argument substitution failures are not considered
/// errors.
///
- /// \returns An empty \c llvm::Optional if we're not in a SFINAE context.
+ /// \returns An empty \c Optional if we're not in a SFINAE context.
/// Otherwise, contains a pointer that, if non-NULL, contains the nearest
/// template-deduction context object, which can be used to capture
/// diagnostics that will be suppressed.
- llvm::Optional<sema::TemplateDeductionInfo *> isSFINAEContext() const;
+ Optional<sema::TemplateDeductionInfo *> isSFINAEContext() const;
/// \brief Determines whether we are currently in a context that
/// is not evaluated as per C++ [expr] p5.
@@ -5911,7 +6062,7 @@ public:
ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D,
const MultiLevelTemplateArgumentList &TemplateArgs,
int indexAdjustment,
- llvm::Optional<unsigned> NumExpansions,
+ Optional<unsigned> NumExpansions,
bool ExpectParameterPack);
bool SubstParmTypes(SourceLocation Loc,
ParmVarDecl **Params, unsigned NumParams,
@@ -6141,10 +6292,6 @@ public:
void DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
ObjCPropertyDecl *SuperProperty,
const IdentifierInfo *Name);
- void ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl);
-
-
- void CompareProperties(Decl *CDecl, Decl *MergeProtocols);
void DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT,
ObjCInterfaceDecl *ID);
@@ -6214,6 +6361,7 @@ public:
ObjCMethodDecl *LookupMethodInObjectType(Selector Sel, QualType Ty,
bool IsInstance);
+ bool CheckARCMethodDecl(ObjCMethodDecl *method);
bool inferObjCARCLifetime(ValueDecl *decl);
ExprResult
@@ -6324,14 +6472,13 @@ public:
ParsedType Type,
SourceLocation RParenLoc,
Expr *SubExpr);
-
+
bool checkInitMethod(ObjCMethodDecl *method, QualType receiverTypeIfCall);
/// \brief Check whether the given new method is a valid override of the
/// given overridden method, and set any properties that should be inherited.
void CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
- const ObjCMethodDecl *Overridden,
- bool IsImplementation);
+ const ObjCMethodDecl *Overridden);
/// \brief Describes the compatibility of a result type with its method.
enum ResultTypeCompatibilityKind {
@@ -6450,9 +6597,21 @@ public:
/// AddAlignedAttr - Adds an aligned attribute to a particular declaration.
void AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
- bool isDeclSpec);
+ unsigned SpellingListIndex, bool IsPackExpansion);
void AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *T,
- bool isDeclSpec);
+ unsigned SpellingListIndex, bool IsPackExpansion);
+
+ // OpenMP directives and clauses.
+
+ /// \brief Called on well-formed '#pragma omp threadprivate'.
+ DeclGroupPtrTy ActOnOpenMPThreadprivateDirective(
+ SourceLocation Loc,
+ Scope *CurScope,
+ ArrayRef<DeclarationNameInfo> IdList);
+ /// \brief Build a new OpenMPThreadPrivateDecl and check its correctness.
+ OMPThreadPrivateDecl *CheckOMPThreadPrivateDecl(
+ SourceLocation Loc,
+ ArrayRef<DeclRefExpr *> VarList);
/// \brief The kind of conversion being performed.
enum CheckedConversionKind {
@@ -6541,7 +6700,8 @@ public:
Expr **Args, unsigned NumArgs,
SmallVector<Expr *, 8> &AllArgs,
VariadicCallType CallType = VariadicDoesNotApply,
- bool AllowExplicit = false);
+ bool AllowExplicit = false,
+ bool IsListInitialization = false);
// DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but
// will create a runtime trap if the resulting type is not a POD type.
@@ -6812,6 +6972,11 @@ public:
/// given type.
ExprResult forceUnknownAnyToType(Expr *E, QualType ToType);
+ /// \brief Type-check an expression that's being passed to an
+ /// __unknown_anytype parameter.
+ ExprResult checkUnknownAnyArg(SourceLocation callLoc,
+ Expr *result, QualType &paramType);
+
// CheckVectorCast - check type constraints for vectors.
// Since vectors are an extension, there are no C standard reference for this.
// We allow casting between vectors and integer datatypes of the same size.
@@ -6883,6 +7048,11 @@ public:
/// with a related result type, emit a note describing what happened.
void EmitRelatedResultTypeNote(const Expr *E);
+ /// \brief Given that we had incompatible pointer types in a return
+ /// statement, check whether we're in a method with a related result
+ /// type, and if so, emit a note describing what happened.
+ void EmitRelatedResultTypeNoteForReturn(QualType destType);
+
/// CheckBooleanCondition - Diagnose problems involving the use of
/// the given expression as a boolean condition (e.g. in an if
/// statement). Also performs the standard function and array
@@ -7033,7 +7203,7 @@ public:
void CodeCompleteTag(Scope *S, unsigned TagSpec);
void CodeCompleteTypeQualifiers(DeclSpec &DS);
void CodeCompleteCase(Scope *S);
- void CodeCompleteCall(Scope *S, Expr *Fn, llvm::ArrayRef<Expr *> Args);
+ void CodeCompleteCall(Scope *S, Expr *Fn, ArrayRef<Expr *> Args);
void CodeCompleteInitializer(Scope *S, Decl *D);
void CodeCompleteReturn(Scope *S);
void CodeCompleteAfterIf(Scope *S);
@@ -7150,12 +7320,11 @@ private:
bool CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall,
const FunctionProtoType *Proto);
void CheckConstructorCall(FunctionDecl *FDecl,
- Expr **Args,
- unsigned NumArgs,
+ ArrayRef<const Expr *> Args,
const FunctionProtoType *Proto,
SourceLocation Loc);
- void checkCall(NamedDecl *FDecl, Expr **Args, unsigned NumArgs,
+ void checkCall(NamedDecl *FDecl, ArrayRef<const Expr *> Args,
unsigned NumProtoArgs, bool IsMemberFunction,
SourceLocation Loc, SourceRange Range,
VariadicCallType CallType);
@@ -7203,7 +7372,7 @@ private:
};
StringLiteralCheckType checkFormatStringExpr(const Expr *E,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<const Expr *> Args,
bool HasVAListArg,
unsigned format_idx,
unsigned firstDataArg,
@@ -7212,16 +7381,17 @@ private:
bool inFunctionCall = true);
void CheckFormatString(const StringLiteral *FExpr, const Expr *OrigFormatExpr,
- Expr **Args, unsigned NumArgs, bool HasVAListArg,
+ ArrayRef<const Expr *> Args, bool HasVAListArg,
unsigned format_idx, unsigned firstDataArg,
FormatStringType Type, bool inFunctionCall,
VariadicCallType CallType);
- bool CheckFormatArguments(const FormatAttr *Format, Expr **Args,
- unsigned NumArgs, bool IsCXXMember,
+ bool CheckFormatArguments(const FormatAttr *Format,
+ ArrayRef<const Expr *> Args,
+ bool IsCXXMember,
VariadicCallType CallType,
SourceLocation Loc, SourceRange Range);
- bool CheckFormatArguments(Expr **Args, unsigned NumArgs,
+ bool CheckFormatArguments(ArrayRef<const Expr *> Args,
bool HasVAListArg, unsigned format_idx,
unsigned firstDataArg, FormatStringType Type,
VariadicCallType CallType,
@@ -7245,6 +7415,13 @@ private:
SourceLocation ReturnLoc);
void CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr* RHS);
void CheckImplicitConversions(Expr *E, SourceLocation CC = SourceLocation());
+ void CheckForIntOverflow(Expr *E);
+ void CheckUnsequencedOperations(Expr *E);
+
+ /// \brief Perform semantic checks on a completed expression. This will either
+ /// be a full-expression or a default argument expression.
+ void CheckCompletedExpr(Expr *E, SourceLocation CheckLoc = SourceLocation(),
+ bool IsConstexpr = false);
void CheckBitFieldInitialization(SourceLocation InitLoc, FieldDecl *Field,
Expr *Init);
@@ -7290,6 +7467,8 @@ private:
/// The parser maintains this state here.
Scope *CurScope;
+ mutable IdentifierInfo *Ident_super;
+
protected:
friend class Parser;
friend class InitializationSequence;
@@ -7307,6 +7486,8 @@ public:
/// template substitution or instantiation.
Scope *getCurScope() const { return CurScope; }
+ IdentifierInfo *getSuperIdentifier() const;
+
Decl *getObjCDeclContext() const;
DeclContext *getCurLexicalContext() const {
diff --git a/include/clang/Sema/SemaInternal.h b/include/clang/Sema/SemaInternal.h
index 64b83e3..bbf4272 100644
--- a/include/clang/Sema/SemaInternal.h
+++ b/include/clang/Sema/SemaInternal.h
@@ -15,9 +15,9 @@
#ifndef LLVM_CLANG_SEMA_SEMA_INTERNAL_H
#define LLVM_CLANG_SEMA_SEMA_INTERNAL_H
+#include "clang/AST/ASTContext.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaDiagnostic.h"
-#include "clang/AST/ASTContext.h"
namespace clang {
diff --git a/include/clang/Sema/Template.h b/include/clang/Sema/Template.h
index bbccd25..492e580 100644
--- a/include/clang/Sema/Template.h
+++ b/include/clang/Sema/Template.h
@@ -14,6 +14,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclVisitor.h"
+#include "clang/Sema/Sema.h"
#include "llvm/ADT/SmallVector.h"
#include <cassert>
#include <utility>
@@ -344,7 +345,16 @@ namespace clang {
void SetPartiallySubstitutedPack(NamedDecl *Pack,
const TemplateArgument *ExplicitArgs,
unsigned NumExplicitArgs);
-
+
+ /// \brief Reset the partially-substituted pack when it is no longer of
+ /// interest.
+ void ResetPartiallySubstitutedPack() {
+ assert(PartiallySubstitutedPack && "No partially-substituted pack");
+ PartiallySubstitutedPack = 0;
+ ArgsInPartiallySubstitutedPack = 0;
+ NumArgsInPartiallySubstitutedPack = 0;
+ }
+
/// \brief Retrieve the partially-substitued template parameter pack.
///
/// If there is no partially-substituted parameter pack, returns NULL.
@@ -420,6 +430,7 @@ namespace clang {
Decl *VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
Decl *VisitClassScopeFunctionSpecializationDecl(
ClassScopeFunctionSpecializationDecl *D);
+ Decl *VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
// Base case. FIXME: Remove once we can instantiate everything.
Decl *VisitDecl(Decl *D) {
diff --git a/include/clang/Sema/TemplateDeduction.h b/include/clang/Sema/TemplateDeduction.h
index 251a659..3abb8f1 100644
--- a/include/clang/Sema/TemplateDeduction.h
+++ b/include/clang/Sema/TemplateDeduction.h
@@ -13,8 +13,8 @@
#ifndef LLVM_CLANG_SEMA_TEMPLATE_DEDUCTION_H
#define LLVM_CLANG_SEMA_TEMPLATE_DEDUCTION_H
-#include "clang/Basic/PartialDiagnostic.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/Basic/PartialDiagnostic.h"
#include "llvm/ADT/SmallVector.h"
namespace clang {
@@ -47,7 +47,7 @@ class TemplateDeductionInfo {
public:
TemplateDeductionInfo(SourceLocation Loc)
- : Deduced(0), Loc(Loc), HasSFINAEDiagnostic(false) { }
+ : Deduced(0), Loc(Loc), HasSFINAEDiagnostic(false), Expression(0) { }
/// \brief Returns the location at which template argument is
/// occurring.
@@ -141,15 +141,25 @@ public:
/// TDK_SubstitutionFailure: this argument is the template
/// argument we were instantiating when we encountered an error.
///
- /// TDK_NonDeducedMismatch: this is the template argument
- /// provided in the source code.
+ /// TDK_NonDeducedMismatch: this is the component of the 'parameter'
+ /// of the deduction, directly provided in the source code.
TemplateArgument FirstArg;
/// \brief The second template argument to which the template
/// argument deduction failure refers.
///
+ /// TDK_NonDeducedMismatch: this is the mismatching component of the
+ /// 'argument' of the deduction, from which we are deducing arguments.
+ ///
/// FIXME: Finish documenting this.
TemplateArgument SecondArg;
+
+ /// \brief The expression which caused a deduction failure.
+ ///
+ /// TDK_FailedOverloadResolution: this argument is the reference to
+ // an overloaded function which could not be resolved to a specific
+ // function.
+ Expr *Expression;
};
}
diff --git a/include/clang/Sema/TypoCorrection.h b/include/clang/Sema/TypoCorrection.h
index 2b4a9e6..cdd71c8 100644
--- a/include/clang/Sema/TypoCorrection.h
+++ b/include/clang/Sema/TypoCorrection.h
@@ -16,6 +16,7 @@
#define LLVM_CLANG_SEMA_TYPOCORRECTION_H
#include "clang/AST/DeclCXX.h"
+#include "clang/Sema/DeclSpec.h"
#include "llvm/ADT/SmallVector.h"
namespace clang {
@@ -181,12 +182,12 @@ public:
return CorrectionRange;
}
- typedef llvm::SmallVector<NamedDecl*, 1>::iterator decl_iterator;
+ typedef SmallVector<NamedDecl *, 1>::iterator decl_iterator;
decl_iterator begin() {
return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin();
}
decl_iterator end() { return CorrectionDecls.end(); }
- typedef llvm::SmallVector<NamedDecl*, 1>::const_iterator const_decl_iterator;
+ typedef SmallVector<NamedDecl *, 1>::const_iterator const_decl_iterator;
const_decl_iterator begin() const {
return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin();
}
@@ -200,7 +201,7 @@ private:
// Results.
DeclarationName CorrectionName;
NestedNameSpecifier *CorrectionNameSpec;
- llvm::SmallVector<NamedDecl*, 1> CorrectionDecls;
+ SmallVector<NamedDecl *, 1> CorrectionDecls;
unsigned CharDistance;
unsigned QualifierDistance;
unsigned CallbackDistance;
@@ -227,9 +228,11 @@ class CorrectionCandidateCallback {
/// candidate is viable, without ranking potentially viable candidates.
/// Only ValidateCandidate or RankCandidate need to be overriden by a
/// callback wishing to check the viability of correction candidates.
- virtual bool ValidateCandidate(const TypoCorrection &candidate) {
- return true;
- }
+ /// The default predicate always returns true if the candidate is not a type
+ /// name or keyword, true for types if WantTypeSpecifiers is true, and true
+ /// for keywords if WantTypeSpecifiers, WantExpressionKeywords,
+ /// WantCXXNamedCasts, WantRemainingKeywords, or WantObjCSuper is true.
+ virtual bool ValidateCandidate(const TypoCorrection &candidate);
/// \brief Method used by Sema::CorrectTypo to assign an "edit distance" rank
/// to a candidate (where a lower value represents a better candidate), or
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index 8c58fb2..9b685ba 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -18,9 +18,9 @@
#define LLVM_CLANG_FRONTEND_PCHBITCODES_H
#include "clang/AST/Type.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/Bitcode/BitCodes.h"
#include "llvm/Support/DataTypes.h"
-#include "llvm/ADT/DenseMap.h"
namespace clang {
namespace serialization {
@@ -35,7 +35,7 @@ namespace clang {
/// Version 4 of AST files also requires that the version control branch and
/// revision match exactly, since there is no backward compatibility of
/// AST files at this time.
- const unsigned VERSION_MAJOR = 4;
+ const unsigned VERSION_MAJOR = 5;
/// \brief AST file minor version number supported by this version of
/// Clang.
@@ -129,7 +129,14 @@ namespace clang {
/// \brief An ID number that refers to a macro in an AST file.
typedef uint32_t MacroID;
-
+
+ /// \brief A global ID number that refers to a macro in an AST file.
+ typedef uint32_t GlobalMacroID;
+
+ /// \brief A local to a module ID number that refers to a macro in an
+ /// AST file.
+ typedef uint32_t LocalMacroID;
+
/// \brief The number of predefined macro IDs.
const unsigned int NUM_PREDEF_MACRO_IDS = 1;
@@ -259,21 +266,25 @@ namespace clang {
/// \brief The directory that the PCH was originally created in.
ORIGINAL_PCH_DIR = 6,
+ /// \brief Record code for file ID of the file or buffer that was used to
+ /// generate the AST file.
+ ORIGINAL_FILE_ID = 7,
+
/// \brief Offsets into the input-files block where input files
/// reside.
- INPUT_FILE_OFFSETS = 7,
+ INPUT_FILE_OFFSETS = 8,
/// \brief Record code for the diagnostic options table.
- DIAGNOSTIC_OPTIONS = 8,
+ DIAGNOSTIC_OPTIONS = 9,
/// \brief Record code for the filesystem options table.
- FILE_SYSTEM_OPTIONS = 9,
+ FILE_SYSTEM_OPTIONS = 10,
/// \brief Record code for the headers search options table.
- HEADER_SEARCH_OPTIONS = 10,
+ HEADER_SEARCH_OPTIONS = 11,
/// \brief Record code for the preprocessor options table.
- PREPROCESSOR_OPTIONS = 11
+ PREPROCESSOR_OPTIONS = 12
};
/// \brief Record types that occur within the input-files block
@@ -319,6 +330,11 @@ namespace clang {
/// NULL-terminated string that corresponds to that identifier.
IDENTIFIER_OFFSET = 3,
+ /// \brief This is so that older clang versions, before the introduction
+ /// of the control block, can read and reject the newer PCH format.
+ /// *DON"T CHANGE THIS NUMBER*.
+ METADATA_OLD_FORMAT = 4,
+
/// \brief Record code for the identifier table.
///
/// The identifier table is a simple blob that contains
@@ -331,7 +347,7 @@ namespace clang {
/// between offsets (for unresolved identifier IDs) and
/// IdentifierInfo pointers (for already-resolved identifier
/// IDs).
- IDENTIFIER_TABLE = 4,
+ IDENTIFIER_TABLE = 5,
/// \brief Record code for the array of external definitions.
///
@@ -341,7 +357,7 @@ namespace clang {
/// reported to the AST consumer after the AST file has been
/// read, since their presence can affect the semantics of the
/// program (e.g., for code generation).
- EXTERNAL_DEFINITIONS = 5,
+ EXTERNAL_DEFINITIONS = 6,
/// \brief Record code for the set of non-builtin, special
/// types.
@@ -350,33 +366,33 @@ namespace clang {
/// that are constructed during semantic analysis (e.g.,
/// __builtin_va_list). The SPECIAL_TYPE_* constants provide
/// offsets into this record.
- SPECIAL_TYPES = 6,
+ SPECIAL_TYPES = 7,
/// \brief Record code for the extra statistics we gather while
/// generating an AST file.
- STATISTICS = 7,
+ STATISTICS = 8,
/// \brief Record code for the array of tentative definitions.
- TENTATIVE_DEFINITIONS = 8,
+ TENTATIVE_DEFINITIONS = 9,
- /// \brief Record code for the array of locally-scoped external
+ /// \brief Record code for the array of locally-scoped extern "C"
/// declarations.
- LOCALLY_SCOPED_EXTERNAL_DECLS = 9,
+ LOCALLY_SCOPED_EXTERN_C_DECLS = 10,
/// \brief Record code for the table of offsets into the
/// Objective-C method pool.
- SELECTOR_OFFSETS = 10,
+ SELECTOR_OFFSETS = 11,
/// \brief Record code for the Objective-C method pool,
- METHOD_POOL = 11,
+ METHOD_POOL = 12,
/// \brief The value of the next __COUNTER__ to dispense.
/// [PP_COUNTER_VALUE, Val]
- PP_COUNTER_VALUE = 12,
+ PP_COUNTER_VALUE = 13,
/// \brief Record code for the table of offsets into the block
/// of source-location information.
- SOURCE_LOCATION_OFFSETS = 13,
+ SOURCE_LOCATION_OFFSETS = 14,
/// \brief Record code for the set of source location entries
/// that need to be preloaded by the AST reader.
@@ -384,7 +400,7 @@ namespace clang {
/// This set contains the source location entry for the
/// predefines buffer and for any file entries that need to be
/// preloaded.
- SOURCE_LOCATION_PRELOADS = 14,
+ SOURCE_LOCATION_PRELOADS = 15,
/// \brief Record code for the set of ext_vector type names.
EXT_VECTOR_DECLS = 16,
@@ -513,9 +529,13 @@ namespace clang {
/// macro definition.
MACRO_OFFSET = 47,
- /// \brief Record of updates for a macro that was modified after
- /// being deserialized.
- MACRO_UPDATES = 48
+ /// \brief Mapping table from the identifier ID to the offset of the
+ /// macro directive history for the identifier.
+ MACRO_TABLE = 48,
+
+ /// \brief Record code for undefined but used functions and variables that
+ /// need a definition in this TU.
+ UNDEFINED_BUT_USED = 49
};
/// \brief Record types used within a source manager block.
@@ -552,7 +572,10 @@ namespace clang {
/// \brief Describes one token.
/// [PP_TOKEN, SLoc, Length, IdentInfoID, Kind, Flags]
- PP_TOKEN = 3
+ PP_TOKEN = 3,
+
+ /// \brief The macro directives history for a particular identifier.
+ PP_MACRO_DIRECTIVE_HISTORY = 4
};
/// \brief Record types used within a preprocessor detail block.
@@ -594,7 +617,13 @@ namespace clang {
SUBMODULE_REQUIRES = 8,
/// \brief Specifies a header that has been explicitly excluded
/// from this submodule.
- SUBMODULE_EXCLUDED_HEADER = 9
+ SUBMODULE_EXCLUDED_HEADER = 9,
+ /// \brief Specifies a library or framework to link against.
+ SUBMODULE_LINK_LIBRARY = 10,
+ /// \brief Specifies a configuration macro for this module.
+ SUBMODULE_CONFIG_MACRO = 11,
+ /// \brief Specifies a conflict with another module.
+ SUBMODULE_CONFLICT = 12
};
/// \brief Record types used within a comments block.
@@ -692,7 +721,23 @@ namespace clang {
/// \brief The __va_list_tag placeholder type.
PREDEF_TYPE_VA_LIST_TAG = 36,
/// \brief The placeholder type for builtin functions.
- PREDEF_TYPE_BUILTIN_FN = 37
+ PREDEF_TYPE_BUILTIN_FN = 37,
+ /// \brief OpenCL 1d image type.
+ PREDEF_TYPE_IMAGE1D_ID = 38,
+ /// \brief OpenCL 1d image array type.
+ PREDEF_TYPE_IMAGE1D_ARR_ID = 39,
+ /// \brief OpenCL 1d image buffer type.
+ PREDEF_TYPE_IMAGE1D_BUFF_ID = 40,
+ /// \brief OpenCL 2d image type.
+ PREDEF_TYPE_IMAGE2D_ID = 41,
+ /// \brief OpenCL 2d image array type.
+ PREDEF_TYPE_IMAGE2D_ARR_ID = 42,
+ /// \brief OpenCL 3d image type.
+ PREDEF_TYPE_IMAGE3D_ID = 43,
+ /// \brief OpenCL event type.
+ PREDEF_TYPE_EVENT_ID = 44,
+ /// \brief OpenCL sampler type.
+ PREDEF_TYPE_SAMPLER_ID = 45
};
/// \brief The number of predefined type IDs that are reserved for
@@ -1000,7 +1045,11 @@ namespace clang {
/// function specialization. (Microsoft extension).
DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION,
/// \brief An ImportDecl recording a module import.
- DECL_IMPORT
+ DECL_IMPORT,
+ /// \brief A OMPThreadPrivateDecl record.
+ DECL_OMP_THREADPRIVATE,
+ /// \brief An EmptyDecl record.
+ DECL_EMPTY
};
/// \brief Record codes for each kind of statement or expression.
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index e23ea5c..9255336 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -14,33 +14,33 @@
#ifndef LLVM_CLANG_FRONTEND_AST_READER_H
#define LLVM_CLANG_FRONTEND_AST_READER_H
-#include "clang/Serialization/ASTBitCodes.h"
-#include "clang/Serialization/ContinuousRangeMap.h"
-#include "clang/Serialization/Module.h"
-#include "clang/Serialization/ModuleManager.h"
-#include "clang/Sema/ExternalSemaSource.h"
-#include "clang/AST/DeclarationName.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclarationName.h"
#include "clang/AST/TemplateBase.h"
-#include "clang/Lex/ExternalPreprocessorSource.h"
-#include "clang/Lex/HeaderSearch.h"
-#include "clang/Lex/PPMutationListener.h"
-#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemOptions.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Version.h"
+#include "clang/Lex/ExternalPreprocessorSource.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/PreprocessingRecord.h"
+#include "clang/Sema/ExternalSemaSource.h"
+#include "clang/Serialization/ASTBitCodes.h"
+#include "clang/Serialization/ContinuousRangeMap.h"
+#include "clang/Serialization/Module.h"
+#include "clang/Serialization/ModuleManager.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/DenseSet.h"
#include "llvm/Bitcode/BitstreamReader.h"
#include "llvm/Support/DataTypes.h"
#include <deque>
@@ -48,6 +48,7 @@
#include <string>
#include <utility>
#include <vector>
+#include <sys/stat.h>
namespace llvm {
class MemoryBuffer;
@@ -68,8 +69,10 @@ class NestedNameSpecifier;
class CXXBaseSpecifier;
class CXXConstructorDecl;
class CXXCtorInitializer;
+class GlobalModuleIndex;
class GotoStmt;
class MacroDefinition;
+class MacroDirective;
class NamedDecl;
class OpaqueValueExpr;
class Preprocessor;
@@ -85,6 +88,7 @@ class TypeLocReader;
struct HeaderFileInfo;
class VersionTuple;
class TargetOptions;
+class ASTUnresolvedSet;
/// \brief Abstract interface for callback invocations by the ASTReader.
///
@@ -96,6 +100,14 @@ class ASTReaderListener {
public:
virtual ~ASTReaderListener();
+ /// \brief Receives the full Clang version information.
+ ///
+ /// \returns true to indicate that the version is invalid. Subclasses should
+ /// generally defer to this implementation.
+ virtual bool ReadFullVersionInformation(StringRef FullVersion) {
+ return FullVersion != getClangFullRepositoryVersion();
+ }
+
/// \brief Receives the language options.
///
/// \returns true to indicate the options are invalid or false otherwise.
@@ -233,6 +245,8 @@ public:
Success,
/// \brief The AST file itself appears corrupted.
Failure,
+ /// \brief The AST file was missing.
+ Missing,
/// \brief The AST file is out-of-date relative to its input files,
/// and needs to be regenerated.
OutOfDate,
@@ -291,6 +305,9 @@ private:
/// \brief The module manager which manages modules and their dependencies
ModuleManager ModuleMgr;
+ /// \brief The global module index, if loaded.
+ llvm::OwningPtr<GlobalModuleIndex> GlobalIndex;
+
/// \brief A map of global bit offsets to the module that stores entities
/// at those bit offsets.
ContinuousRangeMap<uint64_t, ModuleFile*, 4> GlobalBitOffsetsMap;
@@ -387,7 +404,7 @@ private:
typedef llvm::MapVector<Decl *, uint64_t,
llvm::SmallDenseMap<Decl *, unsigned, 4>,
- llvm::SmallVector<std::pair<Decl *, uint64_t>, 4> >
+ SmallVector<std::pair<Decl *, uint64_t>, 4> >
PendingBodiesMap;
/// \brief Functions or methods that have bodies that will be attached.
@@ -431,15 +448,6 @@ private:
/// global macro ID to produce a local ID.
GlobalMacroMapType GlobalMacroMap;
- typedef llvm::DenseMap<serialization::MacroID,
- llvm::SmallVector<std::pair<serialization::SubmoduleID,
- MacroUpdate>, 1> >
- MacroUpdatesMap;
-
- /// \brief Mapping from (global) macro IDs to the set of updates to be
- /// performed to the corresponding macro.
- MacroUpdatesMap MacroUpdates;
-
/// \brief A vector containing submodules that have already been loaded.
///
/// This vector is indexed by the Submodule ID (-1). NULL submodule entries
@@ -459,28 +467,22 @@ private:
public:
enum NameKind {
Declaration,
- MacroVisibility,
- MacroUndef
+ MacroVisibility
} Kind;
private:
- unsigned Loc;
-
union {
Decl *D;
- MacroInfo *MI;
+ MacroDirective *MD;
};
IdentifierInfo *Id;
public:
- HiddenName(Decl *D) : Kind(Declaration), Loc(), D(D), Id() { }
+ HiddenName(Decl *D) : Kind(Declaration), D(D), Id() { }
- HiddenName(IdentifierInfo *II, MacroInfo *MI)
- : Kind(MacroVisibility), Loc(), MI(MI), Id(II) { }
-
- HiddenName(IdentifierInfo *II, MacroInfo *MI, SourceLocation Loc)
- : Kind(MacroUndef), Loc(Loc.getRawEncoding()), MI(MI), Id(II) { }
+ HiddenName(IdentifierInfo *II, MacroDirective *MD)
+ : Kind(MacroVisibility), MD(MD), Id(II) { }
NameKind getKind() const { return Kind; }
@@ -489,21 +491,14 @@ private:
return D;
}
- std::pair<IdentifierInfo *, MacroInfo *> getMacro() const {
- assert((getKind() == MacroUndef || getKind() == MacroVisibility)
- && "Hidden name is not a macro!");
- return std::make_pair(Id, MI);
- }
-
- SourceLocation getMacroUndefLoc() const {
- assert(getKind() == MacroUndef && "Hidden name is not an undef!");
- return SourceLocation::getFromRawEncoding(Loc);
+ std::pair<IdentifierInfo *, MacroDirective *> getMacro() const {
+ assert(getKind() == MacroVisibility && "Hidden name is not a macro!");
+ return std::make_pair(Id, MD);
}
};
/// \brief A set of hidden declarations.
- typedef llvm::SmallVector<HiddenName, 2>
- HiddenNames;
+ typedef SmallVector<HiddenName, 2> HiddenNames;
typedef llvm::DenseMap<Module *, HiddenNames> HiddenNamesMapType;
@@ -512,28 +507,30 @@ private:
HiddenNamesMapType HiddenNamesMap;
- /// \brief A module import or export that hasn't yet been resolved.
- struct UnresolvedModuleImportExport {
+ /// \brief A module import, export, or conflict that hasn't yet been resolved.
+ struct UnresolvedModuleRef {
/// \brief The file in which this module resides.
ModuleFile *File;
/// \brief The module that is importing or exporting.
Module *Mod;
-
+
+ /// \brief The kind of module reference.
+ enum { Import, Export, Conflict } Kind;
+
/// \brief The local ID of the module that is being exported.
unsigned ID;
-
- /// \brief Whether this is an import (vs. an export).
- unsigned IsImport : 1;
-
+
/// \brief Whether this is a wildcard export.
unsigned IsWildcard : 1;
+
+ /// \brief String data.
+ StringRef String;
};
/// \brief The set of module imports and exports that still need to be
/// resolved.
- llvm::SmallVector<UnresolvedModuleImportExport, 2>
- UnresolvedModuleImportExports;
+ SmallVector<UnresolvedModuleRef, 2> UnresolvedModuleRefs;
/// \brief A vector containing selectors that have already been loaded.
///
@@ -546,7 +543,7 @@ private:
GlobalSelectorMapType;
/// \brief Mapping from global selector IDs to the module in which the
- /// selector resides along with the offset that should be added to the
+
/// global selector ID to produce a local ID.
GlobalSelectorMapType GlobalSelectorMap;
@@ -554,8 +551,35 @@ private:
/// global method pool for this selector.
llvm::DenseMap<Selector, unsigned> SelectorGeneration;
- typedef llvm::MapVector<IdentifierInfo *,
- llvm::SmallVector<serialization::MacroID, 2> >
+ struct PendingMacroInfo {
+ ModuleFile *M;
+
+ struct ModuleMacroDataTy {
+ serialization::GlobalMacroID GMacID;
+ unsigned ImportLoc;
+ };
+ struct PCHMacroDataTy {
+ uint64_t MacroDirectivesOffset;
+ };
+
+ union {
+ ModuleMacroDataTy ModuleMacroData;
+ PCHMacroDataTy PCHMacroData;
+ };
+
+ PendingMacroInfo(ModuleFile *M,
+ serialization::GlobalMacroID GMacID,
+ SourceLocation ImportLoc) : M(M) {
+ ModuleMacroData.GMacID = GMacID;
+ ModuleMacroData.ImportLoc = ImportLoc.getRawEncoding();
+ }
+
+ PendingMacroInfo(ModuleFile *M, uint64_t MacroDirectivesOffset) : M(M) {
+ PCHMacroData.MacroDirectivesOffset = MacroDirectivesOffset;
+ }
+ };
+
+ typedef llvm::MapVector<IdentifierInfo *, SmallVector<PendingMacroInfo, 2> >
PendingMacroIDsMap;
/// \brief Mapping from identifiers that have a macro history to the global
@@ -637,11 +661,11 @@ private:
/// \brief Fields containing data that is used for semantic analysis
//@{
- /// \brief The IDs of all locally scoped external decls in the chain.
+ /// \brief The IDs of all locally scoped extern "C" decls in the chain.
///
/// Sema tracks these to validate that the types are consistent across all
- /// local external declarations.
- SmallVector<uint64_t, 16> LocallyScopedExternalDecls;
+ /// local extern "C" declarations.
+ SmallVector<uint64_t, 16> LocallyScopedExternCDecls;
/// \brief The IDs of all dynamic class declarations in the chain.
///
@@ -674,6 +698,10 @@ private:
/// \brief A list of the namespaces we've seen.
SmallVector<uint64_t, 4> KnownNamespaces;
+ /// \brief A list of undefined decls with internal linkage followed by the
+ /// SourceLocation of a matching ODR-use.
+ SmallVector<uint64_t, 8> UndefinedButUsed;
+
/// \brief A list of modules that were imported by precompiled headers or
/// any other non-module AST file.
SmallVector<serialization::SubmoduleID, 2> ImportedModules;
@@ -693,6 +721,12 @@ private:
/// \brief Whether to accept an AST file with compiler errors.
bool AllowASTWithCompilerErrors;
+ /// \brief Whether we are allowed to use the global module index.
+ bool UseGlobalIndex;
+
+ /// \brief Whether we have tried loading the global module index yet.
+ bool TriedLoadingGlobalIndex;
+
/// \brief The current "generation" of the module file import stack, which
/// indicates how many separate module file load operations have occurred.
unsigned CurrentGeneration;
@@ -727,6 +761,12 @@ private:
/// \brief The total number of macros stored in the chain.
unsigned TotalNumMacros;
+ /// \brief The number of lookups into identifier tables.
+ unsigned NumIdentifierLookups;
+
+ /// \brief The number of lookups into identifier tables that succeed.
+ unsigned NumIdentifierLookupHits;
+
/// \brief The number of selectors that have been read.
unsigned NumSelectorsRead;
@@ -734,8 +774,20 @@ private:
unsigned NumMethodPoolEntriesRead;
/// \brief The number of times we have looked up a selector in the method
- /// pool and not found anything interesting.
- unsigned NumMethodPoolMisses;
+ /// pool.
+ unsigned NumMethodPoolLookups;
+
+ /// \brief The number of times we have looked up a selector in the method
+ /// pool and found something.
+ unsigned NumMethodPoolHits;
+
+ /// \brief The number of times we have looked up a selector in the method
+ /// pool within a specific module.
+ unsigned NumMethodPoolTableLookups;
+
+ /// \brief The number of times we have looked up a selector in the method
+ /// pool within a specific module and found something.
+ unsigned NumMethodPoolTableHits;
/// \brief The total number of method pool entries in the selector table.
unsigned TotalNumMethodPoolEntries;
@@ -761,19 +813,13 @@ private:
/// Number of CXX base specifiers currently loaded
unsigned NumCXXBaseSpecifiersLoaded;
- /// \brief An IdentifierInfo that has been loaded but whose top-level
- /// declarations of the same name have not (yet) been loaded.
- struct PendingIdentifierInfo {
- IdentifierInfo *II;
- SmallVector<uint32_t, 4> DeclIDs;
- };
-
/// \brief The set of identifiers that were read while the AST reader was
/// (recursively) loading declarations.
///
/// The declarations on the identifier chain for these identifiers will be
/// loaded once the recursive loading has completed.
- std::deque<PendingIdentifierInfo> PendingIdentifierInfos;
+ llvm::MapVector<IdentifierInfo *, SmallVector<uint32_t, 4> >
+ PendingIdentifierInfos;
/// \brief The generation number of each identifier, which keeps track of
/// the last time we loaded information about this identifier.
@@ -797,11 +843,26 @@ private:
/// Each element is the global declaration ID of the first declaration in
/// the chain. Elements in this vector should be unique; use
/// PendingDeclChainsKnown to ensure uniqueness.
- llvm::SmallVector<serialization::DeclID, 16> PendingDeclChains;
+ SmallVector<serialization::DeclID, 16> PendingDeclChains;
/// \brief Keeps track of the elements added to PendingDeclChains.
llvm::SmallSet<serialization::DeclID, 16> PendingDeclChainsKnown;
+ /// \brief The Decl IDs for the Sema/Lexical DeclContext of a Decl that has
+ /// been loaded but its DeclContext was not set yet.
+ struct PendingDeclContextInfo {
+ Decl *D;
+ serialization::GlobalDeclID SemaDC;
+ serialization::GlobalDeclID LexicalDC;
+ };
+
+ /// \brief The set of Decls that have been loaded but their DeclContexts are
+ /// not set yet.
+ ///
+ /// The DeclContexts for these Decls will be set once recursive loading has
+ /// been completed.
+ std::deque<PendingDeclContextInfo> PendingDeclContextInfos;
+
/// \brief The set of Objective-C categories that have been deserialized
/// since the last time the declaration chains were linked.
llvm::SmallPtrSet<ObjCCategoryDecl *, 16> CategoriesDeserialized;
@@ -809,9 +870,9 @@ private:
/// \brief The set of Objective-C class definitions that have already been
/// loaded, for which we will need to check for categories whenever a new
/// module is loaded.
- llvm::SmallVector<ObjCInterfaceDecl *, 16> ObjCClassesLoaded;
+ SmallVector<ObjCInterfaceDecl *, 16> ObjCClassesLoaded;
- typedef llvm::DenseMap<Decl *, llvm::SmallVector<serialization::DeclID, 2> >
+ typedef llvm::DenseMap<Decl *, SmallVector<serialization::DeclID, 2> >
MergedDeclsMap;
/// \brief A mapping from canonical declarations to the set of additional
@@ -820,7 +881,7 @@ private:
MergedDeclsMap MergedDecls;
typedef llvm::DenseMap<serialization::GlobalDeclID,
- llvm::SmallVector<serialization::DeclID, 2> >
+ SmallVector<serialization::DeclID, 2> >
StoredMergedDeclsMap;
/// \brief A mapping from canonical declaration IDs to the set of additional
@@ -883,11 +944,10 @@ private:
/// \brief Reads a statement from the specified cursor.
Stmt *ReadStmtFromStream(ModuleFile &F);
- typedef llvm::PointerIntPair<const FileEntry *, 1, bool> InputFile;
-
/// \brief Retrieve the file entry and 'overridden' bit for an input
/// file in the given module file.
- InputFile getInputFile(ModuleFile &F, unsigned ID, bool Complain = true);
+ serialization::InputFile getInputFile(ModuleFile &F, unsigned ID,
+ bool Complain = true);
/// \brief Get a FileEntry out of stored-in-PCH filename, making sure we take
/// into account all the necessary relocations.
@@ -895,12 +955,24 @@ private:
void MaybeAddSystemRootToFilename(ModuleFile &M, std::string &Filename);
+ struct ImportedModule {
+ ModuleFile *Mod;
+ ModuleFile *ImportedBy;
+ SourceLocation ImportLoc;
+
+ ImportedModule(ModuleFile *Mod,
+ ModuleFile *ImportedBy,
+ SourceLocation ImportLoc)
+ : Mod(Mod), ImportedBy(ImportedBy), ImportLoc(ImportLoc) { }
+ };
+
ASTReadResult ReadASTCore(StringRef FileName, ModuleKind Type,
- ModuleFile *ImportedBy,
- llvm::SmallVectorImpl<ModuleFile *> &Loaded,
+ SourceLocation ImportLoc, ModuleFile *ImportedBy,
+ SmallVectorImpl<ImportedModule> &Loaded,
+ off_t ExpectedSize, time_t ExpectedModTime,
unsigned ClientLoadCapabilities);
ASTReadResult ReadControlBlock(ModuleFile &F,
- llvm::SmallVectorImpl<ModuleFile *> &Loaded,
+ SmallVectorImpl<ImportedModule> &Loaded,
unsigned ClientLoadCapabilities);
bool ReadASTBlock(ModuleFile &F);
bool ParseLineTable(ModuleFile &F, SmallVectorImpl<uint64_t> &Record);
@@ -1034,6 +1106,14 @@ private:
void finishPendingActions();
+ void addPendingDeclContextInfo(Decl *D,
+ serialization::GlobalDeclID SemaDC,
+ serialization::GlobalDeclID LexicalDC) {
+ assert(D);
+ PendingDeclContextInfo Info = { D, SemaDC, LexicalDC };
+ PendingDeclContextInfos.push_back(Info);
+ }
+
/// \brief Produce an error diagnostic and return true.
///
/// This routine should only be used for fatal errors that have to
@@ -1065,13 +1145,18 @@ public:
/// \param AllowASTWithCompilerErrors If true, the AST reader will accept an
/// AST file the was created out of an AST with compiler errors,
/// otherwise it will reject it.
+ ///
+ /// \param UseGlobalIndex If true, the AST reader will try to load and use
+ /// the global module index.
ASTReader(Preprocessor &PP, ASTContext &Context, StringRef isysroot = "",
bool DisableValidation = false,
- bool AllowASTWithCompilerErrors = false);
+ bool AllowASTWithCompilerErrors = false,
+ bool UseGlobalIndex = true);
~ASTReader();
SourceManager &getSourceManager() const { return SourceMgr; }
+ FileManager &getFileManager() const { return FileMgr; }
/// \brief Flags that indicate what kind of AST loading failures the client
/// of the AST reader can directly handle.
@@ -1082,15 +1167,18 @@ public:
/// \brief The client can't handle any AST loading failures.
ARR_None = 0,
/// \brief The client can handle an AST file that cannot load because it
+ /// is missing.
+ ARR_Missing = 0x1,
+ /// \brief The client can handle an AST file that cannot load because it
/// is out-of-date relative to its input files.
- ARR_OutOfDate = 0x1,
+ ARR_OutOfDate = 0x2,
/// \brief The client can handle an AST file that cannot load because it
/// was built with a different version of Clang.
- ARR_VersionMismatch = 0x2,
+ ARR_VersionMismatch = 0x4,
/// \brief The client can handle an AST file that cannot load because it's
/// compiled configuration doesn't match that of the context it was
/// loaded into.
- ARR_ConfigurationMismatch = 0x4
+ ARR_ConfigurationMismatch = 0x8
};
/// \brief Load the AST file designated by the given file name.
@@ -1100,10 +1188,14 @@ public:
/// \param Type The kind of AST being loaded, e.g., PCH, module, main file,
/// or preamble.
///
+ /// \param ImportLoc the location where the module file will be considered as
+ /// imported from. For non-module AST types it should be invalid.
+ ///
/// \param ClientLoadCapabilities The set of client load-failure
/// capabilities, represented as a bitset of the enumerators of
/// LoadFailureCapabilities.
ASTReadResult ReadAST(const std::string &FileName, ModuleKind Type,
+ SourceLocation ImportLoc,
unsigned ClientLoadCapabilities);
/// \brief Make the entities in the given module and any of its (non-explicit)
@@ -1113,11 +1205,17 @@ public:
///
/// \param NameVisibility The level of visibility to give the names in the
/// module. Visibility can only be increased over time.
+ ///
+ /// \param ImportLoc The location at which the import occurs.
+ ///
+ /// \param Complain Whether to complain about conflicting module imports.
void makeModuleVisible(Module *Mod,
- Module::NameVisibilityKind NameVisibility);
+ Module::NameVisibilityKind NameVisibility,
+ SourceLocation ImportLoc,
+ bool Complain);
/// \brief Make the names within this set of hidden names visible.
- void makeNamesVisible(const HiddenNames &Names);
+ void makeNamesVisible(const HiddenNames &Names, Module *Owner);
/// \brief Set the AST callbacks listener.
void setListener(ASTReaderListener *listener) {
@@ -1127,6 +1225,18 @@ public:
/// \brief Set the AST deserialization listener.
void setDeserializationListener(ASTDeserializationListener *Listener);
+ /// \brief Determine whether this AST reader has a global index.
+ bool hasGlobalIndex() const { return GlobalIndex; }
+
+ /// \brief Attempts to load the global index.
+ ///
+ /// \returns true if loading the global index has failed for any reason.
+ bool loadGlobalIndex();
+
+ /// \brief Determine whether we tried to load the global index, but failed,
+ /// e.g., because it is out-of-date or does not exist.
+ bool isGlobalIndexUnavailable() const;
+
/// \brief Initializes the ASTContext
void InitializeContext();
@@ -1193,8 +1303,8 @@ public:
/// \brief Optionally returns true or false if the preallocated preprocessed
/// entity with index \p Index came from file \p FID.
- virtual llvm::Optional<bool> isPreprocessedEntityInFileID(unsigned Index,
- FileID FID);
+ virtual Optional<bool> isPreprocessedEntityInFileID(unsigned Index,
+ FileID FID);
/// \brief Read the header file information for the given file entry.
virtual HeaderFileInfo GetHeaderFileInfo(const FileEntry *FE);
@@ -1297,7 +1407,7 @@ public:
/// \brief Retrieve the module file that owns the given declaration, or NULL
/// if the declaration is not from a module file.
- ModuleFile *getOwningModuleFile(Decl *D);
+ ModuleFile *getOwningModuleFile(const Decl *D);
/// \brief Returns the source location for the decl \p ID.
SourceLocation getSourceLocationForDeclID(serialization::GlobalDeclID ID);
@@ -1374,7 +1484,7 @@ public:
/// \brief Finds all the visible declarations with a given name.
/// The current implementation of this method just loads the entire
/// lookup table as unmaterialized references.
- virtual DeclContext::lookup_result
+ virtual bool
FindExternalVisibleDeclsByName(const DeclContext *DC,
DeclarationName Name);
@@ -1459,6 +1569,9 @@ public:
virtual void ReadKnownNamespaces(
SmallVectorImpl<NamespaceDecl *> &Namespaces);
+ virtual void ReadUndefinedButUsed(
+ llvm::DenseMap<NamedDecl *, SourceLocation> &Undefined);
+
virtual void ReadTentativeDefinitions(
SmallVectorImpl<VarDecl *> &TentativeDefs);
@@ -1472,7 +1585,7 @@ public:
virtual void ReadDynamicClasses(SmallVectorImpl<CXXRecordDecl *> &Decls);
- virtual void ReadLocallyScopedExternalDecls(
+ virtual void ReadLocallyScopedExternCDecls(
SmallVectorImpl<NamedDecl *> &Decls);
virtual void ReadReferencedSelectors(
@@ -1493,7 +1606,7 @@ public:
void SetIdentifierInfo(unsigned ID, IdentifierInfo *II);
void SetGloballyVisibleDecls(IdentifierInfo *II,
const SmallVectorImpl<uint32_t> &DeclIDs,
- bool Nonrecursive = false);
+ SmallVectorImpl<Decl *> *Decls = 0);
/// \brief Report a diagnostic.
DiagnosticBuilder Diag(unsigned DiagID);
@@ -1520,8 +1633,16 @@ public:
serialization::IdentifierID getGlobalIdentifierID(ModuleFile &M,
unsigned LocalID);
+ void resolvePendingMacro(IdentifierInfo *II, const PendingMacroInfo &PMInfo);
+
+ void installPCHMacroDirectives(IdentifierInfo *II,
+ ModuleFile &M, uint64_t Offset);
+
+ void installImportedMacro(IdentifierInfo *II, MacroDirective *MD,
+ Module *Owner);
+
/// \brief Retrieve the macro with the given ID.
- MacroInfo *getMacro(serialization::MacroID ID, MacroInfo *Hint = 0);
+ MacroInfo *getMacro(serialization::MacroID ID);
/// \brief Retrieve the global macro ID corresponding to the given local
/// ID within the given module file.
@@ -1530,6 +1651,10 @@ public:
/// \brief Read the source location entry with index ID.
virtual bool ReadSLocEntry(int ID);
+ /// \brief Retrieve the module import location and module name for the
+ /// given source manager entry ID.
+ virtual std::pair<SourceLocation, StringRef> getModuleImportLoc(int ID);
+
/// \brief Retrieve the global submodule ID given a module and its local ID
/// number.
serialization::SubmoduleID
@@ -1538,7 +1663,12 @@ public:
/// \brief Retrieve the submodule that corresponds to a global submodule ID.
///
Module *getSubmodule(serialization::SubmoduleID GlobalID);
-
+
+ /// \brief Retrieve the module that corresponds to the given module ID.
+ ///
+ /// Note: overrides method in ExternalASTSource
+ virtual Module *getModule(unsigned ID);
+
/// \brief Retrieve a selector from the given module with its local ID
/// number.
Selector getLocalSelector(ModuleFile &M, unsigned LocalID);
@@ -1597,7 +1727,7 @@ public:
unsigned &Idx);
/// \brief Read a UnresolvedSet structure.
- void ReadUnresolvedSet(ModuleFile &F, UnresolvedSetImpl &Set,
+ void ReadUnresolvedSet(ModuleFile &F, ASTUnresolvedSet &Set,
const RecordData &Record, unsigned &Idx);
/// \brief Read a C++ base specifier.
@@ -1620,13 +1750,13 @@ public:
/// \brief Read a source location.
SourceLocation ReadSourceLocation(ModuleFile &ModuleFile,
- const RecordData &Record, unsigned& Idx) {
+ const RecordData &Record, unsigned &Idx) {
return ReadSourceLocation(ModuleFile, Record[Idx++]);
}
/// \brief Read a source range.
SourceRange ReadSourceRange(ModuleFile &F,
- const RecordData &Record, unsigned& Idx);
+ const RecordData &Record, unsigned &Idx);
/// \brief Read an integral value
llvm::APInt ReadAPInt(const RecordData &Record, unsigned &Idx);
@@ -1635,7 +1765,8 @@ public:
llvm::APSInt ReadAPSInt(const RecordData &Record, unsigned &Idx);
/// \brief Read a floating-point value
- llvm::APFloat ReadAPFloat(const RecordData &Record, unsigned &Idx);
+ llvm::APFloat ReadAPFloat(const RecordData &Record,
+ const llvm::fltSemantics &Sem, unsigned &Idx);
// \brief Read a string
static std::string ReadString(const RecordData &Record, unsigned &Idx);
@@ -1670,20 +1801,32 @@ public:
Expr *ReadSubExpr();
/// \brief Reads the macro record located at the given offset.
- void ReadMacroRecord(ModuleFile &F, uint64_t Offset, MacroInfo *Hint = 0);
+ MacroInfo *ReadMacroRecord(ModuleFile &F, uint64_t Offset);
/// \brief Determine the global preprocessed entity ID that corresponds to
/// the given local ID within the given module.
serialization::PreprocessedEntityID
getGlobalPreprocessedEntityID(ModuleFile &M, unsigned LocalID) const;
- /// \brief Note that the identifier has a macro history.
+ /// \brief Add a macro to resolve imported from a module.
///
/// \param II The name of the macro.
+ /// \param M The module file.
+ /// \param GMacID The global macro ID that is associated with this identifier.
+ /// \param ImportLoc The location where the module is imported.
+ void addPendingMacroFromModule(IdentifierInfo *II,
+ ModuleFile *M,
+ serialization::GlobalMacroID GMacID,
+ SourceLocation ImportLoc);
+
+ /// \brief Add a macro to deserialize its macro directive history from a PCH.
///
- /// \param IDs The global macro IDs that are associated with this identifier.
- void setIdentifierIsMacro(IdentifierInfo *II,
- ArrayRef<serialization::MacroID> IDs);
+ /// \param II The name of the macro.
+ /// \param M The module file.
+ /// \param MacroDirectivesOffset Offset of the serialized macro directive
+ /// history.
+ void addPendingMacroFromPCH(IdentifierInfo *II,
+ ModuleFile *M, uint64_t MacroDirectivesOffset);
/// \brief Read the set of macros defined by this external macro source.
virtual void ReadDefinedMacros();
@@ -1734,7 +1877,7 @@ public:
/// then restores it when destroyed.
struct SavedStreamPosition {
explicit SavedStreamPosition(llvm::BitstreamCursor &Cursor)
- : Cursor(Cursor), Offset(Cursor.GetCurrentBitNo()) { }
+ : Cursor(Cursor), Offset(Cursor.GetCurrentBitNo()) { }
~SavedStreamPosition() {
Cursor.JumpToBit(Offset);
diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h
index ac81e21..2938dc7 100644
--- a/include/clang/Serialization/ASTWriter.h
+++ b/include/clang/Serialization/ASTWriter.h
@@ -14,20 +14,19 @@
#ifndef LLVM_CLANG_FRONTEND_AST_WRITER_H
#define LLVM_CLANG_FRONTEND_AST_WRITER_H
+#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/TemplateBase.h"
-#include "clang/AST/ASTMutationListener.h"
-#include "clang/Lex/PPMutationListener.h"
+#include "clang/Sema/SemaConsumer.h"
#include "clang/Serialization/ASTBitCodes.h"
#include "clang/Serialization/ASTDeserializationListener.h"
-#include "clang/Sema/SemaConsumer.h"
-#include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/Bitcode/BitstreamWriter.h"
#include <map>
#include <queue>
@@ -48,12 +47,14 @@ class CXXCtorInitializer;
class FileEntry;
class FPOptions;
class HeaderSearch;
+class HeaderSearchOptions;
class IdentifierResolver;
class MacroDefinition;
+class MacroDirective;
+class MacroInfo;
class OpaqueValueExpr;
class OpenCLOptions;
class ASTReader;
-class MacroInfo;
class Module;
class PreprocessedEntity;
class PreprocessingRecord;
@@ -63,6 +64,7 @@ class SourceManager;
class SwitchCase;
class TargetInfo;
class VersionTuple;
+class ASTUnresolvedSet;
namespace SrcMgr { class SLocEntry; }
@@ -73,7 +75,6 @@ namespace SrcMgr { class SLocEntry; }
/// data structures. This bitstream can be de-serialized via an
/// instance of the ASTReader class.
class ASTWriter : public ASTDeserializationListener,
- public PPMutationListener,
public ASTMutationListener {
public:
typedef SmallVector<uint64_t, 64> RecordData;
@@ -231,6 +232,16 @@ private:
/// \brief Map that provides the ID numbers of each macro.
llvm::DenseMap<MacroInfo *, serialization::MacroID> MacroIDs;
+ struct MacroInfoToEmitData {
+ const IdentifierInfo *Name;
+ MacroInfo *MI;
+ serialization::MacroID ID;
+ };
+ /// \brief The macro infos to emit.
+ std::vector<MacroInfoToEmitData> MacroInfosToEmit;
+
+ llvm::DenseMap<const IdentifierInfo *, uint64_t> IdentMacroDirectivesOffsetMap;
+
/// @name FlushStmt Caches
/// @{
@@ -266,11 +277,6 @@ private:
/// table, indexed by the Selector ID (-1).
std::vector<uint32_t> SelectorOffsets;
- typedef llvm::MapVector<MacroInfo *, MacroUpdate> MacroUpdatesMap;
-
- /// \brief Updates to macro definitions that were loaded from an AST file.
- MacroUpdatesMap MacroUpdates;
-
/// \brief Mapping from macro definitions (as they occur in the preprocessing
/// record) to the macro IDs.
llvm::DenseMap<const MacroDefinition *, serialization::PreprocessedEntityID>
@@ -343,7 +349,7 @@ private:
/// \brief The set of declarations that may have redeclaration chains that
/// need to be serialized.
- llvm::SetVector<Decl *, llvm::SmallVector<Decl *, 4>,
+ llvm::SetVector<Decl *, SmallVector<Decl *, 4>,
llvm::SmallPtrSet<Decl *, 4> > Redeclarations;
/// \brief Statements that we've encountered while serializing a
@@ -415,7 +421,9 @@ private:
void WriteBlockInfoBlock();
void WriteControlBlock(Preprocessor &PP, ASTContext &Context,
StringRef isysroot, const std::string &OutputFile);
- void WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot);
+ void WriteInputFiles(SourceManager &SourceMgr,
+ HeaderSearchOptions &HSOpts,
+ StringRef isysroot);
void WriteSourceManagerBlock(SourceManager &SourceMgr,
const Preprocessor &PP,
StringRef isysroot);
@@ -424,7 +432,8 @@ private:
void WritePreprocessorDetail(PreprocessingRecord &PPRec);
void WriteSubmodules(Module *WritingModule);
- void WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag);
+ void WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag,
+ bool isModule);
void WriteCXXBaseSpecifiersOffsets();
void WriteType(QualType T);
uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext *DC);
@@ -437,7 +446,6 @@ private:
void WriteIdentifierTable(Preprocessor &PP, IdentifierResolver &IdResolver,
bool IsModule);
void WriteAttributes(ArrayRef<const Attr*> Attrs, RecordDataImpl &Record);
- void WriteMacroUpdates();
void ResolveDeclUpdatesBlocks();
void WriteDeclUpdatesBlocks();
void WriteDeclReplacementsBlock();
@@ -508,9 +516,6 @@ public:
/// \brief Emit a reference to an identifier.
void AddIdentifierRef(const IdentifierInfo *II, RecordDataImpl &Record);
- /// \brief Emit a reference to a macro.
- void addMacroRef(MacroInfo *MI, RecordDataImpl &Record);
-
/// \brief Emit a Selector (which is a smart pointer reference).
void AddSelectorRef(Selector, RecordDataImpl &Record);
@@ -529,7 +534,12 @@ public:
serialization::IdentID getIdentifierRef(const IdentifierInfo *II);
/// \brief Get the unique number used to refer to the given macro.
- serialization::MacroID getMacroRef(MacroInfo *MI);
+ serialization::MacroID getMacroRef(MacroInfo *MI, const IdentifierInfo *Name);
+
+ /// \brief Determine the ID of an already-emitted macro.
+ serialization::MacroID getMacroID(MacroInfo *MI);
+
+ uint64_t getMacroDirectivesOffset(const IdentifierInfo *Name);
/// \brief Emit a reference to a type.
void AddTypeRef(QualType T, RecordDataImpl &Record);
@@ -603,7 +613,7 @@ public:
RecordDataImpl &Record);
/// \brief Emit a UnresolvedSet structure.
- void AddUnresolvedSet(const UnresolvedSetImpl &Set, RecordDataImpl &Record);
+ void AddUnresolvedSet(const ASTUnresolvedSet &Set, RecordDataImpl &Record);
/// \brief Emit a C++ base specifier.
void AddCXXBaseSpecifier(const CXXBaseSpecifier &Base,
@@ -640,6 +650,10 @@ public:
/// source location.
serialization::SubmoduleID inferSubmoduleIDFromLocation(SourceLocation Loc);
+ /// \brief Retrieve a submodule ID for this module.
+ /// Returns 0 If no ID has been associated with the module.
+ unsigned getExistingSubmoduleID(Module *Mod) const;
+
/// \brief Note that the identifier II occurs at the given offset
/// within the identifier table.
void SetIdentifierOffset(const IdentifierInfo *II, uint32_t Offset);
@@ -699,9 +713,6 @@ public:
MacroDefinition *MD);
void ModuleRead(serialization::SubmoduleID ID, Module *Mod);
- // PPMutationListener implementation.
- virtual void UndefinedMacro(MacroInfo *MI);
-
// ASTMutationListener implementation.
virtual void CompletedTagDefinition(const TagDecl *D);
virtual void AddedVisibleDecl(const DeclContext *DC, const Decl *D);
@@ -728,7 +739,7 @@ class PCHGenerator : public SemaConsumer {
std::string isysroot;
raw_ostream *Out;
Sema *SemaPtr;
- llvm::SmallVector<char, 128> Buffer;
+ SmallVector<char, 128> Buffer;
llvm::BitstreamWriter Stream;
ASTWriter Writer;
@@ -743,7 +754,6 @@ public:
~PCHGenerator();
virtual void InitializeSema(Sema &S) { SemaPtr = &S; }
virtual void HandleTranslationUnit(ASTContext &Ctx);
- virtual PPMutationListener *GetPPMutationListener();
virtual ASTMutationListener *GetASTMutationListener();
virtual ASTDeserializationListener *GetASTDeserializationListener();
};
diff --git a/include/clang/Serialization/ContinuousRangeMap.h b/include/clang/Serialization/ContinuousRangeMap.h
index d89cd02..f8ef8a1 100644
--- a/include/clang/Serialization/ContinuousRangeMap.h
+++ b/include/clang/Serialization/ContinuousRangeMap.h
@@ -15,6 +15,7 @@
#ifndef LLVM_CLANG_SERIALIZATION_CONTINUOUS_RANGE_MAP_H
#define LLVM_CLANG_SERIALIZATION_CONTINUOUS_RANGE_MAP_H
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/SmallVector.h"
#include <algorithm>
#include <utility>
diff --git a/include/clang/Serialization/GlobalModuleIndex.h b/include/clang/Serialization/GlobalModuleIndex.h
new file mode 100644
index 0000000..eaf26d1
--- /dev/null
+++ b/include/clang/Serialization/GlobalModuleIndex.h
@@ -0,0 +1,194 @@
+//===--- GlobalModuleIndex.h - Global Module Index --------------*- 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 GlobalModuleIndex class, which manages a global index
+// containing all of the identifiers known to the various modules within a given
+// subdirectory of the module cache. It is used to improve the performance of
+// queries such as "do any modules know about this identifier?"
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_SERIALIZATION_GLOBAL_MODULE_INDEX_H
+#define LLVM_CLANG_SERIALIZATION_GLOBAL_MODULE_INDEX_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include <utility>
+
+namespace llvm {
+class BitstreamCursor;
+class MemoryBuffer;
+}
+
+namespace clang {
+
+class DirectoryEntry;
+class FileEntry;
+class FileManager;
+
+namespace serialization {
+ class ModuleFile;
+}
+
+using llvm::SmallVector;
+using llvm::SmallVectorImpl;
+using llvm::StringRef;
+using serialization::ModuleFile;
+
+/// \brief A global index for a set of module files, providing information about
+/// the identifiers within those module files.
+///
+/// The global index is an aid for name lookup into modules, offering a central
+/// place where one can look for identifiers determine which
+/// module files contain any information about that identifier. This
+/// allows the client to restrict the search to only those module files known
+/// to have a information about that identifier, improving performance. Moreover,
+/// the global module index may know about module files that have not been
+/// imported, and can be queried to determine which modules the current
+/// translation could or should load to fix a problem.
+class GlobalModuleIndex {
+ /// \brief Buffer containing the index file, which is lazily accessed so long
+ /// as the global module index is live.
+ llvm::OwningPtr<llvm::MemoryBuffer> Buffer;
+
+ /// \brief The hash table.
+ ///
+ /// This pointer actually points to a IdentifierIndexTable object,
+ /// but that type is only accessible within the implementation of
+ /// GlobalModuleIndex.
+ void *IdentifierIndex;
+
+ /// \brief Information about a given module file.
+ struct ModuleInfo {
+ ModuleInfo() : File(), Size(), ModTime() { }
+
+ /// \brief The module file, once it has been resolved.
+ ModuleFile *File;
+
+ /// \brief The module file name.
+ std::string FileName;
+
+ /// \brief Size of the module file at the time the global index was built.
+ off_t Size;
+
+ /// \brief Modification time of the module file at the time the global
+ /// index was built.
+ time_t ModTime;
+
+ /// \brief The module IDs on which this module directly depends.
+ /// FIXME: We don't really need a vector here.
+ llvm::SmallVector<unsigned, 4> Dependencies;
+ };
+
+ /// \brief A mapping from module IDs to information about each module.
+ ///
+ /// This vector may have gaps, if module files have been removed or have
+ /// been updated since the index was built. A gap is indicated by an empty
+ /// file name.
+ llvm::SmallVector<ModuleInfo, 16> Modules;
+
+ /// \brief Lazily-populated mapping from module files to their
+ /// corresponding index into the \c Modules vector.
+ llvm::DenseMap<ModuleFile *, unsigned> ModulesByFile;
+
+ /// \brief The set of modules that have not yet been resolved.
+ ///
+ /// The string is just the name of the module itself, which maps to the
+ /// module ID.
+ llvm::StringMap<unsigned> UnresolvedModules;
+
+ /// \brief The number of identifier lookups we performed.
+ unsigned NumIdentifierLookups;
+
+ /// \brief The number of identifier lookup hits, where we recognize the
+ /// identifier.
+ unsigned NumIdentifierLookupHits;
+
+ /// \brief Internal constructor. Use \c readIndex() to read an index.
+ explicit GlobalModuleIndex(llvm::MemoryBuffer *Buffer,
+ llvm::BitstreamCursor Cursor);
+
+ GlobalModuleIndex(const GlobalModuleIndex &) LLVM_DELETED_FUNCTION;
+ GlobalModuleIndex &operator=(const GlobalModuleIndex &) LLVM_DELETED_FUNCTION;
+
+public:
+ ~GlobalModuleIndex();
+
+ /// \brief An error code returned when trying to read an index.
+ enum ErrorCode {
+ /// \brief No error occurred.
+ EC_None,
+ /// \brief No index was found.
+ EC_NotFound,
+ /// \brief Some other process is currently building the index; it is not
+ /// available yet.
+ EC_Building,
+ /// \brief There was an unspecified I/O error reading or writing the index.
+ EC_IOError
+ };
+
+ /// \brief Read a global index file for the given directory.
+ ///
+ /// \param Path The path to the specific module cache where the module files
+ /// for the intended configuration reside.
+ ///
+ /// \returns A pair containing the global module index (if it exists) and
+ /// the error code.
+ static std::pair<GlobalModuleIndex *, ErrorCode>
+ readIndex(StringRef Path);
+
+ /// \brief Retrieve the set of modules that have up-to-date indexes.
+ ///
+ /// \param ModuleFiles Will be populated with the set of module files that
+ /// have been indexed.
+ void getKnownModules(SmallVectorImpl<ModuleFile *> &ModuleFiles);
+
+ /// \brief Retrieve the set of module files on which the given module file
+ /// directly depends.
+ void getModuleDependencies(ModuleFile *File,
+ SmallVectorImpl<ModuleFile *> &Dependencies);
+
+ /// \brief A set of module files in which we found a result.
+ typedef llvm::SmallPtrSet<ModuleFile *, 4> HitSet;
+
+ /// \brief Look for all of the module files with information about the given
+ /// identifier, e.g., a global function, variable, or type with that name.
+ ///
+ /// \param Name The identifier to look for.
+ ///
+ /// \param Hits Will be populated with the set of module files that have
+ /// information about this name.
+ ///
+ /// \returns true if the identifier is known to the index, false otherwise.
+ bool lookupIdentifier(StringRef Name, HitSet &Hits);
+
+ /// \brief Note that the given module file has been loaded.
+ ///
+ /// \returns false if the global module index has information about this
+ /// module file, and true otherwise.
+ bool loadedModuleFile(ModuleFile *File);
+
+ /// \brief Print statistics to standard error.
+ void printStats();
+
+ /// \brief Write a global index into the given
+ ///
+ /// \param FileMgr The file manager to use to load module files.
+ ///
+ /// \param Path The path to the directory containing module files, into
+ /// which the global index will be written.
+ static ErrorCode writeIndex(FileManager &FileMgr, StringRef Path);
+};
+
+}
+
+#endif
diff --git a/include/clang/Serialization/Module.h b/include/clang/Serialization/Module.h
index 39fa3d9..89c604f 100644
--- a/include/clang/Serialization/Module.h
+++ b/include/clang/Serialization/Module.h
@@ -15,9 +15,9 @@
#ifndef LLVM_CLANG_SERIALIZATION_MODULE_H
#define LLVM_CLANG_SERIALIZATION_MODULE_H
+#include "clang/Basic/SourceLocation.h"
#include "clang/Serialization/ASTBitCodes.h"
#include "clang/Serialization/ContinuousRangeMap.h"
-#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/Bitcode/BitstreamReader.h"
@@ -55,6 +55,35 @@ struct DeclContextInfo {
unsigned NumLexicalDecls;
};
+/// \brief The input file that has been loaded from this AST file, along with
+/// bools indicating whether this was an overridden buffer or if it was
+/// out-of-date.
+class InputFile {
+ enum {
+ Overridden = 1,
+ OutOfDate = 2
+ };
+ llvm::PointerIntPair<const FileEntry *, 2, unsigned> Val;
+
+public:
+ InputFile() {}
+ InputFile(const FileEntry *File,
+ bool isOverridden = false, bool isOutOfDate = false) {
+ assert(!(isOverridden && isOutOfDate) &&
+ "an overridden cannot be out-of-date");
+ unsigned intVal = 0;
+ if (isOverridden)
+ intVal = Overridden;
+ else if (isOutOfDate)
+ intVal = OutOfDate;
+ Val.setPointerAndInt(File, intVal);
+ }
+
+ const FileEntry *getFile() const { return Val.getPointer(); }
+ bool isOverridden() const { return Val.getInt() == Overridden; }
+ bool isOutOfDate() const { return Val.getInt() == OutOfDate; }
+};
+
/// \brief Information about a module that has been loaded by the ASTReader.
///
/// Each instance of the Module class corresponds to a single AST file, which
@@ -69,6 +98,9 @@ public:
// === General information ===
+ /// \brief The index of this module in the list of modules.
+ unsigned Index;
+
/// \brief The type of this module.
ModuleKind Kind;
@@ -121,8 +153,15 @@ public:
/// \brief The main bitstream cursor for the main block.
llvm::BitstreamCursor Stream;
+ /// \brief The source location where the module was explicitly or implicitly
+ /// imported in the local translation unit.
+ ///
+ /// If module A depends on and imports module B, both modules will have the
+ /// same DirectImportLoc, but different ImportLoc (B's ImportLoc will be a
+ /// source location inside module A).
+ SourceLocation DirectImportLoc;
+
/// \brief The source location where this module was first imported.
- /// FIXME: This is not properly initialized yet.
SourceLocation ImportLoc;
/// \brief The first source location in this module.
@@ -135,10 +174,8 @@ public:
/// \brief Offsets for all of the input file entries in the AST file.
const uint32_t *InputFileOffsets;
- /// \brief The input files that have been loaded from this AST file, along
- /// with a bool indicating whether this was an overridden buffer.
- std::vector<llvm::PointerIntPair<const FileEntry *, 1, bool> >
- InputFilesLoaded;
+ /// \brief The input files that have been loaded from this AST file.
+ std::vector<InputFile> InputFilesLoaded;
// === Source Locations ===
@@ -252,10 +289,6 @@ public:
/// the header files.
void *HeaderFileInfoTable;
- /// \brief Actual data for the list of framework names used in the header
- /// search information.
- const char *HeaderFileFrameworkStrings;
-
// === Submodule information ===
/// \brief The number of submodules in this module.
unsigned LocalNumSubmodules;
diff --git a/include/clang/Serialization/ModuleManager.h b/include/clang/Serialization/ModuleManager.h
index 6dcaa21..b2c4063 100644
--- a/include/clang/Serialization/ModuleManager.h
+++ b/include/clang/Serialization/ModuleManager.h
@@ -15,19 +15,22 @@
#ifndef LLVM_CLANG_SERIALIZATION_MODULE_MANAGER_H
#define LLVM_CLANG_SERIALIZATION_MODULE_MANAGER_H
-#include "clang/Serialization/Module.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Serialization/Module.h"
#include "llvm/ADT/DenseMap.h"
namespace clang {
+class GlobalModuleIndex;
+class ModuleMap;
+
namespace serialization {
-
+
/// \brief Manages the set of modules loaded by an AST reader.
class ModuleManager {
/// \brief The chain of AST files. The first entry is the one named by the
/// user, the last one is the one that doesn't depend on anything further.
- llvm::SmallVector<ModuleFile*, 2> Chain;
+ SmallVector<ModuleFile *, 2> Chain;
/// \brief All loaded modules, indexed by name.
llvm::DenseMap<const FileEntry *, ModuleFile *> Modules;
@@ -38,7 +41,60 @@ class ModuleManager {
/// \brief A lookup of in-memory (virtual file) buffers
llvm::DenseMap<const FileEntry *, llvm::MemoryBuffer *> InMemoryBuffers;
-
+
+ /// \brief The visitation order.
+ SmallVector<ModuleFile *, 4> VisitOrder;
+
+ /// \brief The list of module files that both we and the global module index
+ /// know about.
+ ///
+ /// Either the global index or the module manager may have modules that the
+ /// other does not know about, because the global index can be out-of-date
+ /// (in which case the module manager could have modules it does not) and
+ /// this particular translation unit might not have loaded all of the modules
+ /// known to the global index.
+ SmallVector<ModuleFile *, 4> ModulesInCommonWithGlobalIndex;
+
+ /// \brief The global module index, if one is attached.
+ ///
+ /// The global module index will actually be owned by the ASTReader; this is
+ /// just an non-owning pointer.
+ GlobalModuleIndex *GlobalIndex;
+
+ /// \brief State used by the "visit" operation to avoid malloc traffic in
+ /// calls to visit().
+ struct VisitState {
+ explicit VisitState(unsigned N)
+ : VisitNumber(N, 0), NextVisitNumber(1), NextState(0)
+ {
+ Stack.reserve(N);
+ }
+
+ ~VisitState() {
+ delete NextState;
+ }
+
+ /// \brief The stack used when marking the imports of a particular module
+ /// as not-to-be-visited.
+ SmallVector<ModuleFile *, 4> Stack;
+
+ /// \brief The visit number of each module file, which indicates when
+ /// this module file was last visited.
+ SmallVector<unsigned, 4> VisitNumber;
+
+ /// \brief The next visit number to use to mark visited module files.
+ unsigned NextVisitNumber;
+
+ /// \brief The next visit state.
+ VisitState *NextState;
+ };
+
+ /// \brief The first visit() state in the chain.
+ VisitState *FirstVisitState;
+
+ VisitState *allocateVisitState();
+ void returnVisitState(VisitState *State);
+
public:
typedef SmallVector<ModuleFile*, 2>::iterator ModuleIterator;
typedef SmallVector<ModuleFile*, 2>::const_iterator ModuleConstIterator;
@@ -79,12 +135,28 @@ public:
/// \brief Returns the module associated with the given name
ModuleFile *lookup(StringRef Name);
-
+
+ /// \brief Returns the module associated with the given module file.
+ ModuleFile *lookup(const FileEntry *File);
+
/// \brief Returns the in-memory (virtual file) buffer with the given name
llvm::MemoryBuffer *lookupBuffer(StringRef Name);
/// \brief Number of modules loaded
unsigned size() const { return Chain.size(); }
+
+ /// \brief The result of attempting to add a new module.
+ enum AddModuleResult {
+ /// \brief The module file had already been loaded.
+ AlreadyLoaded,
+ /// \brief The module file was just loaded in response to this call.
+ NewlyLoaded,
+ /// \brief The module file is missing.
+ Missing,
+ /// \brief The module file is out-of-date.
+ OutOfDate
+ };
+
/// \brief Attempts to create a new module and add it to the list of known
/// modules.
///
@@ -92,26 +164,48 @@ public:
///
/// \param Type The kind of module being loaded.
///
+ /// \param ImportLoc The location at which the module is imported.
+ ///
/// \param ImportedBy The module that is importing this module, or NULL if
/// this module is imported directly by the user.
///
/// \param Generation The generation in which this module was loaded.
///
+ /// \param ExpectedSize The expected size of the module file, used for
+ /// validation. This will be zero if unknown.
+ ///
+ /// \param ExpectedModTime The expected modification time of the module
+ /// file, used for validation. This will be zero if unknown.
+ ///
+ /// \param Module A pointer to the module file if the module was successfully
+ /// loaded.
+ ///
/// \param ErrorStr Will be set to a non-empty string if any errors occurred
/// while trying to load the module.
///
/// \return A pointer to the module that corresponds to this file name,
- /// and a boolean indicating whether the module was newly added.
- std::pair<ModuleFile *, bool>
- addModule(StringRef FileName, ModuleKind Type, ModuleFile *ImportedBy,
- unsigned Generation, std::string &ErrorStr);
+ /// and a value indicating whether the module was loaded.
+ AddModuleResult addModule(StringRef FileName, ModuleKind Type,
+ SourceLocation ImportLoc,
+ ModuleFile *ImportedBy, unsigned Generation,
+ off_t ExpectedSize, time_t ExpectedModTime,
+ ModuleFile *&Module,
+ std::string &ErrorStr);
/// \brief Remove the given set of modules.
- void removeModules(ModuleIterator first, ModuleIterator last);
+ void removeModules(ModuleIterator first, ModuleIterator last,
+ ModuleMap *modMap);
/// \brief Add an in-memory buffer the list of known buffers
void addInMemoryBuffer(StringRef FileName, llvm::MemoryBuffer *Buffer);
-
+
+ /// \brief Set the global module index.
+ void setGlobalIndex(GlobalModuleIndex *Index);
+
+ /// \brief Notification from the AST reader that the given module file
+ /// has been "accepted", and will not (can not) be unloaded.
+ void moduleFileAccepted(ModuleFile *MF);
+
/// \brief Visit each of the modules.
///
/// This routine visits each of the modules, starting with the
@@ -130,7 +224,13 @@ public:
///
/// \param UserData User data associated with the visitor object, which
/// will be passed along to the visitor.
- void visit(bool (*Visitor)(ModuleFile &M, void *UserData), void *UserData);
+ ///
+ /// \param ModuleFilesHit If non-NULL, contains the set of module files
+ /// that we know we need to visit because the global module index told us to.
+ /// Any module that is known to both the global module index and the module
+ /// manager that is *not* in this set can be skipped.
+ void visit(bool (*Visitor)(ModuleFile &M, void *UserData), void *UserData,
+ llvm::SmallPtrSet<ModuleFile *, 4> *ModuleFilesHit = 0);
/// \brief Visit each of the modules with a depth-first traversal.
///
@@ -151,7 +251,29 @@ public:
void visitDepthFirst(bool (*Visitor)(ModuleFile &M, bool Preorder,
void *UserData),
void *UserData);
-
+
+ /// \brief Attempt to resolve the given module file name to a file entry.
+ ///
+ /// \param FileName The name of the module file.
+ ///
+ /// \param ExpectedSize The size that the module file is expected to have.
+ /// If the actual size differs, the resolver should return \c true.
+ ///
+ /// \param ExpectedModTime The modification time that the module file is
+ /// expected to have. If the actual modification time differs, the resolver
+ /// should return \c true.
+ ///
+ /// \param File Will be set to the file if there is one, or null
+ /// otherwise.
+ ///
+ /// \returns True if a file exists but does not meet the size/
+ /// modification time criteria, false if the file is either available and
+ /// suitable, or is missing.
+ bool lookupModuleFile(StringRef FileName,
+ off_t ExpectedSize,
+ time_t ExpectedModTime,
+ const FileEntry *&File);
+
/// \brief View the graphviz representation of the module graph.
void viewGraph();
};
diff --git a/include/clang/StaticAnalyzer/Core/Analyses.def b/include/clang/StaticAnalyzer/Core/Analyses.def
index 01a6ffd..dc79450 100644
--- a/include/clang/StaticAnalyzer/Core/Analyses.def
+++ b/include/clang/StaticAnalyzer/Core/Analyses.def
@@ -41,22 +41,12 @@ ANALYSIS_PURGE(PurgeStmt, "statement", "Purge symbols, bindings, and constraint
ANALYSIS_PURGE(PurgeBlock, "block", "Purge symbols, bindings, and constraints before every basic block")
ANALYSIS_PURGE(PurgeNone, "none", "Do not purge symbols, bindings, or constraints")
-#ifndef ANALYSIS_IPA
-#define ANALYSIS_IPA(NAME, CMDFLAG, DESC)
-#endif
-
-ANALYSIS_IPA(None, "none", "Perform only intra-procedural analysis")
-ANALYSIS_IPA(BasicInlining, "basic-inlining", "Inline C functions and blocks when their definitions are available")
-ANALYSIS_IPA(Inlining, "inlining", "Inline callees when their definitions are available")
-ANALYSIS_IPA(DynamicDispatch, "dynamic", "Experimental: Enable inlining of dynamically dispatched methods")
-ANALYSIS_IPA(DynamicDispatchBifurcate, "dynamic-bifurcate", "Experimental: Enable inlining of dynamically dispatched methods, bifurcate paths when exact type info is unavailable")
-
#ifndef ANALYSIS_INLINING_MODE
#define ANALYSIS_INLINING_MODE(NAME, CMDFLAG, DESC)
#endif
-ANALYSIS_INLINING_MODE(All, "all", "Analyze all functions in the order defined in the TU")
-ANALYSIS_INLINING_MODE(NoRedundancy, "noredundancy", "Do not analyze a function which has been previously inlined, use call graph to order")
+ANALYSIS_INLINING_MODE(All, "all", "Analyze all functions as top level")
+ANALYSIS_INLINING_MODE(NoRedundancy, "noredundancy", "Do not analyze a function which has been previously inlined")
#undef ANALYSIS_STORE
#undef ANALYSIS_CONSTRAINTS
diff --git a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
index fa0754a..6dbdbbf 100644
--- a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
+++ b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
@@ -15,12 +15,12 @@
#ifndef LLVM_CLANG_ANALYZEROPTIONS_H
#define LLVM_CLANG_ANALYZEROPTIONS_H
-#include <string>
-#include <vector>
#include "clang/Basic/LLVM.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringMap.h"
+#include <string>
+#include <vector>
namespace clang {
class ASTConsumer;
@@ -64,13 +64,6 @@ enum AnalysisPurgeMode {
NumPurgeModes
};
-/// AnalysisIPAMode - Set of inter-procedural modes.
-enum AnalysisIPAMode {
-#define ANALYSIS_IPA(NAME, CMDFLAG, DESC) NAME,
-#include "clang/StaticAnalyzer/Core/Analyses.def"
-NumIPAModes
-};
-
/// AnalysisInlineFunctionSelection - Set of inlining function selection heuristics.
enum AnalysisInliningMode {
#define ANALYSIS_INLINING_MODE(NAME, CMDFLAG, DESC) NAME,
@@ -102,8 +95,28 @@ enum CXXInlineableMemberKind {
CIMK_Destructors
};
+/// \brief Describes the different modes of inter-procedural analysis.
+enum IPAKind {
+ IPAK_NotSet = 0,
+
+ /// Perform only intra-procedural analysis.
+ IPAK_None = 1,
+
+ /// Inline C functions and blocks when their definitions are available.
+ IPAK_BasicInlining = 2,
-class AnalyzerOptions : public llvm::RefCountedBase<AnalyzerOptions> {
+ /// Inline callees(C, C++, ObjC) when their definitions are available.
+ IPAK_Inlining = 3,
+
+ /// Enable inlining of dynamically dispatched methods.
+ IPAK_DynamicDispatch = 4,
+
+ /// Enable inlining of dynamically dispatched methods, bifurcate paths when
+ /// exact type info is unavailable.
+ IPAK_DynamicDispatchBifurcate = 5
+};
+
+class AnalyzerOptions : public RefCountedBase<AnalyzerOptions> {
public:
typedef llvm::StringMap<std::string> ConfigTable;
@@ -117,14 +130,8 @@ public:
AnalysisDiagClients AnalysisDiagOpt;
AnalysisPurgeMode AnalysisPurgeOpt;
- // \brief The interprocedural analysis mode.
- AnalysisIPAMode IPAMode;
-
std::string AnalyzeSpecificFunction;
- /// \brief The maximum number of exploded nodes the analyzer will generate.
- unsigned MaxNodes;
-
/// \brief The maximum number of times the analyzer visits a block.
unsigned maxBlockVisitOnPath;
@@ -159,39 +166,71 @@ public:
unsigned InlineMaxStackDepth;
/// \brief The mode of function selection used during inlining.
- unsigned InlineMaxFunctionSize;
-
- /// \brief The mode of function selection used during inlining.
AnalysisInliningMode InliningMode;
private:
+ /// \brief Describes the kinds for high-level analyzer mode.
+ enum UserModeKind {
+ UMK_NotSet = 0,
+ /// Perform shallow but fast analyzes.
+ UMK_Shallow = 1,
+ /// Perform deep analyzes.
+ UMK_Deep = 2
+ };
+
+ /// Controls the high-level analyzer mode, which influences the default
+ /// settings for some of the lower-level config options (such as IPAMode).
+ /// \sa getUserMode
+ UserModeKind UserMode;
+
+ /// Controls the mode of inter-procedural analysis.
+ IPAKind IPAMode;
+
/// Controls which C++ member functions will be considered for inlining.
CXXInlineableMemberKind CXXMemberInliningMode;
/// \sa includeTemporaryDtorsInCFG
- llvm::Optional<bool> IncludeTemporaryDtorsInCFG;
+ Optional<bool> IncludeTemporaryDtorsInCFG;
/// \sa mayInlineCXXStandardLibrary
- llvm::Optional<bool> InlineCXXStandardLibrary;
+ Optional<bool> InlineCXXStandardLibrary;
/// \sa mayInlineTemplateFunctions
- llvm::Optional<bool> InlineTemplateFunctions;
+ Optional<bool> InlineTemplateFunctions;
+
+ /// \sa mayInlineCXXContainerCtorsAndDtors
+ Optional<bool> InlineCXXContainerCtorsAndDtors;
/// \sa mayInlineObjCMethod
- llvm::Optional<bool> ObjCInliningMode;
+ Optional<bool> ObjCInliningMode;
// Cache of the "ipa-always-inline-size" setting.
// \sa getAlwaysInlineSize
- llvm::Optional<unsigned> AlwaysInlineSize;
+ Optional<unsigned> AlwaysInlineSize;
- /// \sa shouldPruneNullReturnPaths
- llvm::Optional<bool> PruneNullReturnPaths;
+ /// \sa shouldSuppressNullReturnPaths
+ Optional<bool> SuppressNullReturnPaths;
+
+ // \sa getMaxInlinableSize
+ Optional<unsigned> MaxInlinableSize;
/// \sa shouldAvoidSuppressingNullArgumentPaths
- llvm::Optional<bool> AvoidSuppressingNullArgumentPaths;
-
+ Optional<bool> AvoidSuppressingNullArgumentPaths;
+
+ /// \sa shouldSuppressInlinedDefensiveChecks
+ Optional<bool> SuppressInlinedDefensiveChecks;
+
+ /// \sa shouldSuppressFromCXXStandardLibrary
+ Optional<bool> SuppressFromCXXStandardLibrary;
+
/// \sa getGraphTrimInterval
- llvm::Optional<unsigned> GraphTrimInterval;
+ Optional<unsigned> GraphTrimInterval;
+
+ /// \sa getMaxTimesInlineLarge
+ Optional<unsigned> MaxTimesInlineLarge;
+
+ /// \sa getMaxNodesPerTopLevelFunction
+ Optional<unsigned> MaxNodesPerTopLevelFunction;
/// Interprets an option's string value as a boolean.
///
@@ -200,13 +239,20 @@ private:
bool getBooleanOption(StringRef Name, bool DefaultVal);
/// Variant that accepts a Optional value to cache the result.
- bool getBooleanOption(llvm::Optional<bool> &V, StringRef Name,
- bool DefaultVal);
-
+ bool getBooleanOption(Optional<bool> &V, StringRef Name, bool DefaultVal);
+
/// Interprets an option's string value as an integer value.
- int getOptionAsInteger(llvm::StringRef Name, int DefaultVal);
+ int getOptionAsInteger(StringRef Name, int DefaultVal);
public:
+ /// \brief Retrieves and sets the UserMode. This is a high-level option,
+ /// which is used to set other low-level options. It is not accessible
+ /// outside of AnalyzerOptions.
+ UserModeKind getUserMode();
+
+ /// \brief Returns the inter-procedural analysis mode.
+ IPAKind getIPAMode();
+
/// Returns the option controlling which C++ member functions will be
/// considered for inlining.
///
@@ -238,6 +284,13 @@ public:
/// accepts the values "true" and "false".
bool mayInlineTemplateFunctions();
+ /// Returns whether or not constructors and destructors of C++ container
+ /// objects may be considered for inlining.
+ ///
+ /// This is controlled by the 'c++-container-inlining' config option, which
+ /// accepts the values "true" and "false".
+ bool mayInlineCXXContainerCtorsAndDtors();
+
/// Returns whether or not paths that go through null returns should be
/// suppressed.
///
@@ -246,12 +299,12 @@ public:
///
/// This is controlled by the 'suppress-null-return-paths' config option,
/// which accepts the values "true" and "false".
- bool shouldPruneNullReturnPaths();
+ bool shouldSuppressNullReturnPaths();
/// Returns whether a bug report should \em not be suppressed if its path
/// includes a call with a null argument, even if that call has a null return.
///
- /// This option has no effect when #shouldPruneNullReturnPaths() is false.
+ /// This option has no effect when #shouldSuppressNullReturnPaths() is false.
///
/// This is a counter-heuristic to avoid false negatives.
///
@@ -259,12 +312,43 @@ public:
/// option, which accepts the values "true" and "false".
bool shouldAvoidSuppressingNullArgumentPaths();
+ /// Returns whether or not diagnostics containing inlined defensive NULL
+ /// checks should be suppressed.
+ ///
+ /// This is controlled by the 'suppress-inlined-defensive-checks' config
+ /// option, which accepts the values "true" and "false".
+ bool shouldSuppressInlinedDefensiveChecks();
+
+ /// Returns whether or not diagnostics reported within the C++ standard
+ /// library should be suppressed.
+ ///
+ /// This is controlled by the 'suppress-c++-stdlib' config option,
+ /// which accepts the values "true" and "false".
+ bool shouldSuppressFromCXXStandardLibrary();
+
+ /// Returns whether irrelevant parts of a bug report path should be pruned
+ /// out of the final output.
+ ///
+ /// This is controlled by the 'prune-paths' config option, which accepts the
+ /// values "true" and "false".
+ bool shouldPrunePaths();
+
+ /// Returns true if 'static' initializers should be in conditional logic
+ /// in the CFG.
+ bool shouldConditionalizeStaticInitializers();
+
// Returns the size of the functions (in basic blocks), which should be
// considered to be small enough to always inline.
//
// This is controlled by "ipa-always-inline-size" analyzer-config option.
unsigned getAlwaysInlineSize();
-
+
+ // Returns the bound on the number of basic blocks in an inlined function
+ // (50 by default).
+ //
+ // This is controlled by "-analyzer-config max-inlinable-size" option.
+ unsigned getMaxInlinableSize();
+
/// Returns true if the analyzer engine should synthesize fake bodies
/// for well-known functions.
bool shouldSynthesizeBodies();
@@ -276,32 +360,45 @@ public:
/// node reclamation, set the option to "0".
unsigned getGraphTrimInterval();
+ /// Returns the maximum times a large function could be inlined.
+ ///
+ /// This is controlled by the 'max-times-inline-large' config option.
+ unsigned getMaxTimesInlineLarge();
+
+ /// Returns the maximum number of nodes the analyzer can generate while
+ /// exploring a top level function (for each exploded graph).
+ /// 150000 is default; 0 means no limit.
+ ///
+ /// This is controlled by the 'max-nodes' config option.
+ unsigned getMaxNodesPerTopLevelFunction();
+
public:
- AnalyzerOptions() : CXXMemberInliningMode() {
- AnalysisStoreOpt = RegionStoreModel;
- AnalysisConstraintsOpt = RangeConstraintsModel;
- AnalysisDiagOpt = PD_HTML;
- AnalysisPurgeOpt = PurgeStmt;
- IPAMode = DynamicDispatchBifurcate;
- ShowCheckerHelp = 0;
- AnalyzeAll = 0;
- AnalyzerDisplayProgress = 0;
- AnalyzeNestedBlocks = 0;
- eagerlyAssumeBinOpBifurcation = 0;
- TrimGraph = 0;
- visualizeExplodedGraphWithGraphViz = 0;
- visualizeExplodedGraphWithUbiGraph = 0;
- UnoptimizedCFG = 0;
- PrintStats = 0;
- NoRetryExhausted = 0;
+ AnalyzerOptions() :
+ AnalysisStoreOpt(RegionStoreModel),
+ AnalysisConstraintsOpt(RangeConstraintsModel),
+ AnalysisDiagOpt(PD_HTML),
+ AnalysisPurgeOpt(PurgeStmt),
+ ShowCheckerHelp(0),
+ AnalyzeAll(0),
+ AnalyzerDisplayProgress(0),
+ AnalyzeNestedBlocks(0),
+ eagerlyAssumeBinOpBifurcation(0),
+ TrimGraph(0),
+ visualizeExplodedGraphWithGraphViz(0),
+ visualizeExplodedGraphWithUbiGraph(0),
+ UnoptimizedCFG(0),
+ PrintStats(0),
+ NoRetryExhausted(0),
// Cap the stack depth at 4 calls (5 stack frames, base + 4 calls).
- InlineMaxStackDepth = 5;
- InlineMaxFunctionSize = 200;
- InliningMode = NoRedundancy;
- }
+ InlineMaxStackDepth(5),
+ InliningMode(NoRedundancy),
+ UserMode(UMK_NotSet),
+ IPAMode(IPAK_NotSet),
+ CXXMemberInliningMode() {}
+
};
-typedef llvm::IntrusiveRefCntPtr<AnalyzerOptions> AnalyzerOptionsRef;
+typedef IntrusiveRefCntPtr<AnalyzerOptions> AnalyzerOptionsRef;
}
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
index b5a88ba..7a87e47 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
@@ -19,12 +19,12 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/ilist.h"
-#include "llvm/ADT/ilist_node.h"
#include "llvm/ADT/ImmutableSet.h"
-#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/ilist.h"
+#include "llvm/ADT/ilist_node.h"
namespace clang {
@@ -75,6 +75,8 @@ protected:
std::string Description;
PathDiagnosticLocation Location;
PathDiagnosticLocation UniqueingLocation;
+ const Decl *UniqueingDecl;
+
const ExplodedNode *ErrorNode;
SmallVector<SourceRange, 4> Ranges;
ExtraTextList ExtraText;
@@ -87,14 +89,14 @@ protected:
/// diagnostics to include when constructing the final path diagnostic.
/// The stack is largely used by BugReporter when generating PathDiagnostics
/// for multiple PathDiagnosticConsumers.
- llvm::SmallVector<Symbols *, 2> interestingSymbols;
+ SmallVector<Symbols *, 2> interestingSymbols;
/// A (stack of) set of regions that are registered with this report as being
/// "interesting", and thus used to help decide which diagnostics
/// to include when constructing the final path diagnostic.
/// The stack is largely used by BugReporter when generating PathDiagnostics
/// for multiple PathDiagnosticConsumers.
- llvm::SmallVector<Regions *, 2> interestingRegions;
+ SmallVector<Regions *, 2> interestingRegions;
/// A set of location contexts that correspoind to call sites which should be
/// considered "interesting".
@@ -162,9 +164,10 @@ public:
/// for uniquing reports. For example, memory leaks checker, could set this to
/// the allocation site, rather then the location where the bug is reported.
BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode,
- PathDiagnosticLocation LocationToUnique)
+ PathDiagnosticLocation LocationToUnique, const Decl *DeclToUnique)
: BT(bt), DeclWithIssue(0), Description(desc),
UniqueingLocation(LocationToUnique),
+ UniqueingDecl(DeclToUnique),
ErrorNode(errornode), ConfigurationChangeToken(0),
DoNotPrunePath(false) {}
@@ -260,6 +263,16 @@ public:
/// This location is used by clients rendering diagnostics.
virtual PathDiagnosticLocation getLocation(const SourceManager &SM) const;
+ /// \brief Get the location on which the report should be uniqued.
+ PathDiagnosticLocation getUniqueingLocation() const {
+ return UniqueingLocation;
+ }
+
+ /// \brief Get the declaration containing the uniqueing location.
+ const Decl *getUniqueingDecl() const {
+ return UniqueingDecl;
+ }
+
const Stmt *getStmt() const;
/// \brief Add a range to a bug report.
@@ -440,8 +453,7 @@ public:
return true;
}
- bool RemoveUneededCalls(PathPieces &pieces, BugReport *R,
- PathDiagnosticCallPiece *CallWithLoc = 0);
+ bool RemoveUnneededCalls(PathPieces &pieces, BugReport *R);
void Register(BugType *BT);
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
index 78e35ca..2e5f207 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h
@@ -55,8 +55,8 @@ public:
///
/// The last parameter can be used to register a new visitor with the given
/// BugReport while processing a node.
- virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
- const ExplodedNode *PrevN,
+ virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *Succ,
+ const ExplodedNode *Pred,
BugReporterContext &BRC,
BugReport &BR) = 0;
@@ -99,26 +99,24 @@ class FindLastStoreBRVisitor
{
const MemRegion *R;
SVal V;
- bool satisfied;
+ bool Satisfied;
-public:
- /// \brief Convenience method to create a visitor given only the MemRegion.
- /// Returns NULL if the visitor cannot be created. For example, when the
- /// corresponding value is unknown.
- static BugReporterVisitor *createVisitorObject(const ExplodedNode *N,
- const MemRegion *R);
+ /// If the visitor is tracking the value directly responsible for the
+ /// bug, we are going to employ false positive suppression.
+ bool EnableNullFPSuppression;
+public:
/// Creates a visitor for every VarDecl inside a Stmt and registers it with
/// the BugReport.
- static void registerStatementVarDecls(BugReport &BR, const Stmt *S);
+ static void registerStatementVarDecls(BugReport &BR, const Stmt *S,
+ bool EnableNullFPSuppression);
- FindLastStoreBRVisitor(SVal v, const MemRegion *r)
- : R(r), V(v), satisfied(false) {
- assert (!V.isUnknown() && "Cannot track unknown value.");
-
- // TODO: Does it make sense to allow undef values here?
- // (If not, also see UndefCapturedBlockVarChecker)?
- }
+ FindLastStoreBRVisitor(KnownSVal V, const MemRegion *R,
+ bool InEnableNullFPSuppression)
+ : R(R),
+ V(V),
+ Satisfied(false),
+ EnableNullFPSuppression(InEnableNullFPSuppression) {}
void Profile(llvm::FoldingSetNodeID &ID) const;
@@ -132,12 +130,14 @@ class TrackConstraintBRVisitor
: public BugReporterVisitorImpl<TrackConstraintBRVisitor>
{
DefinedSVal Constraint;
- const bool Assumption;
- bool isSatisfied;
+ bool Assumption;
+ bool IsSatisfied;
+ bool IsZeroCheck;
public:
TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption)
- : Constraint(constraint), Assumption(assumption), isSatisfied(false) {}
+ : Constraint(constraint), Assumption(assumption), IsSatisfied(false),
+ IsZeroCheck(!Assumption && Constraint.getAs<Loc>()) {}
void Profile(llvm::FoldingSetNodeID &ID) const;
@@ -149,12 +149,19 @@ public:
const ExplodedNode *PrevN,
BugReporterContext &BRC,
BugReport &BR);
+
+private:
+ /// Checks if the constraint is valid in the current state.
+ bool isUnderconstrained(const ExplodedNode *N) const;
+
};
+/// \class NilReceiverBRVisitor
+/// \brief Prints path notes when a message is sent to a nil receiver.
class NilReceiverBRVisitor
- : public BugReporterVisitorImpl<NilReceiverBRVisitor>
-{
+ : public BugReporterVisitorImpl<NilReceiverBRVisitor> {
public:
+
void Profile(llvm::FoldingSetNodeID &ID) const {
static int x = 0;
ID.AddPointer(&x);
@@ -164,6 +171,10 @@ public:
const ExplodedNode *PrevN,
BugReporterContext &BRC,
BugReport &BR);
+
+ /// If the statement is a message send expression with nil receiver, returns
+ /// the receiver expression. Returns NULL otherwise.
+ static const Expr *getNilReceiver(const Stmt *S, const ExplodedNode *N);
};
/// Visitor that tries to report interesting diagnostics from conditions.
@@ -223,11 +234,38 @@ public:
const ExplodedNode *N);
bool patternMatch(const Expr *Ex,
- llvm::raw_ostream &Out,
+ raw_ostream &Out,
BugReporterContext &BRC,
BugReport &R,
const ExplodedNode *N,
- llvm::Optional<bool> &prunable);
+ Optional<bool> &prunable);
+};
+
+/// \brief Suppress reports that might lead to known false positives.
+///
+/// Currently this suppresses reports based on locations of bugs.
+class LikelyFalsePositiveSuppressionBRVisitor
+ : public BugReporterVisitorImpl<LikelyFalsePositiveSuppressionBRVisitor> {
+public:
+ static void *getTag() {
+ static int Tag = 0;
+ return static_cast<void *>(&Tag);
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddPointer(getTag());
+ }
+
+ virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N,
+ const ExplodedNode *Prev,
+ BugReporterContext &BRC,
+ BugReport &BR) {
+ return 0;
+ }
+
+ virtual PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
+ const ExplodedNode *N,
+ BugReport &BR);
};
/// \brief When a region containing undefined value or '0' value is passed
@@ -256,6 +294,38 @@ public:
BugReport &BR);
};
+class SuppressInlineDefensiveChecksVisitor
+: public BugReporterVisitorImpl<SuppressInlineDefensiveChecksVisitor>
+{
+ /// The symbolic value for which we are tracking constraints.
+ /// This value is constrained to null in the end of path.
+ DefinedSVal V;
+
+ /// Track if we found the node where the constraint was first added.
+ bool IsSatisfied;
+
+ /// Since the visitors can be registered on nodes previous to the last
+ /// node in the BugReport, but the path traversal always starts with the last
+ /// node, the visitor invariant (that we start with a node in which V is null)
+ /// might not hold when node visitation starts. We are going to start tracking
+ /// from the last node in which the value is null.
+ bool IsTrackingTurnedOn;
+
+public:
+ SuppressInlineDefensiveChecksVisitor(DefinedSVal Val, const ExplodedNode *N);
+
+ void Profile(llvm::FoldingSetNodeID &ID) const;
+
+ /// Return the tag associated with this visitor. This tag will be used
+ /// to make all PathDiagnosticPieces created by this visitor.
+ static const char *getTag();
+
+ PathDiagnosticPiece *VisitNode(const ExplodedNode *Succ,
+ const ExplodedNode *Pred,
+ BugReporterContext &BRC,
+ BugReport &BR);
+};
+
namespace bugreporter {
/// Attempts to add visitors to trace a null or undefined value back to its
@@ -268,14 +338,17 @@ namespace bugreporter {
/// \param IsArg Whether the statement is an argument to an inlined function.
/// If this is the case, \p N \em must be the CallEnter node for
/// the function.
+/// \param EnableNullFPSuppression Whether we should employ false positive
+/// suppression (inlined defensive checks, returned null).
///
/// \return Whether or not the function was able to add visitors for this
/// statement. Note that returning \c true does not actually imply
/// that any visitors were added.
bool trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, BugReport &R,
- bool IsArg = false);
+ bool IsArg = false,
+ bool EnableNullFPSuppression = true);
-const Stmt *GetDerefExpr(const ExplodedNode *N);
+const Expr *getDerefExpr(const Stmt *S);
const Stmt *GetDenomExpr(const ExplodedNode *N);
const Stmt *GetRetValExpr(const ExplodedNode *N);
bool isDeclRefExprToReference(const Expr *E);
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
index cb49122..644aa31 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
@@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_ANALYSIS_BUGTYPE
#define LLVM_CLANG_ANALYSIS_BUGTYPE
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/FoldingSet.h"
#include <string>
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
index 6dc26e6..3f0a1b1 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
@@ -14,12 +14,12 @@
#ifndef LLVM_CLANG_PATH_DIAGNOSTIC_H
#define LLVM_CLANG_PATH_DIAGNOSTIC_H
-#include "clang/Basic/SourceLocation.h"
#include "clang/Analysis/ProgramPoint.h"
+#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
-#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/PointerUnion.h"
#include <deque>
#include <iterator>
#include <string>
@@ -341,7 +341,7 @@ protected:
public:
virtual ~PathDiagnosticPiece();
- llvm::StringRef getString() const { return str; }
+ StringRef getString() const { return str; }
/// Tag this PathDiagnosticPiece with the given C-string.
void setTag(const char *tag) { Tag = tag; }
@@ -461,13 +461,13 @@ public:
};
class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece {
- llvm::Optional<bool> IsPrunable;
+ Optional<bool> IsPrunable;
/// If the event occurs in a different frame than the final diagnostic,
/// supply a message that will be used to construct an extra hint on the
/// returns from all the calls on the stack from this event to the final
/// diagnostic.
- llvm::OwningPtr<StackHintGenerator> CallStackHint;
+ OwningPtr<StackHintGenerator> CallStackHint;
public:
PathDiagnosticEventPiece(const PathDiagnosticLocation &pos,
@@ -670,13 +670,19 @@ class PathDiagnostic : public llvm::FoldingSetNode {
std::deque<std::string> OtherDesc;
PathDiagnosticLocation Loc;
PathPieces pathImpl;
- llvm::SmallVector<PathPieces *, 3> pathStack;
+ SmallVector<PathPieces *, 3> pathStack;
- PathDiagnostic(); // Do not implement.
+ /// \brief Important bug uniqueing location.
+ /// The location info is useful to differentiate between bugs.
+ PathDiagnosticLocation UniqueingLoc;
+ const Decl *UniqueingDecl;
+
+ PathDiagnostic() LLVM_DELETED_FUNCTION;
public:
PathDiagnostic(const Decl *DeclWithIssue, StringRef bugtype,
StringRef verboseDesc, StringRef shortDesc,
- StringRef category);
+ StringRef category, PathDiagnosticLocation LocationToUnique,
+ const Decl *DeclToUnique);
~PathDiagnostic();
@@ -738,6 +744,16 @@ public:
return Loc;
}
+ /// \brief Get the location on which the report should be uniqued.
+ PathDiagnosticLocation getUniqueingLoc() const {
+ return UniqueingLoc;
+ }
+
+ /// \brief Get the declaration containing the uniqueing location.
+ const Decl *getUniqueingDecl() const {
+ return UniqueingDecl;
+ }
+
void flattenLocations() {
Loc.flatten();
for (PathPieces::iterator I = pathImpl.begin(), E = pathImpl.end();
diff --git a/include/clang/StaticAnalyzer/Core/Checker.h b/include/clang/StaticAnalyzer/Core/Checker.h
index 9eb1248..0dbaab0 100644
--- a/include/clang/StaticAnalyzer/Core/Checker.h
+++ b/include/clang/StaticAnalyzer/Core/Checker.h
@@ -34,11 +34,11 @@ class ASTDecl {
template <typename CHECKER>
static void _checkDecl(void *checker, const Decl *D, AnalysisManager& mgr,
BugReporter &BR) {
- ((const CHECKER *)checker)->checkASTDecl(llvm::cast<DECL>(D), mgr, BR);
+ ((const CHECKER *)checker)->checkASTDecl(cast<DECL>(D), mgr, BR);
}
static bool _handlesDecl(const Decl *D) {
- return llvm::isa<DECL>(D);
+ return isa<DECL>(D);
}
public:
template <typename CHECKER>
@@ -86,11 +86,11 @@ template <typename STMT>
class PreStmt {
template <typename CHECKER>
static void _checkStmt(void *checker, const Stmt *S, CheckerContext &C) {
- ((const CHECKER *)checker)->checkPreStmt(llvm::cast<STMT>(S), C);
+ ((const CHECKER *)checker)->checkPreStmt(cast<STMT>(S), C);
}
static bool _handlesStmt(const Stmt *S) {
- return llvm::isa<STMT>(S);
+ return isa<STMT>(S);
}
public:
template <typename CHECKER>
@@ -105,11 +105,11 @@ template <typename STMT>
class PostStmt {
template <typename CHECKER>
static void _checkStmt(void *checker, const Stmt *S, CheckerContext &C) {
- ((const CHECKER *)checker)->checkPostStmt(llvm::cast<STMT>(S), C);
+ ((const CHECKER *)checker)->checkPostStmt(cast<STMT>(S), C);
}
static bool _handlesStmt(const Stmt *S) {
- return llvm::isa<STMT>(S);
+ return isa<STMT>(S);
}
public:
template <typename CHECKER>
@@ -227,18 +227,18 @@ public:
}
};
-class EndPath {
+class EndFunction {
template <typename CHECKER>
- static void _checkEndPath(void *checker,
- CheckerContext &C) {
- ((const CHECKER *)checker)->checkEndPath(C);
+ static void _checkEndFunction(void *checker,
+ CheckerContext &C) {
+ ((const CHECKER *)checker)->checkEndFunction(C);
}
public:
template <typename CHECKER>
static void _register(CHECKER *checker, CheckerManager &mgr) {
- mgr._registerForEndPath(
- CheckerManager::CheckEndPathFunc(checker, _checkEndPath<CHECKER>));
+ mgr._registerForEndFunction(
+ CheckerManager::CheckEndFunctionFunc(checker, _checkEndFunction<CHECKER>));
}
};
@@ -293,7 +293,7 @@ class RegionChanges {
static ProgramStateRef
_checkRegionChanges(void *checker,
ProgramStateRef state,
- const StoreManager::InvalidatedSymbols *invalidated,
+ const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> Explicits,
ArrayRef<const MemRegion *> Regions,
const CallEvent *Call) {
@@ -317,6 +317,59 @@ public:
}
};
+class PointerEscape {
+ template <typename CHECKER>
+ static ProgramStateRef
+ _checkPointerEscape(void *checker,
+ ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind,
+ bool IsConst) {
+ if (!IsConst)
+ return ((const CHECKER *)checker)->checkPointerEscape(State,
+ Escaped,
+ Call,
+ Kind);
+ return State;
+ }
+
+public:
+ template <typename CHECKER>
+ static void _register(CHECKER *checker, CheckerManager &mgr) {
+ mgr._registerForPointerEscape(
+ CheckerManager::CheckPointerEscapeFunc(checker,
+ _checkPointerEscape<CHECKER>));
+ }
+};
+
+class ConstPointerEscape {
+ template <typename CHECKER>
+ static ProgramStateRef
+ _checkConstPointerEscape(void *checker,
+ ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind,
+ bool IsConst) {
+ if (IsConst)
+ return ((const CHECKER *)checker)->checkConstPointerEscape(State,
+ Escaped,
+ Call,
+ Kind);
+ return State;
+ }
+
+public:
+ template <typename CHECKER>
+ static void _register(CHECKER *checker, CheckerManager &mgr) {
+ mgr._registerForPointerEscape(
+ CheckerManager::CheckPointerEscapeFunc(checker,
+ _checkConstPointerEscape<CHECKER>));
+ }
+};
+
+
template <typename EVENT>
class Event {
template <typename CHECKER>
@@ -448,6 +501,14 @@ struct ImplicitNullDerefEvent {
BugReporter *BR;
};
+/// \brief A helper class which wraps a boolean value set to false by default.
+struct DefaultBool {
+ bool val;
+ DefaultBool() : val(false) {}
+ operator bool() const { return val; }
+ DefaultBool &operator=(bool b) { val = b; return *this; }
+};
+
} // end ento namespace
} // end clang namespace
diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h
index 7ae8e53..6f99fc1 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerManager.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h
@@ -14,12 +14,12 @@
#ifndef LLVM_CLANG_SA_CORE_CHECKERMANAGER_H
#define LLVM_CLANG_SA_CORE_CHECKERMANAGER_H
+#include "clang/Analysis/ProgramPoint.h"
#include "clang/Basic/LangOptions.h"
-#include "llvm/ADT/SmallVector.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
-#include "clang/Analysis/ProgramPoint.h"
+#include "llvm/ADT/SmallVector.h"
#include <vector>
namespace clang {
@@ -112,6 +112,26 @@ public:
RET operator()() const { return Fn(Checker); }
};
+/// \brief Describes the different reasons a pointer escapes
+/// during analysis.
+enum PointerEscapeKind {
+ /// A pointer escapes due to binding its value to a location
+ /// that the analyzer cannot track.
+ PSK_EscapeOnBind,
+
+ /// The pointer has been passed to a function call directly.
+ PSK_DirectEscapeOnCall,
+
+ /// The pointer has been passed to a function indirectly.
+ /// For example, the pointer is accessible through an
+ /// argument to a function.
+ PSK_IndirectEscapeOnCall,
+
+ /// The reason for pointer escape is unknown. For example,
+ /// a region containing this pointer is invalidated.
+ PSK_EscapeOther
+};
+
class CheckerManager {
const LangOptions LangOpts;
@@ -264,11 +284,11 @@ public:
void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR,
ExprEngine &Eng);
- /// \brief Run checkers for end of path.
- void runCheckersForEndPath(NodeBuilderContext &BC,
- ExplodedNodeSet &Dst,
- ExplodedNode *Pred,
- ExprEngine &Eng);
+ /// \brief Run checkers on end of function.
+ void runCheckersForEndFunction(NodeBuilderContext &BC,
+ ExplodedNodeSet &Dst,
+ ExplodedNode *Pred,
+ ExprEngine &Eng);
/// \brief Run checkers for branch condition.
void runCheckersForBranchCondition(const Stmt *condition,
@@ -310,14 +330,34 @@ public:
/// by a call.
ProgramStateRef
runCheckersForRegionChanges(ProgramStateRef state,
- const StoreManager::InvalidatedSymbols *invalidated,
+ const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
const CallEvent *Call);
+ /// \brief Run checkers when pointers escape.
+ ///
+ /// This notifies the checkers about pointer escape, which occurs whenever
+ /// the analyzer cannot track the symbol any more. For example, as a
+ /// result of assigning a pointer into a global or when it's passed to a
+ /// function call the analyzer cannot model.
+ ///
+ /// \param State The state at the point of escape.
+ /// \param Escaped The list of escaped symbols.
+ /// \param Call The corresponding CallEvent, if the symbols escape as
+ /// parameters to the given call.
+ /// \param IsConst Specifies if the pointer is const.
+ /// \returns Checkers can modify the state by returning a new one.
+ ProgramStateRef
+ runCheckersForPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind,
+ bool IsConst = false);
+
/// \brief Run checkers for handling assumptions on symbolic values.
ProgramStateRef runCheckersForEvalAssume(ProgramStateRef state,
- SVal Cond, bool Assumption);
+ SVal Cond, bool Assumption);
/// \brief Run checkers for evaluating a call.
///
@@ -382,7 +422,7 @@ public:
CheckEndAnalysisFunc;
typedef CheckerFn<void (CheckerContext &)>
- CheckEndPathFunc;
+ CheckEndFunctionFunc;
typedef CheckerFn<void (const Stmt *, CheckerContext &)>
CheckBranchConditionFunc;
@@ -393,13 +433,20 @@ public:
typedef CheckerFn<void (ProgramStateRef,SymbolReaper &)> CheckLiveSymbolsFunc;
typedef CheckerFn<ProgramStateRef (ProgramStateRef,
- const StoreManager::InvalidatedSymbols *symbols,
+ const InvalidatedSymbols *symbols,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
const CallEvent *Call)>
CheckRegionChangesFunc;
typedef CheckerFn<bool (ProgramStateRef)> WantsRegionChangeUpdateFunc;
+
+ typedef CheckerFn<ProgramStateRef (ProgramStateRef,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind,
+ bool IsConst)>
+ CheckPointerEscapeFunc;
typedef CheckerFn<ProgramStateRef (ProgramStateRef,
const SVal &cond, bool assumption)>
@@ -430,7 +477,7 @@ public:
void _registerForEndAnalysis(CheckEndAnalysisFunc checkfn);
- void _registerForEndPath(CheckEndPathFunc checkfn);
+ void _registerForEndFunction(CheckEndFunctionFunc checkfn);
void _registerForBranchCondition(CheckBranchConditionFunc checkfn);
@@ -441,6 +488,10 @@ public:
void _registerForRegionChanges(CheckRegionChangesFunc checkfn,
WantsRegionChangeUpdateFunc wantUpdateFn);
+ void _registerForPointerEscape(CheckPointerEscapeFunc checkfn);
+
+ void _registerForConstPointerEscape(CheckPointerEscapeFunc checkfn);
+
void _registerForEvalAssume(EvalAssumeFunc checkfn);
void _registerForEvalCall(EvalCallFunc checkfn);
@@ -552,7 +603,7 @@ private:
std::vector<CheckEndAnalysisFunc> EndAnalysisCheckers;
- std::vector<CheckEndPathFunc> EndPathCheckers;
+ std::vector<CheckEndFunctionFunc> EndFunctionCheckers;
std::vector<CheckBranchConditionFunc> BranchConditionCheckers;
@@ -566,6 +617,8 @@ private:
};
std::vector<RegionChangesCheckerInfo> RegionChangesCheckers;
+ std::vector<CheckPointerEscapeFunc> PointerEscapeCheckers;
+
std::vector<EvalAssumeFunc> EvalAssumeCheckers;
std::vector<EvalCallFunc> EvalCallCheckers;
diff --git a/include/clang/StaticAnalyzer/Core/CheckerOptInfo.h b/include/clang/StaticAnalyzer/Core/CheckerOptInfo.h
index 6ce5b3c..e981871 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerOptInfo.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerOptInfo.h
@@ -11,6 +11,7 @@
#define LLVM_CLANG_STATICANALYZER_CORE_CHECKEROPTINFO_H
#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/StringRef.h"
namespace clang {
namespace ento {
diff --git a/include/clang/StaticAnalyzer/Core/CheckerRegistry.h b/include/clang/StaticAnalyzer/Core/CheckerRegistry.h
index 1452d45..4557aa4 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerRegistry.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerRegistry.h
@@ -10,8 +10,8 @@
#ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRY_H
#define LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRY_H
-#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/Basic/LLVM.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include <vector>
// FIXME: move this information to an HTML file in docs/.
diff --git a/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h b/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
index 3aab648..b856de7 100644
--- a/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
+++ b/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h
@@ -19,6 +19,7 @@
namespace clang {
+class AnalyzerOptions;
class Preprocessor;
namespace ento {
@@ -26,21 +27,18 @@ namespace ento {
class PathDiagnosticConsumer;
typedef std::vector<PathDiagnosticConsumer*> PathDiagnosticConsumers;
-void createHTMLDiagnosticConsumer(PathDiagnosticConsumers &C,
- const std::string& prefix,
- const Preprocessor &PP);
+#define CREATE_CONSUMER(NAME)\
+void create ## NAME ## DiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,\
+ PathDiagnosticConsumers &C,\
+ const std::string& prefix,\
+ const Preprocessor &PP);
-void createPlistDiagnosticConsumer(PathDiagnosticConsumers &C,
- const std::string& prefix,
- const Preprocessor &PP);
+CREATE_CONSUMER(HTML)
+CREATE_CONSUMER(Plist)
+CREATE_CONSUMER(PlistMultiFile)
+CREATE_CONSUMER(TextPath)
-void createPlistMultiFileDiagnosticConsumer(PathDiagnosticConsumers &C,
- const std::string& prefix,
- const Preprocessor &PP);
-
-void createTextPathDiagnosticConsumer(PathDiagnosticConsumers &C,
- const std::string& prefix,
- const Preprocessor &PP);
+#undef CREATE_CONSUMER
} // end 'ento' namespace
} // end 'clang' namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h b/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h
index 27f3677..9502900 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h
@@ -81,9 +81,12 @@ public:
/// Tests whether a given value is losslessly representable using this type.
///
- /// Note that signedness conversions will be rejected, even with the same bit
- /// pattern. For example, -1s8 is not in range for 'unsigned char' (u8).
- RangeTestResultKind testInRange(const llvm::APSInt &Val) const LLVM_READONLY;
+ /// \param Val The value to test.
+ /// \param AllowMixedSign Whether or not to allow signedness conversions.
+ /// This determines whether -1s8 is considered in range
+ /// for 'unsigned char' (u8).
+ RangeTestResultKind testInRange(const llvm::APSInt &Val,
+ bool AllowMixedSign) const LLVM_READONLY;
bool operator==(const APSIntType &Other) const {
return BitWidth == Other.BitWidth && IsUnsigned == Other.IsUnsigned;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
index 9038ae5..458c896 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h
@@ -100,7 +100,7 @@ public:
}
bool shouldInlineCall() const {
- return options.IPAMode != None;
+ return options.getIPAMode() != IPAK_None;
}
CFG *getCFG(Decl const *D) {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
index fb39354..1135b51 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h
@@ -16,9 +16,10 @@
#ifndef LLVM_CLANG_GR_BASICVALUEFACTORY_H
#define LLVM_CLANG_GR_BASICVALUEFACTORY_H
+#include "clang/AST/ASTContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
namespace clang {
namespace ento {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index a6a91e2..f990b8d 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -16,11 +16,11 @@
#ifndef LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_CALL
#define LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_CALL
-#include "clang/Basic/SourceManager.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/ADT/PointerIntPair.h"
@@ -162,11 +162,11 @@ protected:
}
- typedef SmallVectorImpl<const MemRegion *> RegionList;
+ typedef SmallVectorImpl<SVal> ValueList;
/// \brief Used to specify non-argument regions that will be invalidated as a
/// result of this call.
- virtual void getExtraInvalidatedRegions(RegionList &Regions) const {}
+ virtual void getExtraInvalidatedValues(ValueList &Values) const {}
public:
virtual ~CallEvent() {}
@@ -181,7 +181,7 @@ public:
}
/// \brief The state in which the call is being evaluated.
- ProgramStateRef getState() const {
+ const ProgramStateRef &getState() const {
return State;
}
@@ -228,6 +228,11 @@ public:
return false;
}
+ /// \brief Returns true if this is a call to a variadic function or method.
+ virtual bool isVariadic() const {
+ return false;
+ }
+
/// \brief Returns a source range for the entire call, suitable for
/// outputting in diagnostics.
virtual SourceRange getSourceRange() const {
@@ -331,7 +336,9 @@ public:
/// of some kind.
static bool isCallStmt(const Stmt *S);
- /// \brief Returns the result type of a function, method declaration.
+ /// \brief Returns the result type of a function or method declaration.
+ ///
+ /// This will return a null QualType if the result type cannot be determined.
static QualType getDeclaredResultType(const Decl *D);
// Iterator access to formal parameters and their types.
@@ -416,6 +423,10 @@ public:
return RuntimeDefinition();
}
+ virtual bool isVariadic() const {
+ return getDecl()->isVariadic();
+ }
+
virtual bool argumentsMayEscape() const;
virtual void getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
@@ -493,7 +504,7 @@ protected:
BlockCall(const BlockCall &Other) : SimpleCall(Other) {}
virtual void cloneTo(void *Dest) const { new (Dest) BlockCall(*this); }
- virtual void getExtraInvalidatedRegions(RegionList &Regions) const;
+ virtual void getExtraInvalidatedValues(ValueList &Values) const;
public:
/// \brief Returns the region associated with this instance of the block.
@@ -516,6 +527,10 @@ public:
return RuntimeDefinition(getBlockDecl());
}
+ virtual bool isVariadic() const {
+ return getBlockDecl()->isVariadic();
+ }
+
virtual void getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
BindingsTy &Bindings) const;
@@ -533,7 +548,7 @@ public:
/// it is written.
class CXXInstanceCall : public AnyFunctionCall {
protected:
- virtual void getExtraInvalidatedRegions(RegionList &Regions) const;
+ virtual void getExtraInvalidatedValues(ValueList &Values) const;
CXXInstanceCall(const CallExpr *CE, ProgramStateRef St,
const LocationContext *LCtx)
@@ -716,7 +731,7 @@ protected:
CXXConstructorCall(const CXXConstructorCall &Other) : AnyFunctionCall(Other){}
virtual void cloneTo(void *Dest) const { new (Dest) CXXConstructorCall(*this); }
- virtual void getExtraInvalidatedRegions(RegionList &Regions) const;
+ virtual void getExtraInvalidatedValues(ValueList &Values) const;
public:
virtual const CXXConstructExpr *getOriginExpr() const {
@@ -815,7 +830,7 @@ protected:
ObjCMethodCall(const ObjCMethodCall &Other) : CallEvent(Other) {}
virtual void cloneTo(void *Dest) const { new (Dest) ObjCMethodCall(*this); }
- virtual void getExtraInvalidatedRegions(RegionList &Regions) const;
+ virtual void getExtraInvalidatedValues(ValueList &Values) const;
/// Check if the selector may have multiple definitions (may have overrides).
virtual bool canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl,
@@ -834,6 +849,9 @@ public:
virtual const Expr *getArgExpr(unsigned Index) const {
return getOriginExpr()->getArg(Index);
}
+ virtual bool isVariadic() const {
+ return getDecl()->isVariadic();
+ }
bool isInstanceMessage() const {
return getOriginExpr()->isInstanceMessage();
@@ -1024,7 +1042,7 @@ namespace llvm {
typedef const T *SimpleType;
static SimpleType
- getSimplifiedValue(const clang::ento::CallEventRef<T>& Val) {
+ getSimplifiedValue(clang::ento::CallEventRef<T> Val) {
return Val.getPtr();
}
};
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
index 4558cd9..cda1366 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
@@ -119,7 +119,7 @@ public:
/// the state of the program before the checker ran. Note, checkers should
/// not retain the node in their state since the nodes might get invalidated.
ExplodedNode *getPredecessor() { return Pred; }
- ProgramStateRef getState() const { return Pred->getState(); }
+ const ProgramStateRef &getState() const { return Pred->getState(); }
/// \brief Check if the checker changed the state of the execution; ex: added
/// a new transition or a bug report.
@@ -185,7 +185,7 @@ public:
/// example, for finding variables that the given symbol was assigned to.
static const MemRegion *getLocationRegionIfPostStore(const ExplodedNode *N) {
ProgramPoint L = N->getLocation();
- if (const PostStore *PSL = dyn_cast<PostStore>(&L))
+ if (Optional<PostStore> PSL = L.getAs<PostStore>())
return reinterpret_cast<const MemRegion*>(PSL->getLocationValue());
return 0;
}
@@ -303,14 +303,6 @@ private:
}
};
-/// \brief A helper class which wraps a boolean value set to false by default.
-struct DefaultBool {
- bool Val;
- DefaultBool() : Val(false) {}
- operator bool() const { return Val; }
- DefaultBool &operator=(bool b) { Val = b; return *this; }
-};
-
} // end GR namespace
} // end clang namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
index 4a78849..1e76ea6 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
@@ -14,8 +14,8 @@
#ifndef LLVM_CLANG_GR_CONSTRAINT_MANAGER_H
#define LLVM_CLANG_GR_CONSTRAINT_MANAGER_H
-#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
#include "llvm/Support/SaveAndRestore.h"
namespace llvm {
@@ -28,7 +28,7 @@ namespace ento {
class SubEngine;
class ConditionTruthVal {
- llvm::Optional<bool> Val;
+ Optional<bool> Val;
public:
/// Construct a ConditionTruthVal indicating the constraint is constrained
/// to either true or false, depending on the boolean value provided.
@@ -78,9 +78,13 @@ public:
// If StTrue is infeasible, asserting the falseness of Cond is unnecessary
// because the existing constraints already establish this.
if (!StTrue) {
- // FIXME: This is fairly expensive and should be disabled even in
- // Release+Asserts builds.
+#ifndef __OPTIMIZE__
+ // This check is expensive and should be disabled even in Release+Asserts
+ // builds.
+ // FIXME: __OPTIMIZE__ is a GNU extension that Clang implements but MSVC
+ // does not. Is there a good equivalent there?
assert(assume(State, Cond, false) && "System is over constrained.");
+#endif
return ProgramStatePair((ProgramStateRef)NULL, State);
}
@@ -118,7 +122,7 @@ public:
/// Convenience method to query the state to see if a symbol is null or
/// not null, or if neither assumption can be made.
ConditionTruthVal isNull(ProgramStateRef State, SymbolRef Sym) {
- llvm::SaveAndRestore<bool> DisableNotify(NotifyAssumeClients, false);
+ SaveAndRestore<bool> DisableNotify(NotifyAssumeClients, false);
return checkNull(State, Sym);
}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
index b668640..a2e211e 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
@@ -17,10 +17,10 @@
#include "clang/AST/Expr.h"
#include "clang/Analysis/AnalysisContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h"
#include "llvm/ADT/OwningPtr.h"
namespace clang {
@@ -96,6 +96,10 @@ private:
void HandleBranch(const Stmt *Cond, const Stmt *Term, const CFGBlock *B,
ExplodedNode *Pred);
+ /// Handle conditional logic for running static initializers.
+ void HandleStaticInit(const DeclStmt *DS, const CFGBlock *B,
+ ExplodedNode *Pred);
+
private:
CoreEngine(const CoreEngine &) LLVM_DELETED_FUNCTION;
void operator=(const CoreEngine &) LLVM_DELETED_FUNCTION;
@@ -463,7 +467,7 @@ public:
bool operator!=(const iterator &X) const { return I != X.I; }
const LabelDecl *getLabel() const {
- return llvm::cast<LabelStmt>((*I)->getLabel())->getDecl();
+ return cast<LabelStmt>((*I)->getLabel())->getDecl();
}
const CFGBlock *getBlock() const {
@@ -510,7 +514,7 @@ public:
bool operator==(const iterator &X) const { return I == X.I; }
const CaseStmt *getCase() const {
- return llvm::cast<CaseStmt>((*I)->getLabel());
+ return cast<CaseStmt>((*I)->getLabel());
}
const CFGBlock *getBlock() const {
@@ -522,7 +526,7 @@ public:
iterator end() { return iterator(Src->succ_rend()); }
const SwitchStmt *getSwitch() const {
- return llvm::cast<SwitchStmt>(Src->getTerminator());
+ return cast<SwitchStmt>(Src->getTerminator());
}
ExplodedNode *generateCaseStmtNode(const iterator &I,
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
index eb9bd85..f3a582d 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h
@@ -33,9 +33,6 @@ class SValBuilder;
/// other things.
class EnvironmentEntry : public std::pair<const Stmt*,
const StackFrameContext *> {
- friend class EnvironmentManager;
- EnvironmentEntry makeLocation() const;
-
public:
EnvironmentEntry(const Stmt *s, const LocationContext *L);
@@ -118,13 +115,6 @@ public:
/// Bind a symbolic value to the given environment entry.
Environment bindExpr(Environment Env, const EnvironmentEntry &E, SVal V,
bool Invalidate);
-
- /// Bind the location 'location' and value 'V' to the specified
- /// environment entry.
- Environment bindExprAndLocation(Environment Env,
- const EnvironmentEntry &E,
- SVal location,
- SVal V);
Environment removeDeadBindings(Environment Env,
SymbolReaper &SymReaper,
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
index b112e66..5211916 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h
@@ -19,19 +19,19 @@
#ifndef LLVM_CLANG_GR_EXPLODEDGRAPH
#define LLVM_CLANG_GR_EXPLODEDGRAPH
-#include "clang/Analysis/ProgramPoint.h"
-#include "clang/Analysis/AnalysisContext.h"
#include "clang/AST/Decl.h"
-#include "llvm/ADT/SmallVector.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/ProgramPoint.h"
+#include "clang/Analysis/Support/BumpVector.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/GraphTraits.h"
+#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Allocator.h"
-#include "llvm/ADT/OwningPtr.h"
-#include "llvm/ADT/GraphTraits.h"
-#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/Support/Casting.h"
-#include "clang/Analysis/Support/BumpVector.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include <vector>
namespace clang {
@@ -152,10 +152,12 @@ public:
return *getLocationContext()->getAnalysis<T>();
}
- ProgramStateRef getState() const { return State; }
+ const ProgramStateRef &getState() const { return State; }
template <typename T>
- const T* getLocationAs() const { return llvm::dyn_cast<T>(&Location); }
+ Optional<T> getLocationAs() const LLVM_LVALUE_FUNCTION {
+ return Location.getAs<T>();
+ }
static void Profile(llvm::FoldingSetNodeID &ID,
const ProgramPoint &Loc,
@@ -167,7 +169,8 @@ public:
}
void Profile(llvm::FoldingSetNodeID& ID) const {
- Profile(ID, getLocation(), getState(), isSink());
+ // We avoid copy constructors by not using accessors.
+ Profile(ID, Location, State, isSink());
}
/// addPredeccessor - Adds a predecessor to the current node, and
@@ -236,18 +239,8 @@ private:
void replacePredecessor(ExplodedNode *node) { Preds.replaceNode(node); }
};
-// FIXME: Is this class necessary?
-class InterExplodedGraphMap {
- virtual void anchor();
- llvm::DenseMap<const ExplodedNode*, ExplodedNode*> M;
- friend class ExplodedGraph;
-
-public:
- ExplodedNode *getMappedNode(const ExplodedNode *N) const;
-
- InterExplodedGraphMap() {}
- virtual ~InterExplodedGraphMap() {}
-};
+typedef llvm::DenseMap<const ExplodedNode *, const ExplodedNode *>
+ InterExplodedGraphMap;
class ExplodedGraph {
protected:
@@ -365,14 +358,19 @@ public:
typedef llvm::DenseMap<const ExplodedNode*, ExplodedNode*> NodeMap;
- std::pair<ExplodedGraph*, InterExplodedGraphMap*>
- Trim(const NodeTy* const* NBeg, const NodeTy* const* NEnd,
- llvm::DenseMap<const void*, const void*> *InverseMap = 0) const;
-
- ExplodedGraph* TrimInternal(const ExplodedNode* const * NBeg,
- const ExplodedNode* const * NEnd,
- InterExplodedGraphMap *M,
- llvm::DenseMap<const void*, const void*> *InverseMap) const;
+ /// Creates a trimmed version of the graph that only contains paths leading
+ /// to the given nodes.
+ ///
+ /// \param Nodes The nodes which must appear in the final graph. Presumably
+ /// these are end-of-path nodes (i.e. they have no successors).
+ /// \param[out] ForwardMap A optional map from nodes in this graph to nodes in
+ /// the returned graph.
+ /// \param[out] InverseMap An optional map from nodes in the returned graph to
+ /// nodes in this graph.
+ /// \returns The trimmed graph
+ ExplodedGraph *trim(ArrayRef<const NodeTy *> Nodes,
+ InterExplodedGraphMap *ForwardMap = 0,
+ InterExplodedGraphMap *InverseMap = 0) const;
/// Enable tracking of recently allocated nodes for potential reclamation
/// when calling reclaimRecentlyAllocatedNodes().
@@ -384,6 +382,10 @@ public:
/// was called.
void reclaimRecentlyAllocatedNodes();
+ /// \brief Returns true if nodes for the given expression kind are always
+ /// kept around.
+ static bool isInterestingLValueExpr(const Expr *Ex);
+
private:
bool shouldCollect(const ExplodedNode *node);
void collectNode(ExplodedNode *node);
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 78b2542..33e4431 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -16,15 +16,15 @@
#ifndef LLVM_CLANG_GR_EXPRENGINE
#define LLVM_CLANG_GR_EXPRENGINE
+#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
#include "clang/Analysis/DomainSpecific/ObjCNoReturn.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/Type.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h"
namespace clang {
@@ -44,8 +44,19 @@ namespace ento {
class AnalysisManager;
class CallEvent;
class SimpleCall;
+class CXXConstructorCall;
class ExprEngine : public SubEngine {
+public:
+ /// The modes of inlining, which override the default analysis-wide settings.
+ enum InliningModes {
+ /// Follow the default settings for inlining callees.
+ Inline_Regular = 0,
+ /// Do minimal inlining of callees.
+ Inline_Minimal = 0x1
+ };
+
+private:
AnalysisManager &AMgr;
AnalysisDeclContextManager &AnalysisDeclContexts;
@@ -64,15 +75,6 @@ class ExprEngine : public SubEngine {
/// svalBuilder - SValBuilder object that creates SVals from expressions.
SValBuilder &svalBuilder;
- /// EntryNode - The immediate predecessor node.
- ExplodedNode *EntryNode;
-
- /// CleanedState - The state for EntryNode "cleaned" of all dead
- /// variables and symbols (as determined by a liveness analysis).
- ProgramStateRef CleanedState;
-
- /// currStmt - The current block-level statement.
- const Stmt *currStmt;
unsigned int currStmtIdx;
const NodeBuilderContext *currBldrCtx;
@@ -92,10 +94,14 @@ class ExprEngine : public SubEngine {
/// AnalysisConsumer. It can be null.
SetOfConstDecls *VisitedCallees;
+ /// The flag, which specifies the mode of inlining for the engine.
+ InliningModes HowToInline;
+
public:
ExprEngine(AnalysisManager &mgr, bool gcEnabled,
SetOfConstDecls *VisitedCalleesIn,
- FunctionSummariesTy *FS);
+ FunctionSummariesTy *FS,
+ InliningModes HowToInlineIn);
~ExprEngine();
@@ -140,11 +146,12 @@ public:
void enqueueEndOfPath(ExplodedNodeSet &S);
void GenerateCallExitNode(ExplodedNode *N);
- /// ViewGraph - Visualize the ExplodedGraph created by executing the
- /// simulation.
+ /// Visualize the ExplodedGraph created by executing the simulation.
void ViewGraph(bool trim = false);
- void ViewGraph(ExplodedNode** Beg, ExplodedNode** End);
+ /// Visualize a trimmed ExplodedGraph that only contains paths to the given
+ /// nodes.
+ void ViewGraph(ArrayRef<const ExplodedNode*> Nodes);
/// getInitialState - Return the initial state used for the root vertex
/// in the ExplodedGraph.
@@ -154,26 +161,33 @@ public:
const ExplodedGraph& getGraph() const { return G; }
/// \brief Run the analyzer's garbage collection - remove dead symbols and
- /// bindings.
+ /// bindings from the state.
///
- /// \param Node - The predecessor node, from which the processing should
- /// start.
- /// \param Out - The returned set of output nodes.
- /// \param ReferenceStmt - Run garbage collection using the symbols,
- /// which are live before the given statement.
- /// \param LC - The location context of the ReferenceStmt.
- /// \param DiagnosticStmt - the statement used to associate the diagnostic
- /// message, if any warnings should occur while removing the dead (leaks
- /// are usually reported here).
- /// \param K - In some cases it is possible to use PreStmt kind. (Do
- /// not use it unless you know what you are doing.)
- /// If the ReferenceStmt is NULL, everything is this and parent contexts is
- /// considered live.
- /// If the stack frame context is NULL, everything on stack is considered
- /// dead.
+ /// Checkers can participate in this process with two callbacks:
+ /// \c checkLiveSymbols and \c checkDeadSymbols. See the CheckerDocumentation
+ /// class for more information.
+ ///
+ /// \param Node The predecessor node, from which the processing should start.
+ /// \param Out The returned set of output nodes.
+ /// \param ReferenceStmt The statement which is about to be processed.
+ /// Everything needed for this statement should be considered live.
+ /// A null statement means that everything in child LocationContexts
+ /// is dead.
+ /// \param LC The location context of the \p ReferenceStmt. A null location
+ /// context means that we have reached the end of analysis and that
+ /// all statements and local variables should be considered dead.
+ /// \param DiagnosticStmt Used as a location for any warnings that should
+ /// occur while removing the dead (e.g. leaks). By default, the
+ /// \p ReferenceStmt is used.
+ /// \param K Denotes whether this is a pre- or post-statement purge. This
+ /// must only be ProgramPoint::PostStmtPurgeDeadSymbolsKind if an
+ /// entire location context is being cleared, in which case the
+ /// \p ReferenceStmt must either be a ReturnStmt or \c NULL. Otherwise,
+ /// it must be ProgramPoint::PreStmtPurgeDeadSymbolsKind (the default)
+ /// and \p ReferenceStmt must be valid (non-null).
void removeDead(ExplodedNode *Node, ExplodedNodeSet &Out,
- const Stmt *ReferenceStmt, const StackFrameContext *LC,
- const Stmt *DiagnosticStmt,
+ const Stmt *ReferenceStmt, const LocationContext *LC,
+ const Stmt *DiagnosticStmt = 0,
ProgramPoint::Kind K = ProgramPoint::PreStmtPurgeDeadSymbolsKind);
/// processCFGElement - Called by CoreEngine. Used to generate new successor
@@ -210,6 +224,15 @@ public:
const CFGBlock *DstT,
const CFGBlock *DstF);
+ /// Called by CoreEngine. Used to processing branching behavior
+ /// at static initalizers.
+ void processStaticInitializer(const DeclStmt *DS,
+ NodeBuilderContext& BuilderCtx,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst,
+ const CFGBlock *DstT,
+ const CFGBlock *DstF);
+
/// processIndirectGoto - Called by CoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a computed goto jump.
void processIndirectGoto(IndirectGotoNodeBuilder& builder);
@@ -218,8 +241,8 @@ public:
/// nodes by processing the 'effects' of a switch statement.
void processSwitch(SwitchNodeBuilder& builder);
- /// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path
- /// nodes when the control reaches the end of a function.
+ /// Called by CoreEngine. Used to generate end-of-path
+ /// nodes when the control reaches the end of a function.
void processEndOfFunction(NodeBuilderContext& BC,
ExplodedNode *Pred);
@@ -250,7 +273,7 @@ public:
/// to the store. Used to update checkers that track region values.
ProgramStateRef
processRegionChanges(ProgramStateRef state,
- const StoreManager::InvalidatedSymbols *invalidated,
+ const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
const CallEvent *Call);
@@ -416,11 +439,11 @@ public:
geteagerlyAssumeBinOpBifurcationTags();
SVal evalMinus(SVal X) {
- return X.isValid() ? svalBuilder.evalMinus(cast<NonLoc>(X)) : X;
+ return X.isValid() ? svalBuilder.evalMinus(X.castAs<NonLoc>()) : X;
}
SVal evalComplement(SVal X) {
- return X.isValid() ? svalBuilder.evalComplement(cast<NonLoc>(X)) : X;
+ return X.isValid() ? svalBuilder.evalComplement(X.castAs<NonLoc>()) : X;
}
public:
@@ -432,7 +455,8 @@ public:
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op,
NonLoc L, SVal R, QualType T) {
- return R.isValid() ? svalBuilder.evalBinOpNN(state,op,L, cast<NonLoc>(R), T) : R;
+ return R.isValid() ? svalBuilder.evalBinOpNN(state, op, L,
+ R.castAs<NonLoc>(), T) : R;
}
SVal evalBinOp(ProgramStateRef ST, BinaryOperator::Opcode Op,
@@ -447,6 +471,20 @@ protected:
SVal location, SVal Val, bool atDeclInit = false,
const ProgramPoint *PP = 0);
+ /// Call PointerEscape callback when a value escapes as a result of bind.
+ ProgramStateRef processPointerEscapedOnBind(ProgramStateRef State,
+ SVal Loc, SVal Val);
+ /// Call PointerEscape callback when a value escapes as a result of
+ /// region invalidation.
+ /// \param[in] IsConst Specifies that the pointer is const.
+ ProgramStateRef notifyCheckersOfPointerEscape(
+ ProgramStateRef State,
+ const InvalidatedSymbols *Invalidated,
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions,
+ const CallEvent *Call,
+ bool IsConst);
+
public:
// FIXME: 'tag' should be removed, and a LocationContext should be used
// instead.
@@ -506,7 +544,10 @@ private:
void examineStackFrames(const Decl *D, const LocationContext *LCtx,
bool &IsRecursive, unsigned &StackDepth);
- bool shouldInlineDecl(const Decl *D, ExplodedNode *Pred);
+ /// Checks our policies and decides weither the given call should be inlined.
+ bool shouldInlineCall(const CallEvent &Call, const Decl *D,
+ const ExplodedNode *Pred);
+
bool inlineCall(const CallEvent &Call, const Decl *D, NodeBuilder &Bldr,
ExplodedNode *Pred, ProgramStateRef State);
@@ -522,6 +563,22 @@ private:
ExplodedNode *Pred);
bool replayWithoutInlining(ExplodedNode *P, const LocationContext *CalleeLC);
+
+ /// Models a trivial copy or move constructor or trivial assignment operator
+ /// call with a simple bind.
+ void performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred,
+ const CallEvent &Call);
+
+ /// If the value of the given expression is a NonLoc, copy it into a new
+ /// temporary object region, and replace the value of the expression with
+ /// that.
+ ///
+ /// If \p ResultE is provided, the new region will be bound to this expression
+ /// instead of \p E.
+ ProgramStateRef createTemporaryRegionIfNeeded(ProgramStateRef State,
+ const LocationContext *LC,
+ const Expr *E,
+ const Expr *ResultE = 0);
};
/// Traits for storing the call processing policy inside GDM.
@@ -531,7 +588,7 @@ private:
struct ReplayWithoutInlining{};
template <>
struct ProgramStateTrait<ReplayWithoutInlining> :
- public ProgramStatePartialTrait<void*> {
+ public ProgramStatePartialTrait<const void*> {
static void *GDMIndex() { static int index = 0; return &index; }
};
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h b/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
index cf4a692..169af93 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h
@@ -7,94 +7,126 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines a summary of a function gathered/used by static analyzes.
+// This file defines a summary of a function gathered/used by static analysis.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GR_FUNCTIONSUMMARY_H
#define LLVM_CLANG_GR_FUNCTIONSUMMARY_H
-#include <deque>
-#include "clang/AST/Decl.h"
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallBitVector.h"
+#include <deque>
namespace clang {
+class Decl;
+
namespace ento {
typedef std::deque<Decl*> SetOfDecls;
typedef llvm::DenseSet<const Decl*> SetOfConstDecls;
class FunctionSummariesTy {
- struct FunctionSummary {
- /// True if this function has reached a max block count while inlined from
- /// at least one call site.
- bool MayReachMaxBlockCount;
+ class FunctionSummary {
+ public:
+ /// Marks the IDs of the basic blocks visited during the analyzes.
+ llvm::SmallBitVector VisitedBasicBlocks;
/// Total number of blocks in the function.
- unsigned TotalBasicBlocks;
+ unsigned TotalBasicBlocks : 30;
- /// Marks the IDs of the basic blocks visited during the analyzes.
- llvm::BitVector VisitedBasicBlocks;
+ /// True if this function has been checked against the rules for which
+ /// functions may be inlined.
+ unsigned InlineChecked : 1;
+
+ /// True if this function may be inlined.
+ unsigned MayInline : 1;
+
+ /// The number of times the function has been inlined.
+ unsigned TimesInlined : 32;
FunctionSummary() :
- MayReachMaxBlockCount(false),
TotalBasicBlocks(0),
- VisitedBasicBlocks(0) {}
+ InlineChecked(0),
+ TimesInlined(0) {}
};
- typedef llvm::DenseMap<const Decl*, FunctionSummary*> MapTy;
+ typedef llvm::DenseMap<const Decl *, FunctionSummary> MapTy;
MapTy Map;
public:
- ~FunctionSummariesTy();
-
MapTy::iterator findOrInsertSummary(const Decl *D) {
MapTy::iterator I = Map.find(D);
if (I != Map.end())
return I;
- FunctionSummary *DS = new FunctionSummary();
- I = Map.insert(std::pair<const Decl*, FunctionSummary*>(D, DS)).first;
+
+ typedef std::pair<const Decl *, FunctionSummary> KVPair;
+ I = Map.insert(KVPair(D, FunctionSummary())).first;
assert(I != Map.end());
return I;
}
- void markReachedMaxBlockCount(const Decl* D) {
+ void markMayInline(const Decl *D) {
MapTy::iterator I = findOrInsertSummary(D);
- I->second->MayReachMaxBlockCount = true;
+ I->second.InlineChecked = 1;
+ I->second.MayInline = 1;
}
- bool hasReachedMaxBlockCount(const Decl* D) {
- MapTy::const_iterator I = Map.find(D);
- if (I != Map.end())
- return I->second->MayReachMaxBlockCount;
- return false;
+ void markShouldNotInline(const Decl *D) {
+ MapTy::iterator I = findOrInsertSummary(D);
+ I->second.InlineChecked = 1;
+ I->second.MayInline = 0;
+ }
+
+ void markReachedMaxBlockCount(const Decl *D) {
+ markShouldNotInline(D);
+ }
+
+ Optional<bool> mayInline(const Decl *D) {
+ MapTy::const_iterator I = Map.find(D);
+ if (I != Map.end() && I->second.InlineChecked)
+ return I->second.MayInline;
+ return None;
}
void markVisitedBasicBlock(unsigned ID, const Decl* D, unsigned TotalIDs) {
MapTy::iterator I = findOrInsertSummary(D);
- llvm::BitVector &Blocks = I->second->VisitedBasicBlocks;
+ llvm::SmallBitVector &Blocks = I->second.VisitedBasicBlocks;
assert(ID < TotalIDs);
if (TotalIDs > Blocks.size()) {
Blocks.resize(TotalIDs);
- I->second->TotalBasicBlocks = TotalIDs;
+ I->second.TotalBasicBlocks = TotalIDs;
}
- Blocks[ID] = true;
+ Blocks.set(ID);
}
unsigned getNumVisitedBasicBlocks(const Decl* D) {
MapTy::const_iterator I = Map.find(D);
- if (I != Map.end())
- return I->second->VisitedBasicBlocks.count();
+ if (I != Map.end())
+ return I->second.VisitedBasicBlocks.count();
return 0;
}
+ unsigned getNumTimesInlined(const Decl* D) {
+ MapTy::const_iterator I = Map.find(D);
+ if (I != Map.end())
+ return I->second.TimesInlined;
+ return 0;
+ }
+
+ void bumpNumTimesInlined(const Decl* D) {
+ MapTy::iterator I = findOrInsertSummary(D);
+ I->second.TimesInlined++;
+ }
+
/// Get the percentage of the reachable blocks.
unsigned getPercentBlocksReachable(const Decl *D) {
MapTy::const_iterator I = Map.find(D);
if (I != Map.end())
- return ((I->second->VisitedBasicBlocks.count() * 100) /
- I->second->TotalBasicBlocks);
+ return ((I->second.VisitedBasicBlocks.count() * 100) /
+ I->second.TotalBasicBlocks);
return 0;
}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
index 34fbc3c..af2f365 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h
@@ -22,8 +22,8 @@
#include "clang/AST/ExprObjC.h"
#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
-#include "llvm/Support/ErrorHandling.h"
#include "llvm/ADT/FoldingSet.h"
+#include "llvm/Support/ErrorHandling.h"
#include <string>
namespace llvm {
@@ -642,26 +642,20 @@ public:
explicit referenced_vars_iterator(const MemRegion * const *r,
const MemRegion * const *originalR)
: R(r), OriginalR(originalR) {}
-
- operator const MemRegion * const *() const {
- return R;
- }
-
- const MemRegion *getCapturedRegion() const {
- return *R;
- }
- const MemRegion *getOriginalRegion() const {
- return *OriginalR;
- }
- const VarRegion* operator*() const {
+ const VarRegion *getCapturedRegion() const {
return cast<VarRegion>(*R);
}
-
+ const VarRegion *getOriginalRegion() const {
+ return cast<VarRegion>(*OriginalR);
+ }
+
bool operator==(const referenced_vars_iterator &I) const {
+ assert((R == 0) == (I.R == 0));
return I.R == R;
}
bool operator!=(const referenced_vars_iterator &I) const {
+ assert((R == 0) == (I.R == 0));
return I.R != R;
}
referenced_vars_iterator &operator++() {
@@ -670,6 +664,10 @@ public:
return *this;
}
};
+
+ /// Return the original region for a captured region, if
+ /// one exists.
+ const VarRegion *getOriginalRegion(const VarRegion *VR) const;
referenced_vars_iterator referenced_vars_begin() const;
referenced_vars_iterator referenced_vars_end() const;
@@ -686,6 +684,8 @@ public:
}
private:
void LazyInitializeReferencedVars();
+ std::pair<const VarRegion *, const VarRegion *>
+ getCaptureRegions(const VarDecl *VD);
};
/// SymbolicRegion - A special, "non-concrete" region. Unlike other region
@@ -952,6 +952,9 @@ public:
const ObjCIvarDecl *getDecl() const;
QualType getValueType() const;
+ bool canPrintPretty() const;
+ void printPretty(raw_ostream &os) const;
+
void dumpToStream(raw_ostream &os) const;
static bool classof(const MemRegion* R) {
@@ -993,8 +996,8 @@ class ElementRegion : public TypedValueRegion {
ElementRegion(QualType elementType, NonLoc Idx, const MemRegion* sReg)
: TypedValueRegion(sReg, ElementRegionKind),
ElementType(elementType), Index(Idx) {
- assert((!isa<nonloc::ConcreteInt>(&Idx) ||
- cast<nonloc::ConcreteInt>(&Idx)->getValue().isSigned()) &&
+ assert((!Idx.getAs<nonloc::ConcreteInt>() ||
+ Idx.castAs<nonloc::ConcreteInt>().getValue().isSigned()) &&
"The index must be signed");
}
@@ -1057,16 +1060,18 @@ public:
class CXXBaseObjectRegion : public TypedValueRegion {
friend class MemRegionManager;
- const CXXRecordDecl *decl;
+ llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> Data;
- CXXBaseObjectRegion(const CXXRecordDecl *d, const MemRegion *sReg)
- : TypedValueRegion(sReg, CXXBaseObjectRegionKind), decl(d) {}
+ CXXBaseObjectRegion(const CXXRecordDecl *RD, bool IsVirtual,
+ const MemRegion *SReg)
+ : TypedValueRegion(SReg, CXXBaseObjectRegionKind), Data(RD, IsVirtual) {}
- static void ProfileRegion(llvm::FoldingSetNodeID &ID,
- const CXXRecordDecl *decl, const MemRegion *sReg);
+ static void ProfileRegion(llvm::FoldingSetNodeID &ID, const CXXRecordDecl *RD,
+ bool IsVirtual, const MemRegion *SReg);
public:
- const CXXRecordDecl *getDecl() const { return decl; }
+ const CXXRecordDecl *getDecl() const { return Data.getPointer(); }
+ bool isVirtual() const { return Data.getInt(); }
QualType getValueType() const;
@@ -1216,15 +1221,21 @@ public:
const CXXTempObjectRegion *getCXXTempObjectRegion(Expr const *Ex,
LocationContext const *LC);
- const CXXBaseObjectRegion *getCXXBaseObjectRegion(const CXXRecordDecl *decl,
- const MemRegion *superRegion);
+ /// Create a CXXBaseObjectRegion with the given base class for region
+ /// \p Super.
+ ///
+ /// The type of \p Super is assumed be a class deriving from \p BaseClass.
+ const CXXBaseObjectRegion *
+ getCXXBaseObjectRegion(const CXXRecordDecl *BaseClass, const MemRegion *Super,
+ bool IsVirtual);
/// Create a CXXBaseObjectRegion with the same CXXRecordDecl but a different
/// super region.
const CXXBaseObjectRegion *
getCXXBaseObjectRegionWithSuper(const CXXBaseObjectRegion *baseReg,
const MemRegion *superRegion) {
- return getCXXBaseObjectRegion(baseReg->getDecl(), superRegion);
+ return getCXXBaseObjectRegion(baseReg->getDecl(), superRegion,
+ baseReg->isVirtual());
}
const FunctionTextRegion *getFunctionTextRegion(const NamedDecl *FD);
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
index 86c94de..6ea7211 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -18,13 +18,13 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/Environment.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h"
-#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/ADT/PointerIntPair.h"
namespace llvm {
class APSInt;
@@ -170,19 +170,30 @@ public:
// If no new state is feasible, NULL is returned.
//
+ /// Assumes that the value of \p cond is zero (if \p assumption is "false")
+ /// or non-zero (if \p assumption is "true").
+ ///
+ /// This returns a new state with the added constraint on \p cond.
+ /// If no new state is feasible, NULL is returned.
ProgramStateRef assume(DefinedOrUnknownSVal cond, bool assumption) const;
- /// This method assumes both "true" and "false" for 'cond', and
- /// returns both corresponding states. It's shorthand for doing
- /// 'assume' twice.
- std::pair<ProgramStateRef , ProgramStateRef >
+ /// Assumes both "true" and "false" for \p cond, and returns both
+ /// corresponding states (respectively).
+ ///
+ /// This is more efficient than calling assume() twice. Note that one (but not
+ /// both) of the returned states may be NULL.
+ std::pair<ProgramStateRef, ProgramStateRef>
assume(DefinedOrUnknownSVal cond) const;
ProgramStateRef assumeInBound(DefinedOrUnknownSVal idx,
DefinedOrUnknownSVal upperBound,
bool assumption,
QualType IndexType = QualType()) const;
-
+
+ /// \brief Check if the given SVal is constrained to zero or is a zero
+ /// constant.
+ ConditionTruthVal isNull(SVal V) const;
+
/// Utility method for getting regions.
const VarRegion* getRegion(const VarDecl *D, const LocationContext *LC) const;
@@ -203,12 +214,6 @@ public:
ProgramStateRef BindExpr(const Stmt *S, const LocationContext *LCtx,
SVal V, bool Invalidate = true) const;
- /// Create a new state by binding the value 'V' and location 'locaton' to the
- /// statement 'S' in the state's environment.
- ProgramStateRef bindExprAndLocation(const Stmt *S,
- const LocationContext *LCtx,
- SVal location, SVal V) const;
-
ProgramStateRef bindLoc(Loc location,
SVal V,
bool notifyChanges = true) const;
@@ -219,14 +224,38 @@ public:
ProgramStateRef killBinding(Loc LV) const;
- /// invalidateRegions - Returns the state with bindings for the given regions
- /// cleared from the store. The regions are provided as a continuous array
- /// from Begin to End. Optionally invalidates global regions as well.
- ProgramStateRef invalidateRegions(ArrayRef<const MemRegion *> Regions,
- const Expr *E, unsigned BlockCount,
- const LocationContext *LCtx,
- StoreManager::InvalidatedSymbols *IS = 0,
- const CallEvent *Call = 0) const;
+ /// \brief Returns the state with bindings for the given regions
+ /// cleared from the store.
+ ///
+ /// Optionally invalidates global regions as well.
+ ///
+ /// \param Regions the set of regions to be invalidated.
+ /// \param E the expression that caused the invalidation.
+ /// \param BlockCount The number of times the current basic block has been
+ // visited.
+ /// \param CausesPointerEscape the flag is set to true when
+ /// the invalidation entails escape of a symbol (representing a
+ /// pointer). For example, due to it being passed as an argument in a
+ /// call.
+ /// \param IS the set of invalidated symbols.
+ /// \param Call if non-null, the invalidated regions represent parameters to
+ /// the call and should be considered directly invalidated.
+ /// \param ConstRegions the set of regions whose contents are accessible,
+ /// even though the regions themselves should not be invalidated.
+ ProgramStateRef
+ invalidateRegions(ArrayRef<const MemRegion *> Regions, const Expr *E,
+ unsigned BlockCount, const LocationContext *LCtx,
+ bool CausesPointerEscape, InvalidatedSymbols *IS = 0,
+ const CallEvent *Call = 0,
+ ArrayRef<const MemRegion *> ConstRegions =
+ ArrayRef<const MemRegion *>()) const;
+
+ ProgramStateRef
+ invalidateRegions(ArrayRef<SVal> Regions, const Expr *E,
+ unsigned BlockCount, const LocationContext *LCtx,
+ bool CausesPointerEscape, InvalidatedSymbols *IS = 0,
+ const CallEvent *Call = 0,
+ ArrayRef<SVal> ConstRegions = ArrayRef<SVal>()) const;
/// enterStackFrame - Returns the state for entry to the given stack frame,
/// preserving the current state.
@@ -396,13 +425,17 @@ public:
private:
friend void ProgramStateRetain(const ProgramState *state);
friend void ProgramStateRelease(const ProgramState *state);
-
- ProgramStateRef
- invalidateRegionsImpl(ArrayRef<const MemRegion *> Regions,
+
+ /// \sa invalidateValues()
+ /// \sa invalidateRegions()
+ ProgramStateRef
+ invalidateRegionsImpl(ArrayRef<SVal> Values,
const Expr *E, unsigned BlockCount,
const LocationContext *LCtx,
- StoreManager::InvalidatedSymbols &IS,
- const CallEvent *Call) const;
+ bool ResultsInSymbolEscape,
+ InvalidatedSymbols &IS,
+ const CallEvent *Call,
+ ArrayRef<SVal> ConstValues) const;
};
//===----------------------------------------------------------------------===//
@@ -611,22 +644,24 @@ inline ProgramStateRef ProgramState::assume(DefinedOrUnknownSVal Cond,
bool Assumption) const {
if (Cond.isUnknown())
return this;
-
- return getStateManager().ConstraintMgr->assume(this, cast<DefinedSVal>(Cond),
- Assumption);
+
+ return getStateManager().ConstraintMgr
+ ->assume(this, Cond.castAs<DefinedSVal>(), Assumption);
}
inline std::pair<ProgramStateRef , ProgramStateRef >
ProgramState::assume(DefinedOrUnknownSVal Cond) const {
if (Cond.isUnknown())
return std::make_pair(this, this);
-
- return getStateManager().ConstraintMgr->assumeDual(this,
- cast<DefinedSVal>(Cond));
+
+ return getStateManager().ConstraintMgr
+ ->assumeDual(this, Cond.castAs<DefinedSVal>());
}
inline ProgramStateRef ProgramState::bindLoc(SVal LV, SVal V) const {
- return !isa<Loc>(LV) ? this : bindLoc(cast<Loc>(LV), V);
+ if (Optional<Loc> L = LV.getAs<Loc>())
+ return bindLoc(*L, V);
+ return this;
}
inline Loc ProgramState::getLValue(const VarDecl *VD,
@@ -660,7 +695,7 @@ inline SVal ProgramState::getLValue(const IndirectFieldDecl *D,
}
inline SVal ProgramState::getLValue(QualType ElementType, SVal Idx, SVal Base) const{
- if (NonLoc *N = dyn_cast<NonLoc>(&Idx))
+ if (Optional<NonLoc> N = Idx.getAs<NonLoc>())
return getStateManager().StoreMgr->getLValueElement(ElementType, *N, Base);
return UnknownVal();
}
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
index ea2a852..eb52ae4 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h
@@ -18,6 +18,8 @@
#ifndef LLVM_CLANG_GR_PROGRAMSTATETRAIT_H
#define LLVM_CLANG_GR_PROGRAMSTATETRAIT_H
+#include "llvm/Support/DataTypes.h"
+
namespace llvm {
class BumpPtrAllocator;
template <typename K, typename D, typename I> class ImmutableMap;
@@ -165,7 +167,7 @@ namespace ento {
}
static inline void *MakeVoidPtr(data_type D) {
- return (void*) D.getInternalPointer();
+ return const_cast<llvm::ImmutableListImpl<T> *>(D.getInternalPointer());
}
static inline context_type MakeContext(void *p) {
@@ -221,7 +223,20 @@ namespace ento {
}
};
-} // end GR namespace
+ // Partial specialization for const void *.
+ template <> struct ProgramStatePartialTrait<const void *> {
+ typedef const void *data_type;
+
+ static inline data_type MakeData(void * const *p) {
+ return p ? *p : data_type();
+ }
+
+ static inline void *MakeVoidPtr(data_type d) {
+ return const_cast<void *>(d);
+ }
+ };
+
+} // end ento namespace
} // end clang namespace
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
index 5d72e73..f7e49a3 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -17,11 +17,10 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
-#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
namespace clang {
@@ -124,7 +123,7 @@ public:
ProgramStateManager &getStateManager() { return StateMgr; }
QualType getConditionType() const {
- return getContext().IntTy;
+ return Context.getLangOpts().CPlusPlus ? Context.BoolTy : Context.IntTy;
}
QualType getArrayIndexType() const {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
index c2134cf..1c5519e 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
@@ -16,8 +16,8 @@
#define LLVM_CLANG_GR_RVALUE_H
#include "clang/Basic/LLVM.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
#include "llvm/ADT/ImmutableList.h"
//==------------------------------------------------------------------------==//
@@ -33,7 +33,7 @@ class LazyCompoundValData;
class ProgramState;
class BasicValueFactory;
class MemRegion;
-class TypedRegion;
+class TypedValueRegion;
class MemRegionManager;
class ProgramStateManager;
class SValBuilder;
@@ -69,6 +69,29 @@ protected:
public:
explicit SVal() : Data(0), Kind(0) {}
+ /// \brief Convert to the specified SVal type, asserting that this SVal is of
+ /// the desired type.
+ template<typename T>
+ T castAs() const {
+ assert(T::isKind(*this));
+ T t;
+ SVal& sv = t;
+ sv = *this;
+ return t;
+ }
+
+ /// \brief Convert to the specified SVal type, returning None if this SVal is
+ /// not of the desired type.
+ template<typename T>
+ Optional<T> getAs() const {
+ if (!T::isKind(*this))
+ return None;
+ T t;
+ SVal& sv = t;
+ sv = *this;
+ return t;
+ }
+
/// BufferTy - A temporary buffer to hold a set of SVals.
typedef SmallVector<SVal,5> BufferTy;
@@ -161,29 +184,32 @@ class UndefinedVal : public SVal {
public:
UndefinedVal() : SVal(UndefinedKind) {}
- static inline bool classof(const SVal* V) {
- return V->getBaseKind() == UndefinedKind;
+private:
+ friend class SVal;
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == UndefinedKind;
}
};
class DefinedOrUnknownSVal : public SVal {
private:
- // Do not implement. We want calling these methods to be a compiler
- // error since they are tautologically false.
- bool isUndef() const;
- bool isValid() const;
+ // We want calling these methods to be a compiler error since they are
+ // tautologically false.
+ bool isUndef() const LLVM_DELETED_FUNCTION;
+ bool isValid() const LLVM_DELETED_FUNCTION;
protected:
+ DefinedOrUnknownSVal() {}
explicit DefinedOrUnknownSVal(const void *d, bool isLoc, unsigned ValKind)
: SVal(d, isLoc, ValKind) {}
explicit DefinedOrUnknownSVal(BaseKind k, void *D = NULL)
: SVal(k, D) {}
-public:
- // Implement isa<T> support.
- static inline bool classof(const SVal *V) {
- return !V->isUndef();
+private:
+ friend class SVal;
+ static bool isKind(const SVal& V) {
+ return !V.isUndef();
}
};
@@ -191,61 +217,79 @@ class UnknownVal : public DefinedOrUnknownSVal {
public:
explicit UnknownVal() : DefinedOrUnknownSVal(UnknownKind) {}
- static inline bool classof(const SVal *V) {
- return V->getBaseKind() == UnknownKind;
+private:
+ friend class SVal;
+ static bool isKind(const SVal &V) {
+ return V.getBaseKind() == UnknownKind;
}
};
class DefinedSVal : public DefinedOrUnknownSVal {
private:
- // Do not implement. We want calling these methods to be a compiler
- // error since they are tautologically true/false.
- bool isUnknown() const;
- bool isUnknownOrUndef() const;
- bool isValid() const;
+ // We want calling these methods to be a compiler error since they are
+ // tautologically true/false.
+ bool isUnknown() const LLVM_DELETED_FUNCTION;
+ bool isUnknownOrUndef() const LLVM_DELETED_FUNCTION;
+ bool isValid() const LLVM_DELETED_FUNCTION;
protected:
+ DefinedSVal() {}
explicit DefinedSVal(const void *d, bool isLoc, unsigned ValKind)
: DefinedOrUnknownSVal(d, isLoc, ValKind) {}
-public:
- // Implement isa<T> support.
- static inline bool classof(const SVal *V) {
- return !V->isUnknownOrUndef();
+private:
+ friend class SVal;
+ static bool isKind(const SVal& V) {
+ return !V.isUnknownOrUndef();
+ }
+};
+
+
+/// \brief Represents an SVal that is guaranteed to not be UnknownVal.
+class KnownSVal : public SVal {
+ KnownSVal() {}
+ friend class SVal;
+ static bool isKind(const SVal &V) {
+ return !V.isUnknown();
}
+public:
+ KnownSVal(const DefinedSVal &V) : SVal(V) {}
+ KnownSVal(const UndefinedVal &V) : SVal(V) {}
};
class NonLoc : public DefinedSVal {
protected:
+ NonLoc() {}
explicit NonLoc(unsigned SubKind, const void *d)
: DefinedSVal(d, false, SubKind) {}
public:
void dumpToStream(raw_ostream &Out) const;
- // Implement isa<T> support.
- static inline bool classof(const SVal* V) {
- return V->getBaseKind() == NonLocKind;
+private:
+ friend class SVal;
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == NonLocKind;
}
};
class Loc : public DefinedSVal {
protected:
+ Loc() {}
explicit Loc(unsigned SubKind, const void *D)
: DefinedSVal(const_cast<void*>(D), true, SubKind) {}
public:
void dumpToStream(raw_ostream &Out) const;
- Loc(const Loc& X) : DefinedSVal(X.Data, true, X.getSubKind()) {}
-
- // Implement isa<T> support.
- static inline bool classof(const SVal* V) {
- return V->getBaseKind() == LocKind;
- }
-
static inline bool isLocType(QualType T) {
return T->isAnyPointerType() || T->isBlockPointerType() ||
T->isReferenceType();
}
+
+private:
+ friend class SVal;
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == LocKind;
+ }
};
//==------------------------------------------------------------------------==//
@@ -266,17 +310,20 @@ public:
return (const SymExpr*) Data;
}
- bool isExpression() {
+ bool isExpression() const {
return !isa<SymbolData>(getSymbol());
}
- static inline bool classof(const SVal* V) {
- return V->getBaseKind() == NonLocKind &&
- V->getSubKind() == SymbolValKind;
+private:
+ friend class SVal;
+ SymbolVal() {}
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == NonLocKind &&
+ V.getSubKind() == SymbolValKind;
}
- static inline bool classof(const NonLoc* V) {
- return V->getSubKind() == SymbolValKind;
+ static bool isKind(const NonLoc& V) {
+ return V.getSubKind() == SymbolValKind;
}
};
@@ -297,38 +344,40 @@ public:
ConcreteInt evalMinus(SValBuilder &svalBuilder) const;
- // Implement isa<T> support.
- static inline bool classof(const SVal* V) {
- return V->getBaseKind() == NonLocKind &&
- V->getSubKind() == ConcreteIntKind;
+private:
+ friend class SVal;
+ ConcreteInt() {}
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == NonLocKind &&
+ V.getSubKind() == ConcreteIntKind;
}
- static inline bool classof(const NonLoc* V) {
- return V->getSubKind() == ConcreteIntKind;
+ static bool isKind(const NonLoc& V) {
+ return V.getSubKind() == ConcreteIntKind;
}
};
class LocAsInteger : public NonLoc {
friend class ento::SValBuilder;
- explicit LocAsInteger(const std::pair<SVal, uintptr_t>& data) :
- NonLoc(LocAsIntegerKind, &data) {
- assert (isa<Loc>(data.first));
- }
+ explicit LocAsInteger(const std::pair<SVal, uintptr_t> &data)
+ : NonLoc(LocAsIntegerKind, &data) {
+ assert (data.first.getAs<Loc>());
+ }
public:
Loc getLoc() const {
const std::pair<SVal, uintptr_t> *D =
static_cast<const std::pair<SVal, uintptr_t> *>(Data);
- return cast<Loc>(D->first);
+ return D->first.castAs<Loc>();
}
- const Loc& getPersistentLoc() const {
+ Loc getPersistentLoc() const {
const std::pair<SVal, uintptr_t> *D =
static_cast<const std::pair<SVal, uintptr_t> *>(Data);
const SVal& V = D->first;
- return cast<Loc>(V);
+ return V.castAs<Loc>();
}
unsigned getNumBits() const {
@@ -337,14 +386,16 @@ public:
return D->second;
}
- // Implement isa<T> support.
- static inline bool classof(const SVal* V) {
- return V->getBaseKind() == NonLocKind &&
- V->getSubKind() == LocAsIntegerKind;
+private:
+ friend class SVal;
+ LocAsInteger() {}
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == NonLocKind &&
+ V.getSubKind() == LocAsIntegerKind;
}
- static inline bool classof(const NonLoc* V) {
- return V->getSubKind() == LocAsIntegerKind;
+ static bool isKind(const NonLoc& V) {
+ return V.getSubKind() == LocAsIntegerKind;
}
};
@@ -362,12 +413,15 @@ public:
iterator begin() const;
iterator end() const;
- static bool classof(const SVal* V) {
- return V->getBaseKind() == NonLocKind && V->getSubKind() == CompoundValKind;
+private:
+ friend class SVal;
+ CompoundVal() {}
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == NonLocKind && V.getSubKind() == CompoundValKind;
}
- static bool classof(const NonLoc* V) {
- return V->getSubKind() == CompoundValKind;
+ static bool isKind(const NonLoc& V) {
+ return V.getSubKind() == CompoundValKind;
}
};
@@ -381,14 +435,17 @@ public:
return static_cast<const LazyCompoundValData*>(Data);
}
const void *getStore() const;
- const TypedRegion *getRegion() const;
+ const TypedValueRegion *getRegion() const;
- static bool classof(const SVal *V) {
- return V->getBaseKind() == NonLocKind &&
- V->getSubKind() == LazyCompoundValKind;
+private:
+ friend class SVal;
+ LazyCompoundVal() {}
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == NonLocKind &&
+ V.getSubKind() == LazyCompoundValKind;
}
- static bool classof(const NonLoc *V) {
- return V->getSubKind() == LazyCompoundValKind;
+ static bool isKind(const NonLoc& V) {
+ return V.getSubKind() == LazyCompoundValKind;
}
};
@@ -410,12 +467,15 @@ public:
return static_cast<const LabelDecl*>(Data);
}
- static inline bool classof(const SVal* V) {
- return V->getBaseKind() == LocKind && V->getSubKind() == GotoLabelKind;
+private:
+ friend class SVal;
+ GotoLabel() {}
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == LocKind && V.getSubKind() == GotoLabelKind;
}
- static inline bool classof(const Loc* V) {
- return V->getSubKind() == GotoLabelKind;
+ static bool isKind(const Loc& V) {
+ return V.getSubKind() == GotoLabelKind;
}
};
@@ -434,7 +494,7 @@ public:
template <typename REGION>
const REGION* getRegionAs() const {
- return llvm::dyn_cast<REGION>(getRegion());
+ return dyn_cast<REGION>(getRegion());
}
inline bool operator==(const MemRegionVal& R) const {
@@ -445,14 +505,16 @@ public:
return getRegion() != R.getRegion();
}
- // Implement isa<T> support.
- static inline bool classof(const SVal* V) {
- return V->getBaseKind() == LocKind &&
- V->getSubKind() == MemRegionKind;
+private:
+ friend class SVal;
+ MemRegionVal() {}
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == LocKind &&
+ V.getSubKind() == MemRegionKind;
}
- static inline bool classof(const Loc* V) {
- return V->getSubKind() == MemRegionKind;
+ static bool isKind(const Loc& V) {
+ return V.getSubKind() == MemRegionKind;
}
};
@@ -468,19 +530,22 @@ public:
SVal evalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op,
const ConcreteInt& R) const;
- // Implement isa<T> support.
- static inline bool classof(const SVal* V) {
- return V->getBaseKind() == LocKind &&
- V->getSubKind() == ConcreteIntKind;
+private:
+ friend class SVal;
+ ConcreteInt() {}
+ static bool isKind(const SVal& V) {
+ return V.getBaseKind() == LocKind &&
+ V.getSubKind() == ConcreteIntKind;
}
- static inline bool classof(const Loc* V) {
- return V->getSubKind() == ConcreteIntKind;
+ static bool isKind(const Loc& V) {
+ return V.getSubKind() == ConcreteIntKind;
}
};
} // end ento::loc namespace
-} // end GR namespace
+
+} // end ento namespace
} // end clang namespace
@@ -491,6 +556,11 @@ static inline raw_ostream &operator<<(raw_ostream &os,
return os;
}
+template <typename T> struct isPodLike;
+template <> struct isPodLike<clang::ento::SVal> {
+ static const bool value = true;
+};
+
} // end llvm namespace
#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
index 979546b..bbfd579 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
@@ -14,9 +14,9 @@
#ifndef LLVM_CLANG_GR_STORE_H
#define LLVM_CLANG_GR_STORE_H
-#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/Optional.h"
@@ -35,6 +35,8 @@ class ProgramState;
class ProgramStateManager;
class ScanReachableSymbols;
+typedef llvm::DenseSet<SymbolRef> InvalidatedSymbols;
+
class StoreManager {
protected:
SValBuilder &svalBuilder;
@@ -134,7 +136,8 @@ public:
SVal evalDerivedToBase(SVal Derived, const CXXBasePath &CastPath);
/// Evaluates a derived-to-base cast through a single level of derivation.
- SVal evalDerivedToBase(SVal Derived, QualType DerivedPtrType);
+ SVal evalDerivedToBase(SVal Derived, QualType DerivedPtrType,
+ bool IsVirtual);
/// \brief Evaluates C++ dynamic_cast cast.
/// The callback may result in the following 3 scenarios:
@@ -168,7 +171,6 @@ public:
/// associated with the object is recycled.
virtual void decrementReferenceCount(Store store) {}
- typedef llvm::DenseSet<SymbolRef> InvalidatedSymbols;
typedef SmallVector<const MemRegion *, 8> InvalidatedRegions;
/// invalidateRegions - Clears out the specified regions from the store,
@@ -176,26 +178,40 @@ public:
/// invalidate additional regions that may have changed based on accessing
/// the given regions. Optionally, invalidates non-static globals as well.
/// \param[in] store The initial store
- /// \param[in] Regions The regions to invalidate.
+ /// \param[in] Values The values to invalidate.
+ /// \param[in] ConstValues The values to invalidate; these are known to be
+ /// const, so only regions accesible from them should be invalidated.
/// \param[in] E The current statement being evaluated. Used to conjure
/// symbols to mark the values of invalidated regions.
/// \param[in] Count The current block count. Used to conjure
/// symbols to mark the values of invalidated regions.
- /// \param[in,out] IS A set to fill with any symbols that are no longer
- /// accessible. Pass \c NULL if this information will not be used.
/// \param[in] Call The call expression which will be used to determine which
/// globals should get invalidated.
+ /// \param[in,out] IS A set to fill with any symbols that are no longer
+ /// accessible. Pass \c NULL if this information will not be used.
+ /// \param[in,out] ConstIS A set to fill with any symbols corresponding to
+ /// the ConstValues.
+ /// \param[in,out] InvalidatedTopLevel A vector to fill with regions
+ //// explicitely being invalidated. Pass \c NULL if this
+ /// information will not be used.
+ /// \param[in,out] InvalidatedTopLevelConst A vector to fill with const
+ //// regions explicitely being invalidated. Pass \c NULL if this
+ /// information will not be used.
/// \param[in,out] Invalidated A vector to fill with any regions being
/// invalidated. This should include any regions explicitly invalidated
/// even if they do not currently have bindings. Pass \c NULL if this
/// information will not be used.
virtual StoreRef invalidateRegions(Store store,
- ArrayRef<const MemRegion *> Regions,
- const Expr *E, unsigned Count,
- const LocationContext *LCtx,
- InvalidatedSymbols &IS,
- const CallEvent *Call,
- InvalidatedRegions *Invalidated) = 0;
+ ArrayRef<SVal> Values,
+ ArrayRef<SVal> ConstValues,
+ const Expr *E, unsigned Count,
+ const LocationContext *LCtx,
+ const CallEvent *Call,
+ InvalidatedSymbols &IS,
+ InvalidatedSymbols &ConstIS,
+ InvalidatedRegions *InvalidatedTopLevel,
+ InvalidatedRegions *InvalidatedTopLevelConst,
+ InvalidatedRegions *Invalidated) = 0;
/// enterStackFrame - Let the StoreManager to do something when execution
/// engine is about to execute into a callee.
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
index 1e71077..d410063 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
@@ -72,6 +72,15 @@ public:
const CFGBlock *DstT,
const CFGBlock *DstF) = 0;
+ /// Called by CoreEngine. Used to processing branching behavior
+ /// at static initalizers.
+ virtual void processStaticInitializer(const DeclStmt *DS,
+ NodeBuilderContext& BuilderCtx,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst,
+ const CFGBlock *DstT,
+ const CFGBlock *DstF) = 0;
+
/// Called by CoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a computed goto jump.
virtual void processIndirectGoto(IndirectGotoNodeBuilder& builder) = 0;
@@ -104,7 +113,7 @@ public:
/// made to the store. Used to update checkers that track region values.
virtual ProgramStateRef
processRegionChanges(ProgramStateRef state,
- const StoreManager::InvalidatedSymbols *invalidated,
+ const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
const CallEvent *Call) = 0;
@@ -116,6 +125,17 @@ public:
return processRegionChanges(state, 0, MR, MR, 0);
}
+ virtual ProgramStateRef
+ processPointerEscapedOnBind(ProgramStateRef State, SVal Loc, SVal Val) = 0;
+
+ virtual ProgramStateRef
+ notifyCheckersOfPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols *Invalidated,
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions,
+ const CallEvent *Call,
+ bool IsConst = false) = 0;
+
/// printState - Called by ProgramStateManager to print checker-specific data.
virtual void printState(raw_ostream &Out, ProgramStateRef State,
const char *NL, const char *Sep) = 0;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
index 873f773..56afca2 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
@@ -20,10 +20,10 @@
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Basic/LLVM.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
-#include "llvm/Support/DataTypes.h"
-#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/Support/DataTypes.h"
namespace llvm {
class BumpPtrAllocator;
@@ -96,7 +96,7 @@ public:
};
typedef const SymExpr* SymbolRef;
-typedef llvm::SmallVector<SymbolRef, 2> SymbolRefSmallVectorTy;
+typedef SmallVector<SymbolRef, 2> SymbolRefSmallVectorTy;
typedef unsigned SymbolID;
/// \brief A symbol representing data which can be stored in a memory location
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
index c274cea..4c58d4b 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h
@@ -14,7 +14,11 @@
#ifndef LLVM_CLANG_TAINTMANAGER_H
#define LLVM_CLANG_TAINTMANAGER_H
+#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h"
+#include "llvm/ADT/ImmutableMap.h"
namespace clang {
namespace ento {
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h b/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
index 51aa753..d12a151 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
@@ -16,7 +16,8 @@
#define LLVM_CLANG_GR_WORKLIST
#include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h"
-#include <cstddef>
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
+#include <cassert>
namespace clang {
@@ -24,9 +25,6 @@ class CFGBlock;
namespace ento {
-class ExplodedNode;
-class ExplodedNodeImpl;
-
class WorkListUnit {
ExplodedNode *node;
BlockCounter counter;
diff --git a/include/clang/Tooling/CommonOptionsParser.h b/include/clang/Tooling/CommonOptionsParser.h
index a1bad12..6775934 100644
--- a/include/clang/Tooling/CommonOptionsParser.h
+++ b/include/clang/Tooling/CommonOptionsParser.h
@@ -53,8 +53,8 @@ namespace tooling {
///
/// int main(int argc, const char **argv) {
/// CommonOptionsParser OptionsParser(argc, argv);
-/// ClangTool Tool(OptionsParser.GetCompilations(),
-/// OptionsParser.GetSourcePathListi());
+/// ClangTool Tool(OptionsParser.getCompilations(),
+/// OptionsParser.getSourcePathListi());
/// return Tool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>());
/// }
/// \endcode
@@ -67,19 +67,19 @@ public:
CommonOptionsParser(int &argc, const char **argv);
/// Returns a reference to the loaded compilations database.
- CompilationDatabase &GetCompilations() {
+ CompilationDatabase &getCompilations() {
return *Compilations;
}
/// Returns a list of source file paths to process.
- std::vector<std::string> GetSourcePathList() {
+ std::vector<std::string> getSourcePathList() {
return SourcePathList;
}
static const char *const HelpMessage;
private:
- llvm::OwningPtr<CompilationDatabase> Compilations;
+ OwningPtr<CompilationDatabase> Compilations;
std::vector<std::string> SourcePathList;
};
diff --git a/include/clang/Tooling/CompilationDatabase.h b/include/clang/Tooling/CompilationDatabase.h
index a40bffe..7a8054f 100644
--- a/include/clang/Tooling/CompilationDatabase.h
+++ b/include/clang/Tooling/CompilationDatabase.h
@@ -33,7 +33,6 @@
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
-
#include <string>
#include <vector>
@@ -106,6 +105,10 @@ public:
/// \brief Returns the list of all files available in the compilation database.
virtual std::vector<std::string> getAllFiles() const = 0;
+
+ /// \brief Returns all compile commands for all the files in the compilation
+ /// database.
+ virtual std::vector<CompileCommand> getAllCompileCommands() const = 0;
};
/// \brief Interface for compilation database plugins.
@@ -149,7 +152,7 @@ public:
/// The argument list is meant to be compatible with normal llvm command line
/// parsing in main methods.
/// int main(int argc, char **argv) {
- /// llvm::OwningPtr<FixedCompilationDatabase> Compilations(
+ /// OwningPtr<FixedCompilationDatabase> Compilations(
/// FixedCompilationDatabase::loadFromCommandLine(argc, argv));
/// cl::ParseCommandLineOptions(argc, argv);
/// ...
@@ -181,6 +184,12 @@ public:
/// Note: This is always an empty list for the fixed compilation database.
virtual std::vector<std::string> getAllFiles() const;
+ /// \brief Returns all compile commands for all the files in the compilation
+ /// database.
+ ///
+ /// Note: This is always an empty list for the fixed compilation database.
+ virtual std::vector<CompileCommand> getAllCompileCommands() const;
+
private:
/// This is built up to contain a single entry vector to be returned from
/// getCompileCommands after adding the positional argument.
diff --git a/include/clang/Tooling/FileMatchTrie.h b/include/clang/Tooling/FileMatchTrie.h
index ff988be..e531854 100644
--- a/include/clang/Tooling/FileMatchTrie.h
+++ b/include/clang/Tooling/FileMatchTrie.h
@@ -18,7 +18,6 @@
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/StringRef.h"
-
#include <string>
#include <vector>
@@ -77,7 +76,7 @@ public:
/// matches, an empty \c StringRef is returned and a corresponding message
/// written to 'Error'.
StringRef findEquivalent(StringRef FileName,
- llvm::raw_ostream &Error) const;
+ raw_ostream &Error) const;
private:
FileMatchTrieNode *Root;
OwningPtr<PathComparator> Comparator;
diff --git a/include/clang/Tooling/JSONCompilationDatabase.h b/include/clang/Tooling/JSONCompilationDatabase.h
index d62ab5c..e3f149b 100644
--- a/include/clang/Tooling/JSONCompilationDatabase.h
+++ b/include/clang/Tooling/JSONCompilationDatabase.h
@@ -75,6 +75,10 @@ public:
/// These are the 'file' entries of the JSON objects.
virtual std::vector<std::string> getAllFiles() const;
+ /// \brief Returns all compile commands for all the files in the compilation
+ /// database.
+ virtual std::vector<CompileCommand> getAllCompileCommands() const;
+
private:
/// \brief Constructs a JSON compilation database on a memory buffer.
JSONCompilationDatabase(llvm::MemoryBuffer *Database)
@@ -91,12 +95,16 @@ private:
typedef std::pair<llvm::yaml::ScalarNode*,
llvm::yaml::ScalarNode*> CompileCommandRef;
+ /// \brief Converts the given array of CompileCommandRefs to CompileCommands.
+ void getCommands(ArrayRef<CompileCommandRef> CommandsRef,
+ std::vector<CompileCommand> &Commands) const;
+
// Maps file paths to the compile command lines for that file.
llvm::StringMap< std::vector<CompileCommandRef> > IndexByFile;
FileMatchTrie MatchTrie;
- llvm::OwningPtr<llvm::MemoryBuffer> Database;
+ OwningPtr<llvm::MemoryBuffer> Database;
llvm::SourceMgr SM;
llvm::yaml::Stream YAMLStream;
};
diff --git a/include/clang/Tooling/Refactoring.h b/include/clang/Tooling/Refactoring.h
index aaffc1a..079ce74 100644
--- a/include/clang/Tooling/Refactoring.h
+++ b/include/clang/Tooling/Refactoring.h
@@ -19,9 +19,9 @@
#ifndef LLVM_CLANG_TOOLING_REFACTORING_H
#define LLVM_CLANG_TOOLING_REFACTORING_H
-#include "llvm/ADT/StringRef.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/StringRef.h"
#include <set>
#include <string>
@@ -47,22 +47,22 @@ public:
/// \param FilePath A source file accessible via a SourceManager.
/// \param Offset The byte offset of the start of the range in the file.
/// \param Length The length of the range in bytes.
- Replacement(llvm::StringRef FilePath, unsigned Offset,
- unsigned Length, llvm::StringRef ReplacementText);
+ Replacement(StringRef FilePath, unsigned Offset,
+ unsigned Length, StringRef ReplacementText);
/// \brief Creates a Replacement of the range [Start, Start+Length) with
/// ReplacementText.
Replacement(SourceManager &Sources, SourceLocation Start, unsigned Length,
- llvm::StringRef ReplacementText);
+ StringRef ReplacementText);
/// \brief Creates a Replacement of the given range with ReplacementText.
Replacement(SourceManager &Sources, const CharSourceRange &Range,
- llvm::StringRef ReplacementText);
+ StringRef ReplacementText);
/// \brief Creates a Replacement of the node with ReplacementText.
template <typename Node>
Replacement(SourceManager &Sources, const Node &NodeToReplace,
- llvm::StringRef ReplacementText);
+ StringRef ReplacementText);
/// \brief Returns whether this replacement can be applied to a file.
///
@@ -91,9 +91,9 @@ public:
private:
void setFromSourceLocation(SourceManager &Sources, SourceLocation Start,
- unsigned Length, llvm::StringRef ReplacementText);
+ unsigned Length, StringRef ReplacementText);
void setFromSourceRange(SourceManager &Sources, const CharSourceRange &Range,
- llvm::StringRef ReplacementText);
+ StringRef ReplacementText);
std::string FilePath;
unsigned Offset;
@@ -105,41 +105,54 @@ public:
/// FIXME: Change to a vector and deduplicate in the RefactoringTool.
typedef std::set<Replacement, Replacement::Less> Replacements;
-/// \brief Apply all replacements on the Rewriter.
+/// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite.
+///
+/// Replacement applications happen independently of the success of
+/// other applications.
///
-/// If at least one Apply returns false, ApplyAll returns false. Every
-/// Apply will be executed independently of the result of other
-/// Apply operations.
+/// \returns true if all replacements apply. false otherwise.
bool applyAllReplacements(Replacements &Replaces, Rewriter &Rewrite);
/// \brief A tool to run refactorings.
///
-/// This is a refactoring specific version of \see ClangTool.
-/// All text replacements added to getReplacements() during the run of the
-/// tool will be applied and saved after all translation units have been
-/// processed.
-class RefactoringTool {
+/// This is a refactoring specific version of \see ClangTool. FrontendActions
+/// passed to run() and runAndSave() should add replacements to
+/// getReplacements().
+class RefactoringTool : public ClangTool {
public:
/// \see ClangTool::ClangTool.
RefactoringTool(const CompilationDatabase &Compilations,
ArrayRef<std::string> SourcePaths);
- /// \brief Returns a set of replacements. All replacements added during the
- /// run of the tool will be applied after all translation units have been
- /// processed.
+ /// \brief Returns the set of replacements to which replacements should
+ /// be added during the run of the tool.
Replacements &getReplacements();
- /// \see ClangTool::run.
- int run(FrontendActionFactory *ActionFactory);
+ /// \brief Call run(), apply all generated replacements, and immediately save
+ /// the results to disk.
+ ///
+ /// \returns 0 upon success. Non-zero upon failure.
+ int runAndSave(FrontendActionFactory *ActionFactory);
+
+ /// \brief Apply all stored replacements to the given Rewriter.
+ ///
+ /// Replacement applications happen independently of the success of other
+ /// applications.
+ ///
+ /// \returns true if all replacements apply. false otherwise.
+ bool applyAllReplacements(Rewriter &Rewrite);
+
+private:
+ /// \brief Write all refactored files to disk.
+ int saveRewrittenFiles(Rewriter &Rewrite);
private:
- ClangTool Tool;
Replacements Replace;
};
template <typename Node>
Replacement::Replacement(SourceManager &Sources, const Node &NodeToReplace,
- llvm::StringRef ReplacementText) {
+ StringRef ReplacementText) {
const CharSourceRange Range =
CharSourceRange::getTokenRange(NodeToReplace->getSourceRange());
setFromSourceRange(Sources, Range, ReplacementText);
@@ -149,4 +162,3 @@ Replacement::Replacement(SourceManager &Sources, const Node &NodeToReplace,
} // end namespace clang
#endif // end namespace LLVM_CLANG_TOOLING_REFACTORING_H
-
diff --git a/include/clang/Tooling/Tooling.h b/include/clang/Tooling/Tooling.h
index a03bcb1..27e5a0a 100644
--- a/include/clang/Tooling/Tooling.h
+++ b/include/clang/Tooling/Tooling.h
@@ -30,14 +30,14 @@
#ifndef LLVM_CLANG_TOOLING_TOOLING_H
#define LLVM_CLANG_TOOLING_TOOLING_H
-#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/Twine.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LLVM.h"
#include "clang/Driver/Util.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Tooling/ArgumentsAdjusters.h"
#include "clang/Tooling/CompilationDatabase.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/Twine.h"
#include <string>
#include <vector>
@@ -151,11 +151,10 @@ class ToolInvocation {
bool runInvocation(const char *BinaryName,
clang::driver::Compilation *Compilation,
- clang::CompilerInvocation *Invocation,
- const clang::driver::ArgStringList &CC1Args);
+ clang::CompilerInvocation *Invocation);
std::vector<std::string> CommandLine;
- llvm::OwningPtr<FrontendAction> ToolAction;
+ OwningPtr<FrontendAction> ToolAction;
FileManager *Files;
// Maps <file name> -> <file content>.
llvm::StringMap<StringRef> MappedFileContents;
@@ -179,6 +178,8 @@ class ClangTool {
ClangTool(const CompilationDatabase &Compilations,
ArrayRef<std::string> SourcePaths);
+ virtual ~ClangTool() {}
+
/// \brief Map a virtual file to be used while running the tool.
///
/// \param FilePath The path at which the content will be mapped.
@@ -195,7 +196,7 @@ class ClangTool {
/// \param ActionFactory Factory generating the frontend actions. The function
/// takes ownership of this parameter. A new action is generated for every
/// processed translation unit.
- int run(FrontendActionFactory *ActionFactory);
+ virtual int run(FrontendActionFactory *ActionFactory);
/// \brief Returns the file manager used in the tool.
///
@@ -210,7 +211,7 @@ class ClangTool {
// Contains a list of pairs (<file name>, <file content>).
std::vector< std::pair<StringRef, StringRef> > MappedFileContents;
- llvm::OwningPtr<ArgumentsAdjuster> ArgsAdjuster;
+ OwningPtr<ArgumentsAdjuster> ArgsAdjuster;
};
template <typename T>
@@ -244,7 +245,7 @@ inline FrontendActionFactory *newFrontendActionFactory(
: ConsumerFactory(ConsumerFactory), EndCallback(EndCallback) {}
clang::ASTConsumer *CreateASTConsumer(clang::CompilerInstance &,
- llvm::StringRef) {
+ StringRef) {
return ConsumerFactory->newASTConsumer();
}
diff --git a/lib/ARCMigrate/ARCMT.cpp b/lib/ARCMigrate/ARCMT.cpp
index b57d996..72f3520 100644
--- a/lib/ARCMigrate/ARCMT.cpp
+++ b/lib/ARCMigrate/ARCMT.cpp
@@ -8,18 +8,19 @@
//===----------------------------------------------------------------------===//
#include "Internals.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Basic/DiagnosticCategories.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/Utils.h"
-#include "clang/AST/ASTConsumer.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Sema/SemaDiagnostic.h"
-#include "clang/Basic/DiagnosticCategories.h"
-#include "clang/Lex/Preprocessor.h"
-#include "llvm/Support/MemoryBuffer.h"
+#include "clang/Serialization/ASTReader.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/Support/MemoryBuffer.h"
using namespace clang;
using namespace arcmt;
@@ -39,8 +40,9 @@ bool CapturedDiagList::clearDiagnostic(ArrayRef<unsigned> IDs,
diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) {
cleared = true;
ListTy::iterator eraseS = I++;
- while (I != List.end() && I->getLevel() == DiagnosticsEngine::Note)
- ++I;
+ if (eraseS->getLevel() != DiagnosticsEngine::Note)
+ while (I != List.end() && I->getLevel() == DiagnosticsEngine::Note)
+ ++I;
// Clear the diagnostic and any notes following it.
I = List.erase(eraseS, I);
continue;
@@ -130,7 +132,8 @@ public:
const Diagnostic &Info) {
if (DiagnosticIDs::isARCDiagnostic(Info.getID()) ||
level >= DiagnosticsEngine::Error || level == DiagnosticsEngine::Note) {
- CapturedDiags.push_back(StoredDiagnostic(level, Info));
+ if (Info.getLocation().isValid())
+ CapturedDiags.push_back(StoredDiagnostic(level, Info));
return;
}
@@ -172,8 +175,24 @@ static CompilerInvocation *
createInvocationForMigration(CompilerInvocation &origCI) {
OwningPtr<CompilerInvocation> CInvok;
CInvok.reset(new CompilerInvocation(origCI));
- CInvok->getPreprocessorOpts().ImplicitPCHInclude = std::string();
- CInvok->getPreprocessorOpts().ImplicitPTHInclude = std::string();
+ PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts();
+ if (!PPOpts.ImplicitPCHInclude.empty()) {
+ // We can't use a PCH because it was likely built in non-ARC mode and we
+ // want to parse in ARC. Include the original header.
+ FileManager FileMgr(origCI.getFileSystemOpts());
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(),
+ new IgnoringDiagConsumer()));
+ std::string OriginalFile =
+ ASTReader::getOriginalSourceFile(PPOpts.ImplicitPCHInclude,
+ FileMgr, *Diags);
+ if (!OriginalFile.empty())
+ PPOpts.Includes.insert(PPOpts.Includes.begin(), OriginalFile);
+ PPOpts.ImplicitPCHInclude.clear();
+ }
+ // FIXME: Get the original header of a PTH as well.
+ CInvok->getPreprocessorOpts().ImplicitPTHInclude.clear();
std::string define = getARCMTMacroName();
define += '=';
CInvok->getPreprocessorOpts().addMacroDef(define);
@@ -295,7 +314,8 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
std::vector<SourceLocation> ARCMTMacroLocs;
TransformActions testAct(*Diags, capturedDiags, Ctx, Unit->getPreprocessor());
- MigrationPass pass(Ctx, OrigGCMode, Unit->getSema(), testAct, ARCMTMacroLocs);
+ MigrationPass pass(Ctx, OrigGCMode, Unit->getSema(), testAct, capturedDiags,
+ ARCMTMacroLocs);
pass.setNSAllocReallocError(NoNSAllocReallocError);
pass.setNoFinalizeRemoval(NoFinalizeRemoval);
@@ -416,8 +436,8 @@ bool arcmt::getFileRemappingsFromFileList(
bool hasErrorOccurred = false;
llvm::StringMap<bool> Uniquer;
- llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
new DiagnosticsEngine(DiagID, new DiagnosticOptions,
DiagClient, /*ShouldOwnClient=*/false));
@@ -461,7 +481,7 @@ public:
ARCMTMacroTrackerPPCallbacks(std::vector<SourceLocation> &ARCMTMacroLocs)
: ARCMTMacroLocs(ARCMTMacroLocs) { }
- virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo *MI,
+ virtual void MacroExpands(const Token &MacroNameTok, const MacroDirective *MD,
SourceRange Range) {
if (MacroNameTok.getIdentifierInfo()->getName() == getARCMTMacroName())
ARCMTMacroLocs.push_back(MacroNameTok.getLocation());
@@ -598,7 +618,7 @@ bool MigrationProcess::applyTransform(TransformFn trans,
Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts());
TransformActions TA(*Diags, capturedDiags, Ctx, Unit->getPreprocessor());
MigrationPass pass(Ctx, OrigCI.getLangOpts()->getGC(),
- Unit->getSema(), TA, ARCMTMacroLocs);
+ Unit->getSema(), TA, capturedDiags, ARCMTMacroLocs);
trans(pass);
diff --git a/lib/ARCMigrate/CMakeLists.txt b/lib/ARCMigrate/CMakeLists.txt
index 731bcb4..da51d6d 100644
--- a/lib/ARCMigrate/CMakeLists.txt
+++ b/lib/ARCMigrate/CMakeLists.txt
@@ -9,15 +9,16 @@ add_clang_library(clangARCMigrate
TransAutoreleasePool.cpp
TransBlockObjCVariable.cpp
TransEmptyStatementsAndDealloc.cpp
- TransformActions.cpp
- Transforms.cpp
TransGCAttrs.cpp
TransGCCalls.cpp
TransProperties.cpp
+ TransProtectedScope.cpp
TransRetainReleaseDealloc.cpp
TransUnbridgedCasts.cpp
TransUnusedInitDelegate.cpp
TransZeroOutPropsInDealloc.cpp
+ TransformActions.cpp
+ Transforms.cpp
)
add_dependencies(clangARCMigrate
diff --git a/lib/ARCMigrate/FileRemapper.cpp b/lib/ARCMigrate/FileRemapper.cpp
index 28ca9a5..6a8686c 100644
--- a/lib/ARCMigrate/FileRemapper.cpp
+++ b/lib/ARCMigrate/FileRemapper.cpp
@@ -8,12 +8,12 @@
//===----------------------------------------------------------------------===//
#include "clang/ARCMigrate/FileRemapper.h"
-#include "clang/Lex/PreprocessorOptions.h"
-#include "clang/Basic/FileManager.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
-#include "llvm/Support/FileSystem.h"
#include "llvm/Support/raw_ostream.h"
#include <fstream>
diff --git a/lib/ARCMigrate/Internals.h b/lib/ARCMigrate/Internals.h
index 1966a98..3690c83 100644
--- a/lib/ARCMigrate/Internals.h
+++ b/lib/ARCMigrate/Internals.h
@@ -146,16 +146,20 @@ public:
MigratorOptions MigOptions;
Sema &SemaRef;
TransformActions &TA;
+ const CapturedDiagList &CapturedDiags;
std::vector<SourceLocation> &ARCMTMacroLocs;
- llvm::Optional<bool> EnableCFBridgeFns;
+ Optional<bool> EnableCFBridgeFns;
MigrationPass(ASTContext &Ctx, LangOptions::GCMode OrigGCMode,
Sema &sema, TransformActions &TA,
+ const CapturedDiagList &capturedDiags,
std::vector<SourceLocation> &ARCMTMacroLocs)
: Ctx(Ctx), OrigGCMode(OrigGCMode), MigOptions(),
- SemaRef(sema), TA(TA),
+ SemaRef(sema), TA(TA), CapturedDiags(capturedDiags),
ARCMTMacroLocs(ARCMTMacroLocs) { }
+ const CapturedDiagList &getDiags() const { return CapturedDiags; }
+
bool isGCMigration() const { return OrigGCMode != LangOptions::NonGC; }
bool noNSAllocReallocError() const { return MigOptions.NoNSAllocReallocError; }
void setNSAllocReallocError(bool val) { MigOptions.NoNSAllocReallocError = val; }
diff --git a/lib/ARCMigrate/ObjCMT.cpp b/lib/ARCMigrate/ObjCMT.cpp
index dfe14e2..57fac03 100644
--- a/lib/ARCMigrate/ObjCMT.cpp
+++ b/lib/ARCMigrate/ObjCMT.cpp
@@ -8,19 +8,21 @@
//===----------------------------------------------------------------------===//
#include "clang/ARCMigrate/ARCMTActions.h"
-#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Frontend/MultiplexConsumer.h"
+#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/NSAPI.h"
-#include "clang/AST/ASTConsumer.h"
-#include "clang/Edit/Rewriters.h"
-#include "clang/Edit/EditedSource.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Basic/FileManager.h"
#include "clang/Edit/Commit.h"
+#include "clang/Edit/EditedSource.h"
#include "clang/Edit/EditsReceiver.h"
-#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Edit/Rewriters.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/MultiplexConsumer.h"
+#include "clang/Lex/PPConditionalDirectiveRecord.h"
#include "clang/Lex/Preprocessor.h"
-#include "clang/Basic/FileManager.h"
+#include "clang/Rewrite/Core/Rewriter.h"
#include "llvm/ADT/SmallString.h"
using namespace clang;
@@ -35,11 +37,11 @@ public:
std::string MigrateDir;
bool MigrateLiterals;
bool MigrateSubscripting;
- llvm::OwningPtr<NSAPI> NSAPIObj;
- llvm::OwningPtr<edit::EditedSource> Editor;
+ OwningPtr<NSAPI> NSAPIObj;
+ OwningPtr<edit::EditedSource> Editor;
FileRemapper &Remapper;
FileManager &FileMgr;
- const PreprocessingRecord *PPRec;
+ const PPConditionalDirectiveRecord *PPRec;
bool IsOutputFile;
ObjCMigrateASTConsumer(StringRef migrateDir,
@@ -47,7 +49,7 @@ public:
bool migrateSubscripting,
FileRemapper &remapper,
FileManager &fileMgr,
- const PreprocessingRecord *PPRec,
+ const PPConditionalDirectiveRecord *PPRec,
bool isOutputFile = false)
: MigrateDir(migrateDir),
MigrateLiterals(migrateLiterals),
@@ -93,6 +95,9 @@ ObjCMigrateAction::ObjCMigrateAction(FrontendAction *WrappedAction,
ASTConsumer *ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
+ PPConditionalDirectiveRecord *
+ PPRec = new PPConditionalDirectiveRecord(CompInst->getSourceManager());
+ CompInst->getPreprocessor().addPPCallbacks(PPRec);
ASTConsumer *
WrappedConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile);
ASTConsumer *MTConsumer = new ObjCMigrateASTConsumer(MigrateDir,
@@ -100,7 +105,7 @@ ASTConsumer *ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI,
MigrateSubscripting,
Remapper,
CompInst->getFileManager(),
- CompInst->getPreprocessor().getPreprocessingRecord());
+ PPRec);
ASTConsumer *Consumers[] = { MTConsumer, WrappedConsumer };
return new MultiplexConsumer(Consumers);
}
@@ -110,17 +115,17 @@ bool ObjCMigrateAction::BeginInvocation(CompilerInstance &CI) {
/*ignoreIfFilesChanges=*/true);
CompInst = &CI;
CI.getDiagnostics().setIgnoreAllWarnings(true);
- CI.getPreprocessorOpts().DetailedRecord = true;
- CI.getPreprocessorOpts().DetailedRecordConditionalDirectives = true;
return true;
}
namespace {
class ObjCMigrator : public RecursiveASTVisitor<ObjCMigrator> {
ObjCMigrateASTConsumer &Consumer;
+ ParentMap &PMap;
public:
- ObjCMigrator(ObjCMigrateASTConsumer &consumer) : Consumer(consumer) { }
+ ObjCMigrator(ObjCMigrateASTConsumer &consumer, ParentMap &PMap)
+ : Consumer(consumer), PMap(PMap) { }
bool shouldVisitTemplateInstantiations() const { return false; }
bool shouldWalkTypesOfTypeLocs() const { return false; }
@@ -128,7 +133,7 @@ public:
bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
if (Consumer.MigrateLiterals) {
edit::Commit commit(*Consumer.Editor);
- edit::rewriteToObjCLiteralSyntax(E, *Consumer.NSAPIObj, commit);
+ edit::rewriteToObjCLiteralSyntax(E, *Consumer.NSAPIObj, commit, &PMap);
Consumer.Editor->commit(commit);
}
@@ -151,6 +156,23 @@ public:
return WalkUpFromObjCMessageExpr(E);
}
};
+
+class BodyMigrator : public RecursiveASTVisitor<BodyMigrator> {
+ ObjCMigrateASTConsumer &Consumer;
+ OwningPtr<ParentMap> PMap;
+
+public:
+ BodyMigrator(ObjCMigrateASTConsumer &consumer) : Consumer(consumer) { }
+
+ bool shouldVisitTemplateInstantiations() const { return false; }
+ bool shouldWalkTypesOfTypeLocs() const { return false; }
+
+ bool TraverseStmt(Stmt *S) {
+ PMap.reset(new ParentMap(S));
+ ObjCMigrator(Consumer, *PMap).TraverseStmt(S);
+ return true;
+ }
+};
}
void ObjCMigrateASTConsumer::migrateDecl(Decl *D) {
@@ -159,7 +181,7 @@ void ObjCMigrateASTConsumer::migrateDecl(Decl *D) {
if (isa<ObjCMethodDecl>(D))
return; // Wait for the ObjC container declaration.
- ObjCMigrator(*this).TraverseDecl(D);
+ BodyMigrator(*this).TraverseDecl(D);
}
namespace {
@@ -191,13 +213,13 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
RewriteBuffer &buf = I->second;
const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID);
assert(file);
- llvm::SmallString<512> newText;
+ SmallString<512> newText;
llvm::raw_svector_ostream vecOS(newText);
buf.write(vecOS);
vecOS.flush();
llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy(
StringRef(newText.data(), newText.size()), file->getName());
- llvm::SmallString<64> filePath(file->getName());
+ SmallString<64> filePath(file->getName());
FileMgr.FixupRelativePath(filePath);
Remapper.remap(filePath.str(), memBuf);
}
@@ -211,18 +233,19 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
bool MigrateSourceAction::BeginInvocation(CompilerInstance &CI) {
CI.getDiagnostics().setIgnoreAllWarnings(true);
- CI.getPreprocessorOpts().DetailedRecord = true;
- CI.getPreprocessorOpts().DetailedRecordConditionalDirectives = true;
return true;
}
ASTConsumer *MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
+ PPConditionalDirectiveRecord *
+ PPRec = new PPConditionalDirectiveRecord(CI.getSourceManager());
+ CI.getPreprocessor().addPPCallbacks(PPRec);
return new ObjCMigrateASTConsumer(CI.getFrontendOpts().OutputFile,
/*MigrateLiterals=*/true,
/*MigrateSubscripting=*/true,
Remapper,
CI.getFileManager(),
- CI.getPreprocessor().getPreprocessingRecord(),
+ PPRec,
/*isOutputFile=*/true);
}
diff --git a/lib/ARCMigrate/PlistReporter.cpp b/lib/ARCMigrate/PlistReporter.cpp
index d1bc90f..144ba2e 100644
--- a/lib/ARCMigrate/PlistReporter.cpp
+++ b/lib/ARCMigrate/PlistReporter.cpp
@@ -8,9 +8,9 @@
//===----------------------------------------------------------------------===//
#include "Internals.h"
-#include "clang/Lex/Lexer.h"
-#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
using namespace clang;
using namespace arcmt;
diff --git a/lib/ARCMigrate/TransAPIUses.cpp b/lib/ARCMigrate/TransAPIUses.cpp
index 5336f85..2305b6d 100644
--- a/lib/ARCMigrate/TransAPIUses.cpp
+++ b/lib/ARCMigrate/TransAPIUses.cpp
@@ -1,4 +1,4 @@
-//===--- TransAPIUses.cpp - Tranformations to ARC mode --------------------===//
+//===--- TransAPIUses.cpp - Transformations to ARC mode -------------------===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/lib/ARCMigrate/TransARCAssign.cpp b/lib/ARCMigrate/TransARCAssign.cpp
index b83f85a..80bfd22 100644
--- a/lib/ARCMigrate/TransARCAssign.cpp
+++ b/lib/ARCMigrate/TransARCAssign.cpp
@@ -1,4 +1,4 @@
-//===--- TransARCAssign.cpp - Tranformations to ARC mode ------------------===//
+//===--- TransARCAssign.cpp - Transformations to ARC mode -----------------===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/lib/ARCMigrate/TransAutoreleasePool.cpp b/lib/ARCMigrate/TransAutoreleasePool.cpp
index 5205ce4..a2990e7 100644
--- a/lib/ARCMigrate/TransAutoreleasePool.cpp
+++ b/lib/ARCMigrate/TransAutoreleasePool.cpp
@@ -1,4 +1,4 @@
-//===--- TransAutoreleasePool.cpp - Tranformations to ARC mode ------------===//
+//===--- TransAutoreleasePool.cpp - Transformations to ARC mode -----------===//
//
// The LLVM Compiler Infrastructure
//
@@ -30,8 +30,8 @@
#include "Transforms.h"
#include "Internals.h"
#include "clang/AST/ASTContext.h"
-#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include <map>
using namespace clang;
diff --git a/lib/ARCMigrate/TransBlockObjCVariable.cpp b/lib/ARCMigrate/TransBlockObjCVariable.cpp
index 2a79c9a..97c4e34 100644
--- a/lib/ARCMigrate/TransBlockObjCVariable.cpp
+++ b/lib/ARCMigrate/TransBlockObjCVariable.cpp
@@ -1,4 +1,4 @@
-//===--- TransBlockObjCVariable.cpp - Tranformations to ARC mode ----------===//
+//===--- TransBlockObjCVariable.cpp - Transformations to ARC mode ---------===//
//
// The LLVM Compiler Infrastructure
//
@@ -28,6 +28,7 @@
#include "Transforms.h"
#include "Internals.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/Basic/SourceManager.h"
using namespace clang;
diff --git a/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp b/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp
index 552cb2f..ffb638f 100644
--- a/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp
+++ b/lib/ARCMigrate/TransEmptyStatementsAndDealloc.cpp
@@ -1,4 +1,4 @@
-//===--- TransEmptyStatements.cpp - Tranformations to ARC mode ------------===//
+//===--- TransEmptyStatements.cpp - Transformations to ARC mode -----------===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/lib/ARCMigrate/TransGCAttrs.cpp b/lib/ARCMigrate/TransGCAttrs.cpp
index eec7306..d8be1ae 100644
--- a/lib/ARCMigrate/TransGCAttrs.cpp
+++ b/lib/ARCMigrate/TransGCAttrs.cpp
@@ -63,19 +63,18 @@ public:
return;
TypeLoc TL = TInfo->getTypeLoc();
while (TL) {
- if (const QualifiedTypeLoc *QL = dyn_cast<QualifiedTypeLoc>(&TL)) {
- TL = QL->getUnqualifiedLoc();
- } else if (const AttributedTypeLoc *
- Attr = dyn_cast<AttributedTypeLoc>(&TL)) {
- if (handleAttr(*Attr, D))
+ if (QualifiedTypeLoc QL = TL.getAs<QualifiedTypeLoc>()) {
+ TL = QL.getUnqualifiedLoc();
+ } else if (AttributedTypeLoc Attr = TL.getAs<AttributedTypeLoc>()) {
+ if (handleAttr(Attr, D))
break;
- TL = Attr->getModifiedLoc();
- } else if (const ArrayTypeLoc *Arr = dyn_cast<ArrayTypeLoc>(&TL)) {
- TL = Arr->getElementLoc();
- } else if (const PointerTypeLoc *PT = dyn_cast<PointerTypeLoc>(&TL)) {
- TL = PT->getPointeeLoc();
- } else if (const ReferenceTypeLoc *RT = dyn_cast<ReferenceTypeLoc>(&TL))
- TL = RT->getPointeeLoc();
+ TL = Attr.getModifiedLoc();
+ } else if (ArrayTypeLoc Arr = TL.getAs<ArrayTypeLoc>()) {
+ TL = Arr.getElementLoc();
+ } else if (PointerTypeLoc PT = TL.getAs<PointerTypeLoc>()) {
+ TL = PT.getPointeeLoc();
+ } else if (ReferenceTypeLoc RT = TL.getAs<ReferenceTypeLoc>())
+ TL = RT.getPointeeLoc();
else
break;
}
@@ -249,8 +248,9 @@ static void checkAllAtProps(MigrationContext &MigrateCtx,
if (!TInfo)
return;
TypeLoc TL = TInfo->getTypeLoc();
- if (AttributedTypeLoc *ATL = dyn_cast<AttributedTypeLoc>(&TL)) {
- ATLs.push_back(std::make_pair(*ATL, PD));
+ if (AttributedTypeLoc ATL =
+ TL.getAs<AttributedTypeLoc>()) {
+ ATLs.push_back(std::make_pair(ATL, PD));
if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
hasWeak = true;
} else if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong)
diff --git a/lib/ARCMigrate/TransGCCalls.cpp b/lib/ARCMigrate/TransGCCalls.cpp
index 2ec480c..249f20f 100644
--- a/lib/ARCMigrate/TransGCCalls.cpp
+++ b/lib/ARCMigrate/TransGCCalls.cpp
@@ -1,4 +1,4 @@
-//===--- TransGCCalls.cpp - Tranformations to ARC mode --------------------===//
+//===--- TransGCCalls.cpp - Transformations to ARC mode -------------------===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/lib/ARCMigrate/TransProperties.cpp b/lib/ARCMigrate/TransProperties.cpp
index fdd6e88..b6ddc43 100644
--- a/lib/ARCMigrate/TransProperties.cpp
+++ b/lib/ARCMigrate/TransProperties.cpp
@@ -1,4 +1,4 @@
-//===--- TransProperties.cpp - Tranformations to ARC mode -----------------===//
+//===--- TransProperties.cpp - Transformations to ARC mode ----------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -32,9 +32,9 @@
#include "Transforms.h"
#include "Internals.h"
-#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include <map>
using namespace clang;
@@ -141,10 +141,12 @@ public:
AtPropDeclsTy AtExtProps;
// Look through extensions.
- for (ObjCCategoryDecl *Cat = iface->getCategoryList();
- Cat; Cat = Cat->getNextClassCategory())
- if (Cat->IsClassExtension())
- collectProperties(Cat, AtExtProps, &AtProps);
+ for (ObjCInterfaceDecl::visible_extensions_iterator
+ ext = iface->visible_extensions_begin(),
+ extEnd = iface->visible_extensions_end();
+ ext != extEnd; ++ext) {
+ collectProperties(*ext, AtExtProps, &AtProps);
+ }
for (AtPropDeclsTy::iterator
I = AtExtProps.begin(), E = AtExtProps.end(); I != E; ++I) {
@@ -226,8 +228,10 @@ private:
for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
if (I->ImplD)
- Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership,
- I->ImplD->getLocation());
+ Pass.TA.clearDiagnostic(diag::err_arc_strong_property_ownership,
+ diag::err_arc_assign_property_ownership,
+ diag::err_arc_inconsistent_property_ownership,
+ I->IvarD->getLocation());
}
}
@@ -253,8 +257,10 @@ private:
}
}
if (I->ImplD)
- Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership,
- I->ImplD->getLocation());
+ Pass.TA.clearDiagnostic(diag::err_arc_strong_property_ownership,
+ diag::err_arc_assign_property_ownership,
+ diag::err_arc_inconsistent_property_ownership,
+ I->IvarD->getLocation());
}
}
@@ -276,8 +282,10 @@ private:
canUseWeak ? "__weak " : "__unsafe_unretained ");
}
if (I->ImplD) {
- Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership,
- I->ImplD->getLocation());
+ Pass.TA.clearDiagnostic(diag::err_arc_strong_property_ownership,
+ diag::err_arc_assign_property_ownership,
+ diag::err_arc_inconsistent_property_ownership,
+ I->IvarD->getLocation());
Pass.TA.clearDiagnostic(
diag::err_arc_objc_property_default_assign_on_object,
I->ImplD->getLocation());
diff --git a/lib/ARCMigrate/TransProtectedScope.cpp b/lib/ARCMigrate/TransProtectedScope.cpp
new file mode 100644
index 0000000..237aa42
--- /dev/null
+++ b/lib/ARCMigrate/TransProtectedScope.cpp
@@ -0,0 +1,202 @@
+//===--- TransProtectedScope.cpp - Transformations to ARC mode ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Adds brackets in case statements that "contain" initialization of retaining
+// variable, thus emitting the "switch case is in protected scope" error.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Transforms.h"
+#include "Internals.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Sema/SemaDiagnostic.h"
+
+using namespace clang;
+using namespace arcmt;
+using namespace trans;
+
+namespace {
+
+class LocalRefsCollector : public RecursiveASTVisitor<LocalRefsCollector> {
+ SmallVectorImpl<DeclRefExpr *> &Refs;
+
+public:
+ LocalRefsCollector(SmallVectorImpl<DeclRefExpr *> &refs)
+ : Refs(refs) { }
+
+ bool VisitDeclRefExpr(DeclRefExpr *E) {
+ if (ValueDecl *D = E->getDecl())
+ if (D->getDeclContext()->getRedeclContext()->isFunctionOrMethod())
+ Refs.push_back(E);
+ return true;
+ }
+};
+
+struct CaseInfo {
+ SwitchCase *SC;
+ SourceRange Range;
+ enum {
+ St_Unchecked,
+ St_CannotFix,
+ St_Fixed
+ } State;
+
+ CaseInfo() : SC(0), State(St_Unchecked) {}
+ CaseInfo(SwitchCase *S, SourceRange Range)
+ : SC(S), Range(Range), State(St_Unchecked) {}
+};
+
+class CaseCollector : public RecursiveASTVisitor<CaseCollector> {
+ ParentMap &PMap;
+ SmallVectorImpl<CaseInfo> &Cases;
+
+public:
+ CaseCollector(ParentMap &PMap, SmallVectorImpl<CaseInfo> &Cases)
+ : PMap(PMap), Cases(Cases) { }
+
+ bool VisitSwitchStmt(SwitchStmt *S) {
+ SwitchCase *Curr = S->getSwitchCaseList();
+ if (!Curr)
+ return true;
+ Stmt *Parent = getCaseParent(Curr);
+ Curr = Curr->getNextSwitchCase();
+ // Make sure all case statements are in the same scope.
+ while (Curr) {
+ if (getCaseParent(Curr) != Parent)
+ return true;
+ Curr = Curr->getNextSwitchCase();
+ }
+
+ SourceLocation NextLoc = S->getLocEnd();
+ Curr = S->getSwitchCaseList();
+ // We iterate over case statements in reverse source-order.
+ while (Curr) {
+ Cases.push_back(CaseInfo(Curr,SourceRange(Curr->getLocStart(), NextLoc)));
+ NextLoc = Curr->getLocStart();
+ Curr = Curr->getNextSwitchCase();
+ }
+ return true;
+ }
+
+ Stmt *getCaseParent(SwitchCase *S) {
+ Stmt *Parent = PMap.getParent(S);
+ while (Parent && (isa<SwitchCase>(Parent) || isa<LabelStmt>(Parent)))
+ Parent = PMap.getParent(Parent);
+ return Parent;
+ }
+};
+
+class ProtectedScopeFixer {
+ MigrationPass &Pass;
+ SourceManager &SM;
+ SmallVector<CaseInfo, 16> Cases;
+ SmallVector<DeclRefExpr *, 16> LocalRefs;
+
+public:
+ ProtectedScopeFixer(BodyContext &BodyCtx)
+ : Pass(BodyCtx.getMigrationContext().Pass),
+ SM(Pass.Ctx.getSourceManager()) {
+
+ CaseCollector(BodyCtx.getParentMap(), Cases)
+ .TraverseStmt(BodyCtx.getTopStmt());
+ LocalRefsCollector(LocalRefs).TraverseStmt(BodyCtx.getTopStmt());
+
+ SourceRange BodyRange = BodyCtx.getTopStmt()->getSourceRange();
+ const CapturedDiagList &DiagList = Pass.getDiags();
+ // Copy the diagnostics so we don't have to worry about invaliding iterators
+ // from the diagnostic list.
+ SmallVector<StoredDiagnostic, 16> StoredDiags;
+ StoredDiags.append(DiagList.begin(), DiagList.end());
+ SmallVectorImpl<StoredDiagnostic>::iterator
+ I = StoredDiags.begin(), E = StoredDiags.end();
+ while (I != E) {
+ if (I->getID() == diag::err_switch_into_protected_scope &&
+ isInRange(I->getLocation(), BodyRange)) {
+ handleProtectedScopeError(I, E);
+ continue;
+ }
+ ++I;
+ }
+ }
+
+ void handleProtectedScopeError(
+ SmallVectorImpl<StoredDiagnostic>::iterator &DiagI,
+ SmallVectorImpl<StoredDiagnostic>::iterator DiagE){
+ Transaction Trans(Pass.TA);
+ assert(DiagI->getID() == diag::err_switch_into_protected_scope);
+ SourceLocation ErrLoc = DiagI->getLocation();
+ bool handledAllNotes = true;
+ ++DiagI;
+ for (; DiagI != DiagE && DiagI->getLevel() == DiagnosticsEngine::Note;
+ ++DiagI) {
+ if (!handleProtectedNote(*DiagI))
+ handledAllNotes = false;
+ }
+
+ if (handledAllNotes)
+ Pass.TA.clearDiagnostic(diag::err_switch_into_protected_scope, ErrLoc);
+ }
+
+ bool handleProtectedNote(const StoredDiagnostic &Diag) {
+ assert(Diag.getLevel() == DiagnosticsEngine::Note);
+
+ for (unsigned i = 0; i != Cases.size(); i++) {
+ CaseInfo &info = Cases[i];
+ if (isInRange(Diag.getLocation(), info.Range)) {
+
+ if (info.State == CaseInfo::St_Unchecked)
+ tryFixing(info);
+ assert(info.State != CaseInfo::St_Unchecked);
+
+ if (info.State == CaseInfo::St_Fixed) {
+ Pass.TA.clearDiagnostic(Diag.getID(), Diag.getLocation());
+ return true;
+ }
+ return false;
+ }
+ }
+
+ return false;
+ }
+
+ void tryFixing(CaseInfo &info) {
+ assert(info.State == CaseInfo::St_Unchecked);
+ if (hasVarReferencedOutside(info)) {
+ info.State = CaseInfo::St_CannotFix;
+ return;
+ }
+
+ Pass.TA.insertAfterToken(info.SC->getColonLoc(), " {");
+ Pass.TA.insert(info.Range.getEnd(), "}\n");
+ info.State = CaseInfo::St_Fixed;
+ }
+
+ bool hasVarReferencedOutside(CaseInfo &info) {
+ for (unsigned i = 0, e = LocalRefs.size(); i != e; ++i) {
+ DeclRefExpr *DRE = LocalRefs[i];
+ if (isInRange(DRE->getDecl()->getLocation(), info.Range) &&
+ !isInRange(DRE->getLocation(), info.Range))
+ return true;
+ }
+ return false;
+ }
+
+ bool isInRange(SourceLocation Loc, SourceRange R) {
+ if (Loc.isInvalid())
+ return false;
+ return !SM.isBeforeInTranslationUnit(Loc, R.getBegin()) &&
+ SM.isBeforeInTranslationUnit(Loc, R.getEnd());
+ }
+};
+
+} // anonymous namespace
+
+void ProtectedScopeTraverser::traverseBody(BodyContext &BodyCtx) {
+ ProtectedScopeFixer Fix(BodyCtx);
+}
diff --git a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
index 91d2b39..0c8d155 100644
--- a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
+++ b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp
@@ -1,4 +1,4 @@
-//===--- TransRetainReleaseDealloc.cpp - Tranformations to ARC mode -------===//
+//===--- TransRetainReleaseDealloc.cpp - Transformations to ARC mode ------===//
//
// The LLVM Compiler Infrastructure
//
@@ -24,6 +24,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
#include "clang/Sema/SemaDiagnostic.h"
+#include "llvm/ADT/StringSwitch.h"
using namespace clang;
using namespace arcmt;
@@ -161,13 +162,47 @@ public:
private:
/// \brief Checks for idioms where an unused -autorelease is common.
///
- /// Currently only returns true for this idiom which is common in property
+ /// Returns true for this idiom which is common in property
/// setters:
///
/// [backingValue autorelease];
/// backingValue = [newValue retain]; // in general a +1 assign
///
+ /// For these as well:
+ ///
+ /// [[var retain] autorelease];
+ /// return var;
+ ///
bool isCommonUnusedAutorelease(ObjCMessageExpr *E) {
+ if (isPlusOneAssignBeforeOrAfterAutorelease(E))
+ return true;
+ if (isReturnedAfterAutorelease(E))
+ return true;
+ return false;
+ }
+
+ bool isReturnedAfterAutorelease(ObjCMessageExpr *E) {
+ Expr *Rec = E->getInstanceReceiver();
+ if (!Rec)
+ return false;
+
+ Decl *RefD = getReferencedDecl(Rec);
+ if (!RefD)
+ return false;
+
+ Stmt *nextStmt = getNextStmt(E);
+ if (!nextStmt)
+ return false;
+
+ // Check for "return <variable>;".
+
+ if (ReturnStmt *RetS = dyn_cast<ReturnStmt>(nextStmt))
+ return RefD == getReferencedDecl(RetS->getRetValue());
+
+ return false;
+ }
+
+ bool isPlusOneAssignBeforeOrAfterAutorelease(ObjCMessageExpr *E) {
Expr *Rec = E->getInstanceReceiver();
if (!Rec)
return false;
@@ -176,6 +211,47 @@ private:
if (!RefD)
return false;
+ Stmt *prevStmt, *nextStmt;
+ llvm::tie(prevStmt, nextStmt) = getPreviousAndNextStmt(E);
+
+ return isPlusOneAssignToVar(prevStmt, RefD) ||
+ isPlusOneAssignToVar(nextStmt, RefD);
+ }
+
+ bool isPlusOneAssignToVar(Stmt *S, Decl *RefD) {
+ if (!S)
+ return false;
+
+ // Check for "RefD = [+1 retained object];".
+
+ if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(S)) {
+ if (RefD != getReferencedDecl(Bop->getLHS()))
+ return false;
+ if (isPlusOneAssign(Bop))
+ return true;
+ return false;
+ }
+
+ if (DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
+ if (DS->isSingleDecl() && DS->getSingleDecl() == RefD) {
+ if (VarDecl *VD = dyn_cast<VarDecl>(RefD))
+ return isPlusOne(VD->getInit());
+ }
+ return false;
+ }
+
+ return false;
+ }
+
+ Stmt *getNextStmt(Expr *E) {
+ return getPreviousAndNextStmt(E).second;
+ }
+
+ std::pair<Stmt *, Stmt *> getPreviousAndNextStmt(Expr *E) {
+ Stmt *prevStmt = 0, *nextStmt = 0;
+ if (!E)
+ return std::make_pair(prevStmt, nextStmt);
+
Stmt *OuterS = E, *InnerS;
do {
InnerS = OuterS;
@@ -186,36 +262,34 @@ private:
isa<ExprWithCleanups>(OuterS)));
if (!OuterS)
- return false;
-
- // Find next statement after the -autorelease.
+ return std::make_pair(prevStmt, nextStmt);
Stmt::child_iterator currChildS = OuterS->child_begin();
Stmt::child_iterator childE = OuterS->child_end();
+ Stmt::child_iterator prevChildS = childE;
for (; currChildS != childE; ++currChildS) {
if (*currChildS == InnerS)
break;
+ prevChildS = currChildS;
}
+
+ if (prevChildS != childE) {
+ prevStmt = *prevChildS;
+ if (prevStmt)
+ prevStmt = prevStmt->IgnoreImplicit();
+ }
+
if (currChildS == childE)
- return false;
+ return std::make_pair(prevStmt, nextStmt);
++currChildS;
if (currChildS == childE)
- return false;
+ return std::make_pair(prevStmt, nextStmt);
- Stmt *nextStmt = *currChildS;
- if (!nextStmt)
- return false;
- nextStmt = nextStmt->IgnoreImplicit();
+ nextStmt = *currChildS;
+ if (nextStmt)
+ nextStmt = nextStmt->IgnoreImplicit();
- // Check for "RefD = [+1 retained object];".
-
- if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(nextStmt)) {
- if (RefD != getReferencedDecl(Bop->getLHS()))
- return false;
- if (isPlusOneAssign(Bop))
- return true;
- }
- return false;
+ return std::make_pair(prevStmt, nextStmt);
}
Decl *getReferencedDecl(Expr *E) {
@@ -223,6 +297,17 @@ private:
return 0;
E = E->IgnoreParenCasts();
+ if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) {
+ switch (ME->getMethodFamily()) {
+ case OMF_copy:
+ case OMF_autorelease:
+ case OMF_release:
+ case OMF_retain:
+ return getReferencedDecl(ME->getInstanceReceiver());
+ default:
+ return 0;
+ }
+ }
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
return DRE->getDecl();
if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
diff --git a/lib/ARCMigrate/TransUnbridgedCasts.cpp b/lib/ARCMigrate/TransUnbridgedCasts.cpp
index ac18b5d..fc4a75f 100644
--- a/lib/ARCMigrate/TransUnbridgedCasts.cpp
+++ b/lib/ARCMigrate/TransUnbridgedCasts.cpp
@@ -1,4 +1,4 @@
-//===--- TransUnbridgedCasts.cpp - Tranformations to ARC mode -------------===//
+//===--- TransUnbridgedCasts.cpp - Transformations to ARC mode ------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -30,13 +30,22 @@
// ---->
// CFStringRef str = (__bridge CFStringRef)self;
//
+// Uses of Block_copy/Block_release macros are rewritten:
+//
+// c = Block_copy(b);
+// Block_release(c);
+// ---->
+// c = [b copy];
+// <removed>
+//
//===----------------------------------------------------------------------===//
#include "Transforms.h"
#include "Internals.h"
-#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/ParentMap.h"
+#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
#include "clang/Sema/SemaDiagnostic.h"
@@ -53,32 +62,32 @@ class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{
IdentifierInfo *SelfII;
OwningPtr<ParentMap> StmtMap;
Decl *ParentD;
+ Stmt *Body;
+ mutable OwningPtr<ExprSet> Removables;
public:
- UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass), ParentD(0) {
+ UnbridgedCastRewriter(MigrationPass &pass) : Pass(pass), ParentD(0), Body(0) {
SelfII = &Pass.Ctx.Idents.get("self");
}
void transformBody(Stmt *body, Decl *ParentD) {
this->ParentD = ParentD;
+ Body = body;
StmtMap.reset(new ParentMap(body));
TraverseStmt(body);
}
bool VisitCastExpr(CastExpr *E) {
- if (E->getCastKind() != CK_CPointerToObjCPointerCast
- && E->getCastKind() != CK_BitCast)
+ if (E->getCastKind() != CK_CPointerToObjCPointerCast &&
+ E->getCastKind() != CK_BitCast &&
+ E->getCastKind() != CK_AnyPointerToBlockPointerCast)
return true;
QualType castType = E->getType();
Expr *castExpr = E->getSubExpr();
QualType castExprType = castExpr->getType();
- if (castType->isObjCObjectPointerType() &&
- castExprType->isObjCObjectPointerType())
- return true;
- if (!castType->isObjCObjectPointerType() &&
- !castExprType->isObjCObjectPointerType())
+ if (castType->isObjCRetainableType() == castExprType->isObjCRetainableType())
return true;
bool exprRetainable = castExprType->isObjCIndirectLifetimeType();
@@ -93,7 +102,7 @@ public:
if (loc.isValid() && Pass.Ctx.getSourceManager().isInSystemHeader(loc))
return true;
- if (castType->isObjCObjectPointerType())
+ if (castType->isObjCRetainableType())
transformNonObjCToObjCCast(E);
else
transformObjCToNonObjCCast(E);
@@ -139,7 +148,7 @@ private:
if (FD->getName() == "CFRetain" &&
FD->getNumParams() == 1 &&
FD->getParent()->isTranslationUnit() &&
- FD->getLinkage() == ExternalLinkage) {
+ FD->hasExternalLinkage()) {
Expr *Arg = callE->getArg(0);
if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
const Expr *sub = ICE->getSubExpr();
@@ -262,7 +271,78 @@ private:
rewriteToBridgedCast(castE, OBC_BridgeRetained, Trans);
}
+ void getBlockMacroRanges(CastExpr *E, SourceRange &Outer, SourceRange &Inner) {
+ SourceManager &SM = Pass.Ctx.getSourceManager();
+ SourceLocation Loc = E->getExprLoc();
+ assert(Loc.isMacroID());
+ SourceLocation MacroBegin, MacroEnd;
+ llvm::tie(MacroBegin, MacroEnd) = SM.getImmediateExpansionRange(Loc);
+ SourceRange SubRange = E->getSubExpr()->IgnoreParenImpCasts()->getSourceRange();
+ SourceLocation InnerBegin = SM.getImmediateMacroCallerLoc(SubRange.getBegin());
+ SourceLocation InnerEnd = SM.getImmediateMacroCallerLoc(SubRange.getEnd());
+
+ Outer = SourceRange(MacroBegin, MacroEnd);
+ Inner = SourceRange(InnerBegin, InnerEnd);
+ }
+
+ void rewriteBlockCopyMacro(CastExpr *E) {
+ SourceRange OuterRange, InnerRange;
+ getBlockMacroRanges(E, OuterRange, InnerRange);
+
+ Transaction Trans(Pass.TA);
+ Pass.TA.replace(OuterRange, InnerRange);
+ Pass.TA.insert(InnerRange.getBegin(), "[");
+ Pass.TA.insertAfterToken(InnerRange.getEnd(), " copy]");
+ Pass.TA.clearDiagnostic(diag::err_arc_mismatched_cast,
+ diag::err_arc_cast_requires_bridge,
+ OuterRange);
+ }
+
+ void removeBlockReleaseMacro(CastExpr *E) {
+ SourceRange OuterRange, InnerRange;
+ getBlockMacroRanges(E, OuterRange, InnerRange);
+
+ Transaction Trans(Pass.TA);
+ Pass.TA.clearDiagnostic(diag::err_arc_mismatched_cast,
+ diag::err_arc_cast_requires_bridge,
+ OuterRange);
+ if (!hasSideEffects(E, Pass.Ctx)) {
+ if (tryRemoving(cast<Expr>(StmtMap->getParentIgnoreParenCasts(E))))
+ return;
+ }
+ Pass.TA.replace(OuterRange, InnerRange);
+ }
+
+ bool tryRemoving(Expr *E) const {
+ if (!Removables) {
+ Removables.reset(new ExprSet);
+ collectRemovables(Body, *Removables);
+ }
+
+ if (Removables->count(E)) {
+ Pass.TA.removeStmt(E);
+ return true;
+ }
+
+ return false;
+ }
+
void transformObjCToNonObjCCast(CastExpr *E) {
+ SourceLocation CastLoc = E->getExprLoc();
+ if (CastLoc.isMacroID()) {
+ StringRef MacroName = Lexer::getImmediateMacroName(CastLoc,
+ Pass.Ctx.getSourceManager(),
+ Pass.Ctx.getLangOpts());
+ if (MacroName == "Block_copy") {
+ rewriteBlockCopyMacro(E);
+ return;
+ }
+ if (MacroName == "Block_release") {
+ removeBlockReleaseMacro(E);
+ return;
+ }
+ }
+
if (isSelf(E->getSubExpr()))
return rewriteToBridgedCast(E, OBC_Bridge);
@@ -333,7 +413,7 @@ private:
FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl()))
if (FD->getName() == "CFRetain" && FD->getNumParams() == 1 &&
FD->getParent()->isTranslationUnit() &&
- FD->getLinkage() == ExternalLinkage)
+ FD->hasExternalLinkage())
return true;
return false;
@@ -350,7 +430,7 @@ private:
if (arg == E || arg->IgnoreParenImpCasts() == E)
break;
}
- if (i < callE->getNumArgs()) {
+ if (i < callE->getNumArgs() && i < FD->getNumParams()) {
ParmVarDecl *PD = FD->getParamDecl(i);
if (PD->getAttr<CFConsumedAttr>()) {
isConsumed = true;
diff --git a/lib/ARCMigrate/TransUnusedInitDelegate.cpp b/lib/ARCMigrate/TransUnusedInitDelegate.cpp
index 3057e39..e316c73 100644
--- a/lib/ARCMigrate/TransUnusedInitDelegate.cpp
+++ b/lib/ARCMigrate/TransUnusedInitDelegate.cpp
@@ -1,4 +1,4 @@
-//===--- TransUnusedInitDelegate.cpp - Tranformations to ARC mode ---------===//
+//===--- TransUnusedInitDelegate.cpp - Transformations to ARC mode --------===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp b/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp
index a07596d..4d088e0 100644
--- a/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp
+++ b/lib/ARCMigrate/TransZeroOutPropsInDealloc.cpp
@@ -1,4 +1,4 @@
-//===--- TransZeroOutPropsInDealloc.cpp - Tranformations to ARC mode ------===//
+//===--- TransZeroOutPropsInDealloc.cpp - Transformations to ARC mode -----===//
//
// The LLVM Compiler Infrastructure
//
diff --git a/lib/ARCMigrate/TransformActions.cpp b/lib/ARCMigrate/TransformActions.cpp
index 783db1c..2fd0619 100644
--- a/lib/ARCMigrate/TransformActions.cpp
+++ b/lib/ARCMigrate/TransformActions.cpp
@@ -10,8 +10,8 @@
#include "Internals.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/DenseSet.h"
#include <map>
using namespace clang;
diff --git a/lib/ARCMigrate/Transforms.cpp b/lib/ARCMigrate/Transforms.cpp
index 805a67d..0872195 100644
--- a/lib/ARCMigrate/Transforms.cpp
+++ b/lib/ARCMigrate/Transforms.cpp
@@ -1,4 +1,4 @@
-//===--- Tranforms.cpp - Tranformations to ARC mode -----------------------===//
+//===--- Transforms.cpp - Transformations to ARC mode ---------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -9,16 +9,17 @@
#include "Transforms.h"
#include "Internals.h"
-#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Lexer.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaDiagnostic.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/StringSwitch.h"
#include <map>
using namespace clang;
@@ -70,13 +71,22 @@ bool trans::isPlusOneAssign(const BinaryOperator *E) {
if (E->getOpcode() != BO_Assign)
return false;
+ return isPlusOne(E->getRHS());
+}
+
+bool trans::isPlusOne(const Expr *E) {
+ if (!E)
+ return false;
+ if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(E))
+ E = EWC->getSubExpr();
+
if (const ObjCMessageExpr *
- ME = dyn_cast<ObjCMessageExpr>(E->getRHS()->IgnoreParenCasts()))
+ ME = dyn_cast<ObjCMessageExpr>(E->IgnoreParenCasts()))
if (ME->getMethodFamily() == OMF_retain)
return true;
if (const CallExpr *
- callE = dyn_cast<CallExpr>(E->getRHS()->IgnoreParenCasts())) {
+ callE = dyn_cast<CallExpr>(E->IgnoreParenCasts())) {
if (const FunctionDecl *FD = callE->getDirectCallee()) {
if (FD->getAttr<CFReturnsRetainedAttr>())
return true;
@@ -84,7 +94,7 @@ bool trans::isPlusOneAssign(const BinaryOperator *E) {
if (FD->isGlobal() &&
FD->getIdentifier() &&
FD->getParent()->isTranslationUnit() &&
- FD->getLinkage() == ExternalLinkage &&
+ FD->hasExternalLinkage() &&
ento::cocoa::isRefType(callE->getType(), "CF",
FD->getIdentifier()->getName())) {
StringRef fname = FD->getIdentifier()->getName();
@@ -97,7 +107,7 @@ bool trans::isPlusOneAssign(const BinaryOperator *E) {
}
}
- const ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E->getRHS());
+ const ImplicitCastExpr *implCE = dyn_cast<ImplicitCastExpr>(E);
while (implCE && implCE->getCastKind() == CK_BitCast)
implCE = dyn_cast<ImplicitCastExpr>(implCE->getSubExpr());
@@ -188,7 +198,7 @@ bool trans::isGlobalVar(Expr *E) {
E = E->IgnoreParenCasts();
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
return DRE->getDecl()->getDeclContext()->isFileContext() &&
- DRE->getDecl()->getLinkage() == ExternalLinkage;
+ DRE->getDecl()->hasExternalLinkage();
if (ConditionalOperator *condOp = dyn_cast<ConditionalOperator>(E))
return isGlobalVar(condOp->getTrueExpr()) &&
isGlobalVar(condOp->getFalseExpr());
@@ -563,6 +573,7 @@ static void traverseAST(MigrationPass &pass) {
}
MigrateCtx.addTraverser(new PropertyRewriteTraverser());
MigrateCtx.addTraverser(new BlockObjCVariableTraverser());
+ MigrateCtx.addTraverser(new ProtectedScopeTraverser());
MigrateCtx.traverse(pass.Ctx.getTranslationUnitDecl());
}
diff --git a/lib/ARCMigrate/Transforms.h b/lib/ARCMigrate/Transforms.h
index 5d4ac94..cb7d153 100644
--- a/lib/ARCMigrate/Transforms.h
+++ b/lib/ARCMigrate/Transforms.h
@@ -1,4 +1,4 @@
-//===-- Transforms.h - Tranformations to ARC mode ---------------*- C++ -*-===//
+//===-- Transforms.h - Transformations to ARC mode --------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -10,8 +10,8 @@
#ifndef LLVM_CLANG_LIB_ARCMIGRATE_TRANSFORMS_H
#define LLVM_CLANG_LIB_ARCMIGRATE_TRANSFORMS_H
-#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/ParentMap.h"
+#include "clang/AST/RecursiveASTVisitor.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/Support/SaveAndRestore.h"
@@ -135,6 +135,11 @@ public:
virtual void traverseBody(BodyContext &BodyCtx);
};
+class ProtectedScopeTraverser : public ASTTraverser {
+public:
+ virtual void traverseBody(BodyContext &BodyCtx);
+};
+
// GC transformations
class GCAttrsTraverser : public ASTTraverser {
@@ -156,6 +161,7 @@ bool canApplyWeak(ASTContext &Ctx, QualType type,
bool AllowOnUnknownClass = false);
bool isPlusOneAssign(const BinaryOperator *E);
+bool isPlusOne(const Expr *E);
/// \brief 'Loc' is the end of a statement range. This returns the location
/// immediately after the semicolon following the statement.
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp
index 2d7c9bd..98e825b 100644
--- a/lib/AST/APValue.cpp
+++ b/lib/AST/APValue.cpp
@@ -19,8 +19,8 @@
#include "clang/AST/Type.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
namespace {
@@ -348,6 +348,8 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{
bool IsReference = Ty->isReferenceType();
QualType InnerTy
= IsReference ? Ty.getNonReferenceType() : Ty->getPointeeType();
+ if (InnerTy.isNull())
+ InnerTy = Ty;
if (!hasLValuePath()) {
// No lvalue path: just print the offset.
diff --git a/lib/AST/ASTConsumer.cpp b/lib/AST/ASTConsumer.cpp
index a4e17c0..55033b2 100644
--- a/lib/AST/ASTConsumer.cpp
+++ b/lib/AST/ASTConsumer.cpp
@@ -12,8 +12,8 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTConsumer.h"
-#include "clang/AST/DeclGroup.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclGroup.h"
using namespace clang;
bool ASTConsumer::HandleTopLevelDecl(DeclGroupRef D) {
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 74c68ae..7245c03 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -12,28 +12,29 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
+#include "CXXABI.h"
+#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/CharUnits.h"
+#include "clang/AST/Comment.h"
#include "clang/AST/CommentCommandTraits.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/TypeLoc.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExternalASTSource.h"
-#include "clang/AST/ASTMutationListener.h"
-#include "clang/AST/RecordLayout.h"
#include "clang/AST/Mangle.h"
-#include "clang/AST/Comment.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Capacity.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/Capacity.h"
-#include "CXXABI.h"
#include <map>
using namespace clang;
@@ -84,6 +85,14 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
return NULL;
}
+ if (const ClassTemplateSpecializationDecl *CTSD =
+ dyn_cast<ClassTemplateSpecializationDecl>(D)) {
+ TemplateSpecializationKind TSK = CTSD->getSpecializationKind();
+ if (TSK == TSK_ImplicitInstantiation ||
+ TSK == TSK_Undeclared)
+ return NULL;
+ }
+
if (const EnumDecl *ED = dyn_cast<EnumDecl>(D)) {
if (ED->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
return NULL;
@@ -364,10 +373,12 @@ static void addRedeclaredMethods(const ObjCMethodDecl *ObjCMethod,
if (!ID)
return;
// Add redeclared method here.
- for (const ObjCCategoryDecl *ClsExtDecl = ID->getFirstClassExtension();
- ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) {
+ for (ObjCInterfaceDecl::known_extensions_iterator
+ Ext = ID->known_extensions_begin(),
+ ExtEnd = ID->known_extensions_end();
+ Ext != ExtEnd; ++Ext) {
if (ObjCMethodDecl *RedeclaredMethod =
- ClsExtDecl->getMethod(ObjCMethod->getSelector(),
+ Ext->getMethod(ObjCMethod->getSelector(),
ObjCMethod->isInstanceMethod()))
Redeclared.push_back(RedeclaredMethod);
}
@@ -412,15 +423,26 @@ comments::FullComment *ASTContext::getCommentForDecl(
if (!RC) {
if (isa<ObjCMethodDecl>(D) || isa<FunctionDecl>(D)) {
SmallVector<const NamedDecl*, 8> Overridden;
- if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D))
+ const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D);
+ if (OMD && OMD->isPropertyAccessor())
+ if (const ObjCPropertyDecl *PDecl = OMD->findPropertyDecl())
+ if (comments::FullComment *FC = getCommentForDecl(PDecl, PP))
+ return cloneFullComment(FC, D);
+ if (OMD)
addRedeclaredMethods(OMD, Overridden);
getOverriddenMethods(dyn_cast<NamedDecl>(D), Overridden);
- for (unsigned i = 0, e = Overridden.size(); i < e; i++) {
- if (comments::FullComment *FC = getCommentForDecl(Overridden[i], PP)) {
- comments::FullComment *CFC = cloneFullComment(FC, D);
- return CFC;
- }
- }
+ for (unsigned i = 0, e = Overridden.size(); i < e; i++)
+ if (comments::FullComment *FC = getCommentForDecl(Overridden[i], PP))
+ return cloneFullComment(FC, D);
+ }
+ else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
+ // Attach any tag type's documentation to its typedef if latter
+ // does not have one of its own.
+ QualType QT = TD->getUnderlyingType();
+ if (const TagType *TT = QT->getAs<TagType>())
+ if (const Decl *TD = TT->getDecl())
+ if (comments::FullComment *FC = getCommentForDecl(TD, PP))
+ return cloneFullComment(FC, D);
}
return NULL;
}
@@ -571,12 +593,14 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
CXXABI *ASTContext::createCXXABI(const TargetInfo &T) {
if (!LangOpts.CPlusPlus) return 0;
- switch (T.getCXXABI()) {
- case CXXABI_ARM:
+ switch (T.getCXXABI().getKind()) {
+ case TargetCXXABI::GenericARM:
+ case TargetCXXABI::iOS:
return CreateARMCXXABI(*this);
- case CXXABI_Itanium:
+ case TargetCXXABI::GenericAArch64: // Same as Itanium at this level
+ case TargetCXXABI::GenericItanium:
return CreateItaniumCXXABI(*this);
- case CXXABI_Microsoft:
+ case TargetCXXABI::Microsoft:
return CreateMicrosoftCXXABI(*this);
}
llvm_unreachable("Invalid CXXABI type!");
@@ -630,9 +654,9 @@ ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM,
DeclarationNames(*this),
ExternalSource(0), Listener(0),
Comments(SM), CommentsLoaded(false),
- CommentCommandTraits(BumpAlloc),
+ CommentCommandTraits(BumpAlloc, LOpts.CommentOpts),
LastSDM(0, 0),
- UniqueBlockByRefTypeID(0)
+ UniqueBlockByRefTypeID(0)
{
if (size_reserve > 0) Types.reserve(size_reserve);
TUDecl = TranslationUnitDecl::Create(*this);
@@ -873,12 +897,26 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) {
InitBuiltinType(ObjCBuiltinIdTy, BuiltinType::ObjCId);
InitBuiltinType(ObjCBuiltinClassTy, BuiltinType::ObjCClass);
InitBuiltinType(ObjCBuiltinSelTy, BuiltinType::ObjCSel);
+
+ if (LangOpts.OpenCL) {
+ InitBuiltinType(OCLImage1dTy, BuiltinType::OCLImage1d);
+ InitBuiltinType(OCLImage1dArrayTy, BuiltinType::OCLImage1dArray);
+ InitBuiltinType(OCLImage1dBufferTy, BuiltinType::OCLImage1dBuffer);
+ InitBuiltinType(OCLImage2dTy, BuiltinType::OCLImage2d);
+ InitBuiltinType(OCLImage2dArrayTy, BuiltinType::OCLImage2dArray);
+ InitBuiltinType(OCLImage3dTy, BuiltinType::OCLImage3d);
+
+ InitBuiltinType(OCLSamplerTy, BuiltinType::OCLSampler);
+ InitBuiltinType(OCLEventTy, BuiltinType::OCLEvent);
+ }
// Builtin type for __objc_yes and __objc_no
ObjCBuiltinBoolTy = (Target.useSignedCharForObjCBool() ?
SignedCharTy : BoolTy);
ObjCConstantStringType = QualType();
+
+ ObjCSuperType = QualType();
// void * type
VoidPtrTy = getPointerType(VoidTy);
@@ -1411,6 +1449,22 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
Width = Target->getPointerWidth(0);
Align = Target->getPointerAlign(0);
break;
+ case BuiltinType::OCLSampler:
+ // Samplers are modeled as integers.
+ Width = Target->getIntWidth();
+ Align = Target->getIntAlign();
+ break;
+ case BuiltinType::OCLEvent:
+ case BuiltinType::OCLImage1d:
+ case BuiltinType::OCLImage1dArray:
+ case BuiltinType::OCLImage1dBuffer:
+ case BuiltinType::OCLImage2d:
+ case BuiltinType::OCLImage2dArray:
+ case BuiltinType::OCLImage3d:
+ // Currently these types are pointers to opaque types.
+ Width = Target->getPointerWidth(0);
+ Align = Target->getPointerAlign(0);
+ break;
}
break;
case Type::ObjCObjectPointer:
@@ -1442,10 +1496,7 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
}
case Type::MemberPointer: {
const MemberPointerType *MPT = cast<MemberPointerType>(T);
- std::pair<uint64_t, unsigned> PtrDiffInfo =
- getTypeInfo(getPointerDiffType());
- Width = PtrDiffInfo.first * ABI->getMemberPointerSize(MPT);
- Align = PtrDiffInfo.second;
+ llvm::tie(Width, Align) = ABI->getMemberPointerWidthAndAlign(MPT);
break;
}
case Type::Complex: {
@@ -1548,18 +1599,21 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
}
case Type::Atomic: {
+ // Start with the base type information.
std::pair<uint64_t, unsigned> Info
= getTypeInfo(cast<AtomicType>(T)->getValueType());
Width = Info.first;
Align = Info.second;
- if (Width != 0 && Width <= Target->getMaxAtomicPromoteWidth() &&
- llvm::isPowerOf2_64(Width)) {
- // We can potentially perform lock-free atomic operations for this
- // type; promote the alignment appropriately.
- // FIXME: We could potentially promote the width here as well...
- // is that worthwhile? (Non-struct atomic types generally have
- // power-of-two size anyway, but structs might not. Requires a bit
- // of implementation work to make sure we zero out the extra bits.)
+
+ // If the size of the type doesn't exceed the platform's max
+ // atomic promotion width, make the size and alignment more
+ // favorable to atomic operations:
+ if (Width != 0 && Width <= Target->getMaxAtomicPromoteWidth()) {
+ // Round the size up to a power of 2.
+ if (!llvm::isPowerOf2_64(Width))
+ Width = llvm::NextPowerOf2(Width);
+
+ // Set the alignment equal to the size.
Align = static_cast<unsigned>(Width);
}
}
@@ -1658,9 +1712,13 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
}
// Categories of this Interface.
- for (const ObjCCategoryDecl *CDeclChain = OI->getCategoryList();
- CDeclChain; CDeclChain = CDeclChain->getNextClassCategory())
- CollectInheritedProtocols(CDeclChain, Protocols);
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = OI->visible_categories_begin(),
+ CatEnd = OI->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
+ CollectInheritedProtocols(*Cat, Protocols);
+ }
+
if (ObjCInterfaceDecl *SD = OI->getSuperClass())
while (SD) {
CollectInheritedProtocols(SD, Protocols);
@@ -1690,10 +1748,13 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
unsigned ASTContext::CountNonClassIvars(const ObjCInterfaceDecl *OI) const {
unsigned count = 0;
// Count ivars declared in class extension.
- for (const ObjCCategoryDecl *CDecl = OI->getFirstClassExtension(); CDecl;
- CDecl = CDecl->getNextClassExtension())
- count += CDecl->ivar_size();
-
+ for (ObjCInterfaceDecl::known_extensions_iterator
+ Ext = OI->known_extensions_begin(),
+ ExtEnd = OI->known_extensions_end();
+ Ext != ExtEnd; ++Ext) {
+ count += Ext->ivar_size();
+ }
+
// Count ivar defined in this class's implementation. This
// includes synthesized ivars.
if (ObjCImplementationDecl *ImplDecl = OI->getImplementation())
@@ -1750,12 +1811,16 @@ void ASTContext::setObjCImplementation(ObjCCategoryDecl *CatD,
ObjCImpls[CatD] = ImplD;
}
-ObjCInterfaceDecl *ASTContext::getObjContainingInterface(NamedDecl *ND) const {
- if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ND->getDeclContext()))
+const ObjCInterfaceDecl *ASTContext::getObjContainingInterface(
+ const NamedDecl *ND) const {
+ if (const ObjCInterfaceDecl *ID =
+ dyn_cast<ObjCInterfaceDecl>(ND->getDeclContext()))
return ID;
- if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ND->getDeclContext()))
+ if (const ObjCCategoryDecl *CD =
+ dyn_cast<ObjCCategoryDecl>(ND->getDeclContext()))
return CD->getClassInterface();
- if (ObjCImplDecl *IMD = dyn_cast<ObjCImplDecl>(ND->getDeclContext()))
+ if (const ObjCImplDecl *IMD =
+ dyn_cast<ObjCImplDecl>(ND->getDeclContext()))
return IMD->getClassInterface();
return 0;
@@ -1906,8 +1971,10 @@ const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T,
const FunctionProtoType *FPT = cast<FunctionProtoType>(T);
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.ExtInfo = Info;
- Result = getFunctionType(FPT->getResultType(), FPT->arg_type_begin(),
- FPT->getNumArgs(), EPI);
+ Result = getFunctionType(FPT->getResultType(),
+ ArrayRef<QualType>(FPT->arg_type_begin(),
+ FPT->getNumArgs()),
+ EPI);
}
return cast<FunctionType>(Result.getTypePtr());
@@ -2562,16 +2629,25 @@ ASTContext::getFunctionNoProtoType(QualType ResultTy,
return QualType(New, 0);
}
+/// \brief Determine whether \p T is canonical as the result type of a function.
+static bool isCanonicalResultType(QualType T) {
+ return T.isCanonical() &&
+ (T.getObjCLifetime() == Qualifiers::OCL_None ||
+ T.getObjCLifetime() == Qualifiers::OCL_ExplicitNone);
+}
+
/// getFunctionType - Return a normal function type with a typed argument
/// list. isVariadic indicates whether the argument list includes '...'.
QualType
-ASTContext::getFunctionType(QualType ResultTy,
- const QualType *ArgArray, unsigned NumArgs,
+ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
const FunctionProtoType::ExtProtoInfo &EPI) const {
+ size_t NumArgs = ArgArray.size();
+
// Unique functions, to guarantee there is only one function of a particular
// structure.
llvm::FoldingSetNodeID ID;
- FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, EPI, *this);
+ FunctionProtoType::Profile(ID, ResultTy, ArgArray.begin(), NumArgs, EPI,
+ *this);
void *InsertPos = 0;
if (FunctionProtoType *FTP =
@@ -2580,7 +2656,7 @@ ASTContext::getFunctionType(QualType ResultTy,
// Determine whether the type being created is already canonical or not.
bool isCanonical =
- EPI.ExceptionSpecType == EST_None && ResultTy.isCanonical() &&
+ EPI.ExceptionSpecType == EST_None && isCanonicalResultType(ResultTy) &&
!EPI.HasTrailingReturn;
for (unsigned i = 0; i != NumArgs && isCanonical; ++i)
if (!ArgArray[i].isCanonicalAsParam())
@@ -2606,9 +2682,15 @@ ASTContext::getFunctionType(QualType ResultTy,
CanonicalEPI.ExtInfo
= CanonicalEPI.ExtInfo.withCallingConv(getCanonicalCallConv(CallConv));
- Canonical = getFunctionType(getCanonicalType(ResultTy),
- CanonicalArgs.data(), NumArgs,
- CanonicalEPI);
+ // Result types do not have ARC lifetime qualifiers.
+ QualType CanResultTy = getCanonicalType(ResultTy);
+ if (ResultTy.getQualifiers().hasObjCLifetime()) {
+ Qualifiers Qs = CanResultTy.getQualifiers();
+ Qs.removeObjCLifetime();
+ CanResultTy = getQualifiedType(CanResultTy.getUnqualifiedType(), Qs);
+ }
+
+ Canonical = getFunctionType(CanResultTy, CanonicalArgs, CanonicalEPI);
// Get the new insert position for the node we care about.
FunctionProtoType *NewIP =
@@ -2641,7 +2723,7 @@ ASTContext::getFunctionType(QualType ResultTy,
FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment);
FunctionProtoType::ExtProtoInfo newEPI = EPI;
newEPI.ExtInfo = EPI.ExtInfo.withCallingConv(CallConv);
- new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, Canonical, newEPI);
+ new (FTP) FunctionProtoType(ResultTy, ArgArray, Canonical, newEPI);
Types.push_back(FTP);
FunctionProtoTypes.InsertNode(FTP, InsertPos);
return QualType(FTP, 0);
@@ -2877,8 +2959,8 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name,
QualType TST = getTemplateSpecializationType(Name, Args, Underlying);
TypeSourceInfo *DI = CreateTypeSourceInfo(TST);
- TemplateSpecializationTypeLoc TL
- = cast<TemplateSpecializationTypeLoc>(DI->getTypeLoc());
+ TemplateSpecializationTypeLoc TL =
+ DI->getTypeLoc().castAs<TemplateSpecializationTypeLoc>();
TL.setTemplateKeywordLoc(SourceLocation());
TL.setTemplateNameLoc(NameLoc);
TL.setLAngleLoc(Args.getLAngleLoc());
@@ -3154,7 +3236,7 @@ ASTContext::getDependentTemplateSpecializationType(
}
QualType ASTContext::getPackExpansionType(QualType Pattern,
- llvm::Optional<unsigned> NumExpansions) {
+ Optional<unsigned> NumExpansions) {
llvm::FoldingSetNodeID ID;
PackExpansionType::Profile(ID, Pattern, NumExpansions);
@@ -3528,6 +3610,14 @@ QualType ASTContext::getUnsignedWCharType() const {
return UnsignedIntTy;
}
+QualType ASTContext::getIntPtrType() const {
+ return getFromTargetType(Target->getIntPtrType());
+}
+
+QualType ASTContext::getUIntPtrType() const {
+ return getCorrespondingUnsignedType(getIntPtrType());
+}
+
/// getPointerDiffType - Return the unique type for "ptrdiff_t" (C99 7.17)
/// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9).
QualType ASTContext::getPointerDiffType() const {
@@ -3993,7 +4083,8 @@ ASTContext::getConstantArrayElementCount(const ConstantArrayType *CA) const {
uint64_t ElementCount = 1;
do {
ElementCount *= CA->getSize().getZExtValue();
- CA = dyn_cast<ConstantArrayType>(CA->getElementType());
+ CA = dyn_cast_or_null<ConstantArrayType>(
+ CA->getElementType()->getAsArrayTypeUnsafe());
} while (CA);
return ElementCount;
}
@@ -4032,7 +4123,7 @@ QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size,
assert(Domain->isRealFloatingType() && "Unknown domain!");
switch (EltRank) {
- case HalfRank: llvm_unreachable("Half ranks are not valid here");
+ case HalfRank: return HalfTy;
case FloatRank: return FloatTy;
case DoubleRank: return DoubleTy;
case LongDoubleRank: return LongDoubleTy;
@@ -4159,8 +4250,8 @@ QualType ASTContext::getPromotedIntegerType(QualType Promotable) const {
// At this point, we should have a signed or unsigned integer type.
if (Promotable->isSignedIntegerType())
return IntTy;
- uint64_t PromotableSize = getTypeSize(Promotable);
- uint64_t IntSize = getTypeSize(IntTy);
+ uint64_t PromotableSize = getIntWidth(Promotable);
+ uint64_t IntSize = getIntWidth(IntTy);
assert(Promotable->isUnsignedIntegerType() && PromotableSize <= IntSize);
return (PromotableSize != IntSize) ? IntTy : UnsignedIntTy;
}
@@ -4273,6 +4364,16 @@ QualType ASTContext::getCFConstantStringType() const {
return getTagDeclType(CFConstantStringTypeDecl);
}
+QualType ASTContext::getObjCSuperType() const {
+ if (ObjCSuperType.isNull()) {
+ RecordDecl *ObjCSuperTypeDecl =
+ CreateRecordDecl(*this, TTK_Struct, TUDecl, &Idents.get("objc_super"));
+ TUDecl->addDecl(ObjCSuperTypeDecl);
+ ObjCSuperType = getTagDeclType(ObjCSuperTypeDecl);
+ }
+ return ObjCSuperType;
+}
+
void ASTContext::setCFConstantStringType(QualType T) {
const RecordType *Rec = T->getAs<RecordType>();
assert(Rec && "Invalid CFConstantStringType");
@@ -4361,78 +4462,68 @@ QualType ASTContext::getBlockDescriptorExtendedType() const {
return getTagDeclType(BlockDescriptorExtendedType);
}
-bool ASTContext::BlockRequiresCopying(QualType Ty) const {
- if (Ty->isObjCRetainableType())
+/// BlockRequiresCopying - Returns true if byref variable "D" of type "Ty"
+/// requires copy/dispose. Note that this must match the logic
+/// in buildByrefHelpers.
+bool ASTContext::BlockRequiresCopying(QualType Ty,
+ const VarDecl *D) {
+ if (const CXXRecordDecl *record = Ty->getAsCXXRecordDecl()) {
+ const Expr *copyExpr = getBlockVarCopyInits(D);
+ if (!copyExpr && record->hasTrivialDestructor()) return false;
+
return true;
- if (getLangOpts().CPlusPlus) {
- if (const RecordType *RT = Ty->getAs<RecordType>()) {
- CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- return RD->hasConstCopyConstructor();
-
+ }
+
+ if (!Ty->isObjCRetainableType()) return false;
+
+ Qualifiers qs = Ty.getQualifiers();
+
+ // If we have lifetime, that dominates.
+ if (Qualifiers::ObjCLifetime lifetime = qs.getObjCLifetime()) {
+ assert(getLangOpts().ObjCAutoRefCount);
+
+ switch (lifetime) {
+ case Qualifiers::OCL_None: llvm_unreachable("impossible");
+
+ // These are just bits as far as the runtime is concerned.
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Autoreleasing:
+ return false;
+
+ // Tell the runtime that this is ARC __weak, called by the
+ // byref routines.
+ case Qualifiers::OCL_Weak:
+ // ARC __strong __block variables need to be retained.
+ case Qualifiers::OCL_Strong:
+ return true;
}
+ llvm_unreachable("fell out of lifetime switch!");
}
- return false;
+ return (Ty->isBlockPointerType() || isObjCNSObjectType(Ty) ||
+ Ty->isObjCObjectPointerType());
}
-QualType
-ASTContext::BuildByRefType(StringRef DeclName, QualType Ty) const {
- // type = struct __Block_byref_1_X {
- // void *__isa;
- // struct __Block_byref_1_X *__forwarding;
- // unsigned int __flags;
- // unsigned int __size;
- // void *__copy_helper; // as needed
- // void *__destroy_help // as needed
- // int X;
- // } *
-
- bool HasCopyAndDispose = BlockRequiresCopying(Ty);
-
- // FIXME: Move up
- SmallString<36> Name;
- llvm::raw_svector_ostream(Name) << "__Block_byref_" <<
- ++UniqueBlockByRefTypeID << '_' << DeclName;
- RecordDecl *T;
- T = CreateRecordDecl(*this, TTK_Struct, TUDecl, &Idents.get(Name.str()));
- T->startDefinition();
- QualType Int32Ty = IntTy;
- assert(getIntWidth(IntTy) == 32 && "non-32bit int not supported");
- QualType FieldTypes[] = {
- getPointerType(VoidPtrTy),
- getPointerType(getTagDeclType(T)),
- Int32Ty,
- Int32Ty,
- getPointerType(VoidPtrTy),
- getPointerType(VoidPtrTy),
- Ty
- };
-
- StringRef FieldNames[] = {
- "__isa",
- "__forwarding",
- "__flags",
- "__size",
- "__copy_helper",
- "__destroy_helper",
- DeclName,
- };
-
- for (size_t i = 0; i < 7; ++i) {
- if (!HasCopyAndDispose && i >=4 && i <= 5)
- continue;
- FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(),
- SourceLocation(),
- &Idents.get(FieldNames[i]),
- FieldTypes[i], /*TInfo=*/0,
- /*BitWidth=*/0, /*Mutable=*/false,
- ICIS_NoInit);
- Field->setAccess(AS_public);
- T->addDecl(Field);
- }
-
- T->completeDefinition();
-
- return getPointerType(getTagDeclType(T));
+bool ASTContext::getByrefLifetime(QualType Ty,
+ Qualifiers::ObjCLifetime &LifeTime,
+ bool &HasByrefExtendedLayout) const {
+
+ if (!getLangOpts().ObjC1 ||
+ getLangOpts().getGC() != LangOptions::NonGC)
+ return false;
+
+ HasByrefExtendedLayout = false;
+ if (Ty->isRecordType()) {
+ HasByrefExtendedLayout = true;
+ LifeTime = Qualifiers::OCL_None;
+ }
+ else if (getLangOpts().ObjCAutoRefCount)
+ LifeTime = Ty.getObjCLifetime();
+ // MRR.
+ else if (Ty->isObjCObjectPointerType() || Ty->isBlockPointerType())
+ LifeTime = Qualifiers::OCL_ExplicitNone;
+ else
+ LifeTime = Qualifiers::OCL_None;
+ return true;
}
TypedefDecl *ASTContext::getObjCInstanceTypeDecl() {
@@ -4793,17 +4884,19 @@ void ASTContext::getObjCEncodingForType(QualType T, std::string& S,
true /* outermost type */);
}
-static char ObjCEncodingForPrimitiveKind(const ASTContext *C, QualType T) {
- switch (T->getAs<BuiltinType>()->getKind()) {
- default: llvm_unreachable("Unhandled builtin type kind");
+static char getObjCEncodingForPrimitiveKind(const ASTContext *C,
+ BuiltinType::Kind kind) {
+ switch (kind) {
case BuiltinType::Void: return 'v';
case BuiltinType::Bool: return 'B';
case BuiltinType::Char_U:
case BuiltinType::UChar: return 'C';
+ case BuiltinType::Char16:
case BuiltinType::UShort: return 'S';
+ case BuiltinType::Char32:
case BuiltinType::UInt: return 'I';
case BuiltinType::ULong:
- return C->getIntWidth(T) == 32 ? 'L' : 'Q';
+ return C->getTargetInfo().getLongWidth() == 32 ? 'L' : 'Q';
case BuiltinType::UInt128: return 'T';
case BuiltinType::ULongLong: return 'Q';
case BuiltinType::Char_S:
@@ -4813,13 +4906,40 @@ static char ObjCEncodingForPrimitiveKind(const ASTContext *C, QualType T) {
case BuiltinType::WChar_U:
case BuiltinType::Int: return 'i';
case BuiltinType::Long:
- return C->getIntWidth(T) == 32 ? 'l' : 'q';
+ return C->getTargetInfo().getLongWidth() == 32 ? 'l' : 'q';
case BuiltinType::LongLong: return 'q';
case BuiltinType::Int128: return 't';
case BuiltinType::Float: return 'f';
case BuiltinType::Double: return 'd';
case BuiltinType::LongDouble: return 'D';
+ case BuiltinType::NullPtr: return '*'; // like char*
+
+ case BuiltinType::Half:
+ // FIXME: potentially need @encodes for these!
+ return ' ';
+
+ case BuiltinType::ObjCId:
+ case BuiltinType::ObjCClass:
+ case BuiltinType::ObjCSel:
+ llvm_unreachable("@encoding ObjC primitive type");
+
+ // OpenCL and placeholder types don't need @encodings.
+ case BuiltinType::OCLImage1d:
+ case BuiltinType::OCLImage1dArray:
+ case BuiltinType::OCLImage1dBuffer:
+ case BuiltinType::OCLImage2d:
+ case BuiltinType::OCLImage2dArray:
+ case BuiltinType::OCLImage3d:
+ case BuiltinType::OCLEvent:
+ case BuiltinType::OCLSampler:
+ case BuiltinType::Dependent:
+#define BUILTIN_TYPE(KIND, ID)
+#define PLACEHOLDER_TYPE(KIND, ID) \
+ case BuiltinType::KIND:
+#include "clang/AST/BuiltinTypes.def"
+ llvm_unreachable("invalid builtin type for @encode");
}
+ llvm_unreachable("invalid BuiltinType::Kind value");
}
static char ObjCEncodingForEnumType(const ASTContext *C, const EnumType *ET) {
@@ -4830,7 +4950,8 @@ static char ObjCEncodingForEnumType(const ASTContext *C, const EnumType *ET) {
return 'i';
// The encoding of a fixed enum type matches its fixed underlying type.
- return ObjCEncodingForPrimitiveKind(C, Enum->getIntegerType());
+ const BuiltinType *BT = Enum->getIntegerType()->castAs<BuiltinType>();
+ return getObjCEncodingForPrimitiveKind(C, BT->getKind());
}
static void EncodeBitField(const ASTContext *Ctx, std::string& S,
@@ -4858,8 +4979,10 @@ static void EncodeBitField(const ASTContext *Ctx, std::string& S,
S += llvm::utostr(RL.getFieldOffset(FD->getFieldIndex()));
if (const EnumType *ET = T->getAs<EnumType>())
S += ObjCEncodingForEnumType(Ctx, ET);
- else
- S += ObjCEncodingForPrimitiveKind(Ctx, T);
+ else {
+ const BuiltinType *BT = T->castAs<BuiltinType>();
+ S += getObjCEncodingForPrimitiveKind(Ctx, BT->getKind());
+ }
}
S += llvm::utostr(FD->getBitWidthValue(*Ctx));
}
@@ -4873,33 +4996,52 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
bool EncodingProperty,
bool StructField,
bool EncodeBlockParameters,
- bool EncodeClassNames) const {
- if (T->getAs<BuiltinType>()) {
+ bool EncodeClassNames,
+ bool EncodePointerToObjCTypedef) const {
+ CanQualType CT = getCanonicalType(T);
+ switch (CT->getTypeClass()) {
+ case Type::Builtin:
+ case Type::Enum:
if (FD && FD->isBitField())
return EncodeBitField(this, S, T, FD);
- S += ObjCEncodingForPrimitiveKind(this, T);
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CT))
+ S += getObjCEncodingForPrimitiveKind(this, BT->getKind());
+ else
+ S += ObjCEncodingForEnumType(this, cast<EnumType>(CT));
return;
- }
- if (const ComplexType *CT = T->getAs<ComplexType>()) {
+ case Type::Complex: {
+ const ComplexType *CT = T->castAs<ComplexType>();
S += 'j';
getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, 0, false,
false);
return;
}
-
- // encoding for pointer or r3eference types.
- QualType PointeeTy;
- if (const PointerType *PT = T->getAs<PointerType>()) {
- if (PT->isObjCSelType()) {
- S += ':';
- return;
- }
- PointeeTy = PT->getPointeeType();
+
+ case Type::Atomic: {
+ const AtomicType *AT = T->castAs<AtomicType>();
+ S += 'A';
+ getObjCEncodingForTypeImpl(AT->getValueType(), S, false, false, 0,
+ false, false);
+ return;
}
- else if (const ReferenceType *RT = T->getAs<ReferenceType>())
- PointeeTy = RT->getPointeeType();
- if (!PointeeTy.isNull()) {
+
+ // encoding for pointer or reference types.
+ case Type::Pointer:
+ case Type::LValueReference:
+ case Type::RValueReference: {
+ QualType PointeeTy;
+ if (isa<PointerType>(CT)) {
+ const PointerType *PT = T->castAs<PointerType>();
+ if (PT->isObjCSelType()) {
+ S += ':';
+ return;
+ }
+ PointeeTy = PT->getPointeeType();
+ } else {
+ PointeeTy = T->castAs<ReferenceType>()->getPointeeType();
+ }
+
bool isReadOnly = false;
// For historical/compatibility reasons, the read-only qualifier of the
// pointee gets emitted _before_ the '^'. The read-only qualifier of
@@ -4954,10 +5096,12 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
NULL);
return;
}
-
- if (const ArrayType *AT =
- // Ignore type qualifiers etc.
- dyn_cast<ArrayType>(T->getCanonicalTypeInternal())) {
+
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ case Type::VariableArray: {
+ const ArrayType *AT = cast<ArrayType>(CT);
+
if (isa<IncompleteArrayType>(AT) && !StructField) {
// Incomplete arrays are encoded as a pointer to the array element.
S += '^';
@@ -4986,13 +5130,13 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
return;
}
- if (T->getAs<FunctionType>()) {
+ case Type::FunctionNoProto:
+ case Type::FunctionProto:
S += '?';
return;
- }
- if (const RecordType *RTy = T->getAs<RecordType>()) {
- RecordDecl *RDecl = RTy->getDecl();
+ case Type::Record: {
+ RecordDecl *RDecl = cast<RecordType>(CT)->getDecl();
S += RDecl->isUnion() ? '(' : '{';
// Anonymous structures print as '?'
if (const IdentifierInfo *II = RDecl->getIdentifier()) {
@@ -5000,13 +5144,11 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
if (ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(RDecl)) {
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
- std::string TemplateArgsStr
- = TemplateSpecializationType::PrintTemplateArgumentList(
+ llvm::raw_string_ostream OS(S);
+ TemplateSpecializationType::PrintTemplateArgumentList(OS,
TemplateArgs.data(),
TemplateArgs.size(),
(*this).getPrintingPolicy());
-
- S += TemplateArgsStr;
}
} else {
S += '?';
@@ -5043,19 +5185,12 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
S += RDecl->isUnion() ? ')' : '}';
return;
}
-
- if (const EnumType *ET = T->getAs<EnumType>()) {
- if (FD && FD->isBitField())
- EncodeBitField(this, S, T, FD);
- else
- S += ObjCEncodingForEnumType(this, ET);
- return;
- }
- if (const BlockPointerType *BT = T->getAs<BlockPointerType>()) {
+ case Type::BlockPointer: {
+ const BlockPointerType *BT = T->castAs<BlockPointerType>();
S += "@?"; // Unlike a pointer-to-function, which is "^?".
if (EncodeBlockParameters) {
- const FunctionType *FT = BT->getPointeeType()->getAs<FunctionType>();
+ const FunctionType *FT = BT->getPointeeType()->castAs<FunctionType>();
S += '<';
// Block return type
@@ -5089,11 +5224,14 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
return;
}
- // Ignore protocol qualifiers when mangling at this level.
- if (const ObjCObjectType *OT = T->getAs<ObjCObjectType>())
- T = OT->getBaseType();
+ case Type::ObjCObject:
+ case Type::ObjCInterface: {
+ // Ignore protocol qualifiers when mangling at this level.
+ T = T->castAs<ObjCObjectType>()->getBaseType();
- if (const ObjCInterfaceType *OIT = T->getAs<ObjCInterfaceType>()) {
+ // The assumption seems to be that this assert will succeed
+ // because nested levels will have filtered out 'id' and 'Class'.
+ const ObjCInterfaceType *OIT = T->castAs<ObjCInterfaceType>();
// @encode(class_name)
ObjCInterfaceDecl *OI = OIT->getDecl();
S += '{';
@@ -5107,13 +5245,16 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
if (Field->isBitField())
getObjCEncodingForTypeImpl(Field->getType(), S, false, true, Field);
else
- getObjCEncodingForTypeImpl(Field->getType(), S, false, true, FD);
+ getObjCEncodingForTypeImpl(Field->getType(), S, false, true, FD,
+ false, false, false, false, false,
+ EncodePointerToObjCTypedef);
}
S += '}';
return;
}
- if (const ObjCObjectPointerType *OPT = T->getAs<ObjCObjectPointerType>()) {
+ case Type::ObjCObjectPointer: {
+ const ObjCObjectPointerType *OPT = T->castAs<ObjCObjectPointerType>();
if (OPT->isObjCIdType()) {
S += '@';
return;
@@ -5148,14 +5289,17 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
QualType PointeeTy = OPT->getPointeeType();
if (!EncodingProperty &&
- isa<TypedefType>(PointeeTy.getTypePtr())) {
+ isa<TypedefType>(PointeeTy.getTypePtr()) &&
+ !EncodePointerToObjCTypedef) {
// Another historical/compatibility reason.
// We encode the underlying type which comes out as
// {...};
S += '^';
getObjCEncodingForTypeImpl(PointeeTy, S,
false, ExpandPointedToStructures,
- NULL);
+ NULL,
+ false, false, false, false, false,
+ /*EncodePointerToObjCTypedef*/true);
return;
}
@@ -5176,18 +5320,29 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
}
// gcc just blithely ignores member pointers.
- // TODO: maybe there should be a mangling for these
- if (T->getAs<MemberPointerType>())
+ // FIXME: we shoul do better than that. 'M' is available.
+ case Type::MemberPointer:
return;
- if (T->isVectorType()) {
+ case Type::Vector:
+ case Type::ExtVector:
// This matches gcc's encoding, even though technically it is
// insufficient.
// FIXME. We should do a better job than gcc.
return;
+
+#define ABSTRACT_TYPE(KIND, BASE)
+#define TYPE(KIND, BASE)
+#define DEPENDENT_TYPE(KIND, BASE) \
+ case Type::KIND:
+#define NON_CANONICAL_TYPE(KIND, BASE) \
+ case Type::KIND:
+#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(KIND, BASE) \
+ case Type::KIND:
+#include "clang/AST/TypeNodes.def"
+ llvm_unreachable("@encode for dependent type!");
}
-
- llvm_unreachable("@encode for type not implemented!");
+ llvm_unreachable("bad type kind!");
}
void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl,
@@ -5426,6 +5581,85 @@ static TypedefDecl *CreateVoidPtrBuiltinVaListDecl(const ASTContext *Context) {
return VaListTypeDecl;
}
+static TypedefDecl *
+CreateAArch64ABIBuiltinVaListDecl(const ASTContext *Context) {
+ RecordDecl *VaListTagDecl;
+ if (Context->getLangOpts().CPlusPlus) {
+ // namespace std { struct __va_list {
+ NamespaceDecl *NS;
+ NS = NamespaceDecl::Create(const_cast<ASTContext &>(*Context),
+ Context->getTranslationUnitDecl(),
+ /*Inline*/false, SourceLocation(),
+ SourceLocation(), &Context->Idents.get("std"),
+ /*PrevDecl*/0);
+
+ VaListTagDecl = CXXRecordDecl::Create(*Context, TTK_Struct,
+ Context->getTranslationUnitDecl(),
+ SourceLocation(), SourceLocation(),
+ &Context->Idents.get("__va_list"));
+ VaListTagDecl->setDeclContext(NS);
+ } else {
+ // struct __va_list
+ VaListTagDecl = CreateRecordDecl(*Context, TTK_Struct,
+ Context->getTranslationUnitDecl(),
+ &Context->Idents.get("__va_list"));
+ }
+
+ VaListTagDecl->startDefinition();
+
+ const size_t NumFields = 5;
+ QualType FieldTypes[NumFields];
+ const char *FieldNames[NumFields];
+
+ // void *__stack;
+ FieldTypes[0] = Context->getPointerType(Context->VoidTy);
+ FieldNames[0] = "__stack";
+
+ // void *__gr_top;
+ FieldTypes[1] = Context->getPointerType(Context->VoidTy);
+ FieldNames[1] = "__gr_top";
+
+ // void *__vr_top;
+ FieldTypes[2] = Context->getPointerType(Context->VoidTy);
+ FieldNames[2] = "__vr_top";
+
+ // int __gr_offs;
+ FieldTypes[3] = Context->IntTy;
+ FieldNames[3] = "__gr_offs";
+
+ // int __vr_offs;
+ FieldTypes[4] = Context->IntTy;
+ FieldNames[4] = "__vr_offs";
+
+ // Create fields
+ for (unsigned i = 0; i < NumFields; ++i) {
+ FieldDecl *Field = FieldDecl::Create(const_cast<ASTContext &>(*Context),
+ VaListTagDecl,
+ SourceLocation(),
+ SourceLocation(),
+ &Context->Idents.get(FieldNames[i]),
+ FieldTypes[i], /*TInfo=*/0,
+ /*BitWidth=*/0,
+ /*Mutable=*/false,
+ ICIS_NoInit);
+ Field->setAccess(AS_public);
+ VaListTagDecl->addDecl(Field);
+ }
+ VaListTagDecl->completeDefinition();
+ QualType VaListTagType = Context->getRecordType(VaListTagDecl);
+ Context->VaListTagTy = VaListTagType;
+
+ // } __builtin_va_list;
+ TypedefDecl *VaListTypedefDecl
+ = TypedefDecl::Create(const_cast<ASTContext &>(*Context),
+ Context->getTranslationUnitDecl(),
+ SourceLocation(), SourceLocation(),
+ &Context->Idents.get("__builtin_va_list"),
+ Context->getTrivialTypeSourceInfo(VaListTagType));
+
+ return VaListTypedefDecl;
+}
+
static TypedefDecl *CreatePowerABIBuiltinVaListDecl(const ASTContext *Context) {
// typedef struct __va_list_tag {
RecordDecl *VaListTagDecl;
@@ -5659,6 +5893,8 @@ static TypedefDecl *CreateVaListDecl(const ASTContext *Context,
return CreateCharPtrBuiltinVaListDecl(Context);
case TargetInfo::VoidPtrBuiltinVaList:
return CreateVoidPtrBuiltinVaListDecl(Context);
+ case TargetInfo::AArch64ABIBuiltinVaList:
+ return CreateAArch64ABIBuiltinVaListDecl(Context);
case TargetInfo::PowerABIBuiltinVaList:
return CreatePowerABIBuiltinVaListDecl(Context);
case TargetInfo::X86_64ABIBuiltinVaList:
@@ -6496,14 +6732,14 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
if (lbaseInfo.getProducesResult() != rbaseInfo.getProducesResult())
return QualType();
- // functypes which return are preferred over those that do not.
- if (lbaseInfo.getNoReturn() && !rbaseInfo.getNoReturn())
- allLTypes = false;
- else if (!lbaseInfo.getNoReturn() && rbaseInfo.getNoReturn())
- allRTypes = false;
// FIXME: some uses, e.g. conditional exprs, really want this to be 'both'.
bool NoReturn = lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn();
+ if (lbaseInfo.getNoReturn() != NoReturn)
+ allLTypes = false;
+ if (rbaseInfo.getNoReturn() != NoReturn)
+ allRTypes = false;
+
FunctionType::ExtInfo einfo = lbaseInfo.withNoReturn(NoReturn);
if (lproto && rproto) { // two C99 style function prototypes
@@ -6557,7 +6793,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
FunctionProtoType::ExtProtoInfo EPI = lproto->getExtProtoInfo();
EPI.ExtInfo = einfo;
- return getFunctionType(retType, types.begin(), types.size(), EPI);
+ return getFunctionType(retType, types, EPI);
}
if (lproto) allRTypes = false;
@@ -6594,8 +6830,10 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
FunctionProtoType::ExtProtoInfo EPI = proto->getExtProtoInfo();
EPI.ExtInfo = einfo;
- return getFunctionType(retType, proto->arg_type_begin(),
- proto->getNumArgs(), EPI);
+ return getFunctionType(retType,
+ ArrayRef<QualType>(proto->arg_type_begin(),
+ proto->getNumArgs()),
+ EPI);
}
if (allLTypes) return lhs;
@@ -6603,6 +6841,27 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
return getFunctionNoProtoType(retType, einfo);
}
+/// Given that we have an enum type and a non-enum type, try to merge them.
+static QualType mergeEnumWithInteger(ASTContext &Context, const EnumType *ET,
+ QualType other, bool isBlockReturnType) {
+ // C99 6.7.2.2p4: Each enumerated type shall be compatible with char,
+ // a signed integer type, or an unsigned integer type.
+ // Compatibility is based on the underlying type, not the promotion
+ // type.
+ QualType underlyingType = ET->getDecl()->getIntegerType();
+ if (underlyingType.isNull()) return QualType();
+ if (Context.hasSameType(underlyingType, other))
+ return other;
+
+ // In block return types, we're more permissive and accept any
+ // integral type of the same size.
+ if (isBlockReturnType && other->isIntegerType() &&
+ Context.getTypeSize(underlyingType) == Context.getTypeSize(other))
+ return other;
+
+ return QualType();
+}
+
QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
bool OfBlockPointer,
bool Unqualified, bool BlockReturnType) {
@@ -6684,19 +6943,13 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
// If the canonical type classes don't match.
if (LHSClass != RHSClass) {
- // C99 6.7.2.2p4: Each enumerated type shall be compatible with char,
- // a signed integer type, or an unsigned integer type.
- // Compatibility is based on the underlying type, not the promotion
- // type.
+ // Note that we only have special rules for turning block enum
+ // returns into block int returns, not vice-versa.
if (const EnumType* ETy = LHS->getAs<EnumType>()) {
- QualType TINT = ETy->getDecl()->getIntegerType();
- if (!TINT.isNull() && hasSameType(TINT, RHSCan.getUnqualifiedType()))
- return RHS;
+ return mergeEnumWithInteger(*this, ETy, RHS, false);
}
if (const EnumType* ETy = RHS->getAs<EnumType>()) {
- QualType TINT = ETy->getDecl()->getIntegerType();
- if (!TINT.isNull() && hasSameType(TINT, LHSCan.getUnqualifiedType()))
- return LHS;
+ return mergeEnumWithInteger(*this, ETy, LHS, BlockReturnType);
}
// allow block pointer type to match an 'id' type.
if (OfBlockPointer && !BlockReturnType) {
@@ -6928,8 +7181,10 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) {
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.ExtInfo = getFunctionExtInfo(LHS);
QualType ResultType
- = getFunctionType(OldReturnType, FPT->arg_type_begin(),
- FPT->getNumArgs(), EPI);
+ = getFunctionType(OldReturnType,
+ ArrayRef<QualType>(FPT->arg_type_begin(),
+ FPT->getNumArgs()),
+ EPI);
return ResultType;
}
}
@@ -7137,6 +7392,9 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
case 'H':
Type = Context.getObjCSelType();
break;
+ case 'M':
+ Type = Context.getObjCSuperType();
+ break;
case 'a':
Type = Context.getBuiltinVaListType();
assert(!Type.isNull() && "builtin va list type not initialized!");
@@ -7318,7 +7576,7 @@ QualType ASTContext::GetBuiltinType(unsigned Id,
EPI.ExtInfo = EI;
EPI.Variadic = Variadic;
- return getFunctionType(ResType, ArgTypes.data(), ArgTypes.size(), EPI);
+ return getFunctionType(ResType, ArgTypes, EPI);
}
GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) {
@@ -7383,9 +7641,6 @@ GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) {
TSK = VD->getTemplateSpecializationKind();
Linkage L = VD->getLinkage();
- if (L == ExternalLinkage && getLangOpts().CPlusPlus &&
- VD->getType()->getLinkage() == UniqueExternalLinkage)
- L = UniqueExternalLinkage;
switch (L) {
case NoLinkage:
@@ -7418,7 +7673,15 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (!VD->isFileVarDecl())
return false;
- } else if (!isa<FunctionDecl>(D))
+ } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // We never need to emit an uninstantiated function template.
+ if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate)
+ return false;
+ } else
+ return false;
+
+ // If this is a member of a class template, we do not need to emit it.
+ if (D->getDeclContext()->isDependentContext())
return false;
// Weak references don't produce any output by themselves.
@@ -7438,13 +7701,16 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
if (FD->hasAttr<ConstructorAttr>() || FD->hasAttr<DestructorAttr>())
return true;
- // The key function for a class is required.
- if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
- const CXXRecordDecl *RD = MD->getParent();
- if (MD->isOutOfLine() && RD->isDynamicClass()) {
- const CXXMethodDecl *KeyFunc = getKeyFunction(RD);
- if (KeyFunc && KeyFunc->getCanonicalDecl() == MD->getCanonicalDecl())
- return true;
+ // The key function for a class is required. This rule only comes
+ // into play when inline functions can be key functions, though.
+ if (getTargetInfo().getCXXABI().canKeyFunctionBeInline()) {
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ const CXXRecordDecl *RD = MD->getParent();
+ if (MD->isOutOfLine() && RD->isDynamicClass()) {
+ const CXXMethodDecl *KeyFunc = getCurrentKeyFunction(RD);
+ if (KeyFunc && KeyFunc->getCanonicalDecl() == MD->getCanonicalDecl())
+ return true;
+ }
}
}
@@ -7465,27 +7731,20 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
if (VD->isThisDeclarationADefinition() == VarDecl::DeclarationOnly)
return false;
- // Structs that have non-trivial constructors or destructors are required.
+ // Variables that can be needed in other TUs are required.
+ GVALinkage L = GetGVALinkageForVariable(VD);
+ if (L != GVA_Internal && L != GVA_TemplateInstantiation)
+ return true;
- // FIXME: Handle references.
- // FIXME: Be more selective about which constructors we care about.
- if (const RecordType *RT = VD->getType()->getAs<RecordType>()) {
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
- if (RD->hasDefinition() && !(RD->hasTrivialDefaultConstructor() &&
- RD->hasTrivialCopyConstructor() &&
- RD->hasTrivialMoveConstructor() &&
- RD->hasTrivialDestructor()))
- return true;
- }
- }
+ // Variables that have destruction with side-effects are required.
+ if (VD->getType().isDestructedType())
+ return true;
- GVALinkage L = GetGVALinkageForVariable(VD);
- if (L == GVA_Internal || L == GVA_TemplateInstantiation) {
- if (!(VD->getInit() && VD->getInit()->HasSideEffects(*this)))
- return false;
- }
+ // Variables that have initialization with side-effects are required.
+ if (VD->getInit() && VD->getInit()->HasSideEffects(*this))
+ return true;
- return true;
+ return false;
}
CallingConv ASTContext::getDefaultCXXMethodCallConv(bool isVariadic) {
@@ -7494,7 +7753,8 @@ CallingConv ASTContext::getDefaultCXXMethodCallConv(bool isVariadic) {
}
CallingConv ASTContext::getCanonicalCallConv(CallingConv CC) const {
- if (CC == CC_C && !LangOpts.MRTD && getTargetInfo().getCXXABI() != CXXABI_Microsoft)
+ if (CC == CC_C && !LangOpts.MRTD &&
+ getTargetInfo().getCXXABI().isMemberFunctionCCDefault())
return CC_Default;
return CC;
}
@@ -7505,11 +7765,13 @@ bool ASTContext::isNearlyEmpty(const CXXRecordDecl *RD) const {
}
MangleContext *ASTContext::createMangleContext() {
- switch (Target->getCXXABI()) {
- case CXXABI_ARM:
- case CXXABI_Itanium:
+ switch (Target->getCXXABI().getKind()) {
+ case TargetCXXABI::GenericAArch64:
+ case TargetCXXABI::GenericItanium:
+ case TargetCXXABI::GenericARM:
+ case TargetCXXABI::iOS:
return createItaniumMangleContext(*this, getDiagnostics());
- case CXXABI_Microsoft:
+ case TargetCXXABI::Microsoft:
return createMicrosoftMangleContext(*this, getDiagnostics());
}
llvm_unreachable("Unsupported ABI");
@@ -7534,6 +7796,23 @@ size_t ASTContext::getSideTableAllocatedMemory() const {
+ llvm::capacity_in_bytes(ClassScopeSpecializationPattern);
}
+void ASTContext::addUnnamedTag(const TagDecl *Tag) {
+ // FIXME: This mangling should be applied to function local classes too
+ if (!Tag->getName().empty() || Tag->getTypedefNameForAnonDecl() ||
+ !isa<CXXRecordDecl>(Tag->getParent()) || Tag->getLinkage() != ExternalLinkage)
+ return;
+
+ std::pair<llvm::DenseMap<const DeclContext *, unsigned>::iterator, bool> P =
+ UnnamedMangleContexts.insert(std::make_pair(Tag->getParent(), 0));
+ UnnamedMangleNumbers.insert(std::make_pair(Tag, P.first->second++));
+}
+
+int ASTContext::getUnnamedTagManglingNumber(const TagDecl *Tag) const {
+ llvm::DenseMap<const TagDecl *, unsigned>::const_iterator I =
+ UnnamedMangleNumbers.find(Tag);
+ return I != UnnamedMangleNumbers.end() ? I->second : -1;
+}
+
unsigned ASTContext::getLambdaManglingNumber(CXXMethodDecl *CallOperator) {
CXXRecordDecl *Lambda = CallOperator->getParent();
return LambdaMangleContexts[Lambda->getDeclContext()]
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index 0b9c524..1ed65e4 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -11,12 +11,11 @@
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTDiagnostic.h"
-
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
-#include "clang/AST/TemplateBase.h"
-#include "clang/AST/ExprCXX.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/TemplateBase.h"
#include "clang/AST/Type.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
@@ -232,7 +231,7 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
static bool FormatTemplateTypeDiff(ASTContext &Context, QualType FromType,
QualType ToType, bool PrintTree,
bool PrintFromType, bool ElideType,
- bool ShowColors, std::string &S);
+ bool ShowColors, raw_ostream &OS);
void clang::FormatASTNodeDiagnosticArgument(
DiagnosticsEngine::ArgumentKind Kind,
@@ -248,7 +247,8 @@ void clang::FormatASTNodeDiagnosticArgument(
ArrayRef<intptr_t> QualTypeVals) {
ASTContext &Context = *static_cast<ASTContext*>(Cookie);
- std::string S;
+ size_t OldEnd = Output.size();
+ llvm::raw_svector_ostream OS(Output);
bool NeedQuotes = true;
switch (Kind) {
@@ -262,7 +262,7 @@ void clang::FormatASTNodeDiagnosticArgument(
if (FormatTemplateTypeDiff(Context, FromType, ToType, TDT.PrintTree,
TDT.PrintFromType, TDT.ElideType,
- TDT.ShowColors, S)) {
+ TDT.ShowColors, OS)) {
NeedQuotes = !TDT.PrintTree;
TDT.TemplateDiffUsed = true;
break;
@@ -273,7 +273,7 @@ void clang::FormatASTNodeDiagnosticArgument(
if (TDT.PrintTree)
return;
- // Attempting to do a templete diff on non-templates. Set the variables
+ // Attempting to do a template diff on non-templates. Set the variables
// and continue with regular type printing of the appropriate type.
Val = TDT.PrintFromType ? TDT.FromType : TDT.ToType;
ModLen = 0;
@@ -285,23 +285,23 @@ void clang::FormatASTNodeDiagnosticArgument(
"Invalid modifier for QualType argument");
QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val)));
- S = ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, NumPrevArgs,
- QualTypeVals);
+ OS << ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, NumPrevArgs,
+ QualTypeVals);
NeedQuotes = false;
break;
}
case DiagnosticsEngine::ak_declarationname: {
- DeclarationName N = DeclarationName::getFromOpaqueInteger(Val);
- S = N.getAsString();
-
if (ModLen == 9 && !memcmp(Modifier, "objcclass", 9) && ArgLen == 0)
- S = '+' + S;
+ OS << '+';
else if (ModLen == 12 && !memcmp(Modifier, "objcinstance", 12)
&& ArgLen==0)
- S = '-' + S;
+ OS << '-';
else
assert(ModLen == 0 && ArgLen == 0 &&
"Invalid modifier for DeclarationName argument");
+
+ DeclarationName N = DeclarationName::getFromOpaqueInteger(Val);
+ N.printName(OS);
break;
}
case DiagnosticsEngine::ak_nameddecl: {
@@ -314,13 +314,12 @@ void clang::FormatASTNodeDiagnosticArgument(
Qualified = false;
}
const NamedDecl *ND = reinterpret_cast<const NamedDecl*>(Val);
- ND->getNameForDiagnostic(S, Context.getPrintingPolicy(), Qualified);
+ ND->getNameForDiagnostic(OS, Context.getPrintingPolicy(), Qualified);
break;
}
case DiagnosticsEngine::ak_nestednamespec: {
- llvm::raw_string_ostream OS(S);
- reinterpret_cast<NestedNameSpecifier*>(Val)->print(OS,
- Context.getPrintingPolicy());
+ NestedNameSpecifier *NNS = reinterpret_cast<NestedNameSpecifier*>(Val);
+ NNS->print(OS, Context.getPrintingPolicy());
NeedQuotes = false;
break;
}
@@ -331,39 +330,39 @@ void clang::FormatASTNodeDiagnosticArgument(
if (DC->isTranslationUnit()) {
// FIXME: Get these strings from some localized place
if (Context.getLangOpts().CPlusPlus)
- S = "the global namespace";
+ OS << "the global namespace";
else
- S = "the global scope";
+ OS << "the global scope";
} else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) {
- S = ConvertTypeToDiagnosticString(Context,
- Context.getTypeDeclType(Type),
- PrevArgs, NumPrevArgs, QualTypeVals);
+ OS << ConvertTypeToDiagnosticString(Context,
+ Context.getTypeDeclType(Type),
+ PrevArgs, NumPrevArgs,
+ QualTypeVals);
} else {
// FIXME: Get these strings from some localized place
NamedDecl *ND = cast<NamedDecl>(DC);
if (isa<NamespaceDecl>(ND))
- S += "namespace ";
+ OS << "namespace ";
else if (isa<ObjCMethodDecl>(ND))
- S += "method ";
+ OS << "method ";
else if (isa<FunctionDecl>(ND))
- S += "function ";
-
- S += "'";
- ND->getNameForDiagnostic(S, Context.getPrintingPolicy(), true);
- S += "'";
+ OS << "function ";
+
+ OS << '\'';
+ ND->getNameForDiagnostic(OS, Context.getPrintingPolicy(), true);
+ OS << '\'';
}
NeedQuotes = false;
break;
}
}
-
- if (NeedQuotes)
- Output.push_back('\'');
-
- Output.append(S.begin(), S.end());
-
- if (NeedQuotes)
+
+ OS.flush();
+
+ if (NeedQuotes) {
+ Output.insert(Output.begin()+OldEnd, '\'');
Output.push_back('\'');
+ }
}
/// TemplateDiff - A class that constructs a pretty string for a pair of
@@ -396,21 +395,39 @@ class TemplateDiff {
/// will this type be outputed.
QualType ToType;
- /// Str - Storage for the output stream.
- llvm::SmallString<128> Str;
-
/// OS - The stream used to construct the output strings.
- llvm::raw_svector_ostream OS;
+ raw_ostream &OS;
/// IsBold - Keeps track of the bold formatting for the output string.
bool IsBold;
/// DiffTree - A tree representation the differences between two types.
class DiffTree {
+ public:
+ /// DiffKind - The difference in a DiffNode and which fields are used.
+ enum DiffKind {
+ /// Incomplete or invalid node.
+ Invalid,
+ /// Another level of templates, uses TemplateDecl and Qualifiers
+ Template,
+ /// Type difference, uses QualType
+ Type,
+ /// Expression difference, uses Expr
+ Expression,
+ /// Template argument difference, uses TemplateDecl
+ TemplateTemplate,
+ /// Integer difference, uses APSInt and Expr
+ Integer,
+ /// Declaration difference, uses ValueDecl
+ Declaration
+ };
+ private:
/// DiffNode - The root node stores the original type. Each child node
/// stores template arguments of their parents. For templated types, the
/// template decl is also stored.
struct DiffNode {
+ DiffKind Kind;
+
/// NextNode - The index of the next sibling node or 0.
unsigned NextNode;
@@ -439,6 +456,9 @@ class TemplateDiff {
/// IsValidFromInt, IsValidToInt - Whether the APSInt's are valid.
bool IsValidFromInt, IsValidToInt;
+ /// FromValueDecl, ToValueDecl - Whether the argument is a decl.
+ ValueDecl *FromValueDecl, *ToValueDecl;
+
/// FromDefault, ToDefault - Whether the argument is a default argument.
bool FromDefault, ToDefault;
@@ -446,13 +466,14 @@ class TemplateDiff {
bool Same;
DiffNode(unsigned ParentNode = 0)
- : NextNode(0), ChildNode(0), ParentNode(ParentNode),
+ : Kind(Invalid), NextNode(0), ChildNode(0), ParentNode(ParentNode),
FromType(), ToType(), FromExpr(0), ToExpr(0), FromTD(0), ToTD(0),
- FromDefault(false), ToDefault(false), Same(false) { }
+ IsValidFromInt(false), IsValidToInt(false), FromValueDecl(0),
+ ToValueDecl(0), FromDefault(false), ToDefault(false), Same(false) { }
};
/// FlatTree - A flattened tree used to store the DiffNodes.
- llvm::SmallVector<DiffNode, 16> FlatTree;
+ SmallVector<DiffNode, 16> FlatTree;
/// CurrentNode - The index of the current node being used.
unsigned CurrentNode;
@@ -504,6 +525,12 @@ class TemplateDiff {
FlatTree[CurrentNode].ToQual = ToQual;
}
+ /// SetNode - Set FromValueDecl and ToValueDecl of the current node.
+ void SetNode(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl) {
+ FlatTree[CurrentNode].FromValueDecl = FromValueDecl;
+ FlatTree[CurrentNode].ToValueDecl = ToValueDecl;
+ }
+
/// SetSame - Sets the same flag of the current node.
void SetSame(bool Same) {
FlatTree[CurrentNode].Same = Same;
@@ -515,6 +542,11 @@ class TemplateDiff {
FlatTree[CurrentNode].ToDefault = ToDefault;
}
+ /// SetKind - Sets the current node's type.
+ void SetKind(DiffKind Kind) {
+ FlatTree[CurrentNode].Kind = Kind;
+ }
+
/// Up - Changes the node to the parent of the current node.
void Up() {
CurrentNode = FlatTree[CurrentNode].ParentNode;
@@ -554,39 +586,6 @@ class TemplateDiff {
ReadNode = FlatTree[ReadNode].ParentNode;
}
- /// NodeIsTemplate - Returns true if a template decl is set, and types are
- /// set.
- bool NodeIsTemplate() {
- return (FlatTree[ReadNode].FromTD &&
- !FlatTree[ReadNode].ToType.isNull()) ||
- (FlatTree[ReadNode].ToTD && !FlatTree[ReadNode].ToType.isNull());
- }
-
- /// NodeIsQualType - Returns true if a Qualtype is set.
- bool NodeIsQualType() {
- return !FlatTree[ReadNode].FromType.isNull() ||
- !FlatTree[ReadNode].ToType.isNull();
- }
-
- /// NodeIsExpr - Returns true if an expr is set.
- bool NodeIsExpr() {
- return FlatTree[ReadNode].FromExpr || FlatTree[ReadNode].ToExpr;
- }
-
- /// NodeIsTemplateTemplate - Returns true if the argument is a template
- /// template type.
- bool NodeIsTemplateTemplate() {
- return FlatTree[ReadNode].FromType.isNull() &&
- FlatTree[ReadNode].ToType.isNull() &&
- (FlatTree[ReadNode].FromTD || FlatTree[ReadNode].ToTD);
- }
-
- /// NodeIsAPSInt - Returns true if the arugments are stored in APSInt's.
- bool NodeIsAPSInt() {
- return FlatTree[ReadNode].IsValidFromInt ||
- FlatTree[ReadNode].IsValidToInt;
- }
-
/// GetNode - Gets the FromType and ToType.
void GetNode(QualType &FromType, QualType &ToType) {
FromType = FlatTree[ReadNode].FromType;
@@ -620,6 +619,12 @@ class TemplateDiff {
ToQual = FlatTree[ReadNode].ToQual;
}
+ /// GetNode - Gets the FromValueDecl and ToValueDecl.
+ void GetNode(ValueDecl *&FromValueDecl, ValueDecl *&ToValueDecl) {
+ FromValueDecl = FlatTree[ReadNode].FromValueDecl;
+ ToValueDecl = FlatTree[ReadNode].ToValueDecl;
+ }
+
/// NodeIsSame - Returns true the arguments are the same.
bool NodeIsSame() {
return FlatTree[ReadNode].Same;
@@ -662,9 +667,12 @@ class TemplateDiff {
/// Empty - Returns true if the tree has no information.
bool Empty() {
- return !FlatTree[0].FromTD && !FlatTree[0].ToTD &&
- !FlatTree[0].FromExpr && !FlatTree[0].ToExpr &&
- FlatTree[0].FromType.isNull() && FlatTree[0].ToType.isNull();
+ return GetKind() == Invalid;
+ }
+
+ /// GetKind - Returns the current node's type.
+ DiffKind GetKind() {
+ return FlatTree[ReadNode].Kind;
}
};
@@ -681,6 +689,10 @@ class TemplateDiff {
/// traverse over.
const TemplateSpecializationType *TST;
+ /// DesugarTST - desugared template specialization used to extract
+ /// default argument information
+ const TemplateSpecializationType *DesugarTST;
+
/// Index - the index of the template argument in TST.
unsigned Index;
@@ -693,8 +705,10 @@ class TemplateDiff {
/// TSTiterator - Constructs an iterator and sets it to the first template
/// argument.
- TSTiterator(const TemplateSpecializationType *TST)
- : TST(TST), Index(0), CurrentTA(0), EndTA(0) {
+ TSTiterator(ASTContext &Context, const TemplateSpecializationType *TST)
+ : TST(TST),
+ DesugarTST(GetTemplateSpecializationType(Context, TST->desugar())),
+ Index(0), CurrentTA(0), EndTA(0) {
if (isEnd()) return;
// Set to first template argument. If not a parameter pack, done.
@@ -715,12 +729,17 @@ class TemplateDiff {
/// isEnd - Returns true if the iterator is one past the end.
bool isEnd() const {
- return Index == TST->getNumArgs();
+ return Index >= TST->getNumArgs();
}
/// &operator++ - Increment the iterator to the next template argument.
TSTiterator &operator++() {
- assert(!isEnd() && "Iterator incremented past end of arguments.");
+ // After the end, Index should be the default argument position in
+ // DesugarTST, if it exists.
+ if (isEnd()) {
+ ++Index;
+ return *this;
+ }
// If in a parameter pack, advance in the parameter pack.
if (CurrentTA != EndTA) {
@@ -761,6 +780,11 @@ class TemplateDiff {
pointer operator->() const {
return &operator*();
}
+
+ /// getDesugar - Returns the deduced template argument from DesguarTST
+ reference getDesugar() const {
+ return DesugarTST->getArg(Index);
+ }
};
// These functions build up the template diff tree, including functions to
@@ -787,7 +811,7 @@ class TemplateDiff {
TemplateName(CTSD->getSpecializedTemplate()),
CTSD->getTemplateArgs().data(),
CTSD->getTemplateArgs().size(),
- Ty.getCanonicalType());
+ Ty.getLocalUnqualifiedType().getCanonicalType());
return Ty->getAs<TemplateSpecializationType>();
}
@@ -800,7 +824,7 @@ class TemplateDiff {
TemplateParameterList *Params =
FromTST->getTemplateName().getAsTemplateDecl()->getTemplateParameters();
unsigned TotalArgs = 0;
- for (TSTiterator FromIter(FromTST), ToIter(ToTST);
+ for (TSTiterator FromIter(Context, FromTST), ToIter(Context, ToTST);
!FromIter.isEnd() || !ToIter.isEnd(); ++TotalArgs) {
Tree.AddNode();
@@ -814,11 +838,12 @@ class TemplateDiff {
if (TemplateTypeParmDecl *DefaultTTPD =
dyn_cast<TemplateTypeParmDecl>(ParamND)) {
QualType FromType, ToType;
- GetType(FromIter, DefaultTTPD, FromType);
- GetType(ToIter, DefaultTTPD, ToType);
+ FromType = GetType(FromIter, DefaultTTPD);
+ ToType = GetType(ToIter, DefaultTTPD);
Tree.SetNode(FromType, ToType);
Tree.SetDefault(FromIter.isEnd() && !FromType.isNull(),
ToIter.isEnd() && !ToType.isNull());
+ Tree.SetKind(DiffTree::Type);
if (!FromType.isNull() && !ToType.isNull()) {
if (Context.hasSameType(FromType, ToType)) {
Tree.SetSame(true);
@@ -837,6 +862,7 @@ class TemplateDiff {
Tree.SetNode(FromArgTST->getTemplateName().getAsTemplateDecl(),
ToArgTST->getTemplateName().getAsTemplateDecl());
Tree.SetNode(FromQual, ToQual);
+ Tree.SetKind(DiffTree::Template);
DiffTemplate(FromArgTST, ToArgTST);
}
}
@@ -846,41 +872,83 @@ class TemplateDiff {
// Handle Expressions
if (NonTypeTemplateParmDecl *DefaultNTTPD =
dyn_cast<NonTypeTemplateParmDecl>(ParamND)) {
- Expr *FromExpr, *ToExpr;
+ Expr *FromExpr = 0, *ToExpr = 0;
llvm::APSInt FromInt, ToInt;
+ ValueDecl *FromValueDecl = 0, *ToValueDecl = 0;
+ unsigned ParamWidth = 128; // Safe default
+ if (DefaultNTTPD->getType()->isIntegralOrEnumerationType())
+ ParamWidth = Context.getIntWidth(DefaultNTTPD->getType());
bool HasFromInt = !FromIter.isEnd() &&
FromIter->getKind() == TemplateArgument::Integral;
bool HasToInt = !ToIter.isEnd() &&
ToIter->getKind() == TemplateArgument::Integral;
- //bool IsValidFromInt = false, IsValidToInt = false;
+ bool HasFromValueDecl =
+ !FromIter.isEnd() &&
+ FromIter->getKind() == TemplateArgument::Declaration;
+ bool HasToValueDecl =
+ !ToIter.isEnd() &&
+ ToIter->getKind() == TemplateArgument::Declaration;
+
+ assert(((!HasFromInt && !HasToInt) ||
+ (!HasFromValueDecl && !HasToValueDecl)) &&
+ "Template argument cannot be both integer and declaration");
+
if (HasFromInt)
FromInt = FromIter->getAsIntegral();
+ else if (HasFromValueDecl)
+ FromValueDecl = FromIter->getAsDecl();
else
- GetExpr(FromIter, DefaultNTTPD, FromExpr);
+ FromExpr = GetExpr(FromIter, DefaultNTTPD);
if (HasToInt)
ToInt = ToIter->getAsIntegral();
+ else if (HasToValueDecl)
+ ToValueDecl = ToIter->getAsDecl();
else
- GetExpr(ToIter, DefaultNTTPD, ToExpr);
+ ToExpr = GetExpr(ToIter, DefaultNTTPD);
- if (!HasFromInt && !HasToInt) {
+ if (!HasFromInt && !HasToInt && !HasFromValueDecl && !HasToValueDecl) {
Tree.SetNode(FromExpr, ToExpr);
- Tree.SetSame(IsEqualExpr(Context, FromExpr, ToExpr));
Tree.SetDefault(FromIter.isEnd() && FromExpr,
ToIter.isEnd() && ToExpr);
- } else {
+ if (DefaultNTTPD->getType()->isIntegralOrEnumerationType()) {
+ if (FromExpr)
+ FromInt = GetInt(FromIter, FromExpr);
+ if (ToExpr)
+ ToInt = GetInt(ToIter, ToExpr);
+ Tree.SetNode(FromInt, ToInt, FromExpr, ToExpr);
+ Tree.SetSame(IsSameConvertedInt(ParamWidth, FromInt, ToInt));
+ Tree.SetKind(DiffTree::Integer);
+ } else {
+ Tree.SetSame(IsEqualExpr(Context, ParamWidth, FromExpr, ToExpr));
+ Tree.SetKind(DiffTree::Expression);
+ }
+ } else if (HasFromInt || HasToInt) {
if (!HasFromInt && FromExpr) {
- FromInt = FromExpr->EvaluateKnownConstInt(Context);
+ FromInt = GetInt(FromIter, FromExpr);
HasFromInt = true;
}
if (!HasToInt && ToExpr) {
- ToInt = ToExpr->EvaluateKnownConstInt(Context);
+ ToInt = GetInt(ToIter, ToExpr);
HasToInt = true;
}
Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt);
- Tree.SetSame(llvm::APSInt::isSameValue(FromInt, ToInt));
+ Tree.SetSame(IsSameConvertedInt(ParamWidth, FromInt, ToInt));
Tree.SetDefault(FromIter.isEnd() && HasFromInt,
ToIter.isEnd() && HasToInt);
+ Tree.SetKind(DiffTree::Integer);
+ } else {
+ if (!HasFromValueDecl && FromExpr)
+ FromValueDecl = GetValueDecl(FromIter, FromExpr);
+ if (!HasToValueDecl && ToExpr)
+ ToValueDecl = GetValueDecl(ToIter, ToExpr);
+ Tree.SetNode(FromValueDecl, ToValueDecl);
+ Tree.SetSame(FromValueDecl && ToValueDecl &&
+ FromValueDecl->getCanonicalDecl() ==
+ ToValueDecl->getCanonicalDecl());
+ Tree.SetDefault(FromIter.isEnd() && FromValueDecl,
+ ToIter.isEnd() && ToValueDecl);
+ Tree.SetKind(DiffTree::Declaration);
}
}
@@ -888,15 +956,17 @@ class TemplateDiff {
if (TemplateTemplateParmDecl *DefaultTTPD =
dyn_cast<TemplateTemplateParmDecl>(ParamND)) {
TemplateDecl *FromDecl, *ToDecl;
- GetTemplateDecl(FromIter, DefaultTTPD, FromDecl);
- GetTemplateDecl(ToIter, DefaultTTPD, ToDecl);
+ FromDecl = GetTemplateDecl(FromIter, DefaultTTPD);
+ ToDecl = GetTemplateDecl(ToIter, DefaultTTPD);
Tree.SetNode(FromDecl, ToDecl);
- Tree.SetSame(FromDecl && ToDecl &&
- FromDecl->getIdentifier() == ToDecl->getIdentifier());
+ Tree.SetSame(
+ FromDecl && ToDecl &&
+ FromDecl->getCanonicalDecl() == ToDecl->getCanonicalDecl());
+ Tree.SetKind(DiffTree::TemplateTemplate);
}
- if (!FromIter.isEnd()) ++FromIter;
- if (!ToIter.isEnd()) ++ToIter;
+ ++FromIter;
+ ++ToIter;
Tree.Up();
}
}
@@ -917,8 +987,8 @@ class TemplateDiff {
/// even if the template arguments are not.
static bool hasSameBaseTemplate(const TemplateSpecializationType *FromTST,
const TemplateSpecializationType *ToTST) {
- return FromTST->getTemplateName().getAsTemplateDecl()->getIdentifier() ==
- ToTST->getTemplateName().getAsTemplateDecl()->getIdentifier();
+ return FromTST->getTemplateName().getAsTemplateDecl()->getCanonicalDecl() ==
+ ToTST->getTemplateName().getAsTemplateDecl()->getCanonicalDecl();
}
/// hasSameTemplate - Returns true if both types are specialized from the
@@ -962,22 +1032,21 @@ class TemplateDiff {
/// GetType - Retrieves the template type arguments, including default
/// arguments.
- void GetType(const TSTiterator &Iter, TemplateTypeParmDecl *DefaultTTPD,
- QualType &ArgType) {
- ArgType = QualType();
+ QualType GetType(const TSTiterator &Iter, TemplateTypeParmDecl *DefaultTTPD) {
bool isVariadic = DefaultTTPD->isParameterPack();
if (!Iter.isEnd())
- ArgType = Iter->getAsType();
- else if (!isVariadic)
- ArgType = DefaultTTPD->getDefaultArgument();
+ return Iter->getAsType();
+ if (!isVariadic)
+ return DefaultTTPD->getDefaultArgument();
+
+ return QualType();
}
/// GetExpr - Retrieves the template expression argument, including default
/// arguments.
- void GetExpr(const TSTiterator &Iter, NonTypeTemplateParmDecl *DefaultNTTPD,
- Expr *&ArgExpr) {
- ArgExpr = 0;
+ Expr *GetExpr(const TSTiterator &Iter, NonTypeTemplateParmDecl *DefaultNTTPD) {
+ Expr *ArgExpr = 0;
bool isVariadic = DefaultNTTPD->isParameterPack();
if (!Iter.isEnd())
@@ -989,14 +1058,50 @@ class TemplateDiff {
while (SubstNonTypeTemplateParmExpr *SNTTPE =
dyn_cast<SubstNonTypeTemplateParmExpr>(ArgExpr))
ArgExpr = SNTTPE->getReplacement();
+
+ return ArgExpr;
+ }
+
+ /// GetInt - Retrieves the template integer argument, including evaluating
+ /// default arguments.
+ llvm::APInt GetInt(const TSTiterator &Iter, Expr *ArgExpr) {
+ // Default, value-depenedent expressions require fetching
+ // from the desugared TemplateArgument
+ if (Iter.isEnd() && ArgExpr->isValueDependent())
+ switch (Iter.getDesugar().getKind()) {
+ case TemplateArgument::Integral:
+ return Iter.getDesugar().getAsIntegral();
+ case TemplateArgument::Expression:
+ ArgExpr = Iter.getDesugar().getAsExpr();
+ return ArgExpr->EvaluateKnownConstInt(Context);
+ default:
+ assert(0 && "Unexpected template argument kind");
+ }
+ return ArgExpr->EvaluateKnownConstInt(Context);
+ }
+
+ /// GetValueDecl - Retrieves the template integer argument, including
+ /// default expression argument.
+ ValueDecl *GetValueDecl(const TSTiterator &Iter, Expr *ArgExpr) {
+ // Default, value-depenedent expressions require fetching
+ // from the desugared TemplateArgument
+ if (Iter.isEnd() && ArgExpr->isValueDependent())
+ switch (Iter.getDesugar().getKind()) {
+ case TemplateArgument::Declaration:
+ return Iter.getDesugar().getAsDecl();
+ case TemplateArgument::Expression:
+ ArgExpr = Iter.getDesugar().getAsExpr();
+ return cast<DeclRefExpr>(ArgExpr)->getDecl();
+ default:
+ assert(0 && "Unexpected template argument kind");
+ }
+ return cast<DeclRefExpr>(ArgExpr)->getDecl();
}
/// GetTemplateDecl - Retrieves the template template arguments, including
/// default arguments.
- void GetTemplateDecl(const TSTiterator &Iter,
- TemplateTemplateParmDecl *DefaultTTPD,
- TemplateDecl *&ArgDecl) {
- ArgDecl = 0;
+ TemplateDecl *GetTemplateDecl(const TSTiterator &Iter,
+ TemplateTemplateParmDecl *DefaultTTPD) {
bool isVariadic = DefaultTTPD->isParameterPack();
TemplateArgument TA = DefaultTTPD->getDefaultArgument().getArgument();
@@ -1005,13 +1110,25 @@ class TemplateDiff {
DefaultTD = TA.getAsTemplate().getAsTemplateDecl();
if (!Iter.isEnd())
- ArgDecl = Iter->getAsTemplate().getAsTemplateDecl();
- else if (!isVariadic)
- ArgDecl = DefaultTD;
+ return Iter->getAsTemplate().getAsTemplateDecl();
+ if (!isVariadic)
+ return DefaultTD;
+
+ return 0;
+ }
+
+ /// IsSameConvertedInt - Returns true if both integers are equal when
+ /// converted to an integer type with the given width.
+ static bool IsSameConvertedInt(unsigned Width, const llvm::APSInt &X,
+ const llvm::APSInt &Y) {
+ llvm::APInt ConvertedX = X.extOrTrunc(Width);
+ llvm::APInt ConvertedY = Y.extOrTrunc(Width);
+ return ConvertedX == ConvertedY;
}
/// IsEqualExpr - Returns true if the expressions evaluate to the same value.
- static bool IsEqualExpr(ASTContext &Context, Expr *FromExpr, Expr *ToExpr) {
+ static bool IsEqualExpr(ASTContext &Context, unsigned ParamWidth,
+ Expr *FromExpr, Expr *ToExpr) {
if (FromExpr == ToExpr)
return true;
@@ -1033,7 +1150,7 @@ class TemplateDiff {
Expr::EvalResult FromResult, ToResult;
if (!FromExpr->EvaluateAsRValue(FromResult, Context) ||
!ToExpr->EvaluateAsRValue(ToResult, Context))
- assert(0 && "Template arguments must be known at compile time.");
+ return false;
APValue &FromVal = FromResult.Val;
APValue &ToVal = ToResult.Val;
@@ -1042,7 +1159,7 @@ class TemplateDiff {
switch (FromVal.getKind()) {
case APValue::Int:
- return FromVal.getInt() == ToVal.getInt();
+ return IsSameConvertedInt(ParamWidth, FromVal.getInt(), ToVal.getInt());
case APValue::LValue: {
APValue::LValueBase FromBase = FromVal.getLValueBase();
APValue::LValueBase ToBase = ToVal.getLValueBase();
@@ -1068,81 +1185,97 @@ class TemplateDiff {
void TreeToString(int Indent = 1) {
if (PrintTree) {
OS << '\n';
- for (int i = 0; i < Indent; ++i)
- OS << " ";
+ OS.indent(2 * Indent);
++Indent;
}
// Handle cases where the difference is not templates with different
// arguments.
- if (!Tree.NodeIsTemplate()) {
- if (Tree.NodeIsQualType()) {
+ switch (Tree.GetKind()) {
+ case DiffTree::Invalid:
+ llvm_unreachable("Template diffing failed with bad DiffNode");
+ case DiffTree::Type: {
QualType FromType, ToType;
Tree.GetNode(FromType, ToType);
PrintTypeNames(FromType, ToType, Tree.FromDefault(), Tree.ToDefault(),
Tree.NodeIsSame());
return;
}
- if (Tree.NodeIsExpr()) {
+ case DiffTree::Expression: {
Expr *FromExpr, *ToExpr;
Tree.GetNode(FromExpr, ToExpr);
PrintExpr(FromExpr, ToExpr, Tree.FromDefault(), Tree.ToDefault(),
Tree.NodeIsSame());
return;
}
- if (Tree.NodeIsTemplateTemplate()) {
+ case DiffTree::TemplateTemplate: {
TemplateDecl *FromTD, *ToTD;
Tree.GetNode(FromTD, ToTD);
PrintTemplateTemplate(FromTD, ToTD, Tree.FromDefault(),
Tree.ToDefault(), Tree.NodeIsSame());
return;
}
-
- if (Tree.NodeIsAPSInt()) {
+ case DiffTree::Integer: {
llvm::APSInt FromInt, ToInt;
+ Expr *FromExpr, *ToExpr;
bool IsValidFromInt, IsValidToInt;
+ Tree.GetNode(FromExpr, ToExpr);
Tree.GetNode(FromInt, ToInt, IsValidFromInt, IsValidToInt);
PrintAPSInt(FromInt, ToInt, IsValidFromInt, IsValidToInt,
- Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame());
+ FromExpr, ToExpr, Tree.FromDefault(), Tree.ToDefault(),
+ Tree.NodeIsSame());
return;
}
- llvm_unreachable("Unable to deduce template difference.");
- }
-
- // Node is root of template. Recurse on children.
- TemplateDecl *FromTD, *ToTD;
- Tree.GetNode(FromTD, ToTD);
-
- assert(Tree.HasChildren() && "Template difference not found in diff tree.");
-
- Qualifiers FromQual, ToQual;
- Tree.GetNode(FromQual, ToQual);
- PrintQualifiers(FromQual, ToQual);
+ case DiffTree::Declaration: {
+ ValueDecl *FromValueDecl, *ToValueDecl;
+ Tree.GetNode(FromValueDecl, ToValueDecl);
+ PrintValueDecl(FromValueDecl, ToValueDecl, Tree.FromDefault(),
+ Tree.ToDefault(), Tree.NodeIsSame());
+ return;
+ }
+ case DiffTree::Template: {
+ // Node is root of template. Recurse on children.
+ TemplateDecl *FromTD, *ToTD;
+ Tree.GetNode(FromTD, ToTD);
- OS << FromTD->getNameAsString() << '<';
- Tree.MoveToChild();
- unsigned NumElideArgs = 0;
- do {
- if (ElideType) {
- if (Tree.NodeIsSame()) {
- ++NumElideArgs;
- continue;
+ if (!Tree.HasChildren()) {
+ // If we're dealing with a template specialization with zero
+ // arguments, there are no children; special-case this.
+ OS << FromTD->getNameAsString() << "<>";
+ return;
}
- if (NumElideArgs > 0) {
+
+ Qualifiers FromQual, ToQual;
+ Tree.GetNode(FromQual, ToQual);
+ PrintQualifiers(FromQual, ToQual);
+
+ OS << FromTD->getNameAsString() << '<';
+ Tree.MoveToChild();
+ unsigned NumElideArgs = 0;
+ do {
+ if (ElideType) {
+ if (Tree.NodeIsSame()) {
+ ++NumElideArgs;
+ continue;
+ }
+ if (NumElideArgs > 0) {
+ PrintElideArgs(NumElideArgs, Indent);
+ NumElideArgs = 0;
+ OS << ", ";
+ }
+ }
+ TreeToString(Indent);
+ if (Tree.HasNextSibling())
+ OS << ", ";
+ } while (Tree.AdvanceSibling());
+ if (NumElideArgs > 0)
PrintElideArgs(NumElideArgs, Indent);
- NumElideArgs = 0;
- OS << ", ";
- }
+
+ Tree.Parent();
+ OS << ">";
+ return;
}
- TreeToString(Indent);
- if (Tree.HasNextSibling())
- OS << ", ";
- } while (Tree.AdvanceSibling());
- if (NumElideArgs > 0)
- PrintElideArgs(NumElideArgs, Indent);
-
- Tree.Parent();
- OS << ">";
+ }
}
// To signal to the text printer that a certain text needs to be bolded,
@@ -1260,21 +1393,29 @@ class TemplateDiff {
void PrintTemplateTemplate(TemplateDecl *FromTD, TemplateDecl *ToTD,
bool FromDefault, bool ToDefault, bool Same) {
assert((FromTD || ToTD) && "Only one template argument may be missing.");
+
+ std::string FromName = FromTD ? FromTD->getName() : "(no argument)";
+ std::string ToName = ToTD ? ToTD->getName() : "(no argument)";
+ if (FromTD && ToTD && FromName == ToName) {
+ FromName = FromTD->getQualifiedNameAsString();
+ ToName = ToTD->getQualifiedNameAsString();
+ }
+
if (Same) {
OS << "template " << FromTD->getNameAsString();
} else if (!PrintTree) {
OS << (FromDefault ? "(default) template " : "template ");
Bold();
- OS << (FromTD ? FromTD->getNameAsString() : "(no argument)");
+ OS << FromName;
Unbold();
} else {
OS << (FromDefault ? "[(default) template " : "[template ");
Bold();
- OS << (FromTD ? FromTD->getNameAsString() : "(no argument)");
+ OS << FromName;
Unbold();
OS << " != " << (ToDefault ? "(default) template " : "template ");
Bold();
- OS << (ToTD ? ToTD->getNameAsString() : "(no argument)");
+ OS << ToName;
Unbold();
OS << ']';
}
@@ -1283,8 +1424,8 @@ class TemplateDiff {
/// PrintAPSInt - Handles printing of integral arguments, highlighting
/// argument differences.
void PrintAPSInt(llvm::APSInt FromInt, llvm::APSInt ToInt,
- bool IsValidFromInt, bool IsValidToInt, bool FromDefault,
- bool ToDefault, bool Same) {
+ bool IsValidFromInt, bool IsValidToInt, Expr *FromExpr,
+ Expr *ToExpr, bool FromDefault, bool ToDefault, bool Same) {
assert((IsValidFromInt || IsValidToInt) &&
"Only one integral argument may be missing.");
@@ -1292,20 +1433,74 @@ class TemplateDiff {
OS << FromInt.toString(10);
} else if (!PrintTree) {
OS << (FromDefault ? "(default) " : "");
+ PrintAPSInt(FromInt, FromExpr, IsValidFromInt);
+ } else {
+ OS << (FromDefault ? "[(default) " : "[");
+ PrintAPSInt(FromInt, FromExpr, IsValidFromInt);
+ OS << " != " << (ToDefault ? "(default) " : "");
+ PrintAPSInt(ToInt, ToExpr, IsValidToInt);
+ OS << ']';
+ }
+ }
+
+ /// PrintAPSInt - If valid, print the APSInt. If the expression is
+ /// gives more information, print it too.
+ void PrintAPSInt(llvm::APSInt Val, Expr *E, bool Valid) {
+ Bold();
+ if (Valid) {
+ if (HasExtraInfo(E)) {
+ PrintExpr(E);
+ Unbold();
+ OS << " aka ";
+ Bold();
+ }
+ OS << Val.toString(10);
+ } else {
+ OS << "(no argument)";
+ }
+ Unbold();
+ }
+
+ /// HasExtraInfo - Returns true if E is not an integer literal or the
+ /// negation of an integer literal
+ bool HasExtraInfo(Expr *E) {
+ if (!E) return false;
+ if (isa<IntegerLiteral>(E)) return false;
+
+ if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E))
+ if (UO->getOpcode() == UO_Minus)
+ if (isa<IntegerLiteral>(UO->getSubExpr()))
+ return false;
+
+ return true;
+ }
+
+ /// PrintDecl - Handles printing of Decl arguments, highlighting
+ /// argument differences.
+ void PrintValueDecl(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl,
+ bool FromDefault, bool ToDefault, bool Same) {
+ assert((FromValueDecl || ToValueDecl) &&
+ "Only one Decl argument may be NULL");
+
+ if (Same) {
+ OS << FromValueDecl->getName();
+ } else if (!PrintTree) {
+ OS << (FromDefault ? "(default) " : "");
Bold();
- OS << (IsValidFromInt ? FromInt.toString(10) : "(no argument)");
+ OS << (FromValueDecl ? FromValueDecl->getName() : "(no argument)");
Unbold();
} else {
OS << (FromDefault ? "[(default) " : "[");
Bold();
- OS << (IsValidFromInt ? FromInt.toString(10) : "(no argument)");
+ OS << (FromValueDecl ? FromValueDecl->getName() : "(no argument)");
Unbold();
OS << " != " << (ToDefault ? "(default) " : "");
Bold();
- OS << (IsValidToInt ? ToInt.toString(10) : "(no argument)");
+ OS << (ToValueDecl ? ToValueDecl->getName() : "(no argument)");
Unbold();
OS << ']';
}
+
}
// Prints the appropriate placeholder for elided template arguments.
@@ -1386,9 +1581,9 @@ class TemplateDiff {
public:
- TemplateDiff(ASTContext &Context, QualType FromType, QualType ToType,
- bool PrintTree, bool PrintFromType, bool ElideType,
- bool ShowColor)
+ TemplateDiff(raw_ostream &OS, ASTContext &Context, QualType FromType,
+ QualType ToType, bool PrintTree, bool PrintFromType,
+ bool ElideType, bool ShowColor)
: Context(Context),
Policy(Context.getLangOpts()),
ElideType(ElideType),
@@ -1397,7 +1592,7 @@ public:
// When printing a single type, the FromType is the one printed.
FromType(PrintFromType ? FromType : ToType),
ToType(PrintFromType ? ToType : FromType),
- OS(Str),
+ OS(OS),
IsBold(false) {
}
@@ -1424,6 +1619,7 @@ public:
ToQual -= QualType(ToOrigTST, 0).getQualifiers();
Tree.SetNode(FromType, ToType);
Tree.SetNode(FromQual, ToQual);
+ Tree.SetKind(DiffTree::Template);
// Same base template, but different arguments.
Tree.SetNode(FromOrigTST->getTemplateName().getAsTemplateDecl(),
@@ -1432,17 +1628,16 @@ public:
DiffTemplate(FromOrigTST, ToOrigTST);
}
- /// MakeString - When the two types given are templated types with the same
+ /// Emit - When the two types given are templated types with the same
/// base template, a string representation of the type difference will be
- /// loaded into S and return true. Otherwise, return false.
- bool MakeString(std::string &S) {
+ /// emitted to the stream and return true. Otherwise, return false.
+ bool Emit() {
Tree.StartTraverse();
if (Tree.Empty())
return false;
TreeToString();
assert(!IsBold && "Bold is applied to end of string.");
- S = OS.str();
return true;
}
}; // end class TemplateDiff
@@ -1454,11 +1649,11 @@ public:
static bool FormatTemplateTypeDiff(ASTContext &Context, QualType FromType,
QualType ToType, bool PrintTree,
bool PrintFromType, bool ElideType,
- bool ShowColors, std::string &S) {
+ bool ShowColors, raw_ostream &OS) {
if (PrintTree)
PrintFromType = true;
- TemplateDiff TD(Context, FromType, ToType, PrintTree, PrintFromType,
+ TemplateDiff TD(OS, Context, FromType, ToType, PrintTree, PrintFromType,
ElideType, ShowColors);
TD.DiffTemplate();
- return TD.MakeString(S);
+ return TD.Emit();
}
diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
new file mode 100644
index 0000000..b1d174b
--- /dev/null
+++ b/lib/AST/ASTDumper.cpp
@@ -0,0 +1,1996 @@
+//===--- ASTDumper.cpp - Dumping implementation for ASTs ------------------===//
+//
+// 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 AST dump methods, which dump out the
+// AST in a form that exposes type details and other fields.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/CommentVisitor.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/Module.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+using namespace clang::comments;
+
+//===----------------------------------------------------------------------===//
+// ASTDumper Visitor
+//===----------------------------------------------------------------------===//
+
+namespace {
+ // Colors used for various parts of the AST dump
+
+ struct TerminalColor {
+ raw_ostream::Colors Color;
+ bool Bold;
+ };
+
+ // Decl kind names (VarDecl, FunctionDecl, etc)
+ static const TerminalColor DeclKindNameColor = { raw_ostream::GREEN, true };
+ // Attr names (CleanupAttr, GuardedByAttr, etc)
+ static const TerminalColor AttrColor = { raw_ostream::BLUE, true };
+ // Statement names (DeclStmt, ImplicitCastExpr, etc)
+ static const TerminalColor StmtColor = { raw_ostream::MAGENTA, true };
+ // Comment names (FullComment, ParagraphComment, TextComment, etc)
+ static const TerminalColor CommentColor = { raw_ostream::YELLOW, true };
+
+ // Type names (int, float, etc, plus user defined types)
+ static const TerminalColor TypeColor = { raw_ostream::GREEN, false };
+
+ // Pointer address
+ static const TerminalColor AddressColor = { raw_ostream::YELLOW, false };
+ // Source locations
+ static const TerminalColor LocationColor = { raw_ostream::YELLOW, false };
+
+ // lvalue/xvalue
+ static const TerminalColor ValueKindColor = { raw_ostream::CYAN, false };
+ // bitfield/objcproperty/objcsubscript/vectorcomponent
+ static const TerminalColor ObjectKindColor = { raw_ostream::CYAN, false };
+
+ // Null statements
+ static const TerminalColor NullColor = { raw_ostream::BLUE, false };
+
+ // CastKind from CastExpr's
+ static const TerminalColor CastColor = { raw_ostream::RED, false };
+
+ // Value of the statement
+ static const TerminalColor ValueColor = { raw_ostream::CYAN, true };
+ // Decl names
+ static const TerminalColor DeclNameColor = { raw_ostream::CYAN, true };
+
+ // Indents ( `, -. | )
+ static const TerminalColor IndentColor = { raw_ostream::BLUE, false };
+
+ class ASTDumper
+ : public ConstDeclVisitor<ASTDumper>, public ConstStmtVisitor<ASTDumper>,
+ public ConstCommentVisitor<ASTDumper> {
+ raw_ostream &OS;
+ const CommandTraits *Traits;
+ const SourceManager *SM;
+ bool IsFirstLine;
+
+ // Indicates whether more child are expected at the current tree depth
+ enum IndentType { IT_Child, IT_LastChild };
+
+ /// Indents[i] indicates if another child exists at level i.
+ /// Used by Indent() to print the tree structure.
+ llvm::SmallVector<IndentType, 32> Indents;
+
+ /// Indicates that more children will be needed at this indent level.
+ /// If true, prevents lastChild() from marking the node as the last child.
+ /// This is used when there are multiple collections of children to be
+ /// dumped as well as during conditional node dumping.
+ bool MoreChildren;
+
+ /// Keep track of the last location we print out so that we can
+ /// print out deltas from then on out.
+ const char *LastLocFilename;
+ unsigned LastLocLine;
+
+ /// The \c FullComment parent of the comment being dumped.
+ const FullComment *FC;
+
+ bool ShowColors;
+
+ class IndentScope {
+ ASTDumper &Dumper;
+ // Preserve the Dumper's MoreChildren value from the previous IndentScope
+ bool MoreChildren;
+ public:
+ IndentScope(ASTDumper &Dumper) : Dumper(Dumper) {
+ MoreChildren = Dumper.hasMoreChildren();
+ Dumper.setMoreChildren(false);
+ Dumper.indent();
+ }
+ ~IndentScope() {
+ Dumper.setMoreChildren(MoreChildren);
+ Dumper.unindent();
+ }
+ };
+
+ class ColorScope {
+ ASTDumper &Dumper;
+ public:
+ ColorScope(ASTDumper &Dumper, TerminalColor Color)
+ : Dumper(Dumper) {
+ if (Dumper.ShowColors)
+ Dumper.OS.changeColor(Color.Color, Color.Bold);
+ }
+ ~ColorScope() {
+ if (Dumper.ShowColors)
+ Dumper.OS.resetColor();
+ }
+ };
+
+ public:
+ ASTDumper(raw_ostream &OS, const CommandTraits *Traits,
+ const SourceManager *SM)
+ : OS(OS), Traits(Traits), SM(SM), IsFirstLine(true), MoreChildren(false),
+ LastLocFilename(""), LastLocLine(~0U), FC(0),
+ ShowColors(SM && SM->getDiagnostics().getShowColors()) { }
+
+ ASTDumper(raw_ostream &OS, const CommandTraits *Traits,
+ const SourceManager *SM, bool ShowColors)
+ : OS(OS), Traits(Traits), SM(SM), IsFirstLine(true), MoreChildren(false),
+ LastLocFilename(""), LastLocLine(~0U),
+ ShowColors(ShowColors) { }
+
+ ~ASTDumper() {
+ OS << "\n";
+ }
+
+ void dumpDecl(const Decl *D);
+ void dumpStmt(const Stmt *S);
+ void dumpFullComment(const FullComment *C);
+
+ // Formatting
+ void indent();
+ void unindent();
+ void lastChild();
+ bool hasMoreChildren();
+ void setMoreChildren(bool Value);
+
+ // Utilities
+ void dumpPointer(const void *Ptr);
+ void dumpSourceRange(SourceRange R);
+ void dumpLocation(SourceLocation Loc);
+ void dumpBareType(QualType T);
+ void dumpType(QualType T);
+ void dumpBareDeclRef(const Decl *Node);
+ void dumpDeclRef(const Decl *Node, const char *Label = 0);
+ void dumpName(const NamedDecl *D);
+ bool hasNodes(const DeclContext *DC);
+ void dumpDeclContext(const DeclContext *DC);
+ void dumpAttr(const Attr *A);
+
+ // C++ Utilities
+ void dumpAccessSpecifier(AccessSpecifier AS);
+ void dumpCXXCtorInitializer(const CXXCtorInitializer *Init);
+ void dumpTemplateParameters(const TemplateParameterList *TPL);
+ void dumpTemplateArgumentListInfo(const TemplateArgumentListInfo &TALI);
+ void dumpTemplateArgumentLoc(const TemplateArgumentLoc &A);
+ void dumpTemplateArgumentList(const TemplateArgumentList &TAL);
+ void dumpTemplateArgument(const TemplateArgument &A,
+ SourceRange R = SourceRange());
+
+ // Decls
+ void VisitLabelDecl(const LabelDecl *D);
+ void VisitTypedefDecl(const TypedefDecl *D);
+ void VisitEnumDecl(const EnumDecl *D);
+ void VisitRecordDecl(const RecordDecl *D);
+ void VisitEnumConstantDecl(const EnumConstantDecl *D);
+ void VisitIndirectFieldDecl(const IndirectFieldDecl *D);
+ void VisitFunctionDecl(const FunctionDecl *D);
+ void VisitFieldDecl(const FieldDecl *D);
+ void VisitVarDecl(const VarDecl *D);
+ void VisitFileScopeAsmDecl(const FileScopeAsmDecl *D);
+ void VisitImportDecl(const ImportDecl *D);
+
+ // C++ Decls
+ void VisitNamespaceDecl(const NamespaceDecl *D);
+ void VisitUsingDirectiveDecl(const UsingDirectiveDecl *D);
+ void VisitNamespaceAliasDecl(const NamespaceAliasDecl *D);
+ void VisitTypeAliasDecl(const TypeAliasDecl *D);
+ void VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D);
+ void VisitCXXRecordDecl(const CXXRecordDecl *D);
+ void VisitStaticAssertDecl(const StaticAssertDecl *D);
+ void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D);
+ void VisitClassTemplateDecl(const ClassTemplateDecl *D);
+ void VisitClassTemplateSpecializationDecl(
+ const ClassTemplateSpecializationDecl *D);
+ void VisitClassTemplatePartialSpecializationDecl(
+ const ClassTemplatePartialSpecializationDecl *D);
+ void VisitClassScopeFunctionSpecializationDecl(
+ const ClassScopeFunctionSpecializationDecl *D);
+ void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D);
+ void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D);
+ void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D);
+ void VisitUsingDecl(const UsingDecl *D);
+ void VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D);
+ void VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D);
+ void VisitUsingShadowDecl(const UsingShadowDecl *D);
+ void VisitLinkageSpecDecl(const LinkageSpecDecl *D);
+ void VisitAccessSpecDecl(const AccessSpecDecl *D);
+ void VisitFriendDecl(const FriendDecl *D);
+
+ // ObjC Decls
+ void VisitObjCIvarDecl(const ObjCIvarDecl *D);
+ void VisitObjCMethodDecl(const ObjCMethodDecl *D);
+ void VisitObjCCategoryDecl(const ObjCCategoryDecl *D);
+ void VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D);
+ void VisitObjCProtocolDecl(const ObjCProtocolDecl *D);
+ void VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D);
+ void VisitObjCImplementationDecl(const ObjCImplementationDecl *D);
+ void VisitObjCCompatibleAliasDecl(const ObjCCompatibleAliasDecl *D);
+ void VisitObjCPropertyDecl(const ObjCPropertyDecl *D);
+ void VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D);
+ void VisitBlockDecl(const BlockDecl *D);
+
+ // Stmts.
+ void VisitStmt(const Stmt *Node);
+ void VisitDeclStmt(const DeclStmt *Node);
+ void VisitAttributedStmt(const AttributedStmt *Node);
+ void VisitLabelStmt(const LabelStmt *Node);
+ void VisitGotoStmt(const GotoStmt *Node);
+
+ // Exprs
+ void VisitExpr(const Expr *Node);
+ void VisitCastExpr(const CastExpr *Node);
+ void VisitDeclRefExpr(const DeclRefExpr *Node);
+ void VisitPredefinedExpr(const PredefinedExpr *Node);
+ void VisitCharacterLiteral(const CharacterLiteral *Node);
+ void VisitIntegerLiteral(const IntegerLiteral *Node);
+ void VisitFloatingLiteral(const FloatingLiteral *Node);
+ void VisitStringLiteral(const StringLiteral *Str);
+ void VisitUnaryOperator(const UnaryOperator *Node);
+ void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Node);
+ void VisitMemberExpr(const MemberExpr *Node);
+ void VisitExtVectorElementExpr(const ExtVectorElementExpr *Node);
+ void VisitBinaryOperator(const BinaryOperator *Node);
+ void VisitCompoundAssignOperator(const CompoundAssignOperator *Node);
+ void VisitAddrLabelExpr(const AddrLabelExpr *Node);
+ void VisitBlockExpr(const BlockExpr *Node);
+ void VisitOpaqueValueExpr(const OpaqueValueExpr *Node);
+
+ // C++
+ void VisitCXXNamedCastExpr(const CXXNamedCastExpr *Node);
+ void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *Node);
+ void VisitCXXThisExpr(const CXXThisExpr *Node);
+ void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node);
+ void VisitCXXConstructExpr(const CXXConstructExpr *Node);
+ void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node);
+ void VisitExprWithCleanups(const ExprWithCleanups *Node);
+ void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node);
+ void dumpCXXTemporary(const CXXTemporary *Temporary);
+
+ // ObjC
+ void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node);
+ void VisitObjCEncodeExpr(const ObjCEncodeExpr *Node);
+ void VisitObjCMessageExpr(const ObjCMessageExpr *Node);
+ void VisitObjCBoxedExpr(const ObjCBoxedExpr *Node);
+ void VisitObjCSelectorExpr(const ObjCSelectorExpr *Node);
+ void VisitObjCProtocolExpr(const ObjCProtocolExpr *Node);
+ void VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *Node);
+ void VisitObjCSubscriptRefExpr(const ObjCSubscriptRefExpr *Node);
+ void VisitObjCIvarRefExpr(const ObjCIvarRefExpr *Node);
+ void VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *Node);
+
+ // Comments.
+ const char *getCommandName(unsigned CommandID);
+ void dumpComment(const Comment *C);
+
+ // Inline comments.
+ void visitTextComment(const TextComment *C);
+ void visitInlineCommandComment(const InlineCommandComment *C);
+ void visitHTMLStartTagComment(const HTMLStartTagComment *C);
+ void visitHTMLEndTagComment(const HTMLEndTagComment *C);
+
+ // Block comments.
+ void visitBlockCommandComment(const BlockCommandComment *C);
+ void visitParamCommandComment(const ParamCommandComment *C);
+ void visitTParamCommandComment(const TParamCommandComment *C);
+ void visitVerbatimBlockComment(const VerbatimBlockComment *C);
+ void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
+ void visitVerbatimLineComment(const VerbatimLineComment *C);
+ };
+}
+
+//===----------------------------------------------------------------------===//
+// Utilities
+//===----------------------------------------------------------------------===//
+
+// Print out the appropriate tree structure using the Indents vector.
+// Example of tree and the Indents vector at each level.
+// A { }
+// |-B { IT_Child }
+// | `-C { IT_Child, IT_LastChild }
+// `-D { IT_LastChild }
+// |-E { IT_LastChild, IT_Child }
+// `-F { IT_LastChild, IT_LastChild }
+// Type non-last element, last element
+// IT_Child "| " "|-"
+// IT_LastChild " " "`-"
+void ASTDumper::indent() {
+ if (IsFirstLine)
+ IsFirstLine = false;
+ else
+ OS << "\n";
+
+ ColorScope Color(*this, IndentColor);
+ for (llvm::SmallVector<IndentType, 32>::const_iterator I = Indents.begin(),
+ E = Indents.end();
+ I != E; ++I) {
+ switch (*I) {
+ case IT_Child:
+ if (I == E - 1)
+ OS << "|-";
+ else
+ OS << "| ";
+ continue;
+ case IT_LastChild:
+ if (I == E - 1)
+ OS << "`-";
+ else
+ OS << " ";
+ continue;
+ }
+ llvm_unreachable("Invalid IndentType");
+ }
+ Indents.push_back(IT_Child);
+}
+
+void ASTDumper::unindent() {
+ Indents.pop_back();
+}
+
+// Call before each potential last child node is to be dumped. If MoreChildren
+// is false, then this is the last child, otherwise treat as a regular node.
+void ASTDumper::lastChild() {
+ if (!hasMoreChildren())
+ Indents.back() = IT_LastChild;
+}
+
+// MoreChildren should be set before calling another function that may print
+// additional nodes to prevent conflicting final child nodes.
+bool ASTDumper::hasMoreChildren() {
+ return MoreChildren;
+}
+
+void ASTDumper::setMoreChildren(bool Value) {
+ MoreChildren = Value;
+}
+
+void ASTDumper::dumpPointer(const void *Ptr) {
+ ColorScope Color(*this, AddressColor);
+ OS << ' ' << Ptr;
+}
+
+void ASTDumper::dumpLocation(SourceLocation Loc) {
+ ColorScope Color(*this, LocationColor);
+ SourceLocation SpellingLoc = SM->getSpellingLoc(Loc);
+
+ // The general format we print out is filename:line:col, but we drop pieces
+ // that haven't changed since the last loc printed.
+ PresumedLoc PLoc = SM->getPresumedLoc(SpellingLoc);
+
+ if (PLoc.isInvalid()) {
+ OS << "<invalid sloc>";
+ return;
+ }
+
+ if (strcmp(PLoc.getFilename(), LastLocFilename) != 0) {
+ OS << PLoc.getFilename() << ':' << PLoc.getLine()
+ << ':' << PLoc.getColumn();
+ LastLocFilename = PLoc.getFilename();
+ LastLocLine = PLoc.getLine();
+ } else if (PLoc.getLine() != LastLocLine) {
+ OS << "line" << ':' << PLoc.getLine()
+ << ':' << PLoc.getColumn();
+ LastLocLine = PLoc.getLine();
+ } else {
+ OS << "col" << ':' << PLoc.getColumn();
+ }
+}
+
+void ASTDumper::dumpSourceRange(SourceRange R) {
+ // Can't translate locations if a SourceManager isn't available.
+ if (!SM)
+ return;
+
+ OS << " <";
+ dumpLocation(R.getBegin());
+ if (R.getBegin() != R.getEnd()) {
+ OS << ", ";
+ dumpLocation(R.getEnd());
+ }
+ OS << ">";
+
+ // <t2.c:123:421[blah], t2.c:412:321>
+
+}
+
+void ASTDumper::dumpBareType(QualType T) {
+ ColorScope Color(*this, TypeColor);
+
+ SplitQualType T_split = T.split();
+ OS << "'" << QualType::getAsString(T_split) << "'";
+
+ if (!T.isNull()) {
+ // If the type is sugared, also dump a (shallow) desugared type.
+ SplitQualType D_split = T.getSplitDesugaredType();
+ if (T_split != D_split)
+ OS << ":'" << QualType::getAsString(D_split) << "'";
+ }
+}
+
+void ASTDumper::dumpType(QualType T) {
+ OS << ' ';
+ dumpBareType(T);
+}
+
+void ASTDumper::dumpBareDeclRef(const Decl *D) {
+ {
+ ColorScope Color(*this, DeclKindNameColor);
+ OS << D->getDeclKindName();
+ }
+ dumpPointer(D);
+
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
+ ColorScope Color(*this, DeclNameColor);
+ OS << " '";
+ ND->getDeclName().printName(OS);
+ OS << "'";
+ }
+
+ if (const ValueDecl *VD = dyn_cast<ValueDecl>(D))
+ dumpType(VD->getType());
+}
+
+void ASTDumper::dumpDeclRef(const Decl *D, const char *Label) {
+ if (!D)
+ return;
+
+ IndentScope Indent(*this);
+ if (Label)
+ OS << Label << ' ';
+ dumpBareDeclRef(D);
+}
+
+void ASTDumper::dumpName(const NamedDecl *ND) {
+ if (ND->getDeclName()) {
+ ColorScope Color(*this, DeclNameColor);
+ OS << ' ' << ND->getNameAsString();
+ }
+}
+
+bool ASTDumper::hasNodes(const DeclContext *DC) {
+ if (!DC)
+ return false;
+
+ return DC->decls_begin() != DC->decls_end();
+}
+
+void ASTDumper::dumpDeclContext(const DeclContext *DC) {
+ if (!DC)
+ return;
+ for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end();
+ I != E; ++I) {
+ DeclContext::decl_iterator Next = I;
+ ++Next;
+ if (Next == E)
+ lastChild();
+ dumpDecl(*I);
+ }
+}
+
+void ASTDumper::dumpAttr(const Attr *A) {
+ IndentScope Indent(*this);
+ {
+ ColorScope Color(*this, AttrColor);
+ switch (A->getKind()) {
+#define ATTR(X) case attr::X: OS << #X; break;
+#include "clang/Basic/AttrList.inc"
+ default: llvm_unreachable("unexpected attribute kind");
+ }
+ OS << "Attr";
+ }
+ dumpPointer(A);
+ dumpSourceRange(A->getRange());
+#include "clang/AST/AttrDump.inc"
+}
+
+static Decl *getPreviousDeclImpl(...) {
+ return 0;
+}
+
+template<typename T>
+static const Decl *getPreviousDeclImpl(const Redeclarable<T> *D) {
+ return D->getPreviousDecl();
+}
+
+/// Get the previous declaration in the redeclaration chain for a declaration.
+static const Decl *getPreviousDecl(const Decl *D) {
+ switch (D->getKind()) {
+#define DECL(DERIVED, BASE) \
+ case Decl::DERIVED: \
+ return getPreviousDeclImpl(cast<DERIVED##Decl>(D));
+#define ABSTRACT_DECL(DECL)
+#include "clang/AST/DeclNodes.inc"
+ }
+ llvm_unreachable("Decl that isn't part of DeclNodes.inc!");
+}
+
+//===----------------------------------------------------------------------===//
+// C++ Utilities
+//===----------------------------------------------------------------------===//
+
+void ASTDumper::dumpAccessSpecifier(AccessSpecifier AS) {
+ switch (AS) {
+ case AS_none:
+ break;
+ case AS_public:
+ OS << "public";
+ break;
+ case AS_protected:
+ OS << "protected";
+ break;
+ case AS_private:
+ OS << "private";
+ break;
+ }
+}
+
+void ASTDumper::dumpCXXCtorInitializer(const CXXCtorInitializer *Init) {
+ IndentScope Indent(*this);
+ OS << "CXXCtorInitializer";
+ if (Init->isAnyMemberInitializer()) {
+ OS << ' ';
+ dumpBareDeclRef(Init->getAnyMember());
+ } else {
+ dumpType(QualType(Init->getBaseClass(), 0));
+ }
+ dumpStmt(Init->getInit());
+}
+
+void ASTDumper::dumpTemplateParameters(const TemplateParameterList *TPL) {
+ if (!TPL)
+ return;
+
+ for (TemplateParameterList::const_iterator I = TPL->begin(), E = TPL->end();
+ I != E; ++I)
+ dumpDecl(*I);
+}
+
+void ASTDumper::dumpTemplateArgumentListInfo(
+ const TemplateArgumentListInfo &TALI) {
+ for (unsigned i = 0, e = TALI.size(); i < e; ++i) {
+ if (i + 1 == e)
+ lastChild();
+ dumpTemplateArgumentLoc(TALI[i]);
+ }
+}
+
+void ASTDumper::dumpTemplateArgumentLoc(const TemplateArgumentLoc &A) {
+ dumpTemplateArgument(A.getArgument(), A.getSourceRange());
+}
+
+void ASTDumper::dumpTemplateArgumentList(const TemplateArgumentList &TAL) {
+ for (unsigned i = 0, e = TAL.size(); i < e; ++i)
+ dumpTemplateArgument(TAL[i]);
+}
+
+void ASTDumper::dumpTemplateArgument(const TemplateArgument &A, SourceRange R) {
+ IndentScope Indent(*this);
+ OS << "TemplateArgument";
+ if (R.isValid())
+ dumpSourceRange(R);
+
+ switch (A.getKind()) {
+ case TemplateArgument::Null:
+ OS << " null";
+ break;
+ case TemplateArgument::Type:
+ OS << " type";
+ lastChild();
+ dumpType(A.getAsType());
+ break;
+ case TemplateArgument::Declaration:
+ OS << " decl";
+ lastChild();
+ dumpDeclRef(A.getAsDecl());
+ break;
+ case TemplateArgument::NullPtr:
+ OS << " nullptr";
+ break;
+ case TemplateArgument::Integral:
+ OS << " integral " << A.getAsIntegral();
+ break;
+ case TemplateArgument::Template:
+ OS << " template ";
+ A.getAsTemplate().dump(OS);
+ break;
+ case TemplateArgument::TemplateExpansion:
+ OS << " template expansion";
+ A.getAsTemplateOrTemplatePattern().dump(OS);
+ break;
+ case TemplateArgument::Expression:
+ OS << " expr";
+ lastChild();
+ dumpStmt(A.getAsExpr());
+ break;
+ case TemplateArgument::Pack:
+ OS << " pack";
+ for (TemplateArgument::pack_iterator I = A.pack_begin(), E = A.pack_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpTemplateArgument(*I);
+ }
+ break;
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Decl dumping methods.
+//===----------------------------------------------------------------------===//
+
+void ASTDumper::dumpDecl(const Decl *D) {
+ IndentScope Indent(*this);
+
+ if (!D) {
+ ColorScope Color(*this, NullColor);
+ OS << "<<<NULL>>>";
+ return;
+ }
+
+ {
+ ColorScope Color(*this, DeclKindNameColor);
+ OS << D->getDeclKindName() << "Decl";
+ }
+ dumpPointer(D);
+ if (D->getLexicalDeclContext() != D->getDeclContext())
+ OS << " parent " << cast<Decl>(D->getDeclContext());
+ if (const Decl *Prev = getPreviousDecl(D))
+ OS << " prev " << Prev;
+ dumpSourceRange(D->getSourceRange());
+
+ bool HasAttrs = D->attr_begin() != D->attr_end();
+ bool HasComment = D->getASTContext().getCommentForDecl(D, 0);
+ // Decls within functions are visited by the body
+ bool HasDeclContext = !isa<FunctionDecl>(*D) && !isa<ObjCMethodDecl>(*D) &&
+ hasNodes(dyn_cast<DeclContext>(D));
+
+ setMoreChildren(HasAttrs || HasComment || HasDeclContext);
+ ConstDeclVisitor<ASTDumper>::Visit(D);
+
+ setMoreChildren(HasComment || HasDeclContext);
+ for (Decl::attr_iterator I = D->attr_begin(), E = D->attr_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpAttr(*I);
+ }
+
+ setMoreChildren(HasDeclContext);
+ lastChild();
+ dumpFullComment(D->getASTContext().getCommentForDecl(D, 0));
+
+ setMoreChildren(false);
+ if (HasDeclContext)
+ dumpDeclContext(cast<DeclContext>(D));
+}
+
+void ASTDumper::VisitLabelDecl(const LabelDecl *D) {
+ dumpName(D);
+}
+
+void ASTDumper::VisitTypedefDecl(const TypedefDecl *D) {
+ dumpName(D);
+ dumpType(D->getUnderlyingType());
+ if (D->isModulePrivate())
+ OS << " __module_private__";
+}
+
+void ASTDumper::VisitEnumDecl(const EnumDecl *D) {
+ if (D->isScoped()) {
+ if (D->isScopedUsingClassTag())
+ OS << " class";
+ else
+ OS << " struct";
+ }
+ dumpName(D);
+ if (D->isModulePrivate())
+ OS << " __module_private__";
+ if (D->isFixed())
+ dumpType(D->getIntegerType());
+}
+
+void ASTDumper::VisitRecordDecl(const RecordDecl *D) {
+ OS << ' ' << D->getKindName();
+ dumpName(D);
+ if (D->isModulePrivate())
+ OS << " __module_private__";
+}
+
+void ASTDumper::VisitEnumConstantDecl(const EnumConstantDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+ if (const Expr *Init = D->getInitExpr()) {
+ lastChild();
+ dumpStmt(Init);
+ }
+}
+
+void ASTDumper::VisitIndirectFieldDecl(const IndirectFieldDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+ for (IndirectFieldDecl::chain_iterator I = D->chain_begin(),
+ E = D->chain_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpDeclRef(*I);
+ }
+}
+
+void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+
+ StorageClass SC = D->getStorageClass();
+ if (SC != SC_None)
+ OS << ' ' << VarDecl::getStorageClassSpecifierString(SC);
+ if (D->isInlineSpecified())
+ OS << " inline";
+ if (D->isVirtualAsWritten())
+ OS << " virtual";
+ if (D->isModulePrivate())
+ OS << " __module_private__";
+
+ if (D->isPure())
+ OS << " pure";
+ else if (D->isDeletedAsWritten())
+ OS << " delete";
+
+ bool OldMoreChildren = hasMoreChildren();
+ const FunctionTemplateSpecializationInfo *FTSI =
+ D->getTemplateSpecializationInfo();
+ bool HasTemplateSpecialization = FTSI;
+
+ bool HasNamedDecls = D->getDeclsInPrototypeScope().begin() !=
+ D->getDeclsInPrototypeScope().end();
+
+ bool HasFunctionDecls = D->param_begin() != D->param_end();
+
+ const CXXConstructorDecl *C = dyn_cast<CXXConstructorDecl>(D);
+ bool HasCtorInitializers = C && C->init_begin() != C->init_end();
+
+ bool HasDeclarationBody = D->doesThisDeclarationHaveABody();
+
+ setMoreChildren(OldMoreChildren || HasNamedDecls || HasFunctionDecls ||
+ HasCtorInitializers || HasDeclarationBody);
+ if (HasTemplateSpecialization) {
+ lastChild();
+ dumpTemplateArgumentList(*FTSI->TemplateArguments);
+ }
+
+ setMoreChildren(OldMoreChildren || HasFunctionDecls ||
+ HasCtorInitializers || HasDeclarationBody);
+ for (ArrayRef<NamedDecl *>::iterator
+ I = D->getDeclsInPrototypeScope().begin(),
+ E = D->getDeclsInPrototypeScope().end(); I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpDecl(*I);
+ }
+
+ setMoreChildren(OldMoreChildren || HasCtorInitializers || HasDeclarationBody);
+ for (FunctionDecl::param_const_iterator I = D->param_begin(),
+ E = D->param_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpDecl(*I);
+ }
+
+ setMoreChildren(OldMoreChildren || HasDeclarationBody);
+ if (HasCtorInitializers)
+ for (CXXConstructorDecl::init_const_iterator I = C->init_begin(),
+ E = C->init_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpCXXCtorInitializer(*I);
+ }
+
+ setMoreChildren(OldMoreChildren);
+ if (HasDeclarationBody) {
+ lastChild();
+ dumpStmt(D->getBody());
+ }
+}
+
+void ASTDumper::VisitFieldDecl(const FieldDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+ if (D->isMutable())
+ OS << " mutable";
+ if (D->isModulePrivate())
+ OS << " __module_private__";
+
+ bool OldMoreChildren = hasMoreChildren();
+ bool IsBitField = D->isBitField();
+ Expr *Init = D->getInClassInitializer();
+ bool HasInit = Init;
+
+ setMoreChildren(OldMoreChildren || HasInit);
+ if (IsBitField) {
+ lastChild();
+ dumpStmt(D->getBitWidth());
+ }
+ setMoreChildren(OldMoreChildren);
+ if (HasInit) {
+ lastChild();
+ dumpStmt(Init);
+ }
+}
+
+void ASTDumper::VisitVarDecl(const VarDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+ StorageClass SC = D->getStorageClass();
+ if (SC != SC_None)
+ OS << ' ' << VarDecl::getStorageClassSpecifierString(SC);
+ if (D->isThreadSpecified())
+ OS << " __thread";
+ if (D->isModulePrivate())
+ OS << " __module_private__";
+ if (D->isNRVOVariable())
+ OS << " nrvo";
+ if (D->hasInit()) {
+ lastChild();
+ dumpStmt(D->getInit());
+ }
+}
+
+void ASTDumper::VisitFileScopeAsmDecl(const FileScopeAsmDecl *D) {
+ lastChild();
+ dumpStmt(D->getAsmString());
+}
+
+void ASTDumper::VisitImportDecl(const ImportDecl *D) {
+ OS << ' ' << D->getImportedModule()->getFullModuleName();
+}
+
+//===----------------------------------------------------------------------===//
+// C++ Declarations
+//===----------------------------------------------------------------------===//
+
+void ASTDumper::VisitNamespaceDecl(const NamespaceDecl *D) {
+ dumpName(D);
+ if (D->isInline())
+ OS << " inline";
+ if (!D->isOriginalNamespace())
+ dumpDeclRef(D->getOriginalNamespace(), "original");
+}
+
+void ASTDumper::VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) {
+ OS << ' ';
+ dumpBareDeclRef(D->getNominatedNamespace());
+}
+
+void ASTDumper::VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) {
+ dumpName(D);
+ dumpDeclRef(D->getAliasedNamespace());
+}
+
+void ASTDumper::VisitTypeAliasDecl(const TypeAliasDecl *D) {
+ dumpName(D);
+ dumpType(D->getUnderlyingType());
+}
+
+void ASTDumper::VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D) {
+ dumpName(D);
+ dumpTemplateParameters(D->getTemplateParameters());
+ dumpDecl(D->getTemplatedDecl());
+}
+
+void ASTDumper::VisitCXXRecordDecl(const CXXRecordDecl *D) {
+ VisitRecordDecl(D);
+ if (!D->isCompleteDefinition())
+ return;
+
+ for (CXXRecordDecl::base_class_const_iterator I = D->bases_begin(),
+ E = D->bases_end();
+ I != E; ++I) {
+ IndentScope Indent(*this);
+ if (I->isVirtual())
+ OS << "virtual ";
+ dumpAccessSpecifier(I->getAccessSpecifier());
+ dumpType(I->getType());
+ if (I->isPackExpansion())
+ OS << "...";
+ }
+}
+
+void ASTDumper::VisitStaticAssertDecl(const StaticAssertDecl *D) {
+ dumpStmt(D->getAssertExpr());
+ lastChild();
+ dumpStmt(D->getMessage());
+}
+
+void ASTDumper::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {
+ dumpName(D);
+ dumpTemplateParameters(D->getTemplateParameters());
+ dumpDecl(D->getTemplatedDecl());
+ for (FunctionTemplateDecl::spec_iterator I = D->spec_begin(),
+ E = D->spec_end();
+ I != E; ++I) {
+ FunctionTemplateDecl::spec_iterator Next = I;
+ ++Next;
+ if (Next == E)
+ lastChild();
+ switch (I->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ImplicitInstantiation:
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ExplicitInstantiationDefinition:
+ if (D == D->getCanonicalDecl())
+ dumpDecl(*I);
+ else
+ dumpDeclRef(*I);
+ break;
+ case TSK_ExplicitSpecialization:
+ dumpDeclRef(*I);
+ break;
+ }
+ }
+}
+
+void ASTDumper::VisitClassTemplateDecl(const ClassTemplateDecl *D) {
+ dumpName(D);
+ dumpTemplateParameters(D->getTemplateParameters());
+
+ ClassTemplateDecl::spec_iterator I = D->spec_begin();
+ ClassTemplateDecl::spec_iterator E = D->spec_end();
+ if (I == E)
+ lastChild();
+ dumpDecl(D->getTemplatedDecl());
+ for (; I != E; ++I) {
+ ClassTemplateDecl::spec_iterator Next = I;
+ ++Next;
+ if (Next == E)
+ lastChild();
+ switch (I->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ImplicitInstantiation:
+ if (D == D->getCanonicalDecl())
+ dumpDecl(*I);
+ else
+ dumpDeclRef(*I);
+ break;
+ case TSK_ExplicitSpecialization:
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ExplicitInstantiationDefinition:
+ dumpDeclRef(*I);
+ break;
+ }
+ }
+}
+
+void ASTDumper::VisitClassTemplateSpecializationDecl(
+ const ClassTemplateSpecializationDecl *D) {
+ VisitCXXRecordDecl(D);
+ dumpTemplateArgumentList(D->getTemplateArgs());
+}
+
+void ASTDumper::VisitClassTemplatePartialSpecializationDecl(
+ const ClassTemplatePartialSpecializationDecl *D) {
+ VisitClassTemplateSpecializationDecl(D);
+ dumpTemplateParameters(D->getTemplateParameters());
+}
+
+void ASTDumper::VisitClassScopeFunctionSpecializationDecl(
+ const ClassScopeFunctionSpecializationDecl *D) {
+ dumpDeclRef(D->getSpecialization());
+ if (D->hasExplicitTemplateArgs())
+ dumpTemplateArgumentListInfo(D->templateArgs());
+}
+
+void ASTDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
+ if (D->wasDeclaredWithTypename())
+ OS << " typename";
+ else
+ OS << " class";
+ if (D->isParameterPack())
+ OS << " ...";
+ dumpName(D);
+ if (D->hasDefaultArgument())
+ dumpType(D->getDefaultArgument());
+}
+
+void ASTDumper::VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) {
+ dumpType(D->getType());
+ if (D->isParameterPack())
+ OS << " ...";
+ dumpName(D);
+ if (D->hasDefaultArgument())
+ dumpStmt(D->getDefaultArgument());
+}
+
+void ASTDumper::VisitTemplateTemplateParmDecl(
+ const TemplateTemplateParmDecl *D) {
+ if (D->isParameterPack())
+ OS << " ...";
+ dumpName(D);
+ dumpTemplateParameters(D->getTemplateParameters());
+ if (D->hasDefaultArgument())
+ dumpTemplateArgumentLoc(D->getDefaultArgument());
+}
+
+void ASTDumper::VisitUsingDecl(const UsingDecl *D) {
+ OS << ' ';
+ D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
+ OS << D->getNameAsString();
+}
+
+void ASTDumper::VisitUnresolvedUsingTypenameDecl(
+ const UnresolvedUsingTypenameDecl *D) {
+ OS << ' ';
+ D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
+ OS << D->getNameAsString();
+}
+
+void ASTDumper::VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) {
+ OS << ' ';
+ D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
+ OS << D->getNameAsString();
+ dumpType(D->getType());
+}
+
+void ASTDumper::VisitUsingShadowDecl(const UsingShadowDecl *D) {
+ OS << ' ';
+ dumpBareDeclRef(D->getTargetDecl());
+}
+
+void ASTDumper::VisitLinkageSpecDecl(const LinkageSpecDecl *D) {
+ switch (D->getLanguage()) {
+ case LinkageSpecDecl::lang_c: OS << " C"; break;
+ case LinkageSpecDecl::lang_cxx: OS << " C++"; break;
+ }
+}
+
+void ASTDumper::VisitAccessSpecDecl(const AccessSpecDecl *D) {
+ OS << ' ';
+ dumpAccessSpecifier(D->getAccess());
+}
+
+void ASTDumper::VisitFriendDecl(const FriendDecl *D) {
+ lastChild();
+ if (TypeSourceInfo *T = D->getFriendType())
+ dumpType(T->getType());
+ else
+ dumpDecl(D->getFriendDecl());
+}
+
+//===----------------------------------------------------------------------===//
+// Obj-C Declarations
+//===----------------------------------------------------------------------===//
+
+void ASTDumper::VisitObjCIvarDecl(const ObjCIvarDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+ if (D->getSynthesize())
+ OS << " synthesize";
+
+ switch (D->getAccessControl()) {
+ case ObjCIvarDecl::None:
+ OS << " none";
+ break;
+ case ObjCIvarDecl::Private:
+ OS << " private";
+ break;
+ case ObjCIvarDecl::Protected:
+ OS << " protected";
+ break;
+ case ObjCIvarDecl::Public:
+ OS << " public";
+ break;
+ case ObjCIvarDecl::Package:
+ OS << " package";
+ break;
+ }
+}
+
+void ASTDumper::VisitObjCMethodDecl(const ObjCMethodDecl *D) {
+ if (D->isInstanceMethod())
+ OS << " -";
+ else
+ OS << " +";
+ dumpName(D);
+ dumpType(D->getResultType());
+
+ bool OldMoreChildren = hasMoreChildren();
+ bool IsVariadic = D->isVariadic();
+ bool HasBody = D->hasBody();
+
+ setMoreChildren(OldMoreChildren || IsVariadic || HasBody);
+ if (D->isThisDeclarationADefinition()) {
+ lastChild();
+ dumpDeclContext(D);
+ } else {
+ for (ObjCMethodDecl::param_const_iterator I = D->param_begin(),
+ E = D->param_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpDecl(*I);
+ }
+ }
+
+ setMoreChildren(OldMoreChildren || HasBody);
+ if (IsVariadic) {
+ lastChild();
+ IndentScope Indent(*this);
+ OS << "...";
+ }
+
+ setMoreChildren(OldMoreChildren);
+ if (HasBody) {
+ lastChild();
+ dumpStmt(D->getBody());
+ }
+}
+
+void ASTDumper::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
+ dumpName(D);
+ dumpDeclRef(D->getClassInterface());
+ if (D->protocol_begin() == D->protocol_end())
+ lastChild();
+ dumpDeclRef(D->getImplementation());
+ for (ObjCCategoryDecl::protocol_iterator I = D->protocol_begin(),
+ E = D->protocol_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpDeclRef(*I);
+ }
+}
+
+void ASTDumper::VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) {
+ dumpName(D);
+ dumpDeclRef(D->getClassInterface());
+ lastChild();
+ dumpDeclRef(D->getCategoryDecl());
+}
+
+void ASTDumper::VisitObjCProtocolDecl(const ObjCProtocolDecl *D) {
+ dumpName(D);
+ for (ObjCProtocolDecl::protocol_iterator I = D->protocol_begin(),
+ E = D->protocol_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpDeclRef(*I);
+ }
+}
+
+void ASTDumper::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
+ dumpName(D);
+ dumpDeclRef(D->getSuperClass(), "super");
+ if (D->protocol_begin() == D->protocol_end())
+ lastChild();
+ dumpDeclRef(D->getImplementation());
+ for (ObjCInterfaceDecl::protocol_iterator I = D->protocol_begin(),
+ E = D->protocol_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpDeclRef(*I);
+ }
+}
+
+void ASTDumper::VisitObjCImplementationDecl(const ObjCImplementationDecl *D) {
+ dumpName(D);
+ dumpDeclRef(D->getSuperClass(), "super");
+ if (D->init_begin() == D->init_end())
+ lastChild();
+ dumpDeclRef(D->getClassInterface());
+ for (ObjCImplementationDecl::init_const_iterator I = D->init_begin(),
+ E = D->init_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpCXXCtorInitializer(*I);
+ }
+}
+
+void ASTDumper::VisitObjCCompatibleAliasDecl(const ObjCCompatibleAliasDecl *D) {
+ dumpName(D);
+ lastChild();
+ dumpDeclRef(D->getClassInterface());
+}
+
+void ASTDumper::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+
+ if (D->getPropertyImplementation() == ObjCPropertyDecl::Required)
+ OS << " required";
+ else if (D->getPropertyImplementation() == ObjCPropertyDecl::Optional)
+ OS << " optional";
+
+ ObjCPropertyDecl::PropertyAttributeKind Attrs = D->getPropertyAttributes();
+ if (Attrs != ObjCPropertyDecl::OBJC_PR_noattr) {
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_readonly)
+ OS << " readonly";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_assign)
+ OS << " assign";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_readwrite)
+ OS << " readwrite";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_retain)
+ OS << " retain";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_copy)
+ OS << " copy";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_nonatomic)
+ OS << " nonatomic";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_atomic)
+ OS << " atomic";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_weak)
+ OS << " weak";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_strong)
+ OS << " strong";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained)
+ OS << " unsafe_unretained";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_getter) {
+ if (!(Attrs & ObjCPropertyDecl::OBJC_PR_setter))
+ lastChild();
+ dumpDeclRef(D->getGetterMethodDecl(), "getter");
+ }
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_setter) {
+ lastChild();
+ dumpDeclRef(D->getSetterMethodDecl(), "setter");
+ }
+ }
+}
+
+void ASTDumper::VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) {
+ dumpName(D->getPropertyDecl());
+ if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize)
+ OS << " synthesize";
+ else
+ OS << " dynamic";
+ dumpDeclRef(D->getPropertyDecl());
+ lastChild();
+ dumpDeclRef(D->getPropertyIvarDecl());
+}
+
+void ASTDumper::VisitBlockDecl(const BlockDecl *D) {
+ for (BlockDecl::param_const_iterator I = D->param_begin(), E = D->param_end();
+ I != E; ++I)
+ dumpDecl(*I);
+
+ if (D->isVariadic()) {
+ IndentScope Indent(*this);
+ OS << "...";
+ }
+
+ if (D->capturesCXXThis()) {
+ IndentScope Indent(*this);
+ OS << "capture this";
+ }
+ for (BlockDecl::capture_iterator I = D->capture_begin(), E = D->capture_end();
+ I != E; ++I) {
+ IndentScope Indent(*this);
+ OS << "capture";
+ if (I->isByRef())
+ OS << " byref";
+ if (I->isNested())
+ OS << " nested";
+ if (I->getVariable()) {
+ OS << ' ';
+ dumpBareDeclRef(I->getVariable());
+ }
+ if (I->hasCopyExpr())
+ dumpStmt(I->getCopyExpr());
+ }
+ lastChild();
+ dumpStmt(D->getBody());
+}
+
+//===----------------------------------------------------------------------===//
+// Stmt dumping methods.
+//===----------------------------------------------------------------------===//
+
+void ASTDumper::dumpStmt(const Stmt *S) {
+ IndentScope Indent(*this);
+
+ if (!S) {
+ ColorScope Color(*this, NullColor);
+ OS << "<<<NULL>>>";
+ return;
+ }
+
+ if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
+ VisitDeclStmt(DS);
+ return;
+ }
+
+ setMoreChildren(S->children());
+ ConstStmtVisitor<ASTDumper>::Visit(S);
+ setMoreChildren(false);
+ for (Stmt::const_child_range CI = S->children(); CI; ++CI) {
+ Stmt::const_child_range Next = CI;
+ ++Next;
+ if (!Next)
+ lastChild();
+ dumpStmt(*CI);
+ }
+}
+
+void ASTDumper::VisitStmt(const Stmt *Node) {
+ {
+ ColorScope Color(*this, StmtColor);
+ OS << Node->getStmtClassName();
+ }
+ dumpPointer(Node);
+ dumpSourceRange(Node->getSourceRange());
+}
+
+void ASTDumper::VisitDeclStmt(const DeclStmt *Node) {
+ VisitStmt(Node);
+ for (DeclStmt::const_decl_iterator I = Node->decl_begin(),
+ E = Node->decl_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpDecl(*I);
+ }
+}
+
+void ASTDumper::VisitAttributedStmt(const AttributedStmt *Node) {
+ VisitStmt(Node);
+ for (ArrayRef<const Attr *>::iterator I = Node->getAttrs().begin(),
+ E = Node->getAttrs().end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpAttr(*I);
+ }
+}
+
+void ASTDumper::VisitLabelStmt(const LabelStmt *Node) {
+ VisitStmt(Node);
+ OS << " '" << Node->getName() << "'";
+}
+
+void ASTDumper::VisitGotoStmt(const GotoStmt *Node) {
+ VisitStmt(Node);
+ OS << " '" << Node->getLabel()->getName() << "'";
+ dumpPointer(Node->getLabel());
+}
+
+//===----------------------------------------------------------------------===//
+// Expr dumping methods.
+//===----------------------------------------------------------------------===//
+
+void ASTDumper::VisitExpr(const Expr *Node) {
+ VisitStmt(Node);
+ dumpType(Node->getType());
+
+ {
+ ColorScope Color(*this, ValueKindColor);
+ switch (Node->getValueKind()) {
+ case VK_RValue:
+ break;
+ case VK_LValue:
+ OS << " lvalue";
+ break;
+ case VK_XValue:
+ OS << " xvalue";
+ break;
+ }
+ }
+
+ {
+ ColorScope Color(*this, ObjectKindColor);
+ switch (Node->getObjectKind()) {
+ case OK_Ordinary:
+ break;
+ case OK_BitField:
+ OS << " bitfield";
+ break;
+ case OK_ObjCProperty:
+ OS << " objcproperty";
+ break;
+ case OK_ObjCSubscript:
+ OS << " objcsubscript";
+ break;
+ case OK_VectorComponent:
+ OS << " vectorcomponent";
+ break;
+ }
+ }
+}
+
+static void dumpBasePath(raw_ostream &OS, const CastExpr *Node) {
+ if (Node->path_empty())
+ return;
+
+ OS << " (";
+ bool First = true;
+ for (CastExpr::path_const_iterator I = Node->path_begin(),
+ E = Node->path_end();
+ I != E; ++I) {
+ const CXXBaseSpecifier *Base = *I;
+ if (!First)
+ OS << " -> ";
+
+ const CXXRecordDecl *RD =
+ cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+
+ if (Base->isVirtual())
+ OS << "virtual ";
+ OS << RD->getName();
+ First = false;
+ }
+
+ OS << ')';
+}
+
+void ASTDumper::VisitCastExpr(const CastExpr *Node) {
+ VisitExpr(Node);
+ OS << " <";
+ {
+ ColorScope Color(*this, CastColor);
+ OS << Node->getCastKindName();
+ }
+ dumpBasePath(OS, Node);
+ OS << ">";
+}
+
+void ASTDumper::VisitDeclRefExpr(const DeclRefExpr *Node) {
+ VisitExpr(Node);
+
+ OS << " ";
+ dumpBareDeclRef(Node->getDecl());
+ if (Node->getDecl() != Node->getFoundDecl()) {
+ OS << " (";
+ dumpBareDeclRef(Node->getFoundDecl());
+ OS << ")";
+ }
+}
+
+void ASTDumper::VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node) {
+ VisitExpr(Node);
+ OS << " (";
+ if (!Node->requiresADL())
+ OS << "no ";
+ OS << "ADL) = '" << Node->getName() << '\'';
+
+ UnresolvedLookupExpr::decls_iterator
+ I = Node->decls_begin(), E = Node->decls_end();
+ if (I == E)
+ OS << " empty";
+ for (; I != E; ++I)
+ dumpPointer(*I);
+}
+
+void ASTDumper::VisitObjCIvarRefExpr(const ObjCIvarRefExpr *Node) {
+ VisitExpr(Node);
+
+ {
+ ColorScope Color(*this, DeclKindNameColor);
+ OS << " " << Node->getDecl()->getDeclKindName() << "Decl";
+ }
+ OS << "='" << *Node->getDecl() << "'";
+ dumpPointer(Node->getDecl());
+ if (Node->isFreeIvar())
+ OS << " isFreeIvar";
+}
+
+void ASTDumper::VisitPredefinedExpr(const PredefinedExpr *Node) {
+ VisitExpr(Node);
+ switch (Node->getIdentType()) {
+ default: llvm_unreachable("unknown case");
+ case PredefinedExpr::Func: OS << " __func__"; break;
+ case PredefinedExpr::Function: OS << " __FUNCTION__"; break;
+ case PredefinedExpr::LFunction: OS << " L__FUNCTION__"; break;
+ case PredefinedExpr::PrettyFunction: OS << " __PRETTY_FUNCTION__";break;
+ }
+}
+
+void ASTDumper::VisitCharacterLiteral(const CharacterLiteral *Node) {
+ VisitExpr(Node);
+ ColorScope Color(*this, ValueColor);
+ OS << " " << Node->getValue();
+}
+
+void ASTDumper::VisitIntegerLiteral(const IntegerLiteral *Node) {
+ VisitExpr(Node);
+
+ bool isSigned = Node->getType()->isSignedIntegerType();
+ ColorScope Color(*this, ValueColor);
+ OS << " " << Node->getValue().toString(10, isSigned);
+}
+
+void ASTDumper::VisitFloatingLiteral(const FloatingLiteral *Node) {
+ VisitExpr(Node);
+ ColorScope Color(*this, ValueColor);
+ OS << " " << Node->getValueAsApproximateDouble();
+}
+
+void ASTDumper::VisitStringLiteral(const StringLiteral *Str) {
+ VisitExpr(Str);
+ ColorScope Color(*this, ValueColor);
+ OS << " ";
+ Str->outputString(OS);
+}
+
+void ASTDumper::VisitUnaryOperator(const UnaryOperator *Node) {
+ VisitExpr(Node);
+ OS << " " << (Node->isPostfix() ? "postfix" : "prefix")
+ << " '" << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'";
+}
+
+void ASTDumper::VisitUnaryExprOrTypeTraitExpr(
+ const UnaryExprOrTypeTraitExpr *Node) {
+ VisitExpr(Node);
+ switch(Node->getKind()) {
+ case UETT_SizeOf:
+ OS << " sizeof";
+ break;
+ case UETT_AlignOf:
+ OS << " alignof";
+ break;
+ case UETT_VecStep:
+ OS << " vec_step";
+ break;
+ }
+ if (Node->isArgumentType())
+ dumpType(Node->getArgumentType());
+}
+
+void ASTDumper::VisitMemberExpr(const MemberExpr *Node) {
+ VisitExpr(Node);
+ OS << " " << (Node->isArrow() ? "->" : ".") << *Node->getMemberDecl();
+ dumpPointer(Node->getMemberDecl());
+}
+
+void ASTDumper::VisitExtVectorElementExpr(const ExtVectorElementExpr *Node) {
+ VisitExpr(Node);
+ OS << " " << Node->getAccessor().getNameStart();
+}
+
+void ASTDumper::VisitBinaryOperator(const BinaryOperator *Node) {
+ VisitExpr(Node);
+ OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode()) << "'";
+}
+
+void ASTDumper::VisitCompoundAssignOperator(
+ const CompoundAssignOperator *Node) {
+ VisitExpr(Node);
+ OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode())
+ << "' ComputeLHSTy=";
+ dumpBareType(Node->getComputationLHSType());
+ OS << " ComputeResultTy=";
+ dumpBareType(Node->getComputationResultType());
+}
+
+void ASTDumper::VisitBlockExpr(const BlockExpr *Node) {
+ VisitExpr(Node);
+ dumpDecl(Node->getBlockDecl());
+}
+
+void ASTDumper::VisitOpaqueValueExpr(const OpaqueValueExpr *Node) {
+ VisitExpr(Node);
+
+ if (Expr *Source = Node->getSourceExpr()) {
+ lastChild();
+ dumpStmt(Source);
+ }
+}
+
+// GNU extensions.
+
+void ASTDumper::VisitAddrLabelExpr(const AddrLabelExpr *Node) {
+ VisitExpr(Node);
+ OS << " " << Node->getLabel()->getName();
+ dumpPointer(Node->getLabel());
+}
+
+//===----------------------------------------------------------------------===//
+// C++ Expressions
+//===----------------------------------------------------------------------===//
+
+void ASTDumper::VisitCXXNamedCastExpr(const CXXNamedCastExpr *Node) {
+ VisitExpr(Node);
+ OS << " " << Node->getCastName()
+ << "<" << Node->getTypeAsWritten().getAsString() << ">"
+ << " <" << Node->getCastKindName();
+ dumpBasePath(OS, Node);
+ OS << ">";
+}
+
+void ASTDumper::VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *Node) {
+ VisitExpr(Node);
+ OS << " " << (Node->getValue() ? "true" : "false");
+}
+
+void ASTDumper::VisitCXXThisExpr(const CXXThisExpr *Node) {
+ VisitExpr(Node);
+ OS << " this";
+}
+
+void ASTDumper::VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node) {
+ VisitExpr(Node);
+ OS << " functional cast to " << Node->getTypeAsWritten().getAsString()
+ << " <" << Node->getCastKindName() << ">";
+}
+
+void ASTDumper::VisitCXXConstructExpr(const CXXConstructExpr *Node) {
+ VisitExpr(Node);
+ CXXConstructorDecl *Ctor = Node->getConstructor();
+ dumpType(Ctor->getType());
+ if (Node->isElidable())
+ OS << " elidable";
+ if (Node->requiresZeroInitialization())
+ OS << " zeroing";
+}
+
+void ASTDumper::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node) {
+ VisitExpr(Node);
+ OS << " ";
+ dumpCXXTemporary(Node->getTemporary());
+}
+
+void ASTDumper::VisitExprWithCleanups(const ExprWithCleanups *Node) {
+ VisitExpr(Node);
+ for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i)
+ dumpDeclRef(Node->getObject(i), "cleanup");
+}
+
+void ASTDumper::dumpCXXTemporary(const CXXTemporary *Temporary) {
+ OS << "(CXXTemporary";
+ dumpPointer(Temporary);
+ OS << ")";
+}
+
+//===----------------------------------------------------------------------===//
+// Obj-C Expressions
+//===----------------------------------------------------------------------===//
+
+void ASTDumper::VisitObjCMessageExpr(const ObjCMessageExpr *Node) {
+ VisitExpr(Node);
+ OS << " selector=" << Node->getSelector().getAsString();
+ switch (Node->getReceiverKind()) {
+ case ObjCMessageExpr::Instance:
+ break;
+
+ case ObjCMessageExpr::Class:
+ OS << " class=";
+ dumpBareType(Node->getClassReceiver());
+ break;
+
+ case ObjCMessageExpr::SuperInstance:
+ OS << " super (instance)";
+ break;
+
+ case ObjCMessageExpr::SuperClass:
+ OS << " super (class)";
+ break;
+ }
+}
+
+void ASTDumper::VisitObjCBoxedExpr(const ObjCBoxedExpr *Node) {
+ VisitExpr(Node);
+ OS << " selector=" << Node->getBoxingMethod()->getSelector().getAsString();
+}
+
+void ASTDumper::VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node) {
+ VisitStmt(Node);
+ if (const VarDecl *CatchParam = Node->getCatchParamDecl())
+ dumpDecl(CatchParam);
+ else
+ OS << " catch all";
+}
+
+void ASTDumper::VisitObjCEncodeExpr(const ObjCEncodeExpr *Node) {
+ VisitExpr(Node);
+ dumpType(Node->getEncodedType());
+}
+
+void ASTDumper::VisitObjCSelectorExpr(const ObjCSelectorExpr *Node) {
+ VisitExpr(Node);
+
+ OS << " " << Node->getSelector().getAsString();
+}
+
+void ASTDumper::VisitObjCProtocolExpr(const ObjCProtocolExpr *Node) {
+ VisitExpr(Node);
+
+ OS << ' ' << *Node->getProtocol();
+}
+
+void ASTDumper::VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *Node) {
+ VisitExpr(Node);
+ if (Node->isImplicitProperty()) {
+ OS << " Kind=MethodRef Getter=\"";
+ if (Node->getImplicitPropertyGetter())
+ OS << Node->getImplicitPropertyGetter()->getSelector().getAsString();
+ else
+ OS << "(null)";
+
+ OS << "\" Setter=\"";
+ if (ObjCMethodDecl *Setter = Node->getImplicitPropertySetter())
+ OS << Setter->getSelector().getAsString();
+ else
+ OS << "(null)";
+ OS << "\"";
+ } else {
+ OS << " Kind=PropertyRef Property=\"" << *Node->getExplicitProperty() <<'"';
+ }
+
+ if (Node->isSuperReceiver())
+ OS << " super";
+
+ OS << " Messaging=";
+ if (Node->isMessagingGetter() && Node->isMessagingSetter())
+ OS << "Getter&Setter";
+ else if (Node->isMessagingGetter())
+ OS << "Getter";
+ else if (Node->isMessagingSetter())
+ OS << "Setter";
+}
+
+void ASTDumper::VisitObjCSubscriptRefExpr(const ObjCSubscriptRefExpr *Node) {
+ VisitExpr(Node);
+ if (Node->isArraySubscriptRefExpr())
+ OS << " Kind=ArraySubscript GetterForArray=\"";
+ else
+ OS << " Kind=DictionarySubscript GetterForDictionary=\"";
+ if (Node->getAtIndexMethodDecl())
+ OS << Node->getAtIndexMethodDecl()->getSelector().getAsString();
+ else
+ OS << "(null)";
+
+ if (Node->isArraySubscriptRefExpr())
+ OS << "\" SetterForArray=\"";
+ else
+ OS << "\" SetterForDictionary=\"";
+ if (Node->setAtIndexMethodDecl())
+ OS << Node->setAtIndexMethodDecl()->getSelector().getAsString();
+ else
+ OS << "(null)";
+}
+
+void ASTDumper::VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *Node) {
+ VisitExpr(Node);
+ OS << " " << (Node->getValue() ? "__objc_yes" : "__objc_no");
+}
+
+//===----------------------------------------------------------------------===//
+// Comments
+//===----------------------------------------------------------------------===//
+
+const char *ASTDumper::getCommandName(unsigned CommandID) {
+ if (Traits)
+ return Traits->getCommandInfo(CommandID)->Name;
+ const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID);
+ if (Info)
+ return Info->Name;
+ return "<not a builtin command>";
+}
+
+void ASTDumper::dumpFullComment(const FullComment *C) {
+ if (!C)
+ return;
+
+ FC = C;
+ dumpComment(C);
+ FC = 0;
+}
+
+void ASTDumper::dumpComment(const Comment *C) {
+ IndentScope Indent(*this);
+
+ if (!C) {
+ ColorScope Color(*this, NullColor);
+ OS << "<<<NULL>>>";
+ return;
+ }
+
+ {
+ ColorScope Color(*this, CommentColor);
+ OS << C->getCommentKindName();
+ }
+ dumpPointer(C);
+ dumpSourceRange(C->getSourceRange());
+ ConstCommentVisitor<ASTDumper>::visit(C);
+ for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpComment(*I);
+ }
+}
+
+void ASTDumper::visitTextComment(const TextComment *C) {
+ OS << " Text=\"" << C->getText() << "\"";
+}
+
+void ASTDumper::visitInlineCommandComment(const InlineCommandComment *C) {
+ OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"";
+ switch (C->getRenderKind()) {
+ case InlineCommandComment::RenderNormal:
+ OS << " RenderNormal";
+ break;
+ case InlineCommandComment::RenderBold:
+ OS << " RenderBold";
+ break;
+ case InlineCommandComment::RenderMonospaced:
+ OS << " RenderMonospaced";
+ break;
+ case InlineCommandComment::RenderEmphasized:
+ OS << " RenderEmphasized";
+ break;
+ }
+
+ for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
+ OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
+}
+
+void ASTDumper::visitHTMLStartTagComment(const HTMLStartTagComment *C) {
+ OS << " Name=\"" << C->getTagName() << "\"";
+ if (C->getNumAttrs() != 0) {
+ OS << " Attrs: ";
+ for (unsigned i = 0, e = C->getNumAttrs(); i != e; ++i) {
+ const HTMLStartTagComment::Attribute &Attr = C->getAttr(i);
+ OS << " \"" << Attr.Name << "=\"" << Attr.Value << "\"";
+ }
+ }
+ if (C->isSelfClosing())
+ OS << " SelfClosing";
+}
+
+void ASTDumper::visitHTMLEndTagComment(const HTMLEndTagComment *C) {
+ OS << " Name=\"" << C->getTagName() << "\"";
+}
+
+void ASTDumper::visitBlockCommandComment(const BlockCommandComment *C) {
+ OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"";
+ for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
+ OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
+}
+
+void ASTDumper::visitParamCommandComment(const ParamCommandComment *C) {
+ OS << " " << ParamCommandComment::getDirectionAsString(C->getDirection());
+
+ if (C->isDirectionExplicit())
+ OS << " explicitly";
+ else
+ OS << " implicitly";
+
+ if (C->hasParamName()) {
+ if (C->isParamIndexValid())
+ OS << " Param=\"" << C->getParamName(FC) << "\"";
+ else
+ OS << " Param=\"" << C->getParamNameAsWritten() << "\"";
+ }
+
+ if (C->isParamIndexValid())
+ OS << " ParamIndex=" << C->getParamIndex();
+}
+
+void ASTDumper::visitTParamCommandComment(const TParamCommandComment *C) {
+ if (C->hasParamName()) {
+ if (C->isPositionValid())
+ OS << " Param=\"" << C->getParamName(FC) << "\"";
+ else
+ OS << " Param=\"" << C->getParamNameAsWritten() << "\"";
+ }
+
+ if (C->isPositionValid()) {
+ OS << " Position=<";
+ for (unsigned i = 0, e = C->getDepth(); i != e; ++i) {
+ OS << C->getIndex(i);
+ if (i != e - 1)
+ OS << ", ";
+ }
+ OS << ">";
+ }
+}
+
+void ASTDumper::visitVerbatimBlockComment(const VerbatimBlockComment *C) {
+ OS << " Name=\"" << getCommandName(C->getCommandID()) << "\""
+ " CloseName=\"" << C->getCloseName() << "\"";
+}
+
+void ASTDumper::visitVerbatimBlockLineComment(
+ const VerbatimBlockLineComment *C) {
+ OS << " Text=\"" << C->getText() << "\"";
+}
+
+void ASTDumper::visitVerbatimLineComment(const VerbatimLineComment *C) {
+ OS << " Text=\"" << C->getText() << "\"";
+}
+
+//===----------------------------------------------------------------------===//
+// Decl method implementations
+//===----------------------------------------------------------------------===//
+
+void Decl::dump() const {
+ dump(llvm::errs());
+}
+
+void Decl::dump(raw_ostream &OS) const {
+ ASTDumper P(OS, &getASTContext().getCommentCommandTraits(),
+ &getASTContext().getSourceManager());
+ P.dumpDecl(this);
+}
+
+void Decl::dumpColor() const {
+ ASTDumper P(llvm::errs(), &getASTContext().getCommentCommandTraits(),
+ &getASTContext().getSourceManager(), /*ShowColors*/true);
+ P.dumpDecl(this);
+}
+//===----------------------------------------------------------------------===//
+// Stmt method implementations
+//===----------------------------------------------------------------------===//
+
+void Stmt::dump(SourceManager &SM) const {
+ dump(llvm::errs(), SM);
+}
+
+void Stmt::dump(raw_ostream &OS, SourceManager &SM) const {
+ ASTDumper P(OS, 0, &SM);
+ P.dumpStmt(this);
+}
+
+void Stmt::dump() const {
+ ASTDumper P(llvm::errs(), 0, 0);
+ P.dumpStmt(this);
+}
+
+void Stmt::dumpColor() const {
+ ASTDumper P(llvm::errs(), 0, 0, /*ShowColors*/true);
+ P.dumpStmt(this);
+}
+
+//===----------------------------------------------------------------------===//
+// Comment method implementations
+//===----------------------------------------------------------------------===//
+
+void Comment::dump() const {
+ dump(llvm::errs(), 0, 0);
+}
+
+void Comment::dump(const ASTContext &Context) const {
+ dump(llvm::errs(), &Context.getCommentCommandTraits(),
+ &Context.getSourceManager());
+}
+
+void Comment::dump(raw_ostream &OS, const CommandTraits *Traits,
+ const SourceManager *SM) const {
+ const FullComment *FC = dyn_cast<FullComment>(this);
+ ASTDumper D(OS, Traits, SM);
+ D.dumpFullComment(FC);
+}
+
+void Comment::dumpColor() const {
+ const FullComment *FC = dyn_cast<FullComment>(this);
+ ASTDumper D(llvm::errs(), 0, 0, /*ShowColors*/true);
+ D.dumpFullComment(FC);
+}
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 0d4f303..d2e6d29 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -12,7 +12,6 @@
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTImporter.h"
-
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/DeclCXX.h"
@@ -122,6 +121,7 @@ namespace clang {
bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord,
bool Complain = true);
bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord);
+ bool IsStructuralMatch(EnumConstantDecl *FromEC, EnumConstantDecl *ToEC);
bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To);
Decl *VisitDecl(Decl *D);
Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D);
@@ -206,12 +206,16 @@ namespace {
/// \brief Whether to complain about failures.
bool Complain;
+ /// \brief \c true if the last diagnostic came from C2.
+ bool LastDiagFromC2;
+
StructuralEquivalenceContext(ASTContext &C1, ASTContext &C2,
llvm::DenseSet<std::pair<Decl *, Decl *> > &NonEquivalentDecls,
bool StrictTypeSpelling = false,
bool Complain = true)
: C1(C1), C2(C2), NonEquivalentDecls(NonEquivalentDecls),
- StrictTypeSpelling(StrictTypeSpelling), Complain(Complain) { }
+ StrictTypeSpelling(StrictTypeSpelling), Complain(Complain),
+ LastDiagFromC2(false) {}
/// \brief Determine whether the two declarations are structurally
/// equivalent.
@@ -229,11 +233,17 @@ namespace {
public:
DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID) {
assert(Complain && "Not allowed to complain");
+ if (LastDiagFromC2)
+ C1.getDiagnostics().notePriorDiagnosticFrom(C2.getDiagnostics());
+ LastDiagFromC2 = false;
return C1.getDiagnostics().Report(Loc, DiagID);
}
DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID) {
assert(Complain && "Not allowed to complain");
+ if (!LastDiagFromC2)
+ C2.getDiagnostics().notePriorDiagnosticFrom(C1.getDiagnostics());
+ LastDiagFromC2 = true;
return C2.getDiagnostics().Report(Loc, DiagID);
}
};
@@ -892,14 +902,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
/// including the next assigned index (if none of them match). Returns an
/// empty option if the context is not a record, i.e.. if the anonymous
/// struct/union is at namespace or block scope.
-static llvm::Optional<unsigned>
-findAnonymousStructOrUnionIndex(RecordDecl *Anon) {
+static Optional<unsigned> findAnonymousStructOrUnionIndex(RecordDecl *Anon) {
ASTContext &Context = Anon->getASTContext();
QualType AnonTy = Context.getRecordType(Anon);
RecordDecl *Owner = dyn_cast<RecordDecl>(Anon->getDeclContext());
if (!Owner)
- return llvm::Optional<unsigned>();
+ return None;
unsigned Index = 0;
for (DeclContext::decl_iterator D = Owner->noload_decls_begin(),
@@ -934,10 +943,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (D1->isAnonymousStructOrUnion() && D2->isAnonymousStructOrUnion()) {
// If both anonymous structs/unions are in a record context, make sure
// they occur in the same location in the context records.
- if (llvm::Optional<unsigned> Index1
- = findAnonymousStructOrUnionIndex(D1)) {
- if (llvm::Optional<unsigned> Index2
- = findAnonymousStructOrUnionIndex(D2)) {
+ if (Optional<unsigned> Index1 = findAnonymousStructOrUnionIndex(D1)) {
+ if (Optional<unsigned> Index2 = findAnonymousStructOrUnionIndex(D2)) {
if (*Index1 != *Index2)
return false;
}
@@ -1612,8 +1619,7 @@ QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) {
ToEPI.ExceptionSpecTemplate = cast_or_null<FunctionDecl>(
Importer.Import(FromEPI.ExceptionSpecTemplate));
- return Importer.getToContext().getFunctionType(ToResultType, ArgTypes.data(),
- ArgTypes.size(), ToEPI);
+ return Importer.getToContext().getFunctionType(ToResultType, ArgTypes, ToEPI);
}
QualType ASTNodeImporter::VisitParenType(const ParenType *T) {
@@ -1825,7 +1831,7 @@ void ASTNodeImporter::ImportDefinitionIfNeeded(Decl *FromD, Decl *ToD) {
if (RecordDecl *FromRecord = dyn_cast<RecordDecl>(FromD)) {
if (RecordDecl *ToRecord = cast_or_null<RecordDecl>(ToD)) {
- if (FromRecord->getDefinition() && !ToRecord->getDefinition()) {
+ if (FromRecord->getDefinition() && FromRecord->isCompleteDefinition() && !ToRecord->getDefinition()) {
ImportDefinition(FromRecord, ToRecord);
}
}
@@ -1907,11 +1913,7 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To,
struct CXXRecordDecl::DefinitionData &ToData = ToCXX->data();
struct CXXRecordDecl::DefinitionData &FromData = FromCXX->data();
ToData.UserDeclaredConstructor = FromData.UserDeclaredConstructor;
- ToData.UserDeclaredCopyConstructor = FromData.UserDeclaredCopyConstructor;
- ToData.UserDeclaredMoveConstructor = FromData.UserDeclaredMoveConstructor;
- ToData.UserDeclaredCopyAssignment = FromData.UserDeclaredCopyAssignment;
- ToData.UserDeclaredMoveAssignment = FromData.UserDeclaredMoveAssignment;
- ToData.UserDeclaredDestructor = FromData.UserDeclaredDestructor;
+ ToData.UserDeclaredSpecialMembers = FromData.UserDeclaredSpecialMembers;
ToData.Aggregate = FromData.Aggregate;
ToData.PlainOldData = FromData.PlainOldData;
ToData.Empty = FromData.Empty;
@@ -1925,30 +1927,41 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To,
ToData.HasMutableFields = FromData.HasMutableFields;
ToData.HasOnlyCMembers = FromData.HasOnlyCMembers;
ToData.HasInClassInitializer = FromData.HasInClassInitializer;
- ToData.HasTrivialDefaultConstructor = FromData.HasTrivialDefaultConstructor;
+ ToData.HasUninitializedReferenceMember
+ = FromData.HasUninitializedReferenceMember;
+ ToData.NeedOverloadResolutionForMoveConstructor
+ = FromData.NeedOverloadResolutionForMoveConstructor;
+ ToData.NeedOverloadResolutionForMoveAssignment
+ = FromData.NeedOverloadResolutionForMoveAssignment;
+ ToData.NeedOverloadResolutionForDestructor
+ = FromData.NeedOverloadResolutionForDestructor;
+ ToData.DefaultedMoveConstructorIsDeleted
+ = FromData.DefaultedMoveConstructorIsDeleted;
+ ToData.DefaultedMoveAssignmentIsDeleted
+ = FromData.DefaultedMoveAssignmentIsDeleted;
+ ToData.DefaultedDestructorIsDeleted = FromData.DefaultedDestructorIsDeleted;
+ ToData.HasTrivialSpecialMembers = FromData.HasTrivialSpecialMembers;
+ ToData.HasIrrelevantDestructor = FromData.HasIrrelevantDestructor;
ToData.HasConstexprNonCopyMoveConstructor
= FromData.HasConstexprNonCopyMoveConstructor;
ToData.DefaultedDefaultConstructorIsConstexpr
= FromData.DefaultedDefaultConstructorIsConstexpr;
ToData.HasConstexprDefaultConstructor
= FromData.HasConstexprDefaultConstructor;
- ToData.HasTrivialCopyConstructor = FromData.HasTrivialCopyConstructor;
- ToData.HasTrivialMoveConstructor = FromData.HasTrivialMoveConstructor;
- ToData.HasTrivialCopyAssignment = FromData.HasTrivialCopyAssignment;
- ToData.HasTrivialMoveAssignment = FromData.HasTrivialMoveAssignment;
- ToData.HasTrivialDestructor = FromData.HasTrivialDestructor;
- ToData.HasIrrelevantDestructor = FromData.HasIrrelevantDestructor;
ToData.HasNonLiteralTypeFieldsOrBases
= FromData.HasNonLiteralTypeFieldsOrBases;
// ComputedVisibleConversions not imported.
ToData.UserProvidedDefaultConstructor
= FromData.UserProvidedDefaultConstructor;
- ToData.DeclaredDefaultConstructor = FromData.DeclaredDefaultConstructor;
- ToData.DeclaredCopyConstructor = FromData.DeclaredCopyConstructor;
- ToData.DeclaredMoveConstructor = FromData.DeclaredMoveConstructor;
- ToData.DeclaredCopyAssignment = FromData.DeclaredCopyAssignment;
- ToData.DeclaredMoveAssignment = FromData.DeclaredMoveAssignment;
- ToData.DeclaredDestructor = FromData.DeclaredDestructor;
+ ToData.DeclaredSpecialMembers = FromData.DeclaredSpecialMembers;
+ ToData.ImplicitCopyConstructorHasConstParam
+ = FromData.ImplicitCopyConstructorHasConstParam;
+ ToData.ImplicitCopyAssignmentHasConstParam
+ = FromData.ImplicitCopyAssignmentHasConstParam;
+ ToData.HasDeclaredCopyConstructorWithConstParam
+ = FromData.HasDeclaredCopyConstructorWithConstParam;
+ ToData.HasDeclaredCopyAssignmentWithConstParam
+ = FromData.HasDeclaredCopyAssignmentWithConstParam;
ToData.FailedImplicitMoveConstructor
= FromData.FailedImplicitMoveConstructor;
ToData.FailedImplicitMoveAssignment = FromData.FailedImplicitMoveAssignment;
@@ -2143,7 +2156,18 @@ bool ASTNodeImporter::IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToEnum) {
return Ctx.IsStructurallyEquivalent(FromEnum, ToEnum);
}
-bool ASTNodeImporter::IsStructuralMatch(ClassTemplateDecl *From,
+bool ASTNodeImporter::IsStructuralMatch(EnumConstantDecl *FromEC,
+ EnumConstantDecl *ToEC)
+{
+ const llvm::APSInt &FromVal = FromEC->getInitVal();
+ const llvm::APSInt &ToVal = ToEC->getInitVal();
+
+ return FromVal.isSigned() == ToVal.isSigned() &&
+ FromVal.getBitWidth() == ToVal.getBitWidth() &&
+ FromVal == ToVal;
+}
+
+bool ASTNodeImporter::IsStructuralMatch(ClassTemplateDecl *From,
ClassTemplateDecl *To) {
StructuralEquivalenceContext Ctx(Importer.getFromContext(),
Importer.getToContext(),
@@ -2185,7 +2209,7 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) {
MergeWithNamespace = cast<NamespaceDecl>(DC)->getAnonymousNamespace();
} else {
SmallVector<NamedDecl *, 4> ConflictingDecls;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Namespace))
@@ -2248,7 +2272,7 @@ Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) {
if (!DC->isFunctionOrMethod()) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
unsigned IDNS = Decl::IDNS_Ordinary;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
@@ -2328,7 +2352,7 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
// We may already have an enum of the same name; try to find and match it.
if (!DC->isFunctionOrMethod() && SearchName) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(SearchName, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
@@ -2414,7 +2438,7 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
RecordDecl *AdoptDecl = 0;
if (!DC->isFunctionOrMethod()) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(SearchName, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
@@ -2431,10 +2455,10 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
FoundRecord->isAnonymousStructOrUnion()) {
// If both anonymous structs/unions are in a record context, make sure
// they occur in the same location in the context records.
- if (llvm::Optional<unsigned> Index1
+ if (Optional<unsigned> Index1
= findAnonymousStructOrUnionIndex(D)) {
- if (llvm::Optional<unsigned> Index2
- = findAnonymousStructOrUnionIndex(FoundRecord)) {
+ if (Optional<unsigned> Index2 =
+ findAnonymousStructOrUnionIndex(FoundRecord)) {
if (*Index1 != *Index2)
continue;
}
@@ -2521,12 +2545,18 @@ Decl *ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) {
if (!LexicalDC->isFunctionOrMethod()) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
unsigned IDNS = Decl::IDNS_Ordinary;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
continue;
-
+
+ if (EnumConstantDecl *FoundEnumConstant
+ = dyn_cast<EnumConstantDecl>(FoundDecls[I])) {
+ if (IsStructuralMatch(D, FoundEnumConstant))
+ return Importer.Imported(D, FoundEnumConstant);
+ }
+
ConflictingDecls.push_back(FoundDecls[I]);
}
@@ -2567,7 +2597,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
if (!LexicalDC->isFunctionOrMethod()) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
unsigned IDNS = Decl::IDNS_Ordinary;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
@@ -2629,8 +2659,8 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
FunctionProtoType::ExtProtoInfo DefaultEPI;
FromTy = Importer.getFromContext().getFunctionType(
FromFPT->getResultType(),
- FromFPT->arg_type_begin(),
- FromFPT->arg_type_end() - FromFPT->arg_type_begin(),
+ ArrayRef<QualType>(FromFPT->arg_type_begin(),
+ FromFPT->getNumArgs()),
DefaultEPI);
usedDifferentExceptionSpec = true;
}
@@ -2686,8 +2716,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
cast<CXXRecordDecl>(DC),
D->getInnerLocStart(),
NameInfo, T, TInfo,
- Method->isStatic(),
- Method->getStorageClassAsWritten(),
+ Method->getStorageClass(),
Method->isInlineSpecified(),
D->isConstexpr(),
Importer.Import(D->getLocEnd()));
@@ -2695,7 +2724,6 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
ToFunction = FunctionDecl::Create(Importer.getToContext(), DC,
D->getInnerLocStart(),
NameInfo, T, TInfo, D->getStorageClass(),
- D->getStorageClassAsWritten(),
D->isInlineSpecified(),
D->hasWrittenPrototype(),
D->isConstexpr());
@@ -2777,7 +2805,7 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
return 0;
// Determine whether we've already imported this field.
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (FieldDecl *FoundField = dyn_cast<FieldDecl>(FoundDecls[I])) {
@@ -2833,7 +2861,7 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
return 0;
// Determine whether we've already imported this field.
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (IndirectFieldDecl *FoundField
@@ -2898,7 +2926,7 @@ Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
return 0;
// Determine whether we've already imported this ivar
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (ObjCIvarDecl *FoundIvar = dyn_cast<ObjCIvarDecl>(FoundDecls[I])) {
@@ -2953,7 +2981,7 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
VarDecl *MergeWithVar = 0;
SmallVector<NamedDecl *, 4> ConflictingDecls;
unsigned IDNS = Decl::IDNS_Ordinary;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
@@ -3046,8 +3074,7 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
Importer.Import(D->getInnerLocStart()),
Loc, Name.getAsIdentifierInfo(),
T, TInfo,
- D->getStorageClass(),
- D->getStorageClassAsWritten());
+ D->getStorageClass());
ToVar->setQualifierInfo(Importer.Import(D->getQualifierLoc()));
ToVar->setAccess(D->getAccess());
ToVar->setLexicalDeclContext(LexicalDC);
@@ -3115,7 +3142,6 @@ Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) {
Importer.Import(D->getInnerLocStart()),
Loc, Name.getAsIdentifierInfo(),
T, TInfo, D->getStorageClass(),
- D->getStorageClassAsWritten(),
/*FIXME: Default argument*/ 0);
ToParm->setHasInheritedDefaultArg(D->hasInheritedDefaultArg());
return Importer.Imported(D, ToParm);
@@ -3129,7 +3155,7 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
return 0;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (ObjCMethodDecl *FoundMethod = dyn_cast<ObjCMethodDecl>(FoundDecls[I])) {
@@ -3376,7 +3402,7 @@ Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
return 0;
ObjCProtocolDecl *MergeWithProtocol = 0;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_ObjCProtocol))
@@ -3480,10 +3506,13 @@ bool ASTNodeImporter::ImportDefinition(ObjCInterfaceDecl *From,
// Import categories. When the categories themselves are imported, they'll
// hook themselves into this interface.
- for (ObjCCategoryDecl *FromCat = From->getCategoryList(); FromCat;
- FromCat = FromCat->getNextClassCategory())
- Importer.Import(FromCat);
-
+ for (ObjCInterfaceDecl::known_categories_iterator
+ Cat = From->known_categories_begin(),
+ CatEnd = From->known_categories_end();
+ Cat != CatEnd; ++Cat) {
+ Importer.Import(*Cat);
+ }
+
// If we have an @implementation, import it as well.
if (From->getImplementation()) {
ObjCImplementationDecl *Impl = cast_or_null<ObjCImplementationDecl>(
@@ -3523,7 +3552,7 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
// Look for an existing interface with the same name.
ObjCInterfaceDecl *MergeWithIface = 0;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Ordinary))
@@ -3675,7 +3704,7 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
return 0;
// Check whether we have already imported this property.
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (ObjCPropertyDecl *FoundProp
@@ -3908,7 +3937,7 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
// We may already have a template of the same name; try to find and match it.
if (!DC->isFunctionOrMethod()) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Ordinary))
@@ -4295,7 +4324,7 @@ ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
bool MinimalImport)
: ToContext(ToContext), FromContext(FromContext),
ToFileManager(ToFileManager), FromFileManager(FromFileManager),
- Minimal(MinimalImport)
+ Minimal(MinimalImport), LastDiagFromFrom(false)
{
ImportedDecls[FromContext.getTranslationUnitDecl()]
= ToContext.getTranslationUnitDecl();
@@ -4798,10 +4827,18 @@ DeclarationName ASTImporter::HandleNameConflict(DeclarationName Name,
}
DiagnosticBuilder ASTImporter::ToDiag(SourceLocation Loc, unsigned DiagID) {
+ if (LastDiagFromFrom)
+ ToContext.getDiagnostics().notePriorDiagnosticFrom(
+ FromContext.getDiagnostics());
+ LastDiagFromFrom = false;
return ToContext.getDiagnostics().Report(Loc, DiagID);
}
DiagnosticBuilder ASTImporter::FromDiag(SourceLocation Loc, unsigned DiagID) {
+ if (!LastDiagFromFrom)
+ FromContext.getDiagnostics().notePriorDiagnosticFrom(
+ ToContext.getDiagnostics());
+ LastDiagFromFrom = true;
return FromContext.getDiagnostics().Report(Loc, DiagID);
}
diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp
index cffcc65..daf65e5 100644
--- a/lib/AST/AttrImpl.cpp
+++ b/lib/AST/AttrImpl.cpp
@@ -13,8 +13,8 @@
#include "clang/AST/Attr.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/Type.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
using namespace clang;
Attr::~Attr() { }
@@ -23,4 +23,6 @@ void InheritableAttr::anchor() { }
void InheritableParamAttr::anchor() { }
+void MSInheritanceAttr::anchor() { }
+
#include "clang/AST/AttrImpl.inc"
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index d20d77e..e804fe7 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -5,13 +5,13 @@ add_clang_library(clangAST
ASTConsumer.cpp
ASTContext.cpp
ASTDiagnostic.cpp
+ ASTDumper.cpp
ASTImporter.cpp
AttrImpl.cpp
CXXInheritance.cpp
Comment.cpp
CommentBriefParser.cpp
CommentCommandTraits.cpp
- CommentDumper.cpp
CommentLexer.cpp
CommentParser.cpp
CommentSema.cpp
@@ -22,6 +22,7 @@ add_clang_library(clangAST
DeclFriend.cpp
DeclGroup.cpp
DeclObjC.cpp
+ DeclOpenMP.cpp
DeclPrinter.cpp
DeclTemplate.cpp
DumpXML.cpp
@@ -45,7 +46,6 @@ add_clang_library(clangAST
RecordLayoutBuilder.cpp
SelectorLocationsKind.cpp
Stmt.cpp
- StmtDumper.cpp
StmtIterator.cpp
StmtPrinter.cpp
StmtProfile.cpp
@@ -64,10 +64,13 @@ add_dependencies(clangAST
ClangAttrClasses
ClangAttrList
ClangAttrImpl
+ ClangAttrDump
ClangCommentCommandInfo
+ ClangCommentCommandList
ClangCommentNodes
ClangCommentHTMLTags
ClangCommentHTMLTagsProperties
+ ClangCommentHTMLNamedCharacterReferences
ClangDeclNodes
ClangDiagnosticAST
ClangDiagnosticComment
diff --git a/lib/AST/CXXABI.h b/lib/AST/CXXABI.h
index 0d9c869..6d67d9a 100644
--- a/lib/AST/CXXABI.h
+++ b/lib/AST/CXXABI.h
@@ -27,9 +27,9 @@ class CXXABI {
public:
virtual ~CXXABI();
- /// Returns the size of a member pointer in multiples of the target
- /// pointer size.
- virtual unsigned getMemberPointerSize(const MemberPointerType *MPT) const = 0;
+ /// Returns the width and alignment of a member pointer in bits.
+ virtual std::pair<uint64_t, unsigned>
+ getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const = 0;
/// Returns the default calling convention for C++ methods.
virtual CallingConv getDefaultMethodCallConv(bool isVariadic) const = 0;
diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp
index 213b214..0e0b35d 100644
--- a/lib/AST/CXXInheritance.cpp
+++ b/lib/AST/CXXInheritance.cpp
@@ -12,8 +12,8 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/RecordLayout.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/RecordLayout.h"
#include "llvm/ADT/SetVector.h"
#include <algorithm>
#include <set>
@@ -28,7 +28,7 @@ void CXXBasePaths::ComputeDeclsFound() {
llvm::SetVector<NamedDecl *, SmallVector<NamedDecl *, 8> > Decls;
for (paths_iterator Path = begin(), PathEnd = end(); Path != PathEnd; ++Path)
- Decls.insert(*Path->Decls.first);
+ Decls.insert(Path->Decls.front());
NumDeclsFound = Decls.size();
DeclsFound = new NamedDecl * [NumDeclsFound];
@@ -118,7 +118,19 @@ static bool BaseIsNot(const CXXRecordDecl *Base, void *OpaqueTarget) {
}
bool CXXRecordDecl::isProvablyNotDerivedFrom(const CXXRecordDecl *Base) const {
- return forallBases(BaseIsNot, (void*) Base->getCanonicalDecl());
+ return forallBases(BaseIsNot,
+ const_cast<CXXRecordDecl *>(Base->getCanonicalDecl()));
+}
+
+bool
+CXXRecordDecl::isCurrentInstantiation(const DeclContext *CurContext) const {
+ assert(isDependentContext());
+
+ for (; !CurContext->isFileContext(); CurContext = CurContext->getParent())
+ if (CurContext->Equals(this))
+ return true;
+
+ return false;
}
bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches,
@@ -140,7 +152,9 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches,
CXXRecordDecl *Base =
cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition());
- if (!Base) {
+ if (!Base ||
+ (Base->isDependentContext() &&
+ !Base->isCurrentInstantiation(Record))) {
if (AllowShortCircuit) return false;
AllMatches = false;
continue;
@@ -384,9 +398,9 @@ bool CXXRecordDecl::FindTagMember(const CXXBaseSpecifier *Specifier,
DeclarationName N = DeclarationName::getFromOpaquePtr(Name);
for (Path.Decls = BaseRecord->lookup(N);
- Path.Decls.first != Path.Decls.second;
- ++Path.Decls.first) {
- if ((*Path.Decls.first)->isInIdentifierNamespace(IDNS_Tag))
+ !Path.Decls.empty();
+ Path.Decls = Path.Decls.slice(1)) {
+ if (Path.Decls.front()->isInIdentifierNamespace(IDNS_Tag))
return true;
}
@@ -402,9 +416,9 @@ bool CXXRecordDecl::FindOrdinaryMember(const CXXBaseSpecifier *Specifier,
const unsigned IDNS = IDNS_Ordinary | IDNS_Tag | IDNS_Member;
DeclarationName N = DeclarationName::getFromOpaquePtr(Name);
for (Path.Decls = BaseRecord->lookup(N);
- Path.Decls.first != Path.Decls.second;
- ++Path.Decls.first) {
- if ((*Path.Decls.first)->isInIdentifierNamespace(IDNS))
+ !Path.Decls.empty();
+ Path.Decls = Path.Decls.slice(1)) {
+ if (Path.Decls.front()->isInIdentifierNamespace(IDNS))
return true;
}
@@ -420,11 +434,11 @@ FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier,
DeclarationName N = DeclarationName::getFromOpaquePtr(Name);
for (Path.Decls = BaseRecord->lookup(N);
- Path.Decls.first != Path.Decls.second;
- ++Path.Decls.first) {
+ !Path.Decls.empty();
+ Path.Decls = Path.Decls.slice(1)) {
// FIXME: Refactor the "is it a nested-name-specifier?" check
- if (isa<TypedefNameDecl>(*Path.Decls.first) ||
- (*Path.Decls.first)->isInIdentifierNamespace(IDNS_Tag))
+ if (isa<TypedefNameDecl>(Path.Decls.front()) ||
+ Path.Decls.front()->isInIdentifierNamespace(IDNS_Tag))
return true;
}
@@ -725,4 +739,3 @@ CXXRecordDecl::getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet& Bases) const {
AddIndirectPrimaryBases(BaseDecl, Context, Bases);
}
}
-
diff --git a/lib/AST/Comment.cpp b/lib/AST/Comment.cpp
index 361f8ac..db55c04 100644
--- a/lib/AST/Comment.cpp
+++ b/lib/AST/Comment.cpp
@@ -32,20 +32,6 @@ const char *Comment::getCommentKindName() const {
llvm_unreachable("Unknown comment kind!");
}
-void Comment::dump() const {
- // It is important that Comment::dump() is defined in a different TU than
- // Comment::dump(raw_ostream, SourceManager). If both functions were defined
- // in CommentDumper.cpp, that object file would be removed by linker because
- // none of its functions are referenced by other object files, despite the
- // LLVM_ATTRIBUTE_USED.
- dump(llvm::errs(), NULL, NULL);
-}
-
-void Comment::dump(const ASTContext &Context) const {
- dump(llvm::errs(), &Context.getCommentCommandTraits(),
- &Context.getSourceManager());
-}
-
namespace {
struct good {};
struct bad {};
@@ -255,32 +241,32 @@ void DeclInfo::fill() {
while (true) {
TL = TL.IgnoreParens();
// Look through qualified types.
- if (QualifiedTypeLoc *QualifiedTL = dyn_cast<QualifiedTypeLoc>(&TL)) {
- TL = QualifiedTL->getUnqualifiedLoc();
+ if (QualifiedTypeLoc QualifiedTL = TL.getAs<QualifiedTypeLoc>()) {
+ TL = QualifiedTL.getUnqualifiedLoc();
continue;
}
// Look through pointer types.
- if (PointerTypeLoc *PointerTL = dyn_cast<PointerTypeLoc>(&TL)) {
- TL = PointerTL->getPointeeLoc().getUnqualifiedLoc();
+ if (PointerTypeLoc PointerTL = TL.getAs<PointerTypeLoc>()) {
+ TL = PointerTL.getPointeeLoc().getUnqualifiedLoc();
continue;
}
- if (BlockPointerTypeLoc *BlockPointerTL =
- dyn_cast<BlockPointerTypeLoc>(&TL)) {
- TL = BlockPointerTL->getPointeeLoc().getUnqualifiedLoc();
+ if (BlockPointerTypeLoc BlockPointerTL =
+ TL.getAs<BlockPointerTypeLoc>()) {
+ TL = BlockPointerTL.getPointeeLoc().getUnqualifiedLoc();
continue;
}
- if (MemberPointerTypeLoc *MemberPointerTL =
- dyn_cast<MemberPointerTypeLoc>(&TL)) {
- TL = MemberPointerTL->getPointeeLoc().getUnqualifiedLoc();
+ if (MemberPointerTypeLoc MemberPointerTL =
+ TL.getAs<MemberPointerTypeLoc>()) {
+ TL = MemberPointerTL.getPointeeLoc().getUnqualifiedLoc();
continue;
}
// Is this a typedef for a function type?
- if (FunctionTypeLoc *FTL = dyn_cast<FunctionTypeLoc>(&TL)) {
+ if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) {
Kind = FunctionKind;
- ArrayRef<ParmVarDecl *> Params = FTL->getParams();
+ ArrayRef<ParmVarDecl *> Params = FTL.getParams();
ParamVars = ArrayRef<const ParmVarDecl *>(Params.data(),
Params.size());
- ResultType = FTL->getResultLoc().getType();
+ ResultType = FTL.getResultLoc().getType();
break;
}
break;
diff --git a/lib/AST/CommentBriefParser.cpp b/lib/AST/CommentBriefParser.cpp
index 95daa7e..090b921 100644
--- a/lib/AST/CommentBriefParser.cpp
+++ b/lib/AST/CommentBriefParser.cpp
@@ -78,7 +78,7 @@ std::string BriefParser::Parse() {
continue;
}
- if (Tok.is(tok::command)) {
+ if (Tok.is(tok::backslash_command) || Tok.is(tok::at_command)) {
const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
if (Info->IsBriefCommand) {
FirstParagraphOrBrief.clear();
diff --git a/lib/AST/CommentCommandTraits.cpp b/lib/AST/CommentCommandTraits.cpp
index e7e40fd..e24d542 100644
--- a/lib/AST/CommentCommandTraits.cpp
+++ b/lib/AST/CommentCommandTraits.cpp
@@ -15,9 +15,21 @@ namespace comments {
#include "clang/AST/CommentCommandInfo.inc"
-CommandTraits::CommandTraits(llvm::BumpPtrAllocator &Allocator) :
- NextID(llvm::array_lengthof(Commands)), Allocator(Allocator)
-{ }
+CommandTraits::CommandTraits(llvm::BumpPtrAllocator &Allocator,
+ const CommentOptions &CommentOptions) :
+ NextID(llvm::array_lengthof(Commands)), Allocator(Allocator) {
+ registerCommentOptions(CommentOptions);
+}
+
+void CommandTraits::registerCommentOptions(
+ const CommentOptions &CommentOptions) {
+ for (CommentOptions::BlockCommandNamesTy::const_iterator
+ I = CommentOptions.BlockCommandNames.begin(),
+ E = CommentOptions.BlockCommandNames.end();
+ I != E; I++) {
+ registerBlockCommand(*I);
+ }
+}
const CommandInfo *CommandTraits::getCommandInfoOrNULL(StringRef Name) const {
if (const CommandInfo *Info = getBuiltinCommandInfo(Name))
@@ -31,7 +43,7 @@ const CommandInfo *CommandTraits::getCommandInfo(unsigned CommandID) const {
return getRegisteredCommandInfo(CommandID);
}
-const CommandInfo *CommandTraits::registerUnknownCommand(StringRef CommandName) {
+CommandInfo *CommandTraits::createCommandInfoWithName(StringRef CommandName) {
char *Name = Allocator.Allocate<char>(CommandName.size() + 1);
memcpy(Name, CommandName.data(), CommandName.size());
Name[CommandName.size()] = '\0';
@@ -40,13 +52,25 @@ const CommandInfo *CommandTraits::registerUnknownCommand(StringRef CommandName)
CommandInfo *Info = new (Allocator) CommandInfo();
Info->Name = Name;
Info->ID = NextID++;
- Info->IsUnknownCommand = true;
RegisteredCommands.push_back(Info);
return Info;
}
+const CommandInfo *CommandTraits::registerUnknownCommand(
+ StringRef CommandName) {
+ CommandInfo *Info = createCommandInfoWithName(CommandName);
+ Info->IsUnknownCommand = true;
+ return Info;
+}
+
+const CommandInfo *CommandTraits::registerBlockCommand(StringRef CommandName) {
+ CommandInfo *Info = createCommandInfoWithName(CommandName);
+ Info->IsBlockCommand = true;
+ return Info;
+}
+
const CommandInfo *CommandTraits::getBuiltinCommandInfo(
unsigned CommandID) {
if (CommandID < llvm::array_lengthof(Commands))
diff --git a/lib/AST/CommentDumper.cpp b/lib/AST/CommentDumper.cpp
deleted file mode 100644
index 19d24b2..0000000
--- a/lib/AST/CommentDumper.cpp
+++ /dev/null
@@ -1,257 +0,0 @@
-//===--- CommentDumper.cpp - Dumping implementation for Comment ASTs ------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/AST/CommentVisitor.h"
-#include "llvm/Support/raw_ostream.h"
-
-namespace clang {
-namespace comments {
-
-namespace {
-class CommentDumper: public comments::ConstCommentVisitor<CommentDumper> {
- raw_ostream &OS;
- const CommandTraits *Traits;
- const SourceManager *SM;
-
- /// The \c FullComment parent of the comment being dumped.
- const FullComment *FC;
-
- unsigned IndentLevel;
-
-public:
- CommentDumper(raw_ostream &OS,
- const CommandTraits *Traits,
- const SourceManager *SM,
- const FullComment *FC) :
- OS(OS), Traits(Traits), SM(SM), FC(FC), IndentLevel(0)
- { }
-
- void dumpIndent() const {
- for (unsigned i = 1, e = IndentLevel; i < e; ++i)
- OS << " ";
- }
-
- void dumpLocation(SourceLocation Loc) {
- if (SM)
- Loc.print(OS, *SM);
- }
-
- void dumpSourceRange(const Comment *C);
-
- void dumpComment(const Comment *C);
-
- void dumpSubtree(const Comment *C);
-
- // Inline content.
- void visitTextComment(const TextComment *C);
- void visitInlineCommandComment(const InlineCommandComment *C);
- void visitHTMLStartTagComment(const HTMLStartTagComment *C);
- void visitHTMLEndTagComment(const HTMLEndTagComment *C);
-
- // Block content.
- void visitParagraphComment(const ParagraphComment *C);
- void visitBlockCommandComment(const BlockCommandComment *C);
- void visitParamCommandComment(const ParamCommandComment *C);
- void visitTParamCommandComment(const TParamCommandComment *C);
- void visitVerbatimBlockComment(const VerbatimBlockComment *C);
- void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
- void visitVerbatimLineComment(const VerbatimLineComment *C);
-
- void visitFullComment(const FullComment *C);
-
- const char *getCommandName(unsigned CommandID) {
- if (Traits)
- return Traits->getCommandInfo(CommandID)->Name;
- const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID);
- if (Info)
- return Info->Name;
- return "<not a builtin command>";
- }
-};
-
-void CommentDumper::dumpSourceRange(const Comment *C) {
- if (!SM)
- return;
-
- SourceRange SR = C->getSourceRange();
-
- OS << " <";
- dumpLocation(SR.getBegin());
- if (SR.getBegin() != SR.getEnd()) {
- OS << ", ";
- dumpLocation(SR.getEnd());
- }
- OS << ">";
-}
-
-void CommentDumper::dumpComment(const Comment *C) {
- dumpIndent();
- OS << "(" << C->getCommentKindName()
- << " " << (const void *) C;
- dumpSourceRange(C);
-}
-
-void CommentDumper::dumpSubtree(const Comment *C) {
- ++IndentLevel;
- if (C) {
- visit(C);
- for (Comment::child_iterator I = C->child_begin(),
- E = C->child_end();
- I != E; ++I) {
- OS << '\n';
- dumpSubtree(*I);
- }
- OS << ')';
- } else {
- dumpIndent();
- OS << "<<<NULL>>>";
- }
- --IndentLevel;
-}
-
-void CommentDumper::visitTextComment(const TextComment *C) {
- dumpComment(C);
-
- OS << " Text=\"" << C->getText() << "\"";
-}
-
-void CommentDumper::visitInlineCommandComment(const InlineCommandComment *C) {
- dumpComment(C);
-
- OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"";
- switch (C->getRenderKind()) {
- case InlineCommandComment::RenderNormal:
- OS << " RenderNormal";
- break;
- case InlineCommandComment::RenderBold:
- OS << " RenderBold";
- break;
- case InlineCommandComment::RenderMonospaced:
- OS << " RenderMonospaced";
- break;
- case InlineCommandComment::RenderEmphasized:
- OS << " RenderEmphasized";
- break;
- }
-
- for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
- OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
-}
-
-void CommentDumper::visitHTMLStartTagComment(const HTMLStartTagComment *C) {
- dumpComment(C);
-
- OS << " Name=\"" << C->getTagName() << "\"";
- if (C->getNumAttrs() != 0) {
- OS << " Attrs: ";
- for (unsigned i = 0, e = C->getNumAttrs(); i != e; ++i) {
- const HTMLStartTagComment::Attribute &Attr = C->getAttr(i);
- OS << " \"" << Attr.Name << "=\"" << Attr.Value << "\"";
- }
- }
- if (C->isSelfClosing())
- OS << " SelfClosing";
-}
-
-void CommentDumper::visitHTMLEndTagComment(const HTMLEndTagComment *C) {
- dumpComment(C);
-
- OS << " Name=\"" << C->getTagName() << "\"";
-}
-
-void CommentDumper::visitParagraphComment(const ParagraphComment *C) {
- dumpComment(C);
-}
-
-void CommentDumper::visitBlockCommandComment(const BlockCommandComment *C) {
- dumpComment(C);
-
- OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"";
- for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
- OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
-}
-
-void CommentDumper::visitParamCommandComment(const ParamCommandComment *C) {
- dumpComment(C);
-
- OS << " " << ParamCommandComment::getDirectionAsString(C->getDirection());
-
- if (C->isDirectionExplicit())
- OS << " explicitly";
- else
- OS << " implicitly";
-
- if (C->hasParamName()) {
- if (C->isParamIndexValid())
- OS << " Param=\"" << C->getParamName(FC) << "\"";
- else
- OS << " Param=\"" << C->getParamNameAsWritten() << "\"";
- }
-
- if (C->isParamIndexValid())
- OS << " ParamIndex=" << C->getParamIndex();
-}
-
-void CommentDumper::visitTParamCommandComment(const TParamCommandComment *C) {
- dumpComment(C);
-
- if (C->hasParamName()) {
- if (C->isPositionValid())
- OS << " Param=\"" << C->getParamName(FC) << "\"";
- else
- OS << " Param=\"" << C->getParamNameAsWritten() << "\"";
- }
-
- if (C->isPositionValid()) {
- OS << " Position=<";
- for (unsigned i = 0, e = C->getDepth(); i != e; ++i) {
- OS << C->getIndex(i);
- if (i != e - 1)
- OS << ", ";
- }
- OS << ">";
- }
-}
-
-void CommentDumper::visitVerbatimBlockComment(const VerbatimBlockComment *C) {
- dumpComment(C);
-
- OS << " Name=\"" << getCommandName(C->getCommandID()) << "\""
- " CloseName=\"" << C->getCloseName() << "\"";
-}
-
-void CommentDumper::visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C) {
- dumpComment(C);
-
- OS << " Text=\"" << C->getText() << "\"";
-}
-
-void CommentDumper::visitVerbatimLineComment(const VerbatimLineComment *C) {
- dumpComment(C);
-
- OS << " Text=\"" << C->getText() << "\"";
-}
-
-void CommentDumper::visitFullComment(const FullComment *C) {
- dumpComment(C);
-}
-
-} // unnamed namespace
-
-void Comment::dump(llvm::raw_ostream &OS, const CommandTraits *Traits,
- const SourceManager *SM) const {
- const FullComment *FC = dyn_cast<FullComment>(this);
- CommentDumper D(llvm::errs(), Traits, SM, FC);
- D.dumpSubtree(this);
- llvm::errs() << '\n';
-}
-
-} // end namespace comments
-} // end namespace clang
-
diff --git a/lib/AST/CommentLexer.cpp b/lib/AST/CommentLexer.cpp
index 31a09f7..1194520 100644
--- a/lib/AST/CommentLexer.cpp
+++ b/lib/AST/CommentLexer.cpp
@@ -1,7 +1,9 @@
#include "clang/AST/CommentLexer.h"
#include "clang/AST/CommentCommandTraits.h"
-#include "clang/Basic/ConvertUTF.h"
+#include "clang/Basic/CharInfo.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/ErrorHandling.h"
namespace clang {
@@ -13,34 +15,46 @@ void Token::dump(const Lexer &L, const SourceManager &SM) const {
llvm::errs() << " " << Length << " \"" << L.getSpelling(*this, SM) << "\"\n";
}
-namespace {
-bool isHTMLNamedCharacterReferenceCharacter(char C) {
- return (C >= 'a' && C <= 'z') ||
- (C >= 'A' && C <= 'Z');
+static inline bool isHTMLNamedCharacterReferenceCharacter(char C) {
+ return isLetter(C);
}
-bool isHTMLDecimalCharacterReferenceCharacter(char C) {
- return C >= '0' && C <= '9';
+static inline bool isHTMLDecimalCharacterReferenceCharacter(char C) {
+ return isDigit(C);
}
-bool isHTMLHexCharacterReferenceCharacter(char C) {
- return (C >= '0' && C <= '9') ||
- (C >= 'a' && C <= 'f') ||
- (C >= 'A' && C <= 'F');
+static inline bool isHTMLHexCharacterReferenceCharacter(char C) {
+ return isHexDigit(C);
}
+static inline StringRef convertCodePointToUTF8(
+ llvm::BumpPtrAllocator &Allocator,
+ unsigned CodePoint) {
+ char *Resolved = Allocator.Allocate<char>(UNI_MAX_UTF8_BYTES_PER_CODE_POINT);
+ char *ResolvedPtr = Resolved;
+ if (llvm::ConvertCodePointToUTF8(CodePoint, ResolvedPtr))
+ return StringRef(Resolved, ResolvedPtr - Resolved);
+ else
+ return StringRef();
+}
+
+namespace {
+
#include "clang/AST/CommentHTMLTags.inc"
+#include "clang/AST/CommentHTMLNamedCharacterReferences.inc"
} // unnamed namespace
StringRef Lexer::resolveHTMLNamedCharacterReference(StringRef Name) const {
+ // Fast path, first check a few most widely used named character references.
return llvm::StringSwitch<StringRef>(Name)
.Case("amp", "&")
.Case("lt", "<")
.Case("gt", ">")
.Case("quot", "\"")
.Case("apos", "\'")
- .Default("");
+ // Slow path.
+ .Default(translateHTMLNamedCharacterReferenceToUTF8(Name));
}
StringRef Lexer::resolveHTMLDecimalCharacterReference(StringRef Name) const {
@@ -50,13 +64,7 @@ StringRef Lexer::resolveHTMLDecimalCharacterReference(StringRef Name) const {
CodePoint *= 10;
CodePoint += Name[i] - '0';
}
-
- char *Resolved = Allocator.Allocate<char>(UNI_MAX_UTF8_BYTES_PER_CODE_POINT);
- char *ResolvedPtr = Resolved;
- if (ConvertCodePointToUTF8(CodePoint, ResolvedPtr))
- return StringRef(Resolved, ResolvedPtr - Resolved);
- else
- return StringRef();
+ return convertCodePointToUTF8(Allocator, CodePoint);
}
StringRef Lexer::resolveHTMLHexCharacterReference(StringRef Name) const {
@@ -65,20 +73,9 @@ StringRef Lexer::resolveHTMLHexCharacterReference(StringRef Name) const {
CodePoint *= 16;
const char C = Name[i];
assert(isHTMLHexCharacterReferenceCharacter(C));
- if (C >= '0' && C <= '9')
- CodePoint += Name[i] - '0';
- else if (C >= 'a' && C <= 'f')
- CodePoint += Name[i] - 'a' + 10;
- else
- CodePoint += Name[i] - 'A' + 10;
+ CodePoint += llvm::hexDigitValue(C);
}
-
- char *Resolved = Allocator.Allocate<char>(UNI_MAX_UTF8_BYTES_PER_CODE_POINT);
- char *ResolvedPtr = Resolved;
- if (ConvertCodePointToUTF8(CodePoint, ResolvedPtr))
- return StringRef(Resolved, ResolvedPtr - Resolved);
- else
- return StringRef();
+ return convertCodePointToUTF8(Allocator, CodePoint);
}
void Lexer::skipLineStartingDecorations() {
@@ -99,7 +96,7 @@ void Lexer::skipLineStartingDecorations() {
return;
char C = *NewBufferPtr;
- while (C == ' ' || C == '\t' || C == '\f' || C == '\v') {
+ while (isHorizontalWhitespace(C)) {
NewBufferPtr++;
if (NewBufferPtr == CommentEnd)
return;
@@ -119,8 +116,7 @@ namespace {
/// Returns pointer to the first newline character in the string.
const char *findNewline(const char *BufferPtr, const char *BufferEnd) {
for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
- const char C = *BufferPtr;
- if (C == '\n' || C == '\r')
+ if (isVerticalWhitespace(*BufferPtr))
return BufferPtr;
}
return BufferEnd;
@@ -169,14 +165,11 @@ const char *skipHexCharacterReference(const char *BufferPtr,
}
bool isHTMLIdentifierStartingCharacter(char C) {
- return (C >= 'a' && C <= 'z') ||
- (C >= 'A' && C <= 'Z');
+ return isLetter(C);
}
bool isHTMLIdentifierCharacter(char C) {
- return (C >= 'a' && C <= 'z') ||
- (C >= 'A' && C <= 'Z') ||
- (C >= '0' && C <= '9');
+ return isAlphanumeric(C);
}
const char *skipHTMLIdentifier(const char *BufferPtr, const char *BufferEnd) {
@@ -205,15 +198,6 @@ const char *skipHTMLQuotedString(const char *BufferPtr, const char *BufferEnd)
return BufferEnd;
}
-bool isHorizontalWhitespace(char C) {
- return C == ' ' || C == '\t' || C == '\f' || C == '\v';
-}
-
-bool isWhitespace(char C) {
- return C == ' ' || C == '\n' || C == '\r' ||
- C == '\t' || C == '\f' || C == '\v';
-}
-
const char *skipWhitespace(const char *BufferPtr, const char *BufferEnd) {
for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
if (!isWhitespace(*BufferPtr))
@@ -227,14 +211,11 @@ bool isWhitespace(const char *BufferPtr, const char *BufferEnd) {
}
bool isCommandNameStartCharacter(char C) {
- return (C >= 'a' && C <= 'z') ||
- (C >= 'A' && C <= 'Z');
+ return isLetter(C);
}
bool isCommandNameCharacter(char C) {
- return (C >= 'a' && C <= 'z') ||
- (C >= 'A' && C <= 'Z') ||
- (C >= '0' && C <= '9');
+ return isAlphanumeric(C);
}
const char *skipCommandName(const char *BufferPtr, const char *BufferEnd) {
@@ -250,12 +231,10 @@ const char *skipCommandName(const char *BufferPtr, const char *BufferEnd) {
const char *findBCPLCommentEnd(const char *BufferPtr, const char *BufferEnd) {
const char *CurPtr = BufferPtr;
while (CurPtr != BufferEnd) {
- char C = *CurPtr;
- while (C != '\n' && C != '\r') {
+ while (!isVerticalWhitespace(*CurPtr)) {
CurPtr++;
if (CurPtr == BufferEnd)
return BufferEnd;
- C = *CurPtr;
}
// We found a newline, check if it is escaped.
const char *EscapePtr = CurPtr - 1;
@@ -319,6 +298,11 @@ void Lexer::lexCommentText(Token &T) {
switch(*TokenPtr) {
case '\\':
case '@': {
+ // Commands that start with a backslash and commands that start with
+ // 'at' have equivalent semantics. But we keep information about the
+ // exact syntax in AST for comments.
+ tok::TokenKind CommandKind =
+ (*TokenPtr == '@') ? tok::at_command : tok::backslash_command;
TokenPtr++;
if (TokenPtr == CommentEnd) {
formTextToken(T, TokenPtr);
@@ -379,7 +363,7 @@ void Lexer::lexCommentText(Token &T) {
setupAndLexVerbatimLine(T, TokenPtr, Info);
return;
}
- formTokenWithChars(T, TokenPtr, tok::command);
+ formTokenWithChars(T, TokenPtr, CommandKind);
T.setCommandID(Info->getID());
return;
}
@@ -415,15 +399,12 @@ void Lexer::lexCommentText(Token &T) {
return;
default: {
- while (true) {
- TokenPtr++;
- if (TokenPtr == CommentEnd)
- break;
- const char C = *TokenPtr;
- if(C == '\n' || C == '\r' ||
- C == '\\' || C == '@' || C == '&' || C == '<')
- break;
- }
+ size_t End = StringRef(TokenPtr, CommentEnd - TokenPtr).
+ find_first_of("\n\r\\@&<");
+ if (End != StringRef::npos)
+ TokenPtr += End;
+ else
+ TokenPtr = CommentEnd;
formTextToken(T, TokenPtr);
return;
}
@@ -446,13 +427,11 @@ void Lexer::setupAndLexVerbatimBlock(Token &T,
// If there is a newline following the verbatim opening command, skip the
// newline so that we don't create an tok::verbatim_block_line with empty
// text content.
- if (BufferPtr != CommentEnd) {
- const char C = *BufferPtr;
- if (C == '\n' || C == '\r') {
- BufferPtr = skipNewline(BufferPtr, CommentEnd);
- State = LS_VerbatimBlockBody;
- return;
- }
+ if (BufferPtr != CommentEnd &&
+ isVerticalWhitespace(*BufferPtr)) {
+ BufferPtr = skipNewline(BufferPtr, CommentEnd);
+ State = LS_VerbatimBlockBody;
+ return;
}
State = LS_VerbatimBlockFirstLine;
diff --git a/lib/AST/CommentParser.cpp b/lib/AST/CommentParser.cpp
index d0a8474..09912c6 100644
--- a/lib/AST/CommentParser.cpp
+++ b/lib/AST/CommentParser.cpp
@@ -8,9 +8,10 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/CommentParser.h"
-#include "clang/AST/CommentSema.h"
-#include "clang/AST/CommentDiagnostic.h"
#include "clang/AST/CommentCommandTraits.h"
+#include "clang/AST/CommentDiagnostic.h"
+#include "clang/AST/CommentSema.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/Support/ErrorHandling.h"
@@ -109,11 +110,6 @@ class TextTokenRetokenizer {
return true;
}
- static bool isWhitespace(char C) {
- return C == ' ' || C == '\n' || C == '\r' ||
- C == '\t' || C == '\f' || C == '\v';
- }
-
void consumeWhitespace() {
while (!isEnd()) {
if (isWhitespace(peek()))
@@ -175,8 +171,7 @@ public:
memcpy(TextPtr, WordText.c_str(), Length + 1);
StringRef Text = StringRef(TextPtr, Length);
- formTokenWithChars(Tok, Loc, WordBegin,
- Pos.BufferPtr - WordBegin, Text);
+ formTokenWithChars(Tok, Loc, WordBegin, Length, Text);
return true;
}
@@ -305,7 +300,7 @@ void Parser::parseBlockCommandArgs(BlockCommandComment *BC,
}
BlockCommandComment *Parser::parseBlockCommand() {
- assert(Tok.is(tok::command));
+ assert(Tok.is(tok::backslash_command) || Tok.is(tok::at_command));
ParamCommandComment *PC;
TParamCommandComment *TPC;
@@ -313,25 +308,29 @@ BlockCommandComment *Parser::parseBlockCommand() {
bool IsParam = false;
bool IsTParam = false;
const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
+ CommandMarkerKind CommandMarker =
+ Tok.is(tok::backslash_command) ? CMK_Backslash : CMK_At;
if (Info->IsParamCommand) {
IsParam = true;
PC = S.actOnParamCommandStart(Tok.getLocation(),
Tok.getEndLocation(),
- Tok.getCommandID());
- } if (Info->IsTParamCommand) {
+ Tok.getCommandID(),
+ CommandMarker);
+ } else if (Info->IsTParamCommand) {
IsTParam = true;
TPC = S.actOnTParamCommandStart(Tok.getLocation(),
Tok.getEndLocation(),
- Tok.getCommandID());
+ Tok.getCommandID(),
+ CommandMarker);
} else {
BC = S.actOnBlockCommandStart(Tok.getLocation(),
Tok.getEndLocation(),
- Tok.getCommandID());
+ Tok.getCommandID(),
+ CommandMarker);
}
consumeToken();
- if (Tok.is(tok::command) &&
- Traits.getCommandInfo(Tok.getCommandID())->IsBlockCommand) {
+ if (isTokBlockCommand()) {
// Block command ahead. We can't nest block commands, so pretend that this
// command has an empty argument.
ParagraphComment *Paragraph = S.actOnParagraphComment(
@@ -363,10 +362,28 @@ BlockCommandComment *Parser::parseBlockCommand() {
Retokenizer.putBackLeftoverTokens();
}
- BlockContentComment *Block = parseParagraphOrBlockCommand();
- // Since we have checked for a block command, we should have parsed a
- // paragraph.
- ParagraphComment *Paragraph = cast<ParagraphComment>(Block);
+ // If there's a block command ahead, we will attach an empty paragraph to
+ // this command.
+ bool EmptyParagraph = false;
+ if (isTokBlockCommand())
+ EmptyParagraph = true;
+ else if (Tok.is(tok::newline)) {
+ Token PrevTok = Tok;
+ consumeToken();
+ EmptyParagraph = isTokBlockCommand();
+ putBack(PrevTok);
+ }
+
+ ParagraphComment *Paragraph;
+ if (EmptyParagraph)
+ Paragraph = S.actOnParagraphComment(ArrayRef<InlineContentComment *>());
+ else {
+ BlockContentComment *Block = parseParagraphOrBlockCommand();
+ // Since we have checked for a block command, we should have parsed a
+ // paragraph.
+ Paragraph = cast<ParagraphComment>(Block);
+ }
+
if (IsParam) {
S.actOnParamCommandFinish(PC, Paragraph);
return PC;
@@ -380,7 +397,7 @@ BlockCommandComment *Parser::parseBlockCommand() {
}
InlineCommandComment *Parser::parseInlineCommand() {
- assert(Tok.is(tok::command));
+ assert(Tok.is(tok::backslash_command) || Tok.is(tok::at_command));
const Token CommandTok = Tok;
consumeToken();
@@ -547,7 +564,8 @@ BlockContentComment *Parser::parseParagraphOrBlockCommand() {
consumeToken();
continue;
- case tok::command: {
+ case tok::backslash_command:
+ case tok::at_command: {
const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
if (Info->IsBlockCommand) {
if (Content.size() == 0)
@@ -557,6 +575,7 @@ BlockContentComment *Parser::parseParagraphOrBlockCommand() {
if (Info->IsVerbatimBlockEndCommand) {
Diag(Tok.getLocation(),
diag::warn_verbatim_block_end_without_start)
+ << Tok.is(tok::at_command)
<< Info->Name
<< SourceRange(Tok.getLocation(), Tok.getEndLocation());
consumeToken();
@@ -694,7 +713,8 @@ BlockContentComment *Parser::parseBlockContent() {
switch (Tok.getKind()) {
case tok::text:
case tok::unknown_command:
- case tok::command:
+ case tok::backslash_command:
+ case tok::at_command:
case tok::html_start_tag:
case tok::html_end_tag:
return parseParagraphOrBlockCommand();
diff --git a/lib/AST/CommentSema.cpp b/lib/AST/CommentSema.cpp
index 08ecb3a..e0138d5 100644
--- a/lib/AST/CommentSema.cpp
+++ b/lib/AST/CommentSema.cpp
@@ -8,14 +8,15 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/CommentSema.h"
-#include "clang/AST/CommentDiagnostic.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/CommentCommandTraits.h"
+#include "clang/AST/CommentDiagnostic.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Preprocessor.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringSwitch.h"
namespace clang {
namespace comments {
@@ -28,7 +29,8 @@ Sema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr,
DiagnosticsEngine &Diags, CommandTraits &Traits,
const Preprocessor *PP) :
Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits),
- PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), ReturnsCommand(NULL) {
+ PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), ReturnsCommand(NULL),
+ HeaderfileCommand(NULL) {
}
void Sema::setDecl(const Decl *D) {
@@ -45,10 +47,16 @@ ParagraphComment *Sema::actOnParagraphComment(
return new (Allocator) ParagraphComment(Content);
}
-BlockCommandComment *Sema::actOnBlockCommandStart(SourceLocation LocBegin,
- SourceLocation LocEnd,
- unsigned CommandID) {
- return new (Allocator) BlockCommandComment(LocBegin, LocEnd, CommandID);
+BlockCommandComment *Sema::actOnBlockCommandStart(
+ SourceLocation LocBegin,
+ SourceLocation LocEnd,
+ unsigned CommandID,
+ CommandMarkerKind CommandMarker) {
+ BlockCommandComment *BC = new (Allocator) BlockCommandComment(LocBegin, LocEnd,
+ CommandID,
+ CommandMarker);
+ checkContainerDecl(BC);
+ return BC;
}
void Sema::actOnBlockCommandArgs(BlockCommandComment *Command,
@@ -65,20 +73,139 @@ void Sema::actOnBlockCommandFinish(BlockCommandComment *Command,
checkDeprecatedCommand(Command);
}
-ParamCommandComment *Sema::actOnParamCommandStart(SourceLocation LocBegin,
- SourceLocation LocEnd,
- unsigned CommandID) {
+ParamCommandComment *Sema::actOnParamCommandStart(
+ SourceLocation LocBegin,
+ SourceLocation LocEnd,
+ unsigned CommandID,
+ CommandMarkerKind CommandMarker) {
ParamCommandComment *Command =
- new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID);
+ new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID,
+ CommandMarker);
if (!isFunctionDecl())
Diag(Command->getLocation(),
diag::warn_doc_param_not_attached_to_a_function_decl)
+ << CommandMarker
<< Command->getCommandNameRange(Traits);
return Command;
}
+void Sema::checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment) {
+ const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
+ if (!Info->IsFunctionDeclarationCommand)
+ return;
+
+ unsigned DiagSelect;
+ switch (Comment->getCommandID()) {
+ case CommandTraits::KCI_function:
+ DiagSelect = !isAnyFunctionDecl() ? 1 : 0;
+ break;
+ case CommandTraits::KCI_functiongroup:
+ DiagSelect = !isAnyFunctionDecl() ? 2 : 0;
+ break;
+ case CommandTraits::KCI_method:
+ DiagSelect = !isObjCMethodDecl() ? 3 : 0;
+ break;
+ case CommandTraits::KCI_methodgroup:
+ DiagSelect = !isObjCMethodDecl() ? 4 : 0;
+ break;
+ case CommandTraits::KCI_callback:
+ DiagSelect = !isFunctionPointerVarDecl() ? 5 : 0;
+ break;
+ default:
+ DiagSelect = 0;
+ break;
+ }
+ if (DiagSelect)
+ Diag(Comment->getLocation(), diag::warn_doc_function_method_decl_mismatch)
+ << Comment->getCommandMarker()
+ << (DiagSelect-1) << (DiagSelect-1)
+ << Comment->getSourceRange();
+}
+
+void Sema::checkContainerDeclVerbatimLine(const BlockCommandComment *Comment) {
+ const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
+ if (!Info->IsRecordLikeDeclarationCommand)
+ return;
+ unsigned DiagSelect;
+ switch (Comment->getCommandID()) {
+ case CommandTraits::KCI_class:
+ DiagSelect = !isClassOrStructDecl() ? 1 : 0;
+ break;
+ case CommandTraits::KCI_interface:
+ DiagSelect = !isObjCInterfaceDecl() ? 2 : 0;
+ break;
+ case CommandTraits::KCI_protocol:
+ DiagSelect = !isObjCProtocolDecl() ? 3 : 0;
+ break;
+ case CommandTraits::KCI_struct:
+ DiagSelect = !isClassOrStructDecl() ? 4 : 0;
+ break;
+ case CommandTraits::KCI_union:
+ DiagSelect = !isUnionDecl() ? 5 : 0;
+ break;
+ default:
+ DiagSelect = 0;
+ break;
+ }
+ if (DiagSelect)
+ Diag(Comment->getLocation(), diag::warn_doc_api_container_decl_mismatch)
+ << Comment->getCommandMarker()
+ << (DiagSelect-1) << (DiagSelect-1)
+ << Comment->getSourceRange();
+}
+
+void Sema::checkContainerDecl(const BlockCommandComment *Comment) {
+ const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
+ if (!Info->IsRecordLikeDetailCommand || isRecordLikeDecl())
+ return;
+ unsigned DiagSelect;
+ switch (Comment->getCommandID()) {
+ case CommandTraits::KCI_classdesign:
+ DiagSelect = 1;
+ break;
+ case CommandTraits::KCI_coclass:
+ DiagSelect = 2;
+ break;
+ case CommandTraits::KCI_dependency:
+ DiagSelect = 3;
+ break;
+ case CommandTraits::KCI_helper:
+ DiagSelect = 4;
+ break;
+ case CommandTraits::KCI_helperclass:
+ DiagSelect = 5;
+ break;
+ case CommandTraits::KCI_helps:
+ DiagSelect = 6;
+ break;
+ case CommandTraits::KCI_instancesize:
+ DiagSelect = 7;
+ break;
+ case CommandTraits::KCI_ownership:
+ DiagSelect = 8;
+ break;
+ case CommandTraits::KCI_performance:
+ DiagSelect = 9;
+ break;
+ case CommandTraits::KCI_security:
+ DiagSelect = 10;
+ break;
+ case CommandTraits::KCI_superclass:
+ DiagSelect = 11;
+ break;
+ default:
+ DiagSelect = 0;
+ break;
+ }
+ if (DiagSelect)
+ Diag(Comment->getLocation(), diag::warn_doc_container_decl_mismatch)
+ << Comment->getCommandMarker()
+ << (DiagSelect-1)
+ << Comment->getSourceRange();
+}
+
void Sema::actOnParamCommandDirectionArg(ParamCommandComment *Command,
SourceLocation ArgLocBegin,
SourceLocation ArgLocEnd,
@@ -158,15 +285,19 @@ void Sema::actOnParamCommandFinish(ParamCommandComment *Command,
checkBlockCommandEmptyParagraph(Command);
}
-TParamCommandComment *Sema::actOnTParamCommandStart(SourceLocation LocBegin,
- SourceLocation LocEnd,
- unsigned CommandID) {
+TParamCommandComment *Sema::actOnTParamCommandStart(
+ SourceLocation LocBegin,
+ SourceLocation LocEnd,
+ unsigned CommandID,
+ CommandMarkerKind CommandMarker) {
TParamCommandComment *Command =
- new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID);
+ new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID,
+ CommandMarker);
if (!isTemplateOrSpecialization())
Diag(Command->getLocation(),
diag::warn_doc_tparam_not_attached_to_a_template_decl)
+ << CommandMarker
<< Command->getCommandNameRange(Traits);
return Command;
@@ -324,12 +455,15 @@ VerbatimLineComment *Sema::actOnVerbatimLine(SourceLocation LocBegin,
unsigned CommandID,
SourceLocation TextBegin,
StringRef Text) {
- return new (Allocator) VerbatimLineComment(
+ VerbatimLineComment *VL = new (Allocator) VerbatimLineComment(
LocBegin,
TextBegin.getLocWithOffset(Text.size()),
CommandID,
TextBegin,
Text);
+ checkFunctionDeclVerbatimLine(VL);
+ checkContainerDeclVerbatimLine(VL);
+ return VL;
}
HTMLStartTagComment *Sema::actOnHTMLStartTagStart(SourceLocation LocBegin,
@@ -430,6 +564,7 @@ void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) {
if (!DiagLoc.isValid())
DiagLoc = Command->getCommandNameRange(Traits).getEnd();
Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
+ << Command->getCommandMarker()
<< Command->getCommandName(Traits)
<< Command->getSourceRange();
}
@@ -457,14 +592,19 @@ void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
}
Diag(Command->getLocation(),
diag::warn_doc_returns_attached_to_a_void_function)
+ << Command->getCommandMarker()
<< Command->getCommandName(Traits)
<< DiagKind
<< Command->getSourceRange();
}
return;
}
+ else if (isObjCPropertyDecl())
+ return;
+
Diag(Command->getLocation(),
diag::warn_doc_returns_not_attached_to_a_function_decl)
+ << Command->getCommandMarker()
<< Command->getCommandName(Traits)
<< Command->getSourceRange();
}
@@ -484,6 +624,12 @@ void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) {
return;
}
PrevCommand = ReturnsCommand;
+ } else if (Info->IsHeaderfileCommand) {
+ if (!HeaderfileCommand) {
+ HeaderfileCommand = Command;
+ return;
+ }
+ PrevCommand = HeaderfileCommand;
} else {
// We don't want to check this command for duplicates.
return;
@@ -491,15 +637,18 @@ void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) {
StringRef CommandName = Command->getCommandName(Traits);
StringRef PrevCommandName = PrevCommand->getCommandName(Traits);
Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate)
+ << Command->getCommandMarker()
<< CommandName
<< Command->getSourceRange();
if (CommandName == PrevCommandName)
Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous)
+ << PrevCommand->getCommandMarker()
<< PrevCommandName
<< PrevCommand->getSourceRange();
else
Diag(PrevCommand->getLocation(),
diag::note_doc_block_command_previous_alias)
+ << PrevCommand->getCommandMarker()
<< PrevCommandName
<< CommandName;
}
@@ -559,11 +708,11 @@ void Sema::resolveParamCommandIndexes(const FullComment *FC) {
return;
}
- llvm::SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands;
+ SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands;
// Comment AST nodes that correspond to \c ParamVars for which we have
// found a \\param command or NULL if no documentation was found so far.
- llvm::SmallVector<ParamCommandComment *, 8> ParamVarDocs;
+ SmallVector<ParamCommandComment *, 8> ParamVarDocs;
ArrayRef<const ParmVarDecl *> ParamVars = getParamVars();
ParamVarDocs.resize(ParamVars.size(), NULL);
@@ -596,7 +745,7 @@ void Sema::resolveParamCommandIndexes(const FullComment *FC) {
}
// Find parameter declarations that have no corresponding \\param.
- llvm::SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls;
+ SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls;
for (unsigned i = 0, e = ParamVarDocs.size(); i != e; ++i) {
if (!ParamVarDocs[i])
OrphanedParamDecls.push_back(ParamVars[i]);
@@ -645,6 +794,40 @@ bool Sema::isFunctionDecl() {
return ThisDeclInfo->getKind() == DeclInfo::FunctionKind;
}
+bool Sema::isAnyFunctionDecl() {
+ return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
+ isa<FunctionDecl>(ThisDeclInfo->CurrentDecl);
+}
+
+bool Sema::isObjCMethodDecl() {
+ return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
+ isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl);
+}
+
+/// isFunctionPointerVarDecl - returns 'true' if declaration is a pointer to
+/// function decl.
+bool Sema::isFunctionPointerVarDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ if (ThisDeclInfo->getKind() == DeclInfo::VariableKind) {
+ if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(ThisDeclInfo->CurrentDecl)) {
+ QualType QT = VD->getType();
+ return QT->isFunctionPointerType();
+ }
+ }
+ return false;
+}
+
+bool Sema::isObjCPropertyDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ return ThisDeclInfo->CurrentDecl->getKind() == Decl::ObjCProperty;
+}
+
bool Sema::isTemplateOrSpecialization() {
if (!ThisDeclInfo)
return false;
@@ -653,6 +836,54 @@ bool Sema::isTemplateOrSpecialization() {
return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate;
}
+bool Sema::isRecordLikeDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ return isUnionDecl() || isClassOrStructDecl()
+ || isObjCInterfaceDecl() || isObjCProtocolDecl();
+}
+
+bool Sema::isUnionDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ if (const RecordDecl *RD =
+ dyn_cast_or_null<RecordDecl>(ThisDeclInfo->CurrentDecl))
+ return RD->isUnion();
+ return false;
+}
+
+bool Sema::isClassOrStructDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ return ThisDeclInfo->CurrentDecl &&
+ isa<RecordDecl>(ThisDeclInfo->CurrentDecl) &&
+ !isUnionDecl();
+}
+
+bool Sema::isObjCInterfaceDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ return ThisDeclInfo->CurrentDecl &&
+ isa<ObjCInterfaceDecl>(ThisDeclInfo->CurrentDecl);
+}
+
+bool Sema::isObjCProtocolDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ return ThisDeclInfo->CurrentDecl &&
+ isa<ObjCProtocolDecl>(ThisDeclInfo->CurrentDecl);
+}
+
ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
if (!ThisDeclInfo->IsFilled)
inspectThisDecl();
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 7b13755..bf807ae 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -12,23 +12,24 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/Decl.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/TypeLoc.h"
-#include "clang/AST/Stmt.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/PrettyPrinter.h"
-#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/Support/ErrorHandling.h"
-
+#include "llvm/Support/type_traits.h"
#include <algorithm>
using namespace clang;
@@ -37,17 +38,163 @@ using namespace clang;
// NamedDecl Implementation
//===----------------------------------------------------------------------===//
-static llvm::Optional<Visibility> getVisibilityOf(const Decl *D) {
+// Visibility rules aren't rigorously externally specified, but here
+// are the basic principles behind what we implement:
+//
+// 1. An explicit visibility attribute is generally a direct expression
+// of the user's intent and should be honored. Only the innermost
+// visibility attribute applies. If no visibility attribute applies,
+// global visibility settings are considered.
+//
+// 2. There is one caveat to the above: on or in a template pattern,
+// an explicit visibility attribute is just a default rule, and
+// visibility can be decreased by the visibility of template
+// arguments. But this, too, has an exception: an attribute on an
+// explicit specialization or instantiation causes all the visibility
+// restrictions of the template arguments to be ignored.
+//
+// 3. A variable that does not otherwise have explicit visibility can
+// be restricted by the visibility of its type.
+//
+// 4. A visibility restriction is explicit if it comes from an
+// attribute (or something like it), not a global visibility setting.
+// When emitting a reference to an external symbol, visibility
+// restrictions are ignored unless they are explicit.
+//
+// 5. When computing the visibility of a non-type, including a
+// non-type member of a class, only non-type visibility restrictions
+// are considered: the 'visibility' attribute, global value-visibility
+// settings, and a few special cases like __private_extern.
+//
+// 6. When computing the visibility of a type, including a type member
+// of a class, only type visibility restrictions are considered:
+// the 'type_visibility' attribute and global type-visibility settings.
+// However, a 'visibility' attribute counts as a 'type_visibility'
+// attribute on any declaration that only has the former.
+//
+// The visibility of a "secondary" entity, like a template argument,
+// is computed using the kind of that entity, not the kind of the
+// primary entity for which we are computing visibility. For example,
+// the visibility of a specialization of either of these templates:
+// template <class T, bool (&compare)(T, X)> bool has_match(list<T>, X);
+// template <class T, bool (&compare)(T, X)> class matcher;
+// is restricted according to the type visibility of the argument 'T',
+// the type visibility of 'bool(&)(T,X)', and the value visibility of
+// the argument function 'compare'. That 'has_match' is a value
+// and 'matcher' is a type only matters when looking for attributes
+// and settings from the immediate context.
+
+const unsigned IgnoreExplicitVisibilityBit = 2;
+
+/// Kinds of LV computation. The linkage side of the computation is
+/// always the same, but different things can change how visibility is
+/// computed.
+enum LVComputationKind {
+ /// Do an LV computation for, ultimately, a type.
+ /// Visibility may be restricted by type visibility settings and
+ /// the visibility of template arguments.
+ LVForType = NamedDecl::VisibilityForType,
+
+ /// Do an LV computation for, ultimately, a non-type declaration.
+ /// Visibility may be restricted by value visibility settings and
+ /// the visibility of template arguments.
+ LVForValue = NamedDecl::VisibilityForValue,
+
+ /// Do an LV computation for, ultimately, a type that already has
+ /// some sort of explicit visibility. Visibility may only be
+ /// restricted by the visibility of template arguments.
+ LVForExplicitType = (LVForType | IgnoreExplicitVisibilityBit),
+
+ /// Do an LV computation for, ultimately, a non-type declaration
+ /// that already has some sort of explicit visibility. Visibility
+ /// may only be restricted by the visibility of template arguments.
+ LVForExplicitValue = (LVForValue | IgnoreExplicitVisibilityBit)
+};
+
+/// Does this computation kind permit us to consider additional
+/// visibility settings from attributes and the like?
+static bool hasExplicitVisibilityAlready(LVComputationKind computation) {
+ return ((unsigned(computation) & IgnoreExplicitVisibilityBit) != 0);
+}
+
+/// Given an LVComputationKind, return one of the same type/value sort
+/// that records that it already has explicit visibility.
+static LVComputationKind
+withExplicitVisibilityAlready(LVComputationKind oldKind) {
+ LVComputationKind newKind =
+ static_cast<LVComputationKind>(unsigned(oldKind) |
+ IgnoreExplicitVisibilityBit);
+ assert(oldKind != LVForType || newKind == LVForExplicitType);
+ assert(oldKind != LVForValue || newKind == LVForExplicitValue);
+ assert(oldKind != LVForExplicitType || newKind == LVForExplicitType);
+ assert(oldKind != LVForExplicitValue || newKind == LVForExplicitValue);
+ return newKind;
+}
+
+static Optional<Visibility> getExplicitVisibility(const NamedDecl *D,
+ LVComputationKind kind) {
+ assert(!hasExplicitVisibilityAlready(kind) &&
+ "asking for explicit visibility when we shouldn't be");
+ return D->getExplicitVisibility((NamedDecl::ExplicitVisibilityKind) kind);
+}
+
+/// Is the given declaration a "type" or a "value" for the purposes of
+/// visibility computation?
+static bool usesTypeVisibility(const NamedDecl *D) {
+ return isa<TypeDecl>(D) ||
+ isa<ClassTemplateDecl>(D) ||
+ isa<ObjCInterfaceDecl>(D);
+}
+
+/// Does the given declaration have member specialization information,
+/// and if so, is it an explicit specialization?
+template <class T> static typename
+llvm::enable_if_c<!llvm::is_base_of<RedeclarableTemplateDecl, T>::value,
+ bool>::type
+isExplicitMemberSpecialization(const T *D) {
+ if (const MemberSpecializationInfo *member =
+ D->getMemberSpecializationInfo()) {
+ return member->isExplicitSpecialization();
+ }
+ return false;
+}
+
+/// For templates, this question is easier: a member template can't be
+/// explicitly instantiated, so there's a single bit indicating whether
+/// or not this is an explicit member specialization.
+static bool isExplicitMemberSpecialization(const RedeclarableTemplateDecl *D) {
+ return D->isMemberSpecialization();
+}
+
+/// Given a visibility attribute, return the explicit visibility
+/// associated with it.
+template <class T>
+static Visibility getVisibilityFromAttr(const T *attr) {
+ switch (attr->getVisibility()) {
+ case T::Default:
+ return DefaultVisibility;
+ case T::Hidden:
+ return HiddenVisibility;
+ case T::Protected:
+ return ProtectedVisibility;
+ }
+ llvm_unreachable("bad visibility kind");
+}
+
+/// Return the explicit visibility of the given declaration.
+static Optional<Visibility> getVisibilityOf(const NamedDecl *D,
+ NamedDecl::ExplicitVisibilityKind kind) {
+ // If we're ultimately computing the visibility of a type, look for
+ // a 'type_visibility' attribute before looking for 'visibility'.
+ if (kind == NamedDecl::VisibilityForType) {
+ if (const TypeVisibilityAttr *A = D->getAttr<TypeVisibilityAttr>()) {
+ return getVisibilityFromAttr(A);
+ }
+ }
+
// If this declaration has an explicit visibility attribute, use it.
if (const VisibilityAttr *A = D->getAttr<VisibilityAttr>()) {
- switch (A->getVisibility()) {
- case VisibilityAttr::Default:
- return DefaultVisibility;
- case VisibilityAttr::Hidden:
- return HiddenVisibility;
- case VisibilityAttr::Protected:
- return ProtectedVisibility;
- }
+ return getVisibilityFromAttr(A);
}
// If we're on Mac OS X, an 'availability' for Mac OS X attribute
@@ -61,43 +208,61 @@ static llvm::Optional<Visibility> getVisibilityOf(const Decl *D) {
return DefaultVisibility;
}
- return llvm::Optional<Visibility>();
-}
-
-typedef NamedDecl::LinkageInfo LinkageInfo;
-
-static LinkageInfo getLVForType(QualType T) {
- std::pair<Linkage,Visibility> P = T->getLinkageAndVisibility();
- return LinkageInfo(P.first, P.second, T->isVisibilityExplicit());
+ return None;
}
/// \brief Get the most restrictive linkage for the types in the given
-/// template parameter list.
+/// template parameter list. For visibility purposes, template
+/// parameters are part of the signature of a template.
static LinkageInfo
-getLVForTemplateParameterList(const TemplateParameterList *Params) {
- LinkageInfo LV(ExternalLinkage, DefaultVisibility, false);
- for (TemplateParameterList::const_iterator P = Params->begin(),
- PEnd = Params->end();
+getLVForTemplateParameterList(const TemplateParameterList *params) {
+ LinkageInfo LV;
+ for (TemplateParameterList::const_iterator P = params->begin(),
+ PEnd = params->end();
P != PEnd; ++P) {
+
+ // Template type parameters are the most common and never
+ // contribute to visibility, pack or not.
+ if (isa<TemplateTypeParmDecl>(*P))
+ continue;
+
+ // Non-type template parameters can be restricted by the value type, e.g.
+ // template <enum X> class A { ... };
+ // We have to be careful here, though, because we can be dealing with
+ // dependent types.
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) {
- if (NTTP->isExpandedParameterPack()) {
- for (unsigned I = 0, N = NTTP->getNumExpansionTypes(); I != N; ++I) {
- QualType T = NTTP->getExpansionType(I);
- if (!T->isDependentType())
- LV.merge(getLVForType(T));
+ // Handle the non-pack case first.
+ if (!NTTP->isExpandedParameterPack()) {
+ if (!NTTP->getType()->isDependentType()) {
+ LV.merge(NTTP->getType()->getLinkageAndVisibility());
}
continue;
}
- if (!NTTP->getType()->isDependentType()) {
- LV.merge(getLVForType(NTTP->getType()));
- continue;
+ // Look at all the types in an expanded pack.
+ for (unsigned i = 0, n = NTTP->getNumExpansionTypes(); i != n; ++i) {
+ QualType type = NTTP->getExpansionType(i);
+ if (!type->isDependentType())
+ LV.merge(type->getLinkageAndVisibility());
}
+ continue;
}
- if (TemplateTemplateParmDecl *TTP
- = dyn_cast<TemplateTemplateParmDecl>(*P)) {
+ // Template template parameters can be restricted by their
+ // template parameters, recursively.
+ TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*P);
+
+ // Handle the non-pack case first.
+ if (!TTP->isExpandedParameterPack()) {
LV.merge(getLVForTemplateParameterList(TTP->getTemplateParameters()));
+ continue;
+ }
+
+ // Look at all expansions in an expanded pack.
+ for (unsigned i = 0, n = TTP->getNumExpansionTemplateParameters();
+ i != n; ++i) {
+ LV.merge(getLVForTemplateParameterList(
+ TTP->getExpansionTemplateParameters(i)));
}
}
@@ -105,67 +270,177 @@ getLVForTemplateParameterList(const TemplateParameterList *Params) {
}
/// getLVForDecl - Get the linkage and visibility for the given declaration.
-static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate);
+static LinkageInfo getLVForDecl(const NamedDecl *D,
+ LVComputationKind computation);
/// \brief Get the most restrictive linkage for the types and
/// declarations in the given template argument list.
-static LinkageInfo getLVForTemplateArgumentList(const TemplateArgument *Args,
- unsigned NumArgs,
- bool OnlyTemplate) {
- LinkageInfo LV(ExternalLinkage, DefaultVisibility, false);
+///
+/// Note that we don't take an LVComputationKind because we always
+/// want to honor the visibility of template arguments in the same way.
+static LinkageInfo
+getLVForTemplateArgumentList(ArrayRef<TemplateArgument> args) {
+ LinkageInfo LV;
- for (unsigned I = 0; I != NumArgs; ++I) {
- switch (Args[I].getKind()) {
+ for (unsigned i = 0, e = args.size(); i != e; ++i) {
+ const TemplateArgument &arg = args[i];
+ switch (arg.getKind()) {
case TemplateArgument::Null:
case TemplateArgument::Integral:
case TemplateArgument::Expression:
- break;
+ continue;
case TemplateArgument::Type:
- LV.mergeWithMin(getLVForType(Args[I].getAsType()));
- break;
+ LV.merge(arg.getAsType()->getLinkageAndVisibility());
+ continue;
case TemplateArgument::Declaration:
- if (NamedDecl *ND = dyn_cast<NamedDecl>(Args[I].getAsDecl()))
- LV.mergeWithMin(getLVForDecl(ND, OnlyTemplate));
- break;
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(arg.getAsDecl())) {
+ assert(!usesTypeVisibility(ND));
+ LV.merge(getLVForDecl(ND, LVForValue));
+ }
+ continue;
case TemplateArgument::NullPtr:
- LV.mergeWithMin(getLVForType(Args[I].getNullPtrType()));
- break;
+ LV.merge(arg.getNullPtrType()->getLinkageAndVisibility());
+ continue;
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
if (TemplateDecl *Template
- = Args[I].getAsTemplateOrTemplatePattern().getAsTemplateDecl())
- LV.mergeWithMin(getLVForDecl(Template, OnlyTemplate));
- break;
+ = arg.getAsTemplateOrTemplatePattern().getAsTemplateDecl())
+ LV.merge(getLVForDecl(Template, LVForValue));
+ continue;
case TemplateArgument::Pack:
- LV.mergeWithMin(getLVForTemplateArgumentList(Args[I].pack_begin(),
- Args[I].pack_size(),
- OnlyTemplate));
- break;
+ LV.merge(getLVForTemplateArgumentList(arg.getPackAsArray()));
+ continue;
}
+ llvm_unreachable("bad template argument kind");
}
return LV;
}
static LinkageInfo
-getLVForTemplateArgumentList(const TemplateArgumentList &TArgs,
- bool OnlyTemplate) {
- return getLVForTemplateArgumentList(TArgs.data(), TArgs.size(), OnlyTemplate);
+getLVForTemplateArgumentList(const TemplateArgumentList &TArgs) {
+ return getLVForTemplateArgumentList(TArgs.asArray());
}
-static bool shouldConsiderTemplateVis(const FunctionDecl *fn,
- const FunctionTemplateSpecializationInfo *spec) {
- return !fn->hasAttr<VisibilityAttr>() || spec->isExplicitSpecialization();
+static bool shouldConsiderTemplateVisibility(const FunctionDecl *fn,
+ const FunctionTemplateSpecializationInfo *specInfo) {
+ // Include visibility from the template parameters and arguments
+ // only if this is not an explicit instantiation or specialization
+ // with direct explicit visibility. (Implicit instantiations won't
+ // have a direct attribute.)
+ if (!specInfo->isExplicitInstantiationOrSpecialization())
+ return true;
+
+ return !fn->hasAttr<VisibilityAttr>();
+}
+
+/// Merge in template-related linkage and visibility for the given
+/// function template specialization.
+///
+/// We don't need a computation kind here because we can assume
+/// LVForValue.
+///
+/// \param[out] LV the computation to use for the parent
+static void
+mergeTemplateLV(LinkageInfo &LV, const FunctionDecl *fn,
+ const FunctionTemplateSpecializationInfo *specInfo) {
+ bool considerVisibility =
+ shouldConsiderTemplateVisibility(fn, specInfo);
+
+ // Merge information from the template parameters.
+ FunctionTemplateDecl *temp = specInfo->getTemplate();
+ LinkageInfo tempLV =
+ getLVForTemplateParameterList(temp->getTemplateParameters());
+ LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
+
+ // Merge information from the template arguments.
+ const TemplateArgumentList &templateArgs = *specInfo->TemplateArguments;
+ LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs);
+ LV.mergeMaybeWithVisibility(argsLV, considerVisibility);
+}
+
+/// Does the given declaration have a direct visibility attribute
+/// that would match the given rules?
+static bool hasDirectVisibilityAttribute(const NamedDecl *D,
+ LVComputationKind computation) {
+ switch (computation) {
+ case LVForType:
+ case LVForExplicitType:
+ if (D->hasAttr<TypeVisibilityAttr>())
+ return true;
+ // fallthrough
+ case LVForValue:
+ case LVForExplicitValue:
+ if (D->hasAttr<VisibilityAttr>())
+ return true;
+ return false;
+ }
+ llvm_unreachable("bad visibility computation kind");
+}
+
+/// Should we consider visibility associated with the template
+/// arguments and parameters of the given class template specialization?
+static bool shouldConsiderTemplateVisibility(
+ const ClassTemplateSpecializationDecl *spec,
+ LVComputationKind computation) {
+ // Include visibility from the template parameters and arguments
+ // only if this is not an explicit instantiation or specialization
+ // with direct explicit visibility (and note that implicit
+ // instantiations won't have a direct attribute).
+ //
+ // Furthermore, we want to ignore template parameters and arguments
+ // for an explicit specialization when computing the visibility of a
+ // member thereof with explicit visibility.
+ //
+ // This is a bit complex; let's unpack it.
+ //
+ // An explicit class specialization is an independent, top-level
+ // declaration. As such, if it or any of its members has an
+ // explicit visibility attribute, that must directly express the
+ // user's intent, and we should honor it. The same logic applies to
+ // an explicit instantiation of a member of such a thing.
+
+ // Fast path: if this is not an explicit instantiation or
+ // specialization, we always want to consider template-related
+ // visibility restrictions.
+ if (!spec->isExplicitInstantiationOrSpecialization())
+ return true;
+
+ // This is the 'member thereof' check.
+ if (spec->isExplicitSpecialization() &&
+ hasExplicitVisibilityAlready(computation))
+ return false;
+
+ return !hasDirectVisibilityAttribute(spec, computation);
}
-static bool
-shouldConsiderTemplateVis(const ClassTemplateSpecializationDecl *d) {
- return !d->hasAttr<VisibilityAttr>() || d->isExplicitSpecialization();
+/// Merge in template-related linkage and visibility for the given
+/// class template specialization.
+static void mergeTemplateLV(LinkageInfo &LV,
+ const ClassTemplateSpecializationDecl *spec,
+ LVComputationKind computation) {
+ bool considerVisibility = shouldConsiderTemplateVisibility(spec, computation);
+
+ // Merge information from the template parameters, but ignore
+ // visibility if we're only considering template arguments.
+
+ ClassTemplateDecl *temp = spec->getSpecializedTemplate();
+ LinkageInfo tempLV =
+ getLVForTemplateParameterList(temp->getTemplateParameters());
+ LV.mergeMaybeWithVisibility(tempLV,
+ considerVisibility && !hasExplicitVisibilityAlready(computation));
+
+ // Merge information from the template arguments. We ignore
+ // template-argument visibility if we've got an explicit
+ // instantiation with a visibility attribute.
+ const TemplateArgumentList &templateArgs = spec->getTemplateArgs();
+ LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs);
+ LV.mergeMaybeWithVisibility(argsLV, considerVisibility);
}
static bool useInlineVisibilityHidden(const NamedDecl *D) {
@@ -196,8 +471,13 @@ static bool useInlineVisibilityHidden(const NamedDecl *D) {
FD->hasBody(Def) && Def->isInlined() && !Def->hasAttr<GNUInlineAttr>();
}
+template <typename T> static bool isInExternCContext(T *D) {
+ const T *First = D->getFirstDeclaration();
+ return First->getDeclContext()->isExternCContext();
+}
+
static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
- bool OnlyTemplate) {
+ LVComputationKind computation) {
assert(D->getDeclContext()->getRedeclContext()->isFileContext() &&
"Not a name having namespace scope");
ASTContext &Context = D->getASTContext();
@@ -218,26 +498,24 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// declared to have external linkage; or (there is no equivalent in C99)
if (Context.getLangOpts().CPlusPlus &&
Var->getType().isConstQualified() &&
- !Var->getType().isVolatileQualified() &&
- Var->getStorageClass() != SC_Extern &&
- Var->getStorageClass() != SC_PrivateExtern) {
- bool FoundExtern = false;
- for (const VarDecl *PrevVar = Var->getPreviousDecl();
- PrevVar && !FoundExtern;
- PrevVar = PrevVar->getPreviousDecl())
- if (isExternalLinkage(PrevVar->getLinkage()))
- FoundExtern = true;
-
- if (!FoundExtern)
- return LinkageInfo::internal();
- }
- if (Var->getStorageClass() == SC_None) {
+ !Var->getType().isVolatileQualified()) {
const VarDecl *PrevVar = Var->getPreviousDecl();
- for (; PrevVar; PrevVar = PrevVar->getPreviousDecl())
- if (PrevVar->getStorageClass() == SC_PrivateExtern)
- break;
if (PrevVar)
return PrevVar->getLinkageAndVisibility();
+
+ if (Var->getStorageClass() != SC_Extern &&
+ Var->getStorageClass() != SC_PrivateExtern)
+ return LinkageInfo::internal();
+ }
+
+ for (const VarDecl *PrevVar = Var->getPreviousDecl(); PrevVar;
+ PrevVar = PrevVar->getPreviousDecl()) {
+ if (PrevVar->getStorageClass() == SC_PrivateExtern &&
+ Var->getStorageClass() == SC_None)
+ return PrevVar->getLinkageAndVisibility();
+ // Explicitly declared static.
+ if (PrevVar->getStorageClass() == SC_Static)
+ return LinkageInfo::internal();
}
} else if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) {
// C++ [temp]p4:
@@ -251,7 +529,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
Function = cast<FunctionDecl>(D);
// Explicitly declared static.
- if (Function->getStorageClass() == SC_Static)
+ if (Function->getCanonicalDecl()->getStorageClass() == SC_Static)
return LinkageInfo(InternalLinkage, DefaultVisibility, false);
} else if (const FieldDecl *Field = dyn_cast<FieldDecl>(D)) {
// - a data member of an anonymous union.
@@ -262,8 +540,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
if (D->isInAnonymousNamespace()) {
const VarDecl *Var = dyn_cast<VarDecl>(D);
const FunctionDecl *Func = dyn_cast<FunctionDecl>(D);
- if ((!Var || !Var->getDeclContext()->isExternCContext()) &&
- (!Func || !Func->getDeclContext()->isExternCContext()))
+ if ((!Var || !isInExternCContext(Var)) &&
+ (!Func || !isInExternCContext(Func)))
return LinkageInfo::uniqueExternal();
}
@@ -275,31 +553,41 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// external.
LinkageInfo LV;
- if (!OnlyTemplate) {
- if (llvm::Optional<Visibility> Vis = D->getExplicitVisibility()) {
+ if (!hasExplicitVisibilityAlready(computation)) {
+ if (Optional<Visibility> Vis = getExplicitVisibility(D, computation)) {
LV.mergeVisibility(*Vis, true);
} else {
// If we're declared in a namespace with a visibility attribute,
- // use that namespace's visibility, but don't call it explicit.
+ // use that namespace's visibility, and it still counts as explicit.
for (const DeclContext *DC = D->getDeclContext();
!isa<TranslationUnitDecl>(DC);
DC = DC->getParent()) {
const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC);
if (!ND) continue;
- if (llvm::Optional<Visibility> Vis = ND->getExplicitVisibility()) {
+ if (Optional<Visibility> Vis = getExplicitVisibility(ND, computation)) {
LV.mergeVisibility(*Vis, true);
break;
}
}
}
- }
- if (!OnlyTemplate) {
- LV.mergeVisibility(Context.getLangOpts().getVisibilityMode());
- // If we're paying attention to global visibility, apply
- // -finline-visibility-hidden if this is an inline method.
- if (!LV.visibilityExplicit() && useInlineVisibilityHidden(D))
- LV.mergeVisibility(HiddenVisibility, true);
+ // Add in global settings if the above didn't give us direct visibility.
+ if (!LV.isVisibilityExplicit()) {
+ // Use global type/value visibility as appropriate.
+ Visibility globalVisibility;
+ if (computation == LVForValue) {
+ globalVisibility = Context.getLangOpts().getValueVisibilityMode();
+ } else {
+ assert(computation == LVForType);
+ globalVisibility = Context.getLangOpts().getTypeVisibilityMode();
+ }
+ LV.mergeVisibility(globalVisibility, /*explicit*/ false);
+
+ // If we're paying attention to global visibility, apply
+ // -finline-visibility-hidden if this is an inline method.
+ if (useInlineVisibilityHidden(D))
+ LV.mergeVisibility(HiddenVisibility, true);
+ }
}
// C++ [basic.link]p4:
@@ -330,12 +618,12 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
//
// Note that we don't want to make the variable non-external
// because of this, but unique-external linkage suits us.
- if (Context.getLangOpts().CPlusPlus &&
- !Var->getDeclContext()->isExternCContext()) {
- LinkageInfo TypeLV = getLVForType(Var->getType());
- if (TypeLV.linkage() != ExternalLinkage)
+ if (Context.getLangOpts().CPlusPlus && !isInExternCContext(Var)) {
+ LinkageInfo TypeLV = Var->getType()->getLinkageAndVisibility();
+ if (TypeLV.getLinkage() != ExternalLinkage)
return LinkageInfo::uniqueExternal();
- LV.mergeVisibility(TypeLV);
+ if (!LV.isVisibilityExplicit())
+ LV.mergeVisibility(TypeLV);
}
if (Var->getStorageClass() == SC_PrivateExtern)
@@ -355,30 +643,9 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
if (Function->getStorageClass() == SC_PrivateExtern)
LV.mergeVisibility(HiddenVisibility, true);
- // C99 6.2.2p5:
- // If the declaration of an identifier for a function has no
- // storage-class specifier, its linkage is determined exactly
- // as if it were declared with the storage-class specifier
- // extern.
- if (!Context.getLangOpts().CPlusPlus &&
- (Function->getStorageClass() == SC_Extern ||
- Function->getStorageClass() == SC_PrivateExtern ||
- Function->getStorageClass() == SC_None)) {
- // C99 6.2.2p4:
- // For an identifier declared with the storage-class specifier
- // extern in a scope in which a prior declaration of that
- // identifier is visible, if the prior declaration specifies
- // internal or external linkage, the linkage of the identifier
- // at the later declaration is the same as the linkage
- // specified at the prior declaration. If no prior declaration
- // is visible, or if the prior declaration specifies no
- // linkage, then the identifier has external linkage.
- if (const FunctionDecl *PrevFunc = Function->getPreviousDecl()) {
- LinkageInfo PrevLV = getLVForDecl(PrevFunc, OnlyTemplate);
- if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage());
- LV.mergeVisibility(PrevLV);
- }
- }
+ // Note that Sema::MergeCompatibleFunctionDecls already takes care of
+ // merging storage classes and visibility attributes, so we don't have to
+ // look at previous decls in here.
// In C++, then if the type of the function uses a type with
// unique-external linkage, it's not legally usable from outside
@@ -389,21 +656,12 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
Function->getType()->getLinkage() == UniqueExternalLinkage)
return LinkageInfo::uniqueExternal();
- // Consider LV from the template and the template arguments unless
- // this is an explicit specialization with a visibility attribute.
+ // Consider LV from the template and the template arguments.
+ // We're at file scope, so we do not need to worry about nested
+ // specializations.
if (FunctionTemplateSpecializationInfo *specInfo
= Function->getTemplateSpecializationInfo()) {
- LinkageInfo TempLV = getLVForDecl(specInfo->getTemplate(), true);
- const TemplateArgumentList &templateArgs = *specInfo->TemplateArguments;
- LinkageInfo ArgsLV = getLVForTemplateArgumentList(templateArgs,
- OnlyTemplate);
- if (shouldConsiderTemplateVis(Function, specInfo)) {
- LV.mergeWithMin(TempLV);
- LV.mergeWithMin(ArgsLV);
- } else {
- LV.mergeLinkage(TempLV);
- LV.mergeLinkage(ArgsLV);
- }
+ mergeTemplateLV(LV, Function, specInfo);
}
// - a named class (Clause 9), or an unnamed class defined in a
@@ -414,41 +672,33 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// has the typedef name for linkage purposes (7.1.3); or
} else if (const TagDecl *Tag = dyn_cast<TagDecl>(D)) {
// Unnamed tags have no linkage.
- if (!Tag->getDeclName() && !Tag->getTypedefNameForAnonDecl())
+ if (!Tag->hasNameForLinkage())
return LinkageInfo::none();
// If this is a class template specialization, consider the
- // linkage of the template and template arguments.
+ // linkage of the template and template arguments. We're at file
+ // scope, so we do not need to worry about nested specializations.
if (const ClassTemplateSpecializationDecl *spec
= dyn_cast<ClassTemplateSpecializationDecl>(Tag)) {
- // From the template.
- LinkageInfo TempLV = getLVForDecl(spec->getSpecializedTemplate(), true);
-
- // The arguments at which the template was instantiated.
- const TemplateArgumentList &TemplateArgs = spec->getTemplateArgs();
- LinkageInfo ArgsLV = getLVForTemplateArgumentList(TemplateArgs,
- OnlyTemplate);
- if (shouldConsiderTemplateVis(spec)) {
- LV.mergeWithMin(TempLV);
- LV.mergeWithMin(ArgsLV);
- } else {
- LV.mergeLinkage(TempLV);
- LV.mergeLinkage(ArgsLV);
- }
+ mergeTemplateLV(LV, spec, computation);
}
// - an enumerator belonging to an enumeration with external linkage;
} else if (isa<EnumConstantDecl>(D)) {
LinkageInfo EnumLV = getLVForDecl(cast<NamedDecl>(D->getDeclContext()),
- OnlyTemplate);
- if (!isExternalLinkage(EnumLV.linkage()))
+ computation);
+ if (!isExternalLinkage(EnumLV.getLinkage()))
return LinkageInfo::none();
LV.merge(EnumLV);
// - a template, unless it is a function template that has
// internal linkage (Clause 14);
} else if (const TemplateDecl *temp = dyn_cast<TemplateDecl>(D)) {
- LV.merge(getLVForTemplateParameterList(temp->getTemplateParameters()));
+ bool considerVisibility = !hasExplicitVisibilityAlready(computation);
+ LinkageInfo tempLV =
+ getLVForTemplateParameterList(temp->getTemplateParameters());
+ LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
+
// - a namespace (7.3), unless it is declared within an unnamed
// namespace.
} else if (isa<NamespaceDecl>(D) && !D->isInAnonymousNamespace()) {
@@ -466,13 +716,14 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// If we ended up with non-external linkage, visibility should
// always be default.
- if (LV.linkage() != ExternalLinkage)
- return LinkageInfo(LV.linkage(), DefaultVisibility, false);
+ if (LV.getLinkage() != ExternalLinkage)
+ return LinkageInfo(LV.getLinkage(), DefaultVisibility, false);
return LV;
}
-static LinkageInfo getLVForClassMember(const NamedDecl *D, bool OnlyTemplate) {
+static LinkageInfo getLVForClassMember(const NamedDecl *D,
+ LVComputationKind computation) {
// Only certain class members have linkage. Note that fields don't
// really have linkage, but it's convenient to say they do for the
// purposes of calculating linkage of pointer-to-data-member
@@ -480,46 +731,45 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, bool OnlyTemplate) {
if (!(isa<CXXMethodDecl>(D) ||
isa<VarDecl>(D) ||
isa<FieldDecl>(D) ||
- (isa<TagDecl>(D) &&
- (D->getDeclName() || cast<TagDecl>(D)->getTypedefNameForAnonDecl()))))
+ isa<TagDecl>(D)))
return LinkageInfo::none();
LinkageInfo LV;
// If we have an explicit visibility attribute, merge that in.
- if (!OnlyTemplate) {
- if (llvm::Optional<Visibility> Vis = D->getExplicitVisibility())
+ if (!hasExplicitVisibilityAlready(computation)) {
+ if (Optional<Visibility> Vis = getExplicitVisibility(D, computation))
LV.mergeVisibility(*Vis, true);
// If we're paying attention to global visibility, apply
// -finline-visibility-hidden if this is an inline method.
//
// Note that we do this before merging information about
// the class visibility.
- if (!LV.visibilityExplicit() && useInlineVisibilityHidden(D))
+ if (!LV.isVisibilityExplicit() && useInlineVisibilityHidden(D))
LV.mergeVisibility(HiddenVisibility, true);
}
// If this class member has an explicit visibility attribute, the only
// thing that can change its visibility is the template arguments, so
// only look for them when processing the class.
- bool ClassOnlyTemplate = LV.visibilityExplicit() ? true : OnlyTemplate;
-
- // If this member has an visibility attribute, ClassF will exclude
- // attributes on the class or command line options, keeping only information
- // about the template instantiation. If the member has no visibility
- // attributes, mergeWithMin behaves like merge, so in both cases mergeWithMin
- // produces the desired result.
- LV.mergeWithMin(getLVForDecl(cast<RecordDecl>(D->getDeclContext()),
- ClassOnlyTemplate));
- if (!isExternalLinkage(LV.linkage()))
+ LVComputationKind classComputation = computation;
+ if (LV.isVisibilityExplicit())
+ classComputation = withExplicitVisibilityAlready(computation);
+
+ LinkageInfo classLV =
+ getLVForDecl(cast<RecordDecl>(D->getDeclContext()), classComputation);
+ if (!isExternalLinkage(classLV.getLinkage()))
return LinkageInfo::none();
// If the class already has unique-external linkage, we can't improve.
- if (LV.linkage() == UniqueExternalLinkage)
+ if (classLV.getLinkage() == UniqueExternalLinkage)
return LinkageInfo::uniqueExternal();
- if (!OnlyTemplate)
- LV.mergeVisibility(D->getASTContext().getLangOpts().getVisibilityMode());
+ // Otherwise, don't merge in classLV yet, because in certain cases
+ // we need to completely ignore the visibility from it.
+
+ // Specifically, if this decl exists and has an explicit attribute.
+ const NamedDecl *explicitSpecSuppressor = 0;
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
// If the type of the function uses a type with unique-external
@@ -531,192 +781,269 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, bool OnlyTemplate) {
// the template parameters and arguments.
if (FunctionTemplateSpecializationInfo *spec
= MD->getTemplateSpecializationInfo()) {
- const TemplateArgumentList &TemplateArgs = *spec->TemplateArguments;
- LinkageInfo ArgsLV = getLVForTemplateArgumentList(TemplateArgs,
- OnlyTemplate);
- TemplateParameterList *TemplateParams =
- spec->getTemplate()->getTemplateParameters();
- LinkageInfo ParamsLV = getLVForTemplateParameterList(TemplateParams);
- if (shouldConsiderTemplateVis(MD, spec)) {
- LV.mergeWithMin(ArgsLV);
- if (!OnlyTemplate)
- LV.mergeWithMin(ParamsLV);
- } else {
- LV.mergeLinkage(ArgsLV);
- if (!OnlyTemplate)
- LV.mergeLinkage(ParamsLV);
+ mergeTemplateLV(LV, MD, spec);
+ if (spec->isExplicitSpecialization()) {
+ explicitSpecSuppressor = MD;
+ } else if (isExplicitMemberSpecialization(spec->getTemplate())) {
+ explicitSpecSuppressor = spec->getTemplate()->getTemplatedDecl();
}
+ } else if (isExplicitMemberSpecialization(MD)) {
+ explicitSpecSuppressor = MD;
}
- // Note that in contrast to basically every other situation, we
- // *do* apply -fvisibility to method declarations.
-
} else if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
if (const ClassTemplateSpecializationDecl *spec
= dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
- // Merge template argument/parameter information for member
- // class template specializations.
- const TemplateArgumentList &TemplateArgs = spec->getTemplateArgs();
- LinkageInfo ArgsLV = getLVForTemplateArgumentList(TemplateArgs,
- OnlyTemplate);
- TemplateParameterList *TemplateParams =
- spec->getSpecializedTemplate()->getTemplateParameters();
- LinkageInfo ParamsLV = getLVForTemplateParameterList(TemplateParams);
- if (shouldConsiderTemplateVis(spec)) {
- LV.mergeWithMin(ArgsLV);
- if (!OnlyTemplate)
- LV.mergeWithMin(ParamsLV);
+ mergeTemplateLV(LV, spec, computation);
+ if (spec->isExplicitSpecialization()) {
+ explicitSpecSuppressor = spec;
} else {
- LV.mergeLinkage(ArgsLV);
- if (!OnlyTemplate)
- LV.mergeLinkage(ParamsLV);
+ const ClassTemplateDecl *temp = spec->getSpecializedTemplate();
+ if (isExplicitMemberSpecialization(temp)) {
+ explicitSpecSuppressor = temp->getTemplatedDecl();
+ }
}
+ } else if (isExplicitMemberSpecialization(RD)) {
+ explicitSpecSuppressor = RD;
}
// Static data members.
} else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
// Modify the variable's linkage by its type, but ignore the
// type's visibility unless it's a definition.
- LinkageInfo TypeLV = getLVForType(VD->getType());
- if (TypeLV.linkage() != ExternalLinkage)
- LV.mergeLinkage(UniqueExternalLinkage);
- LV.mergeVisibility(TypeLV);
- }
+ LinkageInfo typeLV = VD->getType()->getLinkageAndVisibility();
+ LV.mergeMaybeWithVisibility(typeLV,
+ !LV.isVisibilityExplicit() && !classLV.isVisibilityExplicit());
- return LV;
-}
+ if (isExplicitMemberSpecialization(VD)) {
+ explicitSpecSuppressor = VD;
+ }
-static void clearLinkageForClass(const CXXRecordDecl *record) {
- for (CXXRecordDecl::decl_iterator
- i = record->decls_begin(), e = record->decls_end(); i != e; ++i) {
- Decl *child = *i;
- if (isa<NamedDecl>(child))
- cast<NamedDecl>(child)->ClearLinkageCache();
+ // Template members.
+ } else if (const TemplateDecl *temp = dyn_cast<TemplateDecl>(D)) {
+ bool considerVisibility =
+ (!LV.isVisibilityExplicit() &&
+ !classLV.isVisibilityExplicit() &&
+ !hasExplicitVisibilityAlready(computation));
+ LinkageInfo tempLV =
+ getLVForTemplateParameterList(temp->getTemplateParameters());
+ LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
+
+ if (const RedeclarableTemplateDecl *redeclTemp =
+ dyn_cast<RedeclarableTemplateDecl>(temp)) {
+ if (isExplicitMemberSpecialization(redeclTemp)) {
+ explicitSpecSuppressor = temp->getTemplatedDecl();
+ }
+ }
}
-}
-void NamedDecl::anchor() { }
+ // We should never be looking for an attribute directly on a template.
+ assert(!explicitSpecSuppressor || !isa<TemplateDecl>(explicitSpecSuppressor));
-void NamedDecl::ClearLinkageCache() {
- // Note that we can't skip clearing the linkage of children just
- // because the parent doesn't have cached linkage: we don't cache
- // when computing linkage for parent contexts.
+ // If this member is an explicit member specialization, and it has
+ // an explicit attribute, ignore visibility from the parent.
+ bool considerClassVisibility = true;
+ if (explicitSpecSuppressor &&
+ // optimization: hasDVA() is true only with explicit visibility.
+ LV.isVisibilityExplicit() &&
+ classLV.getVisibility() != DefaultVisibility &&
+ hasDirectVisibilityAttribute(explicitSpecSuppressor, computation)) {
+ considerClassVisibility = false;
+ }
- HasCachedLinkage = 0;
+ // Finally, merge in information from the class.
+ LV.mergeMaybeWithVisibility(classLV, considerClassVisibility);
+ return LV;
+}
- // If we're changing the linkage of a class, we need to reset the
- // linkage of child declarations, too.
- if (const CXXRecordDecl *record = dyn_cast<CXXRecordDecl>(this))
- clearLinkageForClass(record);
+void NamedDecl::anchor() { }
- if (ClassTemplateDecl *temp =
- dyn_cast<ClassTemplateDecl>(const_cast<NamedDecl*>(this))) {
- // Clear linkage for the template pattern.
- CXXRecordDecl *record = temp->getTemplatedDecl();
- record->HasCachedLinkage = 0;
- clearLinkageForClass(record);
+bool NamedDecl::isLinkageValid() const {
+ if (!HasCachedLinkage)
+ return true;
- // We need to clear linkage for specializations, too.
- for (ClassTemplateDecl::spec_iterator
- i = temp->spec_begin(), e = temp->spec_end(); i != e; ++i)
- i->ClearLinkageCache();
- }
+ return getLVForDecl(this, LVForExplicitValue).getLinkage() ==
+ Linkage(CachedLinkage);
+}
- // Clear cached linkage for function template decls, too.
- if (FunctionTemplateDecl *temp =
- dyn_cast<FunctionTemplateDecl>(const_cast<NamedDecl*>(this))) {
- temp->getTemplatedDecl()->ClearLinkageCache();
- for (FunctionTemplateDecl::spec_iterator
- i = temp->spec_begin(), e = temp->spec_end(); i != e; ++i)
- i->ClearLinkageCache();
- }
-
+bool NamedDecl::hasExternalLinkageUncached() const {
+ return getLVForDecl(this, LVForExplicitValue).getLinkage() == ExternalLinkage;
}
Linkage NamedDecl::getLinkage() const {
- if (HasCachedLinkage) {
- assert(Linkage(CachedLinkage) ==
- getLVForDecl(this, true).linkage());
+ if (HasCachedLinkage)
return Linkage(CachedLinkage);
- }
- CachedLinkage = getLVForDecl(this, true).linkage();
+ // We don't care about visibility here, so ask for the cheapest
+ // possible visibility analysis.
+ CachedLinkage = getLVForDecl(this, LVForExplicitValue).getLinkage();
HasCachedLinkage = 1;
+
+#ifndef NDEBUG
+ verifyLinkage();
+#endif
+
return Linkage(CachedLinkage);
}
LinkageInfo NamedDecl::getLinkageAndVisibility() const {
- LinkageInfo LI = getLVForDecl(this, false);
- assert(!HasCachedLinkage || Linkage(CachedLinkage) == LI.linkage());
+ LVComputationKind computation =
+ (usesTypeVisibility(this) ? LVForType : LVForValue);
+ LinkageInfo LI = getLVForDecl(this, computation);
+ if (HasCachedLinkage) {
+ assert(Linkage(CachedLinkage) == LI.getLinkage());
+ return LI;
+ }
HasCachedLinkage = 1;
- CachedLinkage = LI.linkage();
+ CachedLinkage = LI.getLinkage();
+
+#ifndef NDEBUG
+ verifyLinkage();
+#endif
+
return LI;
}
-llvm::Optional<Visibility> NamedDecl::getExplicitVisibility() const {
- // Use the most recent declaration of a variable.
- if (const VarDecl *Var = dyn_cast<VarDecl>(this)) {
- if (llvm::Optional<Visibility> V =
- getVisibilityOf(Var->getMostRecentDecl()))
- return V;
+void NamedDecl::verifyLinkage() const {
+ // In C (because of gnu inline) and in c++ with microsoft extensions an
+ // static can follow an extern, so we can have two decls with different
+ // linkages.
+ const LangOptions &Opts = getASTContext().getLangOpts();
+ if (!Opts.CPlusPlus || Opts.MicrosoftExt)
+ return;
+
+ // We have just computed the linkage for this decl. By induction we know
+ // that all other computed linkages match, check that the one we just computed
+ // also does.
+ NamedDecl *D = NULL;
+ for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
+ NamedDecl *T = cast<NamedDecl>(*I);
+ if (T == this)
+ continue;
+ if (T->HasCachedLinkage != 0) {
+ D = T;
+ break;
+ }
+ }
+ assert(!D || D->CachedLinkage == CachedLinkage);
+}
+
+Optional<Visibility>
+NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const {
+ // Check the declaration itself first.
+ if (Optional<Visibility> V = getVisibilityOf(this, kind))
+ return V;
+
+ // If this is a member class of a specialization of a class template
+ // and the corresponding decl has explicit visibility, use that.
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(this)) {
+ CXXRecordDecl *InstantiatedFrom = RD->getInstantiatedFromMemberClass();
+ if (InstantiatedFrom)
+ return getVisibilityOf(InstantiatedFrom, kind);
+ }
+
+ // If there wasn't explicit visibility there, and this is a
+ // specialization of a class template, check for visibility
+ // on the pattern.
+ if (const ClassTemplateSpecializationDecl *spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(this))
+ return getVisibilityOf(spec->getSpecializedTemplate()->getTemplatedDecl(),
+ kind);
+ // Use the most recent declaration.
+ const NamedDecl *MostRecent = cast<NamedDecl>(this->getMostRecentDecl());
+ if (MostRecent != this)
+ return MostRecent->getExplicitVisibility(kind);
+
+ if (const VarDecl *Var = dyn_cast<VarDecl>(this)) {
if (Var->isStaticDataMember()) {
VarDecl *InstantiatedFrom = Var->getInstantiatedFromStaticDataMember();
if (InstantiatedFrom)
- return getVisibilityOf(InstantiatedFrom);
+ return getVisibilityOf(InstantiatedFrom, kind);
}
- return llvm::Optional<Visibility>();
+ return None;
}
- // Use the most recent declaration of a function, and also handle
- // function template specializations.
+ // Also handle function template specializations.
if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(this)) {
- if (llvm::Optional<Visibility> V
- = getVisibilityOf(fn->getMostRecentDecl()))
- return V;
-
// If the function is a specialization of a template with an
// explicit visibility attribute, use that.
if (FunctionTemplateSpecializationInfo *templateInfo
= fn->getTemplateSpecializationInfo())
- return getVisibilityOf(templateInfo->getTemplate()->getTemplatedDecl());
+ return getVisibilityOf(templateInfo->getTemplate()->getTemplatedDecl(),
+ kind);
// If the function is a member of a specialization of a class template
// and the corresponding decl has explicit visibility, use that.
FunctionDecl *InstantiatedFrom = fn->getInstantiatedFromMemberFunction();
if (InstantiatedFrom)
- return getVisibilityOf(InstantiatedFrom);
+ return getVisibilityOf(InstantiatedFrom, kind);
- return llvm::Optional<Visibility>();
+ return None;
}
- // Otherwise, just check the declaration itself first.
- if (llvm::Optional<Visibility> V = getVisibilityOf(this))
- return V;
-
// The visibility of a template is stored in the templated decl.
if (const TemplateDecl *TD = dyn_cast<TemplateDecl>(this))
- return getVisibilityOf(TD->getTemplatedDecl());
+ return getVisibilityOf(TD->getTemplatedDecl(), kind);
- // If there wasn't explicit visibility there, and this is a
- // specialization of a class template, check for visibility
- // on the pattern.
- if (const ClassTemplateSpecializationDecl *spec
- = dyn_cast<ClassTemplateSpecializationDecl>(this))
- return getVisibilityOf(spec->getSpecializedTemplate()->getTemplatedDecl());
+ return None;
+}
- // If this is a member class of a specialization of a class template
- // and the corresponding decl has explicit visibility, use that.
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(this)) {
- CXXRecordDecl *InstantiatedFrom = RD->getInstantiatedFromMemberClass();
- if (InstantiatedFrom)
- return getVisibilityOf(InstantiatedFrom);
+static LinkageInfo getLVForLocalDecl(const NamedDecl *D,
+ LVComputationKind computation) {
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
+ if (Function->isInAnonymousNamespace() &&
+ !Function->getDeclContext()->isExternCContext())
+ return LinkageInfo::uniqueExternal();
+
+ // This is a "void f();" which got merged with a file static.
+ if (Function->getCanonicalDecl()->getStorageClass() == SC_Static)
+ return LinkageInfo::internal();
+
+ LinkageInfo LV;
+ if (!hasExplicitVisibilityAlready(computation)) {
+ if (Optional<Visibility> Vis =
+ getExplicitVisibility(Function, computation))
+ LV.mergeVisibility(*Vis, true);
+ }
+
+ // Note that Sema::MergeCompatibleFunctionDecls already takes care of
+ // merging storage classes and visibility attributes, so we don't have to
+ // look at previous decls in here.
+
+ return LV;
}
- return llvm::Optional<Visibility>();
+ if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
+ if (Var->hasExternalStorage()) {
+ if (Var->isInAnonymousNamespace() &&
+ !Var->getDeclContext()->isExternCContext())
+ return LinkageInfo::uniqueExternal();
+
+ LinkageInfo LV;
+ if (Var->getStorageClass() == SC_PrivateExtern)
+ LV.mergeVisibility(HiddenVisibility, true);
+ else if (!hasExplicitVisibilityAlready(computation)) {
+ if (Optional<Visibility> Vis = getExplicitVisibility(Var, computation))
+ LV.mergeVisibility(*Vis, true);
+ }
+
+ if (const VarDecl *Prev = Var->getPreviousDecl()) {
+ LinkageInfo PrevLV = getLVForDecl(Prev, computation);
+ if (PrevLV.getLinkage())
+ LV.setLinkage(PrevLV.getLinkage());
+ LV.mergeVisibility(PrevLV);
+ }
+
+ return LV;
+ }
+ }
+
+ return LinkageInfo::none();
}
-static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate) {
+static LinkageInfo getLVForDecl(const NamedDecl *D,
+ LVComputationKind computation) {
// Objective-C: treat all Objective-C declarations as having external
// linkage.
switch (D->getKind()) {
@@ -751,12 +1078,11 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate) {
if (isa<ParmVarDecl>(ContextDecl))
DC = ContextDecl->getDeclContext()->getRedeclContext();
else
- return getLVForDecl(cast<NamedDecl>(ContextDecl),
- OnlyTemplate);
+ return getLVForDecl(cast<NamedDecl>(ContextDecl), computation);
}
if (const NamedDecl *ND = dyn_cast<NamedDecl>(DC))
- return getLVForDecl(ND, OnlyTemplate);
+ return getLVForDecl(ND, computation);
return LinkageInfo::external();
}
@@ -767,7 +1093,7 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate) {
// Handle linkage for namespace-scope names.
if (D->getDeclContext()->getRedeclContext()->isFileContext())
- return getLVForNamespaceScopeDecl(D, OnlyTemplate);
+ return getLVForNamespaceScopeDecl(D, computation);
// C++ [basic.link]p5:
// In addition, a member function, static data member, a named
@@ -777,7 +1103,7 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate) {
// purposes (7.1.3), has external linkage if the name of the class
// has external linkage.
if (D->getDeclContext()->isRecord())
- return getLVForClassMember(D, OnlyTemplate);
+ return getLVForClassMember(D, computation);
// C++ [basic.link]p6:
// The name of a function declared in block scope and the name of
@@ -790,48 +1116,8 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate) {
// one such matching entity, the program is ill-formed. Otherwise,
// if no matching entity is found, the block scope entity receives
// external linkage.
- if (D->getLexicalDeclContext()->isFunctionOrMethod()) {
- if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
- if (Function->isInAnonymousNamespace() &&
- !Function->getDeclContext()->isExternCContext())
- return LinkageInfo::uniqueExternal();
-
- LinkageInfo LV;
- if (!OnlyTemplate) {
- if (llvm::Optional<Visibility> Vis = Function->getExplicitVisibility())
- LV.mergeVisibility(*Vis, true);
- }
-
- if (const FunctionDecl *Prev = Function->getPreviousDecl()) {
- LinkageInfo PrevLV = getLVForDecl(Prev, OnlyTemplate);
- if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage());
- LV.mergeVisibility(PrevLV);
- }
-
- return LV;
- }
-
- if (const VarDecl *Var = dyn_cast<VarDecl>(D))
- if (Var->getStorageClass() == SC_Extern ||
- Var->getStorageClass() == SC_PrivateExtern) {
- if (Var->isInAnonymousNamespace() &&
- !Var->getDeclContext()->isExternCContext())
- return LinkageInfo::uniqueExternal();
-
- LinkageInfo LV;
- if (Var->getStorageClass() == SC_PrivateExtern)
- LV.mergeVisibility(HiddenVisibility, true);
- else if (!OnlyTemplate) {
- if (llvm::Optional<Visibility> Vis = Var->getExplicitVisibility())
- LV.mergeVisibility(*Vis, true);
- }
-
- // Note that Sema::MergeVarDecl already takes care of implementing
- // C99 6.2.2p4 and propagating the visibility attribute, so we don't
- // have to do it here.
- return LV;
- }
- }
+ if (D->getDeclContext()->isFunctionOrMethod())
+ return getLVForLocalDecl(D, computation);
// C++ [basic.link]p6:
// Names not covered by these rules have no linkage.
@@ -843,10 +1129,24 @@ std::string NamedDecl::getQualifiedNameAsString() const {
}
std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {
+ std::string QualName;
+ llvm::raw_string_ostream OS(QualName);
+ printQualifiedName(OS, P);
+ return OS.str();
+}
+
+void NamedDecl::printQualifiedName(raw_ostream &OS) const {
+ printQualifiedName(OS, getASTContext().getPrintingPolicy());
+}
+
+void NamedDecl::printQualifiedName(raw_ostream &OS,
+ const PrintingPolicy &P) const {
const DeclContext *Ctx = getDeclContext();
- if (Ctx->isFunctionOrMethod())
- return getNameAsString();
+ if (Ctx->isFunctionOrMethod()) {
+ printName(OS);
+ return;
+ }
typedef SmallVector<const DeclContext *, 8> ContextsTy;
ContextsTy Contexts;
@@ -855,22 +1155,18 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {
while (Ctx && isa<NamedDecl>(Ctx)) {
Contexts.push_back(Ctx);
Ctx = Ctx->getParent();
- };
-
- std::string QualName;
- llvm::raw_string_ostream OS(QualName);
+ }
for (ContextsTy::reverse_iterator I = Contexts.rbegin(), E = Contexts.rend();
I != E; ++I) {
if (const ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(*I)) {
+ OS << Spec->getName();
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
- std::string TemplateArgsStr
- = TemplateSpecializationType::PrintTemplateArgumentList(
- TemplateArgs.data(),
- TemplateArgs.size(),
- P);
- OS << Spec->getName() << TemplateArgsStr;
+ TemplateSpecializationType::PrintTemplateArgumentList(OS,
+ TemplateArgs.data(),
+ TemplateArgs.size(),
+ P);
} else if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(*I)) {
if (ND->isAnonymousNamespace())
OS << "<anonymous namespace>";
@@ -912,8 +1208,15 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {
OS << *this;
else
OS << "<anonymous>";
+}
- return OS.str();
+void NamedDecl::getNameForDiagnostic(raw_ostream &OS,
+ const PrintingPolicy &Policy,
+ bool Qualified) const {
+ if (Qualified)
+ printQualifiedName(OS, Policy);
+ else
+ printName(OS);
}
bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
@@ -1166,45 +1469,80 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) {
VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StartL, SourceLocation IdL,
IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
- StorageClass S, StorageClass SCAsWritten) {
- return new (C) VarDecl(Var, DC, StartL, IdL, Id, T, TInfo, S, SCAsWritten);
+ StorageClass S) {
+ return new (C) VarDecl(Var, DC, StartL, IdL, Id, T, TInfo, S);
}
VarDecl *VarDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(VarDecl));
return new (Mem) VarDecl(Var, 0, SourceLocation(), SourceLocation(), 0,
- QualType(), 0, SC_None, SC_None);
+ QualType(), 0, SC_None);
}
void VarDecl::setStorageClass(StorageClass SC) {
assert(isLegalForVariable(SC));
- if (getStorageClass() != SC)
- ClearLinkageCache();
-
VarDeclBits.SClass = SC;
}
SourceRange VarDecl::getSourceRange() const {
if (const Expr *Init = getInit()) {
SourceLocation InitEnd = Init->getLocEnd();
- if (InitEnd.isValid())
+ // If Init is implicit, ignore its source range and fallback on
+ // DeclaratorDecl::getSourceRange() to handle postfix elements.
+ if (InitEnd.isValid() && InitEnd != getLocation())
return SourceRange(getOuterLocStart(), InitEnd);
}
return DeclaratorDecl::getSourceRange();
}
-bool VarDecl::isExternC() const {
- if (getLinkage() != ExternalLinkage)
- return false;
+template<typename T>
+static LanguageLinkage getLanguageLinkageTemplate(const T &D) {
+ // C++ [dcl.link]p1: All function types, function names with external linkage,
+ // and variable names with external linkage have a language linkage.
+ if (!isExternalLinkage(D.getLinkage()))
+ return NoLanguageLinkage;
+
+ // Language linkage is a C++ concept, but saying that everything else in C has
+ // C language linkage fits the implementation nicely.
+ ASTContext &Context = D.getASTContext();
+ if (!Context.getLangOpts().CPlusPlus)
+ return CLanguageLinkage;
- const DeclContext *DC = getDeclContext();
+ // C++ [dcl.link]p4: A C language linkage is ignored in determining the
+ // language linkage of the names of class members and the function type of
+ // class member functions.
+ const DeclContext *DC = D.getDeclContext();
if (DC->isRecord())
+ return CXXLanguageLinkage;
+
+ // If the first decl is in an extern "C" context, any other redeclaration
+ // will have C language linkage. If the first one is not in an extern "C"
+ // context, we would have reported an error for any other decl being in one.
+ const T *First = D.getFirstDeclaration();
+ if (First->getDeclContext()->isExternCContext())
+ return CLanguageLinkage;
+ return CXXLanguageLinkage;
+}
+
+template<typename T>
+static bool isExternCTemplate(const T &D) {
+ // Since the context is ignored for class members, they can only have C++
+ // language linkage or no language linkage.
+ const DeclContext *DC = D.getDeclContext();
+ if (DC->isRecord()) {
+ assert(D.getASTContext().getLangOpts().CPlusPlus);
return false;
+ }
- ASTContext &Context = getASTContext();
- if (!Context.getLangOpts().CPlusPlus)
- return true;
- return DC->isExternCContext();
+ return D.getLanguageLinkage() == CLanguageLinkage;
+}
+
+LanguageLinkage VarDecl::getLanguageLinkage() const {
+ return getLanguageLinkageTemplate(*this);
+}
+
+bool VarDecl::isExternC() const {
+ return isExternCTemplate(*this);
}
VarDecl *VarDecl::getCanonicalDecl() {
@@ -1241,12 +1579,11 @@ VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition(
// AST for 'extern "C" int foo;' is annotated with 'extern'.
if (hasExternalStorage())
return DeclarationOnly;
-
- if (getStorageClassAsWritten() == SC_Extern ||
- getStorageClassAsWritten() == SC_PrivateExtern) {
+
+ if (hasExternalStorage()) {
for (const VarDecl *PrevVar = getPreviousDecl();
PrevVar; PrevVar = PrevVar->getPreviousDecl()) {
- if (PrevVar->getLinkage() == InternalLinkage && PrevVar->hasInit())
+ if (PrevVar->getLinkage() == InternalLinkage)
return DeclarationOnly;
}
}
@@ -1375,7 +1712,7 @@ bool VarDecl::isUsableInConstantExpressions(ASTContext &C) const {
// In C++11, any variable of reference type can be used in a constant
// expression if it is initialized by a constant expression.
- if (Lang.CPlusPlus0x && getType()->isReferenceType())
+ if (Lang.CPlusPlus11 && getType()->isReferenceType())
return true;
// Only const objects can be used in constant expressions in C++. C++98 does
@@ -1391,7 +1728,7 @@ bool VarDecl::isUsableInConstantExpressions(ASTContext &C) const {
// Additionally, in C++11, non-volatile constexpr variables can be used in
// constant expressions.
- return Lang.CPlusPlus0x && isConstexpr();
+ return Lang.CPlusPlus11 && isConstexpr();
}
/// Convert the initializer for this declaration to the elaborated EvaluatedStmt
@@ -1409,12 +1746,12 @@ EvaluatedStmt *VarDecl::ensureEvaluatedStmt() const {
}
APValue *VarDecl::evaluateValue() const {
- llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ SmallVector<PartialDiagnosticAt, 8> Notes;
return evaluateValue(Notes);
}
APValue *VarDecl::evaluateValue(
- llvm::SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
+ SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
EvaluatedStmt *Eval = ensureEvaluatedStmt();
// We only produce notes indicating why an initializer is non-constant the
@@ -1447,7 +1784,7 @@ APValue *VarDecl::evaluateValue(
// In C++11, we have determined whether the initializer was a constant
// expression as a side-effect.
- if (getASTContext().getLangOpts().CPlusPlus0x && !Eval->CheckedICE) {
+ if (getASTContext().getLangOpts().CPlusPlus11 && !Eval->CheckedICE) {
Eval->CheckedICE = true;
Eval->IsICE = Result && Notes.empty();
}
@@ -1471,8 +1808,8 @@ bool VarDecl::checkInitIsICE() const {
// In C++11, evaluate the initializer to check whether it's a constant
// expression.
- if (getASTContext().getLangOpts().CPlusPlus0x) {
- llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ if (getASTContext().getLangOpts().CPlusPlus11) {
+ SmallVector<PartialDiagnosticAt, 8> Notes;
evaluateValue(Notes);
return Eval->IsICE;
}
@@ -1541,16 +1878,15 @@ ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo,
- StorageClass S, StorageClass SCAsWritten,
- Expr *DefArg) {
+ StorageClass S, Expr *DefArg) {
return new (C) ParmVarDecl(ParmVar, DC, StartLoc, IdLoc, Id, T, TInfo,
- S, SCAsWritten, DefArg);
+ S, DefArg);
}
ParmVarDecl *ParmVarDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ParmVarDecl));
return new (Mem) ParmVarDecl(ParmVar, 0, SourceLocation(), SourceLocation(),
- 0, QualType(), 0, SC_None, SC_None, 0);
+ 0, QualType(), 0, SC_None, 0);
}
SourceRange ParmVarDecl::getSourceRange() const {
@@ -1602,17 +1938,13 @@ unsigned ParmVarDecl::getParameterIndexLarge() const {
// FunctionDecl Implementation
//===----------------------------------------------------------------------===//
-void FunctionDecl::getNameForDiagnostic(std::string &S,
- const PrintingPolicy &Policy,
- bool Qualified) const {
- NamedDecl::getNameForDiagnostic(S, Policy, Qualified);
+void FunctionDecl::getNameForDiagnostic(
+ raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const {
+ NamedDecl::getNameForDiagnostic(OS, Policy, Qualified);
const TemplateArgumentList *TemplateArgs = getTemplateSpecializationArgs();
if (TemplateArgs)
- S += TemplateSpecializationType::PrintTemplateArgumentList(
- TemplateArgs->data(),
- TemplateArgs->size(),
- Policy);
-
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, TemplateArgs->data(), TemplateArgs->size(), Policy);
}
bool FunctionDecl::isVariadic() const {
@@ -1684,13 +2016,6 @@ void FunctionDecl::setPure(bool P) {
Parent->markedVirtualFunctionPure();
}
-void FunctionDecl::setConstexpr(bool IC) {
- IsConstexpr = IC;
- CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(this);
- if (IC && CD)
- CD->getParent()->markedConstructorConstexpr(CD);
-}
-
bool FunctionDecl::isMain() const {
const TranslationUnitDecl *tunit =
dyn_cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext());
@@ -1722,29 +2047,25 @@ bool FunctionDecl::isReservedGlobalPlacementOperator() const {
return (proto->getArgType(1).getCanonicalType() == Context.VoidPtrTy);
}
-bool FunctionDecl::isExternC() const {
- if (getLinkage() != ExternalLinkage)
- return false;
-
- if (getAttr<OverloadableAttr>())
- return false;
-
- const DeclContext *DC = getDeclContext();
- if (DC->isRecord())
- return false;
+LanguageLinkage FunctionDecl::getLanguageLinkage() const {
+ // Users expect to be able to write
+ // extern "C" void *__builtin_alloca (size_t);
+ // so consider builtins as having C language linkage.
+ if (getBuiltinID())
+ return CLanguageLinkage;
- ASTContext &Context = getASTContext();
- if (!Context.getLangOpts().CPlusPlus)
- return true;
+ return getLanguageLinkageTemplate(*this);
+}
- return isMain() || DC->isExternCContext();
+bool FunctionDecl::isExternC() const {
+ return isExternCTemplate(*this);
}
bool FunctionDecl::isGlobal() const {
if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(this))
return Method->isStatic();
- if (getStorageClass() == SC_Static)
+ if (getCanonicalDecl()->getStorageClass() == SC_Static)
return false;
for (const DeclContext *DC = getDeclContext();
@@ -1760,6 +2081,12 @@ bool FunctionDecl::isGlobal() const {
return true;
}
+bool FunctionDecl::isNoReturn() const {
+ return hasAttr<NoReturnAttr>() || hasAttr<CXX11NoReturnAttr>() ||
+ hasAttr<C11NoReturnAttr>() ||
+ getType()->getAs<FunctionType>()->getNoReturnAttr();
+}
+
void
FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) {
redeclarable_base::setPreviousDeclaration(PrevDecl);
@@ -1783,14 +2110,6 @@ FunctionDecl *FunctionDecl::getCanonicalDecl() {
return getFirstDeclaration();
}
-void FunctionDecl::setStorageClass(StorageClass SC) {
- assert(isLegalForFunction(SC));
- if (getStorageClass() != SC)
- ClearLinkageCache();
-
- SClass = SC;
-}
-
/// \brief Returns a value indicating whether this function
/// corresponds to a builtin function.
///
@@ -1851,7 +2170,7 @@ unsigned FunctionDecl::getNumParams() const {
}
void FunctionDecl::setParams(ASTContext &C,
- llvm::ArrayRef<ParmVarDecl *> NewParamInfo) {
+ ArrayRef<ParmVarDecl *> NewParamInfo) {
assert(ParamInfo == 0 && "Already has param info!");
assert(NewParamInfo.size() == getNumParams() && "Parameter count mismatch!");
@@ -1862,13 +2181,13 @@ void FunctionDecl::setParams(ASTContext &C,
}
}
-void FunctionDecl::setDeclsInPrototypeScope(llvm::ArrayRef<NamedDecl *> NewDecls) {
+void FunctionDecl::setDeclsInPrototypeScope(ArrayRef<NamedDecl *> NewDecls) {
assert(DeclsInPrototypeScope.empty() && "Already has prototype decls!");
if (!NewDecls.empty()) {
NamedDecl **A = new (getASTContext()) NamedDecl*[NewDecls.size()];
std::copy(NewDecls.begin(), NewDecls.end(), A);
- DeclsInPrototypeScope = llvm::ArrayRef<NamedDecl*>(A, NewDecls.size());
+ DeclsInPrototypeScope = ArrayRef<NamedDecl *>(A, NewDecls.size());
}
}
@@ -1907,38 +2226,6 @@ unsigned FunctionDecl::getMinRequiredArguments() const {
return NumRequiredArgs;
}
-bool FunctionDecl::isInlined() const {
- if (IsInline)
- return true;
-
- if (isa<CXXMethodDecl>(this)) {
- if (!isOutOfLine() || getCanonicalDecl()->isInlineSpecified())
- return true;
- }
-
- switch (getTemplateSpecializationKind()) {
- case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
- return false;
-
- case TSK_ImplicitInstantiation:
- case TSK_ExplicitInstantiationDeclaration:
- case TSK_ExplicitInstantiationDefinition:
- // Handle below.
- break;
- }
-
- const FunctionDecl *PatternDecl = getTemplateInstantiationPattern();
- bool HasPattern = false;
- if (PatternDecl)
- HasPattern = PatternDecl->hasBody(PatternDecl);
-
- if (HasPattern && PatternDecl)
- return PatternDecl->isInlined();
-
- return false;
-}
-
static bool RedeclForcesDefC99(const FunctionDecl *Redecl) {
// Only consider file-scope declarations in this test.
if (!Redecl->getLexicalDeclContext()->isTranslationUnit())
@@ -1973,7 +2260,7 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
//
// FIXME: What happens if gnu_inline gets added on after the first
// declaration?
- if (!isInlineSpecified() || getStorageClassAsWritten() == SC_Extern)
+ if (!isInlineSpecified() || getStorageClass() == SC_Extern)
return false;
const FunctionDecl *Prev = this;
@@ -1985,10 +2272,10 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
// If it's not the case that both 'inline' and 'extern' are
// specified on the definition, then it is always externally visible.
if (!Prev->isInlineSpecified() ||
- Prev->getStorageClassAsWritten() != SC_Extern)
+ Prev->getStorageClass() != SC_Extern)
return false;
} else if (Prev->isInlineSpecified() &&
- Prev->getStorageClassAsWritten() != SC_Extern) {
+ Prev->getStorageClass() != SC_Extern) {
return false;
}
}
@@ -2014,8 +2301,8 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
return FoundBody;
}
-/// \brief For an inline function definition in C or C++, determine whether the
-/// definition will be externally visible.
+/// \brief For an inline function definition in C, or for a gnu_inline function
+/// in C++, determine whether the definition will be externally visible.
///
/// Inline function definitions are always available for inlining optimizations.
/// However, depending on the language dialect, declaration specifiers, and
@@ -2043,7 +2330,7 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const {
// If it's not the case that both 'inline' and 'extern' are
// specified on the definition, then this inline definition is
// externally visible.
- if (!(isInlineSpecified() && getStorageClassAsWritten() == SC_Extern))
+ if (!(isInlineSpecified() && getStorageClass() == SC_Extern))
return true;
// If any declaration is 'inline' but not 'extern', then this definition
@@ -2052,13 +2339,17 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const {
Redecl != RedeclEnd;
++Redecl) {
if (Redecl->isInlineSpecified() &&
- Redecl->getStorageClassAsWritten() != SC_Extern)
+ Redecl->getStorageClass() != SC_Extern)
return true;
}
return false;
}
+ // The rest of this function is C-only.
+ assert(!Context.getLangOpts().CPlusPlus &&
+ "should not use C inline rules in C++");
+
// C99 6.7.4p6:
// [...] If all of the file scope declarations for a function in a
// translation unit include the inline function specifier without extern,
@@ -2118,10 +2409,6 @@ FunctionDecl *FunctionDecl::getInstantiatedFromMemberFunction() const {
return 0;
}
-MemberSpecializationInfo *FunctionDecl::getMemberSpecializationInfo() const {
- return TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>();
-}
-
void
FunctionDecl::setInstantiationOfMemberFunction(ASTContext &C,
FunctionDecl *FD,
@@ -2553,18 +2840,17 @@ TagDecl* TagDecl::getCanonicalDecl() {
return getFirstDeclaration();
}
-void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) {
- TypedefNameDeclOrQualifier = TDD;
+void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) {
+ TypedefNameDeclOrQualifier = TDD;
if (TypeForDecl)
- const_cast<Type*>(TypeForDecl)->ClearLinkageCache();
- ClearLinkageCache();
+ assert(TypeForDecl->isLinkageValid());
+ assert(isLinkageValid());
}
void TagDecl::startDefinition() {
IsBeingDefined = true;
- if (isa<CXXRecordDecl>(this)) {
- CXXRecordDecl *D = cast<CXXRecordDecl>(this);
+ if (CXXRecordDecl *D = dyn_cast<CXXRecordDecl>(this)) {
struct CXXRecordDecl::DefinitionData *Data =
new (getASTContext()) struct CXXRecordDecl::DefinitionData(D);
for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I)
@@ -2587,6 +2873,16 @@ void TagDecl::completeDefinition() {
TagDecl *TagDecl::getDefinition() const {
if (isCompleteDefinition())
return const_cast<TagDecl *>(this);
+
+ // If it's possible for us to have an out-of-date definition, check now.
+ if (MayHaveOutOfDateDef) {
+ if (IdentifierInfo *II = getIdentifier()) {
+ if (II->isOutOfDate()) {
+ updateOutOfDate(*II);
+ }
+ }
+ }
+
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(this))
return CXXRD->getDefinition();
@@ -2643,14 +2939,17 @@ EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC,
bool IsScopedUsingClassTag, bool IsFixed) {
EnumDecl *Enum = new (C) EnumDecl(DC, StartLoc, IdLoc, Id, PrevDecl,
IsScoped, IsScopedUsingClassTag, IsFixed);
+ Enum->MayHaveOutOfDateDef = C.getLangOpts().Modules;
C.getTypeDeclType(Enum, PrevDecl);
return Enum;
}
EnumDecl *EnumDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(EnumDecl));
- return new (Mem) EnumDecl(0, SourceLocation(), SourceLocation(), 0, 0,
- false, false, false);
+ EnumDecl *Enum = new (Mem) EnumDecl(0, SourceLocation(), SourceLocation(),
+ 0, 0, false, false, false);
+ Enum->MayHaveOutOfDateDef = C.getLangOpts().Modules;
+ return Enum;
}
void EnumDecl::completeDefinition(QualType NewType,
@@ -2708,6 +3007,7 @@ RecordDecl::RecordDecl(Kind DK, TagKind TK, DeclContext *DC,
HasFlexibleArrayMember = false;
AnonymousStructOrUnion = false;
HasObjectMember = false;
+ HasVolatileMember = false;
LoadedFieldsFromExternalStorage = false;
assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!");
}
@@ -2717,14 +3017,18 @@ RecordDecl *RecordDecl::Create(const ASTContext &C, TagKind TK, DeclContext *DC,
IdentifierInfo *Id, RecordDecl* PrevDecl) {
RecordDecl* R = new (C) RecordDecl(Record, TK, DC, StartLoc, IdLoc, Id,
PrevDecl);
+ R->MayHaveOutOfDateDef = C.getLangOpts().Modules;
+
C.getTypeDeclType(R, PrevDecl);
return R;
}
RecordDecl *RecordDecl::CreateDeserialized(const ASTContext &C, unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(RecordDecl));
- return new (Mem) RecordDecl(Record, TTK_Struct, 0, SourceLocation(),
- SourceLocation(), 0, 0);
+ RecordDecl *R = new (Mem) RecordDecl(Record, TTK_Struct, 0, SourceLocation(),
+ SourceLocation(), 0, 0);
+ R->MayHaveOutOfDateDef = C.getLangOpts().Modules;
+ return R;
}
bool RecordDecl::isInjectedClassName() const {
@@ -2793,7 +3097,7 @@ void RecordDecl::LoadFieldsFromExternalStorage() const {
// BlockDecl Implementation
//===----------------------------------------------------------------------===//
-void BlockDecl::setParams(llvm::ArrayRef<ParmVarDecl *> NewParamInfo) {
+void BlockDecl::setParams(ArrayRef<ParmVarDecl *> NewParamInfo) {
assert(ParamInfo == 0 && "Already has param info!");
// Zero params -> null pointer.
@@ -2871,6 +3175,14 @@ LabelDecl *LabelDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
void ValueDecl::anchor() { }
+bool ValueDecl::isWeak() const {
+ for (attr_iterator I = attr_begin(), E = attr_end(); I != E; ++I)
+ if (isa<WeakAttr>(*I) || isa<WeakRefAttr>(*I))
+ return true;
+
+ return isWeakImported();
+}
+
void ImplicitParamDecl::anchor() { }
ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC,
@@ -2890,12 +3202,12 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
- StorageClass SC, StorageClass SCAsWritten,
+ StorageClass SC,
bool isInlineSpecified,
bool hasWrittenPrototype,
bool isConstexprSpecified) {
FunctionDecl *New = new (C) FunctionDecl(Function, DC, StartLoc, NameInfo,
- T, TInfo, SC, SCAsWritten,
+ T, TInfo, SC,
isInlineSpecified,
isConstexprSpecified);
New->HasWrittenPrototype = hasWrittenPrototype;
@@ -2906,7 +3218,7 @@ FunctionDecl *FunctionDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(FunctionDecl));
return new (Mem) FunctionDecl(Function, 0, SourceLocation(),
DeclarationNameInfo(), QualType(), 0,
- SC_None, SC_None, false, false);
+ SC_None, false, false);
}
BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
@@ -3013,6 +3325,17 @@ FileScopeAsmDecl *FileScopeAsmDecl::CreateDeserialized(ASTContext &C,
return new (Mem) FileScopeAsmDecl(0, 0, SourceLocation(), SourceLocation());
}
+void EmptyDecl::anchor() {}
+
+EmptyDecl *EmptyDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
+ return new (C) EmptyDecl(DC, L);
+}
+
+EmptyDecl *EmptyDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(EmptyDecl));
+ return new (Mem) EmptyDecl(0, SourceLocation());
+}
+
//===----------------------------------------------------------------------===//
// ImportDecl Implementation
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 4400d50..bd6d99c 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -12,19 +12,21 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/DeclBase.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
-#include "clang/AST/DeclContextInternals.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclContextInternals.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DependentDiagnostic.h"
#include "clang/AST/ExternalASTSource.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Type.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
-#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/Type.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/raw_ostream.h"
@@ -39,6 +41,10 @@ using namespace clang;
#define ABSTRACT_DECL(DECL)
#include "clang/AST/DeclNodes.inc"
+void Decl::updateOutOfDate(IdentifierInfo &II) const {
+ getASTContext().getExternalSource()->updateOutOfDateIdentifier(II);
+}
+
void *Decl::AllocateDeserializedDecl(const ASTContext &Context,
unsigned ID,
unsigned Size) {
@@ -58,6 +64,11 @@ void *Decl::AllocateDeserializedDecl(const ASTContext &Context,
return Result;
}
+Module *Decl::getOwningModuleSlow() const {
+ assert(isFromASTFile() && "Not from AST file?");
+ return getASTContext().getExternalSource()->getModule(getOwningModuleID());
+}
+
const char *Decl::getDeclKindName() const {
switch (DeclKind) {
default: llvm_unreachable("Declaration not in DeclNodes.inc!");
@@ -180,8 +191,11 @@ void PrettyStackTraceDecl::print(raw_ostream &OS) const {
OS << Message;
- if (const NamedDecl *DN = dyn_cast_or_null<NamedDecl>(TheDecl))
- OS << " '" << DN->getQualifiedNameAsString() << '\'';
+ if (const NamedDecl *DN = dyn_cast_or_null<NamedDecl>(TheDecl)) {
+ OS << " '";
+ DN->printQualifiedName(OS);
+ OS << '\'';
+ }
OS << '\n';
}
@@ -253,6 +267,19 @@ ASTMutationListener *Decl::getASTMutationListener() const {
return getASTContext().getASTMutationListener();
}
+unsigned Decl::getMaxAlignment() const {
+ if (!hasAttrs())
+ return 0;
+
+ unsigned Align = 0;
+ const AttrVec &V = getAttrs();
+ ASTContext &Ctx = getASTContext();
+ specific_attr_iterator<AlignedAttr> I(V.begin()), E(V.end());
+ for (; I != E; ++I)
+ Align = std::max(Align, I->getAlignment(Ctx));
+ return Align;
+}
+
bool Decl::isUsed(bool CheckUsedAttr) const {
if (Used)
return true;
@@ -260,13 +287,7 @@ bool Decl::isUsed(bool CheckUsedAttr) const {
// Check for used attribute.
if (CheckUsedAttr && hasAttr<UsedAttr>())
return true;
-
- // Check redeclarations for used attribute.
- for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
- if ((CheckUsedAttr && I->hasAttr<UsedAttr>()) || I->Used)
- return true;
- }
-
+
return false;
}
@@ -414,7 +435,7 @@ bool Decl::canBeWeakImported(bool &IsDefinition) const {
// Variables, if they aren't definitions.
if (const VarDecl *Var = dyn_cast<VarDecl>(this)) {
- if (!Var->hasExternalStorage() || Var->getInit()) {
+ if (Var->isThisDeclarationADefinition()) {
IsDefinition = true;
return false;
}
@@ -541,6 +562,8 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ObjCCategory:
case ObjCCategoryImpl:
case Import:
+ case OMPThreadPrivate:
+ case Empty:
// Never looked up by name.
return 0;
}
@@ -789,6 +812,17 @@ bool DeclContext::isExternCContext() const {
return false;
}
+bool DeclContext::isExternCXXContext() const {
+ const DeclContext *DC = this;
+ while (DC->DeclKind != Decl::TranslationUnit) {
+ if (DC->DeclKind == Decl::LinkageSpec)
+ return cast<LinkageSpecDecl>(DC)->getLanguage()
+ == LinkageSpecDecl::lang_cxx;
+ DC = DC->getParent();
+ }
+ return false;
+}
+
bool DeclContext::Encloses(const DeclContext *DC) const {
if (getPrimaryContext() != this)
return getPrimaryContext()->Encloses(DC);
@@ -862,7 +896,7 @@ DeclContext *DeclContext::getPrimaryContext() {
}
void
-DeclContext::collectAllContexts(llvm::SmallVectorImpl<DeclContext *> &Contexts){
+DeclContext::collectAllContexts(SmallVectorImpl<DeclContext *> &Contexts){
Contexts.clear();
if (DeclKind != Decl::Namespace) {
@@ -900,6 +934,21 @@ DeclContext::BuildDeclChain(ArrayRef<Decl*> Decls,
return std::make_pair(FirstNewDecl, PrevDecl);
}
+/// \brief We have just acquired external visible storage, and we already have
+/// built a lookup map. For every name in the map, pull in the new names from
+/// the external storage.
+void DeclContext::reconcileExternalVisibleStorage() {
+ assert(NeedToReconcileExternalVisibleStorage && LookupPtr.getPointer());
+ NeedToReconcileExternalVisibleStorage = false;
+
+ StoredDeclsMap &Map = *LookupPtr.getPointer();
+ ExternalASTSource *Source = getParentASTContext().getExternalSource();
+ for (StoredDeclsMap::iterator I = Map.begin(); I != Map.end(); ++I) {
+ I->second.removeExternalDecls();
+ Source->FindExternalVisibleDeclsByName(this, I->first);
+ }
+}
+
/// \brief Load the declarations within this lexical storage from an
/// external source.
void
@@ -950,9 +999,8 @@ ExternalASTSource::SetNoExternalVisibleDeclsForName(const DeclContext *DC,
if (!(Map = DC->LookupPtr.getPointer()))
Map = DC->CreateStoredDeclsMap(Context);
- StoredDeclsList &List = (*Map)[Name];
- assert(List.isNull());
- (void) List;
+ // Add an entry to the map for this name, if it's not already present.
+ (*Map)[Name];
return DeclContext::lookup_result();
}
@@ -962,7 +1010,6 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC,
DeclarationName Name,
ArrayRef<NamedDecl*> Decls) {
ASTContext &Context = DC->getParentASTContext();
-
StoredDeclsMap *Map;
if (!(Map = DC->LookupPtr.getPointer()))
Map = DC->CreateStoredDeclsMap(Context);
@@ -973,6 +1020,7 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC,
if (List.isNull())
List.setOnlyValue(*I);
else
+ // FIXME: Need declarationReplaces handling for redeclarations in modules.
List.AddSubsequentDecl(*I);
}
@@ -1114,16 +1162,18 @@ static bool shouldBeHidden(NamedDecl *D) {
StoredDeclsMap *DeclContext::buildLookup() {
assert(this == getPrimaryContext() && "buildLookup called on non-primary DC");
+ // FIXME: Should we keep going if hasExternalVisibleStorage?
if (!LookupPtr.getInt())
return LookupPtr.getPointer();
- llvm::SmallVector<DeclContext *, 2> Contexts;
+ SmallVector<DeclContext *, 2> Contexts;
collectAllContexts(Contexts);
for (unsigned I = 0, N = Contexts.size(); I != N; ++I)
buildLookupImpl(Contexts[I]);
// We no longer have any lazy decls.
LookupPtr.setInt(false);
+ NeedToReconcileExternalVisibleStorage = false;
return LookupPtr.getPointer();
}
@@ -1162,18 +1212,33 @@ DeclContext::lookup(DeclarationName Name) {
return PrimaryContext->lookup(Name);
if (hasExternalVisibleStorage()) {
- // If a PCH has a result for this name, and we have a local declaration, we
- // will have imported the PCH result when adding the local declaration.
- // FIXME: For modules, we could have had more declarations added by module
- // imoprts since we saw the declaration of the local name.
- if (StoredDeclsMap *Map = LookupPtr.getPointer()) {
- StoredDeclsMap::iterator I = Map->find(Name);
- if (I != Map->end())
- return I->second.getLookupResult();
- }
+ StoredDeclsMap *Map = LookupPtr.getPointer();
+ if (LookupPtr.getInt())
+ Map = buildLookup();
+ else if (NeedToReconcileExternalVisibleStorage)
+ reconcileExternalVisibleStorage();
+
+ if (!Map)
+ Map = CreateStoredDeclsMap(getParentASTContext());
+
+ // If a PCH/module has a result for this name, and we have a local
+ // declaration, we will have imported the PCH/module result when adding the
+ // local declaration or when reconciling the module.
+ std::pair<StoredDeclsMap::iterator, bool> R =
+ Map->insert(std::make_pair(Name, StoredDeclsList()));
+ if (!R.second)
+ return R.first->second.getLookupResult();
ExternalASTSource *Source = getParentASTContext().getExternalSource();
- return Source->FindExternalVisibleDeclsByName(this, Name);
+ if (Source->FindExternalVisibleDeclsByName(this, Name)) {
+ if (StoredDeclsMap *Map = LookupPtr.getPointer()) {
+ StoredDeclsMap::iterator I = Map->find(Name);
+ if (I != Map->end())
+ return I->second.getLookupResult();
+ }
+ }
+
+ return lookup_result(lookup_iterator(0), lookup_iterator(0));
}
StoredDeclsMap *Map = LookupPtr.getPointer();
@@ -1190,26 +1255,26 @@ DeclContext::lookup(DeclarationName Name) {
return I->second.getLookupResult();
}
-void DeclContext::localUncachedLookup(DeclarationName Name,
- llvm::SmallVectorImpl<NamedDecl *> &Results) {
+void DeclContext::localUncachedLookup(DeclarationName Name,
+ SmallVectorImpl<NamedDecl *> &Results) {
Results.clear();
// If there's no external storage, just perform a normal lookup and copy
// the results.
if (!hasExternalVisibleStorage() && !hasExternalLexicalStorage() && Name) {
lookup_result LookupResults = lookup(Name);
- Results.insert(Results.end(), LookupResults.first, LookupResults.second);
+ Results.insert(Results.end(), LookupResults.begin(), LookupResults.end());
return;
}
// If we have a lookup table, check there first. Maybe we'll get lucky.
- if (Name) {
+ if (Name && !LookupPtr.getInt()) {
if (StoredDeclsMap *Map = LookupPtr.getPointer()) {
StoredDeclsMap::iterator Pos = Map->find(Name);
if (Pos != Map->end()) {
Results.insert(Results.end(),
- Pos->second.getLookupResult().first,
- Pos->second.getLookupResult().second);
+ Pos->second.getLookupResult().begin(),
+ Pos->second.getLookupResult().end());
return;
}
}
@@ -1361,8 +1426,8 @@ DeclContext::getUsingDirectives() const {
// FIXME: Use something more efficient than normal lookup for using
// directives. In C++, using directives are looked up more than anything else.
lookup_const_result Result = lookup(UsingDirectiveDecl::getName());
- return udir_iterator_range(reinterpret_cast<udir_iterator>(Result.first),
- reinterpret_cast<udir_iterator>(Result.second));
+ return udir_iterator_range(reinterpret_cast<udir_iterator>(Result.begin()),
+ reinterpret_cast<udir_iterator>(Result.end()));
}
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 82e630a..ffad9ae 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -12,10 +12,10 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/TypeLoc.h"
@@ -36,28 +36,33 @@ AccessSpecDecl *AccessSpecDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
}
CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
- : UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
- UserDeclaredMoveConstructor(false), UserDeclaredCopyAssignment(false),
- UserDeclaredMoveAssignment(false), UserDeclaredDestructor(false),
+ : UserDeclaredConstructor(false), UserDeclaredSpecialMembers(0),
Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true),
HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false),
HasMutableFields(false), HasOnlyCMembers(true),
- HasInClassInitializer(false),
- HasTrivialDefaultConstructor(true),
+ HasInClassInitializer(false), HasUninitializedReferenceMember(false),
+ NeedOverloadResolutionForMoveConstructor(false),
+ NeedOverloadResolutionForMoveAssignment(false),
+ NeedOverloadResolutionForDestructor(false),
+ DefaultedMoveConstructorIsDeleted(false),
+ DefaultedMoveAssignmentIsDeleted(false),
+ DefaultedDestructorIsDeleted(false),
+ HasTrivialSpecialMembers(SMF_All),
+ DeclaredNonTrivialSpecialMembers(0),
+ HasIrrelevantDestructor(true),
HasConstexprNonCopyMoveConstructor(false),
DefaultedDefaultConstructorIsConstexpr(true),
- HasConstexprDefaultConstructor(false), HasTrivialCopyConstructor(true),
- HasTrivialMoveConstructor(true), HasTrivialCopyAssignment(true),
- HasTrivialMoveAssignment(true), HasTrivialDestructor(true),
- HasIrrelevantDestructor(true),
+ HasConstexprDefaultConstructor(false),
HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false),
- UserProvidedDefaultConstructor(false), DeclaredDefaultConstructor(false),
- DeclaredCopyConstructor(false), DeclaredMoveConstructor(false),
- DeclaredCopyAssignment(false), DeclaredMoveAssignment(false),
- DeclaredDestructor(false), FailedImplicitMoveConstructor(false),
- FailedImplicitMoveAssignment(false), IsLambda(false), NumBases(0),
- NumVBases(0), Bases(), VBases(), Definition(D), FirstFriend(0) {
+ UserProvidedDefaultConstructor(false), DeclaredSpecialMembers(0),
+ ImplicitCopyConstructorHasConstParam(true),
+ ImplicitCopyAssignmentHasConstParam(true),
+ HasDeclaredCopyConstructorWithConstParam(false),
+ HasDeclaredCopyAssignmentWithConstParam(false),
+ FailedImplicitMoveConstructor(false), FailedImplicitMoveAssignment(false),
+ IsLambda(false), NumBases(0), NumVBases(0), Bases(), VBases(),
+ Definition(D), FirstFriend(0) {
}
CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const {
@@ -82,6 +87,7 @@ CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK,
bool DelayTypeCreation) {
CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, StartLoc, IdLoc,
Id, PrevDecl);
+ R->MayHaveOutOfDateDef = C.getLangOpts().Modules;
// FIXME: DelayTypeCreation seems like such a hack
if (!DelayTypeCreation)
@@ -96,6 +102,7 @@ CXXRecordDecl *CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC,
0, 0);
R->IsBeingDefined = true;
R->DefinitionData = new (C) struct LambdaDefinitionData(R, Info, Dependent);
+ R->MayHaveOutOfDateDef = false;
C.getTypeDeclType(R, /*PrevDecl=*/0);
return R;
}
@@ -103,8 +110,11 @@ CXXRecordDecl *CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC,
CXXRecordDecl *
CXXRecordDecl::CreateDeserialized(const ASTContext &C, unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(CXXRecordDecl));
- return new (Mem) CXXRecordDecl(CXXRecord, TTK_Struct, 0, SourceLocation(),
- SourceLocation(), 0, 0);
+ CXXRecordDecl *R = new (Mem) CXXRecordDecl(CXXRecord, TTK_Struct, 0,
+ SourceLocation(), SourceLocation(),
+ 0, 0);
+ R->MayHaveOutOfDateDef = false;
+ return R;
}
void
@@ -184,38 +194,35 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
BaseClassDecl->vbases_begin(),
E = BaseClassDecl->vbases_end(); VBase != E; ++VBase) {
// Add this base if it's not already in the list.
- if (SeenVBaseTypes.insert(C.getCanonicalType(VBase->getType())))
+ if (SeenVBaseTypes.insert(C.getCanonicalType(VBase->getType()))) {
VBases.push_back(VBase);
+
+ // C++11 [class.copy]p8:
+ // The implicitly-declared copy constructor for a class X will have
+ // the form 'X::X(const X&)' if each [...] virtual base class B of X
+ // has a copy constructor whose first parameter is of type
+ // 'const B&' or 'const volatile B&' [...]
+ if (CXXRecordDecl *VBaseDecl = VBase->getType()->getAsCXXRecordDecl())
+ if (!VBaseDecl->hasCopyConstructorWithConstParam())
+ data().ImplicitCopyConstructorHasConstParam = false;
+ }
}
if (Base->isVirtual()) {
// Add this base if it's not already in the list.
if (SeenVBaseTypes.insert(C.getCanonicalType(BaseType)))
- VBases.push_back(Base);
-
+ VBases.push_back(Base);
+
// C++0x [meta.unary.prop] is_empty:
// T is a class type, but not a union type, with ... no virtual base
// classes
data().Empty = false;
-
- // C++ [class.ctor]p5:
- // A default constructor is trivial [...] if:
- // -- its class has [...] no virtual bases
- data().HasTrivialDefaultConstructor = false;
-
- // C++0x [class.copy]p13:
- // A copy/move constructor for class X is trivial if it is neither
- // user-provided nor deleted and if
- // -- class X has no virtual functions and no virtual base classes, and
- data().HasTrivialCopyConstructor = false;
- data().HasTrivialMoveConstructor = false;
- // C++0x [class.copy]p27:
- // A copy/move assignment operator for class X is trivial if it is
- // neither user-provided nor deleted and if
- // -- class X has no virtual functions and no virtual base classes, and
- data().HasTrivialCopyAssignment = false;
- data().HasTrivialMoveAssignment = false;
+ // C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25:
+ // A [default constructor, copy/move constructor, or copy/move assignment
+ // operator for a class X] is trivial [...] if:
+ // -- class X has [...] no virtual base classes
+ data().HasTrivialSpecialMembers &= SMF_Destructor;
// C++0x [class]p7:
// A standard-layout class is a class that: [...]
@@ -232,36 +239,35 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
// -- all the direct base classes of its class have trivial default
// constructors.
if (!BaseClassDecl->hasTrivialDefaultConstructor())
- data().HasTrivialDefaultConstructor = false;
-
+ data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor;
+
// C++0x [class.copy]p13:
// A copy/move constructor for class X is trivial if [...]
// [...]
// -- the constructor selected to copy/move each direct base class
// subobject is trivial, and
- // FIXME: C++0x: We need to only consider the selected constructor
- // instead of all of them. For now, we treat a move constructor as being
- // non-trivial if it calls anything other than a trivial move constructor.
if (!BaseClassDecl->hasTrivialCopyConstructor())
- data().HasTrivialCopyConstructor = false;
- if (!BaseClassDecl->hasTrivialMoveConstructor() ||
- !(BaseClassDecl->hasDeclaredMoveConstructor() ||
- BaseClassDecl->needsImplicitMoveConstructor()))
- data().HasTrivialMoveConstructor = false;
+ data().HasTrivialSpecialMembers &= ~SMF_CopyConstructor;
+ // If the base class doesn't have a simple move constructor, we'll eagerly
+ // declare it and perform overload resolution to determine which function
+ // it actually calls. If it does have a simple move constructor, this
+ // check is correct.
+ if (!BaseClassDecl->hasTrivialMoveConstructor())
+ data().HasTrivialSpecialMembers &= ~SMF_MoveConstructor;
// C++0x [class.copy]p27:
// A copy/move assignment operator for class X is trivial if [...]
// [...]
// -- the assignment operator selected to copy/move each direct base
// class subobject is trivial, and
- // FIXME: C++0x: We need to only consider the selected operator instead
- // of all of them.
if (!BaseClassDecl->hasTrivialCopyAssignment())
- data().HasTrivialCopyAssignment = false;
- if (!BaseClassDecl->hasTrivialMoveAssignment() ||
- !(BaseClassDecl->hasDeclaredMoveAssignment() ||
- BaseClassDecl->needsImplicitMoveAssignment()))
- data().HasTrivialMoveAssignment = false;
+ data().HasTrivialSpecialMembers &= ~SMF_CopyAssignment;
+ // If the base class doesn't have a simple move assignment, we'll eagerly
+ // declare it and perform overload resolution to determine which function
+ // it actually calls. If it does have a simple move assignment, this
+ // check is correct.
+ if (!BaseClassDecl->hasTrivialMoveAssignment())
+ data().HasTrivialSpecialMembers &= ~SMF_MoveAssignment;
// C++11 [class.ctor]p6:
// If that user-written default constructor would satisfy the
@@ -270,24 +276,48 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
if (!BaseClassDecl->hasConstexprDefaultConstructor())
data().DefaultedDefaultConstructorIsConstexpr = false;
}
-
+
// C++ [class.ctor]p3:
// A destructor is trivial if all the direct base classes of its class
// have trivial destructors.
if (!BaseClassDecl->hasTrivialDestructor())
- data().HasTrivialDestructor = false;
+ data().HasTrivialSpecialMembers &= ~SMF_Destructor;
if (!BaseClassDecl->hasIrrelevantDestructor())
data().HasIrrelevantDestructor = false;
+ // C++11 [class.copy]p18:
+ // The implicitly-declared copy assignment oeprator for a class X will
+ // have the form 'X& X::operator=(const X&)' if each direct base class B
+ // of X has a copy assignment operator whose parameter is of type 'const
+ // B&', 'const volatile B&', or 'B' [...]
+ if (!BaseClassDecl->hasCopyAssignmentWithConstParam())
+ data().ImplicitCopyAssignmentHasConstParam = false;
+
+ // C++11 [class.copy]p8:
+ // The implicitly-declared copy constructor for a class X will have
+ // the form 'X::X(const X&)' if each direct [...] base class B of X
+ // has a copy constructor whose first parameter is of type
+ // 'const B&' or 'const volatile B&' [...]
+ if (!BaseClassDecl->hasCopyConstructorWithConstParam())
+ data().ImplicitCopyConstructorHasConstParam = false;
+
// A class has an Objective-C object member if... or any of its bases
// has an Objective-C object member.
if (BaseClassDecl->hasObjectMember())
setHasObjectMember(true);
+
+ if (BaseClassDecl->hasVolatileMember())
+ setHasVolatileMember(true);
// Keep track of the presence of mutable fields.
if (BaseClassDecl->hasMutableFields())
data().HasMutableFields = true;
+
+ if (BaseClassDecl->hasUninitializedReferenceMember())
+ data().HasUninitializedReferenceMember = true;
+
+ addedClassSubobject(BaseClassDecl);
}
if (VBases.empty())
@@ -296,8 +326,44 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
// Create base specifier for any direct or indirect virtual bases.
data().VBases = new (C) CXXBaseSpecifier[VBases.size()];
data().NumVBases = VBases.size();
- for (int I = 0, E = VBases.size(); I != E; ++I)
+ for (int I = 0, E = VBases.size(); I != E; ++I) {
+ QualType Type = VBases[I]->getType();
+ if (!Type->isDependentType())
+ addedClassSubobject(Type->getAsCXXRecordDecl());
data().getVBases()[I] = *VBases[I];
+ }
+}
+
+void CXXRecordDecl::addedClassSubobject(CXXRecordDecl *Subobj) {
+ // C++11 [class.copy]p11:
+ // A defaulted copy/move constructor for a class X is defined as
+ // deleted if X has:
+ // -- a direct or virtual base class B that cannot be copied/moved [...]
+ // -- a non-static data member of class type M (or array thereof)
+ // that cannot be copied or moved [...]
+ if (!Subobj->hasSimpleMoveConstructor())
+ data().NeedOverloadResolutionForMoveConstructor = true;
+
+ // C++11 [class.copy]p23:
+ // A defaulted copy/move assignment operator for a class X is defined as
+ // deleted if X has:
+ // -- a direct or virtual base class B that cannot be copied/moved [...]
+ // -- a non-static data member of class type M (or array thereof)
+ // that cannot be copied or moved [...]
+ if (!Subobj->hasSimpleMoveAssignment())
+ data().NeedOverloadResolutionForMoveAssignment = true;
+
+ // C++11 [class.ctor]p5, C++11 [class.copy]p11, C++11 [class.dtor]p5:
+ // A defaulted [ctor or dtor] for a class X is defined as
+ // deleted if X has:
+ // -- any direct or virtual base class [...] has a type with a destructor
+ // that is deleted or inaccessible from the defaulted [ctor or dtor].
+ // -- any non-static data member has a type with a destructor
+ // that is deleted or inaccessible from the defaulted [ctor or dtor].
+ if (!Subobj->hasSimpleDestructor()) {
+ data().NeedOverloadResolutionForMoveConstructor = true;
+ data().NeedOverloadResolutionForDestructor = true;
+ }
}
/// Callback function for CXXRecordDecl::forallBases that acknowledges
@@ -313,161 +379,29 @@ bool CXXRecordDecl::hasAnyDependentBases() const {
return !forallBases(SawBase, 0);
}
-bool CXXRecordDecl::hasConstCopyConstructor() const {
- return getCopyConstructor(Qualifiers::Const) != 0;
-}
-
bool CXXRecordDecl::isTriviallyCopyable() const {
// C++0x [class]p5:
// A trivially copyable class is a class that:
// -- has no non-trivial copy constructors,
- if (!hasTrivialCopyConstructor()) return false;
+ if (hasNonTrivialCopyConstructor()) return false;
// -- has no non-trivial move constructors,
- if (!hasTrivialMoveConstructor()) return false;
+ if (hasNonTrivialMoveConstructor()) return false;
// -- has no non-trivial copy assignment operators,
- if (!hasTrivialCopyAssignment()) return false;
+ if (hasNonTrivialCopyAssignment()) return false;
// -- has no non-trivial move assignment operators, and
- if (!hasTrivialMoveAssignment()) return false;
+ if (hasNonTrivialMoveAssignment()) return false;
// -- has a trivial destructor.
if (!hasTrivialDestructor()) return false;
return true;
}
-/// \brief Perform a simplistic form of overload resolution that only considers
-/// cv-qualifiers on a single parameter, and return the best overload candidate
-/// (if there is one).
-static CXXMethodDecl *
-GetBestOverloadCandidateSimple(
- const SmallVectorImpl<std::pair<CXXMethodDecl *, Qualifiers> > &Cands) {
- if (Cands.empty())
- return 0;
- if (Cands.size() == 1)
- return Cands[0].first;
-
- unsigned Best = 0, N = Cands.size();
- for (unsigned I = 1; I != N; ++I)
- if (Cands[Best].second.compatiblyIncludes(Cands[I].second))
- Best = I;
-
- for (unsigned I = 0; I != N; ++I)
- if (I != Best && Cands[Best].second.compatiblyIncludes(Cands[I].second))
- return 0;
-
- return Cands[Best].first;
-}
-
-CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(unsigned TypeQuals) const{
- ASTContext &Context = getASTContext();
- QualType ClassType
- = Context.getTypeDeclType(const_cast<CXXRecordDecl*>(this));
- DeclarationName ConstructorName
- = Context.DeclarationNames.getCXXConstructorName(
- Context.getCanonicalType(ClassType));
- unsigned FoundTQs;
- SmallVector<std::pair<CXXMethodDecl *, Qualifiers>, 4> Found;
- DeclContext::lookup_const_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = this->lookup(ConstructorName);
- Con != ConEnd; ++Con) {
- // C++ [class.copy]p2:
- // A non-template constructor for class X is a copy constructor if [...]
- if (isa<FunctionTemplateDecl>(*Con))
- continue;
-
- CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
- if (Constructor->isCopyConstructor(FoundTQs)) {
- if (((TypeQuals & Qualifiers::Const) == (FoundTQs & Qualifiers::Const)) ||
- (!(TypeQuals & Qualifiers::Const) && (FoundTQs & Qualifiers::Const)))
- Found.push_back(std::make_pair(
- const_cast<CXXConstructorDecl *>(Constructor),
- Qualifiers::fromCVRMask(FoundTQs)));
- }
- }
-
- return cast_or_null<CXXConstructorDecl>(
- GetBestOverloadCandidateSimple(Found));
-}
-
-CXXConstructorDecl *CXXRecordDecl::getMoveConstructor() const {
- for (ctor_iterator I = ctor_begin(), E = ctor_end(); I != E; ++I)
- if (I->isMoveConstructor())
- return *I;
-
- return 0;
-}
-
-CXXMethodDecl *CXXRecordDecl::getCopyAssignmentOperator(bool ArgIsConst) const {
- ASTContext &Context = getASTContext();
- QualType Class = Context.getTypeDeclType(const_cast<CXXRecordDecl *>(this));
- DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
-
- SmallVector<std::pair<CXXMethodDecl *, Qualifiers>, 4> Found;
- DeclContext::lookup_const_iterator Op, OpEnd;
- for (llvm::tie(Op, OpEnd) = this->lookup(Name); Op != OpEnd; ++Op) {
- // C++ [class.copy]p9:
- // A user-declared copy assignment operator is a non-static non-template
- // member function of class X with exactly one parameter of type X, X&,
- // const X&, volatile X& or const volatile X&.
- const CXXMethodDecl* Method = dyn_cast<CXXMethodDecl>(*Op);
- if (!Method || Method->isStatic() || Method->getPrimaryTemplate())
- continue;
-
- const FunctionProtoType *FnType
- = Method->getType()->getAs<FunctionProtoType>();
- assert(FnType && "Overloaded operator has no prototype.");
- // Don't assert on this; an invalid decl might have been left in the AST.
- if (FnType->getNumArgs() != 1 || FnType->isVariadic())
- continue;
-
- QualType ArgType = FnType->getArgType(0);
- Qualifiers Quals;
- if (const LValueReferenceType *Ref = ArgType->getAs<LValueReferenceType>()) {
- ArgType = Ref->getPointeeType();
- // If we have a const argument and we have a reference to a non-const,
- // this function does not match.
- if (ArgIsConst && !ArgType.isConstQualified())
- continue;
-
- Quals = ArgType.getQualifiers();
- } else {
- // By-value copy-assignment operators are treated like const X&
- // copy-assignment operators.
- Quals = Qualifiers::fromCVRMask(Qualifiers::Const);
- }
-
- if (!Context.hasSameUnqualifiedType(ArgType, Class))
- continue;
-
- // Save this copy-assignment operator. It might be "the one".
- Found.push_back(std::make_pair(const_cast<CXXMethodDecl *>(Method), Quals));
- }
-
- // Use a simplistic form of overload resolution to find the candidate.
- return GetBestOverloadCandidateSimple(Found);
-}
-
-CXXMethodDecl *CXXRecordDecl::getMoveAssignmentOperator() const {
- for (method_iterator I = method_begin(), E = method_end(); I != E; ++I)
- if (I->isMoveAssignmentOperator())
- return *I;
-
- return 0;
-}
-
void CXXRecordDecl::markedVirtualFunctionPure() {
// C++ [class.abstract]p2:
// A class is abstract if it has at least one pure virtual function.
data().Abstract = true;
}
-void CXXRecordDecl::markedConstructorConstexpr(CXXConstructorDecl *CD) {
- if (!CD->isCopyOrMoveConstructor())
- data().HasConstexprNonCopyMoveConstructor = true;
-
- if (CD->isDefaultConstructor())
- data().HasConstexprDefaultConstructor = true;
-}
-
void CXXRecordDecl::addedMember(Decl *D) {
if (!D->isImplicit() &&
!isa<FieldDecl>(D) &&
@@ -502,75 +436,41 @@ void CXXRecordDecl::addedMember(Decl *D) {
// A class that declares or inherits a virtual function is called a
// polymorphic class.
data().Polymorphic = true;
-
- // C++0x [class.ctor]p5
- // A default constructor is trivial [...] if:
- // -- its class has no virtual functions [...]
- data().HasTrivialDefaultConstructor = false;
- // C++0x [class.copy]p13:
- // A copy/move constructor for class X is trivial if [...]
+ // C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25:
+ // A [default constructor, copy/move constructor, or copy/move
+ // assignment operator for a class X] is trivial [...] if:
// -- class X has no virtual functions [...]
- data().HasTrivialCopyConstructor = false;
- data().HasTrivialMoveConstructor = false;
+ data().HasTrivialSpecialMembers &= SMF_Destructor;
- // C++0x [class.copy]p27:
- // A copy/move assignment operator for class X is trivial if [...]
- // -- class X has no virtual functions [...]
- data().HasTrivialCopyAssignment = false;
- data().HasTrivialMoveAssignment = false;
-
// C++0x [class]p7:
// A standard-layout class is a class that: [...]
// -- has no virtual functions
data().IsStandardLayout = false;
}
}
-
- if (D->isImplicit()) {
- // Notify that an implicit member was added after the definition
- // was completed.
- if (!isBeingDefined())
- if (ASTMutationListener *L = getASTMutationListener())
- L->AddedCXXImplicitMember(data().Definition, D);
-
- // If this is a special member function, note that it was added and then
- // return early.
- if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
- if (Constructor->isDefaultConstructor()) {
- data().DeclaredDefaultConstructor = true;
- if (Constructor->isConstexpr()) {
- data().HasConstexprDefaultConstructor = true;
- data().HasConstexprNonCopyMoveConstructor = true;
- }
- } else if (Constructor->isCopyConstructor()) {
- data().DeclaredCopyConstructor = true;
- } else if (Constructor->isMoveConstructor()) {
- data().DeclaredMoveConstructor = true;
- } else
- goto NotASpecialMember;
- return;
- } else if (isa<CXXDestructorDecl>(D)) {
- data().DeclaredDestructor = true;
- return;
- } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
- if (Method->isCopyAssignmentOperator())
- data().DeclaredCopyAssignment = true;
- else if (Method->isMoveAssignmentOperator())
- data().DeclaredMoveAssignment = true;
- else
- goto NotASpecialMember;
- return;
- }
-NotASpecialMember:;
- // Any other implicit declarations are handled like normal declarations.
- }
-
- // Handle (user-declared) constructors.
+ // Notify the listener if an implicit member was added after the definition
+ // was completed.
+ if (!isBeingDefined() && D->isImplicit())
+ if (ASTMutationListener *L = getASTMutationListener())
+ L->AddedCXXImplicitMember(data().Definition, D);
+
+ // The kind of special member this declaration is, if any.
+ unsigned SMKind = 0;
+
+ // Handle constructors.
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
- // Note that we have a user-declared constructor.
- data().UserDeclaredConstructor = true;
+ if (!Constructor->isImplicit()) {
+ // Note that we have a user-declared constructor.
+ data().UserDeclaredConstructor = true;
+
+ // C++ [class]p4:
+ // A POD-struct is an aggregate class [...]
+ // Since the POD bit is meant to be C++03 POD-ness, clear it even if the
+ // type is technically an aggregate in C++0x since it wouldn't be in 03.
+ data().PlainOldData = false;
+ }
// Technically, "user-provided" is only defined for special member
// functions, but the intent of the standard is clearly that it should apply
@@ -578,47 +478,29 @@ NotASpecialMember:;
bool UserProvided = Constructor->isUserProvided();
if (Constructor->isDefaultConstructor()) {
- data().DeclaredDefaultConstructor = true;
- if (UserProvided) {
- // C++0x [class.ctor]p5:
- // A default constructor is trivial if it is not user-provided [...]
- data().HasTrivialDefaultConstructor = false;
+ SMKind |= SMF_DefaultConstructor;
+
+ if (UserProvided)
data().UserProvidedDefaultConstructor = true;
- }
- if (Constructor->isConstexpr()) {
+ if (Constructor->isConstexpr())
data().HasConstexprDefaultConstructor = true;
- data().HasConstexprNonCopyMoveConstructor = true;
- }
}
- // Note when we have a user-declared copy or move constructor, which will
- // suppress the implicit declaration of those constructors.
if (!FunTmpl) {
- if (Constructor->isCopyConstructor()) {
- data().UserDeclaredCopyConstructor = true;
- data().DeclaredCopyConstructor = true;
-
- // C++0x [class.copy]p13:
- // A copy/move constructor for class X is trivial if it is not
- // user-provided [...]
- if (UserProvided)
- data().HasTrivialCopyConstructor = false;
- } else if (Constructor->isMoveConstructor()) {
- data().UserDeclaredMoveConstructor = true;
- data().DeclaredMoveConstructor = true;
-
- // C++0x [class.copy]p13:
- // A copy/move constructor for class X is trivial if it is not
- // user-provided [...]
- if (UserProvided)
- data().HasTrivialMoveConstructor = false;
- }
+ unsigned Quals;
+ if (Constructor->isCopyConstructor(Quals)) {
+ SMKind |= SMF_CopyConstructor;
+
+ if (Quals & Qualifiers::Const)
+ data().HasDeclaredCopyConstructorWithConstParam = true;
+ } else if (Constructor->isMoveConstructor())
+ SMKind |= SMF_MoveConstructor;
}
- if (Constructor->isConstexpr() && !Constructor->isCopyOrMoveConstructor()) {
- // Record if we see any constexpr constructors which are neither copy
- // nor move constructors.
+
+ // Record if we see any constexpr constructors which are neither copy
+ // nor move constructors.
+ if (Constructor->isConstexpr() && !Constructor->isCopyOrMoveConstructor())
data().HasConstexprNonCopyMoveConstructor = true;
- }
// C++ [dcl.init.aggr]p1:
// An aggregate is an array or a class with no user-declared
@@ -626,106 +508,99 @@ NotASpecialMember:;
// C++0x [dcl.init.aggr]p1:
// An aggregate is an array or a class with no user-provided
// constructors [...].
- if (!getASTContext().getLangOpts().CPlusPlus0x || UserProvided)
+ if (getASTContext().getLangOpts().CPlusPlus11
+ ? UserProvided : !Constructor->isImplicit())
data().Aggregate = false;
-
- // C++ [class]p4:
- // A POD-struct is an aggregate class [...]
- // Since the POD bit is meant to be C++03 POD-ness, clear it even if the
- // type is technically an aggregate in C++0x since it wouldn't be in 03.
- data().PlainOldData = false;
-
- return;
}
- // Handle (user-declared) destructors.
+ // Handle destructors.
if (CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D)) {
- data().DeclaredDestructor = true;
- data().UserDeclaredDestructor = true;
- data().HasIrrelevantDestructor = false;
-
- // C++ [class]p4:
- // A POD-struct is an aggregate class that has [...] no user-defined
- // destructor.
- // This bit is the C++03 POD bit, not the 0x one.
- data().PlainOldData = false;
-
- // C++11 [class.dtor]p5:
- // A destructor is trivial if it is not user-provided and if
- // -- the destructor is not virtual.
- if (DD->isUserProvided() || DD->isVirtual())
- data().HasTrivialDestructor = false;
+ SMKind |= SMF_Destructor;
- return;
+ if (!DD->isImplicit())
+ data().HasIrrelevantDestructor = false;
+
+ // C++11 [class.dtor]p5:
+ // A destructor is trivial if [...] the destructor is not virtual.
+ if (DD->isVirtual())
+ data().HasTrivialSpecialMembers &= ~SMF_Destructor;
}
-
- // Handle (user-declared) member functions.
+
+ // Handle member functions.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
if (Method->isCopyAssignmentOperator()) {
- // C++ [class]p4:
- // A POD-struct is an aggregate class that [...] has no user-defined
- // copy assignment operator [...].
- // This is the C++03 bit only.
- data().PlainOldData = false;
+ SMKind |= SMF_CopyAssignment;
- // This is a copy assignment operator.
-
- // Suppress the implicit declaration of a copy constructor.
- data().UserDeclaredCopyAssignment = true;
- data().DeclaredCopyAssignment = true;
-
- // C++0x [class.copy]p27:
- // A copy/move assignment operator for class X is trivial if it is
- // neither user-provided nor deleted [...]
- if (Method->isUserProvided())
- data().HasTrivialCopyAssignment = false;
-
- return;
+ const ReferenceType *ParamTy =
+ Method->getParamDecl(0)->getType()->getAs<ReferenceType>();
+ if (!ParamTy || ParamTy->getPointeeType().isConstQualified())
+ data().HasDeclaredCopyAssignmentWithConstParam = true;
}
-
- if (Method->isMoveAssignmentOperator()) {
- // This is an extension in C++03 mode, but we'll keep consistency by
- // taking a move assignment operator to induce non-POD-ness
- data().PlainOldData = false;
-
- // This is a move assignment operator.
- data().UserDeclaredMoveAssignment = true;
- data().DeclaredMoveAssignment = true;
- // C++0x [class.copy]p27:
- // A copy/move assignment operator for class X is trivial if it is
- // neither user-provided nor deleted [...]
- if (Method->isUserProvided())
- data().HasTrivialMoveAssignment = false;
- }
+ if (Method->isMoveAssignmentOperator())
+ SMKind |= SMF_MoveAssignment;
// Keep the list of conversion functions up-to-date.
if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
- // We don't record specializations.
- if (Conversion->getPrimaryTemplate())
- return;
-
// FIXME: We intentionally don't use the decl's access here because it
// hasn't been set yet. That's really just a misdesign in Sema.
-
- if (FunTmpl) {
+ if (Conversion->getPrimaryTemplate()) {
+ // We don't record specializations.
+ } else if (FunTmpl) {
if (FunTmpl->getPreviousDecl())
data().Conversions.replace(FunTmpl->getPreviousDecl(),
FunTmpl);
else
- data().Conversions.addDecl(FunTmpl);
+ data().Conversions.addDecl(getASTContext(), FunTmpl);
} else {
if (Conversion->getPreviousDecl())
data().Conversions.replace(Conversion->getPreviousDecl(),
Conversion);
else
- data().Conversions.addDecl(Conversion);
+ data().Conversions.addDecl(getASTContext(), Conversion);
}
}
-
+
+ if (SMKind) {
+ // If this is the first declaration of a special member, we no longer have
+ // an implicit trivial special member.
+ data().HasTrivialSpecialMembers &=
+ data().DeclaredSpecialMembers | ~SMKind;
+
+ if (!Method->isImplicit() && !Method->isUserProvided()) {
+ // This method is user-declared but not user-provided. We can't work out
+ // whether it's trivial yet (not until we get to the end of the class).
+ // We'll handle this method in finishedDefaultedOrDeletedMember.
+ } else if (Method->isTrivial())
+ data().HasTrivialSpecialMembers |= SMKind;
+ else
+ data().DeclaredNonTrivialSpecialMembers |= SMKind;
+
+ // Note when we have declared a declared special member, and suppress the
+ // implicit declaration of this special member.
+ data().DeclaredSpecialMembers |= SMKind;
+
+ if (!Method->isImplicit()) {
+ data().UserDeclaredSpecialMembers |= SMKind;
+
+ // C++03 [class]p4:
+ // A POD-struct is an aggregate class that has [...] no user-defined
+ // copy assignment operator and no user-defined destructor.
+ //
+ // Since the POD bit is meant to be C++03 POD-ness, and in C++03,
+ // aggregates could not have any constructors, clear it even for an
+ // explicitly defaulted or deleted constructor.
+ // type is technically an aggregate in C++0x since it wouldn't be in 03.
+ //
+ // Also, a user-declared move assignment operator makes a class non-POD.
+ // This is an extension in C++03.
+ data().PlainOldData = false;
+ }
+ }
+
return;
}
-
+
// Handle non-static data members.
if (FieldDecl *Field = dyn_cast<FieldDecl>(D)) {
// C++ [class.bit]p2:
@@ -785,7 +660,8 @@ NotASpecialMember:;
data().PlainOldData = false;
if (T->isReferenceType()) {
- data().HasTrivialDefaultConstructor = false;
+ if (!Field->hasInClassInitializer())
+ data().HasUninitializedReferenceMember = true;
// C++0x [class]p7:
// A standard-layout class is a class that:
@@ -803,7 +679,7 @@ NotASpecialMember:;
// C++11 [class]p5:
// A default constructor is trivial if [...] no non-static data member
// of its class has a brace-or-equal-initializer.
- data().HasTrivialDefaultConstructor = false;
+ data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor;
// C++11 [dcl.init.aggr]p1:
// An aggregate is a [...] class with [...] no
@@ -815,16 +691,39 @@ NotASpecialMember:;
data().PlainOldData = false;
}
+ // C++11 [class.copy]p23:
+ // A defaulted copy/move assignment operator for a class X is defined
+ // as deleted if X has:
+ // -- a non-static data member of reference type
+ if (T->isReferenceType())
+ data().DefaultedMoveAssignmentIsDeleted = true;
+
if (const RecordType *RecordTy = T->getAs<RecordType>()) {
CXXRecordDecl* FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl());
if (FieldRec->getDefinition()) {
+ addedClassSubobject(FieldRec);
+
+ // C++11 [class.ctor]p5, C++11 [class.copy]p11:
+ // A defaulted [special member] for a class X is defined as
+ // deleted if:
+ // -- X is a union-like class that has a variant member with a
+ // non-trivial [corresponding special member]
+ if (isUnion()) {
+ if (FieldRec->hasNonTrivialMoveConstructor())
+ data().DefaultedMoveConstructorIsDeleted = true;
+ if (FieldRec->hasNonTrivialMoveAssignment())
+ data().DefaultedMoveAssignmentIsDeleted = true;
+ if (FieldRec->hasNonTrivialDestructor())
+ data().DefaultedDestructorIsDeleted = true;
+ }
+
// C++0x [class.ctor]p5:
// A default constructor is trivial [...] if:
// -- for all the non-static data members of its class that are of
// class type (or array thereof), each such class has a trivial
// default constructor.
if (!FieldRec->hasTrivialDefaultConstructor())
- data().HasTrivialDefaultConstructor = false;
+ data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor;
// C++0x [class.copy]p13:
// A copy/move constructor for class X is trivial if [...]
@@ -832,13 +731,13 @@ NotASpecialMember:;
// -- for each non-static data member of X that is of class type (or
// an array thereof), the constructor selected to copy/move that
// member is trivial;
- // FIXME: C++0x: We don't correctly model 'selected' constructors.
if (!FieldRec->hasTrivialCopyConstructor())
- data().HasTrivialCopyConstructor = false;
- if (!FieldRec->hasTrivialMoveConstructor() ||
- !(FieldRec->hasDeclaredMoveConstructor() ||
- FieldRec->needsImplicitMoveConstructor()))
- data().HasTrivialMoveConstructor = false;
+ data().HasTrivialSpecialMembers &= ~SMF_CopyConstructor;
+ // If the field doesn't have a simple move constructor, we'll eagerly
+ // declare the move constructor for this class and we'll decide whether
+ // it's trivial then.
+ if (!FieldRec->hasTrivialMoveConstructor())
+ data().HasTrivialSpecialMembers &= ~SMF_MoveConstructor;
// C++0x [class.copy]p27:
// A copy/move assignment operator for class X is trivial if [...]
@@ -846,20 +745,22 @@ NotASpecialMember:;
// -- for each non-static data member of X that is of class type (or
// an array thereof), the assignment operator selected to
// copy/move that member is trivial;
- // FIXME: C++0x: We don't correctly model 'selected' operators.
if (!FieldRec->hasTrivialCopyAssignment())
- data().HasTrivialCopyAssignment = false;
- if (!FieldRec->hasTrivialMoveAssignment() ||
- !(FieldRec->hasDeclaredMoveAssignment() ||
- FieldRec->needsImplicitMoveAssignment()))
- data().HasTrivialMoveAssignment = false;
+ data().HasTrivialSpecialMembers &= ~SMF_CopyAssignment;
+ // If the field doesn't have a simple move assignment, we'll eagerly
+ // declare the move assignment for this class and we'll decide whether
+ // it's trivial then.
+ if (!FieldRec->hasTrivialMoveAssignment())
+ data().HasTrivialSpecialMembers &= ~SMF_MoveAssignment;
if (!FieldRec->hasTrivialDestructor())
- data().HasTrivialDestructor = false;
+ data().HasTrivialSpecialMembers &= ~SMF_Destructor;
if (!FieldRec->hasIrrelevantDestructor())
data().HasIrrelevantDestructor = false;
if (FieldRec->hasObjectMember())
setHasObjectMember(true);
+ if (FieldRec->hasVolatileMember())
+ setHasVolatileMember(true);
// C++0x [class]p7:
// A standard-layout class is a class that:
@@ -910,12 +811,42 @@ NotASpecialMember:;
// The standard requires any in-class initializer to be a constant
// expression. We consider this to be a defect.
data().DefaultedDefaultConstructorIsConstexpr = false;
+
+ // C++11 [class.copy]p8:
+ // The implicitly-declared copy constructor for a class X will have
+ // the form 'X::X(const X&)' if [...] for all the non-static data
+ // members of X that are of a class type M (or array thereof), each
+ // such class type has a copy constructor whose first parameter is
+ // of type 'const M&' or 'const volatile M&'.
+ if (!FieldRec->hasCopyConstructorWithConstParam())
+ data().ImplicitCopyConstructorHasConstParam = false;
+
+ // C++11 [class.copy]p18:
+ // The implicitly-declared copy assignment oeprator for a class X will
+ // have the form 'X& X::operator=(const X&)' if [...] for all the
+ // non-static data members of X that are of a class type M (or array
+ // thereof), each such class type has a copy assignment operator whose
+ // parameter is of type 'const M&', 'const volatile M&' or 'M'.
+ if (!FieldRec->hasCopyAssignmentWithConstParam())
+ data().ImplicitCopyAssignmentHasConstParam = false;
+
+ if (FieldRec->hasUninitializedReferenceMember() &&
+ !Field->hasInClassInitializer())
+ data().HasUninitializedReferenceMember = true;
}
} else {
// Base element type of field is a non-class type.
if (!T->isLiteralType() ||
(!Field->hasInClassInitializer() && !isUnion()))
data().DefaultedDefaultConstructorIsConstexpr = false;
+
+ // C++11 [class.copy]p23:
+ // A defaulted copy/move assignment operator for a class X is defined
+ // as deleted if X has:
+ // -- a non-static data member of const non-class type (or array
+ // thereof)
+ if (T.isConstQualified())
+ data().DefaultedMoveAssignmentIsDeleted = true;
}
// C++0x [class]p7:
@@ -943,7 +874,41 @@ NotASpecialMember:;
if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(D))
if (Shadow->getDeclName().getNameKind()
== DeclarationName::CXXConversionFunctionName)
- data().Conversions.addDecl(Shadow, Shadow->getAccess());
+ data().Conversions.addDecl(getASTContext(), Shadow, Shadow->getAccess());
+}
+
+void CXXRecordDecl::finishedDefaultedOrDeletedMember(CXXMethodDecl *D) {
+ assert(!D->isImplicit() && !D->isUserProvided());
+
+ // The kind of special member this declaration is, if any.
+ unsigned SMKind = 0;
+
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
+ if (Constructor->isDefaultConstructor()) {
+ SMKind |= SMF_DefaultConstructor;
+ if (Constructor->isConstexpr())
+ data().HasConstexprDefaultConstructor = true;
+ }
+ if (Constructor->isCopyConstructor())
+ SMKind |= SMF_CopyConstructor;
+ else if (Constructor->isMoveConstructor())
+ SMKind |= SMF_MoveConstructor;
+ else if (Constructor->isConstexpr())
+ // We may now know that the constructor is constexpr.
+ data().HasConstexprNonCopyMoveConstructor = true;
+ } else if (isa<CXXDestructorDecl>(D))
+ SMKind |= SMF_Destructor;
+ else if (D->isCopyAssignmentOperator())
+ SMKind |= SMF_CopyAssignment;
+ else if (D->isMoveAssignmentOperator())
+ SMKind |= SMF_MoveAssignment;
+
+ // Update which trivial / non-trivial special members we have.
+ // addedMember will have skipped this step for this member.
+ if (D->isTrivial())
+ data().HasTrivialSpecialMembers |= SMKind;
+ else
+ data().DeclaredNonTrivialSpecialMembers |= SMKind;
}
bool CXXRecordDecl::isCLike() const {
@@ -1004,7 +969,7 @@ static void CollectVisibleConversions(ASTContext &Context,
bool InVirtual,
AccessSpecifier Access,
const llvm::SmallPtrSet<CanQualType, 8> &ParentHiddenTypes,
- UnresolvedSetImpl &Output,
+ ASTUnresolvedSet &Output,
UnresolvedSetImpl &VOutput,
llvm::SmallPtrSet<NamedDecl*, 8> &HiddenVBaseCs) {
// The set of types which have conversions in this class or its
@@ -1015,12 +980,13 @@ static void CollectVisibleConversions(ASTContext &Context,
// Collect the direct conversions and figure out which conversions
// will be hidden in the subclasses.
- UnresolvedSetImpl &Cs = *Record->getConversionFunctions();
- if (!Cs.empty()) {
+ CXXRecordDecl::conversion_iterator ConvI = Record->conversion_begin();
+ CXXRecordDecl::conversion_iterator ConvE = Record->conversion_end();
+ if (ConvI != ConvE) {
HiddenTypesBuffer = ParentHiddenTypes;
HiddenTypes = &HiddenTypesBuffer;
- for (UnresolvedSetIterator I = Cs.begin(), E = Cs.end(); I != E; ++I) {
+ for (CXXRecordDecl::conversion_iterator I = ConvI; I != ConvE; ++I) {
CanQualType ConvType(GetConversionType(Context, I.getDecl()));
bool Hidden = ParentHiddenTypes.count(ConvType);
if (!Hidden)
@@ -1039,7 +1005,7 @@ static void CollectVisibleConversions(ASTContext &Context,
if (InVirtual)
VOutput.addDecl(I.getDecl(), IAccess);
else
- Output.addDecl(I.getDecl(), IAccess);
+ Output.addDecl(Context, I.getDecl(), IAccess);
}
}
}
@@ -1066,7 +1032,7 @@ static void CollectVisibleConversions(ASTContext &Context,
/// bases. It might be worth special-casing that, really.
static void CollectVisibleConversions(ASTContext &Context,
CXXRecordDecl *Record,
- UnresolvedSetImpl &Output) {
+ ASTUnresolvedSet &Output) {
// The collection of all conversions in virtual bases that we've
// found. These will be added to the output as long as they don't
// appear in the hidden-conversions set.
@@ -1081,10 +1047,11 @@ static void CollectVisibleConversions(ASTContext &Context,
// Go ahead and collect the direct conversions and add them to the
// hidden-types set.
- UnresolvedSetImpl &Cs = *Record->getConversionFunctions();
- Output.append(Cs.begin(), Cs.end());
- for (UnresolvedSetIterator I = Cs.begin(), E = Cs.end(); I != E; ++I)
- HiddenTypes.insert(GetConversionType(Context, I.getDecl()));
+ CXXRecordDecl::conversion_iterator ConvI = Record->conversion_begin();
+ CXXRecordDecl::conversion_iterator ConvE = Record->conversion_end();
+ Output.append(Context, ConvI, ConvE);
+ for (; ConvI != ConvE; ++ConvI)
+ HiddenTypes.insert(GetConversionType(Context, ConvI.getDecl()));
// Recursively collect conversions from base classes.
for (CXXRecordDecl::base_class_iterator
@@ -1101,22 +1068,24 @@ static void CollectVisibleConversions(ASTContext &Context,
for (UnresolvedSetIterator I = VBaseCs.begin(), E = VBaseCs.end();
I != E; ++I) {
if (!HiddenVBaseCs.count(cast<NamedDecl>(I.getDecl()->getCanonicalDecl())))
- Output.addDecl(I.getDecl(), I.getAccess());
+ Output.addDecl(Context, I.getDecl(), I.getAccess());
}
}
/// getVisibleConversionFunctions - get all conversion functions visible
/// in current class; including conversion function templates.
-const UnresolvedSetImpl *CXXRecordDecl::getVisibleConversionFunctions() {
+std::pair<CXXRecordDecl::conversion_iterator,CXXRecordDecl::conversion_iterator>
+CXXRecordDecl::getVisibleConversionFunctions() {
// If root class, all conversions are visible.
if (bases_begin() == bases_end())
- return &data().Conversions;
+ return std::make_pair(data().Conversions.begin(), data().Conversions.end());
// If visible conversion list is already evaluated, return it.
- if (data().ComputedVisibleConversions)
- return &data().VisibleConversions;
- CollectVisibleConversions(getASTContext(), this, data().VisibleConversions);
- data().ComputedVisibleConversions = true;
- return &data().VisibleConversions;
+ if (!data().ComputedVisibleConversions) {
+ CollectVisibleConversions(getASTContext(), this, data().VisibleConversions);
+ data().ComputedVisibleConversions = true;
+ }
+ return std::make_pair(data().VisibleConversions.begin(),
+ data().VisibleConversions.end());
}
void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) {
@@ -1131,7 +1100,7 @@ void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) {
// with sufficiently large numbers of directly-declared conversions
// that asymptotic behavior matters.
- UnresolvedSetImpl &Convs = *getConversionFunctions();
+ ASTUnresolvedSet &Convs = data().Conversions;
for (unsigned I = 0, E = Convs.size(); I != E; ++I) {
if (Convs[I].getDecl() == ConvDecl) {
Convs.erase(I);
@@ -1151,10 +1120,6 @@ CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() const {
return 0;
}
-MemberSpecializationInfo *CXXRecordDecl::getMemberSpecializationInfo() const {
- return TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>();
-}
-
void
CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD,
TemplateSpecializationKind TSK) {
@@ -1200,12 +1165,11 @@ CXXDestructorDecl *CXXRecordDecl::getDestructor() const {
= Context.DeclarationNames.getCXXDestructorName(
Context.getCanonicalType(ClassType));
- DeclContext::lookup_const_iterator I, E;
- llvm::tie(I, E) = lookup(Name);
- if (I == E)
+ DeclContext::lookup_const_result R = lookup(Name);
+ if (R.empty())
return 0;
- CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(*I);
+ CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(R.front());
return Dtor;
}
@@ -1225,12 +1189,7 @@ void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) {
// non-trivial.
struct DefinitionData &Data = data();
Data.PlainOldData = false;
- Data.HasTrivialDefaultConstructor = false;
- Data.HasTrivialCopyConstructor = false;
- Data.HasTrivialMoveConstructor = false;
- Data.HasTrivialCopyAssignment = false;
- Data.HasTrivialMoveAssignment = false;
- Data.HasTrivialDestructor = false;
+ Data.HasTrivialSpecialMembers = 0;
Data.HasIrrelevantDestructor = false;
}
@@ -1270,7 +1229,7 @@ void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) {
for (UnresolvedSetIterator I = data().Conversions.begin(),
E = data().Conversions.end();
I != E; ++I)
- data().Conversions.setAccess(I, (*I)->getAccess());
+ I.setAccess((*I)->getAccess());
}
bool CXXRecordDecl::mayBeAbstract() const {
@@ -1292,6 +1251,42 @@ bool CXXRecordDecl::mayBeAbstract() const {
void CXXMethodDecl::anchor() { }
+bool CXXMethodDecl::isStatic() const {
+ const CXXMethodDecl *MD = this;
+ for (;;) {
+ const CXXMethodDecl *C = MD->getCanonicalDecl();
+ if (C != MD) {
+ MD = C;
+ continue;
+ }
+
+ FunctionTemplateSpecializationInfo *Info =
+ MD->getTemplateSpecializationInfo();
+ if (!Info)
+ break;
+ MD = cast<CXXMethodDecl>(Info->getTemplate()->getTemplatedDecl());
+ }
+
+ if (MD->getStorageClass() == SC_Static)
+ return true;
+
+ DeclarationName Name = getDeclName();
+ // [class.free]p1:
+ // Any allocation function for a class T is a static member
+ // (even if not explicitly declared static).
+ if (Name.getCXXOverloadedOperator() == OO_New ||
+ Name.getCXXOverloadedOperator() == OO_Array_New)
+ return true;
+
+ // [class.free]p6 Any deallocation function for a class X is a static member
+ // (even if not explicitly declared static).
+ if (Name.getCXXOverloadedOperator() == OO_Delete ||
+ Name.getCXXOverloadedOperator() == OO_Array_Delete)
+ return true;
+
+ return false;
+}
+
static bool recursivelyOverrides(const CXXMethodDecl *DerivedMD,
const CXXMethodDecl *BaseMD) {
for (CXXMethodDecl::method_iterator I = DerivedMD->begin_overridden_methods(),
@@ -1324,7 +1319,7 @@ CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD,
}
lookup_const_result Candidates = RD->lookup(getDeclName());
- for (NamedDecl * const * I = Candidates.first; I != Candidates.second; ++I) {
+ for (NamedDecl * const * I = Candidates.begin(); I != Candidates.end(); ++I) {
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*I);
if (!MD)
continue;
@@ -1353,10 +1348,10 @@ CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
- bool isStatic, StorageClass SCAsWritten, bool isInline,
+ StorageClass SC, bool isInline,
bool isConstexpr, SourceLocation EndLocation) {
return new (C) CXXMethodDecl(CXXMethod, RD, StartLoc, NameInfo, T, TInfo,
- isStatic, SCAsWritten, isInline, isConstexpr,
+ SC, isInline, isConstexpr,
EndLocation);
}
@@ -1364,7 +1359,7 @@ CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(CXXMethodDecl));
return new (Mem) CXXMethodDecl(CXXMethod, 0, SourceLocation(),
DeclarationNameInfo(), QualType(),
- 0, false, SC_None, false, false,
+ 0, SC_None, false, false,
SourceLocation());
}
@@ -1399,9 +1394,10 @@ bool CXXMethodDecl::isUsualDeallocationFunction() const {
// This function is a usual deallocation function if there are no
// single-parameter deallocation functions of the same kind.
- for (DeclContext::lookup_const_result R = getDeclContext()->lookup(getDeclName());
- R.first != R.second; ++R.first) {
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*R.first))
+ DeclContext::lookup_const_result R = getDeclContext()->lookup(getDeclName());
+ for (DeclContext::lookup_const_result::iterator I = R.begin(), E = R.end();
+ I != E; ++I) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I))
if (FD->getNumParams() == 1)
return false;
}
diff --git a/lib/AST/DeclFriend.cpp b/lib/AST/DeclFriend.cpp
index 553d170..37a812e 100644
--- a/lib/AST/DeclFriend.cpp
+++ b/lib/AST/DeclFriend.cpp
@@ -27,7 +27,8 @@ FriendDecl *FriendDecl::getNextFriendSlowCase() {
FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
FriendUnion Friend,
- SourceLocation FriendL) {
+ SourceLocation FriendL,
+ ArrayRef<TemplateParameterList*> FriendTypeTPLists) {
#ifndef NDEBUG
if (Friend.is<NamedDecl*>()) {
NamedDecl *D = Friend.get<NamedDecl*>();
@@ -40,15 +41,25 @@ FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC,
// to the original declaration when instantiating members.
assert(D->getFriendObjectKind() ||
(cast<CXXRecordDecl>(DC)->getTemplateSpecializationKind()));
+ // These template parameters are for friend types only.
+ assert(FriendTypeTPLists.size() == 0);
}
#endif
- FriendDecl *FD = new (C) FriendDecl(DC, L, Friend, FriendL);
+ std::size_t Size = sizeof(FriendDecl)
+ + FriendTypeTPLists.size() * sizeof(TemplateParameterList*);
+ void *Mem = C.Allocate(Size);
+ FriendDecl *FD = new (Mem) FriendDecl(DC, L, Friend, FriendL,
+ FriendTypeTPLists);
cast<CXXRecordDecl>(DC)->pushFriendDecl(FD);
return FD;
}
-FriendDecl *FriendDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(FriendDecl));
- return new (Mem) FriendDecl(EmptyShell());
+FriendDecl *FriendDecl::CreateDeserialized(ASTContext &C, unsigned ID,
+ unsigned FriendTypeNumTPLists) {
+ std::size_t Size = sizeof(FriendDecl)
+ + FriendTypeNumTPLists * sizeof(TemplateParameterList*);
+ void *Mem = AllocateDeserializedDecl(C, ID, Size);
+ return new (Mem) FriendDecl(EmptyShell(), FriendTypeNumTPLists);
}
+
diff --git a/lib/AST/DeclGroup.cpp b/lib/AST/DeclGroup.cpp
index 036acc2..9861f22 100644
--- a/lib/AST/DeclGroup.cpp
+++ b/lib/AST/DeclGroup.cpp
@@ -12,8 +12,8 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/DeclGroup.h"
-#include "clang/AST/Decl.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
#include "llvm/Support/Allocator.h"
using namespace clang;
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 65a9878..5f5ba52 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -13,8 +13,9 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/Stmt.h"
#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/Stmt.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
using namespace clang;
@@ -53,8 +54,9 @@ void ObjCContainerDecl::anchor() { }
///
ObjCIvarDecl *
ObjCContainerDecl::getIvarDecl(IdentifierInfo *Id) const {
- lookup_const_iterator Ivar, IvarEnd;
- for (llvm::tie(Ivar, IvarEnd) = lookup(Id); Ivar != IvarEnd; ++Ivar) {
+ lookup_const_result R = lookup(Id);
+ for (lookup_const_iterator Ivar = R.begin(), IvarEnd = R.end();
+ Ivar != IvarEnd; ++Ivar) {
if (ObjCIvarDecl *ivar = dyn_cast<ObjCIvarDecl>(*Ivar))
return ivar;
}
@@ -63,7 +65,16 @@ ObjCContainerDecl::getIvarDecl(IdentifierInfo *Id) const {
// Get the local instance/class method declared in this interface.
ObjCMethodDecl *
-ObjCContainerDecl::getMethod(Selector Sel, bool isInstance) const {
+ObjCContainerDecl::getMethod(Selector Sel, bool isInstance,
+ bool AllowHidden) const {
+ // If this context is a hidden protocol definition, don't find any
+ // methods there.
+ if (const ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(this)) {
+ if (const ObjCProtocolDecl *Def = Proto->getDefinition())
+ if (Def->isHidden() && !AllowHidden)
+ return 0;
+ }
+
// Since instance & class methods can have the same name, the loop below
// ensures we get the correct method.
//
@@ -72,8 +83,9 @@ ObjCContainerDecl::getMethod(Selector Sel, bool isInstance) const {
// + (float) class_method;
// @end
//
- lookup_const_iterator Meth, MethEnd;
- for (llvm::tie(Meth, MethEnd) = lookup(Sel); Meth != MethEnd; ++Meth) {
+ lookup_const_result R = lookup(Sel);
+ for (lookup_const_iterator Meth = R.begin(), MethEnd = R.end();
+ Meth != MethEnd; ++Meth) {
ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth);
if (MD && MD->isInstanceMethod() == isInstance)
return MD;
@@ -81,13 +93,86 @@ ObjCContainerDecl::getMethod(Selector Sel, bool isInstance) const {
return 0;
}
+/// HasUserDeclaredSetterMethod - This routine returns 'true' if a user declared setter
+/// method was found in the class, its protocols, its super classes or categories.
+/// It also returns 'true' if one of its categories has declared a 'readwrite' property.
+/// This is because, user must provide a setter method for the category's 'readwrite'
+/// property.
+bool
+ObjCContainerDecl::HasUserDeclaredSetterMethod(const ObjCPropertyDecl *Property) const {
+ Selector Sel = Property->getSetterName();
+ lookup_const_result R = lookup(Sel);
+ for (lookup_const_iterator Meth = R.begin(), MethEnd = R.end();
+ Meth != MethEnd; ++Meth) {
+ ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth);
+ if (MD && MD->isInstanceMethod() && !MD->isImplicit())
+ return true;
+ }
+
+ if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(this)) {
+ // Also look into categories, including class extensions, looking
+ // for a user declared instance method.
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = ID->visible_categories_begin(),
+ CatEnd = ID->visible_categories_end();
+ Cat != CatEnd;
+ ++Cat) {
+ if (ObjCMethodDecl *MD = Cat->getInstanceMethod(Sel))
+ if (!MD->isImplicit())
+ return true;
+ if (Cat->IsClassExtension())
+ continue;
+ // Also search through the categories looking for a 'readwrite' declaration
+ // of this property. If one found, presumably a setter will be provided
+ // (properties declared in categories will not get auto-synthesized).
+ for (ObjCContainerDecl::prop_iterator P = Cat->prop_begin(),
+ E = Cat->prop_end(); P != E; ++P)
+ if (P->getIdentifier() == Property->getIdentifier()) {
+ if (P->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readwrite)
+ return true;
+ break;
+ }
+ }
+
+ // Also look into protocols, for a user declared instance method.
+ for (ObjCInterfaceDecl::all_protocol_iterator P =
+ ID->all_referenced_protocol_begin(),
+ PE = ID->all_referenced_protocol_end(); P != PE; ++P) {
+ ObjCProtocolDecl *Proto = (*P);
+ if (Proto->HasUserDeclaredSetterMethod(Property))
+ return true;
+ }
+ // And in its super class.
+ ObjCInterfaceDecl *OSC = ID->getSuperClass();
+ while (OSC) {
+ if (OSC->HasUserDeclaredSetterMethod(Property))
+ return true;
+ OSC = OSC->getSuperClass();
+ }
+ }
+ if (const ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(this))
+ for (ObjCProtocolDecl::protocol_iterator PI = PD->protocol_begin(),
+ E = PD->protocol_end(); PI != E; ++PI) {
+ if ((*PI)->HasUserDeclaredSetterMethod(Property))
+ return true;
+ }
+ return false;
+}
+
ObjCPropertyDecl *
ObjCPropertyDecl::findPropertyDecl(const DeclContext *DC,
IdentifierInfo *propertyID) {
+ // If this context is a hidden protocol definition, don't find any
+ // property.
+ if (const ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(DC)) {
+ if (const ObjCProtocolDecl *Def = Proto->getDefinition())
+ if (Def->isHidden())
+ return 0;
+ }
- DeclContext::lookup_const_iterator I, E;
- llvm::tie(I, E) = DC->lookup(propertyID);
- for ( ; I != E; ++I)
+ DeclContext::lookup_const_result R = DC->lookup(propertyID);
+ for (DeclContext::lookup_const_iterator I = R.begin(), E = R.end(); I != E;
+ ++I)
if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(*I))
return PD;
@@ -108,6 +193,12 @@ ObjCPropertyDecl::getDefaultSynthIvarName(ASTContext &Ctx) const {
/// in 'PropertyId' and returns it. It returns 0, if not found.
ObjCPropertyDecl *
ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
+ // Don't find properties within hidden protocol definitions.
+ if (const ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(this)) {
+ if (const ObjCProtocolDecl *Def = Proto->getDefinition())
+ if (Def->isHidden())
+ return 0;
+ }
if (ObjCPropertyDecl *PD =
ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(this), PropertyId))
@@ -126,12 +217,15 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
}
case Decl::ObjCInterface: {
const ObjCInterfaceDecl *OID = cast<ObjCInterfaceDecl>(this);
- // Look through categories.
- for (ObjCCategoryDecl *Cat = OID->getCategoryList();
- Cat; Cat = Cat->getNextClassCategory())
+ // Look through categories (but not extensions).
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = OID->visible_categories_begin(),
+ CatEnd = OID->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
if (!Cat->IsClassExtension())
if (ObjCPropertyDecl *P = Cat->FindPropertyDeclaration(PropertyId))
return P;
+ }
// Look through protocols.
for (ObjCInterfaceDecl::all_protocol_iterator
@@ -190,21 +284,43 @@ ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass(
return 0;
}
-void ObjCInterfaceDecl::collectPropertiesToImplement(PropertyMap &PM) const {
+void ObjCInterfaceDecl::collectPropertiesToImplement(PropertyMap &PM,
+ PropertyDeclOrder &PO) const {
for (ObjCContainerDecl::prop_iterator P = prop_begin(),
E = prop_end(); P != E; ++P) {
ObjCPropertyDecl *Prop = *P;
PM[Prop->getIdentifier()] = Prop;
+ PO.push_back(Prop);
}
for (ObjCInterfaceDecl::all_protocol_iterator
PI = all_referenced_protocol_begin(),
E = all_referenced_protocol_end(); PI != E; ++PI)
- (*PI)->collectPropertiesToImplement(PM);
+ (*PI)->collectPropertiesToImplement(PM, PO);
// Note, the properties declared only in class extensions are still copied
// into the main @interface's property list, and therefore we don't
// explicitly, have to search class extension properties.
}
+bool ObjCInterfaceDecl::isArcWeakrefUnavailable() const {
+ const ObjCInterfaceDecl *Class = this;
+ while (Class) {
+ if (Class->hasAttr<ArcWeakrefUnavailableAttr>())
+ return true;
+ Class = Class->getSuperClass();
+ }
+ return false;
+}
+
+const ObjCInterfaceDecl *ObjCInterfaceDecl::isObjCRequiresPropertyDefs() const {
+ const ObjCInterfaceDecl *Class = this;
+ while (Class) {
+ if (Class->hasAttr<ObjCRequiresPropertyDefsAttr>())
+ return Class;
+ Class = Class->getSuperClass();
+ }
+ return 0;
+}
+
void ObjCInterfaceDecl::mergeClassExtensionProtocolList(
ObjCProtocolDecl *const* ExtList, unsigned ExtNum,
ASTContext &C)
@@ -254,8 +370,8 @@ void ObjCInterfaceDecl::mergeClassExtensionProtocolList(
void ObjCInterfaceDecl::allocateDefinitionData() {
assert(!hasDefinition() && "ObjC class already has a definition");
- Data = new (getASTContext()) DefinitionData();
- Data->Definition = this;
+ Data.setPointer(new (getASTContext()) DefinitionData());
+ Data.getPointer()->Definition = this;
// Make the type point at the definition, now that we have one.
if (TypeForDecl)
@@ -273,24 +389,6 @@ void ObjCInterfaceDecl::startDefinition() {
}
}
-/// getFirstClassExtension - Find first class extension of the given class.
-ObjCCategoryDecl* ObjCInterfaceDecl::getFirstClassExtension() const {
- for (ObjCCategoryDecl *CDecl = getCategoryList(); CDecl;
- CDecl = CDecl->getNextClassCategory())
- if (CDecl->IsClassExtension())
- return CDecl;
- return 0;
-}
-
-/// getNextClassCategory - Find next class extension in list of categories.
-const ObjCCategoryDecl* ObjCCategoryDecl::getNextClassExtension() const {
- for (const ObjCCategoryDecl *CDecl = getNextClassCategory(); CDecl;
- CDecl = CDecl->getNextClassCategory())
- if (CDecl->IsClassExtension())
- return CDecl;
- return 0;
-}
-
ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID,
ObjCInterfaceDecl *&clsDeclared) {
// FIXME: Should make sure no callers ever do this.
@@ -306,9 +404,12 @@ ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID,
clsDeclared = ClassDecl;
return I;
}
- for (const ObjCCategoryDecl *CDecl = ClassDecl->getFirstClassExtension();
- CDecl; CDecl = CDecl->getNextClassExtension()) {
- if (ObjCIvarDecl *I = CDecl->getIvarDecl(ID)) {
+
+ for (ObjCInterfaceDecl::visible_extensions_iterator
+ Ext = ClassDecl->visible_extensions_begin(),
+ ExtEnd = ClassDecl->visible_extensions_end();
+ Ext != ExtEnd; ++Ext) {
+ if (ObjCIvarDecl *I = Ext->getIvarDecl(ID)) {
clsDeclared = ClassDecl;
return I;
}
@@ -367,21 +468,22 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel,
return MethodDecl;
// Didn't find one yet - now look through categories.
- ObjCCategoryDecl *CatDecl = ClassDecl->getCategoryList();
- while (CatDecl) {
- if ((MethodDecl = CatDecl->getMethod(Sel, isInstance)))
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = ClassDecl->visible_categories_begin(),
+ CatEnd = ClassDecl->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
+ if ((MethodDecl = Cat->getMethod(Sel, isInstance)))
return MethodDecl;
if (!shallowCategoryLookup) {
// Didn't find one yet - look through protocols.
const ObjCList<ObjCProtocolDecl> &Protocols =
- CatDecl->getReferencedProtocols();
+ Cat->getReferencedProtocols();
for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
E = Protocols.end(); I != E; ++I)
if ((MethodDecl = (*I)->lookupMethod(Sel, isInstance)))
return MethodDecl;
}
- CatDecl = CatDecl->getNextClassCategory();
}
ClassDecl = ClassDecl->getSuperClass();
@@ -753,7 +855,8 @@ static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container,
if (MovedToSuper)
if (ObjCMethodDecl *
Overridden = Container->getMethod(Method->getSelector(),
- Method->isInstanceMethod()))
+ Method->isInstanceMethod(),
+ /*AllowHidden=*/true))
if (Method != Overridden) {
// We found an override at this category; there is no need to look
// into its protocols.
@@ -771,7 +874,8 @@ static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container,
// Check whether we have a matching method at this level.
if (const ObjCMethodDecl *
Overridden = Container->getMethod(Method->getSelector(),
- Method->isInstanceMethod()))
+ Method->isInstanceMethod(),
+ /*AllowHidden=*/true))
if (Method != Overridden) {
// We found an override at this level; there is no need to look
// into other protocols or categories.
@@ -793,10 +897,13 @@ static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container,
P != PEnd; ++P)
CollectOverriddenMethodsRecurse(*P, Method, Methods, MovedToSuper);
- for (const ObjCCategoryDecl *Category = Interface->getCategoryList();
- Category; Category = Category->getNextClassCategory())
- CollectOverriddenMethodsRecurse(Category, Method, Methods,
+ for (ObjCInterfaceDecl::known_categories_iterator
+ Cat = Interface->known_categories_begin(),
+ CatEnd = Interface->known_categories_end();
+ Cat != CatEnd; ++Cat) {
+ CollectOverriddenMethodsRecurse(*Cat, Method, Methods,
MovedToSuper);
+ }
if (const ObjCInterfaceDecl *Super = Interface->getSuperClass())
return CollectOverriddenMethodsRecurse(Super, Method, Methods,
@@ -827,7 +934,8 @@ static void collectOverriddenMethodsSlow(const ObjCMethodDecl *Method,
// Start searching for overridden methods using the method from the
// interface as starting point.
if (const ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(),
- Method->isInstanceMethod()))
+ Method->isInstanceMethod(),
+ /*AllowHidden=*/true))
Method = IFaceMeth;
CollectOverriddenMethods(ID, Method, overridden);
@@ -839,7 +947,8 @@ static void collectOverriddenMethodsSlow(const ObjCMethodDecl *Method,
// Start searching for overridden methods using the method from the
// interface as starting point.
if (const ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(),
- Method->isInstanceMethod()))
+ Method->isInstanceMethod(),
+ /*AllowHidden=*/true))
Method = IFaceMeth;
CollectOverriddenMethods(ID, Method, overridden);
@@ -858,11 +967,14 @@ static void collectOnCategoriesAfterLocation(SourceLocation Loc,
if (!Class)
return;
- for (const ObjCCategoryDecl *Category = Class->getCategoryList();
- Category; Category = Category->getNextClassCategory())
- if (SM.isBeforeInTranslationUnit(Loc, Category->getLocation()))
- CollectOverriddenMethodsRecurse(Category, Method, Methods, true);
-
+ for (ObjCInterfaceDecl::known_categories_iterator
+ Cat = Class->known_categories_begin(),
+ CatEnd = Class->known_categories_end();
+ Cat != CatEnd; ++Cat) {
+ if (SM.isBeforeInTranslationUnit(Loc, Cat->getLocation()))
+ CollectOverriddenMethodsRecurse(*Cat, Method, Methods, true);
+ }
+
collectOnCategoriesAfterLocation(Loc, Class->getSuperClass(), SM,
Method, Methods);
}
@@ -924,6 +1036,11 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const {
if (isPropertyAccessor()) {
const ObjCContainerDecl *Container = cast<ObjCContainerDecl>(getParent());
+ // If container is class extension, find its primary class.
+ if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(Container))
+ if (CatDecl->IsClassExtension())
+ Container = CatDecl->getClassInterface();
+
bool IsGetter = (NumArgs == 0);
for (ObjCContainerDecl::prop_iterator I = Container->prop_begin(),
@@ -967,6 +1084,7 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::Create(const ASTContext &C,
bool isInternal){
ObjCInterfaceDecl *Result = new (C) ObjCInterfaceDecl(DC, atLoc, Id, ClassLoc,
PrevDecl, isInternal);
+ Result->Data.setInt(!C.getLangOpts().Modules);
C.getObjCInterfaceType(Result, PrevDecl);
return Result;
}
@@ -974,8 +1092,11 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::Create(const ASTContext &C,
ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCInterfaceDecl));
- return new (Mem) ObjCInterfaceDecl(0, SourceLocation(), 0, SourceLocation(),
- 0, false);
+ ObjCInterfaceDecl *Result = new (Mem) ObjCInterfaceDecl(0, SourceLocation(),
+ 0, SourceLocation(),
+ 0, false);
+ Result->Data.setInt(!C.getLangOpts().Modules);
+ return Result;
}
ObjCInterfaceDecl::
@@ -1026,49 +1147,96 @@ void ObjCInterfaceDecl::setImplementation(ObjCImplementationDecl *ImplD) {
getASTContext().setObjCImplementation(getDefinition(), ImplD);
}
+namespace {
+ struct SynthesizeIvarChunk {
+ uint64_t Size;
+ ObjCIvarDecl *Ivar;
+ SynthesizeIvarChunk(uint64_t size, ObjCIvarDecl *ivar)
+ : Size(size), Ivar(ivar) {}
+ };
+
+ bool operator<(const SynthesizeIvarChunk & LHS,
+ const SynthesizeIvarChunk &RHS) {
+ return LHS.Size < RHS.Size;
+ }
+}
+
/// all_declared_ivar_begin - return first ivar declared in this class,
/// its extensions and its implementation. Lazily build the list on first
/// access.
+///
+/// Caveat: The list returned by this method reflects the current
+/// state of the parser. The cache will be updated for every ivar
+/// added by an extension or the implementation when they are
+/// encountered.
+/// See also ObjCIvarDecl::Create().
ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() {
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return 0;
- if (data().IvarList)
- return data().IvarList;
-
ObjCIvarDecl *curIvar = 0;
- if (!ivar_empty()) {
- ObjCInterfaceDecl::ivar_iterator I = ivar_begin(), E = ivar_end();
- data().IvarList = *I; ++I;
- for (curIvar = data().IvarList; I != E; curIvar = *I, ++I)
- curIvar->setNextIvar(*I);
- }
-
- for (const ObjCCategoryDecl *CDecl = getFirstClassExtension(); CDecl;
- CDecl = CDecl->getNextClassExtension()) {
- if (!CDecl->ivar_empty()) {
- ObjCCategoryDecl::ivar_iterator I = CDecl->ivar_begin(),
- E = CDecl->ivar_end();
- if (!data().IvarList) {
- data().IvarList = *I; ++I;
- curIvar = data().IvarList;
- }
- for ( ;I != E; curIvar = *I, ++I)
+ if (!data().IvarList) {
+ if (!ivar_empty()) {
+ ObjCInterfaceDecl::ivar_iterator I = ivar_begin(), E = ivar_end();
+ data().IvarList = *I; ++I;
+ for (curIvar = data().IvarList; I != E; curIvar = *I, ++I)
curIvar->setNextIvar(*I);
}
+
+ for (ObjCInterfaceDecl::known_extensions_iterator
+ Ext = known_extensions_begin(),
+ ExtEnd = known_extensions_end();
+ Ext != ExtEnd; ++Ext) {
+ if (!Ext->ivar_empty()) {
+ ObjCCategoryDecl::ivar_iterator
+ I = Ext->ivar_begin(),
+ E = Ext->ivar_end();
+ if (!data().IvarList) {
+ data().IvarList = *I; ++I;
+ curIvar = data().IvarList;
+ }
+ for ( ;I != E; curIvar = *I, ++I)
+ curIvar->setNextIvar(*I);
+ }
+ }
+ data().IvarListMissingImplementation = true;
}
+
+ // cached and complete!
+ if (!data().IvarListMissingImplementation)
+ return data().IvarList;
if (ObjCImplementationDecl *ImplDecl = getImplementation()) {
+ data().IvarListMissingImplementation = false;
if (!ImplDecl->ivar_empty()) {
- ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(),
- E = ImplDecl->ivar_end();
- if (!data().IvarList) {
- data().IvarList = *I; ++I;
- curIvar = data().IvarList;
+ SmallVector<SynthesizeIvarChunk, 16> layout;
+ for (ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(),
+ E = ImplDecl->ivar_end(); I != E; ++I) {
+ ObjCIvarDecl *IV = *I;
+ if (IV->getSynthesize() && !IV->isInvalidDecl()) {
+ layout.push_back(SynthesizeIvarChunk(
+ IV->getASTContext().getTypeSize(IV->getType()), IV));
+ continue;
+ }
+ if (!data().IvarList)
+ data().IvarList = *I;
+ else
+ curIvar->setNextIvar(*I);
+ curIvar = *I;
+ }
+
+ if (!layout.empty()) {
+ // Order synthesized ivars by their size.
+ std::stable_sort(layout.begin(), layout.end());
+ unsigned Ix = 0, EIx = layout.size();
+ if (!data().IvarList) {
+ data().IvarList = layout[0].Ivar; Ix++;
+ curIvar = data().IvarList;
+ }
+ for ( ; Ix != EIx; curIvar = layout[Ix].Ivar, Ix++)
+ curIvar->setNextIvar(layout[Ix].Ivar);
}
- for ( ;I != E; curIvar = *I, ++I)
- curIvar->setNextIvar(*I);
}
}
return data().IvarList;
@@ -1087,29 +1255,41 @@ ObjCInterfaceDecl::FindCategoryDeclaration(IdentifierInfo *CategoryId) const {
if (data().ExternallyCompleted)
LoadExternalDefinition();
- for (ObjCCategoryDecl *Category = getCategoryList();
- Category; Category = Category->getNextClassCategory())
- if (Category->getIdentifier() == CategoryId)
- return Category;
+ for (visible_categories_iterator Cat = visible_categories_begin(),
+ CatEnd = visible_categories_end();
+ Cat != CatEnd;
+ ++Cat) {
+ if (Cat->getIdentifier() == CategoryId)
+ return *Cat;
+ }
+
return 0;
}
ObjCMethodDecl *
ObjCInterfaceDecl::getCategoryInstanceMethod(Selector Sel) const {
- for (ObjCCategoryDecl *Category = getCategoryList();
- Category; Category = Category->getNextClassCategory())
- if (ObjCCategoryImplDecl *Impl = Category->getImplementation())
+ for (visible_categories_iterator Cat = visible_categories_begin(),
+ CatEnd = visible_categories_end();
+ Cat != CatEnd;
+ ++Cat) {
+ if (ObjCCategoryImplDecl *Impl = Cat->getImplementation())
if (ObjCMethodDecl *MD = Impl->getInstanceMethod(Sel))
return MD;
+ }
+
return 0;
}
ObjCMethodDecl *ObjCInterfaceDecl::getCategoryClassMethod(Selector Sel) const {
- for (ObjCCategoryDecl *Category = getCategoryList();
- Category; Category = Category->getNextClassCategory())
- if (ObjCCategoryImplDecl *Impl = Category->getImplementation())
+ for (visible_categories_iterator Cat = visible_categories_begin(),
+ CatEnd = visible_categories_end();
+ Cat != CatEnd;
+ ++Cat) {
+ if (ObjCCategoryImplDecl *Impl = Cat->getImplementation())
if (ObjCMethodDecl *MD = Impl->getClassMethod(Sel))
return MD;
+ }
+
return 0;
}
@@ -1141,10 +1321,13 @@ bool ObjCInterfaceDecl::ClassImplementsProtocol(ObjCProtocolDecl *lProto,
// 2nd, look up the category.
if (lookupCategory)
- for (ObjCCategoryDecl *CDecl = IDecl->getCategoryList(); CDecl;
- CDecl = CDecl->getNextClassCategory()) {
- for (ObjCCategoryDecl::protocol_iterator PI = CDecl->protocol_begin(),
- E = CDecl->protocol_end(); PI != E; ++PI)
+ for (visible_categories_iterator Cat = visible_categories_begin(),
+ CatEnd = visible_categories_end();
+ Cat != CatEnd;
+ ++Cat) {
+ for (ObjCCategoryDecl::protocol_iterator PI = Cat->protocol_begin(),
+ E = Cat->protocol_end();
+ PI != E; ++PI)
if (getASTContext().ProtocolCompatibleWithProtocol(lProto, *PI))
return true;
}
@@ -1274,15 +1457,17 @@ ObjCProtocolDecl *ObjCProtocolDecl::Create(ASTContext &C, DeclContext *DC,
ObjCProtocolDecl *PrevDecl) {
ObjCProtocolDecl *Result
= new (C) ObjCProtocolDecl(DC, Id, nameLoc, atStartLoc, PrevDecl);
-
+ Result->Data.setInt(!C.getLangOpts().Modules);
return Result;
}
ObjCProtocolDecl *ObjCProtocolDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCProtocolDecl));
- return new (Mem) ObjCProtocolDecl(0, 0, SourceLocation(), SourceLocation(),
- 0);
+ ObjCProtocolDecl *Result = new (Mem) ObjCProtocolDecl(0, 0, SourceLocation(),
+ SourceLocation(), 0);
+ Result->Data.setInt(!C.getLangOpts().Modules);
+ return Result;
}
ObjCProtocolDecl *ObjCProtocolDecl::lookupProtocolNamed(IdentifierInfo *Name) {
@@ -1304,6 +1489,12 @@ ObjCMethodDecl *ObjCProtocolDecl::lookupMethod(Selector Sel,
bool isInstance) const {
ObjCMethodDecl *MethodDecl = NULL;
+ // If there is no definition or the definition is hidden, we don't find
+ // anything.
+ const ObjCProtocolDecl *Def = getDefinition();
+ if (!Def || Def->isHidden())
+ return NULL;
+
if ((MethodDecl = getMethod(Sel, isInstance)))
return MethodDecl;
@@ -1314,9 +1505,9 @@ ObjCMethodDecl *ObjCProtocolDecl::lookupMethod(Selector Sel,
}
void ObjCProtocolDecl::allocateDefinitionData() {
- assert(!Data && "Protocol already has a definition!");
- Data = new (getASTContext()) DefinitionData;
- Data->Definition = this;
+ assert(!Data.getPointer() && "Protocol already has a definition!");
+ Data.setPointer(new (getASTContext()) DefinitionData);
+ Data.getPointer()->Definition = this;
}
void ObjCProtocolDecl::startDefinition() {
@@ -1328,17 +1519,22 @@ void ObjCProtocolDecl::startDefinition() {
RD->Data = this->Data;
}
-void ObjCProtocolDecl::collectPropertiesToImplement(PropertyMap &PM) const {
- for (ObjCProtocolDecl::prop_iterator P = prop_begin(),
- E = prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = *P;
- // Insert into PM if not there already.
- PM.insert(std::make_pair(Prop->getIdentifier(), Prop));
+void ObjCProtocolDecl::collectPropertiesToImplement(PropertyMap &PM,
+ PropertyDeclOrder &PO) const {
+
+ if (const ObjCProtocolDecl *PDecl = getDefinition()) {
+ for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
+ E = PDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = *P;
+ // Insert into PM if not there already.
+ PM.insert(std::make_pair(Prop->getIdentifier(), Prop));
+ PO.push_back(Prop);
+ }
+ // Scan through protocol's protocols.
+ for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
+ E = PDecl->protocol_end(); PI != E; ++PI)
+ (*PI)->collectPropertiesToImplement(PM, PO);
}
- // Scan through protocol's protocols.
- for (ObjCProtocolDecl::protocol_iterator PI = protocol_begin(),
- E = protocol_end(); PI != E; ++PI)
- (*PI)->collectPropertiesToImplement(PM);
}
@@ -1362,9 +1558,9 @@ ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC,
IvarLBraceLoc, IvarRBraceLoc);
if (IDecl) {
// Link this category into its class's category list.
- CatDecl->NextClassCategory = IDecl->getCategoryList();
+ CatDecl->NextClassCategory = IDecl->getCategoryListRaw();
if (IDecl->hasDefinition()) {
- IDecl->setCategoryList(CatDecl);
+ IDecl->setCategoryListRaw(CatDecl);
if (ASTMutationListener *L = C.getASTMutationListener())
L->AddedObjCCategoryToInterface(CatDecl, IDecl);
}
@@ -1450,7 +1646,7 @@ void ObjCImplDecl::setClassInterface(ObjCInterfaceDecl *IFace) {
}
/// FindPropertyImplIvarDecl - This method lookup the ivar in the list of
-/// properties implemented in this category \@implementation block and returns
+/// properties implemented in this \@implementation block and returns
/// the implemented property that uses it.
///
ObjCPropertyImplDecl *ObjCImplDecl::
diff --git a/lib/AST/DeclOpenMP.cpp b/lib/AST/DeclOpenMP.cpp
new file mode 100644
index 0000000..c0d10a0
--- /dev/null
+++ b/lib/AST/DeclOpenMP.cpp
@@ -0,0 +1,60 @@
+//===--- DeclOpenMP.cpp - Declaration OpenMP AST Node Implementation ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// \brief This file implements OMPThreadPrivateDecl class.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclOpenMP.h"
+#include "clang/AST/Expr.h"
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// OMPThreadPrivateDecl Implementation.
+//===----------------------------------------------------------------------===//
+
+void OMPThreadPrivateDecl::anchor() { }
+
+OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C,
+ DeclContext *DC,
+ SourceLocation L,
+ ArrayRef<DeclRefExpr *> VL) {
+ unsigned Size = sizeof(OMPThreadPrivateDecl) +
+ (VL.size() * sizeof(DeclRefExpr *));
+
+ void *Mem = C.Allocate(Size, llvm::alignOf<OMPThreadPrivateDecl>());
+ OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate,
+ DC, L);
+ D->NumVars = VL.size();
+ D->setVars(VL);
+ return D;
+}
+
+OMPThreadPrivateDecl *OMPThreadPrivateDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID,
+ unsigned N) {
+ unsigned Size = sizeof(OMPThreadPrivateDecl) + (N * sizeof(DeclRefExpr *));
+
+ void *Mem = AllocateDeserializedDecl(C, ID, Size);
+ OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate,
+ 0, SourceLocation());
+ D->NumVars = N;
+ return D;
+}
+
+void OMPThreadPrivateDecl::setVars(ArrayRef<DeclRefExpr *> VL) {
+ assert(VL.size() == NumVars &&
+ "Number of variables is not the same as the preallocated buffer");
+ DeclRefExpr **Vars = reinterpret_cast<DeclRefExpr **>(this + 1);
+ std::copy(VL.begin(), VL.end(), Vars);
+}
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 386ad66..c3bf8f8 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -7,15 +7,16 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements the Decl::dump method, which pretty print the
+// This file implements the Decl::print method, which pretty prints the
// AST back out to C/Objective-C/C++/Objective-C++ code.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclVisitor.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/PrettyPrinter.h"
@@ -50,7 +51,9 @@ namespace {
void VisitEnumDecl(EnumDecl *D);
void VisitRecordDecl(RecordDecl *D);
void VisitEnumConstantDecl(EnumConstantDecl *D);
+ void VisitEmptyDecl(EmptyDecl *D);
void VisitFunctionDecl(FunctionDecl *D);
+ void VisitFriendDecl(FriendDecl *D);
void VisitFieldDecl(FieldDecl *D);
void VisitVarDecl(VarDecl *D);
void VisitLabelDecl(LabelDecl *D);
@@ -79,9 +82,10 @@ namespace {
void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
void VisitUsingDecl(UsingDecl *D);
void VisitUsingShadowDecl(UsingShadowDecl *D);
+ void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
void PrintTemplateParameters(const TemplateParameterList *Params,
- const TemplateArgumentList *Args);
+ const TemplateArgumentList *Args = 0);
void prettyPrintAttributes(Decl *D);
};
}
@@ -174,16 +178,6 @@ void DeclContext::dumpDeclContext() const {
Printer.VisitDeclContext(const_cast<DeclContext *>(this), /*Indent=*/false);
}
-void Decl::dump() const {
- dump(llvm::errs());
-}
-
-void Decl::dump(raw_ostream &Out) const {
- PrintingPolicy Policy = getASTContext().getPrintingPolicy();
- Policy.DumpSourceManager = &getASTContext().getSourceManager();
- print(Out, Policy, /*Indentation*/ 0, /*PrintInstantiation*/ true);
-}
-
raw_ostream& DeclPrinter::Indent(unsigned Indentation) {
for (unsigned i = 0; i != Indentation; ++i)
Out << " ";
@@ -191,7 +185,7 @@ raw_ostream& DeclPrinter::Indent(unsigned Indentation) {
}
void DeclPrinter::prettyPrintAttributes(Decl *D) {
- if (Policy.SuppressAttributes)
+ if (Policy.PolishForDeclaration)
return;
if (D->hasAttrs()) {
@@ -240,18 +234,18 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
if (isa<ObjCIvarDecl>(*D))
continue;
- if (!Policy.DumpSourceManager) {
- // Skip over implicit declarations in pretty-printing mode.
- if (D->isImplicit()) continue;
- // FIXME: Ugly hack so we don't pretty-print the builtin declaration
- // of __builtin_va_list or __[u]int128_t. There should be some other way
- // to check that.
- if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) {
- if (IdentifierInfo *II = ND->getIdentifier()) {
- if (II->isStr("__builtin_va_list") ||
- II->isStr("__int128_t") || II->isStr("__uint128_t"))
- continue;
- }
+ // Skip over implicit declarations in pretty-printing mode.
+ if (D->isImplicit())
+ continue;
+
+ // FIXME: Ugly hack so we don't pretty-print the builtin declaration
+ // of __builtin_va_list or __[u]int128_t. There should be some other way
+ // to check that.
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) {
+ if (IdentifierInfo *II = ND->getIdentifier()) {
+ if (II->isStr("__builtin_va_list") ||
+ II->isStr("__int128_t") || II->isStr("__uint128_t"))
+ continue;
}
}
@@ -298,8 +292,10 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
// FIXME: Need to be able to tell the DeclPrinter when
const char *Terminator = 0;
- if (isa<FunctionDecl>(*D) &&
- cast<FunctionDecl>(*D)->isThisDeclarationADefinition())
+ if (isa<OMPThreadPrivateDecl>(*D))
+ Terminator = 0;
+ else if (isa<FunctionDecl>(*D) &&
+ cast<FunctionDecl>(*D)->isThisDeclarationADefinition())
Terminator = 0;
else if (isa<ObjCMethodDecl>(*D) && cast<ObjCMethodDecl>(*D)->getBody())
Terminator = 0;
@@ -395,8 +391,9 @@ void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) {
}
void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
+ CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D);
if (!Policy.SuppressSpecifiers) {
- switch (D->getStorageClassAsWritten()) {
+ switch (D->getStorageClass()) {
case SC_None: break;
case SC_Extern: Out << "extern "; break;
case SC_Static: Out << "static "; break;
@@ -408,6 +405,8 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (D->isInlineSpecified()) Out << "inline ";
if (D->isVirtualAsWritten()) Out << "virtual ";
if (D->isModulePrivate()) Out << "__module_private__ ";
+ if (CDecl && CDecl->isExplicitSpecified())
+ Out << "explicit ";
}
PrintingPolicy SubPolicy(Policy);
@@ -483,7 +482,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
}
}
- if (CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D)) {
+ if (CDecl) {
bool HasInitializerList = false;
for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(),
E = CDecl->init_end();
@@ -545,9 +544,15 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
}
Out << ")";
}
- }
- else
+ if (!Proto.empty())
+ Out << Proto;
+ } else {
+ if (FT && FT->hasTrailingReturn()) {
+ Out << "auto " << Proto << " -> ";
+ Proto.clear();
+ }
AFT->getResultType().print(Out, Policy, Proto);
+ }
} else {
Ty.print(Out, Policy, Proto);
}
@@ -558,6 +563,8 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
Out << " = 0";
else if (D->isDeletedAsWritten())
Out << " = delete";
+ else if (D->isExplicitlyDefaulted())
+ Out << " = default";
else if (D->doesThisDeclarationHaveABody() && !Policy.TerseOutput) {
if (!D->hasPrototype() && D->getNumParams()) {
// This is a K&R function definition, so we need to print the
@@ -579,6 +586,31 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
}
}
+void DeclPrinter::VisitFriendDecl(FriendDecl *D) {
+ if (TypeSourceInfo *TSI = D->getFriendType()) {
+ unsigned NumTPLists = D->getFriendTypeNumTemplateParameterLists();
+ for (unsigned i = 0; i < NumTPLists; ++i)
+ PrintTemplateParameters(D->getFriendTypeTemplateParameterList(i));
+ Out << "friend ";
+ Out << " " << TSI->getType().getAsString(Policy);
+ }
+ else if (FunctionDecl *FD =
+ dyn_cast<FunctionDecl>(D->getFriendDecl())) {
+ Out << "friend ";
+ VisitFunctionDecl(FD);
+ }
+ else if (FunctionTemplateDecl *FTD =
+ dyn_cast<FunctionTemplateDecl>(D->getFriendDecl())) {
+ Out << "friend ";
+ VisitFunctionTemplateDecl(FTD);
+ }
+ else if (ClassTemplateDecl *CTD =
+ dyn_cast<ClassTemplateDecl>(D->getFriendDecl())) {
+ Out << "friend ";
+ VisitRedeclarableTemplateDecl(CTD);
+ }
+}
+
void DeclPrinter::VisitFieldDecl(FieldDecl *D) {
if (!Policy.SuppressSpecifiers && D->isMutable())
Out << "mutable ";
@@ -609,9 +641,9 @@ void DeclPrinter::VisitLabelDecl(LabelDecl *D) {
void DeclPrinter::VisitVarDecl(VarDecl *D) {
- StorageClass SCAsWritten = D->getStorageClassAsWritten();
- if (!Policy.SuppressSpecifiers && SCAsWritten != SC_None)
- Out << VarDecl::getStorageClassSpecifierString(SCAsWritten) << " ";
+ StorageClass SC = D->getStorageClass();
+ if (!Policy.SuppressSpecifiers && SC != SC_None)
+ Out << VarDecl::getStorageClassSpecifierString(SC) << " ";
if (!Policy.SuppressSpecifiers && D->isThreadSpecified())
Out << "__thread ";
@@ -625,9 +657,14 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
Expr *Init = D->getInit();
if (!Policy.SuppressInitializers && Init) {
bool ImplicitInit = false;
- if (CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(Init))
- ImplicitInit = D->getInitStyle() == VarDecl::CallInit &&
- Construct->getNumArgs() == 0 && !Construct->isListInitialization();
+ if (CXXConstructExpr *Construct =
+ dyn_cast<CXXConstructExpr>(Init->IgnoreImplicit())) {
+ if (D->getInitStyle() == VarDecl::CallInit &&
+ !Construct->isListInitialization()) {
+ ImplicitInit = Construct->getNumArgs() == 0 ||
+ Construct->getArg(0)->isDefaultArgument();
+ }
+ }
if (!ImplicitInit) {
if ((D->getInitStyle() == VarDecl::CallInit) && !isa<ParenListExpr>(Init))
Out << "(";
@@ -653,7 +690,7 @@ void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
}
void DeclPrinter::VisitImportDecl(ImportDecl *D) {
- Out << "@__experimental_modules_import " << D->getImportedModule()->getFullModuleName()
+ Out << "@import " << D->getImportedModule()->getFullModuleName()
<< ";\n";
}
@@ -690,6 +727,10 @@ void DeclPrinter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
Out << *D->getAliasedNamespace();
}
+void DeclPrinter::VisitEmptyDecl(EmptyDecl *D) {
+ prettyPrintAttributes(D);
+}
+
void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
if (!Policy.SuppressSpecifiers && D->isModulePrivate())
Out << "__module_private__ ";
@@ -746,8 +787,8 @@ void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
Visit(*D->decls_begin());
}
-void DeclPrinter::PrintTemplateParameters(
- const TemplateParameterList *Params, const TemplateArgumentList *Args = 0) {
+void DeclPrinter::PrintTemplateParameters(const TemplateParameterList *Params,
+ const TemplateArgumentList *Args) {
assert(Params);
assert(!Args || Params->size() == Args->size());
@@ -882,6 +923,8 @@ void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
OMD->getBody()->printPretty(Out, 0, Policy);
Out << '\n';
}
+ else if (Policy.PolishForDeclaration)
+ Out << ';';
}
void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) {
@@ -892,7 +935,17 @@ void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) {
Out << "@implementation " << I << " : " << *SID;
else
Out << "@implementation " << I;
- Out << "\n";
+
+ if (OID->ivar_size() > 0) {
+ Out << "{\n";
+ Indentation += Policy.Indentation;
+ for (ObjCImplementationDecl::ivar_iterator I = OID->ivar_begin(),
+ E = OID->ivar_end(); I != E; ++I) {
+ Indent() << I->getType().getAsString(Policy) << ' ' << **I << ";\n";
+ }
+ Indentation -= Policy.Indentation;
+ Out << "}\n";
+ }
VisitDeclContext(OID, false);
Out << "@end";
}
@@ -905,7 +958,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
Out << "@class " << I << ";";
return;
}
-
+ bool eolnOut = false;
if (SID)
Out << "@interface " << I << " : " << *SID;
else
@@ -917,13 +970,12 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
E = Protocols.end(); I != E; ++I)
Out << (I == Protocols.begin() ? '<' : ',') << **I;
- }
-
- if (!Protocols.empty())
Out << "> ";
+ }
if (OID->ivar_size() > 0) {
Out << "{\n";
+ eolnOut = true;
Indentation += Policy.Indentation;
for (ObjCInterfaceDecl::ivar_iterator I = OID->ivar_begin(),
E = OID->ivar_end(); I != E; ++I) {
@@ -932,19 +984,33 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
Indentation -= Policy.Indentation;
Out << "}\n";
}
+ else if (SID) {
+ Out << "\n";
+ eolnOut = true;
+ }
VisitDeclContext(OID, false);
+ if (!eolnOut)
+ Out << ' ';
Out << "@end";
// FIXME: implement the rest...
}
void DeclPrinter::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) {
if (!PID->isThisDeclarationADefinition()) {
- Out << "@protocol " << PID->getIdentifier() << ";\n";
+ Out << "@protocol " << *PID << ";\n";
return;
}
-
- Out << "@protocol " << *PID << '\n';
+ // Protocols?
+ const ObjCList<ObjCProtocolDecl> &Protocols = PID->getReferencedProtocols();
+ if (!Protocols.empty()) {
+ Out << "@protocol " << *PID;
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
+ E = Protocols.end(); I != E; ++I)
+ Out << (I == Protocols.begin() ? '<' : ',') << **I;
+ Out << ">\n";
+ } else
+ Out << "@protocol " << *PID << '\n';
VisitDeclContext(PID, false);
Out << "@end";
}
@@ -959,6 +1025,17 @@ void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) {
void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) {
Out << "@interface " << *PID->getClassInterface() << '(' << *PID << ")\n";
+ if (PID->ivar_size() > 0) {
+ Out << "{\n";
+ Indentation += Policy.Indentation;
+ for (ObjCCategoryDecl::ivar_iterator I = PID->ivar_begin(),
+ E = PID->ivar_end(); I != E; ++I) {
+ Indent() << I->getType().getAsString(Policy) << ' ' << **I << ";\n";
+ }
+ Indentation -= Policy.Indentation;
+ Out << "}\n";
+ }
+
VisitDeclContext(PID, false);
Out << "@end";
@@ -1040,6 +1117,8 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) {
Out << " )";
}
Out << ' ' << PDecl->getType().getAsString(Policy) << ' ' << *PDecl;
+ if (Policy.PolishForDeclaration)
+ Out << ';';
}
void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) {
@@ -1068,9 +1147,23 @@ DeclPrinter::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
void DeclPrinter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
Out << "using ";
D->getQualifier()->print(Out, Policy);
- Out << D->getDeclName();
+ Out << D->getName();
}
void DeclPrinter::VisitUsingShadowDecl(UsingShadowDecl *D) {
// ignore
}
+
+void DeclPrinter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
+ Out << "#pragma omp threadprivate";
+ if (!D->varlist_empty()) {
+ for (OMPThreadPrivateDecl::varlist_iterator I = D->varlist_begin(),
+ E = D->varlist_end();
+ I != E; ++I) {
+ Out << (I == D->varlist_begin() ? '(' : ',')
+ << *cast<NamedDecl>((*I)->getDecl());
+ }
+ Out << ")";
+ }
+}
+
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index a70983f..0b94f7d 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -11,13 +11,13 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
-#include "clang/AST/ASTContext.h"
#include "clang/AST/TypeLoc.h"
-#include "clang/AST/ASTMutationListener.h"
#include "clang/Basic/IdentifierTable.h"
#include "llvm/ADT/STLExtras.h"
#include <memory>
@@ -128,12 +128,12 @@ static void AdoptTemplateParameterList(TemplateParameterList *Params,
// RedeclarableTemplateDecl Implementation
//===----------------------------------------------------------------------===//
-RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() {
+RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() const {
if (!Common) {
// Walk the previous-declaration chain until we either find a declaration
// with a common pointer or we run out of previous declarations.
- llvm::SmallVector<RedeclarableTemplateDecl *, 2> PrevDecls;
- for (RedeclarableTemplateDecl *Prev = getPreviousDecl(); Prev;
+ SmallVector<const RedeclarableTemplateDecl *, 2> PrevDecls;
+ for (const RedeclarableTemplateDecl *Prev = getPreviousDecl(); Prev;
Prev = Prev->getPreviousDecl()) {
if (Prev->Common) {
Common = Prev->Common;
@@ -184,9 +184,8 @@ static void GenerateInjectedTemplateArgs(ASTContext &Context,
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
QualType ArgType = Context.getTypeDeclType(TTP);
if (TTP->isParameterPack())
- ArgType = Context.getPackExpansionType(ArgType,
- llvm::Optional<unsigned>());
-
+ ArgType = Context.getPackExpansionType(ArgType, None);
+
Arg = TemplateArgument(ArgType);
} else if (NonTypeTemplateParmDecl *NTTP =
dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
@@ -197,13 +196,12 @@ static void GenerateInjectedTemplateArgs(ASTContext &Context,
if (NTTP->isParameterPack())
E = new (Context) PackExpansionExpr(Context.DependentTy, E,
- NTTP->getLocation(),
- llvm::Optional<unsigned>());
+ NTTP->getLocation(), None);
Arg = TemplateArgument(E);
} else {
TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param);
if (TTP->isParameterPack())
- Arg = TemplateArgument(TemplateName(TTP), llvm::Optional<unsigned>());
+ Arg = TemplateArgument(TemplateName(TTP), Optional<unsigned>());
else
Arg = TemplateArgument(TemplateName(TTP));
}
@@ -241,7 +239,7 @@ FunctionTemplateDecl *FunctionTemplateDecl::CreateDeserialized(ASTContext &C,
}
RedeclarableTemplateDecl::CommonBase *
-FunctionTemplateDecl::newCommon(ASTContext &C) {
+FunctionTemplateDecl::newCommon(ASTContext &C) const {
Common *CommonPtr = new (C) Common;
C.AddDeallocation(DeallocateCommon, CommonPtr);
return CommonPtr;
@@ -304,7 +302,7 @@ ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C,
return new (Mem) ClassTemplateDecl(EmptyShell());
}
-void ClassTemplateDecl::LoadLazySpecializations() {
+void ClassTemplateDecl::LoadLazySpecializations() const {
Common *CommonPtr = getCommonPtr();
if (CommonPtr->LazySpecializations) {
ASTContext &Context = getASTContext();
@@ -316,7 +314,7 @@ void ClassTemplateDecl::LoadLazySpecializations() {
}
llvm::FoldingSetVector<ClassTemplateSpecializationDecl> &
-ClassTemplateDecl::getSpecializations() {
+ClassTemplateDecl::getSpecializations() const {
LoadLazySpecializations();
return getCommonPtr()->Specializations;
}
@@ -328,7 +326,7 @@ ClassTemplateDecl::getPartialSpecializations() {
}
RedeclarableTemplateDecl::CommonBase *
-ClassTemplateDecl::newCommon(ASTContext &C) {
+ClassTemplateDecl::newCommon(ASTContext &C) const {
Common *CommonPtr = new (C) Common;
C.AddDeallocation(DeallocateCommon, CommonPtr);
return CommonPtr;
@@ -620,7 +618,7 @@ TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D, unsigned P,
IdentifierInfo *Id,
TemplateParameterList *Params,
- llvm::ArrayRef<TemplateParameterList*> Expansions) {
+ ArrayRef<TemplateParameterList *> Expansions) {
void *Mem = C.Allocate(sizeof(TemplateTemplateParmDecl) +
sizeof(TemplateParameterList*) * Expansions.size());
return new (Mem) TemplateTemplateParmDecl(DC, L, D, P, Id, Params,
@@ -728,6 +726,8 @@ ClassTemplateSpecializationDecl::Create(ASTContext &Context, TagKind TK,
SpecializedTemplate,
Args, NumArgs,
PrevDecl);
+ Result->MayHaveOutOfDateDef = false;
+
Context.getTypeDeclType(Result, PrevDecl);
return Result;
}
@@ -737,20 +737,19 @@ ClassTemplateSpecializationDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID,
sizeof(ClassTemplateSpecializationDecl));
- return new (Mem) ClassTemplateSpecializationDecl(ClassTemplateSpecialization);
+ ClassTemplateSpecializationDecl *Result =
+ new (Mem) ClassTemplateSpecializationDecl(ClassTemplateSpecialization);
+ Result->MayHaveOutOfDateDef = false;
+ return Result;
}
-void
-ClassTemplateSpecializationDecl::getNameForDiagnostic(std::string &S,
- const PrintingPolicy &Policy,
- bool Qualified) const {
- NamedDecl::getNameForDiagnostic(S, Policy, Qualified);
+void ClassTemplateSpecializationDecl::getNameForDiagnostic(
+ raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const {
+ NamedDecl::getNameForDiagnostic(OS, Policy, Qualified);
const TemplateArgumentList &TemplateArgs = getTemplateArgs();
- S += TemplateSpecializationType::PrintTemplateArgumentList(
- TemplateArgs.data(),
- TemplateArgs.size(),
- Policy);
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, TemplateArgs.data(), TemplateArgs.size(), Policy);
}
ClassTemplateDecl *
@@ -857,6 +856,7 @@ Create(ASTContext &Context, TagKind TK,DeclContext *DC,
PrevDecl,
SequenceNumber);
Result->setSpecializationKind(TSK_ExplicitSpecialization);
+ Result->MayHaveOutOfDateDef = false;
Context.getInjectedClassNameType(Result, CanonInjectedType);
return Result;
@@ -867,7 +867,10 @@ ClassTemplatePartialSpecializationDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID,
sizeof(ClassTemplatePartialSpecializationDecl));
- return new (Mem) ClassTemplatePartialSpecializationDecl();
+ ClassTemplatePartialSpecializationDecl *Result
+ = new (Mem) ClassTemplatePartialSpecializationDecl();
+ Result->MayHaveOutOfDateDef = false;
+ return Result;
}
//===----------------------------------------------------------------------===//
@@ -919,7 +922,7 @@ void TypeAliasTemplateDecl::DeallocateCommon(void *Ptr) {
static_cast<Common *>(Ptr)->~Common();
}
RedeclarableTemplateDecl::CommonBase *
-TypeAliasTemplateDecl::newCommon(ASTContext &C) {
+TypeAliasTemplateDecl::newCommon(ASTContext &C) const {
Common *CommonPtr = new (C) Common;
C.AddDeallocation(DeallocateCommon, CommonPtr);
return CommonPtr;
diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
index 28188d9..e4a41b6 100644
--- a/lib/AST/DeclarationName.cpp
+++ b/lib/AST/DeclarationName.cpp
@@ -364,6 +364,21 @@ DeclarationNameTable::~DeclarationNameTable() {
delete LiteralNames;
}
+DeclarationName DeclarationNameTable::getCXXConstructorName(CanQualType Ty) {
+ return getCXXSpecialName(DeclarationName::CXXConstructorName,
+ Ty.getUnqualifiedType());
+}
+
+DeclarationName DeclarationNameTable::getCXXDestructorName(CanQualType Ty) {
+ return getCXXSpecialName(DeclarationName::CXXDestructorName,
+ Ty.getUnqualifiedType());
+}
+
+DeclarationName
+DeclarationNameTable::getCXXConversionFunctionName(CanQualType Ty) {
+ return getCXXSpecialName(DeclarationName::CXXConversionFunctionName, Ty);
+}
+
DeclarationName
DeclarationNameTable::getCXXSpecialName(DeclarationName::NameKind Kind,
CanQualType Ty) {
diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp
index 5f43fbc..be22ae4 100644
--- a/lib/AST/DumpXML.cpp
+++ b/lib/AST/DumpXML.cpp
@@ -17,6 +17,7 @@
// Only pay for this in code size in assertions-enabled builds.
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclFriend.h"
@@ -37,8 +38,6 @@
#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeLocVisitor.h"
#include "clang/AST/TypeVisitor.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/ExprCXX.h"
#include "llvm/ADT/SmallString.h"
using namespace clang;
@@ -500,8 +499,8 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
for (FunctionDecl::param_iterator
I = D->param_begin(), E = D->param_end(); I != E; ++I)
dispatch(*I);
- for (llvm::ArrayRef<NamedDecl*>::iterator
- I = D->getDeclsInPrototypeScope().begin(), E = D->getDeclsInPrototypeScope().end();
+ for (ArrayRef<NamedDecl *>::iterator I = D->getDeclsInPrototypeScope().begin(),
+ E = D->getDeclsInPrototypeScope().end();
I != E; ++I)
dispatch(*I);
if (D->doesThisDeclarationHaveABody())
@@ -749,14 +748,6 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
visitDeclContext(D);
}
- // ObjCInterfaceDecl
- void visitCategoryList(ObjCCategoryDecl *D) {
- if (!D) return;
-
- TemporaryContainer C(*this, "categories");
- for (; D; D = D->getNextClassCategory())
- visitDeclRef(D);
- }
void visitObjCInterfaceDeclAttrs(ObjCInterfaceDecl *D) {
setPointer("typeptr", D->getTypeForDecl());
setFlag("forward_decl", !D->isThisDeclarationADefinition());
@@ -771,7 +762,17 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I)
visitDeclRef(*I);
}
- visitCategoryList(D->getCategoryList());
+
+ if (!D->visible_categories_empty()) {
+ TemporaryContainer C(*this, "categories");
+
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = D->visible_categories_begin(),
+ CatEnd = D->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
+ visitDeclRef(*Cat);
+ }
+ }
}
void visitObjCInterfaceDeclAsContext(ObjCInterfaceDecl *D) {
visitDeclContext(D);
@@ -923,6 +924,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
case CC_AAPCS: return set("cc", "aapcs");
case CC_AAPCS_VFP: return set("cc", "aapcs_vfp");
case CC_PnaclCall: return set("cc", "pnaclcall");
+ case CC_IntelOclBicc: return set("cc", "intel_ocl_bicc");
}
}
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index f3a2e05..b97f4d1 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -11,22 +11,24 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/AST/Expr.h"
-#include "clang/AST/ExprCXX.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/EvaluatedExprVisitor.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
-#include "clang/Lex/LiteralSupport.h"
-#include "clang/Lex/Lexer.h"
-#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Basic/Builtins.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/LiteralSupport.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
@@ -277,7 +279,7 @@ static void computeDeclRefDependence(ASTContext &Ctx, NamedDecl *D, QualType T,
// - an entity with reference type and is initialized with an
// expression that is value-dependent [C++11]
if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
- if ((Ctx.getLangOpts().CPlusPlus0x ?
+ if ((Ctx.getLangOpts().CPlusPlus11 ?
Var->getType()->isLiteralType() :
Var->getType()->isIntegralOrEnumerationType()) &&
(Var->getType().isConstQualified() ||
@@ -444,14 +446,6 @@ DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context,
return new (Mem) DeclRefExpr(EmptyShell());
}
-SourceRange DeclRefExpr::getSourceRange() const {
- SourceRange R = getNameInfo().getSourceRange();
- if (hasQualifier())
- R.setBegin(getQualifierLoc().getBeginLoc());
- if (hasExplicitTemplateArgs())
- R.setEnd(getRAngleLoc());
- return R;
-}
SourceLocation DeclRefExpr::getLocStart() const {
if (hasQualifier())
return getQualifierLoc().getBeginLoc();
@@ -483,8 +477,9 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
}
PrintingPolicy Policy(Context.getLangOpts());
- std::string Proto = FD->getQualifiedNameAsString(Policy);
+ std::string Proto;
llvm::raw_string_ostream POut(Proto);
+ FD->printQualifiedName(POut, Policy);
const FunctionDecl *Decl = FD;
if (const FunctionDecl* Pattern = FD->getTemplateInstantiationPattern())
@@ -509,7 +504,7 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
POut << ")";
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
- const FunctionType *FT = cast<FunctionType>(MD->getType().getTypePtr());
+ const FunctionType *FT = MD->getType()->castAs<FunctionType>();
if (FT->isConst())
POut << " const";
if (FT->isVolatile())
@@ -653,16 +648,14 @@ FloatingLiteral::FloatingLiteral(ASTContext &C, const llvm::APFloat &V,
bool isexact, QualType Type, SourceLocation L)
: Expr(FloatingLiteralClass, Type, VK_RValue, OK_Ordinary, false, false,
false, false), Loc(L) {
- FloatingLiteralBits.IsIEEE =
- &C.getTargetInfo().getLongDoubleFormat() == &llvm::APFloat::IEEEquad;
+ setSemantics(V.getSemantics());
FloatingLiteralBits.IsExact = isexact;
setValue(C, V);
}
FloatingLiteral::FloatingLiteral(ASTContext &C, EmptyShell Empty)
: Expr(FloatingLiteralClass, Empty) {
- FloatingLiteralBits.IsIEEE =
- &C.getTargetInfo().getLongDoubleFormat() == &llvm::APFloat::IEEEquad;
+ setRawSemantics(IEEEhalf);
FloatingLiteralBits.IsExact = false;
}
@@ -677,6 +670,41 @@ FloatingLiteral::Create(ASTContext &C, EmptyShell Empty) {
return new (C) FloatingLiteral(C, Empty);
}
+const llvm::fltSemantics &FloatingLiteral::getSemantics() const {
+ switch(FloatingLiteralBits.Semantics) {
+ case IEEEhalf:
+ return llvm::APFloat::IEEEhalf;
+ case IEEEsingle:
+ return llvm::APFloat::IEEEsingle;
+ case IEEEdouble:
+ return llvm::APFloat::IEEEdouble;
+ case x87DoubleExtended:
+ return llvm::APFloat::x87DoubleExtended;
+ case IEEEquad:
+ return llvm::APFloat::IEEEquad;
+ case PPCDoubleDouble:
+ return llvm::APFloat::PPCDoubleDouble;
+ }
+ llvm_unreachable("Unrecognised floating semantics");
+}
+
+void FloatingLiteral::setSemantics(const llvm::fltSemantics &Sem) {
+ if (&Sem == &llvm::APFloat::IEEEhalf)
+ FloatingLiteralBits.Semantics = IEEEhalf;
+ else if (&Sem == &llvm::APFloat::IEEEsingle)
+ FloatingLiteralBits.Semantics = IEEEsingle;
+ else if (&Sem == &llvm::APFloat::IEEEdouble)
+ FloatingLiteralBits.Semantics = IEEEdouble;
+ else if (&Sem == &llvm::APFloat::x87DoubleExtended)
+ FloatingLiteralBits.Semantics = x87DoubleExtended;
+ else if (&Sem == &llvm::APFloat::IEEEquad)
+ FloatingLiteralBits.Semantics = IEEEquad;
+ else if (&Sem == &llvm::APFloat::PPCDoubleDouble)
+ FloatingLiteralBits.Semantics = PPCDoubleDouble;
+ else
+ llvm_unreachable("Unknown floating semantics");
+}
+
/// getValueAsApproximateDouble - This returns the value as an inaccurate
/// double. Note that this may cause loss of precision, but is useful for
/// debugging dumps, etc.
@@ -745,7 +773,7 @@ StringLiteral *StringLiteral::CreateEmpty(ASTContext &C, unsigned NumStrs) {
return SL;
}
-void StringLiteral::outputString(raw_ostream &OS) {
+void StringLiteral::outputString(raw_ostream &OS) const {
switch (getKind()) {
case Ascii: break; // no prefix.
case Wide: OS << 'L'; break;
@@ -818,7 +846,7 @@ void StringLiteral::outputString(raw_ostream &OS) {
assert(Char <= 0xff &&
"Characters above 0xff should already have been handled.");
- if (isprint(Char))
+ if (isPrintable(Char))
OS << (char)Char;
else // Output anything hard as an octal escape.
OS << '\\'
@@ -1144,6 +1172,12 @@ unsigned CallExpr::isBuiltinCall() const {
return FDecl->getBuiltinID();
}
+bool CallExpr::isUnevaluatedBuiltinCall(ASTContext &Ctx) const {
+ if (unsigned BI = isBuiltinCall())
+ return Ctx.BuiltinInfo.isUnevaluated(BI);
+ return false;
+}
+
QualType CallExpr::getCallReturnType() const {
QualType CalleeType = getCallee()->getType();
if (const PointerType *FnTypePtr = CalleeType->getAs<PointerType>())
@@ -1158,21 +1192,9 @@ QualType CallExpr::getCallReturnType() const {
return FnType->getResultType();
}
-SourceRange CallExpr::getSourceRange() const {
- if (isa<CXXOperatorCallExpr>(this))
- return cast<CXXOperatorCallExpr>(this)->getSourceRange();
-
- SourceLocation begin = getCallee()->getLocStart();
- if (begin.isInvalid() && getNumArgs() > 0)
- begin = getArg(0)->getLocStart();
- SourceLocation end = getRParenLoc();
- if (end.isInvalid() && getNumArgs() > 0)
- end = getArg(getNumArgs() - 1)->getLocEnd();
- return SourceRange(begin, end);
-}
SourceLocation CallExpr::getLocStart() const {
if (isa<CXXOperatorCallExpr>(this))
- return cast<CXXOperatorCallExpr>(this)->getSourceRange().getBegin();
+ return cast<CXXOperatorCallExpr>(this)->getLocStart();
SourceLocation begin = getCallee()->getLocStart();
if (begin.isInvalid() && getNumArgs() > 0)
@@ -1181,7 +1203,7 @@ SourceLocation CallExpr::getLocStart() const {
}
SourceLocation CallExpr::getLocEnd() const {
if (isa<CXXOperatorCallExpr>(this))
- return cast<CXXOperatorCallExpr>(this)->getSourceRange().getEnd();
+ return cast<CXXOperatorCallExpr>(this)->getLocEnd();
SourceLocation end = getRParenLoc();
if (end.isInvalid() && getNumArgs() > 0)
@@ -1309,9 +1331,6 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
return E;
}
-SourceRange MemberExpr::getSourceRange() const {
- return SourceRange(getLocStart(), getLocEnd());
-}
SourceLocation MemberExpr::getLocStart() const {
if (isImplicitAccess()) {
if (hasQualifier())
@@ -1416,6 +1435,7 @@ void CastExpr::CheckCastConsistency() const {
case CK_ARCConsumeObject:
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject:
+ case CK_ZeroToOCLEvent:
assert(!getType()->isBooleanType() && "unheralded conversion to bool");
goto CheckNoBasePath;
@@ -1547,6 +1567,8 @@ const char *CastExpr::getCastKindName() const {
return "CopyAndAutoreleaseBlockObject";
case CK_BuiltinFnToFnPtr:
return "BuiltinFnToFnPtr";
+ case CK_ZeroToOCLEvent:
+ return "ZeroToOCLEvent";
}
llvm_unreachable("Unhandled cast kind!");
@@ -1807,10 +1829,10 @@ bool InitListExpr::isStringLiteralInit() const {
return isa<StringLiteral>(Init) || isa<ObjCEncodeExpr>(Init);
}
-SourceRange InitListExpr::getSourceRange() const {
+SourceLocation InitListExpr::getLocStart() const {
if (InitListExpr *SyntacticForm = getSyntacticForm())
- return SyntacticForm->getSourceRange();
- SourceLocation Beg = LBraceLoc, End = RBraceLoc;
+ return SyntacticForm->getLocStart();
+ SourceLocation Beg = LBraceLoc;
if (Beg.isInvalid()) {
// Find the first non-null initializer.
for (InitExprsTy::const_iterator I = InitExprs.begin(),
@@ -1822,18 +1844,25 @@ SourceRange InitListExpr::getSourceRange() const {
}
}
}
+ return Beg;
+}
+
+SourceLocation InitListExpr::getLocEnd() const {
+ if (InitListExpr *SyntacticForm = getSyntacticForm())
+ return SyntacticForm->getLocEnd();
+ SourceLocation End = RBraceLoc;
if (End.isInvalid()) {
// Find the first non-null initializer from the end.
for (InitExprsTy::const_reverse_iterator I = InitExprs.rbegin(),
- E = InitExprs.rend();
- I != E; ++I) {
+ E = InitExprs.rend();
+ I != E; ++I) {
if (Stmt *S = *I) {
- End = S->getSourceRange().getEnd();
+ End = S->getLocEnd();
break;
- }
+ }
}
}
- return SourceRange(Beg, End);
+ return End;
}
/// getFunctionType - Return the underlying function type for this block.
@@ -2115,10 +2144,6 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
return false;
}
- // Ignore casts within macro expansions.
- if (getExprLoc().isMacroID())
- return CE->getSubExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
-
// If this is a cast to a constructor conversion, check the operand.
// Otherwise, the result of the cast is unused.
if (CE->getCastKind() == CK_ConstructorConversion)
@@ -2581,7 +2606,7 @@ bool Expr::isImplicitCXXThis() const {
/// hasAnyTypeDependentArguments - Determines if any of the expressions
/// in Exprs is type-dependent.
-bool Expr::hasAnyTypeDependentArguments(llvm::ArrayRef<Expr *> Exprs) {
+bool Expr::hasAnyTypeDependentArguments(ArrayRef<Expr *> Exprs) {
for (unsigned I = 0; I < Exprs.size(); ++I)
if (Exprs[I]->isTypeDependent())
return true;
@@ -3025,9 +3050,9 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
return Source->isNullPointerConstant(Ctx, NPC);
}
- // C++0x nullptr_t is always a null pointer constant.
+ // C++11 nullptr_t is always a null pointer constant.
if (getType()->isNullPtrType())
- return NPCK_CXX0X_nullptr;
+ return NPCK_CXX11_nullptr;
if (const RecordType *UT = getType()->getAsUnionType())
if (UT && UT->getDecl()->hasAttr<TransparentUnionAttr>())
@@ -3045,7 +3070,7 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
// test for the value 0. Don't use the C++11 constant expression semantics
// for this, for now; once the dust settles on core issue 903, we might only
// allow a literal 0 here in C++11 mode.
- if (Ctx.getLangOpts().CPlusPlus0x) {
+ if (Ctx.getLangOpts().CPlusPlus11) {
if (!isCXX98IntegralConstantExpr(Ctx))
return NPCK_NotNull;
} else {
@@ -3683,11 +3708,11 @@ SourceRange DesignatedInitExpr::getDesignatorsSourceRange() const {
DesignatedInitExpr *DIE = const_cast<DesignatedInitExpr*>(this);
if (size() == 1)
return DIE->getDesignator(0)->getSourceRange();
- return SourceRange(DIE->getDesignator(0)->getStartLocation(),
- DIE->getDesignator(size()-1)->getEndLocation());
+ return SourceRange(DIE->getDesignator(0)->getLocStart(),
+ DIE->getDesignator(size()-1)->getLocEnd());
}
-SourceRange DesignatedInitExpr::getSourceRange() const {
+SourceLocation DesignatedInitExpr::getLocStart() const {
SourceLocation StartLoc;
Designator &First =
*const_cast<DesignatedInitExpr*>(this)->designators_begin();
@@ -3699,30 +3724,37 @@ SourceRange DesignatedInitExpr::getSourceRange() const {
} else
StartLoc =
SourceLocation::getFromRawEncoding(First.ArrayOrRange.LBracketLoc);
- return SourceRange(StartLoc, getInit()->getSourceRange().getEnd());
+ return StartLoc;
+}
+
+SourceLocation DesignatedInitExpr::getLocEnd() const {
+ return getInit()->getLocEnd();
}
-Expr *DesignatedInitExpr::getArrayIndex(const Designator& D) {
+Expr *DesignatedInitExpr::getArrayIndex(const Designator& D) const {
assert(D.Kind == Designator::ArrayDesignator && "Requires array designator");
- char* Ptr = static_cast<char*>(static_cast<void *>(this));
+ char *Ptr = static_cast<char *>(
+ const_cast<void *>(static_cast<const void *>(this)));
Ptr += sizeof(DesignatedInitExpr);
Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 1));
}
-Expr *DesignatedInitExpr::getArrayRangeStart(const Designator& D) {
+Expr *DesignatedInitExpr::getArrayRangeStart(const Designator &D) const {
assert(D.Kind == Designator::ArrayRangeDesignator &&
"Requires array range designator");
- char* Ptr = static_cast<char*>(static_cast<void *>(this));
+ char *Ptr = static_cast<char *>(
+ const_cast<void *>(static_cast<const void *>(this)));
Ptr += sizeof(DesignatedInitExpr);
Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 1));
}
-Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator& D) {
+Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator &D) const {
assert(D.Kind == Designator::ArrayRangeDesignator &&
"Requires array range designator");
- char* Ptr = static_cast<char*>(static_cast<void *>(this));
+ char *Ptr = static_cast<char *>(
+ const_cast<void *>(static_cast<const void *>(this)));
Ptr += sizeof(DesignatedInitExpr);
Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 2));
@@ -3895,7 +3927,7 @@ Stmt::child_range ObjCMessageExpr::children() {
reinterpret_cast<Stmt **>(getArgs() + getNumArgs()));
}
-ObjCArrayLiteral::ObjCArrayLiteral(llvm::ArrayRef<Expr *> Elements,
+ObjCArrayLiteral::ObjCArrayLiteral(ArrayRef<Expr *> Elements,
QualType T, ObjCMethodDecl *Method,
SourceRange SR)
: Expr(ObjCArrayLiteralClass, T, VK_RValue, OK_Ordinary,
@@ -3916,7 +3948,7 @@ ObjCArrayLiteral::ObjCArrayLiteral(llvm::ArrayRef<Expr *> Elements,
}
ObjCArrayLiteral *ObjCArrayLiteral::Create(ASTContext &C,
- llvm::ArrayRef<Expr *> Elements,
+ ArrayRef<Expr *> Elements,
QualType T, ObjCMethodDecl * Method,
SourceRange SR) {
void *Mem = C.Allocate(sizeof(ObjCArrayLiteral)
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 55722a2..12a47fc 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -11,12 +11,13 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Basic/IdentifierTable.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/TypeLoc.h"
+#include "clang/Basic/IdentifierTable.h"
using namespace clang;
@@ -72,11 +73,8 @@ UuidAttr *CXXUuidofExpr::GetUuidAttrOfType(QualType QT) {
}
// CXXScalarValueInitExpr
-SourceRange CXXScalarValueInitExpr::getSourceRange() const {
- SourceLocation Start = RParenLoc;
- if (TypeInfo)
- Start = TypeInfo->getTypeLoc().getBeginLoc();
- return SourceRange(Start, RParenLoc);
+SourceLocation CXXScalarValueInitExpr::getLocStart() const {
+ return TypeInfo ? TypeInfo->getTypeLoc().getBeginLoc() : RParenLoc;
}
// CXXNewExpr
@@ -180,7 +178,8 @@ CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(ASTContext &Context,
SourceLocation ColonColonLoc, SourceLocation TildeLoc,
PseudoDestructorTypeStorage DestroyedType)
: Expr(CXXPseudoDestructorExprClass,
- Context.getPointerType(Context.getFunctionType(Context.VoidTy, 0, 0,
+ Context.getPointerType(Context.getFunctionType(Context.VoidTy,
+ ArrayRef<QualType>(),
FunctionProtoType::ExtProtoInfo())),
VK_RValue, OK_Ordinary,
/*isTypeDependent=*/(Base->isTypeDependent() ||
@@ -217,11 +216,11 @@ QualType CXXPseudoDestructorExpr::getDestroyedType() const {
return QualType();
}
-SourceRange CXXPseudoDestructorExpr::getSourceRange() const {
+SourceLocation CXXPseudoDestructorExpr::getLocEnd() const {
SourceLocation End = DestroyedType.getLocation();
if (TypeSourceInfo *TInfo = DestroyedType.getTypeSourceInfo())
End = TInfo->getTypeLoc().getLocalSourceRange().getEnd();
- return SourceRange(Base->getLocStart(), End);
+ return End;
}
// UnresolvedLookupExpr
@@ -419,12 +418,18 @@ DependentScopeDeclRefExpr::CreateEmpty(ASTContext &C,
return E;
}
-SourceRange CXXConstructExpr::getSourceRange() const {
+SourceLocation CXXConstructExpr::getLocStart() const {
if (isa<CXXTemporaryObjectExpr>(this))
- return cast<CXXTemporaryObjectExpr>(this)->getSourceRange();
+ return cast<CXXTemporaryObjectExpr>(this)->getLocStart();
+ return Loc;
+}
+
+SourceLocation CXXConstructExpr::getLocEnd() const {
+ if (isa<CXXTemporaryObjectExpr>(this))
+ return cast<CXXTemporaryObjectExpr>(this)->getLocEnd();
if (ParenRange.isValid())
- return SourceRange(Loc, ParenRange.getEnd());
+ return ParenRange.getEnd();
SourceLocation End = Loc;
for (unsigned I = getNumArgs(); I > 0; --I) {
@@ -438,7 +443,7 @@ SourceRange CXXConstructExpr::getSourceRange() const {
}
}
- return SourceRange(Loc, End);
+ return End;
}
SourceRange CXXOperatorCallExpr::getSourceRangeImpl() const {
@@ -522,13 +527,14 @@ CXXStaticCastExpr *CXXStaticCastExpr::Create(ASTContext &C, QualType T,
const CXXCastPath *BasePath,
TypeSourceInfo *WrittenTy,
SourceLocation L,
- SourceLocation RParenLoc) {
+ SourceLocation RParenLoc,
+ SourceRange AngleBrackets) {
unsigned PathSize = (BasePath ? BasePath->size() : 0);
void *Buffer = C.Allocate(sizeof(CXXStaticCastExpr)
+ PathSize * sizeof(CXXBaseSpecifier*));
CXXStaticCastExpr *E =
new (Buffer) CXXStaticCastExpr(T, VK, K, Op, PathSize, WrittenTy, L,
- RParenLoc);
+ RParenLoc, AngleBrackets);
if (PathSize) E->setCastPath(*BasePath);
return E;
}
@@ -546,13 +552,14 @@ CXXDynamicCastExpr *CXXDynamicCastExpr::Create(ASTContext &C, QualType T,
const CXXCastPath *BasePath,
TypeSourceInfo *WrittenTy,
SourceLocation L,
- SourceLocation RParenLoc) {
+ SourceLocation RParenLoc,
+ SourceRange AngleBrackets) {
unsigned PathSize = (BasePath ? BasePath->size() : 0);
void *Buffer = C.Allocate(sizeof(CXXDynamicCastExpr)
+ PathSize * sizeof(CXXBaseSpecifier*));
CXXDynamicCastExpr *E =
new (Buffer) CXXDynamicCastExpr(T, VK, K, Op, PathSize, WrittenTy, L,
- RParenLoc);
+ RParenLoc, AngleBrackets);
if (PathSize) E->setCastPath(*BasePath);
return E;
}
@@ -602,13 +609,14 @@ CXXReinterpretCastExpr::Create(ASTContext &C, QualType T, ExprValueKind VK,
CastKind K, Expr *Op,
const CXXCastPath *BasePath,
TypeSourceInfo *WrittenTy, SourceLocation L,
- SourceLocation RParenLoc) {
+ SourceLocation RParenLoc,
+ SourceRange AngleBrackets) {
unsigned PathSize = (BasePath ? BasePath->size() : 0);
void *Buffer =
C.Allocate(sizeof(CXXReinterpretCastExpr) + PathSize * sizeof(CXXBaseSpecifier*));
CXXReinterpretCastExpr *E =
new (Buffer) CXXReinterpretCastExpr(T, VK, K, Op, PathSize, WrittenTy, L,
- RParenLoc);
+ RParenLoc, AngleBrackets);
if (PathSize) E->setCastPath(*BasePath);
return E;
}
@@ -624,8 +632,9 @@ CXXConstCastExpr *CXXConstCastExpr::Create(ASTContext &C, QualType T,
ExprValueKind VK, Expr *Op,
TypeSourceInfo *WrittenTy,
SourceLocation L,
- SourceLocation RParenLoc) {
- return new (C) CXXConstCastExpr(T, VK, Op, WrittenTy, L, RParenLoc);
+ SourceLocation RParenLoc,
+ SourceRange AngleBrackets) {
+ return new (C) CXXConstCastExpr(T, VK, Op, WrittenTy, L, RParenLoc, AngleBrackets);
}
CXXConstCastExpr *CXXConstCastExpr::CreateEmpty(ASTContext &C) {
@@ -716,19 +725,24 @@ CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C,
ArrayRef<Expr*> Args,
SourceRange parenRange,
bool HadMultipleCandidates,
+ bool ListInitialization,
bool ZeroInitialization)
: CXXConstructExpr(C, CXXTemporaryObjectExprClass,
Type->getType().getNonReferenceType(),
Type->getTypeLoc().getBeginLoc(),
Cons, false, Args,
- HadMultipleCandidates, /*FIXME*/false, ZeroInitialization,
+ HadMultipleCandidates,
+ ListInitialization, ZeroInitialization,
CXXConstructExpr::CK_Complete, parenRange),
Type(Type) {
}
-SourceRange CXXTemporaryObjectExpr::getSourceRange() const {
- return SourceRange(Type->getTypeLoc().getBeginLoc(),
- getParenRange().getEnd());
+SourceLocation CXXTemporaryObjectExpr::getLocStart() const {
+ return Type->getTypeLoc().getBeginLoc();
+}
+
+SourceLocation CXXTemporaryObjectExpr::getLocEnd() const {
+ return getParenRange().getEnd();
}
CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T,
@@ -963,9 +977,9 @@ CXXMethodDecl *LambdaExpr::getCallOperator() const {
DeclarationName Name
= Record->getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
DeclContext::lookup_result Calls = Record->lookup(Name);
- assert(Calls.first != Calls.second && "Missing lambda call operator!");
- CXXMethodDecl *Result = cast<CXXMethodDecl>(*Calls.first++);
- assert(Calls.first == Calls.second && "More than lambda one call operator?");
+ assert(!Calls.empty() && "Missing lambda call operator!");
+ assert(Calls.size() == 1 && "More than one lambda call operator!");
+ CXXMethodDecl *Result = cast<CXXMethodDecl>(Calls.front());
return Result;
}
@@ -1057,8 +1071,8 @@ CXXUnresolvedConstructExpr::CreateEmpty(ASTContext &C, unsigned NumArgs) {
return new (Mem) CXXUnresolvedConstructExpr(Empty, NumArgs);
}
-SourceRange CXXUnresolvedConstructExpr::getSourceRange() const {
- return SourceRange(Type->getTypeLoc().getBeginLoc(), RParenLoc);
+SourceLocation CXXUnresolvedConstructExpr::getLocStart() const {
+ return Type->getTypeLoc().getBeginLoc();
}
CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
@@ -1330,7 +1344,7 @@ FunctionParmPackExpr::FunctionParmPackExpr(QualType T, ParmVarDecl *ParamPack,
FunctionParmPackExpr *
FunctionParmPackExpr::Create(ASTContext &Context, QualType T,
ParmVarDecl *ParamPack, SourceLocation NameLoc,
- llvm::ArrayRef<Decl*> Params) {
+ ArrayRef<Decl *> Params) {
return new (Context.Allocate(sizeof(FunctionParmPackExpr) +
sizeof(ParmVarDecl*) * Params.size()))
FunctionParmPackExpr(T, ParamPack, NameLoc, Params.size(), Params.data());
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index 24ec6bb..61bc3e2 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -11,14 +11,14 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/Support/ErrorHandling.h"
#include "clang/AST/Expr.h"
-#include "clang/AST/ExprCXX.h"
-#include "clang/AST/ExprObjC.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "llvm/Support/ErrorHandling.h"
using namespace clang;
typedef Expr::Classification Cl;
@@ -34,21 +34,6 @@ static Cl::Kinds ClassifyConditional(ASTContext &Ctx,
static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E,
Cl::Kinds Kind, SourceLocation &Loc);
-static Cl::Kinds ClassifyExprValueKind(const LangOptions &Lang,
- const Expr *E,
- ExprValueKind Kind) {
- switch (Kind) {
- case VK_RValue:
- return Lang.CPlusPlus && E->getType()->isRecordType() ?
- Cl::CL_ClassTemporary : Cl::CL_PRValue;
- case VK_LValue:
- return Cl::CL_LValue;
- case VK_XValue:
- return Cl::CL_XValue;
- }
- llvm_unreachable("Invalid value category of implicit cast.");
-}
-
Cl Expr::ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const {
assert(!TR->isReferenceType() && "Expressions can't have reference type.");
@@ -100,6 +85,20 @@ static Cl::Kinds ClassifyTemporary(QualType T) {
return Cl::CL_PRValue;
}
+static Cl::Kinds ClassifyExprValueKind(const LangOptions &Lang,
+ const Expr *E,
+ ExprValueKind Kind) {
+ switch (Kind) {
+ case VK_RValue:
+ return Lang.CPlusPlus ? ClassifyTemporary(E->getType()) : Cl::CL_PRValue;
+ case VK_LValue:
+ return Cl::CL_LValue;
+ case VK_XValue:
+ return Cl::CL_XValue;
+ }
+ llvm_unreachable("Invalid value category of implicit cast.");
+}
+
static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
// This function takes the first stab at classifying expressions.
const LangOptions &Lang = Ctx.getLangOpts();
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 6e0b5fc..ae86150 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -35,15 +35,16 @@
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/CharUnits.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeLoc.h"
-#include "clang/AST/ASTDiagnostic.h"
-#include "clang/AST/Expr.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
#include <cstring>
#include <functional>
@@ -317,7 +318,7 @@ namespace {
OptionalDiagnostic &operator<<(const APSInt &I) {
if (Diag) {
- llvm::SmallVector<char, 32> Buffer;
+ SmallVector<char, 32> Buffer;
I.toString(Buffer);
*Diag << StringRef(Buffer.data(), Buffer.size());
}
@@ -326,7 +327,7 @@ namespace {
OptionalDiagnostic &operator<<(const APFloat &F) {
if (Diag) {
- llvm::SmallVector<char, 32> Buffer;
+ SmallVector<char, 32> Buffer;
F.toString(Buffer);
*Diag << StringRef(Buffer.data(), Buffer.size());
}
@@ -383,13 +384,17 @@ namespace {
/// expression is a potential constant expression? If so, some diagnostics
/// are suppressed.
bool CheckingPotentialConstantExpression;
+
+ bool IntOverflowCheckMode;
- EvalInfo(const ASTContext &C, Expr::EvalStatus &S)
+ EvalInfo(const ASTContext &C, Expr::EvalStatus &S,
+ bool OverflowCheckMode=false)
: Ctx(const_cast<ASTContext&>(C)), EvalStatus(S), CurrentCall(0),
CallStackDepth(0), NextCallIndex(1),
BottomFrame(*this, SourceLocation(), 0, 0, 0),
EvaluatingDecl(0), EvaluatingDeclValue(0), HasActiveDiagnostic(false),
- CheckingPotentialConstantExpression(false) {}
+ CheckingPotentialConstantExpression(false),
+ IntOverflowCheckMode(OverflowCheckMode) {}
void setEvaluatingDecl(const VarDecl *VD, APValue &Value) {
EvaluatingDecl = VD;
@@ -473,6 +478,8 @@ namespace {
return OptionalDiagnostic();
}
+ bool getIntOverflowCheckMode() { return IntOverflowCheckMode; }
+
/// Diagnose that the evaluation does not produce a C++11 core constant
/// expression.
template<typename LocArg>
@@ -505,8 +512,11 @@ namespace {
/// Should we continue evaluation as much as possible after encountering a
/// construct which can't be folded?
bool keepEvaluatingAfterFailure() {
- return CheckingPotentialConstantExpression &&
- EvalStatus.Diag && EvalStatus.Diag->empty();
+ // Should return true in IntOverflowCheckMode, so that we check for
+ // overflow even if some subexpressions can't be evaluated as constants.
+ return IntOverflowCheckMode ||
+ (CheckingPotentialConstantExpression &&
+ EvalStatus.Diag && EvalStatus.Diag->empty());
}
};
@@ -534,8 +544,7 @@ namespace {
public:
SpeculativeEvaluationRAII(EvalInfo &Info,
- llvm::SmallVectorImpl<PartialDiagnosticAt>
- *NewDiag = 0)
+ SmallVectorImpl<PartialDiagnosticAt> *NewDiag = 0)
: Info(Info), Old(Info.EvalStatus) {
Info.EvalStatus.Diag = NewDiag;
}
@@ -586,7 +595,7 @@ CallStackFrame::~CallStackFrame() {
}
/// Produce a string describing the given constexpr call.
-static void describeCall(CallStackFrame *Frame, llvm::raw_ostream &Out) {
+static void describeCall(CallStackFrame *Frame, raw_ostream &Out) {
unsigned ArgIndex = 0;
bool IsMemberCall = isa<CXXMethodDecl>(Frame->Callee) &&
!isa<CXXConstructorDecl>(Frame->Callee) &&
@@ -634,7 +643,7 @@ void EvalInfo::addCallStack(unsigned Limit) {
continue;
}
- llvm::SmallVector<char, 128> Buffer;
+ SmallVector<char, 128> Buffer;
llvm::raw_svector_ostream Out(Buffer);
describeCall(Frame, Out);
addDiag(Frame->CallLoc, diag::note_constexpr_call_here) << Out.str();
@@ -737,7 +746,7 @@ namespace {
bool checkSubobject(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK) {
// Outside C++11, do not build a designator referring to a subobject of
// any object: we won't use such a designator for anything.
- if (!Info.getLangOpts().CPlusPlus0x)
+ if (!Info.getLangOpts().CPlusPlus11)
Designator.setInvalid();
return checkNullPointer(Info, E, CSK) &&
Designator.checkSubobject(Info, E, CSK);
@@ -971,7 +980,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
// manufacture when checking potential constant expressions is conservatively
// assumed to be global here.
if (!IsGlobalLValue(Base)) {
- if (Info.getLangOpts().CPlusPlus0x) {
+ if (Info.getLangOpts().CPlusPlus11) {
const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
Info.Diag(Loc, diag::note_constexpr_non_global, 1)
<< IsReferenceType << !Designator.Entries.empty()
@@ -1025,7 +1034,7 @@ static bool CheckLiteralType(EvalInfo &Info, const Expr *E) {
return true;
// Prvalue constant expressions must be of literal types.
- if (Info.getLangOpts().CPlusPlus0x)
+ if (Info.getLangOpts().CPlusPlus11)
Info.Diag(E, diag::note_constexpr_nonliteral)
<< E->getType();
else
@@ -1462,7 +1471,7 @@ static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E,
// Check that we can fold the initializer. In C++, we will have already done
// this in the cases where it matters for conformance.
- llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ SmallVector<PartialDiagnosticAt, 8> Notes;
if (!VD->evaluateValue(Notes)) {
Info.Diag(E, diag::note_constexpr_var_init_non_constant,
Notes.size() + 1) << VD;
@@ -1526,7 +1535,7 @@ static bool ExtractSubobject(EvalInfo &Info, const Expr *E,
// A diagnostic will have already been produced.
return false;
if (Sub.isOnePastTheEnd()) {
- Info.Diag(E, Info.getLangOpts().CPlusPlus0x ?
+ Info.Diag(E, Info.getLangOpts().CPlusPlus11 ?
(unsigned)diag::note_constexpr_read_past_end :
(unsigned)diag::note_invalid_subexpr_in_const_expr);
return false;
@@ -1548,7 +1557,7 @@ static bool ExtractSubobject(EvalInfo &Info, const Expr *E,
if (CAT->getSize().ule(Index)) {
// Note, it should not be possible to form a pointer with a valid
// designator which points more than one past the end of the array.
- Info.Diag(E, Info.getLangOpts().CPlusPlus0x ?
+ Info.Diag(E, Info.getLangOpts().CPlusPlus11 ?
(unsigned)diag::note_constexpr_read_past_end :
(unsigned)diag::note_invalid_subexpr_in_const_expr);
return false;
@@ -1570,7 +1579,7 @@ static bool ExtractSubobject(EvalInfo &Info, const Expr *E,
// Next subobject is a complex number.
uint64_t Index = Sub.Entries[I].ArrayIndex;
if (Index > 1) {
- Info.Diag(E, Info.getLangOpts().CPlusPlus0x ?
+ Info.Diag(E, Info.getLangOpts().CPlusPlus11 ?
(unsigned)diag::note_constexpr_read_past_end :
(unsigned)diag::note_invalid_subexpr_in_const_expr);
return false;
@@ -1795,7 +1804,7 @@ static bool HandleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
// We support folding of const floating-point types, in order to make
// static const data members of such types (supported as an extension)
// more useful.
- if (Info.getLangOpts().CPlusPlus0x) {
+ if (Info.getLangOpts().CPlusPlus11) {
Info.CCEDiag(Conv, diag::note_constexpr_ltor_non_constexpr, 1) << VD;
Info.Note(VD->getLocation(), diag::note_declared_at);
} else {
@@ -1803,7 +1812,7 @@ static bool HandleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
}
} else {
// FIXME: Allow folding of values of any literal type in all languages.
- if (Info.getLangOpts().CPlusPlus0x) {
+ if (Info.getLangOpts().CPlusPlus11) {
Info.Diag(Conv, diag::note_constexpr_ltor_non_constexpr, 1) << VD;
Info.Note(VD->getLocation(), diag::note_declared_at);
} else {
@@ -2080,7 +2089,7 @@ static bool CheckTrivialDefaultConstructor(EvalInfo &Info, SourceLocation Loc,
// call is a core constant expression whether or not the constructor is
// constexpr.
if (!CD->isConstexpr() && !IsValueInitialization) {
- if (Info.getLangOpts().CPlusPlus0x) {
+ if (Info.getLangOpts().CPlusPlus11) {
// FIXME: If DiagDecl is an implicitly-declared special member function,
// we should be much more explicit about why it's not constexpr.
Info.CCEDiag(Loc, diag::note_constexpr_invalid_function, 1)
@@ -2108,7 +2117,7 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
if (Definition && Definition->isConstexpr() && !Definition->isInvalidDecl())
return true;
- if (Info.getLangOpts().CPlusPlus0x) {
+ if (Info.getLangOpts().CPlusPlus11) {
const FunctionDecl *DiagDecl = Definition ? Definition : Declaration;
// FIXME: If DiagDecl is an implicitly-declared special member function, we
// should be much more explicit about why it's not constexpr.
@@ -2311,7 +2320,7 @@ private:
// Speculatively evaluate both arms.
{
- llvm::SmallVector<PartialDiagnosticAt, 8> Diag;
+ SmallVector<PartialDiagnosticAt, 8> Diag;
SpeculativeEvaluationRAII Speculate(Info, &Diag);
StmtVisitorTy::Visit(E->getFalseExpr());
@@ -2482,7 +2491,7 @@ public:
const FunctionDecl *FD = 0;
LValue *This = 0, ThisVal;
- llvm::ArrayRef<const Expr*> Args(E->getArgs(), E->getNumArgs());
+ ArrayRef<const Expr *> Args(E->getArgs(), E->getNumArgs());
bool HasQualifier = false;
// Extract function decl and 'this' pointer from the callee.
@@ -3487,7 +3496,7 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
if (ZeroInit && !ZeroInitialization(E))
return false;
- llvm::ArrayRef<const Expr*> Args(E->getArgs(), E->getNumArgs());
+ ArrayRef<const Expr *> Args(E->getArgs(), E->getNumArgs());
return HandleConstructorCall(E->getExprLoc(), This, Args,
cast<CXXConstructorDecl>(Definition), Info,
Result);
@@ -3629,7 +3638,6 @@ bool VectorExprEvaluator::VisitCastExpr(const CastExpr* E) {
SmallVector<APValue, 4> Elts;
if (EltTy->isRealFloatingType()) {
const llvm::fltSemantics &Sem = Info.Ctx.getFloatTypeSemantics(EltTy);
- bool isIEESem = &Sem != &APFloat::PPCDoubleDouble;
unsigned FloatEltSize = EltSize;
if (&Sem == &APFloat::x87DoubleExtended)
FloatEltSize = 80;
@@ -3639,7 +3647,7 @@ bool VectorExprEvaluator::VisitCastExpr(const CastExpr* E) {
Elt = SValInt.rotl(i*EltSize+FloatEltSize).trunc(FloatEltSize);
else
Elt = SValInt.rotr(i*EltSize).trunc(FloatEltSize);
- Elts.push_back(APValue(APFloat(Elt, isIEESem)));
+ Elts.push_back(APValue(APFloat(Sem, Elt)));
}
} else if (EltTy->isIntegerType()) {
for (unsigned i = 0; i < NElts; i++) {
@@ -3898,7 +3906,7 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
return false;
}
- llvm::ArrayRef<const Expr*> Args(E->getArgs(), E->getNumArgs());
+ ArrayRef<const Expr *> Args(E->getArgs(), E->getNumArgs());
return HandleConstructorCall(E->getExprLoc(), Subobject, Args,
cast<CXXConstructorDecl>(Definition),
Info, *Value);
@@ -4317,7 +4325,7 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BIstrlen:
// A call to strlen is not a constant expression.
- if (Info.getLangOpts().CPlusPlus0x)
+ if (Info.getLangOpts().CPlusPlus11)
Info.CCEDiag(E, diag::note_constexpr_invalid_function)
<< /*isConstexpr*/0 << /*isConstructor*/0 << "'strlen'";
else
@@ -4419,8 +4427,14 @@ static APSInt CheckedIntArithmetic(EvalInfo &Info, const Expr *E,
APSInt Value(Op(LHS.extend(BitWidth), RHS.extend(BitWidth)), false);
APSInt Result = Value.trunc(LHS.getBitWidth());
- if (Result.extend(BitWidth) != Value)
- HandleOverflow(Info, E, Value, E->getType());
+ if (Result.extend(BitWidth) != Value) {
+ if (Info.getIntOverflowCheckMode())
+ Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
+ diag::warn_integer_constant_overflow)
+ << Result.toString(10) << E->getType();
+ else
+ HandleOverflow(Info, E, Value, E->getType());
+ }
return Result;
}
@@ -4707,9 +4721,14 @@ bool DataRecursiveIntBinOpEvaluator::
return Success(E->getOpcode() == BO_Rem ? LHS % RHS : LHS / RHS, E,
Result);
case BO_Shl: {
- // During constant-folding, a negative shift is an opposite shift. Such
- // a shift is not a constant expression.
- if (RHS.isSigned() && RHS.isNegative()) {
+ if (Info.getLangOpts().OpenCL)
+ // OpenCL 6.3j: shift values are effectively % word size of LHS.
+ RHS &= APSInt(llvm::APInt(RHS.getBitWidth(),
+ static_cast<uint64_t>(LHS.getBitWidth() - 1)),
+ RHS.isUnsigned());
+ else if (RHS.isSigned() && RHS.isNegative()) {
+ // During constant-folding, a negative shift is an opposite shift. Such
+ // a shift is not a constant expression.
CCEDiag(E, diag::note_constexpr_negative_shift) << RHS;
RHS = -RHS;
goto shift_right;
@@ -4734,9 +4753,14 @@ bool DataRecursiveIntBinOpEvaluator::
return Success(LHS << SA, E, Result);
}
case BO_Shr: {
- // During constant-folding, a negative shift is an opposite shift. Such a
- // shift is not a constant expression.
- if (RHS.isSigned() && RHS.isNegative()) {
+ if (Info.getLangOpts().OpenCL)
+ // OpenCL 6.3j: shift values are effectively % word size of LHS.
+ RHS &= APSInt(llvm::APInt(RHS.getBitWidth(),
+ static_cast<uint64_t>(LHS.getBitWidth() - 1)),
+ RHS.isUnsigned());
+ else if (RHS.isSigned() && RHS.isNegative()) {
+ // During constant-folding, a negative shift is an opposite shift. Such a
+ // shift is not a constant expression.
CCEDiag(E, diag::note_constexpr_negative_shift) << RHS;
RHS = -RHS;
goto shift_left;
@@ -5362,6 +5386,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_IntegralComplexCast:
case CK_IntegralComplexToFloatingComplex:
case CK_BuiltinFnToFnPtr:
+ case CK_ZeroToOCLEvent:
llvm_unreachable("invalid cast kind for integral value");
case CK_BitCast:
@@ -5849,6 +5874,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_ARCExtendBlockObject:
case CK_CopyAndAutoreleaseBlockObject:
case CK_BuiltinFnToFnPtr:
+ case CK_ZeroToOCLEvent:
llvm_unreachable("invalid cast kind for complex value");
case CK_LValueToRValue:
@@ -6191,12 +6217,12 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
return false;
Result = Info.CurrentCall->Temporaries[E];
} else if (E->getType()->isVoidType()) {
- if (!Info.getLangOpts().CPlusPlus0x)
+ if (!Info.getLangOpts().CPlusPlus11)
Info.CCEDiag(E, diag::note_constexpr_nonliteral)
<< E->getType();
if (!EvaluateVoid(E, Info))
return false;
- } else if (Info.getLangOpts().CPlusPlus0x) {
+ } else if (Info.getLangOpts().CPlusPlus11) {
Info.Diag(E, diag::note_constexpr_nonliteral) << E->getType();
return false;
} else {
@@ -6249,26 +6275,39 @@ static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) {
return CheckConstantExpression(Info, E->getExprLoc(), E->getType(), Result);
}
-/// EvaluateAsRValue - Return true if this is a constant which we can fold using
-/// any crazy technique (that has nothing to do with language standards) that
-/// we want to. If this function returns true, it returns the folded constant
-/// in Result. If this expression is a glvalue, an lvalue-to-rvalue conversion
-/// will be applied to the result.
-bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx) const {
+static bool FastEvaluateAsRValue(const Expr *Exp, Expr::EvalResult &Result,
+ const ASTContext &Ctx, bool &IsConst) {
// Fast-path evaluations of integer literals, since we sometimes see files
// containing vast quantities of these.
- if (const IntegerLiteral *L = dyn_cast<IntegerLiteral>(this)) {
+ if (const IntegerLiteral *L = dyn_cast<IntegerLiteral>(Exp)) {
Result.Val = APValue(APSInt(L->getValue(),
L->getType()->isUnsignedIntegerType()));
+ IsConst = true;
return true;
}
-
+
// FIXME: Evaluating values of large array and record types can cause
// performance problems. Only do so in C++11 for now.
- if (isRValue() && (getType()->isArrayType() || getType()->isRecordType()) &&
- !Ctx.getLangOpts().CPlusPlus0x)
- return false;
+ if (Exp->isRValue() && (Exp->getType()->isArrayType() ||
+ Exp->getType()->isRecordType()) &&
+ !Ctx.getLangOpts().CPlusPlus11) {
+ IsConst = false;
+ return true;
+ }
+ return false;
+}
+
+/// EvaluateAsRValue - Return true if this is a constant which we can fold using
+/// any crazy technique (that has nothing to do with language standards) that
+/// we want to. If this function returns true, it returns the folded constant
+/// in Result. If this expression is a glvalue, an lvalue-to-rvalue conversion
+/// will be applied to the result.
+bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx) const {
+ bool IsConst;
+ if (FastEvaluateAsRValue(this, Result, Ctx, IsConst))
+ return IsConst;
+
EvalInfo Info(Ctx, Result);
return ::EvaluateAsRValue(Info, this, Result.Val);
}
@@ -6309,11 +6348,11 @@ bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const {
bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
const VarDecl *VD,
- llvm::SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
+ SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
// FIXME: Evaluating initializers for large array and record types can cause
// performance problems. Only do so in C++11 for now.
if (isRValue() && (getType()->isArrayType() || getType()->isRecordType()) &&
- !Ctx.getLangOpts().CPlusPlus0x)
+ !Ctx.getLangOpts().CPlusPlus11)
return false;
Expr::EvalStatus EStatus;
@@ -6353,8 +6392,10 @@ bool Expr::isEvaluatable(const ASTContext &Ctx) const {
return EvaluateAsRValue(Result, Ctx) && !Result.HasSideEffects;
}
-APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx) const {
+APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx,
+ SmallVectorImpl<PartialDiagnosticAt> *Diag) const {
EvalResult EvalResult;
+ EvalResult.Diag = Diag;
bool Result = EvaluateAsRValue(EvalResult, Ctx);
(void)Result;
assert(Result && "Could not evaluate expression");
@@ -6363,6 +6404,17 @@ APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx) const {
return EvalResult.Val.getInt();
}
+void Expr::EvaluateForOverflow(const ASTContext &Ctx,
+ SmallVectorImpl<PartialDiagnosticAt> *Diags) const {
+ bool IsConst;
+ EvalResult EvalResult;
+ EvalResult.Diag = Diags;
+ if (!FastEvaluateAsRValue(this, EvalResult, Ctx, IsConst)) {
+ EvalInfo Info(Ctx, EvalResult, true);
+ (void)::EvaluateAsRValue(Info, this, EvalResult.Val);
+ }
+}
+
bool Expr::EvalResult::isGlobalLValue() const {
assert(Val.isLValue());
return IsGlobalLValue(Val.getLValueBase());
@@ -6374,54 +6426,55 @@ APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx) const {
/// FIXME: Pass up a reason why! Invalid operation in i-c-e, division by zero,
/// comma, etc
-///
-/// FIXME: Handle offsetof. Two things to do: Handle GCC's __builtin_offsetof
-/// to support gcc 4.0+ and handle the idiom GCC recognizes with a null pointer
-/// cast+dereference.
// CheckICE - This function does the fundamental ICE checking: the returned
-// ICEDiag contains a Val of 0, 1, or 2, and a possibly null SourceLocation.
+// ICEDiag contains an ICEKind indicating whether the expression is an ICE,
+// and a (possibly null) SourceLocation indicating the location of the problem.
+//
// Note that to reduce code duplication, this helper does no evaluation
// itself; the caller checks whether the expression is evaluatable, and
// in the rare cases where CheckICE actually cares about the evaluated
// value, it calls into Evalute.
-//
-// Meanings of Val:
-// 0: This expression is an ICE.
-// 1: This expression is not an ICE, but if it isn't evaluated, it's
-// a legal subexpression for an ICE. This return value is used to handle
-// the comma operator in C99 mode.
-// 2: This expression is not an ICE, and is not a legal subexpression for one.
namespace {
+enum ICEKind {
+ /// This expression is an ICE.
+ IK_ICE,
+ /// This expression is not an ICE, but if it isn't evaluated, it's
+ /// a legal subexpression for an ICE. This return value is used to handle
+ /// the comma operator in C99 mode, and non-constant subexpressions.
+ IK_ICEIfUnevaluated,
+ /// This expression is not an ICE, and is not a legal subexpression for one.
+ IK_NotICE
+};
+
struct ICEDiag {
- unsigned Val;
+ ICEKind Kind;
SourceLocation Loc;
- public:
- ICEDiag(unsigned v, SourceLocation l) : Val(v), Loc(l) {}
- ICEDiag() : Val(0) {}
+ ICEDiag(ICEKind IK, SourceLocation l) : Kind(IK), Loc(l) {}
};
}
-static ICEDiag NoDiag() { return ICEDiag(); }
+static ICEDiag NoDiag() { return ICEDiag(IK_ICE, SourceLocation()); }
+
+static ICEDiag Worst(ICEDiag A, ICEDiag B) { return A.Kind >= B.Kind ? A : B; }
static ICEDiag CheckEvalInICE(const Expr* E, ASTContext &Ctx) {
Expr::EvalResult EVResult;
if (!E->EvaluateAsRValue(EVResult, Ctx) || EVResult.HasSideEffects ||
- !EVResult.Val.isInt()) {
- return ICEDiag(2, E->getLocStart());
- }
+ !EVResult.Val.isInt())
+ return ICEDiag(IK_NotICE, E->getLocStart());
+
return NoDiag();
}
static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
assert(!E->isValueDependent() && "Should not see value dependent exprs!");
- if (!E->getType()->isIntegralOrEnumerationType()) {
- return ICEDiag(2, E->getLocStart());
- }
+ if (!E->getType()->isIntegralOrEnumerationType())
+ return ICEDiag(IK_NotICE, E->getLocStart());
switch (E->getStmtClass()) {
#define ABSTRACT_STMT(Node)
@@ -6490,7 +6543,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::AtomicExprClass:
case Expr::InitListExprClass:
case Expr::LambdaExprClass:
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
case Expr::SizeOfPackExprClass:
case Expr::GNUNullExprClass:
@@ -6525,7 +6578,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
const CallExpr *CE = cast<CallExpr>(E);
if (CE->isBuiltinCall())
return CheckEvalInICE(E, Ctx);
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
}
case Expr::DeclRefExprClass: {
if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl()))
@@ -6537,14 +6590,14 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
// getAnyInitializer() can find a default argument, which leads
// to chaos.
if (isa<ParmVarDecl>(D))
- return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
+ return ICEDiag(IK_NotICE, cast<DeclRefExpr>(E)->getLocation());
// C++ 7.1.5.1p2
// A variable of non-volatile const-qualified integral or enumeration
// type initialized by an ICE can be used in ICEs.
if (const VarDecl *Dcl = dyn_cast<VarDecl>(D)) {
if (!Dcl->getType()->isIntegralOrEnumerationType())
- return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
+ return ICEDiag(IK_NotICE, cast<DeclRefExpr>(E)->getLocation());
const VarDecl *VD;
// Look for a declaration of this variable that has an initializer, and
@@ -6552,10 +6605,10 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
if (Dcl->getAnyInitializer(VD) && VD->checkInitIsICE())
return NoDiag();
else
- return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
+ return ICEDiag(IK_NotICE, cast<DeclRefExpr>(E)->getLocation());
}
}
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
}
case Expr::UnaryOperatorClass: {
const UnaryOperator *Exp = cast<UnaryOperator>(E);
@@ -6569,7 +6622,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
// C99 6.6/3 allows increment and decrement within unevaluated
// subexpressions of constant expressions, but they can never be ICEs
// because an ICE cannot contain an lvalue operand.
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
case UO_Extension:
case UO_LNot:
case UO_Plus:
@@ -6579,23 +6632,23 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case UO_Imag:
return CheckICE(Exp->getSubExpr(), Ctx);
}
-
+
// OffsetOf falls through here.
}
case Expr::OffsetOfExprClass: {
- // Note that per C99, offsetof must be an ICE. And AFAIK, using
- // EvaluateAsRValue matches the proposed gcc behavior for cases like
- // "offsetof(struct s{int x[4];}, x[1.0])". This doesn't affect
- // compliance: we should warn earlier for offsetof expressions with
- // array subscripts that aren't ICEs, and if the array subscripts
- // are ICEs, the value of the offsetof must be an integer constant.
- return CheckEvalInICE(E, Ctx);
+ // Note that per C99, offsetof must be an ICE. And AFAIK, using
+ // EvaluateAsRValue matches the proposed gcc behavior for cases like
+ // "offsetof(struct s{int x[4];}, x[1.0])". This doesn't affect
+ // compliance: we should warn earlier for offsetof expressions with
+ // array subscripts that aren't ICEs, and if the array subscripts
+ // are ICEs, the value of the offsetof must be an integer constant.
+ return CheckEvalInICE(E, Ctx);
}
case Expr::UnaryExprOrTypeTraitExprClass: {
const UnaryExprOrTypeTraitExpr *Exp = cast<UnaryExprOrTypeTraitExpr>(E);
if ((Exp->getKind() == UETT_SizeOf) &&
Exp->getTypeOfArgument()->isVariableArrayType())
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
return NoDiag();
}
case Expr::BinaryOperatorClass: {
@@ -6617,7 +6670,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
// C99 6.6/3 allows assignments within unevaluated subexpressions of
// constant expressions, but they can never be ICEs because an ICE cannot
// contain an lvalue operand.
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
case BO_Mul:
case BO_Div:
@@ -6642,14 +6695,14 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
Exp->getOpcode() == BO_Rem) {
// EvaluateAsRValue gives an error for undefined Div/Rem, so make sure
// we don't evaluate one.
- if (LHSResult.Val == 0 && RHSResult.Val == 0) {
+ if (LHSResult.Kind == IK_ICE && RHSResult.Kind == IK_ICE) {
llvm::APSInt REval = Exp->getRHS()->EvaluateKnownConstInt(Ctx);
if (REval == 0)
- return ICEDiag(1, E->getLocStart());
+ return ICEDiag(IK_ICEIfUnevaluated, E->getLocStart());
if (REval.isSigned() && REval.isAllOnesValue()) {
llvm::APSInt LEval = Exp->getLHS()->EvaluateKnownConstInt(Ctx);
if (LEval.isMinSignedValue())
- return ICEDiag(1, E->getLocStart());
+ return ICEDiag(IK_ICEIfUnevaluated, E->getLocStart());
}
}
}
@@ -6657,22 +6710,20 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
if (Ctx.getLangOpts().C99) {
// C99 6.6p3 introduces a strange edge case: comma can be in an ICE
// if it isn't evaluated.
- if (LHSResult.Val == 0 && RHSResult.Val == 0)
- return ICEDiag(1, E->getLocStart());
+ if (LHSResult.Kind == IK_ICE && RHSResult.Kind == IK_ICE)
+ return ICEDiag(IK_ICEIfUnevaluated, E->getLocStart());
} else {
// In both C89 and C++, commas in ICEs are illegal.
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
}
}
- if (LHSResult.Val >= RHSResult.Val)
- return LHSResult;
- return RHSResult;
+ return Worst(LHSResult, RHSResult);
}
case BO_LAnd:
case BO_LOr: {
ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx);
ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx);
- if (LHSResult.Val == 0 && RHSResult.Val == 1) {
+ if (LHSResult.Kind == IK_ICE && RHSResult.Kind == IK_ICEIfUnevaluated) {
// Rare case where the RHS has a comma "side-effect"; we need
// to actually check the condition to see whether the side
// with the comma is evaluated.
@@ -6682,9 +6733,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
return NoDiag();
}
- if (LHSResult.Val >= RHSResult.Val)
- return LHSResult;
- return RHSResult;
+ return Worst(LHSResult, RHSResult);
}
}
}
@@ -6709,7 +6758,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
if (FL->getValue().convertToInteger(IgnoredVal,
llvm::APFloat::rmTowardZero,
&Ignored) & APFloat::opInvalidOp)
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
return NoDiag();
}
}
@@ -6722,18 +6771,18 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case CK_IntegralCast:
return CheckICE(SubExpr, Ctx);
default:
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
}
}
case Expr::BinaryConditionalOperatorClass: {
const BinaryConditionalOperator *Exp = cast<BinaryConditionalOperator>(E);
ICEDiag CommonResult = CheckICE(Exp->getCommon(), Ctx);
- if (CommonResult.Val == 2) return CommonResult;
+ if (CommonResult.Kind == IK_NotICE) return CommonResult;
ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx);
- if (FalseResult.Val == 2) return FalseResult;
- if (CommonResult.Val == 1) return CommonResult;
- if (FalseResult.Val == 1 &&
- Exp->getCommon()->EvaluateKnownConstInt(Ctx) == 0) return NoDiag();
+ if (FalseResult.Kind == IK_NotICE) return FalseResult;
+ if (CommonResult.Kind == IK_ICEIfUnevaluated) return CommonResult;
+ if (FalseResult.Kind == IK_ICEIfUnevaluated &&
+ Exp->getCommon()->EvaluateKnownConstInt(Ctx) != 0) return NoDiag();
return FalseResult;
}
case Expr::ConditionalOperatorClass: {
@@ -6747,26 +6796,25 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
if (CallCE->isBuiltinCall() == Builtin::BI__builtin_constant_p)
return CheckEvalInICE(E, Ctx);
ICEDiag CondResult = CheckICE(Exp->getCond(), Ctx);
- if (CondResult.Val == 2)
+ if (CondResult.Kind == IK_NotICE)
return CondResult;
ICEDiag TrueResult = CheckICE(Exp->getTrueExpr(), Ctx);
ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx);
- if (TrueResult.Val == 2)
+ if (TrueResult.Kind == IK_NotICE)
return TrueResult;
- if (FalseResult.Val == 2)
+ if (FalseResult.Kind == IK_NotICE)
return FalseResult;
- if (CondResult.Val == 1)
+ if (CondResult.Kind == IK_ICEIfUnevaluated)
return CondResult;
- if (TrueResult.Val == 0 && FalseResult.Val == 0)
+ if (TrueResult.Kind == IK_ICE && FalseResult.Kind == IK_ICE)
return NoDiag();
// Rare case where the diagnostics depend on which side is evaluated
// Note that if we get here, CondResult is 0, and at least one of
// TrueResult and FalseResult is non-zero.
- if (Exp->getCond()->EvaluateKnownConstInt(Ctx) == 0) {
+ if (Exp->getCond()->EvaluateKnownConstInt(Ctx) == 0)
return FalseResult;
- }
return TrueResult;
}
case Expr::CXXDefaultArgExprClass:
@@ -6799,12 +6847,12 @@ static bool EvaluateCPlusPlus11IntegralConstantExpr(ASTContext &Ctx,
}
bool Expr::isIntegerConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const {
- if (Ctx.getLangOpts().CPlusPlus0x)
+ if (Ctx.getLangOpts().CPlusPlus11)
return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, 0, Loc);
- ICEDiag d = CheckICE(this, Ctx);
- if (d.Val != 0) {
- if (Loc) *Loc = d.Loc;
+ ICEDiag D = CheckICE(this, Ctx);
+ if (D.Kind != IK_ICE) {
+ if (Loc) *Loc = D.Loc;
return false;
}
return true;
@@ -6812,7 +6860,7 @@ bool Expr::isIntegerConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const {
bool Expr::isIntegerConstantExpr(llvm::APSInt &Value, ASTContext &Ctx,
SourceLocation *Loc, bool isEvaluated) const {
- if (Ctx.getLangOpts().CPlusPlus0x)
+ if (Ctx.getLangOpts().CPlusPlus11)
return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, &Value, Loc);
if (!isIntegerConstantExpr(Ctx, Loc))
@@ -6823,7 +6871,7 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Value, ASTContext &Ctx,
}
bool Expr::isCXX98IntegralConstantExpr(ASTContext &Ctx) const {
- return CheckICE(this, Ctx).Val == 0;
+ return CheckICE(this, Ctx).Kind == IK_ICE;
}
bool Expr::isCXX11ConstantExpr(ASTContext &Ctx, APValue *Result,
@@ -6834,7 +6882,7 @@ bool Expr::isCXX11ConstantExpr(ASTContext &Ctx, APValue *Result,
// Build evaluation settings.
Expr::EvalStatus Status;
- llvm::SmallVector<PartialDiagnosticAt, 8> Diags;
+ SmallVector<PartialDiagnosticAt, 8> Diags;
Status.Diag = &Diags;
EvalInfo Info(Ctx, Status);
@@ -6853,7 +6901,7 @@ bool Expr::isCXX11ConstantExpr(ASTContext &Ctx, APValue *Result,
}
bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
- llvm::SmallVectorImpl<
+ SmallVectorImpl<
PartialDiagnosticAt> &Diags) {
// FIXME: It would be useful to check constexpr function templates, but at the
// moment the constant expression evaluator cannot cope with the non-rigorous
diff --git a/lib/AST/ExternalASTSource.cpp b/lib/AST/ExternalASTSource.cpp
index 6b9fe26..96ebe92 100644
--- a/lib/AST/ExternalASTSource.cpp
+++ b/lib/AST/ExternalASTSource.cpp
@@ -43,10 +43,10 @@ ExternalASTSource::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
return 0;
}
-DeclContextLookupResult
+bool
ExternalASTSource::FindExternalVisibleDeclsByName(const DeclContext *DC,
DeclarationName Name) {
- return DeclContext::lookup_result();
+ return false;
}
void ExternalASTSource::completeVisibleDeclsMap(const DeclContext *DC) {
diff --git a/lib/AST/InheritViz.cpp b/lib/AST/InheritViz.cpp
index b70520f..e03632a 100644
--- a/lib/AST/InheritViz.cpp
+++ b/lib/AST/InheritViz.cpp
@@ -134,7 +134,7 @@ InheritanceHierarchyWriter::WriteNodeReference(QualType Type,
/// viewInheritance - Display the inheritance hierarchy of this C++
/// class using GraphViz.
void CXXRecordDecl::viewInheritance(ASTContext& Context) const {
- QualType Self = Context.getTypeDeclType(const_cast<CXXRecordDecl *>(this));
+ QualType Self = Context.getTypeDeclType(this);
std::string ErrMsg;
sys::Path Filename = sys::Path::GetTemporaryDirectory(&ErrMsg);
if (Filename.isEmpty()) {
diff --git a/lib/AST/ItaniumCXXABI.cpp b/lib/AST/ItaniumCXXABI.cpp
index ce1244c..894eb3b 100644
--- a/lib/AST/ItaniumCXXABI.cpp
+++ b/lib/AST/ItaniumCXXABI.cpp
@@ -19,8 +19,8 @@
#include "CXXABI.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/RecordLayout.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/RecordLayout.h"
#include "clang/AST/Type.h"
#include "clang/Basic/TargetInfo.h"
@@ -33,10 +33,15 @@ protected:
public:
ItaniumCXXABI(ASTContext &Ctx) : Context(Ctx) { }
- unsigned getMemberPointerSize(const MemberPointerType *MPT) const {
- QualType Pointee = MPT->getPointeeType();
- if (Pointee->isFunctionType()) return 2;
- return 1;
+ std::pair<uint64_t, unsigned>
+ getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const {
+ const TargetInfo &Target = Context.getTargetInfo();
+ TargetInfo::IntType PtrDiff = Target.getPtrDiffType(0);
+ uint64_t Width = Target.getTypeWidth(PtrDiff);
+ unsigned Align = Target.getTypeAlign(PtrDiff);
+ if (MPT->getPointeeType()->isFunctionType())
+ Width = 2 * Width;
+ return std::make_pair(Width, Align);
}
CallingConv getDefaultMethodCallConv(bool isVariadic) const {
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index 851944a..21c4993 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -16,6 +16,7 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/Mangle.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
@@ -27,8 +28,8 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
#define MANGLE_CHECKER 0
@@ -355,17 +356,6 @@ private:
}
-static bool isInCLinkageSpecification(const Decl *D) {
- D = D->getCanonicalDecl();
- for (const DeclContext *DC = getEffectiveDeclContext(D);
- !DC->isTranslationUnit(); DC = getEffectiveParentContext(DC)) {
- if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC))
- return Linkage->getLanguage() == LinkageSpecDecl::lang_c;
- }
-
- return false;
-}
-
bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) {
// In C, functions with no attributes never need to be mangled. Fastpath them.
if (!getASTContext().getLangOpts().CPlusPlus && !D->hasAttrs())
@@ -376,20 +366,38 @@ bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) {
if (D->hasAttr<AsmLabelAttr>())
return true;
- // Clang's "overloadable" attribute extension to C/C++ implies name mangling
- // (always) as does passing a C++ member function and a function
- // whose name is not a simple identifier.
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
- if (FD && (FD->hasAttr<OverloadableAttr>() || isa<CXXMethodDecl>(FD) ||
- !FD->getDeclName().isIdentifier()))
- return true;
+ if (FD) {
+ LanguageLinkage L = FD->getLanguageLinkage();
+ // Overloadable functions need mangling.
+ if (FD->hasAttr<OverloadableAttr>())
+ return true;
+
+ // "main" is not mangled.
+ if (FD->isMain())
+ return false;
+
+ // C++ functions and those whose names are not a simple identifier need
+ // mangling.
+ if (!FD->getDeclName().isIdentifier() || L == CXXLanguageLinkage)
+ return true;
+
+ // C functions are not mangled.
+ if (L == CLanguageLinkage)
+ return false;
+ }
// Otherwise, no mangling is done outside C++ mode.
if (!getASTContext().getLangOpts().CPlusPlus)
return false;
- // Variables at global scope with non-internal linkage are not mangled
- if (!FD) {
+ const VarDecl *VD = dyn_cast<VarDecl>(D);
+ if (VD) {
+ // C variables are not mangled.
+ if (VD->isExternC())
+ return false;
+
+ // Variables at global scope with non-internal linkage are not mangled
const DeclContext *DC = getEffectiveDeclContext(D);
// Check for extern variable declared locally.
if (DC->isFunctionOrMethod() && D->hasLinkage())
@@ -399,14 +407,6 @@ bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) {
return false;
}
- // Class members are always mangled.
- if (getEffectiveDeclContext(D)->isRecord())
- return true;
-
- // C functions and "main" are not mangled.
- if ((FD && FD->isMain()) || isInCLinkageSpecification(D))
- return false;
-
return true;
}
@@ -656,7 +656,7 @@ void CXXNameMangler::mangleFloat(const llvm::APFloat &f) {
assert(numCharacters != 0);
// Allocate a buffer of the right number of characters.
- llvm::SmallVector<char, 20> buffer;
+ SmallVector<char, 20> buffer;
buffer.set_size(numCharacters);
// Fill the buffer left-to-right.
@@ -1117,7 +1117,16 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
break;
}
}
-
+
+ int UnnamedMangle = Context.getASTContext().getUnnamedTagManglingNumber(TD);
+ if (UnnamedMangle != -1) {
+ Out << "Ut";
+ if (UnnamedMangle != 0)
+ Out << llvm::utostr(UnnamedMangle - 1);
+ Out << '_';
+ break;
+ }
+
// Get a unique id for the anonymous struct.
uint64_t AnonStructId = Context.getAnonymousStructId(TD);
@@ -1658,7 +1667,8 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) {
// where <address-space-number> is a source name consisting of 'AS'
// followed by the address space <number>.
SmallString<64> ASString;
- ASString = "AS" + llvm::utostr_32(Quals.getAddressSpace());
+ ASString = "AS" + llvm::utostr_32(
+ Context.getASTContext().getTargetAddressSpace(Quals.getAddressSpace()));
Out << 'U' << ASString.size() << ASString;
}
@@ -1870,6 +1880,14 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
case BuiltinType::ObjCId: Out << "11objc_object"; break;
case BuiltinType::ObjCClass: Out << "10objc_class"; break;
case BuiltinType::ObjCSel: Out << "13objc_selector"; break;
+ case BuiltinType::OCLImage1d: Out << "11ocl_image1d"; break;
+ case BuiltinType::OCLImage1dArray: Out << "16ocl_image1darray"; break;
+ case BuiltinType::OCLImage1dBuffer: Out << "17ocl_image1dbuffer"; break;
+ case BuiltinType::OCLImage2d: Out << "11ocl_image2d"; break;
+ case BuiltinType::OCLImage2dArray: Out << "16ocl_image2darray"; break;
+ case BuiltinType::OCLImage3d: Out << "11ocl_image3d"; break;
+ case BuiltinType::OCLSampler: Out << "11ocl_sampler"; break;
+ case BuiltinType::OCLEvent: Out << "9ocl_event"; break;
}
}
diff --git a/lib/AST/LambdaMangleContext.cpp b/lib/AST/LambdaMangleContext.cpp
index 6f4fe2d..54f445d 100644
--- a/lib/AST/LambdaMangleContext.cpp
+++ b/lib/AST/LambdaMangleContext.cpp
@@ -23,10 +23,11 @@ unsigned LambdaMangleContext::getManglingNumber(CXXMethodDecl *CallOperator) {
= CallOperator->getType()->getAs<FunctionProtoType>();
ASTContext &Context = CallOperator->getASTContext();
- QualType Key = Context.getFunctionType(Context.VoidTy,
- Proto->arg_type_begin(),
- Proto->getNumArgs(),
- FunctionProtoType::ExtProtoInfo());
+ QualType Key =
+ Context.getFunctionType(Context.VoidTy,
+ ArrayRef<QualType>(Proto->arg_type_begin(),
+ Proto->getNumArgs()),
+ FunctionProtoType::ExtProtoInfo());
Key = Context.getCanonicalType(Key);
return ++ManglingNumbers[Key->castAs<FunctionProtoType>()];
}
diff --git a/lib/AST/Mangle.cpp b/lib/AST/Mangle.cpp
index d5f8371..eb79412 100644
--- a/lib/AST/Mangle.cpp
+++ b/lib/AST/Mangle.cpp
@@ -20,8 +20,8 @@
#include "clang/Basic/ABI.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
#define MANGLE_CHECKER 0
diff --git a/lib/AST/MicrosoftCXXABI.cpp b/lib/AST/MicrosoftCXXABI.cpp
index 51308ea..6553e9d 100644
--- a/lib/AST/MicrosoftCXXABI.cpp
+++ b/lib/AST/MicrosoftCXXABI.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "CXXABI.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/RecordLayout.h"
@@ -27,13 +28,14 @@ class MicrosoftCXXABI : public CXXABI {
public:
MicrosoftCXXABI(ASTContext &Ctx) : Context(Ctx) { }
- unsigned getMemberPointerSize(const MemberPointerType *MPT) const;
+ std::pair<uint64_t, unsigned>
+ getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const;
CallingConv getDefaultMethodCallConv(bool isVariadic) const {
- if (!isVariadic && Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86)
+ if (!isVariadic &&
+ Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86)
return CC_X86ThisCall;
- else
- return CC_C;
+ return CC_C;
}
bool isNearlyEmpty(const CXXRecordDecl *RD) const {
@@ -52,17 +54,121 @@ public:
};
}
-unsigned MicrosoftCXXABI::getMemberPointerSize(const MemberPointerType *MPT) const {
- QualType Pointee = MPT->getPointeeType();
- CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
- if (RD->getNumVBases() > 0) {
- if (Pointee->isFunctionType())
- return 3;
- else
- return 2;
- } else if (RD->getNumBases() > 1 && Pointee->isFunctionType())
- return 2;
- return 1;
+// getNumBases() seems to only give us the number of direct bases, and not the
+// total. This function tells us if we inherit from anybody that uses MI, or if
+// we have a non-primary base class, which uses the multiple inheritance model.
+static bool usesMultipleInheritanceModel(const CXXRecordDecl *RD) {
+ while (RD->getNumBases() > 0) {
+ if (RD->getNumBases() > 1)
+ return true;
+ assert(RD->getNumBases() == 1);
+ const CXXRecordDecl *Base =
+ RD->bases_begin()->getType()->getAsCXXRecordDecl();
+ if (RD->isPolymorphic() && !Base->isPolymorphic())
+ return true;
+ RD = Base;
+ }
+ return false;
+}
+
+static MSInheritanceModel MSInheritanceAttrToModel(attr::Kind Kind) {
+ switch (Kind) {
+ default: llvm_unreachable("expected MS inheritance attribute");
+ case attr::SingleInheritance: return MSIM_Single;
+ case attr::MultipleInheritance: return MSIM_Multiple;
+ case attr::VirtualInheritance: return MSIM_Virtual;
+ case attr::UnspecifiedInheritance: return MSIM_Unspecified;
+ }
+}
+
+MSInheritanceModel CXXRecordDecl::getMSInheritanceModel() const {
+ if (Attr *IA = this->getAttr<MSInheritanceAttr>())
+ return MSInheritanceAttrToModel(IA->getKind());
+ // If there was no explicit attribute, the record must be defined already, and
+ // we can figure out the inheritance model from its other properties.
+ if (this->getNumVBases() > 0)
+ return MSIM_Virtual;
+ if (usesMultipleInheritanceModel(this))
+ return MSIM_Multiple;
+ return MSIM_Single;
+}
+
+// Returns the number of pointer and integer slots used to represent a member
+// pointer in the MS C++ ABI.
+//
+// Member function pointers have the following general form; however, fields
+// are dropped as permitted (under the MSVC interpretation) by the inheritance
+// model of the actual class.
+//
+// struct {
+// // A pointer to the member function to call. If the member function is
+// // virtual, this will be a thunk that forwards to the appropriate vftable
+// // slot.
+// void *FunctionPointerOrVirtualThunk;
+//
+// // An offset to add to the address of the vbtable pointer after (possibly)
+// // selecting the virtual base but before resolving and calling the function.
+// // Only needed if the class has any virtual bases or bases at a non-zero
+// // offset.
+// int NonVirtualBaseAdjustment;
+//
+// // An offset within the vb-table that selects the virtual base containing
+// // the member. Loading from this offset produces a new offset that is
+// // added to the address of the vb-table pointer to produce the base.
+// int VirtualBaseAdjustmentOffset;
+//
+// // The offset of the vb-table pointer within the object. Only needed for
+// // incomplete types.
+// int VBTableOffset;
+// };
+std::pair<unsigned, unsigned>
+MemberPointerType::getMSMemberPointerSlots() const {
+ const CXXRecordDecl *RD = this->getClass()->getAsCXXRecordDecl();
+ MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
+ unsigned Ptrs;
+ unsigned Ints = 0;
+ if (this->isMemberFunctionPointer()) {
+ // Member function pointers are a struct of a function pointer followed by a
+ // variable number of ints depending on the inheritance model used. The
+ // function pointer is a real function if it is non-virtual and a vftable
+ // slot thunk if it is virtual. The ints select the object base passed for
+ // the 'this' pointer.
+ Ptrs = 1; // First slot is always a function pointer.
+ switch (Inheritance) {
+ case MSIM_Unspecified: ++Ints; // VBTableOffset
+ case MSIM_Virtual: ++Ints; // VirtualBaseAdjustmentOffset
+ case MSIM_Multiple: ++Ints; // NonVirtualBaseAdjustment
+ case MSIM_Single: break; // Nothing
+ }
+ } else {
+ // Data pointers are an aggregate of ints. The first int is an offset
+ // followed by vbtable-related offsets.
+ Ptrs = 0;
+ switch (Inheritance) {
+ case MSIM_Unspecified: ++Ints; // VBTableOffset
+ case MSIM_Virtual: ++Ints; // VirtualBaseAdjustmentOffset
+ case MSIM_Multiple: // Nothing
+ case MSIM_Single: ++Ints; // Field offset
+ }
+ }
+ return std::make_pair(Ptrs, Ints);
+}
+
+std::pair<uint64_t, unsigned> MicrosoftCXXABI::getMemberPointerWidthAndAlign(
+ const MemberPointerType *MPT) const {
+ const TargetInfo &Target = Context.getTargetInfo();
+ assert(Target.getTriple().getArch() == llvm::Triple::x86 ||
+ Target.getTriple().getArch() == llvm::Triple::x86_64);
+ unsigned Ptrs, Ints;
+ llvm::tie(Ptrs, Ints) = MPT->getMSMemberPointerSlots();
+ // The nominal struct is laid out with pointers followed by ints and aligned
+ // to a pointer width if any are present and an int width otherwise.
+ unsigned PtrSize = Target.getPointerWidth(0);
+ unsigned IntSize = Target.getIntWidth();
+ uint64_t Width = Ptrs * PtrSize + Ints * IntSize;
+ unsigned Align = Ptrs > 0 ? Target.getPointerAlign(0) : Target.getIntAlign();
+ Width = llvm::RoundUpToAlignment(Width, Align);
+ return std::make_pair(Width, Align);
}
CXXABI *clang::CreateMicrosoftCXXABI(ASTContext &Ctx) {
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index 5d5b83d..40f8730 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -13,6 +13,7 @@
#include "clang/AST/Mangle.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
@@ -21,19 +22,31 @@
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/ABI.h"
#include "clang/Basic/DiagnosticOptions.h"
-
#include <map>
using namespace clang;
namespace {
+static const FunctionDecl *getStructor(const FunctionDecl *fn) {
+ if (const FunctionTemplateDecl *ftd = fn->getPrimaryTemplate())
+ return ftd->getTemplatedDecl();
+
+ return fn;
+}
+
/// MicrosoftCXXNameMangler - Manage the mangling of a single name for the
/// Microsoft Visual C++ ABI.
class MicrosoftCXXNameMangler {
MangleContext &Context;
raw_ostream &Out;
+ /// The "structor" is the top-level declaration being mangled, if
+ /// that's not a template specialization; otherwise it's the pattern
+ /// for that specialization.
+ const NamedDecl *Structor;
+ unsigned StructorType;
+
// FIXME: audit the performance of BackRefMap as it might do way too many
// copying of strings.
typedef std::map<std::string, unsigned> BackRefMap;
@@ -47,7 +60,15 @@ class MicrosoftCXXNameMangler {
public:
MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_)
- : Context(C), Out(Out_), UseNameBackReferences(true) { }
+ : Context(C), Out(Out_),
+ Structor(0), StructorType(-1),
+ UseNameBackReferences(true) { }
+
+ MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_,
+ const CXXDestructorDecl *D, CXXDtorType Type)
+ : Context(C), Out(Out_),
+ Structor(getStructor(D)), StructorType(Type),
+ UseNameBackReferences(true) { }
raw_ostream &getStream() const { return Out; }
@@ -68,12 +89,13 @@ private:
void mangleSourceName(const IdentifierInfo *II);
void manglePostfix(const DeclContext *DC, bool NoFunction=false);
void mangleOperatorName(OverloadedOperatorKind OO, SourceLocation Loc);
+ void mangleCXXDtorType(CXXDtorType T);
void mangleQualifiers(Qualifiers Quals, bool IsMember);
void manglePointerQualifiers(Qualifiers Quals);
void mangleUnscopedTemplateName(const TemplateDecl *ND);
void mangleTemplateInstantiationName(const TemplateDecl *TD,
- const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs);
+ const TemplateArgumentList &TemplateArgs);
void mangleObjCMethodName(const ObjCMethodDecl *MD);
void mangleLocalName(const FunctionDecl *FD);
@@ -96,12 +118,12 @@ private:
void mangleExtraDimensions(QualType T);
void mangleFunctionClass(const FunctionDecl *FD);
void mangleCallingConvention(const FunctionType *T, bool IsInstMethod = false);
- void mangleIntegerLiteral(QualType T, const llvm::APSInt &Number);
+ void mangleIntegerLiteral(const llvm::APSInt &Number, bool IsBoolean);
void mangleExpression(const Expr *E);
void mangleThrowSpecification(const FunctionProtoType *T);
- void mangleTemplateArgs(
- const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs);
+ void mangleTemplateArgs(const TemplateDecl *TD,
+ const TemplateArgumentList &TemplateArgs);
};
@@ -345,47 +367,19 @@ void MicrosoftCXXNameMangler::mangleNumber(const llvm::APSInt &Value) {
}
static const TemplateDecl *
-isTemplate(const NamedDecl *ND,
- SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) {
+isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) {
// Check if we have a function template.
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)){
if (const TemplateDecl *TD = FD->getPrimaryTemplate()) {
- if (FD->getTemplateSpecializationArgsAsWritten()) {
- const ASTTemplateArgumentListInfo *ArgList =
- FD->getTemplateSpecializationArgsAsWritten();
- TemplateArgs.append(ArgList->getTemplateArgs(),
- ArgList->getTemplateArgs() +
- ArgList->NumTemplateArgs);
- } else {
- const TemplateArgumentList *ArgList =
- FD->getTemplateSpecializationArgs();
- TemplateArgumentListInfo LI;
- for (unsigned i = 0, e = ArgList->size(); i != e; ++i)
- TemplateArgs.push_back(TemplateArgumentLoc(ArgList->get(i),
- FD->getTypeSourceInfo()));
- }
+ TemplateArgs = FD->getTemplateSpecializationArgs();
return TD;
}
}
// Check if we have a class template.
if (const ClassTemplateSpecializationDecl *Spec =
- dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
- TypeSourceInfo *TSI = Spec->getTypeAsWritten();
- if (TSI) {
- TemplateSpecializationTypeLoc TSTL =
- cast<TemplateSpecializationTypeLoc>(TSI->getTypeLoc());
- TemplateArgumentListInfo LI(TSTL.getLAngleLoc(), TSTL.getRAngleLoc());
- for (unsigned i = 0, e = TSTL.getNumArgs(); i != e; ++i)
- TemplateArgs.push_back(TSTL.getArgLoc(i));
- } else {
- TemplateArgumentListInfo LI;
- const TemplateArgumentList &ArgList =
- Spec->getTemplateArgs();
- for (unsigned i = 0, e = ArgList.size(); i != e; ++i)
- TemplateArgs.push_back(TemplateArgumentLoc(ArgList[i],
- TemplateArgumentLocInfo()));
- }
+ dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
+ TemplateArgs = &Spec->getTemplateArgs();
return Spec->getSpecializedTemplate();
}
@@ -399,8 +393,9 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
// ::= <ctor-dtor-name>
// ::= <source-name>
// ::= <template-name>
- SmallVector<TemplateArgumentLoc, 2> TemplateArgs;
+
// Check if we have a template.
+ const TemplateArgumentList *TemplateArgs = 0;
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
// We have a template.
// Here comes the tricky thing: if we need to mangle something like
@@ -430,7 +425,7 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
Found = NameBackReferences.find(BackReferenceKey);
}
if (!UseNameBackReferences || Found == NameBackReferences.end()) {
- mangleTemplateInstantiationName(TD, TemplateArgs);
+ mangleTemplateInstantiationName(TD, *TemplateArgs);
if (UseNameBackReferences && NameBackReferences.size() < 10) {
size_t Size = NameBackReferences.size();
NameBackReferences[BackReferenceKey] = Size;
@@ -453,7 +448,7 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) {
if (NS->isAnonymousNamespace()) {
- Out << "?A";
+ Out << "?A@";
break;
}
}
@@ -481,11 +476,22 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
llvm_unreachable("Can't mangle Objective-C selector names here!");
case DeclarationName::CXXConstructorName:
+ if (ND == Structor) {
+ assert(StructorType == Ctor_Complete &&
+ "Should never be asked to mangle a ctor other than complete");
+ }
Out << "?0";
break;
case DeclarationName::CXXDestructorName:
- Out << "?1";
+ if (ND == Structor)
+ // If the named decl is the C++ destructor we're mangling,
+ // use the type we were given.
+ mangleCXXDtorType(static_cast<CXXDtorType>(StructorType));
+ else
+ // Otherwise, use the complete destructor name. This is relevant if a
+ // class with a destructor is declared within a destructor.
+ mangleCXXDtorType(Dtor_Complete);
break;
case DeclarationName::CXXConversionFunctionName:
@@ -543,6 +549,23 @@ void MicrosoftCXXNameMangler::manglePostfix(const DeclContext *DC,
}
}
+void MicrosoftCXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
+ switch (T) {
+ case Dtor_Deleting:
+ Out << "?_G";
+ return;
+ case Dtor_Base:
+ // FIXME: We should be asked to mangle base dtors.
+ // However, fixing this would require larger changes to the CodeGenModule.
+ // Please put llvm_unreachable here when CGM is changed.
+ // For now, just mangle a base dtor the same way as a complete dtor...
+ case Dtor_Complete:
+ Out << "?1";
+ return;
+ }
+ llvm_unreachable("Unsupported dtor type?");
+}
+
void MicrosoftCXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO,
SourceLocation Loc) {
switch (OO) {
@@ -736,19 +759,23 @@ void MicrosoftCXXNameMangler::mangleLocalName(const FunctionDecl *FD) {
void MicrosoftCXXNameMangler::mangleTemplateInstantiationName(
const TemplateDecl *TD,
- const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) {
+ const TemplateArgumentList &TemplateArgs) {
// <template-name> ::= <unscoped-template-name> <template-args>
// ::= <substitution>
// Always start with the unqualified name.
// Templates have their own context for back references.
- BackRefMap TemplateContext;
- NameBackReferences.swap(TemplateContext);
+ ArgBackRefMap OuterArgsContext;
+ BackRefMap OuterTemplateContext;
+ NameBackReferences.swap(OuterTemplateContext);
+ TypeBackReferences.swap(OuterArgsContext);
mangleUnscopedTemplateName(TD);
- mangleTemplateArgs(TemplateArgs);
+ mangleTemplateArgs(TD, TemplateArgs);
- NameBackReferences.swap(TemplateContext);
+ // Restore the previous back reference contexts.
+ NameBackReferences.swap(OuterTemplateContext);
+ TypeBackReferences.swap(OuterArgsContext);
}
void
@@ -759,13 +786,13 @@ MicrosoftCXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *TD) {
}
void
-MicrosoftCXXNameMangler::mangleIntegerLiteral(QualType T,
- const llvm::APSInt &Value) {
+MicrosoftCXXNameMangler::mangleIntegerLiteral(const llvm::APSInt &Value,
+ bool IsBoolean) {
// <integer-literal> ::= $0 <number>
Out << "$0";
// Make sure booleans are encoded as 0/1.
- if (T->isBooleanType())
- Out << (Value.getBoolValue() ? "0" : "A@");
+ if (IsBoolean && Value.getBoolValue())
+ mangleNumber(1);
else
mangleNumber(Value);
}
@@ -775,7 +802,7 @@ MicrosoftCXXNameMangler::mangleExpression(const Expr *E) {
// See if this is a constant expression.
llvm::APSInt Value;
if (E->isIntegerConstantExpr(Value, Context.getASTContext())) {
- mangleIntegerLiteral(E->getType(), Value);
+ mangleIntegerLiteral(Value, E->getType()->isBooleanType());
return;
}
@@ -788,39 +815,42 @@ MicrosoftCXXNameMangler::mangleExpression(const Expr *E) {
}
void
-MicrosoftCXXNameMangler::mangleTemplateArgs(
- const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) {
+MicrosoftCXXNameMangler::mangleTemplateArgs(const TemplateDecl *TD,
+ const TemplateArgumentList &TemplateArgs) {
// <template-args> ::= {<type> | <integer-literal>}+ @
unsigned NumTemplateArgs = TemplateArgs.size();
for (unsigned i = 0; i < NumTemplateArgs; ++i) {
- const TemplateArgumentLoc &TAL = TemplateArgs[i];
- const TemplateArgument &TA = TAL.getArgument();
+ const TemplateArgument &TA = TemplateArgs[i];
switch (TA.getKind()) {
case TemplateArgument::Null:
llvm_unreachable("Can't mangle null template arguments!");
case TemplateArgument::Type:
- mangleType(TA.getAsType(), TAL.getSourceRange());
+ mangleType(TA.getAsType(), SourceRange());
+ break;
+ case TemplateArgument::Declaration:
+ mangle(cast<NamedDecl>(TA.getAsDecl()), "$1?");
break;
case TemplateArgument::Integral:
- mangleIntegerLiteral(TA.getIntegralType(), TA.getAsIntegral());
+ mangleIntegerLiteral(TA.getAsIntegral(),
+ TA.getIntegralType()->isBooleanType());
break;
case TemplateArgument::Expression:
mangleExpression(TA.getAsExpr());
break;
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
- case TemplateArgument::Declaration:
case TemplateArgument::NullPtr:
case TemplateArgument::Pack: {
// Issue a diagnostic.
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this %select{ERROR|ERROR|pointer/reference|nullptr|"
- "integral|template|template pack expansion|ERROR|parameter pack}0 "
- "template argument yet");
- Diags.Report(TAL.getLocation(), DiagID)
+ "cannot mangle template argument %0 of kind %select{ERROR|ERROR|"
+ "pointer/reference|nullptr|integral|template|template pack expansion|"
+ "ERROR|parameter pack}1 yet");
+ Diags.Report(TD->getLocation(), DiagID)
+ << i + 1
<< TA.getKind()
- << TAL.getSourceRange();
+ << TD->getSourceRange();
}
}
}
@@ -1048,6 +1078,15 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T,
case BuiltinType::ObjCId: Out << "PAUobjc_object@@"; break;
case BuiltinType::ObjCClass: Out << "PAUobjc_class@@"; break;
case BuiltinType::ObjCSel: Out << "PAUobjc_selector@@"; break;
+
+ case BuiltinType::OCLImage1d: Out << "PAUocl_image1d@@"; break;
+ case BuiltinType::OCLImage1dArray: Out << "PAUocl_image1darray@@"; break;
+ case BuiltinType::OCLImage1dBuffer: Out << "PAUocl_image1dbuffer@@"; break;
+ case BuiltinType::OCLImage2d: Out << "PAUocl_image2d@@"; break;
+ case BuiltinType::OCLImage2dArray: Out << "PAUocl_image2darray@@"; break;
+ case BuiltinType::OCLImage3d: Out << "PAUocl_image3d@@"; break;
+ case BuiltinType::OCLSampler: Out << "PAUocl_sampler@@"; break;
+ case BuiltinType::OCLEvent: Out << "PAUocl_event@@"; break;
case BuiltinType::NullPtr: Out << "$$T"; break;
@@ -1096,9 +1135,18 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionType *T,
// <return-type> ::= <type>
// ::= @ # structors (they have no declared return type)
- if (IsStructor)
+ if (IsStructor) {
+ if (isa<CXXDestructorDecl>(D) && D == Structor &&
+ StructorType == Dtor_Deleting) {
+ // The scalar deleting destructor takes an extra int argument.
+ // However, the FunctionType generated has 0 arguments.
+ // FIXME: This is a temporary hack.
+ // Maybe should fix the FunctionType creation instead?
+ Out << "PAXI@Z";
+ return;
+ }
Out << '@';
- else {
+ } else {
QualType Result = Proto->getResultType();
const Type* RT = Result.getTypePtr();
if (!RT->isAnyPointerType() && !RT->isReferenceType()) {
@@ -1471,12 +1519,38 @@ void MicrosoftCXXNameMangler::mangleType(const ComplexType *T,
void MicrosoftCXXNameMangler::mangleType(const VectorType *T,
SourceRange Range) {
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this vector type yet");
- Diags.Report(Range.getBegin(), DiagID)
- << Range;
+ const BuiltinType *ET = T->getElementType()->getAs<BuiltinType>();
+ assert(ET && "vectors with non-builtin elements are unsupported");
+ uint64_t Width = getASTContext().getTypeSize(T);
+ // Pattern match exactly the typedefs in our intrinsic headers. Anything that
+ // doesn't match the Intel types uses a custom mangling below.
+ bool IntelVector = true;
+ if (Width == 64 && ET->getKind() == BuiltinType::LongLong) {
+ Out << "T__m64";
+ } else if (Width == 128 || Width == 256) {
+ if (ET->getKind() == BuiltinType::Float)
+ Out << "T__m" << Width;
+ else if (ET->getKind() == BuiltinType::LongLong)
+ Out << "T__m" << Width << 'i';
+ else if (ET->getKind() == BuiltinType::Double)
+ Out << "U__m" << Width << 'd';
+ else
+ IntelVector = false;
+ } else {
+ IntelVector = false;
+ }
+
+ if (!IntelVector) {
+ // The MS ABI doesn't have a special mangling for vector types, so we define
+ // our own mangling to handle uses of __vector_size__ on user-specified
+ // types, and for extensions like __v4sf.
+ Out << "T__clang_vec" << T->getNumElements() << '_';
+ mangleType(ET, Range);
+ }
+
+ Out << "@@";
}
+
void MicrosoftCXXNameMangler::mangleType(const ExtVectorType *T,
SourceRange Range) {
DiagnosticsEngine &Diags = Context.getDiags();
@@ -1697,7 +1771,7 @@ void MicrosoftMangleContext::mangleCXXCtor(const CXXConstructorDecl *D,
void MicrosoftMangleContext::mangleCXXDtor(const CXXDestructorDecl *D,
CXXDtorType Type,
raw_ostream & Out) {
- MicrosoftCXXNameMangler mangler(*this, Out);
+ MicrosoftCXXNameMangler mangler(*this, Out, D, Type);
mangler.mangle(D);
}
void MicrosoftMangleContext::mangleReferenceTemporary(const clang::VarDecl *VD,
diff --git a/lib/AST/NSAPI.cpp b/lib/AST/NSAPI.cpp
index 0837509..a862630 100644
--- a/lib/AST/NSAPI.cpp
+++ b/lib/AST/NSAPI.cpp
@@ -67,7 +67,7 @@ Selector NSAPI::getNSStringSelector(NSStringMethodKind MK) const {
return NSStringSelectors[MK];
}
-llvm::Optional<NSAPI::NSStringMethodKind>
+Optional<NSAPI::NSStringMethodKind>
NSAPI::getNSStringMethodKind(Selector Sel) const {
for (unsigned i = 0; i != NumNSStringMethods; ++i) {
NSStringMethodKind MK = NSStringMethodKind(i);
@@ -75,7 +75,7 @@ NSAPI::getNSStringMethodKind(Selector Sel) const {
return MK;
}
- return llvm::Optional<NSStringMethodKind>();
+ return None;
}
Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const {
@@ -126,15 +126,14 @@ Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const {
return NSArraySelectors[MK];
}
-llvm::Optional<NSAPI::NSArrayMethodKind>
-NSAPI::getNSArrayMethodKind(Selector Sel) {
+Optional<NSAPI::NSArrayMethodKind> NSAPI::getNSArrayMethodKind(Selector Sel) {
for (unsigned i = 0; i != NumNSArrayMethods; ++i) {
NSArrayMethodKind MK = NSArrayMethodKind(i);
if (Sel == getNSArraySelector(MK))
return MK;
}
- return llvm::Optional<NSArrayMethodKind>();
+ return None;
}
Selector NSAPI::getNSDictionarySelector(
@@ -186,6 +185,14 @@ Selector NSAPI::getNSDictionarySelector(
Sel = Ctx.Selectors.getUnarySelector(
&Ctx.Idents.get("initWithObjectsAndKeys"));
break;
+ case NSDict_initWithObjectsForKeys: {
+ IdentifierInfo *KeyIdents[] = {
+ &Ctx.Idents.get("initWithObjects"),
+ &Ctx.Idents.get("forKeys")
+ };
+ Sel = Ctx.Selectors.getSelector(2, KeyIdents);
+ break;
+ }
case NSDict_objectForKey:
Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectForKey"));
break;
@@ -204,7 +211,7 @@ Selector NSAPI::getNSDictionarySelector(
return NSDictionarySelectors[MK];
}
-llvm::Optional<NSAPI::NSDictionaryMethodKind>
+Optional<NSAPI::NSDictionaryMethodKind>
NSAPI::getNSDictionaryMethodKind(Selector Sel) {
for (unsigned i = 0; i != NumNSDictionaryMethods; ++i) {
NSDictionaryMethodKind MK = NSDictionaryMethodKind(i);
@@ -212,7 +219,7 @@ NSAPI::getNSDictionaryMethodKind(Selector Sel) {
return MK;
}
- return llvm::Optional<NSDictionaryMethodKind>();
+ return None;
}
Selector NSAPI::getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,
@@ -267,7 +274,7 @@ Selector NSAPI::getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,
return Sels[MK];
}
-llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
+Optional<NSAPI::NSNumberLiteralMethodKind>
NSAPI::getNSNumberLiteralMethodKind(Selector Sel) const {
for (unsigned i = 0; i != NumNSNumberLiteralMethods; ++i) {
NSNumberLiteralMethodKind MK = NSNumberLiteralMethodKind(i);
@@ -275,14 +282,14 @@ NSAPI::getNSNumberLiteralMethodKind(Selector Sel) const {
return MK;
}
- return llvm::Optional<NSNumberLiteralMethodKind>();
+ return None;
}
-llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
+Optional<NSAPI::NSNumberLiteralMethodKind>
NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
const BuiltinType *BT = T->getAs<BuiltinType>();
if (!BT)
- return llvm::Optional<NSAPI::NSNumberLiteralMethodKind>();
+ return None;
const TypedefType *TDT = T->getAs<TypedefType>();
if (TDT) {
@@ -337,6 +344,14 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
case BuiltinType::ObjCClass:
case BuiltinType::ObjCId:
case BuiltinType::ObjCSel:
+ case BuiltinType::OCLImage1d:
+ case BuiltinType::OCLImage1dArray:
+ case BuiltinType::OCLImage1dBuffer:
+ case BuiltinType::OCLImage2d:
+ case BuiltinType::OCLImage2dArray:
+ case BuiltinType::OCLImage3d:
+ case BuiltinType::OCLSampler:
+ case BuiltinType::OCLEvent:
case BuiltinType::BoundMember:
case BuiltinType::Dependent:
case BuiltinType::Overload:
@@ -348,7 +363,7 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
break;
}
- return llvm::Optional<NSAPI::NSNumberLiteralMethodKind>();
+ return None;
}
/// \brief Returns true if \param T is a typedef of "BOOL" in objective-c.
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index 49b119b..79cc21a 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -57,7 +57,8 @@ NestedNameSpecifier::Create(const ASTContext &Context,
NestedNameSpecifier *
NestedNameSpecifier::Create(const ASTContext &Context,
- NestedNameSpecifier *Prefix, NamespaceDecl *NS) {
+ NestedNameSpecifier *Prefix,
+ const NamespaceDecl *NS) {
assert(NS && "Namespace cannot be NULL");
assert((!Prefix ||
(Prefix->getAsType() == 0 && Prefix->getAsIdentifier() == 0)) &&
@@ -65,7 +66,7 @@ NestedNameSpecifier::Create(const ASTContext &Context,
NestedNameSpecifier Mockup;
Mockup.Prefix.setPointer(Prefix);
Mockup.Prefix.setInt(StoredNamespaceOrAlias);
- Mockup.Specifier = NS;
+ Mockup.Specifier = const_cast<NamespaceDecl *>(NS);
return FindOrInsert(Context, Mockup);
}
@@ -248,7 +249,6 @@ NestedNameSpecifier::print(raw_ostream &OS,
// Fall through to print the type.
case TypeSpec: {
- std::string TypeStr;
const Type *T = getAsType();
PrintingPolicy InnerPolicy(Policy);
@@ -270,15 +270,12 @@ NestedNameSpecifier::print(raw_ostream &OS,
SpecType->getTemplateName().print(OS, InnerPolicy, true);
// Print the template argument list.
- TypeStr = TemplateSpecializationType::PrintTemplateArgumentList(
- SpecType->getArgs(),
- SpecType->getNumArgs(),
- InnerPolicy);
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, SpecType->getArgs(), SpecType->getNumArgs(), InnerPolicy);
} else {
// Print the type normally
- TypeStr = QualType(T, 0).getAsString(InnerPolicy);
+ QualType(T, 0).print(OS, InnerPolicy);
}
- OS << TypeStr;
break;
}
}
diff --git a/lib/AST/RawCommentList.cpp b/lib/AST/RawCommentList.cpp
index 80b6272..f2386a5 100644
--- a/lib/AST/RawCommentList.cpp
+++ b/lib/AST/RawCommentList.cpp
@@ -10,11 +10,11 @@
#include "clang/AST/RawCommentList.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Comment.h"
-#include "clang/AST/CommentLexer.h"
#include "clang/AST/CommentBriefParser.h"
-#include "clang/AST/CommentSema.h"
-#include "clang/AST/CommentParser.h"
#include "clang/AST/CommentCommandTraits.h"
+#include "clang/AST/CommentLexer.h"
+#include "clang/AST/CommentParser.h"
+#include "clang/AST/CommentSema.h"
#include "llvm/ADT/STLExtras.h"
using namespace clang;
diff --git a/lib/AST/RecordLayout.cpp b/lib/AST/RecordLayout.cpp
index 2ae0aab..f6cfe63 100644
--- a/lib/AST/RecordLayout.cpp
+++ b/lib/AST/RecordLayout.cpp
@@ -75,10 +75,9 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx,
#ifndef NDEBUG
if (const CXXRecordDecl *PrimaryBase = getPrimaryBase()) {
if (isPrimaryBaseVirtual()) {
- // Microsoft ABI doesn't have primary virtual base
- if (Ctx.getTargetInfo().getCXXABI() != CXXABI_Microsoft) {
- assert(getVBaseClassOffset(PrimaryBase).isZero() &&
- "Primary virtual base must be at offset 0!");
+ if (Ctx.getTargetInfo().getCXXABI().hasPrimaryVBases()) {
+ assert(getVBaseClassOffset(PrimaryBase).isZero() &&
+ "Primary virtual base must be at offset 0!");
}
} else {
assert(getBaseClassOffset(PrimaryBase).isZero() &&
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 4dfffc4..42c3ba3 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/RecordLayout.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/CXXInheritance.h"
@@ -14,13 +15,12 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
-#include "clang/AST/RecordLayout.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/SemaDiagnostic.h"
-#include "llvm/Support/Format.h"
#include "llvm/ADT/SmallSet.h"
-#include "llvm/Support/MathExtras.h"
#include "llvm/Support/CrashRecoveryContext.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MathExtras.h"
using namespace clang;
@@ -676,8 +676,12 @@ protected:
bool FieldPacked, const FieldDecl *D);
void LayoutBitField(const FieldDecl *D);
+ TargetCXXABI getCXXABI() const {
+ return Context.getTargetInfo().getCXXABI();
+ }
+
bool isMicrosoftCXXABI() const {
- return Context.getTargetInfo().getCXXABI() == CXXABI_Microsoft;
+ return getCXXABI().isMicrosoft();
}
void MSLayoutVirtualBases(const CXXRecordDecl *RD);
@@ -791,8 +795,6 @@ protected:
RecordLayoutBuilder(const RecordLayoutBuilder &) LLVM_DELETED_FUNCTION;
void operator=(const RecordLayoutBuilder &) LLVM_DELETED_FUNCTION;
-public:
- static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD);
};
} // end anonymous namespace
@@ -2343,8 +2345,8 @@ void RecordLayoutBuilder::CheckFieldPadding(uint64_t Offset,
<< D->getIdentifier();
}
-const CXXMethodDecl *
-RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
+static const CXXMethodDecl *computeKeyFunction(ASTContext &Context,
+ const CXXRecordDecl *RD) {
// If a class isn't polymorphic it doesn't have a key function.
if (!RD->isPolymorphic())
return 0;
@@ -2362,6 +2364,9 @@ RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
TSK == TSK_ExplicitInstantiationDefinition)
return 0;
+ bool allowInlineFunctions =
+ Context.getTargetInfo().getCXXABI().canKeyFunctionBeInline();
+
for (CXXRecordDecl::method_iterator I = RD->method_begin(),
E = RD->method_end(); I != E; ++I) {
const CXXMethodDecl *MD = *I;
@@ -2387,6 +2392,13 @@ RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
if (!MD->isUserProvided())
continue;
+ // In certain ABIs, ignore functions with out-of-line inline definitions.
+ if (!allowInlineFunctions) {
+ const FunctionDecl *Def;
+ if (MD->hasBody(Def) && Def->isInlineSpecified())
+ continue;
+ }
+
// We found it.
return MD;
}
@@ -2399,6 +2411,48 @@ RecordLayoutBuilder::Diag(SourceLocation Loc, unsigned DiagID) {
return Context.getDiagnostics().Report(Loc, DiagID);
}
+/// Does the target C++ ABI require us to skip over the tail-padding
+/// of the given class (considering it as a base class) when allocating
+/// objects?
+static bool mustSkipTailPadding(TargetCXXABI ABI, const CXXRecordDecl *RD) {
+ switch (ABI.getTailPaddingUseRules()) {
+ case TargetCXXABI::AlwaysUseTailPadding:
+ return false;
+
+ case TargetCXXABI::UseTailPaddingUnlessPOD03:
+ // FIXME: To the extent that this is meant to cover the Itanium ABI
+ // rules, we should implement the restrictions about over-sized
+ // bitfields:
+ //
+ // http://mentorembedded.github.com/cxx-abi/abi.html#POD :
+ // In general, a type is considered a POD for the purposes of
+ // layout if it is a POD type (in the sense of ISO C++
+ // [basic.types]). However, a POD-struct or POD-union (in the
+ // sense of ISO C++ [class]) with a bitfield member whose
+ // declared width is wider than the declared type of the
+ // bitfield is not a POD for the purpose of layout. Similarly,
+ // an array type is not a POD for the purpose of layout if the
+ // element type of the array is not a POD for the purpose of
+ // layout.
+ //
+ // Where references to the ISO C++ are made in this paragraph,
+ // the Technical Corrigendum 1 version of the standard is
+ // intended.
+ return RD->isPOD();
+
+ case TargetCXXABI::UseTailPaddingUnlessPOD11:
+ // This is equivalent to RD->getTypeForDecl().isCXX11PODType(),
+ // but with a lot of abstraction penalty stripped off. This does
+ // assume that these properties are set correctly even in C++98
+ // mode; fortunately, that is true because we want to assign
+ // consistently semantics to the type-traits intrinsics (or at
+ // least as many of them as possible).
+ return RD->isTrivial() && RD->isStandardLayout();
+ }
+
+ llvm_unreachable("bad tail-padding use kind");
+}
+
/// getASTRecordLayout - Get or compute information about the layout of the
/// specified record (struct/union/class), which indicates its size and field
/// position information.
@@ -2443,18 +2497,17 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
Builder.Layout(RD);
}
- // FIXME: This is not always correct. See the part about bitfields at
- // http://www.codesourcery.com/public/cxx-abi/abi.html#POD for more info.
- // FIXME: IsPODForThePurposeOfLayout should be stored in the record layout.
- // This does not affect the calculations of MSVC layouts
- bool IsPODForThePurposeOfLayout =
- (!Builder.isMicrosoftCXXABI() && cast<CXXRecordDecl>(D)->isPOD());
+ // In certain situations, we are allowed to lay out objects in the
+ // tail-padding of base classes. This is ABI-dependent.
+ // FIXME: this should be stored in the record layout.
+ bool skipTailPadding =
+ mustSkipTailPadding(getTargetInfo().getCXXABI(), cast<CXXRecordDecl>(D));
// FIXME: This should be done in FinalizeLayout.
CharUnits DataSize =
- IsPODForThePurposeOfLayout ? Builder.getSize() : Builder.getDataSize();
+ skipTailPadding ? Builder.getSize() : Builder.getDataSize();
CharUnits NonVirtualSize =
- IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize;
+ skipTailPadding ? DataSize : Builder.NonVirtualSize;
NewEntry =
new (*this) ASTRecordLayout(*this, Builder.getSize(),
@@ -2492,15 +2545,37 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
return *NewEntry;
}
-const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) {
+const CXXMethodDecl *ASTContext::getCurrentKeyFunction(const CXXRecordDecl *RD) {
+ assert(RD->getDefinition() && "Cannot get key function for forward decl!");
RD = cast<CXXRecordDecl>(RD->getDefinition());
- assert(RD && "Cannot get key function for forward declarations!");
- const CXXMethodDecl *&Entry = KeyFunctions[RD];
- if (!Entry)
- Entry = RecordLayoutBuilder::ComputeKeyFunction(RD);
+ const CXXMethodDecl *&entry = KeyFunctions[RD];
+ if (!entry) {
+ entry = computeKeyFunction(*this, RD);
+ }
- return Entry;
+ return entry;
+}
+
+void ASTContext::setNonKeyFunction(const CXXMethodDecl *method) {
+ assert(method == method->getFirstDeclaration() &&
+ "not working with method declaration from class definition");
+
+ // Look up the cache entry. Since we're working with the first
+ // declaration, its parent must be the class definition, which is
+ // the correct key for the KeyFunctions hash.
+ llvm::DenseMap<const CXXRecordDecl*, const CXXMethodDecl*>::iterator
+ i = KeyFunctions.find(method->getParent());
+
+ // If it's not cached, there's nothing to do.
+ if (i == KeyFunctions.end()) return;
+
+ // If it is cached, check whether it's the target method, and if so,
+ // remove it from the cache.
+ if (i->second == method) {
+ // FIXME: remember that we did this for module / chained PCH state?
+ KeyFunctions.erase(i);
+ }
}
static uint64_t getFieldOffset(const ASTContext &C, const FieldDecl *FD) {
@@ -2577,6 +2652,11 @@ static void PrintOffset(raw_ostream &OS,
OS.indent(IndentLevel * 2);
}
+static void PrintIndentNoOffset(raw_ostream &OS, unsigned IndentLevel) {
+ OS << " | ";
+ OS.indent(IndentLevel * 2);
+}
+
static void DumpCXXRecordLayout(raw_ostream &OS,
const CXXRecordDecl *RD, const ASTContext &C,
CharUnits Offset,
@@ -2601,7 +2681,7 @@ static void DumpCXXRecordLayout(raw_ostream &OS,
// Vtable pointer.
if (RD->isDynamicClass() && !PrimaryBase &&
- C.getTargetInfo().getCXXABI() != CXXABI_Microsoft) {
+ !C.getTargetInfo().getCXXABI().isMicrosoft()) {
PrintOffset(OS, Offset, IndentLevel);
OS << '(' << *RD << " vtable pointer)\n";
}
@@ -2680,11 +2760,14 @@ static void DumpCXXRecordLayout(raw_ostream &OS,
/*IncludeVirtualBases=*/false);
}
- OS << " sizeof=" << Layout.getSize().getQuantity();
+ PrintIndentNoOffset(OS, IndentLevel - 1);
+ OS << "[sizeof=" << Layout.getSize().getQuantity();
OS << ", dsize=" << Layout.getDataSize().getQuantity();
OS << ", align=" << Layout.getAlignment().getQuantity() << '\n';
- OS << " nvsize=" << Layout.getNonVirtualSize().getQuantity();
- OS << ", nvalign=" << Layout.getNonVirtualAlign().getQuantity() << '\n';
+
+ PrintIndentNoOffset(OS, IndentLevel - 1);
+ OS << " nvsize=" << Layout.getNonVirtualSize().getQuantity();
+ OS << ", nvalign=" << Layout.getNonVirtualAlign().getQuantity() << "]\n";
OS << '\n';
}
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index eafcf92..2ae5a12 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -11,15 +11,17 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/AST/Stmt.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/Type.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/ASTDiagnostic.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/Token.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -46,6 +48,16 @@ static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) {
return StmtClassInfo[E];
}
+void *Stmt::operator new(size_t bytes, ASTContext& C,
+ unsigned alignment) throw() {
+ return ::operator new(bytes, C, alignment);
+}
+
+void *Stmt::operator new(size_t bytes, ASTContext* C,
+ unsigned alignment) throw() {
+ return ::operator new(bytes, *C, alignment);
+}
+
const char *Stmt::getStmtClassName() const {
return getStmtInfoTableEntry((StmtClass) StmtBits.sClass).Name;
}
@@ -131,18 +143,28 @@ namespace {
return bad();
}
- typedef SourceRange getSourceRange_t() const;
- template <class T> good implements_getSourceRange(getSourceRange_t T::*) {
+ typedef SourceLocation getLocStart_t() const;
+ template <class T> good implements_getLocStart(getLocStart_t T::*) {
return good();
}
- static inline bad implements_getSourceRange(getSourceRange_t Stmt::*) {
+ static inline bad implements_getLocStart(getLocStart_t Stmt::*) {
+ return bad();
+ }
+
+ typedef SourceLocation getLocEnd_t() const;
+ template <class T> good implements_getLocEnd(getLocEnd_t T::*) {
+ return good();
+ }
+ static inline bad implements_getLocEnd(getLocEnd_t Stmt::*) {
return bad();
}
#define ASSERT_IMPLEMENTS_children(type) \
(void) sizeof(is_good(implements_children(&type::children)))
-#define ASSERT_IMPLEMENTS_getSourceRange(type) \
- (void) sizeof(is_good(implements_getSourceRange(&type::getSourceRange)))
+#define ASSERT_IMPLEMENTS_getLocStart(type) \
+ (void) sizeof(is_good(implements_getLocStart(&type::getLocStart)))
+#define ASSERT_IMPLEMENTS_getLocEnd(type) \
+ (void) sizeof(is_good(implements_getLocEnd(&type::getLocEnd)))
}
/// Check whether the various Stmt classes implement their member
@@ -151,7 +173,8 @@ static inline void check_implementations() {
#define ABSTRACT_STMT(type)
#define STMT(type, base) \
ASSERT_IMPLEMENTS_children(type); \
- ASSERT_IMPLEMENTS_getSourceRange(type);
+ ASSERT_IMPLEMENTS_getLocStart(type); \
+ ASSERT_IMPLEMENTS_getLocEnd(type);
#include "clang/AST/StmtNodes.inc"
}
@@ -167,67 +190,51 @@ Stmt::child_range Stmt::children() {
llvm_unreachable("unknown statement kind!");
}
-SourceRange Stmt::getSourceRange() const {
- switch (getStmtClass()) {
- case Stmt::NoStmtClass: llvm_unreachable("statement without class");
-#define ABSTRACT_STMT(type)
-#define STMT(type, base) \
- case Stmt::type##Class: \
- return static_cast<const type*>(this)->getSourceRange();
-#include "clang/AST/StmtNodes.inc"
- }
- llvm_unreachable("unknown statement kind!");
-}
-
// Amusing macro metaprogramming hack: check whether a class provides
-// a more specific implementation of getLocStart() and getLocEnd().
+// a more specific implementation of getSourceRange.
//
// See also Expr.cpp:getExprLoc().
namespace {
/// This implementation is used when a class provides a custom
- /// implementation of getLocStart.
+ /// implementation of getSourceRange.
template <class S, class T>
- SourceLocation getLocStartImpl(const Stmt *stmt,
- SourceLocation (T::*v)() const) {
- return static_cast<const S*>(stmt)->getLocStart();
+ SourceRange getSourceRangeImpl(const Stmt *stmt,
+ SourceRange (T::*v)() const) {
+ return static_cast<const S*>(stmt)->getSourceRange();
}
/// This implementation is used when a class doesn't provide a custom
- /// implementation of getLocStart. Overload resolution should pick it over
+ /// implementation of getSourceRange. Overload resolution should pick it over
/// the implementation above because it's more specialized according to
/// function template partial ordering.
template <class S>
- SourceLocation getLocStartImpl(const Stmt *stmt,
- SourceLocation (Stmt::*v)() const) {
- return static_cast<const S*>(stmt)->getSourceRange().getBegin();
- }
-
- /// This implementation is used when a class provides a custom
- /// implementation of getLocEnd.
- template <class S, class T>
- SourceLocation getLocEndImpl(const Stmt *stmt,
- SourceLocation (T::*v)() const) {
- return static_cast<const S*>(stmt)->getLocEnd();
+ SourceRange getSourceRangeImpl(const Stmt *stmt,
+ SourceRange (Stmt::*v)() const) {
+ return SourceRange(static_cast<const S*>(stmt)->getLocStart(),
+ static_cast<const S*>(stmt)->getLocEnd());
}
+}
- /// This implementation is used when a class doesn't provide a custom
- /// implementation of getLocEnd. Overload resolution should pick it over
- /// the implementation above because it's more specialized according to
- /// function template partial ordering.
- template <class S>
- SourceLocation getLocEndImpl(const Stmt *stmt,
- SourceLocation (Stmt::*v)() const) {
- return static_cast<const S*>(stmt)->getSourceRange().getEnd();
+SourceRange Stmt::getSourceRange() const {
+ switch (getStmtClass()) {
+ case Stmt::NoStmtClass: llvm_unreachable("statement without class");
+#define ABSTRACT_STMT(type)
+#define STMT(type, base) \
+ case Stmt::type##Class: \
+ return getSourceRangeImpl<type>(this, &type::getSourceRange);
+#include "clang/AST/StmtNodes.inc"
}
+ llvm_unreachable("unknown statement kind!");
}
SourceLocation Stmt::getLocStart() const {
+// llvm::errs() << "getLocStart() for " << getStmtClassName() << "\n";
switch (getStmtClass()) {
case Stmt::NoStmtClass: llvm_unreachable("statement without class");
#define ABSTRACT_STMT(type)
#define STMT(type, base) \
case Stmt::type##Class: \
- return getLocStartImpl<type>(this, &type::getLocStart);
+ return static_cast<const type*>(this)->getLocStart();
#include "clang/AST/StmtNodes.inc"
}
llvm_unreachable("unknown statement kind");
@@ -239,26 +246,26 @@ SourceLocation Stmt::getLocEnd() const {
#define ABSTRACT_STMT(type)
#define STMT(type, base) \
case Stmt::type##Class: \
- return getLocEndImpl<type>(this, &type::getLocEnd);
+ return static_cast<const type*>(this)->getLocEnd();
#include "clang/AST/StmtNodes.inc"
}
llvm_unreachable("unknown statement kind");
}
-CompoundStmt::CompoundStmt(ASTContext &C, Stmt **StmtStart, unsigned NumStmts,
+CompoundStmt::CompoundStmt(ASTContext &C, ArrayRef<Stmt*> Stmts,
SourceLocation LB, SourceLocation RB)
: Stmt(CompoundStmtClass), LBracLoc(LB), RBracLoc(RB) {
- CompoundStmtBits.NumStmts = NumStmts;
- assert(CompoundStmtBits.NumStmts == NumStmts &&
+ CompoundStmtBits.NumStmts = Stmts.size();
+ assert(CompoundStmtBits.NumStmts == Stmts.size() &&
"NumStmts doesn't fit in bits of CompoundStmtBits.NumStmts!");
- if (NumStmts == 0) {
+ if (Stmts.size() == 0) {
Body = 0;
return;
}
- Body = new (C) Stmt*[NumStmts];
- memcpy(Body, StmtStart, NumStmts * sizeof(*Body));
+ Body = new (C) Stmt*[Stmts.size()];
+ std::copy(Stmts.begin(), Stmts.end(), Body);
}
void CompoundStmt::setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts) {
@@ -291,14 +298,6 @@ AttributedStmt *AttributedStmt::CreateEmpty(ASTContext &C, unsigned NumAttrs) {
return new (Mem) AttributedStmt(EmptyShell(), NumAttrs);
}
-// This is defined here to avoid polluting Stmt.h with importing Expr.h
-SourceRange ReturnStmt::getSourceRange() const {
- if (RetExpr)
- return SourceRange(RetLoc, RetExpr->getLocEnd());
- else
- return SourceRange(RetLoc);
-}
-
bool Stmt::hasImplicitControlFlow() const {
switch (StmtBits.sClass) {
default:
@@ -541,7 +540,7 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
// Handle %x4 and %x[foo] by capturing x as the modifier character.
char Modifier = '\0';
- if (isalpha(EscapedChar)) {
+ if (isLetter(EscapedChar)) {
if (CurPtr == StrEnd) { // Premature end.
DiagOffs = CurPtr-StrStart-1;
return diag::err_asm_invalid_escape;
@@ -550,12 +549,12 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
EscapedChar = *CurPtr++;
}
- if (isdigit(EscapedChar)) {
+ if (isDigit(EscapedChar)) {
// %n - Assembler operand n
unsigned N = 0;
--CurPtr;
- while (CurPtr != StrEnd && isdigit(*CurPtr))
+ while (CurPtr != StrEnd && isDigit(*CurPtr))
N = N*10 + ((*CurPtr++)-'0');
unsigned NumOperands =
@@ -762,26 +761,21 @@ ObjCAtTryStmt *ObjCAtTryStmt::CreateEmpty(ASTContext &Context,
return new (Mem) ObjCAtTryStmt(EmptyShell(), NumCatchStmts, HasFinally);
}
-SourceRange ObjCAtTryStmt::getSourceRange() const {
- SourceLocation EndLoc;
+SourceLocation ObjCAtTryStmt::getLocEnd() const {
if (HasFinally)
- EndLoc = getFinallyStmt()->getLocEnd();
- else if (NumCatchStmts)
- EndLoc = getCatchStmt(NumCatchStmts - 1)->getLocEnd();
- else
- EndLoc = getTryBody()->getLocEnd();
-
- return SourceRange(AtTryLoc, EndLoc);
+ return getFinallyStmt()->getLocEnd();
+ if (NumCatchStmts)
+ return getCatchStmt(NumCatchStmts - 1)->getLocEnd();
+ return getTryBody()->getLocEnd();
}
CXXTryStmt *CXXTryStmt::Create(ASTContext &C, SourceLocation tryLoc,
- Stmt *tryBlock, Stmt **handlers,
- unsigned numHandlers) {
+ Stmt *tryBlock, ArrayRef<Stmt*> handlers) {
std::size_t Size = sizeof(CXXTryStmt);
- Size += ((numHandlers + 1) * sizeof(Stmt));
+ Size += ((handlers.size() + 1) * sizeof(Stmt));
void *Mem = C.Allocate(Size, llvm::alignOf<CXXTryStmt>());
- return new (Mem) CXXTryStmt(tryLoc, tryBlock, handlers, numHandlers);
+ return new (Mem) CXXTryStmt(tryLoc, tryBlock, handlers);
}
CXXTryStmt *CXXTryStmt::Create(ASTContext &C, EmptyShell Empty,
@@ -794,11 +788,11 @@ CXXTryStmt *CXXTryStmt::Create(ASTContext &C, EmptyShell Empty,
}
CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock,
- Stmt **handlers, unsigned numHandlers)
- : Stmt(CXXTryStmtClass), TryLoc(tryLoc), NumHandlers(numHandlers) {
+ ArrayRef<Stmt*> handlers)
+ : Stmt(CXXTryStmtClass), TryLoc(tryLoc), NumHandlers(handlers.size()) {
Stmt **Stmts = reinterpret_cast<Stmt **>(this + 1);
Stmts[0] = tryBlock;
- std::copy(handlers, handlers + NumHandlers, Stmts + 1);
+ std::copy(handlers.begin(), handlers.end(), Stmts + 1);
}
CXXForRangeStmt::CXXForRangeStmt(DeclStmt *Range, DeclStmt *BeginEndStmt,
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
deleted file mode 100644
index fbc990f..0000000
--- a/lib/AST/StmtDumper.cpp
+++ /dev/null
@@ -1,760 +0,0 @@
-//===--- StmtDumper.cpp - Dumping implementation for Stmt ASTs ------------===//
-//
-// 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 Stmt::dump method, which dumps out the
-// AST in a form that exposes type details and other fields.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/AST/StmtVisitor.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/PrettyPrinter.h"
-#include "clang/Basic/SourceManager.h"
-#include "llvm/Support/raw_ostream.h"
-using namespace clang;
-
-//===----------------------------------------------------------------------===//
-// StmtDumper Visitor
-//===----------------------------------------------------------------------===//
-
-namespace {
- class StmtDumper : public StmtVisitor<StmtDumper> {
- SourceManager *SM;
- raw_ostream &OS;
- unsigned IndentLevel;
- bool IsFirstLine;
-
- /// MaxDepth - When doing a normal dump (not dumpAll) we only want to dump
- /// the first few levels of an AST. This keeps track of how many ast levels
- /// are left.
- unsigned MaxDepth;
-
- /// LastLocFilename/LastLocLine - Keep track of the last location we print
- /// out so that we can print out deltas from then on out.
- const char *LastLocFilename;
- unsigned LastLocLine;
-
- class IndentScope {
- StmtDumper &Dumper;
- public:
- IndentScope(StmtDumper &Dumper) : Dumper(Dumper) {
- Dumper.indent();
- }
- ~IndentScope() {
- Dumper.unindent();
- }
- };
-
- public:
- StmtDumper(SourceManager *sm, raw_ostream &os, unsigned maxDepth)
- : SM(sm), OS(os), IndentLevel(0), IsFirstLine(true), MaxDepth(maxDepth) {
- LastLocFilename = "";
- LastLocLine = ~0U;
- }
-
- ~StmtDumper() {
- OS << "\n";
- }
-
- void DumpSubTree(Stmt *S) {
- // Prune the recursion if not using dump all.
- if (MaxDepth == 0) return;
-
- IndentScope Indent(*this);
-
- if (!S) {
- OS << "<<<NULL>>>";
- return;
- }
-
- if (DeclStmt* DS = dyn_cast<DeclStmt>(S)) {
- VisitDeclStmt(DS);
- return;
- }
-
- Visit(S);
- for (Stmt::child_range CI = S->children(); CI; CI++)
- DumpSubTree(*CI);
- }
-
- void DumpDeclarator(Decl *D);
-
- void indent() {
- if (IsFirstLine)
- IsFirstLine = false;
- else
- OS << "\n";
- OS.indent(IndentLevel * 2);
- OS << "(";
- IndentLevel++;
- }
-
- void unindent() {
- OS << ")";
- IndentLevel--;
- }
-
- void DumpType(QualType T) {
- SplitQualType T_split = T.split();
- OS << "'" << QualType::getAsString(T_split) << "'";
-
- if (!T.isNull()) {
- // If the type is sugared, also dump a (shallow) desugared type.
- SplitQualType D_split = T.getSplitDesugaredType();
- if (T_split != D_split)
- OS << ":'" << QualType::getAsString(D_split) << "'";
- }
- }
- void DumpDeclRef(Decl *node);
- void DumpStmt(const Stmt *Node) {
- OS << Node->getStmtClassName()
- << " " << (const void*)Node;
- DumpSourceRange(Node);
- }
- void DumpValueKind(ExprValueKind K) {
- switch (K) {
- case VK_RValue: break;
- case VK_LValue: OS << " lvalue"; break;
- case VK_XValue: OS << " xvalue"; break;
- }
- }
- void DumpObjectKind(ExprObjectKind K) {
- switch (K) {
- case OK_Ordinary: break;
- case OK_BitField: OS << " bitfield"; break;
- case OK_ObjCProperty: OS << " objcproperty"; break;
- case OK_ObjCSubscript: OS << " objcsubscript"; break;
- case OK_VectorComponent: OS << " vectorcomponent"; break;
- }
- }
- void DumpExpr(const Expr *Node) {
- DumpStmt(Node);
- OS << ' ';
- DumpType(Node->getType());
- DumpValueKind(Node->getValueKind());
- DumpObjectKind(Node->getObjectKind());
- }
- void DumpSourceRange(const Stmt *Node);
- void DumpLocation(SourceLocation Loc);
-
- // Stmts.
- void VisitStmt(Stmt *Node);
- void VisitDeclStmt(DeclStmt *Node);
- void VisitLabelStmt(LabelStmt *Node);
- void VisitGotoStmt(GotoStmt *Node);
-
- // Exprs
- void VisitExpr(Expr *Node);
- void VisitCastExpr(CastExpr *Node);
- void VisitDeclRefExpr(DeclRefExpr *Node);
- void VisitPredefinedExpr(PredefinedExpr *Node);
- void VisitCharacterLiteral(CharacterLiteral *Node);
- void VisitIntegerLiteral(IntegerLiteral *Node);
- void VisitFloatingLiteral(FloatingLiteral *Node);
- void VisitStringLiteral(StringLiteral *Str);
- void VisitUnaryOperator(UnaryOperator *Node);
- void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node);
- void VisitMemberExpr(MemberExpr *Node);
- void VisitExtVectorElementExpr(ExtVectorElementExpr *Node);
- void VisitBinaryOperator(BinaryOperator *Node);
- void VisitCompoundAssignOperator(CompoundAssignOperator *Node);
- void VisitAddrLabelExpr(AddrLabelExpr *Node);
- void VisitBlockExpr(BlockExpr *Node);
- void VisitOpaqueValueExpr(OpaqueValueExpr *Node);
-
- // C++
- void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node);
- void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node);
- void VisitCXXThisExpr(CXXThisExpr *Node);
- void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node);
- void VisitCXXConstructExpr(CXXConstructExpr *Node);
- void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node);
- void VisitExprWithCleanups(ExprWithCleanups *Node);
- void VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node);
- void DumpCXXTemporary(CXXTemporary *Temporary);
-
- // ObjC
- void VisitObjCAtCatchStmt(ObjCAtCatchStmt *Node);
- void VisitObjCEncodeExpr(ObjCEncodeExpr *Node);
- void VisitObjCMessageExpr(ObjCMessageExpr* Node);
- void VisitObjCBoxedExpr(ObjCBoxedExpr* Node);
- void VisitObjCSelectorExpr(ObjCSelectorExpr *Node);
- void VisitObjCProtocolExpr(ObjCProtocolExpr *Node);
- void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node);
- void VisitObjCSubscriptRefExpr(ObjCSubscriptRefExpr *Node);
- void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node);
- void VisitObjCBoolLiteralExpr(ObjCBoolLiteralExpr *Node);
- };
-}
-
-//===----------------------------------------------------------------------===//
-// Utilities
-//===----------------------------------------------------------------------===//
-
-void StmtDumper::DumpLocation(SourceLocation Loc) {
- SourceLocation SpellingLoc = SM->getSpellingLoc(Loc);
-
- // The general format we print out is filename:line:col, but we drop pieces
- // that haven't changed since the last loc printed.
- PresumedLoc PLoc = SM->getPresumedLoc(SpellingLoc);
-
- if (PLoc.isInvalid()) {
- OS << "<invalid sloc>";
- return;
- }
-
- if (strcmp(PLoc.getFilename(), LastLocFilename) != 0) {
- OS << PLoc.getFilename() << ':' << PLoc.getLine()
- << ':' << PLoc.getColumn();
- LastLocFilename = PLoc.getFilename();
- LastLocLine = PLoc.getLine();
- } else if (PLoc.getLine() != LastLocLine) {
- OS << "line" << ':' << PLoc.getLine()
- << ':' << PLoc.getColumn();
- LastLocLine = PLoc.getLine();
- } else {
- OS << "col" << ':' << PLoc.getColumn();
- }
-}
-
-void StmtDumper::DumpSourceRange(const Stmt *Node) {
- // Can't translate locations if a SourceManager isn't available.
- if (SM == 0) return;
-
- // TODO: If the parent expression is available, we can print a delta vs its
- // location.
- SourceRange R = Node->getSourceRange();
-
- OS << " <";
- DumpLocation(R.getBegin());
- if (R.getBegin() != R.getEnd()) {
- OS << ", ";
- DumpLocation(R.getEnd());
- }
- OS << ">";
-
- // <t2.c:123:421[blah], t2.c:412:321>
-
-}
-
-
-//===----------------------------------------------------------------------===//
-// Stmt printing methods.
-//===----------------------------------------------------------------------===//
-
-void StmtDumper::VisitStmt(Stmt *Node) {
- DumpStmt(Node);
-}
-
-void StmtDumper::DumpDeclarator(Decl *D) {
- // FIXME: Need to complete/beautify this... this code simply shows the
- // nodes are where they need to be.
- if (TypedefDecl *localType = dyn_cast<TypedefDecl>(D)) {
- OS << "\"typedef " << localType->getUnderlyingType().getAsString()
- << ' ' << *localType << '"';
- } else if (TypeAliasDecl *localType = dyn_cast<TypeAliasDecl>(D)) {
- OS << "\"using " << *localType << " = "
- << localType->getUnderlyingType().getAsString() << '"';
- } else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
- OS << "\"";
- // Emit storage class for vardecls.
- if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
- if (V->getStorageClass() != SC_None)
- OS << VarDecl::getStorageClassSpecifierString(V->getStorageClass())
- << " ";
- }
-
- std::string Name = VD->getNameAsString();
- VD->getType().getAsStringInternal(Name,
- PrintingPolicy(VD->getASTContext().getLangOpts()));
- OS << Name;
-
- // If this is a vardecl with an initializer, emit it.
- if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
- if (V->getInit()) {
- OS << " =";
- DumpSubTree(V->getInit());
- }
- }
- OS << '"';
- } else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
- // print a free standing tag decl (e.g. "struct x;").
- const char *tagname;
- if (const IdentifierInfo *II = TD->getIdentifier())
- tagname = II->getNameStart();
- else
- tagname = "<anonymous>";
- OS << '"' << TD->getKindName() << ' ' << tagname << ";\"";
- // FIXME: print tag bodies.
- } else if (UsingDirectiveDecl *UD = dyn_cast<UsingDirectiveDecl>(D)) {
- // print using-directive decl (e.g. "using namespace x;")
- const char *ns;
- if (const IdentifierInfo *II = UD->getNominatedNamespace()->getIdentifier())
- ns = II->getNameStart();
- else
- ns = "<anonymous>";
- OS << '"' << UD->getDeclKindName() << ns << ";\"";
- } else if (UsingDecl *UD = dyn_cast<UsingDecl>(D)) {
- // print using decl (e.g. "using std::string;")
- const char *tn = UD->isTypeName() ? "typename " : "";
- OS << '"' << UD->getDeclKindName() << tn;
- UD->getQualifier()->print(OS,
- PrintingPolicy(UD->getASTContext().getLangOpts()));
- OS << ";\"";
- } else if (LabelDecl *LD = dyn_cast<LabelDecl>(D)) {
- OS << "label " << *LD;
- } else if (StaticAssertDecl *SAD = dyn_cast<StaticAssertDecl>(D)) {
- OS << "\"static_assert(";
- DumpSubTree(SAD->getAssertExpr());
- OS << ",";
- DumpSubTree(SAD->getMessage());
- OS << ");\"";
- } else {
- llvm_unreachable("Unexpected decl");
- }
-}
-
-void StmtDumper::VisitDeclStmt(DeclStmt *Node) {
- DumpStmt(Node);
- for (DeclStmt::decl_iterator DI = Node->decl_begin(), DE = Node->decl_end();
- DI != DE; ++DI) {
- IndentScope Indent(*this);
- Decl* D = *DI;
- OS << (void*) D << " ";
- DumpDeclarator(D);
- }
-}
-
-void StmtDumper::VisitLabelStmt(LabelStmt *Node) {
- DumpStmt(Node);
- OS << " '" << Node->getName() << "'";
-}
-
-void StmtDumper::VisitGotoStmt(GotoStmt *Node) {
- DumpStmt(Node);
- OS << " '" << Node->getLabel()->getName()
- << "':" << (void*)Node->getLabel();
-}
-
-//===----------------------------------------------------------------------===//
-// Expr printing methods.
-//===----------------------------------------------------------------------===//
-
-void StmtDumper::VisitExpr(Expr *Node) {
- DumpExpr(Node);
-}
-
-static void DumpBasePath(raw_ostream &OS, CastExpr *Node) {
- if (Node->path_empty())
- return;
-
- OS << " (";
- bool First = true;
- for (CastExpr::path_iterator
- I = Node->path_begin(), E = Node->path_end(); I != E; ++I) {
- const CXXBaseSpecifier *Base = *I;
- if (!First)
- OS << " -> ";
-
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
-
- if (Base->isVirtual())
- OS << "virtual ";
- OS << RD->getName();
- First = false;
- }
-
- OS << ')';
-}
-
-void StmtDumper::VisitCastExpr(CastExpr *Node) {
- DumpExpr(Node);
- OS << " <" << Node->getCastKindName();
- DumpBasePath(OS, Node);
- OS << ">";
-}
-
-void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) {
- DumpExpr(Node);
-
- OS << " ";
- DumpDeclRef(Node->getDecl());
- if (Node->getDecl() != Node->getFoundDecl()) {
- OS << " (";
- DumpDeclRef(Node->getFoundDecl());
- OS << ")";
- }
-}
-
-void StmtDumper::DumpDeclRef(Decl *d) {
- OS << d->getDeclKindName() << ' ' << (void*) d;
-
- if (NamedDecl *nd = dyn_cast<NamedDecl>(d)) {
- OS << " '";
- nd->getDeclName().printName(OS);
- OS << "'";
- }
-
- if (ValueDecl *vd = dyn_cast<ValueDecl>(d)) {
- OS << ' '; DumpType(vd->getType());
- }
-}
-
-void StmtDumper::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) {
- DumpExpr(Node);
- OS << " (";
- if (!Node->requiresADL()) OS << "no ";
- OS << "ADL) = '" << Node->getName() << '\'';
-
- UnresolvedLookupExpr::decls_iterator
- I = Node->decls_begin(), E = Node->decls_end();
- if (I == E) OS << " empty";
- for (; I != E; ++I)
- OS << " " << (void*) *I;
-}
-
-void StmtDumper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
- DumpExpr(Node);
-
- OS << " " << Node->getDecl()->getDeclKindName()
- << "Decl='" << *Node->getDecl()
- << "' " << (void*)Node->getDecl();
- if (Node->isFreeIvar())
- OS << " isFreeIvar";
-}
-
-void StmtDumper::VisitPredefinedExpr(PredefinedExpr *Node) {
- DumpExpr(Node);
- switch (Node->getIdentType()) {
- default: llvm_unreachable("unknown case");
- case PredefinedExpr::Func: OS << " __func__"; break;
- case PredefinedExpr::Function: OS << " __FUNCTION__"; break;
- case PredefinedExpr::LFunction: OS << " L__FUNCTION__"; break;
- case PredefinedExpr::PrettyFunction: OS << " __PRETTY_FUNCTION__";break;
- }
-}
-
-void StmtDumper::VisitCharacterLiteral(CharacterLiteral *Node) {
- DumpExpr(Node);
- OS << " " << Node->getValue();
-}
-
-void StmtDumper::VisitIntegerLiteral(IntegerLiteral *Node) {
- DumpExpr(Node);
-
- bool isSigned = Node->getType()->isSignedIntegerType();
- OS << " " << Node->getValue().toString(10, isSigned);
-}
-void StmtDumper::VisitFloatingLiteral(FloatingLiteral *Node) {
- DumpExpr(Node);
- OS << " " << Node->getValueAsApproximateDouble();
-}
-
-void StmtDumper::VisitStringLiteral(StringLiteral *Str) {
- DumpExpr(Str);
- OS << " ";
- Str->outputString(OS);
-}
-
-void StmtDumper::VisitUnaryOperator(UnaryOperator *Node) {
- DumpExpr(Node);
- OS << " " << (Node->isPostfix() ? "postfix" : "prefix")
- << " '" << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'";
-}
-void StmtDumper::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node) {
- DumpExpr(Node);
- switch(Node->getKind()) {
- case UETT_SizeOf:
- OS << " sizeof ";
- break;
- case UETT_AlignOf:
- OS << " alignof ";
- break;
- case UETT_VecStep:
- OS << " vec_step ";
- break;
- }
- if (Node->isArgumentType())
- DumpType(Node->getArgumentType());
-}
-
-void StmtDumper::VisitMemberExpr(MemberExpr *Node) {
- DumpExpr(Node);
- OS << " " << (Node->isArrow() ? "->" : ".")
- << *Node->getMemberDecl() << ' '
- << (void*)Node->getMemberDecl();
-}
-void StmtDumper::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
- DumpExpr(Node);
- OS << " " << Node->getAccessor().getNameStart();
-}
-void StmtDumper::VisitBinaryOperator(BinaryOperator *Node) {
- DumpExpr(Node);
- OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode()) << "'";
-}
-void StmtDumper::VisitCompoundAssignOperator(CompoundAssignOperator *Node) {
- DumpExpr(Node);
- OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode())
- << "' ComputeLHSTy=";
- DumpType(Node->getComputationLHSType());
- OS << " ComputeResultTy=";
- DumpType(Node->getComputationResultType());
-}
-
-void StmtDumper::VisitBlockExpr(BlockExpr *Node) {
- DumpExpr(Node);
-
- BlockDecl *block = Node->getBlockDecl();
- OS << " decl=" << block;
-
- if (block->capturesCXXThis()) {
- IndentScope Indent(*this);
- OS << "capture this";
- }
- for (BlockDecl::capture_iterator
- i = block->capture_begin(), e = block->capture_end(); i != e; ++i) {
- IndentScope Indent(*this);
- OS << "capture ";
- if (i->isByRef()) OS << "byref ";
- if (i->isNested()) OS << "nested ";
- if (i->getVariable())
- DumpDeclRef(i->getVariable());
- if (i->hasCopyExpr()) DumpSubTree(i->getCopyExpr());
- }
-
- DumpSubTree(block->getBody());
-}
-
-void StmtDumper::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {
- DumpExpr(Node);
-
- if (Expr *Source = Node->getSourceExpr())
- DumpSubTree(Source);
-}
-
-// GNU extensions.
-
-void StmtDumper::VisitAddrLabelExpr(AddrLabelExpr *Node) {
- DumpExpr(Node);
- OS << " " << Node->getLabel()->getName()
- << " " << (void*)Node->getLabel();
-}
-
-//===----------------------------------------------------------------------===//
-// C++ Expressions
-//===----------------------------------------------------------------------===//
-
-void StmtDumper::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) {
- DumpExpr(Node);
- OS << " " << Node->getCastName()
- << "<" << Node->getTypeAsWritten().getAsString() << ">"
- << " <" << Node->getCastKindName();
- DumpBasePath(OS, Node);
- OS << ">";
-}
-
-void StmtDumper::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) {
- DumpExpr(Node);
- OS << " " << (Node->getValue() ? "true" : "false");
-}
-
-void StmtDumper::VisitCXXThisExpr(CXXThisExpr *Node) {
- DumpExpr(Node);
- OS << " this";
-}
-
-void StmtDumper::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) {
- DumpExpr(Node);
- OS << " functional cast to " << Node->getTypeAsWritten().getAsString()
- << " <" << Node->getCastKindName() << ">";
-}
-
-void StmtDumper::VisitCXXConstructExpr(CXXConstructExpr *Node) {
- DumpExpr(Node);
- CXXConstructorDecl *Ctor = Node->getConstructor();
- DumpType(Ctor->getType());
- if (Node->isElidable())
- OS << " elidable";
- if (Node->requiresZeroInitialization())
- OS << " zeroing";
-}
-
-void StmtDumper::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) {
- DumpExpr(Node);
- OS << " ";
- DumpCXXTemporary(Node->getTemporary());
-}
-
-void StmtDumper::VisitExprWithCleanups(ExprWithCleanups *Node) {
- DumpExpr(Node);
- for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i) {
- IndentScope Indent(*this);
- OS << "cleanup ";
- DumpDeclRef(Node->getObject(i));
- }
-}
-
-void StmtDumper::DumpCXXTemporary(CXXTemporary *Temporary) {
- OS << "(CXXTemporary " << (void *)Temporary << ")";
-}
-
-//===----------------------------------------------------------------------===//
-// Obj-C Expressions
-//===----------------------------------------------------------------------===//
-
-void StmtDumper::VisitObjCMessageExpr(ObjCMessageExpr* Node) {
- DumpExpr(Node);
- OS << " selector=" << Node->getSelector().getAsString();
- switch (Node->getReceiverKind()) {
- case ObjCMessageExpr::Instance:
- break;
-
- case ObjCMessageExpr::Class:
- OS << " class=";
- DumpType(Node->getClassReceiver());
- break;
-
- case ObjCMessageExpr::SuperInstance:
- OS << " super (instance)";
- break;
-
- case ObjCMessageExpr::SuperClass:
- OS << " super (class)";
- break;
- }
-}
-
-void StmtDumper::VisitObjCBoxedExpr(ObjCBoxedExpr* Node) {
- DumpExpr(Node);
- OS << " selector=" << Node->getBoxingMethod()->getSelector().getAsString();
-}
-
-void StmtDumper::VisitObjCAtCatchStmt(ObjCAtCatchStmt *Node) {
- DumpStmt(Node);
- if (VarDecl *CatchParam = Node->getCatchParamDecl()) {
- OS << " catch parm = ";
- DumpDeclarator(CatchParam);
- } else {
- OS << " catch all";
- }
-}
-
-void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
- DumpExpr(Node);
- OS << " ";
- DumpType(Node->getEncodedType());
-}
-
-void StmtDumper::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) {
- DumpExpr(Node);
-
- OS << " " << Node->getSelector().getAsString();
-}
-
-void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) {
- DumpExpr(Node);
-
- OS << ' ' <<* Node->getProtocol();
-}
-
-void StmtDumper::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
- DumpExpr(Node);
- if (Node->isImplicitProperty()) {
- OS << " Kind=MethodRef Getter=\"";
- if (Node->getImplicitPropertyGetter())
- OS << Node->getImplicitPropertyGetter()->getSelector().getAsString();
- else
- OS << "(null)";
-
- OS << "\" Setter=\"";
- if (ObjCMethodDecl *Setter = Node->getImplicitPropertySetter())
- OS << Setter->getSelector().getAsString();
- else
- OS << "(null)";
- OS << "\"";
- } else {
- OS << " Kind=PropertyRef Property=\"" << *Node->getExplicitProperty() <<'"';
- }
-
- if (Node->isSuperReceiver())
- OS << " super";
-
- OS << " Messaging=";
- if (Node->isMessagingGetter() && Node->isMessagingSetter())
- OS << "Getter&Setter";
- else if (Node->isMessagingGetter())
- OS << "Getter";
- else if (Node->isMessagingSetter())
- OS << "Setter";
-}
-
-void StmtDumper::VisitObjCSubscriptRefExpr(ObjCSubscriptRefExpr *Node) {
- DumpExpr(Node);
- if (Node->isArraySubscriptRefExpr())
- OS << " Kind=ArraySubscript GetterForArray=\"";
- else
- OS << " Kind=DictionarySubscript GetterForDictionary=\"";
- if (Node->getAtIndexMethodDecl())
- OS << Node->getAtIndexMethodDecl()->getSelector().getAsString();
- else
- OS << "(null)";
-
- if (Node->isArraySubscriptRefExpr())
- OS << "\" SetterForArray=\"";
- else
- OS << "\" SetterForDictionary=\"";
- if (Node->setAtIndexMethodDecl())
- OS << Node->setAtIndexMethodDecl()->getSelector().getAsString();
- else
- OS << "(null)";
-}
-
-void StmtDumper::VisitObjCBoolLiteralExpr(ObjCBoolLiteralExpr *Node) {
- DumpExpr(Node);
- OS << " " << (Node->getValue() ? "__objc_yes" : "__objc_no");
-}
-
-//===----------------------------------------------------------------------===//
-// Stmt method implementations
-//===----------------------------------------------------------------------===//
-
-/// dump - This does a local dump of the specified AST fragment. It dumps the
-/// specified node and a few nodes underneath it, but not the whole subtree.
-/// This is useful in a debugger.
-void Stmt::dump(SourceManager &SM) const {
- dump(llvm::errs(), SM);
-}
-
-void Stmt::dump(raw_ostream &OS, SourceManager &SM) const {
- StmtDumper P(&SM, OS, 4);
- P.DumpSubTree(const_cast<Stmt*>(this));
-}
-
-/// dump - This does a local dump of the specified AST fragment. It dumps the
-/// specified node and a few nodes underneath it, but not the whole subtree.
-/// This is useful in a debugger.
-void Stmt::dump() const {
- StmtDumper P(0, llvm::errs(), 4);
- P.DumpSubTree(const_cast<Stmt*>(this));
-}
-
-/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
-void Stmt::dumpAll(SourceManager &SM) const {
- StmtDumper P(&SM, llvm::errs(), ~0U);
- P.DumpSubTree(const_cast<Stmt*>(this));
-}
-
-/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
-void Stmt::dumpAll() const {
- StmtDumper P(0, llvm::errs(), ~0U);
- P.DumpSubTree(const_cast<Stmt*>(this));
-}
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 57eb1a9..7df7fdb 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -13,14 +13,17 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
-#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/CharInfo.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Format.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -583,10 +586,8 @@ void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) {
OS << "template ";
OS << Node->getNameInfo();
if (Node->hasExplicitTemplateArgs())
- OS << TemplateSpecializationType::PrintTemplateArgumentList(
- Node->getTemplateArgs(),
- Node->getNumTemplateArgs(),
- Policy);
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, Node->getTemplateArgs(), Node->getNumTemplateArgs(), Policy);
}
void StmtPrinter::VisitDependentScopeDeclRefExpr(
@@ -597,10 +598,8 @@ void StmtPrinter::VisitDependentScopeDeclRefExpr(
OS << "template ";
OS << Node->getNameInfo();
if (Node->hasExplicitTemplateArgs())
- OS << TemplateSpecializationType::PrintTemplateArgumentList(
- Node->getTemplateArgs(),
- Node->getNumTemplateArgs(),
- Policy);
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, Node->getTemplateArgs(), Node->getNumTemplateArgs(), Policy);
}
void StmtPrinter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) {
@@ -610,10 +609,8 @@ void StmtPrinter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) {
OS << "template ";
OS << Node->getNameInfo();
if (Node->hasExplicitTemplateArgs())
- OS << TemplateSpecializationType::PrintTemplateArgumentList(
- Node->getTemplateArgs(),
- Node->getNumTemplateArgs(),
- Policy);
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, Node->getTemplateArgs(), Node->getNumTemplateArgs(), Policy);
}
void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
@@ -709,15 +706,14 @@ void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) {
OS << "'\\v'";
break;
default:
- if (value < 256 && isprint(value)) {
+ if (value < 256 && isPrintable((unsigned char)value))
OS << "'" << (char)value << "'";
- } else if (value < 256) {
- OS << "'\\x";
- OS.write_hex(value) << "'";
- } else {
- // FIXME what to really do here?
- OS << value;
- }
+ else if (value < 256)
+ OS << "'\\x" << llvm::format("%02x", value) << "'";
+ else if (value <= 0xFFFF)
+ OS << "'\\u" << llvm::format("%04x", value) << "'";
+ else
+ OS << "'\\U" << llvm::format("%08x", value) << "'";
}
}
@@ -810,7 +806,8 @@ void StmtPrinter::VisitUnaryOperator(UnaryOperator *Node) {
void StmtPrinter::VisitOffsetOfExpr(OffsetOfExpr *Node) {
OS << "__builtin_offsetof(";
- OS << Node->getTypeSourceInfo()->getType().getAsString(Policy) << ", ";
+ Node->getTypeSourceInfo()->getType().print(OS, Policy);
+ OS << ", ";
bool PrintedSomething = false;
for (unsigned i = 0, n = Node->getNumComponents(); i < n; ++i) {
OffsetOfExpr::OffsetOfNode ON = Node->getComponent(i);
@@ -858,9 +855,11 @@ void StmtPrinter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node){
OS << "vec_step";
break;
}
- if (Node->isArgumentType())
- OS << "(" << Node->getArgumentType().getAsString(Policy) << ")";
- else {
+ if (Node->isArgumentType()) {
+ OS << '(';
+ Node->getArgumentType().print(OS, Policy);
+ OS << ')';
+ } else {
OS << " ";
PrintExpr(Node->getArgumentExpr());
}
@@ -875,7 +874,7 @@ void StmtPrinter::VisitGenericSelectionExpr(GenericSelectionExpr *Node) {
if (T.isNull())
OS << "default";
else
- OS << T.getAsString(Policy);
+ T.print(OS, Policy);
OS << ": ";
PrintExpr(Node->getAssocExpr(i));
}
@@ -910,20 +909,26 @@ void StmtPrinter::VisitCallExpr(CallExpr *Call) {
void StmtPrinter::VisitMemberExpr(MemberExpr *Node) {
// FIXME: Suppress printing implicit bases (like "this")
PrintExpr(Node->getBase());
+
+ MemberExpr *ParentMember = dyn_cast<MemberExpr>(Node->getBase());
+ FieldDecl *ParentDecl = ParentMember
+ ? dyn_cast<FieldDecl>(ParentMember->getMemberDecl()) : NULL;
+
+ if (!ParentDecl || !ParentDecl->isAnonymousStructOrUnion())
+ OS << (Node->isArrow() ? "->" : ".");
+
if (FieldDecl *FD = dyn_cast<FieldDecl>(Node->getMemberDecl()))
if (FD->isAnonymousStructOrUnion())
return;
- OS << (Node->isArrow() ? "->" : ".");
+
if (NestedNameSpecifier *Qualifier = Node->getQualifier())
Qualifier->print(OS, Policy);
if (Node->hasTemplateKeyword())
OS << "template ";
OS << Node->getMemberNameInfo();
if (Node->hasExplicitTemplateArgs())
- OS << TemplateSpecializationType::PrintTemplateArgumentList(
- Node->getTemplateArgs(),
- Node->getNumTemplateArgs(),
- Policy);
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, Node->getTemplateArgs(), Node->getNumTemplateArgs(), Policy);
}
void StmtPrinter::VisitObjCIsaExpr(ObjCIsaExpr *Node) {
PrintExpr(Node->getBase());
@@ -936,11 +941,15 @@ void StmtPrinter::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
OS << Node->getAccessor().getName();
}
void StmtPrinter::VisitCStyleCastExpr(CStyleCastExpr *Node) {
- OS << "(" << Node->getTypeAsWritten().getAsString(Policy) << ")";
+ OS << '(';
+ Node->getTypeAsWritten().print(OS, Policy);
+ OS << ')';
PrintExpr(Node->getSubExpr());
}
void StmtPrinter::VisitCompoundLiteralExpr(CompoundLiteralExpr *Node) {
- OS << "(" << Node->getType().getAsString(Policy) << ")";
+ OS << '(';
+ Node->getType().print(OS, Policy);
+ OS << ')';
PrintExpr(Node->getInitializer());
}
void StmtPrinter::VisitImplicitCastExpr(ImplicitCastExpr *Node) {
@@ -1059,10 +1068,14 @@ void StmtPrinter::VisitDesignatedInitExpr(DesignatedInitExpr *Node) {
}
void StmtPrinter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *Node) {
- if (Policy.LangOpts.CPlusPlus)
- OS << "/*implicit*/" << Node->getType().getAsString(Policy) << "()";
- else {
- OS << "/*implicit*/(" << Node->getType().getAsString(Policy) << ")";
+ if (Policy.LangOpts.CPlusPlus) {
+ OS << "/*implicit*/";
+ Node->getType().print(OS, Policy);
+ OS << "()";
+ } else {
+ OS << "/*implicit*/(";
+ Node->getType().print(OS, Policy);
+ OS << ')';
if (Node->getType()->isRecordType())
OS << "{}";
else
@@ -1074,7 +1087,7 @@ void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) {
OS << "__builtin_va_arg(";
PrintExpr(Node->getSubExpr());
OS << ", ";
- OS << Node->getType().getAsString(Policy);
+ Node->getType().print(OS, Policy);
OS << ")";
}
@@ -1183,7 +1196,8 @@ void StmtPrinter::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *Node) {
void StmtPrinter::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) {
OS << Node->getCastName() << '<';
- OS << Node->getTypeAsWritten().getAsString(Policy) << ">(";
+ Node->getTypeAsWritten().print(OS, Policy);
+ OS << ">(";
PrintExpr(Node->getSubExpr());
OS << ")";
}
@@ -1207,7 +1221,7 @@ void StmtPrinter::VisitCXXConstCastExpr(CXXConstCastExpr *Node) {
void StmtPrinter::VisitCXXTypeidExpr(CXXTypeidExpr *Node) {
OS << "typeid(";
if (Node->isTypeOperand()) {
- OS << Node->getTypeOperand().getAsString(Policy);
+ Node->getTypeOperand().print(OS, Policy);
} else {
PrintExpr(Node->getExprOperand());
}
@@ -1217,7 +1231,7 @@ void StmtPrinter::VisitCXXTypeidExpr(CXXTypeidExpr *Node) {
void StmtPrinter::VisitCXXUuidofExpr(CXXUuidofExpr *Node) {
OS << "__uuidof(";
if (Node->isTypeOperand()) {
- OS << Node->getTypeOperand().getAsString(Policy);
+ Node->getTypeOperand().print(OS, Policy);
} else {
PrintExpr(Node->getExprOperand());
}
@@ -1288,7 +1302,7 @@ void StmtPrinter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *Node) {
}
void StmtPrinter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) {
- OS << Node->getType().getAsString(Policy);
+ Node->getType().print(OS, Policy);
OS << "(";
PrintExpr(Node->getSubExpr());
OS << ")";
@@ -1299,7 +1313,7 @@ void StmtPrinter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) {
}
void StmtPrinter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *Node) {
- OS << Node->getType().getAsString(Policy);
+ Node->getType().print(OS, Policy);
OS << "(";
for (CXXTemporaryObjectExpr::arg_iterator Arg = Node->arg_begin(),
ArgEnd = Node->arg_end();
@@ -1369,8 +1383,7 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
NeedComma = true;
}
std::string ParamStr = (*P)->getNameAsString();
- (*P)->getOriginalType().getAsStringInternal(ParamStr, Policy);
- OS << ParamStr;
+ (*P)->getOriginalType().print(OS, Policy, ParamStr);
}
if (Method->isVariadic()) {
if (NeedComma)
@@ -1384,17 +1397,15 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
const FunctionProtoType *Proto
= Method->getType()->getAs<FunctionProtoType>();
- {
- std::string ExceptionSpec;
- Proto->printExceptionSpecification(ExceptionSpec, Policy);
- OS << ExceptionSpec;
- }
+ Proto->printExceptionSpecification(OS, Policy);
// FIXME: Attributes
// Print the trailing return type if it was specified in the source.
- if (Node->hasExplicitResultType())
- OS << " -> " << Proto->getResultType().getAsString(Policy);
+ if (Node->hasExplicitResultType()) {
+ OS << " -> ";
+ Proto->getResultType().print(OS, Policy);
+ }
}
// Print the body.
@@ -1405,9 +1416,10 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
void StmtPrinter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *Node) {
if (TypeSourceInfo *TSInfo = Node->getTypeSourceInfo())
- OS << TSInfo->getType().getAsString(Policy) << "()";
+ TSInfo->getType().print(OS, Policy);
else
- OS << Node->getType().getAsString(Policy) << "()";
+ Node->getType().print(OS, Policy);
+ OS << "()";
}
void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) {
@@ -1431,12 +1443,11 @@ void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) {
std::string TypeS;
if (Expr *Size = E->getArraySize()) {
llvm::raw_string_ostream s(TypeS);
+ s << '[';
Size->printPretty(s, Helper, Policy);
- s.flush();
- TypeS = "[" + TypeS + "]";
+ s << ']';
}
- E->getAllocatedType().getAsStringInternal(TypeS, Policy);
- OS << TypeS;
+ E->getAllocatedType().print(OS, Policy, TypeS);
if (E->isParenTypeId())
OS << ")";
@@ -1469,15 +1480,16 @@ void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
E->getQualifier()->print(OS, Policy);
OS << "~";
- std::string TypeS;
if (IdentifierInfo *II = E->getDestroyedTypeIdentifier())
OS << II->getName();
else
- E->getDestroyedType().getAsStringInternal(TypeS, Policy);
- OS << TypeS;
+ E->getDestroyedType().print(OS, Policy);
}
void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) {
+ if (E->isListInitialization())
+ OS << "{ ";
+
for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) {
if (isa<CXXDefaultArgExpr>(E->getArg(i))) {
// Don't print any defaulted arguments
@@ -1487,6 +1499,9 @@ void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) {
if (i) OS << ", ";
PrintExpr(E->getArg(i));
}
+
+ if (E->isListInitialization())
+ OS << " }";
}
void StmtPrinter::VisitExprWithCleanups(ExprWithCleanups *E) {
@@ -1497,7 +1512,7 @@ void StmtPrinter::VisitExprWithCleanups(ExprWithCleanups *E) {
void
StmtPrinter::VisitCXXUnresolvedConstructExpr(
CXXUnresolvedConstructExpr *Node) {
- OS << Node->getTypeAsWritten().getAsString(Policy);
+ Node->getTypeAsWritten().print(OS, Policy);
OS << "(";
for (CXXUnresolvedConstructExpr::arg_iterator Arg = Node->arg_begin(),
ArgEnd = Node->arg_end();
@@ -1520,12 +1535,9 @@ void StmtPrinter::VisitCXXDependentScopeMemberExpr(
if (Node->hasTemplateKeyword())
OS << "template ";
OS << Node->getMemberNameInfo();
- if (Node->hasExplicitTemplateArgs()) {
- OS << TemplateSpecializationType::PrintTemplateArgumentList(
- Node->getTemplateArgs(),
- Node->getNumTemplateArgs(),
- Policy);
- }
+ if (Node->hasExplicitTemplateArgs())
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, Node->getTemplateArgs(), Node->getNumTemplateArgs(), Policy);
}
void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) {
@@ -1538,20 +1550,20 @@ void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) {
if (Node->hasTemplateKeyword())
OS << "template ";
OS << Node->getMemberNameInfo();
- if (Node->hasExplicitTemplateArgs()) {
- OS << TemplateSpecializationType::PrintTemplateArgumentList(
- Node->getTemplateArgs(),
- Node->getNumTemplateArgs(),
- Policy);
- }
+ if (Node->hasExplicitTemplateArgs())
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, Node->getTemplateArgs(), Node->getNumTemplateArgs(), Policy);
}
static const char *getTypeTraitName(UnaryTypeTrait UTT) {
switch (UTT) {
case UTT_HasNothrowAssign: return "__has_nothrow_assign";
+ case UTT_HasNothrowMoveAssign: return "__has_nothrow_move_assign";
case UTT_HasNothrowConstructor: return "__has_nothrow_constructor";
case UTT_HasNothrowCopy: return "__has_nothrow_copy";
case UTT_HasTrivialAssign: return "__has_trivial_assign";
+ case UTT_HasTrivialMoveAssign: return "__has_trivial_move_assign";
+ case UTT_HasTrivialMoveConstructor: return "__has_trivial_move_constructor";
case UTT_HasTrivialDefaultConstructor: return "__has_trivial_constructor";
case UTT_HasTrivialCopy: return "__has_trivial_copy";
case UTT_HasTrivialDestructor: return "__has_trivial_destructor";
@@ -1631,14 +1643,17 @@ static const char *getExpressionTraitName(ExpressionTrait ET) {
}
void StmtPrinter::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
- OS << getTypeTraitName(E->getTrait()) << "("
- << E->getQueriedType().getAsString(Policy) << ")";
+ OS << getTypeTraitName(E->getTrait()) << '(';
+ E->getQueriedType().print(OS, Policy);
+ OS << ')';
}
void StmtPrinter::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) {
- OS << getTypeTraitName(E->getTrait()) << "("
- << E->getLhsType().getAsString(Policy) << ","
- << E->getRhsType().getAsString(Policy) << ")";
+ OS << getTypeTraitName(E->getTrait()) << '(';
+ E->getLhsType().print(OS, Policy);
+ OS << ',';
+ E->getRhsType().print(OS, Policy);
+ OS << ')';
}
void StmtPrinter::VisitTypeTraitExpr(TypeTraitExpr *E) {
@@ -1646,20 +1661,21 @@ void StmtPrinter::VisitTypeTraitExpr(TypeTraitExpr *E) {
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) {
if (I > 0)
OS << ", ";
- OS << E->getArg(I)->getType().getAsString(Policy);
+ E->getArg(I)->getType().print(OS, Policy);
}
OS << ")";
}
void StmtPrinter::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
- OS << getTypeTraitName(E->getTrait()) << "("
- << E->getQueriedType().getAsString(Policy) << ")";
+ OS << getTypeTraitName(E->getTrait()) << '(';
+ E->getQueriedType().print(OS, Policy);
+ OS << ')';
}
void StmtPrinter::VisitExpressionTraitExpr(ExpressionTraitExpr *E) {
- OS << getExpressionTraitName(E->getTrait()) << "(";
- PrintExpr(E->getQueriedExpression());
- OS << ")";
+ OS << getExpressionTraitName(E->getTrait()) << '(';
+ PrintExpr(E->getQueriedExpression());
+ OS << ')';
}
void StmtPrinter::VisitCXXNoexceptExpr(CXXNoexceptExpr *E) {
@@ -1738,7 +1754,9 @@ void StmtPrinter::VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) {
}
void StmtPrinter::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
- OS << "@encode(" << Node->getEncodedType().getAsString(Policy) << ')';
+ OS << "@encode(";
+ Node->getEncodedType().print(OS, Policy);
+ OS << ')';
}
void StmtPrinter::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) {
@@ -1757,7 +1775,7 @@ void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) {
break;
case ObjCMessageExpr::Class:
- OS << Mess->getClassReceiver().getAsString(Policy);
+ Mess->getClassReceiver().print(OS, Policy);
break;
case ObjCMessageExpr::SuperInstance:
@@ -1798,8 +1816,9 @@ StmtPrinter::VisitObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *E) {
void
StmtPrinter::VisitObjCBridgedCastExpr(ObjCBridgedCastExpr *E) {
- OS << "(" << E->getBridgeKindName() << E->getType().getAsString(Policy)
- << ")";
+ OS << '(' << E->getBridgeKindName();
+ E->getType().print(OS, Policy);
+ OS << ')';
PrintExpr(E->getSubExpr());
}
@@ -1813,13 +1832,11 @@ void StmtPrinter::VisitBlockExpr(BlockExpr *Node) {
OS << "()";
} else if (!BD->param_empty() || cast<FunctionProtoType>(AFT)->isVariadic()) {
OS << '(';
- std::string ParamStr;
for (BlockDecl::param_iterator AI = BD->param_begin(),
E = BD->param_end(); AI != E; ++AI) {
if (AI != BD->param_begin()) OS << ", ";
- ParamStr = (*AI)->getNameAsString();
- (*AI)->getType().getAsStringInternal(ParamStr, Policy);
- OS << ParamStr;
+ std::string ParamStr = (*AI)->getNameAsString();
+ (*AI)->getType().print(OS, Policy, ParamStr);
}
const FunctionProtoType *FT = cast<FunctionProtoType>(AFT);
@@ -1829,6 +1846,7 @@ void StmtPrinter::VisitBlockExpr(BlockExpr *Node) {
}
OS << ')';
}
+ OS << "{ }";
}
void StmtPrinter::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {
@@ -1838,7 +1856,8 @@ void StmtPrinter::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {
void StmtPrinter::VisitAsTypeExpr(AsTypeExpr *Node) {
OS << "__builtin_astype(";
PrintExpr(Node->getSrcExpr());
- OS << ", " << Node->getType().getAsString();
+ OS << ", ";
+ Node->getType().print(OS, Policy);
OS << ")";
}
@@ -1859,11 +1878,6 @@ void Stmt::printPretty(raw_ostream &OS,
return;
}
- if (Policy.DumpSourceManager) {
- dump(OS, *Policy.DumpSourceManager);
- return;
- }
-
StmtPrinter P(OS, Helper, Policy, Indentation);
P.Visit(const_cast<Stmt*>(this));
}
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index e9ee385..d68b95e 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -23,8 +23,8 @@
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
#include <algorithm>
-#include <cctype>
using namespace clang;
@@ -224,12 +224,12 @@ bool TemplateArgument::containsUnexpandedParameterPack() const {
return false;
}
-llvm::Optional<unsigned> TemplateArgument::getNumTemplateExpansions() const {
+Optional<unsigned> TemplateArgument::getNumTemplateExpansions() const {
assert(Kind == TemplateExpansion);
if (TemplateArg.NumExpansions)
return TemplateArg.NumExpansions - 1;
- return llvm::Optional<unsigned>();
+ return None;
}
void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
@@ -347,9 +347,7 @@ void TemplateArgument::print(const PrintingPolicy &Policy,
case Type: {
PrintingPolicy SubPolicy(Policy);
SubPolicy.SuppressStrongLifetime = true;
- std::string TypeStr;
- getAsType().getAsStringInternal(TypeStr, SubPolicy);
- Out << TypeStr;
+ getAsType().print(Out, SubPolicy);
break;
}
@@ -451,10 +449,9 @@ SourceRange TemplateArgumentLoc::getSourceRange() const {
llvm_unreachable("Invalid TemplateArgument Kind!");
}
-TemplateArgumentLoc
-TemplateArgumentLoc::getPackExpansionPattern(SourceLocation &Ellipsis,
- llvm::Optional<unsigned> &NumExpansions,
- ASTContext &Context) const {
+TemplateArgumentLoc TemplateArgumentLoc::getPackExpansionPattern(
+ SourceLocation &Ellipsis, Optional<unsigned> &NumExpansions,
+ ASTContext &Context) const {
assert(Argument.isPackExpansion());
switch (Argument.getKind()) {
@@ -466,8 +463,8 @@ TemplateArgumentLoc::getPackExpansionPattern(SourceLocation &Ellipsis,
ExpansionTSInfo = Context.getTrivialTypeSourceInfo(
getArgument().getAsType(),
Ellipsis);
- PackExpansionTypeLoc Expansion
- = cast<PackExpansionTypeLoc>(ExpansionTSInfo->getTypeLoc());
+ PackExpansionTypeLoc Expansion =
+ ExpansionTSInfo->getTypeLoc().castAs<PackExpansionTypeLoc>();
Ellipsis = Expansion.getEllipsisLoc();
TypeLoc Pattern = Expansion.getPatternLoc();
diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp
index e89ba53..8767c63 100644
--- a/lib/AST/TemplateName.cpp
+++ b/lib/AST/TemplateName.cpp
@@ -1,4 +1,4 @@
-//===--- TemplateName.h - C++ Template Name Representation-------*- C++ -*-===//
+//===--- TemplateName.cpp - C++ Template Name Representation---------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -12,10 +12,10 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/TemplateName.h"
-#include "clang/AST/TemplateBase.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/TemplateBase.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LangOptions.h"
#include "llvm/Support/raw_ostream.h"
@@ -163,14 +163,20 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
LangOptions LO;
LO.CPlusPlus = true;
LO.Bool = true;
+ OS << '\'';
N.print(OS, PrintingPolicy(LO));
+ OS << '\'';
OS.flush();
return DB << NameStr;
}
-void TemplateName::dump() const {
+void TemplateName::dump(raw_ostream &OS) const {
LangOptions LO; // FIXME!
LO.CPlusPlus = true;
LO.Bool = true;
- print(llvm::errs(), PrintingPolicy(LO));
+ print(OS, PrintingPolicy(LO));
+}
+
+void TemplateName::dump() const {
+ dump(llvm::errs());
}
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 580ec50..0c5636d 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -12,13 +12,14 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/CharUnits.h"
-#include "clang/AST/Type.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/Type.h"
#include "clang/AST/TypeVisitor.h"
#include "clang/Basic/Specifiers.h"
#include "llvm/ADT/APSInt.h"
@@ -75,16 +76,35 @@ bool QualType::isConstant(QualType T, ASTContext &Ctx) {
unsigned ConstantArrayType::getNumAddressingBits(ASTContext &Context,
QualType ElementType,
const llvm::APInt &NumElements) {
+ uint64_t ElementSize = Context.getTypeSizeInChars(ElementType).getQuantity();
+
+ // Fast path the common cases so we can avoid the conservative computation
+ // below, which in common cases allocates "large" APSInt values, which are
+ // slow.
+
+ // If the element size is a power of 2, we can directly compute the additional
+ // number of addressing bits beyond those required for the element count.
+ if (llvm::isPowerOf2_64(ElementSize)) {
+ return NumElements.getActiveBits() + llvm::Log2_64(ElementSize);
+ }
+
+ // If both the element count and element size fit in 32-bits, we can do the
+ // computation directly in 64-bits.
+ if ((ElementSize >> 32) == 0 && NumElements.getBitWidth() <= 64 &&
+ (NumElements.getZExtValue() >> 32) == 0) {
+ uint64_t TotalSize = NumElements.getZExtValue() * ElementSize;
+ return 64 - llvm::CountLeadingZeros_64(TotalSize);
+ }
+
+ // Otherwise, use APSInt to handle arbitrary sized values.
llvm::APSInt SizeExtended(NumElements, true);
unsigned SizeTypeBits = Context.getTypeSize(Context.getSizeType());
SizeExtended = SizeExtended.extend(std::max(SizeTypeBits,
SizeExtended.getBitWidth()) * 2);
- uint64_t ElementSize
- = Context.getTypeSizeInChars(ElementType).getQuantity();
llvm::APSInt TotalSize(llvm::APInt(SizeExtended.getBitWidth(), ElementSize));
TotalSize *= SizeExtended;
-
+
return TotalSize.getActiveBits();
}
@@ -939,7 +959,7 @@ bool Type::isIncompleteType(NamedDecl **Def) const {
bool QualType::isPODType(ASTContext &Context) const {
// C++11 has a more relaxed definition of POD.
- if (Context.getLangOpts().CPlusPlus0x)
+ if (Context.getLangOpts().CPlusPlus11)
return isCXX11PODType(Context);
return isCXX98PODType(Context);
@@ -1052,11 +1072,13 @@ bool QualType::isTrivialType(ASTContext &Context) const {
if (const RecordType *RT = CanonicalType->getAs<RecordType>()) {
if (const CXXRecordDecl *ClassDecl =
dyn_cast<CXXRecordDecl>(RT->getDecl())) {
- // C++0x [class]p5:
- // A trivial class is a class that has a trivial default constructor
- if (!ClassDecl->hasTrivialDefaultConstructor()) return false;
- // and is trivially copyable.
- if (!ClassDecl->isTriviallyCopyable()) return false;
+ // C++11 [class]p6:
+ // A trivial class is a class that has a default constructor,
+ // has no non-trivial default constructors, and is trivially
+ // copyable.
+ return ClassDecl->hasDefaultConstructor() &&
+ !ClassDecl->hasNonTrivialDefaultConstructor() &&
+ ClassDecl->isTriviallyCopyable();
}
return true;
@@ -1509,6 +1531,14 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const {
case ObjCId: return "id";
case ObjCClass: return "Class";
case ObjCSel: return "SEL";
+ case OCLImage1d: return "image1d_t";
+ case OCLImage1dArray: return "image1d_array_t";
+ case OCLImage1dBuffer: return "image1d_buffer_t";
+ case OCLImage2d: return "image2d_t";
+ case OCLImage2dArray: return "image2d_array_t";
+ case OCLImage3d: return "image3d_t";
+ case OCLSampler: return "sampler_t";
+ case OCLEvent: return "event_t";
}
llvm_unreachable("Invalid builtin type.");
@@ -1543,29 +1573,33 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) {
case CC_AAPCS: return "aapcs";
case CC_AAPCS_VFP: return "aapcs-vfp";
case CC_PnaclCall: return "pnaclcall";
+ case CC_IntelOclBicc: return "intel_ocl_bicc";
}
llvm_unreachable("Invalid calling convention.");
}
-FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
- unsigned numArgs, QualType canonical,
+FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> args,
+ QualType canonical,
const ExtProtoInfo &epi)
- : FunctionType(FunctionProto, result, epi.TypeQuals, epi.RefQualifier,
+ : FunctionType(FunctionProto, result, epi.TypeQuals,
canonical,
result->isDependentType(),
result->isInstantiationDependentType(),
result->isVariablyModifiedType(),
result->containsUnexpandedParameterPack(),
epi.ExtInfo),
- NumArgs(numArgs), NumExceptions(epi.NumExceptions),
+ NumArgs(args.size()), NumExceptions(epi.NumExceptions),
ExceptionSpecType(epi.ExceptionSpecType),
HasAnyConsumedArgs(epi.ConsumedArguments != 0),
- Variadic(epi.Variadic), HasTrailingReturn(epi.HasTrailingReturn)
+ Variadic(epi.Variadic), HasTrailingReturn(epi.HasTrailingReturn),
+ RefQualifier(epi.RefQualifier)
{
+ assert(NumArgs == args.size() && "function has too many parameters");
+
// Fill in the trailing argument array.
QualType *argSlot = reinterpret_cast<QualType*>(this+1);
- for (unsigned i = 0; i != numArgs; ++i) {
+ for (unsigned i = 0; i != NumArgs; ++i) {
if (args[i]->isDependentType())
setDependent();
else if (args[i]->isInstantiationDependentType())
@@ -1579,7 +1613,7 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
if (getExceptionSpecType() == EST_Dynamic) {
// Fill in the exception array.
- QualType *exnSlot = argSlot + numArgs;
+ QualType *exnSlot = argSlot + NumArgs;
for (unsigned i = 0, e = epi.NumExceptions; i != e; ++i) {
if (epi.Exceptions[i]->isDependentType())
setDependent();
@@ -1593,7 +1627,7 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
}
} else if (getExceptionSpecType() == EST_ComputedNoexcept) {
// Store the noexcept expression and context.
- Expr **noexSlot = reinterpret_cast<Expr**>(argSlot + numArgs);
+ Expr **noexSlot = reinterpret_cast<Expr**>(argSlot + NumArgs);
*noexSlot = epi.NoexceptExpr;
if (epi.NoexceptExpr) {
@@ -1606,7 +1640,7 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
} else if (getExceptionSpecType() == EST_Uninstantiated) {
// Store the function decl from which we will resolve our
// exception specification.
- FunctionDecl **slot = reinterpret_cast<FunctionDecl**>(argSlot + numArgs);
+ FunctionDecl **slot = reinterpret_cast<FunctionDecl**>(argSlot + NumArgs);
slot[0] = epi.ExceptionSpecDecl;
slot[1] = epi.ExceptionSpecTemplate;
// This exception specification doesn't make the type dependent, because
@@ -1614,13 +1648,13 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
} else if (getExceptionSpecType() == EST_Unevaluated) {
// Store the function decl from which we will resolve our
// exception specification.
- FunctionDecl **slot = reinterpret_cast<FunctionDecl**>(argSlot + numArgs);
+ FunctionDecl **slot = reinterpret_cast<FunctionDecl**>(argSlot + NumArgs);
slot[0] = epi.ExceptionSpecDecl;
}
if (epi.ConsumedArguments) {
bool *consumedArgs = const_cast<bool*>(getConsumedArgsBuffer());
- for (unsigned i = 0; i != numArgs; ++i)
+ for (unsigned i = 0; i != NumArgs; ++i)
consumedArgs[i] = epi.ConsumedArguments[i];
}
}
@@ -1987,22 +2021,18 @@ namespace {
/// \brief The cached properties of a type.
class CachedProperties {
- NamedDecl::LinkageInfo LV;
+ Linkage L;
bool local;
-
+
public:
- CachedProperties(NamedDecl::LinkageInfo LV, bool local)
- : LV(LV), local(local) {}
-
- Linkage getLinkage() const { return LV.linkage(); }
- Visibility getVisibility() const { return LV.visibility(); }
- bool isVisibilityExplicit() const { return LV.visibilityExplicit(); }
+ CachedProperties(Linkage L, bool local) : L(L), local(local) {}
+
+ Linkage getLinkage() const { return L; }
bool hasLocalOrUnnamedType() const { return local; }
-
+
friend CachedProperties merge(CachedProperties L, CachedProperties R) {
- NamedDecl::LinkageInfo MergedLV = L.LV;
- MergedLV.merge(R.LV);
- return CachedProperties(MergedLV,
+ Linkage MergedLinkage = minLinkage(L.L, R.L);
+ return CachedProperties(MergedLinkage,
L.hasLocalOrUnnamedType() | R.hasLocalOrUnnamedType());
}
};
@@ -2022,10 +2052,8 @@ public:
static CachedProperties get(const Type *T) {
ensure(T);
- NamedDecl::LinkageInfo LV(T->TypeBits.getLinkage(),
- T->TypeBits.getVisibility(),
- T->TypeBits.isVisibilityExplicit());
- return CachedProperties(LV, T->TypeBits.hasLocalOrUnnamedType());
+ return CachedProperties(T->TypeBits.getLinkage(),
+ T->TypeBits.hasLocalOrUnnamedType());
}
static void ensure(const Type *T) {
@@ -2037,10 +2065,7 @@ public:
if (!T->isCanonicalUnqualified()) {
const Type *CT = T->getCanonicalTypeInternal().getTypePtr();
ensure(CT);
- T->TypeBits.CacheValidAndVisibility =
- CT->TypeBits.CacheValidAndVisibility;
- T->TypeBits.CachedExplicitVisibility =
- CT->TypeBits.CachedExplicitVisibility;
+ T->TypeBits.CacheValid = true;
T->TypeBits.CachedLinkage = CT->TypeBits.CachedLinkage;
T->TypeBits.CachedLocalOrUnnamed = CT->TypeBits.CachedLocalOrUnnamed;
return;
@@ -2048,10 +2073,7 @@ public:
// Compute the cached properties and then set the cache.
CachedProperties Result = computeCachedProperties(T);
- T->TypeBits.CacheValidAndVisibility = Result.getVisibility() + 1U;
- T->TypeBits.CachedExplicitVisibility = Result.isVisibilityExplicit();
- assert(T->TypeBits.isCacheValid() &&
- T->TypeBits.getVisibility() == Result.getVisibility());
+ T->TypeBits.CacheValid = true;
T->TypeBits.CachedLinkage = Result.getLinkage();
T->TypeBits.CachedLocalOrUnnamed = Result.hasLocalOrUnnamedType();
}
@@ -2077,13 +2099,13 @@ static CachedProperties computeCachedProperties(const Type *T) {
#include "clang/AST/TypeNodes.def"
// Treat instantiation-dependent types as external.
assert(T->isInstantiationDependentType());
- return CachedProperties(NamedDecl::LinkageInfo(), false);
+ return CachedProperties(ExternalLinkage, false);
case Type::Builtin:
// C++ [basic.link]p8:
// A type is said to have linkage if and only if:
// - it is a fundamental type (3.9.1); or
- return CachedProperties(NamedDecl::LinkageInfo(), false);
+ return CachedProperties(ExternalLinkage, false);
case Type::Record:
case Type::Enum: {
@@ -2093,11 +2115,11 @@ static CachedProperties computeCachedProperties(const Type *T) {
// - it is a class or enumeration type that is named (or has a name
// for linkage purposes (7.1.3)) and the name has linkage; or
// - it is a specialization of a class template (14); or
- NamedDecl::LinkageInfo LV = Tag->getLinkageAndVisibility();
+ Linkage L = Tag->getLinkage();
bool IsLocalOrUnnamed =
Tag->getDeclContext()->isFunctionOrMethod() ||
- (!Tag->getIdentifier() && !Tag->getTypedefNameForAnonDecl());
- return CachedProperties(LV, IsLocalOrUnnamed);
+ !Tag->hasNameForLinkage();
+ return CachedProperties(L, IsLocalOrUnnamed);
}
// C++ [basic.link]p8:
@@ -2135,9 +2157,8 @@ static CachedProperties computeCachedProperties(const Type *T) {
return result;
}
case Type::ObjCInterface: {
- NamedDecl::LinkageInfo LV =
- cast<ObjCInterfaceType>(T)->getDecl()->getLinkageAndVisibility();
- return CachedProperties(LV, false);
+ Linkage L = cast<ObjCInterfaceType>(T)->getDecl()->getLinkage();
+ return CachedProperties(L, false);
}
case Type::ObjCObject:
return Cache::get(cast<ObjCObjectType>(T)->getBaseType());
@@ -2156,31 +2177,99 @@ Linkage Type::getLinkage() const {
return TypeBits.getLinkage();
}
-/// \brief Determine the linkage of this type.
-Visibility Type::getVisibility() const {
+bool Type::hasUnnamedOrLocalType() const {
Cache::ensure(this);
- return TypeBits.getVisibility();
+ return TypeBits.hasLocalOrUnnamedType();
}
-bool Type::isVisibilityExplicit() const {
- Cache::ensure(this);
- return TypeBits.isVisibilityExplicit();
+static LinkageInfo computeLinkageInfo(QualType T);
+
+static LinkageInfo computeLinkageInfo(const Type *T) {
+ switch (T->getTypeClass()) {
+#define TYPE(Class,Base)
+#define NON_CANONICAL_TYPE(Class,Base) case Type::Class:
+#include "clang/AST/TypeNodes.def"
+ llvm_unreachable("didn't expect a non-canonical type here");
+
+#define TYPE(Class,Base)
+#define DEPENDENT_TYPE(Class,Base) case Type::Class:
+#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class,Base) case Type::Class:
+#include "clang/AST/TypeNodes.def"
+ // Treat instantiation-dependent types as external.
+ assert(T->isInstantiationDependentType());
+ return LinkageInfo::external();
+
+ case Type::Builtin:
+ return LinkageInfo::external();
+
+ case Type::Record:
+ case Type::Enum:
+ return cast<TagType>(T)->getDecl()->getLinkageAndVisibility();
+
+ case Type::Complex:
+ return computeLinkageInfo(cast<ComplexType>(T)->getElementType());
+ case Type::Pointer:
+ return computeLinkageInfo(cast<PointerType>(T)->getPointeeType());
+ case Type::BlockPointer:
+ return computeLinkageInfo(cast<BlockPointerType>(T)->getPointeeType());
+ case Type::LValueReference:
+ case Type::RValueReference:
+ return computeLinkageInfo(cast<ReferenceType>(T)->getPointeeType());
+ case Type::MemberPointer: {
+ const MemberPointerType *MPT = cast<MemberPointerType>(T);
+ LinkageInfo LV = computeLinkageInfo(MPT->getClass());
+ LV.merge(computeLinkageInfo(MPT->getPointeeType()));
+ return LV;
+ }
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ case Type::VariableArray:
+ return computeLinkageInfo(cast<ArrayType>(T)->getElementType());
+ case Type::Vector:
+ case Type::ExtVector:
+ return computeLinkageInfo(cast<VectorType>(T)->getElementType());
+ case Type::FunctionNoProto:
+ return computeLinkageInfo(cast<FunctionType>(T)->getResultType());
+ case Type::FunctionProto: {
+ const FunctionProtoType *FPT = cast<FunctionProtoType>(T);
+ LinkageInfo LV = computeLinkageInfo(FPT->getResultType());
+ for (FunctionProtoType::arg_type_iterator ai = FPT->arg_type_begin(),
+ ae = FPT->arg_type_end(); ai != ae; ++ai)
+ LV.merge(computeLinkageInfo(*ai));
+ return LV;
+ }
+ case Type::ObjCInterface:
+ return cast<ObjCInterfaceType>(T)->getDecl()->getLinkageAndVisibility();
+ case Type::ObjCObject:
+ return computeLinkageInfo(cast<ObjCObjectType>(T)->getBaseType());
+ case Type::ObjCObjectPointer:
+ return computeLinkageInfo(cast<ObjCObjectPointerType>(T)->getPointeeType());
+ case Type::Atomic:
+ return computeLinkageInfo(cast<AtomicType>(T)->getValueType());
+ }
+
+ llvm_unreachable("unhandled type class");
}
-bool Type::hasUnnamedOrLocalType() const {
- Cache::ensure(this);
- return TypeBits.hasLocalOrUnnamedType();
+static LinkageInfo computeLinkageInfo(QualType T) {
+ return computeLinkageInfo(T.getTypePtr());
}
-std::pair<Linkage,Visibility> Type::getLinkageAndVisibility() const {
- Cache::ensure(this);
- return std::make_pair(TypeBits.getLinkage(), TypeBits.getVisibility());
+bool Type::isLinkageValid() const {
+ if (!TypeBits.isCacheValid())
+ return true;
+
+ return computeLinkageInfo(getCanonicalTypeInternal()).getLinkage() ==
+ TypeBits.getLinkage();
}
-void Type::ClearLinkageCache() {
- TypeBits.CacheValidAndVisibility = 0;
- if (QualType(this, 0) != CanonicalType)
- CanonicalType->TypeBits.CacheValidAndVisibility = 0;
+LinkageInfo Type::getLinkageAndVisibility() const {
+ if (!isCanonicalUnqualified())
+ return computeLinkageInfo(getCanonicalTypeInternal());
+
+ LinkageInfo LV = computeLinkageInfo(this);
+ assert(LV.getLinkage() == getLinkage());
+ return LV;
}
Qualifiers::ObjCLifetime Type::getObjCARCImplicitLifetime() const {
@@ -2296,25 +2385,3 @@ QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) {
return DK_none;
}
-
-bool QualType::hasTrivialAssignment(ASTContext &Context, bool Copying) const {
- switch (getObjCLifetime()) {
- case Qualifiers::OCL_None:
- break;
-
- case Qualifiers::OCL_ExplicitNone:
- return true;
-
- case Qualifiers::OCL_Autoreleasing:
- case Qualifiers::OCL_Strong:
- case Qualifiers::OCL_Weak:
- return !Context.getLangOpts().ObjCAutoRefCount;
- }
-
- if (const CXXRecordDecl *Record
- = getTypePtr()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl())
- return Copying ? Record->hasTrivialCopyAssignment() :
- Record->hasTrivialMoveAssignment();
-
- return true;
-}
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index 58c4cbd..03d4030 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/lib/AST/TypeLoc.cpp
@@ -11,11 +11,12 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/Support/raw_ostream.h"
-#include "clang/AST/TypeLocVisitor.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/TypeLocVisitor.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -85,7 +86,7 @@ void TypeLoc::initializeImpl(ASTContext &Context, TypeLoc TL,
#define ABSTRACT_TYPELOC(CLASS, PARENT)
#define TYPELOC(CLASS, PARENT) \
case CLASS: { \
- CLASS##TypeLoc TLCasted = cast<CLASS##TypeLoc>(TL); \
+ CLASS##TypeLoc TLCasted = TL.castAs<CLASS##TypeLoc>(); \
TLCasted.initializeLocal(Context, Loc); \
TL = TLCasted.getNextTypeLoc(); \
if (!TL) return; \
@@ -105,7 +106,8 @@ SourceLocation TypeLoc::getBeginLoc() const {
LeftMost = Cur;
break;
case FunctionProto:
- if (cast<FunctionProtoTypeLoc>(&Cur)->getTypePtr()->hasTrailingReturn()) {
+ if (Cur.castAs<FunctionProtoTypeLoc>().getTypePtr()
+ ->hasTrailingReturn()) {
LeftMost = Cur;
break;
}
@@ -150,7 +152,7 @@ SourceLocation TypeLoc::getEndLoc() const {
Last = Cur;
break;
case FunctionProto:
- if (cast<FunctionProtoTypeLoc>(&Cur)->getTypePtr()->hasTrailingReturn())
+ if (Cur.castAs<FunctionProtoTypeLoc>().getTypePtr()->hasTrailingReturn())
Last = TypeLoc();
else
Last = Cur;
@@ -197,9 +199,9 @@ namespace {
/// because it's a convenient base class. Ideally we would not accept
/// those here, but ideally we would have better implementations for
/// them.
-bool TypeSpecTypeLoc::classof(const TypeLoc *TL) {
- if (TL->getType().hasLocalQualifiers()) return false;
- return TSTChecker().Visit(*TL);
+bool TypeSpecTypeLoc::isKind(const TypeLoc &TL) {
+ if (TL.getType().hasLocalQualifiers()) return false;
+ return TSTChecker().Visit(TL);
}
// Reimplemented to account for GNU/C++ extension
@@ -261,6 +263,14 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
case BuiltinType::ObjCId:
case BuiltinType::ObjCClass:
case BuiltinType::ObjCSel:
+ case BuiltinType::OCLImage1d:
+ case BuiltinType::OCLImage1dArray:
+ case BuiltinType::OCLImage1dBuffer:
+ case BuiltinType::OCLImage2d:
+ case BuiltinType::OCLImage2dArray:
+ case BuiltinType::OCLImage3d:
+ case BuiltinType::OCLSampler:
+ case BuiltinType::OCLEvent:
case BuiltinType::BuiltinFn:
return TST_unspecified;
}
@@ -269,8 +279,8 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
}
TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) {
- while (ParenTypeLoc* PTL = dyn_cast<ParenTypeLoc>(&TL))
- TL = PTL->getInnerLoc();
+ while (ParenTypeLoc PTL = TL.getAs<ParenTypeLoc>())
+ TL = PTL.getInnerLoc();
return TL;
}
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 90b2ca9..9d1717a 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -11,19 +11,19 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
-#include "clang/AST/PrettyPrinter.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/SaveAndRestore.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
namespace {
@@ -647,6 +647,9 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
case CC_PnaclCall:
OS << " __attribute__((pnaclcall))";
break;
+ case CC_IntelOclBicc:
+ OS << " __attribute__((intel_ocl_bicc))";
+ break;
}
if (Info.getNoReturn())
OS << " __attribute__((noreturn))";
@@ -1168,6 +1171,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
break;
}
case AttributedType::attr_pnaclcall: OS << "pnaclcall"; break;
+ case AttributedType::attr_inteloclbicc: OS << "inteloclbicc"; break;
}
OS << "))";
}
@@ -1344,132 +1348,6 @@ PrintTemplateArgumentList(raw_ostream &OS,
OS << '>';
}
-void
-FunctionProtoType::printExceptionSpecification(std::string &S,
- const PrintingPolicy &Policy)
- const {
-
- if (hasDynamicExceptionSpec()) {
- S += " throw(";
- if (getExceptionSpecType() == EST_MSAny)
- S += "...";
- else
- for (unsigned I = 0, N = getNumExceptions(); I != N; ++I) {
- if (I)
- S += ", ";
-
- S += getExceptionType(I).getAsString(Policy);
- }
- S += ")";
- } else if (isNoexceptExceptionSpec(getExceptionSpecType())) {
- S += " noexcept";
- if (getExceptionSpecType() == EST_ComputedNoexcept) {
- S += "(";
- llvm::raw_string_ostream EOut(S);
- getNoexceptExpr()->printPretty(EOut, 0, Policy);
- EOut.flush();
- S += EOut.str();
- S += ")";
- }
- }
-}
-
-std::string TemplateSpecializationType::
- PrintTemplateArgumentList(const TemplateArgumentListInfo &Args,
- const PrintingPolicy &Policy) {
- return PrintTemplateArgumentList(Args.getArgumentArray(),
- Args.size(),
- Policy);
-}
-
-std::string
-TemplateSpecializationType::PrintTemplateArgumentList(
- const TemplateArgument *Args,
- unsigned NumArgs,
- const PrintingPolicy &Policy,
- bool SkipBrackets) {
- std::string SpecString;
- if (!SkipBrackets)
- SpecString += '<';
-
- for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
- if (SpecString.size() > unsigned(!SkipBrackets))
- SpecString += ", ";
-
- // Print the argument into a string.
- std::string ArgString;
- if (Args[Arg].getKind() == TemplateArgument::Pack) {
- ArgString = PrintTemplateArgumentList(Args[Arg].pack_begin(),
- Args[Arg].pack_size(),
- Policy, true);
- } else {
- llvm::raw_string_ostream ArgOut(ArgString);
- Args[Arg].print(Policy, ArgOut);
- }
-
- // If this is the first argument and its string representation
- // begins with the global scope specifier ('::foo'), add a space
- // to avoid printing the diagraph '<:'.
- if (!Arg && !ArgString.empty() && ArgString[0] == ':')
- SpecString += ' ';
-
- SpecString += ArgString;
- }
-
- // If the last character of our string is '>', add another space to
- // keep the two '>''s separate tokens. We don't *have* to do this in
- // C++0x, but it's still good hygiene.
- if (!SpecString.empty() && SpecString[SpecString.size() - 1] == '>')
- SpecString += ' ';
-
- if (!SkipBrackets)
- SpecString += '>';
-
- return SpecString;
-}
-
-// Sadly, repeat all that with TemplateArgLoc.
-std::string TemplateSpecializationType::
-PrintTemplateArgumentList(const TemplateArgumentLoc *Args, unsigned NumArgs,
- const PrintingPolicy &Policy) {
- std::string SpecString;
- SpecString += '<';
- for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
- if (SpecString.size() > 1)
- SpecString += ", ";
-
- // Print the argument into a string.
- std::string ArgString;
- if (Args[Arg].getArgument().getKind() == TemplateArgument::Pack) {
- ArgString = PrintTemplateArgumentList(
- Args[Arg].getArgument().pack_begin(),
- Args[Arg].getArgument().pack_size(),
- Policy, true);
- } else {
- llvm::raw_string_ostream ArgOut(ArgString);
- Args[Arg].getArgument().print(Policy, ArgOut);
- }
-
- // If this is the first argument and its string representation
- // begins with the global scope specifier ('::foo'), add a space
- // to avoid printing the diagraph '<:'.
- if (!Arg && !ArgString.empty() && ArgString[0] == ':')
- SpecString += ' ';
-
- SpecString += ArgString;
- }
-
- // If the last character of our string is '>', add another space to
- // keep the two '>''s separate tokens. We don't *have* to do this in
- // C++0x, but it's still good hygiene.
- if (SpecString[SpecString.size() - 1] == '>')
- SpecString += ' ';
-
- SpecString += '>';
-
- return SpecString;
-}
-
void QualType::dump(const char *msg) const {
if (msg)
llvm::errs() << msg << ": ";
@@ -1599,11 +1477,7 @@ void QualType::print(const Type *ty, Qualifiers qs,
raw_ostream &OS, const PrintingPolicy &policy,
const Twine &PlaceHolder) {
SmallString<128> PHBuf;
- StringRef PH;
- if (PlaceHolder.isSingleStringRef())
- PH = PlaceHolder.getSingleStringRef();
- else
- PH = PlaceHolder.toStringRef(PHBuf);
+ StringRef PH = PlaceHolder.toStringRef(PHBuf);
TypePrinter(policy).print(ty, qs, OS, PH);
}
diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp
index 33dad40..f80232f 100644
--- a/lib/AST/VTableBuilder.cpp
+++ b/lib/AST/VTableBuilder.cpp
@@ -17,6 +17,7 @@
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cstdio>
@@ -256,11 +257,9 @@ static BaseOffset ComputeBaseOffset(ASTContext &Context,
const CXXRecordDecl *DerivedRD) {
CXXBasePaths Paths(/*FindAmbiguities=*/false,
/*RecordPaths=*/true, /*DetectVirtual=*/false);
-
- if (!const_cast<CXXRecordDecl *>(DerivedRD)->
- isDerivedFrom(const_cast<CXXRecordDecl *>(BaseRD), Paths)) {
+
+ if (!DerivedRD->isDerivedFrom(BaseRD, Paths))
llvm_unreachable("Class must be derived from the passed in base class!");
- }
return ComputeBaseOffset(Context, DerivedRD, Paths.front());
}
@@ -1001,6 +1000,10 @@ public:
dumpLayout(llvm::errs());
}
+ bool isMicrosoftABI() const {
+ return VTables.isMicrosoftABI();
+ }
+
uint64_t getNumThunks() const {
return Thunks.size();
}
@@ -1157,6 +1160,8 @@ void VTableBuilder::ComputeThisAdjustments() {
break;
case VTableComponent::CK_DeletingDtorPointer:
// We've already added the thunk when we saw the complete dtor pointer.
+ // FIXME: check how this works in the Microsoft ABI
+ // while working on the multiple inheritance patch.
continue;
}
@@ -1197,10 +1202,8 @@ VTableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
CXXBasePaths Paths(/*FindAmbiguities=*/true,
/*RecordPaths=*/true, /*DetectVirtual=*/true);
- if (!const_cast<CXXRecordDecl *>(DerivedRD)->
- isDerivedFrom(const_cast<CXXRecordDecl *>(BaseRD), Paths)) {
+ if (!DerivedRD->isDerivedFrom(BaseRD, Paths))
llvm_unreachable("Class must be derived from the passed in base class!");
- }
// We have to go through all the paths, and see which one leads us to the
// right base subobject.
@@ -1295,9 +1298,15 @@ VTableBuilder::AddMethod(const CXXMethodDecl *MD,
assert(ReturnAdjustment.isEmpty() &&
"Destructor can't have return adjustment!");
- // Add both the complete destructor and the deleting destructor.
- Components.push_back(VTableComponent::MakeCompleteDtor(DD));
- Components.push_back(VTableComponent::MakeDeletingDtor(DD));
+ // FIXME: Should probably add a layer of abstraction for vtable generation.
+ if (!isMicrosoftABI()) {
+ // Add both the complete destructor and the deleting destructor.
+ Components.push_back(VTableComponent::MakeCompleteDtor(DD));
+ Components.push_back(VTableComponent::MakeDeletingDtor(DD));
+ } else {
+ // Add the scalar deleting destructor.
+ Components.push_back(VTableComponent::MakeDeletingDtor(DD));
+ }
} else {
// Add the return adjustment if necessary.
if (!ReturnAdjustment.isEmpty())
@@ -1612,14 +1621,19 @@ VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
if (Base.getBase() == MostDerivedClass)
VBaseOffsetOffsets = Builder.getVBaseOffsetOffsets();
- // Add the offset to top.
- CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass;
- Components.push_back(
- VTableComponent::MakeOffsetToTop(OffsetToTop));
-
- // Next, add the RTTI.
- Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass));
-
+ // FIXME: Should probably add a layer of abstraction for vtable generation.
+ if (!isMicrosoftABI()) {
+ // Add the offset to top.
+ CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass;
+ Components.push_back(VTableComponent::MakeOffsetToTop(OffsetToTop));
+
+ // Next, add the RTTI.
+ Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass));
+ } else {
+ // FIXME: unclear what to do with RTTI in MS ABI as emitting it anywhere
+ // breaks the vftable layout. Just skip RTTI for now, can't mangle anyway.
+ }
+
uint64_t AddressPoint = Components.size();
// Now go through all virtual member functions and add them.
@@ -1936,6 +1950,8 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
Out << DD->getQualifiedNameAsString();
if (IsComplete)
Out << "() [complete]";
+ else if (isMicrosoftABI())
+ Out << "() [scalar deleting]";
else
Out << "() [deleting]";
@@ -2120,10 +2136,16 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
MD);
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
- IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Complete))] =
- MethodName + " [complete]";
- IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))] =
- MethodName + " [deleting]";
+ // FIXME: Should add a layer of abstraction for vtable generation.
+ if (!isMicrosoftABI()) {
+ IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Complete))]
+ = MethodName + " [complete]";
+ IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))]
+ = MethodName + " [deleting]";
+ } else {
+ IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))]
+ = MethodName + " [scalar deleting]";
+ }
} else {
IndicesMap[VTables.getMethodVTableIndex(MD)] = MethodName;
}
@@ -2154,12 +2176,14 @@ VTableLayout::VTableLayout(uint64_t NumVTableComponents,
const VTableComponent *VTableComponents,
uint64_t NumVTableThunks,
const VTableThunkTy *VTableThunks,
- const AddressPointsMapTy &AddressPoints)
+ const AddressPointsMapTy &AddressPoints,
+ bool IsMicrosoftABI)
: NumVTableComponents(NumVTableComponents),
VTableComponents(new VTableComponent[NumVTableComponents]),
NumVTableThunks(NumVTableThunks),
VTableThunks(new VTableThunkTy[NumVTableThunks]),
- AddressPoints(AddressPoints) {
+ AddressPoints(AddressPoints),
+ IsMicrosoftABI(IsMicrosoftABI) {
std::copy(VTableComponents, VTableComponents+NumVTableComponents,
this->VTableComponents.get());
std::copy(VTableThunks, VTableThunks+NumVTableThunks,
@@ -2168,6 +2192,11 @@ VTableLayout::VTableLayout(uint64_t NumVTableComponents,
VTableLayout::~VTableLayout() { }
+VTableContext::VTableContext(ASTContext &Context)
+ : Context(Context),
+ IsMicrosoftABI(Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+}
+
VTableContext::~VTableContext() {
llvm::DeleteContainerSeconds(VTableLayouts);
}
@@ -2239,12 +2268,18 @@ void VTableContext::ComputeMethodVTableIndices(const CXXRecordDecl *RD) {
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
const CXXDestructorDecl *OverriddenDD =
cast<CXXDestructorDecl>(OverriddenMD);
-
- // Add both the complete and deleting entries.
- MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] =
- getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Complete));
- MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] =
- getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
+
+ if (!isMicrosoftABI()) {
+ // Add both the complete and deleting entries.
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] =
+ getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Complete));
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] =
+ getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
+ } else {
+ // Add the scalar deleting destructor.
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] =
+ getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
+ }
} else {
MethodVTableIndices[MD] = getMethodVTableIndex(OverriddenMD);
}
@@ -2262,11 +2297,16 @@ void VTableContext::ComputeMethodVTableIndices(const CXXRecordDecl *RD) {
continue;
}
- // Add the complete dtor.
- MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++;
-
- // Add the deleting dtor.
- MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++;
+ if (!isMicrosoftABI()) {
+ // Add the complete dtor.
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++;
+
+ // Add the deleting dtor.
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++;
+ } else {
+ // Add the scalar deleting dtor.
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++;
+ }
} else {
// Add the entry.
MethodVTableIndices[MD] = CurrentIndex++;
@@ -2278,6 +2318,11 @@ void VTableContext::ComputeMethodVTableIndices(const CXXRecordDecl *RD) {
// If a class has an implicitly-defined virtual destructor,
// its entries come after the declared virtual function pointers.
+ if (isMicrosoftABI()) {
+ ErrorUnsupported("implicit virtual destructor in the Microsoft ABI",
+ ImplicitVirtualDtor->getLocation());
+ }
+
// Add the complete dtor.
MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] =
CurrentIndex++;
@@ -2357,7 +2402,8 @@ static VTableLayout *CreateVTableLayout(const VTableBuilder &Builder) {
Builder.vtable_component_begin(),
VTableThunks.size(),
VTableThunks.data(),
- Builder.getAddressPoints());
+ Builder.getAddressPoints(),
+ Builder.isMicrosoftABI());
}
void VTableContext::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) {
@@ -2397,6 +2443,14 @@ void VTableContext::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) {
}
}
+void VTableContext::ErrorUnsupported(StringRef Feature,
+ SourceLocation Location) {
+ clang::DiagnosticsEngine &Diags = Context.getDiagnostics();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "v-table layout for %0 is not supported yet");
+ Diags.Report(Context.getFullLoc(Location), DiagID) << Feature;
+}
+
VTableLayout *VTableContext::createConstructionVTableLayout(
const CXXRecordDecl *MostDerivedClass,
CharUnits MostDerivedClassOffset,
diff --git a/lib/ASTMatchers/ASTMatchFinder.cpp b/lib/ASTMatchers/ASTMatchFinder.cpp
index 8ecb26e..6ebd736 100644
--- a/lib/ASTMatchers/ASTMatchFinder.cpp
+++ b/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -20,6 +20,7 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
+#include <deque>
#include <set>
namespace clang {
@@ -29,62 +30,6 @@ namespace {
typedef MatchFinder::MatchCallback MatchCallback;
-/// \brief A \c RecursiveASTVisitor that builds a map from nodes to their
-/// parents as defined by the \c RecursiveASTVisitor.
-///
-/// Note that the relationship described here is purely in terms of AST
-/// traversal - there are other relationships (for example declaration context)
-/// in the AST that are better modeled by special matchers.
-///
-/// FIXME: Currently only builds up the map using \c Stmt and \c Decl nodes.
-class ParentMapASTVisitor : public RecursiveASTVisitor<ParentMapASTVisitor> {
-public:
- /// \brief Maps from a node to its parent.
- typedef llvm::DenseMap<const void*, ast_type_traits::DynTypedNode> ParentMap;
-
- /// \brief Builds and returns the translation unit's parent map.
- ///
- /// The caller takes ownership of the returned \c ParentMap.
- static ParentMap *buildMap(TranslationUnitDecl &TU) {
- ParentMapASTVisitor Visitor(new ParentMap);
- Visitor.TraverseDecl(&TU);
- return Visitor.Parents;
- }
-
-private:
- typedef RecursiveASTVisitor<ParentMapASTVisitor> VisitorBase;
-
- ParentMapASTVisitor(ParentMap *Parents) : Parents(Parents) {}
-
- bool shouldVisitTemplateInstantiations() const { return true; }
- bool shouldVisitImplicitCode() const { return true; }
-
- template <typename T>
- bool TraverseNode(T *Node, bool (VisitorBase::*traverse)(T*)) {
- if (Node == NULL)
- return true;
- if (ParentStack.size() > 0)
- (*Parents)[Node] = ParentStack.back();
- ParentStack.push_back(ast_type_traits::DynTypedNode::create(*Node));
- bool Result = (this->*traverse)(Node);
- ParentStack.pop_back();
- return Result;
- }
-
- bool TraverseDecl(Decl *DeclNode) {
- return TraverseNode(DeclNode, &VisitorBase::TraverseDecl);
- }
-
- bool TraverseStmt(Stmt *StmtNode) {
- return TraverseNode(StmtNode, &VisitorBase::TraverseStmt);
- }
-
- ParentMap *Parents;
- llvm::SmallVector<ast_type_traits::DynTypedNode, 16> ParentStack;
-
- friend class RecursiveASTVisitor<ParentMapASTVisitor>;
-};
-
// We use memoization to avoid running the same matcher on the same
// AST node twice. This pair is the key for looking up match
// result. It consists of an ID of the MatcherInterface (for
@@ -183,6 +128,8 @@ public:
// We assume that the QualType and the contained type are on the same
// hierarchy level. Thus, we try to match either of them.
bool TraverseType(QualType TypeNode) {
+ if (TypeNode.isNull())
+ return true;
ScopedIncrement ScopedDepth(&CurrentDepth);
// Match the Type.
if (!match(*TypeNode))
@@ -193,6 +140,8 @@ public:
// We assume that the TypeLoc, contained QualType and contained Type all are
// on the same hierarchy level. Thus, we try to match all of them.
bool TraverseTypeLoc(TypeLoc TypeLocNode) {
+ if (TypeLocNode.isNull())
+ return true;
ScopedIncrement ScopedDepth(&CurrentDepth);
// Match the Type.
if (!match(*TypeLocNode.getType()))
@@ -208,14 +157,19 @@ public:
return (NNS == NULL) || traverse(*NNS);
}
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
+ if (!NNS)
+ return true;
ScopedIncrement ScopedDepth(&CurrentDepth);
if (!match(*NNS.getNestedNameSpecifier()))
return false;
- return !NNS || traverse(NNS);
+ return traverse(NNS);
}
bool shouldVisitTemplateInstantiations() const { return true; }
bool shouldVisitImplicitCode() const { return true; }
+ // Disables data recursion. We intercept Traverse* methods in the RAV, which
+ // are not triggered during data recursion.
+ bool shouldUseDataRecursionFor(clang::Stmt *S) const { return false; }
private:
// Used for updating the depth during traversal.
@@ -435,38 +389,118 @@ public:
const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder,
AncestorMatchMode MatchMode) {
- if (!Parents) {
- // We always need to run over the whole translation unit, as
- // \c hasAncestor can escape any subtree.
- Parents.reset(ParentMapASTVisitor::buildMap(
- *ActiveASTContext->getTranslationUnitDecl()));
- }
- ast_type_traits::DynTypedNode Ancestor = Node;
- while (Ancestor.get<TranslationUnitDecl>() !=
- ActiveASTContext->getTranslationUnitDecl()) {
- assert(Ancestor.getMemoizationData() &&
- "Invariant broken: only nodes that support memoization may be "
- "used in the parent map.");
- ParentMapASTVisitor::ParentMap::const_iterator I =
- Parents->find(Ancestor.getMemoizationData());
- if (I == Parents->end()) {
- assert(false &&
- "Found node that is not in the parent map.");
- return false;
+ return memoizedMatchesAncestorOfRecursively(Node, Matcher, Builder,
+ MatchMode);
+ }
+
+ // Matches all registered matchers on the given node and calls the
+ // result callback for every node that matches.
+ void match(const ast_type_traits::DynTypedNode& Node) {
+ for (std::vector<std::pair<const internal::DynTypedMatcher*,
+ MatchCallback*> >::const_iterator
+ I = MatcherCallbackPairs->begin(), E = MatcherCallbackPairs->end();
+ I != E; ++I) {
+ BoundNodesTreeBuilder Builder;
+ if (I->first->matches(Node, this, &Builder)) {
+ BoundNodesTree BoundNodes = Builder.build();
+ MatchVisitor Visitor(ActiveASTContext, I->second);
+ BoundNodes.visitMatches(&Visitor);
}
- Ancestor = I->second;
- if (Matcher.matches(Ancestor, this, Builder))
- return true;
- if (MatchMode == ASTMatchFinder::AMM_ParentOnly)
- return false;
}
- return false;
}
+ template <typename T> void match(const T &Node) {
+ match(ast_type_traits::DynTypedNode::create(Node));
+ }
+
+ // Implements ASTMatchFinder::getASTContext.
+ virtual ASTContext &getASTContext() const { return *ActiveASTContext; }
+
bool shouldVisitTemplateInstantiations() const { return true; }
bool shouldVisitImplicitCode() const { return true; }
+ // Disables data recursion. We intercept Traverse* methods in the RAV, which
+ // are not triggered during data recursion.
+ bool shouldUseDataRecursionFor(clang::Stmt *S) const { return false; }
private:
+ // Returns whether an ancestor of \p Node matches \p Matcher.
+ //
+ // The order of matching ((which can lead to different nodes being bound in
+ // case there are multiple matches) is breadth first search.
+ //
+ // To allow memoization in the very common case of having deeply nested
+ // expressions inside a template function, we first walk up the AST, memoizing
+ // the result of the match along the way, as long as there is only a single
+ // parent.
+ //
+ // Once there are multiple parents, the breadth first search order does not
+ // allow simple memoization on the ancestors. Thus, we only memoize as long
+ // as there is a single parent.
+ bool memoizedMatchesAncestorOfRecursively(
+ const ast_type_traits::DynTypedNode &Node, const DynTypedMatcher &Matcher,
+ BoundNodesTreeBuilder *Builder, AncestorMatchMode MatchMode) {
+ if (Node.get<TranslationUnitDecl>() ==
+ ActiveASTContext->getTranslationUnitDecl())
+ return false;
+ assert(Node.getMemoizationData() &&
+ "Invariant broken: only nodes that support memoization may be "
+ "used in the parent map.");
+ ASTContext::ParentVector Parents = ActiveASTContext->getParents(Node);
+ if (Parents.empty()) {
+ assert(false && "Found node that is not in the parent map.");
+ return false;
+ }
+ const UntypedMatchInput input(Matcher.getID(), Node.getMemoizationData());
+ MemoizationMap::iterator I = ResultCache.find(input);
+ if (I == ResultCache.end()) {
+ BoundNodesTreeBuilder AncestorBoundNodesBuilder;
+ bool Matches = false;
+ if (Parents.size() == 1) {
+ // Only one parent - do recursive memoization.
+ const ast_type_traits::DynTypedNode Parent = Parents[0];
+ if (Matcher.matches(Parent, this, &AncestorBoundNodesBuilder)) {
+ Matches = true;
+ } else if (MatchMode != ASTMatchFinder::AMM_ParentOnly) {
+ Matches = memoizedMatchesAncestorOfRecursively(
+ Parent, Matcher, &AncestorBoundNodesBuilder, MatchMode);
+ }
+ } else {
+ // Multiple parents - BFS over the rest of the nodes.
+ llvm::DenseSet<const void *> Visited;
+ std::deque<ast_type_traits::DynTypedNode> Queue(Parents.begin(),
+ Parents.end());
+ while (!Queue.empty()) {
+ if (Matcher.matches(Queue.front(), this,
+ &AncestorBoundNodesBuilder)) {
+ Matches = true;
+ break;
+ }
+ if (MatchMode != ASTMatchFinder::AMM_ParentOnly) {
+ ASTContext::ParentVector Ancestors =
+ ActiveASTContext->getParents(Queue.front());
+ for (ASTContext::ParentVector::const_iterator I = Ancestors.begin(),
+ E = Ancestors.end();
+ I != E; ++I) {
+ // Make sure we do not visit the same node twice.
+ // Otherwise, we'll visit the common ancestors as often as there
+ // are splits on the way down.
+ if (Visited.insert(I->getMemoizationData()).second)
+ Queue.push_back(*I);
+ }
+ }
+ Queue.pop_front();
+ }
+ }
+
+ I = ResultCache.insert(std::make_pair(input, MemoizedMatchResult()))
+ .first;
+ I->second.Nodes = AncestorBoundNodesBuilder.build();
+ I->second.ResultOfMatch = Matches;
+ }
+ I->second.Nodes.copyTo(Builder);
+ return I->second.ResultOfMatch;
+ }
+
// Implements a BoundNodesTree::Visitor that calls a MatchCallback with
// the aggregated bound nodes for each match.
class MatchVisitor : public BoundNodesTree::Visitor {
@@ -501,24 +535,6 @@ private:
return false;
}
- // Matches all registered matchers on the given node and calls the
- // result callback for every node that matches.
- template <typename T>
- void match(const T &node) {
- for (std::vector<std::pair<const internal::DynTypedMatcher*,
- MatchCallback*> >::const_iterator
- I = MatcherCallbackPairs->begin(), E = MatcherCallbackPairs->end();
- I != E; ++I) {
- BoundNodesTreeBuilder Builder;
- if (I->first->matches(ast_type_traits::DynTypedNode::create(node),
- this, &Builder)) {
- BoundNodesTree BoundNodes = Builder.build();
- MatchVisitor Visitor(ActiveASTContext, I->second);
- BoundNodes.visitMatches(&Visitor);
- }
- }
- }
-
std::vector<std::pair<const internal::DynTypedMatcher*,
MatchCallback*> > *const MatcherCallbackPairs;
ASTContext *ActiveASTContext;
@@ -529,8 +545,6 @@ private:
// Maps (matcher, node) -> the match result for memoization.
typedef llvm::DenseMap<UntypedMatchInput, MemoizedMatchResult> MemoizationMap;
MemoizationMap ResultCache;
-
- llvm::OwningPtr<ParentMapASTVisitor::ParentMap> Parents;
};
// Returns true if the given class is directly or indirectly derived
@@ -579,7 +593,7 @@ bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
if (SpecializationDecl != NULL) {
ClassDecl = SpecializationDecl;
} else {
- ClassDecl = llvm::dyn_cast<CXXRecordDecl>(
+ ClassDecl = dyn_cast<CXXRecordDecl>(
TemplateType->getTemplateName()
.getAsTemplateDecl()->getTemplatedDecl());
}
@@ -587,7 +601,12 @@ bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
ClassDecl = TypeNode->getAsCXXRecordDecl();
}
assert(ClassDecl != NULL);
- assert(ClassDecl != Declaration);
+ if (ClassDecl == Declaration) {
+ // This can happen for recursive template definitions; if the
+ // current declaration did not match, we can safely return false.
+ assert(TemplateType);
+ return false;
+ }
if (Base.matches(*ClassDecl, this, Builder))
return true;
if (classIsDerivedFrom(ClassDecl, Base, Builder))
@@ -729,16 +748,11 @@ ASTConsumer *MatchFinder::newASTConsumer() {
return new internal::MatchASTConsumer(&MatcherCallbackPairs, ParsingDone);
}
-void MatchFinder::findAll(const Decl &Node, ASTContext &Context) {
- internal::MatchASTVisitor Visitor(&MatcherCallbackPairs);
- Visitor.set_active_ast_context(&Context);
- Visitor.TraverseDecl(const_cast<Decl*>(&Node));
-}
-
-void MatchFinder::findAll(const Stmt &Node, ASTContext &Context) {
+void MatchFinder::match(const clang::ast_type_traits::DynTypedNode &Node,
+ ASTContext &Context) {
internal::MatchASTVisitor Visitor(&MatcherCallbackPairs);
Visitor.set_active_ast_context(&Context);
- Visitor.TraverseStmt(const_cast<Stmt*>(&Node));
+ Visitor.match(Node);
}
void MatchFinder::registerTestCallbackAfterParsing(
diff --git a/lib/ASTMatchers/ASTMatchersInternal.cpp b/lib/ASTMatchers/ASTMatchersInternal.cpp
index 408195d..f1a9ff2 100644
--- a/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -27,8 +27,11 @@ void BoundNodesMap::copyTo(BoundNodesTreeBuilder *Builder) const {
}
void BoundNodesMap::copyTo(BoundNodesMap *Other) const {
- copy(NodeMap.begin(), NodeMap.end(),
- inserter(Other->NodeMap, Other->NodeMap.begin()));
+ for (IDToNodeMap::const_iterator I = NodeMap.begin(),
+ E = NodeMap.end();
+ I != E; ++I) {
+ Other->NodeMap[I->first] = I->second;
+ }
}
BoundNodesTree::BoundNodesTree() {}
diff --git a/lib/ASTMatchers/CMakeLists.txt b/lib/ASTMatchers/CMakeLists.txt
index 8fc7d4b..86560d6 100644
--- a/lib/ASTMatchers/CMakeLists.txt
+++ b/lib/ASTMatchers/CMakeLists.txt
@@ -1,5 +1,4 @@
set(LLVM_LINK_COMPONENTS support)
-set(LLVM_USED_LIBS clangBasic clangAST)
add_clang_library(clangASTMatchers
ASTMatchFinder.cpp
@@ -15,3 +14,8 @@ add_dependencies(clangASTMatchers
ClangDiagnosticCommon
ClangStmtNodes
)
+
+target_link_libraries(clangASTMatchers
+ clangBasic
+ clangAST
+ )
diff --git a/lib/Analysis/AnalysisDeclContext.cpp b/lib/Analysis/AnalysisDeclContext.cpp
index e7df0a8..5ff7842 100644
--- a/lib/Analysis/AnalysisDeclContext.cpp
+++ b/lib/Analysis/AnalysisDeclContext.cpp
@@ -12,24 +12,24 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Analysis/AnalysisContext.h"
+#include "BodyFarm.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/Analyses/PseudoConstantAnalysis.h"
-#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
-#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/CFGStmtMap.h"
#include "clang/Analysis/Support/BumpVector.h"
-#include "llvm/Support/SaveAndRestore.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/ErrorHandling.h"
-
-#include "BodyFarm.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
@@ -67,13 +67,15 @@ AnalysisDeclContextManager::AnalysisDeclContextManager(bool useUnoptimizedCFG,
bool addImplicitDtors,
bool addInitializers,
bool addTemporaryDtors,
- bool synthesizeBodies)
+ bool synthesizeBodies,
+ bool addStaticInitBranch)
: SynthesizeBodies(synthesizeBodies)
{
cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG;
cfgBuildOptions.AddImplicitDtors = addImplicitDtors;
cfgBuildOptions.AddInitializers = addInitializers;
cfgBuildOptions.AddTemporaryDtors = addTemporaryDtors;
+ cfgBuildOptions.AddStaticInitBranches = addStaticInitBranch;
}
void AnalysisDeclContextManager::clear() {
@@ -87,11 +89,14 @@ static BodyFarm &getBodyFarm(ASTContext &C) {
return *BF;
}
-Stmt *AnalysisDeclContext::getBody() const {
+Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const {
+ IsAutosynthesized = false;
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
Stmt *Body = FD->getBody();
- if (!Body && Manager && Manager->synthesizeBodies())
+ if (!Body && Manager && Manager->synthesizeBodies()) {
+ IsAutosynthesized = true;
return getBodyFarm(getASTContext()).getBody(FD);
+ }
return Body;
}
else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
@@ -105,6 +110,17 @@ Stmt *AnalysisDeclContext::getBody() const {
llvm_unreachable("unknown code decl");
}
+Stmt *AnalysisDeclContext::getBody() const {
+ bool Tmp;
+ return getBody(Tmp);
+}
+
+bool AnalysisDeclContext::isBodyAutosynthesized() const {
+ bool Tmp;
+ getBody(Tmp);
+ return Tmp;
+}
+
const ImplicitParamDecl *AnalysisDeclContext::getSelfDecl() const {
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
return MD->getSelfDecl();
@@ -371,6 +387,31 @@ bool LocationContext::isParentOf(const LocationContext *LC) const {
return false;
}
+void LocationContext::dumpStack() const {
+ ASTContext &Ctx = getAnalysisDeclContext()->getASTContext();
+ PrintingPolicy PP(Ctx.getLangOpts());
+ PP.TerseOutput = 1;
+
+ unsigned Frame = 0;
+ for (const LocationContext *LCtx = this; LCtx; LCtx = LCtx->getParent()) {
+ switch (LCtx->getKind()) {
+ case StackFrame:
+ llvm::errs() << '#' << Frame++ << ' ';
+ cast<StackFrameContext>(LCtx)->getDecl()->print(llvm::errs(), PP);
+ llvm::errs() << '\n';
+ break;
+ case Scope:
+ llvm::errs() << " (scope)\n";
+ break;
+ case Block:
+ llvm::errs() << " (block context: "
+ << cast<BlockInvocationContext>(LCtx)->getContextData()
+ << ")\n";
+ break;
+ }
+ }
+}
+
//===----------------------------------------------------------------------===//
// Lazily generated map to query the external variables referenced by a Block.
//===----------------------------------------------------------------------===//
@@ -403,9 +444,6 @@ public:
if (!VD->hasLocalStorage()) {
if (Visited.insert(VD))
BEVals.push_back(VD, BC);
- } else if (DR->refersToEnclosingLocal()) {
- if (Visited.insert(VD) && IsTrackedDecl(VD))
- BEVals.push_back(VD, BC);
}
}
}
@@ -440,7 +478,13 @@ static DeclVec* LazyInitializeReferencedDecls(const BlockDecl *BD,
DeclVec *BV = (DeclVec*) A.Allocate<DeclVec>();
new (BV) DeclVec(BC, 10);
- // Find the referenced variables.
+ // Go through the capture list.
+ for (BlockDecl::capture_const_iterator CI = BD->capture_begin(),
+ CE = BD->capture_end(); CI != CE; ++CI) {
+ BV->push_back(CI->getVariable(), BC);
+ }
+
+ // Find the referenced global/static variables.
FindBlockDeclRefExprsVals F(*BV, BC);
F.Visit(BD->getBody());
diff --git a/lib/Analysis/BodyFarm.cpp b/lib/Analysis/BodyFarm.cpp
index 794ff9c..dda26bf 100644
--- a/lib/Analysis/BodyFarm.cpp
+++ b/lib/Analysis/BodyFarm.cpp
@@ -12,12 +12,12 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/ADT/StringSwitch.h"
+#include "BodyFarm.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/Expr.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
-#include "BodyFarm.h"
+#include "llvm/ADT/StringSwitch.h"
using namespace clang;
@@ -103,9 +103,7 @@ BinaryOperator *ASTMaker::makeComparison(const Expr *LHS, const Expr *RHS,
}
CompoundStmt *ASTMaker::makeCompound(ArrayRef<Stmt *> Stmts) {
- return new (C) CompoundStmt(C, const_cast<Stmt**>(Stmts.data()),
- Stmts.size(),
- SourceLocation(), SourceLocation());
+ return new (C) CompoundStmt(C, Stmts, SourceLocation(), SourceLocation());
}
DeclRefExpr *ASTMaker::makeDeclRefExpr(const VarDecl *D) {
@@ -270,7 +268,11 @@ static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D)
if (D->param_size() != 3)
return 0;
- // Body for:
+ // Signature:
+ // _Bool OSAtomicCompareAndSwapPtr(void *__oldValue,
+ // void *__newValue,
+ // void * volatile *__theValue)
+ // Generate body:
// if (oldValue == *theValue) {
// *theValue = newValue;
// return YES;
@@ -342,7 +344,7 @@ static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D)
Stmt *BodyFarm::getBody(const FunctionDecl *D) {
D = D->getCanonicalDecl();
- llvm::Optional<Stmt *> &Val = Bodies[D];
+ Optional<Stmt *> &Val = Bodies[D];
if (Val.hasValue())
return Val.getValue();
diff --git a/lib/Analysis/BodyFarm.h b/lib/Analysis/BodyFarm.h
index d503cc1..96f61df 100644
--- a/lib/Analysis/BodyFarm.h
+++ b/lib/Analysis/BodyFarm.h
@@ -15,8 +15,9 @@
#ifndef LLVM_CLANG_ANALYSIS_BODYFARM_H
#define LLVM_CLANG_ANALYSIS_BODYFARM_H
-#include "llvm/ADT/Optional.h"
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Optional.h"
namespace clang {
@@ -33,7 +34,7 @@ public:
Stmt *getBody(const FunctionDecl *D);
private:
- typedef llvm::DenseMap<const Decl *, llvm::Optional<Stmt *> > BodyMap;
+ typedef llvm::DenseMap<const Decl *, Optional<Stmt *> > BodyMap;
ASTContext &C;
BodyMap Bodies;
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index 315e543..1adb8b8 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -12,20 +12,20 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/Support/SaveAndRestore.h"
#include "clang/Analysis/CFG.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclCXX.h"
-#include "clang/AST/StmtVisitor.h"
#include "clang/AST/PrettyPrinter.h"
-#include "clang/AST/CharUnits.h"
-#include "clang/Basic/AttrKinds.h"
-#include "llvm/Support/GraphWriter.h"
-#include "llvm/Support/Allocator.h"
-#include "llvm/Support/Format.h"
+#include "clang/AST/StmtVisitor.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/GraphWriter.h"
+#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
@@ -233,6 +233,44 @@ public:
}
};
+class reverse_children {
+ llvm::SmallVector<Stmt *, 12> childrenBuf;
+ ArrayRef<Stmt*> children;
+public:
+ reverse_children(Stmt *S);
+
+ typedef ArrayRef<Stmt*>::reverse_iterator iterator;
+ iterator begin() const { return children.rbegin(); }
+ iterator end() const { return children.rend(); }
+};
+
+
+reverse_children::reverse_children(Stmt *S) {
+ if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
+ children = CE->getRawSubExprs();
+ return;
+ }
+ switch (S->getStmtClass()) {
+ // Note: Fill in this switch with more cases we want to optimize.
+ case Stmt::InitListExprClass: {
+ InitListExpr *IE = cast<InitListExpr>(S);
+ children = llvm::makeArrayRef(reinterpret_cast<Stmt**>(IE->getInits()),
+ IE->getNumInits());
+ return;
+ }
+ default:
+ break;
+ }
+
+ // Default case for all other statements.
+ for (Stmt::child_range I = S->children(); I; ++I) {
+ childrenBuf.push_back(*I);
+ }
+
+ // This needs to be done *after* childrenBuf has been populated.
+ children = childrenBuf;
+}
+
/// CFGBuilder - This class implements CFG construction from an AST.
/// The builder is stateful: an instance of the builder should be used to only
/// construct a single CFG.
@@ -637,7 +675,7 @@ CFG* CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) {
E = BackpatchBlocks.end(); I != E; ++I ) {
CFGBlock *B = I->block;
- GotoStmt *G = cast<GotoStmt>(B->getTerminator());
+ const GotoStmt *G = cast<GotoStmt>(B->getTerminator());
LabelMapTy::iterator LI = LabelMap.find(G->getLabel());
// If there is no target for the goto, then we are looking at an
@@ -807,7 +845,7 @@ void CFGBuilder::addAutomaticObjDtors(LocalScope::const_iterator B,
Ty = Context->getBaseElementType(Ty);
const CXXDestructorDecl *Dtor = Ty->getAsCXXRecordDecl()->getDestructor();
- if (cast<FunctionType>(Dtor->getType())->getNoReturnAttr())
+ if (Dtor->isNoReturn())
Block = createNoReturnBlock();
else
autoCreateBlock();
@@ -1166,14 +1204,19 @@ CFGBlock *CFGBuilder::VisitStmt(Stmt *S, AddStmtChoice asc) {
}
/// VisitChildren - Visit the children of a Stmt.
-CFGBlock *CFGBuilder::VisitChildren(Stmt *Terminator) {
- CFGBlock *lastBlock = Block;
- for (Stmt::child_range I = Terminator->children(); I; ++I)
- if (Stmt *child = *I)
- if (CFGBlock *b = Visit(child))
- lastBlock = b;
+CFGBlock *CFGBuilder::VisitChildren(Stmt *S) {
+ CFGBlock *B = Block;
- return lastBlock;
+ // Visit the children in their reverse order so that they appear in
+ // left-to-right (natural) order in the CFG.
+ reverse_children RChildren(S);
+ for (reverse_children::iterator I = RChildren.begin(), E = RChildren.end();
+ I != E; ++I) {
+ if (Stmt *Child = *I)
+ if (CFGBlock *R = Visit(Child))
+ B = R;
+ }
+ return B;
}
CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A,
@@ -1402,7 +1445,7 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
}
if (FunctionDecl *FD = C->getDirectCallee()) {
- if (FD->hasAttr<NoReturnAttr>())
+ if (FD->isNoReturn())
NoReturn = true;
if (FD->hasAttr<NoThrowAttr>())
AddEHEdge = false;
@@ -1610,6 +1653,21 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
bool IsReference = false;
bool HasTemporaries = false;
+ // Guard static initializers under a branch.
+ CFGBlock *blockAfterStaticInit = 0;
+
+ if (BuildOpts.AddStaticInitBranches && VD->isStaticLocal()) {
+ // For static variables, we need to create a branch to track
+ // whether or not they are initialized.
+ if (Block) {
+ Succ = Block;
+ Block = 0;
+ if (badCFG)
+ return 0;
+ }
+ blockAfterStaticInit = Succ;
+ }
+
// Destructors of temporaries in initialization expression should be called
// after initialization finishes.
Expr *Init = VD->getInit();
@@ -1657,7 +1715,17 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
if (ScopePos && VD == *ScopePos)
++ScopePos;
- return Block ? Block : LastBlock;
+ CFGBlock *B = LastBlock;
+ if (blockAfterStaticInit) {
+ Succ = B;
+ Block = createBlock(false);
+ Block->setTerminator(DS);
+ addSuccessor(Block, blockAfterStaticInit);
+ addSuccessor(Block, B);
+ B = Block;
+ }
+
+ return B;
}
CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) {
@@ -3093,19 +3161,14 @@ tryAgain:
CFGBlock *CFGBuilder::VisitChildrenForTemporaryDtors(Stmt *E) {
// When visiting children for destructors we want to visit them in reverse
- // order. Because there's no reverse iterator for children must to reverse
- // them in helper vector.
- typedef SmallVector<Stmt *, 4> ChildrenVect;
- ChildrenVect ChildrenRev;
- for (Stmt::child_range I = E->children(); I; ++I) {
- if (*I) ChildrenRev.push_back(*I);
- }
-
+ // order that they will appear in the CFG. Because the CFG is built
+ // bottom-up, this means we visit them in their natural order, which
+ // reverses them in the CFG.
CFGBlock *B = Block;
- for (ChildrenVect::reverse_iterator I = ChildrenRev.rbegin(),
- L = ChildrenRev.rend(); I != L; ++I) {
- if (CFGBlock *R = VisitForTemporaryDtors(*I))
- B = R;
+ for (Stmt::child_range I = E->children(); I; ++I) {
+ if (Stmt *Child = *I)
+ if (CFGBlock *R = VisitForTemporaryDtors(Child))
+ B = R;
}
return B;
}
@@ -3190,7 +3253,7 @@ CFGBlock *CFGBuilder::VisitCXXBindTemporaryExprForTemporaryDtors(
// a new block for the destructor which does not have as a successor
// anything built thus far. Control won't flow out of this block.
const CXXDestructorDecl *Dtor = E->getTemporary()->getDestructor();
- if (cast<FunctionType>(Dtor->getType())->getNoReturnAttr())
+ if (Dtor->isNoReturn())
Block = createNoReturnBlock();
else
autoCreateBlock();
@@ -3294,13 +3357,12 @@ CFG* CFG::buildCFG(const Decl *D, Stmt *Statement, ASTContext *C,
const CXXDestructorDecl *
CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const {
switch (getKind()) {
- case CFGElement::Invalid:
case CFGElement::Statement:
case CFGElement::Initializer:
llvm_unreachable("getDestructorDecl should only be used with "
"ImplicitDtors");
case CFGElement::AutomaticObjectDtor: {
- const VarDecl *var = cast<CFGAutomaticObjDtor>(this)->getVarDecl();
+ const VarDecl *var = castAs<CFGAutomaticObjDtor>().getVarDecl();
QualType ty = var->getType();
ty = ty.getNonReferenceType();
while (const ArrayType *arrayType = astContext.getAsArrayType(ty)) {
@@ -3313,7 +3375,7 @@ CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const {
}
case CFGElement::TemporaryDtor: {
const CXXBindTemporaryExpr *bindExpr =
- cast<CFGTemporaryDtor>(this)->getBindTemporaryExpr();
+ castAs<CFGTemporaryDtor>().getBindTemporaryExpr();
const CXXTemporary *temp = bindExpr->getTemporary();
return temp->getDestructor();
}
@@ -3327,10 +3389,8 @@ CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const {
}
bool CFGImplicitDtor::isNoReturn(ASTContext &astContext) const {
- if (const CXXDestructorDecl *decl = getDestructorDecl(astContext)) {
- QualType ty = decl->getType();
- return cast<FunctionType>(ty)->getNoReturnAttr();
- }
+ if (const CXXDestructorDecl *DD = getDestructorDecl(astContext))
+ return DD->isNoReturn();
return false;
}
@@ -3370,7 +3430,7 @@ static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) {
for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I)
for (CFGBlock::iterator BI=(*I)->begin(), EI=(*I)->end(); BI != EI; ++BI)
- if (const CFGStmt *S = BI->getAs<CFGStmt>())
+ if (Optional<CFGStmt> S = BI->getAs<CFGStmt>())
FindSubExprAssignments(S->getStmt(), SubExprAssignments);
for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I) {
@@ -3379,7 +3439,7 @@ static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) {
// block-level that are block-level expressions.
for (CFGBlock::iterator BI=(*I)->begin(), EI=(*I)->end(); BI != EI; ++BI) {
- const CFGStmt *CS = BI->getAs<CFGStmt>();
+ Optional<CFGStmt> CS = BI->getAs<CFGStmt>();
if (!CS)
continue;
if (const Expr *Exp = dyn_cast<Expr>(CS->getStmt())) {
@@ -3495,7 +3555,7 @@ public:
unsigned j = 1;
for (CFGBlock::const_iterator BI = (*I)->begin(), BEnd = (*I)->end() ;
BI != BEnd; ++BI, ++j ) {
- if (const CFGStmt *SE = BI->getAs<CFGStmt>()) {
+ if (Optional<CFGStmt> SE = BI->getAs<CFGStmt>()) {
const Stmt *stmt= SE->getStmt();
std::pair<unsigned, unsigned> P((*I)->getBlockID(), j);
StmtMap[stmt] = P;
@@ -3607,6 +3667,11 @@ public:
Terminator->printPretty(OS, Helper, Policy);
}
+ void VisitDeclStmt(DeclStmt *DS) {
+ VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
+ OS << "static init " << VD->getName();
+ }
+
void VisitForStmt(ForStmt *F) {
OS << "for (" ;
if (F->getInit())
@@ -3685,7 +3750,7 @@ public:
static void print_elem(raw_ostream &OS, StmtPrinterHelper* Helper,
const CFGElement &E) {
- if (const CFGStmt *CS = E.getAs<CFGStmt>()) {
+ if (Optional<CFGStmt> CS = E.getAs<CFGStmt>()) {
const Stmt *S = CS->getStmt();
if (Helper) {
@@ -3733,7 +3798,7 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper* Helper,
if (isa<Expr>(S))
OS << '\n';
- } else if (const CFGInitializer *IE = E.getAs<CFGInitializer>()) {
+ } else if (Optional<CFGInitializer> IE = E.getAs<CFGInitializer>()) {
const CXXCtorInitializer *I = IE->getInitializer();
if (I->isBaseInitializer())
OS << I->getBaseClass()->getAsCXXRecordDecl()->getName();
@@ -3748,7 +3813,8 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper* Helper,
OS << " (Base initializer)\n";
else OS << " (Member initializer)\n";
- } else if (const CFGAutomaticObjDtor *DE = E.getAs<CFGAutomaticObjDtor>()){
+ } else if (Optional<CFGAutomaticObjDtor> DE =
+ E.getAs<CFGAutomaticObjDtor>()) {
const VarDecl *VD = DE->getVarDecl();
Helper->handleDecl(VD, OS);
@@ -3760,19 +3826,19 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper* Helper,
OS << ".~" << T->getAsCXXRecordDecl()->getName().str() << "()";
OS << " (Implicit destructor)\n";
- } else if (const CFGBaseDtor *BE = E.getAs<CFGBaseDtor>()) {
+ } else if (Optional<CFGBaseDtor> BE = E.getAs<CFGBaseDtor>()) {
const CXXBaseSpecifier *BS = BE->getBaseSpecifier();
OS << "~" << BS->getType()->getAsCXXRecordDecl()->getName() << "()";
OS << " (Base object destructor)\n";
- } else if (const CFGMemberDtor *ME = E.getAs<CFGMemberDtor>()) {
+ } else if (Optional<CFGMemberDtor> ME = E.getAs<CFGMemberDtor>()) {
const FieldDecl *FD = ME->getFieldDecl();
const Type *T = FD->getType()->getBaseElementTypeUnsafe();
OS << "this->" << FD->getName();
OS << ".~" << T->getAsCXXRecordDecl()->getName() << "()";
OS << " (Member object destructor)\n";
- } else if (const CFGTemporaryDtor *TE = E.getAs<CFGTemporaryDtor>()) {
+ } else if (Optional<CFGTemporaryDtor> TE = E.getAs<CFGTemporaryDtor>()) {
const CXXBindTemporaryExpr *BT = TE->getBindTemporaryExpr();
OS << "~" << BT->getType()->getAsCXXRecordDecl()->getName() << "()";
OS << " (Temporary object destructor)\n";
@@ -3893,7 +3959,7 @@ static void print_block(raw_ostream &OS, const CFG* cfg,
for (CFGBlock::const_pred_iterator I = B.pred_begin(), E = B.pred_end();
I != E; ++I, ++i) {
- if (i == 8 || (i-8) == 0)
+ if (i % 10 == 8)
OS << "\n ";
OS << " B" << (*I)->getBlockID();
@@ -3922,7 +3988,7 @@ static void print_block(raw_ostream &OS, const CFG* cfg,
for (CFGBlock::const_succ_iterator I = B.succ_begin(), E = B.succ_end();
I != E; ++I, ++i) {
- if (i == 8 || (i-8) % 10 == 0)
+ if (i % 10 == 8)
OS << "\n ";
if (*I)
diff --git a/lib/Analysis/CFGStmtMap.cpp b/lib/Analysis/CFGStmtMap.cpp
index 16df676..87c2f5b 100644
--- a/lib/Analysis/CFGStmtMap.cpp
+++ b/lib/Analysis/CFGStmtMap.cpp
@@ -50,7 +50,7 @@ static void Accumulate(SMap &SM, CFGBlock *B) {
// First walk the block-level expressions.
for (CFGBlock::iterator I = B->begin(), E = B->end(); I != E; ++I) {
const CFGElement &CE = *I;
- const CFGStmt *CS = CE.getAs<CFGStmt>();
+ Optional<CFGStmt> CS = CE.getAs<CFGStmt>();
if (!CS)
continue;
diff --git a/lib/Analysis/CallGraph.cpp b/lib/Analysis/CallGraph.cpp
index 6b75956..3387015 100644
--- a/lib/Analysis/CallGraph.cpp
+++ b/lib/Analysis/CallGraph.cpp
@@ -10,16 +10,21 @@
// This file defines the AST-based CallGraph.
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/CallGraph.h"
+#define DEBUG_TYPE "CallGraph"
+#include "clang/Analysis/CallGraph.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/StmtVisitor.h"
-
+#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/ADT/Statistic.h"
#include "llvm/Support/GraphWriter.h"
using namespace clang;
+STATISTIC(NumObjCCallEdges, "Number of Objective-C method call edges");
+STATISTIC(NumBlockCallEdges, "Number of block call edges");
+
namespace {
/// A helper class, which walks the AST and locates all the call sites in the
/// given function body.
@@ -33,13 +38,48 @@ public:
void VisitStmt(Stmt *S) { VisitChildren(S); }
- void VisitCallExpr(CallExpr *CE) {
- // TODO: We need to handle ObjC method calls as well.
+ Decl *getDeclFromCall(CallExpr *CE) {
if (FunctionDecl *CalleeDecl = CE->getDirectCallee())
- if (G->includeInGraph(CalleeDecl)) {
- CallGraphNode *CalleeNode = G->getOrInsertNode(CalleeDecl);
- CallerNode->addCallee(CalleeNode, G);
+ return CalleeDecl;
+
+ // Simple detection of a call through a block.
+ Expr *CEE = CE->getCallee()->IgnoreParenImpCasts();
+ if (BlockExpr *Block = dyn_cast<BlockExpr>(CEE)) {
+ NumBlockCallEdges++;
+ return Block->getBlockDecl();
+ }
+
+ return 0;
+ }
+
+ void addCalledDecl(Decl *D) {
+ if (G->includeInGraph(D)) {
+ CallGraphNode *CalleeNode = G->getOrInsertNode(D);
+ CallerNode->addCallee(CalleeNode, G);
+ }
+ }
+
+ void VisitCallExpr(CallExpr *CE) {
+ if (Decl *D = getDeclFromCall(CE))
+ addCalledDecl(D);
+ }
+
+ // Adds may-call edges for the ObjC message sends.
+ void VisitObjCMessageExpr(ObjCMessageExpr *ME) {
+ if (ObjCInterfaceDecl *IDecl = ME->getReceiverInterface()) {
+ Selector Sel = ME->getSelector();
+
+ // Find the callee definition within the same translation unit.
+ Decl *D = 0;
+ if (ME->isInstanceMessage())
+ D = IDecl->lookupPrivateMethod(Sel);
+ else
+ D = IDecl->lookupPrivateClassMethod(Sel);
+ if (D) {
+ addCalledDecl(D);
+ NumObjCCallEdges++;
}
+ }
}
void VisitChildren(Stmt *S) {
@@ -51,6 +91,16 @@ public:
} // end anonymous namespace
+void CallGraph::addNodesForBlocks(DeclContext *D) {
+ if (BlockDecl *BD = dyn_cast<BlockDecl>(D))
+ addNodeForDecl(BD, true);
+
+ for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end();
+ I!=E; ++I)
+ if (DeclContext *DC = dyn_cast<DeclContext>(*I))
+ addNodesForBlocks(DC);
+}
+
CallGraph::CallGraph() {
Root = getOrInsertNode(0);
}
@@ -65,6 +115,10 @@ CallGraph::~CallGraph() {
}
bool CallGraph::includeInGraph(const Decl *D) {
+ assert(D);
+ if (!D->getBody())
+ return false;
+
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// We skip function template definitions, as their semantics is
// only determined when they are instantiated.
@@ -88,14 +142,8 @@ bool CallGraph::includeInGraph(const Decl *D) {
void CallGraph::addNodeForDecl(Decl* D, bool IsGlobal) {
assert(D);
- // Do nothing if the node already exists.
- if (FunctionMap.find(D) != FunctionMap.end())
- return;
-
// Allocate a new node, mark it as root, and process it's calls.
CallGraphNode *Node = getOrInsertNode(D);
- if (IsGlobal)
- Root->addCallee(Node, this);
// Process all the calls by this function as well.
CGBuilder builder(this, Node);
@@ -115,23 +163,31 @@ CallGraphNode *CallGraph::getOrInsertNode(Decl *F) {
return Node;
Node = new CallGraphNode(F);
- // If not root, add to the parentless list.
+ // Make Root node a parent of all functions to make sure all are reachable.
if (F != 0)
- ParentlessNodes.insert(Node);
+ Root->addCallee(Node, this);
return Node;
}
void CallGraph::print(raw_ostream &OS) const {
OS << " --- Call graph Dump --- \n";
- for (const_iterator I = begin(), E = end(); I != E; ++I) {
+
+ // We are going to print the graph in reverse post order, partially, to make
+ // sure the output is deterministic.
+ llvm::ReversePostOrderTraversal<const clang::CallGraph*> RPOT(this);
+ for (llvm::ReversePostOrderTraversal<const clang::CallGraph*>::rpo_iterator
+ I = RPOT.begin(), E = RPOT.end(); I != E; ++I) {
+ const CallGraphNode *N = *I;
+
OS << " Function: ";
- if (I->second == Root)
+ if (N == Root)
OS << "< root >";
else
- I->second->print(OS);
+ N->print(OS);
+
OS << " calls: ";
- for (CallGraphNode::iterator CI = I->second->begin(),
- CE = I->second->end(); CI != CE; ++CI) {
+ for (CallGraphNode::const_iterator CI = N->begin(),
+ CE = N->end(); CI != CE; ++CI) {
assert(*CI != Root && "No one can call the root node.");
(*CI)->print(OS);
OS << " ";
@@ -149,15 +205,10 @@ void CallGraph::viewGraph() const {
llvm::ViewGraph(this, "CallGraph");
}
-StringRef CallGraphNode::getName() const {
- if (const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(FD))
- if (const IdentifierInfo *II = D->getIdentifier())
- return II->getName();
- return "< >";
-}
-
void CallGraphNode::print(raw_ostream &os) const {
- os << getName();
+ if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(FD))
+ return ND->printName(os);
+ os << "< >";
}
void CallGraphNode::dump() const {
@@ -176,7 +227,10 @@ struct DOTGraphTraits<const CallGraph*> : public DefaultDOTGraphTraits {
if (CG->getRoot() == Node) {
return "< root >";
}
- return Node->getName();
+ if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Node->getDecl()))
+ return ND->getNameAsString();
+ else
+ return "< >";
}
};
diff --git a/lib/Analysis/CocoaConventions.cpp b/lib/Analysis/CocoaConventions.cpp
index ce973af..0db3cac 100644
--- a/lib/Analysis/CocoaConventions.cpp
+++ b/lib/Analysis/CocoaConventions.cpp
@@ -12,12 +12,12 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
-#include "clang/AST/Type.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/CharInfo.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/ErrorHandling.h"
-#include <cctype>
using namespace clang;
using namespace ento;
@@ -106,7 +106,7 @@ bool coreFoundation::followsCreateRule(const FunctionDecl *fn) {
char ch = *it;
if (ch == 'C' || ch == 'c') {
// Make sure this isn't something like 'recreate' or 'Scopy'.
- if (ch == 'c' && it != start && isalpha(*(it - 1)))
+ if (ch == 'c' && it != start && isLetter(*(it - 1)))
continue;
++it;
@@ -131,7 +131,7 @@ bool coreFoundation::followsCreateRule(const FunctionDecl *fn) {
continue;
}
- if (it == endI || !islower(*it))
+ if (it == endI || !isLowercase(*it))
return true;
// If we matched a lowercase character, it isn't the end of the
diff --git a/lib/Analysis/FormatString.cpp b/lib/Analysis/FormatString.cpp
index 73063b5..ad0dce4 100644
--- a/lib/Analysis/FormatString.cpp
+++ b/lib/Analysis/FormatString.cpp
@@ -204,7 +204,7 @@ clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,
case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break;
case 'q': lmKind = LengthModifier::AsQuad; ++I; break;
case 'a':
- if (IsScanf && !LO.C99 && !LO.CPlusPlus0x) {
+ if (IsScanf && !LO.C99 && !LO.CPlusPlus11) {
// For scanf in C90, look at the next character to see if this should
// be parsed as the GNU extension 'a' length modifier. If not, this
// will be parsed as a conversion specifier.
@@ -527,13 +527,13 @@ const char *ConversionSpecifier::toString() const {
return NULL;
}
-llvm::Optional<ConversionSpecifier>
+Optional<ConversionSpecifier>
ConversionSpecifier::getStandardSpecifier() const {
ConversionSpecifier::Kind NewKind;
switch (getKind()) {
default:
- return llvm::Optional<ConversionSpecifier>();
+ return None;
case DArg:
NewKind = dArg;
break;
@@ -756,8 +756,7 @@ bool FormatSpecifier::hasStandardLengthConversionCombination() const {
return true;
}
-llvm::Optional<LengthModifier>
-FormatSpecifier::getCorrectedLengthModifier() const {
+Optional<LengthModifier> FormatSpecifier::getCorrectedLengthModifier() const {
if (CS.isAnyIntArg() || CS.getKind() == ConversionSpecifier::nArg) {
if (LM.getKind() == LengthModifier::AsLongDouble ||
LM.getKind() == LengthModifier::AsQuad) {
@@ -767,7 +766,7 @@ FormatSpecifier::getCorrectedLengthModifier() const {
}
}
- return llvm::Optional<LengthModifier>();
+ return None;
}
bool FormatSpecifier::namedTypeToLengthModifier(QualType QT,
diff --git a/lib/Analysis/FormatStringParsing.h b/lib/Analysis/FormatStringParsing.h
index f483ec6..6b25123 100644
--- a/lib/Analysis/FormatStringParsing.h
+++ b/lib/Analysis/FormatStringParsing.h
@@ -1,9 +1,9 @@
#ifndef LLVM_CLANG_FORMAT_PARSING_H
#define LLVM_CLANG_FORMAT_PARSING_H
-#include "clang/Analysis/Analyses/FormatString.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Type.h"
+#include "clang/Analysis/Analyses/FormatString.h"
#include "llvm/Support/raw_ostream.h"
namespace clang {
diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp
index 38f8199..b43892a 100644
--- a/lib/Analysis/LiveVariables.cpp
+++ b/lib/Analysis/LiveVariables.cpp
@@ -1,15 +1,25 @@
-#include "clang/Analysis/Analyses/LiveVariables.h"
-#include "clang/Analysis/Analyses/PostOrderCFGView.h"
+//=- LiveVariables.cpp - Live Variable Analysis for Source CFGs ----------*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements Live Variables analysis for source-level CFGs.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/AST/Stmt.h"
-#include "clang/Analysis/CFG.h"
-#include "clang/Analysis/AnalysisContext.h"
#include "clang/AST/StmtVisitor.h"
-
-#include "llvm/ADT/PostOrderIterator.h"
+#include "clang/Analysis/Analyses/PostOrderCFGView.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/CFG.h"
#include "llvm/ADT/DenseMap.h"
-
-#include <deque>
+#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <vector>
@@ -464,15 +474,16 @@ LiveVariablesImpl::runOnBlock(const CFGBlock *block,
ei = block->rend(); it != ei; ++it) {
const CFGElement &elem = *it;
- if (const CFGAutomaticObjDtor *Dtor = dyn_cast<CFGAutomaticObjDtor>(&elem)){
+ if (Optional<CFGAutomaticObjDtor> Dtor =
+ elem.getAs<CFGAutomaticObjDtor>()) {
val.liveDecls = DSetFact.add(val.liveDecls, Dtor->getVarDecl());
continue;
}
- if (!isa<CFGStmt>(elem))
+ if (!elem.getAs<CFGStmt>())
continue;
- const Stmt *S = cast<CFGStmt>(elem).getStmt();
+ const Stmt *S = elem.castAs<CFGStmt>().getStmt();
TF.Visit(const_cast<Stmt*>(S));
stmtsToLiveness[S] = val;
}
@@ -524,8 +535,9 @@ LiveVariables::computeLiveness(AnalysisDeclContext &AC,
if (killAtAssign)
for (CFGBlock::const_iterator bi = block->begin(), be = block->end();
bi != be; ++bi) {
- if (const CFGStmt *cs = bi->getAs<CFGStmt>()) {
- if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(cs->getStmt())) {
+ if (Optional<CFGStmt> cs = bi->getAs<CFGStmt>()) {
+ if (const BinaryOperator *BO =
+ dyn_cast<BinaryOperator>(cs->getStmt())) {
if (BO->getOpcode() == BO_Assign) {
if (const DeclRefExpr *DR =
dyn_cast<DeclRefExpr>(BO->getLHS()->IgnoreParens())) {
diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp
index 2fa5a88..8f151b9 100644
--- a/lib/Analysis/PrintfFormatString.cpp
+++ b/lib/Analysis/PrintfFormatString.cpp
@@ -13,8 +13,8 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/Analyses/FormatString.h"
-#include "clang/Basic/TargetInfo.h"
#include "FormatStringParsing.h"
+#include "clang/Basic/TargetInfo.h"
using clang::analyze_format_string::ArgType;
using clang::analyze_format_string::FormatStringHandler;
@@ -359,17 +359,19 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,
case ConversionSpecifier::sArg:
if (LM.getKind() == LengthModifier::AsWideChar) {
if (IsObjCLiteral)
- return Ctx.getPointerType(Ctx.UnsignedShortTy.withConst());
+ return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
+ "const unichar *");
return ArgType(ArgType::WCStrTy, "wchar_t *");
}
return ArgType::CStrTy;
case ConversionSpecifier::SArg:
if (IsObjCLiteral)
- return Ctx.getPointerType(Ctx.UnsignedShortTy.withConst());
+ return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),
+ "const unichar *");
return ArgType(ArgType::WCStrTy, "wchar_t *");
case ConversionSpecifier::CArg:
if (IsObjCLiteral)
- return Ctx.UnsignedShortTy;
+ return ArgType(Ctx.UnsignedShortTy, "unichar");
return ArgType(Ctx.WCharTy, "wchar_t");
case ConversionSpecifier::pArg:
return ArgType::CPointerTy;
@@ -494,11 +496,29 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
}
// Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
- if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus0x))
+ if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
namedTypeToLengthModifier(QT, LM);
- // If fixing the length modifier was enough, we are done.
+ // If fixing the length modifier was enough, we might be done.
if (hasValidLengthModifier(Ctx.getTargetInfo())) {
+ // If we're going to offer a fix anyway, make sure the sign matches.
+ switch (CS.getKind()) {
+ case ConversionSpecifier::uArg:
+ case ConversionSpecifier::UArg:
+ if (QT->isSignedIntegerType())
+ CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg);
+ break;
+ case ConversionSpecifier::dArg:
+ case ConversionSpecifier::DArg:
+ case ConversionSpecifier::iArg:
+ if (QT->isUnsignedIntegerType() && !HasPlusPrefix)
+ CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg);
+ break;
+ default:
+ // Other specifiers do not have signed/unsigned variants.
+ break;
+ }
+
const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);
if (ATR.isValid() && ATR.matchesType(Ctx, QT))
return true;
@@ -506,7 +526,7 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
// Set conversion specifier and disable any flags which do not apply to it.
// Let typedefs to char fall through to int, as %c is silly for uint8_t.
- if (isa<TypedefType>(QT) && QT->isAnyCharacterType()) {
+ if (!isa<TypedefType>(QT) && QT->isCharType()) {
CS.setKind(ConversionSpecifier::cArg);
LM.setKind(LengthModifier::None);
Precision.setHowSpecified(OptionalAmount::NotSpecified);
diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp
index 11f2ebe..a90aebb 100644
--- a/lib/Analysis/ReachableCode.cpp
+++ b/lib/Analysis/ReachableCode.cpp
@@ -12,16 +12,16 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/ADT/BitVector.h"
-#include "llvm/ADT/SmallVector.h"
+#include "clang/Analysis/Analyses/ReachableCode.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/StmtCXX.h"
-#include "clang/Analysis/Analyses/ReachableCode.h"
-#include "clang/Analysis/CFG.h"
#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/CFG.h"
#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/SmallVector.h"
using namespace clang;
@@ -29,9 +29,9 @@ namespace {
class DeadCodeScan {
llvm::BitVector Visited;
llvm::BitVector &Reachable;
- llvm::SmallVector<const CFGBlock *, 10> WorkList;
+ SmallVector<const CFGBlock *, 10> WorkList;
- typedef llvm::SmallVector<std::pair<const CFGBlock *, const Stmt *>, 12>
+ typedef SmallVector<std::pair<const CFGBlock *, const Stmt *>, 12>
DeferredLocsTy;
DeferredLocsTy DeferredLocs;
@@ -95,7 +95,7 @@ static bool isValidDeadStmt(const Stmt *S) {
const Stmt *DeadCodeScan::findDeadCode(const clang::CFGBlock *Block) {
for (CFGBlock::const_iterator I = Block->begin(), E = Block->end(); I!=E; ++I)
- if (const CFGStmt *CS = I->getAs<CFGStmt>()) {
+ if (Optional<CFGStmt> CS = I->getAs<CFGStmt>()) {
const Stmt *S = CS->getStmt();
if (isValidDeadStmt(S))
return S;
diff --git a/lib/Analysis/ScanfFormatString.cpp b/lib/Analysis/ScanfFormatString.cpp
index 574e56a..2dbc9e4 100644
--- a/lib/Analysis/ScanfFormatString.cpp
+++ b/lib/Analysis/ScanfFormatString.cpp
@@ -13,8 +13,8 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/Analyses/FormatString.h"
-#include "clang/Basic/TargetInfo.h"
#include "FormatStringParsing.h"
+#include "clang/Basic/TargetInfo.h"
using clang::analyze_format_string::ArgType;
using clang::analyze_format_string::FormatStringHandler;
@@ -445,7 +445,7 @@ bool ScanfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
}
// Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
- if (isa<TypedefType>(PT) && (LangOpt.C99 || LangOpt.CPlusPlus0x))
+ if (isa<TypedefType>(PT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
namedTypeToLengthModifier(PT, LM);
// If fixing the length modifier was enough, we are done.
diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp
index c7f1f62..4fe342d 100644
--- a/lib/Analysis/ThreadSafety.cpp
+++ b/lib/Analysis/ThreadSafety.cpp
@@ -16,17 +16,18 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/Analyses/ThreadSafety.h"
-#include "clang/Analysis/Analyses/PostOrderCFGView.h"
-#include "clang/Analysis/AnalysisContext.h"
-#include "clang/Analysis/CFG.h"
-#include "clang/Analysis/CFGStmtMap.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtVisitor.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/SourceLocation.h"
+#include "clang/Analysis/Analyses/PostOrderCFGView.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/CFGStmtMap.h"
#include "clang/Basic/OperatorKinds.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableMap.h"
@@ -164,15 +165,16 @@ private:
/// should be evaluated; multiple calling contexts can be chained together
/// by the lock_returned attribute.
struct CallingContext {
- const NamedDecl* AttrDecl; // The decl to which the attribute is attached.
- Expr* SelfArg; // Implicit object argument -- e.g. 'this'
- bool SelfArrow; // is Self referred to with -> or .?
- unsigned NumArgs; // Number of funArgs
- Expr** FunArgs; // Function arguments
- CallingContext* PrevCtx; // The previous context; or 0 if none.
-
- CallingContext(const NamedDecl *D = 0, Expr *S = 0,
- unsigned N = 0, Expr **A = 0, CallingContext *P = 0)
+ const NamedDecl* AttrDecl; // The decl to which the attribute is attached.
+ const Expr* SelfArg; // Implicit object argument -- e.g. 'this'
+ bool SelfArrow; // is Self referred to with -> or .?
+ unsigned NumArgs; // Number of funArgs
+ const Expr* const* FunArgs; // Function arguments
+ CallingContext* PrevCtx; // The previous context; or 0 if none.
+
+ CallingContext(const NamedDecl *D = 0, const Expr *S = 0,
+ unsigned N = 0, const Expr* const *A = 0,
+ CallingContext *P = 0)
: AttrDecl(D), SelfArg(S), SelfArrow(false),
NumArgs(N), FunArgs(A), PrevCtx(P)
{ }
@@ -272,15 +274,16 @@ private:
/// NDeref returns the number of Derefence and AddressOf operations
/// preceeding the Expr; this is used to decide whether to pretty-print
/// SExprs with . or ->.
- unsigned buildSExpr(Expr *Exp, CallingContext* CallCtx, int* NDeref = 0) {
+ unsigned buildSExpr(const Expr *Exp, CallingContext* CallCtx,
+ int* NDeref = 0) {
if (!Exp)
return 0;
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp)) {
- NamedDecl *ND = cast<NamedDecl>(DRE->getDecl()->getCanonicalDecl());
- ParmVarDecl *PV = dyn_cast_or_null<ParmVarDecl>(ND);
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp)) {
+ const NamedDecl *ND = cast<NamedDecl>(DRE->getDecl()->getCanonicalDecl());
+ const ParmVarDecl *PV = dyn_cast_or_null<ParmVarDecl>(ND);
if (PV) {
- FunctionDecl *FD =
+ const FunctionDecl *FD =
cast<FunctionDecl>(PV->getDeclContext())->getCanonicalDecl();
unsigned i = PV->getFunctionScopeIndex();
@@ -309,18 +312,18 @@ private:
makeThis();
return 1;
}
- } else if (MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) {
- NamedDecl *ND = ME->getMemberDecl();
+ } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) {
+ const NamedDecl *ND = ME->getMemberDecl();
int ImplicitDeref = ME->isArrow() ? 1 : 0;
unsigned Root = makeDot(ND, false);
unsigned Sz = buildSExpr(ME->getBase(), CallCtx, &ImplicitDeref);
NodeVec[Root].setArrow(ImplicitDeref > 0);
NodeVec[Root].setSize(Sz + 1);
return Sz + 1;
- } else if (CXXMemberCallExpr *CMCE = dyn_cast<CXXMemberCallExpr>(Exp)) {
+ } else if (const CXXMemberCallExpr *CMCE = dyn_cast<CXXMemberCallExpr>(Exp)) {
// When calling a function with a lock_returned attribute, replace
// the function call with the expression in lock_returned.
- CXXMethodDecl* MD =
+ const CXXMethodDecl* MD =
cast<CXXMethodDecl>(CMCE->getMethodDecl()->getMostRecentDecl());
if (LockReturnedAttr* At = MD->getAttr<LockReturnedAttr>()) {
CallingContext LRCallCtx(CMCE->getMethodDecl());
@@ -343,14 +346,14 @@ private:
unsigned NumCallArgs = CMCE->getNumArgs();
unsigned Root = makeMCall(NumCallArgs, CMCE->getMethodDecl());
unsigned Sz = buildSExpr(CMCE->getImplicitObjectArgument(), CallCtx);
- Expr** CallArgs = CMCE->getArgs();
+ const Expr* const* CallArgs = CMCE->getArgs();
for (unsigned i = 0; i < NumCallArgs; ++i) {
Sz += buildSExpr(CallArgs[i], CallCtx);
}
NodeVec[Root].setSize(Sz + 1);
return Sz + 1;
- } else if (CallExpr *CE = dyn_cast<CallExpr>(Exp)) {
- FunctionDecl* FD =
+ } else if (const CallExpr *CE = dyn_cast<CallExpr>(Exp)) {
+ const FunctionDecl* FD =
cast<FunctionDecl>(CE->getDirectCallee()->getMostRecentDecl());
if (LockReturnedAttr* At = FD->getAttr<LockReturnedAttr>()) {
CallingContext LRCallCtx(CE->getDirectCallee());
@@ -361,7 +364,7 @@ private:
}
// Treat smart pointers and iterators as pointers;
// ignore the * and -> operators.
- if (CXXOperatorCallExpr *OE = dyn_cast<CXXOperatorCallExpr>(CE)) {
+ if (const CXXOperatorCallExpr *OE = dyn_cast<CXXOperatorCallExpr>(CE)) {
OverloadedOperatorKind k = OE->getOperator();
if (k == OO_Star) {
if (NDeref) ++(*NDeref);
@@ -374,19 +377,19 @@ private:
unsigned NumCallArgs = CE->getNumArgs();
unsigned Root = makeCall(NumCallArgs, 0);
unsigned Sz = buildSExpr(CE->getCallee(), CallCtx);
- Expr** CallArgs = CE->getArgs();
+ const Expr* const* CallArgs = CE->getArgs();
for (unsigned i = 0; i < NumCallArgs; ++i) {
Sz += buildSExpr(CallArgs[i], CallCtx);
}
NodeVec[Root].setSize(Sz+1);
return Sz+1;
- } else if (BinaryOperator *BOE = dyn_cast<BinaryOperator>(Exp)) {
+ } else if (const BinaryOperator *BOE = dyn_cast<BinaryOperator>(Exp)) {
unsigned Root = makeBinary();
unsigned Sz = buildSExpr(BOE->getLHS(), CallCtx);
Sz += buildSExpr(BOE->getRHS(), CallCtx);
NodeVec[Root].setSize(Sz);
return Sz;
- } else if (UnaryOperator *UOE = dyn_cast<UnaryOperator>(Exp)) {
+ } else if (const UnaryOperator *UOE = dyn_cast<UnaryOperator>(Exp)) {
// Ignore & and * operators -- they're no-ops.
// However, we try to figure out whether the expression is a pointer,
// so we can use . and -> appropriately in error messages.
@@ -412,13 +415,14 @@ private:
unsigned Sz = buildSExpr(UOE->getSubExpr(), CallCtx);
NodeVec[Root].setSize(Sz);
return Sz;
- } else if (ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(Exp)) {
+ } else if (const ArraySubscriptExpr *ASE =
+ dyn_cast<ArraySubscriptExpr>(Exp)) {
unsigned Root = makeIndex();
unsigned Sz = buildSExpr(ASE->getBase(), CallCtx);
Sz += buildSExpr(ASE->getIdx(), CallCtx);
NodeVec[Root].setSize(Sz);
return Sz;
- } else if (AbstractConditionalOperator *CE =
+ } else if (const AbstractConditionalOperator *CE =
dyn_cast<AbstractConditionalOperator>(Exp)) {
unsigned Root = makeUnknown(3);
unsigned Sz = buildSExpr(CE->getCond(), CallCtx);
@@ -426,20 +430,20 @@ private:
Sz += buildSExpr(CE->getFalseExpr(), CallCtx);
NodeVec[Root].setSize(Sz);
return Sz;
- } else if (ChooseExpr *CE = dyn_cast<ChooseExpr>(Exp)) {
+ } else if (const ChooseExpr *CE = dyn_cast<ChooseExpr>(Exp)) {
unsigned Root = makeUnknown(3);
unsigned Sz = buildSExpr(CE->getCond(), CallCtx);
Sz += buildSExpr(CE->getLHS(), CallCtx);
Sz += buildSExpr(CE->getRHS(), CallCtx);
NodeVec[Root].setSize(Sz);
return Sz;
- } else if (CastExpr *CE = dyn_cast<CastExpr>(Exp)) {
+ } else if (const CastExpr *CE = dyn_cast<CastExpr>(Exp)) {
return buildSExpr(CE->getSubExpr(), CallCtx, NDeref);
- } else if (ParenExpr *PE = dyn_cast<ParenExpr>(Exp)) {
+ } else if (const ParenExpr *PE = dyn_cast<ParenExpr>(Exp)) {
return buildSExpr(PE->getSubExpr(), CallCtx, NDeref);
- } else if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Exp)) {
+ } else if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Exp)) {
return buildSExpr(EWC->getSubExpr(), CallCtx, NDeref);
- } else if (CXXBindTemporaryExpr *E = dyn_cast<CXXBindTemporaryExpr>(Exp)) {
+ } else if (const CXXBindTemporaryExpr *E = dyn_cast<CXXBindTemporaryExpr>(Exp)) {
return buildSExpr(E->getSubExpr(), CallCtx, NDeref);
} else if (isa<CharacterLiteral>(Exp) ||
isa<CXXNullPtrLiteralExpr>(Exp) ||
@@ -463,12 +467,12 @@ private:
/// \param DeclExp An expression involving the Decl on which the attribute
/// occurs.
/// \param D The declaration to which the lock/unlock attribute is attached.
- void buildSExprFromExpr(Expr *MutexExp, Expr *DeclExp, const NamedDecl *D,
- VarDecl *SelfDecl = 0) {
+ void buildSExprFromExpr(const Expr *MutexExp, const Expr *DeclExp,
+ const NamedDecl *D, VarDecl *SelfDecl = 0) {
CallingContext CallCtx(D);
if (MutexExp) {
- if (StringLiteral* SLit = dyn_cast<StringLiteral>(MutexExp)) {
+ if (const StringLiteral* SLit = dyn_cast<StringLiteral>(MutexExp)) {
if (SLit->getString() == StringRef("*"))
// The "*" expr is a universal lock, which essentially turns off
// checks until it is removed from the lockset.
@@ -488,18 +492,21 @@ private:
// Examine DeclExp to find SelfArg and FunArgs, which are used to substitute
// for formal parameters when we call buildMutexID later.
- if (MemberExpr *ME = dyn_cast<MemberExpr>(DeclExp)) {
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(DeclExp)) {
CallCtx.SelfArg = ME->getBase();
CallCtx.SelfArrow = ME->isArrow();
- } else if (CXXMemberCallExpr *CE = dyn_cast<CXXMemberCallExpr>(DeclExp)) {
+ } else if (const CXXMemberCallExpr *CE =
+ dyn_cast<CXXMemberCallExpr>(DeclExp)) {
CallCtx.SelfArg = CE->getImplicitObjectArgument();
CallCtx.SelfArrow = dyn_cast<MemberExpr>(CE->getCallee())->isArrow();
CallCtx.NumArgs = CE->getNumArgs();
CallCtx.FunArgs = CE->getArgs();
- } else if (CallExpr *CE = dyn_cast<CallExpr>(DeclExp)) {
+ } else if (const CallExpr *CE =
+ dyn_cast<CallExpr>(DeclExp)) {
CallCtx.NumArgs = CE->getNumArgs();
CallCtx.FunArgs = CE->getArgs();
- } else if (CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(DeclExp)) {
+ } else if (const CXXConstructExpr *CE =
+ dyn_cast<CXXConstructExpr>(DeclExp)) {
CallCtx.SelfArg = 0; // Will be set below
CallCtx.NumArgs = CE->getNumArgs();
CallCtx.FunArgs = CE->getArgs();
@@ -543,7 +550,7 @@ public:
/// occurs.
/// \param D The declaration to which the lock/unlock attribute is attached.
/// Caller must check isValid() after construction.
- SExpr(Expr* MutexExp, Expr *DeclExp, const NamedDecl* D,
+ SExpr(const Expr* MutexExp, const Expr *DeclExp, const NamedDecl* D,
VarDecl *SelfDecl=0) {
buildSExprFromExpr(MutexExp, DeclExp, D, SelfDecl);
}
@@ -566,8 +573,9 @@ public:
}
/// Issue a warning about an invalid lock expression
- static void warnInvalidLock(ThreadSafetyHandler &Handler, Expr* MutexExp,
- Expr *DeclExp, const NamedDecl* D) {
+ static void warnInvalidLock(ThreadSafetyHandler &Handler,
+ const Expr *MutexExp,
+ const Expr *DeclExp, const NamedDecl* D) {
SourceLocation Loc;
if (DeclExp)
Loc = DeclExp->getExprLoc();
@@ -776,7 +784,7 @@ struct LockData {
/// \brief A FactEntry stores a single fact that is known at a particular point
/// in the program execution. Currently, this is information regarding a lock
-/// that is held at that point.
+/// that is held at that point.
struct FactEntry {
SExpr MutID;
LockData LDat;
@@ -789,7 +797,7 @@ struct FactEntry {
typedef unsigned short FactID;
-/// \brief FactManager manages the memory for all facts that are created during
+/// \brief FactManager manages the memory for all facts that are created during
/// the analysis of a single routine.
class FactManager {
private:
@@ -807,9 +815,9 @@ public:
/// \brief A FactSet is the set of facts that are known to be true at a
-/// particular program point. FactSets must be small, because they are
+/// particular program point. FactSets must be small, because they are
/// frequently copied, and are thus implemented as a set of indices into a
-/// table maintained by a FactManager. A typical FactSet only holds 1 or 2
+/// table maintained by a FactManager. A typical FactSet only holds 1 or 2
/// locks, so we can get away with doing a linear search for lookup. Note
/// that a hashtable or map is inappropriate in this case, because lookups
/// may involve partial pattern matches, rather than exact matches.
@@ -1342,8 +1350,8 @@ void LocalVariableMap::traverseCFG(CFG *CFGraph,
BE = CurrBlock->end(); BI != BE; ++BI) {
switch (BI->getKind()) {
case CFGElement::Statement: {
- const CFGStmt *CS = cast<CFGStmt>(&*BI);
- VMapBuilder.Visit(const_cast<Stmt*>(CS->getStmt()));
+ CFGStmt CS = BI->castAs<CFGStmt>();
+ VMapBuilder.Visit(const_cast<Stmt*>(CS.getStmt()));
break;
}
default:
@@ -1389,7 +1397,7 @@ static void findBlockLocations(CFG *CFGraph,
for (CFGBlock::const_reverse_iterator BI = CurrBlock->rbegin(),
BE = CurrBlock->rend(); BI != BE; ++BI) {
// FIXME: Handle other CFGElement kinds.
- if (const CFGStmt *CS = dyn_cast<CFGStmt>(&*BI)) {
+ if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>()) {
CurrBlockInfo->ExitLoc = CS->getStmt()->getLocStart();
break;
}
@@ -1402,7 +1410,7 @@ static void findBlockLocations(CFG *CFGraph,
for (CFGBlock::const_iterator BI = CurrBlock->begin(),
BE = CurrBlock->end(); BI != BE; ++BI) {
// FIXME: Handle other CFGElement kinds.
- if (const CFGStmt *CS = dyn_cast<CFGStmt>(&*BI)) {
+ if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>()) {
CurrBlockInfo->EntryLoc = CS->getStmt()->getLocStart();
break;
}
@@ -1733,14 +1741,15 @@ class BuildLockset : public StmtVisitor<BuildLockset> {
unsigned CtxIndex;
// Helper functions
- const ValueDecl *getValueDecl(Expr *Exp);
+ const ValueDecl *getValueDecl(const Expr *Exp);
- void warnIfMutexNotHeld(const NamedDecl *D, Expr *Exp, AccessKind AK,
+ void warnIfMutexNotHeld(const NamedDecl *D, const Expr *Exp, AccessKind AK,
Expr *MutexExp, ProtectedOperationKind POK);
- void warnIfMutexHeld(const NamedDecl *D, Expr *Exp, Expr *MutexExp);
+ void warnIfMutexHeld(const NamedDecl *D, const Expr *Exp, Expr *MutexExp);
+
+ void checkAccess(const Expr *Exp, AccessKind AK);
+ void checkPtAccess(const Expr *Exp, AccessKind AK);
- void checkAccess(Expr *Exp, AccessKind AK);
- void checkDereference(Expr *Exp, AccessKind AK);
void handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD = 0);
public:
@@ -1762,7 +1771,10 @@ public:
/// \brief Gets the value decl pointer from DeclRefExprs or MemberExprs
-const ValueDecl *BuildLockset::getValueDecl(Expr *Exp) {
+const ValueDecl *BuildLockset::getValueDecl(const Expr *Exp) {
+ if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(Exp))
+ return getValueDecl(CE->getSubExpr());
+
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Exp))
return DR->getDecl();
@@ -1774,7 +1786,7 @@ const ValueDecl *BuildLockset::getValueDecl(Expr *Exp) {
/// \brief Warn if the LSet does not contain a lock sufficient to protect access
/// of at least the passed in AccessKind.
-void BuildLockset::warnIfMutexNotHeld(const NamedDecl *D, Expr *Exp,
+void BuildLockset::warnIfMutexNotHeld(const NamedDecl *D, const Expr *Exp,
AccessKind AK, Expr *MutexExp,
ProtectedOperationKind POK) {
LockKind LK = getLockKindFromAccessKind(AK);
@@ -1813,7 +1825,7 @@ void BuildLockset::warnIfMutexNotHeld(const NamedDecl *D, Expr *Exp,
}
/// \brief Warn if the LSet contains the given lock.
-void BuildLockset::warnIfMutexHeld(const NamedDecl *D, Expr* Exp,
+void BuildLockset::warnIfMutexHeld(const NamedDecl *D, const Expr* Exp,
Expr *MutexExp) {
SExpr Mutex(MutexExp, Exp, D);
if (!Mutex.isValid()) {
@@ -1831,51 +1843,61 @@ void BuildLockset::warnIfMutexHeld(const NamedDecl *D, Expr* Exp,
}
-/// \brief This method identifies variable dereferences and checks pt_guarded_by
-/// and pt_guarded_var annotations. Note that we only check these annotations
-/// at the time a pointer is dereferenced.
-/// FIXME: We need to check for other types of pointer dereferences
-/// (e.g. [], ->) and deal with them here.
-/// \param Exp An expression that has been read or written.
-void BuildLockset::checkDereference(Expr *Exp, AccessKind AK) {
- UnaryOperator *UO = dyn_cast<UnaryOperator>(Exp);
- if (!UO || UO->getOpcode() != clang::UO_Deref)
+/// \brief Checks guarded_by and pt_guarded_by attributes.
+/// Whenever we identify an access (read or write) to a DeclRefExpr that is
+/// marked with guarded_by, we must ensure the appropriate mutexes are held.
+/// Similarly, we check if the access is to an expression that dereferences
+/// a pointer marked with pt_guarded_by.
+void BuildLockset::checkAccess(const Expr *Exp, AccessKind AK) {
+ Exp = Exp->IgnoreParenCasts();
+
+ if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Exp)) {
+ // For dereferences
+ if (UO->getOpcode() == clang::UO_Deref)
+ checkPtAccess(UO->getSubExpr(), AK);
return;
- Exp = UO->getSubExpr()->IgnoreParenCasts();
+ }
+
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) {
+ if (ME->isArrow())
+ checkPtAccess(ME->getBase(), AK);
+ else
+ checkAccess(ME->getBase(), AK);
+ }
const ValueDecl *D = getValueDecl(Exp);
- if(!D || !D->hasAttrs())
+ if (!D || !D->hasAttrs())
return;
- if (D->getAttr<PtGuardedVarAttr>() && FSet.isEmpty())
- Analyzer->Handler.handleNoMutexHeld(D, POK_VarDereference, AK,
+ if (D->getAttr<GuardedVarAttr>() && FSet.isEmpty())
+ Analyzer->Handler.handleNoMutexHeld(D, POK_VarAccess, AK,
Exp->getExprLoc());
const AttrVec &ArgAttrs = D->getAttrs();
- for(unsigned i = 0, Size = ArgAttrs.size(); i < Size; ++i)
- if (PtGuardedByAttr *PGBAttr = dyn_cast<PtGuardedByAttr>(ArgAttrs[i]))
- warnIfMutexNotHeld(D, Exp, AK, PGBAttr->getArg(), POK_VarDereference);
+ for (unsigned i = 0, Size = ArgAttrs.size(); i < Size; ++i)
+ if (GuardedByAttr *GBAttr = dyn_cast<GuardedByAttr>(ArgAttrs[i]))
+ warnIfMutexNotHeld(D, Exp, AK, GBAttr->getArg(), POK_VarAccess);
}
-/// \brief Checks guarded_by and guarded_var attributes.
-/// Whenever we identify an access (read or write) of a DeclRefExpr or
-/// MemberExpr, we need to check whether there are any guarded_by or
-/// guarded_var attributes, and make sure we hold the appropriate mutexes.
-void BuildLockset::checkAccess(Expr *Exp, AccessKind AK) {
+/// \brief Checks pt_guarded_by and pt_guarded_var attributes.
+void BuildLockset::checkPtAccess(const Expr *Exp, AccessKind AK) {
+ Exp = Exp->IgnoreParenCasts();
+
const ValueDecl *D = getValueDecl(Exp);
- if(!D || !D->hasAttrs())
+ if (!D || !D->hasAttrs())
return;
- if (D->getAttr<GuardedVarAttr>() && FSet.isEmpty())
- Analyzer->Handler.handleNoMutexHeld(D, POK_VarAccess, AK,
+ if (D->getAttr<PtGuardedVarAttr>() && FSet.isEmpty())
+ Analyzer->Handler.handleNoMutexHeld(D, POK_VarDereference, AK,
Exp->getExprLoc());
const AttrVec &ArgAttrs = D->getAttrs();
- for(unsigned i = 0, Size = ArgAttrs.size(); i < Size; ++i)
- if (GuardedByAttr *GBAttr = dyn_cast<GuardedByAttr>(ArgAttrs[i]))
- warnIfMutexNotHeld(D, Exp, AK, GBAttr->getArg(), POK_VarAccess);
+ for (unsigned i = 0, Size = ArgAttrs.size(); i < Size; ++i)
+ if (PtGuardedByAttr *GBAttr = dyn_cast<PtGuardedByAttr>(ArgAttrs[i]))
+ warnIfMutexNotHeld(D, Exp, AK, GBAttr->getArg(), POK_VarDereference);
}
+
/// \brief Process a function call, method call, constructor call,
/// or destructor call. This involves looking at the attributes on the
/// corresponding function/method/constructor/destructor, issuing warnings,
@@ -2009,9 +2031,7 @@ void BuildLockset::VisitUnaryOperator(UnaryOperator *UO) {
case clang::UO_PostInc:
case clang::UO_PreDec:
case clang::UO_PreInc: {
- Expr *SubExp = UO->getSubExpr()->IgnoreParenCasts();
- checkAccess(SubExp, AK_Written);
- checkDereference(SubExp, AK_Written);
+ checkAccess(UO->getSubExpr(), AK_Written);
break;
}
default:
@@ -2029,9 +2049,7 @@ void BuildLockset::VisitBinaryOperator(BinaryOperator *BO) {
// adjust the context
LVarCtx = Analyzer->LocalVarMap.getNextContext(CtxIndex, BO, LVarCtx);
- Expr *LHSExp = BO->getLHS()->IgnoreParenCasts();
- checkAccess(LHSExp, AK_Written);
- checkDereference(LHSExp, AK_Written);
+ checkAccess(BO->getLHS(), AK_Written);
}
/// Whenever we do an LValue to Rvalue cast, we are reading a variable and
@@ -2040,13 +2058,46 @@ void BuildLockset::VisitBinaryOperator(BinaryOperator *BO) {
void BuildLockset::VisitCastExpr(CastExpr *CE) {
if (CE->getCastKind() != CK_LValueToRValue)
return;
- Expr *SubExp = CE->getSubExpr()->IgnoreParenCasts();
- checkAccess(SubExp, AK_Read);
- checkDereference(SubExp, AK_Read);
+ checkAccess(CE->getSubExpr(), AK_Read);
}
void BuildLockset::VisitCallExpr(CallExpr *Exp) {
+ if (CXXMemberCallExpr *CE = dyn_cast<CXXMemberCallExpr>(Exp)) {
+ MemberExpr *ME = dyn_cast<MemberExpr>(CE->getCallee());
+ // ME can be null when calling a method pointer
+ CXXMethodDecl *MD = CE->getMethodDecl();
+
+ if (ME && MD) {
+ if (ME->isArrow()) {
+ if (MD->isConst()) {
+ checkPtAccess(CE->getImplicitObjectArgument(), AK_Read);
+ } else { // FIXME -- should be AK_Written
+ checkPtAccess(CE->getImplicitObjectArgument(), AK_Read);
+ }
+ } else {
+ if (MD->isConst())
+ checkAccess(CE->getImplicitObjectArgument(), AK_Read);
+ else // FIXME -- should be AK_Written
+ checkAccess(CE->getImplicitObjectArgument(), AK_Read);
+ }
+ }
+ } else if (CXXOperatorCallExpr *OE = dyn_cast<CXXOperatorCallExpr>(Exp)) {
+ switch (OE->getOperator()) {
+ case OO_Equal: {
+ const Expr *Target = OE->getArg(0);
+ const Expr *Source = OE->getArg(1);
+ checkAccess(Target, AK_Written);
+ checkAccess(Source, AK_Read);
+ break;
+ }
+ default: {
+ const Expr *Source = OE->getArg(0);
+ checkAccess(Source, AK_Read);
+ break;
+ }
+ }
+ }
NamedDecl *D = dyn_cast_or_null<NamedDecl>(Exp->getCalleeDecl());
if(!D || !D->hasAttrs())
return;
@@ -2054,6 +2105,11 @@ void BuildLockset::VisitCallExpr(CallExpr *Exp) {
}
void BuildLockset::VisitCXXConstructExpr(CXXConstructExpr *Exp) {
+ const CXXConstructorDecl *D = Exp->getConstructor();
+ if (D && D->isCopyConstructor()) {
+ const Expr* Source = Exp->getArg(0);
+ checkAccess(Source, AK_Read);
+ }
// FIXME -- only handles constructors in DeclStmt below.
}
@@ -2164,6 +2220,21 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &FSet1,
}
+// Return true if block B never continues to its successors.
+inline bool neverReturns(const CFGBlock* B) {
+ if (B->hasNoReturnElement())
+ return true;
+ if (B->empty())
+ return false;
+
+ CFGElement Last = B->back();
+ if (Optional<CFGStmt> S = Last.getAs<CFGStmt>()) {
+ if (isa<CXXThrowExpr>(S->getStmt()))
+ return true;
+ }
+ return false;
+}
+
/// \brief Check a function's CFG for thread-safety violations.
///
@@ -2281,7 +2352,7 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
// union because the real error is probably that we forgot to unlock M on
// all code paths.
bool LocksetInitialized = false;
- llvm::SmallVector<CFGBlock*, 8> SpecialBlocks;
+ SmallVector<CFGBlock *, 8> SpecialBlocks;
for (CFGBlock::const_pred_iterator PI = CurrBlock->pred_begin(),
PE = CurrBlock->pred_end(); PI != PE; ++PI) {
@@ -2293,7 +2364,7 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID];
// Ignore edges from blocks that can't return.
- if ((*PI)->hasNoReturnElement() || !PrevBlockInfo->Reachable)
+ if (neverReturns(*PI) || !PrevBlockInfo->Reachable)
continue;
// Okay, we can reach this block from the entry.
@@ -2310,7 +2381,6 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
}
}
-
FactSet PrevLockset;
getEdgeLockset(PrevLockset, PrevBlockInfo->ExitSet, *PI, CurrBlock);
@@ -2368,22 +2438,22 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
BE = CurrBlock->end(); BI != BE; ++BI) {
switch (BI->getKind()) {
case CFGElement::Statement: {
- const CFGStmt *CS = cast<CFGStmt>(&*BI);
- LocksetBuilder.Visit(const_cast<Stmt*>(CS->getStmt()));
+ CFGStmt CS = BI->castAs<CFGStmt>();
+ LocksetBuilder.Visit(const_cast<Stmt*>(CS.getStmt()));
break;
}
// Ignore BaseDtor, MemberDtor, and TemporaryDtor for now.
case CFGElement::AutomaticObjectDtor: {
- const CFGAutomaticObjDtor *AD = cast<CFGAutomaticObjDtor>(&*BI);
- CXXDestructorDecl *DD = const_cast<CXXDestructorDecl*>(
- AD->getDestructorDecl(AC.getASTContext()));
+ CFGAutomaticObjDtor AD = BI->castAs<CFGAutomaticObjDtor>();
+ CXXDestructorDecl *DD = const_cast<CXXDestructorDecl *>(
+ AD.getDestructorDecl(AC.getASTContext()));
if (!DD->hasAttrs())
break;
// Create a dummy expression,
- VarDecl *VD = const_cast<VarDecl*>(AD->getVarDecl());
+ VarDecl *VD = const_cast<VarDecl*>(AD.getVarDecl());
DeclRefExpr DRE(VD, false, VD->getType(), VK_LValue,
- AD->getTriggerStmt()->getLocEnd());
+ AD.getTriggerStmt()->getLocEnd());
LocksetBuilder.handleCall(&DRE, DD);
break;
}
diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp
index b2e27ca..730aa6b 100644
--- a/lib/Analysis/UninitializedValues.cpp
+++ b/lib/Analysis/UninitializedValues.cpp
@@ -11,20 +11,22 @@
//
//===----------------------------------------------------------------------===//
-#include <utility>
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/SmallBitVector.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/PackedVector.h"
-#include "llvm/ADT/DenseMap.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
-#include "clang/Analysis/CFG.h"
-#include "clang/Analysis/AnalysisContext.h"
-#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
+#include "clang/Analysis/Analyses/PostOrderCFGView.h"
#include "clang/Analysis/Analyses/UninitializedValues.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/CFG.h"
#include "clang/Analysis/DomainSpecific/ObjCNoReturn.h"
+#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/PackedVector.h"
+#include "llvm/ADT/SmallBitVector.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/SaveAndRestore.h"
+#include <utility>
using namespace clang;
@@ -57,7 +59,7 @@ public:
unsigned size() const { return map.size(); }
/// Returns the bit vector index for a given declaration.
- llvm::Optional<unsigned> getValueIndex(const VarDecl *d) const;
+ Optional<unsigned> getValueIndex(const VarDecl *d) const;
};
}
@@ -72,10 +74,10 @@ void DeclToIndex::computeMap(const DeclContext &dc) {
}
}
-llvm::Optional<unsigned> DeclToIndex::getValueIndex(const VarDecl *d) const {
+Optional<unsigned> DeclToIndex::getValueIndex(const VarDecl *d) const {
llvm::DenseMap<const VarDecl *, unsigned>::const_iterator I = map.find(d);
if (I == map.end())
- return llvm::Optional<unsigned>();
+ return None;
return I->second;
}
@@ -130,7 +132,7 @@ public:
Value getValue(const CFGBlock *block, const CFGBlock *dstBlock,
const VarDecl *vd) {
- const llvm::Optional<unsigned> &idx = declToIndex.getValueIndex(vd);
+ const Optional<unsigned> &idx = declToIndex.getValueIndex(vd);
assert(idx.hasValue());
return getValueVector(block)[idx.getValue()];
}
@@ -191,7 +193,7 @@ void CFGBlockValues::resetScratch() {
}
ValueVector::reference CFGBlockValues::operator[](const VarDecl *vd) {
- const llvm::Optional<unsigned> &idx = declToIndex.getValueIndex(vd);
+ const Optional<unsigned> &idx = declToIndex.getValueIndex(vd);
assert(idx.hasValue());
return scratch[idx.getValue()];
}
@@ -202,10 +204,20 @@ ValueVector::reference CFGBlockValues::operator[](const VarDecl *vd) {
namespace {
class DataflowWorklist {
+ PostOrderCFGView::iterator PO_I, PO_E;
SmallVector<const CFGBlock *, 20> worklist;
llvm::BitVector enqueuedBlocks;
public:
- DataflowWorklist(const CFG &cfg) : enqueuedBlocks(cfg.getNumBlockIDs()) {}
+ DataflowWorklist(const CFG &cfg, PostOrderCFGView &view)
+ : PO_I(view.begin()), PO_E(view.end()),
+ enqueuedBlocks(cfg.getNumBlockIDs(), true) {
+ // Treat the first block as already analyzed.
+ if (PO_I != PO_E) {
+ assert(*PO_I == &cfg.getEntry());
+ enqueuedBlocks[(*PO_I)->getBlockID()] = false;
+ ++PO_I;
+ }
+ }
void enqueueSuccessors(const CFGBlock *block);
const CFGBlock *dequeue();
@@ -213,7 +225,6 @@ public:
}
void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) {
- unsigned OldWorklistSize = worklist.size();
for (CFGBlock::const_succ_iterator I = block->succ_begin(),
E = block->succ_end(); I != E; ++I) {
const CFGBlock *Successor = *I;
@@ -222,22 +233,30 @@ void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) {
worklist.push_back(Successor);
enqueuedBlocks[Successor->getBlockID()] = true;
}
- if (OldWorklistSize == 0 || OldWorklistSize == worklist.size())
- return;
-
- // Rotate the newly added blocks to the start of the worklist so that it forms
- // a proper queue when we pop off the end of the worklist.
- std::rotate(worklist.begin(), worklist.begin() + OldWorklistSize,
- worklist.end());
}
const CFGBlock *DataflowWorklist::dequeue() {
- if (worklist.empty())
+ const CFGBlock *B = 0;
+
+ // First dequeue from the worklist. This can represent
+ // updates along backedges that we want propagated as quickly as possible.
+ if (!worklist.empty()) {
+ B = worklist.back();
+ worklist.pop_back();
+ }
+ // Next dequeue from the initial reverse post order. This is the
+ // theoretical ideal in the presence of no back edges.
+ else if (PO_I != PO_E) {
+ B = *PO_I;
+ ++PO_I;
+ }
+ else {
return 0;
- const CFGBlock *b = worklist.back();
- worklist.pop_back();
- enqueuedBlocks[b->getBlockID()] = false;
- return b;
+ }
+
+ assert(enqueuedBlocks[B->getBlockID()] == true);
+ enqueuedBlocks[B->getBlockID()] = false;
+ return B;
}
//------------------------------------------------------------------------====//
@@ -339,6 +358,16 @@ static const DeclRefExpr *getSelfInitExpr(VarDecl *VD) {
}
void ClassifyRefs::classify(const Expr *E, Class C) {
+ // The result of a ?: could also be an lvalue.
+ E = E->IgnoreParens();
+ if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
+ const Expr *TrueExpr = CO->getTrueExpr();
+ if (!isa<OpaqueValueExpr>(TrueExpr))
+ classify(TrueExpr, C);
+ classify(CO->getFalseExpr(), C);
+ return;
+ }
+
FindVarResult Var = findVar(E, DC);
if (const DeclRefExpr *DRE = Var.getDeclRefExpr())
Classification[DRE] = std::max(Classification[DRE], C);
@@ -408,13 +437,13 @@ class TransferFunctions : public StmtVisitor<TransferFunctions> {
AnalysisDeclContext &ac;
const ClassifyRefs &classification;
ObjCNoReturn objCNoRet;
- UninitVariablesHandler *handler;
+ UninitVariablesHandler &handler;
public:
TransferFunctions(CFGBlockValues &vals, const CFG &cfg,
const CFGBlock *block, AnalysisDeclContext &ac,
const ClassifyRefs &classification,
- UninitVariablesHandler *handler)
+ UninitVariablesHandler &handler)
: vals(vals), cfg(cfg), block(block), ac(ac),
classification(classification), objCNoRet(ac.getASTContext()),
handler(handler) {}
@@ -490,8 +519,8 @@ public:
// 'n' is definitely uninitialized for two edges into block 7 (from blocks 2
// and 4), so we report that any time either of those edges is taken (in
// each case when 'b == false'), 'n' is used uninitialized.
- llvm::SmallVector<const CFGBlock*, 32> Queue;
- llvm::SmallVector<unsigned, 32> SuccsVisited(cfg.getNumBlockIDs(), 0);
+ SmallVector<const CFGBlock*, 32> Queue;
+ SmallVector<unsigned, 32> SuccsVisited(cfg.getNumBlockIDs(), 0);
Queue.push_back(block);
// Specify that we've already visited all successors of the starting block.
// This has the dual purpose of ensuring we never add it to the queue, and
@@ -571,11 +600,9 @@ public:
}
void TransferFunctions::reportUse(const Expr *ex, const VarDecl *vd) {
- if (!handler)
- return;
Value v = vals[vd];
if (isUninitialized(v))
- handler->handleUseOfUninitVariable(vd, getUninitUse(ex, vd, v));
+ handler.handleUseOfUninitVariable(vd, getUninitUse(ex, vd, v));
}
void TransferFunctions::VisitObjCForCollectionStmt(ObjCForCollectionStmt *FS) {
@@ -636,8 +663,7 @@ void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) {
vals[cast<VarDecl>(dr->getDecl())] = Initialized;
break;
case ClassifyRefs::SelfInit:
- if (handler)
- handler->handleSelfInit(cast<VarDecl>(dr->getDecl()));
+ handler.handleSelfInit(cast<VarDecl>(dr->getDecl()));
break;
}
}
@@ -703,7 +729,7 @@ static bool runOnBlock(const CFGBlock *block, const CFG &cfg,
AnalysisDeclContext &ac, CFGBlockValues &vals,
const ClassifyRefs &classification,
llvm::BitVector &wasAnalyzed,
- UninitVariablesHandler *handler = 0) {
+ UninitVariablesHandler &handler) {
wasAnalyzed[block->getBlockID()] = true;
vals.resetScratch();
// Merge in values of predecessor blocks.
@@ -720,13 +746,49 @@ static bool runOnBlock(const CFGBlock *block, const CFG &cfg,
TransferFunctions tf(vals, cfg, block, ac, classification, handler);
for (CFGBlock::const_iterator I = block->begin(), E = block->end();
I != E; ++I) {
- if (const CFGStmt *cs = dyn_cast<CFGStmt>(&*I)) {
+ if (Optional<CFGStmt> cs = I->getAs<CFGStmt>())
tf.Visit(const_cast<Stmt*>(cs->getStmt()));
- }
}
return vals.updateValueVectorWithScratch(block);
}
+/// PruneBlocksHandler is a special UninitVariablesHandler that is used
+/// to detect when a CFGBlock has any *potential* use of an uninitialized
+/// variable. It is mainly used to prune out work during the final
+/// reporting pass.
+namespace {
+struct PruneBlocksHandler : public UninitVariablesHandler {
+ PruneBlocksHandler(unsigned numBlocks)
+ : hadUse(numBlocks, false), hadAnyUse(false),
+ currentBlock(0) {}
+
+ virtual ~PruneBlocksHandler() {}
+
+ /// Records if a CFGBlock had a potential use of an uninitialized variable.
+ llvm::BitVector hadUse;
+
+ /// Records if any CFGBlock had a potential use of an uninitialized variable.
+ bool hadAnyUse;
+
+ /// The current block to scribble use information.
+ unsigned currentBlock;
+
+ virtual void handleUseOfUninitVariable(const VarDecl *vd,
+ const UninitUse &use) {
+ hadUse[currentBlock] = true;
+ hadAnyUse = true;
+ }
+
+ /// Called when the uninitialized variable analysis detects the
+ /// idiom 'int x = x'. All other uses of 'x' within the initializer
+ /// are handled by handleUseOfUninitVariable.
+ virtual void handleSelfInit(const VarDecl *vd) {
+ hadUse[currentBlock] = true;
+ hadAnyUse = true;
+ }
+};
+}
+
void clang::runUninitializedVariablesAnalysis(
const DeclContext &dc,
const CFG &cfg,
@@ -753,27 +815,33 @@ void clang::runUninitializedVariablesAnalysis(
}
// Proceed with the workist.
- DataflowWorklist worklist(cfg);
+ DataflowWorklist worklist(cfg, *ac.getAnalysis<PostOrderCFGView>());
llvm::BitVector previouslyVisited(cfg.getNumBlockIDs());
worklist.enqueueSuccessors(&cfg.getEntry());
llvm::BitVector wasAnalyzed(cfg.getNumBlockIDs(), false);
wasAnalyzed[cfg.getEntry().getBlockID()] = true;
+ PruneBlocksHandler PBH(cfg.getNumBlockIDs());
while (const CFGBlock *block = worklist.dequeue()) {
+ PBH.currentBlock = block->getBlockID();
+
// Did the block change?
bool changed = runOnBlock(block, cfg, ac, vals,
- classification, wasAnalyzed);
+ classification, wasAnalyzed, PBH);
++stats.NumBlockVisits;
if (changed || !previouslyVisited[block->getBlockID()])
worklist.enqueueSuccessors(block);
previouslyVisited[block->getBlockID()] = true;
}
-
- // Run through the blocks one more time, and report uninitialized variabes.
+
+ if (!PBH.hadAnyUse)
+ return;
+
+ // Run through the blocks one more time, and report uninitialized variables.
for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) {
const CFGBlock *block = *BI;
- if (wasAnalyzed[block->getBlockID()]) {
- runOnBlock(block, cfg, ac, vals, classification, wasAnalyzed, &handler);
+ if (PBH.hadUse[block->getBlockID()]) {
+ runOnBlock(block, cfg, ac, vals, classification, wasAnalyzed, handler);
++stats.NumBlockVisits;
}
}
diff --git a/lib/Basic/Builtins.cpp b/lib/Basic/Builtins.cpp
index c78a292..242c204 100644
--- a/lib/Basic/Builtins.cpp
+++ b/lib/Basic/Builtins.cpp
@@ -13,8 +13,8 @@
#include "clang/Basic/Builtins.h"
#include "clang/Basic/IdentifierTable.h"
-#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallVector.h"
using namespace clang;
diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt
index 73e693b..3411169 100644
--- a/lib/Basic/CMakeLists.txt
+++ b/lib/Basic/CMakeLists.txt
@@ -2,8 +2,7 @@ set(LLVM_LINK_COMPONENTS mc)
add_clang_library(clangBasic
Builtins.cpp
- ConvertUTF.c
- ConvertUTFWrapper.cpp
+ CharInfo.cpp
Diagnostic.cpp
DiagnosticIDs.cpp
FileManager.cpp
@@ -12,6 +11,8 @@ add_clang_library(clangBasic
LangOptions.cpp
Module.cpp
ObjCRuntime.cpp
+ OpenMPKinds.cpp
+ OperatorPrecedence.cpp
SourceLocation.cpp
SourceManager.cpp
TargetInfo.cpp
@@ -28,9 +29,25 @@ if( NOT IS_SYMLINK "${CLANG_SOURCE_DIR}" ) # See PR 8437
find_package(Subversion)
endif()
if (Subversion_FOUND AND EXISTS "${CLANG_SOURCE_DIR}/.svn")
- Subversion_WC_INFO(${CLANG_SOURCE_DIR} CLANG)
+ # Create custom target to generate the Subversion version include.
+ add_custom_target(clang_revision_tag ALL
+ COMMAND ${CMAKE_COMMAND} -DFIRST_SOURCE_DIR=${LLVM_MAIN_SRC_DIR}
+ -DFIRST_REPOSITORY=LLVM_REPOSITORY
+ -DSECOND_SOURCE_DIR=${CLANG_SOURCE_DIR}
+ -DSECOND_REPOSITORY=SVN_REPOSITORY
+ -DHEADER_FILE=${CMAKE_CURRENT_BINARY_DIR}/SVNVersion.inc
+ -P ${LLVM_MAIN_SRC_DIR}/cmake/modules/GetSVN.cmake)
+
+ # Mark the generated header as being generated.
+message(STATUS "Expecting header to go in ${CMAKE_CURRENT_BINARY_DIR}/SVNVersion.inc")
+ set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/SVNVersion.inc
+ PROPERTIES GENERATED TRUE
+ HEADER_FILE_ONLY TRUE)
+
+ # Tell Version.cpp that it needs to build with -DHAVE_SVN_VERSION_INC.
set_source_files_properties(Version.cpp
- PROPERTIES COMPILE_DEFINITIONS "SVN_REVISION=\"${CLANG_WC_REVISION}\"")
+ PROPERTIES COMPILE_DEFINITIONS "HAVE_SVN_VERSION_INC")
+
endif()
add_dependencies(clangBasic
@@ -49,3 +66,8 @@ add_dependencies(clangBasic
ClangDiagnosticSema
ClangDiagnosticSerialization
)
+
+# clangBasic depends on the version.
+if (Subversion_FOUND AND EXISTS "${CLANG_SOURCE_DIR}/.svn")
+ add_dependencies(clangBasic clang_revision_tag)
+endif() \ No newline at end of file
diff --git a/lib/Basic/CharInfo.cpp b/lib/Basic/CharInfo.cpp
new file mode 100644
index 0000000..32b3277
--- /dev/null
+++ b/lib/Basic/CharInfo.cpp
@@ -0,0 +1,81 @@
+//===--- CharInfo.cpp - Static Data for Classifying ASCII Characters ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/CharInfo.h"
+
+using namespace clang::charinfo;
+
+// Statically initialize CharInfo table based on ASCII character set
+// Reference: FreeBSD 7.2 /usr/share/misc/ascii
+const uint16_t clang::charinfo::InfoTable[256] = {
+ // 0 NUL 1 SOH 2 STX 3 ETX
+ // 4 EOT 5 ENQ 6 ACK 7 BEL
+ 0 , 0 , 0 , 0 ,
+ 0 , 0 , 0 , 0 ,
+ // 8 BS 9 HT 10 NL 11 VT
+ //12 NP 13 CR 14 SO 15 SI
+ 0 , CHAR_HORZ_WS, CHAR_VERT_WS, CHAR_HORZ_WS,
+ CHAR_HORZ_WS, CHAR_VERT_WS, 0 , 0 ,
+ //16 DLE 17 DC1 18 DC2 19 DC3
+ //20 DC4 21 NAK 22 SYN 23 ETB
+ 0 , 0 , 0 , 0 ,
+ 0 , 0 , 0 , 0 ,
+ //24 CAN 25 EM 26 SUB 27 ESC
+ //28 FS 29 GS 30 RS 31 US
+ 0 , 0 , 0 , 0 ,
+ 0 , 0 , 0 , 0 ,
+ //32 SP 33 ! 34 " 35 #
+ //36 $ 37 % 38 & 39 '
+ CHAR_SPACE , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL ,
+ CHAR_PUNCT , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL ,
+ //40 ( 41 ) 42 * 43 +
+ //44 , 45 - 46 . 47 /
+ CHAR_PUNCT , CHAR_PUNCT , CHAR_RAWDEL , CHAR_RAWDEL ,
+ CHAR_RAWDEL , CHAR_RAWDEL , CHAR_PERIOD , CHAR_RAWDEL ,
+ //48 0 49 1 50 2 51 3
+ //52 4 53 5 54 6 55 7
+ CHAR_DIGIT , CHAR_DIGIT , CHAR_DIGIT , CHAR_DIGIT ,
+ CHAR_DIGIT , CHAR_DIGIT , CHAR_DIGIT , CHAR_DIGIT ,
+ //56 8 57 9 58 : 59 ;
+ //60 < 61 = 62 > 63 ?
+ CHAR_DIGIT , CHAR_DIGIT , CHAR_RAWDEL , CHAR_RAWDEL ,
+ CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL ,
+ //64 @ 65 A 66 B 67 C
+ //68 D 69 E 70 F 71 G
+ CHAR_PUNCT , CHAR_XUPPER , CHAR_XUPPER , CHAR_XUPPER ,
+ CHAR_XUPPER , CHAR_XUPPER , CHAR_XUPPER , CHAR_UPPER ,
+ //72 H 73 I 74 J 75 K
+ //76 L 77 M 78 N 79 O
+ CHAR_UPPER , CHAR_UPPER , CHAR_UPPER , CHAR_UPPER ,
+ CHAR_UPPER , CHAR_UPPER , CHAR_UPPER , CHAR_UPPER ,
+ //80 P 81 Q 82 R 83 S
+ //84 T 85 U 86 V 87 W
+ CHAR_UPPER , CHAR_UPPER , CHAR_UPPER , CHAR_UPPER ,
+ CHAR_UPPER , CHAR_UPPER , CHAR_UPPER , CHAR_UPPER ,
+ //88 X 89 Y 90 Z 91 [
+ //92 \ 93 ] 94 ^ 95 _
+ CHAR_UPPER , CHAR_UPPER , CHAR_UPPER , CHAR_RAWDEL ,
+ CHAR_PUNCT , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_UNDER ,
+ //96 ` 97 a 98 b 99 c
+ //100 d 101 e 102 f 103 g
+ CHAR_PUNCT , CHAR_XLOWER , CHAR_XLOWER , CHAR_XLOWER ,
+ CHAR_XLOWER , CHAR_XLOWER , CHAR_XLOWER , CHAR_LOWER ,
+ //104 h 105 i 106 j 107 k
+ //108 l 109 m 110 n 111 o
+ CHAR_LOWER , CHAR_LOWER , CHAR_LOWER , CHAR_LOWER ,
+ CHAR_LOWER , CHAR_LOWER , CHAR_LOWER , CHAR_LOWER ,
+ //112 p 113 q 114 r 115 s
+ //116 t 117 u 118 v 119 w
+ CHAR_LOWER , CHAR_LOWER , CHAR_LOWER , CHAR_LOWER ,
+ CHAR_LOWER , CHAR_LOWER , CHAR_LOWER , CHAR_LOWER ,
+ //120 x 121 y 122 z 123 {
+ //124 | 125 } 126 ~ 127 DEL
+ CHAR_LOWER , CHAR_LOWER , CHAR_LOWER , CHAR_RAWDEL ,
+ CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , 0
+};
diff --git a/lib/Basic/ConvertUTF.c b/lib/Basic/ConvertUTF.c
deleted file mode 100644
index d16965d..0000000
--- a/lib/Basic/ConvertUTF.c
+++ /dev/null
@@ -1,571 +0,0 @@
-/*===--- ConvertUTF.c - Universal Character Names conversions ---------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is distributed under the University of Illinois Open Source
- * License. See LICENSE.TXT for details.
- *
- *===------------------------------------------------------------------------=*/
-/*
- * Copyright 2001-2004 Unicode, Inc.
- *
- * Disclaimer
- *
- * This source code is provided as is by Unicode, Inc. No claims are
- * made as to fitness for any particular purpose. No warranties of any
- * kind are expressed or implied. The recipient agrees to determine
- * applicability of information provided. If this file has been
- * purchased on magnetic or optical media from Unicode, Inc., the
- * sole remedy for any claim will be exchange of defective media
- * within 90 days of receipt.
- *
- * Limitations on Rights to Redistribute This Code
- *
- * Unicode, Inc. hereby grants the right to freely use the information
- * supplied in this file in the creation of products supporting the
- * Unicode Standard, and to make copies of this file in any form
- * for internal or external distribution as long as this notice
- * remains attached.
- */
-
-/* ---------------------------------------------------------------------
-
- Conversions between UTF32, UTF-16, and UTF-8. Source code file.
- Author: Mark E. Davis, 1994.
- Rev History: Rick McGowan, fixes & updates May 2001.
- Sept 2001: fixed const & error conditions per
- mods suggested by S. Parent & A. Lillich.
- June 2002: Tim Dodd added detection and handling of incomplete
- source sequences, enhanced error detection, added casts
- to eliminate compiler warnings.
- July 2003: slight mods to back out aggressive FFFE detection.
- Jan 2004: updated switches in from-UTF8 conversions.
- Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
-
- See the header file "ConvertUTF.h" for complete documentation.
-
------------------------------------------------------------------------- */
-
-
-#include "clang/Basic/ConvertUTF.h"
-#ifdef CVTUTF_DEBUG
-#include <stdio.h>
-#endif
-
-static const int halfShift = 10; /* used for shifting by 10 bits */
-
-static const UTF32 halfBase = 0x0010000UL;
-static const UTF32 halfMask = 0x3FFUL;
-
-#define UNI_SUR_HIGH_START (UTF32)0xD800
-#define UNI_SUR_HIGH_END (UTF32)0xDBFF
-#define UNI_SUR_LOW_START (UTF32)0xDC00
-#define UNI_SUR_LOW_END (UTF32)0xDFFF
-#define false 0
-#define true 1
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Index into the table below with the first byte of a UTF-8 sequence to
- * get the number of trailing bytes that are supposed to follow it.
- * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
- * left as-is for anyone who may want to do such conversion, which was
- * allowed in earlier algorithms.
- */
-static const char trailingBytesForUTF8[256] = {
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
-};
-
-/*
- * Magic values subtracted from a buffer value during UTF8 conversion.
- * This table contains as many values as there might be trailing bytes
- * in a UTF-8 sequence.
- */
-static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
- 0x03C82080UL, 0xFA082080UL, 0x82082080UL };
-
-/*
- * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
- * into the first byte, depending on how many bytes follow. There are
- * as many entries in this table as there are UTF-8 sequence types.
- * (I.e., one byte sequence, two byte... etc.). Remember that sequencs
- * for *legal* UTF-8 will be 4 or fewer bytes total.
- */
-static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
-
-/* --------------------------------------------------------------------- */
-
-/* The interface converts a whole buffer to avoid function-call overhead.
- * Constants have been gathered. Loops & conditionals have been removed as
- * much as possible for efficiency, in favor of drop-through switches.
- * (See "Note A" at the bottom of the file for equivalent code.)
- * If your compiler supports it, the "isLegalUTF8" call can be turned
- * into an inline function.
- */
-
-
-/* --------------------------------------------------------------------- */
-
-ConversionResult ConvertUTF32toUTF16 (
- const UTF32** sourceStart, const UTF32* sourceEnd,
- UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
- ConversionResult result = conversionOK;
- const UTF32* source = *sourceStart;
- UTF16* target = *targetStart;
- while (source < sourceEnd) {
- UTF32 ch;
- if (target >= targetEnd) {
- result = targetExhausted; break;
- }
- ch = *source++;
- if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
- /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
- if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
- if (flags == strictConversion) {
- --source; /* return to the illegal value itself */
- result = sourceIllegal;
- break;
- } else {
- *target++ = UNI_REPLACEMENT_CHAR;
- }
- } else {
- *target++ = (UTF16)ch; /* normal case */
- }
- } else if (ch > UNI_MAX_LEGAL_UTF32) {
- if (flags == strictConversion) {
- result = sourceIllegal;
- } else {
- *target++ = UNI_REPLACEMENT_CHAR;
- }
- } else {
- /* target is a character in range 0xFFFF - 0x10FFFF. */
- if (target + 1 >= targetEnd) {
- --source; /* Back up source pointer! */
- result = targetExhausted; break;
- }
- ch -= halfBase;
- *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
- *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
- }
- }
- *sourceStart = source;
- *targetStart = target;
- return result;
-}
-
-/* --------------------------------------------------------------------- */
-
-ConversionResult ConvertUTF16toUTF32 (
- const UTF16** sourceStart, const UTF16* sourceEnd,
- UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
- ConversionResult result = conversionOK;
- const UTF16* source = *sourceStart;
- UTF32* target = *targetStart;
- UTF32 ch, ch2;
- while (source < sourceEnd) {
- const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
- ch = *source++;
- /* If we have a surrogate pair, convert to UTF32 first. */
- if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
- /* If the 16 bits following the high surrogate are in the source buffer... */
- if (source < sourceEnd) {
- ch2 = *source;
- /* If it's a low surrogate, convert to UTF32. */
- if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
- ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
- + (ch2 - UNI_SUR_LOW_START) + halfBase;
- ++source;
- } else if (flags == strictConversion) { /* it's an unpaired high surrogate */
- --source; /* return to the illegal value itself */
- result = sourceIllegal;
- break;
- }
- } else { /* We don't have the 16 bits following the high surrogate. */
- --source; /* return to the high surrogate */
- result = sourceExhausted;
- break;
- }
- } else if (flags == strictConversion) {
- /* UTF-16 surrogate values are illegal in UTF-32 */
- if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
- --source; /* return to the illegal value itself */
- result = sourceIllegal;
- break;
- }
- }
- if (target >= targetEnd) {
- source = oldSource; /* Back up source pointer! */
- result = targetExhausted; break;
- }
- *target++ = ch;
- }
- *sourceStart = source;
- *targetStart = target;
-#ifdef CVTUTF_DEBUG
-if (result == sourceIllegal) {
- fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2);
- fflush(stderr);
-}
-#endif
- return result;
-}
-ConversionResult ConvertUTF16toUTF8 (
- const UTF16** sourceStart, const UTF16* sourceEnd,
- UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
- ConversionResult result = conversionOK;
- const UTF16* source = *sourceStart;
- UTF8* target = *targetStart;
- while (source < sourceEnd) {
- UTF32 ch;
- unsigned short bytesToWrite = 0;
- const UTF32 byteMask = 0xBF;
- const UTF32 byteMark = 0x80;
- const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
- ch = *source++;
- /* If we have a surrogate pair, convert to UTF32 first. */
- if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
- /* If the 16 bits following the high surrogate are in the source buffer... */
- if (source < sourceEnd) {
- UTF32 ch2 = *source;
- /* If it's a low surrogate, convert to UTF32. */
- if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
- ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
- + (ch2 - UNI_SUR_LOW_START) + halfBase;
- ++source;
- } else if (flags == strictConversion) { /* it's an unpaired high surrogate */
- --source; /* return to the illegal value itself */
- result = sourceIllegal;
- break;
- }
- } else { /* We don't have the 16 bits following the high surrogate. */
- --source; /* return to the high surrogate */
- result = sourceExhausted;
- break;
- }
- } else if (flags == strictConversion) {
- /* UTF-16 surrogate values are illegal in UTF-32 */
- if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
- --source; /* return to the illegal value itself */
- result = sourceIllegal;
- break;
- }
- }
- /* Figure out how many bytes the result will require */
- if (ch < (UTF32)0x80) { bytesToWrite = 1;
- } else if (ch < (UTF32)0x800) { bytesToWrite = 2;
- } else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
- } else if (ch < (UTF32)0x110000) { bytesToWrite = 4;
- } else { bytesToWrite = 3;
- ch = UNI_REPLACEMENT_CHAR;
- }
-
- target += bytesToWrite;
- if (target > targetEnd) {
- source = oldSource; /* Back up source pointer! */
- target -= bytesToWrite; result = targetExhausted; break;
- }
- switch (bytesToWrite) { /* note: everything falls through. */
- case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
- case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
- case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
- case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]);
- }
- target += bytesToWrite;
- }
- *sourceStart = source;
- *targetStart = target;
- return result;
-}
-
-/* --------------------------------------------------------------------- */
-
-ConversionResult ConvertUTF32toUTF8 (
- const UTF32** sourceStart, const UTF32* sourceEnd,
- UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
- ConversionResult result = conversionOK;
- const UTF32* source = *sourceStart;
- UTF8* target = *targetStart;
- while (source < sourceEnd) {
- UTF32 ch;
- unsigned short bytesToWrite = 0;
- const UTF32 byteMask = 0xBF;
- const UTF32 byteMark = 0x80;
- ch = *source++;
- if (flags == strictConversion ) {
- /* UTF-16 surrogate values are illegal in UTF-32 */
- if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
- --source; /* return to the illegal value itself */
- result = sourceIllegal;
- break;
- }
- }
- /*
- * Figure out how many bytes the result will require. Turn any
- * illegally large UTF32 things (> Plane 17) into replacement chars.
- */
- if (ch < (UTF32)0x80) { bytesToWrite = 1;
- } else if (ch < (UTF32)0x800) { bytesToWrite = 2;
- } else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
- } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4;
- } else { bytesToWrite = 3;
- ch = UNI_REPLACEMENT_CHAR;
- result = sourceIllegal;
- }
-
- target += bytesToWrite;
- if (target > targetEnd) {
- --source; /* Back up source pointer! */
- target -= bytesToWrite; result = targetExhausted; break;
- }
- switch (bytesToWrite) { /* note: everything falls through. */
- case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
- case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
- case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
- case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
- }
- target += bytesToWrite;
- }
- *sourceStart = source;
- *targetStart = target;
- return result;
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Utility routine to tell whether a sequence of bytes is legal UTF-8.
- * This must be called with the length pre-determined by the first byte.
- * If not calling this from ConvertUTF8to*, then the length can be set by:
- * length = trailingBytesForUTF8[*source]+1;
- * and the sequence is illegal right away if there aren't that many bytes
- * available.
- * If presented with a length > 4, this returns false. The Unicode
- * definition of UTF-8 goes up to 4-byte sequences.
- */
-
-static Boolean isLegalUTF8(const UTF8 *source, int length) {
- UTF8 a;
- const UTF8 *srcptr = source+length;
- switch (length) {
- default: return false;
- /* Everything else falls through when "true"... */
- case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
- case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
- case 2: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
-
- switch (*source) {
- /* no fall-through in this inner switch */
- case 0xE0: if (a < 0xA0) return false; break;
- case 0xED: if (a > 0x9F) return false; break;
- case 0xF0: if (a < 0x90) return false; break;
- case 0xF4: if (a > 0x8F) return false; break;
- default: if (a < 0x80) return false;
- }
-
- case 1: if (*source >= 0x80 && *source < 0xC2) return false;
- }
- if (*source > 0xF4) return false;
- return true;
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Exported function to return whether a UTF-8 sequence is legal or not.
- * This is not used here; it's just exported.
- */
-Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
- int length = trailingBytesForUTF8[*source]+1;
- if (length > sourceEnd - source) {
- return false;
- }
- return isLegalUTF8(source, length);
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Exported function to return the total number of bytes in a codepoint
- * represented in UTF-8, given the value of the first byte.
- */
-unsigned getNumBytesForUTF8(UTF8 first) {
- return trailingBytesForUTF8[first] + 1;
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Exported function to return whether a UTF-8 string is legal or not.
- * This is not used here; it's just exported.
- */
-Boolean isLegalUTF8String(const UTF8 **source, const UTF8 *sourceEnd) {
- while (*source != sourceEnd) {
- int length = trailingBytesForUTF8[**source] + 1;
- if (length > sourceEnd - *source || !isLegalUTF8(*source, length))
- return false;
- *source += length;
- }
- return true;
-}
-
-/* --------------------------------------------------------------------- */
-
-ConversionResult ConvertUTF8toUTF16 (
- const UTF8** sourceStart, const UTF8* sourceEnd,
- UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
- ConversionResult result = conversionOK;
- const UTF8* source = *sourceStart;
- UTF16* target = *targetStart;
- while (source < sourceEnd) {
- UTF32 ch = 0;
- unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
- if (extraBytesToRead >= sourceEnd - source) {
- result = sourceExhausted; break;
- }
- /* Do this check whether lenient or strict */
- if (!isLegalUTF8(source, extraBytesToRead+1)) {
- result = sourceIllegal;
- break;
- }
- /*
- * The cases all fall through. See "Note A" below.
- */
- switch (extraBytesToRead) {
- case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
- case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
- case 3: ch += *source++; ch <<= 6;
- case 2: ch += *source++; ch <<= 6;
- case 1: ch += *source++; ch <<= 6;
- case 0: ch += *source++;
- }
- ch -= offsetsFromUTF8[extraBytesToRead];
-
- if (target >= targetEnd) {
- source -= (extraBytesToRead+1); /* Back up source pointer! */
- result = targetExhausted; break;
- }
- if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
- /* UTF-16 surrogate values are illegal in UTF-32 */
- if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
- if (flags == strictConversion) {
- source -= (extraBytesToRead+1); /* return to the illegal value itself */
- result = sourceIllegal;
- break;
- } else {
- *target++ = UNI_REPLACEMENT_CHAR;
- }
- } else {
- *target++ = (UTF16)ch; /* normal case */
- }
- } else if (ch > UNI_MAX_UTF16) {
- if (flags == strictConversion) {
- result = sourceIllegal;
- source -= (extraBytesToRead+1); /* return to the start */
- break; /* Bail out; shouldn't continue */
- } else {
- *target++ = UNI_REPLACEMENT_CHAR;
- }
- } else {
- /* target is a character in range 0xFFFF - 0x10FFFF. */
- if (target + 1 >= targetEnd) {
- source -= (extraBytesToRead+1); /* Back up source pointer! */
- result = targetExhausted; break;
- }
- ch -= halfBase;
- *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
- *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
- }
- }
- *sourceStart = source;
- *targetStart = target;
- return result;
-}
-
-/* --------------------------------------------------------------------- */
-
-ConversionResult ConvertUTF8toUTF32 (
- const UTF8** sourceStart, const UTF8* sourceEnd,
- UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
- ConversionResult result = conversionOK;
- const UTF8* source = *sourceStart;
- UTF32* target = *targetStart;
- while (source < sourceEnd) {
- UTF32 ch = 0;
- unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
- if (extraBytesToRead >= sourceEnd - source) {
- result = sourceExhausted; break;
- }
- /* Do this check whether lenient or strict */
- if (!isLegalUTF8(source, extraBytesToRead+1)) {
- result = sourceIllegal;
- break;
- }
- /*
- * The cases all fall through. See "Note A" below.
- */
- switch (extraBytesToRead) {
- case 5: ch += *source++; ch <<= 6;
- case 4: ch += *source++; ch <<= 6;
- case 3: ch += *source++; ch <<= 6;
- case 2: ch += *source++; ch <<= 6;
- case 1: ch += *source++; ch <<= 6;
- case 0: ch += *source++;
- }
- ch -= offsetsFromUTF8[extraBytesToRead];
-
- if (target >= targetEnd) {
- source -= (extraBytesToRead+1); /* Back up the source pointer! */
- result = targetExhausted; break;
- }
- if (ch <= UNI_MAX_LEGAL_UTF32) {
- /*
- * UTF-16 surrogate values are illegal in UTF-32, and anything
- * over Plane 17 (> 0x10FFFF) is illegal.
- */
- if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
- if (flags == strictConversion) {
- source -= (extraBytesToRead+1); /* return to the illegal value itself */
- result = sourceIllegal;
- break;
- } else {
- *target++ = UNI_REPLACEMENT_CHAR;
- }
- } else {
- *target++ = ch;
- }
- } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
- result = sourceIllegal;
- *target++ = UNI_REPLACEMENT_CHAR;
- }
- }
- *sourceStart = source;
- *targetStart = target;
- return result;
-}
-
-/* ---------------------------------------------------------------------
-
- Note A.
- The fall-through switches in UTF-8 reading code save a
- temp variable, some decrements & conditionals. The switches
- are equivalent to the following loop:
- {
- int tmpBytesToRead = extraBytesToRead+1;
- do {
- ch += *source++;
- --tmpBytesToRead;
- if (tmpBytesToRead) ch <<= 6;
- } while (tmpBytesToRead > 0);
- }
- In UTF-8 writing code, the switches on "bytesToWrite" are
- similarly unrolled loops.
-
- --------------------------------------------------------------------- */
diff --git a/lib/Basic/ConvertUTFWrapper.cpp b/lib/Basic/ConvertUTFWrapper.cpp
deleted file mode 100644
index 6be3828..0000000
--- a/lib/Basic/ConvertUTFWrapper.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-//===-- ConvertUTFWrapper.cpp - Wrap ConvertUTF.h with clang data types -----===
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Basic/ConvertUTF.h"
-#include "clang/Basic/LLVM.h"
-
-namespace clang {
-
-bool ConvertUTF8toWide(unsigned WideCharWidth, llvm::StringRef Source,
- char *&ResultPtr, const UTF8 *&ErrorPtr) {
- assert(WideCharWidth == 1 || WideCharWidth == 2 || WideCharWidth == 4);
- ConversionResult result = conversionOK;
- // Copy the character span over.
- if (WideCharWidth == 1) {
- const UTF8 *Pos = reinterpret_cast<const UTF8*>(Source.begin());
- if (!isLegalUTF8String(&Pos, reinterpret_cast<const UTF8*>(Source.end()))) {
- result = sourceIllegal;
- ErrorPtr = Pos;
- } else {
- memcpy(ResultPtr, Source.data(), Source.size());
- ResultPtr += Source.size();
- }
- } else if (WideCharWidth == 2) {
- const UTF8 *sourceStart = (const UTF8*)Source.data();
- // FIXME: Make the type of the result buffer correct instead of
- // using reinterpret_cast.
- UTF16 *targetStart = reinterpret_cast<UTF16*>(ResultPtr);
- ConversionFlags flags = strictConversion;
- result = ConvertUTF8toUTF16(
- &sourceStart, sourceStart + Source.size(),
- &targetStart, targetStart + 2*Source.size(), flags);
- if (result == conversionOK)
- ResultPtr = reinterpret_cast<char*>(targetStart);
- else
- ErrorPtr = sourceStart;
- } else if (WideCharWidth == 4) {
- const UTF8 *sourceStart = (const UTF8*)Source.data();
- // FIXME: Make the type of the result buffer correct instead of
- // using reinterpret_cast.
- UTF32 *targetStart = reinterpret_cast<UTF32*>(ResultPtr);
- ConversionFlags flags = strictConversion;
- result = ConvertUTF8toUTF32(
- &sourceStart, sourceStart + Source.size(),
- &targetStart, targetStart + 4*Source.size(), flags);
- if (result == conversionOK)
- ResultPtr = reinterpret_cast<char*>(targetStart);
- else
- ErrorPtr = sourceStart;
- }
- assert((result != targetExhausted)
- && "ConvertUTF8toUTFXX exhausted target buffer");
- return result == conversionOK;
-}
-
-bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr) {
- const UTF32 *SourceStart = &Source;
- const UTF32 *SourceEnd = SourceStart + 1;
- UTF8 *TargetStart = reinterpret_cast<UTF8 *>(ResultPtr);
- UTF8 *TargetEnd = TargetStart + 4;
- ConversionResult CR = ConvertUTF32toUTF8(&SourceStart, SourceEnd,
- &TargetStart, TargetEnd,
- strictConversion);
- if (CR != conversionOK)
- return false;
-
- ResultPtr = reinterpret_cast<char*>(TargetStart);
- return true;
-}
-
-} // end namespace clang
diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp
index 854c4c5..842bacb 100644
--- a/lib/Basic/Diagnostic.cpp
+++ b/lib/Basic/Diagnostic.cpp
@@ -11,15 +11,15 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/CrashRecoveryContext.h"
-#include <cctype>
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -97,6 +97,7 @@ bool DiagnosticsEngine::popMappings(SourceLocation Loc) {
void DiagnosticsEngine::Reset() {
ErrorOccurred = false;
+ UncompilableErrorOccurred = false;
FatalErrorOccurred = false;
UnrecoverableErrorOccurred = false;
@@ -107,11 +108,7 @@ void DiagnosticsEngine::Reset() {
TrapNumUnrecoverableErrorsOccurred = 0;
CurDiagID = ~0U;
- // Set LastDiagLevel to an "unset" state. If we set it to 'Ignored', notes
- // using a DiagnosticsEngine associated to a translation unit that follow
- // diagnostics from a DiagnosticsEngine associated to anoter t.u. will not be
- // displayed.
- LastDiagLevel = (DiagnosticIDs::Level)-1;
+ LastDiagLevel = DiagnosticIDs::Ignored;
DelayedDiagID = 0;
// Clear state related to #pragma diagnostic.
@@ -237,7 +234,7 @@ bool DiagnosticsEngine::setDiagnosticGroupMapping(
StringRef Group, diag::Mapping Map, SourceLocation Loc)
{
// Get the diagnostics in this group.
- llvm::SmallVector<diag::kind, 8> GroupDiags;
+ SmallVector<diag::kind, 8> GroupDiags;
if (Diags->getDiagnosticsInGroup(Group, GroupDiags))
return true;
@@ -277,7 +274,7 @@ bool DiagnosticsEngine::setDiagnosticGroupWarningAsError(StringRef Group,
// potentially downgrade anything already mapped to be a warning.
// Get the diagnostics in this group.
- llvm::SmallVector<diag::kind, 8> GroupDiags;
+ SmallVector<diag::kind, 8> GroupDiags;
if (Diags->getDiagnosticsInGroup(Group, GroupDiags))
return true;
@@ -324,7 +321,7 @@ bool DiagnosticsEngine::setDiagnosticGroupErrorAsFatal(StringRef Group,
// potentially downgrade anything already mapped to be an error.
// Get the diagnostics in this group.
- llvm::SmallVector<diag::kind, 8> GroupDiags;
+ SmallVector<diag::kind, 8> GroupDiags;
if (Diags->getDiagnosticsInGroup(Group, GroupDiags))
return true;
@@ -345,7 +342,7 @@ bool DiagnosticsEngine::setDiagnosticGroupErrorAsFatal(StringRef Group,
void DiagnosticsEngine::setMappingToAllDiagnostics(diag::Mapping Map,
SourceLocation Loc) {
// Get all the diagnostics.
- llvm::SmallVector<diag::kind, 64> AllDiags;
+ SmallVector<diag::kind, 64> AllDiags;
Diags->getAllDiagnostics(AllDiags);
// Set the mapping.
@@ -460,8 +457,8 @@ static const char *ScanFormat(const char *I, const char *E, char Target) {
// Escaped characters get implicitly skipped here.
// Format specifier.
- if (!isdigit(*I) && !ispunct(*I)) {
- for (I++; I != E && !isdigit(*I) && *I != '{'; I++) ;
+ if (!isDigit(*I) && !isPunctuation(*I)) {
+ for (I++; I != E && !isDigit(*I) && *I != '{'; I++) ;
if (I == E) break;
if (*I == '{')
Depth++;
@@ -685,7 +682,7 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
OutStr.append(DiagStr, StrEnd);
DiagStr = StrEnd;
continue;
- } else if (ispunct(DiagStr[1])) {
+ } else if (isPunctuation(DiagStr[1])) {
OutStr.push_back(DiagStr[1]); // %% -> %.
DiagStr += 2;
continue;
@@ -703,7 +700,7 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
unsigned ModifierLen = 0, ArgumentLen = 0;
// Check to see if we have a modifier. If so eat it.
- if (!isdigit(DiagStr[0])) {
+ if (!isDigit(DiagStr[0])) {
Modifier = DiagStr;
while (DiagStr[0] == '-' ||
(DiagStr[0] >= 'a' && DiagStr[0] <= 'z'))
@@ -722,22 +719,40 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
}
}
- assert(isdigit(*DiagStr) && "Invalid format for argument in diagnostic");
+ assert(isDigit(*DiagStr) && "Invalid format for argument in diagnostic");
unsigned ArgNo = *DiagStr++ - '0';
// Only used for type diffing.
unsigned ArgNo2 = ArgNo;
DiagnosticsEngine::ArgumentKind Kind = getArgKind(ArgNo);
- if (Kind == DiagnosticsEngine::ak_qualtype &&
- ModifierIs(Modifier, ModifierLen, "diff")) {
- Kind = DiagnosticsEngine::ak_qualtype_pair;
- assert(*DiagStr == ',' && isdigit(*(DiagStr + 1)) &&
+ if (ModifierIs(Modifier, ModifierLen, "diff")) {
+ assert(*DiagStr == ',' && isDigit(*(DiagStr + 1)) &&
"Invalid format for diff modifier");
++DiagStr; // Comma.
ArgNo2 = *DiagStr++ - '0';
- assert(getArgKind(ArgNo2) == DiagnosticsEngine::ak_qualtype &&
- "Second value of type diff must be a qualtype");
+ DiagnosticsEngine::ArgumentKind Kind2 = getArgKind(ArgNo2);
+ if (Kind == DiagnosticsEngine::ak_qualtype &&
+ Kind2 == DiagnosticsEngine::ak_qualtype)
+ Kind = DiagnosticsEngine::ak_qualtype_pair;
+ else {
+ // %diff only supports QualTypes. For other kinds of arguments,
+ // use the default printing. For example, if the modifier is:
+ // "%diff{compare $ to $|other text}1,2"
+ // treat it as:
+ // "compare %1 to %2"
+ const char *Pipe = ScanFormat(Argument, Argument + ArgumentLen, '|');
+ const char *FirstDollar = ScanFormat(Argument, Pipe, '$');
+ const char *SecondDollar = ScanFormat(FirstDollar + 1, Pipe, '$');
+ const char ArgStr1[] = { '%', static_cast<char>('0' + ArgNo) };
+ const char ArgStr2[] = { '%', static_cast<char>('0' + ArgNo2) };
+ FormatDiagnostic(Argument, FirstDollar, OutStr);
+ FormatDiagnostic(ArgStr1, ArgStr1 + 2, OutStr);
+ FormatDiagnostic(FirstDollar + 1, SecondDollar, OutStr);
+ FormatDiagnostic(ArgStr2, ArgStr2 + 2, OutStr);
+ FormatDiagnostic(SecondDollar + 1, Pipe, OutStr);
+ continue;
+ }
}
switch (Kind) {
@@ -940,11 +955,10 @@ StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level,
StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID,
StringRef Message, FullSourceLoc Loc,
ArrayRef<CharSourceRange> Ranges,
- ArrayRef<FixItHint> Fixits)
- : ID(ID), Level(Level), Loc(Loc), Message(Message)
+ ArrayRef<FixItHint> FixIts)
+ : ID(ID), Level(Level), Loc(Loc), Message(Message),
+ Ranges(Ranges.begin(), Ranges.end()), FixIts(FixIts.begin(), FixIts.end())
{
- this->Ranges.assign(Ranges.begin(), Ranges.end());
- this->FixIts.assign(FixIts.begin(), FixIts.end());
}
StoredDiagnostic::~StoredDiagnostic() { }
diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp
index ed97643..353af4b 100644
--- a/lib/Basic/DiagnosticIDs.cpp
+++ b/lib/Basic/DiagnosticIDs.cpp
@@ -17,7 +17,6 @@
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/ErrorHandling.h"
-
#include <map>
using namespace clang;
@@ -108,16 +107,51 @@ static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) {
}
#endif
- // Search the diagnostic table with a binary search.
- StaticDiagInfoRec Find = { static_cast<unsigned short>(DiagID),
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ // Out of bounds diag. Can't be in the table.
+ using namespace diag;
+ if (DiagID >= DIAG_UPPER_LIMIT)
+ return 0;
- const StaticDiagInfoRec *Found =
- std::lower_bound(StaticDiagInfo, StaticDiagInfo + StaticDiagInfoSize, Find);
- if (Found == StaticDiagInfo + StaticDiagInfoSize ||
- Found->DiagID != DiagID)
+ // Compute the index of the requested diagnostic in the static table.
+ // 1. Add the number of diagnostics in each category preceeding the
+ // diagnostic and of the category the diagnostic is in. This gives us
+ // the offset of the category in the table.
+ // 2. Subtract the number of IDs in each category from our ID. This gives us
+ // the offset of the diagnostic in the category.
+ // This is cheaper than a binary search on the table as it doesn't touch
+ // memory at all.
+ unsigned Offset = 0;
+ unsigned ID = DiagID;
+#define DIAG_START_COMMON 0 // Sentinel value.
+#define CATEGORY(NAME, PREV) \
+ if (DiagID > DIAG_START_##NAME) { \
+ Offset += NUM_BUILTIN_##PREV##_DIAGNOSTICS - DIAG_START_##PREV - 1; \
+ ID -= DIAG_START_##NAME - DIAG_START_##PREV; \
+ }
+CATEGORY(DRIVER, COMMON)
+CATEGORY(FRONTEND, DRIVER)
+CATEGORY(SERIALIZATION, FRONTEND)
+CATEGORY(LEX, SERIALIZATION)
+CATEGORY(PARSE, LEX)
+CATEGORY(AST, PARSE)
+CATEGORY(COMMENT, AST)
+CATEGORY(SEMA, COMMENT)
+CATEGORY(ANALYSIS, SEMA)
+#undef CATEGORY
+#undef DIAG_START_COMMON
+
+ // Avoid out of bounds reads.
+ if (ID + Offset >= StaticDiagInfoSize)
return 0;
+ assert(ID < StaticDiagInfoSize && Offset < StaticDiagInfoSize);
+
+ const StaticDiagInfoRec *Found = &StaticDiagInfo[ID + Offset];
+ // If the diag id doesn't match we found a different diag, abort. This can
+ // happen when this function is called with an ID that points into a hole in
+ // the diagID space.
+ if (Found->DiagID != DiagID)
+ return 0;
return Found;
}
@@ -247,14 +281,14 @@ namespace clang {
/// diagnostic.
StringRef getDescription(unsigned DiagID) const {
assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() &&
- "Invalid diagnosic ID");
+ "Invalid diagnostic ID");
return DiagInfo[DiagID-DIAG_UPPER_LIMIT].second;
}
/// getLevel - Return the level of the specified custom diagnostic.
DiagnosticIDs::Level getLevel(unsigned DiagID) const {
assert(this && DiagID-DIAG_UPPER_LIMIT < DiagInfo.size() &&
- "Invalid diagnosic ID");
+ "Invalid diagnostic ID");
return DiagInfo[DiagID-DIAG_UPPER_LIMIT].first;
}
@@ -291,7 +325,7 @@ DiagnosticIDs::~DiagnosticIDs() {
}
/// getCustomDiagID - Return an ID for a diagnostic with the specified message
-/// and level. If this is the first request for this diagnosic, it is
+/// and level. If this is the first request for this diagnostic, it is
/// registered and created, otherwise the existing ID is returned.
unsigned DiagnosticIDs::getCustomDiagID(Level L, StringRef Message) {
if (CustomDiagInfo == 0)
@@ -512,9 +546,8 @@ StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) {
}
void DiagnosticIDs::getDiagnosticsInGroup(
- const WarningOption *Group,
- llvm::SmallVectorImpl<diag::kind> &Diags) const
-{
+ const WarningOption *Group,
+ SmallVectorImpl<diag::kind> &Diags) const {
// Add the members of the option diagnostic set.
if (const short *Member = Group->Members) {
for (; *Member != -1; ++Member)
@@ -529,9 +562,8 @@ void DiagnosticIDs::getDiagnosticsInGroup(
}
bool DiagnosticIDs::getDiagnosticsInGroup(
- StringRef Group,
- llvm::SmallVectorImpl<diag::kind> &Diags) const
-{
+ StringRef Group,
+ SmallVectorImpl<diag::kind> &Diags) const {
WarningOption Key = { Group.size(), Group.data(), 0, 0 };
const WarningOption *Found =
std::lower_bound(OptionTable, OptionTable + OptionTableSize, Key,
@@ -545,7 +577,7 @@ bool DiagnosticIDs::getDiagnosticsInGroup(
}
void DiagnosticIDs::getAllDiagnostics(
- llvm::SmallVectorImpl<diag::kind> &Diags) const {
+ SmallVectorImpl<diag::kind> &Diags) const {
for (unsigned i = 0; i != StaticDiagInfoSize; ++i)
Diags.push_back(StaticDiagInfo[i].DiagID);
}
@@ -629,6 +661,10 @@ bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const {
if (isUnrecoverable(DiagID))
Diag.UnrecoverableErrorOccurred = true;
+ // Warnings which have been upgraded to errors do not prevent compilation.
+ if (isDefaultMappingAsError(DiagID))
+ Diag.UncompilableErrorOccurred = true;
+
Diag.ErrorOccurred = true;
if (Diag.Client->IncludeInDiagnosticCounts()) {
++Diag.NumErrors;
diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp
index a816969..9cc5902 100644
--- a/lib/Basic/FileManager.cpp
+++ b/lib/Basic/FileManager.cpp
@@ -20,12 +20,12 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemStatCache.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
-#include "llvm/Config/llvm-config.h"
#include <map>
#include <set>
#include <string>
@@ -40,6 +40,9 @@
#define S_ISFIFO(x) (0)
#endif
#endif
+#if defined(LLVM_ON_UNIX)
+#include <limits.h>
+#endif
using namespace clang;
// FIXME: Enhance libsystem to support inode and other fields.
@@ -311,7 +314,7 @@ const DirectoryEntry *FileManager::getDirectory(StringRef DirName,
// Check to see if the directory exists.
struct stat StatBuf;
- if (getStatValue(InterndDirName, StatBuf, 0/*directory lookup*/)) {
+ if (getStatValue(InterndDirName, StatBuf, false, 0/*directory lookup*/)) {
// There's no real directory at the given path.
if (!CacheFailure)
SeenDirEntries.erase(DirName);
@@ -376,7 +379,8 @@ const FileEntry *FileManager::getFile(StringRef Filename, bool openFile,
// Nope, there isn't. Check to see if the file exists.
int FileDescriptor = -1;
struct stat StatBuf;
- if (getStatValue(InterndFileName, StatBuf, &FileDescriptor)) {
+ if (getStatValue(InterndFileName, StatBuf, true,
+ openFile ? &FileDescriptor : 0)) {
// There's no real file at the given path.
if (!CacheFailure)
SeenFileEntries.erase(Filename);
@@ -444,14 +448,9 @@ FileManager::getVirtualFile(StringRef Filename, off_t Size,
"The directory of a virtual file should already be in the cache.");
// Check to see if the file exists. If so, drop the virtual file
- int FileDescriptor = -1;
struct stat StatBuf;
const char *InterndFileName = NamedFileEnt.getKeyData();
- if (getStatValue(InterndFileName, StatBuf, &FileDescriptor) == 0) {
- // If the stat process opened the file, close it to avoid a FD leak.
- if (FileDescriptor != -1)
- close(FileDescriptor);
-
+ if (getStatValue(InterndFileName, StatBuf, true, 0) == 0) {
StatBuf.st_size = Size;
StatBuf.st_mtime = ModificationTime;
UFE = &UniqueRealFiles.getFile(InterndFileName, StatBuf);
@@ -564,18 +563,18 @@ getBufferForFile(StringRef Filename, std::string *ErrorStr) {
/// false if it's an existent real file. If FileDescriptor is NULL,
/// do directory look-up instead of file look-up.
bool FileManager::getStatValue(const char *Path, struct stat &StatBuf,
- int *FileDescriptor) {
+ bool isFile, int *FileDescriptor) {
// FIXME: FileSystemOpts shouldn't be passed in here, all paths should be
// absolute!
if (FileSystemOpts.WorkingDir.empty())
- return FileSystemStatCache::get(Path, StatBuf, FileDescriptor,
+ return FileSystemStatCache::get(Path, StatBuf, isFile, FileDescriptor,
StatCache.get());
SmallString<128> FilePath(Path);
FixupRelativePath(FilePath);
- return FileSystemStatCache::get(FilePath.c_str(), StatBuf, FileDescriptor,
- StatCache.get());
+ return FileSystemStatCache::get(FilePath.c_str(), StatBuf,
+ isFile, FileDescriptor, StatCache.get());
}
bool FileManager::getNoncachedStatValue(StringRef Path,
@@ -624,6 +623,29 @@ void FileManager::modifyFileEntry(FileEntry *File,
File->ModTime = ModificationTime;
}
+StringRef FileManager::getCanonicalName(const DirectoryEntry *Dir) {
+ // FIXME: use llvm::sys::fs::canonical() when it gets implemented
+#ifdef LLVM_ON_UNIX
+ llvm::DenseMap<const DirectoryEntry *, llvm::StringRef>::iterator Known
+ = CanonicalDirNames.find(Dir);
+ if (Known != CanonicalDirNames.end())
+ return Known->second;
+
+ StringRef CanonicalName(Dir->getName());
+ char CanonicalNameBuf[PATH_MAX];
+ if (realpath(Dir->getName(), CanonicalNameBuf)) {
+ unsigned Len = strlen(CanonicalNameBuf);
+ char *Mem = static_cast<char *>(CanonicalNameStorage.Allocate(Len, 1));
+ memcpy(Mem, CanonicalNameBuf, Len);
+ CanonicalName = StringRef(Mem, Len);
+ }
+
+ CanonicalDirNames.insert(std::make_pair(Dir, CanonicalName));
+ return CanonicalName;
+#else
+ return StringRef(Dir->getName());
+#endif
+}
void FileManager::PrintStats() const {
llvm::errs() << "\n*** File Manager Stats:\n";
diff --git a/lib/Basic/FileSystemStatCache.cpp b/lib/Basic/FileSystemStatCache.cpp
index 875d397..38c4629 100644
--- a/lib/Basic/FileSystemStatCache.cpp
+++ b/lib/Basic/FileSystemStatCache.cpp
@@ -34,21 +34,23 @@ void FileSystemStatCache::anchor() { }
/// path, using the cache to accelerate it if possible. This returns true if
/// the path does not exist or false if it exists.
///
-/// If FileDescriptor is non-null, then this lookup should only return success
-/// for files (not directories). If it is null this lookup should only return
+/// If isFile is true, then this lookup should only return success for files
+/// (not directories). If it is false this lookup should only return
/// success for directories (not files). On a successful file lookup, the
/// implementation can optionally fill in FileDescriptor with a valid
/// descriptor and the client guarantees that it will close it.
bool FileSystemStatCache::get(const char *Path, struct stat &StatBuf,
- int *FileDescriptor, FileSystemStatCache *Cache) {
+ bool isFile, int *FileDescriptor,
+ FileSystemStatCache *Cache) {
LookupResult R;
- bool isForDir = FileDescriptor == 0;
+ bool isForDir = !isFile;
// If we have a cache, use it to resolve the stat query.
if (Cache)
- R = Cache->getStat(Path, StatBuf, FileDescriptor);
- else if (isForDir) {
- // If this is a directory and we have no cache, just go to the file system.
+ R = Cache->getStat(Path, StatBuf, isFile, FileDescriptor);
+ else if (isForDir || !FileDescriptor) {
+ // If this is a directory or a file descriptor is not needed and we have
+ // no cache, just go to the file system.
R = ::stat(Path, &StatBuf) != 0 ? CacheMissing : CacheExists;
} else {
// Otherwise, we have to go to the filesystem. We can always just use
@@ -104,8 +106,8 @@ bool FileSystemStatCache::get(const char *Path, struct stat &StatBuf,
MemorizeStatCalls::LookupResult
MemorizeStatCalls::getStat(const char *Path, struct stat &StatBuf,
- int *FileDescriptor) {
- LookupResult Result = statChained(Path, StatBuf, FileDescriptor);
+ bool isFile, int *FileDescriptor) {
+ LookupResult Result = statChained(Path, StatBuf, isFile, FileDescriptor);
// Do not cache failed stats, it is easy to construct common inconsistent
// situations if we do, and they are not important for PCH performance (which
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index 1965bf9..429d9d8 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -13,13 +13,13 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/LangOptions.h"
-#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
-#include <cctype>
+#include "llvm/Support/raw_ostream.h"
#include <cstdio>
using namespace clang;
@@ -82,7 +82,7 @@ IdentifierTable::IdentifierTable(const LangOptions &LangOpts,
// Add the '_experimental_modules_import' contextual keyword.
- get("__experimental_modules_import").setModulesImport(true);
+ get("import").setModulesImport(true);
}
//===----------------------------------------------------------------------===//
@@ -94,7 +94,7 @@ namespace {
enum {
KEYC99 = 0x1,
KEYCXX = 0x2,
- KEYCXX0X = 0x4,
+ KEYCXX11 = 0x4,
KEYGNU = 0x8,
KEYMS = 0x10,
BOOLSUPPORT = 0x20,
@@ -124,7 +124,7 @@ static void AddKeyword(StringRef Keyword,
unsigned AddResult = 0;
if (Flags == KEYALL) AddResult = 2;
else if (LangOpts.CPlusPlus && (Flags & KEYCXX)) AddResult = 2;
- else if (LangOpts.CPlusPlus0x && (Flags & KEYCXX0X)) AddResult = 2;
+ else if (LangOpts.CPlusPlus11 && (Flags & KEYCXX11)) AddResult = 2;
else if (LangOpts.C99 && (Flags & KEYC99)) AddResult = 2;
else if (LangOpts.GNUKeywords && (Flags & KEYGNU)) AddResult = 1;
else if (LangOpts.MicrosoftExt && (Flags & KEYMS)) AddResult = 1;
@@ -138,7 +138,7 @@ static void AddKeyword(StringRef Keyword,
// We treat bridge casts as objective-C keywords so we can warn on them
// in non-arc mode.
else if (LangOpts.ObjC2 && (Flags & KEYARC)) AddResult = 2;
- else if (LangOpts.CPlusPlus && (Flags & KEYCXX0X)) AddResult = 3;
+ else if (LangOpts.CPlusPlus && (Flags & KEYCXX11)) AddResult = 3;
// Don't add this keyword under MicrosoftMode.
if (LangOpts.MicrosoftMode && (Flags & KEYNOMS))
@@ -404,9 +404,8 @@ std::string Selector::getAsString() const {
/// given "word", which is assumed to end in a lowercase letter.
static bool startsWithWord(StringRef name, StringRef word) {
if (name.size() < word.size()) return false;
- return ((name.size() == word.size() ||
- !islower(name[word.size()]))
- && name.startswith(word));
+ return ((name.size() == word.size() || !isLowercase(name[word.size()])) &&
+ name.startswith(word));
}
ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) {
@@ -472,7 +471,7 @@ SelectorTable::constructSetterName(IdentifierTable &Idents,
SmallString<100> SelectorName;
SelectorName = "set";
SelectorName += Name->getName();
- SelectorName[3] = toupper(SelectorName[3]);
+ SelectorName[3] = toUppercase(SelectorName[3]);
IdentifierInfo *SetterName = &Idents.get(SelectorName);
return SelTable.getUnarySelector(SetterName);
}
diff --git a/lib/Basic/LangOptions.cpp b/lib/Basic/LangOptions.cpp
index 991992a..f8714b2 100644
--- a/lib/Basic/LangOptions.cpp
+++ b/lib/Basic/LangOptions.cpp
@@ -14,10 +14,14 @@
using namespace clang;
+const SanitizerOptions SanitizerOptions::Disabled = {};
+
LangOptions::LangOptions() {
#define LANGOPT(Name, Bits, Default, Description) Name = Default;
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) set##Name(Default);
#include "clang/Basic/LangOptions.def"
+
+ Sanitize = SanitizerOptions::Disabled;
}
void LangOptions::resetNonModularOptions() {
@@ -26,7 +30,11 @@ void LangOptions::resetNonModularOptions() {
#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
Name = Default;
#include "clang/Basic/LangOptions.def"
-
+
+ // FIXME: This should not be reset; modules can be different with different
+ // sanitizer options (this affects __has_feature(address_sanitizer) etc).
+ Sanitize = SanitizerOptions::Disabled;
+
CurrentModule.clear();
}
diff --git a/lib/Basic/Module.cpp b/lib/Basic/Module.cpp
index 76c7f8b..13518cd 100644
--- a/lib/Basic/Module.cpp
+++ b/lib/Basic/Module.cpp
@@ -1,4 +1,4 @@
-//===--- Module.h - Describe a module ---------------------------*- C++ -*-===//
+//===--- Module.cpp - Describe a module -----------------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -15,10 +15,11 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetInfo.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/raw_ostream.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
@@ -27,7 +28,8 @@ Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
Umbrella(), ASTFile(0), IsAvailable(true), IsFromModuleFile(false),
IsFramework(IsFramework), IsExplicit(IsExplicit), IsSystem(false),
InferSubmodules(false), InferExplicitSubmodules(false),
- InferExportWildcard(false), NameVisibility(Hidden)
+ InferExportWildcard(false), ConfigMacrosExhaustive(false),
+ NameVisibility(Hidden)
{
if (Parent) {
if (!Parent->isAvailable())
@@ -45,7 +47,6 @@ Module::~Module() {
I != IEnd; ++I) {
delete *I;
}
-
}
/// \brief Determine whether a translation unit built using the current
@@ -56,7 +57,7 @@ static bool hasFeature(StringRef Feature, const LangOptions &LangOpts,
.Case("altivec", LangOpts.AltiVec)
.Case("blocks", LangOpts.Blocks)
.Case("cplusplus", LangOpts.CPlusPlus)
- .Case("cplusplus11", LangOpts.CPlusPlus0x)
+ .Case("cplusplus11", LangOpts.CPlusPlus11)
.Case("objc", LangOpts.ObjC1)
.Case("objc_arc", LangOpts.ObjCAutoRefCount)
.Case("opencl", LangOpts.OpenCL)
@@ -103,15 +104,15 @@ const Module *Module::getTopLevelModule() const {
}
std::string Module::getFullModuleName() const {
- llvm::SmallVector<StringRef, 2> Names;
+ SmallVector<StringRef, 2> Names;
// Build up the set of module names (from innermost to outermost).
for (const Module *M = this; M; M = M->Parent)
Names.push_back(M->Name);
std::string Result;
- for (llvm::SmallVector<StringRef, 2>::reverse_iterator I = Names.rbegin(),
- IEnd = Names.rend();
+ for (SmallVector<StringRef, 2>::reverse_iterator I = Names.rbegin(),
+ IEnd = Names.rend();
I != IEnd; ++I) {
if (!Result.empty())
Result += '.';
@@ -129,6 +130,19 @@ const DirectoryEntry *Module::getUmbrellaDir() const {
return Umbrella.dyn_cast<const DirectoryEntry *>();
}
+ArrayRef<const FileEntry *> Module::getTopHeaders(FileManager &FileMgr) {
+ if (!TopHeaderNames.empty()) {
+ for (std::vector<std::string>::iterator
+ I = TopHeaderNames.begin(), E = TopHeaderNames.end(); I != E; ++I) {
+ if (const FileEntry *FE = FileMgr.getFile(*I))
+ TopHeaders.insert(FE);
+ }
+ TopHeaderNames.clear();
+ }
+
+ return llvm::makeArrayRef(TopHeaders.begin(), TopHeaders.end());
+}
+
void Module::addRequirement(StringRef Feature, const LangOptions &LangOpts,
const TargetInfo &Target) {
Requires.push_back(Feature);
@@ -140,7 +154,7 @@ void Module::addRequirement(StringRef Feature, const LangOptions &LangOpts,
if (!IsAvailable)
return;
- llvm::SmallVector<Module *, 2> Stack;
+ SmallVector<Module *, 2> Stack;
Stack.push_back(this);
while (!Stack.empty()) {
Module *Current = Stack.back();
@@ -167,7 +181,7 @@ Module *Module::findSubmodule(StringRef Name) const {
return SubModules[Pos->getValue()];
}
-static void printModuleId(llvm::raw_ostream &OS, const ModuleId &Id) {
+static void printModuleId(raw_ostream &OS, const ModuleId &Id) {
for (unsigned I = 0, N = Id.size(); I != N; ++I) {
if (I)
OS << ".";
@@ -175,7 +189,60 @@ static void printModuleId(llvm::raw_ostream &OS, const ModuleId &Id) {
}
}
-void Module::print(llvm::raw_ostream &OS, unsigned Indent) const {
+void Module::getExportedModules(SmallVectorImpl<Module *> &Exported) const {
+ bool AnyWildcard = false;
+ bool UnrestrictedWildcard = false;
+ SmallVector<Module *, 4> WildcardRestrictions;
+ for (unsigned I = 0, N = Exports.size(); I != N; ++I) {
+ Module *Mod = Exports[I].getPointer();
+ if (!Exports[I].getInt()) {
+ // Export a named module directly; no wildcards involved.
+ Exported.push_back(Mod);
+
+ continue;
+ }
+
+ // Wildcard export: export all of the imported modules that match
+ // the given pattern.
+ AnyWildcard = true;
+ if (UnrestrictedWildcard)
+ continue;
+
+ if (Module *Restriction = Exports[I].getPointer())
+ WildcardRestrictions.push_back(Restriction);
+ else {
+ WildcardRestrictions.clear();
+ UnrestrictedWildcard = true;
+ }
+ }
+
+ // If there were any wildcards, push any imported modules that were
+ // re-exported by the wildcard restriction.
+ if (!AnyWildcard)
+ return;
+
+ for (unsigned I = 0, N = Imports.size(); I != N; ++I) {
+ Module *Mod = Imports[I];
+ bool Acceptable = UnrestrictedWildcard;
+ if (!Acceptable) {
+ // Check whether this module meets one of the restrictions.
+ for (unsigned R = 0, NR = WildcardRestrictions.size(); R != NR; ++R) {
+ Module *Restriction = WildcardRestrictions[R];
+ if (Mod == Restriction || Mod->isSubModuleOf(Restriction)) {
+ Acceptable = true;
+ break;
+ }
+ }
+ }
+
+ if (!Acceptable)
+ continue;
+
+ Exported.push_back(Mod);
+ }
+}
+
+void Module::print(raw_ostream &OS, unsigned Indent) const {
OS.indent(Indent);
if (IsFramework)
OS << "framework ";
@@ -212,7 +279,20 @@ void Module::print(llvm::raw_ostream &OS, unsigned Indent) const {
OS.write_escaped(UmbrellaDir->getName());
OS << "\"\n";
}
-
+
+ if (!ConfigMacros.empty() || ConfigMacrosExhaustive) {
+ OS.indent(Indent + 2);
+ OS << "config_macros ";
+ if (ConfigMacrosExhaustive)
+ OS << "[exhaustive]";
+ for (unsigned I = 0, N = ConfigMacros.size(); I != N; ++I) {
+ if (I)
+ OS << ", ";
+ OS << ConfigMacros[I];
+ }
+ OS << "\n";
+ }
+
for (unsigned I = 0, N = Headers.size(); I != N; ++I) {
OS.indent(Indent + 2);
OS << "header \"";
@@ -257,6 +337,34 @@ void Module::print(llvm::raw_ostream &OS, unsigned Indent) const {
OS << "\n";
}
+ for (unsigned I = 0, N = LinkLibraries.size(); I != N; ++I) {
+ OS.indent(Indent + 2);
+ OS << "link ";
+ if (LinkLibraries[I].IsFramework)
+ OS << "framework ";
+ OS << "\"";
+ OS.write_escaped(LinkLibraries[I].Library);
+ OS << "\"";
+ }
+
+ for (unsigned I = 0, N = UnresolvedConflicts.size(); I != N; ++I) {
+ OS.indent(Indent + 2);
+ OS << "conflict ";
+ printModuleId(OS, UnresolvedConflicts[I].Id);
+ OS << ", \"";
+ OS.write_escaped(UnresolvedConflicts[I].Message);
+ OS << "\"\n";
+ }
+
+ for (unsigned I = 0, N = Conflicts.size(); I != N; ++I) {
+ OS.indent(Indent + 2);
+ OS << "conflict ";
+ OS << Conflicts[I].Other->getFullModuleName();
+ OS << ", \"";
+ OS.write_escaped(Conflicts[I].Message);
+ OS << "\"\n";
+ }
+
if (InferSubmodules) {
OS.indent(Indent + 2);
if (InferExplicitSubmodules)
diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp
new file mode 100644
index 0000000..835908d
--- /dev/null
+++ b/lib/Basic/OpenMPKinds.cpp
@@ -0,0 +1,43 @@
+//===--- OpenMPKinds.cpp - Token Kinds Support ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// \brief This file implements the OpenMP enum and support functions.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/OpenMPKinds.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <cassert>
+
+using namespace clang;
+
+OpenMPDirectiveKind clang::getOpenMPDirectiveKind(StringRef Str) {
+ return llvm::StringSwitch<OpenMPDirectiveKind>(Str)
+#define OPENMP_DIRECTIVE(Name) \
+ .Case(#Name, OMPD_##Name)
+#include "clang/Basic/OpenMPKinds.def"
+ .Default(OMPD_unknown);
+}
+
+const char *clang::getOpenMPDirectiveName(OpenMPDirectiveKind Kind) {
+ assert(Kind < NUM_OPENMP_DIRECTIVES);
+ switch (Kind) {
+ case OMPD_unknown:
+ return ("unknown");
+#define OPENMP_DIRECTIVE(Name) \
+ case OMPD_##Name : return #Name;
+#include "clang/Basic/OpenMPKinds.def"
+ default:
+ break;
+ }
+ llvm_unreachable("Invalid OpenMP directive kind");
+}
diff --git a/lib/Basic/OperatorPrecedence.cpp b/lib/Basic/OperatorPrecedence.cpp
new file mode 100644
index 0000000..f9de231
--- /dev/null
+++ b/lib/Basic/OperatorPrecedence.cpp
@@ -0,0 +1,76 @@
+//===--- OperatorPrecedence.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Defines and computes precedence levels for binary/ternary operators.
+///
+//===----------------------------------------------------------------------===//
+#include "clang/Basic/OperatorPrecedence.h"
+
+namespace clang {
+
+prec::Level getBinOpPrecedence(tok::TokenKind Kind, bool GreaterThanIsOperator,
+ bool CPlusPlus11) {
+ switch (Kind) {
+ case tok::greater:
+ // C++ [temp.names]p3:
+ // [...] When parsing a template-argument-list, the first
+ // non-nested > is taken as the ending delimiter rather than a
+ // greater-than operator. [...]
+ if (GreaterThanIsOperator)
+ return prec::Relational;
+ return prec::Unknown;
+
+ case tok::greatergreater:
+ // C++0x [temp.names]p3:
+ //
+ // [...] Similarly, the first non-nested >> is treated as two
+ // consecutive but distinct > tokens, the first of which is
+ // taken as the end of the template-argument-list and completes
+ // the template-id. [...]
+ if (GreaterThanIsOperator || !CPlusPlus11)
+ return prec::Shift;
+ return prec::Unknown;
+
+ default: return prec::Unknown;
+ case tok::comma: return prec::Comma;
+ case tok::equal:
+ case tok::starequal:
+ case tok::slashequal:
+ case tok::percentequal:
+ case tok::plusequal:
+ case tok::minusequal:
+ case tok::lesslessequal:
+ case tok::greatergreaterequal:
+ case tok::ampequal:
+ case tok::caretequal:
+ case tok::pipeequal: return prec::Assignment;
+ case tok::question: return prec::Conditional;
+ case tok::pipepipe: return prec::LogicalOr;
+ case tok::ampamp: return prec::LogicalAnd;
+ case tok::pipe: return prec::InclusiveOr;
+ case tok::caret: return prec::ExclusiveOr;
+ case tok::amp: return prec::And;
+ case tok::exclaimequal:
+ case tok::equalequal: return prec::Equality;
+ case tok::lessequal:
+ case tok::less:
+ case tok::greaterequal: return prec::Relational;
+ case tok::lessless: return prec::Shift;
+ case tok::plus:
+ case tok::minus: return prec::Additive;
+ case tok::percent:
+ case tok::slash:
+ case tok::star: return prec::Multiplicative;
+ case tok::periodstar:
+ case tok::arrowstar: return prec::PointerToMember;
+ }
+}
+
+} // namespace clang
diff --git a/lib/Basic/SourceLocation.cpp b/lib/Basic/SourceLocation.cpp
index 0d62f7b..1822091 100644
--- a/lib/Basic/SourceLocation.cpp
+++ b/lib/Basic/SourceLocation.cpp
@@ -65,7 +65,7 @@ std::string SourceLocation::printToString(const SourceManager &SM) const {
std::string S;
llvm::raw_string_ostream OS(S);
print(OS, SM);
- return S;
+ return OS.str();
}
void SourceLocation::dump(const SourceManager &SM) const {
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index cd0284a..1b8383b 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -12,20 +12,20 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/SourceManagerInternals.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
-#include "llvm/ADT/StringSwitch.h"
+#include "clang/Basic/SourceManagerInternals.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Capacity.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Path.h"
-#include "llvm/Support/Capacity.h"
+#include "llvm/Support/raw_ostream.h"
#include <algorithm>
-#include <string>
#include <cstring>
+#include <string>
#include <sys/stat.h>
using namespace clang;
@@ -721,7 +721,7 @@ FileID SourceManager::getFileIDLocal(unsigned SLocOffset) const {
// See if this is near the file point - worst case we start scanning from the
// most newly created FileID.
- std::vector<SrcMgr::SLocEntry>::const_iterator I;
+ const SrcMgr::SLocEntry *I;
if (LastFileIDLookup.ID < 0 ||
LocalSLocEntryTable[LastFileIDLookup.ID].getOffset() < SLocOffset) {
@@ -840,10 +840,17 @@ FileID SourceManager::getFileIDLoaded(unsigned SLocOffset) const {
++NumProbes;
unsigned MiddleIndex = (LessIndex - GreaterIndex) / 2 + GreaterIndex;
const SrcMgr::SLocEntry &E = getLoadedSLocEntry(MiddleIndex);
+ if (E.getOffset() == 0)
+ return FileID(); // invalid entry.
++NumProbes;
if (E.getOffset() > SLocOffset) {
+ // Sanity checking, otherwise a bug may lead to hanging in release build.
+ if (GreaterIndex == MiddleIndex) {
+ assert(0 && "binary search missed the entry");
+ return FileID();
+ }
GreaterIndex = MiddleIndex;
continue;
}
@@ -856,6 +863,11 @@ FileID SourceManager::getFileIDLoaded(unsigned SLocOffset) const {
return Res;
}
+ // Sanity checking, otherwise a bug may lead to hanging in release build.
+ if (LessIndex == MiddleIndex) {
+ assert(0 && "binary search missed the entry");
+ return FileID();
+ }
LessIndex = MiddleIndex;
}
}
@@ -974,11 +986,18 @@ bool SourceManager::isMacroArgExpansion(SourceLocation Loc) const {
if (!Loc.isMacroID()) return false;
FileID FID = getFileID(Loc);
- const SrcMgr::SLocEntry *E = &getSLocEntry(FID);
- const SrcMgr::ExpansionInfo &Expansion = E->getExpansion();
+ const SrcMgr::ExpansionInfo &Expansion = getSLocEntry(FID).getExpansion();
return Expansion.isMacroArgExpansion();
}
+bool SourceManager::isMacroBodyExpansion(SourceLocation Loc) const {
+ if (!Loc.isMacroID()) return false;
+
+ FileID FID = getFileID(Loc);
+ const SrcMgr::ExpansionInfo &Expansion = getSLocEntry(FID).getExpansion();
+ return Expansion.isMacroBodyExpansion();
+}
+
//===----------------------------------------------------------------------===//
// Queries about the code at a SourceLocation.
@@ -1032,7 +1051,8 @@ unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos,
// See if we just calculated the line number for this FilePos and can use
// that to lookup the start of the line instead of searching for it.
if (LastLineNoFileIDQuery == FID &&
- LastLineNoContentCache->SourceLineCache != 0) {
+ LastLineNoContentCache->SourceLineCache != 0 &&
+ LastLineNoResult < LastLineNoContentCache->NumLines) {
unsigned *SourceLineCache = LastLineNoContentCache->SourceLineCache;
unsigned LineStart = SourceLineCache[LastLineNoResult - 1];
unsigned LineEnd = SourceLineCache[LastLineNoResult];
@@ -1361,7 +1381,8 @@ const char *SourceManager::getBufferName(SourceLocation Loc,
///
/// Note that a presumed location is always given as the expansion point of an
/// expansion location, not at the spelling location.
-PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const {
+PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc,
+ bool UseLineDirectives) const {
if (Loc.isInvalid()) return PresumedLoc();
// Presumed locations are always for expansion points.
@@ -1395,7 +1416,7 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const {
// If we have #line directives in this file, update and overwrite the physical
// location info if appropriate.
- if (FI.hasLineDirectives()) {
+ if (UseLineDirectives && FI.hasLineDirectives()) {
assert(LineTable && "Can't have linetable entries without a LineTable!");
// See if there is a #line directive before this. If so, get it.
if (const LineEntry *Entry =
@@ -1451,13 +1472,13 @@ unsigned SourceManager::getFileIDSize(FileID FID) const {
///
/// This routine involves a system call, and therefore should only be used
/// in non-performance-critical code.
-static llvm::Optional<ino_t> getActualFileInode(const FileEntry *File) {
+static Optional<ino_t> getActualFileInode(const FileEntry *File) {
if (!File)
- return llvm::Optional<ino_t>();
+ return None;
struct stat StatBuf;
if (::stat(File->getName(), &StatBuf))
- return llvm::Optional<ino_t>();
+ return None;
return StatBuf.st_ino;
}
@@ -1488,8 +1509,8 @@ FileID SourceManager::translateFile(const FileEntry *SourceFile) const {
// First, check the main file ID, since it is common to look for a
// location in the main file.
- llvm::Optional<ino_t> SourceFileInode;
- llvm::Optional<StringRef> SourceFileName;
+ Optional<ino_t> SourceFileInode;
+ Optional<StringRef> SourceFileName;
if (!MainFileID.isInvalid()) {
bool Invalid = false;
const SLocEntry &MainSLoc = getSLocEntry(MainFileID, &Invalid);
@@ -1511,8 +1532,7 @@ FileID SourceManager::translateFile(const FileEntry *SourceFile) const {
if (*SourceFileName == llvm::sys::path::filename(MainFile->getName())) {
SourceFileInode = getActualFileInode(SourceFile);
if (SourceFileInode) {
- if (llvm::Optional<ino_t> MainFileInode
- = getActualFileInode(MainFile)) {
+ if (Optional<ino_t> MainFileInode = getActualFileInode(MainFile)) {
if (*SourceFileInode == *MainFileInode) {
FirstFID = MainFileID;
SourceFile = MainFile;
@@ -1576,7 +1596,7 @@ FileID SourceManager::translateFile(const FileEntry *SourceFile) const {
const FileEntry *Entry =FileContentCache? FileContentCache->OrigEntry : 0;
if (Entry &&
*SourceFileName == llvm::sys::path::filename(Entry->getName())) {
- if (llvm::Optional<ino_t> EntryInode = getActualFileInode(Entry)) {
+ if (Optional<ino_t> EntryInode = getActualFileInode(Entry)) {
if (*SourceFileInode == *EntryInode) {
FirstFID = FileID::get(I);
SourceFile = Entry;
@@ -1847,7 +1867,32 @@ static bool MoveUpIncludeHierarchy(std::pair<FileID, unsigned> &Loc,
Loc = SM.getDecomposedLoc(UpperLoc);
return false;
}
-
+
+/// Return the cache entry for comparing the given file IDs
+/// for isBeforeInTranslationUnit.
+InBeforeInTUCacheEntry &SourceManager::getInBeforeInTUCache(FileID LFID,
+ FileID RFID) const {
+ // This is a magic number for limiting the cache size. It was experimentally
+ // derived from a small Objective-C project (where the cache filled
+ // out to ~250 items). We can make it larger if necessary.
+ enum { MagicCacheSize = 300 };
+ IsBeforeInTUCacheKey Key(LFID, RFID);
+
+ // If the cache size isn't too large, do a lookup and if necessary default
+ // construct an entry. We can then return it to the caller for direct
+ // use. When they update the value, the cache will get automatically
+ // updated as well.
+ if (IBTUCache.size() < MagicCacheSize)
+ return IBTUCache[Key];
+
+ // Otherwise, do a lookup that will not construct a new value.
+ InBeforeInTUCache::iterator I = IBTUCache.find(Key);
+ if (I != IBTUCache.end())
+ return I->second;
+
+ // Fall back to the overflow value.
+ return IBTUCacheOverflow;
+}
/// \brief Determines the order of 2 source locations in the translation unit.
///
@@ -1867,6 +1912,11 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS,
// If we are comparing a source location with multiple locations in the same
// file, we get a big win by caching the result.
+ InBeforeInTUCacheEntry &IsBeforeInTUCache =
+ getInBeforeInTUCache(LOffs.first, ROffs.first);
+
+ // If we are comparing a source location with multiple locations in the same
+ // file, we get a big win by caching the result.
if (IsBeforeInTUCache.isCacheValid(LOffs.first, ROffs.first))
return IsBeforeInTUCache.getCachedResult(LOffs.second, ROffs.second);
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index 83d4e2b..70ea235 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -11,13 +11,13 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Basic/AddressSpaces.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/AddressSpaces.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/ErrorHandling.h"
-#include <cctype>
#include <cstdlib>
using namespace clang;
@@ -84,7 +84,7 @@ TargetInfo::TargetInfo(const std::string &T) : TargetOpts(), Triple(T)
ComplexLongDoubleUsesFP2Ret = false;
// Default to using the Itanium ABI.
- CXXABI = CXXABI_Itanium;
+ TheCXXABI.set(TargetCXXABI::GenericItanium);
// Default to an empty address space map.
AddrSpaceMap = &DefaultAddrSpaceMap;
@@ -223,7 +223,7 @@ bool TargetInfo::isValidGCCRegisterName(StringRef Name) const {
getGCCRegNames(Names, NumNames);
// If we have a number it maps to an entry in the register name array.
- if (isdigit(Name[0])) {
+ if (isDigit(Name[0])) {
int n;
if (!Name.getAsInteger(0, n))
return n >= 0 && (unsigned)n < NumNames;
@@ -279,7 +279,7 @@ TargetInfo::getNormalizedGCCRegisterName(StringRef Name) const {
getGCCRegNames(Names, NumNames);
// First, check if we have a number.
- if (isdigit(Name[0])) {
+ if (isDigit(Name[0])) {
int n;
if (!Name.getAsInteger(0, n)) {
assert(n >= 0 && (unsigned)n < NumNames &&
@@ -496,3 +496,17 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints,
return true;
}
+
+bool TargetCXXABI::tryParse(llvm::StringRef name) {
+ const Kind unknown = static_cast<Kind>(-1);
+ Kind kind = llvm::StringSwitch<Kind>(name)
+ .Case("arm", GenericARM)
+ .Case("ios", iOS)
+ .Case("itanium", GenericItanium)
+ .Case("microsoft", Microsoft)
+ .Default(unknown);
+ if (kind == unknown) return false;
+
+ set(kind);
+ return true;
+}
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index f36ef82..3eda9d8 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -25,9 +25,9 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/IR/Type.h"
#include "llvm/MC/MCSectionMachO.h"
#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Type.h"
#include <algorithm>
using namespace clang;
@@ -94,7 +94,7 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts,
Builder.defineMacro("OBJC_NEW_PROPERTIES");
// AddressSanitizer doesn't play well with source fortification, which is on
// by default on Darwin.
- if (Opts.SanitizeAddress) Builder.defineMacro("_FORTIFY_SOURCE", "0");
+ if (Opts.Sanitize.Address) Builder.defineMacro("_FORTIFY_SOURCE", "0");
if (!Opts.ObjCAutoRefCount) {
// __weak is always defined, for use in blocks and with objc pointers.
@@ -384,13 +384,13 @@ public:
case llvm::Triple::x86:
case llvm::Triple::x86_64:
case llvm::Triple::arm:
- case llvm::Triple::sparc:
+ case llvm::Triple::sparc:
this->MCountName = "__mcount";
break;
case llvm::Triple::mips64:
case llvm::Triple::mips64el:
case llvm::Triple::ppc:
- case llvm::Triple::sparcv9:
+ case llvm::Triple::sparcv9:
this->MCountName = "_mcount";
break;
}
@@ -575,7 +575,7 @@ protected:
if (Opts.MicrosoftExt) {
Builder.defineMacro("_MSC_EXTENSIONS");
- if (Opts.CPlusPlus0x) {
+ if (Opts.CPlusPlus11) {
Builder.defineMacro("_RVALUE_REFERENCES_V2_SUPPORTED");
Builder.defineMacro("_RVALUE_REFERENCES_SUPPORTED");
Builder.defineMacro("_NATIVE_NULLPTR_SUPPORTED");
@@ -661,9 +661,19 @@ public:
ArchDefine603 = 1 << 4,
ArchDefine604 = 1 << 5,
ArchDefinePwr4 = 1 << 6,
- ArchDefinePwr6 = 1 << 7
+ ArchDefinePwr5 = 1 << 7,
+ ArchDefinePwr5x = 1 << 8,
+ ArchDefinePwr6 = 1 << 9,
+ ArchDefinePwr6x = 1 << 10,
+ ArchDefinePwr7 = 1 << 11,
+ ArchDefineA2 = 1 << 12,
+ ArchDefineA2q = 1 << 13
} ArchDefineTypes;
+ // Note: GCC recognizes the following additional cpus:
+ // 401, 403, 405, 405fp, 440fp, 464, 464fp, 476, 476fp, 505, 740, 801,
+ // 821, 823, 8540, 8548, e300c2, e300c3, e500mc64, e6500, 860, cell,
+ // titan, rs64.
virtual bool setCPU(const std::string &Name) {
bool CPUKnown = llvm::StringSwitch<bool>(Name)
.Case("generic", true)
@@ -677,6 +687,7 @@ public:
.Case("604", true)
.Case("604e", true)
.Case("620", true)
+ .Case("630", true)
.Case("g3", true)
.Case("7400", true)
.Case("g4", true)
@@ -686,11 +697,26 @@ public:
.Case("970", true)
.Case("g5", true)
.Case("a2", true)
+ .Case("a2q", true)
.Case("e500mc", true)
.Case("e5500", true)
+ .Case("power3", true)
+ .Case("pwr3", true)
+ .Case("power4", true)
+ .Case("pwr4", true)
+ .Case("power5", true)
+ .Case("pwr5", true)
+ .Case("power5x", true)
+ .Case("pwr5x", true)
+ .Case("power6", true)
.Case("pwr6", true)
+ .Case("power6x", true)
+ .Case("pwr6x", true)
+ .Case("power7", true)
.Case("pwr7", true)
+ .Case("powerpc", true)
.Case("ppc", true)
+ .Case("powerpc64", true)
.Case("ppc64", true)
.Default(false);
@@ -711,6 +737,12 @@ public:
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const;
+ virtual void getDefaultFeatures(llvm::StringMap<bool> &Features) const;
+
+ virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
+ StringRef Name,
+ bool Enabled) const;
+
virtual bool hasFeature(StringRef Feature) const;
virtual void getGCCRegNames(const char * const *&Names,
@@ -818,6 +850,11 @@ public:
virtual const char *getClobbers() const {
return "";
}
+ int getEHDataRegisterNumber(unsigned RegNo) const {
+ if (RegNo == 0) return 3;
+ if (RegNo == 1) return 4;
+ return -1;
+ }
};
const Builtin::Info PPCTargetInfo::BuiltinInfo[] = {
@@ -875,14 +912,42 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
.Case("604", ArchDefineName | ArchDefinePpcgr)
.Case("604e", ArchDefineName | ArchDefine604 | ArchDefinePpcgr)
.Case("620", ArchDefineName | ArchDefinePpcgr)
+ .Case("630", ArchDefineName | ArchDefinePpcgr)
.Case("7400", ArchDefineName | ArchDefinePpcgr)
.Case("7450", ArchDefineName | ArchDefinePpcgr)
.Case("750", ArchDefineName | ArchDefinePpcgr)
.Case("970", ArchDefineName | ArchDefinePwr4 | ArchDefinePpcgr
| ArchDefinePpcsq)
- .Case("pwr6", ArchDefinePwr6 | ArchDefinePpcgr | ArchDefinePpcsq)
- .Case("pwr7", ArchDefineName | ArchDefinePwr6 | ArchDefinePpcgr
+ .Case("a2", ArchDefineA2)
+ .Case("a2q", ArchDefineName | ArchDefineA2 | ArchDefineA2q)
+ .Case("pwr3", ArchDefinePpcgr)
+ .Case("pwr4", ArchDefineName | ArchDefinePpcgr | ArchDefinePpcsq)
+ .Case("pwr5", ArchDefineName | ArchDefinePwr4 | ArchDefinePpcgr
| ArchDefinePpcsq)
+ .Case("pwr5x", ArchDefineName | ArchDefinePwr5 | ArchDefinePwr4
+ | ArchDefinePpcgr | ArchDefinePpcsq)
+ .Case("pwr6", ArchDefineName | ArchDefinePwr5x | ArchDefinePwr5
+ | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq)
+ .Case("pwr6x", ArchDefineName | ArchDefinePwr6 | ArchDefinePwr5x
+ | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr
+ | ArchDefinePpcsq)
+ .Case("pwr7", ArchDefineName | ArchDefinePwr6x | ArchDefinePwr6
+ | ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4
+ | ArchDefinePwr6 | ArchDefinePpcgr | ArchDefinePpcsq)
+ .Case("power3", ArchDefinePpcgr)
+ .Case("power4", ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq)
+ .Case("power5", ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr
+ | ArchDefinePpcsq)
+ .Case("power5x", ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4
+ | ArchDefinePpcgr | ArchDefinePpcsq)
+ .Case("power6", ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5
+ | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq)
+ .Case("power6x", ArchDefinePwr6x | ArchDefinePwr6 | ArchDefinePwr5x
+ | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr
+ | ArchDefinePpcsq)
+ .Case("power7", ArchDefinePwr7 | ArchDefinePwr6x | ArchDefinePwr6
+ | ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4
+ | ArchDefinePwr6 | ArchDefinePpcgr | ArchDefinePpcsq)
.Default(ArchDefineNone);
if (defs & ArchDefineName)
@@ -897,12 +962,80 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("_ARCH_603");
if (defs & ArchDefine604)
Builder.defineMacro("_ARCH_604");
- if (defs & (ArchDefinePwr4 | ArchDefinePwr6))
+ if (defs & ArchDefinePwr4)
Builder.defineMacro("_ARCH_PWR4");
- if (defs & ArchDefinePwr6) {
+ if (defs & ArchDefinePwr5)
Builder.defineMacro("_ARCH_PWR5");
+ if (defs & ArchDefinePwr5x)
+ Builder.defineMacro("_ARCH_PWR5X");
+ if (defs & ArchDefinePwr6)
Builder.defineMacro("_ARCH_PWR6");
+ if (defs & ArchDefinePwr6x)
+ Builder.defineMacro("_ARCH_PWR6X");
+ if (defs & ArchDefinePwr7)
+ Builder.defineMacro("_ARCH_PWR7");
+ if (defs & ArchDefineA2)
+ Builder.defineMacro("_ARCH_A2");
+ if (defs & ArchDefineA2q) {
+ Builder.defineMacro("_ARCH_A2Q");
+ Builder.defineMacro("_ARCH_QP");
+ }
+
+ if (getTriple().getVendor() == llvm::Triple::BGQ) {
+ Builder.defineMacro("__bg__");
+ Builder.defineMacro("__THW_BLUEGENE__");
+ Builder.defineMacro("__bgq__");
+ Builder.defineMacro("__TOS_BGQ__");
+ }
+
+ // FIXME: The following are not yet generated here by Clang, but are
+ // generated by GCC:
+ //
+ // _SOFT_FLOAT_
+ // __RECIP_PRECISION__
+ // __APPLE_ALTIVEC__
+ // __VSX__
+ // __RECIP__
+ // __RECIPF__
+ // __RSQRTE__
+ // __RSQRTEF__
+ // _SOFT_DOUBLE_
+ // __NO_LWSYNC__
+ // __HAVE_BSWAP__
+ // __LONGDOUBLE128
+ // __CMODEL_MEDIUM__
+ // __CMODEL_LARGE__
+ // _CALL_SYSV
+ // _CALL_DARWIN
+ // __NO_FPRS__
+}
+
+void PPCTargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
+ Features["altivec"] = llvm::StringSwitch<bool>(CPU)
+ .Case("7400", true)
+ .Case("g4", true)
+ .Case("7450", true)
+ .Case("g4+", true)
+ .Case("970", true)
+ .Case("g5", true)
+ .Case("pwr6", true)
+ .Case("pwr7", true)
+ .Case("ppc64", true)
+ .Default(false);
+
+ Features["qpx"] = (CPU == "a2q");
+}
+
+bool PPCTargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
+ StringRef Name,
+ bool Enabled) const {
+ if (Name == "altivec" || Name == "fprnd" || Name == "mfocrf" ||
+ Name == "popcntd" || Name == "qpx") {
+ Features[Name] = Enabled;
+ return true;
}
+
+ return false;
}
bool PPCTargetInfo::hasFeature(StringRef Feature) const {
@@ -1122,7 +1255,7 @@ namespace {
class NVPTXTargetInfo : public TargetInfo {
static const char * const GCCRegNames[];
static const Builtin::Info BuiltinInfo[];
- std::vector<llvm::StringRef> AvailableFeatures;
+ std::vector<StringRef> AvailableFeatures;
public:
NVPTXTargetInfo(const std::string& triple) : TargetInfo(triple) {
BigEndian = false;
@@ -1169,7 +1302,14 @@ namespace {
return TargetInfo::CharPtrBuiltinVaList;
}
virtual bool setCPU(const std::string &Name) {
- return Name == "sm_10" || Name == "sm_13" || Name == "sm_20";
+ bool Valid = llvm::StringSwitch<bool>(Name)
+ .Case("sm_20", true)
+ .Case("sm_21", true)
+ .Case("sm_30", true)
+ .Case("sm_35", true)
+ .Default(false);
+
+ return Valid;
}
virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
StringRef Name,
@@ -1241,16 +1381,50 @@ static const unsigned R600AddrSpaceMap[] = {
3 // cuda_shared
};
+static const char *DescriptionStringR600 =
+ "e"
+ "-p:32:32:32"
+ "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32"
+ "-v16:16:16-v24:32:32-v32:32:32-v48:64:64-v64:64:64-v96:128:128-v128:128:128"
+ "-v192:256:256-v256:256:256-v512:512:512-v1024:1024:1024-v2048:2048:2048"
+ "-n32:64";
+
+static const char *DescriptionStringR600DoubleOps =
+ "e"
+ "-p:32:32:32"
+ "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64"
+ "-v16:16:16-v24:32:32-v32:32:32-v48:64:64-v64:64:64-v96:128:128-v128:128:128"
+ "-v192:256:256-v256:256:256-v512:512:512-v1024:1024:1024-v2048:2048:2048"
+ "-n32:64";
+
+static const char *DescriptionStringSI =
+ "e"
+ "-p:64:64:64"
+ "-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64"
+ "-v16:16:16-v24:32:32-v32:32:32-v48:64:64-v64:64:64-v96:128:128-v128:128:128"
+ "-v192:256:256-v256:256:256-v512:512:512-v1024:1024:1024-v2048:2048:2048"
+ "-n32:64";
+
class R600TargetInfo : public TargetInfo {
+ /// \brief The GPU profiles supported by the R600 target.
+ enum GPUKind {
+ GK_NONE,
+ GK_R600,
+ GK_R600_DOUBLE_OPS,
+ GK_R700,
+ GK_R700_DOUBLE_OPS,
+ GK_EVERGREEN,
+ GK_EVERGREEN_DOUBLE_OPS,
+ GK_NORTHERN_ISLANDS,
+ GK_CAYMAN,
+ GK_SOUTHERN_ISLANDS
+ } GPU;
+
public:
- R600TargetInfo(const std::string& triple) : TargetInfo(triple) {
- DescriptionString =
- "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16"
- "-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f80:32:32"
- "-v16:16:16-v24:32:32-v32:32:32-v48:64:64-v64:64:64"
- "-v96:128:128-v128:128:128-v192:256:256-v256:256:256"
- "-v512:512:512-v1024:1024:1024-v2048:2048:2048"
- "-n8:16:32:64";
+ R600TargetInfo(const std::string& triple)
+ : TargetInfo(triple),
+ GPU(GK_R600) {
+ DescriptionString = DescriptionStringR600;
AddrSpaceMap = &R600AddrSpaceMap;
}
@@ -1291,6 +1465,65 @@ public:
return TargetInfo::CharPtrBuiltinVaList;
}
+ virtual bool setCPU(const std::string &Name) {
+ GPU = llvm::StringSwitch<GPUKind>(Name)
+ .Case("r600" , GK_R600)
+ .Case("rv610", GK_R600)
+ .Case("rv620", GK_R600)
+ .Case("rv630", GK_R600)
+ .Case("rv635", GK_R600)
+ .Case("rs780", GK_R600)
+ .Case("rs880", GK_R600)
+ .Case("rv670", GK_R600_DOUBLE_OPS)
+ .Case("rv710", GK_R700)
+ .Case("rv730", GK_R700)
+ .Case("rv740", GK_R700_DOUBLE_OPS)
+ .Case("rv770", GK_R700_DOUBLE_OPS)
+ .Case("palm", GK_EVERGREEN)
+ .Case("cedar", GK_EVERGREEN)
+ .Case("sumo", GK_EVERGREEN)
+ .Case("sumo2", GK_EVERGREEN)
+ .Case("redwood", GK_EVERGREEN)
+ .Case("juniper", GK_EVERGREEN)
+ .Case("hemlock", GK_EVERGREEN_DOUBLE_OPS)
+ .Case("cypress", GK_EVERGREEN_DOUBLE_OPS)
+ .Case("barts", GK_NORTHERN_ISLANDS)
+ .Case("turks", GK_NORTHERN_ISLANDS)
+ .Case("caicos", GK_NORTHERN_ISLANDS)
+ .Case("cayman", GK_CAYMAN)
+ .Case("aruba", GK_CAYMAN)
+ .Case("tahiti", GK_SOUTHERN_ISLANDS)
+ .Case("pitcairn", GK_SOUTHERN_ISLANDS)
+ .Case("verde", GK_SOUTHERN_ISLANDS)
+ .Case("oland", GK_SOUTHERN_ISLANDS)
+ .Default(GK_NONE);
+
+ if (GPU == GK_NONE) {
+ return false;
+ }
+
+ // Set the correct data layout
+ switch (GPU) {
+ case GK_NONE:
+ case GK_R600:
+ case GK_R700:
+ case GK_EVERGREEN:
+ case GK_NORTHERN_ISLANDS:
+ DescriptionString = DescriptionStringR600;
+ break;
+ case GK_R600_DOUBLE_OPS:
+ case GK_R700_DOUBLE_OPS:
+ case GK_EVERGREEN_DOUBLE_OPS:
+ case GK_CAYMAN:
+ DescriptionString = DescriptionStringR600DoubleOps;
+ break;
+ case GK_SOUTHERN_ISLANDS:
+ DescriptionString = DescriptionStringSI;
+ break;
+ }
+
+ return true;
+ }
};
} // end anonymous namespace
@@ -1476,6 +1709,8 @@ class X86TargetInfo : public TargetInfo {
bool HasBMI2;
bool HasPOPCNT;
bool HasRTM;
+ bool HasPRFCHW;
+ bool HasRDSEED;
bool HasSSE4a;
bool HasFMA4;
bool HasFMA;
@@ -1627,8 +1862,8 @@ public:
: TargetInfo(triple), SSELevel(NoSSE), MMX3DNowLevel(NoMMX3DNow),
HasAES(false), HasPCLMUL(false), HasLZCNT(false), HasRDRND(false),
HasBMI(false), HasBMI2(false), HasPOPCNT(false), HasRTM(false),
- HasSSE4a(false), HasFMA4(false), HasFMA(false), HasXOP(false),
- HasF16C(false), CPU(CK_Generic) {
+ HasPRFCHW(false), HasRDSEED(false), HasSSE4a(false), HasFMA4(false),
+ HasFMA(false), HasXOP(false), HasF16C(false), CPU(CK_Generic) {
BigEndian = false;
LongDoubleFormat = &llvm::APFloat::x87DoubleExtended;
}
@@ -1652,7 +1887,7 @@ public:
NumAliases = 0;
}
virtual void getGCCAddlRegNames(const AddlRegName *&Names,
- unsigned &NumNames) const {
+ unsigned &NumNames) const {
Names = AddlRegNames;
NumNames = llvm::array_lengthof(AddlRegNames);
}
@@ -1803,11 +2038,12 @@ public:
CC == CC_X86FastCall ||
CC == CC_X86StdCall ||
CC == CC_C ||
- CC == CC_X86Pascal) ? CCCR_OK : CCCR_Warning;
+ CC == CC_X86Pascal ||
+ CC == CC_IntelOclBicc) ? CCCR_OK : CCCR_Warning;
}
- virtual CallingConv getDefaultCallingConv() const {
- return CC_C;
+ virtual CallingConv getDefaultCallingConv(CallingConvMethodType MT) const {
+ return MT == CCMT_Member ? CC_X86ThisCall : CC_C;
}
};
@@ -1833,6 +2069,8 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
Features["bmi2"] = false;
Features["popcnt"] = false;
Features["rtm"] = false;
+ Features["prfchw"] = false;
+ Features["rdseed"] = false;
Features["fma4"] = false;
Features["fma"] = false;
Features["xop"] = false;
@@ -1842,7 +2080,7 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
// X86_64 always has SSE2.
if (getTriple().getArch() == llvm::Triple::x86_64)
- Features["sse2"] = Features["sse"] = Features["mmx"] = true;
+ setFeatureEnabled(Features, "sse2", true);
switch (CPU) {
case CK_Generic:
@@ -1859,58 +2097,50 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
break;
case CK_Pentium3:
case CK_Pentium3M:
- setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "sse", true);
break;
case CK_PentiumM:
case CK_Pentium4:
case CK_Pentium4M:
case CK_x86_64:
- setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "sse2", true);
break;
case CK_Yonah:
case CK_Prescott:
case CK_Nocona:
- setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "sse3", true);
break;
case CK_Core2:
- setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "ssse3", true);
break;
case CK_Penryn:
- setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "sse4.1", true);
break;
case CK_Atom:
- setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "ssse3", true);
break;
case CK_Corei7:
- setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "sse4", true);
break;
case CK_Corei7AVX:
- setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "avx", true);
setFeatureEnabled(Features, "aes", true);
setFeatureEnabled(Features, "pclmul", true);
break;
case CK_CoreAVXi:
- setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "avx", true);
setFeatureEnabled(Features, "aes", true);
setFeatureEnabled(Features, "pclmul", true);
setFeatureEnabled(Features, "rdrnd", true);
+ setFeatureEnabled(Features, "f16c", true);
break;
case CK_CoreAVX2:
- setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "avx2", true);
setFeatureEnabled(Features, "aes", true);
setFeatureEnabled(Features, "pclmul", true);
setFeatureEnabled(Features, "lzcnt", true);
setFeatureEnabled(Features, "rdrnd", true);
+ setFeatureEnabled(Features, "f16c", true);
setFeatureEnabled(Features, "bmi", true);
setFeatureEnabled(Features, "bmi2", true);
setFeatureEnabled(Features, "rtm", true);
@@ -1954,20 +2184,31 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
setFeatureEnabled(Features, "sse3", true);
setFeatureEnabled(Features, "sse4a", true);
setFeatureEnabled(Features, "3dnowa", true);
+ setFeatureEnabled(Features, "lzcnt", true);
+ setFeatureEnabled(Features, "popcnt", true);
break;
case CK_BTVER1:
setFeatureEnabled(Features, "ssse3", true);
setFeatureEnabled(Features, "sse4a", true);
+ setFeatureEnabled(Features, "lzcnt", true);
+ setFeatureEnabled(Features, "popcnt", true);
break;
case CK_BDVER1:
+ setFeatureEnabled(Features, "xop", true);
+ setFeatureEnabled(Features, "lzcnt", true);
+ setFeatureEnabled(Features, "aes", true);
+ setFeatureEnabled(Features, "pclmul", true);
+ break;
case CK_BDVER2:
- setFeatureEnabled(Features, "avx", true);
setFeatureEnabled(Features, "xop", true);
+ setFeatureEnabled(Features, "lzcnt", true);
setFeatureEnabled(Features, "aes", true);
setFeatureEnabled(Features, "pclmul", true);
+ setFeatureEnabled(Features, "bmi", true);
+ setFeatureEnabled(Features, "fma", true);
+ setFeatureEnabled(Features, "f16c", true);
break;
case CK_C3_2:
- setFeatureEnabled(Features, "mmx", true);
setFeatureEnabled(Features, "sse", true);
break;
}
@@ -2026,12 +2267,12 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
Features["ssse3"] = Features["sse41"] = Features["sse42"] =
Features["popcnt"] = Features["avx"] = Features["fma"] = true;
else if (Name == "fma4")
- Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
+ Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
Features["ssse3"] = Features["sse41"] = Features["sse42"] =
Features["popcnt"] = Features["avx"] = Features["sse4a"] =
Features["fma4"] = true;
else if (Name == "xop")
- Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
+ Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] =
Features["ssse3"] = Features["sse41"] = Features["sse42"] =
Features["popcnt"] = Features["avx"] = Features["sse4a"] =
Features["fma4"] = Features["xop"] = true;
@@ -2052,6 +2293,10 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
Features["f16c"] = true;
else if (Name == "rtm")
Features["rtm"] = true;
+ else if (Name == "prfchw")
+ Features["prfchw"] = true;
+ else if (Name == "rdseed")
+ Features["rdseed"] = true;
} else {
if (Name == "mmx")
Features["mmx"] = Features["3dnow"] = Features["3dnowa"] = false;
@@ -2116,6 +2361,10 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
Features["f16c"] = false;
else if (Name == "rtm")
Features["rtm"] = false;
+ else if (Name == "prfchw")
+ Features["prfchw"] = false;
+ else if (Name == "rdseed")
+ Features["rdseed"] = false;
}
return true;
@@ -2172,6 +2421,16 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) {
continue;
}
+ if (Feature == "prfchw") {
+ HasPRFCHW = true;
+ continue;
+ }
+
+ if (Feature == "rdseed") {
+ HasRDSEED = true;
+ continue;
+ }
+
if (Feature == "sse4a") {
HasSSE4a = true;
continue;
@@ -2396,6 +2655,12 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
if (HasRTM)
Builder.defineMacro("__RTM__");
+ if (HasPRFCHW)
+ Builder.defineMacro("__PRFCHW__");
+
+ if (HasRDSEED)
+ Builder.defineMacro("__RDSEED__");
+
if (HasSSE4a)
Builder.defineMacro("__SSE4A__");
@@ -2465,6 +2730,14 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
case NoMMX3DNow:
break;
}
+
+ if (CPU >= CK_i486) {
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
+ }
+ if (CPU >= CK_i586)
+ Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
}
bool X86TargetInfo::hasFeature(StringRef Feature) const {
@@ -2484,6 +2757,8 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
.Case("pclmul", HasPCLMUL)
.Case("popcnt", HasPOPCNT)
.Case("rtm", HasRTM)
+ .Case("prfchw", HasPRFCHW)
+ .Case("rdseed", HasRDSEED)
.Case("sse", SSELevel >= SSE1)
.Case("sse2", SSELevel >= SSE2)
.Case("sse3", SSELevel >= SSE3)
@@ -2600,6 +2875,19 @@ public:
if (RegNo == 1) return 2;
return -1;
}
+ virtual bool validateInputSize(StringRef Constraint,
+ unsigned Size) const {
+ switch (Constraint[0]) {
+ default: break;
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ return Size <= 32;
+ }
+
+ return true;
+ }
};
} // end anonymous namespace
@@ -2747,6 +3035,7 @@ public:
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
X86_32TargetInfo::getTargetDefines(Opts, Builder);
+ Builder.defineMacro("_X86_");
Builder.defineMacro("__CYGWIN__");
Builder.defineMacro("__CYGWIN32__");
DefineStd(Builder, "unix", Opts);
@@ -2877,11 +3166,13 @@ public:
}
virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const {
- return TargetInfo::checkCallingConvention(CC);
+ return (CC == CC_Default ||
+ CC == CC_C ||
+ CC == CC_IntelOclBicc) ? CCCR_OK : CCCR_Warning;
}
- virtual CallingConv getDefaultCallingConv() const {
- return CC_Default;
+ virtual CallingConv getDefaultCallingConv(CallingConvMethodType MT) const {
+ return CC_C;
}
};
@@ -2995,6 +3286,190 @@ public:
Int64Type = SignedLongLong;
}
};
+}
+
+namespace {
+class AArch64TargetInfo : public TargetInfo {
+ static const char * const GCCRegNames[];
+ static const TargetInfo::GCCRegAlias GCCRegAliases[];
+public:
+ AArch64TargetInfo(const std::string& triple) : TargetInfo(triple) {
+ BigEndian = false;
+ LongWidth = LongAlign = 64;
+ LongDoubleWidth = LongDoubleAlign = 128;
+ PointerWidth = PointerAlign = 64;
+ SuitableAlign = 128;
+ DescriptionString = "e-p:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
+ "i64:64:64-i128:128:128-f32:32:32-f64:64:64-"
+ "f128:128:128-n32:64-S128";
+
+ WCharType = UnsignedInt;
+ LongDoubleFormat = &llvm::APFloat::IEEEquad;
+
+ // AArch64 backend supports 64-bit operations at the moment. In principle
+ // 128-bit is possible if register-pairs are used.
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
+
+ TheCXXABI.set(TargetCXXABI::GenericAArch64);
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ // GCC defines theses currently
+ Builder.defineMacro("__aarch64__");
+ Builder.defineMacro("__AARCH64EL__");
+
+ // ACLE predefines. Many can only have one possible value on v8 AArch64.
+
+ // FIXME: these were written based on an unreleased version of a 32-bit ACLE
+ // which was intended to be compatible with a 64-bit implementation. They
+ // will need updating when a real 64-bit ACLE exists. Particularly pressing
+ // instances are: __AARCH_ISA_A32, __AARCH_ISA_T32, __ARCH_PCS.
+ Builder.defineMacro("__AARCH_ACLE", "101");
+ Builder.defineMacro("__AARCH", "8");
+ Builder.defineMacro("__AARCH_PROFILE", "'A'");
+
+ Builder.defineMacro("__AARCH_FEATURE_UNALIGNED");
+ Builder.defineMacro("__AARCH_FEATURE_CLZ");
+ Builder.defineMacro("__AARCH_FEATURE_FMA");
+
+ // FIXME: ACLE 1.1 reserves bit 4. Will almost certainly come to mean
+ // 128-bit LDXP present, at which point this becomes 0x1f.
+ Builder.defineMacro("__AARCH_FEATURE_LDREX", "0xf");
+
+ // 0xe implies support for half, single and double precision operations.
+ Builder.defineMacro("__AARCH_FP", "0xe");
+
+ // PCS specifies this for SysV variants, which is all we support. Other ABIs
+ // may choose __AARCH_FP16_FORMAT_ALTERNATIVE.
+ Builder.defineMacro("__AARCH_FP16_FORMAT_IEEE");
+
+ if (Opts.FastMath || Opts.FiniteMathOnly)
+ Builder.defineMacro("__AARCH_FP_FAST");
+
+ if ((Opts.C99 || Opts.C11) && !Opts.Freestanding)
+ Builder.defineMacro("__AARCH_FP_FENV_ROUNDING");
+
+ Builder.defineMacro("__AARCH_SIZEOF_WCHAR_T",
+ Opts.ShortWChar ? "2" : "4");
+
+ Builder.defineMacro("__AARCH_SIZEOF_MINIMAL_ENUM",
+ Opts.ShortEnums ? "1" : "4");
+
+ if (BigEndian)
+ Builder.defineMacro("__AARCH_BIG_ENDIAN");
+ }
+ virtual void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const {
+ Records = 0;
+ NumRecords = 0;
+ }
+ virtual bool hasFeature(StringRef Feature) const {
+ return Feature == "aarch64";
+ }
+ virtual void getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const;
+ virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const;
+
+ virtual bool isCLZForZeroUndef() const { return false; }
+
+ virtual bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const {
+ switch (*Name) {
+ default: return false;
+ case 'w': // An FP/SIMD vector register
+ Info.setAllowsRegister();
+ return true;
+ case 'I': // Constant that can be used with an ADD instruction
+ case 'J': // Constant that can be used with a SUB instruction
+ case 'K': // Constant that can be used with a 32-bit logical instruction
+ case 'L': // Constant that can be used with a 64-bit logical instruction
+ case 'M': // Constant that can be used as a 32-bit MOV immediate
+ case 'N': // Constant that can be used as a 64-bit MOV immediate
+ case 'Y': // Floating point constant zero
+ case 'Z': // Integer constant zero
+ return true;
+ case 'Q': // A memory reference with base register and no offset
+ Info.setAllowsMemory();
+ return true;
+ case 'S': // A symbolic address
+ Info.setAllowsRegister();
+ return true;
+ case 'U':
+ // Ump: A memory address suitable for ldp/stp in SI, DI, SF and DF modes, whatever they may be
+ // Utf: A memory address suitable for ldp/stp in TF mode, whatever it may be
+ // Usa: An absolute symbolic address
+ // Ush: The high part (bits 32:12) of a pc-relative symbolic address
+ llvm_unreachable("FIXME: Unimplemented support for bizarre constraints");
+ }
+ }
+
+ virtual const char *getClobbers() const {
+ // There are no AArch64 clobbers shared by all asm statements.
+ return "";
+ }
+
+ virtual BuiltinVaListKind getBuiltinVaListKind() const {
+ return TargetInfo::AArch64ABIBuiltinVaList;
+ }
+};
+
+const char * const AArch64TargetInfo::GCCRegNames[] = {
+ "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7",
+ "w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15",
+ "w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23",
+ "w24", "w25", "w26", "w27", "w28", "w29", "w30", "wsp", "wzr",
+
+ "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
+ "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
+ "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
+ "x24", "x25", "x26", "x27", "x28", "x29", "x30", "sp", "xzr",
+
+ "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7",
+ "b8", "b9", "b10", "b11", "b12", "b13", "b14", "b15",
+ "b16", "b17", "b18", "b19", "b20", "b21", "b22", "b23",
+ "b24", "b25", "b26", "b27", "b28", "b29", "b30", "b31",
+
+ "h0", "h1", "h2", "h3", "h4", "h5", "h6", "h7",
+ "h8", "h9", "h10", "h11", "h12", "h13", "h14", "h15",
+ "h16", "h17", "h18", "h19", "h20", "h21", "h22", "h23",
+ "h24", "h25", "h26", "h27", "h28", "h29", "h30", "h31",
+
+ "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+ "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15",
+ "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
+ "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",
+
+ "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
+ "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15",
+ "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
+ "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31",
+
+ "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
+ "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15",
+ "q16", "q17", "q18", "q19", "q20", "q21", "q22", "q23",
+ "q24", "q25", "q26", "q27", "q28", "q29", "q30", "q31"
+};
+
+void AArch64TargetInfo::getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const {
+ Names = GCCRegNames;
+ NumNames = llvm::array_lengthof(GCCRegNames);
+}
+
+const TargetInfo::GCCRegAlias AArch64TargetInfo::GCCRegAliases[] = {
+ { { "x16" }, "ip0"},
+ { { "x17" }, "ip1"},
+ { { "x29" }, "fp" },
+ { { "x30" }, "lr" }
+};
+
+void AArch64TargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const {
+ Aliases = GCCRegAliases;
+ NumAliases = llvm::array_lengthof(GCCRegAliases);
+
+}
} // end anonymous namespace
namespace {
@@ -3056,7 +3531,7 @@ public:
}
// ARM targets default to using the ARM C++ ABI.
- CXXABI = CXXABI_ARM;
+ TheCXXABI.set(TargetCXXABI::GenericARM);
// ARM has atomics up to 8 bytes
// FIXME: Set MaxAtomicInlineWidth if we have the feature v6e
@@ -3078,7 +3553,9 @@ public:
// name.
if (Name == "apcs-gnu") {
DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 32;
- SizeType = UnsignedLong;
+ // size_t is unsigned int on FreeBSD.
+ if (getTriple().getOS() != llvm::Triple::FreeBSD)
+ SizeType = UnsignedLong;
// Revert to using SignedInt on apcs-gnu to comply with existing behaviour.
WCharType = SignedInt;
@@ -3124,7 +3601,7 @@ public:
else if (CPU == "cortex-a8" || CPU == "cortex-a15" ||
CPU == "cortex-a9" || CPU == "cortex-a9-mp")
Features["neon"] = true;
- else if (CPU == "swift") {
+ else if (CPU == "swift" || CPU == "cortex-a7") {
Features["vfp4"] = true;
Features["neon"] = true;
}
@@ -3197,7 +3674,9 @@ public:
.Cases("arm1176jz-s", "arm1176jzf-s", "6ZK")
.Cases("arm1136jf-s", "mpcorenovfp", "mpcore", "6K")
.Cases("arm1156t2-s", "arm1156t2f-s", "6T2")
- .Cases("cortex-a8", "cortex-a9", "cortex-a15", "7A")
+ .Cases("cortex-a5", "cortex-a7", "cortex-a8", "7A")
+ .Cases("cortex-a9", "cortex-a15", "7A")
+ .Case("cortex-r5", "7R")
.Case("cortex-a9-mp", "7F")
.Case("swift", "7S")
.Cases("cortex-m3", "cortex-m4", "7M")
@@ -3208,6 +3687,7 @@ public:
return llvm::StringSwitch<const char*>(Name)
.Cases("cortex-a8", "cortex-a9", "A")
.Cases("cortex-m3", "cortex-m4", "cortex-m0", "M")
+ .Case("cortex-r5", "R")
.Default("");
}
virtual bool setCPU(const std::string &Name) {
@@ -3318,11 +3798,11 @@ public:
case 'v': // ...VFP load/store (reg+constant offset)
case 'y': // ...iWMMXt load/store
case 't': // address valid for load/store opaque types wider
- // than 128-bits
+ // than 128-bits
case 'n': // valid address for Neon doubleword vector load/store
case 'm': // valid address for Neon element and structure load/store
case 's': // valid address for non-offset loads/stores of quad-word
- // values in four ARM registers
+ // values in four ARM registers
Info.setAllowsMemory();
Name++;
return true;
@@ -3348,6 +3828,9 @@ public:
virtual bool validateConstraintModifier(StringRef Constraint,
const char Modifier,
unsigned Size) const {
+ bool isOutput = (Constraint[0] == '=');
+ bool isInOut = (Constraint[0] == '+');
+
// Strip off constraint modifiers.
while (Constraint[0] == '=' ||
Constraint[0] == '+' ||
@@ -3359,7 +3842,8 @@ public:
case 'r': {
switch (Modifier) {
default:
- return Size == 32;
+ return isInOut || (isOutput && Size >= 32) ||
+ (!isOutput && !isInOut && Size <= 32);
case 'q':
// A register of size 32 cannot fit a vector type.
return false;
@@ -3377,6 +3861,12 @@ public:
virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const {
return (CC == CC_AAPCS || CC == CC_AAPCS_VFP) ? CCCR_OK : CCCR_Warning;
}
+
+ virtual int getEHDataRegisterNumber(unsigned RegNo) const {
+ if (RegNo == 0) return 0;
+ if (RegNo == 1) return 1;
+ return -1;
+ }
};
const char * const ARMTargetInfo::GCCRegNames[] = {
@@ -3458,6 +3948,9 @@ public:
// iOS always has 64-bit atomic instructions.
// FIXME: This should be based off of the target features in ARMTargetInfo.
MaxAtomicInlineWidth = 64;
+
+ // Darwin on iOS uses a variant of the ARM C++ ABI.
+ TheCXXABI.set(TargetCXXABI::iOS);
}
};
} // end anonymous namespace.
@@ -3474,7 +3967,7 @@ public:
HexagonTargetInfo(const std::string& triple) : TargetInfo(triple) {
BigEndian = false;
DescriptionString = ("e-p:32:32:32-"
- "i64:64:64-i32:32:32-i16:16:16-i1:32:32"
+ "i64:64:64-i32:32:32-i16:16:16-i1:32:32-"
"f64:64:64-f32:32:32-a0:0-n32");
// {} in inline assembly are packet specifiers, not assembly variant
@@ -3513,8 +4006,6 @@ public:
static const char *getHexagonCPUSuffix(StringRef Name) {
return llvm::StringSwitch<const char*>(Name)
- .Case("hexagonv2", "2")
- .Case("hexagonv3", "3")
.Case("hexagonv4", "4")
.Case("hexagonv5", "5")
.Default(0);
@@ -4040,6 +4531,9 @@ public:
case 'x': // hilo register pair
Info.setAllowsRegister();
return true;
+ case 'R': // An address that can be used in a non-macro load or store
+ Info.setAllowsMemory();
+ return true;
}
}
@@ -4058,6 +4552,12 @@ public:
Name == "mips16" || Name == "dsp" || Name == "dspr2") {
Features[Name] = Enabled;
return true;
+ } else if (Name == "32") {
+ Features["o32"] = Enabled;
+ return true;
+ } else if (Name == "64") {
+ Features["n64"] = Enabled;
+ return true;
}
return false;
}
@@ -4087,6 +4587,12 @@ public:
if (it != Features.end())
Features.erase(it);
}
+
+ virtual int getEHDataRegisterNumber(unsigned RegNo) const {
+ if (RegNo == 0) return 4;
+ if (RegNo == 1) return 5;
+ return -1;
+ }
};
const Builtin::Info MipsTargetInfoBase::BuiltinInfo[] = {
@@ -4102,11 +4608,15 @@ public:
MipsTargetInfoBase(triple, "o32", "mips32") {
SizeType = UnsignedInt;
PtrDiffType = SignedInt;
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32;
}
virtual bool setABI(const std::string &Name) {
if ((Name == "o32") || (Name == "eabi")) {
ABI = Name;
return true;
+ } else if (Name == "32") {
+ ABI = "o32";
+ return true;
} else
return false;
}
@@ -4168,7 +4678,7 @@ class Mips32EBTargetInfo : public Mips32TargetInfoBase {
public:
Mips32EBTargetInfo(const std::string& triple) : Mips32TargetInfoBase(triple) {
DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32";
+ "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32-S64";
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
@@ -4183,7 +4693,7 @@ public:
Mips32ELTargetInfo(const std::string& triple) : Mips32TargetInfoBase(triple) {
BigEndian = false;
DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32";
+ "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32-S64";
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
@@ -4202,22 +4712,28 @@ public:
PointerWidth = PointerAlign = 64;
LongDoubleWidth = LongDoubleAlign = 128;
LongDoubleFormat = &llvm::APFloat::IEEEquad;
+ if (getTriple().getOS() == llvm::Triple::FreeBSD) {
+ LongDoubleWidth = LongDoubleAlign = 64;
+ LongDoubleFormat = &llvm::APFloat::IEEEdouble;
+ }
SuitableAlign = 128;
+ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
}
virtual bool setABI(const std::string &Name) {
SetDescriptionString(Name);
-
- if (Name != "n32" && Name != "n64")
- return false;
-
- ABI = Name;
-
if (Name == "n32") {
LongWidth = LongAlign = 32;
PointerWidth = PointerAlign = 32;
- }
-
- return true;
+ ABI = Name;
+ return true;
+ } else if (Name == "n64") {
+ ABI = Name;
+ return true;
+ } else if (Name == "64") {
+ ABI = "n64";
+ return true;
+ } else
+ return false;
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
@@ -4285,14 +4801,14 @@ class Mips64EBTargetInfo : public Mips64TargetInfoBase {
if (Name == "n32")
DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-f128:128:128-"
- "v64:64:64-n32";
+ "v64:64:64-n32:64-S128";
}
public:
Mips64EBTargetInfo(const std::string& triple) : Mips64TargetInfoBase(triple) {
// Default ABI is n64.
DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-f128:128:128-"
- "v64:64:64-n32";
+ "v64:64:64-n32:64-S128";
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
@@ -4308,7 +4824,7 @@ class Mips64ELTargetInfo : public Mips64TargetInfoBase {
if (Name == "n32")
DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-f128:128:128"
- "-v64:64:64-n32";
+ "-v64:64:64-n32:64-S128";
}
public:
Mips64ELTargetInfo(const std::string& triple) : Mips64TargetInfoBase(triple) {
@@ -4316,7 +4832,7 @@ public:
BigEndian = false;
DescriptionString = "e-p:64:64:64-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-f128:128:128-"
- "v64:64:64-n32";
+ "v64:64:64-n32:64-S128";
}
virtual void getTargetDefines(const LangOptions &Opts,
MacroBuilder &Builder) const {
@@ -4399,6 +4915,97 @@ void PNaClTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases,
}
} // end anonymous namespace.
+namespace {
+ static const unsigned SPIRAddrSpaceMap[] = {
+ 1, // opencl_global
+ 3, // opencl_local
+ 2, // opencl_constant
+ 0, // cuda_device
+ 0, // cuda_constant
+ 0 // cuda_shared
+ };
+ class SPIRTargetInfo : public TargetInfo {
+ static const char * const GCCRegNames[];
+ static const Builtin::Info BuiltinInfo[];
+ std::vector<StringRef> AvailableFeatures;
+ public:
+ SPIRTargetInfo(const std::string& triple) : TargetInfo(triple) {
+ assert(getTriple().getOS() == llvm::Triple::UnknownOS &&
+ "SPIR target must use unknown OS");
+ assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment &&
+ "SPIR target must use unknown environment type");
+ BigEndian = false;
+ TLSSupported = false;
+ LongWidth = LongAlign = 64;
+ AddrSpaceMap = &SPIRAddrSpaceMap;
+ // Define available target features
+ // These must be defined in sorted order!
+ NoAsmVariants = true;
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "SPIR", Opts);
+ }
+ virtual bool hasFeature(StringRef Feature) const {
+ return Feature == "spir";
+ }
+
+ virtual void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const {}
+ virtual const char *getClobbers() const {
+ return "";
+ }
+ virtual void getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const {}
+ virtual bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &info) const {
+ return true;
+ }
+ virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const {}
+ virtual BuiltinVaListKind getBuiltinVaListKind() const {
+ return TargetInfo::VoidPtrBuiltinVaList;
+ }
+ };
+
+
+ class SPIR32TargetInfo : public SPIRTargetInfo {
+ public:
+ SPIR32TargetInfo(const std::string& triple) : SPIRTargetInfo(triple) {
+ PointerWidth = PointerAlign = 32;
+ SizeType = TargetInfo::UnsignedInt;
+ PtrDiffType = IntPtrType = TargetInfo::SignedInt;
+ DescriptionString
+ = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"
+ "f32:32:32-f64:64:64-v16:16:16-v24:32:32-v32:32:32-v48:64:64-"
+ "v64:64:64-v96:128:128-v128:128:128-v192:256:256-v256:256:256-"
+ "v512:512:512-v1024:1024:1024";
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "SPIR32", Opts);
+ }
+ };
+
+ class SPIR64TargetInfo : public SPIRTargetInfo {
+ public:
+ SPIR64TargetInfo(const std::string& triple) : SPIRTargetInfo(triple) {
+ PointerWidth = PointerAlign = 64;
+ SizeType = TargetInfo::UnsignedLong;
+ PtrDiffType = IntPtrType = TargetInfo::SignedLong;
+ DescriptionString
+ = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-"
+ "f32:32:32-f64:64:64-v16:16:16-v24:32:32-v32:32:32-v48:64:64-"
+ "v64:64:64-v96:128:128-v128:128:128-v192:256:256-v256:256:256-"
+ "v512:512:512-v1024:1024:1024";
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ MacroBuilder &Builder) const {
+ DefineStd(Builder, "SPIR64", Opts);
+ }
+ };
+}
+
//===----------------------------------------------------------------------===//
// Driver code
@@ -4415,6 +5022,14 @@ static TargetInfo *AllocateTarget(const std::string &T) {
case llvm::Triple::hexagon:
return new HexagonTargetInfo(T);
+ case llvm::Triple::aarch64:
+ switch (os) {
+ case llvm::Triple::Linux:
+ return new LinuxTargetInfo<AArch64TargetInfo>(T);
+ default:
+ return new AArch64TargetInfo(T);
+ }
+
case llvm::Triple::arm:
case llvm::Triple::thumb:
if (Triple.isOSDarwin())
@@ -4433,7 +5048,7 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new BitrigTargetInfo<ARMTargetInfo>(T);
case llvm::Triple::RTEMS:
return new RTEMSTargetInfo<ARMTargetInfo>(T);
- case llvm::Triple::NativeClient:
+ case llvm::Triple::NaCl:
return new NaClTargetInfo<ARMTargetInfo>(T);
default:
return new ARMTargetInfo(T);
@@ -4504,7 +5119,7 @@ static TargetInfo *AllocateTarget(const std::string &T) {
case llvm::Triple::le32:
switch (os) {
- case llvm::Triple::NativeClient:
+ case llvm::Triple::NaCl:
return new NaClTargetInfo<PNaClTargetInfo>(T);
default:
return NULL;
@@ -4573,10 +5188,6 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new SparcV8TargetInfo(T);
}
- // FIXME: Need a real SPU target.
- case llvm::Triple::cellspu:
- return new PS3SPUTargetInfo<PPC64TargetInfo>(T);
-
case llvm::Triple::tce:
return new TCETargetInfo(T);
@@ -4613,7 +5224,7 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new HaikuX86_32TargetInfo(T);
case llvm::Triple::RTEMS:
return new RTEMSX86_32TargetInfo(T);
- case llvm::Triple::NativeClient:
+ case llvm::Triple::NaCl:
return new NaClTargetInfo<X86_32TargetInfo>(T);
default:
return new X86_32TargetInfo(T);
@@ -4644,19 +5255,34 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new MinGWX86_64TargetInfo(T);
case llvm::Triple::Win32: // This is what Triple.h supports now.
return new VisualStudioWindowsX86_64TargetInfo(T);
- case llvm::Triple::NativeClient:
+ case llvm::Triple::NaCl:
return new NaClTargetInfo<X86_64TargetInfo>(T);
default:
return new X86_64TargetInfo(T);
}
+
+ case llvm::Triple::spir: {
+ llvm::Triple Triple(T);
+ if (Triple.getOS() != llvm::Triple::UnknownOS ||
+ Triple.getEnvironment() != llvm::Triple::UnknownEnvironment)
+ return NULL;
+ return new SPIR32TargetInfo(T);
+ }
+ case llvm::Triple::spir64: {
+ llvm::Triple Triple(T);
+ if (Triple.getOS() != llvm::Triple::UnknownOS ||
+ Triple.getEnvironment() != llvm::Triple::UnknownEnvironment)
+ return NULL;
+ return new SPIR64TargetInfo(T);
+ }
}
}
/// CreateTargetInfo - Return the target info object for the specified target
/// triple.
TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
- TargetOptions &Opts) {
- llvm::Triple Triple(Opts.Triple);
+ TargetOptions *Opts) {
+ llvm::Triple Triple(Opts->Triple);
// Construct the target
OwningPtr<TargetInfo> Target(AllocateTarget(Triple.str()));
@@ -4667,20 +5293,20 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
Target->setTargetOpts(Opts);
// Set the target CPU if specified.
- if (!Opts.CPU.empty() && !Target->setCPU(Opts.CPU)) {
- Diags.Report(diag::err_target_unknown_cpu) << Opts.CPU;
+ if (!Opts->CPU.empty() && !Target->setCPU(Opts->CPU)) {
+ Diags.Report(diag::err_target_unknown_cpu) << Opts->CPU;
return 0;
}
// Set the target ABI if specified.
- if (!Opts.ABI.empty() && !Target->setABI(Opts.ABI)) {
- Diags.Report(diag::err_target_unknown_abi) << Opts.ABI;
+ if (!Opts->ABI.empty() && !Target->setABI(Opts->ABI)) {
+ Diags.Report(diag::err_target_unknown_abi) << Opts->ABI;
return 0;
}
// Set the target C++ ABI.
- if (!Opts.CXXABI.empty() && !Target->setCXXABI(Opts.CXXABI)) {
- Diags.Report(diag::err_target_unknown_cxxabi) << Opts.CXXABI;
+ if (!Opts->CXXABI.empty() && !Target->setCXXABI(Opts->CXXABI)) {
+ Diags.Report(diag::err_target_unknown_cxxabi) << Opts->CXXABI;
return 0;
}
@@ -4692,8 +5318,8 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
// Apply the user specified deltas.
// First the enables.
for (std::vector<std::string>::const_iterator
- it = Opts.FeaturesAsWritten.begin(),
- ie = Opts.FeaturesAsWritten.end();
+ it = Opts->FeaturesAsWritten.begin(),
+ ie = Opts->FeaturesAsWritten.end();
it != ie; ++it) {
const char *Name = it->c_str();
@@ -4709,8 +5335,8 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
// Then the disables.
for (std::vector<std::string>::const_iterator
- it = Opts.FeaturesAsWritten.begin(),
- ie = Opts.FeaturesAsWritten.end();
+ it = Opts->FeaturesAsWritten.begin(),
+ ie = Opts->FeaturesAsWritten.end();
it != ie; ++it) {
const char *Name = it->c_str();
@@ -4729,11 +5355,11 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags,
//
// FIXME: If we are completely confident that we have the right set, we only
// need to pass the minuses.
- Opts.Features.clear();
+ Opts->Features.clear();
for (llvm::StringMap<bool>::const_iterator it = Features.begin(),
ie = Features.end(); it != ie; ++it)
- Opts.Features.push_back((it->second ? "+" : "-") + it->first().str());
- Target->HandleTargetFeatures(Opts.Features);
+ Opts->Features.push_back((it->second ? "+" : "-") + it->first().str());
+ Target->HandleTargetFeatures(Opts->Features);
return Target.take();
}
diff --git a/lib/Basic/TokenKinds.cpp b/lib/Basic/TokenKinds.cpp
index 8cdc1e3..6ce076e 100644
--- a/lib/Basic/TokenKinds.cpp
+++ b/lib/Basic/TokenKinds.cpp
@@ -12,7 +12,6 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/TokenKinds.h"
-
#include <cassert>
using namespace clang;
diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp
index dc7d8d1..7381e70 100644
--- a/lib/Basic/Version.cpp
+++ b/lib/Basic/Version.cpp
@@ -13,10 +13,14 @@
#include "clang/Basic/Version.h"
#include "clang/Basic/LLVM.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Config/config.h"
-#include <cstring>
+#include "llvm/Support/raw_ostream.h"
#include <cstdlib>
+#include <cstring>
+
+#ifdef HAVE_SVN_VERSION_INC
+# include "SVNVersion.inc"
+#endif
namespace clang {
@@ -32,7 +36,7 @@ std::string getClangRepositoryPath() {
// If the SVN_REPOSITORY is empty, try to use the SVN keyword. This helps us
// pick up a tag in an SVN export, for example.
- static StringRef SVNRepository("$URL: http://llvm.org/svn/llvm-project/cfe/tags/RELEASE_32/final/lib/Basic/Version.cpp $");
+ static StringRef SVNRepository("$URL: http://llvm.org/svn/llvm-project/cfe/trunk/lib/Basic/Version.cpp $");
if (URL.empty()) {
URL = SVNRepository.slice(SVNRepository.find(':'),
SVNRepository.find("/lib/Basic"));
diff --git a/lib/Basic/VersionTuple.cpp b/lib/Basic/VersionTuple.cpp
index 4f479d0..8b781ab 100644
--- a/lib/Basic/VersionTuple.cpp
+++ b/lib/Basic/VersionTuple.cpp
@@ -28,9 +28,9 @@ std::string VersionTuple::getAsString() const {
raw_ostream& clang::operator<<(raw_ostream &Out,
const VersionTuple &V) {
Out << V.getMajor();
- if (llvm::Optional<unsigned> Minor = V.getMinor())
+ if (Optional<unsigned> Minor = V.getMinor())
Out << '.' << *Minor;
- if (llvm::Optional<unsigned> Subminor = V.getSubminor())
+ if (Optional<unsigned> Subminor = V.getSubminor())
Out << '.' << *Subminor;
return Out;
}
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 206c228..053320c 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -16,3 +16,4 @@ add_subdirectory(Frontend)
add_subdirectory(FrontendTool)
add_subdirectory(Tooling)
add_subdirectory(StaticAnalyzer)
+add_subdirectory(Format)
diff --git a/lib/CodeGen/ABIInfo.h b/lib/CodeGen/ABIInfo.h
index da6d035..35780f1 100644
--- a/lib/CodeGen/ABIInfo.h
+++ b/lib/CodeGen/ABIInfo.h
@@ -11,7 +11,8 @@
#define CLANG_CODEGEN_ABIINFO_H
#include "clang/AST/Type.h"
-#include "llvm/Type.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/CallingConv.h"
namespace llvm {
class Value;
@@ -102,8 +103,10 @@ namespace clang {
return ABIArgInfo(Ignore, 0, 0, false, false, false, false, 0);
}
static ABIArgInfo getIndirect(unsigned Alignment, bool ByVal = true
- , bool Realign = false) {
- return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, false, false, 0);
+ , bool Realign = false
+ , llvm::Type *Padding = 0) {
+ return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, false, false,
+ Padding);
}
static ABIArgInfo getIndirectInReg(unsigned Alignment, bool ByVal = true
, bool Realign = false) {
@@ -182,14 +185,24 @@ namespace clang {
class ABIInfo {
public:
CodeGen::CodeGenTypes &CGT;
+ protected:
+ llvm::CallingConv::ID RuntimeCC;
+ public:
+ ABIInfo(CodeGen::CodeGenTypes &cgt)
+ : CGT(cgt), RuntimeCC(llvm::CallingConv::C) {}
- ABIInfo(CodeGen::CodeGenTypes &cgt) : CGT(cgt) {}
virtual ~ABIInfo();
ASTContext &getContext() const;
llvm::LLVMContext &getVMContext() const;
const llvm::DataLayout &getDataLayout() const;
+ /// Return the calling convention to use for system runtime
+ /// functions.
+ llvm::CallingConv::ID getRuntimeCC() const {
+ return RuntimeCC;
+ }
+
virtual void computeInfo(CodeGen::CGFunctionInfo &FI) const = 0;
/// EmitVAArg - Emit the target dependent code to load a value of
diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp
index 62f87c9..45079c0 100644
--- a/lib/CodeGen/BackendUtil.cpp
+++ b/lib/CodeGen/BackendUtil.cpp
@@ -9,31 +9,32 @@
#include "clang/CodeGen/BackendUtil.h"
#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/TargetOptions.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
-#include "llvm/Module.h"
-#include "llvm/PassManager.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/CodeGen/RegAllocRegistry.h"
#include "llvm/CodeGen/SchedulerRegistry.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Module.h"
#include "llvm/MC/SubtargetFeature.h"
+#include "llvm/PassManager.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/DataLayout.h"
#include "llvm/Target/TargetLibraryInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
-#include "llvm/Transforms/Instrumentation.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/Transforms/Instrumentation.h"
+#include "llvm/Transforms/ObjCARC.h"
#include "llvm/Transforms/Scalar.h"
using namespace clang;
using namespace llvm;
@@ -58,13 +59,8 @@ private:
if (!CodeGenPasses) {
CodeGenPasses = new PassManager();
CodeGenPasses->add(new DataLayout(TheModule));
- // Add TargetTransformInfo.
- if (TM) {
- TargetTransformInfo *TTI =
- new TargetTransformInfo(TM->getScalarTargetTransformInfo(),
- TM->getVectorTargetTransformInfo());
- CodeGenPasses->add(TTI);
- }
+ if (TM)
+ TM->addAnalysisPasses(*CodeGenPasses);
}
return CodeGenPasses;
}
@@ -73,12 +69,8 @@ private:
if (!PerModulePasses) {
PerModulePasses = new PassManager();
PerModulePasses->add(new DataLayout(TheModule));
- if (TM) {
- TargetTransformInfo *TTI =
- new TargetTransformInfo(TM->getScalarTargetTransformInfo(),
- TM->getVectorTargetTransformInfo());
- PerModulePasses->add(TTI);
- }
+ if (TM)
+ TM->addAnalysisPasses(*PerModulePasses);
}
return PerModulePasses;
}
@@ -87,12 +79,8 @@ private:
if (!PerFunctionPasses) {
PerFunctionPasses = new FunctionPassManager(TheModule);
PerFunctionPasses->add(new DataLayout(TheModule));
- if (TM) {
- TargetTransformInfo *TTI =
- new TargetTransformInfo(TM->getScalarTargetTransformInfo(),
- TM->getVectorTargetTransformInfo());
- PerFunctionPasses->add(TTI);
- }
+ if (TM)
+ TM->addAnalysisPasses(*PerFunctionPasses);
}
return PerFunctionPasses;
}
@@ -135,6 +123,20 @@ public:
void EmitAssembly(BackendAction Action, raw_ostream *OS);
};
+// We need this wrapper to access LangOpts and CGOpts from extension functions
+// that we add to the PassManagerBuilder.
+class PassManagerBuilderWrapper : public PassManagerBuilder {
+public:
+ PassManagerBuilderWrapper(const CodeGenOptions &CGOpts,
+ const LangOptions &LangOpts)
+ : PassManagerBuilder(), CGOpts(CGOpts), LangOpts(LangOpts) {}
+ const CodeGenOptions &getCGOpts() const { return CGOpts; }
+ const LangOptions &getLangOpts() const { return LangOpts; }
+private:
+ const CodeGenOptions &CGOpts;
+ const LangOptions &LangOpts;
+};
+
}
static void addObjCARCAPElimPass(const PassManagerBuilder &Builder, PassManagerBase &PM) {
@@ -152,20 +154,56 @@ static void addObjCARCOptPass(const PassManagerBuilder &Builder, PassManagerBase
PM.add(createObjCARCOptPass());
}
-static unsigned BoundsChecking;
static void addBoundsCheckingPass(const PassManagerBuilder &Builder,
PassManagerBase &PM) {
- PM.add(createBoundsCheckingPass(BoundsChecking));
+ PM.add(createBoundsCheckingPass());
}
-static void addAddressSanitizerPass(const PassManagerBuilder &Builder,
- PassManagerBase &PM) {
- PM.add(createAddressSanitizerPass());
+static void addAddressSanitizerPasses(const PassManagerBuilder &Builder,
+ PassManagerBase &PM) {
+ const PassManagerBuilderWrapper &BuilderWrapper =
+ static_cast<const PassManagerBuilderWrapper&>(Builder);
+ const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts();
+ const LangOptions &LangOpts = BuilderWrapper.getLangOpts();
+ PM.add(createAddressSanitizerFunctionPass(
+ LangOpts.Sanitize.InitOrder,
+ LangOpts.Sanitize.UseAfterReturn,
+ LangOpts.Sanitize.UseAfterScope,
+ CGOpts.SanitizerBlacklistFile,
+ CGOpts.SanitizeAddressZeroBaseShadow));
+ PM.add(createAddressSanitizerModulePass(
+ LangOpts.Sanitize.InitOrder,
+ CGOpts.SanitizerBlacklistFile,
+ CGOpts.SanitizeAddressZeroBaseShadow));
+}
+
+static void addMemorySanitizerPass(const PassManagerBuilder &Builder,
+ PassManagerBase &PM) {
+ const PassManagerBuilderWrapper &BuilderWrapper =
+ static_cast<const PassManagerBuilderWrapper&>(Builder);
+ const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts();
+ PM.add(createMemorySanitizerPass(CGOpts.SanitizeMemoryTrackOrigins,
+ CGOpts.SanitizerBlacklistFile));
+
+ // MemorySanitizer inserts complex instrumentation that mostly follows
+ // the logic of the original code, but operates on "shadow" values.
+ // It can benefit from re-running some general purpose optimization passes.
+ if (Builder.OptLevel > 0) {
+ PM.add(createEarlyCSEPass());
+ PM.add(createReassociatePass());
+ PM.add(createLICMPass());
+ PM.add(createGVNPass());
+ PM.add(createInstructionCombiningPass());
+ PM.add(createDeadStoreEliminationPass());
+ }
}
static void addThreadSanitizerPass(const PassManagerBuilder &Builder,
PassManagerBase &PM) {
- PM.add(createThreadSanitizerPass());
+ const PassManagerBuilderWrapper &BuilderWrapper =
+ static_cast<const PassManagerBuilderWrapper&>(Builder);
+ const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts();
+ PM.add(createThreadSanitizerPass(CGOpts.SanitizerBlacklistFile));
}
void EmitAssemblyHelper::CreatePasses(TargetMachine *TM) {
@@ -178,8 +216,8 @@ void EmitAssemblyHelper::CreatePasses(TargetMachine *TM) {
OptLevel = 0;
Inlining = CodeGenOpts.NoInlining;
}
-
- PassManagerBuilder PMBuilder;
+
+ PassManagerBuilderWrapper PMBuilder(CodeGenOpts, LangOpts);
PMBuilder.OptLevel = OptLevel;
PMBuilder.SizeLevel = CodeGenOpts.OptimizeSize;
@@ -197,22 +235,28 @@ void EmitAssemblyHelper::CreatePasses(TargetMachine *TM) {
addObjCARCOptPass);
}
- if (CodeGenOpts.BoundsChecking > 0) {
- BoundsChecking = CodeGenOpts.BoundsChecking;
+ if (LangOpts.Sanitize.Bounds) {
PMBuilder.addExtension(PassManagerBuilder::EP_ScalarOptimizerLate,
addBoundsCheckingPass);
PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
addBoundsCheckingPass);
}
- if (LangOpts.SanitizeAddress) {
+ if (LangOpts.Sanitize.Address) {
PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
- addAddressSanitizerPass);
+ addAddressSanitizerPasses);
PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
- addAddressSanitizerPass);
+ addAddressSanitizerPasses);
}
- if (LangOpts.SanitizeThread) {
+ if (LangOpts.Sanitize.Memory) {
+ PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
+ addMemorySanitizerPass);
+ PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
+ addMemorySanitizerPass);
+ }
+
+ if (LangOpts.Sanitize.Thread) {
PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
addThreadSanitizerPass);
PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0,
@@ -258,11 +302,19 @@ void EmitAssemblyHelper::CreatePasses(TargetMachine *TM) {
// Set up the per-module pass manager.
PassManager *MPM = getPerModulePasses(TM);
- if (CodeGenOpts.EmitGcovArcs || CodeGenOpts.EmitGcovNotes) {
- MPM->add(createGCOVProfilerPass(CodeGenOpts.EmitGcovNotes,
- CodeGenOpts.EmitGcovArcs,
- TargetTriple.isMacOSX()));
-
+ if (!CodeGenOpts.DisableGCov &&
+ (CodeGenOpts.EmitGcovArcs || CodeGenOpts.EmitGcovNotes)) {
+ // Not using 'GCOVOptions::getDefault' allows us to avoid exiting if
+ // LLVM's -default-gcov-version flag is set to something invalid.
+ GCOVOptions Options;
+ Options.EmitNotes = CodeGenOpts.EmitGcovNotes;
+ Options.EmitData = CodeGenOpts.EmitGcovArcs;
+ memcpy(Options.Version, CodeGenOpts.CoverageVersion, 4);
+ Options.UseCfgChecksum = CodeGenOpts.CoverageExtraChecksum;
+ Options.NoRedZone = CodeGenOpts.DisableRedZone;
+ Options.FunctionNamesInData =
+ !CodeGenOpts.CoverageNoFunctionNamesInData;
+ MPM->add(createGCOVProfilerPass(Options));
if (CodeGenOpts.getDebugInfo() == CodeGenOptions::NoDebugInfo)
MPM->add(createStripSymbolsPass(true));
}
@@ -381,14 +433,14 @@ TargetMachine *EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) {
}
// Set FP fusion mode.
- switch (LangOpts.getFPContractMode()) {
- case LangOptions::FPC_Off:
+ switch (CodeGenOpts.getFPContractMode()) {
+ case CodeGenOptions::FPC_Off:
Options.AllowFPOpFusion = llvm::FPOpFusion::Strict;
break;
- case LangOptions::FPC_On:
+ case CodeGenOptions::FPC_On:
Options.AllowFPOpFusion = llvm::FPOpFusion::Standard;
break;
- case LangOptions::FPC_Fast:
+ case CodeGenOptions::FPC_Fast:
Options.AllowFPOpFusion = llvm::FPOpFusion::Fast;
break;
}
@@ -405,6 +457,7 @@ TargetMachine *EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) {
Options.TrapFuncName = CodeGenOpts.TrapFuncName;
Options.PositionIndependentExecutable = LangOpts.PIELevel != 0;
Options.SSPBufferSize = CodeGenOpts.SSPBufferSize;
+ Options.EnableSegmentedStacks = CodeGenOpts.EnableSegmentedStacks;
TargetMachine *TM = TheTarget->createTargetMachine(Triple, TargetOpts.CPU,
FeaturesStr, Options,
@@ -438,9 +491,8 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action,
TLI->disableAllFunctions();
PM->add(TLI);
- // Add TargetTransformInfo.
- PM->add(new TargetTransformInfo(TM->getScalarTargetTransformInfo(),
- TM->getVectorTargetTransformInfo()));
+ // Add Target specific analysis passes.
+ TM->addAnalysisPasses(*PM);
// Normal mode, emit a .s or .o file by running the code generator. Note,
// this also adds codegenerator level optimization passes.
@@ -476,6 +528,7 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action, raw_ostream *OS) {
Action != Backend_EmitBC &&
Action != Backend_EmitLL);
TargetMachine *TM = CreateTargetMachine(UsesCodeGen);
+ if (UsesCodeGen && !TM) return;
CreatePasses(TM);
switch (Action) {
diff --git a/lib/CodeGen/CGAtomic.cpp b/lib/CodeGen/CGAtomic.cpp
new file mode 100644
index 0000000..817d5c4
--- /dev/null
+++ b/lib/CodeGen/CGAtomic.cpp
@@ -0,0 +1,942 @@
+//===--- CGAtomic.cpp - Emit LLVM IR for atomic operations ----------------===//
+//
+// 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 code for emitting atomic operations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeGenFunction.h"
+#include "CGCall.h"
+#include "CodeGenModule.h"
+#include "clang/AST/ASTContext.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/Operator.h"
+
+using namespace clang;
+using namespace CodeGen;
+
+// The ABI values for various atomic memory orderings.
+enum AtomicOrderingKind {
+ AO_ABI_memory_order_relaxed = 0,
+ AO_ABI_memory_order_consume = 1,
+ AO_ABI_memory_order_acquire = 2,
+ AO_ABI_memory_order_release = 3,
+ AO_ABI_memory_order_acq_rel = 4,
+ AO_ABI_memory_order_seq_cst = 5
+};
+
+namespace {
+ class AtomicInfo {
+ CodeGenFunction &CGF;
+ QualType AtomicTy;
+ QualType ValueTy;
+ uint64_t AtomicSizeInBits;
+ uint64_t ValueSizeInBits;
+ CharUnits AtomicAlign;
+ CharUnits ValueAlign;
+ CharUnits LValueAlign;
+ TypeEvaluationKind EvaluationKind;
+ bool UseLibcall;
+ public:
+ AtomicInfo(CodeGenFunction &CGF, LValue &lvalue) : CGF(CGF) {
+ assert(lvalue.isSimple());
+
+ AtomicTy = lvalue.getType();
+ ValueTy = AtomicTy->castAs<AtomicType>()->getValueType();
+ EvaluationKind = CGF.getEvaluationKind(ValueTy);
+
+ ASTContext &C = CGF.getContext();
+
+ uint64_t valueAlignInBits;
+ llvm::tie(ValueSizeInBits, valueAlignInBits) = C.getTypeInfo(ValueTy);
+
+ uint64_t atomicAlignInBits;
+ llvm::tie(AtomicSizeInBits, atomicAlignInBits) = C.getTypeInfo(AtomicTy);
+
+ assert(ValueSizeInBits <= AtomicSizeInBits);
+ assert(valueAlignInBits <= atomicAlignInBits);
+
+ AtomicAlign = C.toCharUnitsFromBits(atomicAlignInBits);
+ ValueAlign = C.toCharUnitsFromBits(valueAlignInBits);
+ if (lvalue.getAlignment().isZero())
+ lvalue.setAlignment(AtomicAlign);
+
+ UseLibcall =
+ (AtomicSizeInBits > uint64_t(C.toBits(lvalue.getAlignment())) ||
+ AtomicSizeInBits > C.getTargetInfo().getMaxAtomicInlineWidth());
+ }
+
+ QualType getAtomicType() const { return AtomicTy; }
+ QualType getValueType() const { return ValueTy; }
+ CharUnits getAtomicAlignment() const { return AtomicAlign; }
+ CharUnits getValueAlignment() const { return ValueAlign; }
+ uint64_t getAtomicSizeInBits() const { return AtomicSizeInBits; }
+ uint64_t getValueSizeInBits() const { return AtomicSizeInBits; }
+ TypeEvaluationKind getEvaluationKind() const { return EvaluationKind; }
+ bool shouldUseLibcall() const { return UseLibcall; }
+
+ /// Is the atomic size larger than the underlying value type?
+ ///
+ /// Note that the absence of padding does not mean that atomic
+ /// objects are completely interchangeable with non-atomic
+ /// objects: we might have promoted the alignment of a type
+ /// without making it bigger.
+ bool hasPadding() const {
+ return (ValueSizeInBits != AtomicSizeInBits);
+ }
+
+ void emitMemSetZeroIfNecessary(LValue dest) const;
+
+ llvm::Value *getAtomicSizeValue() const {
+ CharUnits size = CGF.getContext().toCharUnitsFromBits(AtomicSizeInBits);
+ return CGF.CGM.getSize(size);
+ }
+
+ /// Cast the given pointer to an integer pointer suitable for
+ /// atomic operations.
+ llvm::Value *emitCastToAtomicIntPointer(llvm::Value *addr) const;
+
+ /// Turn an atomic-layout object into an r-value.
+ RValue convertTempToRValue(llvm::Value *addr,
+ AggValueSlot resultSlot) const;
+
+ /// Copy an atomic r-value into atomic-layout memory.
+ void emitCopyIntoMemory(RValue rvalue, LValue lvalue) const;
+
+ /// Project an l-value down to the value field.
+ LValue projectValue(LValue lvalue) const {
+ llvm::Value *addr = lvalue.getAddress();
+ if (hasPadding())
+ addr = CGF.Builder.CreateStructGEP(addr, 0);
+
+ return LValue::MakeAddr(addr, getValueType(), lvalue.getAlignment(),
+ CGF.getContext(), lvalue.getTBAAInfo());
+ }
+
+ /// Materialize an atomic r-value in atomic-layout memory.
+ llvm::Value *materializeRValue(RValue rvalue) const;
+
+ private:
+ bool requiresMemSetZero(llvm::Type *type) const;
+ };
+}
+
+static RValue emitAtomicLibcall(CodeGenFunction &CGF,
+ StringRef fnName,
+ QualType resultType,
+ CallArgList &args) {
+ const CGFunctionInfo &fnInfo =
+ CGF.CGM.getTypes().arrangeFreeFunctionCall(resultType, args,
+ FunctionType::ExtInfo(), RequiredArgs::All);
+ llvm::FunctionType *fnTy = CGF.CGM.getTypes().GetFunctionType(fnInfo);
+ llvm::Constant *fn = CGF.CGM.CreateRuntimeFunction(fnTy, fnName);
+ return CGF.EmitCall(fnInfo, fn, ReturnValueSlot(), args);
+}
+
+/// Does a store of the given IR type modify the full expected width?
+static bool isFullSizeType(CodeGenModule &CGM, llvm::Type *type,
+ uint64_t expectedSize) {
+ return (CGM.getDataLayout().getTypeStoreSize(type) * 8 == expectedSize);
+}
+
+/// Does the atomic type require memsetting to zero before initialization?
+///
+/// The IR type is provided as a way of making certain queries faster.
+bool AtomicInfo::requiresMemSetZero(llvm::Type *type) const {
+ // If the atomic type has size padding, we definitely need a memset.
+ if (hasPadding()) return true;
+
+ // Otherwise, do some simple heuristics to try to avoid it:
+ switch (getEvaluationKind()) {
+ // For scalars and complexes, check whether the store size of the
+ // type uses the full size.
+ case TEK_Scalar:
+ return !isFullSizeType(CGF.CGM, type, AtomicSizeInBits);
+ case TEK_Complex:
+ return !isFullSizeType(CGF.CGM, type->getStructElementType(0),
+ AtomicSizeInBits / 2);
+
+ // Just be pessimistic about aggregates.
+ case TEK_Aggregate:
+ return true;
+ }
+ llvm_unreachable("bad evaluation kind");
+}
+
+void AtomicInfo::emitMemSetZeroIfNecessary(LValue dest) const {
+ llvm::Value *addr = dest.getAddress();
+ if (!requiresMemSetZero(addr->getType()->getPointerElementType()))
+ return;
+
+ CGF.Builder.CreateMemSet(addr, llvm::ConstantInt::get(CGF.Int8Ty, 0),
+ AtomicSizeInBits / 8,
+ dest.getAlignment().getQuantity());
+}
+
+static void
+EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, llvm::Value *Dest,
+ llvm::Value *Ptr, llvm::Value *Val1, llvm::Value *Val2,
+ uint64_t Size, unsigned Align, llvm::AtomicOrdering Order) {
+ llvm::AtomicRMWInst::BinOp Op = llvm::AtomicRMWInst::Add;
+ llvm::Instruction::BinaryOps PostOp = (llvm::Instruction::BinaryOps)0;
+
+ switch (E->getOp()) {
+ case AtomicExpr::AO__c11_atomic_init:
+ llvm_unreachable("Already handled!");
+
+ case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
+ case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
+ case AtomicExpr::AO__atomic_compare_exchange:
+ case AtomicExpr::AO__atomic_compare_exchange_n: {
+ // Note that cmpxchg only supports specifying one ordering and
+ // doesn't support weak cmpxchg, at least at the moment.
+ llvm::LoadInst *LoadVal1 = CGF.Builder.CreateLoad(Val1);
+ LoadVal1->setAlignment(Align);
+ llvm::LoadInst *LoadVal2 = CGF.Builder.CreateLoad(Val2);
+ LoadVal2->setAlignment(Align);
+ llvm::AtomicCmpXchgInst *CXI =
+ CGF.Builder.CreateAtomicCmpXchg(Ptr, LoadVal1, LoadVal2, Order);
+ CXI->setVolatile(E->isVolatile());
+ llvm::StoreInst *StoreVal1 = CGF.Builder.CreateStore(CXI, Val1);
+ StoreVal1->setAlignment(Align);
+ llvm::Value *Cmp = CGF.Builder.CreateICmpEQ(CXI, LoadVal1);
+ CGF.EmitStoreOfScalar(Cmp, CGF.MakeAddrLValue(Dest, E->getType()));
+ return;
+ }
+
+ case AtomicExpr::AO__c11_atomic_load:
+ case AtomicExpr::AO__atomic_load_n:
+ case AtomicExpr::AO__atomic_load: {
+ llvm::LoadInst *Load = CGF.Builder.CreateLoad(Ptr);
+ Load->setAtomic(Order);
+ Load->setAlignment(Size);
+ Load->setVolatile(E->isVolatile());
+ llvm::StoreInst *StoreDest = CGF.Builder.CreateStore(Load, Dest);
+ StoreDest->setAlignment(Align);
+ return;
+ }
+
+ case AtomicExpr::AO__c11_atomic_store:
+ case AtomicExpr::AO__atomic_store:
+ case AtomicExpr::AO__atomic_store_n: {
+ assert(!Dest && "Store does not return a value");
+ llvm::LoadInst *LoadVal1 = CGF.Builder.CreateLoad(Val1);
+ LoadVal1->setAlignment(Align);
+ llvm::StoreInst *Store = CGF.Builder.CreateStore(LoadVal1, Ptr);
+ Store->setAtomic(Order);
+ Store->setAlignment(Size);
+ Store->setVolatile(E->isVolatile());
+ return;
+ }
+
+ case AtomicExpr::AO__c11_atomic_exchange:
+ case AtomicExpr::AO__atomic_exchange_n:
+ case AtomicExpr::AO__atomic_exchange:
+ Op = llvm::AtomicRMWInst::Xchg;
+ break;
+
+ case AtomicExpr::AO__atomic_add_fetch:
+ PostOp = llvm::Instruction::Add;
+ // Fall through.
+ case AtomicExpr::AO__c11_atomic_fetch_add:
+ case AtomicExpr::AO__atomic_fetch_add:
+ Op = llvm::AtomicRMWInst::Add;
+ break;
+
+ case AtomicExpr::AO__atomic_sub_fetch:
+ PostOp = llvm::Instruction::Sub;
+ // Fall through.
+ case AtomicExpr::AO__c11_atomic_fetch_sub:
+ case AtomicExpr::AO__atomic_fetch_sub:
+ Op = llvm::AtomicRMWInst::Sub;
+ break;
+
+ case AtomicExpr::AO__atomic_and_fetch:
+ PostOp = llvm::Instruction::And;
+ // Fall through.
+ case AtomicExpr::AO__c11_atomic_fetch_and:
+ case AtomicExpr::AO__atomic_fetch_and:
+ Op = llvm::AtomicRMWInst::And;
+ break;
+
+ case AtomicExpr::AO__atomic_or_fetch:
+ PostOp = llvm::Instruction::Or;
+ // Fall through.
+ case AtomicExpr::AO__c11_atomic_fetch_or:
+ case AtomicExpr::AO__atomic_fetch_or:
+ Op = llvm::AtomicRMWInst::Or;
+ break;
+
+ case AtomicExpr::AO__atomic_xor_fetch:
+ PostOp = llvm::Instruction::Xor;
+ // Fall through.
+ case AtomicExpr::AO__c11_atomic_fetch_xor:
+ case AtomicExpr::AO__atomic_fetch_xor:
+ Op = llvm::AtomicRMWInst::Xor;
+ break;
+
+ case AtomicExpr::AO__atomic_nand_fetch:
+ PostOp = llvm::Instruction::And;
+ // Fall through.
+ case AtomicExpr::AO__atomic_fetch_nand:
+ Op = llvm::AtomicRMWInst::Nand;
+ break;
+ }
+
+ llvm::LoadInst *LoadVal1 = CGF.Builder.CreateLoad(Val1);
+ LoadVal1->setAlignment(Align);
+ llvm::AtomicRMWInst *RMWI =
+ CGF.Builder.CreateAtomicRMW(Op, Ptr, LoadVal1, Order);
+ RMWI->setVolatile(E->isVolatile());
+
+ // For __atomic_*_fetch operations, perform the operation again to
+ // determine the value which was written.
+ llvm::Value *Result = RMWI;
+ if (PostOp)
+ Result = CGF.Builder.CreateBinOp(PostOp, RMWI, LoadVal1);
+ if (E->getOp() == AtomicExpr::AO__atomic_nand_fetch)
+ Result = CGF.Builder.CreateNot(Result);
+ llvm::StoreInst *StoreDest = CGF.Builder.CreateStore(Result, Dest);
+ StoreDest->setAlignment(Align);
+}
+
+// This function emits any expression (scalar, complex, or aggregate)
+// into a temporary alloca.
+static llvm::Value *
+EmitValToTemp(CodeGenFunction &CGF, Expr *E) {
+ llvm::Value *DeclPtr = CGF.CreateMemTemp(E->getType(), ".atomictmp");
+ CGF.EmitAnyExprToMem(E, DeclPtr, E->getType().getQualifiers(),
+ /*Init*/ true);
+ return DeclPtr;
+}
+
+RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
+ QualType AtomicTy = E->getPtr()->getType()->getPointeeType();
+ QualType MemTy = AtomicTy;
+ if (const AtomicType *AT = AtomicTy->getAs<AtomicType>())
+ MemTy = AT->getValueType();
+ CharUnits sizeChars = getContext().getTypeSizeInChars(AtomicTy);
+ uint64_t Size = sizeChars.getQuantity();
+ CharUnits alignChars = getContext().getTypeAlignInChars(AtomicTy);
+ unsigned Align = alignChars.getQuantity();
+ unsigned MaxInlineWidthInBits =
+ getContext().getTargetInfo().getMaxAtomicInlineWidth();
+ bool UseLibcall = (Size != Align ||
+ getContext().toBits(sizeChars) > MaxInlineWidthInBits);
+
+ llvm::Value *Ptr, *Order, *OrderFail = 0, *Val1 = 0, *Val2 = 0;
+ Ptr = EmitScalarExpr(E->getPtr());
+
+ if (E->getOp() == AtomicExpr::AO__c11_atomic_init) {
+ assert(!Dest && "Init does not return a value");
+ LValue lvalue = LValue::MakeAddr(Ptr, AtomicTy, alignChars, getContext());
+ EmitAtomicInit(E->getVal1(), lvalue);
+ return RValue::get(0);
+ }
+
+ Order = EmitScalarExpr(E->getOrder());
+
+ switch (E->getOp()) {
+ case AtomicExpr::AO__c11_atomic_init:
+ llvm_unreachable("Already handled!");
+
+ case AtomicExpr::AO__c11_atomic_load:
+ case AtomicExpr::AO__atomic_load_n:
+ break;
+
+ case AtomicExpr::AO__atomic_load:
+ Dest = EmitScalarExpr(E->getVal1());
+ break;
+
+ case AtomicExpr::AO__atomic_store:
+ Val1 = EmitScalarExpr(E->getVal1());
+ break;
+
+ case AtomicExpr::AO__atomic_exchange:
+ Val1 = EmitScalarExpr(E->getVal1());
+ Dest = EmitScalarExpr(E->getVal2());
+ break;
+
+ case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
+ case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
+ case AtomicExpr::AO__atomic_compare_exchange_n:
+ case AtomicExpr::AO__atomic_compare_exchange:
+ Val1 = EmitScalarExpr(E->getVal1());
+ if (E->getOp() == AtomicExpr::AO__atomic_compare_exchange)
+ Val2 = EmitScalarExpr(E->getVal2());
+ else
+ Val2 = EmitValToTemp(*this, E->getVal2());
+ OrderFail = EmitScalarExpr(E->getOrderFail());
+ // Evaluate and discard the 'weak' argument.
+ if (E->getNumSubExprs() == 6)
+ EmitScalarExpr(E->getWeak());
+ break;
+
+ case AtomicExpr::AO__c11_atomic_fetch_add:
+ case AtomicExpr::AO__c11_atomic_fetch_sub:
+ if (MemTy->isPointerType()) {
+ // For pointer arithmetic, we're required to do a bit of math:
+ // adding 1 to an int* is not the same as adding 1 to a uintptr_t.
+ // ... but only for the C11 builtins. The GNU builtins expect the
+ // user to multiply by sizeof(T).
+ QualType Val1Ty = E->getVal1()->getType();
+ llvm::Value *Val1Scalar = EmitScalarExpr(E->getVal1());
+ CharUnits PointeeIncAmt =
+ getContext().getTypeSizeInChars(MemTy->getPointeeType());
+ Val1Scalar = Builder.CreateMul(Val1Scalar, CGM.getSize(PointeeIncAmt));
+ Val1 = CreateMemTemp(Val1Ty, ".atomictmp");
+ EmitStoreOfScalar(Val1Scalar, MakeAddrLValue(Val1, Val1Ty));
+ break;
+ }
+ // Fall through.
+ case AtomicExpr::AO__atomic_fetch_add:
+ case AtomicExpr::AO__atomic_fetch_sub:
+ case AtomicExpr::AO__atomic_add_fetch:
+ case AtomicExpr::AO__atomic_sub_fetch:
+ case AtomicExpr::AO__c11_atomic_store:
+ case AtomicExpr::AO__c11_atomic_exchange:
+ case AtomicExpr::AO__atomic_store_n:
+ case AtomicExpr::AO__atomic_exchange_n:
+ case AtomicExpr::AO__c11_atomic_fetch_and:
+ case AtomicExpr::AO__c11_atomic_fetch_or:
+ case AtomicExpr::AO__c11_atomic_fetch_xor:
+ case AtomicExpr::AO__atomic_fetch_and:
+ case AtomicExpr::AO__atomic_fetch_or:
+ case AtomicExpr::AO__atomic_fetch_xor:
+ case AtomicExpr::AO__atomic_fetch_nand:
+ case AtomicExpr::AO__atomic_and_fetch:
+ case AtomicExpr::AO__atomic_or_fetch:
+ case AtomicExpr::AO__atomic_xor_fetch:
+ case AtomicExpr::AO__atomic_nand_fetch:
+ Val1 = EmitValToTemp(*this, E->getVal1());
+ break;
+ }
+
+ if (!E->getType()->isVoidType() && !Dest)
+ Dest = CreateMemTemp(E->getType(), ".atomicdst");
+
+ // Use a library call. See: http://gcc.gnu.org/wiki/Atomic/GCCMM/LIbrary .
+ if (UseLibcall) {
+
+ SmallVector<QualType, 5> Params;
+ CallArgList Args;
+ // Size is always the first parameter
+ Args.add(RValue::get(llvm::ConstantInt::get(SizeTy, Size)),
+ getContext().getSizeType());
+ // Atomic address is always the second parameter
+ Args.add(RValue::get(EmitCastToVoidPtr(Ptr)),
+ getContext().VoidPtrTy);
+
+ const char* LibCallName;
+ QualType RetTy = getContext().VoidTy;
+ switch (E->getOp()) {
+ // There is only one libcall for compare an exchange, because there is no
+ // optimisation benefit possible from a libcall version of a weak compare
+ // and exchange.
+ // bool __atomic_compare_exchange(size_t size, void *obj, void *expected,
+ // void *desired, int success, int failure)
+ case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
+ case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
+ case AtomicExpr::AO__atomic_compare_exchange:
+ case AtomicExpr::AO__atomic_compare_exchange_n:
+ LibCallName = "__atomic_compare_exchange";
+ RetTy = getContext().BoolTy;
+ Args.add(RValue::get(EmitCastToVoidPtr(Val1)),
+ getContext().VoidPtrTy);
+ Args.add(RValue::get(EmitCastToVoidPtr(Val2)),
+ getContext().VoidPtrTy);
+ Args.add(RValue::get(Order),
+ getContext().IntTy);
+ Order = OrderFail;
+ break;
+ // void __atomic_exchange(size_t size, void *mem, void *val, void *return,
+ // int order)
+ case AtomicExpr::AO__c11_atomic_exchange:
+ case AtomicExpr::AO__atomic_exchange_n:
+ case AtomicExpr::AO__atomic_exchange:
+ LibCallName = "__atomic_exchange";
+ Args.add(RValue::get(EmitCastToVoidPtr(Val1)),
+ getContext().VoidPtrTy);
+ Args.add(RValue::get(EmitCastToVoidPtr(Dest)),
+ getContext().VoidPtrTy);
+ break;
+ // void __atomic_store(size_t size, void *mem, void *val, int order)
+ case AtomicExpr::AO__c11_atomic_store:
+ case AtomicExpr::AO__atomic_store:
+ case AtomicExpr::AO__atomic_store_n:
+ LibCallName = "__atomic_store";
+ Args.add(RValue::get(EmitCastToVoidPtr(Val1)),
+ getContext().VoidPtrTy);
+ break;
+ // void __atomic_load(size_t size, void *mem, void *return, int order)
+ case AtomicExpr::AO__c11_atomic_load:
+ case AtomicExpr::AO__atomic_load:
+ case AtomicExpr::AO__atomic_load_n:
+ LibCallName = "__atomic_load";
+ Args.add(RValue::get(EmitCastToVoidPtr(Dest)),
+ getContext().VoidPtrTy);
+ break;
+#if 0
+ // These are only defined for 1-16 byte integers. It is not clear what
+ // their semantics would be on anything else...
+ case AtomicExpr::Add: LibCallName = "__atomic_fetch_add_generic"; break;
+ case AtomicExpr::Sub: LibCallName = "__atomic_fetch_sub_generic"; break;
+ case AtomicExpr::And: LibCallName = "__atomic_fetch_and_generic"; break;
+ case AtomicExpr::Or: LibCallName = "__atomic_fetch_or_generic"; break;
+ case AtomicExpr::Xor: LibCallName = "__atomic_fetch_xor_generic"; break;
+#endif
+ default: return EmitUnsupportedRValue(E, "atomic library call");
+ }
+ // order is always the last parameter
+ Args.add(RValue::get(Order),
+ getContext().IntTy);
+
+ const CGFunctionInfo &FuncInfo =
+ CGM.getTypes().arrangeFreeFunctionCall(RetTy, Args,
+ FunctionType::ExtInfo(), RequiredArgs::All);
+ llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FuncInfo);
+ llvm::Constant *Func = CGM.CreateRuntimeFunction(FTy, LibCallName);
+ RValue Res = EmitCall(FuncInfo, Func, ReturnValueSlot(), Args);
+ if (E->isCmpXChg())
+ return Res;
+ if (E->getType()->isVoidType())
+ return RValue::get(0);
+ return convertTempToRValue(Dest, E->getType());
+ }
+
+ bool IsStore = E->getOp() == AtomicExpr::AO__c11_atomic_store ||
+ E->getOp() == AtomicExpr::AO__atomic_store ||
+ E->getOp() == AtomicExpr::AO__atomic_store_n;
+ bool IsLoad = E->getOp() == AtomicExpr::AO__c11_atomic_load ||
+ E->getOp() == AtomicExpr::AO__atomic_load ||
+ E->getOp() == AtomicExpr::AO__atomic_load_n;
+
+ llvm::Type *IPtrTy =
+ llvm::IntegerType::get(getLLVMContext(), Size * 8)->getPointerTo();
+ llvm::Value *OrigDest = Dest;
+ Ptr = Builder.CreateBitCast(Ptr, IPtrTy);
+ if (Val1) Val1 = Builder.CreateBitCast(Val1, IPtrTy);
+ if (Val2) Val2 = Builder.CreateBitCast(Val2, IPtrTy);
+ if (Dest && !E->isCmpXChg()) Dest = Builder.CreateBitCast(Dest, IPtrTy);
+
+ if (isa<llvm::ConstantInt>(Order)) {
+ int ord = cast<llvm::ConstantInt>(Order)->getZExtValue();
+ switch (ord) {
+ case AO_ABI_memory_order_relaxed:
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::Monotonic);
+ break;
+ case AO_ABI_memory_order_consume:
+ case AO_ABI_memory_order_acquire:
+ if (IsStore)
+ break; // Avoid crashing on code with undefined behavior
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::Acquire);
+ break;
+ case AO_ABI_memory_order_release:
+ if (IsLoad)
+ break; // Avoid crashing on code with undefined behavior
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::Release);
+ break;
+ case AO_ABI_memory_order_acq_rel:
+ if (IsLoad || IsStore)
+ break; // Avoid crashing on code with undefined behavior
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::AcquireRelease);
+ break;
+ case AO_ABI_memory_order_seq_cst:
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::SequentiallyConsistent);
+ break;
+ default: // invalid order
+ // We should not ever get here normally, but it's hard to
+ // enforce that in general.
+ break;
+ }
+ if (E->getType()->isVoidType())
+ return RValue::get(0);
+ return convertTempToRValue(OrigDest, E->getType());
+ }
+
+ // Long case, when Order isn't obviously constant.
+
+ // Create all the relevant BB's
+ llvm::BasicBlock *MonotonicBB = 0, *AcquireBB = 0, *ReleaseBB = 0,
+ *AcqRelBB = 0, *SeqCstBB = 0;
+ MonotonicBB = createBasicBlock("monotonic", CurFn);
+ if (!IsStore)
+ AcquireBB = createBasicBlock("acquire", CurFn);
+ if (!IsLoad)
+ ReleaseBB = createBasicBlock("release", CurFn);
+ if (!IsLoad && !IsStore)
+ AcqRelBB = createBasicBlock("acqrel", CurFn);
+ SeqCstBB = createBasicBlock("seqcst", CurFn);
+ llvm::BasicBlock *ContBB = createBasicBlock("atomic.continue", CurFn);
+
+ // Create the switch for the split
+ // MonotonicBB is arbitrarily chosen as the default case; in practice, this
+ // doesn't matter unless someone is crazy enough to use something that
+ // doesn't fold to a constant for the ordering.
+ Order = Builder.CreateIntCast(Order, Builder.getInt32Ty(), false);
+ llvm::SwitchInst *SI = Builder.CreateSwitch(Order, MonotonicBB);
+
+ // Emit all the different atomics
+ Builder.SetInsertPoint(MonotonicBB);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::Monotonic);
+ Builder.CreateBr(ContBB);
+ if (!IsStore) {
+ Builder.SetInsertPoint(AcquireBB);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::Acquire);
+ Builder.CreateBr(ContBB);
+ SI->addCase(Builder.getInt32(1), AcquireBB);
+ SI->addCase(Builder.getInt32(2), AcquireBB);
+ }
+ if (!IsLoad) {
+ Builder.SetInsertPoint(ReleaseBB);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::Release);
+ Builder.CreateBr(ContBB);
+ SI->addCase(Builder.getInt32(3), ReleaseBB);
+ }
+ if (!IsLoad && !IsStore) {
+ Builder.SetInsertPoint(AcqRelBB);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::AcquireRelease);
+ Builder.CreateBr(ContBB);
+ SI->addCase(Builder.getInt32(4), AcqRelBB);
+ }
+ Builder.SetInsertPoint(SeqCstBB);
+ EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
+ llvm::SequentiallyConsistent);
+ Builder.CreateBr(ContBB);
+ SI->addCase(Builder.getInt32(5), SeqCstBB);
+
+ // Cleanup and return
+ Builder.SetInsertPoint(ContBB);
+ if (E->getType()->isVoidType())
+ return RValue::get(0);
+ return convertTempToRValue(OrigDest, E->getType());
+}
+
+llvm::Value *AtomicInfo::emitCastToAtomicIntPointer(llvm::Value *addr) const {
+ unsigned addrspace =
+ cast<llvm::PointerType>(addr->getType())->getAddressSpace();
+ llvm::IntegerType *ty =
+ llvm::IntegerType::get(CGF.getLLVMContext(), AtomicSizeInBits);
+ return CGF.Builder.CreateBitCast(addr, ty->getPointerTo(addrspace));
+}
+
+RValue AtomicInfo::convertTempToRValue(llvm::Value *addr,
+ AggValueSlot resultSlot) const {
+ if (EvaluationKind == TEK_Aggregate) {
+ // Nothing to do if the result is ignored.
+ if (resultSlot.isIgnored()) return resultSlot.asRValue();
+
+ assert(resultSlot.getAddr() == addr || hasPadding());
+
+ // In these cases, we should have emitted directly into the result slot.
+ if (!hasPadding() || resultSlot.isValueOfAtomic())
+ return resultSlot.asRValue();
+
+ // Otherwise, fall into the common path.
+ }
+
+ // Drill into the padding structure if we have one.
+ if (hasPadding())
+ addr = CGF.Builder.CreateStructGEP(addr, 0);
+
+ // If we're emitting to an aggregate, copy into the result slot.
+ if (EvaluationKind == TEK_Aggregate) {
+ CGF.EmitAggregateCopy(resultSlot.getAddr(), addr, getValueType(),
+ resultSlot.isVolatile());
+ return resultSlot.asRValue();
+ }
+
+ // Otherwise, just convert the temporary to an r-value using the
+ // normal conversion routine.
+ return CGF.convertTempToRValue(addr, getValueType());
+}
+
+/// Emit a load from an l-value of atomic type. Note that the r-value
+/// we produce is an r-value of the atomic *value* type.
+RValue CodeGenFunction::EmitAtomicLoad(LValue src, AggValueSlot resultSlot) {
+ AtomicInfo atomics(*this, src);
+
+ // Check whether we should use a library call.
+ if (atomics.shouldUseLibcall()) {
+ llvm::Value *tempAddr;
+ if (resultSlot.isValueOfAtomic()) {
+ assert(atomics.getEvaluationKind() == TEK_Aggregate);
+ tempAddr = resultSlot.getPaddedAtomicAddr();
+ } else if (!resultSlot.isIgnored() && !atomics.hasPadding()) {
+ assert(atomics.getEvaluationKind() == TEK_Aggregate);
+ tempAddr = resultSlot.getAddr();
+ } else {
+ tempAddr = CreateMemTemp(atomics.getAtomicType(), "atomic-load-temp");
+ }
+
+ // void __atomic_load(size_t size, void *mem, void *return, int order);
+ CallArgList args;
+ args.add(RValue::get(atomics.getAtomicSizeValue()),
+ getContext().getSizeType());
+ args.add(RValue::get(EmitCastToVoidPtr(src.getAddress())),
+ getContext().VoidPtrTy);
+ args.add(RValue::get(EmitCastToVoidPtr(tempAddr)),
+ getContext().VoidPtrTy);
+ args.add(RValue::get(llvm::ConstantInt::get(IntTy,
+ AO_ABI_memory_order_seq_cst)),
+ getContext().IntTy);
+ emitAtomicLibcall(*this, "__atomic_load", getContext().VoidTy, args);
+
+ // Produce the r-value.
+ return atomics.convertTempToRValue(tempAddr, resultSlot);
+ }
+
+ // Okay, we're doing this natively.
+ llvm::Value *addr = atomics.emitCastToAtomicIntPointer(src.getAddress());
+ llvm::LoadInst *load = Builder.CreateLoad(addr, "atomic-load");
+ load->setAtomic(llvm::SequentiallyConsistent);
+
+ // Other decoration.
+ load->setAlignment(src.getAlignment().getQuantity());
+ if (src.isVolatileQualified())
+ load->setVolatile(true);
+ if (src.getTBAAInfo())
+ CGM.DecorateInstruction(load, src.getTBAAInfo());
+
+ // Okay, turn that back into the original value type.
+ QualType valueType = atomics.getValueType();
+ llvm::Value *result = load;
+
+ // If we're ignoring an aggregate return, don't do anything.
+ if (atomics.getEvaluationKind() == TEK_Aggregate && resultSlot.isIgnored())
+ return RValue::getAggregate(0, false);
+
+ // The easiest way to do this this is to go through memory, but we
+ // try not to in some easy cases.
+ if (atomics.getEvaluationKind() == TEK_Scalar && !atomics.hasPadding()) {
+ llvm::Type *resultTy = CGM.getTypes().ConvertTypeForMem(valueType);
+ if (isa<llvm::IntegerType>(resultTy)) {
+ assert(result->getType() == resultTy);
+ result = EmitFromMemory(result, valueType);
+ } else if (isa<llvm::PointerType>(resultTy)) {
+ result = Builder.CreateIntToPtr(result, resultTy);
+ } else {
+ result = Builder.CreateBitCast(result, resultTy);
+ }
+ return RValue::get(result);
+ }
+
+ // Create a temporary. This needs to be big enough to hold the
+ // atomic integer.
+ llvm::Value *temp;
+ bool tempIsVolatile = false;
+ CharUnits tempAlignment;
+ if (atomics.getEvaluationKind() == TEK_Aggregate &&
+ (!atomics.hasPadding() || resultSlot.isValueOfAtomic())) {
+ assert(!resultSlot.isIgnored());
+ if (resultSlot.isValueOfAtomic()) {
+ temp = resultSlot.getPaddedAtomicAddr();
+ tempAlignment = atomics.getAtomicAlignment();
+ } else {
+ temp = resultSlot.getAddr();
+ tempAlignment = atomics.getValueAlignment();
+ }
+ tempIsVolatile = resultSlot.isVolatile();
+ } else {
+ temp = CreateMemTemp(atomics.getAtomicType(), "atomic-load-temp");
+ tempAlignment = atomics.getAtomicAlignment();
+ }
+
+ // Slam the integer into the temporary.
+ llvm::Value *castTemp = atomics.emitCastToAtomicIntPointer(temp);
+ Builder.CreateAlignedStore(result, castTemp, tempAlignment.getQuantity())
+ ->setVolatile(tempIsVolatile);
+
+ return atomics.convertTempToRValue(temp, resultSlot);
+}
+
+
+
+/// Copy an r-value into memory as part of storing to an atomic type.
+/// This needs to create a bit-pattern suitable for atomic operations.
+void AtomicInfo::emitCopyIntoMemory(RValue rvalue, LValue dest) const {
+ // If we have an r-value, the rvalue should be of the atomic type,
+ // which means that the caller is responsible for having zeroed
+ // any padding. Just do an aggregate copy of that type.
+ if (rvalue.isAggregate()) {
+ CGF.EmitAggregateCopy(dest.getAddress(),
+ rvalue.getAggregateAddr(),
+ getAtomicType(),
+ (rvalue.isVolatileQualified()
+ || dest.isVolatileQualified()),
+ dest.getAlignment());
+ return;
+ }
+
+ // Okay, otherwise we're copying stuff.
+
+ // Zero out the buffer if necessary.
+ emitMemSetZeroIfNecessary(dest);
+
+ // Drill past the padding if present.
+ dest = projectValue(dest);
+
+ // Okay, store the rvalue in.
+ if (rvalue.isScalar()) {
+ CGF.EmitStoreOfScalar(rvalue.getScalarVal(), dest, /*init*/ true);
+ } else {
+ CGF.EmitStoreOfComplex(rvalue.getComplexVal(), dest, /*init*/ true);
+ }
+}
+
+
+/// Materialize an r-value into memory for the purposes of storing it
+/// to an atomic type.
+llvm::Value *AtomicInfo::materializeRValue(RValue rvalue) const {
+ // Aggregate r-values are already in memory, and EmitAtomicStore
+ // requires them to be values of the atomic type.
+ if (rvalue.isAggregate())
+ return rvalue.getAggregateAddr();
+
+ // Otherwise, make a temporary and materialize into it.
+ llvm::Value *temp = CGF.CreateMemTemp(getAtomicType(), "atomic-store-temp");
+ LValue tempLV = CGF.MakeAddrLValue(temp, getAtomicType(), getAtomicAlignment());
+ emitCopyIntoMemory(rvalue, tempLV);
+ return temp;
+}
+
+/// Emit a store to an l-value of atomic type.
+///
+/// Note that the r-value is expected to be an r-value *of the atomic
+/// type*; this means that for aggregate r-values, it should include
+/// storage for any padding that was necessary.
+void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue dest,
+ bool isInit) {
+ // If this is an aggregate r-value, it should agree in type except
+ // maybe for address-space qualification.
+ assert(!rvalue.isAggregate() ||
+ rvalue.getAggregateAddr()->getType()->getPointerElementType()
+ == dest.getAddress()->getType()->getPointerElementType());
+
+ AtomicInfo atomics(*this, dest);
+
+ // If this is an initialization, just put the value there normally.
+ if (isInit) {
+ atomics.emitCopyIntoMemory(rvalue, dest);
+ return;
+ }
+
+ // Check whether we should use a library call.
+ if (atomics.shouldUseLibcall()) {
+ // Produce a source address.
+ llvm::Value *srcAddr = atomics.materializeRValue(rvalue);
+
+ // void __atomic_store(size_t size, void *mem, void *val, int order)
+ CallArgList args;
+ args.add(RValue::get(atomics.getAtomicSizeValue()),
+ getContext().getSizeType());
+ args.add(RValue::get(EmitCastToVoidPtr(dest.getAddress())),
+ getContext().VoidPtrTy);
+ args.add(RValue::get(EmitCastToVoidPtr(srcAddr)),
+ getContext().VoidPtrTy);
+ args.add(RValue::get(llvm::ConstantInt::get(IntTy,
+ AO_ABI_memory_order_seq_cst)),
+ getContext().IntTy);
+ emitAtomicLibcall(*this, "__atomic_store", getContext().VoidTy, args);
+ return;
+ }
+
+ // Okay, we're doing this natively.
+ llvm::Value *intValue;
+
+ // If we've got a scalar value of the right size, try to avoid going
+ // through memory.
+ if (rvalue.isScalar() && !atomics.hasPadding()) {
+ llvm::Value *value = rvalue.getScalarVal();
+ if (isa<llvm::IntegerType>(value->getType())) {
+ intValue = value;
+ } else {
+ llvm::IntegerType *inputIntTy =
+ llvm::IntegerType::get(getLLVMContext(), atomics.getValueSizeInBits());
+ if (isa<llvm::PointerType>(value->getType())) {
+ intValue = Builder.CreatePtrToInt(value, inputIntTy);
+ } else {
+ intValue = Builder.CreateBitCast(value, inputIntTy);
+ }
+ }
+
+ // Otherwise, we need to go through memory.
+ } else {
+ // Put the r-value in memory.
+ llvm::Value *addr = atomics.materializeRValue(rvalue);
+
+ // Cast the temporary to the atomic int type and pull a value out.
+ addr = atomics.emitCastToAtomicIntPointer(addr);
+ intValue = Builder.CreateAlignedLoad(addr,
+ atomics.getAtomicAlignment().getQuantity());
+ }
+
+ // Do the atomic store.
+ llvm::Value *addr = atomics.emitCastToAtomicIntPointer(dest.getAddress());
+ llvm::StoreInst *store = Builder.CreateStore(intValue, addr);
+
+ // Initializations don't need to be atomic.
+ if (!isInit) store->setAtomic(llvm::SequentiallyConsistent);
+
+ // Other decoration.
+ store->setAlignment(dest.getAlignment().getQuantity());
+ if (dest.isVolatileQualified())
+ store->setVolatile(true);
+ if (dest.getTBAAInfo())
+ CGM.DecorateInstruction(store, dest.getTBAAInfo());
+}
+
+void CodeGenFunction::EmitAtomicInit(Expr *init, LValue dest) {
+ AtomicInfo atomics(*this, dest);
+
+ switch (atomics.getEvaluationKind()) {
+ case TEK_Scalar: {
+ llvm::Value *value = EmitScalarExpr(init);
+ atomics.emitCopyIntoMemory(RValue::get(value), dest);
+ return;
+ }
+
+ case TEK_Complex: {
+ ComplexPairTy value = EmitComplexExpr(init);
+ atomics.emitCopyIntoMemory(RValue::getComplex(value), dest);
+ return;
+ }
+
+ case TEK_Aggregate: {
+ // Memset the buffer first if there's any possibility of
+ // uninitialized internal bits.
+ atomics.emitMemSetZeroIfNecessary(dest);
+
+ // HACK: whether the initializer actually has an atomic type
+ // doesn't really seem reliable right now.
+ if (!init->getType()->isAtomicType()) {
+ dest = atomics.projectValue(dest);
+ }
+
+ // Evaluate the expression directly into the destination.
+ AggValueSlot slot = AggValueSlot::forLValue(dest,
+ AggValueSlot::IsNotDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased);
+ EmitAggExpr(init, slot);
+ return;
+ }
+ }
+ llvm_unreachable("bad evaluation kind");
+}
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 6742f36..227ee2d 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -11,16 +11,18 @@
//
//===----------------------------------------------------------------------===//
+#include "CGBlocks.h"
#include "CGDebugInfo.h"
-#include "CodeGenFunction.h"
#include "CGObjCRuntime.h"
+#include "CodeGenFunction.h"
#include "CodeGenModule.h"
-#include "CGBlocks.h"
#include "clang/AST/DeclObjC.h"
-#include "llvm/Module.h"
#include "llvm/ADT/SmallSet.h"
-#include "llvm/DataLayout.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/CallSite.h"
#include <algorithm>
+#include <cstdio>
using namespace clang;
using namespace CodeGen;
@@ -181,13 +183,16 @@ namespace {
struct BlockLayoutChunk {
CharUnits Alignment;
CharUnits Size;
+ Qualifiers::ObjCLifetime Lifetime;
const BlockDecl::Capture *Capture; // null for 'this'
llvm::Type *Type;
BlockLayoutChunk(CharUnits align, CharUnits size,
+ Qualifiers::ObjCLifetime lifetime,
const BlockDecl::Capture *capture,
llvm::Type *type)
- : Alignment(align), Size(size), Capture(capture), Type(type) {}
+ : Alignment(align), Size(size), Lifetime(lifetime),
+ Capture(capture), Type(type) {}
/// Tell the block info that this chunk has the given field index.
void setIndex(CGBlockInfo &info, unsigned index) {
@@ -199,9 +204,35 @@ namespace {
}
};
- /// Order by descending alignment.
+ /// Order by 1) all __strong together 2) next, all byfref together 3) next,
+ /// all __weak together. Preserve descending alignment in all situations.
bool operator<(const BlockLayoutChunk &left, const BlockLayoutChunk &right) {
- return left.Alignment > right.Alignment;
+ CharUnits LeftValue, RightValue;
+ bool LeftByref = left.Capture ? left.Capture->isByRef() : false;
+ bool RightByref = right.Capture ? right.Capture->isByRef() : false;
+
+ if (left.Lifetime == Qualifiers::OCL_Strong &&
+ left.Alignment >= right.Alignment)
+ LeftValue = CharUnits::fromQuantity(64);
+ else if (LeftByref && left.Alignment >= right.Alignment)
+ LeftValue = CharUnits::fromQuantity(32);
+ else if (left.Lifetime == Qualifiers::OCL_Weak &&
+ left.Alignment >= right.Alignment)
+ LeftValue = CharUnits::fromQuantity(16);
+ else
+ LeftValue = left.Alignment;
+ if (right.Lifetime == Qualifiers::OCL_Strong &&
+ right.Alignment >= left.Alignment)
+ RightValue = CharUnits::fromQuantity(64);
+ else if (RightByref && right.Alignment >= left.Alignment)
+ RightValue = CharUnits::fromQuantity(32);
+ else if (right.Lifetime == Qualifiers::OCL_Weak &&
+ right.Alignment >= left.Alignment)
+ RightValue = CharUnits::fromQuantity(16);
+ else
+ RightValue = right.Alignment;
+
+ return LeftValue > RightValue;
}
}
@@ -217,7 +248,7 @@ static bool isSafeForCXXConstantCapture(QualType type) {
// Maintain semantics for classes with non-trivial dtors or copy ctors.
if (!record->hasTrivialDestructor()) return false;
- if (!record->hasTrivialCopyConstructor()) return false;
+ if (record->hasNonTrivialCopyConstructor()) return false;
// Otherwise, we just have to make sure there aren't any mutable
// fields that might have changed since initialization.
@@ -336,7 +367,9 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
= CGM.getContext().getTypeInfoInChars(thisType);
maxFieldAlign = std::max(maxFieldAlign, tinfo.second);
- layout.push_back(BlockLayoutChunk(tinfo.second, tinfo.first, 0, llvmType));
+ layout.push_back(BlockLayoutChunk(tinfo.second, tinfo.first,
+ Qualifiers::OCL_None,
+ 0, llvmType));
}
// Next, all the block captures.
@@ -357,6 +390,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
maxFieldAlign = std::max(maxFieldAlign, tinfo.second);
layout.push_back(BlockLayoutChunk(tinfo.second, tinfo.first,
+ Qualifiers::OCL_None,
&*ci, llvmType));
continue;
}
@@ -370,8 +404,9 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
// If we have a lifetime qualifier, honor it for capture purposes.
// That includes *not* copying it if it's __unsafe_unretained.
- if (Qualifiers::ObjCLifetime lifetime
- = variable->getType().getObjCLifetime()) {
+ Qualifiers::ObjCLifetime lifetime =
+ variable->getType().getObjCLifetime();
+ if (lifetime) {
switch (lifetime) {
case Qualifiers::OCL_None: llvm_unreachable("impossible");
case Qualifiers::OCL_ExplicitNone:
@@ -386,6 +421,8 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
// Block pointers require copy/dispose. So do Objective-C pointers.
} else if (variable->getType()->isObjCRetainableType()) {
info.NeedsCopyDispose = true;
+ // used for mrr below.
+ lifetime = Qualifiers::OCL_Strong;
// So do types that require non-trivial copy construction.
} else if (ci->hasCopyExpr()) {
@@ -412,7 +449,7 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
llvm::Type *llvmType =
CGM.getTypes().ConvertTypeForMem(VT);
- layout.push_back(BlockLayoutChunk(align, size, &*ci, llvmType));
+ layout.push_back(BlockLayoutChunk(align, size, lifetime, &*ci, llvmType));
}
// If that was everything, we're done here.
@@ -427,7 +464,11 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
// to get reproducible results. There should probably be an
// llvm::array_pod_stable_sort.
std::stable_sort(layout.begin(), layout.end());
-
+
+ // Needed for blocks layout info.
+ info.BlockHeaderForcedGapOffset = info.BlockSize;
+ info.BlockHeaderForcedGapSize = CharUnits::Zero();
+
CharUnits &blockSize = info.BlockSize;
info.BlockAlign = std::max(maxFieldAlign, info.BlockAlign);
@@ -468,17 +509,22 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
endAlign = getLowBit(blockSize);
// ...until we get to the alignment of the maximum field.
- if (endAlign >= maxFieldAlign)
+ if (endAlign >= maxFieldAlign) {
+ if (li == first) {
+ // No user field was appended. So, a gap was added.
+ // Save total gap size for use in block layout bit map.
+ info.BlockHeaderForcedGapSize = li->Size;
+ }
break;
+ }
}
-
// Don't re-append everything we just appended.
layout.erase(first, li);
}
}
assert(endAlign == getLowBit(blockSize));
-
+
// At this point, we just have to add padding if the end align still
// isn't aligned right.
if (endAlign < maxFieldAlign) {
@@ -493,7 +539,6 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
assert(endAlign >= maxFieldAlign);
assert(endAlign == getLowBit(blockSize));
-
// Slam everything else on now. This works because they have
// strictly decreasing alignment and we expect that size is always a
// multiple of alignment.
@@ -732,8 +777,16 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
// special; we'll simply emit it directly.
src = 0;
} else {
- // This is a [[type]]*.
- src = LocalDeclMap[variable];
+ // Just look it up in the locals map, which will give us back a
+ // [[type]]*. If that doesn't work, do the more elaborate DRE
+ // emission.
+ src = LocalDeclMap.lookup(variable);
+ if (!src) {
+ DeclRefExpr declRef(const_cast<VarDecl*>(variable),
+ /*refersToEnclosing*/ ci->isNested(), type,
+ VK_LValue, SourceLocation());
+ src = EmitDeclRefLValue(&declRef).getAddress();
+ }
}
// For byrefs, we just write the pointer to the byref struct into
@@ -896,7 +949,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E,
const FunctionType *FuncTy = FnType->castAs<FunctionType>();
const CGFunctionInfo &FnInfo =
- CGM.getTypes().arrangeFreeFunctionCall(Args, FuncTy);
+ CGM.getTypes().arrangeBlockFunctionCall(Args, FuncTy);
// Cast the function pointer to the right type.
llvm::Type *BlockFTy = CGM.getTypes().GetFunctionType(FnInfo);
@@ -1085,6 +1138,24 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
BlockPointer = Builder.CreateBitCast(blockAddr,
blockInfo.StructureType->getPointerTo(),
"block");
+ // At -O0 we generate an explicit alloca for the BlockPointer, so the RA
+ // won't delete the dbg.declare intrinsics for captured variables.
+ llvm::Value *BlockPointerDbgLoc = BlockPointer;
+ if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
+ // Allocate a stack slot for it, so we can point the debugger to it
+ llvm::AllocaInst *Alloca = CreateTempAlloca(BlockPointer->getType(),
+ "block.addr");
+ unsigned Align = getContext().getDeclAlign(&selfDecl).getQuantity();
+ Alloca->setAlignment(Align);
+ // Set the DebugLocation to empty, so the store is recognized as a
+ // frame setup instruction by llvm::DwarfDebug::beginFunction().
+ llvm::DebugLoc Empty;
+ llvm::DebugLoc Loc = Builder.getCurrentDebugLocation();
+ Builder.SetCurrentDebugLocation(Empty);
+ Builder.CreateAlignedStore(BlockPointer, Alloca, Align);
+ Builder.SetCurrentDebugLocation(Loc);
+ BlockPointerDbgLoc = Alloca;
+ }
// If we have a C++ 'this' reference, go ahead and force it into
// existence now.
@@ -1104,6 +1175,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
// There might not be a capture for 'self', but if there is...
if (blockInfo.Captures.count(self)) {
const CGBlockInfo::Capture &capture = blockInfo.getCapture(self);
+
llvm::Value *selfAddr = Builder.CreateStructGEP(BlockPointer,
capture.getIndex(),
"block.captured-self");
@@ -1124,7 +1196,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
CreateMemTemp(variable->getType(), "block.captured-const");
alloca->setAlignment(align);
- Builder.CreateStore(capture.getConstant(), alloca, align);
+ Builder.CreateAlignedStore(capture.getConstant(), alloca, align);
LocalDeclMap[variable] = alloca;
}
@@ -1163,10 +1235,13 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
continue;
}
- DI->EmitDeclareOfBlockDeclRefVariable(variable, BlockPointer,
+ DI->EmitDeclareOfBlockDeclRefVariable(variable, BlockPointerDbgLoc,
Builder, blockInfo);
}
}
+ // Recover location if it was changed in the above loop.
+ DI->EmitLocation(Builder,
+ cast<CompoundStmt>(blockDecl->getBody())->getRBracLoc());
}
// And resume where we left off.
@@ -1199,7 +1274,14 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
*/
-
+/// Generate the copy-helper function for a block closure object:
+/// static void block_copy_helper(block_t *dst, block_t *src);
+/// The runtime will have previously initialized 'dst' by doing a
+/// bit-copy of 'src'.
+///
+/// Note that this copies an entire block closure object to the heap;
+/// it should not be confused with a 'byref copy helper', which moves
+/// the contents of an individual __block variable to the heap.
llvm::Constant *
CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
ASTContext &C = getContext();
@@ -1234,7 +1316,6 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
SourceLocation(),
SourceLocation(), II, C.VoidTy, 0,
SC_Static,
- SC_None,
false,
false);
StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
@@ -1344,8 +1425,24 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
} else {
srcValue = Builder.CreateBitCast(srcValue, VoidPtrTy);
llvm::Value *dstAddr = Builder.CreateBitCast(dstField, VoidPtrTy);
- Builder.CreateCall3(CGM.getBlockObjectAssign(), dstAddr, srcValue,
- llvm::ConstantInt::get(Int32Ty, flags.getBitMask()));
+ llvm::Value *args[] = {
+ dstAddr, srcValue, llvm::ConstantInt::get(Int32Ty, flags.getBitMask())
+ };
+
+ bool copyCanThrow = false;
+ if (ci->isByRef() && variable->getType()->getAsCXXRecordDecl()) {
+ const Expr *copyExpr =
+ CGM.getContext().getBlockVarCopyInits(variable);
+ if (copyExpr) {
+ copyCanThrow = true; // FIXME: reuse the noexcept logic
+ }
+ }
+
+ if (copyCanThrow) {
+ EmitRuntimeCallOrInvoke(CGM.getBlockObjectAssign(), args);
+ } else {
+ EmitNounwindRuntimeCall(CGM.getBlockObjectAssign(), args);
+ }
}
}
}
@@ -1355,6 +1452,13 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) {
return llvm::ConstantExpr::getBitCast(Fn, VoidPtrTy);
}
+/// Generate the destroy-helper function for a block closure object:
+/// static void block_destroy_helper(block_t *theBlock);
+///
+/// Note that this destroys a heap-allocated block closure object;
+/// it should not be confused with a 'byref destroy helper', which
+/// destroys the heap-allocated contents of an individual __block
+/// variable.
llvm::Constant *
CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
ASTContext &C = getContext();
@@ -1386,7 +1490,6 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
SourceLocation(),
SourceLocation(), II, C.VoidTy, 0,
SC_Static,
- SC_None,
false, false);
StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation());
@@ -1461,7 +1564,7 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) {
// Destroy strong objects with a call if requested.
} else if (useARCStrongDestroy) {
- EmitARCDestroyStrong(srcField, /*precise*/ false);
+ EmitARCDestroyStrong(srcField, ARCImpreciseLifetime);
// Otherwise we call _Block_object_dispose. It wouldn't be too
// hard to just emit this as a cleanup if we wanted to make sure
@@ -1501,7 +1604,9 @@ public:
llvm::Value *flagsVal = llvm::ConstantInt::get(CGF.Int32Ty, flags);
llvm::Value *fn = CGF.CGM.getBlockObjectAssign();
- CGF.Builder.CreateCall3(fn, destField, srcValue, flagsVal);
+
+ llvm::Value *args[] = { destField, srcValue, flagsVal };
+ CGF.EmitNounwindRuntimeCall(fn, args);
}
void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
@@ -1553,6 +1658,13 @@ public:
llvm::Value *null =
llvm::ConstantPointerNull::get(cast<llvm::PointerType>(value->getType()));
+ if (CGF.CGM.getCodeGenOpts().OptimizationLevel == 0) {
+ llvm::StoreInst *store = CGF.Builder.CreateStore(null, destField);
+ store->setAlignment(Alignment.getQuantity());
+ CGF.EmitARCStoreStrongCall(destField, value, /*ignored*/ true);
+ CGF.EmitARCStoreStrongCall(srcField, null, /*ignored*/ true);
+ return;
+ }
llvm::StoreInst *store = CGF.Builder.CreateStore(value, destField);
store->setAlignment(Alignment.getQuantity());
@@ -1561,7 +1673,7 @@ public:
}
void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
- CGF.EmitARCDestroyStrong(field, /*precise*/ false);
+ CGF.EmitARCDestroyStrong(field, ARCImpreciseLifetime);
}
void profileImpl(llvm::FoldingSetNodeID &id) const {
@@ -1591,7 +1703,7 @@ public:
}
void emitDispose(CodeGenFunction &CGF, llvm::Value *field) {
- CGF.EmitARCDestroyStrong(field, /*precise*/ false);
+ CGF.EmitARCDestroyStrong(field, ARCImpreciseLifetime);
}
void profileImpl(llvm::FoldingSetNodeID &id) const {
@@ -1633,6 +1745,7 @@ public:
static llvm::Constant *
generateByrefCopyHelper(CodeGenFunction &CGF,
llvm::StructType &byrefType,
+ unsigned valueFieldIndex,
CodeGenModule::ByrefHelpers &byrefInfo) {
ASTContext &Context = CGF.getContext();
@@ -1667,7 +1780,6 @@ generateByrefCopyHelper(CodeGenFunction &CGF,
SourceLocation(),
SourceLocation(), II, R, 0,
SC_Static,
- SC_None,
false, false);
// Initialize debug info if necessary.
@@ -1681,13 +1793,13 @@ generateByrefCopyHelper(CodeGenFunction &CGF,
llvm::Value *destField = CGF.GetAddrOfLocalVar(&dst);
destField = CGF.Builder.CreateLoad(destField);
destField = CGF.Builder.CreateBitCast(destField, byrefPtrType);
- destField = CGF.Builder.CreateStructGEP(destField, 6, "x");
+ destField = CGF.Builder.CreateStructGEP(destField, valueFieldIndex, "x");
// src->x
llvm::Value *srcField = CGF.GetAddrOfLocalVar(&src);
srcField = CGF.Builder.CreateLoad(srcField);
srcField = CGF.Builder.CreateBitCast(srcField, byrefPtrType);
- srcField = CGF.Builder.CreateStructGEP(srcField, 6, "x");
+ srcField = CGF.Builder.CreateStructGEP(srcField, valueFieldIndex, "x");
byrefInfo.emitCopy(CGF, destField, srcField);
}
@@ -1700,15 +1812,17 @@ generateByrefCopyHelper(CodeGenFunction &CGF,
/// Build the copy helper for a __block variable.
static llvm::Constant *buildByrefCopyHelper(CodeGenModule &CGM,
llvm::StructType &byrefType,
+ unsigned byrefValueIndex,
CodeGenModule::ByrefHelpers &info) {
CodeGenFunction CGF(CGM);
- return generateByrefCopyHelper(CGF, byrefType, info);
+ return generateByrefCopyHelper(CGF, byrefType, byrefValueIndex, info);
}
/// Generate code for a __block variable's dispose helper.
static llvm::Constant *
generateByrefDisposeHelper(CodeGenFunction &CGF,
llvm::StructType &byrefType,
+ unsigned byrefValueIndex,
CodeGenModule::ByrefHelpers &byrefInfo) {
ASTContext &Context = CGF.getContext();
QualType R = Context.VoidTy;
@@ -1740,7 +1854,6 @@ generateByrefDisposeHelper(CodeGenFunction &CGF,
SourceLocation(),
SourceLocation(), II, R, 0,
SC_Static,
- SC_None,
false, false);
// Initialize debug info if necessary.
CGF.maybeInitializeDebugInfo();
@@ -1750,7 +1863,7 @@ generateByrefDisposeHelper(CodeGenFunction &CGF,
llvm::Value *V = CGF.GetAddrOfLocalVar(&src);
V = CGF.Builder.CreateLoad(V);
V = CGF.Builder.CreateBitCast(V, byrefType.getPointerTo(0));
- V = CGF.Builder.CreateStructGEP(V, 6, "x");
+ V = CGF.Builder.CreateStructGEP(V, byrefValueIndex, "x");
byrefInfo.emitDispose(CGF, V);
}
@@ -1763,14 +1876,17 @@ generateByrefDisposeHelper(CodeGenFunction &CGF,
/// Build the dispose helper for a __block variable.
static llvm::Constant *buildByrefDisposeHelper(CodeGenModule &CGM,
llvm::StructType &byrefType,
+ unsigned byrefValueIndex,
CodeGenModule::ByrefHelpers &info) {
CodeGenFunction CGF(CGM);
- return generateByrefDisposeHelper(CGF, byrefType, info);
+ return generateByrefDisposeHelper(CGF, byrefType, byrefValueIndex, info);
}
-///
+/// Lazily build the copy and dispose helpers for a __block variable
+/// with the given information.
template <class T> static T *buildByrefHelpers(CodeGenModule &CGM,
llvm::StructType &byrefTy,
+ unsigned byrefValueIndex,
T &byrefInfo) {
// Increase the field's alignment to be at least pointer alignment,
// since the layout of the byref struct will guarantee at least that.
@@ -1785,26 +1901,33 @@ template <class T> static T *buildByrefHelpers(CodeGenModule &CGM,
= CGM.ByrefHelpersCache.FindNodeOrInsertPos(id, insertPos);
if (node) return static_cast<T*>(node);
- byrefInfo.CopyHelper = buildByrefCopyHelper(CGM, byrefTy, byrefInfo);
- byrefInfo.DisposeHelper = buildByrefDisposeHelper(CGM, byrefTy, byrefInfo);
+ byrefInfo.CopyHelper =
+ buildByrefCopyHelper(CGM, byrefTy, byrefValueIndex, byrefInfo);
+ byrefInfo.DisposeHelper =
+ buildByrefDisposeHelper(CGM, byrefTy, byrefValueIndex,byrefInfo);
T *copy = new (CGM.getContext()) T(byrefInfo);
CGM.ByrefHelpersCache.InsertNode(copy, insertPos);
return copy;
}
+/// Build the copy and dispose helpers for the given __block variable
+/// emission. Places the helpers in the global cache. Returns null
+/// if no helpers are required.
CodeGenModule::ByrefHelpers *
CodeGenFunction::buildByrefHelpers(llvm::StructType &byrefType,
const AutoVarEmission &emission) {
const VarDecl &var = *emission.Variable;
QualType type = var.getType();
+ unsigned byrefValueIndex = getByRefValueLLVMField(&var);
+
if (const CXXRecordDecl *record = type->getAsCXXRecordDecl()) {
const Expr *copyExpr = CGM.getContext().getBlockVarCopyInits(&var);
if (!copyExpr && record->hasTrivialDestructor()) return 0;
CXXByrefHelpers byrefInfo(emission.Alignment, type, copyExpr);
- return ::buildByrefHelpers(CGM, byrefType, byrefInfo);
+ return ::buildByrefHelpers(CGM, byrefType, byrefValueIndex, byrefInfo);
}
// Otherwise, if we don't have a retainable type, there's nothing to do.
@@ -1829,7 +1952,7 @@ CodeGenFunction::buildByrefHelpers(llvm::StructType &byrefType,
// byref routines.
case Qualifiers::OCL_Weak: {
ARCWeakByrefHelpers byrefInfo(emission.Alignment);
- return ::buildByrefHelpers(CGM, byrefType, byrefInfo);
+ return ::buildByrefHelpers(CGM, byrefType, byrefValueIndex, byrefInfo);
}
// ARC __strong __block variables need to be retained.
@@ -1838,13 +1961,13 @@ CodeGenFunction::buildByrefHelpers(llvm::StructType &byrefType,
// transfer possible.
if (type->isBlockPointerType()) {
ARCStrongBlockByrefHelpers byrefInfo(emission.Alignment);
- return ::buildByrefHelpers(CGM, byrefType, byrefInfo);
+ return ::buildByrefHelpers(CGM, byrefType, byrefValueIndex, byrefInfo);
// Otherwise, we transfer ownership of the retain from the stack
// to the heap.
} else {
ARCStrongByrefHelpers byrefInfo(emission.Alignment);
- return ::buildByrefHelpers(CGM, byrefType, byrefInfo);
+ return ::buildByrefHelpers(CGM, byrefType, byrefValueIndex, byrefInfo);
}
}
llvm_unreachable("fell out of lifetime switch!");
@@ -1864,7 +1987,7 @@ CodeGenFunction::buildByrefHelpers(llvm::StructType &byrefType,
flags |= BLOCK_FIELD_IS_WEAK;
ObjectByrefHelpers byrefInfo(emission.Alignment, flags);
- return ::buildByrefHelpers(CGM, byrefType, byrefInfo);
+ return ::buildByrefHelpers(CGM, byrefType, byrefValueIndex, byrefInfo);
}
unsigned CodeGenFunction::getByRefValueLLVMField(const ValueDecl *VD) const {
@@ -1892,6 +2015,7 @@ llvm::Value *CodeGenFunction::BuildBlockByrefAddress(llvm::Value *BaseAddr,
/// int32_t __size;
/// void *__copy_helper; // only if needed
/// void *__destroy_helper; // only if needed
+/// void *__byref_variable_layout;// only if needed
/// char padding[X]; // only if needed
/// T x;
/// } x
@@ -1920,9 +2044,8 @@ llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) {
// int32_t __size;
types.push_back(Int32Ty);
-
- bool HasCopyAndDispose =
- (Ty->isObjCRetainableType()) || getContext().getBlockVarCopyInits(D);
+ // Note that this must match *exactly* the logic in buildByrefHelpers.
+ bool HasCopyAndDispose = getContext().BlockRequiresCopying(Ty, D);
if (HasCopyAndDispose) {
/// void *__copy_helper;
types.push_back(Int8PtrTy);
@@ -1930,6 +2053,12 @@ llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) {
/// void *__destroy_helper;
types.push_back(Int8PtrTy);
}
+ bool HasByrefExtendedLayout = false;
+ Qualifiers::ObjCLifetime Lifetime;
+ if (getContext().getByrefLifetime(Ty, Lifetime, HasByrefExtendedLayout) &&
+ HasByrefExtendedLayout)
+ /// void *__byref_variable_layout;
+ types.push_back(Int8PtrTy);
bool Packed = false;
CharUnits Align = getContext().getDeclAlign(D);
@@ -1939,9 +2068,14 @@ llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) {
// The struct above has 2 32-bit integers.
unsigned CurrentOffsetInBytes = 4 * 2;
- // And either 2 or 4 pointers.
- CurrentOffsetInBytes += (HasCopyAndDispose ? 4 : 2) *
- CGM.getDataLayout().getTypeAllocSize(Int8PtrTy);
+ // And either 2, 3, 4 or 5 pointers.
+ unsigned noPointers = 2;
+ if (HasCopyAndDispose)
+ noPointers += 2;
+ if (HasByrefExtendedLayout)
+ noPointers += 1;
+
+ CurrentOffsetInBytes += noPointers * CGM.getDataLayout().getTypeAllocSize(Int8PtrTy);
// Align the offset.
unsigned AlignedOffsetInBytes =
@@ -1991,6 +2125,11 @@ void CodeGenFunction::emitByrefStructureInit(const AutoVarEmission &emission) {
const VarDecl &D = *emission.Variable;
QualType type = D.getType();
+ bool HasByrefExtendedLayout;
+ Qualifiers::ObjCLifetime ByrefLifetime;
+ bool ByRefHasLifetime =
+ getContext().getByrefLifetime(type, ByrefLifetime, HasByrefExtendedLayout);
+
llvm::Value *V;
// Initialize the 'isa', which is just 0 or 1.
@@ -2006,9 +2145,49 @@ void CodeGenFunction::emitByrefStructureInit(const AutoVarEmission &emission) {
// Blocks ABI:
// c) the flags field is set to either 0 if no helper functions are
- // needed or BLOCK_HAS_COPY_DISPOSE if they are,
+ // needed or BLOCK_BYREF_HAS_COPY_DISPOSE if they are,
BlockFlags flags;
- if (helpers) flags |= BLOCK_HAS_COPY_DISPOSE;
+ if (helpers) flags |= BLOCK_BYREF_HAS_COPY_DISPOSE;
+ if (ByRefHasLifetime) {
+ if (HasByrefExtendedLayout) flags |= BLOCK_BYREF_LAYOUT_EXTENDED;
+ else switch (ByrefLifetime) {
+ case Qualifiers::OCL_Strong:
+ flags |= BLOCK_BYREF_LAYOUT_STRONG;
+ break;
+ case Qualifiers::OCL_Weak:
+ flags |= BLOCK_BYREF_LAYOUT_WEAK;
+ break;
+ case Qualifiers::OCL_ExplicitNone:
+ flags |= BLOCK_BYREF_LAYOUT_UNRETAINED;
+ break;
+ case Qualifiers::OCL_None:
+ if (!type->isObjCObjectPointerType() && !type->isBlockPointerType())
+ flags |= BLOCK_BYREF_LAYOUT_NON_OBJECT;
+ break;
+ default:
+ break;
+ }
+ if (CGM.getLangOpts().ObjCGCBitmapPrint) {
+ printf("\n Inline flag for BYREF variable layout (%d):", flags.getBitMask());
+ if (flags & BLOCK_BYREF_HAS_COPY_DISPOSE)
+ printf(" BLOCK_BYREF_HAS_COPY_DISPOSE");
+ if (flags & BLOCK_BYREF_LAYOUT_MASK) {
+ BlockFlags ThisFlag(flags.getBitMask() & BLOCK_BYREF_LAYOUT_MASK);
+ if (ThisFlag == BLOCK_BYREF_LAYOUT_EXTENDED)
+ printf(" BLOCK_BYREF_LAYOUT_EXTENDED");
+ if (ThisFlag == BLOCK_BYREF_LAYOUT_STRONG)
+ printf(" BLOCK_BYREF_LAYOUT_STRONG");
+ if (ThisFlag == BLOCK_BYREF_LAYOUT_WEAK)
+ printf(" BLOCK_BYREF_LAYOUT_WEAK");
+ if (ThisFlag == BLOCK_BYREF_LAYOUT_UNRETAINED)
+ printf(" BLOCK_BYREF_LAYOUT_UNRETAINED");
+ if (ThisFlag == BLOCK_BYREF_LAYOUT_NON_OBJECT)
+ printf(" BLOCK_BYREF_LAYOUT_NON_OBJECT");
+ }
+ printf("\n");
+ }
+ }
+
Builder.CreateStore(llvm::ConstantInt::get(IntTy, flags.getBitMask()),
Builder.CreateStructGEP(addr, 2, "byref.flags"));
@@ -2023,14 +2202,25 @@ void CodeGenFunction::emitByrefStructureInit(const AutoVarEmission &emission) {
llvm::Value *destroy_helper = Builder.CreateStructGEP(addr, 5);
Builder.CreateStore(helpers->DisposeHelper, destroy_helper);
}
+ if (ByRefHasLifetime && HasByrefExtendedLayout) {
+ llvm::Constant* ByrefLayoutInfo = CGM.getObjCRuntime().BuildByrefLayout(CGM, type);
+ llvm::Value *ByrefInfoAddr = Builder.CreateStructGEP(addr, helpers ? 6 : 4,
+ "byref.layout");
+ // cast destination to pointer to source type.
+ llvm::Type *DesTy = ByrefLayoutInfo->getType();
+ DesTy = DesTy->getPointerTo();
+ llvm::Value *BC = Builder.CreatePointerCast(ByrefInfoAddr, DesTy);
+ Builder.CreateStore(ByrefLayoutInfo, BC);
+ }
}
void CodeGenFunction::BuildBlockRelease(llvm::Value *V, BlockFieldFlags flags) {
llvm::Value *F = CGM.getBlockObjectDispose();
- llvm::Value *N;
- V = Builder.CreateBitCast(V, Int8PtrTy);
- N = llvm::ConstantInt::get(Int32Ty, flags.getBitMask());
- Builder.CreateCall2(F, V, N);
+ llvm::Value *args[] = {
+ Builder.CreateBitCast(V, Int8PtrTy),
+ llvm::ConstantInt::get(Int32Ty, flags.getBitMask())
+ };
+ EmitNounwindRuntimeCall(F, args); // FIXME: throwing destructors?
}
namespace {
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index f85701a..020638a 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -14,19 +14,18 @@
#ifndef CLANG_CODEGEN_CGBLOCKS_H
#define CLANG_CODEGEN_CGBLOCKS_H
+#include "CGBuilder.h"
+#include "CGCall.h"
+#include "CGValue.h"
+#include "CodeGenFunction.h"
#include "CodeGenTypes.h"
-#include "clang/AST/Type.h"
-#include "llvm/Module.h"
-#include "clang/Basic/TargetInfo.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
-
-#include "CodeGenFunction.h"
-#include "CGBuilder.h"
-#include "CGCall.h"
-#include "CGValue.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/IR/Module.h"
namespace llvm {
class Module;
@@ -69,11 +68,12 @@ enum BlockLiteralFlags {
class BlockFlags {
uint32_t flags;
- BlockFlags(uint32_t flags) : flags(flags) {}
public:
+ BlockFlags(uint32_t flags) : flags(flags) {}
BlockFlags() : flags(0) {}
BlockFlags(BlockLiteralFlags flag) : flags(flag) {}
-
+ BlockFlags(BlockByrefFlags flag) : flags(flag) {}
+
uint32_t getBitMask() const { return flags; }
bool empty() const { return flags == 0; }
@@ -87,6 +87,9 @@ public:
friend bool operator&(BlockFlags l, BlockFlags r) {
return (l.flags & r.flags);
}
+ bool operator==(BlockFlags r) {
+ return (flags == r.flags);
+ }
};
inline BlockFlags operator|(BlockLiteralFlags l, BlockLiteralFlags r) {
return BlockFlags(l) | BlockFlags(r);
@@ -141,7 +144,7 @@ inline BlockFieldFlags operator|(BlockFieldFlag_t l, BlockFieldFlag_t r) {
class CGBlockInfo {
public:
/// Name - The name of the block, kindof.
- llvm::StringRef Name;
+ StringRef Name;
/// The field index of 'this' within the block, if there is one.
unsigned CXXThisIndex;
@@ -208,6 +211,14 @@ public:
const BlockExpr *BlockExpression;
CharUnits BlockSize;
CharUnits BlockAlign;
+
+ // Offset of the gap caused by block header having a smaller
+ // alignment than the alignment of the block descriptor. This
+ // is the gap offset before the first capturued field.
+ CharUnits BlockHeaderForcedGapOffset;
+ // Gap size caused by aligning first field after block header.
+ // This could be zero if no forced alignment is required.
+ CharUnits BlockHeaderForcedGapSize;
/// An instruction which dominates the full-expression that the
/// block is inside.
@@ -236,7 +247,7 @@ public:
return BlockExpression;
}
- CGBlockInfo(const BlockDecl *blockDecl, llvm::StringRef Name);
+ CGBlockInfo(const BlockDecl *blockDecl, StringRef Name);
};
} // end namespace CodeGen
diff --git a/lib/CodeGen/CGBuilder.h b/lib/CodeGen/CGBuilder.h
index a790a74..fd21e7e 100644
--- a/lib/CodeGen/CGBuilder.h
+++ b/lib/CodeGen/CGBuilder.h
@@ -10,7 +10,7 @@
#ifndef CLANG_CODEGEN_CGBUILDER_H
#define CLANG_CODEGEN_CGBUILDER_H
-#include "llvm/IRBuilder.h"
+#include "llvm/IR/IRBuilder.h"
namespace clang {
namespace CodeGen {
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index e8c05d3..3c89652 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -11,16 +11,16 @@
//
//===----------------------------------------------------------------------===//
-#include "TargetInfo.h"
#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
#include "CGObjCRuntime.h"
-#include "clang/Basic/TargetInfo.h"
+#include "CodeGenModule.h"
+#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/Basic/TargetBuiltins.h"
-#include "llvm/Intrinsics.h"
-#include "llvm/DataLayout.h"
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Intrinsics.h"
using namespace clang;
using namespace CodeGen;
@@ -160,7 +160,7 @@ static Value *EmitFAbs(CodeGenFunction &CGF, Value *V, QualType ValTy) {
false);
llvm::Value *Fn = CGF.CGM.CreateRuntimeFunction(FT, FnName);
- return CGF.Builder.CreateCall(Fn, V, "abs");
+ return CGF.EmitNounwindRuntimeCall(Fn, V, "abs");
}
static RValue emitLibraryCall(CodeGenFunction &CGF, const FunctionDecl *Fn,
@@ -169,6 +169,30 @@ static RValue emitLibraryCall(CodeGenFunction &CGF, const FunctionDecl *Fn,
ReturnValueSlot(), E->arg_begin(), E->arg_end(), Fn);
}
+/// \brief Emit a call to llvm.{sadd,uadd,ssub,usub,smul,umul}.with.overflow.*
+/// depending on IntrinsicID.
+///
+/// \arg CGF The current codegen function.
+/// \arg IntrinsicID The ID for the Intrinsic we wish to generate.
+/// \arg X The first argument to the llvm.*.with.overflow.*.
+/// \arg Y The second argument to the llvm.*.with.overflow.*.
+/// \arg Carry The carry returned by the llvm.*.with.overflow.*.
+/// \returns The result (i.e. sum/product) returned by the intrinsic.
+static llvm::Value *EmitOverflowIntrinsic(CodeGenFunction &CGF,
+ const llvm::Intrinsic::ID IntrinsicID,
+ llvm::Value *X, llvm::Value *Y,
+ llvm::Value *&Carry) {
+ // Make sure we have integers of the same width.
+ assert(X->getType() == Y->getType() &&
+ "Arguments must be the same type. (Did you forget to make sure both "
+ "arguments have the same integer width?)");
+
+ llvm::Value *Callee = CGF.CGM.getIntrinsic(IntrinsicID, X->getType());
+ llvm::Value *Tmp = CGF.Builder.CreateCall2(Callee, X, Y);
+ Carry = CGF.Builder.CreateExtractValue(Tmp, 1);
+ return CGF.Builder.CreateExtractValue(Tmp, 0);
+}
+
RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
unsigned BuiltinID, const CallExpr *E) {
// See if we can constant fold this builtin. If so, don't emit it at all.
@@ -244,14 +268,20 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
}
case Builtin::BI__builtin_creal:
case Builtin::BI__builtin_crealf:
- case Builtin::BI__builtin_creall: {
+ case Builtin::BI__builtin_creall:
+ case Builtin::BIcreal:
+ case Builtin::BIcrealf:
+ case Builtin::BIcreall: {
ComplexPairTy ComplexVal = EmitComplexExpr(E->getArg(0));
return RValue::get(ComplexVal.first);
}
case Builtin::BI__builtin_cimag:
case Builtin::BI__builtin_cimagf:
- case Builtin::BI__builtin_cimagl: {
+ case Builtin::BI__builtin_cimagl:
+ case Builtin::BIcimag:
+ case Builtin::BIcimagf:
+ case Builtin::BIcimagl: {
ComplexPairTy ComplexVal = EmitComplexExpr(E->getArg(0));
return RValue::get(ComplexVal.second);
}
@@ -406,10 +436,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(Builder.CreateCall(F));
}
case Builtin::BI__builtin_unreachable: {
- if (getLangOpts().SanitizeUnreachable)
+ if (SanOpts->Unreachable)
EmitCheck(Builder.getFalse(), "builtin_unreachable",
EmitCheckSourceLocation(E->getExprLoc()),
- llvm::ArrayRef<llvm::Value *>());
+ ArrayRef<llvm::Value *>(), CRK_Unrecoverable);
else
Builder.CreateUnreachable();
@@ -1312,9 +1342,74 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
// Get the annotation string, go through casts. Sema requires this to be a
// non-wide string literal, potentially casted, so the cast<> is safe.
const Expr *AnnotationStrExpr = E->getArg(1)->IgnoreParenCasts();
- llvm::StringRef Str = cast<StringLiteral>(AnnotationStrExpr)->getString();
+ StringRef Str = cast<StringLiteral>(AnnotationStrExpr)->getString();
return RValue::get(EmitAnnotationCall(F, AnnVal, Str, E->getExprLoc()));
}
+ case Builtin::BI__builtin_addcs:
+ case Builtin::BI__builtin_addc:
+ case Builtin::BI__builtin_addcl:
+ case Builtin::BI__builtin_addcll:
+ case Builtin::BI__builtin_subcs:
+ case Builtin::BI__builtin_subc:
+ case Builtin::BI__builtin_subcl:
+ case Builtin::BI__builtin_subcll: {
+
+ // We translate all of these builtins from expressions of the form:
+ // int x = ..., y = ..., carryin = ..., carryout, result;
+ // result = __builtin_addc(x, y, carryin, &carryout);
+ //
+ // to LLVM IR of the form:
+ //
+ // %tmp1 = call {i32, i1} @llvm.uadd.with.overflow.i32(i32 %x, i32 %y)
+ // %tmpsum1 = extractvalue {i32, i1} %tmp1, 0
+ // %carry1 = extractvalue {i32, i1} %tmp1, 1
+ // %tmp2 = call {i32, i1} @llvm.uadd.with.overflow.i32(i32 %tmpsum1,
+ // i32 %carryin)
+ // %result = extractvalue {i32, i1} %tmp2, 0
+ // %carry2 = extractvalue {i32, i1} %tmp2, 1
+ // %tmp3 = or i1 %carry1, %carry2
+ // %tmp4 = zext i1 %tmp3 to i32
+ // store i32 %tmp4, i32* %carryout
+
+ // Scalarize our inputs.
+ llvm::Value *X = EmitScalarExpr(E->getArg(0));
+ llvm::Value *Y = EmitScalarExpr(E->getArg(1));
+ llvm::Value *Carryin = EmitScalarExpr(E->getArg(2));
+ std::pair<llvm::Value*, unsigned> CarryOutPtr =
+ EmitPointerWithAlignment(E->getArg(3));
+
+ // Decide if we are lowering to a uadd.with.overflow or usub.with.overflow.
+ llvm::Intrinsic::ID IntrinsicId;
+ switch (BuiltinID) {
+ default: llvm_unreachable("Unknown multiprecision builtin id.");
+ case Builtin::BI__builtin_addcs:
+ case Builtin::BI__builtin_addc:
+ case Builtin::BI__builtin_addcl:
+ case Builtin::BI__builtin_addcll:
+ IntrinsicId = llvm::Intrinsic::uadd_with_overflow;
+ break;
+ case Builtin::BI__builtin_subcs:
+ case Builtin::BI__builtin_subc:
+ case Builtin::BI__builtin_subcl:
+ case Builtin::BI__builtin_subcll:
+ IntrinsicId = llvm::Intrinsic::usub_with_overflow;
+ break;
+ }
+
+ // Construct our resulting LLVM IR expression.
+ llvm::Value *Carry1;
+ llvm::Value *Sum1 = EmitOverflowIntrinsic(*this, IntrinsicId,
+ X, Y, Carry1);
+ llvm::Value *Carry2;
+ llvm::Value *Sum2 = EmitOverflowIntrinsic(*this, IntrinsicId,
+ Sum1, Carryin, Carry2);
+ llvm::Value *CarryOut = Builder.CreateZExt(Builder.CreateOr(Carry1, Carry2),
+ X->getType());
+ llvm::StoreInst *CarryOutStore = Builder.CreateStore(CarryOut,
+ CarryOutPtr.first);
+ CarryOutStore->setAlignment(CarryOutPtr.second);
+ return RValue::get(Sum2);
+ }
case Builtin::BI__noop:
return RValue::get(0);
}
@@ -1401,9 +1496,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
ErrorUnsupported(E, "builtin function");
// Unknown builtin, for now just dump it out and return undef.
- if (hasAggregateLLVMType(E->getType()))
- return RValue::getAggregate(CreateMemTemp(E->getType()));
- return RValue::get(llvm::UndefValue::get(ConvertType(E->getType())));
+ return GetUndefRValue(E->getType());
}
Value *CodeGenFunction::EmitTargetBuiltinExpr(unsigned BuiltinID,
@@ -1540,7 +1633,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
llvm::Type *Ty = CGM.getTypes().ConvertType(FD->getType());
llvm::FunctionType *FTy = cast<llvm::FunctionType>(Ty);
StringRef Name = FD->getName();
- return Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, Name), Ops);
+ return EmitNounwindRuntimeCall(CGM.CreateRuntimeFunction(FTy, Name), Ops);
}
if (BuiltinID == ARM::BI__builtin_arm_ldrexd) {
@@ -2037,7 +2130,9 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
Ops[0] = Builder.CreateBitCast(Ops[0], Ty);
Ops[1] = Builder.CreateBitCast(Ops[1], Ty);
Ops[2] = Builder.CreateBitCast(Ops[2], Ty);
- return Builder.CreateCall3(F, Ops[0], Ops[1], Ops[2]);
+
+ // NEON intrinsic puts accumulator first, unlike the LLVM fma.
+ return Builder.CreateCall3(F, Ops[1], Ops[2], Ops[0]);
}
case ARM::BI__builtin_neon_vpadal_v:
case ARM::BI__builtin_neon_vpadalq_v: {
@@ -2614,7 +2709,10 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
}
case X86::BI__builtin_ia32_rdrand16_step:
case X86::BI__builtin_ia32_rdrand32_step:
- case X86::BI__builtin_ia32_rdrand64_step: {
+ case X86::BI__builtin_ia32_rdrand64_step:
+ case X86::BI__builtin_ia32_rdseed16_step:
+ case X86::BI__builtin_ia32_rdseed32_step:
+ case X86::BI__builtin_ia32_rdseed64_step: {
Intrinsic::ID ID;
switch (BuiltinID) {
default: llvm_unreachable("Unsupported intrinsic!");
@@ -2627,6 +2725,15 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
case X86::BI__builtin_ia32_rdrand64_step:
ID = Intrinsic::x86_rdrand_64;
break;
+ case X86::BI__builtin_ia32_rdseed16_step:
+ ID = Intrinsic::x86_rdseed_16;
+ break;
+ case X86::BI__builtin_ia32_rdseed32_step:
+ ID = Intrinsic::x86_rdseed_32;
+ break;
+ case X86::BI__builtin_ia32_rdseed64_step:
+ ID = Intrinsic::x86_rdseed_64;
+ break;
}
Value *Call = Builder.CreateCall(CGM.getIntrinsic(ID));
diff --git a/lib/CodeGen/CGCUDANV.cpp b/lib/CodeGen/CGCUDANV.cpp
index 88a0bdc..0ebf1aa 100644
--- a/lib/CodeGen/CGCUDANV.cpp
+++ b/lib/CodeGen/CGCUDANV.cpp
@@ -16,11 +16,10 @@
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "clang/AST/Decl.h"
-#include "llvm/BasicBlock.h"
-#include "llvm/Constants.h"
-#include "llvm/DerivedTypes.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DerivedTypes.h"
#include "llvm/Support/CallSite.h"
-
#include <vector>
using namespace clang;
@@ -79,7 +78,7 @@ llvm::Constant *CGNVCUDARuntime::getLaunchFn() const {
void CGNVCUDARuntime::EmitDeviceStubBody(CodeGenFunction &CGF,
FunctionArgList &Args) {
// Build the argument value list and the argument stack struct type.
- llvm::SmallVector<llvm::Value *, 16> ArgValues;
+ SmallVector<llvm::Value *, 16> ArgValues;
std::vector<llvm::Type *> ArgTypes;
for (FunctionArgList::const_iterator I = Args.begin(), E = Args.end();
I != E; ++I) {
@@ -105,7 +104,7 @@ void CGNVCUDARuntime::EmitDeviceStubBody(CodeGenFunction &CGF,
Args[2] = CGF.Builder.CreateIntCast(
llvm::ConstantExpr::getOffsetOf(ArgStackTy, I),
SizeTy, false);
- llvm::CallSite CS = CGF.EmitCallOrInvoke(cudaSetupArgFn, Args);
+ llvm::CallSite CS = CGF.EmitRuntimeCallOrInvoke(cudaSetupArgFn, Args);
llvm::Constant *Zero = llvm::ConstantInt::get(IntTy, 0);
llvm::Value *CSZero = CGF.Builder.CreateICmpEQ(CS.getInstruction(), Zero);
CGF.Builder.CreateCondBr(CSZero, NextBlock, EndBlock);
@@ -115,7 +114,7 @@ void CGNVCUDARuntime::EmitDeviceStubBody(CodeGenFunction &CGF,
// Emit the call to cudaLaunch
llvm::Constant *cudaLaunchFn = getLaunchFn();
llvm::Value *Arg = CGF.Builder.CreatePointerCast(CGF.CurFn, CharPtrTy);
- CGF.EmitCallOrInvoke(cudaLaunchFn, Arg);
+ CGF.EmitRuntimeCallOrInvoke(cudaLaunchFn, Arg);
CGF.EmitBranch(EndBlock);
CGF.EmitBlock(EndBlock);
diff --git a/lib/CodeGen/CGCUDARuntime.cpp b/lib/CodeGen/CGCUDARuntime.cpp
index 77dc248..fc72008 100644
--- a/lib/CodeGen/CGCUDARuntime.cpp
+++ b/lib/CodeGen/CGCUDARuntime.cpp
@@ -14,10 +14,10 @@
//===----------------------------------------------------------------------===//
#include "CGCUDARuntime.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/ExprCXX.h"
#include "CGCall.h"
#include "CodeGenFunction.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/ExprCXX.h"
using namespace clang;
using namespace CodeGen;
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index 003fef5..983cb92 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -13,15 +13,15 @@
// We might split this into multiple files if it gets too unwieldy
+#include "CodeGenModule.h"
#include "CGCXXABI.h"
#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/RecordLayout.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Mangle.h"
+#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/StringExtras.h"
@@ -183,14 +183,16 @@ void CodeGenModule::EmitCXXConstructors(const CXXConstructorDecl *D) {
// The constructor used for constructing this as a base class;
// ignores virtual bases.
- EmitGlobal(GlobalDecl(D, Ctor_Base));
+ if (getTarget().getCXXABI().hasConstructorVariants())
+ EmitGlobal(GlobalDecl(D, Ctor_Base));
}
void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *ctor,
CXXCtorType ctorType) {
// The complete constructor is equivalent to the base constructor
// for classes with no virtual bases. Try to emit it as an alias.
- if (ctorType == Ctor_Complete &&
+ if (getTarget().getCXXABI().hasConstructorVariants() &&
+ ctorType == Ctor_Complete &&
!ctor->getParent()->getNumVBases() &&
!TryEmitDefinitionAsAlias(GlobalDecl(ctor, Ctor_Complete),
GlobalDecl(ctor, Ctor_Base)))
diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp
index 91795b9..0c0a76f 100644
--- a/lib/CodeGen/CGCXXABI.cpp
+++ b/lib/CodeGen/CGCXXABI.cpp
@@ -19,8 +19,7 @@ using namespace CodeGen;
CGCXXABI::~CGCXXABI() { }
-static void ErrorUnsupportedABI(CodeGenFunction &CGF,
- StringRef S) {
+void CGCXXABI::ErrorUnsupportedABI(CodeGenFunction &CGF, StringRef S) {
DiagnosticsEngine &Diags = CGF.CGM.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
"cannot yet compile %0 in this ABI");
@@ -29,8 +28,7 @@ static void ErrorUnsupportedABI(CodeGenFunction &CGF,
<< S;
}
-static llvm::Constant *GetBogusMemberPointer(CodeGenModule &CGM,
- QualType T) {
+llvm::Constant *CGCXXABI::GetBogusMemberPointer(QualType T) {
return llvm::Constant::getNullValue(CGM.getTypes().ConvertType(T));
}
@@ -67,12 +65,12 @@ llvm::Value *CGCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
const CastExpr *E,
llvm::Value *Src) {
ErrorUnsupportedABI(CGF, "member function pointer conversions");
- return GetBogusMemberPointer(CGM, E->getType());
+ return GetBogusMemberPointer(E->getType());
}
llvm::Constant *CGCXXABI::EmitMemberPointerConversion(const CastExpr *E,
llvm::Constant *Src) {
- return GetBogusMemberPointer(CGM, E->getType());
+ return GetBogusMemberPointer(E->getType());
}
llvm::Value *
@@ -95,22 +93,22 @@ CGCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
llvm::Constant *
CGCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) {
- return GetBogusMemberPointer(CGM, QualType(MPT, 0));
+ return GetBogusMemberPointer(QualType(MPT, 0));
}
llvm::Constant *CGCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
- return GetBogusMemberPointer(CGM,
+ return GetBogusMemberPointer(
CGM.getContext().getMemberPointerType(MD->getType(),
MD->getParent()->getTypeForDecl()));
}
llvm::Constant *CGCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
CharUnits offset) {
- return GetBogusMemberPointer(CGM, QualType(MPT, 0));
+ return GetBogusMemberPointer(QualType(MPT, 0));
}
llvm::Constant *CGCXXABI::EmitMemberPointer(const APValue &MP, QualType MPT) {
- return GetBogusMemberPointer(CGM, MPT);
+ return GetBogusMemberPointer(MPT);
}
bool CGCXXABI::isZeroInitializable(const MemberPointerType *MPT) {
@@ -248,3 +246,12 @@ llvm::Constant *CGCXXABI::getMemberPointerAdjustment(const CastExpr *E) {
E->path_begin(),
E->path_end());
}
+
+llvm::BasicBlock *CGCXXABI::EmitCtorCompleteObjectHandler(
+ CodeGenFunction &CGF) {
+ if (CGM.getTarget().getCXXABI().hasConstructorVariants())
+ llvm_unreachable("shouldn't be called in this ABI");
+
+ ErrorUnsupportedABI(CGF, "complete object detection in ctor");
+ return 0;
+}
diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h
index 570aeb0..702e59b 100644
--- a/lib/CodeGen/CGCXXABI.h
+++ b/lib/CodeGen/CGCXXABI.h
@@ -15,9 +15,8 @@
#ifndef CLANG_CODEGEN_CXXABI_H
#define CLANG_CODEGEN_CXXABI_H
-#include "clang/Basic/LLVM.h"
-
#include "CodeGenFunction.h"
+#include "clang/Basic/LLVM.h"
namespace llvm {
class Constant;
@@ -55,11 +54,26 @@ protected:
return CGF.CXXABIThisValue;
}
+ /// Issue a diagnostic about unsupported features in the ABI.
+ void ErrorUnsupportedABI(CodeGenFunction &CGF, StringRef S);
+
+ /// Get a null value for unsupported member pointers.
+ llvm::Constant *GetBogusMemberPointer(QualType T);
+
+ // FIXME: Every place that calls getVTT{Decl,Value} is something
+ // that needs to be abstracted properly.
ImplicitParamDecl *&getVTTDecl(CodeGenFunction &CGF) {
- return CGF.CXXVTTDecl;
+ return CGF.CXXStructorImplicitParamDecl;
}
llvm::Value *&getVTTValue(CodeGenFunction &CGF) {
- return CGF.CXXVTTValue;
+ return CGF.CXXStructorImplicitParamValue;
+ }
+
+ ImplicitParamDecl *&getStructorImplicitParamDecl(CodeGenFunction &CGF) {
+ return CGF.CXXStructorImplicitParamDecl;
+ }
+ llvm::Value *&getStructorImplicitParamValue(CodeGenFunction &CGF) {
+ return CGF.CXXStructorImplicitParamValue;
}
/// Build a parameter variable suitable for 'this'.
@@ -83,6 +97,10 @@ public:
return *MangleCtx;
}
+ /// Returns true if the given instance method is one of the
+ /// kinds that the ABI says returns 'this'.
+ virtual bool HasThisReturn(GlobalDecl GD) const { return false; }
+
/// Find the LLVM type used to represent the given member pointer
/// type.
virtual llvm::Type *
@@ -177,6 +195,8 @@ public:
CanQualType &ResTy,
SmallVectorImpl<CanQualType> &ArgTys) = 0;
+ virtual llvm::BasicBlock *EmitCtorCompleteObjectHandler(CodeGenFunction &CGF);
+
/// Build the signature of the given destructor variant by adding
/// any required parameters. For convenience, ResTy has been
/// initialized to 'void' and ArgTys has been initialized with the
@@ -199,6 +219,23 @@ public:
/// Emit the ABI-specific prolog for the function.
virtual void EmitInstanceFunctionProlog(CodeGenFunction &CGF) = 0;
+ /// Emit the constructor call. Return the function that is called.
+ virtual llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,
+ const CXXConstructorDecl *D,
+ CXXCtorType Type, bool ForVirtualBase,
+ bool Delegating,
+ llvm::Value *This,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd) = 0;
+
+ /// Emit the ABI-specific virtual destructor call.
+ virtual RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,
+ const CXXDestructorDecl *Dtor,
+ CXXDtorType DtorType,
+ SourceLocation CallLoc,
+ ReturnValueSlot ReturnValue,
+ llvm::Value *This) = 0;
+
virtual void EmitReturnFromThunk(CodeGenFunction &CGF,
RValue RV, QualType ResultType);
@@ -295,16 +332,14 @@ public:
/// \param addr - a pointer to pass to the destructor function.
virtual void registerGlobalDtor(CodeGenFunction &CGF, llvm::Constant *dtor,
llvm::Constant *addr);
-
- /***************************** Virtual Tables *******************************/
-
- /// Generates and emits the virtual tables for a class.
- virtual void EmitVTables(const CXXRecordDecl *Class) = 0;
};
-/// Creates an instance of a C++ ABI class.
-CGCXXABI *CreateARMCXXABI(CodeGenModule &CGM);
+// Create an instance of a C++ ABI class:
+
+/// Creates an Itanium-family ABI.
CGCXXABI *CreateItaniumCXXABI(CodeGenModule &CGM);
+
+/// Creates a Microsoft-family ABI.
CGCXXABI *CreateMicrosoftCXXABI(CodeGenModule &CGM);
}
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 2d1d152..faf32e3 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -13,20 +13,22 @@
//===----------------------------------------------------------------------===//
#include "CGCall.h"
-#include "CGCXXABI.h"
#include "ABIInfo.h"
+#include "CGCXXABI.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "TargetInfo.h"
-#include "clang/Basic/TargetInfo.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
-#include "llvm/Attributes.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/IR/Attributes.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/InlineAsm.h"
+#include "llvm/MC/SubtargetFeature.h"
#include "llvm/Support/CallSite.h"
-#include "llvm/DataLayout.h"
-#include "llvm/InlineAsm.h"
#include "llvm/Transforms/Utils/Local.h"
using namespace clang;
using namespace CodeGen;
@@ -41,6 +43,7 @@ static unsigned ClangCallConvToLLVMCallConv(CallingConv CC) {
case CC_X86ThisCall: return llvm::CallingConv::X86_ThisCall;
case CC_AAPCS: return llvm::CallingConv::ARM_AAPCS;
case CC_AAPCS_VFP: return llvm::CallingConv::ARM_AAPCS_VFP;
+ case CC_IntelOclBicc: return llvm::CallingConv::Intel_OCL_BI;
// TODO: add support for CC_X86Pascal to llvm
}
}
@@ -151,6 +154,9 @@ static CallingConv getCallingConventionForDecl(const Decl *D) {
if (D->hasAttr<PnaclCallAttr>())
return CC_PnaclCall;
+ if (D->hasAttr<IntelOclBiccAttr>())
+ return CC_IntelOclBicc;
+
return CC_C;
}
@@ -316,6 +322,37 @@ CodeGenTypes::arrangeGlobalDeclaration(GlobalDecl GD) {
return arrangeFunctionDeclaration(FD);
}
+/// Arrange a call as unto a free function, except possibly with an
+/// additional number of formal parameters considered required.
+static const CGFunctionInfo &
+arrangeFreeFunctionLikeCall(CodeGenTypes &CGT,
+ const CallArgList &args,
+ const FunctionType *fnType,
+ unsigned numExtraRequiredArgs) {
+ assert(args.size() >= numExtraRequiredArgs);
+
+ // In most cases, there are no optional arguments.
+ RequiredArgs required = RequiredArgs::All;
+
+ // If we have a variadic prototype, the required arguments are the
+ // extra prefix plus the arguments in the prototype.
+ if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(fnType)) {
+ if (proto->isVariadic())
+ required = RequiredArgs(proto->getNumArgs() + numExtraRequiredArgs);
+
+ // If we don't have a prototype at all, but we're supposed to
+ // explicitly use the variadic convention for unprototyped calls,
+ // treat all of the arguments as required but preserve the nominal
+ // possibility of variadics.
+ } else if (CGT.CGM.getTargetCodeGenInfo()
+ .isNoProtoCallVariadic(args, cast<FunctionNoProtoType>(fnType))) {
+ required = RequiredArgs(args.size());
+ }
+
+ return CGT.arrangeFreeFunctionCall(fnType->getResultType(), args,
+ fnType->getExtInfo(), required);
+}
+
/// Figure out the rules for calling a function with the given formal
/// type using the given arguments. The arguments are necessary
/// because the function might be unprototyped, in which case it's
@@ -323,17 +360,15 @@ CodeGenTypes::arrangeGlobalDeclaration(GlobalDecl GD) {
const CGFunctionInfo &
CodeGenTypes::arrangeFreeFunctionCall(const CallArgList &args,
const FunctionType *fnType) {
- RequiredArgs required = RequiredArgs::All;
- if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(fnType)) {
- if (proto->isVariadic())
- required = RequiredArgs(proto->getNumArgs());
- } else if (CGM.getTargetCodeGenInfo()
- .isNoProtoCallVariadic(args, cast<FunctionNoProtoType>(fnType))) {
- required = RequiredArgs(0);
- }
+ return arrangeFreeFunctionLikeCall(*this, args, fnType, 0);
+}
- return arrangeFreeFunctionCall(fnType->getResultType(), args,
- fnType->getExtInfo(), required);
+/// A block function call is essentially a free-function call with an
+/// extra implicit argument.
+const CGFunctionInfo &
+CodeGenTypes::arrangeBlockFunctionCall(const CallArgList &args,
+ const FunctionType *fnType) {
+ return arrangeFreeFunctionLikeCall(*this, args, fnType, 1);
}
const CGFunctionInfo &
@@ -692,12 +727,13 @@ static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr,
// Otherwise do coercion through memory. This is stupid, but
// simple.
llvm::Value *Tmp = CGF.CreateTempAlloca(Ty);
- llvm::Value *Casted =
- CGF.Builder.CreateBitCast(Tmp, llvm::PointerType::getUnqual(SrcTy));
- llvm::StoreInst *Store =
- CGF.Builder.CreateStore(CGF.Builder.CreateLoad(SrcPtr), Casted);
- // FIXME: Use better alignment / avoid requiring aligned store.
- Store->setAlignment(1);
+ llvm::Type *I8PtrTy = CGF.Builder.getInt8PtrTy();
+ llvm::Value *Casted = CGF.Builder.CreateBitCast(Tmp, I8PtrTy);
+ llvm::Value *SrcCasted = CGF.Builder.CreateBitCast(SrcPtr, I8PtrTy);
+ // FIXME: Use better alignment.
+ CGF.Builder.CreateMemCpy(Casted, SrcCasted,
+ llvm::ConstantInt::get(CGF.IntPtrTy, SrcSize),
+ 1, false);
return CGF.Builder.CreateLoad(Tmp);
}
@@ -779,12 +815,13 @@ static void CreateCoercedStore(llvm::Value *Src,
// to that information.
llvm::Value *Tmp = CGF.CreateTempAlloca(SrcTy);
CGF.Builder.CreateStore(Src, Tmp);
- llvm::Value *Casted =
- CGF.Builder.CreateBitCast(Tmp, llvm::PointerType::getUnqual(DstTy));
- llvm::LoadInst *Load = CGF.Builder.CreateLoad(Casted);
- // FIXME: Use better alignment / avoid requiring aligned load.
- Load->setAlignment(1);
- CGF.Builder.CreateStore(Load, DstPtr, DstIsVolatile);
+ llvm::Type *I8PtrTy = CGF.Builder.getInt8PtrTy();
+ llvm::Value *Casted = CGF.Builder.CreateBitCast(Tmp, I8PtrTy);
+ llvm::Value *DstCasted = CGF.Builder.CreateBitCast(DstPtr, I8PtrTy);
+ // FIXME: Use better alignment.
+ CGF.Builder.CreateMemCpy(DstCasted, Casted,
+ llvm::ConstantInt::get(CGF.IntPtrTy, DstSize),
+ 1, false);
}
}
@@ -863,8 +900,14 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) {
break;
}
- for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(),
- ie = FI.arg_end(); it != ie; ++it) {
+ // Add in all of the required arguments.
+ CGFunctionInfo::const_arg_iterator it = FI.arg_begin(), ie;
+ if (FI.isVariadic()) {
+ ie = it + FI.getRequiredArgs().getNumRequiredArgs();
+ } else {
+ ie = FI.arg_end();
+ }
+ for (; it != ie; ++it) {
const ABIArgInfo &argAI = it->info;
// Insert a padding type to ensure proper alignment.
@@ -927,53 +970,85 @@ llvm::Type *CodeGenTypes::GetFunctionTypeForVTable(GlobalDecl GD) {
void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
const Decl *TargetDecl,
AttributeListType &PAL,
- unsigned &CallingConv) {
+ unsigned &CallingConv,
+ bool AttrOnCallSite) {
llvm::AttrBuilder FuncAttrs;
llvm::AttrBuilder RetAttrs;
CallingConv = FI.getEffectiveCallingConvention();
if (FI.isNoReturn())
- FuncAttrs.addAttribute(llvm::Attributes::NoReturn);
+ FuncAttrs.addAttribute(llvm::Attribute::NoReturn);
// FIXME: handle sseregparm someday...
if (TargetDecl) {
if (TargetDecl->hasAttr<ReturnsTwiceAttr>())
- FuncAttrs.addAttribute(llvm::Attributes::ReturnsTwice);
+ FuncAttrs.addAttribute(llvm::Attribute::ReturnsTwice);
if (TargetDecl->hasAttr<NoThrowAttr>())
- FuncAttrs.addAttribute(llvm::Attributes::NoUnwind);
- else if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {
+ FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
+ if (TargetDecl->hasAttr<NoReturnAttr>())
+ FuncAttrs.addAttribute(llvm::Attribute::NoReturn);
+
+ if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) {
const FunctionProtoType *FPT = Fn->getType()->getAs<FunctionProtoType>();
if (FPT && FPT->isNothrow(getContext()))
- FuncAttrs.addAttribute(llvm::Attributes::NoUnwind);
+ FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
+ // Don't use [[noreturn]] or _Noreturn for a call to a virtual function.
+ // These attributes are not inherited by overloads.
+ const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Fn);
+ if (Fn->isNoReturn() && !(AttrOnCallSite && MD && MD->isVirtual()))
+ FuncAttrs.addAttribute(llvm::Attribute::NoReturn);
}
- if (TargetDecl->hasAttr<NoReturnAttr>())
- FuncAttrs.addAttribute(llvm::Attributes::NoReturn);
-
- if (TargetDecl->hasAttr<ReturnsTwiceAttr>())
- FuncAttrs.addAttribute(llvm::Attributes::ReturnsTwice);
-
// 'const' and 'pure' attribute functions are also nounwind.
if (TargetDecl->hasAttr<ConstAttr>()) {
- FuncAttrs.addAttribute(llvm::Attributes::ReadNone);
- FuncAttrs.addAttribute(llvm::Attributes::NoUnwind);
+ FuncAttrs.addAttribute(llvm::Attribute::ReadNone);
+ FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
} else if (TargetDecl->hasAttr<PureAttr>()) {
- FuncAttrs.addAttribute(llvm::Attributes::ReadOnly);
- FuncAttrs.addAttribute(llvm::Attributes::NoUnwind);
+ FuncAttrs.addAttribute(llvm::Attribute::ReadOnly);
+ FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
}
if (TargetDecl->hasAttr<MallocAttr>())
- RetAttrs.addAttribute(llvm::Attributes::NoAlias);
+ RetAttrs.addAttribute(llvm::Attribute::NoAlias);
}
if (CodeGenOpts.OptimizeSize)
- FuncAttrs.addAttribute(llvm::Attributes::OptimizeForSize);
+ FuncAttrs.addAttribute(llvm::Attribute::OptimizeForSize);
if (CodeGenOpts.OptimizeSize == 2)
- FuncAttrs.addAttribute(llvm::Attributes::MinSize);
+ FuncAttrs.addAttribute(llvm::Attribute::MinSize);
if (CodeGenOpts.DisableRedZone)
- FuncAttrs.addAttribute(llvm::Attributes::NoRedZone);
+ FuncAttrs.addAttribute(llvm::Attribute::NoRedZone);
if (CodeGenOpts.NoImplicitFloat)
- FuncAttrs.addAttribute(llvm::Attributes::NoImplicitFloat);
+ FuncAttrs.addAttribute(llvm::Attribute::NoImplicitFloat);
+
+ if (AttrOnCallSite) {
+ // Attributes that should go on the call site only.
+ if (!CodeGenOpts.SimplifyLibCalls)
+ FuncAttrs.addAttribute(llvm::Attribute::NoBuiltin);
+ } else {
+ // Attributes that should go on the function, but not the call site.
+ if (!CodeGenOpts.DisableFPElim) {
+ FuncAttrs.addAttribute("no-frame-pointer-elim", "false");
+ FuncAttrs.addAttribute("no-frame-pointer-elim-non-leaf", "false");
+ } else if (CodeGenOpts.OmitLeafFramePointer) {
+ FuncAttrs.addAttribute("no-frame-pointer-elim", "false");
+ FuncAttrs.addAttribute("no-frame-pointer-elim-non-leaf", "true");
+ } else {
+ FuncAttrs.addAttribute("no-frame-pointer-elim", "true");
+ FuncAttrs.addAttribute("no-frame-pointer-elim-non-leaf", "true");
+ }
+
+ FuncAttrs.addAttribute("less-precise-fpmad",
+ CodeGenOpts.LessPreciseFPMAD ? "true" : "false");
+ FuncAttrs.addAttribute("no-infs-fp-math",
+ CodeGenOpts.NoInfsFPMath ? "true" : "false");
+ FuncAttrs.addAttribute("no-nans-fp-math",
+ CodeGenOpts.NoNaNsFPMath ? "true" : "false");
+ FuncAttrs.addAttribute("unsafe-fp-math",
+ CodeGenOpts.UnsafeFPMath ? "true" : "false");
+ FuncAttrs.addAttribute("use-soft-float",
+ CodeGenOpts.SoftFloat ? "true" : "false");
+ }
QualType RetTy = FI.getReturnType();
unsigned Index = 1;
@@ -981,9 +1056,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
switch (RetAI.getKind()) {
case ABIArgInfo::Extend:
if (RetTy->hasSignedIntegerRepresentation())
- RetAttrs.addAttribute(llvm::Attributes::SExt);
+ RetAttrs.addAttribute(llvm::Attribute::SExt);
else if (RetTy->hasUnsignedIntegerRepresentation())
- RetAttrs.addAttribute(llvm::Attributes::ZExt);
+ RetAttrs.addAttribute(llvm::Attribute::ZExt);
break;
case ABIArgInfo::Direct:
case ABIArgInfo::Ignore:
@@ -991,18 +1066,16 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
case ABIArgInfo::Indirect: {
llvm::AttrBuilder SRETAttrs;
- SRETAttrs.addAttribute(llvm::Attributes::StructRet);
+ SRETAttrs.addAttribute(llvm::Attribute::StructRet);
if (RetAI.getInReg())
- SRETAttrs.addAttribute(llvm::Attributes::InReg);
+ SRETAttrs.addAttribute(llvm::Attribute::InReg);
PAL.push_back(llvm::
- AttributeWithIndex::get(Index,
- llvm::Attributes::get(getLLVMContext(),
- SRETAttrs)));
+ AttributeSet::get(getLLVMContext(), Index, SRETAttrs));
++Index;
// sret disables readnone and readonly
- FuncAttrs.removeAttribute(llvm::Attributes::ReadOnly)
- .removeAttribute(llvm::Attributes::ReadNone);
+ FuncAttrs.removeAttribute(llvm::Attribute::ReadOnly)
+ .removeAttribute(llvm::Attribute::ReadNone);
break;
}
@@ -1012,9 +1085,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
if (RetAttrs.hasAttributes())
PAL.push_back(llvm::
- AttributeWithIndex::get(llvm::AttrListPtr::ReturnIndex,
- llvm::Attributes::get(getLLVMContext(),
- RetAttrs)));
+ AttributeSet::get(getLLVMContext(),
+ llvm::AttributeSet::ReturnIndex,
+ RetAttrs));
for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(),
ie = FI.arg_end(); it != ie; ++it) {
@@ -1023,13 +1096,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
llvm::AttrBuilder Attrs;
if (AI.getPaddingType()) {
- if (AI.getPaddingInReg()) {
- llvm::AttrBuilder PadAttrs;
- PadAttrs.addAttribute(llvm::Attributes::InReg);
-
- llvm::Attributes A =llvm::Attributes::get(getLLVMContext(), PadAttrs);
- PAL.push_back(llvm::AttributeWithIndex::get(Index, A));
- }
+ if (AI.getPaddingInReg())
+ PAL.push_back(llvm::AttributeSet::get(getLLVMContext(), Index,
+ llvm::Attribute::InReg));
// Increment Index if there is padding.
++Index;
}
@@ -1040,13 +1109,13 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
switch (AI.getKind()) {
case ABIArgInfo::Extend:
if (ParamType->isSignedIntegerOrEnumerationType())
- Attrs.addAttribute(llvm::Attributes::SExt);
+ Attrs.addAttribute(llvm::Attribute::SExt);
else if (ParamType->isUnsignedIntegerOrEnumerationType())
- Attrs.addAttribute(llvm::Attributes::ZExt);
+ Attrs.addAttribute(llvm::Attribute::ZExt);
// FALL THROUGH
case ABIArgInfo::Direct:
if (AI.getInReg())
- Attrs.addAttribute(llvm::Attributes::InReg);
+ Attrs.addAttribute(llvm::Attribute::InReg);
// FIXME: handle sseregparm someday...
@@ -1055,25 +1124,24 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
unsigned Extra = STy->getNumElements()-1; // 1 will be added below.
if (Attrs.hasAttributes())
for (unsigned I = 0; I < Extra; ++I)
- PAL.push_back(llvm::AttributeWithIndex::get(Index + I,
- llvm::Attributes::get(getLLVMContext(),
- Attrs)));
+ PAL.push_back(llvm::AttributeSet::get(getLLVMContext(), Index + I,
+ Attrs));
Index += Extra;
}
break;
case ABIArgInfo::Indirect:
if (AI.getInReg())
- Attrs.addAttribute(llvm::Attributes::InReg);
+ Attrs.addAttribute(llvm::Attribute::InReg);
if (AI.getIndirectByVal())
- Attrs.addAttribute(llvm::Attributes::ByVal);
+ Attrs.addAttribute(llvm::Attribute::ByVal);
Attrs.addAlignmentAttr(AI.getIndirectAlign());
// byval disables readnone and readonly.
- FuncAttrs.removeAttribute(llvm::Attributes::ReadOnly)
- .removeAttribute(llvm::Attributes::ReadNone);
+ FuncAttrs.removeAttribute(llvm::Attribute::ReadOnly)
+ .removeAttribute(llvm::Attribute::ReadNone);
break;
case ABIArgInfo::Ignore:
@@ -1092,16 +1160,14 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
}
if (Attrs.hasAttributes())
- PAL.push_back(llvm::AttributeWithIndex::get(Index,
- llvm::Attributes::get(getLLVMContext(),
- Attrs)));
+ PAL.push_back(llvm::AttributeSet::get(getLLVMContext(), Index, Attrs));
++Index;
}
if (FuncAttrs.hasAttributes())
PAL.push_back(llvm::
- AttributeWithIndex::get(llvm::AttrListPtr::FunctionIndex,
- llvm::Attributes::get(getLLVMContext(),
- FuncAttrs)));
+ AttributeSet::get(getLLVMContext(),
+ llvm::AttributeSet::FunctionIndex,
+ FuncAttrs));
}
/// An argument came in as a promoted argument; demote it back to its
@@ -1149,8 +1215,9 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// Name the struct return argument.
if (CGM.ReturnTypeUsesSRet(FI)) {
AI->setName("agg.result");
- AI->addAttr(llvm::Attributes::get(getLLVMContext(),
- llvm::Attributes::NoAlias));
+ AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
+ AI->getArgNo() + 1,
+ llvm::Attribute::NoAlias));
++AI;
}
@@ -1175,7 +1242,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
case ABIArgInfo::Indirect: {
llvm::Value *V = AI;
- if (hasAggregateLLVMType(Ty)) {
+ if (!hasScalarEvaluationKind(Ty)) {
// Aggregates and complex variables are accessed by reference. All we
// need to do is realign the value, if requested
if (ArgI.getIndirectRealign()) {
@@ -1221,8 +1288,9 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
llvm::Value *V = AI;
if (Arg->getType().isRestrictQualified())
- AI->addAttr(llvm::Attributes::get(getLLVMContext(),
- llvm::Attributes::NoAlias));
+ AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
+ AI->getArgNo() + 1,
+ llvm::Attribute::NoAlias));
// Ensure the argument is the correct type.
if (V->getType() != ArgI.getCoerceToType())
@@ -1230,7 +1298,15 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
if (isPromoted)
V = emitArgumentDemotion(*this, Arg, V);
-
+
+ // Because of merging of function types from multiple decls it is
+ // possible for the type of an argument to not match the corresponding
+ // type in the function type. Since we are codegening the callee
+ // in here, add a cast to the argument type.
+ llvm::Type *LTy = ConvertType(Arg->getType());
+ if (V->getType() != LTy)
+ V = Builder.CreateBitCast(V, LTy);
+
EmitParmDecl(*Arg, V, ArgNo);
break;
}
@@ -1299,7 +1375,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// Match to what EmitParmDecl is expecting for this type.
- if (!CodeGenFunction::hasAggregateLLVMType(Ty)) {
+ if (CodeGenFunction::hasScalarEvaluationKind(Ty)) {
V = EmitLoadOfScalar(V, false, AlignmentToUse, Ty);
if (isPromoted)
V = emitArgumentDemotion(*this, Arg, V);
@@ -1328,7 +1404,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
case ABIArgInfo::Ignore:
// Initialize the local variable appropriately.
- if (hasAggregateLLVMType(Ty))
+ if (!hasScalarEvaluationKind(Ty))
EmitParmDecl(*Arg, CreateMemTemp(Ty), ArgNo);
else
EmitParmDecl(*Arg, llvm::UndefValue::get(ConvertType(Arg->getType())),
@@ -1538,6 +1614,18 @@ static llvm::StoreInst *findDominatingStoreToReturnValue(CodeGenFunction &CGF) {
return store;
}
+/// Check whether 'this' argument of a callsite matches 'this' of the caller.
+static bool checkThisPointer(llvm::Value *ThisArg, llvm::Value *This) {
+ if (ThisArg == This)
+ return true;
+ // Check whether ThisArg is a bitcast of This.
+ llvm::BitCastInst *Bitcast;
+ if ((Bitcast = dyn_cast<llvm::BitCastInst>(ThisArg)) &&
+ Bitcast->getOperand(0) == This)
+ return true;
+ return false;
+}
+
void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
// Functions with no result always return void.
if (ReturnValue == 0) {
@@ -1552,15 +1640,23 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
switch (RetAI.getKind()) {
case ABIArgInfo::Indirect: {
- unsigned Alignment = getContext().getTypeAlignInChars(RetTy).getQuantity();
- if (RetTy->isAnyComplexType()) {
- ComplexPairTy RT = LoadComplexFromAddr(ReturnValue, false);
- StoreComplexToAddr(RT, CurFn->arg_begin(), false);
- } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
+ switch (getEvaluationKind(RetTy)) {
+ case TEK_Complex: {
+ ComplexPairTy RT =
+ EmitLoadOfComplex(MakeNaturalAlignAddrLValue(ReturnValue, RetTy));
+ EmitStoreOfComplex(RT,
+ MakeNaturalAlignAddrLValue(CurFn->arg_begin(), RetTy),
+ /*isInit*/ true);
+ break;
+ }
+ case TEK_Aggregate:
// Do nothing; aggregrates get evaluated directly into the destination.
- } else {
- EmitStoreOfScalar(Builder.CreateLoad(ReturnValue), CurFn->arg_begin(),
- false, Alignment, RetTy);
+ break;
+ case TEK_Scalar:
+ EmitStoreOfScalar(Builder.CreateLoad(ReturnValue),
+ MakeNaturalAlignAddrLValue(CurFn->arg_begin(), RetTy),
+ /*isInit*/ true);
+ break;
}
break;
}
@@ -1621,6 +1717,19 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
llvm_unreachable("Invalid ABI kind for return argument");
}
+ // If this function returns 'this', the last instruction is a CallInst
+ // that returns 'this', and 'this' argument of the CallInst points to
+ // the same object as CXXThisValue, use the return value from the CallInst.
+ // We will not need to keep 'this' alive through the callsite. It also enables
+ // optimizations in the backend, such as tail call optimization.
+ if (CalleeWithThisReturn && CGM.getCXXABI().HasThisReturn(CurGD)) {
+ llvm::BasicBlock *IP = Builder.GetInsertBlock();
+ llvm::CallInst *Callsite;
+ if (!IP->empty() && (Callsite = dyn_cast<llvm::CallInst>(&IP->back())) &&
+ Callsite->getCalledFunction() == CalleeWithThisReturn &&
+ checkThisPointer(Callsite->getOperand(0), CXXThisValue))
+ RV = Builder.CreateBitCast(Callsite, RetAI.getCoerceToType());
+ }
llvm::Instruction *Ret = RV ? Builder.CreateRet(RV) : Builder.CreateRetVoid();
if (!RetDbgLoc.isUnknown())
Ret->setDebugLoc(RetDbgLoc);
@@ -1637,10 +1746,10 @@ void CodeGenFunction::EmitDelegateCallArg(CallArgList &args,
// For the most part, we just need to load the alloca, except:
// 1) aggregate r-values are actually pointers to temporaries, and
- // 2) references to aggregates are pointers directly to the aggregate.
- // I don't know why references to non-aggregates are different here.
+ // 2) references to non-scalars are pointers directly to the aggregate.
+ // I don't know why references to scalars are different here.
if (const ReferenceType *ref = type->getAs<ReferenceType>()) {
- if (hasAggregateLLVMType(ref->getPointeeType()))
+ if (!hasScalarEvaluationKind(ref->getPointeeType()))
return args.add(RValue::getAggregate(local), type);
// Locals which are references to scalars are represented
@@ -1648,17 +1757,7 @@ void CodeGenFunction::EmitDelegateCallArg(CallArgList &args,
return args.add(RValue::get(Builder.CreateLoad(local)), type);
}
- if (type->isAnyComplexType()) {
- ComplexPairTy complex = LoadComplexFromAddr(local, /*volatile*/ false);
- return args.add(RValue::getComplex(complex), type);
- }
-
- if (hasAggregateLLVMType(type))
- return args.add(RValue::getAggregate(local), type);
-
- unsigned alignment = getContext().getDeclAlign(param).getQuantity();
- llvm::Value *value = EmitLoadOfScalar(local, false, alignment, type);
- return args.add(RValue::get(value), type);
+ args.add(convertTempToRValue(local, type), type);
}
static bool isProvablyNull(llvm::Value *addr) {
@@ -1672,7 +1771,8 @@ static bool isProvablyNonNull(llvm::Value *addr) {
/// Emit the actual writing-back of a writeback.
static void emitWriteback(CodeGenFunction &CGF,
const CallArgList::Writeback &writeback) {
- llvm::Value *srcAddr = writeback.Address;
+ const LValue &srcLV = writeback.Source;
+ llvm::Value *srcAddr = srcLV.getAddress();
assert(!isProvablyNull(srcAddr) &&
"shouldn't have writeback for provably null argument");
@@ -1699,9 +1799,35 @@ static void emitWriteback(CodeGenFunction &CGF,
"icr.writeback-cast");
// Perform the writeback.
- QualType srcAddrType = writeback.AddressType;
- CGF.EmitStoreThroughLValue(RValue::get(value),
- CGF.MakeAddrLValue(srcAddr, srcAddrType));
+
+ // If we have a "to use" value, it's something we need to emit a use
+ // of. This has to be carefully threaded in: if it's done after the
+ // release it's potentially undefined behavior (and the optimizer
+ // will ignore it), and if it happens before the retain then the
+ // optimizer could move the release there.
+ if (writeback.ToUse) {
+ assert(srcLV.getObjCLifetime() == Qualifiers::OCL_Strong);
+
+ // Retain the new value. No need to block-copy here: the block's
+ // being passed up the stack.
+ value = CGF.EmitARCRetainNonBlock(value);
+
+ // Emit the intrinsic use here.
+ CGF.EmitARCIntrinsicUse(writeback.ToUse);
+
+ // Load the old value (primitively).
+ llvm::Value *oldValue = CGF.EmitLoadOfScalar(srcLV);
+
+ // Put the new value in place (primitively).
+ CGF.EmitStoreOfScalar(value, srcLV, /*init*/ false);
+
+ // Release the old value.
+ CGF.EmitARCRelease(oldValue, srcLV.isARCPreciseLifetime());
+
+ // Otherwise, we can just do a normal lvalue store.
+ } else {
+ CGF.EmitStoreThroughLValue(RValue::get(value), srcLV);
+ }
// Jump to the continuation block.
if (!provablyNonNull)
@@ -1715,11 +1841,33 @@ static void emitWritebacks(CodeGenFunction &CGF,
emitWriteback(CGF, *i);
}
+static const Expr *maybeGetUnaryAddrOfOperand(const Expr *E) {
+ if (const UnaryOperator *uop = dyn_cast<UnaryOperator>(E->IgnoreParens()))
+ if (uop->getOpcode() == UO_AddrOf)
+ return uop->getSubExpr();
+ return 0;
+}
+
/// Emit an argument that's being passed call-by-writeback. That is,
/// we are passing the address of
static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
const ObjCIndirectCopyRestoreExpr *CRE) {
- llvm::Value *srcAddr = CGF.EmitScalarExpr(CRE->getSubExpr());
+ LValue srcLV;
+
+ // Make an optimistic effort to emit the address as an l-value.
+ // This can fail if the the argument expression is more complicated.
+ if (const Expr *lvExpr = maybeGetUnaryAddrOfOperand(CRE->getSubExpr())) {
+ srcLV = CGF.EmitLValue(lvExpr);
+
+ // Otherwise, just emit it as a scalar.
+ } else {
+ llvm::Value *srcAddr = CGF.EmitScalarExpr(CRE->getSubExpr());
+
+ QualType srcAddrType =
+ CRE->getSubExpr()->getType()->castAs<PointerType>()->getPointeeType();
+ srcLV = CGF.MakeNaturalAlignAddrLValue(srcAddr, srcAddrType);
+ }
+ llvm::Value *srcAddr = srcLV.getAddress();
// The dest and src types don't necessarily match in LLVM terms
// because of the crazy ObjC compatibility rules.
@@ -1734,13 +1882,15 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
return;
}
- QualType srcAddrType =
- CRE->getSubExpr()->getType()->castAs<PointerType>()->getPointeeType();
-
// Create the temporary.
llvm::Value *temp = CGF.CreateTempAlloca(destType->getElementType(),
"icr.temp");
-
+ // Loading an l-value can introduce a cleanup if the l-value is __weak,
+ // and that cleanup will be conditional if we can't prove that the l-value
+ // isn't null, so we need to register a dominating point so that the cleanups
+ // system will make valid IR.
+ CodeGenFunction::ConditionalEvaluation condEval(CGF);
+
// Zero-initialize it if we're not doing a copy-initialization.
bool shouldCopy = CRE->shouldCopy();
if (!shouldCopy) {
@@ -1749,8 +1899,9 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
cast<llvm::PointerType>(destType->getElementType()));
CGF.Builder.CreateStore(null, temp);
}
-
+
llvm::BasicBlock *contBB = 0;
+ llvm::BasicBlock *originBB = 0;
// If the address is *not* known to be non-null, we need to switch.
llvm::Value *finalArgument;
@@ -1768,16 +1919,19 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
// If we need to copy, then the load has to be conditional, which
// means we need control flow.
if (shouldCopy) {
+ originBB = CGF.Builder.GetInsertBlock();
contBB = CGF.createBasicBlock("icr.cont");
llvm::BasicBlock *copyBB = CGF.createBasicBlock("icr.copy");
CGF.Builder.CreateCondBr(isNull, contBB, copyBB);
CGF.EmitBlock(copyBB);
+ condEval.begin(CGF);
}
}
+ llvm::Value *valueToUse = 0;
+
// Perform a copy if necessary.
if (shouldCopy) {
- LValue srcLV = CGF.MakeAddrLValue(srcAddr, srcAddrType);
RValue srcRV = CGF.EmitLoadOfLValue(srcLV);
assert(srcRV.isScalar());
@@ -1787,13 +1941,37 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
// Use an ordinary store, not a store-to-lvalue.
CGF.Builder.CreateStore(src, temp);
- }
+ // If optimization is enabled, and the value was held in a
+ // __strong variable, we need to tell the optimizer that this
+ // value has to stay alive until we're doing the store back.
+ // This is because the temporary is effectively unretained,
+ // and so otherwise we can violate the high-level semantics.
+ if (CGF.CGM.getCodeGenOpts().OptimizationLevel != 0 &&
+ srcLV.getObjCLifetime() == Qualifiers::OCL_Strong) {
+ valueToUse = src;
+ }
+ }
+
// Finish the control flow if we needed it.
- if (shouldCopy && !provablyNonNull)
+ if (shouldCopy && !provablyNonNull) {
+ llvm::BasicBlock *copyBB = CGF.Builder.GetInsertBlock();
CGF.EmitBlock(contBB);
- args.addWriteback(srcAddr, srcAddrType, temp);
+ // Make a phi for the value to intrinsically use.
+ if (valueToUse) {
+ llvm::PHINode *phiToUse = CGF.Builder.CreatePHI(valueToUse->getType(), 2,
+ "icr.to-use");
+ phiToUse->addIncoming(valueToUse, copyBB);
+ phiToUse->addIncoming(llvm::UndefValue::get(valueToUse->getType()),
+ originBB);
+ valueToUse = phiToUse;
+ }
+
+ condEval.end(CGF);
+ }
+
+ args.addWriteback(srcLV, temp, valueToUse);
args.add(RValue::get(finalArgument), CRE->getType());
}
@@ -1815,7 +1993,7 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
type);
}
- if (hasAggregateLLVMType(type) && !E->getType()->isAnyComplexType() &&
+ if (hasAggregateEvaluationKind(type) &&
isa<ImplicitCastExpr>(E) &&
cast<CastExpr>(E)->getCastKind() == CK_LValueToRValue) {
LValue L = EmitLValue(cast<CastExpr>(E)->getSubExpr());
@@ -1837,6 +2015,85 @@ CodeGenFunction::AddObjCARCExceptionMetadata(llvm::Instruction *Inst) {
CGM.getNoObjCARCExceptionsMetadata());
}
+/// Emits a call to the given no-arguments nounwind runtime function.
+llvm::CallInst *
+CodeGenFunction::EmitNounwindRuntimeCall(llvm::Value *callee,
+ const llvm::Twine &name) {
+ return EmitNounwindRuntimeCall(callee, ArrayRef<llvm::Value*>(), name);
+}
+
+/// Emits a call to the given nounwind runtime function.
+llvm::CallInst *
+CodeGenFunction::EmitNounwindRuntimeCall(llvm::Value *callee,
+ ArrayRef<llvm::Value*> args,
+ const llvm::Twine &name) {
+ llvm::CallInst *call = EmitRuntimeCall(callee, args, name);
+ call->setDoesNotThrow();
+ return call;
+}
+
+/// Emits a simple call (never an invoke) to the given no-arguments
+/// runtime function.
+llvm::CallInst *
+CodeGenFunction::EmitRuntimeCall(llvm::Value *callee,
+ const llvm::Twine &name) {
+ return EmitRuntimeCall(callee, ArrayRef<llvm::Value*>(), name);
+}
+
+/// Emits a simple call (never an invoke) to the given runtime
+/// function.
+llvm::CallInst *
+CodeGenFunction::EmitRuntimeCall(llvm::Value *callee,
+ ArrayRef<llvm::Value*> args,
+ const llvm::Twine &name) {
+ llvm::CallInst *call = Builder.CreateCall(callee, args, name);
+ call->setCallingConv(getRuntimeCC());
+ return call;
+}
+
+/// Emits a call or invoke to the given noreturn runtime function.
+void CodeGenFunction::EmitNoreturnRuntimeCallOrInvoke(llvm::Value *callee,
+ ArrayRef<llvm::Value*> args) {
+ if (getInvokeDest()) {
+ llvm::InvokeInst *invoke =
+ Builder.CreateInvoke(callee,
+ getUnreachableBlock(),
+ getInvokeDest(),
+ args);
+ invoke->setDoesNotReturn();
+ invoke->setCallingConv(getRuntimeCC());
+ } else {
+ llvm::CallInst *call = Builder.CreateCall(callee, args);
+ call->setDoesNotReturn();
+ call->setCallingConv(getRuntimeCC());
+ Builder.CreateUnreachable();
+ }
+}
+
+/// Emits a call or invoke instruction to the given nullary runtime
+/// function.
+llvm::CallSite
+CodeGenFunction::EmitRuntimeCallOrInvoke(llvm::Value *callee,
+ const Twine &name) {
+ return EmitRuntimeCallOrInvoke(callee, ArrayRef<llvm::Value*>(), name);
+}
+
+/// Emits a call or invoke instruction to the given runtime function.
+llvm::CallSite
+CodeGenFunction::EmitRuntimeCallOrInvoke(llvm::Value *callee,
+ ArrayRef<llvm::Value*> args,
+ const Twine &name) {
+ llvm::CallSite callSite = EmitCallOrInvoke(callee, args, name);
+ callSite.setCallingConv(getRuntimeCC());
+ return callSite;
+}
+
+llvm::CallSite
+CodeGenFunction::EmitCallOrInvoke(llvm::Value *Callee,
+ const Twine &Name) {
+ return EmitCallOrInvoke(Callee, ArrayRef<llvm::Value *>(), Name);
+}
+
/// Emits a call or invoke instruction to the given function, depending
/// on the current state of the EH stack.
llvm::CallSite
@@ -1862,12 +2119,6 @@ CodeGenFunction::EmitCallOrInvoke(llvm::Value *Callee,
return Inst;
}
-llvm::CallSite
-CodeGenFunction::EmitCallOrInvoke(llvm::Value *Callee,
- const Twine &Name) {
- return EmitCallOrInvoke(Callee, ArrayRef<llvm::Value *>(), Name);
-}
-
static void checkArgMatches(llvm::Value *Elt, unsigned &ArgNo,
llvm::FunctionType *FTy) {
if (ArgNo < FTy->getNumParams())
@@ -1886,15 +2137,7 @@ void CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV,
llvm::Value *Addr = RV.getAggregateAddr();
for (unsigned Elt = 0; Elt < NumElts; ++Elt) {
llvm::Value *EltAddr = Builder.CreateConstGEP2_32(Addr, 0, Elt);
- LValue LV = MakeAddrLValue(EltAddr, EltTy);
- RValue EltRV;
- if (EltTy->isAnyComplexType())
- // FIXME: Volatile?
- EltRV = RValue::getComplex(LoadComplexFromAddr(LV.getAddress(), false));
- else if (CodeGenFunction::hasAggregateLLVMType(EltTy))
- EltRV = LV.asAggregateRValue();
- else
- EltRV = EmitLoadOfLValue(LV);
+ RValue EltRV = convertTempToRValue(EltAddr, EltTy);
ExpandTypeToArgs(EltTy, EltRV, Args, IRFuncTy);
}
} else if (const RecordType *RT = Ty->getAs<RecordType>()) {
@@ -1987,8 +2230,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
const ABIArgInfo &ArgInfo = info_it->info;
RValue RV = I->RV;
- unsigned TypeAlign =
- getContext().getTypeAlignInChars(I->Ty).getQuantity();
+ CharUnits TypeAlign = getContext().getTypeAlignInChars(I->Ty);
// Insert a padding argument to ensure proper alignment.
if (llvm::Type *PaddingType = ArgInfo.getPaddingType()) {
@@ -2004,28 +2246,36 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
if (ArgInfo.getIndirectAlign() > AI->getAlignment())
AI->setAlignment(ArgInfo.getIndirectAlign());
Args.push_back(AI);
+
+ LValue argLV =
+ MakeAddrLValue(Args.back(), I->Ty, TypeAlign);
if (RV.isScalar())
- EmitStoreOfScalar(RV.getScalarVal(), Args.back(), false,
- TypeAlign, I->Ty);
+ EmitStoreOfScalar(RV.getScalarVal(), argLV, /*init*/ true);
else
- StoreComplexToAddr(RV.getComplexVal(), Args.back(), false);
+ EmitStoreOfComplex(RV.getComplexVal(), argLV, /*init*/ true);
// Validate argument match.
checkArgMatches(AI, IRArgNo, IRFuncTy);
} else {
// We want to avoid creating an unnecessary temporary+copy here;
- // however, we need one in two cases:
+ // however, we need one in three cases:
// 1. If the argument is not byval, and we are required to copy the
// source. (This case doesn't occur on any common architecture.)
// 2. If the argument is byval, RV is not sufficiently aligned, and
// we cannot force it to be sufficiently aligned.
+ // 3. If the argument is byval, but RV is located in an address space
+ // different than that of the argument (0).
llvm::Value *Addr = RV.getAggregateAddr();
unsigned Align = ArgInfo.getIndirectAlign();
const llvm::DataLayout *TD = &CGM.getDataLayout();
+ const unsigned RVAddrSpace = Addr->getType()->getPointerAddressSpace();
+ const unsigned ArgAddrSpace = (IRArgNo < IRFuncTy->getNumParams() ?
+ IRFuncTy->getParamType(IRArgNo)->getPointerAddressSpace() : 0);
if ((!ArgInfo.getIndirectByVal() && I->NeedsCopy) ||
- (ArgInfo.getIndirectByVal() && TypeAlign < Align &&
- llvm::getOrEnforceKnownAlignment(Addr, Align, TD) < Align)) {
+ (ArgInfo.getIndirectByVal() && TypeAlign.getQuantity() < Align &&
+ llvm::getOrEnforceKnownAlignment(Addr, Align, TD) < Align) ||
+ (ArgInfo.getIndirectByVal() && (RVAddrSpace != ArgAddrSpace))) {
// Create an aligned temporary, and copy to it.
llvm::AllocaInst *AI = CreateMemTemp(I->Ty);
if (Align > AI->getAlignment())
@@ -2073,12 +2323,14 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// FIXME: Avoid the conversion through memory if possible.
llvm::Value *SrcPtr;
- if (RV.isScalar()) {
- SrcPtr = CreateMemTemp(I->Ty, "coerce");
- EmitStoreOfScalar(RV.getScalarVal(), SrcPtr, false, TypeAlign, I->Ty);
- } else if (RV.isComplex()) {
+ if (RV.isScalar() || RV.isComplex()) {
SrcPtr = CreateMemTemp(I->Ty, "coerce");
- StoreComplexToAddr(RV.getComplexVal(), SrcPtr, false);
+ LValue SrcLV = MakeAddrLValue(SrcPtr, I->Ty, TypeAlign);
+ if (RV.isScalar()) {
+ EmitStoreOfScalar(RV.getScalarVal(), SrcLV, /*init*/ true);
+ } else {
+ EmitStoreOfComplex(RV.getComplexVal(), SrcLV, /*init*/ true);
+ }
} else
SrcPtr = RV.getAggregateAddr();
@@ -2176,12 +2428,14 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
unsigned CallingConv;
CodeGen::AttributeListType AttributeList;
- CGM.ConstructAttributeList(CallInfo, TargetDecl, AttributeList, CallingConv);
- llvm::AttrListPtr Attrs = llvm::AttrListPtr::get(getLLVMContext(),
- AttributeList);
+ CGM.ConstructAttributeList(CallInfo, TargetDecl, AttributeList,
+ CallingConv, true);
+ llvm::AttributeSet Attrs = llvm::AttributeSet::get(getLLVMContext(),
+ AttributeList);
llvm::BasicBlock *InvokeDest = 0;
- if (!Attrs.getFnAttributes().hasAttribute(llvm::Attributes::NoUnwind))
+ if (!Attrs.hasAttribute(llvm::AttributeSet::FunctionIndex,
+ llvm::Attribute::NoUnwind))
InvokeDest = getInvokeDest();
llvm::CallSite CS;
@@ -2229,14 +2483,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
emitWritebacks(*this, CallArgs);
switch (RetAI.getKind()) {
- case ABIArgInfo::Indirect: {
- unsigned Alignment = getContext().getTypeAlignInChars(RetTy).getQuantity();
- if (RetTy->isAnyComplexType())
- return RValue::getComplex(LoadComplexFromAddr(Args[0], false));
- if (CodeGenFunction::hasAggregateLLVMType(RetTy))
- return RValue::getAggregate(Args[0]);
- return RValue::get(EmitLoadOfScalar(Args[0], false, Alignment, RetTy));
- }
+ case ABIArgInfo::Indirect:
+ return convertTempToRValue(Args[0], RetTy);
case ABIArgInfo::Ignore:
// If we are ignoring an argument that had a result, make sure to
@@ -2247,12 +2495,13 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
case ABIArgInfo::Direct: {
llvm::Type *RetIRTy = ConvertType(RetTy);
if (RetAI.getCoerceToType() == RetIRTy && RetAI.getDirectOffset() == 0) {
- if (RetTy->isAnyComplexType()) {
+ switch (getEvaluationKind(RetTy)) {
+ case TEK_Complex: {
llvm::Value *Real = Builder.CreateExtractValue(CI, 0);
llvm::Value *Imag = Builder.CreateExtractValue(CI, 1);
return RValue::getComplex(std::make_pair(Real, Imag));
}
- if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
+ case TEK_Aggregate: {
llvm::Value *DestPtr = ReturnValue.getValue();
bool DestIsVolatile = ReturnValue.isVolatile();
@@ -2263,13 +2512,16 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
BuildAggStore(*this, CI, DestPtr, DestIsVolatile, false);
return RValue::getAggregate(DestPtr);
}
-
- // If the argument doesn't match, perform a bitcast to coerce it. This
- // can happen due to trivial type mismatches.
- llvm::Value *V = CI;
- if (V->getType() != RetIRTy)
- V = Builder.CreateBitCast(V, RetIRTy);
- return RValue::get(V);
+ case TEK_Scalar: {
+ // If the argument doesn't match, perform a bitcast to coerce it. This
+ // can happen due to trivial type mismatches.
+ llvm::Value *V = CI;
+ if (V->getType() != RetIRTy)
+ V = Builder.CreateBitCast(V, RetIRTy);
+ return RValue::get(V);
+ }
+ }
+ llvm_unreachable("bad evaluation kind");
}
llvm::Value *DestPtr = ReturnValue.getValue();
@@ -2290,12 +2542,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
}
CreateCoercedStore(CI, StorePtr, DestIsVolatile, *this);
- unsigned Alignment = getContext().getTypeAlignInChars(RetTy).getQuantity();
- if (RetTy->isAnyComplexType())
- return RValue::getComplex(LoadComplexFromAddr(DestPtr, false));
- if (CodeGenFunction::hasAggregateLLVMType(RetTy))
- return RValue::getAggregate(DestPtr);
- return RValue::get(EmitLoadOfScalar(DestPtr, false, Alignment, RetTy));
+ return convertTempToRValue(DestPtr, RetTy);
}
case ABIArgInfo::Expand:
diff --git a/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h
index dead7bd..85c3320 100644
--- a/lib/CodeGen/CGCall.h
+++ b/lib/CodeGen/CGCall.h
@@ -15,23 +15,20 @@
#ifndef CLANG_CODEGEN_CGCALL_H
#define CLANG_CODEGEN_CGCALL_H
-#include "llvm/ADT/FoldingSet.h"
-#include "llvm/Value.h"
-#include "clang/AST/Type.h"
-#include "clang/AST/CanonicalType.h"
-
#include "CGValue.h"
+#include "clang/AST/CanonicalType.h"
+#include "clang/AST/Type.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/IR/Value.h"
// FIXME: Restructure so we don't have to expose so much stuff.
#include "ABIInfo.h"
namespace llvm {
- struct AttributeWithIndex;
+ class AttributeSet;
class Function;
class Type;
class Value;
-
- template<typename T, unsigned> class SmallVector;
}
namespace clang {
@@ -42,7 +39,7 @@ namespace clang {
class VarDecl;
namespace CodeGen {
- typedef SmallVector<llvm::AttributeWithIndex, 8> AttributeListType;
+ typedef SmallVector<llvm::AttributeSet, 8> AttributeListType;
struct CallArg {
RValue RV;
@@ -59,14 +56,15 @@ namespace CodeGen {
public SmallVector<CallArg, 16> {
public:
struct Writeback {
- /// The original argument.
- llvm::Value *Address;
-
- /// The pointee type of the original argument.
- QualType AddressType;
+ /// The original argument. Note that the argument l-value
+ /// is potentially null.
+ LValue Source;
/// The temporary alloca.
llvm::Value *Temporary;
+
+ /// A value to "use" after the writeback, or null.
+ llvm::Value *ToUse;
};
void add(RValue rvalue, QualType type, bool needscopy = false) {
@@ -79,12 +77,12 @@ namespace CodeGen {
other.Writebacks.begin(), other.Writebacks.end());
}
- void addWriteback(llvm::Value *address, QualType addressType,
- llvm::Value *temporary) {
+ void addWriteback(LValue srcLV, llvm::Value *temporary,
+ llvm::Value *toUse) {
Writeback writeback;
- writeback.Address = address;
- writeback.AddressType = addressType;
+ writeback.Source = srcLV;
writeback.Temporary = temporary;
+ writeback.ToUse = toUse;
Writebacks.push_back(writeback);
}
@@ -135,7 +133,7 @@ namespace CodeGen {
}
bool allowsOptionalArgs() const { return NumRequired != ~0U; }
- bool getNumRequiredArgs() const {
+ unsigned getNumRequiredArgs() const {
assert(allowsOptionalArgs());
return NumRequired;
}
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index b2225e4..2ececb0 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -13,11 +13,14 @@
#include "CGBlocks.h"
#include "CGDebugInfo.h"
+#include "CGRecordLayout.h"
#include "CodeGenFunction.h"
+#include "CGCXXABI.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/Basic/TargetBuiltins.h"
#include "clang/Frontend/CodeGenOptions.h"
using namespace clang;
@@ -232,7 +235,7 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
QualType DerivedTy =
getContext().getCanonicalType(getContext().getTagDeclType(Derived));
llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo();
-
+
llvm::Value *NonVirtualOffset =
CGM.GetNonVirtualBaseClassOffset(Derived, PathBegin, PathEnd);
@@ -278,50 +281,51 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
return Value;
}
-
-/// GetVTTParameter - Return the VTT parameter that should be passed to a
-/// base constructor/destructor with virtual bases.
-static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD,
- bool ForVirtualBase) {
+
+llvm::Value *CodeGenFunction::GetVTTParameter(GlobalDecl GD,
+ bool ForVirtualBase,
+ bool Delegating) {
if (!CodeGenVTables::needsVTTParameter(GD)) {
// This constructor/destructor does not need a VTT parameter.
return 0;
}
- const CXXRecordDecl *RD = cast<CXXMethodDecl>(CGF.CurFuncDecl)->getParent();
+ const CXXRecordDecl *RD = cast<CXXMethodDecl>(CurFuncDecl)->getParent();
const CXXRecordDecl *Base = cast<CXXMethodDecl>(GD.getDecl())->getParent();
llvm::Value *VTT;
uint64_t SubVTTIndex;
- // If the record matches the base, this is the complete ctor/dtor
- // variant calling the base variant in a class with virtual bases.
- if (RD == Base) {
- assert(!CodeGenVTables::needsVTTParameter(CGF.CurGD) &&
+ if (Delegating) {
+ // If this is a delegating constructor call, just load the VTT.
+ return LoadCXXVTT();
+ } else if (RD == Base) {
+ // If the record matches the base, this is the complete ctor/dtor
+ // variant calling the base variant in a class with virtual bases.
+ assert(!CodeGenVTables::needsVTTParameter(CurGD) &&
"doing no-op VTT offset in base dtor/ctor?");
assert(!ForVirtualBase && "Can't have same class as virtual base!");
SubVTTIndex = 0;
} else {
- const ASTRecordLayout &Layout =
- CGF.getContext().getASTRecordLayout(RD);
+ const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
CharUnits BaseOffset = ForVirtualBase ?
Layout.getVBaseClassOffset(Base) :
Layout.getBaseClassOffset(Base);
SubVTTIndex =
- CGF.CGM.getVTables().getSubVTTIndex(RD, BaseSubobject(Base, BaseOffset));
+ CGM.getVTables().getSubVTTIndex(RD, BaseSubobject(Base, BaseOffset));
assert(SubVTTIndex != 0 && "Sub-VTT index must be greater than zero!");
}
- if (CodeGenVTables::needsVTTParameter(CGF.CurGD)) {
+ if (CodeGenVTables::needsVTTParameter(CurGD)) {
// A VTT parameter was passed to the constructor, use it.
- VTT = CGF.LoadCXXVTT();
- VTT = CGF.Builder.CreateConstInBoundsGEP1_64(VTT, SubVTTIndex);
+ VTT = LoadCXXVTT();
+ VTT = Builder.CreateConstInBoundsGEP1_64(VTT, SubVTTIndex);
} else {
// We're the complete constructor, so get the VTT by name.
- VTT = CGF.CGM.getVTables().GetAddrOfVTT(RD);
- VTT = CGF.Builder.CreateConstInBoundsGEP2_64(VTT, 0, SubVTTIndex);
+ VTT = CGM.getVTables().GetAddrOfVTT(RD);
+ VTT = Builder.CreateConstInBoundsGEP2_64(VTT, 0, SubVTTIndex);
}
return VTT;
@@ -344,7 +348,8 @@ namespace {
CGF.GetAddressOfDirectBaseInCompleteClass(CGF.LoadCXXThis(),
DerivedClass, BaseClass,
BaseIsVirtual);
- CGF.EmitCXXDestructorCall(D, Dtor_Base, BaseIsVirtual, Addr);
+ CGF.EmitCXXDestructorCall(D, Dtor_Base, BaseIsVirtual,
+ /*Delegating=*/false, Addr);
}
};
@@ -446,12 +451,14 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF,
LV.setAlignment(std::min(Align, LV.getAlignment()));
}
- if (!CGF.hasAggregateLLVMType(T)) {
+ switch (CGF.getEvaluationKind(T)) {
+ case TEK_Scalar:
CGF.EmitScalarInit(Init, /*decl*/ 0, LV, false);
- } else if (T->isAnyComplexType()) {
- CGF.EmitComplexExprIntoAddr(Init, LV.getAddress(),
- LV.isVolatileQualified());
- } else {
+ break;
+ case TEK_Complex:
+ CGF.EmitComplexExprIntoLValue(Init, LV, /*isInit*/ true);
+ break;
+ case TEK_Aggregate: {
AggValueSlot Slot =
AggValueSlot::forLValue(LV,
AggValueSlot::IsDestructed,
@@ -459,6 +466,8 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF,
AggValueSlot::IsNotAliased);
CGF.EmitAggExpr(Init, Slot);
+ break;
+ }
}
}
@@ -527,21 +536,6 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF,
CGF.EmitBlock(AfterFor, true);
}
-namespace {
- struct CallMemberDtor : EHScopeStack::Cleanup {
- llvm::Value *V;
- CXXDestructorDecl *Dtor;
-
- CallMemberDtor(llvm::Value *V, CXXDestructorDecl *Dtor)
- : V(V), Dtor(Dtor) {}
-
- void Emit(CodeGenFunction &CGF, Flags flags) {
- CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false,
- V);
- }
- };
-}
-
static void EmitMemberInitializer(CodeGenFunction &CGF,
const CXXRecordDecl *ClassDecl,
CXXCtorInitializer *MemberInit,
@@ -610,16 +604,19 @@ void CodeGenFunction::EmitInitializerForField(FieldDecl *Field,
LValue LHS, Expr *Init,
ArrayRef<VarDecl *> ArrayIndexes) {
QualType FieldType = Field->getType();
- if (!hasAggregateLLVMType(FieldType)) {
+ switch (getEvaluationKind(FieldType)) {
+ case TEK_Scalar:
if (LHS.isSimple()) {
EmitExprAsInit(Init, Field, LHS, false);
} else {
RValue RHS = RValue::get(EmitScalarExpr(Init));
EmitStoreThroughLValue(RHS, LHS);
}
- } else if (FieldType->isAnyComplexType()) {
- EmitComplexExprIntoAddr(Init, LHS.getAddress(), LHS.isVolatileQualified());
- } else {
+ break;
+ case TEK_Complex:
+ EmitComplexExprIntoLValue(Init, LHS, /*isInit*/ true);
+ break;
+ case TEK_Aggregate: {
llvm::Value *ArrayIndexVar = 0;
if (ArrayIndexes.size()) {
llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
@@ -647,22 +644,14 @@ void CodeGenFunction::EmitInitializerForField(FieldDecl *Field,
EmitAggMemberInitializer(*this, LHS, Init, ArrayIndexVar, FieldType,
ArrayIndexes, 0);
-
- if (!CGM.getLangOpts().Exceptions)
- return;
-
- // FIXME: If we have an array of classes w/ non-trivial destructors,
- // we need to destroy in reverse order of construction along the exception
- // path.
- const RecordType *RT = FieldType->getAs<RecordType>();
- if (!RT)
- return;
-
- CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (!RD->hasTrivialDestructor())
- EHStack.pushCleanup<CallMemberDtor>(EHCleanup, LHS.getAddress(),
- RD->getDestructor());
}
+ }
+
+ // Ensure that we destroy this object if an exception is thrown
+ // later in the constructor.
+ QualType::DestructionKind dtorKind = FieldType.isDestructedType();
+ if (needsEHCleanup(dtorKind))
+ pushEHDestroy(dtorKind, LHS.getAddress(), FieldType);
}
/// Checks whether the given constructor is a valid subject for the
@@ -721,7 +710,7 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
// Before we go any further, try the complete->base constructor
// delegation optimization.
if (CtorType == Ctor_Complete && IsConstructorDelegationValid(Ctor) &&
- CGM.getContext().getTargetInfo().getCXXABI() != CXXABI_Microsoft) {
+ CGM.getContext().getTargetInfo().getCXXABI().hasConstructorVariants()) {
if (CGDebugInfo *DI = getDebugInfo())
DI->EmitLocation(Builder, Ctor->getLocEnd());
EmitDelegateCXXConstructorCall(Ctor, Ctor_Base, Args);
@@ -761,6 +750,353 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
ExitCXXTryStmt(*cast<CXXTryStmt>(Body), true);
}
+namespace {
+ class FieldMemcpyizer {
+ public:
+ FieldMemcpyizer(CodeGenFunction &CGF, const CXXRecordDecl *ClassDecl,
+ const VarDecl *SrcRec)
+ : CGF(CGF), ClassDecl(ClassDecl), SrcRec(SrcRec),
+ RecLayout(CGF.getContext().getASTRecordLayout(ClassDecl)),
+ FirstField(0), LastField(0), FirstFieldOffset(0), LastFieldOffset(0),
+ LastAddedFieldIndex(0) { }
+
+ static bool isMemcpyableField(FieldDecl *F) {
+ Qualifiers Qual = F->getType().getQualifiers();
+ if (Qual.hasVolatile() || Qual.hasObjCLifetime())
+ return false;
+ return true;
+ }
+
+ void addMemcpyableField(FieldDecl *F) {
+ if (FirstField == 0)
+ addInitialField(F);
+ else
+ addNextField(F);
+ }
+
+ CharUnits getMemcpySize() const {
+ unsigned LastFieldSize =
+ LastField->isBitField() ?
+ LastField->getBitWidthValue(CGF.getContext()) :
+ CGF.getContext().getTypeSize(LastField->getType());
+ uint64_t MemcpySizeBits =
+ LastFieldOffset + LastFieldSize - FirstFieldOffset +
+ CGF.getContext().getCharWidth() - 1;
+ CharUnits MemcpySize =
+ CGF.getContext().toCharUnitsFromBits(MemcpySizeBits);
+ return MemcpySize;
+ }
+
+ void emitMemcpy() {
+ // Give the subclass a chance to bail out if it feels the memcpy isn't
+ // worth it (e.g. Hasn't aggregated enough data).
+ if (FirstField == 0) {
+ return;
+ }
+
+ CharUnits Alignment;
+
+ if (FirstField->isBitField()) {
+ const CGRecordLayout &RL =
+ CGF.getTypes().getCGRecordLayout(FirstField->getParent());
+ const CGBitFieldInfo &BFInfo = RL.getBitFieldInfo(FirstField);
+ Alignment = CharUnits::fromQuantity(BFInfo.StorageAlignment);
+ } else {
+ Alignment = CGF.getContext().getDeclAlign(FirstField);
+ }
+
+ assert((CGF.getContext().toCharUnitsFromBits(FirstFieldOffset) %
+ Alignment) == 0 && "Bad field alignment.");
+
+ CharUnits MemcpySize = getMemcpySize();
+ QualType RecordTy = CGF.getContext().getTypeDeclType(ClassDecl);
+ llvm::Value *ThisPtr = CGF.LoadCXXThis();
+ LValue DestLV = CGF.MakeNaturalAlignAddrLValue(ThisPtr, RecordTy);
+ LValue Dest = CGF.EmitLValueForFieldInitialization(DestLV, FirstField);
+ llvm::Value *SrcPtr = CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(SrcRec));
+ LValue SrcLV = CGF.MakeNaturalAlignAddrLValue(SrcPtr, RecordTy);
+ LValue Src = CGF.EmitLValueForFieldInitialization(SrcLV, FirstField);
+
+ emitMemcpyIR(Dest.isBitField() ? Dest.getBitFieldAddr() : Dest.getAddress(),
+ Src.isBitField() ? Src.getBitFieldAddr() : Src.getAddress(),
+ MemcpySize, Alignment);
+ reset();
+ }
+
+ void reset() {
+ FirstField = 0;
+ }
+
+ protected:
+ CodeGenFunction &CGF;
+ const CXXRecordDecl *ClassDecl;
+
+ private:
+
+ void emitMemcpyIR(llvm::Value *DestPtr, llvm::Value *SrcPtr,
+ CharUnits Size, CharUnits Alignment) {
+ llvm::PointerType *DPT = cast<llvm::PointerType>(DestPtr->getType());
+ llvm::Type *DBP =
+ llvm::Type::getInt8PtrTy(CGF.getLLVMContext(), DPT->getAddressSpace());
+ DestPtr = CGF.Builder.CreateBitCast(DestPtr, DBP);
+
+ llvm::PointerType *SPT = cast<llvm::PointerType>(SrcPtr->getType());
+ llvm::Type *SBP =
+ llvm::Type::getInt8PtrTy(CGF.getLLVMContext(), SPT->getAddressSpace());
+ SrcPtr = CGF.Builder.CreateBitCast(SrcPtr, SBP);
+
+ CGF.Builder.CreateMemCpy(DestPtr, SrcPtr, Size.getQuantity(),
+ Alignment.getQuantity());
+ }
+
+ void addInitialField(FieldDecl *F) {
+ FirstField = F;
+ LastField = F;
+ FirstFieldOffset = RecLayout.getFieldOffset(F->getFieldIndex());
+ LastFieldOffset = FirstFieldOffset;
+ LastAddedFieldIndex = F->getFieldIndex();
+ return;
+ }
+
+ void addNextField(FieldDecl *F) {
+ assert(F->getFieldIndex() == LastAddedFieldIndex + 1 &&
+ "Cannot aggregate non-contiguous fields.");
+ LastAddedFieldIndex = F->getFieldIndex();
+
+ // The 'first' and 'last' fields are chosen by offset, rather than field
+ // index. This allows the code to support bitfields, as well as regular
+ // fields.
+ uint64_t FOffset = RecLayout.getFieldOffset(F->getFieldIndex());
+ if (FOffset < FirstFieldOffset) {
+ FirstField = F;
+ FirstFieldOffset = FOffset;
+ } else if (FOffset > LastFieldOffset) {
+ LastField = F;
+ LastFieldOffset = FOffset;
+ }
+ }
+
+ const VarDecl *SrcRec;
+ const ASTRecordLayout &RecLayout;
+ FieldDecl *FirstField;
+ FieldDecl *LastField;
+ uint64_t FirstFieldOffset, LastFieldOffset;
+ unsigned LastAddedFieldIndex;
+ };
+
+ class ConstructorMemcpyizer : public FieldMemcpyizer {
+ private:
+
+ /// Get source argument for copy constructor. Returns null if not a copy
+ /// constructor.
+ static const VarDecl* getTrivialCopySource(const CXXConstructorDecl *CD,
+ FunctionArgList &Args) {
+ if (CD->isCopyOrMoveConstructor() && CD->isImplicitlyDefined())
+ return Args[Args.size() - 1];
+ return 0;
+ }
+
+ // Returns true if a CXXCtorInitializer represents a member initialization
+ // that can be rolled into a memcpy.
+ bool isMemberInitMemcpyable(CXXCtorInitializer *MemberInit) const {
+ if (!MemcpyableCtor)
+ return false;
+ FieldDecl *Field = MemberInit->getMember();
+ assert(Field != 0 && "No field for member init.");
+ QualType FieldType = Field->getType();
+ CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(MemberInit->getInit());
+
+ // Bail out on non-POD, not-trivially-constructable members.
+ if (!(CE && CE->getConstructor()->isTrivial()) &&
+ !(FieldType.isTriviallyCopyableType(CGF.getContext()) ||
+ FieldType->isReferenceType()))
+ return false;
+
+ // Bail out on volatile fields.
+ if (!isMemcpyableField(Field))
+ return false;
+
+ // Otherwise we're good.
+ return true;
+ }
+
+ public:
+ ConstructorMemcpyizer(CodeGenFunction &CGF, const CXXConstructorDecl *CD,
+ FunctionArgList &Args)
+ : FieldMemcpyizer(CGF, CD->getParent(), getTrivialCopySource(CD, Args)),
+ ConstructorDecl(CD),
+ MemcpyableCtor(CD->isImplicitlyDefined() &&
+ CD->isCopyOrMoveConstructor() &&
+ CGF.getLangOpts().getGC() == LangOptions::NonGC),
+ Args(Args) { }
+
+ void addMemberInitializer(CXXCtorInitializer *MemberInit) {
+ if (isMemberInitMemcpyable(MemberInit)) {
+ AggregatedInits.push_back(MemberInit);
+ addMemcpyableField(MemberInit->getMember());
+ } else {
+ emitAggregatedInits();
+ EmitMemberInitializer(CGF, ConstructorDecl->getParent(), MemberInit,
+ ConstructorDecl, Args);
+ }
+ }
+
+ void emitAggregatedInits() {
+ if (AggregatedInits.size() <= 1) {
+ // This memcpy is too small to be worthwhile. Fall back on default
+ // codegen.
+ for (unsigned i = 0; i < AggregatedInits.size(); ++i) {
+ EmitMemberInitializer(CGF, ConstructorDecl->getParent(),
+ AggregatedInits[i], ConstructorDecl, Args);
+ }
+ reset();
+ return;
+ }
+
+ pushEHDestructors();
+ emitMemcpy();
+ AggregatedInits.clear();
+ }
+
+ void pushEHDestructors() {
+ llvm::Value *ThisPtr = CGF.LoadCXXThis();
+ QualType RecordTy = CGF.getContext().getTypeDeclType(ClassDecl);
+ LValue LHS = CGF.MakeNaturalAlignAddrLValue(ThisPtr, RecordTy);
+
+ for (unsigned i = 0; i < AggregatedInits.size(); ++i) {
+ QualType FieldType = AggregatedInits[i]->getMember()->getType();
+ QualType::DestructionKind dtorKind = FieldType.isDestructedType();
+ if (CGF.needsEHCleanup(dtorKind))
+ CGF.pushEHDestroy(dtorKind, LHS.getAddress(), FieldType);
+ }
+ }
+
+ void finish() {
+ emitAggregatedInits();
+ }
+
+ private:
+ const CXXConstructorDecl *ConstructorDecl;
+ bool MemcpyableCtor;
+ FunctionArgList &Args;
+ SmallVector<CXXCtorInitializer*, 16> AggregatedInits;
+ };
+
+ class AssignmentMemcpyizer : public FieldMemcpyizer {
+ private:
+
+ // Returns the memcpyable field copied by the given statement, if one
+ // exists. Otherwise r
+ FieldDecl* getMemcpyableField(Stmt *S) {
+ if (!AssignmentsMemcpyable)
+ return 0;
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(S)) {
+ // Recognise trivial assignments.
+ if (BO->getOpcode() != BO_Assign)
+ return 0;
+ MemberExpr *ME = dyn_cast<MemberExpr>(BO->getLHS());
+ if (!ME)
+ return 0;
+ FieldDecl *Field = dyn_cast<FieldDecl>(ME->getMemberDecl());
+ if (!Field || !isMemcpyableField(Field))
+ return 0;
+ Stmt *RHS = BO->getRHS();
+ if (ImplicitCastExpr *EC = dyn_cast<ImplicitCastExpr>(RHS))
+ RHS = EC->getSubExpr();
+ if (!RHS)
+ return 0;
+ MemberExpr *ME2 = dyn_cast<MemberExpr>(RHS);
+ if (dyn_cast<FieldDecl>(ME2->getMemberDecl()) != Field)
+ return 0;
+ return Field;
+ } else if (CXXMemberCallExpr *MCE = dyn_cast<CXXMemberCallExpr>(S)) {
+ CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MCE->getCalleeDecl());
+ if (!(MD && (MD->isCopyAssignmentOperator() ||
+ MD->isMoveAssignmentOperator()) &&
+ MD->isTrivial()))
+ return 0;
+ MemberExpr *IOA = dyn_cast<MemberExpr>(MCE->getImplicitObjectArgument());
+ if (!IOA)
+ return 0;
+ FieldDecl *Field = dyn_cast<FieldDecl>(IOA->getMemberDecl());
+ if (!Field || !isMemcpyableField(Field))
+ return 0;
+ MemberExpr *Arg0 = dyn_cast<MemberExpr>(MCE->getArg(0));
+ if (!Arg0 || Field != dyn_cast<FieldDecl>(Arg0->getMemberDecl()))
+ return 0;
+ return Field;
+ } else if (CallExpr *CE = dyn_cast<CallExpr>(S)) {
+ FunctionDecl *FD = dyn_cast<FunctionDecl>(CE->getCalleeDecl());
+ if (!FD || FD->getBuiltinID() != Builtin::BI__builtin_memcpy)
+ return 0;
+ Expr *DstPtr = CE->getArg(0);
+ if (ImplicitCastExpr *DC = dyn_cast<ImplicitCastExpr>(DstPtr))
+ DstPtr = DC->getSubExpr();
+ UnaryOperator *DUO = dyn_cast<UnaryOperator>(DstPtr);
+ if (!DUO || DUO->getOpcode() != UO_AddrOf)
+ return 0;
+ MemberExpr *ME = dyn_cast<MemberExpr>(DUO->getSubExpr());
+ if (!ME)
+ return 0;
+ FieldDecl *Field = dyn_cast<FieldDecl>(ME->getMemberDecl());
+ if (!Field || !isMemcpyableField(Field))
+ return 0;
+ Expr *SrcPtr = CE->getArg(1);
+ if (ImplicitCastExpr *SC = dyn_cast<ImplicitCastExpr>(SrcPtr))
+ SrcPtr = SC->getSubExpr();
+ UnaryOperator *SUO = dyn_cast<UnaryOperator>(SrcPtr);
+ if (!SUO || SUO->getOpcode() != UO_AddrOf)
+ return 0;
+ MemberExpr *ME2 = dyn_cast<MemberExpr>(SUO->getSubExpr());
+ if (!ME2 || Field != dyn_cast<FieldDecl>(ME2->getMemberDecl()))
+ return 0;
+ return Field;
+ }
+
+ return 0;
+ }
+
+ bool AssignmentsMemcpyable;
+ SmallVector<Stmt*, 16> AggregatedStmts;
+
+ public:
+
+ AssignmentMemcpyizer(CodeGenFunction &CGF, const CXXMethodDecl *AD,
+ FunctionArgList &Args)
+ : FieldMemcpyizer(CGF, AD->getParent(), Args[Args.size() - 1]),
+ AssignmentsMemcpyable(CGF.getLangOpts().getGC() == LangOptions::NonGC) {
+ assert(Args.size() == 2);
+ }
+
+ void emitAssignment(Stmt *S) {
+ FieldDecl *F = getMemcpyableField(S);
+ if (F) {
+ addMemcpyableField(F);
+ AggregatedStmts.push_back(S);
+ } else {
+ emitAggregatedStmts();
+ CGF.EmitStmt(S);
+ }
+ }
+
+ void emitAggregatedStmts() {
+ if (AggregatedStmts.size() <= 1) {
+ for (unsigned i = 0; i < AggregatedStmts.size(); ++i)
+ CGF.EmitStmt(AggregatedStmts[i]);
+ reset();
+ }
+
+ emitMemcpy();
+ AggregatedStmts.clear();
+ }
+
+ void finish() {
+ emitAggregatedStmts();
+ }
+ };
+
+}
+
/// EmitCtorPrologue - This routine generates necessary code to initialize
/// base classes and non-static data members belonging to this constructor.
void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
@@ -771,26 +1107,47 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
const CXXRecordDecl *ClassDecl = CD->getParent();
- SmallVector<CXXCtorInitializer *, 8> MemberInitializers;
-
- for (CXXConstructorDecl::init_const_iterator B = CD->init_begin(),
- E = CD->init_end();
- B != E; ++B) {
- CXXCtorInitializer *Member = (*B);
-
- if (Member->isBaseInitializer()) {
- EmitBaseInitializer(*this, ClassDecl, Member, CtorType);
- } else {
- assert(Member->isAnyMemberInitializer() &&
- "Delegating initializer on non-delegating constructor");
- MemberInitializers.push_back(Member);
- }
+ CXXConstructorDecl::init_const_iterator B = CD->init_begin(),
+ E = CD->init_end();
+
+ llvm::BasicBlock *BaseCtorContinueBB = 0;
+ if (ClassDecl->getNumVBases() &&
+ !CGM.getTarget().getCXXABI().hasConstructorVariants()) {
+ // The ABIs that don't have constructor variants need to put a branch
+ // before the virtual base initialization code.
+ BaseCtorContinueBB = CGM.getCXXABI().EmitCtorCompleteObjectHandler(*this);
+ assert(BaseCtorContinueBB);
+ }
+
+ // Virtual base initializers first.
+ for (; B != E && (*B)->isBaseInitializer() && (*B)->isBaseVirtual(); B++) {
+ EmitBaseInitializer(*this, ClassDecl, *B, CtorType);
+ }
+
+ if (BaseCtorContinueBB) {
+ // Complete object handler should continue to the remaining initializers.
+ Builder.CreateBr(BaseCtorContinueBB);
+ EmitBlock(BaseCtorContinueBB);
+ }
+
+ // Then, non-virtual base initializers.
+ for (; B != E && (*B)->isBaseInitializer(); B++) {
+ assert(!(*B)->isBaseVirtual());
+ EmitBaseInitializer(*this, ClassDecl, *B, CtorType);
}
InitializeVTablePointers(ClassDecl);
- for (unsigned I = 0, E = MemberInitializers.size(); I != E; ++I)
- EmitMemberInitializer(*this, ClassDecl, MemberInitializers[I], CD, Args);
+ // And finally, initialize class members.
+ ConstructorMemcpyizer CM(*this, CD, Args);
+ for (; B != E; B++) {
+ CXXCtorInitializer *Member = (*B);
+ assert(!Member->isBaseInitializer());
+ assert(Member->isAnyMemberInitializer() &&
+ "Delegating initializer on non-delegating constructor");
+ CM.addMemberInitializer(Member);
+ }
+ CM.finish();
}
static bool
@@ -893,7 +1250,7 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
if (DtorType == Dtor_Deleting) {
EnterDtorCleanups(Dtor, Dtor_Deleting);
EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false,
- LoadCXXThis());
+ /*Delegating=*/false, LoadCXXThis());
PopCleanupBlock();
return;
}
@@ -920,9 +1277,10 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
// Enter the cleanup scopes for virtual bases.
EnterDtorCleanups(Dtor, Dtor_Complete);
- if (!isTryBody && CGM.getContext().getTargetInfo().getCXXABI() != CXXABI_Microsoft) {
+ if (!isTryBody &&
+ CGM.getContext().getTargetInfo().getCXXABI().hasDestructorVariants()) {
EmitCXXDestructorCall(Dtor, Dtor_Base, /*ForVirtualBase=*/false,
- LoadCXXThis());
+ /*Delegating=*/false, LoadCXXThis());
break;
}
// Fallthrough: act like we're in the base variant.
@@ -946,7 +1304,7 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
// -fapple-kext must inline any call to this dtor into
// the caller's body.
if (getLangOpts().AppleKext)
- CurFn->addFnAttr(llvm::Attributes::AlwaysInline);
+ CurFn->addFnAttr(llvm::Attribute::AlwaysInline);
break;
}
@@ -958,6 +1316,24 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
ExitCXXTryStmt(*cast<CXXTryStmt>(Body), true);
}
+void CodeGenFunction::emitImplicitAssignmentOperatorBody(FunctionArgList &Args) {
+ const CXXMethodDecl *AssignOp = cast<CXXMethodDecl>(CurGD.getDecl());
+ const Stmt *RootS = AssignOp->getBody();
+ assert(isa<CompoundStmt>(RootS) &&
+ "Body of an implicit assignment operator should be compound stmt.");
+ const CompoundStmt *RootCS = cast<CompoundStmt>(RootS);
+
+ LexicalScope Scope(*this, RootCS->getSourceRange());
+
+ AssignmentMemcpyizer AM(*this, AssignOp, Args);
+ for (CompoundStmt::const_body_iterator I = RootCS->body_begin(),
+ E = RootCS->body_end();
+ I != E; ++I) {
+ AM.emitAssignment(*I);
+ }
+ AM.finish();
+}
+
namespace {
/// Call the operator delete associated with the current destructor.
struct CallDtorDelete : EHScopeStack::Cleanup {
@@ -971,6 +1347,32 @@ namespace {
}
};
+ struct CallDtorDeleteConditional : EHScopeStack::Cleanup {
+ llvm::Value *ShouldDeleteCondition;
+ public:
+ CallDtorDeleteConditional(llvm::Value *ShouldDeleteCondition)
+ : ShouldDeleteCondition(ShouldDeleteCondition) {
+ assert(ShouldDeleteCondition != NULL);
+ }
+
+ void Emit(CodeGenFunction &CGF, Flags flags) {
+ llvm::BasicBlock *callDeleteBB = CGF.createBasicBlock("dtor.call_delete");
+ llvm::BasicBlock *continueBB = CGF.createBasicBlock("dtor.continue");
+ llvm::Value *ShouldCallDelete
+ = CGF.Builder.CreateIsNull(ShouldDeleteCondition);
+ CGF.Builder.CreateCondBr(ShouldCallDelete, continueBB, callDeleteBB);
+
+ CGF.EmitBlock(callDeleteBB);
+ const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CGF.CurCodeDecl);
+ const CXXRecordDecl *ClassDecl = Dtor->getParent();
+ CGF.EmitDeleteCall(Dtor->getOperatorDelete(), CGF.LoadCXXThis(),
+ CGF.getContext().getTagDeclType(ClassDecl));
+ CGF.Builder.CreateBr(continueBB);
+
+ CGF.EmitBlock(continueBB);
+ }
+ };
+
class DestroyField : public EHScopeStack::Cleanup {
const FieldDecl *field;
CodeGenFunction::Destroyer *destroyer;
@@ -1009,7 +1411,14 @@ void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD,
if (DtorType == Dtor_Deleting) {
assert(DD->getOperatorDelete() &&
"operator delete missing - EmitDtorEpilogue");
- EHStack.pushCleanup<CallDtorDelete>(NormalAndEHCleanup);
+ if (CXXStructorImplicitParamValue) {
+ // If there is an implicit param to the deleting dtor, it's a boolean
+ // telling whether we should call delete at the end of the dtor.
+ EHStack.pushCleanup<CallDtorDeleteConditional>(
+ NormalAndEHCleanup, CXXStructorImplicitParamValue);
+ } else {
+ EHStack.pushCleanup<CallDtorDelete>(NormalAndEHCleanup);
+ }
return;
}
@@ -1089,8 +1498,6 @@ void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD,
/// constructor for each of several members of an array.
///
/// \param ctor the constructor to call for each element
-/// \param argBegin,argEnd the arguments to evaluate and pass to the
-/// constructor
/// \param arrayType the type of the array to initialize
/// \param arrayBegin an arrayType*
/// \param zeroInitialize true if each element should be
@@ -1116,8 +1523,6 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *ctor,
/// \param ctor the constructor to call for each element
/// \param numElements the number of elements in the array;
/// may be zero
-/// \param argBegin,argEnd the arguments to evaluate and pass to the
-/// constructor
/// \param arrayBegin a T*, where T is the type constructed by ctor
/// \param zeroInitialize true if each element should be
/// zero-initialized before it is constructed
@@ -1191,7 +1596,7 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *ctor,
}
EmitCXXConstructorCall(ctor, Ctor_Complete, /*ForVirtualBase=*/ false,
- cur, argBegin, argEnd);
+ /*Delegating=*/false, cur, argBegin, argEnd);
}
// Go to the next element.
@@ -1219,12 +1624,13 @@ void CodeGenFunction::destroyCXXObject(CodeGenFunction &CGF,
const CXXDestructorDecl *dtor = record->getDestructor();
assert(!dtor->isTrivial());
CGF.EmitCXXDestructorCall(dtor, Dtor_Complete, /*for vbase*/ false,
- addr);
+ /*Delegating=*/false, addr);
}
void
CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
CXXCtorType Type, bool ForVirtualBase,
+ bool Delegating,
llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd) {
@@ -1239,6 +1645,7 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
Parent->getLocation());
}
+ // If this is a trivial constructor, just emit what's needed.
if (D->isTrivial()) {
if (ArgBeg == ArgEnd) {
// Trivial default constructor, no codegen required.
@@ -1258,12 +1665,12 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
return;
}
- llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(D, Type), ForVirtualBase);
- llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
-
- // FIXME: Provide a source location here.
- EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
- VTT, ArgBeg, ArgEnd);
+ // Non-trivial constructors are handled in an ABI-specific manner.
+ llvm::Value *Callee = CGM.getCXXABI().EmitConstructorCall(*this, D, Type,
+ ForVirtualBase, Delegating, This, ArgBeg, ArgEnd);
+ if (CGM.getCXXABI().HasThisReturn(CurGD) &&
+ CGM.getCXXABI().HasThisReturn(GlobalDecl(D, Type)))
+ CalleeWithThisReturn = Callee;
}
void
@@ -1333,8 +1740,9 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
++I;
// vtt
- if (llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(Ctor, CtorType),
- /*ForVirtualBase=*/false)) {
+ if (llvm::Value *VTT = GetVTTParameter(GlobalDecl(Ctor, CtorType),
+ /*ForVirtualBase=*/false,
+ /*Delegating=*/true)) {
QualType VoidPP = getContext().getPointerType(getContext().VoidPtrTy);
DelegateArgs.add(RValue::get(VTT), VoidPP);
@@ -1351,9 +1759,12 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
EmitDelegateCallArg(DelegateArgs, param);
}
+ llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(Ctor, CtorType);
EmitCall(CGM.getTypes().arrangeCXXConstructorDeclaration(Ctor, CtorType),
- CGM.GetAddrOfCXXConstructor(Ctor, CtorType),
- ReturnValueSlot(), DelegateArgs, Ctor);
+ Callee, ReturnValueSlot(), DelegateArgs, Ctor);
+ if (CGM.getCXXABI().HasThisReturn(CurGD) &&
+ CGM.getCXXABI().HasThisReturn(GlobalDecl(Ctor, CtorType)))
+ CalleeWithThisReturn = Callee;
}
namespace {
@@ -1368,7 +1779,7 @@ namespace {
void Emit(CodeGenFunction &CGF, Flags flags) {
CGF.EmitCXXDestructorCall(Dtor, Type, /*ForVirtualBase=*/false,
- Addr);
+ /*Delegating=*/true, Addr);
}
};
}
@@ -1404,9 +1815,10 @@ CodeGenFunction::EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor
void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
CXXDtorType Type,
bool ForVirtualBase,
+ bool Delegating,
llvm::Value *This) {
- llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(DD, Type),
- ForVirtualBase);
+ llvm::Value *VTT = GetVTTParameter(GlobalDecl(DD, Type),
+ ForVirtualBase, Delegating);
llvm::Value *Callee = 0;
if (getLangOpts().AppleKext)
Callee = BuildAppleKextVirtualDestructorCall(DD, Type,
@@ -1417,7 +1829,11 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
// FIXME: Provide a source location here.
EmitCXXMemberCall(DD, SourceLocation(), Callee, ReturnValueSlot(), This,
- VTT, 0, 0);
+ VTT, getContext().getPointerType(getContext().VoidPtrTy),
+ 0, 0);
+ if (CGM.getCXXABI().HasThisReturn(CurGD) &&
+ CGM.getCXXABI().HasThisReturn(GlobalDecl(DD, Type)))
+ CalleeWithThisReturn = Callee;
}
namespace {
@@ -1430,7 +1846,8 @@ namespace {
void Emit(CodeGenFunction &CGF, Flags flags) {
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete,
- /*ForVirtualBase=*/false, Addr);
+ /*ForVirtualBase=*/false,
+ /*Delegating=*/false, Addr);
}
};
}
@@ -1757,7 +2174,7 @@ void CodeGenFunction::EmitForwardingCallToLambda(const CXXRecordDecl *lambda,
DeclarationName operatorName
= getContext().DeclarationNames.getCXXOperatorName(OO_Call);
CXXMethodDecl *callOperator =
- cast<CXXMethodDecl>(*lambda->lookup(operatorName).first);
+ cast<CXXMethodDecl>(lambda->lookup(operatorName).front());
// Get the address of the call operator.
const CGFunctionInfo &calleeFnInfo =
@@ -1773,7 +2190,7 @@ void CodeGenFunction::EmitForwardingCallToLambda(const CXXRecordDecl *lambda,
ReturnValueSlot returnSlot;
if (!resultType->isVoidType() &&
calleeFnInfo.getReturnInfo().getKind() == ABIArgInfo::Indirect &&
- hasAggregateLLVMType(calleeFnInfo.getReturnType()))
+ !hasScalarEvaluationKind(calleeFnInfo.getReturnType()))
returnSlot = ReturnValueSlot(ReturnValue, resultType.isVolatileQualified());
// We don't need to separately arrange the call arguments because
@@ -1787,6 +2204,8 @@ void CodeGenFunction::EmitForwardingCallToLambda(const CXXRecordDecl *lambda,
// If necessary, copy the returned value into the slot.
if (!resultType->isVoidType() && returnSlot.isNull())
EmitReturnOfRValue(RV, resultType);
+ else
+ EmitBranchThroughCleanup(ReturnBlock);
}
void CodeGenFunction::EmitLambdaBlockInvokeBody() {
diff --git a/lib/CodeGen/CGCleanup.cpp b/lib/CodeGen/CGCleanup.cpp
index f9ea7e0..861d31f 100644
--- a/lib/CodeGen/CGCleanup.cpp
+++ b/lib/CodeGen/CGCleanup.cpp
@@ -52,7 +52,8 @@ DominatingValue<RValue>::saved_type::save(CodeGenFunction &CGF, RValue rv) {
llvm::StructType::get(V.first->getType(), V.second->getType(),
(void*) 0);
llvm::Value *addr = CGF.CreateTempAlloca(ComplexTy, "saved-complex");
- CGF.StoreComplexToAddr(V, addr, /*volatile*/ false);
+ CGF.Builder.CreateStore(V.first, CGF.Builder.CreateStructGEP(addr, 0));
+ CGF.Builder.CreateStore(V.second, CGF.Builder.CreateStructGEP(addr, 1));
return saved_type(addr, ComplexAddress);
}
@@ -79,8 +80,13 @@ RValue DominatingValue<RValue>::saved_type::restore(CodeGenFunction &CGF) {
return RValue::getAggregate(Value);
case AggregateAddress:
return RValue::getAggregate(CGF.Builder.CreateLoad(Value));
- case ComplexAddress:
- return RValue::getComplex(CGF.LoadComplexFromAddr(Value, false));
+ case ComplexAddress: {
+ llvm::Value *real =
+ CGF.Builder.CreateLoad(CGF.Builder.CreateStructGEP(Value, 0));
+ llvm::Value *imag =
+ CGF.Builder.CreateLoad(CGF.Builder.CreateStructGEP(Value, 1));
+ return RValue::getComplex(real, imag);
+ }
}
llvm_unreachable("bad saved r-value kind");
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 80fa09b..711d686 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -12,30 +12,30 @@
//===----------------------------------------------------------------------===//
#include "CGDebugInfo.h"
-#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
#include "CGBlocks.h"
#include "CGObjCRuntime.h"
+#include "CodeGenFunction.h"
+#include "CodeGenModule.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h"
-#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Version.h"
#include "clang/Frontend/CodeGenOptions.h"
-#include "llvm/Constants.h"
-#include "llvm/DerivedTypes.h"
-#include "llvm/Instructions.h"
-#include "llvm/Intrinsics.h"
-#include "llvm/Module.h"
-#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/Module.h"
#include "llvm/Support/Dwarf.h"
#include "llvm/Support/FileSystem.h"
-#include "llvm/DataLayout.h"
using namespace clang;
using namespace clang::CodeGen;
@@ -79,7 +79,7 @@ void CGDebugInfo::setLocation(SourceLocation Loc) {
llvm::MDNode *N = D;
LexicalBlockStack.pop_back();
LexicalBlockStack.push_back(N);
- } else if (Scope.isLexicalBlock()) {
+ } else if (Scope.isLexicalBlock() || Scope.isSubprogram()) {
llvm::DIDescriptor D
= DBuilder.createLexicalBlockFile(Scope, getOrCreateFile(CurLoc));
llvm::MDNode *N = D;
@@ -126,7 +126,9 @@ StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) {
return FII->getName();
// Otherwise construct human readable name for debug info.
- std::string NS = FD->getNameAsString();
+ SmallString<128> NS;
+ llvm::raw_svector_ostream OS(NS);
+ FD->printName(OS);
// Add any template specialization args.
if (Info) {
@@ -134,15 +136,15 @@ StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) {
const TemplateArgument *Args = TArgs->data();
unsigned NumArgs = TArgs->size();
PrintingPolicy Policy(CGM.getLangOpts());
- NS += TemplateSpecializationType::PrintTemplateArgumentList(Args,
- NumArgs,
- Policy);
+ TemplateSpecializationType::PrintTemplateArgumentList(OS, Args, NumArgs,
+ Policy);
}
// Copy this name on the side and use its reference.
- char *StrPtr = DebugInfoNames.Allocate<char>(NS.length());
- memcpy(StrPtr, NS.data(), NS.length());
- return StringRef(StrPtr, NS.length());
+ OS.flush();
+ char *StrPtr = DebugInfoNames.Allocate<char>(NS.size());
+ memcpy(StrPtr, NS.data(), NS.size());
+ return StringRef(StrPtr, NS.size());
}
StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) {
@@ -199,8 +201,12 @@ CGDebugInfo::getClassName(const RecordDecl *RD) {
}
StringRef Name = RD->getIdentifier()->getName();
PrintingPolicy Policy(CGM.getLangOpts());
- std::string TemplateArgList =
- TemplateSpecializationType::PrintTemplateArgumentList(Args, NumArgs, Policy);
+ SmallString<128> TemplateArgList;
+ {
+ llvm::raw_svector_ostream OS(TemplateArgList);
+ TemplateSpecializationType::PrintTemplateArgumentList(OS, Args, NumArgs,
+ Policy);
+ }
// Copy this name on the side and use its reference.
size_t Length = Name.size() + TemplateArgList.size();
@@ -256,9 +262,9 @@ unsigned CGDebugInfo::getLineNumber(SourceLocation Loc) {
}
/// getColumnNumber - Get column number for the location.
-unsigned CGDebugInfo::getColumnNumber(SourceLocation Loc) {
+unsigned CGDebugInfo::getColumnNumber(SourceLocation Loc, bool Force) {
// We may not want column information at all.
- if (!CGM.getCodeGenOpts().DebugColumnInfo)
+ if (!Force && !CGM.getCodeGenOpts().DebugColumnInfo)
return 0;
// If the location is invalid then use the current column.
@@ -306,6 +312,12 @@ void CGDebugInfo::CreateCompileUnit() {
char *FilenamePtr = DebugInfoNames.Allocate<char>(MainFileName.length());
memcpy(FilenamePtr, MainFileName.c_str(), MainFileName.length());
StringRef Filename(FilenamePtr, MainFileName.length());
+
+ // Save split dwarf file string.
+ std::string SplitDwarfFile = CGM.getCodeGenOpts().SplitDwarfFile;
+ char *SplitDwarfPtr = DebugInfoNames.Allocate<char>(SplitDwarfFile.length());
+ memcpy(SplitDwarfPtr, SplitDwarfFile.c_str(), SplitDwarfFile.length());
+ StringRef SplitDwarfFilename(SplitDwarfPtr, SplitDwarfFile.length());
unsigned LangTag;
const LangOptions &LO = CGM.getLangOpts();
@@ -330,10 +342,10 @@ void CGDebugInfo::CreateCompileUnit() {
RuntimeVers = LO.ObjCRuntime.isNonFragile() ? 2 : 1;
// Create new compile unit.
- DBuilder.createCompileUnit(
- LangTag, Filename, getCurrentDirname(),
- Producer,
- LO.Optimize, CGM.getCodeGenOpts().DwarfDebugFlags, RuntimeVers);
+ DBuilder.createCompileUnit(LangTag, Filename, getCurrentDirname(),
+ Producer, LO.Optimize,
+ CGM.getCodeGenOpts().DwarfDebugFlags,
+ RuntimeVers, SplitDwarfFilename);
// FIXME - Eliminate TheCU.
TheCU = llvm::DICompileUnit(DBuilder.getCU());
}
@@ -380,22 +392,12 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
llvm::DIType ISATy = DBuilder.createPointerType(ClassTy, Size);
- llvm::DIType FwdTy = DBuilder.createStructType(TheCU, "objc_object",
- getOrCreateMainFile(),
- 0, 0, 0, 0,
- llvm::DIArray());
-
- llvm::TrackingVH<llvm::MDNode> ObjNode(FwdTy);
- SmallVector<llvm::Value *, 1> EltTys;
- llvm::DIType FieldTy =
- DBuilder.createMemberType(llvm::DIDescriptor(ObjNode), "isa",
- getOrCreateMainFile(), 0, Size,
- 0, 0, 0, ISATy);
- EltTys.push_back(FieldTy);
- llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
+ ObjTy =
+ DBuilder.createStructType(TheCU, "objc_object", getOrCreateMainFile(),
+ 0, 0, 0, 0, llvm::DIType(), llvm::DIArray());
- ObjNode->replaceOperandWith(10, Elements);
- ObjTy = llvm::DIType(ObjNode);
+ ObjTy.setTypeArray(DBuilder.getOrCreateArray(&*DBuilder.createMemberType(
+ ObjTy, "isa", getOrCreateMainFile(), 0, Size, 0, 0, 0, ISATy)));
return ObjTy;
}
case BuiltinType::ObjCSel: {
@@ -407,6 +409,34 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) {
0);
return SelTy;
}
+
+ case BuiltinType::OCLImage1d:
+ return getOrCreateStructPtrType("opencl_image1d_t",
+ OCLImage1dDITy);
+ case BuiltinType::OCLImage1dArray:
+ return getOrCreateStructPtrType("opencl_image1d_array_t",
+ OCLImage1dArrayDITy);
+ case BuiltinType::OCLImage1dBuffer:
+ return getOrCreateStructPtrType("opencl_image1d_buffer_t",
+ OCLImage1dBufferDITy);
+ case BuiltinType::OCLImage2d:
+ return getOrCreateStructPtrType("opencl_image2d_t",
+ OCLImage2dDITy);
+ case BuiltinType::OCLImage2dArray:
+ return getOrCreateStructPtrType("opencl_image2d_array_t",
+ OCLImage2dArrayDITy);
+ case BuiltinType::OCLImage3d:
+ return getOrCreateStructPtrType("opencl_image3d_t",
+ OCLImage3dDITy);
+ case BuiltinType::OCLSampler:
+ return DBuilder.createBasicType("opencl_sampler_t",
+ CGM.getContext().getTypeSize(BT),
+ CGM.getContext().getTypeAlign(BT),
+ llvm::dwarf::DW_ATE_unsigned);
+ case BuiltinType::OCLEvent:
+ return getOrCreateStructPtrType("opencl_event_t",
+ OCLEventDITy);
+
case BuiltinType::UChar:
case BuiltinType::Char_U: Encoding = llvm::dwarf::DW_ATE_unsigned_char; break;
case BuiltinType::Char_S:
@@ -502,6 +532,13 @@ llvm::DIType CGDebugInfo::CreateQualifiedType(QualType Ty, llvm::DIFile Unit) {
llvm::DIType CGDebugInfo::CreateType(const ObjCObjectPointerType *Ty,
llvm::DIFile Unit) {
+
+ // The frontend treats 'id' as a typedef to an ObjCObjectType,
+ // whereas 'id<protocol>' is treated as an ObjCPointerType. For the
+ // debug info, we want to emit 'id' in both cases.
+ if (Ty->isObjCQualifiedIdType())
+ return getOrCreateType(CGM.getContext().getObjCIdType(), Unit);
+
llvm::DIType DbgTy =
CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty,
Ty->getPointeeType(), Unit);
@@ -556,7 +593,7 @@ llvm::DIDescriptor CGDebugInfo::createContextChain(const Decl *Context) {
if (const RecordDecl *RD = dyn_cast<RecordDecl>(Context)) {
if (!RD->isDependentType()) {
llvm::DIType Ty = getOrCreateLimitedType(CGM.getContext().getTypeDeclType(RD),
- getOrCreateMainFile());
+ getOrCreateMainFile());
return llvm::DIDescriptor(Ty);
}
}
@@ -590,7 +627,6 @@ llvm::DIType CGDebugInfo::CreatePointeeType(QualType PointeeTy,
return RetTy;
}
return getOrCreateType(PointeeTy, Unit);
-
}
llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag,
@@ -601,7 +637,7 @@ llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag,
Tag == llvm::dwarf::DW_TAG_rvalue_reference_type)
return DBuilder.createReferenceType(Tag,
CreatePointeeType(PointeeTy, Unit));
-
+
// Bit size, align and offset of the type.
// Size is always the size of a pointer. We can't use getTypeSize here
// because that does not return the correct value for references.
@@ -613,6 +649,18 @@ llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag,
Size, Align);
}
+llvm::DIType CGDebugInfo::getOrCreateStructPtrType(StringRef Name, llvm::DIType &Cache) {
+ if (Cache.Verify())
+ return Cache;
+ Cache =
+ DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
+ Name, TheCU, getOrCreateMainFile(),
+ 0);
+ unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
+ Cache = DBuilder.createPointerType(Cache, Size);
+ return Cache;
+}
+
llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
llvm::DIFile Unit) {
if (BlockLiteralGenericSet)
@@ -639,7 +687,7 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
EltTy = DBuilder.createStructType(Unit, "__block_descriptor",
Unit, LineNo, FieldOffset, 0,
- Flags, Elements);
+ Flags, llvm::DIType(), Elements);
// Bit size, align and offset of the type.
uint64_t Size = CGM.getContext().getTypeSize(Ty);
@@ -669,7 +717,7 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
EltTy = DBuilder.createStructType(Unit, "__block_literal_generic",
Unit, LineNo, FieldOffset, 0,
- Flags, Elements);
+ Flags, llvm::DIType(), Elements);
BlockLiteralGenericSet = true;
BlockLiteralGeneric = DBuilder.createPointerType(EltTy, Size);
@@ -715,33 +763,6 @@ llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty,
}
-void CGDebugInfo::
-CollectRecordStaticVars(const RecordDecl *RD, llvm::DIType FwdDecl) {
-
- for (RecordDecl::decl_iterator I = RD->decls_begin(), E = RD->decls_end();
- I != E; ++I)
- if (const VarDecl *V = dyn_cast<VarDecl>(*I)) {
- if (V->getInit()) {
- const APValue *Value = V->evaluateValue();
- if (Value && Value->isInt()) {
- llvm::ConstantInt *CI
- = llvm::ConstantInt::get(CGM.getLLVMContext(), Value->getInt());
-
- // Create the descriptor for static variable.
- llvm::DIFile VUnit = getOrCreateFile(V->getLocation());
- StringRef VName = V->getName();
- llvm::DIType VTy = getOrCreateType(V->getType(), VUnit);
- // Do not use DIGlobalVariable for enums.
- if (VTy.getTag() != llvm::dwarf::DW_TAG_enumeration_type) {
- DBuilder.createStaticVariable(FwdDecl, VName, VName, VUnit,
- getLineNumber(V->getLocation()),
- VTy, true, CI);
- }
- }
- }
- }
-}
-
llvm::DIType CGDebugInfo::createFieldType(StringRef name,
QualType type,
uint64_t sizeInBitsOverride,
@@ -775,94 +796,159 @@ llvm::DIType CGDebugInfo::createFieldType(StringRef name,
alignInBits, offsetInBits, flags, debugType);
}
+/// CollectRecordLambdaFields - Helper for CollectRecordFields.
+void CGDebugInfo::
+CollectRecordLambdaFields(const CXXRecordDecl *CXXDecl,
+ SmallVectorImpl<llvm::Value *> &elements,
+ llvm::DIType RecordTy) {
+ // For C++11 Lambdas a Field will be the same as a Capture, but the Capture
+ // has the name and the location of the variable so we should iterate over
+ // both concurrently.
+ const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(CXXDecl);
+ RecordDecl::field_iterator Field = CXXDecl->field_begin();
+ unsigned fieldno = 0;
+ for (CXXRecordDecl::capture_const_iterator I = CXXDecl->captures_begin(),
+ E = CXXDecl->captures_end(); I != E; ++I, ++Field, ++fieldno) {
+ const LambdaExpr::Capture C = *I;
+ if (C.capturesVariable()) {
+ VarDecl *V = C.getCapturedVar();
+ llvm::DIFile VUnit = getOrCreateFile(C.getLocation());
+ StringRef VName = V->getName();
+ uint64_t SizeInBitsOverride = 0;
+ if (Field->isBitField()) {
+ SizeInBitsOverride = Field->getBitWidthValue(CGM.getContext());
+ assert(SizeInBitsOverride && "found named 0-width bitfield");
+ }
+ llvm::DIType fieldType
+ = createFieldType(VName, Field->getType(), SizeInBitsOverride,
+ C.getLocation(), Field->getAccess(),
+ layout.getFieldOffset(fieldno), VUnit, RecordTy);
+ elements.push_back(fieldType);
+ } else {
+ // TODO: Need to handle 'this' in some way by probably renaming the
+ // this of the lambda class and having a field member of 'this' or
+ // by using AT_object_pointer for the function and having that be
+ // used as 'this' for semantic references.
+ assert(C.capturesThis() && "Field that isn't captured and isn't this?");
+ FieldDecl *f = *Field;
+ llvm::DIFile VUnit = getOrCreateFile(f->getLocation());
+ QualType type = f->getType();
+ llvm::DIType fieldType
+ = createFieldType("this", type, 0, f->getLocation(), f->getAccess(),
+ layout.getFieldOffset(fieldno), VUnit, RecordTy);
+
+ elements.push_back(fieldType);
+ }
+ }
+}
+
+/// CollectRecordStaticField - Helper for CollectRecordFields.
+void CGDebugInfo::
+CollectRecordStaticField(const VarDecl *Var,
+ SmallVectorImpl<llvm::Value *> &elements,
+ llvm::DIType RecordTy) {
+ // Create the descriptor for the static variable, with or without
+ // constant initializers.
+ llvm::DIFile VUnit = getOrCreateFile(Var->getLocation());
+ llvm::DIType VTy = getOrCreateType(Var->getType(), VUnit);
+
+ // Do not describe enums as static members.
+ if (VTy.getTag() == llvm::dwarf::DW_TAG_enumeration_type)
+ return;
+
+ unsigned LineNumber = getLineNumber(Var->getLocation());
+ StringRef VName = Var->getName();
+ llvm::Constant *C = NULL;
+ if (Var->getInit()) {
+ const APValue *Value = Var->evaluateValue();
+ if (Value) {
+ if (Value->isInt())
+ C = llvm::ConstantInt::get(CGM.getLLVMContext(), Value->getInt());
+ if (Value->isFloat())
+ C = llvm::ConstantFP::get(CGM.getLLVMContext(), Value->getFloat());
+ }
+ }
+
+ unsigned Flags = 0;
+ AccessSpecifier Access = Var->getAccess();
+ if (Access == clang::AS_private)
+ Flags |= llvm::DIDescriptor::FlagPrivate;
+ else if (Access == clang::AS_protected)
+ Flags |= llvm::DIDescriptor::FlagProtected;
+
+ llvm::DIType GV = DBuilder.createStaticMemberType(RecordTy, VName, VUnit,
+ LineNumber, VTy, Flags, C);
+ elements.push_back(GV);
+ StaticDataMemberCache[Var->getCanonicalDecl()] = llvm::WeakVH(GV);
+}
+
+/// CollectRecordNormalField - Helper for CollectRecordFields.
+void CGDebugInfo::
+CollectRecordNormalField(const FieldDecl *field, uint64_t OffsetInBits,
+ llvm::DIFile tunit,
+ SmallVectorImpl<llvm::Value *> &elements,
+ llvm::DIType RecordTy) {
+ StringRef name = field->getName();
+ QualType type = field->getType();
+
+ // Ignore unnamed fields unless they're anonymous structs/unions.
+ if (name.empty() && !type->isRecordType())
+ return;
+
+ uint64_t SizeInBitsOverride = 0;
+ if (field->isBitField()) {
+ SizeInBitsOverride = field->getBitWidthValue(CGM.getContext());
+ assert(SizeInBitsOverride && "found named 0-width bitfield");
+ }
+
+ llvm::DIType fieldType
+ = createFieldType(name, type, SizeInBitsOverride,
+ field->getLocation(), field->getAccess(),
+ OffsetInBits, tunit, RecordTy);
+
+ elements.push_back(fieldType);
+}
+
/// CollectRecordFields - A helper function to collect debug info for
/// record fields. This is used while creating debug info entry for a Record.
void CGDebugInfo::
CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit,
SmallVectorImpl<llvm::Value *> &elements,
llvm::DIType RecordTy) {
- unsigned fieldNo = 0;
- const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(record);
const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(record);
- // For C++11 Lambdas a Field will be the same as a Capture, but the Capture
- // has the name and the location of the variable so we should iterate over
- // both concurrently.
- if (CXXDecl && CXXDecl->isLambda()) {
- RecordDecl::field_iterator Field = CXXDecl->field_begin();
- unsigned fieldno = 0;
- for (CXXRecordDecl::capture_const_iterator I = CXXDecl->captures_begin(),
- E = CXXDecl->captures_end(); I != E; ++I, ++Field, ++fieldno) {
- const LambdaExpr::Capture C = *I;
- if (C.capturesVariable()) {
- VarDecl *V = C.getCapturedVar();
- llvm::DIFile VUnit = getOrCreateFile(C.getLocation());
- StringRef VName = V->getName();
- uint64_t SizeInBitsOverride = 0;
- if (Field->isBitField()) {
- SizeInBitsOverride = Field->getBitWidthValue(CGM.getContext());
- assert(SizeInBitsOverride && "found named 0-width bitfield");
- }
- llvm::DIType fieldType
- = createFieldType(VName, Field->getType(), SizeInBitsOverride, C.getLocation(),
- Field->getAccess(), layout.getFieldOffset(fieldno),
- VUnit, RecordTy);
- elements.push_back(fieldType);
- } else {
- // TODO: Need to handle 'this' in some way by probably renaming the
- // this of the lambda class and having a field member of 'this' or
- // by using AT_object_pointer for the function and having that be
- // used as 'this' for semantic references.
- assert(C.capturesThis() && "Field that isn't captured and isn't this?");
- FieldDecl *f = *Field;
- llvm::DIFile VUnit = getOrCreateFile(f->getLocation());
- QualType type = f->getType();
- llvm::DIType fieldType
- = createFieldType("this", type, 0, f->getLocation(), f->getAccess(),
- layout.getFieldOffset(fieldNo), VUnit, RecordTy);
-
- elements.push_back(fieldType);
- }
- }
- } else {
+ if (CXXDecl && CXXDecl->isLambda())
+ CollectRecordLambdaFields(CXXDecl, elements, RecordTy);
+ else {
+ const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(record);
+
+ // Field number for non-static fields.
+ unsigned fieldNo = 0;
+
+ // Bookkeeping for an ms struct, which ignores certain fields.
bool IsMsStruct = record->isMsStruct(CGM.getContext());
const FieldDecl *LastFD = 0;
- for (RecordDecl::field_iterator I = record->field_begin(),
- E = record->field_end();
- I != E; ++I, ++fieldNo) {
- FieldDecl *field = *I;
-
- if (IsMsStruct) {
- // Zero-length bitfields following non-bitfield members are ignored
- if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((field), LastFD)) {
- --fieldNo;
- continue;
- }
- LastFD = field;
- }
-
- StringRef name = field->getName();
- QualType type = field->getType();
- // Ignore unnamed fields unless they're anonymous structs/unions.
- if (name.empty() && !type->isRecordType()) {
- LastFD = field;
- continue;
- }
+ // Static and non-static members should appear in the same order as
+ // the corresponding declarations in the source program.
+ for (RecordDecl::decl_iterator I = record->decls_begin(),
+ E = record->decls_end(); I != E; ++I)
+ if (const VarDecl *V = dyn_cast<VarDecl>(*I))
+ CollectRecordStaticField(V, elements, RecordTy);
+ else if (FieldDecl *field = dyn_cast<FieldDecl>(*I)) {
+ if (IsMsStruct) {
+ // Zero-length bitfields following non-bitfield members are
+ // completely ignored; we don't even count them.
+ if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((field), LastFD))
+ continue;
+ LastFD = field;
+ }
+ CollectRecordNormalField(field, layout.getFieldOffset(fieldNo),
+ tunit, elements, RecordTy);
- uint64_t SizeInBitsOverride = 0;
- if (field->isBitField()) {
- SizeInBitsOverride = field->getBitWidthValue(CGM.getContext());
- assert(SizeInBitsOverride && "found named 0-width bitfield");
+ // Bump field number for next field.
+ ++fieldNo;
}
-
- llvm::DIType fieldType
- = createFieldType(name, type, SizeInBitsOverride,
- field->getLocation(), field->getAccess(),
- layout.getFieldOffset(fieldNo), tunit, RecordTy);
-
- elements.push_back(fieldType);
- }
}
}
@@ -872,13 +958,18 @@ CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit,
llvm::DIType
CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
llvm::DIFile Unit) {
- llvm::DIType FnTy
- = getOrCreateType(QualType(Method->getType()->getAs<FunctionProtoType>(),
- 0),
- Unit);
+ const FunctionProtoType *Func = Method->getType()->getAs<FunctionProtoType>();
+ if (Method->isStatic())
+ return getOrCreateType(QualType(Func, 0), Unit);
+ return getOrCreateInstanceMethodType(Method->getThisType(CGM.getContext()),
+ Func, Unit);
+}
+llvm::DIType CGDebugInfo::getOrCreateInstanceMethodType(
+ QualType ThisPtr, const FunctionProtoType *Func, llvm::DIFile Unit) {
// Add "this" pointer.
- llvm::DIArray Args = llvm::DICompositeType(FnTy).getTypeArray();
+ llvm::DIArray Args = llvm::DICompositeType(
+ getOrCreateType(QualType(Func, 0), Unit)).getTypeArray();
assert (Args.getNumElements() && "Invalid number of arguments!");
SmallVector<llvm::Value *, 16> Elts;
@@ -886,32 +977,28 @@ CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
// First element is always return type. For 'void' functions it is NULL.
Elts.push_back(Args.getElement(0));
- if (!Method->isStatic()) {
- // "this" pointer is always first argument.
- QualType ThisPtr = Method->getThisType(CGM.getContext());
-
- const CXXRecordDecl *RD = Method->getParent();
- if (isa<ClassTemplateSpecializationDecl>(RD)) {
- // Create pointer type directly in this case.
- const PointerType *ThisPtrTy = cast<PointerType>(ThisPtr);
- QualType PointeeTy = ThisPtrTy->getPointeeType();
- unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy);
- uint64_t Size = CGM.getContext().getTargetInfo().getPointerWidth(AS);
- uint64_t Align = CGM.getContext().getTypeAlign(ThisPtrTy);
- llvm::DIType PointeeType = getOrCreateType(PointeeTy, Unit);
- llvm::DIType ThisPtrType = DBuilder.createPointerType(PointeeType, Size, Align);
- TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType;
- // TODO: This and the artificial type below are misleading, the
- // types aren't artificial the argument is, but the current
- // metadata doesn't represent that.
- ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType);
- Elts.push_back(ThisPtrType);
- } else {
- llvm::DIType ThisPtrType = getOrCreateType(ThisPtr, Unit);
- TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType;
- ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType);
- Elts.push_back(ThisPtrType);
- }
+ // "this" pointer is always first argument.
+ const CXXRecordDecl *RD = ThisPtr->getPointeeCXXRecordDecl();
+ if (isa<ClassTemplateSpecializationDecl>(RD)) {
+ // Create pointer type directly in this case.
+ const PointerType *ThisPtrTy = cast<PointerType>(ThisPtr);
+ QualType PointeeTy = ThisPtrTy->getPointeeType();
+ unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy);
+ uint64_t Size = CGM.getContext().getTargetInfo().getPointerWidth(AS);
+ uint64_t Align = CGM.getContext().getTypeAlign(ThisPtrTy);
+ llvm::DIType PointeeType = getOrCreateType(PointeeTy, Unit);
+ llvm::DIType ThisPtrType = DBuilder.createPointerType(PointeeType, Size, Align);
+ TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType;
+ // TODO: This and the artificial type below are misleading, the
+ // types aren't artificial the argument is, but the current
+ // metadata doesn't represent that.
+ ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType);
+ Elts.push_back(ThisPtrType);
+ } else {
+ llvm::DIType ThisPtrType = getOrCreateType(ThisPtr, Unit);
+ TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType;
+ ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType);
+ Elts.push_back(ThisPtrType);
}
// Copy rest of the arguments.
@@ -1199,7 +1286,7 @@ CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit,
unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy);
llvm::DIType VPTR
= DBuilder.createMemberType(Unit, getVTableName(RD), Unit,
- 0, Size, 0, 0, 0,
+ 0, Size, 0, 0, llvm::DIDescriptor::FlagArtificial,
getOrCreateVTablePtrType(Unit));
EltTys.push_back(VPTR);
}
@@ -1215,10 +1302,10 @@ llvm::DIType CGDebugInfo::getOrCreateRecordType(QualType RTy,
/// getOrCreateInterfaceType - Emit an objective c interface type standalone
/// debug info.
llvm::DIType CGDebugInfo::getOrCreateInterfaceType(QualType D,
- SourceLocation Loc) {
+ SourceLocation Loc) {
assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
llvm::DIType T = getOrCreateType(D, getOrCreateFile(Loc));
- DBuilder.retainType(T);
+ RetainedTypes.push_back(D.getAsOpaquePtr());
return T;
}
@@ -1236,18 +1323,19 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
// may refer to the forward decl if the struct is recursive) and replace all
// uses of the forward declaration with the final definition.
- llvm::DIType FwdDecl = getOrCreateLimitedType(QualType(Ty, 0), DefUnit);
+ llvm::DICompositeType FwdDecl(
+ getOrCreateLimitedType(QualType(Ty, 0), DefUnit));
+ assert(FwdDecl.Verify() &&
+ "The debug type of a RecordType should be a DICompositeType");
if (FwdDecl.isForwardDecl())
return FwdDecl;
- llvm::TrackingVH<llvm::MDNode> FwdDeclNode(FwdDecl);
-
// Push the struct on region stack.
- LexicalBlockStack.push_back(FwdDeclNode);
+ LexicalBlockStack.push_back(&*FwdDecl);
RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl);
- // Add this to the completed types cache since we're completing it.
+ // Add this to the completed-type cache while we're completing it recursively.
CompletedTypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl;
// Convert all the elements.
@@ -1263,8 +1351,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
CollectVTableInfo(CXXDecl, DefUnit, EltTys);
}
- // Collect static variables with initializers and other fields.
- CollectRecordStaticVars(RD, FwdDecl);
+ // Collect data fields (including static variables and any initializers).
CollectRecordFields(RD, DefUnit, EltTys, FwdDecl);
llvm::DIArray TParamsArray;
if (CXXDecl) {
@@ -1279,19 +1366,10 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) {
RegionMap.erase(Ty->getDecl());
llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
- // FIXME: Magic numbers ahoy! These should be changed when we
- // get some enums in llvm/Analysis/DebugInfo.h to refer to
- // them.
- if (RD->isUnion())
- FwdDeclNode->replaceOperandWith(10, Elements);
- else if (CXXDecl) {
- FwdDeclNode->replaceOperandWith(10, Elements);
- FwdDeclNode->replaceOperandWith(13, TParamsArray);
- } else
- FwdDeclNode->replaceOperandWith(10, Elements);
+ FwdDecl.setTypeArray(Elements, TParamsArray);
- RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDeclNode);
- return llvm::DIType(FwdDeclNode);
+ RegionMap[Ty->getDecl()] = llvm::WeakVH(FwdDecl);
+ return FwdDecl;
}
/// CreateType - get objective-c object type.
@@ -1319,8 +1397,8 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
if (!Def) {
llvm::DIType FwdDecl =
DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
- ID->getName(), TheCU, DefUnit, Line,
- RuntimeLang);
+ ID->getName(), TheCU, DefUnit, Line,
+ RuntimeLang);
return FwdDecl;
}
@@ -1334,18 +1412,18 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
if (ID->getImplementation())
Flags |= llvm::DIDescriptor::FlagObjcClassComplete;
- llvm::DIType RealDecl =
+ llvm::DICompositeType RealDecl =
DBuilder.createStructType(Unit, ID->getName(), DefUnit,
Line, Size, Align, Flags,
- llvm::DIArray(), RuntimeLang);
+ llvm::DIType(), llvm::DIArray(), RuntimeLang);
// Otherwise, insert it into the CompletedTypeCache so that recursive uses
// will find it and we're emitting the complete type.
- CompletedTypeCache[QualType(Ty, 0).getAsOpaquePtr()] = RealDecl;
+ QualType QualTy = QualType(Ty, 0);
+ CompletedTypeCache[QualTy.getAsOpaquePtr()] = RealDecl;
// Push the struct on region stack.
- llvm::TrackingVH<llvm::MDNode> FwdDeclNode(RealDecl);
- LexicalBlockStack.push_back(FwdDeclNode);
+ LexicalBlockStack.push_back(static_cast<llvm::MDNode*>(RealDecl));
RegionMap[Ty->getDecl()] = llvm::WeakVH(RealDecl);
// Convert all the elements.
@@ -1373,13 +1451,13 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
ObjCMethodDecl *Setter = PD->getSetterMethodDecl();
llvm::MDNode *PropertyNode =
DBuilder.createObjCProperty(PD->getName(),
- PUnit, PLine,
+ PUnit, PLine,
(Getter && Getter->isImplicit()) ? "" :
getSelectorName(PD->getGetterName()),
(Setter && Setter->isImplicit()) ? "" :
getSelectorName(PD->getSetterName()),
PD->getPropertyAttributes(),
- getOrCreateType(PD->getType(), PUnit));
+ getOrCreateType(PD->getType(), PUnit));
EltTys.push_back(PropertyNode);
}
@@ -1440,9 +1518,9 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
if (ObjCPropertyImplDecl *PImpD =
ImpD->FindPropertyImplIvarDecl(Field->getIdentifier())) {
if (ObjCPropertyDecl *PD = PImpD->getPropertyDecl()) {
- SourceLocation Loc = PD->getLocation();
- llvm::DIFile PUnit = getOrCreateFile(Loc);
- unsigned PLine = getLineNumber(Loc);
+ SourceLocation Loc = PD->getLocation();
+ llvm::DIFile PUnit = getOrCreateFile(Loc);
+ unsigned PLine = getLineNumber(Loc);
ObjCMethodDecl *Getter = PD->getGetterMethodDecl();
ObjCMethodDecl *Setter = PD->getSetterMethodDecl();
PropertyNode =
@@ -1465,31 +1543,33 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
}
llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);
- FwdDeclNode->replaceOperandWith(10, Elements);
+ RealDecl.setTypeArray(Elements);
+
+ // If the implementation is not yet set, we do not want to mark it
+ // as complete. An implementation may declare additional
+ // private ivars that we would miss otherwise.
+ if (ID->getImplementation() == 0)
+ CompletedTypeCache.erase(QualTy.getAsOpaquePtr());
LexicalBlockStack.pop_back();
- return llvm::DIType(FwdDeclNode);
+ return RealDecl;
}
llvm::DIType CGDebugInfo::CreateType(const VectorType *Ty, llvm::DIFile Unit) {
llvm::DIType ElementTy = getOrCreateType(Ty->getElementType(), Unit);
- int64_t NumElems = Ty->getNumElements();
- int64_t LowerBound = 0;
- if (NumElems == 0)
+ int64_t Count = Ty->getNumElements();
+ if (Count == 0)
// If number of elements are not known then this is an unbounded array.
- // Use Low = 1, Hi = 0 to express such arrays.
- LowerBound = 1;
- else
- --NumElems;
+ // Use Count == -1 to express such arrays.
+ Count = -1;
- llvm::Value *Subscript = DBuilder.getOrCreateSubrange(LowerBound, NumElems);
+ llvm::Value *Subscript = DBuilder.getOrCreateSubrange(0, Count);
llvm::DIArray SubscriptArray = DBuilder.getOrCreateArray(Subscript);
uint64_t Size = CGM.getContext().getTypeSize(Ty);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
- return
- DBuilder.createVectorType(Size, Align, ElementTy, SubscriptArray);
+ return DBuilder.createVectorType(Size, Align, ElementTy, SubscriptArray);
}
llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty,
@@ -1523,19 +1603,19 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty,
SmallVector<llvm::Value *, 8> Subscripts;
QualType EltTy(Ty, 0);
while ((Ty = dyn_cast<ArrayType>(EltTy))) {
- int64_t UpperBound = 0;
- int64_t LowerBound = 0;
- if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty)) {
- if (CAT->getSize().getZExtValue())
- UpperBound = CAT->getSize().getZExtValue() - 1;
- } else
- // This is an unbounded array. Use Low = 1, Hi = 0 to express such
- // arrays.
- LowerBound = 1;
+ // If the number of elements is known, then count is that number. Otherwise,
+ // it's -1. This allows us to represent a subrange with an array of 0
+ // elements, like this:
+ //
+ // struct foo {
+ // int x[0];
+ // };
+ int64_t Count = -1; // Count == -1 is an unbounded array.
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty))
+ Count = CAT->getSize().getZExtValue();
// FIXME: Verify this is right for VLAs.
- Subscripts.push_back(DBuilder.getOrCreateSubrange(LowerBound,
- UpperBound));
+ Subscripts.push_back(DBuilder.getOrCreateSubrange(0, Count));
EltTy = Ty->getElementType();
}
@@ -1561,38 +1641,15 @@ llvm::DIType CGDebugInfo::CreateType(const RValueReferenceType *Ty,
llvm::DIType CGDebugInfo::CreateType(const MemberPointerType *Ty,
llvm::DIFile U) {
- QualType PointerDiffTy = CGM.getContext().getPointerDiffType();
- llvm::DIType PointerDiffDITy = getOrCreateType(PointerDiffTy, U);
-
- if (!Ty->getPointeeType()->isFunctionType()) {
- // We have a data member pointer type.
- return PointerDiffDITy;
- }
-
- // We have a member function pointer type. Treat it as a struct with two
- // ptrdiff_t members.
- std::pair<uint64_t, unsigned> Info = CGM.getContext().getTypeInfo(Ty);
-
- uint64_t FieldOffset = 0;
- llvm::Value *ElementTypes[2];
-
- // FIXME: This should be a DW_TAG_pointer_to_member type.
- ElementTypes[0] =
- DBuilder.createMemberType(U, "ptr", U, 0,
- Info.first, Info.second, FieldOffset, 0,
- PointerDiffDITy);
- FieldOffset += Info.first;
-
- ElementTypes[1] =
- DBuilder.createMemberType(U, "ptr", U, 0,
- Info.first, Info.second, FieldOffset, 0,
- PointerDiffDITy);
-
- llvm::DIArray Elements = DBuilder.getOrCreateArray(ElementTypes);
-
- return DBuilder.createStructType(U, StringRef("test"),
- U, 0, FieldOffset,
- 0, 0, Elements);
+ llvm::DIType ClassType = getOrCreateType(QualType(Ty->getClass(), 0), U);
+ if (!Ty->getPointeeType()->isFunctionType())
+ return DBuilder.createMemberPointerType(
+ CreatePointeeType(Ty->getPointeeType(), U), ClassType);
+ return DBuilder.createMemberPointerType(getOrCreateInstanceMethodType(
+ CGM.getContext().getPointerType(
+ QualType(Ty->getClass(), Ty->getPointeeType().getCVRQualifiers())),
+ Ty->getPointeeType()->getAs<FunctionProtoType>(), U),
+ ClassType);
}
llvm::DIType CGDebugInfo::CreateType(const AtomicType *Ty,
@@ -1651,12 +1708,14 @@ llvm::DIType CGDebugInfo::CreateEnumType(const EnumDecl *ED) {
return DbgTy;
}
-static QualType UnwrapTypeForDebugInfo(QualType T) {
+static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) {
+ Qualifiers Quals;
do {
+ Quals += T.getLocalQualifiers();
QualType LastT = T;
switch (T->getTypeClass()) {
default:
- return T;
+ return C.getQualifiedType(T.getTypePtr(), Quals);
case Type::TemplateSpecialization:
T = cast<TemplateSpecializationType>(T)->desugar();
break;
@@ -1681,13 +1740,8 @@ static QualType UnwrapTypeForDebugInfo(QualType T) {
case Type::Paren:
T = cast<ParenType>(T)->getInnerType();
break;
- case Type::SubstTemplateTypeParm: {
- // We need to keep the qualifiers handy since getReplacementType()
- // will strip them away.
- unsigned Quals = T.getLocalFastQualifiers();
+ case Type::SubstTemplateTypeParm:
T = cast<SubstTemplateTypeParmType>(T)->getReplacementType();
- T.addFastQualifiers(Quals);
- }
break;
case Type::Auto:
T = cast<AutoType>(T)->getDeducedType();
@@ -1695,8 +1749,7 @@ static QualType UnwrapTypeForDebugInfo(QualType T) {
}
assert(T != LastT && "Type unwrapping failed to unwrap!");
- if (T == LastT)
- return T;
+ (void)LastT;
} while (true);
}
@@ -1704,9 +1757,16 @@ static QualType UnwrapTypeForDebugInfo(QualType T) {
llvm::DIType CGDebugInfo::getTypeOrNull(QualType Ty) {
// Unwrap the type as needed for debug information.
- Ty = UnwrapTypeForDebugInfo(Ty);
+ Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext());
// Check for existing entry.
+ if (Ty->getTypeClass() == Type::ObjCInterface) {
+ llvm::Value *V = getCachedInterfaceTypeOrNull(Ty);
+ if (V)
+ return llvm::DIType(cast<llvm::MDNode>(V));
+ else return llvm::DIType();
+ }
+
llvm::DenseMap<void *, llvm::WeakVH>::iterator it =
TypeCache.find(Ty.getAsOpaquePtr());
if (it != TypeCache.end()) {
@@ -1723,20 +1783,40 @@ llvm::DIType CGDebugInfo::getTypeOrNull(QualType Ty) {
llvm::DIType CGDebugInfo::getCompletedTypeOrNull(QualType Ty) {
// Unwrap the type as needed for debug information.
- Ty = UnwrapTypeForDebugInfo(Ty);
+ Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext());
// Check for existing entry.
+ llvm::Value *V = 0;
llvm::DenseMap<void *, llvm::WeakVH>::iterator it =
CompletedTypeCache.find(Ty.getAsOpaquePtr());
- if (it != CompletedTypeCache.end()) {
- // Verify that the debug info still exists.
- if (llvm::Value *V = it->second)
- return llvm::DIType(cast<llvm::MDNode>(V));
+ if (it != CompletedTypeCache.end())
+ V = it->second;
+ else {
+ V = getCachedInterfaceTypeOrNull(Ty);
}
+ // Verify that any cached debug info still exists.
+ if (V != 0)
+ return llvm::DIType(cast<llvm::MDNode>(V));
+
return llvm::DIType();
}
+/// getCachedInterfaceTypeOrNull - Get the type from the interface
+/// cache, unless it needs to regenerated. Otherwise return null.
+llvm::Value *CGDebugInfo::getCachedInterfaceTypeOrNull(QualType Ty) {
+ // Is there a cached interface that hasn't changed?
+ llvm::DenseMap<void *, std::pair<llvm::WeakVH, unsigned > >
+ ::iterator it1 = ObjCInterfaceCache.find(Ty.getAsOpaquePtr());
+
+ if (it1 != ObjCInterfaceCache.end())
+ if (ObjCInterfaceDecl* Decl = getObjCInterfaceDecl(Ty))
+ if (Checksum(Decl) == it1->second.second)
+ // Return cached forward declaration.
+ return it1->second.first;
+
+ return 0;
+}
/// getOrCreateType - Get the type from the cache or create a new
/// one if necessary.
@@ -1745,7 +1825,7 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile Unit) {
return llvm::DIType();
// Unwrap the type as needed for debug information.
- Ty = UnwrapTypeForDebugInfo(Ty);
+ Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext());
llvm::DIType T = getCompletedTypeOrNull(Ty);
@@ -1754,21 +1834,63 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile Unit) {
// Otherwise create the type.
llvm::DIType Res = CreateTypeNode(Ty, Unit);
+ void* TyPtr = Ty.getAsOpaquePtr();
+
+ // And update the type cache.
+ TypeCache[TyPtr] = Res;
llvm::DIType TC = getTypeOrNull(Ty);
if (TC.Verify() && TC.isForwardDecl())
- ReplaceMap.push_back(std::make_pair(Ty.getAsOpaquePtr(),
- static_cast<llvm::Value*>(TC)));
-
- // And update the type cache.
- TypeCache[Ty.getAsOpaquePtr()] = Res;
+ ReplaceMap.push_back(std::make_pair(TyPtr, static_cast<llvm::Value*>(TC)));
+ else if (ObjCInterfaceDecl* Decl = getObjCInterfaceDecl(Ty)) {
+ // Interface types may have elements added to them by a
+ // subsequent implementation or extension, so we keep them in
+ // the ObjCInterfaceCache together with a checksum. Instead of
+ // the (possibly) incomplete interace type, we return a forward
+ // declaration that gets RAUW'd in CGDebugInfo::finalize().
+ llvm::DenseMap<void *, std::pair<llvm::WeakVH, unsigned > >
+ ::iterator it = ObjCInterfaceCache.find(TyPtr);
+ if (it != ObjCInterfaceCache.end())
+ TC = llvm::DIType(cast<llvm::MDNode>(it->second.first));
+ else
+ TC = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
+ Decl->getName(), TheCU, Unit,
+ getLineNumber(Decl->getLocation()),
+ TheCU.getLanguage());
+ // Store the forward declaration in the cache.
+ ObjCInterfaceCache[TyPtr] = std::make_pair(TC, Checksum(Decl));
+
+ // Register the type for replacement in finalize().
+ ReplaceMap.push_back(std::make_pair(TyPtr, static_cast<llvm::Value*>(TC)));
+ return TC;
+ }
if (!Res.isForwardDecl())
- CompletedTypeCache[Ty.getAsOpaquePtr()] = Res;
+ CompletedTypeCache[TyPtr] = Res;
return Res;
}
+/// Currently the checksum merely consists of the number of ivars.
+unsigned CGDebugInfo::Checksum(const ObjCInterfaceDecl
+ *InterfaceDecl) {
+ unsigned IvarNo = 0;
+ for (const ObjCIvarDecl *Ivar = InterfaceDecl->all_declared_ivar_begin();
+ Ivar != 0; Ivar = Ivar->getNextIvar()) ++IvarNo;
+ return IvarNo;
+}
+
+ObjCInterfaceDecl *CGDebugInfo::getObjCInterfaceDecl(QualType Ty) {
+ switch (Ty->getTypeClass()) {
+ case Type::ObjCObjectPointer:
+ return getObjCInterfaceDecl(cast<ObjCObjectPointerType>(Ty)->getPointeeType());
+ case Type::ObjCInterface:
+ return cast<ObjCInterfaceType>(Ty)->getDecl();
+ default:
+ return 0;
+ }
+}
+
/// CreateTypeNode - Create a new debug type node.
llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile Unit) {
// Handle qualifiers, which recursively handles what they refer to.
@@ -1852,12 +1974,12 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile Unit) {
/// getOrCreateLimitedType - Get the type from the cache or create a new
/// limited type if necessary.
llvm::DIType CGDebugInfo::getOrCreateLimitedType(QualType Ty,
- llvm::DIFile Unit) {
+ llvm::DIFile Unit) {
if (Ty.isNull())
return llvm::DIType();
// Unwrap the type as needed for debug information.
- Ty = UnwrapTypeForDebugInfo(Ty);
+ Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext());
llvm::DIType T = getTypeOrNull(Ty);
@@ -1901,46 +2023,45 @@ llvm::DIType CGDebugInfo::CreateLimitedType(const RecordType *Ty) {
uint64_t Size = CGM.getContext().getTypeSize(Ty);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD);
- llvm::TrackingVH<llvm::MDNode> RealDecl;
+ llvm::DICompositeType RealDecl;
if (RD->isUnion())
RealDecl = DBuilder.createUnionType(RDContext, RDName, DefUnit, Line,
- Size, Align, 0, llvm::DIArray());
+ Size, Align, 0, llvm::DIArray());
else if (RD->isClass()) {
// FIXME: This could be a struct type giving a default visibility different
// than C++ class type, but needs llvm metadata changes first.
RealDecl = DBuilder.createClassType(RDContext, RDName, DefUnit, Line,
- Size, Align, 0, 0, llvm::DIType(),
- llvm::DIArray(), llvm::DIType(),
- llvm::DIArray());
+ Size, Align, 0, 0, llvm::DIType(),
+ llvm::DIArray(), llvm::DIType(),
+ llvm::DIArray());
} else
RealDecl = DBuilder.createStructType(RDContext, RDName, DefUnit, Line,
- Size, Align, 0, llvm::DIArray());
+ Size, Align, 0, llvm::DIType(), llvm::DIArray());
RegionMap[Ty->getDecl()] = llvm::WeakVH(RealDecl);
- TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = llvm::DIType(RealDecl);
+ TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = RealDecl;
if (CXXDecl) {
// A class's primary base or the class itself contains the vtable.
- llvm::MDNode *ContainingType = NULL;
+ llvm::DICompositeType ContainingType;
const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
if (const CXXRecordDecl *PBase = RL.getPrimaryBase()) {
// Seek non virtual primary base root.
while (1) {
- const ASTRecordLayout &BRL = CGM.getContext().getASTRecordLayout(PBase);
- const CXXRecordDecl *PBT = BRL.getPrimaryBase();
- if (PBT && !BRL.isPrimaryBaseVirtual())
- PBase = PBT;
- else
- break;
+ const ASTRecordLayout &BRL = CGM.getContext().getASTRecordLayout(PBase);
+ const CXXRecordDecl *PBT = BRL.getPrimaryBase();
+ if (PBT && !BRL.isPrimaryBaseVirtual())
+ PBase = PBT;
+ else
+ break;
}
- ContainingType =
- getOrCreateType(QualType(PBase->getTypeForDecl(), 0), DefUnit);
- }
- else if (CXXDecl->isDynamicClass())
+ ContainingType = llvm::DICompositeType(
+ getOrCreateType(QualType(PBase->getTypeForDecl(), 0), DefUnit));
+ } else if (CXXDecl->isDynamicClass())
ContainingType = RealDecl;
- RealDecl->replaceOperandWith(12, ContainingType);
+ RealDecl.setContainingType(ContainingType);
}
return llvm::DIType(RealDecl);
}
@@ -2027,8 +2148,9 @@ llvm::DIType CGDebugInfo::getOrCreateFunctionType(const Decl *D,
// First element is always return type. For 'void' functions it is NULL.
Elts.push_back(getOrCreateType(OMethod->getResultType(), F));
// "self" pointer is always first argument.
- llvm::DIType SelfTy = getOrCreateType(OMethod->getSelfDecl()->getType(), F);
- Elts.push_back(DBuilder.createObjectPointerType(SelfTy));
+ QualType SelfDeclTy = OMethod->getSelfDecl()->getType();
+ llvm::DIType SelfTy = getOrCreateType(SelfDeclTy, F);
+ Elts.push_back(CreateSelfType(SelfDeclTy, SelfTy));
// "_cmd" pointer is always second argument.
llvm::DIType CmdTy = getOrCreateType(OMethod->getCmdDecl()->getType(), F);
Elts.push_back(DBuilder.createArtificialType(CmdTy));
@@ -2084,13 +2206,18 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
}
}
Name = getFunctionName(FD);
- // Use mangled name as linkage name for c/c++ functions.
+ // Use mangled name as linkage name for C/C++ functions.
if (FD->hasPrototype()) {
LinkageName = CGM.getMangledName(GD);
Flags |= llvm::DIDescriptor::FlagPrototyped;
}
+ // No need to replicate the linkage name if it isn't different from the
+ // subprogram name, no need to have it at all unless coverage is enabled or
+ // debug is set to more than just line tables.
if (LinkageName == Name ||
- CGM.getCodeGenOpts().getDebugInfo() <= CodeGenOptions::DebugLineTablesOnly)
+ (!CGM.getCodeGenOpts().EmitGcovArcs &&
+ !CGM.getCodeGenOpts().EmitGcovNotes &&
+ CGM.getCodeGenOpts().getDebugInfo() <= CodeGenOptions::DebugLineTablesOnly))
LinkageName = StringRef();
if (CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) {
@@ -2151,7 +2278,8 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
/// EmitLocation - Emit metadata to indicate a change in line/column
/// information in the source file.
-void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) {
+void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc,
+ bool ForceColumnInfo) {
// Update our current location
setLocation(Loc);
@@ -2163,16 +2291,19 @@ void CGDebugInfo::EmitLocation(CGBuilderTy &Builder, SourceLocation Loc) {
if (CurLoc == PrevLoc ||
SM.getExpansionLoc(CurLoc) == SM.getExpansionLoc(PrevLoc))
// New Builder may not be in sync with CGDebugInfo.
- if (!Builder.getCurrentDebugLocation().isUnknown())
+ if (!Builder.getCurrentDebugLocation().isUnknown() &&
+ Builder.getCurrentDebugLocation().getScope(CGM.getLLVMContext()) ==
+ LexicalBlockStack.back())
return;
// Update last state.
PrevLoc = CurLoc;
llvm::MDNode *Scope = LexicalBlockStack.back();
- Builder.SetCurrentDebugLocation(llvm::DebugLoc::get(getLineNumber(CurLoc),
- getColumnNumber(CurLoc),
- Scope));
+ Builder.SetCurrentDebugLocation(llvm::DebugLoc::get
+ (getLineNumber(CurLoc),
+ getColumnNumber(CurLoc, ForceColumnInfo),
+ Scope));
}
/// CreateLexicalBlock - Creates a new lexical block node and pushes it on
@@ -2229,7 +2360,7 @@ void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder) {
// EmitTypeForVarWithBlocksAttr - Build up structure info for the byref.
// See BuildByRefType.
-llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD,
+llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
uint64_t *XOffset) {
SmallVector<llvm::Value *, 5> EltTys;
@@ -2248,7 +2379,7 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD,
EltTys.push_back(CreateMemberType(Unit, FType, "__flags", &FieldOffset));
EltTys.push_back(CreateMemberType(Unit, FType, "__size", &FieldOffset));
- bool HasCopyAndDispose = CGM.getContext().BlockRequiresCopying(Type);
+ bool HasCopyAndDispose = CGM.getContext().BlockRequiresCopying(Type, VD);
if (HasCopyAndDispose) {
FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy);
EltTys.push_back(CreateMemberType(Unit, FType, "__copy_helper",
@@ -2256,6 +2387,14 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD,
EltTys.push_back(CreateMemberType(Unit, FType, "__destroy_helper",
&FieldOffset));
}
+ bool HasByrefExtendedLayout;
+ Qualifiers::ObjCLifetime Lifetime;
+ if (CGM.getContext().getByrefLifetime(Type,
+ Lifetime, HasByrefExtendedLayout)
+ && HasByrefExtendedLayout)
+ EltTys.push_back(CreateMemberType(Unit, FType,
+ "__byref_variable_layout",
+ &FieldOffset));
CharUnits Align = CGM.getContext().getDeclAlign(VD);
if (Align > CGM.getContext().toCharUnitsFromBits(
@@ -2292,7 +2431,7 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD,
unsigned Flags = llvm::DIDescriptor::FlagBlockByrefStruct;
return DBuilder.createStructType(Unit, "", Unit, 0, FieldOffset, 0, Flags,
- Elements);
+ llvm::DIType(), Elements);
}
/// EmitDeclare - Emit local variable declaration debug info.
@@ -2324,7 +2463,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
// If an aggregate variable has non trivial destructor or non trivial copy
// constructor than it is pass indirectly. Let debug info know about this
// by using reference of the aggregate type as a argument type.
- if (!Record->hasTrivialCopyConstructor() ||
+ if (Record->hasNonTrivialCopyConstructor() ||
!Record->hasTrivialDestructor())
Ty = DBuilder.createReferenceType(llvm::dwarf::DW_TAG_reference_type, Ty);
}
@@ -2392,25 +2531,11 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
return;
}
-
- // Create the descriptor for the variable.
- llvm::DIVariable D =
- DBuilder.createLocalVariable(Tag, llvm::DIDescriptor(Scope),
- Name, Unit, Line, Ty,
- CGM.getLangOpts().Optimize, Flags, ArgNo);
-
- // Insert an llvm.dbg.declare into the current block.
- llvm::Instruction *Call =
- DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock());
- Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
- return;
- }
-
- // If VD is an anonymous union then Storage represents value for
- // all union fields.
- if (const RecordType *RT = dyn_cast<RecordType>(VD->getType())) {
+ } else if (const RecordType *RT = dyn_cast<RecordType>(VD->getType())) {
+ // If VD is an anonymous union then Storage represents value for
+ // all union fields.
const RecordDecl *RD = cast<RecordDecl>(RT->getDecl());
- if (RD->isUnion()) {
+ if (RD->isUnion() && RD->isAnonymousStructOrUnion()) {
for (RecordDecl::field_iterator I = RD->field_begin(),
E = RD->field_end();
I != E; ++I) {
@@ -2434,8 +2559,20 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock());
Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
}
+ return;
}
}
+
+ // Create the descriptor for the variable.
+ llvm::DIVariable D =
+ DBuilder.createLocalVariable(Tag, llvm::DIDescriptor(Scope),
+ Name, Unit, Line, Ty,
+ CGM.getLangOpts().Optimize, Flags, ArgNo);
+
+ // Insert an llvm.dbg.declare into the current block.
+ llvm::Instruction *Call =
+ DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock());
+ Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope));
}
void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD,
@@ -2445,6 +2582,19 @@ void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD,
EmitDeclare(VD, llvm::dwarf::DW_TAG_auto_variable, Storage, 0, Builder);
}
+/// Look up the completed type for a self pointer in the TypeCache and
+/// create a copy of it with the ObjectPointer and Artificial flags
+/// set. If the type is not cached, a new one is created. This should
+/// never happen though, since creating a type for the implicit self
+/// argument implies that we already parsed the interface definition
+/// and the ivar declarations in the implementation.
+llvm::DIType CGDebugInfo::CreateSelfType(const QualType &QualTy, llvm::DIType Ty) {
+ llvm::DIType CachedTy = getTypeOrNull(QualTy);
+ if (CachedTy.Verify()) Ty = CachedTy;
+ else DEBUG(llvm::dbgs() << "No cached type for self.");
+ return DBuilder.createObjectPointerType(Ty);
+}
+
void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(const VarDecl *VD,
llvm::Value *Storage,
CGBuilderTy &Builder,
@@ -2468,7 +2618,7 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(const VarDecl *VD,
// Self is passed along as an implicit non-arg variable in a
// block. Mark it as the object pointer.
if (isa<ImplicitParamDecl>(VD) && VD->getName() == "self")
- Ty = DBuilder.createObjectPointerType(Ty);
+ Ty = CreateSelfType(VD->getType(), Ty);
// Get location information.
unsigned Line = getLineNumber(VD->getLocation());
@@ -2482,6 +2632,8 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(const VarDecl *VD,
SmallVector<llvm::Value *, 9> addr;
llvm::Type *Int64Ty = CGM.Int64Ty;
+ if (isa<llvm::AllocaInst>(Storage))
+ addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref));
addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
if (isByRef) {
@@ -2503,6 +2655,7 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(const VarDecl *VD,
DBuilder.createComplexVariable(llvm::dwarf::DW_TAG_auto_variable,
llvm::DIDescriptor(LexicalBlockStack.back()),
VD->getName(), Unit, Line, Ty, addr);
+
// Insert an llvm.dbg.declare into the current block.
llvm::Instruction *Call =
DBuilder.insertDeclare(Storage, D, Builder.GetInsertPoint());
@@ -2530,7 +2683,8 @@ namespace {
}
void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
- llvm::Value *addr,
+ llvm::Value *Arg,
+ llvm::Value *LocalAddr,
CGBuilderTy &Builder) {
assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo);
ASTContext &C = CGM.getContext();
@@ -2651,27 +2805,48 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
DBuilder.createStructType(tunit, typeName.str(), tunit, line,
CGM.getContext().toBits(block.BlockSize),
CGM.getContext().toBits(block.BlockAlign),
- 0, fieldsArray);
+ 0, llvm::DIType(), fieldsArray);
type = DBuilder.createPointerType(type, CGM.PointerWidthInBits);
// Get overall information about the block.
unsigned flags = llvm::DIDescriptor::FlagArtificial;
llvm::MDNode *scope = LexicalBlockStack.back();
- StringRef name = ".block_descriptor";
// Create the descriptor for the parameter.
llvm::DIVariable debugVar =
DBuilder.createLocalVariable(llvm::dwarf::DW_TAG_arg_variable,
llvm::DIDescriptor(scope),
- name, tunit, line, type,
+ Arg->getName(), tunit, line, type,
CGM.getLangOpts().Optimize, flags,
- cast<llvm::Argument>(addr)->getArgNo() + 1);
-
- // Insert an llvm.dbg.value into the current block.
- llvm::Instruction *declare =
- DBuilder.insertDbgValueIntrinsic(addr, 0, debugVar,
- Builder.GetInsertBlock());
- declare->setDebugLoc(llvm::DebugLoc::get(line, column, scope));
+ cast<llvm::Argument>(Arg)->getArgNo() + 1);
+
+ if (LocalAddr) {
+ // Insert an llvm.dbg.value into the current block.
+ llvm::Instruction *DbgVal =
+ DBuilder.insertDbgValueIntrinsic(LocalAddr, 0, debugVar,
+ Builder.GetInsertBlock());
+ DbgVal->setDebugLoc(llvm::DebugLoc::get(line, column, scope));
+ }
+
+ // Insert an llvm.dbg.declare into the current block.
+ llvm::Instruction *DbgDecl =
+ DBuilder.insertDeclare(Arg, debugVar, Builder.GetInsertBlock());
+ DbgDecl->setDebugLoc(llvm::DebugLoc::get(line, column, scope));
+}
+
+/// getStaticDataMemberDeclaration - If D is an out-of-class definition of
+/// a static data member of a class, find its corresponding in-class
+/// declaration.
+llvm::DIDerivedType CGDebugInfo::getStaticDataMemberDeclaration(const Decl *D) {
+ if (cast<VarDecl>(D)->isStaticDataMember()) {
+ llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator
+ MI = StaticDataMemberCache.find(D->getCanonicalDecl());
+ if (MI != StaticDataMemberCache.end())
+ // Verify the info still exists.
+ if (llvm::Value *V = MI->second)
+ return llvm::DIDerivedType(cast<llvm::MDNode>(V));
+ }
+ return llvm::DIDerivedType();
}
/// EmitGlobalVariable - Emit information about a global variable.
@@ -2705,7 +2880,8 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
getContextDescriptor(dyn_cast<Decl>(D->getDeclContext()));
DBuilder.createStaticVariable(DContext, DeclName, LinkageName,
Unit, LineNo, getOrCreateType(T, Unit),
- Var->hasInternalLinkage(), Var);
+ Var->hasInternalLinkage(), Var,
+ getStaticDataMemberDeclaration(D));
}
/// EmitGlobalVariable - Emit information about an objective-c interface.
@@ -2752,7 +2928,8 @@ void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD,
return;
DBuilder.createStaticVariable(Unit, Name, Name, Unit,
getLineNumber(VD->getLocation()),
- Ty, true, Init);
+ Ty, true, Init,
+ getStaticDataMemberDeclaration(VD));
}
/// getOrCreateNamesSpace - Return namespace descriptor for the given
@@ -2774,7 +2951,7 @@ CGDebugInfo::getOrCreateNameSpace(const NamespaceDecl *NSDecl) {
return NS;
}
-void CGDebugInfo::finalize(void) {
+void CGDebugInfo::finalize() {
for (std::vector<std::pair<void *, llvm::WeakVH> >::const_iterator VI
= ReplaceMap.begin(), VE = ReplaceMap.end(); VI != VE; ++VI) {
llvm::DIType Ty, RepTy;
@@ -2789,10 +2966,16 @@ void CGDebugInfo::finalize(void) {
if (llvm::Value *V = it->second)
RepTy = llvm::DIType(cast<llvm::MDNode>(V));
}
-
- if (Ty.Verify() && Ty.isForwardDecl() && RepTy.Verify()) {
+
+ if (Ty.Verify() && Ty.isForwardDecl() && RepTy.Verify())
Ty.replaceAllUsesWith(RepTy);
- }
}
+
+ // We keep our own list of retained types, because we need to look
+ // up the final type in the type cache.
+ for (std::vector<void *>::const_iterator RI = RetainedTypes.begin(),
+ RE = RetainedTypes.end(); RI != RE; ++RI)
+ DBuilder.retainType(llvm::DIType(cast<llvm::MDNode>(TypeCache[*RI])));
+
DBuilder.finalize();
}
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index 2e88a73..3a0df99 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -14,16 +14,15 @@
#ifndef CLANG_CODEGEN_CGDEBUGINFO_H
#define CLANG_CODEGEN_CGDEBUGINFO_H
-#include "clang/AST/Type.h"
+#include "CGBuilder.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
#include "clang/Basic/SourceLocation.h"
-#include "llvm/DebugInfo.h"
-#include "llvm/DIBuilder.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/Support/ValueHandle.h"
+#include "llvm/DIBuilder.h"
+#include "llvm/DebugInfo.h"
#include "llvm/Support/Allocator.h"
-
-#include "CGBuilder.h"
+#include "llvm/Support/ValueHandle.h"
namespace llvm {
class MDNode;
@@ -33,6 +32,7 @@ namespace clang {
class CXXMethodDecl;
class VarDecl;
class ObjCInterfaceDecl;
+ class ObjCIvarDecl;
class ClassTemplateSpecializationDecl;
class GlobalDecl;
@@ -51,12 +51,24 @@ class CGDebugInfo {
SourceLocation CurLoc, PrevLoc;
llvm::DIType VTablePtrType;
llvm::DIType ClassTy;
- llvm::DIType ObjTy;
+ llvm::DICompositeType ObjTy;
llvm::DIType SelTy;
+ llvm::DIType OCLImage1dDITy, OCLImage1dArrayDITy, OCLImage1dBufferDITy;
+ llvm::DIType OCLImage2dDITy, OCLImage2dArrayDITy;
+ llvm::DIType OCLImage3dDITy;
+ llvm::DIType OCLEventDITy;
/// TypeCache - Cache of previously constructed Types.
llvm::DenseMap<void *, llvm::WeakVH> TypeCache;
+ /// ObjCInterfaceCache - Cache of previously constructed interfaces
+ /// which may change. Storing a pair of DIType and checksum.
+ llvm::DenseMap<void *, std::pair<llvm::WeakVH, unsigned > >
+ ObjCInterfaceCache;
+
+ /// RetainedTypes - list of interfaces we want to keep even if orphaned.
+ std::vector<void *> RetainedTypes;
+
/// CompleteTypeCache - Cache of previously constructed complete RecordTypes.
llvm::DenseMap<void *, llvm::WeakVH> CompletedTypeCache;
@@ -83,8 +95,10 @@ class CGDebugInfo {
llvm::DenseMap<const char *, llvm::WeakVH> DIFileCache;
llvm::DenseMap<const FunctionDecl *, llvm::WeakVH> SPCache;
llvm::DenseMap<const NamespaceDecl *, llvm::WeakVH> NameSpaceCache;
+ llvm::DenseMap<const Decl *, llvm::WeakVH> StaticDataMemberCache;
/// Helper functions for getOrCreateType.
+ unsigned Checksum(const ObjCInterfaceDecl *InterfaceDecl);
llvm::DIType CreateType(const BuiltinType *Ty);
llvm::DIType CreateType(const ComplexType *Ty);
llvm::DIType CreateQualifiedType(QualType Ty, llvm::DIFile F);
@@ -105,10 +119,13 @@ class CGDebugInfo {
llvm::DIType CreateType(const MemberPointerType *Ty, llvm::DIFile F);
llvm::DIType CreateType(const AtomicType *Ty, llvm::DIFile F);
llvm::DIType CreateEnumType(const EnumDecl *ED);
+ llvm::DIType CreateSelfType(const QualType &QualTy, llvm::DIType Ty);
llvm::DIType getTypeOrNull(const QualType);
llvm::DIType getCompletedTypeOrNull(const QualType);
llvm::DIType getOrCreateMethodType(const CXXMethodDecl *Method,
llvm::DIFile F);
+ llvm::DIType getOrCreateInstanceMethodType(
+ QualType ThisPtr, const FunctionProtoType *Func, llvm::DIFile Unit);
llvm::DIType getOrCreateFunctionType(const Decl *D, QualType FnType,
llvm::DIFile F);
llvm::DIType getOrCreateVTablePtrType(llvm::DIFile F);
@@ -117,7 +134,10 @@ class CGDebugInfo {
llvm::DIType CreatePointerLikeType(unsigned Tag,
const Type *Ty, QualType PointeeTy,
llvm::DIFile F);
-
+
+ llvm::Value *getCachedInterfaceTypeOrNull(const QualType Ty);
+ llvm::DIType getOrCreateStructPtrType(StringRef Name, llvm::DIType &Cache);
+
llvm::DISubprogram CreateCXXMemberFunction(const CXXMethodDecl *Method,
llvm::DIFile F,
llvm::DIType RecordTy);
@@ -152,7 +172,18 @@ class CGDebugInfo {
AccessSpecifier AS, uint64_t offsetInBits,
llvm::DIFile tunit,
llvm::DIDescriptor scope);
- void CollectRecordStaticVars(const RecordDecl *, llvm::DIType);
+
+ // Helpers for collecting fields of a record.
+ void CollectRecordLambdaFields(const CXXRecordDecl *CXXDecl,
+ SmallVectorImpl<llvm::Value *> &E,
+ llvm::DIType RecordTy);
+ void CollectRecordStaticField(const VarDecl *Var,
+ SmallVectorImpl<llvm::Value *> &E,
+ llvm::DIType RecordTy);
+ void CollectRecordNormalField(const FieldDecl *Field, uint64_t OffsetInBits,
+ llvm::DIFile F,
+ SmallVectorImpl<llvm::Value *> &E,
+ llvm::DIType RecordTy);
void CollectRecordFields(const RecordDecl *Decl, llvm::DIFile F,
SmallVectorImpl<llvm::Value *> &E,
llvm::DIType RecordTy);
@@ -169,7 +200,7 @@ public:
CGDebugInfo(CodeGenModule &CGM);
~CGDebugInfo();
- void finalize(void);
+ void finalize();
/// setLocation - Update the current source location. If \arg loc is
/// invalid it is ignored.
@@ -177,7 +208,9 @@ public:
/// EmitLocation - Emit metadata to indicate a change in line/column
/// information in the source file.
- void EmitLocation(CGBuilderTy &Builder, SourceLocation Loc);
+ /// \param ForceColumnInfo Assume DebugColumnInfo option is true.
+ void EmitLocation(CGBuilderTy &Builder, SourceLocation Loc,
+ bool ForceColumnInfo = false);
/// EmitFunctionStart - Emit a call to llvm.dbg.function.start to indicate
/// start of a new function.
@@ -216,7 +249,8 @@ public:
/// llvm.dbg.declare for the block-literal argument to a block
/// invocation function.
void EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block,
- llvm::Value *addr,
+ llvm::Value *Arg,
+ llvm::Value *LocalAddr,
CGBuilderTy &Builder);
/// EmitGlobalVariable - Emit information about a global variable.
@@ -243,7 +277,7 @@ private:
// EmitTypeForVarWithBlocksAttr - Build up structure info for the byref.
// See BuildByRefType.
- llvm::DIType EmitTypeForVarWithBlocksAttr(const ValueDecl *VD,
+ llvm::DIType EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
uint64_t *OffSet);
/// getContextDescriptor - Get context info for the decl.
@@ -280,6 +314,10 @@ private:
/// CreateTypeNode - Create type metadata for a source language type.
llvm::DIType CreateTypeNode(QualType Ty, llvm::DIFile F);
+ /// getObjCInterfaceDecl - return the underlying ObjCInterfaceDecl
+ /// if Ty is an ObjCInterface or a pointer to one.
+ ObjCInterfaceDecl* getObjCInterfaceDecl(QualType Ty);
+
/// CreateLimitedTypeNode - Create type metadata for a source language
/// type, but only partial types for records.
llvm::DIType CreateLimitedTypeNode(QualType Ty, llvm::DIFile F);
@@ -292,6 +330,11 @@ private:
/// declaration for the given method definition.
llvm::DISubprogram getFunctionDeclaration(const Decl *D);
+ /// getStaticDataMemberDeclaration - Return debug info descriptor to
+ /// describe in-class static data member declaration for the given
+ /// out-of-class definition.
+ llvm::DIDerivedType getStaticDataMemberDeclaration(const Decl *D);
+
/// getFunctionName - Get function name for the given FunctionDecl. If the
/// name is constructred on demand (e.g. C++ destructor) then the name
/// is stored on the side.
@@ -317,7 +360,8 @@ private:
/// getColumnNumber - Get column number for the location. If location is
/// invalid then use current location.
- unsigned getColumnNumber(SourceLocation Loc);
+ /// \param Force Assume DebugColumnInfo option is true.
+ unsigned getColumnNumber(SourceLocation Loc, bool Force=false);
};
} // namespace CodeGen
} // namespace clang
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 8870587..5375c5e 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -11,10 +11,10 @@
//
//===----------------------------------------------------------------------===//
-#include "CGDebugInfo.h"
#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
+#include "CGDebugInfo.h"
#include "CGOpenCLRuntime.h"
+#include "CodeGenModule.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.h"
@@ -22,10 +22,10 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
-#include "llvm/GlobalVariable.h"
-#include "llvm/Intrinsics.h"
-#include "llvm/DataLayout.h"
-#include "llvm/Type.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/Type.h"
using namespace clang;
using namespace CodeGen;
@@ -83,6 +83,8 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::StaticAssert: // static_assert(X, ""); [C++0x]
case Decl::Label: // __label__ x;
case Decl::Import:
+ case Decl::OMPThreadPrivate:
+ case Decl::Empty:
// None of these decls require codegen support.
return;
@@ -386,7 +388,9 @@ namespace {
}
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete,
- /*ForVirtualBase=*/false, Loc);
+ /*ForVirtualBase=*/false,
+ /*Delegating=*/false,
+ Loc);
if (NRVO) CGF.EmitBlock(SkipDtorBB);
}
@@ -448,6 +452,22 @@ namespace {
CGF.EmitCall(FnInfo, CleanupFn, ReturnValueSlot(), Args);
}
};
+
+ /// A cleanup to call @llvm.lifetime.end.
+ class CallLifetimeEnd : public EHScopeStack::Cleanup {
+ llvm::Value *Addr;
+ llvm::Value *Size;
+ public:
+ CallLifetimeEnd(llvm::Value *addr, llvm::Value *size)
+ : Addr(addr), Size(size) {}
+
+ void Emit(CodeGenFunction &CGF, Flags flags) {
+ llvm::Value *castAddr = CGF.Builder.CreateBitCast(Addr, CGF.Int8PtrTy);
+ CGF.Builder.CreateCall2(CGF.CGM.getLLVMLifetimeEndFn(),
+ Size, castAddr)
+ ->setDoesNotThrow();
+ }
+ };
}
/// EmitAutoVarWithLifetime - Does the setup required for an automatic
@@ -624,7 +644,7 @@ void CodeGenFunction::EmitScalarInit(const Expr *init,
if (accessedByInit && lifetime == Qualifiers::OCL_Strong) {
llvm::Value *oldValue = EmitLoadOfScalar(lvalue);
EmitStoreOfScalar(value, lvalue, /* isInitialization */ true);
- EmitARCRelease(oldValue, /*precise*/ false);
+ EmitARCRelease(oldValue, ARCImpreciseLifetime);
return;
}
@@ -752,7 +772,6 @@ static bool shouldUseMemSetPlusStoresToInitialize(llvm::Constant *Init,
// If a global is all zeros, always use a memset.
if (isa<llvm::ConstantAggregateZero>(Init)) return true;
-
// If a non-zero global is <= 32 bytes, always use a memcpy. If it is large,
// do it if it will require 6 or fewer scalar stores.
// TODO: Should budget depends on the size? Avoiding a large global warrants
@@ -764,6 +783,23 @@ static bool shouldUseMemSetPlusStoresToInitialize(llvm::Constant *Init,
canEmitInitWithFewStoresAfterMemset(Init, StoreBudget);
}
+/// Should we use the LLVM lifetime intrinsics for the given local variable?
+static bool shouldUseLifetimeMarkers(CodeGenFunction &CGF, const VarDecl &D,
+ unsigned Size) {
+ // Always emit lifetime markers in -fsanitize=use-after-scope mode.
+ if (CGF.getLangOpts().Sanitize.UseAfterScope)
+ return true;
+ // For now, only in optimized builds.
+ if (CGF.CGM.getCodeGenOpts().OptimizationLevel == 0)
+ return false;
+
+ // Limit the size of marked objects to 32 bytes. We don't want to increase
+ // compile time by marking tiny objects.
+ unsigned SizeThreshold = 32;
+
+ return Size > SizeThreshold;
+}
+
/// EmitAutoVarDecl - Emit code and set up an entry in LocalDeclMap for a
/// variable declaration with auto, register, or no storage class specifier.
@@ -794,85 +830,91 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
llvm::Value *DeclPtr;
if (Ty->isConstantSizeType()) {
- if (!Target.useGlobalsForAutomaticVariables()) {
- bool NRVO = getLangOpts().ElideConstructors &&
- D.isNRVOVariable();
-
- // If this value is a POD array or struct with a statically
- // determinable constant initializer, there are optimizations we can do.
- //
- // TODO: We should constant-evaluate the initializer of any variable,
- // as long as it is initialized by a constant expression. Currently,
- // isConstantInitializer produces wrong answers for structs with
- // reference or bitfield members, and a few other cases, and checking
- // for POD-ness protects us from some of these.
- if (D.getInit() &&
- (Ty->isArrayType() || Ty->isRecordType()) &&
- (Ty.isPODType(getContext()) ||
- getContext().getBaseElementType(Ty)->isObjCObjectPointerType()) &&
- D.getInit()->isConstantInitializer(getContext(), false)) {
-
- // If the variable's a const type, and it's neither an NRVO
- // candidate nor a __block variable and has no mutable members,
- // emit it as a global instead.
- if (CGM.getCodeGenOpts().MergeAllConstants && !NRVO && !isByRef &&
- CGM.isTypeConstant(Ty, true)) {
- EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
-
- emission.Address = 0; // signal this condition to later callbacks
- assert(emission.wasEmittedAsGlobal());
- return emission;
- }
-
- // Otherwise, tell the initialization code that we're in this case.
- emission.IsConstantAggregate = true;
+ bool NRVO = getLangOpts().ElideConstructors &&
+ D.isNRVOVariable();
+
+ // If this value is a POD array or struct with a statically
+ // determinable constant initializer, there are optimizations we can do.
+ //
+ // TODO: We should constant-evaluate the initializer of any variable,
+ // as long as it is initialized by a constant expression. Currently,
+ // isConstantInitializer produces wrong answers for structs with
+ // reference or bitfield members, and a few other cases, and checking
+ // for POD-ness protects us from some of these.
+ if (D.getInit() &&
+ (Ty->isArrayType() || Ty->isRecordType()) &&
+ (Ty.isPODType(getContext()) ||
+ getContext().getBaseElementType(Ty)->isObjCObjectPointerType()) &&
+ D.getInit()->isConstantInitializer(getContext(), false)) {
+
+ // If the variable's a const type, and it's neither an NRVO
+ // candidate nor a __block variable and has no mutable members,
+ // emit it as a global instead.
+ if (CGM.getCodeGenOpts().MergeAllConstants && !NRVO && !isByRef &&
+ CGM.isTypeConstant(Ty, true)) {
+ EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
+
+ emission.Address = 0; // signal this condition to later callbacks
+ assert(emission.wasEmittedAsGlobal());
+ return emission;
}
- // A normal fixed sized variable becomes an alloca in the entry block,
- // unless it's an NRVO variable.
- llvm::Type *LTy = ConvertTypeForMem(Ty);
+ // Otherwise, tell the initialization code that we're in this case.
+ emission.IsConstantAggregate = true;
+ }
- if (NRVO) {
- // The named return value optimization: allocate this variable in the
- // return slot, so that we can elide the copy when returning this
- // variable (C++0x [class.copy]p34).
- DeclPtr = ReturnValue;
-
- if (const RecordType *RecordTy = Ty->getAs<RecordType>()) {
- if (!cast<CXXRecordDecl>(RecordTy->getDecl())->hasTrivialDestructor()) {
- // Create a flag that is used to indicate when the NRVO was applied
- // to this variable. Set it to zero to indicate that NRVO was not
- // applied.
- llvm::Value *Zero = Builder.getFalse();
- llvm::Value *NRVOFlag = CreateTempAlloca(Zero->getType(), "nrvo");
- EnsureInsertPoint();
- Builder.CreateStore(Zero, NRVOFlag);
-
- // Record the NRVO flag for this variable.
- NRVOFlags[&D] = NRVOFlag;
- emission.NRVOFlag = NRVOFlag;
- }
+ // A normal fixed sized variable becomes an alloca in the entry block,
+ // unless it's an NRVO variable.
+ llvm::Type *LTy = ConvertTypeForMem(Ty);
+
+ if (NRVO) {
+ // The named return value optimization: allocate this variable in the
+ // return slot, so that we can elide the copy when returning this
+ // variable (C++0x [class.copy]p34).
+ DeclPtr = ReturnValue;
+
+ if (const RecordType *RecordTy = Ty->getAs<RecordType>()) {
+ if (!cast<CXXRecordDecl>(RecordTy->getDecl())->hasTrivialDestructor()) {
+ // Create a flag that is used to indicate when the NRVO was applied
+ // to this variable. Set it to zero to indicate that NRVO was not
+ // applied.
+ llvm::Value *Zero = Builder.getFalse();
+ llvm::Value *NRVOFlag = CreateTempAlloca(Zero->getType(), "nrvo");
+ EnsureInsertPoint();
+ Builder.CreateStore(Zero, NRVOFlag);
+
+ // Record the NRVO flag for this variable.
+ NRVOFlags[&D] = NRVOFlag;
+ emission.NRVOFlag = NRVOFlag;
}
- } else {
- if (isByRef)
- LTy = BuildByRefType(&D);
-
- llvm::AllocaInst *Alloc = CreateTempAlloca(LTy);
- Alloc->setName(D.getName());
-
- CharUnits allocaAlignment = alignment;
- if (isByRef)
- allocaAlignment = std::max(allocaAlignment,
- getContext().toCharUnitsFromBits(Target.getPointerAlign(0)));
- Alloc->setAlignment(allocaAlignment.getQuantity());
- DeclPtr = Alloc;
}
} else {
- // Targets that don't support recursion emit locals as globals.
- const char *Class =
- D.getStorageClass() == SC_Register ? ".reg." : ".auto.";
- DeclPtr = CreateStaticVarDecl(D, Class,
- llvm::GlobalValue::InternalLinkage);
+ if (isByRef)
+ LTy = BuildByRefType(&D);
+
+ llvm::AllocaInst *Alloc = CreateTempAlloca(LTy);
+ Alloc->setName(D.getName());
+
+ CharUnits allocaAlignment = alignment;
+ if (isByRef)
+ allocaAlignment = std::max(allocaAlignment,
+ getContext().toCharUnitsFromBits(Target.getPointerAlign(0)));
+ Alloc->setAlignment(allocaAlignment.getQuantity());
+ DeclPtr = Alloc;
+
+ // Emit a lifetime intrinsic if meaningful. There's no point
+ // in doing this if we don't have a valid insertion point (?).
+ uint64_t size = CGM.getDataLayout().getTypeAllocSize(LTy);
+ if (HaveInsertPoint() && shouldUseLifetimeMarkers(*this, D, size)) {
+ llvm::Value *sizeV = llvm::ConstantInt::get(Int64Ty, size);
+
+ emission.SizeForLifetimeMarkers = sizeV;
+ llvm::Value *castAddr = Builder.CreateBitCast(Alloc, Int8PtrTy);
+ Builder.CreateCall2(CGM.getLLVMLifetimeStartFn(), sizeV, castAddr)
+ ->setDoesNotThrow();
+ } else {
+ assert(!emission.useLifetimeMarkers());
+ }
}
} else {
EnsureInsertPoint();
@@ -917,11 +959,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
if (CGM.getCodeGenOpts().getDebugInfo()
>= CodeGenOptions::LimitedDebugInfo) {
DI->setLocation(D.getLocation());
- if (Target.useGlobalsForAutomaticVariables()) {
- DI->EmitGlobalVariable(static_cast<llvm::GlobalVariable *>(DeclPtr),
- &D);
- } else
- DI->EmitDeclareOfAutoVariable(&D, DeclPtr, Builder);
+ DI->EmitDeclareOfAutoVariable(&D, DeclPtr, Builder);
}
}
@@ -1112,21 +1150,33 @@ void CodeGenFunction::EmitExprAsInit(const Expr *init,
if (capturedByInit)
drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
EmitStoreThroughLValue(rvalue, lvalue, true);
- } else if (!hasAggregateLLVMType(type)) {
+ return;
+ }
+ switch (getEvaluationKind(type)) {
+ case TEK_Scalar:
EmitScalarInit(init, D, lvalue, capturedByInit);
- } else if (type->isAnyComplexType()) {
+ return;
+ case TEK_Complex: {
ComplexPairTy complex = EmitComplexExpr(init);
if (capturedByInit)
drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
- StoreComplexToAddr(complex, lvalue.getAddress(), lvalue.isVolatile());
- } else {
- // TODO: how can we delay here if D is captured by its initializer?
- EmitAggExpr(init, AggValueSlot::forLValue(lvalue,
+ EmitStoreOfComplex(complex, lvalue, /*init*/ true);
+ return;
+ }
+ case TEK_Aggregate:
+ if (type->isAtomicType()) {
+ EmitAtomicInit(const_cast<Expr*>(init), lvalue);
+ } else {
+ // TODO: how can we delay here if D is captured by its initializer?
+ EmitAggExpr(init, AggValueSlot::forLValue(lvalue,
AggValueSlot::IsDestructed,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased));
+ }
MaybeEmitStdInitializerListCleanup(lvalue.getAddress(), init);
+ return;
}
+ llvm_unreachable("bad evaluation kind");
}
/// Enter a destroy cleanup for the given local variable.
@@ -1199,6 +1249,14 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
const VarDecl &D = *emission.Variable;
+ // Make sure we call @llvm.lifetime.end. This needs to happen
+ // *last*, so the cleanup needs to be pushed *first*.
+ if (emission.useLifetimeMarkers()) {
+ EHStack.pushCleanup<CallLifetimeEnd>(NormalCleanup,
+ emission.getAllocatedAddress(),
+ emission.getSizeForLifetimeMarkers());
+ }
+
// Check the type for a cleanup.
if (QualType::DestructionKind dtorKind = D.getType().isDestructedType())
emitAutoVarTypeCleanup(emission, dtorKind);
@@ -1240,7 +1298,18 @@ CodeGenFunction::getDestroyer(QualType::DestructionKind kind) {
llvm_unreachable("Unknown DestructionKind");
}
-/// pushDestroy - Push the standard destructor for the given type.
+/// pushEHDestroy - Push the standard destructor for the given type as
+/// an EH-only cleanup.
+void CodeGenFunction::pushEHDestroy(QualType::DestructionKind dtorKind,
+ llvm::Value *addr, QualType type) {
+ assert(dtorKind && "cannot push destructor for trivial type");
+ assert(needsEHCleanup(dtorKind));
+
+ pushDestroy(EHCleanup, addr, type, getDestroyer(dtorKind), true);
+}
+
+/// pushDestroy - Push the standard destructor for the given type as
+/// at least a normal cleanup.
void CodeGenFunction::pushDestroy(QualType::DestructionKind dtorKind,
llvm::Value *addr, QualType type) {
assert(dtorKind && "cannot push destructor for trivial type");
@@ -1434,10 +1503,6 @@ namespace {
///
/// \param elementType - the immediate element type of the array;
/// possibly still an array type
-/// \param array - a value of type elementType*
-/// \param destructionKind - the kind of destruction required
-/// \param initializedElementCount - a value of type size_t* holding
-/// the number of successfully-constructed elements
void CodeGenFunction::pushIrregularPartialArrayCleanup(llvm::Value *arrayBegin,
llvm::Value *arrayEndPointer,
QualType elementType,
@@ -1453,10 +1518,6 @@ void CodeGenFunction::pushIrregularPartialArrayCleanup(llvm::Value *arrayBegin,
///
/// \param elementType - the immediate element type of the array;
/// possibly still an array type
-/// \param array - a value of type elementType*
-/// \param destructionKind - the kind of destruction required
-/// \param initializedElementCount - a value of type size_t* holding
-/// the number of successfully-constructed elements
void CodeGenFunction::pushRegularPartialArrayCleanup(llvm::Value *arrayBegin,
llvm::Value *arrayEnd,
QualType elementType,
@@ -1466,18 +1527,37 @@ void CodeGenFunction::pushRegularPartialArrayCleanup(llvm::Value *arrayBegin,
elementType, destroyer);
}
+/// Lazily declare the @llvm.lifetime.start intrinsic.
+llvm::Constant *CodeGenModule::getLLVMLifetimeStartFn() {
+ if (LifetimeStartFn) return LifetimeStartFn;
+ LifetimeStartFn = llvm::Intrinsic::getDeclaration(&getModule(),
+ llvm::Intrinsic::lifetime_start);
+ return LifetimeStartFn;
+}
+
+/// Lazily declare the @llvm.lifetime.end intrinsic.
+llvm::Constant *CodeGenModule::getLLVMLifetimeEndFn() {
+ if (LifetimeEndFn) return LifetimeEndFn;
+ LifetimeEndFn = llvm::Intrinsic::getDeclaration(&getModule(),
+ llvm::Intrinsic::lifetime_end);
+ return LifetimeEndFn;
+}
+
namespace {
/// A cleanup to perform a release of an object at the end of a
/// function. This is used to balance out the incoming +1 of a
/// ns_consumed argument when we can't reasonably do that just by
/// not doing the initial retain for a __block argument.
struct ConsumeARCParameter : EHScopeStack::Cleanup {
- ConsumeARCParameter(llvm::Value *param) : Param(param) {}
+ ConsumeARCParameter(llvm::Value *param,
+ ARCPreciseLifetime_t precise)
+ : Param(param), Precise(precise) {}
llvm::Value *Param;
+ ARCPreciseLifetime_t Precise;
void Emit(CodeGenFunction &CGF, Flags flags) {
- CGF.EmitARCRelease(Param, /*precise*/ false);
+ CGF.EmitARCRelease(Param, Precise);
}
};
}
@@ -1492,17 +1572,29 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
Arg->setName(D.getName());
+ QualType Ty = D.getType();
+
// Use better IR generation for certain implicit parameters.
if (isa<ImplicitParamDecl>(D)) {
// The only implicit argument a block has is its literal.
if (BlockInfo) {
LocalDeclMap[&D] = Arg;
+ llvm::Value *LocalAddr = 0;
+ if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
+ // Allocate a stack slot to let the debug info survive the RA.
+ llvm::AllocaInst *Alloc = CreateTempAlloca(ConvertTypeForMem(Ty),
+ D.getName() + ".addr");
+ Alloc->setAlignment(getContext().getDeclAlign(&D).getQuantity());
+ LValue lv = MakeAddrLValue(Alloc, Ty, getContext().getDeclAlign(&D));
+ EmitStoreOfScalar(Arg, lv, /* isInitialization */ true);
+ LocalAddr = Builder.CreateLoad(Alloc);
+ }
if (CGDebugInfo *DI = getDebugInfo()) {
if (CGM.getCodeGenOpts().getDebugInfo()
>= CodeGenOptions::LimitedDebugInfo) {
DI->setLocation(D.getLocation());
- DI->EmitDeclareOfBlockLiteralArgVariable(*BlockInfo, Arg, Builder);
+ DI->EmitDeclareOfBlockLiteralArgVariable(*BlockInfo, Arg, LocalAddr, Builder);
}
}
@@ -1510,24 +1602,23 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
}
}
- QualType Ty = D.getType();
-
llvm::Value *DeclPtr;
// If this is an aggregate or variable sized value, reuse the input pointer.
if (!Ty->isConstantSizeType() ||
- CodeGenFunction::hasAggregateLLVMType(Ty)) {
+ !CodeGenFunction::hasScalarEvaluationKind(Ty)) {
DeclPtr = Arg;
} else {
// Otherwise, create a temporary to hold the value.
llvm::AllocaInst *Alloc = CreateTempAlloca(ConvertTypeForMem(Ty),
D.getName() + ".addr");
- Alloc->setAlignment(getContext().getDeclAlign(&D).getQuantity());
+ CharUnits Align = getContext().getDeclAlign(&D);
+ Alloc->setAlignment(Align.getQuantity());
DeclPtr = Alloc;
bool doStore = true;
Qualifiers qs = Ty.getQualifiers();
-
+ LValue lv = MakeAddrLValue(DeclPtr, Ty, Align);
if (Qualifiers::ObjCLifetime lt = qs.getObjCLifetime()) {
// We honor __attribute__((ns_consumed)) for types with lifetime.
// For __strong, it's handled by just skipping the initial retain;
@@ -1548,15 +1639,30 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
}
if (lt == Qualifiers::OCL_Strong) {
- if (!isConsumed)
+ if (!isConsumed) {
+ if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
+ // use objc_storeStrong(&dest, value) for retaining the
+ // object. But first, store a null into 'dest' because
+ // objc_storeStrong attempts to release its old value.
+ llvm::Value * Null = CGM.EmitNullConstant(D.getType());
+ EmitStoreOfScalar(Null, lv, /* isInitialization */ true);
+ EmitARCStoreStrongCall(lv.getAddress(), Arg, true);
+ doStore = false;
+ }
+ else
// Don't use objc_retainBlock for block pointers, because we
// don't want to Block_copy something just because we got it
// as a parameter.
- Arg = EmitARCRetainNonBlock(Arg);
+ Arg = EmitARCRetainNonBlock(Arg);
+ }
} else {
// Push the cleanup for a consumed parameter.
- if (isConsumed)
- EHStack.pushCleanup<ConsumeARCParameter>(getARCCleanupKind(), Arg);
+ if (isConsumed) {
+ ARCPreciseLifetime_t precise = (D.hasAttr<ObjCPreciseLifetimeAttr>()
+ ? ARCPreciseLifetime : ARCImpreciseLifetime);
+ EHStack.pushCleanup<ConsumeARCParameter>(getARCCleanupKind(), Arg,
+ precise);
+ }
if (lt == Qualifiers::OCL_Weak) {
EmitARCInitWeak(DeclPtr, Arg);
@@ -1569,11 +1675,8 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg,
}
// Store the initial value into the alloca.
- if (doStore) {
- LValue lv = MakeAddrLValue(DeclPtr, Ty,
- getContext().getDeclAlign(&D));
+ if (doStore)
EmitStoreOfScalar(Arg, lv, /* isInitialization */ true);
- }
}
llvm::Value *&DMEntry = LocalDeclMap[&D];
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index 65be3c1..0448d31 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -12,11 +12,11 @@
//===----------------------------------------------------------------------===//
#include "CodeGenFunction.h"
-#include "CGObjCRuntime.h"
#include "CGCXXABI.h"
+#include "CGObjCRuntime.h"
#include "clang/Frontend/CodeGenOptions.h"
-#include "llvm/Intrinsics.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/IR/Intrinsics.h"
using namespace clang;
using namespace CodeGen;
@@ -34,7 +34,8 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D,
LValue lv = CGF.MakeAddrLValue(DeclPtr, type, alignment);
const Expr *Init = D.getInit();
- if (!CGF.hasAggregateLLVMType(type)) {
+ switch (CGF.getEvaluationKind(type)) {
+ case TEK_Scalar: {
CodeGenModule &CGM = CGF.CGM;
if (lv.isObjCStrong())
CGM.getObjCRuntime().EmitObjCGlobalAssign(CGF, CGF.EmitScalarExpr(Init),
@@ -44,13 +45,18 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D,
DeclPtr);
else
CGF.EmitScalarInit(Init, &D, lv, false);
- } else if (type->isAnyComplexType()) {
- CGF.EmitComplexExprIntoAddr(Init, DeclPtr, lv.isVolatile());
- } else {
+ return;
+ }
+ case TEK_Complex:
+ CGF.EmitComplexExprIntoLValue(Init, lv, /*isInit*/ true);
+ return;
+ case TEK_Aggregate:
CGF.EmitAggExpr(Init, AggValueSlot::forLValue(lv,AggValueSlot::IsDestructed,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased));
+ return;
}
+ llvm_unreachable("bad evaluation kind");
}
/// Emit code to cause the destruction of the given variable with
@@ -198,7 +204,7 @@ void CodeGenFunction::registerGlobalDtorWithAtExit(llvm::Constant *dtor,
if (llvm::Function *atexitFn = dyn_cast<llvm::Function>(atexit))
atexitFn->setDoesNotThrow();
- Builder.CreateCall(atexit, dtorStub)->setDoesNotThrow();
+ EmitNounwindRuntimeCall(atexit, dtorStub);
}
void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D,
@@ -229,11 +235,17 @@ CreateGlobalInitOrDestructFunction(CodeGenModule &CGM,
Fn->setSection(Section);
}
+ Fn->setCallingConv(CGM.getRuntimeCC());
+
if (!CGM.getLangOpts().Exceptions)
Fn->setDoesNotThrow();
- if (CGM.getLangOpts().SanitizeAddress)
- Fn->addFnAttr(llvm::Attributes::AddressSafety);
+ if (CGM.getSanOpts().Address)
+ Fn->addFnAttr(llvm::Attribute::SanitizeAddress);
+ if (CGM.getSanOpts().Thread)
+ Fn->addFnAttr(llvm::Attribute::SanitizeThread);
+ if (CGM.getSanOpts().Memory)
+ Fn->addFnAttr(llvm::Attribute::SanitizeMemory);
return Fn;
}
@@ -388,7 +400,7 @@ void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
for (unsigned i = 0; i != NumDecls; ++i)
if (Decls[i])
- Builder.CreateCall(Decls[i]);
+ EmitRuntimeCall(Decls[i]);
Scope.ForceCleanup();
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index 86dee5a..36642bc 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -16,84 +16,85 @@
#include "CGObjCRuntime.h"
#include "TargetInfo.h"
#include "clang/AST/StmtCXX.h"
-#include "llvm/Intrinsics.h"
+#include "clang/AST/StmtObjC.h"
+#include "llvm/IR/Intrinsics.h"
#include "llvm/Support/CallSite.h"
using namespace clang;
using namespace CodeGen;
-static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) {
+static llvm::Constant *getAllocateExceptionFn(CodeGenModule &CGM) {
// void *__cxa_allocate_exception(size_t thrown_size);
llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGF.Int8PtrTy, CGF.SizeTy, /*IsVarArgs=*/false);
+ llvm::FunctionType::get(CGM.Int8PtrTy, CGM.SizeTy, /*IsVarArgs=*/false);
- return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception");
+ return CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception");
}
-static llvm::Constant *getFreeExceptionFn(CodeGenFunction &CGF) {
+static llvm::Constant *getFreeExceptionFn(CodeGenModule &CGM) {
// void __cxa_free_exception(void *thrown_exception);
llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGF.VoidTy, CGF.Int8PtrTy, /*IsVarArgs=*/false);
+ llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);
- return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception");
+ return CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception");
}
-static llvm::Constant *getThrowFn(CodeGenFunction &CGF) {
+static llvm::Constant *getThrowFn(CodeGenModule &CGM) {
// void __cxa_throw(void *thrown_exception, std::type_info *tinfo,
// void (*dest) (void *));
- llvm::Type *Args[3] = { CGF.Int8PtrTy, CGF.Int8PtrTy, CGF.Int8PtrTy };
+ llvm::Type *Args[3] = { CGM.Int8PtrTy, CGM.Int8PtrTy, CGM.Int8PtrTy };
llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGF.VoidTy, Args, /*IsVarArgs=*/false);
+ llvm::FunctionType::get(CGM.VoidTy, Args, /*IsVarArgs=*/false);
- return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_throw");
+ return CGM.CreateRuntimeFunction(FTy, "__cxa_throw");
}
-static llvm::Constant *getReThrowFn(CodeGenFunction &CGF) {
+static llvm::Constant *getReThrowFn(CodeGenModule &CGM) {
// void __cxa_rethrow();
llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGF.VoidTy, /*IsVarArgs=*/false);
+ llvm::FunctionType::get(CGM.VoidTy, /*IsVarArgs=*/false);
- return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow");
+ return CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow");
}
-static llvm::Constant *getGetExceptionPtrFn(CodeGenFunction &CGF) {
+static llvm::Constant *getGetExceptionPtrFn(CodeGenModule &CGM) {
// void *__cxa_get_exception_ptr(void*);
llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGF.Int8PtrTy, CGF.Int8PtrTy, /*IsVarArgs=*/false);
+ llvm::FunctionType::get(CGM.Int8PtrTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);
- return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_get_exception_ptr");
+ return CGM.CreateRuntimeFunction(FTy, "__cxa_get_exception_ptr");
}
-static llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) {
+static llvm::Constant *getBeginCatchFn(CodeGenModule &CGM) {
// void *__cxa_begin_catch(void*);
llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGF.Int8PtrTy, CGF.Int8PtrTy, /*IsVarArgs=*/false);
+ llvm::FunctionType::get(CGM.Int8PtrTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);
- return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch");
+ return CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch");
}
-static llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) {
+static llvm::Constant *getEndCatchFn(CodeGenModule &CGM) {
// void __cxa_end_catch();
llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGF.VoidTy, /*IsVarArgs=*/false);
+ llvm::FunctionType::get(CGM.VoidTy, /*IsVarArgs=*/false);
- return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch");
+ return CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch");
}
-static llvm::Constant *getUnexpectedFn(CodeGenFunction &CGF) {
+static llvm::Constant *getUnexpectedFn(CodeGenModule &CGM) {
// void __cxa_call_unexepcted(void *thrown_exception);
llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGF.VoidTy, CGF.Int8PtrTy, /*IsVarArgs=*/false);
+ llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);
- return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected");
+ return CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected");
}
llvm::Constant *CodeGenFunction::getUnwindResumeFn() {
@@ -114,31 +115,31 @@ llvm::Constant *CodeGenFunction::getUnwindResumeOrRethrowFn() {
return CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow");
}
-static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) {
+static llvm::Constant *getTerminateFn(CodeGenModule &CGM) {
// void __terminate();
llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGF.VoidTy, /*IsVarArgs=*/false);
+ llvm::FunctionType::get(CGM.VoidTy, /*IsVarArgs=*/false);
StringRef name;
// In C++, use std::terminate().
- if (CGF.getLangOpts().CPlusPlus)
+ if (CGM.getLangOpts().CPlusPlus)
name = "_ZSt9terminatev"; // FIXME: mangling!
- else if (CGF.getLangOpts().ObjC1 &&
- CGF.getLangOpts().ObjCRuntime.hasTerminate())
+ else if (CGM.getLangOpts().ObjC1 &&
+ CGM.getLangOpts().ObjCRuntime.hasTerminate())
name = "objc_terminate";
else
name = "abort";
- return CGF.CGM.CreateRuntimeFunction(FTy, name);
+ return CGM.CreateRuntimeFunction(FTy, name);
}
-static llvm::Constant *getCatchallRethrowFn(CodeGenFunction &CGF,
+static llvm::Constant *getCatchallRethrowFn(CodeGenModule &CGM,
StringRef Name) {
llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGF.VoidTy, CGF.Int8PtrTy, /*IsVarArgs=*/false);
+ llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);
- return CGF.CGM.CreateRuntimeFunction(FTy, Name);
+ return CGM.CreateRuntimeFunction(FTy, Name);
}
namespace {
@@ -155,6 +156,7 @@ namespace {
static const EHPersonality GNU_C;
static const EHPersonality GNU_C_SJLJ;
static const EHPersonality GNU_ObjC;
+ static const EHPersonality GNUstep_ObjC;
static const EHPersonality GNU_ObjCXX;
static const EHPersonality NeXT_ObjC;
static const EHPersonality GNU_CPlusPlus;
@@ -172,6 +174,8 @@ const EHPersonality
EHPersonality::GNU_ObjC = {"__gnu_objc_personality_v0", "objc_exception_throw"};
const EHPersonality
EHPersonality::GNU_ObjCXX = { "__gnustep_objcxx_personality_v0", 0 };
+const EHPersonality
+EHPersonality::GNUstep_ObjC = { "__gnustep_objc_personality_v0", 0 };
static const EHPersonality &getCPersonality(const LangOptions &L) {
if (L.SjLjExceptions)
@@ -187,6 +191,9 @@ static const EHPersonality &getObjCPersonality(const LangOptions &L) {
case ObjCRuntime::iOS:
return EHPersonality::NeXT_ObjC;
case ObjCRuntime::GNUstep:
+ if (L.ObjCRuntime.getVersion() >= VersionTuple(1, 7))
+ return EHPersonality::GNUstep_ObjC;
+ // fallthrough
case ObjCRuntime::GCC:
case ObjCRuntime::ObjFW:
return EHPersonality::GNU_ObjC;
@@ -357,8 +364,7 @@ namespace {
llvm::Value *exn;
FreeException(llvm::Value *exn) : exn(exn) {}
void Emit(CodeGenFunction &CGF, Flags flags) {
- CGF.Builder.CreateCall(getFreeExceptionFn(CGF), exn)
- ->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(getFreeExceptionFn(CGF.CGM), exn);
}
};
}
@@ -415,15 +421,8 @@ llvm::Value *CodeGenFunction::getSelectorFromSlot() {
void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
if (!E->getSubExpr()) {
- if (getInvokeDest()) {
- Builder.CreateInvoke(getReThrowFn(*this),
- getUnreachableBlock(),
- getInvokeDest())
- ->setDoesNotReturn();
- } else {
- Builder.CreateCall(getReThrowFn(*this))->setDoesNotReturn();
- Builder.CreateUnreachable();
- }
+ EmitNoreturnRuntimeCallOrInvoke(getReThrowFn(CGM),
+ ArrayRef<llvm::Value*>());
// throw is an expression, and the expression emitters expect us
// to leave ourselves at a valid insertion point.
@@ -434,16 +433,26 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
QualType ThrowType = E->getSubExpr()->getType();
+ if (ThrowType->isObjCObjectPointerType()) {
+ const Stmt *ThrowStmt = E->getSubExpr();
+ const ObjCAtThrowStmt S(E->getExprLoc(),
+ const_cast<Stmt *>(ThrowStmt));
+ CGM.getObjCRuntime().EmitThrowStmt(*this, S, false);
+ // This will clear insertion point which was not cleared in
+ // call to EmitThrowStmt.
+ EmitBlock(createBasicBlock("throw.cont"));
+ return;
+ }
+
// Now allocate the exception object.
llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
uint64_t TypeSize = getContext().getTypeSizeInChars(ThrowType).getQuantity();
- llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(*this);
+ llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(CGM);
llvm::CallInst *ExceptionPtr =
- Builder.CreateCall(AllocExceptionFn,
- llvm::ConstantInt::get(SizeTy, TypeSize),
- "exception");
- ExceptionPtr->setDoesNotThrow();
+ EmitNounwindRuntimeCall(AllocExceptionFn,
+ llvm::ConstantInt::get(SizeTy, TypeSize),
+ "exception");
EmitAnyExprToExn(*this, E->getSubExpr(), ExceptionPtr);
@@ -464,18 +473,8 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
}
if (!Dtor) Dtor = llvm::Constant::getNullValue(Int8PtrTy);
- if (getInvokeDest()) {
- llvm::InvokeInst *ThrowCall =
- Builder.CreateInvoke3(getThrowFn(*this),
- getUnreachableBlock(), getInvokeDest(),
- ExceptionPtr, TypeInfo, Dtor);
- ThrowCall->setDoesNotReturn();
- } else {
- llvm::CallInst *ThrowCall =
- Builder.CreateCall3(getThrowFn(*this), ExceptionPtr, TypeInfo, Dtor);
- ThrowCall->setDoesNotReturn();
- Builder.CreateUnreachable();
- }
+ llvm::Value *args[] = { ExceptionPtr, TypeInfo, Dtor };
+ EmitNoreturnRuntimeCallOrInvoke(getThrowFn(CGM), args);
// throw is an expression, and the expression emitters expect us
// to leave ourselves at a valid insertion point.
@@ -545,7 +544,7 @@ static void emitFilterDispatchBlock(CodeGenFunction &CGF,
// according to the last landing pad the exception was thrown
// into. Seriously.
llvm::Value *exn = CGF.getExceptionFromSlot();
- CGF.Builder.CreateCall(getUnexpectedFn(CGF), exn)
+ CGF.EmitRuntimeCall(getUnexpectedFn(CGF.CGM), exn)
->setDoesNotReturn();
CGF.Builder.CreateUnreachable();
}
@@ -853,7 +852,7 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
// Create a filter expression: a constant array indicating which filter
// types there are. The personality routine only lands here if the filter
// doesn't match.
- llvm::SmallVector<llvm::Constant*, 8> Filters;
+ SmallVector<llvm::Constant*, 8> Filters;
llvm::ArrayType *AType =
llvm::ArrayType::get(!filterTypes.empty() ?
filterTypes[0]->getType() : Int8PtrTy,
@@ -907,11 +906,11 @@ namespace {
void Emit(CodeGenFunction &CGF, Flags flags) {
if (!MightThrow) {
- CGF.Builder.CreateCall(getEndCatchFn(CGF))->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(getEndCatchFn(CGF.CGM));
return;
}
- CGF.EmitCallOrInvoke(getEndCatchFn(CGF));
+ CGF.EmitRuntimeCallOrInvoke(getEndCatchFn(CGF.CGM));
}
};
}
@@ -923,12 +922,12 @@ namespace {
static llvm::Value *CallBeginCatch(CodeGenFunction &CGF,
llvm::Value *Exn,
bool EndMightThrow) {
- llvm::CallInst *Call = CGF.Builder.CreateCall(getBeginCatchFn(CGF), Exn);
- Call->setDoesNotThrow();
+ llvm::CallInst *call =
+ CGF.EmitNounwindRuntimeCall(getBeginCatchFn(CGF.CGM), Exn);
CGF.EHStack.pushCleanup<CallEndCatch>(NormalAndEHCleanup, EndMightThrow);
- return Call;
+ return call;
}
/// A "special initializer" callback for initializing a catch
@@ -1003,10 +1002,9 @@ static void InitCatchParam(CodeGenFunction &CGF,
return;
}
- // Non-aggregates (plus complexes).
- bool IsComplex = false;
- if (!CGF.hasAggregateLLVMType(CatchType) ||
- (IsComplex = CatchType->isAnyComplexType())) {
+ // Scalars and complexes.
+ TypeEvaluationKind TEK = CGF.getEvaluationKind(CatchType);
+ if (TEK != TEK_Aggregate) {
llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn, false);
// If the catch type is a pointer type, __cxa_begin_catch returns
@@ -1038,17 +1036,23 @@ static void InitCatchParam(CodeGenFunction &CGF,
llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok
llvm::Value *Cast = CGF.Builder.CreateBitCast(AdjustedExn, PtrTy);
- if (IsComplex) {
- CGF.StoreComplexToAddr(CGF.LoadComplexFromAddr(Cast, /*volatile*/ false),
- ParamAddr, /*volatile*/ false);
- } else {
- unsigned Alignment =
- CGF.getContext().getDeclAlign(&CatchParam).getQuantity();
- llvm::Value *ExnLoad = CGF.Builder.CreateLoad(Cast, "exn.scalar");
- CGF.EmitStoreOfScalar(ExnLoad, ParamAddr, /*volatile*/ false, Alignment,
- CatchType);
+ LValue srcLV = CGF.MakeNaturalAlignAddrLValue(Cast, CatchType);
+ LValue destLV = CGF.MakeAddrLValue(ParamAddr, CatchType,
+ CGF.getContext().getDeclAlign(&CatchParam));
+ switch (TEK) {
+ case TEK_Complex:
+ CGF.EmitStoreOfComplex(CGF.EmitLoadOfComplex(srcLV), destLV,
+ /*init*/ true);
+ return;
+ case TEK_Scalar: {
+ llvm::Value *ExnLoad = CGF.EmitLoadOfScalar(srcLV);
+ CGF.EmitStoreOfScalar(ExnLoad, destLV, /*init*/ true);
+ return;
}
- return;
+ case TEK_Aggregate:
+ llvm_unreachable("evaluation kind filtered out!");
+ }
+ llvm_unreachable("bad evaluation kind");
}
assert(isa<RecordType>(CatchType) && "unexpected catch type!");
@@ -1068,8 +1072,7 @@ static void InitCatchParam(CodeGenFunction &CGF,
// We have to call __cxa_get_exception_ptr to get the adjusted
// pointer before copying.
llvm::CallInst *rawAdjustedExn =
- CGF.Builder.CreateCall(getGetExceptionPtrFn(CGF), Exn);
- rawAdjustedExn->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(getGetExceptionPtrFn(CGF.CGM), Exn);
// Cast that to the appropriate type.
llvm::Value *adjustedExn = CGF.Builder.CreateBitCast(rawAdjustedExn, PtrTy);
@@ -1292,7 +1295,7 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {
// constructor function-try-block's catch handler (p14), so this
// really only applies to destructors.
if (doImplicitRethrow && HaveInsertPoint()) {
- EmitCallOrInvoke(getReThrowFn(*this));
+ EmitRuntimeCallOrInvoke(getReThrowFn(CGM));
Builder.CreateUnreachable();
Builder.ClearInsertionPoint();
}
@@ -1324,7 +1327,7 @@ namespace {
CGF.Builder.CreateLoad(ForEHVar, "finally.endcatch");
CGF.Builder.CreateCondBr(ShouldEndCatch, EndCatchBB, CleanupContBB);
CGF.EmitBlock(EndCatchBB);
- CGF.EmitCallOrInvoke(EndCatchFn); // catch-all, so might throw
+ CGF.EmitRuntimeCallOrInvoke(EndCatchFn); // catch-all, so might throw
CGF.EmitBlock(CleanupContBB);
}
};
@@ -1369,9 +1372,10 @@ namespace {
CGF.EmitBlock(RethrowBB);
if (SavedExnVar) {
- CGF.EmitCallOrInvoke(RethrowFn, CGF.Builder.CreateLoad(SavedExnVar));
+ CGF.EmitRuntimeCallOrInvoke(RethrowFn,
+ CGF.Builder.CreateLoad(SavedExnVar));
} else {
- CGF.EmitCallOrInvoke(RethrowFn);
+ CGF.EmitRuntimeCallOrInvoke(RethrowFn);
}
CGF.Builder.CreateUnreachable();
@@ -1476,7 +1480,7 @@ void CodeGenFunction::FinallyInfo::exit(CodeGenFunction &CGF) {
// If there's a begin-catch function, call it.
if (BeginCatchFn) {
exn = CGF.getExceptionFromSlot();
- CGF.Builder.CreateCall(BeginCatchFn, exn)->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(BeginCatchFn, exn);
}
// If we need to remember the exception pointer to rethrow later, do so.
@@ -1498,6 +1502,68 @@ void CodeGenFunction::FinallyInfo::exit(CodeGenFunction &CGF) {
CGF.PopCleanupBlock();
}
+/// In a terminate landing pad, should we use __clang__call_terminate
+/// or just a naked call to std::terminate?
+///
+/// __clang_call_terminate calls __cxa_begin_catch, which then allows
+/// std::terminate to usefully report something about the
+/// violating exception.
+static bool useClangCallTerminate(CodeGenModule &CGM) {
+ // Only do this for Itanium-family ABIs in C++ mode.
+ return (CGM.getLangOpts().CPlusPlus &&
+ CGM.getTarget().getCXXABI().isItaniumFamily());
+}
+
+/// Get or define the following function:
+/// void @__clang_call_terminate(i8* %exn) nounwind noreturn
+/// This code is used only in C++.
+static llvm::Constant *getClangCallTerminateFn(CodeGenModule &CGM) {
+ llvm::FunctionType *fnTy =
+ llvm::FunctionType::get(CGM.VoidTy, CGM.Int8PtrTy, /*IsVarArgs=*/false);
+ llvm::Constant *fnRef =
+ CGM.CreateRuntimeFunction(fnTy, "__clang_call_terminate");
+
+ llvm::Function *fn = dyn_cast<llvm::Function>(fnRef);
+ if (fn && fn->empty()) {
+ fn->setDoesNotThrow();
+ fn->setDoesNotReturn();
+
+ // What we really want is to massively penalize inlining without
+ // forbidding it completely. The difference between that and
+ // 'noinline' is negligible.
+ fn->addFnAttr(llvm::Attribute::NoInline);
+
+ // Allow this function to be shared across translation units, but
+ // we don't want it to turn into an exported symbol.
+ fn->setLinkage(llvm::Function::LinkOnceODRLinkage);
+ fn->setVisibility(llvm::Function::HiddenVisibility);
+
+ // Set up the function.
+ llvm::BasicBlock *entry =
+ llvm::BasicBlock::Create(CGM.getLLVMContext(), "", fn);
+ CGBuilderTy builder(entry);
+
+ // Pull the exception pointer out of the parameter list.
+ llvm::Value *exn = &*fn->arg_begin();
+
+ // Call __cxa_begin_catch(exn).
+ llvm::CallInst *catchCall = builder.CreateCall(getBeginCatchFn(CGM), exn);
+ catchCall->setDoesNotThrow();
+ catchCall->setCallingConv(CGM.getRuntimeCC());
+
+ // Call std::terminate().
+ llvm::CallInst *termCall = builder.CreateCall(getTerminateFn(CGM));
+ termCall->setDoesNotThrow();
+ termCall->setDoesNotReturn();
+ termCall->setCallingConv(CGM.getRuntimeCC());
+
+ // std::terminate cannot return.
+ builder.CreateUnreachable();
+ }
+
+ return fnRef;
+}
+
llvm::BasicBlock *CodeGenFunction::getTerminateLandingPad() {
if (TerminateLandingPad)
return TerminateLandingPad;
@@ -1515,9 +1581,15 @@ llvm::BasicBlock *CodeGenFunction::getTerminateLandingPad() {
getOpaquePersonalityFn(CGM, Personality), 0);
LPadInst->addClause(getCatchAllValue(*this));
- llvm::CallInst *TerminateCall = Builder.CreateCall(getTerminateFn(*this));
- TerminateCall->setDoesNotReturn();
- TerminateCall->setDoesNotThrow();
+ llvm::CallInst *terminateCall;
+ if (useClangCallTerminate(CGM)) {
+ // Extract out the exception pointer.
+ llvm::Value *exn = Builder.CreateExtractValue(LPadInst, 0);
+ terminateCall = EmitNounwindRuntimeCall(getClangCallTerminateFn(CGM), exn);
+ } else {
+ terminateCall = EmitNounwindRuntimeCall(getTerminateFn(CGM));
+ }
+ terminateCall->setDoesNotReturn();
Builder.CreateUnreachable();
// Restore the saved insertion state.
@@ -1536,9 +1608,8 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() {
// end of the function by FinishFunction.
TerminateHandler = createBasicBlock("terminate.handler");
Builder.SetInsertPoint(TerminateHandler);
- llvm::CallInst *TerminateCall = Builder.CreateCall(getTerminateFn(*this));
+ llvm::CallInst *TerminateCall = EmitNounwindRuntimeCall(getTerminateFn(CGM));
TerminateCall->setDoesNotReturn();
- TerminateCall->setDoesNotThrow();
Builder.CreateUnreachable();
// Restore the saved insertion state.
@@ -1562,8 +1633,8 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) {
// anything on the EH stack which needs our help.
const char *RethrowName = Personality.CatchallRethrowFn;
if (RethrowName != 0 && !isCleanup) {
- Builder.CreateCall(getCatchallRethrowFn(*this, RethrowName),
- getExceptionFromSlot())
+ EmitRuntimeCall(getCatchallRethrowFn(CGM, RethrowName),
+ getExceptionFromSlot())
->setDoesNotReturn();
} else {
switch (CleanupHackLevel) {
@@ -1571,8 +1642,8 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) {
// In mandatory-catchall mode, we need to use
// _Unwind_Resume_or_Rethrow, or whatever the personality's
// equivalent is.
- Builder.CreateCall(getUnwindResumeOrRethrowFn(),
- getExceptionFromSlot())
+ EmitRuntimeCall(getUnwindResumeOrRethrowFn(),
+ getExceptionFromSlot())
->setDoesNotReturn();
break;
case CHL_MandatoryCleanup: {
@@ -1596,7 +1667,7 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) {
// In an idealized mode where we don't have to worry about the
// optimizer combining landing pads, we should just use
// _Unwind_Resume (or the personality's equivalent).
- Builder.CreateCall(getUnwindResumeFn(), getExceptionFromSlot())
+ EmitRuntimeCall(getUnwindResumeFn(), getExceptionFromSlot())
->setDoesNotReturn();
break;
}
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 63cc5b5..2f5186d 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -12,22 +12,23 @@
//===----------------------------------------------------------------------===//
#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
-#include "CGCall.h"
#include "CGCXXABI.h"
+#include "CGCall.h"
#include "CGDebugInfo.h"
-#include "CGRecordLayout.h"
#include "CGObjCRuntime.h"
+#include "CGRecordLayout.h"
+#include "CodeGenModule.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
-#include "clang/Basic/ConvertUTF.h"
#include "clang/Frontend/CodeGenOptions.h"
-#include "llvm/Intrinsics.h"
-#include "llvm/LLVMContext.h"
-#include "llvm/MDBuilder.h"
-#include "llvm/DataLayout.h"
#include "llvm/ADT/Hashing.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/MDBuilder.h"
+#include "llvm/Support/ConvertUTF.h"
+
using namespace clang;
using namespace CodeGen;
@@ -113,15 +114,18 @@ void CodeGenFunction::EmitIgnoredExpr(const Expr *E) {
RValue CodeGenFunction::EmitAnyExpr(const Expr *E,
AggValueSlot aggSlot,
bool ignoreResult) {
- if (!hasAggregateLLVMType(E->getType()))
+ switch (getEvaluationKind(E->getType())) {
+ case TEK_Scalar:
return RValue::get(EmitScalarExpr(E, ignoreResult));
- else if (E->getType()->isAnyComplexType())
+ case TEK_Complex:
return RValue::getComplex(EmitComplexExpr(E, ignoreResult, ignoreResult));
-
- if (!ignoreResult && aggSlot.isIgnored())
- aggSlot = CreateAggTemp(E->getType(), "agg-temp");
- EmitAggExpr(E, aggSlot);
- return aggSlot.asRValue();
+ case TEK_Aggregate:
+ if (!ignoreResult && aggSlot.isIgnored())
+ aggSlot = CreateAggTemp(E->getType(), "agg-temp");
+ EmitAggExpr(E, aggSlot);
+ return aggSlot.asRValue();
+ }
+ llvm_unreachable("bad evaluation kind");
}
/// EmitAnyExprToTemp - Similary to EmitAnyExpr(), however, the result will
@@ -129,8 +133,7 @@ RValue CodeGenFunction::EmitAnyExpr(const Expr *E,
RValue CodeGenFunction::EmitAnyExprToTemp(const Expr *E) {
AggValueSlot AggSlot = AggValueSlot::ignored();
- if (hasAggregateLLVMType(E->getType()) &&
- !E->getType()->isAnyComplexType())
+ if (hasAggregateEvaluationKind(E->getType()))
AggSlot = CreateAggTemp(E->getType(), "agg.tmp");
return EmitAnyExpr(E, AggSlot);
}
@@ -142,19 +145,30 @@ void CodeGenFunction::EmitAnyExprToMem(const Expr *E,
Qualifiers Quals,
bool IsInit) {
// FIXME: This function should take an LValue as an argument.
- if (E->getType()->isAnyComplexType()) {
- EmitComplexExprIntoAddr(E, Location, Quals.hasVolatile());
- } else if (hasAggregateLLVMType(E->getType())) {
+ switch (getEvaluationKind(E->getType())) {
+ case TEK_Complex:
+ EmitComplexExprIntoLValue(E,
+ MakeNaturalAlignAddrLValue(Location, E->getType()),
+ /*isInit*/ false);
+ return;
+
+ case TEK_Aggregate: {
CharUnits Alignment = getContext().getTypeAlignInChars(E->getType());
EmitAggExpr(E, AggValueSlot::forAddr(Location, Alignment, Quals,
AggValueSlot::IsDestructed_t(IsInit),
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsAliased_t(!IsInit)));
- } else {
+ return;
+ }
+
+ case TEK_Scalar: {
RValue RV = RValue::get(EmitScalarExpr(E, /*Ignore*/ false));
LValue LV = MakeAddrLValue(Location, E->getType());
EmitStoreThroughLValue(RV, LV);
+ return;
+ }
}
+ llvm_unreachable("bad evaluation kind");
}
static llvm::Value *
@@ -287,8 +301,7 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
// Create a reference temporary if necessary.
AggValueSlot AggSlot = AggValueSlot::ignored();
- if (CGF.hasAggregateLLVMType(E->getType()) &&
- !E->getType()->isAnyComplexType()) {
+ if (CGF.hasAggregateEvaluationKind(E->getType())) {
ReferenceTemporary = CreateReferenceTemporary(CGF, E->getType(),
InitializedDecl);
CharUnits Alignment = CGF.getContext().getTypeAlignInChars(E->getType());
@@ -302,7 +315,8 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
if (InitializedDecl) {
// Get the destructor for the reference temporary.
- if (const RecordType *RT = E->getType()->getAs<RecordType>()) {
+ if (const RecordType *RT =
+ E->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()) {
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RT->getDecl());
if (!ClassDecl->hasTrivialDestructor())
ReferenceTemporaryDtor = ClassDecl->getDestructor();
@@ -368,14 +382,12 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
InitializedDecl);
- unsigned Alignment =
- CGF.getContext().getTypeAlignInChars(E->getType()).getQuantity();
+ LValue tempLV = CGF.MakeNaturalAlignAddrLValue(ReferenceTemporary,
+ E->getType());
if (RV.isScalar())
- CGF.EmitStoreOfScalar(RV.getScalarVal(), ReferenceTemporary,
- /*Volatile=*/false, Alignment, E->getType());
+ CGF.EmitStoreOfScalar(RV.getScalarVal(), tempLV, /*init*/ true);
else
- CGF.StoreComplexToAddr(RV.getComplexVal(), ReferenceTemporary,
- /*Volatile=*/false);
+ CGF.EmitStoreOfComplex(RV.getComplexVal(), tempLV, /*init*/ true);
return ReferenceTemporary;
}
@@ -405,10 +417,19 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E,
const VarDecl *VD = dyn_cast_or_null<VarDecl>(InitializedDecl);
if (VD && VD->hasGlobalStorage()) {
if (ReferenceTemporaryDtor) {
- llvm::Constant *DtorFn =
- CGM.GetAddrOfCXXDestructor(ReferenceTemporaryDtor, Dtor_Complete);
- CGM.getCXXABI().registerGlobalDtor(*this, DtorFn,
- cast<llvm::Constant>(ReferenceTemporary));
+ llvm::Constant *CleanupFn;
+ llvm::Constant *CleanupArg;
+ if (E->getType()->isArrayType()) {
+ CleanupFn = CodeGenFunction(CGM).generateDestroyHelper(
+ cast<llvm::Constant>(ReferenceTemporary), E->getType(),
+ destroyCXXObject, getLangOpts().Exceptions);
+ CleanupArg = llvm::Constant::getNullValue(Int8PtrTy);
+ } else {
+ CleanupFn =
+ CGM.GetAddrOfCXXDestructor(ReferenceTemporaryDtor, Dtor_Complete);
+ CleanupArg = cast<llvm::Constant>(ReferenceTemporary);
+ }
+ CGM.getCXXABI().registerGlobalDtor(*this, CleanupFn, CleanupArg);
} else {
assert(!ObjCARCReferenceLifetimeType.isNull());
// Note: We intentionally do not register a global "destructor" to
@@ -418,9 +439,13 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E,
return RValue::get(Value);
}
- if (ReferenceTemporaryDtor)
- PushDestructorCleanup(ReferenceTemporaryDtor, ReferenceTemporary);
- else {
+ if (ReferenceTemporaryDtor) {
+ if (E->getType()->isArrayType())
+ pushDestroy(NormalAndEHCleanup, ReferenceTemporary, E->getType(),
+ destroyCXXObject, getLangOpts().Exceptions);
+ else
+ PushDestructorCleanup(ReferenceTemporaryDtor, ReferenceTemporary);
+ } else {
switch (ObjCARCReferenceLifetimeType.getObjCLifetime()) {
case Qualifiers::OCL_None:
llvm_unreachable(
@@ -486,14 +511,25 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
return;
llvm::Value *Cond = 0;
+ llvm::BasicBlock *Done = 0;
- if (getLangOpts().SanitizeNull) {
+ if (SanOpts->Null) {
// The glvalue must not be an empty glvalue.
Cond = Builder.CreateICmpNE(
Address, llvm::Constant::getNullValue(Address->getType()));
+
+ if (TCK == TCK_DowncastPointer) {
+ // When performing a pointer downcast, it's OK if the value is null.
+ // Skip the remaining checks in that case.
+ Done = createBasicBlock("null");
+ llvm::BasicBlock *Rest = createBasicBlock("not.null");
+ Builder.CreateCondBr(Cond, Rest, Done);
+ EmitBlock(Rest);
+ Cond = 0;
+ }
}
- if (getLangOpts().SanitizeObjectSize && !Ty->isIncompleteType()) {
+ if (SanOpts->ObjectSize && !Ty->isIncompleteType()) {
uint64_t Size = getContext().getTypeSizeInChars(Ty).getQuantity();
// The glvalue must refer to a large enough storage region.
@@ -510,7 +546,7 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
uint64_t AlignVal = 0;
- if (getLangOpts().SanitizeAlignment) {
+ if (SanOpts->Alignment) {
AlignVal = Alignment.getQuantity();
if (!Ty->isIncompleteType() && !AlignVal)
AlignVal = getContext().getTypeAlignInChars(Ty).getQuantity();
@@ -533,20 +569,28 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
llvm::ConstantInt::get(SizeTy, AlignVal),
llvm::ConstantInt::get(Int8Ty, TCK)
};
- EmitCheck(Cond, "type_mismatch", StaticData, Address);
+ EmitCheck(Cond, "type_mismatch", StaticData, Address, CRK_Recoverable);
}
// If possible, check that the vptr indicates that there is a subobject of
// type Ty at offset zero within this object.
+ //
+ // C++11 [basic.life]p5,6:
+ // [For storage which does not refer to an object within its lifetime]
+ // The program has undefined behavior if:
+ // -- the [pointer or glvalue] is used to access a non-static data member
+ // or call a non-static member function
CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
- if (getLangOpts().SanitizeVptr && TCK != TCK_ConstructorCall &&
+ if (SanOpts->Vptr &&
+ (TCK == TCK_MemberAccess || TCK == TCK_MemberCall ||
+ TCK == TCK_DowncastPointer || TCK == TCK_DowncastReference) &&
RD && RD->hasDefinition() && RD->isDynamicClass()) {
// Compute a hash of the mangled name of the type.
//
// FIXME: This is not guaranteed to be deterministic! Move to a
// fingerprinting mechanism once LLVM provides one. For the time
// being the implementation happens to be deterministic.
- llvm::SmallString<64> MangledName;
+ SmallString<64> MangledName;
llvm::raw_svector_ostream Out(MangledName);
CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty.getUnqualifiedType(),
Out);
@@ -586,16 +630,100 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc,
};
llvm::Value *DynamicData[] = { Address, Hash };
EmitCheck(Builder.CreateICmpEQ(CacheVal, Hash),
- "dynamic_type_cache_miss", StaticData, DynamicData, true);
+ "dynamic_type_cache_miss", StaticData, DynamicData,
+ CRK_AlwaysRecoverable);
+ }
+
+ if (Done) {
+ Builder.CreateBr(Done);
+ EmitBlock(Done);
+ }
+}
+
+/// Determine whether this expression refers to a flexible array member in a
+/// struct. We disable array bounds checks for such members.
+static bool isFlexibleArrayMemberExpr(const Expr *E) {
+ // For compatibility with existing code, we treat arrays of length 0 or
+ // 1 as flexible array members.
+ const ArrayType *AT = E->getType()->castAsArrayTypeUnsafe();
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) {
+ if (CAT->getSize().ugt(1))
+ return false;
+ } else if (!isa<IncompleteArrayType>(AT))
+ return false;
+
+ E = E->IgnoreParens();
+
+ // A flexible array member must be the last member in the class.
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+ // FIXME: If the base type of the member expr is not FD->getParent(),
+ // this should not be treated as a flexible array member access.
+ if (const FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
+ RecordDecl::field_iterator FI(
+ DeclContext::decl_iterator(const_cast<FieldDecl *>(FD)));
+ return ++FI == FD->getParent()->field_end();
+ }
+ }
+
+ return false;
+}
+
+/// If Base is known to point to the start of an array, return the length of
+/// that array. Return 0 if the length cannot be determined.
+static llvm::Value *getArrayIndexingBound(
+ CodeGenFunction &CGF, const Expr *Base, QualType &IndexedType) {
+ // For the vector indexing extension, the bound is the number of elements.
+ if (const VectorType *VT = Base->getType()->getAs<VectorType>()) {
+ IndexedType = Base->getType();
+ return CGF.Builder.getInt32(VT->getNumElements());
+ }
+
+ Base = Base->IgnoreParens();
+
+ if (const CastExpr *CE = dyn_cast<CastExpr>(Base)) {
+ if (CE->getCastKind() == CK_ArrayToPointerDecay &&
+ !isFlexibleArrayMemberExpr(CE->getSubExpr())) {
+ IndexedType = CE->getSubExpr()->getType();
+ const ArrayType *AT = IndexedType->castAsArrayTypeUnsafe();
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT))
+ return CGF.Builder.getInt(CAT->getSize());
+ else if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(AT))
+ return CGF.getVLASize(VAT).first;
+ }
}
+
+ return 0;
+}
+
+void CodeGenFunction::EmitBoundsCheck(const Expr *E, const Expr *Base,
+ llvm::Value *Index, QualType IndexType,
+ bool Accessed) {
+ assert(SanOpts->Bounds && "should not be called unless adding bounds checks");
+
+ QualType IndexedType;
+ llvm::Value *Bound = getArrayIndexingBound(*this, Base, IndexedType);
+ if (!Bound)
+ return;
+
+ bool IndexSigned = IndexType->isSignedIntegerOrEnumerationType();
+ llvm::Value *IndexVal = Builder.CreateIntCast(Index, SizeTy, IndexSigned);
+ llvm::Value *BoundVal = Builder.CreateIntCast(Bound, SizeTy, false);
+
+ llvm::Constant *StaticData[] = {
+ EmitCheckSourceLocation(E->getExprLoc()),
+ EmitCheckTypeDescriptor(IndexedType),
+ EmitCheckTypeDescriptor(IndexType)
+ };
+ llvm::Value *Check = Accessed ? Builder.CreateICmpULT(IndexVal, BoundVal)
+ : Builder.CreateICmpULE(IndexVal, BoundVal);
+ EmitCheck(Check, "out_of_bounds", StaticData, Index, CRK_Recoverable);
}
CodeGenFunction::ComplexPairTy CodeGenFunction::
EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV,
bool isInc, bool isPre) {
- ComplexPairTy InVal = LoadComplexFromAddr(LV.getAddress(),
- LV.isVolatileQualified());
+ ComplexPairTy InVal = EmitLoadOfComplex(LV);
llvm::Value *NextVal;
if (isa<llvm::IntegerType>(InVal.first->getType())) {
@@ -618,7 +746,7 @@ EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV,
ComplexPairTy IncVal(NextVal, InVal.second);
// Store the updated result through the lvalue.
- StoreComplexToAddr(IncVal, LV.getAddress(), LV.isVolatileQualified());
+ EmitStoreOfComplex(IncVal, LV, /*init*/ false);
// If this is a postinc, return the value read from memory, otherwise use the
// updated value.
@@ -633,9 +761,11 @@ EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV,
RValue CodeGenFunction::GetUndefRValue(QualType Ty) {
if (Ty->isVoidType())
return RValue::get(0);
-
- if (const ComplexType *CTy = Ty->getAs<ComplexType>()) {
- llvm::Type *EltTy = ConvertType(CTy->getElementType());
+
+ switch (getEvaluationKind(Ty)) {
+ case TEK_Complex: {
+ llvm::Type *EltTy =
+ ConvertType(Ty->castAs<ComplexType>()->getElementType());
llvm::Value *U = llvm::UndefValue::get(EltTy);
return RValue::getComplex(std::make_pair(U, U));
}
@@ -643,12 +773,15 @@ RValue CodeGenFunction::GetUndefRValue(QualType Ty) {
// If this is a use of an undefined aggregate type, the aggregate must have an
// identifiable address. Just because the contents of the value are undefined
// doesn't mean that the address can't be taken and compared.
- if (hasAggregateLLVMType(Ty)) {
+ case TEK_Aggregate: {
llvm::Value *DestPtr = CreateMemTemp(Ty, "undef.agg.tmp");
return RValue::getAggregate(DestPtr);
}
-
- return RValue::get(llvm::UndefValue::get(ConvertType(Ty)));
+
+ case TEK_Scalar:
+ return RValue::get(llvm::UndefValue::get(ConvertType(Ty)));
+ }
+ llvm_unreachable("bad evaluation kind");
}
RValue CodeGenFunction::EmitUnsupportedRValue(const Expr *E,
@@ -665,7 +798,11 @@ LValue CodeGenFunction::EmitUnsupportedLValue(const Expr *E,
}
LValue CodeGenFunction::EmitCheckedLValue(const Expr *E, TypeCheckKind TCK) {
- LValue LV = EmitLValue(E);
+ LValue LV;
+ if (SanOpts->Bounds && isa<ArraySubscriptExpr>(E))
+ LV = EmitArraySubscriptExpr(cast<ArraySubscriptExpr>(E), /*Accessed*/true);
+ else
+ LV = EmitLValue(E);
if (!isa<DeclRefExpr>(E) && !LV.isBitField() && LV.isSimple())
EmitTypeCheck(TCK, E->getExprLoc(), LV.getAddress(),
E->getType(), LV.getAlignment());
@@ -907,7 +1044,8 @@ CodeGenFunction::tryEmitAsConstant(DeclRefExpr *refExpr) {
llvm::Value *CodeGenFunction::EmitLoadOfScalar(LValue lvalue) {
return EmitLoadOfScalar(lvalue.getAddress(), lvalue.isVolatile(),
lvalue.getAlignment().getQuantity(),
- lvalue.getType(), lvalue.getTBAAInfo());
+ lvalue.getType(), lvalue.getTBAAInfo(),
+ lvalue.getTBAABaseType(), lvalue.getTBAAOffset());
}
static bool hasBooleanRepresentation(QualType Ty) {
@@ -923,23 +1061,22 @@ static bool hasBooleanRepresentation(QualType Ty) {
return false;
}
-llvm::MDNode *CodeGenFunction::getRangeForLoadFromType(QualType Ty) {
+static bool getRangeForType(CodeGenFunction &CGF, QualType Ty,
+ llvm::APInt &Min, llvm::APInt &End,
+ bool StrictEnums) {
const EnumType *ET = Ty->getAs<EnumType>();
- bool IsRegularCPlusPlusEnum = (getLangOpts().CPlusPlus && ET &&
- CGM.getCodeGenOpts().StrictEnums &&
- !ET->getDecl()->isFixed());
+ bool IsRegularCPlusPlusEnum = CGF.getLangOpts().CPlusPlus && StrictEnums &&
+ ET && !ET->getDecl()->isFixed();
bool IsBool = hasBooleanRepresentation(Ty);
if (!IsBool && !IsRegularCPlusPlusEnum)
- return NULL;
+ return false;
- llvm::APInt Min;
- llvm::APInt End;
if (IsBool) {
- Min = llvm::APInt(8, 0);
- End = llvm::APInt(8, 2);
+ Min = llvm::APInt(CGF.getContext().getTypeSize(Ty), 0);
+ End = llvm::APInt(CGF.getContext().getTypeSize(Ty), 2);
} else {
const EnumDecl *ED = ET->getDecl();
- llvm::Type *LTy = ConvertTypeForMem(ED->getIntegerType());
+ llvm::Type *LTy = CGF.ConvertTypeForMem(ED->getIntegerType());
unsigned Bitwidth = LTy->getScalarSizeInBits();
unsigned NumNegativeBits = ED->getNumNegativeBits();
unsigned NumPositiveBits = ED->getNumPositiveBits();
@@ -955,6 +1092,14 @@ llvm::MDNode *CodeGenFunction::getRangeForLoadFromType(QualType Ty) {
Min = llvm::APInt(Bitwidth, 0);
}
}
+ return true;
+}
+
+llvm::MDNode *CodeGenFunction::getRangeForLoadFromType(QualType Ty) {
+ llvm::APInt Min, End;
+ if (!getRangeForType(*this, Ty, Min, End,
+ CGM.getCodeGenOpts().StrictEnums))
+ return 0;
llvm::MDBuilder MDHelper(getLLVMContext());
return MDHelper.createRange(Min, End);
@@ -962,8 +1107,9 @@ llvm::MDNode *CodeGenFunction::getRangeForLoadFromType(QualType Ty) {
llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
unsigned Alignment, QualType Ty,
- llvm::MDNode *TBAAInfo) {
-
+ llvm::MDNode *TBAAInfo,
+ QualType TBAABaseType,
+ uint64_t TBAAOffset) {
// For better performance, handle vector loads differently.
if (Ty->isVectorType()) {
llvm::Value *V;
@@ -986,19 +1132,14 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
"castToVec4");
// Now load value.
llvm::Value *LoadVal = Builder.CreateLoad(Cast, Volatile, "loadVec4");
-
+
// Shuffle vector to get vec3.
- llvm::SmallVector<llvm::Constant*, 3> Mask;
- Mask.push_back(llvm::ConstantInt::get(
- llvm::Type::getInt32Ty(getLLVMContext()),
- 0));
- Mask.push_back(llvm::ConstantInt::get(
- llvm::Type::getInt32Ty(getLLVMContext()),
- 1));
- Mask.push_back(llvm::ConstantInt::get(
- llvm::Type::getInt32Ty(getLLVMContext()),
- 2));
-
+ llvm::Constant *Mask[] = {
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(getLLVMContext()), 0),
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(getLLVMContext()), 1),
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(getLLVMContext()), 2)
+ };
+
llvm::Value *MaskV = llvm::ConstantVector::get(Mask);
V = Builder.CreateShuffleVector(LoadVal,
llvm::UndefValue::get(vec4Ty),
@@ -1006,19 +1147,47 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
return EmitFromMemory(V, Ty);
}
}
+
+ // Atomic operations have to be done on integral types.
+ if (Ty->isAtomicType()) {
+ LValue lvalue = LValue::MakeAddr(Addr, Ty,
+ CharUnits::fromQuantity(Alignment),
+ getContext(), TBAAInfo);
+ return EmitAtomicLoad(lvalue).getScalarVal();
+ }
llvm::LoadInst *Load = Builder.CreateLoad(Addr);
if (Volatile)
Load->setVolatile(true);
if (Alignment)
Load->setAlignment(Alignment);
- if (TBAAInfo)
- CGM.DecorateInstruction(Load, TBAAInfo);
- // If this is an atomic type, all normal reads must be atomic
- if (Ty->isAtomicType())
- Load->setAtomic(llvm::SequentiallyConsistent);
-
- if (CGM.getCodeGenOpts().OptimizationLevel > 0)
+ if (TBAAInfo) {
+ llvm::MDNode *TBAAPath = CGM.getTBAAStructTagInfo(TBAABaseType, TBAAInfo,
+ TBAAOffset);
+ CGM.DecorateInstruction(Load, TBAAPath);
+ }
+
+ if ((SanOpts->Bool && hasBooleanRepresentation(Ty)) ||
+ (SanOpts->Enum && Ty->getAs<EnumType>())) {
+ llvm::APInt Min, End;
+ if (getRangeForType(*this, Ty, Min, End, true)) {
+ --End;
+ llvm::Value *Check;
+ if (!Min)
+ Check = Builder.CreateICmpULE(
+ Load, llvm::ConstantInt::get(getLLVMContext(), End));
+ else {
+ llvm::Value *Upper = Builder.CreateICmpSLE(
+ Load, llvm::ConstantInt::get(getLLVMContext(), End));
+ llvm::Value *Lower = Builder.CreateICmpSGE(
+ Load, llvm::ConstantInt::get(getLLVMContext(), Min));
+ Check = Builder.CreateAnd(Upper, Lower);
+ }
+ // FIXME: Provide a SourceLocation.
+ EmitCheck(Check, "load_invalid_value", EmitCheckTypeDescriptor(Ty),
+ EmitCheckValue(Load), CRK_Recoverable);
+ }
+ } else if (CGM.getCodeGenOpts().OptimizationLevel > 0)
if (llvm::MDNode *RangeInfo = getRangeForLoadFromType(Ty))
Load->setMetadata(llvm::LLVMContext::MD_range, RangeInfo);
@@ -1031,8 +1200,9 @@ llvm::Value *CodeGenFunction::EmitToMemory(llvm::Value *Value, QualType Ty) {
// This should really always be an i1, but sometimes it's already
// an i8, and it's awkward to track those cases down.
if (Value->getType()->isIntegerTy(1))
- return Builder.CreateZExt(Value, Builder.getInt8Ty(), "frombool");
- assert(Value->getType()->isIntegerTy(8) && "value rep of bool not i1/i8");
+ return Builder.CreateZExt(Value, ConvertTypeForMem(Ty), "frombool");
+ assert(Value->getType()->isIntegerTy(getContext().getTypeSize(Ty)) &&
+ "wrong value rep of bool");
}
return Value;
@@ -1041,7 +1211,8 @@ llvm::Value *CodeGenFunction::EmitToMemory(llvm::Value *Value, QualType Ty) {
llvm::Value *CodeGenFunction::EmitFromMemory(llvm::Value *Value, QualType Ty) {
// Bool has a different representation in memory than in registers.
if (hasBooleanRepresentation(Ty)) {
- assert(Value->getType()->isIntegerTy(8) && "memory rep of bool not i8");
+ assert(Value->getType()->isIntegerTy(getContext().getTypeSize(Ty)) &&
+ "wrong value rep of bool");
return Builder.CreateTrunc(Value, Builder.getInt1Ty(), "tobool");
}
@@ -1052,7 +1223,8 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr,
bool Volatile, unsigned Alignment,
QualType Ty,
llvm::MDNode *TBAAInfo,
- bool isInit) {
+ bool isInit, QualType TBAABaseType,
+ uint64_t TBAAOffset) {
// Handle vectors differently to get better performance.
if (Ty->isVectorType()) {
@@ -1063,7 +1235,7 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr,
llvm::LLVMContext &VMContext = getLLVMContext();
// Our source is a vec3, do a shuffle vector to make it a vec4.
- llvm::SmallVector<llvm::Constant*, 4> Mask;
+ SmallVector<llvm::Constant*, 4> Mask;
Mask.push_back(llvm::ConstantInt::get(
llvm::Type::getInt32Ty(VMContext),
0));
@@ -1090,21 +1262,32 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr,
}
Value = EmitToMemory(Value, Ty);
-
+
+ if (Ty->isAtomicType()) {
+ EmitAtomicStore(RValue::get(Value),
+ LValue::MakeAddr(Addr, Ty,
+ CharUnits::fromQuantity(Alignment),
+ getContext(), TBAAInfo),
+ isInit);
+ return;
+ }
+
llvm::StoreInst *Store = Builder.CreateStore(Value, Addr, Volatile);
if (Alignment)
Store->setAlignment(Alignment);
- if (TBAAInfo)
- CGM.DecorateInstruction(Store, TBAAInfo);
- if (!isInit && Ty->isAtomicType())
- Store->setAtomic(llvm::SequentiallyConsistent);
+ if (TBAAInfo) {
+ llvm::MDNode *TBAAPath = CGM.getTBAAStructTagInfo(TBAABaseType, TBAAInfo,
+ TBAAOffset);
+ CGM.DecorateInstruction(Store, TBAAPath);
+ }
}
void CodeGenFunction::EmitStoreOfScalar(llvm::Value *value, LValue lvalue,
- bool isInit) {
+ bool isInit) {
EmitStoreOfScalar(value, lvalue.getAddress(), lvalue.isVolatile(),
lvalue.getAlignment().getQuantity(), lvalue.getType(),
- lvalue.getTBAAInfo(), isInit);
+ lvalue.getTBAAInfo(), isInit, lvalue.getTBAABaseType(),
+ lvalue.getTBAAOffset());
}
/// EmitLoadOfLValue - Given an expression that represents a value lvalue, this
@@ -1117,8 +1300,11 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV) {
return RValue::get(CGM.getObjCRuntime().EmitObjCWeakRead(*this,
AddrWeakObj));
}
- if (LV.getQuals().getObjCLifetime() == Qualifiers::OCL_Weak)
- return RValue::get(EmitARCLoadWeak(LV.getAddress()));
+ if (LV.getQuals().getObjCLifetime() == Qualifiers::OCL_Weak) {
+ llvm::Value *Object = EmitARCLoadWeakRetained(LV.getAddress());
+ Object = EmitObjCConsumeObject(LV.getType(), Object);
+ return RValue::get(Object);
+ }
if (LV.isSimple()) {
assert(!LV.getType()->isFunctionType());
@@ -1149,72 +1335,30 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV) {
// Get the output type.
llvm::Type *ResLTy = ConvertType(LV.getType());
- unsigned ResSizeInBits = CGM.getDataLayout().getTypeSizeInBits(ResLTy);
-
- // Compute the result as an OR of all of the individual component accesses.
- llvm::Value *Res = 0;
- for (unsigned i = 0, e = Info.getNumComponents(); i != e; ++i) {
- const CGBitFieldInfo::AccessInfo &AI = Info.getComponent(i);
- CharUnits AccessAlignment = AI.AccessAlignment;
- if (!LV.getAlignment().isZero())
- AccessAlignment = std::min(AccessAlignment, LV.getAlignment());
-
- // Get the field pointer.
- llvm::Value *Ptr = LV.getBitFieldBaseAddr();
-
- // Only offset by the field index if used, so that incoming values are not
- // required to be structures.
- if (AI.FieldIndex)
- Ptr = Builder.CreateStructGEP(Ptr, AI.FieldIndex, "bf.field");
-
- // Offset by the byte offset, if used.
- if (!AI.FieldByteOffset.isZero()) {
- Ptr = EmitCastToVoidPtr(Ptr);
- Ptr = Builder.CreateConstGEP1_32(Ptr, AI.FieldByteOffset.getQuantity(),
- "bf.field.offs");
- }
-
- // Cast to the access type.
- llvm::Type *PTy = llvm::Type::getIntNPtrTy(getLLVMContext(), AI.AccessWidth,
- CGM.getContext().getTargetAddressSpace(LV.getType()));
- Ptr = Builder.CreateBitCast(Ptr, PTy);
-
- // Perform the load.
- llvm::LoadInst *Load = Builder.CreateLoad(Ptr, LV.isVolatileQualified());
- Load->setAlignment(AccessAlignment.getQuantity());
-
- // Shift out unused low bits and mask out unused high bits.
- llvm::Value *Val = Load;
- if (AI.FieldBitStart)
- Val = Builder.CreateLShr(Load, AI.FieldBitStart);
- Val = Builder.CreateAnd(Val, llvm::APInt::getLowBitsSet(AI.AccessWidth,
- AI.TargetBitWidth),
- "bf.clear");
-
- // Extend or truncate to the target size.
- if (AI.AccessWidth < ResSizeInBits)
- Val = Builder.CreateZExt(Val, ResLTy);
- else if (AI.AccessWidth > ResSizeInBits)
- Val = Builder.CreateTrunc(Val, ResLTy);
-
- // Shift into place, and OR into the result.
- if (AI.TargetBitOffset)
- Val = Builder.CreateShl(Val, AI.TargetBitOffset);
- Res = Res ? Builder.CreateOr(Res, Val) : Val;
- }
- // If the bit-field is signed, perform the sign-extension.
- //
- // FIXME: This can easily be folded into the load of the high bits, which
- // could also eliminate the mask of high bits in some situations.
- if (Info.isSigned()) {
- unsigned ExtraBits = ResSizeInBits - Info.getSize();
- if (ExtraBits)
- Res = Builder.CreateAShr(Builder.CreateShl(Res, ExtraBits),
- ExtraBits, "bf.val.sext");
+ llvm::Value *Ptr = LV.getBitFieldAddr();
+ llvm::Value *Val = Builder.CreateLoad(Ptr, LV.isVolatileQualified(),
+ "bf.load");
+ cast<llvm::LoadInst>(Val)->setAlignment(Info.StorageAlignment);
+
+ if (Info.IsSigned) {
+ assert(static_cast<unsigned>(Info.Offset + Info.Size) <= Info.StorageSize);
+ unsigned HighBits = Info.StorageSize - Info.Offset - Info.Size;
+ if (HighBits)
+ Val = Builder.CreateShl(Val, HighBits, "bf.shl");
+ if (Info.Offset + HighBits)
+ Val = Builder.CreateAShr(Val, Info.Offset + HighBits, "bf.ashr");
+ } else {
+ if (Info.Offset)
+ Val = Builder.CreateLShr(Val, Info.Offset, "bf.lshr");
+ if (static_cast<unsigned>(Info.Offset) + Info.Size < Info.StorageSize)
+ Val = Builder.CreateAnd(Val, llvm::APInt::getLowBitsSet(Info.StorageSize,
+ Info.Size),
+ "bf.clear");
}
+ Val = Builder.CreateIntCast(Val, ResLTy, Info.IsSigned, "bf.cast");
- return RValue::get(Res);
+ return RValue::get(Val);
}
// If this is a reference to a subset of the elements of a vector, create an
@@ -1344,106 +1488,71 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, bool isInit
void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
llvm::Value **Result) {
const CGBitFieldInfo &Info = Dst.getBitFieldInfo();
-
- // Get the output type.
llvm::Type *ResLTy = ConvertTypeForMem(Dst.getType());
- unsigned ResSizeInBits = CGM.getDataLayout().getTypeSizeInBits(ResLTy);
+ llvm::Value *Ptr = Dst.getBitFieldAddr();
// Get the source value, truncated to the width of the bit-field.
llvm::Value *SrcVal = Src.getScalarVal();
- if (hasBooleanRepresentation(Dst.getType()))
- SrcVal = Builder.CreateIntCast(SrcVal, ResLTy, /*IsSigned=*/false);
-
- SrcVal = Builder.CreateAnd(SrcVal, llvm::APInt::getLowBitsSet(ResSizeInBits,
- Info.getSize()),
- "bf.value");
-
- // Return the new value of the bit-field, if requested.
- if (Result) {
- // Cast back to the proper type for result.
- llvm::Type *SrcTy = Src.getScalarVal()->getType();
- llvm::Value *ReloadVal = Builder.CreateIntCast(SrcVal, SrcTy, false,
- "bf.reload.val");
-
- // Sign extend if necessary.
- if (Info.isSigned()) {
- unsigned ExtraBits = ResSizeInBits - Info.getSize();
- if (ExtraBits)
- ReloadVal = Builder.CreateAShr(Builder.CreateShl(ReloadVal, ExtraBits),
- ExtraBits, "bf.reload.sext");
- }
+ // Cast the source to the storage type and shift it into place.
+ SrcVal = Builder.CreateIntCast(SrcVal,
+ Ptr->getType()->getPointerElementType(),
+ /*IsSigned=*/false);
+ llvm::Value *MaskedVal = SrcVal;
+
+ // See if there are other bits in the bitfield's storage we'll need to load
+ // and mask together with source before storing.
+ if (Info.StorageSize != Info.Size) {
+ assert(Info.StorageSize > Info.Size && "Invalid bitfield size.");
+ llvm::Value *Val = Builder.CreateLoad(Ptr, Dst.isVolatileQualified(),
+ "bf.load");
+ cast<llvm::LoadInst>(Val)->setAlignment(Info.StorageAlignment);
+
+ // Mask the source value as needed.
+ if (!hasBooleanRepresentation(Dst.getType()))
+ SrcVal = Builder.CreateAnd(SrcVal,
+ llvm::APInt::getLowBitsSet(Info.StorageSize,
+ Info.Size),
+ "bf.value");
+ MaskedVal = SrcVal;
+ if (Info.Offset)
+ SrcVal = Builder.CreateShl(SrcVal, Info.Offset, "bf.shl");
+
+ // Mask out the original value.
+ Val = Builder.CreateAnd(Val,
+ ~llvm::APInt::getBitsSet(Info.StorageSize,
+ Info.Offset,
+ Info.Offset + Info.Size),
+ "bf.clear");
- *Result = ReloadVal;
+ // Or together the unchanged values and the source value.
+ SrcVal = Builder.CreateOr(Val, SrcVal, "bf.set");
+ } else {
+ assert(Info.Offset == 0);
}
- // Iterate over the components, writing each piece to memory.
- for (unsigned i = 0, e = Info.getNumComponents(); i != e; ++i) {
- const CGBitFieldInfo::AccessInfo &AI = Info.getComponent(i);
- CharUnits AccessAlignment = AI.AccessAlignment;
- if (!Dst.getAlignment().isZero())
- AccessAlignment = std::min(AccessAlignment, Dst.getAlignment());
-
- // Get the field pointer.
- llvm::Value *Ptr = Dst.getBitFieldBaseAddr();
- unsigned addressSpace =
- cast<llvm::PointerType>(Ptr->getType())->getAddressSpace();
-
- // Only offset by the field index if used, so that incoming values are not
- // required to be structures.
- if (AI.FieldIndex)
- Ptr = Builder.CreateStructGEP(Ptr, AI.FieldIndex, "bf.field");
-
- // Offset by the byte offset, if used.
- if (!AI.FieldByteOffset.isZero()) {
- Ptr = EmitCastToVoidPtr(Ptr);
- Ptr = Builder.CreateConstGEP1_32(Ptr, AI.FieldByteOffset.getQuantity(),
- "bf.field.offs");
- }
+ // Write the new value back out.
+ llvm::StoreInst *Store = Builder.CreateStore(SrcVal, Ptr,
+ Dst.isVolatileQualified());
+ Store->setAlignment(Info.StorageAlignment);
- // Cast to the access type.
- llvm::Type *AccessLTy =
- llvm::Type::getIntNTy(getLLVMContext(), AI.AccessWidth);
-
- llvm::Type *PTy = AccessLTy->getPointerTo(addressSpace);
- Ptr = Builder.CreateBitCast(Ptr, PTy);
-
- // Extract the piece of the bit-field value to write in this access, limited
- // to the values that are part of this access.
- llvm::Value *Val = SrcVal;
- if (AI.TargetBitOffset)
- Val = Builder.CreateLShr(Val, AI.TargetBitOffset);
- Val = Builder.CreateAnd(Val, llvm::APInt::getLowBitsSet(ResSizeInBits,
- AI.TargetBitWidth));
-
- // Extend or truncate to the access size.
- if (ResSizeInBits < AI.AccessWidth)
- Val = Builder.CreateZExt(Val, AccessLTy);
- else if (ResSizeInBits > AI.AccessWidth)
- Val = Builder.CreateTrunc(Val, AccessLTy);
-
- // Shift into the position in memory.
- if (AI.FieldBitStart)
- Val = Builder.CreateShl(Val, AI.FieldBitStart);
-
- // If necessary, load and OR in bits that are outside of the bit-field.
- if (AI.TargetBitWidth != AI.AccessWidth) {
- llvm::LoadInst *Load = Builder.CreateLoad(Ptr, Dst.isVolatileQualified());
- Load->setAlignment(AccessAlignment.getQuantity());
-
- // Compute the mask for zeroing the bits that are part of the bit-field.
- llvm::APInt InvMask =
- ~llvm::APInt::getBitsSet(AI.AccessWidth, AI.FieldBitStart,
- AI.FieldBitStart + AI.TargetBitWidth);
-
- // Apply the mask and OR in to the value to write.
- Val = Builder.CreateOr(Builder.CreateAnd(Load, InvMask), Val);
+ // Return the new value of the bit-field, if requested.
+ if (Result) {
+ llvm::Value *ResultVal = MaskedVal;
+
+ // Sign extend the value if needed.
+ if (Info.IsSigned) {
+ assert(Info.Size <= Info.StorageSize);
+ unsigned HighBits = Info.StorageSize - Info.Size;
+ if (HighBits) {
+ ResultVal = Builder.CreateShl(ResultVal, HighBits, "bf.result.shl");
+ ResultVal = Builder.CreateAShr(ResultVal, HighBits, "bf.result.ashr");
+ }
}
- // Write the value.
- llvm::StoreInst *Store = Builder.CreateStore(Val, Ptr,
- Dst.isVolatileQualified());
- Store->setAlignment(AccessAlignment.getQuantity());
+ ResultVal = Builder.CreateIntCast(ResultVal, ResLTy, Info.IsSigned,
+ "bf.result.cast");
+ *Result = EmitFromMemory(ResultVal, Dst.getType());
}
}
@@ -1625,9 +1734,6 @@ EmitBitCastOfLValueToProperType(CodeGenFunction &CGF,
static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF,
const Expr *E, const VarDecl *VD) {
- assert((VD->hasExternalStorage() || VD->isFileVarDecl()) &&
- "Var decl must have external storage or be a file var decl!");
-
llvm::Value *V = CGF.CGM.GetAddrOfGlobalVar(VD);
llvm::Type *RealVarTy = CGF.getTypes().ConvertTypeForMem(VD->getType());
V = EmitBitCastOfLValueToProperType(CGF, V, RealVarTy);
@@ -1700,16 +1806,12 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
// Check if this is a global variable.
- if (VD->hasExternalStorage() || VD->isFileVarDecl())
+ if (VD->hasLinkage() || VD->isStaticDataMember())
return EmitGlobalVarDeclLValue(*this, E, VD);
bool isBlockVariable = VD->hasAttr<BlocksAttr>();
- bool NonGCable = VD->hasLocalStorage() &&
- !VD->getType()->isReferenceType() &&
- !isBlockVariable;
-
- llvm::Value *V = LocalDeclMap[VD];
+ llvm::Value *V = LocalDeclMap.lookup(VD);
if (!V && VD->isStaticLocal())
V = CGM.getStaticLocalDeclAddress(VD);
@@ -1742,10 +1844,20 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
LV = MakeAddrLValue(V, T, Alignment);
}
+ bool isLocalStorage = VD->hasLocalStorage();
+
+ bool NonGCable = isLocalStorage &&
+ !VD->getType()->isReferenceType() &&
+ !isBlockVariable;
if (NonGCable) {
LV.getQuals().removeObjCGCAttr();
LV.setNonGC(true);
}
+
+ bool isImpreciseLifetime =
+ (isLocalStorage && !VD->hasAttr<ObjCPreciseLifetimeAttr>());
+ if (isImpreciseLifetime)
+ LV.setARCPreciseLifetime(ARCImpreciseLifetime);
setObjCGCLValueClass(getContext(), E, LV);
return LV;
}
@@ -1945,7 +2057,7 @@ llvm::Constant *CodeGenFunction::EmitCheckTypeDescriptor(QualType T) {
if (T->isIntegerType()) {
TypeKind = 0;
TypeInfo = (llvm::Log2_32(getContext().getTypeSize(T)) << 1) |
- T->isSignedIntegerType();
+ (T->isSignedIntegerType() ? 1 : 0);
} else if (T->isFloatingType()) {
TypeKind = 1;
TypeInfo = getContext().getTypeSize(T);
@@ -1953,7 +2065,7 @@ llvm::Constant *CodeGenFunction::EmitCheckTypeDescriptor(QualType T) {
// Format the type name as if for a diagnostic, including quotes and
// optionally an 'aka'.
- llvm::SmallString<32> Buffer;
+ SmallString<32> Buffer;
CGM.getDiags().ConvertArgToString(DiagnosticsEngine::ak_qualtype,
(intptr_t)T.getAsOpaquePtr(),
0, 0, 0, 0, 0, 0, Buffer,
@@ -1977,6 +2089,15 @@ llvm::Constant *CodeGenFunction::EmitCheckTypeDescriptor(QualType T) {
llvm::Value *CodeGenFunction::EmitCheckValue(llvm::Value *V) {
llvm::Type *TargetTy = IntPtrTy;
+ // Floating-point types which fit into intptr_t are bitcast to integers
+ // and then passed directly (after zero-extension, if necessary).
+ if (V->getType()->isFloatingPointTy()) {
+ unsigned Bits = V->getType()->getPrimitiveSizeInBits();
+ if (Bits <= TargetTy->getIntegerBitWidth())
+ V = Builder.CreateBitCast(V, llvm::Type::getIntNTy(getLLVMContext(),
+ Bits));
+ }
+
// Integers which fit in intptr_t are zero-extended and passed directly.
if (V->getType()->isIntegerTy() &&
V->getType()->getIntegerBitWidth() <= TargetTy->getIntegerBitWidth())
@@ -1984,7 +2105,7 @@ llvm::Value *CodeGenFunction::EmitCheckValue(llvm::Value *V) {
// Pointers are passed directly, everything else is passed by address.
if (!V->getType()->isPointerTy()) {
- llvm::Value *Ptr = Builder.CreateAlloca(V->getType());
+ llvm::Value *Ptr = CreateTempAlloca(V->getType());
Builder.CreateStore(V, Ptr);
V = Ptr;
}
@@ -2016,23 +2137,39 @@ llvm::Constant *CodeGenFunction::EmitCheckSourceLocation(SourceLocation Loc) {
}
void CodeGenFunction::EmitCheck(llvm::Value *Checked, StringRef CheckName,
- llvm::ArrayRef<llvm::Constant *> StaticArgs,
- llvm::ArrayRef<llvm::Value *> DynamicArgs,
- bool Recoverable) {
+ ArrayRef<llvm::Constant *> StaticArgs,
+ ArrayRef<llvm::Value *> DynamicArgs,
+ CheckRecoverableKind RecoverKind) {
+ assert(SanOpts != &SanitizerOptions::Disabled);
+
+ if (CGM.getCodeGenOpts().SanitizeUndefinedTrapOnError) {
+ assert (RecoverKind != CRK_AlwaysRecoverable &&
+ "Runtime call required for AlwaysRecoverable kind!");
+ return EmitTrapCheck(Checked);
+ }
+
llvm::BasicBlock *Cont = createBasicBlock("cont");
llvm::BasicBlock *Handler = createBasicBlock("handler." + CheckName);
- Builder.CreateCondBr(Checked, Cont, Handler);
+
+ llvm::Instruction *Branch = Builder.CreateCondBr(Checked, Cont, Handler);
+
+ // Give hint that we very much don't expect to execute the handler
+ // Value chosen to match UR_NONTAKEN_WEIGHT, see BranchProbabilityInfo.cpp
+ llvm::MDBuilder MDHelper(getLLVMContext());
+ llvm::MDNode *Node = MDHelper.createBranchWeights((1U << 20) - 1, 1);
+ Branch->setMetadata(llvm::LLVMContext::MD_prof, Node);
+
EmitBlock(Handler);
llvm::Constant *Info = llvm::ConstantStruct::getAnon(StaticArgs);
llvm::GlobalValue *InfoPtr =
- new llvm::GlobalVariable(CGM.getModule(), Info->getType(), true,
+ new llvm::GlobalVariable(CGM.getModule(), Info->getType(), false,
llvm::GlobalVariable::PrivateLinkage, Info);
InfoPtr->setUnnamedAddr(true);
- llvm::SmallVector<llvm::Value *, 4> Args;
- llvm::SmallVector<llvm::Type *, 4> ArgTypes;
+ SmallVector<llvm::Value *, 4> Args;
+ SmallVector<llvm::Type *, 4> ArgTypes;
Args.reserve(DynamicArgs.size() + 1);
ArgTypes.reserve(DynamicArgs.size() + 1);
@@ -2046,31 +2183,41 @@ void CodeGenFunction::EmitCheck(llvm::Value *Checked, StringRef CheckName,
ArgTypes.push_back(IntPtrTy);
}
+ bool Recover = (RecoverKind == CRK_AlwaysRecoverable) ||
+ ((RecoverKind == CRK_Recoverable) &&
+ CGM.getCodeGenOpts().SanitizeRecover);
+
llvm::FunctionType *FnType =
llvm::FunctionType::get(CGM.VoidTy, ArgTypes, false);
llvm::AttrBuilder B;
- if (!Recoverable) {
- B.addAttribute(llvm::Attributes::NoReturn)
- .addAttribute(llvm::Attributes::NoUnwind);
- }
- B.addAttribute(llvm::Attributes::UWTable);
- llvm::Value *Fn = CGM.CreateRuntimeFunction(FnType,
- ("__ubsan_handle_" + CheckName).str(),
- llvm::Attributes::get(getLLVMContext(),
- B));
- llvm::CallInst *HandlerCall = Builder.CreateCall(Fn, Args);
- if (Recoverable) {
+ if (!Recover) {
+ B.addAttribute(llvm::Attribute::NoReturn)
+ .addAttribute(llvm::Attribute::NoUnwind);
+ }
+ B.addAttribute(llvm::Attribute::UWTable);
+
+ // Checks that have two variants use a suffix to differentiate them
+ bool NeedsAbortSuffix = (RecoverKind != CRK_Unrecoverable) &&
+ !CGM.getCodeGenOpts().SanitizeRecover;
+ std::string FunctionName = ("__ubsan_handle_" + CheckName +
+ (NeedsAbortSuffix? "_abort" : "")).str();
+ llvm::Value *Fn =
+ CGM.CreateRuntimeFunction(FnType, FunctionName,
+ llvm::AttributeSet::get(getLLVMContext(),
+ llvm::AttributeSet::FunctionIndex,
+ B));
+ llvm::CallInst *HandlerCall = EmitNounwindRuntimeCall(Fn, Args);
+ if (Recover) {
Builder.CreateBr(Cont);
} else {
HandlerCall->setDoesNotReturn();
- HandlerCall->setDoesNotThrow();
Builder.CreateUnreachable();
}
EmitBlock(Cont);
}
-void CodeGenFunction::EmitTrapvCheck(llvm::Value *Checked) {
+void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked) {
llvm::BasicBlock *Cont = createBasicBlock("cont");
// If we're optimizing, collapse all calls to trap down to just one per
@@ -2107,12 +2254,16 @@ static const Expr *isSimpleArrayDecayOperand(const Expr *E) {
return SubExpr;
}
-LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
+LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
+ bool Accessed) {
// The index must always be an integer, which is not an aggregate. Emit it.
llvm::Value *Idx = EmitScalarExpr(E->getIdx());
QualType IdxTy = E->getIdx()->getType();
bool IdxSigned = IdxTy->isSignedIntegerOrEnumerationType();
+ if (SanOpts->Bounds)
+ EmitBoundsCheck(E, E->getBase(), Idx, IdxTy, Accessed);
+
// If the base is a vector type, then we are forming a vector element lvalue
// with this subscript.
if (E->getBase()->getType()->isVectorType()) {
@@ -2173,7 +2324,13 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
// "gep x, i" here. Emit one "gep A, 0, i".
assert(Array->getType()->isArrayType() &&
"Array to pointer decay must have array source type!");
- LValue ArrayLV = EmitLValue(Array);
+ LValue ArrayLV;
+ // For simple multidimensional array indexing, set the 'accessed' flag for
+ // better bounds-checking of the base expression.
+ if (const ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(Array))
+ ArrayLV = EmitArraySubscriptExpr(ASE, /*Accessed*/ true);
+ else
+ ArrayLV = EmitLValue(Array);
llvm::Value *ArrayPtr = ArrayLV.getAddress();
llvm::Value *Zero = llvm::ConstantInt::get(Int32Ty, 0);
llvm::Value *Args[] = { Zero, Idx };
@@ -2318,10 +2475,21 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
const CGRecordLayout &RL =
CGM.getTypes().getCGRecordLayout(field->getParent());
const CGBitFieldInfo &Info = RL.getBitFieldInfo(field);
+ llvm::Value *Addr = base.getAddress();
+ unsigned Idx = RL.getLLVMFieldNo(field);
+ if (Idx != 0)
+ // For structs, we GEP to the field that the record layout suggests.
+ Addr = Builder.CreateStructGEP(Addr, Idx, field->getName());
+ // Get the access type.
+ llvm::Type *PtrTy = llvm::Type::getIntNPtrTy(
+ getLLVMContext(), Info.StorageSize,
+ CGM.getContext().getTargetAddressSpace(base.getType()));
+ if (Addr->getType() != PtrTy)
+ Addr = Builder.CreateBitCast(Addr, PtrTy);
+
QualType fieldType =
field->getType().withCVRQualifiers(base.getVRQualifiers());
- return LValue::MakeBitfield(base.getAddress(), Info, fieldType,
- base.getAlignment());
+ return LValue::MakeBitfield(Addr, Info, fieldType, base.getAlignment());
}
const RecordDecl *rec = field->getParent();
@@ -2337,9 +2505,12 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
llvm::Value *addr = base.getAddress();
unsigned cvr = base.getVRQualifiers();
+ bool TBAAPath = CGM.getCodeGenOpts().StructPathTBAA;
if (rec->isUnion()) {
// For unions, there is no pointer adjustment.
assert(!type->isReferenceType() && "union has reference member");
+ // TODO: handle path-aware TBAA for union.
+ TBAAPath = false;
} else {
// For structs, we GEP to the field that the record layout suggests.
unsigned idx = CGM.getTypes().getCGRecordLayout(rec).getLLVMFieldNo(field);
@@ -2351,6 +2522,8 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
if (cvr & Qualifiers::Volatile) load->setVolatile(true);
load->setAlignment(alignment.getQuantity());
+ // Loading the reference will disable path-aware TBAA.
+ TBAAPath = false;
if (CGM.shouldUseTBAA()) {
llvm::MDNode *tbaa;
if (mayAlias)
@@ -2384,6 +2557,16 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
LValue LV = MakeAddrLValue(addr, type, alignment);
LV.getQuals().addCVRQualifiers(cvr);
+ if (TBAAPath) {
+ const ASTRecordLayout &Layout =
+ getContext().getASTRecordLayout(field->getParent());
+ // Set the base type to be the base type of the base LValue and
+ // update offset to be relative to the base type.
+ LV.setTBAABaseType(base.getTBAABaseType());
+ LV.setTBAAOffset(base.getTBAAOffset() +
+ Layout.getFieldOffset(field->getFieldIndex()) /
+ getContext().getCharWidth());
+ }
// __weak attribute on a field is ignored.
if (LV.getQuals().getObjCGCAttr() == Qualifiers::Weak)
@@ -2462,8 +2645,7 @@ LValue CodeGenFunction::
EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) {
if (!expr->isGLValue()) {
// ?: here should be an aggregate.
- assert((hasAggregateLLVMType(expr->getType()) &&
- !expr->getType()->isAnyComplexType()) &&
+ assert(hasAggregateEvaluationKind(expr->getType()) &&
"Unexpected conditional operator!");
return EmitAggExprToLValue(expr);
}
@@ -2630,7 +2812,13 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
cast<CXXRecordDecl>(DerivedClassTy->getDecl());
LValue LV = EmitLValue(E->getSubExpr());
-
+
+ // C++11 [expr.static.cast]p2: Behavior is undefined if a downcast is
+ // performed and the object is not of the derived type.
+ if (SanitizePerformTypeCheck)
+ EmitTypeCheck(TCK_DowncastReference, E->getExprLoc(),
+ LV.getAddress(), E->getType());
+
// Perform the base-to-derived conversion
llvm::Value *Derived =
GetAddressOfDerivedClass(LV.getAddress(), DerivedClassDecl,
@@ -2655,6 +2843,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
ConvertType(ToType));
return MakeAddrLValue(V, E->getType());
}
+ case CK_ZeroToOCLEvent:
+ llvm_unreachable("NULL to OpenCL event lvalue cast is not valid");
}
llvm_unreachable("Unhandled lvalue cast kind?");
@@ -2683,14 +2873,15 @@ RValue CodeGenFunction::EmitRValueForField(LValue LV,
const FieldDecl *FD) {
QualType FT = FD->getType();
LValue FieldLV = EmitLValueForField(LV, FD);
- if (FT->isAnyComplexType())
- return RValue::getComplex(
- LoadComplexFromAddr(FieldLV.getAddress(),
- FieldLV.isVolatileQualified()));
- else if (CodeGenFunction::hasAggregateLLVMType(FT))
+ switch (getEvaluationKind(FT)) {
+ case TEK_Complex:
+ return RValue::getComplex(EmitLoadOfComplex(FieldLV));
+ case TEK_Aggregate:
return FieldLV.asAggregateRValue();
-
- return EmitLoadOfLValue(FieldLV);
+ case TEK_Scalar:
+ return EmitLoadOfLValue(FieldLV);
+ }
+ llvm_unreachable("bad evaluation kind");
}
//===--------------------------------------------------------------------===//
@@ -2699,8 +2890,14 @@ RValue CodeGenFunction::EmitRValueForField(LValue LV,
RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
ReturnValueSlot ReturnValue) {
- if (CGDebugInfo *DI = getDebugInfo())
- DI->EmitLocation(Builder, E->getLocStart());
+ if (CGDebugInfo *DI = getDebugInfo()) {
+ SourceLocation Loc = E->getLocStart();
+ // Force column info to be generated so we can differentiate
+ // multiple call sites on the same line in the debug info.
+ const FunctionDecl* Callee = E->getDirectCallee();
+ bool ForceColumnInfo = Callee && Callee->isInlineSpecified();
+ DI->EmitLocation(Builder, Loc, ForceColumnInfo);
+ }
// Builtins never have block type.
if (E->getCallee()->getType()->isBlockPointerType())
@@ -2757,7 +2954,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E,
case Qualifiers::OCL_Strong:
EmitARCRelease(Builder.CreateLoad(BaseValue,
PseudoDtor->getDestroyedType().isVolatileQualified()),
- /*precise*/ true);
+ ARCPreciseLifetime);
break;
case Qualifiers::OCL_Weak:
@@ -2797,8 +2994,9 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
// Note that in all of these cases, __block variables need the RHS
// evaluated first just in case the variable gets moved by the RHS.
-
- if (!hasAggregateLLVMType(E->getType())) {
+
+ switch (getEvaluationKind(E->getType())) {
+ case TEK_Scalar: {
switch (E->getLHS()->getType().getObjCLifetime()) {
case Qualifiers::OCL_Strong:
return EmitARCStoreStrong(E, /*ignored*/ false).first;
@@ -2819,10 +3017,13 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
return LV;
}
- if (E->getType()->isAnyComplexType())
+ case TEK_Complex:
return EmitComplexAssignmentLValue(E);
- return EmitAggExprToLValue(E);
+ case TEK_Aggregate:
+ return EmitAggExprToLValue(E);
+ }
+ llvm_unreachable("bad evaluation kind");
}
LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) {
@@ -2895,7 +3096,7 @@ LValue CodeGenFunction::EmitObjCMessageExprLValue(const ObjCMessageExpr *E) {
LValue CodeGenFunction::EmitObjCSelectorLValue(const ObjCSelectorExpr *E) {
llvm::Value *V =
- CGM.getObjCRuntime().GetSelector(Builder, E->getSelector(), true);
+ CGM.getObjCRuntime().GetSelector(*this, E->getSelector(), true);
return MakeAddrLValue(V, E->getType());
}
@@ -2981,7 +3182,7 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
// through an unprototyped function type works like a *non-variadic*
// call. The way we make this work is to cast to the exact type
// of the promoted arguments.
- if (isa<FunctionNoProtoType>(FnType) && !FnInfo.isVariadic()) {
+ if (isa<FunctionNoProtoType>(FnType)) {
llvm::Type *CalleeTy = getTypes().GetFunctionType(FnInfo);
CalleeTy = CalleeTy->getPointerTo();
Callee = Builder.CreateBitCast(Callee, CalleeTy, "callee.knr.cast");
@@ -3009,475 +3210,20 @@ EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E) {
return MakeAddrLValue(AddV, MPT->getPointeeType());
}
-static void
-EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, llvm::Value *Dest,
- llvm::Value *Ptr, llvm::Value *Val1, llvm::Value *Val2,
- uint64_t Size, unsigned Align, llvm::AtomicOrdering Order) {
- llvm::AtomicRMWInst::BinOp Op = llvm::AtomicRMWInst::Add;
- llvm::Instruction::BinaryOps PostOp = (llvm::Instruction::BinaryOps)0;
-
- switch (E->getOp()) {
- case AtomicExpr::AO__c11_atomic_init:
- llvm_unreachable("Already handled!");
-
- case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
- case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
- case AtomicExpr::AO__atomic_compare_exchange:
- case AtomicExpr::AO__atomic_compare_exchange_n: {
- // Note that cmpxchg only supports specifying one ordering and
- // doesn't support weak cmpxchg, at least at the moment.
- llvm::LoadInst *LoadVal1 = CGF.Builder.CreateLoad(Val1);
- LoadVal1->setAlignment(Align);
- llvm::LoadInst *LoadVal2 = CGF.Builder.CreateLoad(Val2);
- LoadVal2->setAlignment(Align);
- llvm::AtomicCmpXchgInst *CXI =
- CGF.Builder.CreateAtomicCmpXchg(Ptr, LoadVal1, LoadVal2, Order);
- CXI->setVolatile(E->isVolatile());
- llvm::StoreInst *StoreVal1 = CGF.Builder.CreateStore(CXI, Val1);
- StoreVal1->setAlignment(Align);
- llvm::Value *Cmp = CGF.Builder.CreateICmpEQ(CXI, LoadVal1);
- CGF.EmitStoreOfScalar(Cmp, CGF.MakeAddrLValue(Dest, E->getType()));
- return;
- }
-
- case AtomicExpr::AO__c11_atomic_load:
- case AtomicExpr::AO__atomic_load_n:
- case AtomicExpr::AO__atomic_load: {
- llvm::LoadInst *Load = CGF.Builder.CreateLoad(Ptr);
- Load->setAtomic(Order);
- Load->setAlignment(Size);
- Load->setVolatile(E->isVolatile());
- llvm::StoreInst *StoreDest = CGF.Builder.CreateStore(Load, Dest);
- StoreDest->setAlignment(Align);
- return;
- }
-
- case AtomicExpr::AO__c11_atomic_store:
- case AtomicExpr::AO__atomic_store:
- case AtomicExpr::AO__atomic_store_n: {
- assert(!Dest && "Store does not return a value");
- llvm::LoadInst *LoadVal1 = CGF.Builder.CreateLoad(Val1);
- LoadVal1->setAlignment(Align);
- llvm::StoreInst *Store = CGF.Builder.CreateStore(LoadVal1, Ptr);
- Store->setAtomic(Order);
- Store->setAlignment(Size);
- Store->setVolatile(E->isVolatile());
- return;
+/// Given the address of a temporary variable, produce an r-value of
+/// its type.
+RValue CodeGenFunction::convertTempToRValue(llvm::Value *addr,
+ QualType type) {
+ LValue lvalue = MakeNaturalAlignAddrLValue(addr, type);
+ switch (getEvaluationKind(type)) {
+ case TEK_Complex:
+ return RValue::getComplex(EmitLoadOfComplex(lvalue));
+ case TEK_Aggregate:
+ return lvalue.asAggregateRValue();
+ case TEK_Scalar:
+ return RValue::get(EmitLoadOfScalar(lvalue));
}
-
- case AtomicExpr::AO__c11_atomic_exchange:
- case AtomicExpr::AO__atomic_exchange_n:
- case AtomicExpr::AO__atomic_exchange:
- Op = llvm::AtomicRMWInst::Xchg;
- break;
-
- case AtomicExpr::AO__atomic_add_fetch:
- PostOp = llvm::Instruction::Add;
- // Fall through.
- case AtomicExpr::AO__c11_atomic_fetch_add:
- case AtomicExpr::AO__atomic_fetch_add:
- Op = llvm::AtomicRMWInst::Add;
- break;
-
- case AtomicExpr::AO__atomic_sub_fetch:
- PostOp = llvm::Instruction::Sub;
- // Fall through.
- case AtomicExpr::AO__c11_atomic_fetch_sub:
- case AtomicExpr::AO__atomic_fetch_sub:
- Op = llvm::AtomicRMWInst::Sub;
- break;
-
- case AtomicExpr::AO__atomic_and_fetch:
- PostOp = llvm::Instruction::And;
- // Fall through.
- case AtomicExpr::AO__c11_atomic_fetch_and:
- case AtomicExpr::AO__atomic_fetch_and:
- Op = llvm::AtomicRMWInst::And;
- break;
-
- case AtomicExpr::AO__atomic_or_fetch:
- PostOp = llvm::Instruction::Or;
- // Fall through.
- case AtomicExpr::AO__c11_atomic_fetch_or:
- case AtomicExpr::AO__atomic_fetch_or:
- Op = llvm::AtomicRMWInst::Or;
- break;
-
- case AtomicExpr::AO__atomic_xor_fetch:
- PostOp = llvm::Instruction::Xor;
- // Fall through.
- case AtomicExpr::AO__c11_atomic_fetch_xor:
- case AtomicExpr::AO__atomic_fetch_xor:
- Op = llvm::AtomicRMWInst::Xor;
- break;
-
- case AtomicExpr::AO__atomic_nand_fetch:
- PostOp = llvm::Instruction::And;
- // Fall through.
- case AtomicExpr::AO__atomic_fetch_nand:
- Op = llvm::AtomicRMWInst::Nand;
- break;
- }
-
- llvm::LoadInst *LoadVal1 = CGF.Builder.CreateLoad(Val1);
- LoadVal1->setAlignment(Align);
- llvm::AtomicRMWInst *RMWI =
- CGF.Builder.CreateAtomicRMW(Op, Ptr, LoadVal1, Order);
- RMWI->setVolatile(E->isVolatile());
-
- // For __atomic_*_fetch operations, perform the operation again to
- // determine the value which was written.
- llvm::Value *Result = RMWI;
- if (PostOp)
- Result = CGF.Builder.CreateBinOp(PostOp, RMWI, LoadVal1);
- if (E->getOp() == AtomicExpr::AO__atomic_nand_fetch)
- Result = CGF.Builder.CreateNot(Result);
- llvm::StoreInst *StoreDest = CGF.Builder.CreateStore(Result, Dest);
- StoreDest->setAlignment(Align);
-}
-
-// This function emits any expression (scalar, complex, or aggregate)
-// into a temporary alloca.
-static llvm::Value *
-EmitValToTemp(CodeGenFunction &CGF, Expr *E) {
- llvm::Value *DeclPtr = CGF.CreateMemTemp(E->getType(), ".atomictmp");
- CGF.EmitAnyExprToMem(E, DeclPtr, E->getType().getQualifiers(),
- /*Init*/ true);
- return DeclPtr;
-}
-
-static RValue ConvertTempToRValue(CodeGenFunction &CGF, QualType Ty,
- llvm::Value *Dest) {
- if (Ty->isAnyComplexType())
- return RValue::getComplex(CGF.LoadComplexFromAddr(Dest, false));
- if (CGF.hasAggregateLLVMType(Ty))
- return RValue::getAggregate(Dest);
- return RValue::get(CGF.EmitLoadOfScalar(CGF.MakeAddrLValue(Dest, Ty)));
-}
-
-RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
- QualType AtomicTy = E->getPtr()->getType()->getPointeeType();
- QualType MemTy = AtomicTy;
- if (const AtomicType *AT = AtomicTy->getAs<AtomicType>())
- MemTy = AT->getValueType();
- CharUnits sizeChars = getContext().getTypeSizeInChars(AtomicTy);
- uint64_t Size = sizeChars.getQuantity();
- CharUnits alignChars = getContext().getTypeAlignInChars(AtomicTy);
- unsigned Align = alignChars.getQuantity();
- unsigned MaxInlineWidthInBits =
- getContext().getTargetInfo().getMaxAtomicInlineWidth();
- bool UseLibcall = (Size != Align ||
- getContext().toBits(sizeChars) > MaxInlineWidthInBits);
-
- llvm::Value *Ptr, *Order, *OrderFail = 0, *Val1 = 0, *Val2 = 0;
- Ptr = EmitScalarExpr(E->getPtr());
-
- if (E->getOp() == AtomicExpr::AO__c11_atomic_init) {
- assert(!Dest && "Init does not return a value");
- if (!hasAggregateLLVMType(E->getVal1()->getType())) {
- QualType PointeeType
- = E->getPtr()->getType()->getAs<PointerType>()->getPointeeType();
- EmitScalarInit(EmitScalarExpr(E->getVal1()),
- LValue::MakeAddr(Ptr, PointeeType, alignChars,
- getContext()));
- } else if (E->getType()->isAnyComplexType()) {
- EmitComplexExprIntoAddr(E->getVal1(), Ptr, E->isVolatile());
- } else {
- AggValueSlot Slot = AggValueSlot::forAddr(Ptr, alignChars,
- AtomicTy.getQualifiers(),
- AggValueSlot::IsNotDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased);
- EmitAggExpr(E->getVal1(), Slot);
- }
- return RValue::get(0);
- }
-
- Order = EmitScalarExpr(E->getOrder());
-
- switch (E->getOp()) {
- case AtomicExpr::AO__c11_atomic_init:
- llvm_unreachable("Already handled!");
-
- case AtomicExpr::AO__c11_atomic_load:
- case AtomicExpr::AO__atomic_load_n:
- break;
-
- case AtomicExpr::AO__atomic_load:
- Dest = EmitScalarExpr(E->getVal1());
- break;
-
- case AtomicExpr::AO__atomic_store:
- Val1 = EmitScalarExpr(E->getVal1());
- break;
-
- case AtomicExpr::AO__atomic_exchange:
- Val1 = EmitScalarExpr(E->getVal1());
- Dest = EmitScalarExpr(E->getVal2());
- break;
-
- case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
- case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
- case AtomicExpr::AO__atomic_compare_exchange_n:
- case AtomicExpr::AO__atomic_compare_exchange:
- Val1 = EmitScalarExpr(E->getVal1());
- if (E->getOp() == AtomicExpr::AO__atomic_compare_exchange)
- Val2 = EmitScalarExpr(E->getVal2());
- else
- Val2 = EmitValToTemp(*this, E->getVal2());
- OrderFail = EmitScalarExpr(E->getOrderFail());
- // Evaluate and discard the 'weak' argument.
- if (E->getNumSubExprs() == 6)
- EmitScalarExpr(E->getWeak());
- break;
-
- case AtomicExpr::AO__c11_atomic_fetch_add:
- case AtomicExpr::AO__c11_atomic_fetch_sub:
- if (MemTy->isPointerType()) {
- // For pointer arithmetic, we're required to do a bit of math:
- // adding 1 to an int* is not the same as adding 1 to a uintptr_t.
- // ... but only for the C11 builtins. The GNU builtins expect the
- // user to multiply by sizeof(T).
- QualType Val1Ty = E->getVal1()->getType();
- llvm::Value *Val1Scalar = EmitScalarExpr(E->getVal1());
- CharUnits PointeeIncAmt =
- getContext().getTypeSizeInChars(MemTy->getPointeeType());
- Val1Scalar = Builder.CreateMul(Val1Scalar, CGM.getSize(PointeeIncAmt));
- Val1 = CreateMemTemp(Val1Ty, ".atomictmp");
- EmitStoreOfScalar(Val1Scalar, MakeAddrLValue(Val1, Val1Ty));
- break;
- }
- // Fall through.
- case AtomicExpr::AO__atomic_fetch_add:
- case AtomicExpr::AO__atomic_fetch_sub:
- case AtomicExpr::AO__atomic_add_fetch:
- case AtomicExpr::AO__atomic_sub_fetch:
- case AtomicExpr::AO__c11_atomic_store:
- case AtomicExpr::AO__c11_atomic_exchange:
- case AtomicExpr::AO__atomic_store_n:
- case AtomicExpr::AO__atomic_exchange_n:
- case AtomicExpr::AO__c11_atomic_fetch_and:
- case AtomicExpr::AO__c11_atomic_fetch_or:
- case AtomicExpr::AO__c11_atomic_fetch_xor:
- case AtomicExpr::AO__atomic_fetch_and:
- case AtomicExpr::AO__atomic_fetch_or:
- case AtomicExpr::AO__atomic_fetch_xor:
- case AtomicExpr::AO__atomic_fetch_nand:
- case AtomicExpr::AO__atomic_and_fetch:
- case AtomicExpr::AO__atomic_or_fetch:
- case AtomicExpr::AO__atomic_xor_fetch:
- case AtomicExpr::AO__atomic_nand_fetch:
- Val1 = EmitValToTemp(*this, E->getVal1());
- break;
- }
-
- if (!E->getType()->isVoidType() && !Dest)
- Dest = CreateMemTemp(E->getType(), ".atomicdst");
-
- // Use a library call. See: http://gcc.gnu.org/wiki/Atomic/GCCMM/LIbrary .
- if (UseLibcall) {
-
- llvm::SmallVector<QualType, 5> Params;
- CallArgList Args;
- // Size is always the first parameter
- Args.add(RValue::get(llvm::ConstantInt::get(SizeTy, Size)),
- getContext().getSizeType());
- // Atomic address is always the second parameter
- Args.add(RValue::get(EmitCastToVoidPtr(Ptr)),
- getContext().VoidPtrTy);
-
- const char* LibCallName;
- QualType RetTy = getContext().VoidTy;
- switch (E->getOp()) {
- // There is only one libcall for compare an exchange, because there is no
- // optimisation benefit possible from a libcall version of a weak compare
- // and exchange.
- // bool __atomic_compare_exchange(size_t size, void *obj, void *expected,
- // void *desired, int success, int failure)
- case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
- case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
- case AtomicExpr::AO__atomic_compare_exchange:
- case AtomicExpr::AO__atomic_compare_exchange_n:
- LibCallName = "__atomic_compare_exchange";
- RetTy = getContext().BoolTy;
- Args.add(RValue::get(EmitCastToVoidPtr(Val1)),
- getContext().VoidPtrTy);
- Args.add(RValue::get(EmitCastToVoidPtr(Val2)),
- getContext().VoidPtrTy);
- Args.add(RValue::get(Order),
- getContext().IntTy);
- Order = OrderFail;
- break;
- // void __atomic_exchange(size_t size, void *mem, void *val, void *return,
- // int order)
- case AtomicExpr::AO__c11_atomic_exchange:
- case AtomicExpr::AO__atomic_exchange_n:
- case AtomicExpr::AO__atomic_exchange:
- LibCallName = "__atomic_exchange";
- Args.add(RValue::get(EmitCastToVoidPtr(Val1)),
- getContext().VoidPtrTy);
- Args.add(RValue::get(EmitCastToVoidPtr(Dest)),
- getContext().VoidPtrTy);
- break;
- // void __atomic_store(size_t size, void *mem, void *val, int order)
- case AtomicExpr::AO__c11_atomic_store:
- case AtomicExpr::AO__atomic_store:
- case AtomicExpr::AO__atomic_store_n:
- LibCallName = "__atomic_store";
- Args.add(RValue::get(EmitCastToVoidPtr(Val1)),
- getContext().VoidPtrTy);
- break;
- // void __atomic_load(size_t size, void *mem, void *return, int order)
- case AtomicExpr::AO__c11_atomic_load:
- case AtomicExpr::AO__atomic_load:
- case AtomicExpr::AO__atomic_load_n:
- LibCallName = "__atomic_load";
- Args.add(RValue::get(EmitCastToVoidPtr(Dest)),
- getContext().VoidPtrTy);
- break;
-#if 0
- // These are only defined for 1-16 byte integers. It is not clear what
- // their semantics would be on anything else...
- case AtomicExpr::Add: LibCallName = "__atomic_fetch_add_generic"; break;
- case AtomicExpr::Sub: LibCallName = "__atomic_fetch_sub_generic"; break;
- case AtomicExpr::And: LibCallName = "__atomic_fetch_and_generic"; break;
- case AtomicExpr::Or: LibCallName = "__atomic_fetch_or_generic"; break;
- case AtomicExpr::Xor: LibCallName = "__atomic_fetch_xor_generic"; break;
-#endif
- default: return EmitUnsupportedRValue(E, "atomic library call");
- }
- // order is always the last parameter
- Args.add(RValue::get(Order),
- getContext().IntTy);
-
- const CGFunctionInfo &FuncInfo =
- CGM.getTypes().arrangeFreeFunctionCall(RetTy, Args,
- FunctionType::ExtInfo(), RequiredArgs::All);
- llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FuncInfo);
- llvm::Constant *Func = CGM.CreateRuntimeFunction(FTy, LibCallName);
- RValue Res = EmitCall(FuncInfo, Func, ReturnValueSlot(), Args);
- if (E->isCmpXChg())
- return Res;
- if (E->getType()->isVoidType())
- return RValue::get(0);
- return ConvertTempToRValue(*this, E->getType(), Dest);
- }
-
- bool IsStore = E->getOp() == AtomicExpr::AO__c11_atomic_store ||
- E->getOp() == AtomicExpr::AO__atomic_store ||
- E->getOp() == AtomicExpr::AO__atomic_store_n;
- bool IsLoad = E->getOp() == AtomicExpr::AO__c11_atomic_load ||
- E->getOp() == AtomicExpr::AO__atomic_load ||
- E->getOp() == AtomicExpr::AO__atomic_load_n;
-
- llvm::Type *IPtrTy =
- llvm::IntegerType::get(getLLVMContext(), Size * 8)->getPointerTo();
- llvm::Value *OrigDest = Dest;
- Ptr = Builder.CreateBitCast(Ptr, IPtrTy);
- if (Val1) Val1 = Builder.CreateBitCast(Val1, IPtrTy);
- if (Val2) Val2 = Builder.CreateBitCast(Val2, IPtrTy);
- if (Dest && !E->isCmpXChg()) Dest = Builder.CreateBitCast(Dest, IPtrTy);
-
- if (isa<llvm::ConstantInt>(Order)) {
- int ord = cast<llvm::ConstantInt>(Order)->getZExtValue();
- switch (ord) {
- case 0: // memory_order_relaxed
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::Monotonic);
- break;
- case 1: // memory_order_consume
- case 2: // memory_order_acquire
- if (IsStore)
- break; // Avoid crashing on code with undefined behavior
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::Acquire);
- break;
- case 3: // memory_order_release
- if (IsLoad)
- break; // Avoid crashing on code with undefined behavior
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::Release);
- break;
- case 4: // memory_order_acq_rel
- if (IsLoad || IsStore)
- break; // Avoid crashing on code with undefined behavior
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::AcquireRelease);
- break;
- case 5: // memory_order_seq_cst
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::SequentiallyConsistent);
- break;
- default: // invalid order
- // We should not ever get here normally, but it's hard to
- // enforce that in general.
- break;
- }
- if (E->getType()->isVoidType())
- return RValue::get(0);
- return ConvertTempToRValue(*this, E->getType(), OrigDest);
- }
-
- // Long case, when Order isn't obviously constant.
-
- // Create all the relevant BB's
- llvm::BasicBlock *MonotonicBB = 0, *AcquireBB = 0, *ReleaseBB = 0,
- *AcqRelBB = 0, *SeqCstBB = 0;
- MonotonicBB = createBasicBlock("monotonic", CurFn);
- if (!IsStore)
- AcquireBB = createBasicBlock("acquire", CurFn);
- if (!IsLoad)
- ReleaseBB = createBasicBlock("release", CurFn);
- if (!IsLoad && !IsStore)
- AcqRelBB = createBasicBlock("acqrel", CurFn);
- SeqCstBB = createBasicBlock("seqcst", CurFn);
- llvm::BasicBlock *ContBB = createBasicBlock("atomic.continue", CurFn);
-
- // Create the switch for the split
- // MonotonicBB is arbitrarily chosen as the default case; in practice, this
- // doesn't matter unless someone is crazy enough to use something that
- // doesn't fold to a constant for the ordering.
- Order = Builder.CreateIntCast(Order, Builder.getInt32Ty(), false);
- llvm::SwitchInst *SI = Builder.CreateSwitch(Order, MonotonicBB);
-
- // Emit all the different atomics
- Builder.SetInsertPoint(MonotonicBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::Monotonic);
- Builder.CreateBr(ContBB);
- if (!IsStore) {
- Builder.SetInsertPoint(AcquireBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::Acquire);
- Builder.CreateBr(ContBB);
- SI->addCase(Builder.getInt32(1), AcquireBB);
- SI->addCase(Builder.getInt32(2), AcquireBB);
- }
- if (!IsLoad) {
- Builder.SetInsertPoint(ReleaseBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::Release);
- Builder.CreateBr(ContBB);
- SI->addCase(Builder.getInt32(3), ReleaseBB);
- }
- if (!IsLoad && !IsStore) {
- Builder.SetInsertPoint(AcqRelBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::AcquireRelease);
- Builder.CreateBr(ContBB);
- SI->addCase(Builder.getInt32(4), AcqRelBB);
- }
- Builder.SetInsertPoint(SeqCstBB);
- EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align,
- llvm::SequentiallyConsistent);
- Builder.CreateBr(ContBB);
- SI->addCase(Builder.getInt32(5), SeqCstBB);
-
- // Cleanup and return
- Builder.SetInsertPoint(ContBB);
- if (E->getType()->isVoidType())
- return RValue::get(0);
- return ConvertTempToRValue(*this, E->getType(), OrigDest);
+ llvm_unreachable("bad evaluation kind");
}
void CodeGenFunction::SetFPAccuracy(llvm::Value *Val, float Accuracy) {
@@ -3502,7 +3248,7 @@ static LValueOrRValue emitPseudoObjectExpr(CodeGenFunction &CGF,
const PseudoObjectExpr *E,
bool forLValue,
AggValueSlot slot) {
- llvm::SmallVector<CodeGenFunction::OpaqueValueMappingData, 4> opaques;
+ SmallVector<CodeGenFunction::OpaqueValueMappingData, 4> opaques;
// Find the result expression, if any.
const Expr *resultExpr = E->getResultExpr();
@@ -3521,8 +3267,7 @@ static LValueOrRValue emitPseudoObjectExpr(CodeGenFunction &CGF,
typedef CodeGenFunction::OpaqueValueMappingData OVMA;
OVMA opaqueData;
if (ov == resultExpr && ov->isRValue() && !forLValue &&
- CodeGenFunction::hasAggregateLLVMType(ov->getType()) &&
- !ov->getType()->isAnyComplexType()) {
+ CodeGenFunction::hasAggregateEvaluationKind(ov->getType())) {
CGF.EmitAggExpr(ov->getSourceExpr(), slot);
LValue LV = CGF.MakeAddrLValue(slot.getAddr(), ov->getType());
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 718e8f9..1ac13c0 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -12,16 +12,16 @@
//===----------------------------------------------------------------------===//
#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
#include "CGObjCRuntime.h"
+#include "CodeGenModule.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/StmtVisitor.h"
-#include "llvm/Constants.h"
-#include "llvm/Function.h"
-#include "llvm/GlobalVariable.h"
-#include "llvm/Intrinsics.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/Intrinsics.h"
using namespace clang;
using namespace CodeGen;
@@ -29,6 +29,14 @@ using namespace CodeGen;
// Aggregate Expression Emitter
//===----------------------------------------------------------------------===//
+llvm::Value *AggValueSlot::getPaddedAtomicAddr() const {
+ assert(isValueOfAtomic());
+ llvm::GEPOperator *op = cast<llvm::GEPOperator>(getAddr());
+ assert(op->getNumIndices() == 2);
+ assert(op->hasAllZeroIndices());
+ return op->getPointerOperand();
+}
+
namespace {
class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
CodeGenFunction &CGF;
@@ -190,6 +198,38 @@ public:
CGF.EmitAtomicExpr(E, EnsureSlot(E->getType()).getAddr());
}
};
+
+/// A helper class for emitting expressions into the value sub-object
+/// of a padded atomic type.
+class ValueDestForAtomic {
+ AggValueSlot Dest;
+public:
+ ValueDestForAtomic(CodeGenFunction &CGF, AggValueSlot dest, QualType type)
+ : Dest(dest) {
+ assert(!Dest.isValueOfAtomic());
+ if (!Dest.isIgnored() && CGF.CGM.isPaddedAtomicType(type)) {
+ llvm::Value *valueAddr = CGF.Builder.CreateStructGEP(Dest.getAddr(), 0);
+ Dest = AggValueSlot::forAddr(valueAddr,
+ Dest.getAlignment(),
+ Dest.getQualifiers(),
+ Dest.isExternallyDestructed(),
+ Dest.requiresGCollection(),
+ Dest.isPotentiallyAliased(),
+ Dest.isZeroed(),
+ AggValueSlot::IsValueOfAtomic);
+ }
+ }
+
+ const AggValueSlot &getDest() const { return Dest; }
+
+ ~ValueDestForAtomic() {
+ // Kill the GEP if we made one and it didn't end up used.
+ if (Dest.isValueOfAtomic()) {
+ llvm::Instruction *addr = cast<llvm::GetElementPtrInst>(Dest.getAddr());
+ if (addr->use_empty()) addr->eraseFromParent();
+ }
+ }
+};
} // end anonymous namespace.
//===----------------------------------------------------------------------===//
@@ -201,6 +241,14 @@ public:
/// then loads the result into DestPtr.
void AggExprEmitter::EmitAggLoadOfLValue(const Expr *E) {
LValue LV = CGF.EmitLValue(E);
+
+ // If the type of the l-value is atomic, then do an atomic load.
+ if (LV.getType()->isAtomicType()) {
+ ValueDestForAtomic valueDest(CGF, Dest, LV.getType());
+ CGF.EmitAtomicLoad(LV, valueDest.getDest());
+ return;
+ }
+
EmitFinalDestCopy(E->getType(), LV);
}
@@ -213,7 +261,7 @@ bool AggExprEmitter::TypeRequiresGCollection(QualType T) {
// Don't mess with non-trivial C++ types.
RecordDecl *Record = RecordTy->getDecl();
if (isa<CXXRecordDecl>(Record) &&
- (!cast<CXXRecordDecl>(Record)->hasTrivialCopyConstructor() ||
+ (cast<CXXRecordDecl>(Record)->hasNonTrivialCopyConstructor() ||
!cast<CXXRecordDecl>(Record)->hasTrivialDestructor()))
return false;
@@ -531,12 +579,10 @@ void AggExprEmitter::VisitOpaqueValueExpr(OpaqueValueExpr *e) {
void
AggExprEmitter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
- if (E->getType().isPODType(CGF.getContext())) {
+ if (Dest.isPotentiallyAliased() &&
+ E->getType().isPODType(CGF.getContext())) {
// For a POD type, just emit a load of the lvalue + a copy, because our
// compound literal might alias the destination.
- // FIXME: This is a band-aid; the real problem appears to be in our handling
- // of assignments, where we store directly into the LHS without checking
- // whether anything in the RHS aliases.
EmitAggLoadOfLValue(E);
return;
}
@@ -545,6 +591,20 @@ AggExprEmitter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
CGF.EmitAggExpr(E->getInitializer(), Slot);
}
+/// Attempt to look through various unimportant expressions to find a
+/// cast of the given kind.
+static Expr *findPeephole(Expr *op, CastKind kind) {
+ while (true) {
+ op = op->IgnoreParens();
+ if (CastExpr *castE = dyn_cast<CastExpr>(op)) {
+ if (castE->getCastKind() == kind)
+ return castE->getSubExpr();
+ if (castE->getCastKind() == CK_NoOp)
+ continue;
+ }
+ return 0;
+ }
+}
void AggExprEmitter::VisitCastExpr(CastExpr *E) {
switch (E->getCastKind()) {
@@ -584,6 +644,75 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
"should have been unpacked before we got here");
}
+ case CK_NonAtomicToAtomic:
+ case CK_AtomicToNonAtomic: {
+ bool isToAtomic = (E->getCastKind() == CK_NonAtomicToAtomic);
+
+ // Determine the atomic and value types.
+ QualType atomicType = E->getSubExpr()->getType();
+ QualType valueType = E->getType();
+ if (isToAtomic) std::swap(atomicType, valueType);
+
+ assert(atomicType->isAtomicType());
+ assert(CGF.getContext().hasSameUnqualifiedType(valueType,
+ atomicType->castAs<AtomicType>()->getValueType()));
+
+ // Just recurse normally if we're ignoring the result or the
+ // atomic type doesn't change representation.
+ if (Dest.isIgnored() || !CGF.CGM.isPaddedAtomicType(atomicType)) {
+ return Visit(E->getSubExpr());
+ }
+
+ CastKind peepholeTarget =
+ (isToAtomic ? CK_AtomicToNonAtomic : CK_NonAtomicToAtomic);
+
+ // These two cases are reverses of each other; try to peephole them.
+ if (Expr *op = findPeephole(E->getSubExpr(), peepholeTarget)) {
+ assert(CGF.getContext().hasSameUnqualifiedType(op->getType(),
+ E->getType()) &&
+ "peephole significantly changed types?");
+ return Visit(op);
+ }
+
+ // If we're converting an r-value of non-atomic type to an r-value
+ // of atomic type, just make an atomic temporary, emit into that,
+ // and then copy the value out. (FIXME: do we need to
+ // zero-initialize it first?)
+ if (isToAtomic) {
+ ValueDestForAtomic valueDest(CGF, Dest, atomicType);
+ CGF.EmitAggExpr(E->getSubExpr(), valueDest.getDest());
+ return;
+ }
+
+ // Otherwise, we're converting an atomic type to a non-atomic type.
+
+ // If the dest is a value-of-atomic subobject, drill back out.
+ if (Dest.isValueOfAtomic()) {
+ AggValueSlot atomicSlot =
+ AggValueSlot::forAddr(Dest.getPaddedAtomicAddr(),
+ Dest.getAlignment(),
+ Dest.getQualifiers(),
+ Dest.isExternallyDestructed(),
+ Dest.requiresGCollection(),
+ Dest.isPotentiallyAliased(),
+ Dest.isZeroed(),
+ AggValueSlot::IsNotValueOfAtomic);
+ CGF.EmitAggExpr(E->getSubExpr(), atomicSlot);
+ return;
+ }
+
+ // Otherwise, make an atomic temporary, emit into that, and then
+ // copy the value out.
+ AggValueSlot atomicSlot =
+ CGF.CreateAggTemp(atomicType, "atomic-to-nonatomic.temp");
+ CGF.EmitAggExpr(E->getSubExpr(), atomicSlot);
+
+ llvm::Value *valueAddr =
+ Builder.CreateStructGEP(atomicSlot.getAddr(), 0);
+ RValue rvalue = RValue::getAggregate(valueAddr, atomicSlot.isVolatile());
+ return EmitFinalDestCopy(valueType, rvalue);
+ }
+
case CK_LValueToRValue:
// If we're loading from a volatile type, force the destination
// into existence.
@@ -591,11 +720,10 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
EnsureDest(E->getType());
return Visit(E->getSubExpr());
}
+
// fallthrough
case CK_NoOp:
- case CK_AtomicToNonAtomic:
- case CK_NonAtomicToAtomic:
case CK_UserDefinedConversion:
case CK_ConstructorConversion:
assert(CGF.getContext().hasSameUnqualifiedType(E->getSubExpr()->getType(),
@@ -648,6 +776,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
case CK_ARCExtendBlockObject:
case CK_CopyAndAutoreleaseBlockObject:
case CK_BuiltinFnToFnPtr:
+ case CK_ZeroToOCLEvent:
llvm_unreachable("cast kind invalid for aggregate types");
}
}
@@ -776,6 +905,12 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
// Now emit the LHS and copy into it.
LValue LHS = CGF.EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
+ // That copy is an atomic copy if the LHS is atomic.
+ if (LHS.getType()->isAtomicType()) {
+ CGF.EmitAtomicStore(Dest.asRValue(), LHS, /*isInit*/ false);
+ return;
+ }
+
EmitCopy(E->getLHS()->getType(),
AggValueSlot::forLValue(LHS, AggValueSlot::IsDestructed,
needsGC(E->getLHS()->getType()),
@@ -786,11 +921,25 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
LValue LHS = CGF.EmitLValue(E->getLHS());
+ // If we have an atomic type, evaluate into the destination and then
+ // do an atomic copy.
+ if (LHS.getType()->isAtomicType()) {
+ EnsureDest(E->getRHS()->getType());
+ Visit(E->getRHS());
+ CGF.EmitAtomicStore(Dest.asRValue(), LHS, /*isInit*/ false);
+ return;
+ }
+
// Codegen the RHS so that it stores directly into the LHS.
AggValueSlot LHSSlot =
AggValueSlot::forLValue(LHS, AggValueSlot::IsDestructed,
needsGC(E->getLHS()->getType()),
AggValueSlot::IsAliased);
+ // A non-volatile aggregate destination might have volatile member.
+ if (!LHSSlot.isVolatile() &&
+ CGF.hasVolatileMember(E->getLHS()->getType()))
+ LHSSlot.setVolatile(true);
+
CGF.EmitAggExpr(E->getRHS(), LHSSlot);
// Copy into the destination if the assignment isn't ignored.
@@ -931,24 +1080,34 @@ AggExprEmitter::EmitInitializationToLValue(Expr* E, LValue LV) {
// FIXME: Are initializers affected by volatile?
if (Dest.isZeroed() && isSimpleZero(E, CGF)) {
// Storing "i32 0" to a zero'd memory location is a noop.
- } else if (isa<ImplicitValueInitExpr>(E)) {
- EmitNullInitializationToLValue(LV);
+ return;
+ } else if (isa<ImplicitValueInitExpr>(E) || isa<CXXScalarValueInitExpr>(E)) {
+ return EmitNullInitializationToLValue(LV);
} else if (type->isReferenceType()) {
RValue RV = CGF.EmitReferenceBindingToExpr(E, /*InitializedDecl=*/0);
- CGF.EmitStoreThroughLValue(RV, LV);
- } else if (type->isAnyComplexType()) {
- CGF.EmitComplexExprIntoAddr(E, LV.getAddress(), false);
- } else if (CGF.hasAggregateLLVMType(type)) {
+ return CGF.EmitStoreThroughLValue(RV, LV);
+ }
+
+ switch (CGF.getEvaluationKind(type)) {
+ case TEK_Complex:
+ CGF.EmitComplexExprIntoLValue(E, LV, /*isInit*/ true);
+ return;
+ case TEK_Aggregate:
CGF.EmitAggExpr(E, AggValueSlot::forLValue(LV,
AggValueSlot::IsDestructed,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased,
Dest.isZeroed()));
- } else if (LV.isSimple()) {
- CGF.EmitScalarInit(E, /*D=*/0, LV, /*Captured=*/false);
- } else {
- CGF.EmitStoreThroughLValue(RValue::get(CGF.EmitScalarExpr(E)), LV);
+ return;
+ case TEK_Scalar:
+ if (LV.isSimple()) {
+ CGF.EmitScalarInit(E, /*D=*/0, LV, /*Captured=*/false);
+ } else {
+ CGF.EmitStoreThroughLValue(RValue::get(CGF.EmitScalarExpr(E)), LV);
+ }
+ return;
}
+ llvm_unreachable("bad evaluation kind");
}
void AggExprEmitter::EmitNullInitializationToLValue(LValue lv) {
@@ -959,9 +1118,9 @@ void AggExprEmitter::EmitNullInitializationToLValue(LValue lv) {
if (Dest.isZeroed() && CGF.getTypes().isZeroInitializable(type))
return;
- if (!CGF.hasAggregateLLVMType(type)) {
- // For non-aggregates, we can store zero.
- llvm::Value *null = llvm::Constant::getNullValue(CGF.ConvertType(type));
+ if (CGF.hasScalarEvaluationKind(type)) {
+ // For non-aggregates, we can store the appropriate null constant.
+ llvm::Value *null = CGF.CGM.EmitNullConstant(type);
// Note that the following is not equivalent to
// EmitStoreThroughBitfieldLValue for ARC types.
if (lv.isBitField()) {
@@ -1250,7 +1409,7 @@ static void CheckAggExprForMemSetUse(AggValueSlot &Slot, const Expr *E,
/// the value of the aggregate expression is not needed. If VolatileDest is
/// true, DestPtr cannot be 0.
void CodeGenFunction::EmitAggExpr(const Expr *E, AggValueSlot Slot) {
- assert(E && hasAggregateLLVMType(E->getType()) &&
+ assert(E && hasAggregateEvaluationKind(E->getType()) &&
"Invalid aggregate expression to emit");
assert((Slot.getAddr() != 0 || Slot.isIgnored()) &&
"slot has bits but no address");
@@ -1262,7 +1421,7 @@ void CodeGenFunction::EmitAggExpr(const Expr *E, AggValueSlot Slot) {
}
LValue CodeGenFunction::EmitAggExprToLValue(const Expr *E) {
- assert(hasAggregateLLVMType(E->getType()) && "Invalid argument!");
+ assert(hasAggregateEvaluationKind(E->getType()) && "Invalid argument!");
llvm::Value *Temp = CreateMemTemp(E->getType());
LValue LV = MakeAddrLValue(Temp, E->getType());
EmitAggExpr(E, AggValueSlot::forLValue(LV, AggValueSlot::IsNotDestructed,
@@ -1285,7 +1444,7 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr,
Record->hasTrivialCopyAssignment() ||
Record->hasTrivialMoveConstructor() ||
Record->hasTrivialMoveAssignment()) &&
- "Trying to aggregate-copy a type without a trivial copy "
+ "Trying to aggregate-copy a type without a trivial copy/move "
"constructor or assignment operator");
// Ignore empty classes in C++.
if (Record->isEmpty())
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index 7f640f6..83c8ace 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -11,13 +11,13 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Frontend/CodeGenOptions.h"
#include "CodeGenFunction.h"
#include "CGCUDARuntime.h"
#include "CGCXXABI.h"
-#include "CGObjCRuntime.h"
#include "CGDebugInfo.h"
-#include "llvm/Intrinsics.h"
+#include "CGObjCRuntime.h"
+#include "clang/Frontend/CodeGenOptions.h"
+#include "llvm/IR/Intrinsics.h"
#include "llvm/Support/CallSite.h"
using namespace clang;
@@ -28,7 +28,8 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
llvm::Value *Callee,
ReturnValueSlot ReturnValue,
llvm::Value *This,
- llvm::Value *VTT,
+ llvm::Value *ImplicitParam,
+ QualType ImplicitParamTy,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd) {
assert(MD->isInstance() &&
@@ -46,10 +47,9 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
// Push the this ptr.
Args.add(RValue::get(This), MD->getThisType(getContext()));
- // If there is a VTT parameter, emit it.
- if (VTT) {
- QualType T = getContext().getPointerType(getContext().VoidPtrTy);
- Args.add(RValue::get(VTT), T);
+ // If there is an implicit parameter (e.g. VTT), emit it.
+ if (ImplicitParam) {
+ Args.add(RValue::get(ImplicitParam), ImplicitParamTy);
}
const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
@@ -284,7 +284,12 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
llvm::Value *Callee;
if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD)) {
if (UseVirtualCall) {
- Callee = BuildVirtualCall(Dtor, Dtor_Complete, This, Ty);
+ assert(CE->arg_begin() == CE->arg_end() &&
+ "Virtual destructor shouldn't have explicit parameters");
+ return CGM.getCXXABI().EmitVirtualDestructorCall(*this, Dtor,
+ Dtor_Complete,
+ CE->getExprLoc(),
+ ReturnValue, This);
} else {
if (getLangOpts().AppleKext &&
MD->isVirtual() &&
@@ -316,7 +321,8 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
}
return EmitCXXMemberCall(MD, CE->getExprLoc(), Callee, ReturnValue, This,
- /*VTT=*/0, CE->arg_begin(), CE->arg_end());
+ /*ImplicitParam=*/0, QualType(),
+ CE->arg_begin(), CE->arg_end());
}
RValue
@@ -388,7 +394,8 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
llvm::Value *Callee = EmitCXXOperatorMemberCallee(E, MD, This);
return EmitCXXMemberCall(MD, E->getExprLoc(), Callee, ReturnValue, This,
- /*VTT=*/0, E->arg_begin() + 1, E->arg_end());
+ /*ImplicitParam=*/0, QualType(),
+ E->arg_begin() + 1, E->arg_end());
}
RValue CodeGenFunction::EmitCUDAKernelCallExpr(const CUDAKernelCallExpr *E,
@@ -485,11 +492,13 @@ CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E,
} else {
CXXCtorType Type = Ctor_Complete;
bool ForVirtualBase = false;
-
+ bool Delegating = false;
+
switch (E->getConstructionKind()) {
case CXXConstructExpr::CK_Delegating:
// We should be emitting a constructor; GlobalDecl will assert this
Type = CurGD.getCtorType();
+ Delegating = true;
break;
case CXXConstructExpr::CK_Complete:
@@ -505,7 +514,7 @@ CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E,
}
// Call the constructor.
- EmitCXXConstructorCall(CD, Type, ForVirtualBase, Dest.getAddr(),
+ EmitCXXConstructorCall(CD, Type, ForVirtualBase, Delegating, Dest.getAddr(),
E->arg_begin(), E->arg_end());
}
}
@@ -811,14 +820,18 @@ static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const Expr *Init,
QualType AllocType, llvm::Value *NewPtr) {
CharUnits Alignment = CGF.getContext().getTypeAlignInChars(AllocType);
- if (!CGF.hasAggregateLLVMType(AllocType))
+ switch (CGF.getEvaluationKind(AllocType)) {
+ case TEK_Scalar:
CGF.EmitScalarInit(Init, 0, CGF.MakeAddrLValue(NewPtr, AllocType,
Alignment),
false);
- else if (AllocType->isAnyComplexType())
- CGF.EmitComplexExprIntoAddr(Init, NewPtr,
- AllocType.isVolatileQualified());
- else {
+ return;
+ case TEK_Complex:
+ CGF.EmitComplexExprIntoLValue(Init, CGF.MakeAddrLValue(NewPtr, AllocType,
+ Alignment),
+ /*isInit*/ true);
+ return;
+ case TEK_Aggregate: {
AggValueSlot Slot
= AggValueSlot::forAddr(NewPtr, Alignment, AllocType.getQualifiers(),
AggValueSlot::IsDestructed,
@@ -827,7 +840,10 @@ static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const Expr *Init,
CGF.EmitAggExpr(Init, Slot);
CGF.MaybeEmitStdInitializerListCleanup(NewPtr, Init);
+ return;
+ }
}
+ llvm_unreachable("bad evaluation kind");
}
void
@@ -1395,18 +1411,12 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
completePtr, OperatorDelete,
ElementType);
}
-
- llvm::Type *Ty =
- CGF.getTypes().GetFunctionType(
- CGF.getTypes().arrangeCXXDestructor(Dtor, Dtor_Complete));
-
- llvm::Value *Callee
- = CGF.BuildVirtualCall(Dtor,
- UseGlobalDelete? Dtor_Complete : Dtor_Deleting,
- Ptr, Ty);
+
// FIXME: Provide a source location here.
- CGF.EmitCXXMemberCall(Dtor, SourceLocation(), Callee, ReturnValueSlot(),
- Ptr, /*VTT=*/0, 0, 0);
+ CXXDtorType DtorType = UseGlobalDelete ? Dtor_Complete : Dtor_Deleting;
+ CGF.CGM.getCXXABI().EmitVirtualDestructorCall(CGF, Dtor, DtorType,
+ SourceLocation(),
+ ReturnValueSlot(), Ptr);
if (UseGlobalDelete) {
CGF.PopCleanupBlock();
@@ -1425,7 +1435,9 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
if (Dtor)
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete,
- /*ForVirtualBase=*/false, Ptr);
+ /*ForVirtualBase=*/false,
+ /*Delegating=*/false,
+ Ptr);
else if (CGF.getLangOpts().ObjCAutoRefCount &&
ElementType->isObjCLifetimeType()) {
switch (ElementType.getObjCLifetime()) {
@@ -1439,7 +1451,7 @@ static void EmitObjectDelete(CodeGenFunction &CGF,
llvm::Value *PtrValue = CGF.Builder.CreateLoad(Ptr,
ElementType.isVolatileQualified());
- CGF.EmitARCRelease(PtrValue, /*precise*/ true);
+ CGF.EmitARCRelease(PtrValue, ARCPreciseLifetime);
break;
}
@@ -1612,7 +1624,7 @@ static llvm::Constant *getBadTypeidFn(CodeGenFunction &CGF) {
static void EmitBadTypeidCall(CodeGenFunction &CGF) {
llvm::Value *Fn = getBadTypeidFn(CGF);
- CGF.EmitCallOrInvoke(Fn).setDoesNotReturn();
+ CGF.EmitRuntimeCallOrInvoke(Fn).setDoesNotReturn();
CGF.Builder.CreateUnreachable();
}
@@ -1685,11 +1697,16 @@ static llvm::Constant *getDynamicCastFn(CodeGenFunction &CGF) {
CGF.ConvertType(CGF.getContext().getPointerDiffType());
llvm::Type *Args[4] = { Int8PtrTy, Int8PtrTy, Int8PtrTy, PtrDiffTy };
-
- llvm::FunctionType *FTy =
- llvm::FunctionType::get(Int8PtrTy, Args, false);
-
- return CGF.CGM.CreateRuntimeFunction(FTy, "__dynamic_cast");
+
+ llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, Args, false);
+
+ // Mark the function as nounwind readonly.
+ llvm::Attribute::AttrKind FuncAttrs[] = { llvm::Attribute::NoUnwind,
+ llvm::Attribute::ReadOnly };
+ llvm::AttributeSet Attrs = llvm::AttributeSet::get(
+ CGF.getLLVMContext(), llvm::AttributeSet::FunctionIndex, FuncAttrs);
+
+ return CGF.CGM.CreateRuntimeFunction(FTy, "__dynamic_cast", Attrs);
}
static llvm::Constant *getBadCastFn(CodeGenFunction &CGF) {
@@ -1700,10 +1717,62 @@ static llvm::Constant *getBadCastFn(CodeGenFunction &CGF) {
static void EmitBadCastCall(CodeGenFunction &CGF) {
llvm::Value *Fn = getBadCastFn(CGF);
- CGF.EmitCallOrInvoke(Fn).setDoesNotReturn();
+ CGF.EmitRuntimeCallOrInvoke(Fn).setDoesNotReturn();
CGF.Builder.CreateUnreachable();
}
+/// \brief Compute the src2dst_offset hint as described in the
+/// Itanium C++ ABI [2.9.7]
+static CharUnits computeOffsetHint(ASTContext &Context,
+ const CXXRecordDecl *Src,
+ const CXXRecordDecl *Dst) {
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+ /*DetectVirtual=*/false);
+
+ // If Dst is not derived from Src we can skip the whole computation below and
+ // return that Src is not a public base of Dst. Record all inheritance paths.
+ if (!Dst->isDerivedFrom(Src, Paths))
+ return CharUnits::fromQuantity(-2ULL);
+
+ unsigned NumPublicPaths = 0;
+ CharUnits Offset;
+
+ // Now walk all possible inheritance paths.
+ for (CXXBasePaths::paths_iterator I = Paths.begin(), E = Paths.end();
+ I != E; ++I) {
+ if (I->Access != AS_public) // Ignore non-public inheritance.
+ continue;
+
+ ++NumPublicPaths;
+
+ for (CXXBasePath::iterator J = I->begin(), JE = I->end(); J != JE; ++J) {
+ // If the path contains a virtual base class we can't give any hint.
+ // -1: no hint.
+ if (J->Base->isVirtual())
+ return CharUnits::fromQuantity(-1ULL);
+
+ if (NumPublicPaths > 1) // Won't use offsets, skip computation.
+ continue;
+
+ // Accumulate the base class offsets.
+ const ASTRecordLayout &L = Context.getASTRecordLayout(J->Class);
+ Offset += L.getBaseClassOffset(J->Base->getType()->getAsCXXRecordDecl());
+ }
+ }
+
+ // -2: Src is not a public base of Dst.
+ if (NumPublicPaths == 0)
+ return CharUnits::fromQuantity(-2ULL);
+
+ // -3: Src is a multiple public base type but never a virtual base type.
+ if (NumPublicPaths > 1)
+ return CharUnits::fromQuantity(-3ULL);
+
+ // Otherwise, the Src type is a unique public nonvirtual base type of Dst.
+ // Return the offset of Src from the origin of Dst.
+ return Offset;
+}
+
static llvm::Value *
EmitDynamicCastCall(CodeGenFunction &CGF, llvm::Value *Value,
QualType SrcTy, QualType DestTy,
@@ -1753,13 +1822,19 @@ EmitDynamicCastCall(CodeGenFunction &CGF, llvm::Value *Value,
llvm::Value *DestRTTI =
CGF.CGM.GetAddrOfRTTIDescriptor(DestRecordTy.getUnqualifiedType());
- // FIXME: Actually compute a hint here.
- llvm::Value *OffsetHint = llvm::ConstantInt::get(PtrDiffLTy, -1ULL);
+ // Compute the offset hint.
+ const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();
+ const CXXRecordDecl *DestDecl = DestRecordTy->getAsCXXRecordDecl();
+ llvm::Value *OffsetHint =
+ llvm::ConstantInt::get(PtrDiffLTy,
+ computeOffsetHint(CGF.getContext(), SrcDecl,
+ DestDecl).getQuantity());
// Emit the call to __dynamic_cast.
Value = CGF.EmitCastToVoidPtr(Value);
- Value = CGF.Builder.CreateCall4(getDynamicCastFn(CGF), Value,
- SrcRTTI, DestRTTI, OffsetHint);
+
+ llvm::Value *args[] = { Value, SrcRTTI, DestRTTI, OffsetHint };
+ Value = CGF.EmitNounwindRuntimeCall(getDynamicCastFn(CGF), args);
Value = CGF.Builder.CreateBitCast(Value, DestLTy);
/// C++ [expr.dynamic.cast]p9:
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index 66b6f86..5fc73aa 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -15,9 +15,9 @@
#include "CodeGenModule.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/StmtVisitor.h"
-#include "llvm/Constants.h"
-#include "llvm/Function.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Function.h"
using namespace clang;
using namespace CodeGen;
@@ -27,12 +27,21 @@ using namespace CodeGen;
typedef CodeGenFunction::ComplexPairTy ComplexPairTy;
+/// Return the complex type that we are meant to emit.
+static const ComplexType *getComplexType(QualType type) {
+ type = type.getCanonicalType();
+ if (const ComplexType *comp = dyn_cast<ComplexType>(type)) {
+ return comp;
+ } else {
+ return cast<ComplexType>(cast<AtomicType>(type)->getValueType());
+ }
+}
+
namespace {
class ComplexExprEmitter
: public StmtVisitor<ComplexExprEmitter, ComplexPairTy> {
CodeGenFunction &CGF;
CGBuilderTy &Builder;
- // True is we should ignore the value of a
bool IgnoreReal;
bool IgnoreImag;
public:
@@ -63,25 +72,11 @@ public:
return EmitLoadOfLValue(CGF.EmitLValue(E));
}
- ComplexPairTy EmitLoadOfLValue(LValue LV) {
- assert(LV.isSimple() && "complex l-value must be simple");
- return EmitLoadOfComplex(LV.getAddress(), LV.isVolatileQualified());
- }
-
- /// EmitLoadOfComplex - Given a pointer to a complex value, emit code to load
- /// the real and imaginary pieces.
- ComplexPairTy EmitLoadOfComplex(llvm::Value *SrcPtr, bool isVolatile);
-
- /// EmitStoreThroughLValue - Given an l-value of complex type, store
- /// a complex number into it.
- void EmitStoreThroughLValue(ComplexPairTy Val, LValue LV) {
- assert(LV.isSimple() && "complex l-value must be simple");
- return EmitStoreOfComplex(Val, LV.getAddress(), LV.isVolatileQualified());
- }
+ ComplexPairTy EmitLoadOfLValue(LValue LV);
/// EmitStoreOfComplex - Store the specified real/imag parts into the
/// specified value pointer.
- void EmitStoreOfComplex(ComplexPairTy Val, llvm::Value *ResPtr, bool isVol);
+ void EmitStoreOfComplex(ComplexPairTy Val, LValue LV, bool isInit);
/// EmitComplexToComplexCast - Emit a cast from complex value Val to DestType.
ComplexPairTy EmitComplexToComplexCast(ComplexPairTy Val, QualType SrcType,
@@ -194,13 +189,13 @@ public:
}
ComplexPairTy VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) {
assert(E->getType()->isAnyComplexType() && "Expected complex type!");
- QualType Elem = E->getType()->getAs<ComplexType>()->getElementType();
+ QualType Elem = E->getType()->castAs<ComplexType>()->getElementType();
llvm::Constant *Null = llvm::Constant::getNullValue(CGF.ConvertType(Elem));
return ComplexPairTy(Null, Null);
}
ComplexPairTy VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) {
assert(E->getType()->isAnyComplexType() && "Expected complex type!");
- QualType Elem = E->getType()->getAs<ComplexType>()->getElementType();
+ QualType Elem = E->getType()->castAs<ComplexType>()->getElementType();
llvm::Constant *Null =
llvm::Constant::getNullValue(CGF.ConvertType(Elem));
return ComplexPairTy(Null, Null);
@@ -286,10 +281,16 @@ public:
// Utilities
//===----------------------------------------------------------------------===//
-/// EmitLoadOfComplex - Given an RValue reference for a complex, emit code to
+/// EmitLoadOfLValue - Given an RValue reference for a complex, emit code to
/// load the real and imaginary pieces, returning them as Real/Imag.
-ComplexPairTy ComplexExprEmitter::EmitLoadOfComplex(llvm::Value *SrcPtr,
- bool isVolatile) {
+ComplexPairTy ComplexExprEmitter::EmitLoadOfLValue(LValue lvalue) {
+ assert(lvalue.isSimple() && "non-simple complex l-value?");
+ if (lvalue.getType()->isAtomicType())
+ return CGF.EmitAtomicLoad(lvalue).getComplexVal();
+
+ llvm::Value *SrcPtr = lvalue.getAddress();
+ bool isVolatile = lvalue.isVolatileQualified();
+
llvm::Value *Real=0, *Imag=0;
if (!IgnoreReal || isVolatile) {
@@ -308,13 +309,19 @@ ComplexPairTy ComplexExprEmitter::EmitLoadOfComplex(llvm::Value *SrcPtr,
/// EmitStoreOfComplex - Store the specified real/imag parts into the
/// specified value pointer.
-void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val, llvm::Value *Ptr,
- bool isVolatile) {
+void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val,
+ LValue lvalue,
+ bool isInit) {
+ if (lvalue.getType()->isAtomicType())
+ return CGF.EmitAtomicStore(RValue::getComplex(Val), lvalue, isInit);
+
+ llvm::Value *Ptr = lvalue.getAddress();
llvm::Value *RealPtr = Builder.CreateStructGEP(Ptr, 0, "real");
llvm::Value *ImagPtr = Builder.CreateStructGEP(Ptr, 1, "imag");
- Builder.CreateStore(Val.first, RealPtr, isVolatile);
- Builder.CreateStore(Val.second, ImagPtr, isVolatile);
+ // TODO: alignment
+ Builder.CreateStore(Val.first, RealPtr, lvalue.isVolatileQualified());
+ Builder.CreateStore(Val.second, ImagPtr, lvalue.isVolatileQualified());
}
@@ -326,7 +333,7 @@ void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val, llvm::Value *Ptr,
ComplexPairTy ComplexExprEmitter::VisitExpr(Expr *E) {
CGF.ErrorUnsupported(E, "complex expression");
llvm::Type *EltTy =
- CGF.ConvertType(E->getType()->getAs<ComplexType>()->getElementType());
+ CGF.ConvertType(getComplexType(E->getType())->getElementType());
llvm::Value *U = llvm::UndefValue::get(EltTy);
return ComplexPairTy(U, U);
}
@@ -355,8 +362,8 @@ ComplexPairTy ComplexExprEmitter::EmitComplexToComplexCast(ComplexPairTy Val,
QualType SrcType,
QualType DestType) {
// Get the src/dest element type.
- SrcType = SrcType->getAs<ComplexType>()->getElementType();
- DestType = DestType->getAs<ComplexType>()->getElementType();
+ SrcType = SrcType->castAs<ComplexType>()->getElementType();
+ DestType = DestType->castAs<ComplexType>()->getElementType();
// C99 6.3.1.6: When a value of complex type is converted to another
// complex type, both the real and imaginary parts follow the conversion
@@ -381,11 +388,12 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
return Visit(Op);
case CK_LValueBitCast: {
- llvm::Value *V = CGF.EmitLValue(Op).getAddress();
+ LValue origLV = CGF.EmitLValue(Op);
+ llvm::Value *V = origLV.getAddress();
V = Builder.CreateBitCast(V,
CGF.ConvertType(CGF.getContext().getPointerType(DestTy)));
- // FIXME: Are the qualifiers correct here?
- return EmitLoadOfComplex(V, DestTy.isVolatileQualified());
+ return EmitLoadOfLValue(CGF.MakeAddrLValue(V, DestTy,
+ origLV.getAlignment()));
}
case CK_BitCast:
@@ -428,6 +436,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
case CK_ARCExtendBlockObject:
case CK_CopyAndAutoreleaseBlockObject:
case CK_BuiltinFnToFnPtr:
+ case CK_ZeroToOCLEvent:
llvm_unreachable("invalid cast kind for complex value");
case CK_FloatingRealToComplex:
@@ -435,7 +444,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
llvm::Value *Elt = CGF.EmitScalarExpr(Op);
// Convert the input element to the element type of the complex.
- DestTy = DestTy->getAs<ComplexType>()->getElementType();
+ DestTy = DestTy->castAs<ComplexType>()->getElementType();
Elt = CGF.EmitScalarConversion(Elt, Op->getType(), DestTy);
// Return (realval, 0).
@@ -568,7 +577,7 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) {
llvm::Value *Tmp8 = Builder.CreateMul(LHSr, RHSi); // a*d
llvm::Value *Tmp9 = Builder.CreateSub(Tmp7, Tmp8); // bc-ad
- if (Op.Ty->getAs<ComplexType>()->getElementType()->isUnsignedIntegerType()) {
+ if (Op.Ty->castAs<ComplexType>()->getElementType()->isUnsignedIntegerType()) {
DSTr = Builder.CreateUDiv(Tmp3, Tmp6);
DSTi = Builder.CreateUDiv(Tmp9, Tmp6);
} else {
@@ -628,7 +637,7 @@ EmitCompoundAssignLValue(const CompoundAssignOperator *E,
Val = Result;
// Store the result value into the LHS lvalue.
- EmitStoreThroughLValue(Result, LHS);
+ EmitStoreOfComplex(Result, LHS, /*isInit*/ false);
return LHS;
}
@@ -648,7 +657,7 @@ EmitCompoundAssign(const CompoundAssignOperator *E,
if (!LV.isVolatileQualified())
return Val;
- return EmitLoadOfComplex(LV.getAddress(), LV.isVolatileQualified());
+ return EmitLoadOfLValue(LV);
}
LValue ComplexExprEmitter::EmitBinAssignLValue(const BinaryOperator *E,
@@ -666,7 +675,7 @@ LValue ComplexExprEmitter::EmitBinAssignLValue(const BinaryOperator *E,
LValue LHS = CGF.EmitLValue(E->getLHS());
// Store the result value into the LHS lvalue.
- EmitStoreThroughLValue(Val, LHS);
+ EmitStoreOfComplex(Val, LHS, /*isInit*/ false);
return LHS;
}
@@ -683,7 +692,7 @@ ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) {
if (!LV.isVolatileQualified())
return Val;
- return EmitLoadOfComplex(LV.getAddress(), LV.isVolatileQualified());
+ return EmitLoadOfLValue(LV);
}
ComplexPairTy ComplexExprEmitter::VisitBinComma(const BinaryOperator *E) {
@@ -754,7 +763,7 @@ ComplexPairTy ComplexExprEmitter::VisitInitListExpr(InitListExpr *E) {
// Empty init list intializes to null
assert(E->getNumInits() == 0 && "Unexpected number of inits");
- QualType Ty = E->getType()->getAs<ComplexType>()->getElementType();
+ QualType Ty = E->getType()->castAs<ComplexType>()->getElementType();
llvm::Type* LTy = CGF.ConvertType(Ty);
llvm::Value* zeroConstant = llvm::Constant::getNullValue(LTy);
return ComplexPairTy(zeroConstant, zeroConstant);
@@ -767,13 +776,13 @@ ComplexPairTy ComplexExprEmitter::VisitVAArgExpr(VAArgExpr *E) {
if (!ArgPtr) {
CGF.ErrorUnsupported(E, "complex va_arg expression");
llvm::Type *EltTy =
- CGF.ConvertType(E->getType()->getAs<ComplexType>()->getElementType());
+ CGF.ConvertType(E->getType()->castAs<ComplexType>()->getElementType());
llvm::Value *U = llvm::UndefValue::get(EltTy);
return ComplexPairTy(U, U);
}
- // FIXME Volatility.
- return EmitLoadOfComplex(ArgPtr, false);
+ return EmitLoadOfLValue(
+ CGF.MakeNaturalAlignAddrLValue(ArgPtr, E->getType()));
}
//===----------------------------------------------------------------------===//
@@ -784,36 +793,31 @@ ComplexPairTy ComplexExprEmitter::VisitVAArgExpr(VAArgExpr *E) {
/// complex type, ignoring the result.
ComplexPairTy CodeGenFunction::EmitComplexExpr(const Expr *E, bool IgnoreReal,
bool IgnoreImag) {
- assert(E && E->getType()->isAnyComplexType() &&
+ assert(E && getComplexType(E->getType()) &&
"Invalid complex expression to emit");
return ComplexExprEmitter(*this, IgnoreReal, IgnoreImag)
.Visit(const_cast<Expr*>(E));
}
-/// EmitComplexExprIntoAddr - Emit the computation of the specified expression
-/// of complex type, storing into the specified Value*.
-void CodeGenFunction::EmitComplexExprIntoAddr(const Expr *E,
- llvm::Value *DestAddr,
- bool DestIsVolatile) {
- assert(E && E->getType()->isAnyComplexType() &&
+void CodeGenFunction::EmitComplexExprIntoLValue(const Expr *E, LValue dest,
+ bool isInit) {
+ assert(E && getComplexType(E->getType()) &&
"Invalid complex expression to emit");
ComplexExprEmitter Emitter(*this);
ComplexPairTy Val = Emitter.Visit(const_cast<Expr*>(E));
- Emitter.EmitStoreOfComplex(Val, DestAddr, DestIsVolatile);
+ Emitter.EmitStoreOfComplex(Val, dest, isInit);
}
-/// StoreComplexToAddr - Store a complex number into the specified address.
-void CodeGenFunction::StoreComplexToAddr(ComplexPairTy V,
- llvm::Value *DestAddr,
- bool DestIsVolatile) {
- ComplexExprEmitter(*this).EmitStoreOfComplex(V, DestAddr, DestIsVolatile);
+/// EmitStoreOfComplex - Store a complex number into the specified l-value.
+void CodeGenFunction::EmitStoreOfComplex(ComplexPairTy V, LValue dest,
+ bool isInit) {
+ ComplexExprEmitter(*this).EmitStoreOfComplex(V, dest, isInit);
}
-/// LoadComplexFromAddr - Load a complex number from the specified address.
-ComplexPairTy CodeGenFunction::LoadComplexFromAddr(llvm::Value *SrcAddr,
- bool SrcIsVolatile) {
- return ComplexExprEmitter(*this).EmitLoadOfComplex(SrcAddr, SrcIsVolatile);
+/// EmitLoadOfComplex - Load a complex number from the specified address.
+ComplexPairTy CodeGenFunction::EmitLoadOfComplex(LValue src) {
+ return ComplexExprEmitter(*this).EmitLoadOfLValue(src);
}
LValue CodeGenFunction::EmitComplexAssignmentLValue(const BinaryOperator *E) {
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 206f74a..faaf646 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -12,19 +12,19 @@
//===----------------------------------------------------------------------===//
#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
#include "CGCXXABI.h"
#include "CGObjCRuntime.h"
#include "CGRecordLayout.h"
+#include "CodeGenModule.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/Builtins.h"
-#include "llvm/Constants.h"
-#include "llvm/Function.h"
-#include "llvm/GlobalVariable.h"
-#include "llvm/DataLayout.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/GlobalVariable.h"
using namespace clang;
using namespace CodeGen;
@@ -455,7 +455,7 @@ void ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD,
// Accumulate and sort bases, in order to visit them in address order, which
// may not be the same as declaration order.
- llvm::SmallVector<BaseInfo, 8> Bases;
+ SmallVector<BaseInfo, 8> Bases;
Bases.reserve(CD->getNumBases());
unsigned BaseNo = 0;
for (CXXRecordDecl::base_class_const_iterator Base = CD->bases_begin(),
@@ -747,6 +747,7 @@ public:
case CK_FloatingToIntegral:
case CK_FloatingToBoolean:
case CK_FloatingCast:
+ case CK_ZeroToOCLEvent:
return 0;
}
llvm_unreachable("Invalid CastKind");
@@ -905,10 +906,8 @@ public:
if (!VD->hasLocalStorage()) {
if (VD->isFileVarDecl() || VD->hasExternalStorage())
return CGM.GetAddrOfGlobalVar(VD);
- else if (VD->isLocalVarDecl()) {
- assert(CGF && "Can't access static local vars without CGF");
- return CGF->GetAddrOfStaticLocalVar(VD);
- }
+ else if (VD->isLocalVarDecl())
+ return CGM.getStaticLocalDeclAddress(VD);
}
}
return 0;
@@ -1008,6 +1007,22 @@ public:
llvm::Constant *CodeGenModule::EmitConstantInit(const VarDecl &D,
CodeGenFunction *CGF) {
+ // Make a quick check if variable can be default NULL initialized
+ // and avoid going through rest of code which may do, for c++11,
+ // initialization of memory to all NULLs.
+ if (!D.hasLocalStorage()) {
+ QualType Ty = D.getType();
+ if (Ty->isArrayType())
+ Ty = Context.getBaseElementType(Ty);
+ if (Ty->isRecordType())
+ if (const CXXConstructExpr *E =
+ dyn_cast_or_null<CXXConstructExpr>(D.getInit())) {
+ const CXXConstructorDecl *CD = E->getConstructor();
+ if (CD->isTrivial() && CD->isDefaultConstructor())
+ return EmitNullConstant(D.getType());
+ }
+ }
+
if (const APValue *Value = D.evaluateValue())
return EmitConstantValueForMemory(*Value, D.getType(), CGF);
@@ -1124,7 +1139,8 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value,
}
case APValue::Float: {
const llvm::APFloat &Init = Value.getFloat();
- if (&Init.getSemantics() == &llvm::APFloat::IEEEhalf)
+ if (&Init.getSemantics() == &llvm::APFloat::IEEEhalf &&
+ !Context.getLangOpts().NativeHalfType)
return llvm::ConstantInt::get(VMContext, Init.bitcastToAPInt());
else
return llvm::ConstantFP::get(VMContext, Init);
@@ -1197,6 +1213,8 @@ llvm::Constant *CodeGenModule::EmitConstantValue(const APValue &Value,
if (I < NumInitElts)
C = EmitConstantValueForMemory(Value.getArrayInitializedElt(I),
CAT->getElementType(), CGF);
+ else
+ assert(Filler && "Missing filler for implicit elements of initializer");
if (I == 0)
CommonElementType = C->getType();
else if (C->getType() != CommonElementType)
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index b429b1d..ffd0eb5 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -11,24 +11,24 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Frontend/CodeGenOptions.h"
#include "CodeGenFunction.h"
#include "CGCXXABI.h"
+#include "CGDebugInfo.h"
#include "CGObjCRuntime.h"
#include "CodeGenModule.h"
-#include "CGDebugInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/TargetInfo.h"
-#include "llvm/Constants.h"
-#include "llvm/Function.h"
-#include "llvm/GlobalVariable.h"
-#include "llvm/Intrinsics.h"
-#include "llvm/Module.h"
+#include "clang/Frontend/CodeGenOptions.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/Module.h"
#include "llvm/Support/CFG.h"
-#include "llvm/DataLayout.h"
#include <cstdarg>
using namespace clang;
@@ -266,7 +266,7 @@ public:
Value *VisitInitListExpr(InitListExpr *E);
Value *VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) {
- return CGF.CGM.EmitNullConstant(E->getType());
+ return EmitNullValue(E->getType());
}
Value *VisitExplicitCastExpr(ExplicitCastExpr *E) {
if (E->getType()->isVariablyModifiedType())
@@ -406,7 +406,7 @@ public:
case LangOptions::SOB_Defined:
return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul");
case LangOptions::SOB_Undefined:
- if (!CGF.getLangOpts().SanitizeSignedIntegerOverflow)
+ if (!CGF.SanOpts->SignedIntegerOverflow)
return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul");
// Fall through.
case LangOptions::SOB_Trapping:
@@ -414,6 +414,9 @@ public:
}
}
+ if (Ops.Ty->isUnsignedIntegerType() && CGF.SanOpts->UnsignedIntegerOverflow)
+ return EmitOverflowCheckedBinOp(Ops);
+
if (Ops.LHS->getType()->isFPOrFPVectorTy())
return Builder.CreateFMul(Ops.LHS, Ops.RHS, "mul");
return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul");
@@ -425,6 +428,8 @@ public:
// Check for undefined division and modulus behaviors.
void EmitUndefinedBehaviorIntegerDivAndRemCheck(const BinOpInfo &Ops,
llvm::Value *Zero,bool isDiv);
+ // Common helper for getting how wide LHS of shift is.
+ static Value *GetWidthMinusOneValue(Value* LHS,Value* RHS);
Value *EmitDiv(const BinOpInfo &Ops);
Value *EmitRem(const BinOpInfo &Ops);
Value *EmitAdd(const BinOpInfo &Ops);
@@ -578,62 +583,93 @@ void ScalarExprEmitter::EmitFloatConversionCheck(Value *OrigSrc,
Check = Builder.CreateAnd(GE, LE);
}
} else {
- // Floating-point to integer or floating-point to floating-point. This has
- // undefined behavior if the source is +-Inf, NaN, or doesn't fit into the
- // destination type.
const llvm::fltSemantics &SrcSema =
CGF.getContext().getFloatTypeSemantics(OrigSrcType);
- APFloat MaxSrc(SrcSema, APFloat::uninitialized);
- APFloat MinSrc(SrcSema, APFloat::uninitialized);
-
if (isa<llvm::IntegerType>(DstTy)) {
+ // Floating-point to integer. This has undefined behavior if the source is
+ // +-Inf, NaN, or doesn't fit into the destination type (after truncation
+ // to an integer).
unsigned Width = CGF.getContext().getIntWidth(DstType);
bool Unsigned = DstType->isUnsignedIntegerOrEnumerationType();
APSInt Min = APSInt::getMinValue(Width, Unsigned);
+ APFloat MinSrc(SrcSema, APFloat::uninitialized);
if (MinSrc.convertFromAPInt(Min, !Unsigned, APFloat::rmTowardZero) &
APFloat::opOverflow)
// Don't need an overflow check for lower bound. Just check for
// -Inf/NaN.
- MinSrc = APFloat::getLargest(SrcSema, true);
+ MinSrc = APFloat::getInf(SrcSema, true);
+ else
+ // Find the largest value which is too small to represent (before
+ // truncation toward zero).
+ MinSrc.subtract(APFloat(SrcSema, 1), APFloat::rmTowardNegative);
APSInt Max = APSInt::getMaxValue(Width, Unsigned);
+ APFloat MaxSrc(SrcSema, APFloat::uninitialized);
if (MaxSrc.convertFromAPInt(Max, !Unsigned, APFloat::rmTowardZero) &
APFloat::opOverflow)
// Don't need an overflow check for upper bound. Just check for
// +Inf/NaN.
- MaxSrc = APFloat::getLargest(SrcSema, false);
+ MaxSrc = APFloat::getInf(SrcSema, false);
+ else
+ // Find the smallest value which is too large to represent (before
+ // truncation toward zero).
+ MaxSrc.add(APFloat(SrcSema, 1), APFloat::rmTowardPositive);
+
+ // If we're converting from __half, convert the range to float to match
+ // the type of src.
+ if (OrigSrcType->isHalfType()) {
+ const llvm::fltSemantics &Sema =
+ CGF.getContext().getFloatTypeSemantics(SrcType);
+ bool IsInexact;
+ MinSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact);
+ MaxSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact);
+ }
+
+ llvm::Value *GE =
+ Builder.CreateFCmpOGT(Src, llvm::ConstantFP::get(VMContext, MinSrc));
+ llvm::Value *LE =
+ Builder.CreateFCmpOLT(Src, llvm::ConstantFP::get(VMContext, MaxSrc));
+ Check = Builder.CreateAnd(GE, LE);
} else {
+ // FIXME: Maybe split this sanitizer out from float-cast-overflow.
+ //
+ // Floating-point to floating-point. This has undefined behavior if the
+ // source is not in the range of representable values of the destination
+ // type. The C and C++ standards are spectacularly unclear here. We
+ // diagnose finite out-of-range conversions, but allow infinities and NaNs
+ // to convert to the corresponding value in the smaller type.
+ //
+ // C11 Annex F gives all such conversions defined behavior for IEC 60559
+ // conforming implementations. Unfortunately, LLVM's fptrunc instruction
+ // does not.
+
+ // Converting from a lower rank to a higher rank can never have
+ // undefined behavior, since higher-rank types must have a superset
+ // of values of lower-rank types.
+ if (CGF.getContext().getFloatingTypeOrder(OrigSrcType, DstType) != 1)
+ return;
+
+ assert(!OrigSrcType->isHalfType() &&
+ "should not check conversion from __half, it has the lowest rank");
+
const llvm::fltSemantics &DstSema =
CGF.getContext().getFloatTypeSemantics(DstType);
- bool IsInexact;
-
- MinSrc = APFloat::getLargest(DstSema, true);
- if (MinSrc.convert(SrcSema, APFloat::rmTowardZero, &IsInexact) &
- APFloat::opOverflow)
- MinSrc = APFloat::getLargest(SrcSema, true);
+ APFloat MinBad = APFloat::getLargest(DstSema, false);
+ APFloat MaxBad = APFloat::getInf(DstSema, false);
- MaxSrc = APFloat::getLargest(DstSema, false);
- if (MaxSrc.convert(SrcSema, APFloat::rmTowardZero, &IsInexact) &
- APFloat::opOverflow)
- MaxSrc = APFloat::getLargest(SrcSema, false);
- }
-
- // If we're converting from __half, convert the range to float to match
- // the type of src.
- if (OrigSrcType->isHalfType()) {
- const llvm::fltSemantics &Sema =
- CGF.getContext().getFloatTypeSemantics(SrcType);
bool IsInexact;
- MinSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact);
- MaxSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact);
+ MinBad.convert(SrcSema, APFloat::rmTowardZero, &IsInexact);
+ MaxBad.convert(SrcSema, APFloat::rmTowardZero, &IsInexact);
+
+ Value *AbsSrc = CGF.EmitNounwindRuntimeCall(
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::fabs, Src->getType()), Src);
+ llvm::Value *GE =
+ Builder.CreateFCmpOGT(AbsSrc, llvm::ConstantFP::get(VMContext, MinBad));
+ llvm::Value *LE =
+ Builder.CreateFCmpOLT(AbsSrc, llvm::ConstantFP::get(VMContext, MaxBad));
+ Check = Builder.CreateNot(Builder.CreateAnd(GE, LE));
}
-
- llvm::Value *GE =
- Builder.CreateFCmpOGE(Src, llvm::ConstantFP::get(VMContext, MinSrc));
- llvm::Value *LE =
- Builder.CreateFCmpOLE(Src, llvm::ConstantFP::get(VMContext, MaxSrc));
- Check = Builder.CreateAnd(GE, LE);
}
// FIXME: Provide a SourceLocation.
@@ -641,7 +677,8 @@ void ScalarExprEmitter::EmitFloatConversionCheck(Value *OrigSrc,
CGF.EmitCheckTypeDescriptor(OrigSrcType),
CGF.EmitCheckTypeDescriptor(DstType)
};
- CGF.EmitCheck(Check, "float_cast_overflow", StaticArgs, OrigSrc);
+ CGF.EmitCheck(Check, "float_cast_overflow", StaticArgs, OrigSrc,
+ CodeGenFunction::CRK_Recoverable);
}
/// EmitScalarConversion - Emit a conversion from the specified type to the
@@ -658,9 +695,8 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
QualType OrigSrcType = SrcType;
llvm::Type *SrcTy = Src->getType();
- // Floating casts might be a bit special: if we're doing casts to / from half
- // FP, we should go via special intrinsics.
- if (SrcType->isHalfType()) {
+ // If casting to/from storage-only half FP, use special intrinsics.
+ if (SrcType->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType) {
Src = Builder.CreateCall(CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16), Src);
SrcType = CGF.getContext().FloatTy;
SrcTy = CGF.FloatTy;
@@ -707,17 +743,9 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
QualType EltTy = DstType->getAs<ExtVectorType>()->getElementType();
llvm::Value *Elt = EmitScalarConversion(Src, SrcType, EltTy);
- // Insert the element in element zero of an undef vector
- llvm::Value *UnV = llvm::UndefValue::get(DstTy);
- llvm::Value *Idx = Builder.getInt32(0);
- UnV = Builder.CreateInsertElement(UnV, Elt, Idx);
-
// Splat the element across to all elements
unsigned NumElements = cast<llvm::VectorType>(DstTy)->getNumElements();
- llvm::Constant *Mask = llvm::ConstantVector::getSplat(NumElements,
- Builder.getInt32(0));
- llvm::Value *Yay = Builder.CreateShuffleVector(UnV, UnV, Mask, "splat");
- return Yay;
+ return Builder.CreateVectorSplat(NumElements, Elt, "splat");
}
// Allow bitcast from vector to integer/fp of the same size.
@@ -731,12 +759,13 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
// An overflowing conversion has undefined behavior if either the source type
// or the destination type is a floating-point type.
- if (CGF.getLangOpts().SanitizeFloatCastOverflow &&
+ if (CGF.SanOpts->FloatCastOverflow &&
(OrigSrcType->isFloatingType() || DstType->isFloatingType()))
- EmitFloatConversionCheck(OrigSrc, OrigSrcType, Src, SrcType, DstType, DstTy);
+ EmitFloatConversionCheck(OrigSrc, OrigSrcType, Src, SrcType, DstType,
+ DstTy);
// Cast to half via float
- if (DstType->isHalfType())
+ if (DstType->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType)
DstTy = CGF.FloatTy;
if (isa<llvm::IntegerType>(SrcTy)) {
@@ -777,7 +806,7 @@ Value *ScalarExprEmitter::
EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src,
QualType SrcTy, QualType DstTy) {
// Get the source element type.
- SrcTy = SrcTy->getAs<ComplexType>()->getElementType();
+ SrcTy = SrcTy->castAs<ComplexType>()->getElementType();
// Handle conversions to bool first, they are special: comparisons against 0.
if (DstTy->isBooleanType()) {
@@ -795,10 +824,7 @@ EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src,
}
Value *ScalarExprEmitter::EmitNullValue(QualType Ty) {
- if (const MemberPointerType *MPT = Ty->getAs<MemberPointerType>())
- return CGF.CGM.getCXXABI().EmitNullMemberPointer(MPT);
-
- return llvm::Constant::getNullValue(ConvertType(Ty));
+ return CGF.EmitFromMemory(CGF.CGM.EmitNullConstant(Ty), Ty);
}
/// \brief Emit a sanitization check for the given "binary" operation (which
@@ -806,8 +832,8 @@ Value *ScalarExprEmitter::EmitNullValue(QualType Ty) {
/// operation). The check passes if \p Check, which is an \c i1, is \c true.
void ScalarExprEmitter::EmitBinOpCheck(Value *Check, const BinOpInfo &Info) {
StringRef CheckName;
- llvm::SmallVector<llvm::Constant *, 4> StaticData;
- llvm::SmallVector<llvm::Value *, 2> DynamicData;
+ SmallVector<llvm::Constant *, 4> StaticData;
+ SmallVector<llvm::Value *, 2> DynamicData;
BinaryOperatorKind Opcode = Info.Opcode;
if (BinaryOperator::isCompoundAssignmentOp(Opcode))
@@ -831,7 +857,7 @@ void ScalarExprEmitter::EmitBinOpCheck(Value *Check, const BinOpInfo &Info) {
} else if (Opcode == BO_Div || Opcode == BO_Rem) {
// Divide or modulo by zero, or signed overflow (eg INT_MAX / -1).
CheckName = "divrem_overflow";
- StaticData.push_back(CGF.EmitCheckTypeDescriptor(Info.E->getType()));
+ StaticData.push_back(CGF.EmitCheckTypeDescriptor(Info.Ty));
} else {
// Signed arithmetic overflow (+, -, *).
switch (Opcode) {
@@ -840,13 +866,14 @@ void ScalarExprEmitter::EmitBinOpCheck(Value *Check, const BinOpInfo &Info) {
case BO_Mul: CheckName = "mul_overflow"; break;
default: llvm_unreachable("unexpected opcode for bin op check");
}
- StaticData.push_back(CGF.EmitCheckTypeDescriptor(Info.E->getType()));
+ StaticData.push_back(CGF.EmitCheckTypeDescriptor(Info.Ty));
}
DynamicData.push_back(Info.LHS);
DynamicData.push_back(Info.RHS);
}
- CGF.EmitCheck(Check, CheckName, StaticData, DynamicData);
+ CGF.EmitCheck(Check, CheckName, StaticData, DynamicData,
+ CodeGenFunction::CRK_Recoverable);
}
//===----------------------------------------------------------------------===//
@@ -990,7 +1017,12 @@ Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
// integer value.
Value *Base = Visit(E->getBase());
Value *Idx = Visit(E->getIdx());
- bool IdxSigned = E->getIdx()->getType()->isSignedIntegerOrEnumerationType();
+ QualType IdxTy = E->getIdx()->getType();
+
+ if (CGF.SanOpts->Bounds)
+ CGF.EmitBoundsCheck(E, E->getBase(), Idx, IdxTy, /*Accessed*/true);
+
+ bool IdxSigned = IdxTy->isSignedIntegerOrEnumerationType();
Idx = Builder.CreateIntCast(Idx, CGF.Int32Ty, IdxSigned, "vecidxcast");
return Builder.CreateExtractElement(Base, Idx, "vecext");
}
@@ -1224,7 +1256,15 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
const CXXRecordDecl *DerivedClassDecl = DestTy->getPointeeCXXRecordDecl();
assert(DerivedClassDecl && "BaseToDerived arg isn't a C++ object pointer!");
- return CGF.GetAddressOfDerivedClass(Visit(E), DerivedClassDecl,
+ llvm::Value *V = Visit(E);
+
+ // C++11 [expr.static.cast]p11: Behavior is undefined if a downcast is
+ // performed and the object is not of the derived type.
+ if (CGF.SanitizePerformTypeCheck)
+ CGF.EmitTypeCheck(CodeGenFunction::TCK_DowncastPointer, CE->getExprLoc(),
+ V, DestTy->getPointeeType());
+
+ return CGF.GetAddressOfDerivedClass(V, DerivedClassDecl,
CE->path_begin(), CE->path_end(),
ShouldNullCheckClassCastValue(CE));
}
@@ -1352,17 +1392,9 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
Elt = EmitScalarConversion(Elt, E->getType(),
DestTy->getAs<VectorType>()->getElementType());
- // Insert the element in element zero of an undef vector
- llvm::Value *UnV = llvm::UndefValue::get(DstTy);
- llvm::Value *Idx = Builder.getInt32(0);
- UnV = Builder.CreateInsertElement(UnV, Elt, Idx);
-
// Splat the element across to all elements
unsigned NumElements = cast<llvm::VectorType>(DstTy)->getNumElements();
- llvm::Constant *Zero = Builder.getInt32(0);
- llvm::Constant *Mask = llvm::ConstantVector::getSplat(NumElements, Zero);
- llvm::Value *Yay = Builder.CreateShuffleVector(UnV, UnV, Mask, "splat");
- return Yay;
+ return Builder.CreateVectorSplat(NumElements, Elt, "splat");;
}
case CK_IntegralCast:
@@ -1394,6 +1426,11 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
return EmitComplexToScalarConversion(V, E->getType(), DestTy);
}
+ case CK_ZeroToOCLEvent: {
+ assert(DestTy->isEventT() && "CK_ZeroToOCLEvent cast on non event type");
+ return llvm::Constant::getNullValue(ConvertType(DestTy));
+ }
+
}
llvm_unreachable("unknown scalar cast");
@@ -1417,7 +1454,7 @@ EmitAddConsiderOverflowBehavior(const UnaryOperator *E,
case LangOptions::SOB_Defined:
return Builder.CreateAdd(InVal, NextVal, IsInc ? "inc" : "dec");
case LangOptions::SOB_Undefined:
- if (!CGF.getLangOpts().SanitizeSignedIntegerOverflow)
+ if (!CGF.SanOpts->SignedIntegerOverflow)
return Builder.CreateNSWAdd(InVal, NextVal, IsInc ? "inc" : "dec");
// Fall through.
case LangOptions::SOB_Trapping:
@@ -1438,21 +1475,60 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
bool isInc, bool isPre) {
QualType type = E->getSubExpr()->getType();
- llvm::Value *value = EmitLoadOfLValue(LV);
- llvm::Value *input = value;
llvm::PHINode *atomicPHI = 0;
+ llvm::Value *value;
+ llvm::Value *input;
int amount = (isInc ? 1 : -1);
if (const AtomicType *atomicTy = type->getAs<AtomicType>()) {
+ type = atomicTy->getValueType();
+ if (isInc && type->isBooleanType()) {
+ llvm::Value *True = CGF.EmitToMemory(Builder.getTrue(), type);
+ if (isPre) {
+ Builder.Insert(new llvm::StoreInst(True,
+ LV.getAddress(), LV.isVolatileQualified(),
+ LV.getAlignment().getQuantity(),
+ llvm::SequentiallyConsistent));
+ return Builder.getTrue();
+ }
+ // For atomic bool increment, we just store true and return it for
+ // preincrement, do an atomic swap with true for postincrement
+ return Builder.CreateAtomicRMW(llvm::AtomicRMWInst::Xchg,
+ LV.getAddress(), True, llvm::SequentiallyConsistent);
+ }
+ // Special case for atomic increment / decrement on integers, emit
+ // atomicrmw instructions. We skip this if we want to be doing overflow
+ // checking, and fall into the slow path with the atomic cmpxchg loop.
+ if (!type->isBooleanType() && type->isIntegerType() &&
+ !(type->isUnsignedIntegerType() &&
+ CGF.SanOpts->UnsignedIntegerOverflow) &&
+ CGF.getLangOpts().getSignedOverflowBehavior() !=
+ LangOptions::SOB_Trapping) {
+ llvm::AtomicRMWInst::BinOp aop = isInc ? llvm::AtomicRMWInst::Add :
+ llvm::AtomicRMWInst::Sub;
+ llvm::Instruction::BinaryOps op = isInc ? llvm::Instruction::Add :
+ llvm::Instruction::Sub;
+ llvm::Value *amt = CGF.EmitToMemory(
+ llvm::ConstantInt::get(ConvertType(type), 1, true), type);
+ llvm::Value *old = Builder.CreateAtomicRMW(aop,
+ LV.getAddress(), amt, llvm::SequentiallyConsistent);
+ return isPre ? Builder.CreateBinOp(op, old, amt) : old;
+ }
+ value = EmitLoadOfLValue(LV);
+ input = value;
+ // For every other atomic operation, we need to emit a load-op-cmpxchg loop
llvm::BasicBlock *startBB = Builder.GetInsertBlock();
llvm::BasicBlock *opBB = CGF.createBasicBlock("atomic_op", CGF.CurFn);
+ value = CGF.EmitToMemory(value, type);
Builder.CreateBr(opBB);
Builder.SetInsertPoint(opBB);
atomicPHI = Builder.CreatePHI(value->getType(), 2);
atomicPHI->addIncoming(value, startBB);
- type = atomicTy->getValueType();
value = atomicPHI;
+ } else {
+ value = EmitLoadOfLValue(LV);
+ input = value;
}
// Special case of integer increment that we have to check first: bool++.
@@ -1472,11 +1548,22 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
// Note that signed integer inc/dec with width less than int can't
// overflow because of promotion rules; we're just eliding a few steps here.
- if (type->isSignedIntegerOrEnumerationType() &&
- value->getType()->getPrimitiveSizeInBits() >=
- CGF.IntTy->getBitWidth())
+ if (value->getType()->getPrimitiveSizeInBits() >=
+ CGF.IntTy->getBitWidth() &&
+ type->isSignedIntegerOrEnumerationType()) {
value = EmitAddConsiderOverflowBehavior(E, value, amt, isInc);
- else
+ } else if (value->getType()->getPrimitiveSizeInBits() >=
+ CGF.IntTy->getBitWidth() && type->isUnsignedIntegerType() &&
+ CGF.SanOpts->UnsignedIntegerOverflow) {
+ BinOpInfo BinOp;
+ BinOp.LHS = value;
+ BinOp.RHS = llvm::ConstantInt::get(value->getType(), 1, false);
+ BinOp.Ty = E->getType();
+ BinOp.Opcode = isInc ? BO_Add : BO_Sub;
+ BinOp.FPContractable = false;
+ BinOp.E = E;
+ value = EmitOverflowCheckedBinOp(BinOp);
+ } else
value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec");
// Next most common: pointer increment.
@@ -1531,7 +1618,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
// Add the inc/dec to the real part.
llvm::Value *amt;
- if (type->isHalfType()) {
+ if (type->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType) {
// Another special case: half FP increment should be done via float
value =
Builder.CreateCall(CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_from_fp16),
@@ -1553,7 +1640,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
}
value = Builder.CreateFAdd(value, amt, isInc ? "inc" : "dec");
- if (type->isHalfType())
+ if (type->isHalfType() && !CGF.getContext().getLangOpts().NativeHalfType)
value =
Builder.CreateCall(CGF.CGM.getIntrinsic(llvm::Intrinsic::convert_to_fp16),
value);
@@ -1579,7 +1666,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
llvm::BasicBlock *opBB = Builder.GetInsertBlock();
llvm::BasicBlock *contBB = CGF.createBasicBlock("atomic_cont", CGF.CurFn);
llvm::Value *old = Builder.CreateAtomicCmpXchg(LV.getAddress(), atomicPHI,
- value, llvm::SequentiallyConsistent);
+ CGF.EmitToMemory(value, type), llvm::SequentiallyConsistent);
atomicPHI->addIncoming(old, opBB);
llvm::Value *success = Builder.CreateICmpEQ(old, atomicPHI);
Builder.CreateCondBr(success, contBB, opBB);
@@ -1624,12 +1711,15 @@ Value *ScalarExprEmitter::VisitUnaryNot(const UnaryOperator *E) {
}
Value *ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) {
-
// Perform vector logical not on comparison with zero vector.
if (E->getType()->isExtVectorType()) {
Value *Oper = Visit(E->getSubExpr());
Value *Zero = llvm::Constant::getNullValue(Oper->getType());
- Value *Result = Builder.CreateICmp(llvm::CmpInst::ICMP_EQ, Oper, Zero, "cmp");
+ Value *Result;
+ if (Oper->getType()->isFPOrFPVectorTy())
+ Result = Builder.CreateFCmp(llvm::CmpInst::FCMP_OEQ, Oper, Zero, "cmp");
+ else
+ Result = Builder.CreateICmp(llvm::CmpInst::ICMP_EQ, Oper, Zero, "cmp");
return Builder.CreateSExt(Result, ConvertType(E->getType()), "sext");
}
@@ -1852,20 +1942,63 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
OpInfo.E = E;
// Load/convert the LHS.
LValue LHSLV = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
- OpInfo.LHS = EmitLoadOfLValue(LHSLV);
llvm::PHINode *atomicPHI = 0;
- if (LHSTy->isAtomicType()) {
+ if (const AtomicType *atomicTy = LHSTy->getAs<AtomicType>()) {
+ QualType type = atomicTy->getValueType();
+ if (!type->isBooleanType() && type->isIntegerType() &&
+ !(type->isUnsignedIntegerType() &&
+ CGF.SanOpts->UnsignedIntegerOverflow) &&
+ CGF.getLangOpts().getSignedOverflowBehavior() !=
+ LangOptions::SOB_Trapping) {
+ llvm::AtomicRMWInst::BinOp aop = llvm::AtomicRMWInst::BAD_BINOP;
+ switch (OpInfo.Opcode) {
+ // We don't have atomicrmw operands for *, %, /, <<, >>
+ case BO_MulAssign: case BO_DivAssign:
+ case BO_RemAssign:
+ case BO_ShlAssign:
+ case BO_ShrAssign:
+ break;
+ case BO_AddAssign:
+ aop = llvm::AtomicRMWInst::Add;
+ break;
+ case BO_SubAssign:
+ aop = llvm::AtomicRMWInst::Sub;
+ break;
+ case BO_AndAssign:
+ aop = llvm::AtomicRMWInst::And;
+ break;
+ case BO_XorAssign:
+ aop = llvm::AtomicRMWInst::Xor;
+ break;
+ case BO_OrAssign:
+ aop = llvm::AtomicRMWInst::Or;
+ break;
+ default:
+ llvm_unreachable("Invalid compound assignment type");
+ }
+ if (aop != llvm::AtomicRMWInst::BAD_BINOP) {
+ llvm::Value *amt = CGF.EmitToMemory(EmitScalarConversion(OpInfo.RHS,
+ E->getRHS()->getType(), LHSTy), LHSTy);
+ Builder.CreateAtomicRMW(aop, LHSLV.getAddress(), amt,
+ llvm::SequentiallyConsistent);
+ return LHSLV;
+ }
+ }
// FIXME: For floating point types, we should be saving and restoring the
// floating point environment in the loop.
llvm::BasicBlock *startBB = Builder.GetInsertBlock();
llvm::BasicBlock *opBB = CGF.createBasicBlock("atomic_op", CGF.CurFn);
+ OpInfo.LHS = EmitLoadOfLValue(LHSLV);
+ OpInfo.LHS = CGF.EmitToMemory(OpInfo.LHS, type);
Builder.CreateBr(opBB);
Builder.SetInsertPoint(opBB);
atomicPHI = Builder.CreatePHI(OpInfo.LHS->getType(), 2);
atomicPHI->addIncoming(OpInfo.LHS, startBB);
OpInfo.LHS = atomicPHI;
}
+ else
+ OpInfo.LHS = EmitLoadOfLValue(LHSLV);
OpInfo.LHS = EmitScalarConversion(OpInfo.LHS, LHSTy,
E->getComputationLHSType());
@@ -1880,7 +2013,7 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
llvm::BasicBlock *opBB = Builder.GetInsertBlock();
llvm::BasicBlock *contBB = CGF.createBasicBlock("atomic_cont", CGF.CurFn);
llvm::Value *old = Builder.CreateAtomicCmpXchg(LHSLV.getAddress(), atomicPHI,
- Result, llvm::SequentiallyConsistent);
+ CGF.EmitToMemory(Result, LHSTy), llvm::SequentiallyConsistent);
atomicPHI->addIncoming(old, opBB);
llvm::Value *success = Builder.CreateICmpEQ(old, atomicPHI);
Builder.CreateCondBr(success, contBB, opBB);
@@ -1926,10 +2059,10 @@ void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck(
const BinOpInfo &Ops, llvm::Value *Zero, bool isDiv) {
llvm::Value *Cond = 0;
- if (CGF.getLangOpts().SanitizeDivideByZero)
+ if (CGF.SanOpts->IntegerDivideByZero)
Cond = Builder.CreateICmpNE(Ops.RHS, Zero);
- if (CGF.getLangOpts().SanitizeSignedIntegerOverflow &&
+ if (CGF.SanOpts->SignedIntegerOverflow &&
Ops.Ty->hasSignedIntegerRepresentation()) {
llvm::IntegerType *Ty = cast<llvm::IntegerType>(Zero->getType());
@@ -1948,16 +2081,17 @@ void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck(
}
Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
- if (CGF.getLangOpts().SanitizeDivideByZero ||
- CGF.getLangOpts().SanitizeSignedIntegerOverflow) {
+ if ((CGF.SanOpts->IntegerDivideByZero ||
+ CGF.SanOpts->SignedIntegerOverflow) &&
+ Ops.Ty->isIntegerType()) {
llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
-
- if (Ops.Ty->isIntegerType())
- EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, true);
- else if (CGF.getLangOpts().SanitizeDivideByZero &&
- Ops.Ty->isRealFloatingType())
- EmitBinOpCheck(Builder.CreateFCmpUNE(Ops.RHS, Zero), Ops);
+ EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, true);
+ } else if (CGF.SanOpts->FloatDivideByZero &&
+ Ops.Ty->isRealFloatingType()) {
+ llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
+ EmitBinOpCheck(Builder.CreateFCmpUNE(Ops.RHS, Zero), Ops);
}
+
if (Ops.LHS->getType()->isFPOrFPVectorTy()) {
llvm::Value *Val = Builder.CreateFDiv(Ops.LHS, Ops.RHS, "div");
if (CGF.getLangOpts().OpenCL) {
@@ -1978,10 +2112,10 @@ Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) {
Value *ScalarExprEmitter::EmitRem(const BinOpInfo &Ops) {
// Rem in C can't be a floating point type: C99 6.5.5p2.
- if (CGF.getLangOpts().SanitizeDivideByZero) {
+ if (CGF.SanOpts->IntegerDivideByZero) {
llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty));
- if (Ops.Ty->isIntegerType())
+ if (Ops.Ty->isIntegerType())
EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, false);
}
@@ -1995,27 +2129,32 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
unsigned IID;
unsigned OpID = 0;
+ bool isSigned = Ops.Ty->isSignedIntegerOrEnumerationType();
switch (Ops.Opcode) {
case BO_Add:
case BO_AddAssign:
OpID = 1;
- IID = llvm::Intrinsic::sadd_with_overflow;
+ IID = isSigned ? llvm::Intrinsic::sadd_with_overflow :
+ llvm::Intrinsic::uadd_with_overflow;
break;
case BO_Sub:
case BO_SubAssign:
OpID = 2;
- IID = llvm::Intrinsic::ssub_with_overflow;
+ IID = isSigned ? llvm::Intrinsic::ssub_with_overflow :
+ llvm::Intrinsic::usub_with_overflow;
break;
case BO_Mul:
case BO_MulAssign:
OpID = 3;
- IID = llvm::Intrinsic::smul_with_overflow;
+ IID = isSigned ? llvm::Intrinsic::smul_with_overflow :
+ llvm::Intrinsic::umul_with_overflow;
break;
default:
llvm_unreachable("Unsupported operation for overflow detection");
}
OpID <<= 1;
- OpID |= 1;
+ if (isSigned)
+ OpID |= 1;
llvm::Type *opTy = CGF.CGM.getTypes().ConvertType(Ops.Ty);
@@ -2031,10 +2170,10 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
if (handlerName->empty()) {
// If the signed-integer-overflow sanitizer is enabled, emit a call to its
// runtime. Otherwise, this is a -ftrapv check, so just emit a trap.
- if (CGF.getLangOpts().SanitizeSignedIntegerOverflow)
+ if (!isSigned || CGF.SanOpts->SignedIntegerOverflow)
EmitBinOpCheck(Builder.CreateNot(overflow), Ops);
else
- CGF.EmitTrapvCheck(Builder.CreateNot(overflow));
+ CGF.EmitTrapCheck(Builder.CreateNot(overflow));
return result;
}
@@ -2065,9 +2204,14 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) {
// Call the handler with the two arguments, the operation, and the size of
// the result.
- llvm::Value *handlerResult = Builder.CreateCall4(handler, lhs, rhs,
- Builder.getInt8(OpID),
- Builder.getInt8(cast<llvm::IntegerType>(opTy)->getBitWidth()));
+ llvm::Value *handlerArgs[] = {
+ lhs,
+ rhs,
+ Builder.getInt8(OpID),
+ Builder.getInt8(cast<llvm::IntegerType>(opTy)->getBitWidth())
+ };
+ llvm::Value *handlerResult =
+ CGF.EmitNounwindRuntimeCall(handler, handlerArgs);
// Truncate the result back to the desired size.
handlerResult = Builder.CreateTrunc(handlerResult, opTy);
@@ -2113,6 +2257,10 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
if (isSubtraction)
index = CGF.Builder.CreateNeg(index, "idx.neg");
+ if (CGF.SanOpts->Bounds)
+ CGF.EmitBoundsCheck(op.E, pointerOperand, index, indexOperand->getType(),
+ /*Accessed*/ false);
+
const PointerType *pointerType
= pointerOperand->getType()->getAs<PointerType>();
if (!pointerType) {
@@ -2217,7 +2365,7 @@ static Value* tryEmitFMulAdd(const BinOpInfo &op,
// Check whether -ffp-contract=on. (If -ffp-contract=off/fast, fusing is
// either disabled, or handled entirely by the LLVM backend).
- if (CGF.getLangOpts().getFPContractMode() != LangOptions::FPC_On)
+ if (CGF.CGM.getCodeGenOpts().getFPContractMode() != CodeGenOptions::FPC_On)
return 0;
// We have a potentially fusable op. Look for a mul on one of the operands.
@@ -2249,14 +2397,17 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) {
case LangOptions::SOB_Defined:
return Builder.CreateAdd(op.LHS, op.RHS, "add");
case LangOptions::SOB_Undefined:
- if (!CGF.getLangOpts().SanitizeSignedIntegerOverflow)
+ if (!CGF.SanOpts->SignedIntegerOverflow)
return Builder.CreateNSWAdd(op.LHS, op.RHS, "add");
// Fall through.
case LangOptions::SOB_Trapping:
return EmitOverflowCheckedBinOp(op);
}
}
-
+
+ if (op.Ty->isUnsignedIntegerType() && CGF.SanOpts->UnsignedIntegerOverflow)
+ return EmitOverflowCheckedBinOp(op);
+
if (op.LHS->getType()->isFPOrFPVectorTy()) {
// Try to form an fmuladd.
if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder))
@@ -2276,14 +2427,17 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
case LangOptions::SOB_Defined:
return Builder.CreateSub(op.LHS, op.RHS, "sub");
case LangOptions::SOB_Undefined:
- if (!CGF.getLangOpts().SanitizeSignedIntegerOverflow)
+ if (!CGF.SanOpts->SignedIntegerOverflow)
return Builder.CreateNSWSub(op.LHS, op.RHS, "sub");
// Fall through.
case LangOptions::SOB_Trapping:
return EmitOverflowCheckedBinOp(op);
}
}
-
+
+ if (op.Ty->isUnsignedIntegerType() && CGF.SanOpts->UnsignedIntegerOverflow)
+ return EmitOverflowCheckedBinOp(op);
+
if (op.LHS->getType()->isFPOrFPVectorTy()) {
// Try to form an fmuladd.
if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder, true))
@@ -2352,6 +2506,15 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
return Builder.CreateExactSDiv(diffInChars, divisor, "sub.ptr.div");
}
+Value *ScalarExprEmitter::GetWidthMinusOneValue(Value* LHS,Value* RHS) {
+ llvm::IntegerType *Ty;
+ if (llvm::VectorType *VT = dyn_cast<llvm::VectorType>(LHS->getType()))
+ Ty = cast<llvm::IntegerType>(VT->getElementType());
+ else
+ Ty = cast<llvm::IntegerType>(LHS->getType());
+ return llvm::ConstantInt::get(RHS->getType(), Ty->getBitWidth() - 1);
+}
+
Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
// LLVM requires the LHS and RHS to be the same type: promote or truncate the
// RHS to the same size as the LHS.
@@ -2359,18 +2522,20 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
if (Ops.LHS->getType() != RHS->getType())
RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom");
- if (CGF.getLangOpts().SanitizeShift &&
+ if (CGF.SanOpts->Shift && !CGF.getLangOpts().OpenCL &&
isa<llvm::IntegerType>(Ops.LHS->getType())) {
- unsigned Width = cast<llvm::IntegerType>(Ops.LHS->getType())->getBitWidth();
- llvm::Value *WidthMinusOne =
- llvm::ConstantInt::get(RHS->getType(), Width - 1);
- // FIXME: Emit the branching explicitly rather than emitting the check
- // twice.
- EmitBinOpCheck(Builder.CreateICmpULE(RHS, WidthMinusOne), Ops);
+ llvm::Value *WidthMinusOne = GetWidthMinusOneValue(Ops.LHS, RHS);
+ llvm::Value *Valid = Builder.CreateICmpULE(RHS, WidthMinusOne);
if (Ops.Ty->hasSignedIntegerRepresentation()) {
+ llvm::BasicBlock *Orig = Builder.GetInsertBlock();
+ llvm::BasicBlock *Cont = CGF.createBasicBlock("cont");
+ llvm::BasicBlock *CheckBitsShifted = CGF.createBasicBlock("check");
+ Builder.CreateCondBr(Valid, CheckBitsShifted, Cont);
+
// Check whether we are shifting any non-zero bits off the top of the
// integer.
+ CGF.EmitBlock(CheckBitsShifted);
llvm::Value *BitsShiftedOff =
Builder.CreateLShr(Ops.LHS,
Builder.CreateSub(WidthMinusOne, RHS, "shl.zeros",
@@ -2385,9 +2550,19 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
BitsShiftedOff = Builder.CreateLShr(BitsShiftedOff, One);
}
llvm::Value *Zero = llvm::ConstantInt::get(BitsShiftedOff->getType(), 0);
- EmitBinOpCheck(Builder.CreateICmpEQ(BitsShiftedOff, Zero), Ops);
+ llvm::Value *SecondCheck = Builder.CreateICmpEQ(BitsShiftedOff, Zero);
+ CGF.EmitBlock(Cont);
+ llvm::PHINode *P = Builder.CreatePHI(Valid->getType(), 2);
+ P->addIncoming(Valid, Orig);
+ P->addIncoming(SecondCheck, CheckBitsShifted);
+ Valid = P;
}
+
+ EmitBinOpCheck(Valid, Ops);
}
+ // OpenCL 6.3j: shift values are effectively % word size of LHS.
+ if (CGF.getLangOpts().OpenCL)
+ RHS = Builder.CreateAnd(RHS, GetWidthMinusOneValue(Ops.LHS, RHS), "shl.mask");
return Builder.CreateShl(Ops.LHS, RHS, "shl");
}
@@ -2399,12 +2574,13 @@ Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) {
if (Ops.LHS->getType() != RHS->getType())
RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom");
- if (CGF.getLangOpts().SanitizeShift &&
- isa<llvm::IntegerType>(Ops.LHS->getType())) {
- unsigned Width = cast<llvm::IntegerType>(Ops.LHS->getType())->getBitWidth();
- llvm::Value *WidthVal = llvm::ConstantInt::get(RHS->getType(), Width);
- EmitBinOpCheck(Builder.CreateICmpULT(RHS, WidthVal), Ops);
- }
+ if (CGF.SanOpts->Shift && !CGF.getLangOpts().OpenCL &&
+ isa<llvm::IntegerType>(Ops.LHS->getType()))
+ EmitBinOpCheck(Builder.CreateICmpULE(RHS, GetWidthMinusOneValue(Ops.LHS, RHS)), Ops);
+
+ // OpenCL 6.3j: shift values are effectively % word size of LHS.
+ if (CGF.getLangOpts().OpenCL)
+ RHS = Builder.CreateAnd(RHS, GetWidthMinusOneValue(Ops.LHS, RHS), "shr.mask");
if (Ops.Ty->hasUnsignedIntegerRepresentation())
return Builder.CreateLShr(Ops.LHS, RHS, "shr");
@@ -2633,16 +2809,20 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
}
Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
-
// Perform vector logical and on comparisons with zero vectors.
if (E->getType()->isVectorType()) {
Value *LHS = Visit(E->getLHS());
Value *RHS = Visit(E->getRHS());
Value *Zero = llvm::ConstantAggregateZero::get(LHS->getType());
- LHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, LHS, Zero, "cmp");
- RHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, RHS, Zero, "cmp");
+ if (LHS->getType()->isFPOrFPVectorTy()) {
+ LHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, LHS, Zero, "cmp");
+ RHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, RHS, Zero, "cmp");
+ } else {
+ LHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, LHS, Zero, "cmp");
+ RHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, RHS, Zero, "cmp");
+ }
Value *And = Builder.CreateAnd(LHS, RHS);
- return Builder.CreateSExt(And, Zero->getType(), "sext");
+ return Builder.CreateSExt(And, ConvertType(E->getType()), "sext");
}
llvm::Type *ResTy = ConvertType(E->getType());
@@ -2700,16 +2880,20 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
}
Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
-
// Perform vector logical or on comparisons with zero vectors.
if (E->getType()->isVectorType()) {
Value *LHS = Visit(E->getLHS());
Value *RHS = Visit(E->getRHS());
Value *Zero = llvm::ConstantAggregateZero::get(LHS->getType());
- LHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, LHS, Zero, "cmp");
- RHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, RHS, Zero, "cmp");
+ if (LHS->getType()->isFPOrFPVectorTy()) {
+ LHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, LHS, Zero, "cmp");
+ RHS = Builder.CreateFCmp(llvm::CmpInst::FCMP_UNE, RHS, Zero, "cmp");
+ } else {
+ LHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, LHS, Zero, "cmp");
+ RHS = Builder.CreateICmp(llvm::CmpInst::ICMP_NE, RHS, Zero, "cmp");
+ }
Value *Or = Builder.CreateOr(LHS, RHS);
- return Builder.CreateSExt(Or, Zero->getType(), "sext");
+ return Builder.CreateSExt(Or, ConvertType(E->getType()), "sext");
}
llvm::Type *ResTy = ConvertType(E->getType());
@@ -3007,7 +3191,7 @@ Value *ScalarExprEmitter::VisitAtomicExpr(AtomicExpr *E) {
/// EmitScalarExpr - Emit the computation of the specified expression of scalar
/// type, ignoring the result.
Value *CodeGenFunction::EmitScalarExpr(const Expr *E, bool IgnoreResultAssign) {
- assert(E && !hasAggregateLLVMType(E->getType()) &&
+ assert(E && hasScalarEvaluationKind(E->getType()) &&
"Invalid scalar expression to emit");
if (isa<CXXDefaultArgExpr>(E))
@@ -3023,7 +3207,7 @@ Value *CodeGenFunction::EmitScalarExpr(const Expr *E, bool IgnoreResultAssign) {
/// specified destination type, both of which are LLVM scalar types.
Value *CodeGenFunction::EmitScalarConversion(Value *Src, QualType SrcTy,
QualType DstTy) {
- assert(!hasAggregateLLVMType(SrcTy) && !hasAggregateLLVMType(DstTy) &&
+ assert(hasScalarEvaluationKind(SrcTy) && hasScalarEvaluationKind(DstTy) &&
"Invalid scalar expression to emit");
return ScalarExprEmitter(*this).EmitScalarConversion(Src, SrcTy, DstTy);
}
@@ -3034,7 +3218,7 @@ Value *CodeGenFunction::EmitScalarConversion(Value *Src, QualType SrcTy,
Value *CodeGenFunction::EmitComplexToScalarConversion(ComplexPairTy Src,
QualType SrcTy,
QualType DstTy) {
- assert(SrcTy->isAnyComplexType() && !hasAggregateLLVMType(DstTy) &&
+ assert(SrcTy->isAnyComplexType() && hasScalarEvaluationKind(DstTy) &&
"Invalid complex -> scalar conversion");
return ScalarExprEmitter(*this).EmitComplexToScalarConversion(Src, SrcTy,
DstTy);
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index c90e4ec..79d97b9 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -21,8 +21,8 @@
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/DataLayout.h"
-#include "llvm/InlineAsm.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/InlineAsm.h"
using namespace clang;
using namespace CodeGen;
@@ -70,7 +70,7 @@ CodeGenFunction::EmitObjCBoxedExpr(const ObjCBoxedExpr *E) {
// messaged (avoids pulling it out of the result type).
CGObjCRuntime &Runtime = CGM.getObjCRuntime();
const ObjCInterfaceDecl *ClassDecl = BoxingMethod->getClassInterface();
- llvm::Value *Receiver = Runtime.GetClass(Builder, ClassDecl);
+ llvm::Value *Receiver = Runtime.GetClass(*this, ClassDecl);
const ParmVarDecl *argDecl = *BoxingMethod->param_begin();
QualType ArgQT = argDecl->getType().getUnqualifiedType();
@@ -109,32 +109,50 @@ llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E,
if (DLE)
Keys = CreateMemTemp(ElementArrayType, "keys");
+ // In ARC, we may need to do extra work to keep all the keys and
+ // values alive until after the call.
+ SmallVector<llvm::Value *, 16> NeededObjects;
+ bool TrackNeededObjects =
+ (getLangOpts().ObjCAutoRefCount &&
+ CGM.getCodeGenOpts().OptimizationLevel != 0);
+
// Perform the actual initialialization of the array(s).
for (uint64_t i = 0; i < NumElements; i++) {
if (ALE) {
- // Emit the initializer.
+ // Emit the element and store it to the appropriate array slot.
const Expr *Rhs = ALE->getElement(i);
LValue LV = LValue::MakeAddr(Builder.CreateStructGEP(Objects, i),
ElementType,
Context.getTypeAlignInChars(Rhs->getType()),
Context);
- EmitScalarInit(Rhs, /*D=*/0, LV, /*capturedByInit=*/false);
+
+ llvm::Value *value = EmitScalarExpr(Rhs);
+ EmitStoreThroughLValue(RValue::get(value), LV, true);
+ if (TrackNeededObjects) {
+ NeededObjects.push_back(value);
+ }
} else {
- // Emit the key initializer.
+ // Emit the key and store it to the appropriate array slot.
const Expr *Key = DLE->getKeyValueElement(i).Key;
LValue KeyLV = LValue::MakeAddr(Builder.CreateStructGEP(Keys, i),
ElementType,
Context.getTypeAlignInChars(Key->getType()),
Context);
- EmitScalarInit(Key, /*D=*/0, KeyLV, /*capturedByInit=*/false);
+ llvm::Value *keyValue = EmitScalarExpr(Key);
+ EmitStoreThroughLValue(RValue::get(keyValue), KeyLV, /*isInit=*/true);
- // Emit the value initializer.
+ // Emit the value and store it to the appropriate array slot.
const Expr *Value = DLE->getKeyValueElement(i).Value;
LValue ValueLV = LValue::MakeAddr(Builder.CreateStructGEP(Objects, i),
ElementType,
Context.getTypeAlignInChars(Value->getType()),
Context);
- EmitScalarInit(Value, /*D=*/0, ValueLV, /*capturedByInit=*/false);
+ llvm::Value *valueValue = EmitScalarExpr(Value);
+ EmitStoreThroughLValue(RValue::get(valueValue), ValueLV, /*isInit=*/true);
+ if (TrackNeededObjects) {
+ NeededObjects.push_back(keyValue);
+ NeededObjects.push_back(valueValue);
+ }
}
}
@@ -163,7 +181,7 @@ llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E,
ObjCInterfaceDecl *Class
= InterfacePointerType->getObjectType()->getInterface();
CGObjCRuntime &Runtime = CGM.getObjCRuntime();
- llvm::Value *Receiver = Runtime.GetClass(Builder, Class);
+ llvm::Value *Receiver = Runtime.GetClass(*this, Class);
// Generate the message send.
RValue result
@@ -172,6 +190,15 @@ llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E,
Sel,
Receiver, Args, Class,
MethodWithObjects);
+
+ // The above message send needs these objects, but in ARC they are
+ // passed in a buffer that is essentially __unsafe_unretained.
+ // Therefore we must prevent the optimizer from releasing them until
+ // after the call.
+ if (TrackNeededObjects) {
+ EmitARCIntrinsicUse(NeededObjects);
+ }
+
return Builder.CreateBitCast(result.getScalarVal(),
ConvertType(E->getType()));
}
@@ -191,12 +218,12 @@ llvm::Value *CodeGenFunction::EmitObjCSelectorExpr(const ObjCSelectorExpr *E) {
// Note that this implementation allows for non-constant strings to be passed
// as arguments to @selector(). Currently, the only thing preventing this
// behaviour is the type checking in the front end.
- return CGM.getObjCRuntime().GetSelector(Builder, E->getSelector());
+ return CGM.getObjCRuntime().GetSelector(*this, E->getSelector());
}
llvm::Value *CodeGenFunction::EmitObjCProtocolExpr(const ObjCProtocolExpr *E) {
// FIXME: This should pass the Decl not the name.
- return CGM.getObjCRuntime().GenerateProtocolRef(Builder, E->getProtocol());
+ return CGM.getObjCRuntime().GenerateProtocolRef(*this, E->getProtocol());
}
/// \brief Adjust the type of the result of an Objective-C message send
@@ -310,7 +337,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
assert(ObjTy && "Invalid Objective-C class message send");
OID = ObjTy->getInterface();
assert(OID && "Invalid Objective-C class message send");
- Receiver = Runtime.GetClass(Builder, OID);
+ Receiver = Runtime.GetClass(*this, OID);
isClassMessage = true;
break;
}
@@ -772,7 +799,7 @@ static void emitCPPObjectAtomicGetterCall(CodeGenFunction &CGF,
args.add(RValue::get(AtomicHelperFn), CGF.getContext().VoidPtrTy);
llvm::Value *copyCppAtomicObjectFn =
- CGF.CGM.getObjCRuntime().GetCppAtomicObjectFunction();
+ CGF.CGM.getObjCRuntime().GetCppAtomicObjectGetFunction();
CGF.EmitCall(CGF.getTypes().arrangeFreeFunctionCall(CGF.getContext().VoidTy,
args,
FunctionType::ExtInfo(),
@@ -895,16 +922,21 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar, 0);
QualType ivarType = ivar->getType();
- if (ivarType->isAnyComplexType()) {
- ComplexPairTy pair = LoadComplexFromAddr(LV.getAddress(),
- LV.isVolatileQualified());
- StoreComplexToAddr(pair, ReturnValue, LV.isVolatileQualified());
- } else if (hasAggregateLLVMType(ivarType)) {
+ switch (getEvaluationKind(ivarType)) {
+ case TEK_Complex: {
+ ComplexPairTy pair = EmitLoadOfComplex(LV);
+ EmitStoreOfComplex(pair,
+ MakeNaturalAlignAddrLValue(ReturnValue, ivarType),
+ /*init*/ true);
+ return;
+ }
+ case TEK_Aggregate:
// The return value slot is guaranteed to not be aliased, but
// that's not necessarily the same as "on the stack", so
// we still potentially need objc_memmove_collectable.
EmitAggregateCopy(ReturnValue, LV.getAddress(), ivarType);
- } else {
+ return;
+ case TEK_Scalar: {
llvm::Value *value;
if (propType->isReferenceType()) {
value = LV.getAddress();
@@ -926,8 +958,10 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
}
EmitReturnOfRValue(RValue::get(value), propType);
+ return;
}
- return;
+ }
+ llvm_unreachable("bad evaluation kind");
}
}
@@ -1007,7 +1041,7 @@ static void emitCPPObjectAtomicSetterCall(CodeGenFunction &CGF,
args.add(RValue::get(AtomicHelperFn), CGF.getContext().VoidPtrTy);
llvm::Value *copyCppAtomicObjectFn =
- CGF.CGM.getObjCRuntime().GetCppAtomicObjectFunction();
+ CGF.CGM.getObjCRuntime().GetCppAtomicObjectSetFunction();
CGF.EmitCall(CGF.getTypes().arrangeFreeFunctionCall(CGF.getContext().VoidTy,
args,
FunctionType::ExtInfo(),
@@ -1182,7 +1216,8 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
selfDecl->getType(), CK_LValueToRValue, &self,
VK_RValue);
ObjCIvarRefExpr ivarRef(ivar, ivar->getType().getNonReferenceType(),
- SourceLocation(), &selfLoad, true, true);
+ SourceLocation(), SourceLocation(),
+ &selfLoad, true, true);
ParmVarDecl *argDecl = *setterMethod->param_begin();
QualType argType = argDecl->getType().getNonReferenceType();
@@ -1679,7 +1714,8 @@ namespace {
llvm::Value *object;
void Emit(CodeGenFunction &CGF, Flags flags) {
- CGF.EmitARCRelease(object, /*precise*/ true);
+ // Releases at the end of the full-expression are imprecise.
+ CGF.EmitARCRelease(object, ARCImpreciseLifetime);
}
};
}
@@ -1699,21 +1735,38 @@ llvm::Value *CodeGenFunction::EmitObjCExtendObjectLifetime(QualType type,
return EmitARCRetainAutorelease(type, value);
}
+/// Given a number of pointers, inform the optimizer that they're
+/// being intrinsically used up until this point in the program.
+void CodeGenFunction::EmitARCIntrinsicUse(ArrayRef<llvm::Value*> values) {
+ llvm::Constant *&fn = CGM.getARCEntrypoints().clang_arc_use;
+ if (!fn) {
+ llvm::FunctionType *fnType =
+ llvm::FunctionType::get(CGM.VoidTy, ArrayRef<llvm::Type*>(), true);
+ fn = CGM.CreateRuntimeFunction(fnType, "clang.arc.use");
+ }
+
+ // This isn't really a "runtime" function, but as an intrinsic it
+ // doesn't really matter as long as we align things up.
+ EmitNounwindRuntimeCall(fn, values);
+}
+
static llvm::Constant *createARCRuntimeFunction(CodeGenModule &CGM,
llvm::FunctionType *type,
StringRef fnName) {
llvm::Constant *fn = CGM.CreateRuntimeFunction(type, fnName);
- // If the target runtime doesn't naturally support ARC, emit weak
- // references to the runtime support library. We don't really
- // permit this to fail, but we need a particular relocation style.
if (llvm::Function *f = dyn_cast<llvm::Function>(fn)) {
- if (!CGM.getLangOpts().ObjCRuntime.hasNativeARC())
+ // If the target runtime doesn't naturally support ARC, emit weak
+ // references to the runtime support library. We don't really
+ // permit this to fail, but we need a particular relocation style.
+ if (!CGM.getLangOpts().ObjCRuntime.hasNativeARC()) {
f->setLinkage(llvm::Function::ExternalWeakLinkage);
- // set nonlazybind attribute for these APIs for performance.
- if (fnName == "objc_retain" || fnName == "objc_release")
- f->addFnAttr(llvm::Attributes::NonLazyBind);
+ } else if (fnName == "objc_retain" || fnName == "objc_release") {
+ // If we have Native ARC, set nonlazybind attribute for these APIs for
+ // performance.
+ f->addFnAttr(llvm::Attribute::NonLazyBind);
+ }
}
return fn;
@@ -1725,13 +1778,13 @@ static llvm::Constant *createARCRuntimeFunction(CodeGenModule &CGM,
static llvm::Value *emitARCValueOperation(CodeGenFunction &CGF,
llvm::Value *value,
llvm::Constant *&fn,
- StringRef fnName) {
+ StringRef fnName,
+ bool isTailCall = false) {
if (isa<llvm::ConstantPointerNull>(value)) return value;
if (!fn) {
- std::vector<llvm::Type*> args(1, CGF.Int8PtrTy);
llvm::FunctionType *fnType =
- llvm::FunctionType::get(CGF.Int8PtrTy, args, false);
+ llvm::FunctionType::get(CGF.Int8PtrTy, CGF.Int8PtrTy, false);
fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName);
}
@@ -1740,8 +1793,9 @@ static llvm::Value *emitARCValueOperation(CodeGenFunction &CGF,
value = CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy);
// Call the function.
- llvm::CallInst *call = CGF.Builder.CreateCall(fn, value);
- call->setDoesNotThrow();
+ llvm::CallInst *call = CGF.EmitNounwindRuntimeCall(fn, value);
+ if (isTailCall)
+ call->setTailCall();
// Cast the result back to the original type.
return CGF.Builder.CreateBitCast(call, origType);
@@ -1754,9 +1808,8 @@ static llvm::Value *emitARCLoadOperation(CodeGenFunction &CGF,
llvm::Constant *&fn,
StringRef fnName) {
if (!fn) {
- std::vector<llvm::Type*> args(1, CGF.Int8PtrPtrTy);
llvm::FunctionType *fnType =
- llvm::FunctionType::get(CGF.Int8PtrTy, args, false);
+ llvm::FunctionType::get(CGF.Int8PtrTy, CGF.Int8PtrPtrTy, false);
fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName);
}
@@ -1765,11 +1818,9 @@ static llvm::Value *emitARCLoadOperation(CodeGenFunction &CGF,
addr = CGF.Builder.CreateBitCast(addr, CGF.Int8PtrPtrTy);
// Call the function.
- llvm::CallInst *call = CGF.Builder.CreateCall(fn, addr);
- call->setDoesNotThrow();
+ llvm::Value *result = CGF.EmitNounwindRuntimeCall(fn, addr);
// Cast the result back to a dereference of the original type.
- llvm::Value *result = call;
if (origType != CGF.Int8PtrPtrTy)
result = CGF.Builder.CreateBitCast(result,
cast<llvm::PointerType>(origType)->getElementType());
@@ -1798,11 +1849,11 @@ static llvm::Value *emitARCStoreOperation(CodeGenFunction &CGF,
llvm::Type *origType = value->getType();
- addr = CGF.Builder.CreateBitCast(addr, CGF.Int8PtrPtrTy);
- value = CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy);
-
- llvm::CallInst *result = CGF.Builder.CreateCall2(fn, addr, value);
- result->setDoesNotThrow();
+ llvm::Value *args[] = {
+ CGF.Builder.CreateBitCast(addr, CGF.Int8PtrPtrTy),
+ CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy)
+ };
+ llvm::CallInst *result = CGF.EmitNounwindRuntimeCall(fn, args);
if (ignored) return 0;
@@ -1819,17 +1870,18 @@ static void emitARCCopyOperation(CodeGenFunction &CGF,
assert(dst->getType() == src->getType());
if (!fn) {
- std::vector<llvm::Type*> argTypes(2, CGF.Int8PtrPtrTy);
+ llvm::Type *argTypes[] = { CGF.Int8PtrPtrTy, CGF.Int8PtrPtrTy };
+
llvm::FunctionType *fnType
= llvm::FunctionType::get(CGF.Builder.getVoidTy(), argTypes, false);
fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName);
}
- dst = CGF.Builder.CreateBitCast(dst, CGF.Int8PtrPtrTy);
- src = CGF.Builder.CreateBitCast(src, CGF.Int8PtrPtrTy);
-
- llvm::CallInst *result = CGF.Builder.CreateCall2(fn, dst, src);
- result->setDoesNotThrow();
+ llvm::Value *args[] = {
+ CGF.Builder.CreateBitCast(dst, CGF.Int8PtrPtrTy),
+ CGF.Builder.CreateBitCast(src, CGF.Int8PtrPtrTy)
+ };
+ CGF.EmitNounwindRuntimeCall(fn, args);
}
/// Produce the code to do a retain. Based on the type, calls one of:
@@ -1932,14 +1984,14 @@ CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) {
/// Release the given object.
/// call void \@objc_release(i8* %value)
-void CodeGenFunction::EmitARCRelease(llvm::Value *value, bool precise) {
+void CodeGenFunction::EmitARCRelease(llvm::Value *value,
+ ARCPreciseLifetime_t precise) {
if (isa<llvm::ConstantPointerNull>(value)) return;
llvm::Constant *&fn = CGM.getARCEntrypoints().objc_release;
if (!fn) {
- std::vector<llvm::Type*> args(1, Int8PtrTy);
llvm::FunctionType *fnType =
- llvm::FunctionType::get(Builder.getVoidTy(), args, false);
+ llvm::FunctionType::get(Builder.getVoidTy(), Int8PtrTy, false);
fn = createARCRuntimeFunction(CGM, fnType, "objc_release");
}
@@ -1947,10 +1999,9 @@ void CodeGenFunction::EmitARCRelease(llvm::Value *value, bool precise) {
value = Builder.CreateBitCast(value, Int8PtrTy);
// Call objc_release.
- llvm::CallInst *call = Builder.CreateCall(fn, value);
- call->setDoesNotThrow();
+ llvm::CallInst *call = EmitNounwindRuntimeCall(fn, value);
- if (!precise) {
+ if (precise == ARCImpreciseLifetime) {
SmallVector<llvm::Value*,1> args;
call->setMetadata("clang.imprecise_release",
llvm::MDNode::get(Builder.getContext(), args));
@@ -1966,7 +2017,8 @@ void CodeGenFunction::EmitARCRelease(llvm::Value *value, bool precise) {
/// At -O1 and above, just load and call objc_release.
///
/// call void \@objc_storeStrong(i8** %addr, i8* null)
-void CodeGenFunction::EmitARCDestroyStrong(llvm::Value *addr, bool precise) {
+void CodeGenFunction::EmitARCDestroyStrong(llvm::Value *addr,
+ ARCPreciseLifetime_t precise) {
if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
llvm::PointerType *addrTy = cast<llvm::PointerType>(addr->getType());
llvm::Value *null = llvm::ConstantPointerNull::get(
@@ -1995,10 +2047,11 @@ llvm::Value *CodeGenFunction::EmitARCStoreStrongCall(llvm::Value *addr,
fn = createARCRuntimeFunction(CGM, fnType, "objc_storeStrong");
}
- addr = Builder.CreateBitCast(addr, Int8PtrPtrTy);
- llvm::Value *castValue = Builder.CreateBitCast(value, Int8PtrTy);
-
- Builder.CreateCall2(fn, addr, castValue)->setDoesNotThrow();
+ llvm::Value *args[] = {
+ Builder.CreateBitCast(addr, Int8PtrPtrTy),
+ Builder.CreateBitCast(value, Int8PtrTy)
+ };
+ EmitNounwindRuntimeCall(fn, args);
if (ignored) return 0;
return value;
@@ -2035,7 +2088,7 @@ llvm::Value *CodeGenFunction::EmitARCStoreStrong(LValue dst,
EmitStoreOfScalar(newValue, dst);
// Finally, release the old value.
- EmitARCRelease(oldValue, /*precise*/ false);
+ EmitARCRelease(oldValue, dst.isARCPreciseLifetime());
return newValue;
}
@@ -2054,7 +2107,8 @@ llvm::Value *
CodeGenFunction::EmitARCAutoreleaseReturnValue(llvm::Value *value) {
return emitARCValueOperation(*this, value,
CGM.getARCEntrypoints().objc_autoreleaseReturnValue,
- "objc_autoreleaseReturnValue");
+ "objc_autoreleaseReturnValue",
+ /*isTailCall*/ true);
}
/// Do a fused retain/autorelease of the given object.
@@ -2063,7 +2117,8 @@ llvm::Value *
CodeGenFunction::EmitARCRetainAutoreleaseReturnValue(llvm::Value *value) {
return emitARCValueOperation(*this, value,
CGM.getARCEntrypoints().objc_retainAutoreleaseReturnValue,
- "objc_retainAutoreleaseReturnValue");
+ "objc_retainAutoreleaseReturnValue",
+ /*isTailCall*/ true);
}
/// Do a fused retain/autorelease of the given object.
@@ -2144,17 +2199,15 @@ void CodeGenFunction::EmitARCInitWeak(llvm::Value *addr, llvm::Value *value) {
void CodeGenFunction::EmitARCDestroyWeak(llvm::Value *addr) {
llvm::Constant *&fn = CGM.getARCEntrypoints().objc_destroyWeak;
if (!fn) {
- std::vector<llvm::Type*> args(1, Int8PtrPtrTy);
llvm::FunctionType *fnType =
- llvm::FunctionType::get(Builder.getVoidTy(), args, false);
+ llvm::FunctionType::get(Builder.getVoidTy(), Int8PtrPtrTy, false);
fn = createARCRuntimeFunction(CGM, fnType, "objc_destroyWeak");
}
// Cast the argument to 'id*'.
addr = Builder.CreateBitCast(addr, Int8PtrPtrTy);
- llvm::CallInst *call = Builder.CreateCall(fn, addr);
- call->setDoesNotThrow();
+ EmitNounwindRuntimeCall(fn, addr);
}
/// void \@objc_moveWeak(i8** %dest, i8** %src)
@@ -2185,10 +2238,7 @@ llvm::Value *CodeGenFunction::EmitObjCAutoreleasePoolPush() {
fn = createARCRuntimeFunction(CGM, fnType, "objc_autoreleasePoolPush");
}
- llvm::CallInst *call = Builder.CreateCall(fn);
- call->setDoesNotThrow();
-
- return call;
+ return EmitNounwindRuntimeCall(fn);
}
/// Produce the code to do a primitive release.
@@ -2198,17 +2248,15 @@ void CodeGenFunction::EmitObjCAutoreleasePoolPop(llvm::Value *value) {
llvm::Constant *&fn = CGM.getRREntrypoints().objc_autoreleasePoolPop;
if (!fn) {
- std::vector<llvm::Type*> args(1, Int8PtrTy);
llvm::FunctionType *fnType =
- llvm::FunctionType::get(Builder.getVoidTy(), args, false);
+ llvm::FunctionType::get(Builder.getVoidTy(), Int8PtrTy, false);
// We don't want to use a weak import here; instead we should not
// fall into this path.
fn = createARCRuntimeFunction(CGM, fnType, "objc_autoreleasePoolPop");
}
- llvm::CallInst *call = Builder.CreateCall(fn, value);
- call->setDoesNotThrow();
+ EmitNounwindRuntimeCall(fn, value);
}
/// Produce the code to do an MRR version objc_autoreleasepool_push.
@@ -2218,7 +2266,7 @@ void CodeGenFunction::EmitObjCAutoreleasePoolPop(llvm::Value *value) {
///
llvm::Value *CodeGenFunction::EmitObjCMRRAutoreleasePoolPush() {
CGObjCRuntime &Runtime = CGM.getObjCRuntime();
- llvm::Value *Receiver = Runtime.EmitNSAutoreleasePoolClassRef(Builder);
+ llvm::Value *Receiver = Runtime.EmitNSAutoreleasePoolClassRef(*this);
// [NSAutoreleasePool alloc]
IdentifierInfo *II = &CGM.getContext().Idents.get("alloc");
Selector AllocSel = getContext().Selectors.getSelector(0, &II);
@@ -2252,13 +2300,13 @@ void CodeGenFunction::EmitObjCMRRAutoreleasePoolPop(llvm::Value *Arg) {
void CodeGenFunction::destroyARCStrongPrecise(CodeGenFunction &CGF,
llvm::Value *addr,
QualType type) {
- CGF.EmitARCDestroyStrong(addr, /*precise*/ true);
+ CGF.EmitARCDestroyStrong(addr, ARCPreciseLifetime);
}
void CodeGenFunction::destroyARCStrongImprecise(CodeGenFunction &CGF,
llvm::Value *addr,
QualType type) {
- CGF.EmitARCDestroyStrong(addr, /*precise*/ false);
+ CGF.EmitARCDestroyStrong(addr, ARCImpreciseLifetime);
}
void CodeGenFunction::destroyARCWeak(CodeGenFunction &CGF,
@@ -2440,7 +2488,7 @@ static bool shouldEmitSeparateBlockRetain(const Expr *e) {
/// This massively duplicates emitPseudoObjectRValue.
static TryEmitResult tryEmitARCRetainPseudoObject(CodeGenFunction &CGF,
const PseudoObjectExpr *E) {
- llvm::SmallVector<CodeGenFunction::OpaqueValueMappingData, 4> opaques;
+ SmallVector<CodeGenFunction::OpaqueValueMappingData, 4> opaques;
// Find the result expression.
const Expr *resultExpr = E->getResultExpr();
@@ -2490,12 +2538,10 @@ static TryEmitResult tryEmitARCRetainPseudoObject(CodeGenFunction &CGF,
static TryEmitResult
tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) {
- // Look through cleanups.
- if (const ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(e)) {
- CGF.enterFullExpression(cleanups);
- CodeGenFunction::RunCleanupsScope scope(CGF);
- return tryEmitARCRetainScalarExpr(CGF, cleanups->getSubExpr());
- }
+ // We should *never* see a nested full-expression here, because if
+ // we fail to emit at +1, our caller must not retain after we close
+ // out the full-expression.
+ assert(!isa<ExprWithCleanups>(e));
// The desired result type, if it differs from the type of the
// ultimate opaque expression.
@@ -2647,6 +2693,13 @@ static llvm::Value *emitARCRetainLoadOfScalar(CodeGenFunction &CGF,
/// best-effort attempt to peephole expressions that naturally produce
/// retained objects.
llvm::Value *CodeGenFunction::EmitARCRetainScalarExpr(const Expr *e) {
+ // The retain needs to happen within the full-expression.
+ if (const ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(e)) {
+ enterFullExpression(cleanups);
+ RunCleanupsScope scope(*this);
+ return EmitARCRetainScalarExpr(cleanups->getSubExpr());
+ }
+
TryEmitResult result = tryEmitARCRetainScalarExpr(*this, e);
llvm::Value *value = result.getPointer();
if (!result.getInt())
@@ -2656,6 +2709,13 @@ llvm::Value *CodeGenFunction::EmitARCRetainScalarExpr(const Expr *e) {
llvm::Value *
CodeGenFunction::EmitARCRetainAutoreleaseScalarExpr(const Expr *e) {
+ // The retain needs to happen within the full-expression.
+ if (const ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(e)) {
+ enterFullExpression(cleanups);
+ RunCleanupsScope scope(*this);
+ return EmitARCRetainAutoreleaseScalarExpr(cleanups->getSubExpr());
+ }
+
TryEmitResult result = tryEmitARCRetainScalarExpr(*this, e);
llvm::Value *value = result.getPointer();
if (result.getInt())
@@ -2687,17 +2747,7 @@ llvm::Value *CodeGenFunction::EmitObjCThrowOperand(const Expr *expr) {
// In ARC, retain and autorelease the expression.
if (getLangOpts().ObjCAutoRefCount) {
// Do so before running any cleanups for the full-expression.
- // tryEmitARCRetainScalarExpr does make an effort to do things
- // inside cleanups, but there are crazy cases like
- // @throw A().foo;
- // where a full retain+autorelease is required and would
- // otherwise happen after the destructor for the temporary.
- if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(expr)) {
- enterFullExpression(ewc);
- expr = ewc->getSubExpr();
- }
-
- CodeGenFunction::RunCleanupsScope cleanups(*this);
+ // EmitARCRetainAutoreleaseScalarExpr does this for us.
return EmitARCRetainAutoreleaseScalarExpr(expr);
}
@@ -2733,7 +2783,7 @@ CodeGenFunction::EmitARCStoreStrong(const BinaryOperator *e,
llvm::Value *oldValue =
EmitLoadOfScalar(lvalue);
EmitStoreOfScalar(value, lvalue);
- EmitARCRelease(oldValue, /*precise*/ false);
+ EmitARCRelease(oldValue, lvalue.isARCPreciseLifetime());
} else {
value = EmitARCStoreStrong(lvalue, value, ignored);
}
@@ -2791,12 +2841,7 @@ void CodeGenFunction::EmitExtendGCLifetime(llvm::Value *object) {
/* side effects */ true);
object = Builder.CreateBitCast(object, VoidPtrTy);
- Builder.CreateCall(extender, object)->setDoesNotThrow();
-}
-
-static bool hasAtomicCopyHelperAPI(const ObjCRuntime &runtime) {
- // For now, only NeXT has these APIs.
- return runtime.isNeXTFamily();
+ EmitNounwindRuntimeCall(extender, object);
}
/// GenerateObjCAtomicSetterCopyHelperFunction - Given a c++ object type with
@@ -2806,9 +2851,8 @@ static bool hasAtomicCopyHelperAPI(const ObjCRuntime &runtime) {
llvm::Constant *
CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
const ObjCPropertyImplDecl *PID) {
- // FIXME. This api is for NeXt runtime only for now.
if (!getLangOpts().CPlusPlus ||
- !hasAtomicCopyHelperAPI(getLangOpts().ObjCRuntime))
+ !getLangOpts().ObjCRuntime.hasAtomicCopyHelper())
return 0;
QualType Ty = PID->getPropertyIvarDecl()->getType();
if (!Ty->isRecordType())
@@ -2831,7 +2875,6 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
SourceLocation(),
SourceLocation(), II, C.VoidTy, 0,
SC_Static,
- SC_None,
false,
false);
@@ -2890,9 +2933,8 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
llvm::Constant *
CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
const ObjCPropertyImplDecl *PID) {
- // FIXME. This api is for NeXt runtime only for now.
if (!getLangOpts().CPlusPlus ||
- !hasAtomicCopyHelperAPI(getLangOpts().ObjCRuntime))
+ !getLangOpts().ObjCRuntime.hasAtomicCopyHelper())
return 0;
const ObjCPropertyDecl *PD = PID->getPropertyDecl();
QualType Ty = PD->getType();
@@ -2917,7 +2959,6 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
SourceLocation(),
SourceLocation(), II, C.VoidTy, 0,
SC_Static,
- SC_None,
false,
false);
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index 68d234d..fbf8a1a 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -15,26 +15,24 @@
//===----------------------------------------------------------------------===//
#include "CGObjCRuntime.h"
-#include "CodeGenModule.h"
-#include "CodeGenFunction.h"
#include "CGCleanup.h"
+#include "CodeGenFunction.h"
+#include "CodeGenModule.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtObjC.h"
-#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
-
-#include "llvm/Intrinsics.h"
-#include "llvm/Module.h"
-#include "llvm/LLVMContext.h"
+#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Support/Compiler.h"
-#include "llvm/DataLayout.h"
-
#include <cstdarg>
@@ -194,7 +192,7 @@ protected:
/// The element types must match the types of the structure elements in the
/// first argument.
llvm::GlobalVariable *MakeGlobal(llvm::StructType *Ty,
- llvm::ArrayRef<llvm::Constant*> V,
+ ArrayRef<llvm::Constant *> V,
StringRef Name="",
llvm::GlobalValue::LinkageTypes linkage
=llvm::GlobalValue::InternalLinkage) {
@@ -206,7 +204,7 @@ protected:
/// elements that the array type declares, of the type specified as the array
/// element type.
llvm::GlobalVariable *MakeGlobal(llvm::ArrayType *Ty,
- llvm::ArrayRef<llvm::Constant*> V,
+ ArrayRef<llvm::Constant *> V,
StringRef Name="",
llvm::GlobalValue::LinkageTypes linkage
=llvm::GlobalValue::InternalLinkage) {
@@ -217,7 +215,7 @@ protected:
/// Generates a global array, inferring the array type from the specified
/// element type and the size of the initialiser.
llvm::GlobalVariable *MakeGlobalArray(llvm::Type *Ty,
- llvm::ArrayRef<llvm::Constant*> V,
+ ArrayRef<llvm::Constant *> V,
StringRef Name="",
llvm::GlobalValue::LinkageTypes linkage
=llvm::GlobalValue::InternalLinkage) {
@@ -227,7 +225,7 @@ protected:
/// Returns a property name and encoding string.
llvm::Constant *MakePropertyEncodingString(const ObjCPropertyDecl *PD,
const Decl *Container) {
- ObjCRuntime R = CGM.getLangOpts().ObjCRuntime;
+ const ObjCRuntime &R = CGM.getLangOpts().ObjCRuntime;
if ((R.getKind() == ObjCRuntime::GNUstep) &&
(R.getVersion() >= VersionTuple(1, 6))) {
std::string NameAndAttributes;
@@ -238,15 +236,44 @@ protected:
NameAndAttributes += TypeStr;
NameAndAttributes += '\0';
NameAndAttributes += PD->getNameAsString();
+ NameAndAttributes += '\0';
return llvm::ConstantExpr::getGetElementPtr(
CGM.GetAddrOfConstantString(NameAndAttributes), Zeros);
}
return MakeConstantString(PD->getNameAsString());
}
+ /// Push the property attributes into two structure fields.
+ void PushPropertyAttributes(std::vector<llvm::Constant*> &Fields,
+ ObjCPropertyDecl *property, bool isSynthesized=true, bool
+ isDynamic=true) {
+ int attrs = property->getPropertyAttributes();
+ // For read-only properties, clear the copy and retain flags
+ if (attrs & ObjCPropertyDecl::OBJC_PR_readonly) {
+ attrs &= ~ObjCPropertyDecl::OBJC_PR_copy;
+ attrs &= ~ObjCPropertyDecl::OBJC_PR_retain;
+ attrs &= ~ObjCPropertyDecl::OBJC_PR_weak;
+ attrs &= ~ObjCPropertyDecl::OBJC_PR_strong;
+ }
+ // The first flags field has the same attribute values as clang uses internally
+ Fields.push_back(llvm::ConstantInt::get(Int8Ty, attrs & 0xff));
+ attrs >>= 8;
+ attrs <<= 2;
+ // For protocol properties, synthesized and dynamic have no meaning, so we
+ // reuse these flags to indicate that this is a protocol property (both set
+ // has no meaning, as a property can't be both synthesized and dynamic)
+ attrs |= isSynthesized ? (1<<0) : 0;
+ attrs |= isDynamic ? (1<<1) : 0;
+ // The second field is the next four fields left shifted by two, with the
+ // low bit set to indicate whether the field is synthesized or dynamic.
+ Fields.push_back(llvm::ConstantInt::get(Int8Ty, attrs & 0xff));
+ // Two padding fields
+ Fields.push_back(llvm::ConstantInt::get(Int8Ty, 0));
+ Fields.push_back(llvm::ConstantInt::get(Int8Ty, 0));
+ }
/// Ensures that the value has the required type, by inserting a bitcast if
/// required. This function lets us avoid inserting bitcasts that are
/// redundant.
- llvm::Value* EnforceType(CGBuilderTy B, llvm::Value *V, llvm::Type *Ty){
+ llvm::Value* EnforceType(CGBuilderTy &B, llvm::Value *V, llvm::Type *Ty) {
if (V->getType() == Ty) return V;
return B.CreateBitCast(V, Ty);
}
@@ -385,7 +412,7 @@ private:
/// a class defined in the runtime, declaring no methods, but adopting the
/// protocols. This is a horribly ugly hack, but it allows us to collect all
/// of the protocols without changing the ABI.
- void GenerateProtocolHolderCategory(void);
+ void GenerateProtocolHolderCategory();
/// Generates a class structure.
llvm::Constant *GenerateClassStructure(
llvm::Constant *MetaClass,
@@ -409,7 +436,7 @@ private:
ArrayRef<llvm::Constant *> MethodTypes);
/// Returns a selector with the specified type encoding. An empty string is
/// used to return an untyped selector (with the types field set to NULL).
- llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel,
+ llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel,
const std::string &TypeEncoding, bool lval);
/// Returns the variable used to store the offset of an instance variable.
llvm::GlobalVariable *ObjCIvarOffsetVariable(const ObjCInterfaceDecl *ID,
@@ -419,7 +446,7 @@ private:
protected:
void EmitClassRef(const std::string &className);
/// Emits a pointer to the named class
- virtual llvm::Value *GetClassNamed(CGBuilderTy &Builder,
+ virtual llvm::Value *GetClassNamed(CodeGenFunction &CGF,
const std::string &Name, bool isWeak);
/// Looks up the method for sending a message to the specified object. This
/// mechanism differs between the GCC and GNU runtimes, so this method must be
@@ -472,11 +499,11 @@ public:
bool IsClassMessage,
const CallArgList &CallArgs,
const ObjCMethodDecl *Method);
- virtual llvm::Value *GetClass(CGBuilderTy &Builder,
+ virtual llvm::Value *GetClass(CodeGenFunction &CGF,
const ObjCInterfaceDecl *OID);
- virtual llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel,
+ virtual llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel,
bool lval = false);
- virtual llvm::Value *GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl
+ virtual llvm::Value *GetSelector(CodeGenFunction &CGF, const ObjCMethodDecl
*Method);
virtual llvm::Constant *GetEHType(QualType T);
@@ -485,7 +512,7 @@ public:
virtual void GenerateCategory(const ObjCCategoryImplDecl *CMD);
virtual void GenerateClass(const ObjCImplementationDecl *ClassDecl);
virtual void RegisterAlias(const ObjCCompatibleAliasDecl *OAD);
- virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder,
+ virtual llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF,
const ObjCProtocolDecl *PD);
virtual void GenerateProtocol(const ObjCProtocolDecl *PD);
virtual llvm::Function *ModuleInitFunction();
@@ -494,8 +521,9 @@ public:
virtual llvm::Constant *GetOptimizedPropertySetFunction(bool atomic,
bool copy);
virtual llvm::Constant *GetSetStructFunction();
- virtual llvm::Constant *GetCppAtomicObjectFunction();
virtual llvm::Constant *GetGetStructFunction();
+ virtual llvm::Constant *GetCppAtomicObjectGetFunction();
+ virtual llvm::Constant *GetCppAtomicObjectSetFunction();
virtual llvm::Constant *EnumerationMutationFunction();
virtual void EmitTryStmt(CodeGenFunction &CGF,
@@ -503,7 +531,8 @@ public:
virtual void EmitSynchronizedStmt(CodeGenFunction &CGF,
const ObjCAtSynchronizedStmt &S);
virtual void EmitThrowStmt(CodeGenFunction &CGF,
- const ObjCAtThrowStmt &S);
+ const ObjCAtThrowStmt &S,
+ bool ClearInsertionPoint=true);
virtual llvm::Value * EmitObjCWeakRead(CodeGenFunction &CGF,
llvm::Value *AddrWeakObj);
virtual void EmitObjCWeakAssign(CodeGenFunction &CGF,
@@ -528,7 +557,7 @@ public:
virtual llvm::Value *EmitIvarOffset(CodeGenFunction &CGF,
const ObjCInterfaceDecl *Interface,
const ObjCIvarDecl *Ivar);
- virtual llvm::Value *EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder);
+ virtual llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF);
virtual llvm::Constant *BuildGCBlockLayout(CodeGenModule &CGM,
const CGBlockInfo &blockInfo) {
return NULLPtr;
@@ -537,6 +566,12 @@ public:
const CGBlockInfo &blockInfo) {
return NULLPtr;
}
+
+ virtual llvm::Constant *BuildByrefLayout(CodeGenModule &CGM,
+ QualType T) {
+ return NULLPtr;
+ }
+
virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) {
return 0;
}
@@ -566,7 +601,7 @@ protected:
llvm::Value *args[] = {
EnforceType(Builder, Receiver, IdTy),
EnforceType(Builder, cmd, SelectorTy) };
- llvm::CallSite imp = CGF.EmitCallOrInvoke(MsgLookupFn, args);
+ llvm::CallSite imp = CGF.EmitRuntimeCallOrInvoke(MsgLookupFn, args);
imp->setMetadata(msgSendMDKind, node);
return imp.getInstruction();
}
@@ -576,7 +611,7 @@ protected:
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *lookupArgs[] = {EnforceType(Builder, ObjCSuper,
PtrToObjCSuperTy), cmd};
- return Builder.CreateCall(MsgLookupSuperFn, lookupArgs);
+ return CGF.EmitNounwindRuntimeCall(MsgLookupSuperFn, lookupArgs);
}
public:
CGObjCGCC(CodeGenModule &Mod) : CGObjCGNU(Mod, 8, 2) {
@@ -597,6 +632,20 @@ class CGObjCGNUstep : public CGObjCGNU {
/// arguments. Returns the slot for the corresponding method. Superclass
/// message lookup rarely changes, so this is a good caching opportunity.
LazyRuntimeFunction SlotLookupSuperFn;
+ /// Specialised function for setting atomic retain properties
+ LazyRuntimeFunction SetPropertyAtomic;
+ /// Specialised function for setting atomic copy properties
+ LazyRuntimeFunction SetPropertyAtomicCopy;
+ /// Specialised function for setting nonatomic retain properties
+ LazyRuntimeFunction SetPropertyNonAtomic;
+ /// Specialised function for setting nonatomic copy properties
+ LazyRuntimeFunction SetPropertyNonAtomicCopy;
+ /// Function to perform atomic copies of C++ objects with nontrivial copy
+ /// constructors from Objective-C ivars.
+ LazyRuntimeFunction CxxAtomicObjectGetFn;
+ /// Function to perform atomic copies of C++ objects with nontrivial copy
+ /// constructors to Objective-C ivars.
+ LazyRuntimeFunction CxxAtomicObjectSetFn;
/// Type of an slot structure pointer. This is returned by the various
/// lookup functions.
llvm::Type *SlotTy;
@@ -629,7 +678,7 @@ class CGObjCGNUstep : public CGObjCGNU {
EnforceType(Builder, ReceiverPtr, PtrToIdTy),
EnforceType(Builder, cmd, SelectorTy),
EnforceType(Builder, self, IdTy) };
- llvm::CallSite slot = CGF.EmitCallOrInvoke(LookupFn, args);
+ llvm::CallSite slot = CGF.EmitRuntimeCallOrInvoke(LookupFn, args);
slot.setOnlyReadsMemory();
slot->setMetadata(msgSendMDKind, node);
@@ -648,13 +697,16 @@ class CGObjCGNUstep : public CGObjCGNU {
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *lookupArgs[] = {ObjCSuper, cmd};
- llvm::CallInst *slot = Builder.CreateCall(SlotLookupSuperFn, lookupArgs);
+ llvm::CallInst *slot =
+ CGF.EmitNounwindRuntimeCall(SlotLookupSuperFn, lookupArgs);
slot->setOnlyReadsMemory();
return Builder.CreateLoad(Builder.CreateStructGEP(slot, 4));
}
public:
CGObjCGNUstep(CodeGenModule &Mod) : CGObjCGNU(Mod, 9, 3) {
+ const ObjCRuntime &R = CGM.getLangOpts().ObjCRuntime;
+
llvm::StructType *SlotStructTy = llvm::StructType::get(PtrTy,
PtrTy, PtrTy, IntTy, IMPTy, NULL);
SlotTy = llvm::PointerType::getUnqual(SlotStructTy);
@@ -672,8 +724,69 @@ class CGObjCGNUstep : public CGObjCGNU {
// void __cxa_end_catch(void)
ExitCatchFn.init(&CGM, "__cxa_end_catch", VoidTy, NULL);
// void _Unwind_Resume_or_Rethrow(void*)
- ExceptionReThrowFn.init(&CGM, "_Unwind_Resume_or_Rethrow", VoidTy, PtrTy, NULL);
+ ExceptionReThrowFn.init(&CGM, "_Unwind_Resume_or_Rethrow", VoidTy,
+ PtrTy, NULL);
+ } else if (R.getVersion() >= VersionTuple(1, 7)) {
+ llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
+ // id objc_begin_catch(void *e)
+ EnterCatchFn.init(&CGM, "objc_begin_catch", IdTy, PtrTy, NULL);
+ // void objc_end_catch(void)
+ ExitCatchFn.init(&CGM, "objc_end_catch", VoidTy, NULL);
+ // void _Unwind_Resume_or_Rethrow(void*)
+ ExceptionReThrowFn.init(&CGM, "objc_exception_rethrow", VoidTy,
+ PtrTy, NULL);
}
+ llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext);
+ SetPropertyAtomic.init(&CGM, "objc_setProperty_atomic", VoidTy, IdTy,
+ SelectorTy, IdTy, PtrDiffTy, NULL);
+ SetPropertyAtomicCopy.init(&CGM, "objc_setProperty_atomic_copy", VoidTy,
+ IdTy, SelectorTy, IdTy, PtrDiffTy, NULL);
+ SetPropertyNonAtomic.init(&CGM, "objc_setProperty_nonatomic", VoidTy,
+ IdTy, SelectorTy, IdTy, PtrDiffTy, NULL);
+ SetPropertyNonAtomicCopy.init(&CGM, "objc_setProperty_nonatomic_copy",
+ VoidTy, IdTy, SelectorTy, IdTy, PtrDiffTy, NULL);
+ // void objc_setCppObjectAtomic(void *dest, const void *src, void
+ // *helper);
+ CxxAtomicObjectSetFn.init(&CGM, "objc_setCppObjectAtomic", VoidTy, PtrTy,
+ PtrTy, PtrTy, NULL);
+ // void objc_getCppObjectAtomic(void *dest, const void *src, void
+ // *helper);
+ CxxAtomicObjectGetFn.init(&CGM, "objc_getCppObjectAtomic", VoidTy, PtrTy,
+ PtrTy, PtrTy, NULL);
+ }
+ virtual llvm::Constant *GetCppAtomicObjectGetFunction() {
+ // The optimised functions were added in version 1.7 of the GNUstep
+ // runtime.
+ assert (CGM.getLangOpts().ObjCRuntime.getVersion() >=
+ VersionTuple(1, 7));
+ return CxxAtomicObjectGetFn;
+ }
+ virtual llvm::Constant *GetCppAtomicObjectSetFunction() {
+ // The optimised functions were added in version 1.7 of the GNUstep
+ // runtime.
+ assert (CGM.getLangOpts().ObjCRuntime.getVersion() >=
+ VersionTuple(1, 7));
+ return CxxAtomicObjectSetFn;
+ }
+ virtual llvm::Constant *GetOptimizedPropertySetFunction(bool atomic,
+ bool copy) {
+ // The optimised property functions omit the GC check, and so are not
+ // safe to use in GC mode. The standard functions are fast in GC mode,
+ // so there is less advantage in using them.
+ assert ((CGM.getLangOpts().getGC() == LangOptions::NonGC));
+ // The optimised functions were added in version 1.7 of the GNUstep
+ // runtime.
+ assert (CGM.getLangOpts().ObjCRuntime.getVersion() >=
+ VersionTuple(1, 7));
+
+ if (atomic) {
+ if (copy) return SetPropertyAtomicCopy;
+ return SetPropertyAtomic;
+ }
+ if (copy) return SetPropertyNonAtomicCopy;
+ return SetPropertyNonAtomic;
+
+ return 0;
}
};
@@ -697,7 +810,7 @@ protected:
llvm::Value *args[] = {
EnforceType(Builder, Receiver, IdTy),
EnforceType(Builder, cmd, SelectorTy) };
- llvm::CallSite imp = CGF.EmitCallOrInvoke(MsgLookupFn, args);
+ llvm::CallSite imp = CGF.EmitRuntimeCallOrInvoke(MsgLookupFn, args);
imp->setMetadata(msgSendMDKind, node);
return imp.getInstruction();
}
@@ -708,13 +821,13 @@ protected:
CGBuilderTy &Builder = CGF.Builder;
llvm::Value *lookupArgs[] = {EnforceType(Builder, ObjCSuper,
PtrToObjCSuperTy), cmd};
- return Builder.CreateCall(MsgLookupSuperFn, lookupArgs);
+ return CGF.EmitNounwindRuntimeCall(MsgLookupSuperFn, lookupArgs);
}
- virtual llvm::Value *GetClassNamed(CGBuilderTy &Builder,
+ virtual llvm::Value *GetClassNamed(CodeGenFunction &CGF,
const std::string &Name, bool isWeak) {
if (isWeak)
- return CGObjCGNU::GetClassNamed(Builder, Name, isWeak);
+ return CGObjCGNU::GetClassNamed(CGF, Name, isWeak);
EmitClassRef(Name);
@@ -894,7 +1007,7 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
}
}
-llvm::Value *CGObjCGNU::GetClassNamed(CGBuilderTy &Builder,
+llvm::Value *CGObjCGNU::GetClassNamed(CodeGenFunction &CGF,
const std::string &Name,
bool isWeak) {
llvm::Value *ClassName = CGM.GetAddrOfConstantCString(Name);
@@ -907,25 +1020,25 @@ llvm::Value *CGObjCGNU::GetClassNamed(CGBuilderTy &Builder,
// with memoized versions or with static references if it's safe to do so.
if (!isWeak)
EmitClassRef(Name);
- ClassName = Builder.CreateStructGEP(ClassName, 0);
+ ClassName = CGF.Builder.CreateStructGEP(ClassName, 0);
llvm::Constant *ClassLookupFn =
CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, PtrToInt8Ty, true),
"objc_lookup_class");
- return Builder.CreateCall(ClassLookupFn, ClassName);
+ return CGF.EmitNounwindRuntimeCall(ClassLookupFn, ClassName);
}
// This has to perform the lookup every time, since posing and related
// techniques can modify the name -> class mapping.
-llvm::Value *CGObjCGNU::GetClass(CGBuilderTy &Builder,
+llvm::Value *CGObjCGNU::GetClass(CodeGenFunction &CGF,
const ObjCInterfaceDecl *OID) {
- return GetClassNamed(Builder, OID->getNameAsString(), OID->isWeakImported());
+ return GetClassNamed(CGF, OID->getNameAsString(), OID->isWeakImported());
}
-llvm::Value *CGObjCGNU::EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder) {
- return GetClassNamed(Builder, "NSAutoreleasePool", false);
+llvm::Value *CGObjCGNU::EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) {
+ return GetClassNamed(CGF, "NSAutoreleasePool", false);
}
-llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, Selector Sel,
+llvm::Value *CGObjCGNU::GetSelector(CodeGenFunction &CGF, Selector Sel,
const std::string &TypeEncoding, bool lval) {
SmallVector<TypedSelector, 2> &Types = SelectorTable[Sel];
@@ -948,23 +1061,23 @@ llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, Selector Sel,
}
if (lval) {
- llvm::Value *tmp = Builder.CreateAlloca(SelValue->getType());
- Builder.CreateStore(SelValue, tmp);
+ llvm::Value *tmp = CGF.CreateTempAlloca(SelValue->getType());
+ CGF.Builder.CreateStore(SelValue, tmp);
return tmp;
}
return SelValue;
}
-llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, Selector Sel,
+llvm::Value *CGObjCGNU::GetSelector(CodeGenFunction &CGF, Selector Sel,
bool lval) {
- return GetSelector(Builder, Sel, std::string(), lval);
+ return GetSelector(CGF, Sel, std::string(), lval);
}
-llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl
- *Method) {
+llvm::Value *CGObjCGNU::GetSelector(CodeGenFunction &CGF,
+ const ObjCMethodDecl *Method) {
std::string SelTypes;
CGM.getContext().getObjCEncodingForMethodDecl(Method, SelTypes);
- return GetSelector(Builder, Method->getSelector(), SelTypes, false);
+ return GetSelector(CGF, Method->getSelector(), SelTypes, false);
}
llvm::Constant *CGObjCGNU::GetEHType(QualType T) {
@@ -1114,7 +1227,7 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF,
}
}
- llvm::Value *cmd = GetSelector(Builder, Sel);
+ llvm::Value *cmd = GetSelector(CGF, Sel);
CallArgList ActualArgs;
@@ -1249,9 +1362,9 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy));
llvm::Value *cmd;
if (Method)
- cmd = GetSelector(Builder, Method);
+ cmd = GetSelector(CGF, Method);
else
- cmd = GetSelector(Builder, Sel);
+ cmd = GetSelector(CGF, Sel);
cmd = EnforceType(Builder, cmd, SelectorTy);
Receiver = EnforceType(Builder, Receiver, IdTy);
@@ -1594,12 +1707,12 @@ llvm::Constant *CGObjCGNU::GenerateProtocolList(ArrayRef<std::string>Protocols){
return MakeGlobal(ProtocolListTy, Elements, ".objc_protocol_list");
}
-llvm::Value *CGObjCGNU::GenerateProtocolRef(CGBuilderTy &Builder,
+llvm::Value *CGObjCGNU::GenerateProtocolRef(CodeGenFunction &CGF,
const ObjCProtocolDecl *PD) {
llvm::Value *protocol = ExistingProtocols[PD->getNameAsString()];
llvm::Type *T =
CGM.getTypes().ConvertType(CGM.getContext().getObjCProtoType());
- return Builder.CreateBitCast(protocol, llvm::PointerType::getUnqual(T));
+ return CGF.Builder.CreateBitCast(protocol, llvm::PointerType::getUnqual(T));
}
llvm::Constant *CGObjCGNU::GenerateEmptyProtocol(
@@ -1703,8 +1816,8 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
// simplify the runtime library by allowing it to use the same data
// structures for protocol metadata everywhere.
llvm::StructType *PropertyMetadataTy = llvm::StructType::get(
- PtrToInt8Ty, Int8Ty, Int8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty,
- PtrToInt8Ty, NULL);
+ PtrToInt8Ty, Int8Ty, Int8Ty, Int8Ty, Int8Ty, PtrToInt8Ty,
+ PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, NULL);
std::vector<llvm::Constant*> Properties;
std::vector<llvm::Constant*> OptionalProperties;
@@ -1716,12 +1829,9 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
std::vector<llvm::Constant*> Fields;
ObjCPropertyDecl *property = *iter;
+ Fields.push_back(MakePropertyEncodingString(property, 0));
+ PushPropertyAttributes(Fields, property);
- Fields.push_back(MakePropertyEncodingString(property, PD));
-
- Fields.push_back(llvm::ConstantInt::get(Int8Ty,
- property->getPropertyAttributes()));
- Fields.push_back(llvm::ConstantInt::get(Int8Ty, 0));
if (ObjCMethodDecl *getter = property->getGetterMethodDecl()) {
std::string TypeStr;
Context.getObjCEncodingForMethodDecl(getter,TypeStr);
@@ -1804,7 +1914,7 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
llvm::ConstantExpr::getBitCast(MakeGlobal(ProtocolTy, Elements,
".objc_protocol"), IdTy);
}
-void CGObjCGNU::GenerateProtocolHolderCategory(void) {
+void CGObjCGNU::GenerateProtocolHolderCategory() {
// Collect information about instance methods
SmallVector<Selector, 1> MethodSels;
SmallVector<llvm::Constant*, 1> MethodTypes;
@@ -1872,7 +1982,7 @@ llvm::Constant *CGObjCGNU::MakeBitField(ArrayRef<bool> bits) {
}
return llvm::ConstantInt::get(IntPtrTy, val);
}
- llvm::SmallVector<llvm::Constant*, 8> values;
+ SmallVector<llvm::Constant *, 8> values;
int v=0;
while (v < bitCount) {
int32_t word = 0;
@@ -1951,15 +2061,13 @@ llvm::Constant *CGObjCGNU::GeneratePropertyList(const ObjCImplementationDecl *OI
SmallVectorImpl<Selector> &InstanceMethodSels,
SmallVectorImpl<llvm::Constant*> &InstanceMethodTypes) {
ASTContext &Context = CGM.getContext();
- //
- // Property metadata: name, attributes, isSynthesized, setter name, setter
- // types, getter name, getter types.
+ // Property metadata: name, attributes, attributes2, padding1, padding2,
+ // setter name, setter types, getter name, getter types.
llvm::StructType *PropertyMetadataTy = llvm::StructType::get(
- PtrToInt8Ty, Int8Ty, Int8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty,
- PtrToInt8Ty, NULL);
+ PtrToInt8Ty, Int8Ty, Int8Ty, Int8Ty, Int8Ty, PtrToInt8Ty,
+ PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, NULL);
std::vector<llvm::Constant*> Properties;
-
// Add all of the property methods need adding to the method list and to the
// property metadata list.
for (ObjCImplDecl::propimpl_iterator
@@ -1970,11 +2078,11 @@ llvm::Constant *CGObjCGNU::GeneratePropertyList(const ObjCImplementationDecl *OI
ObjCPropertyImplDecl *propertyImpl = *iter;
bool isSynthesized = (propertyImpl->getPropertyImplementation() ==
ObjCPropertyImplDecl::Synthesize);
+ bool isDynamic = (propertyImpl->getPropertyImplementation() ==
+ ObjCPropertyImplDecl::Dynamic);
Fields.push_back(MakePropertyEncodingString(property, OID));
- Fields.push_back(llvm::ConstantInt::get(Int8Ty,
- property->getPropertyAttributes()));
- Fields.push_back(llvm::ConstantInt::get(Int8Ty, isSynthesized));
+ PushPropertyAttributes(Fields, property, isSynthesized, isDynamic);
if (ObjCMethodDecl *getter = property->getGetterMethodDecl()) {
std::string TypeStr;
Context.getObjCEncodingForMethodDecl(getter,TypeStr);
@@ -2531,7 +2639,10 @@ llvm::Constant *CGObjCGNU::GetGetStructFunction() {
llvm::Constant *CGObjCGNU::GetSetStructFunction() {
return SetStructPropertyFn;
}
-llvm::Constant *CGObjCGNU::GetCppAtomicObjectFunction() {
+llvm::Constant *CGObjCGNU::GetCppAtomicObjectGetFunction() {
+ return 0;
+}
+llvm::Constant *CGObjCGNU::GetCppAtomicObjectSetFunction() {
return 0;
}
@@ -2563,7 +2674,8 @@ void CGObjCGNU::EmitTryStmt(CodeGenFunction &CGF,
}
void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF,
- const ObjCAtThrowStmt &S) {
+ const ObjCAtThrowStmt &S,
+ bool ClearInsertionPoint) {
llvm::Value *ExceptionAsObject;
if (const Expr *ThrowExpr = S.getThrowExpr()) {
@@ -2576,22 +2688,23 @@ void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF,
}
ExceptionAsObject = CGF.Builder.CreateBitCast(ExceptionAsObject, IdTy);
llvm::CallSite Throw =
- CGF.EmitCallOrInvoke(ExceptionThrowFn, ExceptionAsObject);
+ CGF.EmitRuntimeCallOrInvoke(ExceptionThrowFn, ExceptionAsObject);
Throw.setDoesNotReturn();
CGF.Builder.CreateUnreachable();
- CGF.Builder.ClearInsertionPoint();
+ if (ClearInsertionPoint)
+ CGF.Builder.ClearInsertionPoint();
}
llvm::Value * CGObjCGNU::EmitObjCWeakRead(CodeGenFunction &CGF,
llvm::Value *AddrWeakObj) {
- CGBuilderTy B = CGF.Builder;
+ CGBuilderTy &B = CGF.Builder;
AddrWeakObj = EnforceType(B, AddrWeakObj, PtrToIdTy);
return B.CreateCall(WeakReadFn, AddrWeakObj);
}
void CGObjCGNU::EmitObjCWeakAssign(CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
- CGBuilderTy B = CGF.Builder;
+ CGBuilderTy &B = CGF.Builder;
src = EnforceType(B, src, IdTy);
dst = EnforceType(B, dst, PtrToIdTy);
B.CreateCall2(WeakAssignFn, src, dst);
@@ -2600,7 +2713,7 @@ void CGObjCGNU::EmitObjCWeakAssign(CodeGenFunction &CGF,
void CGObjCGNU::EmitObjCGlobalAssign(CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst,
bool threadlocal) {
- CGBuilderTy B = CGF.Builder;
+ CGBuilderTy &B = CGF.Builder;
src = EnforceType(B, src, IdTy);
dst = EnforceType(B, dst, PtrToIdTy);
if (!threadlocal)
@@ -2613,7 +2726,7 @@ void CGObjCGNU::EmitObjCGlobalAssign(CodeGenFunction &CGF,
void CGObjCGNU::EmitObjCIvarAssign(CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst,
llvm::Value *ivarOffset) {
- CGBuilderTy B = CGF.Builder;
+ CGBuilderTy &B = CGF.Builder;
src = EnforceType(B, src, IdTy);
dst = EnforceType(B, dst, IdTy);
B.CreateCall3(IvarAssignFn, src, dst, ivarOffset);
@@ -2621,7 +2734,7 @@ void CGObjCGNU::EmitObjCIvarAssign(CodeGenFunction &CGF,
void CGObjCGNU::EmitObjCStrongCastAssign(CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
- CGBuilderTy B = CGF.Builder;
+ CGBuilderTy &B = CGF.Builder;
src = EnforceType(B, src, IdTy);
dst = EnforceType(B, dst, PtrToIdTy);
B.CreateCall2(StrongCastAssignFn, src, dst);
@@ -2631,7 +2744,7 @@ void CGObjCGNU::EmitGCMemmoveCollectable(CodeGenFunction &CGF,
llvm::Value *DestPtr,
llvm::Value *SrcPtr,
llvm::Value *Size) {
- CGBuilderTy B = CGF.Builder;
+ CGBuilderTy &B = CGF.Builder;
DestPtr = EnforceType(B, DestPtr, PtrTy);
SrcPtr = EnforceType(B, SrcPtr, PtrTy);
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 2203f01..6274e1b 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -12,12 +12,11 @@
//===----------------------------------------------------------------------===//
#include "CGObjCRuntime.h"
-
-#include "CGRecordLayout.h"
-#include "CodeGenModule.h"
-#include "CodeGenFunction.h"
#include "CGBlocks.h"
#include "CGCleanup.h"
+#include "CGRecordLayout.h"
+#include "CodeGenFunction.h"
+#include "CodeGenModule.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
@@ -25,18 +24,17 @@
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Frontend/CodeGenOptions.h"
-
-#include "llvm/InlineAsm.h"
-#include "llvm/IntrinsicInst.h"
-#include "llvm/LLVMContext.h"
-#include "llvm/Module.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SetVector.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/InlineAsm.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/DataLayout.h"
#include <cstdio>
using namespace clang;
@@ -63,11 +61,13 @@ private:
// Add the non-lazy-bind attribute, since objc_msgSend is likely to
// be called a lot.
llvm::Type *params[] = { ObjectPtrTy, SelectorPtrTy };
- return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
- params, true),
- "objc_msgSend",
- llvm::Attributes::get(CGM.getLLVMContext(),
- llvm::Attributes::NonLazyBind));
+ return
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
+ params, true),
+ "objc_msgSend",
+ llvm::AttributeSet::get(CGM.getLLVMContext(),
+ llvm::AttributeSet::FunctionIndex,
+ llvm::Attribute::NonLazyBind));
}
/// void objc_msgSend_stret (id, SEL, ...)
@@ -581,11 +581,13 @@ public:
llvm::Constant *getSetJmpFn() {
// This is specifically the prototype for x86.
llvm::Type *params[] = { CGM.Int32Ty->getPointerTo() };
- return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.Int32Ty,
- params, false),
- "_setjmp",
- llvm::Attributes::get(CGM.getLLVMContext(),
- llvm::Attributes::NonLazyBind));
+ return
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.Int32Ty,
+ params, false),
+ "_setjmp",
+ llvm::AttributeSet::get(CGM.getLLVMContext(),
+ llvm::AttributeSet::FunctionIndex,
+ llvm::Attribute::NonLazyBind));
}
public:
@@ -881,16 +883,16 @@ protected:
llvm::DenseSet<IdentifierInfo*> DefinedProtocols;
/// DefinedClasses - List of defined classes.
- llvm::SmallVector<llvm::GlobalValue*, 16> DefinedClasses;
+ SmallVector<llvm::GlobalValue*, 16> DefinedClasses;
/// DefinedNonLazyClasses - List of defined "non-lazy" classes.
- llvm::SmallVector<llvm::GlobalValue*, 16> DefinedNonLazyClasses;
+ SmallVector<llvm::GlobalValue*, 16> DefinedNonLazyClasses;
/// DefinedCategories - List of defined categories.
- llvm::SmallVector<llvm::GlobalValue*, 16> DefinedCategories;
+ SmallVector<llvm::GlobalValue*, 16> DefinedCategories;
/// DefinedNonLazyCategories - List of defined "non-lazy" categories.
- llvm::SmallVector<llvm::GlobalValue*, 16> DefinedNonLazyCategories;
+ SmallVector<llvm::GlobalValue*, 16> DefinedNonLazyCategories;
/// GetNameForMethod - Return a name for the given method.
/// \param[out] NameOut - The return value.
@@ -943,7 +945,7 @@ protected:
unsigned int BytePos, bool ForStrongLayout,
bool &HasUnion);
- Qualifiers::ObjCLifetime getBlockCaptureLifetime(QualType QT);
+ Qualifiers::ObjCLifetime getBlockCaptureLifetime(QualType QT, bool ByrefLayout);
void UpdateRunSkipBlockVars(bool IsByref,
Qualifiers::ObjCLifetime LifeTime,
@@ -951,15 +953,19 @@ protected:
CharUnits FieldSize);
void BuildRCBlockVarRecordLayout(const RecordType *RT,
- CharUnits BytePos, bool &HasUnion);
+ CharUnits BytePos, bool &HasUnion,
+ bool ByrefLayout=false);
void BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
const RecordDecl *RD,
ArrayRef<const FieldDecl*> RecFields,
- CharUnits BytePos, bool &HasUnion);
+ CharUnits BytePos, bool &HasUnion,
+ bool ByrefLayout);
uint64_t InlineLayoutInstruction(SmallVectorImpl<unsigned char> &Layout);
+ llvm::Constant *getBitmapBlockLayout(bool ComputeByrefLayout);
+
/// GetIvarLayoutName - Returns a unique constant for the given
/// ivar layout bitmap.
@@ -982,7 +988,7 @@ protected:
/// PushProtocolProperties - Push protocol's property on the input stack.
void PushProtocolProperties(
llvm::SmallPtrSet<const IdentifierInfo*, 16> &PropertySet,
- llvm::SmallVectorImpl<llvm::Constant*> &Properties,
+ SmallVectorImpl<llvm::Constant*> &Properties,
const Decl *Container,
const ObjCProtocolDecl *PROTO,
const ObjCCommonTypesHelper &ObjCTypes);
@@ -1053,6 +1059,8 @@ public:
virtual llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM,
const CGBlockInfo &blockInfo);
+ virtual llvm::Constant *BuildByrefLayout(CodeGen::CodeGenModule &CGM,
+ QualType T);
};
class CGObjCMac : public CGObjCCommonMac {
@@ -1078,13 +1086,13 @@ private:
/// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
/// for the given class.
- llvm::Value *EmitClassRef(CGBuilderTy &Builder,
+ llvm::Value *EmitClassRef(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID);
- llvm::Value *EmitClassRefFromId(CGBuilderTy &Builder,
+ llvm::Value *EmitClassRefFromId(CodeGenFunction &CGF,
IdentifierInfo *II);
- llvm::Value *EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder);
+ llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF);
/// EmitSuperClassRef - Emits reference to class's main metadata class.
llvm::Value *EmitSuperClassRef(const ObjCInterfaceDecl *ID);
@@ -1162,7 +1170,7 @@ private:
/// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy,
/// for the given selector.
- llvm::Value *EmitSelector(CGBuilderTy &Builder, Selector Sel,
+ llvm::Value *EmitSelector(CodeGenFunction &CGF, Selector Sel,
bool lval=false);
public:
@@ -1191,15 +1199,15 @@ public:
const CallArgList &CallArgs,
const ObjCMethodDecl *Method);
- virtual llvm::Value *GetClass(CGBuilderTy &Builder,
+ virtual llvm::Value *GetClass(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID);
- virtual llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel,
+ virtual llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel,
bool lval = false);
/// The NeXT/Apple runtimes do not support typed selectors; just emit an
/// untyped one.
- virtual llvm::Value *GetSelector(CGBuilderTy &Builder,
+ virtual llvm::Value *GetSelector(CodeGenFunction &CGF,
const ObjCMethodDecl *Method);
virtual llvm::Constant *GetEHType(QualType T);
@@ -1210,7 +1218,7 @@ public:
virtual void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) {}
- virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder,
+ virtual llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF,
const ObjCProtocolDecl *PD);
virtual llvm::Constant *GetPropertyGetFunction();
@@ -1219,7 +1227,8 @@ public:
bool copy);
virtual llvm::Constant *GetGetStructFunction();
virtual llvm::Constant *GetSetStructFunction();
- virtual llvm::Constant *GetCppAtomicObjectFunction();
+ virtual llvm::Constant *GetCppAtomicObjectGetFunction();
+ virtual llvm::Constant *GetCppAtomicObjectSetFunction();
virtual llvm::Constant *EnumerationMutationFunction();
virtual void EmitTryStmt(CodeGen::CodeGenFunction &CGF,
@@ -1228,7 +1237,8 @@ public:
const ObjCAtSynchronizedStmt &S);
void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, const Stmt &S);
virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
- const ObjCAtThrowStmt &S);
+ const ObjCAtThrowStmt &S,
+ bool ClearInsertionPoint=true);
virtual llvm::Value * EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
llvm::Value *AddrWeakObj);
virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
@@ -1360,22 +1370,22 @@ private:
/// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
/// for the given class reference.
- llvm::Value *EmitClassRef(CGBuilderTy &Builder,
+ llvm::Value *EmitClassRef(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID);
- llvm::Value *EmitClassRefFromId(CGBuilderTy &Builder,
+ llvm::Value *EmitClassRefFromId(CodeGenFunction &CGF,
IdentifierInfo *II);
- llvm::Value *EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder);
+ llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF);
/// EmitSuperClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
/// for the given super class reference.
- llvm::Value *EmitSuperClassRef(CGBuilderTy &Builder,
+ llvm::Value *EmitSuperClassRef(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID);
/// EmitMetaClassRef - Return a Value * of the address of _class_t
/// meta-data
- llvm::Value *EmitMetaClassRef(CGBuilderTy &Builder,
+ llvm::Value *EmitMetaClassRef(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID);
/// ObjCIvarOffsetVariable - Returns the ivar offset variable for
@@ -1387,7 +1397,7 @@ private:
/// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy,
/// for the given selector.
- llvm::Value *EmitSelector(CGBuilderTy &Builder, Selector Sel,
+ llvm::Value *EmitSelector(CodeGenFunction &CGF, Selector Sel,
bool lval=false);
/// GetInterfaceEHType - Get the cached ehtype for the given Objective-C
@@ -1422,6 +1432,25 @@ private:
/// class implementation is "non-lazy".
bool ImplementationIsNonLazy(const ObjCImplDecl *OD) const;
+ bool IsIvarOffsetKnownIdempotent(const CodeGen::CodeGenFunction &CGF,
+ const ObjCInterfaceDecl *ID,
+ const ObjCIvarDecl *IV) {
+ // Annotate the load as an invariant load iff the object type is the type,
+ // or a derived type, of the class containing the ivar within an ObjC
+ // method. This check is needed because the ivar offset is a lazily
+ // initialised value that may depend on objc_msgSend to perform a fixup on
+ // the first message dispatch.
+ //
+ // An additional opportunity to mark the load as invariant arises when the
+ // base of the ivar access is a parameter to an Objective C method.
+ // However, because the parameters are not available in the current
+ // interface, we cannot perform this check.
+ if (CGF.CurFuncDecl && isa<ObjCMethodDecl>(CGF.CurFuncDecl))
+ if (IV->getContainingInterface()->isSuperClassOf(ID))
+ return true;
+ return false;
+ }
+
public:
CGObjCNonFragileABIMac(CodeGen::CodeGenModule &cgm);
// FIXME. All stubs for now!
@@ -1448,18 +1477,18 @@ public:
const CallArgList &CallArgs,
const ObjCMethodDecl *Method);
- virtual llvm::Value *GetClass(CGBuilderTy &Builder,
+ virtual llvm::Value *GetClass(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID);
- virtual llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel,
+ virtual llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel,
bool lvalue = false)
- { return EmitSelector(Builder, Sel, lvalue); }
+ { return EmitSelector(CGF, Sel, lvalue); }
/// The NeXT/Apple runtimes do not support typed selectors; just emit an
/// untyped one.
- virtual llvm::Value *GetSelector(CGBuilderTy &Builder,
+ virtual llvm::Value *GetSelector(CodeGenFunction &CGF,
const ObjCMethodDecl *Method)
- { return EmitSelector(Builder, Method->getSelector()); }
+ { return EmitSelector(CGF, Method->getSelector()); }
virtual void GenerateCategory(const ObjCCategoryImplDecl *CMD);
@@ -1467,7 +1496,7 @@ public:
virtual void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) {}
- virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder,
+ virtual llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF,
const ObjCProtocolDecl *PD);
virtual llvm::Constant *GetEHType(QualType T);
@@ -1490,7 +1519,10 @@ public:
virtual llvm::Constant *GetGetStructFunction() {
return ObjCTypes.getCopyStructFn();
}
- virtual llvm::Constant *GetCppAtomicObjectFunction() {
+ virtual llvm::Constant *GetCppAtomicObjectSetFunction() {
+ return ObjCTypes.getCppAtomicObjectFunction();
+ }
+ virtual llvm::Constant *GetCppAtomicObjectGetFunction() {
return ObjCTypes.getCppAtomicObjectFunction();
}
@@ -1503,7 +1535,8 @@ public:
virtual void EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
const ObjCAtSynchronizedStmt &S);
virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
- const ObjCAtThrowStmt &S);
+ const ObjCAtThrowStmt &S,
+ bool ClearInsertionPoint=true);
virtual llvm::Value * EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
llvm::Value *AddrWeakObj);
virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
@@ -1533,16 +1566,18 @@ public:
/// value.
struct NullReturnState {
llvm::BasicBlock *NullBB;
- llvm::BasicBlock *callBB;
- NullReturnState() : NullBB(0), callBB(0) {}
+ NullReturnState() : NullBB(0) {}
+ /// Perform a null-check of the given receiver.
void init(CodeGenFunction &CGF, llvm::Value *receiver) {
- // Make blocks for the null-init and call edges.
- NullBB = CGF.createBasicBlock("msgSend.nullinit");
- callBB = CGF.createBasicBlock("msgSend.call");
+ // Make blocks for the null-receiver and call edges.
+ NullBB = CGF.createBasicBlock("msgSend.null-receiver");
+ llvm::BasicBlock *callBB = CGF.createBasicBlock("msgSend.call");
// Check for a null receiver and, if there is one, jump to the
- // null-init test.
+ // null-receiver block. There's no point in trying to avoid it:
+ // we're always going to put *something* there, because otherwise
+ // we shouldn't have done this null-check in the first place.
llvm::Value *isNull = CGF.Builder.CreateIsNull(receiver);
CGF.Builder.CreateCondBr(isNull, NullBB, callBB);
@@ -1550,25 +1585,29 @@ struct NullReturnState {
CGF.EmitBlock(callBB);
}
+ /// Complete the null-return operation. It is valid to call this
+ /// regardless of whether 'init' has been called.
RValue complete(CodeGenFunction &CGF, RValue result, QualType resultType,
const CallArgList &CallArgs,
const ObjCMethodDecl *Method) {
+ // If we never had to do a null-check, just use the raw result.
if (!NullBB) return result;
-
- llvm::Value *NullInitPtr = 0;
- if (result.isScalar() && !resultType->isVoidType()) {
- NullInitPtr = CGF.CreateTempAlloca(result.getScalarVal()->getType());
- CGF.Builder.CreateStore(result.getScalarVal(), NullInitPtr);
- }
+ // The continuation block. This will be left null if we don't have an
+ // IP, which can happen if the method we're calling is marked noreturn.
+ llvm::BasicBlock *contBB = 0;
+
// Finish the call path.
- llvm::BasicBlock *contBB = CGF.createBasicBlock("msgSend.cont");
- if (CGF.HaveInsertPoint()) CGF.Builder.CreateBr(contBB);
+ llvm::BasicBlock *callBB = CGF.Builder.GetInsertBlock();
+ if (callBB) {
+ contBB = CGF.createBasicBlock("msgSend.cont");
+ CGF.Builder.CreateBr(contBB);
+ }
- // Emit the null-init block and perform the null-initialization there.
+ // Okay, start emitting the null-receiver block.
CGF.EmitBlock(NullBB);
- // Release consumed arguments along the null-receiver path.
+ // Release any consumed arguments we've got.
if (Method) {
CallArgList::const_iterator I = CallArgs.begin();
for (ObjCMethodDecl::param_const_iterator i = Method->param_begin(),
@@ -1578,43 +1617,64 @@ struct NullReturnState {
RValue RV = I->RV;
assert(RV.isScalar() &&
"NullReturnState::complete - arg not on object");
- CGF.EmitARCRelease(RV.getScalarVal(), true);
+ CGF.EmitARCRelease(RV.getScalarVal(), ARCImpreciseLifetime);
}
}
}
-
+
+ // The phi code below assumes that we haven't needed any control flow yet.
+ assert(CGF.Builder.GetInsertBlock() == NullBB);
+
+ // If we've got a void return, just jump to the continuation block.
+ if (result.isScalar() && resultType->isVoidType()) {
+ // No jumps required if the message-send was noreturn.
+ if (contBB) CGF.EmitBlock(contBB);
+ return result;
+ }
+
+ // If we've got a scalar return, build a phi.
if (result.isScalar()) {
- if (NullInitPtr)
- CGF.EmitNullInitialization(NullInitPtr, resultType);
- // Jump to the continuation block.
+ // Derive the null-initialization value.
+ llvm::Constant *null = CGF.CGM.EmitNullConstant(resultType);
+
+ // If no join is necessary, just flow out.
+ if (!contBB) return RValue::get(null);
+
+ // Otherwise, build a phi.
CGF.EmitBlock(contBB);
- return NullInitPtr ? RValue::get(CGF.Builder.CreateLoad(NullInitPtr))
- : result;
+ llvm::PHINode *phi = CGF.Builder.CreatePHI(null->getType(), 2);
+ phi->addIncoming(result.getScalarVal(), callBB);
+ phi->addIncoming(null, NullBB);
+ return RValue::get(phi);
}
-
- if (!resultType->isAnyComplexType()) {
+
+ // If we've got an aggregate return, null the buffer out.
+ // FIXME: maybe we should be doing things differently for all the
+ // cases where the ABI has us returning (1) non-agg values in
+ // memory or (2) agg values in registers.
+ if (result.isAggregate()) {
assert(result.isAggregate() && "null init of non-aggregate result?");
CGF.EmitNullInitialization(result.getAggregateAddr(), resultType);
- // Jump to the continuation block.
- CGF.EmitBlock(contBB);
+ if (contBB) CGF.EmitBlock(contBB);
return result;
}
- // _Complex type
- // FIXME. Now easy to handle any other scalar type whose result is returned
- // in memory due to ABI limitations.
+ // Complex types.
CGF.EmitBlock(contBB);
- CodeGenFunction::ComplexPairTy CallCV = result.getComplexVal();
- llvm::Type *MemberType = CallCV.first->getType();
- llvm::Constant *ZeroCV = llvm::Constant::getNullValue(MemberType);
- // Create phi instruction for scalar complex value.
- llvm::PHINode *PHIReal = CGF.Builder.CreatePHI(MemberType, 2);
- PHIReal->addIncoming(ZeroCV, NullBB);
- PHIReal->addIncoming(CallCV.first, callBB);
- llvm::PHINode *PHIImag = CGF.Builder.CreatePHI(MemberType, 2);
- PHIImag->addIncoming(ZeroCV, NullBB);
- PHIImag->addIncoming(CallCV.second, callBB);
- return RValue::getComplex(PHIReal, PHIImag);
+ CodeGenFunction::ComplexPairTy callResult = result.getComplexVal();
+
+ // Find the scalar type and its zero value.
+ llvm::Type *scalarTy = callResult.first->getType();
+ llvm::Constant *scalarZero = llvm::Constant::getNullValue(scalarTy);
+
+ // Build phis for both coordinates.
+ llvm::PHINode *real = CGF.Builder.CreatePHI(scalarTy, 2);
+ real->addIncoming(callResult.first, callBB);
+ real->addIncoming(scalarZero, NullBB);
+ llvm::PHINode *imag = CGF.Builder.CreatePHI(scalarTy, 2);
+ imag->addIncoming(callResult.second, callBB);
+ imag->addIncoming(scalarZero, NullBB);
+ return RValue::getComplex(real, imag);
}
};
@@ -1655,19 +1715,19 @@ CGObjCMac::CGObjCMac(CodeGen::CodeGenModule &cgm) : CGObjCCommonMac(cgm),
/// GetClass - Return a reference to the class for the given interface
/// decl.
-llvm::Value *CGObjCMac::GetClass(CGBuilderTy &Builder,
+llvm::Value *CGObjCMac::GetClass(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID) {
- return EmitClassRef(Builder, ID);
+ return EmitClassRef(CGF, ID);
}
/// GetSelector - Return the pointer to the unique'd string for this selector.
-llvm::Value *CGObjCMac::GetSelector(CGBuilderTy &Builder, Selector Sel,
+llvm::Value *CGObjCMac::GetSelector(CodeGenFunction &CGF, Selector Sel,
bool lval) {
- return EmitSelector(Builder, Sel, lval);
+ return EmitSelector(CGF, Sel, lval);
}
-llvm::Value *CGObjCMac::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl
+llvm::Value *CGObjCMac::GetSelector(CodeGenFunction &CGF, const ObjCMethodDecl
*Method) {
- return EmitSelector(Builder, Method->getSelector());
+ return EmitSelector(CGF, Method->getSelector());
}
llvm::Constant *CGObjCMac::GetEHType(QualType T) {
@@ -1750,7 +1810,7 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
// _metaclass_ for the current class, pointed at by
// the class's "isa" pointer. The following assumes that
// isa" is the first ivar in a class (which it must be).
- Target = EmitClassRef(CGF.Builder, Class->getSuperClass());
+ Target = EmitClassRef(CGF, Class->getSuperClass());
Target = CGF.Builder.CreateStructGEP(Target, 0);
Target = CGF.Builder.CreateLoad(Target);
} else {
@@ -1761,7 +1821,7 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
}
}
else if (isCategoryImpl)
- Target = EmitClassRef(CGF.Builder, Class->getSuperClass());
+ Target = EmitClassRef(CGF, Class->getSuperClass());
else {
llvm::Value *ClassPtr = EmitSuperClassRef(Class);
ClassPtr = CGF.Builder.CreateStructGEP(ClassPtr, 1);
@@ -1775,7 +1835,7 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
CGF.Builder.CreateStore(Target,
CGF.Builder.CreateStructGEP(ObjCSuper, 1));
return EmitMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF.Builder, Sel),
+ EmitSelector(CGF, Sel),
ObjCSuper, ObjCTypes.SuperPtrCTy,
true, CallArgs, Method, ObjCTypes);
}
@@ -1790,7 +1850,7 @@ CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method) {
return EmitMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF.Builder, Sel),
+ EmitSelector(CGF, Sel),
Receiver, CGF.getContext().getObjCIdType(),
false, CallArgs, Method, ObjCTypes);
}
@@ -1968,13 +2028,14 @@ llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM,
/// getBlockCaptureLifetime - This routine returns life time of the captured
/// block variable for the purpose of block layout meta-data generation. FQT is
/// the type of the variable captured in the block.
-Qualifiers::ObjCLifetime CGObjCCommonMac::getBlockCaptureLifetime(QualType FQT) {
+Qualifiers::ObjCLifetime CGObjCCommonMac::getBlockCaptureLifetime(QualType FQT,
+ bool ByrefLayout) {
if (CGM.getLangOpts().ObjCAutoRefCount)
return FQT.getObjCLifetime();
// MRR.
if (FQT->isObjCObjectPointerType() || FQT->isBlockPointerType())
- return Qualifiers::OCL_ExplicitNone;
+ return ByrefLayout ? Qualifiers::OCL_ExplicitNone : Qualifiers::OCL_Strong;
return Qualifiers::OCL_None;
}
@@ -2005,7 +2066,8 @@ void CGObjCCommonMac::UpdateRunSkipBlockVars(bool IsByref,
void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
const RecordDecl *RD,
ArrayRef<const FieldDecl*> RecFields,
- CharUnits BytePos, bool &HasUnion) {
+ CharUnits BytePos, bool &HasUnion,
+ bool ByrefLayout) {
bool IsUnion = (RD && RD->isUnion());
CharUnits MaxUnionSize = CharUnits::Zero();
const FieldDecl *MaxField = 0;
@@ -2088,7 +2150,7 @@ void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
}
} else {
UpdateRunSkipBlockVars(false,
- getBlockCaptureLifetime(FQT),
+ getBlockCaptureLifetime(FQT, ByrefLayout),
BytePos + FieldOffset,
FieldSize);
}
@@ -2104,7 +2166,8 @@ void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
CharUnits Size = CharUnits::fromQuantity(UnsSize);
Size += LastBitfieldOrUnnamedOffset;
UpdateRunSkipBlockVars(false,
- getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType()),
+ getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType(),
+ ByrefLayout),
BytePos + LastBitfieldOrUnnamedOffset,
Size);
} else {
@@ -2113,7 +2176,8 @@ void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
CharUnits FieldSize
= CGM.getContext().getTypeSizeInChars(LastFieldBitfieldOrUnnamed->getType());
UpdateRunSkipBlockVars(false,
- getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType()),
+ getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType(),
+ ByrefLayout),
BytePos + LastBitfieldOrUnnamedOffset,
FieldSize);
}
@@ -2121,14 +2185,15 @@ void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
if (MaxField)
UpdateRunSkipBlockVars(false,
- getBlockCaptureLifetime(MaxField->getType()),
+ getBlockCaptureLifetime(MaxField->getType(), ByrefLayout),
BytePos + MaxFieldOffset,
MaxUnionSize);
}
void CGObjCCommonMac::BuildRCBlockVarRecordLayout(const RecordType *RT,
CharUnits BytePos,
- bool &HasUnion) {
+ bool &HasUnion,
+ bool ByrefLayout) {
const RecordDecl *RD = RT->getDecl();
SmallVector<const FieldDecl*, 16> Fields;
for (RecordDecl::field_iterator i = RD->field_begin(),
@@ -2138,7 +2203,7 @@ void CGObjCCommonMac::BuildRCBlockVarRecordLayout(const RecordType *RT,
const llvm::StructLayout *RecLayout =
CGM.getDataLayout().getStructLayout(cast<llvm::StructType>(Ty));
- BuildRCRecordLayout(RecLayout, RD, Fields, BytePos, HasUnion);
+ BuildRCRecordLayout(RecLayout, RD, Fields, BytePos, HasUnion, ByrefLayout);
}
/// InlineLayoutInstruction - This routine produce an inline instruction for the
@@ -2247,64 +2312,19 @@ uint64_t CGObjCCommonMac::InlineLayoutInstruction(
return Result;
}
-llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
- const CGBlockInfo &blockInfo) {
- assert(CGM.getLangOpts().getGC() == LangOptions::NonGC);
-
+llvm::Constant *CGObjCCommonMac::getBitmapBlockLayout(bool ComputeByrefLayout) {
llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy);
-
- RunSkipBlockVars.clear();
- bool hasUnion = false;
-
+ if (RunSkipBlockVars.empty())
+ return nullPtr;
unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0);
unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth();
unsigned WordSizeInBytes = WordSizeInBits/ByteSizeInBits;
- const BlockDecl *blockDecl = blockInfo.getBlockDecl();
-
- // Calculate the basic layout of the block structure.
- const llvm::StructLayout *layout =
- CGM.getDataLayout().getStructLayout(blockInfo.StructureType);
-
- // Ignore the optional 'this' capture: C++ objects are not assumed
- // to be GC'ed.
-
- // Walk the captured variables.
- for (BlockDecl::capture_const_iterator ci = blockDecl->capture_begin(),
- ce = blockDecl->capture_end(); ci != ce; ++ci) {
- const VarDecl *variable = ci->getVariable();
- QualType type = variable->getType();
-
- const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
-
- // Ignore constant captures.
- if (capture.isConstant()) continue;
-
- CharUnits fieldOffset =
- CharUnits::fromQuantity(layout->getElementOffset(capture.getIndex()));
-
- assert(!type->isArrayType() && "array variable should not be caught");
- if (const RecordType *record = type->getAs<RecordType>()) {
- BuildRCBlockVarRecordLayout(record, fieldOffset, hasUnion);
- continue;
- }
- CharUnits fieldSize;
- if (ci->isByRef())
- fieldSize = CharUnits::fromQuantity(WordSizeInBytes);
- else
- fieldSize = CGM.getContext().getTypeSizeInChars(type);
- UpdateRunSkipBlockVars(ci->isByRef(), getBlockCaptureLifetime(type),
- fieldOffset, fieldSize);
- }
-
- if (RunSkipBlockVars.empty())
- return nullPtr;
-
// Sort on byte position; captures might not be allocated in order,
// and unions can do funny things.
llvm::array_pod_sort(RunSkipBlockVars.begin(), RunSkipBlockVars.end());
SmallVector<unsigned char, 16> Layout;
-
+
unsigned size = RunSkipBlockVars.size();
for (unsigned i = 0; i < size; i++) {
enum BLOCK_LAYOUT_OPCODE opcode = RunSkipBlockVars[i].opcode;
@@ -2320,11 +2340,11 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
break;
}
CharUnits size_in_bytes =
- end_byte_pos - start_byte_pos + RunSkipBlockVars[j-1].block_var_size;
+ end_byte_pos - start_byte_pos + RunSkipBlockVars[j-1].block_var_size;
if (j < size) {
CharUnits gap =
- RunSkipBlockVars[j].block_var_bytepos -
- RunSkipBlockVars[j-1].block_var_bytepos - RunSkipBlockVars[j-1].block_var_size;
+ RunSkipBlockVars[j].block_var_bytepos -
+ RunSkipBlockVars[j-1].block_var_bytepos - RunSkipBlockVars[j-1].block_var_size;
size_in_bytes += gap;
}
CharUnits residue_in_bytes = CharUnits::Zero();
@@ -2333,7 +2353,7 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
size_in_bytes -= residue_in_bytes;
opcode = BLOCK_LAYOUT_NON_OBJECT_WORDS;
}
-
+
unsigned size_in_words = size_in_bytes.getQuantity() / WordSizeInBytes;
while (size_in_words >= 16) {
// Note that value in imm. is one less that the actual
@@ -2350,7 +2370,7 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
}
if (residue_in_bytes > CharUnits::Zero()) {
unsigned char inst =
- (BLOCK_LAYOUT_NON_OBJECT_BYTES << 4) | (residue_in_bytes.getQuantity()-1);
+ (BLOCK_LAYOUT_NON_OBJECT_BYTES << 4) | (residue_in_bytes.getQuantity()-1);
Layout.push_back(inst);
}
}
@@ -2369,7 +2389,10 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
if (Result != 0) {
// Block variable layout instruction has been inlined.
if (CGM.getLangOpts().ObjCGCBitmapPrint) {
- printf("\n Inline instruction for block variable layout: ");
+ if (ComputeByrefLayout)
+ printf("\n Inline instruction for BYREF variable layout: ");
+ else
+ printf("\n Inline instruction for block variable layout: ");
printf("0x0%llx\n", (unsigned long long)Result);
}
if (WordSizeInBytes == 8) {
@@ -2389,7 +2412,10 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
BitMap += Layout[i];
if (CGM.getLangOpts().ObjCGCBitmapPrint) {
- printf("\n block variable layout: ");
+ if (ComputeByrefLayout)
+ printf("\n BYREF variable layout: ");
+ else
+ printf("\n block variable layout: ");
for (unsigned i = 0, e = BitMap.size(); i != e; i++) {
unsigned char inst = BitMap[i];
enum BLOCK_LAYOUT_OPCODE opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
@@ -2417,10 +2443,10 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
case BLOCK_LAYOUT_UNRETAINED:
printf("BL_UNRETAINED:");
break;
- }
+ }
// Actual value of word count is one more that what is in the imm.
// field of the instruction
- printf("%d", (inst & 0xf) + delta);
+ printf("%d", (inst & 0xf) + delta);
if (i < e-1)
printf(", ");
else
@@ -2429,13 +2455,84 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
}
llvm::GlobalVariable * Entry =
- CreateMetadataVar("\01L_OBJC_CLASS_NAME_",
+ CreateMetadataVar("\01L_OBJC_CLASS_NAME_",
llvm::ConstantDataArray::getString(VMContext, BitMap,false),
"__TEXT,__objc_classname,cstring_literals", 1, true);
return getConstantGEP(VMContext, Entry, 0, 0);
}
-llvm::Value *CGObjCMac::GenerateProtocolRef(CGBuilderTy &Builder,
+llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
+ const CGBlockInfo &blockInfo) {
+ assert(CGM.getLangOpts().getGC() == LangOptions::NonGC);
+
+ RunSkipBlockVars.clear();
+ bool hasUnion = false;
+
+ unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0);
+ unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth();
+ unsigned WordSizeInBytes = WordSizeInBits/ByteSizeInBits;
+
+ const BlockDecl *blockDecl = blockInfo.getBlockDecl();
+
+ // Calculate the basic layout of the block structure.
+ const llvm::StructLayout *layout =
+ CGM.getDataLayout().getStructLayout(blockInfo.StructureType);
+
+ // Ignore the optional 'this' capture: C++ objects are not assumed
+ // to be GC'ed.
+ if (blockInfo.BlockHeaderForcedGapSize != CharUnits::Zero())
+ UpdateRunSkipBlockVars(false, Qualifiers::OCL_None,
+ blockInfo.BlockHeaderForcedGapOffset,
+ blockInfo.BlockHeaderForcedGapSize);
+ // Walk the captured variables.
+ for (BlockDecl::capture_const_iterator ci = blockDecl->capture_begin(),
+ ce = blockDecl->capture_end(); ci != ce; ++ci) {
+ const VarDecl *variable = ci->getVariable();
+ QualType type = variable->getType();
+
+ const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable);
+
+ // Ignore constant captures.
+ if (capture.isConstant()) continue;
+
+ CharUnits fieldOffset =
+ CharUnits::fromQuantity(layout->getElementOffset(capture.getIndex()));
+
+ assert(!type->isArrayType() && "array variable should not be caught");
+ if (!ci->isByRef())
+ if (const RecordType *record = type->getAs<RecordType>()) {
+ BuildRCBlockVarRecordLayout(record, fieldOffset, hasUnion);
+ continue;
+ }
+ CharUnits fieldSize;
+ if (ci->isByRef())
+ fieldSize = CharUnits::fromQuantity(WordSizeInBytes);
+ else
+ fieldSize = CGM.getContext().getTypeSizeInChars(type);
+ UpdateRunSkipBlockVars(ci->isByRef(), getBlockCaptureLifetime(type, false),
+ fieldOffset, fieldSize);
+ }
+ return getBitmapBlockLayout(false);
+}
+
+
+llvm::Constant *CGObjCCommonMac::BuildByrefLayout(CodeGen::CodeGenModule &CGM,
+ QualType T) {
+ assert(CGM.getLangOpts().getGC() == LangOptions::NonGC);
+ assert(!T->isArrayType() && "__block array variable should not be caught");
+ CharUnits fieldOffset;
+ RunSkipBlockVars.clear();
+ bool hasUnion = false;
+ if (const RecordType *record = T->getAs<RecordType>()) {
+ BuildRCBlockVarRecordLayout(record, fieldOffset, hasUnion, true /*ByrefLayout */);
+ llvm::Constant *Result = getBitmapBlockLayout(true);
+ return Result;
+ }
+ llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy);
+ return nullPtr;
+}
+
+llvm::Value *CGObjCMac::GenerateProtocolRef(CodeGenFunction &CGF,
const ObjCProtocolDecl *PD) {
// FIXME: I don't understand why gcc generates this, or where it is
// resolved. Investigate. Its also wasteful to look this up over and over.
@@ -2644,7 +2741,7 @@ llvm::Constant *
CGObjCMac::EmitProtocolList(Twine Name,
ObjCProtocolDecl::protocol_iterator begin,
ObjCProtocolDecl::protocol_iterator end) {
- llvm::SmallVector<llvm::Constant*, 16> ProtocolRefs;
+ SmallVector<llvm::Constant *, 16> ProtocolRefs;
for (; begin != end; ++begin)
ProtocolRefs.push_back(GetProtocolRef(*begin));
@@ -2675,7 +2772,7 @@ CGObjCMac::EmitProtocolList(Twine Name,
void CGObjCCommonMac::
PushProtocolProperties(llvm::SmallPtrSet<const IdentifierInfo*,16> &PropertySet,
- llvm::SmallVectorImpl<llvm::Constant*> &Properties,
+ SmallVectorImpl<llvm::Constant *> &Properties,
const Decl *Container,
const ObjCProtocolDecl *PROTO,
const ObjCCommonTypesHelper &ObjCTypes) {
@@ -2711,7 +2808,7 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name,
const Decl *Container,
const ObjCContainerDecl *OCD,
const ObjCCommonTypesHelper &ObjCTypes) {
- llvm::SmallVector<llvm::Constant*, 16> Properties;
+ SmallVector<llvm::Constant *, 16> Properties;
llvm::SmallPtrSet<const IdentifierInfo*, 16> PropertySet;
for (ObjCContainerDecl::prop_iterator I = OCD->prop_begin(),
E = OCD->prop_end(); I != E; ++I) {
@@ -2846,7 +2943,7 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
llvm::raw_svector_ostream(ExtName) << Interface->getName() << '_'
<< OCD->getName();
- llvm::SmallVector<llvm::Constant*, 16> InstanceMethods, ClassMethods;
+ SmallVector<llvm::Constant *, 16> InstanceMethods, ClassMethods;
for (ObjCCategoryImplDecl::instmeth_iterator
i = OCD->instmeth_begin(), e = OCD->instmeth_end(); i != e; ++i) {
// Instance methods should always be defined.
@@ -2974,7 +3071,7 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
if (ID->getClassInterface()->getVisibility() == HiddenVisibility)
Flags |= FragileABI_Class_Hidden;
- llvm::SmallVector<llvm::Constant*, 16> InstanceMethods, ClassMethods;
+ SmallVector<llvm::Constant *, 16> InstanceMethods, ClassMethods;
for (ObjCImplementationDecl::instmeth_iterator
i = ID->instmeth_begin(), e = ID->instmeth_end(); i != e; ++i) {
// Instance methods should always be defined.
@@ -3368,7 +3465,10 @@ llvm::Constant *CGObjCMac::GetSetStructFunction() {
return ObjCTypes.getCopyStructFn();
}
-llvm::Constant *CGObjCMac::GetCppAtomicObjectFunction() {
+llvm::Constant *CGObjCMac::GetCppAtomicObjectGetFunction() {
+ return ObjCTypes.getCppAtomicObjectFunction();
+}
+llvm::Constant *CGObjCMac::GetCppAtomicObjectSetFunction() {
return ObjCTypes.getCppAtomicObjectFunction();
}
@@ -3411,14 +3511,17 @@ namespace {
FinallyCallExit, FinallyNoCallExit);
CGF.EmitBlock(FinallyCallExit);
- CGF.Builder.CreateCall(ObjCTypes.getExceptionTryExitFn(), ExceptionData)
- ->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionTryExitFn(),
+ ExceptionData);
CGF.EmitBlock(FinallyNoCallExit);
if (isa<ObjCAtTryStmt>(S)) {
if (const ObjCAtFinallyStmt* FinallyStmt =
cast<ObjCAtTryStmt>(S).getFinallyStmt()) {
+ // Don't try to do the @finally if this is an EH cleanup.
+ if (flags.isForEHCleanup()) return;
+
// Save the current cleanup destination in case there's
// control flow inside the finally statement.
llvm::Value *CurCleanupDest =
@@ -3438,8 +3541,7 @@ namespace {
// Emit objc_sync_exit(expr); as finally's sole statement for
// @synchronized.
llvm::Value *SyncArg = CGF.Builder.CreateLoad(SyncArgSlot);
- CGF.Builder.CreateCall(ObjCTypes.getSyncExitFn(), SyncArg)
- ->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getSyncExitFn(), SyncArg);
}
}
};
@@ -3516,12 +3618,14 @@ FragileHazards::FragileHazards(CodeGenFunction &CGF) : CGF(CGF) {
void FragileHazards::emitWriteHazard() {
if (Locals.empty()) return;
- CGF.Builder.CreateCall(WriteHazard, Locals)->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(WriteHazard, Locals);
}
void FragileHazards::emitReadHazard(CGBuilderTy &Builder) {
assert(!Locals.empty());
- Builder.CreateCall(ReadHazard, Locals)->setDoesNotThrow();
+ llvm::CallInst *call = Builder.CreateCall(ReadHazard, Locals);
+ call->setDoesNotThrow();
+ call->setCallingConv(CGF.getRuntimeCC());
}
/// Emit read hazards in all the protected blocks, i.e. all the blocks
@@ -3726,8 +3830,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
llvm::Value *SyncArg =
CGF.EmitScalarExpr(cast<ObjCAtSynchronizedStmt>(S).getSynchExpr());
SyncArg = CGF.Builder.CreateBitCast(SyncArg, ObjCTypes.ObjectPtrTy);
- CGF.Builder.CreateCall(ObjCTypes.getSyncEnterFn(), SyncArg)
- ->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getSyncEnterFn(), SyncArg);
SyncArgSlot = CGF.CreateTempAlloca(SyncArg->getType(), "sync.arg");
CGF.Builder.CreateStore(SyncArg, SyncArgSlot);
@@ -3760,7 +3863,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
llvm::Value *PropagatingExnVar = 0;
// Push a normal cleanup to leave the try scope.
- CGF.EHStack.pushCleanup<PerformFragileFinally>(NormalCleanup, &S,
+ CGF.EHStack.pushCleanup<PerformFragileFinally>(NormalAndEHCleanup, &S,
SyncArgSlot,
CallTryExitVar,
ExceptionData,
@@ -3769,8 +3872,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// Enter a try block:
// - Call objc_exception_try_enter to push ExceptionData on top of
// the EH stack.
- CGF.Builder.CreateCall(ObjCTypes.getExceptionTryEnterFn(), ExceptionData)
- ->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionTryEnterFn(), ExceptionData);
// - Call setjmp on the exception data buffer.
llvm::Constant *Zero = llvm::ConstantInt::get(CGF.Builder.getInt32Ty(), 0);
@@ -3778,8 +3880,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
llvm::Value *SetJmpBuffer =
CGF.Builder.CreateGEP(ExceptionData, GEPIndexes, "setjmp_buffer");
llvm::CallInst *SetJmpResult =
- CGF.Builder.CreateCall(ObjCTypes.getSetJmpFn(), SetJmpBuffer, "setjmp_result");
- SetJmpResult->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getSetJmpFn(), SetJmpBuffer, "setjmp_result");
SetJmpResult->setCanReturnTwice();
// If setjmp returned 0, enter the protected block; otherwise,
@@ -3816,9 +3917,8 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// Retrieve the exception object. We may emit multiple blocks but
// nothing can cross this so the value is already in SSA form.
llvm::CallInst *Caught =
- CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(),
- ExceptionData, "caught");
- Caught->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionExtractFn(),
+ ExceptionData, "caught");
// Push the exception to rethrow onto the EH value stack for the
// benefit of any @throws in the handlers.
@@ -3839,13 +3939,12 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// Enter a new exception try block (in case a @catch block
// throws an exception).
- CGF.Builder.CreateCall(ObjCTypes.getExceptionTryEnterFn(), ExceptionData)
- ->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionTryEnterFn(),
+ ExceptionData);
llvm::CallInst *SetJmpResult =
- CGF.Builder.CreateCall(ObjCTypes.getSetJmpFn(), SetJmpBuffer,
- "setjmp.result");
- SetJmpResult->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getSetJmpFn(),
+ SetJmpBuffer, "setjmp.result");
SetJmpResult->setCanReturnTwice();
llvm::Value *Threw =
@@ -3913,12 +4012,12 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
assert(IDecl && "Catch parameter must have Objective-C type!");
// Check if the @catch block matches the exception object.
- llvm::Value *Class = EmitClassRef(CGF.Builder, IDecl);
+ llvm::Value *Class = EmitClassRef(CGF, IDecl);
+ llvm::Value *matchArgs[] = { Class, Caught };
llvm::CallInst *Match =
- CGF.Builder.CreateCall2(ObjCTypes.getExceptionMatchFn(),
- Class, Caught, "match");
- Match->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionMatchFn(),
+ matchArgs, "match");
llvm::BasicBlock *MatchedBlock = CGF.createBasicBlock("match");
llvm::BasicBlock *NextCatchBlock = CGF.createBasicBlock("catch.next");
@@ -3975,9 +4074,8 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// propagating-exception slot.
assert(PropagatingExnVar);
llvm::CallInst *NewCaught =
- CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(),
- ExceptionData, "caught");
- NewCaught->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionExtractFn(),
+ ExceptionData, "caught");
CGF.Builder.CreateStore(NewCaught, PropagatingExnVar);
// Don't pop the catch handler; the throw already did.
@@ -4008,14 +4106,13 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// Otherwise, just look in the buffer for the exception to throw.
} else {
llvm::CallInst *Caught =
- CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(),
- ExceptionData);
- Caught->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionExtractFn(),
+ ExceptionData);
PropagatingExn = Caught;
}
- CGF.Builder.CreateCall(ObjCTypes.getExceptionThrowFn(), PropagatingExn)
- ->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionThrowFn(),
+ PropagatingExn);
CGF.Builder.CreateUnreachable();
}
@@ -4023,7 +4120,8 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
}
void CGObjCMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
- const ObjCAtThrowStmt &S) {
+ const ObjCAtThrowStmt &S,
+ bool ClearInsertionPoint) {
llvm::Value *ExceptionAsObject;
if (const Expr *ThrowExpr = S.getThrowExpr()) {
@@ -4036,12 +4134,13 @@ void CGObjCMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
ExceptionAsObject = CGF.ObjCEHValueStack.back();
}
- CGF.Builder.CreateCall(ObjCTypes.getExceptionThrowFn(), ExceptionAsObject)
+ CGF.EmitRuntimeCall(ObjCTypes.getExceptionThrowFn(), ExceptionAsObject)
->setDoesNotReturn();
CGF.Builder.CreateUnreachable();
// Clear the insertion point to indicate we are in unreachable code.
- CGF.Builder.ClearInsertionPoint();
+ if (ClearInsertionPoint)
+ CGF.Builder.ClearInsertionPoint();
}
/// EmitObjCWeakRead - Code gen for loading value of a __weak
@@ -4053,8 +4152,9 @@ llvm::Value * CGObjCMac::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
cast<llvm::PointerType>(AddrWeakObj->getType())->getElementType();
AddrWeakObj = CGF.Builder.CreateBitCast(AddrWeakObj,
ObjCTypes.PtrObjectPtrTy);
- llvm::Value *read_weak = CGF.Builder.CreateCall(ObjCTypes.getGcReadWeakFn(),
- AddrWeakObj, "weakread");
+ llvm::Value *read_weak =
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcReadWeakFn(),
+ AddrWeakObj, "weakread");
read_weak = CGF.Builder.CreateBitCast(read_weak, DestTy);
return read_weak;
}
@@ -4074,8 +4174,9 @@ void CGObjCMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- CGF.Builder.CreateCall2(ObjCTypes.getGcAssignWeakFn(),
- src, dst, "weakassign");
+ llvm::Value *args[] = { src, dst };
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignWeakFn(),
+ args, "weakassign");
return;
}
@@ -4095,12 +4196,13 @@ void CGObjCMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
+ llvm::Value *args[] = { src, dst };
if (!threadlocal)
- CGF.Builder.CreateCall2(ObjCTypes.getGcAssignGlobalFn(),
- src, dst, "globalassign");
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignGlobalFn(),
+ args, "globalassign");
else
- CGF.Builder.CreateCall2(ObjCTypes.getGcAssignThreadLocalFn(),
- src, dst, "threadlocalassign");
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignThreadLocalFn(),
+ args, "threadlocalassign");
return;
}
@@ -4121,8 +4223,8 @@ void CGObjCMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- CGF.Builder.CreateCall3(ObjCTypes.getGcAssignIvarFn(),
- src, dst, ivarOffset);
+ llvm::Value *args[] = { src, dst, ivarOffset };
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignIvarFn(), args);
return;
}
@@ -4141,8 +4243,9 @@ void CGObjCMac::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- CGF.Builder.CreateCall2(ObjCTypes.getGcAssignStrongCastFn(),
- src, dst, "weakassign");
+ llvm::Value *args[] = { src, dst };
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignStrongCastFn(),
+ args, "weakassign");
return;
}
@@ -4152,9 +4255,8 @@ void CGObjCMac::EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
llvm::Value *size) {
SrcPtr = CGF.Builder.CreateBitCast(SrcPtr, ObjCTypes.Int8PtrTy);
DestPtr = CGF.Builder.CreateBitCast(DestPtr, ObjCTypes.Int8PtrTy);
- CGF.Builder.CreateCall3(ObjCTypes.GcMemmoveCollectableFn(),
- DestPtr, SrcPtr, size);
- return;
+ llvm::Value *args[] = { DestPtr, SrcPtr, size };
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.GcMemmoveCollectableFn(), args);
}
/// EmitObjCValueForIvar - Code Gen for ivar reference.
@@ -4318,8 +4420,8 @@ llvm::Constant *CGObjCMac::EmitModuleSymbols() {
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.SymtabPtrTy);
}
-llvm::Value *CGObjCMac::EmitClassRefFromId(CGBuilderTy &Builder,
- IdentifierInfo *II) {
+llvm::Value *CGObjCMac::EmitClassRefFromId(CodeGenFunction &CGF,
+ IdentifierInfo *II) {
LazySymbols.insert(II);
llvm::GlobalVariable *&Entry = ClassReferences[II];
@@ -4334,20 +4436,20 @@ llvm::Value *CGObjCMac::EmitClassRefFromId(CGBuilderTy &Builder,
4, true);
}
- return Builder.CreateLoad(Entry);
+ return CGF.Builder.CreateLoad(Entry);
}
-llvm::Value *CGObjCMac::EmitClassRef(CGBuilderTy &Builder,
+llvm::Value *CGObjCMac::EmitClassRef(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID) {
- return EmitClassRefFromId(Builder, ID->getIdentifier());
+ return EmitClassRefFromId(CGF, ID->getIdentifier());
}
-llvm::Value *CGObjCMac::EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder) {
+llvm::Value *CGObjCMac::EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) {
IdentifierInfo *II = &CGM.getContext().Idents.get("NSAutoreleasePool");
- return EmitClassRefFromId(Builder, II);
+ return EmitClassRefFromId(CGF, II);
}
-llvm::Value *CGObjCMac::EmitSelector(CGBuilderTy &Builder, Selector Sel,
+llvm::Value *CGObjCMac::EmitSelector(CodeGenFunction &CGF, Selector Sel,
bool lvalue) {
llvm::GlobalVariable *&Entry = SelectorReferences[Sel];
@@ -4359,11 +4461,12 @@ llvm::Value *CGObjCMac::EmitSelector(CGBuilderTy &Builder, Selector Sel,
CreateMetadataVar("\01L_OBJC_SELECTOR_REFERENCES_", Casted,
"__OBJC,__message_refs,literal_pointers,no_dead_strip",
4, true);
+ Entry->setExternallyInitialized(true);
}
if (lvalue)
return Entry;
- return Builder.CreateLoad(Entry);
+ return CGF.Builder.CreateLoad(Entry);
}
llvm::Constant *CGObjCCommonMac::GetClassName(IdentifierInfo *Ident) {
@@ -5825,7 +5928,7 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
/// It generates a weak reference to l_OBJC_PROTOCOL_REFERENCE_$_Proto1
/// which will hold address of the protocol meta-data.
///
-llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CGBuilderTy &Builder,
+llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CodeGenFunction &CGF,
const ObjCProtocolDecl *PD) {
// This routine is called for @protocol only. So, we must build definition
@@ -5840,7 +5943,7 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CGBuilderTy &Builder,
llvm::GlobalVariable *PTGV = CGM.getModule().getGlobalVariable(ProtocolName);
if (PTGV)
- return Builder.CreateLoad(PTGV);
+ return CGF.Builder.CreateLoad(PTGV);
PTGV = new llvm::GlobalVariable(
CGM.getModule(),
Init->getType(), false,
@@ -5850,7 +5953,7 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CGBuilderTy &Builder,
PTGV->setSection("__DATA, __objc_protorefs, coalesced, no_dead_strip");
PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
CGM.AddUsedGlobal(PTGV);
- return Builder.CreateLoad(PTGV);
+ return CGF.Builder.CreateLoad(PTGV);
}
/// GenerateCategory - Build metadata for a category implementation.
@@ -6288,7 +6391,7 @@ llvm::Constant *
CGObjCNonFragileABIMac::EmitProtocolList(Twine Name,
ObjCProtocolDecl::protocol_iterator begin,
ObjCProtocolDecl::protocol_iterator end) {
- llvm::SmallVector<llvm::Constant*, 16> ProtocolRefs;
+ SmallVector<llvm::Constant *, 16> ProtocolRefs;
// Just return null for empty protocol lists
if (begin == end)
@@ -6365,10 +6468,12 @@ LValue CGObjCNonFragileABIMac::EmitObjCValueForIvar(
unsigned CVRQualifiers) {
ObjCInterfaceDecl *ID = ObjectTy->getAs<ObjCObjectType>()->getInterface();
llvm::Value *Offset = EmitIvarOffset(CGF, ID, Ivar);
- if (llvm::LoadInst *LI = dyn_cast<llvm::LoadInst>(Offset))
- LI->setMetadata(CGM.getModule().getMDKindID("invariant.load"),
- llvm::MDNode::get(VMContext,
- ArrayRef<llvm::Value*>()));
+
+ if (IsIvarOffsetKnownIdempotent(CGF, ID, Ivar))
+ if (llvm::LoadInst *LI = cast<llvm::LoadInst>(Offset))
+ LI->setMetadata(CGM.getModule().getMDKindID("invariant.load"),
+ llvm::MDNode::get(VMContext, ArrayRef<llvm::Value*>()));
+
return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers,
Offset);
}
@@ -6530,7 +6635,7 @@ CGObjCNonFragileABIMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
Receiver, CGF.getContext().getObjCIdType(),
false, CallArgs, Method)
: EmitMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF.Builder, Sel),
+ EmitSelector(CGF, Sel),
Receiver, CGF.getContext().getObjCIdType(),
false, CallArgs, Method, ObjCTypes);
}
@@ -6548,7 +6653,7 @@ CGObjCNonFragileABIMac::GetClassGlobal(const std::string &Name) {
return GV;
}
-llvm::Value *CGObjCNonFragileABIMac::EmitClassRefFromId(CGBuilderTy &Builder,
+llvm::Value *CGObjCNonFragileABIMac::EmitClassRefFromId(CodeGenFunction &CGF,
IdentifierInfo *II) {
llvm::GlobalVariable *&Entry = ClassReferences[II];
@@ -6567,22 +6672,22 @@ llvm::Value *CGObjCNonFragileABIMac::EmitClassRefFromId(CGBuilderTy &Builder,
CGM.AddUsedGlobal(Entry);
}
- return Builder.CreateLoad(Entry);
+ return CGF.Builder.CreateLoad(Entry);
}
-llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CGBuilderTy &Builder,
+llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID) {
- return EmitClassRefFromId(Builder, ID->getIdentifier());
+ return EmitClassRefFromId(CGF, ID->getIdentifier());
}
llvm::Value *CGObjCNonFragileABIMac::EmitNSAutoreleasePoolClassRef(
- CGBuilderTy &Builder) {
+ CodeGenFunction &CGF) {
IdentifierInfo *II = &CGM.getContext().Idents.get("NSAutoreleasePool");
- return EmitClassRefFromId(Builder, II);
+ return EmitClassRefFromId(CGF, II);
}
llvm::Value *
-CGObjCNonFragileABIMac::EmitSuperClassRef(CGBuilderTy &Builder,
+CGObjCNonFragileABIMac::EmitSuperClassRef(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID) {
llvm::GlobalVariable *&Entry = SuperClassReferences[ID->getIdentifier()];
@@ -6601,17 +6706,17 @@ CGObjCNonFragileABIMac::EmitSuperClassRef(CGBuilderTy &Builder,
CGM.AddUsedGlobal(Entry);
}
- return Builder.CreateLoad(Entry);
+ return CGF.Builder.CreateLoad(Entry);
}
/// EmitMetaClassRef - Return a Value * of the address of _class_t
/// meta-data
///
-llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder,
+llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID) {
llvm::GlobalVariable * &Entry = MetaClassReferences[ID->getIdentifier()];
if (Entry)
- return Builder.CreateLoad(Entry);
+ return CGF.Builder.CreateLoad(Entry);
std::string MetaClassName(getMetaclassSymbolPrefix() + ID->getNameAsString());
llvm::GlobalVariable *MetaClassGV = GetClassGlobal(MetaClassName);
@@ -6627,12 +6732,12 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder,
Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
CGM.AddUsedGlobal(Entry);
- return Builder.CreateLoad(Entry);
+ return CGF.Builder.CreateLoad(Entry);
}
/// GetClass - Return a reference to the class for the given interface
/// decl.
-llvm::Value *CGObjCNonFragileABIMac::GetClass(CGBuilderTy &Builder,
+llvm::Value *CGObjCNonFragileABIMac::GetClass(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID) {
if (ID->isWeakImported()) {
std::string ClassName(getClassSymbolPrefix() + ID->getNameAsString());
@@ -6640,7 +6745,7 @@ llvm::Value *CGObjCNonFragileABIMac::GetClass(CGBuilderTy &Builder,
ClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
}
- return EmitClassRef(Builder, ID);
+ return EmitClassRef(CGF, ID);
}
/// Generates a message send where the super is the receiver. This is
@@ -6671,9 +6776,9 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
// If this is a class message the metaclass is passed as the target.
llvm::Value *Target;
if (IsClassMessage)
- Target = EmitMetaClassRef(CGF.Builder, Class);
+ Target = EmitMetaClassRef(CGF, Class);
else
- Target = EmitSuperClassRef(CGF.Builder, Class);
+ Target = EmitSuperClassRef(CGF, Class);
// FIXME: We shouldn't need to do this cast, rectify the ASTContext and
// ObjCTypes types.
@@ -6688,12 +6793,12 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
ObjCSuper, ObjCTypes.SuperPtrCTy,
true, CallArgs, Method)
: EmitMessageSend(CGF, Return, ResultType,
- EmitSelector(CGF.Builder, Sel),
+ EmitSelector(CGF, Sel),
ObjCSuper, ObjCTypes.SuperPtrCTy,
true, CallArgs, Method, ObjCTypes);
}
-llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CGBuilderTy &Builder,
+llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CodeGenFunction &CGF,
Selector Sel, bool lval) {
llvm::GlobalVariable *&Entry = SelectorReferences[Sel];
@@ -6705,13 +6810,14 @@ llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CGBuilderTy &Builder,
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.SelectorPtrTy, false,
llvm::GlobalValue::InternalLinkage,
Casted, "\01L_OBJC_SELECTOR_REFERENCES_");
+ Entry->setExternallyInitialized(true);
Entry->setSection("__DATA, __objc_selrefs, literal_pointers, no_dead_strip");
CGM.AddUsedGlobal(Entry);
}
if (lval)
return Entry;
- llvm::LoadInst* LI = Builder.CreateLoad(Entry);
+ llvm::LoadInst* LI = CGF.Builder.CreateLoad(Entry);
LI->setMetadata(CGM.getModule().getMDKindID("invariant.load"),
llvm::MDNode::get(VMContext,
@@ -6735,9 +6841,8 @@ void CGObjCNonFragileABIMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- CGF.Builder.CreateCall3(ObjCTypes.getGcAssignIvarFn(),
- src, dst, ivarOffset);
- return;
+ llvm::Value *args[] = { src, dst, ivarOffset };
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignIvarFn(), args);
}
/// EmitObjCStrongCastAssign - Code gen for assigning to a __strong cast object.
@@ -6756,9 +6861,9 @@ void CGObjCNonFragileABIMac::EmitObjCStrongCastAssign(
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- CGF.Builder.CreateCall2(ObjCTypes.getGcAssignStrongCastFn(),
- src, dst, "weakassign");
- return;
+ llvm::Value *args[] = { src, dst };
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignStrongCastFn(),
+ args, "weakassign");
}
void CGObjCNonFragileABIMac::EmitGCMemmoveCollectable(
@@ -6768,9 +6873,8 @@ void CGObjCNonFragileABIMac::EmitGCMemmoveCollectable(
llvm::Value *Size) {
SrcPtr = CGF.Builder.CreateBitCast(SrcPtr, ObjCTypes.Int8PtrTy);
DestPtr = CGF.Builder.CreateBitCast(DestPtr, ObjCTypes.Int8PtrTy);
- CGF.Builder.CreateCall3(ObjCTypes.GcMemmoveCollectableFn(),
- DestPtr, SrcPtr, Size);
- return;
+ llvm::Value *args[] = { DestPtr, SrcPtr, Size };
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.GcMemmoveCollectableFn(), args);
}
/// EmitObjCWeakRead - Code gen for loading value of a __weak
@@ -6782,8 +6886,9 @@ llvm::Value * CGObjCNonFragileABIMac::EmitObjCWeakRead(
llvm::Type* DestTy =
cast<llvm::PointerType>(AddrWeakObj->getType())->getElementType();
AddrWeakObj = CGF.Builder.CreateBitCast(AddrWeakObj, ObjCTypes.PtrObjectPtrTy);
- llvm::Value *read_weak = CGF.Builder.CreateCall(ObjCTypes.getGcReadWeakFn(),
- AddrWeakObj, "weakread");
+ llvm::Value *read_weak =
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcReadWeakFn(),
+ AddrWeakObj, "weakread");
read_weak = CGF.Builder.CreateBitCast(read_weak, DestTy);
return read_weak;
}
@@ -6803,9 +6908,9 @@ void CGObjCNonFragileABIMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- CGF.Builder.CreateCall2(ObjCTypes.getGcAssignWeakFn(),
- src, dst, "weakassign");
- return;
+ llvm::Value *args[] = { src, dst };
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignWeakFn(),
+ args, "weakassign");
}
/// EmitObjCGlobalAssign - Code gen for assigning to a __strong object.
@@ -6824,13 +6929,13 @@ void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
+ llvm::Value *args[] = { src, dst };
if (!threadlocal)
- CGF.Builder.CreateCall2(ObjCTypes.getGcAssignGlobalFn(),
- src, dst, "globalassign");
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignGlobalFn(),
+ args, "globalassign");
else
- CGF.Builder.CreateCall2(ObjCTypes.getGcAssignThreadLocalFn(),
- src, dst, "threadlocalassign");
- return;
+ CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignThreadLocalFn(),
+ args, "threadlocalassign");
}
void
@@ -6876,19 +6981,21 @@ void CGObjCNonFragileABIMac::EmitTryStmt(CodeGen::CodeGenFunction &CGF,
/// EmitThrowStmt - Generate code for a throw statement.
void CGObjCNonFragileABIMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
- const ObjCAtThrowStmt &S) {
+ const ObjCAtThrowStmt &S,
+ bool ClearInsertionPoint) {
if (const Expr *ThrowExpr = S.getThrowExpr()) {
llvm::Value *Exception = CGF.EmitObjCThrowOperand(ThrowExpr);
Exception = CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy);
- CGF.EmitCallOrInvoke(ObjCTypes.getExceptionThrowFn(), Exception)
+ CGF.EmitRuntimeCallOrInvoke(ObjCTypes.getExceptionThrowFn(), Exception)
.setDoesNotReturn();
} else {
- CGF.EmitCallOrInvoke(ObjCTypes.getExceptionRethrowFn())
+ CGF.EmitRuntimeCallOrInvoke(ObjCTypes.getExceptionRethrowFn())
.setDoesNotReturn();
}
CGF.Builder.CreateUnreachable();
- CGF.Builder.ClearInsertionPoint();
+ if (ClearInsertionPoint)
+ CGF.Builder.ClearInsertionPoint();
}
llvm::Constant *
@@ -6946,7 +7053,7 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID,
ID->getIdentifier()->getName()));
}
- if (CGM.getLangOpts().getVisibilityMode() == HiddenVisibility)
+ if (ID->getVisibility() == HiddenVisibility)
Entry->setVisibility(llvm::GlobalValue::HiddenVisibility);
Entry->setAlignment(CGM.getDataLayout().getABITypeAlignment(
ObjCTypes.EHTypeTy));
diff --git a/lib/CodeGen/CGObjCRuntime.cpp b/lib/CodeGen/CGObjCRuntime.cpp
index 6932dd7..abd10a2 100644
--- a/lib/CodeGen/CGObjCRuntime.cpp
+++ b/lib/CodeGen/CGObjCRuntime.cpp
@@ -14,15 +14,12 @@
//===----------------------------------------------------------------------===//
#include "CGObjCRuntime.h"
-
+#include "CGCleanup.h"
#include "CGRecordLayout.h"
-#include "CodeGenModule.h"
#include "CodeGenFunction.h"
-#include "CGCleanup.h"
-
+#include "CodeGenModule.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtObjC.h"
-
#include "llvm/Support/CallSite.h"
using namespace clang;
@@ -92,14 +89,13 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
unsigned CVRQualifiers,
llvm::Value *Offset) {
// Compute (type*) ( (char *) BaseValue + Offset)
- llvm::Type *I8Ptr = CGF.Int8PtrTy;
QualType IvarTy = Ivar->getType();
llvm::Type *LTy = CGF.CGM.getTypes().ConvertTypeForMem(IvarTy);
- llvm::Value *V = CGF.Builder.CreateBitCast(BaseValue, I8Ptr);
+ llvm::Value *V = CGF.Builder.CreateBitCast(BaseValue, CGF.Int8PtrTy);
V = CGF.Builder.CreateInBoundsGEP(V, Offset, "add.ptr");
- V = CGF.Builder.CreateBitCast(V, llvm::PointerType::getUnqual(LTy));
if (!Ivar->isBitField()) {
+ V = CGF.Builder.CreateBitCast(V, llvm::PointerType::getUnqual(LTy));
LValue LV = CGF.MakeNaturalAlignAddrLValue(V, IvarTy);
LV.getQuals().addCVRQualifiers(CVRQualifiers);
return LV;
@@ -119,16 +115,14 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
// Note, there is a subtle invariant here: we can only call this routine on
// non-synthesized ivars but we may be called for synthesized ivars. However,
// a synthesized ivar can never be a bit-field, so this is safe.
- const ASTRecordLayout &RL =
- CGF.CGM.getContext().getASTObjCInterfaceLayout(OID);
- uint64_t TypeSizeInBits = CGF.CGM.getContext().toBits(RL.getSize());
uint64_t FieldBitOffset = LookupFieldBitOffset(CGF.CGM, OID, 0, Ivar);
uint64_t BitOffset = FieldBitOffset % CGF.CGM.getContext().getCharWidth();
- uint64_t ContainingTypeAlign = CGF.CGM.getContext().getTargetInfo().getCharAlign();
- uint64_t ContainingTypeSize = TypeSizeInBits - (FieldBitOffset - BitOffset);
+ uint64_t AlignmentBits = CGF.CGM.getContext().getTargetInfo().getCharAlign();
uint64_t BitFieldSize = Ivar->getBitWidthValue(CGF.getContext());
- CharUnits ContainingTypeAlignCharUnits =
- CGF.CGM.getContext().toCharUnitsFromBits(ContainingTypeAlign);
+ CharUnits StorageSize =
+ CGF.CGM.getContext().toCharUnitsFromBits(
+ llvm::RoundUpToAlignment(BitOffset + BitFieldSize, AlignmentBits));
+ CharUnits Alignment = CGF.CGM.getContext().toCharUnitsFromBits(AlignmentBits);
// Allocate a new CGBitFieldInfo object to describe this access.
//
@@ -138,11 +132,15 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
// objects.
CGBitFieldInfo *Info = new (CGF.CGM.getContext()) CGBitFieldInfo(
CGBitFieldInfo::MakeInfo(CGF.CGM.getTypes(), Ivar, BitOffset, BitFieldSize,
- ContainingTypeSize, ContainingTypeAlign));
+ CGF.CGM.getContext().toBits(StorageSize),
+ Alignment.getQuantity()));
+ V = CGF.Builder.CreateBitCast(V,
+ llvm::Type::getIntNPtrTy(CGF.getLLVMContext(),
+ Info->StorageSize));
return LValue::MakeBitfield(V, *Info,
IvarTy.withCVRQualifiers(CVRQualifiers),
- ContainingTypeAlignCharUnits);
+ Alignment);
}
namespace {
@@ -165,7 +163,7 @@ namespace {
return;
}
- CGF.EmitCallOrInvoke(Fn);
+ CGF.EmitRuntimeCallOrInvoke(Fn);
}
};
}
diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h
index 3e77875..7f030f2 100644
--- a/lib/CodeGen/CGObjCRuntime.h
+++ b/lib/CodeGen/CGObjCRuntime.h
@@ -15,12 +15,11 @@
#ifndef CLANG_CODEGEN_OBCJRUNTIME_H
#define CLANG_CODEGEN_OBCJRUNTIME_H
-#include "clang/Basic/IdentifierTable.h" // Selector
-#include "clang/AST/DeclObjC.h"
-
#include "CGBuilder.h"
#include "CGCall.h"
#include "CGValue.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/IdentifierTable.h" // Selector
namespace llvm {
class Constant;
@@ -120,11 +119,11 @@ public:
/// Get a selector for the specified name and type values. The
/// return value should have the LLVM type for pointer-to
/// ASTContext::getObjCSelType().
- virtual llvm::Value *GetSelector(CGBuilderTy &Builder,
+ virtual llvm::Value *GetSelector(CodeGenFunction &CGF,
Selector Sel, bool lval=false) = 0;
/// Get a typed selector.
- virtual llvm::Value *GetSelector(CGBuilderTy &Builder,
+ virtual llvm::Value *GetSelector(CodeGenFunction &CGF,
const ObjCMethodDecl *Method) = 0;
/// Get the type constant to catch for the given ObjC pointer type.
@@ -180,7 +179,7 @@ public:
/// Emit the code to return the named protocol as an object, as in a
/// \@protocol expression.
- virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder,
+ virtual llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF,
const ObjCProtocolDecl *OPD) = 0;
/// Generate the named protocol. Protocols contain method metadata but no
@@ -210,17 +209,20 @@ public:
virtual llvm::Constant *GetGetStructFunction() = 0;
// API for atomic copying of qualified aggregates in setter.
virtual llvm::Constant *GetSetStructFunction() = 0;
- // API for atomic copying of qualified aggregates with non-trivial copy
- // assignment (c++) in setter/getter.
- virtual llvm::Constant *GetCppAtomicObjectFunction() = 0;
+ /// API for atomic copying of qualified aggregates with non-trivial copy
+ /// assignment (c++) in setter.
+ virtual llvm::Constant *GetCppAtomicObjectSetFunction() = 0;
+ /// API for atomic copying of qualified aggregates with non-trivial copy
+ /// assignment (c++) in getter.
+ virtual llvm::Constant *GetCppAtomicObjectGetFunction() = 0;
/// GetClass - Return a reference to the class for the given
/// interface decl.
- virtual llvm::Value *GetClass(CGBuilderTy &Builder,
+ virtual llvm::Value *GetClass(CodeGenFunction &CGF,
const ObjCInterfaceDecl *OID) = 0;
- virtual llvm::Value *EmitNSAutoreleasePoolClassRef(CGBuilderTy &Builder) {
+ virtual llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) {
llvm_unreachable("autoreleasepool unsupported in this ABI");
}
@@ -233,7 +235,8 @@ public:
virtual void EmitTryStmt(CodeGen::CodeGenFunction &CGF,
const ObjCAtTryStmt &S) = 0;
virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
- const ObjCAtThrowStmt &S) = 0;
+ const ObjCAtThrowStmt &S,
+ bool ClearInsertionPoint=true) = 0;
virtual llvm::Value *EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
llvm::Value *AddrWeakObj) = 0;
virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
@@ -263,6 +266,8 @@ public:
const CodeGen::CGBlockInfo &blockInfo) = 0;
virtual llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM,
const CodeGen::CGBlockInfo &blockInfo) = 0;
+ virtual llvm::Constant *BuildByrefLayout(CodeGen::CodeGenModule &CGM,
+ QualType T) = 0;
virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) = 0;
struct MessageSendInfo {
diff --git a/lib/CodeGen/CGOpenCLRuntime.cpp b/lib/CodeGen/CGOpenCLRuntime.cpp
index 3a0e116..7c454ac 100644
--- a/lib/CodeGen/CGOpenCLRuntime.cpp
+++ b/lib/CodeGen/CGOpenCLRuntime.cpp
@@ -15,7 +15,9 @@
#include "CGOpenCLRuntime.h"
#include "CodeGenFunction.h"
-#include "llvm/GlobalValue.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/GlobalValue.h"
+#include <assert.h>
using namespace clang;
using namespace CodeGen;
@@ -26,3 +28,37 @@ void CGOpenCLRuntime::EmitWorkGroupLocalVarDecl(CodeGenFunction &CGF,
const VarDecl &D) {
return CGF.EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
}
+
+llvm::Type *CGOpenCLRuntime::convertOpenCLSpecificType(const Type *T) {
+ assert(T->isOpenCLSpecificType() &&
+ "Not an OpenCL specific type!");
+
+ switch (cast<BuiltinType>(T)->getKind()) {
+ default:
+ llvm_unreachable("Unexpected opencl builtin type!");
+ return 0;
+ case BuiltinType::OCLImage1d:
+ return llvm::PointerType::get(llvm::StructType::create(
+ CGM.getLLVMContext(), "opencl.image1d_t"), 0);
+ case BuiltinType::OCLImage1dArray:
+ return llvm::PointerType::get(llvm::StructType::create(
+ CGM.getLLVMContext(), "opencl.image1d_array_t"), 0);
+ case BuiltinType::OCLImage1dBuffer:
+ return llvm::PointerType::get(llvm::StructType::create(
+ CGM.getLLVMContext(), "opencl.image1d_buffer_t"), 0);
+ case BuiltinType::OCLImage2d:
+ return llvm::PointerType::get(llvm::StructType::create(
+ CGM.getLLVMContext(), "opencl.image2d_t"), 0);
+ case BuiltinType::OCLImage2dArray:
+ return llvm::PointerType::get(llvm::StructType::create(
+ CGM.getLLVMContext(), "opencl.image2d_array_t"), 0);
+ case BuiltinType::OCLImage3d:
+ return llvm::PointerType::get(llvm::StructType::create(
+ CGM.getLLVMContext(), "opencl.image3d_t"), 0);
+ case BuiltinType::OCLSampler:
+ return llvm::IntegerType::get(CGM.getLLVMContext(),32);
+ case BuiltinType::OCLEvent:
+ return llvm::PointerType::get(llvm::StructType::create(
+ CGM.getLLVMContext(), "opencl.event_t"), 0);
+ }
+}
diff --git a/lib/CodeGen/CGOpenCLRuntime.h b/lib/CodeGen/CGOpenCLRuntime.h
index 9a8430f..7b675c3 100644
--- a/lib/CodeGen/CGOpenCLRuntime.h
+++ b/lib/CodeGen/CGOpenCLRuntime.h
@@ -16,6 +16,10 @@
#ifndef CLANG_CODEGEN_OPENCLRUNTIME_H
#define CLANG_CODEGEN_OPENCLRUNTIME_H
+#include "clang/AST/Type.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/Value.h"
+
namespace clang {
class VarDecl;
@@ -38,6 +42,8 @@ public:
/// CodeGenFunction::EmitStaticVarDecl to emit an internal global for D.
virtual void EmitWorkGroupLocalVarDecl(CodeGenFunction &CGF,
const VarDecl &D);
+
+ virtual llvm::Type *convertOpenCLSpecificType(const Type *T);
};
}
diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp
index 7c83d39..869843c 100644
--- a/lib/CodeGen/CGRTTI.cpp
+++ b/lib/CodeGen/CGRTTI.cpp
@@ -13,10 +13,10 @@
#include "CodeGenModule.h"
#include "CGCXXABI.h"
+#include "CGObjCRuntime.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/Type.h"
#include "clang/Frontend/CodeGenOptions.h"
-#include "CGObjCRuntime.h"
using namespace clang;
using namespace CodeGen;
@@ -191,6 +191,14 @@ static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) {
case BuiltinType::Char32:
case BuiltinType::Int128:
case BuiltinType::UInt128:
+ case BuiltinType::OCLImage1d:
+ case BuiltinType::OCLImage1dArray:
+ case BuiltinType::OCLImage1dBuffer:
+ case BuiltinType::OCLImage2d:
+ case BuiltinType::OCLImage2dArray:
+ case BuiltinType::OCLImage3d:
+ case BuiltinType::OCLSampler:
+ case BuiltinType::OCLEvent:
return true;
case BuiltinType::Dependent:
@@ -244,10 +252,12 @@ static bool IsStandardLibraryRTTIDescriptor(QualType Ty) {
/// the given type exists somewhere else, and that we should not emit the type
/// information in this translation unit. Assumes that it is not a
/// standard-library type.
-static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM, QualType Ty) {
+static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM,
+ QualType Ty) {
ASTContext &Context = CGM.getContext();
- // If RTTI is disabled, don't consider key functions.
+ // If RTTI is disabled, assume it might be disabled in the
+ // translation unit that defines any potential key function, too.
if (!Context.getLangOpts().RTTI) return false;
if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
@@ -258,7 +268,9 @@ static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM, QualType Ty) {
if (!RD->isDynamicClass())
return false;
- return !CGM.getVTables().ShouldEmitVTableInThisTU(RD);
+ // FIXME: this may need to be reconsidered if the key function
+ // changes.
+ return CGM.getVTables().isVTableExternal(RD);
}
return false;
diff --git a/lib/CodeGen/CGRecordLayout.h b/lib/CodeGen/CGRecordLayout.h
index 3db5e04..b29fc98 100644
--- a/lib/CodeGen/CGRecordLayout.h
+++ b/lib/CodeGen/CGRecordLayout.h
@@ -14,7 +14,7 @@
#include "clang/AST/Decl.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/DerivedTypes.h"
+#include "llvm/IR/DerivedTypes.h"
namespace llvm {
class StructType;
@@ -23,122 +23,71 @@ namespace llvm {
namespace clang {
namespace CodeGen {
-/// \brief Helper object for describing how to generate the code for access to a
-/// bit-field.
+/// \brief Structure with information about how a bitfield should be accessed.
///
-/// This structure is intended to describe the "policy" of how the bit-field
-/// should be accessed, which may be target, language, or ABI dependent.
-class CGBitFieldInfo {
-public:
- /// Descriptor for a single component of a bit-field access. The entire
- /// bit-field is constituted of a bitwise OR of all of the individual
- /// components.
- ///
- /// Each component describes an accessed value, which is how the component
- /// should be transferred to/from memory, and a target placement, which is how
- /// that component fits into the constituted bit-field. The pseudo-IR for a
- /// load is:
- ///
- /// %0 = gep %base, 0, FieldIndex
- /// %1 = gep (i8*) %0, FieldByteOffset
- /// %2 = (i(AccessWidth) *) %1
- /// %3 = load %2, align AccessAlignment
- /// %4 = shr %3, FieldBitStart
- ///
- /// and the composed bit-field is formed as the boolean OR of all accesses,
- /// masked to TargetBitWidth bits and shifted to TargetBitOffset.
- struct AccessInfo {
- /// Offset of the field to load in the LLVM structure, if any.
- unsigned FieldIndex;
-
- /// Byte offset from the field address, if any. This should generally be
- /// unused as the cleanest IR comes from having a well-constructed LLVM type
- /// with proper GEP instructions, but sometimes its use is required, for
- /// example if an access is intended to straddle an LLVM field boundary.
- CharUnits FieldByteOffset;
-
- /// Bit offset in the accessed value to use. The width is implied by \see
- /// TargetBitWidth.
- unsigned FieldBitStart;
-
- /// Bit width of the memory access to perform.
- unsigned AccessWidth;
-
- /// The alignment of the memory access, assuming the parent is aligned.
- CharUnits AccessAlignment;
-
- /// Offset for the target value.
- unsigned TargetBitOffset;
-
- /// Number of bits in the access that are destined for the bit-field.
- unsigned TargetBitWidth;
- };
-
-private:
- /// The components to use to access the bit-field. We may need up to three
- /// separate components to support up to i64 bit-field access (4 + 2 + 1 byte
- /// accesses).
- //
- // FIXME: De-hardcode this, just allocate following the struct.
- AccessInfo Components[3];
+/// Often we layout a sequence of bitfields as a contiguous sequence of bits.
+/// When the AST record layout does this, we represent it in the LLVM IR's type
+/// as either a sequence of i8 members or a byte array to reserve the number of
+/// bytes touched without forcing any particular alignment beyond the basic
+/// character alignment.
+///
+/// Then accessing a particular bitfield involves converting this byte array
+/// into a single integer of that size (i24 or i40 -- may not be power-of-two
+/// size), loading it, and shifting and masking to extract the particular
+/// subsequence of bits which make up that particular bitfield. This structure
+/// encodes the information used to construct the extraction code sequences.
+/// The CGRecordLayout also has a field index which encodes which byte-sequence
+/// this bitfield falls within. Let's assume the following C struct:
+///
+/// struct S {
+/// char a, b, c;
+/// unsigned bits : 3;
+/// unsigned more_bits : 4;
+/// unsigned still_more_bits : 7;
+/// };
+///
+/// This will end up as the following LLVM type. The first array is the
+/// bitfield, and the second is the padding out to a 4-byte alignmnet.
+///
+/// %t = type { i8, i8, i8, i8, i8, [3 x i8] }
+///
+/// When generating code to access more_bits, we'll generate something
+/// essentially like this:
+///
+/// define i32 @foo(%t* %base) {
+/// %0 = gep %t* %base, i32 0, i32 3
+/// %2 = load i8* %1
+/// %3 = lshr i8 %2, 3
+/// %4 = and i8 %3, 15
+/// %5 = zext i8 %4 to i32
+/// ret i32 %i
+/// }
+///
+struct CGBitFieldInfo {
+ /// The offset within a contiguous run of bitfields that are represented as
+ /// a single "field" within the LLVM struct type. This offset is in bits.
+ unsigned Offset : 16;
/// The total size of the bit-field, in bits.
- unsigned Size;
-
- /// The number of access components to use.
- unsigned NumComponents;
+ unsigned Size : 15;
/// Whether the bit-field is signed.
- bool IsSigned : 1;
+ unsigned IsSigned : 1;
-public:
- CGBitFieldInfo(unsigned Size, unsigned NumComponents, AccessInfo *_Components,
- bool IsSigned) : Size(Size), NumComponents(NumComponents),
- IsSigned(IsSigned) {
- assert(NumComponents <= 3 && "invalid number of components!");
- for (unsigned i = 0; i != NumComponents; ++i)
- Components[i] = _Components[i];
-
- // Check some invariants.
- unsigned AccessedSize = 0;
- for (unsigned i = 0, e = getNumComponents(); i != e; ++i) {
- const AccessInfo &AI = getComponent(i);
- AccessedSize += AI.TargetBitWidth;
-
- // We shouldn't try to load 0 bits.
- assert(AI.TargetBitWidth > 0);
-
- // We can't load more bits than we accessed.
- assert(AI.FieldBitStart + AI.TargetBitWidth <= AI.AccessWidth);
-
- // We shouldn't put any bits outside the result size.
- assert(AI.TargetBitWidth + AI.TargetBitOffset <= Size);
- }
-
- // Check that the total number of target bits matches the total bit-field
- // size.
- assert(AccessedSize == Size && "Total size does not match accessed size!");
- }
-
-public:
- /// \brief Check whether this bit-field access is (i.e., should be sign
- /// extended on loads).
- bool isSigned() const { return IsSigned; }
-
- /// \brief Get the size of the bit-field, in bits.
- unsigned getSize() const { return Size; }
+ /// The storage size in bits which should be used when accessing this
+ /// bitfield.
+ unsigned StorageSize;
- /// @name Component Access
- /// @{
+ /// The alignment which should be used when accessing the bitfield.
+ unsigned StorageAlignment;
- unsigned getNumComponents() const { return NumComponents; }
+ CGBitFieldInfo()
+ : Offset(), Size(), IsSigned(), StorageSize(), StorageAlignment() {}
- const AccessInfo &getComponent(unsigned Index) const {
- assert(Index < getNumComponents() && "Invalid access!");
- return Components[Index];
- }
-
- /// @}
+ CGBitFieldInfo(unsigned Offset, unsigned Size, bool IsSigned,
+ unsigned StorageSize, unsigned StorageAlignment)
+ : Offset(Offset), Size(Size), IsSigned(IsSigned),
+ StorageSize(StorageSize), StorageAlignment(StorageAlignment) {}
void print(raw_ostream &OS) const;
void dump() const;
@@ -146,17 +95,11 @@ public:
/// \brief Given a bit-field decl, build an appropriate helper object for
/// accessing that field (which is expected to have the given offset and
/// size).
- static CGBitFieldInfo MakeInfo(class CodeGenTypes &Types, const FieldDecl *FD,
- uint64_t FieldOffset, uint64_t FieldSize);
-
- /// \brief Given a bit-field decl, build an appropriate helper object for
- /// accessing that field (which is expected to have the given offset and
- /// size). The field decl should be known to be contained within a type of at
- /// least the given size and with the given alignment.
- static CGBitFieldInfo MakeInfo(CodeGenTypes &Types, const FieldDecl *FD,
- uint64_t FieldOffset, uint64_t FieldSize,
- uint64_t ContainingTypeSizeInBits,
- unsigned ContainingTypeAlign);
+ static CGBitFieldInfo MakeInfo(class CodeGenTypes &Types,
+ const FieldDecl *FD,
+ uint64_t Offset, uint64_t Size,
+ uint64_t StorageSize,
+ uint64_t StorageAlignment);
};
/// CGRecordLayout - This class handles struct and union layout info while
@@ -240,7 +183,6 @@ public:
/// \brief Return llvm::StructType element number that corresponds to the
/// field FD.
unsigned getLLVMFieldNo(const FieldDecl *FD) const {
- assert(!FD->isBitField() && "Invalid call for bit-field decl!");
assert(FieldInfo.count(FD) && "Invalid field for record!");
return FieldInfo.lookup(FD);
}
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index 26ef3ef..2c6438b 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -12,6 +12,8 @@
//===----------------------------------------------------------------------===//
#include "CGRecordLayout.h"
+#include "CGCXXABI.h"
+#include "CodeGenTypes.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/CXXInheritance.h"
@@ -19,13 +21,11 @@
#include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Frontend/CodeGenOptions.h"
-#include "CodeGenTypes.h"
-#include "CGCXXABI.h"
-#include "llvm/DerivedTypes.h"
-#include "llvm/Type.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Type.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/DataLayout.h"
using namespace clang;
using namespace CodeGen;
@@ -100,10 +100,6 @@ private:
/// Alignment - Contains the alignment of the RecordDecl.
CharUnits Alignment;
- /// BitsAvailableInLastField - If a bit field spans only part of a LLVM field,
- /// this will have the number of bits still available in the field.
- char BitsAvailableInLastField;
-
/// NextFieldOffset - Holds the next field offset.
CharUnits NextFieldOffset;
@@ -115,6 +111,12 @@ private:
/// LayoutUnion - Will layout a union RecordDecl.
void LayoutUnion(const RecordDecl *D);
+ /// Lay out a sequence of contiguous bitfields.
+ bool LayoutBitfields(const ASTRecordLayout &Layout,
+ unsigned &FirstFieldNo,
+ RecordDecl::field_iterator &FI,
+ RecordDecl::field_iterator FE);
+
/// LayoutField - try to layout all fields in the record decl.
/// Returns false if the operation failed because the struct is not packed.
bool LayoutFields(const RecordDecl *D);
@@ -194,7 +196,7 @@ public:
: BaseSubobjectType(0),
IsZeroInitializable(true), IsZeroInitializableAsBase(true),
Packed(false), IsMsStruct(false),
- Types(Types), BitsAvailableInLastField(0) { }
+ Types(Types) { }
/// Layout - Will layout a RecordDecl.
void Layout(const RecordDecl *D);
@@ -230,13 +232,10 @@ void CGRecordLayoutBuilder::Layout(const RecordDecl *D) {
}
CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
- const FieldDecl *FD,
- uint64_t FieldOffset,
- uint64_t FieldSize,
- uint64_t ContainingTypeSizeInBits,
- unsigned ContainingTypeAlign) {
- assert(ContainingTypeAlign && "Expected alignment to be specified");
-
+ const FieldDecl *FD,
+ uint64_t Offset, uint64_t Size,
+ uint64_t StorageSize,
+ uint64_t StorageAlignment) {
llvm::Type *Ty = Types.ConvertTypeForMem(FD->getType());
CharUnits TypeSizeInBytes =
CharUnits::fromQuantity(Types.getDataLayout().getTypeAllocSize(Ty));
@@ -244,7 +243,7 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
bool IsSigned = FD->getType()->isSignedIntegerOrEnumerationType();
- if (FieldSize > TypeSizeInBits) {
+ if (Size > TypeSizeInBits) {
// We have a wide bit-field. The extra bits are only used for padding, so
// if we have a bitfield of type T, with size N:
//
@@ -254,173 +253,131 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
//
// T t : sizeof(T);
//
- FieldSize = TypeSizeInBits;
+ Size = TypeSizeInBits;
}
- // in big-endian machines the first fields are in higher bit positions,
- // so revert the offset. The byte offsets are reversed(back) later.
+ // Reverse the bit offsets for big endian machines. Because we represent
+ // a bitfield as a single large integer load, we can imagine the bits
+ // counting from the most-significant-bit instead of the
+ // least-significant-bit.
if (Types.getDataLayout().isBigEndian()) {
- FieldOffset = ((ContainingTypeSizeInBits)-FieldOffset-FieldSize);
- }
-
- // Compute the access components. The policy we use is to start by attempting
- // to access using the width of the bit-field type itself and to always access
- // at aligned indices of that type. If such an access would fail because it
- // extends past the bound of the type, then we reduce size to the next smaller
- // power of two and retry. The current algorithm assumes pow2 sized types,
- // although this is easy to fix.
- //
- assert(llvm::isPowerOf2_32(TypeSizeInBits) && "Unexpected type size!");
- CGBitFieldInfo::AccessInfo Components[3];
- unsigned NumComponents = 0;
- unsigned AccessedTargetBits = 0; // The number of target bits accessed.
- unsigned AccessWidth = TypeSizeInBits; // The current access width to attempt.
-
- // If requested, widen the initial bit-field access to be register sized. The
- // theory is that this is most likely to allow multiple accesses into the same
- // structure to be coalesced, and that the backend should be smart enough to
- // narrow the store if no coalescing is ever done.
- //
- // The subsequent code will handle align these access to common boundaries and
- // guaranteeing that we do not access past the end of the structure.
- if (Types.getCodeGenOpts().UseRegisterSizedBitfieldAccess) {
- if (AccessWidth < Types.getTarget().getRegisterWidth())
- AccessWidth = Types.getTarget().getRegisterWidth();
+ Offset = StorageSize - (Offset + Size);
}
- // Round down from the field offset to find the first access position that is
- // at an aligned offset of the initial access type.
- uint64_t AccessStart = FieldOffset - (FieldOffset % AccessWidth);
-
- // Adjust initial access size to fit within record.
- while (AccessWidth > Types.getTarget().getCharWidth() &&
- AccessStart + AccessWidth > ContainingTypeSizeInBits) {
- AccessWidth >>= 1;
- AccessStart = FieldOffset - (FieldOffset % AccessWidth);
- }
-
- while (AccessedTargetBits < FieldSize) {
- // Check that we can access using a type of this size, without reading off
- // the end of the structure. This can occur with packed structures and
- // -fno-bitfield-type-align, for example.
- if (AccessStart + AccessWidth > ContainingTypeSizeInBits) {
- // If so, reduce access size to the next smaller power-of-two and retry.
- AccessWidth >>= 1;
- assert(AccessWidth >= Types.getTarget().getCharWidth()
- && "Cannot access under byte size!");
- continue;
- }
-
- // Otherwise, add an access component.
-
- // First, compute the bits inside this access which are part of the
- // target. We are reading bits [AccessStart, AccessStart + AccessWidth); the
- // intersection with [FieldOffset, FieldOffset + FieldSize) gives the bits
- // in the target that we are reading.
- assert(FieldOffset < AccessStart + AccessWidth && "Invalid access start!");
- assert(AccessStart < FieldOffset + FieldSize && "Invalid access start!");
- uint64_t AccessBitsInFieldStart = std::max(AccessStart, FieldOffset);
- uint64_t AccessBitsInFieldSize =
- std::min(AccessWidth + AccessStart,
- FieldOffset + FieldSize) - AccessBitsInFieldStart;
-
- assert(NumComponents < 3 && "Unexpected number of components!");
- CGBitFieldInfo::AccessInfo &AI = Components[NumComponents++];
- AI.FieldIndex = 0;
- // FIXME: We still follow the old access pattern of only using the field
- // byte offset. We should switch this once we fix the struct layout to be
- // pretty.
-
- // on big-endian machines we reverted the bit offset because first fields are
- // in higher bits. But this also reverts the bytes, so fix this here by reverting
- // the byte offset on big-endian machines.
- if (Types.getDataLayout().isBigEndian()) {
- AI.FieldByteOffset = Types.getContext().toCharUnitsFromBits(
- ContainingTypeSizeInBits - AccessStart - AccessWidth);
- } else {
- AI.FieldByteOffset = Types.getContext().toCharUnitsFromBits(AccessStart);
- }
- AI.FieldBitStart = AccessBitsInFieldStart - AccessStart;
- AI.AccessWidth = AccessWidth;
- AI.AccessAlignment = Types.getContext().toCharUnitsFromBits(
- llvm::MinAlign(ContainingTypeAlign, AccessStart));
- AI.TargetBitOffset = AccessedTargetBits;
- AI.TargetBitWidth = AccessBitsInFieldSize;
-
- AccessStart += AccessWidth;
- AccessedTargetBits += AI.TargetBitWidth;
- }
-
- assert(AccessedTargetBits == FieldSize && "Invalid bit-field access!");
- return CGBitFieldInfo(FieldSize, NumComponents, Components, IsSigned);
+ return CGBitFieldInfo(Offset, Size, IsSigned, StorageSize, StorageAlignment);
}
-CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types,
- const FieldDecl *FD,
- uint64_t FieldOffset,
- uint64_t FieldSize) {
- const RecordDecl *RD = FD->getParent();
- const ASTRecordLayout &RL = Types.getContext().getASTRecordLayout(RD);
- uint64_t ContainingTypeSizeInBits = Types.getContext().toBits(RL.getSize());
- unsigned ContainingTypeAlign = Types.getContext().toBits(RL.getAlignment());
-
- return MakeInfo(Types, FD, FieldOffset, FieldSize, ContainingTypeSizeInBits,
- ContainingTypeAlign);
-}
-
-void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D,
- uint64_t fieldOffset) {
- uint64_t fieldSize = D->getBitWidthValue(Types.getContext());
-
- if (fieldSize == 0)
- return;
-
- uint64_t nextFieldOffsetInBits = Types.getContext().toBits(NextFieldOffset);
- CharUnits numBytesToAppend;
- unsigned charAlign = Types.getContext().getTargetInfo().getCharAlign();
-
- if (fieldOffset < nextFieldOffsetInBits && !BitsAvailableInLastField) {
- assert(fieldOffset % charAlign == 0 &&
- "Field offset not aligned correctly");
-
- CharUnits fieldOffsetInCharUnits =
- Types.getContext().toCharUnitsFromBits(fieldOffset);
+/// \brief Layout the range of bitfields from BFI to BFE as contiguous storage.
+bool CGRecordLayoutBuilder::LayoutBitfields(const ASTRecordLayout &Layout,
+ unsigned &FirstFieldNo,
+ RecordDecl::field_iterator &FI,
+ RecordDecl::field_iterator FE) {
+ assert(FI != FE);
+ uint64_t FirstFieldOffset = Layout.getFieldOffset(FirstFieldNo);
+ uint64_t NextFieldOffsetInBits = Types.getContext().toBits(NextFieldOffset);
+
+ unsigned CharAlign = Types.getContext().getTargetInfo().getCharAlign();
+ assert(FirstFieldOffset % CharAlign == 0 &&
+ "First field offset is misaligned");
+ CharUnits FirstFieldOffsetInBytes
+ = Types.getContext().toCharUnitsFromBits(FirstFieldOffset);
+
+ unsigned StorageAlignment
+ = llvm::MinAlign(Alignment.getQuantity(),
+ FirstFieldOffsetInBytes.getQuantity());
+
+ if (FirstFieldOffset < NextFieldOffsetInBits) {
+ CharUnits FieldOffsetInCharUnits =
+ Types.getContext().toCharUnitsFromBits(FirstFieldOffset);
// Try to resize the last base field.
- if (ResizeLastBaseFieldIfNecessary(fieldOffsetInCharUnits))
- nextFieldOffsetInBits = Types.getContext().toBits(NextFieldOffset);
- }
-
- if (fieldOffset < nextFieldOffsetInBits) {
- assert(BitsAvailableInLastField && "Bitfield size mismatch!");
- assert(!NextFieldOffset.isZero() && "Must have laid out at least one byte");
-
- // The bitfield begins in the previous bit-field.
- numBytesToAppend = Types.getContext().toCharUnitsFromBits(
- llvm::RoundUpToAlignment(fieldSize - BitsAvailableInLastField,
- charAlign));
- } else {
- assert(fieldOffset % charAlign == 0 &&
- "Field offset not aligned correctly");
-
- // Append padding if necessary.
- AppendPadding(Types.getContext().toCharUnitsFromBits(fieldOffset),
- CharUnits::One());
+ if (!ResizeLastBaseFieldIfNecessary(FieldOffsetInCharUnits))
+ llvm_unreachable("We must be able to resize the last base if we need to "
+ "pack bits into it.");
- numBytesToAppend = Types.getContext().toCharUnitsFromBits(
- llvm::RoundUpToAlignment(fieldSize, charAlign));
-
- assert(!numBytesToAppend.isZero() && "No bytes to append!");
+ NextFieldOffsetInBits = Types.getContext().toBits(NextFieldOffset);
+ assert(FirstFieldOffset >= NextFieldOffsetInBits);
}
- // Add the bit field info.
- BitFields.insert(std::make_pair(D,
- CGBitFieldInfo::MakeInfo(Types, D, fieldOffset, fieldSize)));
-
- AppendBytes(numBytesToAppend);
+ // Append padding if necessary.
+ AppendPadding(Types.getContext().toCharUnitsFromBits(FirstFieldOffset),
+ CharUnits::One());
+
+ // Find the last bitfield in a contiguous run of bitfields.
+ RecordDecl::field_iterator BFI = FI;
+ unsigned LastFieldNo = FirstFieldNo;
+ uint64_t NextContiguousFieldOffset = FirstFieldOffset;
+ for (RecordDecl::field_iterator FJ = FI;
+ (FJ != FE && (*FJ)->isBitField() &&
+ NextContiguousFieldOffset == Layout.getFieldOffset(LastFieldNo) &&
+ (*FJ)->getBitWidthValue(Types.getContext()) != 0); FI = FJ++) {
+ NextContiguousFieldOffset += (*FJ)->getBitWidthValue(Types.getContext());
+ ++LastFieldNo;
+
+ // We must use packed structs for packed fields, and also unnamed bit
+ // fields since they don't affect the struct alignment.
+ if (!Packed && ((*FJ)->hasAttr<PackedAttr>() || !(*FJ)->getDeclName()))
+ return false;
+ }
+ RecordDecl::field_iterator BFE = llvm::next(FI);
+ --LastFieldNo;
+ assert(LastFieldNo >= FirstFieldNo && "Empty run of contiguous bitfields");
+ FieldDecl *LastFD = *FI;
+
+ // Find the last bitfield's offset, add its size, and round it up to the
+ // character alignment to compute the storage required.
+ uint64_t LastFieldOffset = Layout.getFieldOffset(LastFieldNo);
+ uint64_t LastFieldSize = LastFD->getBitWidthValue(Types.getContext());
+ uint64_t TotalBits = (LastFieldOffset + LastFieldSize) - FirstFieldOffset;
+ CharUnits StorageBytes = Types.getContext().toCharUnitsFromBits(
+ llvm::RoundUpToAlignment(TotalBits, CharAlign));
+ uint64_t StorageBits = Types.getContext().toBits(StorageBytes);
+
+ // Grow the storage to encompass any known padding in the layout when doing
+ // so will make the storage a power-of-two. There are two cases when we can
+ // do this. The first is when we have a subsequent field and can widen up to
+ // its offset. The second is when the data size of the AST record layout is
+ // past the end of the current storage. The latter is true when there is tail
+ // padding on a struct and no members of a super class can be packed into it.
+ //
+ // Note that we widen the storage as much as possible here to express the
+ // maximum latitude the language provides, and rely on the backend to lower
+ // these in conjunction with shifts and masks to narrower operations where
+ // beneficial.
+ uint64_t EndOffset = Types.getContext().toBits(Layout.getDataSize());
+ if (BFE != FE)
+ // If there are more fields to be laid out, the offset at the end of the
+ // bitfield is the offset of the next field in the record.
+ EndOffset = Layout.getFieldOffset(LastFieldNo + 1);
+ assert(EndOffset >= (FirstFieldOffset + TotalBits) &&
+ "End offset is not past the end of the known storage bits.");
+ uint64_t SpaceBits = EndOffset - FirstFieldOffset;
+ uint64_t LongBits = Types.getContext().getTargetInfo().getLongWidth();
+ uint64_t WidenedBits = (StorageBits / LongBits) * LongBits +
+ llvm::NextPowerOf2(StorageBits % LongBits - 1);
+ assert(WidenedBits >= StorageBits && "Widening shrunk the bits!");
+ if (WidenedBits <= SpaceBits) {
+ StorageBits = WidenedBits;
+ StorageBytes = Types.getContext().toCharUnitsFromBits(StorageBits);
+ assert(StorageBits == (uint64_t)Types.getContext().toBits(StorageBytes));
+ }
- BitsAvailableInLastField =
- Types.getContext().toBits(NextFieldOffset) - (fieldOffset + fieldSize);
+ unsigned FieldIndex = FieldTypes.size();
+ AppendBytes(StorageBytes);
+
+ // Now walk the bitfields associating them with this field of storage and
+ // building up the bitfield specific info.
+ unsigned FieldNo = FirstFieldNo;
+ for (; BFI != BFE; ++BFI, ++FieldNo) {
+ FieldDecl *FD = *BFI;
+ uint64_t FieldOffset = Layout.getFieldOffset(FieldNo) - FirstFieldOffset;
+ uint64_t FieldSize = FD->getBitWidthValue(Types.getContext());
+ Fields[FD] = FieldIndex;
+ BitFields[FD] = CGBitFieldInfo::MakeInfo(Types, FD, FieldOffset, FieldSize,
+ StorageBits, StorageAlignment);
+ }
+ FirstFieldNo = LastFieldNo;
+ return true;
}
bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D,
@@ -429,15 +386,7 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D,
if (!Packed && D->hasAttr<PackedAttr>())
return false;
- if (D->isBitField()) {
- // We must use packed structs for unnamed bit fields since they
- // don't affect the struct alignment.
- if (!Packed && !D->getDeclName())
- return false;
-
- LayoutBitField(D, fieldOffset);
- return true;
- }
+ assert(!D->isBitField() && "Bitfields should be laid out seperately.");
CheckZeroInitializable(D->getType());
@@ -497,6 +446,7 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D,
llvm::Type *
CGRecordLayoutBuilder::LayoutUnionField(const FieldDecl *Field,
const ASTRecordLayout &Layout) {
+ Fields[Field] = 0;
if (Field->isBitField()) {
uint64_t FieldSize = Field->getBitWidthValue(Types.getContext());
@@ -504,22 +454,23 @@ CGRecordLayoutBuilder::LayoutUnionField(const FieldDecl *Field,
if (FieldSize == 0)
return 0;
- llvm::Type *FieldTy = llvm::Type::getInt8Ty(Types.getLLVMContext());
- CharUnits NumBytesToAppend = Types.getContext().toCharUnitsFromBits(
- llvm::RoundUpToAlignment(FieldSize,
- Types.getContext().getTargetInfo().getCharAlign()));
+ unsigned StorageBits = llvm::RoundUpToAlignment(
+ FieldSize, Types.getContext().getTargetInfo().getCharAlign());
+ CharUnits NumBytesToAppend
+ = Types.getContext().toCharUnitsFromBits(StorageBits);
+ llvm::Type *FieldTy = llvm::Type::getInt8Ty(Types.getLLVMContext());
if (NumBytesToAppend > CharUnits::One())
FieldTy = llvm::ArrayType::get(FieldTy, NumBytesToAppend.getQuantity());
// Add the bit field info.
- BitFields.insert(std::make_pair(Field,
- CGBitFieldInfo::MakeInfo(Types, Field, 0, FieldSize)));
+ BitFields[Field] = CGBitFieldInfo::MakeInfo(Types, Field, 0, FieldSize,
+ StorageBits,
+ Alignment.getQuantity());
return FieldTy;
}
// This is a regular union field.
- Fields[Field] = 0;
return Types.ConvertTypeForMem(Field->getType());
}
@@ -815,20 +766,38 @@ bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
unsigned FieldNo = 0;
const FieldDecl *LastFD = 0;
- for (RecordDecl::field_iterator Field = D->field_begin(),
- FieldEnd = D->field_end(); Field != FieldEnd; ++Field, ++FieldNo) {
+ for (RecordDecl::field_iterator FI = D->field_begin(), FE = D->field_end();
+ FI != FE; ++FI, ++FieldNo) {
+ FieldDecl *FD = *FI;
if (IsMsStruct) {
// Zero-length bitfields following non-bitfield members are
// ignored:
- const FieldDecl *FD = *Field;
if (Types.getContext().ZeroBitfieldFollowsNonBitfield(FD, LastFD)) {
--FieldNo;
continue;
}
LastFD = FD;
}
-
- if (!LayoutField(*Field, Layout.getFieldOffset(FieldNo))) {
+
+ // If this field is a bitfield, layout all of the consecutive
+ // non-zero-length bitfields and the last zero-length bitfield; these will
+ // all share storage.
+ if (FD->isBitField()) {
+ // If all we have is a zero-width bitfield, skip it.
+ if (FD->getBitWidthValue(Types.getContext()) == 0)
+ continue;
+
+ // Layout this range of bitfields.
+ if (!LayoutBitfields(Layout, FieldNo, FI, FE)) {
+ assert(!Packed &&
+ "Could not layout bitfields even with a packed LLVM struct!");
+ return false;
+ }
+ assert(FI != FE && "Advanced past the last bitfield");
+ continue;
+ }
+
+ if (!LayoutField(FD, Layout.getFieldOffset(FieldNo))) {
assert(!Packed &&
"Could not layout fields even with a packed LLVM struct!");
return false;
@@ -845,7 +814,7 @@ bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
// Lay out the virtual bases. The MS ABI uses a different
// algorithm here due to the lack of primary virtual bases.
- if (Types.getContext().getTargetInfo().getCXXABI() != CXXABI_Microsoft) {
+ if (Types.getContext().getTargetInfo().getCXXABI().hasPrimaryVBases()) {
RD->getIndirectPrimaryBases(IndirectPrimaryBases);
if (Layout.isPrimaryBaseVirtual())
IndirectPrimaryBases.insert(Layout.getPrimaryBase());
@@ -889,7 +858,6 @@ void CGRecordLayoutBuilder::AppendField(CharUnits fieldOffset,
FieldTypes.push_back(fieldType);
NextFieldOffset = fieldOffset + fieldSize;
- BitsAvailableInLastField = 0;
}
void CGRecordLayoutBuilder::AppendPadding(CharUnits fieldOffset,
@@ -1090,18 +1058,39 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D,
LastFD = FD;
continue;
}
-
+
+ // Don't inspect zero-length bitfields.
+ if (FD->getBitWidthValue(getContext()) == 0)
+ continue;
+
const CGBitFieldInfo &Info = RL->getBitFieldInfo(FD);
- for (unsigned i = 0, e = Info.getNumComponents(); i != e; ++i) {
- const CGBitFieldInfo::AccessInfo &AI = Info.getComponent(i);
-
- // Verify that every component access is within the structure.
- uint64_t FieldOffset = SL->getElementOffsetInBits(AI.FieldIndex);
- uint64_t AccessBitOffset = FieldOffset +
- getContext().toBits(AI.FieldByteOffset);
- assert(AccessBitOffset + AI.AccessWidth <= TypeSizeInBits &&
- "Invalid bit-field access (out of range)!");
+ llvm::Type *ElementTy = ST->getTypeAtIndex(RL->getLLVMFieldNo(FD));
+
+ // Unions have overlapping elements dictating their layout, but for
+ // non-unions we can verify that this section of the layout is the exact
+ // expected size.
+ if (D->isUnion()) {
+ // For unions we verify that the start is zero and the size
+ // is in-bounds. However, on BE systems, the offset may be non-zero, but
+ // the size + offset should match the storage size in that case as it
+ // "starts" at the back.
+ if (getDataLayout().isBigEndian())
+ assert(static_cast<unsigned>(Info.Offset + Info.Size) ==
+ Info.StorageSize &&
+ "Big endian union bitfield does not end at the back");
+ else
+ assert(Info.Offset == 0 &&
+ "Little endian union bitfield with a non-zero offset");
+ assert(Info.StorageSize <= SL->getSizeInBits() &&
+ "Union not large enough for bitfield storage");
+ } else {
+ assert(Info.StorageSize ==
+ getDataLayout().getTypeAllocSizeInBits(ElementTy) &&
+ "Storage size does not match the element type size");
}
+ assert(Info.Size > 0 && "Empty bitfield!");
+ assert(static_cast<unsigned>(Info.Offset) + Info.Size <= Info.StorageSize &&
+ "Bitfield outside of its allocated storage");
}
#endif
@@ -1143,32 +1132,12 @@ void CGRecordLayout::dump() const {
}
void CGBitFieldInfo::print(raw_ostream &OS) const {
- OS << "<CGBitFieldInfo";
- OS << " Size:" << Size;
- OS << " IsSigned:" << IsSigned << "\n";
-
- OS.indent(4 + strlen("<CGBitFieldInfo"));
- OS << " NumComponents:" << getNumComponents();
- OS << " Components: [";
- if (getNumComponents()) {
- OS << "\n";
- for (unsigned i = 0, e = getNumComponents(); i != e; ++i) {
- const AccessInfo &AI = getComponent(i);
- OS.indent(8);
- OS << "<AccessInfo"
- << " FieldIndex:" << AI.FieldIndex
- << " FieldByteOffset:" << AI.FieldByteOffset.getQuantity()
- << " FieldBitStart:" << AI.FieldBitStart
- << " AccessWidth:" << AI.AccessWidth << "\n";
- OS.indent(8 + strlen("<AccessInfo"));
- OS << " AccessAlignment:" << AI.AccessAlignment.getQuantity()
- << " TargetBitOffset:" << AI.TargetBitOffset
- << " TargetBitWidth:" << AI.TargetBitWidth
- << ">\n";
- }
- OS.indent(4);
- }
- OS << "]>";
+ OS << "<CGBitFieldInfo"
+ << " Offset:" << Offset
+ << " Size:" << Size
+ << " IsSigned:" << IsSigned
+ << " StorageSize:" << StorageSize
+ << " StorageAlignment:" << StorageAlignment << ">";
}
void CGBitFieldInfo::dump() const {
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index 3548dba..3153ca8 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -11,17 +11,17 @@
//
//===----------------------------------------------------------------------===//
+#include "CodeGenFunction.h"
#include "CGDebugInfo.h"
#include "CodeGenModule.h"
-#include "CodeGenFunction.h"
#include "TargetInfo.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/InlineAsm.h"
-#include "llvm/Intrinsics.h"
-#include "llvm/DataLayout.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/InlineAsm.h"
+#include "llvm/IR/Intrinsics.h"
using namespace clang;
using namespace CodeGen;
@@ -198,6 +198,12 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
// Keep track of the current cleanup stack depth, including debug scopes.
LexicalScope Scope(*this, S.getSourceRange());
+ return EmitCompoundStmtWithoutScope(S, GetLast, AggSlot);
+}
+
+RValue CodeGenFunction::EmitCompoundStmtWithoutScope(const CompoundStmt &S, bool GetLast,
+ AggValueSlot AggSlot) {
+
for (CompoundStmt::const_body_iterator I = S.body_begin(),
E = S.body_end()-GetLast; I != E; ++I)
EmitStmt(*I);
@@ -313,6 +319,12 @@ CodeGenFunction::getJumpDestForLabel(const LabelDecl *D) {
}
void CodeGenFunction::EmitLabel(const LabelDecl *D) {
+ // Add this label to the current lexical scope if we're within any
+ // normal cleanups. Jumps "in" to this label --- when permitted by
+ // the language --- may need to be routed around such cleanups.
+ if (EHStack.hasNormalCleanups() && CurLexicalScope)
+ CurLexicalScope->addLabel(D);
+
JumpDest &Dest = LabelMap[D];
// If we didn't need a forward reference to this label, just go
@@ -324,16 +336,36 @@ void CodeGenFunction::EmitLabel(const LabelDecl *D) {
// it from the branch-fixups list.
} else {
assert(!Dest.getScopeDepth().isValid() && "already emitted label!");
- Dest = JumpDest(Dest.getBlock(),
- EHStack.stable_begin(),
- Dest.getDestIndex());
-
+ Dest.setScopeDepth(EHStack.stable_begin());
ResolveBranchFixups(Dest.getBlock());
}
EmitBlock(Dest.getBlock());
}
+/// Change the cleanup scope of the labels in this lexical scope to
+/// match the scope of the enclosing context.
+void CodeGenFunction::LexicalScope::rescopeLabels() {
+ assert(!Labels.empty());
+ EHScopeStack::stable_iterator innermostScope
+ = CGF.EHStack.getInnermostNormalCleanup();
+
+ // Change the scope depth of all the labels.
+ for (SmallVectorImpl<const LabelDecl*>::const_iterator
+ i = Labels.begin(), e = Labels.end(); i != e; ++i) {
+ assert(CGF.LabelMap.count(*i));
+ JumpDest &dest = CGF.LabelMap.find(*i)->second;
+ assert(dest.getScopeDepth().isValid());
+ assert(innermostScope.encloses(dest.getScopeDepth()));
+ dest.setScopeDepth(innermostScope);
+ }
+
+ // Reparent the labels if the new scope also has cleanups.
+ if (innermostScope != EHScopeStack::stable_end() && ParentScope) {
+ ParentScope->Labels.append(Labels.begin(), Labels.end());
+ }
+}
+
void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) {
EmitLabel(S.getDecl());
@@ -735,7 +767,9 @@ void CodeGenFunction::EmitReturnOfRValue(RValue RV, QualType Ty) {
} else if (RV.isAggregate()) {
EmitAggregateCopy(ReturnValue, RV.getAggregateAddr(), Ty);
} else {
- StoreComplexToAddr(RV.getComplexVal(), ReturnValue, false);
+ EmitStoreOfComplex(RV.getComplexVal(),
+ MakeNaturalAlignAddrLValue(ReturnValue, Ty),
+ /*init*/ true);
}
EmitBranchThroughCleanup(ReturnBlock);
}
@@ -760,8 +794,7 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
// FIXME: Clean this up by using an LValue for ReturnTemp,
// EmitStoreThroughLValue, and EmitAnyExpr.
- if (S.getNRVOCandidate() && S.getNRVOCandidate()->isNRVOVariable() &&
- !Target.useGlobalsForAutomaticVariables()) {
+ if (S.getNRVOCandidate() && S.getNRVOCandidate()->isNRVOVariable()) {
// Apply the named return value optimization for this return statement,
// which means doing nothing: the appropriate result has already been
// constructed into the NRVO variable.
@@ -782,16 +815,26 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
// rather than the value.
RValue Result = EmitReferenceBindingToExpr(RV, /*InitializedDecl=*/0);
Builder.CreateStore(Result.getScalarVal(), ReturnValue);
- } else if (!hasAggregateLLVMType(RV->getType())) {
- Builder.CreateStore(EmitScalarExpr(RV), ReturnValue);
- } else if (RV->getType()->isAnyComplexType()) {
- EmitComplexExprIntoAddr(RV, ReturnValue, false);
} else {
- CharUnits Alignment = getContext().getTypeAlignInChars(RV->getType());
- EmitAggExpr(RV, AggValueSlot::forAddr(ReturnValue, Alignment, Qualifiers(),
- AggValueSlot::IsDestructed,
- AggValueSlot::DoesNotNeedGCBarriers,
- AggValueSlot::IsNotAliased));
+ switch (getEvaluationKind(RV->getType())) {
+ case TEK_Scalar:
+ Builder.CreateStore(EmitScalarExpr(RV), ReturnValue);
+ break;
+ case TEK_Complex:
+ EmitComplexExprIntoLValue(RV,
+ MakeNaturalAlignAddrLValue(ReturnValue, RV->getType()),
+ /*isInit*/ true);
+ break;
+ case TEK_Aggregate: {
+ CharUnits Alignment = getContext().getTypeAlignInChars(RV->getType());
+ EmitAggExpr(RV, AggValueSlot::forAddr(ReturnValue, Alignment,
+ Qualifiers(),
+ AggValueSlot::IsDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased));
+ break;
+ }
+ }
}
cleanupScope.ForceCleanup();
@@ -1349,7 +1392,7 @@ CodeGenFunction::EmitAsmInputLValue(const TargetInfo::ConstraintInfo &Info,
std::string &ConstraintStr) {
llvm::Value *Arg;
if (Info.allowsRegister() || !Info.allowsMemory()) {
- if (!CodeGenFunction::hasAggregateLLVMType(InputType)) {
+ if (CodeGenFunction::hasScalarEvaluationKind(InputType)) {
Arg = EmitLoadOfLValue(InputValue).getScalarVal();
} else {
llvm::Type *Ty = ConvertType(InputType);
@@ -1378,7 +1421,7 @@ llvm::Value* CodeGenFunction::EmitAsmInput(
const Expr *InputExpr,
std::string &ConstraintStr) {
if (Info.allowsRegister() || !Info.allowsMemory())
- if (!CodeGenFunction::hasAggregateLLVMType(InputExpr->getType()))
+ if (CodeGenFunction::hasScalarEvaluationKind(InputExpr->getType()))
return EmitScalarExpr(InputExpr);
InputExpr = InputExpr->IgnoreParenNoopCasts(getContext());
@@ -1473,7 +1516,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// If this is a register output, then make the inline asm return it
// by-value. If this is a memory result, return the value by-reference.
- if (!Info.allowsMemory() && !hasAggregateLLVMType(OutExpr->getType())) {
+ if (!Info.allowsMemory() && hasScalarEvaluationKind(OutExpr->getType())) {
Constraints += "=" + OutputConstraint;
ResultRegQualTys.push_back(OutExpr->getType());
ResultRegDests.push_back(Dest);
@@ -1640,9 +1683,8 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
llvm::InlineAsm::get(FTy, AsmString, Constraints, HasSideEffect,
/* IsAlignStack */ false, AsmDialect);
llvm::CallInst *Result = Builder.CreateCall(IA, Args);
- Result->addAttribute(llvm::AttrListPtr::FunctionIndex,
- llvm::Attributes::get(getLLVMContext(),
- llvm::Attributes::NoUnwind));
+ Result->addAttribute(llvm::AttributeSet::FunctionIndex,
+ llvm::Attribute::NoUnwind);
// Slap the source location of the inline asm into a !srcloc metadata on the
// call. FIXME: Handle metadata for MS-style inline asms.
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index 5b37fe4..069cd5f 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -11,9 +11,9 @@
//
//===----------------------------------------------------------------------===//
-#include "CodeGenModule.h"
#include "CodeGenFunction.h"
#include "CGCXXABI.h"
+#include "CodeGenModule.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Frontend/CodeGenOptions.h"
@@ -31,33 +31,6 @@ using namespace CodeGen;
CodeGenVTables::CodeGenVTables(CodeGenModule &CGM)
: CGM(CGM), VTContext(CGM.getContext()) { }
-bool CodeGenVTables::ShouldEmitVTableInThisTU(const CXXRecordDecl *RD) {
- assert(RD->isDynamicClass() && "Non dynamic classes have no VTable.");
-
- TemplateSpecializationKind TSK = RD->getTemplateSpecializationKind();
- if (TSK == TSK_ExplicitInstantiationDeclaration)
- return false;
-
- const CXXMethodDecl *KeyFunction = CGM.getContext().getKeyFunction(RD);
- if (!KeyFunction)
- return true;
-
- // Itanium C++ ABI, 5.2.6 Instantiated Templates:
- // An instantiation of a class template requires:
- // - In the object where instantiated, the virtual table...
- if (TSK == TSK_ImplicitInstantiation ||
- TSK == TSK_ExplicitInstantiationDefinition)
- return true;
-
- // If we're building with optimization, we always emit VTables since that
- // allows for virtual function calls to be devirtualized.
- // (We don't want to do this in -fapple-kext mode however).
- if (CGM.getCodeGenOpts().OptimizationLevel && !CGM.getLangOpts().AppleKext)
- return true;
-
- return KeyFunction->hasBody();
-}
-
llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD,
const ThunkInfo &Thunk) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
@@ -143,7 +116,7 @@ static void setThunkVisibility(CodeGenModule &CGM, const CXXMethodDecl *MD,
Fn->getVisibility() != llvm::GlobalVariable::DefaultVisibility)
return;
- if (MD->getExplicitVisibility())
+ if (MD->getExplicitVisibility(ValueDecl::VisibilityForValue))
return;
switch (MD->getTemplateSpecializationKind()) {
@@ -388,7 +361,7 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn,
ReturnValueSlot Slot;
if (!ResultType->isVoidType() &&
FnInfo.getReturnInfo().getKind() == ABIArgInfo::Indirect &&
- hasAggregateLLVMType(CurFnInfo->getReturnType()))
+ !hasScalarEvaluationKind(CurFnInfo->getReturnType()))
Slot = ReturnValueSlot(ReturnValue, ResultType.isVolatileQualified());
// Now emit our call.
@@ -645,9 +618,8 @@ llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTable(const CXXRecordDecl *RD) {
if (VTable)
return VTable;
- // We may need to generate a definition for this vtable.
- if (ShouldEmitVTableInThisTU(RD))
- CGM.DeferredVTables.push_back(RD);
+ // Queue up this v-table for possible deferred emission.
+ CGM.addDeferredVTable(RD);
SmallString<256> OutName;
llvm::raw_svector_ostream Out(OutName);
@@ -714,6 +686,14 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
llvm::ArrayType *ArrayType =
llvm::ArrayType::get(CGM.Int8PtrTy, VTLayout->getNumVTableComponents());
+ // Construction vtable symbols are not part of the Itanium ABI, so we cannot
+ // guarantee that they actually will be available externally. Instead, when
+ // emitting an available_externally VTT, we provide references to an internal
+ // linkage construction vtable. The ABI only requires complete-object vtables
+ // to be the same for all instances of a type, not construction vtables.
+ if (Linkage == llvm::GlobalVariable::AvailableExternallyLinkage)
+ Linkage = llvm::GlobalVariable::InternalLinkage;
+
// Create the variable that will hold the construction vtable.
llvm::GlobalVariable *VTable =
CGM.CreateOrReplaceCXXRuntimeVariable(Name, ArrayType, Linkage);
@@ -734,18 +714,111 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
return VTable;
}
+/// Compute the required linkage of the v-table for the given class.
+///
+/// Note that we only call this at the end of the translation unit.
+llvm::GlobalVariable::LinkageTypes
+CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
+ if (RD->getLinkage() != ExternalLinkage)
+ return llvm::GlobalVariable::InternalLinkage;
+
+ // We're at the end of the translation unit, so the current key
+ // function is fully correct.
+ if (const CXXMethodDecl *keyFunction = Context.getCurrentKeyFunction(RD)) {
+ // If this class has a key function, use that to determine the
+ // linkage of the vtable.
+ const FunctionDecl *def = 0;
+ if (keyFunction->hasBody(def))
+ keyFunction = cast<CXXMethodDecl>(def);
+
+ switch (keyFunction->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ // When compiling with optimizations turned on, we emit all vtables,
+ // even if the key function is not defined in the current translation
+ // unit. If this is the case, use available_externally linkage.
+ if (!def && CodeGenOpts.OptimizationLevel)
+ return llvm::GlobalVariable::AvailableExternallyLinkage;
+
+ if (keyFunction->isInlined())
+ return !Context.getLangOpts().AppleKext ?
+ llvm::GlobalVariable::LinkOnceODRLinkage :
+ llvm::Function::InternalLinkage;
+
+ return llvm::GlobalVariable::ExternalLinkage;
+
+ case TSK_ImplicitInstantiation:
+ return !Context.getLangOpts().AppleKext ?
+ llvm::GlobalVariable::LinkOnceODRLinkage :
+ llvm::Function::InternalLinkage;
+
+ case TSK_ExplicitInstantiationDefinition:
+ return !Context.getLangOpts().AppleKext ?
+ llvm::GlobalVariable::WeakODRLinkage :
+ llvm::Function::InternalLinkage;
+
+ case TSK_ExplicitInstantiationDeclaration:
+ return !Context.getLangOpts().AppleKext ?
+ llvm::GlobalVariable::AvailableExternallyLinkage :
+ llvm::Function::InternalLinkage;
+ }
+ }
+
+ // -fapple-kext mode does not support weak linkage, so we must use
+ // internal linkage.
+ if (Context.getLangOpts().AppleKext)
+ return llvm::Function::InternalLinkage;
+
+ switch (RD->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ case TSK_ImplicitInstantiation:
+ return llvm::GlobalVariable::LinkOnceODRLinkage;
+
+ case TSK_ExplicitInstantiationDeclaration:
+ return llvm::GlobalVariable::AvailableExternallyLinkage;
+
+ case TSK_ExplicitInstantiationDefinition:
+ return llvm::GlobalVariable::WeakODRLinkage;
+ }
+
+ llvm_unreachable("Invalid TemplateSpecializationKind!");
+}
+
+/// This is a callback from Sema to tell us that it believes that a
+/// particular v-table is required to be emitted in this translation
+/// unit.
+///
+/// The reason we don't simply trust this callback is because Sema
+/// will happily report that something is used even when it's used
+/// only in code that we don't actually have to emit.
+///
+/// \param isRequired - if true, the v-table is mandatory, e.g.
+/// because the translation unit defines the key function
+void CodeGenModule::EmitVTable(CXXRecordDecl *theClass, bool isRequired) {
+ if (!isRequired) return;
+
+ VTables.GenerateClassData(theClass);
+}
+
void
-CodeGenVTables::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
- const CXXRecordDecl *RD) {
+CodeGenVTables::GenerateClassData(const CXXRecordDecl *RD) {
+ // First off, check whether we've already emitted the v-table and
+ // associated stuff.
llvm::GlobalVariable *VTable = GetAddrOfVTable(RD);
if (VTable->hasInitializer())
return;
+ llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD);
EmitVTableDefinition(VTable, Linkage, RD);
if (RD->getNumVBases()) {
- llvm::GlobalVariable *VTT = GetAddrOfVTT(RD);
- EmitVTTDefinition(VTT, Linkage, RD);
+ if (!CGM.getTarget().getCXXABI().isMicrosoft()) {
+ llvm::GlobalVariable *VTT = GetAddrOfVTT(RD);
+ EmitVTTDefinition(VTT, Linkage, RD);
+ } else {
+ // FIXME: Emit vbtables here.
+ }
}
// If this is the magic class __cxxabiv1::__fundamental_type_info,
@@ -760,3 +833,80 @@ CodeGenVTables::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
DC->getParent()->isTranslationUnit())
CGM.EmitFundamentalRTTIDescriptors();
}
+
+/// At this point in the translation unit, does it appear that can we
+/// rely on the vtable being defined elsewhere in the program?
+///
+/// The response is really only definitive when called at the end of
+/// the translation unit.
+///
+/// The only semantic restriction here is that the object file should
+/// not contain a v-table definition when that v-table is defined
+/// strongly elsewhere. Otherwise, we'd just like to avoid emitting
+/// v-tables when unnecessary.
+bool CodeGenVTables::isVTableExternal(const CXXRecordDecl *RD) {
+ assert(RD->isDynamicClass() && "Non dynamic classes have no VTable.");
+
+ // If we have an explicit instantiation declaration (and not a
+ // definition), the v-table is defined elsewhere.
+ TemplateSpecializationKind TSK = RD->getTemplateSpecializationKind();
+ if (TSK == TSK_ExplicitInstantiationDeclaration)
+ return true;
+
+ // Otherwise, if the class is an instantiated template, the
+ // v-table must be defined here.
+ if (TSK == TSK_ImplicitInstantiation ||
+ TSK == TSK_ExplicitInstantiationDefinition)
+ return false;
+
+ // Otherwise, if the class doesn't have a key function (possibly
+ // anymore), the v-table must be defined here.
+ const CXXMethodDecl *keyFunction = CGM.getContext().getCurrentKeyFunction(RD);
+ if (!keyFunction)
+ return false;
+
+ // Otherwise, if we don't have a definition of the key function, the
+ // v-table must be defined somewhere else.
+ return !keyFunction->hasBody();
+}
+
+/// Given that we're currently at the end of the translation unit, and
+/// we've emitted a reference to the v-table for this class, should
+/// we define that v-table?
+static bool shouldEmitVTableAtEndOfTranslationUnit(CodeGenModule &CGM,
+ const CXXRecordDecl *RD) {
+ // If we're building with optimization, we always emit v-tables
+ // since that allows for virtual function calls to be devirtualized.
+ // If the v-table is defined strongly elsewhere, this definition
+ // will be emitted available_externally.
+ //
+ // However, we don't want to do this in -fapple-kext mode, because
+ // kext mode does not permit devirtualization.
+ if (CGM.getCodeGenOpts().OptimizationLevel && !CGM.getLangOpts().AppleKext)
+ return true;
+
+ return !CGM.getVTables().isVTableExternal(RD);
+}
+
+/// Given that at some point we emitted a reference to one or more
+/// v-tables, and that we are now at the end of the translation unit,
+/// decide whether we should emit them.
+void CodeGenModule::EmitDeferredVTables() {
+#ifndef NDEBUG
+ // Remember the size of DeferredVTables, because we're going to assume
+ // that this entire operation doesn't modify it.
+ size_t savedSize = DeferredVTables.size();
+#endif
+
+ typedef std::vector<const CXXRecordDecl *>::const_iterator const_iterator;
+ for (const_iterator i = DeferredVTables.begin(),
+ e = DeferredVTables.end(); i != e; ++i) {
+ const CXXRecordDecl *RD = *i;
+ if (shouldEmitVTableAtEndOfTranslationUnit(*this, RD))
+ VTables.GenerateClassData(RD);
+ }
+
+ assert(savedSize == DeferredVTables.size() &&
+ "deferred extra v-tables during v-table emission?");
+ DeferredVTables.clear();
+}
diff --git a/lib/CodeGen/CGVTables.h b/lib/CodeGen/CGVTables.h
index 828330e..bd3bdb1 100644
--- a/lib/CodeGen/CGVTables.h
+++ b/lib/CodeGen/CGVTables.h
@@ -14,13 +14,13 @@
#ifndef CLANG_CODEGEN_CGVTABLE_H
#define CLANG_CODEGEN_CGVTABLE_H
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/GlobalVariable.h"
-#include "clang/Basic/ABI.h"
#include "clang/AST/BaseSubobject.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/GlobalDecl.h"
#include "clang/AST/VTableBuilder.h"
+#include "clang/Basic/ABI.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/IR/GlobalVariable.h"
namespace clang {
class CXXRecordDecl;
@@ -77,10 +77,6 @@ public:
VTableContext &getVTableContext() { return VTContext; }
- /// \brief True if the VTable of this record must be emitted in the
- /// translation unit.
- bool ShouldEmitVTableInThisTU(const CXXRecordDecl *RD);
-
/// needsVTTParameter - Return whether the given global decl needs a VTT
/// parameter, which it does if it's a base constructor or destructor with
/// virtual bases.
@@ -127,13 +123,13 @@ public:
/// EmitThunks - Emit the associated thunks for the given global decl.
void EmitThunks(GlobalDecl GD);
- /// GenerateClassData - Generate all the class data required to be generated
- /// upon definition of a KeyFunction. This includes the vtable, the
- /// rtti data structure and the VTT.
- ///
- /// \param Linkage - The desired linkage of the vtable, the RTTI and the VTT.
- void GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
- const CXXRecordDecl *RD);
+ /// GenerateClassData - Generate all the class data required to be
+ /// generated upon definition of a KeyFunction. This includes the
+ /// vtable, the RTTI data structure (if RTTI is enabled) and the VTT
+ /// (if the class has virtual bases).
+ void GenerateClassData(const CXXRecordDecl *RD);
+
+ bool isVTableExternal(const CXXRecordDecl *RD);
};
} // end namespace CodeGen
diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h
index c2b8e4d..b625b86 100644
--- a/lib/CodeGen/CGValue.h
+++ b/lib/CodeGen/CGValue.h
@@ -18,16 +18,17 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Type.h"
+#include "llvm/IR/Value.h"
namespace llvm {
class Constant;
- class Value;
+ class MDNode;
}
namespace clang {
namespace CodeGen {
class AggValueSlot;
- class CGBitFieldInfo;
+ struct CGBitFieldInfo;
/// RValue - This trivial value class is used to represent the result of an
/// expression that is evaluated. It can be one of three things: either a
@@ -96,6 +97,10 @@ public:
}
};
+/// Does an ARC strong l-value have precise lifetime?
+enum ARCPreciseLifetime_t {
+ ARCImpreciseLifetime, ARCPreciseLifetime
+};
/// LValue - This represents an lvalue references. Because C/C++ allow
/// bitfields, this is not a simple LLVM pointer, it may be a pointer plus a
@@ -146,8 +151,17 @@ class LValue {
// Lvalue is a thread local reference
bool ThreadLocalRef : 1;
+ // Lvalue has ARC imprecise lifetime. We store this inverted to try
+ // to make the default bitfield pattern all-zeroes.
+ bool ImpreciseLifetime : 1;
+
Expr *BaseIvarExp;
+ /// Used by struct-path-aware TBAA.
+ QualType TBAABaseType;
+ /// Offset relative to the base type.
+ uint64_t TBAAOffset;
+
/// TBAAInfo - TBAA information to attach to dereferences of this LValue.
llvm::MDNode *TBAAInfo;
@@ -163,8 +177,13 @@ private:
// Initialize Objective-C flags.
this->Ivar = this->ObjIsArray = this->NonGC = this->GlobalObjCRef = false;
+ this->ImpreciseLifetime = false;
this->ThreadLocalRef = false;
this->BaseIvarExp = 0;
+
+ // Initialize fields for TBAA.
+ this->TBAABaseType = Type;
+ this->TBAAOffset = 0;
this->TBAAInfo = TBAAInfo;
}
@@ -201,6 +220,13 @@ public:
bool isThreadLocalRef() const { return ThreadLocalRef; }
void setThreadLocalRef(bool Value) { ThreadLocalRef = Value;}
+ ARCPreciseLifetime_t isARCPreciseLifetime() const {
+ return ARCPreciseLifetime_t(!ImpreciseLifetime);
+ }
+ void setARCPreciseLifetime(ARCPreciseLifetime_t value) {
+ ImpreciseLifetime = (value == ARCImpreciseLifetime);
+ }
+
bool isObjCWeak() const {
return Quals.getObjCGCAttr() == Qualifiers::Weak;
}
@@ -215,6 +241,12 @@ public:
Expr *getBaseIvarExp() const { return BaseIvarExp; }
void setBaseIvarExp(Expr *V) { BaseIvarExp = V; }
+ QualType getTBAABaseType() const { return TBAABaseType; }
+ void setTBAABaseType(QualType T) { TBAABaseType = T; }
+
+ uint64_t getTBAAOffset() const { return TBAAOffset; }
+ void setTBAAOffset(uint64_t O) { TBAAOffset = O; }
+
llvm::MDNode *getTBAAInfo() const { return TBAAInfo; }
void setTBAAInfo(llvm::MDNode *N) { TBAAInfo = N; }
@@ -245,7 +277,7 @@ public:
}
// bitfield lvalue
- llvm::Value *getBitFieldBaseAddr() const {
+ llvm::Value *getBitFieldAddr() const {
assert(isBitField());
return V;
}
@@ -289,16 +321,16 @@ public:
/// \brief Create a new object to represent a bit-field access.
///
- /// \param BaseValue - The base address of the structure containing the
- /// bit-field.
+ /// \param Addr - The base address of the bit-field sequence this
+ /// bit-field refers to.
/// \param Info - The information describing how to perform the bit-field
/// access.
- static LValue MakeBitfield(llvm::Value *BaseValue,
+ static LValue MakeBitfield(llvm::Value *Addr,
const CGBitFieldInfo &Info,
QualType type, CharUnits Alignment) {
LValue R;
R.LVType = BitField;
- R.V = BaseValue;
+ R.V = Addr;
R.BitFieldInfo = &Info;
R.Initialize(type, type.getQualifiers(), Alignment);
return R;
@@ -349,11 +381,23 @@ class AggValueSlot {
/// evaluating an expression which constructs such an object.
bool AliasedFlag : 1;
+ /// ValueOfAtomicFlag - This is set to true if the slot is the value
+ /// subobject of an object the size of an _Atomic(T). The specific
+ /// guarantees this makes are:
+ /// - the address is guaranteed to be a getelementptr into the
+ /// padding struct and
+ /// - it is okay to store something the width of an _Atomic(T)
+ /// into the address.
+ /// Tracking this allows us to avoid some obviously unnecessary
+ /// memcpys.
+ bool ValueOfAtomicFlag : 1;
+
public:
enum IsAliased_t { IsNotAliased, IsAliased };
enum IsDestructed_t { IsNotDestructed, IsDestructed };
enum IsZeroed_t { IsNotZeroed, IsZeroed };
enum NeedsGCBarriers_t { DoesNotNeedGCBarriers, NeedsGCBarriers };
+ enum IsValueOfAtomic_t { IsNotValueOfAtomic, IsValueOfAtomic };
/// ignored - Returns an aggregate value slot indicating that the
/// aggregate value is being ignored.
@@ -377,7 +421,9 @@ public:
IsDestructed_t isDestructed,
NeedsGCBarriers_t needsGC,
IsAliased_t isAliased,
- IsZeroed_t isZeroed = IsNotZeroed) {
+ IsZeroed_t isZeroed = IsNotZeroed,
+ IsValueOfAtomic_t isValueOfAtomic
+ = IsNotValueOfAtomic) {
AggValueSlot AV;
AV.Addr = addr;
AV.Alignment = align.getQuantity();
@@ -386,6 +432,7 @@ public:
AV.ObjCGCFlag = needsGC;
AV.ZeroedFlag = isZeroed;
AV.AliasedFlag = isAliased;
+ AV.ValueOfAtomicFlag = isValueOfAtomic;
return AV;
}
@@ -393,9 +440,12 @@ public:
IsDestructed_t isDestructed,
NeedsGCBarriers_t needsGC,
IsAliased_t isAliased,
- IsZeroed_t isZeroed = IsNotZeroed) {
+ IsZeroed_t isZeroed = IsNotZeroed,
+ IsValueOfAtomic_t isValueOfAtomic
+ = IsNotValueOfAtomic) {
return forAddr(LV.getAddress(), LV.getAlignment(),
- LV.getQuals(), isDestructed, needsGC, isAliased, isZeroed);
+ LV.getQuals(), isDestructed, needsGC, isAliased, isZeroed,
+ isValueOfAtomic);
}
IsDestructed_t isExternallyDestructed() const {
@@ -411,6 +461,10 @@ public:
return Quals.hasVolatile();
}
+ void setVolatile(bool flag) {
+ Quals.setVolatile(flag);
+ }
+
Qualifiers::ObjCLifetime getObjCLifetime() const {
return Quals.getObjCLifetime();
}
@@ -423,6 +477,12 @@ public:
return Addr;
}
+ IsValueOfAtomic_t isValueOfAtomic() const {
+ return IsValueOfAtomic_t(ValueOfAtomicFlag);
+ }
+
+ llvm::Value *getPaddedAtomicAddr() const;
+
bool isIgnored() const {
return Addr == 0;
}
diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt
index 76be85f..9ca2295 100644
--- a/lib/CodeGen/CMakeLists.txt
+++ b/lib/CodeGen/CMakeLists.txt
@@ -2,6 +2,7 @@ set(LLVM_LINK_COMPONENTS
asmparser
bitreader
bitwriter
+ irreader
instrumentation
ipo
linker
@@ -10,6 +11,7 @@ set(LLVM_LINK_COMPONENTS
add_clang_library(clangCodeGen
BackendUtil.cpp
+ CGAtomic.cpp
CGBlocks.cpp
CGBuiltin.cpp
CGCall.cpp
diff --git a/lib/CodeGen/CodeGenAction.cpp b/lib/CodeGen/CodeGenAction.cpp
index 9d6d183..679cfeb 100644
--- a/lib/CodeGen/CodeGenAction.cpp
+++ b/lib/CodeGen/CodeGenAction.cpp
@@ -8,24 +8,24 @@
//===----------------------------------------------------------------------===//
#include "clang/CodeGen/CodeGenAction.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/TargetInfo.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclGroup.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/CodeGen/BackendUtil.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
-#include "llvm/LLVMContext.h"
-#include "llvm/Linker.h"
-#include "llvm/Module.h"
-#include "llvm/Pass.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Bitcode/ReaderWriter.h"
-#include "llvm/Support/IRReader.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IRReader/IRReader.h"
+#include "llvm/Linker.h"
+#include "llvm/Pass.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/Timer.h"
@@ -67,7 +67,7 @@ namespace clang {
AsmOutStream(OS),
Context(),
LLVMIRGeneration("LLVM IR Generation Time"),
- Gen(CreateLLVMCodeGen(Diags, infile, compopts, C)),
+ Gen(CreateLLVMCodeGen(Diags, infile, compopts, targetopts, C)),
LinkModule(LinkModule)
{
llvm::TimePassesIsEnabled = TimePasses;
@@ -398,7 +398,7 @@ void CodeGenAction::ExecuteAction() {
Msg = Msg.substr(7);
// Escape '%', which is interpreted as a format character.
- llvm::SmallString<128> EscapedMessage;
+ SmallString<128> EscapedMessage;
for (unsigned i = 0, e = Msg.size(); i != e; ++i) {
if (Msg[i] == '%')
EscapedMessage += '%';
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 18f1623..2c3cabe 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -12,19 +12,21 @@
//===----------------------------------------------------------------------===//
#include "CodeGenFunction.h"
-#include "CodeGenModule.h"
#include "CGCUDARuntime.h"
#include "CGCXXABI.h"
#include "CGDebugInfo.h"
-#include "clang/Basic/TargetInfo.h"
+#include "CodeGenModule.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/Basic/OpenCL.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CodeGenOptions.h"
-#include "llvm/Intrinsics.h"
-#include "llvm/MDBuilder.h"
-#include "llvm/DataLayout.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/MDBuilder.h"
+#include "llvm/IR/Operator.h"
using namespace clang;
using namespace CodeGen;
@@ -32,20 +34,32 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)
: CodeGenTypeCache(cgm), CGM(cgm),
Target(CGM.getContext().getTargetInfo()),
Builder(cgm.getModule().getContext()),
- SanitizePerformTypeCheck(CGM.getLangOpts().SanitizeNull |
- CGM.getLangOpts().SanitizeAlignment |
- CGM.getLangOpts().SanitizeObjectSize |
- CGM.getLangOpts().SanitizeVptr),
+ SanitizePerformTypeCheck(CGM.getSanOpts().Null |
+ CGM.getSanOpts().Alignment |
+ CGM.getSanOpts().ObjectSize |
+ CGM.getSanOpts().Vptr),
+ SanOpts(&CGM.getSanOpts()),
AutoreleaseResult(false), BlockInfo(0), BlockPointer(0),
LambdaThisCaptureField(0), NormalCleanupDest(0), NextCleanupDestIndex(1),
FirstBlockInfo(0), EHResumeBlock(0), ExceptionSlot(0), EHSelectorSlot(0),
- DebugInfo(0), DisableDebugInfo(false), DidCallStackSave(false),
+ DebugInfo(0), DisableDebugInfo(false), CalleeWithThisReturn(0),
+ DidCallStackSave(false),
IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0),
- CXXABIThisDecl(0), CXXABIThisValue(0), CXXThisValue(0), CXXVTTDecl(0),
- CXXVTTValue(0), OutermostConditional(0), TerminateLandingPad(0),
+ CXXABIThisDecl(0), CXXABIThisValue(0), CXXThisValue(0),
+ CXXStructorImplicitParamDecl(0), CXXStructorImplicitParamValue(0),
+ OutermostConditional(0), CurLexicalScope(0), TerminateLandingPad(0),
TerminateHandler(0), TrapBB(0) {
if (!suppressNewContext)
CGM.getCXXABI().getMangleContext().startNewFunction();
+
+ llvm::FastMathFlags FMF;
+ if (CGM.getLangOpts().FastMath)
+ FMF.setUnsafeAlgebra();
+ if (CGM.getLangOpts().FiniteMathOnly) {
+ FMF.setNoNaNs();
+ FMF.setNoInfs();
+ }
+ Builder.SetFastMathFlags(FMF);
}
CodeGenFunction::~CodeGenFunction() {
@@ -65,45 +79,53 @@ llvm::Type *CodeGenFunction::ConvertType(QualType T) {
return CGM.getTypes().ConvertType(T);
}
-bool CodeGenFunction::hasAggregateLLVMType(QualType type) {
- switch (type.getCanonicalType()->getTypeClass()) {
+TypeEvaluationKind CodeGenFunction::getEvaluationKind(QualType type) {
+ type = type.getCanonicalType();
+ while (true) {
+ switch (type->getTypeClass()) {
#define TYPE(name, parent)
#define ABSTRACT_TYPE(name, parent)
#define NON_CANONICAL_TYPE(name, parent) case Type::name:
#define DEPENDENT_TYPE(name, parent) case Type::name:
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(name, parent) case Type::name:
#include "clang/AST/TypeNodes.def"
- llvm_unreachable("non-canonical or dependent type in IR-generation");
-
- case Type::Builtin:
- case Type::Pointer:
- case Type::BlockPointer:
- case Type::LValueReference:
- case Type::RValueReference:
- case Type::MemberPointer:
- case Type::Vector:
- case Type::ExtVector:
- case Type::FunctionProto:
- case Type::FunctionNoProto:
- case Type::Enum:
- case Type::ObjCObjectPointer:
- return false;
+ llvm_unreachable("non-canonical or dependent type in IR-generation");
- // Complexes, arrays, records, and Objective-C objects.
- case Type::Complex:
- case Type::ConstantArray:
- case Type::IncompleteArray:
- case Type::VariableArray:
- case Type::Record:
- case Type::ObjCObject:
- case Type::ObjCInterface:
- return true;
+ // Various scalar types.
+ case Type::Builtin:
+ case Type::Pointer:
+ case Type::BlockPointer:
+ case Type::LValueReference:
+ case Type::RValueReference:
+ case Type::MemberPointer:
+ case Type::Vector:
+ case Type::ExtVector:
+ case Type::FunctionProto:
+ case Type::FunctionNoProto:
+ case Type::Enum:
+ case Type::ObjCObjectPointer:
+ return TEK_Scalar;
- // In IRGen, atomic types are just the underlying type
- case Type::Atomic:
- return hasAggregateLLVMType(type->getAs<AtomicType>()->getValueType());
+ // Complexes.
+ case Type::Complex:
+ return TEK_Complex;
+
+ // Arrays, records, and Objective-C objects.
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ case Type::VariableArray:
+ case Type::Record:
+ case Type::ObjCObject:
+ case Type::ObjCInterface:
+ return TEK_Aggregate;
+
+ // We operate on atomic values according to their underlying type.
+ case Type::Atomic:
+ type = cast<AtomicType>(type)->getValueType();
+ continue;
+ }
+ llvm_unreachable("unknown type kind!");
}
- llvm_unreachable("unknown type kind!");
}
void CodeGenFunction::EmitReturnBlock() {
@@ -132,7 +154,10 @@ void CodeGenFunction::EmitReturnBlock() {
dyn_cast<llvm::BranchInst>(*ReturnBlock.getBlock()->use_begin());
if (BI && BI->isUnconditional() &&
BI->getSuccessor(0) == ReturnBlock.getBlock()) {
- // Reset insertion point, including debug location, and delete the branch.
+ // Reset insertion point, including debug location, and delete the
+ // branch. This is really subtle and only works because the next change
+ // in location will hit the caching in CGDebugInfo::EmitLocation and not
+ // override this.
Builder.SetCurrentDebugLocation(BI->getDebugLoc());
Builder.SetInsertPoint(BI->getParent());
BI->eraseFromParent();
@@ -159,6 +184,9 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
assert(BreakContinueStack.empty() &&
"mismatched push/pop in break/continue stack!");
+ if (CGDebugInfo *DI = getDebugInfo())
+ DI->EmitLocation(Builder, EndLoc);
+
// Pop any cleanups that might have been associated with the
// parameters. Do this in whatever block we're currently in; it's
// important to do this before we enter the return block or return
@@ -174,7 +202,6 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
// Emit debug descriptor for function end.
if (CGDebugInfo *DI = getDebugInfo()) {
- DI->setLocation(EndLoc);
DI->EmitFunctionEnd(Builder);
}
@@ -190,12 +217,12 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
EmitBlock(IndirectBranch->getParent());
Builder.ClearInsertionPoint();
}
-
+
// Remove the AllocaInsertPt instruction, which is just a convenience for us.
llvm::Instruction *Ptr = AllocaInsertPt;
AllocaInsertPt = 0;
Ptr->eraseFromParent();
-
+
// If someone took the address of a label but never did an indirect goto, we
// made a zero entry PHI node, which is illegal, zap it now.
if (IndirectBranch) {
@@ -241,9 +268,12 @@ void CodeGenFunction::EmitFunctionInstrumentation(const char *Fn) {
llvm::ConstantInt::get(Int32Ty, 0),
"callsite");
- Builder.CreateCall2(F,
- llvm::ConstantExpr::getBitCast(CurFn, PointerTy),
- CallSite);
+ llvm::Value *args[] = {
+ llvm::ConstantExpr::getBitCast(CurFn, PointerTy),
+ CallSite
+ };
+
+ EmitNounwindRuntimeCall(F, args);
}
void CodeGenFunction::EmitMCountInstrumentation() {
@@ -251,37 +281,114 @@ void CodeGenFunction::EmitMCountInstrumentation() {
llvm::Constant *MCountFn = CGM.CreateRuntimeFunction(FTy,
Target.getMCountName());
- Builder.CreateCall(MCountFn);
+ EmitNounwindRuntimeCall(MCountFn);
}
// OpenCL v1.2 s5.6.4.6 allows the compiler to store kernel argument
// information in the program executable. The argument information stored
// includes the argument name, its type, the address and access qualifiers used.
-// FIXME: Add type, address, and access qualifiers.
static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn,
CodeGenModule &CGM,llvm::LLVMContext &Context,
- llvm::SmallVector <llvm::Value*, 5> &kernelMDArgs) {
-
- // Create MDNodes that represents the kernel arg metadata.
+ SmallVector <llvm::Value*, 5> &kernelMDArgs,
+ CGBuilderTy& Builder, ASTContext &ASTCtx) {
+ // Create MDNodes that represent the kernel arg metadata.
// Each MDNode is a list in the form of "key", N number of values which is
// the same number of values as their are kernel arguments.
-
+
+ // MDNode for the kernel argument address space qualifiers.
+ SmallVector<llvm::Value*, 8> addressQuals;
+ addressQuals.push_back(llvm::MDString::get(Context, "kernel_arg_addr_space"));
+
+ // MDNode for the kernel argument access qualifiers (images only).
+ SmallVector<llvm::Value*, 8> accessQuals;
+ accessQuals.push_back(llvm::MDString::get(Context, "kernel_arg_access_qual"));
+
+ // MDNode for the kernel argument type names.
+ SmallVector<llvm::Value*, 8> argTypeNames;
+ argTypeNames.push_back(llvm::MDString::get(Context, "kernel_arg_type"));
+
+ // MDNode for the kernel argument type qualifiers.
+ SmallVector<llvm::Value*, 8> argTypeQuals;
+ argTypeQuals.push_back(llvm::MDString::get(Context, "kernel_arg_type_qual"));
+
// MDNode for the kernel argument names.
SmallVector<llvm::Value*, 8> argNames;
argNames.push_back(llvm::MDString::get(Context, "kernel_arg_name"));
-
+
for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) {
const ParmVarDecl *parm = FD->getParamDecl(i);
+ QualType ty = parm->getType();
+ std::string typeQuals;
+
+ if (ty->isPointerType()) {
+ QualType pointeeTy = ty->getPointeeType();
+
+ // Get address qualifier.
+ addressQuals.push_back(Builder.getInt32(ASTCtx.getTargetAddressSpace(
+ pointeeTy.getAddressSpace())));
+
+ // Get argument type name.
+ std::string typeName = pointeeTy.getUnqualifiedType().getAsString() + "*";
+
+ // Turn "unsigned type" to "utype"
+ std::string::size_type pos = typeName.find("unsigned");
+ if (pos != std::string::npos)
+ typeName.erase(pos+1, 8);
+
+ argTypeNames.push_back(llvm::MDString::get(Context, typeName));
+
+ // Get argument type qualifiers:
+ if (ty.isRestrictQualified())
+ typeQuals = "restrict";
+ if (pointeeTy.isConstQualified() ||
+ (pointeeTy.getAddressSpace() == LangAS::opencl_constant))
+ typeQuals += typeQuals.empty() ? "const" : " const";
+ if (pointeeTy.isVolatileQualified())
+ typeQuals += typeQuals.empty() ? "volatile" : " volatile";
+ } else {
+ addressQuals.push_back(Builder.getInt32(0));
+
+ // Get argument type name.
+ std::string typeName = ty.getUnqualifiedType().getAsString();
+
+ // Turn "unsigned type" to "utype"
+ std::string::size_type pos = typeName.find("unsigned");
+ if (pos != std::string::npos)
+ typeName.erase(pos+1, 8);
+
+ argTypeNames.push_back(llvm::MDString::get(Context, typeName));
+
+ // Get argument type qualifiers:
+ if (ty.isConstQualified())
+ typeQuals = "const";
+ if (ty.isVolatileQualified())
+ typeQuals += typeQuals.empty() ? "volatile" : " volatile";
+ }
+ argTypeQuals.push_back(llvm::MDString::get(Context, typeQuals));
+
+ // Get image access qualifier:
+ if (ty->isImageType()) {
+ if (parm->hasAttr<OpenCLImageAccessAttr>() &&
+ parm->getAttr<OpenCLImageAccessAttr>()->getAccess() == CLIA_write_only)
+ accessQuals.push_back(llvm::MDString::get(Context, "write_only"));
+ else
+ accessQuals.push_back(llvm::MDString::get(Context, "read_only"));
+ } else
+ accessQuals.push_back(llvm::MDString::get(Context, "none"));
+
// Get argument name.
argNames.push_back(llvm::MDString::get(Context, parm->getName()));
-
}
- // Add MDNode to the list of all metadata.
+
+ kernelMDArgs.push_back(llvm::MDNode::get(Context, addressQuals));
+ kernelMDArgs.push_back(llvm::MDNode::get(Context, accessQuals));
+ kernelMDArgs.push_back(llvm::MDNode::get(Context, argTypeNames));
+ kernelMDArgs.push_back(llvm::MDNode::get(Context, argTypeQuals));
kernelMDArgs.push_back(llvm::MDNode::get(Context, argNames));
}
-void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,
+void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,
llvm::Function *Fn)
{
if (!FD->hasAttr<OpenCLKernelAttr>())
@@ -289,37 +396,49 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,
llvm::LLVMContext &Context = getLLVMContext();
- llvm::SmallVector <llvm::Value*, 5> kernelMDArgs;
+ SmallVector <llvm::Value*, 5> kernelMDArgs;
kernelMDArgs.push_back(Fn);
if (CGM.getCodeGenOpts().EmitOpenCLArgMetadata)
- GenOpenCLArgMetadata(FD, Fn, CGM, Context, kernelMDArgs);
-
+ GenOpenCLArgMetadata(FD, Fn, CGM, Context, kernelMDArgs,
+ Builder, getContext());
+
+ if (FD->hasAttr<VecTypeHintAttr>()) {
+ VecTypeHintAttr *attr = FD->getAttr<VecTypeHintAttr>();
+ QualType hintQTy = attr->getTypeHint();
+ const ExtVectorType *hintEltQTy = hintQTy->getAs<ExtVectorType>();
+ bool isSignedInteger =
+ hintQTy->isSignedIntegerType() ||
+ (hintEltQTy && hintEltQTy->getElementType()->isSignedIntegerType());
+ llvm::Value *attrMDArgs[] = {
+ llvm::MDString::get(Context, "vec_type_hint"),
+ llvm::UndefValue::get(CGM.getTypes().ConvertType(attr->getTypeHint())),
+ llvm::ConstantInt::get(
+ llvm::IntegerType::get(Context, 32),
+ llvm::APInt(32, (uint64_t)(isSignedInteger ? 1 : 0)))
+ };
+ kernelMDArgs.push_back(llvm::MDNode::get(Context, attrMDArgs));
+ }
+
if (FD->hasAttr<WorkGroupSizeHintAttr>()) {
- llvm::SmallVector <llvm::Value*, 5> attrMDArgs;
- attrMDArgs.push_back(llvm::MDString::get(Context, "work_group_size_hint"));
WorkGroupSizeHintAttr *attr = FD->getAttr<WorkGroupSizeHintAttr>();
- llvm::Type *iTy = llvm::IntegerType::get(Context, 32);
- attrMDArgs.push_back(llvm::ConstantInt::get(iTy,
- llvm::APInt(32, (uint64_t)attr->getXDim())));
- attrMDArgs.push_back(llvm::ConstantInt::get(iTy,
- llvm::APInt(32, (uint64_t)attr->getYDim())));
- attrMDArgs.push_back(llvm::ConstantInt::get(iTy,
- llvm::APInt(32, (uint64_t)attr->getZDim())));
+ llvm::Value *attrMDArgs[] = {
+ llvm::MDString::get(Context, "work_group_size_hint"),
+ Builder.getInt32(attr->getXDim()),
+ Builder.getInt32(attr->getYDim()),
+ Builder.getInt32(attr->getZDim())
+ };
kernelMDArgs.push_back(llvm::MDNode::get(Context, attrMDArgs));
}
if (FD->hasAttr<ReqdWorkGroupSizeAttr>()) {
- llvm::SmallVector <llvm::Value*, 5> attrMDArgs;
- attrMDArgs.push_back(llvm::MDString::get(Context, "reqd_work_group_size"));
ReqdWorkGroupSizeAttr *attr = FD->getAttr<ReqdWorkGroupSizeAttr>();
- llvm::Type *iTy = llvm::IntegerType::get(Context, 32);
- attrMDArgs.push_back(llvm::ConstantInt::get(iTy,
- llvm::APInt(32, (uint64_t)attr->getXDim())));
- attrMDArgs.push_back(llvm::ConstantInt::get(iTy,
- llvm::APInt(32, (uint64_t)attr->getYDim())));
- attrMDArgs.push_back(llvm::ConstantInt::get(iTy,
- llvm::APInt(32, (uint64_t)attr->getZDim())));
+ llvm::Value *attrMDArgs[] = {
+ llvm::MDString::get(Context, "reqd_work_group_size"),
+ Builder.getInt32(attr->getXDim()),
+ Builder.getInt32(attr->getYDim()),
+ Builder.getInt32(attr->getZDim())
+ };
kernelMDArgs.push_back(llvm::MDNode::get(Context, attrMDArgs));
}
@@ -335,7 +454,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
const FunctionArgList &Args,
SourceLocation StartLoc) {
const Decl *D = GD.getDecl();
-
+
DidCallStackSave = false;
CurCodeDecl = CurFuncDecl = D;
FnRetTy = RetTy;
@@ -343,14 +462,19 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
CurFnInfo = &FnInfo;
assert(CurFn->isDeclaration() && "Function already has body?");
+ if (CGM.getSanitizerBlacklist().isIn(*Fn)) {
+ SanOpts = &SanitizerOptions::Disabled;
+ SanitizePerformTypeCheck = false;
+ }
+
// Pass inline keyword to optimizer if it appears explicitly on any
// declaration.
- if (!CGM.getCodeGenOpts().NoInline)
+ if (!CGM.getCodeGenOpts().NoInline)
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
for (FunctionDecl::redecl_iterator RI = FD->redecls_begin(),
RE = FD->redecls_end(); RI != RE; ++RI)
if (RI->isInlineSpecified()) {
- Fn->addFnAttr(llvm::Attributes::InlineHint);
+ Fn->addFnAttr(llvm::Attribute::InlineHint);
break;
}
@@ -376,19 +500,16 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
// Emit subprogram debug descriptor.
if (CGDebugInfo *DI = getDebugInfo()) {
- unsigned NumArgs = 0;
- QualType *ArgsArray = new QualType[Args.size()];
+ SmallVector<QualType, 16> ArgTypes;
for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end();
i != e; ++i) {
- ArgsArray[NumArgs++] = (*i)->getType();
+ ArgTypes.push_back((*i)->getType());
}
QualType FnType =
- getContext().getFunctionType(RetTy, ArgsArray, NumArgs,
+ getContext().getFunctionType(RetTy, ArgTypes,
FunctionProtoType::ExtProtoInfo());
- delete[] ArgsArray;
-
DI->setLocation(StartLoc);
DI->EmitFunctionStart(GD, FnType, CurFn, Builder);
}
@@ -403,7 +524,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
// Void type; nothing to return.
ReturnValue = 0;
} else if (CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect &&
- hasAggregateLLVMType(CurFnInfo->getReturnType())) {
+ !hasScalarEvaluationKind(CurFnInfo->getReturnType())) {
// Indirect aggregate return; emit returned value directly into sret slot.
// This reduces code size, and affects correctness in C++.
ReturnValue = CurFn->arg_begin();
@@ -454,7 +575,16 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
// emit the type size.
for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end();
i != e; ++i) {
- QualType Ty = (*i)->getType();
+ const VarDecl *VD = *i;
+
+ // Dig out the type as written from ParmVarDecls; it's unclear whether
+ // the standard (C99 6.9.1p10) requires this, but we're following the
+ // precedent set by gcc.
+ QualType Ty;
+ if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(VD))
+ Ty = PVD->getOriginalType();
+ else
+ Ty = VD->getType();
if (Ty->isVariablyModifiedType())
EmitVariablyModifiedType(Ty);
@@ -467,7 +597,10 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
void CodeGenFunction::EmitFunctionBody(FunctionArgList &Args) {
const FunctionDecl *FD = cast<FunctionDecl>(CurGD.getDecl());
assert(FD->getBody());
- EmitStmt(FD->getBody());
+ if (const CompoundStmt *S = dyn_cast<CompoundStmt>(FD->getBody()))
+ EmitCompoundStmtWithoutScope(*S);
+ else
+ EmitStmt(FD->getBody());
}
/// Tries to mark the given function nounwind based on the
@@ -493,7 +626,7 @@ static void TryMarkNoThrow(llvm::Function *F) {
void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
const CGFunctionInfo &FnInfo) {
const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
-
+
// Check if we should generate debug info for this function.
if (!FD->hasAttr<NoDebugAttr>())
maybeInitializeDebugInfo();
@@ -511,6 +644,10 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
SourceRange BodyRange;
if (Stmt *Body = FD->getBody()) BodyRange = Body->getSourceRange();
+ // CalleeWithThisReturn keeps track of the last callee inside this function
+ // that returns 'this'. Before starting the function, we set it to null.
+ CalleeWithThisReturn = 0;
+
// Emit the standard function prologue.
StartFunction(GD, ResTy, Fn, FnInfo, Args, BodyRange.getBegin());
@@ -533,6 +670,11 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
// The lambda "__invoke" function is special, because it forwards or
// clones the body of the function call operator (but is actually static).
EmitLambdaStaticInvokeFunction(cast<CXXMethodDecl>(FD));
+ } else if (FD->isDefaulted() && isa<CXXMethodDecl>(FD) &&
+ cast<CXXMethodDecl>(FD)->isCopyAssignmentOperator()) {
+ // Implicit copy-assignment gets the same special treatment as implicit
+ // copy-constructors.
+ emitImplicitAssignmentOperatorBody(Args);
}
else
EmitFunctionBody(Args);
@@ -545,10 +687,10 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
// function call is used by the caller, the behavior is undefined.
if (getLangOpts().CPlusPlus && !FD->hasImplicitReturnZero() &&
!FD->getResultType()->isVoidType() && Builder.GetInsertBlock()) {
- if (getLangOpts().SanitizeReturn)
+ if (SanOpts->Return)
EmitCheck(Builder.getFalse(), "missing_return",
EmitCheckSourceLocation(FD->getLocation()),
- llvm::ArrayRef<llvm::Value*>());
+ ArrayRef<llvm::Value *>(), CRK_Unrecoverable);
else if (CGM.getCodeGenOpts().OptimizationLevel == 0)
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::trap));
Builder.CreateUnreachable();
@@ -557,6 +699,9 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
// Emit the standard function epilogue.
FinishFunction(BodyRange.getEnd());
+ // CalleeWithThisReturn keeps track of the last callee inside this function
+ // that returns 'this'. After finishing the function, we set it to null.
+ CalleeWithThisReturn = 0;
// If we haven't marked the function nothrow through other means, do
// a quick pass now to see if we can.
@@ -578,7 +723,7 @@ bool CodeGenFunction::ContainsLabel(const Stmt *S, bool IgnoreCaseStmts) {
// can't jump to one from outside their declared region.
if (isa<LabelStmt>(S))
return true;
-
+
// If this is a case/default statement, and we haven't seen a switch, we have
// to emit the code.
if (isa<SwitchCase>(S) && !IgnoreCaseStmts)
@@ -608,15 +753,15 @@ bool CodeGenFunction::containsBreak(const Stmt *S) {
if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) || isa<DoStmt>(S) ||
isa<ForStmt>(S))
return false;
-
+
if (isa<BreakStmt>(S))
return true;
-
+
// Scan subexpressions for verboten breaks.
for (Stmt::const_child_range I = S->children(); I; ++I)
if (containsBreak(*I))
return true;
-
+
return false;
}
@@ -629,7 +774,7 @@ bool CodeGenFunction::ConstantFoldsToSimpleInteger(const Expr *Cond,
llvm::APSInt ResultInt;
if (!ConstantFoldsToSimpleInteger(Cond, ResultInt))
return false;
-
+
ResultBool = ResultInt.getBoolValue();
return true;
}
@@ -698,7 +843,7 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
return;
}
-
+
if (CondBOp->getOpcode() == BO_LOr) {
// If we have "0 || X", simplify the code. "1 || X" would have constant
// folded if the case was simple enough.
@@ -781,7 +926,7 @@ void CodeGenFunction::ErrorUnsupported(const Stmt *S, const char *Type,
/// base element of the array
/// \param sizeInChars - the total size of the VLA, in chars
static void emitNonZeroVLAInit(CodeGenFunction &CGF, QualType baseType,
- llvm::Value *dest, llvm::Value *src,
+ llvm::Value *dest, llvm::Value *src,
llvm::Value *sizeInChars) {
std::pair<CharUnits,CharUnits> baseSizeAndAlign
= CGF.getContext().getTypeInfoInChars(baseType);
@@ -821,7 +966,7 @@ static void emitNonZeroVLAInit(CodeGenFunction &CGF, QualType baseType,
cur->addIncoming(next, loopBB);
CGF.EmitBlock(contBB);
-}
+}
void
CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) {
@@ -841,7 +986,7 @@ CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) {
DestPtr = Builder.CreateBitCast(DestPtr, BP);
// Get size and alignment info for this aggregate.
- std::pair<CharUnits, CharUnits> TypeInfo =
+ std::pair<CharUnits, CharUnits> TypeInfo =
getContext().getTypeInfoInChars(Ty);
CharUnits Size = TypeInfo.first;
CharUnits Align = TypeInfo.second;
@@ -882,9 +1027,9 @@ CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) {
llvm::Constant *NullConstant = CGM.EmitNullConstant(Ty);
- llvm::GlobalVariable *NullVariable =
+ llvm::GlobalVariable *NullVariable =
new llvm::GlobalVariable(CGM.getModule(), NullConstant->getType(),
- /*isConstant=*/true,
+ /*isConstant=*/true,
llvm::GlobalVariable::PrivateLinkage,
NullConstant, Twine());
llvm::Value *SrcPtr =
@@ -895,12 +1040,12 @@ CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) {
// Get and call the appropriate llvm.memcpy overload.
Builder.CreateMemCpy(DestPtr, SrcPtr, SizeVal, Align.getQuantity(), false);
return;
- }
-
+ }
+
// Otherwise, just memset the whole thing to zero. This is legal
// because in LLVM, all default initializers (other than the ones we just
// handled above) are guaranteed to have a bit pattern of all zeros.
- Builder.CreateMemSet(DestPtr, Builder.getInt8(0), SizeVal,
+ Builder.CreateMemSet(DestPtr, Builder.getInt8(0), SizeVal,
Align.getQuantity(), false);
}
@@ -908,9 +1053,9 @@ llvm::BlockAddress *CodeGenFunction::GetAddrOfLabel(const LabelDecl *L) {
// Make sure that there is a block for the indirect goto.
if (IndirectBranch == 0)
GetIndirectGotoBlock();
-
+
llvm::BasicBlock *BB = getJumpDestForLabel(L).getBlock();
-
+
// Make sure the indirect branch includes all of the address-taken blocks.
IndirectBranch->addDestination(BB);
return llvm::BlockAddress::get(CurFn, BB);
@@ -919,13 +1064,13 @@ llvm::BlockAddress *CodeGenFunction::GetAddrOfLabel(const LabelDecl *L) {
llvm::BasicBlock *CodeGenFunction::GetIndirectGotoBlock() {
// If we already made the indirect branch for indirect goto, return its block.
if (IndirectBranch) return IndirectBranch->getParent();
-
+
CGBuilderTy TmpBuilder(createBasicBlock("indirectgoto"));
-
+
// Create the PHI node that indirect gotos will add entries to.
llvm::Value *DestVal = TmpBuilder.CreatePHI(Int8PtrTy, 0,
"indirect.goto.dest");
-
+
// Create the indirect branch instruction.
IndirectBranch = TmpBuilder.CreateIndirectBr(DestVal);
return IndirectBranch->getParent();
@@ -1130,7 +1275,7 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
// If the size is an expression that is not an integer constant
// expression [...] each time it is evaluated it shall have a value
// greater than zero.
- if (getLangOpts().SanitizeVLABound &&
+ if (SanOpts->VLABound &&
size->getType()->isSignedIntegerType()) {
llvm::Value *Zero = llvm::Constant::getNullValue(Size->getType());
llvm::Constant *StaticArgs[] = {
@@ -1138,7 +1283,8 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
EmitCheckTypeDescriptor(size->getType())
};
EmitCheck(Builder.CreateICmpSGT(Size, Zero),
- "vla_bound_not_positive", StaticArgs, Size);
+ "vla_bound_not_positive", StaticArgs, Size,
+ CRK_Recoverable);
}
// Always zexting here would be wrong if it weren't
@@ -1188,7 +1334,7 @@ llvm::Value* CodeGenFunction::EmitVAListRef(const Expr* E) {
return EmitLValue(E).getAddress();
}
-void CodeGenFunction::EmitDeclRefExprDbgValue(const DeclRefExpr *E,
+void CodeGenFunction::EmitDeclRefExprDbgValue(const DeclRefExpr *E,
llvm::Constant *Init) {
assert (Init && "Invalid DeclRefExpr initializer!");
if (CGDebugInfo *Dbg = getDebugInfo())
@@ -1225,7 +1371,7 @@ void CodeGenFunction::unprotectFromPeepholes(PeepholeProtection protection) {
llvm::Value *CodeGenFunction::EmitAnnotationCall(llvm::Value *AnnotationFn,
llvm::Value *AnnotatedVal,
- llvm::StringRef AnnotationStr,
+ StringRef AnnotationStr,
SourceLocation Location) {
llvm::Value *Args[4] = {
AnnotatedVal,
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index f2ab226..645d5ff 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -14,22 +14,22 @@
#ifndef CLANG_CODEGEN_CODEGENFUNCTION_H
#define CLANG_CODEGEN_CODEGENFUNCTION_H
-#include "clang/AST/Type.h"
+#include "CGBuilder.h"
+#include "CGDebugInfo.h"
+#include "CGValue.h"
+#include "CodeGenModule.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
-#include "clang/AST/CharUnits.h"
-#include "clang/Frontend/CodeGenOptions.h"
+#include "clang/AST/Type.h"
#include "clang/Basic/ABI.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/Support/ValueHandle.h"
#include "llvm/Support/Debug.h"
-#include "CodeGenModule.h"
-#include "CGBuilder.h"
-#include "CGDebugInfo.h"
-#include "CGValue.h"
+#include "llvm/Support/ValueHandle.h"
namespace llvm {
class BasicBlock;
@@ -78,6 +78,17 @@ namespace CodeGen {
class BlockFlags;
class BlockFieldFlags;
+/// The kind of evaluation to perform on values of a particular
+/// type. Basically, is the code in CGExprScalar, CGExprComplex, or
+/// CGExprAgg?
+///
+/// TODO: should vectors maybe be split out into their own thing?
+enum TypeEvaluationKind {
+ TEK_Scalar,
+ TEK_Complex,
+ TEK_Aggregate
+};
+
/// A branch fixup. These are required when emitting a goto to a
/// label which hasn't been emitted yet. The goto is optimistically
/// emitted as a branch to the basic block for the label, and (if it
@@ -551,6 +562,11 @@ public:
EHScopeStack::stable_iterator getScopeDepth() const { return ScopeDepth; }
unsigned getDestIndex() const { return Index; }
+ // This should be used cautiously.
+ void setScopeDepth(EHScopeStack::stable_iterator depth) {
+ ScopeDepth = depth;
+ }
+
private:
llvm::BasicBlock *Block;
EHScopeStack::stable_iterator ScopeDepth;
@@ -598,6 +614,9 @@ public:
/// calls to EmitTypeCheck can be skipped.
bool SanitizePerformTypeCheck;
+ /// \brief Sanitizer options to use for this function.
+ const SanitizerOptions *SanOpts;
+
/// In ARC, whether we should autorelease the return value.
bool AutoreleaseResult;
@@ -793,14 +812,16 @@ public:
class RunCleanupsScope {
EHScopeStack::stable_iterator CleanupStackDepth;
bool OldDidCallStackSave;
+ protected:
bool PerformCleanup;
+ private:
RunCleanupsScope(const RunCleanupsScope &) LLVM_DELETED_FUNCTION;
void operator=(const RunCleanupsScope &) LLVM_DELETED_FUNCTION;
protected:
CodeGenFunction& CGF;
-
+
public:
/// \brief Enter a new cleanup scope.
explicit RunCleanupsScope(CodeGenFunction &CGF)
@@ -837,7 +858,8 @@ public:
class LexicalScope: protected RunCleanupsScope {
SourceRange Range;
- bool PopDebugStack;
+ SmallVector<const LabelDecl*, 4> Labels;
+ LexicalScope *ParentScope;
LexicalScope(const LexicalScope &) LLVM_DELETED_FUNCTION;
void operator=(const LexicalScope &) LLVM_DELETED_FUNCTION;
@@ -845,29 +867,39 @@ public:
public:
/// \brief Enter a new cleanup scope.
explicit LexicalScope(CodeGenFunction &CGF, SourceRange Range)
- : RunCleanupsScope(CGF), Range(Range), PopDebugStack(true) {
+ : RunCleanupsScope(CGF), Range(Range), ParentScope(CGF.CurLexicalScope) {
+ CGF.CurLexicalScope = this;
if (CGDebugInfo *DI = CGF.getDebugInfo())
DI->EmitLexicalBlockStart(CGF.Builder, Range.getBegin());
}
+ void addLabel(const LabelDecl *label) {
+ assert(PerformCleanup && "adding label to dead scope?");
+ Labels.push_back(label);
+ }
+
/// \brief Exit this cleanup scope, emitting any accumulated
/// cleanups.
~LexicalScope() {
- if (PopDebugStack) {
- CGDebugInfo *DI = CGF.getDebugInfo();
- if (DI) DI->EmitLexicalBlockEnd(CGF.Builder, Range.getEnd());
- }
+ if (CGDebugInfo *DI = CGF.getDebugInfo())
+ DI->EmitLexicalBlockEnd(CGF.Builder, Range.getEnd());
+
+ // If we should perform a cleanup, force them now. Note that
+ // this ends the cleanup scope before rescoping any labels.
+ if (PerformCleanup) ForceCleanup();
}
/// \brief Force the emission of cleanups now, instead of waiting
/// until this object is destroyed.
void ForceCleanup() {
+ CGF.CurLexicalScope = ParentScope;
RunCleanupsScope::ForceCleanup();
- if (CGDebugInfo *DI = CGF.getDebugInfo()) {
- DI->EmitLexicalBlockEnd(CGF.Builder, Range.getEnd());
- PopDebugStack = false;
- }
+
+ if (!Labels.empty())
+ rescopeLabels();
}
+
+ void rescopeLabels();
};
@@ -1116,6 +1148,10 @@ private:
CGDebugInfo *DebugInfo;
bool DisableDebugInfo;
+ /// If the current function returns 'this', use the field to keep track of
+ /// the callee that returns 'this'.
+ llvm::Value *CalleeWithThisReturn;
+
/// DidCallStackSave - Whether llvm.stacksave has been called. Used to avoid
/// calling llvm.stacksave for multiple VLAs in the same scope.
bool DidCallStackSave;
@@ -1176,17 +1212,18 @@ private:
llvm::Value *CXXABIThisValue;
llvm::Value *CXXThisValue;
- /// CXXVTTDecl - When generating code for a base object constructor or
- /// base object destructor with virtual bases, this will hold the implicit
- /// VTT parameter.
- ImplicitParamDecl *CXXVTTDecl;
- llvm::Value *CXXVTTValue;
+ /// CXXStructorImplicitParamDecl - When generating code for a constructor or
+ /// destructor, this will hold the implicit argument (e.g. VTT).
+ ImplicitParamDecl *CXXStructorImplicitParamDecl;
+ llvm::Value *CXXStructorImplicitParamValue;
/// OutermostConditional - Points to the outermost active
/// conditional control. This is used so that we know if a
/// temporary should be destroyed conditionally.
ConditionalEvaluation *OutermostConditional;
+ /// The current lexical scope.
+ LexicalScope *CurLexicalScope;
/// ByrefValueInfoMap - For each __block variable, contains a pair of the LLVM
/// type as well as the field number that contains the actual data.
@@ -1200,6 +1237,9 @@ private:
/// Add a kernel metadata node to the named metadata node 'opencl.kernels'.
/// In the kernel metadata node, reference the kernel function and metadata
/// nodes for its optional attribute qualifiers (OpenCL 1.1 6.7.2):
+ /// - A node for the vec_type_hint(<type>) qualifier contains string
+ /// "vec_type_hint", an undefined value of the <type> data type,
+ /// and a Boolean that is true if the <type> is integer and signed.
/// - A node for the work_group_size_hint(X,Y,Z) qualifier contains string
/// "work_group_size_hint", and three 32-bit integers X, Y and Z.
/// - A node for the reqd_work_group_size(X,Y,Z) qualifier contains string
@@ -1279,6 +1319,8 @@ public:
void pushDestroy(QualType::DestructionKind dtorKind,
llvm::Value *addr, QualType type);
+ void pushEHDestroy(QualType::DestructionKind dtorKind,
+ llvm::Value *addr, QualType type);
void pushDestroy(CleanupKind kind, llvm::Value *addr, QualType type,
Destroyer *destroyer, bool useEHCleanupForArray);
void emitDestroy(llvm::Value *addr, QualType type, Destroyer *destroyer,
@@ -1397,6 +1439,7 @@ public:
void EmitConstructorBody(FunctionArgList &Args);
void EmitDestructorBody(FunctionArgList &Args);
+ void emitImplicitAssignmentOperatorBody(FunctionArgList &Args);
void EmitFunctionBody(FunctionArgList &Args);
void EmitForwardingCallToLambda(const CXXRecordDecl *Lambda,
@@ -1509,7 +1552,15 @@ public:
/// hasAggregateLLVMType - Return true if the specified AST type will map into
/// an aggregate LLVM type or is void.
- static bool hasAggregateLLVMType(QualType T);
+ static TypeEvaluationKind getEvaluationKind(QualType T);
+
+ static bool hasScalarEvaluationKind(QualType T) {
+ return getEvaluationKind(T) == TEK_Scalar;
+ }
+
+ static bool hasAggregateEvaluationKind(QualType T) {
+ return getEvaluationKind(T) == TEK_Aggregate;
+ }
/// createBasicBlock - Create an LLVM basic block.
llvm::BasicBlock *createBasicBlock(const Twine &name = "",
@@ -1662,17 +1713,27 @@ public:
void EmitExprAsInit(const Expr *init, const ValueDecl *D,
LValue lvalue, bool capturedByInit);
- /// EmitAggregateCopy - Emit an aggrate assignment.
+ /// hasVolatileMember - returns true if aggregate type has a volatile
+ /// member.
+ bool hasVolatileMember(QualType T) {
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ const RecordDecl *RD = cast<RecordDecl>(RT->getDecl());
+ return RD->hasVolatileMember();
+ }
+ return false;
+ }
+ /// EmitAggregateCopy - Emit an aggregate assignment.
///
/// The difference to EmitAggregateCopy is that tail padding is not copied.
/// This is required for correctness when assigning non-POD structures in C++.
void EmitAggregateAssign(llvm::Value *DestPtr, llvm::Value *SrcPtr,
- QualType EltTy, bool isVolatile=false,
- CharUnits Alignment = CharUnits::Zero()) {
- EmitAggregateCopy(DestPtr, SrcPtr, EltTy, isVolatile, Alignment, true);
+ QualType EltTy) {
+ bool IsVolatile = hasVolatileMember(EltTy);
+ EmitAggregateCopy(DestPtr, SrcPtr, EltTy, IsVolatile, CharUnits::Zero(),
+ true);
}
- /// EmitAggregateCopy - Emit an aggrate copy.
+ /// EmitAggregateCopy - Emit an aggregate copy.
///
/// \param isVolatile - True iff either the source or the destination is
/// volatile.
@@ -1687,11 +1748,6 @@ public:
/// then reuse it.
void StartBlock(const char *N);
- /// GetAddrOfStaticLocalVar - Return the address of a static local variable.
- llvm::Constant *GetAddrOfStaticLocalVar(const VarDecl *BVD) {
- return cast<llvm::Constant>(GetAddrOfLocalVar(BVD));
- }
-
/// GetAddrOfLocalVar - Return the address of a local variable.
llvm::Value *GetAddrOfLocalVar(const VarDecl *VD) {
llvm::Value *Res = LocalDeclMap[VD];
@@ -1767,9 +1823,19 @@ public:
/// LoadCXXVTT - Load the VTT parameter to base constructors/destructors have
/// virtual bases.
+ // FIXME: Every place that calls LoadCXXVTT is something
+ // that needs to be abstracted properly.
llvm::Value *LoadCXXVTT() {
- assert(CXXVTTValue && "no VTT value for this function");
- return CXXVTTValue;
+ assert(CXXStructorImplicitParamValue && "no VTT value for this function");
+ return CXXStructorImplicitParamValue;
+ }
+
+ /// LoadCXXStructorImplicitParam - Load the implicit parameter
+ /// for a constructor/destructor.
+ llvm::Value *LoadCXXStructorImplicitParam() {
+ assert(CXXStructorImplicitParamValue &&
+ "no implicit argument value for this function");
+ return CXXStructorImplicitParamValue;
}
/// GetAddressOfBaseOfCompleteClass - Convert the given pointer to a
@@ -1798,6 +1864,13 @@ public:
const CXXRecordDecl *ClassDecl,
const CXXRecordDecl *BaseClassDecl);
+ /// GetVTTParameter - Return the VTT parameter that should be passed to a
+ /// base constructor/destructor with virtual bases.
+ /// FIXME: VTTs are Itanium ABI-specific, so the definition should move
+ /// to ItaniumCXXABI.cpp together with all the references to VTT.
+ llvm::Value *GetVTTParameter(GlobalDecl GD, bool ForVirtualBase,
+ bool Delegating);
+
void EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
CXXCtorType CtorType,
const FunctionArgList &Args);
@@ -1808,7 +1881,8 @@ public:
void EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor,
const FunctionArgList &Args);
void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type,
- bool ForVirtualBase, llvm::Value *This,
+ bool ForVirtualBase, bool Delegating,
+ llvm::Value *This,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd);
@@ -1834,7 +1908,8 @@ public:
static Destroyer destroyCXXObject;
void EmitCXXDestructorCall(const CXXDestructorDecl *D, CXXDtorType Type,
- bool ForVirtualBase, llvm::Value *This);
+ bool ForVirtualBase, bool Delegating,
+ llvm::Value *This);
void EmitNewArrayInitializer(const CXXNewExpr *E, QualType elementType,
llvm::Value *NewPtr, llvm::Value *NumElements);
@@ -1874,7 +1949,13 @@ public:
/// Must be an object within its lifetime.
TCK_MemberCall,
/// Checking the 'this' pointer for a constructor call.
- TCK_ConstructorCall
+ TCK_ConstructorCall,
+ /// Checking the operand of a static_cast to a derived pointer type. Must be
+ /// null or an object within its lifetime.
+ TCK_DowncastPointer,
+ /// Checking the operand of a static_cast to a derived reference type. Must
+ /// be an object within its lifetime.
+ TCK_DowncastReference
};
/// \brief Emit a check that \p V is the address of storage of the
@@ -1882,6 +1963,12 @@ public:
void EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, llvm::Value *V,
QualType Type, CharUnits Alignment = CharUnits::Zero());
+ /// \brief Emit a check that \p Base points into an array object, which
+ /// we can access at index \p Index. \p Accessed should be \c false if we
+ /// this expression is used as an lvalue, for instance in "&Arr[Idx]".
+ void EmitBoundsCheck(const Expr *E, const Expr *Base, llvm::Value *Index,
+ QualType IndexType, bool Accessed);
+
llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
bool isInc, bool isPre);
ComplexPairTy EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV,
@@ -1933,18 +2020,34 @@ public:
/// initializer.
bool IsConstantAggregate;
+ /// Non-null if we should use lifetime annotations.
+ llvm::Value *SizeForLifetimeMarkers;
+
struct Invalid {};
AutoVarEmission(Invalid) : Variable(0) {}
AutoVarEmission(const VarDecl &variable)
: Variable(&variable), Address(0), NRVOFlag(0),
- IsByRef(false), IsConstantAggregate(false) {}
+ IsByRef(false), IsConstantAggregate(false),
+ SizeForLifetimeMarkers(0) {}
bool wasEmittedAsGlobal() const { return Address == 0; }
public:
static AutoVarEmission invalid() { return AutoVarEmission(Invalid()); }
+ bool useLifetimeMarkers() const { return SizeForLifetimeMarkers != 0; }
+ llvm::Value *getSizeForLifetimeMarkers() const {
+ assert(useLifetimeMarkers());
+ return SizeForLifetimeMarkers;
+ }
+
+ /// Returns the raw, allocated address, which is not necessarily
+ /// the address of the object itself.
+ llvm::Value *getAllocatedAddress() const {
+ return Address;
+ }
+
/// Returns the address of the object within this declaration.
/// Note that this does not chase the forwarding pointer for
/// __block decls.
@@ -2005,6 +2108,9 @@ public:
RValue EmitCompoundStmt(const CompoundStmt &S, bool GetLast = false,
AggValueSlot AVS = AggValueSlot::ignored());
+ RValue EmitCompoundStmtWithoutScope(const CompoundStmt &S,
+ bool GetLast = false, AggValueSlot AVS =
+ AggValueSlot::ignored());
/// EmitLabel - Emit the block for the given label. It is legal to call this
/// function even if there is no current insertion point.
@@ -2083,6 +2189,15 @@ public:
/// that the address will be used to access the object.
LValue EmitCheckedLValue(const Expr *E, TypeCheckKind TCK);
+ RValue convertTempToRValue(llvm::Value *addr, QualType type);
+
+ void EmitAtomicInit(Expr *E, LValue lvalue);
+
+ RValue EmitAtomicLoad(LValue lvalue,
+ AggValueSlot slot = AggValueSlot::ignored());
+
+ void EmitAtomicStore(RValue rvalue, LValue lvalue, bool isInit);
+
/// EmitToMemory - Change a scalar value from its value
/// representation to its in-memory representation.
llvm::Value *EmitToMemory(llvm::Value *Value, QualType Ty);
@@ -2096,7 +2211,9 @@ public:
/// the LLVM value representation.
llvm::Value *EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
unsigned Alignment, QualType Ty,
- llvm::MDNode *TBAAInfo = 0);
+ llvm::MDNode *TBAAInfo = 0,
+ QualType TBAABaseTy = QualType(),
+ uint64_t TBAAOffset = 0);
/// EmitLoadOfScalar - Load a scalar value from an address, taking
/// care to appropriately convert from the memory representation to
@@ -2109,7 +2226,9 @@ public:
/// the LLVM value representation.
void EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr,
bool Volatile, unsigned Alignment, QualType Ty,
- llvm::MDNode *TBAAInfo = 0, bool isInit=false);
+ llvm::MDNode *TBAAInfo = 0, bool isInit = false,
+ QualType TBAABaseTy = QualType(),
+ uint64_t TBAAOffset = 0);
/// EmitStoreOfScalar - Store a scalar value to an address, taking
/// care to appropriately convert from the memory representation to
@@ -2156,7 +2275,8 @@ public:
LValue EmitObjCEncodeExprLValue(const ObjCEncodeExpr *E);
LValue EmitPredefinedLValue(const PredefinedExpr *E);
LValue EmitUnaryOpLValue(const UnaryOperator *E);
- LValue EmitArraySubscriptExpr(const ArraySubscriptExpr *E);
+ LValue EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
+ bool Accessed = false);
LValue EmitExtVectorElementExpr(const ExtVectorElementExpr *E);
LValue EmitMemberExpr(const MemberExpr *E);
LValue EmitObjCIsaExpr(const ObjCIsaExpr *E);
@@ -2256,11 +2376,29 @@ public:
RValue EmitCallExpr(const CallExpr *E,
ReturnValueSlot ReturnValue = ReturnValueSlot());
+ llvm::CallInst *EmitRuntimeCall(llvm::Value *callee,
+ const Twine &name = "");
+ llvm::CallInst *EmitRuntimeCall(llvm::Value *callee,
+ ArrayRef<llvm::Value*> args,
+ const Twine &name = "");
+ llvm::CallInst *EmitNounwindRuntimeCall(llvm::Value *callee,
+ const Twine &name = "");
+ llvm::CallInst *EmitNounwindRuntimeCall(llvm::Value *callee,
+ ArrayRef<llvm::Value*> args,
+ const Twine &name = "");
+
llvm::CallSite EmitCallOrInvoke(llvm::Value *Callee,
ArrayRef<llvm::Value *> Args,
const Twine &Name = "");
llvm::CallSite EmitCallOrInvoke(llvm::Value *Callee,
const Twine &Name = "");
+ llvm::CallSite EmitRuntimeCallOrInvoke(llvm::Value *callee,
+ ArrayRef<llvm::Value*> args,
+ const Twine &name = "");
+ llvm::CallSite EmitRuntimeCallOrInvoke(llvm::Value *callee,
+ const Twine &name = "");
+ void EmitNoreturnRuntimeCallOrInvoke(llvm::Value *callee,
+ ArrayRef<llvm::Value*> args);
llvm::Value *BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This,
llvm::Type *Ty);
@@ -2279,7 +2417,8 @@ public:
llvm::Value *Callee,
ReturnValueSlot ReturnValue,
llvm::Value *This,
- llvm::Value *VTT,
+ llvm::Value *ImplicitParam,
+ QualType ImplicitParamTy,
CallExpr::const_arg_iterator ArgBeg,
CallExpr::const_arg_iterator ArgEnd);
RValue EmitCXXMemberCallExpr(const CXXMemberCallExpr *E,
@@ -2350,14 +2489,14 @@ public:
llvm::Value *EmitARCRetainAutorelease(QualType type, llvm::Value *value);
llvm::Value *EmitARCRetainAutoreleaseNonBlock(llvm::Value *value);
llvm::Value *EmitARCStoreStrong(LValue lvalue, llvm::Value *value,
- bool ignored);
+ bool resultIgnored);
llvm::Value *EmitARCStoreStrongCall(llvm::Value *addr, llvm::Value *value,
- bool ignored);
+ bool resultIgnored);
llvm::Value *EmitARCRetain(QualType type, llvm::Value *value);
llvm::Value *EmitARCRetainNonBlock(llvm::Value *value);
llvm::Value *EmitARCRetainBlock(llvm::Value *value, bool mandatory);
- void EmitARCDestroyStrong(llvm::Value *addr, bool precise);
- void EmitARCRelease(llvm::Value *value, bool precise);
+ void EmitARCDestroyStrong(llvm::Value *addr, ARCPreciseLifetime_t precise);
+ void EmitARCRelease(llvm::Value *value, ARCPreciseLifetime_t precise);
llvm::Value *EmitARCAutorelease(llvm::Value *value);
llvm::Value *EmitARCAutoreleaseReturnValue(llvm::Value *value);
llvm::Value *EmitARCRetainAutoreleaseReturnValue(llvm::Value *value);
@@ -2378,6 +2517,8 @@ public:
llvm::Value *EmitARCRetainScalarExpr(const Expr *expr);
llvm::Value *EmitARCRetainAutoreleaseScalarExpr(const Expr *expr);
+ void EmitARCIntrinsicUse(llvm::ArrayRef<llvm::Value*> values);
+
static Destroyer destroyARCStrongImprecise;
static Destroyer destroyARCStrongPrecise;
static Destroyer destroyARCWeak;
@@ -2439,16 +2580,15 @@ public:
bool IgnoreReal = false,
bool IgnoreImag = false);
- /// EmitComplexExprIntoAddr - Emit the computation of the specified expression
- /// of complex type, storing into the specified Value*.
- void EmitComplexExprIntoAddr(const Expr *E, llvm::Value *DestAddr,
- bool DestIsVolatile);
+ /// EmitComplexExprIntoLValue - Emit the given expression of complex
+ /// type and place its result into the specified l-value.
+ void EmitComplexExprIntoLValue(const Expr *E, LValue dest, bool isInit);
+
+ /// EmitStoreOfComplex - Store a complex number into the specified l-value.
+ void EmitStoreOfComplex(ComplexPairTy V, LValue dest, bool isInit);
- /// StoreComplexToAddr - Store a complex number into the specified address.
- void StoreComplexToAddr(ComplexPairTy V, llvm::Value *DestAddr,
- bool DestIsVolatile);
- /// LoadComplexFromAddr - Load a complex number from the specified address.
- ComplexPairTy LoadComplexFromAddr(llvm::Value *SrcAddr, bool SrcIsVolatile);
+ /// EmitLoadOfComplex - Load a complex number from the specified l-value.
+ ComplexPairTy EmitLoadOfComplex(LValue src);
/// CreateStaticVarDecl - Create a zero-initialized LLVM global for
/// a static local variable.
@@ -2523,7 +2663,7 @@ public:
/// Emit an annotation call (intrinsic or builtin).
llvm::Value *EmitAnnotationCall(llvm::Value *AnnotationFn,
llvm::Value *AnnotatedVal,
- llvm::StringRef AnnotationStr,
+ StringRef AnnotationStr,
SourceLocation Location);
/// Emit local annotations for the local variable V, declared by D.
@@ -2575,17 +2715,27 @@ public:
/// passing to a runtime sanitizer handler.
llvm::Constant *EmitCheckSourceLocation(SourceLocation Loc);
+ /// \brief Specify under what conditions this check can be recovered
+ enum CheckRecoverableKind {
+ /// Always terminate program execution if this check fails
+ CRK_Unrecoverable,
+ /// Check supports recovering, allows user to specify which
+ CRK_Recoverable,
+ /// Runtime conditionally aborts, always need to support recovery.
+ CRK_AlwaysRecoverable
+ };
+
/// \brief Create a basic block that will call a handler function in a
/// sanitizer runtime with the provided arguments, and create a conditional
/// branch to it.
void EmitCheck(llvm::Value *Checked, StringRef CheckName,
- llvm::ArrayRef<llvm::Constant *> StaticArgs,
- llvm::ArrayRef<llvm::Value *> DynamicArgs,
- bool Recoverable = false);
+ ArrayRef<llvm::Constant *> StaticArgs,
+ ArrayRef<llvm::Value *> DynamicArgs,
+ CheckRecoverableKind Recoverable);
/// \brief Create a basic block that will call the trap intrinsic, and emit a
/// conditional branch to it, for the -ftrapv checks.
- void EmitTrapvCheck(llvm::Value *Checked);
+ void EmitTrapCheck(llvm::Value *Checked);
/// EmitCallArg - Emit a single call argument.
void EmitCallArg(CallArgList &args, const Expr *E, QualType ArgType);
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 17972e2..c518a55 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -12,49 +12,57 @@
//===----------------------------------------------------------------------===//
#include "CodeGenModule.h"
-#include "CGDebugInfo.h"
-#include "CodeGenFunction.h"
-#include "CodeGenTBAA.h"
-#include "CGCall.h"
#include "CGCUDARuntime.h"
#include "CGCXXABI.h"
+#include "CGCall.h"
+#include "CGDebugInfo.h"
#include "CGObjCRuntime.h"
#include "CGOpenCLRuntime.h"
+#include "CodeGenFunction.h"
+#include "CodeGenTBAA.h"
#include "TargetInfo.h"
-#include "clang/Frontend/CodeGenOptions.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
-#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/Builtins.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/Module.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/Basic/ConvertUTF.h"
-#include "llvm/CallingConv.h"
-#include "llvm/Module.h"
-#include "llvm/Intrinsics.h"
-#include "llvm/LLVMContext.h"
+#include "clang/Basic/TargetOptions.h"
+#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/Triple.h"
-#include "llvm/Target/Mangler.h"
-#include "llvm/DataLayout.h"
+#include "llvm/IR/CallingConv.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
#include "llvm/Support/CallSite.h"
+#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Target/Mangler.h"
+
using namespace clang;
using namespace CodeGen;
static const char AnnotationSection[] = "llvm.metadata";
static CGCXXABI &createCXXABI(CodeGenModule &CGM) {
- switch (CGM.getContext().getTargetInfo().getCXXABI()) {
- case CXXABI_ARM: return *CreateARMCXXABI(CGM);
- case CXXABI_Itanium: return *CreateItaniumCXXABI(CGM);
- case CXXABI_Microsoft: return *CreateMicrosoftCXXABI(CGM);
+ switch (CGM.getContext().getTargetInfo().getCXXABI().getKind()) {
+ case TargetCXXABI::GenericAArch64:
+ case TargetCXXABI::GenericARM:
+ case TargetCXXABI::iOS:
+ case TargetCXXABI::GenericItanium:
+ return *CreateItaniumCXXABI(CGM);
+ case TargetCXXABI::Microsoft:
+ return *CreateMicrosoftCXXABI(CGM);
}
llvm_unreachable("invalid C++ ABI kind");
@@ -62,10 +70,11 @@ static CGCXXABI &createCXXABI(CodeGenModule &CGM) {
CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
- llvm::Module &M, const llvm::DataLayout &TD,
+ const TargetOptions &TO, llvm::Module &M,
+ const llvm::DataLayout &TD,
DiagnosticsEngine &diags)
- : Context(C), LangOpts(C.getLangOpts()), CodeGenOpts(CGO), TheModule(M),
- TheDataLayout(TD), TheTargetCodeGenInfo(0), Diags(diags),
+ : Context(C), LangOpts(C.getLangOpts()), CodeGenOpts(CGO), TargetOpts(TO),
+ TheModule(M), TheDataLayout(TD), TheTargetCodeGenInfo(0), Diags(diags),
ABI(createCXXABI(*this)),
Types(*this),
TBAA(0),
@@ -76,8 +85,12 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
VMContext(M.getContext()),
NSConcreteGlobalBlock(0), NSConcreteStackBlock(0),
BlockObjectAssign(0), BlockObjectDispose(0),
- BlockDescriptorType(0), GenericBlockLiteralType(0) {
-
+ BlockDescriptorType(0), GenericBlockLiteralType(0),
+ LifetimeStartFn(0), LifetimeEndFn(0),
+ SanitizerBlacklist(CGO.SanitizerBlacklistFile),
+ SanOpts(SanitizerBlacklist.isIn(M) ?
+ SanitizerOptions::Disabled : LangOpts.Sanitize) {
+
// Initialize the type cache.
llvm::LLVMContext &LLVMContext = M.getContext();
VoidTy = llvm::Type::getVoidTy(LLVMContext);
@@ -95,6 +108,8 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
Int8PtrTy = Int8Ty->getPointerTo(0);
Int8PtrPtrTy = Int8PtrTy->getPointerTo(0);
+ RuntimeCC = getTargetCodeGenInfo().getABIInfo().getRuntimeCC();
+
if (LangOpts.ObjC1)
createObjCRuntime();
if (LangOpts.OpenCL)
@@ -103,7 +118,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
createCUDARuntime();
// Enable TBAA unless it's suppressed. ThreadSanitizer needs TBAA even at O0.
- if (LangOpts.SanitizeThread ||
+ if (SanOpts.Thread ||
(!CodeGenOpts.RelaxedAliasing && CodeGenOpts.OptimizationLevel > 0))
TBAA = new CodeGenTBAA(Context, VMContext, CodeGenOpts, getLangOpts(),
ABI.getMangleContext());
@@ -173,6 +188,10 @@ void CodeGenModule::Release() {
EmitGlobalAnnotations();
EmitLLVMUsed();
+ if (CodeGenOpts.ModulesAutolink) {
+ EmitModuleLinkOptions();
+ }
+
SimplifyPersonality();
if (getCodeGenOpts().EmitDeclMetadata)
@@ -208,6 +227,20 @@ llvm::MDNode *CodeGenModule::getTBAAStructInfo(QualType QTy) {
return TBAA->getTBAAStructInfo(QTy);
}
+llvm::MDNode *CodeGenModule::getTBAAStructTypeInfo(QualType QTy) {
+ if (!TBAA)
+ return 0;
+ return TBAA->getTBAAStructTypeInfo(QTy);
+}
+
+llvm::MDNode *CodeGenModule::getTBAAStructTagInfo(QualType BaseTy,
+ llvm::MDNode *AccessN,
+ uint64_t O) {
+ if (!TBAA)
+ return 0;
+ return TBAA->getTBAAStructTagInfo(BaseTy, AccessN, O);
+}
+
void CodeGenModule::DecorateInstruction(llvm::Instruction *Inst,
llvm::MDNode *TBAAInfo) {
Inst->setMetadata(llvm::LLVMContext::MD_tbaa, TBAAInfo);
@@ -260,9 +293,9 @@ void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV,
}
// Set visibility for definitions.
- NamedDecl::LinkageInfo LV = D->getLinkageAndVisibility();
- if (LV.visibilityExplicit() || !GV->hasAvailableExternallyLinkage())
- GV->setVisibility(GetLLVMVisibility(LV.visibility()));
+ LinkageInfo LV = D->getLinkageAndVisibility();
+ if (LV.isVisibilityExplicit() || !GV->hasAvailableExternallyLinkage())
+ GV->setVisibility(GetLLVMVisibility(LV.getVisibility()));
}
static llvm::GlobalVariable::ThreadLocalMode GetLLVMTLSModel(StringRef S) {
@@ -331,7 +364,7 @@ void CodeGenModule::setTypeVisibility(llvm::GlobalValue *GV,
return;
// Don't override an explicit visibility attribute.
- if (RD->getExplicitVisibility())
+ if (RD->getExplicitVisibility(NamedDecl::VisibilityForType))
return;
switch (RD->getTemplateSpecializationKind()) {
@@ -360,7 +393,9 @@ void CodeGenModule::setTypeVisibility(llvm::GlobalValue *GV,
// that don't have the key function's definition. But ignore
// this if we're emitting RTTI under -fno-rtti.
if (!(TVK != TVK_ForRTTI) || LangOpts.RTTI) {
- if (Context.getKeyFunction(RD))
+ // FIXME: what should we do if we "lose" the key function during
+ // the emission of the file?
+ if (Context.getCurrentKeyFunction(RD))
return;
}
@@ -532,8 +567,8 @@ void CodeGenModule::SetLLVMFunctionAttributes(const Decl *D,
llvm::Function *F) {
unsigned CallingConv;
AttributeListType AttributeList;
- ConstructAttributeList(Info, D, AttributeList, CallingConv);
- F->setAttributes(llvm::AttrListPtr::get(getLLVMContext(), AttributeList));
+ ConstructAttributeList(Info, D, AttributeList, CallingConv, false);
+ F->setAttributes(llvm::AttributeSet::get(getLLVMContext(), AttributeList));
F->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
}
@@ -563,28 +598,29 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
F->setHasUWTable();
if (!hasUnwindExceptions(LangOpts))
- F->addFnAttr(llvm::Attributes::NoUnwind);
+ F->addFnAttr(llvm::Attribute::NoUnwind);
if (D->hasAttr<NakedAttr>()) {
// Naked implies noinline: we should not be inlining such functions.
- F->addFnAttr(llvm::Attributes::Naked);
- F->addFnAttr(llvm::Attributes::NoInline);
+ F->addFnAttr(llvm::Attribute::Naked);
+ F->addFnAttr(llvm::Attribute::NoInline);
}
if (D->hasAttr<NoInlineAttr>())
- F->addFnAttr(llvm::Attributes::NoInline);
+ F->addFnAttr(llvm::Attribute::NoInline);
// (noinline wins over always_inline, and we can't specify both in IR)
if ((D->hasAttr<AlwaysInlineAttr>() || D->hasAttr<ForceInlineAttr>()) &&
- !F->getFnAttributes().hasAttribute(llvm::Attributes::NoInline))
- F->addFnAttr(llvm::Attributes::AlwaysInline);
+ !F->getAttributes().hasAttribute(llvm::AttributeSet::FunctionIndex,
+ llvm::Attribute::NoInline))
+ F->addFnAttr(llvm::Attribute::AlwaysInline);
// FIXME: Communicate hot and cold attributes to LLVM more directly.
if (D->hasAttr<ColdAttr>())
- F->addFnAttr(llvm::Attributes::OptimizeForSize);
+ F->addFnAttr(llvm::Attribute::OptimizeForSize);
if (D->hasAttr<MinSizeAttr>())
- F->addFnAttr(llvm::Attributes::MinSize);
+ F->addFnAttr(llvm::Attribute::MinSize);
if (isa<CXXConstructorDecl>(D) || isa<CXXDestructorDecl>(D))
F->setUnnamedAddr(true);
@@ -594,15 +630,23 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
F->setUnnamedAddr(true);
if (LangOpts.getStackProtector() == LangOptions::SSPOn)
- F->addFnAttr(llvm::Attributes::StackProtect);
+ F->addFnAttr(llvm::Attribute::StackProtect);
else if (LangOpts.getStackProtector() == LangOptions::SSPReq)
- F->addFnAttr(llvm::Attributes::StackProtectReq);
-
- if (LangOpts.SanitizeAddress) {
- // When AddressSanitizer is enabled, set AddressSafety attribute
- // unless __attribute__((no_address_safety_analysis)) is used.
- if (!D->hasAttr<NoAddressSafetyAnalysisAttr>())
- F->addFnAttr(llvm::Attributes::AddressSafety);
+ F->addFnAttr(llvm::Attribute::StackProtectReq);
+
+ // Add sanitizer attributes if function is not blacklisted.
+ if (!SanitizerBlacklist.isIn(*F)) {
+ // When AddressSanitizer is enabled, set SanitizeAddress attribute
+ // unless __attribute__((no_sanitize_address)) is used.
+ if (SanOpts.Address && !D->hasAttr<NoSanitizeAddressAttr>())
+ F->addFnAttr(llvm::Attribute::SanitizeAddress);
+ // Same for ThreadSanitizer and __attribute__((no_sanitize_thread))
+ if (SanOpts.Thread && !D->hasAttr<NoSanitizeThreadAttr>()) {
+ F->addFnAttr(llvm::Attribute::SanitizeThread);
+ }
+ // Same for MemorySanitizer and __attribute__((no_sanitize_memory))
+ if (SanOpts.Memory && !D->hasAttr<NoSanitizeMemoryAttr>())
+ F->addFnAttr(llvm::Attribute::SanitizeMemory);
}
unsigned alignment = D->getMaxAlignment() / Context.getCharWidth();
@@ -627,7 +671,9 @@ void CodeGenModule::SetCommonAttributes(const Decl *D,
if (const SectionAttr *SA = D->getAttr<SectionAttr>())
GV->setSection(SA->getName());
- getTargetCodeGenInfo().SetTargetAttributes(D, GV, *this);
+ // Alias cannot have attributes. Filter them here.
+ if (!isa<llvm::GlobalAlias>(GV))
+ getTargetCodeGenInfo().SetTargetAttributes(D, GV, *this);
}
void CodeGenModule::SetInternalFunctionAttributes(const Decl *D,
@@ -670,9 +716,9 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD,
} else {
F->setLinkage(llvm::Function::ExternalLinkage);
- NamedDecl::LinkageInfo LV = FD->getLinkageAndVisibility();
- if (LV.linkage() == ExternalLinkage && LV.visibilityExplicit()) {
- F->setVisibility(GetLLVMVisibility(LV.visibility()));
+ LinkageInfo LV = FD->getLinkageAndVisibility();
+ if (LV.getLinkage() == ExternalLinkage && LV.isVisibilityExplicit()) {
+ F->setVisibility(GetLLVMVisibility(LV.getVisibility()));
}
}
@@ -713,19 +759,130 @@ void CodeGenModule::EmitLLVMUsed() {
GV->setSection("llvm.metadata");
}
+/// \brief Add link options implied by the given module, including modules
+/// it depends on, using a postorder walk.
+static void addLinkOptionsPostorder(llvm::LLVMContext &Context,
+ Module *Mod,
+ SmallVectorImpl<llvm::Value *> &Metadata,
+ llvm::SmallPtrSet<Module *, 16> &Visited) {
+ // Import this module's parent.
+ if (Mod->Parent && Visited.insert(Mod->Parent)) {
+ addLinkOptionsPostorder(Context, Mod->Parent, Metadata, Visited);
+ }
+
+ // Import this module's dependencies.
+ for (unsigned I = Mod->Imports.size(); I > 0; --I) {
+ if (Visited.insert(Mod->Imports[I-1]))
+ addLinkOptionsPostorder(Context, Mod->Imports[I-1], Metadata, Visited);
+ }
+
+ // Add linker options to link against the libraries/frameworks
+ // described by this module.
+ for (unsigned I = Mod->LinkLibraries.size(); I > 0; --I) {
+ // FIXME: -lfoo is Unix-centric and -framework Foo is Darwin-centric.
+ // We need to know more about the linker to know how to encode these
+ // options propertly.
+
+ // Link against a framework.
+ if (Mod->LinkLibraries[I-1].IsFramework) {
+ llvm::Value *Args[2] = {
+ llvm::MDString::get(Context, "-framework"),
+ llvm::MDString::get(Context, Mod->LinkLibraries[I-1].Library)
+ };
+
+ Metadata.push_back(llvm::MDNode::get(Context, Args));
+ continue;
+ }
+
+ // Link against a library.
+ llvm::Value *OptString
+ = llvm::MDString::get(Context,
+ "-l" + Mod->LinkLibraries[I-1].Library);
+ Metadata.push_back(llvm::MDNode::get(Context, OptString));
+ }
+}
+
+void CodeGenModule::EmitModuleLinkOptions() {
+ // Collect the set of all of the modules we want to visit to emit link
+ // options, which is essentially the imported modules and all of their
+ // non-explicit child modules.
+ llvm::SetVector<clang::Module *> LinkModules;
+ llvm::SmallPtrSet<clang::Module *, 16> Visited;
+ SmallVector<clang::Module *, 16> Stack;
+
+ // Seed the stack with imported modules.
+ for (llvm::SetVector<clang::Module *>::iterator M = ImportedModules.begin(),
+ MEnd = ImportedModules.end();
+ M != MEnd; ++M) {
+ if (Visited.insert(*M))
+ Stack.push_back(*M);
+ }
+
+ // Find all of the modules to import, making a little effort to prune
+ // non-leaf modules.
+ while (!Stack.empty()) {
+ clang::Module *Mod = Stack.back();
+ Stack.pop_back();
+
+ bool AnyChildren = false;
+
+ // Visit the submodules of this module.
+ for (clang::Module::submodule_iterator Sub = Mod->submodule_begin(),
+ SubEnd = Mod->submodule_end();
+ Sub != SubEnd; ++Sub) {
+ // Skip explicit children; they need to be explicitly imported to be
+ // linked against.
+ if ((*Sub)->IsExplicit)
+ continue;
+
+ if (Visited.insert(*Sub)) {
+ Stack.push_back(*Sub);
+ AnyChildren = true;
+ }
+ }
+
+ // We didn't find any children, so add this module to the list of
+ // modules to link against.
+ if (!AnyChildren) {
+ LinkModules.insert(Mod);
+ }
+ }
+
+ // Add link options for all of the imported modules in reverse topological
+ // order.
+ SmallVector<llvm::Value *, 16> MetadataArgs;
+ Visited.clear();
+ for (llvm::SetVector<clang::Module *>::iterator M = LinkModules.begin(),
+ MEnd = LinkModules.end();
+ M != MEnd; ++M) {
+ if (Visited.insert(*M))
+ addLinkOptionsPostorder(getLLVMContext(), *M, MetadataArgs, Visited);
+ }
+ std::reverse(MetadataArgs.begin(), MetadataArgs.end());
+
+ // Add the linker options metadata flag.
+ getModule().addModuleFlag(llvm::Module::AppendUnique, "Linker Options",
+ llvm::MDNode::get(getLLVMContext(), MetadataArgs));
+}
+
void CodeGenModule::EmitDeferred() {
// Emit code for any potentially referenced deferred decls. Since a
// previously unused static decl may become used during the generation of code
// for a static function, iterate until no changes are made.
- while (!DeferredDeclsToEmit.empty() || !DeferredVTables.empty()) {
+ while (true) {
if (!DeferredVTables.empty()) {
- const CXXRecordDecl *RD = DeferredVTables.back();
- DeferredVTables.pop_back();
- getCXXABI().EmitVTables(RD);
- continue;
+ EmitDeferredVTables();
+
+ // Emitting a v-table doesn't directly cause more v-tables to
+ // become deferred, although it can cause functions to be
+ // emitted that then need those v-tables.
+ assert(DeferredVTables.empty());
}
+ // Stop if we're out of both deferred v-tables and deferred declarations.
+ if (DeferredDeclsToEmit.empty()) break;
+
GlobalDecl D = DeferredDeclsToEmit.back();
DeferredDeclsToEmit.pop_back();
@@ -767,7 +924,7 @@ void CodeGenModule::EmitGlobalAnnotations() {
gv->setSection(AnnotationSection);
}
-llvm::Constant *CodeGenModule::EmitAnnotationString(llvm::StringRef Str) {
+llvm::Constant *CodeGenModule::EmitAnnotationString(StringRef Str) {
llvm::StringMap<llvm::Constant*>::iterator i = AnnotationStrings.find(Str);
if (i != AnnotationStrings.end())
return i->second;
@@ -1106,7 +1263,7 @@ llvm::Constant *
CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
llvm::Type *Ty,
GlobalDecl D, bool ForVTable,
- llvm::Attributes ExtraAttrs) {
+ llvm::AttributeSet ExtraAttrs) {
// Lookup the entry, lazily creating it if necessary.
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
if (Entry) {
@@ -1142,8 +1299,13 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName,
assert(F->getName() == MangledName && "name was uniqued!");
if (D.getDecl())
SetFunctionAttributes(D, F, IsIncompleteFunction);
- if (ExtraAttrs.hasAttributes())
- F->addAttribute(llvm::AttrListPtr::FunctionIndex, ExtraAttrs);
+ if (ExtraAttrs.hasAttributes(llvm::AttributeSet::FunctionIndex)) {
+ llvm::AttrBuilder B(ExtraAttrs, llvm::AttributeSet::FunctionIndex);
+ F->addAttributes(llvm::AttributeSet::FunctionIndex,
+ llvm::AttributeSet::get(VMContext,
+ llvm::AttributeSet::FunctionIndex,
+ B));
+ }
// This is the first use or definition of a mangled name. If there is a
// deferred decl with this name, remember that we need to emit it at the end
@@ -1214,9 +1376,14 @@ llvm::Constant *CodeGenModule::GetAddrOfFunction(GlobalDecl GD,
llvm::Constant *
CodeGenModule::CreateRuntimeFunction(llvm::FunctionType *FTy,
StringRef Name,
- llvm::Attributes ExtraAttrs) {
- return GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false,
- ExtraAttrs);
+ llvm::AttributeSet ExtraAttrs) {
+ llvm::Constant *C
+ = GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false,
+ ExtraAttrs);
+ if (llvm::Function *F = dyn_cast<llvm::Function>(C))
+ if (F->empty())
+ F->setCallingConv(getRuntimeCC());
+ return C;
}
/// isTypeConstant - Determine whether an object of this type can be emitted
@@ -1294,8 +1461,8 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
GV->setConstant(isTypeConstant(D->getType(), false));
// Set linkage and visibility in case we never see a definition.
- NamedDecl::LinkageInfo LV = D->getLinkageAndVisibility();
- if (LV.linkage() != ExternalLinkage) {
+ LinkageInfo LV = D->getLinkageAndVisibility();
+ if (LV.getLinkage() != ExternalLinkage) {
// Don't set internal linkage on declarations.
} else {
if (D->hasAttr<DLLImportAttr>())
@@ -1304,8 +1471,8 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
GV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
// Set visibility on a declaration only if it's explicit.
- if (LV.visibilityExplicit())
- GV->setVisibility(GetLLVMVisibility(LV.visibility()));
+ if (LV.isVisibilityExplicit())
+ GV->setVisibility(GetLLVMVisibility(LV.getVisibility()));
}
if (D->isThreadSpecified())
@@ -1403,80 +1570,6 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) {
EmitGlobalVarDefinition(D);
}
-void CodeGenModule::EmitVTable(CXXRecordDecl *Class, bool DefinitionRequired) {
- if (DefinitionRequired)
- getCXXABI().EmitVTables(Class);
-}
-
-llvm::GlobalVariable::LinkageTypes
-CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
- if (RD->getLinkage() != ExternalLinkage)
- return llvm::GlobalVariable::InternalLinkage;
-
- if (const CXXMethodDecl *KeyFunction
- = RD->getASTContext().getKeyFunction(RD)) {
- // If this class has a key function, use that to determine the linkage of
- // the vtable.
- const FunctionDecl *Def = 0;
- if (KeyFunction->hasBody(Def))
- KeyFunction = cast<CXXMethodDecl>(Def);
-
- switch (KeyFunction->getTemplateSpecializationKind()) {
- case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
- // When compiling with optimizations turned on, we emit all vtables,
- // even if the key function is not defined in the current translation
- // unit. If this is the case, use available_externally linkage.
- if (!Def && CodeGenOpts.OptimizationLevel)
- return llvm::GlobalVariable::AvailableExternallyLinkage;
-
- if (KeyFunction->isInlined())
- return !Context.getLangOpts().AppleKext ?
- llvm::GlobalVariable::LinkOnceODRLinkage :
- llvm::Function::InternalLinkage;
-
- return llvm::GlobalVariable::ExternalLinkage;
-
- case TSK_ImplicitInstantiation:
- return !Context.getLangOpts().AppleKext ?
- llvm::GlobalVariable::LinkOnceODRLinkage :
- llvm::Function::InternalLinkage;
-
- case TSK_ExplicitInstantiationDefinition:
- return !Context.getLangOpts().AppleKext ?
- llvm::GlobalVariable::WeakODRLinkage :
- llvm::Function::InternalLinkage;
-
- case TSK_ExplicitInstantiationDeclaration:
- // FIXME: Use available_externally linkage. However, this currently
- // breaks LLVM's build due to undefined symbols.
- // return llvm::GlobalVariable::AvailableExternallyLinkage;
- return !Context.getLangOpts().AppleKext ?
- llvm::GlobalVariable::LinkOnceODRLinkage :
- llvm::Function::InternalLinkage;
- }
- }
-
- if (Context.getLangOpts().AppleKext)
- return llvm::Function::InternalLinkage;
-
- switch (RD->getTemplateSpecializationKind()) {
- case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
- case TSK_ImplicitInstantiation:
- // FIXME: Use available_externally linkage. However, this currently
- // breaks LLVM's build due to undefined symbols.
- // return llvm::GlobalVariable::AvailableExternallyLinkage;
- case TSK_ExplicitInstantiationDeclaration:
- return llvm::GlobalVariable::LinkOnceODRLinkage;
-
- case TSK_ExplicitInstantiationDefinition:
- return llvm::GlobalVariable::WeakODRLinkage;
- }
-
- llvm_unreachable("Invalid TemplateSpecializationKind!");
-}
-
CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const {
return Context.toCharUnitsFromBits(
TheDataLayout.getTypeStoreSizeInBits(Ty));
@@ -1523,7 +1616,7 @@ CodeGenModule::MaybeEmitGlobalStdInitializerListInitializer(const VarDecl *D,
D->getDeclContext()),
D->getLocStart(), D->getLocation(),
name, arrayType, sourceInfo,
- SC_Static, SC_Static);
+ SC_Static);
// Now clone the InitListExpr to initialize the array instead.
// Incredible hack: we want to use the existing InitListExpr here, so we need
@@ -1739,7 +1832,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
// If we are compiling with ASan, add metadata indicating dynamically
// initialized globals.
- if (LangOpts.SanitizeAddress && NeedsGlobalCtor) {
+ if (SanOpts.Address && NeedsGlobalCtor) {
llvm::Module &M = getModule();
llvm::NamedMDNode *DynamicInitializers =
@@ -1785,105 +1878,139 @@ CodeGenModule::GetLLVMLinkageVarDefinition(const VarDecl *D,
return llvm::GlobalVariable::ExternalLinkage;
}
-/// ReplaceUsesOfNonProtoTypeWithRealFunction - This function is called when we
-/// implement a function with no prototype, e.g. "int foo() {}". If there are
-/// existing call uses of the old function in the module, this adjusts them to
-/// call the new function directly.
-///
-/// This is not just a cleanup: the always_inline pass requires direct calls to
-/// functions to be able to inline them. If there is a bitcast in the way, it
-/// won't inline them. Instcombine normally deletes these calls, but it isn't
-/// run at -O0.
-static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
- llvm::Function *NewFn) {
- // If we're redefining a global as a function, don't transform it.
- llvm::Function *OldFn = dyn_cast<llvm::Function>(Old);
- if (OldFn == 0) return;
-
- llvm::Type *NewRetTy = NewFn->getReturnType();
- SmallVector<llvm::Value*, 4> ArgList;
-
- for (llvm::Value::use_iterator UI = OldFn->use_begin(), E = OldFn->use_end();
- UI != E; ) {
- // TODO: Do invokes ever occur in C code? If so, we should handle them too.
- llvm::Value::use_iterator I = UI++; // Increment before the CI is erased.
- llvm::CallInst *CI = dyn_cast<llvm::CallInst>(*I);
- if (!CI) continue; // FIXME: when we allow Invoke, just do CallSite CS(*I)
- llvm::CallSite CS(CI);
- if (!CI || !CS.isCallee(I)) continue;
-
- // If the return types don't match exactly, and if the call isn't dead, then
- // we can't transform this call.
- if (CI->getType() != NewRetTy && !CI->use_empty())
+/// Replace the uses of a function that was declared with a non-proto type.
+/// We want to silently drop extra arguments from call sites
+static void replaceUsesOfNonProtoConstant(llvm::Constant *old,
+ llvm::Function *newFn) {
+ // Fast path.
+ if (old->use_empty()) return;
+
+ llvm::Type *newRetTy = newFn->getReturnType();
+ SmallVector<llvm::Value*, 4> newArgs;
+
+ for (llvm::Value::use_iterator ui = old->use_begin(), ue = old->use_end();
+ ui != ue; ) {
+ llvm::Value::use_iterator use = ui++; // Increment before the use is erased.
+ llvm::User *user = *use;
+
+ // Recognize and replace uses of bitcasts. Most calls to
+ // unprototyped functions will use bitcasts.
+ if (llvm::ConstantExpr *bitcast = dyn_cast<llvm::ConstantExpr>(user)) {
+ if (bitcast->getOpcode() == llvm::Instruction::BitCast)
+ replaceUsesOfNonProtoConstant(bitcast, newFn);
+ continue;
+ }
+
+ // Recognize calls to the function.
+ llvm::CallSite callSite(user);
+ if (!callSite) continue;
+ if (!callSite.isCallee(use)) continue;
+
+ // If the return types don't match exactly, then we can't
+ // transform this call unless it's dead.
+ if (callSite->getType() != newRetTy && !callSite->use_empty())
continue;
- // Get the attribute list.
- llvm::SmallVector<llvm::AttributeWithIndex, 8> AttrVec;
- llvm::AttrListPtr AttrList = CI->getAttributes();
-
- // Get any return attributes.
- llvm::Attributes RAttrs = AttrList.getRetAttributes();
-
- // Add the return attributes.
- if (RAttrs.hasAttributes())
- AttrVec.push_back(llvm::
- AttributeWithIndex::get(llvm::AttrListPtr::ReturnIndex,
- RAttrs));
-
- // If the function was passed too few arguments, don't transform. If extra
- // arguments were passed, we silently drop them. If any of the types
- // mismatch, we don't transform.
- unsigned ArgNo = 0;
- bool DontTransform = false;
- for (llvm::Function::arg_iterator AI = NewFn->arg_begin(),
- E = NewFn->arg_end(); AI != E; ++AI, ++ArgNo) {
- if (CS.arg_size() == ArgNo ||
- CS.getArgument(ArgNo)->getType() != AI->getType()) {
- DontTransform = true;
+ // Get the call site's attribute list.
+ SmallVector<llvm::AttributeSet, 8> newAttrs;
+ llvm::AttributeSet oldAttrs = callSite.getAttributes();
+
+ // Collect any return attributes from the call.
+ if (oldAttrs.hasAttributes(llvm::AttributeSet::ReturnIndex))
+ newAttrs.push_back(
+ llvm::AttributeSet::get(newFn->getContext(),
+ oldAttrs.getRetAttributes()));
+
+ // If the function was passed too few arguments, don't transform.
+ unsigned newNumArgs = newFn->arg_size();
+ if (callSite.arg_size() < newNumArgs) continue;
+
+ // If extra arguments were passed, we silently drop them.
+ // If any of the types mismatch, we don't transform.
+ unsigned argNo = 0;
+ bool dontTransform = false;
+ for (llvm::Function::arg_iterator ai = newFn->arg_begin(),
+ ae = newFn->arg_end(); ai != ae; ++ai, ++argNo) {
+ if (callSite.getArgument(argNo)->getType() != ai->getType()) {
+ dontTransform = true;
break;
}
// Add any parameter attributes.
- llvm::Attributes PAttrs = AttrList.getParamAttributes(ArgNo + 1);
- if (PAttrs.hasAttributes())
- AttrVec.push_back(llvm::AttributeWithIndex::get(ArgNo + 1, PAttrs));
+ if (oldAttrs.hasAttributes(argNo + 1))
+ newAttrs.
+ push_back(llvm::
+ AttributeSet::get(newFn->getContext(),
+ oldAttrs.getParamAttributes(argNo + 1)));
}
- if (DontTransform)
+ if (dontTransform)
continue;
- llvm::Attributes FnAttrs = AttrList.getFnAttributes();
- if (FnAttrs.hasAttributes())
- AttrVec.push_back(llvm::
- AttributeWithIndex::get(llvm::AttrListPtr::FunctionIndex,
- FnAttrs));
+ if (oldAttrs.hasAttributes(llvm::AttributeSet::FunctionIndex))
+ newAttrs.push_back(llvm::AttributeSet::get(newFn->getContext(),
+ oldAttrs.getFnAttributes()));
// Okay, we can transform this. Create the new call instruction and copy
// over the required information.
- ArgList.append(CS.arg_begin(), CS.arg_begin() + ArgNo);
- llvm::CallInst *NewCall = llvm::CallInst::Create(NewFn, ArgList, "", CI);
- ArgList.clear();
- if (!NewCall->getType()->isVoidTy())
- NewCall->takeName(CI);
- NewCall->setAttributes(llvm::AttrListPtr::get(OldFn->getContext(), AttrVec));
- NewCall->setCallingConv(CI->getCallingConv());
+ newArgs.append(callSite.arg_begin(), callSite.arg_begin() + argNo);
+
+ llvm::CallSite newCall;
+ if (callSite.isCall()) {
+ newCall = llvm::CallInst::Create(newFn, newArgs, "",
+ callSite.getInstruction());
+ } else {
+ llvm::InvokeInst *oldInvoke =
+ cast<llvm::InvokeInst>(callSite.getInstruction());
+ newCall = llvm::InvokeInst::Create(newFn,
+ oldInvoke->getNormalDest(),
+ oldInvoke->getUnwindDest(),
+ newArgs, "",
+ callSite.getInstruction());
+ }
+ newArgs.clear(); // for the next iteration
+
+ if (!newCall->getType()->isVoidTy())
+ newCall->takeName(callSite.getInstruction());
+ newCall.setAttributes(
+ llvm::AttributeSet::get(newFn->getContext(), newAttrs));
+ newCall.setCallingConv(callSite.getCallingConv());
// Finally, remove the old call, replacing any uses with the new one.
- if (!CI->use_empty())
- CI->replaceAllUsesWith(NewCall);
+ if (!callSite->use_empty())
+ callSite->replaceAllUsesWith(newCall.getInstruction());
// Copy debug location attached to CI.
- if (!CI->getDebugLoc().isUnknown())
- NewCall->setDebugLoc(CI->getDebugLoc());
- CI->eraseFromParent();
+ if (!callSite->getDebugLoc().isUnknown())
+ newCall->setDebugLoc(callSite->getDebugLoc());
+ callSite->eraseFromParent();
}
}
+/// ReplaceUsesOfNonProtoTypeWithRealFunction - This function is called when we
+/// implement a function with no prototype, e.g. "int foo() {}". If there are
+/// existing call uses of the old function in the module, this adjusts them to
+/// call the new function directly.
+///
+/// This is not just a cleanup: the always_inline pass requires direct calls to
+/// functions to be able to inline them. If there is a bitcast in the way, it
+/// won't inline them. Instcombine normally deletes these calls, but it isn't
+/// run at -O0.
+static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
+ llvm::Function *NewFn) {
+ // If we're redefining a global as a function, don't transform it.
+ if (!isa<llvm::Function>(Old)) return;
+
+ replaceUsesOfNonProtoConstant(Old, NewFn);
+}
+
void CodeGenModule::HandleCXXStaticMemberVarInstantiation(VarDecl *VD) {
TemplateSpecializationKind TSK = VD->getTemplateSpecializationKind();
// If we have a definition, this might be a deferred decl. If the
// instantiation is explicit, make sure we emit it at the end.
if (VD->getDefinition() && TSK == TSK_ExplicitInstantiationDefinition)
GetAddrOfGlobalVar(VD);
+
+ EmitTopLevelDecl(VD);
}
void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) {
@@ -1921,10 +2048,14 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) {
OldFn->setName(StringRef());
llvm::Function *NewFn = cast<llvm::Function>(GetAddrOfFunction(GD, Ty));
- // If this is an implementation of a function without a prototype, try to
- // replace any existing uses of the function (which may be calls) with uses
- // of the new function
- if (D->getType()->isFunctionNoProtoType()) {
+ // This might be an implementation of a function without a
+ // prototype, in which case, try to do special replacement of
+ // calls which match the new prototype. The really key thing here
+ // is that we also potentially drop arguments from the call site
+ // so as to make a direct call, which makes the inliner happier
+ // and suppresses a number of optimizer warnings (!) about
+ // dropping arguments.
+ if (!OldFn->use_empty()) {
ReplaceUsesOfNonProtoTypeWithRealFunction(OldFn, NewFn);
OldFn->removeDeadConstantUsers();
}
@@ -2131,7 +2262,8 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
llvm::Constant *C = 0;
if (isUTF16) {
ArrayRef<uint16_t> Arr =
- llvm::makeArrayRef<uint16_t>((uint16_t*)Entry.getKey().data(),
+ llvm::makeArrayRef<uint16_t>(reinterpret_cast<uint16_t*>(
+ const_cast<char *>(Entry.getKey().data())),
Entry.getKey().size() / 2);
C = llvm::ConstantDataArray::get(VMContext, Arr);
} else {
@@ -2644,7 +2776,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
case Decl::TypeAliasTemplate:
case Decl::NamespaceAlias:
case Decl::Block:
- case Decl::Import:
+ case Decl::Empty:
break;
case Decl::CXXConstructor:
// Skip function templates
@@ -2691,9 +2823,9 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
ObjCRuntime->GenerateClass(OMD);
// Emit global variable debug information.
if (CGDebugInfo *DI = getModuleDebugInfo())
- DI->getOrCreateInterfaceType(getContext().getObjCInterfaceType(OMD->getClassInterface()),
- OMD->getLocation());
-
+ if (getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo)
+ DI->getOrCreateInterfaceType(getContext().getObjCInterfaceType(
+ OMD->getClassInterface()), OMD->getLocation());
break;
}
case Decl::ObjCMethod: {
@@ -2725,6 +2857,20 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
break;
}
+ case Decl::Import: {
+ ImportDecl *Import = cast<ImportDecl>(D);
+
+ // Ignore import declarations that come from imported modules.
+ if (clang::Module *Owner = Import->getOwningModule()) {
+ if (getLangOpts().CurrentModule.empty() ||
+ Owner->getTopLevelModule()->Name == getLangOpts().CurrentModule)
+ break;
+ }
+
+ ImportedModules.insert(Import->getImportedModule());
+ break;
+ }
+
default:
// Make sure we handled everything we should, every other kind is a
// non-top-level decl. FIXME: Would be nice to have an isTopLevelDeclKind
@@ -2828,7 +2974,7 @@ llvm::Constant *CodeGenModule::EmitUuidofInitializer(StringRef Uuid,
const char *Uuidstr = Uuid.data();
for (int i = 0; i < 36; ++i) {
if (i == 8 || i == 13 || i == 18 || i == 23) assert(Uuidstr[i] == '-');
- else assert(isxdigit(Uuidstr[i]));
+ else assert(isHexDigit(Uuidstr[i]));
}
llvm::APInt Field0(32, StringRef(Uuidstr , 8), 16);
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 1167c87..5b2153e 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -14,20 +14,24 @@
#ifndef CLANG_CODEGEN_CODEGENMODULE_H
#define CLANG_CODEGEN_CODEGENMODULE_H
-#include "clang/Basic/ABI.h"
-#include "clang/Basic/LangOptions.h"
+#include "CGVTables.h"
+#include "CodeGenTypes.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/GlobalDecl.h"
#include "clang/AST/Mangle.h"
-#include "CGVTables.h"
-#include "CodeGenTypes.h"
-#include "llvm/Module.h"
+#include "clang/Basic/ABI.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/Module.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/IR/CallingConv.h"
+#include "llvm/IR/Module.h"
#include "llvm/Support/ValueHandle.h"
+#include "llvm/Transforms/Utils/BlackList.h"
namespace llvm {
class Module;
@@ -43,6 +47,7 @@ namespace llvm {
namespace clang {
class TargetCodeGenInfo;
class ASTContext;
+ class AtomicType;
class FunctionDecl;
class IdentifierInfo;
class ObjCMethodDecl;
@@ -62,10 +67,12 @@ namespace clang {
class VarDecl;
class LangOptions;
class CodeGenOptions;
+ class TargetOptions;
class DiagnosticsEngine;
class AnnotateAttr;
class CXXDestructorDecl;
class MangleBuffer;
+ class Module;
namespace CodeGen {
@@ -140,6 +147,11 @@ namespace CodeGen {
unsigned char PointerSizeInBytes;
unsigned char SizeSizeInBytes; // sizeof(size_t)
};
+
+ llvm::CallingConv::ID RuntimeCC;
+ llvm::CallingConv::ID getRuntimeCC() const {
+ return RuntimeCC;
+ }
};
struct RREntrypoints {
@@ -205,8 +217,11 @@ struct ARCEntrypoints {
/// A void(void) inline asm to use to mark that the return value of
/// a call will be immediately retain.
llvm::InlineAsm *retainAutoreleasedReturnValueMarker;
+
+ /// void clang.arc.use(...);
+ llvm::Constant *clang_arc_use;
};
-
+
/// CodeGenModule - This class organizes the cross-function state that is used
/// while generating LLVM code.
class CodeGenModule : public CodeGenTypeCache {
@@ -218,6 +233,7 @@ class CodeGenModule : public CodeGenTypeCache {
ASTContext &Context;
const LangOptions &LangOpts;
const CodeGenOptions &CodeGenOpts;
+ const TargetOptions &TargetOpts;
llvm::Module &TheModule;
const llvm::DataLayout &TheDataLayout;
mutable const TargetCodeGenInfo *TheTargetCodeGenInfo;
@@ -254,6 +270,9 @@ class CodeGenModule : public CodeGenTypeCache {
/// is done.
std::vector<GlobalDecl> DeferredDeclsToEmit;
+ /// DeferredVTables - A queue of (optional) vtables to consider emitting.
+ std::vector<const CXXRecordDecl*> DeferredVTables;
+
/// LLVMUsed - List of global values which are required to be
/// present in the object file; bitcast to i8*. This is used for
/// forcing visibility of symbols which may otherwise be optimized
@@ -313,6 +332,9 @@ class CodeGenModule : public CodeGenTypeCache {
/// run on termination.
std::vector<std::pair<llvm::WeakVH,llvm::Constant*> > CXXGlobalDtors;
+ /// \brief The complete set of modules that has been imported.
+ llvm::SetVector<clang::Module *> ImportedModules;
+
/// @name Cache for Objective-C runtime types
/// @{
@@ -358,14 +380,24 @@ class CodeGenModule : public CodeGenTypeCache {
struct {
int GlobalUniqueCount;
} Block;
-
+
+ /// void @llvm.lifetime.start(i64 %size, i8* nocapture <ptr>)
+ llvm::Constant *LifetimeStartFn;
+
+ /// void @llvm.lifetime.end(i64 %size, i8* nocapture <ptr>)
+ llvm::Constant *LifetimeEndFn;
+
GlobalDecl initializedGlobalDecl;
+ llvm::BlackList SanitizerBlacklist;
+
+ const SanitizerOptions &SanOpts;
+
/// @}
public:
CodeGenModule(ASTContext &C, const CodeGenOptions &CodeGenOpts,
- llvm::Module &M, const llvm::DataLayout &TD,
- DiagnosticsEngine &Diags);
+ const TargetOptions &TargetOpts, llvm::Module &M,
+ const llvm::DataLayout &TD, DiagnosticsEngine &Diags);
~CodeGenModule();
@@ -469,9 +501,17 @@ public:
llvm::MDNode *getTBAAInfo(QualType QTy);
llvm::MDNode *getTBAAInfoForVTablePtr();
llvm::MDNode *getTBAAStructInfo(QualType QTy);
+ /// Return the MDNode in the type DAG for the given struct type.
+ llvm::MDNode *getTBAAStructTypeInfo(QualType QTy);
+ /// Return the path-aware tag for given base type, access node and offset.
+ llvm::MDNode *getTBAAStructTagInfo(QualType BaseTy, llvm::MDNode *AccessN,
+ uint64_t O);
bool isTypeConstant(QualType QTy, bool ExcludeCtorDtor);
+ bool isPaddedAtomicType(QualType type);
+ bool isPaddedAtomicType(const AtomicType *type);
+
static void DecorateInstruction(llvm::Instruction *Inst,
llvm::MDNode *TBAAInfo);
@@ -711,8 +751,8 @@ public:
/// type and name.
llvm::Constant *CreateRuntimeFunction(llvm::FunctionType *Ty,
StringRef Name,
- llvm::Attributes ExtraAttrs =
- llvm::Attributes());
+ llvm::AttributeSet ExtraAttrs =
+ llvm::AttributeSet());
/// CreateRuntimeVariable - Create a new runtime global variable with the
/// specified type and name.
llvm::Constant *CreateRuntimeVariable(llvm::Type *Ty,
@@ -728,6 +768,9 @@ public:
///@}
+ llvm::Constant *getLLVMLifetimeStartFn();
+ llvm::Constant *getLLVMLifetimeEndFn();
+
// UpdateCompleteType - Make sure that this type is translated.
void UpdateCompletedType(const TagDecl *TD);
@@ -823,7 +866,8 @@ public:
void ConstructAttributeList(const CGFunctionInfo &Info,
const Decl *TargetDecl,
AttributeListType &PAL,
- unsigned &CallingConv);
+ unsigned &CallingConv,
+ bool AttrOnCallSite);
StringRef getMangledName(GlobalDecl GD);
void getBlockMangledName(GlobalDecl GD, MangleBuffer &Buffer,
@@ -854,13 +898,11 @@ public:
GetLLVMLinkageVarDefinition(const VarDecl *D,
llvm::GlobalVariable *GV);
- std::vector<const CXXRecordDecl*> DeferredVTables;
-
/// Emit all the global annotations.
void EmitGlobalAnnotations();
/// Emit an annotation string.
- llvm::Constant *EmitAnnotationString(llvm::StringRef Str);
+ llvm::Constant *EmitAnnotationString(StringRef Str);
/// Emit the annotation's translation unit.
llvm::Constant *EmitAnnotationUnit(SourceLocation Loc);
@@ -883,6 +925,16 @@ public:
/// annotations are emitted during finalization of the LLVM code.
void AddGlobalAnnotations(const ValueDecl *D, llvm::GlobalValue *GV);
+ const llvm::BlackList &getSanitizerBlacklist() const {
+ return SanitizerBlacklist;
+ }
+
+ const SanitizerOptions &getSanOpts() const { return SanOpts; }
+
+ void addDeferredVTable(const CXXRecordDecl *RD) {
+ DeferredVTables.push_back(RD);
+ }
+
private:
llvm::GlobalValue *GetGlobalValue(StringRef Ref);
@@ -890,8 +942,8 @@ private:
llvm::Type *Ty,
GlobalDecl D,
bool ForVTable,
- llvm::Attributes ExtraAttrs =
- llvm::Attributes());
+ llvm::AttributeSet ExtraAttrs =
+ llvm::AttributeSet());
llvm::Constant *GetOrCreateLLVMGlobal(StringRef MangledName,
llvm::PointerType *PTy,
const VarDecl *D,
@@ -983,11 +1035,18 @@ private:
/// EmitDeferred - Emit any needed decls for which code generation
/// was deferred.
- void EmitDeferred(void);
+ void EmitDeferred();
+
+ /// EmitDeferredVTables - Emit any vtables which we deferred and
+ /// still have a use for.
+ void EmitDeferredVTables();
/// EmitLLVMUsed - Emit the llvm.used metadata used to force
/// references to global which may otherwise be optimized out.
- void EmitLLVMUsed(void);
+ void EmitLLVMUsed();
+
+ /// \brief Emit the link options introduced by imported modules.
+ void EmitModuleLinkOptions();
void EmitDeclMetadata();
diff --git a/lib/CodeGen/CodeGenTBAA.cpp b/lib/CodeGen/CodeGenTBAA.cpp
index d9004a0..7e4d34a 100644
--- a/lib/CodeGen/CodeGenTBAA.cpp
+++ b/lib/CodeGen/CodeGenTBAA.cpp
@@ -17,13 +17,15 @@
#include "CodeGenTBAA.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/RecordLayout.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Mangle.h"
+#include "clang/AST/RecordLayout.h"
#include "clang/Frontend/CodeGenOptions.h"
-#include "llvm/LLVMContext.h"
-#include "llvm/Metadata.h"
-#include "llvm/Constants.h"
-#include "llvm/Type.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Metadata.h"
+#include "llvm/IR/Type.h"
using namespace clang;
using namespace CodeGen;
@@ -224,3 +226,87 @@ CodeGenTBAA::getTBAAStructInfo(QualType QTy) {
// For now, handle any other kind of type conservatively.
return StructMetadataCache[Ty] = NULL;
}
+
+/// Check if the given type can be handled by path-aware TBAA.
+static bool isTBAAPathStruct(QualType QTy) {
+ if (const RecordType *TTy = QTy->getAs<RecordType>()) {
+ const RecordDecl *RD = TTy->getDecl()->getDefinition();
+ // RD can be struct, union, class, interface or enum.
+ // For now, we only handle struct.
+ if (RD->isStruct() && !RD->hasFlexibleArrayMember())
+ return true;
+ }
+ return false;
+}
+
+llvm::MDNode *
+CodeGenTBAA::getTBAAStructTypeInfo(QualType QTy) {
+ const Type *Ty = Context.getCanonicalType(QTy).getTypePtr();
+ assert(isTBAAPathStruct(QTy));
+
+ if (llvm::MDNode *N = StructTypeMetadataCache[Ty])
+ return N;
+
+ if (const RecordType *TTy = QTy->getAs<RecordType>()) {
+ const RecordDecl *RD = TTy->getDecl()->getDefinition();
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ SmallVector <std::pair<uint64_t, llvm::MDNode*>, 4> Fields;
+ // To reduce the size of MDNode for a given struct type, we only output
+ // once for all the fields with the same scalar types.
+ // Offsets for scalar fields in the type DAG are not used.
+ llvm::SmallSet <llvm::MDNode*, 4> ScalarFieldTypes;
+ unsigned idx = 0;
+ for (RecordDecl::field_iterator i = RD->field_begin(),
+ e = RD->field_end(); i != e; ++i, ++idx) {
+ QualType FieldQTy = i->getType();
+ llvm::MDNode *FieldNode;
+ if (isTBAAPathStruct(FieldQTy))
+ FieldNode = getTBAAStructTypeInfo(FieldQTy);
+ else {
+ FieldNode = getTBAAInfo(FieldQTy);
+ // Ignore this field if the type already exists.
+ if (ScalarFieldTypes.count(FieldNode))
+ continue;
+ ScalarFieldTypes.insert(FieldNode);
+ }
+ if (!FieldNode)
+ return StructTypeMetadataCache[Ty] = NULL;
+ Fields.push_back(std::make_pair(
+ Layout.getFieldOffset(idx) / Context.getCharWidth(), FieldNode));
+ }
+
+ // TODO: This is using the RTTI name. Is there a better way to get
+ // a unique string for a type?
+ SmallString<256> OutName;
+ llvm::raw_svector_ostream Out(OutName);
+ MContext.mangleCXXRTTIName(QualType(Ty, 0), Out);
+ Out.flush();
+ // Create the struct type node with a vector of pairs (offset, type).
+ return StructTypeMetadataCache[Ty] =
+ MDHelper.createTBAAStructTypeNode(OutName, Fields);
+ }
+
+ return StructMetadataCache[Ty] = NULL;
+}
+
+llvm::MDNode *
+CodeGenTBAA::getTBAAStructTagInfo(QualType BaseQTy, llvm::MDNode *AccessNode,
+ uint64_t Offset) {
+ if (!CodeGenOpts.StructPathTBAA)
+ return AccessNode;
+
+ const Type *BTy = Context.getCanonicalType(BaseQTy).getTypePtr();
+ TBAAPathTag PathTag = TBAAPathTag(BTy, AccessNode, Offset);
+ if (llvm::MDNode *N = StructTagMetadataCache[PathTag])
+ return N;
+
+ llvm::MDNode *BNode = 0;
+ if (isTBAAPathStruct(BaseQTy))
+ BNode = getTBAAStructTypeInfo(BaseQTy);
+ if (!BNode)
+ return StructTagMetadataCache[PathTag] = AccessNode;
+
+ return StructTagMetadataCache[PathTag] =
+ MDHelper.createTBAAStructTagNode(BNode, AccessNode, Offset);
+}
diff --git a/lib/CodeGen/CodeGenTBAA.h b/lib/CodeGen/CodeGenTBAA.h
index eedb996..9ddc3aa 100644
--- a/lib/CodeGen/CodeGenTBAA.h
+++ b/lib/CodeGen/CodeGenTBAA.h
@@ -16,8 +16,8 @@
#define CLANG_CODEGEN_CODEGENTBAA_H
#include "clang/Basic/LLVM.h"
-#include "llvm/MDBuilder.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/IR/MDBuilder.h"
namespace llvm {
class LLVMContext;
@@ -35,6 +35,14 @@ namespace clang {
namespace CodeGen {
class CGRecordLayout;
+ struct TBAAPathTag {
+ TBAAPathTag(const Type *B, const llvm::MDNode *A, uint64_t O)
+ : BaseT(B), AccessN(A), Offset(O) {}
+ const Type *BaseT;
+ const llvm::MDNode *AccessN;
+ uint64_t Offset;
+ };
+
/// CodeGenTBAA - This class organizes the cross-module state that is used
/// while lowering AST types to LLVM types.
class CodeGenTBAA {
@@ -46,8 +54,13 @@ class CodeGenTBAA {
// MDHelper - Helper for creating metadata.
llvm::MDBuilder MDHelper;
- /// MetadataCache - This maps clang::Types to llvm::MDNodes describing them.
+ /// MetadataCache - This maps clang::Types to scalar llvm::MDNodes describing
+ /// them.
llvm::DenseMap<const Type *, llvm::MDNode *> MetadataCache;
+ /// This maps clang::Types to a struct node in the type DAG.
+ llvm::DenseMap<const Type *, llvm::MDNode *> StructTypeMetadataCache;
+ /// This maps TBAAPathTags to a tag node.
+ llvm::DenseMap<TBAAPathTag, llvm::MDNode *> StructTagMetadataCache;
/// StructMetadataCache - This maps clang::Types to llvm::MDNodes describing
/// them for struct assignments.
@@ -89,9 +102,49 @@ public:
/// getTBAAStructInfo - Get the TBAAStruct MDNode to be used for a memcpy of
/// the given type.
llvm::MDNode *getTBAAStructInfo(QualType QTy);
+
+ /// Get the MDNode in the type DAG for given struct type QType.
+ llvm::MDNode *getTBAAStructTypeInfo(QualType QType);
+ /// Get the tag MDNode for a given base type, the actual sclar access MDNode
+ /// and offset into the base type.
+ llvm::MDNode *getTBAAStructTagInfo(QualType BaseQType,
+ llvm::MDNode *AccessNode, uint64_t Offset);
};
} // end namespace CodeGen
} // end namespace clang
+namespace llvm {
+
+template<> struct DenseMapInfo<clang::CodeGen::TBAAPathTag> {
+ static clang::CodeGen::TBAAPathTag getEmptyKey() {
+ return clang::CodeGen::TBAAPathTag(
+ DenseMapInfo<const clang::Type *>::getEmptyKey(),
+ DenseMapInfo<const MDNode *>::getEmptyKey(),
+ DenseMapInfo<uint64_t>::getEmptyKey());
+ }
+
+ static clang::CodeGen::TBAAPathTag getTombstoneKey() {
+ return clang::CodeGen::TBAAPathTag(
+ DenseMapInfo<const clang::Type *>::getTombstoneKey(),
+ DenseMapInfo<const MDNode *>::getTombstoneKey(),
+ DenseMapInfo<uint64_t>::getTombstoneKey());
+ }
+
+ static unsigned getHashValue(const clang::CodeGen::TBAAPathTag &Val) {
+ return DenseMapInfo<const clang::Type *>::getHashValue(Val.BaseT) ^
+ DenseMapInfo<const MDNode *>::getHashValue(Val.AccessN) ^
+ DenseMapInfo<uint64_t>::getHashValue(Val.Offset);
+ }
+
+ static bool isEqual(const clang::CodeGen::TBAAPathTag &LHS,
+ const clang::CodeGen::TBAAPathTag &RHS) {
+ return LHS.BaseT == RHS.BaseT &&
+ LHS.AccessN == RHS.AccessN &&
+ LHS.Offset == RHS.Offset;
+ }
+};
+
+} // end namespace llvm
+
#endif
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index 3c6c5c9..8fc78e3 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -12,18 +12,19 @@
//===----------------------------------------------------------------------===//
#include "CodeGenTypes.h"
-#include "CGCall.h"
#include "CGCXXABI.h"
+#include "CGCall.h"
+#include "CGOpenCLRuntime.h"
#include "CGRecordLayout.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h"
-#include "llvm/DerivedTypes.h"
-#include "llvm/Module.h"
-#include "llvm/DataLayout.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Module.h"
using namespace clang;
using namespace CodeGen;
@@ -60,14 +61,14 @@ void CodeGenTypes::addRecordTypeName(const RecordDecl *RD,
// FIXME: We should not have to check for a null decl context here.
// Right now we do it because the implicit Obj-C decls don't have one.
if (RD->getDeclContext())
- OS << RD->getQualifiedNameAsString();
+ RD->printQualifiedName(OS);
else
RD->printName(OS);
} else if (const TypedefNameDecl *TDD = RD->getTypedefNameForAnonDecl()) {
// FIXME: We should not have to check for a null decl context here.
// Right now we do it because the implicit Obj-C decls don't have one.
if (TDD->getDeclContext())
- OS << TDD->getQualifiedNameAsString();
+ TDD->printQualifiedName(OS);
else
TDD->printName(OS);
} else
@@ -262,9 +263,14 @@ void CodeGenTypes::UpdateCompletedType(const TagDecl *TD) {
}
static llvm::Type *getTypeForFormat(llvm::LLVMContext &VMContext,
- const llvm::fltSemantics &format) {
- if (&format == &llvm::APFloat::IEEEhalf)
- return llvm::Type::getInt16Ty(VMContext);
+ const llvm::fltSemantics &format,
+ bool UseNativeHalf = false) {
+ if (&format == &llvm::APFloat::IEEEhalf) {
+ if (UseNativeHalf)
+ return llvm::Type::getHalfTy(VMContext);
+ else
+ return llvm::Type::getInt16Ty(VMContext);
+ }
if (&format == &llvm::APFloat::IEEEsingle)
return llvm::Type::getFloatTy(VMContext);
if (&format == &llvm::APFloat::IEEEdouble)
@@ -343,18 +349,17 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
break;
case BuiltinType::Half:
- // Half is special: it might be lowered to i16 (and will be storage-only
- // type),. or can be represented as a set of native operations.
-
- // FIXME: Ask target which kind of half FP it prefers (storage only vs
- // native).
- ResultType = llvm::Type::getInt16Ty(getLLVMContext());
+ // Half FP can either be storage-only (lowered to i16) or native.
+ ResultType = getTypeForFormat(getLLVMContext(),
+ Context.getFloatTypeSemantics(T),
+ Context.getLangOpts().NativeHalfType);
break;
case BuiltinType::Float:
case BuiltinType::Double:
case BuiltinType::LongDouble:
ResultType = getTypeForFormat(getLLVMContext(),
- Context.getFloatTypeSemantics(T));
+ Context.getFloatTypeSemantics(T),
+ /* UseNativeHalf = */ false);
break;
case BuiltinType::NullPtr:
@@ -366,6 +371,17 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
case BuiltinType::Int128:
ResultType = llvm::IntegerType::get(getLLVMContext(), 128);
break;
+
+ case BuiltinType::OCLImage1d:
+ case BuiltinType::OCLImage1dArray:
+ case BuiltinType::OCLImage1dBuffer:
+ case BuiltinType::OCLImage2d:
+ case BuiltinType::OCLImage2dArray:
+ case BuiltinType::OCLImage3d:
+ case BuiltinType::OCLSampler:
+ case BuiltinType::OCLEvent:
+ ResultType = CGM.getOpenCLRuntime().convertOpenCLSpecificType(Ty);
+ break;
case BuiltinType::Dependent:
#define BUILTIN_TYPE(Id, SingletonId)
@@ -453,9 +469,19 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
// cannot lower the function type.
if (!isFuncTypeConvertible(FT)) {
// This function's type depends on an incomplete tag type.
+
+ // Force conversion of all the relevant record types, to make sure
+ // we re-convert the FunctionType when appropriate.
+ if (const RecordType *RT = FT->getResultType()->getAs<RecordType>())
+ ConvertRecordDeclType(RT->getDecl());
+ if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FT))
+ for (unsigned i = 0, e = FPT->getNumArgs(); i != e; i++)
+ if (const RecordType *RT = FPT->getArgType(i)->getAs<RecordType>())
+ ConvertRecordDeclType(RT->getDecl());
+
// Return a placeholder type.
ResultType = llvm::StructType::get(getLLVMContext());
-
+
SkippedLayout = true;
break;
}
@@ -556,7 +582,21 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
}
case Type::Atomic: {
- ResultType = ConvertType(cast<AtomicType>(Ty)->getValueType());
+ QualType valueType = cast<AtomicType>(Ty)->getValueType();
+ ResultType = ConvertTypeForMem(valueType);
+
+ // Pad out to the inflated size if necessary.
+ uint64_t valueSize = Context.getTypeSize(valueType);
+ uint64_t atomicSize = Context.getTypeSize(Ty);
+ if (valueSize != atomicSize) {
+ assert(valueSize < atomicSize);
+ llvm::Type *elts[] = {
+ ResultType,
+ llvm::ArrayType::get(CGM.Int8Ty, (atomicSize - valueSize) / 8)
+ };
+ ResultType = llvm::StructType::get(getLLVMContext(),
+ llvm::makeArrayRef(elts));
+ }
break;
}
}
@@ -567,6 +607,14 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
return ResultType;
}
+bool CodeGenModule::isPaddedAtomicType(QualType type) {
+ return isPaddedAtomicType(type->castAs<AtomicType>());
+}
+
+bool CodeGenModule::isPaddedAtomicType(const AtomicType *type) {
+ return Context.getTypeSize(type) != Context.getTypeSize(type->getValueType());
+}
+
/// ConvertRecordDeclType - Lay out a tagged decl type like struct or union.
llvm::StructType *CodeGenTypes::ConvertRecordDeclType(const RecordDecl *RD) {
// TagDecl's are not necessarily unique, instead use the (clang)
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index 0519911..11fd76f 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -16,8 +16,8 @@
#include "CGCall.h"
#include "clang/AST/GlobalDecl.h"
-#include "llvm/Module.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/IR/Module.h"
#include <vector>
namespace llvm {
@@ -58,6 +58,7 @@ namespace CodeGen {
/// CodeGenTypes - This class organizes the cross-module state that is used
/// while lowering AST types to LLVM types.
class CodeGenTypes {
+public:
// Some of this stuff should probably be left on the CGM.
ASTContext &Context;
const TargetInfo &Target;
@@ -68,6 +69,7 @@ class CodeGenTypes {
const CodeGenOptions &CodeGenOpts;
CodeGenModule &CGM;
+private:
/// The opaque type map for Objective-C interfaces. All direct
/// manipulation is done by the runtime interfaces, which are
/// responsible for coercing to the appropriate type; these opaque
@@ -195,6 +197,8 @@ public:
const CallArgList &args,
FunctionType::ExtInfo info,
RequiredArgs required);
+ const CGFunctionInfo &arrangeBlockFunctionCall(const CallArgList &args,
+ const FunctionType *type);
const CGFunctionInfo &arrangeCXXMethodCall(const CallArgList &args,
const FunctionProtoType *type,
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index 245150c..e25d422 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -25,33 +25,21 @@
#include "CodeGenModule.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/Type.h"
-#include "llvm/Intrinsics.h"
-#include "llvm/DataLayout.h"
-#include "llvm/Value.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/Value.h"
using namespace clang;
using namespace CodeGen;
namespace {
class ItaniumCXXABI : public CodeGen::CGCXXABI {
-private:
- llvm::IntegerType *PtrDiffTy;
protected:
bool IsARM;
- // It's a little silly for us to cache this.
- llvm::IntegerType *getPtrDiffTy() {
- if (!PtrDiffTy) {
- QualType T = getContext().getPointerDiffType();
- llvm::Type *Ty = CGM.getTypes().ConvertType(T);
- PtrDiffTy = cast<llvm::IntegerType>(Ty);
- }
- return PtrDiffTy;
- }
-
public:
ItaniumCXXABI(CodeGen::CodeGenModule &CGM, bool IsARM = false) :
- CGCXXABI(CGM), PtrDiffTy(0), IsARM(IsARM) { }
+ CGCXXABI(CGM), IsARM(IsARM) { }
bool isZeroInitializable(const MemberPointerType *MPT);
@@ -112,6 +100,21 @@ public:
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
+ llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,
+ const CXXConstructorDecl *D,
+ CXXCtorType Type, bool ForVirtualBase,
+ bool Delegating,
+ llvm::Value *This,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd);
+
+ RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,
+ const CXXDestructorDecl *Dtor,
+ CXXDtorType DtorType,
+ SourceLocation CallLoc,
+ ReturnValueSlot ReturnValue,
+ llvm::Value *This);
+
StringRef GetPureVirtualCallName() { return "__cxa_pure_virtual"; }
StringRef GetDeletedVirtualCallName() { return "__cxa_deleted_virtual"; }
@@ -129,8 +132,6 @@ public:
llvm::GlobalVariable *DeclPtr, bool PerformInit);
void registerGlobalDtor(CodeGenFunction &CGF, llvm::Constant *dtor,
llvm::Constant *addr);
-
- void EmitVTables(const CXXRecordDecl *Class);
};
class ARMCXXABI : public ItaniumCXXABI {
@@ -164,11 +165,11 @@ public:
llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF, llvm::Value *allocPtr,
CharUnits cookieSize);
-private:
/// \brief Returns true if the given instance method is one of the
/// kinds that the ARM ABI says returns 'this'.
- static bool HasThisReturn(GlobalDecl GD) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+ bool HasThisReturn(GlobalDecl GD) const {
+ const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(GD.getDecl());
+ if (!MD) return false;
return ((isa<CXXDestructorDecl>(MD) && GD.getDtorType() != Dtor_Deleting) ||
(isa<CXXConstructorDecl>(MD)));
}
@@ -176,18 +177,33 @@ private:
}
CodeGen::CGCXXABI *CodeGen::CreateItaniumCXXABI(CodeGenModule &CGM) {
- return new ItaniumCXXABI(CGM);
-}
-
-CodeGen::CGCXXABI *CodeGen::CreateARMCXXABI(CodeGenModule &CGM) {
- return new ARMCXXABI(CGM);
+ switch (CGM.getContext().getTargetInfo().getCXXABI().getKind()) {
+ // For IR-generation purposes, there's no significant difference
+ // between the ARM and iOS ABIs.
+ case TargetCXXABI::GenericARM:
+ case TargetCXXABI::iOS:
+ return new ARMCXXABI(CGM);
+
+ // Note that AArch64 uses the generic ItaniumCXXABI class since it doesn't
+ // include the other 32-bit ARM oddities: constructor/destructor return values
+ // and array cookies.
+ case TargetCXXABI::GenericAArch64:
+ return new ItaniumCXXABI(CGM, /*IsARM = */ true);
+
+ case TargetCXXABI::GenericItanium:
+ return new ItaniumCXXABI(CGM);
+
+ case TargetCXXABI::Microsoft:
+ llvm_unreachable("Microsoft ABI is not Itanium-based");
+ }
+ llvm_unreachable("bad ABI kind");
}
llvm::Type *
ItaniumCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) {
if (MPT->isMemberDataPointer())
- return getPtrDiffTy();
- return llvm::StructType::get(getPtrDiffTy(), getPtrDiffTy(), NULL);
+ return CGM.PtrDiffTy;
+ return llvm::StructType::get(CGM.PtrDiffTy, CGM.PtrDiffTy, NULL);
}
/// In the Itanium and ARM ABIs, method pointers have the form:
@@ -226,8 +242,7 @@ ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF,
CGM.getTypes().GetFunctionType(
CGM.getTypes().arrangeCXXMethodType(RD, FPT));
- llvm::IntegerType *ptrdiff = getPtrDiffTy();
- llvm::Constant *ptrdiff_1 = llvm::ConstantInt::get(ptrdiff, 1);
+ llvm::Constant *ptrdiff_1 = llvm::ConstantInt::get(CGM.PtrDiffTy, 1);
llvm::BasicBlock *FnVirtual = CGF.createBasicBlock("memptr.virtual");
llvm::BasicBlock *FnNonVirtual = CGF.createBasicBlock("memptr.nonvirtual");
@@ -300,7 +315,7 @@ llvm::Value *ItaniumCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF,
llvm::Value *Base,
llvm::Value *MemPtr,
const MemberPointerType *MPT) {
- assert(MemPtr->getType() == getPtrDiffTy());
+ assert(MemPtr->getType() == CGM.PtrDiffTy);
CGBuilderTy &Builder = CGF.Builder;
@@ -448,14 +463,12 @@ ItaniumCXXABI::EmitMemberPointerConversion(const CastExpr *E,
llvm::Constant *
ItaniumCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) {
- llvm::Type *ptrdiff_t = getPtrDiffTy();
-
// Itanium C++ ABI 2.3:
// A NULL pointer is represented as -1.
if (MPT->isMemberDataPointer())
- return llvm::ConstantInt::get(ptrdiff_t, -1ULL, /*isSigned=*/true);
+ return llvm::ConstantInt::get(CGM.PtrDiffTy, -1ULL, /*isSigned=*/true);
- llvm::Constant *Zero = llvm::ConstantInt::get(ptrdiff_t, 0);
+ llvm::Constant *Zero = llvm::ConstantInt::get(CGM.PtrDiffTy, 0);
llvm::Constant *Values[2] = { Zero, Zero };
return llvm::ConstantStruct::getAnon(Values);
}
@@ -466,7 +479,7 @@ ItaniumCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
// Itanium C++ ABI 2.3:
// A pointer to data member is an offset from the base address of
// the class object containing it, represented as a ptrdiff_t
- return llvm::ConstantInt::get(getPtrDiffTy(), offset.getQuantity());
+ return llvm::ConstantInt::get(CGM.PtrDiffTy, offset.getQuantity());
}
llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
@@ -479,7 +492,6 @@ llvm::Constant *ItaniumCXXABI::BuildMemberPointer(const CXXMethodDecl *MD,
MD = MD->getCanonicalDecl();
CodeGenTypes &Types = CGM.getTypes();
- llvm::Type *ptrdiff_t = getPtrDiffTy();
// Get the function pointer (or index if this is a virtual function).
llvm::Constant *MemPtr[2];
@@ -498,16 +510,16 @@ llvm::Constant *ItaniumCXXABI::BuildMemberPointer(const CXXMethodDecl *MD,
// least significant bit of adj then makes exactly the same
// discrimination as the least significant bit of ptr does for
// Itanium.
- MemPtr[0] = llvm::ConstantInt::get(ptrdiff_t, VTableOffset);
- MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t,
+ MemPtr[0] = llvm::ConstantInt::get(CGM.PtrDiffTy, VTableOffset);
+ MemPtr[1] = llvm::ConstantInt::get(CGM.PtrDiffTy,
2 * ThisAdjustment.getQuantity() + 1);
} else {
// Itanium C++ ABI 2.3:
// For a virtual function, [the pointer field] is 1 plus the
// virtual table offset (in bytes) of the function,
// represented as a ptrdiff_t.
- MemPtr[0] = llvm::ConstantInt::get(ptrdiff_t, VTableOffset + 1);
- MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t,
+ MemPtr[0] = llvm::ConstantInt::get(CGM.PtrDiffTy, VTableOffset + 1);
+ MemPtr[1] = llvm::ConstantInt::get(CGM.PtrDiffTy,
ThisAdjustment.getQuantity());
}
} else {
@@ -520,12 +532,12 @@ llvm::Constant *ItaniumCXXABI::BuildMemberPointer(const CXXMethodDecl *MD,
} else {
// Use an arbitrary non-function type to tell GetAddrOfFunction that the
// function type is incomplete.
- Ty = ptrdiff_t;
+ Ty = CGM.PtrDiffTy;
}
llvm::Constant *addr = CGM.GetAddrOfFunction(MD, Ty);
- MemPtr[0] = llvm::ConstantExpr::getPtrToInt(addr, ptrdiff_t);
- MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, (IsARM ? 2 : 1) *
+ MemPtr[0] = llvm::ConstantExpr::getPtrToInt(addr, CGM.PtrDiffTy);
+ MemPtr[1] = llvm::ConstantInt::get(CGM.PtrDiffTy, (IsARM ? 2 : 1) *
ThisAdjustment.getQuantity());
}
@@ -650,7 +662,7 @@ ItaniumCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
/// For member data pointers, this is just a check against -1.
if (MPT->isMemberDataPointer()) {
- assert(MemPtr->getType() == getPtrDiffTy());
+ assert(MemPtr->getType() == CGM.PtrDiffTy);
llvm::Value *NegativeOne =
llvm::Constant::getAllOnesValue(MemPtr->getType());
return Builder.CreateICmpNE(MemPtr, NegativeOne, "memptr.tobool");
@@ -806,6 +818,41 @@ void ARMCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
}
+llvm::Value *ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
+ const CXXConstructorDecl *D,
+ CXXCtorType Type, bool ForVirtualBase,
+ bool Delegating,
+ llvm::Value *This,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd) {
+ llvm::Value *VTT = CGF.GetVTTParameter(GlobalDecl(D, Type), ForVirtualBase,
+ Delegating);
+ QualType VTTTy = getContext().getPointerType(getContext().VoidPtrTy);
+ llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
+
+ // FIXME: Provide a source location here.
+ CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
+ VTT, VTTTy, ArgBeg, ArgEnd);
+ return Callee;
+}
+
+RValue ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
+ const CXXDestructorDecl *Dtor,
+ CXXDtorType DtorType,
+ SourceLocation CallLoc,
+ ReturnValueSlot ReturnValue,
+ llvm::Value *This) {
+ assert(DtorType == Dtor_Deleting || DtorType == Dtor_Complete);
+
+ const CGFunctionInfo *FInfo
+ = &CGM.getTypes().arrangeCXXDestructor(Dtor, DtorType);
+ llvm::Type *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo);
+ llvm::Value *Callee = CGF.BuildVirtualCall(Dtor, DtorType, This, Ty);
+
+ return CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValue, This,
+ /*ImplicitParam=*/0, QualType(), 0, 0);
+}
+
void ARMCXXABI::EmitReturnFromThunk(CodeGenFunction &CGF,
RValue RV, QualType ResultType) {
if (!isa<CXXDestructorDecl>(CGF.CurGD.getDecl()))
@@ -883,50 +930,46 @@ llvm::Value *ItaniumCXXABI::readArrayCookieImpl(CodeGenFunction &CGF,
}
CharUnits ARMCXXABI::getArrayCookieSizeImpl(QualType elementType) {
- // On ARM, the cookie is always:
+ // ARM says that the cookie is always:
// struct array_cookie {
// std::size_t element_size; // element_size != 0
// std::size_t element_count;
// };
- // TODO: what should we do if the allocated type actually wants
- // greater alignment?
- return CharUnits::fromQuantity(2 * CGM.SizeSizeInBytes);
+ // But the base ABI doesn't give anything an alignment greater than
+ // 8, so we can dismiss this as typical ABI-author blindness to
+ // actual language complexity and round up to the element alignment.
+ return std::max(CharUnits::fromQuantity(2 * CGM.SizeSizeInBytes),
+ CGM.getContext().getTypeAlignInChars(elementType));
}
llvm::Value *ARMCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
- llvm::Value *NewPtr,
- llvm::Value *NumElements,
+ llvm::Value *newPtr,
+ llvm::Value *numElements,
const CXXNewExpr *expr,
- QualType ElementType) {
+ QualType elementType) {
assert(requiresArrayCookie(expr));
- // NewPtr is a char*.
-
- unsigned AS = NewPtr->getType()->getPointerAddressSpace();
-
- ASTContext &Ctx = getContext();
- CharUnits SizeSize = Ctx.getTypeSizeInChars(Ctx.getSizeType());
- llvm::IntegerType *SizeTy =
- cast<llvm::IntegerType>(CGF.ConvertType(Ctx.getSizeType()));
+ // NewPtr is a char*, but we generalize to arbitrary addrspaces.
+ unsigned AS = newPtr->getType()->getPointerAddressSpace();
// The cookie is always at the start of the buffer.
- llvm::Value *CookiePtr = NewPtr;
+ llvm::Value *cookie = newPtr;
// The first element is the element size.
- CookiePtr = CGF.Builder.CreateBitCast(CookiePtr, SizeTy->getPointerTo(AS));
- llvm::Value *ElementSize = llvm::ConstantInt::get(SizeTy,
- Ctx.getTypeSizeInChars(ElementType).getQuantity());
- CGF.Builder.CreateStore(ElementSize, CookiePtr);
+ cookie = CGF.Builder.CreateBitCast(cookie, CGF.SizeTy->getPointerTo(AS));
+ llvm::Value *elementSize = llvm::ConstantInt::get(CGF.SizeTy,
+ getContext().getTypeSizeInChars(elementType).getQuantity());
+ CGF.Builder.CreateStore(elementSize, cookie);
// The second element is the element count.
- CookiePtr = CGF.Builder.CreateConstInBoundsGEP1_32(CookiePtr, 1);
- CGF.Builder.CreateStore(NumElements, CookiePtr);
+ cookie = CGF.Builder.CreateConstInBoundsGEP1_32(cookie, 1);
+ CGF.Builder.CreateStore(numElements, cookie);
// Finally, compute a pointer to the actual data buffer by skipping
// over the cookie completely.
- CharUnits CookieSize = 2 * SizeSize;
- return CGF.Builder.CreateConstInBoundsGEP1_64(NewPtr,
- CookieSize.getQuantity());
+ CharUnits cookieSize = ARMCXXABI::getArrayCookieSizeImpl(elementType);
+ return CGF.Builder.CreateConstInBoundsGEP1_64(newPtr,
+ cookieSize.getQuantity());
}
llvm::Value *ARMCXXABI::readArrayCookieImpl(CodeGenFunction &CGF,
@@ -952,8 +995,9 @@ static llvm::Constant *getGuardAcquireFn(CodeGenModule &CGM,
llvm::FunctionType::get(CGM.getTypes().ConvertType(CGM.getContext().IntTy),
GuardPtrTy, /*isVarArg=*/false);
return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_acquire",
- llvm::Attributes::get(CGM.getLLVMContext(),
- llvm::Attributes::NoUnwind));
+ llvm::AttributeSet::get(CGM.getLLVMContext(),
+ llvm::AttributeSet::FunctionIndex,
+ llvm::Attribute::NoUnwind));
}
static llvm::Constant *getGuardReleaseFn(CodeGenModule &CGM,
@@ -962,8 +1006,9 @@ static llvm::Constant *getGuardReleaseFn(CodeGenModule &CGM,
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.VoidTy, GuardPtrTy, /*isVarArg=*/false);
return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_release",
- llvm::Attributes::get(CGM.getLLVMContext(),
- llvm::Attributes::NoUnwind));
+ llvm::AttributeSet::get(CGM.getLLVMContext(),
+ llvm::AttributeSet::FunctionIndex,
+ llvm::Attribute::NoUnwind));
}
static llvm::Constant *getGuardAbortFn(CodeGenModule &CGM,
@@ -972,8 +1017,9 @@ static llvm::Constant *getGuardAbortFn(CodeGenModule &CGM,
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.VoidTy, GuardPtrTy, /*isVarArg=*/false);
return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_abort",
- llvm::Attributes::get(CGM.getLLVMContext(),
- llvm::Attributes::NoUnwind));
+ llvm::AttributeSet::get(CGM.getLLVMContext(),
+ llvm::AttributeSet::FunctionIndex,
+ llvm::Attribute::NoUnwind));
}
namespace {
@@ -982,8 +1028,8 @@ namespace {
CallGuardAbort(llvm::GlobalVariable *Guard) : Guard(Guard) {}
void Emit(CodeGenFunction &CGF, Flags flags) {
- CGF.Builder.CreateCall(getGuardAbortFn(CGF.CGM, Guard->getType()), Guard)
- ->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(getGuardAbortFn(CGF.CGM, Guard->getType()),
+ Guard);
}
};
}
@@ -1009,8 +1055,9 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
if (useInt8GuardVariable) {
guardTy = CGF.Int8Ty;
} else {
- // Guard variables are 64 bits in the generic ABI and 32 bits on ARM.
- guardTy = (IsARM ? CGF.Int32Ty : CGF.Int64Ty);
+ // Guard variables are 64 bits in the generic ABI and size width on ARM
+ // (i.e. 32-bit on AArch32, 64-bit on AArch64).
+ guardTy = (IsARM ? CGF.SizeTy : CGF.Int64Ty);
}
llvm::PointerType *guardPtrTy = guardTy->getPointerTo();
@@ -1053,7 +1100,8 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
// }
if (IsARM && !useInt8GuardVariable) {
llvm::Value *V = Builder.CreateLoad(guard);
- V = Builder.CreateAnd(V, Builder.getInt32(1));
+ llvm::Value *Test1 = llvm::ConstantInt::get(guardTy, 1);
+ V = Builder.CreateAnd(V, Test1);
isInitialized = Builder.CreateIsNull(V, "guard.uninitialized");
// Itanium C++ ABI 3.3.2:
@@ -1100,7 +1148,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
if (threadsafe) {
// Call __cxa_guard_acquire.
llvm::Value *V
- = Builder.CreateCall(getGuardAcquireFn(CGM, guardPtrTy), guard);
+ = CGF.EmitNounwindRuntimeCall(getGuardAcquireFn(CGM, guardPtrTy), guard);
llvm::BasicBlock *InitBlock = CGF.createBasicBlock("init");
@@ -1121,7 +1169,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
CGF.PopCleanupBlock();
// Call __cxa_guard_release. This cannot throw.
- Builder.CreateCall(getGuardReleaseFn(CGM, guardPtrTy), guard);
+ CGF.EmitNounwindRuntimeCall(getGuardReleaseFn(CGM, guardPtrTy), guard);
} else {
Builder.CreateStore(llvm::ConstantInt::get(guardTy, 1), guard);
}
@@ -1159,7 +1207,7 @@ static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF,
llvm::ConstantExpr::getBitCast(addr, CGF.Int8PtrTy),
handle
};
- CGF.Builder.CreateCall(atexit, args)->setDoesNotThrow();
+ CGF.EmitNounwindRuntimeCall(atexit, args);
}
/// Register a global destructor as best as we know how.
@@ -1180,8 +1228,3 @@ void ItaniumCXXABI::registerGlobalDtor(CodeGenFunction &CGF,
CGF.registerGlobalDtorWithAtExit(dtor, addr);
}
-
-/// Generate and emit virtual tables for the given class.
-void ItaniumCXXABI::EmitVTables(const CXXRecordDecl *Class) {
- CGM.getVTables().GenerateClassData(CGM.getVTableLinkage(Class), Class);
-}
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp
index 8d205c3..00b15c9 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -42,13 +42,12 @@ public:
CanQualType &ResTy,
SmallVectorImpl<CanQualType> &ArgTys);
+ llvm::BasicBlock *EmitCtorCompleteObjectHandler(CodeGenFunction &CGF);
+
void BuildDestructorSignature(const CXXDestructorDecl *Ctor,
CXXDtorType Type,
CanQualType &ResTy,
- SmallVectorImpl<CanQualType> &ArgTys) {
- // 'this' is already in place
- // TODO: 'for base' flag
- }
+ SmallVectorImpl<CanQualType> &ArgTys);
void BuildInstanceFunctionParams(CodeGenFunction &CGF,
QualType &ResTy,
@@ -56,13 +55,25 @@ public:
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
+ llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,
+ const CXXConstructorDecl *D,
+ CXXCtorType Type, bool ForVirtualBase,
+ bool Delegating,
+ llvm::Value *This,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd);
+
+ RValue EmitVirtualDestructorCall(CodeGenFunction &CGF,
+ const CXXDestructorDecl *Dtor,
+ CXXDtorType DtorType,
+ SourceLocation CallLoc,
+ ReturnValueSlot ReturnValue,
+ llvm::Value *This);
+
void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
llvm::GlobalVariable *DeclPtr,
bool PerformInit);
- void EmitVTables(const CXXRecordDecl *Class);
-
-
// ==== Notes on array cookies =========
//
// MSVC seems to only use cookies when the class has a destructor; a
@@ -98,6 +109,33 @@ public:
llvm::Value *allocPtr,
CharUnits cookieSize);
static bool needThisReturn(GlobalDecl GD);
+
+private:
+ llvm::Constant *getSimpleNullMemberPointer(const MemberPointerType *MPT);
+
+ llvm::Constant *getZeroPtrDiff() {
+ return llvm::ConstantInt::get(CGM.PtrDiffTy, 0);
+ }
+
+ llvm::Constant *getAllOnesPtrDiff() {
+ return llvm::Constant::getAllOnesValue(CGM.PtrDiffTy);
+ }
+
+public:
+ virtual llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT);
+
+ virtual llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT,
+ CharUnits offset);
+
+ virtual llvm::Value *EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
+ llvm::Value *MemPtr,
+ const MemberPointerType *MPT);
+
+ virtual llvm::Value *EmitMemberDataPointerAddress(CodeGenFunction &CGF,
+ llvm::Value *Base,
+ llvm::Value *MemPtr,
+ const MemberPointerType *MPT);
+
};
}
@@ -119,9 +157,57 @@ void MicrosoftCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor,
CanQualType &ResTy,
SmallVectorImpl<CanQualType> &ArgTys) {
// 'this' is already in place
- // TODO: 'for base' flag
+
// Ctor returns this ptr
ResTy = ArgTys[0];
+
+ const CXXRecordDecl *Class = Ctor->getParent();
+ if (Class->getNumVBases()) {
+ // Constructors of classes with virtual bases take an implicit parameter.
+ ArgTys.push_back(CGM.getContext().IntTy);
+ }
+}
+
+llvm::BasicBlock *MicrosoftCXXABI::EmitCtorCompleteObjectHandler(
+ CodeGenFunction &CGF) {
+ llvm::Value *IsMostDerivedClass = getStructorImplicitParamValue(CGF);
+ assert(IsMostDerivedClass &&
+ "ctor for a class with virtual bases must have an implicit parameter");
+ llvm::Value *IsCompleteObject
+ = CGF.Builder.CreateIsNotNull(IsMostDerivedClass, "is_complete_object");
+
+ llvm::BasicBlock *CallVbaseCtorsBB = CGF.createBasicBlock("ctor.init_vbases");
+ llvm::BasicBlock *SkipVbaseCtorsBB = CGF.createBasicBlock("ctor.skip_vbases");
+ CGF.Builder.CreateCondBr(IsCompleteObject,
+ CallVbaseCtorsBB, SkipVbaseCtorsBB);
+
+ CGF.EmitBlock(CallVbaseCtorsBB);
+ // FIXME: emit vbtables somewhere around here.
+
+ // CGF will put the base ctor calls in this basic block for us later.
+
+ return SkipVbaseCtorsBB;
+}
+
+void MicrosoftCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor,
+ CXXDtorType Type,
+ CanQualType &ResTy,
+ SmallVectorImpl<CanQualType> &ArgTys) {
+ // 'this' is already in place
+ // TODO: 'for base' flag
+
+ if (Type == Dtor_Deleting) {
+ // The scalar deleting destructor takes an implicit bool parameter.
+ ArgTys.push_back(CGM.getContext().BoolTy);
+ }
+}
+
+static bool IsDeletingDtor(GlobalDecl GD) {
+ const CXXMethodDecl* MD = cast<CXXMethodDecl>(GD.getDecl());
+ if (isa<CXXDestructorDecl>(MD)) {
+ return GD.getDtorType() == Dtor_Deleting;
+ }
+ return false;
}
void MicrosoftCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
@@ -131,6 +217,26 @@ void MicrosoftCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF,
if (needThisReturn(CGF.CurGD)) {
ResTy = Params[0]->getType();
}
+
+ ASTContext &Context = getContext();
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
+ if (isa<CXXConstructorDecl>(MD) && MD->getParent()->getNumVBases()) {
+ ImplicitParamDecl *IsMostDerived
+ = ImplicitParamDecl::Create(Context, 0,
+ CGF.CurGD.getDecl()->getLocation(),
+ &Context.Idents.get("is_most_derived"),
+ Context.IntTy);
+ Params.push_back(IsMostDerived);
+ getStructorImplicitParamDecl(CGF) = IsMostDerived;
+ } else if (IsDeletingDtor(CGF.CurGD)) {
+ ImplicitParamDecl *ShouldDelete
+ = ImplicitParamDecl::Create(Context, 0,
+ CGF.CurGD.getDecl()->getLocation(),
+ &Context.Idents.get("should_call_delete"),
+ Context.BoolTy);
+ Params.push_back(ShouldDelete);
+ getStructorImplicitParamDecl(CGF) = ShouldDelete;
+ }
}
void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
@@ -138,6 +244,73 @@ void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
if (needThisReturn(CGF.CurGD)) {
CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
}
+
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
+ if (isa<CXXConstructorDecl>(MD) && MD->getParent()->getNumVBases()) {
+ assert(getStructorImplicitParamDecl(CGF) &&
+ "no implicit parameter for a constructor with virtual bases?");
+ getStructorImplicitParamValue(CGF)
+ = CGF.Builder.CreateLoad(
+ CGF.GetAddrOfLocalVar(getStructorImplicitParamDecl(CGF)),
+ "is_most_derived");
+ }
+
+ if (IsDeletingDtor(CGF.CurGD)) {
+ assert(getStructorImplicitParamDecl(CGF) &&
+ "no implicit parameter for a deleting destructor?");
+ getStructorImplicitParamValue(CGF)
+ = CGF.Builder.CreateLoad(
+ CGF.GetAddrOfLocalVar(getStructorImplicitParamDecl(CGF)),
+ "should_call_delete");
+ }
+}
+
+llvm::Value *MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
+ const CXXConstructorDecl *D,
+ CXXCtorType Type, bool ForVirtualBase,
+ bool Delegating,
+ llvm::Value *This,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd) {
+ assert(Type == Ctor_Complete || Type == Ctor_Base);
+ llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Ctor_Complete);
+
+ llvm::Value *ImplicitParam = 0;
+ QualType ImplicitParamTy;
+ if (D->getParent()->getNumVBases()) {
+ ImplicitParam = llvm::ConstantInt::get(CGM.Int32Ty, Type == Ctor_Complete);
+ ImplicitParamTy = getContext().IntTy;
+ }
+
+ // FIXME: Provide a source location here.
+ CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
+ ImplicitParam, ImplicitParamTy,
+ ArgBeg, ArgEnd);
+ return Callee;
+}
+
+RValue MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
+ const CXXDestructorDecl *Dtor,
+ CXXDtorType DtorType,
+ SourceLocation CallLoc,
+ ReturnValueSlot ReturnValue,
+ llvm::Value *This) {
+ assert(DtorType == Dtor_Deleting || DtorType == Dtor_Complete);
+
+ // We have only one destructor in the vftable but can get both behaviors
+ // by passing an implicit bool parameter.
+ const CGFunctionInfo *FInfo
+ = &CGM.getTypes().arrangeCXXDestructor(Dtor, Dtor_Deleting);
+ llvm::Type *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo);
+ llvm::Value *Callee = CGF.BuildVirtualCall(Dtor, Dtor_Deleting, This, Ty);
+
+ ASTContext &Context = CGF.getContext();
+ llvm::Value *ImplicitParam
+ = llvm::ConstantInt::get(llvm::IntegerType::getInt1Ty(CGF.getLLVMContext()),
+ DtorType == Dtor_Deleting);
+
+ return CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValue, This,
+ ImplicitParam, Context.BoolTy, 0, 0);
}
bool MicrosoftCXXABI::requiresArrayCookie(const CXXDeleteExpr *expr,
@@ -206,8 +379,93 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
CGF.EmitCXXGlobalVarDeclInit(D, DeclPtr, PerformInit);
}
-void MicrosoftCXXABI::EmitVTables(const CXXRecordDecl *Class) {
- // FIXME: implement
+// Returns true for member pointer types that we know how to represent with a
+// simple ptrdiff_t. Currently we only know how to emit, test, and load member
+// data pointers for complete single inheritance classes.
+static bool isSimpleMemberPointer(const MemberPointerType *MPT) {
+ const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
+ return (MPT->isMemberDataPointer() &&
+ !MPT->getClass()->isIncompleteType() &&
+ RD->getNumVBases() == 0);
+}
+
+llvm::Constant *
+MicrosoftCXXABI::getSimpleNullMemberPointer(const MemberPointerType *MPT) {
+ if (isSimpleMemberPointer(MPT)) {
+ const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
+ // A null member data pointer is represented as -1 if the class is not
+ // polymorphic, and 0 otherwise.
+ if (RD->isPolymorphic())
+ return getZeroPtrDiff();
+ return getAllOnesPtrDiff();
+ }
+ return GetBogusMemberPointer(QualType(MPT, 0));
+}
+
+llvm::Constant *
+MicrosoftCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) {
+ if (isSimpleMemberPointer(MPT))
+ return getSimpleNullMemberPointer(MPT);
+ // FIXME: Implement function member pointers.
+ return GetBogusMemberPointer(QualType(MPT, 0));
+}
+
+llvm::Constant *
+MicrosoftCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
+ CharUnits offset) {
+ // Member data pointers are plain offsets when no virtual bases are involved.
+ if (isSimpleMemberPointer(MPT))
+ return llvm::ConstantInt::get(CGM.PtrDiffTy, offset.getQuantity());
+ // FIXME: Implement member pointers other inheritance models.
+ return GetBogusMemberPointer(QualType(MPT, 0));
+}
+
+llvm::Value *
+MicrosoftCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
+ llvm::Value *MemPtr,
+ const MemberPointerType *MPT) {
+ CGBuilderTy &Builder = CGF.Builder;
+
+ // For member data pointers, this is just a check against -1 or 0.
+ if (isSimpleMemberPointer(MPT)) {
+ llvm::Constant *Val = getSimpleNullMemberPointer(MPT);
+ return Builder.CreateICmpNE(MemPtr, Val, "memptr.tobool");
+ }
+
+ // FIXME: Implement member pointers other inheritance models.
+ ErrorUnsupportedABI(CGF, "function member pointer tests");
+ return GetBogusMemberPointer(QualType(MPT, 0));
+}
+
+llvm::Value *
+MicrosoftCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF,
+ llvm::Value *Base,
+ llvm::Value *MemPtr,
+ const MemberPointerType *MPT) {
+ unsigned AS = Base->getType()->getPointerAddressSpace();
+ llvm::Type *PType =
+ CGF.ConvertTypeForMem(MPT->getPointeeType())->getPointerTo(AS);
+ CGBuilderTy &Builder = CGF.Builder;
+
+ if (MPT->isMemberFunctionPointer()) {
+ ErrorUnsupportedABI(CGF, "function member pointer address");
+ return llvm::Constant::getNullValue(PType);
+ }
+
+ llvm::Value *Addr;
+ if (isSimpleMemberPointer(MPT)) {
+ // Add the offset with GEP and i8*.
+ assert(MemPtr->getType() == CGM.PtrDiffTy);
+ Base = Builder.CreateBitCast(Base, Builder.getInt8Ty()->getPointerTo(AS));
+ Addr = Builder.CreateInBoundsGEP(Base, MemPtr, "memptr.offset");
+ } else {
+ ErrorUnsupportedABI(CGF, "non-scalar member pointers");
+ return llvm::Constant::getNullValue(PType);
+ }
+
+ // Cast the address to the appropriate pointer type, adopting the address
+ // space of the base pointer.
+ return Builder.CreateBitCast(Addr, PType);
}
CGCXXABI *clang::CodeGen::CreateMicrosoftCXXABI(CodeGenModule &CGM) {
diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp
index 0125559..d6e5f06 100644
--- a/lib/CodeGen/ModuleBuilder.cpp
+++ b/lib/CodeGen/ModuleBuilder.cpp
@@ -13,16 +13,16 @@
#include "clang/CodeGen/ModuleBuilder.h"
#include "CodeGenModule.h"
-#include "clang/Frontend/CodeGenOptions.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/TargetInfo.h"
-#include "llvm/LLVMContext.h"
-#include "llvm/Module.h"
-#include "llvm/DataLayout.h"
+#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
using namespace clang;
namespace {
@@ -31,13 +31,16 @@ namespace {
OwningPtr<const llvm::DataLayout> TD;
ASTContext *Ctx;
const CodeGenOptions CodeGenOpts; // Intentionally copied in.
+ const TargetOptions TargetOpts; // Intentionally copied in.
protected:
OwningPtr<llvm::Module> M;
OwningPtr<CodeGen::CodeGenModule> Builder;
public:
CodeGeneratorImpl(DiagnosticsEngine &diags, const std::string& ModuleName,
- const CodeGenOptions &CGO, llvm::LLVMContext& C)
- : Diags(diags), CodeGenOpts(CGO), M(new llvm::Module(ModuleName, C)) {}
+ const CodeGenOptions &CGO, const TargetOptions &TO,
+ llvm::LLVMContext& C)
+ : Diags(diags), CodeGenOpts(CGO), TargetOpts(TO),
+ M(new llvm::Module(ModuleName, C)) {}
virtual ~CodeGeneratorImpl() {}
@@ -55,7 +58,7 @@ namespace {
M->setTargetTriple(Ctx->getTargetInfo().getTriple().getTriple());
M->setDataLayout(Ctx->getTargetInfo().getTargetDescription());
TD.reset(new llvm::DataLayout(Ctx->getTargetInfo().getTargetDescription()));
- Builder.reset(new CodeGen::CodeGenModule(Context, CodeGenOpts,
+ Builder.reset(new CodeGen::CodeGenModule(Context, CodeGenOpts, TargetOpts,
*M, *TD, Diags));
}
@@ -122,6 +125,7 @@ void CodeGenerator::anchor() { }
CodeGenerator *clang::CreateLLVMCodeGen(DiagnosticsEngine &Diags,
const std::string& ModuleName,
const CodeGenOptions &CGO,
+ const TargetOptions &TO,
llvm::LLVMContext& C) {
- return new CodeGeneratorImpl(Diags, ModuleName, CGO, C);
+ return new CodeGeneratorImpl(Diags, ModuleName, CGO, TO, C);
}
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index ffff0d0..7cc63b7 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -17,9 +17,9 @@
#include "CodeGenFunction.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Frontend/CodeGenOptions.h"
-#include "llvm/Type.h"
-#include "llvm/DataLayout.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Type.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace CodeGen;
@@ -37,7 +37,7 @@ static void AssignToArrayRange(CodeGen::CGBuilderTy &Builder,
}
static bool isAggregateTypeForABI(QualType T) {
- return CodeGenFunction::hasAggregateLLVMType(T) ||
+ return !CodeGenFunction::hasScalarEvaluationKind(T) ||
T->isMemberFunctionPointerType();
}
@@ -95,6 +95,7 @@ unsigned TargetCodeGenInfo::getSizeOfUnwindException() const {
// x86-32 FreeBSD, Linux, Darwin
// PowerPC Linux, Darwin
// ARM Darwin (*not* EABI)
+ // AArch64 Linux
return 32;
}
@@ -173,7 +174,7 @@ static bool hasNonTrivialDestructorOrCopyConstructor(const RecordType *RT) {
if (!RD)
return false;
- return !RD->hasTrivialDestructor() || !RD->hasTrivialCopyConstructor();
+ return !RD->hasTrivialDestructor() || RD->hasNonTrivialCopyConstructor();
}
/// isRecordWithNonTrivialDestructorOrCopyConstructor - Determine if a type is
@@ -266,9 +267,15 @@ static const Type *isSingleElementStruct(QualType T, ASTContext &Context) {
}
static bool is32Or64BitBasicType(QualType Ty, ASTContext &Context) {
+ // Treat complex types as the element type.
+ if (const ComplexType *CTy = Ty->getAs<ComplexType>())
+ Ty = CTy->getElementType();
+
+ // Check for a type which we know has a simple scalar argument-passing
+ // convention without any padding. (We're specifically looking for 32
+ // and 64-bit integer and integer-equivalents, float, and double.)
if (!Ty->getAs<BuiltinType>() && !Ty->hasPointerRepresentation() &&
- !Ty->isAnyComplexType() && !Ty->isEnumeralType() &&
- !Ty->isBlockPointerType())
+ !Ty->isEnumeralType() && !Ty->isBlockPointerType())
return false;
uint64_t Size = Context.getTypeSize(Ty);
@@ -414,6 +421,8 @@ class PNaClTargetCodeGenInfo : public TargetCodeGenInfo {
void PNaClABIInfo::computeInfo(CGFunctionInfo &FI) const {
FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
+ // Obtain the initial number of registers available for passing integers
+ // from the function's regparm attribute.
unsigned FreeRegs = FI.getHasRegParm() ? FI.getRegParm() : 0;
for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
@@ -426,15 +435,18 @@ llvm::Value *PNaClABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
return 0;
}
+// \brief Classify argument of given type \p Ty. \p FreeRegs is the number of
+// registers available for passing arguments - it can be updated by this
+// method.
ABIArgInfo PNaClABIInfo::classifyArgumentType(QualType Ty,
unsigned &FreeRegs) const {
if (isAggregateTypeForABI(Ty)) {
- // Records with non trivial destructors/constructors should not be passed
- // by value.
+ // In the PNaCl ABI we always pass records/structures on the stack. The
+ // byval attribute can be used if the record doesn't have non-trivial
+ // constructors/destructors.
FreeRegs = 0;
if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty))
return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
-
return ABIArgInfo::getIndirect(0);
}
@@ -445,14 +457,17 @@ ABIArgInfo PNaClABIInfo::classifyArgumentType(QualType Ty,
ABIArgInfo BaseInfo = (Ty->isPromotableIntegerType() ?
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
- // Regparm regs hold 32 bits.
- unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32;
- if (SizeInRegs == 0) return BaseInfo;
- if (SizeInRegs > FreeRegs) {
+ // Figure out how many of the free registers can be occupied by this type.
+ // regparm registers are 32-bit.
+ unsigned NumRegsRequired = (getContext().getTypeSize(Ty) + 31) / 32;
+ if (NumRegsRequired == 0) return BaseInfo;
+ if (NumRegsRequired > FreeRegs) {
+ // If this type needs more registers than we have available, no more
+ // passing in-registers can happen.
FreeRegs = 0;
return BaseInfo;
}
- FreeRegs -= SizeInRegs;
+ FreeRegs -= NumRegsRequired;
return BaseInfo.isDirect() ?
ABIArgInfo::getDirectInReg(BaseInfo.getCoerceToType()) :
ABIArgInfo::getExtendInReg(BaseInfo.getCoerceToType());
@@ -462,6 +477,7 @@ ABIArgInfo PNaClABIInfo::classifyReturnType(QualType RetTy) const {
if (RetTy->isVoidType())
return ABIArgInfo::getIgnore();
+ // In the PNaCl ABI we always return records/structures on the stack.
if (isAggregateTypeForABI(RetTy))
return ABIArgInfo::getIndirect(0);
@@ -473,11 +489,9 @@ ABIArgInfo PNaClABIInfo::classifyReturnType(QualType RetTy) const {
ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
}
-/// UseX86_MMXType - Return true if this is an MMX type that should use the
-/// special x86_mmx type.
-bool UseX86_MMXType(llvm::Type *IRType) {
- // If the type is an MMX type <2 x i32>, <4 x i16>, or <8 x i8>, use the
- // special x86_mmx type.
+/// IsX86_MMXType - Return true if this is an MMX type.
+bool IsX86_MMXType(llvm::Type *IRType) {
+ // Return true if the type is an MMX type <2 x i32>, <4 x i16>, or <8 x i8>.
return IRType->isVectorTy() && IRType->getPrimitiveSizeInBits() == 64 &&
cast<llvm::VectorType>(IRType)->getElementType()->isIntegerTy() &&
IRType->getScalarSizeInBits() != 64;
@@ -506,7 +520,6 @@ class X86_32ABIInfo : public ABIInfo {
bool IsDarwinVectorABI;
bool IsSmallStructInRegABI;
- bool IsMMXDisabled;
bool IsWin32FloatStructABI;
unsigned DefaultNumRegisterParameters;
@@ -539,18 +552,17 @@ public:
virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const;
- X86_32ABIInfo(CodeGen::CodeGenTypes &CGT, bool d, bool p, bool m, bool w,
+ X86_32ABIInfo(CodeGen::CodeGenTypes &CGT, bool d, bool p, bool w,
unsigned r)
: ABIInfo(CGT), IsDarwinVectorABI(d), IsSmallStructInRegABI(p),
- IsMMXDisabled(m), IsWin32FloatStructABI(w),
- DefaultNumRegisterParameters(r) {}
+ IsWin32FloatStructABI(w), DefaultNumRegisterParameters(r) {}
};
class X86_32TargetCodeGenInfo : public TargetCodeGenInfo {
public:
X86_32TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT,
- bool d, bool p, bool m, bool w, unsigned r)
- :TargetCodeGenInfo(new X86_32ABIInfo(CGT, d, p, m, w, r)) {}
+ bool d, bool p, bool w, unsigned r)
+ :TargetCodeGenInfo(new X86_32ABIInfo(CGT, d, p, w, r)) {}
void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
CodeGen::CodeGenModule &CGM) const;
@@ -903,15 +915,8 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
Size));
}
- llvm::Type *IRType = CGT.ConvertType(Ty);
- if (UseX86_MMXType(IRType)) {
- if (IsMMXDisabled)
- return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),
- 64));
- ABIArgInfo AAI = ABIArgInfo::getDirect(IRType);
- AAI.setCoerceToType(llvm::Type::getX86_MMXTy(getVMContext()));
- return AAI;
- }
+ if (IsX86_MMXType(CGT.ConvertType(Ty)))
+ return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), 64));
return ABIArgInfo::getDirect();
}
@@ -1013,8 +1018,10 @@ void X86_32TargetCodeGenInfo::SetTargetAttributes(const Decl *D,
// Now add the 'alignstack' attribute with a value of 16.
llvm::AttrBuilder B;
B.addStackAlignmentAttr(16);
- Fn->addAttribute(llvm::AttrListPtr::FunctionIndex,
- llvm::Attributes::get(CGM.getLLVMContext(), B));
+ Fn->addAttributes(llvm::AttributeSet::FunctionIndex,
+ llvm::AttributeSet::get(CGM.getLLVMContext(),
+ llvm::AttributeSet::FunctionIndex,
+ B));
}
}
}
@@ -1381,7 +1388,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
} else if ((k == BuiltinType::Float || k == BuiltinType::Double) ||
(k == BuiltinType::LongDouble &&
getContext().getTargetInfo().getTriple().getOS() ==
- llvm::Triple::NativeClient)) {
+ llvm::Triple::NaCl)) {
Current = SSE;
} else if (k == BuiltinType::LongDouble) {
Lo = X87;
@@ -1470,7 +1477,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
else if (ET == getContext().DoubleTy ||
(ET == getContext().LongDoubleTy &&
getContext().getTargetInfo().getTriple().getOS() ==
- llvm::Triple::NativeClient))
+ llvm::Triple::NaCl))
Lo = Hi = SSE;
else if (ET == getContext().LongDoubleTy)
Current = ComplexX87;
@@ -2777,6 +2784,9 @@ PPC64_SVR4_ABIInfo::isPromotableTypeForABI(QualType Ty) const {
ABIArgInfo
PPC64_SVR4_ABIInfo::classifyArgumentType(QualType Ty) const {
+ if (Ty->isAnyComplexType())
+ return ABIArgInfo::getDirect();
+
if (isAggregateTypeForABI(Ty)) {
// Records with non trivial destructors/constructors should not be passed
// by value.
@@ -2795,6 +2805,9 @@ PPC64_SVR4_ABIInfo::classifyReturnType(QualType RetTy) const {
if (RetTy->isVoidType())
return ABIArgInfo::getIgnore();
+ if (RetTy->isAnyComplexType())
+ return ABIArgInfo::getDirect();
+
if (isAggregateTypeForABI(RetTy))
return ABIArgInfo::getIndirect(0);
@@ -2813,14 +2826,52 @@ llvm::Value *PPC64_SVR4_ABIInfo::EmitVAArg(llvm::Value *VAListAddr,
llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, "ap");
llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur");
- // Update the va_list pointer.
+ // Update the va_list pointer. The pointer should be bumped by the
+ // size of the object. We can trust getTypeSize() except for a complex
+ // type whose base type is smaller than a doubleword. For these, the
+ // size of the object is 16 bytes; see below for further explanation.
unsigned SizeInBytes = CGF.getContext().getTypeSize(Ty) / 8;
+ QualType BaseTy;
+ unsigned CplxBaseSize = 0;
+
+ if (const ComplexType *CTy = Ty->getAs<ComplexType>()) {
+ BaseTy = CTy->getElementType();
+ CplxBaseSize = CGF.getContext().getTypeSize(BaseTy) / 8;
+ if (CplxBaseSize < 8)
+ SizeInBytes = 16;
+ }
+
unsigned Offset = llvm::RoundUpToAlignment(SizeInBytes, 8);
llvm::Value *NextAddr =
Builder.CreateGEP(Addr, llvm::ConstantInt::get(CGF.Int64Ty, Offset),
"ap.next");
Builder.CreateStore(NextAddr, VAListAddrAsBPP);
+ // If we have a complex type and the base type is smaller than 8 bytes,
+ // the ABI calls for the real and imaginary parts to be right-adjusted
+ // in separate doublewords. However, Clang expects us to produce a
+ // pointer to a structure with the two parts packed tightly. So generate
+ // loads of the real and imaginary parts relative to the va_list pointer,
+ // and store them to a temporary structure.
+ if (CplxBaseSize && CplxBaseSize < 8) {
+ llvm::Value *RealAddr = Builder.CreatePtrToInt(Addr, CGF.Int64Ty);
+ llvm::Value *ImagAddr = RealAddr;
+ RealAddr = Builder.CreateAdd(RealAddr, Builder.getInt64(8 - CplxBaseSize));
+ ImagAddr = Builder.CreateAdd(ImagAddr, Builder.getInt64(16 - CplxBaseSize));
+ llvm::Type *PBaseTy = llvm::PointerType::getUnqual(CGF.ConvertType(BaseTy));
+ RealAddr = Builder.CreateIntToPtr(RealAddr, PBaseTy);
+ ImagAddr = Builder.CreateIntToPtr(ImagAddr, PBaseTy);
+ llvm::Value *Real = Builder.CreateLoad(RealAddr, false, ".vareal");
+ llvm::Value *Imag = Builder.CreateLoad(ImagAddr, false, ".vaimag");
+ llvm::Value *Ptr = CGF.CreateTempAlloca(CGT.ConvertTypeForMem(Ty),
+ "vacplx");
+ llvm::Value *RealPtr = Builder.CreateStructGEP(Ptr, 0, ".real");
+ llvm::Value *ImagPtr = Builder.CreateStructGEP(Ptr, 1, ".imag");
+ Builder.CreateStore(Real, RealPtr, false);
+ Builder.CreateStore(Imag, ImagPtr, false);
+ return Ptr;
+ }
+
// If the argument is smaller than 8 bytes, it is right-adjusted in
// its doubleword slot. Adjust the pointer to pick it up from the
// correct offset.
@@ -2908,7 +2959,9 @@ private:
ABIKind Kind;
public:
- ARMABIInfo(CodeGenTypes &CGT, ABIKind _Kind) : ABIInfo(CGT), Kind(_Kind) {}
+ ARMABIInfo(CodeGenTypes &CGT, ABIKind _Kind) : ABIInfo(CGT), Kind(_Kind) {
+ setRuntimeCC();
+ }
bool isEABI() const {
StringRef Env =
@@ -2930,6 +2983,10 @@ private:
virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const;
+
+ llvm::CallingConv::ID getLLVMDefaultCC() const;
+ llvm::CallingConv::ID getABIDefaultCC() const;
+ void setRuntimeCC();
};
class ARMTargetCodeGenInfo : public TargetCodeGenInfo {
@@ -2999,32 +3056,41 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const {
if (FI.getCallingConvention() != llvm::CallingConv::C)
return;
- // Calling convention as default by an ABI.
- llvm::CallingConv::ID DefaultCC;
+ llvm::CallingConv::ID cc = getRuntimeCC();
+ if (cc != llvm::CallingConv::C)
+ FI.setEffectiveCallingConvention(cc);
+}
+
+/// Return the default calling convention that LLVM will use.
+llvm::CallingConv::ID ARMABIInfo::getLLVMDefaultCC() const {
+ // The default calling convention that LLVM will infer.
if (getContext().getTargetInfo().getTriple().getEnvironmentName()=="gnueabihf")
- DefaultCC = llvm::CallingConv::ARM_AAPCS_VFP;
+ return llvm::CallingConv::ARM_AAPCS_VFP;
else if (isEABI())
- DefaultCC = llvm::CallingConv::ARM_AAPCS;
+ return llvm::CallingConv::ARM_AAPCS;
else
- DefaultCC = llvm::CallingConv::ARM_APCS;
+ return llvm::CallingConv::ARM_APCS;
+}
- // If user did not ask for specific calling convention explicitly (e.g. via
- // pcs attribute), set effective calling convention if it's different than ABI
- // default.
+/// Return the calling convention that our ABI would like us to use
+/// as the C calling convention.
+llvm::CallingConv::ID ARMABIInfo::getABIDefaultCC() const {
switch (getABIKind()) {
- case APCS:
- if (DefaultCC != llvm::CallingConv::ARM_APCS)
- FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_APCS);
- break;
- case AAPCS:
- if (DefaultCC != llvm::CallingConv::ARM_AAPCS)
- FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_AAPCS);
- break;
- case AAPCS_VFP:
- if (DefaultCC != llvm::CallingConv::ARM_AAPCS_VFP)
- FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_AAPCS_VFP);
- break;
+ case APCS: return llvm::CallingConv::ARM_APCS;
+ case AAPCS: return llvm::CallingConv::ARM_AAPCS;
+ case AAPCS_VFP: return llvm::CallingConv::ARM_AAPCS_VFP;
}
+ llvm_unreachable("bad ABI kind");
+}
+
+void ARMABIInfo::setRuntimeCC() {
+ assert(getRuntimeCC() == llvm::CallingConv::C);
+
+ // Don't muddy up the IR with a ton of explicit annotations if
+ // they'd just match what LLVM will infer from the triple.
+ llvm::CallingConv::ID abiCC = getABIDefaultCC();
+ if (abiCC != getLLVMDefaultCC())
+ RuntimeCC = abiCC;
}
/// isHomogeneousAggregate - Return true if a type is an AAPCS-VFP homogeneous
@@ -3539,6 +3605,420 @@ llvm::Value *NaClARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
}
//===----------------------------------------------------------------------===//
+// AArch64 ABI Implementation
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class AArch64ABIInfo : public ABIInfo {
+public:
+ AArch64ABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {}
+
+private:
+ // The AArch64 PCS is explicit about return types and argument types being
+ // handled identically, so we don't need to draw a distinction between
+ // Argument and Return classification.
+ ABIArgInfo classifyGenericType(QualType Ty, int &FreeIntRegs,
+ int &FreeVFPRegs) const;
+
+ ABIArgInfo tryUseRegs(QualType Ty, int &FreeRegs, int RegsNeeded, bool IsInt,
+ llvm::Type *DirectTy = 0) const;
+
+ virtual void computeInfo(CGFunctionInfo &FI) const;
+
+ virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const;
+};
+
+class AArch64TargetCodeGenInfo : public TargetCodeGenInfo {
+public:
+ AArch64TargetCodeGenInfo(CodeGenTypes &CGT)
+ :TargetCodeGenInfo(new AArch64ABIInfo(CGT)) {}
+
+ const AArch64ABIInfo &getABIInfo() const {
+ return static_cast<const AArch64ABIInfo&>(TargetCodeGenInfo::getABIInfo());
+ }
+
+ int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const {
+ return 31;
+ }
+
+ bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
+ llvm::Value *Address) const {
+ // 0-31 are x0-x30 and sp: 8 bytes each
+ llvm::Value *Eight8 = llvm::ConstantInt::get(CGF.Int8Ty, 8);
+ AssignToArrayRange(CGF.Builder, Address, Eight8, 0, 31);
+
+ // 64-95 are v0-v31: 16 bytes each
+ llvm::Value *Sixteen8 = llvm::ConstantInt::get(CGF.Int8Ty, 16);
+ AssignToArrayRange(CGF.Builder, Address, Sixteen8, 64, 95);
+
+ return false;
+ }
+
+};
+
+}
+
+void AArch64ABIInfo::computeInfo(CGFunctionInfo &FI) const {
+ int FreeIntRegs = 8, FreeVFPRegs = 8;
+
+ FI.getReturnInfo() = classifyGenericType(FI.getReturnType(),
+ FreeIntRegs, FreeVFPRegs);
+
+ FreeIntRegs = FreeVFPRegs = 8;
+ for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
+ it != ie; ++it) {
+ it->info = classifyGenericType(it->type, FreeIntRegs, FreeVFPRegs);
+
+ }
+}
+
+ABIArgInfo
+AArch64ABIInfo::tryUseRegs(QualType Ty, int &FreeRegs, int RegsNeeded,
+ bool IsInt, llvm::Type *DirectTy) const {
+ if (FreeRegs >= RegsNeeded) {
+ FreeRegs -= RegsNeeded;
+ return ABIArgInfo::getDirect(DirectTy);
+ }
+
+ llvm::Type *Padding = 0;
+
+ // We need padding so that later arguments don't get filled in anyway. That
+ // wouldn't happen if only ByVal arguments followed in the same category, but
+ // a large structure will simply seem to be a pointer as far as LLVM is
+ // concerned.
+ if (FreeRegs > 0) {
+ if (IsInt)
+ Padding = llvm::Type::getInt64Ty(getVMContext());
+ else
+ Padding = llvm::Type::getFloatTy(getVMContext());
+
+ // Either [N x i64] or [N x float].
+ Padding = llvm::ArrayType::get(Padding, FreeRegs);
+ FreeRegs = 0;
+ }
+
+ return ABIArgInfo::getIndirect(getContext().getTypeAlign(Ty) / 8,
+ /*IsByVal=*/ true, /*Realign=*/ false,
+ Padding);
+}
+
+
+ABIArgInfo AArch64ABIInfo::classifyGenericType(QualType Ty,
+ int &FreeIntRegs,
+ int &FreeVFPRegs) const {
+ // Can only occurs for return, but harmless otherwise.
+ if (Ty->isVoidType())
+ return ABIArgInfo::getIgnore();
+
+ // Large vector types should be returned via memory. There's no such concept
+ // in the ABI, but they'd be over 16 bytes anyway so no matter how they're
+ // classified they'd go into memory (see B.3).
+ if (Ty->isVectorType() && getContext().getTypeSize(Ty) > 128) {
+ if (FreeIntRegs > 0)
+ --FreeIntRegs;
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+ }
+
+ // All non-aggregate LLVM types have a concrete ABI representation so they can
+ // be passed directly. After this block we're guaranteed to be in a
+ // complicated case.
+ if (!isAggregateTypeForABI(Ty)) {
+ // Treat an enum type as its underlying type.
+ if (const EnumType *EnumTy = Ty->getAs<EnumType>())
+ Ty = EnumTy->getDecl()->getIntegerType();
+
+ if (Ty->isFloatingType() || Ty->isVectorType())
+ return tryUseRegs(Ty, FreeVFPRegs, /*RegsNeeded=*/ 1, /*IsInt=*/ false);
+
+ assert(getContext().getTypeSize(Ty) <= 128 &&
+ "unexpectedly large scalar type");
+
+ int RegsNeeded = getContext().getTypeSize(Ty) > 64 ? 2 : 1;
+
+ // If the type may need padding registers to ensure "alignment", we must be
+ // careful when this is accounted for. Increasing the effective size covers
+ // all cases.
+ if (getContext().getTypeAlign(Ty) == 128)
+ RegsNeeded += FreeIntRegs % 2 != 0;
+
+ return tryUseRegs(Ty, FreeIntRegs, RegsNeeded, /*IsInt=*/ true);
+ }
+
+ // Structures with either a non-trivial destructor or a non-trivial
+ // copy constructor are always indirect.
+ if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) {
+ if (FreeIntRegs > 0)
+ --FreeIntRegs;
+ return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+ }
+
+ if (isEmptyRecord(getContext(), Ty, true)) {
+ if (!getContext().getLangOpts().CPlusPlus) {
+ // Empty structs outside C++ mode are a GNU extension, so no ABI can
+ // possibly tell us what to do. It turns out (I believe) that GCC ignores
+ // the object for parameter-passsing purposes.
+ return ABIArgInfo::getIgnore();
+ }
+
+ // The combination of C++98 9p5 (sizeof(struct) != 0) and the pseudocode
+ // description of va_arg in the PCS require that an empty struct does
+ // actually occupy space for parameter-passing. I'm hoping for a
+ // clarification giving an explicit paragraph to point to in future.
+ return tryUseRegs(Ty, FreeIntRegs, /*RegsNeeded=*/ 1, /*IsInt=*/ true,
+ llvm::Type::getInt8Ty(getVMContext()));
+ }
+
+ // Homogeneous vector aggregates get passed in registers or on the stack.
+ const Type *Base = 0;
+ uint64_t NumMembers = 0;
+ if (isHomogeneousAggregate(Ty, Base, getContext(), &NumMembers)) {
+ assert(Base && "Base class should be set for homogeneous aggregate");
+ // Homogeneous aggregates are passed and returned directly.
+ return tryUseRegs(Ty, FreeVFPRegs, /*RegsNeeded=*/ NumMembers,
+ /*IsInt=*/ false);
+ }
+
+ uint64_t Size = getContext().getTypeSize(Ty);
+ if (Size <= 128) {
+ // Small structs can use the same direct type whether they're in registers
+ // or on the stack.
+ llvm::Type *BaseTy;
+ unsigned NumBases;
+ int SizeInRegs = (Size + 63) / 64;
+
+ if (getContext().getTypeAlign(Ty) == 128) {
+ BaseTy = llvm::Type::getIntNTy(getVMContext(), 128);
+ NumBases = 1;
+
+ // If the type may need padding registers to ensure "alignment", we must
+ // be careful when this is accounted for. Increasing the effective size
+ // covers all cases.
+ SizeInRegs += FreeIntRegs % 2 != 0;
+ } else {
+ BaseTy = llvm::Type::getInt64Ty(getVMContext());
+ NumBases = SizeInRegs;
+ }
+ llvm::Type *DirectTy = llvm::ArrayType::get(BaseTy, NumBases);
+
+ return tryUseRegs(Ty, FreeIntRegs, /*RegsNeeded=*/ SizeInRegs,
+ /*IsInt=*/ true, DirectTy);
+ }
+
+ // If the aggregate is > 16 bytes, it's passed and returned indirectly. In
+ // LLVM terms the return uses an "sret" pointer, but that's handled elsewhere.
+ --FreeIntRegs;
+ return ABIArgInfo::getIndirect(0, /* byVal = */ false);
+}
+
+llvm::Value *AArch64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
+ CodeGenFunction &CGF) const {
+ // The AArch64 va_list type and handling is specified in the Procedure Call
+ // Standard, section B.4:
+ //
+ // struct {
+ // void *__stack;
+ // void *__gr_top;
+ // void *__vr_top;
+ // int __gr_offs;
+ // int __vr_offs;
+ // };
+
+ assert(!CGF.CGM.getDataLayout().isBigEndian()
+ && "va_arg not implemented for big-endian AArch64");
+
+ int FreeIntRegs = 8, FreeVFPRegs = 8;
+ Ty = CGF.getContext().getCanonicalType(Ty);
+ ABIArgInfo AI = classifyGenericType(Ty, FreeIntRegs, FreeVFPRegs);
+
+ llvm::BasicBlock *MaybeRegBlock = CGF.createBasicBlock("vaarg.maybe_reg");
+ llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg");
+ llvm::BasicBlock *OnStackBlock = CGF.createBasicBlock("vaarg.on_stack");
+ llvm::BasicBlock *ContBlock = CGF.createBasicBlock("vaarg.end");
+
+ llvm::Value *reg_offs_p = 0, *reg_offs = 0;
+ int reg_top_index;
+ int RegSize;
+ if (FreeIntRegs < 8) {
+ assert(FreeVFPRegs == 8 && "Arguments never split between int & VFP regs");
+ // 3 is the field number of __gr_offs
+ reg_offs_p = CGF.Builder.CreateStructGEP(VAListAddr, 3, "gr_offs_p");
+ reg_offs = CGF.Builder.CreateLoad(reg_offs_p, "gr_offs");
+ reg_top_index = 1; // field number for __gr_top
+ RegSize = 8 * (8 - FreeIntRegs);
+ } else {
+ assert(FreeVFPRegs < 8 && "Argument must go in VFP or int regs");
+ // 4 is the field number of __vr_offs.
+ reg_offs_p = CGF.Builder.CreateStructGEP(VAListAddr, 4, "vr_offs_p");
+ reg_offs = CGF.Builder.CreateLoad(reg_offs_p, "vr_offs");
+ reg_top_index = 2; // field number for __vr_top
+ RegSize = 16 * (8 - FreeVFPRegs);
+ }
+
+ //=======================================
+ // Find out where argument was passed
+ //=======================================
+
+ // If reg_offs >= 0 we're already using the stack for this type of
+ // argument. We don't want to keep updating reg_offs (in case it overflows,
+ // though anyone passing 2GB of arguments, each at most 16 bytes, deserves
+ // whatever they get).
+ llvm::Value *UsingStack = 0;
+ UsingStack = CGF.Builder.CreateICmpSGE(reg_offs,
+ llvm::ConstantInt::get(CGF.Int32Ty, 0));
+
+ CGF.Builder.CreateCondBr(UsingStack, OnStackBlock, MaybeRegBlock);
+
+ // Otherwise, at least some kind of argument could go in these registers, the
+ // quesiton is whether this particular type is too big.
+ CGF.EmitBlock(MaybeRegBlock);
+
+ // Integer arguments may need to correct register alignment (for example a
+ // "struct { __int128 a; };" gets passed in x_2N, x_{2N+1}). In this case we
+ // align __gr_offs to calculate the potential address.
+ if (FreeIntRegs < 8 && AI.isDirect() && getContext().getTypeAlign(Ty) > 64) {
+ int Align = getContext().getTypeAlign(Ty) / 8;
+
+ reg_offs = CGF.Builder.CreateAdd(reg_offs,
+ llvm::ConstantInt::get(CGF.Int32Ty, Align - 1),
+ "align_regoffs");
+ reg_offs = CGF.Builder.CreateAnd(reg_offs,
+ llvm::ConstantInt::get(CGF.Int32Ty, -Align),
+ "aligned_regoffs");
+ }
+
+ // Update the gr_offs/vr_offs pointer for next call to va_arg on this va_list.
+ llvm::Value *NewOffset = 0;
+ NewOffset = CGF.Builder.CreateAdd(reg_offs,
+ llvm::ConstantInt::get(CGF.Int32Ty, RegSize),
+ "new_reg_offs");
+ CGF.Builder.CreateStore(NewOffset, reg_offs_p);
+
+ // Now we're in a position to decide whether this argument really was in
+ // registers or not.
+ llvm::Value *InRegs = 0;
+ InRegs = CGF.Builder.CreateICmpSLE(NewOffset,
+ llvm::ConstantInt::get(CGF.Int32Ty, 0),
+ "inreg");
+
+ CGF.Builder.CreateCondBr(InRegs, InRegBlock, OnStackBlock);
+
+ //=======================================
+ // Argument was in registers
+ //=======================================
+
+ // Now we emit the code for if the argument was originally passed in
+ // registers. First start the appropriate block:
+ CGF.EmitBlock(InRegBlock);
+
+ llvm::Value *reg_top_p = 0, *reg_top = 0;
+ reg_top_p = CGF.Builder.CreateStructGEP(VAListAddr, reg_top_index, "reg_top_p");
+ reg_top = CGF.Builder.CreateLoad(reg_top_p, "reg_top");
+ llvm::Value *BaseAddr = CGF.Builder.CreateGEP(reg_top, reg_offs);
+ llvm::Value *RegAddr = 0;
+ llvm::Type *MemTy = llvm::PointerType::getUnqual(CGF.ConvertTypeForMem(Ty));
+
+ if (!AI.isDirect()) {
+ // If it's been passed indirectly (actually a struct), whatever we find from
+ // stored registers or on the stack will actually be a struct **.
+ MemTy = llvm::PointerType::getUnqual(MemTy);
+ }
+
+ const Type *Base = 0;
+ uint64_t NumMembers;
+ if (isHomogeneousAggregate(Ty, Base, getContext(), &NumMembers)
+ && NumMembers > 1) {
+ // Homogeneous aggregates passed in registers will have their elements split
+ // and stored 16-bytes apart regardless of size (they're notionally in qN,
+ // qN+1, ...). We reload and store into a temporary local variable
+ // contiguously.
+ assert(AI.isDirect() && "Homogeneous aggregates should be passed directly");
+ llvm::Type *BaseTy = CGF.ConvertType(QualType(Base, 0));
+ llvm::Type *HFATy = llvm::ArrayType::get(BaseTy, NumMembers);
+ llvm::Value *Tmp = CGF.CreateTempAlloca(HFATy);
+
+ for (unsigned i = 0; i < NumMembers; ++i) {
+ llvm::Value *BaseOffset = llvm::ConstantInt::get(CGF.Int32Ty, 16 * i);
+ llvm::Value *LoadAddr = CGF.Builder.CreateGEP(BaseAddr, BaseOffset);
+ LoadAddr = CGF.Builder.CreateBitCast(LoadAddr,
+ llvm::PointerType::getUnqual(BaseTy));
+ llvm::Value *StoreAddr = CGF.Builder.CreateStructGEP(Tmp, i);
+
+ llvm::Value *Elem = CGF.Builder.CreateLoad(LoadAddr);
+ CGF.Builder.CreateStore(Elem, StoreAddr);
+ }
+
+ RegAddr = CGF.Builder.CreateBitCast(Tmp, MemTy);
+ } else {
+ // Otherwise the object is contiguous in memory
+ RegAddr = CGF.Builder.CreateBitCast(BaseAddr, MemTy);
+ }
+
+ CGF.EmitBranch(ContBlock);
+
+ //=======================================
+ // Argument was on the stack
+ //=======================================
+ CGF.EmitBlock(OnStackBlock);
+
+ llvm::Value *stack_p = 0, *OnStackAddr = 0;
+ stack_p = CGF.Builder.CreateStructGEP(VAListAddr, 0, "stack_p");
+ OnStackAddr = CGF.Builder.CreateLoad(stack_p, "stack");
+
+ // Again, stack arguments may need realigmnent. In this case both integer and
+ // floating-point ones might be affected.
+ if (AI.isDirect() && getContext().getTypeAlign(Ty) > 64) {
+ int Align = getContext().getTypeAlign(Ty) / 8;
+
+ OnStackAddr = CGF.Builder.CreatePtrToInt(OnStackAddr, CGF.Int64Ty);
+
+ OnStackAddr = CGF.Builder.CreateAdd(OnStackAddr,
+ llvm::ConstantInt::get(CGF.Int64Ty, Align - 1),
+ "align_stack");
+ OnStackAddr = CGF.Builder.CreateAnd(OnStackAddr,
+ llvm::ConstantInt::get(CGF.Int64Ty, -Align),
+ "align_stack");
+
+ OnStackAddr = CGF.Builder.CreateIntToPtr(OnStackAddr, CGF.Int8PtrTy);
+ }
+
+ uint64_t StackSize;
+ if (AI.isDirect())
+ StackSize = getContext().getTypeSize(Ty) / 8;
+ else
+ StackSize = 8;
+
+ // All stack slots are 8 bytes
+ StackSize = llvm::RoundUpToAlignment(StackSize, 8);
+
+ llvm::Value *StackSizeC = llvm::ConstantInt::get(CGF.Int32Ty, StackSize);
+ llvm::Value *NewStack = CGF.Builder.CreateGEP(OnStackAddr, StackSizeC,
+ "new_stack");
+
+ // Write the new value of __stack for the next call to va_arg
+ CGF.Builder.CreateStore(NewStack, stack_p);
+
+ OnStackAddr = CGF.Builder.CreateBitCast(OnStackAddr, MemTy);
+
+ CGF.EmitBranch(ContBlock);
+
+ //=======================================
+ // Tidy up
+ //=======================================
+ CGF.EmitBlock(ContBlock);
+
+ llvm::PHINode *ResAddr = CGF.Builder.CreatePHI(MemTy, 2, "vaarg.addr");
+ ResAddr->addIncoming(RegAddr, InRegBlock);
+ ResAddr->addIncoming(OnStackAddr, OnStackBlock);
+
+ if (AI.isDirect())
+ return ResAddr;
+
+ return CGF.Builder.CreateLoad(ResAddr, "vaarg.addr");
+}
+
+//===----------------------------------------------------------------------===//
// NVPTX ABI Implementation
//===----------------------------------------------------------------------===//
@@ -3563,6 +4043,8 @@ public:
virtual void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
CodeGen::CodeGenModule &M) const;
+private:
+ static void addKernelMetadata(llvm::Function *F);
};
ABIArgInfo NVPTXABIInfo::classifyReturnType(QualType RetTy) const {
@@ -3590,25 +4072,7 @@ void NVPTXABIInfo::computeInfo(CGFunctionInfo &FI) const {
if (FI.getCallingConvention() != llvm::CallingConv::C)
return;
- // Calling convention as default by an ABI.
- // We're still using the PTX_Kernel/PTX_Device calling conventions here,
- // but we should switch to NVVM metadata later on.
- llvm::CallingConv::ID DefaultCC;
- const LangOptions &LangOpts = getContext().getLangOpts();
- if (LangOpts.OpenCL || LangOpts.CUDA) {
- // If we are in OpenCL or CUDA mode, then default to device functions
- DefaultCC = llvm::CallingConv::PTX_Device;
- } else {
- // If we are in standard C/C++ mode, use the triple to decide on the default
- StringRef Env =
- getContext().getTargetInfo().getTriple().getEnvironmentName();
- if (Env == "device")
- DefaultCC = llvm::CallingConv::PTX_Device;
- else
- DefaultCC = llvm::CallingConv::PTX_Kernel;
- }
- FI.setEffectiveCallingConvention(DefaultCC);
-
+ FI.setEffectiveCallingConvention(getRuntimeCC());
}
llvm::Value *NVPTXABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
@@ -3626,26 +4090,43 @@ SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
// Perform special handling in OpenCL mode
if (M.getLangOpts().OpenCL) {
- // Use OpenCL function attributes to set proper calling conventions
+ // Use OpenCL function attributes to check for kernel functions
// By default, all functions are device functions
if (FD->hasAttr<OpenCLKernelAttr>()) {
- // OpenCL __kernel functions get a kernel calling convention
- F->setCallingConv(llvm::CallingConv::PTX_Kernel);
+ // OpenCL __kernel functions get kernel metadata
+ addKernelMetadata(F);
// And kernel functions are not subject to inlining
- F->addFnAttr(llvm::Attributes::NoInline);
+ F->addFnAttr(llvm::Attribute::NoInline);
}
}
// Perform special handling in CUDA mode.
if (M.getLangOpts().CUDA) {
- // CUDA __global__ functions get a kernel calling convention. Since
+ // CUDA __global__ functions get a kernel metadata entry. Since
// __global__ functions cannot be called from the device, we do not
// need to set the noinline attribute.
if (FD->getAttr<CUDAGlobalAttr>())
- F->setCallingConv(llvm::CallingConv::PTX_Kernel);
+ addKernelMetadata(F);
}
}
+void NVPTXTargetCodeGenInfo::addKernelMetadata(llvm::Function *F) {
+ llvm::Module *M = F->getParent();
+ llvm::LLVMContext &Ctx = M->getContext();
+
+ // Get "nvvm.annotations" metadata node
+ llvm::NamedMDNode *MD = M->getOrInsertNamedMetadata("nvvm.annotations");
+
+ // Create !{<func-ref>, metadata !"kernel", i32 1} node
+ llvm::SmallVector<llvm::Value *, 3> MDVals;
+ MDVals.push_back(F);
+ MDVals.push_back(llvm::MDString::get(Ctx, "kernel"));
+ MDVals.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx), 1));
+
+ // Append metadata to nvvm.annotations
+ MD->addOperand(llvm::MDNode::get(Ctx, MDVals));
+}
+
}
//===----------------------------------------------------------------------===//
@@ -3748,7 +4229,7 @@ void MBlazeTargetCodeGenInfo::SetTargetAttributes(const Decl *D,
F->setCallingConv(CC);
// Step 2: Add attributes goodness.
- F->addFnAttr(llvm::Attributes::NoInline);
+ F->addFnAttr(llvm::Attribute::NoInline);
}
// Step 3: Emit _interrupt_handler alias.
@@ -3786,12 +4267,12 @@ void MSP430TargetCodeGenInfo::SetTargetAttributes(const Decl *D,
F->setCallingConv(llvm::CallingConv::MSP430_INTR);
// Step 2: Add attributes goodness.
- F->addFnAttr(llvm::Attributes::NoInline);
+ F->addFnAttr(llvm::Attribute::NoInline);
// Step 3: Emit ISR vector alias.
- unsigned Num = attr->getNumber() + 0xffe0;
+ unsigned Num = attr->getNumber() / 2;
new llvm::GlobalAlias(GV->getType(), llvm::Function::ExternalLinkage,
- "vector_" + Twine::utohexstr(Num),
+ "__isr_" + Twine(Num),
GV, &M.getModule());
}
}
@@ -3834,6 +4315,19 @@ public:
return 29;
}
+ void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
+ CodeGen::CodeGenModule &CGM) const {
+ const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
+ if (!FD) return;
+ llvm::Function *Fn = cast<llvm::Function>(GV);
+ if (FD->hasAttr<Mips16Attr>()) {
+ Fn->addFnAttr("mips16");
+ }
+ else if (FD->hasAttr<NoMips16Attr>()) {
+ Fn->addFnAttr("nomips16");
+ }
+ }
+
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
llvm::Value *Address) const;
@@ -3963,7 +4457,8 @@ MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const {
if (Ty->isPromotableIntegerType())
return ABIArgInfo::getExtend();
- return ABIArgInfo::getDirect(0, 0, getPaddingType(Align, OrigOffset));
+ return ABIArgInfo::getDirect(0, 0,
+ IsO32 ? 0 : getPaddingType(Align, OrigOffset));
}
llvm::Type*
@@ -4143,7 +4638,7 @@ void TCETargetCodeGenInfo::SetTargetAttributes(const Decl *D,
if (M.getLangOpts().OpenCL) {
if (FD->hasAttr<OpenCLKernelAttr>()) {
// OpenCL C Kernel functions are not subject to inlining
- F->addFnAttr(llvm::Attributes::NoInline);
+ F->addFnAttr(llvm::Attribute::NoInline);
if (FD->hasAttr<ReqdWorkGroupSizeAttr>()) {
@@ -4337,6 +4832,9 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
case llvm::Triple::mips64el:
return *(TheTargetCodeGenInfo = new MIPSTargetCodeGenInfo(Types, false));
+ case llvm::Triple::aarch64:
+ return *(TheTargetCodeGenInfo = new AArch64TargetCodeGenInfo(Types));
+
case llvm::Triple::arm:
case llvm::Triple::thumb:
{
@@ -4348,7 +4846,7 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
Kind = ARMABIInfo::AAPCS_VFP;
switch (Triple.getOS()) {
- case llvm::Triple::NativeClient:
+ case llvm::Triple::NaCl:
return *(TheTargetCodeGenInfo =
new NaClARMTargetCodeGenInfo(Types, Kind));
default:
@@ -4379,11 +4877,9 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
return *(TheTargetCodeGenInfo = new TCETargetCodeGenInfo(Types));
case llvm::Triple::x86: {
- bool DisableMMX = strcmp(getContext().getTargetInfo().getABI(), "no-mmx") == 0;
-
if (Triple.isOSDarwin())
return *(TheTargetCodeGenInfo =
- new X86_32TargetCodeGenInfo(Types, true, true, DisableMMX, false,
+ new X86_32TargetCodeGenInfo(Types, true, true, false,
CodeGenOpts.NumRegisterParameters));
switch (Triple.getOS()) {
@@ -4395,19 +4891,17 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
case llvm::Triple::OpenBSD:
case llvm::Triple::Bitrig:
return *(TheTargetCodeGenInfo =
- new X86_32TargetCodeGenInfo(Types, false, true, DisableMMX,
- false,
+ new X86_32TargetCodeGenInfo(Types, false, true, false,
CodeGenOpts.NumRegisterParameters));
case llvm::Triple::Win32:
return *(TheTargetCodeGenInfo =
- new X86_32TargetCodeGenInfo(Types, false, true, DisableMMX, true,
+ new X86_32TargetCodeGenInfo(Types, false, true, true,
CodeGenOpts.NumRegisterParameters));
default:
return *(TheTargetCodeGenInfo =
- new X86_32TargetCodeGenInfo(Types, false, false, DisableMMX,
- false,
+ new X86_32TargetCodeGenInfo(Types, false, false, false,
CodeGenOpts.NumRegisterParameters));
}
}
@@ -4420,7 +4914,7 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
case llvm::Triple::MinGW32:
case llvm::Triple::Cygwin:
return *(TheTargetCodeGenInfo = new WinX86_64TargetCodeGenInfo(Types));
- case llvm::Triple::NativeClient:
+ case llvm::Triple::NaCl:
return *(TheTargetCodeGenInfo = new NaClX86_64TargetCodeGenInfo(Types, HasAVX));
default:
return *(TheTargetCodeGenInfo = new X86_64TargetCodeGenInfo(Types,
diff --git a/lib/CodeGen/TargetInfo.h b/lib/CodeGen/TargetInfo.h
index 88b4997..bb50ce6 100644
--- a/lib/CodeGen/TargetInfo.h
+++ b/lib/CodeGen/TargetInfo.h
@@ -15,8 +15,8 @@
#ifndef CLANG_CODEGEN_TARGETINFO_H
#define CLANG_CODEGEN_TARGETINFO_H
-#include "clang/Basic/LLVM.h"
#include "clang/AST/Type.h"
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/StringRef.h"
namespace llvm {
@@ -158,10 +158,13 @@ namespace clang {
/// - the conventions are substantively different in how they pass
/// arguments, because in this case using the variadic convention
/// will lead to C99 violations.
- /// It is not necessarily correct when arguments are passed in the
- /// same way and some out-of-band information is passed for the
- /// benefit of variadic callees, as is the case for x86-64.
- /// In this case the ABI should be consulted.
+ ///
+ /// However, some platforms make the conventions identical except
+ /// for passing additional out-of-band information to a variadic
+ /// function: for example, x86-64 passes the number of SSE
+ /// arguments in %al. On these platforms, it is desireable to
+ /// call unprototyped functions using the variadic convention so
+ /// that unprototyped calls to varargs functions still succeed.
virtual bool isNoProtoCallVariadic(const CodeGen::CallArgList &args,
const FunctionNoProtoType *fnType) const;
};
diff --git a/lib/Driver/Action.cpp b/lib/Driver/Action.cpp
index d7b4bc7..2b5bbee 100644
--- a/lib/Driver/Action.cpp
+++ b/lib/Driver/Action.cpp
@@ -9,7 +9,6 @@
#include "clang/Driver/Action.h"
#include "llvm/Support/ErrorHandling.h"
-
#include <cassert>
using namespace clang::driver;
diff --git a/lib/Driver/ArgList.cpp b/lib/Driver/ArgList.cpp
index b3a43df..6c57b62 100644
--- a/lib/Driver/ArgList.cpp
+++ b/lib/Driver/ArgList.cpp
@@ -11,7 +11,6 @@
#include "clang/Driver/Arg.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Option.h"
-
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/raw_ostream.h"
@@ -84,7 +83,6 @@ Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1) const {
(*it)->getOption().matches(Id1)) {
Res = *it;
Res->claim();
-
}
}
@@ -308,6 +306,14 @@ const char *ArgList::GetOrMakeJoinedArgString(unsigned Index,
return MakeArgString(LHS + RHS);
}
+void ArgList::dump() {
+ llvm::errs() << "ArgList:";
+ for (iterator it = begin(), ie = end(); it != ie; ++it) {
+ llvm::errs() << " " << (*it)->getSpelling();
+ }
+ llvm::errs() << "\n";
+}
+
//
InputArgList::InputArgList(const char* const *ArgBegin,
diff --git a/lib/Driver/CC1AsOptions.cpp b/lib/Driver/CC1AsOptions.cpp
index 4f89b73..9048043 100644
--- a/lib/Driver/CC1AsOptions.cpp
+++ b/lib/Driver/CC1AsOptions.cpp
@@ -8,8 +8,8 @@
//===----------------------------------------------------------------------===//
#include "clang/Driver/CC1AsOptions.h"
-#include "clang/Driver/Option.h"
#include "clang/Driver/OptTable.h"
+#include "clang/Driver/Option.h"
using namespace clang;
using namespace clang::driver;
using namespace clang::driver::options;
diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp
index 124e50c..1bff4a3 100644
--- a/lib/Driver/Compilation.cpp
+++ b/lib/Driver/Compilation.cpp
@@ -8,20 +8,18 @@
//===----------------------------------------------------------------------===//
#include "clang/Driver/Compilation.h"
-
#include "clang/Driver/Action.h"
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/ToolChain.h"
-
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Program.h"
-#include <sys/stat.h>
+#include "llvm/Support/raw_ostream.h"
#include <errno.h>
+#include <sys/stat.h>
using namespace clang::driver;
using namespace clang;
@@ -113,7 +111,7 @@ static bool skipArg(const char *Flag, bool &SkipNextArg) {
bool Res = llvm::StringSwitch<bool>(Flag)
.Cases("-I", "-MF", "-MT", "-MQ", true)
.Cases("-o", "-coverage-file", "-dependency-file", true)
- .Cases("-fdebug-compilation-dir", "-fmodule-cache-path", "-idirafter", true)
+ .Cases("-fdebug-compilation-dir", "-idirafter", true)
.Cases("-include", "-include-pch", "-internal-isystem", true)
.Cases("-internal-externc-isystem", "-iprefix", "-iwithprefix", true)
.Cases("-iwithprefixbefore", "-isysroot", "-isystem", "-iquote", true)
@@ -201,39 +199,56 @@ void Compilation::PrintDiagnosticJob(raw_ostream &OS, const Job &J) const {
}
}
+bool Compilation::CleanupFile(const char *File, bool IssueErrors) const {
+ llvm::sys::Path P(File);
+ std::string Error;
+
+ // Don't try to remove files which we don't have write access to (but may be
+ // able to remove), or non-regular files. Underlying tools may have
+ // intentionally not overwritten them.
+ if (!P.canWrite() || !P.isRegularFile())
+ return true;
+
+ if (P.eraseFromDisk(false, &Error)) {
+ // Failure is only failure if the file exists and is "regular". There is
+ // a race condition here due to the limited interface of
+ // llvm::sys::Path, we want to know if the removal gave ENOENT.
+
+ // FIXME: Grumble, P.exists() is broken. PR3837.
+ struct stat buf;
+ if (::stat(P.c_str(), &buf) == 0 ? (buf.st_mode & S_IFMT) == S_IFREG :
+ (errno != ENOENT)) {
+ if (IssueErrors)
+ getDriver().Diag(clang::diag::err_drv_unable_to_remove_file)
+ << Error;
+ return false;
+ }
+ }
+ return true;
+}
+
bool Compilation::CleanupFileList(const ArgStringList &Files,
bool IssueErrors) const {
bool Success = true;
-
for (ArgStringList::const_iterator
- it = Files.begin(), ie = Files.end(); it != ie; ++it) {
+ it = Files.begin(), ie = Files.end(); it != ie; ++it)
+ Success &= CleanupFile(*it, IssueErrors);
+ return Success;
+}
- llvm::sys::Path P(*it);
- std::string Error;
+bool Compilation::CleanupFileMap(const ArgStringMap &Files,
+ const JobAction *JA,
+ bool IssueErrors) const {
+ bool Success = true;
+ for (ArgStringMap::const_iterator
+ it = Files.begin(), ie = Files.end(); it != ie; ++it) {
- // Don't try to remove files which we don't have write access to (but may be
- // able to remove). Underlying tools may have intentionally not overwritten
- // them.
- if (!P.canWrite())
+ // If specified, only delete the files associated with the JobAction.
+ // Otherwise, delete all files in the map.
+ if (JA && it->first != JA)
continue;
-
- if (P.eraseFromDisk(false, &Error)) {
- // Failure is only failure if the file exists and is "regular". There is
- // a race condition here due to the limited interface of
- // llvm::sys::Path, we want to know if the removal gave ENOENT.
-
- // FIXME: Grumble, P.exists() is broken. PR3837.
- struct stat buf;
- if (::stat(P.c_str(), &buf) == 0 ? (buf.st_mode & S_IFMT) == S_IFREG :
- (errno != ENOENT)) {
- if (IssueErrors)
- getDriver().Diag(clang::diag::err_drv_unable_to_remove_file)
- << Error;
- Success = false;
- }
- }
+ Success &= CleanupFile(it->second, IssueErrors);
}
-
return Success;
}
@@ -275,11 +290,12 @@ int Compilation::ExecuteCommand(const Command &C,
}
std::string Error;
+ bool ExecutionFailed;
int Res =
llvm::sys::Program::ExecuteAndWait(Prog, Argv,
/*env*/0, Redirects,
/*secondsToWait*/0, /*memoryLimit*/0,
- &Error);
+ &Error, &ExecutionFailed);
if (!Error.empty()) {
assert(Res && "Error string set with 0 result code!");
getDriver().Diag(clang::diag::err_drv_command_failure) << Error;
@@ -289,24 +305,51 @@ int Compilation::ExecuteCommand(const Command &C,
FailingCommand = &C;
delete[] Argv;
- return Res;
+ return ExecutionFailed ? 1 : Res;
+}
+
+typedef SmallVectorImpl< std::pair<int, const Command *> > FailingCommandList;
+
+static bool ActionFailed(const Action *A,
+ const FailingCommandList &FailingCommands) {
+
+ if (FailingCommands.empty())
+ return false;
+
+ for (FailingCommandList::const_iterator CI = FailingCommands.begin(),
+ CE = FailingCommands.end(); CI != CE; ++CI)
+ if (A == &(CI->second->getSource()))
+ return true;
+
+ for (Action::const_iterator AI = A->begin(), AE = A->end(); AI != AE; ++AI)
+ if (ActionFailed(*AI, FailingCommands))
+ return true;
+
+ return false;
}
-int Compilation::ExecuteJob(const Job &J,
- const Command *&FailingCommand) const {
+static bool InputsOk(const Command &C,
+ const FailingCommandList &FailingCommands) {
+ return !ActionFailed(&C.getSource(), FailingCommands);
+}
+
+void Compilation::ExecuteJob(const Job &J,
+ FailingCommandList &FailingCommands) const {
if (const Command *C = dyn_cast<Command>(&J)) {
- return ExecuteCommand(*C, FailingCommand);
+ if (!InputsOk(*C, FailingCommands))
+ return;
+ const Command *FailingCommand = 0;
+ if (int Res = ExecuteCommand(*C, FailingCommand))
+ FailingCommands.push_back(std::make_pair(Res, FailingCommand));
} else {
const JobList *Jobs = cast<JobList>(&J);
- for (JobList::const_iterator
- it = Jobs->begin(), ie = Jobs->end(); it != ie; ++it)
- if (int Res = ExecuteJob(**it, FailingCommand))
- return Res;
- return 0;
+ for (JobList::const_iterator it = Jobs->begin(), ie = Jobs->end();
+ it != ie; ++it)
+ ExecuteJob(**it, FailingCommands);
}
}
-void Compilation::initCompilationForDiagnostics(void) {
+void Compilation::initCompilationForDiagnostics() {
// Free actions and jobs.
DeleteContainerPointers(Actions);
Jobs.clear();
@@ -314,6 +357,7 @@ void Compilation::initCompilationForDiagnostics(void) {
// Clear temporary/results file lists.
TempFiles.clear();
ResultFiles.clear();
+ FailureResultFiles.clear();
// Remove any user specified output. Claim any unclaimed arguments, so as
// to avoid emitting warnings about unused args.
@@ -331,6 +375,6 @@ void Compilation::initCompilationForDiagnostics(void) {
Redirects[2] = new const llvm::sys::Path();
}
-StringRef Compilation::getSysRoot(void) const {
+StringRef Compilation::getSysRoot() const {
return getDriver().SysRoot;
}
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 68471ec..ad1921b 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -8,7 +8,9 @@
//===----------------------------------------------------------------------===//
#include "clang/Driver/Driver.h"
-
+#include "InputInfo.h"
+#include "ToolChains.h"
+#include "clang/Basic/Version.h"
#include "clang/Driver/Action.h"
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
@@ -20,24 +22,20 @@
#include "clang/Driver/Options.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
-
-#include "clang/Basic/Version.h"
-
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Program.h"
-
-#include "InputInfo.h"
-#include "ToolChains.h"
-
+#include "llvm/Support/raw_ostream.h"
#include <map>
+// FIXME: It would prevent us from including llvm-config.h
+// if config.h were included before system_error.h.
#include "clang/Config/config.h"
using namespace clang::driver;
@@ -46,7 +44,6 @@ using namespace clang;
Driver::Driver(StringRef ClangExecutable,
StringRef DefaultTargetTriple,
StringRef DefaultImageName,
- bool IsProduction,
DiagnosticsEngine &Diags)
: Opts(createDriverOptTable()), Diags(Diags),
ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT),
@@ -129,6 +126,7 @@ const {
// -{fsyntax-only,-analyze,emit-ast,S} only run up to the compiler.
} else if ((PhaseArg = DAL.getLastArg(options::OPT_fsyntax_only)) ||
+ (PhaseArg = DAL.getLastArg(options::OPT_module_file_info)) ||
(PhaseArg = DAL.getLastArg(options::OPT_rewrite_objc)) ||
(PhaseArg = DAL.getLastArg(options::OPT_rewrite_legacy_objc)) ||
(PhaseArg = DAL.getLastArg(options::OPT__migrate)) ||
@@ -242,7 +240,8 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
if (char *env = ::getenv("COMPILER_PATH")) {
StringRef CompilerPath = env;
while (!CompilerPath.empty()) {
- std::pair<StringRef, StringRef> Split = CompilerPath.split(':');
+ std::pair<StringRef, StringRef> Split
+ = CompilerPath.split(llvm::sys::PathSeparator);
PrefixDirs.push_back(Split.first);
CompilerPath = Split.second;
}
@@ -251,7 +250,7 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
// FIXME: What are we going to do with -V and -b?
// FIXME: This stuff needs to go into the Compilation, not the driver.
- bool CCCPrintOptions = false, CCCPrintActions = false;
+ bool CCCPrintOptions, CCCPrintActions;
InputArgList *Args = ParseArgStrings(ArgList.slice(1));
@@ -293,6 +292,9 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
if (Args->hasArg(options::OPT_nostdlib))
UseStdLib = false;
+ if (const Arg *A = Args->getLastArg(options::OPT_resource_dir))
+ ResourceDir = A->getValue();
+
// Perform the default argument translations.
DerivedArgList *TranslatedArgs = TranslateInputArgs(*Args);
@@ -342,8 +344,9 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
if (C.getArgs().hasArg(options::OPT_fno_crash_diagnostics))
return;
- // Don't try to generate diagnostics for link jobs.
- if (FailingCommand && FailingCommand->getCreator().isLinkJob())
+ // Don't try to generate diagnostics for link or dsymutil jobs.
+ if (FailingCommand && (FailingCommand->getCreator().isLinkJob() ||
+ FailingCommand->getCreator().isDsymutilJob()))
return;
// Print the version of the compiler.
@@ -369,9 +372,12 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
C.PrintDiagnosticJob(OS, C.getJobs());
OS.flush();
- // Clear stale state and suppress tool output.
+ // Keep track of whether we produce any errors while trying to produce
+ // preprocessed sources.
+ DiagnosticErrorTrap Trap(Diags);
+
+ // Suppress tool output.
C.initCompilationForDiagnostics();
- Diags.Reset();
// Construct the list of inputs.
InputList Inputs;
@@ -398,6 +404,12 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
}
}
+ if (Inputs.empty()) {
+ Diag(clang::diag::note_drv_command_failed_diag_msg)
+ << "Error generating preprocessed source(s) - no preprocessable inputs.";
+ return;
+ }
+
// Don't attempt to generate preprocessed files if multiple -arch options are
// used, unless they're all duplicates.
llvm::StringSet<> ArchNames;
@@ -416,12 +428,6 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
return;
}
- if (Inputs.empty()) {
- Diag(clang::diag::note_drv_command_failed_diag_msg)
- << "Error generating preprocessed source(s) - no preprocessable inputs.";
- return;
- }
-
// Construct the list of abstract actions to perform for this compilation. On
// Darwin OSes this uses the driver-driver and builds universal actions.
const ToolChain &TC = C.getDefaultToolChain();
@@ -433,18 +439,18 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
BuildJobs(C);
// If there were errors building the compilation, quit now.
- if (Diags.hasErrorOccurred()) {
+ if (Trap.hasErrorOccurred()) {
Diag(clang::diag::note_drv_command_failed_diag_msg)
<< "Error generating preprocessed source(s).";
return;
}
// Generate preprocessed output.
- FailingCommand = 0;
- int Res = C.ExecuteJob(C.getJobs(), FailingCommand);
+ SmallVector<std::pair<int, const Command *>, 4> FailingCommands;
+ C.ExecuteJob(C.getJobs(), FailingCommands);
// If the command succeeded, we are done.
- if (Res == 0) {
+ if (FailingCommands.empty()) {
Diag(clang::diag::note_drv_command_failed_diag_msg)
<< "\n********************\n\n"
"PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:\n"
@@ -485,8 +491,9 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
<< "\n\n********************";
} else {
// Failure, remove preprocessed files.
- if (!C.getArgs().hasArg(options::OPT_save_temps))
+ if (!C.getArgs().hasArg(options::OPT_save_temps)) {
C.CleanupFileList(C.getTempFiles(), true);
+ }
Diag(clang::diag::note_drv_command_failed_diag_msg)
<< "Error generating preprocessed source(s).";
@@ -494,7 +501,7 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
}
int Driver::ExecuteCompilation(const Compilation &C,
- const Command *&FailingCommand) const {
+ SmallVectorImpl< std::pair<int, const Command *> > &FailingCommands) const {
// Just print if -### was present.
if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) {
C.PrintJob(llvm::errs(), C.getJobs(), "\n", true);
@@ -505,44 +512,52 @@ int Driver::ExecuteCompilation(const Compilation &C,
if (Diags.hasErrorOccurred())
return 1;
- int Res = C.ExecuteJob(C.getJobs(), FailingCommand);
+ C.ExecuteJob(C.getJobs(), FailingCommands);
// Remove temp files.
C.CleanupFileList(C.getTempFiles());
// If the command succeeded, we are done.
- if (Res == 0)
- return Res;
-
- // Otherwise, remove result files as well.
- if (!C.getArgs().hasArg(options::OPT_save_temps)) {
- C.CleanupFileList(C.getResultFiles(), true);
+ if (FailingCommands.empty())
+ return 0;
- // Failure result files are valid unless we crashed.
- if (Res < 0)
- C.CleanupFileList(C.getFailureResultFiles(), true);
- }
+ // Otherwise, remove result files and print extra information about abnormal
+ // failures.
+ for (SmallVectorImpl< std::pair<int, const Command *> >::iterator it =
+ FailingCommands.begin(), ie = FailingCommands.end(); it != ie; ++it) {
+ int Res = it->first;
+ const Command *FailingCommand = it->second;
+
+ // Remove result files if we're not saving temps.
+ if (!C.getArgs().hasArg(options::OPT_save_temps)) {
+ const JobAction *JA = cast<JobAction>(&FailingCommand->getSource());
+ C.CleanupFileMap(C.getResultFiles(), JA, true);
+
+ // Failure result files are valid unless we crashed.
+ if (Res < 0)
+ C.CleanupFileMap(C.getFailureResultFiles(), JA, true);
+ }
- // Print extra information about abnormal failures, if possible.
- //
- // This is ad-hoc, but we don't want to be excessively noisy. If the result
- // status was 1, assume the command failed normally. In particular, if it was
- // the compiler then assume it gave a reasonable error code. Failures in other
- // tools are less common, and they generally have worse diagnostics, so always
- // print the diagnostic there.
- const Tool &FailingTool = FailingCommand->getCreator();
-
- if (!FailingCommand->getCreator().hasGoodDiagnostics() || Res != 1) {
- // FIXME: See FIXME above regarding result code interpretation.
- if (Res < 0)
- Diag(clang::diag::err_drv_command_signalled)
- << FailingTool.getShortName();
- else
- Diag(clang::diag::err_drv_command_failed)
- << FailingTool.getShortName() << Res;
+ // Print extra information about abnormal failures, if possible.
+ //
+ // This is ad-hoc, but we don't want to be excessively noisy. If the result
+ // status was 1, assume the command failed normally. In particular, if it
+ // was the compiler then assume it gave a reasonable error code. Failures
+ // in other tools are less common, and they generally have worse
+ // diagnostics, so always print the diagnostic there.
+ const Tool &FailingTool = FailingCommand->getCreator();
+
+ if (!FailingCommand->getCreator().hasGoodDiagnostics() || Res != 1) {
+ // FIXME: See FIXME above regarding result code interpretation.
+ if (Res < 0)
+ Diag(clang::diag::err_drv_command_signalled)
+ << FailingTool.getShortName();
+ else
+ Diag(clang::diag::err_drv_command_failed)
+ << FailingTool.getShortName() << Res;
+ }
}
-
- return Res;
+ return 0;
}
void Driver::PrintOptions(const ArgList &Args) const {
@@ -861,7 +876,7 @@ void Driver::BuildUniversalActions(const ToolChain &TC,
// Add a 'dsymutil' step if necessary, when debug info is enabled and we
// have a compile input. We need to run 'dsymutil' ourselves in such cases
- // because the debug info will refer to a temporary object file which is
+ // because the debug info will refer to a temporary object file which
// will be removed at the end of the compilation process.
if (Act->getType() == types::TY_Image) {
ActionList Inputs;
@@ -1026,17 +1041,18 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args,
// Construct the actions to perform.
ActionList LinkerInputs;
- unsigned NumSteps = 0;
+ ActionList SplitInputs;
+ llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PL;
for (unsigned i = 0, e = Inputs.size(); i != e; ++i) {
types::ID InputType = Inputs[i].first;
const Arg *InputArg = Inputs[i].second;
- NumSteps = types::getNumCompilationPhases(InputType);
- assert(NumSteps && "Invalid number of steps!");
+ PL.clear();
+ types::getCompilationPhases(InputType, PL);
// If the first step comes after the final phase we are doing as part of
// this compilation, warn the user about it.
- phases::ID InitialPhase = types::getCompilationPhase(InputType, 0);
+ phases::ID InitialPhase = PL[0];
if (InitialPhase > FinalPhase) {
// Claim here to avoid the more general unused warning.
InputArg->claim();
@@ -1071,8 +1087,9 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args,
// Build the pipeline for this file.
OwningPtr<Action> Current(new InputAction(*InputArg, InputType));
- for (unsigned i = 0; i != NumSteps; ++i) {
- phases::ID Phase = types::getCompilationPhase(InputType, i);
+ for (llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases>::iterator
+ i = PL.begin(), e = PL.end(); i != e; ++i) {
+ phases::ID Phase = *i;
// We are done if this step is past what the user requested.
if (Phase > FinalPhase)
@@ -1080,7 +1097,7 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args,
// Queue linker inputs.
if (Phase == phases::Link) {
- assert(i + 1 == NumSteps && "linking must be final compilation step.");
+ assert((i + 1) == e && "linking must be final compilation step.");
LinkerInputs.push_back(Current.take());
break;
}
@@ -1108,7 +1125,7 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args,
// If we are linking, claim any options which are obviously only used for
// compilation.
- if (FinalPhase == phases::Link && (NumSteps == 1))
+ if (FinalPhase == phases::Link && PL.size() == 1)
Args.ClaimAllArgs(options::OPT_CompileOnly_Group);
}
@@ -1154,6 +1171,8 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
return new MigrateJobAction(Input, types::TY_Remap);
} else if (Args.hasArg(options::OPT_emit_ast)) {
return new CompileJobAction(Input, types::TY_AST);
+ } else if (Args.hasArg(options::OPT_module_file_info)) {
+ return new CompileJobAction(Input, types::TY_ModuleFile);
} else if (IsUsingLTO(Args)) {
types::ID Output =
Args.hasArg(options::OPT_S) ? types::TY_LTO_IR : types::TY_LTO_BC;
@@ -1272,7 +1291,7 @@ void Driver::BuildJobs(Compilation &C) const {
}
}
-static const Tool &SelectToolForJob(Compilation &C, const ToolChain *TC,
+static const Tool *SelectToolForJob(Compilation &C, const ToolChain *TC,
const JobAction *JA,
const ActionList *&Inputs) {
const Tool *ToolForJob = 0;
@@ -1281,23 +1300,23 @@ static const Tool &SelectToolForJob(Compilation &C, const ToolChain *TC,
// bottom up, so what we are actually looking for is an assembler job with a
// compiler input.
- if (C.getArgs().hasFlag(options::OPT_integrated_as,
- options::OPT_no_integrated_as,
- TC->IsIntegratedAssemblerDefault()) &&
+ if (TC->useIntegratedAs() &&
!C.getArgs().hasArg(options::OPT_save_temps) &&
isa<AssembleJobAction>(JA) &&
Inputs->size() == 1 && isa<CompileJobAction>(*Inputs->begin())) {
- const Tool &Compiler = TC->SelectTool(
- C, cast<JobAction>(**Inputs->begin()), (*Inputs)[0]->getInputs());
- if (Compiler.hasIntegratedAssembler()) {
+ const Tool *Compiler =
+ TC->SelectTool(cast<JobAction>(**Inputs->begin()));
+ if (!Compiler)
+ return NULL;
+ if (Compiler->hasIntegratedAssembler()) {
Inputs = &(*Inputs)[0]->getInputs();
- ToolForJob = &Compiler;
+ ToolForJob = Compiler;
}
}
// Otherwise use the tool for the current job.
if (!ToolForJob)
- ToolForJob = &TC->SelectTool(C, *JA, *Inputs);
+ ToolForJob = TC->SelectTool(*JA);
// See if we should use an integrated preprocessor. We do so when we have
// exactly one input, since this is the only use case we care about
@@ -1310,7 +1329,7 @@ static const Tool &SelectToolForJob(Compilation &C, const ToolChain *TC,
ToolForJob->hasIntegratedCPP())
Inputs = &(*Inputs)[0]->getInputs();
- return *ToolForJob;
+ return ToolForJob;
}
void Driver::BuildJobsForAction(Compilation &C,
@@ -1352,23 +1371,19 @@ void Driver::BuildJobsForAction(Compilation &C,
const ActionList *Inputs = &A->getInputs();
const JobAction *JA = cast<JobAction>(A);
- const Tool &T = SelectToolForJob(C, TC, JA, Inputs);
+ const Tool *T = SelectToolForJob(C, TC, JA, Inputs);
+ if (!T)
+ return;
// Only use pipes when there is exactly one input.
InputInfoList InputInfos;
for (ActionList::const_iterator it = Inputs->begin(), ie = Inputs->end();
it != ie; ++it) {
- // Treat dsymutil sub-jobs as being at the top-level too, they shouldn't get
- // temporary output names.
- //
+ // Treat dsymutil and verify sub-jobs as being at the top-level too, they
+ // shouldn't get temporary output names.
// FIXME: Clean this up.
bool SubJobAtTopLevel = false;
- if (AtTopLevel && isa<DsymutilJobAction>(A))
- SubJobAtTopLevel = true;
-
- // Also treat verify sub-jobs as being at the top-level. They don't
- // produce any output and so don't need temporary output names.
- if (AtTopLevel && isa<VerifyJobAction>(A))
+ if (AtTopLevel && (isa<DsymutilJobAction>(A) || isa<VerifyJobAction>(A)))
SubJobAtTopLevel = true;
InputInfo II;
@@ -1386,16 +1401,15 @@ void Driver::BuildJobsForAction(Compilation &C,
BaseInput = InputInfos[0].getFilename();
// Determine the place to write output to, if any.
- if (JA->getType() == types::TY_Nothing) {
+ if (JA->getType() == types::TY_Nothing)
Result = InputInfo(A->getType(), BaseInput);
- } else {
+ else
Result = InputInfo(GetNamedOutputPath(C, *JA, BaseInput, AtTopLevel),
A->getType(), BaseInput);
- }
if (CCCPrintBindings && !CCGenDiagnostics) {
- llvm::errs() << "# \"" << T.getToolChain().getTripleString() << '"'
- << " - \"" << T.getName() << "\", inputs: [";
+ llvm::errs() << "# \"" << T->getToolChain().getTripleString() << '"'
+ << " - \"" << T->getName() << "\", inputs: [";
for (unsigned i = 0, e = InputInfos.size(); i != e; ++i) {
llvm::errs() << InputInfos[i].getAsString();
if (i + 1 != e)
@@ -1403,8 +1417,8 @@ void Driver::BuildJobsForAction(Compilation &C,
}
llvm::errs() << "], output: " << Result.getAsString() << "\n";
} else {
- T.ConstructJob(C, *JA, Result, InputInfos,
- C.getArgsForToolChain(TC, BoundArch), LinkingOutput);
+ T->ConstructJob(C, *JA, Result, InputInfos,
+ C.getArgsForToolChain(TC, BoundArch), LinkingOutput);
}
}
@@ -1417,11 +1431,12 @@ const char *Driver::GetNamedOutputPath(Compilation &C,
if (AtTopLevel && !isa<DsymutilJobAction>(JA) &&
!isa<VerifyJobAction>(JA)) {
if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o))
- return C.addResultFile(FinalOutput->getValue());
+ return C.addResultFile(FinalOutput->getValue(), &JA);
}
// Default to writing to stdout?
- if (AtTopLevel && isa<PreprocessJobAction>(JA) && !CCGenDiagnostics)
+ if (AtTopLevel && !CCGenDiagnostics &&
+ (isa<PreprocessJobAction>(JA) || JA.getType() == types::TY_ModuleFile))
return "-";
// Output to a temporary file?
@@ -1487,9 +1502,9 @@ const char *Driver::GetNamedOutputPath(Compilation &C,
BasePath = NamedOutput;
else
llvm::sys::path::append(BasePath, NamedOutput);
- return C.addResultFile(C.getArgs().MakeArgString(BasePath.c_str()));
+ return C.addResultFile(C.getArgs().MakeArgString(BasePath.c_str()), &JA);
} else {
- return C.addResultFile(NamedOutput);
+ return C.addResultFile(NamedOutput, &JA);
}
}
@@ -1638,6 +1653,21 @@ static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple,
}
}
+ // Handle pseudo-target flags '-EL' and '-EB'.
+ if (Arg *A = Args.getLastArg(options::OPT_EL, options::OPT_EB)) {
+ if (A->getOption().matches(options::OPT_EL)) {
+ if (Target.getArch() == llvm::Triple::mips)
+ Target.setArch(llvm::Triple::mipsel);
+ else if (Target.getArch() == llvm::Triple::mips64)
+ Target.setArch(llvm::Triple::mips64el);
+ } else {
+ if (Target.getArch() == llvm::Triple::mipsel)
+ Target.setArch(llvm::Triple::mips);
+ else if (Target.getArch() == llvm::Triple::mips64el)
+ Target.setArch(llvm::Triple::mips64);
+ }
+ }
+
// Skip further flag support on OSes which don't support '-m32' or '-m64'.
if (Target.getArchName() == "tce" ||
Target.getOS() == llvm::Triple::AuroraUX ||
@@ -1681,7 +1711,7 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
Target.getArch() == llvm::Triple::x86_64 ||
Target.getArch() == llvm::Triple::arm ||
Target.getArch() == llvm::Triple::thumb)
- TC = new toolchains::DarwinClang(*this, Target);
+ TC = new toolchains::DarwinClang(*this, Target, Args);
else
TC = new toolchains::Darwin_Generic_GCC(*this, Target, Args);
break;
@@ -1705,7 +1735,7 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
break;
case llvm::Triple::Linux:
if (Target.getArch() == llvm::Triple::hexagon)
- TC = new toolchains::Hexagon_TC(*this, Target);
+ TC = new toolchains::Hexagon_TC(*this, Target, Args);
else
TC = new toolchains::Linux(*this, Target, Args);
break;
@@ -1713,17 +1743,21 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
TC = new toolchains::Solaris(*this, Target, Args);
break;
case llvm::Triple::Win32:
- TC = new toolchains::Windows(*this, Target);
+ TC = new toolchains::Windows(*this, Target, Args);
break;
case llvm::Triple::MinGW32:
// FIXME: We need a MinGW toolchain. Fallthrough for now.
default:
// TCE is an OSless target
if (Target.getArchName() == "tce") {
- TC = new toolchains::TCEToolChain(*this, Target);
+ TC = new toolchains::TCEToolChain(*this, Target, Args);
+ break;
+ }
+ // If Hexagon is configured as an OSless target
+ if (Target.getArch() == llvm::Triple::hexagon) {
+ TC = new toolchains::Hexagon_TC(*this, Target, Args);
break;
}
-
TC = new toolchains::Generic_GCC(*this, Target, Args);
break;
}
@@ -1731,8 +1765,7 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
return *TC;
}
-bool Driver::ShouldUseClangCompiler(const Compilation &C, const JobAction &JA,
- const llvm::Triple &Triple) const {
+bool Driver::ShouldUseClangCompiler(const JobAction &JA) const {
// Check if user requested no clang, or clang doesn't understand this type (we
// only handle single inputs for now).
if (JA.size() != 1 ||
diff --git a/lib/Driver/InputInfo.h b/lib/Driver/InputInfo.h
index 2a2f4b9..a243d32 100644
--- a/lib/Driver/InputInfo.h
+++ b/lib/Driver/InputInfo.h
@@ -10,8 +10,8 @@
#ifndef CLANG_LIB_DRIVER_INPUTINFO_H_
#define CLANG_LIB_DRIVER_INPUTINFO_H_
+#include "clang/Driver/Arg.h"
#include "clang/Driver/Types.h"
-
#include <cassert>
#include <string>
diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp
index 825c86a..8c46705 100644
--- a/lib/Driver/Job.cpp
+++ b/lib/Driver/Job.cpp
@@ -8,9 +8,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Driver/Job.h"
-
#include "llvm/ADT/STLExtras.h"
-
#include <cassert>
using namespace clang::driver;
diff --git a/lib/Driver/OptTable.cpp b/lib/Driver/OptTable.cpp
index 6e7b695..20214a6 100644
--- a/lib/Driver/OptTable.cpp
+++ b/lib/Driver/OptTable.cpp
@@ -12,8 +12,8 @@
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Option.h"
#include "clang/Driver/Options.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <map>
using namespace clang::driver;
diff --git a/lib/Driver/Option.cpp b/lib/Driver/Option.cpp
index 9a34df5..dbc61ea 100644
--- a/lib/Driver/Option.cpp
+++ b/lib/Driver/Option.cpp
@@ -8,14 +8,13 @@
//===----------------------------------------------------------------------===//
#include "clang/Driver/Option.h"
-
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/ErrorHandling.h"
#include "llvm/ADT/Twine.h"
-#include <cassert>
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
#include <algorithm>
+#include <cassert>
using namespace clang::driver;
Option::Option(const OptTable::Info *info, const OptTable *owner)
diff --git a/lib/Driver/Phases.cpp b/lib/Driver/Phases.cpp
index b885eee..155e53b 100644
--- a/lib/Driver/Phases.cpp
+++ b/lib/Driver/Phases.cpp
@@ -9,7 +9,6 @@
#include "clang/Driver/Phases.h"
#include "llvm/Support/ErrorHandling.h"
-
#include <cassert>
using namespace clang::driver;
diff --git a/lib/Driver/SanitizerArgs.h b/lib/Driver/SanitizerArgs.h
index ecb396e..e61f15a 100644
--- a/lib/Driver/SanitizerArgs.h
+++ b/lib/Driver/SanitizerArgs.h
@@ -9,7 +9,13 @@
#ifndef CLANG_LIB_DRIVER_SANITIZERARGS_H_
#define CLANG_LIB_DRIVER_SANITIZERARGS_H_
+#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Path.h"
namespace clang {
namespace driver {
@@ -30,59 +36,151 @@ class SanitizerArgs {
#include "clang/Basic/Sanitizers.def"
NeedsAsanRt = Address,
NeedsTsanRt = Thread,
- NeedsUbsanRt = Undefined
+ NeedsMsanRt = Memory,
+ NeedsUbsanRt = Undefined | Integer,
+ NotAllowedWithTrap = Vptr
};
unsigned Kind;
+ std::string BlacklistFile;
+ bool MsanTrackOrigins;
+ bool AsanZeroBaseShadow;
+ bool UbsanTrapOnError;
public:
- SanitizerArgs() : Kind(0) {}
+ SanitizerArgs() : Kind(0), BlacklistFile(""), MsanTrackOrigins(false),
+ AsanZeroBaseShadow(false), UbsanTrapOnError(false) {}
/// Parses the sanitizer arguments from an argument list.
SanitizerArgs(const Driver &D, const ArgList &Args);
bool needsAsanRt() const { return Kind & NeedsAsanRt; }
bool needsTsanRt() const { return Kind & NeedsTsanRt; }
- bool needsUbsanRt() const { return Kind & NeedsUbsanRt; }
+ bool needsMsanRt() const { return Kind & NeedsMsanRt; }
+ bool needsUbsanRt() const {
+ if (UbsanTrapOnError)
+ return false;
+ return Kind & NeedsUbsanRt;
+ }
bool sanitizesVptr() const { return Kind & Vptr; }
-
+ bool notAllowedWithTrap() const { return Kind & NotAllowedWithTrap; }
+
void addArgs(const ArgList &Args, ArgStringList &CmdArgs) const {
if (!Kind)
return;
- llvm::SmallString<256> SanitizeOpt("-fsanitize=");
+ SmallString<256> SanitizeOpt("-fsanitize=");
#define SANITIZER(NAME, ID) \
if (Kind & ID) \
SanitizeOpt += NAME ",";
#include "clang/Basic/Sanitizers.def"
SanitizeOpt.pop_back();
CmdArgs.push_back(Args.MakeArgString(SanitizeOpt));
+ if (!BlacklistFile.empty()) {
+ SmallString<64> BlacklistOpt("-fsanitize-blacklist=");
+ BlacklistOpt += BlacklistFile;
+ CmdArgs.push_back(Args.MakeArgString(BlacklistOpt));
+ }
+
+ if (MsanTrackOrigins)
+ CmdArgs.push_back(Args.MakeArgString("-fsanitize-memory-track-origins"));
+
+ if (AsanZeroBaseShadow)
+ CmdArgs.push_back(Args.MakeArgString(
+ "-fsanitize-address-zero-base-shadow"));
}
private:
/// Parse a single value from a -fsanitize= or -fno-sanitize= value list.
- /// Returns a member of the \c SanitizeKind enumeration, or \c 0 if \p Value
- /// is not known.
+ /// Returns OR of members of the \c SanitizeKind enumeration, or \c 0
+ /// if \p Value is not known.
static unsigned parse(const char *Value) {
- return llvm::StringSwitch<SanitizeKind>(Value)
+ unsigned ParsedKind = llvm::StringSwitch<SanitizeKind>(Value)
#define SANITIZER(NAME, ID) .Case(NAME, ID)
#define SANITIZER_GROUP(NAME, ID, ALIAS) .Case(NAME, ID)
#include "clang/Basic/Sanitizers.def"
.Default(SanitizeKind());
+ // Assume -fsanitize=address implies -fsanitize=init-order.
+ // FIXME: This should be either specified in Sanitizers.def, or go away when
+ // we get rid of "-fsanitize=init-order" flag at all.
+ if (ParsedKind & Address)
+ ParsedKind |= InitOrder;
+ return ParsedKind;
}
/// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
/// invalid components.
- static unsigned parse(const Driver &D, const Arg *A) {
+ static unsigned parse(const Driver &D, const Arg *A, bool DiagnoseErrors) {
unsigned Kind = 0;
for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) {
if (unsigned K = parse(A->getValue(I)))
Kind |= K;
- else
+ else if (DiagnoseErrors)
D.Diag(diag::err_drv_unsupported_option_argument)
<< A->getOption().getName() << A->getValue(I);
}
return Kind;
}
+ /// Parse a single flag of the form -f[no]sanitize=, or
+ /// -f*-sanitizer. Sets the masks defining required change of Kind value.
+ /// Returns true if the flag was parsed successfully.
+ static bool parse(const Driver &D, const ArgList &Args, const Arg *A,
+ unsigned &Add, unsigned &Remove, bool DiagnoseErrors) {
+ Add = 0;
+ Remove = 0;
+ const char *DeprecatedReplacement = 0;
+ if (A->getOption().matches(options::OPT_faddress_sanitizer)) {
+ Add = Address;
+ DeprecatedReplacement = "-fsanitize=address";
+ } else if (A->getOption().matches(options::OPT_fno_address_sanitizer)) {
+ Remove = Address;
+ DeprecatedReplacement = "-fno-sanitize=address";
+ } else if (A->getOption().matches(options::OPT_fthread_sanitizer)) {
+ Add = Thread;
+ DeprecatedReplacement = "-fsanitize=thread";
+ } else if (A->getOption().matches(options::OPT_fno_thread_sanitizer)) {
+ Remove = Thread;
+ DeprecatedReplacement = "-fno-sanitize=thread";
+ } else if (A->getOption().matches(options::OPT_fcatch_undefined_behavior)) {
+ Add = UndefinedTrap;
+ DeprecatedReplacement =
+ "-fsanitize=undefined-trap -fsanitize-undefined-trap-on-error";
+ } else if (A->getOption().matches(options::OPT_fbounds_checking) ||
+ A->getOption().matches(options::OPT_fbounds_checking_EQ)) {
+ Add = Bounds;
+ DeprecatedReplacement = "-fsanitize=bounds";
+ } else if (A->getOption().matches(options::OPT_fsanitize_EQ)) {
+ Add = parse(D, A, DiagnoseErrors);
+ } else if (A->getOption().matches(options::OPT_fno_sanitize_EQ)) {
+ Remove = parse(D, A, DiagnoseErrors);
+ } else {
+ // Flag is not relevant to sanitizers.
+ return false;
+ }
+ // If this is a deprecated synonym, produce a warning directing users
+ // towards the new spelling.
+ if (DeprecatedReplacement && DiagnoseErrors)
+ D.Diag(diag::warn_drv_deprecated_arg)
+ << A->getAsString(Args) << DeprecatedReplacement;
+ return true;
+ }
+
+ /// Produce an argument string from ArgList \p Args, which shows how it
+ /// provides a sanitizer kind in \p Mask. For example, the argument list
+ /// "-fsanitize=thread,vptr -faddress-sanitizer" with mask \c NeedsUbsanRt
+ /// would produce "-fsanitize=vptr".
+ static std::string lastArgumentForKind(const Driver &D, const ArgList &Args,
+ unsigned Kind) {
+ for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend();
+ I != E; ++I) {
+ unsigned Add, Remove;
+ if (parse(D, Args, *I, Add, Remove, false) &&
+ (Add & Kind))
+ return describeSanitizeArg(Args, *I, Kind);
+ Kind &= ~Remove;
+ }
+ llvm_unreachable("arg list didn't provide expected value");
+ }
+
/// Produce an argument string from argument \p A, which shows how it provides
/// a value in \p Mask. For instance, the argument
/// "-fsanitize=address,alignment" with mask \c NeedsUbsanRt would produce
@@ -98,6 +196,18 @@ class SanitizerArgs {
llvm_unreachable("arg didn't provide expected value");
}
+
+ static bool getDefaultBlacklistForKind(const Driver &D, unsigned Kind,
+ std::string &BLPath) {
+ // For now, specify the default blacklist location for ASan only.
+ if (Kind & NeedsAsanRt) {
+ SmallString<64> Path(D.ResourceDir);
+ llvm::sys::path::append(Path, "asan_blacklist.txt");
+ BLPath = Path.str();
+ return true;
+ }
+ return false;
+ }
};
} // namespace driver
diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
index de8ed1d..19270b2 100644
--- a/lib/Driver/ToolChain.cpp
+++ b/lib/Driver/ToolChain.cpp
@@ -7,8 +7,9 @@
//
//===----------------------------------------------------------------------===//
+#include "Tools.h"
#include "clang/Driver/ToolChain.h"
-
+#include "clang/Basic/ObjCRuntime.h"
#include "clang/Driver/Action.h"
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
@@ -18,12 +19,12 @@
#include "clang/Driver/Options.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
-#include "clang/Basic/ObjCRuntime.h"
using namespace clang::driver;
using namespace clang;
-ToolChain::ToolChain(const Driver &D, const llvm::Triple &T)
- : D(D), Triple(T) {
+ToolChain::ToolChain(const Driver &D, const llvm::Triple &T,
+ const ArgList &A)
+ : D(D), Triple(T), Args(A) {
}
ToolChain::~ToolChain() {
@@ -33,6 +34,12 @@ const Driver &ToolChain::getDriver() const {
return D;
}
+bool ToolChain::useIntegratedAs() const {
+ return Args.hasFlag(options::OPT_integrated_as,
+ options::OPT_no_integrated_as,
+ IsIntegratedAssemblerDefault());
+}
+
std::string ToolChain::getDefaultUniversalArchName() const {
// In universal driver terms, the arch name accepted by -arch isn't exactly
// the same as the ones that appear in the triple. Roughly speaking, this is
@@ -52,6 +59,73 @@ bool ToolChain::IsUnwindTablesDefault() const {
return false;
}
+Tool *ToolChain::getClang() const {
+ if (!Clang)
+ Clang.reset(new tools::Clang(*this));
+ return Clang.get();
+}
+
+Tool *ToolChain::buildAssembler() const {
+ return new tools::ClangAs(*this);
+}
+
+Tool *ToolChain::buildLinker() const {
+ llvm_unreachable("Linking is not supported by this toolchain");
+}
+
+Tool *ToolChain::getAssemble() const {
+ if (!Assemble)
+ Assemble.reset(buildAssembler());
+ return Assemble.get();
+}
+
+Tool *ToolChain::getClangAs() const {
+ if (!Assemble)
+ Assemble.reset(new tools::ClangAs(*this));
+ return Assemble.get();
+}
+
+Tool *ToolChain::getLink() const {
+ if (!Link)
+ Link.reset(buildLinker());
+ return Link.get();
+}
+
+Tool *ToolChain::getTool(Action::ActionClass AC) const {
+ switch (AC) {
+ case Action::AssembleJobClass:
+ return getAssemble();
+
+ case Action::LinkJobClass:
+ return getLink();
+
+ case Action::InputClass:
+ case Action::BindArchClass:
+ case Action::LipoJobClass:
+ case Action::DsymutilJobClass:
+ case Action::VerifyJobClass:
+ llvm_unreachable("Invalid tool kind.");
+
+ case Action::CompileJobClass:
+ case Action::PrecompileJobClass:
+ case Action::PreprocessJobClass:
+ case Action::AnalyzeJobClass:
+ case Action::MigrateJobClass:
+ return getClang();
+ }
+
+ llvm_unreachable("Invalid tool kind.");
+}
+
+Tool *ToolChain::SelectTool(const JobAction &JA) const {
+ if (getDriver().ShouldUseClangCompiler(JA))
+ return getClang();
+ Action::ActionClass AC = JA.getKind();
+ if (AC == Action::AssembleJobClass && useIntegratedAs())
+ return getClangAs();
+ return getTool(AC);
+}
+
std::string ToolChain::GetFilePath(const char *Name) const {
return D.GetFilePath(Name, *this);
@@ -110,15 +184,17 @@ static const char *getARMTargetCPU(const ArgList &Args,
.Case("armv6j", "arm1136j-s")
.Cases("armv6z", "armv6zk", "arm1176jzf-s")
.Case("armv6t2", "arm1156t2-s")
+ .Cases("armv6m", "armv6-m", "cortex-m0")
.Cases("armv7", "armv7a", "armv7-a", "cortex-a8")
+ .Cases("armv7l", "armv7-l", "cortex-a8")
.Cases("armv7f", "armv7-f", "cortex-a9-mp")
.Cases("armv7s", "armv7-s", "swift")
.Cases("armv7r", "armv7-r", "cortex-r4")
.Cases("armv7m", "armv7-m", "cortex-m3")
+ .Cases("armv7em", "armv7e-m", "cortex-m4")
.Case("ep9312", "ep9312")
.Case("iwmmxt", "iwmmxt")
.Case("xscale", "xscale")
- .Cases("armv6m", "armv6-m", "cortex-m0")
// If all else failed, return the most base CPU LLVM supports.
.Default("arm7tdmi");
}
@@ -141,10 +217,12 @@ static const char *getLLVMArchSuffixForARM(StringRef CPU) {
.Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "v6")
.Cases("arm1176jzf-s", "mpcorenovfp", "mpcore", "v6")
.Cases("arm1156t2-s", "arm1156t2f-s", "v6t2")
- .Cases("cortex-a8", "cortex-a9", "cortex-a15", "v7")
- .Case("cortex-m3", "v7m")
- .Case("cortex-m4", "v7m")
+ .Cases("cortex-a5", "cortex-a7", "cortex-a8", "v7")
+ .Cases("cortex-a9", "cortex-a15", "v7")
+ .Case("cortex-r5", "v7r")
.Case("cortex-m0", "v6m")
+ .Case("cortex-m3", "v7m")
+ .Case("cortex-m4", "v7em")
.Case("cortex-a9-mp", "v7f")
.Case("swift", "v7s")
.Default("");
@@ -166,7 +244,8 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args,
// FIXME: Thumb should just be another -target-feaure, not in the triple.
StringRef Suffix =
getLLVMArchSuffixForARM(getARMTargetCPU(Args, Triple));
- bool ThumbDefault = (Suffix.startswith("v7") && getTriple().isOSDarwin());
+ bool ThumbDefault = Suffix.startswith("v6m") ||
+ (Suffix.startswith("v7") && getTriple().isOSDarwin());
std::string ArchName = "arm";
// Assembly files should start in ARM mode.
@@ -197,7 +276,8 @@ void ToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
// Each toolchain should provide the appropriate include flags.
}
-void ToolChain::addClangTargetOptions(ArgStringList &CC1Args) const {
+void ToolChain::addClangTargetOptions(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
}
ToolChain::RuntimeLibType ToolChain::GetRuntimeLibType(
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index 7d70cd5..bcfe51e 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -8,7 +8,9 @@
//===----------------------------------------------------------------------===//
#include "ToolChains.h"
-
+#include "SanitizerArgs.h"
+#include "clang/Basic/ObjCRuntime.h"
+#include "clang/Basic/Version.h"
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Compilation.h"
@@ -17,34 +19,31 @@
#include "clang/Driver/OptTable.h"
#include "clang/Driver/Option.h"
#include "clang/Driver/Options.h"
-#include "clang/Basic/ObjCRuntime.h"
-#include "clang/Basic/Version.h"
-
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
-#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
-#include "SanitizerArgs.h"
+// FIXME: This needs to be listed last until we fix the broken include guards
+// in these files and the LLVM config.h files.
+#include "clang/Config/config.h" // for GCC_INSTALL_PREFIX
#include <cstdlib> // ::getenv
-#include "clang/Config/config.h" // for GCC_INSTALL_PREFIX
-
using namespace clang::driver;
using namespace clang::driver::toolchains;
using namespace clang;
/// Darwin - Darwin tool chain for i386 and x86_64.
-Darwin::Darwin(const Driver &D, const llvm::Triple& Triple)
- : ToolChain(D, Triple), TargetInitialized(false)
+Darwin::Darwin(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
+ : ToolChain(D, Triple, Args), TargetInitialized(false)
{
// Compute the initial Darwin version from the triple
unsigned Major, Minor, Micro;
@@ -100,15 +99,17 @@ bool Darwin::hasBlocksRuntime() const {
static const char *GetArmArchForMArch(StringRef Value) {
return llvm::StringSwitch<const char*>(Value)
.Case("armv6k", "armv6")
+ .Case("armv6m", "armv6m")
.Case("armv5tej", "armv5")
.Case("xscale", "xscale")
.Case("armv4t", "armv4t")
.Case("armv7", "armv7")
.Cases("armv7a", "armv7-a", "armv7")
.Cases("armv7r", "armv7-r", "armv7")
- .Cases("armv7m", "armv7-m", "armv7")
+ .Cases("armv7em", "armv7e-m", "armv7em")
.Cases("armv7f", "armv7-f", "armv7f")
.Cases("armv7k", "armv7-k", "armv7k")
+ .Cases("armv7m", "armv7-m", "armv7m")
.Cases("armv7s", "armv7-s", "armv7s")
.Default(0);
}
@@ -119,11 +120,12 @@ static const char *GetArmArchForMCpu(StringRef Value) {
.Cases("arm10e", "arm10tdmi", "armv5")
.Cases("arm1020t", "arm1020e", "arm1022e", "arm1026ej-s", "armv5")
.Case("xscale", "xscale")
- .Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s",
- "arm1176jzf-s", "cortex-m0", "armv6")
- .Cases("cortex-a8", "cortex-r4", "cortex-m3", "cortex-a9", "cortex-a15",
- "armv7")
+ .Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "arm1176jzf-s", "armv6")
+ .Case("cortex-m0", "armv6m")
+ .Cases("cortex-a8", "cortex-r4", "cortex-a9", "cortex-a15", "armv7")
.Case("cortex-a9-mp", "armv7f")
+ .Case("cortex-m3", "armv7m")
+ .Case("cortex-m4", "armv7em")
.Case("swift", "armv7s")
.Default(0);
}
@@ -149,10 +151,6 @@ StringRef Darwin::getDarwinArchName(const ArgList &Args) const {
}
Darwin::~Darwin() {
- // Free tool implementations.
- for (llvm::DenseMap<unsigned, Tool*>::iterator
- it = Tools.begin(), ie = Tools.end(); it != ie; ++it)
- delete it->second;
}
std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args,
@@ -174,57 +172,36 @@ std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args,
void Generic_ELF::anchor() {}
-Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const {
- Action::ActionClass Key = JA.getKind();
-
- if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) {
- // FIXME: This seems like a hacky way to choose clang frontend.
- Key = Action::AnalyzeJobClass;
- }
-
- bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as,
- options::OPT_no_integrated_as,
- IsIntegratedAssemblerDefault());
-
- Tool *&T = Tools[Key];
- if (!T) {
- switch (Key) {
- case Action::InputClass:
- case Action::BindArchClass:
- llvm_unreachable("Invalid tool kind.");
- case Action::PreprocessJobClass:
- T = new tools::darwin::Preprocess(*this); break;
- case Action::AnalyzeJobClass:
- case Action::MigrateJobClass:
- T = new tools::Clang(*this); break;
- case Action::PrecompileJobClass:
- case Action::CompileJobClass:
- T = new tools::darwin::Compile(*this); break;
- case Action::AssembleJobClass: {
- if (UseIntegratedAs)
- T = new tools::ClangAs(*this);
- else
- T = new tools::darwin::Assemble(*this);
- break;
- }
- case Action::LinkJobClass:
- T = new tools::darwin::Link(*this); break;
- case Action::LipoJobClass:
- T = new tools::darwin::Lipo(*this); break;
- case Action::DsymutilJobClass:
- T = new tools::darwin::Dsymutil(*this); break;
- case Action::VerifyJobClass:
- T = new tools::darwin::VerifyDebug(*this); break;
- }
+Tool *Darwin::getTool(Action::ActionClass AC) const {
+ switch (AC) {
+ case Action::LipoJobClass:
+ if (!Lipo)
+ Lipo.reset(new tools::darwin::Lipo(*this));
+ return Lipo.get();
+ case Action::DsymutilJobClass:
+ if (!Dsymutil)
+ Dsymutil.reset(new tools::darwin::Dsymutil(*this));
+ return Dsymutil.get();
+ case Action::VerifyJobClass:
+ if (!VerifyDebug)
+ VerifyDebug.reset(new tools::darwin::VerifyDebug(*this));
+ return VerifyDebug.get();
+ default:
+ return ToolChain::getTool(AC);
}
+}
- return *T;
+Tool *Darwin::buildLinker() const {
+ return new tools::darwin::Link(*this);
}
+Tool *Darwin::buildAssembler() const {
+ return new tools::darwin::Assemble(*this);
+}
-DarwinClang::DarwinClang(const Driver &D, const llvm::Triple& Triple)
- : Darwin(D, Triple)
+DarwinClang::DarwinClang(const Driver &D, const llvm::Triple& Triple,
+ const ArgList &Args)
+ : Darwin(D, Triple, Args)
{
getProgramPaths().push_back(getDriver().getInstalledDir());
if (getDriver().getInstalledDir() != getDriver().Dir)
@@ -261,16 +238,18 @@ void DarwinClang::AddLinkARCArgs(const ArgList &Args,
void DarwinClang::AddLinkRuntimeLib(const ArgList &Args,
ArgStringList &CmdArgs,
- const char *DarwinStaticLib) const {
+ const char *DarwinStaticLib,
+ bool AlwaysLink) const {
llvm::sys::Path P(getDriver().ResourceDir);
P.appendComponent("lib");
P.appendComponent("darwin");
P.appendComponent(DarwinStaticLib);
// For now, allow missing resource libraries to support developers who may
- // not have compiler-rt checked out or integrated into their build.
+ // not have compiler-rt checked out or integrated into their build (unless
+ // we explicitly force linking with this library).
bool Exists;
- if (!llvm::sys::fs::exists(P.str(), Exists) && Exists)
+ if (AlwaysLink || (!llvm::sys::fs::exists(P.str(), Exists) && Exists))
CmdArgs.push_back(Args.MakeArgString(P.str()));
}
@@ -317,21 +296,35 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
SanitizerArgs Sanitize(getDriver(), Args);
+ // Add Ubsan runtime library, if required.
+ if (Sanitize.needsUbsanRt()) {
+ if (isTargetIPhoneOS()) {
+ getDriver().Diag(diag::err_drv_clang_unsupported_per_platform)
+ << "-fsanitize=undefined";
+ } else {
+ AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.ubsan_osx.a", true);
+
+ // The Ubsan runtime library requires C++.
+ AddCXXStdlibLibArgs(Args, CmdArgs);
+ }
+ }
+
// Add ASAN runtime library, if required. Dynamic libraries and bundles
// should not be linked with the runtime library.
if (Sanitize.needsAsanRt()) {
- if (Args.hasArg(options::OPT_dynamiclib) ||
- Args.hasArg(options::OPT_bundle)) return;
- if (isTargetIPhoneOS()) {
+ if (isTargetIPhoneOS() && !isTargetIOSSimulator()) {
getDriver().Diag(diag::err_drv_clang_unsupported_per_platform)
<< "-fsanitize=address";
} else {
- AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.asan_osx.a");
-
- // The ASAN runtime library requires C++ and CoreFoundation.
- AddCXXStdlibLibArgs(Args, CmdArgs);
- CmdArgs.push_back("-framework");
- CmdArgs.push_back("CoreFoundation");
+ if (Args.hasArg(options::OPT_dynamiclib) ||
+ Args.hasArg(options::OPT_bundle)) {
+ // Assume the binary will provide the ASan runtime.
+ } else {
+ AddLinkRuntimeLib(Args, CmdArgs,
+ "libclang_rt.asan_osx_dynamic.dylib", true);
+ // The ASAN runtime library requires C++.
+ AddCXXStdlibLibArgs(Args, CmdArgs);
+ }
}
}
@@ -381,11 +374,17 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
// Support allowing the SDKROOT environment variable used by xcrun and other
// Xcode tools to define the default sysroot, by making it the default for
// isysroot.
- if (!Args.hasArg(options::OPT_isysroot)) {
+ if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
+ // Warn if the path does not exist.
+ bool Exists;
+ if (llvm::sys::fs::exists(A->getValue(), Exists) || !Exists)
+ getDriver().Diag(clang::diag::warn_missing_sysroot) << A->getValue();
+ } else {
if (char *env = ::getenv("SDKROOT")) {
- // We only use this value as the default if it is an absolute path and
- // exists.
- if (llvm::sys::path::is_absolute(env) && llvm::sys::fs::exists(env)) {
+ // We only use this value as the default if it is an absolute path,
+ // exists, and it is not the root path.
+ if (llvm::sys::path::is_absolute(env) && llvm::sys::fs::exists(env) &&
+ StringRef(env) != "/") {
Args.append(Args.MakeSeparateArg(
0, Opts.getOption(options::OPT_isysroot), env));
}
@@ -796,12 +795,18 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
DAL->AddJoinedArg(0, MArch, "xscale");
else if (Name == "armv6")
DAL->AddJoinedArg(0, MArch, "armv6k");
+ else if (Name == "armv6m")
+ DAL->AddJoinedArg(0, MArch, "armv6m");
else if (Name == "armv7")
DAL->AddJoinedArg(0, MArch, "armv7a");
+ else if (Name == "armv7em")
+ DAL->AddJoinedArg(0, MArch, "armv7em");
else if (Name == "armv7f")
DAL->AddJoinedArg(0, MArch, "armv7f");
else if (Name == "armv7k")
DAL->AddJoinedArg(0, MArch, "armv7k");
+ else if (Name == "armv7m")
+ DAL->AddJoinedArg(0, MArch, "armv7m");
else if (Name == "armv7s")
DAL->AddJoinedArg(0, MArch, "armv7s");
@@ -931,7 +936,7 @@ Generic_GCC::GCCVersion Linux::GCCVersion::Parse(StringRef VersionText) {
// And retains any patch number it finds.
StringRef PatchText = GoodVersion.PatchSuffix = Second.second.str();
if (!PatchText.empty()) {
- if (unsigned EndNumber = PatchText.find_first_not_of("0123456789")) {
+ if (size_t EndNumber = PatchText.find_first_not_of("0123456789")) {
// Try to parse the number and any suffix.
if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) ||
GoodVersion.Patch < 0)
@@ -945,20 +950,33 @@ Generic_GCC::GCCVersion Linux::GCCVersion::Parse(StringRef VersionText) {
/// \brief Less-than for GCCVersion, implementing a Strict Weak Ordering.
bool Generic_GCC::GCCVersion::operator<(const GCCVersion &RHS) const {
- if (Major < RHS.Major) return true; if (Major > RHS.Major) return false;
- if (Minor < RHS.Minor) return true; if (Minor > RHS.Minor) return false;
-
- // Note that we rank versions with *no* patch specified is better than ones
- // hard-coding a patch version. Thus if the RHS has no patch, it always
- // wins, and the LHS only wins if it has no patch and the RHS does have
- // a patch.
- if (RHS.Patch == -1) return true; if (Patch == -1) return false;
- if (Patch < RHS.Patch) return true; if (Patch > RHS.Patch) return false;
- if (PatchSuffix == RHS.PatchSuffix) return false;
-
- // Finally, between completely tied version numbers, the version with the
- // suffix loses as we prefer full releases.
- if (RHS.PatchSuffix.empty()) return true;
+ if (Major != RHS.Major)
+ return Major < RHS.Major;
+ if (Minor != RHS.Minor)
+ return Minor < RHS.Minor;
+ if (Patch != RHS.Patch) {
+ // Note that versions without a specified patch sort higher than those with
+ // a patch.
+ if (RHS.Patch == -1)
+ return true;
+ if (Patch == -1)
+ return false;
+
+ // Otherwise just sort on the patch itself.
+ return Patch < RHS.Patch;
+ }
+ if (PatchSuffix != RHS.PatchSuffix) {
+ // Sort empty suffixes higher.
+ if (RHS.PatchSuffix.empty())
+ return true;
+ if (PatchSuffix.empty())
+ return false;
+
+ // Provide a lexicographic sort to make this a total ordering.
+ return PatchSuffix < RHS.PatchSuffix;
+ }
+
+ // The versions are equal.
return false;
}
@@ -1051,6 +1069,12 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
// Declare a bunch of static data sets that we'll select between below. These
// are specifically designed to always refer to string literals to avoid any
// lifetime or initialization issues.
+ static const char *const AArch64LibDirs[] = { "/lib" };
+ static const char *const AArch64Triples[] = {
+ "aarch64-none-linux-gnu",
+ "aarch64-linux-gnu"
+ };
+
static const char *const ARMLibDirs[] = { "/lib" };
static const char *const ARMTriples[] = {
"arm-linux-gnueabi",
@@ -1078,6 +1102,7 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
"i686-pc-linux-gnu",
"i486-linux-gnu",
"i386-linux-gnu",
+ "i386-redhat-linux6E",
"i686-redhat-linux",
"i586-redhat-linux",
"i386-redhat-linux",
@@ -1103,6 +1128,7 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
static const char *const PPCTriples[] = {
"powerpc-linux-gnu",
"powerpc-unknown-linux-gnu",
+ "powerpc-linux-gnuspe",
"powerpc-suse-linux",
"powerpc-montavista-linuxspe"
};
@@ -1115,6 +1141,16 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
};
switch (TargetTriple.getArch()) {
+ case llvm::Triple::aarch64:
+ LibDirs.append(AArch64LibDirs, AArch64LibDirs
+ + llvm::array_lengthof(AArch64LibDirs));
+ TripleAliases.append(
+ AArch64Triples, AArch64Triples + llvm::array_lengthof(AArch64Triples));
+ MultiarchLibDirs.append(
+ AArch64LibDirs, AArch64LibDirs + llvm::array_lengthof(AArch64LibDirs));
+ MultiarchTripleAliases.append(
+ AArch64Triples, AArch64Triples + llvm::array_lengthof(AArch64Triples));
+ break;
case llvm::Triple::arm:
case llvm::Triple::thumb:
LibDirs.append(ARMLibDirs, ARMLibDirs + llvm::array_lengthof(ARMLibDirs));
@@ -1316,60 +1352,40 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple& Triple,
const ArgList &Args)
- : ToolChain(D, Triple), GCCInstallation(getDriver(), Triple, Args) {
+ : ToolChain(D, Triple, Args), GCCInstallation(getDriver(), Triple, Args) {
getProgramPaths().push_back(getDriver().getInstalledDir());
if (getDriver().getInstalledDir() != getDriver().Dir)
getProgramPaths().push_back(getDriver().Dir);
}
Generic_GCC::~Generic_GCC() {
- // Free tool implementations.
- for (llvm::DenseMap<unsigned, Tool*>::iterator
- it = Tools.begin(), ie = Tools.end(); it != ie; ++it)
- delete it->second;
-}
-
-Tool &Generic_GCC::SelectTool(const Compilation &C,
- const JobAction &JA,
- const ActionList &Inputs) const {
- Action::ActionClass Key;
- if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
- Key = Action::AnalyzeJobClass;
- else
- Key = JA.getKind();
-
- Tool *&T = Tools[Key];
- if (!T) {
- switch (Key) {
- case Action::InputClass:
- case Action::BindArchClass:
- llvm_unreachable("Invalid tool kind.");
- case Action::PreprocessJobClass:
- T = new tools::gcc::Preprocess(*this); break;
- case Action::PrecompileJobClass:
- T = new tools::gcc::Precompile(*this); break;
- case Action::AnalyzeJobClass:
- case Action::MigrateJobClass:
- T = new tools::Clang(*this); break;
- case Action::CompileJobClass:
- T = new tools::gcc::Compile(*this); break;
- case Action::AssembleJobClass:
- T = new tools::gcc::Assemble(*this); break;
- case Action::LinkJobClass:
- T = new tools::gcc::Link(*this); break;
-
- // This is a bit ungeneric, but the only platform using a driver
- // driver is Darwin.
- case Action::LipoJobClass:
- T = new tools::darwin::Lipo(*this); break;
- case Action::DsymutilJobClass:
- T = new tools::darwin::Dsymutil(*this); break;
- case Action::VerifyJobClass:
- T = new tools::darwin::VerifyDebug(*this); break;
- }
+}
+
+Tool *Generic_GCC::getTool(Action::ActionClass AC) const {
+ switch (AC) {
+ case Action::PreprocessJobClass:
+ if (!Preprocess)
+ Preprocess.reset(new tools::gcc::Preprocess(*this));
+ return Preprocess.get();
+ case Action::PrecompileJobClass:
+ if (!Precompile)
+ Precompile.reset(new tools::gcc::Precompile(*this));
+ return Precompile.get();
+ case Action::CompileJobClass:
+ if (!Compile)
+ Compile.reset(new tools::gcc::Compile(*this));
+ return Compile.get();
+ default:
+ return ToolChain::getTool(AC);
}
+}
+
+Tool *Generic_GCC::buildAssembler() const {
+ return new tools::gcc::Assemble(*this);
+}
- return *T;
+Tool *Generic_GCC::buildLinker() const {
+ return new tools::gcc::Link(*this);
}
bool Generic_GCC::IsUnwindTablesDefault() const {
@@ -1386,71 +1402,216 @@ bool Generic_GCC::isPICDefaultForced() const {
/// Hexagon Toolchain
-Hexagon_TC::Hexagon_TC(const Driver &D, const llvm::Triple& Triple)
- : ToolChain(D, Triple) {
- getProgramPaths().push_back(getDriver().getInstalledDir());
- if (getDriver().getInstalledDir() != getDriver().Dir.c_str())
- getProgramPaths().push_back(getDriver().Dir);
+std::string Hexagon_TC::GetGnuDir(const std::string &InstalledDir) {
+
+ // Locate the rest of the toolchain ...
+ if (strlen(GCC_INSTALL_PREFIX))
+ return std::string(GCC_INSTALL_PREFIX);
+
+ std::string InstallRelDir = InstalledDir + "/../../gnu";
+ if (llvm::sys::fs::exists(InstallRelDir))
+ return InstallRelDir;
+
+ std::string PrefixRelDir = std::string(LLVM_PREFIX) + "/../gnu";
+ if (llvm::sys::fs::exists(PrefixRelDir))
+ return PrefixRelDir;
+
+ return InstallRelDir;
+}
+
+static void GetHexagonLibraryPaths(
+ const ArgList &Args,
+ const std::string Ver,
+ const std::string MarchString,
+ const std::string &InstalledDir,
+ ToolChain::path_list *LibPaths)
+{
+ bool buildingLib = Args.hasArg(options::OPT_shared);
+
+ //----------------------------------------------------------------------------
+ // -L Args
+ //----------------------------------------------------------------------------
+ for (arg_iterator
+ it = Args.filtered_begin(options::OPT_L),
+ ie = Args.filtered_end();
+ it != ie;
+ ++it) {
+ for (unsigned i = 0, e = (*it)->getNumValues(); i != e; ++i)
+ LibPaths->push_back((*it)->getValue(i));
+ }
+
+ //----------------------------------------------------------------------------
+ // Other standard paths
+ //----------------------------------------------------------------------------
+ const std::string MarchSuffix = "/" + MarchString;
+ const std::string G0Suffix = "/G0";
+ const std::string MarchG0Suffix = MarchSuffix + G0Suffix;
+ const std::string RootDir = Hexagon_TC::GetGnuDir(InstalledDir) + "/";
+
+ // lib/gcc/hexagon/...
+ std::string LibGCCHexagonDir = RootDir + "lib/gcc/hexagon/";
+ if (buildingLib) {
+ LibPaths->push_back(LibGCCHexagonDir + Ver + MarchG0Suffix);
+ LibPaths->push_back(LibGCCHexagonDir + Ver + G0Suffix);
+ }
+ LibPaths->push_back(LibGCCHexagonDir + Ver + MarchSuffix);
+ LibPaths->push_back(LibGCCHexagonDir + Ver);
+
+ // lib/gcc/...
+ LibPaths->push_back(RootDir + "lib/gcc");
+
+ // hexagon/lib/...
+ std::string HexagonLibDir = RootDir + "hexagon/lib";
+ if (buildingLib) {
+ LibPaths->push_back(HexagonLibDir + MarchG0Suffix);
+ LibPaths->push_back(HexagonLibDir + G0Suffix);
+ }
+ LibPaths->push_back(HexagonLibDir + MarchSuffix);
+ LibPaths->push_back(HexagonLibDir);
+}
+
+Hexagon_TC::Hexagon_TC(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : Linux(D, Triple, Args) {
+ const std::string InstalledDir(getDriver().getInstalledDir());
+ const std::string GnuDir = Hexagon_TC::GetGnuDir(InstalledDir);
+
+ // Note: Generic_GCC::Generic_GCC adds InstalledDir and getDriver().Dir to
+ // program paths
+ const std::string BinDir(GnuDir + "/bin");
+ if (llvm::sys::fs::exists(BinDir))
+ getProgramPaths().push_back(BinDir);
+
+ // Determine version of GCC libraries and headers to use.
+ const std::string HexagonDir(GnuDir + "/lib/gcc/hexagon");
+ llvm::error_code ec;
+ GCCVersion MaxVersion= GCCVersion::Parse("0.0.0");
+ for (llvm::sys::fs::directory_iterator di(HexagonDir, ec), de;
+ !ec && di != de; di = di.increment(ec)) {
+ GCCVersion cv = GCCVersion::Parse(llvm::sys::path::filename(di->path()));
+ if (MaxVersion < cv)
+ MaxVersion = cv;
+ }
+ GCCLibAndIncVersion = MaxVersion;
+
+ ToolChain::path_list *LibPaths= &getFilePaths();
+
+ // Remove paths added by Linux toolchain. Currently Hexagon_TC really targets
+ // 'elf' OS type, so the Linux paths are not appropriate. When we actually
+ // support 'linux' we'll need to fix this up
+ LibPaths->clear();
+
+ GetHexagonLibraryPaths(
+ Args,
+ GetGCCLibAndIncVersion(),
+ GetTargetCPU(Args),
+ InstalledDir,
+ LibPaths);
}
Hexagon_TC::~Hexagon_TC() {
- // Free tool implementations.
- for (llvm::DenseMap<unsigned, Tool*>::iterator
- it = Tools.begin(), ie = Tools.end(); it != ie; ++it)
- delete it->second;
-}
-
-Tool &Hexagon_TC::SelectTool(const Compilation &C,
- const JobAction &JA,
- const ActionList &Inputs) const {
- Action::ActionClass Key;
- // if (JA.getKind () == Action::CompileJobClass)
- // Key = JA.getKind ();
- // else
-
- if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
- Key = Action::AnalyzeJobClass;
- else
- Key = JA.getKind();
- // if ((JA.getKind () == Action::CompileJobClass)
- // && (JA.getType () != types::TY_LTO_BC)) {
- // Key = JA.getKind ();
- // }
-
- Tool *&T = Tools[Key];
- if (!T) {
- switch (Key) {
- case Action::InputClass:
- case Action::BindArchClass:
- assert(0 && "Invalid tool kind.");
- case Action::AnalyzeJobClass:
- T = new tools::Clang(*this); break;
- case Action::AssembleJobClass:
- T = new tools::hexagon::Assemble(*this); break;
- case Action::LinkJobClass:
- T = new tools::hexagon::Link(*this); break;
- default:
- assert(false && "Unsupported action for Hexagon target.");
- }
+}
+
+Tool *Hexagon_TC::buildAssembler() const {
+ return new tools::hexagon::Assemble(*this);
+}
+
+Tool *Hexagon_TC::buildLinker() const {
+ return new tools::hexagon::Link(*this);
+}
+
+void Hexagon_TC::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ const Driver &D = getDriver();
+
+ if (DriverArgs.hasArg(options::OPT_nostdinc) ||
+ DriverArgs.hasArg(options::OPT_nostdlibinc))
+ return;
+
+ llvm::sys::Path InstallDir(D.InstalledDir);
+ std::string Ver(GetGCCLibAndIncVersion());
+ std::string GnuDir = Hexagon_TC::GetGnuDir(D.InstalledDir);
+ std::string HexagonDir(GnuDir + "/lib/gcc/hexagon/" + Ver);
+ addExternCSystemInclude(DriverArgs, CC1Args, HexagonDir + "/include");
+ addExternCSystemInclude(DriverArgs, CC1Args, HexagonDir + "/include-fixed");
+ addExternCSystemInclude(DriverArgs, CC1Args, GnuDir + "/hexagon/include");
+}
+
+void Hexagon_TC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+
+ if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
+ DriverArgs.hasArg(options::OPT_nostdincxx))
+ return;
+
+ const Driver &D = getDriver();
+ std::string Ver(GetGCCLibAndIncVersion());
+ llvm::sys::Path IncludeDir(Hexagon_TC::GetGnuDir(D.InstalledDir));
+
+ IncludeDir.appendComponent("hexagon/include/c++/");
+ IncludeDir.appendComponent(Ver);
+ addSystemInclude(DriverArgs, CC1Args, IncludeDir.str());
+}
+
+ToolChain::CXXStdlibType
+Hexagon_TC::GetCXXStdlibType(const ArgList &Args) const {
+ Arg *A = Args.getLastArg(options::OPT_stdlib_EQ);
+ if (!A)
+ return ToolChain::CST_Libstdcxx;
+
+ StringRef Value = A->getValue();
+ if (Value != "libstdc++") {
+ getDriver().Diag(diag::err_drv_invalid_stdlib_name)
+ << A->getAsString(Args);
}
- return *T;
+ return ToolChain::CST_Libstdcxx;
}
-bool Hexagon_TC::isPICDefault() const {
- return false;
+static Arg *GetLastHexagonArchArg(const ArgList &Args)
+{
+ Arg *A = NULL;
+
+ for (ArgList::const_iterator it = Args.begin(), ie = Args.end();
+ it != ie; ++it) {
+ if ((*it)->getOption().matches(options::OPT_march_EQ) ||
+ (*it)->getOption().matches(options::OPT_mcpu_EQ)) {
+ A = *it;
+ A->claim();
+ } else if ((*it)->getOption().matches(options::OPT_m_Joined)) {
+ StringRef Value = (*it)->getValue(0);
+ if (Value.startswith("v")) {
+ A = *it;
+ A->claim();
+ }
+ }
+ }
+ return A;
}
-bool Hexagon_TC::isPICDefaultForced() const {
- return false;
+StringRef Hexagon_TC::GetTargetCPU(const ArgList &Args)
+{
+ // Select the default CPU (v4) if none was given or detection failed.
+ Arg *A = GetLastHexagonArchArg (Args);
+ if (A) {
+ StringRef WhichHexagon = A->getValue();
+ if (WhichHexagon.startswith("hexagon"))
+ return WhichHexagon.substr(sizeof("hexagon") - 1);
+ if (WhichHexagon != "")
+ return WhichHexagon;
+ }
+
+ return "v4";
}
+// End Hexagon
/// TCEToolChain - A tool chain using the llvm bitcode tools to perform
/// all subcommands. See http://tce.cs.tut.fi for our peculiar target.
/// Currently does not support anything else but compilation.
-TCEToolChain::TCEToolChain(const Driver &D, const llvm::Triple& Triple)
- : ToolChain(D, Triple) {
+TCEToolChain::TCEToolChain(const Driver &D, const llvm::Triple& Triple,
+ const ArgList &Args)
+ : ToolChain(D, Triple, Args) {
// Path mangling to find libexec
std::string Path(getDriver().Dir);
@@ -1459,9 +1620,6 @@ TCEToolChain::TCEToolChain(const Driver &D, const llvm::Triple& Triple)
}
TCEToolChain::~TCEToolChain() {
- for (llvm::DenseMap<unsigned, Tool*>::iterator
- it = Tools.begin(), ie = Tools.end(); it != ie; ++it)
- delete it->second;
}
bool TCEToolChain::IsMathErrnoDefault() const {
@@ -1476,26 +1634,6 @@ bool TCEToolChain::isPICDefaultForced() const {
return false;
}
-Tool &TCEToolChain::SelectTool(const Compilation &C,
- const JobAction &JA,
- const ActionList &Inputs) const {
- Action::ActionClass Key;
- Key = Action::AnalyzeJobClass;
-
- Tool *&T = Tools[Key];
- if (!T) {
- switch (Key) {
- case Action::PreprocessJobClass:
- T = new tools::gcc::Preprocess(*this); break;
- case Action::AnalyzeJobClass:
- T = new tools::Clang(*this); break;
- default:
- llvm_unreachable("Unsupported action for TCE target.");
- }
- }
- return *T;
-}
-
/// OpenBSD - OpenBSD tool chain which can call as(1) and ld(1) directly.
OpenBSD::OpenBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
@@ -1504,36 +1642,12 @@ OpenBSD::OpenBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Arg
getFilePaths().push_back("/usr/lib");
}
-Tool &OpenBSD::SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const {
- Action::ActionClass Key;
- if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
- Key = Action::AnalyzeJobClass;
- else
- Key = JA.getKind();
-
- bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as,
- options::OPT_no_integrated_as,
- IsIntegratedAssemblerDefault());
-
- Tool *&T = Tools[Key];
- if (!T) {
- switch (Key) {
- case Action::AssembleJobClass: {
- if (UseIntegratedAs)
- T = new tools::ClangAs(*this);
- else
- T = new tools::openbsd::Assemble(*this);
- break;
- }
- case Action::LinkJobClass:
- T = new tools::openbsd::Link(*this); break;
- default:
- T = &Generic_GCC::SelectTool(C, JA, Inputs);
- }
- }
+Tool *OpenBSD::buildAssembler() const {
+ return new tools::openbsd::Assemble(*this);
+}
- return *T;
+Tool *OpenBSD::buildLinker() const {
+ return new tools::openbsd::Link(*this);
}
/// Bitrig - Bitrig tool chain which can call as(1) and ld(1) directly.
@@ -1544,36 +1658,12 @@ Bitrig::Bitrig(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
getFilePaths().push_back("/usr/lib");
}
-Tool &Bitrig::SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const {
- Action::ActionClass Key;
- if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
- Key = Action::AnalyzeJobClass;
- else
- Key = JA.getKind();
-
- bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as,
- options::OPT_no_integrated_as,
- IsIntegratedAssemblerDefault());
-
- Tool *&T = Tools[Key];
- if (!T) {
- switch (Key) {
- case Action::AssembleJobClass: {
- if (UseIntegratedAs)
- T = new tools::ClangAs(*this);
- else
- T = new tools::bitrig::Assemble(*this);
- break;
- }
- case Action::LinkJobClass:
- T = new tools::bitrig::Link(*this); break;
- default:
- T = &Generic_GCC::SelectTool(C, JA, Inputs);
- }
- }
+Tool *Bitrig::buildAssembler() const {
+ return new tools::bitrig::Assemble(*this);
+}
- return *T;
+Tool *Bitrig::buildLinker() const {
+ return new tools::bitrig::Link(*this);
}
void Bitrig::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
@@ -1636,35 +1726,25 @@ FreeBSD::FreeBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Arg
getFilePaths().push_back(getDriver().SysRoot + "/usr/lib");
}
-Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const {
- Action::ActionClass Key;
- if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
- Key = Action::AnalyzeJobClass;
- else
- Key = JA.getKind();
-
- bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as,
- options::OPT_no_integrated_as,
- IsIntegratedAssemblerDefault());
-
- Tool *&T = Tools[Key];
- if (!T) {
- switch (Key) {
- case Action::AssembleJobClass:
- if (UseIntegratedAs)
- T = new tools::ClangAs(*this);
- else
- T = new tools::freebsd::Assemble(*this);
- break;
- case Action::LinkJobClass:
- T = new tools::freebsd::Link(*this); break;
- default:
- T = &Generic_GCC::SelectTool(C, JA, Inputs);
- }
- }
+Tool *FreeBSD::buildAssembler() const {
+ return new tools::freebsd::Assemble(*this);
+}
+
+Tool *FreeBSD::buildLinker() const {
+ return new tools::freebsd::Link(*this);
+}
- return *T;
+bool FreeBSD::UseSjLjExceptions() const {
+ // FreeBSD uses SjLj exceptions on ARM oabi.
+ switch (getTriple().getEnvironment()) {
+ case llvm::Triple::GNUEABI:
+ case llvm::Triple::EABI:
+ return false;
+
+ default:
+ return (getTriple().getArch() == llvm::Triple::arm ||
+ getTriple().getArch() == llvm::Triple::thumb);
+ }
}
/// NetBSD - NetBSD tool chain which can call as(1) and ld(1) directly.
@@ -1685,36 +1765,12 @@ NetBSD::NetBSD(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
}
}
-Tool &NetBSD::SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const {
- Action::ActionClass Key;
- if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
- Key = Action::AnalyzeJobClass;
- else
- Key = JA.getKind();
-
- bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as,
- options::OPT_no_integrated_as,
- IsIntegratedAssemblerDefault());
-
- Tool *&T = Tools[Key];
- if (!T) {
- switch (Key) {
- case Action::AssembleJobClass:
- if (UseIntegratedAs)
- T = new tools::ClangAs(*this);
- else
- T = new tools::netbsd::Assemble(*this);
- break;
- case Action::LinkJobClass:
- T = new tools::netbsd::Link(*this);
- break;
- default:
- T = &Generic_GCC::SelectTool(C, JA, Inputs);
- }
- }
+Tool *NetBSD::buildAssembler() const {
+ return new tools::netbsd::Assemble(*this);
+}
- return *T;
+Tool *NetBSD::buildLinker() const {
+ return new tools::netbsd::Link(*this);
}
/// Minix - Minix tool chain which can call as(1) and ld(1) directly.
@@ -1725,27 +1781,12 @@ Minix::Minix(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
getFilePaths().push_back("/usr/lib");
}
-Tool &Minix::SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const {
- Action::ActionClass Key;
- if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
- Key = Action::AnalyzeJobClass;
- else
- Key = JA.getKind();
-
- Tool *&T = Tools[Key];
- if (!T) {
- switch (Key) {
- case Action::AssembleJobClass:
- T = new tools::minix::Assemble(*this); break;
- case Action::LinkJobClass:
- T = new tools::minix::Link(*this); break;
- default:
- T = &Generic_GCC::SelectTool(C, JA, Inputs);
- }
- }
+Tool *Minix::buildAssembler() const {
+ return new tools::minix::Assemble(*this);
+}
- return *T;
+Tool *Minix::buildLinker() const {
+ return new tools::minix::Link(*this);
}
/// AuroraUX - AuroraUX tool chain which can call as(1) and ld(1) directly.
@@ -1766,27 +1807,12 @@ AuroraUX::AuroraUX(const Driver &D, const llvm::Triple& Triple,
}
-Tool &AuroraUX::SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const {
- Action::ActionClass Key;
- if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
- Key = Action::AnalyzeJobClass;
- else
- Key = JA.getKind();
-
- Tool *&T = Tools[Key];
- if (!T) {
- switch (Key) {
- case Action::AssembleJobClass:
- T = new tools::auroraux::Assemble(*this); break;
- case Action::LinkJobClass:
- T = new tools::auroraux::Link(*this); break;
- default:
- T = &Generic_GCC::SelectTool(C, JA, Inputs);
- }
- }
+Tool *AuroraUX::buildAssembler() const {
+ return new tools::auroraux::Assemble(*this);
+}
- return *T;
+Tool *AuroraUX::buildLinker() const {
+ return new tools::auroraux::Link(*this);
}
/// Solaris - Solaris tool chain which can call as(1) and ld(1) directly.
@@ -1803,36 +1829,22 @@ Solaris::Solaris(const Driver &D, const llvm::Triple& Triple,
getFilePaths().push_back("/usr/lib");
}
-Tool &Solaris::SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const {
- Action::ActionClass Key;
- if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
- Key = Action::AnalyzeJobClass;
- else
- Key = JA.getKind();
-
- Tool *&T = Tools[Key];
- if (!T) {
- switch (Key) {
- case Action::AssembleJobClass:
- T = new tools::solaris::Assemble(*this); break;
- case Action::LinkJobClass:
- T = new tools::solaris::Link(*this); break;
- default:
- T = &Generic_GCC::SelectTool(C, JA, Inputs);
- }
- }
+Tool *Solaris::buildAssembler() const {
+ return new tools::solaris::Assemble(*this);
+}
- return *T;
+Tool *Solaris::buildLinker() const {
+ return new tools::solaris::Link(*this);
}
-/// Linux toolchain (very bare-bones at the moment).
+/// Distribution (very bare-bones at the moment).
-enum LinuxDistro {
+enum Distro {
ArchLinux,
DebianLenny,
DebianSqueeze,
DebianWheezy,
+ DebianJessie,
Exherbo,
RHEL4,
RHEL5,
@@ -1860,33 +1872,33 @@ enum LinuxDistro {
UnknownDistro
};
-static bool IsRedhat(enum LinuxDistro Distro) {
+static bool IsRedhat(enum Distro Distro) {
return (Distro >= Fedora13 && Distro <= FedoraRawhide) ||
(Distro >= RHEL4 && Distro <= RHEL6);
}
-static bool IsOpenSuse(enum LinuxDistro Distro) {
+static bool IsOpenSuse(enum Distro Distro) {
return Distro >= OpenSuse11_3 && Distro <= OpenSuse12_2;
}
-static bool IsDebian(enum LinuxDistro Distro) {
- return Distro >= DebianLenny && Distro <= DebianWheezy;
+static bool IsDebian(enum Distro Distro) {
+ return Distro >= DebianLenny && Distro <= DebianJessie;
}
-static bool IsUbuntu(enum LinuxDistro Distro) {
+static bool IsUbuntu(enum Distro Distro) {
return Distro >= UbuntuHardy && Distro <= UbuntuRaring;
}
-static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) {
+static Distro DetectDistro(llvm::Triple::ArchType Arch) {
OwningPtr<llvm::MemoryBuffer> File;
if (!llvm::MemoryBuffer::getFile("/etc/lsb-release", File)) {
StringRef Data = File.get()->getBuffer();
SmallVector<StringRef, 8> Lines;
Data.split(Lines, "\n");
- LinuxDistro Version = UnknownDistro;
+ Distro Version = UnknownDistro;
for (unsigned i = 0, s = Lines.size(); i != s; ++i)
if (Version == UnknownDistro && Lines[i].startswith("DISTRIB_CODENAME="))
- Version = llvm::StringSwitch<LinuxDistro>(Lines[i].substr(17))
+ Version = llvm::StringSwitch<Distro>(Lines[i].substr(17))
.Case("hardy", UbuntuHardy)
.Case("intrepid", UbuntuIntrepid)
.Case("jaunty", UbuntuJaunty)
@@ -1919,11 +1931,11 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) {
Data.find("release 6") != StringRef::npos)
return RHEL6;
else if ((Data.startswith("Red Hat Enterprise Linux") ||
- Data.startswith("CentOS")) &&
+ Data.startswith("CentOS")) &&
Data.find("release 5") != StringRef::npos)
return RHEL5;
else if ((Data.startswith("Red Hat Enterprise Linux") ||
- Data.startswith("CentOS")) &&
+ Data.startswith("CentOS")) &&
Data.find("release 4") != StringRef::npos)
return RHEL4;
return UnknownDistro;
@@ -1937,11 +1949,13 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) {
return DebianSqueeze;
else if (Data.startswith("wheezy/sid") || Data[0] == '7')
return DebianWheezy;
+ else if (Data.startswith("jessie/sid") || Data[0] == '8')
+ return DebianJessie;
return UnknownDistro;
}
if (!llvm::MemoryBuffer::getFile("/etc/SuSE-release", File))
- return llvm::StringSwitch<LinuxDistro>(File.get()->getBuffer())
+ return llvm::StringSwitch<Distro>(File.get()->getBuffer())
.StartsWith("openSUSE 11.3", OpenSuse11_3)
.StartsWith("openSUSE 11.4", OpenSuse11_4)
.StartsWith("openSUSE 12.1", OpenSuse12_1)
@@ -1994,6 +2008,9 @@ static std::string getMultiarchTriple(const llvm::Triple TargetTriple,
if (llvm::sys::fs::exists(SysRoot + "/lib/x86_64-linux-gnu"))
return "x86_64-linux-gnu";
return TargetTriple.str();
+ case llvm::Triple::aarch64:
+ if (llvm::sys::fs::exists(SysRoot + "/lib/aarch64-linux-gnu"))
+ return "aarch64-linux-gnu";
case llvm::Triple::mips:
if (llvm::sys::fs::exists(SysRoot + "/lib/mips-linux-gnu"))
return "mips-linux-gnu";
@@ -2003,6 +2020,8 @@ static std::string getMultiarchTriple(const llvm::Triple TargetTriple,
return "mipsel-linux-gnu";
return TargetTriple.str();
case llvm::Triple::ppc:
+ if (llvm::sys::fs::exists(SysRoot + "/lib/powerpc-linux-gnuspe"))
+ return "powerpc-linux-gnuspe";
if (llvm::sys::fs::exists(SysRoot + "/lib/powerpc-linux-gnu"))
return "powerpc-linux-gnu";
return TargetTriple.str();
@@ -2070,7 +2089,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
Linker = GetProgramPath("ld");
- LinuxDistro Distro = DetectLinuxDistro(Arch);
+ Distro Distro = DetectDistro(Arch);
if (IsOpenSuse(Distro) || IsUbuntu(Distro)) {
ExtraOpts.push_back("-z");
@@ -2101,7 +2120,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
ExtraOpts.push_back("--no-add-needed");
if (Distro == DebianSqueeze || Distro == DebianWheezy ||
- IsOpenSuse(Distro) ||
+ Distro == DebianJessie || IsOpenSuse(Distro) ||
(IsRedhat(Distro) && Distro != RHEL4 && Distro != RHEL5) ||
(IsUbuntu(Distro) && Distro >= UbuntuKarmic))
ExtraOpts.push_back("--build-id");
@@ -2184,40 +2203,24 @@ bool Linux::HasNativeLLVMSupport() const {
return true;
}
-Tool &Linux::SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const {
- Action::ActionClass Key;
- if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
- Key = Action::AnalyzeJobClass;
- else
- Key = JA.getKind();
-
- bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as,
- options::OPT_no_integrated_as,
- IsIntegratedAssemblerDefault());
-
- Tool *&T = Tools[Key];
- if (!T) {
- switch (Key) {
- case Action::AssembleJobClass:
- if (UseIntegratedAs)
- T = new tools::ClangAs(*this);
- else
- T = new tools::linuxtools::Assemble(*this);
- break;
- case Action::LinkJobClass:
- T = new tools::linuxtools::Link(*this); break;
- default:
- T = &Generic_GCC::SelectTool(C, JA, Inputs);
- }
- }
+Tool *Linux::buildLinker() const {
+ return new tools::gnutools::Link(*this);
+}
- return *T;
+Tool *Linux::buildAssembler() const {
+ return new tools::gnutools::Assemble(*this);
}
-void Linux::addClangTargetOptions(ArgStringList &CC1Args) const {
+void Linux::addClangTargetOptions(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
const Generic_GCC::GCCVersion &V = GCCInstallation.getVersion();
- if (V >= Generic_GCC::GCCVersion::Parse("4.7.0"))
+ bool UseInitArrayDefault
+ = V >= Generic_GCC::GCCVersion::Parse("4.7.0") ||
+ getTriple().getArch() == llvm::Triple::aarch64 ||
+ getTriple().getEnvironment() == llvm::Triple::Android;
+ if (DriverArgs.hasFlag(options::OPT_fuse_init_array,
+ options::OPT_fno_use_init_array,
+ UseInitArrayDefault))
CC1Args.push_back("-fuse-init-array");
}
@@ -2276,6 +2279,9 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
"/usr/include/i686-linux-gnu",
"/usr/include/i486-linux-gnu"
};
+ const StringRef AArch64MultiarchIncludeDirs[] = {
+ "/usr/include/aarch64-linux-gnu"
+ };
const StringRef ARMMultiarchIncludeDirs[] = {
"/usr/include/arm-linux-gnueabi"
};
@@ -2299,6 +2305,8 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
MultiarchIncludeDirs = X86_64MultiarchIncludeDirs;
} else if (getTriple().getArch() == llvm::Triple::x86) {
MultiarchIncludeDirs = X86MultiarchIncludeDirs;
+ } else if (getTriple().getArch() == llvm::Triple::aarch64) {
+ MultiarchIncludeDirs = AArch64MultiarchIncludeDirs;
} else if (getTriple().getArch() == llvm::Triple::arm) {
if (getTriple().getEnvironment() == llvm::Triple::GNUEABIHF)
MultiarchIncludeDirs = ARMHFMultiarchIncludeDirs;
@@ -2333,7 +2341,7 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/include");
}
-/// \brief Helper to add the thre variant paths for a libstdc++ installation.
+/// \brief Helper to add the three variant paths for a libstdc++ installation.
/*static*/ bool Linux::addLibStdCXXIncludePaths(Twine Base, Twine TargetArchDir,
const ArgList &DriverArgs,
ArgStringList &CC1Args) {
@@ -2345,6 +2353,22 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
return true;
}
+/// \brief Helper to add an extra variant path for an (Ubuntu) multilib
+/// libstdc++ installation.
+/*static*/ bool Linux::addLibStdCXXIncludePaths(Twine Base, Twine Suffix,
+ Twine TargetArchDir,
+ Twine MultiLibSuffix,
+ const ArgList &DriverArgs,
+ ArgStringList &CC1Args) {
+ if (!addLibStdCXXIncludePaths(Base+Suffix, TargetArchDir + MultiLibSuffix,
+ DriverArgs, CC1Args))
+ return false;
+
+ addSystemInclude(DriverArgs, CC1Args, Base + "/" + TargetArchDir + Suffix
+ + MultiLibSuffix);
+ return true;
+}
+
void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
@@ -2372,8 +2396,14 @@ void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
StringRef Version = GCCInstallation.getVersion().Text;
StringRef TripleStr = GCCInstallation.getTriple().str();
+ if (addLibStdCXXIncludePaths(LibDir.str() + "/../include",
+ "/c++/" + Version.str(),
+ TripleStr,
+ GCCInstallation.getMultiarchSuffix(),
+ DriverArgs, CC1Args))
+ return;
+
const std::string IncludePathCandidates[] = {
- LibDir.str() + "/../include/c++/" + Version.str(),
// Gentoo is weird and places its headers inside the GCC install, so if the
// first attempt to find the headers fails, try this pattern.
InstallDir.str() + "/include/g++-v4",
@@ -2407,25 +2437,10 @@ DragonFly::DragonFly(const Driver &D, const llvm::Triple& Triple, const ArgList
getFilePaths().push_back("/usr/lib/gcc41");
}
-Tool &DragonFly::SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const {
- Action::ActionClass Key;
- if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
- Key = Action::AnalyzeJobClass;
- else
- Key = JA.getKind();
-
- Tool *&T = Tools[Key];
- if (!T) {
- switch (Key) {
- case Action::AssembleJobClass:
- T = new tools::dragonfly::Assemble(*this); break;
- case Action::LinkJobClass:
- T = new tools::dragonfly::Link(*this); break;
- default:
- T = &Generic_GCC::SelectTool(C, JA, Inputs);
- }
- }
+Tool *DragonFly::buildAssembler() const {
+ return new tools::dragonfly::Assemble(*this);
+}
- return *T;
+Tool *DragonFly::buildLinker() const {
+ return new tools::dragonfly::Link(*this);
}
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index 4c267e8..3421c53 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -10,15 +10,13 @@
#ifndef CLANG_LIB_DRIVER_TOOLCHAINS_H_
#define CLANG_LIB_DRIVER_TOOLCHAINS_H_
+#include "Tools.h"
+#include "clang/Basic/VersionTuple.h"
#include "clang/Driver/Action.h"
#include "clang/Driver/ToolChain.h"
-
-#include "clang/Basic/VersionTuple.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/Compiler.h"
-#include "Tools.h"
-
namespace clang {
namespace driver {
namespace toolchains {
@@ -119,20 +117,19 @@ protected:
GCCInstallationDetector GCCInstallation;
- mutable llvm::DenseMap<unsigned, Tool*> Tools;
-
public:
Generic_GCC(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
~Generic_GCC();
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const;
-
virtual bool IsUnwindTablesDefault() const;
virtual bool isPICDefault() const;
virtual bool isPICDefaultForced() const;
protected:
+ virtual Tool *getTool(Action::ActionClass AC) const;
+ virtual Tool *buildAssembler() const;
+ virtual Tool *buildLinker() const;
+
/// \name ToolChain Implementation Helper Functions
/// @{
@@ -143,21 +140,11 @@ protected:
bool isTarget32Bit() const { return getTriple().isArch32Bit(); }
/// @}
-};
-
-class LLVM_LIBRARY_VISIBILITY Hexagon_TC : public ToolChain {
-protected:
- mutable llvm::DenseMap<unsigned, Tool*> Tools;
-
-public:
- Hexagon_TC(const Driver &D, const llvm::Triple& Triple);
- ~Hexagon_TC();
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const;
-
- virtual bool isPICDefault() const;
- virtual bool isPICDefaultForced() const;
+private:
+ mutable OwningPtr<tools::gcc::Preprocess> Preprocess;
+ mutable OwningPtr<tools::gcc::Precompile> Precompile;
+ mutable OwningPtr<tools::gcc::Compile> Compile;
};
/// Darwin - The base Darwin tool chain.
@@ -166,8 +153,15 @@ public:
/// The host version.
unsigned DarwinVersion[3];
+protected:
+ virtual Tool *buildAssembler() const;
+ virtual Tool *buildLinker() const;
+ virtual Tool *getTool(Action::ActionClass AC) const;
+
private:
- mutable llvm::DenseMap<unsigned, Tool*> Tools;
+ mutable OwningPtr<tools::darwin::Lipo> Lipo;
+ mutable OwningPtr<tools::darwin::Dsymutil> Dsymutil;
+ mutable OwningPtr<tools::darwin::VerifyDebug> VerifyDebug;
/// Whether the information on the target has been initialized.
//
@@ -198,7 +192,7 @@ private:
void AddDeploymentTarget(DerivedArgList &Args) const;
public:
- Darwin(const Driver &D, const llvm::Triple& Triple);
+ Darwin(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
~Darwin();
std::string ComputeEffectiveClangTriple(const ArgList &Args,
@@ -286,9 +280,6 @@ public:
virtual DerivedArgList *TranslateArgs(const DerivedArgList &Args,
const char *BoundArch) const;
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const;
-
virtual bool IsBlocksDefault() const {
// Always allow blocks on Darwin; users interested in versioning are
// expected to use /usr/include/Blocks.h.
@@ -314,10 +305,6 @@ public:
return false;
}
- virtual bool IsObjCDefaultSynthPropertiesDefault() const {
- return true;
- }
-
virtual bool IsEncodeExtendedBlockSignatureDefault() const {
return true;
}
@@ -363,16 +350,17 @@ public:
/// DarwinClang - The Darwin toolchain used by Clang.
class LLVM_LIBRARY_VISIBILITY DarwinClang : public Darwin {
public:
- DarwinClang(const Driver &D, const llvm::Triple& Triple);
+ DarwinClang(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
/// @name Darwin ToolChain Implementation
/// {
virtual void AddLinkRuntimeLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const;
- void AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs,
- const char *DarwinStaticLib) const;
-
+ void AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs,
+ const char *DarwinStaticLib,
+ bool AlwaysLink = false) const;
+
virtual void AddCXXStdlibLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const;
@@ -393,7 +381,7 @@ public:
std::string ComputeEffectiveClangTriple(const ArgList &Args,
types::ID InputType) const;
- virtual bool isPICDefault() const { return false; };
+ virtual bool isPICDefault() const { return false; }
};
class LLVM_LIBRARY_VISIBILITY Generic_ELF : public Generic_GCC {
@@ -404,7 +392,8 @@ public:
virtual bool IsIntegratedAssemblerDefault() const {
// Default integrated assembler to on for x86.
- return (getTriple().getArch() == llvm::Triple::x86 ||
+ return (getTriple().getArch() == llvm::Triple::aarch64 ||
+ getTriple().getArch() == llvm::Triple::x86 ||
getTriple().getArch() == llvm::Triple::x86_64);
}
};
@@ -413,18 +402,20 @@ class LLVM_LIBRARY_VISIBILITY AuroraUX : public Generic_GCC {
public:
AuroraUX(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const;
+protected:
+ virtual Tool *buildAssembler() const;
+ virtual Tool *buildLinker() const;
};
class LLVM_LIBRARY_VISIBILITY Solaris : public Generic_GCC {
public:
Solaris(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const;
-
virtual bool IsIntegratedAssemblerDefault() const { return true; }
+protected:
+ virtual Tool *buildAssembler() const;
+ virtual Tool *buildLinker() const;
+
};
@@ -435,8 +426,9 @@ public:
virtual bool IsMathErrnoDefault() const { return false; }
virtual bool IsObjCNonFragileABIDefault() const { return true; }
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const;
+protected:
+ virtual Tool *buildAssembler() const;
+ virtual Tool *buildLinker() const;
};
class LLVM_LIBRARY_VISIBILITY Bitrig : public Generic_ELF {
@@ -447,9 +439,6 @@ public:
virtual bool IsObjCNonFragileABIDefault() const { return true; }
virtual bool IsObjCLegacyDispatchDefault() const { return false; }
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const;
-
virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const;
virtual void AddCXXStdlibLibArgs(const ArgList &Args,
@@ -457,6 +446,10 @@ public:
virtual unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const {
return 1;
}
+
+protected:
+ virtual Tool *buildAssembler() const;
+ virtual Tool *buildLinker() const;
};
class LLVM_LIBRARY_VISIBILITY FreeBSD : public Generic_ELF {
@@ -466,8 +459,10 @@ public:
virtual bool IsMathErrnoDefault() const { return false; }
virtual bool IsObjCNonFragileABIDefault() const { return true; }
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const;
+ virtual bool UseSjLjExceptions() const;
+protected:
+ virtual Tool *buildAssembler() const;
+ virtual Tool *buildLinker() const;
};
class LLVM_LIBRARY_VISIBILITY NetBSD : public Generic_ELF {
@@ -477,16 +472,18 @@ public:
virtual bool IsMathErrnoDefault() const { return false; }
virtual bool IsObjCNonFragileABIDefault() const { return true; }
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const;
+protected:
+ virtual Tool *buildAssembler() const;
+ virtual Tool *buildLinker() const;
};
class LLVM_LIBRARY_VISIBILITY Minix : public Generic_ELF {
public:
Minix(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const;
+protected:
+ virtual Tool *buildAssembler() const;
+ virtual Tool *buildLinker() const;
};
class LLVM_LIBRARY_VISIBILITY DragonFly : public Generic_ELF {
@@ -495,8 +492,9 @@ public:
virtual bool IsMathErrnoDefault() const { return false; }
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const;
+protected:
+ virtual Tool *buildAssembler() const;
+ virtual Tool *buildLinker() const;
};
class LLVM_LIBRARY_VISIBILITY Linux : public Generic_ELF {
@@ -505,55 +503,71 @@ public:
virtual bool HasNativeLLVMSupport() const;
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const;
-
virtual void AddClangSystemIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const;
- virtual void addClangTargetOptions(ArgStringList &CC1Args) const;
+ virtual void addClangTargetOptions(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const;
virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const;
std::string Linker;
std::vector<std::string> ExtraOpts;
+protected:
+ virtual Tool *buildAssembler() const;
+ virtual Tool *buildLinker() const;
+
private:
+ static bool addLibStdCXXIncludePaths(Twine Base, Twine Suffix,
+ Twine TargetArchDir,
+ Twine MultiLibSuffix,
+ const ArgList &DriverArgs,
+ ArgStringList &CC1Args);
static bool addLibStdCXXIncludePaths(Twine Base, Twine TargetArchDir,
const ArgList &DriverArgs,
ArgStringList &CC1Args);
};
+class LLVM_LIBRARY_VISIBILITY Hexagon_TC : public Linux {
+protected:
+ GCCVersion GCCLibAndIncVersion;
+ virtual Tool *buildAssembler() const;
+ virtual Tool *buildLinker() const;
+
+public:
+ Hexagon_TC(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args);
+ ~Hexagon_TC();
+
+ virtual void AddClangSystemIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const;
+ virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const;
+ virtual CXXStdlibType GetCXXStdlibType(const ArgList &Args) const;
+
+ StringRef GetGCCLibAndIncVersion() const { return GCCLibAndIncVersion.Text; }
+
+ static std::string GetGnuDir(const std::string &InstalledDir);
+
+ static StringRef GetTargetCPU(const ArgList &Args);
+};
/// TCEToolChain - A tool chain using the llvm bitcode tools to perform
/// all subcommands. See http://tce.cs.tut.fi for our peculiar target.
class LLVM_LIBRARY_VISIBILITY TCEToolChain : public ToolChain {
public:
- TCEToolChain(const Driver &D, const llvm::Triple& Triple);
+ TCEToolChain(const Driver &D, const llvm::Triple& Triple,
+ const ArgList &Args);
~TCEToolChain();
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const;
bool IsMathErrnoDefault() const;
bool isPICDefault() const;
bool isPICDefaultForced() const;
-
-private:
- mutable llvm::DenseMap<unsigned, Tool*> Tools;
-
};
class LLVM_LIBRARY_VISIBILITY Windows : public ToolChain {
- mutable llvm::DenseMap<unsigned, Tool*> Tools;
-
public:
- Windows(const Driver &D, const llvm::Triple& Triple);
-
- virtual Tool &SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const;
-
- virtual bool IsObjCDefaultSynthPropertiesDefault() const {
- return true;
- }
+ Windows(const Driver &D, const llvm::Triple& Triple, const ArgList &Args);
virtual bool IsIntegratedAssemblerDefault() const;
virtual bool IsUnwindTablesDefault() const;
@@ -564,7 +578,9 @@ public:
ArgStringList &CC1Args) const;
virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const;
-
+protected:
+ virtual Tool *buildLinker() const;
+ virtual Tool *buildAssembler() const;
};
} // end namespace toolchains
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index e37959b..77a72ba 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -8,33 +8,31 @@
//===----------------------------------------------------------------------===//
#include "Tools.h"
-
+#include "InputInfo.h"
+#include "SanitizerArgs.h"
+#include "ToolChains.h"
+#include "clang/Basic/ObjCRuntime.h"
+#include "clang/Basic/Version.h"
#include "clang/Driver/Action.h"
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
+#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
-#include "clang/Driver/Compilation.h"
#include "clang/Driver/Job.h"
#include "clang/Driver/Option.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/ToolChain.h"
#include "clang/Driver/Util.h"
-#include "clang/Basic/ObjCRuntime.h"
-
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/Process.h"
-#include "llvm/Support/ErrorHandling.h"
-
-#include "InputInfo.h"
-#include "SanitizerArgs.h"
-#include "ToolChains.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang::driver;
using namespace clang::driver::tools;
@@ -230,6 +228,7 @@ static bool forwardToGCC(const Option &O) {
}
void Clang::AddPreprocessingOptions(Compilation &C,
+ const JobAction &JA,
const Driver &D,
const ArgList &Args,
ArgStringList &CmdArgs,
@@ -250,15 +249,15 @@ void Clang::AddPreprocessingOptions(Compilation &C,
const char *DepFile;
if (Arg *MF = Args.getLastArg(options::OPT_MF)) {
DepFile = MF->getValue();
- C.addFailureResultFile(DepFile);
+ C.addFailureResultFile(DepFile, &JA);
} else if (Output.getType() == types::TY_Dependencies) {
DepFile = Output.getFilename();
} else if (A->getOption().matches(options::OPT_M) ||
A->getOption().matches(options::OPT_MM)) {
DepFile = "-";
} else {
- DepFile = darwin::CC1::getDependencyFileName(Args, Inputs);
- C.addFailureResultFile(DepFile);
+ DepFile = getDependencyFileName(Args, Inputs);
+ C.addFailureResultFile(DepFile, &JA);
}
CmdArgs.push_back("-dependency-file");
CmdArgs.push_back(DepFile);
@@ -415,21 +414,7 @@ void Clang::AddPreprocessingOptions(Compilation &C,
CmdArgs.push_back(C.getArgs().MakeArgString(sysroot));
}
}
-
- // If a module path was provided, pass it along. Otherwise, use a temporary
- // directory.
- if (Arg *A = Args.getLastArg(options::OPT_fmodule_cache_path)) {
- A->claim();
- A->render(Args, CmdArgs);
- } else {
- SmallString<128> DefaultModuleCache;
- llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false,
- DefaultModuleCache);
- llvm::sys::path::append(DefaultModuleCache, "clang-module-cache");
- CmdArgs.push_back("-fmodule-cache-path");
- CmdArgs.push_back(Args.MakeArgString(DefaultModuleCache));
- }
-
+
// Parse additional include paths from environment variables.
// FIXME: We should probably sink the logic for handling these from the
// frontend into the driver. It will allow deleting 4 otherwise unused flags.
@@ -471,10 +456,12 @@ static const char *getLLVMArchSuffixForARM(StringRef CPU) {
.Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "v6")
.Cases("arm1176jzf-s", "mpcorenovfp", "mpcore", "v6")
.Cases("arm1156t2-s", "arm1156t2f-s", "v6t2")
- .Cases("cortex-a8", "cortex-a9", "cortex-a15", "v7")
- .Case("cortex-m3", "v7m")
- .Case("cortex-m4", "v7m")
+ .Cases("cortex-a5", "cortex-a7", "cortex-a8", "v7")
+ .Cases("cortex-a9", "cortex-a15", "v7")
+ .Case("cortex-r5", "v7r")
.Case("cortex-m0", "v6m")
+ .Case("cortex-m3", "v7m")
+ .Case("cortex-m4", "v7em")
.Case("cortex-a9-mp", "v7f")
.Case("swift", "v7s")
.Default("");
@@ -530,7 +517,9 @@ static std::string getARMTargetCPU(const ArgList &Args,
.Case("armv6j", "arm1136j-s")
.Cases("armv6z", "armv6zk", "arm1176jzf-s")
.Case("armv6t2", "arm1156t2-s")
+ .Cases("armv6m", "armv6-m", "cortex-m0")
.Cases("armv7", "armv7a", "armv7-a", "cortex-a8")
+ .Cases("armv7em", "armv7e-m", "cortex-m4")
.Cases("armv7f", "armv7-f", "cortex-a9-mp")
.Cases("armv7s", "armv7-s", "swift")
.Cases("armv7r", "armv7-r", "cortex-r4")
@@ -538,7 +527,6 @@ static std::string getARMTargetCPU(const ArgList &Args,
.Case("ep9312", "ep9312")
.Case("iwmmxt", "iwmmxt")
.Case("xscale", "xscale")
- .Cases("armv6m", "armv6-m", "cortex-m0")
// If all else failed, return the most base CPU LLVM supports.
.Default("arm7tdmi");
}
@@ -549,6 +537,7 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) {
default:
return true;
+ case llvm::Triple::aarch64:
case llvm::Triple::arm:
case llvm::Triple::ppc:
case llvm::Triple::ppc64:
@@ -609,8 +598,9 @@ static void addFPMathArgs(const Driver &D, const Arg *A, const ArgList &Args,
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("+neonfp");
- if (CPU != "cortex-a8" && CPU != "cortex-a9" && CPU != "cortex-a9-mp" &&
- CPU != "cortex-a15")
+ if (CPU != "cortex-a5" && CPU != "cortex-a7" &&
+ CPU != "cortex-a8" && CPU != "cortex-a9" &&
+ CPU != "cortex-a9-mp" && CPU != "cortex-a15")
D.Diag(diag::err_drv_invalid_feature) << "-mfpmath=neon" << CPU;
} else if (FPMath == "vfp" || FPMath == "vfp2" || FPMath == "vfp3" ||
@@ -665,6 +655,11 @@ static StringRef getARMFloatABI(const Driver &D,
break;
}
+ case llvm::Triple::FreeBSD:
+ // FreeBSD defaults to soft float
+ FloatABI = "soft";
+ break;
+
default:
switch(Triple.getEnvironment()) {
case llvm::Triple::GNUEABIHF:
@@ -878,8 +873,8 @@ static void getMipsCPUAndABI(const ArgList &Args,
if (!ABIName.empty()) {
// Deduce CPU name from ABI name.
CPUName = llvm::StringSwitch<const char *>(ABIName)
- .Cases("o32", "eabi", DefMips32CPU)
- .Cases("n32", "n64", DefMips64CPU)
+ .Cases("32", "o32", "eabi", DefMips32CPU)
+ .Cases("n32", "n64", "64", DefMips64CPU)
.Default("");
}
else if (!CPUName.empty()) {
@@ -893,6 +888,14 @@ static void getMipsCPUAndABI(const ArgList &Args,
// FIXME: Warn on inconsistent cpu and abi usage.
}
+// Convert ABI name to the GNU tools acceptable variant.
+static StringRef getGnuCompatibleMipsABIName(StringRef ABI) {
+ return llvm::StringSwitch<llvm::StringRef>(ABI)
+ .Case("o32", "32")
+ .Case("n64", "64")
+ .Default(ABI);
+}
+
// Select the MIPS float ABI as determined by -msoft-float, -mhard-float,
// and -mfloat-abi=.
static StringRef getMipsFloatABI(const Driver &D, const ArgList &Args) {
@@ -955,7 +958,9 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args,
StringRef FloatABI = getMipsFloatABI(D, Args);
- if (FloatABI == "soft") {
+ bool IsMips16 = Args.getLastArg(options::OPT_mips16) != NULL;
+
+ if (FloatABI == "soft" || (FloatABI == "hard" && IsMips16)) {
// Floating point operations and argument passing are soft.
CmdArgs.push_back("-msoft-float");
CmdArgs.push_back("-mfloat-abi");
@@ -966,6 +971,11 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args,
// Now it is the only method.
CmdArgs.push_back("-target-feature");
CmdArgs.push_back("+soft-float");
+
+ if (FloatABI == "hard" && IsMips16) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-mips16-hard-float");
+ }
}
else if (FloatABI == "single") {
// Restrict the use of hardware floating-point
@@ -990,6 +1000,13 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args,
options::OPT_mdspr2, options::OPT_mno_dspr2,
"dspr2");
+ if (Arg *A = Args.getLastArg(options::OPT_mxgot, options::OPT_mno_xgot)) {
+ if (A->getOption().matches(options::OPT_mxgot)) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-mxgot");
+ }
+ }
+
if (Arg *A = Args.getLastArg(options::OPT_G)) {
StringRef v = A->getValue();
CmdArgs.push_back("-mllvm");
@@ -1024,6 +1041,7 @@ static std::string getPPCTargetCPU(const ArgList &Args) {
.Case("604", "604")
.Case("604e", "604e")
.Case("620", "620")
+ .Case("630", "pwr3")
.Case("G3", "g3")
.Case("7400", "7400")
.Case("G4", "g4")
@@ -1033,10 +1051,23 @@ static std::string getPPCTargetCPU(const ArgList &Args) {
.Case("970", "970")
.Case("G5", "g5")
.Case("a2", "a2")
+ .Case("a2q", "a2q")
.Case("e500mc", "e500mc")
.Case("e5500", "e5500")
+ .Case("power3", "pwr3")
+ .Case("power4", "pwr4")
+ .Case("power5", "pwr5")
+ .Case("power5x", "pwr5x")
.Case("power6", "pwr6")
+ .Case("power6x", "pwr6x")
.Case("power7", "pwr7")
+ .Case("pwr3", "pwr3")
+ .Case("pwr4", "pwr4")
+ .Case("pwr5", "pwr5")
+ .Case("pwr5x", "pwr5x")
+ .Case("pwr6", "pwr6")
+ .Case("pwr6x", "pwr6x")
+ .Case("pwr7", "pwr7")
.Case("powerpc", "ppc")
.Case("powerpc64", "ppc64")
.Default("");
@@ -1064,6 +1095,55 @@ void Clang::AddPPCTargetArgs(const ArgList &Args,
CmdArgs.push_back("-target-cpu");
CmdArgs.push_back(Args.MakeArgString(TargetCPUName.c_str()));
}
+
+ // Allow override of the Altivec feature.
+ AddTargetFeature(Args, CmdArgs,
+ options::OPT_faltivec, options::OPT_fno_altivec,
+ "altivec");
+
+ AddTargetFeature(Args, CmdArgs,
+ options::OPT_mfprnd, options::OPT_mno_fprnd,
+ "fprnd");
+
+ // Note that gcc calls this mfcrf and LLVM calls this mfocrf.
+ AddTargetFeature(Args, CmdArgs,
+ options::OPT_mmfcrf, options::OPT_mno_mfcrf,
+ "mfocrf");
+
+ AddTargetFeature(Args, CmdArgs,
+ options::OPT_mpopcntd, options::OPT_mno_popcntd,
+ "popcntd");
+
+ // It is really only possible to turn qpx off because turning qpx on is tied
+ // to using the a2q CPU.
+ if (Args.hasFlag(options::OPT_mno_qpx, options::OPT_mqpx, false)) {
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back("-qpx");
+ }
+}
+
+/// Get the (LLVM) name of the R600 gpu we are targeting.
+static std::string getR600TargetGPU(const ArgList &Args) {
+ if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
+ std::string GPUName = A->getValue();
+ return llvm::StringSwitch<const char *>(GPUName)
+ .Cases("rv610", "rv620", "rv630", "r600")
+ .Cases("rv635", "rs780", "rs880", "r600")
+ .Case("rv740", "rv770")
+ .Case("palm", "cedar")
+ .Cases("sumo", "sumo2", "redwood")
+ .Case("hemlock", "cypress")
+ .Case("aruba", "cayman")
+ .Default(GPUName.c_str());
+ }
+ return "";
+}
+
+void Clang::AddR600TargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ std::string TargetGPUName = getR600TargetGPU(Args);
+ CmdArgs.push_back("-target-cpu");
+ CmdArgs.push_back(Args.MakeArgString(TargetGPUName.c_str()));
}
void Clang::AddSparcTargetArgs(const ArgList &Args,
@@ -1109,10 +1189,59 @@ void Clang::AddSparcTargetArgs(const ArgList &Args,
}
}
+static const char *getX86TargetCPU(const ArgList &Args,
+ const llvm::Triple &Triple) {
+ if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
+ if (StringRef(A->getValue()) != "native")
+ return A->getValue();
+
+ // FIXME: Reject attempts to use -march=native unless the target matches
+ // the host.
+ //
+ // FIXME: We should also incorporate the detected target features for use
+ // with -native.
+ std::string CPU = llvm::sys::getHostCPUName();
+ if (!CPU.empty() && CPU != "generic")
+ return Args.MakeArgString(CPU);
+ }
+
+ // Select the default CPU if none was given (or detection failed).
+
+ if (Triple.getArch() != llvm::Triple::x86_64 &&
+ Triple.getArch() != llvm::Triple::x86)
+ return 0; // This routine is only handling x86 targets.
+
+ bool Is64Bit = Triple.getArch() == llvm::Triple::x86_64;
+
+ // FIXME: Need target hooks.
+ if (Triple.isOSDarwin())
+ return Is64Bit ? "core2" : "yonah";
+
+ // Everything else goes to x86-64 in 64-bit mode.
+ if (Is64Bit)
+ return "x86-64";
+
+ if (Triple.getOSName().startswith("haiku"))
+ return "i586";
+ if (Triple.getOSName().startswith("openbsd"))
+ return "i486";
+ if (Triple.getOSName().startswith("bitrig"))
+ return "i686";
+ if (Triple.getOSName().startswith("freebsd"))
+ return "i486";
+ if (Triple.getOSName().startswith("netbsd"))
+ return "i486";
+ // All x86 devices running Android have core2 as their common
+ // denominator. This makes a better choice than pentium4.
+ if (Triple.getEnvironment() == llvm::Triple::Android)
+ return "core2";
+
+ // Fallback to p4.
+ return "pentium4";
+}
+
void Clang::AddX86TargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
- const bool isAndroid =
- getToolChain().getTriple().getEnvironment() == llvm::Triple::Android;
if (!Args.hasFlag(options::OPT_mred_zone,
options::OPT_mno_red_zone,
true) ||
@@ -1120,70 +1249,21 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
Args.hasArg(options::OPT_fapple_kext))
CmdArgs.push_back("-disable-red-zone");
- if (Args.hasFlag(options::OPT_msoft_float,
- options::OPT_mno_soft_float,
- false))
- CmdArgs.push_back("-no-implicit-float");
-
- const char *CPUName = 0;
- if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
- if (StringRef(A->getValue()) == "native") {
- // FIXME: Reject attempts to use -march=native unless the target matches
- // the host.
- //
- // FIXME: We should also incorporate the detected target features for use
- // with -native.
- std::string CPU = llvm::sys::getHostCPUName();
- if (!CPU.empty() && CPU != "generic")
- CPUName = Args.MakeArgString(CPU);
- } else
- CPUName = A->getValue();
- }
-
- // Select the default CPU if none was given (or detection failed).
- if (!CPUName) {
- // FIXME: Need target hooks.
- if (getToolChain().getTriple().isOSDarwin()) {
- if (getToolChain().getArch() == llvm::Triple::x86_64)
- CPUName = "core2";
- else if (getToolChain().getArch() == llvm::Triple::x86)
- CPUName = "yonah";
- } else if (getToolChain().getOS().startswith("haiku")) {
- if (getToolChain().getArch() == llvm::Triple::x86_64)
- CPUName = "x86-64";
- else if (getToolChain().getArch() == llvm::Triple::x86)
- CPUName = "i586";
- } else if (getToolChain().getOS().startswith("openbsd")) {
- if (getToolChain().getArch() == llvm::Triple::x86_64)
- CPUName = "x86-64";
- else if (getToolChain().getArch() == llvm::Triple::x86)
- CPUName = "i486";
- } else if (getToolChain().getOS().startswith("bitrig")) {
- if (getToolChain().getArch() == llvm::Triple::x86_64)
- CPUName = "x86-64";
- else if (getToolChain().getArch() == llvm::Triple::x86)
- CPUName = "i686";
- } else if (getToolChain().getOS().startswith("freebsd")) {
- if (getToolChain().getArch() == llvm::Triple::x86_64)
- CPUName = "x86-64";
- else if (getToolChain().getArch() == llvm::Triple::x86)
- CPUName = "i486";
- } else if (getToolChain().getOS().startswith("netbsd")) {
- if (getToolChain().getArch() == llvm::Triple::x86_64)
- CPUName = "x86-64";
- else if (getToolChain().getArch() == llvm::Triple::x86)
- CPUName = "i486";
- } else {
- if (getToolChain().getArch() == llvm::Triple::x86_64)
- CPUName = "x86-64";
- else if (getToolChain().getArch() == llvm::Triple::x86)
- // All x86 devices running Android have core2 as their common
- // denominator. This makes a better choice than pentium4.
- CPUName = isAndroid ? "core2" : "pentium4";
- }
+ // Default to avoid implicit floating-point for kernel/kext code, but allow
+ // that to be overridden with -mno-soft-float.
+ bool NoImplicitFloat = (Args.hasArg(options::OPT_mkernel) ||
+ Args.hasArg(options::OPT_fapple_kext));
+ if (Arg *A = Args.getLastArg(options::OPT_msoft_float,
+ options::OPT_mno_soft_float,
+ options::OPT_mno_implicit_float)) {
+ const Option &O = A->getOption();
+ NoImplicitFloat = (O.matches(options::OPT_mno_implicit_float) ||
+ O.matches(options::OPT_msoft_float));
}
+ if (NoImplicitFloat)
+ CmdArgs.push_back("-no-implicit-float");
- if (CPUName) {
+ if (const char *CPUName = getX86TargetCPU(Args, getToolChain().getTriple())) {
CmdArgs.push_back("-target-cpu");
CmdArgs.push_back(CPUName);
}
@@ -1223,43 +1303,26 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
}
}
-static Arg* getLastHexagonArchArg (const ArgList &Args)
-{
- Arg * A = NULL;
-
- for (ArgList::const_iterator it = Args.begin(), ie = Args.end();
- it != ie; ++it) {
- if ((*it)->getOption().matches(options::OPT_march_EQ) ||
- (*it)->getOption().matches(options::OPT_mcpu_EQ)) {
- A = *it;
- A->claim();
- }
- else if ((*it)->getOption().matches(options::OPT_m_Joined)){
- StringRef Value = (*it)->getValue(0);
- if (Value.startswith("v")) {
- A = *it;
- A->claim();
- }
- }
- }
- return A;
+static inline bool HasPICArg(const ArgList &Args) {
+ return Args.hasArg(options::OPT_fPIC)
+ || Args.hasArg(options::OPT_fpic);
}
-static StringRef getHexagonTargetCPU(const ArgList &Args)
-{
- Arg *A;
- llvm::StringRef WhichHexagon;
+static Arg *GetLastSmallDataThresholdArg(const ArgList &Args) {
+ return Args.getLastArg(options::OPT_G,
+ options::OPT_G_EQ,
+ options::OPT_msmall_data_threshold_EQ);
+}
- // Select the default CPU (v4) if none was given or detection failed.
- if ((A = getLastHexagonArchArg (Args))) {
- WhichHexagon = A->getValue();
- if (WhichHexagon == "")
- return "v4";
- else
- return WhichHexagon;
+static std::string GetHexagonSmallDataThresholdValue(const ArgList &Args) {
+ std::string value;
+ if (HasPICArg(Args))
+ value = "0";
+ else if (Arg *A = GetLastSmallDataThresholdArg(Args)) {
+ value = A->getValue();
+ A->claim();
}
- else
- return "v4";
+ return value;
}
void Clang::AddHexagonTargetArgs(const ArgList &Args,
@@ -1267,20 +1330,18 @@ void Clang::AddHexagonTargetArgs(const ArgList &Args,
llvm::Triple Triple = getToolChain().getTriple();
CmdArgs.push_back("-target-cpu");
- CmdArgs.push_back(Args.MakeArgString("hexagon" + getHexagonTargetCPU(Args)));
+ CmdArgs.push_back(Args.MakeArgString(
+ "hexagon"
+ + toolchains::Hexagon_TC::GetTargetCPU(Args)));
CmdArgs.push_back("-fno-signed-char");
- CmdArgs.push_back("-nobuiltininc");
-
- if (Args.hasArg(options::OPT_mqdsp6_compat))
- CmdArgs.push_back("-mqdsp6-compat");
+ CmdArgs.push_back("-mqdsp6-compat");
+ CmdArgs.push_back("-Wreturn-type");
- if (Arg *A = Args.getLastArg(options::OPT_G,
- options::OPT_msmall_data_threshold_EQ)) {
- std::string SmallDataThreshold="-small-data-threshold=";
- SmallDataThreshold += A->getValue();
+ std::string SmallDataThreshold = GetHexagonSmallDataThresholdValue(Args);
+ if (!SmallDataThreshold.empty()) {
CmdArgs.push_back ("-mllvm");
- CmdArgs.push_back(Args.MakeArgString(SmallDataThreshold));
- A->claim();
+ CmdArgs.push_back(Args.MakeArgString(
+ "-hexagon-small-data-threshold=" + SmallDataThreshold));
}
if (!Args.hasArg(options::OPT_fno_short_enums))
@@ -1397,24 +1458,18 @@ static bool ShouldDisableCFI(const ArgList &Args,
if (TC.getTriple().isOSDarwin()) {
// The native darwin assembler doesn't support cfi directives, so
// we disable them if we think the .s file will be passed to it.
- Default = Args.hasFlag(options::OPT_integrated_as,
- options::OPT_no_integrated_as,
- TC.IsIntegratedAssemblerDefault());
+ Default = TC.useIntegratedAs();
}
return !Args.hasFlag(options::OPT_fdwarf2_cfi_asm,
- options::OPT_fno_dwarf2_cfi_asm,
- Default);
+ options::OPT_fno_dwarf2_cfi_asm,
+ Default);
}
static bool ShouldDisableDwarfDirectory(const ArgList &Args,
const ToolChain &TC) {
- bool IsIADefault = TC.IsIntegratedAssemblerDefault();
- bool UseIntegratedAs = Args.hasFlag(options::OPT_integrated_as,
- options::OPT_no_integrated_as,
- IsIADefault);
bool UseDwarfDirectory = Args.hasFlag(options::OPT_fdwarf_directory_asm,
options::OPT_fno_dwarf_directory_asm,
- UseIntegratedAs);
+ TC.useIntegratedAs());
return !UseDwarfDirectory;
}
@@ -1453,63 +1508,147 @@ static bool UseRelaxAll(Compilation &C, const ArgList &Args) {
RelaxDefault);
}
-SanitizerArgs::SanitizerArgs(const Driver &D, const ArgList &Args) {
- Kind = 0;
-
- const Arg *AsanArg, *TsanArg, *UbsanArg;
+SanitizerArgs::SanitizerArgs(const Driver &D, const ArgList &Args)
+ : Kind(0), BlacklistFile(""), MsanTrackOrigins(false),
+ AsanZeroBaseShadow(false) {
+ unsigned AllKinds = 0; // All kinds of sanitizers that were turned on
+ // at least once (possibly, disabled further).
for (ArgList::const_iterator I = Args.begin(), E = Args.end(); I != E; ++I) {
- unsigned Add = 0, Remove = 0;
- const char *DeprecatedReplacement = 0;
- if ((*I)->getOption().matches(options::OPT_faddress_sanitizer)) {
- Add = Address;
- DeprecatedReplacement = "-fsanitize=address";
- } else if ((*I)->getOption().matches(options::OPT_fno_address_sanitizer)) {
- Remove = Address;
- DeprecatedReplacement = "-fno-sanitize=address";
- } else if ((*I)->getOption().matches(options::OPT_fthread_sanitizer)) {
- Add = Thread;
- DeprecatedReplacement = "-fsanitize=thread";
- } else if ((*I)->getOption().matches(options::OPT_fno_thread_sanitizer)) {
- Remove = Thread;
- DeprecatedReplacement = "-fno-sanitize=thread";
- } else if ((*I)->getOption().matches(options::OPT_fcatch_undefined_behavior)) {
- Add = Undefined;
- DeprecatedReplacement = "-fsanitize=undefined";
- } else if ((*I)->getOption().matches(options::OPT_fsanitize_EQ)) {
- Add = parse(D, *I);
- } else if ((*I)->getOption().matches(options::OPT_fno_sanitize_EQ)) {
- Remove = parse(D, *I);
- } else {
+ unsigned Add, Remove;
+ if (!parse(D, Args, *I, Add, Remove, true))
continue;
- }
-
(*I)->claim();
-
Kind |= Add;
Kind &= ~Remove;
+ AllKinds |= Add;
+ }
+
+ UbsanTrapOnError =
+ Args.hasArg(options::OPT_fcatch_undefined_behavior) ||
+ Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error,
+ options::OPT_fno_sanitize_undefined_trap_on_error, false);
- if (Add & NeedsAsanRt) AsanArg = *I;
- if (Add & NeedsTsanRt) TsanArg = *I;
- if (Add & NeedsUbsanRt) UbsanArg = *I;
+ if (Args.hasArg(options::OPT_fcatch_undefined_behavior) &&
+ !Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error,
+ options::OPT_fno_sanitize_undefined_trap_on_error, true)) {
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << "-fcatch-undefined-behavior"
+ << "-fno-sanitize-undefined-trap-on-error";
+ }
- // If this is a deprecated synonym, produce a warning directing users
- // towards the new spelling.
- if (DeprecatedReplacement)
- D.Diag(diag::warn_drv_deprecated_arg)
- << (*I)->getAsString(Args) << DeprecatedReplacement;
+ // Warn about undefined sanitizer options that require runtime support.
+ if (UbsanTrapOnError && notAllowedWithTrap()) {
+ if (Args.hasArg(options::OPT_fcatch_undefined_behavior))
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << lastArgumentForKind(D, Args, NotAllowedWithTrap)
+ << "-fcatch-undefined-behavior";
+ else if (Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error,
+ options::OPT_fno_sanitize_undefined_trap_on_error,
+ false))
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << lastArgumentForKind(D, Args, NotAllowedWithTrap)
+ << "-fsanitize-undefined-trap-on-error";
}
// Only one runtime library can be used at once.
- // FIXME: Allow Ubsan to be combined with the other two.
bool NeedsAsan = needsAsanRt();
bool NeedsTsan = needsTsanRt();
- bool NeedsUbsan = needsUbsanRt();
- if (NeedsAsan + NeedsTsan + NeedsUbsan > 1)
+ bool NeedsMsan = needsMsanRt();
+ if (NeedsAsan && NeedsTsan)
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << lastArgumentForKind(D, Args, NeedsAsanRt)
+ << lastArgumentForKind(D, Args, NeedsTsanRt);
+ if (NeedsAsan && NeedsMsan)
D.Diag(diag::err_drv_argument_not_allowed_with)
- << describeSanitizeArg(Args, NeedsAsan ? AsanArg : TsanArg,
- NeedsAsan ? NeedsAsanRt : NeedsTsanRt)
- << describeSanitizeArg(Args, NeedsUbsan ? UbsanArg : TsanArg,
- NeedsUbsan ? NeedsUbsanRt : NeedsTsanRt);
+ << lastArgumentForKind(D, Args, NeedsAsanRt)
+ << lastArgumentForKind(D, Args, NeedsMsanRt);
+ if (NeedsTsan && NeedsMsan)
+ D.Diag(diag::err_drv_argument_not_allowed_with)
+ << lastArgumentForKind(D, Args, NeedsTsanRt)
+ << lastArgumentForKind(D, Args, NeedsMsanRt);
+
+ // If -fsanitize contains extra features of ASan, it should also
+ // explicitly contain -fsanitize=address (probably, turned off later in the
+ // command line).
+ if ((Kind & AddressFull) != 0 && (AllKinds & Address) == 0)
+ D.Diag(diag::warn_drv_unused_sanitizer)
+ << lastArgumentForKind(D, Args, AddressFull)
+ << "-fsanitize=address";
+
+ // Parse -f(no-)sanitize-blacklist options.
+ if (Arg *BLArg = Args.getLastArg(options::OPT_fsanitize_blacklist,
+ options::OPT_fno_sanitize_blacklist)) {
+ if (BLArg->getOption().matches(options::OPT_fsanitize_blacklist)) {
+ std::string BLPath = BLArg->getValue();
+ bool BLExists = false;
+ if (!llvm::sys::fs::exists(BLPath, BLExists) && BLExists)
+ BlacklistFile = BLPath;
+ else
+ D.Diag(diag::err_drv_no_such_file) << BLPath;
+ }
+ } else {
+ // If no -fsanitize-blacklist option is specified, try to look up for
+ // blacklist in the resource directory.
+ std::string BLPath;
+ bool BLExists = false;
+ if (getDefaultBlacklistForKind(D, Kind, BLPath) &&
+ !llvm::sys::fs::exists(BLPath, BLExists) && BLExists)
+ BlacklistFile = BLPath;
+ }
+
+ // Parse -f(no-)sanitize-memory-track-origins options.
+ if (NeedsMsan)
+ MsanTrackOrigins =
+ Args.hasFlag(options::OPT_fsanitize_memory_track_origins,
+ options::OPT_fno_sanitize_memory_track_origins,
+ /* Default */false);
+
+ // Parse -f(no-)sanitize-address-zero-base-shadow options.
+ if (NeedsAsan)
+ AsanZeroBaseShadow =
+ Args.hasFlag(options::OPT_fsanitize_address_zero_base_shadow,
+ options::OPT_fno_sanitize_address_zero_base_shadow,
+ /* Default */false);
+}
+
+static void addSanitizerRTLinkFlagsLinux(
+ const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs,
+ const StringRef Sanitizer, bool BeforeLibStdCXX,
+ bool ExportSymbols = true) {
+ // Sanitizer runtime is located in the Linux library directory and
+ // has name "libclang_rt.<Sanitizer>-<ArchName>.a".
+ SmallString<128> LibSanitizer(TC.getDriver().ResourceDir);
+ llvm::sys::path::append(
+ LibSanitizer, "lib", "linux",
+ (Twine("libclang_rt.") + Sanitizer + "-" + TC.getArchName() + ".a"));
+
+ // Sanitizer runtime may need to come before -lstdc++ (or -lc++, libstdc++.a,
+ // etc.) so that the linker picks custom versions of the global 'operator
+ // new' and 'operator delete' symbols. We take the extreme (but simple)
+ // strategy of inserting it at the front of the link command. It also
+ // needs to be forced to end up in the executable, so wrap it in
+ // whole-archive.
+ SmallVector<const char *, 3> LibSanitizerArgs;
+ LibSanitizerArgs.push_back("-whole-archive");
+ LibSanitizerArgs.push_back(Args.MakeArgString(LibSanitizer));
+ LibSanitizerArgs.push_back("-no-whole-archive");
+
+ CmdArgs.insert(BeforeLibStdCXX ? CmdArgs.begin() : CmdArgs.end(),
+ LibSanitizerArgs.begin(), LibSanitizerArgs.end());
+
+ CmdArgs.push_back("-lpthread");
+ CmdArgs.push_back("-ldl");
+
+ // If possible, use a dynamic symbols file to export the symbols from the
+ // runtime library. If we can't do so, use -export-dynamic instead to export
+ // all symbols from the binary.
+ if (ExportSymbols) {
+ if (llvm::sys::fs::exists(LibSanitizer + ".syms"))
+ CmdArgs.push_back(
+ Args.MakeArgString("--dynamic-list=" + LibSanitizer + ".syms"));
+ else
+ CmdArgs.push_back("-export-dynamic");
+ }
}
/// If AddressSanitizer is enabled, add appropriate linker flags (Linux).
@@ -1526,19 +1665,17 @@ static void addAsanRTLinux(const ToolChain &TC, const ArgList &Args,
llvm::sys::path::append(LibAsan, "lib", "linux",
(Twine("libclang_rt.asan-") +
TC.getArchName() + "-android.so"));
- CmdArgs.push_back(Args.MakeArgString(LibAsan));
+ CmdArgs.insert(CmdArgs.begin(), Args.MakeArgString(LibAsan));
} else {
if (!Args.hasArg(options::OPT_shared)) {
- // LibAsan is "libclang_rt.asan-<ArchName>.a" in the Linux library
- // resource directory.
- SmallString<128> LibAsan(TC.getDriver().ResourceDir);
- llvm::sys::path::append(LibAsan, "lib", "linux",
- (Twine("libclang_rt.asan-") +
- TC.getArchName() + ".a"));
- CmdArgs.push_back(Args.MakeArgString(LibAsan));
- CmdArgs.push_back("-lpthread");
- CmdArgs.push_back("-ldl");
- CmdArgs.push_back("-export-dynamic");
+ bool ZeroBaseShadow = Args.hasFlag(
+ options::OPT_fsanitize_address_zero_base_shadow,
+ options::OPT_fno_sanitize_address_zero_base_shadow, false);
+ if (ZeroBaseShadow && !Args.hasArg(options::OPT_pie)) {
+ TC.getDriver().Diag(diag::err_drv_argument_only_allowed_with) <<
+ "-fsanitize-address-zero-base-shadow" << "-pie";
+ }
+ addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "asan", true);
}
}
}
@@ -1548,33 +1685,44 @@ static void addAsanRTLinux(const ToolChain &TC, const ArgList &Args,
static void addTsanRTLinux(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {
if (!Args.hasArg(options::OPT_shared)) {
- // LibTsan is "libclang_rt.tsan-<ArchName>.a" in the Linux library
- // resource directory.
- SmallString<128> LibTsan(TC.getDriver().ResourceDir);
- llvm::sys::path::append(LibTsan, "lib", "linux",
- (Twine("libclang_rt.tsan-") +
- TC.getArchName() + ".a"));
- CmdArgs.push_back(Args.MakeArgString(LibTsan));
- CmdArgs.push_back("-lpthread");
- CmdArgs.push_back("-ldl");
- CmdArgs.push_back("-export-dynamic");
+ if (!Args.hasArg(options::OPT_pie))
+ TC.getDriver().Diag(diag::err_drv_argument_only_allowed_with) <<
+ "-fsanitize=thread" << "-pie";
+ addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "tsan", true);
+ }
+}
+
+/// If MemorySanitizer is enabled, add appropriate linker flags (Linux).
+/// This needs to be called before we add the C run-time (malloc, etc).
+static void addMsanRTLinux(const ToolChain &TC, const ArgList &Args,
+ ArgStringList &CmdArgs) {
+ if (!Args.hasArg(options::OPT_shared)) {
+ if (!Args.hasArg(options::OPT_pie))
+ TC.getDriver().Diag(diag::err_drv_argument_only_allowed_with) <<
+ "-fsanitize=memory" << "-pie";
+ addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "msan", true);
}
}
/// If UndefinedBehaviorSanitizer is enabled, add appropriate linker flags
/// (Linux).
static void addUbsanRTLinux(const ToolChain &TC, const ArgList &Args,
- ArgStringList &CmdArgs) {
- if (!Args.hasArg(options::OPT_shared)) {
- // LibUbsan is "libclang_rt.ubsan-<ArchName>.a" in the Linux library
- // resource directory.
- SmallString<128> LibUbsan(TC.getDriver().ResourceDir);
- llvm::sys::path::append(LibUbsan, "lib", "linux",
- (Twine("libclang_rt.ubsan-") +
- TC.getArchName() + ".a"));
- CmdArgs.push_back(Args.MakeArgString(LibUbsan));
- CmdArgs.push_back("-lpthread");
- }
+ ArgStringList &CmdArgs, bool IsCXX,
+ bool HasOtherSanitizerRt) {
+ if (Args.hasArg(options::OPT_shared))
+ return;
+
+ // Need a copy of sanitizer_common. This could come from another sanitizer
+ // runtime; if we're not including one, include our own copy.
+ if (!HasOtherSanitizerRt)
+ addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "san", true, false);
+
+ addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "ubsan", false);
+
+ // Only include the bits of the runtime which need a C++ ABI library if
+ // we're linking in C++ mode.
+ if (IsCXX)
+ addSanitizerRTLinkFlagsLinux(TC, Args, CmdArgs, "ubsan_cxx", false);
}
static bool shouldUseFramePointer(const ArgList &Args,
@@ -1595,6 +1743,80 @@ static bool shouldUseFramePointer(const ArgList &Args,
return true;
}
+static bool shouldUseLeafFramePointer(const ArgList &Args,
+ const llvm::Triple &Triple) {
+ if (Arg *A = Args.getLastArg(options::OPT_mno_omit_leaf_frame_pointer,
+ options::OPT_momit_leaf_frame_pointer))
+ return A->getOption().matches(options::OPT_mno_omit_leaf_frame_pointer);
+
+ // Don't use a leaf frame pointer on linux x86 and x86_64 if optimizing.
+ if ((Triple.getArch() == llvm::Triple::x86_64 ||
+ Triple.getArch() == llvm::Triple::x86) &&
+ Triple.getOS() == llvm::Triple::Linux) {
+ if (Arg *A = Args.getLastArg(options::OPT_O_Group))
+ if (!A->getOption().matches(options::OPT_O0))
+ return false;
+ }
+
+ return true;
+}
+
+/// If the PWD environment variable is set, add a CC1 option to specify the
+/// debug compilation directory.
+static void addDebugCompDirArg(const ArgList &Args, ArgStringList &CmdArgs) {
+ if (const char *pwd = ::getenv("PWD")) {
+ // GCC also verifies that stat(pwd) and stat(".") have the same inode
+ // number. Not doing those because stats are slow, but we could.
+ if (llvm::sys::path::is_absolute(pwd)) {
+ std::string CompDir = pwd;
+ CmdArgs.push_back("-fdebug-compilation-dir");
+ CmdArgs.push_back(Args.MakeArgString(CompDir));
+ }
+ }
+}
+
+static const char *SplitDebugName(const ArgList &Args,
+ const InputInfoList &Inputs) {
+ Arg *FinalOutput = Args.getLastArg(options::OPT_o);
+ if (FinalOutput && Args.hasArg(options::OPT_c)) {
+ SmallString<128> T(FinalOutput->getValue());
+ llvm::sys::path::replace_extension(T, "dwo");
+ return Args.MakeArgString(T);
+ } else {
+ // Use the compilation dir.
+ SmallString<128> T(Args.getLastArgValue(options::OPT_fdebug_compilation_dir));
+ SmallString<128> F(llvm::sys::path::stem(Inputs[0].getBaseInput()));
+ llvm::sys::path::replace_extension(F, "dwo");
+ T += F;
+ return Args.MakeArgString(F);
+ }
+}
+
+static void SplitDebugInfo(const ToolChain &TC, Compilation &C,
+ const Tool &T, const JobAction &JA,
+ const ArgList &Args, const InputInfo &Output,
+ const char *OutFile) {
+ ArgStringList ExtractArgs;
+ ExtractArgs.push_back("--extract-dwo");
+
+ ArgStringList StripArgs;
+ StripArgs.push_back("--strip-dwo");
+
+ // Grabbing the output of the earlier compile step.
+ StripArgs.push_back(Output.getFilename());
+ ExtractArgs.push_back(Output.getFilename());
+ ExtractArgs.push_back(OutFile);
+
+ const char *Exec =
+ Args.MakeArgString(TC.GetProgramPath("objcopy"));
+
+ // First extract the dwo sections.
+ C.addCommand(new Command(JA, T, Exec, ExtractArgs));
+
+ // Then remove them from the original .o file.
+ C.addCommand(new Command(JA, T, Exec, StripArgs));
+}
+
void Clang::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -1628,8 +1850,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
} else if (isa<PreprocessJobAction>(JA)) {
if (Output.getType() == types::TY_Dependencies)
CmdArgs.push_back("-Eonly");
- else
+ else {
CmdArgs.push_back("-E");
+ if (Args.hasArg(options::OPT_rewrite_objc) &&
+ !Args.hasArg(options::OPT_g_Group))
+ CmdArgs.push_back("-P");
+ }
} else if (isa<AssembleJobAction>(JA)) {
CmdArgs.push_back("-emit-obj");
@@ -1690,6 +1916,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-S");
} else if (JA.getType() == types::TY_AST) {
CmdArgs.push_back("-emit-pch");
+ } else if (JA.getType() == types::TY_ModuleFile) {
+ CmdArgs.push_back("-module-file-info");
} else if (JA.getType() == types::TY_RewrittenObjC) {
CmdArgs.push_back("-rewrite-objc");
rewriteKind = RK_NonFragile;
@@ -1713,10 +1941,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Set the main file name, so that debug info works even with
// -save-temps.
CmdArgs.push_back("-main-file-name");
- CmdArgs.push_back(darwin::CC1::getBaseInputName(Args, Inputs));
+ CmdArgs.push_back(getBaseInputName(Args, Inputs));
// Some flags which affect the language (via preprocessor
- // defines). See darwin::CC1::AddCPPArgs.
+ // defines).
if (Args.hasArg(options::OPT_static))
CmdArgs.push_back("-static-define");
@@ -1812,8 +2040,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Note that these flags are trump-cards. Regardless of the order w.r.t. the
// PIC or PIE options above, if these show up, PIC is disabled.
llvm::Triple Triple(TripleStr);
- if ((Args.hasArg(options::OPT_mkernel) ||
- Args.hasArg(options::OPT_fapple_kext)) &&
+ if (KernelOrKext &&
(Triple.getOS() != llvm::Triple::IOS ||
Triple.isOSVersionLT(6)))
PIC = PIE = false;
@@ -1878,6 +2105,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_strict_aliasing,
getToolChain().IsStrictAliasingDefault()))
CmdArgs.push_back("-relaxed-aliasing");
+ if (Args.hasArg(options::OPT_fstruct_path_tbaa))
+ CmdArgs.push_back("-struct-path-tbaa");
if (Args.hasFlag(options::OPT_fstrict_enums, options::OPT_fno_strict_enums,
false))
CmdArgs.push_back("-fstrict-enums");
@@ -1885,6 +2114,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_optimize_sibling_calls))
CmdArgs.push_back("-mdisable-tail-calls");
+ // Handle segmented stacks.
+ if (Args.hasArg(options::OPT_fsplit_stack))
+ CmdArgs.push_back("-split-stacks");
+
// Handle various floating point optimization flags, mapping them to the
// appropriate LLVM code generation flags. The pattern for all of these is to
// default off the codegen optimizations, and if any flag enables them and no
@@ -2047,7 +2280,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
AsynchronousUnwindTables))
CmdArgs.push_back("-munwind-tables");
- getToolChain().addClangTargetOptions(CmdArgs);
+ getToolChain().addClangTargetOptions(Args, CmdArgs);
if (Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) {
CmdArgs.push_back("-mlimit-float-precision");
@@ -2084,6 +2317,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
AddPPCTargetArgs(Args, CmdArgs);
break;
+ case llvm::Triple::r600:
+ AddR600TargetArgs(Args, CmdArgs);
+ break;
+
case llvm::Triple::sparc:
AddSparcTargetArgs(Args, CmdArgs);
break;
@@ -2106,10 +2343,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue());
}
- // -mno-omit-leaf-frame-pointer is the default on Darwin.
- if (Args.hasFlag(options::OPT_momit_leaf_frame_pointer,
- options::OPT_mno_omit_leaf_frame_pointer,
- !getToolChain().getTriple().isOSDarwin()))
+ if (!shouldUseLeafFramePointer(Args, getToolChain().getTriple()))
CmdArgs.push_back("-momit-leaf-frame-pointer");
// Explicitly error on some things we know we don't support and can't just
@@ -2143,16 +2377,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
D.CCLogDiagnosticsFilename : "-");
}
- // Use the last option from "-g" group. "-gline-tables-only" is
- // preserved, all other debug options are substituted with "-g".
+ // Use the last option from "-g" group. "-gline-tables-only"
+ // is preserved, all other debug options are substituted with "-g".
Args.ClaimAllArgs(options::OPT_g_Group);
if (Arg *A = Args.getLastArg(options::OPT_g_Group)) {
- if (A->getOption().matches(options::OPT_gline_tables_only)) {
+ if (A->getOption().matches(options::OPT_gline_tables_only))
CmdArgs.push_back("-gline-tables-only");
- } else if (!A->getOption().matches(options::OPT_g0) &&
- !A->getOption().matches(options::OPT_ggdb0)) {
+ else if (!A->getOption().matches(options::OPT_g0) &&
+ !A->getOption().matches(options::OPT_ggdb0))
CmdArgs.push_back("-g");
- }
}
// We ignore flags -gstrict-dwarf and -grecord-gcc-switches for now.
@@ -2160,6 +2393,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_gcolumn_info))
CmdArgs.push_back("-dwarf-column-info");
+ // -gsplit-dwarf should turn on -g and enable the backend dwarf
+ // splitting and extraction.
+ // FIXME: Currently only works on Linux.
+ if (getToolChain().getTriple().getOS() == llvm::Triple::Linux &&
+ Args.hasArg(options::OPT_gsplit_dwarf)) {
+ CmdArgs.push_back("-g");
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-split-dwarf=Enable");
+ }
+
Args.AddAllArgs(CmdArgs, options::OPT_ffunction_sections);
Args.AddAllArgs(CmdArgs, options::OPT_fdata_sections);
@@ -2176,9 +2419,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
C.getArgs().hasArg(options::OPT_S)) {
if (Output.isFilename()) {
CmdArgs.push_back("-coverage-file");
- SmallString<128> absFilename(Output.getFilename());
- llvm::sys::fs::make_absolute(absFilename);
- CmdArgs.push_back(Args.MakeArgString(absFilename));
+ SmallString<128> CoverageFilename(Output.getFilename());
+ if (llvm::sys::path::is_relative(CoverageFilename.str())) {
+ if (const char *pwd = ::getenv("PWD")) {
+ if (llvm::sys::path::is_absolute(pwd)) {
+ SmallString<128> Pwd(pwd);
+ llvm::sys::path::append(Pwd, CoverageFilename.str());
+ CoverageFilename.swap(Pwd);
+ }
+ }
+ }
+ CmdArgs.push_back(Args.MakeArgString(CoverageFilename));
}
}
@@ -2250,7 +2501,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
//
// FIXME: Support -fpreprocessed
if (types::getPreprocessedType(InputType) != types::TY_INVALID)
- AddPreprocessingOptions(C, D, Args, CmdArgs, Output, Inputs);
+ AddPreprocessingOptions(C, JA, D, Args, CmdArgs, Output, Inputs);
// Don't warn about "clang -c -DPIC -fPIC test.i" because libtool.m4 assumes
// that "The compiler can only warn and ignore the option if not recognized".
@@ -2270,6 +2521,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
A->render(Args, CmdArgs);
}
+ // Don't warn about unused -flto. This can happen when we're preprocessing or
+ // precompiling.
+ Args.ClaimAllArgs(options::OPT_flto);
+
Args.AddAllArgs(CmdArgs, options::OPT_W_Group);
if (Args.hasFlag(options::OPT_pedantic, options::OPT_no_pedantic, false))
CmdArgs.push_back("-pedantic");
@@ -2342,15 +2597,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (ShouldDisableDwarfDirectory(Args, getToolChain()))
CmdArgs.push_back("-fno-dwarf-directory-asm");
- if (const char *pwd = ::getenv("PWD")) {
- // GCC also verifies that stat(pwd) and stat(".") have the same inode
- // number. Not doing those because stats are slow, but we could.
- if (llvm::sys::path::is_absolute(pwd)) {
- std::string CompDir = pwd;
- CmdArgs.push_back("-fdebug-compilation-dir");
- CmdArgs.push_back(Args.MakeArgString(CompDir));
- }
- }
+ // Add in -fdebug-compilation-dir if necessary.
+ addDebugCompDirArg(Args, CmdArgs);
if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_,
options::OPT_ftemplate_depth_EQ)) {
@@ -2363,6 +2611,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue());
}
+ if (Arg *A = Args.getLastArg(options::OPT_fbracket_depth_EQ)) {
+ CmdArgs.push_back("-fbracket-depth");
+ CmdArgs.push_back(A->getValue());
+ }
+
if (Arg *A = Args.getLastArg(options::OPT_Wlarge_by_value_copy_EQ,
options::OPT_Wlarge_by_value_copy_def)) {
if (A->getNumValues()) {
@@ -2372,14 +2625,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-Wlarge-by-value-copy=64"); // default value
}
- if (Arg *A = Args.getLastArg(options::OPT_fbounds_checking,
- options::OPT_fbounds_checking_EQ)) {
- if (A->getNumValues()) {
- StringRef val = A->getValue();
- CmdArgs.push_back(Args.MakeArgString("-fbounds-checking=" + val));
- } else
- CmdArgs.push_back("-fbounds-checking=1");
- }
if (Args.hasArg(options::OPT_relocatable_pch))
CmdArgs.push_back("-relocatable-pch");
@@ -2426,9 +2671,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(Twine(N)));
}
- if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ)) {
- CmdArgs.push_back("-fvisibility");
- CmdArgs.push_back(A->getValue());
+ // -fvisibility= and -fvisibility-ms-compat are of a piece.
+ if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ,
+ options::OPT_fvisibility_ms_compat)) {
+ if (A->getOption().matches(options::OPT_fvisibility_EQ)) {
+ CmdArgs.push_back("-fvisibility");
+ CmdArgs.push_back(A->getValue());
+ } else {
+ assert(A->getOption().matches(options::OPT_fvisibility_ms_compat));
+ CmdArgs.push_back("-fvisibility");
+ CmdArgs.push_back("hidden");
+ CmdArgs.push_back("-ftype-visibility");
+ CmdArgs.push_back("default");
+ }
}
Args.AddLastArg(CmdArgs, options::OPT_fvisibility_inlines_hidden);
@@ -2453,7 +2708,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
SanitizerArgs Sanitize(D, Args);
Sanitize.addArgs(Args, CmdArgs);
- // Report and error for -faltivec on anything other then PowerPC.
+ if (!Args.hasFlag(options::OPT_fsanitize_recover,
+ options::OPT_fno_sanitize_recover,
+ true))
+ CmdArgs.push_back("-fno-sanitize-recover");
+
+ if (Args.hasArg(options::OPT_fcatch_undefined_behavior) ||
+ Args.hasFlag(options::OPT_fsanitize_undefined_trap_on_error,
+ options::OPT_fno_sanitize_undefined_trap_on_error, false))
+ CmdArgs.push_back("-fsanitize-undefined-trap-on-error");
+
+ // Report an error for -faltivec on anything other than PowerPC.
if (const Arg *A = Args.getLastArg(options::OPT_faltivec))
if (!(getToolChain().getTriple().getArch() == llvm::Triple::ppc ||
getToolChain().getTriple().getArch() == llvm::Triple::ppc64))
@@ -2552,7 +2817,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
StringRef alignment = Args.getLastArgValue(options::OPT_mstack_alignment);
CmdArgs.push_back(Args.MakeArgString("-mstack-alignment=" + alignment));
}
- if (Args.hasArg(options::OPT_mstrict_align)) {
+ // -mkernel implies -mstrict-align; don't add the redundant option.
+ if (Args.hasArg(options::OPT_mstrict_align) && !KernelOrKext) {
CmdArgs.push_back("-backend-option");
CmdArgs.push_back("-arm-strict-align");
}
@@ -2591,12 +2857,49 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// -fmodules enables modules (off by default). However, for C++/Objective-C++,
// users must also pass -fcxx-modules. The latter flag will disappear once the
// modules implementation is solid for C++/Objective-C++ programs as well.
+ bool HaveModules = false;
if (Args.hasFlag(options::OPT_fmodules, options::OPT_fno_modules, false)) {
bool AllowedInCXX = Args.hasFlag(options::OPT_fcxx_modules,
options::OPT_fno_cxx_modules,
false);
- if (AllowedInCXX || !types::isCXX(InputType))
+ if (AllowedInCXX || !types::isCXX(InputType)) {
CmdArgs.push_back("-fmodules");
+ HaveModules = true;
+ }
+ }
+
+ // If a module path was provided, pass it along. Otherwise, use a temporary
+ // directory.
+ if (Arg *A = Args.getLastArg(options::OPT_fmodules_cache_path)) {
+ A->claim();
+ if (HaveModules) {
+ A->render(Args, CmdArgs);
+ }
+ } else if (HaveModules) {
+ SmallString<128> DefaultModuleCache;
+ llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false,
+ DefaultModuleCache);
+ llvm::sys::path::append(DefaultModuleCache, "org.llvm.clang");
+ llvm::sys::path::append(DefaultModuleCache, "ModuleCache");
+ const char Arg[] = "-fmodules-cache-path=";
+ DefaultModuleCache.insert(DefaultModuleCache.begin(),
+ Arg, Arg + strlen(Arg));
+ CmdArgs.push_back(Args.MakeArgString(DefaultModuleCache));
+ }
+
+ // Pass through all -fmodules-ignore-macro arguments.
+ Args.AddAllArgs(CmdArgs, options::OPT_fmodules_ignore_macro);
+ Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_interval);
+ Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_after);
+
+ // -fmodules-autolink (on by default when modules is enabled) automatically
+ // links against libraries for imported modules. This requires the
+ // integrated assembler.
+ if (HaveModules && getToolChain().useIntegratedAs() &&
+ Args.hasFlag(options::OPT_fmodules_autolink,
+ options::OPT_fno_modules_autolink,
+ true)) {
+ CmdArgs.push_back("-fmodules-autolink");
}
// -faccess-control is default.
@@ -2658,10 +2961,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
getToolChain().getTriple().getOS() == llvm::Triple::Win32))
CmdArgs.push_back("-fms-extensions");
- // -fms-inline-asm.
- if (Args.hasArg(options::OPT_fenable_experimental_ms_inline_asm))
- CmdArgs.push_back("-fenable-experimental-ms-inline-asm");
-
// -fms-compatibility=0 is default.
if (Args.hasFlag(options::OPT_fms_compatibility,
options::OPT_fno_ms_compatibility,
@@ -2683,7 +2982,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
- // -fborland-extensions=0 is default.
+ // -fno-borland-extensions is default.
if (Args.hasFlag(options::OPT_fborland_extensions,
options::OPT_fno_borland_extensions, false))
CmdArgs.push_back("-fborland-extensions");
@@ -2837,8 +3136,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fpack-struct=1");
}
- if (Args.hasArg(options::OPT_mkernel) ||
- Args.hasArg(options::OPT_fapple_kext)) {
+ if (KernelOrKext) {
if (!Args.hasArg(options::OPT_fcommon))
CmdArgs.push_back("-fno-common");
Args.ClaimAllArgs(options::OPT_fno_common);
@@ -2919,9 +3217,24 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fno-spell-checking");
- // Silently ignore -fasm-blocks for now.
- (void) Args.hasFlag(options::OPT_fasm_blocks, options::OPT_fno_asm_blocks,
- false);
+ // -fno-asm-blocks is default.
+ if (Args.hasFlag(options::OPT_fasm_blocks, options::OPT_fno_asm_blocks,
+ false))
+ CmdArgs.push_back("-fasm-blocks");
+
+ // -fvectorize is default.
+ if (Args.hasFlag(options::OPT_fvectorize,
+ options::OPT_fno_vectorize, true)) {
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-vectorize-loops");
+ }
+
+ // -fno-slp-vectorize is default.
+ if (Args.hasFlag(options::OPT_fslp_vectorize,
+ options::OPT_fno_slp_vectorize, false)) {
+ CmdArgs.push_back("-backend-option");
+ CmdArgs.push_back("-vectorize");
+ }
if (Arg *A = Args.getLastArg(options::OPT_fshow_overloads_EQ))
A->render(Args, CmdArgs);
@@ -2983,6 +3296,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_fretain_comments_from_system_headers))
CmdArgs.push_back("-fretain-comments-from-system-headers");
+ // Forward -fcomment-block-commands to -cc1.
+ Args.AddAllArgs(CmdArgs, options::OPT_fcomment_block_commands);
+
// Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option
// parser.
Args.AddAllArgValues(CmdArgs, options::OPT_Xclang);
@@ -3043,8 +3359,27 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(Flags.str()));
}
+ // Add the split debug info name to the command lines here so we
+ // can propagate it to the backend.
+ bool SplitDwarf = Args.hasArg(options::OPT_gsplit_dwarf) &&
+ (getToolChain().getTriple().getOS() == llvm::Triple::Linux) &&
+ (isa<AssembleJobAction>(JA) || isa<CompileJobAction>(JA));
+ const char *SplitDwarfOut;
+ if (SplitDwarf) {
+ CmdArgs.push_back("-split-dwarf-file");
+ SplitDwarfOut = SplitDebugName(Args, Inputs);
+ CmdArgs.push_back(SplitDwarfOut);
+ }
+
+ // Finally add the compile command to the compilation.
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ // Handle the debug info splitting at object creation time if we're
+ // creating an object.
+ // TODO: Currently only works on linux with newer objcopy.
+ if (SplitDwarf && !isa<CompileJobAction>(JA))
+ SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, SplitDwarfOut);
+
if (Arg *A = Args.getLastArg(options::OPT_pg))
if (Args.hasArg(options::OPT_fomit_frame_pointer))
D.Diag(diag::err_drv_argument_not_allowed_with)
@@ -3085,6 +3420,15 @@ void ClangAs::AddARMTargetArgs(const ArgList &Args,
addFPMathArgs(D, A, Args, CmdArgs, getARMTargetCPU(Args, Triple));
}
+void ClangAs::AddX86TargetArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ // Set the CPU based on -march=.
+ if (const char *CPUName = getX86TargetCPU(Args, getToolChain().getTriple())) {
+ CmdArgs.push_back("-target-cpu");
+ CmdArgs.push_back(CPUName);
+ }
+}
+
/// Add options related to the Objective-C runtime/ABI.
///
/// Returns true if the runtime is non-fragile.
@@ -3243,6 +3587,11 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-filetype");
CmdArgs.push_back("obj");
+ // Set the main file name, so that debug info works even with
+ // -save-temps or preprocessed assembly.
+ CmdArgs.push_back("-main-file-name");
+ CmdArgs.push_back(Clang::getBaseInputName(Args, Inputs));
+
if (UseRelaxAll(C, Args))
CmdArgs.push_back("-relax-all");
@@ -3255,6 +3604,11 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
case llvm::Triple::thumb:
AddARMTargetArgs(Args, CmdArgs);
break;
+
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ AddX86TargetArgs(Args, CmdArgs);
+ break;
}
// Ignore explicit -force_cpusubtype_ALL option.
@@ -3267,13 +3621,22 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
SourceAction = SourceAction->getInputs()[0];
}
- // Forward -g, assuming we are dealing with an actual assembly file.
+ // Forward -g and handle debug info related flags, assuming we are dealing
+ // with an actual assembly file.
if (SourceAction->getType() == types::TY_Asm ||
SourceAction->getType() == types::TY_PP_Asm) {
Args.ClaimAllArgs(options::OPT_g_Group);
if (Arg *A = Args.getLastArg(options::OPT_g_Group))
if (!A->getOption().matches(options::OPT_g0))
CmdArgs.push_back("-g");
+
+ // Add the -fdebug-compilation-dir flag if needed.
+ addDebugCompDirArg(Args, CmdArgs);
+
+ // Set the AT_producer to the clang version when using the integrated
+ // assembler on assembly source files.
+ CmdArgs.push_back("-dwarf-debug-producer");
+ CmdArgs.push_back(Args.MakeArgString(getClangFullVersion()));
}
// Optionally embed the -cc1as level arguments into the debug info, for build
@@ -3361,7 +3724,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
// here.
if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::ppc)
CmdArgs.push_back("-m32");
- else if (Arch == llvm::Triple::x86_64 || Arch == llvm::Triple::x86_64)
+ else if (Arch == llvm::Triple::x86_64 || Arch == llvm::Triple::ppc64)
CmdArgs.push_back("-m64");
if (Output.isFilename()) {
@@ -3395,6 +3758,9 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
else if (II.getType() == types::TY_AST)
D.Diag(diag::err_drv_no_ast_support)
<< getToolChain().getTripleString();
+ else if (II.getType() == types::TY_ModuleFile)
+ D.Diag(diag::err_drv_no_module_support)
+ << getToolChain().getTripleString();
if (types::canTypeBeUserSpecified(II.getType())) {
CmdArgs.push_back("-x");
@@ -3483,7 +3849,7 @@ void hexagon::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
ArgStringList CmdArgs;
std::string MarchString = "-march=";
- MarchString += getHexagonTargetCPU(Args);
+ MarchString += toolchains::Hexagon_TC::GetTargetCPU(Args);
CmdArgs.push_back(Args.MakeArgString(MarchString));
RenderExtraToolArgs(JA, CmdArgs);
@@ -3496,6 +3862,14 @@ void hexagon::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fsyntax-only");
}
+ std::string SmallDataThreshold = GetHexagonSmallDataThresholdValue(Args);
+ if (!SmallDataThreshold.empty())
+ CmdArgs.push_back(
+ Args.MakeArgString(std::string("-G") + SmallDataThreshold));
+
+ Args.AddAllArgs(CmdArgs, options::OPT_g_Group);
+ Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
+ options::OPT_Xassembler);
// Only pass -x if gcc will understand it; otherwise hope gcc
// understands the suffix correctly. The main use case this would go
@@ -3517,6 +3891,9 @@ void hexagon::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
else if (II.getType() == types::TY_AST)
D.Diag(clang::diag::err_drv_no_ast_support)
<< getToolChain().getTripleString();
+ else if (II.getType() == types::TY_ModuleFile)
+ D.Diag(diag::err_drv_no_module_support)
+ << getToolChain().getTripleString();
if (II.isFilename())
CmdArgs.push_back(II.getFilename());
@@ -3542,77 +3919,168 @@ void hexagon::Link::ConstructJob(Compilation &C, const JobAction &JA,
const ArgList &Args,
const char *LinkingOutput) const {
- const Driver &D = getToolChain().getDriver();
+ const toolchains::Hexagon_TC& ToolChain =
+ static_cast<const toolchains::Hexagon_TC&>(getToolChain());
+ const Driver &D = ToolChain.getDriver();
+
ArgStringList CmdArgs;
- for (ArgList::const_iterator
- it = Args.begin(), ie = Args.end(); it != ie; ++it) {
- Arg *A = *it;
- if (forwardToGCC(A->getOption())) {
- // Don't forward any -g arguments to assembly steps.
- if (isa<AssembleJobAction>(JA) &&
- A->getOption().matches(options::OPT_g_Group))
- continue;
+ //----------------------------------------------------------------------------
+ //
+ //----------------------------------------------------------------------------
+ bool hasStaticArg = Args.hasArg(options::OPT_static);
+ bool buildingLib = Args.hasArg(options::OPT_shared);
+ bool buildPIE = Args.hasArg(options::OPT_pie);
+ bool incStdLib = !Args.hasArg(options::OPT_nostdlib);
+ bool incStartFiles = !Args.hasArg(options::OPT_nostartfiles);
+ bool incDefLibs = !Args.hasArg(options::OPT_nodefaultlibs);
+ bool useShared = buildingLib && !hasStaticArg;
+
+ //----------------------------------------------------------------------------
+ // Silence warnings for various options
+ //----------------------------------------------------------------------------
- // It is unfortunate that we have to claim here, as this means
- // we will basically never report anything interesting for
- // platforms using a generic gcc, even if we are just using gcc
- // to get to the assembler.
- A->claim();
- A->render(Args, CmdArgs);
- }
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ Args.ClaimAllArgs(options::OPT_emit_llvm);
+ Args.ClaimAllArgs(options::OPT_w); // Other warning options are already
+ // handled somewhere else.
+ Args.ClaimAllArgs(options::OPT_static_libgcc);
+
+ //----------------------------------------------------------------------------
+ //
+ //----------------------------------------------------------------------------
+ for (std::vector<std::string>::const_iterator i = ToolChain.ExtraOpts.begin(),
+ e = ToolChain.ExtraOpts.end();
+ i != e; ++i)
+ CmdArgs.push_back(i->c_str());
+
+ std::string MarchString = toolchains::Hexagon_TC::GetTargetCPU(Args);
+ CmdArgs.push_back(Args.MakeArgString("-m" + MarchString));
+
+ if (buildingLib) {
+ CmdArgs.push_back("-shared");
+ CmdArgs.push_back("-call_shared"); // should be the default, but doing as
+ // hexagon-gcc does
}
- RenderExtraToolArgs(JA, CmdArgs);
+ if (hasStaticArg)
+ CmdArgs.push_back("-static");
- // Add Arch Information
- Arg *A;
- if ((A = getLastHexagonArchArg(Args))) {
- if (A->getOption().matches(options::OPT_m_Joined))
- A->render(Args, CmdArgs);
- else
- CmdArgs.push_back (Args.MakeArgString("-m" + getHexagonTargetCPU(Args)));
+ if (buildPIE && !buildingLib)
+ CmdArgs.push_back("-pie");
+
+ std::string SmallDataThreshold = GetHexagonSmallDataThresholdValue(Args);
+ if (!SmallDataThreshold.empty()) {
+ CmdArgs.push_back(
+ Args.MakeArgString(std::string("-G") + SmallDataThreshold));
}
- else {
- CmdArgs.push_back (Args.MakeArgString("-m" + getHexagonTargetCPU(Args)));
+
+ //----------------------------------------------------------------------------
+ //
+ //----------------------------------------------------------------------------
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ const std::string MarchSuffix = "/" + MarchString;
+ const std::string G0Suffix = "/G0";
+ const std::string MarchG0Suffix = MarchSuffix + G0Suffix;
+ const std::string RootDir = toolchains::Hexagon_TC::GetGnuDir(D.InstalledDir)
+ + "/";
+ const std::string StartFilesDir = RootDir
+ + "hexagon/lib"
+ + (buildingLib
+ ? MarchG0Suffix : MarchSuffix);
+
+ //----------------------------------------------------------------------------
+ // moslib
+ //----------------------------------------------------------------------------
+ std::vector<std::string> oslibs;
+ bool hasStandalone= false;
+
+ for (arg_iterator it = Args.filtered_begin(options::OPT_moslib_EQ),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ (*it)->claim();
+ oslibs.push_back((*it)->getValue());
+ hasStandalone = hasStandalone || (oslibs.back() == "standalone");
+ }
+ if (oslibs.empty()) {
+ oslibs.push_back("standalone");
+ hasStandalone = true;
}
- CmdArgs.push_back("-mqdsp6-compat");
+ //----------------------------------------------------------------------------
+ // Start Files
+ //----------------------------------------------------------------------------
+ if (incStdLib && incStartFiles) {
- const char *GCCName;
- if (C.getDriver().CCCIsCXX)
- GCCName = "hexagon-g++";
- else
- GCCName = "hexagon-gcc";
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath(GCCName));
+ if (!buildingLib) {
+ if (hasStandalone) {
+ CmdArgs.push_back(
+ Args.MakeArgString(StartFilesDir + "/crt0_standalone.o"));
+ }
+ CmdArgs.push_back(Args.MakeArgString(StartFilesDir + "/crt0.o"));
+ }
+ std::string initObj = useShared ? "/initS.o" : "/init.o";
+ CmdArgs.push_back(Args.MakeArgString(StartFilesDir + initObj));
+ }
+
+ //----------------------------------------------------------------------------
+ // Library Search Paths
+ //----------------------------------------------------------------------------
+ const ToolChain::path_list &LibPaths = ToolChain.getFilePaths();
+ for (ToolChain::path_list::const_iterator
+ i = LibPaths.begin(),
+ e = LibPaths.end();
+ i != e;
+ ++i)
+ CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + *i));
- if (Output.isFilename()) {
- CmdArgs.push_back("-o");
- CmdArgs.push_back(Output.getFilename());
- }
+ //----------------------------------------------------------------------------
+ //
+ //----------------------------------------------------------------------------
+ Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
+ Args.AddAllArgs(CmdArgs, options::OPT_e);
+ Args.AddAllArgs(CmdArgs, options::OPT_s);
+ Args.AddAllArgs(CmdArgs, options::OPT_t);
+ Args.AddAllArgs(CmdArgs, options::OPT_u_Group);
- for (InputInfoList::const_iterator
- it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
- const InputInfo &II = *it;
+ AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
- // Don't try to pass LLVM or AST inputs to a generic gcc.
- if (II.getType() == types::TY_LLVM_IR || II.getType() == types::TY_LTO_IR ||
- II.getType() == types::TY_LLVM_BC || II.getType() == types::TY_LTO_BC)
- D.Diag(clang::diag::err_drv_no_linker_llvm_support)
- << getToolChain().getTripleString();
- else if (II.getType() == types::TY_AST)
- D.Diag(clang::diag::err_drv_no_ast_support)
- << getToolChain().getTripleString();
+ //----------------------------------------------------------------------------
+ // Libraries
+ //----------------------------------------------------------------------------
+ if (incStdLib && incDefLibs) {
+ if (D.CCCIsCXX) {
+ ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+ CmdArgs.push_back("-lm");
+ }
- if (II.isFilename())
- CmdArgs.push_back(II.getFilename());
- else
- // Don't render as input, we need gcc to do the translations. FIXME: Pranav: What is this ?
- II.getInputArg().render(Args, CmdArgs);
+ CmdArgs.push_back("--start-group");
+
+ if (!buildingLib) {
+ for(std::vector<std::string>::iterator i = oslibs.begin(),
+ e = oslibs.end(); i != e; ++i)
+ CmdArgs.push_back(Args.MakeArgString("-l" + *i));
+ CmdArgs.push_back("-lc");
+ }
+ CmdArgs.push_back("-lgcc");
+
+ CmdArgs.push_back("--end-group");
}
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ //----------------------------------------------------------------------------
+ // End files
+ //----------------------------------------------------------------------------
+ if (incStdLib && incStartFiles) {
+ std::string finiObj = useShared ? "/finiS.o" : "/fini.o";
+ CmdArgs.push_back(Args.MakeArgString(StartFilesDir + finiObj));
+ }
+
+ std::string Linker = ToolChain.GetProgramPath("hexagon-ld");
+ C.addCommand(
+ new Command(
+ JA, *this,
+ Args.MakeArgString(Linker), CmdArgs));
}
// Hexagon tools end.
@@ -3638,8 +4106,9 @@ llvm::Triple::ArchType darwin::getArchTypeForDarwinArchName(StringRef Str) {
llvm::Triple::x86)
.Case("x86_64", llvm::Triple::x86_64)
// This is derived from the driver driver.
- .Cases("arm", "armv4t", "armv5", "armv6", llvm::Triple::arm)
- .Cases("armv7", "armv7f", "armv7k", "armv7s", "xscale", llvm::Triple::arm)
+ .Cases("arm", "armv4t", "armv5", "armv6", "armv6m", llvm::Triple::arm)
+ .Cases("armv7", "armv7em", "armv7f", "armv7k", "armv7m", llvm::Triple::arm)
+ .Cases("armv7s", "xscale", llvm::Triple::arm)
.Case("r600", llvm::Triple::r600)
.Case("nvptx", llvm::Triple::nvptx)
.Case("nvptx64", llvm::Triple::nvptx64)
@@ -3648,38 +4117,14 @@ llvm::Triple::ArchType darwin::getArchTypeForDarwinArchName(StringRef Str) {
.Default(llvm::Triple::UnknownArch);
}
-const char *darwin::CC1::getCC1Name(types::ID Type) const {
- switch (Type) {
- default:
- llvm_unreachable("Unexpected type for Darwin CC1 tool.");
- case types::TY_Asm:
- case types::TY_C: case types::TY_CHeader:
- case types::TY_PP_C: case types::TY_PP_CHeader:
- return "cc1";
- case types::TY_ObjC: case types::TY_ObjCHeader:
- case types::TY_PP_ObjC: case types::TY_PP_ObjC_Alias:
- case types::TY_PP_ObjCHeader:
- return "cc1obj";
- case types::TY_CXX: case types::TY_CXXHeader:
- case types::TY_PP_CXX: case types::TY_PP_CXXHeader:
- return "cc1plus";
- case types::TY_ObjCXX: case types::TY_ObjCXXHeader:
- case types::TY_PP_ObjCXX: case types::TY_PP_ObjCXX_Alias:
- case types::TY_PP_ObjCXXHeader:
- return "cc1objplus";
- }
-}
-
-void darwin::CC1::anchor() {}
-
-const char *darwin::CC1::getBaseInputName(const ArgList &Args,
- const InputInfoList &Inputs) {
+const char *Clang::getBaseInputName(const ArgList &Args,
+ const InputInfoList &Inputs) {
return Args.MakeArgString(
llvm::sys::path::filename(Inputs[0].getBaseInput()));
}
-const char *darwin::CC1::getBaseInputStem(const ArgList &Args,
- const InputInfoList &Inputs) {
+const char *Clang::getBaseInputStem(const ArgList &Args,
+ const InputInfoList &Inputs) {
const char *Str = getBaseInputName(Args, Inputs);
if (const char *End = strrchr(Str, '.'))
@@ -3688,9 +4133,8 @@ const char *darwin::CC1::getBaseInputStem(const ArgList &Args,
return Str;
}
-const char *
-darwin::CC1::getDependencyFileName(const ArgList &Args,
- const InputInfoList &Inputs) {
+const char *Clang::getDependencyFileName(const ArgList &Args,
+ const InputInfoList &Inputs) {
// FIXME: Think about this more.
std::string Res;
@@ -3698,588 +4142,11 @@ darwin::CC1::getDependencyFileName(const ArgList &Args,
std::string Str(OutputOpt->getValue());
Res = Str.substr(0, Str.rfind('.'));
} else {
- Res = darwin::CC1::getBaseInputStem(Args, Inputs);
+ Res = getBaseInputStem(Args, Inputs);
}
return Args.MakeArgString(Res + ".d");
}
-void darwin::CC1::RemoveCC1UnsupportedArgs(ArgStringList &CmdArgs) const {
- for (ArgStringList::iterator it = CmdArgs.begin(), ie = CmdArgs.end();
- it != ie;) {
-
- StringRef Option = *it;
- bool RemoveOption = false;
-
- // Erase both -fmodule-cache-path and its argument.
- if (Option.equals("-fmodule-cache-path") && it+2 != ie) {
- it = CmdArgs.erase(it, it+2);
- ie = CmdArgs.end();
- continue;
- }
-
- // Remove unsupported -f options.
- if (Option.startswith("-f")) {
- // Remove -f/-fno- to reduce the number of cases.
- if (Option.startswith("-fno-"))
- Option = Option.substr(5);
- else
- Option = Option.substr(2);
- RemoveOption = llvm::StringSwitch<bool>(Option)
- .Case("altivec", true)
- .Case("modules", true)
- .Case("diagnostics-show-note-include-stack", true)
- .Default(false);
- }
-
- // Handle machine specific options.
- if (Option.startswith("-m")) {
- RemoveOption = llvm::StringSwitch<bool>(Option)
- .Case("-mthumb", true)
- .Case("-mno-thumb", true)
- .Case("-mno-fused-madd", true)
- .Case("-mlong-branch", true)
- .Case("-mlongcall", true)
- .Case("-mcpu=G4", true)
- .Case("-mcpu=G5", true)
- .Default(false);
- }
-
- // Handle warning options.
- if (Option.startswith("-W")) {
- // Remove -W/-Wno- to reduce the number of cases.
- if (Option.startswith("-Wno-"))
- Option = Option.substr(5);
- else
- Option = Option.substr(2);
-
- RemoveOption = llvm::StringSwitch<bool>(Option)
- .Case("address-of-temporary", true)
- .Case("ambiguous-member-template", true)
- .Case("analyzer-incompatible-plugin", true)
- .Case("array-bounds", true)
- .Case("array-bounds-pointer-arithmetic", true)
- .Case("bind-to-temporary-copy", true)
- .Case("bitwise-op-parentheses", true)
- .Case("bool-conversions", true)
- .Case("builtin-macro-redefined", true)
- .Case("c++-hex-floats", true)
- .Case("c++0x-compat", true)
- .Case("c++0x-extensions", true)
- .Case("c++0x-narrowing", true)
- .Case("c++11-compat", true)
- .Case("c++11-extensions", true)
- .Case("c++11-narrowing", true)
- .Case("conditional-uninitialized", true)
- .Case("constant-conversion", true)
- .Case("conversion-null", true)
- .Case("CFString-literal", true)
- .Case("constant-logical-operand", true)
- .Case("custom-atomic-properties", true)
- .Case("default-arg-special-member", true)
- .Case("delegating-ctor-cycles", true)
- .Case("delete-non-virtual-dtor", true)
- .Case("deprecated-implementations", true)
- .Case("deprecated-writable-strings", true)
- .Case("distributed-object-modifiers", true)
- .Case("duplicate-method-arg", true)
- .Case("dynamic-class-memaccess", true)
- .Case("enum-compare", true)
- .Case("enum-conversion", true)
- .Case("exit-time-destructors", true)
- .Case("gnu", true)
- .Case("gnu-designator", true)
- .Case("header-hygiene", true)
- .Case("idiomatic-parentheses", true)
- .Case("ignored-qualifiers", true)
- .Case("implicit-atomic-properties", true)
- .Case("incompatible-pointer-types", true)
- .Case("incomplete-implementation", true)
- .Case("int-conversion", true)
- .Case("initializer-overrides", true)
- .Case("invalid-noreturn", true)
- .Case("invalid-token-paste", true)
- .Case("language-extension-token", true)
- .Case("literal-conversion", true)
- .Case("literal-range", true)
- .Case("local-type-template-args", true)
- .Case("logical-op-parentheses", true)
- .Case("method-signatures", true)
- .Case("microsoft", true)
- .Case("mismatched-tags", true)
- .Case("missing-method-return-type", true)
- .Case("non-pod-varargs", true)
- .Case("nonfragile-abi2", true)
- .Case("null-arithmetic", true)
- .Case("null-dereference", true)
- .Case("out-of-line-declaration", true)
- .Case("overriding-method-mismatch", true)
- .Case("readonly-setter-attrs", true)
- .Case("return-stack-address", true)
- .Case("self-assign", true)
- .Case("semicolon-before-method-body", true)
- .Case("sentinel", true)
- .Case("shift-overflow", true)
- .Case("shift-sign-overflow", true)
- .Case("sign-conversion", true)
- .Case("sizeof-array-argument", true)
- .Case("sizeof-pointer-memaccess", true)
- .Case("string-compare", true)
- .Case("super-class-method-mismatch", true)
- .Case("tautological-compare", true)
- .Case("typedef-redefinition", true)
- .Case("typename-missing", true)
- .Case("undefined-reinterpret-cast", true)
- .Case("unknown-warning-option", true)
- .Case("unnamed-type-template-args", true)
- .Case("unneeded-internal-declaration", true)
- .Case("unneeded-member-function", true)
- .Case("unused-comparison", true)
- .Case("unused-exception-parameter", true)
- .Case("unused-member-function", true)
- .Case("unused-result", true)
- .Case("vector-conversions", true)
- .Case("vla", true)
- .Case("used-but-marked-unused", true)
- .Case("weak-vtables", true)
- .Default(false);
- } // if (Option.startswith("-W"))
- if (RemoveOption) {
- it = CmdArgs.erase(it);
- ie = CmdArgs.end();
- } else {
- ++it;
- }
- }
-}
-
-void darwin::CC1::AddCC1Args(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- const Driver &D = getToolChain().getDriver();
-
- CheckCodeGenerationOptions(D, Args);
-
- // Derived from cc1 spec.
- if ((!Args.hasArg(options::OPT_mkernel) ||
- (getDarwinToolChain().isTargetIPhoneOS() &&
- !getDarwinToolChain().isIPhoneOSVersionLT(6, 0))) &&
- !Args.hasArg(options::OPT_static) &&
- !Args.hasArg(options::OPT_mdynamic_no_pic))
- CmdArgs.push_back("-fPIC");
-
- if (getToolChain().getTriple().getArch() == llvm::Triple::arm ||
- getToolChain().getTriple().getArch() == llvm::Triple::thumb) {
- if (!Args.hasArg(options::OPT_fbuiltin_strcat))
- CmdArgs.push_back("-fno-builtin-strcat");
- if (!Args.hasArg(options::OPT_fbuiltin_strcpy))
- CmdArgs.push_back("-fno-builtin-strcpy");
- }
-
- if (Args.hasArg(options::OPT_g_Flag) &&
- !Args.hasArg(options::OPT_fno_eliminate_unused_debug_symbols))
- CmdArgs.push_back("-feliminate-unused-debug-symbols");
-}
-
-void darwin::CC1::AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs,
- const InputInfoList &Inputs,
- const ArgStringList &OutputArgs) const {
- const Driver &D = getToolChain().getDriver();
-
- // Derived from cc1_options spec.
- if (Args.hasArg(options::OPT_fast) ||
- Args.hasArg(options::OPT_fastf) ||
- Args.hasArg(options::OPT_fastcp))
- CmdArgs.push_back("-O3");
-
- if (Arg *A = Args.getLastArg(options::OPT_pg))
- if (Args.hasArg(options::OPT_fomit_frame_pointer))
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << A->getAsString(Args) << "-fomit-frame-pointer";
-
- AddCC1Args(Args, CmdArgs);
-
- if (!Args.hasArg(options::OPT_Q))
- CmdArgs.push_back("-quiet");
-
- CmdArgs.push_back("-dumpbase");
- CmdArgs.push_back(darwin::CC1::getBaseInputName(Args, Inputs));
-
- Args.AddAllArgs(CmdArgs, options::OPT_d_Group);
-
- Args.AddAllArgs(CmdArgs, options::OPT_m_Group);
- Args.AddAllArgs(CmdArgs, options::OPT_a_Group);
-
- // FIXME: The goal is to use the user provided -o if that is our
- // final output, otherwise to drive from the original input
- // name. Find a clean way to go about this.
- if ((Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) &&
- Args.hasArg(options::OPT_o)) {
- Arg *OutputOpt = Args.getLastArg(options::OPT_o);
- CmdArgs.push_back("-auxbase-strip");
- CmdArgs.push_back(OutputOpt->getValue());
- } else {
- CmdArgs.push_back("-auxbase");
- CmdArgs.push_back(darwin::CC1::getBaseInputStem(Args, Inputs));
- }
-
- Args.AddAllArgs(CmdArgs, options::OPT_g_Group);
-
- Args.AddAllArgs(CmdArgs, options::OPT_O);
- // FIXME: -Wall is getting some special treatment. Investigate.
- Args.AddAllArgs(CmdArgs, options::OPT_W_Group, options::OPT_pedantic_Group);
- Args.AddLastArg(CmdArgs, options::OPT_w);
- Args.AddAllArgs(CmdArgs, options::OPT_std_EQ, options::OPT_ansi,
- options::OPT_trigraphs);
- if (!Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi)) {
- // Honor -std-default.
- Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ,
- "-std=", /*Joined=*/true);
- }
-
- if (Args.hasArg(options::OPT_v))
- CmdArgs.push_back("-version");
- if (Args.hasArg(options::OPT_pg) &&
- getToolChain().SupportsProfiling())
- CmdArgs.push_back("-p");
- Args.AddLastArg(CmdArgs, options::OPT_p);
-
- // The driver treats -fsyntax-only specially.
- if (getToolChain().getTriple().getArch() == llvm::Triple::arm ||
- getToolChain().getTriple().getArch() == llvm::Triple::thumb) {
- // Removes -fbuiltin-str{cat,cpy}; these aren't recognized by cc1 but are
- // used to inhibit the default -fno-builtin-str{cat,cpy}.
- //
- // FIXME: Should we grow a better way to deal with "removing" args?
- for (arg_iterator it = Args.filtered_begin(options::OPT_f_Group,
- options::OPT_fsyntax_only),
- ie = Args.filtered_end(); it != ie; ++it) {
- if (!(*it)->getOption().matches(options::OPT_fbuiltin_strcat) &&
- !(*it)->getOption().matches(options::OPT_fbuiltin_strcpy)) {
- (*it)->claim();
- (*it)->render(Args, CmdArgs);
- }
- }
- } else
- Args.AddAllArgs(CmdArgs, options::OPT_f_Group, options::OPT_fsyntax_only);
-
- // Claim Clang only -f options, they aren't worth warning about.
- Args.ClaimAllArgs(options::OPT_f_clang_Group);
-
- Args.AddAllArgs(CmdArgs, options::OPT_undef);
- if (Args.hasArg(options::OPT_Qn))
- CmdArgs.push_back("-fno-ident");
-
- // FIXME: This isn't correct.
- //Args.AddLastArg(CmdArgs, options::OPT__help)
- //Args.AddLastArg(CmdArgs, options::OPT__targetHelp)
-
- CmdArgs.append(OutputArgs.begin(), OutputArgs.end());
-
- // FIXME: Still don't get what is happening here. Investigate.
- Args.AddAllArgs(CmdArgs, options::OPT__param);
-
- if (Args.hasArg(options::OPT_fmudflap) ||
- Args.hasArg(options::OPT_fmudflapth)) {
- CmdArgs.push_back("-fno-builtin");
- CmdArgs.push_back("-fno-merge-constants");
- }
-
- if (Args.hasArg(options::OPT_coverage)) {
- CmdArgs.push_back("-fprofile-arcs");
- CmdArgs.push_back("-ftest-coverage");
- }
-
- if (types::isCXX(Inputs[0].getType()))
- CmdArgs.push_back("-D__private_extern__=extern");
-}
-
-void darwin::CC1::AddCPPOptionsArgs(const ArgList &Args, ArgStringList &CmdArgs,
- const InputInfoList &Inputs,
- const ArgStringList &OutputArgs) const {
- // Derived from cpp_options
- AddCPPUniqueOptionsArgs(Args, CmdArgs, Inputs);
-
- CmdArgs.append(OutputArgs.begin(), OutputArgs.end());
-
- AddCC1Args(Args, CmdArgs);
-
- // NOTE: The code below has some commonality with cpp_options, but
- // in classic gcc style ends up sending things in different
- // orders. This may be a good merge candidate once we drop pedantic
- // compatibility.
-
- Args.AddAllArgs(CmdArgs, options::OPT_m_Group);
- Args.AddAllArgs(CmdArgs, options::OPT_std_EQ, options::OPT_ansi,
- options::OPT_trigraphs);
- if (!Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi)) {
- // Honor -std-default.
- Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ,
- "-std=", /*Joined=*/true);
- }
- Args.AddAllArgs(CmdArgs, options::OPT_W_Group, options::OPT_pedantic_Group);
- Args.AddLastArg(CmdArgs, options::OPT_w);
-
- // The driver treats -fsyntax-only specially.
- Args.AddAllArgs(CmdArgs, options::OPT_f_Group, options::OPT_fsyntax_only);
-
- // Claim Clang only -f options, they aren't worth warning about.
- Args.ClaimAllArgs(options::OPT_f_clang_Group);
-
- if (Args.hasArg(options::OPT_g_Group) && !Args.hasArg(options::OPT_g0) &&
- !Args.hasArg(options::OPT_fno_working_directory))
- CmdArgs.push_back("-fworking-directory");
-
- Args.AddAllArgs(CmdArgs, options::OPT_O);
- Args.AddAllArgs(CmdArgs, options::OPT_undef);
- if (Args.hasArg(options::OPT_save_temps))
- CmdArgs.push_back("-fpch-preprocess");
-}
-
-void darwin::CC1::AddCPPUniqueOptionsArgs(const ArgList &Args,
- ArgStringList &CmdArgs,
- const InputInfoList &Inputs) const {
- const Driver &D = getToolChain().getDriver();
-
- CheckPreprocessingOptions(D, Args);
-
- // Derived from cpp_unique_options.
- // -{C,CC} only with -E is checked in CheckPreprocessingOptions().
- Args.AddLastArg(CmdArgs, options::OPT_C);
- Args.AddLastArg(CmdArgs, options::OPT_CC);
- if (!Args.hasArg(options::OPT_Q))
- CmdArgs.push_back("-quiet");
- Args.AddAllArgs(CmdArgs, options::OPT_nostdinc);
- Args.AddAllArgs(CmdArgs, options::OPT_nostdincxx);
- Args.AddLastArg(CmdArgs, options::OPT_v);
- Args.AddAllArgs(CmdArgs, options::OPT_I_Group, options::OPT_F);
- Args.AddLastArg(CmdArgs, options::OPT_P);
-
- // FIXME: Handle %I properly.
- if (getToolChain().getArch() == llvm::Triple::x86_64) {
- CmdArgs.push_back("-imultilib");
- CmdArgs.push_back("x86_64");
- }
-
- if (Args.hasArg(options::OPT_MD)) {
- CmdArgs.push_back("-MD");
- CmdArgs.push_back(darwin::CC1::getDependencyFileName(Args, Inputs));
- }
-
- if (Args.hasArg(options::OPT_MMD)) {
- CmdArgs.push_back("-MMD");
- CmdArgs.push_back(darwin::CC1::getDependencyFileName(Args, Inputs));
- }
-
- Args.AddLastArg(CmdArgs, options::OPT_M);
- Args.AddLastArg(CmdArgs, options::OPT_MM);
- Args.AddAllArgs(CmdArgs, options::OPT_MF);
- Args.AddLastArg(CmdArgs, options::OPT_MG);
- Args.AddLastArg(CmdArgs, options::OPT_MP);
- Args.AddAllArgs(CmdArgs, options::OPT_MQ);
- Args.AddAllArgs(CmdArgs, options::OPT_MT);
- if (!Args.hasArg(options::OPT_M) && !Args.hasArg(options::OPT_MM) &&
- (Args.hasArg(options::OPT_MD) || Args.hasArg(options::OPT_MMD))) {
- if (Arg *OutputOpt = Args.getLastArg(options::OPT_o)) {
- CmdArgs.push_back("-MQ");
- CmdArgs.push_back(OutputOpt->getValue());
- }
- }
-
- Args.AddLastArg(CmdArgs, options::OPT_remap);
- if (Args.hasArg(options::OPT_g3))
- CmdArgs.push_back("-dD");
- Args.AddLastArg(CmdArgs, options::OPT_H);
-
- AddCPPArgs(Args, CmdArgs);
-
- Args.AddAllArgs(CmdArgs, options::OPT_D, options::OPT_U, options::OPT_A);
- Args.AddAllArgs(CmdArgs, options::OPT_i_Group);
-
- for (InputInfoList::const_iterator
- it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
- const InputInfo &II = *it;
-
- CmdArgs.push_back(II.getFilename());
- }
-
- Args.AddAllArgValues(CmdArgs, options::OPT_Wp_COMMA,
- options::OPT_Xpreprocessor);
-
- if (Args.hasArg(options::OPT_fmudflap)) {
- CmdArgs.push_back("-D_MUDFLAP");
- CmdArgs.push_back("-include");
- CmdArgs.push_back("mf-runtime.h");
- }
-
- if (Args.hasArg(options::OPT_fmudflapth)) {
- CmdArgs.push_back("-D_MUDFLAP");
- CmdArgs.push_back("-D_MUDFLAPTH");
- CmdArgs.push_back("-include");
- CmdArgs.push_back("mf-runtime.h");
- }
-}
-
-void darwin::CC1::AddCPPArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- // Derived from cpp spec.
-
- if (Args.hasArg(options::OPT_static)) {
- // The gcc spec is broken here, it refers to dynamic but
- // that has been translated. Start by being bug compatible.
-
- // if (!Args.hasArg(arglist.parser.dynamicOption))
- CmdArgs.push_back("-D__STATIC__");
- } else
- CmdArgs.push_back("-D__DYNAMIC__");
-
- if (Args.hasArg(options::OPT_pthread))
- CmdArgs.push_back("-D_REENTRANT");
-}
-
-void darwin::Preprocess::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- ArgStringList CmdArgs;
-
- assert(Inputs.size() == 1 && "Unexpected number of inputs!");
-
- CmdArgs.push_back("-E");
-
- if (Args.hasArg(options::OPT_traditional) ||
- Args.hasArg(options::OPT_traditional_cpp))
- CmdArgs.push_back("-traditional-cpp");
-
- ArgStringList OutputArgs;
- assert(Output.isFilename() && "Unexpected CC1 output.");
- OutputArgs.push_back("-o");
- OutputArgs.push_back(Output.getFilename());
-
- if (Args.hasArg(options::OPT_E) || getToolChain().getDriver().CCCIsCPP) {
- AddCPPOptionsArgs(Args, CmdArgs, Inputs, OutputArgs);
- } else {
- AddCPPOptionsArgs(Args, CmdArgs, Inputs, ArgStringList());
- CmdArgs.append(OutputArgs.begin(), OutputArgs.end());
- }
-
- Args.AddAllArgs(CmdArgs, options::OPT_d_Group);
-
- RemoveCC1UnsupportedArgs(CmdArgs);
-
- const char *CC1Name = getCC1Name(Inputs[0].getType());
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath(CC1Name));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
-}
-
-void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
- const Driver &D = getToolChain().getDriver();
- ArgStringList CmdArgs;
-
- assert(Inputs.size() == 1 && "Unexpected number of inputs!");
-
- // Silence warning about unused --serialize-diagnostics
- Args.ClaimAllArgs(options::OPT__serialize_diags);
-
- types::ID InputType = Inputs[0].getType();
- if (const Arg *A = Args.getLastArg(options::OPT_traditional))
- D.Diag(diag::err_drv_argument_only_allowed_with)
- << A->getAsString(Args) << "-E";
-
- if (JA.getType() == types::TY_LLVM_IR ||
- JA.getType() == types::TY_LTO_IR)
- CmdArgs.push_back("-emit-llvm");
- else if (JA.getType() == types::TY_LLVM_BC ||
- JA.getType() == types::TY_LTO_BC)
- CmdArgs.push_back("-emit-llvm-bc");
- else if (Output.getType() == types::TY_AST)
- D.Diag(diag::err_drv_no_ast_support)
- << getToolChain().getTripleString();
- else if (JA.getType() != types::TY_PP_Asm &&
- JA.getType() != types::TY_PCH)
- D.Diag(diag::err_drv_invalid_gcc_output_type)
- << getTypeName(JA.getType());
-
- ArgStringList OutputArgs;
- if (Output.getType() != types::TY_PCH) {
- OutputArgs.push_back("-o");
- if (Output.isNothing())
- OutputArgs.push_back("/dev/null");
- else
- OutputArgs.push_back(Output.getFilename());
- }
-
- // There is no need for this level of compatibility, but it makes
- // diffing easier.
- bool OutputArgsEarly = (Args.hasArg(options::OPT_fsyntax_only) ||
- Args.hasArg(options::OPT_S));
-
- if (types::getPreprocessedType(InputType) != types::TY_INVALID) {
- AddCPPUniqueOptionsArgs(Args, CmdArgs, Inputs);
- if (OutputArgsEarly) {
- AddCC1OptionsArgs(Args, CmdArgs, Inputs, OutputArgs);
- } else {
- AddCC1OptionsArgs(Args, CmdArgs, Inputs, ArgStringList());
- CmdArgs.append(OutputArgs.begin(), OutputArgs.end());
- }
- } else {
- CmdArgs.push_back("-fpreprocessed");
-
- for (InputInfoList::const_iterator
- it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
- const InputInfo &II = *it;
-
- // Reject AST inputs.
- if (II.getType() == types::TY_AST) {
- D.Diag(diag::err_drv_no_ast_support)
- << getToolChain().getTripleString();
- return;
- }
-
- CmdArgs.push_back(II.getFilename());
- }
-
- if (OutputArgsEarly) {
- AddCC1OptionsArgs(Args, CmdArgs, Inputs, OutputArgs);
- } else {
- AddCC1OptionsArgs(Args, CmdArgs, Inputs, ArgStringList());
- CmdArgs.append(OutputArgs.begin(), OutputArgs.end());
- }
- }
-
- if (Output.getType() == types::TY_PCH) {
- assert(Output.isFilename() && "Invalid PCH output.");
-
- CmdArgs.push_back("-o");
- // NOTE: gcc uses a temp .s file for this, but there doesn't seem
- // to be a good reason.
- const char *TmpPath = C.getArgs().MakeArgString(
- D.GetTemporaryPath("cc", "s"));
- C.addTempFile(TmpPath);
- CmdArgs.push_back(TmpPath);
-
- // If we're emitting a pch file with the last 4 characters of ".pth"
- // and falling back to llvm-gcc we want to use ".gch" instead.
- std::string OutputFile(Output.getFilename());
- size_t loc = OutputFile.rfind(".pth");
- if (loc != std::string::npos)
- OutputFile.replace(loc, 4, ".gch");
- const char *Tmp = C.getArgs().MakeArgString("--output-pch="+OutputFile);
- CmdArgs.push_back(Tmp);
- }
-
- RemoveCC1UnsupportedArgs(CmdArgs);
-
- const char *CC1Name = getCC1Name(Inputs[0].getType());
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath(CC1Name));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
-}
-
void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
@@ -4613,6 +4480,9 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (Args.hasArg(options::OPT_ObjC) || Args.hasArg(options::OPT_ObjCXX))
CmdArgs.push_back("-ObjC");
+ if (Args.hasArg(options::OPT_rdynamic))
+ CmdArgs.push_back("-export_dynamic");
+
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
@@ -4710,11 +4580,11 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgs(CmdArgs, options::OPT_L);
SanitizerArgs Sanitize(getToolChain().getDriver(), Args);
- // If we're building a dynamic lib with -fsanitize=address, or
- // -fsanitize=undefined, unresolved symbols may appear. Mark all
+ // If we're building a dynamic lib with -fsanitize=address,
+ // unresolved symbols may appear. Mark all
// of them as dynamic_lookup. Linking executables is handled in
// lib/Driver/ToolChains.cpp.
- if (Sanitize.needsAsanRt() || Sanitize.needsUbsanRt()) {
+ if (Sanitize.needsAsanRt()) {
if (Args.hasArg(options::OPT_dynamiclib) ||
Args.hasArg(options::OPT_bundle)) {
CmdArgs.push_back("-undefined");
@@ -4828,10 +4698,10 @@ void darwin::Dsymutil::ConstructJob(Compilation &C, const JobAction &JA,
}
void darwin::VerifyDebug::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
ArgStringList CmdArgs;
CmdArgs.push_back("--verify");
CmdArgs.push_back("--debug-info");
@@ -5125,6 +4995,14 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
const Driver &D = getToolChain().getDriver();
ArgStringList CmdArgs;
+ // Silence warning for "clang -g foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ // and "clang -emit-llvm foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_emit_llvm);
+ // and for "clang -w foo.o -o foo". Other warning options are already
+ // handled somewhere else.
+ Args.ClaimAllArgs(options::OPT_w);
+
if ((!Args.hasArg(options::OPT_nostdlib)) &&
(!Args.hasArg(options::OPT_shared))) {
CmdArgs.push_back("-e");
@@ -5179,6 +5057,10 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgs(CmdArgs, options::OPT_L);
Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
Args.AddAllArgs(CmdArgs, options::OPT_e);
+ Args.AddAllArgs(CmdArgs, options::OPT_s);
+ Args.AddAllArgs(CmdArgs, options::OPT_t);
+ Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag);
+ Args.AddAllArgs(CmdArgs, options::OPT_r);
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
@@ -5395,14 +5277,8 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-march");
CmdArgs.push_back(CPUName.data());
- // Convert ABI name to the GNU tools acceptable variant.
- if (ABIName == "o32")
- ABIName = "32";
- else if (ABIName == "n64")
- ABIName = "64";
-
CmdArgs.push_back("-mabi");
- CmdArgs.push_back(ABIName.data());
+ CmdArgs.push_back(getGnuCompatibleMipsABIName(ABIName).data());
if (getToolChain().getArch() == llvm::Triple::mips ||
getToolChain().getArch() == llvm::Triple::mips64)
@@ -5421,6 +5297,18 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
LastPICArg->getOption().matches(options::OPT_fpie))) {
CmdArgs.push_back("-KPIC");
}
+ } else if (getToolChain().getArch() == llvm::Triple::arm ||
+ getToolChain().getArch() == llvm::Triple::thumb) {
+ CmdArgs.push_back("-mfpu=softvfp");
+ switch(getToolChain().getTriple().getEnvironment()) {
+ case llvm::Triple::GNUEABI:
+ case llvm::Triple::EABI:
+ CmdArgs.push_back("-meabi=5");
+ break;
+
+ default:
+ CmdArgs.push_back("-matpcs");
+ }
}
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA,
@@ -5765,11 +5653,11 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
-void linuxtools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
+void gnutools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
ArgStringList CmdArgs;
// Add --32/--64 to make sure we get the format we want.
@@ -5809,14 +5697,8 @@ void linuxtools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-march");
CmdArgs.push_back(CPUName.data());
- // Convert ABI name to the GNU tools acceptable variant.
- if (ABIName == "o32")
- ABIName = "32";
- else if (ABIName == "n64")
- ABIName = "64";
-
CmdArgs.push_back("-mabi");
- CmdArgs.push_back(ABIName.data());
+ CmdArgs.push_back(getGnuCompatibleMipsABIName(ABIName).data());
if (getToolChain().getArch() == llvm::Triple::mips ||
getToolChain().getArch() == llvm::Triple::mips64)
@@ -5857,12 +5739,12 @@ void linuxtools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
static void AddLibgcc(llvm::Triple Triple, const Driver &D,
ArgStringList &CmdArgs, const ArgList &Args) {
bool isAndroid = Triple.getEnvironment() == llvm::Triple::Android;
- bool StaticLibgcc = isAndroid || Args.hasArg(options::OPT_static) ||
- Args.hasArg(options::OPT_static_libgcc);
+ bool StaticLibgcc = Args.hasArg(options::OPT_static_libgcc) ||
+ Args.hasArg(options::OPT_static);
if (!D.CCCIsCXX)
CmdArgs.push_back("-lgcc");
- if (StaticLibgcc) {
+ if (StaticLibgcc || isAndroid) {
if (D.CCCIsCXX)
CmdArgs.push_back("-lgcc");
} else {
@@ -5877,6 +5759,14 @@ static void AddLibgcc(llvm::Triple Triple, const Driver &D,
CmdArgs.push_back("-lgcc_eh");
else if (!Args.hasArg(options::OPT_shared) && D.CCCIsCXX)
CmdArgs.push_back("-lgcc");
+
+ // According to Android ABI, we have to link with libdl if we are
+ // linking with non-static libgcc.
+ //
+ // NOTE: This fixes a link error on Android MIPS as well. The non-static
+ // libgcc for MIPS relies on _Unwind_Find_FDE and dl_iterate_phdr from libdl.
+ if (isAndroid && !StaticLibgcc)
+ CmdArgs.push_back("-ldl");
}
static bool hasMipsN32ABIArg(const ArgList &Args) {
@@ -5884,11 +5774,11 @@ static bool hasMipsN32ABIArg(const ArgList &Args) {
return A && (A->getValue() == StringRef("n32"));
}
-void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &Args,
- const char *LinkingOutput) const {
+void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
const toolchains::Linux& ToolChain =
static_cast<const toolchains::Linux&>(getToolChain());
const Driver &D = ToolChain.getDriver();
@@ -5908,7 +5798,7 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
if (!D.SysRoot.empty())
CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
- if (Args.hasArg(options::OPT_pie))
+ if (Args.hasArg(options::OPT_pie) && !Args.hasArg(options::OPT_shared))
CmdArgs.push_back("-pie");
if (Args.hasArg(options::OPT_rdynamic))
@@ -5929,6 +5819,8 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-m");
if (ToolChain.getArch() == llvm::Triple::x86)
CmdArgs.push_back("elf_i386");
+ else if (ToolChain.getArch() == llvm::Triple::aarch64)
+ CmdArgs.push_back("aarch64linux");
else if (ToolChain.getArch() == llvm::Triple::arm
|| ToolChain.getArch() == llvm::Triple::thumb)
CmdArgs.push_back("armelf_linux_eabi");
@@ -5977,6 +5869,8 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("/system/bin/linker");
else if (ToolChain.getArch() == llvm::Triple::x86)
CmdArgs.push_back("/lib/ld-linux.so.2");
+ else if (ToolChain.getArch() == llvm::Triple::aarch64)
+ CmdArgs.push_back("/lib/ld-linux-aarch64.so.1");
else if (ToolChain.getArch() == llvm::Triple::arm ||
ToolChain.getArch() == llvm::Triple::thumb) {
if (ToolChain.getTriple().getEnvironment() == llvm::Triple::GNUEABIHF)
@@ -6051,8 +5945,27 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-plugin");
std::string Plugin = ToolChain.getDriver().Dir + "/../lib/LLVMgold.so";
CmdArgs.push_back(Args.MakeArgString(Plugin));
+
+ // Try to pass driver level flags relevant to LTO code generation down to
+ // the plugin.
+
+ // Handle architecture-specific flags for selecting CPU variants.
+ if (ToolChain.getArch() == llvm::Triple::x86 ||
+ ToolChain.getArch() == llvm::Triple::x86_64)
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine("-plugin-opt=mcpu=") +
+ getX86TargetCPU(Args, ToolChain.getTriple())));
+ else if (ToolChain.getArch() == llvm::Triple::arm ||
+ ToolChain.getArch() == llvm::Triple::thumb)
+ CmdArgs.push_back(
+ Args.MakeArgString(Twine("-plugin-opt=mcpu=") +
+ getARMTargetCPU(Args, ToolChain.getTriple())));
+
+ // FIXME: Factor out logic for MIPS, PPC, and other targets to support this
+ // as well.
}
+
if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
CmdArgs.push_back("--no-demangle");
@@ -6060,9 +5973,17 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
SanitizerArgs Sanitize(D, Args);
- // Call this before we add the C++ ABI library.
+ // Call these before we add the C++ ABI library.
if (Sanitize.needsUbsanRt())
- addUbsanRTLinux(getToolChain(), Args, CmdArgs);
+ addUbsanRTLinux(getToolChain(), Args, CmdArgs, D.CCCIsCXX,
+ Sanitize.needsAsanRt() || Sanitize.needsTsanRt() ||
+ Sanitize.needsMsanRt());
+ if (Sanitize.needsAsanRt())
+ addAsanRTLinux(getToolChain(), Args, CmdArgs);
+ if (Sanitize.needsTsanRt())
+ addTsanRTLinux(getToolChain(), Args, CmdArgs);
+ if (Sanitize.needsMsanRt())
+ addMsanRTLinux(getToolChain(), Args, CmdArgs);
if (D.CCCIsCXX &&
!Args.hasArg(options::OPT_nostdlib) &&
@@ -6077,21 +5998,24 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-lm");
}
- // Call this before we add the C run-time.
- if (Sanitize.needsAsanRt())
- addAsanRTLinux(getToolChain(), Args, CmdArgs);
- if (Sanitize.needsTsanRt())
- addTsanRTLinux(getToolChain(), Args, CmdArgs);
-
if (!Args.hasArg(options::OPT_nostdlib)) {
if (!Args.hasArg(options::OPT_nodefaultlibs)) {
if (Args.hasArg(options::OPT_static))
CmdArgs.push_back("--start-group");
+ bool OpenMP = Args.hasArg(options::OPT_fopenmp);
+ if (OpenMP) {
+ CmdArgs.push_back("-lgomp");
+
+ // FIXME: Exclude this for platforms whith libgomp that doesn't require
+ // librt. Most modern Linux platfroms require it, but some may not.
+ CmdArgs.push_back("-lrt");
+ }
+
AddLibgcc(ToolChain.getTriple(), D, CmdArgs, Args);
if (Args.hasArg(options::OPT_pthread) ||
- Args.hasArg(options::OPT_pthreads))
+ Args.hasArg(options::OPT_pthreads) || OpenMP)
CmdArgs.push_back("-lpthread");
CmdArgs.push_back("-lc");
@@ -6193,7 +6117,7 @@ void minix::Link::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-lCompilerRT-Generic");
CmdArgs.push_back("-L/usr/pkg/compiler-rt/lib");
CmdArgs.push_back(
- Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
+ Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
}
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld"));
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
index 5898c66..d647171 100644
--- a/lib/Driver/Tools.h
+++ b/lib/Driver/Tools.h
@@ -13,7 +13,6 @@
#include "clang/Driver/Tool.h"
#include "clang/Driver/Types.h"
#include "clang/Driver/Util.h"
-
#include "llvm/ADT/Triple.h"
#include "llvm/Support/Compiler.h"
@@ -31,7 +30,17 @@ namespace tools {
/// \brief Clang compiler tool.
class LLVM_LIBRARY_VISIBILITY Clang : public Tool {
+ public:
+ static const char *getBaseInputName(const ArgList &Args,
+ const InputInfoList &Inputs);
+ static const char *getBaseInputStem(const ArgList &Args,
+ const InputInfoList &Inputs);
+ static const char *getDependencyFileName(const ArgList &Args,
+ const InputInfoList &Inputs);
+
+ private:
void AddPreprocessingOptions(Compilation &C,
+ const JobAction &JA,
const Driver &D,
const ArgList &Args,
ArgStringList &CmdArgs,
@@ -42,6 +51,7 @@ namespace tools {
bool KernelOrKext) const;
void AddMIPSTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
void AddPPCTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
+ void AddR600TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
void AddSparcTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
void AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
void AddHexagonTargetArgs (const ArgList &Args, ArgStringList &CmdArgs) const;
@@ -68,6 +78,7 @@ namespace tools {
/// \brief Clang integrated assembler tool.
class LLVM_LIBRARY_VISIBILITY ClangAs : public Tool {
void AddARMTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
+ void AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
public:
ClangAs(const ToolChain &TC) : Tool("clang::as",
"clang integrated assembler", TC) {}
@@ -218,63 +229,6 @@ namespace darwin {
const ToolChain &TC) : Tool(Name, ShortName, TC) {}
};
- class LLVM_LIBRARY_VISIBILITY CC1 : public DarwinTool {
- virtual void anchor();
- public:
- static const char *getBaseInputName(const ArgList &Args,
- const InputInfoList &Input);
- static const char *getBaseInputStem(const ArgList &Args,
- const InputInfoList &Input);
- static const char *getDependencyFileName(const ArgList &Args,
- const InputInfoList &Inputs);
-
- protected:
- const char *getCC1Name(types::ID Type) const;
-
- void AddCC1Args(const ArgList &Args, ArgStringList &CmdArgs) const;
- void RemoveCC1UnsupportedArgs(ArgStringList &CmdArgs) const;
- void AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs,
- const InputInfoList &Inputs,
- const ArgStringList &OutputArgs) const;
- void AddCPPOptionsArgs(const ArgList &Args, ArgStringList &CmdArgs,
- const InputInfoList &Inputs,
- const ArgStringList &OutputArgs) const;
- void AddCPPUniqueOptionsArgs(const ArgList &Args,
- ArgStringList &CmdArgs,
- const InputInfoList &Inputs) const;
- void AddCPPArgs(const ArgList &Args, ArgStringList &CmdArgs) const;
-
- public:
- CC1(const char *Name, const char *ShortName,
- const ToolChain &TC) : DarwinTool(Name, ShortName, TC) {}
-
- virtual bool hasGoodDiagnostics() const { return true; }
- virtual bool hasIntegratedCPP() const { return true; }
- };
-
- class LLVM_LIBRARY_VISIBILITY Preprocess : public CC1 {
- public:
- Preprocess(const ToolChain &TC) : CC1("darwin::Preprocess",
- "gcc preprocessor", TC) {}
-
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &TCArgs,
- const char *LinkingOutput) const;
- };
-
- class LLVM_LIBRARY_VISIBILITY Compile : public CC1 {
- public:
- Compile(const ToolChain &TC) : CC1("darwin::Compile", "gcc frontend", TC) {}
-
- virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &TCArgs,
- const char *LinkingOutput) const;
- };
-
class LLVM_LIBRARY_VISIBILITY Assemble : public DarwinTool {
public:
Assemble(const ToolChain &TC) : DarwinTool("darwin::Assemble",
@@ -326,6 +280,7 @@ namespace darwin {
"dsymutil", TC) {}
virtual bool hasIntegratedCPP() const { return false; }
+ virtual bool isDsymutilJob() const { return true; }
virtual void ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
@@ -337,15 +292,15 @@ namespace darwin {
class LLVM_LIBRARY_VISIBILITY VerifyDebug : public DarwinTool {
public:
VerifyDebug(const ToolChain &TC) : DarwinTool("darwin::VerifyDebug",
- "dwarfdump", TC) {}
+ "dwarfdump", TC) {}
virtual bool hasIntegratedCPP() const { return false; }
virtual void ConstructJob(Compilation &C, const JobAction &JA,
- const InputInfo &Output,
- const InputInfoList &Inputs,
- const ArgList &TCArgs,
- const char *LinkingOutput) const;
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
+ const char *LinkingOutput) const;
};
}
@@ -473,12 +428,11 @@ namespace netbsd {
};
} // end namespace netbsd
- /// linux -- Directly call GNU Binutils assembler and linker
-namespace linuxtools {
+ /// Directly call GNU Binutils' assembler and linker.
+namespace gnutools {
class LLVM_LIBRARY_VISIBILITY Assemble : public Tool {
public:
- Assemble(const ToolChain &TC) : Tool("linux::Assemble", "assembler",
- TC) {}
+ Assemble(const ToolChain &TC) : Tool("GNU::Assemble", "assembler", TC) {}
virtual bool hasIntegratedCPP() const { return false; }
@@ -490,7 +444,7 @@ namespace linuxtools {
};
class LLVM_LIBRARY_VISIBILITY Link : public Tool {
public:
- Link(const ToolChain &TC) : Tool("linux::Link", "linker", TC) {}
+ Link(const ToolChain &TC) : Tool("GNU::Link", "linker", TC) {}
virtual bool hasIntegratedCPP() const { return false; }
virtual bool isLinkJob() const { return true; }
diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp
index 862025e..7d22596 100644
--- a/lib/Driver/Types.cpp
+++ b/lib/Driver/Types.cpp
@@ -8,10 +8,9 @@
//===----------------------------------------------------------------------===//
#include "clang/Driver/Types.h"
-
#include "llvm/ADT/StringSwitch.h"
-#include <string.h>
#include <cassert>
+#include <string.h>
using namespace clang::driver;
using namespace clang::driver::types;
@@ -88,7 +87,7 @@ bool types::isAcceptedByClang(ID Id) {
case TY_ObjCHeader: case TY_PP_ObjCHeader:
case TY_CXXHeader: case TY_PP_CXXHeader:
case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader:
- case TY_AST:
+ case TY_AST: case TY_ModuleFile:
case TY_LLVM_IR: case TY_LLVM_BC:
return true;
}
@@ -113,7 +112,7 @@ bool types::isCXX(ID Id) {
return false;
case TY_CXX: case TY_PP_CXX:
- case TY_ObjCXX: case TY_PP_ObjCXX:
+ case TY_ObjCXX: case TY_PP_ObjCXX: case TY_PP_ObjCXX_Alias:
case TY_CXXHeader: case TY_PP_CXXHeader:
case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader:
case TY_CUDA:
@@ -165,16 +164,15 @@ types::ID types::lookupTypeForExtension(const char *Ext) {
.Case("F90", TY_Fortran)
.Case("F95", TY_Fortran)
.Case("mii", TY_PP_ObjCXX)
+ .Case("pcm", TY_ModuleFile)
.Default(TY_INVALID);
}
types::ID types::lookupTypeForTypeSpecifier(const char *Name) {
- unsigned N = strlen(Name);
-
for (unsigned i=0; i<numTypes; ++i) {
types::ID Id = (types::ID) (i + 1);
if (canTypeBeUserSpecified(Id) &&
- memcmp(Name, getInfo(Id).Name, N + 1) == 0)
+ strcmp(Name, getInfo(Id).Name) == 0)
return Id;
}
@@ -182,54 +180,36 @@ types::ID types::lookupTypeForTypeSpecifier(const char *Name) {
}
// FIXME: Why don't we just put this list in the defs file, eh.
-
-unsigned types::getNumCompilationPhases(ID Id) {
- if (Id == TY_Object)
- return 1;
-
- unsigned N = 0;
- if (getPreprocessedType(Id) != TY_INVALID)
- N += 1;
-
- if (onlyAssembleType(Id))
- return N + 2; // assemble, link
- if (onlyPrecompileType(Id))
- return N + 1; // precompile
-
- return N + 3; // compile, assemble, link
-}
-
-phases::ID types::getCompilationPhase(ID Id, unsigned N) {
- assert(N < getNumCompilationPhases(Id) && "Invalid index.");
-
- if (Id == TY_Object)
- return phases::Link;
-
- if (getPreprocessedType(Id) != TY_INVALID) {
- if (N == 0)
- return phases::Preprocess;
- --N;
+void types::getCompilationPhases(
+ ID Id,
+ llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> &P) {
+ if (Id != TY_Object) {
+ if (getPreprocessedType(Id) != TY_INVALID) {
+ P.push_back(phases::Preprocess);
+ }
+
+ if (onlyPrecompileType(Id)) {
+ P.push_back(phases::Precompile);
+ } else {
+ if (!onlyAssembleType(Id)) {
+ P.push_back(phases::Compile);
+ }
+ P.push_back(phases::Assemble);
+ }
}
-
- if (onlyAssembleType(Id))
- return N == 0 ? phases::Assemble : phases::Link;
-
- if (onlyPrecompileType(Id))
- return phases::Precompile;
-
- if (N == 0)
- return phases::Compile;
- if (N == 1)
- return phases::Assemble;
-
- return phases::Link;
+ if (!onlyPrecompileType(Id)) {
+ P.push_back(phases::Link);
+ }
+ assert(0 < P.size() && "Not enough phases in list");
+ assert(P.size() <= phases::MaxNumberOfPhases && "Too many phases in list");
+ return;
}
ID types::lookupCXXTypeForCType(ID Id) {
switch (Id) {
default:
return Id;
-
+
case types::TY_C:
return types::TY_CXX;
case types::TY_PP_C:
diff --git a/lib/Driver/WindowsToolChain.cpp b/lib/Driver/WindowsToolChain.cpp
index de2d535..dac7e77 100644
--- a/lib/Driver/WindowsToolChain.cpp
+++ b/lib/Driver/WindowsToolChain.cpp
@@ -8,13 +8,14 @@
//===----------------------------------------------------------------------===//
#include "ToolChains.h"
-
+#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/Version.h"
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
+#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
-#include "clang/Basic/Version.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Path.h"
@@ -31,49 +32,20 @@ using namespace clang::driver;
using namespace clang::driver::toolchains;
using namespace clang;
-Windows::Windows(const Driver &D, const llvm::Triple& Triple)
- : ToolChain(D, Triple) {
+Windows::Windows(const Driver &D, const llvm::Triple& Triple,
+ const ArgList &Args)
+ : ToolChain(D, Triple, Args) {
}
-Tool &Windows::SelectTool(const Compilation &C, const JobAction &JA,
- const ActionList &Inputs) const {
- Action::ActionClass Key;
- if (getDriver().ShouldUseClangCompiler(C, JA, getTriple()))
- Key = Action::AnalyzeJobClass;
- else
- Key = JA.getKind();
-
- bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as,
- options::OPT_no_integrated_as,
- IsIntegratedAssemblerDefault());
-
- Tool *&T = Tools[Key];
- if (!T) {
- switch (Key) {
- case Action::InputClass:
- case Action::BindArchClass:
- case Action::LipoJobClass:
- case Action::DsymutilJobClass:
- case Action::VerifyJobClass:
- llvm_unreachable("Invalid tool kind.");
- case Action::PreprocessJobClass:
- case Action::PrecompileJobClass:
- case Action::AnalyzeJobClass:
- case Action::MigrateJobClass:
- case Action::CompileJobClass:
- T = new tools::Clang(*this); break;
- case Action::AssembleJobClass:
- if (!UseIntegratedAs && getTriple().getEnvironment() == llvm::Triple::MachO)
- T = new tools::darwin::Assemble(*this);
- else
- T = new tools::ClangAs(*this);
- break;
- case Action::LinkJobClass:
- T = new tools::visualstudio::Link(*this); break;
- }
- }
+Tool *Windows::buildLinker() const {
+ return new tools::visualstudio::Link(*this);
+}
- return *T;
+Tool *Windows::buildAssembler() const {
+ if (getTriple().getEnvironment() == llvm::Triple::MachO)
+ return new tools::darwin::Assemble(*this);
+ getDriver().Diag(clang::diag::err_no_external_windows_assembler);
+ return NULL;
}
bool Windows::IsIntegratedAssemblerDefault() const {
@@ -158,12 +130,12 @@ static bool getSystemRegistryString(const char *keyPath, const char *valueName,
for (index = 0; RegEnumKeyEx(hTopKey, index, keyName, &size, NULL,
NULL, NULL, NULL) == ERROR_SUCCESS; index++) {
const char *sp = keyName;
- while (*sp && !isdigit(*sp))
+ while (*sp && !isDigit(*sp))
sp++;
if (!*sp)
continue;
const char *ep = sp + 1;
- while (*ep && (isdigit(*ep) || (*ep == '.')))
+ while (*ep && (isDigit(*ep) || (*ep == '.')))
ep++;
char numBuf[32];
strncpy(numBuf, sp, sizeof(numBuf) - 1);
diff --git a/lib/Edit/Commit.cpp b/lib/Edit/Commit.cpp
index 41c72e4..0b4ea3e 100644
--- a/lib/Edit/Commit.cpp
+++ b/lib/Edit/Commit.cpp
@@ -8,10 +8,10 @@
//===----------------------------------------------------------------------===//
#include "clang/Edit/Commit.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Edit/EditedSource.h"
#include "clang/Lex/Lexer.h"
-#include "clang/Lex/PreprocessingRecord.h"
-#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/PPConditionalDirectiveRecord.h"
using namespace clang;
using namespace edit;
@@ -37,7 +37,7 @@ CharSourceRange Commit::Edit::getInsertFromRange(SourceManager &SM) const {
Commit::Commit(EditedSource &Editor)
: SourceMgr(Editor.getSourceManager()), LangOpts(Editor.getLangOpts()),
- PPRec(Editor.getPreprocessingRecord()),
+ PPRec(Editor.getPPCondDirectiveRecord()),
Editor(&Editor), IsCommitable(true) { }
bool Commit::insert(SourceLocation loc, StringRef text,
diff --git a/lib/Edit/EditedSource.cpp b/lib/Edit/EditedSource.cpp
index b2a1663..dd99ca9 100644
--- a/lib/Edit/EditedSource.cpp
+++ b/lib/Edit/EditedSource.cpp
@@ -8,10 +8,11 @@
//===----------------------------------------------------------------------===//
#include "clang/Edit/EditedSource.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Edit/Commit.h"
#include "clang/Edit/EditsReceiver.h"
#include "clang/Lex/Lexer.h"
-#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
@@ -23,7 +24,7 @@ void EditsReceiver::remove(CharSourceRange range) {
}
StringRef EditedSource::copyString(const Twine &twine) {
- llvm::SmallString<128> Data;
+ SmallString<128> Data;
return copyString(twine.toStringRef(Data));
}
@@ -88,7 +89,7 @@ bool EditedSource::commitInsertFromRange(SourceLocation OrigLoc,
if (Len == 0)
return true;
- llvm::SmallString<128> StrVec;
+ SmallString<128> StrVec;
FileOffset BeginOffs = InsertFromRangeOffs;
FileOffset EndOffs = BeginOffs.getWithOffset(Len);
FileEditsTy::iterator I = FileEdits.upper_bound(BeginOffs);
@@ -239,13 +240,78 @@ bool EditedSource::commit(const Commit &commit) {
return true;
}
+// \brief Returns true if it is ok to make the two given characters adjacent.
+static bool canBeJoined(char left, char right, const LangOptions &LangOpts) {
+ // FIXME: Should use TokenConcatenation to make sure we don't allow stuff like
+ // making two '<' adjacent.
+ return !(Lexer::isIdentifierBodyChar(left, LangOpts) &&
+ Lexer::isIdentifierBodyChar(right, LangOpts));
+}
+
+/// \brief Returns true if it is ok to eliminate the trailing whitespace between
+/// the given characters.
+static bool canRemoveWhitespace(char left, char beforeWSpace, char right,
+ const LangOptions &LangOpts) {
+ if (!canBeJoined(left, right, LangOpts))
+ return false;
+ if (isWhitespace(left) || isWhitespace(right))
+ return true;
+ if (canBeJoined(beforeWSpace, right, LangOpts))
+ return false; // the whitespace was intentional, keep it.
+ return true;
+}
+
+/// \brief Check the range that we are going to remove and:
+/// -Remove any trailing whitespace if possible.
+/// -Insert a space if removing the range is going to mess up the source tokens.
+static void adjustRemoval(const SourceManager &SM, const LangOptions &LangOpts,
+ SourceLocation Loc, FileOffset offs,
+ unsigned &len, StringRef &text) {
+ assert(len && text.empty());
+ SourceLocation BeginTokLoc = Lexer::GetBeginningOfToken(Loc, SM, LangOpts);
+ if (BeginTokLoc != Loc)
+ return; // the range is not at the beginning of a token, keep the range.
+
+ bool Invalid = false;
+ StringRef buffer = SM.getBufferData(offs.getFID(), &Invalid);
+ if (Invalid)
+ return;
+
+ unsigned begin = offs.getOffset();
+ unsigned end = begin + len;
+
+ // FIXME: Remove newline.
+
+ if (begin == 0) {
+ if (buffer[end] == ' ')
+ ++len;
+ return;
+ }
+
+ if (buffer[end] == ' ') {
+ if (canRemoveWhitespace(/*left=*/buffer[begin-1],
+ /*beforeWSpace=*/buffer[end-1],
+ /*right=*/buffer[end+1],
+ LangOpts))
+ ++len;
+ return;
+ }
+
+ if (!canBeJoined(buffer[begin-1], buffer[end], LangOpts))
+ text = " ";
+}
+
static void applyRewrite(EditsReceiver &receiver,
StringRef text, FileOffset offs, unsigned len,
- const SourceManager &SM) {
+ const SourceManager &SM, const LangOptions &LangOpts) {
assert(!offs.getFID().isInvalid());
SourceLocation Loc = SM.getLocForStartOfFile(offs.getFID());
Loc = Loc.getLocWithOffset(offs.getOffset());
assert(Loc.isFileID());
+
+ if (text.empty())
+ adjustRemoval(SM, LangOpts, Loc, offs, len, text);
+
CharSourceRange range = CharSourceRange::getCharRange(Loc,
Loc.getLocWithOffset(len));
@@ -262,7 +328,7 @@ static void applyRewrite(EditsReceiver &receiver,
}
void EditedSource::applyRewrites(EditsReceiver &receiver) {
- llvm::SmallString<128> StrVec;
+ SmallString<128> StrVec;
FileOffset CurOffs, CurEnd;
unsigned CurLen;
@@ -288,14 +354,14 @@ void EditedSource::applyRewrites(EditsReceiver &receiver) {
continue;
}
- applyRewrite(receiver, StrVec.str(), CurOffs, CurLen, SourceMgr);
+ applyRewrite(receiver, StrVec.str(), CurOffs, CurLen, SourceMgr, LangOpts);
CurOffs = offs;
StrVec = act.Text;
CurLen = act.RemoveLen;
CurEnd = CurOffs.getWithOffset(CurLen);
}
- applyRewrite(receiver, StrVec.str(), CurOffs, CurLen, SourceMgr);
+ applyRewrite(receiver, StrVec.str(), CurOffs, CurLen, SourceMgr, LangOpts);
}
void EditedSource::clearRewrites() {
diff --git a/lib/Edit/RewriteObjCFoundationAPI.cpp b/lib/Edit/RewriteObjCFoundationAPI.cpp
index de96fee..f4206fb 100644
--- a/lib/Edit/RewriteObjCFoundationAPI.cpp
+++ b/lib/Edit/RewriteObjCFoundationAPI.cpp
@@ -12,12 +12,13 @@
//===----------------------------------------------------------------------===//
#include "clang/Edit/Rewriters.h"
-#include "clang/Edit/Commit.h"
-#include "clang/Lex/Lexer.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
#include "clang/AST/NSAPI.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/Edit/Commit.h"
+#include "clang/Lex/Lexer.h"
using namespace clang;
using namespace edit;
@@ -295,9 +296,8 @@ bool edit::rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg,
if (!Method)
return false;
- const ObjCInterfaceDecl *
- IFace = NS.getASTContext().getObjContainingInterface(
- const_cast<ObjCMethodDecl *>(Method));
+ const ObjCInterfaceDecl *IFace =
+ NS.getASTContext().getObjContainingInterface(Method);
if (!IFace)
return false;
Selector Sel = Msg->getSelector();
@@ -325,7 +325,8 @@ bool edit::rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg,
//===----------------------------------------------------------------------===//
static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
- const NSAPI &NS, Commit &commit);
+ const NSAPI &NS, Commit &commit,
+ const ParentMap *PMap);
static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
const NSAPI &NS, Commit &commit);
static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
@@ -336,13 +337,14 @@ static bool rewriteToStringBoxedExpression(const ObjCMessageExpr *Msg,
const NSAPI &NS, Commit &commit);
bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
- const NSAPI &NS, Commit &commit) {
+ const NSAPI &NS, Commit &commit,
+ const ParentMap *PMap) {
IdentifierInfo *II = 0;
if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
return false;
if (II == NS.getNSClassId(NSAPI::ClassId_NSArray))
- return rewriteToArrayLiteral(Msg, NS, commit);
+ return rewriteToArrayLiteral(Msg, NS, commit, PMap);
if (II == NS.getNSClassId(NSAPI::ClassId_NSDictionary))
return rewriteToDictionaryLiteral(Msg, NS, commit);
if (II == NS.getNSClassId(NSAPI::ClassId_NSNumber))
@@ -353,6 +355,19 @@ bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
return false;
}
+/// \brief Returns true if the immediate message arguments of \c Msg should not
+/// be rewritten because it will interfere with the rewrite of the parent
+/// message expression. e.g.
+/// \code
+/// [NSDictionary dictionaryWithObjects:
+/// [NSArray arrayWithObjects:@"1", @"2", nil]
+/// forKeys:[NSArray arrayWithObjects:@"A", @"B", nil]];
+/// \endcode
+/// It will return true for this because we are going to rewrite this directly
+/// to a dictionary literal without any array literals.
+static bool shouldNotRewriteImmediateMessageArgs(const ObjCMessageExpr *Msg,
+ const NSAPI &NS);
+
//===----------------------------------------------------------------------===//
// rewriteToArrayLiteral.
//===----------------------------------------------------------------------===//
@@ -361,7 +376,15 @@ bool edit::rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg,
static void objectifyExpr(const Expr *E, Commit &commit);
static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
- const NSAPI &NS, Commit &commit) {
+ const NSAPI &NS, Commit &commit,
+ const ParentMap *PMap) {
+ if (PMap) {
+ const ObjCMessageExpr *ParentMsg =
+ dyn_cast_or_null<ObjCMessageExpr>(PMap->getParentIgnoreParenCasts(Msg));
+ if (shouldNotRewriteImmediateMessageArgs(ParentMsg, NS))
+ return false;
+ }
+
Selector Sel = Msg->getSelector();
SourceRange MsgRange = Msg->getSourceRange();
@@ -411,6 +434,59 @@ static bool rewriteToArrayLiteral(const ObjCMessageExpr *Msg,
// rewriteToDictionaryLiteral.
//===----------------------------------------------------------------------===//
+/// \brief If \c Msg is an NSArray creation message or literal, this gets the
+/// objects that were used to create it.
+/// \returns true if it is an NSArray and we got objects, or false otherwise.
+static bool getNSArrayObjects(const Expr *E, const NSAPI &NS,
+ SmallVectorImpl<const Expr *> &Objs) {
+ if (!E)
+ return false;
+
+ E = E->IgnoreParenCasts();
+ if (!E)
+ return false;
+
+ if (const ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E)) {
+ IdentifierInfo *Cls = 0;
+ if (!checkForLiteralCreation(Msg, Cls, NS.getASTContext().getLangOpts()))
+ return false;
+
+ if (Cls != NS.getNSClassId(NSAPI::ClassId_NSArray))
+ return false;
+
+ Selector Sel = Msg->getSelector();
+ if (Sel == NS.getNSArraySelector(NSAPI::NSArr_array))
+ return true; // empty array.
+
+ if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObject)) {
+ if (Msg->getNumArgs() != 1)
+ return false;
+ Objs.push_back(Msg->getArg(0));
+ return true;
+ }
+
+ if (Sel == NS.getNSArraySelector(NSAPI::NSArr_arrayWithObjects) ||
+ Sel == NS.getNSArraySelector(NSAPI::NSArr_initWithObjects)) {
+ if (Msg->getNumArgs() == 0)
+ return false;
+ const Expr *SentinelExpr = Msg->getArg(Msg->getNumArgs() - 1);
+ if (!NS.getASTContext().isSentinelNullExpr(SentinelExpr))
+ return false;
+
+ for (unsigned i = 0, e = Msg->getNumArgs() - 1; i != e; ++i)
+ Objs.push_back(Msg->getArg(i));
+ return true;
+ }
+
+ } else if (const ObjCArrayLiteral *ArrLit = dyn_cast<ObjCArrayLiteral>(E)) {
+ for (unsigned i = 0, e = ArrLit->getNumElements(); i != e; ++i)
+ Objs.push_back(ArrLit->getElement(i));
+ return true;
+ }
+
+ return false;
+}
+
static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
const NSAPI &NS, Commit &commit) {
Selector Sel = Msg->getSelector();
@@ -481,6 +557,83 @@ static bool rewriteToDictionaryLiteral(const ObjCMessageExpr *Msg,
return true;
}
+ if (Sel == NS.getNSDictionarySelector(
+ NSAPI::NSDict_dictionaryWithObjectsForKeys) ||
+ Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsForKeys)) {
+ if (Msg->getNumArgs() != 2)
+ return false;
+
+ SmallVector<const Expr *, 8> Vals;
+ if (!getNSArrayObjects(Msg->getArg(0), NS, Vals))
+ return false;
+
+ SmallVector<const Expr *, 8> Keys;
+ if (!getNSArrayObjects(Msg->getArg(1), NS, Keys))
+ return false;
+
+ if (Vals.size() != Keys.size())
+ return false;
+
+ if (Vals.empty()) {
+ commit.replace(MsgRange, "@{}");
+ return true;
+ }
+
+ for (unsigned i = 0, n = Vals.size(); i < n; ++i) {
+ objectifyExpr(Vals[i], commit);
+ objectifyExpr(Keys[i], commit);
+
+ SourceRange ValRange = Vals[i]->getSourceRange();
+ SourceRange KeyRange = Keys[i]->getSourceRange();
+ // Insert value after key.
+ commit.insertAfterToken(KeyRange.getEnd(), ": ");
+ commit.insertFromRange(KeyRange.getEnd(), ValRange, /*afterToken=*/true);
+ }
+ // Range of arguments up until and including the last key.
+ // The first value is cut off, the value will move after the key.
+ SourceRange ArgRange(Keys.front()->getLocStart(),
+ Keys.back()->getLocEnd());
+ commit.insertWrap("@{", ArgRange, "}");
+ commit.replaceWithInner(MsgRange, ArgRange);
+ return true;
+ }
+
+ return false;
+}
+
+static bool shouldNotRewriteImmediateMessageArgs(const ObjCMessageExpr *Msg,
+ const NSAPI &NS) {
+ if (!Msg)
+ return false;
+
+ IdentifierInfo *II = 0;
+ if (!checkForLiteralCreation(Msg, II, NS.getASTContext().getLangOpts()))
+ return false;
+
+ if (II != NS.getNSClassId(NSAPI::ClassId_NSDictionary))
+ return false;
+
+ Selector Sel = Msg->getSelector();
+ if (Sel == NS.getNSDictionarySelector(
+ NSAPI::NSDict_dictionaryWithObjectsForKeys) ||
+ Sel == NS.getNSDictionarySelector(NSAPI::NSDict_initWithObjectsForKeys)) {
+ if (Msg->getNumArgs() != 2)
+ return false;
+
+ SmallVector<const Expr *, 8> Vals;
+ if (!getNSArrayObjects(Msg->getArg(0), NS, Vals))
+ return false;
+
+ SmallVector<const Expr *, 8> Keys;
+ if (!getNSArrayObjects(Msg->getArg(1), NS, Keys))
+ return false;
+
+ if (Vals.size() != Keys.size())
+ return false;
+
+ return true;
+ }
+
return false;
}
@@ -540,7 +693,7 @@ static bool getLiteralInfo(SourceRange literalRange,
if (text.empty())
return false;
- llvm::Optional<bool> UpperU, UpperL;
+ Optional<bool> UpperU, UpperL;
bool UpperF = false;
struct Suff {
@@ -624,7 +777,7 @@ static bool rewriteToNumberLiteral(const ObjCMessageExpr *Msg,
ASTContext &Ctx = NS.getASTContext();
Selector Sel = Msg->getSelector();
- llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
+ Optional<NSAPI::NSNumberLiteralMethodKind>
MKOpt = NS.getNSNumberLiteralMethodKind(Sel);
if (!MKOpt)
return false;
@@ -828,7 +981,7 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
ASTContext &Ctx = NS.getASTContext();
Selector Sel = Msg->getSelector();
- llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
+ Optional<NSAPI::NSNumberLiteralMethodKind>
MKOpt = NS.getNSNumberLiteralMethodKind(Sel);
if (!MKOpt)
return false;
@@ -921,6 +1074,7 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg,
case CK_NonAtomicToAtomic:
case CK_CopyAndAutoreleaseBlockObject:
case CK_BuiltinFnToFnPtr:
+ case CK_ZeroToOCLEvent:
return false;
}
}
diff --git a/lib/Format/CMakeLists.txt b/lib/Format/CMakeLists.txt
new file mode 100644
index 0000000..d8630ee
--- /dev/null
+++ b/lib/Format/CMakeLists.txt
@@ -0,0 +1,26 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangFormat
+ TokenAnnotator.cpp
+ UnwrappedLineParser.cpp
+ Format.cpp
+ )
+
+add_dependencies(clangFormat
+ ClangAttrClasses
+ ClangAttrList
+ ClangDeclNodes
+ ClangDiagnosticCommon
+ ClangDiagnosticFrontend
+ ClangStmtNodes
+ )
+
+target_link_libraries(clangFormat
+ clangBasic
+ clangFrontend
+ clangAST
+ clangASTMatchers
+ clangRewriteCore
+ clangRewriteFrontend
+ clangTooling
+ )
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
new file mode 100644
index 0000000..101b16f
--- /dev/null
+++ b/lib/Format/Format.cpp
@@ -0,0 +1,1763 @@
+//===--- Format.cpp - Format C++ code -------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements functions declared in Format.h. This will be
+/// split into separate files as we go.
+///
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "format-formatter"
+
+#include "TokenAnnotator.h"
+#include "UnwrappedLineParser.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/OperatorPrecedence.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Format/Format.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Debug.h"
+#include <queue>
+#include <string>
+
+namespace clang {
+namespace format {
+
+FormatStyle getLLVMStyle() {
+ FormatStyle LLVMStyle;
+ LLVMStyle.ColumnLimit = 80;
+ LLVMStyle.MaxEmptyLinesToKeep = 1;
+ LLVMStyle.PointerBindsToType = false;
+ LLVMStyle.DerivePointerBinding = false;
+ LLVMStyle.AccessModifierOffset = -2;
+ LLVMStyle.Standard = FormatStyle::LS_Cpp03;
+ LLVMStyle.IndentCaseLabels = false;
+ LLVMStyle.SpacesBeforeTrailingComments = 1;
+ LLVMStyle.BinPackParameters = true;
+ LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true;
+ LLVMStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = false;
+ LLVMStyle.AllowShortIfStatementsOnASingleLine = false;
+ LLVMStyle.ObjCSpaceBeforeProtocolList = true;
+ LLVMStyle.PenaltyExcessCharacter = 1000000;
+ LLVMStyle.PenaltyReturnTypeOnItsOwnLine = 5;
+ return LLVMStyle;
+}
+
+FormatStyle getGoogleStyle() {
+ FormatStyle GoogleStyle;
+ GoogleStyle.ColumnLimit = 80;
+ GoogleStyle.MaxEmptyLinesToKeep = 1;
+ GoogleStyle.PointerBindsToType = true;
+ GoogleStyle.DerivePointerBinding = true;
+ GoogleStyle.AccessModifierOffset = -1;
+ GoogleStyle.Standard = FormatStyle::LS_Auto;
+ GoogleStyle.IndentCaseLabels = true;
+ GoogleStyle.SpacesBeforeTrailingComments = 2;
+ GoogleStyle.BinPackParameters = true;
+ GoogleStyle.AllowAllParametersOfDeclarationOnNextLine = true;
+ GoogleStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = true;
+ GoogleStyle.AllowShortIfStatementsOnASingleLine = false;
+ GoogleStyle.ObjCSpaceBeforeProtocolList = false;
+ GoogleStyle.PenaltyExcessCharacter = 1000000;
+ GoogleStyle.PenaltyReturnTypeOnItsOwnLine = 100;
+ return GoogleStyle;
+}
+
+FormatStyle getChromiumStyle() {
+ FormatStyle ChromiumStyle = getGoogleStyle();
+ ChromiumStyle.AllowAllParametersOfDeclarationOnNextLine = false;
+ ChromiumStyle.BinPackParameters = false;
+ ChromiumStyle.Standard = FormatStyle::LS_Cpp03;
+ ChromiumStyle.DerivePointerBinding = false;
+ return ChromiumStyle;
+}
+
+static bool isTrailingComment(const AnnotatedToken &Tok) {
+ return Tok.is(tok::comment) &&
+ (Tok.Children.empty() || Tok.Children[0].MustBreakBefore);
+}
+
+static bool isComparison(const AnnotatedToken &Tok) {
+ prec::Level Precedence = getPrecedence(Tok);
+ return Tok.Type == TT_BinaryOperator &&
+ (Precedence == prec::Equality || Precedence == prec::Relational);
+}
+
+// Returns the length of everything up to the first possible line break after
+// the ), ], } or > matching \c Tok.
+static unsigned getLengthToMatchingParen(const AnnotatedToken &Tok) {
+ if (Tok.MatchingParen == NULL)
+ return 0;
+ AnnotatedToken *End = Tok.MatchingParen;
+ while (!End->Children.empty() && !End->Children[0].CanBreakBefore) {
+ End = &End->Children[0];
+ }
+ return End->TotalLength - Tok.TotalLength + 1;
+}
+
+static size_t
+calculateColumnLimit(const FormatStyle &Style, bool InPPDirective) {
+ // In preprocessor directives reserve two chars for trailing " \"
+ return Style.ColumnLimit - (InPPDirective ? 2 : 0);
+}
+
+/// \brief Manages the whitespaces around tokens and their replacements.
+///
+/// This includes special handling for certain constructs, e.g. the alignment of
+/// trailing line comments.
+class WhitespaceManager {
+public:
+ WhitespaceManager(SourceManager &SourceMgr, const FormatStyle &Style)
+ : SourceMgr(SourceMgr), Style(Style) {}
+
+ /// \brief Replaces the whitespace in front of \p Tok. Only call once for
+ /// each \c AnnotatedToken.
+ void replaceWhitespace(const AnnotatedToken &Tok, unsigned NewLines,
+ unsigned Spaces, unsigned WhitespaceStartColumn) {
+ // 2+ newlines mean an empty line separating logic scopes.
+ if (NewLines >= 2)
+ alignComments();
+
+ SourceLocation TokenLoc = Tok.FormatTok.Tok.getLocation();
+ bool LineExceedsColumnLimit = Spaces + WhitespaceStartColumn +
+ Tok.FormatTok.TokenLength > Style.ColumnLimit;
+
+ // Align line comments if they are trailing or if they continue other
+ // trailing comments.
+ if (isTrailingComment(Tok)) {
+ // Remove the comment's trailing whitespace.
+ if (Tok.FormatTok.Tok.getLength() != Tok.FormatTok.TokenLength)
+ Replaces.insert(tooling::Replacement(
+ SourceMgr, TokenLoc.getLocWithOffset(Tok.FormatTok.TokenLength),
+ Tok.FormatTok.Tok.getLength() - Tok.FormatTok.TokenLength, ""));
+
+ // Align comment with other comments.
+ if ((Tok.Parent != NULL || !Comments.empty()) &&
+ !LineExceedsColumnLimit) {
+ StoredComment Comment;
+ Comment.Tok = Tok.FormatTok;
+ Comment.Spaces = Spaces;
+ Comment.NewLines = NewLines;
+ Comment.MinColumn =
+ NewLines > 0 ? Spaces : WhitespaceStartColumn + Spaces;
+ Comment.MaxColumn = Style.ColumnLimit - Tok.FormatTok.TokenLength;
+ Comment.Untouchable = false;
+ Comments.push_back(Comment);
+ return;
+ }
+ }
+
+ // If this line does not have a trailing comment, align the stored comments.
+ if (Tok.Children.empty() && !isTrailingComment(Tok))
+ alignComments();
+
+ if (Tok.Type == TT_BlockComment) {
+ indentBlockComment(Tok, Spaces, WhitespaceStartColumn, NewLines, false);
+ } else if (Tok.Type == TT_LineComment && LineExceedsColumnLimit) {
+ StringRef Line(SourceMgr.getCharacterData(TokenLoc),
+ Tok.FormatTok.TokenLength);
+ int StartColumn = Spaces + (NewLines == 0 ? WhitespaceStartColumn : 0);
+ StringRef Prefix = getLineCommentPrefix(Line);
+ std::string NewPrefix = std::string(StartColumn, ' ') + Prefix.str();
+ splitLineInComment(Tok.FormatTok, Line.substr(Prefix.size()),
+ StartColumn + Prefix.size(), NewPrefix,
+ /*InPPDirective=*/ false,
+ /*CommentHasMoreLines=*/ false);
+ }
+
+ storeReplacement(Tok.FormatTok, getNewLineText(NewLines, Spaces));
+ }
+
+ /// \brief Like \c replaceWhitespace, but additionally adds right-aligned
+ /// backslashes to escape newlines inside a preprocessor directive.
+ ///
+ /// This function and \c replaceWhitespace have the same behavior if
+ /// \c Newlines == 0.
+ void replacePPWhitespace(const AnnotatedToken &Tok, unsigned NewLines,
+ unsigned Spaces, unsigned WhitespaceStartColumn) {
+ if (Tok.Type == TT_BlockComment)
+ indentBlockComment(Tok, Spaces, WhitespaceStartColumn, NewLines, true);
+
+ storeReplacement(Tok.FormatTok,
+ getNewLineText(NewLines, Spaces, WhitespaceStartColumn));
+ }
+
+ /// \brief Inserts a line break into the middle of a token.
+ ///
+ /// Will break at \p Offset inside \p Tok, putting \p Prefix before the line
+ /// break and \p Postfix before the rest of the token starts in the next line.
+ ///
+ /// \p InPPDirective, \p Spaces, \p WhitespaceStartColumn and \p Style are
+ /// used to generate the correct line break.
+ void breakToken(const FormatToken &Tok, unsigned Offset,
+ unsigned ReplaceChars, StringRef Prefix, StringRef Postfix,
+ bool InPPDirective, unsigned Spaces,
+ unsigned WhitespaceStartColumn) {
+ std::string NewLineText;
+ if (!InPPDirective)
+ NewLineText = getNewLineText(1, Spaces);
+ else
+ NewLineText = getNewLineText(1, Spaces, WhitespaceStartColumn);
+ std::string ReplacementText = (Prefix + NewLineText + Postfix).str();
+ SourceLocation Location = Tok.Tok.getLocation().getLocWithOffset(Offset);
+ Replaces.insert(tooling::Replacement(SourceMgr, Location, ReplaceChars,
+ ReplacementText));
+ }
+
+ /// \brief Returns all the \c Replacements created during formatting.
+ const tooling::Replacements &generateReplacements() {
+ alignComments();
+ return Replaces;
+ }
+
+ void addUntouchableComment(unsigned Column) {
+ StoredComment Comment;
+ Comment.MinColumn = Column;
+ Comment.MaxColumn = Column;
+ Comment.Untouchable = true;
+ Comments.push_back(Comment);
+ }
+
+private:
+ static StringRef getLineCommentPrefix(StringRef Comment) {
+ const char *KnownPrefixes[] = { "/// ", "///", "// ", "//" };
+ for (size_t i = 0; i < llvm::array_lengthof(KnownPrefixes); ++i)
+ if (Comment.startswith(KnownPrefixes[i]))
+ return KnownPrefixes[i];
+ return "";
+ }
+
+ /// \brief Finds a common prefix of lines of a block comment to properly
+ /// indent (and possibly decorate with '*'s) added lines.
+ ///
+ /// The first line is ignored (it's special and starts with /*). The number of
+ /// lines should be more than one.
+ static StringRef findCommentLinesPrefix(ArrayRef<StringRef> Lines,
+ const char *PrefixChars = " *") {
+ assert(Lines.size() > 1);
+ StringRef Prefix(Lines[1].data(), Lines[1].find_first_not_of(PrefixChars));
+ for (size_t i = 2; i < Lines.size(); ++i) {
+ for (size_t j = 0; j < Prefix.size() && j < Lines[i].size(); ++j) {
+ if (Prefix[j] != Lines[i][j]) {
+ Prefix = Prefix.substr(0, j);
+ break;
+ }
+ }
+ }
+ return Prefix;
+ }
+
+ /// \brief Splits one line in a line or block comment, if it doesn't fit to
+ /// provided column limit. Removes trailing whitespace in each line.
+ ///
+ /// \param Line points to the line contents without leading // or /*.
+ ///
+ /// \param StartColumn is the column where the first character of Line will be
+ /// located after formatting.
+ ///
+ /// \param LinePrefix is inserted after each line break.
+ ///
+ /// When \param InPPDirective is true, each line break will be preceded by a
+ /// backslash in the last column to make line breaks inside the comment
+ /// visually consistent with line breaks outside the comment. This only makes
+ /// sense for block comments.
+ ///
+ /// When \param CommentHasMoreLines is false, no line breaks/trailing
+ /// backslashes will be inserted after it.
+ void splitLineInComment(const FormatToken &Tok, StringRef Line,
+ size_t StartColumn, StringRef LinePrefix,
+ bool InPPDirective, bool CommentHasMoreLines,
+ const char *WhiteSpaceChars = " ") {
+ size_t ColumnLimit = calculateColumnLimit(Style, InPPDirective);
+ const char *TokenStart = SourceMgr.getCharacterData(Tok.Tok.getLocation());
+
+ StringRef TrimmedLine = Line.rtrim();
+ int TrailingSpaceLength = Line.size() - TrimmedLine.size();
+
+ // Don't touch leading whitespace.
+ Line = TrimmedLine.ltrim();
+ StartColumn += TrimmedLine.size() - Line.size();
+
+ while (Line.size() + StartColumn > ColumnLimit) {
+ // Try to break at the last whitespace before the column limit.
+ size_t SpacePos =
+ Line.find_last_of(WhiteSpaceChars, ColumnLimit - StartColumn + 1);
+ if (SpacePos == StringRef::npos) {
+ // Try to find any whitespace in the line.
+ SpacePos = Line.find_first_of(WhiteSpaceChars);
+ if (SpacePos == StringRef::npos) // No whitespace found, give up.
+ break;
+ }
+
+ StringRef NextCut = Line.substr(0, SpacePos).rtrim();
+ StringRef RemainingLine = Line.substr(SpacePos).ltrim();
+ if (RemainingLine.empty())
+ break;
+
+ if (RemainingLine == "*/" && LinePrefix.endswith("* "))
+ LinePrefix = LinePrefix.substr(0, LinePrefix.size() - 2);
+
+ Line = RemainingLine;
+
+ size_t ReplaceChars = Line.begin() - NextCut.end();
+ breakToken(Tok, NextCut.end() - TokenStart, ReplaceChars, "", LinePrefix,
+ InPPDirective, 0, NextCut.size() + StartColumn);
+ StartColumn = LinePrefix.size();
+ }
+
+ if (TrailingSpaceLength > 0 || (InPPDirective && CommentHasMoreLines)) {
+ // Remove trailing whitespace/insert backslash. + 1 is for \n
+ breakToken(Tok, Line.end() - TokenStart, TrailingSpaceLength + 1, "", "",
+ InPPDirective, 0, Line.size() + StartColumn);
+ }
+ }
+
+ /// \brief Changes indentation of all lines in a block comment by Indent,
+ /// removes trailing whitespace from each line, splits lines that end up
+ /// exceeding the column limit.
+ void indentBlockComment(const AnnotatedToken &Tok, int Indent,
+ int WhitespaceStartColumn, int NewLines,
+ bool InPPDirective) {
+ assert(Tok.Type == TT_BlockComment);
+ int StartColumn = Indent + (NewLines == 0 ? WhitespaceStartColumn : 0);
+ const SourceLocation TokenLoc = Tok.FormatTok.Tok.getLocation();
+ const int CurrentIndent = SourceMgr.getSpellingColumnNumber(TokenLoc) - 1;
+ const int IndentDelta = Indent - CurrentIndent;
+ const StringRef Text(SourceMgr.getCharacterData(TokenLoc),
+ Tok.FormatTok.TokenLength);
+ assert(Text.startswith("/*") && Text.endswith("*/"));
+
+ SmallVector<StringRef, 16> Lines;
+ Text.split(Lines, "\n");
+
+ if (IndentDelta > 0) {
+ std::string WhiteSpace(IndentDelta, ' ');
+ for (size_t i = 1; i < Lines.size(); ++i) {
+ Replaces.insert(tooling::Replacement(
+ SourceMgr, TokenLoc.getLocWithOffset(Lines[i].data() - Text.data()),
+ 0, WhiteSpace));
+ }
+ } else if (IndentDelta < 0) {
+ std::string WhiteSpace(-IndentDelta, ' ');
+ // Check that the line is indented enough.
+ for (size_t i = 1; i < Lines.size(); ++i) {
+ if (!Lines[i].startswith(WhiteSpace))
+ return;
+ }
+ for (size_t i = 1; i < Lines.size(); ++i) {
+ Replaces.insert(tooling::Replacement(
+ SourceMgr, TokenLoc.getLocWithOffset(Lines[i].data() - Text.data()),
+ -IndentDelta, ""));
+ }
+ }
+
+ // Split long lines in comments.
+ size_t OldPrefixSize = 0;
+ std::string NewPrefix;
+ if (Lines.size() > 1) {
+ StringRef CurrentPrefix = findCommentLinesPrefix(Lines);
+ OldPrefixSize = CurrentPrefix.size();
+ NewPrefix = (IndentDelta < 0)
+ ? CurrentPrefix.substr(-IndentDelta).str()
+ : std::string(IndentDelta, ' ') + CurrentPrefix.str();
+ if (CurrentPrefix.endswith("*")) {
+ NewPrefix += " ";
+ ++OldPrefixSize;
+ }
+ } else if (Tok.Parent == 0) {
+ NewPrefix = std::string(StartColumn, ' ') + " * ";
+ }
+
+ StartColumn += 2;
+ for (size_t i = 0; i < Lines.size(); ++i) {
+ StringRef Line = Lines[i].substr(i == 0 ? 2 : OldPrefixSize);
+ splitLineInComment(Tok.FormatTok, Line, StartColumn, NewPrefix,
+ InPPDirective, i != Lines.size() - 1);
+ StartColumn = NewPrefix.size();
+ }
+ }
+
+ std::string getNewLineText(unsigned NewLines, unsigned Spaces) {
+ return std::string(NewLines, '\n') + std::string(Spaces, ' ');
+ }
+
+ std::string getNewLineText(unsigned NewLines, unsigned Spaces,
+ unsigned WhitespaceStartColumn) {
+ std::string NewLineText;
+ if (NewLines > 0) {
+ unsigned Offset =
+ std::min<int>(Style.ColumnLimit - 1, WhitespaceStartColumn);
+ for (unsigned i = 0; i < NewLines; ++i) {
+ NewLineText += std::string(Style.ColumnLimit - Offset - 1, ' ');
+ NewLineText += "\\\n";
+ Offset = 0;
+ }
+ }
+ return NewLineText + std::string(Spaces, ' ');
+ }
+
+ /// \brief Structure to store a comment for later layout and alignment.
+ struct StoredComment {
+ FormatToken Tok;
+ unsigned MinColumn;
+ unsigned MaxColumn;
+ unsigned NewLines;
+ unsigned Spaces;
+ bool Untouchable;
+ };
+ SmallVector<StoredComment, 16> Comments;
+ typedef SmallVector<StoredComment, 16>::iterator comment_iterator;
+
+ /// \brief Try to align all stashed comments.
+ void alignComments() {
+ unsigned MinColumn = 0;
+ unsigned MaxColumn = UINT_MAX;
+ comment_iterator Start = Comments.begin();
+ for (comment_iterator I = Start, E = Comments.end(); I != E; ++I) {
+ if (I->MinColumn > MaxColumn || I->MaxColumn < MinColumn) {
+ alignComments(Start, I, MinColumn);
+ MinColumn = I->MinColumn;
+ MaxColumn = I->MaxColumn;
+ Start = I;
+ } else {
+ MinColumn = std::max(MinColumn, I->MinColumn);
+ MaxColumn = std::min(MaxColumn, I->MaxColumn);
+ }
+ }
+ alignComments(Start, Comments.end(), MinColumn);
+ Comments.clear();
+ }
+
+ /// \brief Put all the comments between \p I and \p E into \p Column.
+ void alignComments(comment_iterator I, comment_iterator E, unsigned Column) {
+ while (I != E) {
+ if (!I->Untouchable) {
+ unsigned Spaces = I->Spaces + Column - I->MinColumn;
+ storeReplacement(I->Tok, getNewLineText(I->NewLines, Spaces));
+ }
+ ++I;
+ }
+ }
+
+ /// \brief Stores \p Text as the replacement for the whitespace in front of
+ /// \p Tok.
+ void storeReplacement(const FormatToken &Tok, const std::string Text) {
+ // Don't create a replacement, if it does not change anything.
+ if (StringRef(SourceMgr.getCharacterData(Tok.WhiteSpaceStart),
+ Tok.WhiteSpaceLength) == Text)
+ return;
+
+ Replaces.insert(tooling::Replacement(SourceMgr, Tok.WhiteSpaceStart,
+ Tok.WhiteSpaceLength, Text));
+ }
+
+ SourceManager &SourceMgr;
+ tooling::Replacements Replaces;
+ const FormatStyle &Style;
+};
+
+class UnwrappedLineFormatter {
+public:
+ UnwrappedLineFormatter(const FormatStyle &Style, SourceManager &SourceMgr,
+ const AnnotatedLine &Line, unsigned FirstIndent,
+ const AnnotatedToken &RootToken,
+ WhitespaceManager &Whitespaces, bool StructuralError)
+ : Style(Style), SourceMgr(SourceMgr), Line(Line),
+ FirstIndent(FirstIndent), RootToken(RootToken),
+ Whitespaces(Whitespaces), Count(0) {}
+
+ /// \brief Formats an \c UnwrappedLine.
+ ///
+ /// \returns The column after the last token in the last line of the
+ /// \c UnwrappedLine.
+ unsigned format(const AnnotatedLine *NextLine) {
+ // Initialize state dependent on indent.
+ LineState State;
+ State.Column = FirstIndent;
+ State.NextToken = &RootToken;
+ State.Stack.push_back(
+ ParenState(FirstIndent, FirstIndent, !Style.BinPackParameters,
+ /*HasMultiParameterLine=*/ false));
+ State.LineContainsContinuedForLoopSection = false;
+ State.ParenLevel = 0;
+ State.StartOfStringLiteral = 0;
+ State.StartOfLineLevel = State.ParenLevel;
+
+ DEBUG({
+ DebugTokenState(*State.NextToken);
+ });
+
+ // The first token has already been indented and thus consumed.
+ moveStateToNextToken(State, /*DryRun=*/ false);
+
+ // If everything fits on a single line, just put it there.
+ unsigned ColumnLimit = Style.ColumnLimit;
+ if (NextLine && NextLine->InPPDirective &&
+ !NextLine->First.FormatTok.HasUnescapedNewline)
+ ColumnLimit = getColumnLimit();
+ if (Line.Last->TotalLength <= ColumnLimit - FirstIndent) {
+ while (State.NextToken != NULL) {
+ addTokenToState(false, false, State);
+ }
+ return State.Column;
+ }
+
+ // If the ObjC method declaration does not fit on a line, we should format
+ // it with one arg per line.
+ if (Line.Type == LT_ObjCMethodDecl)
+ State.Stack.back().BreakBeforeParameter = true;
+
+ // Find best solution in solution space.
+ return analyzeSolutionSpace(State);
+ }
+
+private:
+ void DebugTokenState(const AnnotatedToken &AnnotatedTok) {
+ const Token &Tok = AnnotatedTok.FormatTok.Tok;
+ llvm::errs() << StringRef(SourceMgr.getCharacterData(Tok.getLocation()),
+ Tok.getLength());
+ llvm::errs();
+ }
+
+ struct ParenState {
+ ParenState(unsigned Indent, unsigned LastSpace, bool AvoidBinPacking,
+ bool HasMultiParameterLine)
+ : Indent(Indent), LastSpace(LastSpace), FirstLessLess(0),
+ BreakBeforeClosingBrace(false), QuestionColumn(0),
+ AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false),
+ HasMultiParameterLine(HasMultiParameterLine), ColonPos(0),
+ StartOfFunctionCall(0), NestedNameSpecifierContinuation(0),
+ CallContinuation(0), VariablePos(0) {}
+
+ /// \brief The position to which a specific parenthesis level needs to be
+ /// indented.
+ unsigned Indent;
+
+ /// \brief The position of the last space on each level.
+ ///
+ /// Used e.g. to break like:
+ /// functionCall(Parameter, otherCall(
+ /// OtherParameter));
+ unsigned LastSpace;
+
+ /// \brief The position the first "<<" operator encountered on each level.
+ ///
+ /// Used to align "<<" operators. 0 if no such operator has been encountered
+ /// on a level.
+ unsigned FirstLessLess;
+
+ /// \brief Whether a newline needs to be inserted before the block's closing
+ /// brace.
+ ///
+ /// We only want to insert a newline before the closing brace if there also
+ /// was a newline after the beginning left brace.
+ bool BreakBeforeClosingBrace;
+
+ /// \brief The column of a \c ? in a conditional expression;
+ unsigned QuestionColumn;
+
+ /// \brief Avoid bin packing, i.e. multiple parameters/elements on multiple
+ /// lines, in this context.
+ bool AvoidBinPacking;
+
+ /// \brief Break after the next comma (or all the commas in this context if
+ /// \c AvoidBinPacking is \c true).
+ bool BreakBeforeParameter;
+
+ /// \brief This context already has a line with more than one parameter.
+ bool HasMultiParameterLine;
+
+ /// \brief The position of the colon in an ObjC method declaration/call.
+ unsigned ColonPos;
+
+ /// \brief The start of the most recent function in a builder-type call.
+ unsigned StartOfFunctionCall;
+
+ /// \brief If a nested name specifier was broken over multiple lines, this
+ /// contains the start column of the second line. Otherwise 0.
+ unsigned NestedNameSpecifierContinuation;
+
+ /// \brief If a call expression was broken over multiple lines, this
+ /// contains the start column of the second line. Otherwise 0.
+ unsigned CallContinuation;
+
+ /// \brief The column of the first variable name in a variable declaration.
+ ///
+ /// Used to align further variables if necessary.
+ unsigned VariablePos;
+
+ bool operator<(const ParenState &Other) const {
+ if (Indent != Other.Indent)
+ return Indent < Other.Indent;
+ if (LastSpace != Other.LastSpace)
+ return LastSpace < Other.LastSpace;
+ if (FirstLessLess != Other.FirstLessLess)
+ return FirstLessLess < Other.FirstLessLess;
+ if (BreakBeforeClosingBrace != Other.BreakBeforeClosingBrace)
+ return BreakBeforeClosingBrace;
+ if (QuestionColumn != Other.QuestionColumn)
+ return QuestionColumn < Other.QuestionColumn;
+ if (AvoidBinPacking != Other.AvoidBinPacking)
+ return AvoidBinPacking;
+ if (BreakBeforeParameter != Other.BreakBeforeParameter)
+ return BreakBeforeParameter;
+ if (HasMultiParameterLine != Other.HasMultiParameterLine)
+ return HasMultiParameterLine;
+ if (ColonPos != Other.ColonPos)
+ return ColonPos < Other.ColonPos;
+ if (StartOfFunctionCall != Other.StartOfFunctionCall)
+ return StartOfFunctionCall < Other.StartOfFunctionCall;
+ if (NestedNameSpecifierContinuation !=
+ Other.NestedNameSpecifierContinuation)
+ return NestedNameSpecifierContinuation <
+ Other.NestedNameSpecifierContinuation;
+ if (CallContinuation != Other.CallContinuation)
+ return CallContinuation < Other.CallContinuation;
+ if (VariablePos != Other.VariablePos)
+ return VariablePos < Other.VariablePos;
+ return false;
+ }
+ };
+
+ /// \brief The current state when indenting a unwrapped line.
+ ///
+ /// As the indenting tries different combinations this is copied by value.
+ struct LineState {
+ /// \brief The number of used columns in the current line.
+ unsigned Column;
+
+ /// \brief The token that needs to be next formatted.
+ const AnnotatedToken *NextToken;
+
+ /// \brief \c true if this line contains a continued for-loop section.
+ bool LineContainsContinuedForLoopSection;
+
+ /// \brief The level of nesting inside (), [], <> and {}.
+ unsigned ParenLevel;
+
+ /// \brief The \c ParenLevel at the start of this line.
+ unsigned StartOfLineLevel;
+
+ /// \brief The start column of the string literal, if we're in a string
+ /// literal sequence, 0 otherwise.
+ unsigned StartOfStringLiteral;
+
+ /// \brief A stack keeping track of properties applying to parenthesis
+ /// levels.
+ std::vector<ParenState> Stack;
+
+ /// \brief Comparison operator to be able to used \c LineState in \c map.
+ bool operator<(const LineState &Other) const {
+ if (NextToken != Other.NextToken)
+ return NextToken < Other.NextToken;
+ if (Column != Other.Column)
+ return Column < Other.Column;
+ if (LineContainsContinuedForLoopSection !=
+ Other.LineContainsContinuedForLoopSection)
+ return LineContainsContinuedForLoopSection;
+ if (ParenLevel != Other.ParenLevel)
+ return ParenLevel < Other.ParenLevel;
+ if (StartOfLineLevel != Other.StartOfLineLevel)
+ return StartOfLineLevel < Other.StartOfLineLevel;
+ if (StartOfStringLiteral != Other.StartOfStringLiteral)
+ return StartOfStringLiteral < Other.StartOfStringLiteral;
+ return Stack < Other.Stack;
+ }
+ };
+
+ /// \brief Appends the next token to \p State and updates information
+ /// necessary for indentation.
+ ///
+ /// Puts the token on the current line if \p Newline is \c true and adds a
+ /// line break and necessary indentation otherwise.
+ ///
+ /// If \p DryRun is \c false, also creates and stores the required
+ /// \c Replacement.
+ unsigned addTokenToState(bool Newline, bool DryRun, LineState &State) {
+ const AnnotatedToken &Current = *State.NextToken;
+ const AnnotatedToken &Previous = *State.NextToken->Parent;
+
+ if (State.Stack.size() == 0 || Current.Type == TT_ImplicitStringLiteral) {
+ State.Column += State.NextToken->FormatTok.WhiteSpaceLength +
+ State.NextToken->FormatTok.TokenLength;
+ if (State.NextToken->Children.empty())
+ State.NextToken = NULL;
+ else
+ State.NextToken = &State.NextToken->Children[0];
+ return 0;
+ }
+
+ // If we are continuing an expression, we want to indent an extra 4 spaces.
+ unsigned ContinuationIndent =
+ std::max(State.Stack.back().LastSpace, State.Stack.back().Indent) + 4;
+ if (Newline) {
+ unsigned WhitespaceStartColumn = State.Column;
+ if (Current.is(tok::r_brace)) {
+ State.Column = Line.Level * 2;
+ } else if (Current.is(tok::string_literal) &&
+ State.StartOfStringLiteral != 0) {
+ State.Column = State.StartOfStringLiteral;
+ State.Stack.back().BreakBeforeParameter = true;
+ } else if (Current.is(tok::lessless) &&
+ State.Stack.back().FirstLessLess != 0) {
+ State.Column = State.Stack.back().FirstLessLess;
+ } else if (Previous.is(tok::coloncolon)) {
+ if (State.Stack.back().NestedNameSpecifierContinuation == 0) {
+ State.Column = ContinuationIndent;
+ State.Stack.back().NestedNameSpecifierContinuation = State.Column;
+ } else {
+ State.Column = State.Stack.back().NestedNameSpecifierContinuation;
+ }
+ } else if (Current.isOneOf(tok::period, tok::arrow)) {
+ if (State.Stack.back().CallContinuation == 0) {
+ State.Column = ContinuationIndent;
+ State.Stack.back().CallContinuation = State.Column;
+ } else {
+ State.Column = State.Stack.back().CallContinuation;
+ }
+ } else if (Current.Type == TT_ConditionalExpr) {
+ State.Column = State.Stack.back().QuestionColumn;
+ } else if (Previous.is(tok::comma) &&
+ State.Stack.back().VariablePos != 0) {
+ State.Column = State.Stack.back().VariablePos;
+ } else if (Previous.ClosesTemplateDeclaration ||
+ (Current.Type == TT_StartOfName && State.ParenLevel == 0)) {
+ State.Column = State.Stack.back().Indent;
+ } else if (Current.Type == TT_ObjCSelectorName) {
+ if (State.Stack.back().ColonPos > Current.FormatTok.TokenLength) {
+ State.Column =
+ State.Stack.back().ColonPos - Current.FormatTok.TokenLength;
+ } else {
+ State.Column = State.Stack.back().Indent;
+ State.Stack.back().ColonPos =
+ State.Column + Current.FormatTok.TokenLength;
+ }
+ } else if (Current.Type == TT_StartOfName || Current.is(tok::question) ||
+ Previous.is(tok::equal) || isComparison(Previous) ||
+ Previous.Type == TT_ObjCMethodExpr) {
+ State.Column = ContinuationIndent;
+ } else {
+ State.Column = State.Stack.back().Indent;
+ // Ensure that we fall back to indenting 4 spaces instead of just
+ // flushing continuations left.
+ if (State.Column == FirstIndent)
+ State.Column += 4;
+ }
+
+ if (Current.is(tok::question))
+ State.Stack.back().BreakBeforeParameter = true;
+ if (Previous.isOneOf(tok::comma, tok::semi) &&
+ !State.Stack.back().AvoidBinPacking)
+ State.Stack.back().BreakBeforeParameter = false;
+
+ if (!DryRun) {
+ unsigned NewLines = 1;
+ if (Current.Type == TT_LineComment)
+ NewLines =
+ std::max(NewLines, std::min(Current.FormatTok.NewlinesBefore,
+ Style.MaxEmptyLinesToKeep + 1));
+ if (!Line.InPPDirective)
+ Whitespaces.replaceWhitespace(Current, NewLines, State.Column,
+ WhitespaceStartColumn);
+ else
+ Whitespaces.replacePPWhitespace(Current, NewLines, State.Column,
+ WhitespaceStartColumn);
+ }
+
+ State.Stack.back().LastSpace = State.Column;
+ State.StartOfLineLevel = State.ParenLevel;
+
+ // Any break on this level means that the parent level has been broken
+ // and we need to avoid bin packing there.
+ for (unsigned i = 0, e = State.Stack.size() - 1; i != e; ++i) {
+ State.Stack[i].BreakBeforeParameter = true;
+ }
+ if (Current.isOneOf(tok::period, tok::arrow))
+ State.Stack.back().BreakBeforeParameter = true;
+
+ // If we break after {, we should also break before the corresponding }.
+ if (Previous.is(tok::l_brace))
+ State.Stack.back().BreakBeforeClosingBrace = true;
+
+ if (State.Stack.back().AvoidBinPacking) {
+ // If we are breaking after '(', '{', '<', this is not bin packing
+ // unless AllowAllParametersOfDeclarationOnNextLine is false.
+ if ((Previous.isNot(tok::l_paren) && Previous.isNot(tok::l_brace)) ||
+ (!Style.AllowAllParametersOfDeclarationOnNextLine &&
+ Line.MustBeDeclaration))
+ State.Stack.back().BreakBeforeParameter = true;
+ }
+ } else {
+ if (Current.is(tok::equal) &&
+ (RootToken.is(tok::kw_for) || State.ParenLevel == 0) &&
+ State.Stack.back().VariablePos == 0) {
+ State.Stack.back().VariablePos = State.Column;
+ // Move over * and & if they are bound to the variable name.
+ const AnnotatedToken *Tok = &Previous;
+ while (Tok &&
+ State.Stack.back().VariablePos >= Tok->FormatTok.TokenLength) {
+ State.Stack.back().VariablePos -= Tok->FormatTok.TokenLength;
+ if (Tok->SpacesRequiredBefore != 0)
+ break;
+ Tok = Tok->Parent;
+ }
+ if (Previous.PartOfMultiVariableDeclStmt)
+ State.Stack.back().LastSpace = State.Stack.back().VariablePos;
+ }
+
+ unsigned Spaces = State.NextToken->SpacesRequiredBefore;
+
+ if (!DryRun)
+ Whitespaces.replaceWhitespace(Current, 0, Spaces, State.Column);
+
+ if (Current.Type == TT_ObjCSelectorName &&
+ State.Stack.back().ColonPos == 0) {
+ if (State.Stack.back().Indent + Current.LongestObjCSelectorName >
+ State.Column + Spaces + Current.FormatTok.TokenLength)
+ State.Stack.back().ColonPos =
+ State.Stack.back().Indent + Current.LongestObjCSelectorName;
+ else
+ State.Stack.back().ColonPos =
+ State.Column + Spaces + Current.FormatTok.TokenLength;
+ }
+
+ if (Current.Type != TT_LineComment &&
+ (Previous.isOneOf(tok::l_paren, tok::l_brace) ||
+ State.NextToken->Parent->Type == TT_TemplateOpener))
+ State.Stack.back().Indent = State.Column + Spaces;
+ if (Previous.is(tok::comma) && !isTrailingComment(Current))
+ State.Stack.back().HasMultiParameterLine = true;
+
+ State.Column += Spaces;
+ if (Current.is(tok::l_paren) && Previous.isOneOf(tok::kw_if, tok::kw_for))
+ // Treat the condition inside an if as if it was a second function
+ // parameter, i.e. let nested calls have an indent of 4.
+ State.Stack.back().LastSpace = State.Column + 1; // 1 is length of "(".
+ else if (Previous.is(tok::comma))
+ State.Stack.back().LastSpace = State.Column;
+ else if ((Previous.Type == TT_BinaryOperator ||
+ Previous.Type == TT_ConditionalExpr ||
+ Previous.Type == TT_CtorInitializerColon) &&
+ getPrecedence(Previous) != prec::Assignment)
+ State.Stack.back().LastSpace = State.Column;
+ else if (Previous.Type == TT_InheritanceColon)
+ State.Stack.back().Indent = State.Column;
+ else if (Previous.ParameterCount > 1 &&
+ (Previous.isOneOf(tok::l_paren, tok::l_square, tok::l_brace) ||
+ Previous.Type == TT_TemplateOpener))
+ // If this function has multiple parameters, indent nested calls from
+ // the start of the first parameter.
+ State.Stack.back().LastSpace = State.Column;
+ }
+
+ return moveStateToNextToken(State, DryRun);
+ }
+
+ /// \brief Mark the next token as consumed in \p State and modify its stacks
+ /// accordingly.
+ unsigned moveStateToNextToken(LineState &State, bool DryRun) {
+ const AnnotatedToken &Current = *State.NextToken;
+ assert(State.Stack.size());
+
+ if (Current.Type == TT_InheritanceColon)
+ State.Stack.back().AvoidBinPacking = true;
+ if (Current.is(tok::lessless) && State.Stack.back().FirstLessLess == 0)
+ State.Stack.back().FirstLessLess = State.Column;
+ if (Current.is(tok::question))
+ State.Stack.back().QuestionColumn = State.Column;
+ if (Current.isOneOf(tok::period, tok::arrow) &&
+ Line.Type == LT_BuilderTypeCall && State.ParenLevel == 0)
+ State.Stack.back().StartOfFunctionCall =
+ Current.LastInChainOfCalls ? 0 : State.Column;
+ if (Current.Type == TT_CtorInitializerColon) {
+ if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine)
+ State.Stack.back().AvoidBinPacking = true;
+ State.Stack.back().BreakBeforeParameter = false;
+ }
+
+ // In ObjC method declaration we align on the ":" of parameters, but we need
+ // to ensure that we indent parameters on subsequent lines by at least 4.
+ if (Current.Type == TT_ObjCMethodSpecifier)
+ State.Stack.back().Indent += 4;
+
+ // Insert scopes created by fake parenthesis.
+ for (unsigned i = 0, e = Current.FakeLParens; i != e; ++i) {
+ ParenState NewParenState = State.Stack.back();
+ NewParenState.Indent = std::max(State.Column, State.Stack.back().Indent);
+ NewParenState.BreakBeforeParameter = false;
+ State.Stack.push_back(NewParenState);
+ }
+
+ // If we encounter an opening (, [, { or <, we add a level to our stacks to
+ // prepare for the following tokens.
+ if (Current.isOneOf(tok::l_paren, tok::l_square, tok::l_brace) ||
+ State.NextToken->Type == TT_TemplateOpener) {
+ unsigned NewIndent;
+ bool AvoidBinPacking;
+ if (Current.is(tok::l_brace)) {
+ NewIndent = 2 + State.Stack.back().LastSpace;
+ AvoidBinPacking = false;
+ } else {
+ NewIndent = 4 + std::max(State.Stack.back().LastSpace,
+ State.Stack.back().StartOfFunctionCall);
+ AvoidBinPacking =
+ !Style.BinPackParameters || State.Stack.back().AvoidBinPacking;
+ }
+ State.Stack.push_back(
+ ParenState(NewIndent, State.Stack.back().LastSpace, AvoidBinPacking,
+ State.Stack.back().HasMultiParameterLine));
+ ++State.ParenLevel;
+ }
+
+ // If this '[' opens an ObjC call, determine whether all parameters fit into
+ // one line and put one per line if they don't.
+ if (Current.is(tok::l_square) && Current.Type == TT_ObjCMethodExpr &&
+ Current.MatchingParen != NULL) {
+ if (getLengthToMatchingParen(Current) + State.Column > getColumnLimit())
+ State.Stack.back().BreakBeforeParameter = true;
+ }
+
+ // If we encounter a closing ), ], } or >, we can remove a level from our
+ // stacks.
+ if (Current.isOneOf(tok::r_paren, tok::r_square) ||
+ (Current.is(tok::r_brace) && State.NextToken != &RootToken) ||
+ State.NextToken->Type == TT_TemplateCloser) {
+ State.Stack.pop_back();
+ --State.ParenLevel;
+ }
+
+ // Remove scopes created by fake parenthesis.
+ for (unsigned i = 0, e = Current.FakeRParens; i != e; ++i) {
+ unsigned VariablePos = State.Stack.back().VariablePos;
+ State.Stack.pop_back();
+ State.Stack.back().VariablePos = VariablePos;
+ }
+
+ if (Current.is(tok::string_literal)) {
+ State.StartOfStringLiteral = State.Column;
+ } else if (Current.isNot(tok::comment)) {
+ State.StartOfStringLiteral = 0;
+ }
+
+ State.Column += Current.FormatTok.TokenLength;
+
+ if (State.NextToken->Children.empty())
+ State.NextToken = NULL;
+ else
+ State.NextToken = &State.NextToken->Children[0];
+
+ return breakProtrudingToken(Current, State, DryRun);
+ }
+
+ /// \brief If the current token sticks out over the end of the line, break
+ /// it if possible.
+ unsigned breakProtrudingToken(const AnnotatedToken &Current, LineState &State,
+ bool DryRun) {
+ if (Current.isNot(tok::string_literal))
+ return 0;
+ // Only break up default narrow strings.
+ const char *LiteralData = Current.FormatTok.Tok.getLiteralData();
+ if (!LiteralData || *LiteralData != '"')
+ return 0;
+
+ unsigned Penalty = 0;
+ unsigned TailOffset = 0;
+ unsigned TailLength = Current.FormatTok.TokenLength;
+ unsigned StartColumn = State.Column - Current.FormatTok.TokenLength;
+ unsigned OffsetFromStart = 0;
+ while (StartColumn + TailLength > getColumnLimit()) {
+ StringRef Text = StringRef(LiteralData + TailOffset, TailLength);
+ if (StartColumn + OffsetFromStart + 1 > getColumnLimit())
+ break;
+ StringRef::size_type SplitPoint = getSplitPoint(
+ Text, getColumnLimit() - StartColumn - OffsetFromStart - 1);
+ if (SplitPoint == StringRef::npos)
+ break;
+ assert(SplitPoint != 0);
+ // +2, because 'Text' starts after the opening quotes, and does not
+ // include the closing quote we need to insert.
+ unsigned WhitespaceStartColumn =
+ StartColumn + OffsetFromStart + SplitPoint + 2;
+ State.Stack.back().LastSpace = StartColumn;
+ if (!DryRun) {
+ Whitespaces.breakToken(Current.FormatTok, TailOffset + SplitPoint + 1,
+ 0, "\"", "\"", Line.InPPDirective, StartColumn,
+ WhitespaceStartColumn);
+ }
+ TailOffset += SplitPoint + 1;
+ TailLength -= SplitPoint + 1;
+ OffsetFromStart = 1;
+ Penalty += Style.PenaltyExcessCharacter;
+ for (unsigned i = 0, e = State.Stack.size(); i != e; ++i)
+ State.Stack[i].BreakBeforeParameter = true;
+ }
+ State.Column = StartColumn + TailLength;
+ return Penalty;
+ }
+
+ StringRef::size_type
+ getSplitPoint(StringRef Text, StringRef::size_type Offset) {
+ StringRef::size_type SpaceOffset = Text.rfind(' ', Offset);
+ if (SpaceOffset != StringRef::npos && SpaceOffset != 0)
+ return SpaceOffset;
+ StringRef::size_type SlashOffset = Text.rfind('/', Offset);
+ if (SlashOffset != StringRef::npos && SlashOffset != 0)
+ return SlashOffset;
+ StringRef::size_type Split = getStartOfCharacter(Text, Offset);
+ if (Split != StringRef::npos && Split > 1)
+ // Do not split at 0.
+ return Split - 1;
+ return StringRef::npos;
+ }
+
+ StringRef::size_type
+ getStartOfCharacter(StringRef Text, StringRef::size_type Offset) {
+ StringRef::size_type NextEscape = Text.find('\\');
+ while (NextEscape != StringRef::npos && NextEscape < Offset) {
+ StringRef::size_type SequenceLength =
+ getEscapeSequenceLength(Text.substr(NextEscape));
+ if (Offset < NextEscape + SequenceLength)
+ return NextEscape;
+ NextEscape = Text.find('\\', NextEscape + SequenceLength);
+ }
+ return Offset;
+ }
+
+ unsigned getEscapeSequenceLength(StringRef Text) {
+ assert(Text[0] == '\\');
+ if (Text.size() < 2)
+ return 1;
+
+ switch (Text[1]) {
+ case 'u':
+ return 6;
+ case 'U':
+ return 10;
+ case 'x':
+ return getHexLength(Text);
+ default:
+ if (Text[1] >= '0' && Text[1] <= '7')
+ return getOctalLength(Text);
+ return 2;
+ }
+ }
+
+ unsigned getHexLength(StringRef Text) {
+ unsigned I = 2; // Point after '\x'.
+ while (I < Text.size() && ((Text[I] >= '0' && Text[I] <= '9') ||
+ (Text[I] >= 'a' && Text[I] <= 'f') ||
+ (Text[I] >= 'A' && Text[I] <= 'F'))) {
+ ++I;
+ }
+ return I;
+ }
+
+ unsigned getOctalLength(StringRef Text) {
+ unsigned I = 1;
+ while (I < Text.size() && I < 4 && (Text[I] >= '0' && Text[I] <= '7')) {
+ ++I;
+ }
+ return I;
+ }
+
+ unsigned getColumnLimit() {
+ return calculateColumnLimit(Style, Line.InPPDirective);
+ }
+
+ /// \brief An edge in the solution space from \c Previous->State to \c State,
+ /// inserting a newline dependent on the \c NewLine.
+ struct StateNode {
+ StateNode(const LineState &State, bool NewLine, StateNode *Previous)
+ : State(State), NewLine(NewLine), Previous(Previous) {}
+ LineState State;
+ bool NewLine;
+ StateNode *Previous;
+ };
+
+ /// \brief A pair of <penalty, count> that is used to prioritize the BFS on.
+ ///
+ /// In case of equal penalties, we want to prefer states that were inserted
+ /// first. During state generation we make sure that we insert states first
+ /// that break the line as late as possible.
+ typedef std::pair<unsigned, unsigned> OrderedPenalty;
+
+ /// \brief An item in the prioritized BFS search queue. The \c StateNode's
+ /// \c State has the given \c OrderedPenalty.
+ typedef std::pair<OrderedPenalty, StateNode *> QueueItem;
+
+ /// \brief The BFS queue type.
+ typedef std::priority_queue<QueueItem, std::vector<QueueItem>,
+ std::greater<QueueItem> > QueueType;
+
+ /// \brief Analyze the entire solution space starting from \p InitialState.
+ ///
+ /// This implements a variant of Dijkstra's algorithm on the graph that spans
+ /// the solution space (\c LineStates are the nodes). The algorithm tries to
+ /// find the shortest path (the one with lowest penalty) from \p InitialState
+ /// to a state where all tokens are placed.
+ unsigned analyzeSolutionSpace(LineState &InitialState) {
+ std::set<LineState> Seen;
+
+ // Insert start element into queue.
+ StateNode *Node =
+ new (Allocator.Allocate()) StateNode(InitialState, false, NULL);
+ Queue.push(QueueItem(OrderedPenalty(0, Count), Node));
+ ++Count;
+
+ // While not empty, take first element and follow edges.
+ while (!Queue.empty()) {
+ unsigned Penalty = Queue.top().first.first;
+ StateNode *Node = Queue.top().second;
+ if (Node->State.NextToken == NULL) {
+ DEBUG(llvm::errs() << "\n---\nPenalty for line: " << Penalty << "\n");
+ break;
+ }
+ Queue.pop();
+
+ if (!Seen.insert(Node->State).second)
+ // State already examined with lower penalty.
+ continue;
+
+ addNextStateToQueue(Penalty, Node, /*NewLine=*/ false);
+ addNextStateToQueue(Penalty, Node, /*NewLine=*/ true);
+ }
+
+ if (Queue.empty())
+ // We were unable to find a solution, do nothing.
+ // FIXME: Add diagnostic?
+ return 0;
+
+ // Reconstruct the solution.
+ reconstructPath(InitialState, Queue.top().second);
+ DEBUG(llvm::errs() << "---\n");
+
+ // Return the column after the last token of the solution.
+ return Queue.top().second->State.Column;
+ }
+
+ void reconstructPath(LineState &State, StateNode *Current) {
+ // FIXME: This recursive implementation limits the possible number
+ // of tokens per line if compiled into a binary with small stack space.
+ // To become more independent of stack frame limitations we would need
+ // to also change the TokenAnnotator.
+ if (Current->Previous == NULL)
+ return;
+ reconstructPath(State, Current->Previous);
+ DEBUG({
+ if (Current->NewLine) {
+ llvm::errs()
+ << "Penalty for splitting before "
+ << Current->Previous->State.NextToken->FormatTok.Tok.getName()
+ << ": " << Current->Previous->State.NextToken->SplitPenalty << "\n";
+ }
+ });
+ addTokenToState(Current->NewLine, false, State);
+ }
+
+ /// \brief Add the following state to the analysis queue \c Queue.
+ ///
+ /// Assume the current state is \p PreviousNode and has been reached with a
+ /// penalty of \p Penalty. Insert a line break if \p NewLine is \c true.
+ void addNextStateToQueue(unsigned Penalty, StateNode *PreviousNode,
+ bool NewLine) {
+ if (NewLine && !canBreak(PreviousNode->State))
+ return;
+ if (!NewLine && mustBreak(PreviousNode->State))
+ return;
+ if (NewLine)
+ Penalty += PreviousNode->State.NextToken->SplitPenalty;
+
+ StateNode *Node = new (Allocator.Allocate())
+ StateNode(PreviousNode->State, NewLine, PreviousNode);
+ Penalty += addTokenToState(NewLine, true, Node->State);
+ if (Node->State.Column > getColumnLimit()) {
+ unsigned ExcessCharacters = Node->State.Column - getColumnLimit();
+ Penalty += Style.PenaltyExcessCharacter * ExcessCharacters;
+ }
+
+ Queue.push(QueueItem(OrderedPenalty(Penalty, Count), Node));
+ ++Count;
+ }
+
+ /// \brief Returns \c true, if a line break after \p State is allowed.
+ bool canBreak(const LineState &State) {
+ if (!State.NextToken->CanBreakBefore &&
+ !(State.NextToken->is(tok::r_brace) &&
+ State.Stack.back().BreakBeforeClosingBrace))
+ return false;
+ // Trying to insert a parameter on a new line if there are already more than
+ // one parameter on the current line is bin packing.
+ if (State.Stack.back().HasMultiParameterLine &&
+ State.Stack.back().AvoidBinPacking)
+ return false;
+ return true;
+ }
+
+ /// \brief Returns \c true, if a line break after \p State is mandatory.
+ bool mustBreak(const LineState &State) {
+ if (State.NextToken->MustBreakBefore)
+ return true;
+ if (State.NextToken->is(tok::r_brace) &&
+ State.Stack.back().BreakBeforeClosingBrace)
+ return true;
+ if (State.NextToken->Parent->is(tok::semi) &&
+ State.LineContainsContinuedForLoopSection)
+ return true;
+ if ((State.NextToken->Parent->isOneOf(tok::comma, tok::semi) ||
+ State.NextToken->is(tok::question) ||
+ State.NextToken->Type == TT_ConditionalExpr) &&
+ State.Stack.back().BreakBeforeParameter &&
+ !isTrailingComment(*State.NextToken) &&
+ State.NextToken->isNot(tok::r_paren) &&
+ State.NextToken->isNot(tok::r_brace))
+ return true;
+ // FIXME: Comparing LongestObjCSelectorName to 0 is a hacky way of finding
+ // out whether it is the first parameter. Clean this up.
+ if (State.NextToken->Type == TT_ObjCSelectorName &&
+ State.NextToken->LongestObjCSelectorName == 0 &&
+ State.Stack.back().BreakBeforeParameter)
+ return true;
+ if ((State.NextToken->Type == TT_CtorInitializerColon ||
+ (State.NextToken->Parent->ClosesTemplateDeclaration &&
+ State.ParenLevel == 0)))
+ return true;
+ if (State.NextToken->Type == TT_InlineASMColon)
+ return true;
+ // This prevents breaks like:
+ // ...
+ // SomeParameter, OtherParameter).DoSomething(
+ // ...
+ // As they hide "DoSomething" and generally bad for readability.
+ if (State.NextToken->isOneOf(tok::period, tok::arrow) &&
+ getRemainingLength(State) + State.Column > getColumnLimit() &&
+ State.ParenLevel < State.StartOfLineLevel)
+ return true;
+ return false;
+ }
+
+ // Returns the total number of columns required for the remaining tokens.
+ unsigned getRemainingLength(const LineState &State) {
+ if (State.NextToken && State.NextToken->Parent)
+ return Line.Last->TotalLength - State.NextToken->Parent->TotalLength;
+ return 0;
+ }
+
+ FormatStyle Style;
+ SourceManager &SourceMgr;
+ const AnnotatedLine &Line;
+ const unsigned FirstIndent;
+ const AnnotatedToken &RootToken;
+ WhitespaceManager &Whitespaces;
+
+ llvm::SpecificBumpPtrAllocator<StateNode> Allocator;
+ QueueType Queue;
+ // Increasing count of \c StateNode items we have created. This is used
+ // to create a deterministic order independent of the container.
+ unsigned Count;
+};
+
+class LexerBasedFormatTokenSource : public FormatTokenSource {
+public:
+ LexerBasedFormatTokenSource(Lexer &Lex, SourceManager &SourceMgr)
+ : GreaterStashed(false), Lex(Lex), SourceMgr(SourceMgr),
+ IdentTable(Lex.getLangOpts()) {
+ Lex.SetKeepWhitespaceMode(true);
+ }
+
+ virtual FormatToken getNextToken() {
+ if (GreaterStashed) {
+ FormatTok.NewlinesBefore = 0;
+ FormatTok.WhiteSpaceStart =
+ FormatTok.Tok.getLocation().getLocWithOffset(1);
+ FormatTok.WhiteSpaceLength = 0;
+ GreaterStashed = false;
+ return FormatTok;
+ }
+
+ FormatTok = FormatToken();
+ Lex.LexFromRawLexer(FormatTok.Tok);
+ StringRef Text = rawTokenText(FormatTok.Tok);
+ FormatTok.WhiteSpaceStart = FormatTok.Tok.getLocation();
+ if (SourceMgr.getFileOffset(FormatTok.WhiteSpaceStart) == 0)
+ FormatTok.IsFirst = true;
+
+ // Consume and record whitespace until we find a significant token.
+ while (FormatTok.Tok.is(tok::unknown)) {
+ unsigned Newlines = Text.count('\n');
+ if (Newlines > 0)
+ FormatTok.LastNewlineOffset =
+ FormatTok.WhiteSpaceLength + Text.rfind('\n') + 1;
+ unsigned EscapedNewlines = Text.count("\\\n");
+ FormatTok.NewlinesBefore += Newlines;
+ FormatTok.HasUnescapedNewline |= EscapedNewlines != Newlines;
+ FormatTok.WhiteSpaceLength += FormatTok.Tok.getLength();
+
+ if (FormatTok.Tok.is(tok::eof))
+ return FormatTok;
+ Lex.LexFromRawLexer(FormatTok.Tok);
+ Text = rawTokenText(FormatTok.Tok);
+ }
+
+ // Now FormatTok is the next non-whitespace token.
+ FormatTok.TokenLength = Text.size();
+
+ // In case the token starts with escaped newlines, we want to
+ // take them into account as whitespace - this pattern is quite frequent
+ // in macro definitions.
+ // FIXME: What do we want to do with other escaped spaces, and escaped
+ // spaces or newlines in the middle of tokens?
+ // FIXME: Add a more explicit test.
+ unsigned i = 0;
+ while (i + 1 < Text.size() && Text[i] == '\\' && Text[i + 1] == '\n') {
+ // FIXME: ++FormatTok.NewlinesBefore is missing...
+ FormatTok.WhiteSpaceLength += 2;
+ FormatTok.TokenLength -= 2;
+ i += 2;
+ }
+
+ if (FormatTok.Tok.is(tok::raw_identifier)) {
+ IdentifierInfo &Info = IdentTable.get(Text);
+ FormatTok.Tok.setIdentifierInfo(&Info);
+ FormatTok.Tok.setKind(Info.getTokenID());
+ }
+
+ if (FormatTok.Tok.is(tok::greatergreater)) {
+ FormatTok.Tok.setKind(tok::greater);
+ FormatTok.TokenLength = 1;
+ GreaterStashed = true;
+ }
+
+ // If we reformat comments, we remove trailing whitespace. Update the length
+ // accordingly.
+ if (FormatTok.Tok.is(tok::comment))
+ FormatTok.TokenLength = Text.rtrim().size();
+
+ return FormatTok;
+ }
+
+ IdentifierTable &getIdentTable() { return IdentTable; }
+
+private:
+ FormatToken FormatTok;
+ bool GreaterStashed;
+ Lexer &Lex;
+ SourceManager &SourceMgr;
+ IdentifierTable IdentTable;
+
+ /// Returns the text of \c FormatTok.
+ StringRef rawTokenText(Token &Tok) {
+ return StringRef(SourceMgr.getCharacterData(Tok.getLocation()),
+ Tok.getLength());
+ }
+};
+
+class Formatter : public UnwrappedLineConsumer {
+public:
+ Formatter(DiagnosticsEngine &Diag, const FormatStyle &Style, Lexer &Lex,
+ SourceManager &SourceMgr,
+ const std::vector<CharSourceRange> &Ranges)
+ : Diag(Diag), Style(Style), Lex(Lex), SourceMgr(SourceMgr),
+ Whitespaces(SourceMgr, Style), Ranges(Ranges) {}
+
+ virtual ~Formatter() {}
+
+ tooling::Replacements format() {
+ LexerBasedFormatTokenSource Tokens(Lex, SourceMgr);
+ UnwrappedLineParser Parser(Diag, Style, Tokens, *this);
+ StructuralError = Parser.parse();
+ unsigned PreviousEndOfLineColumn = 0;
+ TokenAnnotator Annotator(Style, SourceMgr, Lex,
+ Tokens.getIdentTable().get("in"));
+ for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
+ Annotator.annotate(AnnotatedLines[i]);
+ }
+ deriveLocalStyle();
+ for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
+ Annotator.calculateFormattingInformation(AnnotatedLines[i]);
+
+ // Adapt level to the next line if this is a comment.
+ // FIXME: Can/should this be done in the UnwrappedLineParser?
+ if (i + 1 != e && AnnotatedLines[i].First.is(tok::comment) &&
+ AnnotatedLines[i].First.Children.empty() &&
+ AnnotatedLines[i + 1].First.isNot(tok::r_brace))
+ AnnotatedLines[i].Level = AnnotatedLines[i + 1].Level;
+ }
+ std::vector<int> IndentForLevel;
+ bool PreviousLineWasTouched = false;
+ const AnnotatedToken *PreviousLineLastToken = 0;
+ for (std::vector<AnnotatedLine>::iterator I = AnnotatedLines.begin(),
+ E = AnnotatedLines.end();
+ I != E; ++I) {
+ const AnnotatedLine &TheLine = *I;
+ const FormatToken &FirstTok = TheLine.First.FormatTok;
+ int Offset = getIndentOffset(TheLine.First);
+ while (IndentForLevel.size() <= TheLine.Level)
+ IndentForLevel.push_back(-1);
+ IndentForLevel.resize(TheLine.Level + 1);
+ bool WasMoved = PreviousLineWasTouched && FirstTok.NewlinesBefore == 0;
+ if (TheLine.First.is(tok::eof)) {
+ if (PreviousLineWasTouched) {
+ unsigned NewLines = std::min(FirstTok.NewlinesBefore, 1u);
+ Whitespaces.replaceWhitespace(TheLine.First, NewLines, /*Indent*/ 0,
+ /*WhitespaceStartColumn*/ 0);
+ }
+ } else if (TheLine.Type != LT_Invalid &&
+ (WasMoved || touchesLine(TheLine))) {
+ unsigned LevelIndent = getIndent(IndentForLevel, TheLine.Level);
+ unsigned Indent = LevelIndent;
+ if (static_cast<int>(Indent) + Offset >= 0)
+ Indent += Offset;
+ if (!FirstTok.WhiteSpaceStart.isValid() || StructuralError) {
+ Indent = LevelIndent =
+ SourceMgr.getSpellingColumnNumber(FirstTok.Tok.getLocation()) - 1;
+ } else {
+ formatFirstToken(TheLine.First, PreviousLineLastToken, Indent,
+ TheLine.InPPDirective, PreviousEndOfLineColumn);
+ }
+ tryFitMultipleLinesInOne(Indent, I, E);
+ UnwrappedLineFormatter Formatter(Style, SourceMgr, TheLine, Indent,
+ TheLine.First, Whitespaces,
+ StructuralError);
+ PreviousEndOfLineColumn =
+ Formatter.format(I + 1 != E ? &*(I + 1) : NULL);
+ IndentForLevel[TheLine.Level] = LevelIndent;
+ PreviousLineWasTouched = true;
+ } else {
+ if (FirstTok.NewlinesBefore > 0 || FirstTok.IsFirst) {
+ unsigned Indent =
+ SourceMgr.getSpellingColumnNumber(FirstTok.Tok.getLocation()) - 1;
+ unsigned LevelIndent = Indent;
+ if (static_cast<int>(LevelIndent) - Offset >= 0)
+ LevelIndent -= Offset;
+ if (TheLine.First.isNot(tok::comment))
+ IndentForLevel[TheLine.Level] = LevelIndent;
+
+ // Remove trailing whitespace of the previous line if it was touched.
+ if (PreviousLineWasTouched || touchesEmptyLineBefore(TheLine))
+ formatFirstToken(TheLine.First, PreviousLineLastToken, Indent,
+ TheLine.InPPDirective, PreviousEndOfLineColumn);
+ }
+ // If we did not reformat this unwrapped line, the column at the end of
+ // the last token is unchanged - thus, we can calculate the end of the
+ // last token.
+ SourceLocation LastLoc = TheLine.Last->FormatTok.Tok.getLocation();
+ PreviousEndOfLineColumn =
+ SourceMgr.getSpellingColumnNumber(LastLoc) +
+ Lex.MeasureTokenLength(LastLoc, SourceMgr, Lex.getLangOpts()) - 1;
+ PreviousLineWasTouched = false;
+ if (TheLine.Last->is(tok::comment))
+ Whitespaces.addUntouchableComment(SourceMgr.getSpellingColumnNumber(
+ TheLine.Last->FormatTok.Tok.getLocation()) - 1);
+ }
+ PreviousLineLastToken = I->Last;
+ }
+ return Whitespaces.generateReplacements();
+ }
+
+private:
+ void deriveLocalStyle() {
+ unsigned CountBoundToVariable = 0;
+ unsigned CountBoundToType = 0;
+ bool HasCpp03IncompatibleFormat = false;
+ for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) {
+ if (AnnotatedLines[i].First.Children.empty())
+ continue;
+ AnnotatedToken *Tok = &AnnotatedLines[i].First.Children[0];
+ while (!Tok->Children.empty()) {
+ if (Tok->Type == TT_PointerOrReference) {
+ bool SpacesBefore = Tok->FormatTok.WhiteSpaceLength > 0;
+ bool SpacesAfter = Tok->Children[0].FormatTok.WhiteSpaceLength > 0;
+ if (SpacesBefore && !SpacesAfter)
+ ++CountBoundToVariable;
+ else if (!SpacesBefore && SpacesAfter)
+ ++CountBoundToType;
+ }
+
+ if (Tok->Type == TT_TemplateCloser &&
+ Tok->Parent->Type == TT_TemplateCloser &&
+ Tok->FormatTok.WhiteSpaceLength == 0)
+ HasCpp03IncompatibleFormat = true;
+ Tok = &Tok->Children[0];
+ }
+ }
+ if (Style.DerivePointerBinding) {
+ if (CountBoundToType > CountBoundToVariable)
+ Style.PointerBindsToType = true;
+ else if (CountBoundToType < CountBoundToVariable)
+ Style.PointerBindsToType = false;
+ }
+ if (Style.Standard == FormatStyle::LS_Auto) {
+ Style.Standard = HasCpp03IncompatibleFormat ? FormatStyle::LS_Cpp11
+ : FormatStyle::LS_Cpp03;
+ }
+ }
+
+ /// \brief Get the indent of \p Level from \p IndentForLevel.
+ ///
+ /// \p IndentForLevel must contain the indent for the level \c l
+ /// at \p IndentForLevel[l], or a value < 0 if the indent for
+ /// that level is unknown.
+ unsigned getIndent(const std::vector<int> IndentForLevel, unsigned Level) {
+ if (IndentForLevel[Level] != -1)
+ return IndentForLevel[Level];
+ if (Level == 0)
+ return 0;
+ return getIndent(IndentForLevel, Level - 1) + 2;
+ }
+
+ /// \brief Get the offset of the line relatively to the level.
+ ///
+ /// For example, 'public:' labels in classes are offset by 1 or 2
+ /// characters to the left from their level.
+ int getIndentOffset(const AnnotatedToken &RootToken) {
+ if (RootToken.isAccessSpecifier(false) || RootToken.isObjCAccessSpecifier())
+ return Style.AccessModifierOffset;
+ return 0;
+ }
+
+ /// \brief Tries to merge lines into one.
+ ///
+ /// This will change \c Line and \c AnnotatedLine to contain the merged line,
+ /// if possible; note that \c I will be incremented when lines are merged.
+ ///
+ /// Returns whether the resulting \c Line can fit in a single line.
+ void tryFitMultipleLinesInOne(unsigned Indent,
+ std::vector<AnnotatedLine>::iterator &I,
+ std::vector<AnnotatedLine>::iterator E) {
+ // We can never merge stuff if there are trailing line comments.
+ if (I->Last->Type == TT_LineComment)
+ return;
+
+ unsigned Limit = Style.ColumnLimit - Indent;
+ // If we already exceed the column limit, we set 'Limit' to 0. The different
+ // tryMerge..() functions can then decide whether to still do merging.
+ Limit = I->Last->TotalLength > Limit ? 0 : Limit - I->Last->TotalLength;
+
+ if (I + 1 == E || (I + 1)->Type == LT_Invalid)
+ return;
+
+ if (I->Last->is(tok::l_brace)) {
+ tryMergeSimpleBlock(I, E, Limit);
+ } else if (I->First.is(tok::kw_if)) {
+ tryMergeSimpleIf(I, E, Limit);
+ } else if (I->InPPDirective && (I->First.FormatTok.HasUnescapedNewline ||
+ I->First.FormatTok.IsFirst)) {
+ tryMergeSimplePPDirective(I, E, Limit);
+ }
+ return;
+ }
+
+ void tryMergeSimplePPDirective(std::vector<AnnotatedLine>::iterator &I,
+ std::vector<AnnotatedLine>::iterator E,
+ unsigned Limit) {
+ if (Limit == 0)
+ return;
+ AnnotatedLine &Line = *I;
+ if (!(I + 1)->InPPDirective || (I + 1)->First.FormatTok.HasUnescapedNewline)
+ return;
+ if (I + 2 != E && (I + 2)->InPPDirective &&
+ !(I + 2)->First.FormatTok.HasUnescapedNewline)
+ return;
+ if (1 + (I + 1)->Last->TotalLength > Limit)
+ return;
+ join(Line, *(++I));
+ }
+
+ void tryMergeSimpleIf(std::vector<AnnotatedLine>::iterator &I,
+ std::vector<AnnotatedLine>::iterator E,
+ unsigned Limit) {
+ if (Limit == 0)
+ return;
+ if (!Style.AllowShortIfStatementsOnASingleLine)
+ return;
+ if ((I + 1)->InPPDirective != I->InPPDirective ||
+ ((I + 1)->InPPDirective &&
+ (I + 1)->First.FormatTok.HasUnescapedNewline))
+ return;
+ AnnotatedLine &Line = *I;
+ if (Line.Last->isNot(tok::r_paren))
+ return;
+ if (1 + (I + 1)->Last->TotalLength > Limit)
+ return;
+ if ((I + 1)->First.is(tok::kw_if) || (I + 1)->First.Type == TT_LineComment)
+ return;
+ // Only inline simple if's (no nested if or else).
+ if (I + 2 != E && (I + 2)->First.is(tok::kw_else))
+ return;
+ join(Line, *(++I));
+ }
+
+ void tryMergeSimpleBlock(std::vector<AnnotatedLine>::iterator &I,
+ std::vector<AnnotatedLine>::iterator E,
+ unsigned Limit) {
+ // First, check that the current line allows merging. This is the case if
+ // we're not in a control flow statement and the last token is an opening
+ // brace.
+ AnnotatedLine &Line = *I;
+ if (Line.First.isOneOf(tok::kw_if, tok::kw_while, tok::kw_do, tok::r_brace,
+ tok::kw_else, tok::kw_try, tok::kw_catch,
+ tok::kw_for,
+ // This gets rid of all ObjC @ keywords and methods.
+ tok::at, tok::minus, tok::plus))
+ return;
+
+ AnnotatedToken *Tok = &(I + 1)->First;
+ if (Tok->Children.empty() && Tok->is(tok::r_brace) &&
+ !Tok->MustBreakBefore) {
+ // We merge empty blocks even if the line exceeds the column limit.
+ Tok->SpacesRequiredBefore = 0;
+ Tok->CanBreakBefore = true;
+ join(Line, *(I + 1));
+ I += 1;
+ } else if (Limit != 0) {
+ // Check that we still have three lines and they fit into the limit.
+ if (I + 2 == E || (I + 2)->Type == LT_Invalid ||
+ !nextTwoLinesFitInto(I, Limit))
+ return;
+
+ // Second, check that the next line does not contain any braces - if it
+ // does, readability declines when putting it into a single line.
+ if ((I + 1)->Last->Type == TT_LineComment || Tok->MustBreakBefore)
+ return;
+ do {
+ if (Tok->isOneOf(tok::l_brace, tok::r_brace))
+ return;
+ Tok = Tok->Children.empty() ? NULL : &Tok->Children.back();
+ } while (Tok != NULL);
+
+ // Last, check that the third line contains a single closing brace.
+ Tok = &(I + 2)->First;
+ if (!Tok->Children.empty() || Tok->isNot(tok::r_brace) ||
+ Tok->MustBreakBefore)
+ return;
+
+ join(Line, *(I + 1));
+ join(Line, *(I + 2));
+ I += 2;
+ }
+ }
+
+ bool nextTwoLinesFitInto(std::vector<AnnotatedLine>::iterator I,
+ unsigned Limit) {
+ return 1 + (I + 1)->Last->TotalLength + 1 + (I + 2)->Last->TotalLength <=
+ Limit;
+ }
+
+ void join(AnnotatedLine &A, const AnnotatedLine &B) {
+ unsigned LengthA = A.Last->TotalLength + B.First.SpacesRequiredBefore;
+ A.Last->Children.push_back(B.First);
+ while (!A.Last->Children.empty()) {
+ A.Last->Children[0].Parent = A.Last;
+ A.Last->Children[0].TotalLength += LengthA;
+ A.Last = &A.Last->Children[0];
+ }
+ }
+
+ bool touchesRanges(const CharSourceRange &Range) {
+ for (unsigned i = 0, e = Ranges.size(); i != e; ++i) {
+ if (!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),
+ Ranges[i].getBegin()) &&
+ !SourceMgr.isBeforeInTranslationUnit(Ranges[i].getEnd(),
+ Range.getBegin()))
+ return true;
+ }
+ return false;
+ }
+
+ bool touchesLine(const AnnotatedLine &TheLine) {
+ const FormatToken *First = &TheLine.First.FormatTok;
+ const FormatToken *Last = &TheLine.Last->FormatTok;
+ CharSourceRange LineRange = CharSourceRange::getTokenRange(
+ First->WhiteSpaceStart.getLocWithOffset(First->LastNewlineOffset),
+ Last->Tok.getLocation());
+ return touchesRanges(LineRange);
+ }
+
+ bool touchesEmptyLineBefore(const AnnotatedLine &TheLine) {
+ const FormatToken *First = &TheLine.First.FormatTok;
+ CharSourceRange LineRange = CharSourceRange::getCharRange(
+ First->WhiteSpaceStart,
+ First->WhiteSpaceStart.getLocWithOffset(First->LastNewlineOffset));
+ return touchesRanges(LineRange);
+ }
+
+ virtual void consumeUnwrappedLine(const UnwrappedLine &TheLine) {
+ AnnotatedLines.push_back(AnnotatedLine(TheLine));
+ }
+
+ /// \brief Add a new line and the required indent before the first Token
+ /// of the \c UnwrappedLine if there was no structural parsing error.
+ /// Returns the indent level of the \c UnwrappedLine.
+ void formatFirstToken(const AnnotatedToken &RootToken,
+ const AnnotatedToken *PreviousToken, unsigned Indent,
+ bool InPPDirective, unsigned PreviousEndOfLineColumn) {
+ const FormatToken &Tok = RootToken.FormatTok;
+
+ unsigned Newlines =
+ std::min(Tok.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1);
+ if (Newlines == 0 && !Tok.IsFirst)
+ Newlines = 1;
+
+ if (!InPPDirective || Tok.HasUnescapedNewline) {
+ // Insert extra new line before access specifiers.
+ if (PreviousToken && PreviousToken->isOneOf(tok::semi, tok::r_brace) &&
+ RootToken.isAccessSpecifier() && Tok.NewlinesBefore == 1)
+ ++Newlines;
+
+ Whitespaces.replaceWhitespace(RootToken, Newlines, Indent, 0);
+ } else {
+ Whitespaces.replacePPWhitespace(RootToken, Newlines, Indent,
+ PreviousEndOfLineColumn);
+ }
+ }
+
+ DiagnosticsEngine &Diag;
+ FormatStyle Style;
+ Lexer &Lex;
+ SourceManager &SourceMgr;
+ WhitespaceManager Whitespaces;
+ std::vector<CharSourceRange> Ranges;
+ std::vector<AnnotatedLine> AnnotatedLines;
+ bool StructuralError;
+};
+
+tooling::Replacements
+reformat(const FormatStyle &Style, Lexer &Lex, SourceManager &SourceMgr,
+ std::vector<CharSourceRange> Ranges, DiagnosticConsumer *DiagClient) {
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ OwningPtr<DiagnosticConsumer> DiagPrinter;
+ if (DiagClient == 0) {
+ DiagPrinter.reset(new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts));
+ DiagPrinter->BeginSourceFile(Lex.getLangOpts(), Lex.getPP());
+ DiagClient = DiagPrinter.get();
+ }
+ DiagnosticsEngine Diagnostics(
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
+ DiagClient, false);
+ Diagnostics.setSourceManager(&SourceMgr);
+ Formatter formatter(Diagnostics, Style, Lex, SourceMgr, Ranges);
+ return formatter.format();
+}
+
+LangOptions getFormattingLangOpts() {
+ LangOptions LangOpts;
+ LangOpts.CPlusPlus = 1;
+ LangOpts.CPlusPlus11 = 1;
+ LangOpts.LineComment = 1;
+ LangOpts.Bool = 1;
+ LangOpts.ObjC1 = 1;
+ LangOpts.ObjC2 = 1;
+ return LangOpts;
+}
+
+} // namespace format
+} // namespace clang
diff --git a/lib/Format/Makefile b/lib/Format/Makefile
new file mode 100644
index 0000000..f4d2b98
--- /dev/null
+++ b/lib/Format/Makefile
@@ -0,0 +1,13 @@
+##===- clang/lib/Format/Makefile ---------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL := ../..
+LIBRARYNAME := clangFormat
+
+include $(CLANG_LEVEL)/Makefile
diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp
new file mode 100644
index 0000000..427157e
--- /dev/null
+++ b/lib/Format/TokenAnnotator.cpp
@@ -0,0 +1,1187 @@
+//===--- TokenAnnotator.cpp - Format C++ code -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements a token annotator, i.e. creates
+/// \c AnnotatedTokens out of \c FormatTokens with required extra information.
+///
+//===----------------------------------------------------------------------===//
+
+#include "TokenAnnotator.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+
+namespace clang {
+namespace format {
+
+static bool isUnaryOperator(const AnnotatedToken &Tok) {
+ switch (Tok.FormatTok.Tok.getKind()) {
+ case tok::plus:
+ case tok::plusplus:
+ case tok::minus:
+ case tok::minusminus:
+ case tok::exclaim:
+ case tok::tilde:
+ case tok::kw_sizeof:
+ case tok::kw_alignof:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool isBinaryOperator(const AnnotatedToken &Tok) {
+ // Comma is a binary operator, but does not behave as such wrt. formatting.
+ return getPrecedence(Tok) > prec::Comma;
+}
+
+// Returns the previous token ignoring comments.
+static AnnotatedToken *getPreviousToken(AnnotatedToken &Tok) {
+ AnnotatedToken *PrevToken = Tok.Parent;
+ while (PrevToken != NULL && PrevToken->is(tok::comment))
+ PrevToken = PrevToken->Parent;
+ return PrevToken;
+}
+static const AnnotatedToken *getPreviousToken(const AnnotatedToken &Tok) {
+ return getPreviousToken(const_cast<AnnotatedToken &>(Tok));
+}
+
+static bool isTrailingComment(AnnotatedToken *Tok) {
+ return Tok != NULL && Tok->is(tok::comment) &&
+ (Tok->Children.empty() ||
+ Tok->Children[0].FormatTok.NewlinesBefore > 0);
+}
+
+// Returns the next token ignoring comments.
+static const AnnotatedToken *getNextToken(const AnnotatedToken &Tok) {
+ if (Tok.Children.empty())
+ return NULL;
+ const AnnotatedToken *NextToken = &Tok.Children[0];
+ while (NextToken->is(tok::comment)) {
+ if (NextToken->Children.empty())
+ return NULL;
+ NextToken = &NextToken->Children[0];
+ }
+ return NextToken;
+}
+
+static bool closesScope(const AnnotatedToken &Tok) {
+ return Tok.isOneOf(tok::r_paren, tok::r_brace, tok::r_square) ||
+ Tok.Type == TT_TemplateCloser;
+}
+
+static bool opensScope(const AnnotatedToken &Tok) {
+ return Tok.isOneOf(tok::l_paren, tok::l_brace, tok::l_square) ||
+ Tok.Type == TT_TemplateOpener;
+}
+
+/// \brief A parser that gathers additional information about tokens.
+///
+/// The \c TokenAnnotator tries to match parenthesis and square brakets and
+/// store a parenthesis levels. It also tries to resolve matching "<" and ">"
+/// into template parameter lists.
+class AnnotatingParser {
+public:
+ AnnotatingParser(SourceManager &SourceMgr, Lexer &Lex, AnnotatedLine &Line,
+ IdentifierInfo &Ident_in)
+ : SourceMgr(SourceMgr), Lex(Lex), Line(Line), CurrentToken(&Line.First),
+ KeywordVirtualFound(false), Ident_in(Ident_in) {
+ Contexts.push_back(Context(tok::unknown, 1, /*IsExpression=*/ false));
+ }
+
+private:
+ bool parseAngle() {
+ if (CurrentToken == NULL)
+ return false;
+ ScopedContextCreator ContextCreator(*this, tok::less, 10);
+ AnnotatedToken *Left = CurrentToken->Parent;
+ Contexts.back().IsExpression = false;
+ while (CurrentToken != NULL) {
+ if (CurrentToken->is(tok::greater)) {
+ Left->MatchingParen = CurrentToken;
+ CurrentToken->MatchingParen = Left;
+ CurrentToken->Type = TT_TemplateCloser;
+ next();
+ return true;
+ }
+ if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace,
+ tok::pipepipe, tok::ampamp, tok::question,
+ tok::colon))
+ return false;
+ updateParameterCount(Left, CurrentToken);
+ if (!consumeToken())
+ return false;
+ }
+ return false;
+ }
+
+ bool parseParens(bool LookForDecls = false) {
+ if (CurrentToken == NULL)
+ return false;
+ ScopedContextCreator ContextCreator(*this, tok::l_paren, 1);
+
+ // FIXME: This is a bit of a hack. Do better.
+ Contexts.back().ColonIsForRangeExpr =
+ Contexts.size() == 2 && Contexts[0].ColonIsForRangeExpr;
+
+ bool StartsObjCMethodExpr = false;
+ AnnotatedToken *Left = CurrentToken->Parent;
+ if (CurrentToken->is(tok::caret)) {
+ // ^( starts a block.
+ Left->Type = TT_ObjCBlockLParen;
+ } else if (AnnotatedToken *MaybeSel = Left->Parent) {
+ // @selector( starts a selector.
+ if (MaybeSel->isObjCAtKeyword(tok::objc_selector) && MaybeSel->Parent &&
+ MaybeSel->Parent->is(tok::at)) {
+ StartsObjCMethodExpr = true;
+ }
+ }
+
+ if (StartsObjCMethodExpr) {
+ Contexts.back().ColonIsObjCMethodExpr = true;
+ Left->Type = TT_ObjCMethodExpr;
+ }
+
+ while (CurrentToken != NULL) {
+ // LookForDecls is set when "if (" has been seen. Check for
+ // 'identifier' '*' 'identifier' followed by not '=' -- this
+ // '*' has to be a binary operator but determineStarAmpUsage() will
+ // categorize it as an unary operator, so set the right type here.
+ if (LookForDecls && !CurrentToken->Children.empty()) {
+ AnnotatedToken &Prev = *CurrentToken->Parent;
+ AnnotatedToken &Next = CurrentToken->Children[0];
+ if (Prev.Parent->is(tok::identifier) &&
+ Prev.isOneOf(tok::star, tok::amp, tok::ampamp) &&
+ CurrentToken->is(tok::identifier) && Next.isNot(tok::equal)) {
+ Prev.Type = TT_BinaryOperator;
+ LookForDecls = false;
+ }
+ }
+
+ if (CurrentToken->is(tok::r_paren)) {
+ Left->MatchingParen = CurrentToken;
+ CurrentToken->MatchingParen = Left;
+
+ if (StartsObjCMethodExpr) {
+ CurrentToken->Type = TT_ObjCMethodExpr;
+ if (Contexts.back().FirstObjCSelectorName != NULL) {
+ Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName =
+ Contexts.back().LongestObjCSelectorName;
+ }
+ }
+
+ next();
+ return true;
+ }
+ if (CurrentToken->isOneOf(tok::r_square, tok::r_brace))
+ return false;
+ updateParameterCount(Left, CurrentToken);
+ if (!consumeToken())
+ return false;
+ }
+ return false;
+ }
+
+ bool parseSquare() {
+ if (!CurrentToken)
+ return false;
+
+ // A '[' could be an index subscript (after an indentifier or after
+ // ')' or ']'), it could be the start of an Objective-C method
+ // expression, or it could the the start of an Objective-C array literal.
+ AnnotatedToken *Left = CurrentToken->Parent;
+ AnnotatedToken *Parent = getPreviousToken(*Left);
+ bool StartsObjCMethodExpr =
+ Contexts.back().CanBeExpression &&
+ (!Parent || Parent->isOneOf(tok::colon, tok::l_square, tok::l_paren,
+ tok::kw_return, tok::kw_throw) ||
+ isUnaryOperator(*Parent) || Parent->Type == TT_ObjCForIn ||
+ Parent->Type == TT_CastRParen ||
+ getBinOpPrecedence(Parent->FormatTok.Tok.getKind(), true, true) >
+ prec::Unknown);
+ ScopedContextCreator ContextCreator(*this, tok::l_square, 10);
+ Contexts.back().IsExpression = true;
+ bool StartsObjCArrayLiteral = Parent && Parent->is(tok::at);
+
+ if (StartsObjCMethodExpr) {
+ Contexts.back().ColonIsObjCMethodExpr = true;
+ Left->Type = TT_ObjCMethodExpr;
+ } else if (StartsObjCArrayLiteral) {
+ Left->Type = TT_ObjCArrayLiteral;
+ }
+
+ while (CurrentToken != NULL) {
+ if (CurrentToken->is(tok::r_square)) {
+ if (!CurrentToken->Children.empty() &&
+ CurrentToken->Children[0].is(tok::l_paren)) {
+ // An ObjC method call is rarely followed by an open parenthesis.
+ // FIXME: Do we incorrectly label ":" with this?
+ StartsObjCMethodExpr = false;
+ Left->Type = TT_Unknown;
+ }
+ if (StartsObjCMethodExpr) {
+ CurrentToken->Type = TT_ObjCMethodExpr;
+ // determineStarAmpUsage() thinks that '*' '[' is allocating an
+ // array of pointers, but if '[' starts a selector then '*' is a
+ // binary operator.
+ if (Parent != NULL && Parent->Type == TT_PointerOrReference)
+ Parent->Type = TT_BinaryOperator;
+ } else if (StartsObjCArrayLiteral) {
+ CurrentToken->Type = TT_ObjCArrayLiteral;
+ }
+ Left->MatchingParen = CurrentToken;
+ CurrentToken->MatchingParen = Left;
+ if (Contexts.back().FirstObjCSelectorName != NULL)
+ Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName =
+ Contexts.back().LongestObjCSelectorName;
+ next();
+ return true;
+ }
+ if (CurrentToken->isOneOf(tok::r_paren, tok::r_brace))
+ return false;
+ updateParameterCount(Left, CurrentToken);
+ if (!consumeToken())
+ return false;
+ }
+ return false;
+ }
+
+ bool parseBrace() {
+ // Lines are fine to end with '{'.
+ if (CurrentToken == NULL)
+ return true;
+ ScopedContextCreator ContextCreator(*this, tok::l_brace, 1);
+ AnnotatedToken *Left = CurrentToken->Parent;
+ while (CurrentToken != NULL) {
+ if (CurrentToken->is(tok::r_brace)) {
+ Left->MatchingParen = CurrentToken;
+ CurrentToken->MatchingParen = Left;
+ next();
+ return true;
+ }
+ if (CurrentToken->isOneOf(tok::r_paren, tok::r_square))
+ return false;
+ updateParameterCount(Left, CurrentToken);
+ if (!consumeToken())
+ return false;
+ }
+ return true;
+ }
+
+ void updateParameterCount(AnnotatedToken *Left, AnnotatedToken *Current) {
+ if (Current->is(tok::comma))
+ ++Left->ParameterCount;
+ else if (Left->ParameterCount == 0 && Current->isNot(tok::comment))
+ Left->ParameterCount = 1;
+ }
+
+ bool parseConditional() {
+ while (CurrentToken != NULL) {
+ if (CurrentToken->is(tok::colon)) {
+ CurrentToken->Type = TT_ConditionalExpr;
+ next();
+ return true;
+ }
+ if (!consumeToken())
+ return false;
+ }
+ return false;
+ }
+
+ bool parseTemplateDeclaration() {
+ if (CurrentToken != NULL && CurrentToken->is(tok::less)) {
+ CurrentToken->Type = TT_TemplateOpener;
+ next();
+ if (!parseAngle())
+ return false;
+ if (CurrentToken != NULL)
+ CurrentToken->Parent->ClosesTemplateDeclaration = true;
+ return true;
+ }
+ return false;
+ }
+
+ bool consumeToken() {
+ AnnotatedToken *Tok = CurrentToken;
+ next();
+ switch (Tok->FormatTok.Tok.getKind()) {
+ case tok::plus:
+ case tok::minus:
+ if (Tok->Parent == NULL && Line.MustBeDeclaration)
+ Tok->Type = TT_ObjCMethodSpecifier;
+ break;
+ case tok::colon:
+ if (Tok->Parent == NULL)
+ return false;
+ // Colons from ?: are handled in parseConditional().
+ if (Tok->Parent->is(tok::r_paren) && Contexts.size() == 1) {
+ Tok->Type = TT_CtorInitializerColon;
+ } else if (Contexts.back().ColonIsObjCMethodExpr ||
+ Line.First.Type == TT_ObjCMethodSpecifier) {
+ Tok->Type = TT_ObjCMethodExpr;
+ Tok->Parent->Type = TT_ObjCSelectorName;
+ if (Tok->Parent->FormatTok.TokenLength >
+ Contexts.back().LongestObjCSelectorName)
+ Contexts.back().LongestObjCSelectorName =
+ Tok->Parent->FormatTok.TokenLength;
+ if (Contexts.back().FirstObjCSelectorName == NULL)
+ Contexts.back().FirstObjCSelectorName = Tok->Parent;
+ } else if (Contexts.back().ColonIsForRangeExpr) {
+ Tok->Type = TT_RangeBasedForLoopColon;
+ } else if (Contexts.size() == 1) {
+ Tok->Type = TT_InheritanceColon;
+ } else if (Contexts.back().ContextKind == tok::l_paren) {
+ Tok->Type = TT_InlineASMColon;
+ }
+ break;
+ case tok::kw_if:
+ case tok::kw_while:
+ if (CurrentToken != NULL && CurrentToken->is(tok::l_paren)) {
+ next();
+ if (!parseParens(/*LookForDecls=*/ true))
+ return false;
+ }
+ break;
+ case tok::kw_for:
+ Contexts.back().ColonIsForRangeExpr = true;
+ next();
+ if (!parseParens())
+ return false;
+ break;
+ case tok::l_paren:
+ if (!parseParens())
+ return false;
+ if (Line.MustBeDeclaration)
+ Line.MightBeFunctionDecl = true;
+ break;
+ case tok::l_square:
+ if (!parseSquare())
+ return false;
+ break;
+ case tok::l_brace:
+ if (!parseBrace())
+ return false;
+ break;
+ case tok::less:
+ if (parseAngle())
+ Tok->Type = TT_TemplateOpener;
+ else {
+ Tok->Type = TT_BinaryOperator;
+ CurrentToken = Tok;
+ next();
+ }
+ break;
+ case tok::r_paren:
+ case tok::r_square:
+ return false;
+ case tok::r_brace:
+ // Lines can start with '}'.
+ if (Tok->Parent != NULL)
+ return false;
+ break;
+ case tok::greater:
+ Tok->Type = TT_BinaryOperator;
+ break;
+ case tok::kw_operator:
+ while (CurrentToken && CurrentToken->isNot(tok::l_paren)) {
+ if (CurrentToken->isOneOf(tok::star, tok::amp))
+ CurrentToken->Type = TT_PointerOrReference;
+ consumeToken();
+ }
+ if (CurrentToken)
+ CurrentToken->Type = TT_OverloadedOperatorLParen;
+ break;
+ case tok::question:
+ parseConditional();
+ break;
+ case tok::kw_template:
+ parseTemplateDeclaration();
+ break;
+ case tok::identifier:
+ if (Line.First.is(tok::kw_for) &&
+ Tok->FormatTok.Tok.getIdentifierInfo() == &Ident_in)
+ Tok->Type = TT_ObjCForIn;
+ break;
+ case tok::comma:
+ if (Contexts.back().FirstStartOfName)
+ Contexts.back().FirstStartOfName->PartOfMultiVariableDeclStmt = true;
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
+
+ void parseIncludeDirective() {
+ next();
+ if (CurrentToken != NULL && CurrentToken->is(tok::less)) {
+ next();
+ while (CurrentToken != NULL) {
+ if (CurrentToken->isNot(tok::comment) ||
+ !CurrentToken->Children.empty())
+ CurrentToken->Type = TT_ImplicitStringLiteral;
+ next();
+ }
+ } else {
+ while (CurrentToken != NULL) {
+ if (CurrentToken->is(tok::string_literal))
+ // Mark these string literals as "implicit" literals, too, so that
+ // they are not split or line-wrapped.
+ CurrentToken->Type = TT_ImplicitStringLiteral;
+ next();
+ }
+ }
+ }
+
+ void parseWarningOrError() {
+ next();
+ // We still want to format the whitespace left of the first token of the
+ // warning or error.
+ next();
+ while (CurrentToken != NULL) {
+ CurrentToken->Type = TT_ImplicitStringLiteral;
+ next();
+ }
+ }
+
+ void parsePreprocessorDirective() {
+ next();
+ if (CurrentToken == NULL)
+ return;
+ // Hashes in the middle of a line can lead to any strange token
+ // sequence.
+ if (CurrentToken->FormatTok.Tok.getIdentifierInfo() == NULL)
+ return;
+ switch (CurrentToken->FormatTok.Tok.getIdentifierInfo()->getPPKeywordID()) {
+ case tok::pp_include:
+ case tok::pp_import:
+ parseIncludeDirective();
+ break;
+ case tok::pp_error:
+ case tok::pp_warning:
+ parseWarningOrError();
+ break;
+ default:
+ break;
+ }
+ while (CurrentToken != NULL)
+ next();
+ }
+
+public:
+ LineType parseLine() {
+ int PeriodsAndArrows = 0;
+ AnnotatedToken *LastPeriodOrArrow = NULL;
+ bool CanBeBuilderTypeStmt = true;
+ if (CurrentToken->is(tok::hash)) {
+ parsePreprocessorDirective();
+ return LT_PreprocessorDirective;
+ }
+ while (CurrentToken != NULL) {
+ if (CurrentToken->is(tok::kw_virtual))
+ KeywordVirtualFound = true;
+ if (CurrentToken->isOneOf(tok::period, tok::arrow)) {
+ ++PeriodsAndArrows;
+ LastPeriodOrArrow = CurrentToken;
+ }
+ AnnotatedToken *TheToken = CurrentToken;
+ if (!consumeToken())
+ return LT_Invalid;
+ if (getPrecedence(*TheToken) > prec::Assignment &&
+ TheToken->Type == TT_BinaryOperator)
+ CanBeBuilderTypeStmt = false;
+ }
+ if (KeywordVirtualFound)
+ return LT_VirtualFunctionDecl;
+
+ // Assume a builder-type call if there are 2 or more "." and "->".
+ if (PeriodsAndArrows >= 2 && CanBeBuilderTypeStmt) {
+ LastPeriodOrArrow->LastInChainOfCalls = true;
+ return LT_BuilderTypeCall;
+ }
+
+ if (Line.First.Type == TT_ObjCMethodSpecifier) {
+ if (Contexts.back().FirstObjCSelectorName != NULL)
+ Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName =
+ Contexts.back().LongestObjCSelectorName;
+ return LT_ObjCMethodDecl;
+ }
+
+ return LT_Other;
+ }
+
+private:
+ void next() {
+ if (CurrentToken != NULL) {
+ determineTokenType(*CurrentToken);
+ CurrentToken->BindingStrength = Contexts.back().BindingStrength;
+ }
+
+ if (CurrentToken != NULL && !CurrentToken->Children.empty())
+ CurrentToken = &CurrentToken->Children[0];
+ else
+ CurrentToken = NULL;
+
+ // Reset token type in case we have already looked at it and then recovered
+ // from an error (e.g. failure to find the matching >).
+ if (CurrentToken != NULL)
+ CurrentToken->Type = TT_Unknown;
+ }
+
+ /// \brief A struct to hold information valid in a specific context, e.g.
+ /// a pair of parenthesis.
+ struct Context {
+ Context(tok::TokenKind ContextKind, unsigned BindingStrength,
+ bool IsExpression)
+ : ContextKind(ContextKind), BindingStrength(BindingStrength),
+ LongestObjCSelectorName(0), ColonIsForRangeExpr(false),
+ ColonIsObjCMethodExpr(false), FirstObjCSelectorName(NULL),
+ FirstStartOfName(NULL), IsExpression(IsExpression),
+ CanBeExpression(true) {}
+
+ tok::TokenKind ContextKind;
+ unsigned BindingStrength;
+ unsigned LongestObjCSelectorName;
+ bool ColonIsForRangeExpr;
+ bool ColonIsObjCMethodExpr;
+ AnnotatedToken *FirstObjCSelectorName;
+ AnnotatedToken *FirstStartOfName;
+ bool IsExpression;
+ bool CanBeExpression;
+ };
+
+ /// \brief Puts a new \c Context onto the stack \c Contexts for the lifetime
+ /// of each instance.
+ struct ScopedContextCreator {
+ AnnotatingParser &P;
+
+ ScopedContextCreator(AnnotatingParser &P, tok::TokenKind ContextKind,
+ unsigned Increase)
+ : P(P) {
+ P.Contexts.push_back(
+ Context(ContextKind, P.Contexts.back().BindingStrength + Increase,
+ P.Contexts.back().IsExpression));
+ }
+
+ ~ScopedContextCreator() { P.Contexts.pop_back(); }
+ };
+
+ void determineTokenType(AnnotatedToken &Current) {
+ if (getPrecedence(Current) == prec::Assignment) {
+ Contexts.back().IsExpression = true;
+ for (AnnotatedToken *Previous = Current.Parent;
+ Previous && Previous->isNot(tok::comma);
+ Previous = Previous->Parent) {
+ if (Previous->is(tok::r_square))
+ Previous = Previous->MatchingParen;
+ if (Previous->Type == TT_BinaryOperator &&
+ Previous->isOneOf(tok::star, tok::amp)) {
+ Previous->Type = TT_PointerOrReference;
+ }
+ }
+ } else if (Current.isOneOf(tok::kw_return, tok::kw_throw) ||
+ (Current.is(tok::l_paren) && !Line.MustBeDeclaration &&
+ (!Current.Parent || Current.Parent->isNot(tok::kw_for)))) {
+ Contexts.back().IsExpression = true;
+ } else if (Current.isOneOf(tok::r_paren, tok::greater, tok::comma)) {
+ for (AnnotatedToken *Previous = Current.Parent;
+ Previous && Previous->isOneOf(tok::star, tok::amp);
+ Previous = Previous->Parent)
+ Previous->Type = TT_PointerOrReference;
+ } else if (Current.Parent &&
+ Current.Parent->Type == TT_CtorInitializerColon) {
+ Contexts.back().IsExpression = true;
+ } else if (Current.is(tok::kw_new)) {
+ Contexts.back().CanBeExpression = false;
+ }
+
+ if (Current.Type == TT_Unknown) {
+ if (Current.Parent && Current.is(tok::identifier) &&
+ ((Current.Parent->is(tok::identifier) &&
+ Current.Parent->FormatTok.Tok.getIdentifierInfo()
+ ->getPPKeywordID() == tok::pp_not_keyword) ||
+ isSimpleTypeSpecifier(*Current.Parent) ||
+ Current.Parent->Type == TT_PointerOrReference ||
+ Current.Parent->Type == TT_TemplateCloser)) {
+ Contexts.back().FirstStartOfName = &Current;
+ Current.Type = TT_StartOfName;
+ } else if (Current.isOneOf(tok::star, tok::amp, tok::ampamp)) {
+ Current.Type =
+ determineStarAmpUsage(Current, Contexts.back().IsExpression);
+ } else if (Current.isOneOf(tok::minus, tok::plus, tok::caret)) {
+ Current.Type = determinePlusMinusCaretUsage(Current);
+ } else if (Current.isOneOf(tok::minusminus, tok::plusplus)) {
+ Current.Type = determineIncrementUsage(Current);
+ } else if (Current.is(tok::exclaim)) {
+ Current.Type = TT_UnaryOperator;
+ } else if (isBinaryOperator(Current)) {
+ Current.Type = TT_BinaryOperator;
+ } else if (Current.is(tok::comment)) {
+ std::string Data(Lexer::getSpelling(Current.FormatTok.Tok, SourceMgr,
+ Lex.getLangOpts()));
+ if (StringRef(Data).startswith("//"))
+ Current.Type = TT_LineComment;
+ else
+ Current.Type = TT_BlockComment;
+ } else if (Current.is(tok::r_paren)) {
+ bool ParensNotExpr = !Current.Parent ||
+ Current.Parent->Type == TT_PointerOrReference ||
+ Current.Parent->Type == TT_TemplateCloser;
+ bool ParensCouldEndDecl =
+ !Current.Children.empty() &&
+ Current.Children[0].isOneOf(tok::equal, tok::semi, tok::l_brace);
+ bool IsSizeOfOrAlignOf =
+ Current.MatchingParen && Current.MatchingParen->Parent &&
+ Current.MatchingParen->Parent->isOneOf(tok::kw_sizeof,
+ tok::kw_alignof);
+ if (ParensNotExpr && !ParensCouldEndDecl && !IsSizeOfOrAlignOf &&
+ Contexts.back().IsExpression)
+ // FIXME: We need to get smarter and understand more cases of casts.
+ Current.Type = TT_CastRParen;
+ } else if (Current.is(tok::at) && Current.Children.size()) {
+ switch (Current.Children[0].FormatTok.Tok.getObjCKeywordID()) {
+ case tok::objc_interface:
+ case tok::objc_implementation:
+ case tok::objc_protocol:
+ Current.Type = TT_ObjCDecl;
+ break;
+ case tok::objc_property:
+ Current.Type = TT_ObjCProperty;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ /// \brief Return the type of the given token assuming it is * or &.
+ TokenType
+ determineStarAmpUsage(const AnnotatedToken &Tok, bool IsExpression) {
+ const AnnotatedToken *PrevToken = getPreviousToken(Tok);
+ if (PrevToken == NULL)
+ return TT_UnaryOperator;
+
+ const AnnotatedToken *NextToken = getNextToken(Tok);
+ if (NextToken == NULL)
+ return TT_Unknown;
+
+ if (PrevToken->is(tok::l_paren) && !IsExpression)
+ return TT_PointerOrReference;
+
+ if (PrevToken->isOneOf(tok::l_paren, tok::l_square, tok::l_brace,
+ tok::comma, tok::semi, tok::kw_return, tok::colon,
+ tok::equal) ||
+ PrevToken->Type == TT_BinaryOperator ||
+ PrevToken->Type == TT_UnaryOperator || PrevToken->Type == TT_CastRParen)
+ return TT_UnaryOperator;
+
+ if (NextToken->is(tok::l_square))
+ return TT_PointerOrReference;
+
+ if (PrevToken->FormatTok.Tok.isLiteral() ||
+ PrevToken->isOneOf(tok::r_paren, tok::r_square) ||
+ NextToken->FormatTok.Tok.isLiteral() || isUnaryOperator(*NextToken))
+ return TT_BinaryOperator;
+
+ // It is very unlikely that we are going to find a pointer or reference type
+ // definition on the RHS of an assignment.
+ if (IsExpression)
+ return TT_BinaryOperator;
+
+ return TT_PointerOrReference;
+ }
+
+ TokenType determinePlusMinusCaretUsage(const AnnotatedToken &Tok) {
+ const AnnotatedToken *PrevToken = getPreviousToken(Tok);
+ if (PrevToken == NULL)
+ return TT_UnaryOperator;
+
+ // Use heuristics to recognize unary operators.
+ if (PrevToken->isOneOf(tok::equal, tok::l_paren, tok::comma, tok::l_square,
+ tok::question, tok::colon, tok::kw_return,
+ tok::kw_case, tok::at, tok::l_brace))
+ return TT_UnaryOperator;
+
+ // There can't be two consecutive binary operators.
+ if (PrevToken->Type == TT_BinaryOperator)
+ return TT_UnaryOperator;
+
+ // Fall back to marking the token as binary operator.
+ return TT_BinaryOperator;
+ }
+
+ /// \brief Determine whether ++/-- are pre- or post-increments/-decrements.
+ TokenType determineIncrementUsage(const AnnotatedToken &Tok) {
+ const AnnotatedToken *PrevToken = getPreviousToken(Tok);
+ if (PrevToken == NULL)
+ return TT_UnaryOperator;
+ if (PrevToken->isOneOf(tok::r_paren, tok::r_square, tok::identifier))
+ return TT_TrailingUnaryOperator;
+
+ return TT_UnaryOperator;
+ }
+
+ // FIXME: This is copy&pasted from Sema. Put it in a common place and remove
+ // duplication.
+ /// \brief Determine whether the token kind starts a simple-type-specifier.
+ bool isSimpleTypeSpecifier(const AnnotatedToken &Tok) const {
+ switch (Tok.FormatTok.Tok.getKind()) {
+ case tok::kw_short:
+ case tok::kw_long:
+ case tok::kw___int64:
+ case tok::kw___int128:
+ case tok::kw_signed:
+ case tok::kw_unsigned:
+ case tok::kw_void:
+ case tok::kw_char:
+ case tok::kw_int:
+ case tok::kw_half:
+ case tok::kw_float:
+ case tok::kw_double:
+ case tok::kw_wchar_t:
+ case tok::kw_bool:
+ case tok::kw___underlying_type:
+ return true;
+ case tok::annot_typename:
+ case tok::kw_char16_t:
+ case tok::kw_char32_t:
+ case tok::kw_typeof:
+ case tok::kw_decltype:
+ return Lex.getLangOpts().CPlusPlus;
+ default:
+ break;
+ }
+ return false;
+ }
+
+ SmallVector<Context, 8> Contexts;
+
+ SourceManager &SourceMgr;
+ Lexer &Lex;
+ AnnotatedLine &Line;
+ AnnotatedToken *CurrentToken;
+ bool KeywordVirtualFound;
+ IdentifierInfo &Ident_in;
+};
+
+/// \brief Parses binary expressions by inserting fake parenthesis based on
+/// operator precedence.
+class ExpressionParser {
+public:
+ ExpressionParser(AnnotatedLine &Line) : Current(&Line.First) {}
+
+ /// \brief Parse expressions with the given operatore precedence.
+ void parse(int Precedence = 0) {
+ if (Precedence > prec::PointerToMember || Current == NULL)
+ return;
+
+ // Skip over "return" until we can properly parse it.
+ if (Current->is(tok::kw_return))
+ next();
+
+ // Eagerly consume trailing comments.
+ while (isTrailingComment(Current)) {
+ next();
+ }
+
+ AnnotatedToken *Start = Current;
+ bool OperatorFound = false;
+
+ while (Current) {
+ // Consume operators with higher precedence.
+ parse(prec::Level(Precedence + 1));
+
+ int CurrentPrecedence = 0;
+ if (Current) {
+ if (Current->Type == TT_ConditionalExpr)
+ CurrentPrecedence = 1 + (int) prec::Conditional;
+ else if (Current->is(tok::semi) || Current->Type == TT_InlineASMColon ||
+ Current->Type == TT_CtorInitializerColon)
+ CurrentPrecedence = 1;
+ else if (Current->Type == TT_BinaryOperator || Current->is(tok::comma))
+ CurrentPrecedence = 1 + (int) getPrecedence(*Current);
+ }
+
+ // At the end of the line or when an operator with higher precedence is
+ // found, insert fake parenthesis and return.
+ if (Current == NULL || closesScope(*Current) ||
+ (CurrentPrecedence != 0 && CurrentPrecedence < Precedence)) {
+ if (OperatorFound) {
+ ++Start->FakeLParens;
+ if (Current)
+ ++Current->Parent->FakeRParens;
+ }
+ return;
+ }
+
+ // Consume scopes: (), [], <> and {}
+ if (opensScope(*Current)) {
+ AnnotatedToken *Left = Current;
+ while (Current && !closesScope(*Current)) {
+ next();
+ parse();
+ }
+ // Remove fake parens that just duplicate the real parens.
+ if (Current && Left->Children[0].FakeLParens > 0 &&
+ Current->Parent->FakeRParens > 0) {
+ --Left->Children[0].FakeLParens;
+ --Current->Parent->FakeRParens;
+ }
+ next();
+ } else {
+ // Operator found.
+ if (CurrentPrecedence == Precedence)
+ OperatorFound = true;
+
+ next();
+ }
+ }
+ }
+
+private:
+ void next() {
+ if (Current != NULL)
+ Current = Current->Children.empty() ? NULL : &Current->Children[0];
+ }
+
+ AnnotatedToken *Current;
+};
+
+void TokenAnnotator::annotate(AnnotatedLine &Line) {
+ AnnotatingParser Parser(SourceMgr, Lex, Line, Ident_in);
+ Line.Type = Parser.parseLine();
+ if (Line.Type == LT_Invalid)
+ return;
+
+ ExpressionParser ExprParser(Line);
+ ExprParser.parse();
+
+ if (Line.First.Type == TT_ObjCMethodSpecifier)
+ Line.Type = LT_ObjCMethodDecl;
+ else if (Line.First.Type == TT_ObjCDecl)
+ Line.Type = LT_ObjCDecl;
+ else if (Line.First.Type == TT_ObjCProperty)
+ Line.Type = LT_ObjCProperty;
+
+ Line.First.SpacesRequiredBefore = 1;
+ Line.First.MustBreakBefore = Line.First.FormatTok.MustBreakBefore;
+ Line.First.CanBreakBefore = Line.First.MustBreakBefore;
+
+ Line.First.TotalLength = Line.First.FormatTok.TokenLength;
+}
+
+void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) {
+ if (Line.First.Children.empty())
+ return;
+ AnnotatedToken *Current = &Line.First.Children[0];
+ while (Current != NULL) {
+ if (Current->Type == TT_LineComment)
+ Current->SpacesRequiredBefore = Style.SpacesBeforeTrailingComments;
+ else
+ Current->SpacesRequiredBefore =
+ spaceRequiredBefore(Line, *Current) ? 1 : 0;
+
+ if (Current->FormatTok.MustBreakBefore) {
+ Current->MustBreakBefore = true;
+ } else if (Current->Type == TT_LineComment) {
+ Current->MustBreakBefore = Current->FormatTok.NewlinesBefore > 0;
+ } else if (isTrailingComment(Current->Parent) ||
+ (Current->is(tok::string_literal) &&
+ Current->Parent->is(tok::string_literal))) {
+ Current->MustBreakBefore = true;
+ } else if (Current->is(tok::lessless) && !Current->Children.empty() &&
+ Current->Parent->is(tok::string_literal) &&
+ Current->Children[0].is(tok::string_literal)) {
+ Current->MustBreakBefore = true;
+ } else {
+ Current->MustBreakBefore = false;
+ }
+ Current->CanBreakBefore =
+ Current->MustBreakBefore || canBreakBefore(Line, *Current);
+ if (Current->MustBreakBefore)
+ Current->TotalLength = Current->Parent->TotalLength + Style.ColumnLimit;
+ else
+ Current->TotalLength =
+ Current->Parent->TotalLength + Current->FormatTok.TokenLength +
+ Current->SpacesRequiredBefore;
+ // FIXME: Only calculate this if CanBreakBefore is true once static
+ // initializers etc. are sorted out.
+ // FIXME: Move magic numbers to a better place.
+ Current->SplitPenalty =
+ 20 * Current->BindingStrength + splitPenalty(Line, *Current);
+
+ Current = Current->Children.empty() ? NULL : &Current->Children[0];
+ }
+}
+
+unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
+ const AnnotatedToken &Tok) {
+ const AnnotatedToken &Left = *Tok.Parent;
+ const AnnotatedToken &Right = Tok;
+
+ if (Right.Type == TT_StartOfName) {
+ if (Line.First.is(tok::kw_for) && Right.PartOfMultiVariableDeclStmt)
+ return 3;
+ else if (Line.MightBeFunctionDecl && Right.BindingStrength == 1)
+ // FIXME: Clean up hack of using BindingStrength to find top-level names.
+ return Style.PenaltyReturnTypeOnItsOwnLine;
+ else
+ return 100;
+ }
+ if (Left.is(tok::equal) && Right.is(tok::l_brace))
+ return 150;
+ if (Left.is(tok::coloncolon))
+ return 500;
+
+ if (Left.Type == TT_RangeBasedForLoopColon ||
+ Left.Type == TT_InheritanceColon)
+ return 2;
+
+ if (Right.isOneOf(tok::arrow, tok::period)) {
+ if (Line.Type == LT_BuilderTypeCall)
+ return prec::PointerToMember;
+ if (Left.isOneOf(tok::r_paren, tok::r_square) && Left.MatchingParen &&
+ Left.MatchingParen->ParameterCount > 0)
+ return 20; // Should be smaller than breaking at a nested comma.
+ return 150;
+ }
+
+ // In for-loops, prefer breaking at ',' and ';'.
+ if (Line.First.is(tok::kw_for) && Left.is(tok::equal))
+ return 4;
+
+ if (Left.is(tok::semi))
+ return 0;
+ if (Left.is(tok::comma))
+ return 1;
+
+ // In Objective-C method expressions, prefer breaking before "param:" over
+ // breaking after it.
+ if (Right.Type == TT_ObjCSelectorName)
+ return 0;
+ if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr)
+ return 20;
+
+ if (opensScope(Left))
+ return Left.ParameterCount > 1 ? prec::Comma : 20;
+
+ if (Right.is(tok::lessless)) {
+ if (Left.is(tok::string_literal)) {
+ StringRef Content = StringRef(Left.FormatTok.Tok.getLiteralData(),
+ Left.FormatTok.TokenLength);
+ Content = Content.drop_back(1).drop_front(1).trim();
+ if (Content.size() > 1 &&
+ (Content.back() == ':' || Content.back() == '='))
+ return 100;
+ }
+ return prec::Shift;
+ }
+ if (Left.Type == TT_ConditionalExpr)
+ return prec::Conditional;
+ prec::Level Level = getPrecedence(Left);
+
+ if (Level != prec::Unknown)
+ return Level;
+
+ return 3;
+}
+
+bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
+ const AnnotatedToken &Left,
+ const AnnotatedToken &Right) {
+ if (Right.is(tok::hashhash))
+ return Left.is(tok::hash);
+ if (Left.isOneOf(tok::hashhash, tok::hash))
+ return Right.is(tok::hash);
+ if (Right.isOneOf(tok::r_paren, tok::semi, tok::comma))
+ return false;
+ if (Right.is(tok::less) &&
+ (Left.is(tok::kw_template) ||
+ (Line.Type == LT_ObjCDecl && Style.ObjCSpaceBeforeProtocolList)))
+ return true;
+ if (Left.is(tok::arrow) || Right.is(tok::arrow))
+ return false;
+ if (Left.isOneOf(tok::exclaim, tok::tilde))
+ return false;
+ if (Left.is(tok::at) &&
+ Right.isOneOf(tok::identifier, tok::string_literal, tok::char_constant,
+ tok::numeric_constant, tok::l_paren, tok::l_brace,
+ tok::kw_true, tok::kw_false))
+ return false;
+ if (Left.is(tok::coloncolon))
+ return false;
+ if (Right.is(tok::coloncolon))
+ return !Left.isOneOf(tok::identifier, tok::greater, tok::l_paren);
+ if (Left.is(tok::less) || Right.isOneOf(tok::greater, tok::less))
+ return false;
+ if (Right.Type == TT_PointerOrReference)
+ return Left.FormatTok.Tok.isLiteral() ||
+ ((Left.Type != TT_PointerOrReference) && Left.isNot(tok::l_paren) &&
+ !Style.PointerBindsToType);
+ if (Left.Type == TT_PointerOrReference)
+ return Right.FormatTok.Tok.isLiteral() ||
+ ((Right.Type != TT_PointerOrReference) &&
+ Right.isNot(tok::l_paren) && Style.PointerBindsToType &&
+ Left.Parent && Left.Parent->isNot(tok::l_paren));
+ if (Right.is(tok::star) && Left.is(tok::l_paren))
+ return false;
+ if (Left.is(tok::l_square))
+ return Left.Type == TT_ObjCArrayLiteral && Right.isNot(tok::r_square);
+ if (Right.is(tok::r_square))
+ return Right.Type == TT_ObjCArrayLiteral;
+ if (Right.is(tok::l_square) && Right.Type != TT_ObjCMethodExpr)
+ return false;
+ if (Left.is(tok::period) || Right.is(tok::period))
+ return false;
+ if (Left.is(tok::colon))
+ return Left.Type != TT_ObjCMethodExpr;
+ if (Right.is(tok::colon))
+ return Right.Type != TT_ObjCMethodExpr;
+ if (Left.is(tok::l_paren))
+ return false;
+ if (Right.is(tok::l_paren)) {
+ return Line.Type == LT_ObjCDecl ||
+ Left.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while, tok::kw_switch,
+ tok::kw_return, tok::kw_catch, tok::kw_new,
+ tok::kw_delete);
+ }
+ if (Left.is(tok::at) &&
+ Right.FormatTok.Tok.getObjCKeywordID() != tok::objc_not_keyword)
+ return false;
+ if (Left.is(tok::l_brace) && Right.is(tok::r_brace))
+ return false;
+ return true;
+}
+
+bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
+ const AnnotatedToken &Tok) {
+ if (Tok.FormatTok.Tok.getIdentifierInfo() &&
+ Tok.Parent->FormatTok.Tok.getIdentifierInfo())
+ return true; // Never ever merge two identifiers.
+ if (Line.Type == LT_ObjCMethodDecl) {
+ if (Tok.Parent->Type == TT_ObjCMethodSpecifier)
+ return true;
+ if (Tok.Parent->is(tok::r_paren) && Tok.is(tok::identifier))
+ // Don't space between ')' and <id>
+ return false;
+ }
+ if (Line.Type == LT_ObjCProperty &&
+ (Tok.is(tok::equal) || Tok.Parent->is(tok::equal)))
+ return false;
+
+ if (Tok.Parent->is(tok::comma))
+ return true;
+ if (Tok.is(tok::comma))
+ return false;
+ if (Tok.Type == TT_CtorInitializerColon || Tok.Type == TT_ObjCBlockLParen)
+ return true;
+ if (Tok.Parent->FormatTok.Tok.is(tok::kw_operator))
+ return false;
+ if (Tok.Type == TT_OverloadedOperatorLParen)
+ return false;
+ if (Tok.is(tok::colon))
+ return !Line.First.isOneOf(tok::kw_case, tok::kw_default) &&
+ !Tok.Children.empty() && Tok.Type != TT_ObjCMethodExpr;
+ if (Tok.is(tok::l_paren) && !Tok.Children.empty() &&
+ Tok.Children[0].Type == TT_PointerOrReference &&
+ !Tok.Children[0].Children.empty() &&
+ Tok.Children[0].Children[0].isNot(tok::r_paren) &&
+ Tok.Parent->isNot(tok::l_paren) &&
+ (Tok.Parent->Type != TT_PointerOrReference || Style.PointerBindsToType))
+ return true;
+ if (Tok.Parent->Type == TT_UnaryOperator || Tok.Parent->Type == TT_CastRParen)
+ return false;
+ if (Tok.Type == TT_UnaryOperator)
+ return !Tok.Parent->isOneOf(tok::l_paren, tok::l_square, tok::at) &&
+ (Tok.Parent->isNot(tok::colon) ||
+ Tok.Parent->Type != TT_ObjCMethodExpr);
+ if (Tok.Parent->is(tok::greater) && Tok.is(tok::greater)) {
+ return Tok.Type == TT_TemplateCloser &&
+ Tok.Parent->Type == TT_TemplateCloser &&
+ Style.Standard != FormatStyle::LS_Cpp11;
+ }
+ if (Tok.isOneOf(tok::arrowstar, tok::periodstar) ||
+ Tok.Parent->isOneOf(tok::arrowstar, tok::periodstar))
+ return false;
+ if (Tok.Type == TT_BinaryOperator || Tok.Parent->Type == TT_BinaryOperator)
+ return true;
+ if (Tok.Parent->Type == TT_TemplateCloser && Tok.is(tok::l_paren))
+ return false;
+ if (Tok.is(tok::less) && Line.First.is(tok::hash))
+ return true;
+ if (Tok.Type == TT_TrailingUnaryOperator)
+ return false;
+ return spaceRequiredBetween(Line, *Tok.Parent, Tok);
+}
+
+bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
+ const AnnotatedToken &Right) {
+ const AnnotatedToken &Left = *Right.Parent;
+ if (Right.Type == TT_StartOfName)
+ return true;
+ if (Right.is(tok::colon) && Right.Type == TT_ObjCMethodExpr)
+ return false;
+ if (Left.is(tok::colon) && Left.Type == TT_ObjCMethodExpr)
+ return true;
+ if (Right.Type == TT_ObjCSelectorName)
+ return true;
+ if (Left.ClosesTemplateDeclaration)
+ return true;
+ if (Right.Type == TT_ConditionalExpr || Right.is(tok::question))
+ return true;
+ if (Right.Type == TT_RangeBasedForLoopColon ||
+ Right.Type == TT_InheritanceColon)
+ return false;
+ if (Left.Type == TT_RangeBasedForLoopColon ||
+ Left.Type == TT_InheritanceColon)
+ return true;
+ if (Right.Type == TT_RangeBasedForLoopColon)
+ return false;
+ if (Left.Type == TT_PointerOrReference || Left.Type == TT_TemplateCloser ||
+ Left.Type == TT_UnaryOperator || Left.Type == TT_ConditionalExpr ||
+ Left.isOneOf(tok::question, tok::kw_operator))
+ return false;
+ if (Left.is(tok::equal) && Line.Type == LT_VirtualFunctionDecl)
+ return false;
+ if (Left.is(tok::l_paren) && Right.is(tok::l_paren) && Left.Parent &&
+ Left.Parent->is(tok::kw___attribute))
+ return false;
+
+ if (Right.Type == TT_LineComment)
+ // We rely on MustBreakBefore being set correctly here as we should not
+ // change the "binding" behavior of a comment.
+ return false;
+
+ // Allow breaking after a trailing 'const', e.g. after a method declaration,
+ // unless it is follow by ';', '{' or '='.
+ if (Left.is(tok::kw_const) && Left.Parent != NULL &&
+ Left.Parent->is(tok::r_paren))
+ return !Right.isOneOf(tok::l_brace, tok::semi, tok::equal);
+
+ if (Right.is(tok::kw___attribute))
+ return true;
+
+ // We only break before r_brace if there was a corresponding break before
+ // the l_brace, which is tracked by BreakBeforeClosingBrace.
+ if (Right.isOneOf(tok::r_brace, tok::r_paren, tok::greater))
+ return false;
+ if (Left.is(tok::identifier) && Right.is(tok::string_literal))
+ return true;
+ return (isBinaryOperator(Left) && Left.isNot(tok::lessless)) ||
+ Left.isOneOf(tok::comma, tok::coloncolon, tok::semi, tok::l_brace) ||
+ Right.isOneOf(tok::lessless, tok::arrow, tok::period, tok::colon) ||
+ (Left.is(tok::r_paren) && Left.Type != TT_CastRParen &&
+ Right.isOneOf(tok::identifier, tok::kw___attribute)) ||
+ (Left.is(tok::l_paren) && !Right.is(tok::r_paren)) ||
+ (Left.is(tok::l_square) && !Right.is(tok::r_square));
+}
+
+} // namespace format
+} // namespace clang
diff --git a/lib/Format/TokenAnnotator.h b/lib/Format/TokenAnnotator.h
new file mode 100644
index 0000000..c41ee33
--- /dev/null
+++ b/lib/Format/TokenAnnotator.h
@@ -0,0 +1,262 @@
+//===--- TokenAnnotator.h - Format C++ code ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements a token annotator, i.e. creates
+/// \c AnnotatedTokens out of \c FormatTokens with required extra information.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FORMAT_TOKEN_ANNOTATOR_H
+#define LLVM_CLANG_FORMAT_TOKEN_ANNOTATOR_H
+
+#include "UnwrappedLineParser.h"
+#include "clang/Basic/OperatorPrecedence.h"
+#include "clang/Format/Format.h"
+#include <string>
+
+namespace clang {
+class Lexer;
+class SourceManager;
+
+namespace format {
+
+enum TokenType {
+ TT_BinaryOperator,
+ TT_BlockComment,
+ TT_CastRParen,
+ TT_ConditionalExpr,
+ TT_CtorInitializerColon,
+ TT_ImplicitStringLiteral,
+ TT_InlineASMColon,
+ TT_InheritanceColon,
+ TT_LineComment,
+ TT_ObjCArrayLiteral,
+ TT_ObjCBlockLParen,
+ TT_ObjCDecl,
+ TT_ObjCForIn,
+ TT_ObjCMethodExpr,
+ TT_ObjCMethodSpecifier,
+ TT_ObjCProperty,
+ TT_ObjCSelectorName,
+ TT_OverloadedOperatorLParen,
+ TT_PointerOrReference,
+ TT_PureVirtualSpecifier,
+ TT_RangeBasedForLoopColon,
+ TT_StartOfName,
+ TT_TemplateCloser,
+ TT_TemplateOpener,
+ TT_TrailingUnaryOperator,
+ TT_UnaryOperator,
+ TT_Unknown
+};
+
+enum LineType {
+ LT_Invalid,
+ LT_Other,
+ LT_BuilderTypeCall,
+ LT_PreprocessorDirective,
+ LT_VirtualFunctionDecl,
+ LT_ObjCDecl, // An @interface, @implementation, or @protocol line.
+ LT_ObjCMethodDecl,
+ LT_ObjCProperty // An @property line.
+};
+
+class AnnotatedToken {
+public:
+ explicit AnnotatedToken(const FormatToken &FormatTok)
+ : FormatTok(FormatTok), Type(TT_Unknown), SpacesRequiredBefore(0),
+ CanBreakBefore(false), MustBreakBefore(false),
+ ClosesTemplateDeclaration(false), MatchingParen(NULL),
+ ParameterCount(0), BindingStrength(0), SplitPenalty(0),
+ LongestObjCSelectorName(0), Parent(NULL), FakeLParens(0),
+ FakeRParens(0), LastInChainOfCalls(false),
+ PartOfMultiVariableDeclStmt(false) {}
+
+ bool is(tok::TokenKind Kind) const { return FormatTok.Tok.is(Kind); }
+
+ bool isOneOf(tok::TokenKind K1, tok::TokenKind K2) const {
+ return is(K1) || is(K2);
+ }
+
+ bool isOneOf(tok::TokenKind K1, tok::TokenKind K2, tok::TokenKind K3) const {
+ return is(K1) || is(K2) || is(K3);
+ }
+
+ bool isOneOf(
+ tok::TokenKind K1, tok::TokenKind K2, tok::TokenKind K3,
+ tok::TokenKind K4, tok::TokenKind K5 = tok::NUM_TOKENS,
+ tok::TokenKind K6 = tok::NUM_TOKENS, tok::TokenKind K7 = tok::NUM_TOKENS,
+ tok::TokenKind K8 = tok::NUM_TOKENS, tok::TokenKind K9 = tok::NUM_TOKENS,
+ tok::TokenKind K10 = tok::NUM_TOKENS,
+ tok::TokenKind K11 = tok::NUM_TOKENS,
+ tok::TokenKind K12 = tok::NUM_TOKENS) const {
+ return is(K1) || is(K2) || is(K3) || is(K4) || is(K5) || is(K6) || is(K7) ||
+ is(K8) || is(K9) || is(K10) || is(K11) || is(K12);
+ }
+
+ bool isNot(tok::TokenKind Kind) const { return FormatTok.Tok.isNot(Kind); }
+
+ bool isObjCAtKeyword(tok::ObjCKeywordKind Kind) const {
+ return FormatTok.Tok.isObjCAtKeyword(Kind);
+ }
+
+ bool isAccessSpecifier(bool ColonRequired = true) const {
+ return isOneOf(tok::kw_public, tok::kw_protected, tok::kw_private) &&
+ (!ColonRequired ||
+ (!Children.empty() && Children[0].is(tok::colon)));
+ }
+
+ bool isObjCAccessSpecifier() const {
+ return is(tok::at) && !Children.empty() &&
+ (Children[0].isObjCAtKeyword(tok::objc_public) ||
+ Children[0].isObjCAtKeyword(tok::objc_protected) ||
+ Children[0].isObjCAtKeyword(tok::objc_package) ||
+ Children[0].isObjCAtKeyword(tok::objc_private));
+ }
+
+ FormatToken FormatTok;
+
+ TokenType Type;
+
+ unsigned SpacesRequiredBefore;
+ bool CanBreakBefore;
+ bool MustBreakBefore;
+
+ bool ClosesTemplateDeclaration;
+
+ AnnotatedToken *MatchingParen;
+
+ /// \brief Number of parameters, if this is "(", "[" or "<".
+ ///
+ /// This is initialized to 1 as we don't need to distinguish functions with
+ /// 0 parameters from functions with 1 parameter. Thus, we can simply count
+ /// the number of commas.
+ unsigned ParameterCount;
+
+ /// \brief The total length of the line up to and including this token.
+ unsigned TotalLength;
+
+ // FIXME: Come up with a 'cleaner' concept.
+ /// \brief The binding strength of a token. This is a combined value of
+ /// operator precedence, parenthesis nesting, etc.
+ unsigned BindingStrength;
+
+ /// \brief Penalty for inserting a line break before this token.
+ unsigned SplitPenalty;
+
+ /// \brief If this is the first ObjC selector name in an ObjC method
+ /// definition or call, this contains the length of the longest name.
+ unsigned LongestObjCSelectorName;
+
+ std::vector<AnnotatedToken> Children;
+ AnnotatedToken *Parent;
+
+ /// \brief Insert this many fake ( before this token for correct indentation.
+ unsigned FakeLParens;
+ /// \brief Insert this many fake ) after this token for correct indentation.
+ unsigned FakeRParens;
+
+ /// \brief Is this the last "." or "->" in a builder-type call?
+ bool LastInChainOfCalls;
+
+ /// \brief Is this token part of a \c DeclStmt defining multiple variables?
+ ///
+ /// Only set if \c Type == \c TT_StartOfName.
+ bool PartOfMultiVariableDeclStmt;
+
+ const AnnotatedToken *getPreviousNoneComment() const {
+ AnnotatedToken *Tok = Parent;
+ while (Tok != NULL && Tok->is(tok::comment))
+ Tok = Tok->Parent;
+ return Tok;
+ }
+};
+
+class AnnotatedLine {
+public:
+ AnnotatedLine(const UnwrappedLine &Line)
+ : First(Line.Tokens.front()), Level(Line.Level),
+ InPPDirective(Line.InPPDirective),
+ MustBeDeclaration(Line.MustBeDeclaration),
+ MightBeFunctionDecl(false) {
+ assert(!Line.Tokens.empty());
+ AnnotatedToken *Current = &First;
+ for (std::list<FormatToken>::const_iterator I = ++Line.Tokens.begin(),
+ E = Line.Tokens.end();
+ I != E; ++I) {
+ Current->Children.push_back(AnnotatedToken(*I));
+ Current->Children[0].Parent = Current;
+ Current = &Current->Children[0];
+ }
+ Last = Current;
+ }
+ AnnotatedLine(const AnnotatedLine &Other)
+ : First(Other.First), Type(Other.Type), Level(Other.Level),
+ InPPDirective(Other.InPPDirective),
+ MustBeDeclaration(Other.MustBeDeclaration),
+ MightBeFunctionDecl(Other.MightBeFunctionDecl) {
+ Last = &First;
+ while (!Last->Children.empty()) {
+ Last->Children[0].Parent = Last;
+ Last = &Last->Children[0];
+ }
+ }
+
+ AnnotatedToken First;
+ AnnotatedToken *Last;
+
+ LineType Type;
+ unsigned Level;
+ bool InPPDirective;
+ bool MustBeDeclaration;
+ bool MightBeFunctionDecl;
+};
+
+inline prec::Level getPrecedence(const AnnotatedToken &Tok) {
+ return getBinOpPrecedence(Tok.FormatTok.Tok.getKind(), true, true);
+}
+
+/// \brief Determines extra information about the tokens comprising an
+/// \c UnwrappedLine.
+class TokenAnnotator {
+public:
+ TokenAnnotator(const FormatStyle &Style, SourceManager &SourceMgr, Lexer &Lex,
+ IdentifierInfo &Ident_in)
+ : Style(Style), SourceMgr(SourceMgr), Lex(Lex), Ident_in(Ident_in) {
+ }
+
+ void annotate(AnnotatedLine &Line);
+ void calculateFormattingInformation(AnnotatedLine &Line);
+
+private:
+ /// \brief Calculate the penalty for splitting before \c Tok.
+ unsigned splitPenalty(const AnnotatedLine &Line, const AnnotatedToken &Tok);
+
+ bool spaceRequiredBetween(const AnnotatedLine &Line,
+ const AnnotatedToken &Left,
+ const AnnotatedToken &Right);
+
+ bool spaceRequiredBefore(const AnnotatedLine &Line,
+ const AnnotatedToken &Tok);
+
+ bool canBreakBefore(const AnnotatedLine &Line, const AnnotatedToken &Right);
+
+ const FormatStyle &Style;
+ SourceManager &SourceMgr;
+ Lexer &Lex;
+
+ // Contextual keywords:
+ IdentifierInfo &Ident_in;
+};
+
+} // end namespace format
+} // end namespace clang
+
+#endif // LLVM_CLANG_FORMAT_TOKEN_ANNOTATOR_H
diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp
new file mode 100644
index 0000000..89a391b
--- /dev/null
+++ b/lib/Format/UnwrappedLineParser.cpp
@@ -0,0 +1,858 @@
+//===--- UnwrappedLineParser.cpp - Format C++ code ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file contains the implementation of the UnwrappedLineParser,
+/// which turns a stream of tokens into UnwrappedLines.
+///
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "format-parser"
+
+#include "UnwrappedLineParser.h"
+#include "clang/Basic/Diagnostic.h"
+#include "llvm/Support/Debug.h"
+
+namespace clang {
+namespace format {
+
+class ScopedDeclarationState {
+public:
+ ScopedDeclarationState(UnwrappedLine &Line, std::vector<bool> &Stack,
+ bool MustBeDeclaration)
+ : Line(Line), Stack(Stack) {
+ Line.MustBeDeclaration = MustBeDeclaration;
+ Stack.push_back(MustBeDeclaration);
+ }
+ ~ScopedDeclarationState() {
+ Stack.pop_back();
+ if (!Stack.empty())
+ Line.MustBeDeclaration = Stack.back();
+ else
+ Line.MustBeDeclaration = true;
+ }
+private:
+ UnwrappedLine &Line;
+ std::vector<bool> &Stack;
+};
+
+class ScopedMacroState : public FormatTokenSource {
+public:
+ ScopedMacroState(UnwrappedLine &Line, FormatTokenSource *&TokenSource,
+ FormatToken &ResetToken)
+ : Line(Line), TokenSource(TokenSource), ResetToken(ResetToken),
+ PreviousLineLevel(Line.Level), PreviousTokenSource(TokenSource) {
+ TokenSource = this;
+ Line.Level = 0;
+ Line.InPPDirective = true;
+ }
+
+ ~ScopedMacroState() {
+ TokenSource = PreviousTokenSource;
+ ResetToken = Token;
+ Line.InPPDirective = false;
+ Line.Level = PreviousLineLevel;
+ }
+
+ virtual FormatToken getNextToken() {
+ // The \c UnwrappedLineParser guards against this by never calling
+ // \c getNextToken() after it has encountered the first eof token.
+ assert(!eof());
+ Token = PreviousTokenSource->getNextToken();
+ if (eof())
+ return createEOF();
+ return Token;
+ }
+
+private:
+ bool eof() { return Token.NewlinesBefore > 0 && Token.HasUnescapedNewline; }
+
+ FormatToken createEOF() {
+ FormatToken FormatTok;
+ FormatTok.Tok.startToken();
+ FormatTok.Tok.setKind(tok::eof);
+ return FormatTok;
+ }
+
+ UnwrappedLine &Line;
+ FormatTokenSource *&TokenSource;
+ FormatToken &ResetToken;
+ unsigned PreviousLineLevel;
+ FormatTokenSource *PreviousTokenSource;
+
+ FormatToken Token;
+};
+
+class ScopedLineState {
+public:
+ ScopedLineState(UnwrappedLineParser &Parser,
+ bool SwitchToPreprocessorLines = false)
+ : Parser(Parser), SwitchToPreprocessorLines(SwitchToPreprocessorLines) {
+ if (SwitchToPreprocessorLines)
+ Parser.CurrentLines = &Parser.PreprocessorDirectives;
+ PreBlockLine = Parser.Line.take();
+ Parser.Line.reset(new UnwrappedLine());
+ Parser.Line->Level = PreBlockLine->Level;
+ Parser.Line->InPPDirective = PreBlockLine->InPPDirective;
+ }
+
+ ~ScopedLineState() {
+ if (!Parser.Line->Tokens.empty()) {
+ Parser.addUnwrappedLine();
+ }
+ assert(Parser.Line->Tokens.empty());
+ Parser.Line.reset(PreBlockLine);
+ Parser.MustBreakBeforeNextToken = true;
+ if (SwitchToPreprocessorLines)
+ Parser.CurrentLines = &Parser.Lines;
+ }
+
+private:
+ UnwrappedLineParser &Parser;
+ const bool SwitchToPreprocessorLines;
+
+ UnwrappedLine *PreBlockLine;
+};
+
+UnwrappedLineParser::UnwrappedLineParser(
+ clang::DiagnosticsEngine &Diag, const FormatStyle &Style,
+ FormatTokenSource &Tokens, UnwrappedLineConsumer &Callback)
+ : Line(new UnwrappedLine), MustBreakBeforeNextToken(false),
+ CurrentLines(&Lines), Diag(Diag), Style(Style), Tokens(&Tokens),
+ Callback(Callback) {}
+
+bool UnwrappedLineParser::parse() {
+ DEBUG(llvm::dbgs() << "----\n");
+ readToken();
+ bool Error = parseFile();
+ for (std::vector<UnwrappedLine>::iterator I = Lines.begin(), E = Lines.end();
+ I != E; ++I) {
+ Callback.consumeUnwrappedLine(*I);
+ }
+
+ // Create line with eof token.
+ pushToken(FormatTok);
+ Callback.consumeUnwrappedLine(*Line);
+
+ return Error;
+}
+
+bool UnwrappedLineParser::parseFile() {
+ ScopedDeclarationState DeclarationState(
+ *Line, DeclarationScopeStack,
+ /*MustBeDeclaration=*/ !Line->InPPDirective);
+ bool Error = parseLevel(/*HasOpeningBrace=*/ false);
+ // Make sure to format the remaining tokens.
+ flushComments(true);
+ addUnwrappedLine();
+ return Error;
+}
+
+bool UnwrappedLineParser::parseLevel(bool HasOpeningBrace) {
+ bool Error = false;
+ do {
+ switch (FormatTok.Tok.getKind()) {
+ case tok::comment:
+ nextToken();
+ addUnwrappedLine();
+ break;
+ case tok::l_brace:
+ // FIXME: Add parameter whether this can happen - if this happens, we must
+ // be in a non-declaration context.
+ Error |= parseBlock(/*MustBeDeclaration=*/ false);
+ addUnwrappedLine();
+ break;
+ case tok::r_brace:
+ if (HasOpeningBrace) {
+ return false;
+ } else {
+ Diag.Report(FormatTok.Tok.getLocation(),
+ Diag.getCustomDiagID(clang::DiagnosticsEngine::Error,
+ "unexpected '}'"));
+ Error = true;
+ nextToken();
+ addUnwrappedLine();
+ }
+ break;
+ default:
+ parseStructuralElement();
+ break;
+ }
+ } while (!eof());
+ return Error;
+}
+
+bool UnwrappedLineParser::parseBlock(bool MustBeDeclaration,
+ unsigned AddLevels) {
+ assert(FormatTok.Tok.is(tok::l_brace) && "'{' expected");
+ nextToken();
+
+ addUnwrappedLine();
+
+ ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
+ MustBeDeclaration);
+ Line->Level += AddLevels;
+ parseLevel(/*HasOpeningBrace=*/ true);
+
+ if (!FormatTok.Tok.is(tok::r_brace)) {
+ Line->Level -= AddLevels;
+ return true;
+ }
+
+ nextToken(); // Munch the closing brace.
+ Line->Level -= AddLevels;
+ return false;
+}
+
+void UnwrappedLineParser::parsePPDirective() {
+ assert(FormatTok.Tok.is(tok::hash) && "'#' expected");
+ ScopedMacroState MacroState(*Line, Tokens, FormatTok);
+ nextToken();
+
+ if (FormatTok.Tok.getIdentifierInfo() == NULL) {
+ parsePPUnknown();
+ return;
+ }
+
+ switch (FormatTok.Tok.getIdentifierInfo()->getPPKeywordID()) {
+ case tok::pp_define:
+ parsePPDefine();
+ break;
+ default:
+ parsePPUnknown();
+ break;
+ }
+}
+
+void UnwrappedLineParser::parsePPDefine() {
+ nextToken();
+
+ if (FormatTok.Tok.getKind() != tok::identifier) {
+ parsePPUnknown();
+ return;
+ }
+ nextToken();
+ if (FormatTok.Tok.getKind() == tok::l_paren &&
+ FormatTok.WhiteSpaceLength == 0) {
+ parseParens();
+ }
+ addUnwrappedLine();
+ Line->Level = 1;
+
+ // Errors during a preprocessor directive can only affect the layout of the
+ // preprocessor directive, and thus we ignore them. An alternative approach
+ // would be to use the same approach we use on the file level (no
+ // re-indentation if there was a structural error) within the macro
+ // definition.
+ parseFile();
+}
+
+void UnwrappedLineParser::parsePPUnknown() {
+ do {
+ nextToken();
+ } while (!eof());
+ addUnwrappedLine();
+}
+
+void UnwrappedLineParser::parseStructuralElement() {
+ assert(!FormatTok.Tok.is(tok::l_brace));
+ int TokenNumber = 0;
+ switch (FormatTok.Tok.getKind()) {
+ case tok::at:
+ nextToken();
+ if (FormatTok.Tok.is(tok::l_brace)) {
+ parseBracedList();
+ break;
+ }
+ switch (FormatTok.Tok.getObjCKeywordID()) {
+ case tok::objc_public:
+ case tok::objc_protected:
+ case tok::objc_package:
+ case tok::objc_private:
+ return parseAccessSpecifier();
+ case tok::objc_interface:
+ case tok::objc_implementation:
+ return parseObjCInterfaceOrImplementation();
+ case tok::objc_protocol:
+ return parseObjCProtocol();
+ case tok::objc_end:
+ return; // Handled by the caller.
+ case tok::objc_optional:
+ case tok::objc_required:
+ nextToken();
+ addUnwrappedLine();
+ return;
+ default:
+ break;
+ }
+ break;
+ case tok::kw_namespace:
+ parseNamespace();
+ return;
+ case tok::kw_inline:
+ nextToken();
+ TokenNumber++;
+ if (FormatTok.Tok.is(tok::kw_namespace)) {
+ parseNamespace();
+ return;
+ }
+ break;
+ case tok::kw_public:
+ case tok::kw_protected:
+ case tok::kw_private:
+ parseAccessSpecifier();
+ return;
+ case tok::kw_if:
+ parseIfThenElse();
+ return;
+ case tok::kw_for:
+ case tok::kw_while:
+ parseForOrWhileLoop();
+ return;
+ case tok::kw_do:
+ parseDoWhile();
+ return;
+ case tok::kw_switch:
+ parseSwitch();
+ return;
+ case tok::kw_default:
+ nextToken();
+ parseLabel();
+ return;
+ case tok::kw_case:
+ parseCaseLabel();
+ return;
+ case tok::kw_return:
+ parseReturn();
+ return;
+ case tok::kw_extern:
+ nextToken();
+ if (FormatTok.Tok.is(tok::string_literal)) {
+ nextToken();
+ if (FormatTok.Tok.is(tok::l_brace)) {
+ parseBlock(/*MustBeDeclaration=*/ true, 0);
+ addUnwrappedLine();
+ return;
+ }
+ }
+ // In all other cases, parse the declaration.
+ break;
+ default:
+ break;
+ }
+ do {
+ ++TokenNumber;
+ switch (FormatTok.Tok.getKind()) {
+ case tok::at:
+ nextToken();
+ if (FormatTok.Tok.is(tok::l_brace))
+ parseBracedList();
+ break;
+ case tok::kw_enum:
+ parseEnum();
+ break;
+ case tok::kw_struct:
+ case tok::kw_union:
+ case tok::kw_class:
+ parseRecord();
+ // A record declaration or definition is always the start of a structural
+ // element.
+ break;
+ case tok::semi:
+ nextToken();
+ addUnwrappedLine();
+ return;
+ case tok::r_brace:
+ addUnwrappedLine();
+ return;
+ case tok::l_paren:
+ parseParens();
+ break;
+ case tok::l_brace:
+ // A block outside of parentheses must be the last part of a
+ // structural element.
+ // FIXME: Figure out cases where this is not true, and add projections for
+ // them (the one we know is missing are lambdas).
+ parseBlock(/*MustBeDeclaration=*/ false);
+ addUnwrappedLine();
+ return;
+ case tok::identifier:
+ nextToken();
+ if (TokenNumber == 1 && FormatTok.Tok.is(tok::colon)) {
+ parseLabel();
+ return;
+ }
+ break;
+ case tok::equal:
+ nextToken();
+ if (FormatTok.Tok.is(tok::l_brace)) {
+ parseBracedList();
+ }
+ break;
+ default:
+ nextToken();
+ break;
+ }
+ } while (!eof());
+}
+
+void UnwrappedLineParser::parseBracedList() {
+ nextToken();
+
+ do {
+ switch (FormatTok.Tok.getKind()) {
+ case tok::l_brace:
+ parseBracedList();
+ break;
+ case tok::r_brace:
+ nextToken();
+ return;
+ default:
+ nextToken();
+ break;
+ }
+ } while (!eof());
+}
+
+void UnwrappedLineParser::parseReturn() {
+ nextToken();
+
+ do {
+ switch (FormatTok.Tok.getKind()) {
+ case tok::l_brace:
+ parseBracedList();
+ break;
+ case tok::l_paren:
+ parseParens();
+ break;
+ case tok::r_brace:
+ // Assume missing ';'.
+ addUnwrappedLine();
+ return;
+ case tok::semi:
+ nextToken();
+ addUnwrappedLine();
+ return;
+ default:
+ nextToken();
+ break;
+ }
+ } while (!eof());
+}
+
+void UnwrappedLineParser::parseParens() {
+ assert(FormatTok.Tok.is(tok::l_paren) && "'(' expected.");
+ nextToken();
+ do {
+ switch (FormatTok.Tok.getKind()) {
+ case tok::l_paren:
+ parseParens();
+ break;
+ case tok::r_paren:
+ nextToken();
+ return;
+ case tok::l_brace: {
+ nextToken();
+ ScopedLineState LineState(*this);
+ ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack,
+ /*MustBeDeclaration=*/ false);
+ Line->Level += 1;
+ parseLevel(/*HasOpeningBrace=*/ true);
+ Line->Level -= 1;
+ break;
+ }
+ case tok::at:
+ nextToken();
+ if (FormatTok.Tok.is(tok::l_brace))
+ parseBracedList();
+ break;
+ default:
+ nextToken();
+ break;
+ }
+ } while (!eof());
+}
+
+void UnwrappedLineParser::parseIfThenElse() {
+ assert(FormatTok.Tok.is(tok::kw_if) && "'if' expected");
+ nextToken();
+ if (FormatTok.Tok.is(tok::l_paren))
+ parseParens();
+ bool NeedsUnwrappedLine = false;
+ if (FormatTok.Tok.is(tok::l_brace)) {
+ parseBlock(/*MustBeDeclaration=*/ false);
+ NeedsUnwrappedLine = true;
+ } else {
+ addUnwrappedLine();
+ ++Line->Level;
+ parseStructuralElement();
+ --Line->Level;
+ }
+ if (FormatTok.Tok.is(tok::kw_else)) {
+ nextToken();
+ if (FormatTok.Tok.is(tok::l_brace)) {
+ parseBlock(/*MustBeDeclaration=*/ false);
+ addUnwrappedLine();
+ } else if (FormatTok.Tok.is(tok::kw_if)) {
+ parseIfThenElse();
+ } else {
+ addUnwrappedLine();
+ ++Line->Level;
+ parseStructuralElement();
+ --Line->Level;
+ }
+ } else if (NeedsUnwrappedLine) {
+ addUnwrappedLine();
+ }
+}
+
+void UnwrappedLineParser::parseNamespace() {
+ assert(FormatTok.Tok.is(tok::kw_namespace) && "'namespace' expected");
+ nextToken();
+ if (FormatTok.Tok.is(tok::identifier))
+ nextToken();
+ if (FormatTok.Tok.is(tok::l_brace)) {
+ parseBlock(/*MustBeDeclaration=*/ true, 0);
+ // Munch the semicolon after a namespace. This is more common than one would
+ // think. Puttin the semicolon into its own line is very ugly.
+ if (FormatTok.Tok.is(tok::semi))
+ nextToken();
+ addUnwrappedLine();
+ }
+ // FIXME: Add error handling.
+}
+
+void UnwrappedLineParser::parseForOrWhileLoop() {
+ assert((FormatTok.Tok.is(tok::kw_for) || FormatTok.Tok.is(tok::kw_while)) &&
+ "'for' or 'while' expected");
+ nextToken();
+ if (FormatTok.Tok.is(tok::l_paren))
+ parseParens();
+ if (FormatTok.Tok.is(tok::l_brace)) {
+ parseBlock(/*MustBeDeclaration=*/ false);
+ addUnwrappedLine();
+ } else {
+ addUnwrappedLine();
+ ++Line->Level;
+ parseStructuralElement();
+ --Line->Level;
+ }
+}
+
+void UnwrappedLineParser::parseDoWhile() {
+ assert(FormatTok.Tok.is(tok::kw_do) && "'do' expected");
+ nextToken();
+ if (FormatTok.Tok.is(tok::l_brace)) {
+ parseBlock(/*MustBeDeclaration=*/ false);
+ } else {
+ addUnwrappedLine();
+ ++Line->Level;
+ parseStructuralElement();
+ --Line->Level;
+ }
+
+ // FIXME: Add error handling.
+ if (!FormatTok.Tok.is(tok::kw_while)) {
+ addUnwrappedLine();
+ return;
+ }
+
+ nextToken();
+ parseStructuralElement();
+}
+
+void UnwrappedLineParser::parseLabel() {
+ if (FormatTok.Tok.isNot(tok::colon))
+ return;
+ nextToken();
+ unsigned OldLineLevel = Line->Level;
+ if (Line->Level > 1 || (!Line->InPPDirective && Line->Level > 0))
+ --Line->Level;
+ if (CommentsBeforeNextToken.empty() && FormatTok.Tok.is(tok::l_brace)) {
+ parseBlock(/*MustBeDeclaration=*/ false);
+ if (FormatTok.Tok.is(tok::kw_break))
+ parseStructuralElement(); // "break;" after "}" goes on the same line.
+ }
+ addUnwrappedLine();
+ Line->Level = OldLineLevel;
+}
+
+void UnwrappedLineParser::parseCaseLabel() {
+ assert(FormatTok.Tok.is(tok::kw_case) && "'case' expected");
+ // FIXME: fix handling of complex expressions here.
+ do {
+ nextToken();
+ } while (!eof() && !FormatTok.Tok.is(tok::colon));
+ parseLabel();
+}
+
+void UnwrappedLineParser::parseSwitch() {
+ assert(FormatTok.Tok.is(tok::kw_switch) && "'switch' expected");
+ nextToken();
+ if (FormatTok.Tok.is(tok::l_paren))
+ parseParens();
+ if (FormatTok.Tok.is(tok::l_brace)) {
+ parseBlock(/*MustBeDeclaration=*/ false, Style.IndentCaseLabels ? 2 : 1);
+ addUnwrappedLine();
+ } else {
+ addUnwrappedLine();
+ Line->Level += (Style.IndentCaseLabels ? 2 : 1);
+ parseStructuralElement();
+ Line->Level -= (Style.IndentCaseLabels ? 2 : 1);
+ }
+}
+
+void UnwrappedLineParser::parseAccessSpecifier() {
+ nextToken();
+ // Otherwise, we don't know what it is, and we'd better keep the next token.
+ if (FormatTok.Tok.is(tok::colon))
+ nextToken();
+ addUnwrappedLine();
+}
+
+void UnwrappedLineParser::parseEnum() {
+ nextToken();
+ if (FormatTok.Tok.is(tok::identifier) ||
+ FormatTok.Tok.is(tok::kw___attribute) ||
+ FormatTok.Tok.is(tok::kw___declspec)) {
+ nextToken();
+ // We can have macros or attributes in between 'enum' and the enum name.
+ if (FormatTok.Tok.is(tok::l_paren)) {
+ parseParens();
+ }
+ if (FormatTok.Tok.is(tok::identifier))
+ nextToken();
+ }
+ if (FormatTok.Tok.is(tok::l_brace)) {
+ nextToken();
+ addUnwrappedLine();
+ ++Line->Level;
+ do {
+ switch (FormatTok.Tok.getKind()) {
+ case tok::l_paren:
+ parseParens();
+ break;
+ case tok::r_brace:
+ addUnwrappedLine();
+ nextToken();
+ --Line->Level;
+ return;
+ case tok::comma:
+ nextToken();
+ addUnwrappedLine();
+ break;
+ default:
+ nextToken();
+ break;
+ }
+ } while (!eof());
+ }
+ // We fall through to parsing a structural element afterwards, so that in
+ // enum A {} n, m;
+ // "} n, m;" will end up in one unwrapped line.
+}
+
+void UnwrappedLineParser::parseRecord() {
+ nextToken();
+ if (FormatTok.Tok.is(tok::identifier) ||
+ FormatTok.Tok.is(tok::kw___attribute) ||
+ FormatTok.Tok.is(tok::kw___declspec)) {
+ nextToken();
+ // We can have macros or attributes in between 'class' and the class name.
+ if (FormatTok.Tok.is(tok::l_paren)) {
+ parseParens();
+ }
+ // The actual identifier can be a nested name specifier, and in macros
+ // it is often token-pasted.
+ while (FormatTok.Tok.is(tok::identifier) ||
+ FormatTok.Tok.is(tok::coloncolon) || FormatTok.Tok.is(tok::hashhash))
+ nextToken();
+
+ // Note that parsing away template declarations here leads to incorrectly
+ // accepting function declarations as record declarations.
+ // In general, we cannot solve this problem. Consider:
+ // class A<int> B() {}
+ // which can be a function definition or a class definition when B() is a
+ // macro. If we find enough real-world cases where this is a problem, we
+ // can parse for the 'template' keyword in the beginning of the statement,
+ // and thus rule out the record production in case there is no template
+ // (this would still leave us with an ambiguity between template function
+ // and class declarations).
+ if (FormatTok.Tok.is(tok::colon) || FormatTok.Tok.is(tok::less)) {
+ while (!eof() && FormatTok.Tok.isNot(tok::l_brace)) {
+ if (FormatTok.Tok.is(tok::semi))
+ return;
+ nextToken();
+ }
+ }
+ }
+ if (FormatTok.Tok.is(tok::l_brace))
+ parseBlock(/*MustBeDeclaration=*/ true);
+ // We fall through to parsing a structural element afterwards, so
+ // class A {} n, m;
+ // will end up in one unwrapped line.
+}
+
+void UnwrappedLineParser::parseObjCProtocolList() {
+ assert(FormatTok.Tok.is(tok::less) && "'<' expected.");
+ do
+ nextToken();
+ while (!eof() && FormatTok.Tok.isNot(tok::greater));
+ nextToken(); // Skip '>'.
+}
+
+void UnwrappedLineParser::parseObjCUntilAtEnd() {
+ do {
+ if (FormatTok.Tok.isObjCAtKeyword(tok::objc_end)) {
+ nextToken();
+ addUnwrappedLine();
+ break;
+ }
+ parseStructuralElement();
+ } while (!eof());
+}
+
+void UnwrappedLineParser::parseObjCInterfaceOrImplementation() {
+ nextToken();
+ nextToken(); // interface name
+
+ // @interface can be followed by either a base class, or a category.
+ if (FormatTok.Tok.is(tok::colon)) {
+ nextToken();
+ nextToken(); // base class name
+ } else if (FormatTok.Tok.is(tok::l_paren))
+ // Skip category, if present.
+ parseParens();
+
+ if (FormatTok.Tok.is(tok::less))
+ parseObjCProtocolList();
+
+ // If instance variables are present, keep the '{' on the first line too.
+ if (FormatTok.Tok.is(tok::l_brace))
+ parseBlock(/*MustBeDeclaration=*/ true);
+
+ // With instance variables, this puts '}' on its own line. Without instance
+ // variables, this ends the @interface line.
+ addUnwrappedLine();
+
+ parseObjCUntilAtEnd();
+}
+
+void UnwrappedLineParser::parseObjCProtocol() {
+ nextToken();
+ nextToken(); // protocol name
+
+ if (FormatTok.Tok.is(tok::less))
+ parseObjCProtocolList();
+
+ // Check for protocol declaration.
+ if (FormatTok.Tok.is(tok::semi)) {
+ nextToken();
+ return addUnwrappedLine();
+ }
+
+ addUnwrappedLine();
+ parseObjCUntilAtEnd();
+}
+
+void UnwrappedLineParser::addUnwrappedLine() {
+ if (Line->Tokens.empty())
+ return;
+ DEBUG({
+ llvm::dbgs() << "Line(" << Line->Level << ")"
+ << (Line->InPPDirective ? " MACRO" : "") << ": ";
+ for (std::list<FormatToken>::iterator I = Line->Tokens.begin(),
+ E = Line->Tokens.end();
+ I != E; ++I) {
+ llvm::dbgs() << I->Tok.getName() << " ";
+
+ }
+ llvm::dbgs() << "\n";
+ });
+ CurrentLines->push_back(*Line);
+ Line->Tokens.clear();
+ if (CurrentLines == &Lines && !PreprocessorDirectives.empty()) {
+ for (std::vector<UnwrappedLine>::iterator
+ I = PreprocessorDirectives.begin(),
+ E = PreprocessorDirectives.end();
+ I != E; ++I) {
+ CurrentLines->push_back(*I);
+ }
+ PreprocessorDirectives.clear();
+ }
+}
+
+bool UnwrappedLineParser::eof() const { return FormatTok.Tok.is(tok::eof); }
+
+void UnwrappedLineParser::flushComments(bool NewlineBeforeNext) {
+ bool JustComments = Line->Tokens.empty();
+ for (SmallVectorImpl<FormatToken>::const_iterator
+ I = CommentsBeforeNextToken.begin(),
+ E = CommentsBeforeNextToken.end();
+ I != E; ++I) {
+ if (I->NewlinesBefore && JustComments) {
+ addUnwrappedLine();
+ }
+ pushToken(*I);
+ }
+ if (NewlineBeforeNext && JustComments) {
+ addUnwrappedLine();
+ }
+ CommentsBeforeNextToken.clear();
+}
+
+void UnwrappedLineParser::nextToken() {
+ if (eof())
+ return;
+ flushComments(FormatTok.NewlinesBefore > 0);
+ pushToken(FormatTok);
+ readToken();
+}
+
+void UnwrappedLineParser::readToken() {
+ bool CommentsInCurrentLine = true;
+ do {
+ FormatTok = Tokens->getNextToken();
+ while (!Line->InPPDirective && FormatTok.Tok.is(tok::hash) &&
+ ((FormatTok.NewlinesBefore > 0 && FormatTok.HasUnescapedNewline) ||
+ FormatTok.IsFirst)) {
+ // If there is an unfinished unwrapped line, we flush the preprocessor
+ // directives only after that unwrapped line was finished later.
+ bool SwitchToPreprocessorLines =
+ !Line->Tokens.empty() && CurrentLines == &Lines;
+ ScopedLineState BlockState(*this, SwitchToPreprocessorLines);
+ // Comments stored before the preprocessor directive need to be output
+ // before the preprocessor directive, at the same level as the
+ // preprocessor directive, as we consider them to apply to the directive.
+ flushComments(FormatTok.NewlinesBefore > 0);
+ parsePPDirective();
+ }
+ if (!FormatTok.Tok.is(tok::comment))
+ return;
+ if (FormatTok.NewlinesBefore > 0 || FormatTok.IsFirst) {
+ CommentsInCurrentLine = false;
+ }
+ if (CommentsInCurrentLine) {
+ pushToken(FormatTok);
+ } else {
+ CommentsBeforeNextToken.push_back(FormatTok);
+ }
+ } while (!eof());
+}
+
+void UnwrappedLineParser::pushToken(const FormatToken &Tok) {
+ Line->Tokens.push_back(Tok);
+ if (MustBreakBeforeNextToken) {
+ Line->Tokens.back().MustBreakBefore = true;
+ MustBreakBeforeNextToken = false;
+ }
+}
+
+} // end namespace format
+} // end namespace clang
diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h
new file mode 100644
index 0000000..f4fecc5
--- /dev/null
+++ b/lib/Format/UnwrappedLineParser.h
@@ -0,0 +1,201 @@
+//===--- UnwrappedLineParser.h - Format C++ code ----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file contains the declaration of the UnwrappedLineParser,
+/// which turns a stream of tokens into UnwrappedLines.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FORMAT_UNWRAPPED_LINE_PARSER_H
+#define LLVM_CLANG_FORMAT_UNWRAPPED_LINE_PARSER_H
+
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Format/Format.h"
+#include "clang/Lex/Lexer.h"
+#include <list>
+
+namespace clang {
+
+class DiagnosticsEngine;
+
+namespace format {
+
+/// \brief A wrapper around a \c Token storing information about the
+/// whitespace characters preceeding it.
+struct FormatToken {
+ FormatToken()
+ : NewlinesBefore(0), HasUnescapedNewline(false), WhiteSpaceLength(0),
+ LastNewlineOffset(0), TokenLength(0), IsFirst(false),
+ MustBreakBefore(false) {}
+
+ /// \brief The \c Token.
+ Token Tok;
+
+ /// \brief The number of newlines immediately before the \c Token.
+ ///
+ /// This can be used to determine what the user wrote in the original code
+ /// and thereby e.g. leave an empty line between two function definitions.
+ unsigned NewlinesBefore;
+
+ /// \brief Whether there is at least one unescaped newline before the \c
+ /// Token.
+ bool HasUnescapedNewline;
+
+ /// \brief The location of the start of the whitespace immediately preceeding
+ /// the \c Token.
+ ///
+ /// Used together with \c WhiteSpaceLength to create a \c Replacement.
+ SourceLocation WhiteSpaceStart;
+
+ /// \brief The length in characters of the whitespace immediately preceeding
+ /// the \c Token.
+ unsigned WhiteSpaceLength;
+
+ /// \brief The offset just past the last '\n' in this token's leading
+ /// whitespace (relative to \c WhiteSpaceStart). 0 if there is no '\n'.
+ unsigned LastNewlineOffset;
+
+ /// \brief The length of the non-whitespace parts of the token. This is
+ /// necessary because we need to handle escaped newlines that are stored
+ /// with the token.
+ unsigned TokenLength;
+
+ /// \brief Indicates that this is the first token.
+ bool IsFirst;
+
+ /// \brief Whether there must be a line break before this token.
+ ///
+ /// This happens for example when a preprocessor directive ended directly
+ /// before the token.
+ bool MustBreakBefore;
+};
+
+/// \brief An unwrapped line is a sequence of \c Token, that we would like to
+/// put on a single line if there was no column limit.
+///
+/// This is used as a main interface between the \c UnwrappedLineParser and the
+/// \c UnwrappedLineFormatter. The key property is that changing the formatting
+/// within an unwrapped line does not affect any other unwrapped lines.
+struct UnwrappedLine {
+ UnwrappedLine() : Level(0), InPPDirective(false), MustBeDeclaration(false) {
+ }
+
+ // FIXME: Don't use std::list here.
+ /// \brief The \c Tokens comprising this \c UnwrappedLine.
+ std::list<FormatToken> Tokens;
+
+ /// \brief The indent level of the \c UnwrappedLine.
+ unsigned Level;
+
+ /// \brief Whether this \c UnwrappedLine is part of a preprocessor directive.
+ bool InPPDirective;
+
+ bool MustBeDeclaration;
+};
+
+class UnwrappedLineConsumer {
+public:
+ virtual ~UnwrappedLineConsumer() {
+ }
+ virtual void consumeUnwrappedLine(const UnwrappedLine &Line) = 0;
+};
+
+class FormatTokenSource {
+public:
+ virtual ~FormatTokenSource() {
+ }
+ virtual FormatToken getNextToken() = 0;
+};
+
+class UnwrappedLineParser {
+public:
+ UnwrappedLineParser(clang::DiagnosticsEngine &Diag, const FormatStyle &Style,
+ FormatTokenSource &Tokens,
+ UnwrappedLineConsumer &Callback);
+
+ /// Returns true in case of a structural error.
+ bool parse();
+
+private:
+ bool parseFile();
+ bool parseLevel(bool HasOpeningBrace);
+ bool parseBlock(bool MustBeDeclaration, unsigned AddLevels = 1);
+ void parsePPDirective();
+ void parsePPDefine();
+ void parsePPUnknown();
+ void parseStructuralElement();
+ void parseBracedList();
+ void parseReturn();
+ void parseParens();
+ void parseIfThenElse();
+ void parseForOrWhileLoop();
+ void parseDoWhile();
+ void parseLabel();
+ void parseCaseLabel();
+ void parseSwitch();
+ void parseNamespace();
+ void parseAccessSpecifier();
+ void parseEnum();
+ void parseRecord();
+ void parseObjCProtocolList();
+ void parseObjCUntilAtEnd();
+ void parseObjCInterfaceOrImplementation();
+ void parseObjCProtocol();
+ void addUnwrappedLine();
+ bool eof() const;
+ void nextToken();
+ void readToken();
+ void flushComments(bool NewlineBeforeNext);
+ void pushToken(const FormatToken &Tok);
+
+ // FIXME: We are constantly running into bugs where Line.Level is incorrectly
+ // subtracted from beyond 0. Introduce a method to subtract from Line.Level
+ // and use that everywhere in the Parser.
+ OwningPtr<UnwrappedLine> Line;
+
+ // Comments are sorted into unwrapped lines by whether they are in the same
+ // line as the previous token, or not. If not, they belong to the next token.
+ // Since the next token might already be in a new unwrapped line, we need to
+ // store the comments belonging to that token.
+ SmallVector<FormatToken, 1> CommentsBeforeNextToken;
+ FormatToken FormatTok;
+ bool MustBreakBeforeNextToken;
+
+ // The parsed lines. Only added to through \c CurrentLines.
+ std::vector<UnwrappedLine> Lines;
+
+ // Preprocessor directives are parsed out-of-order from other unwrapped lines.
+ // Thus, we need to keep a list of preprocessor directives to be reported
+ // after an unwarpped line that has been started was finished.
+ std::vector<UnwrappedLine> PreprocessorDirectives;
+
+ // New unwrapped lines are added via CurrentLines.
+ // Usually points to \c &Lines. While parsing a preprocessor directive when
+ // there is an unfinished previous unwrapped line, will point to
+ // \c &PreprocessorDirectives.
+ std::vector<UnwrappedLine> *CurrentLines;
+
+ // We store for each line whether it must be a declaration depending on
+ // whether we are in a compound statement or not.
+ std::vector<bool> DeclarationScopeStack;
+
+ clang::DiagnosticsEngine &Diag;
+ const FormatStyle &Style;
+ FormatTokenSource *Tokens;
+ UnwrappedLineConsumer &Callback;
+
+ friend class ScopedLineState;
+};
+
+} // end namespace format
+} // end namespace clang
+
+#endif // LLVM_CLANG_FORMAT_UNWRAPPED_LINE_PARSER_H
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
index 882d400..4a63d76 100644
--- a/lib/Frontend/ASTConsumers.cpp
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -12,19 +12,19 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/ASTConsumers.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/SourceManager.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/RecursiveASTVisitor.h"
-#include "llvm/Module.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/IR/Module.h"
#include "llvm/Support/Path.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -59,9 +59,12 @@ namespace {
bool TraverseDecl(Decl *D) {
if (D != NULL && filterMatches(D)) {
- Out.changeColor(llvm::raw_ostream::BLUE) <<
- (Dump ? "Dumping " : "Printing ") << getName(D) << ":\n";
- Out.resetColor();
+ bool ShowColors = Out.has_colors();
+ if (ShowColors)
+ Out.changeColor(raw_ostream::BLUE);
+ Out << (Dump ? "Dumping " : "Printing ") << getName(D) << ":\n";
+ if (ShowColors)
+ Out.resetColor();
if (Dump)
D->dump(Out);
else
@@ -101,7 +104,8 @@ namespace {
bool shouldWalkTypesOfTypeLocs() const { return false; }
virtual bool VisitNamedDecl(NamedDecl *D) {
- Out << D->getQualifiedNameAsString() << "\n";
+ D->printQualifiedName(Out);
+ Out << '\n';
return true;
}
@@ -459,6 +463,10 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "<class template> " << *CTD << '\n';
break;
}
+ case Decl::OMPThreadPrivate: {
+ Out << "<omp threadprivate> " << '"' << *I << "\"\n";
+ break;
+ }
default:
Out << "DeclKind: " << DK << '"' << *I << "\"\n";
llvm_unreachable("decl unhandled");
diff --git a/lib/Frontend/ASTMerge.cpp b/lib/Frontend/ASTMerge.cpp
index 31b1df4..bfb3083 100644
--- a/lib/Frontend/ASTMerge.cpp
+++ b/lib/Frontend/ASTMerge.cpp
@@ -7,12 +7,12 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Frontend/ASTUnit.h"
-#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Frontend/FrontendActions.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/ASTImporter.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
using namespace clang;
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 5576854..c1115ae 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -12,40 +12,40 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/ASTUnit.h"
-#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclVisitor.h"
-#include "clang/AST/TypeOrdering.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/TypeOrdering.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/FrontendOptions.h"
#include "clang/Frontend/MultiplexConsumer.h"
#include "clang/Frontend/Utils.h"
-#include "clang/Serialization/ASTReader.h"
-#include "clang/Serialization/ASTWriter.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
-#include "clang/Basic/TargetOptions.h"
-#include "clang/Basic/TargetInfo.h"
-#include "clang/Basic/Diagnostic.h"
+#include "clang/Serialization/ASTReader.h"
+#include "clang/Serialization/ASTWriter.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Atomic.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Host.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/Timer.h"
+#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Mutex.h"
#include "llvm/Support/MutexGuard.h"
-#include "llvm/Support/CrashRecoveryContext.h"
-#include <cstdlib>
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
#include <cstdio>
+#include <cstdlib>
#include <sys/stat.h>
using namespace clang;
@@ -103,7 +103,7 @@ static llvm::sys::SmartMutex<false> &getOnDiskMutex() {
return M;
}
-static void cleanupOnDiskMapAtExit(void);
+static void cleanupOnDiskMapAtExit();
typedef llvm::DenseMap<const ASTUnit *, OnDiskData *> OnDiskDataMap;
static OnDiskDataMap &getOnDiskDataMap() {
@@ -116,7 +116,7 @@ static OnDiskDataMap &getOnDiskDataMap() {
return M;
}
-static void cleanupOnDiskMapAtExit(void) {
+static void cleanupOnDiskMapAtExit() {
// Use the mutex because there can be an alive thread destroying an ASTUnit.
llvm::MutexGuard Guard(getOnDiskMutex());
OnDiskDataMap &M = getOnDiskDataMap();
@@ -155,7 +155,7 @@ static void removeOnDiskEntry(const ASTUnit *AU) {
}
}
-static void setPreambleFile(const ASTUnit *AU, llvm::StringRef preambleFile) {
+static void setPreambleFile(const ASTUnit *AU, StringRef preambleFile) {
getOnDiskData(AU).PreambleFile = preambleFile;
}
@@ -270,7 +270,7 @@ void ASTUnit::setPreprocessor(Preprocessor *pp) { PP = pp; }
/// \brief Determine the set of code-completion contexts in which this
/// declaration should be shown.
-static unsigned getDeclShowContexts(NamedDecl *ND,
+static unsigned getDeclShowContexts(const NamedDecl *ND,
const LangOptions &LangOpts,
bool &IsNestedNameSpecifier) {
IsNestedNameSpecifier = false;
@@ -310,9 +310,9 @@ static unsigned getDeclShowContexts(NamedDecl *ND,
Contexts |= (1LL << CodeCompletionContext::CCC_EnumTag);
// Part of the nested-name-specifier in C++0x.
- if (LangOpts.CPlusPlus0x)
+ if (LangOpts.CPlusPlus11)
IsNestedNameSpecifier = true;
- } else if (RecordDecl *Record = dyn_cast<RecordDecl>(ND)) {
+ } else if (const RecordDecl *Record = dyn_cast<RecordDecl>(ND)) {
if (Record->isUnion())
Contexts |= (1LL << CodeCompletionContext::CCC_UnionTag);
else
@@ -356,8 +356,9 @@ void ASTUnit::CacheCodeCompletionResults() {
typedef CodeCompletionResult Result;
SmallVector<Result, 8> Results;
CachedCompletionAllocator = new GlobalCodeCompletionAllocator;
+ CodeCompletionTUInfo CCTUInfo(CachedCompletionAllocator);
TheSema->GatherGlobalCodeCompletions(*CachedCompletionAllocator,
- getCodeCompletionTUInfo(), Results);
+ CCTUInfo, Results);
// Translate global code completions into cached completions.
llvm::DenseMap<CanQualType, unsigned> CompletionTypes;
@@ -369,7 +370,7 @@ void ASTUnit::CacheCodeCompletionResults() {
CachedCodeCompletionResult CachedResult;
CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema,
*CachedCompletionAllocator,
- getCodeCompletionTUInfo(),
+ CCTUInfo,
IncludeBriefCommentsInCodeCompletion);
CachedResult.ShowInContexts = getDeclShowContexts(Results[I].Declaration,
Ctx->getLangOpts(),
@@ -435,7 +436,7 @@ void ASTUnit::CacheCodeCompletionResults() {
CachedResult.Completion
= Results[I].CreateCodeCompletionString(*TheSema,
*CachedCompletionAllocator,
- getCodeCompletionTUInfo(),
+ CCTUInfo,
IncludeBriefCommentsInCodeCompletion);
CachedResult.ShowInContexts = RemainingContexts;
CachedResult.Priority = CCP_NestedNameSpecifier;
@@ -458,7 +459,7 @@ void ASTUnit::CacheCodeCompletionResults() {
CachedResult.Completion
= Results[I].CreateCodeCompletionString(*TheSema,
*CachedCompletionAllocator,
- getCodeCompletionTUInfo(),
+ CCTUInfo,
IncludeBriefCommentsInCodeCompletion);
CachedResult.ShowInContexts
= (1LL << CodeCompletionContext::CCC_TopLevel)
@@ -541,8 +542,8 @@ public:
return false;
this->TargetOpts = new TargetOptions(TargetOpts);
- Target = TargetInfo::CreateTargetInfo(PP.getDiagnostics(),
- *this->TargetOpts);
+ Target = TargetInfo::CreateTargetInfo(PP.getDiagnostics(),
+ &*this->TargetOpts);
updated();
return false;
@@ -572,6 +573,11 @@ private:
// Initialize the ASTContext
Context.InitBuiltinTypes(*Target);
+
+ // We didn't have access to the comment options when the ASTContext was
+ // constructed, so register them now.
+ Context.getCommentCommandTraits().registerCommentOptions(
+ LangOpt.CommentOpts);
}
};
@@ -655,8 +661,7 @@ void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> &Diags,
if (CaptureDiagnostics)
Client = new StoredDiagnosticConsumer(AST.StoredDiagnostics);
Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions(),
- ArgEnd-ArgBegin,
- ArgBegin, Client,
+ Client,
/*ShouldOwnClient=*/true,
/*ShouldCloneClient=*/false);
} else if (CaptureDiagnostics) {
@@ -791,11 +796,12 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
Counter));
switch (Reader->ReadAST(Filename, serialization::MK_MainFile,
- ASTReader::ARR_None)) {
+ SourceLocation(), ASTReader::ARR_None)) {
case ASTReader::Success:
break;
case ASTReader::Failure:
+ case ASTReader::Missing:
case ASTReader::OutOfDate:
case ASTReader::VersionMismatch:
case ASTReader::ConfigurationMismatch:
@@ -842,7 +848,8 @@ class MacroDefinitionTrackerPPCallbacks : public PPCallbacks {
public:
explicit MacroDefinitionTrackerPPCallbacks(unsigned &Hash) : Hash(Hash) { }
- virtual void MacroDefined(const Token &MacroNameTok, const MacroInfo *MI) {
+ virtual void MacroDefined(const Token &MacroNameTok,
+ const MacroDirective *MD) {
Hash = llvm::HashString(MacroNameTok.getIdentifierInfo()->getName(), Hash);
}
};
@@ -1081,7 +1088,7 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
// Create the target instance.
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
- Clang->getTargetOpts()));
+ &Clang->getTargetOpts()));
if (!Clang->hasTarget()) {
delete OverrideMainBuffer;
return true;
@@ -1550,7 +1557,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
// Create the target instance.
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
- Clang->getTargetOpts()));
+ &Clang->getTargetOpts()));
if (!Clang->hasTarget()) {
llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk();
Preamble.clear();
@@ -1688,7 +1695,30 @@ void ASTUnit::transferASTDataFromCompilerInstance(CompilerInstance &CI) {
}
StringRef ASTUnit::getMainFileName() const {
- return Invocation->getFrontendOpts().Inputs[0].getFile();
+ if (Invocation && !Invocation->getFrontendOpts().Inputs.empty()) {
+ const FrontendInputFile &Input = Invocation->getFrontendOpts().Inputs[0];
+ if (Input.isFile())
+ return Input.getFile();
+ else
+ return Input.getBuffer()->getBufferIdentifier();
+ }
+
+ if (SourceMgr) {
+ if (const FileEntry *
+ FE = SourceMgr->getFileEntryForID(SourceMgr->getMainFileID()))
+ return FE->getName();
+ }
+
+ return StringRef();
+}
+
+StringRef ASTUnit::getASTFileName() const {
+ if (!isMainFileAST())
+ return StringRef();
+
+ serialization::ModuleFile &
+ Mod = Reader->getModuleManager().getPrimaryModule();
+ return Mod.FileName;
}
ASTUnit *ASTUnit::create(CompilerInvocation *CI,
@@ -1773,7 +1803,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI,
// Create the target instance.
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
- Clang->getTargetOpts()));
+ &Clang->getTargetOpts()));
if (!Clang->hasTarget())
return 0;
@@ -1898,6 +1928,8 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
AST->IncludeBriefCommentsInCodeCompletion
= IncludeBriefCommentsInCodeCompletion;
AST->Invocation = CI;
+ AST->FileSystemOpts = CI->getFileSystemOpts();
+ AST->FileMgr = new FileManager(AST->FileSystemOpts);
AST->UserFilesAreVolatile = UserFilesAreVolatile;
// Recover resources if we crash before exiting this method.
@@ -1931,9 +1963,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
if (!Diags.getPtr()) {
// No diagnostics engine was provided, so create our own diagnostics object
// with the default options.
- Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions(),
- ArgEnd - ArgBegin,
- ArgBegin);
+ Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions());
}
SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
@@ -2369,7 +2399,7 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
// Create the target instance.
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
- Clang->getTargetOpts()));
+ &Clang->getTargetOpts()));
if (!Clang->hasTarget()) {
Clang->setInvocation(0);
return;
@@ -2434,9 +2464,6 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
// If the main file has been overridden due to the use of a preamble,
// make that override happen and introduce the preamble.
- StoredDiagnostics.insert(StoredDiagnostics.end(),
- stored_diag_begin(),
- stored_diag_afterDriver_begin());
if (OverrideMainBuffer) {
PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer);
PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size();
@@ -2458,17 +2485,9 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
OwningPtr<SyntaxOnlyAction> Act;
Act.reset(new SyntaxOnlyAction);
if (Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) {
- if (OverrideMainBuffer) {
- std::string ModName = getPreambleFile(this);
- TranslateStoredDiagnostics(Clang->getModuleManager(), ModName,
- getSourceManager(), PreambleDiagnostics,
- StoredDiagnostics);
- }
Act->Execute();
Act->EndSourceFile();
}
-
- checkAndSanitizeDiags(StoredDiagnostics, getSourceManager());
}
bool ASTUnit::Save(StringRef File) {
diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp
index 3e66613..3f80a16 100644
--- a/lib/Frontend/CacheTokens.cpp
+++ b/lib/Frontend/CacheTokens.cpp
@@ -25,8 +25,8 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
// FIXME: put this somewhere else?
#ifndef S_ISDIR
@@ -517,8 +517,8 @@ public:
~StatListener() {}
LookupResult getStat(const char *Path, struct stat &StatBuf,
- int *FileDescriptor) {
- LookupResult Result = statChained(Path, StatBuf, FileDescriptor);
+ bool isFile, int *FileDescriptor) {
+ LookupResult Result = statChained(Path, StatBuf, isFile, FileDescriptor);
if (Result == CacheMissing) // Failed 'stat'.
PM.insert(PTHEntryKeyVariant(Path), PTHEntry());
diff --git a/lib/Frontend/ChainedIncludesSource.cpp b/lib/Frontend/ChainedIncludesSource.cpp
index 2d58640..a17def0 100644
--- a/lib/Frontend/ChainedIncludesSource.cpp
+++ b/lib/Frontend/ChainedIncludesSource.cpp
@@ -13,14 +13,14 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/ChainedIncludesSource.h"
-#include "clang/Frontend/TextDiagnosticPrinter.h"
-#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/ParseAST.h"
#include "clang/Serialization/ASTReader.h"
#include "clang/Serialization/ASTWriter.h"
-#include "clang/Parse/ParseAST.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Basic/TargetInfo.h"
#include "llvm/Support/MemoryBuffer.h"
using namespace clang;
@@ -39,7 +39,7 @@ static ASTReader *createASTReader(CompilerInstance &CI,
Reader->addInMemoryBuffer(sr, memBufs[ti]);
}
Reader->setDeserializationListener(deserialListener);
- switch (Reader->ReadAST(pchFile, serialization::MK_PCH,
+ switch (Reader->ReadAST(pchFile, serialization::MK_PCH, SourceLocation(),
ASTReader::ARR_None)) {
case ASTReader::Success:
// Set the predefines buffer as suggested by the PCH reader.
@@ -47,6 +47,7 @@ static ASTReader *createASTReader(CompilerInstance &CI,
return Reader.take();
case ASTReader::Failure:
+ case ASTReader::Missing:
case ASTReader::OutOfDate:
case ASTReader::VersionMismatch:
case ASTReader::ConfigurationMismatch:
@@ -99,7 +100,7 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
Clang->setInvocation(CInvok.take());
Clang->setDiagnostics(Diags.getPtr());
Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(),
- Clang->getTargetOpts()));
+ &Clang->getTargetOpts()));
Clang->createFileManager();
Clang->createSourceManager(Clang->getFileManager());
Clang->createPreprocessor();
@@ -112,8 +113,6 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) {
OwningPtr<ASTConsumer> consumer;
consumer.reset(new PCHGenerator(Clang->getPreprocessor(), "-", 0,
/*isysroot=*/"", &OS));
- Clang->getPreprocessor().setPPMutationListener(
- consumer->GetPPMutationListener());
Clang->getASTContext().setASTMutationListener(
consumer->GetASTMutationListener());
Clang->setASTConsumer(consumer.take());
@@ -191,7 +190,7 @@ CXXBaseSpecifier *
ChainedIncludesSource::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
return getFinalReader().GetExternalCXXBaseSpecifiers(Offset);
}
-DeclContextLookupResult
+bool
ChainedIncludesSource::FindExternalVisibleDeclsByName(const DeclContext *DC,
DeclarationName Name) {
return getFinalReader().FindExternalVisibleDeclsByName(DC, Name);
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 22a74fc..df06a81 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -8,7 +8,6 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Sema/Sema.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
@@ -17,9 +16,6 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Version.h"
-#include "clang/Lex/HeaderSearch.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/PTHManager.h"
#include "clang/Frontend/ChainedDiagnosticConsumer.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Frontend/FrontendActions.h"
@@ -27,28 +23,35 @@
#include "clang/Frontend/LogDiagnosticPrinter.h"
#include "clang/Frontend/SerializedDiagnosticPrinter.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
-#include "clang/Frontend/VerifyDiagnosticConsumer.h"
#include "clang/Frontend/Utils.h"
-#include "clang/Serialization/ASTReader.h"
+#include "clang/Frontend/VerifyDiagnosticConsumer.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/PTHManager.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/CodeCompleteConsumer.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Serialization/ASTReader.h"
#include "llvm/ADT/Statistic.h"
-#include "llvm/Support/Timer.h"
+#include "llvm/Config/config.h"
+#include "llvm/Support/CrashRecoveryContext.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/LockFileManager.h"
+#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/Signals.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
-#include "llvm/Support/CrashRecoveryContext.h"
-#include "llvm/Config/config.h"
+#include <sys/stat.h>
+#include <time.h>
using namespace clang;
CompilerInstance::CompilerInstance()
- : Invocation(new CompilerInvocation()), ModuleManager(0) {
+ : Invocation(new CompilerInvocation()), ModuleManager(0),
+ BuildGlobalModuleIndex(false), ModuleBuildFailed(false) {
}
CompilerInstance::~CompilerInstance() {
@@ -59,6 +62,13 @@ void CompilerInstance::setInvocation(CompilerInvocation *Value) {
Invocation = Value;
}
+bool CompilerInstance::shouldBuildGlobalModuleIndex() const {
+ return (BuildGlobalModuleIndex ||
+ (ModuleManager && ModuleManager->isGlobalIndexUnavailable() &&
+ getFrontendOpts().GenerateGlobalModuleIndex)) &&
+ !ModuleBuildFailed;
+}
+
void CompilerInstance::setDiagnostics(DiagnosticsEngine *Value) {
Diagnostics = Value;
}
@@ -92,29 +102,6 @@ void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) {
}
// Diagnostics
-static void SetUpBuildDumpLog(DiagnosticOptions *DiagOpts,
- unsigned argc, const char* const *argv,
- DiagnosticsEngine &Diags) {
- std::string ErrorInfo;
- OwningPtr<raw_ostream> OS(
- new llvm::raw_fd_ostream(DiagOpts->DumpBuildInformation.c_str(),ErrorInfo));
- if (!ErrorInfo.empty()) {
- Diags.Report(diag::err_fe_unable_to_open_logfile)
- << DiagOpts->DumpBuildInformation << ErrorInfo;
- return;
- }
-
- (*OS) << "clang -cc1 command line arguments: ";
- for (unsigned i = 0; i != argc; ++i)
- (*OS) << argv[i] << ' ';
- (*OS) << '\n';
-
- // Chain in a diagnostic client which will log the diagnostics.
- DiagnosticConsumer *Logger =
- new TextDiagnosticPrinter(*OS.take(), DiagOpts, /*OwnsOutputStream=*/true);
- Diags.setClient(new ChainedDiagnosticConsumer(Diags.takeClient(), Logger));
-}
-
static void SetUpDiagnosticLog(DiagnosticOptions *DiagOpts,
const CodeGenOptions *CodeGenOpts,
DiagnosticsEngine &Diags) {
@@ -128,7 +115,7 @@ static void SetUpDiagnosticLog(DiagnosticOptions *DiagOpts,
ErrorInfo, llvm::raw_fd_ostream::F_Append));
if (!ErrorInfo.empty()) {
Diags.Report(diag::warn_fe_cc_log_diagnostics_failure)
- << DiagOpts->DumpBuildInformation << ErrorInfo;
+ << DiagOpts->DiagnosticLogFile << ErrorInfo;
} else {
FileOS->SetUnbuffered();
FileOS->SetUseAtomicWrites(true);
@@ -167,18 +154,16 @@ static void SetupSerializedDiagnostics(DiagnosticOptions *DiagOpts,
SerializedConsumer));
}
-void CompilerInstance::createDiagnostics(int Argc, const char* const *Argv,
- DiagnosticConsumer *Client,
+void CompilerInstance::createDiagnostics(DiagnosticConsumer *Client,
bool ShouldOwnClient,
bool ShouldCloneClient) {
- Diagnostics = createDiagnostics(&getDiagnosticOpts(), Argc, Argv, Client,
+ Diagnostics = createDiagnostics(&getDiagnosticOpts(), Client,
ShouldOwnClient, ShouldCloneClient,
&getCodeGenOpts());
}
IntrusiveRefCntPtr<DiagnosticsEngine>
CompilerInstance::createDiagnostics(DiagnosticOptions *Opts,
- int Argc, const char* const *Argv,
DiagnosticConsumer *Client,
bool ShouldOwnClient,
bool ShouldCloneClient,
@@ -205,9 +190,6 @@ CompilerInstance::createDiagnostics(DiagnosticOptions *Opts,
if (!Opts->DiagnosticLogFile.empty())
SetUpDiagnosticLog(Opts, CodeGenOpts, *Diags);
- if (!Opts->DumpBuildInformation.empty())
- SetUpBuildDumpLog(Opts, Argc, Argv, *Diags);
-
if (!Opts->DiagnosticSerializationFile.empty())
SetupSerializedDiagnostics(Opts, *Diags,
Opts->DiagnosticSerializationFile);
@@ -260,10 +242,12 @@ void CompilerInstance::createPreprocessor() {
}
if (PPOpts.DetailedRecord)
- PP->createPreprocessingRecord(PPOpts.DetailedRecordConditionalDirectives);
+ PP->createPreprocessingRecord();
InitializePreprocessor(*PP, PPOpts, getHeaderSearchOpts(), getFrontendOpts());
+ PP->setPreprocessedOutput(getPreprocessorOutputOpts().ShowCPP);
+
// Set up the module path, including the hash for the
// module-creation options.
SmallString<256> SpecificModuleCache(
@@ -317,7 +301,8 @@ void CompilerInstance::createPCHExternalASTSource(StringRef Path,
AllowPCHWithCompilerErrors,
getPreprocessor(), getASTContext(),
DeserializationListener,
- Preamble));
+ Preamble,
+ getFrontendOpts().UseGlobalModuleIndex));
ModuleManager = static_cast<ASTReader*>(Source.get());
getASTContext().setExternalSource(Source);
}
@@ -330,18 +315,21 @@ CompilerInstance::createPCHExternalASTSource(StringRef Path,
Preprocessor &PP,
ASTContext &Context,
void *DeserializationListener,
- bool Preamble) {
+ bool Preamble,
+ bool UseGlobalModuleIndex) {
OwningPtr<ASTReader> Reader;
Reader.reset(new ASTReader(PP, Context,
Sysroot.empty() ? "" : Sysroot.c_str(),
DisablePCHValidation,
- AllowPCHWithCompilerErrors));
+ AllowPCHWithCompilerErrors,
+ UseGlobalModuleIndex));
Reader->setDeserializationListener(
static_cast<ASTDeserializationListener *>(DeserializationListener));
switch (Reader->ReadAST(Path,
Preamble ? serialization::MK_Preamble
: serialization::MK_PCH,
+ SourceLocation(),
ASTReader::ARR_None)) {
case ASTReader::Success:
// Set the predefines buffer as suggested by the PCH reader. Typically, the
@@ -353,6 +341,7 @@ CompilerInstance::createPCHExternalASTSource(StringRef Path,
// Unrecoverable failure: don't even try to process the input file.
break;
+ case ASTReader::Missing:
case ASTReader::OutOfDate:
case ASTReader::VersionMismatch:
case ASTReader::ConfigurationMismatch:
@@ -619,7 +608,6 @@ bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input,
Diags.Report(diag::err_fe_error_reading) << InputFile;
return false;
}
- SourceMgr.createMainFileID(File, Kind);
// The natural SourceManager infrastructure can't currently handle named
// pipes, but we would at least like to accept them for the main
@@ -631,8 +619,13 @@ bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input,
Diags.Report(diag::err_cannot_open_file) << InputFile << ec.message();
return false;
}
+
+ // Create a new virtual file that will have the correct size.
+ File = FileMgr.getVirtualFile(InputFile, MB->getBufferSize(), 0);
SourceMgr.overrideFileContents(File, MB.take());
}
+
+ SourceMgr.createMainFileID(File, Kind);
} else {
OwningPtr<llvm::MemoryBuffer> SB;
if (llvm::MemoryBuffer::getSTDIN(SB)) {
@@ -663,7 +656,7 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
raw_ostream &OS = llvm::errs();
// Create the target instance.
- setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), getTargetOpts()));
+ setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), &getTargetOpts()));
if (!hasTarget())
return false;
@@ -754,9 +747,27 @@ static void doCompileMapModule(void *UserData) {
Data.Instance.ExecuteAction(Data.CreateModuleAction);
}
+namespace {
+ /// \brief Function object that checks with the given macro definition should
+ /// be removed, because it is one of the ignored macros.
+ class RemoveIgnoredMacro {
+ const HeaderSearchOptions &HSOpts;
+
+ public:
+ explicit RemoveIgnoredMacro(const HeaderSearchOptions &HSOpts)
+ : HSOpts(HSOpts) { }
+
+ bool operator()(const std::pair<std::string, bool> &def) const {
+ StringRef MacroDef = def.first;
+ return HSOpts.ModulesIgnoreMacros.count(MacroDef.split('=').first) > 0;
+ }
+ };
+}
+
/// \brief Compile a module file for the given module, using the options
/// provided by the importing compiler instance.
static void compileModule(CompilerInstance &ImportingInstance,
+ SourceLocation ImportLoc,
Module *Module,
StringRef ModuleFileName) {
llvm::LockFileManager Locked(ModuleFileName);
@@ -789,12 +800,25 @@ static void compileModule(CompilerInstance &ImportingInstance,
Invocation->getLangOpts()->resetNonModularOptions();
PPOpts.resetNonModularOptions();
+ // Remove any macro definitions that are explicitly ignored by the module.
+ // They aren't supposed to affect how the module is built anyway.
+ const HeaderSearchOptions &HSOpts = Invocation->getHeaderSearchOpts();
+ PPOpts.Macros.erase(std::remove_if(PPOpts.Macros.begin(), PPOpts.Macros.end(),
+ RemoveIgnoredMacro(HSOpts)),
+ PPOpts.Macros.end());
+
+
// Note the name of the module we're building.
Invocation->getLangOpts()->CurrentModule = Module->getTopLevelModuleName();
- // Note that this module is part of the module build path, so that we
- // can detect cycles in the module graph.
- PPOpts.ModuleBuildPath.push_back(Module->getTopLevelModuleName());
+ // Make sure that the failed-module structure has been allocated in
+ // the importing instance, and propagate the pointer to the newly-created
+ // instance.
+ PreprocessorOptions &ImportingPPOpts
+ = ImportingInstance.getInvocation().getPreprocessorOpts();
+ if (!ImportingPPOpts.FailedModules)
+ ImportingPPOpts.FailedModules = new PreprocessorOptions::FailedModulesSet;
+ PPOpts.FailedModules = ImportingPPOpts.FailedModules;
// If there is a module map file, build the module using the module map.
// Set up the inputs/outputs so that we build the module from its umbrella
@@ -802,6 +826,7 @@ static void compileModule(CompilerInstance &ImportingInstance,
FrontendOptions &FrontendOpts = Invocation->getFrontendOpts();
FrontendOpts.OutputFile = ModuleFileName.str();
FrontendOpts.DisableFree = false;
+ FrontendOpts.GenerateGlobalModuleIndex = false;
FrontendOpts.Inputs.clear();
InputKind IK = getSourceInputKindFromOptions(*Invocation->getLangOpts());
@@ -843,11 +868,21 @@ static void compileModule(CompilerInstance &ImportingInstance,
// module.
CompilerInstance Instance;
Instance.setInvocation(&*Invocation);
- Instance.createDiagnostics(/*argc=*/0, /*argv=*/0,
- &ImportingInstance.getDiagnosticClient(),
+ Instance.createDiagnostics(&ImportingInstance.getDiagnosticClient(),
/*ShouldOwnClient=*/true,
/*ShouldCloneClient=*/true);
-
+
+ // Note that this module is part of the module build stack, so that we
+ // can detect cycles in the module graph.
+ Instance.createFileManager(); // FIXME: Adopt file manager from importer?
+ Instance.createSourceManager(Instance.getFileManager());
+ SourceManager &SourceMgr = Instance.getSourceManager();
+ SourceMgr.setModuleBuildStack(
+ ImportingInstance.getSourceManager().getModuleBuildStack());
+ SourceMgr.pushModuleBuildStack(Module->getTopLevelModuleName(),
+ FullSourceLoc(ImportLoc, ImportingInstance.getSourceManager()));
+
+
// Construct a module-generating action.
GenerateModuleAction CreateModuleAction;
@@ -865,19 +900,204 @@ static void compileModule(CompilerInstance &ImportingInstance,
Instance.clearOutputFiles(/*EraseFiles=*/true);
if (!TempModuleMapFileName.empty())
llvm::sys::Path(TempModuleMapFileName).eraseFromDisk();
+
+ // We've rebuilt a module. If we're allowed to generate or update the global
+ // module index, record that fact in the importing compiler instance.
+ if (ImportingInstance.getFrontendOpts().GenerateGlobalModuleIndex) {
+ ImportingInstance.setBuildGlobalModuleIndex(true);
+ }
+}
+
+/// \brief Diagnose differences between the current definition of the given
+/// configuration macro and the definition provided on the command line.
+static void checkConfigMacro(Preprocessor &PP, StringRef ConfigMacro,
+ Module *Mod, SourceLocation ImportLoc) {
+ IdentifierInfo *Id = PP.getIdentifierInfo(ConfigMacro);
+ SourceManager &SourceMgr = PP.getSourceManager();
+
+ // If this identifier has never had a macro definition, then it could
+ // not have changed.
+ if (!Id->hadMacroDefinition())
+ return;
+
+ // If this identifier does not currently have a macro definition,
+ // check whether it had one on the command line.
+ if (!Id->hasMacroDefinition()) {
+ MacroDirective::DefInfo LatestDef =
+ PP.getMacroDirectiveHistory(Id)->getDefinition();
+ for (MacroDirective::DefInfo Def = LatestDef; Def;
+ Def = Def.getPreviousDefinition()) {
+ FileID FID = SourceMgr.getFileID(Def.getLocation());
+ if (FID.isInvalid())
+ continue;
+
+ // We only care about the predefines buffer.
+ if (FID != PP.getPredefinesFileID())
+ continue;
+
+ // This macro was defined on the command line, then #undef'd later.
+ // Complain.
+ PP.Diag(ImportLoc, diag::warn_module_config_macro_undef)
+ << true << ConfigMacro << Mod->getFullModuleName();
+ if (LatestDef.isUndefined())
+ PP.Diag(LatestDef.getUndefLocation(), diag::note_module_def_undef_here)
+ << true;
+ return;
+ }
+
+ // Okay: no definition in the predefines buffer.
+ return;
+ }
+
+ // This identifier has a macro definition. Check whether we had a definition
+ // on the command line.
+ MacroDirective::DefInfo LatestDef =
+ PP.getMacroDirectiveHistory(Id)->getDefinition();
+ MacroDirective::DefInfo PredefinedDef;
+ for (MacroDirective::DefInfo Def = LatestDef; Def;
+ Def = Def.getPreviousDefinition()) {
+ FileID FID = SourceMgr.getFileID(Def.getLocation());
+ if (FID.isInvalid())
+ continue;
+
+ // We only care about the predefines buffer.
+ if (FID != PP.getPredefinesFileID())
+ continue;
+
+ PredefinedDef = Def;
+ break;
+ }
+
+ // If there was no definition for this macro in the predefines buffer,
+ // complain.
+ if (!PredefinedDef ||
+ (!PredefinedDef.getLocation().isValid() &&
+ PredefinedDef.getUndefLocation().isValid())) {
+ PP.Diag(ImportLoc, diag::warn_module_config_macro_undef)
+ << false << ConfigMacro << Mod->getFullModuleName();
+ PP.Diag(LatestDef.getLocation(), diag::note_module_def_undef_here)
+ << false;
+ return;
+ }
+
+ // If the current macro definition is the same as the predefined macro
+ // definition, it's okay.
+ if (LatestDef.getMacroInfo() == PredefinedDef.getMacroInfo() ||
+ LatestDef.getMacroInfo()->isIdenticalTo(*PredefinedDef.getMacroInfo(),PP,
+ /*Syntactically=*/true))
+ return;
+
+ // The macro definitions differ.
+ PP.Diag(ImportLoc, diag::warn_module_config_macro_undef)
+ << false << ConfigMacro << Mod->getFullModuleName();
+ PP.Diag(LatestDef.getLocation(), diag::note_module_def_undef_here)
+ << false;
+}
+
+/// \brief Write a new timestamp file with the given path.
+static void writeTimestampFile(StringRef TimestampFile) {
+ std::string ErrorInfo;
+ llvm::raw_fd_ostream Out(TimestampFile.str().c_str(), ErrorInfo,
+ llvm::raw_fd_ostream::F_Binary);
}
-Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
- ModuleIdPath Path,
- Module::NameVisibilityKind Visibility,
- bool IsInclusionDirective) {
+/// \brief Prune the module cache of modules that haven't been accessed in
+/// a long time.
+static void pruneModuleCache(const HeaderSearchOptions &HSOpts) {
+ struct stat StatBuf;
+ llvm::SmallString<128> TimestampFile;
+ TimestampFile = HSOpts.ModuleCachePath;
+ llvm::sys::path::append(TimestampFile, "modules.timestamp");
+
+ // Try to stat() the timestamp file.
+ if (::stat(TimestampFile.c_str(), &StatBuf)) {
+ // If the timestamp file wasn't there, create one now.
+ if (errno == ENOENT) {
+ writeTimestampFile(TimestampFile);
+ }
+ return;
+ }
+
+ // Check whether the time stamp is older than our pruning interval.
+ // If not, do nothing.
+ time_t TimeStampModTime = StatBuf.st_mtime;
+ time_t CurrentTime = time(0);
+ if (CurrentTime - TimeStampModTime <= time_t(HSOpts.ModuleCachePruneInterval))
+ return;
+
+ // Write a new timestamp file so that nobody else attempts to prune.
+ // There is a benign race condition here, if two Clang instances happen to
+ // notice at the same time that the timestamp is out-of-date.
+ writeTimestampFile(TimestampFile);
+
+ // Walk the entire module cache, looking for unused module files and module
+ // indices.
+ llvm::error_code EC;
+ SmallString<128> ModuleCachePathNative;
+ llvm::sys::path::native(HSOpts.ModuleCachePath, ModuleCachePathNative);
+ for (llvm::sys::fs::directory_iterator
+ Dir(ModuleCachePathNative.str(), EC), DirEnd;
+ Dir != DirEnd && !EC; Dir.increment(EC)) {
+ // If we don't have a directory, there's nothing to look into.
+ bool IsDirectory;
+ if (llvm::sys::fs::is_directory(Dir->path(), IsDirectory) || !IsDirectory)
+ continue;
+
+ // Walk all of the files within this directory.
+ bool RemovedAllFiles = true;
+ for (llvm::sys::fs::directory_iterator File(Dir->path(), EC), FileEnd;
+ File != FileEnd && !EC; File.increment(EC)) {
+ // We only care about module and global module index files.
+ if (llvm::sys::path::extension(File->path()) != ".pcm" &&
+ llvm::sys::path::filename(File->path()) != "modules.idx") {
+ RemovedAllFiles = false;
+ continue;
+ }
+
+ // Look at this file. If we can't stat it, there's nothing interesting
+ // there.
+ if (::stat(File->path().c_str(), &StatBuf)) {
+ RemovedAllFiles = false;
+ continue;
+ }
+
+ // If the file has been used recently enough, leave it there.
+ time_t FileAccessTime = StatBuf.st_atime;
+ if (CurrentTime - FileAccessTime <=
+ time_t(HSOpts.ModuleCachePruneAfter)) {
+ RemovedAllFiles = false;
+ continue;
+ }
+
+ // Remove the file.
+ bool Existed;
+ if (llvm::sys::fs::remove(File->path(), Existed) || !Existed) {
+ RemovedAllFiles = false;
+ }
+ }
+
+ // If we removed all of the files in the directory, remove the directory
+ // itself.
+ if (RemovedAllFiles) {
+ bool Existed;
+ llvm::sys::fs::remove(Dir->path(), Existed);
+ }
+ }
+}
+
+ModuleLoadResult
+CompilerInstance::loadModule(SourceLocation ImportLoc,
+ ModuleIdPath Path,
+ Module::NameVisibilityKind Visibility,
+ bool IsInclusionDirective) {
// If we've already handled this import, just return the cached result.
// This one-element cache is important to eliminate redundant diagnostics
// when both the preprocessor and parser see the same import declaration.
if (!ImportLoc.isInvalid() && LastModuleImportLoc == ImportLoc) {
// Make the named module visible.
if (LastModuleImportResult)
- ModuleManager->makeModuleVisible(LastModuleImportResult, Visibility);
+ ModuleManager->makeModuleVisible(LastModuleImportResult, Visibility,
+ ImportLoc, /*Complain=*/false);
return LastModuleImportResult;
}
@@ -901,79 +1121,36 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
// Search for a module with the given name.
Module = PP->getHeaderSearchInfo().lookupModule(ModuleName);
std::string ModuleFileName;
- if (Module)
+ if (Module) {
ModuleFileName = PP->getHeaderSearchInfo().getModuleFileName(Module);
- else
+ } else
ModuleFileName = PP->getHeaderSearchInfo().getModuleFileName(ModuleName);
-
- if (ModuleFileName.empty()) {
- getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found)
- << ModuleName
- << SourceRange(ImportLoc, ModuleNameLoc);
- LastModuleImportLoc = ImportLoc;
- LastModuleImportResult = 0;
- return 0;
- }
-
- const FileEntry *ModuleFile
- = getFileManager().getFile(ModuleFileName, /*OpenFile=*/false,
- /*CacheFailure=*/false);
- bool BuildingModule = false;
- if (!ModuleFile && Module) {
- // The module is not cached, but we have a module map from which we can
- // build the module.
-
- // Check whether there is a cycle in the module graph.
- SmallVectorImpl<std::string> &ModuleBuildPath
- = getPreprocessorOpts().ModuleBuildPath;
- SmallVectorImpl<std::string>::iterator Pos
- = std::find(ModuleBuildPath.begin(), ModuleBuildPath.end(), ModuleName);
- if (Pos != ModuleBuildPath.end()) {
- SmallString<256> CyclePath;
- for (; Pos != ModuleBuildPath.end(); ++Pos) {
- CyclePath += *Pos;
- CyclePath += " -> ";
- }
- CyclePath += ModuleName;
-
- getDiagnostics().Report(ModuleNameLoc, diag::err_module_cycle)
- << ModuleName << CyclePath;
- return 0;
- }
-
- getDiagnostics().Report(ModuleNameLoc, diag::warn_module_build)
- << ModuleName;
- BuildingModule = true;
- compileModule(*this, Module, ModuleFileName);
- ModuleFile = FileMgr->getFile(ModuleFileName);
- }
-
- if (!ModuleFile) {
- getDiagnostics().Report(ModuleNameLoc,
- BuildingModule? diag::err_module_not_built
- : diag::err_module_not_found)
- << ModuleName
- << SourceRange(ImportLoc, ModuleNameLoc);
- return 0;
- }
// If we don't already have an ASTReader, create one now.
if (!ModuleManager) {
if (!hasASTContext())
createASTContext();
+ // If we're not recursively building a module, check whether we
+ // need to prune the module cache.
+ if (getSourceManager().getModuleBuildStack().empty() &&
+ getHeaderSearchOpts().ModuleCachePruneInterval > 0 &&
+ getHeaderSearchOpts().ModuleCachePruneAfter > 0) {
+ pruneModuleCache(getHeaderSearchOpts());
+ }
+
std::string Sysroot = getHeaderSearchOpts().Sysroot;
const PreprocessorOptions &PPOpts = getPreprocessorOpts();
ModuleManager = new ASTReader(getPreprocessor(), *Context,
Sysroot.empty() ? "" : Sysroot.c_str(),
- PPOpts.DisablePCHValidation);
+ PPOpts.DisablePCHValidation,
+ /*AllowASTWithCompilerErrors=*/false,
+ getFrontendOpts().UseGlobalModuleIndex);
if (hasASTConsumer()) {
ModuleManager->setDeserializationListener(
getASTConsumer().GetASTDeserializationListener());
getASTContext().setASTMutationListener(
getASTConsumer().GetASTMutationListener());
- getPreprocessor().setPPMutationListener(
- getASTConsumer().GetPPMutationListener());
}
OwningPtr<ExternalASTSource> Source;
Source.reset(ModuleManager);
@@ -984,31 +1161,87 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
ModuleManager->StartTranslationUnit(&getASTConsumer());
}
- // Try to load the module we found.
- unsigned ARRFlags = ASTReader::ARR_None;
- if (Module)
- ARRFlags |= ASTReader::ARR_OutOfDate;
- switch (ModuleManager->ReadAST(ModuleFile->getName(),
- serialization::MK_Module,
- ARRFlags)) {
+ // Try to load the module file.
+ unsigned ARRFlags = ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing;
+ switch (ModuleManager->ReadAST(ModuleFileName, serialization::MK_Module,
+ ImportLoc, ARRFlags)) {
case ASTReader::Success:
break;
case ASTReader::OutOfDate: {
- // The module file is out-of-date. Rebuild it.
- getFileManager().invalidateCache(ModuleFile);
+ // The module file is out-of-date. Remove it, then rebuild it.
bool Existed;
llvm::sys::fs::remove(ModuleFileName, Existed);
- compileModule(*this, Module, ModuleFileName);
-
- // Try loading the module again.
- ModuleFile = FileMgr->getFile(ModuleFileName);
- if (!ModuleFile ||
- ModuleManager->ReadAST(ModuleFileName,
- serialization::MK_Module,
- ASTReader::ARR_None) != ASTReader::Success) {
+ }
+ // Fall through to build the module again.
+
+ case ASTReader::Missing: {
+ // The module file is (now) missing. Build it.
+
+ // If we don't have a module, we don't know how to build the module file.
+ // Complain and return.
+ if (!Module) {
+ getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found)
+ << ModuleName
+ << SourceRange(ImportLoc, ModuleNameLoc);
+ ModuleBuildFailed = true;
+ return ModuleLoadResult();
+ }
+
+ // Check whether there is a cycle in the module graph.
+ ModuleBuildStack ModPath = getSourceManager().getModuleBuildStack();
+ ModuleBuildStack::iterator Pos = ModPath.begin(), PosEnd = ModPath.end();
+ for (; Pos != PosEnd; ++Pos) {
+ if (Pos->first == ModuleName)
+ break;
+ }
+
+ if (Pos != PosEnd) {
+ SmallString<256> CyclePath;
+ for (; Pos != PosEnd; ++Pos) {
+ CyclePath += Pos->first;
+ CyclePath += " -> ";
+ }
+ CyclePath += ModuleName;
+
+ getDiagnostics().Report(ModuleNameLoc, diag::err_module_cycle)
+ << ModuleName << CyclePath;
+ return ModuleLoadResult();
+ }
+
+ // Check whether we have already attempted to build this module (but
+ // failed).
+ if (getPreprocessorOpts().FailedModules &&
+ getPreprocessorOpts().FailedModules->hasAlreadyFailed(ModuleName)) {
+ getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_built)
+ << ModuleName
+ << SourceRange(ImportLoc, ModuleNameLoc);
+ ModuleBuildFailed = true;
+ return ModuleLoadResult();
+ }
+
+ // Try to compile the module.
+ compileModule(*this, ModuleNameLoc, Module, ModuleFileName);
+
+ // Try to read the module file, now that we've compiled it.
+ ASTReader::ASTReadResult ReadResult
+ = ModuleManager->ReadAST(ModuleFileName,
+ serialization::MK_Module, ImportLoc,
+ ASTReader::ARR_Missing);
+ if (ReadResult != ASTReader::Success) {
+ if (ReadResult == ASTReader::Missing) {
+ getDiagnostics().Report(ModuleNameLoc,
+ Module? diag::err_module_not_built
+ : diag::err_module_not_found)
+ << ModuleName
+ << SourceRange(ImportLoc, ModuleNameLoc);
+ }
+
+ if (getPreprocessorOpts().FailedModules)
+ getPreprocessorOpts().FailedModules->addFailed(ModuleName);
KnownModules[Path[0].first] = 0;
- return 0;
+ ModuleBuildFailed = true;
+ return ModuleLoadResult();
}
// Okay, we've rebuilt and now loaded the module.
@@ -1021,12 +1254,13 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
// FIXME: The ASTReader will already have complained, but can we showhorn
// that diagnostic information into a more useful form?
KnownModules[Path[0].first] = 0;
- return 0;
+ return ModuleLoadResult();
case ASTReader::Failure:
// Already complained, but note now that we failed.
KnownModules[Path[0].first] = 0;
- return 0;
+ ModuleBuildFailed = true;
+ return ModuleLoadResult();
}
if (!Module) {
@@ -1036,16 +1270,13 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
.findModule((Path[0].first->getName()));
}
- if (Module)
- Module->setASTFile(ModuleFile);
-
// Cache the result of this top-level module lookup for later.
Known = KnownModules.insert(std::make_pair(Path[0].first, Module)).first;
}
// If we never found the module, fail.
if (!Module)
- return 0;
+ return ModuleLoadResult();
// Verify that the rest of the module path actually corresponds to
// a submodule.
@@ -1056,7 +1287,7 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
if (!Sub) {
// Attempt to perform typo correction to find a module name that works.
- llvm::SmallVector<StringRef, 2> Best;
+ SmallVector<StringRef, 2> Best;
unsigned BestEditDistance = (std::numeric_limits<unsigned>::max)();
for (clang::Module::submodule_iterator J = Module->submodule_begin(),
@@ -1115,7 +1346,7 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
<< Module->getFullModuleName()
<< SourceRange(Path.front().second, Path.back().second);
- return 0;
+ return ModuleLoadResult(0, true);
}
// Check whether this module is available.
@@ -1126,13 +1357,21 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
<< Feature
<< SourceRange(Path.front().second, Path.back().second);
LastModuleImportLoc = ImportLoc;
- LastModuleImportResult = 0;
- return 0;
+ LastModuleImportResult = ModuleLoadResult();
+ return ModuleLoadResult();
}
- ModuleManager->makeModuleVisible(Module, Visibility);
+ ModuleManager->makeModuleVisible(Module, Visibility, ImportLoc,
+ /*Complain=*/true);
}
-
+
+ // Check for any configuration macros that have changed.
+ clang::Module *TopModule = Module->getTopLevelModule();
+ for (unsigned I = 0, N = TopModule->ConfigMacros.size(); I != N; ++I) {
+ checkConfigMacro(getPreprocessor(), TopModule->ConfigMacros[I],
+ Module, ImportLoc);
+ }
+
// If this module import was due to an inclusion directive, create an
// implicit import declaration to capture it in the AST.
if (IsInclusionDirective && hasASTContext()) {
@@ -1146,6 +1385,14 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc,
}
LastModuleImportLoc = ImportLoc;
- LastModuleImportResult = Module;
- return Module;
+ LastModuleImportResult = ModuleLoadResult(Module, false);
+ return LastModuleImportResult;
+}
+
+void CompilerInstance::makeModuleVisible(Module *Mod,
+ Module::NameVisibilityKind Visibility,
+ SourceLocation ImportLoc,
+ bool Complain){
+ ModuleManager->makeModuleVisible(Mod, Visibility, ImportLoc, Complain);
}
+
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index b9c198b..41f9417 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -9,17 +9,16 @@
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/Version.h"
#include "clang/Basic/FileManager.h"
-#include "clang/Lex/HeaderSearchOptions.h"
+#include "clang/Basic/Version.h"
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
-#include "clang/Driver/Options.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/OptTable.h"
#include "clang/Driver/Option.h"
-#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Driver/Options.h"
#include "clang/Frontend/LangStandard.h"
+#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Serialization/ASTReader.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/OwningPtr.h"
@@ -71,7 +70,7 @@ static unsigned getOptimizationLevel(ArgList &Args, InputKind IK,
assert (A->getOption().matches(options::OPT_O));
- llvm::StringRef S(A->getValue());
+ StringRef S(A->getValue());
if (S == "s" || S == "z" || S.empty())
return 2;
@@ -189,22 +188,6 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
}
}
- if (Arg *A = Args.getLastArg(OPT_analyzer_ipa)) {
- StringRef Name = A->getValue();
- AnalysisIPAMode Value = llvm::StringSwitch<AnalysisIPAMode>(Name)
-#define ANALYSIS_IPA(NAME, CMDFLAG, DESC) \
- .Case(CMDFLAG, NAME)
-#include "clang/StaticAnalyzer/Core/Analyses.def"
- .Default(NumIPAModes);
- if (Value == NumIPAModes) {
- Diags.Report(diag::err_drv_invalid_value)
- << A->getAsString(Args) << Name;
- Success = false;
- } else {
- Opts.IPAMode = Value;
- }
- }
-
if (Arg *A = Args.getLastArg(OPT_analyzer_inlining_mode)) {
StringRef Name = A->getValue();
AnalysisInliningMode Value = llvm::StringSwitch<AnalysisInliningMode>(Name)
@@ -235,15 +218,11 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args,
Opts.AnalyzeSpecificFunction = Args.getLastArgValue(OPT_analyze_function);
Opts.UnoptimizedCFG = Args.hasArg(OPT_analysis_UnoptimizedCFG);
Opts.TrimGraph = Args.hasArg(OPT_trim_egraph);
- Opts.MaxNodes = Args.getLastArgIntValue(OPT_analyzer_max_nodes, 150000,Diags);
Opts.maxBlockVisitOnPath = Args.getLastArgIntValue(OPT_analyzer_max_loop, 4, Diags);
Opts.PrintStats = Args.hasArg(OPT_analyzer_stats);
Opts.InlineMaxStackDepth =
Args.getLastArgIntValue(OPT_analyzer_inline_max_stack_depth,
Opts.InlineMaxStackDepth, Diags);
- Opts.InlineMaxFunctionSize =
- Args.getLastArgIntValue(OPT_analyzer_inline_max_function_size,
- Opts.InlineMaxFunctionSize, Diags);
Opts.CheckersControlList.clear();
for (arg_iterator it = Args.filtered_begin(OPT_analyzer_checker,
@@ -300,6 +279,10 @@ static bool ParseMigratorArgs(MigratorOptions &Opts, ArgList &Args) {
return true;
}
+static void ParseCommentArgs(CommentOptions &Opts, ArgList &Args) {
+ Opts.BlockCommandNames = Args.getAllArgValues(OPT_fcomment_block_commands);
+}
+
static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
DiagnosticsEngine &Diags) {
using namespace options;
@@ -332,13 +315,16 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.setDebugInfo(CodeGenOptions::FullDebugInfo);
}
Opts.DebugColumnInfo = Args.hasArg(OPT_dwarf_column_info);
+ Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file);
+ Opts.ModulesAutolink = Args.hasArg(OPT_fmodules_autolink);
Opts.DisableLLVMOpts = Args.hasArg(OPT_disable_llvm_optzns);
Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone);
Opts.ForbidGuardVariables = Args.hasArg(OPT_fforbid_guard_variables);
Opts.UseRegisterSizedBitfieldAccess = Args.hasArg(
OPT_fuse_register_sized_bitfield_access);
Opts.RelaxedAliasing = Args.hasArg(OPT_relaxed_aliasing);
+ Opts.StructPathTBAA = Args.hasArg(OPT_struct_path_tbaa);
Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags);
Opts.MergeAllConstants = !Args.hasArg(OPT_fno_merge_all_constants);
Opts.NoCommon = Args.hasArg(OPT_fno_common);
@@ -373,6 +359,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.NumRegisterParameters = Args.getLastArgIntValue(OPT_mregparm, 0, Diags);
Opts.NoGlobalMerge = Args.hasArg(OPT_mno_global_merge);
Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack);
+ Opts.EnableSegmentedStacks = Args.hasArg(OPT_split_stacks);
Opts.RelaxAll = Args.hasArg(OPT_mrelax_all);
Opts.OmitLeafFramePointer = Args.hasArg(OPT_momit_leaf_frame_pointer);
Opts.SaveTempLabels = Args.hasArg(OPT_msave_temp_labels);
@@ -386,8 +373,6 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.UnwindTables = Args.hasArg(OPT_munwind_tables);
Opts.RelocationModel = Args.getLastArgValue(OPT_mrelocation_model, "pic");
Opts.TrapFuncName = Args.getLastArgValue(OPT_ftrap_function_EQ);
- Opts.BoundsChecking = Args.getLastArgIntValue(OPT_fbounds_checking_EQ, 0,
- Diags);
Opts.UseInitArray = Args.hasArg(OPT_fuse_init_array);
Opts.FunctionSections = Args.hasArg(OPT_ffunction_sections);
@@ -395,15 +380,40 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Opts.MainFileName = Args.getLastArgValue(OPT_main_file_name);
Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier);
+ Opts.SanitizeRecover = !Args.hasArg(OPT_fno_sanitize_recover);
- Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions);
- Opts.InstrumentForProfiling = Args.hasArg(OPT_pg);
+ Opts.DisableGCov = Args.hasArg(OPT_test_coverage);
Opts.EmitGcovArcs = Args.hasArg(OPT_femit_coverage_data);
Opts.EmitGcovNotes = Args.hasArg(OPT_femit_coverage_notes);
- Opts.EmitOpenCLArgMetadata = Args.hasArg(OPT_cl_kernel_arg_info);
+ if (Opts.EmitGcovArcs || Opts.EmitGcovNotes) {
Opts.CoverageFile = Args.getLastArgValue(OPT_coverage_file);
+ Opts.CoverageExtraChecksum = Args.hasArg(OPT_coverage_cfg_checksum);
+ Opts.CoverageNoFunctionNamesInData =
+ Args.hasArg(OPT_coverage_no_function_names_in_data);
+ if (Args.hasArg(OPT_coverage_version_EQ)) {
+ StringRef CoverageVersion = Args.getLastArgValue(OPT_coverage_version_EQ);
+ if (CoverageVersion.size() != 4) {
+ Diags.Report(diag::err_drv_invalid_value)
+ << Args.getLastArg(OPT_coverage_version_EQ)->getAsString(Args)
+ << CoverageVersion;
+ } else {
+ memcpy(Opts.CoverageVersion, CoverageVersion.data(), 4);
+ }
+ }
+ }
+
+ Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions);
+ Opts.InstrumentForProfiling = Args.hasArg(OPT_pg);
+ Opts.EmitOpenCLArgMetadata = Args.hasArg(OPT_cl_kernel_arg_info);
Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir);
Opts.LinkBitcodeFile = Args.getLastArgValue(OPT_mlink_bitcode_file);
+ Opts.SanitizerBlacklistFile = Args.getLastArgValue(OPT_fsanitize_blacklist);
+ Opts.SanitizeMemoryTrackOrigins =
+ Args.hasArg(OPT_fsanitize_memory_track_origins);
+ Opts.SanitizeAddressZeroBaseShadow =
+ Args.hasArg(OPT_fsanitize_address_zero_base_shadow);
+ Opts.SanitizeUndefinedTrapOnError =
+ Args.hasArg(OPT_fsanitize_undefined_trap_on_error);
Opts.SSPBufferSize =
Args.getLastArgIntValue(OPT_stack_protector_buffer_size, 8, Diags);
Opts.StackRealignment = Args.hasArg(OPT_mstackrealign);
@@ -446,6 +456,18 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
}
}
+ if (Arg *A = Args.getLastArg(OPT_ffp_contract)) {
+ StringRef Val = A->getValue();
+ if (Val == "fast")
+ Opts.setFPContractMode(CodeGenOptions::FPC_Fast);
+ else if (Val == "on")
+ Opts.setFPContractMode(CodeGenOptions::FPC_On);
+ else if (Val == "off")
+ Opts.setFPContractMode(CodeGenOptions::FPC_Off);
+ else
+ Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val;
+ }
+
return Success;
}
@@ -538,9 +560,11 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info);
Opts.ShowParseableFixits = Args.hasArg(OPT_fdiagnostics_parseable_fixits);
+ Opts.ShowPresumedLoc = !Args.hasArg(OPT_fno_diagnostics_use_presumed_location);
Opts.VerifyDiagnostics = Args.hasArg(OPT_verify);
Opts.ElideType = !Args.hasArg(OPT_fno_elide_type);
Opts.ShowTemplateTree = Args.hasArg(OPT_fdiagnostics_show_template_tree);
+ Opts.WarnOnSpellCheck = Args.hasArg(OPT_fwarn_on_spellcheck);
Opts.ErrorLimit = Args.getLastArgIntValue(OPT_ferror_limit, 0, Diags);
Opts.MacroBacktraceLimit
= Args.getLastArgIntValue(OPT_fmacro_backtrace_limit,
@@ -562,7 +586,6 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,
<< Opts.TabStop << DiagnosticOptions::DefaultTabStop;
}
Opts.MessageLength = Args.getLastArgIntValue(OPT_fmessage_length, 0, Diags);
- Opts.DumpBuildInformation = Args.getLastArgValue(OPT_dump_build_information);
addWarningArgs(Args, Opts.Warnings);
return Success;
@@ -623,6 +646,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.ProgramAction = frontend::InitOnly; break;
case OPT_fsyntax_only:
Opts.ProgramAction = frontend::ParseSyntaxOnly; break;
+ case OPT_module_file_info:
+ Opts.ProgramAction = frontend::ModuleFileInfo; break;
case OPT_print_decl_contexts:
Opts.ProgramAction = frontend::PrintDeclContext; break;
case OPT_print_preamble:
@@ -689,7 +714,9 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
Opts.FixAndRecompile = Args.hasArg(OPT_fixit_recompile);
Opts.FixToTemporaries = Args.hasArg(OPT_fixit_to_temp);
Opts.ASTDumpFilter = Args.getLastArgValue(OPT_ast_dump_filter);
-
+ Opts.UseGlobalModuleIndex = !Args.hasArg(OPT_fno_modules_global_index);
+ Opts.GenerateGlobalModuleIndex = Opts.UseGlobalModuleIndex;
+
Opts.CodeCompleteOpts.IncludeMacros
= Args.hasArg(OPT_code_completion_macros);
Opts.CodeCompleteOpts.IncludeCodePatterns
@@ -756,7 +783,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
.Case("objective-c-header", IK_ObjC)
.Case("c++-header", IK_CXX)
.Case("objective-c++-header", IK_ObjCXX)
- .Case("ast", IK_AST)
+ .Cases("ast", "pcm", IK_AST)
.Case("ir", IK_LLVM_IR)
.Default(IK_None);
if (DashX == IK_None)
@@ -811,9 +838,18 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
if (const Arg *A = Args.getLastArg(OPT_stdlib_EQ))
Opts.UseLibcxx = (strcmp(A->getValue(), "libc++") == 0);
Opts.ResourceDir = Args.getLastArgValue(OPT_resource_dir);
- Opts.ModuleCachePath = Args.getLastArgValue(OPT_fmodule_cache_path);
+ Opts.ModuleCachePath = Args.getLastArgValue(OPT_fmodules_cache_path);
Opts.DisableModuleHash = Args.hasArg(OPT_fdisable_module_hash);
-
+ Opts.ModuleCachePruneInterval
+ = Args.getLastArgIntValue(OPT_fmodules_prune_interval, 7*24*60*60);
+ Opts.ModuleCachePruneAfter
+ = Args.getLastArgIntValue(OPT_fmodules_prune_after, 31*24*60*60);
+ for (arg_iterator it = Args.filtered_begin(OPT_fmodules_ignore_macro),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ StringRef MacroDef = (*it)->getValue();
+ Opts.ModulesIgnoreMacros.insert(MacroDef.split('=').first);
+ }
+
// Add -I..., -F..., and -index-header-map options in order.
bool IsIndexHeaderMap = false;
for (arg_iterator it = Args.filtered_begin(OPT_I, OPT_F,
@@ -828,12 +864,12 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
frontend::IncludeDirGroup Group
= IsIndexHeaderMap? frontend::IndexHeaderMap : frontend::Angled;
- Opts.AddPath((*it)->getValue(), Group, true,
- /*IsFramework=*/ (*it)->getOption().matches(OPT_F), false);
+ Opts.AddPath((*it)->getValue(), Group,
+ /*IsFramework=*/ (*it)->getOption().matches(OPT_F), true);
IsIndexHeaderMap = false;
}
- // Add -iprefix/-iwith-prefix/-iwithprefixbefore options.
+ // Add -iprefix/-iwithprefix/-iwithprefixbefore options.
StringRef Prefix = ""; // FIXME: This isn't the correct default prefix.
for (arg_iterator it = Args.filtered_begin(OPT_iprefix, OPT_iwithprefix,
OPT_iwithprefixbefore),
@@ -843,50 +879,50 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) {
Prefix = A->getValue();
else if (A->getOption().matches(OPT_iwithprefix))
Opts.AddPath(Prefix.str() + A->getValue(),
- frontend::System, false, false, false);
+ frontend::After, false, true);
else
Opts.AddPath(Prefix.str() + A->getValue(),
- frontend::Angled, false, false, false);
+ frontend::Angled, false, true);
}
for (arg_iterator it = Args.filtered_begin(OPT_idirafter),
ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(), frontend::After, true, false, false);
+ Opts.AddPath((*it)->getValue(), frontend::After, false, true);
for (arg_iterator it = Args.filtered_begin(OPT_iquote),
ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(), frontend::Quoted, true, false, false);
+ Opts.AddPath((*it)->getValue(), frontend::Quoted, false, true);
for (arg_iterator it = Args.filtered_begin(OPT_isystem,
OPT_iwithsysroot), ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(), frontend::System, true, false,
+ Opts.AddPath((*it)->getValue(), frontend::System, false,
!(*it)->getOption().matches(OPT_iwithsysroot));
for (arg_iterator it = Args.filtered_begin(OPT_iframework),
ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(), frontend::System, true, true,
- true);
+ Opts.AddPath((*it)->getValue(), frontend::System, true, true);
// Add the paths for the various language specific isystem flags.
for (arg_iterator it = Args.filtered_begin(OPT_c_isystem),
ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(), frontend::CSystem, true, false, true);
+ Opts.AddPath((*it)->getValue(), frontend::CSystem, false, true);
for (arg_iterator it = Args.filtered_begin(OPT_cxx_isystem),
ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(), frontend::CXXSystem, true, false, true);
+ Opts.AddPath((*it)->getValue(), frontend::CXXSystem, false, true);
for (arg_iterator it = Args.filtered_begin(OPT_objc_isystem),
ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(), frontend::ObjCSystem, true, false,true);
+ Opts.AddPath((*it)->getValue(), frontend::ObjCSystem, false,true);
for (arg_iterator it = Args.filtered_begin(OPT_objcxx_isystem),
ie = Args.filtered_end(); it != ie; ++it)
- Opts.AddPath((*it)->getValue(), frontend::ObjCXXSystem, true, false,
- true);
+ Opts.AddPath((*it)->getValue(), frontend::ObjCXXSystem, false, true);
// Add the internal paths from a driver that detects standard include paths.
for (arg_iterator I = Args.filtered_begin(OPT_internal_isystem,
OPT_internal_externc_isystem),
E = Args.filtered_end();
- I != E; ++I)
- Opts.AddPath((*I)->getValue(), frontend::System,
- false, false, /*IgnoreSysRoot=*/true, /*IsInternal=*/true,
- (*I)->getOption().matches(OPT_internal_externc_isystem));
+ I != E; ++I) {
+ frontend::IncludeDirGroup Group = frontend::System;
+ if ((*I)->getOption().matches(OPT_internal_externc_isystem))
+ Group = frontend::ExternCSystem;
+ Opts.AddPath((*I)->getValue(), Group, false, true);
+ }
// Add the path prefixes which are implicitly treated as being system headers.
for (arg_iterator I = Args.filtered_begin(OPT_isystem_prefix,
@@ -945,7 +981,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
Opts.C99 = Std.isC99();
Opts.C11 = Std.isC11();
Opts.CPlusPlus = Std.isCPlusPlus();
- Opts.CPlusPlus0x = Std.isCPlusPlus0x();
+ Opts.CPlusPlus11 = Std.isCPlusPlus11();
Opts.CPlusPlus1y = Std.isCPlusPlus1y();
Opts.Digraphs = Std.hasDigraphs();
Opts.GNUMode = Std.isGNUMode();
@@ -973,6 +1009,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
Opts.CXXOperatorNames = 1;
Opts.LaxVectorConversions = 0;
Opts.DefaultFPContract = 1;
+ Opts.NativeHalfType = 1;
}
if (LangStd == LangStandard::lang_cuda)
@@ -994,6 +1031,24 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
Opts.DollarIdents = !Opts.AsmPreprocessor;
}
+/// Attempt to parse a visibility value out of the given argument.
+static Visibility parseVisibility(Arg *arg, ArgList &args,
+ DiagnosticsEngine &diags) {
+ StringRef value = arg->getValue();
+ if (value == "default") {
+ return DefaultVisibility;
+ } else if (value == "hidden") {
+ return HiddenVisibility;
+ } else if (value == "protected") {
+ // FIXME: diagnose if target does not support protected visibility
+ return ProtectedVisibility;
+ }
+
+ diags.Report(diag::err_drv_invalid_value)
+ << arg->getAsString(args) << value;
+ return DefaultVisibility;
+}
+
static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
DiagnosticsEngine &Diags) {
// FIXME: Cleanup per-file based stuff.
@@ -1122,31 +1177,18 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
if (Args.hasArg(OPT_pthread))
Opts.POSIXThreads = 1;
- if (Args.hasArg(OPT_fdelayed_template_parsing))
- Opts.DelayedTemplateParsing = 1;
-
- StringRef Vis = Args.getLastArgValue(OPT_fvisibility, "default");
- if (Vis == "default")
- Opts.setVisibilityMode(DefaultVisibility);
- else if (Vis == "hidden")
- Opts.setVisibilityMode(HiddenVisibility);
- else if (Vis == "protected")
- // FIXME: diagnose if target does not support protected visibility
- Opts.setVisibilityMode(ProtectedVisibility);
- else
- Diags.Report(diag::err_drv_invalid_value)
- << Args.getLastArg(OPT_fvisibility)->getAsString(Args) << Vis;
+ // The value-visibility mode defaults to "default".
+ if (Arg *visOpt = Args.getLastArg(OPT_fvisibility)) {
+ Opts.setValueVisibilityMode(parseVisibility(visOpt, Args, Diags));
+ } else {
+ Opts.setValueVisibilityMode(DefaultVisibility);
+ }
- if (Arg *A = Args.getLastArg(OPT_ffp_contract)) {
- StringRef Val = A->getValue();
- if (Val == "fast")
- Opts.setFPContractMode(LangOptions::FPC_Fast);
- else if (Val == "on")
- Opts.setFPContractMode(LangOptions::FPC_On);
- else if (Val == "off")
- Opts.setFPContractMode(LangOptions::FPC_Off);
- else
- Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val;
+ // The type-visibility mode defaults to the value-visibility mode.
+ if (Arg *typeVisOpt = Args.getLastArg(OPT_ftype_visibility)) {
+ Opts.setTypeVisibilityMode(parseVisibility(typeVisOpt, Args, Diags));
+ } else {
+ Opts.setTypeVisibilityMode(Opts.getValueVisibilityMode());
}
if (Args.hasArg(OPT_fvisibility_inlines_hidden))
@@ -1171,6 +1213,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.MicrosoftExt
= Args.hasArg(OPT_fms_extensions) || Args.hasArg(OPT_fms_compatibility);
Opts.MicrosoftMode = Args.hasArg(OPT_fms_compatibility);
+ Opts.AsmBlocks = Args.hasArg(OPT_fasm_blocks) || Opts.MicrosoftExt;
Opts.MSCVersion = Args.getLastArgIntValue(OPT_fmsc_version, 0, Diags);
Opts.Borland = Args.hasArg(OPT_fborland_extensions);
Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings);
@@ -1205,6 +1248,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Diags);
Opts.ConstexprCallDepth = Args.getLastArgIntValue(OPT_fconstexpr_depth, 512,
Diags);
+ Opts.BracketDepth = Args.getLastArgIntValue(OPT_fbracket_depth, 256, Diags);
Opts.DelayedTemplateParsing = Args.hasArg(OPT_fdelayed_template_parsing);
Opts.NumLargeByValueCopy = Args.getLastArgIntValue(OPT_Wlarge_by_value_copy_EQ,
0, Diags);
@@ -1238,6 +1282,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.ApplePragmaPack = Args.hasArg(OPT_fapple_pragma_pack);
Opts.CurrentModule = Args.getLastArgValue(OPT_fmodule_name);
+ // Check if -fopenmp is specified.
+ Opts.OpenMP = Args.hasArg(OPT_fopenmp);
+
// Record whether the __DEPRECATED define was requested.
Opts.Deprecated = Args.hasFlag(OPT_fdeprecated_macro,
OPT_fno_deprecated_macro,
@@ -1257,8 +1304,6 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Opts.FastMath = Args.hasArg(OPT_ffast_math);
Opts.FiniteMathOnly = Args.hasArg(OPT_ffinite_math_only);
- Opts.EmitMicrosoftInlineAsm = Args.hasArg(OPT_fenable_experimental_ms_inline_asm);
-
Opts.RetainCommentsFromSystemHeaders =
Args.hasArg(OPT_fretain_comments_from_system_headers);
@@ -1293,7 +1338,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
.Default(Unknown)) {
#define SANITIZER(NAME, ID) \
case ID: \
- Opts.Sanitize##ID = true; \
+ Opts.Sanitize.ID = true; \
break;
#include "clang/Basic/Sanitizers.def"
@@ -1354,8 +1399,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
Opts.MacroIncludes = Args.getAllArgValues(OPT_imacros);
// Add the ordered list of -includes.
- for (arg_iterator it = Args.filtered_begin(OPT_include, OPT_include_pch,
- OPT_include_pth),
+ for (arg_iterator it = Args.filtered_begin(OPT_include),
ie = Args.filtered_end(); it != ie; ++it) {
const Arg *A = *it;
Opts.Includes.push_back(A->getValue());
@@ -1400,9 +1444,49 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
}
static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
- ArgList &Args) {
+ ArgList &Args,
+ frontend::ActionKind Action) {
using namespace options;
- Opts.ShowCPP = !Args.hasArg(OPT_dM);
+
+ switch (Action) {
+ case frontend::ASTDeclList:
+ case frontend::ASTDump:
+ case frontend::ASTDumpXML:
+ case frontend::ASTPrint:
+ case frontend::ASTView:
+ case frontend::EmitAssembly:
+ case frontend::EmitBC:
+ case frontend::EmitHTML:
+ case frontend::EmitLLVM:
+ case frontend::EmitLLVMOnly:
+ case frontend::EmitCodeGenOnly:
+ case frontend::EmitObj:
+ case frontend::FixIt:
+ case frontend::GenerateModule:
+ case frontend::GeneratePCH:
+ case frontend::GeneratePTH:
+ case frontend::ParseSyntaxOnly:
+ case frontend::ModuleFileInfo:
+ case frontend::PluginAction:
+ case frontend::PrintDeclContext:
+ case frontend::RewriteObjC:
+ case frontend::RewriteTest:
+ case frontend::RunAnalysis:
+ case frontend::MigrateSource:
+ Opts.ShowCPP = 0;
+ break;
+
+ case frontend::DumpRawTokens:
+ case frontend::DumpTokens:
+ case frontend::InitOnly:
+ case frontend::PrintPreamble:
+ case frontend::PrintPreprocessedInput:
+ case frontend::RewriteMacros:
+ case frontend::RunPreprocessorOnly:
+ Opts.ShowCPP = !Args.hasArg(OPT_dM);
+ break;
+ }
+
Opts.ShowComments = Args.hasArg(OPT_C);
Opts.ShowLineMarkers = !Args.hasArg(OPT_P);
Opts.ShowMacroComments = Args.hasArg(OPT_CC);
@@ -1466,6 +1550,7 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
ParseDependencyOutputArgs(Res.getDependencyOutputOpts(), *Args);
Success = ParseDiagnosticArgs(Res.getDiagnosticOpts(), *Args, &Diags)
&& Success;
+ ParseCommentArgs(Res.getLangOpts()->CommentOpts, *Args);
ParseFileSystemArgs(Res.getFileSystemOpts(), *Args);
// FIXME: We shouldn't have to pass the DashX option around here
InputKind DashX = ParseFrontendArgs(Res.getFrontendOpts(), *Args, Diags);
@@ -1483,7 +1568,8 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
// parameters from the function and the "FileManager.h" #include.
FileManager FileMgr(Res.getFileSystemOpts());
ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args, FileMgr, Diags);
- ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args);
+ ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args,
+ Res.getFrontendOpts().ProgramAction);
ParseTargetArgs(Res.getTargetOpts(), *Args);
return Success;
@@ -1492,7 +1578,7 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
namespace {
class ModuleSignature {
- llvm::SmallVector<uint64_t, 16> Data;
+ SmallVector<uint64_t, 16> Data;
unsigned CurBit;
uint64_t CurValue;
@@ -1543,6 +1629,8 @@ llvm::APInt ModuleSignature::getAsInteger() const {
}
std::string CompilerInvocation::getModuleHash() const {
+ // Note: For QoI reasons, the things we use as a hash here should all be
+ // dumped via the -module-info flag.
using llvm::hash_code;
using llvm::hash_value;
using llvm::hash_combine;
@@ -1570,6 +1658,7 @@ std::string CompilerInvocation::getModuleHash() const {
// Extend the signature with preprocessor options.
const PreprocessorOptions &ppOpts = getPreprocessorOpts();
+ const HeaderSearchOptions &hsOpts = getHeaderSearchOpts();
code = hash_combine(code, ppOpts.UsePredefines, ppOpts.DetailedRecord);
std::vector<StringRef> MacroDefs;
@@ -1577,11 +1666,19 @@ std::string CompilerInvocation::getModuleHash() const {
I = getPreprocessorOpts().Macros.begin(),
IEnd = getPreprocessorOpts().Macros.end();
I != IEnd; ++I) {
+ // If we're supposed to ignore this macro for the purposes of modules,
+ // don't put it into the hash.
+ if (!hsOpts.ModulesIgnoreMacros.empty()) {
+ // Check whether we're ignoring this macro.
+ StringRef MacroDef = I->first;
+ if (hsOpts.ModulesIgnoreMacros.count(MacroDef.split('=').first))
+ continue;
+ }
+
code = hash_combine(code, I->first, I->second);
}
// Extend the signature with the sysroot.
- const HeaderSearchOptions &hsOpts = getHeaderSearchOpts();
code = hash_combine(code, hsOpts.Sysroot, hsOpts.UseBuiltinIncludes,
hsOpts.UseStandardSystemIncludes,
hsOpts.UseStandardCXXIncludes,
diff --git a/lib/Frontend/CreateInvocationFromCommandLine.cpp b/lib/Frontend/CreateInvocationFromCommandLine.cpp
index d82cb6d..e25eb43 100644
--- a/lib/Frontend/CreateInvocationFromCommandLine.cpp
+++ b/lib/Frontend/CreateInvocationFromCommandLine.cpp
@@ -11,15 +11,15 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Frontend/Utils.h"
-#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Driver/ArgList.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
-#include "clang/Driver/ArgList.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/Tool.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
#include "llvm/Support/Host.h"
using namespace clang;
@@ -34,9 +34,7 @@ clang::createInvocationFromCommandLine(ArrayRef<const char *> ArgList,
if (!Diags.getPtr()) {
// No diagnostics engine was provided, so create our own diagnostics object
// with the default options.
- Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions,
- ArgList.size(),
- ArgList.begin());
+ Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions);
}
SmallVector<const char *, 16> Args;
@@ -48,7 +46,7 @@ clang::createInvocationFromCommandLine(ArrayRef<const char *> ArgList,
// FIXME: We shouldn't have to pass in the path info.
driver::Driver TheDriver("clang", llvm::sys::getDefaultTargetTriple(),
- "a.out", false, *Diags);
+ "a.out", *Diags);
// Don't check that inputs exist, they may have been remapped.
TheDriver.setCheckInputsExist(false);
diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp
index 53ea8be..628def6 100644
--- a/lib/Frontend/DependencyFile.cpp
+++ b/lib/Frontend/DependencyFile.cpp
@@ -151,12 +151,14 @@ void DependencyFileCallback::AddFilename(StringRef Filename) {
Files.push_back(Filename);
}
-/// PrintFilename - GCC escapes spaces, but apparently not ' or " or other
-/// scary characters.
+/// PrintFilename - GCC escapes spaces, # and $, but apparently not ' or " or
+/// other scary characters.
static void PrintFilename(raw_ostream &OS, StringRef Filename) {
for (unsigned i = 0, e = Filename.size(); i != e; ++i) {
- if (Filename[i] == ' ')
+ if (Filename[i] == ' ' || Filename[i] == '#')
OS << '\\';
+ else if (Filename[i] == '$') // $ is escaped by $$.
+ OS << '$';
OS << Filename[i];
}
}
diff --git a/lib/Frontend/DependencyGraph.cpp b/lib/Frontend/DependencyGraph.cpp
index 28d9c5d..e128d91 100644
--- a/lib/Frontend/DependencyGraph.cpp
+++ b/lib/Frontend/DependencyGraph.cpp
@@ -19,8 +19,8 @@
#include "clang/Lex/PPCallbacks.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/SetVector.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/GraphWriter.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
namespace DOT = llvm::DOT;
@@ -31,15 +31,14 @@ class DependencyGraphCallback : public PPCallbacks {
std::string OutputFile;
std::string SysRoot;
llvm::SetVector<const FileEntry *> AllFiles;
- typedef llvm::DenseMap<const FileEntry *,
- llvm::SmallVector<const FileEntry *, 2> >
- DependencyMap;
+ typedef llvm::DenseMap<const FileEntry *,
+ SmallVector<const FileEntry *, 2> > DependencyMap;
DependencyMap Dependencies;
private:
- llvm::raw_ostream &writeNodeReference(llvm::raw_ostream &OS,
- const FileEntry *Node);
+ raw_ostream &writeNodeReference(raw_ostream &OS,
+ const FileEntry *Node);
void OutputGraphFile();
public:
@@ -93,8 +92,8 @@ void DependencyGraphCallback::InclusionDirective(SourceLocation HashLoc,
AllFiles.insert(FromFile);
}
-llvm::raw_ostream &
-DependencyGraphCallback::writeNodeReference(llvm::raw_ostream &OS,
+raw_ostream &
+DependencyGraphCallback::writeNodeReference(raw_ostream &OS,
const FileEntry *Node) {
OS << "header_" << Node->getUID();
return OS;
diff --git a/lib/Frontend/DiagnosticRenderer.cpp b/lib/Frontend/DiagnosticRenderer.cpp
index 359b82b..3b4f55c 100644
--- a/lib/Frontend/DiagnosticRenderer.cpp
+++ b/lib/Frontend/DiagnosticRenderer.cpp
@@ -11,15 +11,15 @@
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Lex/Lexer.h"
-#include "clang/Edit/EditedSource.h"
#include "clang/Edit/Commit.h"
+#include "clang/Edit/EditedSource.h"
#include "clang/Edit/EditsReceiver.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/ErrorHandling.h"
+#include "clang/Lex/Lexer.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
#include <algorithm>
using namespace clang;
@@ -47,6 +47,11 @@ static StringRef getImmediateMacroName(SourceLocation Loc,
while (SM.isMacroArgExpansion(Loc))
Loc = SM.getImmediateExpansionRange(Loc).first;
+ // If the macro's spelling has no FileID, then it's actually a token paste
+ // or stringization (or similar) and not a macro at all.
+ if (!SM.getFileEntryForID(SM.getFileID(SM.getSpellingLoc(Loc))))
+ return StringRef();
+
// Find the spelling location of the start of the non-argument expansion
// range. This is where the macro name was spelled in order to begin
// expanding this macro.
@@ -123,28 +128,18 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc,
const SourceManager *SM,
DiagOrStoredDiag D) {
assert(SM || Loc.isInvalid());
-
+
beginDiagnostic(D, Level);
-
- PresumedLoc PLoc;
- if (Loc.isValid()) {
- PLoc = SM->getPresumedLocForDisplay(Loc);
-
- // First, if this diagnostic is not in the main file, print out the
- // "included from" lines.
- emitIncludeStack(PLoc.getIncludeLoc(), Level, *SM);
- }
-
- // Next, emit the actual diagnostic message.
- emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, SM, D);
-
- // Only recurse if we have a valid location.
- if (Loc.isValid()) {
+
+ if (!Loc.isValid())
+ // If we have no source location, just emit the diagnostic message.
+ emitDiagnosticMessage(Loc, PresumedLoc(), Level, Message, Ranges, SM, D);
+ else {
// Get the ranges into a local array we can hack on.
SmallVector<CharSourceRange, 20> MutableRanges(Ranges.begin(),
Ranges.end());
-
- llvm::SmallVector<FixItHint, 8> MergedFixits;
+
+ SmallVector<FixItHint, 8> MergedFixits;
if (!FixItHints.empty()) {
mergeFixits(FixItHints, *SM, LangOpts, MergedFixits);
FixItHints = MergedFixits;
@@ -155,15 +150,34 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc,
I != E; ++I)
if (I->RemoveRange.isValid())
MutableRanges.push_back(I->RemoveRange);
-
- unsigned MacroDepth = 0;
- emitMacroExpansionsAndCarets(Loc, Level, MutableRanges, FixItHints, *SM,
- MacroDepth);
+
+ SourceLocation UnexpandedLoc = Loc;
+
+ // Find the ultimate expansion location for the diagnostic.
+ Loc = SM->getFileLoc(Loc);
+
+ PresumedLoc PLoc = SM->getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc);
+
+ // First, if this diagnostic is not in the main file, print out the
+ // "included from" lines.
+ emitIncludeStack(Loc, PLoc, Level, *SM);
+
+ // Next, emit the actual diagnostic message and caret.
+ emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, SM, D);
+ emitCaret(Loc, Level, MutableRanges, FixItHints, *SM);
+
+ // If this location is within a macro, walk from UnexpandedLoc up to Loc
+ // and produce a macro backtrace.
+ if (UnexpandedLoc.isValid() && UnexpandedLoc.isMacroID()) {
+ unsigned MacroDepth = 0;
+ emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints, *SM,
+ MacroDepth);
+ }
}
-
+
LastLoc = Loc;
LastLevel = Level;
-
+
endDiagnostic(D, Level);
}
@@ -184,34 +198,55 @@ void DiagnosticRenderer::emitStoredDiagnostic(StoredDiagnostic &Diag) {
/// repeated warnings occur within the same file. It also handles the logic
/// of customizing the formatting and display of the include stack.
///
+/// \param Loc The diagnostic location.
+/// \param PLoc The presumed location of the diagnostic location.
/// \param Level The diagnostic level of the message this stack pertains to.
-/// \param Loc The include location of the current file (not the diagnostic
-/// location).
void DiagnosticRenderer::emitIncludeStack(SourceLocation Loc,
+ PresumedLoc PLoc,
DiagnosticsEngine::Level Level,
const SourceManager &SM) {
+ SourceLocation IncludeLoc = PLoc.getIncludeLoc();
+
// Skip redundant include stacks altogether.
- if (LastIncludeLoc == Loc)
+ if (LastIncludeLoc == IncludeLoc)
return;
- LastIncludeLoc = Loc;
+
+ LastIncludeLoc = IncludeLoc;
if (!DiagOpts->ShowNoteIncludeStack && Level == DiagnosticsEngine::Note)
return;
-
- emitIncludeStackRecursively(Loc, SM);
+
+ if (IncludeLoc.isValid())
+ emitIncludeStackRecursively(IncludeLoc, SM);
+ else {
+ emitModuleBuildStack(SM);
+ emitImportStack(Loc, SM);
+ }
}
/// \brief Helper to recursivly walk up the include stack and print each layer
/// on the way back down.
void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc,
const SourceManager &SM) {
- if (Loc.isInvalid())
+ if (Loc.isInvalid()) {
+ emitModuleBuildStack(SM);
return;
+ }
- PresumedLoc PLoc = SM.getPresumedLoc(Loc);
+ PresumedLoc PLoc = SM.getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc);
if (PLoc.isInvalid())
return;
-
+
+ // If this source location was imported from a module, print the module
+ // import stack rather than the
+ // FIXME: We want submodule granularity here.
+ std::pair<SourceLocation, StringRef> Imported = SM.getModuleImportLoc(Loc);
+ if (Imported.first.isValid()) {
+ // This location was imported by a module. Emit the module import stack.
+ emitImportStackRecursively(Imported.first, Imported.second, SM);
+ return;
+ }
+
// Emit the other include frames first.
emitIncludeStackRecursively(PLoc.getIncludeLoc(), SM);
@@ -219,6 +254,56 @@ void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc,
emitIncludeLocation(Loc, PLoc, SM);
}
+/// \brief Emit the module import stack associated with the current location.
+void DiagnosticRenderer::emitImportStack(SourceLocation Loc,
+ const SourceManager &SM) {
+ if (Loc.isInvalid()) {
+ emitModuleBuildStack(SM);
+ return;
+ }
+
+ std::pair<SourceLocation, StringRef> NextImportLoc
+ = SM.getModuleImportLoc(Loc);
+ emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM);
+}
+
+/// \brief Helper to recursivly walk up the import stack and print each layer
+/// on the way back down.
+void DiagnosticRenderer::emitImportStackRecursively(SourceLocation Loc,
+ StringRef ModuleName,
+ const SourceManager &SM) {
+ if (Loc.isInvalid()) {
+ return;
+ }
+
+ PresumedLoc PLoc = SM.getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc);
+ if (PLoc.isInvalid())
+ return;
+
+ // Emit the other import frames first.
+ std::pair<SourceLocation, StringRef> NextImportLoc
+ = SM.getModuleImportLoc(Loc);
+ emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM);
+
+ // Emit the inclusion text/note.
+ emitImportLocation(Loc, PLoc, ModuleName, SM);
+}
+
+/// \brief Emit the module build stack, for cases where a module is (re-)built
+/// on demand.
+void DiagnosticRenderer::emitModuleBuildStack(const SourceManager &SM) {
+ ModuleBuildStack Stack = SM.getModuleBuildStack();
+ for (unsigned I = 0, N = Stack.size(); I != N; ++I) {
+ const SourceManager &CurSM = Stack[I].second.getManager();
+ SourceLocation CurLoc = Stack[I].second;
+ emitBuildingModuleLocation(CurLoc,
+ CurSM.getPresumedLoc(CurLoc,
+ DiagOpts->ShowPresumedLoc),
+ Stack[I].first,
+ CurSM);
+ }
+}
+
// Helper function to fix up source ranges. It takes in an array of ranges,
// and outputs an array of ranges where we want to draw the range highlighting
// around the location specified by CaretLoc.
@@ -231,31 +316,58 @@ void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc,
// iff the FileID is the same.
static void mapDiagnosticRanges(
SourceLocation CaretLoc,
- const SmallVectorImpl<CharSourceRange>& Ranges,
- SmallVectorImpl<CharSourceRange>& SpellingRanges,
+ ArrayRef<CharSourceRange> Ranges,
+ SmallVectorImpl<CharSourceRange> &SpellingRanges,
const SourceManager *SM) {
FileID CaretLocFileID = SM->getFileID(CaretLoc);
- for (SmallVectorImpl<CharSourceRange>::const_iterator I = Ranges.begin(),
+ for (ArrayRef<CharSourceRange>::const_iterator I = Ranges.begin(),
E = Ranges.end();
I != E; ++I) {
SourceLocation Begin = I->getBegin(), End = I->getEnd();
bool IsTokenRange = I->isTokenRange();
- // Search the macro caller chain for the beginning of the range.
- while (Begin.isMacroID() && SM->getFileID(Begin) != CaretLocFileID)
- Begin = SM->getImmediateMacroCallerLoc(Begin);
+ FileID BeginFileID = SM->getFileID(Begin);
+ FileID EndFileID = SM->getFileID(End);
- // Search the macro caller chain for the beginning of the range.
- while (End.isMacroID() && SM->getFileID(End) != CaretLocFileID) {
- // The computation of the next End is an inlined version of
- // getImmediateMacroCallerLoc, except it chooses the end of an
- // expansion range.
- if (SM->isMacroArgExpansion(End)) {
+ // Find the common parent for the beginning and end of the range.
+
+ // First, crawl the expansion chain for the beginning of the range.
+ llvm::SmallDenseMap<FileID, SourceLocation> BeginLocsMap;
+ while (Begin.isMacroID() && BeginFileID != EndFileID) {
+ BeginLocsMap[BeginFileID] = Begin;
+ Begin = SM->getImmediateExpansionRange(Begin).first;
+ BeginFileID = SM->getFileID(Begin);
+ }
+
+ // Then, crawl the expansion chain for the end of the range.
+ if (BeginFileID != EndFileID) {
+ while (End.isMacroID() && !BeginLocsMap.count(EndFileID)) {
+ End = SM->getImmediateExpansionRange(End).second;
+ EndFileID = SM->getFileID(End);
+ }
+ if (End.isMacroID()) {
+ Begin = BeginLocsMap[EndFileID];
+ BeginFileID = EndFileID;
+ }
+ }
+
+ while (Begin.isMacroID() && BeginFileID != CaretLocFileID) {
+ if (SM->isMacroArgExpansion(Begin)) {
+ Begin = SM->getImmediateSpellingLoc(Begin);
End = SM->getImmediateSpellingLoc(End);
} else {
+ Begin = SM->getImmediateExpansionRange(Begin).first;
End = SM->getImmediateExpansionRange(End).second;
}
+ BeginFileID = SM->getFileID(Begin);
+ if (BeginFileID != SM->getFileID(End)) {
+ // FIXME: Ugly hack to stop a crash; this code is making bad
+ // assumptions and it's too complicated for me to reason
+ // about.
+ Begin = End = SourceLocation();
+ break;
+ }
}
// Return the spelling location of the beginning and end of the range.
@@ -266,6 +378,16 @@ static void mapDiagnosticRanges(
}
}
+void DiagnosticRenderer::emitCaret(SourceLocation Loc,
+ DiagnosticsEngine::Level Level,
+ ArrayRef<CharSourceRange> Ranges,
+ ArrayRef<FixItHint> Hints,
+ const SourceManager &SM) {
+ SmallVector<CharSourceRange, 4> SpellingRanges;
+ mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM);
+ emitCodeContext(Loc, Level, SpellingRanges, Hints, SM);
+}
+
/// \brief Recursively emit notes for each macro expansion and caret
/// diagnostics where appropriate.
///
@@ -277,48 +399,24 @@ static void mapDiagnosticRanges(
/// \param Level The diagnostic level currently being emitted.
/// \param Ranges The underlined ranges for this code snippet.
/// \param Hints The FixIt hints active for this diagnostic.
-/// \param MacroSkipEnd The depth to stop skipping macro expansions.
/// \param OnMacroInst The current depth of the macro expansion stack.
-void DiagnosticRenderer::emitMacroExpansionsAndCarets(
- SourceLocation Loc,
- DiagnosticsEngine::Level Level,
- SmallVectorImpl<CharSourceRange>& Ranges,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM,
- unsigned &MacroDepth,
- unsigned OnMacroInst)
-{
+void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc,
+ DiagnosticsEngine::Level Level,
+ ArrayRef<CharSourceRange> Ranges,
+ ArrayRef<FixItHint> Hints,
+ const SourceManager &SM,
+ unsigned &MacroDepth,
+ unsigned OnMacroInst) {
assert(!Loc.isInvalid() && "must have a valid source location here");
-
- // If this is a file source location, directly emit the source snippet and
- // caret line. Also record the macro depth reached.
- if (Loc.isFileID()) {
- // Map the ranges.
- SmallVector<CharSourceRange, 4> SpellingRanges;
- mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM);
-
- assert(MacroDepth == 0 && "We shouldn't hit a leaf node twice!");
- MacroDepth = OnMacroInst;
- emitCodeContext(Loc, Level, SpellingRanges, Hints, SM);
- return;
- }
- // Otherwise recurse through each macro expansion layer.
-
- // When processing macros, skip over the expansions leading up to
- // a macro argument, and trace the argument's expansion stack instead.
- Loc = SM.skipToMacroArgExpansion(Loc);
-
+
+ // Walk up to the caller of this macro, and produce a backtrace down to there.
SourceLocation OneLevelUp = SM.getImmediateMacroCallerLoc(Loc);
+ if (OneLevelUp.isMacroID())
+ emitMacroExpansions(OneLevelUp, Level, Ranges, Hints, SM,
+ MacroDepth, OnMacroInst + 1);
+ else
+ MacroDepth = OnMacroInst + 1;
- emitMacroExpansionsAndCarets(OneLevelUp, Level, Ranges, Hints, SM, MacroDepth,
- OnMacroInst + 1);
-
- // Save the original location so we can find the spelling of the macro call.
- SourceLocation MacroLoc = Loc;
-
- // Map the location.
- Loc = SM.getImmediateMacroCalleeLoc(Loc);
-
unsigned MacroSkipStart = 0, MacroSkipEnd = 0;
if (MacroDepth > DiagOpts->MacroBacktraceLimit &&
DiagOpts->MacroBacktraceLimit != 0) {
@@ -326,11 +424,11 @@ void DiagnosticRenderer::emitMacroExpansionsAndCarets(
DiagOpts->MacroBacktraceLimit % 2;
MacroSkipEnd = MacroDepth - DiagOpts->MacroBacktraceLimit / 2;
}
-
+
// Whether to suppress printing this macro expansion.
bool Suppressed = (OnMacroInst >= MacroSkipStart &&
OnMacroInst < MacroSkipEnd);
-
+
if (Suppressed) {
// Tell the user that we've skipped contexts.
if (OnMacroInst == MacroSkipStart) {
@@ -344,15 +442,27 @@ void DiagnosticRenderer::emitMacroExpansionsAndCarets(
return;
}
- // Map the ranges.
+ // Find the spelling location for the macro definition. We must use the
+ // spelling location here to avoid emitting a macro bactrace for the note.
+ SourceLocation SpellingLoc = Loc;
+ // If this is the expansion of a macro argument, point the caret at the
+ // use of the argument in the definition of the macro, not the expansion.
+ if (SM.isMacroArgExpansion(Loc))
+ SpellingLoc = SM.getImmediateExpansionRange(Loc).first;
+ SpellingLoc = SM.getSpellingLoc(SpellingLoc);
+
+ // Map the ranges into the FileID of the diagnostic location.
SmallVector<CharSourceRange, 4> SpellingRanges;
- mapDiagnosticRanges(MacroLoc, Ranges, SpellingRanges, &SM);
+ mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM);
SmallString<100> MessageStorage;
llvm::raw_svector_ostream Message(MessageStorage);
- Message << "expanded from macro '"
- << getImmediateMacroName(MacroLoc, SM, LangOpts) << "'";
- emitDiagnostic(SM.getSpellingLoc(Loc), DiagnosticsEngine::Note,
+ StringRef MacroName = getImmediateMacroName(Loc, SM, LangOpts);
+ if (MacroName.empty())
+ Message << "expanded from here";
+ else
+ Message << "expanded from macro '" << MacroName << "'";
+ emitDiagnostic(SpellingLoc, DiagnosticsEngine::Note,
Message.str(),
SpellingRanges, ArrayRef<FixItHint>(), &SM);
}
@@ -370,6 +480,32 @@ void DiagnosticNoteRenderer::emitIncludeLocation(SourceLocation Loc,
emitNote(Loc, Message.str(), &SM);
}
+void DiagnosticNoteRenderer::emitImportLocation(SourceLocation Loc,
+ PresumedLoc PLoc,
+ StringRef ModuleName,
+ const SourceManager &SM) {
+ // Generate a note indicating the include location.
+ SmallString<200> MessageStorage;
+ llvm::raw_svector_ostream Message(MessageStorage);
+ Message << "in module '" << ModuleName << "' imported from "
+ << PLoc.getFilename() << ':' << PLoc.getLine() << ":";
+ emitNote(Loc, Message.str(), &SM);
+}
+
+void
+DiagnosticNoteRenderer::emitBuildingModuleLocation(SourceLocation Loc,
+ PresumedLoc PLoc,
+ StringRef ModuleName,
+ const SourceManager &SM) {
+ // Generate a note indicating the include location.
+ SmallString<200> MessageStorage;
+ llvm::raw_svector_ostream Message(MessageStorage);
+ Message << "while building module '" << ModuleName << "' imported from "
+ << PLoc.getFilename() << ':' << PLoc.getLine() << ":";
+ emitNote(Loc, Message.str(), &SM);
+}
+
+
void DiagnosticNoteRenderer::emitBasicNote(StringRef Message) {
emitNote(SourceLocation(), Message, 0);
}
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
index 2e9a791..6031ad2 100644
--- a/lib/Frontend/FrontendAction.cpp
+++ b/lib/Frontend/FrontendAction.cpp
@@ -11,8 +11,6 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclGroup.h"
-#include "clang/Lex/HeaderSearch.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/ChainedIncludesSource.h"
#include "clang/Frontend/CompilerInstance.h"
@@ -20,15 +18,18 @@
#include "clang/Frontend/FrontendPluginRegistry.h"
#include "clang/Frontend/LayoutOverrideSource.h"
#include "clang/Frontend/MultiplexConsumer.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/ParseAST.h"
#include "clang/Serialization/ASTDeserializationListener.h"
#include "clang/Serialization/ASTReader.h"
+#include "clang/Serialization/GlobalModuleIndex.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
-#include "llvm/Support/Timer.h"
using namespace clang;
namespace {
@@ -187,6 +188,10 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
setCurrentInput(Input, AST);
+ // Inform the diagnostic client we are processing a source file.
+ CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), 0);
+ HasBegunSourceFile = true;
+
// Set the shared objects, these are reset when we finish processing the
// file, otherwise the CompilerInstance will happily destroy them.
CI.setFileManager(&AST->getFileManager());
@@ -198,7 +203,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
if (!BeginSourceFileAction(CI, InputFile))
goto failure;
- /// Create the AST consumer.
+ // Create the AST consumer.
CI.setASTConsumer(CreateWrappedASTConsumer(CI, InputFile));
if (!CI.hasASTConsumer())
goto failure;
@@ -246,16 +251,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
CI.getLangOpts(),
CI.getTargetOpts(),
CI.getPreprocessorOpts())) {
- for (unsigned I = 0, N = PPOpts.Includes.size(); I != N; ++I) {
- if (PPOpts.Includes[I] == PPOpts.ImplicitPCHInclude) {
- PPOpts.Includes[I] = Dir->path();
- PPOpts.ImplicitPCHInclude = Dir->path();
- Found = true;
- break;
- }
- }
-
- assert(Found && "Implicit PCH include not in includes list?");
+ PPOpts.ImplicitPCHInclude = Dir->path();
+ Found = true;
break;
}
}
@@ -279,8 +276,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
if (!BeginSourceFileAction(CI, InputFile))
goto failure;
- /// Create the AST context and consumer unless this is a preprocessor only
- /// action.
+ // Create the AST context and consumer unless this is a preprocessor only
+ // action.
if (!usesPreprocessorOnly()) {
CI.createASTContext();
@@ -290,8 +287,6 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
goto failure;
CI.getASTContext().setASTMutationListener(Consumer->GetASTMutationListener());
- CI.getPreprocessor().setPPMutationListener(
- Consumer->GetPPMutationListener());
if (!CI.getPreprocessorOpts().ChainedIncludes.empty()) {
// Convert headers to PCH and chain them.
@@ -380,6 +375,15 @@ bool FrontendAction::Execute() {
}
else ExecuteAction();
+ // If we are supposed to rebuild the global module index, do so now unless
+ // there were any module-build failures.
+ if (CI.shouldBuildGlobalModuleIndex() && CI.hasFileManager() &&
+ CI.hasPreprocessor()) {
+ GlobalModuleIndex::writeIndex(
+ CI.getFileManager(),
+ CI.getPreprocessor().getHeaderSearchInfo().getModuleCachePath());
+ }
+
return true;
}
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
index 47063f7..5c7567f 100644
--- a/lib/Frontend/FrontendActions.cpp
+++ b/lib/Frontend/FrontendActions.cpp
@@ -9,16 +9,17 @@
#include "clang/Frontend/FrontendActions.h"
#include "clang/AST/ASTConsumer.h"
-#include "clang/Lex/HeaderSearch.h"
-#include "clang/Lex/Pragma.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Parse/Parser.h"
#include "clang/Basic/FileManager.h"
#include "clang/Frontend/ASTConsumers.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/Utils.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/Pragma.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Serialization/ASTReader.h"
#include "clang/Serialization/ASTWriter.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/FileSystem.h"
@@ -173,12 +174,12 @@ static void collectModuleHeaderIncludes(const LangOptions &LangOpts,
// Add includes for each of these headers.
for (unsigned I = 0, N = Module->Headers.size(); I != N; ++I) {
const FileEntry *Header = Module->Headers[I];
- Module->TopHeaders.insert(Header);
+ Module->addTopHeader(Header);
addHeaderInclude(Header, Includes, LangOpts);
}
if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader()) {
- Module->TopHeaders.insert(UmbrellaHeader);
+ Module->addTopHeader(UmbrellaHeader);
if (Module->Parent) {
// Include the umbrella header for submodules.
addHeaderInclude(UmbrellaHeader, Includes, LangOpts);
@@ -203,7 +204,7 @@ static void collectModuleHeaderIncludes(const LangOptions &LangOpts,
if (const FileEntry *Header = FileMgr.getFile(Dir->path())) {
if (ModMap.isHeaderInUnavailableModule(Header))
continue;
- Module->TopHeaders.insert(Header);
+ Module->addTopHeader(Header);
}
// Include this header umbrella header for submodules.
@@ -273,19 +274,11 @@ bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI,
CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(),
Module, HeaderContents);
- StringRef InputName = Module::getModuleInputBufferName();
-
- // We consistently construct a buffer as input to build the module.
- // This means the main file for modules will always be a virtual one.
- // FIXME: Maybe allow using a memory buffer as input directly instead of
- // messing with virtual files.
- const FileEntry *HeaderFile = FileMgr.getVirtualFile(InputName,
- HeaderContents.size(),
- time(0));
- llvm::MemoryBuffer *HeaderContentsBuf
- = llvm::MemoryBuffer::getMemBufferCopy(HeaderContents);
- CI.getSourceManager().overrideFileContents(HeaderFile, HeaderContentsBuf);
- setCurrentInput(FrontendInputFile(InputName, getCurrentFileKind(),
+ llvm::MemoryBuffer *InputBuffer =
+ llvm::MemoryBuffer::getMemBufferCopy(HeaderContents,
+ Module::getModuleInputBufferName());
+ // Ownership of InputBuffer will be transfered to the SourceManager.
+ setCurrentInput(FrontendInputFile(InputBuffer, getCurrentFileKind(),
Module->IsSystem));
return true;
}
@@ -324,6 +317,130 @@ ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI,
return new ASTConsumer();
}
+ASTConsumer *DumpModuleInfoAction::CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) {
+ return new ASTConsumer();
+}
+
+namespace {
+ /// \brief AST reader listener that dumps module information for a module
+ /// file.
+ class DumpModuleInfoListener : public ASTReaderListener {
+ llvm::raw_ostream &Out;
+
+ public:
+ DumpModuleInfoListener(llvm::raw_ostream &Out) : Out(Out) { }
+
+#define DUMP_BOOLEAN(Value, Text) \
+ Out.indent(4) << Text << ": " << (Value? "Yes" : "No") << "\n"
+
+ virtual bool ReadFullVersionInformation(StringRef FullVersion) {
+ Out.indent(2)
+ << "Generated by "
+ << (FullVersion == getClangFullRepositoryVersion()? "this"
+ : "a different")
+ << " Clang: " << FullVersion << "\n";
+ return ASTReaderListener::ReadFullVersionInformation(FullVersion);
+ }
+
+ virtual bool ReadLanguageOptions(const LangOptions &LangOpts,
+ bool Complain) {
+ Out.indent(2) << "Language options:\n";
+#define LANGOPT(Name, Bits, Default, Description) \
+ DUMP_BOOLEAN(LangOpts.Name, Description);
+#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
+ Out.indent(4) << Description << ": " \
+ << static_cast<unsigned>(LangOpts.get##Name()) << "\n";
+#define VALUE_LANGOPT(Name, Bits, Default, Description) \
+ Out.indent(4) << Description << ": " << LangOpts.Name << "\n";
+#define BENIGN_LANGOPT(Name, Bits, Default, Description)
+#define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description)
+#include "clang/Basic/LangOptions.def"
+ return false;
+ }
+
+ virtual bool ReadTargetOptions(const TargetOptions &TargetOpts,
+ bool Complain) {
+ Out.indent(2) << "Target options:\n";
+ Out.indent(4) << " Triple: " << TargetOpts.Triple << "\n";
+ Out.indent(4) << " CPU: " << TargetOpts.CPU << "\n";
+ Out.indent(4) << " ABI: " << TargetOpts.ABI << "\n";
+ Out.indent(4) << " C++ ABI: " << TargetOpts.CXXABI << "\n";
+ Out.indent(4) << " Linker version: " << TargetOpts.LinkerVersion << "\n";
+
+ if (!TargetOpts.FeaturesAsWritten.empty()) {
+ Out.indent(4) << "Target features:\n";
+ for (unsigned I = 0, N = TargetOpts.FeaturesAsWritten.size();
+ I != N; ++I) {
+ Out.indent(6) << TargetOpts.FeaturesAsWritten[I] << "\n";
+ }
+ }
+
+ return false;
+ }
+
+ virtual bool ReadHeaderSearchOptions(const HeaderSearchOptions &HSOpts,
+ bool Complain) {
+ Out.indent(2) << "Header search options:\n";
+ Out.indent(4) << "System root [-isysroot=]: '" << HSOpts.Sysroot << "'\n";
+ DUMP_BOOLEAN(HSOpts.UseBuiltinIncludes,
+ "Use builtin include directories [-nobuiltininc]");
+ DUMP_BOOLEAN(HSOpts.UseStandardSystemIncludes,
+ "Use standard system include directories [-nostdinc]");
+ DUMP_BOOLEAN(HSOpts.UseStandardCXXIncludes,
+ "Use standard C++ include directories [-nostdinc++]");
+ DUMP_BOOLEAN(HSOpts.UseLibcxx,
+ "Use libc++ (rather than libstdc++) [-stdlib=]");
+ return false;
+ }
+
+ virtual bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts,
+ bool Complain,
+ std::string &SuggestedPredefines) {
+ Out.indent(2) << "Preprocessor options:\n";
+ DUMP_BOOLEAN(PPOpts.UsePredefines,
+ "Uses compiler/target-specific predefines [-undef]");
+ DUMP_BOOLEAN(PPOpts.DetailedRecord,
+ "Uses detailed preprocessing record (for indexing)");
+
+ if (!PPOpts.Macros.empty()) {
+ Out.indent(4) << "Predefined macros:\n";
+ }
+
+ for (std::vector<std::pair<std::string, bool/*isUndef*/> >::const_iterator
+ I = PPOpts.Macros.begin(), IEnd = PPOpts.Macros.end();
+ I != IEnd; ++I) {
+ Out.indent(6);
+ if (I->second)
+ Out << "-U";
+ else
+ Out << "-D";
+ Out << I->first << "\n";
+ }
+ return false;
+ }
+#undef DUMP_BOOLEAN
+ };
+}
+
+void DumpModuleInfoAction::ExecuteAction() {
+ // Set up the output file.
+ llvm::OwningPtr<llvm::raw_fd_ostream> OutFile;
+ StringRef OutputFileName = getCompilerInstance().getFrontendOpts().OutputFile;
+ if (!OutputFileName.empty() && OutputFileName != "-") {
+ std::string ErrorInfo;
+ OutFile.reset(new llvm::raw_fd_ostream(OutputFileName.str().c_str(),
+ ErrorInfo));
+ }
+ llvm::raw_ostream &Out = OutFile.get()? *OutFile.get() : llvm::outs();
+
+ Out << "Information for module file '" << getCurrentFile() << "':\n";
+ DumpModuleInfoListener Listener(Out);
+ ASTReader::readASTFileControlBlock(getCurrentFile(),
+ getCompilerInstance().getFileManager(),
+ Listener);
+}
+
//===----------------------------------------------------------------------===//
// Preprocessor Actions
//===----------------------------------------------------------------------===//
diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp
index ea4005f..f1823c6 100644
--- a/lib/Frontend/FrontendOptions.cpp
+++ b/lib/Frontend/FrontendOptions.cpp
@@ -13,7 +13,7 @@ using namespace clang;
InputKind FrontendOptions::getInputKindForExtension(StringRef Extension) {
return llvm::StringSwitch<InputKind>(Extension)
- .Case("ast", IK_AST)
+ .Cases("ast", "pcm", IK_AST)
.Case("c", IK_C)
.Cases("S", "s", IK_Asm)
.Case("i", IK_PreprocessedC)
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index 4fddd11..35eec56 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -14,19 +14,18 @@
#include "clang/Frontend/Utils.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
-#include "clang/Lex/HeaderSearchOptions.h"
+#include "clang/Config/config.h" // C_INCLUDE_DIRS
#include "clang/Lex/HeaderSearch.h"
-#include "llvm/ADT/SmallString.h"
+#include "clang/Lex/HeaderSearchOptions.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Triple.h"
#include "llvm/ADT/Twine.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Path.h"
-
-#include "clang/Config/config.h" // C_INCLUDE_DIRS
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace clang::frontend;
@@ -44,19 +43,23 @@ class InitHeaderSearch {
HeaderSearch &Headers;
bool Verbose;
std::string IncludeSysroot;
- bool IsNotEmptyOrRoot;
+ bool HasSysroot;
public:
InitHeaderSearch(HeaderSearch &HS, bool verbose, StringRef sysroot)
: Headers(HS), Verbose(verbose), IncludeSysroot(sysroot),
- IsNotEmptyOrRoot(!(sysroot.empty() || sysroot == "/")) {
+ HasSysroot(!(sysroot.empty() || sysroot == "/")) {
}
- /// AddPath - Add the specified path to the specified group list.
- void AddPath(const Twine &Path, IncludeDirGroup Group,
- bool isCXXAware, bool isUserSupplied,
- bool isFramework, bool IgnoreSysRoot = false);
+ /// AddPath - Add the specified path to the specified group list, prefixing
+ /// the sysroot if used.
+ void AddPath(const Twine &Path, IncludeDirGroup Group, bool isFramework);
+
+ /// AddUnmappedPath - Add the specified path to the specified group list,
+ /// without performing any sysroot remapping.
+ void AddUnmappedPath(const Twine &Path, IncludeDirGroup Group,
+ bool isFramework);
/// AddSystemHeaderPrefix - Add the specified prefix to the system header
/// prefix list.
@@ -105,45 +108,52 @@ public:
} // end anonymous namespace.
-void InitHeaderSearch::AddPath(const Twine &Path,
- IncludeDirGroup Group, bool isCXXAware,
- bool isUserSupplied, bool isFramework,
- bool IgnoreSysRoot) {
- assert(!Path.isTriviallyEmpty() && "can't handle empty path here");
- FileManager &FM = Headers.getFileMgr();
-
- // Compute the actual path, taking into consideration -isysroot.
- SmallString<256> MappedPathStorage;
- StringRef MappedPathStr = Path.toStringRef(MappedPathStorage);
-
- // Handle isysroot.
- if ((Group == System || Group == CXXSystem) && !IgnoreSysRoot &&
+static bool CanPrefixSysroot(StringRef Path) {
#if defined(_WIN32)
- !MappedPathStr.empty() &&
- llvm::sys::path::is_separator(MappedPathStr[0]) &&
+ return !Path.empty() && llvm::sys::path::is_separator(Path[0]);
#else
- llvm::sys::path::is_absolute(MappedPathStr) &&
+ return llvm::sys::path::is_absolute(Path);
#endif
- IsNotEmptyOrRoot) {
- MappedPathStorage.clear();
- MappedPathStr =
- (IncludeSysroot + Path).toStringRef(MappedPathStorage);
+}
+
+void InitHeaderSearch::AddPath(const Twine &Path, IncludeDirGroup Group,
+ bool isFramework) {
+ // Add the path with sysroot prepended, if desired and this is a system header
+ // group.
+ if (HasSysroot) {
+ SmallString<256> MappedPathStorage;
+ StringRef MappedPathStr = Path.toStringRef(MappedPathStorage);
+ if (CanPrefixSysroot(MappedPathStr)) {
+ AddUnmappedPath(IncludeSysroot + Path, Group, isFramework);
+ return;
+ }
}
+ AddUnmappedPath(Path, Group, isFramework);
+}
+
+void InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group,
+ bool isFramework) {
+ assert(!Path.isTriviallyEmpty() && "can't handle empty path here");
+
+ FileManager &FM = Headers.getFileMgr();
+ SmallString<256> MappedPathStorage;
+ StringRef MappedPathStr = Path.toStringRef(MappedPathStorage);
+
// Compute the DirectoryLookup type.
SrcMgr::CharacteristicKind Type;
- if (Group == Quoted || Group == Angled || Group == IndexHeaderMap)
+ if (Group == Quoted || Group == Angled || Group == IndexHeaderMap) {
Type = SrcMgr::C_User;
- else if (isCXXAware)
- Type = SrcMgr::C_System;
- else
+ } else if (Group == ExternCSystem) {
Type = SrcMgr::C_ExternCSystem;
-
+ } else {
+ Type = SrcMgr::C_System;
+ }
// If the directory exists, add it.
if (const DirectoryEntry *DE = FM.getDirectory(MappedPathStr)) {
- IncludePath.push_back(std::make_pair(Group, DirectoryLookup(DE, Type,
- isUserSupplied, isFramework)));
+ IncludePath.push_back(
+ std::make_pair(Group, DirectoryLookup(DE, Type, isFramework)));
return;
}
@@ -153,8 +163,9 @@ void InitHeaderSearch::AddPath(const Twine &Path,
if (const FileEntry *FE = FM.getFile(MappedPathStr)) {
if (const HeaderMap *HM = Headers.CreateHeaderMap(FE)) {
// It is a headermap, add it to the search path.
- IncludePath.push_back(std::make_pair(Group, DirectoryLookup(HM, Type,
- isUserSupplied, Group == IndexHeaderMap)));
+ IncludePath.push_back(
+ std::make_pair(Group,
+ DirectoryLookup(HM, Type, Group == IndexHeaderMap)));
return;
}
}
@@ -171,42 +182,42 @@ void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(StringRef Base,
StringRef Dir64,
const llvm::Triple &triple) {
// Add the base dir
- AddPath(Base, CXXSystem, true, false, false);
+ AddPath(Base, CXXSystem, false);
// Add the multilib dirs
llvm::Triple::ArchType arch = triple.getArch();
bool is64bit = arch == llvm::Triple::ppc64 || arch == llvm::Triple::x86_64;
if (is64bit)
- AddPath(Base + "/" + ArchDir + "/" + Dir64, CXXSystem, true, false, false);
+ AddPath(Base + "/" + ArchDir + "/" + Dir64, CXXSystem, false);
else
- AddPath(Base + "/" + ArchDir + "/" + Dir32, CXXSystem, true, false, false);
+ AddPath(Base + "/" + ArchDir + "/" + Dir32, CXXSystem, false);
// Add the backward dir
- AddPath(Base + "/backward", CXXSystem, true, false, false);
+ AddPath(Base + "/backward", CXXSystem, false);
}
void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(StringRef Base,
StringRef Arch,
StringRef Version) {
AddPath(Base + "/" + Arch + "/" + Version + "/include/c++",
- CXXSystem, true, false, false);
+ CXXSystem, false);
AddPath(Base + "/" + Arch + "/" + Version + "/include/c++/" + Arch,
- CXXSystem, true, false, false);
+ CXXSystem, false);
AddPath(Base + "/" + Arch + "/" + Version + "/include/c++/backward",
- CXXSystem, true, false, false);
+ CXXSystem, false);
}
void InitHeaderSearch::AddMinGW64CXXPaths(StringRef Base,
StringRef Version) {
// Assumes Base is HeaderSearchOpts' ResourceDir
AddPath(Base + "/../../../include/c++/" + Version,
- CXXSystem, true, false, false);
+ CXXSystem, false);
AddPath(Base + "/../../../include/c++/" + Version + "/x86_64-w64-mingw32",
- CXXSystem, true, false, false);
+ CXXSystem, false);
AddPath(Base + "/../../../include/c++/" + Version + "/i686-w64-mingw32",
- CXXSystem, true, false, false);
+ CXXSystem, false);
AddPath(Base + "/../../../include/c++/" + Version + "/backward",
- CXXSystem, true, false, false);
+ CXXSystem, false);
}
void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
@@ -222,7 +233,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
break;
default:
// FIXME: temporary hack: hard-coded paths.
- AddPath("/usr/local/include", System, true, false, false);
+ AddPath("/usr/local/include", System, false);
break;
}
}
@@ -234,7 +245,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
// supplied path.
llvm::sys::Path P(HSOpts.ResourceDir);
P.appendComponent("include");
- AddPath(P.str(), System, false, false, false, /*IgnoreSysRoot=*/ true);
+ AddUnmappedPath(P.str(), ExternCSystem, false);
}
// All remaining additions are for system include directories, early exit if
@@ -250,7 +261,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
for (SmallVectorImpl<StringRef>::iterator i = dirs.begin();
i != dirs.end();
++i)
- AddPath(*i, System, false, false, false);
+ AddPath(*i, ExternCSystem, false);
return;
}
@@ -260,68 +271,59 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
llvm_unreachable("Include management is handled in the driver.");
case llvm::Triple::Haiku:
- AddPath("/boot/common/include", System, true, false, false);
- AddPath("/boot/develop/headers/os", System, true, false, false);
- AddPath("/boot/develop/headers/os/app", System, true, false, false);
- AddPath("/boot/develop/headers/os/arch", System, true, false, false);
- AddPath("/boot/develop/headers/os/device", System, true, false, false);
- AddPath("/boot/develop/headers/os/drivers", System, true, false, false);
- AddPath("/boot/develop/headers/os/game", System, true, false, false);
- AddPath("/boot/develop/headers/os/interface", System, true, false, false);
- AddPath("/boot/develop/headers/os/kernel", System, true, false, false);
- AddPath("/boot/develop/headers/os/locale", System, true, false, false);
- AddPath("/boot/develop/headers/os/mail", System, true, false, false);
- AddPath("/boot/develop/headers/os/media", System, true, false, false);
- AddPath("/boot/develop/headers/os/midi", System, true, false, false);
- AddPath("/boot/develop/headers/os/midi2", System, true, false, false);
- AddPath("/boot/develop/headers/os/net", System, true, false, false);
- AddPath("/boot/develop/headers/os/storage", System, true, false, false);
- AddPath("/boot/develop/headers/os/support", System, true, false, false);
- AddPath("/boot/develop/headers/os/translation",
- System, true, false, false);
- AddPath("/boot/develop/headers/os/add-ons/graphics",
- System, true, false, false);
- AddPath("/boot/develop/headers/os/add-ons/input_server",
- System, true, false, false);
- AddPath("/boot/develop/headers/os/add-ons/screen_saver",
- System, true, false, false);
- AddPath("/boot/develop/headers/os/add-ons/tracker",
- System, true, false, false);
- AddPath("/boot/develop/headers/os/be_apps/Deskbar",
- System, true, false, false);
- AddPath("/boot/develop/headers/os/be_apps/NetPositive",
- System, true, false, false);
- AddPath("/boot/develop/headers/os/be_apps/Tracker",
- System, true, false, false);
- AddPath("/boot/develop/headers/cpp", System, true, false, false);
- AddPath("/boot/develop/headers/cpp/i586-pc-haiku",
- System, true, false, false);
- AddPath("/boot/develop/headers/3rdparty", System, true, false, false);
- AddPath("/boot/develop/headers/bsd", System, true, false, false);
- AddPath("/boot/develop/headers/glibc", System, true, false, false);
- AddPath("/boot/develop/headers/posix", System, true, false, false);
- AddPath("/boot/develop/headers", System, true, false, false);
+ AddPath("/boot/common/include", System, false);
+ AddPath("/boot/develop/headers/os", System, false);
+ AddPath("/boot/develop/headers/os/app", System, false);
+ AddPath("/boot/develop/headers/os/arch", System, false);
+ AddPath("/boot/develop/headers/os/device", System, false);
+ AddPath("/boot/develop/headers/os/drivers", System, false);
+ AddPath("/boot/develop/headers/os/game", System, false);
+ AddPath("/boot/develop/headers/os/interface", System, false);
+ AddPath("/boot/develop/headers/os/kernel", System, false);
+ AddPath("/boot/develop/headers/os/locale", System, false);
+ AddPath("/boot/develop/headers/os/mail", System, false);
+ AddPath("/boot/develop/headers/os/media", System, false);
+ AddPath("/boot/develop/headers/os/midi", System, false);
+ AddPath("/boot/develop/headers/os/midi2", System, false);
+ AddPath("/boot/develop/headers/os/net", System, false);
+ AddPath("/boot/develop/headers/os/storage", System, false);
+ AddPath("/boot/develop/headers/os/support", System, false);
+ AddPath("/boot/develop/headers/os/translation", System, false);
+ AddPath("/boot/develop/headers/os/add-ons/graphics", System, false);
+ AddPath("/boot/develop/headers/os/add-ons/input_server", System, false);
+ AddPath("/boot/develop/headers/os/add-ons/screen_saver", System, false);
+ AddPath("/boot/develop/headers/os/add-ons/tracker", System, false);
+ AddPath("/boot/develop/headers/os/be_apps/Deskbar", System, false);
+ AddPath("/boot/develop/headers/os/be_apps/NetPositive", System, false);
+ AddPath("/boot/develop/headers/os/be_apps/Tracker", System, false);
+ AddPath("/boot/develop/headers/cpp", System, false);
+ AddPath("/boot/develop/headers/cpp/i586-pc-haiku", System, false);
+ AddPath("/boot/develop/headers/3rdparty", System, false);
+ AddPath("/boot/develop/headers/bsd", System, false);
+ AddPath("/boot/develop/headers/glibc", System, false);
+ AddPath("/boot/develop/headers/posix", System, false);
+ AddPath("/boot/develop/headers", System, false);
break;
case llvm::Triple::RTEMS:
break;
case llvm::Triple::Cygwin:
- AddPath("/usr/include/w32api", System, true, false, false);
+ AddPath("/usr/include/w32api", System, false);
break;
case llvm::Triple::MinGW32: {
// mingw-w64 crt include paths
llvm::sys::Path P(HSOpts.ResourceDir);
P.appendComponent("../../../i686-w64-mingw32/include"); // <sysroot>/i686-w64-mingw32/include
- AddPath(P.str(), System, true, false, false);
+ AddPath(P.str(), System, false);
P = llvm::sys::Path(HSOpts.ResourceDir);
P.appendComponent("../../../x86_64-w64-mingw32/include"); // <sysroot>/x86_64-w64-mingw32/include
- AddPath(P.str(), System, true, false, false);
+ AddPath(P.str(), System, false);
// mingw.org crt include paths
P = llvm::sys::Path(HSOpts.ResourceDir);
P.appendComponent("../../../include"); // <sysroot>/include
- AddPath(P.str(), System, true, false, false);
- AddPath("/mingw/include", System, true, false, false);
+ AddPath(P.str(), System, false);
+ AddPath("/mingw/include", System, false);
#if defined(_WIN32)
- AddPath("c:/mingw/include", System, true, false, false);
+ AddPath("c:/mingw/include", System, false);
#endif
}
break;
@@ -331,7 +333,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
}
if ( os != llvm::Triple::RTEMS )
- AddPath("/usr/include", System, false, false, false);
+ AddPath("/usr/include", ExternCSystem, false);
}
void InitHeaderSearch::
@@ -408,7 +410,7 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp
#endif
break;
case llvm::Triple::DragonFly:
- AddPath("/usr/include/c++/4.1", CXXSystem, true, false, false);
+ AddPath("/usr/include/c++/4.1", CXXSystem, false);
break;
case llvm::Triple::FreeBSD:
// FreeBSD 8.0
@@ -474,16 +476,15 @@ void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang,
// Get foo/lib/c++/v1
P.appendComponent("c++");
P.appendComponent("v1");
- AddPath(P.str(), CXXSystem, true, false, false, true);
+ AddUnmappedPath(P.str(), CXXSystem, false);
}
}
// On Solaris, include the support directory for things like xlocale and
// fudged system headers.
if (triple.getOS() == llvm::Triple::Solaris)
- AddPath("/usr/include/c++/v1/support/solaris", CXXSystem, true, false,
- false);
+ AddPath("/usr/include/c++/v1/support/solaris", CXXSystem, false);
- AddPath("/usr/include/c++/v1", CXXSystem, true, false, false);
+ AddPath("/usr/include/c++/v1", CXXSystem, false);
} else {
AddDefaultCPlusPlusIncludePaths(triple, HSOpts);
}
@@ -494,8 +495,8 @@ void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang,
// Add the default framework include paths on Darwin.
if (HSOpts.UseStandardSystemIncludes) {
if (triple.isOSDarwin()) {
- AddPath("/System/Library/Frameworks", System, true, false, true);
- AddPath("/Library/Frameworks", System, true, false, true);
+ AddPath("/System/Library/Frameworks", System, true);
+ AddPath("/Library/Frameworks", System, true);
}
}
}
@@ -613,7 +614,7 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) {
for (path_iterator it = IncludePath.begin(), ie = IncludePath.end();
it != ie; ++it) {
- if (it->first == System ||
+ if (it->first == System || it->first == ExternCSystem ||
(!Lang.ObjC1 && !Lang.CPlusPlus && it->first == CSystem) ||
(/*FIXME !Lang.ObjC1 && */Lang.CPlusPlus && it->first == CXXSystem) ||
(Lang.ObjC1 && !Lang.CPlusPlus && it->first == ObjCSystem) ||
@@ -669,8 +670,11 @@ void clang::ApplyHeaderSearchOptions(HeaderSearch &HS,
// Add the user defined entries.
for (unsigned i = 0, e = HSOpts.UserEntries.size(); i != e; ++i) {
const HeaderSearchOptions::Entry &E = HSOpts.UserEntries[i];
- Init.AddPath(E.Path, E.Group, !E.ImplicitExternC, E.IsUserSupplied,
- E.IsFramework, E.IgnoreSysRoot);
+ if (E.IgnoreSysRoot) {
+ Init.AddUnmappedPath(E.Path, E.Group, E.IsFramework);
+ } else {
+ Init.AddPath(E.Path, E.Group, E.IsFramework);
+ }
}
Init.AddDefaultIncludePaths(Lang, Triple, HSOpts);
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index 4bbd033..25cfac6 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -11,17 +11,17 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Basic/Version.h"
#include "clang/Frontend/Utils.h"
+#include "clang/Basic/FileManager.h"
#include "clang/Basic/MacroBuilder.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/Version.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/FrontendOptions.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/SourceManager.h"
#include "clang/Serialization/ASTReader.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/Support/FileSystem.h"
@@ -307,7 +307,7 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI,
// C++11 [cpp.predefined]p1:
// The name __cplusplus is defined to the value 201103L when compiling a
// C++ translation unit.
- if (LangOpts.CPlusPlus0x)
+ if (LangOpts.CPlusPlus11)
Builder.defineMacro("__cplusplus", "201103L");
// C++03 [cpp.predefined]p1:
// The name __cplusplus is defined to the value 199711L when compiling a
@@ -377,7 +377,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
if (!LangOpts.GNUMode)
Builder.defineMacro("__STRICT_ANSI__");
- if (LangOpts.CPlusPlus0x)
+ if (LangOpts.CPlusPlus11)
Builder.defineMacro("__GXX_EXPERIMENTAL_CXX0X__");
if (LangOpts.ObjC1) {
@@ -490,6 +490,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
DefineTypeSize("__LONG_LONG_MAX__", TargetInfo::SignedLongLong, TI, Builder);
DefineTypeSize("__WCHAR_MAX__", TI.getWCharType(), TI, Builder);
DefineTypeSize("__INTMAX_MAX__", TI.getIntMaxType(), TI, Builder);
+ DefineTypeSize("__SIZE_MAX__", TI.getSizeType(), TI, Builder);
DefineTypeSizeof("__SIZEOF_DOUBLE__", TI.getDoubleWidth(), TI, Builder);
DefineTypeSizeof("__SIZEOF_FLOAT__", TI.getFloatWidth(), TI, Builder);
@@ -507,6 +508,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
TI.getTypeWidth(TI.getWCharType()), TI, Builder);
DefineTypeSizeof("__SIZEOF_WINT_T__",
TI.getTypeWidth(TI.getWIntType()), TI, Builder);
+ if (TI.hasInt128Type())
+ DefineTypeSizeof("__SIZEOF_INT128__", 128, TI, Builder);
DefineType("__INTMAX_TYPE__", TI.getIntMaxType(), Builder);
DefineType("__UINTMAX_TYPE__", TI.getUIntMaxType(), Builder);
@@ -639,6 +642,16 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
"__attribute__((objc_ownership(none)))");
}
+ // OpenMP definition
+ if (LangOpts.OpenMP) {
+ // OpenMP 2.2:
+ // In implementations that support a preprocessor, the _OPENMP
+ // macro name is defined to have the decimal value yyyymm where
+ // yyyy and mm are the year and the month designations of the
+ // version of the OpenMP API that the implementation support.
+ Builder.defineMacro("_OPENMP", "201107");
+ }
+
// Get other target #defines.
TI.getTargetDefines(LangOpts, Builder);
}
@@ -772,15 +785,16 @@ void clang::InitializePreprocessor(Preprocessor &PP,
AddImplicitIncludeMacros(Builder, InitOpts.MacroIncludes[i],
PP.getFileManager());
+ // Process -include-pch/-include-pth directives.
+ if (!InitOpts.ImplicitPCHInclude.empty())
+ AddImplicitIncludePCH(Builder, PP, InitOpts.ImplicitPCHInclude);
+ if (!InitOpts.ImplicitPTHInclude.empty())
+ AddImplicitIncludePTH(Builder, PP, InitOpts.ImplicitPTHInclude);
+
// Process -include directives.
for (unsigned i = 0, e = InitOpts.Includes.size(); i != e; ++i) {
const std::string &Path = InitOpts.Includes[i];
- if (Path == InitOpts.ImplicitPTHInclude)
- AddImplicitIncludePTH(Builder, PP, Path);
- else if (Path == InitOpts.ImplicitPCHInclude)
- AddImplicitIncludePCH(Builder, PP, Path);
- else
- AddImplicitInclude(Builder, Path, PP.getFileManager());
+ AddImplicitInclude(Builder, Path, PP.getFileManager());
}
// Exit the command line and go back to <built-in> (2 is LC_LEAVE).
diff --git a/lib/Frontend/LayoutOverrideSource.cpp b/lib/Frontend/LayoutOverrideSource.cpp
index e023250..924a640 100644
--- a/lib/Frontend/LayoutOverrideSource.cpp
+++ b/lib/Frontend/LayoutOverrideSource.cpp
@@ -8,8 +8,8 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/LayoutOverrideSource.h"
#include "clang/AST/Decl.h"
+#include "clang/Basic/CharInfo.h"
#include "llvm/Support/raw_ostream.h"
-#include <cctype>
#include <fstream>
#include <string>
@@ -17,16 +17,17 @@ using namespace clang;
/// \brief Parse a simple identifier.
static std::string parseName(StringRef S) {
- unsigned Offset = 0;
- while (Offset < S.size() &&
- (isalpha(S[Offset]) || S[Offset] == '_' ||
- (Offset > 0 && isdigit(S[Offset]))))
+ if (S.empty() || !isIdentifierHead(S[0]))
+ return "";
+
+ unsigned Offset = 1;
+ while (Offset < S.size() && isIdentifierBody(S[Offset]))
++Offset;
return S.substr(0, Offset).str();
}
-LayoutOverrideSource::LayoutOverrideSource(llvm::StringRef Filename) {
+LayoutOverrideSource::LayoutOverrideSource(StringRef Filename) {
std::ifstream Input(Filename.str().c_str());
if (!Input.is_open())
return;
@@ -128,10 +129,10 @@ LayoutOverrideSource::LayoutOverrideSource(llvm::StringRef Filename) {
continue;
LineStr = LineStr.substr(Pos + strlen("FieldOffsets: ["));
- while (!LineStr.empty() && isdigit(LineStr[0])) {
+ while (!LineStr.empty() && isDigit(LineStr[0])) {
// Parse this offset.
unsigned Idx = 1;
- while (Idx < LineStr.size() && isdigit(LineStr[Idx]))
+ while (Idx < LineStr.size() && isDigit(LineStr[Idx]))
++Idx;
unsigned long long Offset = 0;
@@ -141,7 +142,7 @@ LayoutOverrideSource::LayoutOverrideSource(llvm::StringRef Filename) {
// Skip over this offset, the following comma, and any spaces.
LineStr = LineStr.substr(Idx + 1);
- while (!LineStr.empty() && isspace(LineStr[0]))
+ while (!LineStr.empty() && isWhitespace(LineStr[0]))
LineStr = LineStr.substr(1);
}
}
@@ -188,7 +189,7 @@ LayoutOverrideSource::layoutRecordType(const RecordDecl *Record,
}
void LayoutOverrideSource::dump() {
- llvm::raw_ostream &OS = llvm::errs();
+ raw_ostream &OS = llvm::errs();
for (llvm::StringMap<Layout>::iterator L = Layouts.begin(),
LEnd = Layouts.end();
L != LEnd; ++L) {
diff --git a/lib/Frontend/LogDiagnosticPrinter.cpp b/lib/Frontend/LogDiagnosticPrinter.cpp
index 3a04f18..0a22481 100644
--- a/lib/Frontend/LogDiagnosticPrinter.cpp
+++ b/lib/Frontend/LogDiagnosticPrinter.cpp
@@ -12,8 +12,8 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
LogDiagnosticPrinter::LogDiagnosticPrinter(raw_ostream &os,
diff --git a/lib/Frontend/MultiplexConsumer.cpp b/lib/Frontend/MultiplexConsumer.cpp
index 992eeb0..ba83580 100644
--- a/lib/Frontend/MultiplexConsumer.cpp
+++ b/lib/Frontend/MultiplexConsumer.cpp
@@ -14,7 +14,6 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/MultiplexConsumer.h"
-
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/DeclGroup.h"
#include "clang/Serialization/ASTDeserializationListener.h"
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
index 30707dc..f70bd7c 100644
--- a/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/Utils.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/PreprocessorOutputOptions.h"
@@ -21,12 +22,11 @@
#include "clang/Lex/Pragma.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/TokenConcatenation.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
-#include <cctype>
+#include "llvm/Support/raw_ostream.h"
#include <cstdio>
using namespace clang;
@@ -95,6 +95,7 @@ private:
bool DisableLineMarkers;
bool DumpDefines;
bool UseLineDirective;
+ bool IsFirstFileEntered;
public:
PrintPPOutputPPCallbacks(Preprocessor &pp, raw_ostream &os,
bool lineMarkers, bool defines)
@@ -107,6 +108,7 @@ public:
EmittedDirectiveOnThisLine = false;
FileType = SrcMgr::C_User;
Initialized = false;
+ IsFirstFileEntered = false;
// If we're in microsoft mode, use normal #line instead of line markers.
UseLineDirective = PP.getLangOpts().MicrosoftExt;
@@ -137,11 +139,15 @@ public:
diag::Mapping Map, StringRef Str);
bool HandleFirstTokOnLine(Token &Tok);
+
+ /// Move to the line of the provided source location. This will
+ /// return true if the output stream required adjustment or if
+ /// the requested location is on the first line.
bool MoveToLine(SourceLocation Loc) {
PresumedLoc PLoc = SM.getPresumedLoc(Loc);
if (PLoc.isInvalid())
return false;
- return MoveToLine(PLoc.getLine());
+ return MoveToLine(PLoc.getLine()) || (PLoc.getLine() == 1);
}
bool MoveToLine(unsigned LineNo);
@@ -154,10 +160,10 @@ public:
void HandleNewlinesInToken(const char *TokStr, unsigned Len);
/// MacroDefined - This hook is called whenever a macro definition is seen.
- void MacroDefined(const Token &MacroNameTok, const MacroInfo *MI);
+ void MacroDefined(const Token &MacroNameTok, const MacroDirective *MD);
/// MacroUndefined - This hook is called whenever a macro #undef is seen.
- void MacroUndefined(const Token &MacroNameTok, const MacroInfo *MI);
+ void MacroUndefined(const Token &MacroNameTok, const MacroDirective *MD);
};
} // end anonymous namespace
@@ -266,13 +272,25 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc,
Lexer::Stringify(CurFilename);
FileType = NewFileType;
- if (DisableLineMarkers) return;
+ if (DisableLineMarkers) {
+ startNewLineIfNeeded(/*ShouldUpdateCurrentLine=*/false);
+ return;
+ }
if (!Initialized) {
WriteLineInfo(CurLine);
Initialized = true;
}
+ // Do not emit an enter marker for the main file (which we expect is the first
+ // entered file). This matches gcc, and improves compatibility with some tools
+ // which track the # line markers as a way to determine when the preprocessed
+ // output is in the context of the main file.
+ if (Reason == PPCallbacks::EnterFile && !IsFirstFileEntered) {
+ IsFirstFileEntered = true;
+ return;
+ }
+
switch (Reason) {
case PPCallbacks::EnterFile:
WriteLineInfo(CurLine, " 1", 2);
@@ -299,7 +317,8 @@ void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, const std::string &S) {
/// MacroDefined - This hook is called whenever a macro definition is seen.
void PrintPPOutputPPCallbacks::MacroDefined(const Token &MacroNameTok,
- const MacroInfo *MI) {
+ const MacroDirective *MD) {
+ const MacroInfo *MI = MD->getMacroInfo();
// Only print out macro definitions in -dD mode.
if (!DumpDefines ||
// Ignore __FILE__ etc.
@@ -311,7 +330,7 @@ void PrintPPOutputPPCallbacks::MacroDefined(const Token &MacroNameTok,
}
void PrintPPOutputPPCallbacks::MacroUndefined(const Token &MacroNameTok,
- const MacroInfo *MI) {
+ const MacroDirective *MD) {
// Only print out macro definitions in -dD mode.
if (!DumpDefines) return;
@@ -332,7 +351,7 @@ void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc,
for (unsigned i = 0, e = Str.size(); i != e; ++i) {
unsigned char Char = Str[i];
- if (isprint(Char) && Char != '\\' && Char != '"')
+ if (isPrintable(Char) && Char != '\\' && Char != '"')
OS << (char)Char;
else // Output anything hard as an octal escape.
OS << '\\'
@@ -357,7 +376,7 @@ void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc,
for (unsigned i = 0, e = Str.size(); i != e; ++i) {
unsigned char Char = Str[i];
- if (isprint(Char) && Char != '\\' && Char != '"')
+ if (isPrintable(Char) && Char != '\\' && Char != '"')
OS << (char)Char;
else // Output anything hard as an octal escape.
OS << '\\'
@@ -496,6 +515,9 @@ struct UnknownPragmaHandler : public PragmaHandler {
static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
PrintPPOutputPPCallbacks *Callbacks,
raw_ostream &OS) {
+ bool DropComments = PP.getLangOpts().TraditionalCPP &&
+ !PP.getCommentRetentionState();
+
char Buffer[256];
Token PrevPrevTok, PrevTok;
PrevPrevTok.startToken();
@@ -518,7 +540,13 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
OS << ' ';
}
- if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
+ if (DropComments && Tok.is(tok::comment)) {
+ // Skip comments. Normally the preprocessor does not generate
+ // tok::comment nodes at all when not keeping comments, but under
+ // -traditional-cpp the lexer keeps /all/ whitespace, including comments.
+ SourceLocation StartLoc = Tok.getLocation();
+ Callbacks->MoveToLine(StartLoc.getLocWithOffset(Tok.getLength()));
+ } else if (IdentifierInfo *II = Tok.getIdentifierInfo()) {
OS << II->getName();
} else if (Tok.isLiteral() && !Tok.needsCleaning() &&
Tok.getLiteralData()) {
@@ -530,7 +558,7 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
// Tokens that can contain embedded newlines need to adjust our current
// line number.
- if (Tok.getKind() == tok::comment)
+ if (Tok.getKind() == tok::comment || Tok.getKind() == tok::unknown)
Callbacks->HandleNewlinesInToken(TokPtr, Len);
} else {
std::string S = PP.getSpelling(Tok);
@@ -538,7 +566,7 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
// Tokens that can contain embedded newlines need to adjust our current
// line number.
- if (Tok.getKind() == tok::comment)
+ if (Tok.getKind() == tok::comment || Tok.getKind() == tok::unknown)
Callbacks->HandleNewlinesInToken(&S[0], S.size());
}
Callbacks->setEmittedTokensOnThisLine();
@@ -551,7 +579,7 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
}
}
-typedef std::pair<IdentifierInfo*, MacroInfo*> id_macro_pair;
+typedef std::pair<const IdentifierInfo *, MacroInfo *> id_macro_pair;
static int MacroIDCompare(const void* a, const void* b) {
const id_macro_pair *LHS = static_cast<const id_macro_pair*>(a);
const id_macro_pair *RHS = static_cast<const id_macro_pair*>(b);
@@ -574,7 +602,7 @@ static void DoPrintMacros(Preprocessor &PP, raw_ostream *OS) {
for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end();
I != E; ++I) {
if (I->first->hasMacroDefinition())
- MacrosByID.push_back(id_macro_pair(I->first, I->second));
+ MacrosByID.push_back(id_macro_pair(I->first, I->second->getMacroInfo()));
}
llvm::array_pod_sort(MacrosByID.begin(), MacrosByID.end(), MacroIDCompare);
diff --git a/lib/Frontend/SerializedDiagnosticPrinter.cpp b/lib/Frontend/SerializedDiagnosticPrinter.cpp
index 5f8fc1e..4bb662b 100644
--- a/lib/Frontend/SerializedDiagnosticPrinter.cpp
+++ b/lib/Frontend/SerializedDiagnosticPrinter.cpp
@@ -7,19 +7,19 @@
//
//===----------------------------------------------------------------------===//
-#include <vector>
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/DenseSet.h"
+#include "clang/Frontend/SerializedDiagnosticPrinter.h"
+#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
-#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
-#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Version.h"
-#include "clang/Lex/Lexer.h"
-#include "clang/Frontend/SerializedDiagnosticPrinter.h"
#include "clang/Frontend/DiagnosticRenderer.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/raw_ostream.h"
+#include <vector>
using namespace clang;
using namespace clang::serialized_diags;
@@ -44,8 +44,8 @@ public:
}
};
-typedef llvm::SmallVector<uint64_t, 64> RecordData;
-typedef llvm::SmallVectorImpl<uint64_t> RecordDataImpl;
+typedef SmallVector<uint64_t, 64> RecordData;
+typedef SmallVectorImpl<uint64_t> RecordDataImpl;
class SDiagsWriter;
@@ -89,10 +89,16 @@ protected:
class SDiagsWriter : public DiagnosticConsumer {
friend class SDiagsRenderer;
-public:
- explicit SDiagsWriter(llvm::raw_ostream *os, DiagnosticOptions *diags)
- : LangOpts(0), DiagOpts(diags), Stream(Buffer), OS(os),
- EmittedAnyDiagBlocks(false) {
+
+ struct SharedState;
+
+ explicit SDiagsWriter(IntrusiveRefCntPtr<SharedState> State)
+ : LangOpts(0), OriginalInstance(false), State(State) { }
+
+public:
+ SDiagsWriter(raw_ostream *os, DiagnosticOptions *diags)
+ : LangOpts(0), OriginalInstance(true), State(new SharedState(os, diags))
+ {
EmitPreamble();
}
@@ -109,8 +115,7 @@ public:
virtual void finish();
DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
- // It makes no sense to clone this.
- return 0;
+ return new SDiagsWriter(State);
}
private:
@@ -175,50 +180,67 @@ private:
/// \brief The version of the diagnostics file.
enum { Version = 1 };
+ /// \brief Language options, which can differ from one clone of this client
+ /// to another.
const LangOptions *LangOpts;
- llvm::IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
-
- /// \brief The byte buffer for the serialized content.
- SmallString<1024> Buffer;
- /// \brief The BitStreamWriter for the serialized diagnostics.
- llvm::BitstreamWriter Stream;
+ /// \brief Whether this is the original instance (rather than one of its
+ /// clones), responsible for writing the file at the end.
+ bool OriginalInstance;
- /// \brief The name of the diagnostics file.
- OwningPtr<llvm::raw_ostream> OS;
-
- /// \brief The set of constructed record abbreviations.
- AbbreviationMap Abbrevs;
+ /// \brief State that is shared among the various clones of this diagnostic
+ /// consumer.
+ struct SharedState : RefCountedBase<SharedState> {
+ SharedState(raw_ostream *os, DiagnosticOptions *diags)
+ : DiagOpts(diags), Stream(Buffer), OS(os), EmittedAnyDiagBlocks(false) { }
- /// \brief A utility buffer for constructing record content.
- RecordData Record;
+ /// \brief Diagnostic options.
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
- /// \brief A text buffer for rendering diagnostic text.
- SmallString<256> diagBuf;
-
- /// \brief The collection of diagnostic categories used.
- llvm::DenseSet<unsigned> Categories;
-
- /// \brief The collection of files used.
- llvm::DenseMap<const char *, unsigned> Files;
+ /// \brief The byte buffer for the serialized content.
+ SmallString<1024> Buffer;
+
+ /// \brief The BitStreamWriter for the serialized diagnostics.
+ llvm::BitstreamWriter Stream;
+
+ /// \brief The name of the diagnostics file.
+ OwningPtr<raw_ostream> OS;
+
+ /// \brief The set of constructed record abbreviations.
+ AbbreviationMap Abbrevs;
+
+ /// \brief A utility buffer for constructing record content.
+ RecordData Record;
+
+ /// \brief A text buffer for rendering diagnostic text.
+ SmallString<256> diagBuf;
+
+ /// \brief The collection of diagnostic categories used.
+ llvm::DenseSet<unsigned> Categories;
+
+ /// \brief The collection of files used.
+ llvm::DenseMap<const char *, unsigned> Files;
+
+ typedef llvm::DenseMap<const void *, std::pair<unsigned, StringRef> >
+ DiagFlagsTy;
- typedef llvm::DenseMap<const void *, std::pair<unsigned, llvm::StringRef> >
- DiagFlagsTy;
+ /// \brief Map for uniquing strings.
+ DiagFlagsTy DiagFlags;
- /// \brief Map for uniquing strings.
- DiagFlagsTy DiagFlags;
+ /// \brief Whether we have already started emission of any DIAG blocks. Once
+ /// this becomes \c true, we never close a DIAG block until we know that we're
+ /// starting another one or we're done.
+ bool EmittedAnyDiagBlocks;
+ };
- /// \brief Whether we have already started emission of any DIAG blocks. Once
- /// this becomes \c true, we never close a DIAG block until we know that we're
- /// starting another one or we're done.
- bool EmittedAnyDiagBlocks;
+ /// \brief State shared among the various clones of this diagnostic consumer.
+ IntrusiveRefCntPtr<SharedState> State;
};
} // end anonymous namespace
namespace clang {
namespace serialized_diags {
-DiagnosticConsumer *create(llvm::raw_ostream *OS,
- DiagnosticOptions *diags) {
+DiagnosticConsumer *create(raw_ostream *OS, DiagnosticOptions *diags) {
return new SDiagsWriter(OS, diags);
}
} // end namespace serialized_diags
@@ -297,12 +319,12 @@ unsigned SDiagsWriter::getEmitFile(const char *FileName){
if (!FileName)
return 0;
- unsigned &entry = Files[FileName];
+ unsigned &entry = State->Files[FileName];
if (entry)
return entry;
// Lazily generate the record for the file.
- entry = Files.size();
+ entry = State->Files.size();
RecordData Record;
Record.push_back(RECORD_FILENAME);
Record.push_back(entry);
@@ -310,26 +332,28 @@ unsigned SDiagsWriter::getEmitFile(const char *FileName){
Record.push_back(0); // For legacy.
StringRef Name(FileName);
Record.push_back(Name.size());
- Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FILENAME), Record, Name);
+ State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_FILENAME), Record,
+ Name);
return entry;
}
void SDiagsWriter::EmitCharSourceRange(CharSourceRange R,
const SourceManager &SM) {
- Record.clear();
- Record.push_back(RECORD_SOURCE_RANGE);
- AddCharSourceRangeToRecord(R, Record, SM);
- Stream.EmitRecordWithAbbrev(Abbrevs.get(RECORD_SOURCE_RANGE), Record);
+ State->Record.clear();
+ State->Record.push_back(RECORD_SOURCE_RANGE);
+ AddCharSourceRangeToRecord(R, State->Record, SM);
+ State->Stream.EmitRecordWithAbbrev(State->Abbrevs.get(RECORD_SOURCE_RANGE),
+ State->Record);
}
/// \brief Emits the preamble of the diagnostics file.
void SDiagsWriter::EmitPreamble() {
// Emit the file header.
- Stream.Emit((unsigned)'D', 8);
- Stream.Emit((unsigned)'I', 8);
- Stream.Emit((unsigned)'A', 8);
- Stream.Emit((unsigned)'G', 8);
+ State->Stream.Emit((unsigned)'D', 8);
+ State->Stream.Emit((unsigned)'I', 8);
+ State->Stream.Emit((unsigned)'A', 8);
+ State->Stream.Emit((unsigned)'G', 8);
EmitBlockInfoBlock();
EmitMetaBlock();
@@ -349,9 +373,12 @@ static void AddRangeLocationAbbrev(llvm::BitCodeAbbrev *Abbrev) {
}
void SDiagsWriter::EmitBlockInfoBlock() {
- Stream.EnterBlockInfoBlock(3);
+ State->Stream.EnterBlockInfoBlock(3);
using namespace llvm;
+ llvm::BitstreamWriter &Stream = State->Stream;
+ RecordData &Record = State->Record;
+ AbbreviationMap &Abbrevs = State->Abbrevs;
// ==---------------------------------------------------------------------==//
// The subsequent records and Abbrevs are for the "Meta" block.
@@ -435,6 +462,10 @@ void SDiagsWriter::EmitBlockInfoBlock() {
}
void SDiagsWriter::EmitMetaBlock() {
+ llvm::BitstreamWriter &Stream = State->Stream;
+ RecordData &Record = State->Record;
+ AbbreviationMap &Abbrevs = State->Abbrevs;
+
Stream.EnterSubblock(BLOCK_META, 3);
Record.clear();
Record.push_back(RECORD_VERSION);
@@ -444,10 +475,10 @@ void SDiagsWriter::EmitMetaBlock() {
}
unsigned SDiagsWriter::getEmitCategory(unsigned int category) {
- if (Categories.count(category))
+ if (State->Categories.count(category))
return category;
- Categories.insert(category);
+ State->Categories.insert(category);
// We use a local version of 'Record' so that we can be generating
// another record when we lazily generate one for the category entry.
@@ -456,7 +487,8 @@ unsigned SDiagsWriter::getEmitCategory(unsigned int category) {
Record.push_back(category);
StringRef catName = DiagnosticIDs::getCategoryNameFromID(category);
Record.push_back(catName.size());
- Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_CATEGORY), Record, catName);
+ State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_CATEGORY), Record,
+ catName);
return category;
}
@@ -473,9 +505,9 @@ unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
// Here we assume that FlagName points to static data whose pointer
// value is fixed. This allows us to unique by diagnostic groups.
const void *data = FlagName.data();
- std::pair<unsigned, StringRef> &entry = DiagFlags[data];
+ std::pair<unsigned, StringRef> &entry = State->DiagFlags[data];
if (entry.first == 0) {
- entry.first = DiagFlags.size();
+ entry.first = State->DiagFlags.size();
entry.second = FlagName;
// Lazily emit the string in a separate record.
@@ -483,8 +515,8 @@ unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel,
Record.push_back(RECORD_DIAG_FLAG);
Record.push_back(entry.first);
Record.push_back(FlagName.size());
- Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG_FLAG),
- Record, FlagName);
+ State->Stream.EmitRecordWithBlob(State->Abbrevs.get(RECORD_DIAG_FLAG),
+ Record, FlagName);
}
return entry.first;
@@ -496,31 +528,41 @@ void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
// for beginDiagnostic, in case associated notes are emitted before we get
// there.
if (DiagLevel != DiagnosticsEngine::Note) {
- if (EmittedAnyDiagBlocks)
+ if (State->EmittedAnyDiagBlocks)
ExitDiagBlock();
EnterDiagBlock();
- EmittedAnyDiagBlocks = true;
+ State->EmittedAnyDiagBlocks = true;
}
// Compute the diagnostic text.
- diagBuf.clear();
- Info.FormatDiagnostic(diagBuf);
+ State->diagBuf.clear();
+ Info.FormatDiagnostic(State->diagBuf);
if (Info.getLocation().isInvalid()) {
// Special-case diagnostics with no location. We may not have entered a
// source file in this case, so we can't use the normal DiagnosticsRenderer
// machinery.
+
+ // Make sure we bracket all notes as "sub-diagnostics". This matches
+ // the behavior in SDiagsRenderer::emitDiagnostic().
+ if (DiagLevel == DiagnosticsEngine::Note)
+ EnterDiagBlock();
+
EmitDiagnosticMessage(SourceLocation(), PresumedLoc(), DiagLevel,
- diagBuf, 0, &Info);
+ State->diagBuf, 0, &Info);
+
+ if (DiagLevel == DiagnosticsEngine::Note)
+ ExitDiagBlock();
+
return;
}
assert(Info.hasSourceManager() && LangOpts &&
"Unexpected diagnostic with valid location outside of a source file");
- SDiagsRenderer Renderer(*this, *LangOpts, &*DiagOpts);
+ SDiagsRenderer Renderer(*this, *LangOpts, &*State->DiagOpts);
Renderer.emitDiagnostic(Info.getLocation(), DiagLevel,
- diagBuf.str(),
+ State->diagBuf.str(),
Info.getRanges(),
llvm::makeArrayRef(Info.getFixItHints(),
Info.getNumFixItHints()),
@@ -534,6 +576,10 @@ void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc,
StringRef Message,
const SourceManager *SM,
DiagOrStoredDiag D) {
+ llvm::BitstreamWriter &Stream = State->Stream;
+ RecordData &Record = State->Record;
+ AbbreviationMap &Abbrevs = State->Abbrevs;
+
// Emit the RECORD_DIAG record.
Record.clear();
Record.push_back(RECORD_DIAG);
@@ -567,11 +613,11 @@ SDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc,
}
void SDiagsWriter::EnterDiagBlock() {
- Stream.EnterSubblock(BLOCK_DIAG, 4);
+ State->Stream.EnterSubblock(BLOCK_DIAG, 4);
}
void SDiagsWriter::ExitDiagBlock() {
- Stream.ExitBlock();
+ State->Stream.ExitBlock();
}
void SDiagsRenderer::beginDiagnostic(DiagOrStoredDiag D,
@@ -591,6 +637,10 @@ void SDiagsRenderer::endDiagnostic(DiagOrStoredDiag D,
void SDiagsWriter::EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges,
ArrayRef<FixItHint> Hints,
const SourceManager &SM) {
+ llvm::BitstreamWriter &Stream = State->Stream;
+ RecordData &Record = State->Record;
+ AbbreviationMap &Abbrevs = State->Abbrevs;
+
// Emit Source Ranges.
for (ArrayRef<CharSourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
I != E; ++I)
@@ -630,13 +680,17 @@ void SDiagsRenderer::emitNote(SourceLocation Loc, StringRef Message,
}
void SDiagsWriter::finish() {
+ // The original instance is responsible for writing the file.
+ if (!OriginalInstance)
+ return;
+
// Finish off any diagnostic we were in the process of emitting.
- if (EmittedAnyDiagBlocks)
+ if (State->EmittedAnyDiagBlocks)
ExitDiagBlock();
// Write the generated bitstream to "Out".
- OS->write((char *)&Buffer.front(), Buffer.size());
- OS->flush();
+ State->OS->write((char *)&State->Buffer.front(), State->Buffer.size());
+ State->OS->flush();
- OS.reset(0);
+ State->OS.reset(0);
}
diff --git a/lib/Frontend/TextDiagnostic.cpp b/lib/Frontend/TextDiagnostic.cpp
index 35dabad..ca4ad60 100644
--- a/lib/Frontend/TextDiagnostic.cpp
+++ b/lib/Frontend/TextDiagnostic.cpp
@@ -8,19 +8,19 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/TextDiagnostic.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/ConvertUTF.h"
-#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Lex/Lexer.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/Locale.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Locale.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
#include <algorithm>
-#include <cctype>
using namespace clang;
@@ -248,6 +248,7 @@ static void columnToByte(StringRef SourceLine, unsigned TabStop,
out.back() = i;
}
+namespace {
struct SourceColumnMap {
SourceColumnMap(StringRef SourceLine, unsigned TabStop)
: m_SourceLine(SourceLine) {
@@ -313,14 +314,13 @@ private:
};
// used in assert in selectInterestingSourceRegion()
-namespace {
struct char_out_of_range {
const char lower,upper;
char_out_of_range(char lower, char upper) :
lower(lower), upper(upper) {}
bool operator()(char c) { return c < lower || upper < c; }
};
-}
+} // end anonymous namespace
/// \brief When the source code line we want to print is too long for
/// the terminal, select the "interesting" region.
@@ -348,11 +348,11 @@ static void selectInterestingSourceRegion(std::string &SourceLine,
// correctly.
unsigned CaretStart = 0, CaretEnd = CaretLine.size();
for (; CaretStart != CaretEnd; ++CaretStart)
- if (!isspace(static_cast<unsigned char>(CaretLine[CaretStart])))
+ if (!isWhitespace(CaretLine[CaretStart]))
break;
for (; CaretEnd != CaretStart; --CaretEnd)
- if (!isspace(static_cast<unsigned char>(CaretLine[CaretEnd - 1])))
+ if (!isWhitespace(CaretLine[CaretEnd - 1]))
break;
// caret has already been inserted into CaretLine so the above whitespace
@@ -363,11 +363,11 @@ static void selectInterestingSourceRegion(std::string &SourceLine,
if (!FixItInsertionLine.empty()) {
unsigned FixItStart = 0, FixItEnd = FixItInsertionLine.size();
for (; FixItStart != FixItEnd; ++FixItStart)
- if (!isspace(static_cast<unsigned char>(FixItInsertionLine[FixItStart])))
+ if (!isWhitespace(FixItInsertionLine[FixItStart]))
break;
for (; FixItEnd != FixItStart; --FixItEnd)
- if (!isspace(static_cast<unsigned char>(FixItInsertionLine[FixItEnd - 1])))
+ if (!isWhitespace(FixItInsertionLine[FixItEnd - 1]))
break;
CaretStart = std::min(FixItStart, CaretStart);
@@ -423,14 +423,13 @@ static void selectInterestingSourceRegion(std::string &SourceLine,
// Skip over any whitespace we see here; we're looking for
// another bit of interesting text.
// FIXME: Detect non-ASCII whitespace characters too.
- while (NewStart &&
- isspace(static_cast<unsigned char>(SourceLine[NewStart])))
+ while (NewStart && isWhitespace(SourceLine[NewStart]))
NewStart = map.startOfPreviousColumn(NewStart);
// Skip over this bit of "interesting" text.
while (NewStart) {
unsigned Prev = map.startOfPreviousColumn(NewStart);
- if (isspace(static_cast<unsigned char>(SourceLine[Prev])))
+ if (isWhitespace(SourceLine[Prev]))
break;
NewStart = Prev;
}
@@ -450,13 +449,11 @@ static void selectInterestingSourceRegion(std::string &SourceLine,
// Skip over any whitespace we see here; we're looking for
// another bit of interesting text.
// FIXME: Detect non-ASCII whitespace characters too.
- while (NewEnd < SourceLine.size() &&
- isspace(static_cast<unsigned char>(SourceLine[NewEnd])))
+ while (NewEnd < SourceLine.size() && isWhitespace(SourceLine[NewEnd]))
NewEnd = map.startOfNextColumn(NewEnd);
// Skip over this bit of "interesting" text.
- while (NewEnd < SourceLine.size() &&
- !isspace(static_cast<unsigned char>(SourceLine[NewEnd])))
+ while (NewEnd < SourceLine.size() && isWhitespace(SourceLine[NewEnd]))
NewEnd = map.startOfNextColumn(NewEnd);
assert(map.byteToColumn(NewEnd) != -1);
@@ -517,7 +514,7 @@ static void selectInterestingSourceRegion(std::string &SourceLine,
/// greater than or equal to Idx or, if no such character exists,
/// returns the end of the string.
static unsigned skipWhitespace(unsigned Idx, StringRef Str, unsigned Length) {
- while (Idx < Length && isspace(Str[Idx]))
+ while (Idx < Length && isWhitespace(Str[Idx]))
++Idx;
return Idx;
}
@@ -562,7 +559,7 @@ static unsigned findEndOfWord(unsigned Start, StringRef Str,
char EndPunct = findMatchingPunctuation(Str[Start]);
if (!EndPunct) {
// This is a normal word. Just find the first space character.
- while (End < Length && !isspace(Str[End]))
+ while (End < Length && !isWhitespace(Str[End]))
++End;
return End;
}
@@ -581,7 +578,7 @@ static unsigned findEndOfWord(unsigned Start, StringRef Str,
}
// Find the first space character after the punctuation ended.
- while (End < Length && !isspace(Str[End]))
+ while (End < Length && !isWhitespace(Str[End]))
++End;
unsigned PunctWordLength = End - Start;
@@ -884,6 +881,178 @@ void TextDiagnostic::emitIncludeLocation(SourceLocation Loc,
OS << "In included file:\n";
}
+void TextDiagnostic::emitImportLocation(SourceLocation Loc, PresumedLoc PLoc,
+ StringRef ModuleName,
+ const SourceManager &SM) {
+ if (DiagOpts->ShowLocation)
+ OS << "In module '" << ModuleName << "' imported from "
+ << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
+ else
+ OS << "In module " << ModuleName << "':\n";
+}
+
+void TextDiagnostic::emitBuildingModuleLocation(SourceLocation Loc,
+ PresumedLoc PLoc,
+ StringRef ModuleName,
+ const SourceManager &SM) {
+ if (DiagOpts->ShowLocation && PLoc.getFilename())
+ OS << "While building module '" << ModuleName << "' imported from "
+ << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n";
+ else
+ OS << "While building module '" << ModuleName << "':\n";
+}
+
+/// \brief Highlight a SourceRange (with ~'s) for any characters on LineNo.
+static void highlightRange(const CharSourceRange &R,
+ unsigned LineNo, FileID FID,
+ const SourceColumnMap &map,
+ std::string &CaretLine,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ if (!R.isValid()) return;
+
+ SourceLocation Begin = R.getBegin();
+ SourceLocation End = R.getEnd();
+
+ unsigned StartLineNo = SM.getExpansionLineNumber(Begin);
+ if (StartLineNo > LineNo || SM.getFileID(Begin) != FID)
+ return; // No intersection.
+
+ unsigned EndLineNo = SM.getExpansionLineNumber(End);
+ if (EndLineNo < LineNo || SM.getFileID(End) != FID)
+ return; // No intersection.
+
+ // Compute the column number of the start.
+ unsigned StartColNo = 0;
+ if (StartLineNo == LineNo) {
+ StartColNo = SM.getExpansionColumnNumber(Begin);
+ if (StartColNo) --StartColNo; // Zero base the col #.
+ }
+
+ // Compute the column number of the end.
+ unsigned EndColNo = map.getSourceLine().size();
+ if (EndLineNo == LineNo) {
+ EndColNo = SM.getExpansionColumnNumber(End);
+ if (EndColNo) {
+ --EndColNo; // Zero base the col #.
+
+ // Add in the length of the token, so that we cover multi-char tokens if
+ // this is a token range.
+ if (R.isTokenRange())
+ EndColNo += Lexer::MeasureTokenLength(End, SM, LangOpts);
+ } else {
+ EndColNo = CaretLine.size();
+ }
+ }
+
+ assert(StartColNo <= EndColNo && "Invalid range!");
+
+ // Check that a token range does not highlight only whitespace.
+ if (R.isTokenRange()) {
+ // Pick the first non-whitespace column.
+ while (StartColNo < map.getSourceLine().size() &&
+ (map.getSourceLine()[StartColNo] == ' ' ||
+ map.getSourceLine()[StartColNo] == '\t'))
+ StartColNo = map.startOfNextColumn(StartColNo);
+
+ // Pick the last non-whitespace column.
+ if (EndColNo > map.getSourceLine().size())
+ EndColNo = map.getSourceLine().size();
+ while (EndColNo &&
+ (map.getSourceLine()[EndColNo-1] == ' ' ||
+ map.getSourceLine()[EndColNo-1] == '\t'))
+ EndColNo = map.startOfPreviousColumn(EndColNo);
+
+ // If the start/end passed each other, then we are trying to highlight a
+ // range that just exists in whitespace, which must be some sort of other
+ // bug.
+ assert(StartColNo <= EndColNo && "Trying to highlight whitespace??");
+ }
+
+ assert(StartColNo <= map.getSourceLine().size() && "Invalid range!");
+ assert(EndColNo <= map.getSourceLine().size() && "Invalid range!");
+
+ // Fill the range with ~'s.
+ StartColNo = map.byteToContainingColumn(StartColNo);
+ EndColNo = map.byteToContainingColumn(EndColNo);
+
+ assert(StartColNo <= EndColNo && "Invalid range!");
+ if (CaretLine.size() < EndColNo)
+ CaretLine.resize(EndColNo,' ');
+ std::fill(CaretLine.begin()+StartColNo,CaretLine.begin()+EndColNo,'~');
+}
+
+static std::string buildFixItInsertionLine(unsigned LineNo,
+ const SourceColumnMap &map,
+ ArrayRef<FixItHint> Hints,
+ const SourceManager &SM,
+ const DiagnosticOptions *DiagOpts) {
+ std::string FixItInsertionLine;
+ if (Hints.empty() || !DiagOpts->ShowFixits)
+ return FixItInsertionLine;
+ unsigned PrevHintEndCol = 0;
+
+ for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
+ I != E; ++I) {
+ if (!I->CodeToInsert.empty()) {
+ // We have an insertion hint. Determine whether the inserted
+ // code contains no newlines and is on the same line as the caret.
+ std::pair<FileID, unsigned> HintLocInfo
+ = SM.getDecomposedExpansionLoc(I->RemoveRange.getBegin());
+ if (LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) &&
+ StringRef(I->CodeToInsert).find_first_of("\n\r") == StringRef::npos) {
+ // Insert the new code into the line just below the code
+ // that the user wrote.
+ // Note: When modifying this function, be very careful about what is a
+ // "column" (printed width, platform-dependent) and what is a
+ // "byte offset" (SourceManager "column").
+ unsigned HintByteOffset
+ = SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second) - 1;
+
+ // The hint must start inside the source or right at the end
+ assert(HintByteOffset < static_cast<unsigned>(map.bytes())+1);
+ unsigned HintCol = map.byteToContainingColumn(HintByteOffset);
+
+ // If we inserted a long previous hint, push this one forwards, and add
+ // an extra space to show that this is not part of the previous
+ // completion. This is sort of the best we can do when two hints appear
+ // to overlap.
+ //
+ // Note that if this hint is located immediately after the previous
+ // hint, no space will be added, since the location is more important.
+ if (HintCol < PrevHintEndCol)
+ HintCol = PrevHintEndCol + 1;
+
+ // FIXME: This function handles multibyte characters in the source, but
+ // not in the fixits. This assertion is intended to catch unintended
+ // use of multibyte characters in fixits. If we decide to do this, we'll
+ // have to track separate byte widths for the source and fixit lines.
+ assert((size_t)llvm::sys::locale::columnWidth(I->CodeToInsert) ==
+ I->CodeToInsert.size());
+
+ // This relies on one byte per column in our fixit hints.
+ // This should NOT use HintByteOffset, because the source might have
+ // Unicode characters in earlier columns.
+ unsigned LastColumnModified = HintCol + I->CodeToInsert.size();
+ if (LastColumnModified > FixItInsertionLine.size())
+ FixItInsertionLine.resize(LastColumnModified, ' ');
+
+ std::copy(I->CodeToInsert.begin(), I->CodeToInsert.end(),
+ FixItInsertionLine.begin() + HintCol);
+
+ PrevHintEndCol = LastColumnModified;
+ } else {
+ FixItInsertionLine.clear();
+ break;
+ }
+ }
+ }
+
+ expandTabs(FixItInsertionLine, DiagOpts->TabStop);
+
+ return FixItInsertionLine;
+}
+
/// \brief Emit a code snippet and caret line.
///
/// This routine emits a single line's code snippet and caret line..
@@ -924,18 +1093,26 @@ void TextDiagnostic::emitSnippetAndCaret(
unsigned LineNo = SM.getLineNumber(FID, FileOffset);
unsigned ColNo = SM.getColumnNumber(FID, FileOffset);
+
+ // Arbitrarily stop showing snippets when the line is too long.
+ static const ptrdiff_t MaxLineLengthToPrint = 4096;
+ if (ColNo > MaxLineLengthToPrint)
+ return;
// Rewind from the current position to the start of the line.
const char *TokPtr = BufStart+FileOffset;
const char *LineStart = TokPtr-ColNo+1; // Column # is 1-based.
-
// Compute the line end. Scan forward from the error position to the end of
// the line.
const char *LineEnd = TokPtr;
while (*LineEnd != '\n' && *LineEnd != '\r' && *LineEnd != '\0')
++LineEnd;
+ // Arbitrarily stop showing snippets when the line is too long.
+ if (LineEnd - LineStart > MaxLineLengthToPrint)
+ return;
+
// Copy the line of code into an std::string for ease of manipulation.
std::string SourceLine(LineStart, LineEnd);
@@ -949,7 +1126,7 @@ void TextDiagnostic::emitSnippetAndCaret(
for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
E = Ranges.end();
I != E; ++I)
- highlightRange(*I, LineNo, FID, sourceColMap, CaretLine, SM);
+ highlightRange(*I, LineNo, FID, sourceColMap, CaretLine, SM, LangOpts);
// Next, insert the caret itself.
ColNo = sourceColMap.byteToContainingColumn(ColNo-1);
@@ -959,7 +1136,8 @@ void TextDiagnostic::emitSnippetAndCaret(
std::string FixItInsertionLine = buildFixItInsertionLine(LineNo,
sourceColMap,
- Hints, SM);
+ Hints, SM,
+ DiagOpts.getPtr());
// If the source line is too long for our terminal, select only the
// "interesting" source region within that line.
@@ -1041,157 +1219,6 @@ void TextDiagnostic::emitSnippet(StringRef line) {
OS << '\n';
}
-/// \brief Highlight a SourceRange (with ~'s) for any characters on LineNo.
-void TextDiagnostic::highlightRange(const CharSourceRange &R,
- unsigned LineNo, FileID FID,
- const SourceColumnMap &map,
- std::string &CaretLine,
- const SourceManager &SM) {
- if (!R.isValid()) return;
-
- SourceLocation Begin = R.getBegin();
- SourceLocation End = R.getEnd();
-
- unsigned StartLineNo = SM.getExpansionLineNumber(Begin);
- if (StartLineNo > LineNo || SM.getFileID(Begin) != FID)
- return; // No intersection.
-
- unsigned EndLineNo = SM.getExpansionLineNumber(End);
- if (EndLineNo < LineNo || SM.getFileID(End) != FID)
- return; // No intersection.
-
- // Compute the column number of the start.
- unsigned StartColNo = 0;
- if (StartLineNo == LineNo) {
- StartColNo = SM.getExpansionColumnNumber(Begin);
- if (StartColNo) --StartColNo; // Zero base the col #.
- }
-
- // Compute the column number of the end.
- unsigned EndColNo = map.getSourceLine().size();
- if (EndLineNo == LineNo) {
- EndColNo = SM.getExpansionColumnNumber(End);
- if (EndColNo) {
- --EndColNo; // Zero base the col #.
-
- // Add in the length of the token, so that we cover multi-char tokens if
- // this is a token range.
- if (R.isTokenRange())
- EndColNo += Lexer::MeasureTokenLength(End, SM, LangOpts);
- } else {
- EndColNo = CaretLine.size();
- }
- }
-
- assert(StartColNo <= EndColNo && "Invalid range!");
-
- // Check that a token range does not highlight only whitespace.
- if (R.isTokenRange()) {
- // Pick the first non-whitespace column.
- while (StartColNo < map.getSourceLine().size() &&
- (map.getSourceLine()[StartColNo] == ' ' ||
- map.getSourceLine()[StartColNo] == '\t'))
- StartColNo = map.startOfNextColumn(StartColNo);
-
- // Pick the last non-whitespace column.
- if (EndColNo > map.getSourceLine().size())
- EndColNo = map.getSourceLine().size();
- while (EndColNo-1 &&
- (map.getSourceLine()[EndColNo-1] == ' ' ||
- map.getSourceLine()[EndColNo-1] == '\t'))
- EndColNo = map.startOfPreviousColumn(EndColNo);
-
- // If the start/end passed each other, then we are trying to highlight a
- // range that just exists in whitespace, which must be some sort of other
- // bug.
- assert(StartColNo <= EndColNo && "Trying to highlight whitespace??");
- }
-
- assert(StartColNo <= map.getSourceLine().size() && "Invalid range!");
- assert(EndColNo <= map.getSourceLine().size() && "Invalid range!");
-
- // Fill the range with ~'s.
- StartColNo = map.byteToContainingColumn(StartColNo);
- EndColNo = map.byteToContainingColumn(EndColNo);
-
- assert(StartColNo <= EndColNo && "Invalid range!");
- if (CaretLine.size() < EndColNo)
- CaretLine.resize(EndColNo,' ');
- std::fill(CaretLine.begin()+StartColNo,CaretLine.begin()+EndColNo,'~');
-}
-
-std::string TextDiagnostic::buildFixItInsertionLine(
- unsigned LineNo,
- const SourceColumnMap &map,
- ArrayRef<FixItHint> Hints,
- const SourceManager &SM) {
-
- std::string FixItInsertionLine;
- if (Hints.empty() || !DiagOpts->ShowFixits)
- return FixItInsertionLine;
- unsigned PrevHintEndCol = 0;
-
- for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end();
- I != E; ++I) {
- if (!I->CodeToInsert.empty()) {
- // We have an insertion hint. Determine whether the inserted
- // code contains no newlines and is on the same line as the caret.
- std::pair<FileID, unsigned> HintLocInfo
- = SM.getDecomposedExpansionLoc(I->RemoveRange.getBegin());
- if (LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) &&
- StringRef(I->CodeToInsert).find_first_of("\n\r") == StringRef::npos) {
- // Insert the new code into the line just below the code
- // that the user wrote.
- // Note: When modifying this function, be very careful about what is a
- // "column" (printed width, platform-dependent) and what is a
- // "byte offset" (SourceManager "column").
- unsigned HintByteOffset
- = SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second) - 1;
-
- // The hint must start inside the source or right at the end
- assert(HintByteOffset < static_cast<unsigned>(map.bytes())+1);
- unsigned HintCol = map.byteToContainingColumn(HintByteOffset);
-
- // If we inserted a long previous hint, push this one forwards, and add
- // an extra space to show that this is not part of the previous
- // completion. This is sort of the best we can do when two hints appear
- // to overlap.
- //
- // Note that if this hint is located immediately after the previous
- // hint, no space will be added, since the location is more important.
- if (HintCol < PrevHintEndCol)
- HintCol = PrevHintEndCol + 1;
-
- // FIXME: This function handles multibyte characters in the source, but
- // not in the fixits. This assertion is intended to catch unintended
- // use of multibyte characters in fixits. If we decide to do this, we'll
- // have to track separate byte widths for the source and fixit lines.
- assert((size_t)llvm::sys::locale::columnWidth(I->CodeToInsert) ==
- I->CodeToInsert.size());
-
- // This relies on one byte per column in our fixit hints.
- // This should NOT use HintByteOffset, because the source might have
- // Unicode characters in earlier columns.
- unsigned LastColumnModified = HintCol + I->CodeToInsert.size();
- if (LastColumnModified > FixItInsertionLine.size())
- FixItInsertionLine.resize(LastColumnModified, ' ');
-
- std::copy(I->CodeToInsert.begin(), I->CodeToInsert.end(),
- FixItInsertionLine.begin() + HintCol);
-
- PrevHintEndCol = LastColumnModified;
- } else {
- FixItInsertionLine.clear();
- break;
- }
- }
- }
-
- expandTabs(FixItInsertionLine, DiagOpts->TabStop);
-
- return FixItInsertionLine;
-}
-
void TextDiagnostic::emitParseableFixits(ArrayRef<FixItHint> Hints,
const SourceManager &SM) {
if (!DiagOpts->ShowParseableFixits)
diff --git a/lib/Frontend/TextDiagnosticBuffer.cpp b/lib/Frontend/TextDiagnosticBuffer.cpp
index 57105f1..039475a 100644
--- a/lib/Frontend/TextDiagnosticBuffer.cpp
+++ b/lib/Frontend/TextDiagnosticBuffer.cpp
@@ -42,17 +42,37 @@ void TextDiagnosticBuffer::HandleDiagnostic(DiagnosticsEngine::Level Level,
}
}
+/// \brief Escape diagnostic texts to avoid problems when they are fed into the
+/// diagnostic formatter a second time.
+static StringRef escapeDiag(StringRef Str, SmallVectorImpl<char> &Buf) {
+ size_t Pos = Str.find('%');
+ if (Pos == StringRef::npos)
+ return Str;
+
+ // We found a '%'. Replace this and all following '%' with '%%'.
+ Buf.clear();
+ Buf.append(Str.data(), Str.data() + Pos);
+ for (size_t I = Pos, E = Str.size(); I != E; ++I) {
+ if (Str[I] == '%')
+ Buf.push_back('%');
+ Buf.push_back(Str[I]);
+ }
+
+ return StringRef(Buf.data(), Buf.size());
+}
+
void TextDiagnosticBuffer::FlushDiagnostics(DiagnosticsEngine &Diags) const {
+ SmallVector<char, 64> Buf;
// FIXME: Flush the diagnostics in order.
for (const_iterator it = err_begin(), ie = err_end(); it != ie; ++it)
Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Error,
- it->second.c_str()));
+ escapeDiag(it->second, Buf)));
for (const_iterator it = warn_begin(), ie = warn_end(); it != ie; ++it)
Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Warning,
- it->second.c_str()));
+ escapeDiag(it->second, Buf)));
for (const_iterator it = note_begin(), ie = note_end(); it != ie; ++it)
Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Note,
- it->second.c_str()));
+ escapeDiag(it->second, Buf)));
}
DiagnosticConsumer *TextDiagnosticBuffer::clone(DiagnosticsEngine &) const {
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index aa7a61a..010f649 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -17,10 +17,10 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/TextDiagnostic.h"
#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/ADT/SmallString.h"
#include <algorithm>
using namespace clang;
diff --git a/lib/Frontend/VerifyDiagnosticConsumer.cpp b/lib/Frontend/VerifyDiagnosticConsumer.cpp
index 1750946..82f6e91 100644
--- a/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -11,8 +11,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Basic/FileManager.h"
#include "clang/Frontend/VerifyDiagnosticConsumer.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/FileManager.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/TextDiagnosticBuffer.h"
#include "clang/Lex/HeaderSearch.h"
@@ -20,7 +21,6 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/raw_ostream.h"
-#include <cctype>
using namespace clang;
typedef VerifyDiagnosticConsumer::Directive Directive;
@@ -234,7 +234,7 @@ public:
break;
if (!EnsureStartOfWord
// Check if string literal starts a new word.
- || P == Begin || isspace(P[-1])
+ || P == Begin || isWhitespace(P[-1])
// Or it could be preceeded by the start of a comment.
|| (P > (Begin + 1) && (P[-1] == '/' || P[-1] == '*')
&& P[-2] == '/'))
@@ -253,7 +253,7 @@ public:
// Skip zero or more whitespace.
void SkipWhitespace() {
- for (; C < End && isspace(*C); ++C)
+ for (; C < End && isWhitespace(*C); ++C)
;
}
diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp
index f789b7f..b7547b9 100644
--- a/lib/Frontend/Warnings.cpp
+++ b/lib/Frontend/Warnings.cpp
@@ -22,13 +22,13 @@
//
#include "clang/Frontend/Utils.h"
#include "clang/Basic/Diagnostic.h"
-#include "clang/Sema/SemaDiagnostic.h"
-#include "clang/Lex/LexDiagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include <algorithm>
#include <cstring>
#include <utility>
-#include <algorithm>
using namespace clang;
// EmitUnknownDiagWarning - Emit a warning and typo hint for unknown warning
@@ -48,13 +48,15 @@ static void EmitUnknownDiagWarning(DiagnosticsEngine &Diags,
}
void clang::ProcessWarningOptions(DiagnosticsEngine &Diags,
- const DiagnosticOptions &Opts) {
+ const DiagnosticOptions &Opts,
+ bool ReportDiags) {
Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers
Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings);
Diags.setShowOverloads(Opts.getShowOverloads());
Diags.setElideType(Opts.ElideType);
Diags.setPrintTemplateTree(Opts.ShowTemplateTree);
+ Diags.setWarnOnSpellCheck(Opts.WarnOnSpellCheck);
Diags.setShowColors(Opts.ShowColors);
// Handle -ferror-limit
@@ -75,7 +77,7 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags,
else
Diags.setExtensionHandlingBehavior(DiagnosticsEngine::Ext_Ignore);
- llvm::SmallVector<diag::kind, 10> _Diags;
+ SmallVector<diag::kind, 10> _Diags;
const IntrusiveRefCntPtr< DiagnosticIDs > DiagIDs =
Diags.getDiagnosticIDs();
// We parse the warning options twice. The first pass sets diagnostic state,
@@ -84,6 +86,12 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags,
// conflicting options.
for (unsigned Report = 0, ReportEnd = 2; Report != ReportEnd; ++Report) {
bool SetDiagnostic = (Report == 0);
+
+ // If we've set the diagnostic state and are not reporting diagnostics then
+ // we're done.
+ if (!SetDiagnostic && !ReportDiags)
+ break;
+
for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) {
StringRef Opt = Opts.Warnings[i];
StringRef OrigOpt = Opts.Warnings[i];
diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index c7c55b0..b0d76da 100644
--- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -13,24 +13,25 @@
//===----------------------------------------------------------------------===//
#include "clang/FrontendTool/Utils.h"
-#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
#include "clang/ARCMigrate/ARCMTActions.h"
#include "clang/CodeGen/CodeGenAction.h"
+#include "clang/Driver/OptTable.h"
#include "clang/Driver/Option.h"
#include "clang/Driver/Options.h"
-#include "clang/Driver/OptTable.h"
-#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/FrontendPluginRegistry.h"
#include "clang/Rewrite/Frontend/FrontendActions.h"
-#include "llvm/Support/ErrorHandling.h"
+#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/ErrorHandling.h"
using namespace clang;
static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
using namespace clang::frontend;
+ StringRef Action("unknown");
switch (CI.getFrontendOpts().ProgramAction) {
case ASTDeclList: return new ASTDeclListAction();
@@ -42,17 +43,26 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
case DumpTokens: return new DumpTokensAction();
case EmitAssembly: return new EmitAssemblyAction();
case EmitBC: return new EmitBCAction();
+#ifdef CLANG_ENABLE_REWRITER
case EmitHTML: return new HTMLPrintAction();
+#else
+ case EmitHTML: Action = "EmitHTML"; break;
+#endif
case EmitLLVM: return new EmitLLVMAction();
case EmitLLVMOnly: return new EmitLLVMOnlyAction();
case EmitCodeGenOnly: return new EmitCodeGenOnlyAction();
case EmitObj: return new EmitObjAction();
+#ifdef CLANG_ENABLE_REWRITER
case FixIt: return new FixItAction();
+#else
+ case FixIt: Action = "FixIt"; break;
+#endif
case GenerateModule: return new GenerateModuleAction;
case GeneratePCH: return new GeneratePCHAction;
case GeneratePTH: return new GeneratePTHAction();
case InitOnly: return new InitOnlyAction();
case ParseSyntaxOnly: return new SyntaxOnlyAction();
+ case ModuleFileInfo: return new DumpModuleInfoAction();
case PluginAction: {
for (FrontendPluginRegistry::iterator it =
@@ -74,19 +84,46 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
case PrintDeclContext: return new DeclContextPrintAction();
case PrintPreamble: return new PrintPreambleAction();
case PrintPreprocessedInput: {
- if (CI.getPreprocessorOutputOpts().RewriteIncludes)
+ if (CI.getPreprocessorOutputOpts().RewriteIncludes) {
+#ifdef CLANG_ENABLE_REWRITER
return new RewriteIncludesAction();
+#else
+ Action = "RewriteIncludesAction";
+ break;
+#endif
+ }
return new PrintPreprocessedAction();
}
+#ifdef CLANG_ENABLE_REWRITER
case RewriteMacros: return new RewriteMacrosAction();
case RewriteObjC: return new RewriteObjCAction();
case RewriteTest: return new RewriteTestAction();
- case RunAnalysis: return new ento::AnalysisAction();
+#else
+ case RewriteMacros: Action = "RewriteMacros"; break;
+ case RewriteObjC: Action = "RewriteObjC"; break;
+ case RewriteTest: Action = "RewriteTest"; break;
+#endif
+#ifdef CLANG_ENABLE_ARCMT
case MigrateSource: return new arcmt::MigrateSourceAction();
+#else
+ case MigrateSource: Action = "MigrateSource"; break;
+#endif
+#ifdef CLANG_ENABLE_STATIC_ANALYZER
+ case RunAnalysis: return new ento::AnalysisAction();
+#else
+ case RunAnalysis: Action = "RunAnalysis"; break;
+#endif
case RunPreprocessorOnly: return new PreprocessOnlyAction();
}
+
+#if !defined(CLANG_ENABLE_ARCMT) || !defined(CLANG_ENABLE_STATIC_ANALYZER) \
+ || !defined(CLANG_ENABLE_REWRITER)
+ CI.getDiagnostics().Report(diag::err_fe_action_not_available) << Action;
+ return 0;
+#else
llvm_unreachable("Invalid program action!");
+#endif
}
static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
@@ -97,10 +134,13 @@ static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
const FrontendOptions &FEOpts = CI.getFrontendOpts();
+#ifdef CLANG_ENABLE_REWRITER
if (FEOpts.FixAndRecompile) {
Act = new FixItRecompile(Act);
}
+#endif
+#ifdef CLANG_ENABLE_ARCMT
// Potentially wrap the base FE action in an ARC Migrate Tool action.
switch (FEOpts.ARCMTAction) {
case FrontendOptions::ARCMT_None:
@@ -124,6 +164,7 @@ static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
FEOpts.ObjCMTAction & ~FrontendOptions::ObjCMT_Literals,
FEOpts.ObjCMTAction & ~FrontendOptions::ObjCMT_Subscripting);
}
+#endif
// If there are any AST files to merge, create a frontend action
// adaptor to perform the merge.
@@ -176,24 +217,24 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) {
llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args);
}
+#ifdef CLANG_ENABLE_STATIC_ANALYZER
// Honor -analyzer-checker-help.
// This should happen AFTER plugins have been loaded!
if (Clang->getAnalyzerOpts()->ShowCheckerHelp) {
ento::printCheckerHelp(llvm::outs(), Clang->getFrontendOpts().Plugins);
return 0;
}
+#endif
// If there were errors in processing arguments, don't do anything else.
- bool Success = false;
- if (!Clang->getDiagnostics().hasErrorOccurred()) {
- // Create and execute the frontend action.
- OwningPtr<FrontendAction> Act(CreateFrontendAction(*Clang));
- if (Act) {
- Success = Clang->ExecuteAction(*Act);
- if (Clang->getFrontendOpts().DisableFree)
- Act.take();
- }
- }
-
+ if (Clang->getDiagnostics().hasErrorOccurred())
+ return false;
+ // Create and execute the frontend action.
+ OwningPtr<FrontendAction> Act(CreateFrontendAction(*Clang));
+ if (!Act)
+ return false;
+ bool Success = Clang->ExecuteAction(*Act);
+ if (Clang->getFrontendOpts().DisableFree)
+ Act.take();
return Success;
}
diff --git a/lib/FrontendTool/Makefile b/lib/FrontendTool/Makefile
index c43213f..9ce4b76 100644
--- a/lib/FrontendTool/Makefile
+++ b/lib/FrontendTool/Makefile
@@ -11,3 +11,18 @@ CLANG_LEVEL := ../..
LIBRARYNAME := clangFrontendTool
include $(CLANG_LEVEL)/Makefile
+include $(CLANG_LEVEL)/../../Makefile.config
+
+ifeq ($(ENABLE_CLANG_ARCMT),1)
+ CXX.Flags += -DCLANG_ENABLE_ARCMT
+endif
+
+ifeq ($(ENABLE_CLANG_REWRITER),1)
+ CXX.Flags += -DCLANG_ENABLE_REWRITER
+endif
+
+ifeq ($(ENABLE_CLANG_STATIC_ANALYZER),1)
+ CXX.Flags += -DCLANG_ENABLE_STATIC_ANALYZER
+endif
+
+
diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt
index 25e4d90..5e727a7 100644
--- a/lib/Headers/CMakeLists.txt
+++ b/lib/Headers/CMakeLists.txt
@@ -20,6 +20,8 @@ set(files
nmmintrin.h
pmmintrin.h
popcntintrin.h
+ prfchwintrin.h
+ rdseedintrin.h
rtmintrin.h
smmintrin.h
stdalign.h
@@ -27,6 +29,7 @@ set(files
stdbool.h
stddef.h
stdint.h
+ stdnoreturn.h
tgmath.h
tmmintrin.h
varargs.h
@@ -92,6 +95,13 @@ endif ()
add_custom_target(clang-headers ALL DEPENDS ${out_files})
set_target_properties(clang-headers PROPERTIES FOLDER "Misc")
+if (other_output_dir)
+ if(UNIX)
+ add_custom_command(TARGET clang-headers POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E create_symlink "${LLVM_BINARY_DIR}/bin/lib/clang" "${LLVM_BINARY_DIR}/lib/${CMAKE_CFG_INTDIR}/clang")
+ endif()
+endif ()
+
install(FILES ${files} ${output_dir}/arm_neon.h
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
DESTINATION lib${LLVM_LIBDIR_SUFFIX}/clang/${CLANG_VERSION}/include)
diff --git a/lib/Headers/altivec.h b/lib/Headers/altivec.h
index 2bf53fb..74ce08a 100644
--- a/lib/Headers/altivec.h
+++ b/lib/Headers/altivec.h
@@ -37,41 +37,41 @@
#define __ATTRS_o_ai __attribute__((__overloadable__, __always_inline__))
static vector signed char __ATTRS_o_ai
-vec_perm(vector signed char a, vector signed char b, vector unsigned char c);
+vec_perm(vector signed char __a, vector signed char __b, vector unsigned char __c);
static vector unsigned char __ATTRS_o_ai
-vec_perm(vector unsigned char a,
- vector unsigned char b,
- vector unsigned char c);
+vec_perm(vector unsigned char __a,
+ vector unsigned char __b,
+ vector unsigned char __c);
static vector bool char __ATTRS_o_ai
-vec_perm(vector bool char a, vector bool char b, vector unsigned char c);
+vec_perm(vector bool char __a, vector bool char __b, vector unsigned char __c);
static vector short __ATTRS_o_ai
-vec_perm(vector short a, vector short b, vector unsigned char c);
+vec_perm(vector short __a, vector short __b, vector unsigned char __c);
static vector unsigned short __ATTRS_o_ai
-vec_perm(vector unsigned short a,
- vector unsigned short b,
- vector unsigned char c);
+vec_perm(vector unsigned short __a,
+ vector unsigned short __b,
+ vector unsigned char __c);
static vector bool short __ATTRS_o_ai
-vec_perm(vector bool short a, vector bool short b, vector unsigned char c);
+vec_perm(vector bool short __a, vector bool short __b, vector unsigned char __c);
static vector pixel __ATTRS_o_ai
-vec_perm(vector pixel a, vector pixel b, vector unsigned char c);
+vec_perm(vector pixel __a, vector pixel __b, vector unsigned char __c);
static vector int __ATTRS_o_ai
-vec_perm(vector int a, vector int b, vector unsigned char c);
+vec_perm(vector int __a, vector int __b, vector unsigned char __c);
static vector unsigned int __ATTRS_o_ai
-vec_perm(vector unsigned int a, vector unsigned int b, vector unsigned char c);
+vec_perm(vector unsigned int __a, vector unsigned int __b, vector unsigned char __c);
static vector bool int __ATTRS_o_ai
-vec_perm(vector bool int a, vector bool int b, vector unsigned char c);
+vec_perm(vector bool int __a, vector bool int __b, vector unsigned char __c);
static vector float __ATTRS_o_ai
-vec_perm(vector float a, vector float b, vector unsigned char c);
+vec_perm(vector float __a, vector float __b, vector unsigned char __c);
/* vec_abs */
@@ -80,29 +80,29 @@ vec_perm(vector float a, vector float b, vector unsigned char c);
#define __builtin_altivec_abs_v4si vec_abs
static vector signed char __ATTRS_o_ai
-vec_abs(vector signed char a)
+vec_abs(vector signed char __a)
{
- return __builtin_altivec_vmaxsb(a, -a);
+ return __builtin_altivec_vmaxsb(__a, -__a);
}
static vector signed short __ATTRS_o_ai
-vec_abs(vector signed short a)
+vec_abs(vector signed short __a)
{
- return __builtin_altivec_vmaxsh(a, -a);
+ return __builtin_altivec_vmaxsh(__a, -__a);
}
static vector signed int __ATTRS_o_ai
-vec_abs(vector signed int a)
+vec_abs(vector signed int __a)
{
- return __builtin_altivec_vmaxsw(a, -a);
+ return __builtin_altivec_vmaxsw(__a, -__a);
}
static vector float __ATTRS_o_ai
-vec_abs(vector float a)
+vec_abs(vector float __a)
{
- vector unsigned int res = (vector unsigned int)a
+ vector unsigned int __res = (vector unsigned int)__a
& (vector unsigned int)(0x7FFFFFFF);
- return (vector float)res;
+ return (vector float)__res;
}
/* vec_abss */
@@ -112,140 +112,140 @@ vec_abs(vector float a)
#define __builtin_altivec_abss_v4si vec_abss
static vector signed char __ATTRS_o_ai
-vec_abss(vector signed char a)
+vec_abss(vector signed char __a)
{
return __builtin_altivec_vmaxsb
- (a, __builtin_altivec_vsubsbs((vector signed char)(0), a));
+ (__a, __builtin_altivec_vsubsbs((vector signed char)(0), __a));
}
static vector signed short __ATTRS_o_ai
-vec_abss(vector signed short a)
+vec_abss(vector signed short __a)
{
return __builtin_altivec_vmaxsh
- (a, __builtin_altivec_vsubshs((vector signed short)(0), a));
+ (__a, __builtin_altivec_vsubshs((vector signed short)(0), __a));
}
static vector signed int __ATTRS_o_ai
-vec_abss(vector signed int a)
+vec_abss(vector signed int __a)
{
return __builtin_altivec_vmaxsw
- (a, __builtin_altivec_vsubsws((vector signed int)(0), a));
+ (__a, __builtin_altivec_vsubsws((vector signed int)(0), __a));
}
/* vec_add */
static vector signed char __ATTRS_o_ai
-vec_add(vector signed char a, vector signed char b)
+vec_add(vector signed char __a, vector signed char __b)
{
- return a + b;
+ return __a + __b;
}
static vector signed char __ATTRS_o_ai
-vec_add(vector bool char a, vector signed char b)
+vec_add(vector bool char __a, vector signed char __b)
{
- return (vector signed char)a + b;
+ return (vector signed char)__a + __b;
}
static vector signed char __ATTRS_o_ai
-vec_add(vector signed char a, vector bool char b)
+vec_add(vector signed char __a, vector bool char __b)
{
- return a + (vector signed char)b;
+ return __a + (vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_add(vector unsigned char a, vector unsigned char b)
+vec_add(vector unsigned char __a, vector unsigned char __b)
{
- return a + b;
+ return __a + __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_add(vector bool char a, vector unsigned char b)
+vec_add(vector bool char __a, vector unsigned char __b)
{
- return (vector unsigned char)a + b;
+ return (vector unsigned char)__a + __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_add(vector unsigned char a, vector bool char b)
+vec_add(vector unsigned char __a, vector bool char __b)
{
- return a + (vector unsigned char)b;
+ return __a + (vector unsigned char)__b;
}
static vector short __ATTRS_o_ai
-vec_add(vector short a, vector short b)
+vec_add(vector short __a, vector short __b)
{
- return a + b;
+ return __a + __b;
}
static vector short __ATTRS_o_ai
-vec_add(vector bool short a, vector short b)
+vec_add(vector bool short __a, vector short __b)
{
- return (vector short)a + b;
+ return (vector short)__a + __b;
}
static vector short __ATTRS_o_ai
-vec_add(vector short a, vector bool short b)
+vec_add(vector short __a, vector bool short __b)
{
- return a + (vector short)b;
+ return __a + (vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_add(vector unsigned short a, vector unsigned short b)
+vec_add(vector unsigned short __a, vector unsigned short __b)
{
- return a + b;
+ return __a + __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_add(vector bool short a, vector unsigned short b)
+vec_add(vector bool short __a, vector unsigned short __b)
{
- return (vector unsigned short)a + b;
+ return (vector unsigned short)__a + __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_add(vector unsigned short a, vector bool short b)
+vec_add(vector unsigned short __a, vector bool short __b)
{
- return a + (vector unsigned short)b;
+ return __a + (vector unsigned short)__b;
}
static vector int __ATTRS_o_ai
-vec_add(vector int a, vector int b)
+vec_add(vector int __a, vector int __b)
{
- return a + b;
+ return __a + __b;
}
static vector int __ATTRS_o_ai
-vec_add(vector bool int a, vector int b)
+vec_add(vector bool int __a, vector int __b)
{
- return (vector int)a + b;
+ return (vector int)__a + __b;
}
static vector int __ATTRS_o_ai
-vec_add(vector int a, vector bool int b)
+vec_add(vector int __a, vector bool int __b)
{
- return a + (vector int)b;
+ return __a + (vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_add(vector unsigned int a, vector unsigned int b)
+vec_add(vector unsigned int __a, vector unsigned int __b)
{
- return a + b;
+ return __a + __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_add(vector bool int a, vector unsigned int b)
+vec_add(vector bool int __a, vector unsigned int __b)
{
- return (vector unsigned int)a + b;
+ return (vector unsigned int)__a + __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_add(vector unsigned int a, vector bool int b)
+vec_add(vector unsigned int __a, vector bool int __b)
{
- return a + (vector unsigned int)b;
+ return __a + (vector unsigned int)__b;
}
static vector float __ATTRS_o_ai
-vec_add(vector float a, vector float b)
+vec_add(vector float __a, vector float __b)
{
- return a + b;
+ return __a + __b;
}
/* vec_vaddubm */
@@ -253,39 +253,39 @@ vec_add(vector float a, vector float b)
#define __builtin_altivec_vaddubm vec_vaddubm
static vector signed char __ATTRS_o_ai
-vec_vaddubm(vector signed char a, vector signed char b)
+vec_vaddubm(vector signed char __a, vector signed char __b)
{
- return a + b;
+ return __a + __b;
}
static vector signed char __ATTRS_o_ai
-vec_vaddubm(vector bool char a, vector signed char b)
+vec_vaddubm(vector bool char __a, vector signed char __b)
{
- return (vector signed char)a + b;
+ return (vector signed char)__a + __b;
}
static vector signed char __ATTRS_o_ai
-vec_vaddubm(vector signed char a, vector bool char b)
+vec_vaddubm(vector signed char __a, vector bool char __b)
{
- return a + (vector signed char)b;
+ return __a + (vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vaddubm(vector unsigned char a, vector unsigned char b)
+vec_vaddubm(vector unsigned char __a, vector unsigned char __b)
{
- return a + b;
+ return __a + __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vaddubm(vector bool char a, vector unsigned char b)
+vec_vaddubm(vector bool char __a, vector unsigned char __b)
{
- return (vector unsigned char)a + b;
+ return (vector unsigned char)__a + __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vaddubm(vector unsigned char a, vector bool char b)
+vec_vaddubm(vector unsigned char __a, vector bool char __b)
{
- return a + (vector unsigned char)b;
+ return __a + (vector unsigned char)__b;
}
/* vec_vadduhm */
@@ -293,39 +293,39 @@ vec_vaddubm(vector unsigned char a, vector bool char b)
#define __builtin_altivec_vadduhm vec_vadduhm
static vector short __ATTRS_o_ai
-vec_vadduhm(vector short a, vector short b)
+vec_vadduhm(vector short __a, vector short __b)
{
- return a + b;
+ return __a + __b;
}
static vector short __ATTRS_o_ai
-vec_vadduhm(vector bool short a, vector short b)
+vec_vadduhm(vector bool short __a, vector short __b)
{
- return (vector short)a + b;
+ return (vector short)__a + __b;
}
static vector short __ATTRS_o_ai
-vec_vadduhm(vector short a, vector bool short b)
+vec_vadduhm(vector short __a, vector bool short __b)
{
- return a + (vector short)b;
+ return __a + (vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vadduhm(vector unsigned short a, vector unsigned short b)
+vec_vadduhm(vector unsigned short __a, vector unsigned short __b)
{
- return a + b;
+ return __a + __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vadduhm(vector bool short a, vector unsigned short b)
+vec_vadduhm(vector bool short __a, vector unsigned short __b)
{
- return (vector unsigned short)a + b;
+ return (vector unsigned short)__a + __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vadduhm(vector unsigned short a, vector bool short b)
+vec_vadduhm(vector unsigned short __a, vector bool short __b)
{
- return a + (vector unsigned short)b;
+ return __a + (vector unsigned short)__b;
}
/* vec_vadduwm */
@@ -333,39 +333,39 @@ vec_vadduhm(vector unsigned short a, vector bool short b)
#define __builtin_altivec_vadduwm vec_vadduwm
static vector int __ATTRS_o_ai
-vec_vadduwm(vector int a, vector int b)
+vec_vadduwm(vector int __a, vector int __b)
{
- return a + b;
+ return __a + __b;
}
static vector int __ATTRS_o_ai
-vec_vadduwm(vector bool int a, vector int b)
+vec_vadduwm(vector bool int __a, vector int __b)
{
- return (vector int)a + b;
+ return (vector int)__a + __b;
}
static vector int __ATTRS_o_ai
-vec_vadduwm(vector int a, vector bool int b)
+vec_vadduwm(vector int __a, vector bool int __b)
{
- return a + (vector int)b;
+ return __a + (vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vadduwm(vector unsigned int a, vector unsigned int b)
+vec_vadduwm(vector unsigned int __a, vector unsigned int __b)
{
- return a + b;
+ return __a + __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vadduwm(vector bool int a, vector unsigned int b)
+vec_vadduwm(vector bool int __a, vector unsigned int __b)
{
- return (vector unsigned int)a + b;
+ return (vector unsigned int)__a + __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vadduwm(vector unsigned int a, vector bool int b)
+vec_vadduwm(vector unsigned int __a, vector bool int __b)
{
- return a + (vector unsigned int)b;
+ return __a + (vector unsigned int)__b;
}
/* vec_vaddfp */
@@ -373,255 +373,255 @@ vec_vadduwm(vector unsigned int a, vector bool int b)
#define __builtin_altivec_vaddfp vec_vaddfp
static vector float __attribute__((__always_inline__))
-vec_vaddfp(vector float a, vector float b)
+vec_vaddfp(vector float __a, vector float __b)
{
- return a + b;
+ return __a + __b;
}
/* vec_addc */
static vector unsigned int __attribute__((__always_inline__))
-vec_addc(vector unsigned int a, vector unsigned int b)
+vec_addc(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vaddcuw(a, b);
+ return __builtin_altivec_vaddcuw(__a, __b);
}
/* vec_vaddcuw */
static vector unsigned int __attribute__((__always_inline__))
-vec_vaddcuw(vector unsigned int a, vector unsigned int b)
+vec_vaddcuw(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vaddcuw(a, b);
+ return __builtin_altivec_vaddcuw(__a, __b);
}
/* vec_adds */
static vector signed char __ATTRS_o_ai
-vec_adds(vector signed char a, vector signed char b)
+vec_adds(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vaddsbs(a, b);
+ return __builtin_altivec_vaddsbs(__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_adds(vector bool char a, vector signed char b)
+vec_adds(vector bool char __a, vector signed char __b)
{
- return __builtin_altivec_vaddsbs((vector signed char)a, b);
+ return __builtin_altivec_vaddsbs((vector signed char)__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_adds(vector signed char a, vector bool char b)
+vec_adds(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vaddsbs(a, (vector signed char)b);
+ return __builtin_altivec_vaddsbs(__a, (vector signed char)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_adds(vector unsigned char a, vector unsigned char b)
+vec_adds(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vaddubs(a, b);
+ return __builtin_altivec_vaddubs(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_adds(vector bool char a, vector unsigned char b)
+vec_adds(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vaddubs((vector unsigned char)a, b);
+ return __builtin_altivec_vaddubs((vector unsigned char)__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_adds(vector unsigned char a, vector bool char b)
+vec_adds(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vaddubs(a, (vector unsigned char)b);
+ return __builtin_altivec_vaddubs(__a, (vector unsigned char)__b);
}
static vector short __ATTRS_o_ai
-vec_adds(vector short a, vector short b)
+vec_adds(vector short __a, vector short __b)
{
- return __builtin_altivec_vaddshs(a, b);
+ return __builtin_altivec_vaddshs(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_adds(vector bool short a, vector short b)
+vec_adds(vector bool short __a, vector short __b)
{
- return __builtin_altivec_vaddshs((vector short)a, b);
+ return __builtin_altivec_vaddshs((vector short)__a, __b);
}
static vector short __ATTRS_o_ai
-vec_adds(vector short a, vector bool short b)
+vec_adds(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vaddshs(a, (vector short)b);
+ return __builtin_altivec_vaddshs(__a, (vector short)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_adds(vector unsigned short a, vector unsigned short b)
+vec_adds(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vadduhs(a, b);
+ return __builtin_altivec_vadduhs(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_adds(vector bool short a, vector unsigned short b)
+vec_adds(vector bool short __a, vector unsigned short __b)
{
- return __builtin_altivec_vadduhs((vector unsigned short)a, b);
+ return __builtin_altivec_vadduhs((vector unsigned short)__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_adds(vector unsigned short a, vector bool short b)
+vec_adds(vector unsigned short __a, vector bool short __b)
{
- return __builtin_altivec_vadduhs(a, (vector unsigned short)b);
+ return __builtin_altivec_vadduhs(__a, (vector unsigned short)__b);
}
static vector int __ATTRS_o_ai
-vec_adds(vector int a, vector int b)
+vec_adds(vector int __a, vector int __b)
{
- return __builtin_altivec_vaddsws(a, b);
+ return __builtin_altivec_vaddsws(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_adds(vector bool int a, vector int b)
+vec_adds(vector bool int __a, vector int __b)
{
- return __builtin_altivec_vaddsws((vector int)a, b);
+ return __builtin_altivec_vaddsws((vector int)__a, __b);
}
static vector int __ATTRS_o_ai
-vec_adds(vector int a, vector bool int b)
+vec_adds(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vaddsws(a, (vector int)b);
+ return __builtin_altivec_vaddsws(__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_adds(vector unsigned int a, vector unsigned int b)
+vec_adds(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vadduws(a, b);
+ return __builtin_altivec_vadduws(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_adds(vector bool int a, vector unsigned int b)
+vec_adds(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vadduws((vector unsigned int)a, b);
+ return __builtin_altivec_vadduws((vector unsigned int)__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_adds(vector unsigned int a, vector bool int b)
+vec_adds(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vadduws(a, (vector unsigned int)b);
+ return __builtin_altivec_vadduws(__a, (vector unsigned int)__b);
}
/* vec_vaddsbs */
static vector signed char __ATTRS_o_ai
-vec_vaddsbs(vector signed char a, vector signed char b)
+vec_vaddsbs(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vaddsbs(a, b);
+ return __builtin_altivec_vaddsbs(__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_vaddsbs(vector bool char a, vector signed char b)
+vec_vaddsbs(vector bool char __a, vector signed char __b)
{
- return __builtin_altivec_vaddsbs((vector signed char)a, b);
+ return __builtin_altivec_vaddsbs((vector signed char)__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_vaddsbs(vector signed char a, vector bool char b)
+vec_vaddsbs(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vaddsbs(a, (vector signed char)b);
+ return __builtin_altivec_vaddsbs(__a, (vector signed char)__b);
}
/* vec_vaddubs */
static vector unsigned char __ATTRS_o_ai
-vec_vaddubs(vector unsigned char a, vector unsigned char b)
+vec_vaddubs(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vaddubs(a, b);
+ return __builtin_altivec_vaddubs(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vaddubs(vector bool char a, vector unsigned char b)
+vec_vaddubs(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vaddubs((vector unsigned char)a, b);
+ return __builtin_altivec_vaddubs((vector unsigned char)__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vaddubs(vector unsigned char a, vector bool char b)
+vec_vaddubs(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vaddubs(a, (vector unsigned char)b);
+ return __builtin_altivec_vaddubs(__a, (vector unsigned char)__b);
}
/* vec_vaddshs */
static vector short __ATTRS_o_ai
-vec_vaddshs(vector short a, vector short b)
+vec_vaddshs(vector short __a, vector short __b)
{
- return __builtin_altivec_vaddshs(a, b);
+ return __builtin_altivec_vaddshs(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_vaddshs(vector bool short a, vector short b)
+vec_vaddshs(vector bool short __a, vector short __b)
{
- return __builtin_altivec_vaddshs((vector short)a, b);
+ return __builtin_altivec_vaddshs((vector short)__a, __b);
}
static vector short __ATTRS_o_ai
-vec_vaddshs(vector short a, vector bool short b)
+vec_vaddshs(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vaddshs(a, (vector short)b);
+ return __builtin_altivec_vaddshs(__a, (vector short)__b);
}
/* vec_vadduhs */
static vector unsigned short __ATTRS_o_ai
-vec_vadduhs(vector unsigned short a, vector unsigned short b)
+vec_vadduhs(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vadduhs(a, b);
+ return __builtin_altivec_vadduhs(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vadduhs(vector bool short a, vector unsigned short b)
+vec_vadduhs(vector bool short __a, vector unsigned short __b)
{
- return __builtin_altivec_vadduhs((vector unsigned short)a, b);
+ return __builtin_altivec_vadduhs((vector unsigned short)__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vadduhs(vector unsigned short a, vector bool short b)
+vec_vadduhs(vector unsigned short __a, vector bool short __b)
{
- return __builtin_altivec_vadduhs(a, (vector unsigned short)b);
+ return __builtin_altivec_vadduhs(__a, (vector unsigned short)__b);
}
/* vec_vaddsws */
static vector int __ATTRS_o_ai
-vec_vaddsws(vector int a, vector int b)
+vec_vaddsws(vector int __a, vector int __b)
{
- return __builtin_altivec_vaddsws(a, b);
+ return __builtin_altivec_vaddsws(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_vaddsws(vector bool int a, vector int b)
+vec_vaddsws(vector bool int __a, vector int __b)
{
- return __builtin_altivec_vaddsws((vector int)a, b);
+ return __builtin_altivec_vaddsws((vector int)__a, __b);
}
static vector int __ATTRS_o_ai
-vec_vaddsws(vector int a, vector bool int b)
+vec_vaddsws(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vaddsws(a, (vector int)b);
+ return __builtin_altivec_vaddsws(__a, (vector int)__b);
}
/* vec_vadduws */
static vector unsigned int __ATTRS_o_ai
-vec_vadduws(vector unsigned int a, vector unsigned int b)
+vec_vadduws(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vadduws(a, b);
+ return __builtin_altivec_vadduws(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vadduws(vector bool int a, vector unsigned int b)
+vec_vadduws(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vadduws((vector unsigned int)a, b);
+ return __builtin_altivec_vadduws((vector unsigned int)__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vadduws(vector unsigned int a, vector bool int b)
+vec_vadduws(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vadduws(a, (vector unsigned int)b);
+ return __builtin_altivec_vadduws(__a, (vector unsigned int)__b);
}
/* vec_and */
@@ -629,299 +629,299 @@ vec_vadduws(vector unsigned int a, vector bool int b)
#define __builtin_altivec_vand vec_and
static vector signed char __ATTRS_o_ai
-vec_and(vector signed char a, vector signed char b)
+vec_and(vector signed char __a, vector signed char __b)
{
- return a & b;
+ return __a & __b;
}
static vector signed char __ATTRS_o_ai
-vec_and(vector bool char a, vector signed char b)
+vec_and(vector bool char __a, vector signed char __b)
{
- return (vector signed char)a & b;
+ return (vector signed char)__a & __b;
}
static vector signed char __ATTRS_o_ai
-vec_and(vector signed char a, vector bool char b)
+vec_and(vector signed char __a, vector bool char __b)
{
- return a & (vector signed char)b;
+ return __a & (vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_and(vector unsigned char a, vector unsigned char b)
+vec_and(vector unsigned char __a, vector unsigned char __b)
{
- return a & b;
+ return __a & __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_and(vector bool char a, vector unsigned char b)
+vec_and(vector bool char __a, vector unsigned char __b)
{
- return (vector unsigned char)a & b;
+ return (vector unsigned char)__a & __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_and(vector unsigned char a, vector bool char b)
+vec_and(vector unsigned char __a, vector bool char __b)
{
- return a & (vector unsigned char)b;
+ return __a & (vector unsigned char)__b;
}
static vector bool char __ATTRS_o_ai
-vec_and(vector bool char a, vector bool char b)
+vec_and(vector bool char __a, vector bool char __b)
{
- return a & b;
+ return __a & __b;
}
static vector short __ATTRS_o_ai
-vec_and(vector short a, vector short b)
+vec_and(vector short __a, vector short __b)
{
- return a & b;
+ return __a & __b;
}
static vector short __ATTRS_o_ai
-vec_and(vector bool short a, vector short b)
+vec_and(vector bool short __a, vector short __b)
{
- return (vector short)a & b;
+ return (vector short)__a & __b;
}
static vector short __ATTRS_o_ai
-vec_and(vector short a, vector bool short b)
+vec_and(vector short __a, vector bool short __b)
{
- return a & (vector short)b;
+ return __a & (vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_and(vector unsigned short a, vector unsigned short b)
+vec_and(vector unsigned short __a, vector unsigned short __b)
{
- return a & b;
+ return __a & __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_and(vector bool short a, vector unsigned short b)
+vec_and(vector bool short __a, vector unsigned short __b)
{
- return (vector unsigned short)a & b;
+ return (vector unsigned short)__a & __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_and(vector unsigned short a, vector bool short b)
+vec_and(vector unsigned short __a, vector bool short __b)
{
- return a & (vector unsigned short)b;
+ return __a & (vector unsigned short)__b;
}
static vector bool short __ATTRS_o_ai
-vec_and(vector bool short a, vector bool short b)
+vec_and(vector bool short __a, vector bool short __b)
{
- return a & b;
+ return __a & __b;
}
static vector int __ATTRS_o_ai
-vec_and(vector int a, vector int b)
+vec_and(vector int __a, vector int __b)
{
- return a & b;
+ return __a & __b;
}
static vector int __ATTRS_o_ai
-vec_and(vector bool int a, vector int b)
+vec_and(vector bool int __a, vector int __b)
{
- return (vector int)a & b;
+ return (vector int)__a & __b;
}
static vector int __ATTRS_o_ai
-vec_and(vector int a, vector bool int b)
+vec_and(vector int __a, vector bool int __b)
{
- return a & (vector int)b;
+ return __a & (vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_and(vector unsigned int a, vector unsigned int b)
+vec_and(vector unsigned int __a, vector unsigned int __b)
{
- return a & b;
+ return __a & __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_and(vector bool int a, vector unsigned int b)
+vec_and(vector bool int __a, vector unsigned int __b)
{
- return (vector unsigned int)a & b;
+ return (vector unsigned int)__a & __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_and(vector unsigned int a, vector bool int b)
+vec_and(vector unsigned int __a, vector bool int __b)
{
- return a & (vector unsigned int)b;
+ return __a & (vector unsigned int)__b;
}
static vector bool int __ATTRS_o_ai
-vec_and(vector bool int a, vector bool int b)
+vec_and(vector bool int __a, vector bool int __b)
{
- return a & b;
+ return __a & __b;
}
static vector float __ATTRS_o_ai
-vec_and(vector float a, vector float b)
+vec_and(vector float __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a & (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a & (vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_and(vector bool int a, vector float b)
+vec_and(vector bool int __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a & (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a & (vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_and(vector float a, vector bool int b)
+vec_and(vector float __a, vector bool int __b)
{
- vector unsigned int res = (vector unsigned int)a & (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a & (vector unsigned int)__b;
+ return (vector float)__res;
}
/* vec_vand */
static vector signed char __ATTRS_o_ai
-vec_vand(vector signed char a, vector signed char b)
+vec_vand(vector signed char __a, vector signed char __b)
{
- return a & b;
+ return __a & __b;
}
static vector signed char __ATTRS_o_ai
-vec_vand(vector bool char a, vector signed char b)
+vec_vand(vector bool char __a, vector signed char __b)
{
- return (vector signed char)a & b;
+ return (vector signed char)__a & __b;
}
static vector signed char __ATTRS_o_ai
-vec_vand(vector signed char a, vector bool char b)
+vec_vand(vector signed char __a, vector bool char __b)
{
- return a & (vector signed char)b;
+ return __a & (vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vand(vector unsigned char a, vector unsigned char b)
+vec_vand(vector unsigned char __a, vector unsigned char __b)
{
- return a & b;
+ return __a & __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vand(vector bool char a, vector unsigned char b)
+vec_vand(vector bool char __a, vector unsigned char __b)
{
- return (vector unsigned char)a & b;
+ return (vector unsigned char)__a & __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vand(vector unsigned char a, vector bool char b)
+vec_vand(vector unsigned char __a, vector bool char __b)
{
- return a & (vector unsigned char)b;
+ return __a & (vector unsigned char)__b;
}
static vector bool char __ATTRS_o_ai
-vec_vand(vector bool char a, vector bool char b)
+vec_vand(vector bool char __a, vector bool char __b)
{
- return a & b;
+ return __a & __b;
}
static vector short __ATTRS_o_ai
-vec_vand(vector short a, vector short b)
+vec_vand(vector short __a, vector short __b)
{
- return a & b;
+ return __a & __b;
}
static vector short __ATTRS_o_ai
-vec_vand(vector bool short a, vector short b)
+vec_vand(vector bool short __a, vector short __b)
{
- return (vector short)a & b;
+ return (vector short)__a & __b;
}
static vector short __ATTRS_o_ai
-vec_vand(vector short a, vector bool short b)
+vec_vand(vector short __a, vector bool short __b)
{
- return a & (vector short)b;
+ return __a & (vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vand(vector unsigned short a, vector unsigned short b)
+vec_vand(vector unsigned short __a, vector unsigned short __b)
{
- return a & b;
+ return __a & __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vand(vector bool short a, vector unsigned short b)
+vec_vand(vector bool short __a, vector unsigned short __b)
{
- return (vector unsigned short)a & b;
+ return (vector unsigned short)__a & __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vand(vector unsigned short a, vector bool short b)
+vec_vand(vector unsigned short __a, vector bool short __b)
{
- return a & (vector unsigned short)b;
+ return __a & (vector unsigned short)__b;
}
static vector bool short __ATTRS_o_ai
-vec_vand(vector bool short a, vector bool short b)
+vec_vand(vector bool short __a, vector bool short __b)
{
- return a & b;
+ return __a & __b;
}
static vector int __ATTRS_o_ai
-vec_vand(vector int a, vector int b)
+vec_vand(vector int __a, vector int __b)
{
- return a & b;
+ return __a & __b;
}
static vector int __ATTRS_o_ai
-vec_vand(vector bool int a, vector int b)
+vec_vand(vector bool int __a, vector int __b)
{
- return (vector int)a & b;
+ return (vector int)__a & __b;
}
static vector int __ATTRS_o_ai
-vec_vand(vector int a, vector bool int b)
+vec_vand(vector int __a, vector bool int __b)
{
- return a & (vector int)b;
+ return __a & (vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vand(vector unsigned int a, vector unsigned int b)
+vec_vand(vector unsigned int __a, vector unsigned int __b)
{
- return a & b;
+ return __a & __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vand(vector bool int a, vector unsigned int b)
+vec_vand(vector bool int __a, vector unsigned int __b)
{
- return (vector unsigned int)a & b;
+ return (vector unsigned int)__a & __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vand(vector unsigned int a, vector bool int b)
+vec_vand(vector unsigned int __a, vector bool int __b)
{
- return a & (vector unsigned int)b;
+ return __a & (vector unsigned int)__b;
}
static vector bool int __ATTRS_o_ai
-vec_vand(vector bool int a, vector bool int b)
+vec_vand(vector bool int __a, vector bool int __b)
{
- return a & b;
+ return __a & __b;
}
static vector float __ATTRS_o_ai
-vec_vand(vector float a, vector float b)
+vec_vand(vector float __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a & (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a & (vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_vand(vector bool int a, vector float b)
+vec_vand(vector bool int __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a & (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a & (vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_vand(vector float a, vector bool int b)
+vec_vand(vector float __a, vector bool int __b)
{
- vector unsigned int res = (vector unsigned int)a & (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a & (vector unsigned int)__b;
+ return (vector float)__res;
}
/* vec_andc */
@@ -929,703 +929,703 @@ vec_vand(vector float a, vector bool int b)
#define __builtin_altivec_vandc vec_andc
static vector signed char __ATTRS_o_ai
-vec_andc(vector signed char a, vector signed char b)
+vec_andc(vector signed char __a, vector signed char __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector signed char __ATTRS_o_ai
-vec_andc(vector bool char a, vector signed char b)
+vec_andc(vector bool char __a, vector signed char __b)
{
- return (vector signed char)a & ~b;
+ return (vector signed char)__a & ~__b;
}
static vector signed char __ATTRS_o_ai
-vec_andc(vector signed char a, vector bool char b)
+vec_andc(vector signed char __a, vector bool char __b)
{
- return a & ~(vector signed char)b;
+ return __a & ~(vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_andc(vector unsigned char a, vector unsigned char b)
+vec_andc(vector unsigned char __a, vector unsigned char __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_andc(vector bool char a, vector unsigned char b)
+vec_andc(vector bool char __a, vector unsigned char __b)
{
- return (vector unsigned char)a & ~b;
+ return (vector unsigned char)__a & ~__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_andc(vector unsigned char a, vector bool char b)
+vec_andc(vector unsigned char __a, vector bool char __b)
{
- return a & ~(vector unsigned char)b;
+ return __a & ~(vector unsigned char)__b;
}
static vector bool char __ATTRS_o_ai
-vec_andc(vector bool char a, vector bool char b)
+vec_andc(vector bool char __a, vector bool char __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector short __ATTRS_o_ai
-vec_andc(vector short a, vector short b)
+vec_andc(vector short __a, vector short __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector short __ATTRS_o_ai
-vec_andc(vector bool short a, vector short b)
+vec_andc(vector bool short __a, vector short __b)
{
- return (vector short)a & ~b;
+ return (vector short)__a & ~__b;
}
static vector short __ATTRS_o_ai
-vec_andc(vector short a, vector bool short b)
+vec_andc(vector short __a, vector bool short __b)
{
- return a & ~(vector short)b;
+ return __a & ~(vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_andc(vector unsigned short a, vector unsigned short b)
+vec_andc(vector unsigned short __a, vector unsigned short __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_andc(vector bool short a, vector unsigned short b)
+vec_andc(vector bool short __a, vector unsigned short __b)
{
- return (vector unsigned short)a & ~b;
+ return (vector unsigned short)__a & ~__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_andc(vector unsigned short a, vector bool short b)
+vec_andc(vector unsigned short __a, vector bool short __b)
{
- return a & ~(vector unsigned short)b;
+ return __a & ~(vector unsigned short)__b;
}
static vector bool short __ATTRS_o_ai
-vec_andc(vector bool short a, vector bool short b)
+vec_andc(vector bool short __a, vector bool short __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector int __ATTRS_o_ai
-vec_andc(vector int a, vector int b)
+vec_andc(vector int __a, vector int __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector int __ATTRS_o_ai
-vec_andc(vector bool int a, vector int b)
+vec_andc(vector bool int __a, vector int __b)
{
- return (vector int)a & ~b;
+ return (vector int)__a & ~__b;
}
static vector int __ATTRS_o_ai
-vec_andc(vector int a, vector bool int b)
+vec_andc(vector int __a, vector bool int __b)
{
- return a & ~(vector int)b;
+ return __a & ~(vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_andc(vector unsigned int a, vector unsigned int b)
+vec_andc(vector unsigned int __a, vector unsigned int __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_andc(vector bool int a, vector unsigned int b)
+vec_andc(vector bool int __a, vector unsigned int __b)
{
- return (vector unsigned int)a & ~b;
+ return (vector unsigned int)__a & ~__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_andc(vector unsigned int a, vector bool int b)
+vec_andc(vector unsigned int __a, vector bool int __b)
{
- return a & ~(vector unsigned int)b;
+ return __a & ~(vector unsigned int)__b;
}
static vector bool int __ATTRS_o_ai
-vec_andc(vector bool int a, vector bool int b)
+vec_andc(vector bool int __a, vector bool int __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector float __ATTRS_o_ai
-vec_andc(vector float a, vector float b)
+vec_andc(vector float __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a & ~(vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a & ~(vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_andc(vector bool int a, vector float b)
+vec_andc(vector bool int __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a & ~(vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a & ~(vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_andc(vector float a, vector bool int b)
+vec_andc(vector float __a, vector bool int __b)
{
- vector unsigned int res = (vector unsigned int)a & ~(vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a & ~(vector unsigned int)__b;
+ return (vector float)__res;
}
/* vec_vandc */
static vector signed char __ATTRS_o_ai
-vec_vandc(vector signed char a, vector signed char b)
+vec_vandc(vector signed char __a, vector signed char __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector signed char __ATTRS_o_ai
-vec_vandc(vector bool char a, vector signed char b)
+vec_vandc(vector bool char __a, vector signed char __b)
{
- return (vector signed char)a & ~b;
+ return (vector signed char)__a & ~__b;
}
static vector signed char __ATTRS_o_ai
-vec_vandc(vector signed char a, vector bool char b)
+vec_vandc(vector signed char __a, vector bool char __b)
{
- return a & ~(vector signed char)b;
+ return __a & ~(vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vandc(vector unsigned char a, vector unsigned char b)
+vec_vandc(vector unsigned char __a, vector unsigned char __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vandc(vector bool char a, vector unsigned char b)
+vec_vandc(vector bool char __a, vector unsigned char __b)
{
- return (vector unsigned char)a & ~b;
+ return (vector unsigned char)__a & ~__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vandc(vector unsigned char a, vector bool char b)
+vec_vandc(vector unsigned char __a, vector bool char __b)
{
- return a & ~(vector unsigned char)b;
+ return __a & ~(vector unsigned char)__b;
}
static vector bool char __ATTRS_o_ai
-vec_vandc(vector bool char a, vector bool char b)
+vec_vandc(vector bool char __a, vector bool char __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector short __ATTRS_o_ai
-vec_vandc(vector short a, vector short b)
+vec_vandc(vector short __a, vector short __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector short __ATTRS_o_ai
-vec_vandc(vector bool short a, vector short b)
+vec_vandc(vector bool short __a, vector short __b)
{
- return (vector short)a & ~b;
+ return (vector short)__a & ~__b;
}
static vector short __ATTRS_o_ai
-vec_vandc(vector short a, vector bool short b)
+vec_vandc(vector short __a, vector bool short __b)
{
- return a & ~(vector short)b;
+ return __a & ~(vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vandc(vector unsigned short a, vector unsigned short b)
+vec_vandc(vector unsigned short __a, vector unsigned short __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vandc(vector bool short a, vector unsigned short b)
+vec_vandc(vector bool short __a, vector unsigned short __b)
{
- return (vector unsigned short)a & ~b;
+ return (vector unsigned short)__a & ~__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vandc(vector unsigned short a, vector bool short b)
+vec_vandc(vector unsigned short __a, vector bool short __b)
{
- return a & ~(vector unsigned short)b;
+ return __a & ~(vector unsigned short)__b;
}
static vector bool short __ATTRS_o_ai
-vec_vandc(vector bool short a, vector bool short b)
+vec_vandc(vector bool short __a, vector bool short __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector int __ATTRS_o_ai
-vec_vandc(vector int a, vector int b)
+vec_vandc(vector int __a, vector int __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector int __ATTRS_o_ai
-vec_vandc(vector bool int a, vector int b)
+vec_vandc(vector bool int __a, vector int __b)
{
- return (vector int)a & ~b;
+ return (vector int)__a & ~__b;
}
static vector int __ATTRS_o_ai
-vec_vandc(vector int a, vector bool int b)
+vec_vandc(vector int __a, vector bool int __b)
{
- return a & ~(vector int)b;
+ return __a & ~(vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vandc(vector unsigned int a, vector unsigned int b)
+vec_vandc(vector unsigned int __a, vector unsigned int __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vandc(vector bool int a, vector unsigned int b)
+vec_vandc(vector bool int __a, vector unsigned int __b)
{
- return (vector unsigned int)a & ~b;
+ return (vector unsigned int)__a & ~__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vandc(vector unsigned int a, vector bool int b)
+vec_vandc(vector unsigned int __a, vector bool int __b)
{
- return a & ~(vector unsigned int)b;
+ return __a & ~(vector unsigned int)__b;
}
static vector bool int __ATTRS_o_ai
-vec_vandc(vector bool int a, vector bool int b)
+vec_vandc(vector bool int __a, vector bool int __b)
{
- return a & ~b;
+ return __a & ~__b;
}
static vector float __ATTRS_o_ai
-vec_vandc(vector float a, vector float b)
+vec_vandc(vector float __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a & ~(vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a & ~(vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_vandc(vector bool int a, vector float b)
+vec_vandc(vector bool int __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a & ~(vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a & ~(vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_vandc(vector float a, vector bool int b)
+vec_vandc(vector float __a, vector bool int __b)
{
- vector unsigned int res = (vector unsigned int)a & ~(vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a & ~(vector unsigned int)__b;
+ return (vector float)__res;
}
/* vec_avg */
static vector signed char __ATTRS_o_ai
-vec_avg(vector signed char a, vector signed char b)
+vec_avg(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vavgsb(a, b);
+ return __builtin_altivec_vavgsb(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_avg(vector unsigned char a, vector unsigned char b)
+vec_avg(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vavgub(a, b);
+ return __builtin_altivec_vavgub(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_avg(vector short a, vector short b)
+vec_avg(vector short __a, vector short __b)
{
- return __builtin_altivec_vavgsh(a, b);
+ return __builtin_altivec_vavgsh(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_avg(vector unsigned short a, vector unsigned short b)
+vec_avg(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vavguh(a, b);
+ return __builtin_altivec_vavguh(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_avg(vector int a, vector int b)
+vec_avg(vector int __a, vector int __b)
{
- return __builtin_altivec_vavgsw(a, b);
+ return __builtin_altivec_vavgsw(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_avg(vector unsigned int a, vector unsigned int b)
+vec_avg(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vavguw(a, b);
+ return __builtin_altivec_vavguw(__a, __b);
}
/* vec_vavgsb */
static vector signed char __attribute__((__always_inline__))
-vec_vavgsb(vector signed char a, vector signed char b)
+vec_vavgsb(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vavgsb(a, b);
+ return __builtin_altivec_vavgsb(__a, __b);
}
/* vec_vavgub */
static vector unsigned char __attribute__((__always_inline__))
-vec_vavgub(vector unsigned char a, vector unsigned char b)
+vec_vavgub(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vavgub(a, b);
+ return __builtin_altivec_vavgub(__a, __b);
}
/* vec_vavgsh */
static vector short __attribute__((__always_inline__))
-vec_vavgsh(vector short a, vector short b)
+vec_vavgsh(vector short __a, vector short __b)
{
- return __builtin_altivec_vavgsh(a, b);
+ return __builtin_altivec_vavgsh(__a, __b);
}
/* vec_vavguh */
static vector unsigned short __attribute__((__always_inline__))
-vec_vavguh(vector unsigned short a, vector unsigned short b)
+vec_vavguh(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vavguh(a, b);
+ return __builtin_altivec_vavguh(__a, __b);
}
/* vec_vavgsw */
static vector int __attribute__((__always_inline__))
-vec_vavgsw(vector int a, vector int b)
+vec_vavgsw(vector int __a, vector int __b)
{
- return __builtin_altivec_vavgsw(a, b);
+ return __builtin_altivec_vavgsw(__a, __b);
}
/* vec_vavguw */
static vector unsigned int __attribute__((__always_inline__))
-vec_vavguw(vector unsigned int a, vector unsigned int b)
+vec_vavguw(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vavguw(a, b);
+ return __builtin_altivec_vavguw(__a, __b);
}
/* vec_ceil */
static vector float __attribute__((__always_inline__))
-vec_ceil(vector float a)
+vec_ceil(vector float __a)
{
- return __builtin_altivec_vrfip(a);
+ return __builtin_altivec_vrfip(__a);
}
/* vec_vrfip */
static vector float __attribute__((__always_inline__))
-vec_vrfip(vector float a)
+vec_vrfip(vector float __a)
{
- return __builtin_altivec_vrfip(a);
+ return __builtin_altivec_vrfip(__a);
}
/* vec_cmpb */
static vector int __attribute__((__always_inline__))
-vec_cmpb(vector float a, vector float b)
+vec_cmpb(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpbfp(a, b);
+ return __builtin_altivec_vcmpbfp(__a, __b);
}
/* vec_vcmpbfp */
static vector int __attribute__((__always_inline__))
-vec_vcmpbfp(vector float a, vector float b)
+vec_vcmpbfp(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpbfp(a, b);
+ return __builtin_altivec_vcmpbfp(__a, __b);
}
/* vec_cmpeq */
static vector bool char __ATTRS_o_ai
-vec_cmpeq(vector signed char a, vector signed char b)
+vec_cmpeq(vector signed char __a, vector signed char __b)
{
return (vector bool char)
- __builtin_altivec_vcmpequb((vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb((vector char)__a, (vector char)__b);
}
static vector bool char __ATTRS_o_ai
-vec_cmpeq(vector unsigned char a, vector unsigned char b)
+vec_cmpeq(vector unsigned char __a, vector unsigned char __b)
{
return (vector bool char)
- __builtin_altivec_vcmpequb((vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb((vector char)__a, (vector char)__b);
}
static vector bool short __ATTRS_o_ai
-vec_cmpeq(vector short a, vector short b)
+vec_cmpeq(vector short __a, vector short __b)
{
- return (vector bool short)__builtin_altivec_vcmpequh(a, b);
+ return (vector bool short)__builtin_altivec_vcmpequh(__a, __b);
}
static vector bool short __ATTRS_o_ai
-vec_cmpeq(vector unsigned short a, vector unsigned short b)
+vec_cmpeq(vector unsigned short __a, vector unsigned short __b)
{
return (vector bool short)
- __builtin_altivec_vcmpequh((vector short)a, (vector short)b);
+ __builtin_altivec_vcmpequh((vector short)__a, (vector short)__b);
}
static vector bool int __ATTRS_o_ai
-vec_cmpeq(vector int a, vector int b)
+vec_cmpeq(vector int __a, vector int __b)
{
- return (vector bool int)__builtin_altivec_vcmpequw(a, b);
+ return (vector bool int)__builtin_altivec_vcmpequw(__a, __b);
}
static vector bool int __ATTRS_o_ai
-vec_cmpeq(vector unsigned int a, vector unsigned int b)
+vec_cmpeq(vector unsigned int __a, vector unsigned int __b)
{
return (vector bool int)
- __builtin_altivec_vcmpequw((vector int)a, (vector int)b);
+ __builtin_altivec_vcmpequw((vector int)__a, (vector int)__b);
}
static vector bool int __ATTRS_o_ai
-vec_cmpeq(vector float a, vector float b)
+vec_cmpeq(vector float __a, vector float __b)
{
- return (vector bool int)__builtin_altivec_vcmpeqfp(a, b);
+ return (vector bool int)__builtin_altivec_vcmpeqfp(__a, __b);
}
/* vec_cmpge */
static vector bool int __attribute__((__always_inline__))
-vec_cmpge(vector float a, vector float b)
+vec_cmpge(vector float __a, vector float __b)
{
- return (vector bool int)__builtin_altivec_vcmpgefp(a, b);
+ return (vector bool int)__builtin_altivec_vcmpgefp(__a, __b);
}
/* vec_vcmpgefp */
static vector bool int __attribute__((__always_inline__))
-vec_vcmpgefp(vector float a, vector float b)
+vec_vcmpgefp(vector float __a, vector float __b)
{
- return (vector bool int)__builtin_altivec_vcmpgefp(a, b);
+ return (vector bool int)__builtin_altivec_vcmpgefp(__a, __b);
}
/* vec_cmpgt */
static vector bool char __ATTRS_o_ai
-vec_cmpgt(vector signed char a, vector signed char b)
+vec_cmpgt(vector signed char __a, vector signed char __b)
{
- return (vector bool char)__builtin_altivec_vcmpgtsb(a, b);
+ return (vector bool char)__builtin_altivec_vcmpgtsb(__a, __b);
}
static vector bool char __ATTRS_o_ai
-vec_cmpgt(vector unsigned char a, vector unsigned char b)
+vec_cmpgt(vector unsigned char __a, vector unsigned char __b)
{
- return (vector bool char)__builtin_altivec_vcmpgtub(a, b);
+ return (vector bool char)__builtin_altivec_vcmpgtub(__a, __b);
}
static vector bool short __ATTRS_o_ai
-vec_cmpgt(vector short a, vector short b)
+vec_cmpgt(vector short __a, vector short __b)
{
- return (vector bool short)__builtin_altivec_vcmpgtsh(a, b);
+ return (vector bool short)__builtin_altivec_vcmpgtsh(__a, __b);
}
static vector bool short __ATTRS_o_ai
-vec_cmpgt(vector unsigned short a, vector unsigned short b)
+vec_cmpgt(vector unsigned short __a, vector unsigned short __b)
{
- return (vector bool short)__builtin_altivec_vcmpgtuh(a, b);
+ return (vector bool short)__builtin_altivec_vcmpgtuh(__a, __b);
}
static vector bool int __ATTRS_o_ai
-vec_cmpgt(vector int a, vector int b)
+vec_cmpgt(vector int __a, vector int __b)
{
- return (vector bool int)__builtin_altivec_vcmpgtsw(a, b);
+ return (vector bool int)__builtin_altivec_vcmpgtsw(__a, __b);
}
static vector bool int __ATTRS_o_ai
-vec_cmpgt(vector unsigned int a, vector unsigned int b)
+vec_cmpgt(vector unsigned int __a, vector unsigned int __b)
{
- return (vector bool int)__builtin_altivec_vcmpgtuw(a, b);
+ return (vector bool int)__builtin_altivec_vcmpgtuw(__a, __b);
}
static vector bool int __ATTRS_o_ai
-vec_cmpgt(vector float a, vector float b)
+vec_cmpgt(vector float __a, vector float __b)
{
- return (vector bool int)__builtin_altivec_vcmpgtfp(a, b);
+ return (vector bool int)__builtin_altivec_vcmpgtfp(__a, __b);
}
/* vec_vcmpgtsb */
static vector bool char __attribute__((__always_inline__))
-vec_vcmpgtsb(vector signed char a, vector signed char b)
+vec_vcmpgtsb(vector signed char __a, vector signed char __b)
{
- return (vector bool char)__builtin_altivec_vcmpgtsb(a, b);
+ return (vector bool char)__builtin_altivec_vcmpgtsb(__a, __b);
}
/* vec_vcmpgtub */
static vector bool char __attribute__((__always_inline__))
-vec_vcmpgtub(vector unsigned char a, vector unsigned char b)
+vec_vcmpgtub(vector unsigned char __a, vector unsigned char __b)
{
- return (vector bool char)__builtin_altivec_vcmpgtub(a, b);
+ return (vector bool char)__builtin_altivec_vcmpgtub(__a, __b);
}
/* vec_vcmpgtsh */
static vector bool short __attribute__((__always_inline__))
-vec_vcmpgtsh(vector short a, vector short b)
+vec_vcmpgtsh(vector short __a, vector short __b)
{
- return (vector bool short)__builtin_altivec_vcmpgtsh(a, b);
+ return (vector bool short)__builtin_altivec_vcmpgtsh(__a, __b);
}
/* vec_vcmpgtuh */
static vector bool short __attribute__((__always_inline__))
-vec_vcmpgtuh(vector unsigned short a, vector unsigned short b)
+vec_vcmpgtuh(vector unsigned short __a, vector unsigned short __b)
{
- return (vector bool short)__builtin_altivec_vcmpgtuh(a, b);
+ return (vector bool short)__builtin_altivec_vcmpgtuh(__a, __b);
}
/* vec_vcmpgtsw */
static vector bool int __attribute__((__always_inline__))
-vec_vcmpgtsw(vector int a, vector int b)
+vec_vcmpgtsw(vector int __a, vector int __b)
{
- return (vector bool int)__builtin_altivec_vcmpgtsw(a, b);
+ return (vector bool int)__builtin_altivec_vcmpgtsw(__a, __b);
}
/* vec_vcmpgtuw */
static vector bool int __attribute__((__always_inline__))
-vec_vcmpgtuw(vector unsigned int a, vector unsigned int b)
+vec_vcmpgtuw(vector unsigned int __a, vector unsigned int __b)
{
- return (vector bool int)__builtin_altivec_vcmpgtuw(a, b);
+ return (vector bool int)__builtin_altivec_vcmpgtuw(__a, __b);
}
/* vec_vcmpgtfp */
static vector bool int __attribute__((__always_inline__))
-vec_vcmpgtfp(vector float a, vector float b)
+vec_vcmpgtfp(vector float __a, vector float __b)
{
- return (vector bool int)__builtin_altivec_vcmpgtfp(a, b);
+ return (vector bool int)__builtin_altivec_vcmpgtfp(__a, __b);
}
/* vec_cmple */
static vector bool int __attribute__((__always_inline__))
-vec_cmple(vector float a, vector float b)
+vec_cmple(vector float __a, vector float __b)
{
- return (vector bool int)__builtin_altivec_vcmpgefp(b, a);
+ return (vector bool int)__builtin_altivec_vcmpgefp(__b, __a);
}
/* vec_cmplt */
static vector bool char __ATTRS_o_ai
-vec_cmplt(vector signed char a, vector signed char b)
+vec_cmplt(vector signed char __a, vector signed char __b)
{
- return (vector bool char)__builtin_altivec_vcmpgtsb(b, a);
+ return (vector bool char)__builtin_altivec_vcmpgtsb(__b, __a);
}
static vector bool char __ATTRS_o_ai
-vec_cmplt(vector unsigned char a, vector unsigned char b)
+vec_cmplt(vector unsigned char __a, vector unsigned char __b)
{
- return (vector bool char)__builtin_altivec_vcmpgtub(b, a);
+ return (vector bool char)__builtin_altivec_vcmpgtub(__b, __a);
}
static vector bool short __ATTRS_o_ai
-vec_cmplt(vector short a, vector short b)
+vec_cmplt(vector short __a, vector short __b)
{
- return (vector bool short)__builtin_altivec_vcmpgtsh(b, a);
+ return (vector bool short)__builtin_altivec_vcmpgtsh(__b, __a);
}
static vector bool short __ATTRS_o_ai
-vec_cmplt(vector unsigned short a, vector unsigned short b)
+vec_cmplt(vector unsigned short __a, vector unsigned short __b)
{
- return (vector bool short)__builtin_altivec_vcmpgtuh(b, a);
+ return (vector bool short)__builtin_altivec_vcmpgtuh(__b, __a);
}
static vector bool int __ATTRS_o_ai
-vec_cmplt(vector int a, vector int b)
+vec_cmplt(vector int __a, vector int __b)
{
- return (vector bool int)__builtin_altivec_vcmpgtsw(b, a);
+ return (vector bool int)__builtin_altivec_vcmpgtsw(__b, __a);
}
static vector bool int __ATTRS_o_ai
-vec_cmplt(vector unsigned int a, vector unsigned int b)
+vec_cmplt(vector unsigned int __a, vector unsigned int __b)
{
- return (vector bool int)__builtin_altivec_vcmpgtuw(b, a);
+ return (vector bool int)__builtin_altivec_vcmpgtuw(__b, __a);
}
static vector bool int __ATTRS_o_ai
-vec_cmplt(vector float a, vector float b)
+vec_cmplt(vector float __a, vector float __b)
{
- return (vector bool int)__builtin_altivec_vcmpgtfp(b, a);
+ return (vector bool int)__builtin_altivec_vcmpgtfp(__b, __a);
}
/* vec_ctf */
static vector float __ATTRS_o_ai
-vec_ctf(vector int a, int b)
+vec_ctf(vector int __a, int __b)
{
- return __builtin_altivec_vcfsx(a, b);
+ return __builtin_altivec_vcfsx(__a, __b);
}
static vector float __ATTRS_o_ai
-vec_ctf(vector unsigned int a, int b)
+vec_ctf(vector unsigned int __a, int __b)
{
- return __builtin_altivec_vcfux((vector int)a, b);
+ return __builtin_altivec_vcfux((vector int)__a, __b);
}
/* vec_vcfsx */
static vector float __attribute__((__always_inline__))
-vec_vcfsx(vector int a, int b)
+vec_vcfsx(vector int __a, int __b)
{
- return __builtin_altivec_vcfsx(a, b);
+ return __builtin_altivec_vcfsx(__a, __b);
}
/* vec_vcfux */
static vector float __attribute__((__always_inline__))
-vec_vcfux(vector unsigned int a, int b)
+vec_vcfux(vector unsigned int __a, int __b)
{
- return __builtin_altivec_vcfux((vector int)a, b);
+ return __builtin_altivec_vcfux((vector int)__a, __b);
}
/* vec_cts */
static vector int __attribute__((__always_inline__))
-vec_cts(vector float a, int b)
+vec_cts(vector float __a, int __b)
{
- return __builtin_altivec_vctsxs(a, b);
+ return __builtin_altivec_vctsxs(__a, __b);
}
/* vec_vctsxs */
static vector int __attribute__((__always_inline__))
-vec_vctsxs(vector float a, int b)
+vec_vctsxs(vector float __a, int __b)
{
- return __builtin_altivec_vctsxs(a, b);
+ return __builtin_altivec_vctsxs(__a, __b);
}
/* vec_ctu */
static vector unsigned int __attribute__((__always_inline__))
-vec_ctu(vector float a, int b)
+vec_ctu(vector float __a, int __b)
{
- return __builtin_altivec_vctuxs(a, b);
+ return __builtin_altivec_vctuxs(__a, __b);
}
/* vec_vctuxs */
static vector unsigned int __attribute__((__always_inline__))
-vec_vctuxs(vector float a, int b)
+vec_vctuxs(vector float __a, int __b)
{
- return __builtin_altivec_vctuxs(a, b);
+ return __builtin_altivec_vctuxs(__a, __b);
}
/* vec_dss */
static void __attribute__((__always_inline__))
-vec_dss(int a)
+vec_dss(int __a)
{
- __builtin_altivec_dss(a);
+ __builtin_altivec_dss(__a);
}
/* vec_dssall */
@@ -1639,1066 +1639,1066 @@ vec_dssall(void)
/* vec_dst */
static void __attribute__((__always_inline__))
-vec_dst(const void *a, int b, int c)
+vec_dst(const void *__a, int __b, int __c)
{
- __builtin_altivec_dst(a, b, c);
+ __builtin_altivec_dst(__a, __b, __c);
}
/* vec_dstst */
static void __attribute__((__always_inline__))
-vec_dstst(const void *a, int b, int c)
+vec_dstst(const void *__a, int __b, int __c)
{
- __builtin_altivec_dstst(a, b, c);
+ __builtin_altivec_dstst(__a, __b, __c);
}
/* vec_dststt */
static void __attribute__((__always_inline__))
-vec_dststt(const void *a, int b, int c)
+vec_dststt(const void *__a, int __b, int __c)
{
- __builtin_altivec_dststt(a, b, c);
+ __builtin_altivec_dststt(__a, __b, __c);
}
/* vec_dstt */
static void __attribute__((__always_inline__))
-vec_dstt(const void *a, int b, int c)
+vec_dstt(const void *__a, int __b, int __c)
{
- __builtin_altivec_dstt(a, b, c);
+ __builtin_altivec_dstt(__a, __b, __c);
}
/* vec_expte */
static vector float __attribute__((__always_inline__))
-vec_expte(vector float a)
+vec_expte(vector float __a)
{
- return __builtin_altivec_vexptefp(a);
+ return __builtin_altivec_vexptefp(__a);
}
/* vec_vexptefp */
static vector float __attribute__((__always_inline__))
-vec_vexptefp(vector float a)
+vec_vexptefp(vector float __a)
{
- return __builtin_altivec_vexptefp(a);
+ return __builtin_altivec_vexptefp(__a);
}
/* vec_floor */
static vector float __attribute__((__always_inline__))
-vec_floor(vector float a)
+vec_floor(vector float __a)
{
- return __builtin_altivec_vrfim(a);
+ return __builtin_altivec_vrfim(__a);
}
/* vec_vrfim */
static vector float __attribute__((__always_inline__))
-vec_vrfim(vector float a)
+vec_vrfim(vector float __a)
{
- return __builtin_altivec_vrfim(a);
+ return __builtin_altivec_vrfim(__a);
}
/* vec_ld */
static vector signed char __ATTRS_o_ai
-vec_ld(int a, const vector signed char *b)
+vec_ld(int __a, const vector signed char *__b)
{
- return (vector signed char)__builtin_altivec_lvx(a, b);
+ return (vector signed char)__builtin_altivec_lvx(__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_ld(int a, const signed char *b)
+vec_ld(int __a, const signed char *__b)
{
- return (vector signed char)__builtin_altivec_lvx(a, b);
+ return (vector signed char)__builtin_altivec_lvx(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_ld(int a, const vector unsigned char *b)
+vec_ld(int __a, const vector unsigned char *__b)
{
- return (vector unsigned char)__builtin_altivec_lvx(a, b);
+ return (vector unsigned char)__builtin_altivec_lvx(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_ld(int a, const unsigned char *b)
+vec_ld(int __a, const unsigned char *__b)
{
- return (vector unsigned char)__builtin_altivec_lvx(a, b);
+ return (vector unsigned char)__builtin_altivec_lvx(__a, __b);
}
static vector bool char __ATTRS_o_ai
-vec_ld(int a, const vector bool char *b)
+vec_ld(int __a, const vector bool char *__b)
{
- return (vector bool char)__builtin_altivec_lvx(a, b);
+ return (vector bool char)__builtin_altivec_lvx(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_ld(int a, const vector short *b)
+vec_ld(int __a, const vector short *__b)
{
- return (vector short)__builtin_altivec_lvx(a, b);
+ return (vector short)__builtin_altivec_lvx(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_ld(int a, const short *b)
+vec_ld(int __a, const short *__b)
{
- return (vector short)__builtin_altivec_lvx(a, b);
+ return (vector short)__builtin_altivec_lvx(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_ld(int a, const vector unsigned short *b)
+vec_ld(int __a, const vector unsigned short *__b)
{
- return (vector unsigned short)__builtin_altivec_lvx(a, b);
+ return (vector unsigned short)__builtin_altivec_lvx(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_ld(int a, const unsigned short *b)
+vec_ld(int __a, const unsigned short *__b)
{
- return (vector unsigned short)__builtin_altivec_lvx(a, b);
+ return (vector unsigned short)__builtin_altivec_lvx(__a, __b);
}
static vector bool short __ATTRS_o_ai
-vec_ld(int a, const vector bool short *b)
+vec_ld(int __a, const vector bool short *__b)
{
- return (vector bool short)__builtin_altivec_lvx(a, b);
+ return (vector bool short)__builtin_altivec_lvx(__a, __b);
}
static vector pixel __ATTRS_o_ai
-vec_ld(int a, const vector pixel *b)
+vec_ld(int __a, const vector pixel *__b)
{
- return (vector pixel)__builtin_altivec_lvx(a, b);
+ return (vector pixel)__builtin_altivec_lvx(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_ld(int a, const vector int *b)
+vec_ld(int __a, const vector int *__b)
{
- return (vector int)__builtin_altivec_lvx(a, b);
+ return (vector int)__builtin_altivec_lvx(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_ld(int a, const int *b)
+vec_ld(int __a, const int *__b)
{
- return (vector int)__builtin_altivec_lvx(a, b);
+ return (vector int)__builtin_altivec_lvx(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_ld(int a, const vector unsigned int *b)
+vec_ld(int __a, const vector unsigned int *__b)
{
- return (vector unsigned int)__builtin_altivec_lvx(a, b);
+ return (vector unsigned int)__builtin_altivec_lvx(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_ld(int a, const unsigned int *b)
+vec_ld(int __a, const unsigned int *__b)
{
- return (vector unsigned int)__builtin_altivec_lvx(a, b);
+ return (vector unsigned int)__builtin_altivec_lvx(__a, __b);
}
static vector bool int __ATTRS_o_ai
-vec_ld(int a, const vector bool int *b)
+vec_ld(int __a, const vector bool int *__b)
{
- return (vector bool int)__builtin_altivec_lvx(a, b);
+ return (vector bool int)__builtin_altivec_lvx(__a, __b);
}
static vector float __ATTRS_o_ai
-vec_ld(int a, const vector float *b)
+vec_ld(int __a, const vector float *__b)
{
- return (vector float)__builtin_altivec_lvx(a, b);
+ return (vector float)__builtin_altivec_lvx(__a, __b);
}
static vector float __ATTRS_o_ai
-vec_ld(int a, const float *b)
+vec_ld(int __a, const float *__b)
{
- return (vector float)__builtin_altivec_lvx(a, b);
+ return (vector float)__builtin_altivec_lvx(__a, __b);
}
/* vec_lvx */
static vector signed char __ATTRS_o_ai
-vec_lvx(int a, const vector signed char *b)
+vec_lvx(int __a, const vector signed char *__b)
{
- return (vector signed char)__builtin_altivec_lvx(a, b);
+ return (vector signed char)__builtin_altivec_lvx(__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_lvx(int a, const signed char *b)
+vec_lvx(int __a, const signed char *__b)
{
- return (vector signed char)__builtin_altivec_lvx(a, b);
+ return (vector signed char)__builtin_altivec_lvx(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvx(int a, const vector unsigned char *b)
+vec_lvx(int __a, const vector unsigned char *__b)
{
- return (vector unsigned char)__builtin_altivec_lvx(a, b);
+ return (vector unsigned char)__builtin_altivec_lvx(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvx(int a, const unsigned char *b)
+vec_lvx(int __a, const unsigned char *__b)
{
- return (vector unsigned char)__builtin_altivec_lvx(a, b);
+ return (vector unsigned char)__builtin_altivec_lvx(__a, __b);
}
static vector bool char __ATTRS_o_ai
-vec_lvx(int a, const vector bool char *b)
+vec_lvx(int __a, const vector bool char *__b)
{
- return (vector bool char)__builtin_altivec_lvx(a, b);
+ return (vector bool char)__builtin_altivec_lvx(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_lvx(int a, const vector short *b)
+vec_lvx(int __a, const vector short *__b)
{
- return (vector short)__builtin_altivec_lvx(a, b);
+ return (vector short)__builtin_altivec_lvx(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_lvx(int a, const short *b)
+vec_lvx(int __a, const short *__b)
{
- return (vector short)__builtin_altivec_lvx(a, b);
+ return (vector short)__builtin_altivec_lvx(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_lvx(int a, const vector unsigned short *b)
+vec_lvx(int __a, const vector unsigned short *__b)
{
- return (vector unsigned short)__builtin_altivec_lvx(a, b);
+ return (vector unsigned short)__builtin_altivec_lvx(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_lvx(int a, const unsigned short *b)
+vec_lvx(int __a, const unsigned short *__b)
{
- return (vector unsigned short)__builtin_altivec_lvx(a, b);
+ return (vector unsigned short)__builtin_altivec_lvx(__a, __b);
}
static vector bool short __ATTRS_o_ai
-vec_lvx(int a, const vector bool short *b)
+vec_lvx(int __a, const vector bool short *__b)
{
- return (vector bool short)__builtin_altivec_lvx(a, b);
+ return (vector bool short)__builtin_altivec_lvx(__a, __b);
}
static vector pixel __ATTRS_o_ai
-vec_lvx(int a, const vector pixel *b)
+vec_lvx(int __a, const vector pixel *__b)
{
- return (vector pixel)__builtin_altivec_lvx(a, b);
+ return (vector pixel)__builtin_altivec_lvx(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_lvx(int a, const vector int *b)
+vec_lvx(int __a, const vector int *__b)
{
- return (vector int)__builtin_altivec_lvx(a, b);
+ return (vector int)__builtin_altivec_lvx(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_lvx(int a, const int *b)
+vec_lvx(int __a, const int *__b)
{
- return (vector int)__builtin_altivec_lvx(a, b);
+ return (vector int)__builtin_altivec_lvx(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_lvx(int a, const vector unsigned int *b)
+vec_lvx(int __a, const vector unsigned int *__b)
{
- return (vector unsigned int)__builtin_altivec_lvx(a, b);
+ return (vector unsigned int)__builtin_altivec_lvx(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_lvx(int a, const unsigned int *b)
+vec_lvx(int __a, const unsigned int *__b)
{
- return (vector unsigned int)__builtin_altivec_lvx(a, b);
+ return (vector unsigned int)__builtin_altivec_lvx(__a, __b);
}
static vector bool int __ATTRS_o_ai
-vec_lvx(int a, const vector bool int *b)
+vec_lvx(int __a, const vector bool int *__b)
{
- return (vector bool int)__builtin_altivec_lvx(a, b);
+ return (vector bool int)__builtin_altivec_lvx(__a, __b);
}
static vector float __ATTRS_o_ai
-vec_lvx(int a, const vector float *b)
+vec_lvx(int __a, const vector float *__b)
{
- return (vector float)__builtin_altivec_lvx(a, b);
+ return (vector float)__builtin_altivec_lvx(__a, __b);
}
static vector float __ATTRS_o_ai
-vec_lvx(int a, const float *b)
+vec_lvx(int __a, const float *__b)
{
- return (vector float)__builtin_altivec_lvx(a, b);
+ return (vector float)__builtin_altivec_lvx(__a, __b);
}
/* vec_lde */
static vector signed char __ATTRS_o_ai
-vec_lde(int a, const vector signed char *b)
+vec_lde(int __a, const signed char *__b)
{
- return (vector signed char)__builtin_altivec_lvebx(a, b);
+ return (vector signed char)__builtin_altivec_lvebx(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lde(int a, const vector unsigned char *b)
+vec_lde(int __a, const unsigned char *__b)
{
- return (vector unsigned char)__builtin_altivec_lvebx(a, b);
+ return (vector unsigned char)__builtin_altivec_lvebx(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_lde(int a, const vector short *b)
+vec_lde(int __a, const short *__b)
{
- return (vector short)__builtin_altivec_lvehx(a, b);
+ return (vector short)__builtin_altivec_lvehx(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_lde(int a, const vector unsigned short *b)
+vec_lde(int __a, const unsigned short *__b)
{
- return (vector unsigned short)__builtin_altivec_lvehx(a, b);
+ return (vector unsigned short)__builtin_altivec_lvehx(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_lde(int a, const vector int *b)
+vec_lde(int __a, const int *__b)
{
- return (vector int)__builtin_altivec_lvewx(a, b);
+ return (vector int)__builtin_altivec_lvewx(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_lde(int a, const vector unsigned int *b)
+vec_lde(int __a, const unsigned int *__b)
{
- return (vector unsigned int)__builtin_altivec_lvewx(a, b);
+ return (vector unsigned int)__builtin_altivec_lvewx(__a, __b);
}
static vector float __ATTRS_o_ai
-vec_lde(int a, const vector float *b)
+vec_lde(int __a, const float *__b)
{
- return (vector float)__builtin_altivec_lvewx(a, b);
+ return (vector float)__builtin_altivec_lvewx(__a, __b);
}
/* vec_lvebx */
static vector signed char __ATTRS_o_ai
-vec_lvebx(int a, const vector signed char *b)
+vec_lvebx(int __a, const signed char *__b)
{
- return (vector signed char)__builtin_altivec_lvebx(a, b);
+ return (vector signed char)__builtin_altivec_lvebx(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvebx(int a, const vector unsigned char *b)
+vec_lvebx(int __a, const unsigned char *__b)
{
- return (vector unsigned char)__builtin_altivec_lvebx(a, b);
+ return (vector unsigned char)__builtin_altivec_lvebx(__a, __b);
}
/* vec_lvehx */
static vector short __ATTRS_o_ai
-vec_lvehx(int a, const vector short *b)
+vec_lvehx(int __a, const short *__b)
{
- return (vector short)__builtin_altivec_lvehx(a, b);
+ return (vector short)__builtin_altivec_lvehx(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_lvehx(int a, const vector unsigned short *b)
+vec_lvehx(int __a, const unsigned short *__b)
{
- return (vector unsigned short)__builtin_altivec_lvehx(a, b);
+ return (vector unsigned short)__builtin_altivec_lvehx(__a, __b);
}
/* vec_lvewx */
static vector int __ATTRS_o_ai
-vec_lvewx(int a, const vector int *b)
+vec_lvewx(int __a, const int *__b)
{
- return (vector int)__builtin_altivec_lvewx(a, b);
+ return (vector int)__builtin_altivec_lvewx(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_lvewx(int a, const vector unsigned int *b)
+vec_lvewx(int __a, const unsigned int *__b)
{
- return (vector unsigned int)__builtin_altivec_lvewx(a, b);
+ return (vector unsigned int)__builtin_altivec_lvewx(__a, __b);
}
static vector float __ATTRS_o_ai
-vec_lvewx(int a, const vector float *b)
+vec_lvewx(int __a, const float *__b)
{
- return (vector float)__builtin_altivec_lvewx(a, b);
+ return (vector float)__builtin_altivec_lvewx(__a, __b);
}
/* vec_ldl */
static vector signed char __ATTRS_o_ai
-vec_ldl(int a, const vector signed char *b)
+vec_ldl(int __a, const vector signed char *__b)
{
- return (vector signed char)__builtin_altivec_lvxl(a, b);
+ return (vector signed char)__builtin_altivec_lvxl(__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_ldl(int a, const signed char *b)
+vec_ldl(int __a, const signed char *__b)
{
- return (vector signed char)__builtin_altivec_lvxl(a, b);
+ return (vector signed char)__builtin_altivec_lvxl(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_ldl(int a, const vector unsigned char *b)
+vec_ldl(int __a, const vector unsigned char *__b)
{
- return (vector unsigned char)__builtin_altivec_lvxl(a, b);
+ return (vector unsigned char)__builtin_altivec_lvxl(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_ldl(int a, const unsigned char *b)
+vec_ldl(int __a, const unsigned char *__b)
{
- return (vector unsigned char)__builtin_altivec_lvxl(a, b);
+ return (vector unsigned char)__builtin_altivec_lvxl(__a, __b);
}
static vector bool char __ATTRS_o_ai
-vec_ldl(int a, const vector bool char *b)
+vec_ldl(int __a, const vector bool char *__b)
{
- return (vector bool char)__builtin_altivec_lvxl(a, b);
+ return (vector bool char)__builtin_altivec_lvxl(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_ldl(int a, const vector short *b)
+vec_ldl(int __a, const vector short *__b)
{
- return (vector short)__builtin_altivec_lvxl(a, b);
+ return (vector short)__builtin_altivec_lvxl(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_ldl(int a, const short *b)
+vec_ldl(int __a, const short *__b)
{
- return (vector short)__builtin_altivec_lvxl(a, b);
+ return (vector short)__builtin_altivec_lvxl(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_ldl(int a, const vector unsigned short *b)
+vec_ldl(int __a, const vector unsigned short *__b)
{
- return (vector unsigned short)__builtin_altivec_lvxl(a, b);
+ return (vector unsigned short)__builtin_altivec_lvxl(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_ldl(int a, const unsigned short *b)
+vec_ldl(int __a, const unsigned short *__b)
{
- return (vector unsigned short)__builtin_altivec_lvxl(a, b);
+ return (vector unsigned short)__builtin_altivec_lvxl(__a, __b);
}
static vector bool short __ATTRS_o_ai
-vec_ldl(int a, const vector bool short *b)
+vec_ldl(int __a, const vector bool short *__b)
{
- return (vector bool short)__builtin_altivec_lvxl(a, b);
+ return (vector bool short)__builtin_altivec_lvxl(__a, __b);
}
static vector pixel __ATTRS_o_ai
-vec_ldl(int a, const vector pixel *b)
+vec_ldl(int __a, const vector pixel *__b)
{
- return (vector pixel short)__builtin_altivec_lvxl(a, b);
+ return (vector pixel short)__builtin_altivec_lvxl(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_ldl(int a, const vector int *b)
+vec_ldl(int __a, const vector int *__b)
{
- return (vector int)__builtin_altivec_lvxl(a, b);
+ return (vector int)__builtin_altivec_lvxl(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_ldl(int a, const int *b)
+vec_ldl(int __a, const int *__b)
{
- return (vector int)__builtin_altivec_lvxl(a, b);
+ return (vector int)__builtin_altivec_lvxl(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_ldl(int a, const vector unsigned int *b)
+vec_ldl(int __a, const vector unsigned int *__b)
{
- return (vector unsigned int)__builtin_altivec_lvxl(a, b);
+ return (vector unsigned int)__builtin_altivec_lvxl(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_ldl(int a, const unsigned int *b)
+vec_ldl(int __a, const unsigned int *__b)
{
- return (vector unsigned int)__builtin_altivec_lvxl(a, b);
+ return (vector unsigned int)__builtin_altivec_lvxl(__a, __b);
}
static vector bool int __ATTRS_o_ai
-vec_ldl(int a, const vector bool int *b)
+vec_ldl(int __a, const vector bool int *__b)
{
- return (vector bool int)__builtin_altivec_lvxl(a, b);
+ return (vector bool int)__builtin_altivec_lvxl(__a, __b);
}
static vector float __ATTRS_o_ai
-vec_ldl(int a, const vector float *b)
+vec_ldl(int __a, const vector float *__b)
{
- return (vector float)__builtin_altivec_lvxl(a, b);
+ return (vector float)__builtin_altivec_lvxl(__a, __b);
}
static vector float __ATTRS_o_ai
-vec_ldl(int a, const float *b)
+vec_ldl(int __a, const float *__b)
{
- return (vector float)__builtin_altivec_lvxl(a, b);
+ return (vector float)__builtin_altivec_lvxl(__a, __b);
}
/* vec_lvxl */
static vector signed char __ATTRS_o_ai
-vec_lvxl(int a, const vector signed char *b)
+vec_lvxl(int __a, const vector signed char *__b)
{
- return (vector signed char)__builtin_altivec_lvxl(a, b);
+ return (vector signed char)__builtin_altivec_lvxl(__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_lvxl(int a, const signed char *b)
+vec_lvxl(int __a, const signed char *__b)
{
- return (vector signed char)__builtin_altivec_lvxl(a, b);
+ return (vector signed char)__builtin_altivec_lvxl(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvxl(int a, const vector unsigned char *b)
+vec_lvxl(int __a, const vector unsigned char *__b)
{
- return (vector unsigned char)__builtin_altivec_lvxl(a, b);
+ return (vector unsigned char)__builtin_altivec_lvxl(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvxl(int a, const unsigned char *b)
+vec_lvxl(int __a, const unsigned char *__b)
{
- return (vector unsigned char)__builtin_altivec_lvxl(a, b);
+ return (vector unsigned char)__builtin_altivec_lvxl(__a, __b);
}
static vector bool char __ATTRS_o_ai
-vec_lvxl(int a, const vector bool char *b)
+vec_lvxl(int __a, const vector bool char *__b)
{
- return (vector bool char)__builtin_altivec_lvxl(a, b);
+ return (vector bool char)__builtin_altivec_lvxl(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_lvxl(int a, const vector short *b)
+vec_lvxl(int __a, const vector short *__b)
{
- return (vector short)__builtin_altivec_lvxl(a, b);
+ return (vector short)__builtin_altivec_lvxl(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_lvxl(int a, const short *b)
+vec_lvxl(int __a, const short *__b)
{
- return (vector short)__builtin_altivec_lvxl(a, b);
+ return (vector short)__builtin_altivec_lvxl(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_lvxl(int a, const vector unsigned short *b)
+vec_lvxl(int __a, const vector unsigned short *__b)
{
- return (vector unsigned short)__builtin_altivec_lvxl(a, b);
+ return (vector unsigned short)__builtin_altivec_lvxl(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_lvxl(int a, const unsigned short *b)
+vec_lvxl(int __a, const unsigned short *__b)
{
- return (vector unsigned short)__builtin_altivec_lvxl(a, b);
+ return (vector unsigned short)__builtin_altivec_lvxl(__a, __b);
}
static vector bool short __ATTRS_o_ai
-vec_lvxl(int a, const vector bool short *b)
+vec_lvxl(int __a, const vector bool short *__b)
{
- return (vector bool short)__builtin_altivec_lvxl(a, b);
+ return (vector bool short)__builtin_altivec_lvxl(__a, __b);
}
static vector pixel __ATTRS_o_ai
-vec_lvxl(int a, const vector pixel *b)
+vec_lvxl(int __a, const vector pixel *__b)
{
- return (vector pixel)__builtin_altivec_lvxl(a, b);
+ return (vector pixel)__builtin_altivec_lvxl(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_lvxl(int a, const vector int *b)
+vec_lvxl(int __a, const vector int *__b)
{
- return (vector int)__builtin_altivec_lvxl(a, b);
+ return (vector int)__builtin_altivec_lvxl(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_lvxl(int a, const int *b)
+vec_lvxl(int __a, const int *__b)
{
- return (vector int)__builtin_altivec_lvxl(a, b);
+ return (vector int)__builtin_altivec_lvxl(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_lvxl(int a, const vector unsigned int *b)
+vec_lvxl(int __a, const vector unsigned int *__b)
{
- return (vector unsigned int)__builtin_altivec_lvxl(a, b);
+ return (vector unsigned int)__builtin_altivec_lvxl(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_lvxl(int a, const unsigned int *b)
+vec_lvxl(int __a, const unsigned int *__b)
{
- return (vector unsigned int)__builtin_altivec_lvxl(a, b);
+ return (vector unsigned int)__builtin_altivec_lvxl(__a, __b);
}
static vector bool int __ATTRS_o_ai
-vec_lvxl(int a, const vector bool int *b)
+vec_lvxl(int __a, const vector bool int *__b)
{
- return (vector bool int)__builtin_altivec_lvxl(a, b);
+ return (vector bool int)__builtin_altivec_lvxl(__a, __b);
}
static vector float __ATTRS_o_ai
-vec_lvxl(int a, const vector float *b)
+vec_lvxl(int __a, const vector float *__b)
{
- return (vector float)__builtin_altivec_lvxl(a, b);
+ return (vector float)__builtin_altivec_lvxl(__a, __b);
}
static vector float __ATTRS_o_ai
-vec_lvxl(int a, const float *b)
+vec_lvxl(int __a, const float *__b)
{
- return (vector float)__builtin_altivec_lvxl(a, b);
+ return (vector float)__builtin_altivec_lvxl(__a, __b);
}
/* vec_loge */
static vector float __attribute__((__always_inline__))
-vec_loge(vector float a)
+vec_loge(vector float __a)
{
- return __builtin_altivec_vlogefp(a);
+ return __builtin_altivec_vlogefp(__a);
}
/* vec_vlogefp */
static vector float __attribute__((__always_inline__))
-vec_vlogefp(vector float a)
+vec_vlogefp(vector float __a)
{
- return __builtin_altivec_vlogefp(a);
+ return __builtin_altivec_vlogefp(__a);
}
/* vec_lvsl */
static vector unsigned char __ATTRS_o_ai
-vec_lvsl(int a, const signed char *b)
+vec_lvsl(int __a, const signed char *__b)
{
- return (vector unsigned char)__builtin_altivec_lvsl(a, b);
+ return (vector unsigned char)__builtin_altivec_lvsl(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvsl(int a, const unsigned char *b)
+vec_lvsl(int __a, const unsigned char *__b)
{
- return (vector unsigned char)__builtin_altivec_lvsl(a, b);
+ return (vector unsigned char)__builtin_altivec_lvsl(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvsl(int a, const short *b)
+vec_lvsl(int __a, const short *__b)
{
- return (vector unsigned char)__builtin_altivec_lvsl(a, b);
+ return (vector unsigned char)__builtin_altivec_lvsl(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvsl(int a, const unsigned short *b)
+vec_lvsl(int __a, const unsigned short *__b)
{
- return (vector unsigned char)__builtin_altivec_lvsl(a, b);
+ return (vector unsigned char)__builtin_altivec_lvsl(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvsl(int a, const int *b)
+vec_lvsl(int __a, const int *__b)
{
- return (vector unsigned char)__builtin_altivec_lvsl(a, b);
+ return (vector unsigned char)__builtin_altivec_lvsl(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvsl(int a, const unsigned int *b)
+vec_lvsl(int __a, const unsigned int *__b)
{
- return (vector unsigned char)__builtin_altivec_lvsl(a, b);
+ return (vector unsigned char)__builtin_altivec_lvsl(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvsl(int a, const float *b)
+vec_lvsl(int __a, const float *__b)
{
- return (vector unsigned char)__builtin_altivec_lvsl(a, b);
+ return (vector unsigned char)__builtin_altivec_lvsl(__a, __b);
}
/* vec_lvsr */
static vector unsigned char __ATTRS_o_ai
-vec_lvsr(int a, const signed char *b)
+vec_lvsr(int __a, const signed char *__b)
{
- return (vector unsigned char)__builtin_altivec_lvsr(a, b);
+ return (vector unsigned char)__builtin_altivec_lvsr(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvsr(int a, const unsigned char *b)
+vec_lvsr(int __a, const unsigned char *__b)
{
- return (vector unsigned char)__builtin_altivec_lvsr(a, b);
+ return (vector unsigned char)__builtin_altivec_lvsr(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvsr(int a, const short *b)
+vec_lvsr(int __a, const short *__b)
{
- return (vector unsigned char)__builtin_altivec_lvsr(a, b);
+ return (vector unsigned char)__builtin_altivec_lvsr(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvsr(int a, const unsigned short *b)
+vec_lvsr(int __a, const unsigned short *__b)
{
- return (vector unsigned char)__builtin_altivec_lvsr(a, b);
+ return (vector unsigned char)__builtin_altivec_lvsr(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvsr(int a, const int *b)
+vec_lvsr(int __a, const int *__b)
{
- return (vector unsigned char)__builtin_altivec_lvsr(a, b);
+ return (vector unsigned char)__builtin_altivec_lvsr(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvsr(int a, const unsigned int *b)
+vec_lvsr(int __a, const unsigned int *__b)
{
- return (vector unsigned char)__builtin_altivec_lvsr(a, b);
+ return (vector unsigned char)__builtin_altivec_lvsr(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_lvsr(int a, const float *b)
+vec_lvsr(int __a, const float *__b)
{
- return (vector unsigned char)__builtin_altivec_lvsr(a, b);
+ return (vector unsigned char)__builtin_altivec_lvsr(__a, __b);
}
/* vec_madd */
static vector float __attribute__((__always_inline__))
-vec_madd(vector float a, vector float b, vector float c)
+vec_madd(vector float __a, vector float __b, vector float __c)
{
- return __builtin_altivec_vmaddfp(a, b, c);
+ return __builtin_altivec_vmaddfp(__a, __b, __c);
}
/* vec_vmaddfp */
static vector float __attribute__((__always_inline__))
-vec_vmaddfp(vector float a, vector float b, vector float c)
+vec_vmaddfp(vector float __a, vector float __b, vector float __c)
{
- return __builtin_altivec_vmaddfp(a, b, c);
+ return __builtin_altivec_vmaddfp(__a, __b, __c);
}
/* vec_madds */
static vector signed short __attribute__((__always_inline__))
-vec_madds(vector signed short a, vector signed short b, vector signed short c)
+vec_madds(vector signed short __a, vector signed short __b, vector signed short __c)
{
- return __builtin_altivec_vmhaddshs(a, b, c);
+ return __builtin_altivec_vmhaddshs(__a, __b, __c);
}
/* vec_vmhaddshs */
static vector signed short __attribute__((__always_inline__))
-vec_vmhaddshs(vector signed short a,
- vector signed short b,
- vector signed short c)
+vec_vmhaddshs(vector signed short __a,
+ vector signed short __b,
+ vector signed short __c)
{
- return __builtin_altivec_vmhaddshs(a, b, c);
+ return __builtin_altivec_vmhaddshs(__a, __b, __c);
}
/* vec_max */
static vector signed char __ATTRS_o_ai
-vec_max(vector signed char a, vector signed char b)
+vec_max(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vmaxsb(a, b);
+ return __builtin_altivec_vmaxsb(__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_max(vector bool char a, vector signed char b)
+vec_max(vector bool char __a, vector signed char __b)
{
- return __builtin_altivec_vmaxsb((vector signed char)a, b);
+ return __builtin_altivec_vmaxsb((vector signed char)__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_max(vector signed char a, vector bool char b)
+vec_max(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vmaxsb(a, (vector signed char)b);
+ return __builtin_altivec_vmaxsb(__a, (vector signed char)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_max(vector unsigned char a, vector unsigned char b)
+vec_max(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vmaxub(a, b);
+ return __builtin_altivec_vmaxub(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_max(vector bool char a, vector unsigned char b)
+vec_max(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vmaxub((vector unsigned char)a, b);
+ return __builtin_altivec_vmaxub((vector unsigned char)__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_max(vector unsigned char a, vector bool char b)
+vec_max(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vmaxub(a, (vector unsigned char)b);
+ return __builtin_altivec_vmaxub(__a, (vector unsigned char)__b);
}
static vector short __ATTRS_o_ai
-vec_max(vector short a, vector short b)
+vec_max(vector short __a, vector short __b)
{
- return __builtin_altivec_vmaxsh(a, b);
+ return __builtin_altivec_vmaxsh(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_max(vector bool short a, vector short b)
+vec_max(vector bool short __a, vector short __b)
{
- return __builtin_altivec_vmaxsh((vector short)a, b);
+ return __builtin_altivec_vmaxsh((vector short)__a, __b);
}
static vector short __ATTRS_o_ai
-vec_max(vector short a, vector bool short b)
+vec_max(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vmaxsh(a, (vector short)b);
+ return __builtin_altivec_vmaxsh(__a, (vector short)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_max(vector unsigned short a, vector unsigned short b)
+vec_max(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vmaxuh(a, b);
+ return __builtin_altivec_vmaxuh(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_max(vector bool short a, vector unsigned short b)
+vec_max(vector bool short __a, vector unsigned short __b)
{
- return __builtin_altivec_vmaxuh((vector unsigned short)a, b);
+ return __builtin_altivec_vmaxuh((vector unsigned short)__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_max(vector unsigned short a, vector bool short b)
+vec_max(vector unsigned short __a, vector bool short __b)
{
- return __builtin_altivec_vmaxuh(a, (vector unsigned short)b);
+ return __builtin_altivec_vmaxuh(__a, (vector unsigned short)__b);
}
static vector int __ATTRS_o_ai
-vec_max(vector int a, vector int b)
+vec_max(vector int __a, vector int __b)
{
- return __builtin_altivec_vmaxsw(a, b);
+ return __builtin_altivec_vmaxsw(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_max(vector bool int a, vector int b)
+vec_max(vector bool int __a, vector int __b)
{
- return __builtin_altivec_vmaxsw((vector int)a, b);
+ return __builtin_altivec_vmaxsw((vector int)__a, __b);
}
static vector int __ATTRS_o_ai
-vec_max(vector int a, vector bool int b)
+vec_max(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vmaxsw(a, (vector int)b);
+ return __builtin_altivec_vmaxsw(__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_max(vector unsigned int a, vector unsigned int b)
+vec_max(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vmaxuw(a, b);
+ return __builtin_altivec_vmaxuw(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_max(vector bool int a, vector unsigned int b)
+vec_max(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vmaxuw((vector unsigned int)a, b);
+ return __builtin_altivec_vmaxuw((vector unsigned int)__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_max(vector unsigned int a, vector bool int b)
+vec_max(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vmaxuw(a, (vector unsigned int)b);
+ return __builtin_altivec_vmaxuw(__a, (vector unsigned int)__b);
}
static vector float __ATTRS_o_ai
-vec_max(vector float a, vector float b)
+vec_max(vector float __a, vector float __b)
{
- return __builtin_altivec_vmaxfp(a, b);
+ return __builtin_altivec_vmaxfp(__a, __b);
}
/* vec_vmaxsb */
static vector signed char __ATTRS_o_ai
-vec_vmaxsb(vector signed char a, vector signed char b)
+vec_vmaxsb(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vmaxsb(a, b);
+ return __builtin_altivec_vmaxsb(__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_vmaxsb(vector bool char a, vector signed char b)
+vec_vmaxsb(vector bool char __a, vector signed char __b)
{
- return __builtin_altivec_vmaxsb((vector signed char)a, b);
+ return __builtin_altivec_vmaxsb((vector signed char)__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_vmaxsb(vector signed char a, vector bool char b)
+vec_vmaxsb(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vmaxsb(a, (vector signed char)b);
+ return __builtin_altivec_vmaxsb(__a, (vector signed char)__b);
}
/* vec_vmaxub */
static vector unsigned char __ATTRS_o_ai
-vec_vmaxub(vector unsigned char a, vector unsigned char b)
+vec_vmaxub(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vmaxub(a, b);
+ return __builtin_altivec_vmaxub(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vmaxub(vector bool char a, vector unsigned char b)
+vec_vmaxub(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vmaxub((vector unsigned char)a, b);
+ return __builtin_altivec_vmaxub((vector unsigned char)__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vmaxub(vector unsigned char a, vector bool char b)
+vec_vmaxub(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vmaxub(a, (vector unsigned char)b);
+ return __builtin_altivec_vmaxub(__a, (vector unsigned char)__b);
}
/* vec_vmaxsh */
static vector short __ATTRS_o_ai
-vec_vmaxsh(vector short a, vector short b)
+vec_vmaxsh(vector short __a, vector short __b)
{
- return __builtin_altivec_vmaxsh(a, b);
+ return __builtin_altivec_vmaxsh(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_vmaxsh(vector bool short a, vector short b)
+vec_vmaxsh(vector bool short __a, vector short __b)
{
- return __builtin_altivec_vmaxsh((vector short)a, b);
+ return __builtin_altivec_vmaxsh((vector short)__a, __b);
}
static vector short __ATTRS_o_ai
-vec_vmaxsh(vector short a, vector bool short b)
+vec_vmaxsh(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vmaxsh(a, (vector short)b);
+ return __builtin_altivec_vmaxsh(__a, (vector short)__b);
}
/* vec_vmaxuh */
static vector unsigned short __ATTRS_o_ai
-vec_vmaxuh(vector unsigned short a, vector unsigned short b)
+vec_vmaxuh(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vmaxuh(a, b);
+ return __builtin_altivec_vmaxuh(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vmaxuh(vector bool short a, vector unsigned short b)
+vec_vmaxuh(vector bool short __a, vector unsigned short __b)
{
- return __builtin_altivec_vmaxuh((vector unsigned short)a, b);
+ return __builtin_altivec_vmaxuh((vector unsigned short)__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vmaxuh(vector unsigned short a, vector bool short b)
+vec_vmaxuh(vector unsigned short __a, vector bool short __b)
{
- return __builtin_altivec_vmaxuh(a, (vector unsigned short)b);
+ return __builtin_altivec_vmaxuh(__a, (vector unsigned short)__b);
}
/* vec_vmaxsw */
static vector int __ATTRS_o_ai
-vec_vmaxsw(vector int a, vector int b)
+vec_vmaxsw(vector int __a, vector int __b)
{
- return __builtin_altivec_vmaxsw(a, b);
+ return __builtin_altivec_vmaxsw(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_vmaxsw(vector bool int a, vector int b)
+vec_vmaxsw(vector bool int __a, vector int __b)
{
- return __builtin_altivec_vmaxsw((vector int)a, b);
+ return __builtin_altivec_vmaxsw((vector int)__a, __b);
}
static vector int __ATTRS_o_ai
-vec_vmaxsw(vector int a, vector bool int b)
+vec_vmaxsw(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vmaxsw(a, (vector int)b);
+ return __builtin_altivec_vmaxsw(__a, (vector int)__b);
}
/* vec_vmaxuw */
static vector unsigned int __ATTRS_o_ai
-vec_vmaxuw(vector unsigned int a, vector unsigned int b)
+vec_vmaxuw(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vmaxuw(a, b);
+ return __builtin_altivec_vmaxuw(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vmaxuw(vector bool int a, vector unsigned int b)
+vec_vmaxuw(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vmaxuw((vector unsigned int)a, b);
+ return __builtin_altivec_vmaxuw((vector unsigned int)__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vmaxuw(vector unsigned int a, vector bool int b)
+vec_vmaxuw(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vmaxuw(a, (vector unsigned int)b);
+ return __builtin_altivec_vmaxuw(__a, (vector unsigned int)__b);
}
/* vec_vmaxfp */
static vector float __attribute__((__always_inline__))
-vec_vmaxfp(vector float a, vector float b)
+vec_vmaxfp(vector float __a, vector float __b)
{
- return __builtin_altivec_vmaxfp(a, b);
+ return __builtin_altivec_vmaxfp(__a, __b);
}
/* vec_mergeh */
static vector signed char __ATTRS_o_ai
-vec_mergeh(vector signed char a, vector signed char b)
+vec_mergeh(vector signed char __a, vector signed char __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x10, 0x01, 0x11, 0x02, 0x12, 0x03, 0x13,
0x04, 0x14, 0x05, 0x15, 0x06, 0x16, 0x07, 0x17));
}
static vector unsigned char __ATTRS_o_ai
-vec_mergeh(vector unsigned char a, vector unsigned char b)
+vec_mergeh(vector unsigned char __a, vector unsigned char __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x10, 0x01, 0x11, 0x02, 0x12, 0x03, 0x13,
0x04, 0x14, 0x05, 0x15, 0x06, 0x16, 0x07, 0x17));
}
static vector bool char __ATTRS_o_ai
-vec_mergeh(vector bool char a, vector bool char b)
+vec_mergeh(vector bool char __a, vector bool char __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x10, 0x01, 0x11, 0x02, 0x12, 0x03, 0x13,
0x04, 0x14, 0x05, 0x15, 0x06, 0x16, 0x07, 0x17));
}
static vector short __ATTRS_o_ai
-vec_mergeh(vector short a, vector short b)
+vec_mergeh(vector short __a, vector short __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13,
0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17));
}
static vector unsigned short __ATTRS_o_ai
-vec_mergeh(vector unsigned short a, vector unsigned short b)
+vec_mergeh(vector unsigned short __a, vector unsigned short __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13,
0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17));
}
static vector bool short __ATTRS_o_ai
-vec_mergeh(vector bool short a, vector bool short b)
+vec_mergeh(vector bool short __a, vector bool short __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13,
0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17));
}
static vector pixel __ATTRS_o_ai
-vec_mergeh(vector pixel a, vector pixel b)
+vec_mergeh(vector pixel __a, vector pixel __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13,
0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17));
}
static vector int __ATTRS_o_ai
-vec_mergeh(vector int a, vector int b)
+vec_mergeh(vector int __a, vector int __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13,
0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17));
}
static vector unsigned int __ATTRS_o_ai
-vec_mergeh(vector unsigned int a, vector unsigned int b)
+vec_mergeh(vector unsigned int __a, vector unsigned int __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13,
0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17));
}
static vector bool int __ATTRS_o_ai
-vec_mergeh(vector bool int a, vector bool int b)
+vec_mergeh(vector bool int __a, vector bool int __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13,
0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17));
}
static vector float __ATTRS_o_ai
-vec_mergeh(vector float a, vector float b)
+vec_mergeh(vector float __a, vector float __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13,
0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17));
}
@@ -2708,25 +2708,25 @@ vec_mergeh(vector float a, vector float b)
#define __builtin_altivec_vmrghb vec_vmrghb
static vector signed char __ATTRS_o_ai
-vec_vmrghb(vector signed char a, vector signed char b)
+vec_vmrghb(vector signed char __a, vector signed char __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x10, 0x01, 0x11, 0x02, 0x12, 0x03, 0x13,
0x04, 0x14, 0x05, 0x15, 0x06, 0x16, 0x07, 0x17));
}
static vector unsigned char __ATTRS_o_ai
-vec_vmrghb(vector unsigned char a, vector unsigned char b)
+vec_vmrghb(vector unsigned char __a, vector unsigned char __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x10, 0x01, 0x11, 0x02, 0x12, 0x03, 0x13,
0x04, 0x14, 0x05, 0x15, 0x06, 0x16, 0x07, 0x17));
}
static vector bool char __ATTRS_o_ai
-vec_vmrghb(vector bool char a, vector bool char b)
+vec_vmrghb(vector bool char __a, vector bool char __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x10, 0x01, 0x11, 0x02, 0x12, 0x03, 0x13,
0x04, 0x14, 0x05, 0x15, 0x06, 0x16, 0x07, 0x17));
}
@@ -2736,33 +2736,33 @@ vec_vmrghb(vector bool char a, vector bool char b)
#define __builtin_altivec_vmrghh vec_vmrghh
static vector short __ATTRS_o_ai
-vec_vmrghh(vector short a, vector short b)
+vec_vmrghh(vector short __a, vector short __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13,
0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17));
}
static vector unsigned short __ATTRS_o_ai
-vec_vmrghh(vector unsigned short a, vector unsigned short b)
+vec_vmrghh(vector unsigned short __a, vector unsigned short __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13,
0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17));
}
static vector bool short __ATTRS_o_ai
-vec_vmrghh(vector bool short a, vector bool short b)
+vec_vmrghh(vector bool short __a, vector bool short __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13,
0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17));
}
static vector pixel __ATTRS_o_ai
-vec_vmrghh(vector pixel a, vector pixel b)
+vec_vmrghh(vector pixel __a, vector pixel __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13,
0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17));
}
@@ -2772,33 +2772,33 @@ vec_vmrghh(vector pixel a, vector pixel b)
#define __builtin_altivec_vmrghw vec_vmrghw
static vector int __ATTRS_o_ai
-vec_vmrghw(vector int a, vector int b)
+vec_vmrghw(vector int __a, vector int __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13,
0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17));
}
static vector unsigned int __ATTRS_o_ai
-vec_vmrghw(vector unsigned int a, vector unsigned int b)
+vec_vmrghw(vector unsigned int __a, vector unsigned int __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13,
0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17));
}
static vector bool int __ATTRS_o_ai
-vec_vmrghw(vector bool int a, vector bool int b)
+vec_vmrghw(vector bool int __a, vector bool int __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13,
0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17));
}
static vector float __ATTRS_o_ai
-vec_vmrghw(vector float a, vector float b)
+vec_vmrghw(vector float __a, vector float __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13,
0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17));
}
@@ -2806,89 +2806,89 @@ vec_vmrghw(vector float a, vector float b)
/* vec_mergel */
static vector signed char __ATTRS_o_ai
-vec_mergel(vector signed char a, vector signed char b)
+vec_mergel(vector signed char __a, vector signed char __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x18, 0x09, 0x19, 0x0A, 0x1A, 0x0B, 0x1B,
0x0C, 0x1C, 0x0D, 0x1D, 0x0E, 0x1E, 0x0F, 0x1F));
}
static vector unsigned char __ATTRS_o_ai
-vec_mergel(vector unsigned char a, vector unsigned char b)
+vec_mergel(vector unsigned char __a, vector unsigned char __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x18, 0x09, 0x19, 0x0A, 0x1A, 0x0B, 0x1B,
0x0C, 0x1C, 0x0D, 0x1D, 0x0E, 0x1E, 0x0F, 0x1F));
}
static vector bool char __ATTRS_o_ai
-vec_mergel(vector bool char a, vector bool char b)
+vec_mergel(vector bool char __a, vector bool char __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x18, 0x09, 0x19, 0x0A, 0x1A, 0x0B, 0x1B,
0x0C, 0x1C, 0x0D, 0x1D, 0x0E, 0x1E, 0x0F, 0x1F));
}
static vector short __ATTRS_o_ai
-vec_mergel(vector short a, vector short b)
+vec_mergel(vector short __a, vector short __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x18, 0x19, 0x0A, 0x0B, 0x1A, 0x1B,
0x0C, 0x0D, 0x1C, 0x1D, 0x0E, 0x0F, 0x1E, 0x1F));
}
static vector unsigned short __ATTRS_o_ai
-vec_mergel(vector unsigned short a, vector unsigned short b)
+vec_mergel(vector unsigned short __a, vector unsigned short __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x18, 0x19, 0x0A, 0x0B, 0x1A, 0x1B,
0x0C, 0x0D, 0x1C, 0x1D, 0x0E, 0x0F, 0x1E, 0x1F));
}
static vector bool short __ATTRS_o_ai
-vec_mergel(vector bool short a, vector bool short b)
+vec_mergel(vector bool short __a, vector bool short __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x18, 0x19, 0x0A, 0x0B, 0x1A, 0x1B,
0x0C, 0x0D, 0x1C, 0x1D, 0x0E, 0x0F, 0x1E, 0x1F));
}
static vector pixel __ATTRS_o_ai
-vec_mergel(vector pixel a, vector pixel b)
+vec_mergel(vector pixel __a, vector pixel __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x18, 0x19, 0x0A, 0x0B, 0x1A, 0x1B,
0x0C, 0x0D, 0x1C, 0x1D, 0x0E, 0x0F, 0x1E, 0x1F));
}
static vector int __ATTRS_o_ai
-vec_mergel(vector int a, vector int b)
+vec_mergel(vector int __a, vector int __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B,
0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F));
}
static vector unsigned int __ATTRS_o_ai
-vec_mergel(vector unsigned int a, vector unsigned int b)
+vec_mergel(vector unsigned int __a, vector unsigned int __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B,
0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F));
}
static vector bool int __ATTRS_o_ai
-vec_mergel(vector bool int a, vector bool int b)
+vec_mergel(vector bool int __a, vector bool int __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B,
0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F));
}
static vector float __ATTRS_o_ai
-vec_mergel(vector float a, vector float b)
+vec_mergel(vector float __a, vector float __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B,
0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F));
}
@@ -2898,25 +2898,25 @@ vec_mergel(vector float a, vector float b)
#define __builtin_altivec_vmrglb vec_vmrglb
static vector signed char __ATTRS_o_ai
-vec_vmrglb(vector signed char a, vector signed char b)
+vec_vmrglb(vector signed char __a, vector signed char __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x18, 0x09, 0x19, 0x0A, 0x1A, 0x0B, 0x1B,
0x0C, 0x1C, 0x0D, 0x1D, 0x0E, 0x1E, 0x0F, 0x1F));
}
static vector unsigned char __ATTRS_o_ai
-vec_vmrglb(vector unsigned char a, vector unsigned char b)
+vec_vmrglb(vector unsigned char __a, vector unsigned char __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x18, 0x09, 0x19, 0x0A, 0x1A, 0x0B, 0x1B,
0x0C, 0x1C, 0x0D, 0x1D, 0x0E, 0x1E, 0x0F, 0x1F));
}
static vector bool char __ATTRS_o_ai
-vec_vmrglb(vector bool char a, vector bool char b)
+vec_vmrglb(vector bool char __a, vector bool char __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x18, 0x09, 0x19, 0x0A, 0x1A, 0x0B, 0x1B,
0x0C, 0x1C, 0x0D, 0x1D, 0x0E, 0x1E, 0x0F, 0x1F));
}
@@ -2926,33 +2926,33 @@ vec_vmrglb(vector bool char a, vector bool char b)
#define __builtin_altivec_vmrglh vec_vmrglh
static vector short __ATTRS_o_ai
-vec_vmrglh(vector short a, vector short b)
+vec_vmrglh(vector short __a, vector short __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x18, 0x19, 0x0A, 0x0B, 0x1A, 0x1B,
0x0C, 0x0D, 0x1C, 0x1D, 0x0E, 0x0F, 0x1E, 0x1F));
}
static vector unsigned short __ATTRS_o_ai
-vec_vmrglh(vector unsigned short a, vector unsigned short b)
+vec_vmrglh(vector unsigned short __a, vector unsigned short __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x18, 0x19, 0x0A, 0x0B, 0x1A, 0x1B,
0x0C, 0x0D, 0x1C, 0x1D, 0x0E, 0x0F, 0x1E, 0x1F));
}
static vector bool short __ATTRS_o_ai
-vec_vmrglh(vector bool short a, vector bool short b)
+vec_vmrglh(vector bool short __a, vector bool short __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x18, 0x19, 0x0A, 0x0B, 0x1A, 0x1B,
0x0C, 0x0D, 0x1C, 0x1D, 0x0E, 0x0F, 0x1E, 0x1F));
}
static vector pixel __ATTRS_o_ai
-vec_vmrglh(vector pixel a, vector pixel b)
+vec_vmrglh(vector pixel __a, vector pixel __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x18, 0x19, 0x0A, 0x0B, 0x1A, 0x1B,
0x0C, 0x0D, 0x1C, 0x1D, 0x0E, 0x0F, 0x1E, 0x1F));
}
@@ -2962,33 +2962,33 @@ vec_vmrglh(vector pixel a, vector pixel b)
#define __builtin_altivec_vmrglw vec_vmrglw
static vector int __ATTRS_o_ai
-vec_vmrglw(vector int a, vector int b)
+vec_vmrglw(vector int __a, vector int __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B,
0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F));
}
static vector unsigned int __ATTRS_o_ai
-vec_vmrglw(vector unsigned int a, vector unsigned int b)
+vec_vmrglw(vector unsigned int __a, vector unsigned int __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B,
0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F));
}
static vector bool int __ATTRS_o_ai
-vec_vmrglw(vector bool int a, vector bool int b)
+vec_vmrglw(vector bool int __a, vector bool int __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B,
0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F));
}
static vector float __ATTRS_o_ai
-vec_vmrglw(vector float a, vector float b)
+vec_vmrglw(vector float __a, vector float __b)
{
- return vec_perm(a, b, (vector unsigned char)
+ return vec_perm(__a, __b, (vector unsigned char)
(0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B,
0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F));
}
@@ -3004,245 +3004,245 @@ vec_mfvscr(void)
/* vec_min */
static vector signed char __ATTRS_o_ai
-vec_min(vector signed char a, vector signed char b)
+vec_min(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vminsb(a, b);
+ return __builtin_altivec_vminsb(__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_min(vector bool char a, vector signed char b)
+vec_min(vector bool char __a, vector signed char __b)
{
- return __builtin_altivec_vminsb((vector signed char)a, b);
+ return __builtin_altivec_vminsb((vector signed char)__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_min(vector signed char a, vector bool char b)
+vec_min(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vminsb(a, (vector signed char)b);
+ return __builtin_altivec_vminsb(__a, (vector signed char)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_min(vector unsigned char a, vector unsigned char b)
+vec_min(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vminub(a, b);
+ return __builtin_altivec_vminub(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_min(vector bool char a, vector unsigned char b)
+vec_min(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vminub((vector unsigned char)a, b);
+ return __builtin_altivec_vminub((vector unsigned char)__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_min(vector unsigned char a, vector bool char b)
+vec_min(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vminub(a, (vector unsigned char)b);
+ return __builtin_altivec_vminub(__a, (vector unsigned char)__b);
}
static vector short __ATTRS_o_ai
-vec_min(vector short a, vector short b)
+vec_min(vector short __a, vector short __b)
{
- return __builtin_altivec_vminsh(a, b);
+ return __builtin_altivec_vminsh(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_min(vector bool short a, vector short b)
+vec_min(vector bool short __a, vector short __b)
{
- return __builtin_altivec_vminsh((vector short)a, b);
+ return __builtin_altivec_vminsh((vector short)__a, __b);
}
static vector short __ATTRS_o_ai
-vec_min(vector short a, vector bool short b)
+vec_min(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vminsh(a, (vector short)b);
+ return __builtin_altivec_vminsh(__a, (vector short)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_min(vector unsigned short a, vector unsigned short b)
+vec_min(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vminuh(a, b);
+ return __builtin_altivec_vminuh(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_min(vector bool short a, vector unsigned short b)
+vec_min(vector bool short __a, vector unsigned short __b)
{
- return __builtin_altivec_vminuh((vector unsigned short)a, b);
+ return __builtin_altivec_vminuh((vector unsigned short)__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_min(vector unsigned short a, vector bool short b)
+vec_min(vector unsigned short __a, vector bool short __b)
{
- return __builtin_altivec_vminuh(a, (vector unsigned short)b);
+ return __builtin_altivec_vminuh(__a, (vector unsigned short)__b);
}
static vector int __ATTRS_o_ai
-vec_min(vector int a, vector int b)
+vec_min(vector int __a, vector int __b)
{
- return __builtin_altivec_vminsw(a, b);
+ return __builtin_altivec_vminsw(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_min(vector bool int a, vector int b)
+vec_min(vector bool int __a, vector int __b)
{
- return __builtin_altivec_vminsw((vector int)a, b);
+ return __builtin_altivec_vminsw((vector int)__a, __b);
}
static vector int __ATTRS_o_ai
-vec_min(vector int a, vector bool int b)
+vec_min(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vminsw(a, (vector int)b);
+ return __builtin_altivec_vminsw(__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_min(vector unsigned int a, vector unsigned int b)
+vec_min(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vminuw(a, b);
+ return __builtin_altivec_vminuw(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_min(vector bool int a, vector unsigned int b)
+vec_min(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vminuw((vector unsigned int)a, b);
+ return __builtin_altivec_vminuw((vector unsigned int)__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_min(vector unsigned int a, vector bool int b)
+vec_min(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vminuw(a, (vector unsigned int)b);
+ return __builtin_altivec_vminuw(__a, (vector unsigned int)__b);
}
static vector float __ATTRS_o_ai
-vec_min(vector float a, vector float b)
+vec_min(vector float __a, vector float __b)
{
- return __builtin_altivec_vminfp(a, b);
+ return __builtin_altivec_vminfp(__a, __b);
}
/* vec_vminsb */
static vector signed char __ATTRS_o_ai
-vec_vminsb(vector signed char a, vector signed char b)
+vec_vminsb(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vminsb(a, b);
+ return __builtin_altivec_vminsb(__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_vminsb(vector bool char a, vector signed char b)
+vec_vminsb(vector bool char __a, vector signed char __b)
{
- return __builtin_altivec_vminsb((vector signed char)a, b);
+ return __builtin_altivec_vminsb((vector signed char)__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_vminsb(vector signed char a, vector bool char b)
+vec_vminsb(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vminsb(a, (vector signed char)b);
+ return __builtin_altivec_vminsb(__a, (vector signed char)__b);
}
/* vec_vminub */
static vector unsigned char __ATTRS_o_ai
-vec_vminub(vector unsigned char a, vector unsigned char b)
+vec_vminub(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vminub(a, b);
+ return __builtin_altivec_vminub(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vminub(vector bool char a, vector unsigned char b)
+vec_vminub(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vminub((vector unsigned char)a, b);
+ return __builtin_altivec_vminub((vector unsigned char)__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vminub(vector unsigned char a, vector bool char b)
+vec_vminub(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vminub(a, (vector unsigned char)b);
+ return __builtin_altivec_vminub(__a, (vector unsigned char)__b);
}
/* vec_vminsh */
static vector short __ATTRS_o_ai
-vec_vminsh(vector short a, vector short b)
+vec_vminsh(vector short __a, vector short __b)
{
- return __builtin_altivec_vminsh(a, b);
+ return __builtin_altivec_vminsh(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_vminsh(vector bool short a, vector short b)
+vec_vminsh(vector bool short __a, vector short __b)
{
- return __builtin_altivec_vminsh((vector short)a, b);
+ return __builtin_altivec_vminsh((vector short)__a, __b);
}
static vector short __ATTRS_o_ai
-vec_vminsh(vector short a, vector bool short b)
+vec_vminsh(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vminsh(a, (vector short)b);
+ return __builtin_altivec_vminsh(__a, (vector short)__b);
}
/* vec_vminuh */
static vector unsigned short __ATTRS_o_ai
-vec_vminuh(vector unsigned short a, vector unsigned short b)
+vec_vminuh(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vminuh(a, b);
+ return __builtin_altivec_vminuh(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vminuh(vector bool short a, vector unsigned short b)
+vec_vminuh(vector bool short __a, vector unsigned short __b)
{
- return __builtin_altivec_vminuh((vector unsigned short)a, b);
+ return __builtin_altivec_vminuh((vector unsigned short)__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vminuh(vector unsigned short a, vector bool short b)
+vec_vminuh(vector unsigned short __a, vector bool short __b)
{
- return __builtin_altivec_vminuh(a, (vector unsigned short)b);
+ return __builtin_altivec_vminuh(__a, (vector unsigned short)__b);
}
/* vec_vminsw */
static vector int __ATTRS_o_ai
-vec_vminsw(vector int a, vector int b)
+vec_vminsw(vector int __a, vector int __b)
{
- return __builtin_altivec_vminsw(a, b);
+ return __builtin_altivec_vminsw(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_vminsw(vector bool int a, vector int b)
+vec_vminsw(vector bool int __a, vector int __b)
{
- return __builtin_altivec_vminsw((vector int)a, b);
+ return __builtin_altivec_vminsw((vector int)__a, __b);
}
static vector int __ATTRS_o_ai
-vec_vminsw(vector int a, vector bool int b)
+vec_vminsw(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vminsw(a, (vector int)b);
+ return __builtin_altivec_vminsw(__a, (vector int)__b);
}
/* vec_vminuw */
static vector unsigned int __ATTRS_o_ai
-vec_vminuw(vector unsigned int a, vector unsigned int b)
+vec_vminuw(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vminuw(a, b);
+ return __builtin_altivec_vminuw(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vminuw(vector bool int a, vector unsigned int b)
+vec_vminuw(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vminuw((vector unsigned int)a, b);
+ return __builtin_altivec_vminuw((vector unsigned int)__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vminuw(vector unsigned int a, vector bool int b)
+vec_vminuw(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vminuw(a, (vector unsigned int)b);
+ return __builtin_altivec_vminuw(__a, (vector unsigned int)__b);
}
/* vec_vminfp */
static vector float __attribute__((__always_inline__))
-vec_vminfp(vector float a, vector float b)
+vec_vminfp(vector float __a, vector float __b)
{
- return __builtin_altivec_vminfp(a, b);
+ return __builtin_altivec_vminfp(__a, __b);
}
/* vec_mladd */
@@ -3250,371 +3250,371 @@ vec_vminfp(vector float a, vector float b)
#define __builtin_altivec_vmladduhm vec_mladd
static vector short __ATTRS_o_ai
-vec_mladd(vector short a, vector short b, vector short c)
+vec_mladd(vector short __a, vector short __b, vector short __c)
{
- return a * b + c;
+ return __a * __b + __c;
}
static vector short __ATTRS_o_ai
-vec_mladd(vector short a, vector unsigned short b, vector unsigned short c)
+vec_mladd(vector short __a, vector unsigned short __b, vector unsigned short __c)
{
- return a * (vector short)b + (vector short)c;
+ return __a * (vector short)__b + (vector short)__c;
}
static vector short __ATTRS_o_ai
-vec_mladd(vector unsigned short a, vector short b, vector short c)
+vec_mladd(vector unsigned short __a, vector short __b, vector short __c)
{
- return (vector short)a * b + c;
+ return (vector short)__a * __b + __c;
}
static vector unsigned short __ATTRS_o_ai
-vec_mladd(vector unsigned short a,
- vector unsigned short b,
- vector unsigned short c)
+vec_mladd(vector unsigned short __a,
+ vector unsigned short __b,
+ vector unsigned short __c)
{
- return a * b + c;
+ return __a * __b + __c;
}
/* vec_vmladduhm */
static vector short __ATTRS_o_ai
-vec_vmladduhm(vector short a, vector short b, vector short c)
+vec_vmladduhm(vector short __a, vector short __b, vector short __c)
{
- return a * b + c;
+ return __a * __b + __c;
}
static vector short __ATTRS_o_ai
-vec_vmladduhm(vector short a, vector unsigned short b, vector unsigned short c)
+vec_vmladduhm(vector short __a, vector unsigned short __b, vector unsigned short __c)
{
- return a * (vector short)b + (vector short)c;
+ return __a * (vector short)__b + (vector short)__c;
}
static vector short __ATTRS_o_ai
-vec_vmladduhm(vector unsigned short a, vector short b, vector short c)
+vec_vmladduhm(vector unsigned short __a, vector short __b, vector short __c)
{
- return (vector short)a * b + c;
+ return (vector short)__a * __b + __c;
}
static vector unsigned short __ATTRS_o_ai
-vec_vmladduhm(vector unsigned short a,
- vector unsigned short b,
- vector unsigned short c)
+vec_vmladduhm(vector unsigned short __a,
+ vector unsigned short __b,
+ vector unsigned short __c)
{
- return a * b + c;
+ return __a * __b + __c;
}
/* vec_mradds */
static vector short __attribute__((__always_inline__))
-vec_mradds(vector short a, vector short b, vector short c)
+vec_mradds(vector short __a, vector short __b, vector short __c)
{
- return __builtin_altivec_vmhraddshs(a, b, c);
+ return __builtin_altivec_vmhraddshs(__a, __b, __c);
}
/* vec_vmhraddshs */
static vector short __attribute__((__always_inline__))
-vec_vmhraddshs(vector short a, vector short b, vector short c)
+vec_vmhraddshs(vector short __a, vector short __b, vector short __c)
{
- return __builtin_altivec_vmhraddshs(a, b, c);
+ return __builtin_altivec_vmhraddshs(__a, __b, __c);
}
/* vec_msum */
static vector int __ATTRS_o_ai
-vec_msum(vector signed char a, vector unsigned char b, vector int c)
+vec_msum(vector signed char __a, vector unsigned char __b, vector int __c)
{
- return __builtin_altivec_vmsummbm(a, b, c);
+ return __builtin_altivec_vmsummbm(__a, __b, __c);
}
static vector unsigned int __ATTRS_o_ai
-vec_msum(vector unsigned char a, vector unsigned char b, vector unsigned int c)
+vec_msum(vector unsigned char __a, vector unsigned char __b, vector unsigned int __c)
{
- return __builtin_altivec_vmsumubm(a, b, c);
+ return __builtin_altivec_vmsumubm(__a, __b, __c);
}
static vector int __ATTRS_o_ai
-vec_msum(vector short a, vector short b, vector int c)
+vec_msum(vector short __a, vector short __b, vector int __c)
{
- return __builtin_altivec_vmsumshm(a, b, c);
+ return __builtin_altivec_vmsumshm(__a, __b, __c);
}
static vector unsigned int __ATTRS_o_ai
-vec_msum(vector unsigned short a,
- vector unsigned short b,
- vector unsigned int c)
+vec_msum(vector unsigned short __a,
+ vector unsigned short __b,
+ vector unsigned int __c)
{
- return __builtin_altivec_vmsumuhm(a, b, c);
+ return __builtin_altivec_vmsumuhm(__a, __b, __c);
}
/* vec_vmsummbm */
static vector int __attribute__((__always_inline__))
-vec_vmsummbm(vector signed char a, vector unsigned char b, vector int c)
+vec_vmsummbm(vector signed char __a, vector unsigned char __b, vector int __c)
{
- return __builtin_altivec_vmsummbm(a, b, c);
+ return __builtin_altivec_vmsummbm(__a, __b, __c);
}
/* vec_vmsumubm */
static vector unsigned int __attribute__((__always_inline__))
-vec_vmsumubm(vector unsigned char a,
- vector unsigned char b,
- vector unsigned int c)
+vec_vmsumubm(vector unsigned char __a,
+ vector unsigned char __b,
+ vector unsigned int __c)
{
- return __builtin_altivec_vmsumubm(a, b, c);
+ return __builtin_altivec_vmsumubm(__a, __b, __c);
}
/* vec_vmsumshm */
static vector int __attribute__((__always_inline__))
-vec_vmsumshm(vector short a, vector short b, vector int c)
+vec_vmsumshm(vector short __a, vector short __b, vector int __c)
{
- return __builtin_altivec_vmsumshm(a, b, c);
+ return __builtin_altivec_vmsumshm(__a, __b, __c);
}
/* vec_vmsumuhm */
static vector unsigned int __attribute__((__always_inline__))
-vec_vmsumuhm(vector unsigned short a,
- vector unsigned short b,
- vector unsigned int c)
+vec_vmsumuhm(vector unsigned short __a,
+ vector unsigned short __b,
+ vector unsigned int __c)
{
- return __builtin_altivec_vmsumuhm(a, b, c);
+ return __builtin_altivec_vmsumuhm(__a, __b, __c);
}
/* vec_msums */
static vector int __ATTRS_o_ai
-vec_msums(vector short a, vector short b, vector int c)
+vec_msums(vector short __a, vector short __b, vector int __c)
{
- return __builtin_altivec_vmsumshs(a, b, c);
+ return __builtin_altivec_vmsumshs(__a, __b, __c);
}
static vector unsigned int __ATTRS_o_ai
-vec_msums(vector unsigned short a,
- vector unsigned short b,
- vector unsigned int c)
+vec_msums(vector unsigned short __a,
+ vector unsigned short __b,
+ vector unsigned int __c)
{
- return __builtin_altivec_vmsumuhs(a, b, c);
+ return __builtin_altivec_vmsumuhs(__a, __b, __c);
}
/* vec_vmsumshs */
static vector int __attribute__((__always_inline__))
-vec_vmsumshs(vector short a, vector short b, vector int c)
+vec_vmsumshs(vector short __a, vector short __b, vector int __c)
{
- return __builtin_altivec_vmsumshs(a, b, c);
+ return __builtin_altivec_vmsumshs(__a, __b, __c);
}
/* vec_vmsumuhs */
static vector unsigned int __attribute__((__always_inline__))
-vec_vmsumuhs(vector unsigned short a,
- vector unsigned short b,
- vector unsigned int c)
+vec_vmsumuhs(vector unsigned short __a,
+ vector unsigned short __b,
+ vector unsigned int __c)
{
- return __builtin_altivec_vmsumuhs(a, b, c);
+ return __builtin_altivec_vmsumuhs(__a, __b, __c);
}
/* vec_mtvscr */
static void __ATTRS_o_ai
-vec_mtvscr(vector signed char a)
+vec_mtvscr(vector signed char __a)
{
- __builtin_altivec_mtvscr((vector int)a);
+ __builtin_altivec_mtvscr((vector int)__a);
}
static void __ATTRS_o_ai
-vec_mtvscr(vector unsigned char a)
+vec_mtvscr(vector unsigned char __a)
{
- __builtin_altivec_mtvscr((vector int)a);
+ __builtin_altivec_mtvscr((vector int)__a);
}
static void __ATTRS_o_ai
-vec_mtvscr(vector bool char a)
+vec_mtvscr(vector bool char __a)
{
- __builtin_altivec_mtvscr((vector int)a);
+ __builtin_altivec_mtvscr((vector int)__a);
}
static void __ATTRS_o_ai
-vec_mtvscr(vector short a)
+vec_mtvscr(vector short __a)
{
- __builtin_altivec_mtvscr((vector int)a);
+ __builtin_altivec_mtvscr((vector int)__a);
}
static void __ATTRS_o_ai
-vec_mtvscr(vector unsigned short a)
+vec_mtvscr(vector unsigned short __a)
{
- __builtin_altivec_mtvscr((vector int)a);
+ __builtin_altivec_mtvscr((vector int)__a);
}
static void __ATTRS_o_ai
-vec_mtvscr(vector bool short a)
+vec_mtvscr(vector bool short __a)
{
- __builtin_altivec_mtvscr((vector int)a);
+ __builtin_altivec_mtvscr((vector int)__a);
}
static void __ATTRS_o_ai
-vec_mtvscr(vector pixel a)
+vec_mtvscr(vector pixel __a)
{
- __builtin_altivec_mtvscr((vector int)a);
+ __builtin_altivec_mtvscr((vector int)__a);
}
static void __ATTRS_o_ai
-vec_mtvscr(vector int a)
+vec_mtvscr(vector int __a)
{
- __builtin_altivec_mtvscr((vector int)a);
+ __builtin_altivec_mtvscr((vector int)__a);
}
static void __ATTRS_o_ai
-vec_mtvscr(vector unsigned int a)
+vec_mtvscr(vector unsigned int __a)
{
- __builtin_altivec_mtvscr((vector int)a);
+ __builtin_altivec_mtvscr((vector int)__a);
}
static void __ATTRS_o_ai
-vec_mtvscr(vector bool int a)
+vec_mtvscr(vector bool int __a)
{
- __builtin_altivec_mtvscr((vector int)a);
+ __builtin_altivec_mtvscr((vector int)__a);
}
static void __ATTRS_o_ai
-vec_mtvscr(vector float a)
+vec_mtvscr(vector float __a)
{
- __builtin_altivec_mtvscr((vector int)a);
+ __builtin_altivec_mtvscr((vector int)__a);
}
/* vec_mule */
static vector short __ATTRS_o_ai
-vec_mule(vector signed char a, vector signed char b)
+vec_mule(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vmulesb(a, b);
+ return __builtin_altivec_vmulesb(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_mule(vector unsigned char a, vector unsigned char b)
+vec_mule(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vmuleub(a, b);
+ return __builtin_altivec_vmuleub(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_mule(vector short a, vector short b)
+vec_mule(vector short __a, vector short __b)
{
- return __builtin_altivec_vmulesh(a, b);
+ return __builtin_altivec_vmulesh(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_mule(vector unsigned short a, vector unsigned short b)
+vec_mule(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vmuleuh(a, b);
+ return __builtin_altivec_vmuleuh(__a, __b);
}
/* vec_vmulesb */
static vector short __attribute__((__always_inline__))
-vec_vmulesb(vector signed char a, vector signed char b)
+vec_vmulesb(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vmulesb(a, b);
+ return __builtin_altivec_vmulesb(__a, __b);
}
/* vec_vmuleub */
static vector unsigned short __attribute__((__always_inline__))
-vec_vmuleub(vector unsigned char a, vector unsigned char b)
+vec_vmuleub(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vmuleub(a, b);
+ return __builtin_altivec_vmuleub(__a, __b);
}
/* vec_vmulesh */
static vector int __attribute__((__always_inline__))
-vec_vmulesh(vector short a, vector short b)
+vec_vmulesh(vector short __a, vector short __b)
{
- return __builtin_altivec_vmulesh(a, b);
+ return __builtin_altivec_vmulesh(__a, __b);
}
/* vec_vmuleuh */
static vector unsigned int __attribute__((__always_inline__))
-vec_vmuleuh(vector unsigned short a, vector unsigned short b)
+vec_vmuleuh(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vmuleuh(a, b);
+ return __builtin_altivec_vmuleuh(__a, __b);
}
/* vec_mulo */
static vector short __ATTRS_o_ai
-vec_mulo(vector signed char a, vector signed char b)
+vec_mulo(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vmulosb(a, b);
+ return __builtin_altivec_vmulosb(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_mulo(vector unsigned char a, vector unsigned char b)
+vec_mulo(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vmuloub(a, b);
+ return __builtin_altivec_vmuloub(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_mulo(vector short a, vector short b)
+vec_mulo(vector short __a, vector short __b)
{
- return __builtin_altivec_vmulosh(a, b);
+ return __builtin_altivec_vmulosh(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_mulo(vector unsigned short a, vector unsigned short b)
+vec_mulo(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vmulouh(a, b);
+ return __builtin_altivec_vmulouh(__a, __b);
}
/* vec_vmulosb */
static vector short __attribute__((__always_inline__))
-vec_vmulosb(vector signed char a, vector signed char b)
+vec_vmulosb(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vmulosb(a, b);
+ return __builtin_altivec_vmulosb(__a, __b);
}
/* vec_vmuloub */
static vector unsigned short __attribute__((__always_inline__))
-vec_vmuloub(vector unsigned char a, vector unsigned char b)
+vec_vmuloub(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vmuloub(a, b);
+ return __builtin_altivec_vmuloub(__a, __b);
}
/* vec_vmulosh */
static vector int __attribute__((__always_inline__))
-vec_vmulosh(vector short a, vector short b)
+vec_vmulosh(vector short __a, vector short __b)
{
- return __builtin_altivec_vmulosh(a, b);
+ return __builtin_altivec_vmulosh(__a, __b);
}
/* vec_vmulouh */
static vector unsigned int __attribute__((__always_inline__))
-vec_vmulouh(vector unsigned short a, vector unsigned short b)
+vec_vmulouh(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vmulouh(a, b);
+ return __builtin_altivec_vmulouh(__a, __b);
}
/* vec_nmsub */
static vector float __attribute__((__always_inline__))
-vec_nmsub(vector float a, vector float b, vector float c)
+vec_nmsub(vector float __a, vector float __b, vector float __c)
{
- return __builtin_altivec_vnmsubfp(a, b, c);
+ return __builtin_altivec_vnmsubfp(__a, __b, __c);
}
/* vec_vnmsubfp */
static vector float __attribute__((__always_inline__))
-vec_vnmsubfp(vector float a, vector float b, vector float c)
+vec_vnmsubfp(vector float __a, vector float __b, vector float __c)
{
- return __builtin_altivec_vnmsubfp(a, b, c);
+ return __builtin_altivec_vnmsubfp(__a, __b, __c);
}
/* vec_nor */
@@ -3622,127 +3622,127 @@ vec_vnmsubfp(vector float a, vector float b, vector float c)
#define __builtin_altivec_vnor vec_nor
static vector signed char __ATTRS_o_ai
-vec_nor(vector signed char a, vector signed char b)
+vec_nor(vector signed char __a, vector signed char __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_nor(vector unsigned char a, vector unsigned char b)
+vec_nor(vector unsigned char __a, vector unsigned char __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector bool char __ATTRS_o_ai
-vec_nor(vector bool char a, vector bool char b)
+vec_nor(vector bool char __a, vector bool char __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector short __ATTRS_o_ai
-vec_nor(vector short a, vector short b)
+vec_nor(vector short __a, vector short __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_nor(vector unsigned short a, vector unsigned short b)
+vec_nor(vector unsigned short __a, vector unsigned short __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector bool short __ATTRS_o_ai
-vec_nor(vector bool short a, vector bool short b)
+vec_nor(vector bool short __a, vector bool short __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector int __ATTRS_o_ai
-vec_nor(vector int a, vector int b)
+vec_nor(vector int __a, vector int __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_nor(vector unsigned int a, vector unsigned int b)
+vec_nor(vector unsigned int __a, vector unsigned int __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector bool int __ATTRS_o_ai
-vec_nor(vector bool int a, vector bool int b)
+vec_nor(vector bool int __a, vector bool int __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector float __ATTRS_o_ai
-vec_nor(vector float a, vector float b)
+vec_nor(vector float __a, vector float __b)
{
- vector unsigned int res = ~((vector unsigned int)a | (vector unsigned int)b);
- return (vector float)res;
+ vector unsigned int __res = ~((vector unsigned int)__a | (vector unsigned int)__b);
+ return (vector float)__res;
}
/* vec_vnor */
static vector signed char __ATTRS_o_ai
-vec_vnor(vector signed char a, vector signed char b)
+vec_vnor(vector signed char __a, vector signed char __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vnor(vector unsigned char a, vector unsigned char b)
+vec_vnor(vector unsigned char __a, vector unsigned char __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector bool char __ATTRS_o_ai
-vec_vnor(vector bool char a, vector bool char b)
+vec_vnor(vector bool char __a, vector bool char __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector short __ATTRS_o_ai
-vec_vnor(vector short a, vector short b)
+vec_vnor(vector short __a, vector short __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vnor(vector unsigned short a, vector unsigned short b)
+vec_vnor(vector unsigned short __a, vector unsigned short __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector bool short __ATTRS_o_ai
-vec_vnor(vector bool short a, vector bool short b)
+vec_vnor(vector bool short __a, vector bool short __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector int __ATTRS_o_ai
-vec_vnor(vector int a, vector int b)
+vec_vnor(vector int __a, vector int __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vnor(vector unsigned int a, vector unsigned int b)
+vec_vnor(vector unsigned int __a, vector unsigned int __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector bool int __ATTRS_o_ai
-vec_vnor(vector bool int a, vector bool int b)
+vec_vnor(vector bool int __a, vector bool int __b)
{
- return ~(a | b);
+ return ~(__a | __b);
}
static vector float __ATTRS_o_ai
-vec_vnor(vector float a, vector float b)
+vec_vnor(vector float __a, vector float __b)
{
- vector unsigned int res = ~((vector unsigned int)a | (vector unsigned int)b);
- return (vector float)res;
+ vector unsigned int __res = ~((vector unsigned int)__a | (vector unsigned int)__b);
+ return (vector float)__res;
}
/* vec_or */
@@ -3750,347 +3750,347 @@ vec_vnor(vector float a, vector float b)
#define __builtin_altivec_vor vec_or
static vector signed char __ATTRS_o_ai
-vec_or(vector signed char a, vector signed char b)
+vec_or(vector signed char __a, vector signed char __b)
{
- return a | b;
+ return __a | __b;
}
static vector signed char __ATTRS_o_ai
-vec_or(vector bool char a, vector signed char b)
+vec_or(vector bool char __a, vector signed char __b)
{
- return (vector signed char)a | b;
+ return (vector signed char)__a | __b;
}
static vector signed char __ATTRS_o_ai
-vec_or(vector signed char a, vector bool char b)
+vec_or(vector signed char __a, vector bool char __b)
{
- return a | (vector signed char)b;
+ return __a | (vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_or(vector unsigned char a, vector unsigned char b)
+vec_or(vector unsigned char __a, vector unsigned char __b)
{
- return a | b;
+ return __a | __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_or(vector bool char a, vector unsigned char b)
+vec_or(vector bool char __a, vector unsigned char __b)
{
- return (vector unsigned char)a | b;
+ return (vector unsigned char)__a | __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_or(vector unsigned char a, vector bool char b)
+vec_or(vector unsigned char __a, vector bool char __b)
{
- return a | (vector unsigned char)b;
+ return __a | (vector unsigned char)__b;
}
static vector bool char __ATTRS_o_ai
-vec_or(vector bool char a, vector bool char b)
+vec_or(vector bool char __a, vector bool char __b)
{
- return a | b;
+ return __a | __b;
}
static vector short __ATTRS_o_ai
-vec_or(vector short a, vector short b)
+vec_or(vector short __a, vector short __b)
{
- return a | b;
+ return __a | __b;
}
static vector short __ATTRS_o_ai
-vec_or(vector bool short a, vector short b)
+vec_or(vector bool short __a, vector short __b)
{
- return (vector short)a | b;
+ return (vector short)__a | __b;
}
static vector short __ATTRS_o_ai
-vec_or(vector short a, vector bool short b)
+vec_or(vector short __a, vector bool short __b)
{
- return a | (vector short)b;
+ return __a | (vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_or(vector unsigned short a, vector unsigned short b)
+vec_or(vector unsigned short __a, vector unsigned short __b)
{
- return a | b;
+ return __a | __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_or(vector bool short a, vector unsigned short b)
+vec_or(vector bool short __a, vector unsigned short __b)
{
- return (vector unsigned short)a | b;
+ return (vector unsigned short)__a | __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_or(vector unsigned short a, vector bool short b)
+vec_or(vector unsigned short __a, vector bool short __b)
{
- return a | (vector unsigned short)b;
+ return __a | (vector unsigned short)__b;
}
static vector bool short __ATTRS_o_ai
-vec_or(vector bool short a, vector bool short b)
+vec_or(vector bool short __a, vector bool short __b)
{
- return a | b;
+ return __a | __b;
}
static vector int __ATTRS_o_ai
-vec_or(vector int a, vector int b)
+vec_or(vector int __a, vector int __b)
{
- return a | b;
+ return __a | __b;
}
static vector int __ATTRS_o_ai
-vec_or(vector bool int a, vector int b)
+vec_or(vector bool int __a, vector int __b)
{
- return (vector int)a | b;
+ return (vector int)__a | __b;
}
static vector int __ATTRS_o_ai
-vec_or(vector int a, vector bool int b)
+vec_or(vector int __a, vector bool int __b)
{
- return a | (vector int)b;
+ return __a | (vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_or(vector unsigned int a, vector unsigned int b)
+vec_or(vector unsigned int __a, vector unsigned int __b)
{
- return a | b;
+ return __a | __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_or(vector bool int a, vector unsigned int b)
+vec_or(vector bool int __a, vector unsigned int __b)
{
- return (vector unsigned int)a | b;
+ return (vector unsigned int)__a | __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_or(vector unsigned int a, vector bool int b)
+vec_or(vector unsigned int __a, vector bool int __b)
{
- return a | (vector unsigned int)b;
+ return __a | (vector unsigned int)__b;
}
static vector bool int __ATTRS_o_ai
-vec_or(vector bool int a, vector bool int b)
+vec_or(vector bool int __a, vector bool int __b)
{
- return a | b;
+ return __a | __b;
}
static vector float __ATTRS_o_ai
-vec_or(vector float a, vector float b)
+vec_or(vector float __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a | (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a | (vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_or(vector bool int a, vector float b)
+vec_or(vector bool int __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a | (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a | (vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_or(vector float a, vector bool int b)
+vec_or(vector float __a, vector bool int __b)
{
- vector unsigned int res = (vector unsigned int)a | (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a | (vector unsigned int)__b;
+ return (vector float)__res;
}
/* vec_vor */
static vector signed char __ATTRS_o_ai
-vec_vor(vector signed char a, vector signed char b)
+vec_vor(vector signed char __a, vector signed char __b)
{
- return a | b;
+ return __a | __b;
}
static vector signed char __ATTRS_o_ai
-vec_vor(vector bool char a, vector signed char b)
+vec_vor(vector bool char __a, vector signed char __b)
{
- return (vector signed char)a | b;
+ return (vector signed char)__a | __b;
}
static vector signed char __ATTRS_o_ai
-vec_vor(vector signed char a, vector bool char b)
+vec_vor(vector signed char __a, vector bool char __b)
{
- return a | (vector signed char)b;
+ return __a | (vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vor(vector unsigned char a, vector unsigned char b)
+vec_vor(vector unsigned char __a, vector unsigned char __b)
{
- return a | b;
+ return __a | __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vor(vector bool char a, vector unsigned char b)
+vec_vor(vector bool char __a, vector unsigned char __b)
{
- return (vector unsigned char)a | b;
+ return (vector unsigned char)__a | __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vor(vector unsigned char a, vector bool char b)
+vec_vor(vector unsigned char __a, vector bool char __b)
{
- return a | (vector unsigned char)b;
+ return __a | (vector unsigned char)__b;
}
static vector bool char __ATTRS_o_ai
-vec_vor(vector bool char a, vector bool char b)
+vec_vor(vector bool char __a, vector bool char __b)
{
- return a | b;
+ return __a | __b;
}
static vector short __ATTRS_o_ai
-vec_vor(vector short a, vector short b)
+vec_vor(vector short __a, vector short __b)
{
- return a | b;
+ return __a | __b;
}
static vector short __ATTRS_o_ai
-vec_vor(vector bool short a, vector short b)
+vec_vor(vector bool short __a, vector short __b)
{
- return (vector short)a | b;
+ return (vector short)__a | __b;
}
static vector short __ATTRS_o_ai
-vec_vor(vector short a, vector bool short b)
+vec_vor(vector short __a, vector bool short __b)
{
- return a | (vector short)b;
+ return __a | (vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vor(vector unsigned short a, vector unsigned short b)
+vec_vor(vector unsigned short __a, vector unsigned short __b)
{
- return a | b;
+ return __a | __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vor(vector bool short a, vector unsigned short b)
+vec_vor(vector bool short __a, vector unsigned short __b)
{
- return (vector unsigned short)a | b;
+ return (vector unsigned short)__a | __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vor(vector unsigned short a, vector bool short b)
+vec_vor(vector unsigned short __a, vector bool short __b)
{
- return a | (vector unsigned short)b;
+ return __a | (vector unsigned short)__b;
}
static vector bool short __ATTRS_o_ai
-vec_vor(vector bool short a, vector bool short b)
+vec_vor(vector bool short __a, vector bool short __b)
{
- return a | b;
+ return __a | __b;
}
static vector int __ATTRS_o_ai
-vec_vor(vector int a, vector int b)
+vec_vor(vector int __a, vector int __b)
{
- return a | b;
+ return __a | __b;
}
static vector int __ATTRS_o_ai
-vec_vor(vector bool int a, vector int b)
+vec_vor(vector bool int __a, vector int __b)
{
- return (vector int)a | b;
+ return (vector int)__a | __b;
}
static vector int __ATTRS_o_ai
-vec_vor(vector int a, vector bool int b)
+vec_vor(vector int __a, vector bool int __b)
{
- return a | (vector int)b;
+ return __a | (vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vor(vector unsigned int a, vector unsigned int b)
+vec_vor(vector unsigned int __a, vector unsigned int __b)
{
- return a | b;
+ return __a | __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vor(vector bool int a, vector unsigned int b)
+vec_vor(vector bool int __a, vector unsigned int __b)
{
- return (vector unsigned int)a | b;
+ return (vector unsigned int)__a | __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vor(vector unsigned int a, vector bool int b)
+vec_vor(vector unsigned int __a, vector bool int __b)
{
- return a | (vector unsigned int)b;
+ return __a | (vector unsigned int)__b;
}
static vector bool int __ATTRS_o_ai
-vec_vor(vector bool int a, vector bool int b)
+vec_vor(vector bool int __a, vector bool int __b)
{
- return a | b;
+ return __a | __b;
}
static vector float __ATTRS_o_ai
-vec_vor(vector float a, vector float b)
+vec_vor(vector float __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a | (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a | (vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_vor(vector bool int a, vector float b)
+vec_vor(vector bool int __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a | (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a | (vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_vor(vector float a, vector bool int b)
+vec_vor(vector float __a, vector bool int __b)
{
- vector unsigned int res = (vector unsigned int)a | (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a | (vector unsigned int)__b;
+ return (vector float)__res;
}
/* vec_pack */
static vector signed char __ATTRS_o_ai
-vec_pack(vector signed short a, vector signed short b)
+vec_pack(vector signed short __a, vector signed short __b)
{
- return (vector signed char)vec_perm(a, b, (vector unsigned char)
+ return (vector signed char)vec_perm(__a, __b, (vector unsigned char)
(0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F,
0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F));
}
static vector unsigned char __ATTRS_o_ai
-vec_pack(vector unsigned short a, vector unsigned short b)
+vec_pack(vector unsigned short __a, vector unsigned short __b)
{
- return (vector unsigned char)vec_perm(a, b, (vector unsigned char)
+ return (vector unsigned char)vec_perm(__a, __b, (vector unsigned char)
(0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F,
0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F));
}
static vector bool char __ATTRS_o_ai
-vec_pack(vector bool short a, vector bool short b)
+vec_pack(vector bool short __a, vector bool short __b)
{
- return (vector bool char)vec_perm(a, b, (vector unsigned char)
+ return (vector bool char)vec_perm(__a, __b, (vector unsigned char)
(0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F,
0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F));
}
static vector short __ATTRS_o_ai
-vec_pack(vector int a, vector int b)
+vec_pack(vector int __a, vector int __b)
{
- return (vector short)vec_perm(a, b, (vector unsigned char)
+ return (vector short)vec_perm(__a, __b, (vector unsigned char)
(0x02, 0x03, 0x06, 0x07, 0x0A, 0x0B, 0x0E, 0x0F,
0x12, 0x13, 0x16, 0x17, 0x1A, 0x1B, 0x1E, 0x1F));
}
static vector unsigned short __ATTRS_o_ai
-vec_pack(vector unsigned int a, vector unsigned int b)
+vec_pack(vector unsigned int __a, vector unsigned int __b)
{
- return (vector unsigned short)vec_perm(a, b, (vector unsigned char)
+ return (vector unsigned short)vec_perm(__a, __b, (vector unsigned char)
(0x02, 0x03, 0x06, 0x07, 0x0A, 0x0B, 0x0E, 0x0F,
0x12, 0x13, 0x16, 0x17, 0x1A, 0x1B, 0x1E, 0x1F));
}
static vector bool short __ATTRS_o_ai
-vec_pack(vector bool int a, vector bool int b)
+vec_pack(vector bool int __a, vector bool int __b)
{
- return (vector bool short)vec_perm(a, b, (vector unsigned char)
+ return (vector bool short)vec_perm(__a, __b, (vector unsigned char)
(0x02, 0x03, 0x06, 0x07, 0x0A, 0x0B, 0x0E, 0x0F,
0x12, 0x13, 0x16, 0x17, 0x1A, 0x1B, 0x1E, 0x1F));
}
@@ -4100,25 +4100,25 @@ vec_pack(vector bool int a, vector bool int b)
#define __builtin_altivec_vpkuhum vec_vpkuhum
static vector signed char __ATTRS_o_ai
-vec_vpkuhum(vector signed short a, vector signed short b)
+vec_vpkuhum(vector signed short __a, vector signed short __b)
{
- return (vector signed char)vec_perm(a, b, (vector unsigned char)
+ return (vector signed char)vec_perm(__a, __b, (vector unsigned char)
(0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F,
0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F));
}
static vector unsigned char __ATTRS_o_ai
-vec_vpkuhum(vector unsigned short a, vector unsigned short b)
+vec_vpkuhum(vector unsigned short __a, vector unsigned short __b)
{
- return (vector unsigned char)vec_perm(a, b, (vector unsigned char)
+ return (vector unsigned char)vec_perm(__a, __b, (vector unsigned char)
(0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F,
0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F));
}
static vector bool char __ATTRS_o_ai
-vec_vpkuhum(vector bool short a, vector bool short b)
+vec_vpkuhum(vector bool short __a, vector bool short __b)
{
- return (vector bool char)vec_perm(a, b, (vector unsigned char)
+ return (vector bool char)vec_perm(__a, __b, (vector unsigned char)
(0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F,
0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F));
}
@@ -4128,25 +4128,25 @@ vec_vpkuhum(vector bool short a, vector bool short b)
#define __builtin_altivec_vpkuwum vec_vpkuwum
static vector short __ATTRS_o_ai
-vec_vpkuwum(vector int a, vector int b)
+vec_vpkuwum(vector int __a, vector int __b)
{
- return (vector short)vec_perm(a, b, (vector unsigned char)
+ return (vector short)vec_perm(__a, __b, (vector unsigned char)
(0x02, 0x03, 0x06, 0x07, 0x0A, 0x0B, 0x0E, 0x0F,
0x12, 0x13, 0x16, 0x17, 0x1A, 0x1B, 0x1E, 0x1F));
}
static vector unsigned short __ATTRS_o_ai
-vec_vpkuwum(vector unsigned int a, vector unsigned int b)
+vec_vpkuwum(vector unsigned int __a, vector unsigned int __b)
{
- return (vector unsigned short)vec_perm(a, b, (vector unsigned char)
+ return (vector unsigned short)vec_perm(__a, __b, (vector unsigned char)
(0x02, 0x03, 0x06, 0x07, 0x0A, 0x0B, 0x0E, 0x0F,
0x12, 0x13, 0x16, 0x17, 0x1A, 0x1B, 0x1E, 0x1F));
}
static vector bool short __ATTRS_o_ai
-vec_vpkuwum(vector bool int a, vector bool int b)
+vec_vpkuwum(vector bool int __a, vector bool int __b)
{
- return (vector bool short)vec_perm(a, b, (vector unsigned char)
+ return (vector bool short)vec_perm(__a, __b, (vector unsigned char)
(0x02, 0x03, 0x06, 0x07, 0x0A, 0x0B, 0x0E, 0x0F,
0x12, 0x13, 0x16, 0x17, 0x1A, 0x1B, 0x1E, 0x1F));
}
@@ -4154,421 +4154,421 @@ vec_vpkuwum(vector bool int a, vector bool int b)
/* vec_packpx */
static vector pixel __attribute__((__always_inline__))
-vec_packpx(vector unsigned int a, vector unsigned int b)
+vec_packpx(vector unsigned int __a, vector unsigned int __b)
{
- return (vector pixel)__builtin_altivec_vpkpx(a, b);
+ return (vector pixel)__builtin_altivec_vpkpx(__a, __b);
}
/* vec_vpkpx */
static vector pixel __attribute__((__always_inline__))
-vec_vpkpx(vector unsigned int a, vector unsigned int b)
+vec_vpkpx(vector unsigned int __a, vector unsigned int __b)
{
- return (vector pixel)__builtin_altivec_vpkpx(a, b);
+ return (vector pixel)__builtin_altivec_vpkpx(__a, __b);
}
/* vec_packs */
static vector signed char __ATTRS_o_ai
-vec_packs(vector short a, vector short b)
+vec_packs(vector short __a, vector short __b)
{
- return __builtin_altivec_vpkshss(a, b);
+ return __builtin_altivec_vpkshss(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_packs(vector unsigned short a, vector unsigned short b)
+vec_packs(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vpkuhus(a, b);
+ return __builtin_altivec_vpkuhus(__a, __b);
}
static vector signed short __ATTRS_o_ai
-vec_packs(vector int a, vector int b)
+vec_packs(vector int __a, vector int __b)
{
- return __builtin_altivec_vpkswss(a, b);
+ return __builtin_altivec_vpkswss(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_packs(vector unsigned int a, vector unsigned int b)
+vec_packs(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vpkuwus(a, b);
+ return __builtin_altivec_vpkuwus(__a, __b);
}
/* vec_vpkshss */
static vector signed char __attribute__((__always_inline__))
-vec_vpkshss(vector short a, vector short b)
+vec_vpkshss(vector short __a, vector short __b)
{
- return __builtin_altivec_vpkshss(a, b);
+ return __builtin_altivec_vpkshss(__a, __b);
}
/* vec_vpkuhus */
static vector unsigned char __attribute__((__always_inline__))
-vec_vpkuhus(vector unsigned short a, vector unsigned short b)
+vec_vpkuhus(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vpkuhus(a, b);
+ return __builtin_altivec_vpkuhus(__a, __b);
}
/* vec_vpkswss */
static vector signed short __attribute__((__always_inline__))
-vec_vpkswss(vector int a, vector int b)
+vec_vpkswss(vector int __a, vector int __b)
{
- return __builtin_altivec_vpkswss(a, b);
+ return __builtin_altivec_vpkswss(__a, __b);
}
/* vec_vpkuwus */
static vector unsigned short __attribute__((__always_inline__))
-vec_vpkuwus(vector unsigned int a, vector unsigned int b)
+vec_vpkuwus(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vpkuwus(a, b);
+ return __builtin_altivec_vpkuwus(__a, __b);
}
/* vec_packsu */
static vector unsigned char __ATTRS_o_ai
-vec_packsu(vector short a, vector short b)
+vec_packsu(vector short __a, vector short __b)
{
- return __builtin_altivec_vpkshus(a, b);
+ return __builtin_altivec_vpkshus(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_packsu(vector unsigned short a, vector unsigned short b)
+vec_packsu(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vpkuhus(a, b);
+ return __builtin_altivec_vpkuhus(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_packsu(vector int a, vector int b)
+vec_packsu(vector int __a, vector int __b)
{
- return __builtin_altivec_vpkswus(a, b);
+ return __builtin_altivec_vpkswus(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_packsu(vector unsigned int a, vector unsigned int b)
+vec_packsu(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vpkuwus(a, b);
+ return __builtin_altivec_vpkuwus(__a, __b);
}
/* vec_vpkshus */
static vector unsigned char __ATTRS_o_ai
-vec_vpkshus(vector short a, vector short b)
+vec_vpkshus(vector short __a, vector short __b)
{
- return __builtin_altivec_vpkshus(a, b);
+ return __builtin_altivec_vpkshus(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vpkshus(vector unsigned short a, vector unsigned short b)
+vec_vpkshus(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vpkuhus(a, b);
+ return __builtin_altivec_vpkuhus(__a, __b);
}
/* vec_vpkswus */
static vector unsigned short __ATTRS_o_ai
-vec_vpkswus(vector int a, vector int b)
+vec_vpkswus(vector int __a, vector int __b)
{
- return __builtin_altivec_vpkswus(a, b);
+ return __builtin_altivec_vpkswus(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vpkswus(vector unsigned int a, vector unsigned int b)
+vec_vpkswus(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vpkuwus(a, b);
+ return __builtin_altivec_vpkuwus(__a, __b);
}
/* vec_perm */
vector signed char __ATTRS_o_ai
-vec_perm(vector signed char a, vector signed char b, vector unsigned char c)
+vec_perm(vector signed char __a, vector signed char __b, vector unsigned char __c)
{
return (vector signed char)
- __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
vector unsigned char __ATTRS_o_ai
-vec_perm(vector unsigned char a,
- vector unsigned char b,
- vector unsigned char c)
+vec_perm(vector unsigned char __a,
+ vector unsigned char __b,
+ vector unsigned char __c)
{
return (vector unsigned char)
- __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
vector bool char __ATTRS_o_ai
-vec_perm(vector bool char a, vector bool char b, vector unsigned char c)
+vec_perm(vector bool char __a, vector bool char __b, vector unsigned char __c)
{
return (vector bool char)
- __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
vector short __ATTRS_o_ai
-vec_perm(vector short a, vector short b, vector unsigned char c)
+vec_perm(vector short __a, vector short __b, vector unsigned char __c)
{
return (vector short)
- __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
vector unsigned short __ATTRS_o_ai
-vec_perm(vector unsigned short a,
- vector unsigned short b,
- vector unsigned char c)
+vec_perm(vector unsigned short __a,
+ vector unsigned short __b,
+ vector unsigned char __c)
{
return (vector unsigned short)
- __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
vector bool short __ATTRS_o_ai
-vec_perm(vector bool short a, vector bool short b, vector unsigned char c)
+vec_perm(vector bool short __a, vector bool short __b, vector unsigned char __c)
{
return (vector bool short)
- __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
vector pixel __ATTRS_o_ai
-vec_perm(vector pixel a, vector pixel b, vector unsigned char c)
+vec_perm(vector pixel __a, vector pixel __b, vector unsigned char __c)
{
return (vector pixel)
- __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
vector int __ATTRS_o_ai
-vec_perm(vector int a, vector int b, vector unsigned char c)
+vec_perm(vector int __a, vector int __b, vector unsigned char __c)
{
- return (vector int)__builtin_altivec_vperm_4si(a, b, c);
+ return (vector int)__builtin_altivec_vperm_4si(__a, __b, __c);
}
vector unsigned int __ATTRS_o_ai
-vec_perm(vector unsigned int a, vector unsigned int b, vector unsigned char c)
+vec_perm(vector unsigned int __a, vector unsigned int __b, vector unsigned char __c)
{
return (vector unsigned int)
- __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
vector bool int __ATTRS_o_ai
-vec_perm(vector bool int a, vector bool int b, vector unsigned char c)
+vec_perm(vector bool int __a, vector bool int __b, vector unsigned char __c)
{
return (vector bool int)
- __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
vector float __ATTRS_o_ai
-vec_perm(vector float a, vector float b, vector unsigned char c)
+vec_perm(vector float __a, vector float __b, vector unsigned char __c)
{
return (vector float)
- __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
/* vec_vperm */
static vector signed char __ATTRS_o_ai
-vec_vperm(vector signed char a, vector signed char b, vector unsigned char c)
+vec_vperm(vector signed char __a, vector signed char __b, vector unsigned char __c)
{
return (vector signed char)
- __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
static vector unsigned char __ATTRS_o_ai
-vec_vperm(vector unsigned char a,
- vector unsigned char b,
- vector unsigned char c)
+vec_vperm(vector unsigned char __a,
+ vector unsigned char __b,
+ vector unsigned char __c)
{
return (vector unsigned char)
- __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
static vector bool char __ATTRS_o_ai
-vec_vperm(vector bool char a, vector bool char b, vector unsigned char c)
+vec_vperm(vector bool char __a, vector bool char __b, vector unsigned char __c)
{
return (vector bool char)
- __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
static vector short __ATTRS_o_ai
-vec_vperm(vector short a, vector short b, vector unsigned char c)
+vec_vperm(vector short __a, vector short __b, vector unsigned char __c)
{
return (vector short)
- __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
static vector unsigned short __ATTRS_o_ai
-vec_vperm(vector unsigned short a,
- vector unsigned short b,
- vector unsigned char c)
+vec_vperm(vector unsigned short __a,
+ vector unsigned short __b,
+ vector unsigned char __c)
{
return (vector unsigned short)
- __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
static vector bool short __ATTRS_o_ai
-vec_vperm(vector bool short a, vector bool short b, vector unsigned char c)
+vec_vperm(vector bool short __a, vector bool short __b, vector unsigned char __c)
{
return (vector bool short)
- __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
static vector pixel __ATTRS_o_ai
-vec_vperm(vector pixel a, vector pixel b, vector unsigned char c)
+vec_vperm(vector pixel __a, vector pixel __b, vector unsigned char __c)
{
return (vector pixel)
- __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
static vector int __ATTRS_o_ai
-vec_vperm(vector int a, vector int b, vector unsigned char c)
+vec_vperm(vector int __a, vector int __b, vector unsigned char __c)
{
- return (vector int)__builtin_altivec_vperm_4si(a, b, c);
+ return (vector int)__builtin_altivec_vperm_4si(__a, __b, __c);
}
static vector unsigned int __ATTRS_o_ai
-vec_vperm(vector unsigned int a, vector unsigned int b, vector unsigned char c)
+vec_vperm(vector unsigned int __a, vector unsigned int __b, vector unsigned char __c)
{
return (vector unsigned int)
- __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
static vector bool int __ATTRS_o_ai
-vec_vperm(vector bool int a, vector bool int b, vector unsigned char c)
+vec_vperm(vector bool int __a, vector bool int __b, vector unsigned char __c)
{
return (vector bool int)
- __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
static vector float __ATTRS_o_ai
-vec_vperm(vector float a, vector float b, vector unsigned char c)
+vec_vperm(vector float __a, vector float __b, vector unsigned char __c)
{
return (vector float)
- __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c);
+ __builtin_altivec_vperm_4si((vector int)__a, (vector int)__b, __c);
}
/* vec_re */
static vector float __attribute__((__always_inline__))
-vec_re(vector float a)
+vec_re(vector float __a)
{
- return __builtin_altivec_vrefp(a);
+ return __builtin_altivec_vrefp(__a);
}
/* vec_vrefp */
static vector float __attribute__((__always_inline__))
-vec_vrefp(vector float a)
+vec_vrefp(vector float __a)
{
- return __builtin_altivec_vrefp(a);
+ return __builtin_altivec_vrefp(__a);
}
/* vec_rl */
static vector signed char __ATTRS_o_ai
-vec_rl(vector signed char a, vector unsigned char b)
+vec_rl(vector signed char __a, vector unsigned char __b)
{
- return (vector signed char)__builtin_altivec_vrlb((vector char)a, b);
+ return (vector signed char)__builtin_altivec_vrlb((vector char)__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_rl(vector unsigned char a, vector unsigned char b)
+vec_rl(vector unsigned char __a, vector unsigned char __b)
{
- return (vector unsigned char)__builtin_altivec_vrlb((vector char)a, b);
+ return (vector unsigned char)__builtin_altivec_vrlb((vector char)__a, __b);
}
static vector short __ATTRS_o_ai
-vec_rl(vector short a, vector unsigned short b)
+vec_rl(vector short __a, vector unsigned short __b)
{
- return __builtin_altivec_vrlh(a, b);
+ return __builtin_altivec_vrlh(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_rl(vector unsigned short a, vector unsigned short b)
+vec_rl(vector unsigned short __a, vector unsigned short __b)
{
- return (vector unsigned short)__builtin_altivec_vrlh((vector short)a, b);
+ return (vector unsigned short)__builtin_altivec_vrlh((vector short)__a, __b);
}
static vector int __ATTRS_o_ai
-vec_rl(vector int a, vector unsigned int b)
+vec_rl(vector int __a, vector unsigned int __b)
{
- return __builtin_altivec_vrlw(a, b);
+ return __builtin_altivec_vrlw(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_rl(vector unsigned int a, vector unsigned int b)
+vec_rl(vector unsigned int __a, vector unsigned int __b)
{
- return (vector unsigned int)__builtin_altivec_vrlw((vector int)a, b);
+ return (vector unsigned int)__builtin_altivec_vrlw((vector int)__a, __b);
}
/* vec_vrlb */
static vector signed char __ATTRS_o_ai
-vec_vrlb(vector signed char a, vector unsigned char b)
+vec_vrlb(vector signed char __a, vector unsigned char __b)
{
- return (vector signed char)__builtin_altivec_vrlb((vector char)a, b);
+ return (vector signed char)__builtin_altivec_vrlb((vector char)__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vrlb(vector unsigned char a, vector unsigned char b)
+vec_vrlb(vector unsigned char __a, vector unsigned char __b)
{
- return (vector unsigned char)__builtin_altivec_vrlb((vector char)a, b);
+ return (vector unsigned char)__builtin_altivec_vrlb((vector char)__a, __b);
}
/* vec_vrlh */
static vector short __ATTRS_o_ai
-vec_vrlh(vector short a, vector unsigned short b)
+vec_vrlh(vector short __a, vector unsigned short __b)
{
- return __builtin_altivec_vrlh(a, b);
+ return __builtin_altivec_vrlh(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vrlh(vector unsigned short a, vector unsigned short b)
+vec_vrlh(vector unsigned short __a, vector unsigned short __b)
{
- return (vector unsigned short)__builtin_altivec_vrlh((vector short)a, b);
+ return (vector unsigned short)__builtin_altivec_vrlh((vector short)__a, __b);
}
/* vec_vrlw */
static vector int __ATTRS_o_ai
-vec_vrlw(vector int a, vector unsigned int b)
+vec_vrlw(vector int __a, vector unsigned int __b)
{
- return __builtin_altivec_vrlw(a, b);
+ return __builtin_altivec_vrlw(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vrlw(vector unsigned int a, vector unsigned int b)
+vec_vrlw(vector unsigned int __a, vector unsigned int __b)
{
- return (vector unsigned int)__builtin_altivec_vrlw((vector int)a, b);
+ return (vector unsigned int)__builtin_altivec_vrlw((vector int)__a, __b);
}
/* vec_round */
static vector float __attribute__((__always_inline__))
-vec_round(vector float a)
+vec_round(vector float __a)
{
- return __builtin_altivec_vrfin(a);
+ return __builtin_altivec_vrfin(__a);
}
/* vec_vrfin */
static vector float __attribute__((__always_inline__))
-vec_vrfin(vector float a)
+vec_vrfin(vector float __a)
{
- return __builtin_altivec_vrfin(a);
+ return __builtin_altivec_vrfin(__a);
}
/* vec_rsqrte */
static __vector float __attribute__((__always_inline__))
-vec_rsqrte(vector float a)
+vec_rsqrte(vector float __a)
{
- return __builtin_altivec_vrsqrtefp(a);
+ return __builtin_altivec_vrsqrtefp(__a);
}
/* vec_vrsqrtefp */
static __vector float __attribute__((__always_inline__))
-vec_vrsqrtefp(vector float a)
+vec_vrsqrtefp(vector float __a)
{
- return __builtin_altivec_vrsqrtefp(a);
+ return __builtin_altivec_vrsqrtefp(__a);
}
/* vec_sel */
@@ -4576,295 +4576,295 @@ vec_vrsqrtefp(vector float a)
#define __builtin_altivec_vsel_4si vec_sel
static vector signed char __ATTRS_o_ai
-vec_sel(vector signed char a, vector signed char b, vector unsigned char c)
+vec_sel(vector signed char __a, vector signed char __b, vector unsigned char __c)
{
- return (a & ~(vector signed char)c) | (b & (vector signed char)c);
+ return (__a & ~(vector signed char)__c) | (__b & (vector signed char)__c);
}
static vector signed char __ATTRS_o_ai
-vec_sel(vector signed char a, vector signed char b, vector bool char c)
+vec_sel(vector signed char __a, vector signed char __b, vector bool char __c)
{
- return (a & ~(vector signed char)c) | (b & (vector signed char)c);
+ return (__a & ~(vector signed char)__c) | (__b & (vector signed char)__c);
}
static vector unsigned char __ATTRS_o_ai
-vec_sel(vector unsigned char a, vector unsigned char b, vector unsigned char c)
+vec_sel(vector unsigned char __a, vector unsigned char __b, vector unsigned char __c)
{
- return (a & ~c) | (b & c);
+ return (__a & ~__c) | (__b & __c);
}
static vector unsigned char __ATTRS_o_ai
-vec_sel(vector unsigned char a, vector unsigned char b, vector bool char c)
+vec_sel(vector unsigned char __a, vector unsigned char __b, vector bool char __c)
{
- return (a & ~(vector unsigned char)c) | (b & (vector unsigned char)c);
+ return (__a & ~(vector unsigned char)__c) | (__b & (vector unsigned char)__c);
}
static vector bool char __ATTRS_o_ai
-vec_sel(vector bool char a, vector bool char b, vector unsigned char c)
+vec_sel(vector bool char __a, vector bool char __b, vector unsigned char __c)
{
- return (a & ~(vector bool char)c) | (b & (vector bool char)c);
+ return (__a & ~(vector bool char)__c) | (__b & (vector bool char)__c);
}
static vector bool char __ATTRS_o_ai
-vec_sel(vector bool char a, vector bool char b, vector bool char c)
+vec_sel(vector bool char __a, vector bool char __b, vector bool char __c)
{
- return (a & ~c) | (b & c);
+ return (__a & ~__c) | (__b & __c);
}
static vector short __ATTRS_o_ai
-vec_sel(vector short a, vector short b, vector unsigned short c)
+vec_sel(vector short __a, vector short __b, vector unsigned short __c)
{
- return (a & ~(vector short)c) | (b & (vector short)c);
+ return (__a & ~(vector short)__c) | (__b & (vector short)__c);
}
static vector short __ATTRS_o_ai
-vec_sel(vector short a, vector short b, vector bool short c)
+vec_sel(vector short __a, vector short __b, vector bool short __c)
{
- return (a & ~(vector short)c) | (b & (vector short)c);
+ return (__a & ~(vector short)__c) | (__b & (vector short)__c);
}
static vector unsigned short __ATTRS_o_ai
-vec_sel(vector unsigned short a,
- vector unsigned short b,
- vector unsigned short c)
+vec_sel(vector unsigned short __a,
+ vector unsigned short __b,
+ vector unsigned short __c)
{
- return (a & ~c) | (b & c);
+ return (__a & ~__c) | (__b & __c);
}
static vector unsigned short __ATTRS_o_ai
-vec_sel(vector unsigned short a, vector unsigned short b, vector bool short c)
+vec_sel(vector unsigned short __a, vector unsigned short __b, vector bool short __c)
{
- return (a & ~(vector unsigned short)c) | (b & (vector unsigned short)c);
+ return (__a & ~(vector unsigned short)__c) | (__b & (vector unsigned short)__c);
}
static vector bool short __ATTRS_o_ai
-vec_sel(vector bool short a, vector bool short b, vector unsigned short c)
+vec_sel(vector bool short __a, vector bool short __b, vector unsigned short __c)
{
- return (a & ~(vector bool short)c) | (b & (vector bool short)c);
+ return (__a & ~(vector bool short)__c) | (__b & (vector bool short)__c);
}
static vector bool short __ATTRS_o_ai
-vec_sel(vector bool short a, vector bool short b, vector bool short c)
+vec_sel(vector bool short __a, vector bool short __b, vector bool short __c)
{
- return (a & ~c) | (b & c);
+ return (__a & ~__c) | (__b & __c);
}
static vector int __ATTRS_o_ai
-vec_sel(vector int a, vector int b, vector unsigned int c)
+vec_sel(vector int __a, vector int __b, vector unsigned int __c)
{
- return (a & ~(vector int)c) | (b & (vector int)c);
+ return (__a & ~(vector int)__c) | (__b & (vector int)__c);
}
static vector int __ATTRS_o_ai
-vec_sel(vector int a, vector int b, vector bool int c)
+vec_sel(vector int __a, vector int __b, vector bool int __c)
{
- return (a & ~(vector int)c) | (b & (vector int)c);
+ return (__a & ~(vector int)__c) | (__b & (vector int)__c);
}
static vector unsigned int __ATTRS_o_ai
-vec_sel(vector unsigned int a, vector unsigned int b, vector unsigned int c)
+vec_sel(vector unsigned int __a, vector unsigned int __b, vector unsigned int __c)
{
- return (a & ~c) | (b & c);
+ return (__a & ~__c) | (__b & __c);
}
static vector unsigned int __ATTRS_o_ai
-vec_sel(vector unsigned int a, vector unsigned int b, vector bool int c)
+vec_sel(vector unsigned int __a, vector unsigned int __b, vector bool int __c)
{
- return (a & ~(vector unsigned int)c) | (b & (vector unsigned int)c);
+ return (__a & ~(vector unsigned int)__c) | (__b & (vector unsigned int)__c);
}
static vector bool int __ATTRS_o_ai
-vec_sel(vector bool int a, vector bool int b, vector unsigned int c)
+vec_sel(vector bool int __a, vector bool int __b, vector unsigned int __c)
{
- return (a & ~(vector bool int)c) | (b & (vector bool int)c);
+ return (__a & ~(vector bool int)__c) | (__b & (vector bool int)__c);
}
static vector bool int __ATTRS_o_ai
-vec_sel(vector bool int a, vector bool int b, vector bool int c)
+vec_sel(vector bool int __a, vector bool int __b, vector bool int __c)
{
- return (a & ~c) | (b & c);
+ return (__a & ~__c) | (__b & __c);
}
static vector float __ATTRS_o_ai
-vec_sel(vector float a, vector float b, vector unsigned int c)
+vec_sel(vector float __a, vector float __b, vector unsigned int __c)
{
- vector int res = ((vector int)a & ~(vector int)c)
- | ((vector int)b & (vector int)c);
- return (vector float)res;
+ vector int __res = ((vector int)__a & ~(vector int)__c)
+ | ((vector int)__b & (vector int)__c);
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_sel(vector float a, vector float b, vector bool int c)
+vec_sel(vector float __a, vector float __b, vector bool int __c)
{
- vector int res = ((vector int)a & ~(vector int)c)
- | ((vector int)b & (vector int)c);
- return (vector float)res;
+ vector int __res = ((vector int)__a & ~(vector int)__c)
+ | ((vector int)__b & (vector int)__c);
+ return (vector float)__res;
}
/* vec_vsel */
static vector signed char __ATTRS_o_ai
-vec_vsel(vector signed char a, vector signed char b, vector unsigned char c)
+vec_vsel(vector signed char __a, vector signed char __b, vector unsigned char __c)
{
- return (a & ~(vector signed char)c) | (b & (vector signed char)c);
+ return (__a & ~(vector signed char)__c) | (__b & (vector signed char)__c);
}
static vector signed char __ATTRS_o_ai
-vec_vsel(vector signed char a, vector signed char b, vector bool char c)
+vec_vsel(vector signed char __a, vector signed char __b, vector bool char __c)
{
- return (a & ~(vector signed char)c) | (b & (vector signed char)c);
+ return (__a & ~(vector signed char)__c) | (__b & (vector signed char)__c);
}
static vector unsigned char __ATTRS_o_ai
-vec_vsel(vector unsigned char a, vector unsigned char b, vector unsigned char c)
+vec_vsel(vector unsigned char __a, vector unsigned char __b, vector unsigned char __c)
{
- return (a & ~c) | (b & c);
+ return (__a & ~__c) | (__b & __c);
}
static vector unsigned char __ATTRS_o_ai
-vec_vsel(vector unsigned char a, vector unsigned char b, vector bool char c)
+vec_vsel(vector unsigned char __a, vector unsigned char __b, vector bool char __c)
{
- return (a & ~(vector unsigned char)c) | (b & (vector unsigned char)c);
+ return (__a & ~(vector unsigned char)__c) | (__b & (vector unsigned char)__c);
}
static vector bool char __ATTRS_o_ai
-vec_vsel(vector bool char a, vector bool char b, vector unsigned char c)
+vec_vsel(vector bool char __a, vector bool char __b, vector unsigned char __c)
{
- return (a & ~(vector bool char)c) | (b & (vector bool char)c);
+ return (__a & ~(vector bool char)__c) | (__b & (vector bool char)__c);
}
static vector bool char __ATTRS_o_ai
-vec_vsel(vector bool char a, vector bool char b, vector bool char c)
+vec_vsel(vector bool char __a, vector bool char __b, vector bool char __c)
{
- return (a & ~c) | (b & c);
+ return (__a & ~__c) | (__b & __c);
}
static vector short __ATTRS_o_ai
-vec_vsel(vector short a, vector short b, vector unsigned short c)
+vec_vsel(vector short __a, vector short __b, vector unsigned short __c)
{
- return (a & ~(vector short)c) | (b & (vector short)c);
+ return (__a & ~(vector short)__c) | (__b & (vector short)__c);
}
static vector short __ATTRS_o_ai
-vec_vsel(vector short a, vector short b, vector bool short c)
+vec_vsel(vector short __a, vector short __b, vector bool short __c)
{
- return (a & ~(vector short)c) | (b & (vector short)c);
+ return (__a & ~(vector short)__c) | (__b & (vector short)__c);
}
static vector unsigned short __ATTRS_o_ai
-vec_vsel(vector unsigned short a,
- vector unsigned short b,
- vector unsigned short c)
+vec_vsel(vector unsigned short __a,
+ vector unsigned short __b,
+ vector unsigned short __c)
{
- return (a & ~c) | (b & c);
+ return (__a & ~__c) | (__b & __c);
}
static vector unsigned short __ATTRS_o_ai
-vec_vsel(vector unsigned short a, vector unsigned short b, vector bool short c)
+vec_vsel(vector unsigned short __a, vector unsigned short __b, vector bool short __c)
{
- return (a & ~(vector unsigned short)c) | (b & (vector unsigned short)c);
+ return (__a & ~(vector unsigned short)__c) | (__b & (vector unsigned short)__c);
}
static vector bool short __ATTRS_o_ai
-vec_vsel(vector bool short a, vector bool short b, vector unsigned short c)
+vec_vsel(vector bool short __a, vector bool short __b, vector unsigned short __c)
{
- return (a & ~(vector bool short)c) | (b & (vector bool short)c);
+ return (__a & ~(vector bool short)__c) | (__b & (vector bool short)__c);
}
static vector bool short __ATTRS_o_ai
-vec_vsel(vector bool short a, vector bool short b, vector bool short c)
+vec_vsel(vector bool short __a, vector bool short __b, vector bool short __c)
{
- return (a & ~c) | (b & c);
+ return (__a & ~__c) | (__b & __c);
}
static vector int __ATTRS_o_ai
-vec_vsel(vector int a, vector int b, vector unsigned int c)
+vec_vsel(vector int __a, vector int __b, vector unsigned int __c)
{
- return (a & ~(vector int)c) | (b & (vector int)c);
+ return (__a & ~(vector int)__c) | (__b & (vector int)__c);
}
static vector int __ATTRS_o_ai
-vec_vsel(vector int a, vector int b, vector bool int c)
+vec_vsel(vector int __a, vector int __b, vector bool int __c)
{
- return (a & ~(vector int)c) | (b & (vector int)c);
+ return (__a & ~(vector int)__c) | (__b & (vector int)__c);
}
static vector unsigned int __ATTRS_o_ai
-vec_vsel(vector unsigned int a, vector unsigned int b, vector unsigned int c)
+vec_vsel(vector unsigned int __a, vector unsigned int __b, vector unsigned int __c)
{
- return (a & ~c) | (b & c);
+ return (__a & ~__c) | (__b & __c);
}
static vector unsigned int __ATTRS_o_ai
-vec_vsel(vector unsigned int a, vector unsigned int b, vector bool int c)
+vec_vsel(vector unsigned int __a, vector unsigned int __b, vector bool int __c)
{
- return (a & ~(vector unsigned int)c) | (b & (vector unsigned int)c);
+ return (__a & ~(vector unsigned int)__c) | (__b & (vector unsigned int)__c);
}
static vector bool int __ATTRS_o_ai
-vec_vsel(vector bool int a, vector bool int b, vector unsigned int c)
+vec_vsel(vector bool int __a, vector bool int __b, vector unsigned int __c)
{
- return (a & ~(vector bool int)c) | (b & (vector bool int)c);
+ return (__a & ~(vector bool int)__c) | (__b & (vector bool int)__c);
}
static vector bool int __ATTRS_o_ai
-vec_vsel(vector bool int a, vector bool int b, vector bool int c)
+vec_vsel(vector bool int __a, vector bool int __b, vector bool int __c)
{
- return (a & ~c) | (b & c);
+ return (__a & ~__c) | (__b & __c);
}
static vector float __ATTRS_o_ai
-vec_vsel(vector float a, vector float b, vector unsigned int c)
+vec_vsel(vector float __a, vector float __b, vector unsigned int __c)
{
- vector int res = ((vector int)a & ~(vector int)c)
- | ((vector int)b & (vector int)c);
- return (vector float)res;
+ vector int __res = ((vector int)__a & ~(vector int)__c)
+ | ((vector int)__b & (vector int)__c);
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_vsel(vector float a, vector float b, vector bool int c)
+vec_vsel(vector float __a, vector float __b, vector bool int __c)
{
- vector int res = ((vector int)a & ~(vector int)c)
- | ((vector int)b & (vector int)c);
- return (vector float)res;
+ vector int __res = ((vector int)__a & ~(vector int)__c)
+ | ((vector int)__b & (vector int)__c);
+ return (vector float)__res;
}
/* vec_sl */
static vector signed char __ATTRS_o_ai
-vec_sl(vector signed char a, vector unsigned char b)
+vec_sl(vector signed char __a, vector unsigned char __b)
{
- return a << (vector signed char)b;
+ return __a << (vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_sl(vector unsigned char a, vector unsigned char b)
+vec_sl(vector unsigned char __a, vector unsigned char __b)
{
- return a << b;
+ return __a << __b;
}
static vector short __ATTRS_o_ai
-vec_sl(vector short a, vector unsigned short b)
+vec_sl(vector short __a, vector unsigned short __b)
{
- return a << (vector short)b;
+ return __a << (vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_sl(vector unsigned short a, vector unsigned short b)
+vec_sl(vector unsigned short __a, vector unsigned short __b)
{
- return a << b;
+ return __a << __b;
}
static vector int __ATTRS_o_ai
-vec_sl(vector int a, vector unsigned int b)
+vec_sl(vector int __a, vector unsigned int __b)
{
- return a << (vector int)b;
+ return __a << (vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_sl(vector unsigned int a, vector unsigned int b)
+vec_sl(vector unsigned int __a, vector unsigned int __b)
{
- return a << b;
+ return __a << __b;
}
/* vec_vslb */
@@ -4872,15 +4872,15 @@ vec_sl(vector unsigned int a, vector unsigned int b)
#define __builtin_altivec_vslb vec_vslb
static vector signed char __ATTRS_o_ai
-vec_vslb(vector signed char a, vector unsigned char b)
+vec_vslb(vector signed char __a, vector unsigned char __b)
{
- return vec_sl(a, b);
+ return vec_sl(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vslb(vector unsigned char a, vector unsigned char b)
+vec_vslb(vector unsigned char __a, vector unsigned char __b)
{
- return vec_sl(a, b);
+ return vec_sl(__a, __b);
}
/* vec_vslh */
@@ -4888,15 +4888,15 @@ vec_vslb(vector unsigned char a, vector unsigned char b)
#define __builtin_altivec_vslh vec_vslh
static vector short __ATTRS_o_ai
-vec_vslh(vector short a, vector unsigned short b)
+vec_vslh(vector short __a, vector unsigned short __b)
{
- return vec_sl(a, b);
+ return vec_sl(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vslh(vector unsigned short a, vector unsigned short b)
+vec_vslh(vector unsigned short __a, vector unsigned short __b)
{
- return vec_sl(a, b);
+ return vec_sl(__a, __b);
}
/* vec_vslw */
@@ -4904,15 +4904,15 @@ vec_vslh(vector unsigned short a, vector unsigned short b)
#define __builtin_altivec_vslw vec_vslw
static vector int __ATTRS_o_ai
-vec_vslw(vector int a, vector unsigned int b)
+vec_vslw(vector int __a, vector unsigned int __b)
{
- return vec_sl(a, b);
+ return vec_sl(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vslw(vector unsigned int a, vector unsigned int b)
+vec_vslw(vector unsigned int __a, vector unsigned int __b)
{
- return vec_sl(a, b);
+ return vec_sl(__a, __b);
}
/* vec_sld */
@@ -4920,825 +4920,825 @@ vec_vslw(vector unsigned int a, vector unsigned int b)
#define __builtin_altivec_vsldoi_4si vec_sld
static vector signed char __ATTRS_o_ai
-vec_sld(vector signed char a, vector signed char b, unsigned char c)
+vec_sld(vector signed char __a, vector signed char __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
static vector unsigned char __ATTRS_o_ai
-vec_sld(vector unsigned char a, vector unsigned char b, unsigned char c)
+vec_sld(vector unsigned char __a, vector unsigned char __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
static vector short __ATTRS_o_ai
-vec_sld(vector short a, vector short b, unsigned char c)
+vec_sld(vector short __a, vector short __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
static vector unsigned short __ATTRS_o_ai
-vec_sld(vector unsigned short a, vector unsigned short b, unsigned char c)
+vec_sld(vector unsigned short __a, vector unsigned short __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
static vector pixel __ATTRS_o_ai
-vec_sld(vector pixel a, vector pixel b, unsigned char c)
+vec_sld(vector pixel __a, vector pixel __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
static vector int __ATTRS_o_ai
-vec_sld(vector int a, vector int b, unsigned char c)
+vec_sld(vector int __a, vector int __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
static vector unsigned int __ATTRS_o_ai
-vec_sld(vector unsigned int a, vector unsigned int b, unsigned char c)
+vec_sld(vector unsigned int __a, vector unsigned int __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
static vector float __ATTRS_o_ai
-vec_sld(vector float a, vector float b, unsigned char c)
+vec_sld(vector float __a, vector float __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
/* vec_vsldoi */
static vector signed char __ATTRS_o_ai
-vec_vsldoi(vector signed char a, vector signed char b, unsigned char c)
+vec_vsldoi(vector signed char __a, vector signed char __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
static vector unsigned char __ATTRS_o_ai
-vec_vsldoi(vector unsigned char a, vector unsigned char b, unsigned char c)
+vec_vsldoi(vector unsigned char __a, vector unsigned char __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
static vector short __ATTRS_o_ai
-vec_vsldoi(vector short a, vector short b, unsigned char c)
+vec_vsldoi(vector short __a, vector short __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
static vector unsigned short __ATTRS_o_ai
-vec_vsldoi(vector unsigned short a, vector unsigned short b, unsigned char c)
+vec_vsldoi(vector unsigned short __a, vector unsigned short __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
static vector pixel __ATTRS_o_ai
-vec_vsldoi(vector pixel a, vector pixel b, unsigned char c)
+vec_vsldoi(vector pixel __a, vector pixel __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
static vector int __ATTRS_o_ai
-vec_vsldoi(vector int a, vector int b, unsigned char c)
+vec_vsldoi(vector int __a, vector int __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
static vector unsigned int __ATTRS_o_ai
-vec_vsldoi(vector unsigned int a, vector unsigned int b, unsigned char c)
+vec_vsldoi(vector unsigned int __a, vector unsigned int __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
static vector float __ATTRS_o_ai
-vec_vsldoi(vector float a, vector float b, unsigned char c)
+vec_vsldoi(vector float __a, vector float __b, unsigned char __c)
{
- return vec_perm(a, b, (vector unsigned char)
- (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7,
- c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15));
+ return vec_perm(__a, __b, (vector unsigned char)
+ (__c, __c+1, __c+2, __c+3, __c+4, __c+5, __c+6, __c+7,
+ __c+8, __c+9, __c+10, __c+11, __c+12, __c+13, __c+14, __c+15));
}
/* vec_sll */
static vector signed char __ATTRS_o_ai
-vec_sll(vector signed char a, vector unsigned char b)
+vec_sll(vector signed char __a, vector unsigned char __b)
{
return (vector signed char)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector signed char __ATTRS_o_ai
-vec_sll(vector signed char a, vector unsigned short b)
+vec_sll(vector signed char __a, vector unsigned short __b)
{
return (vector signed char)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector signed char __ATTRS_o_ai
-vec_sll(vector signed char a, vector unsigned int b)
+vec_sll(vector signed char __a, vector unsigned int __b)
{
return (vector signed char)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_sll(vector unsigned char a, vector unsigned char b)
+vec_sll(vector unsigned char __a, vector unsigned char __b)
{
return (vector unsigned char)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_sll(vector unsigned char a, vector unsigned short b)
+vec_sll(vector unsigned char __a, vector unsigned short __b)
{
return (vector unsigned char)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_sll(vector unsigned char a, vector unsigned int b)
+vec_sll(vector unsigned char __a, vector unsigned int __b)
{
return (vector unsigned char)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool char __ATTRS_o_ai
-vec_sll(vector bool char a, vector unsigned char b)
+vec_sll(vector bool char __a, vector unsigned char __b)
{
- return (vector bool char)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool char)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool char __ATTRS_o_ai
-vec_sll(vector bool char a, vector unsigned short b)
+vec_sll(vector bool char __a, vector unsigned short __b)
{
- return (vector bool char)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool char)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool char __ATTRS_o_ai
-vec_sll(vector bool char a, vector unsigned int b)
+vec_sll(vector bool char __a, vector unsigned int __b)
{
- return (vector bool char)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool char)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_sll(vector short a, vector unsigned char b)
+vec_sll(vector short __a, vector unsigned char __b)
{
- return (vector short)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_sll(vector short a, vector unsigned short b)
+vec_sll(vector short __a, vector unsigned short __b)
{
- return (vector short)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_sll(vector short a, vector unsigned int b)
+vec_sll(vector short __a, vector unsigned int __b)
{
- return (vector short)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_sll(vector unsigned short a, vector unsigned char b)
+vec_sll(vector unsigned short __a, vector unsigned char __b)
{
return (vector unsigned short)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_sll(vector unsigned short a, vector unsigned short b)
+vec_sll(vector unsigned short __a, vector unsigned short __b)
{
return (vector unsigned short)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_sll(vector unsigned short a, vector unsigned int b)
+vec_sll(vector unsigned short __a, vector unsigned int __b)
{
return (vector unsigned short)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool short __ATTRS_o_ai
-vec_sll(vector bool short a, vector unsigned char b)
+vec_sll(vector bool short __a, vector unsigned char __b)
{
- return (vector bool short)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool short)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool short __ATTRS_o_ai
-vec_sll(vector bool short a, vector unsigned short b)
+vec_sll(vector bool short __a, vector unsigned short __b)
{
- return (vector bool short)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool short)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool short __ATTRS_o_ai
-vec_sll(vector bool short a, vector unsigned int b)
+vec_sll(vector bool short __a, vector unsigned int __b)
{
- return (vector bool short)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool short)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_sll(vector pixel a, vector unsigned char b)
+vec_sll(vector pixel __a, vector unsigned char __b)
{
- return (vector pixel)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_sll(vector pixel a, vector unsigned short b)
+vec_sll(vector pixel __a, vector unsigned short __b)
{
- return (vector pixel)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_sll(vector pixel a, vector unsigned int b)
+vec_sll(vector pixel __a, vector unsigned int __b)
{
- return (vector pixel)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_sll(vector int a, vector unsigned char b)
+vec_sll(vector int __a, vector unsigned char __b)
{
- return (vector int)__builtin_altivec_vsl(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsl(__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_sll(vector int a, vector unsigned short b)
+vec_sll(vector int __a, vector unsigned short __b)
{
- return (vector int)__builtin_altivec_vsl(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsl(__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_sll(vector int a, vector unsigned int b)
+vec_sll(vector int __a, vector unsigned int __b)
{
- return (vector int)__builtin_altivec_vsl(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsl(__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_sll(vector unsigned int a, vector unsigned char b)
+vec_sll(vector unsigned int __a, vector unsigned char __b)
{
return (vector unsigned int)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_sll(vector unsigned int a, vector unsigned short b)
+vec_sll(vector unsigned int __a, vector unsigned short __b)
{
return (vector unsigned int)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_sll(vector unsigned int a, vector unsigned int b)
+vec_sll(vector unsigned int __a, vector unsigned int __b)
{
return (vector unsigned int)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool int __ATTRS_o_ai
-vec_sll(vector bool int a, vector unsigned char b)
+vec_sll(vector bool int __a, vector unsigned char __b)
{
- return (vector bool int)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool int)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool int __ATTRS_o_ai
-vec_sll(vector bool int a, vector unsigned short b)
+vec_sll(vector bool int __a, vector unsigned short __b)
{
- return (vector bool int)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool int)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool int __ATTRS_o_ai
-vec_sll(vector bool int a, vector unsigned int b)
+vec_sll(vector bool int __a, vector unsigned int __b)
{
- return (vector bool int)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool int)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
/* vec_vsl */
static vector signed char __ATTRS_o_ai
-vec_vsl(vector signed char a, vector unsigned char b)
+vec_vsl(vector signed char __a, vector unsigned char __b)
{
return (vector signed char)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector signed char __ATTRS_o_ai
-vec_vsl(vector signed char a, vector unsigned short b)
+vec_vsl(vector signed char __a, vector unsigned short __b)
{
return (vector signed char)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector signed char __ATTRS_o_ai
-vec_vsl(vector signed char a, vector unsigned int b)
+vec_vsl(vector signed char __a, vector unsigned int __b)
{
return (vector signed char)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vsl(vector unsigned char a, vector unsigned char b)
+vec_vsl(vector unsigned char __a, vector unsigned char __b)
{
return (vector unsigned char)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vsl(vector unsigned char a, vector unsigned short b)
+vec_vsl(vector unsigned char __a, vector unsigned short __b)
{
return (vector unsigned char)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vsl(vector unsigned char a, vector unsigned int b)
+vec_vsl(vector unsigned char __a, vector unsigned int __b)
{
return (vector unsigned char)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool char __ATTRS_o_ai
-vec_vsl(vector bool char a, vector unsigned char b)
+vec_vsl(vector bool char __a, vector unsigned char __b)
{
- return (vector bool char)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool char)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool char __ATTRS_o_ai
-vec_vsl(vector bool char a, vector unsigned short b)
+vec_vsl(vector bool char __a, vector unsigned short __b)
{
- return (vector bool char)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool char)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool char __ATTRS_o_ai
-vec_vsl(vector bool char a, vector unsigned int b)
+vec_vsl(vector bool char __a, vector unsigned int __b)
{
- return (vector bool char)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool char)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_vsl(vector short a, vector unsigned char b)
+vec_vsl(vector short __a, vector unsigned char __b)
{
- return (vector short)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_vsl(vector short a, vector unsigned short b)
+vec_vsl(vector short __a, vector unsigned short __b)
{
- return (vector short)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_vsl(vector short a, vector unsigned int b)
+vec_vsl(vector short __a, vector unsigned int __b)
{
- return (vector short)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vsl(vector unsigned short a, vector unsigned char b)
+vec_vsl(vector unsigned short __a, vector unsigned char __b)
{
return (vector unsigned short)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vsl(vector unsigned short a, vector unsigned short b)
+vec_vsl(vector unsigned short __a, vector unsigned short __b)
{
return (vector unsigned short)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vsl(vector unsigned short a, vector unsigned int b)
+vec_vsl(vector unsigned short __a, vector unsigned int __b)
{
return (vector unsigned short)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool short __ATTRS_o_ai
-vec_vsl(vector bool short a, vector unsigned char b)
+vec_vsl(vector bool short __a, vector unsigned char __b)
{
- return (vector bool short)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool short)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool short __ATTRS_o_ai
-vec_vsl(vector bool short a, vector unsigned short b)
+vec_vsl(vector bool short __a, vector unsigned short __b)
{
- return (vector bool short)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool short)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool short __ATTRS_o_ai
-vec_vsl(vector bool short a, vector unsigned int b)
+vec_vsl(vector bool short __a, vector unsigned int __b)
{
- return (vector bool short)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool short)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_vsl(vector pixel a, vector unsigned char b)
+vec_vsl(vector pixel __a, vector unsigned char __b)
{
- return (vector pixel)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_vsl(vector pixel a, vector unsigned short b)
+vec_vsl(vector pixel __a, vector unsigned short __b)
{
- return (vector pixel)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_vsl(vector pixel a, vector unsigned int b)
+vec_vsl(vector pixel __a, vector unsigned int __b)
{
- return (vector pixel)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_vsl(vector int a, vector unsigned char b)
+vec_vsl(vector int __a, vector unsigned char __b)
{
- return (vector int)__builtin_altivec_vsl(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsl(__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_vsl(vector int a, vector unsigned short b)
+vec_vsl(vector int __a, vector unsigned short __b)
{
- return (vector int)__builtin_altivec_vsl(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsl(__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_vsl(vector int a, vector unsigned int b)
+vec_vsl(vector int __a, vector unsigned int __b)
{
- return (vector int)__builtin_altivec_vsl(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsl(__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vsl(vector unsigned int a, vector unsigned char b)
+vec_vsl(vector unsigned int __a, vector unsigned char __b)
{
return (vector unsigned int)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vsl(vector unsigned int a, vector unsigned short b)
+vec_vsl(vector unsigned int __a, vector unsigned short __b)
{
return (vector unsigned int)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vsl(vector unsigned int a, vector unsigned int b)
+vec_vsl(vector unsigned int __a, vector unsigned int __b)
{
return (vector unsigned int)
- __builtin_altivec_vsl((vector int)a, (vector int)b);
+ __builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool int __ATTRS_o_ai
-vec_vsl(vector bool int a, vector unsigned char b)
+vec_vsl(vector bool int __a, vector unsigned char __b)
{
- return (vector bool int)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool int)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool int __ATTRS_o_ai
-vec_vsl(vector bool int a, vector unsigned short b)
+vec_vsl(vector bool int __a, vector unsigned short __b)
{
- return (vector bool int)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool int)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
static vector bool int __ATTRS_o_ai
-vec_vsl(vector bool int a, vector unsigned int b)
+vec_vsl(vector bool int __a, vector unsigned int __b)
{
- return (vector bool int)__builtin_altivec_vsl((vector int)a, (vector int)b);
+ return (vector bool int)__builtin_altivec_vsl((vector int)__a, (vector int)__b);
}
/* vec_slo */
static vector signed char __ATTRS_o_ai
-vec_slo(vector signed char a, vector signed char b)
+vec_slo(vector signed char __a, vector signed char __b)
{
return (vector signed char)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector signed char __ATTRS_o_ai
-vec_slo(vector signed char a, vector unsigned char b)
+vec_slo(vector signed char __a, vector unsigned char __b)
{
return (vector signed char)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_slo(vector unsigned char a, vector signed char b)
+vec_slo(vector unsigned char __a, vector signed char __b)
{
return (vector unsigned char)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_slo(vector unsigned char a, vector unsigned char b)
+vec_slo(vector unsigned char __a, vector unsigned char __b)
{
return (vector unsigned char)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_slo(vector short a, vector signed char b)
+vec_slo(vector short __a, vector signed char __b)
{
- return (vector short)__builtin_altivec_vslo((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_slo(vector short a, vector unsigned char b)
+vec_slo(vector short __a, vector unsigned char __b)
{
- return (vector short)__builtin_altivec_vslo((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_slo(vector unsigned short a, vector signed char b)
+vec_slo(vector unsigned short __a, vector signed char __b)
{
return (vector unsigned short)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_slo(vector unsigned short a, vector unsigned char b)
+vec_slo(vector unsigned short __a, vector unsigned char __b)
{
return (vector unsigned short)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_slo(vector pixel a, vector signed char b)
+vec_slo(vector pixel __a, vector signed char __b)
{
- return (vector pixel)__builtin_altivec_vslo((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_slo(vector pixel a, vector unsigned char b)
+vec_slo(vector pixel __a, vector unsigned char __b)
{
- return (vector pixel)__builtin_altivec_vslo((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_slo(vector int a, vector signed char b)
+vec_slo(vector int __a, vector signed char __b)
{
- return (vector int)__builtin_altivec_vslo(a, (vector int)b);
+ return (vector int)__builtin_altivec_vslo(__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_slo(vector int a, vector unsigned char b)
+vec_slo(vector int __a, vector unsigned char __b)
{
- return (vector int)__builtin_altivec_vslo(a, (vector int)b);
+ return (vector int)__builtin_altivec_vslo(__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_slo(vector unsigned int a, vector signed char b)
+vec_slo(vector unsigned int __a, vector signed char __b)
{
return (vector unsigned int)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_slo(vector unsigned int a, vector unsigned char b)
+vec_slo(vector unsigned int __a, vector unsigned char __b)
{
return (vector unsigned int)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector float __ATTRS_o_ai
-vec_slo(vector float a, vector signed char b)
+vec_slo(vector float __a, vector signed char __b)
{
- return (vector float)__builtin_altivec_vslo((vector int)a, (vector int)b);
+ return (vector float)__builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector float __ATTRS_o_ai
-vec_slo(vector float a, vector unsigned char b)
+vec_slo(vector float __a, vector unsigned char __b)
{
- return (vector float)__builtin_altivec_vslo((vector int)a, (vector int)b);
+ return (vector float)__builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
/* vec_vslo */
static vector signed char __ATTRS_o_ai
-vec_vslo(vector signed char a, vector signed char b)
+vec_vslo(vector signed char __a, vector signed char __b)
{
return (vector signed char)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector signed char __ATTRS_o_ai
-vec_vslo(vector signed char a, vector unsigned char b)
+vec_vslo(vector signed char __a, vector unsigned char __b)
{
return (vector signed char)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vslo(vector unsigned char a, vector signed char b)
+vec_vslo(vector unsigned char __a, vector signed char __b)
{
return (vector unsigned char)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vslo(vector unsigned char a, vector unsigned char b)
+vec_vslo(vector unsigned char __a, vector unsigned char __b)
{
return (vector unsigned char)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_vslo(vector short a, vector signed char b)
+vec_vslo(vector short __a, vector signed char __b)
{
- return (vector short)__builtin_altivec_vslo((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_vslo(vector short a, vector unsigned char b)
+vec_vslo(vector short __a, vector unsigned char __b)
{
- return (vector short)__builtin_altivec_vslo((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vslo(vector unsigned short a, vector signed char b)
+vec_vslo(vector unsigned short __a, vector signed char __b)
{
return (vector unsigned short)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vslo(vector unsigned short a, vector unsigned char b)
+vec_vslo(vector unsigned short __a, vector unsigned char __b)
{
return (vector unsigned short)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_vslo(vector pixel a, vector signed char b)
+vec_vslo(vector pixel __a, vector signed char __b)
{
- return (vector pixel)__builtin_altivec_vslo((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_vslo(vector pixel a, vector unsigned char b)
+vec_vslo(vector pixel __a, vector unsigned char __b)
{
- return (vector pixel)__builtin_altivec_vslo((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_vslo(vector int a, vector signed char b)
+vec_vslo(vector int __a, vector signed char __b)
{
- return (vector int)__builtin_altivec_vslo(a, (vector int)b);
+ return (vector int)__builtin_altivec_vslo(__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_vslo(vector int a, vector unsigned char b)
+vec_vslo(vector int __a, vector unsigned char __b)
{
- return (vector int)__builtin_altivec_vslo(a, (vector int)b);
+ return (vector int)__builtin_altivec_vslo(__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vslo(vector unsigned int a, vector signed char b)
+vec_vslo(vector unsigned int __a, vector signed char __b)
{
return (vector unsigned int)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vslo(vector unsigned int a, vector unsigned char b)
+vec_vslo(vector unsigned int __a, vector unsigned char __b)
{
return (vector unsigned int)
- __builtin_altivec_vslo((vector int)a, (vector int)b);
+ __builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector float __ATTRS_o_ai
-vec_vslo(vector float a, vector signed char b)
+vec_vslo(vector float __a, vector signed char __b)
{
- return (vector float)__builtin_altivec_vslo((vector int)a, (vector int)b);
+ return (vector float)__builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
static vector float __ATTRS_o_ai
-vec_vslo(vector float a, vector unsigned char b)
+vec_vslo(vector float __a, vector unsigned char __b)
{
- return (vector float)__builtin_altivec_vslo((vector int)a, (vector int)b);
+ return (vector float)__builtin_altivec_vslo((vector int)__a, (vector int)__b);
}
/* vec_splat */
static vector signed char __ATTRS_o_ai
-vec_splat(vector signed char a, unsigned char b)
+vec_splat(vector signed char __a, unsigned char __b)
{
- return vec_perm(a, a, (vector unsigned char)(b));
+ return vec_perm(__a, __a, (vector unsigned char)(__b));
}
static vector unsigned char __ATTRS_o_ai
-vec_splat(vector unsigned char a, unsigned char b)
+vec_splat(vector unsigned char __a, unsigned char __b)
{
- return vec_perm(a, a, (vector unsigned char)(b));
+ return vec_perm(__a, __a, (vector unsigned char)(__b));
}
static vector bool char __ATTRS_o_ai
-vec_splat(vector bool char a, unsigned char b)
+vec_splat(vector bool char __a, unsigned char __b)
{
- return vec_perm(a, a, (vector unsigned char)(b));
+ return vec_perm(__a, __a, (vector unsigned char)(__b));
}
static vector short __ATTRS_o_ai
-vec_splat(vector short a, unsigned char b)
+vec_splat(vector short __a, unsigned char __b)
{
- b *= 2;
- unsigned char b1=b+1;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1));
+ __b *= 2;
+ unsigned char b1=__b+1;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1));
}
static vector unsigned short __ATTRS_o_ai
-vec_splat(vector unsigned short a, unsigned char b)
+vec_splat(vector unsigned short __a, unsigned char __b)
{
- b *= 2;
- unsigned char b1=b+1;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1));
+ __b *= 2;
+ unsigned char b1=__b+1;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1));
}
static vector bool short __ATTRS_o_ai
-vec_splat(vector bool short a, unsigned char b)
+vec_splat(vector bool short __a, unsigned char __b)
{
- b *= 2;
- unsigned char b1=b+1;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1));
+ __b *= 2;
+ unsigned char b1=__b+1;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1));
}
static vector pixel __ATTRS_o_ai
-vec_splat(vector pixel a, unsigned char b)
+vec_splat(vector pixel __a, unsigned char __b)
{
- b *= 2;
- unsigned char b1=b+1;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1));
+ __b *= 2;
+ unsigned char b1=__b+1;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1));
}
static vector int __ATTRS_o_ai
-vec_splat(vector int a, unsigned char b)
+vec_splat(vector int __a, unsigned char __b)
{
- b *= 4;
- unsigned char b1=b+1, b2=b+2, b3=b+3;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3));
+ __b *= 4;
+ unsigned char b1=__b+1, b2=__b+2, b3=__b+3;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3));
}
static vector unsigned int __ATTRS_o_ai
-vec_splat(vector unsigned int a, unsigned char b)
+vec_splat(vector unsigned int __a, unsigned char __b)
{
- b *= 4;
- unsigned char b1=b+1, b2=b+2, b3=b+3;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3));
+ __b *= 4;
+ unsigned char b1=__b+1, b2=__b+2, b3=__b+3;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3));
}
static vector bool int __ATTRS_o_ai
-vec_splat(vector bool int a, unsigned char b)
+vec_splat(vector bool int __a, unsigned char __b)
{
- b *= 4;
- unsigned char b1=b+1, b2=b+2, b3=b+3;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3));
+ __b *= 4;
+ unsigned char b1=__b+1, b2=__b+2, b3=__b+3;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3));
}
static vector float __ATTRS_o_ai
-vec_splat(vector float a, unsigned char b)
+vec_splat(vector float __a, unsigned char __b)
{
- b *= 4;
- unsigned char b1=b+1, b2=b+2, b3=b+3;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3));
+ __b *= 4;
+ unsigned char b1=__b+1, b2=__b+2, b3=__b+3;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3));
}
/* vec_vspltb */
@@ -5746,21 +5746,21 @@ vec_splat(vector float a, unsigned char b)
#define __builtin_altivec_vspltb vec_vspltb
static vector signed char __ATTRS_o_ai
-vec_vspltb(vector signed char a, unsigned char b)
+vec_vspltb(vector signed char __a, unsigned char __b)
{
- return vec_perm(a, a, (vector unsigned char)(b));
+ return vec_perm(__a, __a, (vector unsigned char)(__b));
}
static vector unsigned char __ATTRS_o_ai
-vec_vspltb(vector unsigned char a, unsigned char b)
+vec_vspltb(vector unsigned char __a, unsigned char __b)
{
- return vec_perm(a, a, (vector unsigned char)(b));
+ return vec_perm(__a, __a, (vector unsigned char)(__b));
}
static vector bool char __ATTRS_o_ai
-vec_vspltb(vector bool char a, unsigned char b)
+vec_vspltb(vector bool char __a, unsigned char __b)
{
- return vec_perm(a, a, (vector unsigned char)(b));
+ return vec_perm(__a, __a, (vector unsigned char)(__b));
}
/* vec_vsplth */
@@ -5768,39 +5768,39 @@ vec_vspltb(vector bool char a, unsigned char b)
#define __builtin_altivec_vsplth vec_vsplth
static vector short __ATTRS_o_ai
-vec_vsplth(vector short a, unsigned char b)
+vec_vsplth(vector short __a, unsigned char __b)
{
- b *= 2;
- unsigned char b1=b+1;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1));
+ __b *= 2;
+ unsigned char b1=__b+1;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1));
}
static vector unsigned short __ATTRS_o_ai
-vec_vsplth(vector unsigned short a, unsigned char b)
+vec_vsplth(vector unsigned short __a, unsigned char __b)
{
- b *= 2;
- unsigned char b1=b+1;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1));
+ __b *= 2;
+ unsigned char b1=__b+1;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1));
}
static vector bool short __ATTRS_o_ai
-vec_vsplth(vector bool short a, unsigned char b)
+vec_vsplth(vector bool short __a, unsigned char __b)
{
- b *= 2;
- unsigned char b1=b+1;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1));
+ __b *= 2;
+ unsigned char b1=__b+1;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1));
}
static vector pixel __ATTRS_o_ai
-vec_vsplth(vector pixel a, unsigned char b)
+vec_vsplth(vector pixel __a, unsigned char __b)
{
- b *= 2;
- unsigned char b1=b+1;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1, b, b1));
+ __b *= 2;
+ unsigned char b1=__b+1;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1, __b, b1));
}
/* vec_vspltw */
@@ -5808,39 +5808,39 @@ vec_vsplth(vector pixel a, unsigned char b)
#define __builtin_altivec_vspltw vec_vspltw
static vector int __ATTRS_o_ai
-vec_vspltw(vector int a, unsigned char b)
+vec_vspltw(vector int __a, unsigned char __b)
{
- b *= 4;
- unsigned char b1=b+1, b2=b+2, b3=b+3;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3));
+ __b *= 4;
+ unsigned char b1=__b+1, b2=__b+2, b3=__b+3;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3));
}
static vector unsigned int __ATTRS_o_ai
-vec_vspltw(vector unsigned int a, unsigned char b)
+vec_vspltw(vector unsigned int __a, unsigned char __b)
{
- b *= 4;
- unsigned char b1=b+1, b2=b+2, b3=b+3;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3));
+ __b *= 4;
+ unsigned char b1=__b+1, b2=__b+2, b3=__b+3;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3));
}
static vector bool int __ATTRS_o_ai
-vec_vspltw(vector bool int a, unsigned char b)
+vec_vspltw(vector bool int __a, unsigned char __b)
{
- b *= 4;
- unsigned char b1=b+1, b2=b+2, b3=b+3;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3));
+ __b *= 4;
+ unsigned char b1=__b+1, b2=__b+2, b3=__b+3;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3));
}
static vector float __ATTRS_o_ai
-vec_vspltw(vector float a, unsigned char b)
+vec_vspltw(vector float __a, unsigned char __b)
{
- b *= 4;
- unsigned char b1=b+1, b2=b+2, b3=b+3;
- return vec_perm(a, a, (vector unsigned char)
- (b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3, b, b1, b2, b3));
+ __b *= 4;
+ unsigned char b1=__b+1, b2=__b+2, b3=__b+3;
+ return vec_perm(__a, __a, (vector unsigned char)
+ (__b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3, __b, b1, b2, b3));
}
/* vec_splat_s8 */
@@ -5849,18 +5849,18 @@ vec_vspltw(vector float a, unsigned char b)
// FIXME: parameter should be treated as 5-bit signed literal
static vector signed char __ATTRS_o_ai
-vec_splat_s8(signed char a)
+vec_splat_s8(signed char __a)
{
- return (vector signed char)(a);
+ return (vector signed char)(__a);
}
/* vec_vspltisb */
// FIXME: parameter should be treated as 5-bit signed literal
static vector signed char __ATTRS_o_ai
-vec_vspltisb(signed char a)
+vec_vspltisb(signed char __a)
{
- return (vector signed char)(a);
+ return (vector signed char)(__a);
}
/* vec_splat_s16 */
@@ -5869,18 +5869,18 @@ vec_vspltisb(signed char a)
// FIXME: parameter should be treated as 5-bit signed literal
static vector short __ATTRS_o_ai
-vec_splat_s16(signed char a)
+vec_splat_s16(signed char __a)
{
- return (vector short)(a);
+ return (vector short)(__a);
}
/* vec_vspltish */
// FIXME: parameter should be treated as 5-bit signed literal
static vector short __ATTRS_o_ai
-vec_vspltish(signed char a)
+vec_vspltish(signed char __a)
{
- return (vector short)(a);
+ return (vector short)(__a);
}
/* vec_splat_s32 */
@@ -5889,83 +5889,83 @@ vec_vspltish(signed char a)
// FIXME: parameter should be treated as 5-bit signed literal
static vector int __ATTRS_o_ai
-vec_splat_s32(signed char a)
+vec_splat_s32(signed char __a)
{
- return (vector int)(a);
+ return (vector int)(__a);
}
/* vec_vspltisw */
// FIXME: parameter should be treated as 5-bit signed literal
static vector int __ATTRS_o_ai
-vec_vspltisw(signed char a)
+vec_vspltisw(signed char __a)
{
- return (vector int)(a);
+ return (vector int)(__a);
}
/* vec_splat_u8 */
// FIXME: parameter should be treated as 5-bit signed literal
static vector unsigned char __ATTRS_o_ai
-vec_splat_u8(unsigned char a)
+vec_splat_u8(unsigned char __a)
{
- return (vector unsigned char)(a);
+ return (vector unsigned char)(__a);
}
/* vec_splat_u16 */
// FIXME: parameter should be treated as 5-bit signed literal
static vector unsigned short __ATTRS_o_ai
-vec_splat_u16(signed char a)
+vec_splat_u16(signed char __a)
{
- return (vector unsigned short)(a);
+ return (vector unsigned short)(__a);
}
/* vec_splat_u32 */
// FIXME: parameter should be treated as 5-bit signed literal
static vector unsigned int __ATTRS_o_ai
-vec_splat_u32(signed char a)
+vec_splat_u32(signed char __a)
{
- return (vector unsigned int)(a);
+ return (vector unsigned int)(__a);
}
/* vec_sr */
static vector signed char __ATTRS_o_ai
-vec_sr(vector signed char a, vector unsigned char b)
+vec_sr(vector signed char __a, vector unsigned char __b)
{
- return a >> (vector signed char)b;
+ return __a >> (vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_sr(vector unsigned char a, vector unsigned char b)
+vec_sr(vector unsigned char __a, vector unsigned char __b)
{
- return a >> b;
+ return __a >> __b;
}
static vector short __ATTRS_o_ai
-vec_sr(vector short a, vector unsigned short b)
+vec_sr(vector short __a, vector unsigned short __b)
{
- return a >> (vector short)b;
+ return __a >> (vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_sr(vector unsigned short a, vector unsigned short b)
+vec_sr(vector unsigned short __a, vector unsigned short __b)
{
- return a >> b;
+ return __a >> __b;
}
static vector int __ATTRS_o_ai
-vec_sr(vector int a, vector unsigned int b)
+vec_sr(vector int __a, vector unsigned int __b)
{
- return a >> (vector int)b;
+ return __a >> (vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_sr(vector unsigned int a, vector unsigned int b)
+vec_sr(vector unsigned int __a, vector unsigned int __b)
{
- return a >> b;
+ return __a >> __b;
}
/* vec_vsrb */
@@ -5973,15 +5973,15 @@ vec_sr(vector unsigned int a, vector unsigned int b)
#define __builtin_altivec_vsrb vec_vsrb
static vector signed char __ATTRS_o_ai
-vec_vsrb(vector signed char a, vector unsigned char b)
+vec_vsrb(vector signed char __a, vector unsigned char __b)
{
- return a >> (vector signed char)b;
+ return __a >> (vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vsrb(vector unsigned char a, vector unsigned char b)
+vec_vsrb(vector unsigned char __a, vector unsigned char __b)
{
- return a >> b;
+ return __a >> __b;
}
/* vec_vsrh */
@@ -5989,15 +5989,15 @@ vec_vsrb(vector unsigned char a, vector unsigned char b)
#define __builtin_altivec_vsrh vec_vsrh
static vector short __ATTRS_o_ai
-vec_vsrh(vector short a, vector unsigned short b)
+vec_vsrh(vector short __a, vector unsigned short __b)
{
- return a >> (vector short)b;
+ return __a >> (vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vsrh(vector unsigned short a, vector unsigned short b)
+vec_vsrh(vector unsigned short __a, vector unsigned short __b)
{
- return a >> b;
+ return __a >> __b;
}
/* vec_vsrw */
@@ -6005,1631 +6005,1631 @@ vec_vsrh(vector unsigned short a, vector unsigned short b)
#define __builtin_altivec_vsrw vec_vsrw
static vector int __ATTRS_o_ai
-vec_vsrw(vector int a, vector unsigned int b)
+vec_vsrw(vector int __a, vector unsigned int __b)
{
- return a >> (vector int)b;
+ return __a >> (vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vsrw(vector unsigned int a, vector unsigned int b)
+vec_vsrw(vector unsigned int __a, vector unsigned int __b)
{
- return a >> b;
+ return __a >> __b;
}
/* vec_sra */
static vector signed char __ATTRS_o_ai
-vec_sra(vector signed char a, vector unsigned char b)
+vec_sra(vector signed char __a, vector unsigned char __b)
{
- return (vector signed char)__builtin_altivec_vsrab((vector char)a, b);
+ return (vector signed char)__builtin_altivec_vsrab((vector char)__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_sra(vector unsigned char a, vector unsigned char b)
+vec_sra(vector unsigned char __a, vector unsigned char __b)
{
- return (vector unsigned char)__builtin_altivec_vsrab((vector char)a, b);
+ return (vector unsigned char)__builtin_altivec_vsrab((vector char)__a, __b);
}
static vector short __ATTRS_o_ai
-vec_sra(vector short a, vector unsigned short b)
+vec_sra(vector short __a, vector unsigned short __b)
{
- return __builtin_altivec_vsrah(a, (vector unsigned short)b);
+ return __builtin_altivec_vsrah(__a, (vector unsigned short)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_sra(vector unsigned short a, vector unsigned short b)
+vec_sra(vector unsigned short __a, vector unsigned short __b)
{
- return (vector unsigned short)__builtin_altivec_vsrah((vector short)a, b);
+ return (vector unsigned short)__builtin_altivec_vsrah((vector short)__a, __b);
}
static vector int __ATTRS_o_ai
-vec_sra(vector int a, vector unsigned int b)
+vec_sra(vector int __a, vector unsigned int __b)
{
- return __builtin_altivec_vsraw(a, b);
+ return __builtin_altivec_vsraw(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_sra(vector unsigned int a, vector unsigned int b)
+vec_sra(vector unsigned int __a, vector unsigned int __b)
{
- return (vector unsigned int)__builtin_altivec_vsraw((vector int)a, b);
+ return (vector unsigned int)__builtin_altivec_vsraw((vector int)__a, __b);
}
/* vec_vsrab */
static vector signed char __ATTRS_o_ai
-vec_vsrab(vector signed char a, vector unsigned char b)
+vec_vsrab(vector signed char __a, vector unsigned char __b)
{
- return (vector signed char)__builtin_altivec_vsrab((vector char)a, b);
+ return (vector signed char)__builtin_altivec_vsrab((vector char)__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vsrab(vector unsigned char a, vector unsigned char b)
+vec_vsrab(vector unsigned char __a, vector unsigned char __b)
{
- return (vector unsigned char)__builtin_altivec_vsrab((vector char)a, b);
+ return (vector unsigned char)__builtin_altivec_vsrab((vector char)__a, __b);
}
/* vec_vsrah */
static vector short __ATTRS_o_ai
-vec_vsrah(vector short a, vector unsigned short b)
+vec_vsrah(vector short __a, vector unsigned short __b)
{
- return __builtin_altivec_vsrah(a, (vector unsigned short)b);
+ return __builtin_altivec_vsrah(__a, (vector unsigned short)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vsrah(vector unsigned short a, vector unsigned short b)
+vec_vsrah(vector unsigned short __a, vector unsigned short __b)
{
- return (vector unsigned short)__builtin_altivec_vsrah((vector short)a, b);
+ return (vector unsigned short)__builtin_altivec_vsrah((vector short)__a, __b);
}
/* vec_vsraw */
static vector int __ATTRS_o_ai
-vec_vsraw(vector int a, vector unsigned int b)
+vec_vsraw(vector int __a, vector unsigned int __b)
{
- return __builtin_altivec_vsraw(a, b);
+ return __builtin_altivec_vsraw(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vsraw(vector unsigned int a, vector unsigned int b)
+vec_vsraw(vector unsigned int __a, vector unsigned int __b)
{
- return (vector unsigned int)__builtin_altivec_vsraw((vector int)a, b);
+ return (vector unsigned int)__builtin_altivec_vsraw((vector int)__a, __b);
}
/* vec_srl */
static vector signed char __ATTRS_o_ai
-vec_srl(vector signed char a, vector unsigned char b)
+vec_srl(vector signed char __a, vector unsigned char __b)
{
return (vector signed char)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector signed char __ATTRS_o_ai
-vec_srl(vector signed char a, vector unsigned short b)
+vec_srl(vector signed char __a, vector unsigned short __b)
{
return (vector signed char)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector signed char __ATTRS_o_ai
-vec_srl(vector signed char a, vector unsigned int b)
+vec_srl(vector signed char __a, vector unsigned int __b)
{
return (vector signed char)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_srl(vector unsigned char a, vector unsigned char b)
+vec_srl(vector unsigned char __a, vector unsigned char __b)
{
return (vector unsigned char)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_srl(vector unsigned char a, vector unsigned short b)
+vec_srl(vector unsigned char __a, vector unsigned short __b)
{
return (vector unsigned char)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_srl(vector unsigned char a, vector unsigned int b)
+vec_srl(vector unsigned char __a, vector unsigned int __b)
{
return (vector unsigned char)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool char __ATTRS_o_ai
-vec_srl(vector bool char a, vector unsigned char b)
+vec_srl(vector bool char __a, vector unsigned char __b)
{
- return (vector bool char)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool char)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool char __ATTRS_o_ai
-vec_srl(vector bool char a, vector unsigned short b)
+vec_srl(vector bool char __a, vector unsigned short __b)
{
- return (vector bool char)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool char)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool char __ATTRS_o_ai
-vec_srl(vector bool char a, vector unsigned int b)
+vec_srl(vector bool char __a, vector unsigned int __b)
{
- return (vector bool char)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool char)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_srl(vector short a, vector unsigned char b)
+vec_srl(vector short __a, vector unsigned char __b)
{
- return (vector short)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_srl(vector short a, vector unsigned short b)
+vec_srl(vector short __a, vector unsigned short __b)
{
- return (vector short)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_srl(vector short a, vector unsigned int b)
+vec_srl(vector short __a, vector unsigned int __b)
{
- return (vector short)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_srl(vector unsigned short a, vector unsigned char b)
+vec_srl(vector unsigned short __a, vector unsigned char __b)
{
return (vector unsigned short)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_srl(vector unsigned short a, vector unsigned short b)
+vec_srl(vector unsigned short __a, vector unsigned short __b)
{
return (vector unsigned short)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_srl(vector unsigned short a, vector unsigned int b)
+vec_srl(vector unsigned short __a, vector unsigned int __b)
{
return (vector unsigned short)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool short __ATTRS_o_ai
-vec_srl(vector bool short a, vector unsigned char b)
+vec_srl(vector bool short __a, vector unsigned char __b)
{
- return (vector bool short)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool short)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool short __ATTRS_o_ai
-vec_srl(vector bool short a, vector unsigned short b)
+vec_srl(vector bool short __a, vector unsigned short __b)
{
- return (vector bool short)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool short)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool short __ATTRS_o_ai
-vec_srl(vector bool short a, vector unsigned int b)
+vec_srl(vector bool short __a, vector unsigned int __b)
{
- return (vector bool short)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool short)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_srl(vector pixel a, vector unsigned char b)
+vec_srl(vector pixel __a, vector unsigned char __b)
{
- return (vector pixel)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_srl(vector pixel a, vector unsigned short b)
+vec_srl(vector pixel __a, vector unsigned short __b)
{
- return (vector pixel)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_srl(vector pixel a, vector unsigned int b)
+vec_srl(vector pixel __a, vector unsigned int __b)
{
- return (vector pixel)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_srl(vector int a, vector unsigned char b)
+vec_srl(vector int __a, vector unsigned char __b)
{
- return (vector int)__builtin_altivec_vsr(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsr(__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_srl(vector int a, vector unsigned short b)
+vec_srl(vector int __a, vector unsigned short __b)
{
- return (vector int)__builtin_altivec_vsr(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsr(__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_srl(vector int a, vector unsigned int b)
+vec_srl(vector int __a, vector unsigned int __b)
{
- return (vector int)__builtin_altivec_vsr(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsr(__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_srl(vector unsigned int a, vector unsigned char b)
+vec_srl(vector unsigned int __a, vector unsigned char __b)
{
return (vector unsigned int)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_srl(vector unsigned int a, vector unsigned short b)
+vec_srl(vector unsigned int __a, vector unsigned short __b)
{
return (vector unsigned int)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_srl(vector unsigned int a, vector unsigned int b)
+vec_srl(vector unsigned int __a, vector unsigned int __b)
{
return (vector unsigned int)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool int __ATTRS_o_ai
-vec_srl(vector bool int a, vector unsigned char b)
+vec_srl(vector bool int __a, vector unsigned char __b)
{
- return (vector bool int)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool int)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool int __ATTRS_o_ai
-vec_srl(vector bool int a, vector unsigned short b)
+vec_srl(vector bool int __a, vector unsigned short __b)
{
- return (vector bool int)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool int)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool int __ATTRS_o_ai
-vec_srl(vector bool int a, vector unsigned int b)
+vec_srl(vector bool int __a, vector unsigned int __b)
{
- return (vector bool int)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool int)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
/* vec_vsr */
static vector signed char __ATTRS_o_ai
-vec_vsr(vector signed char a, vector unsigned char b)
+vec_vsr(vector signed char __a, vector unsigned char __b)
{
return (vector signed char)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector signed char __ATTRS_o_ai
-vec_vsr(vector signed char a, vector unsigned short b)
+vec_vsr(vector signed char __a, vector unsigned short __b)
{
return (vector signed char)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector signed char __ATTRS_o_ai
-vec_vsr(vector signed char a, vector unsigned int b)
+vec_vsr(vector signed char __a, vector unsigned int __b)
{
return (vector signed char)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vsr(vector unsigned char a, vector unsigned char b)
+vec_vsr(vector unsigned char __a, vector unsigned char __b)
{
return (vector unsigned char)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vsr(vector unsigned char a, vector unsigned short b)
+vec_vsr(vector unsigned char __a, vector unsigned short __b)
{
return (vector unsigned char)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vsr(vector unsigned char a, vector unsigned int b)
+vec_vsr(vector unsigned char __a, vector unsigned int __b)
{
return (vector unsigned char)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool char __ATTRS_o_ai
-vec_vsr(vector bool char a, vector unsigned char b)
+vec_vsr(vector bool char __a, vector unsigned char __b)
{
- return (vector bool char)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool char)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool char __ATTRS_o_ai
-vec_vsr(vector bool char a, vector unsigned short b)
+vec_vsr(vector bool char __a, vector unsigned short __b)
{
- return (vector bool char)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool char)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool char __ATTRS_o_ai
-vec_vsr(vector bool char a, vector unsigned int b)
+vec_vsr(vector bool char __a, vector unsigned int __b)
{
- return (vector bool char)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool char)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_vsr(vector short a, vector unsigned char b)
+vec_vsr(vector short __a, vector unsigned char __b)
{
- return (vector short)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_vsr(vector short a, vector unsigned short b)
+vec_vsr(vector short __a, vector unsigned short __b)
{
- return (vector short)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_vsr(vector short a, vector unsigned int b)
+vec_vsr(vector short __a, vector unsigned int __b)
{
- return (vector short)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vsr(vector unsigned short a, vector unsigned char b)
+vec_vsr(vector unsigned short __a, vector unsigned char __b)
{
return (vector unsigned short)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vsr(vector unsigned short a, vector unsigned short b)
+vec_vsr(vector unsigned short __a, vector unsigned short __b)
{
return (vector unsigned short)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vsr(vector unsigned short a, vector unsigned int b)
+vec_vsr(vector unsigned short __a, vector unsigned int __b)
{
return (vector unsigned short)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool short __ATTRS_o_ai
-vec_vsr(vector bool short a, vector unsigned char b)
+vec_vsr(vector bool short __a, vector unsigned char __b)
{
- return (vector bool short)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool short)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool short __ATTRS_o_ai
-vec_vsr(vector bool short a, vector unsigned short b)
+vec_vsr(vector bool short __a, vector unsigned short __b)
{
- return (vector bool short)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool short)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool short __ATTRS_o_ai
-vec_vsr(vector bool short a, vector unsigned int b)
+vec_vsr(vector bool short __a, vector unsigned int __b)
{
- return (vector bool short)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool short)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_vsr(vector pixel a, vector unsigned char b)
+vec_vsr(vector pixel __a, vector unsigned char __b)
{
- return (vector pixel)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_vsr(vector pixel a, vector unsigned short b)
+vec_vsr(vector pixel __a, vector unsigned short __b)
{
- return (vector pixel)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_vsr(vector pixel a, vector unsigned int b)
+vec_vsr(vector pixel __a, vector unsigned int __b)
{
- return (vector pixel)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_vsr(vector int a, vector unsigned char b)
+vec_vsr(vector int __a, vector unsigned char __b)
{
- return (vector int)__builtin_altivec_vsr(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsr(__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_vsr(vector int a, vector unsigned short b)
+vec_vsr(vector int __a, vector unsigned short __b)
{
- return (vector int)__builtin_altivec_vsr(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsr(__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_vsr(vector int a, vector unsigned int b)
+vec_vsr(vector int __a, vector unsigned int __b)
{
- return (vector int)__builtin_altivec_vsr(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsr(__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vsr(vector unsigned int a, vector unsigned char b)
+vec_vsr(vector unsigned int __a, vector unsigned char __b)
{
return (vector unsigned int)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vsr(vector unsigned int a, vector unsigned short b)
+vec_vsr(vector unsigned int __a, vector unsigned short __b)
{
return (vector unsigned int)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vsr(vector unsigned int a, vector unsigned int b)
+vec_vsr(vector unsigned int __a, vector unsigned int __b)
{
return (vector unsigned int)
- __builtin_altivec_vsr((vector int)a, (vector int)b);
+ __builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool int __ATTRS_o_ai
-vec_vsr(vector bool int a, vector unsigned char b)
+vec_vsr(vector bool int __a, vector unsigned char __b)
{
- return (vector bool int)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool int)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool int __ATTRS_o_ai
-vec_vsr(vector bool int a, vector unsigned short b)
+vec_vsr(vector bool int __a, vector unsigned short __b)
{
- return (vector bool int)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool int)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
static vector bool int __ATTRS_o_ai
-vec_vsr(vector bool int a, vector unsigned int b)
+vec_vsr(vector bool int __a, vector unsigned int __b)
{
- return (vector bool int)__builtin_altivec_vsr((vector int)a, (vector int)b);
+ return (vector bool int)__builtin_altivec_vsr((vector int)__a, (vector int)__b);
}
/* vec_sro */
static vector signed char __ATTRS_o_ai
-vec_sro(vector signed char a, vector signed char b)
+vec_sro(vector signed char __a, vector signed char __b)
{
return (vector signed char)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector signed char __ATTRS_o_ai
-vec_sro(vector signed char a, vector unsigned char b)
+vec_sro(vector signed char __a, vector unsigned char __b)
{
return (vector signed char)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_sro(vector unsigned char a, vector signed char b)
+vec_sro(vector unsigned char __a, vector signed char __b)
{
return (vector unsigned char)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_sro(vector unsigned char a, vector unsigned char b)
+vec_sro(vector unsigned char __a, vector unsigned char __b)
{
return (vector unsigned char)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_sro(vector short a, vector signed char b)
+vec_sro(vector short __a, vector signed char __b)
{
- return (vector short)__builtin_altivec_vsro((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_sro(vector short a, vector unsigned char b)
+vec_sro(vector short __a, vector unsigned char __b)
{
- return (vector short)__builtin_altivec_vsro((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_sro(vector unsigned short a, vector signed char b)
+vec_sro(vector unsigned short __a, vector signed char __b)
{
return (vector unsigned short)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_sro(vector unsigned short a, vector unsigned char b)
+vec_sro(vector unsigned short __a, vector unsigned char __b)
{
return (vector unsigned short)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_sro(vector pixel a, vector signed char b)
+vec_sro(vector pixel __a, vector signed char __b)
{
- return (vector pixel)__builtin_altivec_vsro((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_sro(vector pixel a, vector unsigned char b)
+vec_sro(vector pixel __a, vector unsigned char __b)
{
- return (vector pixel)__builtin_altivec_vsro((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_sro(vector int a, vector signed char b)
+vec_sro(vector int __a, vector signed char __b)
{
- return (vector int)__builtin_altivec_vsro(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsro(__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_sro(vector int a, vector unsigned char b)
+vec_sro(vector int __a, vector unsigned char __b)
{
- return (vector int)__builtin_altivec_vsro(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsro(__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_sro(vector unsigned int a, vector signed char b)
+vec_sro(vector unsigned int __a, vector signed char __b)
{
return (vector unsigned int)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_sro(vector unsigned int a, vector unsigned char b)
+vec_sro(vector unsigned int __a, vector unsigned char __b)
{
return (vector unsigned int)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector float __ATTRS_o_ai
-vec_sro(vector float a, vector signed char b)
+vec_sro(vector float __a, vector signed char __b)
{
- return (vector float)__builtin_altivec_vsro((vector int)a, (vector int)b);
+ return (vector float)__builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector float __ATTRS_o_ai
-vec_sro(vector float a, vector unsigned char b)
+vec_sro(vector float __a, vector unsigned char __b)
{
- return (vector float)__builtin_altivec_vsro((vector int)a, (vector int)b);
+ return (vector float)__builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
/* vec_vsro */
static vector signed char __ATTRS_o_ai
-vec_vsro(vector signed char a, vector signed char b)
+vec_vsro(vector signed char __a, vector signed char __b)
{
return (vector signed char)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector signed char __ATTRS_o_ai
-vec_vsro(vector signed char a, vector unsigned char b)
+vec_vsro(vector signed char __a, vector unsigned char __b)
{
return (vector signed char)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vsro(vector unsigned char a, vector signed char b)
+vec_vsro(vector unsigned char __a, vector signed char __b)
{
return (vector unsigned char)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vsro(vector unsigned char a, vector unsigned char b)
+vec_vsro(vector unsigned char __a, vector unsigned char __b)
{
return (vector unsigned char)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_vsro(vector short a, vector signed char b)
+vec_vsro(vector short __a, vector signed char __b)
{
- return (vector short)__builtin_altivec_vsro((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector short __ATTRS_o_ai
-vec_vsro(vector short a, vector unsigned char b)
+vec_vsro(vector short __a, vector unsigned char __b)
{
- return (vector short)__builtin_altivec_vsro((vector int)a, (vector int)b);
+ return (vector short)__builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vsro(vector unsigned short a, vector signed char b)
+vec_vsro(vector unsigned short __a, vector signed char __b)
{
return (vector unsigned short)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vsro(vector unsigned short a, vector unsigned char b)
+vec_vsro(vector unsigned short __a, vector unsigned char __b)
{
return (vector unsigned short)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_vsro(vector pixel a, vector signed char b)
+vec_vsro(vector pixel __a, vector signed char __b)
{
- return (vector pixel)__builtin_altivec_vsro((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector pixel __ATTRS_o_ai
-vec_vsro(vector pixel a, vector unsigned char b)
+vec_vsro(vector pixel __a, vector unsigned char __b)
{
- return (vector pixel)__builtin_altivec_vsro((vector int)a, (vector int)b);
+ return (vector pixel)__builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_vsro(vector int a, vector signed char b)
+vec_vsro(vector int __a, vector signed char __b)
{
- return (vector int)__builtin_altivec_vsro(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsro(__a, (vector int)__b);
}
static vector int __ATTRS_o_ai
-vec_vsro(vector int a, vector unsigned char b)
+vec_vsro(vector int __a, vector unsigned char __b)
{
- return (vector int)__builtin_altivec_vsro(a, (vector int)b);
+ return (vector int)__builtin_altivec_vsro(__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vsro(vector unsigned int a, vector signed char b)
+vec_vsro(vector unsigned int __a, vector signed char __b)
{
return (vector unsigned int)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vsro(vector unsigned int a, vector unsigned char b)
+vec_vsro(vector unsigned int __a, vector unsigned char __b)
{
return (vector unsigned int)
- __builtin_altivec_vsro((vector int)a, (vector int)b);
+ __builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector float __ATTRS_o_ai
-vec_vsro(vector float a, vector signed char b)
+vec_vsro(vector float __a, vector signed char __b)
{
- return (vector float)__builtin_altivec_vsro((vector int)a, (vector int)b);
+ return (vector float)__builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
static vector float __ATTRS_o_ai
-vec_vsro(vector float a, vector unsigned char b)
+vec_vsro(vector float __a, vector unsigned char __b)
{
- return (vector float)__builtin_altivec_vsro((vector int)a, (vector int)b);
+ return (vector float)__builtin_altivec_vsro((vector int)__a, (vector int)__b);
}
/* vec_st */
static void __ATTRS_o_ai
-vec_st(vector signed char a, int b, vector signed char *c)
+vec_st(vector signed char __a, int __b, vector signed char *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector signed char a, int b, signed char *c)
+vec_st(vector signed char __a, int __b, signed char *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector unsigned char a, int b, vector unsigned char *c)
+vec_st(vector unsigned char __a, int __b, vector unsigned char *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector unsigned char a, int b, unsigned char *c)
+vec_st(vector unsigned char __a, int __b, unsigned char *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector bool char a, int b, signed char *c)
+vec_st(vector bool char __a, int __b, signed char *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector bool char a, int b, unsigned char *c)
+vec_st(vector bool char __a, int __b, unsigned char *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector bool char a, int b, vector bool char *c)
+vec_st(vector bool char __a, int __b, vector bool char *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector short a, int b, vector short *c)
+vec_st(vector short __a, int __b, vector short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector short a, int b, short *c)
+vec_st(vector short __a, int __b, short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector unsigned short a, int b, vector unsigned short *c)
+vec_st(vector unsigned short __a, int __b, vector unsigned short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector unsigned short a, int b, unsigned short *c)
+vec_st(vector unsigned short __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector bool short a, int b, short *c)
+vec_st(vector bool short __a, int __b, short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector bool short a, int b, unsigned short *c)
+vec_st(vector bool short __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector bool short a, int b, vector bool short *c)
+vec_st(vector bool short __a, int __b, vector bool short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector pixel a, int b, short *c)
+vec_st(vector pixel __a, int __b, short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector pixel a, int b, unsigned short *c)
+vec_st(vector pixel __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector pixel a, int b, vector pixel *c)
+vec_st(vector pixel __a, int __b, vector pixel *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector int a, int b, vector int *c)
+vec_st(vector int __a, int __b, vector int *__c)
{
- __builtin_altivec_stvx(a, b, c);
+ __builtin_altivec_stvx(__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector int a, int b, int *c)
+vec_st(vector int __a, int __b, int *__c)
{
- __builtin_altivec_stvx(a, b, c);
+ __builtin_altivec_stvx(__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector unsigned int a, int b, vector unsigned int *c)
+vec_st(vector unsigned int __a, int __b, vector unsigned int *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector unsigned int a, int b, unsigned int *c)
+vec_st(vector unsigned int __a, int __b, unsigned int *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector bool int a, int b, int *c)
+vec_st(vector bool int __a, int __b, int *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector bool int a, int b, unsigned int *c)
+vec_st(vector bool int __a, int __b, unsigned int *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector bool int a, int b, vector bool int *c)
+vec_st(vector bool int __a, int __b, vector bool int *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector float a, int b, vector float *c)
+vec_st(vector float __a, int __b, vector float *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_st(vector float a, int b, float *c)
+vec_st(vector float __a, int __b, float *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
/* vec_stvx */
static void __ATTRS_o_ai
-vec_stvx(vector signed char a, int b, vector signed char *c)
+vec_stvx(vector signed char __a, int __b, vector signed char *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector signed char a, int b, signed char *c)
+vec_stvx(vector signed char __a, int __b, signed char *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector unsigned char a, int b, vector unsigned char *c)
+vec_stvx(vector unsigned char __a, int __b, vector unsigned char *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector unsigned char a, int b, unsigned char *c)
+vec_stvx(vector unsigned char __a, int __b, unsigned char *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector bool char a, int b, signed char *c)
+vec_stvx(vector bool char __a, int __b, signed char *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector bool char a, int b, unsigned char *c)
+vec_stvx(vector bool char __a, int __b, unsigned char *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector bool char a, int b, vector bool char *c)
+vec_stvx(vector bool char __a, int __b, vector bool char *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector short a, int b, vector short *c)
+vec_stvx(vector short __a, int __b, vector short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector short a, int b, short *c)
+vec_stvx(vector short __a, int __b, short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector unsigned short a, int b, vector unsigned short *c)
+vec_stvx(vector unsigned short __a, int __b, vector unsigned short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector unsigned short a, int b, unsigned short *c)
+vec_stvx(vector unsigned short __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector bool short a, int b, short *c)
+vec_stvx(vector bool short __a, int __b, short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector bool short a, int b, unsigned short *c)
+vec_stvx(vector bool short __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector bool short a, int b, vector bool short *c)
+vec_stvx(vector bool short __a, int __b, vector bool short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector pixel a, int b, short *c)
+vec_stvx(vector pixel __a, int __b, short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector pixel a, int b, unsigned short *c)
+vec_stvx(vector pixel __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector pixel a, int b, vector pixel *c)
+vec_stvx(vector pixel __a, int __b, vector pixel *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector int a, int b, vector int *c)
+vec_stvx(vector int __a, int __b, vector int *__c)
{
- __builtin_altivec_stvx(a, b, c);
+ __builtin_altivec_stvx(__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector int a, int b, int *c)
+vec_stvx(vector int __a, int __b, int *__c)
{
- __builtin_altivec_stvx(a, b, c);
+ __builtin_altivec_stvx(__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector unsigned int a, int b, vector unsigned int *c)
+vec_stvx(vector unsigned int __a, int __b, vector unsigned int *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector unsigned int a, int b, unsigned int *c)
+vec_stvx(vector unsigned int __a, int __b, unsigned int *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector bool int a, int b, int *c)
+vec_stvx(vector bool int __a, int __b, int *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector bool int a, int b, unsigned int *c)
+vec_stvx(vector bool int __a, int __b, unsigned int *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector bool int a, int b, vector bool int *c)
+vec_stvx(vector bool int __a, int __b, vector bool int *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector float a, int b, vector float *c)
+vec_stvx(vector float __a, int __b, vector float *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvx(vector float a, int b, float *c)
+vec_stvx(vector float __a, int __b, float *__c)
{
- __builtin_altivec_stvx((vector int)a, b, c);
+ __builtin_altivec_stvx((vector int)__a, __b, __c);
}
/* vec_ste */
static void __ATTRS_o_ai
-vec_ste(vector signed char a, int b, signed char *c)
+vec_ste(vector signed char __a, int __b, signed char *__c)
{
- __builtin_altivec_stvebx((vector char)a, b, c);
+ __builtin_altivec_stvebx((vector char)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_ste(vector unsigned char a, int b, unsigned char *c)
+vec_ste(vector unsigned char __a, int __b, unsigned char *__c)
{
- __builtin_altivec_stvebx((vector char)a, b, c);
+ __builtin_altivec_stvebx((vector char)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_ste(vector bool char a, int b, signed char *c)
+vec_ste(vector bool char __a, int __b, signed char *__c)
{
- __builtin_altivec_stvebx((vector char)a, b, c);
+ __builtin_altivec_stvebx((vector char)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_ste(vector bool char a, int b, unsigned char *c)
+vec_ste(vector bool char __a, int __b, unsigned char *__c)
{
- __builtin_altivec_stvebx((vector char)a, b, c);
+ __builtin_altivec_stvebx((vector char)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_ste(vector short a, int b, short *c)
+vec_ste(vector short __a, int __b, short *__c)
{
- __builtin_altivec_stvehx(a, b, c);
+ __builtin_altivec_stvehx(__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_ste(vector unsigned short a, int b, unsigned short *c)
+vec_ste(vector unsigned short __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvehx((vector short)a, b, c);
+ __builtin_altivec_stvehx((vector short)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_ste(vector bool short a, int b, short *c)
+vec_ste(vector bool short __a, int __b, short *__c)
{
- __builtin_altivec_stvehx((vector short)a, b, c);
+ __builtin_altivec_stvehx((vector short)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_ste(vector bool short a, int b, unsigned short *c)
+vec_ste(vector bool short __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvehx((vector short)a, b, c);
+ __builtin_altivec_stvehx((vector short)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_ste(vector pixel a, int b, short *c)
+vec_ste(vector pixel __a, int __b, short *__c)
{
- __builtin_altivec_stvehx((vector short)a, b, c);
+ __builtin_altivec_stvehx((vector short)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_ste(vector pixel a, int b, unsigned short *c)
+vec_ste(vector pixel __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvehx((vector short)a, b, c);
+ __builtin_altivec_stvehx((vector short)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_ste(vector int a, int b, int *c)
+vec_ste(vector int __a, int __b, int *__c)
{
- __builtin_altivec_stvewx(a, b, c);
+ __builtin_altivec_stvewx(__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_ste(vector unsigned int a, int b, unsigned int *c)
+vec_ste(vector unsigned int __a, int __b, unsigned int *__c)
{
- __builtin_altivec_stvewx((vector int)a, b, c);
+ __builtin_altivec_stvewx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_ste(vector bool int a, int b, int *c)
+vec_ste(vector bool int __a, int __b, int *__c)
{
- __builtin_altivec_stvewx((vector int)a, b, c);
+ __builtin_altivec_stvewx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_ste(vector bool int a, int b, unsigned int *c)
+vec_ste(vector bool int __a, int __b, unsigned int *__c)
{
- __builtin_altivec_stvewx((vector int)a, b, c);
+ __builtin_altivec_stvewx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_ste(vector float a, int b, float *c)
+vec_ste(vector float __a, int __b, float *__c)
{
- __builtin_altivec_stvewx((vector int)a, b, c);
+ __builtin_altivec_stvewx((vector int)__a, __b, __c);
}
/* vec_stvebx */
static void __ATTRS_o_ai
-vec_stvebx(vector signed char a, int b, signed char *c)
+vec_stvebx(vector signed char __a, int __b, signed char *__c)
{
- __builtin_altivec_stvebx((vector char)a, b, c);
+ __builtin_altivec_stvebx((vector char)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvebx(vector unsigned char a, int b, unsigned char *c)
+vec_stvebx(vector unsigned char __a, int __b, unsigned char *__c)
{
- __builtin_altivec_stvebx((vector char)a, b, c);
+ __builtin_altivec_stvebx((vector char)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvebx(vector bool char a, int b, signed char *c)
+vec_stvebx(vector bool char __a, int __b, signed char *__c)
{
- __builtin_altivec_stvebx((vector char)a, b, c);
+ __builtin_altivec_stvebx((vector char)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvebx(vector bool char a, int b, unsigned char *c)
+vec_stvebx(vector bool char __a, int __b, unsigned char *__c)
{
- __builtin_altivec_stvebx((vector char)a, b, c);
+ __builtin_altivec_stvebx((vector char)__a, __b, __c);
}
/* vec_stvehx */
static void __ATTRS_o_ai
-vec_stvehx(vector short a, int b, short *c)
+vec_stvehx(vector short __a, int __b, short *__c)
{
- __builtin_altivec_stvehx(a, b, c);
+ __builtin_altivec_stvehx(__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvehx(vector unsigned short a, int b, unsigned short *c)
+vec_stvehx(vector unsigned short __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvehx((vector short)a, b, c);
+ __builtin_altivec_stvehx((vector short)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvehx(vector bool short a, int b, short *c)
+vec_stvehx(vector bool short __a, int __b, short *__c)
{
- __builtin_altivec_stvehx((vector short)a, b, c);
+ __builtin_altivec_stvehx((vector short)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvehx(vector bool short a, int b, unsigned short *c)
+vec_stvehx(vector bool short __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvehx((vector short)a, b, c);
+ __builtin_altivec_stvehx((vector short)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvehx(vector pixel a, int b, short *c)
+vec_stvehx(vector pixel __a, int __b, short *__c)
{
- __builtin_altivec_stvehx((vector short)a, b, c);
+ __builtin_altivec_stvehx((vector short)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvehx(vector pixel a, int b, unsigned short *c)
+vec_stvehx(vector pixel __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvehx((vector short)a, b, c);
+ __builtin_altivec_stvehx((vector short)__a, __b, __c);
}
/* vec_stvewx */
static void __ATTRS_o_ai
-vec_stvewx(vector int a, int b, int *c)
+vec_stvewx(vector int __a, int __b, int *__c)
{
- __builtin_altivec_stvewx(a, b, c);
+ __builtin_altivec_stvewx(__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvewx(vector unsigned int a, int b, unsigned int *c)
+vec_stvewx(vector unsigned int __a, int __b, unsigned int *__c)
{
- __builtin_altivec_stvewx((vector int)a, b, c);
+ __builtin_altivec_stvewx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvewx(vector bool int a, int b, int *c)
+vec_stvewx(vector bool int __a, int __b, int *__c)
{
- __builtin_altivec_stvewx((vector int)a, b, c);
+ __builtin_altivec_stvewx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvewx(vector bool int a, int b, unsigned int *c)
+vec_stvewx(vector bool int __a, int __b, unsigned int *__c)
{
- __builtin_altivec_stvewx((vector int)a, b, c);
+ __builtin_altivec_stvewx((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvewx(vector float a, int b, float *c)
+vec_stvewx(vector float __a, int __b, float *__c)
{
- __builtin_altivec_stvewx((vector int)a, b, c);
+ __builtin_altivec_stvewx((vector int)__a, __b, __c);
}
/* vec_stl */
static void __ATTRS_o_ai
-vec_stl(vector signed char a, int b, vector signed char *c)
+vec_stl(vector signed char __a, int __b, vector signed char *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector signed char a, int b, signed char *c)
+vec_stl(vector signed char __a, int __b, signed char *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector unsigned char a, int b, vector unsigned char *c)
+vec_stl(vector unsigned char __a, int __b, vector unsigned char *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector unsigned char a, int b, unsigned char *c)
+vec_stl(vector unsigned char __a, int __b, unsigned char *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector bool char a, int b, signed char *c)
+vec_stl(vector bool char __a, int __b, signed char *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector bool char a, int b, unsigned char *c)
+vec_stl(vector bool char __a, int __b, unsigned char *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector bool char a, int b, vector bool char *c)
+vec_stl(vector bool char __a, int __b, vector bool char *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector short a, int b, vector short *c)
+vec_stl(vector short __a, int __b, vector short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector short a, int b, short *c)
+vec_stl(vector short __a, int __b, short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector unsigned short a, int b, vector unsigned short *c)
+vec_stl(vector unsigned short __a, int __b, vector unsigned short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector unsigned short a, int b, unsigned short *c)
+vec_stl(vector unsigned short __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector bool short a, int b, short *c)
+vec_stl(vector bool short __a, int __b, short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector bool short a, int b, unsigned short *c)
+vec_stl(vector bool short __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector bool short a, int b, vector bool short *c)
+vec_stl(vector bool short __a, int __b, vector bool short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector pixel a, int b, short *c)
+vec_stl(vector pixel __a, int __b, short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector pixel a, int b, unsigned short *c)
+vec_stl(vector pixel __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector pixel a, int b, vector pixel *c)
+vec_stl(vector pixel __a, int __b, vector pixel *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector int a, int b, vector int *c)
+vec_stl(vector int __a, int __b, vector int *__c)
{
- __builtin_altivec_stvxl(a, b, c);
+ __builtin_altivec_stvxl(__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector int a, int b, int *c)
+vec_stl(vector int __a, int __b, int *__c)
{
- __builtin_altivec_stvxl(a, b, c);
+ __builtin_altivec_stvxl(__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector unsigned int a, int b, vector unsigned int *c)
+vec_stl(vector unsigned int __a, int __b, vector unsigned int *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector unsigned int a, int b, unsigned int *c)
+vec_stl(vector unsigned int __a, int __b, unsigned int *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector bool int a, int b, int *c)
+vec_stl(vector bool int __a, int __b, int *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector bool int a, int b, unsigned int *c)
+vec_stl(vector bool int __a, int __b, unsigned int *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector bool int a, int b, vector bool int *c)
+vec_stl(vector bool int __a, int __b, vector bool int *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector float a, int b, vector float *c)
+vec_stl(vector float __a, int __b, vector float *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stl(vector float a, int b, float *c)
+vec_stl(vector float __a, int __b, float *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
/* vec_stvxl */
static void __ATTRS_o_ai
-vec_stvxl(vector signed char a, int b, vector signed char *c)
+vec_stvxl(vector signed char __a, int __b, vector signed char *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector signed char a, int b, signed char *c)
+vec_stvxl(vector signed char __a, int __b, signed char *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector unsigned char a, int b, vector unsigned char *c)
+vec_stvxl(vector unsigned char __a, int __b, vector unsigned char *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector unsigned char a, int b, unsigned char *c)
+vec_stvxl(vector unsigned char __a, int __b, unsigned char *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector bool char a, int b, signed char *c)
+vec_stvxl(vector bool char __a, int __b, signed char *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector bool char a, int b, unsigned char *c)
+vec_stvxl(vector bool char __a, int __b, unsigned char *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector bool char a, int b, vector bool char *c)
+vec_stvxl(vector bool char __a, int __b, vector bool char *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector short a, int b, vector short *c)
+vec_stvxl(vector short __a, int __b, vector short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector short a, int b, short *c)
+vec_stvxl(vector short __a, int __b, short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector unsigned short a, int b, vector unsigned short *c)
+vec_stvxl(vector unsigned short __a, int __b, vector unsigned short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector unsigned short a, int b, unsigned short *c)
+vec_stvxl(vector unsigned short __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector bool short a, int b, short *c)
+vec_stvxl(vector bool short __a, int __b, short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector bool short a, int b, unsigned short *c)
+vec_stvxl(vector bool short __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector bool short a, int b, vector bool short *c)
+vec_stvxl(vector bool short __a, int __b, vector bool short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector pixel a, int b, short *c)
+vec_stvxl(vector pixel __a, int __b, short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector pixel a, int b, unsigned short *c)
+vec_stvxl(vector pixel __a, int __b, unsigned short *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector pixel a, int b, vector pixel *c)
+vec_stvxl(vector pixel __a, int __b, vector pixel *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector int a, int b, vector int *c)
+vec_stvxl(vector int __a, int __b, vector int *__c)
{
- __builtin_altivec_stvxl(a, b, c);
+ __builtin_altivec_stvxl(__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector int a, int b, int *c)
+vec_stvxl(vector int __a, int __b, int *__c)
{
- __builtin_altivec_stvxl(a, b, c);
+ __builtin_altivec_stvxl(__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector unsigned int a, int b, vector unsigned int *c)
+vec_stvxl(vector unsigned int __a, int __b, vector unsigned int *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector unsigned int a, int b, unsigned int *c)
+vec_stvxl(vector unsigned int __a, int __b, unsigned int *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector bool int a, int b, int *c)
+vec_stvxl(vector bool int __a, int __b, int *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector bool int a, int b, unsigned int *c)
+vec_stvxl(vector bool int __a, int __b, unsigned int *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector bool int a, int b, vector bool int *c)
+vec_stvxl(vector bool int __a, int __b, vector bool int *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector float a, int b, vector float *c)
+vec_stvxl(vector float __a, int __b, vector float *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
static void __ATTRS_o_ai
-vec_stvxl(vector float a, int b, float *c)
+vec_stvxl(vector float __a, int __b, float *__c)
{
- __builtin_altivec_stvxl((vector int)a, b, c);
+ __builtin_altivec_stvxl((vector int)__a, __b, __c);
}
/* vec_sub */
static vector signed char __ATTRS_o_ai
-vec_sub(vector signed char a, vector signed char b)
+vec_sub(vector signed char __a, vector signed char __b)
{
- return a - b;
+ return __a - __b;
}
static vector signed char __ATTRS_o_ai
-vec_sub(vector bool char a, vector signed char b)
+vec_sub(vector bool char __a, vector signed char __b)
{
- return (vector signed char)a - b;
+ return (vector signed char)__a - __b;
}
static vector signed char __ATTRS_o_ai
-vec_sub(vector signed char a, vector bool char b)
+vec_sub(vector signed char __a, vector bool char __b)
{
- return a - (vector signed char)b;
+ return __a - (vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_sub(vector unsigned char a, vector unsigned char b)
+vec_sub(vector unsigned char __a, vector unsigned char __b)
{
- return a - b;
+ return __a - __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_sub(vector bool char a, vector unsigned char b)
+vec_sub(vector bool char __a, vector unsigned char __b)
{
- return (vector unsigned char)a - b;
+ return (vector unsigned char)__a - __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_sub(vector unsigned char a, vector bool char b)
+vec_sub(vector unsigned char __a, vector bool char __b)
{
- return a - (vector unsigned char)b;
+ return __a - (vector unsigned char)__b;
}
static vector short __ATTRS_o_ai
-vec_sub(vector short a, vector short b)
+vec_sub(vector short __a, vector short __b)
{
- return a - b;
+ return __a - __b;
}
static vector short __ATTRS_o_ai
-vec_sub(vector bool short a, vector short b)
+vec_sub(vector bool short __a, vector short __b)
{
- return (vector short)a - b;
+ return (vector short)__a - __b;
}
static vector short __ATTRS_o_ai
-vec_sub(vector short a, vector bool short b)
+vec_sub(vector short __a, vector bool short __b)
{
- return a - (vector short)b;
+ return __a - (vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_sub(vector unsigned short a, vector unsigned short b)
+vec_sub(vector unsigned short __a, vector unsigned short __b)
{
- return a - b;
+ return __a - __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_sub(vector bool short a, vector unsigned short b)
+vec_sub(vector bool short __a, vector unsigned short __b)
{
- return (vector unsigned short)a - b;
+ return (vector unsigned short)__a - __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_sub(vector unsigned short a, vector bool short b)
+vec_sub(vector unsigned short __a, vector bool short __b)
{
- return a - (vector unsigned short)b;
+ return __a - (vector unsigned short)__b;
}
static vector int __ATTRS_o_ai
-vec_sub(vector int a, vector int b)
+vec_sub(vector int __a, vector int __b)
{
- return a - b;
+ return __a - __b;
}
static vector int __ATTRS_o_ai
-vec_sub(vector bool int a, vector int b)
+vec_sub(vector bool int __a, vector int __b)
{
- return (vector int)a - b;
+ return (vector int)__a - __b;
}
static vector int __ATTRS_o_ai
-vec_sub(vector int a, vector bool int b)
+vec_sub(vector int __a, vector bool int __b)
{
- return a - (vector int)b;
+ return __a - (vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_sub(vector unsigned int a, vector unsigned int b)
+vec_sub(vector unsigned int __a, vector unsigned int __b)
{
- return a - b;
+ return __a - __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_sub(vector bool int a, vector unsigned int b)
+vec_sub(vector bool int __a, vector unsigned int __b)
{
- return (vector unsigned int)a - b;
+ return (vector unsigned int)__a - __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_sub(vector unsigned int a, vector bool int b)
+vec_sub(vector unsigned int __a, vector bool int __b)
{
- return a - (vector unsigned int)b;
+ return __a - (vector unsigned int)__b;
}
static vector float __ATTRS_o_ai
-vec_sub(vector float a, vector float b)
+vec_sub(vector float __a, vector float __b)
{
- return a - b;
+ return __a - __b;
}
/* vec_vsububm */
@@ -7637,39 +7637,39 @@ vec_sub(vector float a, vector float b)
#define __builtin_altivec_vsububm vec_vsububm
static vector signed char __ATTRS_o_ai
-vec_vsububm(vector signed char a, vector signed char b)
+vec_vsububm(vector signed char __a, vector signed char __b)
{
- return a - b;
+ return __a - __b;
}
static vector signed char __ATTRS_o_ai
-vec_vsububm(vector bool char a, vector signed char b)
+vec_vsububm(vector bool char __a, vector signed char __b)
{
- return (vector signed char)a - b;
+ return (vector signed char)__a - __b;
}
static vector signed char __ATTRS_o_ai
-vec_vsububm(vector signed char a, vector bool char b)
+vec_vsububm(vector signed char __a, vector bool char __b)
{
- return a - (vector signed char)b;
+ return __a - (vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vsububm(vector unsigned char a, vector unsigned char b)
+vec_vsububm(vector unsigned char __a, vector unsigned char __b)
{
- return a - b;
+ return __a - __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vsububm(vector bool char a, vector unsigned char b)
+vec_vsububm(vector bool char __a, vector unsigned char __b)
{
- return (vector unsigned char)a - b;
+ return (vector unsigned char)__a - __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vsububm(vector unsigned char a, vector bool char b)
+vec_vsububm(vector unsigned char __a, vector bool char __b)
{
- return a - (vector unsigned char)b;
+ return __a - (vector unsigned char)__b;
}
/* vec_vsubuhm */
@@ -7677,39 +7677,39 @@ vec_vsububm(vector unsigned char a, vector bool char b)
#define __builtin_altivec_vsubuhm vec_vsubuhm
static vector short __ATTRS_o_ai
-vec_vsubuhm(vector short a, vector short b)
+vec_vsubuhm(vector short __a, vector short __b)
{
- return a - b;
+ return __a - __b;
}
static vector short __ATTRS_o_ai
-vec_vsubuhm(vector bool short a, vector short b)
+vec_vsubuhm(vector bool short __a, vector short __b)
{
- return (vector short)a - b;
+ return (vector short)__a - __b;
}
static vector short __ATTRS_o_ai
-vec_vsubuhm(vector short a, vector bool short b)
+vec_vsubuhm(vector short __a, vector bool short __b)
{
- return a - (vector short)b;
+ return __a - (vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vsubuhm(vector unsigned short a, vector unsigned short b)
+vec_vsubuhm(vector unsigned short __a, vector unsigned short __b)
{
- return a - b;
+ return __a - __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vsubuhm(vector bool short a, vector unsigned short b)
+vec_vsubuhm(vector bool short __a, vector unsigned short __b)
{
- return (vector unsigned short)a - b;
+ return (vector unsigned short)__a - __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vsubuhm(vector unsigned short a, vector bool short b)
+vec_vsubuhm(vector unsigned short __a, vector bool short __b)
{
- return a - (vector unsigned short)b;
+ return __a - (vector unsigned short)__b;
}
/* vec_vsubuwm */
@@ -7717,39 +7717,39 @@ vec_vsubuhm(vector unsigned short a, vector bool short b)
#define __builtin_altivec_vsubuwm vec_vsubuwm
static vector int __ATTRS_o_ai
-vec_vsubuwm(vector int a, vector int b)
+vec_vsubuwm(vector int __a, vector int __b)
{
- return a - b;
+ return __a - __b;
}
static vector int __ATTRS_o_ai
-vec_vsubuwm(vector bool int a, vector int b)
+vec_vsubuwm(vector bool int __a, vector int __b)
{
- return (vector int)a - b;
+ return (vector int)__a - __b;
}
static vector int __ATTRS_o_ai
-vec_vsubuwm(vector int a, vector bool int b)
+vec_vsubuwm(vector int __a, vector bool int __b)
{
- return a - (vector int)b;
+ return __a - (vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vsubuwm(vector unsigned int a, vector unsigned int b)
+vec_vsubuwm(vector unsigned int __a, vector unsigned int __b)
{
- return a - b;
+ return __a - __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vsubuwm(vector bool int a, vector unsigned int b)
+vec_vsubuwm(vector bool int __a, vector unsigned int __b)
{
- return (vector unsigned int)a - b;
+ return (vector unsigned int)__a - __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vsubuwm(vector unsigned int a, vector bool int b)
+vec_vsubuwm(vector unsigned int __a, vector bool int __b)
{
- return a - (vector unsigned int)b;
+ return __a - (vector unsigned int)__b;
}
/* vec_vsubfp */
@@ -7757,479 +7757,479 @@ vec_vsubuwm(vector unsigned int a, vector bool int b)
#define __builtin_altivec_vsubfp vec_vsubfp
static vector float __attribute__((__always_inline__))
-vec_vsubfp(vector float a, vector float b)
+vec_vsubfp(vector float __a, vector float __b)
{
- return a - b;
+ return __a - __b;
}
/* vec_subc */
static vector unsigned int __attribute__((__always_inline__))
-vec_subc(vector unsigned int a, vector unsigned int b)
+vec_subc(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vsubcuw(a, b);
+ return __builtin_altivec_vsubcuw(__a, __b);
}
/* vec_vsubcuw */
static vector unsigned int __attribute__((__always_inline__))
-vec_vsubcuw(vector unsigned int a, vector unsigned int b)
+vec_vsubcuw(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vsubcuw(a, b);
+ return __builtin_altivec_vsubcuw(__a, __b);
}
/* vec_subs */
static vector signed char __ATTRS_o_ai
-vec_subs(vector signed char a, vector signed char b)
+vec_subs(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vsubsbs(a, b);
+ return __builtin_altivec_vsubsbs(__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_subs(vector bool char a, vector signed char b)
+vec_subs(vector bool char __a, vector signed char __b)
{
- return __builtin_altivec_vsubsbs((vector signed char)a, b);
+ return __builtin_altivec_vsubsbs((vector signed char)__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_subs(vector signed char a, vector bool char b)
+vec_subs(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vsubsbs(a, (vector signed char)b);
+ return __builtin_altivec_vsubsbs(__a, (vector signed char)__b);
}
static vector unsigned char __ATTRS_o_ai
-vec_subs(vector unsigned char a, vector unsigned char b)
+vec_subs(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vsububs(a, b);
+ return __builtin_altivec_vsububs(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_subs(vector bool char a, vector unsigned char b)
+vec_subs(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vsububs((vector unsigned char)a, b);
+ return __builtin_altivec_vsububs((vector unsigned char)__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_subs(vector unsigned char a, vector bool char b)
+vec_subs(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vsububs(a, (vector unsigned char)b);
+ return __builtin_altivec_vsububs(__a, (vector unsigned char)__b);
}
static vector short __ATTRS_o_ai
-vec_subs(vector short a, vector short b)
+vec_subs(vector short __a, vector short __b)
{
- return __builtin_altivec_vsubshs(a, b);
+ return __builtin_altivec_vsubshs(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_subs(vector bool short a, vector short b)
+vec_subs(vector bool short __a, vector short __b)
{
- return __builtin_altivec_vsubshs((vector short)a, b);
+ return __builtin_altivec_vsubshs((vector short)__a, __b);
}
static vector short __ATTRS_o_ai
-vec_subs(vector short a, vector bool short b)
+vec_subs(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vsubshs(a, (vector short)b);
+ return __builtin_altivec_vsubshs(__a, (vector short)__b);
}
static vector unsigned short __ATTRS_o_ai
-vec_subs(vector unsigned short a, vector unsigned short b)
+vec_subs(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vsubuhs(a, b);
+ return __builtin_altivec_vsubuhs(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_subs(vector bool short a, vector unsigned short b)
+vec_subs(vector bool short __a, vector unsigned short __b)
{
- return __builtin_altivec_vsubuhs((vector unsigned short)a, b);
+ return __builtin_altivec_vsubuhs((vector unsigned short)__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_subs(vector unsigned short a, vector bool short b)
+vec_subs(vector unsigned short __a, vector bool short __b)
{
- return __builtin_altivec_vsubuhs(a, (vector unsigned short)b);
+ return __builtin_altivec_vsubuhs(__a, (vector unsigned short)__b);
}
static vector int __ATTRS_o_ai
-vec_subs(vector int a, vector int b)
+vec_subs(vector int __a, vector int __b)
{
- return __builtin_altivec_vsubsws(a, b);
+ return __builtin_altivec_vsubsws(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_subs(vector bool int a, vector int b)
+vec_subs(vector bool int __a, vector int __b)
{
- return __builtin_altivec_vsubsws((vector int)a, b);
+ return __builtin_altivec_vsubsws((vector int)__a, __b);
}
static vector int __ATTRS_o_ai
-vec_subs(vector int a, vector bool int b)
+vec_subs(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vsubsws(a, (vector int)b);
+ return __builtin_altivec_vsubsws(__a, (vector int)__b);
}
static vector unsigned int __ATTRS_o_ai
-vec_subs(vector unsigned int a, vector unsigned int b)
+vec_subs(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vsubuws(a, b);
+ return __builtin_altivec_vsubuws(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_subs(vector bool int a, vector unsigned int b)
+vec_subs(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vsubuws((vector unsigned int)a, b);
+ return __builtin_altivec_vsubuws((vector unsigned int)__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_subs(vector unsigned int a, vector bool int b)
+vec_subs(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vsubuws(a, (vector unsigned int)b);
+ return __builtin_altivec_vsubuws(__a, (vector unsigned int)__b);
}
/* vec_vsubsbs */
static vector signed char __ATTRS_o_ai
-vec_vsubsbs(vector signed char a, vector signed char b)
+vec_vsubsbs(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vsubsbs(a, b);
+ return __builtin_altivec_vsubsbs(__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_vsubsbs(vector bool char a, vector signed char b)
+vec_vsubsbs(vector bool char __a, vector signed char __b)
{
- return __builtin_altivec_vsubsbs((vector signed char)a, b);
+ return __builtin_altivec_vsubsbs((vector signed char)__a, __b);
}
static vector signed char __ATTRS_o_ai
-vec_vsubsbs(vector signed char a, vector bool char b)
+vec_vsubsbs(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vsubsbs(a, (vector signed char)b);
+ return __builtin_altivec_vsubsbs(__a, (vector signed char)__b);
}
/* vec_vsububs */
static vector unsigned char __ATTRS_o_ai
-vec_vsububs(vector unsigned char a, vector unsigned char b)
+vec_vsububs(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vsububs(a, b);
+ return __builtin_altivec_vsububs(__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vsububs(vector bool char a, vector unsigned char b)
+vec_vsububs(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vsububs((vector unsigned char)a, b);
+ return __builtin_altivec_vsububs((vector unsigned char)__a, __b);
}
static vector unsigned char __ATTRS_o_ai
-vec_vsububs(vector unsigned char a, vector bool char b)
+vec_vsububs(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vsububs(a, (vector unsigned char)b);
+ return __builtin_altivec_vsububs(__a, (vector unsigned char)__b);
}
/* vec_vsubshs */
static vector short __ATTRS_o_ai
-vec_vsubshs(vector short a, vector short b)
+vec_vsubshs(vector short __a, vector short __b)
{
- return __builtin_altivec_vsubshs(a, b);
+ return __builtin_altivec_vsubshs(__a, __b);
}
static vector short __ATTRS_o_ai
-vec_vsubshs(vector bool short a, vector short b)
+vec_vsubshs(vector bool short __a, vector short __b)
{
- return __builtin_altivec_vsubshs((vector short)a, b);
+ return __builtin_altivec_vsubshs((vector short)__a, __b);
}
static vector short __ATTRS_o_ai
-vec_vsubshs(vector short a, vector bool short b)
+vec_vsubshs(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vsubshs(a, (vector short)b);
+ return __builtin_altivec_vsubshs(__a, (vector short)__b);
}
/* vec_vsubuhs */
static vector unsigned short __ATTRS_o_ai
-vec_vsubuhs(vector unsigned short a, vector unsigned short b)
+vec_vsubuhs(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vsubuhs(a, b);
+ return __builtin_altivec_vsubuhs(__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vsubuhs(vector bool short a, vector unsigned short b)
+vec_vsubuhs(vector bool short __a, vector unsigned short __b)
{
- return __builtin_altivec_vsubuhs((vector unsigned short)a, b);
+ return __builtin_altivec_vsubuhs((vector unsigned short)__a, __b);
}
static vector unsigned short __ATTRS_o_ai
-vec_vsubuhs(vector unsigned short a, vector bool short b)
+vec_vsubuhs(vector unsigned short __a, vector bool short __b)
{
- return __builtin_altivec_vsubuhs(a, (vector unsigned short)b);
+ return __builtin_altivec_vsubuhs(__a, (vector unsigned short)__b);
}
/* vec_vsubsws */
static vector int __ATTRS_o_ai
-vec_vsubsws(vector int a, vector int b)
+vec_vsubsws(vector int __a, vector int __b)
{
- return __builtin_altivec_vsubsws(a, b);
+ return __builtin_altivec_vsubsws(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_vsubsws(vector bool int a, vector int b)
+vec_vsubsws(vector bool int __a, vector int __b)
{
- return __builtin_altivec_vsubsws((vector int)a, b);
+ return __builtin_altivec_vsubsws((vector int)__a, __b);
}
static vector int __ATTRS_o_ai
-vec_vsubsws(vector int a, vector bool int b)
+vec_vsubsws(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vsubsws(a, (vector int)b);
+ return __builtin_altivec_vsubsws(__a, (vector int)__b);
}
/* vec_vsubuws */
static vector unsigned int __ATTRS_o_ai
-vec_vsubuws(vector unsigned int a, vector unsigned int b)
+vec_vsubuws(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vsubuws(a, b);
+ return __builtin_altivec_vsubuws(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vsubuws(vector bool int a, vector unsigned int b)
+vec_vsubuws(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vsubuws((vector unsigned int)a, b);
+ return __builtin_altivec_vsubuws((vector unsigned int)__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_vsubuws(vector unsigned int a, vector bool int b)
+vec_vsubuws(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vsubuws(a, (vector unsigned int)b);
+ return __builtin_altivec_vsubuws(__a, (vector unsigned int)__b);
}
/* vec_sum4s */
static vector int __ATTRS_o_ai
-vec_sum4s(vector signed char a, vector int b)
+vec_sum4s(vector signed char __a, vector int __b)
{
- return __builtin_altivec_vsum4sbs(a, b);
+ return __builtin_altivec_vsum4sbs(__a, __b);
}
static vector unsigned int __ATTRS_o_ai
-vec_sum4s(vector unsigned char a, vector unsigned int b)
+vec_sum4s(vector unsigned char __a, vector unsigned int __b)
{
- return __builtin_altivec_vsum4ubs(a, b);
+ return __builtin_altivec_vsum4ubs(__a, __b);
}
static vector int __ATTRS_o_ai
-vec_sum4s(vector signed short a, vector int b)
+vec_sum4s(vector signed short __a, vector int __b)
{
- return __builtin_altivec_vsum4shs(a, b);
+ return __builtin_altivec_vsum4shs(__a, __b);
}
/* vec_vsum4sbs */
static vector int __attribute__((__always_inline__))
-vec_vsum4sbs(vector signed char a, vector int b)
+vec_vsum4sbs(vector signed char __a, vector int __b)
{
- return __builtin_altivec_vsum4sbs(a, b);
+ return __builtin_altivec_vsum4sbs(__a, __b);
}
/* vec_vsum4ubs */
static vector unsigned int __attribute__((__always_inline__))
-vec_vsum4ubs(vector unsigned char a, vector unsigned int b)
+vec_vsum4ubs(vector unsigned char __a, vector unsigned int __b)
{
- return __builtin_altivec_vsum4ubs(a, b);
+ return __builtin_altivec_vsum4ubs(__a, __b);
}
/* vec_vsum4shs */
static vector int __attribute__((__always_inline__))
-vec_vsum4shs(vector signed short a, vector int b)
+vec_vsum4shs(vector signed short __a, vector int __b)
{
- return __builtin_altivec_vsum4shs(a, b);
+ return __builtin_altivec_vsum4shs(__a, __b);
}
/* vec_sum2s */
static vector signed int __attribute__((__always_inline__))
-vec_sum2s(vector int a, vector int b)
+vec_sum2s(vector int __a, vector int __b)
{
- return __builtin_altivec_vsum2sws(a, b);
+ return __builtin_altivec_vsum2sws(__a, __b);
}
/* vec_vsum2sws */
static vector signed int __attribute__((__always_inline__))
-vec_vsum2sws(vector int a, vector int b)
+vec_vsum2sws(vector int __a, vector int __b)
{
- return __builtin_altivec_vsum2sws(a, b);
+ return __builtin_altivec_vsum2sws(__a, __b);
}
/* vec_sums */
static vector signed int __attribute__((__always_inline__))
-vec_sums(vector signed int a, vector signed int b)
+vec_sums(vector signed int __a, vector signed int __b)
{
- return __builtin_altivec_vsumsws(a, b);
+ return __builtin_altivec_vsumsws(__a, __b);
}
/* vec_vsumsws */
static vector signed int __attribute__((__always_inline__))
-vec_vsumsws(vector signed int a, vector signed int b)
+vec_vsumsws(vector signed int __a, vector signed int __b)
{
- return __builtin_altivec_vsumsws(a, b);
+ return __builtin_altivec_vsumsws(__a, __b);
}
/* vec_trunc */
static vector float __attribute__((__always_inline__))
-vec_trunc(vector float a)
+vec_trunc(vector float __a)
{
- return __builtin_altivec_vrfiz(a);
+ return __builtin_altivec_vrfiz(__a);
}
/* vec_vrfiz */
static vector float __attribute__((__always_inline__))
-vec_vrfiz(vector float a)
+vec_vrfiz(vector float __a)
{
- return __builtin_altivec_vrfiz(a);
+ return __builtin_altivec_vrfiz(__a);
}
/* vec_unpackh */
static vector short __ATTRS_o_ai
-vec_unpackh(vector signed char a)
+vec_unpackh(vector signed char __a)
{
- return __builtin_altivec_vupkhsb((vector char)a);
+ return __builtin_altivec_vupkhsb((vector char)__a);
}
static vector bool short __ATTRS_o_ai
-vec_unpackh(vector bool char a)
+vec_unpackh(vector bool char __a)
{
- return (vector bool short)__builtin_altivec_vupkhsb((vector char)a);
+ return (vector bool short)__builtin_altivec_vupkhsb((vector char)__a);
}
static vector int __ATTRS_o_ai
-vec_unpackh(vector short a)
+vec_unpackh(vector short __a)
{
- return __builtin_altivec_vupkhsh(a);
+ return __builtin_altivec_vupkhsh(__a);
}
static vector bool int __ATTRS_o_ai
-vec_unpackh(vector bool short a)
+vec_unpackh(vector bool short __a)
{
- return (vector bool int)__builtin_altivec_vupkhsh((vector short)a);
+ return (vector bool int)__builtin_altivec_vupkhsh((vector short)__a);
}
static vector unsigned int __ATTRS_o_ai
-vec_unpackh(vector pixel a)
+vec_unpackh(vector pixel __a)
{
- return (vector unsigned int)__builtin_altivec_vupkhsh((vector short)a);
+ return (vector unsigned int)__builtin_altivec_vupkhsh((vector short)__a);
}
/* vec_vupkhsb */
static vector short __ATTRS_o_ai
-vec_vupkhsb(vector signed char a)
+vec_vupkhsb(vector signed char __a)
{
- return __builtin_altivec_vupkhsb((vector char)a);
+ return __builtin_altivec_vupkhsb((vector char)__a);
}
static vector bool short __ATTRS_o_ai
-vec_vupkhsb(vector bool char a)
+vec_vupkhsb(vector bool char __a)
{
- return (vector bool short)__builtin_altivec_vupkhsb((vector char)a);
+ return (vector bool short)__builtin_altivec_vupkhsb((vector char)__a);
}
/* vec_vupkhsh */
static vector int __ATTRS_o_ai
-vec_vupkhsh(vector short a)
+vec_vupkhsh(vector short __a)
{
- return __builtin_altivec_vupkhsh(a);
+ return __builtin_altivec_vupkhsh(__a);
}
static vector bool int __ATTRS_o_ai
-vec_vupkhsh(vector bool short a)
+vec_vupkhsh(vector bool short __a)
{
- return (vector bool int)__builtin_altivec_vupkhsh((vector short)a);
+ return (vector bool int)__builtin_altivec_vupkhsh((vector short)__a);
}
static vector unsigned int __ATTRS_o_ai
-vec_vupkhsh(vector pixel a)
+vec_vupkhsh(vector pixel __a)
{
- return (vector unsigned int)__builtin_altivec_vupkhsh((vector short)a);
+ return (vector unsigned int)__builtin_altivec_vupkhsh((vector short)__a);
}
/* vec_unpackl */
static vector short __ATTRS_o_ai
-vec_unpackl(vector signed char a)
+vec_unpackl(vector signed char __a)
{
- return __builtin_altivec_vupklsb((vector char)a);
+ return __builtin_altivec_vupklsb((vector char)__a);
}
static vector bool short __ATTRS_o_ai
-vec_unpackl(vector bool char a)
+vec_unpackl(vector bool char __a)
{
- return (vector bool short)__builtin_altivec_vupklsb((vector char)a);
+ return (vector bool short)__builtin_altivec_vupklsb((vector char)__a);
}
static vector int __ATTRS_o_ai
-vec_unpackl(vector short a)
+vec_unpackl(vector short __a)
{
- return __builtin_altivec_vupklsh(a);
+ return __builtin_altivec_vupklsh(__a);
}
static vector bool int __ATTRS_o_ai
-vec_unpackl(vector bool short a)
+vec_unpackl(vector bool short __a)
{
- return (vector bool int)__builtin_altivec_vupklsh((vector short)a);
+ return (vector bool int)__builtin_altivec_vupklsh((vector short)__a);
}
static vector unsigned int __ATTRS_o_ai
-vec_unpackl(vector pixel a)
+vec_unpackl(vector pixel __a)
{
- return (vector unsigned int)__builtin_altivec_vupklsh((vector short)a);
+ return (vector unsigned int)__builtin_altivec_vupklsh((vector short)__a);
}
/* vec_vupklsb */
static vector short __ATTRS_o_ai
-vec_vupklsb(vector signed char a)
+vec_vupklsb(vector signed char __a)
{
- return __builtin_altivec_vupklsb((vector char)a);
+ return __builtin_altivec_vupklsb((vector char)__a);
}
static vector bool short __ATTRS_o_ai
-vec_vupklsb(vector bool char a)
+vec_vupklsb(vector bool char __a)
{
- return (vector bool short)__builtin_altivec_vupklsb((vector char)a);
+ return (vector bool short)__builtin_altivec_vupklsb((vector char)__a);
}
/* vec_vupklsh */
static vector int __ATTRS_o_ai
-vec_vupklsh(vector short a)
+vec_vupklsh(vector short __a)
{
- return __builtin_altivec_vupklsh(a);
+ return __builtin_altivec_vupklsh(__a);
}
static vector bool int __ATTRS_o_ai
-vec_vupklsh(vector bool short a)
+vec_vupklsh(vector bool short __a)
{
- return (vector bool int)__builtin_altivec_vupklsh((vector short)a);
+ return (vector bool int)__builtin_altivec_vupklsh((vector short)__a);
}
static vector unsigned int __ATTRS_o_ai
-vec_vupklsh(vector pixel a)
+vec_vupklsh(vector pixel __a)
{
- return (vector unsigned int)__builtin_altivec_vupklsh((vector short)a);
+ return (vector unsigned int)__builtin_altivec_vupklsh((vector short)__a);
}
/* vec_xor */
@@ -8237,299 +8237,299 @@ vec_vupklsh(vector pixel a)
#define __builtin_altivec_vxor vec_xor
static vector signed char __ATTRS_o_ai
-vec_xor(vector signed char a, vector signed char b)
+vec_xor(vector signed char __a, vector signed char __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector signed char __ATTRS_o_ai
-vec_xor(vector bool char a, vector signed char b)
+vec_xor(vector bool char __a, vector signed char __b)
{
- return (vector signed char)a ^ b;
+ return (vector signed char)__a ^ __b;
}
static vector signed char __ATTRS_o_ai
-vec_xor(vector signed char a, vector bool char b)
+vec_xor(vector signed char __a, vector bool char __b)
{
- return a ^ (vector signed char)b;
+ return __a ^ (vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_xor(vector unsigned char a, vector unsigned char b)
+vec_xor(vector unsigned char __a, vector unsigned char __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_xor(vector bool char a, vector unsigned char b)
+vec_xor(vector bool char __a, vector unsigned char __b)
{
- return (vector unsigned char)a ^ b;
+ return (vector unsigned char)__a ^ __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_xor(vector unsigned char a, vector bool char b)
+vec_xor(vector unsigned char __a, vector bool char __b)
{
- return a ^ (vector unsigned char)b;
+ return __a ^ (vector unsigned char)__b;
}
static vector bool char __ATTRS_o_ai
-vec_xor(vector bool char a, vector bool char b)
+vec_xor(vector bool char __a, vector bool char __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector short __ATTRS_o_ai
-vec_xor(vector short a, vector short b)
+vec_xor(vector short __a, vector short __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector short __ATTRS_o_ai
-vec_xor(vector bool short a, vector short b)
+vec_xor(vector bool short __a, vector short __b)
{
- return (vector short)a ^ b;
+ return (vector short)__a ^ __b;
}
static vector short __ATTRS_o_ai
-vec_xor(vector short a, vector bool short b)
+vec_xor(vector short __a, vector bool short __b)
{
- return a ^ (vector short)b;
+ return __a ^ (vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_xor(vector unsigned short a, vector unsigned short b)
+vec_xor(vector unsigned short __a, vector unsigned short __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_xor(vector bool short a, vector unsigned short b)
+vec_xor(vector bool short __a, vector unsigned short __b)
{
- return (vector unsigned short)a ^ b;
+ return (vector unsigned short)__a ^ __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_xor(vector unsigned short a, vector bool short b)
+vec_xor(vector unsigned short __a, vector bool short __b)
{
- return a ^ (vector unsigned short)b;
+ return __a ^ (vector unsigned short)__b;
}
static vector bool short __ATTRS_o_ai
-vec_xor(vector bool short a, vector bool short b)
+vec_xor(vector bool short __a, vector bool short __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector int __ATTRS_o_ai
-vec_xor(vector int a, vector int b)
+vec_xor(vector int __a, vector int __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector int __ATTRS_o_ai
-vec_xor(vector bool int a, vector int b)
+vec_xor(vector bool int __a, vector int __b)
{
- return (vector int)a ^ b;
+ return (vector int)__a ^ __b;
}
static vector int __ATTRS_o_ai
-vec_xor(vector int a, vector bool int b)
+vec_xor(vector int __a, vector bool int __b)
{
- return a ^ (vector int)b;
+ return __a ^ (vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_xor(vector unsigned int a, vector unsigned int b)
+vec_xor(vector unsigned int __a, vector unsigned int __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_xor(vector bool int a, vector unsigned int b)
+vec_xor(vector bool int __a, vector unsigned int __b)
{
- return (vector unsigned int)a ^ b;
+ return (vector unsigned int)__a ^ __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_xor(vector unsigned int a, vector bool int b)
+vec_xor(vector unsigned int __a, vector bool int __b)
{
- return a ^ (vector unsigned int)b;
+ return __a ^ (vector unsigned int)__b;
}
static vector bool int __ATTRS_o_ai
-vec_xor(vector bool int a, vector bool int b)
+vec_xor(vector bool int __a, vector bool int __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector float __ATTRS_o_ai
-vec_xor(vector float a, vector float b)
+vec_xor(vector float __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a ^ (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a ^ (vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_xor(vector bool int a, vector float b)
+vec_xor(vector bool int __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a ^ (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a ^ (vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_xor(vector float a, vector bool int b)
+vec_xor(vector float __a, vector bool int __b)
{
- vector unsigned int res = (vector unsigned int)a ^ (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a ^ (vector unsigned int)__b;
+ return (vector float)__res;
}
/* vec_vxor */
static vector signed char __ATTRS_o_ai
-vec_vxor(vector signed char a, vector signed char b)
+vec_vxor(vector signed char __a, vector signed char __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector signed char __ATTRS_o_ai
-vec_vxor(vector bool char a, vector signed char b)
+vec_vxor(vector bool char __a, vector signed char __b)
{
- return (vector signed char)a ^ b;
+ return (vector signed char)__a ^ __b;
}
static vector signed char __ATTRS_o_ai
-vec_vxor(vector signed char a, vector bool char b)
+vec_vxor(vector signed char __a, vector bool char __b)
{
- return a ^ (vector signed char)b;
+ return __a ^ (vector signed char)__b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vxor(vector unsigned char a, vector unsigned char b)
+vec_vxor(vector unsigned char __a, vector unsigned char __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vxor(vector bool char a, vector unsigned char b)
+vec_vxor(vector bool char __a, vector unsigned char __b)
{
- return (vector unsigned char)a ^ b;
+ return (vector unsigned char)__a ^ __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_vxor(vector unsigned char a, vector bool char b)
+vec_vxor(vector unsigned char __a, vector bool char __b)
{
- return a ^ (vector unsigned char)b;
+ return __a ^ (vector unsigned char)__b;
}
static vector bool char __ATTRS_o_ai
-vec_vxor(vector bool char a, vector bool char b)
+vec_vxor(vector bool char __a, vector bool char __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector short __ATTRS_o_ai
-vec_vxor(vector short a, vector short b)
+vec_vxor(vector short __a, vector short __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector short __ATTRS_o_ai
-vec_vxor(vector bool short a, vector short b)
+vec_vxor(vector bool short __a, vector short __b)
{
- return (vector short)a ^ b;
+ return (vector short)__a ^ __b;
}
static vector short __ATTRS_o_ai
-vec_vxor(vector short a, vector bool short b)
+vec_vxor(vector short __a, vector bool short __b)
{
- return a ^ (vector short)b;
+ return __a ^ (vector short)__b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vxor(vector unsigned short a, vector unsigned short b)
+vec_vxor(vector unsigned short __a, vector unsigned short __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vxor(vector bool short a, vector unsigned short b)
+vec_vxor(vector bool short __a, vector unsigned short __b)
{
- return (vector unsigned short)a ^ b;
+ return (vector unsigned short)__a ^ __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_vxor(vector unsigned short a, vector bool short b)
+vec_vxor(vector unsigned short __a, vector bool short __b)
{
- return a ^ (vector unsigned short)b;
+ return __a ^ (vector unsigned short)__b;
}
static vector bool short __ATTRS_o_ai
-vec_vxor(vector bool short a, vector bool short b)
+vec_vxor(vector bool short __a, vector bool short __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector int __ATTRS_o_ai
-vec_vxor(vector int a, vector int b)
+vec_vxor(vector int __a, vector int __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector int __ATTRS_o_ai
-vec_vxor(vector bool int a, vector int b)
+vec_vxor(vector bool int __a, vector int __b)
{
- return (vector int)a ^ b;
+ return (vector int)__a ^ __b;
}
static vector int __ATTRS_o_ai
-vec_vxor(vector int a, vector bool int b)
+vec_vxor(vector int __a, vector bool int __b)
{
- return a ^ (vector int)b;
+ return __a ^ (vector int)__b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vxor(vector unsigned int a, vector unsigned int b)
+vec_vxor(vector unsigned int __a, vector unsigned int __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vxor(vector bool int a, vector unsigned int b)
+vec_vxor(vector bool int __a, vector unsigned int __b)
{
- return (vector unsigned int)a ^ b;
+ return (vector unsigned int)__a ^ __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_vxor(vector unsigned int a, vector bool int b)
+vec_vxor(vector unsigned int __a, vector bool int __b)
{
- return a ^ (vector unsigned int)b;
+ return __a ^ (vector unsigned int)__b;
}
static vector bool int __ATTRS_o_ai
-vec_vxor(vector bool int a, vector bool int b)
+vec_vxor(vector bool int __a, vector bool int __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static vector float __ATTRS_o_ai
-vec_vxor(vector float a, vector float b)
+vec_vxor(vector float __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a ^ (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a ^ (vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_vxor(vector bool int a, vector float b)
+vec_vxor(vector bool int __a, vector float __b)
{
- vector unsigned int res = (vector unsigned int)a ^ (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a ^ (vector unsigned int)__b;
+ return (vector float)__res;
}
static vector float __ATTRS_o_ai
-vec_vxor(vector float a, vector bool int b)
+vec_vxor(vector float __a, vector bool int __b)
{
- vector unsigned int res = (vector unsigned int)a ^ (vector unsigned int)b;
- return (vector float)res;
+ vector unsigned int __res = (vector unsigned int)__a ^ (vector unsigned int)__b;
+ return (vector float)__res;
}
/* ------------------------ extensions for CBEA ----------------------------- */
@@ -8537,1402 +8537,1402 @@ vec_vxor(vector float a, vector bool int b)
/* vec_extract */
static signed char __ATTRS_o_ai
-vec_extract(vector signed char a, int b)
+vec_extract(vector signed char __a, int __b)
{
- return a[b];
+ return __a[__b];
}
static unsigned char __ATTRS_o_ai
-vec_extract(vector unsigned char a, int b)
+vec_extract(vector unsigned char __a, int __b)
{
- return a[b];
+ return __a[__b];
}
static short __ATTRS_o_ai
-vec_extract(vector short a, int b)
+vec_extract(vector short __a, int __b)
{
- return a[b];
+ return __a[__b];
}
static unsigned short __ATTRS_o_ai
-vec_extract(vector unsigned short a, int b)
+vec_extract(vector unsigned short __a, int __b)
{
- return a[b];
+ return __a[__b];
}
static int __ATTRS_o_ai
-vec_extract(vector int a, int b)
+vec_extract(vector int __a, int __b)
{
- return a[b];
+ return __a[__b];
}
static unsigned int __ATTRS_o_ai
-vec_extract(vector unsigned int a, int b)
+vec_extract(vector unsigned int __a, int __b)
{
- return a[b];
+ return __a[__b];
}
static float __ATTRS_o_ai
-vec_extract(vector float a, int b)
+vec_extract(vector float __a, int __b)
{
- return a[b];
+ return __a[__b];
}
/* vec_insert */
static vector signed char __ATTRS_o_ai
-vec_insert(signed char a, vector signed char b, int c)
+vec_insert(signed char __a, vector signed char __b, int __c)
{
- b[c] = a;
- return b;
+ __b[__c] = __a;
+ return __b;
}
static vector unsigned char __ATTRS_o_ai
-vec_insert(unsigned char a, vector unsigned char b, int c)
+vec_insert(unsigned char __a, vector unsigned char __b, int __c)
{
- b[c] = a;
- return b;
+ __b[__c] = __a;
+ return __b;
}
static vector short __ATTRS_o_ai
-vec_insert(short a, vector short b, int c)
+vec_insert(short __a, vector short __b, int __c)
{
- b[c] = a;
- return b;
+ __b[__c] = __a;
+ return __b;
}
static vector unsigned short __ATTRS_o_ai
-vec_insert(unsigned short a, vector unsigned short b, int c)
+vec_insert(unsigned short __a, vector unsigned short __b, int __c)
{
- b[c] = a;
- return b;
+ __b[__c] = __a;
+ return __b;
}
static vector int __ATTRS_o_ai
-vec_insert(int a, vector int b, int c)
+vec_insert(int __a, vector int __b, int __c)
{
- b[c] = a;
- return b;
+ __b[__c] = __a;
+ return __b;
}
static vector unsigned int __ATTRS_o_ai
-vec_insert(unsigned int a, vector unsigned int b, int c)
+vec_insert(unsigned int __a, vector unsigned int __b, int __c)
{
- b[c] = a;
- return b;
+ __b[__c] = __a;
+ return __b;
}
static vector float __ATTRS_o_ai
-vec_insert(float a, vector float b, int c)
+vec_insert(float __a, vector float __b, int __c)
{
- b[c] = a;
- return b;
+ __b[__c] = __a;
+ return __b;
}
/* vec_lvlx */
static vector signed char __ATTRS_o_ai
-vec_lvlx(int a, const signed char *b)
+vec_lvlx(int __a, const signed char *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector signed char)(0),
- vec_lvsl(a, b));
+ vec_lvsl(__a, __b));
}
static vector signed char __ATTRS_o_ai
-vec_lvlx(int a, const vector signed char *b)
+vec_lvlx(int __a, const vector signed char *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector signed char)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector unsigned char __ATTRS_o_ai
-vec_lvlx(int a, const unsigned char *b)
+vec_lvlx(int __a, const unsigned char *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector unsigned char)(0),
- vec_lvsl(a, b));
+ vec_lvsl(__a, __b));
}
static vector unsigned char __ATTRS_o_ai
-vec_lvlx(int a, const vector unsigned char *b)
+vec_lvlx(int __a, const vector unsigned char *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector unsigned char)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector bool char __ATTRS_o_ai
-vec_lvlx(int a, const vector bool char *b)
+vec_lvlx(int __a, const vector bool char *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector bool char)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector short __ATTRS_o_ai
-vec_lvlx(int a, const short *b)
+vec_lvlx(int __a, const short *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector short)(0),
- vec_lvsl(a, b));
+ vec_lvsl(__a, __b));
}
static vector short __ATTRS_o_ai
-vec_lvlx(int a, const vector short *b)
+vec_lvlx(int __a, const vector short *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector short)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector unsigned short __ATTRS_o_ai
-vec_lvlx(int a, const unsigned short *b)
+vec_lvlx(int __a, const unsigned short *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector unsigned short)(0),
- vec_lvsl(a, b));
+ vec_lvsl(__a, __b));
}
static vector unsigned short __ATTRS_o_ai
-vec_lvlx(int a, const vector unsigned short *b)
+vec_lvlx(int __a, const vector unsigned short *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector unsigned short)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector bool short __ATTRS_o_ai
-vec_lvlx(int a, const vector bool short *b)
+vec_lvlx(int __a, const vector bool short *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector bool short)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector pixel __ATTRS_o_ai
-vec_lvlx(int a, const vector pixel *b)
+vec_lvlx(int __a, const vector pixel *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector pixel)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector int __ATTRS_o_ai
-vec_lvlx(int a, const int *b)
+vec_lvlx(int __a, const int *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector int)(0),
- vec_lvsl(a, b));
+ vec_lvsl(__a, __b));
}
static vector int __ATTRS_o_ai
-vec_lvlx(int a, const vector int *b)
+vec_lvlx(int __a, const vector int *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector int)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector unsigned int __ATTRS_o_ai
-vec_lvlx(int a, const unsigned int *b)
+vec_lvlx(int __a, const unsigned int *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector unsigned int)(0),
- vec_lvsl(a, b));
+ vec_lvsl(__a, __b));
}
static vector unsigned int __ATTRS_o_ai
-vec_lvlx(int a, const vector unsigned int *b)
+vec_lvlx(int __a, const vector unsigned int *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector unsigned int)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector bool int __ATTRS_o_ai
-vec_lvlx(int a, const vector bool int *b)
+vec_lvlx(int __a, const vector bool int *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector bool int)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector float __ATTRS_o_ai
-vec_lvlx(int a, const float *b)
+vec_lvlx(int __a, const float *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector float)(0),
- vec_lvsl(a, b));
+ vec_lvsl(__a, __b));
}
static vector float __ATTRS_o_ai
-vec_lvlx(int a, const vector float *b)
+vec_lvlx(int __a, const vector float *__b)
{
- return vec_perm(vec_ld(a, b),
+ return vec_perm(vec_ld(__a, __b),
(vector float)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
/* vec_lvlxl */
static vector signed char __ATTRS_o_ai
-vec_lvlxl(int a, const signed char *b)
+vec_lvlxl(int __a, const signed char *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector signed char)(0),
- vec_lvsl(a, b));
+ vec_lvsl(__a, __b));
}
static vector signed char __ATTRS_o_ai
-vec_lvlxl(int a, const vector signed char *b)
+vec_lvlxl(int __a, const vector signed char *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector signed char)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector unsigned char __ATTRS_o_ai
-vec_lvlxl(int a, const unsigned char *b)
+vec_lvlxl(int __a, const unsigned char *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector unsigned char)(0),
- vec_lvsl(a, b));
+ vec_lvsl(__a, __b));
}
static vector unsigned char __ATTRS_o_ai
-vec_lvlxl(int a, const vector unsigned char *b)
+vec_lvlxl(int __a, const vector unsigned char *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector unsigned char)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector bool char __ATTRS_o_ai
-vec_lvlxl(int a, const vector bool char *b)
+vec_lvlxl(int __a, const vector bool char *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector bool char)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector short __ATTRS_o_ai
-vec_lvlxl(int a, const short *b)
+vec_lvlxl(int __a, const short *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector short)(0),
- vec_lvsl(a, b));
+ vec_lvsl(__a, __b));
}
static vector short __ATTRS_o_ai
-vec_lvlxl(int a, const vector short *b)
+vec_lvlxl(int __a, const vector short *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector short)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector unsigned short __ATTRS_o_ai
-vec_lvlxl(int a, const unsigned short *b)
+vec_lvlxl(int __a, const unsigned short *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector unsigned short)(0),
- vec_lvsl(a, b));
+ vec_lvsl(__a, __b));
}
static vector unsigned short __ATTRS_o_ai
-vec_lvlxl(int a, const vector unsigned short *b)
+vec_lvlxl(int __a, const vector unsigned short *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector unsigned short)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector bool short __ATTRS_o_ai
-vec_lvlxl(int a, const vector bool short *b)
+vec_lvlxl(int __a, const vector bool short *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector bool short)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector pixel __ATTRS_o_ai
-vec_lvlxl(int a, const vector pixel *b)
+vec_lvlxl(int __a, const vector pixel *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector pixel)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector int __ATTRS_o_ai
-vec_lvlxl(int a, const int *b)
+vec_lvlxl(int __a, const int *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector int)(0),
- vec_lvsl(a, b));
+ vec_lvsl(__a, __b));
}
static vector int __ATTRS_o_ai
-vec_lvlxl(int a, const vector int *b)
+vec_lvlxl(int __a, const vector int *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector int)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector unsigned int __ATTRS_o_ai
-vec_lvlxl(int a, const unsigned int *b)
+vec_lvlxl(int __a, const unsigned int *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector unsigned int)(0),
- vec_lvsl(a, b));
+ vec_lvsl(__a, __b));
}
static vector unsigned int __ATTRS_o_ai
-vec_lvlxl(int a, const vector unsigned int *b)
+vec_lvlxl(int __a, const vector unsigned int *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector unsigned int)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector bool int __ATTRS_o_ai
-vec_lvlxl(int a, const vector bool int *b)
+vec_lvlxl(int __a, const vector bool int *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector bool int)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector float __ATTRS_o_ai
-vec_lvlxl(int a, const float *b)
+vec_lvlxl(int __a, const float *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector float)(0),
- vec_lvsl(a, b));
+ vec_lvsl(__a, __b));
}
static vector float __ATTRS_o_ai
-vec_lvlxl(int a, vector float *b)
+vec_lvlxl(int __a, vector float *__b)
{
- return vec_perm(vec_ldl(a, b),
+ return vec_perm(vec_ldl(__a, __b),
(vector float)(0),
- vec_lvsl(a, (unsigned char *)b));
+ vec_lvsl(__a, (unsigned char *)__b));
}
/* vec_lvrx */
static vector signed char __ATTRS_o_ai
-vec_lvrx(int a, const signed char *b)
+vec_lvrx(int __a, const signed char *__b)
{
return vec_perm((vector signed char)(0),
- vec_ld(a, b),
- vec_lvsl(a, b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, __b));
}
static vector signed char __ATTRS_o_ai
-vec_lvrx(int a, const vector signed char *b)
+vec_lvrx(int __a, const vector signed char *__b)
{
return vec_perm((vector signed char)(0),
- vec_ld(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector unsigned char __ATTRS_o_ai
-vec_lvrx(int a, const unsigned char *b)
+vec_lvrx(int __a, const unsigned char *__b)
{
return vec_perm((vector unsigned char)(0),
- vec_ld(a, b),
- vec_lvsl(a, b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, __b));
}
static vector unsigned char __ATTRS_o_ai
-vec_lvrx(int a, const vector unsigned char *b)
+vec_lvrx(int __a, const vector unsigned char *__b)
{
return vec_perm((vector unsigned char)(0),
- vec_ld(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector bool char __ATTRS_o_ai
-vec_lvrx(int a, const vector bool char *b)
+vec_lvrx(int __a, const vector bool char *__b)
{
return vec_perm((vector bool char)(0),
- vec_ld(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector short __ATTRS_o_ai
-vec_lvrx(int a, const short *b)
+vec_lvrx(int __a, const short *__b)
{
return vec_perm((vector short)(0),
- vec_ld(a, b),
- vec_lvsl(a, b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, __b));
}
static vector short __ATTRS_o_ai
-vec_lvrx(int a, const vector short *b)
+vec_lvrx(int __a, const vector short *__b)
{
return vec_perm((vector short)(0),
- vec_ld(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector unsigned short __ATTRS_o_ai
-vec_lvrx(int a, const unsigned short *b)
+vec_lvrx(int __a, const unsigned short *__b)
{
return vec_perm((vector unsigned short)(0),
- vec_ld(a, b),
- vec_lvsl(a, b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, __b));
}
static vector unsigned short __ATTRS_o_ai
-vec_lvrx(int a, const vector unsigned short *b)
+vec_lvrx(int __a, const vector unsigned short *__b)
{
return vec_perm((vector unsigned short)(0),
- vec_ld(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector bool short __ATTRS_o_ai
-vec_lvrx(int a, const vector bool short *b)
+vec_lvrx(int __a, const vector bool short *__b)
{
return vec_perm((vector bool short)(0),
- vec_ld(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector pixel __ATTRS_o_ai
-vec_lvrx(int a, const vector pixel *b)
+vec_lvrx(int __a, const vector pixel *__b)
{
return vec_perm((vector pixel)(0),
- vec_ld(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector int __ATTRS_o_ai
-vec_lvrx(int a, const int *b)
+vec_lvrx(int __a, const int *__b)
{
return vec_perm((vector int)(0),
- vec_ld(a, b),
- vec_lvsl(a, b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, __b));
}
static vector int __ATTRS_o_ai
-vec_lvrx(int a, const vector int *b)
+vec_lvrx(int __a, const vector int *__b)
{
return vec_perm((vector int)(0),
- vec_ld(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector unsigned int __ATTRS_o_ai
-vec_lvrx(int a, const unsigned int *b)
+vec_lvrx(int __a, const unsigned int *__b)
{
return vec_perm((vector unsigned int)(0),
- vec_ld(a, b),
- vec_lvsl(a, b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, __b));
}
static vector unsigned int __ATTRS_o_ai
-vec_lvrx(int a, const vector unsigned int *b)
+vec_lvrx(int __a, const vector unsigned int *__b)
{
return vec_perm((vector unsigned int)(0),
- vec_ld(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector bool int __ATTRS_o_ai
-vec_lvrx(int a, const vector bool int *b)
+vec_lvrx(int __a, const vector bool int *__b)
{
return vec_perm((vector bool int)(0),
- vec_ld(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector float __ATTRS_o_ai
-vec_lvrx(int a, const float *b)
+vec_lvrx(int __a, const float *__b)
{
return vec_perm((vector float)(0),
- vec_ld(a, b),
- vec_lvsl(a, b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, __b));
}
static vector float __ATTRS_o_ai
-vec_lvrx(int a, const vector float *b)
+vec_lvrx(int __a, const vector float *__b)
{
return vec_perm((vector float)(0),
- vec_ld(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ld(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
/* vec_lvrxl */
static vector signed char __ATTRS_o_ai
-vec_lvrxl(int a, const signed char *b)
+vec_lvrxl(int __a, const signed char *__b)
{
return vec_perm((vector signed char)(0),
- vec_ldl(a, b),
- vec_lvsl(a, b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, __b));
}
static vector signed char __ATTRS_o_ai
-vec_lvrxl(int a, const vector signed char *b)
+vec_lvrxl(int __a, const vector signed char *__b)
{
return vec_perm((vector signed char)(0),
- vec_ldl(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector unsigned char __ATTRS_o_ai
-vec_lvrxl(int a, const unsigned char *b)
+vec_lvrxl(int __a, const unsigned char *__b)
{
return vec_perm((vector unsigned char)(0),
- vec_ldl(a, b),
- vec_lvsl(a, b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, __b));
}
static vector unsigned char __ATTRS_o_ai
-vec_lvrxl(int a, const vector unsigned char *b)
+vec_lvrxl(int __a, const vector unsigned char *__b)
{
return vec_perm((vector unsigned char)(0),
- vec_ldl(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector bool char __ATTRS_o_ai
-vec_lvrxl(int a, const vector bool char *b)
+vec_lvrxl(int __a, const vector bool char *__b)
{
return vec_perm((vector bool char)(0),
- vec_ldl(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector short __ATTRS_o_ai
-vec_lvrxl(int a, const short *b)
+vec_lvrxl(int __a, const short *__b)
{
return vec_perm((vector short)(0),
- vec_ldl(a, b),
- vec_lvsl(a, b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, __b));
}
static vector short __ATTRS_o_ai
-vec_lvrxl(int a, const vector short *b)
+vec_lvrxl(int __a, const vector short *__b)
{
return vec_perm((vector short)(0),
- vec_ldl(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector unsigned short __ATTRS_o_ai
-vec_lvrxl(int a, const unsigned short *b)
+vec_lvrxl(int __a, const unsigned short *__b)
{
return vec_perm((vector unsigned short)(0),
- vec_ldl(a, b),
- vec_lvsl(a, b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, __b));
}
static vector unsigned short __ATTRS_o_ai
-vec_lvrxl(int a, const vector unsigned short *b)
+vec_lvrxl(int __a, const vector unsigned short *__b)
{
return vec_perm((vector unsigned short)(0),
- vec_ldl(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector bool short __ATTRS_o_ai
-vec_lvrxl(int a, const vector bool short *b)
+vec_lvrxl(int __a, const vector bool short *__b)
{
return vec_perm((vector bool short)(0),
- vec_ldl(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector pixel __ATTRS_o_ai
-vec_lvrxl(int a, const vector pixel *b)
+vec_lvrxl(int __a, const vector pixel *__b)
{
return vec_perm((vector pixel)(0),
- vec_ldl(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector int __ATTRS_o_ai
-vec_lvrxl(int a, const int *b)
+vec_lvrxl(int __a, const int *__b)
{
return vec_perm((vector int)(0),
- vec_ldl(a, b),
- vec_lvsl(a, b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, __b));
}
static vector int __ATTRS_o_ai
-vec_lvrxl(int a, const vector int *b)
+vec_lvrxl(int __a, const vector int *__b)
{
return vec_perm((vector int)(0),
- vec_ldl(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector unsigned int __ATTRS_o_ai
-vec_lvrxl(int a, const unsigned int *b)
+vec_lvrxl(int __a, const unsigned int *__b)
{
return vec_perm((vector unsigned int)(0),
- vec_ldl(a, b),
- vec_lvsl(a, b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, __b));
}
static vector unsigned int __ATTRS_o_ai
-vec_lvrxl(int a, const vector unsigned int *b)
+vec_lvrxl(int __a, const vector unsigned int *__b)
{
return vec_perm((vector unsigned int)(0),
- vec_ldl(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector bool int __ATTRS_o_ai
-vec_lvrxl(int a, const vector bool int *b)
+vec_lvrxl(int __a, const vector bool int *__b)
{
return vec_perm((vector bool int)(0),
- vec_ldl(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
static vector float __ATTRS_o_ai
-vec_lvrxl(int a, const float *b)
+vec_lvrxl(int __a, const float *__b)
{
return vec_perm((vector float)(0),
- vec_ldl(a, b),
- vec_lvsl(a, b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, __b));
}
static vector float __ATTRS_o_ai
-vec_lvrxl(int a, const vector float *b)
+vec_lvrxl(int __a, const vector float *__b)
{
return vec_perm((vector float)(0),
- vec_ldl(a, b),
- vec_lvsl(a, (unsigned char *)b));
+ vec_ldl(__a, __b),
+ vec_lvsl(__a, (unsigned char *)__b));
}
/* vec_stvlx */
static void __ATTRS_o_ai
-vec_stvlx(vector signed char a, int b, signed char *c)
+vec_stvlx(vector signed char __a, int __b, signed char *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector signed char a, int b, vector signed char *c)
+vec_stvlx(vector signed char __a, int __b, vector signed char *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector unsigned char a, int b, unsigned char *c)
+vec_stvlx(vector unsigned char __a, int __b, unsigned char *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector unsigned char a, int b, vector unsigned char *c)
+vec_stvlx(vector unsigned char __a, int __b, vector unsigned char *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector bool char a, int b, vector bool char *c)
+vec_stvlx(vector bool char __a, int __b, vector bool char *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector short a, int b, short *c)
+vec_stvlx(vector short __a, int __b, short *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector short a, int b, vector short *c)
+vec_stvlx(vector short __a, int __b, vector short *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector unsigned short a, int b, unsigned short *c)
+vec_stvlx(vector unsigned short __a, int __b, unsigned short *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector unsigned short a, int b, vector unsigned short *c)
+vec_stvlx(vector unsigned short __a, int __b, vector unsigned short *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector bool short a, int b, vector bool short *c)
+vec_stvlx(vector bool short __a, int __b, vector bool short *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector pixel a, int b, vector pixel *c)
+vec_stvlx(vector pixel __a, int __b, vector pixel *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector int a, int b, int *c)
+vec_stvlx(vector int __a, int __b, int *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector int a, int b, vector int *c)
+vec_stvlx(vector int __a, int __b, vector int *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector unsigned int a, int b, unsigned int *c)
+vec_stvlx(vector unsigned int __a, int __b, unsigned int *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector unsigned int a, int b, vector unsigned int *c)
+vec_stvlx(vector unsigned int __a, int __b, vector unsigned int *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector bool int a, int b, vector bool int *c)
+vec_stvlx(vector bool int __a, int __b, vector bool int *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlx(vector float a, int b, vector float *c)
+vec_stvlx(vector float __a, int __b, vector float *__c)
{
- return vec_st(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
/* vec_stvlxl */
static void __ATTRS_o_ai
-vec_stvlxl(vector signed char a, int b, signed char *c)
+vec_stvlxl(vector signed char __a, int __b, signed char *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector signed char a, int b, vector signed char *c)
+vec_stvlxl(vector signed char __a, int __b, vector signed char *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector unsigned char a, int b, unsigned char *c)
+vec_stvlxl(vector unsigned char __a, int __b, unsigned char *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector unsigned char a, int b, vector unsigned char *c)
+vec_stvlxl(vector unsigned char __a, int __b, vector unsigned char *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector bool char a, int b, vector bool char *c)
+vec_stvlxl(vector bool char __a, int __b, vector bool char *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector short a, int b, short *c)
+vec_stvlxl(vector short __a, int __b, short *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector short a, int b, vector short *c)
+vec_stvlxl(vector short __a, int __b, vector short *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector unsigned short a, int b, unsigned short *c)
+vec_stvlxl(vector unsigned short __a, int __b, unsigned short *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector unsigned short a, int b, vector unsigned short *c)
+vec_stvlxl(vector unsigned short __a, int __b, vector unsigned short *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector bool short a, int b, vector bool short *c)
+vec_stvlxl(vector bool short __a, int __b, vector bool short *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector pixel a, int b, vector pixel *c)
+vec_stvlxl(vector pixel __a, int __b, vector pixel *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector int a, int b, int *c)
+vec_stvlxl(vector int __a, int __b, int *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector int a, int b, vector int *c)
+vec_stvlxl(vector int __a, int __b, vector int *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector unsigned int a, int b, unsigned int *c)
+vec_stvlxl(vector unsigned int __a, int __b, unsigned int *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector unsigned int a, int b, vector unsigned int *c)
+vec_stvlxl(vector unsigned int __a, int __b, vector unsigned int *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector bool int a, int b, vector bool int *c)
+vec_stvlxl(vector bool int __a, int __b, vector bool int *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvlxl(vector float a, int b, vector float *c)
+vec_stvlxl(vector float __a, int __b, vector float *__c)
{
- return vec_stl(vec_perm(vec_lvrx(b, c),
- a,
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(vec_lvrx(__b, __c),
+ __a,
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
/* vec_stvrx */
static void __ATTRS_o_ai
-vec_stvrx(vector signed char a, int b, signed char *c)
+vec_stvrx(vector signed char __a, int __b, signed char *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector signed char a, int b, vector signed char *c)
+vec_stvrx(vector signed char __a, int __b, vector signed char *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector unsigned char a, int b, unsigned char *c)
+vec_stvrx(vector unsigned char __a, int __b, unsigned char *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector unsigned char a, int b, vector unsigned char *c)
+vec_stvrx(vector unsigned char __a, int __b, vector unsigned char *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector bool char a, int b, vector bool char *c)
+vec_stvrx(vector bool char __a, int __b, vector bool char *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector short a, int b, short *c)
+vec_stvrx(vector short __a, int __b, short *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector short a, int b, vector short *c)
+vec_stvrx(vector short __a, int __b, vector short *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector unsigned short a, int b, unsigned short *c)
+vec_stvrx(vector unsigned short __a, int __b, unsigned short *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector unsigned short a, int b, vector unsigned short *c)
+vec_stvrx(vector unsigned short __a, int __b, vector unsigned short *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector bool short a, int b, vector bool short *c)
+vec_stvrx(vector bool short __a, int __b, vector bool short *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector pixel a, int b, vector pixel *c)
+vec_stvrx(vector pixel __a, int __b, vector pixel *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector int a, int b, int *c)
+vec_stvrx(vector int __a, int __b, int *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector int a, int b, vector int *c)
+vec_stvrx(vector int __a, int __b, vector int *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector unsigned int a, int b, unsigned int *c)
+vec_stvrx(vector unsigned int __a, int __b, unsigned int *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector unsigned int a, int b, vector unsigned int *c)
+vec_stvrx(vector unsigned int __a, int __b, vector unsigned int *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector bool int a, int b, vector bool int *c)
+vec_stvrx(vector bool int __a, int __b, vector bool int *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrx(vector float a, int b, vector float *c)
+vec_stvrx(vector float __a, int __b, vector float *__c)
{
- return vec_st(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_st(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
/* vec_stvrxl */
static void __ATTRS_o_ai
-vec_stvrxl(vector signed char a, int b, signed char *c)
+vec_stvrxl(vector signed char __a, int __b, signed char *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector signed char a, int b, vector signed char *c)
+vec_stvrxl(vector signed char __a, int __b, vector signed char *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector unsigned char a, int b, unsigned char *c)
+vec_stvrxl(vector unsigned char __a, int __b, unsigned char *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector unsigned char a, int b, vector unsigned char *c)
+vec_stvrxl(vector unsigned char __a, int __b, vector unsigned char *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector bool char a, int b, vector bool char *c)
+vec_stvrxl(vector bool char __a, int __b, vector bool char *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector short a, int b, short *c)
+vec_stvrxl(vector short __a, int __b, short *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector short a, int b, vector short *c)
+vec_stvrxl(vector short __a, int __b, vector short *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector unsigned short a, int b, unsigned short *c)
+vec_stvrxl(vector unsigned short __a, int __b, unsigned short *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector unsigned short a, int b, vector unsigned short *c)
+vec_stvrxl(vector unsigned short __a, int __b, vector unsigned short *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector bool short a, int b, vector bool short *c)
+vec_stvrxl(vector bool short __a, int __b, vector bool short *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector pixel a, int b, vector pixel *c)
+vec_stvrxl(vector pixel __a, int __b, vector pixel *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector int a, int b, int *c)
+vec_stvrxl(vector int __a, int __b, int *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector int a, int b, vector int *c)
+vec_stvrxl(vector int __a, int __b, vector int *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector unsigned int a, int b, unsigned int *c)
+vec_stvrxl(vector unsigned int __a, int __b, unsigned int *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, __c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector unsigned int a, int b, vector unsigned int *c)
+vec_stvrxl(vector unsigned int __a, int __b, vector unsigned int *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector bool int a, int b, vector bool int *c)
+vec_stvrxl(vector bool int __a, int __b, vector bool int *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
static void __ATTRS_o_ai
-vec_stvrxl(vector float a, int b, vector float *c)
+vec_stvrxl(vector float __a, int __b, vector float *__c)
{
- return vec_stl(vec_perm(a,
- vec_lvlx(b, c),
- vec_lvsr(b, (unsigned char *)c)),
- b, c);
+ return vec_stl(vec_perm(__a,
+ vec_lvlx(__b, __c),
+ vec_lvsr(__b, (unsigned char *)__c)),
+ __b, __c);
}
/* vec_promote */
static vector signed char __ATTRS_o_ai
-vec_promote(signed char a, int b)
+vec_promote(signed char __a, int __b)
{
- vector signed char res = (vector signed char)(0);
- res[b] = a;
- return res;
+ vector signed char __res = (vector signed char)(0);
+ __res[__b] = __a;
+ return __res;
}
static vector unsigned char __ATTRS_o_ai
-vec_promote(unsigned char a, int b)
+vec_promote(unsigned char __a, int __b)
{
- vector unsigned char res = (vector unsigned char)(0);
- res[b] = a;
- return res;
+ vector unsigned char __res = (vector unsigned char)(0);
+ __res[__b] = __a;
+ return __res;
}
static vector short __ATTRS_o_ai
-vec_promote(short a, int b)
+vec_promote(short __a, int __b)
{
- vector short res = (vector short)(0);
- res[b] = a;
- return res;
+ vector short __res = (vector short)(0);
+ __res[__b] = __a;
+ return __res;
}
static vector unsigned short __ATTRS_o_ai
-vec_promote(unsigned short a, int b)
+vec_promote(unsigned short __a, int __b)
{
- vector unsigned short res = (vector unsigned short)(0);
- res[b] = a;
- return res;
+ vector unsigned short __res = (vector unsigned short)(0);
+ __res[__b] = __a;
+ return __res;
}
static vector int __ATTRS_o_ai
-vec_promote(int a, int b)
+vec_promote(int __a, int __b)
{
- vector int res = (vector int)(0);
- res[b] = a;
- return res;
+ vector int __res = (vector int)(0);
+ __res[__b] = __a;
+ return __res;
}
static vector unsigned int __ATTRS_o_ai
-vec_promote(unsigned int a, int b)
+vec_promote(unsigned int __a, int __b)
{
- vector unsigned int res = (vector unsigned int)(0);
- res[b] = a;
- return res;
+ vector unsigned int __res = (vector unsigned int)(0);
+ __res[__b] = __a;
+ return __res;
}
static vector float __ATTRS_o_ai
-vec_promote(float a, int b)
+vec_promote(float __a, int __b)
{
- vector float res = (vector float)(0);
- res[b] = a;
- return res;
+ vector float __res = (vector float)(0);
+ __res[__b] = __a;
+ return __res;
}
/* vec_splats */
static vector signed char __ATTRS_o_ai
-vec_splats(signed char a)
+vec_splats(signed char __a)
{
- return (vector signed char)(a);
+ return (vector signed char)(__a);
}
static vector unsigned char __ATTRS_o_ai
-vec_splats(unsigned char a)
+vec_splats(unsigned char __a)
{
- return (vector unsigned char)(a);
+ return (vector unsigned char)(__a);
}
static vector short __ATTRS_o_ai
-vec_splats(short a)
+vec_splats(short __a)
{
- return (vector short)(a);
+ return (vector short)(__a);
}
static vector unsigned short __ATTRS_o_ai
-vec_splats(unsigned short a)
+vec_splats(unsigned short __a)
{
- return (vector unsigned short)(a);
+ return (vector unsigned short)(__a);
}
static vector int __ATTRS_o_ai
-vec_splats(int a)
+vec_splats(int __a)
{
- return (vector int)(a);
+ return (vector int)(__a);
}
static vector unsigned int __ATTRS_o_ai
-vec_splats(unsigned int a)
+vec_splats(unsigned int __a)
{
- return (vector unsigned int)(a);
+ return (vector unsigned int)(__a);
}
static vector float __ATTRS_o_ai
-vec_splats(float a)
+vec_splats(float __a)
{
- return (vector float)(a);
+ return (vector float)(__a);
}
/* ----------------------------- predicates --------------------------------- */
@@ -9940,1915 +9940,1915 @@ vec_splats(float a)
/* vec_all_eq */
static int __ATTRS_o_ai
-vec_all_eq(vector signed char a, vector signed char b)
+vec_all_eq(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)a, (vector char)b);
+ return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector signed char a, vector bool char b)
+vec_all_eq(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)a, (vector char)b);
+ return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector unsigned char a, vector unsigned char b)
+vec_all_eq(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)a, (vector char)b);
+ return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector unsigned char a, vector bool char b)
+vec_all_eq(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)a, (vector char)b);
+ return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector bool char a, vector signed char b)
+vec_all_eq(vector bool char __a, vector signed char __b)
{
- return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)a, (vector char)b);
+ return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector bool char a, vector unsigned char b)
+vec_all_eq(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)a, (vector char)b);
+ return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector bool char a, vector bool char b)
+vec_all_eq(vector bool char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)a, (vector char)b);
+ return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector short a, vector short b)
+vec_all_eq(vector short __a, vector short __b)
{
- return __builtin_altivec_vcmpequh_p(__CR6_LT, a, b);
+ return __builtin_altivec_vcmpequh_p(__CR6_LT, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector short a, vector bool short b)
+vec_all_eq(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpequh_p(__CR6_LT, a, (vector short)b);
+ return __builtin_altivec_vcmpequh_p(__CR6_LT, __a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector unsigned short a, vector unsigned short b)
+vec_all_eq(vector unsigned short __a, vector unsigned short __b)
{
return
- __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)a, (vector short)b);
+ __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)__a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector unsigned short a, vector bool short b)
+vec_all_eq(vector unsigned short __a, vector bool short __b)
{
return
- __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)a, (vector short)b);
+ __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)__a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector bool short a, vector short b)
+vec_all_eq(vector bool short __a, vector short __b)
{
return
- __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)a, (vector short)b);
+ __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)__a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector bool short a, vector unsigned short b)
+vec_all_eq(vector bool short __a, vector unsigned short __b)
{
return
- __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)a, (vector short)b);
+ __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)__a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector bool short a, vector bool short b)
+vec_all_eq(vector bool short __a, vector bool short __b)
{
return
- __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)a, (vector short)b);
+ __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)__a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector pixel a, vector pixel b)
+vec_all_eq(vector pixel __a, vector pixel __b)
{
return
- __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)a, (vector short)b);
+ __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)__a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector int a, vector int b)
+vec_all_eq(vector int __a, vector int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_LT, a, b);
+ return __builtin_altivec_vcmpequw_p(__CR6_LT, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector int a, vector bool int b)
+vec_all_eq(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_LT, a, (vector int)b);
+ return __builtin_altivec_vcmpequw_p(__CR6_LT, __a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector unsigned int a, vector unsigned int b)
+vec_all_eq(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)a, (vector int)b);
+ return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector unsigned int a, vector bool int b)
+vec_all_eq(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)a, (vector int)b);
+ return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector bool int a, vector int b)
+vec_all_eq(vector bool int __a, vector int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)a, (vector int)b);
+ return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector bool int a, vector unsigned int b)
+vec_all_eq(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)a, (vector int)b);
+ return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector bool int a, vector bool int b)
+vec_all_eq(vector bool int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)a, (vector int)b);
+ return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_all_eq(vector float a, vector float b)
+vec_all_eq(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpeqfp_p(__CR6_LT, a, b);
+ return __builtin_altivec_vcmpeqfp_p(__CR6_LT, __a, __b);
}
/* vec_all_ge */
static int __ATTRS_o_ai
-vec_all_ge(vector signed char a, vector signed char b)
+vec_all_ge(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_EQ, b, a);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_EQ, __b, __a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector signed char a, vector bool char b)
+vec_all_ge(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_EQ, (vector signed char)b, a);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_EQ, (vector signed char)__b, __a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector unsigned char a, vector unsigned char b)
+vec_all_ge(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_EQ, b, a);
+ return __builtin_altivec_vcmpgtub_p(__CR6_EQ, __b, __a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector unsigned char a, vector bool char b)
+vec_all_ge(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_EQ, (vector unsigned char)b, a);
+ return __builtin_altivec_vcmpgtub_p(__CR6_EQ, (vector unsigned char)__b, __a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector bool char a, vector signed char b)
+vec_all_ge(vector bool char __a, vector signed char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_EQ,
- (vector unsigned char)b,
- (vector unsigned char)a);
+ (vector unsigned char)__b,
+ (vector unsigned char)__a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector bool char a, vector unsigned char b)
+vec_all_ge(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_EQ, b, (vector unsigned char)a);
+ return __builtin_altivec_vcmpgtub_p(__CR6_EQ, __b, (vector unsigned char)__a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector bool char a, vector bool char b)
+vec_all_ge(vector bool char __a, vector bool char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_EQ,
- (vector unsigned char)b,
- (vector unsigned char)a);
+ (vector unsigned char)__b,
+ (vector unsigned char)__a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector short a, vector short b)
+vec_all_ge(vector short __a, vector short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_EQ, b, a);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_EQ, __b, __a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector short a, vector bool short b)
+vec_all_ge(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_EQ, (vector short)b, a);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_EQ, (vector short)__b, __a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector unsigned short a, vector unsigned short b)
+vec_all_ge(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, b, a);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, __b, __a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector unsigned short a, vector bool short b)
+vec_all_ge(vector unsigned short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, (vector unsigned short)b, a);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, (vector unsigned short)__b, __a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector bool short a, vector short b)
+vec_all_ge(vector bool short __a, vector short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_EQ,
- (vector unsigned short)b,
- (vector unsigned short)a);
+ (vector unsigned short)__b,
+ (vector unsigned short)__a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector bool short a, vector unsigned short b)
+vec_all_ge(vector bool short __a, vector unsigned short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, b, (vector unsigned short)a);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, __b, (vector unsigned short)__a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector bool short a, vector bool short b)
+vec_all_ge(vector bool short __a, vector bool short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_EQ,
- (vector unsigned short)b,
- (vector unsigned short)a);
+ (vector unsigned short)__b,
+ (vector unsigned short)__a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector int a, vector int b)
+vec_all_ge(vector int __a, vector int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_EQ, b, a);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_EQ, __b, __a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector int a, vector bool int b)
+vec_all_ge(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_EQ, (vector int)b, a);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_EQ, (vector int)__b, __a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector unsigned int a, vector unsigned int b)
+vec_all_ge(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, b, a);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, __b, __a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector unsigned int a, vector bool int b)
+vec_all_ge(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, (vector unsigned int)b, a);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, (vector unsigned int)__b, __a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector bool int a, vector int b)
+vec_all_ge(vector bool int __a, vector int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_EQ,
- (vector unsigned int)b,
- (vector unsigned int)a);
+ (vector unsigned int)__b,
+ (vector unsigned int)__a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector bool int a, vector unsigned int b)
+vec_all_ge(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, b, (vector unsigned int)a);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, __b, (vector unsigned int)__a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector bool int a, vector bool int b)
+vec_all_ge(vector bool int __a, vector bool int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_EQ,
- (vector unsigned int)b,
- (vector unsigned int)a);
+ (vector unsigned int)__b,
+ (vector unsigned int)__a);
}
static int __ATTRS_o_ai
-vec_all_ge(vector float a, vector float b)
+vec_all_ge(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgefp_p(__CR6_LT, a, b);
+ return __builtin_altivec_vcmpgefp_p(__CR6_LT, __a, __b);
}
/* vec_all_gt */
static int __ATTRS_o_ai
-vec_all_gt(vector signed char a, vector signed char b)
+vec_all_gt(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_LT, a, b);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_LT, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector signed char a, vector bool char b)
+vec_all_gt(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_LT, a, (vector signed char)b);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_LT, __a, (vector signed char)__b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector unsigned char a, vector unsigned char b)
+vec_all_gt(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_LT, a, b);
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector unsigned char a, vector bool char b)
+vec_all_gt(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_LT, a, (vector unsigned char)b);
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT, __a, (vector unsigned char)__b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector bool char a, vector signed char b)
+vec_all_gt(vector bool char __a, vector signed char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_LT,
- (vector unsigned char)a,
- (vector unsigned char)b);
+ (vector unsigned char)__a,
+ (vector unsigned char)__b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector bool char a, vector unsigned char b)
+vec_all_gt(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_LT, (vector unsigned char)a, b);
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT, (vector unsigned char)__a, __b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector bool char a, vector bool char b)
+vec_all_gt(vector bool char __a, vector bool char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_LT,
- (vector unsigned char)a,
- (vector unsigned char)b);
+ (vector unsigned char)__a,
+ (vector unsigned char)__b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector short a, vector short b)
+vec_all_gt(vector short __a, vector short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_LT, a, b);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_LT, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector short a, vector bool short b)
+vec_all_gt(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_LT, a, (vector short)b);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_LT, __a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector unsigned short a, vector unsigned short b)
+vec_all_gt(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_LT, a, b);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_LT, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector unsigned short a, vector bool short b)
+vec_all_gt(vector unsigned short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_LT, a, (vector unsigned short)b);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_LT, __a, (vector unsigned short)__b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector bool short a, vector short b)
+vec_all_gt(vector bool short __a, vector short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_LT,
- (vector unsigned short)a,
- (vector unsigned short)b);
+ (vector unsigned short)__a,
+ (vector unsigned short)__b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector bool short a, vector unsigned short b)
+vec_all_gt(vector bool short __a, vector unsigned short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_LT, (vector unsigned short)a, b);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_LT, (vector unsigned short)__a, __b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector bool short a, vector bool short b)
+vec_all_gt(vector bool short __a, vector bool short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_LT,
- (vector unsigned short)a,
- (vector unsigned short)b);
+ (vector unsigned short)__a,
+ (vector unsigned short)__b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector int a, vector int b)
+vec_all_gt(vector int __a, vector int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_LT, a, b);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_LT, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector int a, vector bool int b)
+vec_all_gt(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_LT, a, (vector int)b);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_LT, __a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector unsigned int a, vector unsigned int b)
+vec_all_gt(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_LT, a, b);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector unsigned int a, vector bool int b)
+vec_all_gt(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_LT, a, (vector unsigned int)b);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT, __a, (vector unsigned int)__b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector bool int a, vector int b)
+vec_all_gt(vector bool int __a, vector int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_LT,
- (vector unsigned int)a,
- (vector unsigned int)b);
+ (vector unsigned int)__a,
+ (vector unsigned int)__b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector bool int a, vector unsigned int b)
+vec_all_gt(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_LT, (vector unsigned int)a, b);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT, (vector unsigned int)__a, __b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector bool int a, vector bool int b)
+vec_all_gt(vector bool int __a, vector bool int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_LT,
- (vector unsigned int)a,
- (vector unsigned int)b);
+ (vector unsigned int)__a,
+ (vector unsigned int)__b);
}
static int __ATTRS_o_ai
-vec_all_gt(vector float a, vector float b)
+vec_all_gt(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgtfp_p(__CR6_LT, a, b);
+ return __builtin_altivec_vcmpgtfp_p(__CR6_LT, __a, __b);
}
/* vec_all_in */
static int __attribute__((__always_inline__))
-vec_all_in(vector float a, vector float b)
+vec_all_in(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpbfp_p(__CR6_EQ, a, b);
+ return __builtin_altivec_vcmpbfp_p(__CR6_EQ, __a, __b);
}
/* vec_all_le */
static int __ATTRS_o_ai
-vec_all_le(vector signed char a, vector signed char b)
+vec_all_le(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_EQ, a, b);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_EQ, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_le(vector signed char a, vector bool char b)
+vec_all_le(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_EQ, a, (vector signed char)b);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_EQ, __a, (vector signed char)__b);
}
static int __ATTRS_o_ai
-vec_all_le(vector unsigned char a, vector unsigned char b)
+vec_all_le(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_EQ, a, b);
+ return __builtin_altivec_vcmpgtub_p(__CR6_EQ, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_le(vector unsigned char a, vector bool char b)
+vec_all_le(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_EQ, a, (vector unsigned char)b);
+ return __builtin_altivec_vcmpgtub_p(__CR6_EQ, __a, (vector unsigned char)__b);
}
static int __ATTRS_o_ai
-vec_all_le(vector bool char a, vector signed char b)
+vec_all_le(vector bool char __a, vector signed char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_EQ,
- (vector unsigned char)a,
- (vector unsigned char)b);
+ (vector unsigned char)__a,
+ (vector unsigned char)__b);
}
static int __ATTRS_o_ai
-vec_all_le(vector bool char a, vector unsigned char b)
+vec_all_le(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_EQ, (vector unsigned char)a, b);
+ return __builtin_altivec_vcmpgtub_p(__CR6_EQ, (vector unsigned char)__a, __b);
}
static int __ATTRS_o_ai
-vec_all_le(vector bool char a, vector bool char b)
+vec_all_le(vector bool char __a, vector bool char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_EQ,
- (vector unsigned char)a,
- (vector unsigned char)b);
+ (vector unsigned char)__a,
+ (vector unsigned char)__b);
}
static int __ATTRS_o_ai
-vec_all_le(vector short a, vector short b)
+vec_all_le(vector short __a, vector short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_EQ, a, b);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_EQ, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_le(vector short a, vector bool short b)
+vec_all_le(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_EQ, a, (vector short)b);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_EQ, __a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_le(vector unsigned short a, vector unsigned short b)
+vec_all_le(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, a, b);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_le(vector unsigned short a, vector bool short b)
+vec_all_le(vector unsigned short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, a, (vector unsigned short)b);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, __a, (vector unsigned short)__b);
}
static int __ATTRS_o_ai
-vec_all_le(vector bool short a, vector short b)
+vec_all_le(vector bool short __a, vector short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_EQ,
- (vector unsigned short)a,
- (vector unsigned short)b);
+ (vector unsigned short)__a,
+ (vector unsigned short)__b);
}
static int __ATTRS_o_ai
-vec_all_le(vector bool short a, vector unsigned short b)
+vec_all_le(vector bool short __a, vector unsigned short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, (vector unsigned short)a, b);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, (vector unsigned short)__a, __b);
}
static int __ATTRS_o_ai
-vec_all_le(vector bool short a, vector bool short b)
+vec_all_le(vector bool short __a, vector bool short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_EQ,
- (vector unsigned short)a,
- (vector unsigned short)b);
+ (vector unsigned short)__a,
+ (vector unsigned short)__b);
}
static int __ATTRS_o_ai
-vec_all_le(vector int a, vector int b)
+vec_all_le(vector int __a, vector int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_EQ, a, b);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_EQ, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_le(vector int a, vector bool int b)
+vec_all_le(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_EQ, a, (vector int)b);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_EQ, __a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_all_le(vector unsigned int a, vector unsigned int b)
+vec_all_le(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, a, b);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_le(vector unsigned int a, vector bool int b)
+vec_all_le(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, a, (vector unsigned int)b);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, __a, (vector unsigned int)__b);
}
static int __ATTRS_o_ai
-vec_all_le(vector bool int a, vector int b)
+vec_all_le(vector bool int __a, vector int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_EQ,
- (vector unsigned int)a,
- (vector unsigned int)b);
+ (vector unsigned int)__a,
+ (vector unsigned int)__b);
}
static int __ATTRS_o_ai
-vec_all_le(vector bool int a, vector unsigned int b)
+vec_all_le(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, (vector unsigned int)a, b);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, (vector unsigned int)__a, __b);
}
static int __ATTRS_o_ai
-vec_all_le(vector bool int a, vector bool int b)
+vec_all_le(vector bool int __a, vector bool int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_EQ,
- (vector unsigned int)a,
- (vector unsigned int)b);
+ (vector unsigned int)__a,
+ (vector unsigned int)__b);
}
static int __ATTRS_o_ai
-vec_all_le(vector float a, vector float b)
+vec_all_le(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgefp_p(__CR6_LT, b, a);
+ return __builtin_altivec_vcmpgefp_p(__CR6_LT, __b, __a);
}
/* vec_all_lt */
static int __ATTRS_o_ai
-vec_all_lt(vector signed char a, vector signed char b)
+vec_all_lt(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_LT, b, a);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_LT, __b, __a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector signed char a, vector bool char b)
+vec_all_lt(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_LT, (vector signed char)b, a);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_LT, (vector signed char)__b, __a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector unsigned char a, vector unsigned char b)
+vec_all_lt(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_LT, b, a);
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT, __b, __a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector unsigned char a, vector bool char b)
+vec_all_lt(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_LT, (vector unsigned char)b, a);
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT, (vector unsigned char)__b, __a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector bool char a, vector signed char b)
+vec_all_lt(vector bool char __a, vector signed char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_LT,
- (vector unsigned char)b,
- (vector unsigned char)a);
+ (vector unsigned char)__b,
+ (vector unsigned char)__a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector bool char a, vector unsigned char b)
+vec_all_lt(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_LT, b, (vector unsigned char)a);
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT, __b, (vector unsigned char)__a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector bool char a, vector bool char b)
+vec_all_lt(vector bool char __a, vector bool char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_LT,
- (vector unsigned char)b,
- (vector unsigned char)a);
+ (vector unsigned char)__b,
+ (vector unsigned char)__a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector short a, vector short b)
+vec_all_lt(vector short __a, vector short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_LT, b, a);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_LT, __b, __a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector short a, vector bool short b)
+vec_all_lt(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_LT, (vector short)b, a);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_LT, (vector short)__b, __a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector unsigned short a, vector unsigned short b)
+vec_all_lt(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_LT, b, a);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_LT, __b, __a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector unsigned short a, vector bool short b)
+vec_all_lt(vector unsigned short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_LT, (vector unsigned short)b, a);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_LT, (vector unsigned short)__b, __a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector bool short a, vector short b)
+vec_all_lt(vector bool short __a, vector short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_LT,
- (vector unsigned short)b,
- (vector unsigned short)a);
+ (vector unsigned short)__b,
+ (vector unsigned short)__a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector bool short a, vector unsigned short b)
+vec_all_lt(vector bool short __a, vector unsigned short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_LT, b, (vector unsigned short)a);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_LT, __b, (vector unsigned short)__a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector bool short a, vector bool short b)
+vec_all_lt(vector bool short __a, vector bool short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_LT,
- (vector unsigned short)b,
- (vector unsigned short)a);
+ (vector unsigned short)__b,
+ (vector unsigned short)__a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector int a, vector int b)
+vec_all_lt(vector int __a, vector int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_LT, b, a);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_LT, __b, __a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector int a, vector bool int b)
+vec_all_lt(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_LT, (vector int)b, a);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_LT, (vector int)__b, __a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector unsigned int a, vector unsigned int b)
+vec_all_lt(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_LT, b, a);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT, __b, __a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector unsigned int a, vector bool int b)
+vec_all_lt(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_LT, (vector unsigned int)b, a);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT, (vector unsigned int)__b, __a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector bool int a, vector int b)
+vec_all_lt(vector bool int __a, vector int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_LT,
- (vector unsigned int)b,
- (vector unsigned int)a);
+ (vector unsigned int)__b,
+ (vector unsigned int)__a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector bool int a, vector unsigned int b)
+vec_all_lt(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_LT, b, (vector unsigned int)a);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT, __b, (vector unsigned int)__a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector bool int a, vector bool int b)
+vec_all_lt(vector bool int __a, vector bool int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_LT,
- (vector unsigned int)b,
- (vector unsigned int)a);
+ (vector unsigned int)__b,
+ (vector unsigned int)__a);
}
static int __ATTRS_o_ai
-vec_all_lt(vector float a, vector float b)
+vec_all_lt(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgtfp_p(__CR6_LT, b, a);
+ return __builtin_altivec_vcmpgtfp_p(__CR6_LT, __b, __a);
}
/* vec_all_nan */
static int __attribute__((__always_inline__))
-vec_all_nan(vector float a)
+vec_all_nan(vector float __a)
{
- return __builtin_altivec_vcmpeqfp_p(__CR6_EQ, a, a);
+ return __builtin_altivec_vcmpeqfp_p(__CR6_EQ, __a, __a);
}
/* vec_all_ne */
static int __ATTRS_o_ai
-vec_all_ne(vector signed char a, vector signed char b)
+vec_all_ne(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)a, (vector char)b);
+ return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector signed char a, vector bool char b)
+vec_all_ne(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)a, (vector char)b);
+ return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector unsigned char a, vector unsigned char b)
+vec_all_ne(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)a, (vector char)b);
+ return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector unsigned char a, vector bool char b)
+vec_all_ne(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)a, (vector char)b);
+ return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector bool char a, vector signed char b)
+vec_all_ne(vector bool char __a, vector signed char __b)
{
- return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)a, (vector char)b);
+ return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector bool char a, vector unsigned char b)
+vec_all_ne(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)a, (vector char)b);
+ return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector bool char a, vector bool char b)
+vec_all_ne(vector bool char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)a, (vector char)b);
+ return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector short a, vector short b)
+vec_all_ne(vector short __a, vector short __b)
{
- return __builtin_altivec_vcmpequh_p(__CR6_EQ, a, b);
+ return __builtin_altivec_vcmpequh_p(__CR6_EQ, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector short a, vector bool short b)
+vec_all_ne(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpequh_p(__CR6_EQ, a, (vector short)b);
+ return __builtin_altivec_vcmpequh_p(__CR6_EQ, __a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector unsigned short a, vector unsigned short b)
+vec_all_ne(vector unsigned short __a, vector unsigned short __b)
{
return
- __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)a, (vector short)b);
+ __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)__a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector unsigned short a, vector bool short b)
+vec_all_ne(vector unsigned short __a, vector bool short __b)
{
return
- __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)a, (vector short)b);
+ __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)__a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector bool short a, vector short b)
+vec_all_ne(vector bool short __a, vector short __b)
{
return
- __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)a, (vector short)b);
+ __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)__a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector bool short a, vector unsigned short b)
+vec_all_ne(vector bool short __a, vector unsigned short __b)
{
return
- __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)a, (vector short)b);
+ __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)__a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector bool short a, vector bool short b)
+vec_all_ne(vector bool short __a, vector bool short __b)
{
return
- __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)a, (vector short)b);
+ __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)__a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector pixel a, vector pixel b)
+vec_all_ne(vector pixel __a, vector pixel __b)
{
return
- __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)a, (vector short)b);
+ __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)__a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector int a, vector int b)
+vec_all_ne(vector int __a, vector int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_EQ, a, b);
+ return __builtin_altivec_vcmpequw_p(__CR6_EQ, __a, __b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector int a, vector bool int b)
+vec_all_ne(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_EQ, a, (vector int)b);
+ return __builtin_altivec_vcmpequw_p(__CR6_EQ, __a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector unsigned int a, vector unsigned int b)
+vec_all_ne(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)a, (vector int)b);
+ return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector unsigned int a, vector bool int b)
+vec_all_ne(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)a, (vector int)b);
+ return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector bool int a, vector int b)
+vec_all_ne(vector bool int __a, vector int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)a, (vector int)b);
+ return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector bool int a, vector unsigned int b)
+vec_all_ne(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)a, (vector int)b);
+ return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector bool int a, vector bool int b)
+vec_all_ne(vector bool int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)a, (vector int)b);
+ return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_all_ne(vector float a, vector float b)
+vec_all_ne(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpeqfp_p(__CR6_EQ, a, b);
+ return __builtin_altivec_vcmpeqfp_p(__CR6_EQ, __a, __b);
}
/* vec_all_nge */
static int __attribute__((__always_inline__))
-vec_all_nge(vector float a, vector float b)
+vec_all_nge(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgefp_p(__CR6_EQ, a, b);
+ return __builtin_altivec_vcmpgefp_p(__CR6_EQ, __a, __b);
}
/* vec_all_ngt */
static int __attribute__((__always_inline__))
-vec_all_ngt(vector float a, vector float b)
+vec_all_ngt(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgtfp_p(__CR6_EQ, a, b);
+ return __builtin_altivec_vcmpgtfp_p(__CR6_EQ, __a, __b);
}
/* vec_all_nle */
static int __attribute__((__always_inline__))
-vec_all_nle(vector float a, vector float b)
+vec_all_nle(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgefp_p(__CR6_EQ, b, a);
+ return __builtin_altivec_vcmpgefp_p(__CR6_EQ, __b, __a);
}
/* vec_all_nlt */
static int __attribute__((__always_inline__))
-vec_all_nlt(vector float a, vector float b)
+vec_all_nlt(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgtfp_p(__CR6_EQ, b, a);
+ return __builtin_altivec_vcmpgtfp_p(__CR6_EQ, __b, __a);
}
/* vec_all_numeric */
static int __attribute__((__always_inline__))
-vec_all_numeric(vector float a)
+vec_all_numeric(vector float __a)
{
- return __builtin_altivec_vcmpeqfp_p(__CR6_LT, a, a);
+ return __builtin_altivec_vcmpeqfp_p(__CR6_LT, __a, __a);
}
/* vec_any_eq */
static int __ATTRS_o_ai
-vec_any_eq(vector signed char a, vector signed char b)
+vec_any_eq(vector signed char __a, vector signed char __b)
{
return
- __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector signed char a, vector bool char b)
+vec_any_eq(vector signed char __a, vector bool char __b)
{
return
- __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector unsigned char a, vector unsigned char b)
+vec_any_eq(vector unsigned char __a, vector unsigned char __b)
{
return
- __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector unsigned char a, vector bool char b)
+vec_any_eq(vector unsigned char __a, vector bool char __b)
{
return
- __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector bool char a, vector signed char b)
+vec_any_eq(vector bool char __a, vector signed char __b)
{
return
- __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector bool char a, vector unsigned char b)
+vec_any_eq(vector bool char __a, vector unsigned char __b)
{
return
- __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector bool char a, vector bool char b)
+vec_any_eq(vector bool char __a, vector bool char __b)
{
return
- __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector short a, vector short b)
+vec_any_eq(vector short __a, vector short __b)
{
- return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV, a, b);
+ return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector short a, vector bool short b)
+vec_any_eq(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV, a, (vector short)b);
+ return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV, __a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector unsigned short a, vector unsigned short b)
+vec_any_eq(vector unsigned short __a, vector unsigned short __b)
{
return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV,
- (vector short)a,
- (vector short)b);
+ (vector short)__a,
+ (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector unsigned short a, vector bool short b)
+vec_any_eq(vector unsigned short __a, vector bool short __b)
{
return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV,
- (vector short)a,
- (vector short)b);
+ (vector short)__a,
+ (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector bool short a, vector short b)
+vec_any_eq(vector bool short __a, vector short __b)
{
return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV,
- (vector short)a,
- (vector short)b);
+ (vector short)__a,
+ (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector bool short a, vector unsigned short b)
+vec_any_eq(vector bool short __a, vector unsigned short __b)
{
return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV,
- (vector short)a,
- (vector short)b);
+ (vector short)__a,
+ (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector bool short a, vector bool short b)
+vec_any_eq(vector bool short __a, vector bool short __b)
{
return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV,
- (vector short)a,
- (vector short)b);
+ (vector short)__a,
+ (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector pixel a, vector pixel b)
+vec_any_eq(vector pixel __a, vector pixel __b)
{
return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV,
- (vector short)a,
- (vector short)b);
+ (vector short)__a,
+ (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector int a, vector int b)
+vec_any_eq(vector int __a, vector int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, a, b);
+ return __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector int a, vector bool int b)
+vec_any_eq(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, a, (vector int)b);
+ return __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, __a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector unsigned int a, vector unsigned int b)
+vec_any_eq(vector unsigned int __a, vector unsigned int __b)
{
return
- __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)a, (vector int)b);
+ __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector unsigned int a, vector bool int b)
+vec_any_eq(vector unsigned int __a, vector bool int __b)
{
return
- __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)a, (vector int)b);
+ __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector bool int a, vector int b)
+vec_any_eq(vector bool int __a, vector int __b)
{
return
- __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)a, (vector int)b);
+ __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector bool int a, vector unsigned int b)
+vec_any_eq(vector bool int __a, vector unsigned int __b)
{
return
- __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)a, (vector int)b);
+ __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector bool int a, vector bool int b)
+vec_any_eq(vector bool int __a, vector bool int __b)
{
return
- __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)a, (vector int)b);
+ __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_any_eq(vector float a, vector float b)
+vec_any_eq(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpeqfp_p(__CR6_EQ_REV, a, b);
+ return __builtin_altivec_vcmpeqfp_p(__CR6_EQ_REV, __a, __b);
}
/* vec_any_ge */
static int __ATTRS_o_ai
-vec_any_ge(vector signed char a, vector signed char b)
+vec_any_ge(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_LT_REV, b, a);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_LT_REV, __b, __a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector signed char a, vector bool char b)
+vec_any_ge(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_LT_REV, (vector signed char)b, a);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_LT_REV, (vector signed char)__b, __a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector unsigned char a, vector unsigned char b)
+vec_any_ge(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, b, a);
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, __b, __a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector unsigned char a, vector bool char b)
+vec_any_ge(vector unsigned char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, (vector unsigned char)b, a);
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, (vector unsigned char)__b, __a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector bool char a, vector signed char b)
+vec_any_ge(vector bool char __a, vector signed char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV,
- (vector unsigned char)b,
- (vector unsigned char)a);
+ (vector unsigned char)__b,
+ (vector unsigned char)__a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector bool char a, vector unsigned char b)
+vec_any_ge(vector bool char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, b, (vector unsigned char)a);
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, __b, (vector unsigned char)__a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector bool char a, vector bool char b)
+vec_any_ge(vector bool char __a, vector bool char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV,
- (vector unsigned char)b,
- (vector unsigned char)a);
+ (vector unsigned char)__b,
+ (vector unsigned char)__a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector short a, vector short b)
+vec_any_ge(vector short __a, vector short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_LT_REV, b, a);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_LT_REV, __b, __a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector short a, vector bool short b)
+vec_any_ge(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_LT_REV, (vector short)b, a);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_LT_REV, (vector short)__b, __a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector unsigned short a, vector unsigned short b)
+vec_any_ge(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, b, a);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, __b, __a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector unsigned short a, vector bool short b)
+vec_any_ge(vector unsigned short __a, vector bool short __b)
{
return
- __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, (vector unsigned short)b, a);
+ __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, (vector unsigned short)__b, __a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector bool short a, vector short b)
+vec_any_ge(vector bool short __a, vector short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV,
- (vector unsigned short)b,
- (vector unsigned short)a);
+ (vector unsigned short)__b,
+ (vector unsigned short)__a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector bool short a, vector unsigned short b)
+vec_any_ge(vector bool short __a, vector unsigned short __b)
{
return
- __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, b, (vector unsigned short)a);
+ __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, __b, (vector unsigned short)__a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector bool short a, vector bool short b)
+vec_any_ge(vector bool short __a, vector bool short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV,
- (vector unsigned short)b,
- (vector unsigned short)a);
+ (vector unsigned short)__b,
+ (vector unsigned short)__a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector int a, vector int b)
+vec_any_ge(vector int __a, vector int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_LT_REV, b, a);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_LT_REV, __b, __a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector int a, vector bool int b)
+vec_any_ge(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_LT_REV, (vector int)b, a);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_LT_REV, (vector int)__b, __a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector unsigned int a, vector unsigned int b)
+vec_any_ge(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, b, a);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, __b, __a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector unsigned int a, vector bool int b)
+vec_any_ge(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, (vector unsigned int)b, a);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, (vector unsigned int)__b, __a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector bool int a, vector int b)
+vec_any_ge(vector bool int __a, vector int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV,
- (vector unsigned int)b,
- (vector unsigned int)a);
+ (vector unsigned int)__b,
+ (vector unsigned int)__a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector bool int a, vector unsigned int b)
+vec_any_ge(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, b, (vector unsigned int)a);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, __b, (vector unsigned int)__a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector bool int a, vector bool int b)
+vec_any_ge(vector bool int __a, vector bool int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV,
- (vector unsigned int)b,
- (vector unsigned int)a);
+ (vector unsigned int)__b,
+ (vector unsigned int)__a);
}
static int __ATTRS_o_ai
-vec_any_ge(vector float a, vector float b)
+vec_any_ge(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgefp_p(__CR6_EQ_REV, a, b);
+ return __builtin_altivec_vcmpgefp_p(__CR6_EQ_REV, __a, __b);
}
/* vec_any_gt */
static int __ATTRS_o_ai
-vec_any_gt(vector signed char a, vector signed char b)
+vec_any_gt(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_EQ_REV, a, b);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_EQ_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector signed char a, vector bool char b)
+vec_any_gt(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_EQ_REV, a, (vector signed char)b);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_EQ_REV, __a, (vector signed char)__b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector unsigned char a, vector unsigned char b)
+vec_any_gt(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, a, b);
+ return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector unsigned char a, vector bool char b)
+vec_any_gt(vector unsigned char __a, vector bool char __b)
{
return
- __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, a, (vector unsigned char)b);
+ __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, __a, (vector unsigned char)__b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector bool char a, vector signed char b)
+vec_any_gt(vector bool char __a, vector signed char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV,
- (vector unsigned char)a,
- (vector unsigned char)b);
+ (vector unsigned char)__a,
+ (vector unsigned char)__b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector bool char a, vector unsigned char b)
+vec_any_gt(vector bool char __a, vector unsigned char __b)
{
return
- __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, (vector unsigned char)a, b);
+ __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, (vector unsigned char)__a, __b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector bool char a, vector bool char b)
+vec_any_gt(vector bool char __a, vector bool char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV,
- (vector unsigned char)a,
- (vector unsigned char)b);
+ (vector unsigned char)__a,
+ (vector unsigned char)__b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector short a, vector short b)
+vec_any_gt(vector short __a, vector short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_EQ_REV, a, b);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_EQ_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector short a, vector bool short b)
+vec_any_gt(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_EQ_REV, a, (vector short)b);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_EQ_REV, __a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector unsigned short a, vector unsigned short b)
+vec_any_gt(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, a, b);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector unsigned short a, vector bool short b)
+vec_any_gt(vector unsigned short __a, vector bool short __b)
{
return
- __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, a, (vector unsigned short)b);
+ __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, __a, (vector unsigned short)__b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector bool short a, vector short b)
+vec_any_gt(vector bool short __a, vector short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV,
- (vector unsigned short)a,
- (vector unsigned short)b);
+ (vector unsigned short)__a,
+ (vector unsigned short)__b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector bool short a, vector unsigned short b)
+vec_any_gt(vector bool short __a, vector unsigned short __b)
{
return
- __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, (vector unsigned short)a, b);
+ __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, (vector unsigned short)__a, __b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector bool short a, vector bool short b)
+vec_any_gt(vector bool short __a, vector bool short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV,
- (vector unsigned short)a,
- (vector unsigned short)b);
+ (vector unsigned short)__a,
+ (vector unsigned short)__b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector int a, vector int b)
+vec_any_gt(vector int __a, vector int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_EQ_REV, a, b);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_EQ_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector int a, vector bool int b)
+vec_any_gt(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_EQ_REV, a, (vector int)b);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_EQ_REV, __a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector unsigned int a, vector unsigned int b)
+vec_any_gt(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, a, b);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector unsigned int a, vector bool int b)
+vec_any_gt(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, a, (vector unsigned int)b);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, __a, (vector unsigned int)__b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector bool int a, vector int b)
+vec_any_gt(vector bool int __a, vector int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV,
- (vector unsigned int)a,
- (vector unsigned int)b);
+ (vector unsigned int)__a,
+ (vector unsigned int)__b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector bool int a, vector unsigned int b)
+vec_any_gt(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, (vector unsigned int)a, b);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, (vector unsigned int)__a, __b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector bool int a, vector bool int b)
+vec_any_gt(vector bool int __a, vector bool int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV,
- (vector unsigned int)a,
- (vector unsigned int)b);
+ (vector unsigned int)__a,
+ (vector unsigned int)__b);
}
static int __ATTRS_o_ai
-vec_any_gt(vector float a, vector float b)
+vec_any_gt(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgtfp_p(__CR6_EQ_REV, a, b);
+ return __builtin_altivec_vcmpgtfp_p(__CR6_EQ_REV, __a, __b);
}
/* vec_any_le */
static int __ATTRS_o_ai
-vec_any_le(vector signed char a, vector signed char b)
+vec_any_le(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_LT_REV, a, b);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_LT_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_le(vector signed char a, vector bool char b)
+vec_any_le(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_LT_REV, a, (vector signed char)b);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_LT_REV, __a, (vector signed char)__b);
}
static int __ATTRS_o_ai
-vec_any_le(vector unsigned char a, vector unsigned char b)
+vec_any_le(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, a, b);
+ return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_le(vector unsigned char a, vector bool char b)
+vec_any_le(vector unsigned char __a, vector bool char __b)
{
return
- __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, a, (vector unsigned char)b);
+ __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, __a, (vector unsigned char)__b);
}
static int __ATTRS_o_ai
-vec_any_le(vector bool char a, vector signed char b)
+vec_any_le(vector bool char __a, vector signed char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV,
- (vector unsigned char)a,
- (vector unsigned char)b);
+ (vector unsigned char)__a,
+ (vector unsigned char)__b);
}
static int __ATTRS_o_ai
-vec_any_le(vector bool char a, vector unsigned char b)
+vec_any_le(vector bool char __a, vector unsigned char __b)
{
return
- __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, (vector unsigned char)a, b);
+ __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, (vector unsigned char)__a, __b);
}
static int __ATTRS_o_ai
-vec_any_le(vector bool char a, vector bool char b)
+vec_any_le(vector bool char __a, vector bool char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV,
- (vector unsigned char)a,
- (vector unsigned char)b);
+ (vector unsigned char)__a,
+ (vector unsigned char)__b);
}
static int __ATTRS_o_ai
-vec_any_le(vector short a, vector short b)
+vec_any_le(vector short __a, vector short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_LT_REV, a, b);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_LT_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_le(vector short a, vector bool short b)
+vec_any_le(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_LT_REV, a, (vector short)b);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_LT_REV, __a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_le(vector unsigned short a, vector unsigned short b)
+vec_any_le(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, a, b);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_le(vector unsigned short a, vector bool short b)
+vec_any_le(vector unsigned short __a, vector bool short __b)
{
return
- __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, a, (vector unsigned short)b);
+ __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, __a, (vector unsigned short)__b);
}
static int __ATTRS_o_ai
-vec_any_le(vector bool short a, vector short b)
+vec_any_le(vector bool short __a, vector short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV,
- (vector unsigned short)a,
- (vector unsigned short)b);
+ (vector unsigned short)__a,
+ (vector unsigned short)__b);
}
static int __ATTRS_o_ai
-vec_any_le(vector bool short a, vector unsigned short b)
+vec_any_le(vector bool short __a, vector unsigned short __b)
{
return
- __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, (vector unsigned short)a, b);
+ __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, (vector unsigned short)__a, __b);
}
static int __ATTRS_o_ai
-vec_any_le(vector bool short a, vector bool short b)
+vec_any_le(vector bool short __a, vector bool short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV,
- (vector unsigned short)a,
- (vector unsigned short)b);
+ (vector unsigned short)__a,
+ (vector unsigned short)__b);
}
static int __ATTRS_o_ai
-vec_any_le(vector int a, vector int b)
+vec_any_le(vector int __a, vector int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_LT_REV, a, b);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_LT_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_le(vector int a, vector bool int b)
+vec_any_le(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_LT_REV, a, (vector int)b);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_LT_REV, __a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_any_le(vector unsigned int a, vector unsigned int b)
+vec_any_le(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, a, b);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_le(vector unsigned int a, vector bool int b)
+vec_any_le(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, a, (vector unsigned int)b);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, __a, (vector unsigned int)__b);
}
static int __ATTRS_o_ai
-vec_any_le(vector bool int a, vector int b)
+vec_any_le(vector bool int __a, vector int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV,
- (vector unsigned int)a,
- (vector unsigned int)b);
+ (vector unsigned int)__a,
+ (vector unsigned int)__b);
}
static int __ATTRS_o_ai
-vec_any_le(vector bool int a, vector unsigned int b)
+vec_any_le(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, (vector unsigned int)a, b);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, (vector unsigned int)__a, __b);
}
static int __ATTRS_o_ai
-vec_any_le(vector bool int a, vector bool int b)
+vec_any_le(vector bool int __a, vector bool int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV,
- (vector unsigned int)a,
- (vector unsigned int)b);
+ (vector unsigned int)__a,
+ (vector unsigned int)__b);
}
static int __ATTRS_o_ai
-vec_any_le(vector float a, vector float b)
+vec_any_le(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgefp_p(__CR6_EQ_REV, b, a);
+ return __builtin_altivec_vcmpgefp_p(__CR6_EQ_REV, __b, __a);
}
/* vec_any_lt */
static int __ATTRS_o_ai
-vec_any_lt(vector signed char a, vector signed char b)
+vec_any_lt(vector signed char __a, vector signed char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_EQ_REV, b, a);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_EQ_REV, __b, __a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector signed char a, vector bool char b)
+vec_any_lt(vector signed char __a, vector bool char __b)
{
- return __builtin_altivec_vcmpgtsb_p(__CR6_EQ_REV, (vector signed char)b, a);
+ return __builtin_altivec_vcmpgtsb_p(__CR6_EQ_REV, (vector signed char)__b, __a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector unsigned char a, vector unsigned char b)
+vec_any_lt(vector unsigned char __a, vector unsigned char __b)
{
- return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, b, a);
+ return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, __b, __a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector unsigned char a, vector bool char b)
+vec_any_lt(vector unsigned char __a, vector bool char __b)
{
return
- __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, (vector unsigned char)b, a);
+ __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, (vector unsigned char)__b, __a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector bool char a, vector signed char b)
+vec_any_lt(vector bool char __a, vector signed char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV,
- (vector unsigned char)b,
- (vector unsigned char)a);
+ (vector unsigned char)__b,
+ (vector unsigned char)__a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector bool char a, vector unsigned char b)
+vec_any_lt(vector bool char __a, vector unsigned char __b)
{
return
- __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, b, (vector unsigned char)a);
+ __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, __b, (vector unsigned char)__a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector bool char a, vector bool char b)
+vec_any_lt(vector bool char __a, vector bool char __b)
{
return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV,
- (vector unsigned char)b,
- (vector unsigned char)a);
+ (vector unsigned char)__b,
+ (vector unsigned char)__a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector short a, vector short b)
+vec_any_lt(vector short __a, vector short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_EQ_REV, b, a);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_EQ_REV, __b, __a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector short a, vector bool short b)
+vec_any_lt(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpgtsh_p(__CR6_EQ_REV, (vector short)b, a);
+ return __builtin_altivec_vcmpgtsh_p(__CR6_EQ_REV, (vector short)__b, __a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector unsigned short a, vector unsigned short b)
+vec_any_lt(vector unsigned short __a, vector unsigned short __b)
{
- return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, b, a);
+ return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, __b, __a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector unsigned short a, vector bool short b)
+vec_any_lt(vector unsigned short __a, vector bool short __b)
{
return
- __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, (vector unsigned short)b, a);
+ __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, (vector unsigned short)__b, __a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector bool short a, vector short b)
+vec_any_lt(vector bool short __a, vector short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV,
- (vector unsigned short)b,
- (vector unsigned short)a);
+ (vector unsigned short)__b,
+ (vector unsigned short)__a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector bool short a, vector unsigned short b)
+vec_any_lt(vector bool short __a, vector unsigned short __b)
{
return
- __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, b, (vector unsigned short)a);
+ __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, __b, (vector unsigned short)__a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector bool short a, vector bool short b)
+vec_any_lt(vector bool short __a, vector bool short __b)
{
return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV,
- (vector unsigned short)b,
- (vector unsigned short)a);
+ (vector unsigned short)__b,
+ (vector unsigned short)__a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector int a, vector int b)
+vec_any_lt(vector int __a, vector int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_EQ_REV, b, a);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_EQ_REV, __b, __a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector int a, vector bool int b)
+vec_any_lt(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtsw_p(__CR6_EQ_REV, (vector int)b, a);
+ return __builtin_altivec_vcmpgtsw_p(__CR6_EQ_REV, (vector int)__b, __a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector unsigned int a, vector unsigned int b)
+vec_any_lt(vector unsigned int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, b, a);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, __b, __a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector unsigned int a, vector bool int b)
+vec_any_lt(vector unsigned int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, (vector unsigned int)b, a);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, (vector unsigned int)__b, __a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector bool int a, vector int b)
+vec_any_lt(vector bool int __a, vector int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV,
- (vector unsigned int)b,
- (vector unsigned int)a);
+ (vector unsigned int)__b,
+ (vector unsigned int)__a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector bool int a, vector unsigned int b)
+vec_any_lt(vector bool int __a, vector unsigned int __b)
{
- return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, b, (vector unsigned int)a);
+ return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, __b, (vector unsigned int)__a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector bool int a, vector bool int b)
+vec_any_lt(vector bool int __a, vector bool int __b)
{
return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV,
- (vector unsigned int)b,
- (vector unsigned int)a);
+ (vector unsigned int)__b,
+ (vector unsigned int)__a);
}
static int __ATTRS_o_ai
-vec_any_lt(vector float a, vector float b)
+vec_any_lt(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgtfp_p(__CR6_EQ_REV, b, a);
+ return __builtin_altivec_vcmpgtfp_p(__CR6_EQ_REV, __b, __a);
}
/* vec_any_nan */
static int __attribute__((__always_inline__))
-vec_any_nan(vector float a)
+vec_any_nan(vector float __a)
{
- return __builtin_altivec_vcmpeqfp_p(__CR6_LT_REV, a, a);
+ return __builtin_altivec_vcmpeqfp_p(__CR6_LT_REV, __a, __a);
}
/* vec_any_ne */
static int __ATTRS_o_ai
-vec_any_ne(vector signed char a, vector signed char b)
+vec_any_ne(vector signed char __a, vector signed char __b)
{
return
- __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector signed char a, vector bool char b)
+vec_any_ne(vector signed char __a, vector bool char __b)
{
return
- __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector unsigned char a, vector unsigned char b)
+vec_any_ne(vector unsigned char __a, vector unsigned char __b)
{
return
- __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector unsigned char a, vector bool char b)
+vec_any_ne(vector unsigned char __a, vector bool char __b)
{
return
- __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector bool char a, vector signed char b)
+vec_any_ne(vector bool char __a, vector signed char __b)
{
return
- __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector bool char a, vector unsigned char b)
+vec_any_ne(vector bool char __a, vector unsigned char __b)
{
return
- __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector bool char a, vector bool char b)
+vec_any_ne(vector bool char __a, vector bool char __b)
{
return
- __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)a, (vector char)b);
+ __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)__a, (vector char)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector short a, vector short b)
+vec_any_ne(vector short __a, vector short __b)
{
- return __builtin_altivec_vcmpequh_p(__CR6_LT_REV, a, b);
+ return __builtin_altivec_vcmpequh_p(__CR6_LT_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector short a, vector bool short b)
+vec_any_ne(vector short __a, vector bool short __b)
{
- return __builtin_altivec_vcmpequh_p(__CR6_LT_REV, a, (vector short)b);
+ return __builtin_altivec_vcmpequh_p(__CR6_LT_REV, __a, (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector unsigned short a, vector unsigned short b)
+vec_any_ne(vector unsigned short __a, vector unsigned short __b)
{
return __builtin_altivec_vcmpequh_p(__CR6_LT_REV,
- (vector short)a,
- (vector short)b);
+ (vector short)__a,
+ (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector unsigned short a, vector bool short b)
+vec_any_ne(vector unsigned short __a, vector bool short __b)
{
return __builtin_altivec_vcmpequh_p(__CR6_LT_REV,
- (vector short)a,
- (vector short)b);
+ (vector short)__a,
+ (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector bool short a, vector short b)
+vec_any_ne(vector bool short __a, vector short __b)
{
return __builtin_altivec_vcmpequh_p(__CR6_LT_REV,
- (vector short)a,
- (vector short)b);
+ (vector short)__a,
+ (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector bool short a, vector unsigned short b)
+vec_any_ne(vector bool short __a, vector unsigned short __b)
{
return __builtin_altivec_vcmpequh_p(__CR6_LT_REV,
- (vector short)a,
- (vector short)b);
+ (vector short)__a,
+ (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector bool short a, vector bool short b)
+vec_any_ne(vector bool short __a, vector bool short __b)
{
return __builtin_altivec_vcmpequh_p(__CR6_LT_REV,
- (vector short)a,
- (vector short)b);
+ (vector short)__a,
+ (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector pixel a, vector pixel b)
+vec_any_ne(vector pixel __a, vector pixel __b)
{
return __builtin_altivec_vcmpequh_p(__CR6_LT_REV,
- (vector short)a,
- (vector short)b);
+ (vector short)__a,
+ (vector short)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector int a, vector int b)
+vec_any_ne(vector int __a, vector int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_LT_REV, a, b);
+ return __builtin_altivec_vcmpequw_p(__CR6_LT_REV, __a, __b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector int a, vector bool int b)
+vec_any_ne(vector int __a, vector bool int __b)
{
- return __builtin_altivec_vcmpequw_p(__CR6_LT_REV, a, (vector int)b);
+ return __builtin_altivec_vcmpequw_p(__CR6_LT_REV, __a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector unsigned int a, vector unsigned int b)
+vec_any_ne(vector unsigned int __a, vector unsigned int __b)
{
return
- __builtin_altivec_vcmpequw_p(__CR6_LT_REV, (vector int)a, (vector int)b);
+ __builtin_altivec_vcmpequw_p(__CR6_LT_REV, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector unsigned int a, vector bool int b)
+vec_any_ne(vector unsigned int __a, vector bool int __b)
{
return
- __builtin_altivec_vcmpequw_p(__CR6_LT_REV, (vector int)a, (vector int)b);
+ __builtin_altivec_vcmpequw_p(__CR6_LT_REV, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector bool int a, vector int b)
+vec_any_ne(vector bool int __a, vector int __b)
{
return
- __builtin_altivec_vcmpequw_p(__CR6_LT_REV, (vector int)a, (vector int)b);
+ __builtin_altivec_vcmpequw_p(__CR6_LT_REV, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector bool int a, vector unsigned int b)
+vec_any_ne(vector bool int __a, vector unsigned int __b)
{
return
- __builtin_altivec_vcmpequw_p(__CR6_LT_REV, (vector int)a, (vector int)b);
+ __builtin_altivec_vcmpequw_p(__CR6_LT_REV, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector bool int a, vector bool int b)
+vec_any_ne(vector bool int __a, vector bool int __b)
{
return
- __builtin_altivec_vcmpequw_p(__CR6_LT_REV, (vector int)a, (vector int)b);
+ __builtin_altivec_vcmpequw_p(__CR6_LT_REV, (vector int)__a, (vector int)__b);
}
static int __ATTRS_o_ai
-vec_any_ne(vector float a, vector float b)
+vec_any_ne(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpeqfp_p(__CR6_LT_REV, a, b);
+ return __builtin_altivec_vcmpeqfp_p(__CR6_LT_REV, __a, __b);
}
/* vec_any_nge */
static int __attribute__((__always_inline__))
-vec_any_nge(vector float a, vector float b)
+vec_any_nge(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgefp_p(__CR6_LT_REV, a, b);
+ return __builtin_altivec_vcmpgefp_p(__CR6_LT_REV, __a, __b);
}
/* vec_any_ngt */
static int __attribute__((__always_inline__))
-vec_any_ngt(vector float a, vector float b)
+vec_any_ngt(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgtfp_p(__CR6_LT_REV, a, b);
+ return __builtin_altivec_vcmpgtfp_p(__CR6_LT_REV, __a, __b);
}
/* vec_any_nle */
static int __attribute__((__always_inline__))
-vec_any_nle(vector float a, vector float b)
+vec_any_nle(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgefp_p(__CR6_LT_REV, b, a);
+ return __builtin_altivec_vcmpgefp_p(__CR6_LT_REV, __b, __a);
}
/* vec_any_nlt */
static int __attribute__((__always_inline__))
-vec_any_nlt(vector float a, vector float b)
+vec_any_nlt(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpgtfp_p(__CR6_LT_REV, b, a);
+ return __builtin_altivec_vcmpgtfp_p(__CR6_LT_REV, __b, __a);
}
/* vec_any_numeric */
static int __attribute__((__always_inline__))
-vec_any_numeric(vector float a)
+vec_any_numeric(vector float __a)
{
- return __builtin_altivec_vcmpeqfp_p(__CR6_EQ_REV, a, a);
+ return __builtin_altivec_vcmpeqfp_p(__CR6_EQ_REV, __a, __a);
}
/* vec_any_out */
static int __attribute__((__always_inline__))
-vec_any_out(vector float a, vector float b)
+vec_any_out(vector float __a, vector float __b)
{
- return __builtin_altivec_vcmpbfp_p(__CR6_EQ_REV, a, b);
+ return __builtin_altivec_vcmpbfp_p(__CR6_EQ_REV, __a, __b);
}
#undef __ATTRS_o_ai
diff --git a/lib/Headers/avx2intrin.h b/lib/Headers/avx2intrin.h
index 2c53aed..63b1efc 100644
--- a/lib/Headers/avx2intrin.h
+++ b/lib/Headers/avx2intrin.h
@@ -29,39 +29,39 @@
#define _mm256_mpsadbw_epu8(X, Y, M) __builtin_ia32_mpsadbw256((X), (Y), (M))
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_abs_epi8(__m256i a)
+_mm256_abs_epi8(__m256i __a)
{
- return (__m256i)__builtin_ia32_pabsb256((__v32qi)a);
+ return (__m256i)__builtin_ia32_pabsb256((__v32qi)__a);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_abs_epi16(__m256i a)
+_mm256_abs_epi16(__m256i __a)
{
- return (__m256i)__builtin_ia32_pabsw256((__v16hi)a);
+ return (__m256i)__builtin_ia32_pabsw256((__v16hi)__a);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_abs_epi32(__m256i a)
+_mm256_abs_epi32(__m256i __a)
{
- return (__m256i)__builtin_ia32_pabsd256((__v8si)a);
+ return (__m256i)__builtin_ia32_pabsd256((__v8si)__a);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_packs_epi16(__m256i a, __m256i b)
+_mm256_packs_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_packsswb256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_packsswb256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_packs_epi32(__m256i a, __m256i b)
+_mm256_packs_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_packssdw256((__v8si)a, (__v8si)b);
+ return (__m256i)__builtin_ia32_packssdw256((__v8si)__a, (__v8si)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_packus_epi16(__m256i a, __m256i b)
+_mm256_packus_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_packuswb256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_packuswb256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
@@ -71,51 +71,51 @@ _mm256_packus_epi32(__m256i __V1, __m256i __V2)
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_add_epi8(__m256i a, __m256i b)
+_mm256_add_epi8(__m256i __a, __m256i __b)
{
- return (__m256i)((__v32qi)a + (__v32qi)b);
+ return (__m256i)((__v32qi)__a + (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_add_epi16(__m256i a, __m256i b)
+_mm256_add_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)((__v16hi)a + (__v16hi)b);
+ return (__m256i)((__v16hi)__a + (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_add_epi32(__m256i a, __m256i b)
+_mm256_add_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)((__v8si)a + (__v8si)b);
+ return (__m256i)((__v8si)__a + (__v8si)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_add_epi64(__m256i a, __m256i b)
+_mm256_add_epi64(__m256i __a, __m256i __b)
{
- return a + b;
+ return __a + __b;
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_adds_epi8(__m256i a, __m256i b)
+_mm256_adds_epi8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_paddsb256((__v32qi)a, (__v32qi)b);
+ return (__m256i)__builtin_ia32_paddsb256((__v32qi)__a, (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_adds_epi16(__m256i a, __m256i b)
+_mm256_adds_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_paddsw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_paddsw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_adds_epu8(__m256i a, __m256i b)
+_mm256_adds_epu8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_paddusb256((__v32qi)a, (__v32qi)b);
+ return (__m256i)__builtin_ia32_paddusb256((__v32qi)__a, (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_adds_epu16(__m256i a, __m256i b)
+_mm256_adds_epu16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_paddusw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_paddusw256((__v16hi)__a, (__v16hi)__b);
}
#define _mm256_alignr_epi8(a, b, n) __extension__ ({ \
@@ -124,27 +124,27 @@ _mm256_adds_epu16(__m256i a, __m256i b)
(__m256i)__builtin_ia32_palignr256((__v32qi)__a, (__v32qi)__b, (n)); })
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_and_si256(__m256i a, __m256i b)
+_mm256_and_si256(__m256i __a, __m256i __b)
{
- return a & b;
+ return __a & __b;
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_andnot_si256(__m256i a, __m256i b)
+_mm256_andnot_si256(__m256i __a, __m256i __b)
{
- return ~a & b;
+ return ~__a & __b;
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_avg_epu8(__m256i a, __m256i b)
+_mm256_avg_epu8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pavgb256((__v32qi)a, (__v32qi)b);
+ return (__m256i)__builtin_ia32_pavgb256((__v32qi)__a, (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_avg_epu16(__m256i a, __m256i b)
+_mm256_avg_epu16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pavgw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_pavgw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
@@ -160,177 +160,177 @@ _mm256_blendv_epi8(__m256i __V1, __m256i __V2, __m256i __M)
(__m256i)__builtin_ia32_pblendw256((__v16hi)__V1, (__v16hi)__V2, (M)); })
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_cmpeq_epi8(__m256i a, __m256i b)
+_mm256_cmpeq_epi8(__m256i __a, __m256i __b)
{
- return (__m256i)((__v32qi)a == (__v32qi)b);
+ return (__m256i)((__v32qi)__a == (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_cmpeq_epi16(__m256i a, __m256i b)
+_mm256_cmpeq_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)((__v16hi)a == (__v16hi)b);
+ return (__m256i)((__v16hi)__a == (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_cmpeq_epi32(__m256i a, __m256i b)
+_mm256_cmpeq_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)((__v8si)a == (__v8si)b);
+ return (__m256i)((__v8si)__a == (__v8si)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_cmpeq_epi64(__m256i a, __m256i b)
+_mm256_cmpeq_epi64(__m256i __a, __m256i __b)
{
- return (__m256i)(a == b);
+ return (__m256i)(__a == __b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_cmpgt_epi8(__m256i a, __m256i b)
+_mm256_cmpgt_epi8(__m256i __a, __m256i __b)
{
- return (__m256i)((__v32qi)a > (__v32qi)b);
+ return (__m256i)((__v32qi)__a > (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_cmpgt_epi16(__m256i a, __m256i b)
+_mm256_cmpgt_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)((__v16hi)a > (__v16hi)b);
+ return (__m256i)((__v16hi)__a > (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_cmpgt_epi32(__m256i a, __m256i b)
+_mm256_cmpgt_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)((__v8si)a > (__v8si)b);
+ return (__m256i)((__v8si)__a > (__v8si)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_cmpgt_epi64(__m256i a, __m256i b)
+_mm256_cmpgt_epi64(__m256i __a, __m256i __b)
{
- return (__m256i)(a > b);
+ return (__m256i)(__a > __b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_hadd_epi16(__m256i a, __m256i b)
+_mm256_hadd_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_phaddw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_phaddw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_hadd_epi32(__m256i a, __m256i b)
+_mm256_hadd_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_phaddd256((__v8si)a, (__v8si)b);
+ return (__m256i)__builtin_ia32_phaddd256((__v8si)__a, (__v8si)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_hadds_epi16(__m256i a, __m256i b)
+_mm256_hadds_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_phaddsw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_phaddsw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_hsub_epi16(__m256i a, __m256i b)
+_mm256_hsub_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_phsubw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_phsubw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_hsub_epi32(__m256i a, __m256i b)
+_mm256_hsub_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_phsubd256((__v8si)a, (__v8si)b);
+ return (__m256i)__builtin_ia32_phsubd256((__v8si)__a, (__v8si)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_hsubs_epi16(__m256i a, __m256i b)
+_mm256_hsubs_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_phsubsw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_phsubsw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_maddubs_epi16(__m256i a, __m256i b)
+_mm256_maddubs_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmaddubsw256((__v32qi)a, (__v32qi)b);
+ return (__m256i)__builtin_ia32_pmaddubsw256((__v32qi)__a, (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_madd_epi16(__m256i a, __m256i b)
+_mm256_madd_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmaddwd256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_pmaddwd256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_max_epi8(__m256i a, __m256i b)
+_mm256_max_epi8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmaxsb256((__v32qi)a, (__v32qi)b);
+ return (__m256i)__builtin_ia32_pmaxsb256((__v32qi)__a, (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_max_epi16(__m256i a, __m256i b)
+_mm256_max_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmaxsw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_pmaxsw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_max_epi32(__m256i a, __m256i b)
+_mm256_max_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmaxsd256((__v8si)a, (__v8si)b);
+ return (__m256i)__builtin_ia32_pmaxsd256((__v8si)__a, (__v8si)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_max_epu8(__m256i a, __m256i b)
+_mm256_max_epu8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmaxub256((__v32qi)a, (__v32qi)b);
+ return (__m256i)__builtin_ia32_pmaxub256((__v32qi)__a, (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_max_epu16(__m256i a, __m256i b)
+_mm256_max_epu16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmaxuw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_pmaxuw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_max_epu32(__m256i a, __m256i b)
+_mm256_max_epu32(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmaxud256((__v8si)a, (__v8si)b);
+ return (__m256i)__builtin_ia32_pmaxud256((__v8si)__a, (__v8si)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_min_epi8(__m256i a, __m256i b)
+_mm256_min_epi8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pminsb256((__v32qi)a, (__v32qi)b);
+ return (__m256i)__builtin_ia32_pminsb256((__v32qi)__a, (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_min_epi16(__m256i a, __m256i b)
+_mm256_min_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pminsw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_pminsw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_min_epi32(__m256i a, __m256i b)
+_mm256_min_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pminsd256((__v8si)a, (__v8si)b);
+ return (__m256i)__builtin_ia32_pminsd256((__v8si)__a, (__v8si)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_min_epu8(__m256i a, __m256i b)
+_mm256_min_epu8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pminub256((__v32qi)a, (__v32qi)b);
+ return (__m256i)__builtin_ia32_pminub256((__v32qi)__a, (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_min_epu16(__m256i a, __m256i b)
+_mm256_min_epu16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pminuw256 ((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_pminuw256 ((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_min_epu32(__m256i a, __m256i b)
+_mm256_min_epu32(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pminud256((__v8si)a, (__v8si)b);
+ return (__m256i)__builtin_ia32_pminud256((__v8si)__a, (__v8si)__b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm256_movemask_epi8(__m256i a)
+_mm256_movemask_epi8(__m256i __a)
{
- return __builtin_ia32_pmovmskb256((__v32qi)a);
+ return __builtin_ia32_pmovmskb256((__v32qi)__a);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
@@ -406,63 +406,63 @@ _mm256_cvtepu32_epi64(__m128i __V)
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_mul_epi32(__m256i a, __m256i b)
+_mm256_mul_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmuldq256((__v8si)a, (__v8si)b);
+ return (__m256i)__builtin_ia32_pmuldq256((__v8si)__a, (__v8si)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_mulhrs_epi16(__m256i a, __m256i b)
+_mm256_mulhrs_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmulhrsw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_pmulhrsw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_mulhi_epu16(__m256i a, __m256i b)
+_mm256_mulhi_epu16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmulhuw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_pmulhuw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_mulhi_epi16(__m256i a, __m256i b)
+_mm256_mulhi_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pmulhw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_pmulhw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_mullo_epi16(__m256i a, __m256i b)
+_mm256_mullo_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)((__v16hi)a * (__v16hi)b);
+ return (__m256i)((__v16hi)__a * (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_mullo_epi32 (__m256i a, __m256i b)
+_mm256_mullo_epi32 (__m256i __a, __m256i __b)
{
- return (__m256i)((__v8si)a * (__v8si)b);
+ return (__m256i)((__v8si)__a * (__v8si)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_mul_epu32(__m256i a, __m256i b)
+_mm256_mul_epu32(__m256i __a, __m256i __b)
{
- return __builtin_ia32_pmuludq256((__v8si)a, (__v8si)b);
+ return __builtin_ia32_pmuludq256((__v8si)__a, (__v8si)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_or_si256(__m256i a, __m256i b)
+_mm256_or_si256(__m256i __a, __m256i __b)
{
- return a | b;
+ return __a | __b;
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_sad_epu8(__m256i a, __m256i b)
+_mm256_sad_epu8(__m256i __a, __m256i __b)
{
- return __builtin_ia32_psadbw256((__v32qi)a, (__v32qi)b);
+ return __builtin_ia32_psadbw256((__v32qi)__a, (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_shuffle_epi8(__m256i a, __m256i b)
+_mm256_shuffle_epi8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_pshufb256((__v32qi)a, (__v32qi)b);
+ return (__m256i)__builtin_ia32_pshufb256((__v32qi)__a, (__v32qi)__b);
}
#define _mm256_shuffle_epi32(a, imm) __extension__ ({ \
@@ -502,21 +502,21 @@ _mm256_shuffle_epi8(__m256i a, __m256i b)
12, 13, 14, 15); })
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_sign_epi8(__m256i a, __m256i b)
+_mm256_sign_epi8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_psignb256((__v32qi)a, (__v32qi)b);
+ return (__m256i)__builtin_ia32_psignb256((__v32qi)__a, (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_sign_epi16(__m256i a, __m256i b)
+_mm256_sign_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_psignw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_psignw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_sign_epi32(__m256i a, __m256i b)
+_mm256_sign_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_psignd256((__v8si)a, (__v8si)b);
+ return (__m256i)__builtin_ia32_psignd256((__v8si)__a, (__v8si)__b);
}
#define _mm256_slli_si256(a, count) __extension__ ({ \
@@ -524,63 +524,63 @@ _mm256_sign_epi32(__m256i a, __m256i b)
(__m256i)__builtin_ia32_pslldqi256(__a, (count)*8); })
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_slli_epi16(__m256i a, int count)
+_mm256_slli_epi16(__m256i __a, int __count)
{
- return (__m256i)__builtin_ia32_psllwi256((__v16hi)a, count);
+ return (__m256i)__builtin_ia32_psllwi256((__v16hi)__a, __count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_sll_epi16(__m256i a, __m128i count)
+_mm256_sll_epi16(__m256i __a, __m128i __count)
{
- return (__m256i)__builtin_ia32_psllw256((__v16hi)a, (__v8hi)count);
+ return (__m256i)__builtin_ia32_psllw256((__v16hi)__a, (__v8hi)__count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_slli_epi32(__m256i a, int count)
+_mm256_slli_epi32(__m256i __a, int __count)
{
- return (__m256i)__builtin_ia32_pslldi256((__v8si)a, count);
+ return (__m256i)__builtin_ia32_pslldi256((__v8si)__a, __count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_sll_epi32(__m256i a, __m128i count)
+_mm256_sll_epi32(__m256i __a, __m128i __count)
{
- return (__m256i)__builtin_ia32_pslld256((__v8si)a, (__v4si)count);
+ return (__m256i)__builtin_ia32_pslld256((__v8si)__a, (__v4si)__count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_slli_epi64(__m256i a, int count)
+_mm256_slli_epi64(__m256i __a, int __count)
{
- return __builtin_ia32_psllqi256(a, count);
+ return __builtin_ia32_psllqi256(__a, __count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_sll_epi64(__m256i a, __m128i count)
+_mm256_sll_epi64(__m256i __a, __m128i __count)
{
- return __builtin_ia32_psllq256(a, count);
+ return __builtin_ia32_psllq256(__a, __count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_srai_epi16(__m256i a, int count)
+_mm256_srai_epi16(__m256i __a, int __count)
{
- return (__m256i)__builtin_ia32_psrawi256((__v16hi)a, count);
+ return (__m256i)__builtin_ia32_psrawi256((__v16hi)__a, __count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_sra_epi16(__m256i a, __m128i count)
+_mm256_sra_epi16(__m256i __a, __m128i __count)
{
- return (__m256i)__builtin_ia32_psraw256((__v16hi)a, (__v8hi)count);
+ return (__m256i)__builtin_ia32_psraw256((__v16hi)__a, (__v8hi)__count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_srai_epi32(__m256i a, int count)
+_mm256_srai_epi32(__m256i __a, int __count)
{
- return (__m256i)__builtin_ia32_psradi256((__v8si)a, count);
+ return (__m256i)__builtin_ia32_psradi256((__v8si)__a, __count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_sra_epi32(__m256i a, __m128i count)
+_mm256_sra_epi32(__m256i __a, __m128i __count)
{
- return (__m256i)__builtin_ia32_psrad256((__v8si)a, (__v4si)count);
+ return (__m256i)__builtin_ia32_psrad256((__v8si)__a, (__v4si)__count);
}
#define _mm256_srli_si256(a, count) __extension__ ({ \
@@ -588,141 +588,141 @@ _mm256_sra_epi32(__m256i a, __m128i count)
(__m256i)__builtin_ia32_psrldqi256(__a, (count)*8); })
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_srli_epi16(__m256i a, int count)
+_mm256_srli_epi16(__m256i __a, int __count)
{
- return (__m256i)__builtin_ia32_psrlwi256((__v16hi)a, count);
+ return (__m256i)__builtin_ia32_psrlwi256((__v16hi)__a, __count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_srl_epi16(__m256i a, __m128i count)
+_mm256_srl_epi16(__m256i __a, __m128i __count)
{
- return (__m256i)__builtin_ia32_psrlw256((__v16hi)a, (__v8hi)count);
+ return (__m256i)__builtin_ia32_psrlw256((__v16hi)__a, (__v8hi)__count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_srli_epi32(__m256i a, int count)
+_mm256_srli_epi32(__m256i __a, int __count)
{
- return (__m256i)__builtin_ia32_psrldi256((__v8si)a, count);
+ return (__m256i)__builtin_ia32_psrldi256((__v8si)__a, __count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_srl_epi32(__m256i a, __m128i count)
+_mm256_srl_epi32(__m256i __a, __m128i __count)
{
- return (__m256i)__builtin_ia32_psrld256((__v8si)a, (__v4si)count);
+ return (__m256i)__builtin_ia32_psrld256((__v8si)__a, (__v4si)__count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_srli_epi64(__m256i a, int count)
+_mm256_srli_epi64(__m256i __a, int __count)
{
- return __builtin_ia32_psrlqi256(a, count);
+ return __builtin_ia32_psrlqi256(__a, __count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_srl_epi64(__m256i a, __m128i count)
+_mm256_srl_epi64(__m256i __a, __m128i __count)
{
- return __builtin_ia32_psrlq256(a, count);
+ return __builtin_ia32_psrlq256(__a, __count);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_sub_epi8(__m256i a, __m256i b)
+_mm256_sub_epi8(__m256i __a, __m256i __b)
{
- return (__m256i)((__v32qi)a - (__v32qi)b);
+ return (__m256i)((__v32qi)__a - (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_sub_epi16(__m256i a, __m256i b)
+_mm256_sub_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)((__v16hi)a - (__v16hi)b);
+ return (__m256i)((__v16hi)__a - (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_sub_epi32(__m256i a, __m256i b)
+_mm256_sub_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)((__v8si)a - (__v8si)b);
+ return (__m256i)((__v8si)__a - (__v8si)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_sub_epi64(__m256i a, __m256i b)
+_mm256_sub_epi64(__m256i __a, __m256i __b)
{
- return a - b;
+ return __a - __b;
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_subs_epi8(__m256i a, __m256i b)
+_mm256_subs_epi8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_psubsb256((__v32qi)a, (__v32qi)b);
+ return (__m256i)__builtin_ia32_psubsb256((__v32qi)__a, (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_subs_epi16(__m256i a, __m256i b)
+_mm256_subs_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_psubsw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_psubsw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_subs_epu8(__m256i a, __m256i b)
+_mm256_subs_epu8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_psubusb256((__v32qi)a, (__v32qi)b);
+ return (__m256i)__builtin_ia32_psubusb256((__v32qi)__a, (__v32qi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_subs_epu16(__m256i a, __m256i b)
+_mm256_subs_epu16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_psubusw256((__v16hi)a, (__v16hi)b);
+ return (__m256i)__builtin_ia32_psubusw256((__v16hi)__a, (__v16hi)__b);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_unpackhi_epi8(__m256i a, __m256i b)
+_mm256_unpackhi_epi8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_shufflevector((__v32qi)a, (__v32qi)b, 8, 32+8, 9, 32+9, 10, 32+10, 11, 32+11, 12, 32+12, 13, 32+13, 14, 32+14, 15, 32+15, 24, 32+24, 25, 32+25, 26, 32+26, 27, 32+27, 28, 32+28, 29, 32+29, 30, 32+30, 31, 32+31);
+ return (__m256i)__builtin_shufflevector((__v32qi)__a, (__v32qi)__b, 8, 32+8, 9, 32+9, 10, 32+10, 11, 32+11, 12, 32+12, 13, 32+13, 14, 32+14, 15, 32+15, 24, 32+24, 25, 32+25, 26, 32+26, 27, 32+27, 28, 32+28, 29, 32+29, 30, 32+30, 31, 32+31);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_unpackhi_epi16(__m256i a, __m256i b)
+_mm256_unpackhi_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_shufflevector((__v16hi)a, (__v16hi)b, 4, 16+4, 5, 16+5, 6, 16+6, 7, 16+7, 12, 16+12, 13, 16+13, 14, 16+14, 15, 16+15);
+ return (__m256i)__builtin_shufflevector((__v16hi)__a, (__v16hi)__b, 4, 16+4, 5, 16+5, 6, 16+6, 7, 16+7, 12, 16+12, 13, 16+13, 14, 16+14, 15, 16+15);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_unpackhi_epi32(__m256i a, __m256i b)
+_mm256_unpackhi_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_shufflevector((__v8si)a, (__v8si)b, 2, 8+2, 3, 8+3, 6, 8+6, 7, 8+7);
+ return (__m256i)__builtin_shufflevector((__v8si)__a, (__v8si)__b, 2, 8+2, 3, 8+3, 6, 8+6, 7, 8+7);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_unpackhi_epi64(__m256i a, __m256i b)
+_mm256_unpackhi_epi64(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_shufflevector(a, b, 1, 4+1, 3, 4+3);
+ return (__m256i)__builtin_shufflevector(__a, __b, 1, 4+1, 3, 4+3);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_unpacklo_epi8(__m256i a, __m256i b)
+_mm256_unpacklo_epi8(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_shufflevector((__v32qi)a, (__v32qi)b, 0, 32+0, 1, 32+1, 2, 32+2, 3, 32+3, 4, 32+4, 5, 32+5, 6, 32+6, 7, 32+7, 16, 32+16, 17, 32+17, 18, 32+18, 19, 32+19, 20, 32+20, 21, 32+21, 22, 32+22, 23, 32+23);
+ return (__m256i)__builtin_shufflevector((__v32qi)__a, (__v32qi)__b, 0, 32+0, 1, 32+1, 2, 32+2, 3, 32+3, 4, 32+4, 5, 32+5, 6, 32+6, 7, 32+7, 16, 32+16, 17, 32+17, 18, 32+18, 19, 32+19, 20, 32+20, 21, 32+21, 22, 32+22, 23, 32+23);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_unpacklo_epi16(__m256i a, __m256i b)
+_mm256_unpacklo_epi16(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_shufflevector((__v16hi)a, (__v16hi)b, 0, 16+0, 1, 16+1, 2, 16+2, 3, 16+3, 8, 16+8, 9, 16+9, 10, 16+10, 11, 16+11);
+ return (__m256i)__builtin_shufflevector((__v16hi)__a, (__v16hi)__b, 0, 16+0, 1, 16+1, 2, 16+2, 3, 16+3, 8, 16+8, 9, 16+9, 10, 16+10, 11, 16+11);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_unpacklo_epi32(__m256i a, __m256i b)
+_mm256_unpacklo_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_shufflevector((__v8si)a, (__v8si)b, 0, 8+0, 1, 8+1, 4, 8+4, 5, 8+5);
+ return (__m256i)__builtin_shufflevector((__v8si)__a, (__v8si)__b, 0, 8+0, 1, 8+1, 4, 8+4, 5, 8+5);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_unpacklo_epi64(__m256i a, __m256i b)
+_mm256_unpacklo_epi64(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_shufflevector(a, b, 0, 4+0, 2, 4+2);
+ return (__m256i)__builtin_shufflevector(__a, __b, 0, 4+0, 2, 4+2);
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_xor_si256(__m256i a, __m256i b)
+_mm256_xor_si256(__m256i __a, __m256i __b)
{
- return a ^ b;
+ return __a ^ __b;
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
@@ -750,9 +750,9 @@ _mm256_broadcastsd_pd(__m128d __X)
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm_broadcastsi128_si256(__m128i const *a)
+_mm_broadcastsi128_si256(__m128i const *__a)
{
- return (__m256i)__builtin_ia32_vbroadcastsi256(a);
+ return (__m256i)__builtin_ia32_vbroadcastsi256(__a);
}
#define _mm_blend_epi32(V1, V2, M) __extension__ ({ \
@@ -815,9 +815,9 @@ _mm_broadcastq_epi64(__m128i __X)
}
static __inline__ __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_permutevar8x32_epi32(__m256i a, __m256i b)
+_mm256_permutevar8x32_epi32(__m256i __a, __m256i __b)
{
- return (__m256i)__builtin_ia32_permvarsi256((__v8si)a, (__v8si)b);
+ return (__m256i)__builtin_ia32_permvarsi256((__v8si)__a, (__v8si)__b);
}
#define _mm256_permute4x64_pd(V, M) __extension__ ({ \
@@ -827,9 +827,9 @@ _mm256_permutevar8x32_epi32(__m256i a, __m256i b)
((M) & 0x30) >> 4, ((M) & 0xc0) >> 6); })
static __inline__ __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_permutevar8x32_ps(__m256 a, __m256 b)
+_mm256_permutevar8x32_ps(__m256 __a, __m256 __b)
{
- return (__m256)__builtin_ia32_permvarsf256((__v8sf)a, (__v8sf)b);
+ return (__m256)__builtin_ia32_permvarsf256((__v8sf)__a, (__v8sf)__b);
}
#define _mm256_permute4x64_epi64(V, M) __extension__ ({ \
diff --git a/lib/Headers/avxintrin.h b/lib/Headers/avxintrin.h
index ee7f835..412d284 100644
--- a/lib/Headers/avxintrin.h
+++ b/lib/Headers/avxintrin.h
@@ -38,111 +38,111 @@ typedef long long __m256i __attribute__((__vector_size__(32)));
/* Arithmetic */
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_add_pd(__m256d a, __m256d b)
+_mm256_add_pd(__m256d __a, __m256d __b)
{
- return a+b;
+ return __a+__b;
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_add_ps(__m256 a, __m256 b)
+_mm256_add_ps(__m256 __a, __m256 __b)
{
- return a+b;
+ return __a+__b;
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_sub_pd(__m256d a, __m256d b)
+_mm256_sub_pd(__m256d __a, __m256d __b)
{
- return a-b;
+ return __a-__b;
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_sub_ps(__m256 a, __m256 b)
+_mm256_sub_ps(__m256 __a, __m256 __b)
{
- return a-b;
+ return __a-__b;
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_addsub_pd(__m256d a, __m256d b)
+_mm256_addsub_pd(__m256d __a, __m256d __b)
{
- return (__m256d)__builtin_ia32_addsubpd256((__v4df)a, (__v4df)b);
+ return (__m256d)__builtin_ia32_addsubpd256((__v4df)__a, (__v4df)__b);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_addsub_ps(__m256 a, __m256 b)
+_mm256_addsub_ps(__m256 __a, __m256 __b)
{
- return (__m256)__builtin_ia32_addsubps256((__v8sf)a, (__v8sf)b);
+ return (__m256)__builtin_ia32_addsubps256((__v8sf)__a, (__v8sf)__b);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_div_pd(__m256d a, __m256d b)
+_mm256_div_pd(__m256d __a, __m256d __b)
{
- return a / b;
+ return __a / __b;
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_div_ps(__m256 a, __m256 b)
+_mm256_div_ps(__m256 __a, __m256 __b)
{
- return a / b;
+ return __a / __b;
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_max_pd(__m256d a, __m256d b)
+_mm256_max_pd(__m256d __a, __m256d __b)
{
- return (__m256d)__builtin_ia32_maxpd256((__v4df)a, (__v4df)b);
+ return (__m256d)__builtin_ia32_maxpd256((__v4df)__a, (__v4df)__b);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_max_ps(__m256 a, __m256 b)
+_mm256_max_ps(__m256 __a, __m256 __b)
{
- return (__m256)__builtin_ia32_maxps256((__v8sf)a, (__v8sf)b);
+ return (__m256)__builtin_ia32_maxps256((__v8sf)__a, (__v8sf)__b);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_min_pd(__m256d a, __m256d b)
+_mm256_min_pd(__m256d __a, __m256d __b)
{
- return (__m256d)__builtin_ia32_minpd256((__v4df)a, (__v4df)b);
+ return (__m256d)__builtin_ia32_minpd256((__v4df)__a, (__v4df)__b);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_min_ps(__m256 a, __m256 b)
+_mm256_min_ps(__m256 __a, __m256 __b)
{
- return (__m256)__builtin_ia32_minps256((__v8sf)a, (__v8sf)b);
+ return (__m256)__builtin_ia32_minps256((__v8sf)__a, (__v8sf)__b);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_mul_pd(__m256d a, __m256d b)
+_mm256_mul_pd(__m256d __a, __m256d __b)
{
- return a * b;
+ return __a * __b;
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_mul_ps(__m256 a, __m256 b)
+_mm256_mul_ps(__m256 __a, __m256 __b)
{
- return a * b;
+ return __a * __b;
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_sqrt_pd(__m256d a)
+_mm256_sqrt_pd(__m256d __a)
{
- return (__m256d)__builtin_ia32_sqrtpd256((__v4df)a);
+ return (__m256d)__builtin_ia32_sqrtpd256((__v4df)__a);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_sqrt_ps(__m256 a)
+_mm256_sqrt_ps(__m256 __a)
{
- return (__m256)__builtin_ia32_sqrtps256((__v8sf)a);
+ return (__m256)__builtin_ia32_sqrtps256((__v8sf)__a);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_rsqrt_ps(__m256 a)
+_mm256_rsqrt_ps(__m256 __a)
{
- return (__m256)__builtin_ia32_rsqrtps256((__v8sf)a);
+ return (__m256)__builtin_ia32_rsqrtps256((__v8sf)__a);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_rcp_ps(__m256 a)
+_mm256_rcp_ps(__m256 __a)
{
- return (__m256)__builtin_ia32_rcpps256((__v8sf)a);
+ return (__m256)__builtin_ia32_rcpps256((__v8sf)__a);
}
#define _mm256_round_pd(V, M) __extension__ ({ \
@@ -160,102 +160,102 @@ _mm256_rcp_ps(__m256 a)
/* Logical */
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_and_pd(__m256d a, __m256d b)
+_mm256_and_pd(__m256d __a, __m256d __b)
{
- return (__m256d)((__v4di)a & (__v4di)b);
+ return (__m256d)((__v4di)__a & (__v4di)__b);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_and_ps(__m256 a, __m256 b)
+_mm256_and_ps(__m256 __a, __m256 __b)
{
- return (__m256)((__v8si)a & (__v8si)b);
+ return (__m256)((__v8si)__a & (__v8si)__b);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_andnot_pd(__m256d a, __m256d b)
+_mm256_andnot_pd(__m256d __a, __m256d __b)
{
- return (__m256d)(~(__v4di)a & (__v4di)b);
+ return (__m256d)(~(__v4di)__a & (__v4di)__b);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_andnot_ps(__m256 a, __m256 b)
+_mm256_andnot_ps(__m256 __a, __m256 __b)
{
- return (__m256)(~(__v8si)a & (__v8si)b);
+ return (__m256)(~(__v8si)__a & (__v8si)__b);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_or_pd(__m256d a, __m256d b)
+_mm256_or_pd(__m256d __a, __m256d __b)
{
- return (__m256d)((__v4di)a | (__v4di)b);
+ return (__m256d)((__v4di)__a | (__v4di)__b);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_or_ps(__m256 a, __m256 b)
+_mm256_or_ps(__m256 __a, __m256 __b)
{
- return (__m256)((__v8si)a | (__v8si)b);
+ return (__m256)((__v8si)__a | (__v8si)__b);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_xor_pd(__m256d a, __m256d b)
+_mm256_xor_pd(__m256d __a, __m256d __b)
{
- return (__m256d)((__v4di)a ^ (__v4di)b);
+ return (__m256d)((__v4di)__a ^ (__v4di)__b);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_xor_ps(__m256 a, __m256 b)
+_mm256_xor_ps(__m256 __a, __m256 __b)
{
- return (__m256)((__v8si)a ^ (__v8si)b);
+ return (__m256)((__v8si)__a ^ (__v8si)__b);
}
/* Horizontal arithmetic */
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_hadd_pd(__m256d a, __m256d b)
+_mm256_hadd_pd(__m256d __a, __m256d __b)
{
- return (__m256d)__builtin_ia32_haddpd256((__v4df)a, (__v4df)b);
+ return (__m256d)__builtin_ia32_haddpd256((__v4df)__a, (__v4df)__b);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_hadd_ps(__m256 a, __m256 b)
+_mm256_hadd_ps(__m256 __a, __m256 __b)
{
- return (__m256)__builtin_ia32_haddps256((__v8sf)a, (__v8sf)b);
+ return (__m256)__builtin_ia32_haddps256((__v8sf)__a, (__v8sf)__b);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_hsub_pd(__m256d a, __m256d b)
+_mm256_hsub_pd(__m256d __a, __m256d __b)
{
- return (__m256d)__builtin_ia32_hsubpd256((__v4df)a, (__v4df)b);
+ return (__m256d)__builtin_ia32_hsubpd256((__v4df)__a, (__v4df)__b);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_hsub_ps(__m256 a, __m256 b)
+_mm256_hsub_ps(__m256 __a, __m256 __b)
{
- return (__m256)__builtin_ia32_hsubps256((__v8sf)a, (__v8sf)b);
+ return (__m256)__builtin_ia32_hsubps256((__v8sf)__a, (__v8sf)__b);
}
/* Vector permutations */
static __inline __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_permutevar_pd(__m128d a, __m128i c)
+_mm_permutevar_pd(__m128d __a, __m128i __c)
{
- return (__m128d)__builtin_ia32_vpermilvarpd((__v2df)a, (__v2di)c);
+ return (__m128d)__builtin_ia32_vpermilvarpd((__v2df)__a, (__v2di)__c);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_permutevar_pd(__m256d a, __m256i c)
+_mm256_permutevar_pd(__m256d __a, __m256i __c)
{
- return (__m256d)__builtin_ia32_vpermilvarpd256((__v4df)a, (__v4di)c);
+ return (__m256d)__builtin_ia32_vpermilvarpd256((__v4df)__a, (__v4di)__c);
}
static __inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_permutevar_ps(__m128 a, __m128i c)
+_mm_permutevar_ps(__m128 __a, __m128i __c)
{
- return (__m128)__builtin_ia32_vpermilvarps((__v4sf)a, (__v4si)c);
+ return (__m128)__builtin_ia32_vpermilvarps((__v4sf)__a, (__v4si)__c);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_permutevar_ps(__m256 a, __m256i c)
+_mm256_permutevar_ps(__m256 __a, __m256i __c)
{
- return (__m256)__builtin_ia32_vpermilvarps256((__v8sf)a,
- (__v8si)c);
+ return (__m256)__builtin_ia32_vpermilvarps256((__v8sf)__a,
+ (__v8si)__c);
}
#define _mm_permute_pd(A, C) __extension__ ({ \
@@ -313,15 +313,17 @@ _mm256_permutevar_ps(__m256 a, __m256i c)
(__m256)__builtin_ia32_blendps256((__v8sf)__V1, (__v8sf)__V2, (M)); })
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_blendv_pd(__m256d a, __m256d b, __m256d c)
+_mm256_blendv_pd(__m256d __a, __m256d __b, __m256d __c)
{
- return (__m256d)__builtin_ia32_blendvpd256((__v4df)a, (__v4df)b, (__v4df)c);
+ return (__m256d)__builtin_ia32_blendvpd256(
+ (__v4df)__a, (__v4df)__b, (__v4df)__c);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_blendv_ps(__m256 a, __m256 b, __m256 c)
+_mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c)
{
- return (__m256)__builtin_ia32_blendvps256((__v8sf)a, (__v8sf)b, (__v8sf)c);
+ return (__m256)__builtin_ia32_blendvps256(
+ (__v8sf)__a, (__v8sf)__b, (__v8sf)__c);
}
/* Vector Dot Product */
@@ -427,32 +429,32 @@ _mm256_blendv_ps(__m256 a, __m256 b, __m256 c)
(__m128i)__builtin_ia32_vextractf128_si256((__v8si)__A, (O)); })
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm256_extract_epi32(__m256i a, int const imm)
+_mm256_extract_epi32(__m256i __a, int const __imm)
{
- __v8si b = (__v8si)a;
- return b[imm];
+ __v8si __b = (__v8si)__a;
+ return __b[__imm];
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm256_extract_epi16(__m256i a, int const imm)
+_mm256_extract_epi16(__m256i __a, int const __imm)
{
- __v16hi b = (__v16hi)a;
- return b[imm];
+ __v16hi __b = (__v16hi)__a;
+ return __b[__imm];
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm256_extract_epi8(__m256i a, int const imm)
+_mm256_extract_epi8(__m256i __a, int const __imm)
{
- __v32qi b = (__v32qi)a;
- return b[imm];
+ __v32qi __b = (__v32qi)__a;
+ return __b[__imm];
}
#ifdef __x86_64__
static __inline long long __attribute__((__always_inline__, __nodebug__))
-_mm256_extract_epi64(__m256i a, const int imm)
+_mm256_extract_epi64(__m256i __a, const int __imm)
{
- __v4di b = (__v4di)a;
- return b[imm];
+ __v4di __b = (__v4di)__a;
+ return __b[__imm];
}
#endif
@@ -473,237 +475,237 @@ _mm256_extract_epi64(__m256i a, const int imm)
(__m256i)__builtin_ia32_vinsertf128_si256((__v8si)__V1, (__v4si)__V2, (O)); })
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_insert_epi32(__m256i a, int b, int const imm)
+_mm256_insert_epi32(__m256i __a, int __b, int const __imm)
{
- __v8si c = (__v8si)a;
- c[imm & 7] = b;
- return (__m256i)c;
+ __v8si __c = (__v8si)__a;
+ __c[__imm & 7] = __b;
+ return (__m256i)__c;
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_insert_epi16(__m256i a, int b, int const imm)
+_mm256_insert_epi16(__m256i __a, int __b, int const __imm)
{
- __v16hi c = (__v16hi)a;
- c[imm & 15] = b;
- return (__m256i)c;
+ __v16hi __c = (__v16hi)__a;
+ __c[__imm & 15] = __b;
+ return (__m256i)__c;
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_insert_epi8(__m256i a, int b, int const imm)
+_mm256_insert_epi8(__m256i __a, int __b, int const __imm)
{
- __v32qi c = (__v32qi)a;
- c[imm & 31] = b;
- return (__m256i)c;
+ __v32qi __c = (__v32qi)__a;
+ __c[__imm & 31] = __b;
+ return (__m256i)__c;
}
#ifdef __x86_64__
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_insert_epi64(__m256i a, int b, int const imm)
+_mm256_insert_epi64(__m256i __a, int __b, int const __imm)
{
- __v4di c = (__v4di)a;
- c[imm & 3] = b;
- return (__m256i)c;
+ __v4di __c = (__v4di)__a;
+ __c[__imm & 3] = __b;
+ return (__m256i)__c;
}
#endif
/* Conversion */
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_cvtepi32_pd(__m128i a)
+_mm256_cvtepi32_pd(__m128i __a)
{
- return (__m256d)__builtin_ia32_cvtdq2pd256((__v4si) a);
+ return (__m256d)__builtin_ia32_cvtdq2pd256((__v4si) __a);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_cvtepi32_ps(__m256i a)
+_mm256_cvtepi32_ps(__m256i __a)
{
- return (__m256)__builtin_ia32_cvtdq2ps256((__v8si) a);
+ return (__m256)__builtin_ia32_cvtdq2ps256((__v8si) __a);
}
static __inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm256_cvtpd_ps(__m256d a)
+_mm256_cvtpd_ps(__m256d __a)
{
- return (__m128)__builtin_ia32_cvtpd2ps256((__v4df) a);
+ return (__m128)__builtin_ia32_cvtpd2ps256((__v4df) __a);
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_cvtps_epi32(__m256 a)
+_mm256_cvtps_epi32(__m256 __a)
{
- return (__m256i)__builtin_ia32_cvtps2dq256((__v8sf) a);
+ return (__m256i)__builtin_ia32_cvtps2dq256((__v8sf) __a);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_cvtps_pd(__m128 a)
+_mm256_cvtps_pd(__m128 __a)
{
- return (__m256d)__builtin_ia32_cvtps2pd256((__v4sf) a);
+ return (__m256d)__builtin_ia32_cvtps2pd256((__v4sf) __a);
}
static __inline __m128i __attribute__((__always_inline__, __nodebug__))
-_mm256_cvttpd_epi32(__m256d a)
+_mm256_cvttpd_epi32(__m256d __a)
{
- return (__m128i)__builtin_ia32_cvttpd2dq256((__v4df) a);
+ return (__m128i)__builtin_ia32_cvttpd2dq256((__v4df) __a);
}
static __inline __m128i __attribute__((__always_inline__, __nodebug__))
-_mm256_cvtpd_epi32(__m256d a)
+_mm256_cvtpd_epi32(__m256d __a)
{
- return (__m128i)__builtin_ia32_cvtpd2dq256((__v4df) a);
+ return (__m128i)__builtin_ia32_cvtpd2dq256((__v4df) __a);
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_cvttps_epi32(__m256 a)
+_mm256_cvttps_epi32(__m256 __a)
{
- return (__m256i)__builtin_ia32_cvttps2dq256((__v8sf) a);
+ return (__m256i)__builtin_ia32_cvttps2dq256((__v8sf) __a);
}
/* Vector replicate */
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_movehdup_ps(__m256 a)
+_mm256_movehdup_ps(__m256 __a)
{
- return __builtin_shufflevector(a, a, 1, 1, 3, 3, 5, 5, 7, 7);
+ return __builtin_shufflevector(__a, __a, 1, 1, 3, 3, 5, 5, 7, 7);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_moveldup_ps(__m256 a)
+_mm256_moveldup_ps(__m256 __a)
{
- return __builtin_shufflevector(a, a, 0, 0, 2, 2, 4, 4, 6, 6);
+ return __builtin_shufflevector(__a, __a, 0, 0, 2, 2, 4, 4, 6, 6);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_movedup_pd(__m256d a)
+_mm256_movedup_pd(__m256d __a)
{
- return __builtin_shufflevector(a, a, 0, 0, 2, 2);
+ return __builtin_shufflevector(__a, __a, 0, 0, 2, 2);
}
/* Unpack and Interleave */
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_unpackhi_pd(__m256d a, __m256d b)
+_mm256_unpackhi_pd(__m256d __a, __m256d __b)
{
- return __builtin_shufflevector(a, b, 1, 5, 1+2, 5+2);
+ return __builtin_shufflevector(__a, __b, 1, 5, 1+2, 5+2);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_unpacklo_pd(__m256d a, __m256d b)
+_mm256_unpacklo_pd(__m256d __a, __m256d __b)
{
- return __builtin_shufflevector(a, b, 0, 4, 0+2, 4+2);
+ return __builtin_shufflevector(__a, __b, 0, 4, 0+2, 4+2);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_unpackhi_ps(__m256 a, __m256 b)
+_mm256_unpackhi_ps(__m256 __a, __m256 __b)
{
- return __builtin_shufflevector(a, b, 2, 10, 2+1, 10+1, 6, 14, 6+1, 14+1);
+ return __builtin_shufflevector(__a, __b, 2, 10, 2+1, 10+1, 6, 14, 6+1, 14+1);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_unpacklo_ps(__m256 a, __m256 b)
+_mm256_unpacklo_ps(__m256 __a, __m256 __b)
{
- return __builtin_shufflevector(a, b, 0, 8, 0+1, 8+1, 4, 12, 4+1, 12+1);
+ return __builtin_shufflevector(__a, __b, 0, 8, 0+1, 8+1, 4, 12, 4+1, 12+1);
}
/* Bit Test */
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm_testz_pd(__m128d a, __m128d b)
+_mm_testz_pd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_vtestzpd((__v2df)a, (__v2df)b);
+ return __builtin_ia32_vtestzpd((__v2df)__a, (__v2df)__b);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm_testc_pd(__m128d a, __m128d b)
+_mm_testc_pd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_vtestcpd((__v2df)a, (__v2df)b);
+ return __builtin_ia32_vtestcpd((__v2df)__a, (__v2df)__b);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm_testnzc_pd(__m128d a, __m128d b)
+_mm_testnzc_pd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_vtestnzcpd((__v2df)a, (__v2df)b);
+ return __builtin_ia32_vtestnzcpd((__v2df)__a, (__v2df)__b);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm_testz_ps(__m128 a, __m128 b)
+_mm_testz_ps(__m128 __a, __m128 __b)
{
- return __builtin_ia32_vtestzps((__v4sf)a, (__v4sf)b);
+ return __builtin_ia32_vtestzps((__v4sf)__a, (__v4sf)__b);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm_testc_ps(__m128 a, __m128 b)
+_mm_testc_ps(__m128 __a, __m128 __b)
{
- return __builtin_ia32_vtestcps((__v4sf)a, (__v4sf)b);
+ return __builtin_ia32_vtestcps((__v4sf)__a, (__v4sf)__b);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm_testnzc_ps(__m128 a, __m128 b)
+_mm_testnzc_ps(__m128 __a, __m128 __b)
{
- return __builtin_ia32_vtestnzcps((__v4sf)a, (__v4sf)b);
+ return __builtin_ia32_vtestnzcps((__v4sf)__a, (__v4sf)__b);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm256_testz_pd(__m256d a, __m256d b)
+_mm256_testz_pd(__m256d __a, __m256d __b)
{
- return __builtin_ia32_vtestzpd256((__v4df)a, (__v4df)b);
+ return __builtin_ia32_vtestzpd256((__v4df)__a, (__v4df)__b);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm256_testc_pd(__m256d a, __m256d b)
+_mm256_testc_pd(__m256d __a, __m256d __b)
{
- return __builtin_ia32_vtestcpd256((__v4df)a, (__v4df)b);
+ return __builtin_ia32_vtestcpd256((__v4df)__a, (__v4df)__b);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm256_testnzc_pd(__m256d a, __m256d b)
+_mm256_testnzc_pd(__m256d __a, __m256d __b)
{
- return __builtin_ia32_vtestnzcpd256((__v4df)a, (__v4df)b);
+ return __builtin_ia32_vtestnzcpd256((__v4df)__a, (__v4df)__b);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm256_testz_ps(__m256 a, __m256 b)
+_mm256_testz_ps(__m256 __a, __m256 __b)
{
- return __builtin_ia32_vtestzps256((__v8sf)a, (__v8sf)b);
+ return __builtin_ia32_vtestzps256((__v8sf)__a, (__v8sf)__b);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm256_testc_ps(__m256 a, __m256 b)
+_mm256_testc_ps(__m256 __a, __m256 __b)
{
- return __builtin_ia32_vtestcps256((__v8sf)a, (__v8sf)b);
+ return __builtin_ia32_vtestcps256((__v8sf)__a, (__v8sf)__b);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm256_testnzc_ps(__m256 a, __m256 b)
+_mm256_testnzc_ps(__m256 __a, __m256 __b)
{
- return __builtin_ia32_vtestnzcps256((__v8sf)a, (__v8sf)b);
+ return __builtin_ia32_vtestnzcps256((__v8sf)__a, (__v8sf)__b);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm256_testz_si256(__m256i a, __m256i b)
+_mm256_testz_si256(__m256i __a, __m256i __b)
{
- return __builtin_ia32_ptestz256((__v4di)a, (__v4di)b);
+ return __builtin_ia32_ptestz256((__v4di)__a, (__v4di)__b);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm256_testc_si256(__m256i a, __m256i b)
+_mm256_testc_si256(__m256i __a, __m256i __b)
{
- return __builtin_ia32_ptestc256((__v4di)a, (__v4di)b);
+ return __builtin_ia32_ptestc256((__v4di)__a, (__v4di)__b);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm256_testnzc_si256(__m256i a, __m256i b)
+_mm256_testnzc_si256(__m256i __a, __m256i __b)
{
- return __builtin_ia32_ptestnzc256((__v4di)a, (__v4di)b);
+ return __builtin_ia32_ptestnzc256((__v4di)__a, (__v4di)__b);
}
/* Vector extract sign mask */
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm256_movemask_pd(__m256d a)
+_mm256_movemask_pd(__m256d __a)
{
- return __builtin_ia32_movmskpd256((__v4df)a);
+ return __builtin_ia32_movmskpd256((__v4df)__a);
}
static __inline int __attribute__((__always_inline__, __nodebug__))
-_mm256_movemask_ps(__m256 a)
+_mm256_movemask_ps(__m256 __a)
{
- return __builtin_ia32_movmskps256((__v8sf)a);
+ return __builtin_ia32_movmskps256((__v8sf)__a);
}
-/* Vector zero */
+/* Vector __zero */
static __inline void __attribute__((__always_inline__, __nodebug__))
_mm256_zeroall(void)
{
@@ -718,341 +720,344 @@ _mm256_zeroupper(void)
/* Vector load with broadcast */
static __inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_broadcast_ss(float const *a)
+_mm_broadcast_ss(float const *__a)
{
- return (__m128)__builtin_ia32_vbroadcastss(a);
+ return (__m128)__builtin_ia32_vbroadcastss(__a);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_broadcast_sd(double const *a)
+_mm256_broadcast_sd(double const *__a)
{
- return (__m256d)__builtin_ia32_vbroadcastsd256(a);
+ return (__m256d)__builtin_ia32_vbroadcastsd256(__a);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_broadcast_ss(float const *a)
+_mm256_broadcast_ss(float const *__a)
{
- return (__m256)__builtin_ia32_vbroadcastss256(a);
+ return (__m256)__builtin_ia32_vbroadcastss256(__a);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_broadcast_pd(__m128d const *a)
+_mm256_broadcast_pd(__m128d const *__a)
{
- return (__m256d)__builtin_ia32_vbroadcastf128_pd256(a);
+ return (__m256d)__builtin_ia32_vbroadcastf128_pd256(__a);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_broadcast_ps(__m128 const *a)
+_mm256_broadcast_ps(__m128 const *__a)
{
- return (__m256)__builtin_ia32_vbroadcastf128_ps256(a);
+ return (__m256)__builtin_ia32_vbroadcastf128_ps256(__a);
}
/* SIMD load ops */
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_load_pd(double const *p)
+_mm256_load_pd(double const *__p)
{
- return *(__m256d *)p;
+ return *(__m256d *)__p;
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_load_ps(float const *p)
+_mm256_load_ps(float const *__p)
{
- return *(__m256 *)p;
+ return *(__m256 *)__p;
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_loadu_pd(double const *p)
+_mm256_loadu_pd(double const *__p)
{
struct __loadu_pd {
- __m256d v;
+ __m256d __v;
} __attribute__((packed, may_alias));
- return ((struct __loadu_pd*)p)->v;
+ return ((struct __loadu_pd*)__p)->__v;
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_loadu_ps(float const *p)
+_mm256_loadu_ps(float const *__p)
{
struct __loadu_ps {
- __m256 v;
+ __m256 __v;
} __attribute__((packed, may_alias));
- return ((struct __loadu_ps*)p)->v;
+ return ((struct __loadu_ps*)__p)->__v;
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_load_si256(__m256i const *p)
+_mm256_load_si256(__m256i const *__p)
{
- return *p;
+ return *__p;
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_loadu_si256(__m256i const *p)
+_mm256_loadu_si256(__m256i const *__p)
{
struct __loadu_si256 {
- __m256i v;
+ __m256i __v;
} __attribute__((packed, may_alias));
- return ((struct __loadu_si256*)p)->v;
+ return ((struct __loadu_si256*)__p)->__v;
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_lddqu_si256(__m256i const *p)
+_mm256_lddqu_si256(__m256i const *__p)
{
- return (__m256i)__builtin_ia32_lddqu256((char const *)p);
+ return (__m256i)__builtin_ia32_lddqu256((char const *)__p);
}
/* SIMD store ops */
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm256_store_pd(double *p, __m256d a)
+_mm256_store_pd(double *__p, __m256d __a)
{
- *(__m256d *)p = a;
+ *(__m256d *)__p = __a;
}
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm256_store_ps(float *p, __m256 a)
+_mm256_store_ps(float *__p, __m256 __a)
{
- *(__m256 *)p = a;
+ *(__m256 *)__p = __a;
}
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm256_storeu_pd(double *p, __m256d a)
+_mm256_storeu_pd(double *__p, __m256d __a)
{
- __builtin_ia32_storeupd256(p, (__v4df)a);
+ __builtin_ia32_storeupd256(__p, (__v4df)__a);
}
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm256_storeu_ps(float *p, __m256 a)
+_mm256_storeu_ps(float *__p, __m256 __a)
{
- __builtin_ia32_storeups256(p, (__v8sf)a);
+ __builtin_ia32_storeups256(__p, (__v8sf)__a);
}
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm256_store_si256(__m256i *p, __m256i a)
+_mm256_store_si256(__m256i *__p, __m256i __a)
{
- *p = a;
+ *__p = __a;
}
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm256_storeu_si256(__m256i *p, __m256i a)
+_mm256_storeu_si256(__m256i *__p, __m256i __a)
{
- __builtin_ia32_storedqu256((char *)p, (__v32qi)a);
+ __builtin_ia32_storedqu256((char *)__p, (__v32qi)__a);
}
/* Conditional load ops */
static __inline __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_maskload_pd(double const *p, __m128d m)
+_mm_maskload_pd(double const *__p, __m128d __m)
{
- return (__m128d)__builtin_ia32_maskloadpd((const __v2df *)p, (__v2df)m);
+ return (__m128d)__builtin_ia32_maskloadpd((const __v2df *)__p, (__v2df)__m);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_maskload_pd(double const *p, __m256d m)
+_mm256_maskload_pd(double const *__p, __m256d __m)
{
- return (__m256d)__builtin_ia32_maskloadpd256((const __v4df *)p, (__v4df)m);
+ return (__m256d)__builtin_ia32_maskloadpd256((const __v4df *)__p,
+ (__v4df)__m);
}
static __inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_maskload_ps(float const *p, __m128 m)
+_mm_maskload_ps(float const *__p, __m128 __m)
{
- return (__m128)__builtin_ia32_maskloadps((const __v4sf *)p, (__v4sf)m);
+ return (__m128)__builtin_ia32_maskloadps((const __v4sf *)__p, (__v4sf)__m);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_maskload_ps(float const *p, __m256 m)
+_mm256_maskload_ps(float const *__p, __m256 __m)
{
- return (__m256)__builtin_ia32_maskloadps256((const __v8sf *)p, (__v8sf)m);
+ return (__m256)__builtin_ia32_maskloadps256((const __v8sf *)__p, (__v8sf)__m);
}
/* Conditional store ops */
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm256_maskstore_ps(float *p, __m256 m, __m256 a)
+_mm256_maskstore_ps(float *__p, __m256 __m, __m256 __a)
{
- __builtin_ia32_maskstoreps256((__v8sf *)p, (__v8sf)m, (__v8sf)a);
+ __builtin_ia32_maskstoreps256((__v8sf *)__p, (__v8sf)__m, (__v8sf)__a);
}
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm_maskstore_pd(double *p, __m128d m, __m128d a)
+_mm_maskstore_pd(double *__p, __m128d __m, __m128d __a)
{
- __builtin_ia32_maskstorepd((__v2df *)p, (__v2df)m, (__v2df)a);
+ __builtin_ia32_maskstorepd((__v2df *)__p, (__v2df)__m, (__v2df)__a);
}
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm256_maskstore_pd(double *p, __m256d m, __m256d a)
+_mm256_maskstore_pd(double *__p, __m256d __m, __m256d __a)
{
- __builtin_ia32_maskstorepd256((__v4df *)p, (__v4df)m, (__v4df)a);
+ __builtin_ia32_maskstorepd256((__v4df *)__p, (__v4df)__m, (__v4df)__a);
}
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm_maskstore_ps(float *p, __m128 m, __m128 a)
+_mm_maskstore_ps(float *__p, __m128 __m, __m128 __a)
{
- __builtin_ia32_maskstoreps((__v4sf *)p, (__v4sf)m, (__v4sf)a);
+ __builtin_ia32_maskstoreps((__v4sf *)__p, (__v4sf)__m, (__v4sf)__a);
}
/* Cacheability support ops */
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm256_stream_si256(__m256i *a, __m256i b)
+_mm256_stream_si256(__m256i *__a, __m256i __b)
{
- __builtin_ia32_movntdq256((__v4di *)a, (__v4di)b);
+ __builtin_ia32_movntdq256((__v4di *)__a, (__v4di)__b);
}
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm256_stream_pd(double *a, __m256d b)
+_mm256_stream_pd(double *__a, __m256d __b)
{
- __builtin_ia32_movntpd256(a, (__v4df)b);
+ __builtin_ia32_movntpd256(__a, (__v4df)__b);
}
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm256_stream_ps(float *p, __m256 a)
+_mm256_stream_ps(float *__p, __m256 __a)
{
- __builtin_ia32_movntps256(p, (__v8sf)a);
+ __builtin_ia32_movntps256(__p, (__v8sf)__a);
}
/* Create vectors */
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_set_pd(double a, double b, double c, double d)
+_mm256_set_pd(double __a, double __b, double __c, double __d)
{
- return (__m256d){ d, c, b, a };
+ return (__m256d){ __d, __c, __b, __a };
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_set_ps(float a, float b, float c, float d,
- float e, float f, float g, float h)
+_mm256_set_ps(float __a, float __b, float __c, float __d,
+ float __e, float __f, float __g, float __h)
{
- return (__m256){ h, g, f, e, d, c, b, a };
+ return (__m256){ __h, __g, __f, __e, __d, __c, __b, __a };
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_set_epi32(int i0, int i1, int i2, int i3,
- int i4, int i5, int i6, int i7)
+_mm256_set_epi32(int __i0, int __i1, int __i2, int __i3,
+ int __i4, int __i5, int __i6, int __i7)
{
- return (__m256i)(__v8si){ i7, i6, i5, i4, i3, i2, i1, i0 };
+ return (__m256i)(__v8si){ __i7, __i6, __i5, __i4, __i3, __i2, __i1, __i0 };
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_set_epi16(short w15, short w14, short w13, short w12,
- short w11, short w10, short w09, short w08,
- short w07, short w06, short w05, short w04,
- short w03, short w02, short w01, short w00)
+_mm256_set_epi16(short __w15, short __w14, short __w13, short __w12,
+ short __w11, short __w10, short __w09, short __w08,
+ short __w07, short __w06, short __w05, short __w04,
+ short __w03, short __w02, short __w01, short __w00)
{
- return (__m256i)(__v16hi){ w00, w01, w02, w03, w04, w05, w06, w07,
- w08, w09, w10, w11, w12, w13, w14, w15 };
+ return (__m256i)(__v16hi){ __w00, __w01, __w02, __w03, __w04, __w05, __w06,
+ __w07, __w08, __w09, __w10, __w11, __w12, __w13, __w14, __w15 };
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_set_epi8(char b31, char b30, char b29, char b28,
- char b27, char b26, char b25, char b24,
- char b23, char b22, char b21, char b20,
- char b19, char b18, char b17, char b16,
- char b15, char b14, char b13, char b12,
- char b11, char b10, char b09, char b08,
- char b07, char b06, char b05, char b04,
- char b03, char b02, char b01, char b00)
+_mm256_set_epi8(char __b31, char __b30, char __b29, char __b28,
+ char __b27, char __b26, char __b25, char __b24,
+ char __b23, char __b22, char __b21, char __b20,
+ char __b19, char __b18, char __b17, char __b16,
+ char __b15, char __b14, char __b13, char __b12,
+ char __b11, char __b10, char __b09, char __b08,
+ char __b07, char __b06, char __b05, char __b04,
+ char __b03, char __b02, char __b01, char __b00)
{
return (__m256i)(__v32qi){
- b00, b01, b02, b03, b04, b05, b06, b07,
- b08, b09, b10, b11, b12, b13, b14, b15,
- b16, b17, b18, b19, b20, b21, b22, b23,
- b24, b25, b26, b27, b28, b29, b30, b31
+ __b00, __b01, __b02, __b03, __b04, __b05, __b06, __b07,
+ __b08, __b09, __b10, __b11, __b12, __b13, __b14, __b15,
+ __b16, __b17, __b18, __b19, __b20, __b21, __b22, __b23,
+ __b24, __b25, __b26, __b27, __b28, __b29, __b30, __b31
};
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_set_epi64x(long long a, long long b, long long c, long long d)
+_mm256_set_epi64x(long long __a, long long __b, long long __c, long long __d)
{
- return (__m256i)(__v4di){ d, c, b, a };
+ return (__m256i)(__v4di){ __d, __c, __b, __a };
}
/* Create vectors with elements in reverse order */
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_setr_pd(double a, double b, double c, double d)
+_mm256_setr_pd(double __a, double __b, double __c, double __d)
{
- return (__m256d){ a, b, c, d };
+ return (__m256d){ __a, __b, __c, __d };
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_setr_ps(float a, float b, float c, float d,
- float e, float f, float g, float h)
+_mm256_setr_ps(float __a, float __b, float __c, float __d,
+ float __e, float __f, float __g, float __h)
{
- return (__m256){ a, b, c, d, e, f, g, h };
+ return (__m256){ __a, __b, __c, __d, __e, __f, __g, __h };
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_setr_epi32(int i0, int i1, int i2, int i3,
- int i4, int i5, int i6, int i7)
+_mm256_setr_epi32(int __i0, int __i1, int __i2, int __i3,
+ int __i4, int __i5, int __i6, int __i7)
{
- return (__m256i)(__v8si){ i0, i1, i2, i3, i4, i5, i6, i7 };
+ return (__m256i)(__v8si){ __i0, __i1, __i2, __i3, __i4, __i5, __i6, __i7 };
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_setr_epi16(short w15, short w14, short w13, short w12,
- short w11, short w10, short w09, short w08,
- short w07, short w06, short w05, short w04,
- short w03, short w02, short w01, short w00)
+_mm256_setr_epi16(short __w15, short __w14, short __w13, short __w12,
+ short __w11, short __w10, short __w09, short __w08,
+ short __w07, short __w06, short __w05, short __w04,
+ short __w03, short __w02, short __w01, short __w00)
{
- return (__m256i)(__v16hi){ w15, w14, w13, w12, w11, w10, w09, w08,
- w07, w06, w05, w04, w03, w02, w01, w00 };
+ return (__m256i)(__v16hi){ __w15, __w14, __w13, __w12, __w11, __w10, __w09,
+ __w08, __w07, __w06, __w05, __w04, __w03, __w02, __w01, __w00 };
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_setr_epi8(char b31, char b30, char b29, char b28,
- char b27, char b26, char b25, char b24,
- char b23, char b22, char b21, char b20,
- char b19, char b18, char b17, char b16,
- char b15, char b14, char b13, char b12,
- char b11, char b10, char b09, char b08,
- char b07, char b06, char b05, char b04,
- char b03, char b02, char b01, char b00)
+_mm256_setr_epi8(char __b31, char __b30, char __b29, char __b28,
+ char __b27, char __b26, char __b25, char __b24,
+ char __b23, char __b22, char __b21, char __b20,
+ char __b19, char __b18, char __b17, char __b16,
+ char __b15, char __b14, char __b13, char __b12,
+ char __b11, char __b10, char __b09, char __b08,
+ char __b07, char __b06, char __b05, char __b04,
+ char __b03, char __b02, char __b01, char __b00)
{
return (__m256i)(__v32qi){
- b31, b30, b29, b28, b27, b26, b25, b24,
- b23, b22, b21, b20, b19, b18, b17, b16,
- b15, b14, b13, b12, b11, b10, b09, b08,
- b07, b06, b05, b04, b03, b02, b01, b00 };
+ __b31, __b30, __b29, __b28, __b27, __b26, __b25, __b24,
+ __b23, __b22, __b21, __b20, __b19, __b18, __b17, __b16,
+ __b15, __b14, __b13, __b12, __b11, __b10, __b09, __b08,
+ __b07, __b06, __b05, __b04, __b03, __b02, __b01, __b00 };
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_setr_epi64x(long long a, long long b, long long c, long long d)
+_mm256_setr_epi64x(long long __a, long long __b, long long __c, long long __d)
{
- return (__m256i)(__v4di){ a, b, c, d };
+ return (__m256i)(__v4di){ __a, __b, __c, __d };
}
/* Create vectors with repeated elements */
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_set1_pd(double w)
+_mm256_set1_pd(double __w)
{
- return (__m256d){ w, w, w, w };
+ return (__m256d){ __w, __w, __w, __w };
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_set1_ps(float w)
+_mm256_set1_ps(float __w)
{
- return (__m256){ w, w, w, w, w, w, w, w };
+ return (__m256){ __w, __w, __w, __w, __w, __w, __w, __w };
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_set1_epi32(int i)
+_mm256_set1_epi32(int __i)
{
- return (__m256i)(__v8si){ i, i, i, i, i, i, i, i };
+ return (__m256i)(__v8si){ __i, __i, __i, __i, __i, __i, __i, __i };
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_set1_epi16(short w)
+_mm256_set1_epi16(short __w)
{
- return (__m256i)(__v16hi){ w, w, w, w, w, w, w, w, w, w, w, w, w, w, w, w };
+ return (__m256i)(__v16hi){ __w, __w, __w, __w, __w, __w, __w, __w, __w, __w,
+ __w, __w, __w, __w, __w, __w };
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_set1_epi8(char b)
+_mm256_set1_epi8(char __b)
{
- return (__m256i)(__v32qi){ b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b,
- b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b };
+ return (__m256i)(__v32qi){ __b, __b, __b, __b, __b, __b, __b, __b, __b, __b,
+ __b, __b, __b, __b, __b, __b, __b, __b, __b, __b, __b, __b, __b, __b, __b,
+ __b, __b, __b, __b, __b, __b, __b };
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_set1_epi64x(long long q)
+_mm256_set1_epi64x(long long __q)
{
- return (__m256i)(__v4di){ q, q, q, q };
+ return (__m256i)(__v4di){ __q, __q, __q, __q };
}
-/* Create zeroed vectors */
+/* Create __zeroed vectors */
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
_mm256_setzero_pd(void)
{
@@ -1073,143 +1078,145 @@ _mm256_setzero_si256(void)
/* Cast between vector types */
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_castpd_ps(__m256d in)
+_mm256_castpd_ps(__m256d __in)
{
- return (__m256)in;
+ return (__m256)__in;
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_castpd_si256(__m256d in)
+_mm256_castpd_si256(__m256d __in)
{
- return (__m256i)in;
+ return (__m256i)__in;
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_castps_pd(__m256 in)
+_mm256_castps_pd(__m256 __in)
{
- return (__m256d)in;
+ return (__m256d)__in;
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_castps_si256(__m256 in)
+_mm256_castps_si256(__m256 __in)
{
- return (__m256i)in;
+ return (__m256i)__in;
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_castsi256_ps(__m256i in)
+_mm256_castsi256_ps(__m256i __in)
{
- return (__m256)in;
+ return (__m256)__in;
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_castsi256_pd(__m256i in)
+_mm256_castsi256_pd(__m256i __in)
{
- return (__m256d)in;
+ return (__m256d)__in;
}
static __inline __m128d __attribute__((__always_inline__, __nodebug__))
-_mm256_castpd256_pd128(__m256d in)
+_mm256_castpd256_pd128(__m256d __in)
{
- return __builtin_shufflevector(in, in, 0, 1);
+ return __builtin_shufflevector(__in, __in, 0, 1);
}
static __inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm256_castps256_ps128(__m256 in)
+_mm256_castps256_ps128(__m256 __in)
{
- return __builtin_shufflevector(in, in, 0, 1, 2, 3);
+ return __builtin_shufflevector(__in, __in, 0, 1, 2, 3);
}
static __inline __m128i __attribute__((__always_inline__, __nodebug__))
-_mm256_castsi256_si128(__m256i in)
+_mm256_castsi256_si128(__m256i __in)
{
- return __builtin_shufflevector(in, in, 0, 1);
+ return __builtin_shufflevector(__in, __in, 0, 1);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_castpd128_pd256(__m128d in)
+_mm256_castpd128_pd256(__m128d __in)
{
- __m128d zero = _mm_setzero_pd();
- return __builtin_shufflevector(in, zero, 0, 1, 2, 2);
+ __m128d __zero = _mm_setzero_pd();
+ return __builtin_shufflevector(__in, __zero, 0, 1, 2, 2);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_castps128_ps256(__m128 in)
+_mm256_castps128_ps256(__m128 __in)
{
- __m128 zero = _mm_setzero_ps();
- return __builtin_shufflevector(in, zero, 0, 1, 2, 3, 4, 4, 4, 4);
+ __m128 __zero = _mm_setzero_ps();
+ return __builtin_shufflevector(__in, __zero, 0, 1, 2, 3, 4, 4, 4, 4);
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_castsi128_si256(__m128i in)
+_mm256_castsi128_si256(__m128i __in)
{
- __m128i zero = _mm_setzero_si128();
- return __builtin_shufflevector(in, zero, 0, 1, 2, 2);
+ __m128i __zero = _mm_setzero_si128();
+ return __builtin_shufflevector(__in, __zero, 0, 1, 2, 2);
}
/* SIMD load ops (unaligned) */
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_loadu2_m128(float const *addr_hi, float const *addr_lo)
+_mm256_loadu2_m128(float const *__addr_hi, float const *__addr_lo)
{
struct __loadu_ps {
- __m128 v;
+ __m128 __v;
} __attribute__((__packed__, __may_alias__));
- __m256 v256 = _mm256_castps128_ps256(((struct __loadu_ps*)addr_lo)->v);
- return _mm256_insertf128_ps(v256, ((struct __loadu_ps*)addr_hi)->v, 1);
+ __m256 __v256 = _mm256_castps128_ps256(((struct __loadu_ps*)__addr_lo)->__v);
+ return _mm256_insertf128_ps(__v256, ((struct __loadu_ps*)__addr_hi)->__v, 1);
}
static __inline __m256d __attribute__((__always_inline__, __nodebug__))
-_mm256_loadu2_m128d(double const *addr_hi, double const *addr_lo)
+_mm256_loadu2_m128d(double const *__addr_hi, double const *__addr_lo)
{
struct __loadu_pd {
- __m128d v;
+ __m128d __v;
} __attribute__((__packed__, __may_alias__));
- __m256d v256 = _mm256_castpd128_pd256(((struct __loadu_pd*)addr_lo)->v);
- return _mm256_insertf128_pd(v256, ((struct __loadu_pd*)addr_hi)->v, 1);
+ __m256d __v256 = _mm256_castpd128_pd256(((struct __loadu_pd*)__addr_lo)->__v);
+ return _mm256_insertf128_pd(__v256, ((struct __loadu_pd*)__addr_hi)->__v, 1);
}
static __inline __m256i __attribute__((__always_inline__, __nodebug__))
-_mm256_loadu2_m128i(__m128i const *addr_hi, __m128i const *addr_lo)
+_mm256_loadu2_m128i(__m128i const *__addr_hi, __m128i const *__addr_lo)
{
struct __loadu_si128 {
- __m128i v;
+ __m128i __v;
} __attribute__((packed, may_alias));
- __m256i v256 = _mm256_castsi128_si256(((struct __loadu_si128*)addr_lo)->v);
- return _mm256_insertf128_si256(v256, ((struct __loadu_si128*)addr_hi)->v, 1);
+ __m256i __v256 = _mm256_castsi128_si256(
+ ((struct __loadu_si128*)__addr_lo)->__v);
+ return _mm256_insertf128_si256(__v256,
+ ((struct __loadu_si128*)__addr_hi)->__v, 1);
}
/* SIMD store ops (unaligned) */
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm256_storeu2_m128(float *addr_hi, float *addr_lo, __m256 a)
+_mm256_storeu2_m128(float *__addr_hi, float *__addr_lo, __m256 __a)
{
- __m128 v128;
+ __m128 __v128;
- v128 = _mm256_castps256_ps128(a);
- __builtin_ia32_storeups(addr_lo, v128);
- v128 = _mm256_extractf128_ps(a, 1);
- __builtin_ia32_storeups(addr_hi, v128);
+ __v128 = _mm256_castps256_ps128(__a);
+ __builtin_ia32_storeups(__addr_lo, __v128);
+ __v128 = _mm256_extractf128_ps(__a, 1);
+ __builtin_ia32_storeups(__addr_hi, __v128);
}
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm256_storeu2_m128d(double *addr_hi, double *addr_lo, __m256d a)
+_mm256_storeu2_m128d(double *__addr_hi, double *__addr_lo, __m256d __a)
{
- __m128d v128;
+ __m128d __v128;
- v128 = _mm256_castpd256_pd128(a);
- __builtin_ia32_storeupd(addr_lo, v128);
- v128 = _mm256_extractf128_pd(a, 1);
- __builtin_ia32_storeupd(addr_hi, v128);
+ __v128 = _mm256_castpd256_pd128(__a);
+ __builtin_ia32_storeupd(__addr_lo, __v128);
+ __v128 = _mm256_extractf128_pd(__a, 1);
+ __builtin_ia32_storeupd(__addr_hi, __v128);
}
static __inline void __attribute__((__always_inline__, __nodebug__))
-_mm256_storeu2_m128i(__m128i *addr_hi, __m128i *addr_lo, __m256i a)
+_mm256_storeu2_m128i(__m128i *__addr_hi, __m128i *__addr_lo, __m256i __a)
{
- __m128i v128;
+ __m128i __v128;
- v128 = _mm256_castsi256_si128(a);
- __builtin_ia32_storedqu((char *)addr_lo, (__v16qi)v128);
- v128 = _mm256_extractf128_si256(a, 1);
- __builtin_ia32_storedqu((char *)addr_hi, (__v16qi)v128);
+ __v128 = _mm256_castsi256_si128(__a);
+ __builtin_ia32_storedqu((char *)__addr_lo, (__v16qi)__v128);
+ __v128 = _mm256_extractf128_si256(__a, 1);
+ __builtin_ia32_storedqu((char *)__addr_hi, (__v16qi)__v128);
}
diff --git a/lib/Headers/cpuid.h b/lib/Headers/cpuid.h
index 33df7c2..7b01238 100644
--- a/lib/Headers/cpuid.h
+++ b/lib/Headers/cpuid.h
@@ -25,9 +25,10 @@
#error this header is for x86 only
#endif
-static inline int __get_cpuid (unsigned int level, unsigned int *eax,
- unsigned int *ebx, unsigned int *ecx,
- unsigned int *edx) {
- __asm("cpuid" : "=a"(*eax), "=b" (*ebx), "=c"(*ecx), "=d"(*edx) : "0"(level));
+static __inline int __get_cpuid (unsigned int __level, unsigned int *__eax,
+ unsigned int *__ebx, unsigned int *__ecx,
+ unsigned int *__edx) {
+ __asm("cpuid" : "=a"(*__eax), "=b" (*__ebx), "=c"(*__ecx), "=d"(*__edx)
+ : "0"(__level));
return 1;
}
diff --git a/lib/Headers/emmintrin.h b/lib/Headers/emmintrin.h
index 91395ed..e18fae4 100644
--- a/lib/Headers/emmintrin.h
+++ b/lib/Headers/emmintrin.h
@@ -40,507 +40,507 @@ typedef short __v8hi __attribute__((__vector_size__(16)));
typedef char __v16qi __attribute__((__vector_size__(16)));
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_add_sd(__m128d a, __m128d b)
+_mm_add_sd(__m128d __a, __m128d __b)
{
- a[0] += b[0];
- return a;
+ __a[0] += __b[0];
+ return __a;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_add_pd(__m128d a, __m128d b)
+_mm_add_pd(__m128d __a, __m128d __b)
{
- return a + b;
+ return __a + __b;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_sub_sd(__m128d a, __m128d b)
+_mm_sub_sd(__m128d __a, __m128d __b)
{
- a[0] -= b[0];
- return a;
+ __a[0] -= __b[0];
+ return __a;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_sub_pd(__m128d a, __m128d b)
+_mm_sub_pd(__m128d __a, __m128d __b)
{
- return a - b;
+ return __a - __b;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_mul_sd(__m128d a, __m128d b)
+_mm_mul_sd(__m128d __a, __m128d __b)
{
- a[0] *= b[0];
- return a;
+ __a[0] *= __b[0];
+ return __a;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_mul_pd(__m128d a, __m128d b)
+_mm_mul_pd(__m128d __a, __m128d __b)
{
- return a * b;
+ return __a * __b;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_div_sd(__m128d a, __m128d b)
+_mm_div_sd(__m128d __a, __m128d __b)
{
- a[0] /= b[0];
- return a;
+ __a[0] /= __b[0];
+ return __a;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_div_pd(__m128d a, __m128d b)
+_mm_div_pd(__m128d __a, __m128d __b)
{
- return a / b;
+ return __a / __b;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_sqrt_sd(__m128d a, __m128d b)
+_mm_sqrt_sd(__m128d __a, __m128d __b)
{
- __m128d c = __builtin_ia32_sqrtsd(b);
- return (__m128d) { c[0], a[1] };
+ __m128d __c = __builtin_ia32_sqrtsd(__b);
+ return (__m128d) { __c[0], __a[1] };
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_sqrt_pd(__m128d a)
+_mm_sqrt_pd(__m128d __a)
{
- return __builtin_ia32_sqrtpd(a);
+ return __builtin_ia32_sqrtpd(__a);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_min_sd(__m128d a, __m128d b)
+_mm_min_sd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_minsd(a, b);
+ return __builtin_ia32_minsd(__a, __b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_min_pd(__m128d a, __m128d b)
+_mm_min_pd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_minpd(a, b);
+ return __builtin_ia32_minpd(__a, __b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_max_sd(__m128d a, __m128d b)
+_mm_max_sd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_maxsd(a, b);
+ return __builtin_ia32_maxsd(__a, __b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_max_pd(__m128d a, __m128d b)
+_mm_max_pd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_maxpd(a, b);
+ return __builtin_ia32_maxpd(__a, __b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_and_pd(__m128d a, __m128d b)
+_mm_and_pd(__m128d __a, __m128d __b)
{
- return (__m128d)((__v4si)a & (__v4si)b);
+ return (__m128d)((__v4si)__a & (__v4si)__b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_andnot_pd(__m128d a, __m128d b)
+_mm_andnot_pd(__m128d __a, __m128d __b)
{
- return (__m128d)(~(__v4si)a & (__v4si)b);
+ return (__m128d)(~(__v4si)__a & (__v4si)__b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_or_pd(__m128d a, __m128d b)
+_mm_or_pd(__m128d __a, __m128d __b)
{
- return (__m128d)((__v4si)a | (__v4si)b);
+ return (__m128d)((__v4si)__a | (__v4si)__b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_xor_pd(__m128d a, __m128d b)
+_mm_xor_pd(__m128d __a, __m128d __b)
{
- return (__m128d)((__v4si)a ^ (__v4si)b);
+ return (__m128d)((__v4si)__a ^ (__v4si)__b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpeq_pd(__m128d a, __m128d b)
+_mm_cmpeq_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(a, b, 0);
+ return (__m128d)__builtin_ia32_cmppd(__a, __b, 0);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmplt_pd(__m128d a, __m128d b)
+_mm_cmplt_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(a, b, 1);
+ return (__m128d)__builtin_ia32_cmppd(__a, __b, 1);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmple_pd(__m128d a, __m128d b)
+_mm_cmple_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(a, b, 2);
+ return (__m128d)__builtin_ia32_cmppd(__a, __b, 2);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpgt_pd(__m128d a, __m128d b)
+_mm_cmpgt_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(b, a, 1);
+ return (__m128d)__builtin_ia32_cmppd(__b, __a, 1);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpge_pd(__m128d a, __m128d b)
+_mm_cmpge_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(b, a, 2);
+ return (__m128d)__builtin_ia32_cmppd(__b, __a, 2);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpord_pd(__m128d a, __m128d b)
+_mm_cmpord_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(a, b, 7);
+ return (__m128d)__builtin_ia32_cmppd(__a, __b, 7);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpunord_pd(__m128d a, __m128d b)
+_mm_cmpunord_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(a, b, 3);
+ return (__m128d)__builtin_ia32_cmppd(__a, __b, 3);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpneq_pd(__m128d a, __m128d b)
+_mm_cmpneq_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(a, b, 4);
+ return (__m128d)__builtin_ia32_cmppd(__a, __b, 4);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpnlt_pd(__m128d a, __m128d b)
+_mm_cmpnlt_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(a, b, 5);
+ return (__m128d)__builtin_ia32_cmppd(__a, __b, 5);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpnle_pd(__m128d a, __m128d b)
+_mm_cmpnle_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(a, b, 6);
+ return (__m128d)__builtin_ia32_cmppd(__a, __b, 6);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpngt_pd(__m128d a, __m128d b)
+_mm_cmpngt_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(b, a, 5);
+ return (__m128d)__builtin_ia32_cmppd(__b, __a, 5);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpnge_pd(__m128d a, __m128d b)
+_mm_cmpnge_pd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmppd(b, a, 6);
+ return (__m128d)__builtin_ia32_cmppd(__b, __a, 6);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpeq_sd(__m128d a, __m128d b)
+_mm_cmpeq_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(a, b, 0);
+ return (__m128d)__builtin_ia32_cmpsd(__a, __b, 0);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmplt_sd(__m128d a, __m128d b)
+_mm_cmplt_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(a, b, 1);
+ return (__m128d)__builtin_ia32_cmpsd(__a, __b, 1);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmple_sd(__m128d a, __m128d b)
+_mm_cmple_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(a, b, 2);
+ return (__m128d)__builtin_ia32_cmpsd(__a, __b, 2);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpgt_sd(__m128d a, __m128d b)
+_mm_cmpgt_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(b, a, 1);
+ return (__m128d)__builtin_ia32_cmpsd(__b, __a, 1);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpge_sd(__m128d a, __m128d b)
+_mm_cmpge_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(b, a, 2);
+ return (__m128d)__builtin_ia32_cmpsd(__b, __a, 2);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpord_sd(__m128d a, __m128d b)
+_mm_cmpord_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(a, b, 7);
+ return (__m128d)__builtin_ia32_cmpsd(__a, __b, 7);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpunord_sd(__m128d a, __m128d b)
+_mm_cmpunord_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(a, b, 3);
+ return (__m128d)__builtin_ia32_cmpsd(__a, __b, 3);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpneq_sd(__m128d a, __m128d b)
+_mm_cmpneq_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(a, b, 4);
+ return (__m128d)__builtin_ia32_cmpsd(__a, __b, 4);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpnlt_sd(__m128d a, __m128d b)
+_mm_cmpnlt_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(a, b, 5);
+ return (__m128d)__builtin_ia32_cmpsd(__a, __b, 5);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpnle_sd(__m128d a, __m128d b)
+_mm_cmpnle_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(a, b, 6);
+ return (__m128d)__builtin_ia32_cmpsd(__a, __b, 6);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpngt_sd(__m128d a, __m128d b)
+_mm_cmpngt_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(b, a, 5);
+ return (__m128d)__builtin_ia32_cmpsd(__b, __a, 5);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cmpnge_sd(__m128d a, __m128d b)
+_mm_cmpnge_sd(__m128d __a, __m128d __b)
{
- return (__m128d)__builtin_ia32_cmpsd(b, a, 6);
+ return (__m128d)__builtin_ia32_cmpsd(__b, __a, 6);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_comieq_sd(__m128d a, __m128d b)
+_mm_comieq_sd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_comisdeq(a, b);
+ return __builtin_ia32_comisdeq(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_comilt_sd(__m128d a, __m128d b)
+_mm_comilt_sd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_comisdlt(a, b);
+ return __builtin_ia32_comisdlt(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_comile_sd(__m128d a, __m128d b)
+_mm_comile_sd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_comisdle(a, b);
+ return __builtin_ia32_comisdle(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_comigt_sd(__m128d a, __m128d b)
+_mm_comigt_sd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_comisdgt(a, b);
+ return __builtin_ia32_comisdgt(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_comige_sd(__m128d a, __m128d b)
+_mm_comige_sd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_comisdge(a, b);
+ return __builtin_ia32_comisdge(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_comineq_sd(__m128d a, __m128d b)
+_mm_comineq_sd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_comisdneq(a, b);
+ return __builtin_ia32_comisdneq(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_ucomieq_sd(__m128d a, __m128d b)
+_mm_ucomieq_sd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_ucomisdeq(a, b);
+ return __builtin_ia32_ucomisdeq(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_ucomilt_sd(__m128d a, __m128d b)
+_mm_ucomilt_sd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_ucomisdlt(a, b);
+ return __builtin_ia32_ucomisdlt(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_ucomile_sd(__m128d a, __m128d b)
+_mm_ucomile_sd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_ucomisdle(a, b);
+ return __builtin_ia32_ucomisdle(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_ucomigt_sd(__m128d a, __m128d b)
+_mm_ucomigt_sd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_ucomisdgt(a, b);
+ return __builtin_ia32_ucomisdgt(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_ucomige_sd(__m128d a, __m128d b)
+_mm_ucomige_sd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_ucomisdge(a, b);
+ return __builtin_ia32_ucomisdge(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_ucomineq_sd(__m128d a, __m128d b)
+_mm_ucomineq_sd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_ucomisdneq(a, b);
+ return __builtin_ia32_ucomisdneq(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtpd_ps(__m128d a)
+_mm_cvtpd_ps(__m128d __a)
{
- return __builtin_ia32_cvtpd2ps(a);
+ return __builtin_ia32_cvtpd2ps(__a);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cvtps_pd(__m128 a)
+_mm_cvtps_pd(__m128 __a)
{
- return __builtin_ia32_cvtps2pd(a);
+ return __builtin_ia32_cvtps2pd(__a);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cvtepi32_pd(__m128i a)
+_mm_cvtepi32_pd(__m128i __a)
{
- return __builtin_ia32_cvtdq2pd((__v4si)a);
+ return __builtin_ia32_cvtdq2pd((__v4si)__a);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cvtpd_epi32(__m128d a)
+_mm_cvtpd_epi32(__m128d __a)
{
- return __builtin_ia32_cvtpd2dq(a);
+ return __builtin_ia32_cvtpd2dq(__a);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_cvtsd_si32(__m128d a)
+_mm_cvtsd_si32(__m128d __a)
{
- return __builtin_ia32_cvtsd2si(a);
+ return __builtin_ia32_cvtsd2si(__a);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtsd_ss(__m128 a, __m128d b)
+_mm_cvtsd_ss(__m128 __a, __m128d __b)
{
- a[0] = b[0];
- return a;
+ __a[0] = __b[0];
+ return __a;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cvtsi32_sd(__m128d a, int b)
+_mm_cvtsi32_sd(__m128d __a, int __b)
{
- a[0] = b;
- return a;
+ __a[0] = __b;
+ return __a;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cvtss_sd(__m128d a, __m128 b)
+_mm_cvtss_sd(__m128d __a, __m128 __b)
{
- a[0] = b[0];
- return a;
+ __a[0] = __b[0];
+ return __a;
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cvttpd_epi32(__m128d a)
+_mm_cvttpd_epi32(__m128d __a)
{
- return (__m128i)__builtin_ia32_cvttpd2dq(a);
+ return (__m128i)__builtin_ia32_cvttpd2dq(__a);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_cvttsd_si32(__m128d a)
+_mm_cvttsd_si32(__m128d __a)
{
- return a[0];
+ return __a[0];
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtpd_pi32(__m128d a)
+_mm_cvtpd_pi32(__m128d __a)
{
- return (__m64)__builtin_ia32_cvtpd2pi(a);
+ return (__m64)__builtin_ia32_cvtpd2pi(__a);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_cvttpd_pi32(__m128d a)
+_mm_cvttpd_pi32(__m128d __a)
{
- return (__m64)__builtin_ia32_cvttpd2pi(a);
+ return (__m64)__builtin_ia32_cvttpd2pi(__a);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cvtpi32_pd(__m64 a)
+_mm_cvtpi32_pd(__m64 __a)
{
- return __builtin_ia32_cvtpi2pd((__v2si)a);
+ return __builtin_ia32_cvtpi2pd((__v2si)__a);
}
static __inline__ double __attribute__((__always_inline__, __nodebug__))
-_mm_cvtsd_f64(__m128d a)
+_mm_cvtsd_f64(__m128d __a)
{
- return a[0];
+ return __a[0];
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_load_pd(double const *dp)
+_mm_load_pd(double const *__dp)
{
- return *(__m128d*)dp;
+ return *(__m128d*)__dp;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_load1_pd(double const *dp)
+_mm_load1_pd(double const *__dp)
{
struct __mm_load1_pd_struct {
- double u;
+ double __u;
} __attribute__((__packed__, __may_alias__));
- double u = ((struct __mm_load1_pd_struct*)dp)->u;
- return (__m128d){ u, u };
+ double __u = ((struct __mm_load1_pd_struct*)__dp)->__u;
+ return (__m128d){ __u, __u };
}
#define _mm_load_pd1(dp) _mm_load1_pd(dp)
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_loadr_pd(double const *dp)
+_mm_loadr_pd(double const *__dp)
{
- __m128d u = *(__m128d*)dp;
- return __builtin_shufflevector(u, u, 1, 0);
+ __m128d __u = *(__m128d*)__dp;
+ return __builtin_shufflevector(__u, __u, 1, 0);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_loadu_pd(double const *dp)
+_mm_loadu_pd(double const *__dp)
{
struct __loadu_pd {
- __m128d v;
+ __m128d __v;
} __attribute__((packed, may_alias));
- return ((struct __loadu_pd*)dp)->v;
+ return ((struct __loadu_pd*)__dp)->__v;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_load_sd(double const *dp)
+_mm_load_sd(double const *__dp)
{
struct __mm_load_sd_struct {
- double u;
+ double __u;
} __attribute__((__packed__, __may_alias__));
- double u = ((struct __mm_load_sd_struct*)dp)->u;
- return (__m128d){ u, 0 };
+ double __u = ((struct __mm_load_sd_struct*)__dp)->__u;
+ return (__m128d){ __u, 0 };
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_loadh_pd(__m128d a, double const *dp)
+_mm_loadh_pd(__m128d __a, double const *__dp)
{
struct __mm_loadh_pd_struct {
- double u;
+ double __u;
} __attribute__((__packed__, __may_alias__));
- double u = ((struct __mm_loadh_pd_struct*)dp)->u;
- return (__m128d){ a[0], u };
+ double __u = ((struct __mm_loadh_pd_struct*)__dp)->__u;
+ return (__m128d){ __a[0], __u };
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_loadl_pd(__m128d a, double const *dp)
+_mm_loadl_pd(__m128d __a, double const *__dp)
{
struct __mm_loadl_pd_struct {
- double u;
+ double __u;
} __attribute__((__packed__, __may_alias__));
- double u = ((struct __mm_loadl_pd_struct*)dp)->u;
- return (__m128d){ u, a[1] };
+ double __u = ((struct __mm_loadl_pd_struct*)__dp)->__u;
+ return (__m128d){ __u, __a[1] };
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_set_sd(double w)
+_mm_set_sd(double __w)
{
- return (__m128d){ w, 0 };
+ return (__m128d){ __w, 0 };
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_set1_pd(double w)
+_mm_set1_pd(double __w)
{
- return (__m128d){ w, w };
+ return (__m128d){ __w, __w };
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_set_pd(double w, double x)
+_mm_set_pd(double __w, double __x)
{
- return (__m128d){ x, w };
+ return (__m128d){ __x, __w };
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_setr_pd(double w, double x)
+_mm_setr_pd(double __w, double __x)
{
- return (__m128d){ w, x };
+ return (__m128d){ __w, __x };
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
@@ -550,275 +550,275 @@ _mm_setzero_pd(void)
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_move_sd(__m128d a, __m128d b)
+_mm_move_sd(__m128d __a, __m128d __b)
{
- return (__m128d){ b[0], a[1] };
+ return (__m128d){ __b[0], __a[1] };
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_store_sd(double *dp, __m128d a)
+_mm_store_sd(double *__dp, __m128d __a)
{
struct __mm_store_sd_struct {
- double u;
+ double __u;
} __attribute__((__packed__, __may_alias__));
- ((struct __mm_store_sd_struct*)dp)->u = a[0];
+ ((struct __mm_store_sd_struct*)__dp)->__u = __a[0];
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_store1_pd(double *dp, __m128d a)
+_mm_store1_pd(double *__dp, __m128d __a)
{
struct __mm_store1_pd_struct {
- double u[2];
+ double __u[2];
} __attribute__((__packed__, __may_alias__));
- ((struct __mm_store1_pd_struct*)dp)->u[0] = a[0];
- ((struct __mm_store1_pd_struct*)dp)->u[1] = a[0];
+ ((struct __mm_store1_pd_struct*)__dp)->__u[0] = __a[0];
+ ((struct __mm_store1_pd_struct*)__dp)->__u[1] = __a[0];
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_store_pd(double *dp, __m128d a)
+_mm_store_pd(double *__dp, __m128d __a)
{
- *(__m128d *)dp = a;
+ *(__m128d *)__dp = __a;
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_storeu_pd(double *dp, __m128d a)
+_mm_storeu_pd(double *__dp, __m128d __a)
{
- __builtin_ia32_storeupd(dp, a);
+ __builtin_ia32_storeupd(__dp, __a);
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_storer_pd(double *dp, __m128d a)
+_mm_storer_pd(double *__dp, __m128d __a)
{
- a = __builtin_shufflevector(a, a, 1, 0);
- *(__m128d *)dp = a;
+ __a = __builtin_shufflevector(__a, __a, 1, 0);
+ *(__m128d *)__dp = __a;
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_storeh_pd(double *dp, __m128d a)
+_mm_storeh_pd(double *__dp, __m128d __a)
{
struct __mm_storeh_pd_struct {
- double u;
+ double __u;
} __attribute__((__packed__, __may_alias__));
- ((struct __mm_storeh_pd_struct*)dp)->u = a[1];
+ ((struct __mm_storeh_pd_struct*)__dp)->__u = __a[1];
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_storel_pd(double *dp, __m128d a)
+_mm_storel_pd(double *__dp, __m128d __a)
{
struct __mm_storeh_pd_struct {
- double u;
+ double __u;
} __attribute__((__packed__, __may_alias__));
- ((struct __mm_storeh_pd_struct*)dp)->u = a[0];
+ ((struct __mm_storeh_pd_struct*)__dp)->__u = __a[0];
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_add_epi8(__m128i a, __m128i b)
+_mm_add_epi8(__m128i __a, __m128i __b)
{
- return (__m128i)((__v16qi)a + (__v16qi)b);
+ return (__m128i)((__v16qi)__a + (__v16qi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_add_epi16(__m128i a, __m128i b)
+_mm_add_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)((__v8hi)a + (__v8hi)b);
+ return (__m128i)((__v8hi)__a + (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_add_epi32(__m128i a, __m128i b)
+_mm_add_epi32(__m128i __a, __m128i __b)
{
- return (__m128i)((__v4si)a + (__v4si)b);
+ return (__m128i)((__v4si)__a + (__v4si)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_add_si64(__m64 a, __m64 b)
+_mm_add_si64(__m64 __a, __m64 __b)
{
- return a + b;
+ return __a + __b;
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_add_epi64(__m128i a, __m128i b)
+_mm_add_epi64(__m128i __a, __m128i __b)
{
- return a + b;
+ return __a + __b;
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_adds_epi8(__m128i a, __m128i b)
+_mm_adds_epi8(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_paddsb128((__v16qi)a, (__v16qi)b);
+ return (__m128i)__builtin_ia32_paddsb128((__v16qi)__a, (__v16qi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_adds_epi16(__m128i a, __m128i b)
+_mm_adds_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_paddsw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_paddsw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_adds_epu8(__m128i a, __m128i b)
+_mm_adds_epu8(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_paddusb128((__v16qi)a, (__v16qi)b);
+ return (__m128i)__builtin_ia32_paddusb128((__v16qi)__a, (__v16qi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_adds_epu16(__m128i a, __m128i b)
+_mm_adds_epu16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_paddusw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_paddusw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_avg_epu8(__m128i a, __m128i b)
+_mm_avg_epu8(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pavgb128((__v16qi)a, (__v16qi)b);
+ return (__m128i)__builtin_ia32_pavgb128((__v16qi)__a, (__v16qi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_avg_epu16(__m128i a, __m128i b)
+_mm_avg_epu16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pavgw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_pavgw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_madd_epi16(__m128i a, __m128i b)
+_mm_madd_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pmaddwd128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_pmaddwd128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_max_epi16(__m128i a, __m128i b)
+_mm_max_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pmaxsw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_pmaxsw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_max_epu8(__m128i a, __m128i b)
+_mm_max_epu8(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pmaxub128((__v16qi)a, (__v16qi)b);
+ return (__m128i)__builtin_ia32_pmaxub128((__v16qi)__a, (__v16qi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_min_epi16(__m128i a, __m128i b)
+_mm_min_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pminsw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_pminsw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_min_epu8(__m128i a, __m128i b)
+_mm_min_epu8(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pminub128((__v16qi)a, (__v16qi)b);
+ return (__m128i)__builtin_ia32_pminub128((__v16qi)__a, (__v16qi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_mulhi_epi16(__m128i a, __m128i b)
+_mm_mulhi_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pmulhw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_pmulhw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_mulhi_epu16(__m128i a, __m128i b)
+_mm_mulhi_epu16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pmulhuw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_pmulhuw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_mullo_epi16(__m128i a, __m128i b)
+_mm_mullo_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)((__v8hi)a * (__v8hi)b);
+ return (__m128i)((__v8hi)__a * (__v8hi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_mul_su32(__m64 a, __m64 b)
+_mm_mul_su32(__m64 __a, __m64 __b)
{
- return __builtin_ia32_pmuludq((__v2si)a, (__v2si)b);
+ return __builtin_ia32_pmuludq((__v2si)__a, (__v2si)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_mul_epu32(__m128i a, __m128i b)
+_mm_mul_epu32(__m128i __a, __m128i __b)
{
- return __builtin_ia32_pmuludq128((__v4si)a, (__v4si)b);
+ return __builtin_ia32_pmuludq128((__v4si)__a, (__v4si)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_sad_epu8(__m128i a, __m128i b)
+_mm_sad_epu8(__m128i __a, __m128i __b)
{
- return __builtin_ia32_psadbw128((__v16qi)a, (__v16qi)b);
+ return __builtin_ia32_psadbw128((__v16qi)__a, (__v16qi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_sub_epi8(__m128i a, __m128i b)
+_mm_sub_epi8(__m128i __a, __m128i __b)
{
- return (__m128i)((__v16qi)a - (__v16qi)b);
+ return (__m128i)((__v16qi)__a - (__v16qi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_sub_epi16(__m128i a, __m128i b)
+_mm_sub_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)((__v8hi)a - (__v8hi)b);
+ return (__m128i)((__v8hi)__a - (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_sub_epi32(__m128i a, __m128i b)
+_mm_sub_epi32(__m128i __a, __m128i __b)
{
- return (__m128i)((__v4si)a - (__v4si)b);
+ return (__m128i)((__v4si)__a - (__v4si)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_sub_si64(__m64 a, __m64 b)
+_mm_sub_si64(__m64 __a, __m64 __b)
{
- return a - b;
+ return __a - __b;
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_sub_epi64(__m128i a, __m128i b)
+_mm_sub_epi64(__m128i __a, __m128i __b)
{
- return a - b;
+ return __a - __b;
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_subs_epi8(__m128i a, __m128i b)
+_mm_subs_epi8(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_psubsb128((__v16qi)a, (__v16qi)b);
+ return (__m128i)__builtin_ia32_psubsb128((__v16qi)__a, (__v16qi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_subs_epi16(__m128i a, __m128i b)
+_mm_subs_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_psubsw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_psubsw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_subs_epu8(__m128i a, __m128i b)
+_mm_subs_epu8(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_psubusb128((__v16qi)a, (__v16qi)b);
+ return (__m128i)__builtin_ia32_psubusb128((__v16qi)__a, (__v16qi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_subs_epu16(__m128i a, __m128i b)
+_mm_subs_epu16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_psubusw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_psubusw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_and_si128(__m128i a, __m128i b)
+_mm_and_si128(__m128i __a, __m128i __b)
{
- return a & b;
+ return __a & __b;
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_andnot_si128(__m128i a, __m128i b)
+_mm_andnot_si128(__m128i __a, __m128i __b)
{
- return ~a & b;
+ return ~__a & __b;
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_or_si128(__m128i a, __m128i b)
+_mm_or_si128(__m128i __a, __m128i __b)
{
- return a | b;
+ return __a | __b;
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_xor_si128(__m128i a, __m128i b)
+_mm_xor_si128(__m128i __a, __m128i __b)
{
- return a ^ b;
+ return __a ^ __b;
}
#define _mm_slli_si128(a, count) __extension__ ({ \
@@ -826,63 +826,63 @@ _mm_xor_si128(__m128i a, __m128i b)
(__m128i)__builtin_ia32_pslldqi128(__a, (count)*8); })
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_slli_epi16(__m128i a, int count)
+_mm_slli_epi16(__m128i __a, int __count)
{
- return (__m128i)__builtin_ia32_psllwi128((__v8hi)a, count);
+ return (__m128i)__builtin_ia32_psllwi128((__v8hi)__a, __count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_sll_epi16(__m128i a, __m128i count)
+_mm_sll_epi16(__m128i __a, __m128i __count)
{
- return (__m128i)__builtin_ia32_psllw128((__v8hi)a, (__v8hi)count);
+ return (__m128i)__builtin_ia32_psllw128((__v8hi)__a, (__v8hi)__count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_slli_epi32(__m128i a, int count)
+_mm_slli_epi32(__m128i __a, int __count)
{
- return (__m128i)__builtin_ia32_pslldi128((__v4si)a, count);
+ return (__m128i)__builtin_ia32_pslldi128((__v4si)__a, __count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_sll_epi32(__m128i a, __m128i count)
+_mm_sll_epi32(__m128i __a, __m128i __count)
{
- return (__m128i)__builtin_ia32_pslld128((__v4si)a, (__v4si)count);
+ return (__m128i)__builtin_ia32_pslld128((__v4si)__a, (__v4si)__count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_slli_epi64(__m128i a, int count)
+_mm_slli_epi64(__m128i __a, int __count)
{
- return __builtin_ia32_psllqi128(a, count);
+ return __builtin_ia32_psllqi128(__a, __count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_sll_epi64(__m128i a, __m128i count)
+_mm_sll_epi64(__m128i __a, __m128i __count)
{
- return __builtin_ia32_psllq128(a, count);
+ return __builtin_ia32_psllq128(__a, __count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_srai_epi16(__m128i a, int count)
+_mm_srai_epi16(__m128i __a, int __count)
{
- return (__m128i)__builtin_ia32_psrawi128((__v8hi)a, count);
+ return (__m128i)__builtin_ia32_psrawi128((__v8hi)__a, __count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_sra_epi16(__m128i a, __m128i count)
+_mm_sra_epi16(__m128i __a, __m128i __count)
{
- return (__m128i)__builtin_ia32_psraw128((__v8hi)a, (__v8hi)count);
+ return (__m128i)__builtin_ia32_psraw128((__v8hi)__a, (__v8hi)__count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_srai_epi32(__m128i a, int count)
+_mm_srai_epi32(__m128i __a, int __count)
{
- return (__m128i)__builtin_ia32_psradi128((__v4si)a, count);
+ return (__m128i)__builtin_ia32_psradi128((__v4si)__a, __count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_sra_epi32(__m128i a, __m128i count)
+_mm_sra_epi32(__m128i __a, __m128i __count)
{
- return (__m128i)__builtin_ia32_psrad128((__v4si)a, (__v4si)count);
+ return (__m128i)__builtin_ia32_psrad128((__v4si)__a, (__v4si)__count);
}
@@ -891,188 +891,188 @@ _mm_sra_epi32(__m128i a, __m128i count)
(__m128i)__builtin_ia32_psrldqi128(__a, (count)*8); })
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_srli_epi16(__m128i a, int count)
+_mm_srli_epi16(__m128i __a, int __count)
{
- return (__m128i)__builtin_ia32_psrlwi128((__v8hi)a, count);
+ return (__m128i)__builtin_ia32_psrlwi128((__v8hi)__a, __count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_srl_epi16(__m128i a, __m128i count)
+_mm_srl_epi16(__m128i __a, __m128i __count)
{
- return (__m128i)__builtin_ia32_psrlw128((__v8hi)a, (__v8hi)count);
+ return (__m128i)__builtin_ia32_psrlw128((__v8hi)__a, (__v8hi)__count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_srli_epi32(__m128i a, int count)
+_mm_srli_epi32(__m128i __a, int __count)
{
- return (__m128i)__builtin_ia32_psrldi128((__v4si)a, count);
+ return (__m128i)__builtin_ia32_psrldi128((__v4si)__a, __count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_srl_epi32(__m128i a, __m128i count)
+_mm_srl_epi32(__m128i __a, __m128i __count)
{
- return (__m128i)__builtin_ia32_psrld128((__v4si)a, (__v4si)count);
+ return (__m128i)__builtin_ia32_psrld128((__v4si)__a, (__v4si)__count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_srli_epi64(__m128i a, int count)
+_mm_srli_epi64(__m128i __a, int __count)
{
- return __builtin_ia32_psrlqi128(a, count);
+ return __builtin_ia32_psrlqi128(__a, __count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_srl_epi64(__m128i a, __m128i count)
+_mm_srl_epi64(__m128i __a, __m128i __count)
{
- return __builtin_ia32_psrlq128(a, count);
+ return __builtin_ia32_psrlq128(__a, __count);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cmpeq_epi8(__m128i a, __m128i b)
+_mm_cmpeq_epi8(__m128i __a, __m128i __b)
{
- return (__m128i)((__v16qi)a == (__v16qi)b);
+ return (__m128i)((__v16qi)__a == (__v16qi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cmpeq_epi16(__m128i a, __m128i b)
+_mm_cmpeq_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)((__v8hi)a == (__v8hi)b);
+ return (__m128i)((__v8hi)__a == (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cmpeq_epi32(__m128i a, __m128i b)
+_mm_cmpeq_epi32(__m128i __a, __m128i __b)
{
- return (__m128i)((__v4si)a == (__v4si)b);
+ return (__m128i)((__v4si)__a == (__v4si)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cmpgt_epi8(__m128i a, __m128i b)
+_mm_cmpgt_epi8(__m128i __a, __m128i __b)
{
/* This function always performs a signed comparison, but __v16qi is a char
which may be signed or unsigned. */
typedef signed char __v16qs __attribute__((__vector_size__(16)));
- return (__m128i)((__v16qs)a > (__v16qs)b);
+ return (__m128i)((__v16qs)__a > (__v16qs)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cmpgt_epi16(__m128i a, __m128i b)
+_mm_cmpgt_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)((__v8hi)a > (__v8hi)b);
+ return (__m128i)((__v8hi)__a > (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cmpgt_epi32(__m128i a, __m128i b)
+_mm_cmpgt_epi32(__m128i __a, __m128i __b)
{
- return (__m128i)((__v4si)a > (__v4si)b);
+ return (__m128i)((__v4si)__a > (__v4si)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cmplt_epi8(__m128i a, __m128i b)
+_mm_cmplt_epi8(__m128i __a, __m128i __b)
{
- return _mm_cmpgt_epi8(b,a);
+ return _mm_cmpgt_epi8(__b, __a);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cmplt_epi16(__m128i a, __m128i b)
+_mm_cmplt_epi16(__m128i __a, __m128i __b)
{
- return _mm_cmpgt_epi16(b,a);
+ return _mm_cmpgt_epi16(__b, __a);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cmplt_epi32(__m128i a, __m128i b)
+_mm_cmplt_epi32(__m128i __a, __m128i __b)
{
- return _mm_cmpgt_epi32(b,a);
+ return _mm_cmpgt_epi32(__b, __a);
}
#ifdef __x86_64__
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_cvtsi64_sd(__m128d a, long long b)
+_mm_cvtsi64_sd(__m128d __a, long long __b)
{
- a[0] = b;
- return a;
+ __a[0] = __b;
+ return __a;
}
static __inline__ long long __attribute__((__always_inline__, __nodebug__))
-_mm_cvtsd_si64(__m128d a)
+_mm_cvtsd_si64(__m128d __a)
{
- return __builtin_ia32_cvtsd2si64(a);
+ return __builtin_ia32_cvtsd2si64(__a);
}
static __inline__ long long __attribute__((__always_inline__, __nodebug__))
-_mm_cvttsd_si64(__m128d a)
+_mm_cvttsd_si64(__m128d __a)
{
- return a[0];
+ return __a[0];
}
#endif
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtepi32_ps(__m128i a)
+_mm_cvtepi32_ps(__m128i __a)
{
- return __builtin_ia32_cvtdq2ps((__v4si)a);
+ return __builtin_ia32_cvtdq2ps((__v4si)__a);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cvtps_epi32(__m128 a)
+_mm_cvtps_epi32(__m128 __a)
{
- return (__m128i)__builtin_ia32_cvtps2dq(a);
+ return (__m128i)__builtin_ia32_cvtps2dq(__a);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cvttps_epi32(__m128 a)
+_mm_cvttps_epi32(__m128 __a)
{
- return (__m128i)__builtin_ia32_cvttps2dq(a);
+ return (__m128i)__builtin_ia32_cvttps2dq(__a);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cvtsi32_si128(int a)
+_mm_cvtsi32_si128(int __a)
{
- return (__m128i)(__v4si){ a, 0, 0, 0 };
+ return (__m128i)(__v4si){ __a, 0, 0, 0 };
}
#ifdef __x86_64__
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_cvtsi64_si128(long long a)
+_mm_cvtsi64_si128(long long __a)
{
- return (__m128i){ a, 0 };
+ return (__m128i){ __a, 0 };
}
#endif
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_cvtsi128_si32(__m128i a)
+_mm_cvtsi128_si32(__m128i __a)
{
- __v4si b = (__v4si)a;
- return b[0];
+ __v4si __b = (__v4si)__a;
+ return __b[0];
}
#ifdef __x86_64__
static __inline__ long long __attribute__((__always_inline__, __nodebug__))
-_mm_cvtsi128_si64(__m128i a)
+_mm_cvtsi128_si64(__m128i __a)
{
- return a[0];
+ return __a[0];
}
#endif
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_load_si128(__m128i const *p)
+_mm_load_si128(__m128i const *__p)
{
- return *p;
+ return *__p;
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_loadu_si128(__m128i const *p)
+_mm_loadu_si128(__m128i const *__p)
{
struct __loadu_si128 {
- __m128i v;
+ __m128i __v;
} __attribute__((packed, may_alias));
- return ((struct __loadu_si128*)p)->v;
+ return ((struct __loadu_si128*)__p)->__v;
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_loadl_epi64(__m128i const *p)
+_mm_loadl_epi64(__m128i const *__p)
{
struct __mm_loadl_epi64_struct {
- long long u;
+ long long __u;
} __attribute__((__packed__, __may_alias__));
- return (__m128i) { ((struct __mm_loadl_epi64_struct*)p)->u, 0};
+ return (__m128i) { ((struct __mm_loadl_epi64_struct*)__p)->__u, 0};
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
@@ -1106,33 +1106,33 @@ _mm_set_epi8(char b15, char b14, char b13, char b12, char b11, char b10, char b9
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_set1_epi64x(long long q)
+_mm_set1_epi64x(long long __q)
{
- return (__m128i){ q, q };
+ return (__m128i){ __q, __q };
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_set1_epi64(__m64 q)
+_mm_set1_epi64(__m64 __q)
{
- return (__m128i){ (long long)q, (long long)q };
+ return (__m128i){ (long long)__q, (long long)__q };
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_set1_epi32(int i)
+_mm_set1_epi32(int __i)
{
- return (__m128i)(__v4si){ i, i, i, i };
+ return (__m128i)(__v4si){ __i, __i, __i, __i };
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_set1_epi16(short w)
+_mm_set1_epi16(short __w)
{
- return (__m128i)(__v8hi){ w, w, w, w, w, w, w, w };
+ return (__m128i)(__v8hi){ __w, __w, __w, __w, __w, __w, __w, __w };
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_set1_epi8(char b)
+_mm_set1_epi8(char __b)
{
- return (__m128i)(__v16qi){ b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b };
+ return (__m128i)(__v16qi){ __b, __b, __b, __b, __b, __b, __b, __b, __b, __b, __b, __b, __b, __b, __b, __b };
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
@@ -1166,54 +1166,54 @@ _mm_setzero_si128(void)
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_store_si128(__m128i *p, __m128i b)
+_mm_store_si128(__m128i *__p, __m128i __b)
{
- *p = b;
+ *__p = __b;
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_storeu_si128(__m128i *p, __m128i b)
+_mm_storeu_si128(__m128i *__p, __m128i __b)
{
- __builtin_ia32_storedqu((char *)p, (__v16qi)b);
+ __builtin_ia32_storedqu((char *)__p, (__v16qi)__b);
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_maskmoveu_si128(__m128i d, __m128i n, char *p)
+_mm_maskmoveu_si128(__m128i __d, __m128i __n, char *__p)
{
- __builtin_ia32_maskmovdqu((__v16qi)d, (__v16qi)n, p);
+ __builtin_ia32_maskmovdqu((__v16qi)__d, (__v16qi)__n, __p);
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_storel_epi64(__m128i *p, __m128i a)
+_mm_storel_epi64(__m128i *__p, __m128i __a)
{
struct __mm_storel_epi64_struct {
- long long u;
+ long long __u;
} __attribute__((__packed__, __may_alias__));
- ((struct __mm_storel_epi64_struct*)p)->u = a[0];
+ ((struct __mm_storel_epi64_struct*)__p)->__u = __a[0];
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_stream_pd(double *p, __m128d a)
+_mm_stream_pd(double *__p, __m128d __a)
{
- __builtin_ia32_movntpd(p, a);
+ __builtin_ia32_movntpd(__p, __a);
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_stream_si128(__m128i *p, __m128i a)
+_mm_stream_si128(__m128i *__p, __m128i __a)
{
- __builtin_ia32_movntdq(p, a);
+ __builtin_ia32_movntdq(__p, __a);
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_stream_si32(int *p, int a)
+_mm_stream_si32(int *__p, int __a)
{
- __builtin_ia32_movnti(p, a);
+ __builtin_ia32_movnti(__p, __a);
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_clflush(void const *p)
+_mm_clflush(void const *__p)
{
- __builtin_ia32_clflush(p);
+ __builtin_ia32_clflush(__p);
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
@@ -1229,42 +1229,42 @@ _mm_mfence(void)
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_packs_epi16(__m128i a, __m128i b)
+_mm_packs_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_packsswb128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_packsswb128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_packs_epi32(__m128i a, __m128i b)
+_mm_packs_epi32(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_packssdw128((__v4si)a, (__v4si)b);
+ return (__m128i)__builtin_ia32_packssdw128((__v4si)__a, (__v4si)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_packus_epi16(__m128i a, __m128i b)
+_mm_packus_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_packuswb128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_packuswb128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_extract_epi16(__m128i a, int imm)
+_mm_extract_epi16(__m128i __a, int __imm)
{
- __v8hi b = (__v8hi)a;
- return (unsigned short)b[imm];
+ __v8hi __b = (__v8hi)__a;
+ return (unsigned short)__b[__imm];
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_insert_epi16(__m128i a, int b, int imm)
+_mm_insert_epi16(__m128i __a, int __b, int __imm)
{
- __v8hi c = (__v8hi)a;
- c[imm & 7] = b;
- return (__m128i)c;
+ __v8hi __c = (__v8hi)__a;
+ __c[__imm & 7] = __b;
+ return (__m128i)__c;
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_movemask_epi8(__m128i a)
+_mm_movemask_epi8(__m128i __a)
{
- return __builtin_ia32_pmovmskb128((__v16qi)a);
+ return __builtin_ia32_pmovmskb128((__v16qi)__a);
}
#define _mm_shuffle_epi32(a, imm) __extension__ ({ \
@@ -1290,87 +1290,87 @@ _mm_movemask_epi8(__m128i a)
4 + (((imm) & 0xc0) >> 6)); })
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_unpackhi_epi8(__m128i a, __m128i b)
+_mm_unpackhi_epi8(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_shufflevector((__v16qi)a, (__v16qi)b, 8, 16+8, 9, 16+9, 10, 16+10, 11, 16+11, 12, 16+12, 13, 16+13, 14, 16+14, 15, 16+15);
+ return (__m128i)__builtin_shufflevector((__v16qi)__a, (__v16qi)__b, 8, 16+8, 9, 16+9, 10, 16+10, 11, 16+11, 12, 16+12, 13, 16+13, 14, 16+14, 15, 16+15);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_unpackhi_epi16(__m128i a, __m128i b)
+_mm_unpackhi_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_shufflevector((__v8hi)a, (__v8hi)b, 4, 8+4, 5, 8+5, 6, 8+6, 7, 8+7);
+ return (__m128i)__builtin_shufflevector((__v8hi)__a, (__v8hi)__b, 4, 8+4, 5, 8+5, 6, 8+6, 7, 8+7);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_unpackhi_epi32(__m128i a, __m128i b)
+_mm_unpackhi_epi32(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_shufflevector((__v4si)a, (__v4si)b, 2, 4+2, 3, 4+3);
+ return (__m128i)__builtin_shufflevector((__v4si)__a, (__v4si)__b, 2, 4+2, 3, 4+3);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_unpackhi_epi64(__m128i a, __m128i b)
+_mm_unpackhi_epi64(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_shufflevector(a, b, 1, 2+1);
+ return (__m128i)__builtin_shufflevector(__a, __b, 1, 2+1);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_unpacklo_epi8(__m128i a, __m128i b)
+_mm_unpacklo_epi8(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_shufflevector((__v16qi)a, (__v16qi)b, 0, 16+0, 1, 16+1, 2, 16+2, 3, 16+3, 4, 16+4, 5, 16+5, 6, 16+6, 7, 16+7);
+ return (__m128i)__builtin_shufflevector((__v16qi)__a, (__v16qi)__b, 0, 16+0, 1, 16+1, 2, 16+2, 3, 16+3, 4, 16+4, 5, 16+5, 6, 16+6, 7, 16+7);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_unpacklo_epi16(__m128i a, __m128i b)
+_mm_unpacklo_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_shufflevector((__v8hi)a, (__v8hi)b, 0, 8+0, 1, 8+1, 2, 8+2, 3, 8+3);
+ return (__m128i)__builtin_shufflevector((__v8hi)__a, (__v8hi)__b, 0, 8+0, 1, 8+1, 2, 8+2, 3, 8+3);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_unpacklo_epi32(__m128i a, __m128i b)
+_mm_unpacklo_epi32(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_shufflevector((__v4si)a, (__v4si)b, 0, 4+0, 1, 4+1);
+ return (__m128i)__builtin_shufflevector((__v4si)__a, (__v4si)__b, 0, 4+0, 1, 4+1);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_unpacklo_epi64(__m128i a, __m128i b)
+_mm_unpacklo_epi64(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_shufflevector(a, b, 0, 2+0);
+ return (__m128i)__builtin_shufflevector(__a, __b, 0, 2+0);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_movepi64_pi64(__m128i a)
+_mm_movepi64_pi64(__m128i __a)
{
- return (__m64)a[0];
+ return (__m64)__a[0];
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_movpi64_pi64(__m64 a)
+_mm_movpi64_pi64(__m64 __a)
{
- return (__m128i){ (long long)a, 0 };
+ return (__m128i){ (long long)__a, 0 };
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_move_epi64(__m128i a)
+_mm_move_epi64(__m128i __a)
{
- return __builtin_shufflevector(a, (__m128i){ 0 }, 0, 2);
+ return __builtin_shufflevector(__a, (__m128i){ 0 }, 0, 2);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_unpackhi_pd(__m128d a, __m128d b)
+_mm_unpackhi_pd(__m128d __a, __m128d __b)
{
- return __builtin_shufflevector(a, b, 1, 2+1);
+ return __builtin_shufflevector(__a, __b, 1, 2+1);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_unpacklo_pd(__m128d a, __m128d b)
+_mm_unpacklo_pd(__m128d __a, __m128d __b)
{
- return __builtin_shufflevector(a, b, 0, 2+0);
+ return __builtin_shufflevector(__a, __b, 0, 2+0);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_movemask_pd(__m128d a)
+_mm_movemask_pd(__m128d __a)
{
- return __builtin_ia32_movmskpd(a);
+ return __builtin_ia32_movmskpd(__a);
}
#define _mm_shuffle_pd(a, b, i) __extension__ ({ \
@@ -1379,39 +1379,39 @@ _mm_movemask_pd(__m128d a)
__builtin_shufflevector(__a, __b, (i) & 1, (((i) & 2) >> 1) + 2); })
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_castpd_ps(__m128d in)
+_mm_castpd_ps(__m128d __in)
{
- return (__m128)in;
+ return (__m128)__in;
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_castpd_si128(__m128d in)
+_mm_castpd_si128(__m128d __in)
{
- return (__m128i)in;
+ return (__m128i)__in;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_castps_pd(__m128 in)
+_mm_castps_pd(__m128 __in)
{
- return (__m128d)in;
+ return (__m128d)__in;
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_castps_si128(__m128 in)
+_mm_castps_si128(__m128 __in)
{
- return (__m128i)in;
+ return (__m128i)__in;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_castsi128_ps(__m128i in)
+_mm_castsi128_ps(__m128i __in)
{
- return (__m128)in;
+ return (__m128)__in;
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_castsi128_pd(__m128i in)
+_mm_castsi128_pd(__m128i __in)
{
- return (__m128d)in;
+ return (__m128d)__in;
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
diff --git a/lib/Headers/f16cintrin.h b/lib/Headers/f16cintrin.h
index 2c96952..a6d7812 100644
--- a/lib/Headers/f16cintrin.h
+++ b/lib/Headers/f16cintrin.h
@@ -1,6 +1,6 @@
/*===---- f16cintrin.h - F16C intrinsics ---------------------------------===
*
- * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * Permission is hereby granted, free of charge, to any person obtaining __a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
@@ -44,15 +44,15 @@ typedef float __m256 __attribute__ ((__vector_size__ (32)));
(__m128i)__builtin_ia32_vcvtps2ph256((__v8sf)__a, (imm)); })
static __inline __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtph_ps(__m128i a)
+_mm_cvtph_ps(__m128i __a)
{
- return (__m128)__builtin_ia32_vcvtph2ps((__v8hi)a);
+ return (__m128)__builtin_ia32_vcvtph2ps((__v8hi)__a);
}
static __inline __m256 __attribute__((__always_inline__, __nodebug__))
-_mm256_cvtph_ps(__m128i a)
+_mm256_cvtph_ps(__m128i __a)
{
- return (__m256)__builtin_ia32_vcvtph2ps256((__v8hi)a);
+ return (__m256)__builtin_ia32_vcvtph2ps256((__v8hi)__a);
}
#endif /* __F16CINTRIN_H */
diff --git a/lib/Headers/immintrin.h b/lib/Headers/immintrin.h
index cd733bf..fea7c3b 100644
--- a/lib/Headers/immintrin.h
+++ b/lib/Headers/immintrin.h
@@ -102,4 +102,13 @@ _rdrand64_step(unsigned long long *__p)
#include <rtmintrin.h>
#endif
+/* FIXME: check __HLE__ as well when HLE is supported. */
+#if defined (__RTM__)
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
+_xtest(void)
+{
+ return __builtin_ia32_xtest();
+}
+#endif
+
#endif /* __IMMINTRIN_H */
diff --git a/lib/Headers/mm3dnow.h b/lib/Headers/mm3dnow.h
index d5236f8..5242d99 100644
--- a/lib/Headers/mm3dnow.h
+++ b/lib/Headers/mm3dnow.h
@@ -25,6 +25,7 @@
#define _MM3DNOW_H_INCLUDED
#include <mmintrin.h>
+#include <prfchwintrin.h>
typedef float __v2sf __attribute__((__vector_size__(8)));
diff --git a/lib/Headers/mm_malloc.h b/lib/Headers/mm_malloc.h
index 5fa1761..305afd3 100644
--- a/lib/Headers/mm_malloc.h
+++ b/lib/Headers/mm_malloc.h
@@ -30,45 +30,45 @@
#include <malloc.h>
#else
#ifndef __cplusplus
-extern int posix_memalign(void **memptr, size_t alignment, size_t size);
+extern int posix_memalign(void **__memptr, size_t __alignment, size_t __size);
#else
// Some systems (e.g. those with GNU libc) declare posix_memalign with an
// exception specifier. Via an "egregious workaround" in
// Sema::CheckEquivalentExceptionSpec, Clang accepts the following as a valid
// redeclaration of glibc's declaration.
-extern "C" int posix_memalign(void **memptr, size_t alignment, size_t size);
+extern "C" int posix_memalign(void **__memptr, size_t __alignment, size_t __size);
#endif
#endif
#if !(defined(_WIN32) && defined(_mm_malloc))
static __inline__ void *__attribute__((__always_inline__, __nodebug__,
__malloc__))
-_mm_malloc(size_t size, size_t align)
+_mm_malloc(size_t __size, size_t __align)
{
- if (align == 1) {
- return malloc(size);
+ if (__align == 1) {
+ return malloc(__size);
}
- if (!(align & (align - 1)) && align < sizeof(void *))
- align = sizeof(void *);
+ if (!(__align & (__align - 1)) && __align < sizeof(void *))
+ __align = sizeof(void *);
- void *mallocedMemory;
+ void *__mallocedMemory;
#if defined(__MINGW32__)
- mallocedMemory = __mingw_aligned_malloc(size, align);
+ __mallocedMemory = __mingw_aligned_malloc(__size, __align);
#elif defined(_WIN32)
- mallocedMemory = _aligned_malloc(size, align);
+ __mallocedMemory = _aligned_malloc(__size, __align);
#else
- if (posix_memalign(&mallocedMemory, align, size))
+ if (posix_memalign(&__mallocedMemory, __align, __size))
return 0;
#endif
- return mallocedMemory;
+ return __mallocedMemory;
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_free(void *p)
+_mm_free(void *__p)
{
- free(p);
+ free(__p);
}
#endif
diff --git a/lib/Headers/module.map b/lib/Headers/module.map
index b24bccc..aa219cb 100644
--- a/lib/Headers/module.map
+++ b/lib/Headers/module.map
@@ -17,6 +17,7 @@ module _Builtin_intrinsics [system] {
}
explicit module cpuid {
+ requires x86
header "cpuid.h"
}
@@ -33,7 +34,6 @@ module _Builtin_intrinsics [system] {
explicit module sse {
requires sse
export mmx
- export * // note: for hackish <emmintrin.h> dependency
header "xmmintrin.h"
}
diff --git a/lib/Headers/pmmintrin.h b/lib/Headers/pmmintrin.h
index 5f9b097..6f1fc32 100644
--- a/lib/Headers/pmmintrin.h
+++ b/lib/Headers/pmmintrin.h
@@ -31,65 +31,65 @@
#include <emmintrin.h>
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_lddqu_si128(__m128i const *p)
+_mm_lddqu_si128(__m128i const *__p)
{
- return (__m128i)__builtin_ia32_lddqu((char const *)p);
+ return (__m128i)__builtin_ia32_lddqu((char const *)__p);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_addsub_ps(__m128 a, __m128 b)
+_mm_addsub_ps(__m128 __a, __m128 __b)
{
- return __builtin_ia32_addsubps(a, b);
+ return __builtin_ia32_addsubps(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_hadd_ps(__m128 a, __m128 b)
+_mm_hadd_ps(__m128 __a, __m128 __b)
{
- return __builtin_ia32_haddps(a, b);
+ return __builtin_ia32_haddps(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_hsub_ps(__m128 a, __m128 b)
+_mm_hsub_ps(__m128 __a, __m128 __b)
{
- return __builtin_ia32_hsubps(a, b);
+ return __builtin_ia32_hsubps(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_movehdup_ps(__m128 a)
+_mm_movehdup_ps(__m128 __a)
{
- return __builtin_shufflevector(a, a, 1, 1, 3, 3);
+ return __builtin_shufflevector(__a, __a, 1, 1, 3, 3);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_moveldup_ps(__m128 a)
+_mm_moveldup_ps(__m128 __a)
{
- return __builtin_shufflevector(a, a, 0, 0, 2, 2);
+ return __builtin_shufflevector(__a, __a, 0, 0, 2, 2);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_addsub_pd(__m128d a, __m128d b)
+_mm_addsub_pd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_addsubpd(a, b);
+ return __builtin_ia32_addsubpd(__a, __b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_hadd_pd(__m128d a, __m128d b)
+_mm_hadd_pd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_haddpd(a, b);
+ return __builtin_ia32_haddpd(__a, __b);
}
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_hsub_pd(__m128d a, __m128d b)
+_mm_hsub_pd(__m128d __a, __m128d __b)
{
- return __builtin_ia32_hsubpd(a, b);
+ return __builtin_ia32_hsubpd(__a, __b);
}
#define _mm_loaddup_pd(dp) _mm_load1_pd(dp)
static __inline__ __m128d __attribute__((__always_inline__, __nodebug__))
-_mm_movedup_pd(__m128d a)
+_mm_movedup_pd(__m128d __a)
{
- return __builtin_shufflevector(a, a, 0, 0);
+ return __builtin_shufflevector(__a, __a, 0, 0);
}
#define _MM_DENORMALS_ZERO_ON (0x0040)
@@ -101,15 +101,15 @@ _mm_movedup_pd(__m128d a)
#define _MM_SET_DENORMALS_ZERO_MODE(x) (_mm_setcsr((_mm_getcsr() & ~_MM_DENORMALS_ZERO_MASK) | (x)))
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_monitor(void const *p, unsigned extensions, unsigned hints)
+_mm_monitor(void const *__p, unsigned __extensions, unsigned __hints)
{
- __builtin_ia32_monitor((void *)p, extensions, hints);
+ __builtin_ia32_monitor((void *)__p, __extensions, __hints);
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_mwait(unsigned extensions, unsigned hints)
+_mm_mwait(unsigned __extensions, unsigned __hints)
{
- __builtin_ia32_mwait(extensions, hints);
+ __builtin_ia32_mwait(__extensions, __hints);
}
#endif /* __SSE3__ */
diff --git a/lib/Headers/prfchwintrin.h b/lib/Headers/prfchwintrin.h
new file mode 100644
index 0000000..2d529c6
--- /dev/null
+++ b/lib/Headers/prfchwintrin.h
@@ -0,0 +1,34 @@
+/*===---- prfchwintrin.h - PREFETCHW intrinsic -----------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#if !defined(__X86INTRIN_H) && !defined(_MM3DNOW_H_INCLUDED)
+#error "Never use <prfchwintrin.h> directly; include <x86intrin.h> or <mm3dnow.h> instead."
+#endif
+
+#if defined(__PRFCHW__) || defined(__3dNOW__)
+static __inline__ void __attribute__((__always_inline__, __nodebug__))
+_m_prefetchw(void *__P)
+{
+ __builtin_prefetch (__P, 1, 3 /* _MM_HINT_T0 */);
+}
+#endif
diff --git a/lib/Headers/rdseedintrin.h b/lib/Headers/rdseedintrin.h
new file mode 100644
index 0000000..54aabd1
--- /dev/null
+++ b/lib/Headers/rdseedintrin.h
@@ -0,0 +1,48 @@
+/*===---- rdseedintrin.h - RDSEED intrinsics -------------------------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef __X86INTRIN_H
+#error "Never use <rdseedintrin.h> directly; include <x86intrin.h> instead."
+#endif
+
+#ifdef __RDSEED__
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
+_rdseed16_step(unsigned short *__p)
+{
+ return __builtin_ia32_rdseed16_step(__p);
+}
+
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
+_rdseed32_step(unsigned int *__p)
+{
+ return __builtin_ia32_rdseed32_step(__p);
+}
+
+#ifdef __x86_64__
+static __inline__ int __attribute__((__always_inline__, __nodebug__))
+_rdseed64_step(unsigned long long *__p)
+{
+ return __builtin_ia32_rdseed64_step(__p);
+}
+#endif
+#endif /* __RDSEED__ */
diff --git a/lib/Headers/smmintrin.h b/lib/Headers/smmintrin.h
index 2fab50e..498f6f0 100644
--- a/lib/Headers/smmintrin.h
+++ b/lib/Headers/smmintrin.h
@@ -195,10 +195,10 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2)
/* SSE4 Insertion and Extraction from XMM Register Instructions. */
#define _mm_insert_ps(X, Y, N) __builtin_ia32_insertps128((X), (Y), (N))
#define _mm_extract_ps(X, N) (__extension__ \
- ({ union { int i; float f; } __t; \
+ ({ union { int __i; float __f; } __t; \
__v4sf __a = (__v4sf)(X); \
- __t.f = __a[N]; \
- __t.i;}))
+ __t.__f = __a[N]; \
+ __t.__i;}))
/* Miscellaneous insert and extract macros. */
/* Extract a single-precision float from X at index N into D. */
diff --git a/lib/Headers/stdalign.h b/lib/Headers/stdalign.h
index e7fbfa0..3738d12 100644
--- a/lib/Headers/stdalign.h
+++ b/lib/Headers/stdalign.h
@@ -24,7 +24,12 @@
#ifndef __STDALIGN_H
#define __STDALIGN_H
+#ifndef __cplusplus
#define alignas _Alignas
+#define alignof _Alignof
+#endif
+
#define __alignas_is_defined 1
+#define __alignof_is_defined 1
#endif /* __STDALIGN_H */
diff --git a/lib/Headers/stddef.h b/lib/Headers/stddef.h
index eb919b5..5296224 100644
--- a/lib/Headers/stddef.h
+++ b/lib/Headers/stddef.h
@@ -26,17 +26,28 @@
#ifndef __STDDEF_H
#define __STDDEF_H
-#ifndef _PTRDIFF_T
+#if !defined(_PTRDIFF_T) || __has_feature(modules)
+/* Always define ptrdiff_t when modules are available. */
+#if !__has_feature(modules)
#define _PTRDIFF_T
-typedef __typeof__(((int*)0)-((int*)0)) ptrdiff_t;
#endif
-#ifndef _SIZE_T
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+#endif
+
+#if !defined(_SIZE_T) || __has_feature(modules)
+/* Always define size_t when modules are available. */
+#if !__has_feature(modules)
#define _SIZE_T
-typedef __typeof__(sizeof(int)) size_t;
#endif
+typedef __SIZE_TYPE__ size_t;
+#endif
+
#ifndef __cplusplus
-#ifndef _WCHAR_T
+/* Always define wchar_t when modules are available. */
+#if !defined(_WCHAR_T) || __has_feature(modules)
+#if !__has_feature(modules)
#define _WCHAR_T
+#endif
typedef __WCHAR_TYPE__ wchar_t;
#endif
#endif
@@ -66,9 +77,12 @@ using ::std::nullptr_t;
/* Some C libraries expect to see a wint_t here. Others (notably MinGW) will use
__WINT_TYPE__ directly; accommodate both by requiring __need_wint_t */
#if defined(__need_wint_t)
-#if !defined(_WINT_T)
+/* Always define wint_t when modules are available. */
+#if !defined(_WINT_T) || __has_feature(modules)
+#if !__has_feature(modules)
#define _WINT_T
+#endif
typedef __WINT_TYPE__ wint_t;
-#endif /* _WINT_T */
+#endif
#undef __need_wint_t
#endif /* __need_wint_t */
diff --git a/lib/Headers/stdnoreturn.h b/lib/Headers/stdnoreturn.h
new file mode 100644
index 0000000..a7a301d
--- /dev/null
+++ b/lib/Headers/stdnoreturn.h
@@ -0,0 +1,30 @@
+/*===---- stdnoreturn.h - Standard header for noreturn macro ---------------===
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *===-----------------------------------------------------------------------===
+ */
+
+#ifndef __STDNORETURN_H
+#define __STDNORETURN_H
+
+#define noreturn _Noreturn
+#define __noreturn_is_defined 1
+
+#endif /* __STDNORETURN_H */
diff --git a/lib/Headers/tmmintrin.h b/lib/Headers/tmmintrin.h
index a62c6cc..4238f5b 100644
--- a/lib/Headers/tmmintrin.h
+++ b/lib/Headers/tmmintrin.h
@@ -31,39 +31,39 @@
#include <pmmintrin.h>
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_abs_pi8(__m64 a)
+_mm_abs_pi8(__m64 __a)
{
- return (__m64)__builtin_ia32_pabsb((__v8qi)a);
+ return (__m64)__builtin_ia32_pabsb((__v8qi)__a);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_abs_epi8(__m128i a)
+_mm_abs_epi8(__m128i __a)
{
- return (__m128i)__builtin_ia32_pabsb128((__v16qi)a);
+ return (__m128i)__builtin_ia32_pabsb128((__v16qi)__a);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_abs_pi16(__m64 a)
+_mm_abs_pi16(__m64 __a)
{
- return (__m64)__builtin_ia32_pabsw((__v4hi)a);
+ return (__m64)__builtin_ia32_pabsw((__v4hi)__a);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_abs_epi16(__m128i a)
+_mm_abs_epi16(__m128i __a)
{
- return (__m128i)__builtin_ia32_pabsw128((__v8hi)a);
+ return (__m128i)__builtin_ia32_pabsw128((__v8hi)__a);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_abs_pi32(__m64 a)
+_mm_abs_pi32(__m64 __a)
{
- return (__m64)__builtin_ia32_pabsd((__v2si)a);
+ return (__m64)__builtin_ia32_pabsd((__v2si)__a);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_abs_epi32(__m128i a)
+_mm_abs_epi32(__m128i __a)
{
- return (__m128i)__builtin_ia32_pabsd128((__v4si)a);
+ return (__m128i)__builtin_ia32_pabsd128((__v4si)__a);
}
#define _mm_alignr_epi8(a, b, n) __extension__ ({ \
@@ -77,147 +77,147 @@ _mm_abs_epi32(__m128i a)
(__m64)__builtin_ia32_palignr((__v8qi)__a, (__v8qi)__b, (n)); })
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_hadd_epi16(__m128i a, __m128i b)
+_mm_hadd_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_phaddw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_phaddw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_hadd_epi32(__m128i a, __m128i b)
+_mm_hadd_epi32(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_phaddd128((__v4si)a, (__v4si)b);
+ return (__m128i)__builtin_ia32_phaddd128((__v4si)__a, (__v4si)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_hadd_pi16(__m64 a, __m64 b)
+_mm_hadd_pi16(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_phaddw((__v4hi)a, (__v4hi)b);
+ return (__m64)__builtin_ia32_phaddw((__v4hi)__a, (__v4hi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_hadd_pi32(__m64 a, __m64 b)
+_mm_hadd_pi32(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_phaddd((__v2si)a, (__v2si)b);
+ return (__m64)__builtin_ia32_phaddd((__v2si)__a, (__v2si)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_hadds_epi16(__m128i a, __m128i b)
+_mm_hadds_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_phaddsw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_phaddsw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_hadds_pi16(__m64 a, __m64 b)
+_mm_hadds_pi16(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_phaddsw((__v4hi)a, (__v4hi)b);
+ return (__m64)__builtin_ia32_phaddsw((__v4hi)__a, (__v4hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_hsub_epi16(__m128i a, __m128i b)
+_mm_hsub_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_phsubw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_phsubw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_hsub_epi32(__m128i a, __m128i b)
+_mm_hsub_epi32(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_phsubd128((__v4si)a, (__v4si)b);
+ return (__m128i)__builtin_ia32_phsubd128((__v4si)__a, (__v4si)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_hsub_pi16(__m64 a, __m64 b)
+_mm_hsub_pi16(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_phsubw((__v4hi)a, (__v4hi)b);
+ return (__m64)__builtin_ia32_phsubw((__v4hi)__a, (__v4hi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_hsub_pi32(__m64 a, __m64 b)
+_mm_hsub_pi32(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_phsubd((__v2si)a, (__v2si)b);
+ return (__m64)__builtin_ia32_phsubd((__v2si)__a, (__v2si)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_hsubs_epi16(__m128i a, __m128i b)
+_mm_hsubs_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_phsubsw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_phsubsw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_hsubs_pi16(__m64 a, __m64 b)
+_mm_hsubs_pi16(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_phsubsw((__v4hi)a, (__v4hi)b);
+ return (__m64)__builtin_ia32_phsubsw((__v4hi)__a, (__v4hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_maddubs_epi16(__m128i a, __m128i b)
+_mm_maddubs_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pmaddubsw128((__v16qi)a, (__v16qi)b);
+ return (__m128i)__builtin_ia32_pmaddubsw128((__v16qi)__a, (__v16qi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_maddubs_pi16(__m64 a, __m64 b)
+_mm_maddubs_pi16(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_pmaddubsw((__v8qi)a, (__v8qi)b);
+ return (__m64)__builtin_ia32_pmaddubsw((__v8qi)__a, (__v8qi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_mulhrs_epi16(__m128i a, __m128i b)
+_mm_mulhrs_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pmulhrsw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_pmulhrsw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_mulhrs_pi16(__m64 a, __m64 b)
+_mm_mulhrs_pi16(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_pmulhrsw((__v4hi)a, (__v4hi)b);
+ return (__m64)__builtin_ia32_pmulhrsw((__v4hi)__a, (__v4hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_shuffle_epi8(__m128i a, __m128i b)
+_mm_shuffle_epi8(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_pshufb128((__v16qi)a, (__v16qi)b);
+ return (__m128i)__builtin_ia32_pshufb128((__v16qi)__a, (__v16qi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_shuffle_pi8(__m64 a, __m64 b)
+_mm_shuffle_pi8(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_pshufb((__v8qi)a, (__v8qi)b);
+ return (__m64)__builtin_ia32_pshufb((__v8qi)__a, (__v8qi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_sign_epi8(__m128i a, __m128i b)
+_mm_sign_epi8(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_psignb128((__v16qi)a, (__v16qi)b);
+ return (__m128i)__builtin_ia32_psignb128((__v16qi)__a, (__v16qi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_sign_epi16(__m128i a, __m128i b)
+_mm_sign_epi16(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_psignw128((__v8hi)a, (__v8hi)b);
+ return (__m128i)__builtin_ia32_psignw128((__v8hi)__a, (__v8hi)__b);
}
static __inline__ __m128i __attribute__((__always_inline__, __nodebug__))
-_mm_sign_epi32(__m128i a, __m128i b)
+_mm_sign_epi32(__m128i __a, __m128i __b)
{
- return (__m128i)__builtin_ia32_psignd128((__v4si)a, (__v4si)b);
+ return (__m128i)__builtin_ia32_psignd128((__v4si)__a, (__v4si)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_sign_pi8(__m64 a, __m64 b)
+_mm_sign_pi8(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_psignb((__v8qi)a, (__v8qi)b);
+ return (__m64)__builtin_ia32_psignb((__v8qi)__a, (__v8qi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_sign_pi16(__m64 a, __m64 b)
+_mm_sign_pi16(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_psignw((__v4hi)a, (__v4hi)b);
+ return (__m64)__builtin_ia32_psignw((__v4hi)__a, (__v4hi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_sign_pi32(__m64 a, __m64 b)
+_mm_sign_pi32(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_psignd((__v2si)a, (__v2si)b);
+ return (__m64)__builtin_ia32_psignd((__v2si)__a, (__v2si)__b);
}
#endif /* __SSSE3__ */
diff --git a/lib/Headers/unwind.h b/lib/Headers/unwind.h
index 6520b83..e94fd70 100644
--- a/lib/Headers/unwind.h
+++ b/lib/Headers/unwind.h
@@ -23,6 +23,9 @@
/* See "Data Definitions for libgcc_s" in the Linux Standard Base.*/
+#ifndef __CLANG_UNWIND_H
+#define __CLANG_UNWIND_H
+
#if __has_include_next(<unwind.h>)
/* Darwin and libunwind provide an unwind.h. If that's available, use
* it. libunwind wraps some of its definitions in #ifdef _GNU_SOURCE,
@@ -59,7 +62,9 @@ extern "C" {
/* It is a bit strange for a header to play with the visibility of the
symbols it declares, but this matches gcc's behavior and some programs
depend on it */
+#ifndef HIDE_EXPORTS
#pragma GCC visibility push(default)
+#endif
struct _Unwind_Context;
typedef enum {
@@ -79,46 +84,50 @@ typedef enum {
#ifdef __arm__
-typedef enum {
- _UVRSC_CORE = 0, /* integer register */
- _UVRSC_VFP = 1, /* vfp */
- _UVRSC_WMMXD = 3, /* Intel WMMX data register */
- _UVRSC_WMMXC = 4 /* Intel WMMX control register */
-} _Unwind_VRS_RegClass;
-
-typedef enum {
- _UVRSD_UINT32 = 0,
- _UVRSD_VFPX = 1,
- _UVRSD_UINT64 = 3,
- _UVRSD_FLOAT = 4,
- _UVRSD_DOUBLE = 5
-} _Unwind_VRS_DataRepresentation;
-
-typedef enum {
- _UVRSR_OK = 0,
- _UVRSR_NOT_IMPLEMENTED = 1,
- _UVRSR_FAILED = 2
-} _Unwind_VRS_Result;
-
-_Unwind_VRS_Result _Unwind_VRS_Get(struct _Unwind_Context *context,
- _Unwind_VRS_RegClass regclass,
- uint32_t regno,
- _Unwind_VRS_DataRepresentation representation,
- void *valuep);
+typedef enum {
+ _UVRSC_CORE = 0, /* integer register */
+ _UVRSC_VFP = 1, /* vfp */
+ _UVRSC_WMMXD = 3, /* Intel WMMX data register */
+ _UVRSC_WMMXC = 4 /* Intel WMMX control register */
+} _Unwind_VRS_RegClass;
+
+typedef enum {
+ _UVRSD_UINT32 = 0,
+ _UVRSD_VFPX = 1,
+ _UVRSD_UINT64 = 3,
+ _UVRSD_FLOAT = 4,
+ _UVRSD_DOUBLE = 5
+} _Unwind_VRS_DataRepresentation;
+
+typedef enum {
+ _UVRSR_OK = 0,
+ _UVRSR_NOT_IMPLEMENTED = 1,
+ _UVRSR_FAILED = 2
+} _Unwind_VRS_Result;
+
+_Unwind_VRS_Result _Unwind_VRS_Get(struct _Unwind_Context *__context,
+ _Unwind_VRS_RegClass __regclass,
+ uint32_t __regno,
+ _Unwind_VRS_DataRepresentation __representation,
+ void *__valuep);
#else
-uintptr_t _Unwind_GetIP(struct _Unwind_Context* context);
+uintptr_t _Unwind_GetIP(struct _Unwind_Context* __context);
#endif
typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context*, void*);
_Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void*);
+#ifndef HIDE_EXPORTS
#pragma GCC visibility pop
+#endif
#ifdef __cplusplus
}
#endif
#endif
+
+#endif /* __CLANG_UNWIND_H */
diff --git a/lib/Headers/x86intrin.h b/lib/Headers/x86intrin.h
index 68ce106..94fbe2f 100644
--- a/lib/Headers/x86intrin.h
+++ b/lib/Headers/x86intrin.h
@@ -46,6 +46,14 @@
#include <popcntintrin.h>
#endif
+#ifdef __RDSEED__
+#include <rdseedintrin.h>
+#endif
+
+#ifdef __PRFCHW__
+#include <prfchwintrin.h>
+#endif
+
#ifdef __SSE4A__
#include <ammintrin.h>
#endif
diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h
index e2480ec..8c5fc95 100644
--- a/lib/Headers/xmmintrin.h
+++ b/lib/Headers/xmmintrin.h
@@ -41,563 +41,563 @@ typedef float __m128 __attribute__((__vector_size__(16)));
#endif
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_add_ss(__m128 a, __m128 b)
+_mm_add_ss(__m128 __a, __m128 __b)
{
- a[0] += b[0];
- return a;
+ __a[0] += __b[0];
+ return __a;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_add_ps(__m128 a, __m128 b)
+_mm_add_ps(__m128 __a, __m128 __b)
{
- return a + b;
+ return __a + __b;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_sub_ss(__m128 a, __m128 b)
+_mm_sub_ss(__m128 __a, __m128 __b)
{
- a[0] -= b[0];
- return a;
+ __a[0] -= __b[0];
+ return __a;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_sub_ps(__m128 a, __m128 b)
+_mm_sub_ps(__m128 __a, __m128 __b)
{
- return a - b;
+ return __a - __b;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_mul_ss(__m128 a, __m128 b)
+_mm_mul_ss(__m128 __a, __m128 __b)
{
- a[0] *= b[0];
- return a;
+ __a[0] *= __b[0];
+ return __a;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_mul_ps(__m128 a, __m128 b)
+_mm_mul_ps(__m128 __a, __m128 __b)
{
- return a * b;
+ return __a * __b;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_div_ss(__m128 a, __m128 b)
+_mm_div_ss(__m128 __a, __m128 __b)
{
- a[0] /= b[0];
- return a;
+ __a[0] /= __b[0];
+ return __a;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_div_ps(__m128 a, __m128 b)
+_mm_div_ps(__m128 __a, __m128 __b)
{
- return a / b;
+ return __a / __b;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_sqrt_ss(__m128 a)
+_mm_sqrt_ss(__m128 __a)
{
- __m128 c = __builtin_ia32_sqrtss(a);
- return (__m128) { c[0], a[1], a[2], a[3] };
+ __m128 __c = __builtin_ia32_sqrtss(__a);
+ return (__m128) { __c[0], __a[1], __a[2], __a[3] };
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_sqrt_ps(__m128 a)
+_mm_sqrt_ps(__m128 __a)
{
- return __builtin_ia32_sqrtps(a);
+ return __builtin_ia32_sqrtps(__a);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_rcp_ss(__m128 a)
+_mm_rcp_ss(__m128 __a)
{
- __m128 c = __builtin_ia32_rcpss(a);
- return (__m128) { c[0], a[1], a[2], a[3] };
+ __m128 __c = __builtin_ia32_rcpss(__a);
+ return (__m128) { __c[0], __a[1], __a[2], __a[3] };
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_rcp_ps(__m128 a)
+_mm_rcp_ps(__m128 __a)
{
- return __builtin_ia32_rcpps(a);
+ return __builtin_ia32_rcpps(__a);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_rsqrt_ss(__m128 a)
+_mm_rsqrt_ss(__m128 __a)
{
- __m128 c = __builtin_ia32_rsqrtss(a);
- return (__m128) { c[0], a[1], a[2], a[3] };
+ __m128 __c = __builtin_ia32_rsqrtss(__a);
+ return (__m128) { __c[0], __a[1], __a[2], __a[3] };
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_rsqrt_ps(__m128 a)
+_mm_rsqrt_ps(__m128 __a)
{
- return __builtin_ia32_rsqrtps(a);
+ return __builtin_ia32_rsqrtps(__a);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_min_ss(__m128 a, __m128 b)
+_mm_min_ss(__m128 __a, __m128 __b)
{
- return __builtin_ia32_minss(a, b);
+ return __builtin_ia32_minss(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_min_ps(__m128 a, __m128 b)
+_mm_min_ps(__m128 __a, __m128 __b)
{
- return __builtin_ia32_minps(a, b);
+ return __builtin_ia32_minps(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_max_ss(__m128 a, __m128 b)
+_mm_max_ss(__m128 __a, __m128 __b)
{
- return __builtin_ia32_maxss(a, b);
+ return __builtin_ia32_maxss(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_max_ps(__m128 a, __m128 b)
+_mm_max_ps(__m128 __a, __m128 __b)
{
- return __builtin_ia32_maxps(a, b);
+ return __builtin_ia32_maxps(__a, __b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_and_ps(__m128 a, __m128 b)
+_mm_and_ps(__m128 __a, __m128 __b)
{
- return (__m128)((__v4si)a & (__v4si)b);
+ return (__m128)((__v4si)__a & (__v4si)__b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_andnot_ps(__m128 a, __m128 b)
+_mm_andnot_ps(__m128 __a, __m128 __b)
{
- return (__m128)(~(__v4si)a & (__v4si)b);
+ return (__m128)(~(__v4si)__a & (__v4si)__b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_or_ps(__m128 a, __m128 b)
+_mm_or_ps(__m128 __a, __m128 __b)
{
- return (__m128)((__v4si)a | (__v4si)b);
+ return (__m128)((__v4si)__a | (__v4si)__b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_xor_ps(__m128 a, __m128 b)
+_mm_xor_ps(__m128 __a, __m128 __b)
{
- return (__m128)((__v4si)a ^ (__v4si)b);
+ return (__m128)((__v4si)__a ^ (__v4si)__b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpeq_ss(__m128 a, __m128 b)
+_mm_cmpeq_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(a, b, 0);
+ return (__m128)__builtin_ia32_cmpss(__a, __b, 0);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpeq_ps(__m128 a, __m128 b)
+_mm_cmpeq_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(a, b, 0);
+ return (__m128)__builtin_ia32_cmpps(__a, __b, 0);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmplt_ss(__m128 a, __m128 b)
+_mm_cmplt_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(a, b, 1);
+ return (__m128)__builtin_ia32_cmpss(__a, __b, 1);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmplt_ps(__m128 a, __m128 b)
+_mm_cmplt_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(a, b, 1);
+ return (__m128)__builtin_ia32_cmpps(__a, __b, 1);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmple_ss(__m128 a, __m128 b)
+_mm_cmple_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(a, b, 2);
+ return (__m128)__builtin_ia32_cmpss(__a, __b, 2);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmple_ps(__m128 a, __m128 b)
+_mm_cmple_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(a, b, 2);
+ return (__m128)__builtin_ia32_cmpps(__a, __b, 2);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpgt_ss(__m128 a, __m128 b)
+_mm_cmpgt_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(b, a, 1);
+ return (__m128)__builtin_ia32_cmpss(__b, __a, 1);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpgt_ps(__m128 a, __m128 b)
+_mm_cmpgt_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(b, a, 1);
+ return (__m128)__builtin_ia32_cmpps(__b, __a, 1);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpge_ss(__m128 a, __m128 b)
+_mm_cmpge_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(b, a, 2);
+ return (__m128)__builtin_ia32_cmpss(__b, __a, 2);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpge_ps(__m128 a, __m128 b)
+_mm_cmpge_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(b, a, 2);
+ return (__m128)__builtin_ia32_cmpps(__b, __a, 2);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpneq_ss(__m128 a, __m128 b)
+_mm_cmpneq_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(a, b, 4);
+ return (__m128)__builtin_ia32_cmpss(__a, __b, 4);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpneq_ps(__m128 a, __m128 b)
+_mm_cmpneq_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(a, b, 4);
+ return (__m128)__builtin_ia32_cmpps(__a, __b, 4);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpnlt_ss(__m128 a, __m128 b)
+_mm_cmpnlt_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(a, b, 5);
+ return (__m128)__builtin_ia32_cmpss(__a, __b, 5);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpnlt_ps(__m128 a, __m128 b)
+_mm_cmpnlt_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(a, b, 5);
+ return (__m128)__builtin_ia32_cmpps(__a, __b, 5);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpnle_ss(__m128 a, __m128 b)
+_mm_cmpnle_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(a, b, 6);
+ return (__m128)__builtin_ia32_cmpss(__a, __b, 6);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpnle_ps(__m128 a, __m128 b)
+_mm_cmpnle_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(a, b, 6);
+ return (__m128)__builtin_ia32_cmpps(__a, __b, 6);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpngt_ss(__m128 a, __m128 b)
+_mm_cmpngt_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(b, a, 5);
+ return (__m128)__builtin_ia32_cmpss(__b, __a, 5);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpngt_ps(__m128 a, __m128 b)
+_mm_cmpngt_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(b, a, 5);
+ return (__m128)__builtin_ia32_cmpps(__b, __a, 5);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpnge_ss(__m128 a, __m128 b)
+_mm_cmpnge_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(b, a, 6);
+ return (__m128)__builtin_ia32_cmpss(__b, __a, 6);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpnge_ps(__m128 a, __m128 b)
+_mm_cmpnge_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(b, a, 6);
+ return (__m128)__builtin_ia32_cmpps(__b, __a, 6);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpord_ss(__m128 a, __m128 b)
+_mm_cmpord_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(a, b, 7);
+ return (__m128)__builtin_ia32_cmpss(__a, __b, 7);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpord_ps(__m128 a, __m128 b)
+_mm_cmpord_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(a, b, 7);
+ return (__m128)__builtin_ia32_cmpps(__a, __b, 7);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpunord_ss(__m128 a, __m128 b)
+_mm_cmpunord_ss(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpss(a, b, 3);
+ return (__m128)__builtin_ia32_cmpss(__a, __b, 3);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cmpunord_ps(__m128 a, __m128 b)
+_mm_cmpunord_ps(__m128 __a, __m128 __b)
{
- return (__m128)__builtin_ia32_cmpps(a, b, 3);
+ return (__m128)__builtin_ia32_cmpps(__a, __b, 3);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_comieq_ss(__m128 a, __m128 b)
+_mm_comieq_ss(__m128 __a, __m128 __b)
{
- return __builtin_ia32_comieq(a, b);
+ return __builtin_ia32_comieq(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_comilt_ss(__m128 a, __m128 b)
+_mm_comilt_ss(__m128 __a, __m128 __b)
{
- return __builtin_ia32_comilt(a, b);
+ return __builtin_ia32_comilt(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_comile_ss(__m128 a, __m128 b)
+_mm_comile_ss(__m128 __a, __m128 __b)
{
- return __builtin_ia32_comile(a, b);
+ return __builtin_ia32_comile(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_comigt_ss(__m128 a, __m128 b)
+_mm_comigt_ss(__m128 __a, __m128 __b)
{
- return __builtin_ia32_comigt(a, b);
+ return __builtin_ia32_comigt(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_comige_ss(__m128 a, __m128 b)
+_mm_comige_ss(__m128 __a, __m128 __b)
{
- return __builtin_ia32_comige(a, b);
+ return __builtin_ia32_comige(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_comineq_ss(__m128 a, __m128 b)
+_mm_comineq_ss(__m128 __a, __m128 __b)
{
- return __builtin_ia32_comineq(a, b);
+ return __builtin_ia32_comineq(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_ucomieq_ss(__m128 a, __m128 b)
+_mm_ucomieq_ss(__m128 __a, __m128 __b)
{
- return __builtin_ia32_ucomieq(a, b);
+ return __builtin_ia32_ucomieq(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_ucomilt_ss(__m128 a, __m128 b)
+_mm_ucomilt_ss(__m128 __a, __m128 __b)
{
- return __builtin_ia32_ucomilt(a, b);
+ return __builtin_ia32_ucomilt(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_ucomile_ss(__m128 a, __m128 b)
+_mm_ucomile_ss(__m128 __a, __m128 __b)
{
- return __builtin_ia32_ucomile(a, b);
+ return __builtin_ia32_ucomile(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_ucomigt_ss(__m128 a, __m128 b)
+_mm_ucomigt_ss(__m128 __a, __m128 __b)
{
- return __builtin_ia32_ucomigt(a, b);
+ return __builtin_ia32_ucomigt(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_ucomige_ss(__m128 a, __m128 b)
+_mm_ucomige_ss(__m128 __a, __m128 __b)
{
- return __builtin_ia32_ucomige(a, b);
+ return __builtin_ia32_ucomige(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_ucomineq_ss(__m128 a, __m128 b)
+_mm_ucomineq_ss(__m128 __a, __m128 __b)
{
- return __builtin_ia32_ucomineq(a, b);
+ return __builtin_ia32_ucomineq(__a, __b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_cvtss_si32(__m128 a)
+_mm_cvtss_si32(__m128 __a)
{
- return __builtin_ia32_cvtss2si(a);
+ return __builtin_ia32_cvtss2si(__a);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_cvt_ss2si(__m128 a)
+_mm_cvt_ss2si(__m128 __a)
{
- return _mm_cvtss_si32(a);
+ return _mm_cvtss_si32(__a);
}
#ifdef __x86_64__
static __inline__ long long __attribute__((__always_inline__, __nodebug__))
-_mm_cvtss_si64(__m128 a)
+_mm_cvtss_si64(__m128 __a)
{
- return __builtin_ia32_cvtss2si64(a);
+ return __builtin_ia32_cvtss2si64(__a);
}
#endif
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtps_pi32(__m128 a)
+_mm_cvtps_pi32(__m128 __a)
{
- return (__m64)__builtin_ia32_cvtps2pi(a);
+ return (__m64)__builtin_ia32_cvtps2pi(__a);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_cvt_ps2pi(__m128 a)
+_mm_cvt_ps2pi(__m128 __a)
{
- return _mm_cvtps_pi32(a);
+ return _mm_cvtps_pi32(__a);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_cvttss_si32(__m128 a)
+_mm_cvttss_si32(__m128 __a)
{
- return a[0];
+ return __a[0];
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_cvtt_ss2si(__m128 a)
+_mm_cvtt_ss2si(__m128 __a)
{
- return _mm_cvttss_si32(a);
+ return _mm_cvttss_si32(__a);
}
static __inline__ long long __attribute__((__always_inline__, __nodebug__))
-_mm_cvttss_si64(__m128 a)
+_mm_cvttss_si64(__m128 __a)
{
- return a[0];
+ return __a[0];
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_cvttps_pi32(__m128 a)
+_mm_cvttps_pi32(__m128 __a)
{
- return (__m64)__builtin_ia32_cvttps2pi(a);
+ return (__m64)__builtin_ia32_cvttps2pi(__a);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtt_ps2pi(__m128 a)
+_mm_cvtt_ps2pi(__m128 __a)
{
- return _mm_cvttps_pi32(a);
+ return _mm_cvttps_pi32(__a);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtsi32_ss(__m128 a, int b)
+_mm_cvtsi32_ss(__m128 __a, int __b)
{
- a[0] = b;
- return a;
+ __a[0] = __b;
+ return __a;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cvt_si2ss(__m128 a, int b)
+_mm_cvt_si2ss(__m128 __a, int __b)
{
- return _mm_cvtsi32_ss(a, b);
+ return _mm_cvtsi32_ss(__a, __b);
}
#ifdef __x86_64__
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtsi64_ss(__m128 a, long long b)
+_mm_cvtsi64_ss(__m128 __a, long long __b)
{
- a[0] = b;
- return a;
+ __a[0] = __b;
+ return __a;
}
#endif
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtpi32_ps(__m128 a, __m64 b)
+_mm_cvtpi32_ps(__m128 __a, __m64 __b)
{
- return __builtin_ia32_cvtpi2ps(a, (__v2si)b);
+ return __builtin_ia32_cvtpi2ps(__a, (__v2si)__b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cvt_pi2ps(__m128 a, __m64 b)
+_mm_cvt_pi2ps(__m128 __a, __m64 __b)
{
- return _mm_cvtpi32_ps(a, b);
+ return _mm_cvtpi32_ps(__a, __b);
}
static __inline__ float __attribute__((__always_inline__, __nodebug__))
-_mm_cvtss_f32(__m128 a)
+_mm_cvtss_f32(__m128 __a)
{
- return a[0];
+ return __a[0];
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_loadh_pi(__m128 a, const __m64 *p)
+_mm_loadh_pi(__m128 __a, const __m64 *__p)
{
typedef float __mm_loadh_pi_v2f32 __attribute__((__vector_size__(8)));
struct __mm_loadh_pi_struct {
- __mm_loadh_pi_v2f32 u;
+ __mm_loadh_pi_v2f32 __u;
} __attribute__((__packed__, __may_alias__));
- __mm_loadh_pi_v2f32 b = ((struct __mm_loadh_pi_struct*)p)->u;
- __m128 bb = __builtin_shufflevector(b, b, 0, 1, 0, 1);
- return __builtin_shufflevector(a, bb, 0, 1, 4, 5);
+ __mm_loadh_pi_v2f32 __b = ((struct __mm_loadh_pi_struct*)__p)->__u;
+ __m128 __bb = __builtin_shufflevector(__b, __b, 0, 1, 0, 1);
+ return __builtin_shufflevector(__a, __bb, 0, 1, 4, 5);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_loadl_pi(__m128 a, const __m64 *p)
+_mm_loadl_pi(__m128 __a, const __m64 *__p)
{
typedef float __mm_loadl_pi_v2f32 __attribute__((__vector_size__(8)));
struct __mm_loadl_pi_struct {
- __mm_loadl_pi_v2f32 u;
+ __mm_loadl_pi_v2f32 __u;
} __attribute__((__packed__, __may_alias__));
- __mm_loadl_pi_v2f32 b = ((struct __mm_loadl_pi_struct*)p)->u;
- __m128 bb = __builtin_shufflevector(b, b, 0, 1, 0, 1);
- return __builtin_shufflevector(a, bb, 4, 5, 2, 3);
+ __mm_loadl_pi_v2f32 __b = ((struct __mm_loadl_pi_struct*)__p)->__u;
+ __m128 __bb = __builtin_shufflevector(__b, __b, 0, 1, 0, 1);
+ return __builtin_shufflevector(__a, __bb, 4, 5, 2, 3);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_load_ss(const float *p)
+_mm_load_ss(const float *__p)
{
struct __mm_load_ss_struct {
- float u;
+ float __u;
} __attribute__((__packed__, __may_alias__));
- float u = ((struct __mm_load_ss_struct*)p)->u;
- return (__m128){ u, 0, 0, 0 };
+ float __u = ((struct __mm_load_ss_struct*)__p)->__u;
+ return (__m128){ __u, 0, 0, 0 };
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_load1_ps(const float *p)
+_mm_load1_ps(const float *__p)
{
struct __mm_load1_ps_struct {
- float u;
+ float __u;
} __attribute__((__packed__, __may_alias__));
- float u = ((struct __mm_load1_ps_struct*)p)->u;
- return (__m128){ u, u, u, u };
+ float __u = ((struct __mm_load1_ps_struct*)__p)->__u;
+ return (__m128){ __u, __u, __u, __u };
}
#define _mm_load_ps1(p) _mm_load1_ps(p)
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_load_ps(const float *p)
+_mm_load_ps(const float *__p)
{
- return *(__m128*)p;
+ return *(__m128*)__p;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_loadu_ps(const float *p)
+_mm_loadu_ps(const float *__p)
{
struct __loadu_ps {
- __m128 v;
+ __m128 __v;
} __attribute__((__packed__, __may_alias__));
- return ((struct __loadu_ps*)p)->v;
+ return ((struct __loadu_ps*)__p)->__v;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_loadr_ps(const float *p)
+_mm_loadr_ps(const float *__p)
{
- __m128 a = _mm_load_ps(p);
- return __builtin_shufflevector(a, a, 3, 2, 1, 0);
+ __m128 __a = _mm_load_ps(__p);
+ return __builtin_shufflevector(__a, __a, 3, 2, 1, 0);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_set_ss(float w)
+_mm_set_ss(float __w)
{
- return (__m128){ w, 0, 0, 0 };
+ return (__m128){ __w, 0, 0, 0 };
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_set1_ps(float w)
+_mm_set1_ps(float __w)
{
- return (__m128){ w, w, w, w };
+ return (__m128){ __w, __w, __w, __w };
}
// Microsoft specific.
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_set_ps1(float w)
+_mm_set_ps1(float __w)
{
- return _mm_set1_ps(w);
+ return _mm_set1_ps(__w);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_set_ps(float z, float y, float x, float w)
+_mm_set_ps(float __z, float __y, float __x, float __w)
{
- return (__m128){ w, x, y, z };
+ return (__m128){ __w, __x, __y, __z };
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_setr_ps(float z, float y, float x, float w)
+_mm_setr_ps(float __z, float __y, float __x, float __w)
{
- return (__m128){ z, y, x, w };
+ return (__m128){ __z, __y, __x, __w };
}
static __inline__ __m128 __attribute__((__always_inline__))
@@ -607,56 +607,56 @@ _mm_setzero_ps(void)
}
static __inline__ void __attribute__((__always_inline__))
-_mm_storeh_pi(__m64 *p, __m128 a)
+_mm_storeh_pi(__m64 *__p, __m128 __a)
{
- __builtin_ia32_storehps((__v2si *)p, a);
+ __builtin_ia32_storehps((__v2si *)__p, __a);
}
static __inline__ void __attribute__((__always_inline__))
-_mm_storel_pi(__m64 *p, __m128 a)
+_mm_storel_pi(__m64 *__p, __m128 __a)
{
- __builtin_ia32_storelps((__v2si *)p, a);
+ __builtin_ia32_storelps((__v2si *)__p, __a);
}
static __inline__ void __attribute__((__always_inline__))
-_mm_store_ss(float *p, __m128 a)
+_mm_store_ss(float *__p, __m128 __a)
{
struct __mm_store_ss_struct {
- float u;
+ float __u;
} __attribute__((__packed__, __may_alias__));
- ((struct __mm_store_ss_struct*)p)->u = a[0];
+ ((struct __mm_store_ss_struct*)__p)->__u = __a[0];
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_storeu_ps(float *p, __m128 a)
+_mm_storeu_ps(float *__p, __m128 __a)
{
- __builtin_ia32_storeups(p, a);
+ __builtin_ia32_storeups(__p, __a);
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_store1_ps(float *p, __m128 a)
+_mm_store1_ps(float *__p, __m128 __a)
{
- a = __builtin_shufflevector(a, a, 0, 0, 0, 0);
- _mm_storeu_ps(p, a);
+ __a = __builtin_shufflevector(__a, __a, 0, 0, 0, 0);
+ _mm_storeu_ps(__p, __a);
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_store_ps1(float *p, __m128 a)
+_mm_store_ps1(float *__p, __m128 __a)
{
- return _mm_store1_ps(p, a);
+ return _mm_store1_ps(__p, __a);
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_store_ps(float *p, __m128 a)
+_mm_store_ps(float *__p, __m128 __a)
{
- *(__m128 *)p = a;
+ *(__m128 *)__p = __a;
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_storer_ps(float *p, __m128 a)
+_mm_storer_ps(float *__p, __m128 __a)
{
- a = __builtin_shufflevector(a, a, 3, 2, 1, 0);
- _mm_store_ps(p, a);
+ __a = __builtin_shufflevector(__a, __a, 3, 2, 1, 0);
+ _mm_store_ps(__p, __a);
}
#define _MM_HINT_T0 3
@@ -670,15 +670,15 @@ _mm_storer_ps(float *p, __m128 a)
#define _mm_prefetch(a, sel) (__builtin_prefetch((void *)(a), 0, (sel)))
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_stream_pi(__m64 *p, __m64 a)
+_mm_stream_pi(__m64 *__p, __m64 __a)
{
- __builtin_ia32_movntq(p, a);
+ __builtin_ia32_movntq(__p, __a);
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_stream_ps(float *p, __m128 a)
+_mm_stream_ps(float *__p, __m128 __a)
{
- __builtin_ia32_movntps(p, a);
+ __builtin_ia32_movntps(__p, __a);
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
@@ -688,54 +688,54 @@ _mm_sfence(void)
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_extract_pi16(__m64 a, int n)
+_mm_extract_pi16(__m64 __a, int __n)
{
- __v4hi b = (__v4hi)a;
- return (unsigned short)b[n & 3];
+ __v4hi __b = (__v4hi)__a;
+ return (unsigned short)__b[__n & 3];
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_insert_pi16(__m64 a, int d, int n)
+_mm_insert_pi16(__m64 __a, int __d, int __n)
{
- __v4hi b = (__v4hi)a;
- b[n & 3] = d;
- return (__m64)b;
+ __v4hi __b = (__v4hi)__a;
+ __b[__n & 3] = __d;
+ return (__m64)__b;
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_max_pi16(__m64 a, __m64 b)
+_mm_max_pi16(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_pmaxsw((__v4hi)a, (__v4hi)b);
+ return (__m64)__builtin_ia32_pmaxsw((__v4hi)__a, (__v4hi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_max_pu8(__m64 a, __m64 b)
+_mm_max_pu8(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_pmaxub((__v8qi)a, (__v8qi)b);
+ return (__m64)__builtin_ia32_pmaxub((__v8qi)__a, (__v8qi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_min_pi16(__m64 a, __m64 b)
+_mm_min_pi16(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_pminsw((__v4hi)a, (__v4hi)b);
+ return (__m64)__builtin_ia32_pminsw((__v4hi)__a, (__v4hi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_min_pu8(__m64 a, __m64 b)
+_mm_min_pu8(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_pminub((__v8qi)a, (__v8qi)b);
+ return (__m64)__builtin_ia32_pminub((__v8qi)__a, (__v8qi)__b);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_movemask_pi8(__m64 a)
+_mm_movemask_pi8(__m64 __a)
{
- return __builtin_ia32_pmovmskb((__v8qi)a);
+ return __builtin_ia32_pmovmskb((__v8qi)__a);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_mulhi_pu16(__m64 a, __m64 b)
+_mm_mulhi_pu16(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_pmulhuw((__v4hi)a, (__v4hi)b);
+ return (__m64)__builtin_ia32_pmulhuw((__v4hi)__a, (__v4hi)__b);
}
#define _mm_shuffle_pi16(a, n) __extension__ ({ \
@@ -743,27 +743,27 @@ _mm_mulhi_pu16(__m64 a, __m64 b)
(__m64)__builtin_ia32_pshufw((__v4hi)__a, (n)); })
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_maskmove_si64(__m64 d, __m64 n, char *p)
+_mm_maskmove_si64(__m64 __d, __m64 __n, char *__p)
{
- __builtin_ia32_maskmovq((__v8qi)d, (__v8qi)n, p);
+ __builtin_ia32_maskmovq((__v8qi)__d, (__v8qi)__n, __p);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_avg_pu8(__m64 a, __m64 b)
+_mm_avg_pu8(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_pavgb((__v8qi)a, (__v8qi)b);
+ return (__m64)__builtin_ia32_pavgb((__v8qi)__a, (__v8qi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_avg_pu16(__m64 a, __m64 b)
+_mm_avg_pu16(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_pavgw((__v4hi)a, (__v4hi)b);
+ return (__m64)__builtin_ia32_pavgw((__v4hi)__a, (__v4hi)__b);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_sad_pu8(__m64 a, __m64 b)
+_mm_sad_pu8(__m64 __a, __m64 __b)
{
- return (__m64)__builtin_ia32_psadbw((__v8qi)a, (__v8qi)b);
+ return (__m64)__builtin_ia32_psadbw((__v8qi)__a, (__v8qi)__b);
}
static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__))
@@ -773,9 +773,9 @@ _mm_getcsr(void)
}
static __inline__ void __attribute__((__always_inline__, __nodebug__))
-_mm_setcsr(unsigned int i)
+_mm_setcsr(unsigned int __i)
{
- __builtin_ia32_ldmxcsr(i);
+ __builtin_ia32_ldmxcsr(__i);
}
#define _mm_shuffle_ps(a, b, mask) __extension__ ({ \
@@ -787,132 +787,132 @@ _mm_setcsr(unsigned int i)
(((mask) & 0xc0) >> 6) + 4); })
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_unpackhi_ps(__m128 a, __m128 b)
+_mm_unpackhi_ps(__m128 __a, __m128 __b)
{
- return __builtin_shufflevector(a, b, 2, 6, 3, 7);
+ return __builtin_shufflevector(__a, __b, 2, 6, 3, 7);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_unpacklo_ps(__m128 a, __m128 b)
+_mm_unpacklo_ps(__m128 __a, __m128 __b)
{
- return __builtin_shufflevector(a, b, 0, 4, 1, 5);
+ return __builtin_shufflevector(__a, __b, 0, 4, 1, 5);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_move_ss(__m128 a, __m128 b)
+_mm_move_ss(__m128 __a, __m128 __b)
{
- return __builtin_shufflevector(a, b, 4, 1, 2, 3);
+ return __builtin_shufflevector(__a, __b, 4, 1, 2, 3);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_movehl_ps(__m128 a, __m128 b)
+_mm_movehl_ps(__m128 __a, __m128 __b)
{
- return __builtin_shufflevector(a, b, 6, 7, 2, 3);
+ return __builtin_shufflevector(__a, __b, 6, 7, 2, 3);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_movelh_ps(__m128 a, __m128 b)
+_mm_movelh_ps(__m128 __a, __m128 __b)
{
- return __builtin_shufflevector(a, b, 0, 1, 4, 5);
+ return __builtin_shufflevector(__a, __b, 0, 1, 4, 5);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtpi16_ps(__m64 a)
+_mm_cvtpi16_ps(__m64 __a)
{
- __m64 b, c;
- __m128 r;
+ __m64 __b, __c;
+ __m128 __r;
- b = _mm_setzero_si64();
- b = _mm_cmpgt_pi16(b, a);
- c = _mm_unpackhi_pi16(a, b);
- r = _mm_setzero_ps();
- r = _mm_cvtpi32_ps(r, c);
- r = _mm_movelh_ps(r, r);
- c = _mm_unpacklo_pi16(a, b);
- r = _mm_cvtpi32_ps(r, c);
+ __b = _mm_setzero_si64();
+ __b = _mm_cmpgt_pi16(__b, __a);
+ __c = _mm_unpackhi_pi16(__a, __b);
+ __r = _mm_setzero_ps();
+ __r = _mm_cvtpi32_ps(__r, __c);
+ __r = _mm_movelh_ps(__r, __r);
+ __c = _mm_unpacklo_pi16(__a, __b);
+ __r = _mm_cvtpi32_ps(__r, __c);
- return r;
+ return __r;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtpu16_ps(__m64 a)
+_mm_cvtpu16_ps(__m64 __a)
{
- __m64 b, c;
- __m128 r;
+ __m64 __b, __c;
+ __m128 __r;
- b = _mm_setzero_si64();
- c = _mm_unpackhi_pi16(a, b);
- r = _mm_setzero_ps();
- r = _mm_cvtpi32_ps(r, c);
- r = _mm_movelh_ps(r, r);
- c = _mm_unpacklo_pi16(a, b);
- r = _mm_cvtpi32_ps(r, c);
+ __b = _mm_setzero_si64();
+ __c = _mm_unpackhi_pi16(__a, __b);
+ __r = _mm_setzero_ps();
+ __r = _mm_cvtpi32_ps(__r, __c);
+ __r = _mm_movelh_ps(__r, __r);
+ __c = _mm_unpacklo_pi16(__a, __b);
+ __r = _mm_cvtpi32_ps(__r, __c);
- return r;
+ return __r;
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtpi8_ps(__m64 a)
+_mm_cvtpi8_ps(__m64 __a)
{
- __m64 b;
+ __m64 __b;
- b = _mm_setzero_si64();
- b = _mm_cmpgt_pi8(b, a);
- b = _mm_unpacklo_pi8(a, b);
+ __b = _mm_setzero_si64();
+ __b = _mm_cmpgt_pi8(__b, __a);
+ __b = _mm_unpacklo_pi8(__a, __b);
- return _mm_cvtpi16_ps(b);
+ return _mm_cvtpi16_ps(__b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtpu8_ps(__m64 a)
+_mm_cvtpu8_ps(__m64 __a)
{
- __m64 b;
+ __m64 __b;
- b = _mm_setzero_si64();
- b = _mm_unpacklo_pi8(a, b);
+ __b = _mm_setzero_si64();
+ __b = _mm_unpacklo_pi8(__a, __b);
- return _mm_cvtpi16_ps(b);
+ return _mm_cvtpi16_ps(__b);
}
static __inline__ __m128 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtpi32x2_ps(__m64 a, __m64 b)
+_mm_cvtpi32x2_ps(__m64 __a, __m64 __b)
{
- __m128 c;
+ __m128 __c;
- c = _mm_setzero_ps();
- c = _mm_cvtpi32_ps(c, b);
- c = _mm_movelh_ps(c, c);
+ __c = _mm_setzero_ps();
+ __c = _mm_cvtpi32_ps(__c, __b);
+ __c = _mm_movelh_ps(__c, __c);
- return _mm_cvtpi32_ps(c, a);
+ return _mm_cvtpi32_ps(__c, __a);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtps_pi16(__m128 a)
+_mm_cvtps_pi16(__m128 __a)
{
- __m64 b, c;
+ __m64 __b, __c;
- b = _mm_cvtps_pi32(a);
- a = _mm_movehl_ps(a, a);
- c = _mm_cvtps_pi32(a);
+ __b = _mm_cvtps_pi32(__a);
+ __a = _mm_movehl_ps(__a, __a);
+ __c = _mm_cvtps_pi32(__a);
- return _mm_packs_pi16(b, c);
+ return _mm_packs_pi16(__b, __c);
}
static __inline__ __m64 __attribute__((__always_inline__, __nodebug__))
-_mm_cvtps_pi8(__m128 a)
+_mm_cvtps_pi8(__m128 __a)
{
- __m64 b, c;
+ __m64 __b, __c;
- b = _mm_cvtps_pi16(a);
- c = _mm_setzero_si64();
+ __b = _mm_cvtps_pi16(__a);
+ __c = _mm_setzero_si64();
- return _mm_packs_pi16(b, c);
+ return _mm_packs_pi16(__b, __c);
}
static __inline__ int __attribute__((__always_inline__, __nodebug__))
-_mm_movemask_ps(__m128 a)
+_mm_movemask_ps(__m128 __a)
{
- return __builtin_ia32_movmskps(a);
+ return __builtin_ia32_movmskps(__a);
}
#define _MM_SHUFFLE(z, y, x, w) (((z) << 6) | ((y) << 4) | ((x) << 2) | (w))
@@ -983,10 +983,12 @@ do { \
#define _m_ _mm_
#define _m_ _mm_
+#if !__has_feature(modules)
/* Ugly hack for backwards-compatibility (compatible with gcc) */
#ifdef __SSE2__
#include <emmintrin.h>
#endif
+#endif
#endif /* __SSE__ */
diff --git a/lib/Lex/CMakeLists.txt b/lib/Lex/CMakeLists.txt
index 241abbc..2ee4682 100644
--- a/lib/Lex/CMakeLists.txt
+++ b/lib/Lex/CMakeLists.txt
@@ -12,6 +12,7 @@ add_clang_library(clangLex
ModuleMap.cpp
PPCaching.cpp
PPCallbacks.cpp
+ PPConditionalDirectiveRecord.cpp
PPDirectives.cpp
PPExpressions.cpp
PPLexerChange.cpp
diff --git a/lib/Lex/HeaderMap.cpp b/lib/Lex/HeaderMap.cpp
index 7dc0491..dcf1f0c 100644
--- a/lib/Lex/HeaderMap.cpp
+++ b/lib/Lex/HeaderMap.cpp
@@ -12,13 +12,13 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/HeaderMap.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/FileManager.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/MemoryBuffer.h"
-#include <cctype>
#include <cstdio>
using namespace clang;
@@ -62,7 +62,7 @@ static inline unsigned HashHMapKey(StringRef Str) {
const char *S = Str.begin(), *End = Str.end();
for (; S != End; S++)
- Result += tolower(*S) * 13;
+ Result += toLowercase(*S) * 13;
return Result;
}
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp
index 67000b68..304bd69 100644
--- a/lib/Lex/HeaderSearch.cpp
+++ b/lib/Lex/HeaderSearch.cpp
@@ -12,17 +12,20 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/HeaderSearch.h"
-#include "clang/Lex/HeaderSearchOptions.h"
-#include "clang/Lex/HeaderMap.h"
-#include "clang/Lex/Lexer.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/IdentifierTable.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Path.h"
+#include "clang/Lex/HeaderMap.h"
+#include "clang/Lex/HeaderSearchOptions.h"
+#include "clang/Lex/Lexer.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Capacity.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
#include <cstdio>
+#if defined(LLVM_ON_UNIX)
+#include <limits.h>
+#endif
using namespace clang;
const IdentifierInfo *
@@ -39,12 +42,12 @@ HeaderFileInfo::getControllingMacro(ExternalIdentifierLookup *External) {
ExternalHeaderFileInfoSource::~ExternalHeaderFileInfoSource() {}
-HeaderSearch::HeaderSearch(llvm::IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts,
+HeaderSearch::HeaderSearch(IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts,
FileManager &FM, DiagnosticsEngine &Diags,
const LangOptions &LangOpts,
const TargetInfo *Target)
: HSOpts(HSOpts), FileMgr(FM), FrameworkMap(64),
- ModMap(FileMgr, *Diags.getClient(), LangOpts, Target)
+ ModMap(FileMgr, *Diags.getClient(), LangOpts, Target, *this)
{
AngledDirIdx = 0;
SystemDirIdx = 0;
@@ -134,7 +137,7 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, bool AllowSearch) {
if (Module || !AllowSearch)
return Module;
- // Look through the various header search paths to load any avai;able module
+ // Look through the various header search paths to load any available module
// maps, searching for a module map that describes this module.
for (unsigned Idx = 0, N = SearchDirs.size(); Idx != N; ++Idx) {
if (SearchDirs[Idx].isFramework()) {
@@ -178,8 +181,22 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, bool AllowSearch) {
if (Module)
break;
}
+
+ // If we've already performed the exhaustive search for module maps in this
+ // search directory, don't do it again.
+ if (SearchDirs[Idx].haveSearchedAllModuleMaps())
+ continue;
+
+ // Load all module maps in the immediate subdirectories of this search
+ // directory.
+ loadSubdirectoryModuleMaps(SearchDirs[Idx]);
+
+ // Look again for the module.
+ Module = ModMap.findModule(ModuleName);
+ if (Module)
+ break;
}
-
+
return Module;
}
@@ -263,6 +280,55 @@ const FileEntry *DirectoryLookup::LookupFile(
return Result;
}
+/// \brief Given a framework directory, find the top-most framework directory.
+///
+/// \param FileMgr The file manager to use for directory lookups.
+/// \param DirName The name of the framework directory.
+/// \param SubmodulePath Will be populated with the submodule path from the
+/// returned top-level module to the originally named framework.
+static const DirectoryEntry *
+getTopFrameworkDir(FileManager &FileMgr, StringRef DirName,
+ SmallVectorImpl<std::string> &SubmodulePath) {
+ assert(llvm::sys::path::extension(DirName) == ".framework" &&
+ "Not a framework directory");
+
+ // Note: as an egregious but useful hack we use the real path here, because
+ // frameworks moving between top-level frameworks to embedded frameworks tend
+ // to be symlinked, and we base the logical structure of modules on the
+ // physical layout. In particular, we need to deal with crazy includes like
+ //
+ // #include <Foo/Frameworks/Bar.framework/Headers/Wibble.h>
+ //
+ // where 'Bar' used to be embedded in 'Foo', is now a top-level framework
+ // which one should access with, e.g.,
+ //
+ // #include <Bar/Wibble.h>
+ //
+ // Similar issues occur when a top-level framework has moved into an
+ // embedded framework.
+ const DirectoryEntry *TopFrameworkDir = FileMgr.getDirectory(DirName);
+ DirName = FileMgr.getCanonicalName(TopFrameworkDir);
+ do {
+ // Get the parent directory name.
+ DirName = llvm::sys::path::parent_path(DirName);
+ if (DirName.empty())
+ break;
+
+ // Determine whether this directory exists.
+ const DirectoryEntry *Dir = FileMgr.getDirectory(DirName);
+ if (!Dir)
+ break;
+
+ // If this is a framework directory, then we're a subframework of this
+ // framework.
+ if (llvm::sys::path::extension(DirName) == ".framework") {
+ SubmodulePath.push_back(llvm::sys::path::stem(DirName));
+ TopFrameworkDir = Dir;
+ }
+ } while (true);
+
+ return TopFrameworkDir;
+}
/// DoFrameworkLookup - Do a lookup of the specified file in the current
/// DirectoryLookup, which is a framework directory.
@@ -334,17 +400,6 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
RelativePath->clear();
RelativePath->append(Filename.begin()+SlashPos+1, Filename.end());
}
-
- // If we're allowed to look for modules, try to load or create the module
- // corresponding to this framework.
- Module *Module = 0;
- if (SuggestedModule) {
- if (const DirectoryEntry *FrameworkDir
- = FileMgr.getDirectory(FrameworkName)) {
- bool IsSystem = getDirCharacteristic() != SrcMgr::C_User;
- Module = HS.loadFrameworkModule(ModuleName, FrameworkDir, IsSystem);
- }
- }
// Check "/System/Library/Frameworks/Cocoa.framework/Headers/file.h"
unsigned OrigSize = FrameworkName.size();
@@ -357,28 +412,64 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(
SearchPath->append(FrameworkName.begin(), FrameworkName.end()-1);
}
- // Determine whether this is the module we're building or not.
- bool AutomaticImport = Module;
FrameworkName.append(Filename.begin()+SlashPos+1, Filename.end());
- if (const FileEntry *FE = FileMgr.getFile(FrameworkName.str(),
- /*openFile=*/!AutomaticImport)) {
- if (AutomaticImport)
- *SuggestedModule = HS.findModuleForHeader(FE);
- return FE;
+ const FileEntry *FE = FileMgr.getFile(FrameworkName.str(),
+ /*openFile=*/!SuggestedModule);
+ if (!FE) {
+ // Check "/System/Library/Frameworks/Cocoa.framework/PrivateHeaders/file.h"
+ const char *Private = "Private";
+ FrameworkName.insert(FrameworkName.begin()+OrigSize, Private,
+ Private+strlen(Private));
+ if (SearchPath != NULL)
+ SearchPath->insert(SearchPath->begin()+OrigSize, Private,
+ Private+strlen(Private));
+
+ FE = FileMgr.getFile(FrameworkName.str(), /*openFile=*/!SuggestedModule);
}
- // Check "/System/Library/Frameworks/Cocoa.framework/PrivateHeaders/file.h"
- const char *Private = "Private";
- FrameworkName.insert(FrameworkName.begin()+OrigSize, Private,
- Private+strlen(Private));
- if (SearchPath != NULL)
- SearchPath->insert(SearchPath->begin()+OrigSize, Private,
- Private+strlen(Private));
-
- const FileEntry *FE = FileMgr.getFile(FrameworkName.str(),
- /*openFile=*/!AutomaticImport);
- if (FE && AutomaticImport)
- *SuggestedModule = HS.findModuleForHeader(FE);
+ // If we found the header and are allowed to suggest a module, do so now.
+ if (FE && SuggestedModule) {
+ // Find the framework in which this header occurs.
+ StringRef FrameworkPath = FE->getName();
+ bool FoundFramework = false;
+ do {
+ // Get the parent directory name.
+ FrameworkPath = llvm::sys::path::parent_path(FrameworkPath);
+ if (FrameworkPath.empty())
+ break;
+
+ // Determine whether this directory exists.
+ const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkPath);
+ if (!Dir)
+ break;
+
+ // If this is a framework directory, then we're a subframework of this
+ // framework.
+ if (llvm::sys::path::extension(FrameworkPath) == ".framework") {
+ FoundFramework = true;
+ break;
+ }
+ } while (true);
+
+ if (FoundFramework) {
+ // Find the top-level framework based on this framework.
+ SmallVector<std::string, 4> SubmodulePath;
+ const DirectoryEntry *TopFrameworkDir
+ = ::getTopFrameworkDir(FileMgr, FrameworkPath, SubmodulePath);
+
+ // Determine the name of the top-level framework.
+ StringRef ModuleName = llvm::sys::path::stem(TopFrameworkDir->getName());
+
+ // Load this framework module. If that succeeds, find the suggested module
+ // for this header, if any.
+ bool IsSystem = getDirCharacteristic() != SrcMgr::C_User;
+ if (HS.loadFrameworkModule(ModuleName, TopFrameworkDir, IsSystem)) {
+ *SuggestedModule = HS.findModuleForHeader(FE);
+ }
+ } else {
+ *SuggestedModule = HS.findModuleForHeader(FE);
+ }
+ }
return FE;
}
@@ -584,7 +675,8 @@ const FileEntry *HeaderSearch::
LookupSubframeworkHeader(StringRef Filename,
const FileEntry *ContextFileEnt,
SmallVectorImpl<char> *SearchPath,
- SmallVectorImpl<char> *RelativePath) {
+ SmallVectorImpl<char> *RelativePath,
+ Module **SuggestedModule) {
assert(ContextFileEnt && "No context file?");
// Framework names must have a '/' in the filename. Find it.
@@ -673,6 +765,26 @@ LookupSubframeworkHeader(StringRef Filename,
// of evaluation.
unsigned DirInfo = getFileInfo(ContextFileEnt).DirInfo;
getFileInfo(FE).DirInfo = DirInfo;
+
+ // If we're supposed to suggest a module, look for one now.
+ if (SuggestedModule) {
+ // Find the top-level framework based on this framework.
+ FrameworkName.pop_back(); // remove the trailing '/'
+ SmallVector<std::string, 4> SubmodulePath;
+ const DirectoryEntry *TopFrameworkDir
+ = ::getTopFrameworkDir(FileMgr, FrameworkName, SubmodulePath);
+
+ // Determine the name of the top-level framework.
+ StringRef ModuleName = llvm::sys::path::stem(TopFrameworkDir->getName());
+
+ // Load this framework module. If that succeeds, find the suggested module
+ // for this header, if any.
+ bool IsSystem = false;
+ if (loadFrameworkModule(ModuleName, TopFrameworkDir, IsSystem)) {
+ *SuggestedModule = findModuleForHeader(FE);
+ }
+ }
+
return FE;
}
@@ -708,6 +820,7 @@ static void mergeHeaderFileInfo(HeaderFileInfo &HFI,
const HeaderFileInfo &OtherHFI) {
HFI.isImport |= OtherHFI.isImport;
HFI.isPragmaOnce |= OtherHFI.isPragmaOnce;
+ HFI.isModuleHeader |= OtherHFI.isModuleHeader;
HFI.NumIncludes += OtherHFI.NumIncludes;
if (!HFI.ControllingMacro && !HFI.ControllingMacroID) {
@@ -749,7 +862,16 @@ bool HeaderSearch::isFileMultipleIncludeGuarded(const FileEntry *File) {
if (ExternalSource && !HFI.Resolved)
mergeHeaderFileInfo(HFI, ExternalSource->GetHeaderFileInfo(File));
- return HFI.isPragmaOnce || HFI.ControllingMacro || HFI.ControllingMacroID;
+ return HFI.isPragmaOnce || HFI.isImport ||
+ HFI.ControllingMacro || HFI.ControllingMacroID;
+}
+
+void HeaderSearch::MarkFileModuleHeader(const FileEntry *FE) {
+ if (FE->getUID() >= FileInfo.size())
+ FileInfo.resize(FE->getUID()+1);
+
+ HeaderFileInfo &HFI = FileInfo[FE->getUID()];
+ HFI.isModuleHeader = true;
}
void HeaderSearch::setHeaderFileInfoForUID(HeaderFileInfo HFI, unsigned UID) {
@@ -809,7 +931,7 @@ StringRef HeaderSearch::getUniqueFrameworkName(StringRef Framework) {
bool HeaderSearch::hasModuleMap(StringRef FileName,
const DirectoryEntry *Root) {
- llvm::SmallVector<const DirectoryEntry *, 2> FixUpDirectories;
+ SmallVector<const DirectoryEntry *, 2> FixUpDirectories;
StringRef DirName = FileName;
do {
@@ -849,7 +971,12 @@ bool HeaderSearch::hasModuleMap(StringRef FileName,
} while (true);
}
-Module *HeaderSearch::findModuleForHeader(const FileEntry *File) {
+Module *HeaderSearch::findModuleForHeader(const FileEntry *File) const {
+ if (ExternalSource) {
+ // Make sure the external source has handled header info about this file,
+ // which includes whether the file is part of a module.
+ (void)getFileInfo(File);
+ }
if (Module *Mod = ModMap.findModuleForHeader(File))
return Mod;
@@ -897,80 +1024,21 @@ Module *HeaderSearch::loadFrameworkModule(StringRef Name,
return ModMap.findModule(Name);
}
- // The top-level framework directory, from which we'll infer a framework
- // module.
- const DirectoryEntry *TopFrameworkDir = Dir;
-
- // The path from the module we're actually looking for back to the top-level
- // framework name.
- llvm::SmallVector<StringRef, 2> SubmodulePath;
+ // Figure out the top-level framework directory and the submodule path from
+ // that top-level framework to the requested framework.
+ SmallVector<std::string, 2> SubmodulePath;
SubmodulePath.push_back(Name);
-
- // Walk the directory structure to find any enclosing frameworks.
-#ifdef LLVM_ON_UNIX
- // Note: as an egregious but useful hack we use the real path here, because
- // frameworks moving from top-level frameworks to embedded frameworks tend
- // to be symlinked from the top-level location to the embedded location,
- // and we need to resolve lookups as if we had found the embedded location.
- char RealDirName[PATH_MAX];
- StringRef DirName;
- if (realpath(Dir->getName(), RealDirName))
- DirName = RealDirName;
- else
- DirName = Dir->getName();
-#else
- StringRef DirName = Dir->getName();
-#endif
- do {
- // Get the parent directory name.
- DirName = llvm::sys::path::parent_path(DirName);
- if (DirName.empty())
- break;
-
- // Determine whether this directory exists.
- Dir = FileMgr.getDirectory(DirName);
- if (!Dir)
- break;
-
- // If this is a framework directory, then we're a subframework of this
- // framework.
- if (llvm::sys::path::extension(DirName) == ".framework") {
- SubmodulePath.push_back(llvm::sys::path::stem(DirName));
- TopFrameworkDir = Dir;
- }
- } while (true);
+ const DirectoryEntry *TopFrameworkDir
+ = ::getTopFrameworkDir(FileMgr, Dir->getName(), SubmodulePath);
- // Determine whether we're allowed to infer a module map.
- bool canInfer = false;
- if (llvm::sys::path::has_parent_path(TopFrameworkDir->getName())) {
- // Figure out the parent path.
- StringRef Parent = llvm::sys::path::parent_path(TopFrameworkDir->getName());
- if (const DirectoryEntry *ParentDir = FileMgr.getDirectory(Parent)) {
- // If there's a module map file in the parent directory, it can
- // explicitly allow us to infer framework modules.
- switch (loadModuleMapFile(ParentDir)) {
- case LMM_AlreadyLoaded:
- case LMM_NewlyLoaded: {
- StringRef Name = llvm::sys::path::stem(TopFrameworkDir->getName());
- canInfer = ModMap.canInferFrameworkModule(ParentDir, Name, IsSystem);
- break;
- }
- case LMM_InvalidModuleMap:
- case LMM_NoDirectory:
- break;
- }
- }
- }
-
- // If we're not allowed to infer a module map, we're done.
- if (!canInfer)
- return 0;
// Try to infer a module map from the top-level framework directory.
Module *Result = ModMap.inferFrameworkModule(SubmodulePath.back(),
TopFrameworkDir,
IsSystem,
/*Parent=*/0);
+ if (!Result)
+ return 0;
// Follow the submodule path to find the requested (sub)framework module
// within the top-level framework module.
@@ -1034,7 +1102,7 @@ HeaderSearch::loadModuleMapFile(const DirectoryEntry *Dir) {
return LMM_InvalidModuleMap;
}
-void HeaderSearch::collectAllModules(llvm::SmallVectorImpl<Module *> &Modules) {
+void HeaderSearch::collectAllModules(SmallVectorImpl<Module *> &Modules) {
Modules.clear();
// Load module maps for each of the header search directories.
@@ -1072,13 +1140,7 @@ void HeaderSearch::collectAllModules(llvm::SmallVectorImpl<Module *> &Modules) {
// Try to load module map files for immediate subdirectories of this search
// directory.
- llvm::error_code EC;
- SmallString<128> DirNative;
- llvm::sys::path::native(SearchDirs[Idx].getDir()->getName(), DirNative);
- for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd;
- Dir != DirEnd && !EC; Dir.increment(EC)) {
- loadModuleMapFile(Dir->path());
- }
+ loadSubdirectoryModuleMaps(SearchDirs[Idx]);
}
// Populate the list of modules.
@@ -1088,3 +1150,18 @@ void HeaderSearch::collectAllModules(llvm::SmallVectorImpl<Module *> &Modules) {
Modules.push_back(M->getValue());
}
}
+
+void HeaderSearch::loadSubdirectoryModuleMaps(DirectoryLookup &SearchDir) {
+ if (SearchDir.haveSearchedAllModuleMaps())
+ return;
+
+ llvm::error_code EC;
+ SmallString<128> DirNative;
+ llvm::sys::path::native(SearchDir.getDir()->getName(), DirNative);
+ for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd;
+ Dir != DirEnd && !EC; Dir.increment(EC)) {
+ loadModuleMapFile(Dir->path());
+ }
+
+ SearchDir.setSearchedAllModuleMaps(true);
+}
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index a5ba7db..ed4666a 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -25,19 +25,21 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/Lexer.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/LexDiagnostic.h"
-#include "clang/Lex/CodeCompletionHandler.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/SourceManager.h"
-#include "llvm/ADT/StringSwitch.h"
+#include "clang/Lex/CodeCompletionHandler.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "UnicodeCharSets.h"
#include <cstring>
using namespace clang;
-static void InitCharacterInfo();
-
//===----------------------------------------------------------------------===//
// Token Class Implementation
//===----------------------------------------------------------------------===//
@@ -64,8 +66,6 @@ void Lexer::anchor() { }
void Lexer::InitLexer(const char *BufStart, const char *BufPtr,
const char *BufEnd) {
- InitCharacterInfo();
-
BufferStart = BufStart;
BufferPtr = BufPtr;
BufferEnd = BufEnd;
@@ -122,8 +122,15 @@ Lexer::Lexer(FileID FID, const llvm::MemoryBuffer *InputFile, Preprocessor &PP)
InitLexer(InputFile->getBufferStart(), InputFile->getBufferStart(),
InputFile->getBufferEnd());
- // Default to keeping comments if the preprocessor wants them.
- SetCommentRetentionState(PP.getCommentRetentionState());
+ resetExtendedTokenMode();
+}
+
+void Lexer::resetExtendedTokenMode() {
+ assert(PP && "Cannot reset token mode without a preprocessor");
+ if (LangOpts.TraditionalCPP)
+ SetKeepWhitespaceMode(true);
+ else
+ SetCommentRetentionState(PP->getCommentRetentionState());
}
/// Lexer constructor - Create a new raw lexer object. This object is only
@@ -233,16 +240,67 @@ void Lexer::Stringify(SmallVectorImpl<char> &Str) {
// Token Spelling
//===----------------------------------------------------------------------===//
+/// \brief Slow case of getSpelling. Extract the characters comprising the
+/// spelling of this token from the provided input buffer.
+static size_t getSpellingSlow(const Token &Tok, const char *BufPtr,
+ const LangOptions &LangOpts, char *Spelling) {
+ assert(Tok.needsCleaning() && "getSpellingSlow called on simple token");
+
+ size_t Length = 0;
+ const char *BufEnd = BufPtr + Tok.getLength();
+
+ if (Tok.is(tok::string_literal)) {
+ // Munch the encoding-prefix and opening double-quote.
+ while (BufPtr < BufEnd) {
+ unsigned Size;
+ Spelling[Length++] = Lexer::getCharAndSizeNoWarn(BufPtr, Size, LangOpts);
+ BufPtr += Size;
+
+ if (Spelling[Length - 1] == '"')
+ break;
+ }
+
+ // Raw string literals need special handling; trigraph expansion and line
+ // splicing do not occur within their d-char-sequence nor within their
+ // r-char-sequence.
+ if (Length >= 2 &&
+ Spelling[Length - 2] == 'R' && Spelling[Length - 1] == '"') {
+ // Search backwards from the end of the token to find the matching closing
+ // quote.
+ const char *RawEnd = BufEnd;
+ do --RawEnd; while (*RawEnd != '"');
+ size_t RawLength = RawEnd - BufPtr + 1;
+
+ // Everything between the quotes is included verbatim in the spelling.
+ memcpy(Spelling + Length, BufPtr, RawLength);
+ Length += RawLength;
+ BufPtr += RawLength;
+
+ // The rest of the token is lexed normally.
+ }
+ }
+
+ while (BufPtr < BufEnd) {
+ unsigned Size;
+ Spelling[Length++] = Lexer::getCharAndSizeNoWarn(BufPtr, Size, LangOpts);
+ BufPtr += Size;
+ }
+
+ assert(Length < Tok.getLength() &&
+ "NeedsCleaning flag set on token that didn't need cleaning!");
+ return Length;
+}
+
/// getSpelling() - Return the 'spelling' of this token. The spelling of a
/// token are the characters used to represent the token in the source file
/// after trigraph expansion and escaped-newline folding. In particular, this
/// wants to get the true, uncanonicalized, spelling of things like digraphs
/// UCNs, etc.
StringRef Lexer::getSpelling(SourceLocation loc,
- SmallVectorImpl<char> &buffer,
- const SourceManager &SM,
- const LangOptions &options,
- bool *invalid) {
+ SmallVectorImpl<char> &buffer,
+ const SourceManager &SM,
+ const LangOptions &options,
+ bool *invalid) {
// Break down the source location.
std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc);
@@ -267,17 +325,10 @@ StringRef Lexer::getSpelling(SourceLocation loc,
// Common case: no need for cleaning.
if (!token.needsCleaning())
return StringRef(tokenBegin, length);
-
- // Hard case, we need to relex the characters into the string.
- buffer.clear();
- buffer.reserve(length);
-
- for (const char *ti = tokenBegin, *te = ti + length; ti != te; ) {
- unsigned charSize;
- buffer.push_back(Lexer::getCharAndSizeNoWarn(ti, charSize, options));
- ti += charSize;
- }
+ // Hard case, we need to relex the characters into the string.
+ buffer.resize(length);
+ buffer.resize(getSpellingSlow(token, tokenBegin, options, buffer.data()));
return StringRef(buffer.data(), buffer.size());
}
@@ -289,31 +340,22 @@ StringRef Lexer::getSpelling(SourceLocation loc,
std::string Lexer::getSpelling(const Token &Tok, const SourceManager &SourceMgr,
const LangOptions &LangOpts, bool *Invalid) {
assert((int)Tok.getLength() >= 0 && "Token character range is bogus!");
-
- // If this token contains nothing interesting, return it directly.
+
bool CharDataInvalid = false;
- const char* TokStart = SourceMgr.getCharacterData(Tok.getLocation(),
+ const char *TokStart = SourceMgr.getCharacterData(Tok.getLocation(),
&CharDataInvalid);
if (Invalid)
*Invalid = CharDataInvalid;
if (CharDataInvalid)
return std::string();
-
+
+ // If this token contains nothing interesting, return it directly.
if (!Tok.needsCleaning())
- return std::string(TokStart, TokStart+Tok.getLength());
-
+ return std::string(TokStart, TokStart + Tok.getLength());
+
std::string Result;
- Result.reserve(Tok.getLength());
-
- // Otherwise, hard case, relex the characters into the string.
- for (const char *Ptr = TokStart, *End = TokStart+Tok.getLength();
- Ptr != End; ) {
- unsigned CharSize;
- Result.push_back(Lexer::getCharAndSizeNoWarn(Ptr, CharSize, LangOpts));
- Ptr += CharSize;
- }
- assert(Result.size() != unsigned(Tok.getLength()) &&
- "NeedsCleaning flag set on something that didn't need cleaning!");
+ Result.resize(Tok.getLength());
+ Result.resize(getSpellingSlow(Tok, TokStart, LangOpts, &*Result.begin()));
return Result;
}
@@ -336,10 +378,12 @@ unsigned Lexer::getSpelling(const Token &Tok, const char *&Buffer,
// NOTE: this has to be checked *before* testing for an IdentifierInfo.
if (Tok.is(tok::raw_identifier))
TokStart = Tok.getRawIdentifierData();
- else if (const IdentifierInfo *II = Tok.getIdentifierInfo()) {
- // Just return the string from the identifier table, which is very quick.
- Buffer = II->getNameStart();
- return II->getLength();
+ else if (!Tok.hasUCN()) {
+ if (const IdentifierInfo *II = Tok.getIdentifierInfo()) {
+ // Just return the string from the identifier table, which is very quick.
+ Buffer = II->getNameStart();
+ return II->getLength();
+ }
}
// NOTE: this can be checked even after testing for an IdentifierInfo.
@@ -365,23 +409,10 @@ unsigned Lexer::getSpelling(const Token &Tok, const char *&Buffer,
}
// Otherwise, hard case, relex the characters into the string.
- char *OutBuf = const_cast<char*>(Buffer);
- for (const char *Ptr = TokStart, *End = TokStart+Tok.getLength();
- Ptr != End; ) {
- unsigned CharSize;
- *OutBuf++ = Lexer::getCharAndSizeNoWarn(Ptr, CharSize, LangOpts);
- Ptr += CharSize;
- }
- assert(unsigned(OutBuf-Buffer) != Tok.getLength() &&
- "NeedsCleaning flag set on something that didn't need cleaning!");
-
- return OutBuf-Buffer;
+ return getSpellingSlow(Tok, TokStart, LangOpts, const_cast<char*>(Buffer));
}
-
-static bool isWhitespace(unsigned char c);
-
/// MeasureTokenLength - Relex the token at the specified location and return
/// its length in bytes in the input file. If the token needs cleaning (e.g.
/// includes a trigraph or an escaped newline) then this count includes bytes
@@ -389,6 +420,17 @@ static bool isWhitespace(unsigned char c);
unsigned Lexer::MeasureTokenLength(SourceLocation Loc,
const SourceManager &SM,
const LangOptions &LangOpts) {
+ Token TheTok;
+ if (getRawToken(Loc, TheTok, SM, LangOpts))
+ return 0;
+ return TheTok.getLength();
+}
+
+/// \brief Relex the token at the specified location.
+/// \returns true if there was a failure, false on success.
+bool Lexer::getRawToken(SourceLocation Loc, Token &Result,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
// TODO: this could be special cased for common tokens like identifiers, ')',
// etc to make this faster, if it mattered. Just look at StrData[0] to handle
// all obviously single-char tokens. This could use
@@ -402,20 +444,19 @@ unsigned Lexer::MeasureTokenLength(SourceLocation Loc,
bool Invalid = false;
StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid);
if (Invalid)
- return 0;
+ return true;
const char *StrData = Buffer.data()+LocInfo.second;
if (isWhitespace(StrData[0]))
- return 0;
+ return true;
// Create a lexer starting at the beginning of this token.
Lexer TheLexer(SM.getLocForStartOfFile(LocInfo.first), LangOpts,
Buffer.begin(), StrData, Buffer.end());
TheLexer.SetCommentRetentionState(true);
- Token TheTok;
- TheLexer.LexFromRawLexer(TheTok);
- return TheTok.getLength();
+ TheLexer.LexFromRawLexer(Result);
+ return false;
}
static SourceLocation getBeginningOfFileToken(SourceLocation Loc,
@@ -969,163 +1010,8 @@ StringRef Lexer::getImmediateMacroName(SourceLocation Loc,
return ExpansionBuffer.substr(ExpansionInfo.second, MacroTokenLength);
}
-//===----------------------------------------------------------------------===//
-// Character information.
-//===----------------------------------------------------------------------===//
-
-enum {
- CHAR_HORZ_WS = 0x01, // ' ', '\t', '\f', '\v'. Note, no '\0'
- CHAR_VERT_WS = 0x02, // '\r', '\n'
- CHAR_LETTER = 0x04, // a-z,A-Z
- CHAR_NUMBER = 0x08, // 0-9
- CHAR_UNDER = 0x10, // _
- CHAR_PERIOD = 0x20, // .
- CHAR_RAWDEL = 0x40 // {}[]#<>%:;?*+-/^&|~!=,"'
-};
-
-// Statically initialize CharInfo table based on ASCII character set
-// Reference: FreeBSD 7.2 /usr/share/misc/ascii
-static const unsigned char CharInfo[256] =
-{
-// 0 NUL 1 SOH 2 STX 3 ETX
-// 4 EOT 5 ENQ 6 ACK 7 BEL
- 0 , 0 , 0 , 0 ,
- 0 , 0 , 0 , 0 ,
-// 8 BS 9 HT 10 NL 11 VT
-//12 NP 13 CR 14 SO 15 SI
- 0 , CHAR_HORZ_WS, CHAR_VERT_WS, CHAR_HORZ_WS,
- CHAR_HORZ_WS, CHAR_VERT_WS, 0 , 0 ,
-//16 DLE 17 DC1 18 DC2 19 DC3
-//20 DC4 21 NAK 22 SYN 23 ETB
- 0 , 0 , 0 , 0 ,
- 0 , 0 , 0 , 0 ,
-//24 CAN 25 EM 26 SUB 27 ESC
-//28 FS 29 GS 30 RS 31 US
- 0 , 0 , 0 , 0 ,
- 0 , 0 , 0 , 0 ,
-//32 SP 33 ! 34 " 35 #
-//36 $ 37 % 38 & 39 '
- CHAR_HORZ_WS, CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL ,
- 0 , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL ,
-//40 ( 41 ) 42 * 43 +
-//44 , 45 - 46 . 47 /
- 0 , 0 , CHAR_RAWDEL , CHAR_RAWDEL ,
- CHAR_RAWDEL , CHAR_RAWDEL , CHAR_PERIOD , CHAR_RAWDEL ,
-//48 0 49 1 50 2 51 3
-//52 4 53 5 54 6 55 7
- CHAR_NUMBER , CHAR_NUMBER , CHAR_NUMBER , CHAR_NUMBER ,
- CHAR_NUMBER , CHAR_NUMBER , CHAR_NUMBER , CHAR_NUMBER ,
-//56 8 57 9 58 : 59 ;
-//60 < 61 = 62 > 63 ?
- CHAR_NUMBER , CHAR_NUMBER , CHAR_RAWDEL , CHAR_RAWDEL ,
- CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL ,
-//64 @ 65 A 66 B 67 C
-//68 D 69 E 70 F 71 G
- 0 , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
- CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
-//72 H 73 I 74 J 75 K
-//76 L 77 M 78 N 79 O
- CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
- CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
-//80 P 81 Q 82 R 83 S
-//84 T 85 U 86 V 87 W
- CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
- CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
-//88 X 89 Y 90 Z 91 [
-//92 \ 93 ] 94 ^ 95 _
- CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_RAWDEL ,
- 0 , CHAR_RAWDEL , CHAR_RAWDEL , CHAR_UNDER ,
-//96 ` 97 a 98 b 99 c
-//100 d 101 e 102 f 103 g
- 0 , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
- CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
-//104 h 105 i 106 j 107 k
-//108 l 109 m 110 n 111 o
- CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
- CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
-//112 p 113 q 114 r 115 s
-//116 t 117 u 118 v 119 w
- CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
- CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_LETTER ,
-//120 x 121 y 122 z 123 {
-//124 | 125 } 126 ~ 127 DEL
- CHAR_LETTER , CHAR_LETTER , CHAR_LETTER , CHAR_RAWDEL ,
- CHAR_RAWDEL , CHAR_RAWDEL , CHAR_RAWDEL , 0
-};
-
-static void InitCharacterInfo() {
- static bool isInited = false;
- if (isInited) return;
- // check the statically-initialized CharInfo table
- assert(CHAR_HORZ_WS == CharInfo[(int)' ']);
- assert(CHAR_HORZ_WS == CharInfo[(int)'\t']);
- assert(CHAR_HORZ_WS == CharInfo[(int)'\f']);
- assert(CHAR_HORZ_WS == CharInfo[(int)'\v']);
- assert(CHAR_VERT_WS == CharInfo[(int)'\n']);
- assert(CHAR_VERT_WS == CharInfo[(int)'\r']);
- assert(CHAR_UNDER == CharInfo[(int)'_']);
- assert(CHAR_PERIOD == CharInfo[(int)'.']);
- for (unsigned i = 'a'; i <= 'z'; ++i) {
- assert(CHAR_LETTER == CharInfo[i]);
- assert(CHAR_LETTER == CharInfo[i+'A'-'a']);
- }
- for (unsigned i = '0'; i <= '9'; ++i)
- assert(CHAR_NUMBER == CharInfo[i]);
-
- isInited = true;
-}
-
-
-/// isIdentifierHead - Return true if this is the first character of an
-/// identifier, which is [a-zA-Z_].
-static inline bool isIdentifierHead(unsigned char c) {
- return (CharInfo[c] & (CHAR_LETTER|CHAR_UNDER)) ? true : false;
-}
-
-/// isIdentifierBody - Return true if this is the body character of an
-/// identifier, which is [a-zA-Z0-9_].
-static inline bool isIdentifierBody(unsigned char c) {
- return (CharInfo[c] & (CHAR_LETTER|CHAR_NUMBER|CHAR_UNDER)) ? true : false;
-}
-
-/// isHorizontalWhitespace - Return true if this character is horizontal
-/// whitespace: ' ', '\\t', '\\f', '\\v'. Note that this returns false for
-/// '\\0'.
-static inline bool isHorizontalWhitespace(unsigned char c) {
- return (CharInfo[c] & CHAR_HORZ_WS) ? true : false;
-}
-
-/// isVerticalWhitespace - Return true if this character is vertical
-/// whitespace: '\\n', '\\r'. Note that this returns false for '\\0'.
-static inline bool isVerticalWhitespace(unsigned char c) {
- return (CharInfo[c] & CHAR_VERT_WS) ? true : false;
-}
-
-/// isWhitespace - Return true if this character is horizontal or vertical
-/// whitespace: ' ', '\\t', '\\f', '\\v', '\\n', '\\r'. Note that this returns
-/// false for '\\0'.
-static inline bool isWhitespace(unsigned char c) {
- return (CharInfo[c] & (CHAR_HORZ_WS|CHAR_VERT_WS)) ? true : false;
-}
-
-/// isNumberBody - Return true if this is the body character of an
-/// preprocessing number, which is [a-zA-Z0-9_.].
-static inline bool isNumberBody(unsigned char c) {
- return (CharInfo[c] & (CHAR_LETTER|CHAR_NUMBER|CHAR_UNDER|CHAR_PERIOD)) ?
- true : false;
-}
-
-/// isRawStringDelimBody - Return true if this is the body character of a
-/// raw string delimiter.
-static inline bool isRawStringDelimBody(unsigned char c) {
- return (CharInfo[c] &
- (CHAR_LETTER|CHAR_NUMBER|CHAR_UNDER|CHAR_PERIOD|CHAR_RAWDEL)) ?
- true : false;
-}
-
-// Allow external clients to make use of CharInfo.
bool Lexer::isIdentifierBodyChar(char c, const LangOptions &LangOpts) {
- return isIdentifierBody(c) || (c == '$' && LangOpts.DollarIdents);
+ return isIdentifierBody(c, LangOpts.DollarIdents);
}
@@ -1293,7 +1179,7 @@ SourceLocation Lexer::findLocationAfterToken(SourceLocation Loc,
// Try to load the file buffer.
bool InvalidTemp = false;
- llvm::StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp);
+ StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp);
if (InvalidTemp)
return SourceLocation();
@@ -1319,8 +1205,15 @@ SourceLocation Lexer::findLocationAfterToken(SourceLocation Loc,
C = *(++TokenEnd);
NumWhitespaceChars++;
}
- if (isVerticalWhitespace(C))
+
+ // Skip \r, \n, \r\n, or \n\r
+ if (C == '\n' || C == '\r') {
+ char PrevC = C;
+ C = *(++TokenEnd);
NumWhitespaceChars++;
+ if ((C == '\n' || C == '\r') && C != PrevC)
+ NumWhitespaceChars++;
+ }
}
return TokenLoc.getLocWithOffset(Tok.getLength() + NumWhitespaceChars);
@@ -1334,7 +1227,6 @@ SourceLocation Lexer::findLocationAfterToken(SourceLocation Loc,
/// 2. If this is an escaped newline (potentially with whitespace between
/// the backslash and newline), implicitly skip the newline and return
/// the char after it.
-/// 3. If this is a UCN, return it. FIXME: C++ UCN's?
///
/// This handles the slow/uncommon case of the getCharAndSize method. Here we
/// know that we can accumulate into Size, and that we have already incremented
@@ -1467,6 +1359,62 @@ void Lexer::SkipBytes(unsigned Bytes, bool StartOfLine) {
IsAtStartOfLine = StartOfLine;
}
+static bool isAllowedIDChar(uint32_t C, const LangOptions &LangOpts) {
+ if (LangOpts.CPlusPlus11 || LangOpts.C11)
+ return isCharInSet(C, C11AllowedIDChars);
+ else if (LangOpts.CPlusPlus)
+ return isCharInSet(C, CXX03AllowedIDChars);
+ else
+ return isCharInSet(C, C99AllowedIDChars);
+}
+
+static bool isAllowedInitiallyIDChar(uint32_t C, const LangOptions &LangOpts) {
+ assert(isAllowedIDChar(C, LangOpts));
+ if (LangOpts.CPlusPlus11 || LangOpts.C11)
+ return !isCharInSet(C, C11DisallowedInitialIDChars);
+ else if (LangOpts.CPlusPlus)
+ return true;
+ else
+ return !isCharInSet(C, C99DisallowedInitialIDChars);
+}
+
+static inline CharSourceRange makeCharRange(Lexer &L, const char *Begin,
+ const char *End) {
+ return CharSourceRange::getCharRange(L.getSourceLocation(Begin),
+ L.getSourceLocation(End));
+}
+
+static void maybeDiagnoseIDCharCompat(DiagnosticsEngine &Diags, uint32_t C,
+ CharSourceRange Range, bool IsFirst) {
+ // Check C99 compatibility.
+ if (Diags.getDiagnosticLevel(diag::warn_c99_compat_unicode_id,
+ Range.getBegin()) > DiagnosticsEngine::Ignored) {
+ enum {
+ CannotAppearInIdentifier = 0,
+ CannotStartIdentifier
+ };
+
+ if (!isCharInSet(C, C99AllowedIDChars)) {
+ Diags.Report(Range.getBegin(), diag::warn_c99_compat_unicode_id)
+ << Range
+ << CannotAppearInIdentifier;
+ } else if (IsFirst && isCharInSet(C, C99DisallowedInitialIDChars)) {
+ Diags.Report(Range.getBegin(), diag::warn_c99_compat_unicode_id)
+ << Range
+ << CannotStartIdentifier;
+ }
+ }
+
+ // Check C++98 compatibility.
+ if (Diags.getDiagnosticLevel(diag::warn_cxx98_compat_unicode_id,
+ Range.getBegin()) > DiagnosticsEngine::Ignored) {
+ if (!isCharInSet(C, CXX03AllowedIDChars)) {
+ Diags.Report(Range.getBegin(), diag::warn_cxx98_compat_unicode_id)
+ << Range;
+ }
+ }
+ }
+
void Lexer::LexIdentifier(Token &Result, const char *CurPtr) {
// Match [_A-Za-z0-9]*, we have already matched [_A-Za-z$]
unsigned Size;
@@ -1478,11 +1426,11 @@ void Lexer::LexIdentifier(Token &Result, const char *CurPtr) {
// Fast path, no $,\,? in identifier found. '\' might be an escaped newline
// or UCN, and ? might be a trigraph for '\', an escaped newline or UCN.
- // FIXME: UCNs.
//
- // TODO: Could merge these checks into a CharInfo flag to make the comparison
- // cheaper
- if (C != '\\' && C != '?' && (C != '$' || !LangOpts.DollarIdents)) {
+ // TODO: Could merge these checks into an InfoTable flag to make the
+ // comparison cheaper
+ if (isASCII(C) && C != '\\' && C != '?' &&
+ (C != '$' || !LangOpts.DollarIdents)) {
FinishIdentifier:
const char *IdStart = BufferPtr;
FormTokenWithChars(Result, CurPtr, tok::raw_identifier);
@@ -1519,8 +1467,51 @@ FinishIdentifier:
CurPtr = ConsumeChar(CurPtr, Size, Result);
C = getCharAndSize(CurPtr, Size);
continue;
- } else if (!isIdentifierBody(C)) { // FIXME: UCNs.
- // Found end of identifier.
+
+ } else if (C == '\\') {
+ const char *UCNPtr = CurPtr + Size;
+ uint32_t CodePoint = tryReadUCN(UCNPtr, CurPtr, /*Token=*/0);
+ if (CodePoint == 0 || !isAllowedIDChar(CodePoint, LangOpts))
+ goto FinishIdentifier;
+
+ if (!isLexingRawMode()) {
+ maybeDiagnoseIDCharCompat(PP->getDiagnostics(), CodePoint,
+ makeCharRange(*this, CurPtr, UCNPtr),
+ /*IsFirst=*/false);
+ }
+
+ Result.setFlag(Token::HasUCN);
+ if ((UCNPtr - CurPtr == 6 && CurPtr[1] == 'u') ||
+ (UCNPtr - CurPtr == 10 && CurPtr[1] == 'U'))
+ CurPtr = UCNPtr;
+ else
+ while (CurPtr != UCNPtr)
+ (void)getAndAdvanceChar(CurPtr, Result);
+
+ C = getCharAndSize(CurPtr, Size);
+ continue;
+ } else if (!isASCII(C)) {
+ const char *UnicodePtr = CurPtr;
+ UTF32 CodePoint;
+ ConversionResult Result =
+ llvm::convertUTF8Sequence((const UTF8 **)&UnicodePtr,
+ (const UTF8 *)BufferEnd,
+ &CodePoint,
+ strictConversion);
+ if (Result != conversionOK ||
+ !isAllowedIDChar(static_cast<uint32_t>(CodePoint), LangOpts))
+ goto FinishIdentifier;
+
+ if (!isLexingRawMode()) {
+ maybeDiagnoseIDCharCompat(PP->getDiagnostics(), CodePoint,
+ makeCharRange(*this, CurPtr, UnicodePtr),
+ /*IsFirst=*/false);
+ }
+
+ CurPtr = UnicodePtr;
+ C = getCharAndSize(CurPtr, Size);
+ continue;
+ } else if (!isIdentifierBody(C)) {
goto FinishIdentifier;
}
@@ -1528,7 +1519,7 @@ FinishIdentifier:
CurPtr = ConsumeChar(CurPtr, Size, Result);
C = getCharAndSize(CurPtr, Size);
- while (isIdentifierBody(C)) { // FIXME: UCNs.
+ while (isIdentifierBody(C)) {
CurPtr = ConsumeChar(CurPtr, Size, Result);
C = getCharAndSize(CurPtr, Size);
}
@@ -1553,7 +1544,7 @@ void Lexer::LexNumericConstant(Token &Result, const char *CurPtr) {
unsigned Size;
char C = getCharAndSize(CurPtr, Size);
char PrevCh = 0;
- while (isNumberBody(C)) { // FIXME: UCNs.
+ while (isPreprocessingNumberBody(C)) { // FIXME: UCNs in ud-suffix.
CurPtr = ConsumeChar(CurPtr, Size, Result);
PrevCh = C;
C = getCharAndSize(CurPtr, Size);
@@ -1598,7 +1589,7 @@ const char *Lexer::LexUDSuffix(Token &Result, const char *CurPtr) {
unsigned Size;
char C = getCharAndSize(CurPtr, Size);
if (isIdentifierHead(C)) {
- if (!getLangOpts().CPlusPlus0x) {
+ if (!getLangOpts().CPlusPlus11) {
if (!isLexingRawMode())
Diag(CurPtr,
C == '_' ? diag::warn_cxx11_compat_user_defined_literal
@@ -1639,7 +1630,9 @@ void Lexer::LexStringLiteral(Token &Result, const char *CurPtr,
(Kind == tok::utf8_string_literal ||
Kind == tok::utf16_string_literal ||
Kind == tok::utf32_string_literal))
- Diag(BufferPtr, diag::warn_cxx98_compat_unicode_literal);
+ Diag(BufferPtr, getLangOpts().CPlusPlus
+ ? diag::warn_cxx98_compat_unicode_literal
+ : diag::warn_c99_compat_unicode_literal);
char C = getAndAdvanceChar(CurPtr, Result);
while (C != '"') {
@@ -1804,7 +1797,9 @@ void Lexer::LexCharConstant(Token &Result, const char *CurPtr,
if (!isLexingRawMode() &&
(Kind == tok::utf16_char_constant || Kind == tok::utf32_char_constant))
- Diag(BufferPtr, diag::warn_cxx98_compat_unicode_literal);
+ Diag(BufferPtr, getLangOpts().CPlusPlus
+ ? diag::warn_cxx98_compat_unicode_literal
+ : diag::warn_c99_compat_unicode_literal);
char C = getAndAdvanceChar(CurPtr, Result);
if (C == '\'') {
@@ -1860,6 +1855,8 @@ void Lexer::LexCharConstant(Token &Result, const char *CurPtr,
///
bool Lexer::SkipWhitespace(Token &Result, const char *CurPtr) {
// Whitespace - Skip it, then return the token after the whitespace.
+ bool SawNewline = isVerticalWhitespace(CurPtr[-1]);
+
unsigned char Char = *CurPtr; // Skip consequtive spaces efficiently.
while (1) {
// Skip horizontal whitespace very aggressively.
@@ -1867,7 +1864,7 @@ bool Lexer::SkipWhitespace(Token &Result, const char *CurPtr) {
Char = *++CurPtr;
// Otherwise if we have something other than whitespace, we're done.
- if (Char != '\n' && Char != '\r')
+ if (!isVerticalWhitespace(Char))
break;
if (ParsingPreprocessorDirective) {
@@ -1877,24 +1874,27 @@ bool Lexer::SkipWhitespace(Token &Result, const char *CurPtr) {
}
// ok, but handle newline.
- // The returned token is at the start of the line.
- Result.setFlag(Token::StartOfLine);
- // No leading whitespace seen so far.
- Result.clearFlag(Token::LeadingSpace);
+ SawNewline = true;
Char = *++CurPtr;
}
- // If this isn't immediately after a newline, there is leading space.
- char PrevChar = CurPtr[-1];
- if (PrevChar != '\n' && PrevChar != '\r')
- Result.setFlag(Token::LeadingSpace);
-
// If the client wants us to return whitespace, return it now.
if (isKeepWhitespaceMode()) {
FormTokenWithChars(Result, CurPtr, tok::unknown);
+ if (SawNewline)
+ IsAtStartOfLine = true;
+ // FIXME: The next token will not have LeadingSpace set.
return true;
}
+ // If this isn't immediately after a newline, there is leading space.
+ char PrevChar = CurPtr[-1];
+ bool HasLeadingSpace = !isVerticalWhitespace(PrevChar);
+
+ Result.setFlagValue(Token::LeadingSpace, HasLeadingSpace);
+ if (SawNewline)
+ Result.setFlag(Token::StartOfLine);
+
BufferPtr = CurPtr;
return false;
}
@@ -2285,7 +2285,6 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) {
// efficiently now. This is safe even in KeepWhitespaceMode because we would
// have already returned above with the comment as a token.
if (isHorizontalWhitespace(*CurPtr)) {
- Result.setFlag(Token::LeadingSpace);
SkipWhitespace(Result, CurPtr+1);
return false;
}
@@ -2367,7 +2366,7 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
FormTokenWithChars(Result, CurPtr, tok::eod);
// Restore comment saving mode, in case it was disabled for directive.
- SetCommentRetentionState(PP->getCommentRetentionState());
+ resetExtendedTokenMode();
return true; // Have a token.
}
@@ -2393,7 +2392,7 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
// C99 5.1.1.2p2: If the file is non-empty and didn't end in a newline, issue
// a pedwarn.
if (CurPtr != BufferStart && (CurPtr[-1] != '\n' && CurPtr[-1] != '\r'))
- Diag(BufferEnd, LangOpts.CPlusPlus0x ? // C++11 [lex.phases] 2.2 p2
+ Diag(BufferEnd, LangOpts.CPlusPlus11 ? // C++11 [lex.phases] 2.2 p2
diag::warn_cxx98_compat_no_newline_eof : diag::ext_no_newline_eof)
<< FixItHint::CreateInsertion(getSourceLocation(BufferEnd), "\n");
@@ -2550,6 +2549,164 @@ bool Lexer::isCodeCompletionPoint(const char *CurPtr) const {
return false;
}
+uint32_t Lexer::tryReadUCN(const char *&StartPtr, const char *SlashLoc,
+ Token *Result) {
+ unsigned CharSize;
+ char Kind = getCharAndSize(StartPtr, CharSize);
+
+ unsigned NumHexDigits;
+ if (Kind == 'u')
+ NumHexDigits = 4;
+ else if (Kind == 'U')
+ NumHexDigits = 8;
+ else
+ return 0;
+
+ if (!LangOpts.CPlusPlus && !LangOpts.C99) {
+ if (Result && !isLexingRawMode())
+ Diag(SlashLoc, diag::warn_ucn_not_valid_in_c89);
+ return 0;
+ }
+
+ const char *CurPtr = StartPtr + CharSize;
+ const char *KindLoc = &CurPtr[-1];
+
+ uint32_t CodePoint = 0;
+ for (unsigned i = 0; i < NumHexDigits; ++i) {
+ char C = getCharAndSize(CurPtr, CharSize);
+
+ unsigned Value = llvm::hexDigitValue(C);
+ if (Value == -1U) {
+ if (Result && !isLexingRawMode()) {
+ if (i == 0) {
+ Diag(BufferPtr, diag::warn_ucn_escape_no_digits)
+ << StringRef(KindLoc, 1);
+ } else {
+ Diag(BufferPtr, diag::warn_ucn_escape_incomplete);
+
+ // If the user wrote \U1234, suggest a fixit to \u.
+ if (i == 4 && NumHexDigits == 8) {
+ CharSourceRange URange = makeCharRange(*this, KindLoc, KindLoc + 1);
+ Diag(KindLoc, diag::note_ucn_four_not_eight)
+ << FixItHint::CreateReplacement(URange, "u");
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ CodePoint <<= 4;
+ CodePoint += Value;
+
+ CurPtr += CharSize;
+ }
+
+ if (Result) {
+ Result->setFlag(Token::HasUCN);
+ if (CurPtr - StartPtr == (ptrdiff_t)NumHexDigits + 2)
+ StartPtr = CurPtr;
+ else
+ while (StartPtr != CurPtr)
+ (void)getAndAdvanceChar(StartPtr, *Result);
+ } else {
+ StartPtr = CurPtr;
+ }
+
+ // C99 6.4.3p2: A universal character name shall not specify a character whose
+ // short identifier is less than 00A0 other than 0024 ($), 0040 (@), or
+ // 0060 (`), nor one in the range D800 through DFFF inclusive.)
+ // C++11 [lex.charset]p2: If the hexadecimal value for a
+ // universal-character-name corresponds to a surrogate code point (in the
+ // range 0xD800-0xDFFF, inclusive), the program is ill-formed. Additionally,
+ // if the hexadecimal value for a universal-character-name outside the
+ // c-char-sequence, s-char-sequence, or r-char-sequence of a character or
+ // string literal corresponds to a control character (in either of the
+ // ranges 0x00-0x1F or 0x7F-0x9F, both inclusive) or to a character in the
+ // basic source character set, the program is ill-formed.
+ if (CodePoint < 0xA0) {
+ if (CodePoint == 0x24 || CodePoint == 0x40 || CodePoint == 0x60)
+ return CodePoint;
+
+ // We don't use isLexingRawMode() here because we need to warn about bad
+ // UCNs even when skipping preprocessing tokens in a #if block.
+ if (Result && PP) {
+ if (CodePoint < 0x20 || CodePoint >= 0x7F)
+ Diag(BufferPtr, diag::err_ucn_control_character);
+ else {
+ char C = static_cast<char>(CodePoint);
+ Diag(BufferPtr, diag::err_ucn_escape_basic_scs) << StringRef(&C, 1);
+ }
+ }
+
+ return 0;
+
+ } else if (CodePoint >= 0xD800 && CodePoint <= 0xDFFF) {
+ // C++03 allows UCNs representing surrogate characters. C99 and C++11 don't.
+ // We don't use isLexingRawMode() here because we need to diagnose bad
+ // UCNs even when skipping preprocessing tokens in a #if block.
+ if (Result && PP) {
+ if (LangOpts.CPlusPlus && !LangOpts.CPlusPlus11)
+ Diag(BufferPtr, diag::warn_ucn_escape_surrogate);
+ else
+ Diag(BufferPtr, diag::err_ucn_escape_invalid);
+ }
+ return 0;
+ }
+
+ return CodePoint;
+}
+
+void Lexer::LexUnicode(Token &Result, uint32_t C, const char *CurPtr) {
+ if (!isLexingRawMode() && !PP->isPreprocessedOutput() &&
+ isCharInSet(C, UnicodeWhitespaceChars)) {
+ Diag(BufferPtr, diag::ext_unicode_whitespace)
+ << makeCharRange(*this, BufferPtr, CurPtr);
+
+ Result.setFlag(Token::LeadingSpace);
+ if (SkipWhitespace(Result, CurPtr))
+ return; // KeepWhitespaceMode
+
+ return LexTokenInternal(Result);
+ }
+
+ if (isAllowedIDChar(C, LangOpts) && isAllowedInitiallyIDChar(C, LangOpts)) {
+ if (!isLexingRawMode() && !ParsingPreprocessorDirective &&
+ !PP->isPreprocessedOutput()) {
+ maybeDiagnoseIDCharCompat(PP->getDiagnostics(), C,
+ makeCharRange(*this, BufferPtr, CurPtr),
+ /*IsFirst=*/true);
+ }
+
+ MIOpt.ReadToken();
+ return LexIdentifier(Result, CurPtr);
+ }
+
+ if (!isLexingRawMode() && !ParsingPreprocessorDirective &&
+ !PP->isPreprocessedOutput() &&
+ !isASCII(*BufferPtr) && !isAllowedIDChar(C, LangOpts)) {
+ // Non-ASCII characters tend to creep into source code unintentionally.
+ // Instead of letting the parser complain about the unknown token,
+ // just drop the character.
+ // Note that we can /only/ do this when the non-ASCII character is actually
+ // spelled as Unicode, not written as a UCN. The standard requires that
+ // we not throw away any possible preprocessor tokens, but there's a
+ // loophole in the mapping of Unicode characters to basic character set
+ // characters that allows us to map these particular characters to, say,
+ // whitespace.
+ Diag(BufferPtr, diag::err_non_ascii)
+ << FixItHint::CreateRemoval(makeCharRange(*this, BufferPtr, CurPtr));
+
+ BufferPtr = CurPtr;
+ return LexTokenInternal(Result);
+ }
+
+ // Otherwise, we have an explicit UCN or a character that's unlikely to show
+ // up by accident.
+ MIOpt.ReadToken();
+ FormTokenWithChars(Result, CurPtr, tok::unknown);
+}
+
/// LexTokenInternal - This implements a simple C family lexer. It is an
/// extremely performance critical piece of code. This assumes that the buffer
@@ -2576,6 +2733,7 @@ LexNextToken:
// whitespace.
if (isKeepWhitespaceMode()) {
FormTokenWithChars(Result, CurPtr, tok::unknown);
+ // FIXME: The next token will not have LeadingSpace set.
return;
}
@@ -2643,7 +2801,7 @@ LexNextToken:
// Restore comment saving mode, in case it was disabled for directive.
if (PP)
- SetCommentRetentionState(PP->getCommentRetentionState());
+ resetExtendedTokenMode();
// Since we consumed a newline, we are back at the start of a line.
IsAtStartOfLine = true;
@@ -2651,8 +2809,7 @@ LexNextToken:
Kind = tok::eod;
break;
}
- // The returned token is at the start of the line.
- Result.setFlag(Token::StartOfLine);
+
// No leading whitespace seen so far.
Result.clearFlag(Token::LeadingSpace);
@@ -2695,11 +2852,11 @@ LexNextToken:
MIOpt.ReadToken();
return LexNumericConstant(Result, CurPtr);
- case 'u': // Identifier (uber) or C++0x UTF-8 or UTF-16 string literal
+ case 'u': // Identifier (uber) or C11/C++11 UTF-8 or UTF-16 string literal
// Notify MIOpt that we read a non-whitespace/non-comment token.
MIOpt.ReadToken();
- if (LangOpts.CPlusPlus0x) {
+ if (LangOpts.CPlusPlus11 || LangOpts.C11) {
Char = getCharAndSize(CurPtr, SizeTmp);
// UTF-16 string literal
@@ -2713,7 +2870,8 @@ LexNextToken:
tok::utf16_char_constant);
// UTF-16 raw string literal
- if (Char == 'R' && getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"')
+ if (Char == 'R' && LangOpts.CPlusPlus11 &&
+ getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"')
return LexRawStringLiteral(Result,
ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result),
@@ -2729,7 +2887,7 @@ LexNextToken:
SizeTmp2, Result),
tok::utf8_string_literal);
- if (Char2 == 'R') {
+ if (Char2 == 'R' && LangOpts.CPlusPlus11) {
unsigned SizeTmp3;
char Char3 = getCharAndSize(CurPtr + SizeTmp + SizeTmp2, SizeTmp3);
// UTF-8 raw string literal
@@ -2747,11 +2905,11 @@ LexNextToken:
// treat u like the start of an identifier.
return LexIdentifier(Result, CurPtr);
- case 'U': // Identifier (Uber) or C++0x UTF-32 string literal
+ case 'U': // Identifier (Uber) or C11/C++11 UTF-32 string literal
// Notify MIOpt that we read a non-whitespace/non-comment token.
MIOpt.ReadToken();
- if (LangOpts.CPlusPlus0x) {
+ if (LangOpts.CPlusPlus11 || LangOpts.C11) {
Char = getCharAndSize(CurPtr, SizeTmp);
// UTF-32 string literal
@@ -2765,7 +2923,8 @@ LexNextToken:
tok::utf32_char_constant);
// UTF-32 raw string literal
- if (Char == 'R' && getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"')
+ if (Char == 'R' && LangOpts.CPlusPlus11 &&
+ getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"')
return LexRawStringLiteral(Result,
ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
SizeTmp2, Result),
@@ -2779,7 +2938,7 @@ LexNextToken:
// Notify MIOpt that we read a non-whitespace/non-comment token.
MIOpt.ReadToken();
- if (LangOpts.CPlusPlus0x) {
+ if (LangOpts.CPlusPlus11) {
Char = getCharAndSize(CurPtr, SizeTmp);
if (Char == '"')
@@ -2802,7 +2961,7 @@ LexNextToken:
tok::wide_string_literal);
// Wide raw string literal.
- if (LangOpts.CPlusPlus0x && Char == 'R' &&
+ if (LangOpts.CPlusPlus11 && Char == 'R' &&
getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == '"')
return LexRawStringLiteral(Result,
ConsumeChar(ConsumeChar(CurPtr, SizeTmp, Result),
@@ -2968,10 +3127,13 @@ LexNextToken:
// this as "foo / bar" and langauges with Line comments would lex it as
// "foo". Check to see if the character after the second slash is a '*'.
// If so, we will lex that as a "/" instead of the start of a comment.
- // However, we never do this in -traditional-cpp mode.
- if ((LangOpts.LineComment ||
- getCharAndSize(CurPtr+SizeTmp, SizeTmp2) != '*') &&
- !LangOpts.TraditionalCPP) {
+ // However, we never do this if we are just preprocessing.
+ bool TreatAsComment = LangOpts.LineComment && !LangOpts.TraditionalCPP;
+ if (!TreatAsComment)
+ if (!(PP && PP->isPreprocessedOutput()))
+ TreatAsComment = getCharAndSize(CurPtr+SizeTmp, SizeTmp2) != '*';
+
+ if (TreatAsComment) {
if (SkipLineComment(Result, ConsumeChar(CurPtr, SizeTmp, Result)))
return; // There is a token to return.
@@ -3020,26 +3182,8 @@ LexNextToken:
// it's actually the start of a preprocessing directive. Callback to
// the preprocessor to handle it.
// FIXME: -fpreprocessed mode??
- if (Result.isAtStartOfLine() && !LexingRawMode && !Is_PragmaLexer) {
- FormTokenWithChars(Result, CurPtr, tok::hash);
- PP->HandleDirective(Result);
-
- // As an optimization, if the preprocessor didn't switch lexers, tail
- // recurse.
- if (PP->isCurrentLexer(this)) {
- // Start a new token. If this is a #include or something, the PP may
- // want us starting at the beginning of the line again. If so, set
- // the StartOfLine flag and clear LeadingSpace.
- if (IsAtStartOfLine) {
- Result.setFlag(Token::StartOfLine);
- Result.clearFlag(Token::LeadingSpace);
- IsAtStartOfLine = false;
- }
- goto LexNextToken; // GCC isn't tail call eliminating.
- }
-
- return PP->Lex(Result);
- }
+ if (Result.isAtStartOfLine() && !LexingRawMode && !Is_PragmaLexer)
+ goto HandleDirective;
Kind = tok::hash;
}
@@ -3077,7 +3221,7 @@ LexNextToken:
CurPtr = ConsumeChar(CurPtr, SizeTmp, Result);
Kind = tok::lessequal;
} else if (LangOpts.Digraphs && Char == ':') { // '<:' -> '['
- if (LangOpts.CPlusPlus0x &&
+ if (LangOpts.CPlusPlus11 &&
getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == ':') {
// C++0x [lex.pptoken]p3:
// Otherwise, if the next three characters are <:: and the subsequent
@@ -3204,25 +3348,8 @@ LexNextToken:
// it's actually the start of a preprocessing directive. Callback to
// the preprocessor to handle it.
// FIXME: -fpreprocessed mode??
- if (Result.isAtStartOfLine() && !LexingRawMode && !Is_PragmaLexer) {
- FormTokenWithChars(Result, CurPtr, tok::hash);
- PP->HandleDirective(Result);
-
- // As an optimization, if the preprocessor didn't switch lexers, tail
- // recurse.
- if (PP->isCurrentLexer(this)) {
- // Start a new token. If this is a #include or something, the PP may
- // want us starting at the beginning of the line again. If so, set
- // the StartOfLine flag and clear LeadingSpace.
- if (IsAtStartOfLine) {
- Result.setFlag(Token::StartOfLine);
- Result.clearFlag(Token::LeadingSpace);
- IsAtStartOfLine = false;
- }
- goto LexNextToken; // GCC isn't tail call eliminating.
- }
- return PP->Lex(Result);
- }
+ if (Result.isAtStartOfLine() && !LexingRawMode && !Is_PragmaLexer)
+ goto HandleDirective;
Kind = tok::hash;
}
@@ -3236,12 +3363,48 @@ LexNextToken:
Kind = tok::unknown;
break;
+ // UCNs (C99 6.4.3, C++11 [lex.charset]p2)
case '\\':
- // FIXME: UCN's.
- // FALL THROUGH.
- default:
+ if (uint32_t CodePoint = tryReadUCN(CurPtr, BufferPtr, &Result))
+ return LexUnicode(Result, CodePoint, CurPtr);
+
Kind = tok::unknown;
break;
+
+ default: {
+ if (isASCII(Char)) {
+ Kind = tok::unknown;
+ break;
+ }
+
+ UTF32 CodePoint;
+
+ // We can't just reset CurPtr to BufferPtr because BufferPtr may point to
+ // an escaped newline.
+ --CurPtr;
+ ConversionResult Status =
+ llvm::convertUTF8Sequence((const UTF8 **)&CurPtr,
+ (const UTF8 *)BufferEnd,
+ &CodePoint,
+ strictConversion);
+ if (Status == conversionOK)
+ return LexUnicode(Result, CodePoint, CurPtr);
+
+ if (isLexingRawMode() || ParsingPreprocessorDirective ||
+ PP->isPreprocessedOutput()) {
+ ++CurPtr;
+ Kind = tok::unknown;
+ break;
+ }
+
+ // Non-ASCII characters tend to creep into source code unintentionally.
+ // Instead of letting the parser complain about the unknown token,
+ // just diagnose the invalid UTF-8, then drop the character.
+ Diag(CurPtr, diag::err_invalid_utf8);
+
+ BufferPtr = CurPtr+1;
+ goto LexNextToken;
+ }
}
// Notify MIOpt that we read a non-whitespace/non-comment token.
@@ -3249,4 +3412,26 @@ LexNextToken:
// Update the location of token as well as BufferPtr.
FormTokenWithChars(Result, CurPtr, Kind);
+ return;
+
+HandleDirective:
+ // We parsed a # character and it's the start of a preprocessing directive.
+
+ FormTokenWithChars(Result, CurPtr, tok::hash);
+ PP->HandleDirective(Result);
+
+ // As an optimization, if the preprocessor didn't switch lexers, tail
+ // recurse.
+ if (PP->isCurrentLexer(this)) {
+ // Start a new token. If this is a #include or something, the PP may
+ // want us starting at the beginning of the line again. If so, set
+ // the StartOfLine flag and clear LeadingSpace.
+ if (IsAtStartOfLine) {
+ Result.setFlag(Token::StartOfLine);
+ Result.clearFlag(Token::LeadingSpace);
+ IsAtStartOfLine = false;
+ }
+ goto LexNextToken; // GCC isn't tail call eliminating.
+ }
+ return PP->Lex(Result);
}
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index e30612e..91da822 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -13,22 +13,15 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/LiteralSupport.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/Basic/ConvertUTF.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/ErrorHandling.h"
-using namespace clang;
-/// HexDigitValue - Return the value of the specified hex digit, or -1 if it's
-/// not valid.
-static int HexDigitValue(char C) {
- if (C >= '0' && C <= '9') return C-'0';
- if (C >= 'a' && C <= 'f') return C-'a'+10;
- if (C >= 'A' && C <= 'F') return C-'A'+10;
- return -1;
-}
+using namespace clang;
static unsigned getCharWidth(tok::TokenKind kind, const TargetInfo &Target) {
switch (kind) {
@@ -136,10 +129,10 @@ static unsigned ProcessCharEscape(const char *ThisTokBegin,
break;
case 'x': { // Hex escape.
ResultChar = 0;
- if (ThisTokBuf == ThisTokEnd || !isxdigit(*ThisTokBuf)) {
+ if (ThisTokBuf == ThisTokEnd || !isHexDigit(*ThisTokBuf)) {
if (Diags)
Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
- diag::err_hex_escape_no_digits);
+ diag::err_hex_escape_no_digits) << "x";
HadError = 1;
break;
}
@@ -147,7 +140,7 @@ static unsigned ProcessCharEscape(const char *ThisTokBegin,
// Hex escapes are a maximal series of hex digits.
bool Overflow = false;
for (; ThisTokBuf != ThisTokEnd; ++ThisTokBuf) {
- int CharVal = HexDigitValue(ThisTokBuf[0]);
+ int CharVal = llvm::hexDigitValue(ThisTokBuf[0]);
if (CharVal == -1) break;
// About to shift out a digit?
Overflow |= (ResultChar & 0xF0000000) ? true : false;
@@ -205,7 +198,7 @@ static unsigned ProcessCharEscape(const char *ThisTokBegin,
if (Diags == 0)
break;
- if (isgraph(ResultChar))
+ if (isPrintable(ResultChar))
Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
diag::ext_unknown_escape)
<< std::string(1, ResultChar);
@@ -232,16 +225,16 @@ static bool ProcessUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
// Skip the '\u' char's.
ThisTokBuf += 2;
- if (ThisTokBuf == ThisTokEnd || !isxdigit(*ThisTokBuf)) {
+ if (ThisTokBuf == ThisTokEnd || !isHexDigit(*ThisTokBuf)) {
if (Diags)
Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf,
- diag::err_ucn_escape_no_digits);
+ diag::err_hex_escape_no_digits) << StringRef(&ThisTokBuf[-1], 1);
return false;
}
UcnLen = (ThisTokBuf[-1] == 'u' ? 4 : 8);
unsigned short UcnLenSave = UcnLen;
for (; ThisTokBuf != ThisTokEnd && UcnLenSave; ++ThisTokBuf, UcnLenSave--) {
- int CharVal = HexDigitValue(ThisTokBuf[0]);
+ int CharVal = llvm::hexDigitValue(ThisTokBuf[0]);
if (CharVal == -1) break;
UcnVal <<= 4;
UcnVal |= CharVal;
@@ -267,7 +260,7 @@ static bool ProcessUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
// characters inside character and string literals
if (UcnVal < 0xa0 &&
(UcnVal != 0x24 && UcnVal != 0x40 && UcnVal != 0x60)) { // $, @, `
- bool IsError = (!Features.CPlusPlus0x || !in_char_string_literal);
+ bool IsError = (!Features.CPlusPlus11 || !in_char_string_literal);
if (Diags) {
char BasicSCSChar = UcnVal;
if (UcnVal >= 0x20 && UcnVal < 0x7f)
@@ -286,7 +279,7 @@ static bool ProcessUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf,
if (!Features.CPlusPlus && !Features.C99 && Diags)
Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf,
- diag::warn_ucn_not_valid_in_c89);
+ diag::warn_ucn_not_valid_in_c89_literal);
return true;
}
@@ -467,8 +460,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
// and FP constants (specifically, the 'pp-number' regex), and assumes that
// the byte at "*end" is both valid and not part of the regex. Because of
// this, it doesn't have to check for 'overscan' in various places.
- assert(!isalnum(*ThisTokEnd) && *ThisTokEnd != '.' && *ThisTokEnd != '_' &&
- "Lexer didn't maximally munch?");
+ assert(!isPreprocessingNumberBody(*ThisTokEnd) && "didn't maximally munch?");
s = DigitsBegin = ThisTokBegin;
saw_exponent = false;
@@ -491,7 +483,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
s = SkipDigits(s);
if (s == ThisTokEnd) {
// Done.
- } else if (isxdigit(*s) && !(*s == 'e' || *s == 'E')) {
+ } else if (isHexDigit(*s) && !(*s == 'e' || *s == 'E')) {
PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s - ThisTokBegin),
diag::err_invalid_decimal_digit) << StringRef(s, 1);
hadError = true;
@@ -616,7 +608,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
}
if (s != ThisTokEnd) {
- if (PP.getLangOpts().CPlusPlus0x && s == SuffixBegin && *s == '_') {
+ if (PP.getLangOpts().CPlusPlus11 && s == SuffixBegin && *s == '_') {
// We have a ud-suffix! By C++11 [lex.ext]p10, ud-suffixes not starting
// with an '_' are ill-formed.
saw_ud_suffix = true;
@@ -643,7 +635,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
s++;
// Handle a hex number like 0x1234.
- if ((*s == 'x' || *s == 'X') && (isxdigit(s[1]) || s[1] == '.')) {
+ if ((*s == 'x' || *s == 'X') && (isHexDigit(s[1]) || s[1] == '.')) {
s++;
radix = 16;
DigitsBegin = s;
@@ -702,7 +694,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
s = SkipBinaryDigits(s);
if (s == ThisTokEnd) {
// Done.
- } else if (isxdigit(*s)) {
+ } else if (isHexDigit(*s)) {
PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-ThisTokBegin),
diag::err_invalid_binary_digit) << StringRef(s, 1);
hadError = true;
@@ -722,7 +714,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
// If we have some other non-octal digit that *is* a decimal digit, see if
// this is part of a floating point number like 094.123 or 09e1.
- if (isdigit(*s)) {
+ if (isDigit(*s)) {
const char *EndDecimal = SkipDigits(s);
if (EndDecimal[0] == '.' || EndDecimal[0] == 'e' || EndDecimal[0] == 'E') {
s = EndDecimal;
@@ -732,7 +724,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) {
// If we have a hex digit other than 'e' (which denotes a FP exponent) then
// the code is using an incorrect base.
- if (isxdigit(*s) && *s != 'e' && *s != 'E') {
+ if (isHexDigit(*s) && *s != 'e' && *s != 'E') {
PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-ThisTokBegin),
diag::err_invalid_octal_digit) << StringRef(s, 1);
hadError = true;
@@ -792,7 +784,7 @@ bool NumericLiteralParser::GetIntegerValue(llvm::APInt &Val) {
if (alwaysFitsInto64Bits(radix, NumDigits)) {
uint64_t N = 0;
for (const char *Ptr = DigitsBegin; Ptr != SuffixBegin; ++Ptr)
- N = N * radix + HexDigitValue(*Ptr);
+ N = N * radix + llvm::hexDigitValue(*Ptr);
// This will truncate the value to Val's input width. Simply check
// for overflow by comparing.
@@ -809,7 +801,7 @@ bool NumericLiteralParser::GetIntegerValue(llvm::APInt &Val) {
bool OverflowOccurred = false;
while (Ptr < SuffixBegin) {
- unsigned C = HexDigitValue(*Ptr++);
+ unsigned C = llvm::hexDigitValue(*Ptr++);
// If this letter is out of bound for this radix, reject it.
assert(C < radix && "NumericLiteralParser ctor should have rejected this");
diff --git a/lib/Lex/MacroArgs.cpp b/lib/Lex/MacroArgs.cpp
index ed8873d..f6e781a 100644
--- a/lib/Lex/MacroArgs.cpp
+++ b/lib/Lex/MacroArgs.cpp
@@ -12,9 +12,9 @@
//===----------------------------------------------------------------------===//
#include "MacroArgs.h"
+#include "clang/Lex/LexDiagnostic.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/LexDiagnostic.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/SaveAndRestore.h"
#include <algorithm>
@@ -23,7 +23,7 @@ using namespace clang;
/// MacroArgs ctor function - This destroys the vector passed in.
MacroArgs *MacroArgs::create(const MacroInfo *MI,
- llvm::ArrayRef<Token> UnexpArgTokens,
+ ArrayRef<Token> UnexpArgTokens,
bool VarargsElided, Preprocessor &PP) {
assert(MI->isFunctionLike() &&
"Can't have args for an object-like macro!");
@@ -215,15 +215,11 @@ Token MacroArgs::StringifyArgument(const Token *ArgToks,
// If this is a string or character constant, escape the token as specified
// by 6.10.3.2p2.
- if (Tok.is(tok::string_literal) || // "foo"
- Tok.is(tok::wide_string_literal) || // L"foo"
- Tok.is(tok::utf8_string_literal) || // u8"foo"
- Tok.is(tok::utf16_string_literal) || // u"foo"
- Tok.is(tok::utf32_string_literal) || // U"foo"
- Tok.is(tok::char_constant) || // 'x'
- Tok.is(tok::wide_char_constant) || // L'x'.
- Tok.is(tok::utf16_char_constant) || // u'x'.
- Tok.is(tok::utf32_char_constant)) { // U'x'.
+ if (tok::isStringLiteral(Tok.getKind()) || // "foo", u8R"x(foo)x"_bar, etc.
+ Tok.is(tok::char_constant) || // 'x'
+ Tok.is(tok::wide_char_constant) || // L'x'.
+ Tok.is(tok::utf16_char_constant) || // u'x'.
+ Tok.is(tok::utf32_char_constant)) { // U'x'.
bool Invalid = false;
std::string TokStr = PP.getSpelling(Tok, &Invalid);
if (!Invalid) {
diff --git a/lib/Lex/MacroArgs.h b/lib/Lex/MacroArgs.h
index cf86d71..1fd295e 100644
--- a/lib/Lex/MacroArgs.h
+++ b/lib/Lex/MacroArgs.h
@@ -14,8 +14,8 @@
#ifndef LLVM_CLANG_MACROARGS_H
#define LLVM_CLANG_MACROARGS_H
+#include "clang/Basic/LLVM.h"
#include "llvm/ADT/ArrayRef.h"
-
#include <vector>
namespace clang {
@@ -60,7 +60,7 @@ public:
/// MacroArgs ctor function - Create a new MacroArgs object with the specified
/// macro and argument info.
static MacroArgs *create(const MacroInfo *MI,
- llvm::ArrayRef<Token> UnexpArgTokens,
+ ArrayRef<Token> UnexpArgTokens,
bool VarargsElided, Preprocessor &PP);
/// destroy - Destroy and deallocate the memory for this object.
diff --git a/lib/Lex/MacroInfo.cpp b/lib/Lex/MacroInfo.cpp
index 904f04e..b61ff71 100644
--- a/lib/Lex/MacroInfo.cpp
+++ b/lib/Lex/MacroInfo.cpp
@@ -17,7 +17,6 @@ using namespace clang;
MacroInfo::MacroInfo(SourceLocation DefLoc)
: Location(DefLoc),
- PreviousDefinition(0),
ArgumentList(0),
NumArguments(0),
IsDefinitionLengthCached(false),
@@ -25,53 +24,12 @@ MacroInfo::MacroInfo(SourceLocation DefLoc)
IsC99Varargs(false),
IsGNUVarargs(false),
IsBuiltinMacro(false),
- IsFromAST(false),
- ChangedAfterLoad(false),
+ HasCommaPasting(false),
IsDisabled(false),
IsUsed(false),
IsAllowRedefinitionsWithoutWarning(false),
IsWarnIfUnused(false),
- IsPublic(true),
- IsHidden(false),
- IsAmbiguous(false) {
-}
-
-MacroInfo::MacroInfo(const MacroInfo &MI, llvm::BumpPtrAllocator &PPAllocator)
- : Location(MI.Location),
- EndLocation(MI.EndLocation),
- UndefLocation(MI.UndefLocation),
- PreviousDefinition(0),
- ArgumentList(0),
- NumArguments(0),
- ReplacementTokens(MI.ReplacementTokens),
- DefinitionLength(MI.DefinitionLength),
- IsDefinitionLengthCached(MI.IsDefinitionLengthCached),
- IsFunctionLike(MI.IsFunctionLike),
- IsC99Varargs(MI.IsC99Varargs),
- IsGNUVarargs(MI.IsGNUVarargs),
- IsBuiltinMacro(MI.IsBuiltinMacro),
- IsFromAST(MI.IsFromAST),
- ChangedAfterLoad(MI.ChangedAfterLoad),
- IsDisabled(MI.IsDisabled),
- IsUsed(MI.IsUsed),
- IsAllowRedefinitionsWithoutWarning(MI.IsAllowRedefinitionsWithoutWarning),
- IsWarnIfUnused(MI.IsWarnIfUnused),
- IsPublic(MI.IsPublic),
- IsHidden(MI.IsHidden),
- IsAmbiguous(MI.IsAmbiguous) {
- setArgumentList(MI.ArgumentList, MI.NumArguments, PPAllocator);
-}
-
-const MacroInfo *MacroInfo::findDefinitionAtLoc(SourceLocation L,
- SourceManager &SM) const {
- assert(L.isValid() && "SourceLocation is invalid.");
- for (const MacroInfo *MI = this; MI; MI = MI->PreviousDefinition) {
- if (MI->Location.isInvalid() || // For macros defined on the command line.
- SM.isBeforeInTranslationUnit(MI->Location, L))
- return (MI->UndefLocation.isInvalid() ||
- SM.isBeforeInTranslationUnit(L, MI->UndefLocation)) ? MI : NULL;
- }
- return NULL;
+ FromASTFile(false) {
}
unsigned MacroInfo::getDefinitionLengthSlow(SourceManager &SM) const {
@@ -103,11 +61,17 @@ unsigned MacroInfo::getDefinitionLengthSlow(SourceManager &SM) const {
return DefinitionLength;
}
-/// isIdenticalTo - Return true if the specified macro definition is equal to
-/// this macro in spelling, arguments, and whitespace. This is used to emit
-/// duplicate definition warnings. This implements the rules in C99 6.10.3.
+/// \brief Return true if the specified macro definition is equal to
+/// this macro in spelling, arguments, and whitespace.
///
-bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP) const {
+/// \param Syntactically if true, the macro definitions can be identical even
+/// if they use different identifiers for the function macro parameters.
+/// Otherwise the comparison is lexical and this implements the rules in
+/// C99 6.10.3.
+bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP,
+ bool Syntactically) const {
+ bool Lexically = !Syntactically;
+
// Check # tokens in replacement, number of args, and various flags all match.
if (ReplacementTokens.size() != Other.ReplacementTokens.size() ||
getNumArgs() != Other.getNumArgs() ||
@@ -116,10 +80,12 @@ bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP) const {
isGNUVarargs() != Other.isGNUVarargs())
return false;
- // Check arguments.
- for (arg_iterator I = arg_begin(), OI = Other.arg_begin(), E = arg_end();
- I != E; ++I, ++OI)
- if (*I != *OI) return false;
+ if (Lexically) {
+ // Check arguments.
+ for (arg_iterator I = arg_begin(), OI = Other.arg_begin(), E = arg_end();
+ I != E; ++I, ++OI)
+ if (*I != *OI) return false;
+ }
// Check all the tokens.
for (unsigned i = 0, e = ReplacementTokens.size(); i != e; ++i) {
@@ -137,7 +103,16 @@ bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP) const {
// If this is an identifier, it is easy.
if (A.getIdentifierInfo() || B.getIdentifierInfo()) {
- if (A.getIdentifierInfo() != B.getIdentifierInfo())
+ if (A.getIdentifierInfo() == B.getIdentifierInfo())
+ continue;
+ if (Lexically)
+ return false;
+ // With syntactic equivalence the parameter names can be different as long
+ // as they are used in the same place.
+ int AArgNum = getArgumentNum(A.getIdentifierInfo());
+ if (AArgNum == -1)
+ return false;
+ if (AArgNum != Other.getArgumentNum(B.getIdentifierInfo()))
return false;
continue;
}
@@ -149,3 +124,41 @@ bool MacroInfo::isIdenticalTo(const MacroInfo &Other, Preprocessor &PP) const {
return true;
}
+
+MacroDirective::DefInfo MacroDirective::getDefinition(bool AllowHidden) {
+ MacroDirective *MD = this;
+ SourceLocation UndefLoc;
+ Optional<bool> isPublic;
+ for (; MD; MD = MD->getPrevious()) {
+ if (!AllowHidden && MD->isHidden())
+ continue;
+
+ if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD))
+ return DefInfo(DefMD, UndefLoc,
+ !isPublic.hasValue() || isPublic.getValue());
+
+ if (UndefMacroDirective *UndefMD = dyn_cast<UndefMacroDirective>(MD)) {
+ UndefLoc = UndefMD->getLocation();
+ continue;
+ }
+
+ VisibilityMacroDirective *VisMD = cast<VisibilityMacroDirective>(MD);
+ if (!isPublic.hasValue())
+ isPublic = VisMD->isPublic();
+ }
+
+ return DefInfo();
+}
+
+const MacroDirective::DefInfo
+MacroDirective::findDirectiveAtLoc(SourceLocation L, SourceManager &SM) const {
+ assert(L.isValid() && "SourceLocation is invalid.");
+ for (DefInfo Def = getDefinition(); Def; Def = Def.getPreviousDefinition()) {
+ if (Def.getLocation().isInvalid() || // For macros defined on the command line.
+ SM.isBeforeInTranslationUnit(Def.getLocation(), L))
+ return (!Def.isUndefined() ||
+ SM.isBeforeInTranslationUnit(L, Def.getUndefLocation()))
+ ? Def : DefInfo();
+ }
+ return DefInfo();
+}
diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp
index 8a936fa..0c03201 100644
--- a/lib/Lex/ModuleMap.cpp
+++ b/lib/Lex/ModuleMap.cpp
@@ -12,68 +12,82 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Lex/ModuleMap.h"
-#include "clang/Lex/Lexer.h"
-#include "clang/Lex/LiteralSupport.h"
-#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/LiteralSupport.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/PathV2.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSwitch.h"
#include <stdlib.h>
+#if defined(LLVM_ON_UNIX)
+#include <limits.h>
+#endif
using namespace clang;
Module::ExportDecl
ModuleMap::resolveExport(Module *Mod,
const Module::UnresolvedExportDecl &Unresolved,
- bool Complain) {
+ bool Complain) const {
// We may have just a wildcard.
if (Unresolved.Id.empty()) {
assert(Unresolved.Wildcard && "Invalid unresolved export");
return Module::ExportDecl(0, true);
}
+ // Resolve the module-id.
+ Module *Context = resolveModuleId(Unresolved.Id, Mod, Complain);
+ if (!Context)
+ return Module::ExportDecl();
+
+ return Module::ExportDecl(Context, Unresolved.Wildcard);
+}
+
+Module *ModuleMap::resolveModuleId(const ModuleId &Id, Module *Mod,
+ bool Complain) const {
// Find the starting module.
- Module *Context = lookupModuleUnqualified(Unresolved.Id[0].first, Mod);
+ Module *Context = lookupModuleUnqualified(Id[0].first, Mod);
if (!Context) {
if (Complain)
- Diags->Report(Unresolved.Id[0].second,
- diag::err_mmap_missing_module_unqualified)
- << Unresolved.Id[0].first << Mod->getFullModuleName();
-
- return Module::ExportDecl();
+ Diags->Report(Id[0].second, diag::err_mmap_missing_module_unqualified)
+ << Id[0].first << Mod->getFullModuleName();
+
+ return 0;
}
// Dig into the module path.
- for (unsigned I = 1, N = Unresolved.Id.size(); I != N; ++I) {
- Module *Sub = lookupModuleQualified(Unresolved.Id[I].first,
- Context);
+ for (unsigned I = 1, N = Id.size(); I != N; ++I) {
+ Module *Sub = lookupModuleQualified(Id[I].first, Context);
if (!Sub) {
if (Complain)
- Diags->Report(Unresolved.Id[I].second,
- diag::err_mmap_missing_module_qualified)
- << Unresolved.Id[I].first << Context->getFullModuleName()
- << SourceRange(Unresolved.Id[0].second, Unresolved.Id[I-1].second);
-
- return Module::ExportDecl();
+ Diags->Report(Id[I].second, diag::err_mmap_missing_module_qualified)
+ << Id[I].first << Context->getFullModuleName()
+ << SourceRange(Id[0].second, Id[I-1].second);
+
+ return 0;
}
-
+
Context = Sub;
}
-
- return Module::ExportDecl(Context, Unresolved.Wildcard);
+
+ return Context;
}
ModuleMap::ModuleMap(FileManager &FileMgr, const DiagnosticConsumer &DC,
- const LangOptions &LangOpts, const TargetInfo *Target)
- : LangOpts(LangOpts), Target(Target), BuiltinIncludeDir(0)
+ const LangOptions &LangOpts, const TargetInfo *Target,
+ HeaderSearch &HeaderInfo)
+ : LangOpts(LangOpts), Target(Target), HeaderInfo(HeaderInfo),
+ BuiltinIncludeDir(0)
{
IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs);
Diags = IntrusiveRefCntPtr<DiagnosticsEngine>(
@@ -104,26 +118,15 @@ static StringRef sanitizeFilenameAsIdentifier(StringRef Name,
if (Name.empty())
return Name;
- // Check whether the filename is already an identifier; this is the common
- // case.
- bool isIdentifier = true;
- for (unsigned I = 0, N = Name.size(); I != N; ++I) {
- if (isalpha(Name[I]) || Name[I] == '_' || (isdigit(Name[I]) && I > 0))
- continue;
-
- isIdentifier = false;
- break;
- }
-
- if (!isIdentifier) {
+ if (!isValidIdentifier(Name)) {
// If we don't already have something with the form of an identifier,
// create a buffer with the sanitized name.
Buffer.clear();
- if (isdigit(Name[0]))
+ if (isDigit(Name[0]))
Buffer.push_back('_');
Buffer.reserve(Buffer.size() + Name.size());
for (unsigned I = 0, N = Name.size(); I != N; ++I) {
- if (isalnum(Name[I]) || isspace(Name[I]))
+ if (isIdentifierBody(Name[I]))
Buffer.push_back(Name[I]);
else
Buffer.push_back('_');
@@ -157,8 +160,13 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
}
const DirectoryEntry *Dir = File->getDir();
- llvm::SmallVector<const DirectoryEntry *, 2> SkippedDirs;
- StringRef DirName = Dir->getName();
+ SmallVector<const DirectoryEntry *, 2> SkippedDirs;
+
+ // Note: as an egregious but useful hack we use the real path here, because
+ // frameworks moving from top-level frameworks to embedded frameworks tend
+ // to be symlinked from the top-level location to the embedded location,
+ // and we need to resolve lookups as if we had found the embedded location.
+ StringRef DirName = SourceMgr->getFileManager().getCanonicalName(Dir);
// Keep walking up the directory hierarchy, looking for a directory with
// an umbrella header.
@@ -204,7 +212,7 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
llvm::sys::path::stem(File->getName()), NameBuf);
Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,
Explicit).first;
- Result->TopHeaders.insert(File);
+ Result->addTopHeader(File);
// If inferred submodules export everything they import, add a
// wildcard to the set of exports.
@@ -241,19 +249,19 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
return 0;
}
-bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) {
- HeadersMap::iterator Known = Headers.find(Header);
+bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) const {
+ HeadersMap::const_iterator Known = Headers.find(Header);
if (Known != Headers.end())
return !Known->second.isAvailable();
const DirectoryEntry *Dir = Header->getDir();
- llvm::SmallVector<const DirectoryEntry *, 2> SkippedDirs;
+ SmallVector<const DirectoryEntry *, 2> SkippedDirs;
StringRef DirName = Dir->getName();
// Keep walking up the directory hierarchy, looking for a directory with
// an umbrella header.
do {
- llvm::DenseMap<const DirectoryEntry *, Module *>::iterator KnownDir
+ llvm::DenseMap<const DirectoryEntry *, Module *>::const_iterator KnownDir
= UmbrellaDirs.find(Dir);
if (KnownDir != UmbrellaDirs.end()) {
Module *Found = KnownDir->second;
@@ -307,15 +315,16 @@ bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) {
return false;
}
-Module *ModuleMap::findModule(StringRef Name) {
- llvm::StringMap<Module *>::iterator Known = Modules.find(Name);
+Module *ModuleMap::findModule(StringRef Name) const {
+ llvm::StringMap<Module *>::const_iterator Known = Modules.find(Name);
if (Known != Modules.end())
return Known->getValue();
return 0;
}
-Module *ModuleMap::lookupModuleUnqualified(StringRef Name, Module *Context) {
+Module *ModuleMap::lookupModuleUnqualified(StringRef Name,
+ Module *Context) const {
for(; Context; Context = Context->Parent) {
if (Module *Sub = lookupModuleQualified(Name, Context))
return Sub;
@@ -324,7 +333,7 @@ Module *ModuleMap::lookupModuleUnqualified(StringRef Name, Module *Context) {
return findModule(Name);
}
-Module *ModuleMap::lookupModuleQualified(StringRef Name, Module *Context) {
+Module *ModuleMap::lookupModuleQualified(StringRef Name, Module *Context) const{
if (!Context)
return findModule(Name);
@@ -347,10 +356,10 @@ ModuleMap::findOrCreateModule(StringRef Name, Module *Parent, bool IsFramework,
}
bool ModuleMap::canInferFrameworkModule(const DirectoryEntry *ParentDir,
- StringRef Name, bool &IsSystem) {
+ StringRef Name, bool &IsSystem) const {
// Check whether we have already looked into the parent directory
// for a module map.
- llvm::DenseMap<const DirectoryEntry *, InferredDirectory>::iterator
+ llvm::DenseMap<const DirectoryEntry *, InferredDirectory>::const_iterator
inferred = InferredDirectories.find(ParentDir);
if (inferred == InferredDirectories.end())
return false;
@@ -370,6 +379,23 @@ bool ModuleMap::canInferFrameworkModule(const DirectoryEntry *ParentDir,
return canInfer;
}
+/// \brief For a framework module, infer the framework against which we
+/// should link.
+static void inferFrameworkLink(Module *Mod, const DirectoryEntry *FrameworkDir,
+ FileManager &FileMgr) {
+ assert(Mod->IsFramework && "Can only infer linking for framework modules");
+ assert(!Mod->isSubFramework() &&
+ "Can only infer linking for top-level frameworks");
+
+ SmallString<128> LibName;
+ LibName += FrameworkDir->getName();
+ llvm::sys::path::append(LibName, Mod->Name);
+ if (FileMgr.getFile(LibName)) {
+ Mod->LinkLibraries.push_back(Module::LinkLibrary(Mod->Name,
+ /*IsFramework=*/true));
+ }
+}
+
Module *
ModuleMap::inferFrameworkModule(StringRef ModuleName,
const DirectoryEntry *FrameworkDir,
@@ -384,14 +410,23 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
// If the framework has a parent path from which we're allowed to infer
// a framework module, do so.
if (!Parent) {
+ // Determine whether we're allowed to infer a module map.
+
+ // Note: as an egregious but useful hack we use the real path here, because
+ // we might be looking at an embedded framework that symlinks out to a
+ // top-level framework, and we need to infer as if we were naming the
+ // top-level framework.
+ StringRef FrameworkDirName
+ = SourceMgr->getFileManager().getCanonicalName(FrameworkDir);
+
bool canInfer = false;
- if (llvm::sys::path::has_parent_path(FrameworkDir->getName())) {
+ if (llvm::sys::path::has_parent_path(FrameworkDirName)) {
// Figure out the parent path.
- StringRef Parent = llvm::sys::path::parent_path(FrameworkDir->getName());
+ StringRef Parent = llvm::sys::path::parent_path(FrameworkDirName);
if (const DirectoryEntry *ParentDir = FileMgr.getDirectory(Parent)) {
// Check whether we have already looked into the parent directory
// for a module map.
- llvm::DenseMap<const DirectoryEntry *, InferredDirectory>::iterator
+ llvm::DenseMap<const DirectoryEntry *, InferredDirectory>::const_iterator
inferred = InferredDirectories.find(ParentDir);
if (inferred == InferredDirectories.end()) {
// We haven't looked here before. Load a module map, if there is
@@ -411,7 +446,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
if (inferred->second.InferModules) {
// We're allowed to infer for this directory, but make sure it's okay
// to infer this particular module.
- StringRef Name = llvm::sys::path::filename(FrameworkDir->getName());
+ StringRef Name = llvm::sys::path::stem(FrameworkDirName);
canInfer = std::find(inferred->second.ExcludedModules.begin(),
inferred->second.ExcludedModules.end(),
Name) == inferred->second.ExcludedModules.end();
@@ -480,29 +515,23 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
// check whether it is actually a subdirectory of the parent directory.
// This will not be the case if the 'subframework' is actually a symlink
// out to a top-level framework.
-#ifdef LLVM_ON_UNIX
- char RealSubframeworkDirName[PATH_MAX];
- if (realpath(Dir->path().c_str(), RealSubframeworkDirName)) {
- StringRef SubframeworkDirName = RealSubframeworkDirName;
-
- bool FoundParent = false;
- do {
- // Get the parent directory name.
- SubframeworkDirName
- = llvm::sys::path::parent_path(SubframeworkDirName);
- if (SubframeworkDirName.empty())
- break;
-
- if (FileMgr.getDirectory(SubframeworkDirName) == FrameworkDir) {
- FoundParent = true;
- break;
- }
- } while (true);
+ StringRef SubframeworkDirName = FileMgr.getCanonicalName(SubframeworkDir);
+ bool FoundParent = false;
+ do {
+ // Get the parent directory name.
+ SubframeworkDirName
+ = llvm::sys::path::parent_path(SubframeworkDirName);
+ if (SubframeworkDirName.empty())
+ break;
+
+ if (FileMgr.getDirectory(SubframeworkDirName) == FrameworkDir) {
+ FoundParent = true;
+ break;
+ }
+ } while (true);
- if (!FoundParent)
- continue;
- }
-#endif
+ if (!FoundParent)
+ continue;
// FIXME: Do we want to warn about subframeworks without umbrella headers?
SmallString<32> NameBuf;
@@ -512,6 +541,12 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
}
}
+ // If the module is a top-level framework, automatically link against the
+ // framework.
+ if (!Result->isSubFramework()) {
+ inferFrameworkLink(Result, FrameworkDir, FileMgr);
+ }
+
return Result;
}
@@ -528,15 +563,17 @@ void ModuleMap::setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir) {
void ModuleMap::addHeader(Module *Mod, const FileEntry *Header,
bool Excluded) {
- if (Excluded)
+ if (Excluded) {
Mod->ExcludedHeaders.push_back(Header);
- else
+ } else {
Mod->Headers.push_back(Header);
+ HeaderInfo.MarkFileModuleHeader(Header);
+ }
Headers[Header] = KnownHeader(Mod, Excluded);
}
const FileEntry *
-ModuleMap::getContainingModuleMapFile(Module *Module) {
+ModuleMap::getContainingModuleMapFile(Module *Module) const {
if (Module->DefinitionLoc.isInvalid() || !SourceMgr)
return 0;
@@ -573,6 +610,25 @@ bool ModuleMap::resolveExports(Module *Mod, bool Complain) {
return HadError;
}
+bool ModuleMap::resolveConflicts(Module *Mod, bool Complain) {
+ bool HadError = false;
+ for (unsigned I = 0, N = Mod->UnresolvedConflicts.size(); I != N; ++I) {
+ Module *OtherMod = resolveModuleId(Mod->UnresolvedConflicts[I].Id,
+ Mod, Complain);
+ if (!OtherMod) {
+ HadError = true;
+ continue;
+ }
+
+ Module::Conflict Conflict;
+ Conflict.Other = OtherMod;
+ Conflict.Message = Mod->UnresolvedConflicts[I].Message;
+ Mod->Conflicts.push_back(Conflict);
+ }
+ Mod->UnresolvedConflicts.clear();
+ return HadError;
+}
+
Module *ModuleMap::inferModuleFromLocation(FullSourceLoc Loc) {
if (Loc.isInvalid())
return 0;
@@ -613,6 +669,8 @@ namespace clang {
struct MMToken {
enum TokenKind {
Comma,
+ ConfigMacros,
+ Conflict,
EndOfFile,
HeaderKeyword,
Identifier,
@@ -620,6 +678,7 @@ namespace clang {
ExplicitKeyword,
ExportKeyword,
FrameworkKeyword,
+ LinkKeyword,
ModuleKeyword,
Period,
UmbrellaKeyword,
@@ -656,10 +715,13 @@ namespace clang {
/// \brief The set of attributes that can be attached to a module.
struct Attributes {
- Attributes() : IsSystem() { }
+ Attributes() : IsSystem(), IsExhaustive() { }
/// \brief Whether this is a system module.
unsigned IsSystem : 1;
+
+ /// \brief Whether this is an exhaustive set of configuration macros.
+ unsigned IsExhaustive : 1;
};
@@ -700,14 +762,16 @@ namespace clang {
/// (or the end of the file).
void skipUntil(MMToken::TokenKind K);
- typedef llvm::SmallVector<std::pair<std::string, SourceLocation>, 2>
- ModuleId;
+ typedef SmallVector<std::pair<std::string, SourceLocation>, 2> ModuleId;
bool parseModuleId(ModuleId &Id);
void parseModuleDecl();
void parseRequiresDecl();
void parseHeaderDecl(SourceLocation UmbrellaLoc, SourceLocation ExcludeLoc);
void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc);
void parseExportDecl();
+ void parseLinkDecl();
+ void parseConfigMacros();
+ void parseConflict();
void parseInferredModuleDecl(bool Framework, bool Explicit);
bool parseOptionalAttributes(Attributes &Attrs);
@@ -745,11 +809,14 @@ retry:
Tok.StringData = LToken.getRawIdentifierData();
Tok.StringLength = LToken.getLength();
Tok.Kind = llvm::StringSwitch<MMToken::TokenKind>(Tok.getString())
- .Case("header", MMToken::HeaderKeyword)
+ .Case("config_macros", MMToken::ConfigMacros)
+ .Case("conflict", MMToken::Conflict)
.Case("exclude", MMToken::ExcludeKeyword)
.Case("explicit", MMToken::ExplicitKeyword)
.Case("export", MMToken::ExportKeyword)
.Case("framework", MMToken::FrameworkKeyword)
+ .Case("header", MMToken::HeaderKeyword)
+ .Case("link", MMToken::LinkKeyword)
.Case("module", MMToken::ModuleKeyword)
.Case("requires", MMToken::RequiresKeyword)
.Case("umbrella", MMToken::UmbrellaKeyword)
@@ -905,7 +972,9 @@ namespace {
/// \brief An unknown attribute.
AT_unknown,
/// \brief The 'system' attribute.
- AT_system
+ AT_system,
+ /// \brief The 'exhaustive' attribute.
+ AT_exhaustive
};
}
@@ -920,6 +989,7 @@ namespace {
/// header-declaration
/// submodule-declaration
/// export-declaration
+/// link-declaration
///
/// submodule-declaration:
/// module-declaration
@@ -1061,7 +1131,15 @@ void ModuleMapParser::parseModuleDecl() {
case MMToken::RBrace:
Done = true;
break;
-
+
+ case MMToken::ConfigMacros:
+ parseConfigMacros();
+ break;
+
+ case MMToken::Conflict:
+ parseConflict();
+ break;
+
case MMToken::ExplicitKeyword:
case MMToken::FrameworkKeyword:
case MMToken::ModuleKeyword:
@@ -1099,7 +1177,11 @@ void ModuleMapParser::parseModuleDecl() {
case MMToken::HeaderKeyword:
parseHeaderDecl(SourceLocation(), SourceLocation());
break;
-
+
+ case MMToken::LinkKeyword:
+ parseLinkDecl();
+ break;
+
default:
Diags.Report(Tok.getLocation(), diag::err_mmap_expected_member);
consumeToken();
@@ -1115,6 +1197,13 @@ void ModuleMapParser::parseModuleDecl() {
HadError = true;
}
+ // If the active module is a top-level framework, and there are no link
+ // libraries, automatically link against the framework.
+ if (ActiveModule->IsFramework && !ActiveModule->isSubFramework() &&
+ ActiveModule->LinkLibraries.empty()) {
+ inferFrameworkLink(ActiveModule, Directory, SourceMgr.getFileManager());
+ }
+
// We're done parsing this module. Pop back to the previous module.
ActiveModule = PreviousActiveModule;
}
@@ -1159,9 +1248,9 @@ void ModuleMapParser::parseRequiresDecl() {
/// \brief Append to \p Paths the set of paths needed to get to the
/// subframework in which the given module lives.
static void appendSubframeworkPaths(Module *Mod,
- llvm::SmallVectorImpl<char> &Path) {
+ SmallVectorImpl<char> &Path) {
// Collect the framework names from the given module to the top-level module.
- llvm::SmallVector<StringRef, 2> Paths;
+ SmallVector<StringRef, 2> Paths;
for (; Mod; Mod = Mod->Parent) {
if (Mod->IsFramework)
Paths.push_back(Mod->Name);
@@ -1307,7 +1396,9 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc,
if (BuiltinFile)
Map.addHeader(ActiveModule, BuiltinFile, Exclude);
}
- } else {
+ } else if (!Exclude) {
+ // Ignore excluded header files. They're optional anyway.
+
Diags.Report(FileNameLoc, diag::err_mmap_header_not_found)
<< Umbrella << FileName;
HadError = true;
@@ -1414,7 +1505,139 @@ void ModuleMapParser::parseExportDecl() {
ActiveModule->UnresolvedExports.push_back(Unresolved);
}
-/// \brief Parse an inferried module declaration (wildcard modules).
+/// \brief Parse a link declaration.
+///
+/// module-declaration:
+/// 'link' 'framework'[opt] string-literal
+void ModuleMapParser::parseLinkDecl() {
+ assert(Tok.is(MMToken::LinkKeyword));
+ SourceLocation LinkLoc = consumeToken();
+
+ // Parse the optional 'framework' keyword.
+ bool IsFramework = false;
+ if (Tok.is(MMToken::FrameworkKeyword)) {
+ consumeToken();
+ IsFramework = true;
+ }
+
+ // Parse the library name
+ if (!Tok.is(MMToken::StringLiteral)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_library_name)
+ << IsFramework << SourceRange(LinkLoc);
+ HadError = true;
+ return;
+ }
+
+ std::string LibraryName = Tok.getString();
+ consumeToken();
+ ActiveModule->LinkLibraries.push_back(Module::LinkLibrary(LibraryName,
+ IsFramework));
+}
+
+/// \brief Parse a configuration macro declaration.
+///
+/// module-declaration:
+/// 'config_macros' attributes[opt] config-macro-list?
+///
+/// config-macro-list:
+/// identifier (',' identifier)?
+void ModuleMapParser::parseConfigMacros() {
+ assert(Tok.is(MMToken::ConfigMacros));
+ SourceLocation ConfigMacrosLoc = consumeToken();
+
+ // Only top-level modules can have configuration macros.
+ if (ActiveModule->Parent) {
+ Diags.Report(ConfigMacrosLoc, diag::err_mmap_config_macro_submodule);
+ }
+
+ // Parse the optional attributes.
+ Attributes Attrs;
+ parseOptionalAttributes(Attrs);
+ if (Attrs.IsExhaustive && !ActiveModule->Parent) {
+ ActiveModule->ConfigMacrosExhaustive = true;
+ }
+
+ // If we don't have an identifier, we're done.
+ if (!Tok.is(MMToken::Identifier))
+ return;
+
+ // Consume the first identifier.
+ if (!ActiveModule->Parent) {
+ ActiveModule->ConfigMacros.push_back(Tok.getString().str());
+ }
+ consumeToken();
+
+ do {
+ // If there's a comma, consume it.
+ if (!Tok.is(MMToken::Comma))
+ break;
+ consumeToken();
+
+ // We expect to see a macro name here.
+ if (!Tok.is(MMToken::Identifier)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_config_macro);
+ break;
+ }
+
+ // Consume the macro name.
+ if (!ActiveModule->Parent) {
+ ActiveModule->ConfigMacros.push_back(Tok.getString().str());
+ }
+ consumeToken();
+ } while (true);
+}
+
+/// \brief Format a module-id into a string.
+static std::string formatModuleId(const ModuleId &Id) {
+ std::string result;
+ {
+ llvm::raw_string_ostream OS(result);
+
+ for (unsigned I = 0, N = Id.size(); I != N; ++I) {
+ if (I)
+ OS << ".";
+ OS << Id[I].first;
+ }
+ }
+
+ return result;
+}
+
+/// \brief Parse a conflict declaration.
+///
+/// module-declaration:
+/// 'conflict' module-id ',' string-literal
+void ModuleMapParser::parseConflict() {
+ assert(Tok.is(MMToken::Conflict));
+ SourceLocation ConflictLoc = consumeToken();
+ Module::UnresolvedConflict Conflict;
+
+ // Parse the module-id.
+ if (parseModuleId(Conflict.Id))
+ return;
+
+ // Parse the ','.
+ if (!Tok.is(MMToken::Comma)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_conflicts_comma)
+ << SourceRange(ConflictLoc);
+ return;
+ }
+ consumeToken();
+
+ // Parse the message.
+ if (!Tok.is(MMToken::StringLiteral)) {
+ Diags.Report(Tok.getLocation(), diag::err_mmap_expected_conflicts_message)
+ << formatModuleId(Conflict.Id);
+ return;
+ }
+ Conflict.Message = Tok.getString().str();
+ consumeToken();
+
+ // Add this unresolved conflict.
+ ActiveModule->UnresolvedConflicts.push_back(Conflict);
+}
+
+/// \brief Parse an inferred module declaration (wildcard modules).
///
/// module-declaration:
/// 'explicit'[opt] 'framework'[opt] 'module' * attributes[opt]
@@ -1593,6 +1816,7 @@ bool ModuleMapParser::parseOptionalAttributes(Attributes &Attrs) {
// Decode the attribute name.
AttributeKind Attribute
= llvm::StringSwitch<AttributeKind>(Tok.getString())
+ .Case("exhaustive", AT_exhaustive)
.Case("system", AT_system)
.Default(AT_unknown);
switch (Attribute) {
@@ -1604,6 +1828,10 @@ bool ModuleMapParser::parseOptionalAttributes(Attributes &Attrs) {
case AT_system:
Attrs.IsSystem = true;
break;
+
+ case AT_exhaustive:
+ Attrs.IsExhaustive = true;
+ break;
}
consumeToken();
@@ -1653,13 +1881,16 @@ bool ModuleMapParser::parseModuleMapFile() {
case MMToken::FrameworkKeyword:
parseModuleDecl();
break;
-
+
case MMToken::Comma:
+ case MMToken::ConfigMacros:
+ case MMToken::Conflict:
case MMToken::ExcludeKeyword:
case MMToken::ExportKeyword:
case MMToken::HeaderKeyword:
case MMToken::Identifier:
case MMToken::LBrace:
+ case MMToken::LinkKeyword:
case MMToken::LSquare:
case MMToken::Period:
case MMToken::RBrace:
@@ -1677,11 +1908,16 @@ bool ModuleMapParser::parseModuleMapFile() {
}
bool ModuleMap::parseModuleMapFile(const FileEntry *File) {
+ llvm::DenseMap<const FileEntry *, bool>::iterator Known
+ = ParsedModuleMap.find(File);
+ if (Known != ParsedModuleMap.end())
+ return Known->second;
+
assert(Target != 0 && "Missing target information");
FileID ID = SourceMgr->createFileID(File, SourceLocation(), SrcMgr::C_User);
const llvm::MemoryBuffer *Buffer = SourceMgr->getBuffer(ID);
if (!Buffer)
- return true;
+ return ParsedModuleMap[File] = true;
// Parse this module map file.
Lexer L(ID, SourceMgr->getBuffer(ID), *SourceMgr, MMapLangOpts);
@@ -1690,6 +1926,6 @@ bool ModuleMap::parseModuleMapFile(const FileEntry *File) {
BuiltinIncludeDir);
bool Result = Parser.parseModuleMapFile();
Diags->getClient()->EndSourceFile();
-
+ ParsedModuleMap[File] = Result;
return Result;
}
diff --git a/lib/Lex/PPConditionalDirectiveRecord.cpp b/lib/Lex/PPConditionalDirectiveRecord.cpp
new file mode 100644
index 0000000..16ce3ef
--- /dev/null
+++ b/lib/Lex/PPConditionalDirectiveRecord.cpp
@@ -0,0 +1,120 @@
+//===--- PPConditionalDirectiveRecord.h - Preprocessing Directives-*- 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 PPConditionalDirectiveRecord class, which maintains
+// a record of conditional directive regions.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/Lex/PPConditionalDirectiveRecord.h"
+#include "llvm/Support/Capacity.h"
+
+using namespace clang;
+
+PPConditionalDirectiveRecord::PPConditionalDirectiveRecord(SourceManager &SM)
+ : SourceMgr(SM) {
+ CondDirectiveStack.push_back(SourceLocation());
+}
+
+bool PPConditionalDirectiveRecord::rangeIntersectsConditionalDirective(
+ SourceRange Range) const {
+ if (Range.isInvalid())
+ return false;
+
+ CondDirectiveLocsTy::const_iterator
+ low = std::lower_bound(CondDirectiveLocs.begin(), CondDirectiveLocs.end(),
+ Range.getBegin(), CondDirectiveLoc::Comp(SourceMgr));
+ if (low == CondDirectiveLocs.end())
+ return false;
+
+ if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), low->getLoc()))
+ return false;
+
+ CondDirectiveLocsTy::const_iterator
+ upp = std::upper_bound(low, CondDirectiveLocs.end(),
+ Range.getEnd(), CondDirectiveLoc::Comp(SourceMgr));
+ SourceLocation uppRegion;
+ if (upp != CondDirectiveLocs.end())
+ uppRegion = upp->getRegionLoc();
+
+ return low->getRegionLoc() != uppRegion;
+}
+
+SourceLocation PPConditionalDirectiveRecord::findConditionalDirectiveRegionLoc(
+ SourceLocation Loc) const {
+ if (Loc.isInvalid())
+ return SourceLocation();
+ if (CondDirectiveLocs.empty())
+ return SourceLocation();
+
+ if (SourceMgr.isBeforeInTranslationUnit(CondDirectiveLocs.back().getLoc(),
+ Loc))
+ return CondDirectiveStack.back();
+
+ CondDirectiveLocsTy::const_iterator
+ low = std::lower_bound(CondDirectiveLocs.begin(), CondDirectiveLocs.end(),
+ Loc, CondDirectiveLoc::Comp(SourceMgr));
+ assert(low != CondDirectiveLocs.end());
+ return low->getRegionLoc();
+}
+
+void PPConditionalDirectiveRecord::addCondDirectiveLoc(
+ CondDirectiveLoc DirLoc) {
+ // Ignore directives in system headers.
+ if (SourceMgr.isInSystemHeader(DirLoc.getLoc()))
+ return;
+
+ assert(CondDirectiveLocs.empty() ||
+ SourceMgr.isBeforeInTranslationUnit(CondDirectiveLocs.back().getLoc(),
+ DirLoc.getLoc()));
+ CondDirectiveLocs.push_back(DirLoc);
+}
+
+void PPConditionalDirectiveRecord::If(SourceLocation Loc,
+ SourceRange ConditionRange) {
+ addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
+ CondDirectiveStack.push_back(Loc);
+}
+
+void PPConditionalDirectiveRecord::Ifdef(SourceLocation Loc,
+ const Token &MacroNameTok,
+ const MacroDirective *MD) {
+ addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
+ CondDirectiveStack.push_back(Loc);
+}
+
+void PPConditionalDirectiveRecord::Ifndef(SourceLocation Loc,
+ const Token &MacroNameTok,
+ const MacroDirective *MD) {
+ addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
+ CondDirectiveStack.push_back(Loc);
+}
+
+void PPConditionalDirectiveRecord::Elif(SourceLocation Loc,
+ SourceRange ConditionRange,
+ SourceLocation IfLoc) {
+ addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
+ CondDirectiveStack.back() = Loc;
+}
+
+void PPConditionalDirectiveRecord::Else(SourceLocation Loc,
+ SourceLocation IfLoc) {
+ addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
+ CondDirectiveStack.back() = Loc;
+}
+
+void PPConditionalDirectiveRecord::Endif(SourceLocation Loc,
+ SourceLocation IfLoc) {
+ addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
+ assert(!CondDirectiveStack.empty());
+ CondDirectiveStack.pop_back();
+}
+
+size_t PPConditionalDirectiveRecord::getTotalMemory() const {
+ return llvm::capacity_in_bytes(CondDirectiveLocs);
+}
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index b7c1846..07c1867 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -13,17 +13,18 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/LiteralSupport.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/CodeCompletionHandler.h"
#include "clang/Lex/HeaderSearch.h"
-#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/LexDiagnostic.h"
-#include "clang/Lex/CodeCompletionHandler.h"
+#include "clang/Lex/LiteralSupport.h"
+#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/Pragma.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/APInt.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -56,12 +57,42 @@ MacroInfo *Preprocessor::AllocateMacroInfo(SourceLocation L) {
return MI;
}
-MacroInfo *Preprocessor::CloneMacroInfo(const MacroInfo &MacroToClone) {
- MacroInfo *MI = AllocateMacroInfo();
- new (MI) MacroInfo(MacroToClone, BP);
+MacroInfo *Preprocessor::AllocateDeserializedMacroInfo(SourceLocation L,
+ unsigned SubModuleID) {
+ LLVM_STATIC_ASSERT(llvm::AlignOf<MacroInfo>::Alignment >= sizeof(SubModuleID),
+ "alignment for MacroInfo is less than the ID");
+ MacroInfo *MI =
+ (MacroInfo*)BP.Allocate(sizeof(MacroInfo) + sizeof(SubModuleID),
+ llvm::AlignOf<MacroInfo>::Alignment);
+ new (MI) MacroInfo(L);
+ MI->FromASTFile = true;
+ MI->setOwningModuleID(SubModuleID);
return MI;
}
+DefMacroDirective *
+Preprocessor::AllocateDefMacroDirective(MacroInfo *MI, SourceLocation Loc,
+ bool isImported) {
+ DefMacroDirective *MD = BP.Allocate<DefMacroDirective>();
+ new (MD) DefMacroDirective(MI, Loc, isImported);
+ return MD;
+}
+
+UndefMacroDirective *
+Preprocessor::AllocateUndefMacroDirective(SourceLocation UndefLoc) {
+ UndefMacroDirective *MD = BP.Allocate<UndefMacroDirective>();
+ new (MD) UndefMacroDirective(UndefLoc);
+ return MD;
+}
+
+VisibilityMacroDirective *
+Preprocessor::AllocateVisibilityMacroDirective(SourceLocation Loc,
+ bool isPublic) {
+ VisibilityMacroDirective *MD = BP.Allocate<VisibilityMacroDirective>();
+ new (MD) VisibilityMacroDirective(Loc, isPublic);
+ return MD;
+}
+
/// \brief Release the specified MacroInfo to be reused for allocating
/// new MacroInfo objects.
void Preprocessor::ReleaseMacroInfo(MacroInfo *MI) {
@@ -140,15 +171,14 @@ void Preprocessor::ReadMacroName(Token &MacroNameTok, char isDefineUndef) {
Diag(MacroNameTok, diag::err_pp_macro_not_identifier);
// Fall through on error.
} else if (isDefineUndef && II->getPPKeywordID() == tok::pp_defined) {
- // Error if defining "defined": C99 6.10.8.4.
+ // Error if defining "defined": C99 6.10.8/4, C++ [cpp.predefined]p4.
Diag(MacroNameTok, diag::err_defined_macro_name);
- } else if (isDefineUndef && II->hasMacroDefinition() &&
+ } else if (isDefineUndef == 2 && II->hasMacroDefinition() &&
getMacroInfo(II)->isBuiltinMacro()) {
- // Error if defining "__LINE__" and other builtins: C99 6.10.8.4.
- if (isDefineUndef == 1)
- Diag(MacroNameTok, diag::pp_redef_builtin_macro);
- else
- Diag(MacroNameTok, diag::pp_undef_builtin_macro);
+ // Warn if undefining "__LINE__" and other builtins, per C99 6.10.8/4
+ // and C++ [cpp.predefined]p4], but allow it as an extension.
+ Diag(MacroNameTok, diag::ext_pp_undef_builtin_macro);
+ return;
} else {
// Okay, we got a good identifier node. Return it.
return;
@@ -255,7 +285,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
// directive mode. Tell the lexer this so any newlines we see will be
// converted into an EOD token (this terminates the macro).
CurPPLexer->ParsingPreprocessorDirective = true;
- if (CurLexer) CurLexer->SetCommentRetentionState(false);
+ if (CurLexer) CurLexer->SetKeepWhitespaceMode(false);
// Read the next token, the directive flavor.
@@ -266,7 +296,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
if (Tok.isNot(tok::raw_identifier)) {
CurPPLexer->ParsingPreprocessorDirective = false;
// Restore comment saving mode.
- if (CurLexer) CurLexer->SetCommentRetentionState(KeepComments);
+ if (CurLexer) CurLexer->resetExtendedTokenMode();
continue;
}
@@ -282,7 +312,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
FirstChar != 'i' && FirstChar != 'e') {
CurPPLexer->ParsingPreprocessorDirective = false;
// Restore comment saving mode.
- if (CurLexer) CurLexer->SetCommentRetentionState(KeepComments);
+ if (CurLexer) CurLexer->resetExtendedTokenMode();
continue;
}
@@ -299,7 +329,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
if (IdLen >= 20) {
CurPPLexer->ParsingPreprocessorDirective = false;
// Restore comment saving mode.
- if (CurLexer) CurLexer->SetCommentRetentionState(KeepComments);
+ if (CurLexer) CurLexer->resetExtendedTokenMode();
continue;
}
memcpy(DirectiveBuf, &DirectiveStr[0], IdLen);
@@ -405,7 +435,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
CurPPLexer->ParsingPreprocessorDirective = false;
// Restore comment saving mode.
- if (CurLexer) CurLexer->SetCommentRetentionState(KeepComments);
+ if (CurLexer) CurLexer->resetExtendedTokenMode();
}
// Finally, if we are out of the conditional (saw an #endif or ran off the end
@@ -536,11 +566,11 @@ const FileEntry *Preprocessor::LookupFile(
// Otherwise, see if this is a subframework header. If so, this is relative
// to one of the headers on the #include stack. Walk the list of the current
// headers on the #include stack and pass them to HeaderInfo.
- // FIXME: SuggestedModule!
if (IsFileLexer()) {
if ((CurFileEnt = SourceMgr.getFileEntryForID(CurPPLexer->getFileID())))
if ((FE = HeaderInfo.LookupSubframeworkHeader(Filename, CurFileEnt,
- SearchPath, RelativePath)))
+ SearchPath, RelativePath,
+ SuggestedModule)))
return FE;
}
@@ -550,7 +580,8 @@ const FileEntry *Preprocessor::LookupFile(
if ((CurFileEnt =
SourceMgr.getFileEntryForID(ISEntry.ThePPLexer->getFileID())))
if ((FE = HeaderInfo.LookupSubframeworkHeader(
- Filename, CurFileEnt, SearchPath, RelativePath)))
+ Filename, CurFileEnt, SearchPath, RelativePath,
+ SuggestedModule)))
return FE;
}
}
@@ -590,6 +621,7 @@ void Preprocessor::HandleDirective(Token &Result) {
// mode. Tell the lexer this so any newlines we see will be converted into an
// EOD token (which terminates the directive).
CurPPLexer->ParsingPreprocessorDirective = true;
+ if (CurLexer) CurLexer->SetKeepWhitespaceMode(false);
++NumDirectives;
@@ -634,14 +666,9 @@ void Preprocessor::HandleDirective(Token &Result) {
// and reset to previous state when returning from this function.
ResetMacroExpansionHelper helper(this);
-TryAgain:
switch (Result.getKind()) {
case tok::eod:
return; // null directive.
- case tok::comment:
- // Handle stuff like "# /*foo*/ define X" in -E -C mode.
- LexUnexpandedToken(Result);
- goto TryAgain;
case tok::code_completion:
if (CodeComplete)
CodeComplete->CodeCompleteDirective(
@@ -788,7 +815,7 @@ static bool GetLineValue(Token &DigitTok, unsigned &Val,
// here.
Val = 0;
for (unsigned i = 0; i != ActualLength; ++i) {
- if (!isdigit(DigitTokBegin[i])) {
+ if (!isDigit(DigitTokBegin[i])) {
PP.Diag(PP.AdvanceToTokenCharacter(DigitTok.getLocation(), i),
diag::err_pp_line_digit_sequence);
PP.DiscardUntilEndOfDirective();
@@ -834,11 +861,11 @@ void Preprocessor::HandleLineDirective(Token &Tok) {
// Enforce C99 6.10.4p3: "The digit sequence shall not specify ... a
// number greater than 2147483647". C90 requires that the line # be <= 32767.
unsigned LineLimit = 32768U;
- if (LangOpts.C99 || LangOpts.CPlusPlus0x)
+ if (LangOpts.C99 || LangOpts.CPlusPlus11)
LineLimit = 2147483648U;
if (LineNo >= LineLimit)
Diag(DigitTok, diag::ext_pp_line_too_big) << LineLimit;
- else if (LangOpts.CPlusPlus0x && LineNo >= 32768U)
+ else if (LangOpts.CPlusPlus11 && LineNo >= 32768U)
Diag(DigitTok, diag::warn_cxx98_compat_pp_line_too_big);
int FilenameID = -1;
@@ -1107,23 +1134,19 @@ void Preprocessor::HandleMacroPublicDirective(Token &Tok) {
// Check to see if this is the last token on the #__public_macro line.
CheckEndOfDirective("__public_macro");
+ IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
// Okay, we finally have a valid identifier to undef.
- MacroInfo *MI = getMacroInfo(MacroNameTok.getIdentifierInfo());
+ MacroDirective *MD = getMacroDirective(II);
// If the macro is not defined, this is an error.
- if (MI == 0) {
- Diag(MacroNameTok, diag::err_pp_visibility_non_macro)
- << MacroNameTok.getIdentifierInfo();
+ if (MD == 0) {
+ Diag(MacroNameTok, diag::err_pp_visibility_non_macro) << II;
return;
}
// Note that this macro has now been exported.
- MI->setVisibility(/*IsPublic=*/true, MacroNameTok.getLocation());
-
- // If this macro definition came from a PCH file, mark it
- // as having changed since serialization.
- if (MI->isFromAST())
- MI->setChangedAfterLoad();
+ appendMacroDirective(II, AllocateVisibilityMacroDirective(
+ MacroNameTok.getLocation(), /*IsPublic=*/true));
}
/// \brief Handle a #private directive.
@@ -1138,23 +1161,19 @@ void Preprocessor::HandleMacroPrivateDirective(Token &Tok) {
// Check to see if this is the last token on the #__private_macro line.
CheckEndOfDirective("__private_macro");
+ IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
// Okay, we finally have a valid identifier to undef.
- MacroInfo *MI = getMacroInfo(MacroNameTok.getIdentifierInfo());
+ MacroDirective *MD = getMacroDirective(II);
// If the macro is not defined, this is an error.
- if (MI == 0) {
- Diag(MacroNameTok, diag::err_pp_visibility_non_macro)
- << MacroNameTok.getIdentifierInfo();
+ if (MD == 0) {
+ Diag(MacroNameTok, diag::err_pp_visibility_non_macro) << II;
return;
}
// Note that this macro has now been marked private.
- MI->setVisibility(/*IsPublic=*/false, MacroNameTok.getLocation());
-
- // If this macro definition came from a PCH file, mark it
- // as having changed since serialization.
- if (MI->isFromAST())
- MI->setChangedAfterLoad();
+ appendMacroDirective(II, AllocateVisibilityMacroDirective(
+ MacroNameTok.getLocation(), /*IsPublic=*/false));
}
//===----------------------------------------------------------------------===//
@@ -1375,7 +1394,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
if (Callbacks->FileNotFound(Filename, RecoveryPath)) {
if (const DirectoryEntry *DE = FileMgr.getDirectory(RecoveryPath)) {
// Add the recovery path to the list of search paths.
- DirectoryLookup DL(DE, SrcMgr::C_User, true, false);
+ DirectoryLookup DL(DE, SrcMgr::C_User, false);
HeaderInfo.AddSearchPath(DL, isAngled);
// Try the lookup again, skipping the cache.
@@ -1426,7 +1445,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
// Compute the module access path corresponding to this module.
// FIXME: Should we have a second loadModule() overload to avoid this
// extra lookup step?
- llvm::SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
+ SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
for (Module *Mod = SuggestedModule; Mod; Mod = Mod->Parent)
Path.push_back(std::make_pair(getIdentifierInfo(Mod->Name),
FilenameTok.getLocation()));
@@ -1476,14 +1495,14 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
Diag(HashLoc, diag::warn_auto_module_import)
<< IncludeKind << PathString
<< FixItHint::CreateReplacement(ReplaceRange,
- "@__experimental_modules_import " + PathString.str().str() + ";");
+ "@import " + PathString.str().str() + ";");
}
// Load the module.
// If this was an #__include_macros directive, only make macros visible.
Module::NameVisibilityKind Visibility
= (IncludeKind == 3)? Module::MacrosVisible : Module::AllVisible;
- Module *Imported
+ ModuleLoadResult Imported
= TheModuleLoader.loadModule(IncludeTok.getLocation(), Path, Visibility,
/*IsIncludeDirective=*/true);
assert((Imported == 0 || Imported == SuggestedModule) &&
@@ -1498,6 +1517,13 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc,
}
return;
}
+
+ // If we failed to find a submodule that we expected to find, we can
+ // continue. Otherwise, there's an error in the included file, so we
+ // don't want to include it.
+ if (!BuildingImportedModule && !Imported.isMissingExpected()) {
+ return;
+ }
}
if (Callbacks && SuggestedModule) {
@@ -1637,10 +1663,16 @@ bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI, Token &Tok) {
return true;
case tok::ellipsis: // #define X(... -> C99 varargs
if (!LangOpts.C99)
- Diag(Tok, LangOpts.CPlusPlus0x ?
+ Diag(Tok, LangOpts.CPlusPlus11 ?
diag::warn_cxx98_compat_variadic_macro :
diag::ext_variadic_macro);
+ // OpenCL v1.2 s6.9.e: variadic macros are not supported.
+ if (LangOpts.OpenCL) {
+ Diag(Tok, diag::err_pp_opencl_variadic_macros);
+ return true;
+ }
+
// Lex the token after the identifier.
LexUnexpandedToken(Tok);
if (Tok.isNot(tok::r_paren)) {
@@ -1763,7 +1795,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
// Read the first token after the arg list for down below.
LexUnexpandedToken(Tok);
- } else if (LangOpts.C99 || LangOpts.CPlusPlus0x) {
+ } else if (LangOpts.C99 || LangOpts.CPlusPlus11) {
// C99 requires whitespace between the macro definition and the body. Emit
// a diagnostic for something like "#define X+".
Diag(Tok, diag::ext_c99_whitespace_required_after_macro_name);
@@ -1809,8 +1841,37 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
while (Tok.isNot(tok::eod)) {
LastTok = Tok;
- if (Tok.isNot(tok::hash)) {
+ if (Tok.isNot(tok::hash) && Tok.isNot(tok::hashhash)) {
+ MI->AddTokenToBody(Tok);
+
+ // Get the next token of the macro.
+ LexUnexpandedToken(Tok);
+ continue;
+ }
+
+ if (Tok.is(tok::hashhash)) {
+
+ // If we see token pasting, check if it looks like the gcc comma
+ // pasting extension. We'll use this information to suppress
+ // diagnostics later on.
+
+ // Get the next token of the macro.
+ LexUnexpandedToken(Tok);
+
+ if (Tok.is(tok::eod)) {
+ MI->AddTokenToBody(LastTok);
+ break;
+ }
+
+ unsigned NumTokens = MI->getNumTokens();
+ if (NumTokens && Tok.getIdentifierInfo() == Ident__VA_ARGS__ &&
+ MI->getReplacementToken(NumTokens-1).is(tok::comma))
+ MI->setHasCommaPasting();
+
+ // Things look ok, add the '##' and param name tokens to the macro.
+ MI->AddTokenToBody(LastTok);
MI->AddTokenToBody(Tok);
+ LastTok = Tok;
// Get the next token of the macro.
LexUnexpandedToken(Tok);
@@ -1874,7 +1935,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
// Finally, if this identifier already had a macro defined for it, verify that
// the macro bodies are identical, and issue diagnostics if they are not.
- if (MacroInfo *OtherMI = getMacroInfo(MacroNameTok.getIdentifierInfo())) {
+ if (const MacroInfo *OtherMI=getMacroInfo(MacroNameTok.getIdentifierInfo())) {
// It is very common for system headers to have tons of macro redefinitions
// and for warnings to be disabled in system headers. If this is the case,
// then don't bother calling MacroInfo::isIdenticalTo.
@@ -1883,10 +1944,14 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
if (!OtherMI->isUsed() && OtherMI->isWarnIfUnused())
Diag(OtherMI->getDefinitionLoc(), diag::pp_macro_not_used);
+ // Warn if defining "__LINE__" and other builtins, per C99 6.10.8/4 and
+ // C++ [cpp.predefined]p4, but allow it as an extension.
+ if (OtherMI->isBuiltinMacro())
+ Diag(MacroNameTok, diag::ext_pp_redef_builtin_macro);
// Macros must be identical. This means all tokens and whitespace
- // separation must be the same. C99 6.10.3.2.
- if (!OtherMI->isAllowRedefinitionsWithoutWarning() &&
- !MI->isIdenticalTo(*OtherMI, *this)) {
+ // separation must be the same. C99 6.10.3p2.
+ else if (!OtherMI->isAllowRedefinitionsWithoutWarning() &&
+ !MI->isIdenticalTo(*OtherMI, *this, /*Syntactic=*/LangOpts.MicrosoftExt)) {
Diag(MI->getDefinitionLoc(), diag::ext_pp_macro_redef)
<< MacroNameTok.getIdentifierInfo();
Diag(OtherMI->getDefinitionLoc(), diag::note_previous_definition);
@@ -1896,7 +1961,8 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
WarnUnusedMacroLocs.erase(OtherMI->getDefinitionLoc());
}
- setMacroInfo(MacroNameTok.getIdentifierInfo(), MI);
+ DefMacroDirective *MD =
+ appendDefMacroDirective(MacroNameTok.getIdentifierInfo(), MI);
assert(!MI->isUsed());
// If we need warning for not using the macro, add its location in the
@@ -1910,7 +1976,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) {
// If the callbacks want to know, tell them about the macro definition.
if (Callbacks)
- Callbacks->MacroDefined(MacroNameTok, MI);
+ Callbacks->MacroDefined(MacroNameTok, MD);
}
/// HandleUndefDirective - Implements \#undef.
@@ -1929,7 +1995,13 @@ void Preprocessor::HandleUndefDirective(Token &UndefTok) {
CheckEndOfDirective("undef");
// Okay, we finally have a valid identifier to undef.
- MacroInfo *MI = getMacroInfo(MacroNameTok.getIdentifierInfo());
+ MacroDirective *MD = getMacroDirective(MacroNameTok.getIdentifierInfo());
+ const MacroInfo *MI = MD ? MD->getMacroInfo() : 0;
+
+ // If the callbacks want to know, tell them about the macro #undef.
+ // Note: no matter if the macro was defined or not.
+ if (Callbacks)
+ Callbacks->MacroUndefined(MacroNameTok, MD);
// If the macro is not defined, this is a noop undef, just return.
if (MI == 0) return;
@@ -1937,27 +2009,11 @@ void Preprocessor::HandleUndefDirective(Token &UndefTok) {
if (!MI->isUsed() && MI->isWarnIfUnused())
Diag(MI->getDefinitionLoc(), diag::pp_macro_not_used);
- // If the callbacks want to know, tell them about the macro #undef.
- if (Callbacks)
- Callbacks->MacroUndefined(MacroNameTok, MI);
-
if (MI->isWarnIfUnused())
WarnUnusedMacroLocs.erase(MI->getDefinitionLoc());
- UndefineMacro(MacroNameTok.getIdentifierInfo(), MI,
- MacroNameTok.getLocation());
-}
-
-void Preprocessor::UndefineMacro(IdentifierInfo *II, MacroInfo *MI,
- SourceLocation UndefLoc) {
- MI->setUndefLoc(UndefLoc);
- if (MI->isFromAST()) {
- MI->setChangedAfterLoad();
- if (Listener)
- Listener->UndefinedMacro(MI);
- }
-
- clearMacroInfo(II);
+ appendMacroDirective(MacroNameTok.getIdentifierInfo(),
+ AllocateUndefMacroDirective(MacroNameTok.getLocation()));
}
@@ -1991,7 +2047,8 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef,
CheckEndOfDirective(isIfndef ? "ifndef" : "ifdef");
IdentifierInfo *MII = MacroNameTok.getIdentifierInfo();
- MacroInfo *MI = getMacroInfo(MII);
+ MacroDirective *MD = getMacroDirective(MII);
+ MacroInfo *MI = MD ? MD->getMacroInfo() : 0;
if (CurPPLexer->getConditionalStackDepth() == 0) {
// If the start of a top-level #ifdef and if the macro is not defined,
@@ -2011,9 +2068,9 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef,
if (Callbacks) {
if (isIfndef)
- Callbacks->Ifndef(DirectiveTok.getLocation(), MacroNameTok);
+ Callbacks->Ifndef(DirectiveTok.getLocation(), MacroNameTok, MD);
else
- Callbacks->Ifdef(DirectiveTok.getLocation(), MacroNameTok);
+ Callbacks->Ifdef(DirectiveTok.getLocation(), MacroNameTok, MD);
}
// Should we include the stuff contained by this directive?
diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp
index d5a88db..d9ce8bf 100644
--- a/lib/Lex/PPExpressions.cpp
+++ b/lib/Lex/PPExpressions.cpp
@@ -17,13 +17,14 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/MacroInfo.h"
-#include "clang/Lex/LiteralSupport.h"
-#include "clang/Lex/CodeCompletionHandler.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/CodeCompletionHandler.h"
#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Lex/LiteralSupport.h"
+#include "clang/Lex/MacroInfo.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
namespace {
@@ -111,15 +112,21 @@ static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
Result.Val = II->hasMacroDefinition();
Result.Val.setIsUnsigned(false); // Result is signed intmax_t.
+ MacroDirective *Macro = 0;
// If there is a macro, mark it used.
if (Result.Val != 0 && ValueLive) {
- MacroInfo *Macro = PP.getMacroInfo(II);
- PP.markMacroAsUsed(Macro);
+ Macro = PP.getMacroDirective(II);
+ PP.markMacroAsUsed(Macro->getMacroInfo());
}
// Invoke the 'defined' callback.
- if (PPCallbacks *Callbacks = PP.getPPCallbacks())
- Callbacks->Defined(PeekTok);
+ if (PPCallbacks *Callbacks = PP.getPPCallbacks()) {
+ MacroDirective *MD = Macro;
+ // Pass the MacroInfo for the macro name even if the value is dead.
+ if (!MD && Result.Val != 0)
+ MD = PP.getMacroDirective(II);
+ Callbacks->Defined(PeekTok, MD);
+ }
// If we are in parens, ensure we have a trailing ).
if (LParenLoc.isValid()) {
@@ -224,7 +231,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
if (!PP.getLangOpts().C99 && Literal.isLongLong) {
if (PP.getLangOpts().CPlusPlus)
PP.Diag(PeekTok,
- PP.getLangOpts().CPlusPlus0x ?
+ PP.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong);
else
PP.Diag(PeekTok, diag::ext_c99_longlong);
@@ -258,9 +265,9 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
return false;
}
case tok::char_constant: // 'x'
- case tok::wide_char_constant: { // L'x'
+ case tok::wide_char_constant: // L'x'
case tok::utf16_char_constant: // u'x'
- case tok::utf32_char_constant: // U'x'
+ case tok::utf32_char_constant: { // U'x'
// Complain about, and drop, any ud-suffix.
if (PeekTok.hasUDSuffix())
PP.Diag(PeekTok, diag::err_pp_invalid_udl) << /*character*/0;
@@ -724,6 +731,7 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec,
/// to "!defined(X)" return X in IfNDefMacro.
bool Preprocessor::
EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
+ SaveAndRestore<bool> PPDir(ParsingIfOrElifDirective, true);
// Save the current state of 'DisableMacroExpansion' and reset it to false. If
// 'DisableMacroExpansion' is true, then we must be in a macro argument list
// in which case a directive is undefined behavior. We want macros to be able
diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp
index d827f58..be4defe 100644
--- a/lib/Lex/PPLexerChange.cpp
+++ b/lib/Lex/PPLexerChange.cpp
@@ -13,15 +13,15 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/HeaderSearch.h"
-#include "clang/Lex/MacroInfo.h"
-#include "clang/Lex/LexDiagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Lex/MacroInfo.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PathV2.h"
-#include "llvm/ADT/StringSwitch.h"
using namespace clang;
PPCallbacks::~PPCallbacks() {}
@@ -158,15 +158,17 @@ void Preprocessor::EnterSourceFileWithPTH(PTHLexer *PL,
/// tokens from it instead of the current buffer.
void Preprocessor::EnterMacro(Token &Tok, SourceLocation ILEnd,
MacroInfo *Macro, MacroArgs *Args) {
- PushIncludeMacroStack();
- CurDirLookup = 0;
-
+ TokenLexer *TokLexer;
if (NumCachedTokenLexers == 0) {
- CurTokenLexer.reset(new TokenLexer(Tok, ILEnd, Macro, Args, *this));
+ TokLexer = new TokenLexer(Tok, ILEnd, Macro, Args, *this);
} else {
- CurTokenLexer.reset(TokenLexerCache[--NumCachedTokenLexers]);
- CurTokenLexer->Init(Tok, ILEnd, Macro, Args);
+ TokLexer = TokenLexerCache[--NumCachedTokenLexers];
+ TokLexer->Init(Tok, ILEnd, Macro, Args);
}
+
+ PushIncludeMacroStack();
+ CurDirLookup = 0;
+ CurTokenLexer.reset(TokLexer);
if (CurLexerKind != CLK_LexAfterModuleImport)
CurLexerKind = CLK_TokenLexer;
}
@@ -186,18 +188,20 @@ void Preprocessor::EnterMacro(Token &Tok, SourceLocation ILEnd,
void Preprocessor::EnterTokenStream(const Token *Toks, unsigned NumToks,
bool DisableMacroExpansion,
bool OwnsTokens) {
- // Save our current state.
- PushIncludeMacroStack();
- CurDirLookup = 0;
-
// Create a macro expander to expand from the specified token stream.
+ TokenLexer *TokLexer;
if (NumCachedTokenLexers == 0) {
- CurTokenLexer.reset(new TokenLexer(Toks, NumToks, DisableMacroExpansion,
- OwnsTokens, *this));
+ TokLexer = new TokenLexer(Toks, NumToks, DisableMacroExpansion,
+ OwnsTokens, *this);
} else {
- CurTokenLexer.reset(TokenLexerCache[--NumCachedTokenLexers]);
- CurTokenLexer->Init(Toks, NumToks, DisableMacroExpansion, OwnsTokens);
+ TokLexer = TokenLexerCache[--NumCachedTokenLexers];
+ TokLexer->Init(Toks, NumToks, DisableMacroExpansion, OwnsTokens);
}
+
+ // Save our current state.
+ PushIncludeMacroStack();
+ CurDirLookup = 0;
+ CurTokenLexer.reset(TokLexer);
if (CurLexerKind != CLK_LexAfterModuleImport)
CurLexerKind = CLK_TokenLexer;
}
@@ -328,6 +332,17 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
CurLexer->BufferPtr = EndPos;
CurLexer->FormTokenWithChars(Result, EndPos, tok::eof);
+ if (isCodeCompletionEnabled()) {
+ // Inserting the code-completion point increases the source buffer by 1,
+ // but the main FileID was created before inserting the point.
+ // Compensate by reducing the EOF location by 1, otherwise the location
+ // will point to the next FileID.
+ // FIXME: This is hacky, the code-completion point should probably be
+ // inserted before the main FileID is created.
+ if (CurLexer->getFileLoc() == CodeCompletionFileLoc)
+ Result.setLocation(Result.getLocation().getLocWithOffset(-1));
+ }
+
if (!isIncrementalProcessingEnabled())
// We're done with lexing.
CurLexer.reset();
@@ -380,7 +395,7 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
SmallString<128> RelativePath;
computeRelativePath(FileMgr, Dir, Header, RelativePath);
Diag(StartLoc, diag::warn_uncovered_module_header)
- << RelativePath;
+ << Mod->getFullModuleName() << RelativePath;
}
}
}
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index eee4342..21451f5 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -14,25 +14,26 @@
#include "clang/Lex/Preprocessor.h"
#include "MacroArgs.h"
-#include "clang/Lex/MacroInfo.h"
-#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/Lex/LexDiagnostic.h"
#include "clang/Lex/CodeCompletionHandler.h"
#include "clang/Lex/ExternalPreprocessorSource.h"
-#include "clang/Lex/LiteralSupport.h"
-#include "llvm/ADT/StringSwitch.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Lex/MacroInfo.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Config/llvm-config.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
#include <cstdio>
#include <ctime>
using namespace clang;
-MacroInfo *Preprocessor::getMacroInfoHistory(IdentifierInfo *II) const {
+MacroDirective *
+Preprocessor::getMacroDirectiveHistory(const IdentifierInfo *II) const {
assert(II->hadMacroDefinition() && "Identifier has not been not a macro!");
macro_iterator Pos = Macros.find(II);
@@ -40,125 +41,31 @@ MacroInfo *Preprocessor::getMacroInfoHistory(IdentifierInfo *II) const {
return Pos->second;
}
-/// setMacroInfo - Specify a macro for this identifier.
-///
-void Preprocessor::setMacroInfo(IdentifierInfo *II, MacroInfo *MI) {
- assert(MI && "MacroInfo should be non-zero!");
- assert(MI->getUndefLoc().isInvalid() &&
- "Undefined macros cannot be registered");
-
- MacroInfo *&StoredMI = Macros[II];
- MI->setPreviousDefinition(StoredMI);
- StoredMI = MI;
- II->setHasMacroDefinition(MI->getUndefLoc().isInvalid());
- if (II->isFromAST())
- II->setChangedSinceDeserialization();
-}
-
-void Preprocessor::addLoadedMacroInfo(IdentifierInfo *II, MacroInfo *MI,
- MacroInfo *Hint) {
- assert(MI && "Missing macro?");
- assert(MI->isFromAST() && "Macro is not from an AST?");
- assert(!MI->getPreviousDefinition() && "Macro already in chain?");
-
- MacroInfo *&StoredMI = Macros[II];
-
- // Easy case: this is the first macro definition for this macro.
- if (!StoredMI) {
- StoredMI = MI;
-
- if (MI->isDefined())
- II->setHasMacroDefinition(true);
- return;
- }
-
- // If this macro is a definition and this identifier has been neither
- // defined nor undef'd in the current translation unit, add this macro
- // to the end of the chain of definitions.
- if (MI->isDefined() && StoredMI->isFromAST()) {
- // Simple case: if this is the first actual definition, just put it at
- // th beginning.
- if (!StoredMI->isDefined()) {
- MI->setPreviousDefinition(StoredMI);
- StoredMI = MI;
-
- II->setHasMacroDefinition(true);
- return;
- }
-
- // Find the end of the definition chain.
- MacroInfo *Prev;
- MacroInfo *PrevPrev = StoredMI;
- bool Ambiguous = StoredMI->isAmbiguous();
- bool MatchedOther = false;
- do {
- Prev = PrevPrev;
-
- // If the macros are not identical, we have an ambiguity.
- if (!Prev->isIdenticalTo(*MI, *this)) {
- if (!Ambiguous) {
- Ambiguous = true;
- StoredMI->setAmbiguous(true);
- }
- } else {
- MatchedOther = true;
- }
- } while ((PrevPrev = Prev->getPreviousDefinition()) &&
- PrevPrev->isDefined());
-
- // If there are ambiguous definitions, and we didn't match any other
- // definition, then mark us as ambiguous.
- if (Ambiguous && !MatchedOther)
- MI->setAmbiguous(true);
-
- // Wire this macro information into the chain.
- MI->setPreviousDefinition(Prev->getPreviousDefinition());
- Prev->setPreviousDefinition(MI);
- return;
- }
-
- // The macro is not a definition; put it at the end of the list.
- MacroInfo *Prev = Hint? Hint : StoredMI;
- while (Prev->getPreviousDefinition())
- Prev = Prev->getPreviousDefinition();
- Prev->setPreviousDefinition(MI);
-}
-
-void Preprocessor::makeLoadedMacroInfoVisible(IdentifierInfo *II,
- MacroInfo *MI) {
- assert(MI->isFromAST() && "Macro must be from the AST");
-
- MacroInfo *&StoredMI = Macros[II];
- if (StoredMI == MI) {
- // Easy case: this is the first macro anyway.
- II->setHasMacroDefinition(MI->isDefined());
- return;
- }
-
- // Go find the macro and pull it out of the list.
- // FIXME: Yes, this is O(N), and making a pile of macros visible or hidden
- // would be quadratic, but it's extremely rare.
- MacroInfo *Prev = StoredMI;
- while (Prev->getPreviousDefinition() != MI)
- Prev = Prev->getPreviousDefinition();
- Prev->setPreviousDefinition(MI->getPreviousDefinition());
- MI->setPreviousDefinition(0);
-
- // Add the macro back to the list.
- addLoadedMacroInfo(II, MI);
-
- II->setHasMacroDefinition(StoredMI->isDefined());
- if (II->isFromAST())
+void Preprocessor::appendMacroDirective(IdentifierInfo *II, MacroDirective *MD){
+ assert(MD && "MacroDirective should be non-zero!");
+ assert(!MD->getPrevious() && "Already attached to a MacroDirective history.");
+
+ MacroDirective *&StoredMD = Macros[II];
+ MD->setPrevious(StoredMD);
+ StoredMD = MD;
+ II->setHasMacroDefinition(MD->isDefined());
+ bool isImportedMacro = isa<DefMacroDirective>(MD) &&
+ cast<DefMacroDirective>(MD)->isImported();
+ if (II->isFromAST() && !isImportedMacro)
II->setChangedSinceDeserialization();
}
-/// \brief Undefine a macro for this identifier.
-void Preprocessor::clearMacroInfo(IdentifierInfo *II) {
- assert(II->hasMacroDefinition() && "Macro is not defined!");
- assert(Macros[II]->getUndefLoc().isValid() && "Macro is still defined!");
- II->setHasMacroDefinition(false);
- if (II->isFromAST())
- II->setChangedSinceDeserialization();
+void Preprocessor::setLoadedMacroDirective(IdentifierInfo *II,
+ MacroDirective *MD) {
+ assert(II && MD);
+ MacroDirective *&StoredMD = Macros[II];
+ assert(!StoredMD &&
+ "the macro history was modified before initializing it from a pch");
+ StoredMD = MD;
+ // Setup the identifier as having associated macro history.
+ II->setHasMacroDefinition(true);
+ if (!MD->isDefined())
+ II->setHasMacroDefinition(false);
}
/// RegisterBuiltinMacro - Register the specified identifier in the identifier
@@ -170,7 +77,7 @@ static IdentifierInfo *RegisterBuiltinMacro(Preprocessor &PP, const char *Name){
// Mark it as being a macro that is builtin.
MacroInfo *MI = PP.AllocateMacroInfo(SourceLocation());
MI->setIsBuiltinMacro();
- PP.setMacroInfo(Id, MI);
+ PP.appendDefMacroDirective(Id, MI);
return Id;
}
@@ -303,7 +210,11 @@ bool Preprocessor::isNextPPTokenLParen() {
/// HandleMacroExpandedIdentifier - If an identifier token is read that is to be
/// expanded as a macro, handle it and return the next token as 'Identifier'.
bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
- MacroInfo *MI) {
+ MacroDirective *MD) {
+ MacroDirective::DefInfo Def = MD->getDefinition();
+ assert(Def.isValid());
+ MacroInfo *MI = Def.getMacroInfo();
+
// If this is a macro expansion in the "#if !defined(x)" line for the file,
// then the macro could expand to different things in other contexts, we need
// to disable the optimization in this case.
@@ -311,7 +222,7 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
// If this is a builtin macro, like __LINE__ or _Pragma, handle it specially.
if (MI->isBuiltinMacro()) {
- if (Callbacks) Callbacks->MacroExpands(Identifier, MI,
+ if (Callbacks) Callbacks->MacroExpands(Identifier, MD,
Identifier.getLocation());
ExpandBuiltinMacro(Identifier);
return false;
@@ -364,13 +275,13 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
// MacroExpands callbacks still happen in source order, queue this
// callback to have it happen after the function macro callback.
DelayedMacroExpandsCallbacks.push_back(
- MacroExpandsInfo(Identifier, MI, ExpansionRange));
+ MacroExpandsInfo(Identifier, MD, ExpansionRange));
} else {
- Callbacks->MacroExpands(Identifier, MI, ExpansionRange);
+ Callbacks->MacroExpands(Identifier, MD, ExpansionRange);
if (!DelayedMacroExpandsCallbacks.empty()) {
for (unsigned i=0, e = DelayedMacroExpandsCallbacks.size(); i!=e; ++i) {
MacroExpandsInfo &Info = DelayedMacroExpandsCallbacks[i];
- Callbacks->MacroExpands(Info.Tok, Info.MI, Info.Range);
+ Callbacks->MacroExpands(Info.Tok, Info.MD, Info.Range);
}
DelayedMacroExpandsCallbacks.clear();
}
@@ -378,16 +289,17 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
}
// If the macro definition is ambiguous, complain.
- if (MI->isAmbiguous()) {
+ if (Def.getDirective()->isAmbiguous()) {
Diag(Identifier, diag::warn_pp_ambiguous_macro)
<< Identifier.getIdentifierInfo();
Diag(MI->getDefinitionLoc(), diag::note_pp_ambiguous_macro_chosen)
<< Identifier.getIdentifierInfo();
- for (MacroInfo *PrevMI = MI->getPreviousDefinition();
- PrevMI && PrevMI->isDefined();
- PrevMI = PrevMI->getPreviousDefinition()) {
- if (PrevMI->isAmbiguous()) {
- Diag(PrevMI->getDefinitionLoc(), diag::note_pp_ambiguous_macro_other)
+ for (MacroDirective::DefInfo PrevDef = Def.getPreviousDefinition();
+ PrevDef && !PrevDef.isUndefined();
+ PrevDef = PrevDef.getPreviousDefinition()) {
+ if (PrevDef.getDirective()->isAmbiguous()) {
+ Diag(PrevDef.getMacroInfo()->getDefinitionLoc(),
+ diag::note_pp_ambiguous_macro_other)
<< Identifier.getIdentifierInfo();
}
}
@@ -455,7 +367,10 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier,
if (MacroInfo *NewMI = getMacroInfo(NewII))
if (!NewMI->isEnabled() || NewMI == MI) {
Identifier.setFlag(Token::DisableExpand);
- Diag(Identifier, diag::pp_disabled_macro_expansion);
+ // Don't warn for "#define X X" like "#define bool bool" from
+ // stdbool.h.
+ if (NewMI != MI || MI->isFunctionLike())
+ Diag(Identifier, diag::pp_disabled_macro_expansion);
}
}
@@ -497,9 +412,13 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
// argument is separated by an EOF token. Use a SmallVector so we can avoid
// heap allocations in the common case.
SmallVector<Token, 64> ArgTokens;
+ bool ContainsCodeCompletionTok = false;
unsigned NumActuals = 0;
while (Tok.isNot(tok::r_paren)) {
+ if (ContainsCodeCompletionTok && (Tok.is(tok::eof) || Tok.is(tok::eod)))
+ break;
+
assert((Tok.is(tok::l_paren) || Tok.is(tok::comma)) &&
"only expect argument separators here");
@@ -516,10 +435,20 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
LexUnexpandedToken(Tok);
if (Tok.is(tok::eof) || Tok.is(tok::eod)) { // "#if f(<eof>" & "#if f(\n"
- Diag(MacroName, diag::err_unterm_macro_invoc);
- // Do not lose the EOF/EOD. Return it to the client.
- MacroName = Tok;
- return 0;
+ if (!ContainsCodeCompletionTok) {
+ Diag(MacroName, diag::err_unterm_macro_invoc);
+ Diag(MI->getDefinitionLoc(), diag::note_macro_here)
+ << MacroName.getIdentifierInfo();
+ // Do not lose the EOF/EOD. Return it to the client.
+ MacroName = Tok;
+ return 0;
+ } else {
+ // Do not lose the EOF/EOD.
+ Token *Toks = new Token[1];
+ Toks[0] = Tok;
+ EnterTokenStream(Toks, 1, true, true);
+ break;
+ }
} else if (Tok.is(tok::r_paren)) {
// If we found the ) token, the macro arg list is done.
if (NumParens-- == 0) {
@@ -550,6 +479,7 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
if (!MI->isEnabled())
Tok.setFlag(Token::DisableExpand);
} else if (Tok.is(tok::code_completion)) {
+ ContainsCodeCompletionTok = true;
if (CodeComplete)
CodeComplete->CodeCompleteMacroArgument(MacroName.getIdentifierInfo(),
MI, NumActuals);
@@ -572,16 +502,20 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
if (ArgTokens.size() != ArgTokenStart)
ArgStartLoc = ArgTokens[ArgTokenStart].getLocation();
- // Emit the diagnostic at the macro name in case there is a missing ).
- // Emitting it at the , could be far away from the macro name.
- Diag(ArgStartLoc, diag::err_too_many_args_in_macro_invoc);
- return 0;
+ if (!ContainsCodeCompletionTok) {
+ // Emit the diagnostic at the macro name in case there is a missing ).
+ // Emitting it at the , could be far away from the macro name.
+ Diag(ArgStartLoc, diag::err_too_many_args_in_macro_invoc);
+ Diag(MI->getDefinitionLoc(), diag::note_macro_here)
+ << MacroName.getIdentifierInfo();
+ return 0;
+ }
}
// Empty arguments are standard in C99 and C++0x, and are supported as an extension in
// other modes.
if (ArgTokens.size() == ArgTokenStart && !LangOpts.C99)
- Diag(Tok, LangOpts.CPlusPlus0x ?
+ Diag(Tok, LangOpts.CPlusPlus11 ?
diag::warn_cxx98_compat_empty_fnmacro_arg :
diag::ext_empty_fnmacro_arg);
@@ -593,8 +527,10 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
EOFTok.setLength(0);
ArgTokens.push_back(EOFTok);
++NumActuals;
- assert(NumFixedArgsLeft != 0 && "Too many arguments parsed");
- --NumFixedArgsLeft;
+ if (!ContainsCodeCompletionTok || NumFixedArgsLeft != 0) {
+ assert(NumFixedArgsLeft != 0 && "Too many arguments parsed");
+ --NumFixedArgsLeft;
+ }
}
// Okay, we either found the r_paren. Check to see if we parsed too few
@@ -604,6 +540,17 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
// See MacroArgs instance var for description of this.
bool isVarargsElided = false;
+ if (ContainsCodeCompletionTok) {
+ // Recover from not-fully-formed macro invocation during code-completion.
+ Token EOFTok;
+ EOFTok.startToken();
+ EOFTok.setKind(tok::eof);
+ EOFTok.setLocation(Tok.getLocation());
+ EOFTok.setLength(0);
+ for (; NumActuals < MinArgsExpected; ++NumActuals)
+ ArgTokens.push_back(EOFTok);
+ }
+
if (NumActuals < MinArgsExpected) {
// There are several cases where too few arguments is ok, handle them now.
if (NumActuals == 0 && MinArgsExpected == 1) {
@@ -619,9 +566,14 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
// Varargs where the named vararg parameter is missing: OK as extension.
// #define A(x, ...)
// A("blah")
- Diag(Tok, diag::ext_missing_varargs_arg);
- Diag(MI->getDefinitionLoc(), diag::note_macro_here)
- << MacroName.getIdentifierInfo();
+ //
+ // If the macro contains the comma pasting extension, the diagnostic
+ // is suppressed; we know we'll get another diagnostic later.
+ if (!MI->hasCommaPasting()) {
+ Diag(Tok, diag::ext_missing_varargs_arg);
+ Diag(MI->getDefinitionLoc(), diag::note_macro_here)
+ << MacroName.getIdentifierInfo();
+ }
// Remember this occurred, allowing us to elide the comma when used for
// cases like:
@@ -630,9 +582,11 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
// #define C(...) blah(a, ## __VA_ARGS__)
// A(x) B(x) C()
isVarargsElided = true;
- } else {
+ } else if (!ContainsCodeCompletionTok) {
// Otherwise, emit the error.
Diag(Tok, diag::err_too_few_args_in_macro_invoc);
+ Diag(MI->getDefinitionLoc(), diag::note_macro_here)
+ << MacroName.getIdentifierInfo();
return 0;
}
@@ -648,10 +602,13 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName,
if (NumActuals == 0 && MinArgsExpected == 2)
ArgTokens.push_back(Tok);
- } else if (NumActuals > MinArgsExpected && !MI->isVariadic()) {
+ } else if (NumActuals > MinArgsExpected && !MI->isVariadic() &&
+ !ContainsCodeCompletionTok) {
// Emit the diagnostic at the macro name in case there is a missing ).
// Emitting it at the , could be far away from the macro name.
Diag(MacroName, diag::err_too_many_args_in_macro_invoc);
+ Diag(MI->getDefinitionLoc(), diag::note_macro_here)
+ << MacroName.getIdentifierInfo();
return 0;
}
@@ -745,7 +702,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
Feature = Feature.substr(2, Feature.size() - 4);
return llvm::StringSwitch<bool>(Feature)
- .Case("address_sanitizer", LangOpts.SanitizeAddress)
+ .Case("address_sanitizer", LangOpts.Sanitize.Address)
.Case("attribute_analyzer_noreturn", true)
.Case("attribute_availability", true)
.Case("attribute_availability_with_message", true)
@@ -767,6 +724,8 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("cxx_exceptions", LangOpts.Exceptions)
.Case("cxx_rtti", LangOpts.RTTI)
.Case("enumerator_attributes", true)
+ .Case("memory_sanitizer", LangOpts.Sanitize.Memory)
+ .Case("thread_sanitizer", LangOpts.Sanitize.Thread)
// Objective-C features
.Case("objc_arr", LangOpts.ObjCAutoRefCount) // FIXME: REMOVE?
.Case("objc_arc", LangOpts.ObjCAutoRefCount)
@@ -776,6 +735,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("objc_instancetype", LangOpts.ObjC2)
.Case("objc_modules", LangOpts.ObjC2 && LangOpts.Modules)
.Case("objc_nonfragile_abi", LangOpts.ObjCRuntime.isNonFragile())
+ .Case("objc_property_explicit_atomic", true) // Does clang support explicit "atomic" keyword?
.Case("objc_weak_class", LangOpts.ObjCRuntime.hasWeakClassImport())
.Case("ownership_holds", true)
.Case("ownership_returns", true)
@@ -792,41 +752,41 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("c_generic_selections", LangOpts.C11)
.Case("c_static_assert", LangOpts.C11)
// C++11 features
- .Case("cxx_access_control_sfinae", LangOpts.CPlusPlus0x)
- .Case("cxx_alias_templates", LangOpts.CPlusPlus0x)
- .Case("cxx_alignas", LangOpts.CPlusPlus0x)
- .Case("cxx_atomic", LangOpts.CPlusPlus0x)
- .Case("cxx_attributes", LangOpts.CPlusPlus0x)
- .Case("cxx_auto_type", LangOpts.CPlusPlus0x)
- .Case("cxx_constexpr", LangOpts.CPlusPlus0x)
- .Case("cxx_decltype", LangOpts.CPlusPlus0x)
- .Case("cxx_decltype_incomplete_return_types", LangOpts.CPlusPlus0x)
- .Case("cxx_default_function_template_args", LangOpts.CPlusPlus0x)
- .Case("cxx_defaulted_functions", LangOpts.CPlusPlus0x)
- .Case("cxx_delegating_constructors", LangOpts.CPlusPlus0x)
- .Case("cxx_deleted_functions", LangOpts.CPlusPlus0x)
- .Case("cxx_explicit_conversions", LangOpts.CPlusPlus0x)
- .Case("cxx_generalized_initializers", LangOpts.CPlusPlus0x)
- .Case("cxx_implicit_moves", LangOpts.CPlusPlus0x)
+ .Case("cxx_access_control_sfinae", LangOpts.CPlusPlus11)
+ .Case("cxx_alias_templates", LangOpts.CPlusPlus11)
+ .Case("cxx_alignas", LangOpts.CPlusPlus11)
+ .Case("cxx_atomic", LangOpts.CPlusPlus11)
+ .Case("cxx_attributes", LangOpts.CPlusPlus11)
+ .Case("cxx_auto_type", LangOpts.CPlusPlus11)
+ .Case("cxx_constexpr", LangOpts.CPlusPlus11)
+ .Case("cxx_decltype", LangOpts.CPlusPlus11)
+ .Case("cxx_decltype_incomplete_return_types", LangOpts.CPlusPlus11)
+ .Case("cxx_default_function_template_args", LangOpts.CPlusPlus11)
+ .Case("cxx_defaulted_functions", LangOpts.CPlusPlus11)
+ .Case("cxx_delegating_constructors", LangOpts.CPlusPlus11)
+ .Case("cxx_deleted_functions", LangOpts.CPlusPlus11)
+ .Case("cxx_explicit_conversions", LangOpts.CPlusPlus11)
+ .Case("cxx_generalized_initializers", LangOpts.CPlusPlus11)
+ .Case("cxx_implicit_moves", LangOpts.CPlusPlus11)
//.Case("cxx_inheriting_constructors", false)
- .Case("cxx_inline_namespaces", LangOpts.CPlusPlus0x)
- .Case("cxx_lambdas", LangOpts.CPlusPlus0x)
- .Case("cxx_local_type_template_args", LangOpts.CPlusPlus0x)
- .Case("cxx_nonstatic_member_init", LangOpts.CPlusPlus0x)
- .Case("cxx_noexcept", LangOpts.CPlusPlus0x)
- .Case("cxx_nullptr", LangOpts.CPlusPlus0x)
- .Case("cxx_override_control", LangOpts.CPlusPlus0x)
- .Case("cxx_range_for", LangOpts.CPlusPlus0x)
- .Case("cxx_raw_string_literals", LangOpts.CPlusPlus0x)
- .Case("cxx_reference_qualified_functions", LangOpts.CPlusPlus0x)
- .Case("cxx_rvalue_references", LangOpts.CPlusPlus0x)
- .Case("cxx_strong_enums", LangOpts.CPlusPlus0x)
- .Case("cxx_static_assert", LangOpts.CPlusPlus0x)
- .Case("cxx_trailing_return", LangOpts.CPlusPlus0x)
- .Case("cxx_unicode_literals", LangOpts.CPlusPlus0x)
- .Case("cxx_unrestricted_unions", LangOpts.CPlusPlus0x)
- .Case("cxx_user_literals", LangOpts.CPlusPlus0x)
- .Case("cxx_variadic_templates", LangOpts.CPlusPlus0x)
+ .Case("cxx_inline_namespaces", LangOpts.CPlusPlus11)
+ .Case("cxx_lambdas", LangOpts.CPlusPlus11)
+ .Case("cxx_local_type_template_args", LangOpts.CPlusPlus11)
+ .Case("cxx_nonstatic_member_init", LangOpts.CPlusPlus11)
+ .Case("cxx_noexcept", LangOpts.CPlusPlus11)
+ .Case("cxx_nullptr", LangOpts.CPlusPlus11)
+ .Case("cxx_override_control", LangOpts.CPlusPlus11)
+ .Case("cxx_range_for", LangOpts.CPlusPlus11)
+ .Case("cxx_raw_string_literals", LangOpts.CPlusPlus11)
+ .Case("cxx_reference_qualified_functions", LangOpts.CPlusPlus11)
+ .Case("cxx_rvalue_references", LangOpts.CPlusPlus11)
+ .Case("cxx_strong_enums", LangOpts.CPlusPlus11)
+ .Case("cxx_static_assert", LangOpts.CPlusPlus11)
+ .Case("cxx_trailing_return", LangOpts.CPlusPlus11)
+ .Case("cxx_unicode_literals", LangOpts.CPlusPlus11)
+ .Case("cxx_unrestricted_unions", LangOpts.CPlusPlus11)
+ .Case("cxx_user_literals", LangOpts.CPlusPlus11)
+ .Case("cxx_variadic_templates", LangOpts.CPlusPlus11)
// Type traits
.Case("has_nothrow_assign", LangOpts.CPlusPlus)
.Case("has_nothrow_copy", LangOpts.CPlusPlus)
@@ -840,10 +800,6 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("is_base_of", LangOpts.CPlusPlus)
.Case("is_class", LangOpts.CPlusPlus)
.Case("is_convertible_to", LangOpts.CPlusPlus)
- // __is_empty is available only if the horrible
- // "struct __is_empty" parsing hack hasn't been needed in this
- // translation unit. If it has, __is_empty reverts to a normal
- // identifier and __has_feature(is_empty) evaluates false.
.Case("is_empty", LangOpts.CPlusPlus)
.Case("is_enum", LangOpts.CPlusPlus)
.Case("is_final", LangOpts.CPlusPlus)
@@ -926,9 +882,15 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
IdentifierInfo *II, Preprocessor &PP,
const DirectoryLookup *LookupFrom) {
// Save the location of the current token. If a '(' is later found, use
- // that location. If no, use the end of this location instead.
+ // that location. If not, use the end of this location instead.
SourceLocation LParenLoc = Tok.getLocation();
+ // These expressions are only allowed within a preprocessor directive.
+ if (!PP.isParsingIfOrElifDirective()) {
+ PP.Diag(LParenLoc, diag::err_pp_directive_required) << II->getName();
+ return false;
+ }
+
// Get '('.
PP.LexNonComment(Tok);
@@ -946,8 +908,14 @@ static bool EvaluateHasIncludeCommon(Token &Tok,
// Save '(' location for possible missing ')' message.
LParenLoc = Tok.getLocation();
- // Get the file name.
- PP.getCurrentLexer()->LexIncludeFilename(Tok);
+ if (PP.getCurrentLexer()) {
+ // Get the file name.
+ PP.getCurrentLexer()->LexIncludeFilename(Tok);
+ } else {
+ // We're in a macro, so we can't use LexIncludeFilename; just
+ // grab the next token.
+ PP.Lex(Tok);
+ }
}
// Reserve a buffer to get the spelling.
@@ -1223,15 +1191,15 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
IdentifierInfo *FeatureII = 0;
// Read the '('.
- Lex(Tok);
+ LexUnexpandedToken(Tok);
if (Tok.is(tok::l_paren)) {
// Read the identifier
- Lex(Tok);
+ LexUnexpandedToken(Tok);
if (Tok.is(tok::identifier) || Tok.is(tok::kw_const)) {
FeatureII = Tok.getIdentifierInfo();
// Read the ')'.
- Lex(Tok);
+ LexUnexpandedToken(Tok);
if (Tok.is(tok::r_paren))
IsValid = true;
}
@@ -1275,69 +1243,49 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
bool IsValid = false;
bool Value = false;
// Read the '('.
- Lex(Tok);
+ LexUnexpandedToken(Tok);
do {
- if (Tok.is(tok::l_paren)) {
- // Read the string.
- Lex(Tok);
-
- // We need at least one string literal.
- if (!Tok.is(tok::string_literal)) {
- StartLoc = Tok.getLocation();
- IsValid = false;
- // Eat tokens until ')'.
- do Lex(Tok); while (!(Tok.is(tok::r_paren) || Tok.is(tok::eod)));
- break;
- }
-
- // String concatenation allows multiple strings, which can even come
- // from macro expansion.
- SmallVector<Token, 4> StrToks;
- while (Tok.is(tok::string_literal)) {
- // Complain about, and drop, any ud-suffix.
- if (Tok.hasUDSuffix())
- Diag(Tok, diag::err_invalid_string_udl);
- StrToks.push_back(Tok);
+ if (Tok.isNot(tok::l_paren)) {
+ Diag(StartLoc, diag::err_warning_check_malformed);
+ break;
+ }
+
+ LexUnexpandedToken(Tok);
+ std::string WarningName;
+ SourceLocation StrStartLoc = Tok.getLocation();
+ if (!FinishLexStringLiteral(Tok, WarningName, "'__has_warning'",
+ /*MacroExpansion=*/false)) {
+ // Eat tokens until ')'.
+ while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::eod) &&
+ Tok.isNot(tok::eof))
LexUnexpandedToken(Tok);
- }
-
- // Is the end a ')'?
- if (!(IsValid = Tok.is(tok::r_paren)))
- break;
-
- // Concatenate and parse the strings.
- StringLiteralParser Literal(&StrToks[0], StrToks.size(), *this);
- assert(Literal.isAscii() && "Didn't allow wide strings in");
- if (Literal.hadError)
- break;
- if (Literal.Pascal) {
- Diag(Tok, diag::warn_pragma_diagnostic_invalid);
- break;
- }
-
- StringRef WarningName(Literal.GetString());
-
- if (WarningName.size() < 3 || WarningName[0] != '-' ||
- WarningName[1] != 'W') {
- Diag(StrToks[0].getLocation(), diag::warn_has_warning_invalid_option);
- break;
- }
-
- // Finally, check if the warning flags maps to a diagnostic group.
- // We construct a SmallVector here to talk to getDiagnosticIDs().
- // Although we don't use the result, this isn't a hot path, and not
- // worth special casing.
- llvm::SmallVector<diag::kind, 10> Diags;
- Value = !getDiagnostics().getDiagnosticIDs()->
- getDiagnosticsInGroup(WarningName.substr(2), Diags);
+ break;
+ }
+
+ // Is the end a ')'?
+ if (!(IsValid = Tok.is(tok::r_paren))) {
+ Diag(StartLoc, diag::err_warning_check_malformed);
+ break;
+ }
+
+ if (WarningName.size() < 3 || WarningName[0] != '-' ||
+ WarningName[1] != 'W') {
+ Diag(StrStartLoc, diag::warn_has_warning_invalid_option);
+ break;
}
+
+ // Finally, check if the warning flags maps to a diagnostic group.
+ // We construct a SmallVector here to talk to getDiagnosticIDs().
+ // Although we don't use the result, this isn't a hot path, and not
+ // worth special casing.
+ SmallVector<diag::kind, 10> Diags;
+ Value = !getDiagnostics().getDiagnosticIDs()->
+ getDiagnosticsInGroup(WarningName.substr(2), Diags);
} while (false);
-
- if (!IsValid)
- Diag(StartLoc, diag::err_warning_check_malformed);
OS << (int)Value;
- Tok.setKind(tok::numeric_constant);
+ if (IsValid)
+ Tok.setKind(tok::numeric_constant);
} else if (II == Ident__building_module) {
// The argument to this builtin should be an identifier. The
// builtin evaluates to 1 when that identifier names the module we are
diff --git a/lib/Lex/PTHLexer.cpp b/lib/Lex/PTHLexer.cpp
index b167172..e8f43f7 100644
--- a/lib/Lex/PTHLexer.cpp
+++ b/lib/Lex/PTHLexer.cpp
@@ -11,17 +11,16 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Basic/TokenKinds.h"
+#include "clang/Lex/PTHLexer.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemStatCache.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/OnDiskHashTable.h"
+#include "clang/Basic/TokenKinds.h"
#include "clang/Lex/LexDiagnostic.h"
-#include "clang/Lex/PTHLexer.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PTHManager.h"
-#include "clang/Lex/Token.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/Token.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
@@ -679,13 +678,13 @@ public:
~PTHStatCache() {}
LookupResult getStat(const char *Path, struct stat &StatBuf,
- int *FileDescriptor) {
+ bool isFile, int *FileDescriptor) {
// Do the lookup for the file's data in the PTH file.
CacheTy::iterator I = Cache.find(Path);
// If we don't get a hit in the PTH file just forward to 'stat'.
if (I == Cache.end())
- return statChained(Path, StatBuf, FileDescriptor);
+ return statChained(Path, StatBuf, isFile, FileDescriptor);
const PTHStatData &Data = *I;
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index e7e6c37..95e8a8c 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -13,13 +13,13 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/Pragma.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/LexDiagnostic.h"
#include "clang/Lex/LiteralSupport.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/MacroInfo.h"
-#include "clang/Lex/LexDiagnostic.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Preprocessor.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
@@ -184,7 +184,7 @@ void Preprocessor::Handle_Pragma(Token &Tok) {
// Read the '"..."'.
Lex(Tok);
- if (Tok.isNot(tok::string_literal) && Tok.isNot(tok::wide_string_literal)) {
+ if (!tok::isStringLiteral(Tok.getKind())) {
Diag(PragmaLoc, diag::err__Pragma_malformed);
// Skip this token, and the ')', if present.
if (Tok.isNot(tok::r_paren))
@@ -219,15 +219,50 @@ void Preprocessor::Handle_Pragma(Token &Tok) {
SourceLocation RParenLoc = Tok.getLocation();
std::string StrVal = getSpelling(StrTok);
- // The _Pragma is lexically sound. Destringize according to C99 6.10.9.1:
- // "The string literal is destringized by deleting the L prefix, if present,
+ // The _Pragma is lexically sound. Destringize according to C11 6.10.9.1:
+ // "The string literal is destringized by deleting any encoding prefix,
// deleting the leading and trailing double-quotes, replacing each escape
// sequence \" by a double-quote, and replacing each escape sequence \\ by a
// single backslash."
- if (StrVal[0] == 'L') // Remove L prefix.
+ if (StrVal[0] == 'L' || StrVal[0] == 'U' ||
+ (StrVal[0] == 'u' && StrVal[1] != '8'))
StrVal.erase(StrVal.begin());
- assert(StrVal[0] == '"' && StrVal[StrVal.size()-1] == '"' &&
- "Invalid string token!");
+ else if (StrVal[0] == 'u')
+ StrVal.erase(StrVal.begin(), StrVal.begin() + 2);
+
+ if (StrVal[0] == 'R') {
+ // FIXME: C++11 does not specify how to handle raw-string-literals here.
+ // We strip off the 'R', the quotes, the d-char-sequences, and the parens.
+ assert(StrVal[1] == '"' && StrVal[StrVal.size() - 1] == '"' &&
+ "Invalid raw string token!");
+
+ // Measure the length of the d-char-sequence.
+ unsigned NumDChars = 0;
+ while (StrVal[2 + NumDChars] != '(') {
+ assert(NumDChars < (StrVal.size() - 5) / 2 &&
+ "Invalid raw string token!");
+ ++NumDChars;
+ }
+ assert(StrVal[StrVal.size() - 2 - NumDChars] == ')');
+
+ // Remove 'R " d-char-sequence' and 'd-char-sequence "'. We'll replace the
+ // parens below.
+ StrVal.erase(0, 2 + NumDChars);
+ StrVal.erase(StrVal.size() - 1 - NumDChars);
+ } else {
+ assert(StrVal[0] == '"' && StrVal[StrVal.size()-1] == '"' &&
+ "Invalid string token!");
+
+ // Remove escaped quotes and escapes.
+ for (unsigned i = 1, e = StrVal.size(); i < e-2; ++i) {
+ if (StrVal[i] == '\\' &&
+ (StrVal[i+1] == '\\' || StrVal[i+1] == '"')) {
+ // \\ -> '\' and \" -> '"'.
+ StrVal.erase(StrVal.begin()+i);
+ --e;
+ }
+ }
+ }
// Remove the front quote, replacing it with a space, so that the pragma
// contents appear to have a space before them.
@@ -236,16 +271,6 @@ void Preprocessor::Handle_Pragma(Token &Tok) {
// Replace the terminating quote with a \n.
StrVal[StrVal.size()-1] = '\n';
- // Remove escaped quotes and escapes.
- for (unsigned i = 0, e = StrVal.size(); i != e-1; ++i) {
- if (StrVal[i] == '\\' &&
- (StrVal[i+1] == '\\' || StrVal[i+1] == '"')) {
- // \\ -> '\' and \" -> '"'.
- StrVal.erase(StrVal.begin()+i);
- --e;
- }
- }
-
// Plop the string (including the newline and trailing null) into a buffer
// where we can lex it.
Token TmpTok;
@@ -470,7 +495,7 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
///
/// The syntax is:
/// \code
-/// \#pragma comment(linker, "foo")
+/// #pragma comment(linker, "foo")
/// \endcode
/// 'linker' is one of five identifiers: compiler, exestr, lib, linker, user.
/// "foo" is a string, which is fully macro expanded, and permits string
@@ -502,38 +527,10 @@ void Preprocessor::HandlePragmaComment(Token &Tok) {
// Read the optional string if present.
Lex(Tok);
std::string ArgumentString;
- if (Tok.is(tok::comma)) {
- Lex(Tok); // eat the comma.
-
- // We need at least one string.
- if (Tok.isNot(tok::string_literal)) {
- Diag(Tok.getLocation(), diag::err_pragma_comment_malformed);
- return;
- }
-
- // String concatenation allows multiple strings, which can even come from
- // macro expansion.
- // "foo " "bar" "Baz"
- SmallVector<Token, 4> StrToks;
- while (Tok.is(tok::string_literal)) {
- if (Tok.hasUDSuffix())
- Diag(Tok, diag::err_invalid_string_udl);
- StrToks.push_back(Tok);
- Lex(Tok);
- }
-
- // Concatenate and parse the strings.
- StringLiteralParser Literal(&StrToks[0], StrToks.size(), *this);
- assert(Literal.isAscii() && "Didn't allow wide strings in");
- if (Literal.hadError)
- return;
- if (Literal.Pascal) {
- Diag(StrToks[0].getLocation(), diag::err_pragma_comment_malformed);
- return;
- }
-
- ArgumentString = Literal.GetString();
- }
+ if (Tok.is(tok::comma) && !LexStringLiteral(Tok, ArgumentString,
+ "pragma comment",
+ /*MacroExpansion=*/true))
+ return;
// FIXME: If the kind is "compiler" warn if the string is present (it is
// ignored).
@@ -560,11 +557,11 @@ void Preprocessor::HandlePragmaComment(Token &Tok) {
/// HandlePragmaMessage - Handle the microsoft and gcc \#pragma message
/// extension. The syntax is:
/// \code
-/// \#pragma message(string)
+/// #pragma message(string)
/// \endcode
/// OR, in GCC mode:
/// \code
-/// \#pragma message string
+/// #pragma message string
/// \endcode
/// string is a string, which is fully macro expanded, and permits string
/// concatenation, embedded escape characters, etc... See MSDN for more details.
@@ -587,34 +584,10 @@ void Preprocessor::HandlePragmaMessage(Token &Tok) {
return;
}
- // We need at least one string.
- if (Tok.isNot(tok::string_literal)) {
- Diag(Tok.getLocation(), diag::err_pragma_message_malformed);
- return;
- }
-
- // String concatenation allows multiple strings, which can even come from
- // macro expansion.
- // "foo " "bar" "Baz"
- SmallVector<Token, 4> StrToks;
- while (Tok.is(tok::string_literal)) {
- if (Tok.hasUDSuffix())
- Diag(Tok, diag::err_invalid_string_udl);
- StrToks.push_back(Tok);
- Lex(Tok);
- }
-
- // Concatenate and parse the strings.
- StringLiteralParser Literal(&StrToks[0], StrToks.size(), *this);
- assert(Literal.isAscii() && "Didn't allow wide strings in");
- if (Literal.hadError)
- return;
- if (Literal.Pascal) {
- Diag(StrToks[0].getLocation(), diag::err_pragma_message_malformed);
+ std::string MessageString;
+ if (!FinishLexStringLiteral(Tok, MessageString, "pragma message",
+ /*MacroExpansion=*/true))
return;
- }
-
- StringRef MessageString(Literal.GetString());
if (ExpectClosingParen) {
if (Tok.isNot(tok::r_paren)) {
@@ -692,7 +665,7 @@ IdentifierInfo *Preprocessor::ParsePragmaPushOrPopMacro(Token &Tok) {
///
/// The syntax is:
/// \code
-/// \#pragma push_macro("macro")
+/// #pragma push_macro("macro")
/// \endcode
void Preprocessor::HandlePragmaPushMacro(Token &PushMacroTok) {
// Parse the pragma directive and get the macro IdentifierInfo*.
@@ -702,17 +675,13 @@ void Preprocessor::HandlePragmaPushMacro(Token &PushMacroTok) {
// Get the MacroInfo associated with IdentInfo.
MacroInfo *MI = getMacroInfo(IdentInfo);
- MacroInfo *MacroCopyToPush = 0;
if (MI) {
- // Make a clone of MI.
- MacroCopyToPush = CloneMacroInfo(*MI);
-
// Allow the original MacroInfo to be redefined later.
MI->setIsAllowRedefinitionsWithoutWarning(true);
}
// Push the cloned MacroInfo so we can retrieve it later.
- PragmaPushMacroInfo[IdentInfo].push_back(MacroCopyToPush);
+ PragmaPushMacroInfo[IdentInfo].push_back(MI);
}
/// \brief Handle \#pragma pop_macro.
@@ -733,10 +702,11 @@ void Preprocessor::HandlePragmaPopMacro(Token &PopMacroTok) {
PragmaPushMacroInfo.find(IdentInfo);
if (iter != PragmaPushMacroInfo.end()) {
// Forget the MacroInfo currently associated with IdentInfo.
- if (MacroInfo *CurrentMI = getMacroInfo(IdentInfo)) {
- if (CurrentMI->isWarnIfUnused())
- WarnUnusedMacroLocs.erase(CurrentMI->getDefinitionLoc());
- UndefineMacro(IdentInfo, CurrentMI, MessageLoc);
+ if (MacroDirective *CurrentMD = getMacroDirective(IdentInfo)) {
+ MacroInfo *MI = CurrentMD->getMacroInfo();
+ if (MI->isWarnIfUnused())
+ WarnUnusedMacroLocs.erase(MI->getDefinitionLoc());
+ appendMacroDirective(IdentInfo, AllocateUndefMacroDirective(MessageLoc));
}
// Get the MacroInfo we want to reinstall.
@@ -744,9 +714,8 @@ void Preprocessor::HandlePragmaPopMacro(Token &PopMacroTok) {
if (MacroToReInstall) {
// Reinstall the previously pushed macro.
- setMacroInfo(IdentInfo, MacroToReInstall);
- } else if (IdentInfo->hasMacroDefinition()) {
- clearMacroInfo(IdentInfo);
+ appendDefMacroDirective(IdentInfo, MacroToReInstall, MessageLoc,
+ /*isImported=*/false);
}
// Pop PragmaPushMacroInfo stack.
@@ -1090,50 +1059,28 @@ public:
}
PP.LexUnexpandedToken(Tok);
+ SourceLocation StringLoc = Tok.getLocation();
- // We need at least one string.
- if (Tok.isNot(tok::string_literal)) {
- PP.Diag(Tok.getLocation(), diag::warn_pragma_diagnostic_invalid_token);
+ std::string WarningName;
+ if (!PP.FinishLexStringLiteral(Tok, WarningName, "pragma diagnostic",
+ /*MacroExpansion=*/false))
return;
- }
-
- // String concatenation allows multiple strings, which can even come from
- // macro expansion.
- // "foo " "bar" "Baz"
- SmallVector<Token, 4> StrToks;
- while (Tok.is(tok::string_literal)) {
- StrToks.push_back(Tok);
- PP.LexUnexpandedToken(Tok);
- }
if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_diagnostic_invalid_token);
return;
}
- // Concatenate and parse the strings.
- StringLiteralParser Literal(&StrToks[0], StrToks.size(), PP);
- assert(Literal.isAscii() && "Didn't allow wide strings in");
- if (Literal.hadError)
- return;
- if (Literal.Pascal) {
- PP.Diag(Tok, diag::warn_pragma_diagnostic_invalid);
- return;
- }
-
- StringRef WarningName(Literal.GetString());
-
if (WarningName.size() < 3 || WarningName[0] != '-' ||
WarningName[1] != 'W') {
- PP.Diag(StrToks[0].getLocation(),
- diag::warn_pragma_diagnostic_invalid_option);
+ PP.Diag(StringLoc, diag::warn_pragma_diagnostic_invalid_option);
return;
}
if (PP.getDiagnostics().setDiagnosticGroupMapping(WarningName.substr(2),
Map, DiagLoc))
- PP.Diag(StrToks[0].getLocation(),
- diag::warn_pragma_diagnostic_unknown_warning) << WarningName;
+ PP.Diag(StringLoc, diag::warn_pragma_diagnostic_unknown_warning)
+ << WarningName;
else if (Callbacks)
Callbacks->PragmaDiagnostic(DiagLoc, Namespace, Map, WarningName);
}
@@ -1277,6 +1224,29 @@ struct PragmaARCCFCodeAuditedHandler : public PragmaHandler {
}
};
+ /// \brief Handle "\#pragma region [...]"
+ ///
+ /// The syntax is
+ /// \code
+ /// #pragma region [optional name]
+ /// #pragma endregion [optional comment]
+ /// \endcode
+ ///
+ /// \note This is
+ /// <a href="http://msdn.microsoft.com/en-us/library/b6xkz944(v=vs.80).aspx">editor-only</a>
+ /// pragma, just skipped by compiler.
+ struct PragmaRegionHandler : public PragmaHandler {
+ PragmaRegionHandler(const char *pragma) : PragmaHandler(pragma) { }
+
+ virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &NameTok) {
+ // #pragma region: endregion matches can be verified
+ // __pragma(region): no sense, but ignored by msvc
+ // _Pragma is not valid for MSVC, but there isn't any point
+ // to handle a _Pragma differently.
+ }
+ };
+
} // end anonymous namespace
@@ -1310,5 +1280,7 @@ void Preprocessor::RegisterBuiltinPragmas() {
if (LangOpts.MicrosoftExt) {
AddPragmaHandler(new PragmaCommentHandler());
AddPragmaHandler(new PragmaIncludeAliasHandler());
+ AddPragmaHandler(new PragmaRegionHandler("region"));
+ AddPragmaHandler(new PragmaRegionHandler("endregion"));
}
}
diff --git a/lib/Lex/PreprocessingRecord.cpp b/lib/Lex/PreprocessingRecord.cpp
index 01f3665e..b10e7f7 100644
--- a/lib/Lex/PreprocessingRecord.cpp
+++ b/lib/Lex/PreprocessingRecord.cpp
@@ -14,8 +14,8 @@
#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Token.h"
-#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Capacity.h"
+#include "llvm/Support/ErrorHandling.h"
using namespace clang;
@@ -38,14 +38,9 @@ InclusionDirective::InclusionDirective(PreprocessingRecord &PPRec,
this->FileName = StringRef(Memory, FileName.size());
}
-PreprocessingRecord::PreprocessingRecord(SourceManager &SM,
- bool RecordConditionalDirectives)
+PreprocessingRecord::PreprocessingRecord(SourceManager &SM)
: SourceMgr(SM),
- RecordCondDirectives(RecordConditionalDirectives), CondDirectiveNextIdx(0),
- ExternalSource(0)
-{
- if (RecordCondDirectives)
- CondDirectiveStack.push_back(CondDirectiveNextIdx++);
+ ExternalSource(0) {
}
/// \brief Returns a pair of [Begin, End) iterators of preprocessed entities
@@ -97,8 +92,10 @@ bool PreprocessingRecord::isEntityInFileID(iterator PPEI, FileID FID) {
int Pos = PPEI.Position;
if (Pos < 0) {
- assert(unsigned(-Pos-1) < LoadedPreprocessedEntities.size() &&
- "Out-of bounds loaded preprocessed entity");
+ if (unsigned(-Pos-1) >= LoadedPreprocessedEntities.size()) {
+ assert(0 && "Out-of bounds loaded preprocessed entity");
+ return false;
+ }
assert(ExternalSource && "No external source to load from");
unsigned LoadedIndex = LoadedPreprocessedEntities.size()+Pos;
if (PreprocessedEntity *PPE = LoadedPreprocessedEntities[LoadedIndex])
@@ -106,8 +103,8 @@ bool PreprocessingRecord::isEntityInFileID(iterator PPEI, FileID FID) {
// See if the external source can see if the entity is in the file without
// deserializing it.
- llvm::Optional<bool>
- IsInFile = ExternalSource->isPreprocessedEntityInFileID(LoadedIndex, FID);
+ Optional<bool> IsInFile =
+ ExternalSource->isPreprocessedEntityInFileID(LoadedIndex, FID);
if (IsInFile.hasValue())
return IsInFile.getValue();
@@ -118,8 +115,10 @@ bool PreprocessingRecord::isEntityInFileID(iterator PPEI, FileID FID) {
FID, SourceMgr);
}
- assert(unsigned(Pos) < PreprocessedEntities.size() &&
- "Out-of bounds local preprocessed entity");
+ if (unsigned(Pos) >= PreprocessedEntities.size()) {
+ assert(0 && "Out-of bounds local preprocessed entity");
+ return false;
+ }
return isPreprocessedEntityIfInFileID(PreprocessedEntities[Pos],
FID, SourceMgr);
}
@@ -249,11 +248,11 @@ PreprocessingRecord::addPreprocessedEntity(PreprocessedEntity *Entity) {
assert(Entity);
SourceLocation BeginLoc = Entity->getSourceRange().getBegin();
- if (!isa<class InclusionDirective>(Entity)) {
+ if (isa<MacroDefinition>(Entity)) {
assert((PreprocessedEntities.empty() ||
!SourceMgr.isBeforeInTranslationUnit(BeginLoc,
PreprocessedEntities.back()->getSourceRange().getBegin())) &&
- "a macro directive was encountered out-of-order");
+ "a macro definition was encountered out-of-order");
PreprocessedEntities.push_back(Entity);
return getPPEntityID(PreprocessedEntities.size()-1, /*isLoaded=*/false);
}
@@ -268,7 +267,15 @@ PreprocessingRecord::addPreprocessedEntity(PreprocessedEntity *Entity) {
// The entity's location is not after the previous one; this can happen with
// include directives that form the filename using macros, e.g:
- // "#include MACRO(STUFF)".
+ // "#include MACRO(STUFF)"
+ // or with macro expansions inside macro arguments where the arguments are
+ // not expanded in the same order as listed, e.g:
+ // \code
+ // #define M1 1
+ // #define M2 2
+ // #define FM(x,y) y x
+ // FM(M1, M2)
+ // \endcode
typedef std::vector<PreprocessedEntity *>::iterator pp_iter;
@@ -313,8 +320,8 @@ unsigned PreprocessingRecord::allocateLoadedEntities(unsigned NumEntities) {
}
void PreprocessingRecord::RegisterMacroDefinition(MacroInfo *Macro,
- PPEntityID PPID) {
- MacroDefinitions[Macro] = PPID;
+ MacroDefinition *Def) {
+ MacroDefinitions[Macro] = Def;
}
/// \brief Retrieve the preprocessed entity at the given ID.
@@ -351,19 +358,17 @@ PreprocessingRecord::getLoadedPreprocessedEntity(unsigned Index) {
}
MacroDefinition *PreprocessingRecord::findMacroDefinition(const MacroInfo *MI) {
- llvm::DenseMap<const MacroInfo *, PPEntityID>::iterator Pos
+ llvm::DenseMap<const MacroInfo *, MacroDefinition *>::iterator Pos
= MacroDefinitions.find(MI);
if (Pos == MacroDefinitions.end())
return 0;
-
- PreprocessedEntity *Entity = getPreprocessedEntity(Pos->second);
- if (Entity->isInvalid())
- return 0;
- return cast<MacroDefinition>(Entity);
+
+ return Pos->second;
}
-void PreprocessingRecord::MacroExpands(const Token &Id, const MacroInfo* MI,
- SourceRange Range) {
+void PreprocessingRecord::addMacroExpansion(const Token &Id,
+ const MacroInfo *MI,
+ SourceRange Range) {
// We don't record nested macro expansions.
if (Id.getLocation().isMacroID())
return;
@@ -376,17 +381,50 @@ void PreprocessingRecord::MacroExpands(const Token &Id, const MacroInfo* MI,
new (*this) MacroExpansion(Def, Range));
}
+void PreprocessingRecord::Ifdef(SourceLocation Loc, const Token &MacroNameTok,
+ const MacroDirective *MD) {
+ // This is not actually a macro expansion but record it as a macro reference.
+ if (MD)
+ addMacroExpansion(MacroNameTok, MD->getMacroInfo(),
+ MacroNameTok.getLocation());
+}
+
+void PreprocessingRecord::Ifndef(SourceLocation Loc, const Token &MacroNameTok,
+ const MacroDirective *MD) {
+ // This is not actually a macro expansion but record it as a macro reference.
+ if (MD)
+ addMacroExpansion(MacroNameTok, MD->getMacroInfo(),
+ MacroNameTok.getLocation());
+}
+
+void PreprocessingRecord::Defined(const Token &MacroNameTok,
+ const MacroDirective *MD) {
+ // This is not actually a macro expansion but record it as a macro reference.
+ if (MD)
+ addMacroExpansion(MacroNameTok, MD->getMacroInfo(),
+ MacroNameTok.getLocation());
+}
+
+void PreprocessingRecord::MacroExpands(const Token &Id,const MacroDirective *MD,
+ SourceRange Range) {
+ addMacroExpansion(Id, MD->getMacroInfo(), Range);
+}
+
void PreprocessingRecord::MacroDefined(const Token &Id,
- const MacroInfo *MI) {
+ const MacroDirective *MD) {
+ const MacroInfo *MI = MD->getMacroInfo();
SourceRange R(MI->getDefinitionLoc(), MI->getDefinitionEndLoc());
MacroDefinition *Def
= new (*this) MacroDefinition(Id.getIdentifierInfo(), R);
- MacroDefinitions[MI] = addPreprocessedEntity(Def);
+ addPreprocessedEntity(Def);
+ MacroDefinitions[MI] = Def;
}
void PreprocessingRecord::MacroUndefined(const Token &Id,
- const MacroInfo *MI) {
- MacroDefinitions.erase(MI);
+ const MacroDirective *MD) {
+ // Note: MI may be null (when #undef'ining an undefined macro).
+ if (MD)
+ MacroDefinitions.erase(MD->getMacroInfo());
}
void PreprocessingRecord::InclusionDirective(
@@ -438,95 +476,6 @@ void PreprocessingRecord::InclusionDirective(
addPreprocessedEntity(ID);
}
-bool PreprocessingRecord::rangeIntersectsConditionalDirective(
- SourceRange Range) const {
- if (Range.isInvalid())
- return false;
-
- CondDirectiveLocsTy::const_iterator
- low = std::lower_bound(CondDirectiveLocs.begin(), CondDirectiveLocs.end(),
- Range.getBegin(), CondDirectiveLoc::Comp(SourceMgr));
- if (low == CondDirectiveLocs.end())
- return false;
-
- if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), low->getLoc()))
- return false;
-
- CondDirectiveLocsTy::const_iterator
- upp = std::upper_bound(low, CondDirectiveLocs.end(),
- Range.getEnd(), CondDirectiveLoc::Comp(SourceMgr));
- unsigned uppIdx;
- if (upp != CondDirectiveLocs.end())
- uppIdx = upp->getIdx();
- else
- uppIdx = 0;
-
- return low->getIdx() != uppIdx;
-}
-
-unsigned PreprocessingRecord::findCondDirectiveIdx(SourceLocation Loc) const {
- if (Loc.isInvalid())
- return 0;
-
- CondDirectiveLocsTy::const_iterator
- low = std::lower_bound(CondDirectiveLocs.begin(), CondDirectiveLocs.end(),
- Loc, CondDirectiveLoc::Comp(SourceMgr));
- if (low == CondDirectiveLocs.end())
- return 0;
- return low->getIdx();
-}
-
-void PreprocessingRecord::addCondDirectiveLoc(CondDirectiveLoc DirLoc) {
- // Ignore directives in system headers.
- if (SourceMgr.isInSystemHeader(DirLoc.getLoc()))
- return;
-
- assert(CondDirectiveLocs.empty() ||
- SourceMgr.isBeforeInTranslationUnit(CondDirectiveLocs.back().getLoc(),
- DirLoc.getLoc()));
- CondDirectiveLocs.push_back(DirLoc);
-}
-
-void PreprocessingRecord::If(SourceLocation Loc, SourceRange ConditionRange) {
- if (RecordCondDirectives) {
- addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
- CondDirectiveStack.push_back(CondDirectiveNextIdx++);
- }
-}
-
-void PreprocessingRecord::Ifdef(SourceLocation Loc, const Token &MacroNameTok) {
- if (RecordCondDirectives) {
- addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
- CondDirectiveStack.push_back(CondDirectiveNextIdx++);
- }
-}
-
-void PreprocessingRecord::Ifndef(SourceLocation Loc,const Token &MacroNameTok) {
- if (RecordCondDirectives) {
- addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
- CondDirectiveStack.push_back(CondDirectiveNextIdx++);
- }
-}
-
-void PreprocessingRecord::Elif(SourceLocation Loc, SourceRange ConditionRange,
- SourceLocation IfLoc) {
- if (RecordCondDirectives)
- addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
-}
-
-void PreprocessingRecord::Else(SourceLocation Loc, SourceLocation IfLoc) {
- if (RecordCondDirectives)
- addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
-}
-
-void PreprocessingRecord::Endif(SourceLocation Loc, SourceLocation IfLoc) {
- if (RecordCondDirectives) {
- addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
- assert(!CondDirectiveStack.empty());
- CondDirectiveStack.pop_back();
- }
-}
-
size_t PreprocessingRecord::getTotalMemory() const {
return BumpAlloc.getTotalMemory()
+ llvm::capacity_in_bytes(MacroDefinitions)
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 3b070ce..53c45dc 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -26,50 +26,48 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/PreprocessorOptions.h"
#include "MacroArgs.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/CodeCompletionHandler.h"
#include "clang/Lex/ExternalPreprocessorSource.h"
#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/Pragma.h"
#include "clang/Lex/PreprocessingRecord.h"
+#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Lex/ScratchBuffer.h"
-#include "clang/Lex/LexDiagnostic.h"
-#include "clang/Lex/CodeCompletionHandler.h"
-#include "clang/Lex/ModuleLoader.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Capacity.h"
+#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/Capacity.h"
using namespace clang;
//===----------------------------------------------------------------------===//
ExternalPreprocessorSource::~ExternalPreprocessorSource() { }
-PPMutationListener::~PPMutationListener() { }
-
-Preprocessor::Preprocessor(llvm::IntrusiveRefCntPtr<PreprocessorOptions> PPOpts,
+Preprocessor::Preprocessor(IntrusiveRefCntPtr<PreprocessorOptions> PPOpts,
DiagnosticsEngine &diags, LangOptions &opts,
const TargetInfo *target, SourceManager &SM,
HeaderSearch &Headers, ModuleLoader &TheModuleLoader,
- IdentifierInfoLookup* IILookup,
- bool OwnsHeaders,
- bool DelayInitialization,
- bool IncrProcessing)
- : PPOpts(PPOpts), Diags(&diags), LangOpts(opts), Target(target),
- FileMgr(Headers.getFileMgr()),
- SourceMgr(SM), HeaderInfo(Headers), TheModuleLoader(TheModuleLoader),
- ExternalSource(0), Identifiers(opts, IILookup),
- IncrementalProcessing(IncrProcessing), CodeComplete(0),
- CodeCompletionFile(0), CodeCompletionOffset(0), CodeCompletionReached(0),
- SkipMainFilePreamble(0, true), CurPPLexer(0),
- CurDirLookup(0), CurLexerKind(CLK_Lexer), Callbacks(0), Listener(0),
- MacroArgCache(0), Record(0), MIChainHead(0), MICache(0)
-{
+ IdentifierInfoLookup *IILookup, bool OwnsHeaders,
+ bool DelayInitialization, bool IncrProcessing)
+ : PPOpts(PPOpts), Diags(&diags), LangOpts(opts), Target(target),
+ FileMgr(Headers.getFileMgr()), SourceMgr(SM), HeaderInfo(Headers),
+ TheModuleLoader(TheModuleLoader), ExternalSource(0),
+ Identifiers(opts, IILookup), IncrementalProcessing(IncrProcessing),
+ CodeComplete(0), CodeCompletionFile(0), CodeCompletionOffset(0),
+ CodeCompletionReached(0), SkipMainFilePreamble(0, true), CurPPLexer(0),
+ CurDirLookup(0), CurLexerKind(CLK_Lexer), Callbacks(0),
+ MacroArgCache(0), Record(0), MIChainHead(0), MICache(0) {
OwnsHeaderSearch = OwnsHeaders;
ScratchBuf = new ScratchBuffer(SourceMgr);
@@ -96,9 +94,11 @@ Preprocessor::Preprocessor(llvm::IntrusiveRefCntPtr<PreprocessorOptions> PPOpts,
InMacroArgPreExpansion = false;
NumCachedTokenLexers = 0;
PragmasEnabled = true;
+ ParsingIfOrElifDirective = false;
+ PreprocessedOutput = false;
CachedLexPos = 0;
-
+
// We haven't read anything from the external source.
ReadMacrosFromExternalSource = false;
@@ -292,7 +292,7 @@ Preprocessor::macro_end(bool IncludeExternalMacros) const {
/// \brief Compares macro tokens with a specified token value sequence.
static bool MacroDefinitionEquals(const MacroInfo *MI,
- llvm::ArrayRef<TokenValue> Tokens) {
+ ArrayRef<TokenValue> Tokens) {
return Tokens.size() == MI->getNumTokens() &&
std::equal(Tokens.begin(), Tokens.end(), MI->tokens_begin());
}
@@ -304,14 +304,15 @@ StringRef Preprocessor::getLastMacroWithSpelling(
StringRef BestSpelling;
for (Preprocessor::macro_iterator I = macro_begin(), E = macro_end();
I != E; ++I) {
- if (!I->second->isObjectLike())
+ if (!I->second->getMacroInfo()->isObjectLike())
continue;
- const MacroInfo *MI = I->second->findDefinitionAtLoc(Loc, SourceMgr);
- if (!MI)
+ const MacroDirective::DefInfo
+ Def = I->second->findDirectiveAtLoc(Loc, SourceMgr);
+ if (!Def)
continue;
- if (!MacroDefinitionEquals(MI, Tokens))
+ if (!MacroDefinitionEquals(Def.getMacroInfo(), Tokens))
continue;
- SourceLocation Location = I->second->getDefinitionLoc();
+ SourceLocation Location = Def.getLocation();
// Choose the macro defined latest.
if (BestLocation.isInvalid() ||
(Location.isValid() &&
@@ -398,7 +399,7 @@ StringRef Preprocessor::getSpelling(const Token &Tok,
SmallVectorImpl<char> &Buffer,
bool *Invalid) const {
// NOTE: this has to be checked *before* testing for an IdentifierInfo.
- if (Tok.isNot(tok::raw_identifier)) {
+ if (Tok.isNot(tok::raw_identifier) && !Tok.hasUCN()) {
// Try the fast path.
if (const IdentifierInfo *II = Tok.getIdentifierInfo())
return II->getName();
@@ -481,6 +482,7 @@ void Preprocessor::EnterMainSourceFile() {
assert(SB && "Cannot create predefined source buffer");
FileID FID = SourceMgr.createFileIDForMemBuffer(SB);
assert(!FID.isInvalid() && "Could not create FileID for predefines?");
+ setPredefinesFileID(FID);
// Start parsing the predefines.
EnterSourceFile(FID, 0, SourceLocation());
@@ -496,6 +498,48 @@ void Preprocessor::EndSourceFile() {
// Lexer Event Handling.
//===----------------------------------------------------------------------===//
+static void appendCodePoint(unsigned Codepoint,
+ llvm::SmallVectorImpl<char> &Str) {
+ char ResultBuf[4];
+ char *ResultPtr = ResultBuf;
+ bool Res = llvm::ConvertCodePointToUTF8(Codepoint, ResultPtr);
+ (void)Res;
+ assert(Res && "Unexpected conversion failure");
+ Str.append(ResultBuf, ResultPtr);
+}
+
+static void expandUCNs(SmallVectorImpl<char> &Buf, StringRef Input) {
+ for (StringRef::iterator I = Input.begin(), E = Input.end(); I != E; ++I) {
+ if (*I != '\\') {
+ Buf.push_back(*I);
+ continue;
+ }
+
+ ++I;
+ assert(*I == 'u' || *I == 'U');
+
+ unsigned NumHexDigits;
+ if (*I == 'u')
+ NumHexDigits = 4;
+ else
+ NumHexDigits = 8;
+
+ assert(I + NumHexDigits <= E);
+
+ uint32_t CodePoint = 0;
+ for (++I; NumHexDigits != 0; ++I, --NumHexDigits) {
+ unsigned Value = llvm::hexDigitValue(*I);
+ assert(Value != -1U);
+
+ CodePoint <<= 4;
+ CodePoint += Value;
+ }
+
+ appendCodePoint(CodePoint, Buf);
+ --I;
+ }
+}
+
/// LookUpIdentifierInfo - Given a tok::raw_identifier token, look up the
/// identifier information for the token and install it into the token,
/// updating the token kind accordingly.
@@ -504,15 +548,22 @@ IdentifierInfo *Preprocessor::LookUpIdentifierInfo(Token &Identifier) const {
// Look up this token, see if it is a macro, or if it is a language keyword.
IdentifierInfo *II;
- if (!Identifier.needsCleaning()) {
+ if (!Identifier.needsCleaning() && !Identifier.hasUCN()) {
// No cleaning needed, just use the characters from the lexed buffer.
II = getIdentifierInfo(StringRef(Identifier.getRawIdentifierData(),
- Identifier.getLength()));
+ Identifier.getLength()));
} else {
// Cleaning needed, alloca a buffer, clean into it, then use the buffer.
SmallString<64> IdentifierBuffer;
StringRef CleanedStr = getSpelling(Identifier, IdentifierBuffer);
- II = getIdentifierInfo(CleanedStr);
+
+ if (Identifier.hasUCN()) {
+ SmallString<64> UCNIdentifierBuffer;
+ expandUCNs(UCNIdentifierBuffer, CleanedStr);
+ II = getIdentifierInfo(UCNIdentifierBuffer);
+ } else {
+ II = getIdentifierInfo(CleanedStr);
+ }
}
// Update the token info (identifier info and appropriate token kind).
@@ -589,19 +640,19 @@ void Preprocessor::HandleIdentifier(Token &Identifier) {
}
// If this is a macro to be expanded, do it.
- if (MacroInfo *MI = getMacroInfo(&II)) {
+ if (MacroDirective *MD = getMacroDirective(&II)) {
+ MacroInfo *MI = MD->getMacroInfo();
if (!DisableMacroExpansion) {
- if (Identifier.isExpandDisabled()) {
- Diag(Identifier, diag::pp_disabled_macro_expansion);
- } else if (MI->isEnabled()) {
- if (!HandleMacroExpandedIdentifier(Identifier, MI))
+ if (!Identifier.isExpandDisabled() && MI->isEnabled()) {
+ if (!HandleMacroExpandedIdentifier(Identifier, MD))
return;
} else {
// C99 6.10.3.4p2 says that a disabled macro may never again be
// expanded, even if it's in a context where it could be expanded in the
// future.
Identifier.setFlag(Token::DisableExpand);
- Diag(Identifier, diag::pp_disabled_macro_expansion);
+ if (MI->isObjectLike() || isNextPPTokenLParen())
+ Diag(Identifier, diag::pp_disabled_macro_expansion);
}
}
}
@@ -630,10 +681,10 @@ void Preprocessor::HandleIdentifier(Token &Identifier) {
if (II.isExtensionToken() && !DisableMacroExpansion)
Diag(Identifier, diag::ext_token_used);
- // If this is the '__experimental_modules_import' contextual keyword, note
+ // If this is the 'import' contextual keyword, note
// that the next token indicates a module name.
//
- // Note that we do not treat '__experimental_modules_import' as a contextual
+ // Note that we do not treat 'import' as a contextual
// keyword when we're in a caching lexer, because caching lexers only get
// used in contexts where import declarations are disallowed.
if (II.isModulesImport() && !InMacroArgs && !DisableMacroExpansion &&
@@ -689,6 +740,47 @@ void Preprocessor::LexAfterModuleImport(Token &Result) {
}
}
+bool Preprocessor::FinishLexStringLiteral(Token &Result, std::string &String,
+ const char *DiagnosticTag,
+ bool AllowMacroExpansion) {
+ // We need at least one string literal.
+ if (Result.isNot(tok::string_literal)) {
+ Diag(Result, diag::err_expected_string_literal)
+ << /*Source='in...'*/0 << DiagnosticTag;
+ return false;
+ }
+
+ // Lex string literal tokens, optionally with macro expansion.
+ SmallVector<Token, 4> StrToks;
+ do {
+ StrToks.push_back(Result);
+
+ if (Result.hasUDSuffix())
+ Diag(Result, diag::err_invalid_string_udl);
+
+ if (AllowMacroExpansion)
+ Lex(Result);
+ else
+ LexUnexpandedToken(Result);
+ } while (Result.is(tok::string_literal));
+
+ // Concatenate and parse the strings.
+ StringLiteralParser Literal(&StrToks[0], StrToks.size(), *this);
+ assert(Literal.isAscii() && "Didn't allow wide strings in");
+
+ if (Literal.hadError)
+ return false;
+
+ if (Literal.Pascal) {
+ Diag(StrToks[0].getLocation(), diag::err_expected_string_literal)
+ << /*Source='in...'*/0 << DiagnosticTag;
+ return false;
+ }
+
+ String = Literal.GetString();
+ return true;
+}
+
void Preprocessor::addCommentHandler(CommentHandler *Handler) {
assert(Handler && "NULL comment handler");
assert(std::find(CommentHandlers.begin(), CommentHandlers.end(), Handler) ==
@@ -723,11 +815,10 @@ CommentHandler::~CommentHandler() { }
CodeCompletionHandler::~CodeCompletionHandler() { }
-void Preprocessor::createPreprocessingRecord(bool RecordConditionalDirectives) {
+void Preprocessor::createPreprocessingRecord() {
if (Record)
return;
- Record = new PreprocessingRecord(getSourceManager(),
- RecordConditionalDirectives);
+ Record = new PreprocessingRecord(getSourceManager());
addPPCallbacks(Record);
}
diff --git a/lib/Lex/PreprocessorLexer.cpp b/lib/Lex/PreprocessorLexer.cpp
index a64c84d..5a59849 100644
--- a/lib/Lex/PreprocessorLexer.cpp
+++ b/lib/Lex/PreprocessorLexer.cpp
@@ -12,9 +12,9 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/PreprocessorLexer.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/LexDiagnostic.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Lex/Preprocessor.h"
using namespace clang;
void PreprocessorLexer::anchor() { }
diff --git a/lib/Lex/TokenConcatenation.cpp b/lib/Lex/TokenConcatenation.cpp
index dd7ebb0..0a66bba 100644
--- a/lib/Lex/TokenConcatenation.cpp
+++ b/lib/Lex/TokenConcatenation.cpp
@@ -12,25 +12,25 @@
//===----------------------------------------------------------------------===//
#include "clang/Lex/TokenConcatenation.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/Support/ErrorHandling.h"
-#include <cctype>
using namespace clang;
/// IsStringPrefix - Return true if Str is a string prefix.
/// 'L', 'u', 'U', or 'u8'. Including raw versions.
-static bool IsStringPrefix(StringRef Str, bool CPlusPlus0x) {
+static bool IsStringPrefix(StringRef Str, bool CPlusPlus11) {
if (Str[0] == 'L' ||
- (CPlusPlus0x && (Str[0] == 'u' || Str[0] == 'U' || Str[0] == 'R'))) {
+ (CPlusPlus11 && (Str[0] == 'u' || Str[0] == 'U' || Str[0] == 'R'))) {
if (Str.size() == 1)
return true; // "L", "u", "U", and "R"
// Check for raw flavors. Need to make sure the first character wasn't
- // already R. Need CPlusPlus0x check for "LR".
- if (Str[1] == 'R' && Str[0] != 'R' && Str.size() == 2 && CPlusPlus0x)
+ // already R. Need CPlusPlus11 check for "LR".
+ if (Str[1] == 'R' && Str[0] != 'R' && Str.size() == 2 && CPlusPlus11)
return true; // "LR", "uR", "UR"
// Check for "u8" and "u8R"
@@ -54,17 +54,17 @@ bool TokenConcatenation::IsIdentifierStringPrefix(const Token &Tok) const {
SourceManager &SM = PP.getSourceManager();
const char *Ptr = SM.getCharacterData(SM.getSpellingLoc(Tok.getLocation()));
return IsStringPrefix(StringRef(Ptr, Tok.getLength()),
- LangOpts.CPlusPlus0x);
+ LangOpts.CPlusPlus11);
}
if (Tok.getLength() < 256) {
char Buffer[256];
const char *TokPtr = Buffer;
unsigned length = PP.getSpelling(Tok, TokPtr);
- return IsStringPrefix(StringRef(TokPtr, length), LangOpts.CPlusPlus0x);
+ return IsStringPrefix(StringRef(TokPtr, length), LangOpts.CPlusPlus11);
}
- return IsStringPrefix(StringRef(PP.getSpelling(Tok)), LangOpts.CPlusPlus0x);
+ return IsStringPrefix(StringRef(PP.getSpelling(Tok)), LangOpts.CPlusPlus11);
}
TokenConcatenation::TokenConcatenation(Preprocessor &pp) : PP(pp) {
@@ -87,7 +87,7 @@ TokenConcatenation::TokenConcatenation(Preprocessor &pp) : PP(pp) {
TokenInfo[tok::arrow ] |= aci_custom_firstchar;
// These tokens have custom code in C++11 mode.
- if (PP.getLangOpts().CPlusPlus0x) {
+ if (PP.getLangOpts().CPlusPlus11) {
TokenInfo[tok::string_literal ] |= aci_custom;
TokenInfo[tok::wide_string_literal ] |= aci_custom;
TokenInfo[tok::utf8_string_literal ] |= aci_custom;
@@ -156,9 +156,10 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok,
// First, check to see if the tokens were directly adjacent in the original
// source. If they were, it must be okay to stick them together: if there
// were an issue, the tokens would have been lexed differently.
- if (PrevTok.getLocation().isFileID() && Tok.getLocation().isFileID() &&
- PrevTok.getLocation().getLocWithOffset(PrevTok.getLength()) ==
- Tok.getLocation())
+ SourceManager &SM = PP.getSourceManager();
+ SourceLocation PrevSpellLoc = SM.getSpellingLoc(PrevTok.getLocation());
+ SourceLocation SpellLoc = SM.getSpellingLoc(Tok.getLocation());
+ if (PrevSpellLoc.getLocWithOffset(PrevTok.getLength()) == SpellLoc)
return false;
tok::TokenKind PrevKind = PrevTok.getKind();
@@ -206,7 +207,7 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok,
case tok::wide_char_constant:
case tok::utf16_char_constant:
case tok::utf32_char_constant:
- if (!PP.getLangOpts().CPlusPlus0x)
+ if (!PP.getLangOpts().CPlusPlus11)
return false;
// In C++11, a string or character literal followed by an identifier is a
@@ -239,13 +240,12 @@ bool TokenConcatenation::AvoidConcat(const Token &PrevPrevTok,
return IsIdentifierStringPrefix(PrevTok);
case tok::numeric_constant:
- return isalnum(FirstChar) || Tok.is(tok::numeric_constant) ||
- FirstChar == '+' || FirstChar == '-' || FirstChar == '.' ||
- (PP.getLangOpts().CPlusPlus0x && FirstChar == '_');
+ return isPreprocessingNumberBody(FirstChar) ||
+ FirstChar == '+' || FirstChar == '-';
case tok::period: // ..., .*, .1234
return (FirstChar == '.' && PrevPrevTok.is(tok::period)) ||
- isdigit(FirstChar) ||
- (PP.getLangOpts().CPlusPlus && FirstChar == '*');
+ isDigit(FirstChar) ||
+ (PP.getLangOpts().CPlusPlus && FirstChar == '*');
case tok::amp: // &&
return FirstChar == '&';
case tok::plus: // ++
diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp
index 59b7478..5b41fe9 100644
--- a/lib/Lex/TokenLexer.cpp
+++ b/lib/Lex/TokenLexer.cpp
@@ -13,10 +13,10 @@
#include "clang/Lex/TokenLexer.h"
#include "MacroArgs.h"
-#include "clang/Lex/MacroInfo.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/LexDiagnostic.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/SmallString.h"
using namespace clang;
@@ -647,6 +647,12 @@ bool TokenLexer::PasteTokens(Token &Tok) {
StartLoc = getExpansionLocForMacroDefLoc(StartLoc);
if (EndLoc.isFileID())
EndLoc = getExpansionLocForMacroDefLoc(EndLoc);
+ FileID MacroFID = SM.getFileID(MacroExpansionStart);
+ while (SM.getFileID(StartLoc) != MacroFID)
+ StartLoc = SM.getImmediateExpansionRange(StartLoc).first;
+ while (SM.getFileID(EndLoc) != MacroFID)
+ EndLoc = SM.getImmediateExpansionRange(EndLoc).second;
+
Tok.setLocation(SM.createExpansionLoc(Tok.getLocation(), StartLoc, EndLoc,
Tok.getLength()));
@@ -743,14 +749,18 @@ static void updateConsecutiveMacroArgTokens(SourceManager &SM,
Token *NextTok = begin_tokens + 1;
for (; NextTok < end_tokens; ++NextTok) {
+ SourceLocation NextLoc = NextTok->getLocation();
+ if (CurLoc.isFileID() != NextLoc.isFileID())
+ break; // Token from different kind of FileID.
+
int RelOffs;
- if (!SM.isInSameSLocAddrSpace(CurLoc, NextTok->getLocation(), &RelOffs))
+ if (!SM.isInSameSLocAddrSpace(CurLoc, NextLoc, &RelOffs))
break; // Token from different local/loaded location.
// Check that token is not before the previous token or more than 50
// "characters" away.
if (RelOffs < 0 || RelOffs > 50)
break;
- CurLoc = NextTok->getLocation();
+ CurLoc = NextLoc;
}
// For the consecutive tokens, find the length of the SLocEntry to contain
diff --git a/lib/Lex/UnicodeCharSets.h b/lib/Lex/UnicodeCharSets.h
new file mode 100644
index 0000000..37ff8af
--- /dev/null
+++ b/lib/Lex/UnicodeCharSets.h
@@ -0,0 +1,496 @@
+//===--- UnicodeCharSets.h - Contains important sets of characters --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef CLANG_LEX_UNICODECHARSETS_H
+#define CLANG_LEX_UNICODECHARSETS_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Mutex.h"
+#include "llvm/Support/MutexGuard.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace {
+ struct UnicodeCharRange {
+ uint32_t Lower;
+ uint32_t Upper;
+ };
+ typedef llvm::ArrayRef<UnicodeCharRange> UnicodeCharSet;
+
+ typedef llvm::SmallPtrSet<const UnicodeCharRange *, 16> ValidatedCharSetsTy;
+}
+
+static inline ValidatedCharSetsTy &getValidatedCharSets() {
+ static ValidatedCharSetsTy Validated;
+ return Validated;
+}
+
+/// Returns true if each of the ranges in \p CharSet is a proper closed range
+/// [min, max], and if the ranges themselves are ordered and non-overlapping.
+static inline bool isValidCharSet(UnicodeCharSet CharSet) {
+#ifndef NDEBUG
+ static llvm::sys::Mutex ValidationMutex;
+
+ // Check the validation cache.
+ {
+ llvm::MutexGuard Guard(ValidationMutex);
+ if (getValidatedCharSets().count(CharSet.data()))
+ return true;
+ }
+
+ // Walk through the ranges.
+ uint32_t Prev = 0;
+ for (UnicodeCharSet::iterator I = CharSet.begin(), E = CharSet.end();
+ I != E; ++I) {
+ if (Prev >= I->Lower) {
+ DEBUG(llvm::dbgs() << "Upper bound 0x");
+ DEBUG(llvm::dbgs().write_hex(Prev));
+ DEBUG(llvm::dbgs() << " should be less than succeeding lower bound 0x");
+ DEBUG(llvm::dbgs().write_hex(I->Lower) << "\n");
+ return false;
+ }
+ if (I->Upper < I->Lower) {
+ DEBUG(llvm::dbgs() << "Upper bound 0x");
+ DEBUG(llvm::dbgs().write_hex(I->Lower));
+ DEBUG(llvm::dbgs() << " should not be less than lower bound 0x");
+ DEBUG(llvm::dbgs().write_hex(I->Upper) << "\n");
+ return false;
+ }
+ Prev = I->Upper;
+ }
+
+ // Update the validation cache.
+ {
+ llvm::MutexGuard Guard(ValidationMutex);
+ getValidatedCharSets().insert(CharSet.data());
+ }
+#endif
+ return true;
+}
+
+/// Returns true if the Unicode code point \p C is within the set of
+/// characters specified by \p CharSet.
+LLVM_READONLY static inline bool isCharInSet(uint32_t C,
+ UnicodeCharSet CharSet) {
+ assert(isValidCharSet(CharSet));
+
+ size_t LowPoint = 0;
+ size_t HighPoint = CharSet.size();
+
+ // Binary search the set of char ranges.
+ while (HighPoint != LowPoint) {
+ size_t MidPoint = (HighPoint + LowPoint) / 2;
+ if (C < CharSet[MidPoint].Lower)
+ HighPoint = MidPoint;
+ else if (C > CharSet[MidPoint].Upper)
+ LowPoint = MidPoint + 1;
+ else
+ return true;
+ }
+
+ return false;
+}
+
+
+// C11 D.1, C++11 [charname.allowed]
+static const UnicodeCharRange C11AllowedIDChars[] = {
+ // 1
+ { 0x00A8, 0x00A8 }, { 0x00AA, 0x00AA }, { 0x00AD, 0x00AD },
+ { 0x00AF, 0x00AF }, { 0x00B2, 0x00B5 }, { 0x00B7, 0x00BA },
+ { 0x00BC, 0x00BE }, { 0x00C0, 0x00D6 }, { 0x00D8, 0x00F6 },
+ { 0x00F8, 0x00FF },
+ // 2
+ { 0x0100, 0x167F }, { 0x1681, 0x180D }, { 0x180F, 0x1FFF },
+ // 3
+ { 0x200B, 0x200D }, { 0x202A, 0x202E }, { 0x203F, 0x2040 },
+ { 0x2054, 0x2054 }, { 0x2060, 0x206F },
+ // 4
+ { 0x2070, 0x218F }, { 0x2460, 0x24FF }, { 0x2776, 0x2793 },
+ { 0x2C00, 0x2DFF }, { 0x2E80, 0x2FFF },
+ // 5
+ { 0x3004, 0x3007 }, { 0x3021, 0x302F }, { 0x3031, 0x303F },
+ // 6
+ { 0x3040, 0xD7FF },
+ // 7
+ { 0xF900, 0xFD3D }, { 0xFD40, 0xFDCF }, { 0xFDF0, 0xFE44 },
+ { 0xFE47, 0xFFFD },
+ // 8
+ { 0x10000, 0x1FFFD }, { 0x20000, 0x2FFFD }, { 0x30000, 0x3FFFD },
+ { 0x40000, 0x4FFFD }, { 0x50000, 0x5FFFD }, { 0x60000, 0x6FFFD },
+ { 0x70000, 0x7FFFD }, { 0x80000, 0x8FFFD }, { 0x90000, 0x9FFFD },
+ { 0xA0000, 0xAFFFD }, { 0xB0000, 0xBFFFD }, { 0xC0000, 0xCFFFD },
+ { 0xD0000, 0xDFFFD }, { 0xE0000, 0xEFFFD }
+};
+
+// C++03 [extendid]
+// Note that this is not the same as C++98, but we don't distinguish C++98
+// and C++03 in Clang.
+static const UnicodeCharRange CXX03AllowedIDChars[] = {
+ // Latin
+ { 0x00C0, 0x00D6 }, { 0x00D8, 0x00F6 }, { 0x00F8, 0x01F5 },
+ { 0x01FA, 0x0217 }, { 0x0250, 0x02A8 },
+
+ // Greek
+ { 0x0384, 0x0384 }, { 0x0388, 0x038A }, { 0x038C, 0x038C },
+ { 0x038E, 0x03A1 }, { 0x03A3, 0x03CE }, { 0x03D0, 0x03D6 },
+ { 0x03DA, 0x03DA }, { 0x03DC, 0x03DC }, { 0x03DE, 0x03DE },
+ { 0x03E0, 0x03E0 }, { 0x03E2, 0x03F3 },
+
+ // Cyrillic
+ { 0x0401, 0x040D }, { 0x040F, 0x044F }, { 0x0451, 0x045C },
+ { 0x045E, 0x0481 }, { 0x0490, 0x04C4 }, { 0x04C7, 0x04C8 },
+ { 0x04CB, 0x04CC }, { 0x04D0, 0x04EB }, { 0x04EE, 0x04F5 },
+ { 0x04F8, 0x04F9 },
+
+ // Armenian
+ { 0x0531, 0x0556 }, { 0x0561, 0x0587 },
+
+ // Hebrew
+ { 0x05D0, 0x05EA }, { 0x05F0, 0x05F4 },
+
+ // Arabic
+ { 0x0621, 0x063A }, { 0x0640, 0x0652 }, { 0x0670, 0x06B7 },
+ { 0x06BA, 0x06BE }, { 0x06C0, 0x06CE }, { 0x06E5, 0x06E7 },
+
+ // Devanagari
+ { 0x0905, 0x0939 }, { 0x0958, 0x0962 },
+
+ // Bengali
+ { 0x0985, 0x098C }, { 0x098F, 0x0990 }, { 0x0993, 0x09A8 },
+ { 0x09AA, 0x09B0 }, { 0x09B2, 0x09B2 }, { 0x09B6, 0x09B9 },
+ { 0x09DC, 0x09DD }, { 0x09DF, 0x09E1 }, { 0x09F0, 0x09F1 },
+
+ // Gurmukhi
+ { 0x0A05, 0x0A0A }, { 0x0A0F, 0x0A10 }, { 0x0A13, 0x0A28 },
+ { 0x0A2A, 0x0A30 }, { 0x0A32, 0x0A33 }, { 0x0A35, 0x0A36 },
+ { 0x0A38, 0x0A39 }, { 0x0A59, 0x0A5C }, { 0x0A5E, 0x0A5E },
+
+ // Gujarti
+ { 0x0A85, 0x0A8B }, { 0x0A8D, 0x0A8D }, { 0x0A8F, 0x0A91 },
+ { 0x0A93, 0x0AA8 }, { 0x0AAA, 0x0AB0 }, { 0x0AB2, 0x0AB3 },
+ { 0x0AB5, 0x0AB9 }, { 0x0AE0, 0x0AE0 },
+
+ // Oriya
+ { 0x0B05, 0x0B0C }, { 0x0B0F, 0x0B10 }, { 0x0B13, 0x0B28 },
+ { 0x0B2A, 0x0B30 }, { 0x0B32, 0x0B33 }, { 0x0B36, 0x0B39 },
+ { 0x0B5C, 0x0B5D }, { 0x0B5F, 0x0B61 },
+
+ // Tamil
+ { 0x0B85, 0x0B8A }, { 0x0B8E, 0x0B90 }, { 0x0B92, 0x0B95 },
+ { 0x0B99, 0x0B9A }, { 0x0B9C, 0x0B9C }, { 0x0B9E, 0x0B9F },
+ { 0x0BA3, 0x0BA4 }, { 0x0BA8, 0x0BAA }, { 0x0BAE, 0x0BB5 },
+ { 0x0BB7, 0x0BB9 },
+
+ // Telugu
+ { 0x0C05, 0x0C0C }, { 0x0C0E, 0x0C10 }, { 0x0C12, 0x0C28 },
+ { 0x0C2A, 0x0C33 }, { 0x0C35, 0x0C39 }, { 0x0C60, 0x0C61 },
+
+ // Kannada
+ { 0x0C85, 0x0C8C }, { 0x0C8E, 0x0C90 }, { 0x0C92, 0x0CA8 },
+ { 0x0CAA, 0x0CB3 }, { 0x0CB5, 0x0CB9 }, { 0x0CE0, 0x0CE1 },
+
+ // Malayam
+ { 0x0D05, 0x0D0C }, { 0x0D0E, 0x0D10 }, { 0x0D12, 0x0D28 },
+ { 0x0D2A, 0x0D39 }, { 0x0D60, 0x0D61 },
+
+ // Thai
+ { 0x0E01, 0x0E30 }, { 0x0E32, 0x0E33 }, { 0x0E40, 0x0E46 },
+ { 0x0E4F, 0x0E5B },
+
+ // Lao
+ { 0x0E81, 0x0E82 }, { 0x0E84, 0x0E84 }, { 0x0E87, 0x0E87 },
+ { 0x0E88, 0x0E88 }, { 0x0E8A, 0x0E8A }, { 0x0E8D, 0x0E8D },
+ { 0x0E94, 0x0E97 }, { 0x0E99, 0x0E9F }, { 0x0EA1, 0x0EA3 },
+ { 0x0EA5, 0x0EA5 }, { 0x0EA7, 0x0EA7 }, { 0x0EAA, 0x0EAA },
+ { 0x0EAB, 0x0EAB }, { 0x0EAD, 0x0EB0 }, { 0x0EB2, 0x0EB2 },
+ { 0x0EB3, 0x0EB3 }, { 0x0EBD, 0x0EBD }, { 0x0EC0, 0x0EC4 },
+ { 0x0EC6, 0x0EC6 },
+
+ // Georgian
+ { 0x10A0, 0x10C5 }, { 0x10D0, 0x10F6 },
+
+ // Hangul
+ { 0x1100, 0x1159 }, { 0x1161, 0x11A2 }, { 0x11A8, 0x11F9 },
+
+ // Latin (2)
+ { 0x1E00, 0x1E9A }, { 0x1EA0, 0x1EF9 },
+
+ // Greek (2)
+ { 0x1F00, 0x1F15 }, { 0x1F18, 0x1F1D }, { 0x1F20, 0x1F45 },
+ { 0x1F48, 0x1F4D }, { 0x1F50, 0x1F57 }, { 0x1F59, 0x1F59 },
+ { 0x1F5B, 0x1F5B }, { 0x1F5D, 0x1F5D }, { 0x1F5F, 0x1F7D },
+ { 0x1F80, 0x1FB4 }, { 0x1FB6, 0x1FBC }, { 0x1FC2, 0x1FC4 },
+ { 0x1FC6, 0x1FCC }, { 0x1FD0, 0x1FD3 }, { 0x1FD6, 0x1FDB },
+ { 0x1FE0, 0x1FEC }, { 0x1FF2, 0x1FF4 }, { 0x1FF6, 0x1FFC },
+
+ // Hiragana
+ { 0x3041, 0x3094 }, { 0x309B, 0x309E },
+
+ // Katakana
+ { 0x30A1, 0x30FE },
+
+ // Bopmofo [sic]
+ { 0x3105, 0x312C },
+
+ // CJK Unified Ideographs
+ { 0x4E00, 0x9FA5 }, { 0xF900, 0xFA2D }, { 0xFB1F, 0xFB36 },
+ { 0xFB38, 0xFB3C }, { 0xFB3E, 0xFB3E }, { 0xFB40, 0xFB41 },
+ { 0xFB42, 0xFB44 }, { 0xFB46, 0xFBB1 }, { 0xFBD3, 0xFD3F },
+ { 0xFD50, 0xFD8F }, { 0xFD92, 0xFDC7 }, { 0xFDF0, 0xFDFB },
+ { 0xFE70, 0xFE72 }, { 0xFE74, 0xFE74 }, { 0xFE76, 0xFEFC },
+ { 0xFF21, 0xFF3A }, { 0xFF41, 0xFF5A }, { 0xFF66, 0xFFBE },
+ { 0xFFC2, 0xFFC7 }, { 0xFFCA, 0xFFCF }, { 0xFFD2, 0xFFD7 },
+ { 0xFFDA, 0xFFDC }
+};
+
+// C99 Annex D
+static const UnicodeCharRange C99AllowedIDChars[] = {
+ // Latin (1)
+ { 0x00AA, 0x00AA },
+
+ // Special characters (1)
+ { 0x00B5, 0x00B5 }, { 0x00B7, 0x00B7 },
+
+ // Latin (2)
+ { 0x00BA, 0x00BA }, { 0x00C0, 0x00D6 }, { 0x00D8, 0x00F6 },
+ { 0x00F8, 0x01F5 }, { 0x01FA, 0x0217 }, { 0x0250, 0x02A8 },
+
+ // Special characters (2)
+ { 0x02B0, 0x02B8 }, { 0x02BB, 0x02BB }, { 0x02BD, 0x02C1 },
+ { 0x02D0, 0x02D1 }, { 0x02E0, 0x02E4 }, { 0x037A, 0x037A },
+
+ // Greek (1)
+ { 0x0386, 0x0386 }, { 0x0388, 0x038A }, { 0x038C, 0x038C },
+ { 0x038E, 0x03A1 }, { 0x03A3, 0x03CE }, { 0x03D0, 0x03D6 },
+ { 0x03DA, 0x03DA }, { 0x03DC, 0x03DC }, { 0x03DE, 0x03DE },
+ { 0x03E0, 0x03E0 }, { 0x03E2, 0x03F3 },
+
+ // Cyrillic
+ { 0x0401, 0x040C }, { 0x040E, 0x044F }, { 0x0451, 0x045C },
+ { 0x045E, 0x0481 }, { 0x0490, 0x04C4 }, { 0x04C7, 0x04C8 },
+ { 0x04CB, 0x04CC }, { 0x04D0, 0x04EB }, { 0x04EE, 0x04F5 },
+ { 0x04F8, 0x04F9 },
+
+ // Armenian (1)
+ { 0x0531, 0x0556 },
+
+ // Special characters (3)
+ { 0x0559, 0x0559 },
+
+ // Armenian (2)
+ { 0x0561, 0x0587 },
+
+ // Hebrew
+ { 0x05B0, 0x05B9 }, { 0x05BB, 0x05BD }, { 0x05BF, 0x05BF },
+ { 0x05C1, 0x05C2 }, { 0x05D0, 0x05EA }, { 0x05F0, 0x05F2 },
+
+ // Arabic (1)
+ { 0x0621, 0x063A }, { 0x0640, 0x0652 },
+
+ // Digits (1)
+ { 0x0660, 0x0669 },
+
+ // Arabic (2)
+ { 0x0670, 0x06B7 }, { 0x06BA, 0x06BE }, { 0x06C0, 0x06CE },
+ { 0x06D0, 0x06DC }, { 0x06E5, 0x06E8 }, { 0x06EA, 0x06ED },
+
+ // Digits (2)
+ { 0x06F0, 0x06F9 },
+
+ // Devanagari and Special characeter 0x093D.
+ { 0x0901, 0x0903 }, { 0x0905, 0x0939 }, { 0x093D, 0x094D },
+ { 0x0950, 0x0952 }, { 0x0958, 0x0963 },
+
+ // Digits (3)
+ { 0x0966, 0x096F },
+
+ // Bengali (1)
+ { 0x0981, 0x0983 }, { 0x0985, 0x098C }, { 0x098F, 0x0990 },
+ { 0x0993, 0x09A8 }, { 0x09AA, 0x09B0 }, { 0x09B2, 0x09B2 },
+ { 0x09B6, 0x09B9 }, { 0x09BE, 0x09C4 }, { 0x09C7, 0x09C8 },
+ { 0x09CB, 0x09CD }, { 0x09DC, 0x09DD }, { 0x09DF, 0x09E3 },
+
+ // Digits (4)
+ { 0x09E6, 0x09EF },
+
+ // Bengali (2)
+ { 0x09F0, 0x09F1 },
+
+ // Gurmukhi (1)
+ { 0x0A02, 0x0A02 }, { 0x0A05, 0x0A0A }, { 0x0A0F, 0x0A10 },
+ { 0x0A13, 0x0A28 }, { 0x0A2A, 0x0A30 }, { 0x0A32, 0x0A33 },
+ { 0x0A35, 0x0A36 }, { 0x0A38, 0x0A39 }, { 0x0A3E, 0x0A42 },
+ { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D }, { 0x0A59, 0x0A5C },
+ { 0x0A5E, 0x0A5E },
+
+ // Digits (5)
+ { 0x0A66, 0x0A6F },
+
+ // Gurmukhi (2)
+ { 0x0A74, 0x0A74 },
+
+ // Gujarti
+ { 0x0A81, 0x0A83 }, { 0x0A85, 0x0A8B }, { 0x0A8D, 0x0A8D },
+ { 0x0A8F, 0x0A91 }, { 0x0A93, 0x0AA8 }, { 0x0AAA, 0x0AB0 },
+ { 0x0AB2, 0x0AB3 }, { 0x0AB5, 0x0AB9 }, { 0x0ABD, 0x0AC5 },
+ { 0x0AC7, 0x0AC9 }, { 0x0ACB, 0x0ACD }, { 0x0AD0, 0x0AD0 },
+ { 0x0AE0, 0x0AE0 },
+
+ // Digits (6)
+ { 0x0AE6, 0x0AEF },
+
+ // Oriya and Special character 0x0B3D
+ { 0x0B01, 0x0B03 }, { 0x0B05, 0x0B0C }, { 0x0B0F, 0x0B10 },
+ { 0x0B13, 0x0B28 }, { 0x0B2A, 0x0B30 }, { 0x0B32, 0x0B33 },
+ { 0x0B36, 0x0B39 }, { 0x0B3D, 0x0B43 }, { 0x0B47, 0x0B48 },
+ { 0x0B4B, 0x0B4D }, { 0x0B5C, 0x0B5D }, { 0x0B5F, 0x0B61 },
+
+ // Digits (7)
+ { 0x0B66, 0x0B6F },
+
+ // Tamil
+ { 0x0B82, 0x0B83 }, { 0x0B85, 0x0B8A }, { 0x0B8E, 0x0B90 },
+ { 0x0B92, 0x0B95 }, { 0x0B99, 0x0B9A }, { 0x0B9C, 0x0B9C },
+ { 0x0B9E, 0x0B9F }, { 0x0BA3, 0x0BA4 }, { 0x0BA8, 0x0BAA },
+ { 0x0BAE, 0x0BB5 }, { 0x0BB7, 0x0BB9 }, { 0x0BBE, 0x0BC2 },
+ { 0x0BC6, 0x0BC8 }, { 0x0BCA, 0x0BCD },
+
+ // Digits (8)
+ { 0x0BE7, 0x0BEF },
+
+ // Telugu
+ { 0x0C01, 0x0C03 }, { 0x0C05, 0x0C0C }, { 0x0C0E, 0x0C10 },
+ { 0x0C12, 0x0C28 }, { 0x0C2A, 0x0C33 }, { 0x0C35, 0x0C39 },
+ { 0x0C3E, 0x0C44 }, { 0x0C46, 0x0C48 }, { 0x0C4A, 0x0C4D },
+ { 0x0C60, 0x0C61 },
+
+ // Digits (9)
+ { 0x0C66, 0x0C6F },
+
+ // Kannada
+ { 0x0C82, 0x0C83 }, { 0x0C85, 0x0C8C }, { 0x0C8E, 0x0C90 },
+ { 0x0C92, 0x0CA8 }, { 0x0CAA, 0x0CB3 }, { 0x0CB5, 0x0CB9 },
+ { 0x0CBE, 0x0CC4 }, { 0x0CC6, 0x0CC8 }, { 0x0CCA, 0x0CCD },
+ { 0x0CDE, 0x0CDE }, { 0x0CE0, 0x0CE1 },
+
+ // Digits (10)
+ { 0x0CE6, 0x0CEF },
+
+ // Malayam
+ { 0x0D02, 0x0D03 }, { 0x0D05, 0x0D0C }, { 0x0D0E, 0x0D10 },
+ { 0x0D12, 0x0D28 }, { 0x0D2A, 0x0D39 }, { 0x0D3E, 0x0D43 },
+ { 0x0D46, 0x0D48 }, { 0x0D4A, 0x0D4D }, { 0x0D60, 0x0D60 },
+
+ // Digits (11)
+ { 0x0D66, 0x0D6F },
+
+ // Thai...including Digits { 0x0E50, 0x0E59 }
+ { 0x0E01, 0x0E3A }, { 0x0E40, 0x0E5B },
+
+ // Lao (1)
+ { 0x0E81, 0x0E82 }, { 0x0E84, 0x0E84 }, { 0x0E87, 0x0E88 },
+ { 0x0E8A, 0x0E8A }, { 0x0E8D, 0x0E8D }, { 0x0E94, 0x0E97 },
+ { 0x0E99, 0x0E9F }, { 0x0EA1, 0x0EA3 }, { 0x0EA5, 0x0EA5 },
+ { 0x0EA7, 0x0EA7 }, { 0x0EAA, 0x0EAB }, { 0x0EAD, 0x0EAE },
+ { 0x0EB0, 0x0EB9 }, { 0x0EBB, 0x0EBD }, { 0x0EC0, 0x0EC4 },
+ { 0x0EC6, 0x0EC6 }, { 0x0EC8, 0x0ECD },
+
+ // Digits (12)
+ { 0x0ED0, 0x0ED9 },
+
+ // Lao (2)
+ { 0x0EDC, 0x0EDD },
+
+ // Tibetan (1)
+ { 0x0F00, 0x0F00 }, { 0x0F18, 0x0F19 },
+
+ // Digits (13)
+ { 0x0F20, 0x0F33 },
+
+ // Tibetan (2)
+ { 0x0F35, 0x0F35 }, { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 },
+ { 0x0F3E, 0x0F47 }, { 0x0F49, 0x0F69 }, { 0x0F71, 0x0F84 },
+ { 0x0F86, 0x0F8B }, { 0x0F90, 0x0F95 }, { 0x0F97, 0x0F97 },
+ { 0x0F99, 0x0FAD }, { 0x0FB1, 0x0FB7 }, { 0x0FB9, 0x0FB9 },
+
+ // Georgian
+ { 0x10A0, 0x10C5 }, { 0x10D0, 0x10F6 },
+
+ // Latin (3)
+ { 0x1E00, 0x1E9B }, { 0x1EA0, 0x1EF9 },
+
+ // Greek (2)
+ { 0x1F00, 0x1F15 }, { 0x1F18, 0x1F1D }, { 0x1F20, 0x1F45 },
+ { 0x1F48, 0x1F4D }, { 0x1F50, 0x1F57 }, { 0x1F59, 0x1F59 },
+ { 0x1F5B, 0x1F5B }, { 0x1F5D, 0x1F5D }, { 0x1F5F, 0x1F7D },
+ { 0x1F80, 0x1FB4 }, { 0x1FB6, 0x1FBC },
+
+ // Special characters (4)
+ { 0x1FBE, 0x1FBE },
+
+ // Greek (3)
+ { 0x1FC2, 0x1FC4 }, { 0x1FC6, 0x1FCC }, { 0x1FD0, 0x1FD3 },
+ { 0x1FD6, 0x1FDB }, { 0x1FE0, 0x1FEC }, { 0x1FF2, 0x1FF4 },
+ { 0x1FF6, 0x1FFC },
+
+ // Special characters (5)
+ { 0x203F, 0x2040 },
+
+ // Latin (4)
+ { 0x207F, 0x207F },
+
+ // Special characters (6)
+ { 0x2102, 0x2102 }, { 0x2107, 0x2107 }, { 0x210A, 0x2113 },
+ { 0x2115, 0x2115 }, { 0x2118, 0x211D }, { 0x2124, 0x2124 },
+ { 0x2126, 0x2126 }, { 0x2128, 0x2128 }, { 0x212A, 0x2131 },
+ { 0x2133, 0x2138 }, { 0x2160, 0x2182 }, { 0x3005, 0x3007 },
+ { 0x3021, 0x3029 },
+
+ // Hiragana
+ { 0x3041, 0x3093 }, { 0x309B, 0x309C },
+
+ // Katakana
+ { 0x30A1, 0x30F6 }, { 0x30FB, 0x30FC },
+
+ // Bopmofo [sic]
+ { 0x3105, 0x312C },
+
+ // CJK Unified Ideographs
+ { 0x4E00, 0x9FA5 },
+
+ // Hangul,
+ { 0xAC00, 0xD7A3 }
+};
+
+// C11 D.2, C++11 [charname.disallowed]
+static const UnicodeCharRange C11DisallowedInitialIDChars[] = {
+ { 0x0300, 0x036F }, { 0x1DC0, 0x1DFF }, { 0x20D0, 0x20FF },
+ { 0xFE20, 0xFE2F }
+};
+
+// C99 6.4.2.1p3: The initial character [of an identifier] shall not be a
+// universal character name designating a digit.
+// C99 Annex D defines these characters as "Digits".
+static const UnicodeCharRange C99DisallowedInitialIDChars[] = {
+ { 0x0660, 0x0669 }, { 0x06F0, 0x06F9 }, { 0x0966, 0x096F },
+ { 0x09E6, 0x09EF }, { 0x0A66, 0x0A6F }, { 0x0AE6, 0x0AEF },
+ { 0x0B66, 0x0B6F }, { 0x0BE7, 0x0BEF }, { 0x0C66, 0x0C6F },
+ { 0x0CE6, 0x0CEF }, { 0x0D66, 0x0D6F }, { 0x0E50, 0x0E59 },
+ { 0x0ED0, 0x0ED9 }, { 0x0F20, 0x0F33 }
+};
+
+// Unicode v6.2, chapter 6.2, table 6-2.
+static const UnicodeCharRange UnicodeWhitespaceChars[] = {
+ { 0x0085, 0x0085 }, { 0x00A0, 0x00A0 }, { 0x1680, 0x1680 },
+ { 0x180E, 0x180E }, { 0x2000, 0x200A }, { 0x2028, 0x2029 },
+ { 0x202F, 0x202F }, { 0x205F, 0x205F }, { 0x3000, 0x3000 }
+};
+
+#endif
diff --git a/lib/Makefile b/lib/Makefile
index 1f14aa0..2e32dfe 100755
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -8,9 +8,19 @@
##===----------------------------------------------------------------------===##
CLANG_LEVEL := ..
-PARALLEL_DIRS = Headers Basic Lex Parse AST ASTMatchers Sema CodeGen Analysis \
- StaticAnalyzer Edit Rewrite ARCMigrate Serialization Frontend \
- FrontendTool Tooling Driver
+# ARCMigrate and Rewrite are always needed because of libclang.
+PARALLEL_DIRS = Headers Basic Lex Parse AST Sema CodeGen Analysis Frontend \
+ FrontendTool Tooling Driver Format Edit ARCMigrate Rewrite \
+ Serialization
-include $(CLANG_LEVEL)/Makefile
+include $(CLANG_LEVEL)/../../Makefile.config
+
+ifeq ($(ENABLE_CLANG_REWRITER),1)
+PARALLEL_DIRS += ASTMatchers
+endif
+ifeq ($(ENABLE_CLANG_STATIC_ANALYZER),1)
+PARALLEL_DIRS += StaticAnalyzer
+endif
+
+include $(CLANG_LEVEL)/Makefile
diff --git a/lib/Parse/CMakeLists.txt b/lib/Parse/CMakeLists.txt
index 55e2aeb..939998e 100644
--- a/lib/Parse/CMakeLists.txt
+++ b/lib/Parse/CMakeLists.txt
@@ -7,6 +7,7 @@ add_clang_library(clangParse
ParseExprCXX.cpp
ParseInit.cpp
ParseObjc.cpp
+ ParseOpenMP.cpp
ParsePragma.cpp
ParseStmt.cpp
ParseTemplate.cpp
diff --git a/lib/Parse/ParseAST.cpp b/lib/Parse/ParseAST.cpp
index 7d68e1f..7cd8a21 100644
--- a/lib/Parse/ParseAST.cpp
+++ b/lib/Parse/ParseAST.cpp
@@ -12,23 +12,68 @@
//===----------------------------------------------------------------------===//
#include "clang/Parse/ParseAST.h"
-#include "clang/Parse/ParseDiagnostic.h"
-#include "clang/Sema/Sema.h"
-#include "clang/Sema/CodeCompleteConsumer.h"
-#include "clang/Sema/SemaConsumer.h"
-#include "clang/Sema/ExternalSemaSource.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/Stmt.h"
+#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
+#include "clang/Sema/ExternalSemaSource.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaConsumer.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include <cstdio>
using namespace clang;
+namespace {
+
+/// If a crash happens while the parser is active, an entry is printed for it.
+class PrettyStackTraceParserEntry : public llvm::PrettyStackTraceEntry {
+ const Parser &P;
+public:
+ PrettyStackTraceParserEntry(const Parser &p) : P(p) {}
+ virtual void print(raw_ostream &OS) const;
+};
+
+/// If a crash happens while the parser is active, print out a line indicating
+/// what the current token is.
+void PrettyStackTraceParserEntry::print(raw_ostream &OS) const {
+ const Token &Tok = P.getCurToken();
+ if (Tok.is(tok::eof)) {
+ OS << "<eof> parser at end of file\n";
+ return;
+ }
+
+ if (Tok.getLocation().isInvalid()) {
+ OS << "<unknown> parser at unknown location\n";
+ return;
+ }
+
+ const Preprocessor &PP = P.getPreprocessor();
+ Tok.getLocation().print(OS, PP.getSourceManager());
+ if (Tok.isAnnotation()) {
+ OS << ": at annotation token\n";
+ } else {
+ // Do the equivalent of PP.getSpelling(Tok) except for the parts that would
+ // allocate memory.
+ bool Invalid = false;
+ const SourceManager &SM = P.getPreprocessor().getSourceManager();
+ unsigned Length = Tok.getLength();
+ const char *Spelling = SM.getCharacterData(Tok.getLocation(), &Invalid);
+ if (Invalid) {
+ OS << ": unknown current parser token\n";
+ return;
+ }
+ OS << ": current parser token '" << StringRef(Spelling, Length) << "'\n";
+ }
+}
+
+} // namespace
+
//===----------------------------------------------------------------------===//
// Public interface to the file
//===----------------------------------------------------------------------===//
@@ -43,9 +88,7 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
CodeCompleteConsumer *CompletionConsumer,
bool SkipFunctionBodies) {
- OwningPtr<Sema> S(new Sema(PP, Ctx, *Consumer,
- TUKind,
- CompletionConsumer));
+ OwningPtr<Sema> S(new Sema(PP, Ctx, *Consumer, TUKind, CompletionConsumer));
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(S.get());
@@ -97,7 +140,7 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {
// is due to a top-level semicolon, an action override, or a parse error
// skipping something.
if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get()))
- return;
+ return;
} while (!P.ParseTopLevelDecl(ADecl));
}
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index 9c5c0597..bc634b5 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -11,18 +11,25 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
+#include "RAIIObjectsForParser.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Scope.h"
-#include "clang/AST/DeclTemplate.h"
-#include "RAIIObjectsForParser.h"
using namespace clang;
+/// Get the FunctionDecl for a function or function template decl.
+static FunctionDecl *getFunctionDecl(Decl *D) {
+ if (FunctionDecl *fn = dyn_cast<FunctionDecl>(D))
+ return fn;
+ return cast<FunctionTemplateDecl>(D)->getTemplatedDecl();
+}
+
/// ParseCXXInlineMethodDef - We parsed and verified that the specified
/// Declarator is a well formed C++ inline method definition. Now lex its body
/// and store its tokens for parsing after the C++ class is complete.
-Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
+NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
AttributeList *AccessAttrs,
ParsingDeclarator &D,
const ParsedTemplateInfo &TemplateInfo,
@@ -38,7 +45,7 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->data() : 0,
TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->size() : 0);
- Decl *FnD;
+ NamedDecl *FnD;
D.setFunctionDefinitionKind(DefinitionKind);
if (D.getDeclSpec().isFriendSpecified())
FnD = Actions.ActOnFriendFunctionDecl(getCurScope(), D,
@@ -75,7 +82,7 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
bool Delete = false;
SourceLocation KWLoc;
if (Tok.is(tok::kw_delete)) {
- Diag(Tok, getLangOpts().CPlusPlus0x ?
+ Diag(Tok, getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_deleted_function :
diag::ext_deleted_function);
@@ -83,7 +90,7 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
Actions.SetDeclDeleted(FnD, KWLoc);
Delete = true;
} else if (Tok.is(tok::kw_default)) {
- Diag(Tok, getLangOpts().CPlusPlus0x ?
+ Diag(Tok, getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_defaulted_function :
diag::ext_defaulted_function);
@@ -117,11 +124,7 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
if (FnD) {
LateParsedTemplatedFunction *LPT = new LateParsedTemplatedFunction(FnD);
- FunctionDecl *FD = 0;
- if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(FnD))
- FD = FunTmpl->getTemplatedDecl();
- else
- FD = cast<FunctionDecl>(FnD);
+ FunctionDecl *FD = getFunctionDecl(FnD);
Actions.CheckForFunctionRedefinition(FD);
LateParsedTemplateMap[FD] = LPT;
@@ -176,6 +179,19 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
getCurrentClass().LateParsedDeclarations.pop_back();
}
+ // If this is a friend function, mark that it's late-parsed so that
+ // it's still known to be a definition even before we attach the
+ // parsed body. Sema needs to treat friend function definitions
+ // differently during template instantiation, and it's possible for
+ // the containing class to be instantiated before all its member
+ // function definitions are parsed.
+ //
+ // If you remove this, you can remove the code that clears the flag
+ // after parsing the member.
+ if (D.getDeclSpec().isFriendSpecified()) {
+ getFunctionDecl(FnD)->setLateTemplateParsed(true);
+ }
+
return FnD;
}
@@ -293,8 +309,8 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
// Introduce the parameters into scope and parse their default
// arguments.
- ParseScope PrototypeScope(this,
- Scope::FunctionPrototypeScope|Scope::DeclScope);
+ ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope |
+ Scope::FunctionDeclarationScope | Scope::DeclScope);
for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) {
// Introduce the parameter into scope.
Actions.ActOnDelayedCXXMethodParameter(getCurScope(),
@@ -322,7 +338,7 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
LM.DefaultArgs[I].Param);
ExprResult DefArgResult;
- if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) {
+ if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
DefArgResult = ParseBraceInitializer();
} else
@@ -391,7 +407,7 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) {
PP.EnterTokenStream(LM.Toks.data(), LM.Toks.size(), true, false);
// Consume the previously pushed token.
- ConsumeAnyToken();
+ ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try))
&& "Inline method not starting with '{', ':' or 'try'");
@@ -427,6 +443,9 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) {
ParseFunctionStatementBody(LM.D, FnScope);
+ // Clear the late-template-parsed bit if we set it before.
+ if (LM.D) getFunctionDecl(LM.D)->setLateTemplateParsed(false);
+
if (Tok.getLocation() != origLoc) {
// Due to parsing error, we either went over the cached tokens or
// there are still cached tokens left. If it's the latter case skip the
@@ -491,7 +510,7 @@ void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) {
PP.EnterTokenStream(MI.Toks.data(), MI.Toks.size(), true, false);
// Consume the previously pushed token.
- ConsumeAnyToken();
+ ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
SourceLocation EqualLoc;
@@ -651,7 +670,7 @@ bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) {
ConsumeBrace();
// In C++03, this has to be the start of the function body, which
// means the initializer is malformed; we'll diagnose it later.
- if (!getLangOpts().CPlusPlus0x)
+ if (!getLangOpts().CPlusPlus11)
return false;
}
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index f73907a..990a909 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -12,13 +12,15 @@
//===----------------------------------------------------------------------===//
#include "clang/Parse/Parser.h"
-#include "clang/Parse/ParseDiagnostic.h"
+#include "RAIIObjectsForParser.h"
+#include "clang/Basic/AddressSpaces.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/OpenCL.h"
+#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/Lookup.h"
-#include "clang/Sema/Scope.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/PrettyDeclStackTrace.h"
-#include "RAIIObjectsForParser.h"
+#include "clang/Sema/Scope.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
@@ -36,13 +38,16 @@ using namespace clang;
TypeResult Parser::ParseTypeName(SourceRange *Range,
Declarator::TheContext Context,
AccessSpecifier AS,
- Decl **OwnedType) {
+ Decl **OwnedType,
+ ParsedAttributes *Attrs) {
DeclSpecContext DSC = getDeclSpecContextFromDeclaratorContext(Context);
if (DSC == DSC_normal)
DSC = DSC_type_specifier;
// Parse the common declaration-specifiers piece.
DeclSpec DS(AttrFactory);
+ if (Attrs)
+ DS.addAttributes(Attrs->getList());
ParseSpecifierQualifierList(DS, AS, DSC);
if (OwnedType)
*OwnedType = DS.isTypeSpecOwned() ? DS.getRepAsDecl() : 0;
@@ -209,6 +214,10 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
SourceLocation ParmLoc;
bool BuiltinType = false;
+ TypeResult T;
+ SourceRange TypeRange;
+ bool TypeParsed = false;
+
switch (Tok.getKind()) {
case tok::kw_char:
case tok::kw_wchar_t:
@@ -227,12 +236,17 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
case tok::kw_void:
case tok::kw_typeof:
// __attribute__(( vec_type_hint(char) ))
- // FIXME: Don't just discard the builtin type token.
- ConsumeToken();
BuiltinType = true;
+ T = ParseTypeName(&TypeRange);
+ TypeParsed = true;
break;
case tok::identifier:
+ if (AttrName->isStr("vec_type_hint")) {
+ T = ParseTypeName(&TypeRange);
+ TypeParsed = true;
+ break;
+ }
ParmName = Tok.getIdentifierInfo();
ParmLoc = ConsumeToken();
break;
@@ -242,8 +256,10 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
}
ExprVector ArgExprs;
+ bool isInvalid = false;
+ bool isParmType = false;
- if (!BuiltinType &&
+ if (!BuiltinType && !AttrName->isStr("vec_type_hint") &&
(ParmLoc.isValid() ? Tok.is(tok::comma) : Tok.isNot(tok::r_paren))) {
// Eat the comma.
if (ParmLoc.isValid())
@@ -278,17 +294,32 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
Diag(Tok, diag::err_iboutletcollection_with_protocol);
SkipUntil(tok::r_paren, false, true); // skip until ')'
}
+ } else if (AttrName->isStr("vec_type_hint")) {
+ if (T.get() && !T.isInvalid())
+ isParmType = true;
+ else {
+ if (Tok.is(tok::identifier))
+ ConsumeToken();
+ if (TypeParsed)
+ isInvalid = true;
+ }
}
SourceLocation RParen = Tok.getLocation();
- if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) {
+ if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen) &&
+ !isInvalid) {
SourceLocation AttrLoc = ScopeLoc.isValid() ? ScopeLoc : AttrNameLoc;
- AttributeList *attr =
- Attrs.addNew(AttrName, SourceRange(AttrLoc, RParen),
- ScopeName, ScopeLoc, ParmName, ParmLoc,
- ArgExprs.data(), ArgExprs.size(), Syntax);
- if (BuiltinType && attr->getKind() == AttributeList::AT_IBOutletCollection)
- Diag(Tok, diag::err_iboutletcollection_builtintype);
+ if (isParmType) {
+ Attrs.addNewTypeAttr(AttrName, SourceRange(AttrLoc, RParen), ScopeName,
+ ScopeLoc, ParmName, ParmLoc, T.get(), Syntax);
+ } else {
+ AttributeList *attr = Attrs.addNew(
+ AttrName, SourceRange(AttrLoc, RParen), ScopeName, ScopeLoc, ParmName,
+ ParmLoc, ArgExprs.data(), ArgExprs.size(), Syntax);
+ if (BuiltinType &&
+ attr->getKind() == AttributeList::AT_IBOutletCollection)
+ Diag(Tok, diag::err_iboutletcollection_builtintype);
+ }
}
}
@@ -457,12 +488,11 @@ void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) {
while (Tok.is(tok::kw___fastcall) || Tok.is(tok::kw___stdcall) ||
Tok.is(tok::kw___thiscall) || Tok.is(tok::kw___cdecl) ||
Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64) ||
- Tok.is(tok::kw___ptr32) ||
- Tok.is(tok::kw___unaligned)) {
+ Tok.is(tok::kw___ptr32) || Tok.is(tok::kw___unaligned)) {
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = ConsumeToken();
attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
- SourceLocation(), 0, 0, AttributeList::AS_MSTypespec);
+ SourceLocation(), 0, 0, AttributeList::AS_Keyword);
}
}
@@ -472,21 +502,23 @@ void Parser::ParseBorlandTypeAttributes(ParsedAttributes &attrs) {
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = ConsumeToken();
attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
- SourceLocation(), 0, 0, AttributeList::AS_MSTypespec);
+ SourceLocation(), 0, 0, AttributeList::AS_Keyword);
}
}
void Parser::ParseOpenCLAttributes(ParsedAttributes &attrs) {
// Treat these like attributes
while (Tok.is(tok::kw___kernel)) {
+ IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = ConsumeToken();
- attrs.addNew(PP.getIdentifierInfo("opencl_kernel_function"),
- AttrNameLoc, 0, AttrNameLoc, 0,
- SourceLocation(), 0, 0, AttributeList::AS_GNU);
+ attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0,
+ SourceLocation(), 0, 0, AttributeList::AS_Keyword);
}
}
void Parser::ParseOpenCLQualifiers(DeclSpec &DS) {
+ // FIXME: The mapping from attribute spelling to semantics should be
+ // performed in Sema, not here.
SourceLocation Loc = Tok.getLocation();
switch(Tok.getKind()) {
// OpenCL qualifiers:
@@ -568,7 +600,7 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) {
// Parse the major version.
unsigned AfterMajor = 0;
unsigned Major = 0;
- while (AfterMajor < ActualLength && isdigit(ThisTokBegin[AfterMajor])) {
+ while (AfterMajor < ActualLength && isDigit(ThisTokBegin[AfterMajor])) {
Major = Major * 10 + ThisTokBegin[AfterMajor] - '0';
++AfterMajor;
}
@@ -600,7 +632,7 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) {
// Parse the minor version.
unsigned AfterMinor = AfterMajor + 1;
unsigned Minor = 0;
- while (AfterMinor < ActualLength && isdigit(ThisTokBegin[AfterMinor])) {
+ while (AfterMinor < ActualLength && isDigit(ThisTokBegin[AfterMinor])) {
Minor = Minor * 10 + ThisTokBegin[AfterMinor] - '0';
++AfterMinor;
}
@@ -627,7 +659,7 @@ VersionTuple Parser::ParseVersionTuple(SourceRange &Range) {
// Parse the subminor version.
unsigned AfterSubminor = AfterMinor + 1;
unsigned Subminor = 0;
- while (AfterSubminor < ActualLength && isdigit(ThisTokBegin[AfterSubminor])) {
+ while (AfterSubminor < ActualLength && isDigit(ThisTokBegin[AfterSubminor])) {
Subminor = Subminor * 10 + ThisTokBegin[AfterSubminor] - '0';
++AfterSubminor;
}
@@ -735,7 +767,8 @@ void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability,
ConsumeToken();
if (Keyword == Ident_message) {
if (!isTokenStringLiteral()) {
- Diag(Tok, diag::err_expected_string_literal);
+ Diag(Tok, diag::err_expected_string_literal)
+ << /*Source='availability attribute'*/2;
SkipUntil(tok::r_paren);
return;
}
@@ -898,9 +931,11 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA,
LA.Toks.push_back(Tok);
PP.EnterTokenStream(LA.Toks.data(), LA.Toks.size(), true, false);
// Consume the previously pushed token.
- ConsumeAnyToken();
+ ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
if (OnDefinition && !IsThreadSafetyAttribute(LA.AttrName.getName())) {
+ // FIXME: Do not warn on C++11 attributes, once we start supporting
+ // them here.
Diag(Tok, diag::warn_attribute_on_function_definition)
<< LA.AttrName.getName();
}
@@ -969,7 +1004,7 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA,
/// \brief Wrapper around a case statement checking if AttrName is
/// one of the thread safety attributes
-bool Parser::IsThreadSafetyAttribute(llvm::StringRef AttrName){
+bool Parser::IsThreadSafetyAttribute(StringRef AttrName) {
return llvm::StringSwitch<bool>(AttrName)
.Case("guarded_by", true)
.Case("guarded_var", true)
@@ -1018,6 +1053,7 @@ void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName,
// now parse the list of expressions
while (Tok.isNot(tok::r_paren)) {
+ EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
ExprResult ArgExpr(ParseAssignmentExpression());
if (ArgExpr.isInvalid()) {
ArgExprsOk = false;
@@ -1137,6 +1173,25 @@ bool Parser::DiagnoseProhibitedCXX11Attribute() {
llvm_unreachable("All cases handled above.");
}
+/// \brief We have found the opening square brackets of a C++11
+/// attribute-specifier in a location where an attribute is not permitted, but
+/// we know where the attributes ought to be written. Parse them anyway, and
+/// provide a fixit moving them to the right place.
+void Parser::DiagnoseMisplacedCXX11Attribute(ParsedAttributesWithRange &Attrs,
+ SourceLocation CorrectLocation) {
+ assert((Tok.is(tok::l_square) && NextToken().is(tok::l_square)) ||
+ Tok.is(tok::kw_alignas));
+
+ // Consume the attributes.
+ SourceLocation Loc = Tok.getLocation();
+ ParseCXX11Attributes(Attrs);
+ CharSourceRange AttrRange(SourceRange(Loc, Attrs.Range.getEnd()), true);
+
+ Diag(Loc, diag::err_attributes_not_allowed)
+ << FixItHint::CreateInsertionFromRange(CorrectLocation, AttrRange)
+ << FixItHint::CreateRemoval(AttrRange);
+}
+
void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) {
Diag(attrs.Range.getBegin(), diag::err_attributes_not_allowed)
<< attrs.Range;
@@ -1145,8 +1200,8 @@ void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) {
void Parser::ProhibitCXX11Attributes(ParsedAttributesWithRange &attrs) {
AttributeList *AttrList = attrs.getList();
while (AttrList) {
- if (AttrList->isCXX0XAttribute()) {
- Diag(AttrList->getLoc(), diag::warn_attribute_no_decl)
+ if (AttrList->isCXX11Attribute()) {
+ Diag(AttrList->getLoc(), diag::err_attribute_not_type_attr)
<< AttrList->getName();
AttrList->setInvalid();
}
@@ -1239,11 +1294,10 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts,
Parser::DeclGroupPtrTy
Parser::ParseSimpleDeclaration(StmtVector &Stmts, unsigned Context,
SourceLocation &DeclEnd,
- ParsedAttributesWithRange &attrs,
+ ParsedAttributesWithRange &Attrs,
bool RequireSemi, ForRangeInit *FRI) {
// Parse the common declaration-specifiers piece.
ParsingDeclSpec DS(*this);
- DS.takeAttributesFrom(attrs);
ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none,
getDeclSpecContextFromDeclaratorContext(Context));
@@ -1251,6 +1305,7 @@ Parser::ParseSimpleDeclaration(StmtVector &Stmts, unsigned Context,
// C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };"
// declaration-specifiers init-declarator-list[opt] ';'
if (Tok.is(tok::semi)) {
+ ProhibitAttributes(Attrs);
DeclEnd = Tok.getLocation();
if (RequireSemi) ConsumeToken();
Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none,
@@ -1259,6 +1314,7 @@ Parser::ParseSimpleDeclaration(StmtVector &Stmts, unsigned Context,
return Actions.ConvertDeclToDeclGroup(TheDecl);
}
+ DS.takeAttributesFrom(Attrs);
return ParseDeclGroup(DS, Context, /*FunctionDefs=*/ false, &DeclEnd, FRI);
}
@@ -1283,7 +1339,7 @@ bool Parser::MightBeDeclarator(unsigned Context) {
return getLangOpts().CPlusPlus;
case tok::l_square: // Might be an attribute on an unnamed bit-field.
- return Context == Declarator::MemberContext && getLangOpts().CPlusPlus0x &&
+ return Context == Declarator::MemberContext && getLangOpts().CPlusPlus11 &&
NextToken().is(tok::l_square);
case tok::colon: // Might be a typo for '::' or an unnamed bit-field.
@@ -1317,7 +1373,7 @@ bool Parser::MightBeDeclarator(unsigned Context) {
(getLangOpts().CPlusPlus && Context == Declarator::FileContext);
case tok::identifier: // Possible virt-specifier.
- return getLangOpts().CPlusPlus0x && isCXX0XVirtSpecifier(NextToken());
+ return getLangOpts().CPlusPlus11 && isCXX11VirtSpecifier(NextToken());
default:
return false;
@@ -1720,7 +1776,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D,
Actions.AddInitializerToDecl(ThisDecl, Initializer.take(),
/*DirectInit=*/true, TypeContainsAuto);
}
- } else if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace) &&
+ } else if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace) &&
(!CurParsedObjCImpl || !D.isFunctionDeclarator())) {
// Parse C++0x braced-init-list.
Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
@@ -1841,7 +1897,8 @@ static bool isValidAfterIdentifierInDeclarator(const Token &T) {
///
bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
const ParsedTemplateInfo &TemplateInfo,
- AccessSpecifier AS, DeclSpecContext DSC) {
+ AccessSpecifier AS, DeclSpecContext DSC,
+ ParsedAttributesWithRange &Attrs) {
assert(Tok.is(tok::identifier) && "should have identifier");
SourceLocation Loc = Tok.getLocation();
@@ -1927,7 +1984,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
ParseEnumSpecifier(Loc, DS, TemplateInfo, AS, DSC_normal);
else
ParseClassSpecifier(TagKind, Loc, DS, TemplateInfo, AS,
- /*EnteringContext*/ false, DSC_normal);
+ /*EnteringContext*/ false, DSC_normal, Attrs);
return true;
}
}
@@ -2056,7 +2113,7 @@ ExprResult Parser::ParseAlignArgument(SourceLocation Start,
} else
ER = ParseConstantExpression();
- if (getLangOpts().CPlusPlus0x && Tok.is(tok::ellipsis))
+ if (getLangOpts().CPlusPlus11 && Tok.is(tok::ellipsis))
EllipsisLoc = ConsumeToken();
return ER;
@@ -2068,15 +2125,15 @@ ExprResult Parser::ParseAlignArgument(SourceLocation Start,
/// alignment-specifier:
/// [C11] '_Alignas' '(' type-id ')'
/// [C11] '_Alignas' '(' constant-expression ')'
-/// [C++0x] 'alignas' '(' type-id ...[opt] ')'
-/// [C++0x] 'alignas' '(' assignment-expression ...[opt] ')'
+/// [C++11] 'alignas' '(' type-id ...[opt] ')'
+/// [C++11] 'alignas' '(' assignment-expression ...[opt] ')'
void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs,
- SourceLocation *endLoc) {
+ SourceLocation *EndLoc) {
assert((Tok.is(tok::kw_alignas) || Tok.is(tok::kw__Alignas)) &&
"Not an alignment-specifier!");
- SourceLocation KWLoc = Tok.getLocation();
- ConsumeToken();
+ IdentifierInfo *KWName = Tok.getIdentifierInfo();
+ SourceLocation KWLoc = ConsumeToken();
BalancedDelimiterTracker T(*this, tok::l_paren);
if (T.expectAndConsume(diag::err_expected_lparen))
@@ -2090,23 +2147,13 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs,
}
T.consumeClose();
- if (endLoc)
- *endLoc = T.getCloseLocation();
-
- // FIXME: Handle pack-expansions here.
- if (EllipsisLoc.isValid()) {
- Diag(EllipsisLoc, diag::err_alignas_pack_exp_unsupported);
- return;
- }
+ if (EndLoc)
+ *EndLoc = T.getCloseLocation();
ExprVector ArgExprs;
ArgExprs.push_back(ArgExpr.release());
- // FIXME: This should not be GNU, but we since the attribute used is
- // based on the spelling, and there is no true spelling for
- // C++11 attributes, this isn't accepted.
- Attrs.addNew(PP.getIdentifierInfo("aligned"), KWLoc, 0, KWLoc,
- 0, T.getOpenLocation(), ArgExprs.data(), 1,
- AttributeList::AS_GNU);
+ Attrs.addNew(KWName, KWLoc, 0, KWLoc, 0, T.getOpenLocation(),
+ ArgExprs.data(), 1, AttributeList::AS_Keyword, EllipsisLoc);
}
/// ParseDeclarationSpecifiers
@@ -2176,7 +2223,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
case tok::l_square:
case tok::kw_alignas:
- if (!isCXX11AttributeSpecifier())
+ if (!getLangOpts().CPlusPlus11 || !isCXX11AttributeSpecifier())
goto DoneWithDeclSpec;
ProhibitAttributes(attrs);
@@ -2270,8 +2317,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// name, then the code is ill-formed; this interpretation is
// reinforced by the NAD status of core issue 635.
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Next);
- if ((DSContext == DSC_top_level ||
- (DSContext == DSC_class && DS.isFriendSpecified())) &&
+ if ((DSContext == DSC_top_level || DSContext == DSC_class) &&
TemplateId->Name &&
Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS)) {
if (isConstructorDeclarator()) {
@@ -2321,8 +2367,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// If we're in a context where the identifier could be a class name,
// check whether this is a constructor declaration.
- if ((DSContext == DSC_top_level ||
- (DSContext == DSC_class && DS.isFriendSpecified())) &&
+ if ((DSContext == DSC_top_level || DSContext == DSC_class) &&
Actions.isCurrentClassName(*Next.getIdentifierInfo(), getCurScope(),
&SS)) {
if (isConstructorDeclarator())
@@ -2351,7 +2396,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// typename.
if (TypeRep == 0) {
ConsumeToken(); // Eat the scope spec so the identifier is current.
- if (ParseImplicitInt(DS, &SS, TemplateInfo, AS, DSContext)) continue;
+ ParsedAttributesWithRange Attrs(AttrFactory);
+ if (ParseImplicitInt(DS, &SS, TemplateInfo, AS, DSContext, Attrs)) {
+ if (!Attrs.empty()) {
+ AttrsLastTime = true;
+ attrs.takeAllFrom(Attrs);
+ }
+ continue;
+ }
goto DoneWithDeclSpec;
}
@@ -2447,7 +2499,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// If this is not a typedef name, don't parse it as part of the declspec,
// it must be an implicit int or an error.
if (!TypeRep) {
- if (ParseImplicitInt(DS, 0, TemplateInfo, AS, DSContext)) continue;
+ ParsedAttributesWithRange Attrs(AttrFactory);
+ if (ParseImplicitInt(DS, 0, TemplateInfo, AS, DSContext, Attrs)) {
+ if (!Attrs.empty()) {
+ AttrsLastTime = true;
+ attrs.takeAllFrom(Attrs);
+ }
+ continue;
+ }
goto DoneWithDeclSpec;
}
@@ -2512,7 +2571,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// Microsoft single token adornments.
case tok::kw___forceinline: {
- isInvalid = DS.SetFunctionSpecInline(Loc, PrevSpec, DiagID);
+ isInvalid = DS.setFunctionSpecInline(Loc);
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
SourceLocation AttrNameLoc = Tok.getLocation();
// FIXME: This does not work correctly if it is set to be a declspec
@@ -2565,7 +2624,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
PrevSpec, DiagID);
break;
case tok::kw_auto:
- if (getLangOpts().CPlusPlus0x) {
+ if (getLangOpts().CPlusPlus11) {
if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) {
isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc,
PrevSpec, DiagID);
@@ -2593,13 +2652,18 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// function-specifier
case tok::kw_inline:
- isInvalid = DS.SetFunctionSpecInline(Loc, PrevSpec, DiagID);
+ isInvalid = DS.setFunctionSpecInline(Loc);
break;
case tok::kw_virtual:
- isInvalid = DS.SetFunctionSpecVirtual(Loc, PrevSpec, DiagID);
+ isInvalid = DS.setFunctionSpecVirtual(Loc);
break;
case tok::kw_explicit:
- isInvalid = DS.SetFunctionSpecExplicit(Loc, PrevSpec, DiagID);
+ isInvalid = DS.setFunctionSpecExplicit(Loc);
+ break;
+ case tok::kw__Noreturn:
+ if (!getLangOpts().C11)
+ Diag(Loc, diag::ext_c11_noreturn);
+ isInvalid = DS.setFunctionSpecNoreturn(Loc);
break;
// alignment-specifier
@@ -2736,6 +2800,38 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
case tok::kw___pixel:
isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID);
break;
+ case tok::kw_image1d_t:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image1d_t, Loc,
+ PrevSpec, DiagID);
+ break;
+ case tok::kw_image1d_array_t:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image1d_array_t, Loc,
+ PrevSpec, DiagID);
+ break;
+ case tok::kw_image1d_buffer_t:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image1d_buffer_t, Loc,
+ PrevSpec, DiagID);
+ break;
+ case tok::kw_image2d_t:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image2d_t, Loc,
+ PrevSpec, DiagID);
+ break;
+ case tok::kw_image2d_array_t:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image2d_array_t, Loc,
+ PrevSpec, DiagID);
+ break;
+ case tok::kw_image3d_t:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_image3d_t, Loc,
+ PrevSpec, DiagID);
+ break;
+ case tok::kw_sampler_t:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_sampler_t, Loc,
+ PrevSpec, DiagID);
+ break;
+ case tok::kw_event_t:
+ isInvalid = DS.SetTypeSpecType(DeclSpec::TST_event_t, Loc,
+ PrevSpec, DiagID);
+ break;
case tok::kw___unknown_anytype:
isInvalid = DS.SetTypeSpecType(TST_unknown_anytype, Loc,
PrevSpec, DiagID);
@@ -2748,8 +2844,20 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
case tok::kw_union: {
tok::TokenKind Kind = Tok.getKind();
ConsumeToken();
+
+ // These are attributes following class specifiers.
+ // To produce better diagnostic, we parse them when
+ // parsing class specifier.
+ ParsedAttributesWithRange Attributes(AttrFactory);
ParseClassSpecifier(Kind, Loc, DS, TemplateInfo, AS,
- EnteringContext, DSContext);
+ EnteringContext, DSContext, Attributes);
+
+ // If there are attributes following class specifier,
+ // take them over and handle them here.
+ if (!Attributes.empty()) {
+ AttrsLastTime = true;
+ attrs.takeAllFrom(Attributes);
+ }
continue;
}
@@ -2797,8 +2905,17 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
continue;
case tok::kw__Atomic:
- ParseAtomicSpecifier(DS);
- continue;
+ // C11 6.7.2.4/4:
+ // If the _Atomic keyword is immediately followed by a left parenthesis,
+ // it is interpreted as a type specifier (with a type name), not as a
+ // type qualifier.
+ if (NextToken().is(tok::l_paren)) {
+ ParseAtomicSpecifier(DS);
+ continue;
+ }
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_atomic, Loc, PrevSpec, DiagID,
+ getLangOpts());
+ break;
// OpenCL qualifiers:
case tok::kw_private:
@@ -2949,6 +3066,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
unsigned TagType, Decl *TagDecl) {
PrettyDeclStackTraceEntry CrashInfo(Actions, TagDecl, RecordLoc,
"parsing struct/union body");
+ assert(!getLangOpts().CPlusPlus && "C++ declarations not supported");
BalancedDelimiterTracker T(*this, tok::l_brace);
if (T.consumeOpen())
@@ -2957,9 +3075,8 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope);
Actions.ActOnTagStartDefinition(getCurScope(), TagDecl);
- // Empty structs are an extension in C (C99 6.7.2.1p7), but are allowed in
- // C++.
- if (Tok.is(tok::r_brace) && !getLangOpts().CPlusPlus) {
+ // Empty structs are an extension in C (C99 6.7.2.1p7).
+ if (Tok.is(tok::r_brace)) {
Diag(Tok, diag::ext_empty_struct_union) << (TagType == TST_union);
Diag(Tok, diag::warn_empty_struct_union_compat) << (TagType == TST_union);
}
@@ -2976,6 +3093,13 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
continue;
}
+ // Parse _Static_assert declaration.
+ if (Tok.is(tok::kw__Static_assert)) {
+ SourceLocation DeclEnd;
+ ParseStaticAssertDeclaration(DeclEnd);
+ continue;
+ }
+
if (!Tok.is(tok::at)) {
struct CFieldCallback : FieldCallback {
Parser &P;
@@ -3093,7 +3217,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
// If attributes exist after tag, parse them.
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseGNUAttributes(attrs);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
// If declspecs exist after tag, parse them.
while (Tok.is(tok::kw___declspec))
@@ -3103,7 +3227,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
bool IsScopedUsingClassTag = false;
// In C++11, recognize 'enum class' and 'enum struct'.
- if (getLangOpts().CPlusPlus0x &&
+ if (getLangOpts().CPlusPlus11 &&
(Tok.is(tok::kw_class) || Tok.is(tok::kw_struct))) {
Diag(Tok, diag::warn_cxx98_compat_scoped_enum);
IsScopedUsingClassTag = Tok.is(tok::kw_class);
@@ -3115,7 +3239,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
// They are allowed afterwards, though.
MaybeParseGNUAttributes(attrs);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
while (Tok.is(tok::kw___declspec))
ParseMicrosoftDeclSpec(attrs);
}
@@ -3135,7 +3259,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
bool AllowDeclaration = DSC != DSC_trailing;
bool AllowFixedUnderlyingType = AllowDeclaration &&
- (getLangOpts().CPlusPlus0x || getLangOpts().MicrosoftExt ||
+ (getLangOpts().CPlusPlus11 || getLangOpts().MicrosoftExt ||
getLangOpts().ObjC2);
CXXScopeSpec &SS = DS.getTypeSpecScope();
@@ -3145,7 +3269,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
ColonProtectionRAIIObject X(*this, AllowFixedUnderlyingType);
if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
- /*EnteringContext=*/false))
+ /*EnteringContext=*/true))
return;
if (SS.isSet() && Tok.isNot(tok::identifier)) {
@@ -3254,7 +3378,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
SourceRange Range;
BaseType = ParseTypeName(&Range);
- if (getLangOpts().CPlusPlus0x) {
+ if (getLangOpts().CPlusPlus11) {
Diag(StartLoc, diag::warn_cxx98_compat_enum_fixed_underlying_type);
} else if (!getLangOpts().ObjC2) {
if (getLangOpts().CPlusPlus)
@@ -3313,7 +3437,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
MultiTemplateParamsArg TParams;
if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
TUK != Sema::TUK_Reference) {
- if (!getLangOpts().CPlusPlus0x || !SS.isSet()) {
+ if (!getLangOpts().CPlusPlus11 || !SS.isSet()) {
// Skip the rest of this declarator, up until the comma or semicolon.
Diag(Tok, diag::err_enum_template);
SkipUntil(tok::comma, true);
@@ -3433,7 +3557,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
// If attributes exist after the enumerator, parse them.
ParsedAttributesWithRange attrs(AttrFactory);
MaybeParseGNUAttributes(attrs);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
ProhibitAttributes(attrs);
SourceLocation EqualLoc;
@@ -3471,12 +3595,12 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
SourceLocation CommaLoc = ConsumeToken();
if (Tok.isNot(tok::identifier)) {
- if (!getLangOpts().C99 && !getLangOpts().CPlusPlus0x)
+ if (!getLangOpts().C99 && !getLangOpts().CPlusPlus11)
Diag(CommaLoc, getLangOpts().CPlusPlus ?
diag::ext_enumerator_list_comma_cxx :
diag::ext_enumerator_list_comma_c)
<< FixItHint::CreateRemoval(CommaLoc);
- else if (getLangOpts().CPlusPlus0x)
+ else if (getLangOpts().CPlusPlus11)
Diag(CommaLoc, diag::warn_cxx98_compat_enumerator_list_comma)
<< FixItHint::CreateRemoval(CommaLoc);
}
@@ -3567,6 +3691,16 @@ bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const {
case tok::kw__Decimal128:
case tok::kw___vector:
+ // OpenCL specific types:
+ case tok::kw_image1d_t:
+ case tok::kw_image1d_array_t:
+ case tok::kw_image1d_buffer_t:
+ case tok::kw_image2d_t:
+ case tok::kw_image2d_array_t:
+ case tok::kw_image3d_t:
+ case tok::kw_sampler_t:
+ case tok::kw_event_t:
+
// struct-or-union-specifier (C99) or class-specifier (C++)
case tok::kw_class:
case tok::kw_struct:
@@ -3639,6 +3773,16 @@ bool Parser::isTypeSpecifierQualifier() {
case tok::kw__Decimal128:
case tok::kw___vector:
+ // OpenCL specific types:
+ case tok::kw_image1d_t:
+ case tok::kw_image1d_array_t:
+ case tok::kw_image1d_buffer_t:
+ case tok::kw_image2d_t:
+ case tok::kw_image2d_array_t:
+ case tok::kw_image3d_t:
+ case tok::kw_sampler_t:
+ case tok::kw_event_t:
+
// struct-or-union-specifier (C99) or class-specifier (C++)
case tok::kw_class:
case tok::kw_struct:
@@ -3652,6 +3796,9 @@ bool Parser::isTypeSpecifierQualifier() {
case tok::kw_volatile:
case tok::kw_restrict:
+ // Debugger support.
+ case tok::kw___unknown_anytype:
+
// typedef-name
case tok::annot_typename:
return true;
@@ -3683,7 +3830,7 @@ bool Parser::isTypeSpecifierQualifier() {
case tok::kw_private:
return getLangOpts().OpenCL;
- // C11 _Atomic()
+ // C11 _Atomic
case tok::kw__Atomic:
return true;
}
@@ -3751,6 +3898,9 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
// Modules
case tok::kw___module_private__:
+ // Debugger support
+ case tok::kw___unknown_anytype:
+
// type-specifiers
case tok::kw_short:
case tok::kw_long:
@@ -3777,6 +3927,16 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::kw__Decimal128:
case tok::kw___vector:
+ // OpenCL specific types:
+ case tok::kw_image1d_t:
+ case tok::kw_image1d_array_t:
+ case tok::kw_image1d_buffer_t:
+ case tok::kw_image2d_t:
+ case tok::kw_image2d_array_t:
+ case tok::kw_image3d_t:
+ case tok::kw_sampler_t:
+ case tok::kw_event_t:
+
// struct-or-union-specifier (C99) or class-specifier (C++)
case tok::kw_class:
case tok::kw_struct:
@@ -3794,6 +3954,10 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::kw_inline:
case tok::kw_virtual:
case tok::kw_explicit:
+ case tok::kw__Noreturn:
+
+ // alignment-specifier
+ case tok::kw__Alignas:
// friend keyword.
case tok::kw_friend:
@@ -3811,7 +3975,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
case tok::annot_decltype:
case tok::kw_constexpr:
- // C11 _Atomic()
+ // C11 _Atomic
case tok::kw__Atomic:
return true;
@@ -3946,13 +4110,14 @@ bool Parser::isConstructorDeclarator() {
/// [vendor] type-qualifier-list attributes
/// [ only if VendorAttributesAllowed=true ]
/// [C++0x] attribute-specifier[opt] is allowed before cv-qualifier-seq
-/// [ only if CXX0XAttributesAllowed=true ]
+/// [ only if CXX11AttributesAllowed=true ]
/// Note: vendor can be GNU, MS, etc.
///
void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
bool VendorAttributesAllowed,
- bool CXX11AttributesAllowed) {
- if (getLangOpts().CPlusPlus0x && CXX11AttributesAllowed &&
+ bool CXX11AttributesAllowed,
+ bool AtomicAllowed) {
+ if (getLangOpts().CPlusPlus11 && CXX11AttributesAllowed &&
isCXX11AttributeSpecifier()) {
ParsedAttributesWithRange attrs(AttrFactory);
ParseCXX11Attributes(attrs);
@@ -3984,6 +4149,12 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID,
getLangOpts());
break;
+ case tok::kw__Atomic:
+ if (!AtomicAllowed)
+ goto DoneWithTypeQuals;
+ isInvalid = DS.SetTypeQual(DeclSpec::TQ_atomic, Loc, PrevSpec, DiagID,
+ getLangOpts());
+ break;
// OpenCL qualifiers:
case tok::kw_private:
@@ -4107,7 +4278,11 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
if (SS.isNotEmpty()) {
if (Tok.isNot(tok::star)) {
// The scope spec really belongs to the direct-declarator.
- D.getCXXScopeSpec() = SS;
+ if (D.mayHaveIdentifier())
+ D.getCXXScopeSpec() = SS;
+ else
+ AnnotateScopeToken(SS, true);
+
if (DirectDeclParser)
(this->*DirectDeclParser)(D);
return;
@@ -4176,7 +4351,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
// Complain about rvalue references in C++03, but then go on and build
// the declarator.
if (Kind == tok::ampamp)
- Diag(Loc, getLangOpts().CPlusPlus0x ?
+ Diag(Loc, getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_rvalue_reference :
diag::ext_rvalue_reference);
@@ -4194,6 +4369,10 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile)
Diag(DS.getVolatileSpecLoc(),
diag::err_invalid_reference_qualifier_application) << "volatile";
+ // 'restrict' is permitted as an extension.
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic)
+ Diag(DS.getAtomicSpecLoc(),
+ diag::err_invalid_reference_qualifier_application) << "_Atomic";
}
// Recursively parse the declarator.
@@ -4216,7 +4395,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
}
}
- // Remember that we parsed a reference type. It doesn't have type-quals.
+ // Remember that we parsed a reference type.
D.AddTypeInfo(DeclaratorChunk::getReference(DS.getTypeQualifiers(), Loc,
Kind == tok::amp),
DS.getAttributes(),
@@ -4308,6 +4487,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
!((D.getContext() == Declarator::PrototypeContext ||
D.getContext() == Declarator::BlockLiteralContext) &&
NextToken().is(tok::r_paren) &&
+ !D.hasGroupingParens() &&
!Actions.containsUnexpandedParameterPacks(D))) {
SourceLocation EllipsisLoc = ConsumeToken();
if (isPtrOperatorToken(Tok.getKind(), getLangOpts())) {
@@ -4334,8 +4514,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
else if (D.getCXXScopeSpec().isSet())
AllowConstructorName =
(D.getContext() == Declarator::FileContext ||
- (D.getContext() == Declarator::MemberContext &&
- D.getDeclSpec().isFriendSpecified()));
+ D.getContext() == Declarator::MemberContext);
else
AllowConstructorName = (D.getContext() == Declarator::MemberContext);
@@ -4391,15 +4570,24 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
// This could be something simple like "int" (in which case the declarator
// portion is empty), if an abstract-declarator is allowed.
D.SetIdentifier(0, Tok.getLocation());
+
+ // The grammar for abstract-pack-declarator does not allow grouping parens.
+ // FIXME: Revisit this once core issue 1488 is resolved.
+ if (D.hasEllipsis() && D.hasGroupingParens())
+ Diag(PP.getLocForEndOfToken(D.getEllipsisLoc()),
+ diag::ext_abstract_pack_declarator_parens);
} else {
if (Tok.getKind() == tok::annot_pragma_parser_crash)
LLVM_BUILTIN_TRAP;
if (D.getContext() == Declarator::MemberContext)
Diag(Tok, diag::err_expected_member_name_or_semi)
<< D.getDeclSpec().getSourceRange();
- else if (getLangOpts().CPlusPlus)
- Diag(Tok, diag::err_expected_unqualified_id) << getLangOpts().CPlusPlus;
- else
+ else if (getLangOpts().CPlusPlus) {
+ if (Tok.is(tok::period) || Tok.is(tok::arrow))
+ Diag(Tok, diag::err_invalid_operator_on_type) << Tok.is(tok::arrow);
+ else
+ Diag(Tok, diag::err_expected_unqualified_id) << getLangOpts().CPlusPlus;
+ } else
Diag(Tok, diag::err_expected_ident_lparen);
D.SetIdentifier(0, Tok.getLocation());
D.setInvalidType(true);
@@ -4411,14 +4599,17 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
// Don't parse attributes unless we have parsed an unparenthesized name.
if (D.hasName() && !D.getNumTypeObjects())
- MaybeParseCXX0XAttributes(D);
+ MaybeParseCXX11Attributes(D);
while (1) {
if (Tok.is(tok::l_paren)) {
// Enter function-declaration scope, limiting any declarators to the
// function prototype scope, including parameter declarators.
ParseScope PrototypeScope(this,
- Scope::FunctionPrototypeScope|Scope::DeclScope);
+ Scope::FunctionPrototypeScope|Scope::DeclScope|
+ (D.isFunctionDeclaratorAFunctionDeclaration()
+ ? Scope::FunctionDeclarationScope : 0));
+
// The paren may be part of a C++ direct initializer, eg. "int x(1);".
// In such a case, check if we actually have a function declarator; if it
// is not, the declarator has been fully parsed.
@@ -4483,13 +4674,10 @@ void Parser::ParseParenDeclarator(Declarator &D) {
// present even if the attribute list was empty.
RequiresArg = true;
}
+
// Eat any Microsoft extensions.
- if (Tok.is(tok::kw___cdecl) || Tok.is(tok::kw___stdcall) ||
- Tok.is(tok::kw___thiscall) || Tok.is(tok::kw___fastcall) ||
- Tok.is(tok::kw___w64) || Tok.is(tok::kw___ptr64) ||
- Tok.is(tok::kw___ptr32) || Tok.is(tok::kw___unaligned)) {
- ParseMicrosoftTypeAttributes(attrs);
- }
+ ParseMicrosoftTypeAttributes(attrs);
+
// Eat any Borland extensions.
if (Tok.is(tok::kw___pascal))
ParseBorlandTypeAttributes(attrs);
@@ -4551,7 +4739,9 @@ void Parser::ParseParenDeclarator(Declarator &D) {
// Enter function-declaration scope, limiting any declarators to the
// function prototype scope, including parameter declarators.
ParseScope PrototypeScope(this,
- Scope::FunctionPrototypeScope|Scope::DeclScope);
+ Scope::FunctionPrototypeScope | Scope::DeclScope |
+ (D.isFunctionDeclaratorAFunctionDeclaration()
+ ? Scope::FunctionDeclarationScope : 0));
ParseFunctionDeclarator(D, attrs, T, false, RequiresArg);
PrototypeScope.Exit();
}
@@ -4646,7 +4836,9 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
// with the virt-specifier-seq and pure-specifier in the same way.
// Parse cv-qualifier-seq[opt].
- ParseTypeQualifierListOpt(DS, false /*no attributes*/, false);
+ ParseTypeQualifierListOpt(DS, /*VendorAttributesAllowed*/ false,
+ /*CXX11AttributesAllowed*/ false,
+ /*AtomicAllowed*/ false);
if (!DS.getSourceRange().getEnd().isInvalid()) {
EndLoc = DS.getSourceRange().getEnd();
ConstQualifierLoc = DS.getConstSpecLoc();
@@ -4655,7 +4847,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
// Parse ref-qualifier[opt].
if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) {
- Diag(Tok, getLangOpts().CPlusPlus0x ?
+ Diag(Tok, getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_ref_qualifier :
diag::ext_ref_qualifier);
@@ -4670,15 +4862,19 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
// "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq
// and the end of the function-definition, member-declarator, or
// declarator.
+ // FIXME: currently, "static" case isn't handled correctly.
bool IsCXX11MemberFunction =
- getLangOpts().CPlusPlus0x &&
- (D.getContext() == Declarator::MemberContext ||
- (D.getContext() == Declarator::FileContext &&
- D.getCXXScopeSpec().isValid() &&
- Actions.CurContext->isRecord()));
+ getLangOpts().CPlusPlus11 &&
+ (D.getContext() == Declarator::MemberContext
+ ? !D.getDeclSpec().isFriendSpecified()
+ : D.getContext() == Declarator::FileContext &&
+ D.getCXXScopeSpec().isValid() &&
+ Actions.CurContext->isRecord());
Sema::CXXThisScopeRAII ThisScope(Actions,
dyn_cast<CXXRecordDecl>(Actions.CurContext),
- DS.getTypeQualifiers(),
+ DS.getTypeQualifiers() |
+ (D.getDeclSpec().isConstexprSpecified()
+ ? Qualifiers::Const : 0),
IsCXX11MemberFunction);
// Parse exception-specification[opt].
@@ -4691,11 +4887,11 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
// Parse attribute-specifier-seq[opt]. Per DR 979 and DR 1297, this goes
// after the exception-specification.
- MaybeParseCXX0XAttributes(FnAttrs);
+ MaybeParseCXX11Attributes(FnAttrs);
// Parse trailing-return-type[opt].
LocalEndLoc = EndLoc;
- if (getLangOpts().CPlusPlus0x && Tok.is(tok::arrow)) {
+ if (getLangOpts().CPlusPlus11 && Tok.is(tok::arrow)) {
Diag(Tok, diag::warn_cxx98_compat_trailing_return_type);
if (D.getDeclSpec().getTypeSpecType() == TST_auto)
StartLoc = D.getDeclSpec().getTypeSpecTypeLoc();
@@ -4866,11 +5062,10 @@ void Parser::ParseParameterDeclarationClause(
DeclSpec DS(AttrFactory);
// Parse any C++11 attributes.
- MaybeParseCXX0XAttributes(DS.getAttributes());
+ MaybeParseCXX11Attributes(DS.getAttributes());
// Skip any Microsoft attributes before a param.
- if (getLangOpts().MicrosoftExt && Tok.is(tok::l_square))
- ParseMicrosoftAttributes(DS.getAttributes());
+ MaybeParseMicrosoftAttributes(DS.getAttributes());
SourceLocation DSStart = Tok.getLocation();
@@ -4955,7 +5150,7 @@ void Parser::ParseParameterDeclarationClause(
Param);
ExprResult DefArgResult;
- if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) {
+ if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
DefArgResult = ParseBraceInitializer();
} else
@@ -5017,7 +5212,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
if (Tok.getKind() == tok::r_square) {
T.consumeClose();
ParsedAttributes attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
// Remember that we parsed the empty array type.
ExprResult NumElements;
@@ -5034,10 +5229,10 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
T.consumeClose();
ParsedAttributes attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
// Remember that we parsed a array type, and remember its features.
- D.AddTypeInfo(DeclaratorChunk::getArray(0, false, 0,
+ D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false,
ExprRes.release(),
T.getOpenLocation(),
T.getCloseLocation()),
@@ -5104,7 +5299,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
T.consumeClose();
ParsedAttributes attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
// Remember that we parsed a array type, and remember its features.
D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(),
@@ -5184,14 +5379,13 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
/// _Atomic ( type-name )
///
void Parser::ParseAtomicSpecifier(DeclSpec &DS) {
- assert(Tok.is(tok::kw__Atomic) && "Not an atomic specifier");
+ assert(Tok.is(tok::kw__Atomic) && NextToken().is(tok::l_paren) &&
+ "Not an atomic specifier");
SourceLocation StartLoc = ConsumeToken();
BalancedDelimiterTracker T(*this, tok::l_paren);
- if (T.expectAndConsume(diag::err_expected_lparen_after, "_Atomic")) {
- SkipUntil(tok::r_paren);
+ if (T.consumeOpen())
return;
- }
TypeResult Result = ParseTypeName();
if (Result.isInvalid()) {
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index f11a9d1..d7f8e98 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -11,16 +11,17 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Basic/OperatorKinds.h"
#include "clang/Parse/Parser.h"
+#include "RAIIObjectsForParser.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/OperatorKinds.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/DeclSpec.h"
-#include "clang/Sema/Scope.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/PrettyDeclStackTrace.h"
+#include "clang/Sema/Scope.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/ADT/SmallString.h"
-#include "RAIIObjectsForParser.h"
using namespace clang;
/// ParseNamespace - We know that the current token is a namespace keyword. This
@@ -157,7 +158,7 @@ Decl *Parser::ParseNamespace(unsigned Context,
// If we're still good, complain about inline namespaces in non-C++0x now.
if (InlineLoc.isValid())
- Diag(InlineLoc, getLangOpts().CPlusPlus0x ?
+ Diag(InlineLoc, getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_inline_namespace : diag::ext_inline_namespace);
// Enter a scope for the namespace.
@@ -195,7 +196,7 @@ void Parser::ParseInnerNamespace(std::vector<SourceLocation>& IdentLoc,
if (index == Ident.size()) {
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
MaybeParseMicrosoftAttributes(attrs);
ParseExternalDeclaration(attrs);
}
@@ -295,7 +296,7 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) {
: SourceLocation());
ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
MaybeParseMicrosoftAttributes(attrs);
if (Tok.isNot(tok::l_brace)) {
@@ -318,7 +319,7 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) {
T.consumeOpen();
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
MaybeParseMicrosoftAttributes(attrs);
ParseExternalDeclaration(attrs);
}
@@ -439,8 +440,8 @@ Decl *Parser::ParseUsingDirective(unsigned Context,
/// unqualified-id
/// 'using' :: unqualified-id
///
-/// alias-declaration: C++0x [decl.typedef]p2
-/// 'using' identifier = type-id ;
+/// alias-declaration: C++11 [dcl.dcl]p1
+/// 'using' identifier attribute-specifier-seq[opt] = type-id ;
///
Decl *Parser::ParseUsingDeclaration(unsigned Context,
const ParsedTemplateInfo &TemplateInfo,
@@ -450,27 +451,27 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
Decl **OwnedType) {
CXXScopeSpec SS;
SourceLocation TypenameLoc;
- bool IsTypeName;
- ParsedAttributesWithRange attrs(AttrFactory);
+ bool IsTypeName = false;
+ ParsedAttributesWithRange Attrs(AttrFactory);
// FIXME: Simply skip the attributes and diagnose, don't bother parsing them.
- MaybeParseCXX0XAttributes(attrs);
- ProhibitAttributes(attrs);
- attrs.clear();
- attrs.Range = SourceRange();
+ MaybeParseCXX11Attributes(Attrs);
+ ProhibitAttributes(Attrs);
+ Attrs.clear();
+ Attrs.Range = SourceRange();
// Ignore optional 'typename'.
// FIXME: This is wrong; we should parse this as a typename-specifier.
if (Tok.is(tok::kw_typename)) {
- TypenameLoc = Tok.getLocation();
- ConsumeToken();
+ TypenameLoc = ConsumeToken();
IsTypeName = true;
}
- else
- IsTypeName = false;
// Parse nested-name-specifier.
- ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false);
+ IdentifierInfo *LastII = 0;
+ ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false,
+ /*MayBePseudoDtor=*/0, /*IsTypename=*/false,
+ /*LastII=*/&LastII);
// Check nested-name specifier.
if (SS.isInvalid()) {
@@ -478,33 +479,45 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
return 0;
}
+ SourceLocation TemplateKWLoc;
+ UnqualifiedId Name;
+
// Parse the unqualified-id. We allow parsing of both constructor and
// destructor names and allow the action module to diagnose any semantic
// errors.
- SourceLocation TemplateKWLoc;
- UnqualifiedId Name;
- if (ParseUnqualifiedId(SS,
- /*EnteringContext=*/false,
- /*AllowDestructorName=*/true,
- /*AllowConstructorName=*/true,
- ParsedType(),
- TemplateKWLoc,
- Name)) {
+ //
+ // C++11 [class.qual]p2:
+ // [...] in a using-declaration that is a member-declaration, if the name
+ // specified after the nested-name-specifier is the same as the identifier
+ // or the simple-template-id's template-name in the last component of the
+ // nested-name-specifier, the name is [...] considered to name the
+ // constructor.
+ if (getLangOpts().CPlusPlus11 && Context == Declarator::MemberContext &&
+ Tok.is(tok::identifier) && NextToken().is(tok::semi) &&
+ SS.isNotEmpty() && LastII == Tok.getIdentifierInfo() &&
+ !SS.getScopeRep()->getAsNamespace() &&
+ !SS.getScopeRep()->getAsNamespaceAlias()) {
+ SourceLocation IdLoc = ConsumeToken();
+ ParsedType Type = Actions.getInheritingConstructorName(SS, IdLoc, *LastII);
+ Name.setConstructorName(Type, IdLoc, IdLoc);
+ } else if (ParseUnqualifiedId(SS, /*EnteringContext=*/ false,
+ /*AllowDestructorName=*/ true,
+ /*AllowConstructorName=*/ true, ParsedType(),
+ TemplateKWLoc, Name)) {
SkipUntil(tok::semi);
return 0;
}
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(Attrs);
// Maybe this is an alias-declaration.
bool IsAliasDecl = Tok.is(tok::equal);
TypeResult TypeAlias;
if (IsAliasDecl) {
- // TODO: Attribute support. C++0x attributes may appear before the equals.
- // Where can GNU attributes appear?
+ // TODO: Can GNU attributes appear here?
ConsumeToken();
- Diag(Tok.getLocation(), getLangOpts().CPlusPlus0x ?
+ Diag(Tok.getLocation(), getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_alias_declaration :
diag::ext_alias_declaration);
@@ -546,25 +559,26 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
TypeAlias = ParseTypeName(0, TemplateInfo.Kind ?
Declarator::AliasTemplateContext :
- Declarator::AliasDeclContext, AS, OwnedType);
+ Declarator::AliasDeclContext, AS, OwnedType,
+ &Attrs);
} else {
// C++11 attributes are not allowed on a using-declaration, but GNU ones
// are.
- ProhibitAttributes(attrs);
+ ProhibitAttributes(Attrs);
// Parse (optional) attributes (most likely GNU strong-using extension).
- MaybeParseGNUAttributes(attrs);
+ MaybeParseGNUAttributes(Attrs);
}
// Eat ';'.
DeclEnd = Tok.getLocation();
ExpectAndConsume(tok::semi, diag::err_expected_semi_after,
- !attrs.empty() ? "attributes list" :
+ !Attrs.empty() ? "attributes list" :
IsAliasDecl ? "alias declaration" : "using declaration",
tok::semi);
// Diagnose an attempt to declare a templated using-declaration.
- // In C++0x, alias-declarations can be templates:
+ // In C++11, alias-declarations can be templates:
// template <...> using id = type;
if (TemplateInfo.Kind && !IsAliasDecl) {
SourceRange R = TemplateInfo.getSourceRange();
@@ -591,13 +605,13 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,
MultiTemplateParamsArg TemplateParamsArg(
TemplateParams ? TemplateParams->data() : 0,
TemplateParams ? TemplateParams->size() : 0);
- // FIXME: Propagate attributes.
return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg,
- UsingLoc, Name, TypeAlias);
+ UsingLoc, Name, Attrs.getList(),
+ TypeAlias);
}
return Actions.ActOnUsingDeclaration(getCurScope(), AS, true, UsingLoc, SS,
- Name, attrs.getList(),
+ Name, Attrs.getList(),
IsTypeName, TypenameLoc);
}
@@ -637,7 +651,8 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
return 0;
if (!isTokenStringLiteral()) {
- Diag(Tok, diag::err_expected_string_literal);
+ Diag(Tok, diag::err_expected_string_literal)
+ << /*Source='static_assert'*/1;
SkipMalformedDecl();
return 0;
}
@@ -800,15 +815,18 @@ void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) {
/// class. The result is either a type or null, depending on whether a type
/// name was found.
///
-/// base-type-specifier: [C++ 10.1]
+/// base-type-specifier: [C++11 class.derived]
/// class-or-decltype
-/// class-or-decltype: [C++ 10.1]
+/// class-or-decltype: [C++11 class.derived]
/// nested-name-specifier[opt] class-name
/// decltype-specifier
-/// class-name: [C++ 9.1]
+/// class-name: [C++ class.name]
/// identifier
/// simple-template-id
///
+/// In C++98, instead of base-type-specifier, we have:
+///
+/// ::[opt] nested-name-specifier[opt] class-name
Parser::TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
SourceLocation &EndLocation) {
// Ignore attempts to use typename
@@ -956,6 +974,7 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) {
case tok::semi: // struct foo {...} ;
case tok::star: // struct foo {...} * P;
case tok::amp: // struct foo {...} & R = ...
+ case tok::ampamp: // struct foo {...} && R = ...
case tok::identifier: // struct foo {...} V ;
case tok::r_paren: //(struct foo {...} ) {4}
case tok::annot_cxxscope: // struct foo {...} a:: b;
@@ -963,6 +982,7 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) {
case tok::annot_template_id: // struct foo {...} a<int> ::b;
case tok::l_paren: // struct foo {...} ( x);
case tok::comma: // __builtin_offsetof(struct foo{...} ,
+ case tok::kw_operator: // struct foo operator ++() {...}
return true;
case tok::colon:
return CouldBeBitfield; // enum E { ... } : 2;
@@ -970,7 +990,12 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) {
case tok::kw_const: // struct foo {...} const x;
case tok::kw_volatile: // struct foo {...} volatile x;
case tok::kw_restrict: // struct foo {...} restrict x;
- case tok::kw_inline: // struct foo {...} inline foo() {};
+ // Function specifiers
+ // Note, no 'explicit'. An explicit function must be either a conversion
+ // operator or a constructor. Either way, it can't have a return type.
+ case tok::kw_inline: // struct foo inline f();
+ case tok::kw_virtual: // struct foo virtual f();
+ case tok::kw_friend: // struct foo friend f();
// Storage-class specifiers
case tok::kw_static: // struct foo {...} static x;
case tok::kw_extern: // struct foo {...} extern x;
@@ -978,6 +1003,7 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) {
case tok::kw_register: // struct foo {...} register x;
case tok::kw_auto: // struct foo {...} auto x;
case tok::kw_mutable: // struct foo {...} mutable x;
+ case tok::kw_thread_local: // struct foo {...} thread_local x;
case tok::kw_constexpr: // struct foo {...} constexpr x;
// As shown above, type qualifiers and storage class specifiers absolutely
// can occur after class specifiers according to the grammar. However,
@@ -1002,6 +1028,13 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) {
if (!getLangOpts().CPlusPlus)
return true;
break;
+ // C++11 attributes
+ case tok::l_square: // enum E [[]] x
+ // Note, no tok::kw_alignas here; alignas cannot appertain to a type.
+ return getLangOpts().CPlusPlus11 && NextToken().is(tok::l_square);
+ case tok::greater:
+ // template<class T = class X>
+ return getLangOpts().CPlusPlus;
}
return false;
}
@@ -1050,7 +1083,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
SourceLocation StartLoc, DeclSpec &DS,
const ParsedTemplateInfo &TemplateInfo,
AccessSpecifier AS,
- bool EnteringContext, DeclSpecContext DSC) {
+ bool EnteringContext, DeclSpecContext DSC,
+ ParsedAttributesWithRange &Attributes) {
DeclSpec::TST TagType;
if (TagTokKind == tok::kw_struct)
TagType = DeclSpec::TST_struct;
@@ -1102,7 +1136,11 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// If C++0x attributes exist here, parse them.
// FIXME: Are we consistent with the ordering of parsing of different
// styles of attributes?
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
+
+ // Source location used by FIXIT to insert misplaced
+ // C++11 attributes
+ SourceLocation AttrFixitLoc = Tok.getLocation();
if (TagType == DeclSpec::TST_struct &&
!Tok.is(tok::identifier) &&
@@ -1232,18 +1270,30 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// - If we have 'struct foo;', then this is either a forward declaration
// or a friend declaration, which have to be treated differently.
// - Otherwise we have something like 'struct foo xyz', a reference.
+ //
+ // We also detect these erroneous cases to provide better diagnostic for
+ // C++11 attributes parsing.
+ // - attributes follow class name:
+ // struct foo [[]] {};
+ // - attributes appear before or after 'final':
+ // struct foo [[]] final [[]] {};
+ //
// However, in type-specifier-seq's, things look like declarations but are
// just references, e.g.
// new struct s;
// or
// &T::operator struct s;
// For these, DSC is DSC_type_specifier.
+
+ // If there are attributes after class name, parse them.
+ MaybeParseCXX11Attributes(Attributes);
+
Sema::TagUseKind TUK;
if (DSC == DSC_trailing)
TUK = Sema::TUK_Reference;
else if (Tok.is(tok::l_brace) ||
(getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||
- (isCXX0XFinalKeyword() &&
+ (isCXX11FinalKeyword() &&
(NextToken().is(tok::l_brace) || NextToken().is(tok::colon)))) {
if (DS.isFriendSpecified()) {
// C++ [class.friend]p2:
@@ -1259,6 +1309,37 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// Okay, this is a class definition.
TUK = Sema::TUK_Definition;
}
+ } else if (isCXX11FinalKeyword() && (NextToken().is(tok::l_square) ||
+ NextToken().is(tok::kw_alignas))) {
+ // We can't tell if this is a definition or reference
+ // until we skipped the 'final' and C++11 attribute specifiers.
+ TentativeParsingAction PA(*this);
+
+ // Skip the 'final' keyword.
+ ConsumeToken();
+
+ // Skip C++11 attribute specifiers.
+ while (true) {
+ if (Tok.is(tok::l_square) && NextToken().is(tok::l_square)) {
+ ConsumeBracket();
+ if (!SkipUntil(tok::r_square))
+ break;
+ } else if (Tok.is(tok::kw_alignas) && NextToken().is(tok::l_paren)) {
+ ConsumeToken();
+ ConsumeParen();
+ if (!SkipUntil(tok::r_paren))
+ break;
+ } else {
+ break;
+ }
+ }
+
+ if (Tok.is(tok::l_brace) || Tok.is(tok::colon))
+ TUK = Sema::TUK_Definition;
+ else
+ TUK = Sema::TUK_Reference;
+
+ PA.Revert();
} else if (DSC != DSC_type_specifier &&
(Tok.is(tok::semi) ||
(Tok.isAtStartOfLine() && !isValidAfterTypeSpecifier(false)))) {
@@ -1273,6 +1354,28 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
} else
TUK = Sema::TUK_Reference;
+ // Forbid misplaced attributes. In cases of a reference, we pass attributes
+ // to caller to handle.
+ if (TUK != Sema::TUK_Reference) {
+ // If this is not a reference, then the only possible
+ // valid place for C++11 attributes to appear here
+ // is between class-key and class-name. If there are
+ // any attributes after class-name, we try a fixit to move
+ // them to the right place.
+ SourceRange AttrRange = Attributes.Range;
+ if (AttrRange.isValid()) {
+ Diag(AttrRange.getBegin(), diag::err_attributes_not_allowed)
+ << AttrRange
+ << FixItHint::CreateInsertionFromRange(AttrFixitLoc,
+ CharSourceRange(AttrRange, true))
+ << FixItHint::CreateRemoval(AttrRange);
+
+ // Recover by adding misplaced attributes to the attribute list
+ // of the class so they can be applied on the class later.
+ attrs.takeAllFrom(Attributes);
+ }
+ }
+
// If this is an elaborated type specifier, and we delayed
// diagnostics before, just merge them into the current pool.
if (shouldDelayDiagsInTag) {
@@ -1414,11 +1517,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TemplateParams? &(*TemplateParams)[0] : 0,
TemplateParams? TemplateParams->size() : 0));
} else {
- if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&
- TUK == Sema::TUK_Definition) {
- // FIXME: Diagnose this particular error.
- }
-
if (TUK != Sema::TUK_Declaration && TUK != Sema::TUK_Definition)
ProhibitAttributes(attrs);
@@ -1453,9 +1551,10 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (TUK == Sema::TUK_Definition) {
assert(Tok.is(tok::l_brace) ||
(getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||
- isCXX0XFinalKeyword());
+ isCXX11FinalKeyword());
if (getLangOpts().CPlusPlus)
- ParseCXXMemberSpecification(StartLoc, TagType, TagOrTempResult.get());
+ ParseCXXMemberSpecification(StartLoc, AttrFixitLoc, attrs, TagType,
+ TagOrTempResult.get());
else
ParseStructUnionBody(StartLoc, TagType, TagOrTempResult.get());
}
@@ -1490,13 +1589,15 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// is permitted.
if (TUK == Sema::TUK_Definition &&
(TemplateInfo.Kind || !isValidAfterTypeSpecifier(false))) {
- ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl,
- DeclSpec::getSpecifierName(TagType));
- // Push this token back into the preprocessor and change our current token
- // to ';' so that the rest of the code recovers as though there were an
- // ';' after the definition.
- PP.EnterToken(Tok);
- Tok.setKind(tok::semi);
+ if (Tok.isNot(tok::semi)) {
+ ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl,
+ DeclSpec::getSpecifierName(TagType));
+ // Push this token back into the preprocessor and change our current token
+ // to ';' so that the rest of the code recovers as though there were an
+ // ';' after the definition.
+ PP.EnterToken(Tok);
+ Tok.setKind(tok::semi);
+ }
}
}
@@ -1544,26 +1645,33 @@ void Parser::ParseBaseClause(Decl *ClassDecl) {
/// 'public bar' and 'virtual private baz' are each base-specifiers.
///
/// base-specifier: [C++ class.derived]
-/// ::[opt] nested-name-specifier[opt] class-name
-/// 'virtual' access-specifier[opt] ::[opt] nested-name-specifier[opt]
-/// base-type-specifier
-/// access-specifier 'virtual'[opt] ::[opt] nested-name-specifier[opt]
-/// base-type-specifier
+/// attribute-specifier-seq[opt] base-type-specifier
+/// attribute-specifier-seq[opt] 'virtual' access-specifier[opt]
+/// base-type-specifier
+/// attribute-specifier-seq[opt] access-specifier 'virtual'[opt]
+/// base-type-specifier
Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) {
bool IsVirtual = false;
SourceLocation StartLoc = Tok.getLocation();
+ ParsedAttributesWithRange Attributes(AttrFactory);
+ MaybeParseCXX11Attributes(Attributes);
+
// Parse the 'virtual' keyword.
if (Tok.is(tok::kw_virtual)) {
ConsumeToken();
IsVirtual = true;
}
+ CheckMisplacedCXX11Attribute(Attributes, StartLoc);
+
// Parse an (optional) access specifier.
AccessSpecifier Access = getAccessSpecifierIfPresent();
if (Access != AS_none)
ConsumeToken();
+ CheckMisplacedCXX11Attribute(Attributes, StartLoc);
+
// Parse the 'virtual' keyword (again!), in case it came after the
// access specifier.
if (Tok.is(tok::kw_virtual)) {
@@ -1577,6 +1685,8 @@ Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) {
IsVirtual = true;
}
+ CheckMisplacedCXX11Attribute(Attributes, StartLoc);
+
// Parse the class-name.
SourceLocation EndLocation;
SourceLocation BaseLoc;
@@ -1596,8 +1706,9 @@ Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) {
// Notify semantic analysis that we have parsed a complete
// base-specifier.
- return Actions.ActOnBaseSpecifier(ClassDecl, Range, IsVirtual, Access,
- BaseType.get(), BaseLoc, EllipsisLoc);
+ return Actions.ActOnBaseSpecifier(ClassDecl, Range, Attributes, IsVirtual,
+ Access, BaseType.get(), BaseLoc,
+ EllipsisLoc);
}
/// getAccessSpecifierIfPresent - Determine whether the next token is
@@ -1653,13 +1764,13 @@ void Parser::HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo,
}
}
-/// isCXX0XVirtSpecifier - Determine whether the given token is a C++0x
+/// isCXX11VirtSpecifier - Determine whether the given token is a C++11
/// virt-specifier.
///
/// virt-specifier:
/// override
/// final
-VirtSpecifiers::Specifier Parser::isCXX0XVirtSpecifier(const Token &Tok) const {
+VirtSpecifiers::Specifier Parser::isCXX11VirtSpecifier(const Token &Tok) const {
if (!getLangOpts().CPlusPlus)
return VirtSpecifiers::VS_None;
@@ -1682,15 +1793,15 @@ VirtSpecifiers::Specifier Parser::isCXX0XVirtSpecifier(const Token &Tok) const {
return VirtSpecifiers::VS_None;
}
-/// ParseOptionalCXX0XVirtSpecifierSeq - Parse a virt-specifier-seq.
+/// ParseOptionalCXX11VirtSpecifierSeq - Parse a virt-specifier-seq.
///
/// virt-specifier-seq:
/// virt-specifier
/// virt-specifier-seq virt-specifier
-void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS,
+void Parser::ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS,
bool IsInterface) {
while (true) {
- VirtSpecifiers::Specifier Specifier = isCXX0XVirtSpecifier();
+ VirtSpecifiers::Specifier Specifier = isCXX11VirtSpecifier();
if (Specifier == VirtSpecifiers::VS_None)
return;
@@ -1706,7 +1817,7 @@ void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS,
Diag(Tok.getLocation(), diag::err_override_control_interface)
<< VirtSpecifiers::getSpecifierName(Specifier);
} else {
- Diag(Tok.getLocation(), getLangOpts().CPlusPlus0x ?
+ Diag(Tok.getLocation(), getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_override_control_keyword :
diag::ext_override_control_keyword)
<< VirtSpecifiers::getSpecifierName(Specifier);
@@ -1715,9 +1826,9 @@ void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS,
}
}
-/// isCXX0XFinalKeyword - Determine whether the next token is a C++0x
+/// isCXX11FinalKeyword - Determine whether the next token is a C++11
/// contextual 'final' keyword.
-bool Parser::isCXX0XFinalKeyword() const {
+bool Parser::isCXX11FinalKeyword() const {
if (!getLangOpts().CPlusPlus)
return false;
@@ -1861,8 +1972,14 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
ColonProtectionRAIIObject X(*this);
ParsedAttributesWithRange attrs(AttrFactory);
- // Optional C++0x attribute-specifier
- MaybeParseCXX0XAttributes(attrs);
+ ParsedAttributesWithRange FnAttrs(AttrFactory);
+ // Optional C++11 attribute-specifier
+ MaybeParseCXX11Attributes(attrs);
+ // We need to keep these attributes for future diagnostic
+ // before they are taken over by declaration specifier.
+ FnAttrs.addAll(attrs.getList());
+ FnAttrs.Range = attrs.Range;
+
MaybeParseMicrosoftAttributes(attrs);
if (Tok.is(tok::kw_using)) {
@@ -1901,6 +2018,10 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
if (Tok.is(tok::semi)) {
ConsumeToken();
+
+ if (DS.isFriendSpecified())
+ ProhibitAttributes(FnAttrs);
+
Decl *TheDecl =
Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS, TemplateParams);
DS.complete(TheDecl);
@@ -1931,7 +2052,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
return;
}
- ParseOptionalCXX0XVirtSpecifierSeq(VS, getCurrentClass().IsInterface);
+ ParseOptionalCXX11VirtSpecifierSeq(VS, getCurrentClass().IsInterface);
// If attributes exist after the declarator, but before an '{', parse them.
MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs);
@@ -1955,7 +2076,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// In C++11, a non-function declarator followed by an open brace is a
// braced-init-list for an in-class member initialization, not an
// erroneous function definition.
- if (Tok.is(tok::l_brace) && !getLangOpts().CPlusPlus0x) {
+ if (Tok.is(tok::l_brace) && !getLangOpts().CPlusPlus11) {
DefinitionKind = FDK_Definition;
} else if (DeclaratorInfo.isFunctionDeclarator()) {
if (Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) {
@@ -1969,12 +2090,21 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
}
}
+ // C++11 [dcl.attr.grammar] p4: If an attribute-specifier-seq appertains
+ // to a friend declaration, that declaration shall be a definition.
+ if (DeclaratorInfo.isFunctionDeclarator() &&
+ DefinitionKind != FDK_Definition && DS.isFriendSpecified()) {
+ // Diagnose attributes that appear before decl specifier:
+ // [[]] friend int foo();
+ ProhibitAttributes(FnAttrs);
+ }
+
if (DefinitionKind) {
if (!DeclaratorInfo.isFunctionDeclarator()) {
Diag(DeclaratorInfo.getIdentifierLoc(), diag::err_func_def_no_params);
ConsumeBrace();
SkipUntil(tok::r_brace, /*StopAtSemi*/false);
-
+
// Consume the optional ';'
if (Tok.is(tok::semi))
ConsumeToken();
@@ -1984,16 +2114,9 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
Diag(DeclaratorInfo.getIdentifierLoc(),
diag::err_function_declared_typedef);
- // This recovery skips the entire function body. It would be nice
- // to simply call ParseCXXInlineMethodDef() below, however Sema
- // assumes the declarator represents a function, not a typedef.
- ConsumeBrace();
- SkipUntil(tok::r_brace, /*StopAtSemi*/false);
- // Consume the optional ';'
- if (Tok.is(tok::semi))
- ConsumeToken();
- return;
+ // Recover by treating the 'typedef' as spurious.
+ DS.ClearStorageClassSpecs();
}
Decl *FunDecl =
@@ -2052,7 +2175,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// FIXME: When g++ adds support for this, we'll need to check whether it
// goes before or after the GNU attributes and __asm__.
- ParseOptionalCXX0XVirtSpecifierSeq(VS, getCurrentClass().IsInterface);
+ ParseOptionalCXX11VirtSpecifierSeq(VS, getCurrentClass().IsInterface);
InClassInitStyle HasInClassInit = ICIS_NoInit;
if ((Tok.is(tok::equal) || Tok.is(tok::l_brace)) && !HasInitializer) {
@@ -2063,8 +2186,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
HasInitializer = true;
if (!DeclaratorInfo.isDeclarationOfFunction() &&
DeclaratorInfo.getDeclSpec().getStorageClassSpec()
- != DeclSpec::SCS_static &&
- DeclaratorInfo.getDeclSpec().getStorageClassSpec()
!= DeclSpec::SCS_typedef)
HasInClassInit = Tok.is(tok::equal) ? ICIS_CopyInit : ICIS_ListInit;
}
@@ -2074,8 +2195,23 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
// this call will *not* return the created decl; It will return null.
// See Sema::ActOnCXXMemberDeclarator for details.
- Decl *ThisDecl = 0;
+ NamedDecl *ThisDecl = 0;
if (DS.isFriendSpecified()) {
+ // C++11 [dcl.attr.grammar] p4: If an attribute-specifier-seq appertains
+ // to a friend declaration, that declaration shall be a definition.
+ //
+ // Diagnose attributes appear after friend member function declarator:
+ // foo [[]] ();
+ SmallVector<SourceRange, 4> Ranges;
+ DeclaratorInfo.getCXX11AttributeRanges(Ranges);
+ if (!Ranges.empty()) {
+ for (SmallVector<SourceRange, 4>::iterator I = Ranges.begin(),
+ E = Ranges.end(); I != E; ++I) {
+ Diag((*I).getBegin(), diag::err_attributes_not_allowed)
+ << *I;
+ }
+ }
+
// TODO: handle initializers, bitfields, 'delete'
ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo,
TemplateParams);
@@ -2100,9 +2236,11 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
LateParsedAttrs.clear();
// Handle the initializer.
- if (HasInClassInit != ICIS_NoInit) {
+ if (HasInClassInit != ICIS_NoInit &&
+ DeclaratorInfo.getDeclSpec().getStorageClassSpec() !=
+ DeclSpec::SCS_static) {
// The initializer was deferred; parse it and cache the tokens.
- Diag(Tok, getLangOpts().CPlusPlus0x ?
+ Diag(Tok, getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_nonstatic_member_init :
diag::ext_nonstatic_member_init);
@@ -2264,6 +2402,8 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction,
/// access-specifier ':' member-specification[opt]
///
void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
+ SourceLocation AttrFixitLoc,
+ ParsedAttributesWithRange &Attrs,
unsigned TagType, Decl *TagDecl) {
assert((TagType == DeclSpec::TST_struct ||
TagType == DeclSpec::TST_interface ||
@@ -2320,17 +2460,23 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
// Parse the optional 'final' keyword.
if (getLangOpts().CPlusPlus && Tok.is(tok::identifier)) {
- assert(isCXX0XFinalKeyword() && "not a class definition");
+ assert(isCXX11FinalKeyword() && "not a class definition");
FinalLoc = ConsumeToken();
if (TagType == DeclSpec::TST_interface) {
Diag(FinalLoc, diag::err_override_control_interface)
<< "final";
} else {
- Diag(FinalLoc, getLangOpts().CPlusPlus0x ?
+ Diag(FinalLoc, getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_override_control_keyword :
diag::ext_override_control_keyword) << "final";
}
+
+ // Parse any C++11 attributes after 'final' keyword.
+ // These attributes are not allowed to appear here,
+ // and the only possible place for them to appertain
+ // to the class would be between class-key and class-name.
+ CheckMisplacedCXX11Attribute(Attrs, AttrFixitLoc);
}
if (Tok.is(tok::colon)) {
@@ -2395,6 +2541,11 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
continue;
}
+ if (Tok.is(tok::annot_pragma_openmp)) {
+ ParseOpenMPDeclarativeDirective();
+ continue;
+ }
+
AccessSpecifier AS = getAccessSpecifierIfPresent();
if (AS != AS_none) {
// Current token is a C++ access specifier.
@@ -2551,8 +2702,7 @@ void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) {
}
} while (true);
- Actions.ActOnMemInitializers(ConstructorDecl, ColonLoc,
- MemInitializers.data(), MemInitializers.size(),
+ Actions.ActOnMemInitializers(ConstructorDecl, ColonLoc, MemInitializers,
AnyErrors);
}
@@ -2606,7 +2756,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
// Parse the '('.
- if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) {
+ if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
ExprResult InitList = ParseBraceInitializer();
@@ -2645,7 +2795,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
EllipsisLoc);
}
- Diag(Tok, getLangOpts().CPlusPlus0x ? diag::err_expected_lparen_or_lbrace
+ Diag(Tok, getLangOpts().CPlusPlus11 ? diag::err_expected_lparen_or_lbrace
: diag::err_expected_lparen);
return true;
}
@@ -2892,9 +3042,9 @@ IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) {
case tok::exclaimequal: // 'not_eq'
// Alternative tokens do not have identifier info, but their spelling
// starts with an alphabetical character.
- llvm::SmallString<8> SpellingBuf;
+ SmallString<8> SpellingBuf;
StringRef Spelling = PP.getSpelling(Tok.getLocation(), SpellingBuf);
- if (std::isalpha(Spelling[0])) {
+ if (isLetter(Spelling[0])) {
Loc = ConsumeToken();
return &PP.getIdentifierTable().get(Spelling);
}
@@ -2908,7 +3058,7 @@ static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName,
AttributeList::AS_CXX11)) {
case AttributeList::AT_CarriesDependency:
case AttributeList::AT_FallThrough:
- case AttributeList::AT_NoReturn: {
+ case AttributeList::AT_CXX11NoReturn: {
return true;
}
@@ -2971,6 +3121,8 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
ConsumeBracket();
ConsumeBracket();
+ llvm::SmallDenseMap<IdentifierInfo*, SourceLocation, 4> SeenAttrs;
+
while (Tok.isNot(tok::r_square)) {
// attribute not present
if (Tok.is(tok::comma)) {
@@ -3004,6 +3156,11 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
bool StandardAttr = IsBuiltInOrStandardCXX11Attribute(AttrName,ScopeName);
bool AttrParsed = false;
+ if (StandardAttr &&
+ !SeenAttrs.insert(std::make_pair(AttrName, AttrLoc)).second)
+ Diag(AttrLoc, diag::err_cxx11_attribute_repeated)
+ << AttrName << SourceRange(SeenAttrs[AttrName]);
+
// Parse attribute arguments
if (Tok.is(tok::l_paren)) {
if (ScopeName && ScopeName->getName() == "gnu") {
@@ -3050,6 +3207,8 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs,
/// attribute-specifier-seq[opt] attribute-specifier
void Parser::ParseCXX11Attributes(ParsedAttributesWithRange &attrs,
SourceLocation *endLoc) {
+ assert(getLangOpts().CPlusPlus11);
+
SourceLocation StartLoc = Tok.getLocation(), Loc;
if (!endLoc)
endLoc = &Loc;
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index c7be0d3..956ba36 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -22,77 +22,16 @@
//===----------------------------------------------------------------------===//
#include "clang/Parse/Parser.h"
+#include "RAIIObjectsForParser.h"
+#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Sema/DeclSpec.h"
-#include "clang/Sema/Scope.h"
#include "clang/Sema/ParsedTemplate.h"
+#include "clang/Sema/Scope.h"
#include "clang/Sema/TypoCorrection.h"
-#include "clang/Basic/PrettyStackTrace.h"
-#include "RAIIObjectsForParser.h"
-#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
using namespace clang;
-/// \brief Return the precedence of the specified binary operator token.
-static prec::Level getBinOpPrecedence(tok::TokenKind Kind,
- bool GreaterThanIsOperator,
- bool CPlusPlus0x) {
- switch (Kind) {
- case tok::greater:
- // C++ [temp.names]p3:
- // [...] When parsing a template-argument-list, the first
- // non-nested > is taken as the ending delimiter rather than a
- // greater-than operator. [...]
- if (GreaterThanIsOperator)
- return prec::Relational;
- return prec::Unknown;
-
- case tok::greatergreater:
- // C++0x [temp.names]p3:
- //
- // [...] Similarly, the first non-nested >> is treated as two
- // consecutive but distinct > tokens, the first of which is
- // taken as the end of the template-argument-list and completes
- // the template-id. [...]
- if (GreaterThanIsOperator || !CPlusPlus0x)
- return prec::Shift;
- return prec::Unknown;
-
- default: return prec::Unknown;
- case tok::comma: return prec::Comma;
- case tok::equal:
- case tok::starequal:
- case tok::slashequal:
- case tok::percentequal:
- case tok::plusequal:
- case tok::minusequal:
- case tok::lesslessequal:
- case tok::greatergreaterequal:
- case tok::ampequal:
- case tok::caretequal:
- case tok::pipeequal: return prec::Assignment;
- case tok::question: return prec::Conditional;
- case tok::pipepipe: return prec::LogicalOr;
- case tok::ampamp: return prec::LogicalAnd;
- case tok::pipe: return prec::InclusiveOr;
- case tok::caret: return prec::ExclusiveOr;
- case tok::amp: return prec::And;
- case tok::exclaimequal:
- case tok::equalequal: return prec::Equality;
- case tok::lessequal:
- case tok::less:
- case tok::greaterequal: return prec::Relational;
- case tok::lessless: return prec::Shift;
- case tok::plus:
- case tok::minus: return prec::Additive;
- case tok::percent:
- case tok::slash:
- case tok::star: return prec::Multiplicative;
- case tok::periodstar:
- case tok::arrowstar: return prec::PointerToMember;
- }
-}
-
-
/// \brief Simple precedence-based parser for binary/ternary operators.
///
/// Note: we diverge from the C99 grammar when parsing the assignment-expression
@@ -282,7 +221,7 @@ ExprResult
Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
prec::Level NextTokPrec = getBinOpPrecedence(Tok.getKind(),
GreaterThanIsOperator,
- getLangOpts().CPlusPlus0x);
+ getLangOpts().CPlusPlus11);
SourceLocation ColonLoc;
while (1) {
@@ -383,7 +322,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
// they only appear on the RHS of assignments later.
ExprResult RHS;
bool RHSIsInitList = false;
- if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) {
+ if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
RHS = ParseBraceInitializer();
RHSIsInitList = true;
} else if (getLangOpts().CPlusPlus && NextTokPrec <= prec::Conditional)
@@ -398,7 +337,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
// operator immediately to the right of the RHS.
prec::Level ThisPrec = NextTokPrec;
NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator,
- getLangOpts().CPlusPlus0x);
+ getLangOpts().CPlusPlus11);
// Assignment and conditional expressions are right-associative.
bool isRightAssoc = ThisPrec == prec::Conditional ||
@@ -426,7 +365,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
LHS = ExprError();
NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator,
- getLangOpts().CPlusPlus0x);
+ getLangOpts().CPlusPlus11);
}
assert(NextTokPrec <= ThisPrec && "Recursion didn't work!");
@@ -1036,7 +975,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::annot_typename:
if (isStartOfObjCClassMessageMissingOpenBracket()) {
ParsedType Type = getTypeAnnotation(Tok);
-
+
// Fake up a Declarator to use with ActOnTypeName.
DeclSpec DS(AttrFactory);
DS.SetRangeStart(Tok.getLocation());
@@ -1046,7 +985,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
unsigned DiagID;
DS.SetTypeSpecType(TST_typename, Tok.getAnnotationEndLoc(),
PrevSpec, DiagID, Type);
-
+
Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
TypeResult Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
if (Ty.isInvalid())
@@ -1058,7 +997,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
break;
}
// Fall through
-
+
case tok::annot_decltype:
case tok::kw_char:
case tok::kw_wchar_t:
@@ -1078,7 +1017,15 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw_void:
case tok::kw_typename:
case tok::kw_typeof:
- case tok::kw___vector: {
+ case tok::kw___vector:
+ case tok::kw_image1d_t:
+ case tok::kw_image1d_array_t:
+ case tok::kw_image1d_buffer_t:
+ case tok::kw_image2d_t:
+ case tok::kw_image2d_array_t:
+ case tok::kw_image3d_t:
+ case tok::kw_sampler_t:
+ case tok::kw_event_t: {
if (!getLangOpts().CPlusPlus) {
Diag(Tok, diag::err_expected_expression);
return ExprError();
@@ -1097,7 +1044,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
DeclSpec DS(AttrFactory);
ParseCXXSimpleTypeSpecifier(DS);
if (Tok.isNot(tok::l_paren) &&
- (!getLangOpts().CPlusPlus0x || Tok.isNot(tok::l_brace)))
+ (!getLangOpts().CPlusPlus11 || Tok.isNot(tok::l_brace)))
return ExprError(Diag(Tok, diag::err_expected_lparen_after_type)
<< DS.getSourceRange());
@@ -1241,10 +1188,13 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw___is_union:
case tok::kw___is_final:
case tok::kw___has_trivial_constructor:
+ case tok::kw___has_trivial_move_constructor:
case tok::kw___has_trivial_copy:
case tok::kw___has_trivial_assign:
+ case tok::kw___has_trivial_move_assign:
case tok::kw___has_trivial_destructor:
case tok::kw___has_nothrow_assign:
+ case tok::kw___has_nothrow_move_assign:
case tok::kw___has_nothrow_copy:
case tok::kw___has_nothrow_constructor:
case tok::kw___has_virtual_destructor:
@@ -1282,7 +1232,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
return ExprError();
}
case tok::l_square:
- if (getLangOpts().CPlusPlus0x) {
+ if (getLangOpts().CPlusPlus11) {
if (getLangOpts().ObjC1) {
// C++11 lambda expressions and Objective-C message sends both start with a
// square bracket. There are three possibilities here:
@@ -1381,7 +1331,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
T.consumeOpen();
Loc = T.getOpenLocation();
ExprResult Idx;
- if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) {
+ if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
Idx = ParseBraceInitializer();
} else
@@ -1459,7 +1409,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
if (Tok.is(tok::code_completion)) {
Actions.CodeCompleteCall(getCurScope(), LHS.get(),
- llvm::ArrayRef<Expr *>());
+ ArrayRef<Expr *>());
cutOffParsing();
return ExprError();
}
@@ -1663,11 +1613,11 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
/// unary-expression: [C99 6.5.3]
/// 'sizeof' unary-expression
/// 'sizeof' '(' type-name ')'
-/// [C++0x] 'sizeof' '...' '(' identifier ')'
+/// [C++11] 'sizeof' '...' '(' identifier ')'
/// [GNU] '__alignof' unary-expression
/// [GNU] '__alignof' '(' type-name ')'
/// [C11] '_Alignof' '(' type-name ')'
-/// [C++0x] 'alignof' '(' type-id ')'
+/// [C++11] 'alignof' '(' type-id ')'
/// \endverbatim
ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
assert((Tok.is(tok::kw_sizeof) || Tok.is(tok::kw___alignof) ||
@@ -1677,7 +1627,7 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
Token OpTok = Tok;
ConsumeToken();
- // [C++0x] 'sizeof' '...' '(' identifier ')'
+ // [C++11] 'sizeof' '...' '(' identifier ')'
if (Tok.is(tok::ellipsis) && OpTok.is(tok::kw_sizeof)) {
SourceLocation EllipsisLoc = ConsumeToken();
SourceLocation LParenLoc, RParenLoc;
@@ -1748,6 +1698,9 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
CastTy.getAsOpaquePtr(),
CastRange);
+ if (OpTok.is(tok::kw_alignof) || OpTok.is(tok::kw__Alignof))
+ Diag(OpTok, diag::ext_alignof_expr) << OpTok.getIdentifierInfo();
+
// If we get here, the operand to the sizeof/alignof was an expresion.
if (!Operand.isInvalid())
Operand = Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(),
@@ -2008,12 +1961,16 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
Tok.is(tok::kw___bridge_retained) ||
Tok.is(tok::kw___bridge_retain)));
if (BridgeCast && !getLangOpts().ObjCAutoRefCount) {
- StringRef BridgeCastName = Tok.getName();
- SourceLocation BridgeKeywordLoc = ConsumeToken();
- if (!PP.getSourceManager().isInSystemHeader(BridgeKeywordLoc))
- Diag(BridgeKeywordLoc, diag::warn_arc_bridge_cast_nonarc)
- << BridgeCastName
- << FixItHint::CreateReplacement(BridgeKeywordLoc, "");
+ if (Tok.isNot(tok::kw___bridge)) {
+ StringRef BridgeCastName = Tok.getName();
+ SourceLocation BridgeKeywordLoc = ConsumeToken();
+ if (!PP.getSourceManager().isInSystemHeader(BridgeKeywordLoc))
+ Diag(BridgeKeywordLoc, diag::warn_arc_bridge_cast_nonarc)
+ << BridgeCastName
+ << FixItHint::CreateReplacement(BridgeKeywordLoc, "");
+ }
+ else
+ ConsumeToken(); // consume __bridge
BridgeCast = false;
}
@@ -2360,10 +2317,10 @@ ExprResult Parser::ParseGenericSelectionExpression() {
/// [C++0x] braced-init-list
/// \endverbatim
bool Parser::ParseExpressionList(SmallVectorImpl<Expr*> &Exprs,
- SmallVectorImpl<SourceLocation> &CommaLocs,
- void (Sema::*Completer)(Scope *S,
- Expr *Data,
- llvm::ArrayRef<Expr *> Args),
+ SmallVectorImpl<SourceLocation> &CommaLocs,
+ void (Sema::*Completer)(Scope *S,
+ Expr *Data,
+ ArrayRef<Expr *> Args),
Expr *Data) {
while (1) {
if (Tok.is(tok::code_completion)) {
@@ -2376,7 +2333,7 @@ bool Parser::ParseExpressionList(SmallVectorImpl<Expr*> &Exprs,
}
ExprResult Expr;
- if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) {
+ if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
Expr = ParseBraceInitializer();
} else
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 2f615e1..17c4adf 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -11,14 +11,14 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
#include "RAIIObjectsForParser.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/Lex/LiteralSupport.h"
+#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/DeclSpec.h"
-#include "clang/Sema/Scope.h"
#include "clang/Sema/ParsedTemplate.h"
+#include "clang/Sema/Scope.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
@@ -99,7 +99,7 @@ void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType,
/// \brief Emits an error for a left parentheses after a double colon.
///
/// When a '(' is found after a '::', emit an error. Attempt to fix the token
-/// stream by removing the '(', and the matching ')' if it found.
+/// stream by removing the '(', and the matching ')' if found.
void Parser::CheckForLParenAfterColonColon() {
if (!Tok.is(tok::l_paren))
return;
@@ -168,19 +168,26 @@ void Parser::CheckForLParenAfterColonColon() {
/// if we do end up determining that we are parsing a destructor name,
/// the last component of the nested-name-specifier is not parsed as
/// part of the scope specifier.
-
-/// member access expression, e.g., the \p T:: in \p p->T::m.
+///
+/// \param IsTypename If \c true, this nested-name-specifier is known to be
+/// part of a type name. This is used to improve error recovery.
+///
+/// \param LastII When non-NULL, points to an IdentifierInfo* that will be
+/// filled in with the leading identifier in the last component of the
+/// nested-name-specifier, if any.
///
/// \returns true if there was an error parsing a scope specifier
bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
ParsedType ObjectType,
bool EnteringContext,
bool *MayBePseudoDestructor,
- bool IsTypename) {
+ bool IsTypename,
+ IdentifierInfo **LastII) {
assert(getLangOpts().CPlusPlus &&
"Call sites of this function should be guarded by checking for C++");
if (Tok.is(tok::annot_cxxscope)) {
+ assert(!LastII && "want last identifier but have already annotated scope");
Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(),
Tok.getAnnotationRange(),
SS);
@@ -188,6 +195,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
return false;
}
+ if (LastII)
+ *LastII = 0;
+
bool HasScopeSpecifier = false;
if (Tok.is(tok::coloncolon)) {
@@ -334,6 +344,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
return false;
}
+ if (LastII)
+ *LastII = TemplateId->Name;
+
// Consume the template-id token.
ConsumeToken();
@@ -405,6 +418,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
return false;
}
+ if (LastII)
+ *LastII = &II;
+
// We have an identifier followed by a '::'. Lookup this name
// as the name in a nested-name-specifier.
SourceLocation IdLoc = ConsumeToken();
@@ -602,7 +618,7 @@ ExprResult Parser::ParseLambdaExpression() {
// Parse lambda-introducer.
LambdaIntroducer Intro;
- llvm::Optional<unsigned> DiagID(ParseLambdaIntroducer(Intro));
+ Optional<unsigned> DiagID(ParseLambdaIntroducer(Intro));
if (DiagID) {
Diag(Tok, DiagID.getValue());
SkipUntil(tok::r_square);
@@ -620,7 +636,7 @@ ExprResult Parser::ParseLambdaExpression() {
///
/// If we are not looking at a lambda expression, returns ExprError().
ExprResult Parser::TryParseLambdaExpression() {
- assert(getLangOpts().CPlusPlus0x
+ assert(getLangOpts().CPlusPlus11
&& Tok.is(tok::l_square)
&& "Not at the start of a possible lambda expression.");
@@ -658,8 +674,8 @@ ExprResult Parser::TryParseLambdaExpression() {
/// ParseLambdaExpression - Parse a lambda introducer.
///
/// Returns a DiagnosticID if it hit something unexpected.
-llvm::Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro){
- typedef llvm::Optional<unsigned> DiagResult;
+Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro) {
+ typedef Optional<unsigned> DiagResult;
assert(Tok.is(tok::l_square) && "Lambda expressions begin with '['.");
BalancedDelimiterTracker T(*this, tok::l_square);
@@ -769,7 +785,7 @@ llvm::Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro){
bool Parser::TryParseLambdaIntroducer(LambdaIntroducer &Intro) {
TentativeParsingAction PA(*this);
- llvm::Optional<unsigned> DiagID(ParseLambdaIntroducer(Intro));
+ Optional<unsigned> DiagID(ParseLambdaIntroducer(Intro));
if (DiagID) {
PA.Revert();
@@ -797,6 +813,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
if (Tok.is(tok::l_paren)) {
ParseScope PrototypeScope(this,
Scope::FunctionPrototypeScope |
+ Scope::FunctionDeclarationScope |
Scope::DeclScope);
SourceLocation DeclEndLoc;
@@ -806,7 +823,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
// Parse parameter-declaration-clause.
ParsedAttributes Attr(AttrFactory);
- llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
+ SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
SourceLocation EllipsisLoc;
if (Tok.isNot(tok::r_paren))
@@ -826,8 +843,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
// Parse exception-specification[opt].
ExceptionSpecificationType ESpecType = EST_None;
SourceRange ESpecRange;
- llvm::SmallVector<ParsedType, 2> DynamicExceptions;
- llvm::SmallVector<SourceRange, 2> DynamicExceptionRanges;
+ SmallVector<ParsedType, 2> DynamicExceptions;
+ SmallVector<SourceRange, 2> DynamicExceptionRanges;
ExprResult NoexceptExpr;
ESpecType = tryParseExceptionSpecification(ESpecRange,
DynamicExceptions,
@@ -838,7 +855,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
DeclEndLoc = ESpecRange.getEnd();
// Parse attribute-specifier[opt].
- MaybeParseCXX0XAttributes(Attr, &DeclEndLoc);
+ MaybeParseCXX11Attributes(Attr, &DeclEndLoc);
SourceLocation FunLocalRangeEnd = DeclEndLoc;
@@ -1288,7 +1305,7 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
ParsedType TypeRep = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get();
assert((Tok.is(tok::l_paren) ||
- (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)))
+ (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)))
&& "Expected '(' or '{'!");
if (Tok.is(tok::l_brace)) {
@@ -1362,7 +1379,7 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut,
}
ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
if (!isCXXConditionDeclaration()) {
ProhibitAttributes(attrs);
@@ -1382,6 +1399,7 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut,
// type-specifier-seq
DeclSpec DS(AttrFactory);
+ DS.takeAttributesFrom(attrs);
ParseSpecifierQualifierList(DS);
// declarator
@@ -1416,7 +1434,7 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut,
ConsumeToken();
ExprResult InitExpr = ExprError();
- if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace)) {
+ if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
Diag(Tok.getLocation(),
diag::warn_cxx98_compat_generalized_initializer_lists);
InitExpr = ParseBraceInitializer();
@@ -1851,7 +1869,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
SymbolLocations[SymbolIdx++] = ConsumeToken();
// Check for array new/delete.
if (Tok.is(tok::l_square) &&
- (!getLangOpts().CPlusPlus0x || NextToken().isNot(tok::l_square))) {
+ (!getLangOpts().CPlusPlus11 || NextToken().isNot(tok::l_square))) {
// Consume the '[' and ']'.
BalancedDelimiterTracker T(*this, tok::l_square);
T.consumeOpen();
@@ -1928,7 +1946,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
// operator string-literal identifier
// operator user-defined-string-literal
- if (getLangOpts().CPlusPlus0x && isTokenStringLiteral()) {
+ if (getLangOpts().CPlusPlus11 && isTokenStringLiteral()) {
Diag(Tok.getLocation(), diag::warn_cxx98_compat_literal_operator);
SourceLocation DiagLoc;
@@ -1936,8 +1954,8 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
// We're past translation phase 6, so perform string literal concatenation
// before checking for "".
- llvm::SmallVector<Token, 4> Toks;
- llvm::SmallVector<SourceLocation, 4> TokLocs;
+ SmallVector<Token, 4> Toks;
+ SmallVector<SourceLocation, 4> TokLocs;
while (isTokenStringLiteral()) {
if (!Tok.is(tok::string_literal) && !DiagId) {
// C++11 [over.literal]p1:
@@ -1986,7 +2004,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
if (DiagId) {
// This isn't a valid literal-operator-id, but we think we know
// what the user meant. Tell them what they should have written.
- llvm::SmallString<32> Str;
+ SmallString<32> Str;
Str += "\"\" ";
Str += II->getName();
Diag(DiagLoc, DiagId) << FixItHint::CreateReplacement(
@@ -2361,7 +2379,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
Initializer = Actions.ActOnParenListExpr(ConstructorLParen,
ConstructorRParen,
ConstructorArgs);
- } else if (Tok.is(tok::l_brace) && getLangOpts().CPlusPlus0x) {
+ } else if (Tok.is(tok::l_brace) && getLangOpts().CPlusPlus11) {
Diag(Tok.getLocation(),
diag::warn_cxx98_compat_generalized_initializer_lists);
Initializer = ParseBraceInitializer();
@@ -2405,7 +2423,7 @@ void Parser::ParseDirectNewDeclarator(Declarator &D) {
// Attributes here appertain to the array type. C++11 [expr.new]p5.
ParsedAttributes Attrs(AttrFactory);
- MaybeParseCXX0XAttributes(Attrs);
+ MaybeParseCXX11Attributes(Attrs);
D.AddTypeInfo(DeclaratorChunk::getArray(0,
/*static=*/false, /*star=*/false,
@@ -2493,11 +2511,15 @@ static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) {
switch(kind) {
default: llvm_unreachable("Not a known unary type trait.");
case tok::kw___has_nothrow_assign: return UTT_HasNothrowAssign;
+ case tok::kw___has_nothrow_move_assign: return UTT_HasNothrowMoveAssign;
case tok::kw___has_nothrow_constructor: return UTT_HasNothrowConstructor;
case tok::kw___has_nothrow_copy: return UTT_HasNothrowCopy;
case tok::kw___has_trivial_assign: return UTT_HasTrivialAssign;
+ case tok::kw___has_trivial_move_assign: return UTT_HasTrivialMoveAssign;
case tok::kw___has_trivial_constructor:
return UTT_HasTrivialDefaultConstructor;
+ case tok::kw___has_trivial_move_constructor:
+ return UTT_HasTrivialMoveConstructor;
case tok::kw___has_trivial_copy: return UTT_HasTrivialCopy;
case tok::kw___has_trivial_destructor: return UTT_HasTrivialDestructor;
case tok::kw___has_virtual_destructor: return UTT_HasVirtualDestructor;
@@ -2659,7 +2681,7 @@ ExprResult Parser::ParseTypeTrait() {
if (Parens.expectAndConsume(diag::err_expected_lparen))
return ExprError();
- llvm::SmallVector<ParsedType, 2> Args;
+ SmallVector<ParsedType, 2> Args;
do {
// Parse the next type.
TypeResult Ty = ParseTypeName();
diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp
index e47fd9b..3b96717 100644
--- a/lib/Parse/ParseInit.cpp
+++ b/lib/Parse/ParseInit.cpp
@@ -12,8 +12,8 @@
//===----------------------------------------------------------------------===//
#include "clang/Parse/Parser.h"
-#include "clang/Parse/ParseDiagnostic.h"
#include "RAIIObjectsForParser.h"
+#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/Designator.h"
#include "clang/Sema/Scope.h"
#include "llvm/ADT/SmallString.h"
@@ -33,7 +33,7 @@ bool Parser::MayBeDesignationStart() {
return true;
case tok::l_square: { // designator: array-designator
- if (!PP.getLangOpts().CPlusPlus0x)
+ if (!PP.getLangOpts().CPlusPlus11)
return true;
// C++11 lambda expressions and C99 designators can be ambiguous all the
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index d321baf..ad95dd5 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -11,9 +11,10 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
#include "RAIIObjectsForParser.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/PrettyDeclStackTrace.h"
#include "clang/Sema/Scope.h"
@@ -21,6 +22,18 @@
#include "llvm/ADT/StringExtras.h"
using namespace clang;
+/// Skips attributes after an Objective-C @ directive. Emits a diagnostic.
+void Parser::MaybeSkipAttributes(tok::ObjCKeywordKind Kind) {
+ ParsedAttributes attrs(AttrFactory);
+ if (Tok.is(tok::kw___attribute)) {
+ if (Kind == tok::objc_interface || Kind == tok::objc_protocol)
+ Diag(Tok, diag::err_objc_postfix_attribute_hint)
+ << (Kind == tok::objc_protocol);
+ else
+ Diag(Tok, diag::err_objc_postfix_attribute);
+ ParseGNUAttributes(attrs);
+ }
+}
/// ParseObjCAtDirectives - Handle parts of the external-declaration production:
/// external-declaration: [C99 6.9]
@@ -65,7 +78,7 @@ Parser::DeclGroupPtrTy Parser::ParseObjCAtDirectives() {
case tok::objc_dynamic:
SingleDecl = ParseObjCPropertyDynamic(AtLoc);
break;
- case tok::objc___experimental_modules_import:
+ case tok::objc_import:
if (getLangOpts().Modules)
return ParseModuleImport(AtLoc);
@@ -92,6 +105,7 @@ Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) {
while (1) {
+ MaybeSkipAttributes(tok::objc_class);
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident);
SkipUntil(tok::semi);
@@ -178,6 +192,8 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
return 0;
}
+ MaybeSkipAttributes(tok::objc_interface);
+
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident); // missing class or category name.
return 0;
@@ -690,7 +706,7 @@ IdentifierInfo *Parser::ParseObjCSelectorPiece(SourceLocation &SelectorLoc) {
case tok::caret:
case tok::caretequal: {
std::string ThisTok(PP.getSpelling(Tok));
- if (isalpha(ThisTok[0])) {
+ if (isLetter(ThisTok[0])) {
IdentifierInfo *II = &PP.getIdentifierTable().get(ThisTok.data());
Tok.setKind(tok::identifier);
SelectorLoc = ConsumeToken();
@@ -1028,8 +1044,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
SmallVector<IdentifierInfo *, 12> KeyIdents;
SmallVector<SourceLocation, 12> KeyLocs;
SmallVector<Sema::ObjCArgInfo, 12> ArgInfos;
- ParseScope PrototypeScope(this,
- Scope::FunctionPrototypeScope|Scope::DeclScope);
+ ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope |
+ Scope::FunctionDeclarationScope | Scope::DeclScope);
AttributePool allParamAttrs(AttrFactory);
while (1) {
@@ -1200,12 +1216,8 @@ ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
}
// Consume the '>'.
- if (Tok.isNot(tok::greater)) {
- Diag(Tok, diag::err_expected_greater);
+ if (ParseGreaterThanInTemplateList(EndLoc, /*ConsumeLastToken=*/true))
return true;
- }
-
- EndLoc = ConsumeToken();
// Convert the list of protocols identifiers into a list of protocol decls.
Actions.FindProtocolDeclaration(WarnOnDeclarations,
@@ -1231,6 +1243,22 @@ bool Parser::ParseObjCProtocolQualifiers(DeclSpec &DS) {
return Result;
}
+void Parser::HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc,
+ BalancedDelimiterTracker &T,
+ SmallVectorImpl<Decl *> &AllIvarDecls,
+ bool RBraceMissing) {
+ if (!RBraceMissing)
+ T.consumeClose();
+
+ Actions.ActOnObjCContainerStartDefinition(interfaceDecl);
+ Actions.ActOnLastBitfield(T.getCloseLocation(), AllIvarDecls);
+ Actions.ActOnObjCContainerFinishDefinition();
+ // Call ActOnFields() even if we don't have any decls. This is useful
+ // for code rewriting tools that need to be aware of the empty list.
+ Actions.ActOnFields(getCurScope(), atLoc, interfaceDecl,
+ AllIvarDecls,
+ T.getOpenLocation(), T.getCloseLocation(), 0);
+}
/// objc-class-instance-variables:
/// '{' objc-instance-variable-decl-list[opt] '}'
@@ -1263,7 +1291,6 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl,
BalancedDelimiterTracker T(*this, tok::l_brace);
T.consumeOpen();
-
// While we still have something to read, read the instance variables.
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
// Each iteration of this loop reads one objc-instance-variable-decl.
@@ -1291,6 +1318,17 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl,
visibility = Tok.getObjCKeywordID();
ConsumeToken();
continue;
+
+ case tok::objc_end:
+ Diag(Tok, diag::err_objc_unexpected_atend);
+ Tok.setLocation(Tok.getLocation().getLocWithOffset(-1));
+ Tok.setKind(tok::at);
+ Tok.setLength(1);
+ PP.EnterToken(Tok);
+ HelperActionsForIvarDeclarations(interfaceDecl, atLoc,
+ T, AllIvarDecls, true);
+ return;
+
default:
Diag(Tok, diag::err_objc_illegal_visibility_spec);
continue;
@@ -1340,16 +1378,8 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl,
SkipUntil(tok::r_brace, true, true);
}
}
- T.consumeClose();
-
- Actions.ActOnObjCContainerStartDefinition(interfaceDecl);
- Actions.ActOnLastBitfield(T.getCloseLocation(), AllIvarDecls);
- Actions.ActOnObjCContainerFinishDefinition();
- // Call ActOnFields() even if we don't have any decls. This is useful
- // for code rewriting tools that need to be aware of the empty list.
- Actions.ActOnFields(getCurScope(), atLoc, interfaceDecl,
- AllIvarDecls,
- T.getOpenLocation(), T.getCloseLocation(), 0);
+ HelperActionsForIvarDeclarations(interfaceDecl, atLoc,
+ T, AllIvarDecls, false);
return;
}
@@ -1382,6 +1412,8 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
return DeclGroupPtrTy();
}
+ MaybeSkipAttributes(tok::objc_protocol);
+
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident); // missing protocol name.
return DeclGroupPtrTy();
@@ -1473,6 +1505,8 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) {
return DeclGroupPtrTy();
}
+ MaybeSkipAttributes(tok::objc_implementation);
+
if (Tok.isNot(tok::identifier)) {
Diag(Tok, diag::err_expected_ident); // missing class or category name.
return DeclGroupPtrTy();
@@ -1540,7 +1574,7 @@ Parser::ParseObjCAtImplementationDeclaration(SourceLocation AtLoc) {
ObjCImplParsingDataRAII ObjCImplParsing(*this, ObjCImpDecl);
while (!ObjCImplParsing.isFinished() && Tok.isNot(tok::eof)) {
ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
MaybeParseMicrosoftAttributes(attrs);
if (DeclGroupPtrTy DGP = ParseExternalDeclaration(attrs)) {
DeclGroupRef DG = DGP.get();
@@ -2040,7 +2074,7 @@ StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) {
// Otherwise, eat the semicolon.
ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
- return Actions.ActOnExprStmt(Actions.MakeFullExpr(Res.take()));
+ return Actions.ActOnExprStmt(Res);
}
ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) {
@@ -2423,7 +2457,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
// Parse objc-selector
SourceLocation Loc;
IdentifierInfo *selIdent = ParseObjCSelectorPiece(Loc);
-
+
SmallVector<IdentifierInfo *, 12> KeyIdents;
SmallVector<SourceLocation, 12> KeyLocs;
ExprVector KeyExprs;
@@ -2547,7 +2581,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
SkipUntil(tok::r_square);
return ExprError();
}
-
+
SourceLocation RBracLoc = ConsumeBracket(); // consume ']'
unsigned nKeys = KeyIdents.size();
@@ -2593,8 +2627,8 @@ ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) {
AtStrings.push_back(Lit.release());
}
- return Owned(Actions.ParseObjCStringLiteral(&AtLocs[0], AtStrings.data(),
- AtStrings.size()));
+ return Actions.ParseObjCStringLiteral(&AtLocs[0], AtStrings.data(),
+ AtStrings.size());
}
/// ParseObjCBooleanLiteral -
@@ -2617,7 +2651,7 @@ ExprResult Parser::ParseObjCCharacterLiteral(SourceLocation AtLoc) {
return Lit;
}
ConsumeToken(); // Consume the literal token.
- return Owned(Actions.BuildObjCNumericLiteral(AtLoc, Lit.take()));
+ return Actions.BuildObjCNumericLiteral(AtLoc, Lit.take());
}
/// ParseObjCNumericLiteral -
@@ -2631,7 +2665,7 @@ ExprResult Parser::ParseObjCNumericLiteral(SourceLocation AtLoc) {
return Lit;
}
ConsumeToken(); // Consume the literal token.
- return Owned(Actions.BuildObjCNumericLiteral(AtLoc, Lit.take()));
+ return Actions.BuildObjCNumericLiteral(AtLoc, Lit.take());
}
/// ParseObjCBoxedExpr -
@@ -2655,8 +2689,8 @@ Parser::ParseObjCBoxedExpr(SourceLocation AtLoc) {
// a boxed expression from a literal.
SourceLocation LPLoc = T.getOpenLocation(), RPLoc = T.getCloseLocation();
ValueExpr = Actions.ActOnParenExpr(LPLoc, RPLoc, ValueExpr.take());
- return Owned(Actions.BuildObjCBoxedExpr(SourceRange(AtLoc, RPLoc),
- ValueExpr.take()));
+ return Actions.BuildObjCBoxedExpr(SourceRange(AtLoc, RPLoc),
+ ValueExpr.take());
}
ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) {
@@ -2689,7 +2723,7 @@ ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) {
}
SourceLocation EndLoc = ConsumeBracket(); // location of ']'
MultiExprArg Args(ElementExprs);
- return Owned(Actions.BuildObjCArrayLiteral(SourceRange(AtLoc, EndLoc), Args));
+ return Actions.BuildObjCArrayLiteral(SourceRange(AtLoc, EndLoc), Args);
}
ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
@@ -2733,7 +2767,7 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
// We have a valid expression. Collect it in a vector so we can
// build the argument list.
ObjCDictionaryElement Element = {
- KeyExpr.get(), ValueExpr.get(), EllipsisLoc, llvm::Optional<unsigned>()
+ KeyExpr.get(), ValueExpr.get(), EllipsisLoc, None
};
Elements.push_back(Element);
@@ -2745,9 +2779,8 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) {
SourceLocation EndLoc = ConsumeBrace();
// Create the ObjCDictionaryLiteral.
- return Owned(Actions.BuildObjCDictionaryLiteral(SourceRange(AtLoc, EndLoc),
- Elements.data(),
- Elements.size()));
+ return Actions.BuildObjCDictionaryLiteral(SourceRange(AtLoc, EndLoc),
+ Elements.data(), Elements.size());
}
/// objc-encode-expression:
@@ -2771,9 +2804,8 @@ Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) {
if (Ty.isInvalid())
return ExprError();
- return Owned(Actions.ParseObjCEncodeExpression(AtLoc, EncLoc,
- T.getOpenLocation(), Ty.get(),
- T.getCloseLocation()));
+ return Actions.ParseObjCEncodeExpression(AtLoc, EncLoc, T.getOpenLocation(),
+ Ty.get(), T.getCloseLocation());
}
/// objc-protocol-expression
@@ -2796,10 +2828,9 @@ Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) {
T.consumeClose();
- return Owned(Actions.ParseObjCProtocolExpression(protocolId, AtLoc, ProtoLoc,
- T.getOpenLocation(),
- ProtoIdLoc,
- T.getCloseLocation()));
+ return Actions.ParseObjCProtocolExpression(protocolId, AtLoc, ProtoLoc,
+ T.getOpenLocation(), ProtoIdLoc,
+ T.getCloseLocation());
}
/// objc-selector-expression
@@ -2860,9 +2891,9 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
}
T.consumeClose();
Selector Sel = PP.getSelectorTable().getSelector(nColons, &KeyIdents[0]);
- return Owned(Actions.ParseObjCSelectorExpression(Sel, AtLoc, SelectorLoc,
- T.getOpenLocation(),
- T.getCloseLocation()));
+ return Actions.ParseObjCSelectorExpression(Sel, AtLoc, SelectorLoc,
+ T.getOpenLocation(),
+ T.getCloseLocation());
}
void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
@@ -2884,7 +2915,7 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
PP.EnterTokenStream(LM.Toks.data(), LM.Toks.size(), true, false);
// Consume the previously pushed token.
- ConsumeAnyToken();
+ ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
assert((Tok.is(tok::l_brace) || Tok.is(tok::kw_try) ||
Tok.is(tok::colon)) &&
diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp
new file mode 100644
index 0000000..507a6b1
--- /dev/null
+++ b/lib/Parse/ParseOpenMP.cpp
@@ -0,0 +1,118 @@
+//===--- ParseOpenMP.cpp - OpenMP directives parsing ----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// \brief This file implements parsing of all OpenMP directives and clauses.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/ParseDiagnostic.h"
+#include "RAIIObjectsForParser.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// OpenMP declarative directives.
+//===----------------------------------------------------------------------===//
+
+/// \brief Parses OpenMP declarative directive
+/// threadprivate-directive
+/// annot_pragma_openmp threadprivate simple-variable-list
+///
+Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
+ assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
+
+ SourceLocation Loc = ConsumeToken();
+ SmallVector<DeclarationNameInfo, 5> Identifiers;
+ OpenMPDirectiveKind Kind = Tok.isAnnotation() ?
+ OMPD_unknown :
+ getOpenMPDirectiveKind(PP.getSpelling(Tok));
+ switch(Kind) {
+ case OMPD_threadprivate:
+ ConsumeToken();
+ if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers)) {
+ // The last seen token is annot_pragma_openmp_end - need to check for
+ // extra tokens.
+ if (Tok.isNot(tok::annot_pragma_openmp_end)) {
+ Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
+ << getOpenMPDirectiveName(OMPD_threadprivate);
+ SkipUntil(tok::annot_pragma_openmp_end, false, true);
+ }
+ ConsumeToken();
+ return Actions.ActOnOpenMPThreadprivateDirective(Loc,
+ getCurScope(),
+ Identifiers);
+ }
+ break;
+ case OMPD_unknown:
+ Diag(Tok, diag::err_omp_unknown_directive);
+ break;
+ default:
+ Diag(Tok, diag::err_omp_unexpected_directive)
+ << getOpenMPDirectiveName(Kind);
+ break;
+ }
+ SkipUntil(tok::annot_pragma_openmp_end, false);
+ return DeclGroupPtrTy();
+}
+
+/// \brief Parses list of simple variables for '#pragma omp threadprivate'
+/// directive
+/// simple-variable-list:
+/// ( unqualified-id {, unqualified-id} ) annot_pragma_openmp_end
+///
+bool Parser::ParseOpenMPSimpleVarList(
+ OpenMPDirectiveKind Kind,
+ SmallVectorImpl<DeclarationNameInfo> &IdList) {
+ // Parse '('.
+ bool IsCorrect = true;
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ if (T.expectAndConsume(diag::err_expected_lparen_after,
+ getOpenMPDirectiveName(Kind))) {
+ SkipUntil(tok::annot_pragma_openmp_end, false, true);
+ return false;
+ }
+
+ // Read tokens while ')' or annot_pragma_openmp_end is not found.
+ do {
+ CXXScopeSpec SS;
+ SourceLocation TemplateKWLoc;
+ UnqualifiedId Name;
+ // Read var name.
+ Token PrevTok = Tok;
+
+ if (ParseUnqualifiedId(SS, false, false, false, ParsedType(),
+ TemplateKWLoc, Name)) {
+ IsCorrect = false;
+ SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
+ false, true);
+ }
+ else if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren) &&
+ Tok.isNot(tok::annot_pragma_openmp_end)) {
+ IsCorrect = false;
+ SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
+ false, true);
+ Diag(PrevTok.getLocation(), diag::err_expected_unqualified_id)
+ << getLangOpts().CPlusPlus
+ << SourceRange(PrevTok.getLocation(), PrevTokLocation);
+ } else {
+ IdList.push_back(Actions.GetNameFromUnqualifiedId(Name));
+ }
+ // Consume ','.
+ if (Tok.is(tok::comma)) {
+ ConsumeToken();
+ }
+ } while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end));
+
+ if (IsCorrect || Tok.is(tok::r_paren)) {
+ IsCorrect = !T.consumeClose() && IsCorrect;
+ }
+
+ return !IsCorrect && IdList.empty();
+}
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index a7605f0..dc6b3ed 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -12,9 +12,9 @@
//===----------------------------------------------------------------------===//
#include "ParsePragma.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
-#include "clang/Lex/Preprocessor.h"
using namespace clang;
/// \brief Handle the annotation token produced for #pragma unused(...)
@@ -718,3 +718,47 @@ PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP,
/*OwnsTokens=*/false);
}
+/// \brief Handle '#pragma omp ...' when OpenMP is disabled.
+///
+void
+PragmaNoOpenMPHandler::HandlePragma(Preprocessor &PP,
+ PragmaIntroducerKind Introducer,
+ Token &FirstTok) {
+ if (PP.getDiagnostics().getDiagnosticLevel(diag::warn_pragma_omp_ignored,
+ FirstTok.getLocation()) !=
+ DiagnosticsEngine::Ignored) {
+ PP.Diag(FirstTok, diag::warn_pragma_omp_ignored);
+ PP.getDiagnostics().setDiagnosticMapping(diag::warn_pragma_omp_ignored,
+ diag::MAP_IGNORE,
+ SourceLocation());
+ }
+ PP.DiscardUntilEndOfDirective();
+}
+
+/// \brief Handle '#pragma omp ...' when OpenMP is enabled.
+///
+void
+PragmaOpenMPHandler::HandlePragma(Preprocessor &PP,
+ PragmaIntroducerKind Introducer,
+ Token &FirstTok) {
+ SmallVector<Token, 16> Pragma;
+ Token Tok;
+ Tok.startToken();
+ Tok.setKind(tok::annot_pragma_openmp);
+ Tok.setLocation(FirstTok.getLocation());
+
+ while (Tok.isNot(tok::eod)) {
+ Pragma.push_back(Tok);
+ PP.Lex(Tok);
+ }
+ SourceLocation EodLoc = Tok.getLocation();
+ Tok.startToken();
+ Tok.setKind(tok::annot_pragma_openmp_end);
+ Tok.setLocation(EodLoc);
+ Pragma.push_back(Tok);
+
+ Token *Toks = new Token[Pragma.size()];
+ std::copy(Pragma.begin(), Pragma.end(), Toks);
+ PP.EnterTokenStream(Toks, Pragma.size(),
+ /*DisableMacroExpansion=*/true, /*OwnsTokens=*/true);
+}
diff --git a/lib/Parse/ParsePragma.h b/lib/Parse/ParsePragma.h
index b9a2a25..841a60b 100644
--- a/lib/Parse/ParsePragma.h
+++ b/lib/Parse/ParsePragma.h
@@ -98,7 +98,20 @@ public:
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken);
};
-
+
+class PragmaNoOpenMPHandler : public PragmaHandler {
+public:
+ PragmaNoOpenMPHandler() : PragmaHandler("omp") { }
+ virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken);
+};
+
+class PragmaOpenMPHandler : public PragmaHandler {
+public:
+ PragmaOpenMPHandler() : PragmaHandler("omp") { }
+ virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+ Token &FirstToken);
+};
} // end namespace clang
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 5883115..355f369 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -14,13 +14,13 @@
#include "clang/Parse/Parser.h"
#include "RAIIObjectsForParser.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/PrettyStackTrace.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/PrettyDeclStackTrace.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/TypoCorrection.h"
-#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/PrettyStackTrace.h"
-#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
using namespace clang;
@@ -84,7 +84,7 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement,
ParenBraceBracketBalancer BalancerRAIIObj(*this);
ParsedAttributesWithRange Attrs(AttrFactory);
- MaybeParseCXX0XAttributes(Attrs, 0, /*MightBeObjCMessageSend*/ true);
+ MaybeParseCXX11Attributes(Attrs, 0, /*MightBeObjCMessageSend*/ true);
StmtResult Res = ParseStatementOrDeclarationAfterAttributes(Stmts,
OnlyStatement, TrailingElseLoc, Attrs);
@@ -288,6 +288,11 @@ Retry:
ProhibitAttributes(Attrs);
HandlePragmaOpenCLExtension();
return StmtEmpty();
+
+ case tok::annot_pragma_openmp:
+ SourceLocation DeclStart = Tok.getLocation();
+ DeclGroupPtrTy Res = ParseOpenMPDeclarativeDirective();
+ return Actions.ActOnDeclStmt(Res, DeclStart, Tok.getLocation());
}
// If we reached this code, the statement must end in a semicolon.
@@ -319,7 +324,7 @@ StmtResult Parser::ParseExprStatement() {
SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true);
if (Tok.is(tok::semi))
ConsumeToken();
- return StmtError();
+ return Actions.ActOnExprStmtError();
}
if (Tok.is(tok::colon) && getCurScope()->isSwitchScope() &&
@@ -335,7 +340,7 @@ StmtResult Parser::ParseExprStatement() {
// Otherwise, eat the semicolon.
ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
- return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr.get()));
+ return Actions.ActOnExprStmt(Expr);
}
StmtResult Parser::ParseSEHTryBlock() {
@@ -830,7 +835,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
ConsumeToken();
ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs, 0, /*MightBeObjCMessageSend*/ true);
+ MaybeParseCXX11Attributes(attrs, 0, /*MightBeObjCMessageSend*/ true);
// If this is the start of a declaration, parse it as such.
if (isDeclarationStatement()) {
@@ -856,7 +861,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
// Eat the semicolon at the end of stmt and convert the expr into a
// statement.
ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
- R = Actions.ActOnExprStmt(Actions.MakeFullExpr(Res.get()));
+ R = Actions.ActOnExprStmt(Res);
}
}
@@ -867,15 +872,10 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
SourceLocation CloseLoc = Tok.getLocation();
// We broke out of the while loop because we found a '}' or EOF.
- if (Tok.isNot(tok::r_brace)) {
- Diag(Tok, diag::err_expected_rbrace);
- Diag(T.getOpenLocation(), diag::note_matching) << "{";
+ if (!T.consumeClose())
// Recover by creating a compound statement with what we parsed so far,
// instead of dropping everything and returning StmtError();
- } else {
- if (!T.consumeClose())
- CloseLoc = T.getCloseLocation();
- }
+ CloseLoc = T.getCloseLocation();
return Actions.ActOnCompoundStmt(T.getOpenLocation(), CloseLoc,
Stmts, isStmtExpr);
@@ -1047,11 +1047,6 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
IfScope.Exit();
- // If the condition was invalid, discard the if statement. We could recover
- // better by replacing it with a valid expr, but don't do that yet.
- if (CondExp.isInvalid() && !CondVar)
- return StmtError();
-
// If the then or else stmt is invalid and the other is valid (and present),
// make turn the invalid one into a null stmt to avoid dropping the other
// part. If both are invalid, return error.
@@ -1290,7 +1285,7 @@ StmtResult Parser::ParseDoStatement() {
// FIXME: Do not just parse the attribute contents and throw them away
ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
ProhibitAttributes(attrs);
ExprResult Cond = ParseExpression();
@@ -1383,7 +1378,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
}
ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
// Parse the first part of the for specifier.
if (Tok.is(tok::semi)) { // for (;
@@ -1395,9 +1390,6 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
if (!C99orCXXorObjC) // Use of C99-style for loops in C90 mode?
Diag(Tok, diag::ext_c99_variable_decl_in_for_loop);
- ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
-
// In C++0x, "for (T NS:a" might not be a typo for ::
bool MightBeForRangeStmt = getLangOpts().CPlusPlus;
ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt);
@@ -1411,7 +1403,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
if (ForRangeInit.ParsedForRangeDecl()) {
- Diag(ForRangeInit.ColonLoc, getLangOpts().CPlusPlus0x ?
+ Diag(ForRangeInit.ColonLoc, getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_for_range : diag::ext_for_range);
ForRange = true;
@@ -1442,7 +1434,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
if (ForEach)
FirstPart = Actions.ActOnForEachLValueExpr(Value.get());
else
- FirstPart = Actions.ActOnExprStmt(Actions.MakeFullExpr(Value.get()));
+ FirstPart = Actions.ActOnExprStmt(Value);
}
if (Tok.is(tok::semi)) {
@@ -1456,7 +1448,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
return StmtError();
}
Collection = ParseExpression();
- } else if (getLangOpts().CPlusPlus0x && Tok.is(tok::colon) && FirstPart.get()) {
+ } else if (getLangOpts().CPlusPlus11 && Tok.is(tok::colon) && FirstPart.get()) {
// User tried to write the reasonable, but ill-formed, for-range-statement
// for (expr : expr) { ... }
Diag(Tok, diag::err_for_range_expected_decl)
@@ -1510,7 +1502,9 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
// Parse the third part of the for specifier.
if (Tok.isNot(tok::r_paren)) { // for (...;...;)
ExprResult Third = ParseExpression();
- ThirdPart = Actions.MakeFullExpr(Third.take());
+ // FIXME: The C++11 standard doesn't actually say that this is a
+ // discarded-value expression, but it clearly should be.
+ ThirdPart = Actions.MakeFullDiscardedValueExpr(Third.take());
}
}
// Match the ')'.
@@ -1652,7 +1646,7 @@ StmtResult Parser::ParseReturnStatement() {
if (Tok.is(tok::l_brace) && getLangOpts().CPlusPlus) {
R = ParseInitializer();
if (R.isUsable())
- Diag(R.get()->getLocStart(), getLangOpts().CPlusPlus0x ?
+ Diag(R.get()->getLocStart(), getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_generalized_initializer_lists :
diag::ext_generalized_initializer_lists)
<< R.get()->getSourceRange();
@@ -1682,9 +1676,6 @@ StmtResult Parser::ParseReturnStatement() {
/// ms-asm-line '\n' ms-asm-instruction-block
///
StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
- // MS-style inline assembly is not fully supported, so emit a warning.
- Diag(AsmLoc, diag::warn_unsupported_msasm);
-
SourceManager &SrcMgr = PP.getSourceManager();
SourceLocation EndLoc = AsmLoc;
SmallVector<Token, 4> AsmToks;
@@ -1777,21 +1768,6 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) {
return StmtError();
}
- // If MS-style inline assembly is disabled, then build an empty asm.
- if (!getLangOpts().EmitMicrosoftInlineAsm) {
- Token t;
- t.setKind(tok::string_literal);
- t.setLiteralData("\"/*FIXME: not done*/\"");
- t.clearFlag(Token::NeedsCleaning);
- t.setLength(21);
- ExprResult AsmString(Actions.ActOnStringLiteral(&t, 1));
- ExprVector Constraints;
- ExprVector Exprs;
- ExprVector Clobbers;
- return Actions.ActOnGCCAsmStmt(AsmLoc, true, true, 0, 0, 0, Constraints,
- Exprs, AsmString.take(), Clobbers, EndLoc);
- }
-
// FIXME: We should be passing source locations for better diagnostics.
return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLoc,
llvm::makeArrayRef(AsmToks), EndLoc);
@@ -1820,7 +1796,7 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) {
assert(Tok.is(tok::kw_asm) && "Not an asm stmt");
SourceLocation AsmLoc = ConsumeToken();
- if (getLangOpts().MicrosoftExt && Tok.isNot(tok::l_paren) &&
+ if (getLangOpts().AsmBlocks && Tok.isNot(tok::l_paren) &&
!isTypeQualifier()) {
msAsm = true;
return ParseMicrosoftAsmStatement(AsmLoc);
@@ -1834,6 +1810,9 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) {
Diag(Loc, diag::w_asm_qualifier_ignored) << "const";
if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict)
Diag(Loc, diag::w_asm_qualifier_ignored) << "restrict";
+ // FIXME: Once GCC supports _Atomic, check whether it permits it here.
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic)
+ Diag(Loc, diag::w_asm_qualifier_ignored) << "_Atomic";
// Remember if this was a volatile asm.
bool isVolatile = DS.getTypeQualifiers() & DeclSpec::TQ_volatile;
@@ -2003,9 +1982,10 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) {
assert(Tok.is(tok::l_brace));
SourceLocation LBraceLoc = Tok.getLocation();
- if (SkipFunctionBodies && trySkippingFunctionBody()) {
+ if (SkipFunctionBodies && (!Decl || Actions.canSkipFunctionBody(Decl)) &&
+ trySkippingFunctionBody()) {
BodyScope.Exit();
- return Actions.ActOnFinishFunctionBody(Decl, 0);
+ return Actions.ActOnSkippedFunctionBody(Decl);
}
PrettyDeclStackTraceEntry CrashInfo(Actions, Decl, LBraceLoc,
@@ -2045,9 +2025,10 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) {
else
Actions.ActOnDefaultCtorInitializers(Decl);
- if (SkipFunctionBodies && trySkippingFunctionBody()) {
+ if (SkipFunctionBodies && Actions.canSkipFunctionBody(Decl) &&
+ trySkippingFunctionBody()) {
BodyScope.Exit();
- return Actions.ActOnFinishFunctionBody(Decl, 0);
+ return Actions.ActOnSkippedFunctionBody(Decl);
}
SourceLocation LBraceLoc = Tok.getLocation();
@@ -2123,8 +2104,8 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) {
// FIXME: Possible draft standard bug: attribute-specifier should be allowed?
StmtResult TryBlock(ParseCompoundStatement(/*isStmtExpr=*/false,
- Scope::DeclScope |
- (FnTry ? Scope::FnTryScope : Scope::TryScope)));
+ Scope::DeclScope | Scope::TryScope |
+ (FnTry ? Scope::FnTryCatchScope : 0)));
if (TryBlock.isInvalid())
return TryBlock;
@@ -2154,7 +2135,7 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) {
else {
StmtVector Handlers;
ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
ProhibitAttributes(attrs);
if (Tok.isNot(tok::kw_catch))
@@ -2175,14 +2156,13 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) {
/// ParseCXXCatchBlock - Parse a C++ catch block, called handler in the standard
///
-/// handler:
-/// 'catch' '(' exception-declaration ')' compound-statement
+/// handler:
+/// 'catch' '(' exception-declaration ')' compound-statement
///
-/// exception-declaration:
-/// type-specifier-seq declarator
-/// type-specifier-seq abstract-declarator
-/// type-specifier-seq
-/// '...'
+/// exception-declaration:
+/// attribute-specifier-seq[opt] type-specifier-seq declarator
+/// attribute-specifier-seq[opt] type-specifier-seq abstract-declarator[opt]
+/// '...'
///
StmtResult Parser::ParseCXXCatchBlock(bool FnCatch) {
assert(Tok.is(tok::kw_catch) && "Expected 'catch'");
@@ -2197,15 +2177,21 @@ StmtResult Parser::ParseCXXCatchBlock(bool FnCatch) {
// The name in a catch exception-declaration is local to the handler and
// shall not be redeclared in the outermost block of the handler.
ParseScope CatchScope(this, Scope::DeclScope | Scope::ControlScope |
- (FnCatch ? Scope::FnCatchScope : Scope::CatchScope));
+ (FnCatch ? Scope::FnTryCatchScope : 0));
// exception-declaration is equivalent to '...' or a parameter-declaration
// without default arguments.
Decl *ExceptionDecl = 0;
if (Tok.isNot(tok::ellipsis)) {
+ ParsedAttributesWithRange Attributes(AttrFactory);
+ MaybeParseCXX11Attributes(Attributes);
+
DeclSpec DS(AttrFactory);
+ DS.takeAttributesFrom(Attributes);
+
if (ParseCXXTypeSpecifierSeq(DS))
return StmtError();
+
Declarator ExDecl(DS, Declarator::CXXCatchContext);
ParseDeclarator(ExDecl);
ExceptionDecl = Actions.ActOnExceptionDeclarator(getCurScope(), ExDecl);
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 2e0411e..f146669 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -12,13 +12,13 @@
//===----------------------------------------------------------------------===//
#include "clang/Parse/Parser.h"
+#include "RAIIObjectsForParser.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
-#include "RAIIObjectsForParser.h"
-#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/ASTConsumer.h"
using namespace clang;
/// \brief Parse a template declaration, explicit instantiation, or
@@ -172,16 +172,6 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context,
/// \brief Parse a single declaration that declares a template,
/// template specialization, or explicit instantiation of a template.
///
-/// \param TemplateParams if non-NULL, the template parameter lists
-/// that preceded this declaration. In this case, the declaration is a
-/// template declaration, out-of-line definition of a template, or an
-/// explicit template specialization. When NULL, the declaration is an
-/// explicit template instantiation.
-///
-/// \param TemplateLoc when TemplateParams is NULL, the location of
-/// the 'template' keyword that indicates that we have an explicit
-/// template instantiation.
-///
/// \param DeclEnd will receive the source location of the last token
/// within this declaration.
///
@@ -208,7 +198,7 @@ Parser::ParseSingleDeclarationAfterTemplate(
}
ParsedAttributesWithRange prefixAttrs(AttrFactory);
- MaybeParseCXX0XAttributes(prefixAttrs);
+ MaybeParseCXX11Attributes(prefixAttrs);
if (Tok.is(tok::kw_using))
return ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd,
@@ -218,22 +208,27 @@ Parser::ParseSingleDeclarationAfterTemplate(
// the template parameters.
ParsingDeclSpec DS(*this, &DiagsFromTParams);
- // Move the attributes from the prefix into the DS.
- if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
- ProhibitAttributes(prefixAttrs);
- else
- DS.takeAttributesFrom(prefixAttrs);
-
ParseDeclarationSpecifiers(DS, TemplateInfo, AS,
getDeclSpecContextFromDeclaratorContext(Context));
if (Tok.is(tok::semi)) {
+ ProhibitAttributes(prefixAttrs);
DeclEnd = ConsumeToken();
- Decl *Decl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS);
+ Decl *Decl = Actions.ParsedFreeStandingDeclSpec(
+ getCurScope(), AS, DS,
+ TemplateInfo.TemplateParams ? *TemplateInfo.TemplateParams
+ : MultiTemplateParamsArg(),
+ TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation);
DS.complete(Decl);
return Decl;
}
+ // Move the attributes from the prefix into the DS.
+ if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
+ ProhibitAttributes(prefixAttrs);
+ else
+ DS.takeAttributesFrom(prefixAttrs);
+
// Parse the declarator.
ParsingDeclarator DeclaratorInfo(*this, DS, (Declarator::TheContext)Context);
ParseDeclarator(DeclaratorInfo);
@@ -250,27 +245,6 @@ Parser::ParseSingleDeclarationAfterTemplate(
if (DeclaratorInfo.isFunctionDeclarator())
MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs);
- // If we have a declaration or declarator list, handle it.
- if (isDeclarationAfterDeclarator()) {
- // Parse this declaration.
- Decl *ThisDecl = ParseDeclarationAfterDeclarator(DeclaratorInfo,
- TemplateInfo);
-
- if (Tok.is(tok::comma)) {
- Diag(Tok, diag::err_multiple_template_declarators)
- << (int)TemplateInfo.Kind;
- SkipUntil(tok::semi, true, false);
- return ThisDecl;
- }
-
- // Eat the semi colon after the declaration.
- ExpectAndConsumeSemi(diag::err_expected_semi_declaration);
- if (LateParsedAttrs.size() > 0)
- ParseLexedAttributeList(LateParsedAttrs, ThisDecl, true, false);
- DeclaratorInfo.complete(ThisDecl);
- return ThisDecl;
- }
-
if (DeclaratorInfo.isFunctionDeclarator() &&
isStartOfFunctionDefinition(DeclaratorInfo)) {
if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
@@ -285,12 +259,23 @@ Parser::ParseSingleDeclarationAfterTemplate(
&LateParsedAttrs);
}
- if (DeclaratorInfo.isFunctionDeclarator())
- Diag(Tok, diag::err_expected_fn_body);
- else
- Diag(Tok, diag::err_invalid_token_after_toplevel_declarator);
- SkipUntil(tok::semi);
- return 0;
+ // Parse this declaration.
+ Decl *ThisDecl = ParseDeclarationAfterDeclarator(DeclaratorInfo,
+ TemplateInfo);
+
+ if (Tok.is(tok::comma)) {
+ Diag(Tok, diag::err_multiple_template_declarators)
+ << (int)TemplateInfo.Kind;
+ SkipUntil(tok::semi, true, false);
+ return ThisDecl;
+ }
+
+ // Eat the semi colon after the declaration.
+ ExpectAndConsumeSemi(diag::err_expected_semi_declaration);
+ if (LateParsedAttrs.size() > 0)
+ ParseLexedAttributeList(LateParsedAttrs, ThisDecl, true, false);
+ DeclaratorInfo.complete(ThisDecl);
+ return ThisDecl;
}
/// ParseTemplateParameters - Parses a template-parameter-list enclosed in
@@ -357,7 +342,7 @@ Parser::ParseTemplateParameterList(unsigned Depth,
SkipUntil(tok::comma, tok::greater, tok::greatergreater, true, true);
}
- // Did we find a comma or the end of the template parmeter list?
+ // Did we find a comma or the end of the template parameter list?
if (Tok.is(tok::comma)) {
ConsumeToken();
} else if (Tok.is(tok::greater) || Tok.is(tok::greatergreater)) {
@@ -491,7 +476,7 @@ Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
EllipsisLoc = ConsumeToken();
Diag(EllipsisLoc,
- getLangOpts().CPlusPlus0x
+ getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_variadic_templates
: diag::ext_variadic_templates);
}
@@ -578,7 +563,7 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
EllipsisLoc = ConsumeToken();
Diag(EllipsisLoc,
- getLangOpts().CPlusPlus0x
+ getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_variadic_templates
: diag::ext_variadic_templates);
}
@@ -675,52 +660,17 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
DefaultArg.take());
}
-/// \brief Parses a template-id that after the template name has
-/// already been parsed.
-///
-/// This routine takes care of parsing the enclosed template argument
-/// list ('<' template-parameter-list [opt] '>') and placing the
-/// results into a form that can be transferred to semantic analysis.
+/// \brief Parses a '>' at the end of a template list.
///
-/// \param Template the template declaration produced by isTemplateName
-///
-/// \param TemplateNameLoc the source location of the template name
+/// If this function encounters '>>', '>>>', '>=', or '>>=', it tries
+/// to determine if these tokens were supposed to be a '>' followed by
+/// '>', '>>', '>=', or '>='. It emits an appropriate diagnostic if necessary.
///
-/// \param SS if non-NULL, the nested-name-specifier preceding the
-/// template name.
+/// \param RAngleLoc the location of the consumed '>'.
///
-/// \param ConsumeLastToken if true, then we will consume the last
-/// token that forms the template-id. Otherwise, we will leave the
-/// last token in the stream (e.g., so that it can be replaced with an
-/// annotation token).
-bool
-Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
- SourceLocation TemplateNameLoc,
- const CXXScopeSpec &SS,
- bool ConsumeLastToken,
- SourceLocation &LAngleLoc,
- TemplateArgList &TemplateArgs,
- SourceLocation &RAngleLoc) {
- assert(Tok.is(tok::less) && "Must have already parsed the template-name");
-
- // Consume the '<'.
- LAngleLoc = ConsumeToken();
-
- // Parse the optional template-argument-list.
- bool Invalid = false;
- {
- GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
- if (Tok.isNot(tok::greater) && Tok.isNot(tok::greatergreater))
- Invalid = ParseTemplateArgumentList(TemplateArgs);
-
- if (Invalid) {
- // Try to find the closing '>'.
- SkipUntil(tok::greater, true, !ConsumeLastToken);
-
- return true;
- }
- }
-
+/// \param ConsumeLastToken if true, the '>' is not consumed.
+bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc,
+ bool ConsumeLastToken) {
// What will be left once we've consumed the '>'.
tok::TokenKind RemainingToken;
const char *ReplacementStr = "> >";
@@ -788,7 +738,7 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
Hint2 = FixItHint::CreateInsertion(Next.getLocation(), " ");
unsigned DiagId = diag::err_two_right_angle_brackets_need_space;
- if (getLangOpts().CPlusPlus0x && Tok.is(tok::greatergreater))
+ if (getLangOpts().CPlusPlus11 && Tok.is(tok::greatergreater))
DiagId = diag::warn_cxx98_compat_two_right_angle_brackets;
else if (Tok.is(tok::greaterequal))
DiagId = diag::err_right_angle_bracket_equal_needs_space;
@@ -819,10 +769,59 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
Tok.setLength(1);
Tok.setLocation(RAngleLoc);
}
-
return false;
}
+
+/// \brief Parses a template-id that after the template name has
+/// already been parsed.
+///
+/// This routine takes care of parsing the enclosed template argument
+/// list ('<' template-parameter-list [opt] '>') and placing the
+/// results into a form that can be transferred to semantic analysis.
+///
+/// \param Template the template declaration produced by isTemplateName
+///
+/// \param TemplateNameLoc the source location of the template name
+///
+/// \param SS if non-NULL, the nested-name-specifier preceding the
+/// template name.
+///
+/// \param ConsumeLastToken if true, then we will consume the last
+/// token that forms the template-id. Otherwise, we will leave the
+/// last token in the stream (e.g., so that it can be replaced with an
+/// annotation token).
+bool
+Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
+ SourceLocation TemplateNameLoc,
+ const CXXScopeSpec &SS,
+ bool ConsumeLastToken,
+ SourceLocation &LAngleLoc,
+ TemplateArgList &TemplateArgs,
+ SourceLocation &RAngleLoc) {
+ assert(Tok.is(tok::less) && "Must have already parsed the template-name");
+
+ // Consume the '<'.
+ LAngleLoc = ConsumeToken();
+
+ // Parse the optional template-argument-list.
+ bool Invalid = false;
+ {
+ GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
+ if (Tok.isNot(tok::greater) && Tok.isNot(tok::greatergreater))
+ Invalid = ParseTemplateArgumentList(TemplateArgs);
+
+ if (Invalid) {
+ // Try to find the closing '>'.
+ SkipUntil(tok::greater, true, !ConsumeLastToken);
+
+ return true;
+ }
+ }
+
+ return ParseGreaterThanInTemplateList(RAngleLoc, ConsumeLastToken);
+}
+
/// \brief Replace the tokens that form a simple-template-id with an
/// annotation token containing the complete template-id.
///
@@ -839,7 +838,7 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
/// \param Template the declaration of the template named by the first
/// token (an identifier), as returned from \c Action::isTemplateName().
///
-/// \param TemplateNameKind the kind of template that \p Template
+/// \param TNK the kind of template that \p Template
/// refers to, as returned from \c Action::isTemplateName().
///
/// \param SS if non-NULL, the nested-name-specifier that precedes
@@ -1201,7 +1200,7 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) {
/// explicit-instantiation:
/// 'extern' [opt] 'template' declaration
///
-/// Note that the 'extern' is a GNU extension and C++0x feature.
+/// Note that the 'extern' is a GNU extension and C++11 feature.
Decl *Parser::ParseExplicitInstantiation(unsigned Context,
SourceLocation ExternLoc,
SourceLocation TemplateLoc,
@@ -1306,7 +1305,7 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) {
PP.EnterTokenStream(LMT.Toks.data(), LMT.Toks.size(), true, false);
// Consume the previously pushed token.
- ConsumeAnyToken();
+ ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try))
&& "Inline method not starting with '{', ':' or 'try'");
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index 40c4eee..5e0ef2b 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -184,6 +184,9 @@ Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) {
return TPResult::Ambiguous();
}
+/// Tentatively parse an init-declarator-list in order to disambiguate it from
+/// an expression.
+///
/// init-declarator-list:
/// init-declarator
/// init-declarator-list ',' init-declarator
@@ -192,14 +195,21 @@ Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) {
/// declarator initializer[opt]
/// [GNU] declarator simple-asm-expr[opt] attributes[opt] initializer[opt]
///
-/// initializer:
-/// '=' initializer-clause
-/// '(' expression-list ')'
+/// initializer:
+/// brace-or-equal-initializer
+/// '(' expression-list ')'
+///
+/// brace-or-equal-initializer:
+/// '=' initializer-clause
+/// [C++11] braced-init-list
+///
+/// initializer-clause:
+/// assignment-expression
+/// braced-init-list
///
-/// initializer-clause:
-/// assignment-expression
-/// '{' initializer-list ','[opt] '}'
-/// '{' '}'
+/// braced-init-list:
+/// '{' initializer-list ','[opt] '}'
+/// '{' '}'
///
Parser::TPResult Parser::TryParseInitDeclaratorList() {
while (1) {
@@ -218,6 +228,10 @@ Parser::TPResult Parser::TryParseInitDeclaratorList() {
ConsumeParen();
if (!SkipUntil(tok::r_paren))
return TPResult::Error();
+ } else if (Tok.is(tok::l_brace)) {
+ // A left-brace here is sufficient to disambiguate the parse; an
+ // expression can never be followed directly by a braced-init-list.
+ return TPResult::True();
} else if (Tok.is(tok::equal) || isTokIdentifier_in()) {
// MSVC and g++ won't examine the rest of declarators if '=' is
// encountered; they just conclude that we have a declaration.
@@ -295,7 +309,7 @@ bool Parser::isCXXConditionDeclaration() {
if (Tok.is(tok::equal) ||
Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute))
TPR = TPResult::True();
- else if (getLangOpts().CPlusPlus0x && Tok.is(tok::l_brace))
+ else if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace))
TPR = TPResult::True();
else
TPR = TPResult::False();
@@ -379,7 +393,7 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) {
// ',', this is a type-id. Otherwise, it's an expression.
} else if (Context == TypeIdAsTemplateArgument &&
(Tok.is(tok::greater) || Tok.is(tok::comma) ||
- (getLangOpts().CPlusPlus0x && Tok.is(tok::greatergreater)))) {
+ (getLangOpts().CPlusPlus11 && Tok.is(tok::greatergreater)))) {
TPR = TPResult::True();
isAmbiguous = true;
@@ -837,6 +851,15 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
case tok::kw___vector:
case tok::kw___pixel:
case tok::kw__Atomic:
+ case tok::kw_image1d_t:
+ case tok::kw_image1d_array_t:
+ case tok::kw_image1d_buffer_t:
+ case tok::kw_image2d_t:
+ case tok::kw_image2d_array_t:
+ case tok::kw_image3d_t:
+ case tok::kw_sampler_t:
+ case tok::kw_event_t:
+ case tok::kw___unknown_anytype:
return TPResult::False();
default:
@@ -976,6 +999,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
// to types and identifiers, in order to try to recover from errors.
CorrectionCandidateCallback TypoCorrection;
TypoCorrection.WantRemainingKeywords = false;
+ TypoCorrection.WantTypeSpecifiers = Next.isNot(tok::arrow);
switch (TryAnnotateName(false /* no nested name specifier */,
&TypoCorrection)) {
case ANK_Error:
@@ -1056,6 +1080,9 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
// Modules
case tok::kw___module_private__:
+
+ // Debugger support
+ case tok::kw___unknown_anytype:
// type-specifier:
// simple-type-specifier
@@ -1212,7 +1239,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
if (isFollowedByParen)
return TPResult::Ambiguous();
- if (getLangOpts().CPlusPlus0x && isFollowedByBrace)
+ if (getLangOpts().CPlusPlus11 && isFollowedByBrace)
return BracedCastResult;
return TPResult::True();
@@ -1244,7 +1271,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
// enum E : int { a = 4 }; // enum
// enum E : int { 4 }; // bit-field
// };
- if (getLangOpts().CPlusPlus0x && NextToken().is(tok::l_brace))
+ if (getLangOpts().CPlusPlus11 && NextToken().is(tok::l_brace))
return BracedCastResult;
if (isStartOfObjCClassMessageMissingOpenBracket())
@@ -1271,7 +1298,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
if (isFollowedByParen)
return TPResult::Ambiguous();
- if (getLangOpts().CPlusPlus0x && isFollowedByBrace)
+ if (getLangOpts().CPlusPlus11 && isFollowedByBrace)
return BracedCastResult;
return TPResult::True();
@@ -1386,7 +1413,7 @@ bool Parser::isCXXFunctionDeclarator(bool *IsAmbiguous) {
if (Next.is(tok::amp) || Next.is(tok::ampamp) ||
Next.is(tok::kw_const) || Next.is(tok::kw_volatile) ||
Next.is(tok::kw_throw) || Next.is(tok::kw_noexcept) ||
- Next.is(tok::l_square) || isCXX0XVirtSpecifier(Next) ||
+ Next.is(tok::l_square) || isCXX11VirtSpecifier(Next) ||
Next.is(tok::l_brace) || Next.is(tok::kw_try) ||
Next.is(tok::equal) || Next.is(tok::arrow))
// The next token cannot appear after a constructor-style initializer,
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index f4cdd61..1ebba3e 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -12,15 +12,15 @@
//===----------------------------------------------------------------------===//
#include "clang/Parse/Parser.h"
+#include "ParsePragma.h"
+#include "RAIIObjectsForParser.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Sema/DeclSpec.h"
-#include "clang/Sema/Scope.h"
#include "clang/Sema/ParsedTemplate.h"
+#include "clang/Sema/Scope.h"
#include "llvm/Support/raw_ostream.h"
-#include "RAIIObjectsForParser.h"
-#include "ParsePragma.h"
-#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/ASTConsumer.h"
using namespace clang;
@@ -96,6 +96,11 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies)
PP.AddPragmaHandler("OPENCL", FPContractHandler.get());
}
+ if (getLangOpts().OpenMP)
+ OpenMPHandler.reset(new PragmaOpenMPHandler());
+ else
+ OpenMPHandler.reset(new PragmaNoOpenMPHandler());
+ PP.AddPragmaHandler(OpenMPHandler.get());
CommentSemaHandler.reset(new ActionCommentHandler(actions));
PP.addCommentHandler(CommentSemaHandler.get());
@@ -103,29 +108,6 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies)
PP.setCodeCompletionHandler(*this);
}
-/// If a crash happens while the parser is active, print out a line indicating
-/// what the current token is.
-void PrettyStackTraceParserEntry::print(raw_ostream &OS) const {
- const Token &Tok = P.getCurToken();
- if (Tok.is(tok::eof)) {
- OS << "<eof> parser at end of file\n";
- return;
- }
-
- if (Tok.getLocation().isInvalid()) {
- OS << "<unknown> parser at unknown location\n";
- return;
- }
-
- const Preprocessor &PP = P.getPreprocessor();
- Tok.getLocation().print(OS, PP.getSourceManager());
- if (Tok.isAnnotation())
- OS << ": at annotation token \n";
- else
- OS << ": current parser token '" << PP.getSpelling(Tok) << "'\n";
-}
-
-
DiagnosticBuilder Parser::Diag(SourceLocation Loc, unsigned DiagID) {
return Diags.Report(Loc, DiagID);
}
@@ -241,7 +223,7 @@ void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, unsigned TST) {
// C++11 allows extra semicolons at namespace scope, but not in any of the
// other contexts.
if (Kind == OutsideFunction && getLangOpts().CPlusPlus) {
- if (getLangOpts().CPlusPlus0x)
+ if (getLangOpts().CPlusPlus11)
Diag(StartLoc, diag::warn_cxx98_compat_top_level_semi)
<< FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc));
else
@@ -451,6 +433,8 @@ Parser::~Parser() {
OpenCLExtensionHandler.reset();
PP.RemovePragmaHandler("OPENCL", FPContractHandler.get());
}
+ PP.RemovePragmaHandler(OpenMPHandler.get());
+ OpenMPHandler.reset();
PP.RemovePragmaHandler("STDC", FPContractHandler.get());
FPContractHandler.reset();
@@ -577,34 +561,18 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) {
}
ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
MaybeParseMicrosoftAttributes(attrs);
Result = ParseExternalDeclaration(attrs);
return false;
}
-/// ParseTranslationUnit:
-/// translation-unit: [C99 6.9]
-/// external-declaration
-/// translation-unit external-declaration
-void Parser::ParseTranslationUnit() {
- Initialize();
-
- DeclGroupPtrTy Res;
- while (!ParseTopLevelDecl(Res))
- /*parse them all*/;
-
- ExitScope();
- assert(getCurScope() == 0 && "Scope imbalance!");
-}
-
/// ParseExternalDeclaration:
///
/// external-declaration: [C99 6.9], declaration: [C++ dcl.dcl]
/// function-definition
/// declaration
-/// [C++0x] empty-declaration
/// [GNU] asm-definition
/// [GNU] __extension__ external-declaration
/// [OBJC] objc-class-definition
@@ -616,8 +584,10 @@ void Parser::ParseTranslationUnit() {
/// [C++] linkage-specification
/// [GNU] asm-definition:
/// simple-asm-expr ';'
+/// [C++11] empty-declaration
+/// [C++11] attribute-declaration
///
-/// [C++0x] empty-declaration:
+/// [C++11] empty-declaration:
/// ';'
///
/// [C++0x/GNU] 'extern' 'template' declaration
@@ -661,10 +631,16 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
case tok::annot_pragma_opencl_extension:
HandlePragmaOpenCLExtension();
return DeclGroupPtrTy();
+ case tok::annot_pragma_openmp:
+ ParseOpenMPDeclarativeDirective();
+ return DeclGroupPtrTy();
case tok::semi:
+ // Either a C++11 empty-declaration or attribute-declaration.
+ SingleDecl = Actions.ActOnEmptyDeclaration(getCurScope(),
+ attrs.getList(),
+ Tok.getLocation());
ConsumeExtraSemi(OutsideFunction);
- // TODO: Invoke action for top-level semicolon.
- return DeclGroupPtrTy();
+ break;
case tok::r_brace:
Diag(Tok, diag::err_extraneous_closing_brace);
ConsumeBrace();
@@ -764,7 +740,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
// Extern templates
SourceLocation ExternLoc = ConsumeToken();
SourceLocation TemplateLoc = ConsumeToken();
- Diag(ExternLoc, getLangOpts().CPlusPlus0x ?
+ Diag(ExternLoc, getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_extern_template :
diag::ext_extern_template) << SourceRange(ExternLoc, TemplateLoc);
SourceLocation DeclEnd;
@@ -783,11 +759,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
default:
dont_know:
// We can't tell whether this is a function-definition or declaration yet.
- if (DS) {
- return ParseDeclarationOrFunctionDefinition(attrs, DS);
- } else {
- return ParseDeclarationOrFunctionDefinition(attrs);
- }
+ return ParseDeclarationOrFunctionDefinition(attrs, DS);
}
// This routine returns a DeclGroup, if the thing we parsed only contains a
@@ -986,7 +958,8 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
if (Tok.isNot(tok::equal)) {
AttributeList *DtorAttrs = D.getAttributes();
while (DtorAttrs) {
- if (!IsThreadSafetyAttribute(DtorAttrs->getName()->getName())) {
+ if (!IsThreadSafetyAttribute(DtorAttrs->getName()->getName()) &&
+ !DtorAttrs->isCXX11Attribute()) {
Diag(DtorAttrs->getLoc(), diag::warn_attribute_on_function_definition)
<< DtorAttrs->getName()->getName();
}
@@ -1076,7 +1049,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
bool Delete = false;
SourceLocation KWLoc;
if (Tok.is(tok::kw_delete)) {
- Diag(Tok, getLangOpts().CPlusPlus0x ?
+ Diag(Tok, getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_deleted_function :
diag::ext_deleted_function);
@@ -1084,7 +1057,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
Actions.SetDeclDeleted(Res, KWLoc);
Delete = true;
} else if (Tok.is(tok::kw_default)) {
- Diag(Tok, getLangOpts().CPlusPlus0x ?
+ Diag(Tok, getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_defaulted_function :
diag::ext_defaulted_function);
@@ -1138,7 +1111,8 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
// Enter function-declaration scope, limiting any declarators to the
// function prototype scope, including parameter declarators.
- ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope|Scope::DeclScope);
+ ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope |
+ Scope::FunctionDeclarationScope | Scope::DeclScope);
// Read all the argument declarations.
while (isDeclarationSpecifier()) {
@@ -1263,7 +1237,8 @@ Parser::ExprResult Parser::ParseAsmStringLiteral() {
return ExprError();
}
default:
- Diag(Tok, diag::err_expected_string_literal);
+ Diag(Tok, diag::err_expected_string_literal)
+ << /*Source='in...'*/0 << "'asm'";
return ExprError();
}
@@ -1857,7 +1832,7 @@ void Parser::ParseMicrosoftIfExistsExternalDeclaration() {
// Parse the declarations.
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
ParsedAttributesWithRange attrs(AttrFactory);
- MaybeParseCXX0XAttributes(attrs);
+ MaybeParseCXX11Attributes(attrs);
MaybeParseMicrosoftAttributes(attrs);
DeclGroupPtrTy Result = ParseExternalDeclaration(attrs);
if (Result && !getCurScope()->getParent())
@@ -1867,11 +1842,11 @@ void Parser::ParseMicrosoftIfExistsExternalDeclaration() {
}
Parser::DeclGroupPtrTy Parser::ParseModuleImport(SourceLocation AtLoc) {
- assert(Tok.isObjCAtKeyword(tok::objc___experimental_modules_import) &&
+ assert(Tok.isObjCAtKeyword(tok::objc_import) &&
"Improper start to module import");
SourceLocation ImportLoc = ConsumeToken();
- llvm::SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
+ SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> Path;
// Parse the module path.
do {
@@ -1909,7 +1884,9 @@ Parser::DeclGroupPtrTy Parser::ParseModuleImport(SourceLocation AtLoc) {
}
bool BalancedDelimiterTracker::diagnoseOverflow() {
- P.Diag(P.Tok, diag::err_parser_impl_limit_overflow);
+ P.Diag(P.Tok, diag::err_bracket_depth_exceeded)
+ << P.getLangOpts().BracketDepth;
+ P.Diag(P.Tok, diag::note_bracket_depth);
P.SkipUntil(tok::eof);
return true;
}
diff --git a/lib/Parse/RAIIObjectsForParser.h b/lib/Parse/RAIIObjectsForParser.h
index 060fd20..213950a 100644
--- a/lib/Parse/RAIIObjectsForParser.h
+++ b/lib/Parse/RAIIObjectsForParser.h
@@ -407,7 +407,7 @@ namespace clang {
if (!P.Tok.is(Kind))
return true;
- if (getDepth() < MaxDepth) {
+ if (getDepth() < P.getLangOpts().BracketDepth) {
LOpen = (P.*Consumer)();
return false;
}
diff --git a/lib/Rewrite/Core/DeltaTree.cpp b/lib/Rewrite/Core/DeltaTree.cpp
index 4692277..7a7f15b 100644
--- a/lib/Rewrite/Core/DeltaTree.cpp
+++ b/lib/Rewrite/Core/DeltaTree.cpp
@@ -13,8 +13,8 @@
#include "clang/Rewrite/Core/DeltaTree.h"
#include "clang/Basic/LLVM.h"
-#include <cstring>
#include <cstdio>
+#include <cstring>
using namespace clang;
/// The DeltaTree class is a multiway search tree (BTree) structure with some
diff --git a/lib/Rewrite/Core/HTMLRewrite.cpp b/lib/Rewrite/Core/HTMLRewrite.cpp
index 0e8e4fe..2d279f1 100644
--- a/lib/Rewrite/Core/HTMLRewrite.cpp
+++ b/lib/Rewrite/Core/HTMLRewrite.cpp
@@ -12,14 +12,13 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Rewrite/Core/HTMLRewrite.h"
-#include "clang/Lex/TokenConcatenation.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/SourceManager.h"
-#include "llvm/ADT/SmallString.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/TokenConcatenation.h"
+#include "clang/Rewrite/Core/Rewriter.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/lib/Rewrite/Core/Rewriter.cpp b/lib/Rewrite/Core/Rewriter.cpp
index 4df967f..c1c6595 100644
--- a/lib/Rewrite/Core/Rewriter.cpp
+++ b/lib/Rewrite/Core/Rewriter.cpp
@@ -13,14 +13,16 @@
//===----------------------------------------------------------------------===//
#include "clang/Rewrite/Core/Rewriter.h"
-#include "clang/AST/Stmt.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/Stmt.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"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
raw_ostream &RewriteBuffer::write(raw_ostream &os) const {
@@ -416,6 +418,7 @@ bool Rewriter::IncreaseIndentation(CharSourceRange range,
return false;
}
+namespace {
// A wrapper for a file stream that atomically overwrites the target.
//
// Creates a file output stream for a temporary file in the constructor,
@@ -461,7 +464,7 @@ public:
}
bool ok() { return FileStream; }
- llvm::raw_ostream &getStream() { return *FileStream; }
+ raw_ostream &getStream() { return *FileStream; }
private:
DiagnosticsEngine &Diagnostics;
@@ -470,6 +473,7 @@ private:
OwningPtr<llvm::raw_fd_ostream> FileStream;
bool &AllWritten;
};
+} // end anonymous namespace
bool Rewriter::overwriteChangedFiles() {
bool AllWritten = true;
diff --git a/lib/Rewrite/Core/TokenRewriter.cpp b/lib/Rewrite/Core/TokenRewriter.cpp
index 940ece2..494defd 100644
--- a/lib/Rewrite/Core/TokenRewriter.cpp
+++ b/lib/Rewrite/Core/TokenRewriter.cpp
@@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "clang/Rewrite/Core/TokenRewriter.h"
+#include "clang/Basic/SourceManager.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,
diff --git a/lib/Rewrite/Frontend/CMakeLists.txt b/lib/Rewrite/Frontend/CMakeLists.txt
index 9017e47..903a3ef 100644
--- a/lib/Rewrite/Frontend/CMakeLists.txt
+++ b/lib/Rewrite/Frontend/CMakeLists.txt
@@ -25,4 +25,5 @@ target_link_libraries(clangRewriteFrontend
clangAST
clangParse
clangFrontend
+ clangRewriteCore
)
diff --git a/lib/Rewrite/Frontend/FixItRewriter.cpp b/lib/Rewrite/Frontend/FixItRewriter.cpp
index 43a1ab1..a3bbdcf 100644
--- a/lib/Rewrite/Frontend/FixItRewriter.cpp
+++ b/lib/Rewrite/Frontend/FixItRewriter.cpp
@@ -14,15 +14,15 @@
//===----------------------------------------------------------------------===//
#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/Edit/Commit.h"
+#include "clang/Edit/EditsReceiver.h"
#include "clang/Frontend/FrontendDiagnostic.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/Path.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
#include <cstdio>
using namespace clang;
diff --git a/lib/Rewrite/Frontend/FrontendActions.cpp b/lib/Rewrite/Frontend/FrontendActions.cpp
index 7d29b6d..9935aeb 100644
--- a/lib/Rewrite/Frontend/FrontendActions.cpp
+++ b/lib/Rewrite/Frontend/FrontendActions.cpp
@@ -9,20 +9,20 @@
#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/FrontendActions.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/Utils.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/Parser.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"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -158,7 +158,9 @@ ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI,
if (CI.getLangOpts().ObjCRuntime.isNonFragile())
return CreateModernObjCRewriter(InFile, OS,
CI.getDiagnostics(), CI.getLangOpts(),
- CI.getDiagnosticOpts().NoRewriteMacros);
+ CI.getDiagnosticOpts().NoRewriteMacros,
+ (CI.getCodeGenOpts().getDebugInfo() !=
+ CodeGenOptions::NoDebugInfo));
return CreateObjCRewriter(InFile, OS,
CI.getDiagnostics(), CI.getLangOpts(),
CI.getDiagnosticOpts().NoRewriteMacros);
diff --git a/lib/Rewrite/Frontend/InclusionRewriter.cpp b/lib/Rewrite/Frontend/InclusionRewriter.cpp
index 9d1bec9..d95fb07 100644
--- a/lib/Rewrite/Frontend/InclusionRewriter.cpp
+++ b/lib/Rewrite/Frontend/InclusionRewriter.cpp
@@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "clang/Rewrite/Frontend/Rewriters.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/PreprocessorOutputOptions.h"
+#include "clang/Lex/Preprocessor.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -39,7 +39,7 @@ class InclusionRewriter : public PPCallbacks {
bool ShowLineMarkers; ///< Show #line markers.
bool UseLineDirective; ///< Use of line directives or line markers.
typedef std::map<unsigned, FileChange> FileChangeMap;
- FileChangeMap FileChanges; /// Tracks which files were included where.
+ 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;
diff --git a/lib/Rewrite/Frontend/RewriteMacros.cpp b/lib/Rewrite/Frontend/RewriteMacros.cpp
index f399dd5..3c1d2e1 100644
--- a/lib/Rewrite/Frontend/RewriteMacros.cpp
+++ b/lib/Rewrite/Frontend/RewriteMacros.cpp
@@ -13,12 +13,12 @@
//===----------------------------------------------------------------------===//
#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 "clang/Lex/Preprocessor.h"
+#include "clang/Rewrite/Core/Rewriter.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
#include <cstdio>
using namespace clang;
diff --git a/lib/Rewrite/Frontend/RewriteModernObjC.cpp b/lib/Rewrite/Frontend/RewriteModernObjC.cpp
index 4b56b37..0e59b11 100644
--- a/lib/Rewrite/Frontend/RewriteModernObjC.cpp
+++ b/lib/Rewrite/Frontend/RewriteModernObjC.cpp
@@ -12,20 +12,23 @@
//===----------------------------------------------------------------------===//
#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/Attr.h"
#include "clang/AST/ParentMap.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Lexer.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/StringExtras.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;
@@ -115,7 +118,7 @@ namespace {
SmallVector<ObjCInterfaceDecl*, 8> DefinedNonLazyClasses;
/// DefinedNonLazyCategories - List of defined "non-lazy" categories.
- llvm::SmallVector<ObjCCategoryDecl*, 8> DefinedNonLazyCategories;
+ SmallVector<ObjCCategoryDecl *, 8> DefinedNonLazyCategories;
SmallVector<Stmt *, 32> Stmts;
SmallVector<int, 8> ObjCBcLabelNo;
@@ -131,6 +134,7 @@ namespace {
SmallVector<DeclRefExpr *, 32> BlockDeclRefs;
+
// Block related declarations.
SmallVector<ValueDecl *, 8> BlockByCopyDecls;
llvm::SmallPtrSet<ValueDecl *, 8> BlockByCopyDeclsPtrSet;
@@ -144,6 +148,14 @@ namespace {
llvm::DenseMap<ObjCInterfaceDecl *,
llvm::SmallPtrSet<ObjCIvarDecl *, 8> > ReferencedIvars;
+ // ivar bitfield grouping containers
+ llvm::DenseSet<const ObjCInterfaceDecl *> ObjCInterefaceHasBitfieldGroups;
+ llvm::DenseMap<const ObjCIvarDecl* , unsigned> IvarGroupNumber;
+ // This container maps an <class, group number for ivar> tuple to the type
+ // of the struct where the bitfield belongs.
+ llvm::DenseMap<std::pair<const ObjCInterfaceDecl*, unsigned>, QualType> GroupRecordType;
+ SmallVector<FunctionDecl*, 32> FunctionDefinitionsSeen;
+
// 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.
@@ -152,6 +164,7 @@ namespace {
// Needed for header files being rewritten
bool IsHeader;
bool SilenceRewriteMacroWarning;
+ bool GenerateLineInfo;
bool objc_impl_method;
bool DisableReplaceStmt;
@@ -193,6 +206,18 @@ namespace {
}
}
+ if (FunctionDecl *FDecl = dyn_cast<FunctionDecl>(*I)) {
+ // Under modern abi, we cannot translate body of the function
+ // yet until all class extensions and its implementation is seen.
+ // This is because they may introduce new bitfields which must go
+ // into their grouping struct.
+ if (FDecl->isThisDeclarationADefinition() &&
+ // Not c functions defined inside an objc container.
+ !FDecl->isTopLevelDeclInObjCContainer()) {
+ FunctionDefinitionsSeen.push_back(FDecl);
+ break;
+ }
+ }
HandleTopLevelSingleDecl(*I);
}
return true;
@@ -201,7 +226,7 @@ namespace {
void HandleDeclInMainFile(Decl *D);
RewriteModernObjC(std::string inFile, raw_ostream *OS,
DiagnosticsEngine &D, const LangOptions &LOpts,
- bool silenceMacroWarn);
+ bool silenceMacroWarn, bool LineInfo);
~RewriteModernObjC() {}
@@ -282,7 +307,7 @@ namespace {
void ConvertSourceLocationToLineDirective(SourceLocation Loc,
std::string &LineString);
void RewriteForwardClassDecl(DeclGroupRef D);
- void RewriteForwardClassDecl(const llvm::SmallVector<Decl*, 8> &DG);
+ void RewriteForwardClassDecl(const SmallVector<Decl *, 8> &DG);
void RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl,
const std::string &typedefString);
void RewriteImplementations();
@@ -300,7 +325,7 @@ namespace {
void RewriteCategoryDecl(ObjCCategoryDecl *Dcl);
void RewriteProtocolDecl(ObjCProtocolDecl *Dcl);
void RewriteForwardProtocolDecl(DeclGroupRef D);
- void RewriteForwardProtocolDecl(const llvm::SmallVector<Decl*, 8> &DG);
+ void RewriteForwardProtocolDecl(const SmallVector<Decl *, 8> &DG);
void RewriteMethodDeclaration(ObjCMethodDecl *Method);
void RewriteProperty(ObjCPropertyDecl *prop);
void RewriteFunctionDecl(FunctionDecl *FD);
@@ -338,6 +363,20 @@ namespace {
void RewriteImplicitCastObjCExpr(CastExpr *IE);
void RewriteLinkageSpec(LinkageSpecDecl *LSD);
+ // Computes ivar bitfield group no.
+ unsigned ObjCIvarBitfieldGroupNo(ObjCIvarDecl *IV);
+ // Names field decl. for ivar bitfield group.
+ void ObjCIvarBitfieldGroupDecl(ObjCIvarDecl *IV, std::string &Result);
+ // Names struct type for ivar bitfield group.
+ void ObjCIvarBitfieldGroupType(ObjCIvarDecl *IV, std::string &Result);
+ // Names symbol for ivar bitfield group field offset.
+ void ObjCIvarBitfieldGroupOffset(ObjCIvarDecl *IV, std::string &Result);
+ // Given an ivar bitfield, it builds (or finds) its group record type.
+ QualType GetGroupRecordTypeForObjCIvarBitfield(ObjCIvarDecl *IV);
+ QualType SynthesizeBitfieldGroupStructType(
+ ObjCIvarDecl *IV,
+ SmallVectorImpl<ObjCIvarDecl *> &IVars);
+
// Block rewriting.
void RewriteBlocksInFunctionProtoType(QualType funcType, NamedDecl *D);
@@ -533,14 +572,13 @@ namespace {
}
QualType getSimpleFunctionType(QualType result,
- const QualType *args,
- unsigned numArgs,
+ ArrayRef<QualType> args,
bool variadic = false) {
if (result == Context->getObjCInstanceType())
result = Context->getObjCIdType();
FunctionProtoType::ExtProtoInfo fpi;
fpi.Variadic = variadic;
- return Context->getFunctionType(result, args, numArgs, fpi);
+ return Context->getFunctionType(result, args, fpi);
}
// Helper function: create a CStyleCastExpr with trivial type source info.
@@ -596,9 +634,10 @@ static bool IsHeaderFile(const std::string &Filename) {
RewriteModernObjC::RewriteModernObjC(std::string inFile, raw_ostream* OS,
DiagnosticsEngine &D, const LangOptions &LOpts,
- bool silenceMacroWarn)
+ bool silenceMacroWarn,
+ bool LineInfo)
: Diags(D), LangOpts(LOpts), InFileName(inFile), OutFile(OS),
- SilenceRewriteMacroWarning(silenceMacroWarn) {
+ SilenceRewriteMacroWarning(silenceMacroWarn), GenerateLineInfo(LineInfo) {
IsHeader = IsHeaderFile(inFile);
RewriteFailedDiag = Diags.getCustomDiagID(DiagnosticsEngine::Warning,
"rewriting sub-expression within a macro (may not be correct)");
@@ -617,8 +656,10 @@ 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);
+ bool SilenceRewriteMacroWarning,
+ bool LineInfo) {
+ return new RewriteModernObjC(InFile, OS, Diags, LOpts,
+ SilenceRewriteMacroWarning, LineInfo);
}
void RewriteModernObjC::InitializeCommon(ASTContext &context) {
@@ -798,11 +839,16 @@ RewriteModernObjC::getIvarAccessString(ObjCIvarDecl *D) {
// Build name of symbol holding ivar offset.
std::string IvarOffsetName;
- WriteInternalIvarName(ClassDecl, D, IvarOffsetName);
+ if (D->isBitField())
+ ObjCIvarBitfieldGroupOffset(D, IvarOffsetName);
+ else
+ WriteInternalIvarName(ClassDecl, D, IvarOffsetName);
std::string S = "(*(";
QualType IvarT = D->getType();
+ if (D->isBitField())
+ IvarT = GetGroupRecordTypeForObjCIvarBitfield(D);
if (!isa<TypedefType>(IvarT) && IvarT->isRecordType()) {
RecordDecl *RD = IvarT->getAs<RecordType>()->getDecl();
@@ -850,6 +896,10 @@ RewriteModernObjC::getIvarAccessString(ObjCIvarDecl *D) {
S += "((char *)self + ";
S += IvarOffsetName;
S += "))";
+ if (D->isBitField()) {
+ S += ".";
+ S += D->getNameAsString();
+ }
ReferencedIvars[const_cast<ObjCInterfaceDecl *>(ClassDecl)].insert(D);
return S;
}
@@ -889,9 +939,8 @@ void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
// Generate the 'getter' function.
ObjCPropertyDecl *PD = PID->getPropertyDecl();
ObjCIvarDecl *OID = PID->getPropertyIvarDecl();
+ assert(IMD && OID && "Synthesized ivars must be attached to @implementation");
- if (!OID)
- return;
unsigned Attributes = PD->getPropertyAttributes();
if (mustSynthesizeSetterGetterMethod(IMD, PD, true /*getter*/)) {
bool GenGetProperty = !(Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) &&
@@ -993,7 +1042,7 @@ void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID,
static void RewriteOneForwardClassDecl(ObjCInterfaceDecl *ForwardDecl,
std::string &typedefString) {
- typedefString += "#ifndef _REWRITER_typedef_";
+ typedefString += "\n#ifndef _REWRITER_typedef_";
typedefString += ForwardDecl->getNameAsString();
typedefString += "\n";
typedefString += "#define _REWRITER_typedef_";
@@ -1026,7 +1075,7 @@ void RewriteModernObjC::RewriteForwardClassDecl(DeclGroupRef D) {
// as a comment.
typedefString += "// @class ";
typedefString += ForwardDecl->getNameAsString();
- typedefString += ";\n";
+ typedefString += ";";
}
RewriteOneForwardClassDecl(ForwardDecl, typedefString);
}
@@ -1035,14 +1084,14 @@ void RewriteModernObjC::RewriteForwardClassDecl(DeclGroupRef D) {
}
void RewriteModernObjC::RewriteForwardClassDecl(
- const llvm::SmallVector<Decl*, 8> &D) {
+ const SmallVector<Decl *, 8> &D) {
std::string typedefString;
for (unsigned i = 0; i < D.size(); i++) {
ObjCInterfaceDecl *ForwardDecl = cast<ObjCInterfaceDecl>(D[i]);
if (i == 0) {
typedefString += "// @class ";
typedefString += ForwardDecl->getNameAsString();
- typedefString += ";\n";
+ typedefString += ";";
}
RewriteOneForwardClassDecl(ForwardDecl, typedefString);
}
@@ -1100,7 +1149,7 @@ void RewriteModernObjC::RewriteCategoryDecl(ObjCCategoryDecl *CatDecl) {
// Lastly, comment out the @end.
ReplaceText(CatDecl->getAtEndRange().getBegin(),
- strlen("@end"), "/* @end */");
+ strlen("@end"), "/* @end */\n");
}
void RewriteModernObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
@@ -1125,7 +1174,7 @@ void RewriteModernObjC::RewriteProtocolDecl(ObjCProtocolDecl *PDecl) {
// Lastly, comment out the @end.
SourceLocation LocEnd = PDecl->getAtEndRange().getBegin();
- ReplaceText(LocEnd, strlen("@end"), "/* @end */");
+ ReplaceText(LocEnd, strlen("@end"), "/* @end */\n");
// Must comment out @optional/@required
const char *startBuf = SM->getCharacterData(LocStart);
@@ -1153,7 +1202,7 @@ void RewriteModernObjC::RewriteForwardProtocolDecl(DeclGroupRef D) {
}
void
-RewriteModernObjC::RewriteForwardProtocolDecl(const llvm::SmallVector<Decl*, 8> &DG) {
+RewriteModernObjC::RewriteForwardProtocolDecl(const SmallVector<Decl *, 8> &DG) {
SourceLocation LocStart = DG[0]->getLocStart();
if (LocStart.isInvalid())
llvm_unreachable("Invalid SourceLocation");
@@ -1393,7 +1442,7 @@ void RewriteModernObjC::RewriteInterfaceDecl(ObjCInterfaceDecl *ClassDecl) {
// Lastly, comment out the @end.
ReplaceText(ClassDecl->getAtEndRange().getBegin(), strlen("@end"),
- "/* @end */");
+ "/* @end */\n");
}
}
@@ -1608,7 +1657,7 @@ Stmt *RewriteModernObjC::RewriteBreakStmt(BreakStmt *S) {
void RewriteModernObjC::ConvertSourceLocationToLineDirective(
SourceLocation Loc,
std::string &LineString) {
- if (Loc.isFileID()) {
+ if (Loc.isFileID() && GenerateLineInfo) {
LineString += "\n#line ";
PresumedLoc PLoc = SM->getPresumedLoc(Loc);
LineString += utostr(PLoc.getLine());
@@ -2042,7 +2091,9 @@ Stmt *RewriteModernObjC::RewriteObjCThrowStmt(ObjCAtThrowStmt *S) {
assert((*wBuf == 'w') && "@throw: can't find 'w'");
ReplaceText(startLoc, wBuf-startBuf+1, buf);
- const char *semiBuf = strchr(startBuf, ';');
+ SourceLocation endLoc = S->getLocEnd();
+ const char *endBuf = SM->getCharacterData(endLoc);
+ const char *semiBuf = strchr(endBuf, ';');
assert((*semiBuf == ';') && "@throw: can't find ';'");
SourceLocation semiLoc = startLoc.getLocWithOffset(semiBuf-startBuf);
if (S->getThrowExpr())
@@ -2208,6 +2259,10 @@ void RewriteModernObjC::RewriteObjCQualifiedInterfaceTypes(Decl *Dcl) {
Loc = FD->getLocation();
Type = FD->getType();
}
+ else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(Dcl)) {
+ Loc = TD->getLocation();
+ Type = TD->getUnderlyingType();
+ }
else
return;
@@ -2305,13 +2360,12 @@ void RewriteModernObjC::SynthSelGetUidFunctionDecl() {
SmallVector<QualType, 16> ArgTys;
ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));
QualType getFuncType =
- getSimpleFunctionType(Context->getObjCSelType(), &ArgTys[0], ArgTys.size());
+ getSimpleFunctionType(Context->getObjCSelType(), ArgTys);
SelGetUidFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- SelGetUidIdent, getFuncType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ SelGetUidIdent, getFuncType, 0,
+ SC_Extern);
}
void RewriteModernObjC::RewriteFunctionDecl(FunctionDecl *FD) {
@@ -2404,13 +2458,12 @@ void RewriteModernObjC::SynthSuperContructorFunctionDecl() {
ArgTys.push_back(argT);
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size());
+ ArgTys);
SuperContructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ msgSendIdent, msgSendType,
+ 0, SC_Extern);
}
// SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...);
@@ -2424,14 +2477,12 @@ void RewriteModernObjC::SynthMsgSendFunctionDecl() {
assert(!argT.isNull() && "Can't find 'SEL' type");
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size(),
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ msgSendIdent, msgSendType, 0,
+ SC_Extern);
}
// SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(void);
@@ -2440,14 +2491,12 @@ void RewriteModernObjC::SynthMsgSendSuperFunctionDecl() {
SmallVector<QualType, 2> ArgTys;
ArgTys.push_back(Context->VoidTy);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], 1,
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ msgSendIdent, msgSendType, 0,
+ SC_Extern);
}
// SynthMsgSendStretFunctionDecl - id objc_msgSend_stret(id self, SEL op, ...);
@@ -2461,14 +2510,12 @@ void RewriteModernObjC::SynthMsgSendStretFunctionDecl() {
assert(!argT.isNull() && "Can't find 'SEL' type");
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size(),
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ msgSendIdent, msgSendType, 0,
+ SC_Extern);
}
// SynthMsgSendSuperStretFunctionDecl -
@@ -2479,14 +2526,13 @@ void RewriteModernObjC::SynthMsgSendSuperStretFunctionDecl() {
SmallVector<QualType, 2> ArgTys;
ArgTys.push_back(Context->VoidTy);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], 1,
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendSuperStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern,
- SC_None, false);
+ msgSendIdent,
+ msgSendType, 0,
+ SC_Extern);
}
// SynthMsgSendFpretFunctionDecl - double objc_msgSend_fpret(id self, SEL op, ...);
@@ -2500,14 +2546,12 @@ void RewriteModernObjC::SynthMsgSendFpretFunctionDecl() {
assert(!argT.isNull() && "Can't find 'SEL' type");
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->DoubleTy,
- &ArgTys[0], ArgTys.size(),
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendFpretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ msgSendIdent, msgSendType, 0,
+ SC_Extern);
}
// SynthGetClassFunctionDecl - Class objc_getClass(const char *name);
@@ -2516,13 +2560,12 @@ void RewriteModernObjC::SynthGetClassFunctionDecl() {
SmallVector<QualType, 16> ArgTys;
ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));
QualType getClassType = getSimpleFunctionType(Context->getObjCClassType(),
- &ArgTys[0], ArgTys.size());
+ ArgTys);
GetClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- getClassIdent, getClassType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ getClassIdent, getClassType, 0,
+ SC_Extern);
}
// SynthGetSuperClassFunctionDecl - Class class_getSuperclass(Class cls);
@@ -2532,15 +2575,13 @@ void RewriteModernObjC::SynthGetSuperClassFunctionDecl() {
SmallVector<QualType, 16> ArgTys;
ArgTys.push_back(Context->getObjCClassType());
QualType getClassType = getSimpleFunctionType(Context->getObjCClassType(),
- &ArgTys[0], ArgTys.size());
+ ArgTys);
GetSuperClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
getSuperClassIdent,
getClassType, 0,
- SC_Extern,
- SC_None,
- false);
+ SC_Extern);
}
// SynthGetMetaClassFunctionDecl - Class objc_getMetaClass(const char *name);
@@ -2549,13 +2590,12 @@ void RewriteModernObjC::SynthGetMetaClassFunctionDecl() {
SmallVector<QualType, 16> ArgTys;
ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));
QualType getClassType = getSimpleFunctionType(Context->getObjCClassType(),
- &ArgTys[0], ArgTys.size());
+ ArgTys);
GetMetaClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- getClassIdent, getClassType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ getClassIdent, getClassType,
+ 0, SC_Extern);
}
Stmt *RewriteModernObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
@@ -2568,7 +2608,7 @@ Stmt *RewriteModernObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
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'))
+ if (!isAlphanumeric(c))
tmpName[i] = '_';
}
S += tmpName;
@@ -2588,7 +2628,7 @@ Stmt *RewriteModernObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
SourceLocation(), &Context->Idents.get(S),
- strType, 0, SC_Static, SC_None);
+ strType, 0, SC_Static);
DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, false, strType, VK_LValue,
SourceLocation());
Expr *Unop = new (Context) UnaryOperator(DRE, UO_AddrOf,
@@ -2697,8 +2737,7 @@ Stmt *RewriteModernObjC::RewriteObjCBoxedExpr(ObjCBoxedExpr *Exp) {
// Now do the "normal" pointer to function cast.
QualType castType =
- getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(),
- BoxingMethod->isVariadic());
+ getSimpleFunctionType(returnType, ArgTypes, BoxingMethod->isVariadic());
castType = Context->getPointerType(castType);
cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast,
cast);
@@ -2731,7 +2770,7 @@ Stmt *RewriteModernObjC::RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp) {
// Build the expression: __NSContainer_literal(int, ...).arr
QualType IntQT = Context->IntTy;
QualType NSArrayFType =
- getSimpleFunctionType(Context->VoidTy, &IntQT, 1, true);
+ getSimpleFunctionType(Context->VoidTy, IntQT, true);
std::string NSArrayFName("__NSContainer_literal");
FunctionDecl *NSArrayFD = SynthBlockInitFunctionDecl(NSArrayFName);
DeclRefExpr *NSArrayDRE =
@@ -2835,8 +2874,7 @@ Stmt *RewriteModernObjC::RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp) {
// Now do the "normal" pointer to function cast.
QualType castType =
- getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(),
- ArrayMethod->isVariadic());
+ getSimpleFunctionType(returnType, ArgTypes, ArrayMethod->isVariadic());
castType = Context->getPointerType(castType);
cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast,
cast);
@@ -2869,7 +2907,7 @@ Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral
// Build the expression: __NSContainer_literal(int, ...).arr
QualType IntQT = Context->IntTy;
QualType NSDictFType =
- getSimpleFunctionType(Context->VoidTy, &IntQT, 1, true);
+ getSimpleFunctionType(Context->VoidTy, IntQT, true);
std::string NSDictFName("__NSContainer_literal");
FunctionDecl *NSDictFD = SynthBlockInitFunctionDecl(NSDictFName);
DeclRefExpr *NSDictDRE =
@@ -3009,8 +3047,7 @@ Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral
// Now do the "normal" pointer to function cast.
QualType castType =
- getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(),
- DictMethod->isVariadic());
+ getSimpleFunctionType(returnType, ArgTypes, DictMethod->isVariadic());
castType = Context->getPointerType(castType);
cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast,
cast);
@@ -3102,7 +3139,7 @@ static SourceLocation getFunctionSourceLocation (RewriteModernObjC &R,
if (!LSD->getRBraceLoc().isValid())
return LSD->getExternLoc();
}
- if (FD->getStorageClassAsWritten() != SC_None)
+ if (FD->getStorageClass() != SC_None)
R.RewriteBlockLiteralFunctionDecl(FD);
return FD->getTypeSpecStartLoc();
}
@@ -3111,7 +3148,7 @@ void RewriteModernObjC::RewriteLineDirective(const Decl *D) {
SourceLocation Location = D->getLocation();
- if (Location.isFileID()) {
+ if (Location.isFileID() && GenerateLineInfo) {
std::string LineString("\n#line ");
PresumedLoc PLoc = SM->getPresumedLoc(Location);
LineString += utostr(PLoc.getLine());
@@ -3152,8 +3189,9 @@ Expr *RewriteModernObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFla
SmallVectorImpl<Expr*> &MsgExprs,
ObjCMethodDecl *Method) {
// Now do the "normal" pointer to function cast.
- QualType castType = getSimpleFunctionType(returnType, &ArgTypes[0], ArgTypes.size(),
- Method ? Method->isVariadic() : false);
+ QualType castType = getSimpleFunctionType(returnType, ArgTypes,
+ Method ? Method->isVariadic()
+ : false);
castType = Context->getPointerType(castType);
// build type for containing the objc_msgSend_stret object.
@@ -3211,8 +3249,8 @@ Expr *RewriteModernObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFla
// 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);
+ SourceLocation(), ID, castType, 0,
+ SC_Extern, false, false);
DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, false, castType, VK_RValue,
SourceLocation());
CallExpr *STCE = new (Context) CallExpr(*Context, DRE, MsgExprs,
@@ -3592,10 +3630,10 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
CK_BitCast, DRE);
// Now do the "normal" pointer to function cast.
+ // If we don't have a method decl, force a variadic cast.
+ const ObjCMethodDecl *MD = Exp->getMethodDecl();
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);
+ getSimpleFunctionType(returnType, ArgTypes, MD ? MD->isVariadic() : true);
castType = Context->getPointerType(castType);
cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast,
cast);
@@ -3685,7 +3723,7 @@ Stmt *RewriteModernObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) {
IdentifierInfo *ID = &Context->Idents.get(Name);
VarDecl *VD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
SourceLocation(), ID, getProtocolType(), 0,
- SC_Extern, SC_None);
+ SC_Extern);
DeclRefExpr *DRE = new (Context) DeclRefExpr(VD, false, getProtocolType(),
VK_LValue, SourceLocation());
Expr *DerefExpr = new (Context) UnaryOperator(DRE, UO_AddrOf,
@@ -3840,16 +3878,16 @@ void RewriteModernObjC::RewriteObjCFieldDecl(FieldDecl *fieldDecl,
Result += " : "; Result += utostr(fieldDecl->getBitWidthValue(*Context));
}
else if (EleboratedType && Type->isArrayType()) {
- CanQualType CType = Context->getCanonicalType(Type);
- while (isa<ArrayType>(CType)) {
- if (const ConstantArrayType *CAT = Context->getAsConstantArrayType(CType)) {
+ const ArrayType *AT = Context->getAsArrayType(Type);
+ do {
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) {
Result += "[";
llvm::APInt Dim = CAT->getSize();
Result += utostr(Dim.getZExtValue());
Result += "]";
}
- CType = CType->getAs<ArrayType>()->getElementType();
- }
+ AT = Context->getAsArrayType(AT->getElementType());
+ } while (AT);
}
Result += ";\n";
@@ -3890,6 +3928,126 @@ void RewriteModernObjC::RewriteLocallyDefinedNamedAggregates(FieldDecl *fieldDec
}
+unsigned RewriteModernObjC::ObjCIvarBitfieldGroupNo(ObjCIvarDecl *IV) {
+ const ObjCInterfaceDecl *CDecl = IV->getContainingInterface();
+ if (ObjCInterefaceHasBitfieldGroups.count(CDecl)) {
+ return IvarGroupNumber[IV];
+ }
+ unsigned GroupNo = 0;
+ SmallVector<const ObjCIvarDecl *, 8> IVars;
+ for (const ObjCIvarDecl *IVD = CDecl->all_declared_ivar_begin();
+ IVD; IVD = IVD->getNextIvar())
+ IVars.push_back(IVD);
+
+ for (unsigned i = 0, e = IVars.size(); i < e; i++)
+ if (IVars[i]->isBitField()) {
+ IvarGroupNumber[IVars[i++]] = ++GroupNo;
+ while (i < e && IVars[i]->isBitField())
+ IvarGroupNumber[IVars[i++]] = GroupNo;
+ if (i < e)
+ --i;
+ }
+
+ ObjCInterefaceHasBitfieldGroups.insert(CDecl);
+ return IvarGroupNumber[IV];
+}
+
+QualType RewriteModernObjC::SynthesizeBitfieldGroupStructType(
+ ObjCIvarDecl *IV,
+ SmallVectorImpl<ObjCIvarDecl *> &IVars) {
+ std::string StructTagName;
+ ObjCIvarBitfieldGroupType(IV, StructTagName);
+ RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct,
+ Context->getTranslationUnitDecl(),
+ SourceLocation(), SourceLocation(),
+ &Context->Idents.get(StructTagName));
+ for (unsigned i=0, e = IVars.size(); i < e; i++) {
+ ObjCIvarDecl *Ivar = IVars[i];
+ RD->addDecl(FieldDecl::Create(*Context, RD, SourceLocation(), SourceLocation(),
+ &Context->Idents.get(Ivar->getName()),
+ Ivar->getType(),
+ 0, /*Expr *BW */Ivar->getBitWidth(), false,
+ ICIS_NoInit));
+ }
+ RD->completeDefinition();
+ return Context->getTagDeclType(RD);
+}
+
+QualType RewriteModernObjC::GetGroupRecordTypeForObjCIvarBitfield(ObjCIvarDecl *IV) {
+ const ObjCInterfaceDecl *CDecl = IV->getContainingInterface();
+ unsigned GroupNo = ObjCIvarBitfieldGroupNo(IV);
+ std::pair<const ObjCInterfaceDecl*, unsigned> tuple = std::make_pair(CDecl, GroupNo);
+ if (GroupRecordType.count(tuple))
+ return GroupRecordType[tuple];
+
+ SmallVector<ObjCIvarDecl *, 8> IVars;
+ for (const ObjCIvarDecl *IVD = CDecl->all_declared_ivar_begin();
+ IVD; IVD = IVD->getNextIvar()) {
+ if (IVD->isBitField())
+ IVars.push_back(const_cast<ObjCIvarDecl *>(IVD));
+ else {
+ if (!IVars.empty()) {
+ unsigned GroupNo = ObjCIvarBitfieldGroupNo(IVars[0]);
+ // Generate the struct type for this group of bitfield ivars.
+ GroupRecordType[std::make_pair(CDecl, GroupNo)] =
+ SynthesizeBitfieldGroupStructType(IVars[0], IVars);
+ IVars.clear();
+ }
+ }
+ }
+ if (!IVars.empty()) {
+ // Do the last one.
+ unsigned GroupNo = ObjCIvarBitfieldGroupNo(IVars[0]);
+ GroupRecordType[std::make_pair(CDecl, GroupNo)] =
+ SynthesizeBitfieldGroupStructType(IVars[0], IVars);
+ }
+ QualType RetQT = GroupRecordType[tuple];
+ assert(!RetQT.isNull() && "GetGroupRecordTypeForObjCIvarBitfield struct type is NULL");
+
+ return RetQT;
+}
+
+/// ObjCIvarBitfieldGroupDecl - Names field decl. for ivar bitfield group.
+/// Name would be: classname__GRBF_n where n is the group number for this ivar.
+void RewriteModernObjC::ObjCIvarBitfieldGroupDecl(ObjCIvarDecl *IV,
+ std::string &Result) {
+ const ObjCInterfaceDecl *CDecl = IV->getContainingInterface();
+ Result += CDecl->getName();
+ Result += "__GRBF_";
+ unsigned GroupNo = ObjCIvarBitfieldGroupNo(IV);
+ Result += utostr(GroupNo);
+ return;
+}
+
+/// ObjCIvarBitfieldGroupType - Names struct type for ivar bitfield group.
+/// Name of the struct would be: classname__T_n where n is the group number for
+/// this ivar.
+void RewriteModernObjC::ObjCIvarBitfieldGroupType(ObjCIvarDecl *IV,
+ std::string &Result) {
+ const ObjCInterfaceDecl *CDecl = IV->getContainingInterface();
+ Result += CDecl->getName();
+ Result += "__T_";
+ unsigned GroupNo = ObjCIvarBitfieldGroupNo(IV);
+ Result += utostr(GroupNo);
+ return;
+}
+
+/// ObjCIvarBitfieldGroupOffset - Names symbol for ivar bitfield group field offset.
+/// Name would be: OBJC_IVAR_$_classname__GRBF_n where n is the group number for
+/// this ivar.
+void RewriteModernObjC::ObjCIvarBitfieldGroupOffset(ObjCIvarDecl *IV,
+ std::string &Result) {
+ Result += "OBJC_IVAR_$_";
+ ObjCIvarBitfieldGroupDecl(IV, Result);
+}
+
+#define SKIP_BITFIELDS(IX, ENDIX, VEC) { \
+ while ((IX < ENDIX) && VEC[IX]->isBitField()) \
+ ++IX; \
+ if (IX < ENDIX) \
+ --IX; \
+}
+
/// RewriteObjCInternalStruct - Rewrite one internal struct corresponding to
/// an objective-c class with ivars.
void RewriteModernObjC::RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl,
@@ -3923,7 +4081,19 @@ void RewriteModernObjC::RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl,
// struct/unions in objective-c classes.
for (unsigned i = 0, e = IVars.size(); i < e; i++)
RewriteLocallyDefinedNamedAggregates(IVars[i], Result);
-
+
+ // Insert named structs which are syntheized to group ivar bitfields
+ // to outer scope as well.
+ for (unsigned i = 0, e = IVars.size(); i < e; i++)
+ if (IVars[i]->isBitField()) {
+ ObjCIvarDecl *IV = IVars[i];
+ QualType QT = GetGroupRecordTypeForObjCIvarBitfield(IV);
+ RewriteObjCFieldDeclType(QT, Result);
+ Result += ";";
+ // skip over ivar bitfields in this group.
+ SKIP_BITFIELDS(i , e, IVars);
+ }
+
Result += "\nstruct ";
Result += CDecl->getNameAsString();
Result += "_IMPL {\n";
@@ -3934,8 +4104,18 @@ void RewriteModernObjC::RewriteObjCInternalStruct(ObjCInterfaceDecl *CDecl,
Result += "_IVARS;\n";
}
- for (unsigned i = 0, e = IVars.size(); i < e; i++)
- RewriteObjCFieldDecl(IVars[i], Result);
+ for (unsigned i = 0, e = IVars.size(); i < e; i++) {
+ if (IVars[i]->isBitField()) {
+ ObjCIvarDecl *IV = IVars[i];
+ Result += "\tstruct ";
+ ObjCIvarBitfieldGroupType(IV, Result); Result += " ";
+ ObjCIvarBitfieldGroupDecl(IV, Result); Result += ";\n";
+ // skip over ivar bitfields in this group.
+ SKIP_BITFIELDS(i , e, IVars);
+ }
+ else
+ RewriteObjCFieldDecl(IVars[i], Result);
+ }
Result += "};\n";
endBuf += Lexer::MeasureTokenLength(LocEnd, *SM, LangOpts);
@@ -3954,9 +4134,18 @@ void RewriteModernObjC::RewriteIvarOffsetSymbols(ObjCInterfaceDecl *CDecl,
llvm::SmallPtrSet<ObjCIvarDecl *, 8> Ivars = ReferencedIvars[CDecl];
if (Ivars.empty())
return;
+
+ llvm::DenseSet<std::pair<const ObjCInterfaceDecl*, unsigned> > GroupSymbolOutput;
for (llvm::SmallPtrSet<ObjCIvarDecl *, 8>::iterator i = Ivars.begin(),
e = Ivars.end(); i != e; i++) {
ObjCIvarDecl *IvarDecl = (*i);
+ const ObjCInterfaceDecl *IDecl = IvarDecl->getContainingInterface();
+ unsigned GroupNo = 0;
+ if (IvarDecl->isBitField()) {
+ GroupNo = ObjCIvarBitfieldGroupNo(IvarDecl);
+ if (GroupSymbolOutput.count(std::make_pair(IDecl, GroupNo)))
+ continue;
+ }
Result += "\n";
if (LangOpts.MicrosoftExt)
Result += "__declspec(allocate(\".objc_ivar$B\")) ";
@@ -3967,7 +4156,12 @@ void RewriteModernObjC::RewriteIvarOffsetSymbols(ObjCInterfaceDecl *CDecl,
Result += "__declspec(dllimport) ";
Result += "unsigned long ";
- WriteInternalIvarName(CDecl, IvarDecl, Result);
+ if (IvarDecl->isBitField()) {
+ ObjCIvarBitfieldGroupOffset(IvarDecl, Result);
+ GroupSymbolOutput.insert(std::make_pair(IDecl, GroupNo));
+ }
+ else
+ WriteInternalIvarName(CDecl, IvarDecl, Result);
Result += ";";
}
}
@@ -4545,7 +4739,7 @@ QualType RewriteModernObjC::convertFunctionTypeOfBlocks(const FunctionType *FT)
}
QualType FuncType;
if (modified)
- FuncType = getSimpleFunctionType(Res, &ArgTypes[0], ArgTypes.size());
+ FuncType = getSimpleFunctionType(Res, ArgTypes);
else FuncType = QualType(FT, 0);
return FuncType;
}
@@ -4612,8 +4806,7 @@ Stmt *RewriteModernObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp
}
}
// Now do the pointer to function cast.
- QualType PtrToFuncCastType
- = getSimpleFunctionType(Exp->getType(), &ArgTypes[0], ArgTypes.size());
+ QualType PtrToFuncCastType = getSimpleFunctionType(Exp->getType(), ArgTypes);
PtrToFuncCastType = Context->getPointerType(PtrToFuncCastType);
@@ -5053,7 +5246,7 @@ void RewriteModernObjC::RewriteByRefVar(VarDecl *ND, bool firstDecl,
// Add void *__Block_byref_id_object_copy;
// void *__Block_byref_id_object_dispose; if needed.
QualType Ty = ND->getType();
- bool HasCopyAndDispose = Context->BlockRequiresCopying(Ty);
+ bool HasCopyAndDispose = Context->BlockRequiresCopying(Ty, ND);
if (HasCopyAndDispose) {
ByrefType += " void (*__Block_byref_id_object_copy)(void*, void*);\n";
ByrefType += " void (*__Block_byref_id_object_dispose)(void*);\n";
@@ -5089,7 +5282,7 @@ void RewriteModernObjC::RewriteByRefVar(VarDecl *ND, bool firstDecl,
flag |= BLOCK_FIELD_IS_OBJECT;
std::string HF = SynthesizeByrefCopyDestroyHelper(ND, flag);
if (!HF.empty())
- InsertText(FunLocStart, HF);
+ Preamble += HF;
}
// struct __Block_byref_ND ND =
@@ -5210,7 +5403,7 @@ FunctionDecl *RewriteModernObjC::SynthBlockInitFunctionDecl(StringRef name) {
QualType FType = Context->getFunctionNoProtoType(Context->VoidPtrTy);
return FunctionDecl::Create(*Context, TUDecl, SourceLocation(),
SourceLocation(), ID, FType, 0, SC_Extern,
- SC_None, false, false);
+ false, false);
}
Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
@@ -5311,7 +5504,7 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp,
SourceLocation(), SourceLocation(),
&Context->Idents.get(DescData.c_str()),
Context->VoidPtrTy, 0,
- SC_Static, SC_None);
+ SC_Static);
UnaryOperator *DescRefExpr =
new (Context) UnaryOperator(new (Context) DeclRefExpr(NewVD, false,
Context->VoidPtrTy,
@@ -5464,6 +5657,8 @@ Stmt *RewriteModernObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) {
} else if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S)) {
return RewriteObjCIvarRefExpr(IvarRefExpr);
}
+ else if (isa<OpaqueValueExpr>(S))
+ S = cast<OpaqueValueExpr>(S)->getSourceExpr();
SourceRange OrigStmtRange = S->getSourceRange();
@@ -5805,6 +6000,8 @@ void RewriteModernObjC::HandleDeclInMainFile(Decl *D) {
RewriteBlockPointerDecl(TD);
else if (TD->getUnderlyingType()->isFunctionPointerType())
CheckFunctionPointerDecl(TD->getUnderlyingType(), TD);
+ else
+ RewriteObjCQualifiedInterfaceTypes(TD);
}
break;
}
@@ -5844,6 +6041,14 @@ void RewriteModernObjC::HandleTranslationUnit(ASTContext &C) {
RewriteInclude();
+ for (unsigned i = 0, e = FunctionDefinitionsSeen.size(); i < e; i++) {
+ // translation of function bodies were postponed untill all class and
+ // their extensions and implementations are seen. This is because, we
+ // cannot build grouping structs for bitfields untill they are all seen.
+ FunctionDecl *FDecl = FunctionDefinitionsSeen[i];
+ HandleTopLevelSingleDecl(FDecl);
+ }
+
// Here's a great place to add any extra declarations that may be needed.
// Write out meta data for each @protocol(<expr>).
for (llvm::SmallPtrSet<ObjCProtocolDecl *,8>::iterator I = ProtocolExprDecls.begin(),
@@ -5865,7 +6070,7 @@ void RewriteModernObjC::HandleTranslationUnit(ASTContext &C) {
// private ivars.
RewriteInterfaceDecl(CDecl);
}
-
+
// Get the buffer corresponding to MainFileID. If we haven't changed it, then
// we are done.
if (const RewriteBuffer *RewriteBuf =
@@ -6060,19 +6265,16 @@ void RewriteModernObjC::Initialize(ASTContext &context) {
/// 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 += "__OFFSETOFIVAR__(struct ";
+ Result += ivar->getContainingInterface()->getNameAsString();
+ if (LangOpts.MicrosoftExt)
+ Result += "_IMPL";
+ Result += ", ";
+ if (ivar->isBitField())
+ ObjCIvarBitfieldGroupDecl(ivar, Result);
+ else
Result += ivar->getNameAsString();
- Result += ")";
- }
+ Result += ")";
}
/// WriteModernMetadataDeclarations - Writes out metadata declarations for modern ABI.
@@ -6749,21 +6951,41 @@ static void Write_IvarOffsetVar(RewriteModernObjC &RewriteObj,
Result += "extern \"C\" unsigned long int ";
else
Result += "extern \"C\" __declspec(dllexport) unsigned long int ";
- WriteInternalIvarName(CDecl, IvarDecl, Result);
+ if (Ivars[i]->isBitField())
+ RewriteObj.ObjCIvarBitfieldGroupOffset(IvarDecl, Result);
+ else
+ WriteInternalIvarName(CDecl, IvarDecl, Result);
Result += " __attribute__ ((used, section (\"__DATA,__objc_ivar\")))";
Result += " = ";
RewriteObj.RewriteIvarOffsetComputation(IvarDecl, Result);
Result += ";\n";
+ if (Ivars[i]->isBitField()) {
+ // skip over rest of the ivar bitfields.
+ SKIP_BITFIELDS(i , e, Ivars);
+ }
}
}
static void Write__ivar_list_t_initializer(RewriteModernObjC &RewriteObj,
ASTContext *Context, std::string &Result,
- ArrayRef<ObjCIvarDecl *> Ivars,
+ ArrayRef<ObjCIvarDecl *> OriginalIvars,
StringRef VarName,
ObjCInterfaceDecl *CDecl) {
- if (Ivars.size() > 0) {
- Write_IvarOffsetVar(RewriteObj, Context, Result, Ivars, CDecl);
+ if (OriginalIvars.size() > 0) {
+ Write_IvarOffsetVar(RewriteObj, Context, Result, OriginalIvars, CDecl);
+ SmallVector<ObjCIvarDecl *, 8> Ivars;
+ // strip off all but the first ivar bitfield from each group of ivars.
+ // Such ivars in the ivar list table will be replaced by their grouping struct
+ // 'ivar'.
+ for (unsigned i = 0, e = OriginalIvars.size(); i < e; i++) {
+ if (OriginalIvars[i]->isBitField()) {
+ Ivars.push_back(OriginalIvars[i]);
+ // skip over rest of the ivar bitfields.
+ SKIP_BITFIELDS(i , e, OriginalIvars);
+ }
+ else
+ Ivars.push_back(OriginalIvars[i]);
+ }
Result += "\nstatic ";
Write__ivar_list_t_TypeDecl(Result, Ivars.size());
@@ -6779,22 +7001,35 @@ static void Write__ivar_list_t_initializer(RewriteModernObjC &RewriteObj,
else
Result += "\t {";
Result += "(unsigned long int *)&";
- WriteInternalIvarName(CDecl, IvarDecl, Result);
+ if (Ivars[i]->isBitField())
+ RewriteObj.ObjCIvarBitfieldGroupOffset(IvarDecl, Result);
+ else
+ WriteInternalIvarName(CDecl, IvarDecl, Result);
Result += ", ";
- Result += "\""; Result += IvarDecl->getName(); Result += "\", ";
+ Result += "\"";
+ if (Ivars[i]->isBitField())
+ RewriteObj.ObjCIvarBitfieldGroupDecl(Ivars[i], Result);
+ else
+ Result += IvarDecl->getName();
+ Result += "\", ";
+
+ QualType IVQT = IvarDecl->getType();
+ if (IvarDecl->isBitField())
+ IVQT = RewriteObj.GetGroupRecordTypeForObjCIvarBitfield(IvarDecl);
+
std::string IvarTypeString, QuoteIvarTypeString;
- Context->getObjCEncodingForType(IvarDecl->getType(), IvarTypeString,
+ Context->getObjCEncodingForType(IVQT, 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;
+ unsigned Align = Context->getTypeAlign(IVQT)/8;
Align = llvm::Log2_32(Align);
Result += llvm::utostr(Align); Result += ", ";
- CharUnits Size = Context->getTypeSizeInChars(IvarDecl->getType());
+ CharUnits Size = Context->getTypeSizeInChars(IVQT);
Result += llvm::utostr(Size.getQuantity());
if (i == e-1)
Result += "}}\n";
@@ -7306,11 +7541,8 @@ void RewriteModernObjC::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl,
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;
+ ObjCCategoryDecl *CDecl
+ = ClassDecl->FindCategoryDeclaration(IDecl->getIdentifier());
std::string FullCategoryName = ClassDecl->getNameAsString();
FullCategoryName += "_$_";
@@ -7522,7 +7754,10 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
// Build name of symbol holding ivar offset.
std::string IvarOffsetName;
- WriteInternalIvarName(clsDeclared, D, IvarOffsetName);
+ if (D->isBitField())
+ ObjCIvarBitfieldGroupOffset(D, IvarOffsetName);
+ else
+ WriteInternalIvarName(clsDeclared, D, IvarOffsetName);
ReferencedIvars[clsDeclared].insert(D);
@@ -7533,7 +7768,7 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
BaseExpr);
VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
SourceLocation(), &Context->Idents.get(IvarOffsetName),
- Context->UnsignedLongTy, 0, SC_Extern, SC_None);
+ Context->UnsignedLongTy, 0, SC_Extern);
DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, false,
Context->UnsignedLongTy, VK_LValue,
SourceLocation());
@@ -7546,6 +7781,8 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
SourceLocation(),
addExpr);
QualType IvarT = D->getType();
+ if (D->isBitField())
+ IvarT = GetGroupRecordTypeForObjCIvarBitfield(D);
if (!isa<TypedefType>(IvarT) && IvarT->isRecordType()) {
RecordDecl *RD = IvarT->getAs<RecordType>()->getDecl();
@@ -7598,8 +7835,23 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
PE = new (Context) ParenExpr(OldRange.getBegin(),
OldRange.getEnd(),
Exp);
+
+ if (D->isBitField()) {
+ FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(),
+ SourceLocation(),
+ &Context->Idents.get(D->getNameAsString()),
+ D->getType(), 0,
+ /*BitWidth=*/D->getBitWidth(),
+ /*Mutable=*/true,
+ ICIS_NoInit);
+ MemberExpr *ME = new (Context) MemberExpr(PE, /*isArrow*/false, FD, SourceLocation(),
+ FD->getType(), VK_LValue,
+ OK_Ordinary);
+ Replacement = ME;
- Replacement = PE;
+ }
+ else
+ Replacement = PE;
}
ReplaceStmtWithRange(IV, Replacement, OldRange);
diff --git a/lib/Rewrite/Frontend/RewriteObjC.cpp b/lib/Rewrite/Frontend/RewriteObjC.cpp
index a6dcc6b..2f5cd0f 100644
--- a/lib/Rewrite/Frontend/RewriteObjC.cpp
+++ b/lib/Rewrite/Frontend/RewriteObjC.cpp
@@ -12,20 +12,22 @@
//===----------------------------------------------------------------------===//
#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/Attr.h"
#include "clang/AST/ParentMap.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/StringExtras.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;
@@ -265,7 +267,7 @@ namespace {
void RewriteRecordBody(RecordDecl *RD);
void RewriteInclude();
void RewriteForwardClassDecl(DeclGroupRef D);
- void RewriteForwardClassDecl(const llvm::SmallVector<Decl*, 8> &DG);
+ void RewriteForwardClassDecl(const SmallVector<Decl *, 8> &DG);
void RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl,
const std::string &typedefString);
void RewriteImplementations();
@@ -283,7 +285,7 @@ namespace {
void RewriteCategoryDecl(ObjCCategoryDecl *Dcl);
void RewriteProtocolDecl(ObjCProtocolDecl *Dcl);
void RewriteForwardProtocolDecl(DeclGroupRef D);
- void RewriteForwardProtocolDecl(const llvm::SmallVector<Decl*, 8> &DG);
+ void RewriteForwardProtocolDecl(const SmallVector<Decl *, 8> &DG);
void RewriteMethodDeclaration(ObjCMethodDecl *Method);
void RewriteProperty(ObjCPropertyDecl *prop);
void RewriteFunctionDecl(FunctionDecl *FD);
@@ -483,14 +485,13 @@ namespace {
}
QualType getSimpleFunctionType(QualType result,
- const QualType *args,
- unsigned numArgs,
+ ArrayRef<QualType> args,
bool variadic = false) {
if (result == Context->getObjCInstanceType())
result = Context->getObjCIdType();
FunctionProtoType::ExtProtoInfo fpi;
fpi.Variadic = variadic;
- return Context->getFunctionType(result, args, numArgs, fpi);
+ return Context->getFunctionType(result, args, fpi);
}
// Helper function: create a CStyleCastExpr with trivial type source info.
@@ -925,8 +926,7 @@ void RewriteObjC::RewriteForwardClassDecl(DeclGroupRef D) {
RewriteForwardClassEpilogue(cast<ObjCInterfaceDecl>(*I), typedefString);
}
-void RewriteObjC::RewriteForwardClassDecl(
- const llvm::SmallVector<Decl*, 8> &D) {
+void RewriteObjC::RewriteForwardClassDecl(const SmallVector<Decl *, 8> &D) {
std::string typedefString;
for (unsigned i = 0; i < D.size(); i++) {
ObjCInterfaceDecl *ForwardDecl = cast<ObjCInterfaceDecl>(D[i]);
@@ -1038,7 +1038,7 @@ void RewriteObjC::RewriteForwardProtocolDecl(DeclGroupRef D) {
}
void
-RewriteObjC::RewriteForwardProtocolDecl(const llvm::SmallVector<Decl*, 8> &DG) {
+RewriteObjC::RewriteForwardProtocolDecl(const SmallVector<Decl *, 8> &DG) {
SourceLocation LocStart = DG[0]->getLocStart();
if (LocStart.isInvalid())
llvm_unreachable("Invalid SourceLocation");
@@ -2262,13 +2262,12 @@ void RewriteObjC::SynthSelGetUidFunctionDecl() {
SmallVector<QualType, 16> ArgTys;
ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));
QualType getFuncType =
- getSimpleFunctionType(Context->getObjCSelType(), &ArgTys[0], ArgTys.size());
+ getSimpleFunctionType(Context->getObjCSelType(), ArgTys);
SelGetUidFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- SelGetUidIdent, getFuncType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ SelGetUidIdent, getFuncType, 0,
+ SC_Extern);
}
void RewriteObjC::RewriteFunctionDecl(FunctionDecl *FD) {
@@ -2359,13 +2358,12 @@ void RewriteObjC::SynthSuperContructorFunctionDecl() {
ArgTys.push_back(argT);
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size());
+ ArgTys);
SuperContructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ msgSendIdent, msgSendType,
+ 0, SC_Extern);
}
// SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...);
@@ -2379,14 +2377,12 @@ void RewriteObjC::SynthMsgSendFunctionDecl() {
assert(!argT.isNull() && "Can't find 'SEL' type");
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size(),
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ msgSendIdent, msgSendType, 0,
+ SC_Extern);
}
// SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(struct objc_super *, SEL op, ...);
@@ -2403,14 +2399,12 @@ void RewriteObjC::SynthMsgSendSuperFunctionDecl() {
assert(!argT.isNull() && "Can't find 'SEL' type");
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size(),
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ msgSendIdent, msgSendType, 0,
+ SC_Extern);
}
// SynthMsgSendStretFunctionDecl - id objc_msgSend_stret(id self, SEL op, ...);
@@ -2424,14 +2418,12 @@ void RewriteObjC::SynthMsgSendStretFunctionDecl() {
assert(!argT.isNull() && "Can't find 'SEL' type");
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size(),
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ msgSendIdent, msgSendType, 0,
+ SC_Extern);
}
// SynthMsgSendSuperStretFunctionDecl -
@@ -2450,14 +2442,13 @@ void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() {
assert(!argT.isNull() && "Can't find 'SEL' type");
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size(),
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendSuperStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern,
- SC_None, false);
+ msgSendIdent,
+ msgSendType, 0,
+ SC_Extern);
}
// SynthMsgSendFpretFunctionDecl - double objc_msgSend_fpret(id self, SEL op, ...);
@@ -2471,14 +2462,12 @@ void RewriteObjC::SynthMsgSendFpretFunctionDecl() {
assert(!argT.isNull() && "Can't find 'SEL' type");
ArgTys.push_back(argT);
QualType msgSendType = getSimpleFunctionType(Context->DoubleTy,
- &ArgTys[0], ArgTys.size(),
- true /*isVariadic*/);
+ ArgTys, /*isVariadic=*/true);
MsgSendFpretFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- msgSendIdent, msgSendType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ msgSendIdent, msgSendType, 0,
+ SC_Extern);
}
// SynthGetClassFunctionDecl - id objc_getClass(const char *name);
@@ -2487,13 +2476,12 @@ void RewriteObjC::SynthGetClassFunctionDecl() {
SmallVector<QualType, 16> ArgTys;
ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));
QualType getClassType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size());
+ ArgTys);
GetClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- getClassIdent, getClassType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ getClassIdent, getClassType, 0,
+ SC_Extern);
}
// SynthGetSuperClassFunctionDecl - Class class_getSuperclass(Class cls);
@@ -2503,15 +2491,13 @@ void RewriteObjC::SynthGetSuperClassFunctionDecl() {
SmallVector<QualType, 16> ArgTys;
ArgTys.push_back(Context->getObjCClassType());
QualType getClassType = getSimpleFunctionType(Context->getObjCClassType(),
- &ArgTys[0], ArgTys.size());
+ ArgTys);
GetSuperClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
SourceLocation(),
SourceLocation(),
getSuperClassIdent,
getClassType, 0,
- SC_Extern,
- SC_None,
- false);
+ SC_Extern);
}
// SynthGetMetaClassFunctionDecl - id objc_getMetaClass(const char *name);
@@ -2520,13 +2506,12 @@ void RewriteObjC::SynthGetMetaClassFunctionDecl() {
SmallVector<QualType, 16> ArgTys;
ArgTys.push_back(Context->getPointerType(Context->CharTy.withConst()));
QualType getClassType = getSimpleFunctionType(Context->getObjCIdType(),
- &ArgTys[0], ArgTys.size());
+ ArgTys);
GetMetaClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl,
- SourceLocation(),
- SourceLocation(),
- getClassIdent, getClassType, 0,
- SC_Extern,
- SC_None, false);
+ SourceLocation(),
+ SourceLocation(),
+ getClassIdent, getClassType,
+ 0, SC_Extern);
}
Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
@@ -2539,7 +2524,7 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
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'))
+ if (!isAlphanumeric(c))
tmpName[i] = '_';
}
S += tmpName;
@@ -2559,7 +2544,7 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
SourceLocation(), &Context->Idents.get(S),
- strType, 0, SC_Static, SC_None);
+ strType, 0, SC_Static);
DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, false, strType, VK_LValue,
SourceLocation());
Expr *Unop = new (Context) UnaryOperator(DRE, UO_AddrOf,
@@ -2651,8 +2636,9 @@ CallExpr *RewriteObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFlavo
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);
+ QualType castType = getSimpleFunctionType(returnType, ArgTypes,
+ Method ? Method->isVariadic()
+ : false);
castType = Context->getPointerType(castType);
cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast,
cast);
@@ -3033,10 +3019,10 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp,
CK_BitCast, DRE);
// Now do the "normal" pointer to function cast.
+ // If we don't have a method decl, force a variadic cast.
+ const ObjCMethodDecl *MD = Exp->getMethodDecl();
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);
+ getSimpleFunctionType(returnType, ArgTypes, MD ? MD->isVariadic() : true);
castType = Context->getPointerType(castType);
cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_BitCast,
cast);
@@ -3126,7 +3112,7 @@ Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) {
IdentifierInfo *ID = &Context->Idents.get(Name);
VarDecl *VD = VarDecl::Create(*Context, TUDecl, SourceLocation(),
SourceLocation(), ID, getProtocolType(), 0,
- SC_Extern, SC_None);
+ SC_Extern);
DeclRefExpr *DRE = new (Context) DeclRefExpr(VD, false, getProtocolType(),
VK_LValue, SourceLocation());
Expr *DerefExpr = new (Context) UnaryOperator(DRE, UO_AddrOf,
@@ -3815,7 +3801,7 @@ QualType RewriteObjC::convertFunctionTypeOfBlocks(const FunctionType *FT) {
// 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());
+ FuncType = getSimpleFunctionType(Res, ArgTypes);
else FuncType = QualType(FT, 0);
return FuncType;
}
@@ -3882,8 +3868,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
}
}
// Now do the pointer to function cast.
- QualType PtrToFuncCastType
- = getSimpleFunctionType(Exp->getType(), &ArgTypes[0], ArgTypes.size());
+ QualType PtrToFuncCastType = getSimpleFunctionType(Exp->getType(), ArgTypes);
PtrToFuncCastType = Context->getPointerType(PtrToFuncCastType);
@@ -4309,7 +4294,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
// Add void *__Block_byref_id_object_copy;
// void *__Block_byref_id_object_dispose; if needed.
QualType Ty = ND->getType();
- bool HasCopyAndDispose = Context->BlockRequiresCopying(Ty);
+ bool HasCopyAndDispose = Context->BlockRequiresCopying(Ty, ND);
if (HasCopyAndDispose) {
ByrefType += " void (*__Block_byref_id_object_copy)(void*, void*);\n";
ByrefType += " void (*__Block_byref_id_object_dispose)(void*);\n";
@@ -4463,7 +4448,7 @@ FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(StringRef name) {
QualType FType = Context->getFunctionNoProtoType(Context->VoidPtrTy);
return FunctionDecl::Create(*Context, TUDecl, SourceLocation(),
SourceLocation(), ID, FType, 0, SC_Extern,
- SC_None, false, false);
+ false, false);
}
Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
@@ -4547,7 +4532,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp,
SourceLocation(), SourceLocation(),
&Context->Idents.get(DescData.c_str()),
Context->VoidPtrTy, 0,
- SC_Static, SC_None);
+ SC_Static);
UnaryOperator *DescRefExpr =
new (Context) UnaryOperator(new (Context) DeclRefExpr(NewVD, false,
Context->VoidPtrTy,
@@ -5754,11 +5739,8 @@ void RewriteObjCFragileABI::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *ID
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;
+ ObjCCategoryDecl *CDecl
+ = ClassDecl->FindCategoryDeclaration(IDecl->getIdentifier());
std::string FullCategoryName = ClassDecl->getNameAsString();
FullCategoryName += '_';
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp
index 801a1b1..00d3c47 100644
--- a/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/lib/Sema/AnalysisBasedWarnings.cpp
@@ -14,42 +14,43 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/AnalysisBasedWarnings.h"
-#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/ScopeInfo.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/SourceLocation.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/Lexer.h"
-#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclCXX.h"
-#include "clang/AST/ExprObjC.h"
-#include "clang/AST/ExprCXX.h"
-#include "clang/AST/StmtObjC.h"
-#include "clang/AST/StmtCXX.h"
+#include "clang/AST/DeclObjC.h"
#include "clang/AST/EvaluatedExprVisitor.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
#include "clang/AST/ParentMap.h"
-#include "clang/AST/StmtVisitor.h"
#include "clang/AST/RecursiveASTVisitor.h"
-#include "clang/Analysis/AnalysisContext.h"
-#include "clang/Analysis/CFG.h"
-#include "clang/Analysis/Analyses/ReachableCode.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtObjC.h"
+#include "clang/AST/StmtVisitor.h"
#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
+#include "clang/Analysis/Analyses/ReachableCode.h"
#include "clang/Analysis/Analyses/ThreadSafety.h"
-#include "clang/Analysis/CFGStmtMap.h"
#include "clang/Analysis/Analyses/UninitializedValues.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/CFGStmtMap.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/ADT/MapVector.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"
#include <algorithm>
+#include <deque>
#include <iterator>
#include <vector>
-#include <deque>
using namespace clang;
@@ -157,7 +158,7 @@ static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) {
CFGBlock::const_reverse_iterator ri = B.rbegin(), re = B.rend();
for ( ; ri != re ; ++ri)
- if (isa<CFGStmt>(*ri))
+ if (ri->getAs<CFGStmt>())
break;
// No more CFGElements in the block?
@@ -171,7 +172,7 @@ static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) {
continue;
}
- CFGStmt CS = cast<CFGStmt>(*ri);
+ CFGStmt CS = ri->castAs<CFGStmt>();
const Stmt *S = CS.getStmt();
if (isa<ReturnStmt>(S)) {
HasLiveReturn = true;
@@ -329,8 +330,7 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body,
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
ReturnsVoid = FD->getResultType()->isVoidType();
- HasNoReturn = FD->hasAttr<NoReturnAttr>() ||
- FD->getType()->getAs<FunctionType>()->getNoReturnAttr();
+ HasNoReturn = FD->isNoReturn();
}
else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
ReturnsVoid = MD->getResultType()->isVoidType();
@@ -505,7 +505,7 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use,
StringRef Str;
SourceRange Range;
- // FixIts to suppress the diagnosic by removing the dead condition.
+ // FixIts to suppress the diagnostic by removing the dead condition.
// For all binary terminators, branch 0 is taken if the condition is true,
// and branch 1 is taken if the condition is false.
int RemoveDiagKind = -1;
@@ -703,7 +703,38 @@ namespace {
return FallthroughStmts;
}
+ void fillReachableBlocks(CFG *Cfg) {
+ assert(ReachableBlocks.empty() && "ReachableBlocks already filled");
+ std::deque<const CFGBlock *> BlockQueue;
+
+ ReachableBlocks.insert(&Cfg->getEntry());
+ BlockQueue.push_back(&Cfg->getEntry());
+ // Mark all case blocks reachable to avoid problems with switching on
+ // constants, covered enums, etc.
+ // These blocks can contain fall-through annotations, and we don't want to
+ // issue a warn_fallthrough_attr_unreachable for them.
+ for (CFG::iterator I = Cfg->begin(), E = Cfg->end(); I != E; ++I) {
+ const CFGBlock *B = *I;
+ const Stmt *L = B->getLabel();
+ if (L && isa<SwitchCase>(L) && ReachableBlocks.insert(B))
+ BlockQueue.push_back(B);
+ }
+
+ while (!BlockQueue.empty()) {
+ const CFGBlock *P = BlockQueue.front();
+ BlockQueue.pop_front();
+ for (CFGBlock::const_succ_iterator I = P->succ_begin(),
+ E = P->succ_end();
+ I != E; ++I) {
+ if (*I && ReachableBlocks.insert(*I))
+ BlockQueue.push_back(*I);
+ }
+ }
+ }
+
bool checkFallThroughIntoBlock(const CFGBlock &B, int &AnnotatedCnt) {
+ assert(!ReachableBlocks.empty() && "ReachableBlocks empty");
+
int UnannotatedCnt = 0;
AnnotatedCnt = 0;
@@ -723,16 +754,21 @@ namespace {
if (SW && SW->getSubStmt() == B.getLabel() && P->begin() == P->end())
continue; // Previous case label has no statements, good.
- if (P->pred_begin() == P->pred_end()) { // The block is unreachable.
- // This only catches trivially unreachable blocks.
- for (CFGBlock::const_iterator ElIt = P->begin(), ElEnd = P->end();
- ElIt != ElEnd; ++ElIt) {
- if (const CFGStmt *CS = ElIt->getAs<CFGStmt>()){
+ const LabelStmt *L = dyn_cast_or_null<LabelStmt>(P->getLabel());
+ if (L && L->getSubStmt() == B.getLabel() && P->begin() == P->end())
+ continue; // Case label is preceded with a normal label, good.
+
+ if (!ReachableBlocks.count(P)) {
+ for (CFGBlock::const_reverse_iterator ElemIt = P->rbegin(),
+ ElemEnd = P->rend();
+ ElemIt != ElemEnd; ++ElemIt) {
+ if (Optional<CFGStmt> CS = ElemIt->getAs<CFGStmt>()) {
if (const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) {
S.Diag(AS->getLocStart(),
diag::warn_fallthrough_attr_unreachable);
markFallthroughVisited(AS);
++AnnotatedCnt;
+ break;
}
// Don't care about other unreachable statements.
}
@@ -781,6 +817,10 @@ namespace {
return true;
}
+ // We don't want to traverse local type declarations. We analyze their
+ // methods separately.
+ bool TraverseDecl(Decl *D) { return true; }
+
private:
static const AttributedStmt *asFallThroughAttr(const Stmt *S) {
@@ -797,7 +837,7 @@ namespace {
for (CFGBlock::const_reverse_iterator ElemIt = B.rbegin(),
ElemEnd = B.rend();
ElemIt != ElemEnd; ++ElemIt) {
- if (const CFGStmt *CS = ElemIt->getAs<CFGStmt>())
+ if (Optional<CFGStmt> CS = ElemIt->getAs<CFGStmt>())
return CS->getStmt();
}
// Workaround to detect a statement thrown out by CFGBuilder:
@@ -813,6 +853,7 @@ namespace {
bool FoundSwitchStatements;
AttrStmts FallthroughStmts;
Sema &S;
+ llvm::SmallPtrSet<const CFGBlock *, 16> ReachableBlocks;
};
}
@@ -827,7 +868,7 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
//
// 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)
+ if (!AC.getASTContext().getLangOpts().CPlusPlus11)
return;
FallthroughMapper FM(S);
@@ -844,16 +885,18 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
if (!Cfg)
return;
- int AnnotatedCnt;
+ FM.fillReachableBlocks(Cfg);
for (CFG::reverse_iterator I = Cfg->rbegin(), E = Cfg->rend(); I != E; ++I) {
- const CFGBlock &B = **I;
- const Stmt *Label = B.getLabel();
+ const CFGBlock *B = *I;
+ const Stmt *Label = B->getLabel();
if (!Label || !isa<SwitchCase>(Label))
continue;
- if (!FM.checkFallThroughIntoBlock(B, AnnotatedCnt))
+ int AnnotatedCnt;
+
+ if (!FM.checkFallThroughIntoBlock(*B, AnnotatedCnt))
continue;
S.Diag(Label->getLocStart(),
@@ -864,9 +907,14 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
SourceLocation L = Label->getLocStart();
if (L.isMacroID())
continue;
- if (S.getLangOpts().CPlusPlus0x) {
- const Stmt *Term = B.getTerminator();
- if (!(B.empty() && Term && isa<BreakStmt>(Term))) {
+ if (S.getLangOpts().CPlusPlus11) {
+ const Stmt *Term = B->getTerminator();
+ // Skip empty cases.
+ while (B->empty() && !Term && B->succ_size() == 1) {
+ B = *B->succ_begin();
+ Term = B->getTerminator();
+ }
+ if (!(B->empty() && Term && isa<BreakStmt>(Term))) {
Preprocessor &PP = S.getPreprocessor();
TokenValue Tokens[] = {
tok::l_square, tok::l_square, PP.getIdentifierInfo("clang"),
@@ -1106,7 +1154,11 @@ struct SLocSort {
class UninitValsDiagReporter : public UninitVariablesHandler {
Sema &S;
typedef SmallVector<UninitUse, 2> UsesVec;
- typedef llvm::DenseMap<const VarDecl *, std::pair<UsesVec*, bool> > UsesMap;
+ typedef std::pair<UsesVec*, bool> MappedType;
+ // Prefer using MapVector to DenseMap, so that iteration order will be
+ // the same as insertion order. This is needed to obtain a deterministic
+ // order of diagnostics when calling flushDiagnostics().
+ typedef llvm::MapVector<const VarDecl *, MappedType> UsesMap;
UsesMap *uses;
public:
@@ -1115,11 +1167,11 @@ public:
flushDiagnostics();
}
- std::pair<UsesVec*, bool> &getUses(const VarDecl *vd) {
+ MappedType &getUses(const VarDecl *vd) {
if (!uses)
uses = new UsesMap();
- UsesMap::mapped_type &V = (*uses)[vd];
+ MappedType &V = (*uses)[vd];
UsesVec *&vec = V.first;
if (!vec)
vec = new UsesVec();
@@ -1138,12 +1190,10 @@ public:
void flushDiagnostics() {
if (!uses)
return;
-
- // FIXME: This iteration order, and thus the resulting diagnostic order,
- // is nondeterministic.
+
for (UsesMap::iterator i = uses->begin(), e = uses->end(); i != e; ++i) {
const VarDecl *vd = i->first;
- const UsesMap::mapped_type &V = i->second;
+ const MappedType &V = i->second;
UsesVec *vec = V.first;
bool hasSelfInit = V.second;
@@ -1198,7 +1248,7 @@ private:
//===----------------------------------------------------------------------===//
namespace clang {
namespace thread_safety {
-typedef llvm::SmallVector<PartialDiagnosticAt, 1> OptionalNotes;
+typedef SmallVector<PartialDiagnosticAt, 1> OptionalNotes;
typedef std::pair<PartialDiagnosticAt, OptionalNotes> DelayedDiag;
typedef std::list<DelayedDiag> DiagList;
@@ -1423,7 +1473,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
if (cast<DeclContext>(D)->isDependentContext())
return;
- if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred()) {
+ if (Diags.hasUncompilableErrorOccurred() || Diags.hasFatalErrorOccurred()) {
// Flush out any possibly unreachable diagnostics.
flushDiagnostics(S, fscope);
return;
@@ -1544,6 +1594,10 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
SourceLocation FL = AC.getDecl()->getLocation();
SourceLocation FEL = AC.getDecl()->getLocEnd();
thread_safety::ThreadSafetyReporter Reporter(S, FL, FEL);
+ if (Diags.getDiagnosticLevel(diag::warn_thread_safety_beta,D->getLocStart())
+ != DiagnosticsEngine::Ignored)
+ Reporter.setIssueBetaWarnings(true);
+
thread_safety::runThreadSafetyAnalysis(AC, Reporter);
Reporter.emitDiagnostics();
}
diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp
index 7c79879..e227d4e 100644
--- a/lib/Sema/AttributeList.cpp
+++ b/lib/Sema/AttributeList.cpp
@@ -15,8 +15,8 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/IdentifierTable.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringSwitch.h"
using namespace clang;
size_t AttributeList::allocated_size() const {
@@ -125,3 +125,14 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name,
return ::getAttrKind(Buf);
}
+
+unsigned AttributeList::getAttributeSpellingListIndex() const {
+ // Both variables will be used in tablegen generated
+ // attribute spell list index matching code.
+ StringRef Name = AttrName->getName();
+ StringRef Scope = ScopeName ? ScopeName->getName() : "";
+
+#include "clang/Sema/AttrSpellingListIndex.inc"
+
+}
+
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index 7cfe3ae..e92f767 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -38,6 +38,7 @@ add_clang_library(clangSema
SemaLambda.cpp
SemaLookup.cpp
SemaObjCProperty.cpp
+ SemaOpenMP.cpp
SemaOverload.cpp
SemaPseudoObject.cpp
SemaStmt.cpp
@@ -58,6 +59,7 @@ add_dependencies(clangSema
ClangAttrList
ClangAttrParsedAttrList
ClangAttrParsedAttrKinds
+ ClangAttrSpellingListIndex
ClangAttrTemplateInstantiate
ClangCommentNodes
ClangDeclNodes
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp
index 0a23601..19be1cb 100644
--- a/lib/Sema/CodeCompleteConsumer.cpp
+++ b/lib/Sema/CodeCompleteConsumer.cpp
@@ -11,15 +11,15 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Sema/CodeCompleteConsumer.h"
-#include "clang/Sema/Scope.h"
-#include "clang/Sema/Sema.h"
+#include "clang-c/Index.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Lex/Preprocessor.h"
-#include "clang-c/Index.h"
-#include "llvm/ADT/SmallString.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/Sema.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
@@ -267,8 +267,8 @@ const char *CodeCompletionAllocator::CopyString(Twine String) {
return CopyString(String.toStringRef(Data));
}
-StringRef CodeCompletionTUInfo::getParentName(DeclContext *DC) {
- NamedDecl *ND = dyn_cast<NamedDecl>(DC);
+StringRef CodeCompletionTUInfo::getParentName(const DeclContext *DC) {
+ const NamedDecl *ND = dyn_cast<NamedDecl>(DC);
if (!ND)
return StringRef();
@@ -283,9 +283,9 @@ StringRef CodeCompletionTUInfo::getParentName(DeclContext *DC) {
return StringRef();
// Find the interesting names.
- llvm::SmallVector<DeclContext *, 2> Contexts;
+ SmallVector<const DeclContext *, 2> Contexts;
while (DC && !DC->isFunctionOrMethod()) {
- if (NamedDecl *ND = dyn_cast<NamedDecl>(DC)) {
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(DC)) {
if (ND->getIdentifier())
Contexts.push_back(DC);
}
@@ -294,7 +294,7 @@ StringRef CodeCompletionTUInfo::getParentName(DeclContext *DC) {
}
{
- llvm::SmallString<128> S;
+ SmallString<128> S;
llvm::raw_svector_ostream OS(S);
bool First = true;
for (unsigned I = Contexts.size(); I != 0; --I) {
@@ -304,12 +304,12 @@ StringRef CodeCompletionTUInfo::getParentName(DeclContext *DC) {
OS << "::";
}
- DeclContext *CurDC = Contexts[I-1];
- if (ObjCCategoryImplDecl *CatImpl = dyn_cast<ObjCCategoryImplDecl>(CurDC))
+ const DeclContext *CurDC = Contexts[I-1];
+ if (const ObjCCategoryImplDecl *CatImpl = dyn_cast<ObjCCategoryImplDecl>(CurDC))
CurDC = CatImpl->getCategoryDecl();
- if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(CurDC)) {
- ObjCInterfaceDecl *Interface = Cat->getClassInterface();
+ if (const ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(CurDC)) {
+ const ObjCInterfaceDecl *Interface = Cat->getClassInterface();
if (!Interface) {
// Assign an empty StringRef but with non-null data to distinguish
// between empty because we didn't process the DeclContext yet.
@@ -377,7 +377,7 @@ void CodeCompletionBuilder::AddChunk(CodeCompletionString::ChunkKind CK,
Chunks.push_back(Chunk(CK, Text));
}
-void CodeCompletionBuilder::addParentContext(DeclContext *DC) {
+void CodeCompletionBuilder::addParentContext(const DeclContext *DC) {
if (DC->isTranslationUnit()) {
return;
}
@@ -385,7 +385,7 @@ void CodeCompletionBuilder::addParentContext(DeclContext *DC) {
if (DC->isFunctionOrMethod())
return;
- NamedDecl *ND = dyn_cast<NamedDecl>(DC);
+ const NamedDecl *ND = dyn_cast<NamedDecl>(DC);
if (!ND)
return;
@@ -396,33 +396,6 @@ void CodeCompletionBuilder::addBriefComment(StringRef Comment) {
BriefComment = Allocator.CopyString(Comment);
}
-unsigned CodeCompletionResult::getPriorityFromDecl(NamedDecl *ND) {
- if (!ND)
- return CCP_Unlikely;
-
- // Context-based decisions.
- DeclContext *DC = ND->getDeclContext()->getRedeclContext();
- if (DC->isFunctionOrMethod() || isa<BlockDecl>(DC)) {
- // _cmd is relatively rare
- if (ImplicitParamDecl *ImplicitParam = dyn_cast<ImplicitParamDecl>(ND))
- if (ImplicitParam->getIdentifier() &&
- ImplicitParam->getIdentifier()->isStr("_cmd"))
- return CCP_ObjC_cmd;
-
- return CCP_LocalDeclaration;
- }
- if (DC->isRecord() || isa<ObjCContainerDecl>(DC))
- return CCP_MemberDeclaration;
-
- // Content-based decisions.
- if (isa<EnumConstantDecl>(ND))
- return CCP_Constant;
- if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND))
- return CCP_Type;
-
- return CCP_Declaration;
-}
-
//===----------------------------------------------------------------------===//
// Code completion overload candidate implementation
//===----------------------------------------------------------------------===//
@@ -526,7 +499,7 @@ PrintingCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef,
}
/// \brief Retrieve the effective availability of the given declaration.
-static AvailabilityResult getDeclAvailability(Decl *D) {
+static AvailabilityResult getDeclAvailability(const Decl *D) {
AvailabilityResult AR = D->getAvailability();
if (isa<EnumConstantDecl>(D))
AR = std::max(AR, cast<Decl>(D->getDeclContext())->getAvailability());
@@ -559,7 +532,7 @@ void CodeCompletionResult::computeCursorKindAndAvailability(bool Accessible) {
break;
}
- if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Declaration))
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(Declaration))
if (Function->isDeleted())
Availability = CXAvailability_NotAvailable;
diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp
index b3066eb..e1d55db 100644
--- a/lib/Sema/DeclSpec.cpp
+++ b/lib/Sema/DeclSpec.cpp
@@ -11,18 +11,18 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Parse/ParseDiagnostic.h" // FIXME: remove this back-dependency!
#include "clang/Sema/DeclSpec.h"
-#include "clang/Sema/LocInfoType.h"
-#include "clang/Sema/ParsedTemplate.h"
-#include "clang/Sema/SemaDiagnostic.h"
-#include "clang/Sema/Sema.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/TypeLoc.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/ParseDiagnostic.h" // FIXME: remove this back-dependency!
+#include "clang/Sema/LocInfoType.h"
+#include "clang/Sema/ParsedTemplate.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/ErrorHandling.h"
#include <cstring>
@@ -169,6 +169,9 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto,
SourceLocation LocalRangeEnd,
Declarator &TheDeclarator,
TypeResult TrailingReturnType) {
+ assert(!(TypeQuals & DeclSpec::TQ_atomic) &&
+ "function cannot have _Atomic qualifier");
+
DeclaratorChunk I;
I.Kind = Function;
I.Loc = LocalRangeBegin;
@@ -280,6 +283,14 @@ bool Declarator::isDeclarationOfFunction() const {
case TST_unspecified:
case TST_void:
case TST_wchar:
+ case TST_image1d_t:
+ case TST_image1d_array_t:
+ case TST_image1d_buffer_t:
+ case TST_image2d_t:
+ case TST_image2d_array_t:
+ case TST_image3d_t:
+ case TST_sampler_t:
+ case TST_event_t:
return false;
case TST_decltype:
@@ -323,7 +334,8 @@ unsigned DeclSpec::getParsedSpecifiers() const {
if (hasTypeSpecifier())
Res |= PQ_TypeSpecifier;
- if (FS_inline_specified || FS_virtual_specified || FS_explicit_specified)
+ if (FS_inline_specified || FS_virtual_specified || FS_explicit_specified ||
+ FS_noreturn_specified)
Res |= PQ_FunctionSpecifier;
return Res;
}
@@ -414,6 +426,14 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) {
case DeclSpec::TST_underlyingType: return "__underlying_type";
case DeclSpec::TST_unknown_anytype: return "__unknown_anytype";
case DeclSpec::TST_atomic: return "_Atomic";
+ case DeclSpec::TST_image1d_t: return "image1d_t";
+ case DeclSpec::TST_image1d_array_t: return "image1d_array_t";
+ case DeclSpec::TST_image1d_buffer_t: return "image1d_buffer_t";
+ case DeclSpec::TST_image2d_t: return "image2d_t";
+ case DeclSpec::TST_image2d_array_t: return "image2d_array_t";
+ case DeclSpec::TST_image3d_t: return "image3d_t";
+ case DeclSpec::TST_sampler_t: return "sampler_t";
+ case DeclSpec::TST_event_t: return "event_t";
case DeclSpec::TST_error: return "(error)";
}
llvm_unreachable("Unknown typespec!");
@@ -425,6 +445,7 @@ const char *DeclSpec::getSpecifierName(TQ T) {
case DeclSpec::TQ_const: return "const";
case DeclSpec::TQ_restrict: return "restrict";
case DeclSpec::TQ_volatile: return "volatile";
+ case DeclSpec::TQ_atomic: return "_Atomic";
}
llvm_unreachable("Unknown typespec!");
}
@@ -693,38 +714,44 @@ bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec,
TypeQualifiers |= T;
switch (T) {
- default: llvm_unreachable("Unknown type qualifier!");
- case TQ_const: TQ_constLoc = Loc; break;
- case TQ_restrict: TQ_restrictLoc = Loc; break;
- case TQ_volatile: TQ_volatileLoc = Loc; break;
+ case TQ_unspecified: break;
+ case TQ_const: TQ_constLoc = Loc; return false;
+ case TQ_restrict: TQ_restrictLoc = Loc; return false;
+ case TQ_volatile: TQ_volatileLoc = Loc; return false;
+ case TQ_atomic: TQ_atomicLoc = Loc; return false;
}
- return false;
+
+ llvm_unreachable("Unknown type qualifier!");
}
-bool DeclSpec::SetFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec,
- unsigned &DiagID) {
+bool DeclSpec::setFunctionSpecInline(SourceLocation Loc) {
// 'inline inline' is ok.
FS_inline_specified = true;
FS_inlineLoc = Loc;
return false;
}
-bool DeclSpec::SetFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec,
- unsigned &DiagID) {
+bool DeclSpec::setFunctionSpecVirtual(SourceLocation Loc) {
// 'virtual virtual' is ok.
FS_virtual_specified = true;
FS_virtualLoc = Loc;
return false;
}
-bool DeclSpec::SetFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec,
- unsigned &DiagID) {
+bool DeclSpec::setFunctionSpecExplicit(SourceLocation Loc) {
// 'explicit explicit' is ok.
FS_explicit_specified = true;
FS_explicitLoc = Loc;
return false;
}
+bool DeclSpec::setFunctionSpecNoreturn(SourceLocation Loc) {
+ // '_Noreturn _Noreturn' is ok.
+ FS_noreturn_specified = true;
+ FS_noreturnLoc = Loc;
+ return false;
+}
+
bool DeclSpec::SetFriendSpec(SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID) {
if (Friend_specified) {
@@ -763,9 +790,10 @@ void DeclSpec::setProtocolQualifiers(Decl * const *Protos,
SourceLocation *ProtoLocs,
SourceLocation LAngleLoc) {
if (NP == 0) return;
- ProtocolQualifiers = new Decl*[NP];
+ Decl **ProtoQuals = new Decl*[NP];
+ memcpy(ProtoQuals, Protos, sizeof(Decl*)*NP);
+ ProtocolQualifiers = ProtoQuals;
ProtocolLocs = new SourceLocation[NP];
- memcpy((void*)ProtocolQualifiers, Protos, sizeof(Decl*)*NP);
memcpy(ProtocolLocs, ProtoLocs, sizeof(SourceLocation)*NP);
NumProtocolQualifiers = NP;
ProtocolLAngleLoc = LAngleLoc;
@@ -787,15 +815,6 @@ void DeclSpec::SaveWrittenBuiltinSpecs() {
}
}
-void DeclSpec::SaveStorageSpecifierAsWritten() {
- if (SCS_extern_in_linkage_spec && StorageClassSpec == SCS_extern)
- // If 'extern' is part of a linkage specification,
- // then it is not a storage class "as written".
- StorageClassSpecAsWritten = SCS_unspecified;
- else
- StorageClassSpecAsWritten = StorageClassSpec;
-}
-
/// Finish - This does final analysis of the declspec, rejecting things like
/// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or
/// diag::NUM_DIAGNOSTICS if there is no error. After calling this method,
@@ -803,7 +822,6 @@ void DeclSpec::SaveStorageSpecifierAsWritten() {
void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) {
// Before possibly changing their values, save specs as written.
SaveWrittenBuiltinSpecs();
- SaveStorageSpecifierAsWritten();
// Check the type specifier components first.
@@ -913,15 +931,15 @@ void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP) {
if (PP.getLangOpts().CPlusPlus && !PP.getLangOpts().MicrosoftExt &&
TypeSpecType == TST_unspecified && StorageClassSpec == SCS_auto) {
TypeSpecType = TST_auto;
- StorageClassSpec = StorageClassSpecAsWritten = SCS_unspecified;
+ StorageClassSpec = SCS_unspecified;
TSTLoc = TSTNameLoc = StorageClassSpecLoc;
StorageClassSpecLoc = SourceLocation();
}
// Diagnose if we've recovered from an ill-formed 'auto' storage class
// specifier in a pre-C++0x dialect of C++.
- if (!PP.getLangOpts().CPlusPlus0x && TypeSpecType == TST_auto)
+ if (!PP.getLangOpts().CPlusPlus11 && TypeSpecType == TST_auto)
Diag(D, TSTLoc, diag::ext_auto_type_specifier);
- if (PP.getLangOpts().CPlusPlus && !PP.getLangOpts().CPlusPlus0x &&
+ if (PP.getLangOpts().CPlusPlus && !PP.getLangOpts().CPlusPlus11 &&
StorageClassSpec == SCS_auto)
Diag(D, StorageClassSpecLoc, diag::warn_auto_storage_class)
<< FixItHint::CreateRemoval(StorageClassSpecLoc);
diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp
index 7d55304..d44c1fb 100644
--- a/lib/Sema/IdentifierResolver.cpp
+++ b/lib/Sema/IdentifierResolver.cpp
@@ -13,12 +13,11 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/IdentifierResolver.h"
-#include "clang/Sema/Scope.h"
#include "clang/AST/Decl.h"
-#include "clang/AST/DeclObjC.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Lex/ExternalPreprocessorSource.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Scope.h"
using namespace clang;
@@ -108,8 +107,7 @@ IdentifierResolver::~IdentifierResolver() {
/// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true
/// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns
/// true if 'D' belongs to the given declaration context.
-bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx,
- ASTContext &Context, Scope *S,
+bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S,
bool ExplicitInstantiationOrSpecialization) const {
Ctx = Ctx->getRedeclContext();
@@ -304,6 +302,14 @@ static DeclMatchKind compareDeclarations(NamedDecl *Existing, NamedDecl *New) {
// If the declarations are redeclarations of each other, keep the newest one.
if (Existing->getCanonicalDecl() == New->getCanonicalDecl()) {
+ // If either of these is the most recent declaration, use it.
+ Decl *MostRecent = Existing->getMostRecentDecl();
+ if (Existing == MostRecent)
+ return DMK_Ignore;
+
+ if (New == MostRecent)
+ return DMK_Replace;
+
// If the existing declaration is somewhere in the previous declaration
// chain of the new declaration, then prefer the new declaration.
for (Decl::redecl_iterator RD = New->redecls_begin(),
diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp
index e2ec1cc..5f92cff 100644
--- a/lib/Sema/JumpDiagnostics.cpp
+++ b/lib/Sema/JumpDiagnostics.cpp
@@ -16,8 +16,8 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
-#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtObjC.h"
#include "llvm/ADT/BitVector.h"
using namespace clang;
@@ -511,8 +511,14 @@ void JumpScopeChecker::VerifyJumps() {
for (SwitchCase *SC = SS->getSwitchCaseList(); SC;
SC = SC->getNextSwitchCase()) {
assert(LabelAndGotoScopes.count(SC) && "Case not visited?");
- CheckJump(SS, SC, SC->getLocStart(),
- diag::err_switch_into_protected_scope, 0,
+ SourceLocation Loc;
+ if (CaseStmt *CS = dyn_cast<CaseStmt>(SC))
+ Loc = CS->getLocStart();
+ else if (DefaultStmt *DS = dyn_cast<DefaultStmt>(SC))
+ Loc = DS->getLocStart();
+ else
+ Loc = SC->getLocStart();
+ CheckJump(SS, SC, Loc, diag::err_switch_into_protected_scope, 0,
diag::warn_cxx98_compat_switch_into_protected_scope);
}
}
@@ -668,7 +674,7 @@ static bool IsMicrosoftJumpWarning(unsigned JumpDiag, unsigned InDiagNote) {
/// Return true if a particular note should be downgraded to a compatibility
/// warning in C++11 mode.
static bool IsCXX98CompatWarning(Sema &S, unsigned InDiagNote) {
- return S.getLangOpts().CPlusPlus0x &&
+ return S.getLangOpts().CPlusPlus11 &&
InDiagNote == diag::note_protected_by_variable_non_pod;
}
diff --git a/lib/Sema/MultiplexExternalSemaSource.cpp b/lib/Sema/MultiplexExternalSemaSource.cpp
index f930fb3..d85624b 100644
--- a/lib/Sema/MultiplexExternalSemaSource.cpp
+++ b/lib/Sema/MultiplexExternalSemaSource.cpp
@@ -11,7 +11,6 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Sema/MultiplexExternalSemaSource.h"
-
#include "clang/AST/DeclContextInternals.h"
#include "clang/Sema/Lookup.h"
@@ -82,19 +81,12 @@ CXXBaseSpecifier *MultiplexExternalSemaSource::GetExternalCXXBaseSpecifiers(
return 0;
}
-DeclContextLookupResult MultiplexExternalSemaSource::
+bool 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();
+ bool AnyDeclsFound = false;
+ for (size_t i = 0; i < Sources.size(); ++i)
+ AnyDeclsFound |= Sources[i]->FindExternalVisibleDeclsByName(DC, Name);
+ return AnyDeclsFound;
}
void MultiplexExternalSemaSource::completeVisibleDeclsMap(const DeclContext *DC){
@@ -201,6 +193,12 @@ void MultiplexExternalSemaSource::ReadKnownNamespaces(
for(size_t i = 0; i < Sources.size(); ++i)
Sources[i]->ReadKnownNamespaces(Namespaces);
}
+
+void MultiplexExternalSemaSource::ReadUndefinedButUsed(
+ llvm::DenseMap<NamedDecl*, SourceLocation> &Undefined){
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->ReadUndefinedButUsed(Undefined);
+}
bool MultiplexExternalSemaSource::LookupUnqualified(LookupResult &R, Scope *S){
for(size_t i = 0; i < Sources.size(); ++i)
@@ -239,10 +237,10 @@ void MultiplexExternalSemaSource::ReadDynamicClasses(
Sources[i]->ReadDynamicClasses(Decls);
}
-void MultiplexExternalSemaSource::ReadLocallyScopedExternalDecls(
+void MultiplexExternalSemaSource::ReadLocallyScopedExternCDecls(
SmallVectorImpl<NamedDecl*> &Decls) {
for(size_t i = 0; i < Sources.size(); ++i)
- Sources[i]->ReadLocallyScopedExternalDecls(Decls);
+ Sources[i]->ReadLocallyScopedExternCDecls(Decls);
}
void MultiplexExternalSemaSource::ReadReferencedSelectors(
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 13a33b7..6bab9e8 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -13,21 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/DelayedDiagnostic.h"
#include "TargetAttributesSema.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/SmallSet.h"
-#include "llvm/ADT/APFloat.h"
-#include "llvm/Support/CrashRecoveryContext.h"
-#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"
-#include "clang/Sema/ScopeInfo.h"
-#include "clang/Sema/SemaConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/DeclCXX.h"
@@ -36,11 +22,25 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
-#include "clang/Lex/HeaderSearch.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/CXXFieldCollector.h"
+#include "clang/Sema/DelayedDiagnostic.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"
+#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/SemaConsumer.h"
+#include "clang/Sema/TemplateDeduction.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/Support/CrashRecoveryContext.h"
using namespace clang;
using namespace sema;
@@ -49,13 +49,14 @@ PrintingPolicy Sema::getPrintingPolicy(const ASTContext &Context,
PrintingPolicy Policy = Context.getPrintingPolicy();
Policy.Bool = Context.getLangOpts().Bool;
if (!Policy.Bool) {
- if (MacroInfo *BoolMacro = PP.getMacroInfo(&Context.Idents.get("bool"))) {
- Policy.Bool = BoolMacro->isObjectLike() &&
+ if (const MacroInfo *
+ BoolMacro = PP.getMacroInfo(&Context.Idents.get("bool"))) {
+ Policy.Bool = BoolMacro->isObjectLike() &&
BoolMacro->getNumTokens() == 1 &&
BoolMacro->getReplacementToken(0).is(tok::kw__Bool);
}
}
-
+
return Policy;
}
@@ -69,7 +70,7 @@ void Sema::ActOnTranslationUnitScope(Scope *S) {
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
TranslationUnitKind TUKind,
CodeCompleteConsumer *CodeCompleter)
- : TheTargetAttributesSema(0), ExternalSource(0),
+ : TheTargetAttributesSema(0), ExternalSource(0),
isMultiplexExternalSource(false), FPFeatures(pp.getLangOpts()),
LangOpts(pp.getLangOpts()), PP(pp), Context(ctxt), Consumer(consumer),
Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
@@ -83,16 +84,16 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
NSStringDecl(0), StringWithUTF8StringMethod(0),
NSArrayDecl(0), ArrayWithObjectsMethod(0),
NSDictionaryDecl(0), DictionaryWithObjectsMethod(0),
- GlobalNewDeleteDeclared(false),
+ GlobalNewDeleteDeclared(false),
TUKind(TUKind),
NumSFINAEErrors(0), InFunctionDeclarator(0),
AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false),
NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1),
CurrentInstantiationScope(0), TyposCorrected(0),
- AnalysisWarnings(*this)
+ AnalysisWarnings(*this), Ident_super(0)
{
TUScope = 0;
-
+
LoadedExternalKnownNamespaces = false;
for (unsigned I = 0; I != NSAPI::NumNSNumberLiteralMethods; ++I)
NSNumberLiteralMethods[I] = 0;
@@ -104,7 +105,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
FieldCollector.reset(new CXXFieldCollector());
// Tell diagnostics how to render things from the AST library.
- PP.getDiagnostics().SetArgToStringFn(&FormatASTNodeDiagnosticArgument,
+ PP.getDiagnostics().SetArgToStringFn(&FormatASTNodeDiagnosticArgument,
&Context);
ExprEvalContexts.push_back(
@@ -117,18 +118,18 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
void Sema::Initialize() {
// Tell the AST consumer about this Sema object.
Consumer.Initialize(Context);
-
+
// FIXME: Isn't this redundant with the initialization above?
if (SemaConsumer *SC = dyn_cast<SemaConsumer>(&Consumer))
SC->InitializeSema(*this);
-
+
// Tell the external Sema source about this Sema object.
if (ExternalSemaSource *ExternalSema
= dyn_cast_or_null<ExternalSemaSource>(Context.getExternalSource()))
ExternalSema->InitializeSema(*this);
// Initialize predefined 128-bit integer types, if needed.
- if (PP.getTargetInfo().getPointerWidth(0) >= 64) {
+ if (PP.getTargetInfo().hasInt128Type()) {
// If either of the 128-bit integer types are unavailable to name lookup,
// define them now.
DeclarationName Int128 = &Context.Idents.get("__int128_t");
@@ -139,7 +140,7 @@ void Sema::Initialize() {
if (IdResolver.begin(UInt128) == IdResolver.end())
PushOnScopeChains(Context.getUInt128Decl(), TUScope);
}
-
+
// Initialize predefined Objective-C types:
if (PP.getLangOpts().ObjC1) {
@@ -154,7 +155,7 @@ void Sema::Initialize() {
DeclarationName Id = &Context.Idents.get("id");
if (IdResolver.begin(Id) == IdResolver.end())
PushOnScopeChains(Context.getObjCIdDecl(), TUScope);
-
+
// Create the built-in typedef for 'Class'.
DeclarationName Class = &Context.Idents.get("Class");
if (IdResolver.begin(Class) == IdResolver.end())
@@ -181,7 +182,7 @@ Sema::~Sema() {
delete FunctionScopes[I];
if (FunctionScopes.size() == 1)
delete FunctionScopes[0];
-
+
// Tell the SemaConsumer to forget about us; we're going out of scope.
if (SemaConsumer *SC = dyn_cast<SemaConsumer>(&Consumer))
SC->ForgetSema();
@@ -209,7 +210,7 @@ bool Sema::makeUnavailableInSystemHeader(SourceLocation loc,
// If we're in template instantiation, it's an error.
if (!ActiveTemplateInstantiations.empty())
return false;
-
+
// If that function's not in a system header, it's an error.
if (!Context.getSourceManager().isInSystemHeader(loc))
return false;
@@ -288,13 +289,13 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty,
// If this is a derived-to-base cast to a through a virtual base, we
// need a vtable.
- if (Kind == CK_DerivedToBase &&
+ if (Kind == CK_DerivedToBase &&
BasePathInvolvesVirtualBase(*BasePath)) {
QualType T = E->getType();
if (const PointerType *Pointer = T->getAs<PointerType>())
T = Pointer->getPointeeType();
if (const RecordType *RecordTy = T->getAs<RecordType>())
- MarkVTableUsed(E->getLocStart(),
+ MarkVTableUsed(E->getLocStart(),
cast<CXXRecordDecl>(RecordTy->getDecl()));
}
@@ -328,7 +329,10 @@ CastKind Sema::ScalarTypeToBooleanCastKind(QualType ScalarTy) {
/// \brief Used to prune the decls of Sema's UnusedFileScopedDecls vector.
static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) {
- if (D->isUsed())
+ if (D->getMostRecentDecl()->isUsed())
+ return true;
+
+ if (D->hasExternalLinkage())
return true;
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
@@ -348,7 +352,7 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
// UnusedFileScopedDecls stores the first declaration.
// The declaration may have become definition so check again.
- const VarDecl *DeclToCheck = VD->getDefinition();
+ const VarDecl *DeclToCheck = VD->getDefinition();
if (DeclToCheck)
return !SemaRef->ShouldWarnIfUnusedFileScopedDecl(DeclToCheck);
@@ -363,68 +367,91 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) {
}
namespace {
- struct UndefinedInternal {
- NamedDecl *decl;
- FullSourceLoc useLoc;
-
- UndefinedInternal(NamedDecl *decl, FullSourceLoc useLoc)
- : decl(decl), useLoc(useLoc) {}
+ struct SortUndefinedButUsed {
+ const SourceManager &SM;
+ explicit SortUndefinedButUsed(SourceManager &SM) : SM(SM) {}
+
+ bool operator()(const std::pair<NamedDecl *, SourceLocation> &l,
+ const std::pair<NamedDecl *, SourceLocation> &r) const {
+ if (l.second.isValid() && !r.second.isValid())
+ return true;
+ if (!l.second.isValid() && r.second.isValid())
+ return false;
+ if (l.second != r.second)
+ return SM.isBeforeInTranslationUnit(l.second, r.second);
+ return SM.isBeforeInTranslationUnit(l.first->getLocation(),
+ r.first->getLocation());
+ }
};
-
- bool operator<(const UndefinedInternal &l, const UndefinedInternal &r) {
- return l.useLoc.isBeforeInTranslationUnitThan(r.useLoc);
- }
}
-/// checkUndefinedInternals - Check for undefined objects with internal linkage.
-static void checkUndefinedInternals(Sema &S) {
- if (S.UndefinedInternals.empty()) return;
-
- // Collect all the still-undefined entities with internal linkage.
- SmallVector<UndefinedInternal, 16> undefined;
- for (llvm::DenseMap<NamedDecl*,SourceLocation>::iterator
- i = S.UndefinedInternals.begin(), e = S.UndefinedInternals.end();
- i != e; ++i) {
- NamedDecl *decl = i->first;
+/// Obtains a sorted list of functions that are undefined but ODR-used.
+void Sema::getUndefinedButUsed(
+ SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> > &Undefined) {
+ for (llvm::DenseMap<NamedDecl *, SourceLocation>::iterator
+ I = UndefinedButUsed.begin(), E = UndefinedButUsed.end();
+ I != E; ++I) {
+ NamedDecl *ND = I->first;
// Ignore attributes that have become invalid.
- if (decl->isInvalidDecl()) continue;
+ if (ND->isInvalidDecl()) continue;
// __attribute__((weakref)) is basically a definition.
- if (decl->hasAttr<WeakRefAttr>()) continue;
+ if (ND->hasAttr<WeakRefAttr>()) continue;
- if (FunctionDecl *fn = dyn_cast<FunctionDecl>(decl)) {
- if (fn->isPure() || fn->hasBody())
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
+ if (FD->isDefined())
+ continue;
+ if (FD->hasExternalLinkage() &&
+ !FD->getMostRecentDecl()->isInlined())
continue;
} else {
- if (cast<VarDecl>(decl)->hasDefinition() != VarDecl::DeclarationOnly)
+ if (cast<VarDecl>(ND)->hasDefinition() != VarDecl::DeclarationOnly)
+ continue;
+ if (ND->hasExternalLinkage())
continue;
}
- // We build a FullSourceLoc so that we can sort with array_pod_sort.
- FullSourceLoc loc(i->second, S.Context.getSourceManager());
- undefined.push_back(UndefinedInternal(decl, loc));
+ Undefined.push_back(std::make_pair(ND, I->second));
}
- if (undefined.empty()) return;
+ // Sort (in order of use site) so that we're not dependent on the iteration
+ // order through an llvm::DenseMap.
+ std::sort(Undefined.begin(), Undefined.end(),
+ SortUndefinedButUsed(Context.getSourceManager()));
+}
+
+/// checkUndefinedButUsed - Check for undefined objects with internal linkage
+/// or that are inline.
+static void checkUndefinedButUsed(Sema &S) {
+ if (S.UndefinedButUsed.empty()) return;
+
+ // Collect all the still-undefined entities with internal linkage.
+ SmallVector<std::pair<NamedDecl *, SourceLocation>, 16> Undefined;
+ S.getUndefinedButUsed(Undefined);
+ if (Undefined.empty()) return;
- // Sort (in order of use site) so that we're not (as) dependent on
- // the iteration order through an llvm::DenseMap.
- llvm::array_pod_sort(undefined.begin(), undefined.end());
+ for (SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> >::iterator
+ I = Undefined.begin(), E = Undefined.end(); I != E; ++I) {
+ NamedDecl *ND = I->first;
- for (SmallVectorImpl<UndefinedInternal>::iterator
- i = undefined.begin(), e = undefined.end(); i != e; ++i) {
- NamedDecl *decl = i->decl;
- S.Diag(decl->getLocation(), diag::warn_undefined_internal)
- << isa<VarDecl>(decl) << decl;
- S.Diag(i->useLoc, diag::note_used_here);
+ if (ND->getLinkage() != ExternalLinkage) {
+ S.Diag(ND->getLocation(), diag::warn_undefined_internal)
+ << isa<VarDecl>(ND) << ND;
+ } else {
+ assert(cast<FunctionDecl>(ND)->getMostRecentDecl()->isInlined() &&
+ "used object requires definition but isn't inline or internal?");
+ S.Diag(ND->getLocation(), diag::warn_undefined_inline) << ND;
+ }
+ if (I->second.isValid())
+ S.Diag(I->second, diag::note_used_here);
}
}
void Sema::LoadExternalWeakUndeclaredIdentifiers() {
if (!ExternalSource)
return;
-
+
SmallVector<std::pair<IdentifierInfo *, WeakInfo>, 4> WeakIDs;
ExternalSource->ReadWeakUndeclaredIdentifiers(WeakIDs);
for (unsigned I = 0, N = WeakIDs.size(); I != N; ++I) {
@@ -432,7 +459,7 @@ void Sema::LoadExternalWeakUndeclaredIdentifiers() {
= WeakUndeclaredIdentifiers.find(WeakIDs[I].first);
if (Pos != WeakUndeclaredIdentifiers.end())
continue;
-
+
WeakUndeclaredIdentifiers.insert(WeakIDs[I]);
}
}
@@ -537,7 +564,7 @@ void Sema::ActOnEndOfTranslationUnit() {
I != E; ++I) {
assert(!(*I)->isDependentType() &&
"Should not see dependent types here!");
- if (const CXXMethodDecl *KeyFunction = Context.getKeyFunction(*I)) {
+ if (const CXXMethodDecl *KeyFunction = Context.getCurrentKeyFunction(*I)) {
const FunctionDecl *Definition = 0;
if (KeyFunction->hasBody(Definition))
MarkVTableUsed(Definition->getLocation(), *I, true);
@@ -561,9 +588,9 @@ void Sema::ActOnEndOfTranslationUnit() {
// or we need to perform template instantiations earlier.
PerformPendingInstantiations();
}
-
+
// Remove file scoped decls that turned out to be used.
- UnusedFileScopedDecls.erase(std::remove_if(UnusedFileScopedDecls.begin(0,
+ UnusedFileScopedDecls.erase(std::remove_if(UnusedFileScopedDecls.begin(0,
true),
UnusedFileScopedDecls.end(),
std::bind1st(std::ptr_fun(ShouldRemoveFromUnused),
@@ -589,24 +616,31 @@ void Sema::ActOnEndOfTranslationUnit() {
<< I->first;
}
+ if (LangOpts.CPlusPlus11 &&
+ Diags.getDiagnosticLevel(diag::warn_delegating_ctor_cycle,
+ SourceLocation())
+ != DiagnosticsEngine::Ignored)
+ CheckDelegatingCtorCycles();
+
if (TUKind == TU_Module) {
// If we are building a module, resolve all of the exported declarations
// now.
if (Module *CurrentModule = PP.getCurrentModule()) {
ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap();
-
- llvm::SmallVector<Module *, 2> Stack;
+
+ SmallVector<Module *, 2> Stack;
Stack.push_back(CurrentModule);
while (!Stack.empty()) {
Module *Mod = Stack.back();
Stack.pop_back();
-
- // Resolve the exported declarations.
+
+ // Resolve the exported declarations and conflicts.
// FIXME: Actually complain, once we figure out how to teach the
- // diagnostic client to deal with complains in the module map at this
+ // diagnostic client to deal with complaints in the module map at this
// point.
ModMap.resolveExports(Mod, /*Complain=*/false);
-
+ ModMap.resolveConflicts(Mod, /*Complain=*/false);
+
// Queue the submodules, so their exports will also be resolved.
for (Module::submodule_iterator Sub = Mod->submodule_begin(),
SubEnd = Mod->submodule_end();
@@ -615,12 +649,12 @@ void Sema::ActOnEndOfTranslationUnit() {
}
}
}
-
+
// Modules don't need any of the checking below.
TUScope = 0;
return;
}
-
+
// C99 6.9.2p2:
// A declaration of an identifier for an object that has file
// scope without an initializer, and without a storage-class
@@ -633,10 +667,10 @@ void Sema::ActOnEndOfTranslationUnit() {
// identifier, with the composite type as of the end of the
// translation unit, with an initializer equal to 0.
llvm::SmallSet<VarDecl *, 32> Seen;
- for (TentativeDefinitionsType::iterator
+ for (TentativeDefinitionsType::iterator
T = TentativeDefinitions.begin(ExternalSource),
TEnd = TentativeDefinitions.end();
- T != TEnd; ++T)
+ T != TEnd; ++T)
{
VarDecl *VD = (*T)->getActingDefinition();
@@ -673,12 +707,6 @@ void Sema::ActOnEndOfTranslationUnit() {
}
- if (LangOpts.CPlusPlus0x &&
- Diags.getDiagnosticLevel(diag::warn_delegating_ctor_cycle,
- SourceLocation())
- != DiagnosticsEngine::Ignored)
- CheckDelegatingCtorCycles();
-
// If there were errors, disable 'unused' warnings since they will mostly be
// noise.
if (!Diags.hasErrorOccurred()) {
@@ -688,7 +716,7 @@ void Sema::ActOnEndOfTranslationUnit() {
E = UnusedFileScopedDecls.end(); I != E; ++I) {
if (ShouldRemoveFromUnused(this, *I))
continue;
-
+
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
const FunctionDecl *DiagD;
if (!FD->hasBody(DiagD))
@@ -700,7 +728,7 @@ void Sema::ActOnEndOfTranslationUnit() {
Diag(DiagD->getLocation(), diag::warn_unneeded_member_function)
<< DiagD->getDeclName();
else {
- if (FD->getStorageClassAsWritten() == SC_Static &&
+ if (FD->getStorageClass() == SC_Static &&
!FD->isInlineSpecified() &&
!SourceMgr.isFromMainFile(
SourceMgr.getExpansionLoc(FD->getLocation())))
@@ -730,7 +758,9 @@ void Sema::ActOnEndOfTranslationUnit() {
}
}
- checkUndefinedInternals(*this);
+ if (ExternalSource)
+ ExternalSource->ReadUndefinedButUsed(UndefinedButUsed);
+ checkUndefinedButUsed(*this);
}
if (Diags.getDiagnosticLevel(diag::warn_unused_private_field,
@@ -809,13 +839,13 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) {
// eliminnated. If it truly cannot be (for example, there is some reentrancy
// issue I am not seeing yet), then there should at least be a clarifying
// comment somewhere.
- if (llvm::Optional<TemplateDeductionInfo*> Info = isSFINAEContext()) {
+ if (Optional<TemplateDeductionInfo*> Info = isSFINAEContext()) {
switch (DiagnosticIDs::getDiagnosticSFINAEResponse(
Diags.getCurrentDiagID())) {
case DiagnosticIDs::SFINAE_Report:
// We'll report the diagnostic below.
break;
-
+
case DiagnosticIDs::SFINAE_SubstitutionFailure:
// Count this failure so that we know that template argument deduction
// has failed.
@@ -832,13 +862,13 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) {
Diags.setLastDiagnosticIgnored();
Diags.Clear();
return;
-
+
case DiagnosticIDs::SFINAE_AccessControl: {
// Per C++ Core Issue 1170, access control is part of SFINAE.
// Additionally, the AccessCheckingSFINAE flag can be used to temporarily
// make access control a part of SFINAE for the purposes of checking
// type traits.
- if (!AccessCheckingSFINAE && !getLangOpts().CPlusPlus0x)
+ if (!AccessCheckingSFINAE && !getLangOpts().CPlusPlus11)
break;
SourceLocation Loc = Diags.getCurrentDiagLoc();
@@ -882,10 +912,10 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) {
return;
}
}
-
+
// Set up the context's printing policy based on our current state.
Context.setPrintingPolicy(getPrintingPolicy());
-
+
// Emit the diagnostic.
if (!Diags.EmitCurrentDiagnostic())
return;
@@ -944,10 +974,10 @@ bool Sema::findMacroSpelling(SourceLocation &locref, StringRef name) {
/// \returns The scope corresponding to the given declaraion context, or NULL
/// if no such scope is open.
Scope *Sema::getScopeForContext(DeclContext *Ctx) {
-
+
if (!Ctx)
return 0;
-
+
Ctx = Ctx->getPrimaryContext();
for (Scope *S = getCurScope(); S; S = S->getParent()) {
// Ignore scopes that cannot have declarations. This is important for
@@ -957,7 +987,7 @@ Scope *Sema::getScopeForContext(DeclContext *Ctx) {
if (Ctx == Entity->getPrimaryContext())
return S;
}
-
+
return 0;
}
@@ -970,7 +1000,7 @@ void Sema::PushFunctionScope() {
FunctionScopes.push_back(FunctionScopes.back());
return;
}
-
+
FunctionScopes.push_back(new FunctionScopeInfo(getDiagnostics()));
}
@@ -979,7 +1009,7 @@ void Sema::PushBlockScope(Scope *BlockScope, BlockDecl *Block) {
BlockScope, Block));
}
-void Sema::PushLambdaScope(CXXRecordDecl *Lambda,
+void Sema::PushLambdaScope(CXXRecordDecl *Lambda,
CXXMethodDecl *CallOperator) {
FunctionScopes.push_back(new LambdaScopeInfo(getDiagnostics(), Lambda,
CallOperator));
@@ -987,9 +1017,9 @@ void Sema::PushLambdaScope(CXXRecordDecl *Lambda,
void Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP,
const Decl *D, const BlockExpr *blkExpr) {
- FunctionScopeInfo *Scope = FunctionScopes.pop_back_val();
+ FunctionScopeInfo *Scope = FunctionScopes.pop_back_val();
assert(!FunctionScopes.empty() && "mismatched push/pop!");
-
+
// Issue any analysis-based warnings.
if (WP && D)
AnalysisWarnings.IssueWarnings(*WP, Scope, D, blkExpr);
@@ -1028,15 +1058,15 @@ bool Sema::hasAnyUnrecoverableErrorsInThisFunction() const {
BlockScopeInfo *Sema::getCurBlock() {
if (FunctionScopes.empty())
return 0;
-
- return dyn_cast<BlockScopeInfo>(FunctionScopes.back());
+
+ return dyn_cast<BlockScopeInfo>(FunctionScopes.back());
}
LambdaScopeInfo *Sema::getCurLambda() {
if (FunctionScopes.empty())
return 0;
-
- return dyn_cast<LambdaScopeInfo>(FunctionScopes.back());
+
+ return dyn_cast<LambdaScopeInfo>(FunctionScopes.back());
}
void Sema::ActOnComment(SourceRange Comment) {
@@ -1071,7 +1101,11 @@ ExternalSemaSource::~ExternalSemaSource() {}
void ExternalSemaSource::ReadMethodPool(Selector Sel) { }
void ExternalSemaSource::ReadKnownNamespaces(
- SmallVectorImpl<NamespaceDecl *> &Namespaces) {
+ SmallVectorImpl<NamespaceDecl *> &Namespaces) {
+}
+
+void ExternalSemaSource::ReadUndefinedButUsed(
+ llvm::DenseMap<NamedDecl *, SourceLocation> &Undefined) {
}
void PrettyDeclStackTraceEntry::print(raw_ostream &OS) const {
@@ -1248,7 +1282,7 @@ bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD,
// actually a CallExpr.
SourceLocation ParenInsertionLoc =
PP.getLocForEndOfToken(Range.getEnd());
- Diag(Loc, PD)
+ Diag(Loc, PD)
<< /*zero-arg*/ 1 << Range
<< (IsCallableWithAppend(E.get())
? FixItHint::CreateInsertion(ParenInsertionLoc, "()")
@@ -1269,3 +1303,9 @@ bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD,
E = ExprError();
return true;
}
+
+IdentifierInfo *Sema::getSuperIdentifier() const {
+ if (!Ident_super)
+ Ident_super = &Context.Idents.get("super");
+ return Ident_super;
+}
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index 58b1a51..79a9d3c 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -12,9 +12,6 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/DelayedDiagnostic.h"
-#include "clang/Sema/Initialization.h"
-#include "clang/Sema/Lookup.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclCXX.h"
@@ -22,6 +19,9 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DependentDiagnostic.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/Sema/DelayedDiagnostic.h"
+#include "clang/Sema/Initialization.h"
+#include "clang/Sema/Lookup.h"
using namespace clang;
using namespace sema;
@@ -217,6 +217,15 @@ struct AccessTarget : public AccessedEntity {
return DeclaringClass;
}
+ /// The "effective" naming class is the canonical non-anonymous
+ /// class containing the actual naming class.
+ const CXXRecordDecl *getEffectiveNamingClass() const {
+ const CXXRecordDecl *namingClass = getNamingClass();
+ while (namingClass->isAnonymousStructOrUnion())
+ namingClass = cast<CXXRecordDecl>(namingClass->getParent());
+ return namingClass->getCanonicalDecl();
+ }
+
private:
void initialize() {
HasInstanceContext = (isMemberAccess() &&
@@ -1023,8 +1032,7 @@ static bool TryDiagnoseProtectedAccess(Sema &S, const EffectiveContext &EC,
assert(Target.isMemberAccess());
- const CXXRecordDecl *NamingClass = Target.getNamingClass();
- NamingClass = NamingClass->getCanonicalDecl();
+ const CXXRecordDecl *NamingClass = Target.getEffectiveNamingClass();
for (EffectiveContext::record_iterator
I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
@@ -1089,129 +1097,173 @@ static bool TryDiagnoseProtectedAccess(Sema &S, const EffectiveContext &EC,
return false;
}
+/// We are unable to access a given declaration due to its direct
+/// access control; diagnose that.
+static void diagnoseBadDirectAccess(Sema &S,
+ const EffectiveContext &EC,
+ AccessTarget &entity) {
+ assert(entity.isMemberAccess());
+ NamedDecl *D = entity.getTargetDecl();
+
+ if (D->getAccess() == AS_protected &&
+ TryDiagnoseProtectedAccess(S, EC, entity))
+ return;
+
+ // Find an original declaration.
+ while (D->isOutOfLine()) {
+ NamedDecl *PrevDecl = 0;
+ if (VarDecl *VD = dyn_cast<VarDecl>(D))
+ PrevDecl = VD->getPreviousDecl();
+ else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ PrevDecl = FD->getPreviousDecl();
+ else if (TypedefNameDecl *TND = dyn_cast<TypedefNameDecl>(D))
+ PrevDecl = TND->getPreviousDecl();
+ else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
+ if (isa<RecordDecl>(D) && cast<RecordDecl>(D)->isInjectedClassName())
+ break;
+ PrevDecl = TD->getPreviousDecl();
+ }
+ if (!PrevDecl) break;
+ D = PrevDecl;
+ }
+
+ CXXRecordDecl *DeclaringClass = FindDeclaringClass(D);
+ Decl *ImmediateChild;
+ if (D->getDeclContext() == DeclaringClass)
+ ImmediateChild = D;
+ else {
+ DeclContext *DC = D->getDeclContext();
+ while (DC->getParent() != DeclaringClass)
+ DC = DC->getParent();
+ ImmediateChild = cast<Decl>(DC);
+ }
+
+ // Check whether there's an AccessSpecDecl preceding this in the
+ // chain of the DeclContext.
+ bool isImplicit = true;
+ for (CXXRecordDecl::decl_iterator
+ I = DeclaringClass->decls_begin(), E = DeclaringClass->decls_end();
+ I != E; ++I) {
+ if (*I == ImmediateChild) break;
+ if (isa<AccessSpecDecl>(*I)) {
+ isImplicit = false;
+ break;
+ }
+ }
+
+ S.Diag(D->getLocation(), diag::note_access_natural)
+ << (unsigned) (D->getAccess() == AS_protected)
+ << isImplicit;
+}
+
/// Diagnose the path which caused the given declaration or base class
/// to become inaccessible.
static void DiagnoseAccessPath(Sema &S,
const EffectiveContext &EC,
- AccessTarget &Entity) {
- AccessSpecifier Access = Entity.getAccess();
+ AccessTarget &entity) {
+ // Save the instance context to preserve invariants.
+ AccessTarget::SavedInstanceContext _ = entity.saveInstanceContext();
- NamedDecl *D = (Entity.isMemberAccess() ? Entity.getTargetDecl() : 0);
- const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass();
+ // This basically repeats the main algorithm but keeps some more
+ // information.
- // Easy case: the decl's natural access determined its path access.
- // We have to check against AS_private here in case Access is AS_none,
- // indicating a non-public member of a private base class.
- if (D && (Access == D->getAccess() || D->getAccess() == AS_private)) {
- switch (HasAccess(S, EC, DeclaringClass, D->getAccess(), Entity)) {
- case AR_inaccessible: {
- if (Access == AS_protected &&
- TryDiagnoseProtectedAccess(S, EC, Entity))
- return;
-
- // Find an original declaration.
- while (D->isOutOfLine()) {
- NamedDecl *PrevDecl = 0;
- if (VarDecl *VD = dyn_cast<VarDecl>(D))
- PrevDecl = VD->getPreviousDecl();
- else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- PrevDecl = FD->getPreviousDecl();
- else if (TypedefNameDecl *TND = dyn_cast<TypedefNameDecl>(D))
- PrevDecl = TND->getPreviousDecl();
- else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
- if (isa<RecordDecl>(D) && cast<RecordDecl>(D)->isInjectedClassName())
- break;
- PrevDecl = TD->getPreviousDecl();
- }
- if (!PrevDecl) break;
- D = PrevDecl;
- }
+ // The natural access so far.
+ AccessSpecifier accessSoFar = AS_public;
- CXXRecordDecl *DeclaringClass = FindDeclaringClass(D);
- Decl *ImmediateChild;
- if (D->getDeclContext() == DeclaringClass)
- ImmediateChild = D;
- else {
- DeclContext *DC = D->getDeclContext();
- while (DC->getParent() != DeclaringClass)
- DC = DC->getParent();
- ImmediateChild = cast<Decl>(DC);
- }
-
- // Check whether there's an AccessSpecDecl preceding this in the
- // chain of the DeclContext.
- bool Implicit = true;
- for (CXXRecordDecl::decl_iterator
- I = DeclaringClass->decls_begin(), E = DeclaringClass->decls_end();
- I != E; ++I) {
- if (*I == ImmediateChild) break;
- if (isa<AccessSpecDecl>(*I)) {
- Implicit = false;
- break;
- }
- }
+ // Check whether we have special rights to the declaring class.
+ if (entity.isMemberAccess()) {
+ NamedDecl *D = entity.getTargetDecl();
+ accessSoFar = D->getAccess();
+ const CXXRecordDecl *declaringClass = entity.getDeclaringClass();
- S.Diag(D->getLocation(), diag::note_access_natural)
- << (unsigned) (Access == AS_protected)
- << Implicit;
- return;
- }
+ switch (HasAccess(S, EC, declaringClass, accessSoFar, entity)) {
+ // If the declaration is accessible when named in its declaring
+ // class, then we must be constrained by the path.
+ case AR_accessible:
+ accessSoFar = AS_public;
+ entity.suppressInstanceContext();
+ break;
- case AR_accessible: break;
+ case AR_inaccessible:
+ if (accessSoFar == AS_private ||
+ declaringClass == entity.getEffectiveNamingClass())
+ return diagnoseBadDirectAccess(S, EC, entity);
+ break;
case AR_dependent:
- llvm_unreachable("can't diagnose dependent access failures");
+ llvm_unreachable("cannot diagnose dependent access");
}
}
- CXXBasePaths Paths;
- CXXBasePath &Path = *FindBestPath(S, EC, Entity, AS_public, Paths);
+ CXXBasePaths paths;
+ CXXBasePath &path = *FindBestPath(S, EC, entity, accessSoFar, paths);
+ assert(path.Access != AS_public);
- CXXBasePath::iterator I = Path.end(), E = Path.begin();
- while (I != E) {
- --I;
+ CXXBasePath::iterator i = path.end(), e = path.begin();
+ CXXBasePath::iterator constrainingBase = i;
+ while (i != e) {
+ --i;
- const CXXBaseSpecifier *BS = I->Base;
- AccessSpecifier BaseAccess = BS->getAccessSpecifier();
+ assert(accessSoFar != AS_none && accessSoFar != AS_private);
- // If this is public inheritance, or the derived class is a friend,
- // skip this step.
- if (BaseAccess == AS_public)
- continue;
+ // Is the entity accessible when named in the deriving class, as
+ // modified by the base specifier?
+ const CXXRecordDecl *derivingClass = i->Class->getCanonicalDecl();
+ const CXXBaseSpecifier *base = i->Base;
- switch (GetFriendKind(S, EC, I->Class)) {
- case AR_accessible: continue;
+ // If the access to this base is worse than the access we have to
+ // the declaration, remember it.
+ AccessSpecifier baseAccess = base->getAccessSpecifier();
+ if (baseAccess > accessSoFar) {
+ constrainingBase = i;
+ accessSoFar = baseAccess;
+ }
+
+ switch (HasAccess(S, EC, derivingClass, accessSoFar, entity)) {
case AR_inaccessible: break;
+ case AR_accessible:
+ accessSoFar = AS_public;
+ entity.suppressInstanceContext();
+ constrainingBase = 0;
+ break;
case AR_dependent:
- llvm_unreachable("can't diagnose dependent access failures");
+ llvm_unreachable("cannot diagnose dependent access");
}
- // Check whether this base specifier is the tighest point
- // constraining access. We have to check against AS_private for
- // the same reasons as above.
- if (BaseAccess == AS_private || BaseAccess >= Access) {
-
- // We're constrained by inheritance, but we want to say
- // "declared private here" if we're diagnosing a hierarchy
- // conversion and this is the final step.
- unsigned diagnostic;
- if (D) diagnostic = diag::note_access_constrained_by_path;
- else if (I + 1 == Path.end()) diagnostic = diag::note_access_natural;
- else diagnostic = diag::note_access_constrained_by_path;
-
- S.Diag(BS->getSourceRange().getBegin(), diagnostic)
- << BS->getSourceRange()
- << (BaseAccess == AS_protected)
- << (BS->getAccessSpecifierAsWritten() == AS_none);
-
- if (D)
- S.Diag(D->getLocation(), diag::note_field_decl);
-
- return;
+ // If this was private inheritance, but we don't have access to
+ // the deriving class, we're done.
+ if (accessSoFar == AS_private) {
+ assert(baseAccess == AS_private);
+ assert(constrainingBase == i);
+ break;
}
}
- llvm_unreachable("access not apparently constrained by path");
+ // If we don't have a constraining base, the access failure must be
+ // due to the original declaration.
+ if (constrainingBase == path.end())
+ return diagnoseBadDirectAccess(S, EC, entity);
+
+ // We're constrained by inheritance, but we want to say
+ // "declared private here" if we're diagnosing a hierarchy
+ // conversion and this is the final step.
+ unsigned diagnostic;
+ if (entity.isMemberAccess() ||
+ constrainingBase + 1 != path.end()) {
+ diagnostic = diag::note_access_constrained_by_path;
+ } else {
+ diagnostic = diag::note_access_natural;
+ }
+
+ const CXXBaseSpecifier *base = constrainingBase->Base;
+
+ S.Diag(base->getSourceRange().getBegin(), diagnostic)
+ << base->getSourceRange()
+ << (base->getAccessSpecifier() == AS_protected)
+ << (base->getAccessSpecifierAsWritten() == AS_none);
+
+ if (entity.isMemberAccess())
+ S.Diag(entity.getTargetDecl()->getLocation(), diag::note_field_decl);
}
static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
@@ -1273,10 +1325,7 @@ static AccessResult IsAccessible(Sema &S,
const EffectiveContext &EC,
AccessTarget &Entity) {
// Determine the actual naming class.
- CXXRecordDecl *NamingClass = Entity.getNamingClass();
- while (NamingClass->isAnonymousStructOrUnion())
- NamingClass = cast<CXXRecordDecl>(NamingClass->getParent());
- NamingClass = NamingClass->getCanonicalDecl();
+ const CXXRecordDecl *NamingClass = Entity.getEffectiveNamingClass();
AccessSpecifier UnprivilegedAccess = Entity.getAccess();
assert(UnprivilegedAccess != AS_public && "public access not weeded out");
@@ -1317,7 +1366,13 @@ static AccessResult IsAccessible(Sema &S,
FinalAccess = Target->getAccess();
switch (HasAccess(S, EC, DeclaringClass, FinalAccess, Entity)) {
case AR_accessible:
+ // Target is accessible at EC when named in its declaring class.
+ // We can now hill-climb and simply check whether the declaring
+ // class is accessible as a base of the naming class. This is
+ // equivalent to checking the access of a notional public
+ // member with no instance context.
FinalAccess = AS_public;
+ Entity.suppressInstanceContext();
break;
case AR_inaccessible: break;
case AR_dependent: return AR_dependent; // see above
@@ -1325,8 +1380,6 @@ static AccessResult IsAccessible(Sema &S,
if (DeclaringClass == NamingClass)
return (FinalAccess == AS_public ? AR_accessible : AR_inaccessible);
-
- Entity.suppressInstanceContext();
} else {
FinalAccess = AS_public;
}
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index f1154c1..e12bbde0 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -13,11 +13,11 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Lookup.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Lookup.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -309,7 +309,8 @@ void Sema::AddPushedVisibilityAttribute(Decl *D) {
if (!VisContext)
return;
- if (isa<NamedDecl>(D) && cast<NamedDecl>(D)->getExplicitVisibility())
+ NamedDecl *ND = dyn_cast<NamedDecl>(D);
+ if (ND && ND->getExplicitVisibility(NamedDecl::VisibilityForValue))
return;
VisStack *Stack = static_cast<VisStack*>(VisContext);
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 15bfd1c..01ac8f7 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -12,21 +12,21 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/Template.h"
+#include "TypeLocBuilder.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Sema/DeclSpec.h"
-#include "TypeLocBuilder.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Template.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
/// \brief Find the current instantiation that associated with the given type.
-static CXXRecordDecl *getCurrentInstantiationOf(QualType T,
+static CXXRecordDecl *getCurrentInstantiationOf(QualType T,
DeclContext *CurContext) {
if (T.isNull())
return 0;
@@ -34,16 +34,10 @@ static CXXRecordDecl *getCurrentInstantiationOf(QualType T,
const Type *Ty = T->getCanonicalTypeInternal().getTypePtr();
if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
CXXRecordDecl *Record = cast<CXXRecordDecl>(RecordTy->getDecl());
- if (!T->isDependentType())
+ if (!Record->isDependentContext() ||
+ Record->isCurrentInstantiation(CurContext))
return Record;
- // This may be a member of a class template or class template partial
- // specialization. If it's part of the current semantic context, then it's
- // an injected-class-name;
- for (; !CurContext->isFileContext(); CurContext = CurContext->getParent())
- if (CurContext->Equals(Record))
- return Record;
-
return 0;
} else if (isa<InjectedClassNameType>(Ty))
return cast<InjectedClassNameType>(Ty)->getDecl();
@@ -84,8 +78,7 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
if (!SS.isSet() || SS.isInvalid())
return 0;
- NestedNameSpecifier *NNS
- = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+ NestedNameSpecifier *NNS = SS.getScopeRep();
if (NNS->isDependent()) {
// If this nested-name-specifier refers to the current
// instantiation, return its DeclContext.
@@ -164,9 +157,7 @@ bool Sema::isDependentScopeSpecifier(const CXXScopeSpec &SS) {
if (!SS.isSet() || SS.isInvalid())
return false;
- NestedNameSpecifier *NNS
- = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
- return NNS->isDependent();
+ return SS.getScopeRep()->isDependent();
}
// \brief Determine whether this C++ scope specifier refers to an
@@ -176,9 +167,7 @@ bool Sema::isUnknownSpecialization(const CXXScopeSpec &SS) {
if (!isDependentScopeSpecifier(SS))
return false;
- NestedNameSpecifier *NNS
- = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
- return getCurrentInstantiationOf(NNS) == 0;
+ return getCurrentInstantiationOf(SS.getScopeRep()) == 0;
}
/// \brief If the given nested name specifier refers to the current
@@ -269,7 +258,7 @@ bool Sema::ActOnCXXGlobalScopeSpecifier(Scope *S, SourceLocation CCLoc,
/// \brief Determines whether the given declaration is an valid acceptable
/// result for name lookup of a nested-name-specifier.
-bool Sema::isAcceptableNestedNameSpecifier(NamedDecl *SD) {
+bool Sema::isAcceptableNestedNameSpecifier(const NamedDecl *SD) {
if (!SD)
return false;
@@ -285,13 +274,13 @@ bool Sema::isAcceptableNestedNameSpecifier(NamedDecl *SD) {
QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD));
if (T->isDependentType())
return true;
- else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(SD)) {
+ else if (const TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(SD)) {
if (TD->getUnderlyingType()->isRecordType() ||
- (Context.getLangOpts().CPlusPlus0x &&
+ (Context.getLangOpts().CPlusPlus11 &&
TD->getUnderlyingType()->isEnumeralType()))
return true;
} else if (isa<RecordDecl>(SD) ||
- (Context.getLangOpts().CPlusPlus0x && isa<EnumDecl>(SD)))
+ (Context.getLangOpts().CPlusPlus11 && isa<EnumDecl>(SD)))
return true;
return false;
@@ -540,7 +529,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
NamedDecl *SD = Found.getAsSingle<NamedDecl>();
if (isAcceptableNestedNameSpecifier(SD)) {
if (!ObjectType.isNull() && !ObjectTypeSearchedInScope &&
- !getLangOpts().CPlusPlus0x) {
+ !getLangOpts().CPlusPlus11) {
// C++03 [basic.lookup.classref]p4:
// [...] If the name is found in both contexts, the
// class-name-or-namespace-name shall refer to the same entity.
@@ -775,8 +764,7 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
if (DependentTemplateName *DTN = Template.get().getAsDependentTemplateName()){
// Handle a dependent template specialization for which we cannot resolve
// the template name.
- assert(DTN->getQualifier()
- == static_cast<NestedNameSpecifier*>(SS.getScopeRep()));
+ assert(DTN->getQualifier() == SS.getScopeRep());
QualType T = Context.getDependentTemplateSpecializationType(ETK_None,
DTN->getQualifier(),
DTN->getIdentifier(),
@@ -883,8 +871,7 @@ void Sema::RestoreNestedNameSpecifierAnnotation(void *AnnotationPtr,
bool Sema::ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");
- NestedNameSpecifier *Qualifier =
- static_cast<NestedNameSpecifier*>(SS.getScopeRep());
+ NestedNameSpecifier *Qualifier = SS.getScopeRep();
// There are only two places a well-formed program may qualify a
// declarator: first, when defining a namespace or class member
diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp
index bf25c61..e2a4084 100644
--- a/lib/Sema/SemaCast.cpp
+++ b/lib/Sema/SemaCast.cpp
@@ -15,12 +15,13 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Initialization.h"
-#include "clang/AST/ExprCXX.h"
-#include "clang/AST/ExprObjC.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/RecordLayout.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Sema/Initialization.h"
#include "llvm/ADT/SmallVector.h"
#include <set>
using namespace clang;
@@ -258,7 +259,8 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
}
return Op.complete(CXXConstCastExpr::Create(Context, Op.ResultType,
Op.ValueKind, Op.SrcExpr.take(), DestTInfo,
- OpLoc, Parens.getEnd()));
+ OpLoc, Parens.getEnd(),
+ AngleBrackets));
case tok::kw_dynamic_cast: {
if (!TypeDependent) {
@@ -269,7 +271,8 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
return Op.complete(CXXDynamicCastExpr::Create(Context, Op.ResultType,
Op.ValueKind, Op.Kind, Op.SrcExpr.take(),
&Op.BasePath, DestTInfo,
- OpLoc, Parens.getEnd()));
+ OpLoc, Parens.getEnd(),
+ AngleBrackets));
}
case tok::kw_reinterpret_cast: {
if (!TypeDependent) {
@@ -280,7 +283,8 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
return Op.complete(CXXReinterpretCastExpr::Create(Context, Op.ResultType,
Op.ValueKind, Op.Kind, Op.SrcExpr.take(),
0, DestTInfo, OpLoc,
- Parens.getEnd()));
+ Parens.getEnd(),
+ AngleBrackets));
}
case tok::kw_static_cast: {
if (!TypeDependent) {
@@ -292,7 +296,8 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
return Op.complete(CXXStaticCastExpr::Create(Context, Op.ResultType,
Op.ValueKind, Op.Kind, Op.SrcExpr.take(),
&Op.BasePath, DestTInfo,
- OpLoc, Parens.getEnd()));
+ OpLoc, Parens.getEnd(),
+ AngleBrackets));
}
}
}
@@ -678,6 +683,98 @@ void CastOperation::CheckConstCast() {
<< SrcExpr.get()->getType() << DestType << OpRange;
}
+/// Check that a reinterpret_cast\<DestType\>(SrcExpr) is not used as upcast
+/// or downcast between respective pointers or references.
+static void DiagnoseReinterpretUpDownCast(Sema &Self, const Expr *SrcExpr,
+ QualType DestType,
+ SourceRange OpRange) {
+ QualType SrcType = SrcExpr->getType();
+ // When casting from pointer or reference, get pointee type; use original
+ // type otherwise.
+ const CXXRecordDecl *SrcPointeeRD = SrcType->getPointeeCXXRecordDecl();
+ const CXXRecordDecl *SrcRD =
+ SrcPointeeRD ? SrcPointeeRD : SrcType->getAsCXXRecordDecl();
+
+ // Examining subobjects for records is only possible if the complete and
+ // valid definition is available. Also, template instantiation is not
+ // allowed here.
+ if (!SrcRD || !SrcRD->isCompleteDefinition() || SrcRD->isInvalidDecl())
+ return;
+
+ const CXXRecordDecl *DestRD = DestType->getPointeeCXXRecordDecl();
+
+ if (!DestRD || !DestRD->isCompleteDefinition() || DestRD->isInvalidDecl())
+ return;
+
+ enum {
+ ReinterpretUpcast,
+ ReinterpretDowncast
+ } ReinterpretKind;
+
+ CXXBasePaths BasePaths;
+
+ if (SrcRD->isDerivedFrom(DestRD, BasePaths))
+ ReinterpretKind = ReinterpretUpcast;
+ else if (DestRD->isDerivedFrom(SrcRD, BasePaths))
+ ReinterpretKind = ReinterpretDowncast;
+ else
+ return;
+
+ bool VirtualBase = true;
+ bool NonZeroOffset = false;
+ for (CXXBasePaths::const_paths_iterator I = BasePaths.begin(),
+ E = BasePaths.end();
+ I != E; ++I) {
+ const CXXBasePath &Path = *I;
+ CharUnits Offset = CharUnits::Zero();
+ bool IsVirtual = false;
+ for (CXXBasePath::const_iterator IElem = Path.begin(), EElem = Path.end();
+ IElem != EElem; ++IElem) {
+ IsVirtual = IElem->Base->isVirtual();
+ if (IsVirtual)
+ break;
+ const CXXRecordDecl *BaseRD = IElem->Base->getType()->getAsCXXRecordDecl();
+ assert(BaseRD && "Base type should be a valid unqualified class type");
+ // Don't check if any base has invalid declaration or has no definition
+ // since it has no layout info.
+ const CXXRecordDecl *Class = IElem->Class,
+ *ClassDefinition = Class->getDefinition();
+ if (Class->isInvalidDecl() || !ClassDefinition ||
+ !ClassDefinition->isCompleteDefinition())
+ return;
+
+ const ASTRecordLayout &DerivedLayout =
+ Self.Context.getASTRecordLayout(Class);
+ Offset += DerivedLayout.getBaseClassOffset(BaseRD);
+ }
+ if (!IsVirtual) {
+ // Don't warn if any path is a non-virtually derived base at offset zero.
+ if (Offset.isZero())
+ return;
+ // Offset makes sense only for non-virtual bases.
+ else
+ NonZeroOffset = true;
+ }
+ VirtualBase = VirtualBase && IsVirtual;
+ }
+
+ assert((VirtualBase || NonZeroOffset) &&
+ "Should have returned if has non-virtual base with zero offset");
+
+ QualType BaseType =
+ ReinterpretKind == ReinterpretUpcast? DestType : SrcType;
+ QualType DerivedType =
+ ReinterpretKind == ReinterpretUpcast? SrcType : DestType;
+
+ SourceLocation BeginLoc = OpRange.getBegin();
+ Self.Diag(BeginLoc, diag::warn_reinterpret_different_from_static)
+ << DerivedType << BaseType << !VirtualBase << ReinterpretKind
+ << OpRange;
+ Self.Diag(BeginLoc, diag::note_reinterpret_updowncast_use_static)
+ << ReinterpretKind
+ << FixItHint::CreateReplacement(BeginLoc, "static_cast");
+}
+
/// CheckReinterpretCast - Check that a reinterpret_cast\<DestType\>(SrcExpr) is
/// valid.
/// Refer to C++ 5.2.10 for details. reinterpret_cast is typically used in code
@@ -710,8 +807,10 @@ void CastOperation::CheckReinterpretCast() {
diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr.get(),
DestType, /*listInitialization=*/false);
}
- } else if (tcr == TC_Success && Self.getLangOpts().ObjCAutoRefCount) {
- checkObjCARCConversion(Sema::CCK_OtherCast);
+ } else if (tcr == TC_Success) {
+ if (Self.getLangOpts().ObjCAutoRefCount)
+ checkObjCARCConversion(Sema::CCK_OtherCast);
+ DiagnoseReinterpretUpDownCast(Self, SrcExpr.get(), DestType, OpRange);
}
}
@@ -1479,6 +1578,8 @@ void Sema::CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType,
static void DiagnoseCastOfObjCSEL(Sema &Self, const ExprResult &SrcExpr,
QualType DestType) {
QualType SrcType = SrcExpr.get()->getType();
+ if (Self.Context.hasSameType(SrcType, DestType))
+ return;
if (const PointerType *SrcPtrTy = SrcType->getAs<PointerType>())
if (SrcPtrTy->isObjCSelType()) {
QualType DT = DestType;
@@ -1773,7 +1874,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
// FIXME: Conditionally-supported behavior should be configurable in the
// TargetInfo or similar.
Self.Diag(OpRange.getBegin(),
- Self.getLangOpts().CPlusPlus0x ?
+ Self.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_cast_fn_obj : diag::ext_cast_fn_obj)
<< OpRange;
return TC_Success;
@@ -1782,7 +1883,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
if (DestType->isFunctionPointerType()) {
// See above.
Self.Diag(OpRange.getBegin(),
- Self.getLangOpts().CPlusPlus0x ?
+ Self.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_cast_fn_obj : diag::ext_cast_fn_obj)
<< OpRange;
return TC_Success;
@@ -2102,6 +2203,15 @@ void CastOperation::CheckCStyleCast() {
}
}
+ if (Self.getLangOpts().OpenCL && !Self.getOpenCLOptions().cl_khr_fp16) {
+ if (DestType->isHalfType()) {
+ Self.Diag(SrcExpr.get()->getLocStart(), diag::err_opencl_cast_to_half)
+ << DestType << SrcExpr.get()->getSourceRange();
+ SrcExpr = ExprError();
+ return;
+ }
+ }
+
// ARC imposes extra restrictions on casts.
if (Self.getLangOpts().ObjCAutoRefCount) {
checkObjCARCConversion(Sema::CCK_CStyleCast);
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 692a210..4e11b3a 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -12,32 +12,31 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Sema/Initialization.h"
-#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Initialization.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/ScopeInfo.h"
-#include "clang/Analysis/Analyses/FormatString.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
-#include "clang/AST/EvaluatedExprVisitor.h"
-#include "clang/AST/DeclObjC.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
+#include "clang/Analysis/Analyses/FormatString.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/TargetBuiltins.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Initialization.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/Sema.h"
#include "llvm/ADT/BitVector.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/raw_ostream.h"
-#include "clang/Basic/TargetBuiltins.h"
-#include "clang/Basic/TargetInfo.h"
-#include "clang/Basic/ConvertUTF.h"
#include <limits>
using namespace clang;
using namespace sema;
@@ -488,8 +487,8 @@ bool Sema::getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember,
/// Handles the checks for format strings, non-POD arguments to vararg
/// functions, and NULL arguments passed to non-NULL parameters.
-void Sema::checkCall(NamedDecl *FDecl, Expr **Args,
- unsigned NumArgs,
+void Sema::checkCall(NamedDecl *FDecl,
+ ArrayRef<const Expr *> Args,
unsigned NumProtoArgs,
bool IsMemberFunction,
SourceLocation Loc,
@@ -503,41 +502,40 @@ void Sema::checkCall(NamedDecl *FDecl, Expr **Args,
for (specific_attr_iterator<FormatAttr>
I = FDecl->specific_attr_begin<FormatAttr>(),
E = FDecl->specific_attr_end<FormatAttr>(); I != E ; ++I)
- if (CheckFormatArguments(*I, Args, NumArgs, IsMemberFunction, CallType,
- Loc, Range))
+ if (CheckFormatArguments(*I, Args, IsMemberFunction, CallType, Loc, Range))
HandledFormatString = true;
// Refuse POD arguments that weren't caught by the format string
// checks above.
if (!HandledFormatString && CallType != VariadicDoesNotApply)
- for (unsigned ArgIdx = NumProtoArgs; ArgIdx < NumArgs; ++ArgIdx) {
+ for (unsigned ArgIdx = NumProtoArgs; ArgIdx < Args.size(); ++ArgIdx) {
// Args[ArgIdx] can be null in malformed code.
- if (Expr *Arg = Args[ArgIdx])
+ if (const Expr *Arg = Args[ArgIdx])
variadicArgumentPODCheck(Arg, CallType);
}
for (specific_attr_iterator<NonNullAttr>
I = FDecl->specific_attr_begin<NonNullAttr>(),
E = FDecl->specific_attr_end<NonNullAttr>(); I != E; ++I)
- CheckNonNullArguments(*I, Args, Loc);
+ CheckNonNullArguments(*I, Args.data(), Loc);
// Type safety checking.
for (specific_attr_iterator<ArgumentWithTypeTagAttr>
i = FDecl->specific_attr_begin<ArgumentWithTypeTagAttr>(),
e = FDecl->specific_attr_end<ArgumentWithTypeTagAttr>(); i != e; ++i) {
- CheckArgumentWithTypeTag(*i, Args);
+ CheckArgumentWithTypeTag(*i, Args.data());
}
}
/// CheckConstructorCall - Check a constructor call for correctness and safety
/// properties not enforced by the C type system.
-void Sema::CheckConstructorCall(FunctionDecl *FDecl, Expr **Args,
- unsigned NumArgs,
+void Sema::CheckConstructorCall(FunctionDecl *FDecl,
+ ArrayRef<const Expr *> Args,
const FunctionProtoType *Proto,
SourceLocation Loc) {
VariadicCallType CallType =
Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply;
- checkCall(FDecl, Args, NumArgs, Proto->getNumArgs(),
+ checkCall(FDecl, Args, Proto->getNumArgs(),
/*IsMemberFunction=*/true, Loc, SourceRange(), CallType);
}
@@ -561,7 +559,8 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
++Args;
--NumArgs;
}
- checkCall(FDecl, Args, NumArgs, NumProtoArgs,
+ checkCall(FDecl, llvm::makeArrayRef<const Expr *>(Args, NumArgs),
+ NumProtoArgs,
IsMemberFunction, TheCall->getRParenLoc(),
TheCall->getCallee()->getSourceRange(), CallType);
@@ -591,7 +590,8 @@ bool Sema::CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation lbrac,
VariadicCallType CallType =
Method->isVariadic() ? VariadicMethod : VariadicDoesNotApply;
- checkCall(Method, Args, NumArgs, Method->param_size(),
+ checkCall(Method, llvm::makeArrayRef<const Expr *>(Args, NumArgs),
+ Method->param_size(),
/*IsMemberFunction=*/false,
lbrac, Method->getSourceRange(), CallType);
@@ -612,7 +612,9 @@ bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall,
Proto && Proto->isVariadic() ? VariadicBlock : VariadicDoesNotApply ;
unsigned NumProtoArgs = Proto ? Proto->getNumArgs() : 0;
- checkCall(NDecl, TheCall->getArgs(), TheCall->getNumArgs(),
+ checkCall(NDecl,
+ llvm::makeArrayRef<const Expr *>(TheCall->getArgs(),
+ TheCall->getNumArgs()),
NumProtoArgs, /*IsMemberFunction=*/false,
TheCall->getRParenLoc(),
TheCall->getCallee()->getSourceRange(), CallType);
@@ -1646,8 +1648,8 @@ bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) {
// format string, we will usually need to emit a warning.
// True string literals are then checked by CheckFormatString.
Sema::StringLiteralCheckType
-Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
- unsigned NumArgs, bool HasVAListArg,
+Sema::checkFormatStringExpr(const Expr *E, ArrayRef<const Expr *> Args,
+ bool HasVAListArg,
unsigned format_idx, unsigned firstDataArg,
FormatStringType Type, VariadicCallType CallType,
bool inFunctionCall) {
@@ -1672,13 +1674,13 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
const AbstractConditionalOperator *C =
cast<AbstractConditionalOperator>(E);
StringLiteralCheckType Left =
- checkFormatStringExpr(C->getTrueExpr(), Args, NumArgs,
+ checkFormatStringExpr(C->getTrueExpr(), Args,
HasVAListArg, format_idx, firstDataArg,
Type, CallType, inFunctionCall);
if (Left == SLCT_NotALiteral)
return SLCT_NotALiteral;
StringLiteralCheckType Right =
- checkFormatStringExpr(C->getFalseExpr(), Args, NumArgs,
+ checkFormatStringExpr(C->getFalseExpr(), Args,
HasVAListArg, format_idx, firstDataArg,
Type, CallType, inFunctionCall);
return Left < Right ? Left : Right;
@@ -1729,7 +1731,7 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
if (InitList->isStringLiteralInit())
Init = InitList->getInit(0)->IgnoreParenImpCasts();
}
- return checkFormatStringExpr(Init, Args, NumArgs,
+ return checkFormatStringExpr(Init, Args,
HasVAListArg, format_idx,
firstDataArg, Type, CallType,
/*inFunctionCall*/false);
@@ -1787,7 +1789,7 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
--ArgIndex;
const Expr *Arg = CE->getArg(ArgIndex - 1);
- return checkFormatStringExpr(Arg, Args, NumArgs,
+ return checkFormatStringExpr(Arg, Args,
HasVAListArg, format_idx, firstDataArg,
Type, CallType, inFunctionCall);
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
@@ -1795,7 +1797,7 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString ||
BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) {
const Expr *Arg = CE->getArg(0);
- return checkFormatStringExpr(Arg, Args, NumArgs,
+ return checkFormatStringExpr(Arg, Args,
HasVAListArg, format_idx,
firstDataArg, Type, CallType,
inFunctionCall);
@@ -1815,7 +1817,7 @@ Sema::checkFormatStringExpr(const Expr *E, Expr **Args,
StrE = cast<StringLiteral>(E);
if (StrE) {
- CheckFormatString(StrE, E, Args, NumArgs, HasVAListArg, format_idx,
+ CheckFormatString(StrE, E, Args, HasVAListArg, format_idx,
firstDataArg, Type, inFunctionCall, CallType);
return SLCT_CheckedLiteral;
}
@@ -1836,8 +1838,20 @@ Sema::CheckNonNullArguments(const NonNullAttr *NonNull,
e = NonNull->args_end();
i != e; ++i) {
const Expr *ArgExpr = ExprArgs[*i];
- if (ArgExpr->isNullPointerConstant(Context,
- Expr::NPC_ValueDependentIsNotNull))
+
+ // As a special case, transparent unions initialized with zero are
+ // considered null for the purposes of the nonnull attribute.
+ if (const RecordType *UT = ArgExpr->getType()->getAsUnionType()) {
+ if (UT->getDecl()->hasAttr<TransparentUnionAttr>())
+ if (const CompoundLiteralExpr *CLE =
+ dyn_cast<CompoundLiteralExpr>(ArgExpr))
+ if (const InitListExpr *ILE =
+ dyn_cast<InitListExpr>(CLE->getInitializer()))
+ ArgExpr = ILE->getInit(0);
+ }
+
+ bool Result;
+ if (ArgExpr->EvaluateAsBooleanCondition(Result, Context) && !Result)
Diag(CallSiteLoc, diag::warn_null_arg) << ArgExpr->getSourceRange();
}
}
@@ -1856,25 +1870,26 @@ Sema::FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) {
/// CheckFormatArguments - Check calls to printf and scanf (and similar
/// functions) for correct use of format strings.
/// Returns true if a format string has been fully checked.
-bool Sema::CheckFormatArguments(const FormatAttr *Format, Expr **Args,
- unsigned NumArgs, bool IsCXXMember,
+bool Sema::CheckFormatArguments(const FormatAttr *Format,
+ ArrayRef<const Expr *> Args,
+ bool IsCXXMember,
VariadicCallType CallType,
SourceLocation Loc, SourceRange Range) {
FormatStringInfo FSI;
if (getFormatStringInfo(Format, IsCXXMember, &FSI))
- return CheckFormatArguments(Args, NumArgs, FSI.HasVAListArg, FSI.FormatIdx,
+ return CheckFormatArguments(Args, FSI.HasVAListArg, FSI.FormatIdx,
FSI.FirstDataArg, GetFormatStringType(Format),
CallType, Loc, Range);
return false;
}
-bool Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs,
+bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args,
bool HasVAListArg, unsigned format_idx,
unsigned firstDataArg, FormatStringType Type,
VariadicCallType CallType,
SourceLocation Loc, SourceRange Range) {
// CHECK: printf/scanf-like function is called with no format string.
- if (format_idx >= NumArgs) {
+ if (format_idx >= Args.size()) {
Diag(Loc, diag::warn_missing_format_string) << Range;
return false;
}
@@ -1894,7 +1909,7 @@ bool Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs,
// ObjC string uses the same format specifiers as C string, so we can use
// the same format string checking logic for both ObjC and C strings.
StringLiteralCheckType CT =
- checkFormatStringExpr(OrigFormatExpr, Args, NumArgs, HasVAListArg,
+ checkFormatStringExpr(OrigFormatExpr, Args, HasVAListArg,
format_idx, firstDataArg, Type, CallType);
if (CT != SLCT_NotALiteral)
// Literal format string found, check done!
@@ -1915,7 +1930,7 @@ bool Sema::CheckFormatArguments(Expr **Args, unsigned NumArgs,
// If there are no arguments specified, warn with -Wformat-security, otherwise
// warn only with -Wformat-nonliteral.
- if (NumArgs == format_idx+1)
+ if (Args.size() == format_idx+1)
Diag(Args[format_idx]->getLocStart(),
diag::warn_format_nonliteral_noargs)
<< OrigFormatExpr->getSourceRange();
@@ -1936,8 +1951,7 @@ protected:
const unsigned NumDataArgs;
const char *Beg; // Start of format string.
const bool HasVAListArg;
- const Expr * const *Args;
- const unsigned NumArgs;
+ ArrayRef<const Expr *> Args;
unsigned FormatIdx;
llvm::BitVector CoveredArgs;
bool usesPositionalArgs;
@@ -1948,13 +1962,13 @@ public:
CheckFormatHandler(Sema &s, const StringLiteral *fexpr,
const Expr *origFormatExpr, unsigned firstDataArg,
unsigned numDataArgs, const char *beg, bool hasVAListArg,
- Expr **args, unsigned numArgs,
+ ArrayRef<const Expr *> Args,
unsigned formatIdx, bool inFunctionCall,
Sema::VariadicCallType callType)
: S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr),
FirstDataArg(firstDataArg), NumDataArgs(numDataArgs),
Beg(beg), HasVAListArg(hasVAListArg),
- Args(args), NumArgs(numArgs), FormatIdx(formatIdx),
+ Args(Args), FormatIdx(formatIdx),
usesPositionalArgs(false), atFirstArg(true),
inFunctionCall(inFunctionCall), CallType(callType) {
CoveredArgs.resize(numDataArgs);
@@ -2066,7 +2080,7 @@ void CheckFormatHandler::HandleInvalidLengthModifier(
CharSourceRange LMRange = getSpecifierRange(LM.getStart(), LM.getLength());
// See if we know how to fix this length modifier.
- llvm::Optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier();
+ Optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier();
if (FixedLM) {
EmitFormatDiagnostic(S.PDiag(DiagID) << LM.toString() << CS.toString(),
getLocationOfByte(LM.getStart()),
@@ -2099,7 +2113,7 @@ void CheckFormatHandler::HandleNonStandardLengthModifier(
CharSourceRange LMRange = getSpecifierRange(LM.getStart(), LM.getLength());
// See if we know how to fix this length modifier.
- llvm::Optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier();
+ Optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier();
if (FixedLM) {
EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard)
<< LM.toString() << 0,
@@ -2126,7 +2140,7 @@ void CheckFormatHandler::HandleNonStandardConversionSpecifier(
using namespace analyze_format_string;
// See if we know how to fix this conversion specifier.
- llvm::Optional<ConversionSpecifier> FixedCS = CS.getStandardSpecifier();
+ Optional<ConversionSpecifier> FixedCS = CS.getStandardSpecifier();
if (FixedCS) {
EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard)
<< CS.toString() << /*conversion specifier*/1,
@@ -2346,11 +2360,11 @@ public:
const Expr *origFormatExpr, unsigned firstDataArg,
unsigned numDataArgs, bool isObjC,
const char *beg, bool hasVAListArg,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<const Expr *> Args,
unsigned formatIdx, bool inFunctionCall,
Sema::VariadicCallType CallType)
: CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg,
- numDataArgs, beg, hasVAListArg, Args, NumArgs,
+ numDataArgs, beg, hasVAListArg, Args,
formatIdx, inFunctionCall, CallType), ObjCContext(isObjC)
{}
@@ -2690,12 +2704,24 @@ static bool requiresParensToAddCast(const Expr *E) {
switch (Inside->getStmtClass()) {
case Stmt::ArraySubscriptExprClass:
case Stmt::CallExprClass:
+ case Stmt::CharacterLiteralClass:
+ case Stmt::CXXBoolLiteralExprClass:
case Stmt::DeclRefExprClass:
+ case Stmt::FloatingLiteralClass:
+ case Stmt::IntegerLiteralClass:
case Stmt::MemberExprClass:
+ case Stmt::ObjCArrayLiteralClass:
+ case Stmt::ObjCBoolLiteralExprClass:
+ case Stmt::ObjCBoxedExprClass:
+ case Stmt::ObjCDictionaryLiteralClass:
+ case Stmt::ObjCEncodeExprClass:
case Stmt::ObjCIvarRefExprClass:
case Stmt::ObjCMessageExprClass:
case Stmt::ObjCPropertyRefExprClass:
+ case Stmt::ObjCStringLiteralClass:
+ case Stmt::ObjCSubscriptRefExprClass:
case Stmt::ParenExprClass:
+ case Stmt::StringLiteralClass:
case Stmt::UnaryOperatorClass:
return false;
default:
@@ -2717,8 +2743,8 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
if (!AT.isValid())
return true;
- QualType IntendedTy = E->getType();
- if (AT.matchesType(S.Context, IntendedTy))
+ QualType ExprTy = E->getType();
+ if (AT.matchesType(S.Context, ExprTy))
return true;
// Look through argument promotions for our error message's reported type.
@@ -2729,7 +2755,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
if (ICE->getCastKind() == CK_IntegralCast ||
ICE->getCastKind() == CK_FloatingCast) {
E = ICE->getSubExpr();
- IntendedTy = E->getType();
+ ExprTy = 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
@@ -2737,22 +2763,63 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
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))
+ if (AT.matchesType(S.Context, ExprTy))
return true;
}
}
+ } else if (const CharacterLiteral *CL = dyn_cast<CharacterLiteral>(E)) {
+ // Special case for 'a', which has type 'int' in C.
+ // Note, however, that we do /not/ want to treat multibyte constants like
+ // 'MooV' as characters! This form is deprecated but still exists.
+ if (ExprTy == S.Context.IntTy)
+ if (llvm::isUIntN(S.Context.getCharWidth(), CL->getValue()))
+ ExprTy = S.Context.CharTy;
+ }
+
+ // %C in an Objective-C context prints a unichar, not a wchar_t.
+ // If the argument is an integer of some kind, believe the %C and suggest
+ // a cast instead of changing the conversion specifier.
+ QualType IntendedTy = ExprTy;
+ if (ObjCContext &&
+ FS.getConversionSpecifier().getKind() == ConversionSpecifier::CArg) {
+ if (ExprTy->isIntegralOrUnscopedEnumerationType() &&
+ !ExprTy->isCharType()) {
+ // 'unichar' is defined as a typedef of unsigned short, but we should
+ // prefer using the typedef if it is visible.
+ IntendedTy = S.Context.UnsignedShortTy;
+
+ LookupResult Result(S, &S.Context.Idents.get("unichar"), E->getLocStart(),
+ Sema::LookupOrdinaryName);
+ if (S.LookupName(Result, S.getCurScope())) {
+ NamedDecl *ND = Result.getFoundDecl();
+ if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(ND))
+ if (TD->getUnderlyingType() == IntendedTy)
+ IntendedTy = S.Context.getTypedefType(TD);
+ }
+ }
}
+ // Special-case some of Darwin's platform-independence types by suggesting
+ // casts to primitive types that are known to be large enough.
+ bool ShouldNotPrintDirectly = false;
if (S.Context.getTargetInfo().getTriple().isOSDarwin()) {
- // Special-case some of Darwin's platform-independence types.
- if (const TypedefType *UserTy = IntendedTy->getAs<TypedefType>()) {
+ // Use a 'while' to peel off layers of typedefs.
+ QualType TyTy = IntendedTy;
+ while (const TypedefType *UserTy = TyTy->getAs<TypedefType>()) {
StringRef Name = UserTy->getDecl()->getName();
- IntendedTy = llvm::StringSwitch<QualType>(Name)
+ QualType CastTy = llvm::StringSwitch<QualType>(Name)
.Case("NSInteger", S.Context.LongTy)
.Case("NSUInteger", S.Context.UnsignedLongTy)
.Case("SInt32", S.Context.IntTy)
.Case("UInt32", S.Context.UnsignedIntTy)
- .Default(IntendedTy);
+ .Default(QualType());
+
+ if (!CastTy.isNull()) {
+ ShouldNotPrintDirectly = true;
+ IntendedTy = CastTy;
+ break;
+ }
+ TyTy = UserTy->desugar();
}
}
@@ -2769,7 +2836,19 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
CharSourceRange SpecRange = getSpecifierRange(StartSpecifier, SpecifierLen);
- if (IntendedTy != E->getType()) {
+ if (IntendedTy == ExprTy) {
+ // In this case, the specifier is wrong and should be changed to match
+ // the argument.
+ EmitFormatDiagnostic(
+ S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
+ << AT.getRepresentativeTypeName(S.Context) << IntendedTy
+ << E->getSourceRange(),
+ E->getLocStart(),
+ /*IsStringLocation*/false,
+ SpecRange,
+ FixItHint::CreateReplacement(SpecRange, os.str()));
+
+ } else {
// 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
@@ -2807,26 +2886,28 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
Hints.push_back(FixItHint::CreateInsertion(After, ")"));
}
- // We extract the name from the typedef because we don't want to show
- // the underlying type in the diagnostic.
- const TypedefType *UserTy = cast<TypedefType>(E->getType());
- StringRef Name = UserTy->getDecl()->getName();
-
- // Finally, emit the diagnostic.
- EmitFormatDiagnostic(S.PDiag(diag::warn_format_argument_needs_cast)
- << Name << IntendedTy
- << E->getSourceRange(),
- E->getLocStart(), /*IsStringLocation=*/false,
- SpecRange, Hints);
- } else {
- EmitFormatDiagnostic(
- S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
- << AT.getRepresentativeTypeName(S.Context) << IntendedTy
- << E->getSourceRange(),
- E->getLocStart(),
- /*IsStringLocation*/false,
- SpecRange,
- FixItHint::CreateReplacement(SpecRange, os.str()));
+ if (ShouldNotPrintDirectly) {
+ // The expression has a type that should not be printed directly.
+ // We extract the name from the typedef because we don't want to show
+ // the underlying type in the diagnostic.
+ StringRef Name = cast<TypedefType>(ExprTy)->getDecl()->getName();
+
+ EmitFormatDiagnostic(S.PDiag(diag::warn_format_argument_needs_cast)
+ << Name << IntendedTy
+ << E->getSourceRange(),
+ E->getLocStart(), /*IsStringLocation=*/false,
+ SpecRange, Hints);
+ } else {
+ // In this case, the expression could be printed using a different
+ // specifier, but we've decided that the specifier is probably correct
+ // and we should cast instead. Just use the normal warning message.
+ EmitFormatDiagnostic(
+ S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
+ << AT.getRepresentativeTypeName(S.Context) << ExprTy
+ << E->getSourceRange(),
+ E->getLocStart(), /*IsStringLocation*/false,
+ SpecRange, Hints);
+ }
}
} else {
const CharSourceRange &CSR = getSpecifierRange(StartSpecifier,
@@ -2834,17 +2915,17 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
// Since the warning for passing non-POD types to variadic functions
// was deferred until now, we emit a warning for non-POD
// arguments here.
- if (S.isValidVarArgType(E->getType()) == Sema::VAK_Invalid) {
+ if (S.isValidVarArgType(ExprTy) == Sema::VAK_Invalid) {
unsigned DiagKind;
- if (E->getType()->isObjCObjectType())
+ if (ExprTy->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()
+ << S.getLangOpts().CPlusPlus11
+ << ExprTy
<< CallType
<< AT.getRepresentativeTypeName(S.Context)
<< CSR
@@ -2855,7 +2936,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
} else
EmitFormatDiagnostic(
S.PDiag(diag::warn_printf_conversion_argument_type_mismatch)
- << AT.getRepresentativeTypeName(S.Context) << E->getType()
+ << AT.getRepresentativeTypeName(S.Context) << ExprTy
<< CSR
<< E->getSourceRange(),
E->getLocStart(), /*IsStringLocation*/false, CSR);
@@ -2872,12 +2953,12 @@ public:
CheckScanfHandler(Sema &s, const StringLiteral *fexpr,
const Expr *origFormatExpr, unsigned firstDataArg,
unsigned numDataArgs, const char *beg, bool hasVAListArg,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<const Expr *> Args,
unsigned formatIdx, bool inFunctionCall,
Sema::VariadicCallType CallType)
: CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg,
numDataArgs, beg, hasVAListArg,
- Args, NumArgs, formatIdx, inFunctionCall, CallType)
+ Args, formatIdx, inFunctionCall, CallType)
{}
bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
@@ -3029,7 +3110,7 @@ bool CheckScanfHandler::HandleScanfSpecifier(
void Sema::CheckFormatString(const StringLiteral *FExpr,
const Expr *OrigFormatExpr,
- Expr **Args, unsigned NumArgs,
+ ArrayRef<const Expr *> Args,
bool HasVAListArg, unsigned format_idx,
unsigned firstDataArg, FormatStringType Type,
bool inFunctionCall, VariadicCallType CallType) {
@@ -3047,7 +3128,7 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
StringRef StrRef = FExpr->getString();
const char *Str = StrRef.data();
unsigned StrLen = StrRef.size();
- const unsigned numDataArgs = NumArgs - firstDataArg;
+ const unsigned numDataArgs = Args.size() - firstDataArg;
// CHECK: empty format string?
if (StrLen == 0 && numDataArgs > 0) {
@@ -3061,7 +3142,7 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
if (Type == FST_Printf || Type == FST_NSString) {
CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg,
numDataArgs, (Type == FST_NSString),
- Str, HasVAListArg, Args, NumArgs, format_idx,
+ Str, HasVAListArg, Args, format_idx,
inFunctionCall, CallType);
if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen,
@@ -3070,7 +3151,7 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
H.DoneProcessing();
} else if (Type == FST_Scanf) {
CheckScanfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, numDataArgs,
- Str, HasVAListArg, Args, NumArgs, format_idx,
+ Str, HasVAListArg, Args, format_idx,
inFunctionCall, CallType);
if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen,
@@ -3177,7 +3258,8 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
if (const UnaryOperator *UnaryOp = dyn_cast<UnaryOperator>(Dest))
if (UnaryOp->getOpcode() == UO_AddrOf)
ActionIdx = 1; // If its an address-of operator, just remove it.
- if (Context.getTypeSize(PointeeTy) == Context.getCharWidth())
+ if (!PointeeTy->isIncompleteType() &&
+ (Context.getTypeSize(PointeeTy) == Context.getCharWidth()))
ActionIdx = 2; // If the pointee's size is sizeof(char),
// suggest an explicit length.
@@ -3922,7 +4004,11 @@ struct IntRange {
unsigned NumPositive = Enum->getNumPositiveBits();
unsigned NumNegative = Enum->getNumNegativeBits();
- return IntRange(std::max(NumPositive, NumNegative), NumNegative == 0);
+ if (NumNegative == 0)
+ return IntRange(NumPositive, true/*NonNegative*/);
+ else
+ return IntRange(std::max(NumPositive + 1, NumNegative),
+ false/*NonNegative*/);
}
const BuiltinType *BT = cast<BuiltinType>(T);
@@ -4328,38 +4414,108 @@ static void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E,
Expr *Constant, Expr *Other,
llvm::APSInt Value,
bool RhsConstant) {
+ // 0 values are handled later by CheckTrivialUnsignedComparison().
+ if (Value == 0)
+ return;
+
BinaryOperatorKind op = E->getOpcode();
QualType OtherT = Other->getType();
QualType ConstantT = Constant->getType();
+ QualType CommonT = E->getLHS()->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
+
+ bool ConstantSigned = ConstantT->isSignedIntegerType();
+ bool CommonSigned = CommonT->isSignedIntegerType();
+
+ bool EqualityOnly = false;
+
+ // TODO: Investigate using GetExprRange() to get tighter bounds on
+ // on the bit ranges.
IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT);
- IntRange LitRange = GetValueRange(S.Context, Value, Value.getBitWidth());
- if (OtherRange.Width >= LitRange.Width)
- return;
+ unsigned OtherWidth = OtherRange.Width;
+
+ if (CommonSigned) {
+ // The common type is signed, therefore no signed to unsigned conversion.
+ if (!OtherRange.NonNegative) {
+ // Check that the constant is representable in type OtherT.
+ if (ConstantSigned) {
+ if (OtherWidth >= Value.getMinSignedBits())
+ return;
+ } else { // !ConstantSigned
+ if (OtherWidth >= Value.getActiveBits() + 1)
+ return;
+ }
+ } else { // !OtherSigned
+ // Check that the constant is representable in type OtherT.
+ // Negative values are out of range.
+ if (ConstantSigned) {
+ if (Value.isNonNegative() && OtherWidth >= Value.getActiveBits())
+ return;
+ } else { // !ConstantSigned
+ if (OtherWidth >= Value.getActiveBits())
+ return;
+ }
+ }
+ } else { // !CommonSigned
+ if (OtherRange.NonNegative) {
+ if (OtherWidth >= Value.getActiveBits())
+ return;
+ } else if (!OtherRange.NonNegative && !ConstantSigned) {
+ // Check to see if the constant is representable in OtherT.
+ if (OtherWidth > Value.getActiveBits())
+ return;
+ // Check to see if the constant is equivalent to a negative value
+ // cast to CommonT.
+ if (S.Context.getIntWidth(ConstantT) == S.Context.getIntWidth(CommonT) &&
+ Value.isNegative() && Value.getMinSignedBits() <= OtherWidth)
+ return;
+ // The constant value rests between values that OtherT can represent after
+ // conversion. Relational comparison still works, but equality
+ // comparisons will be tautological.
+ EqualityOnly = true;
+ } else { // OtherSigned && ConstantSigned
+ assert(0 && "Two signed types converted to unsigned types.");
+ }
+ }
+
+ bool PositiveConstant = !ConstantSigned || Value.isNonNegative();
+
bool IsTrue = true;
- if (op == BO_EQ)
- IsTrue = false;
- else if (op == BO_NE)
- IsTrue = true;
- else if (RhsConstant) {
+ if (op == BO_EQ || op == BO_NE) {
+ IsTrue = op == BO_NE;
+ } else if (EqualityOnly) {
+ return;
+ } else if (RhsConstant) {
if (op == BO_GT || op == BO_GE)
- IsTrue = !LitRange.NonNegative;
+ IsTrue = !PositiveConstant;
else // op == BO_LT || op == BO_LE
- IsTrue = LitRange.NonNegative;
+ IsTrue = PositiveConstant;
} else {
if (op == BO_LT || op == BO_LE)
- IsTrue = !LitRange.NonNegative;
+ IsTrue = !PositiveConstant;
else // op == BO_GT || op == BO_GE
- IsTrue = LitRange.NonNegative;
+ IsTrue = PositiveConstant;
}
- SmallString<16> PrettySourceValue(Value.toString(10));
+
+ // If this is a comparison to an enum constant, include that
+ // constant in the diagnostic.
+ const EnumConstantDecl *ED = 0;
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Constant))
+ ED = dyn_cast<EnumConstantDecl>(DR->getDecl());
+
+ SmallString<64> PrettySourceValue;
+ llvm::raw_svector_ostream OS(PrettySourceValue);
+ if (ED)
+ OS << '\'' << *ED << "' (" << Value << ")";
+ else
+ OS << Value;
+
S.Diag(E->getOperatorLoc(), diag::warn_out_of_range_compare)
- << PrettySourceValue << OtherT << IsTrue
- << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
+ << OS.str() << OtherT << IsTrue
+ << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
}
/// Analyze the operands of the given comparison. Implements the
@@ -4800,7 +4956,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
if ((E->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull)
== Expr::NPCK_GNUNull) && !Target->isAnyPointerType()
&& !Target->isBlockPointerType() && !Target->isMemberPointerType()
- && Target->isScalarType()) {
+ && Target->isScalarType() && !Target->isNullPtrType()) {
SourceLocation Loc = E->getSourceRange().getBegin();
if (Loc.isMacroID())
Loc = S.SourceMgr.getImmediateExpansionRange(Loc).first;
@@ -4843,7 +4999,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
// People want to build with -Wshorten-64-to-32 and not -Wconversion.
if (S.SourceMgr.isInSystemMacro(CC))
return;
-
+
if (TargetRange.Width == 32 && S.Context.getIntWidth(E->getType()) == 64)
return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_integer_64_32,
/* pruneControlFlow */ true);
@@ -4887,10 +5043,8 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
if (const EnumType *SourceEnum = Source->getAs<EnumType>())
if (const EnumType *TargetEnum = Target->getAs<EnumType>())
- if ((SourceEnum->getDecl()->getIdentifier() ||
- SourceEnum->getDecl()->getTypedefNameForAnonDecl()) &&
- (TargetEnum->getDecl()->getIdentifier() ||
- TargetEnum->getDecl()->getTypedefNameForAnonDecl()) &&
+ if (SourceEnum->getDecl()->hasNameForLinkage() &&
+ TargetEnum->getDecl()->hasNameForLinkage() &&
SourceEnum != TargetEnum) {
if (S.SourceMgr.isInSystemMacro(CC))
return;
@@ -5046,6 +5200,462 @@ void Sema::CheckImplicitConversions(Expr *E, SourceLocation CC) {
AnalyzeImplicitConversions(*this, E, CC);
}
+/// Diagnose when expression is an integer constant expression and its evaluation
+/// results in integer overflow
+void Sema::CheckForIntOverflow (Expr *E) {
+ if (isa<BinaryOperator>(E->IgnoreParens())) {
+ llvm::SmallVector<PartialDiagnosticAt, 4> Diags;
+ E->EvaluateForOverflow(Context, &Diags);
+ }
+}
+
+namespace {
+/// \brief Visitor for expressions which looks for unsequenced operations on the
+/// same object.
+class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
+ /// \brief A tree of sequenced regions within an expression. Two regions are
+ /// unsequenced if one is an ancestor or a descendent of the other. When we
+ /// finish processing an expression with sequencing, such as a comma
+ /// expression, we fold its tree nodes into its parent, since they are
+ /// unsequenced with respect to nodes we will visit later.
+ class SequenceTree {
+ struct Value {
+ explicit Value(unsigned Parent) : Parent(Parent), Merged(false) {}
+ unsigned Parent : 31;
+ bool Merged : 1;
+ };
+ llvm::SmallVector<Value, 8> Values;
+
+ public:
+ /// \brief A region within an expression which may be sequenced with respect
+ /// to some other region.
+ class Seq {
+ explicit Seq(unsigned N) : Index(N) {}
+ unsigned Index;
+ friend class SequenceTree;
+ public:
+ Seq() : Index(0) {}
+ };
+
+ SequenceTree() { Values.push_back(Value(0)); }
+ Seq root() const { return Seq(0); }
+
+ /// \brief Create a new sequence of operations, which is an unsequenced
+ /// subset of \p Parent. This sequence of operations is sequenced with
+ /// respect to other children of \p Parent.
+ Seq allocate(Seq Parent) {
+ Values.push_back(Value(Parent.Index));
+ return Seq(Values.size() - 1);
+ }
+
+ /// \brief Merge a sequence of operations into its parent.
+ void merge(Seq S) {
+ Values[S.Index].Merged = true;
+ }
+
+ /// \brief Determine whether two operations are unsequenced. This operation
+ /// is asymmetric: \p Cur should be the more recent sequence, and \p Old
+ /// should have been merged into its parent as appropriate.
+ bool isUnsequenced(Seq Cur, Seq Old) {
+ unsigned C = representative(Cur.Index);
+ unsigned Target = representative(Old.Index);
+ while (C >= Target) {
+ if (C == Target)
+ return true;
+ C = Values[C].Parent;
+ }
+ return false;
+ }
+
+ private:
+ /// \brief Pick a representative for a sequence.
+ unsigned representative(unsigned K) {
+ if (Values[K].Merged)
+ // Perform path compression as we go.
+ return Values[K].Parent = representative(Values[K].Parent);
+ return K;
+ }
+ };
+
+ /// An object for which we can track unsequenced uses.
+ typedef NamedDecl *Object;
+
+ /// Different flavors of object usage which we track. We only track the
+ /// least-sequenced usage of each kind.
+ enum UsageKind {
+ /// A read of an object. Multiple unsequenced reads are OK.
+ UK_Use,
+ /// A modification of an object which is sequenced before the value
+ /// computation of the expression, such as ++n.
+ UK_ModAsValue,
+ /// A modification of an object which is not sequenced before the value
+ /// computation of the expression, such as n++.
+ UK_ModAsSideEffect,
+
+ UK_Count = UK_ModAsSideEffect + 1
+ };
+
+ struct Usage {
+ Usage() : Use(0), Seq() {}
+ Expr *Use;
+ SequenceTree::Seq Seq;
+ };
+
+ struct UsageInfo {
+ UsageInfo() : Diagnosed(false) {}
+ Usage Uses[UK_Count];
+ /// Have we issued a diagnostic for this variable already?
+ bool Diagnosed;
+ };
+ typedef llvm::SmallDenseMap<Object, UsageInfo, 16> UsageInfoMap;
+
+ Sema &SemaRef;
+ /// Sequenced regions within the expression.
+ SequenceTree Tree;
+ /// Declaration modifications and references which we have seen.
+ UsageInfoMap UsageMap;
+ /// The region we are currently within.
+ SequenceTree::Seq Region;
+ /// Filled in with declarations which were modified as a side-effect
+ /// (that is, post-increment operations).
+ llvm::SmallVectorImpl<std::pair<Object, Usage> > *ModAsSideEffect;
+ /// Expressions to check later. We defer checking these to reduce
+ /// stack usage.
+ llvm::SmallVectorImpl<Expr*> &WorkList;
+
+ /// RAII object wrapping the visitation of a sequenced subexpression of an
+ /// expression. At the end of this process, the side-effects of the evaluation
+ /// become sequenced with respect to the value computation of the result, so
+ /// we downgrade any UK_ModAsSideEffect within the evaluation to
+ /// UK_ModAsValue.
+ struct SequencedSubexpression {
+ SequencedSubexpression(SequenceChecker &Self)
+ : Self(Self), OldModAsSideEffect(Self.ModAsSideEffect) {
+ Self.ModAsSideEffect = &ModAsSideEffect;
+ }
+ ~SequencedSubexpression() {
+ for (unsigned I = 0, E = ModAsSideEffect.size(); I != E; ++I) {
+ UsageInfo &U = Self.UsageMap[ModAsSideEffect[I].first];
+ U.Uses[UK_ModAsSideEffect] = ModAsSideEffect[I].second;
+ Self.addUsage(U, ModAsSideEffect[I].first,
+ ModAsSideEffect[I].second.Use, UK_ModAsValue);
+ }
+ Self.ModAsSideEffect = OldModAsSideEffect;
+ }
+
+ SequenceChecker &Self;
+ llvm::SmallVector<std::pair<Object, Usage>, 4> ModAsSideEffect;
+ llvm::SmallVectorImpl<std::pair<Object, Usage> > *OldModAsSideEffect;
+ };
+
+ /// \brief Find the object which is produced by the specified expression,
+ /// if any.
+ Object getObject(Expr *E, bool Mod) const {
+ E = E->IgnoreParenCasts();
+ if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
+ if (Mod && (UO->getOpcode() == UO_PreInc || UO->getOpcode() == UO_PreDec))
+ return getObject(UO->getSubExpr(), Mod);
+ } else if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+ if (BO->getOpcode() == BO_Comma)
+ return getObject(BO->getRHS(), Mod);
+ if (Mod && BO->isAssignmentOp())
+ return getObject(BO->getLHS(), Mod);
+ } else if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+ // FIXME: Check for more interesting cases, like "x.n = ++x.n".
+ if (isa<CXXThisExpr>(ME->getBase()->IgnoreParenCasts()))
+ return ME->getMemberDecl();
+ } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
+ // FIXME: If this is a reference, map through to its value.
+ return DRE->getDecl();
+ return 0;
+ }
+
+ /// \brief Note that an object was modified or used by an expression.
+ void addUsage(UsageInfo &UI, Object O, Expr *Ref, UsageKind UK) {
+ Usage &U = UI.Uses[UK];
+ if (!U.Use || !Tree.isUnsequenced(Region, U.Seq)) {
+ if (UK == UK_ModAsSideEffect && ModAsSideEffect)
+ ModAsSideEffect->push_back(std::make_pair(O, U));
+ U.Use = Ref;
+ U.Seq = Region;
+ }
+ }
+ /// \brief Check whether a modification or use conflicts with a prior usage.
+ void checkUsage(Object O, UsageInfo &UI, Expr *Ref, UsageKind OtherKind,
+ bool IsModMod) {
+ if (UI.Diagnosed)
+ return;
+
+ const Usage &U = UI.Uses[OtherKind];
+ if (!U.Use || !Tree.isUnsequenced(Region, U.Seq))
+ return;
+
+ Expr *Mod = U.Use;
+ Expr *ModOrUse = Ref;
+ if (OtherKind == UK_Use)
+ std::swap(Mod, ModOrUse);
+
+ SemaRef.Diag(Mod->getExprLoc(),
+ IsModMod ? diag::warn_unsequenced_mod_mod
+ : diag::warn_unsequenced_mod_use)
+ << O << SourceRange(ModOrUse->getExprLoc());
+ UI.Diagnosed = true;
+ }
+
+ void notePreUse(Object O, Expr *Use) {
+ UsageInfo &U = UsageMap[O];
+ // Uses conflict with other modifications.
+ checkUsage(O, U, Use, UK_ModAsValue, false);
+ }
+ void notePostUse(Object O, Expr *Use) {
+ UsageInfo &U = UsageMap[O];
+ checkUsage(O, U, Use, UK_ModAsSideEffect, false);
+ addUsage(U, O, Use, UK_Use);
+ }
+
+ void notePreMod(Object O, Expr *Mod) {
+ UsageInfo &U = UsageMap[O];
+ // Modifications conflict with other modifications and with uses.
+ checkUsage(O, U, Mod, UK_ModAsValue, true);
+ checkUsage(O, U, Mod, UK_Use, false);
+ }
+ void notePostMod(Object O, Expr *Use, UsageKind UK) {
+ UsageInfo &U = UsageMap[O];
+ checkUsage(O, U, Use, UK_ModAsSideEffect, true);
+ addUsage(U, O, Use, UK);
+ }
+
+public:
+ SequenceChecker(Sema &S, Expr *E,
+ llvm::SmallVectorImpl<Expr*> &WorkList)
+ : EvaluatedExprVisitor<SequenceChecker>(S.Context), SemaRef(S),
+ Region(Tree.root()), ModAsSideEffect(0), WorkList(WorkList) {
+ Visit(E);
+ }
+
+ void VisitStmt(Stmt *S) {
+ // Skip all statements which aren't expressions for now.
+ }
+
+ void VisitExpr(Expr *E) {
+ // By default, just recurse to evaluated subexpressions.
+ EvaluatedExprVisitor<SequenceChecker>::VisitStmt(E);
+ }
+
+ void VisitCastExpr(CastExpr *E) {
+ Object O = Object();
+ if (E->getCastKind() == CK_LValueToRValue)
+ O = getObject(E->getSubExpr(), false);
+
+ if (O)
+ notePreUse(O, E);
+ VisitExpr(E);
+ if (O)
+ notePostUse(O, E);
+ }
+
+ void VisitBinComma(BinaryOperator *BO) {
+ // C++11 [expr.comma]p1:
+ // Every value computation and side effect associated with the left
+ // expression is sequenced before every value computation and side
+ // effect associated with the right expression.
+ SequenceTree::Seq LHS = Tree.allocate(Region);
+ SequenceTree::Seq RHS = Tree.allocate(Region);
+ SequenceTree::Seq OldRegion = Region;
+
+ {
+ SequencedSubexpression SeqLHS(*this);
+ Region = LHS;
+ Visit(BO->getLHS());
+ }
+
+ Region = RHS;
+ Visit(BO->getRHS());
+
+ Region = OldRegion;
+
+ // Forget that LHS and RHS are sequenced. They are both unsequenced
+ // with respect to other stuff.
+ Tree.merge(LHS);
+ Tree.merge(RHS);
+ }
+
+ void VisitBinAssign(BinaryOperator *BO) {
+ // The modification is sequenced after the value computation of the LHS
+ // and RHS, so check it before inspecting the operands and update the
+ // map afterwards.
+ Object O = getObject(BO->getLHS(), true);
+ if (!O)
+ return VisitExpr(BO);
+
+ notePreMod(O, BO);
+
+ // C++11 [expr.ass]p7:
+ // E1 op= E2 is equivalent to E1 = E1 op E2, except that E1 is evaluated
+ // only once.
+ //
+ // Therefore, for a compound assignment operator, O is considered used
+ // everywhere except within the evaluation of E1 itself.
+ if (isa<CompoundAssignOperator>(BO))
+ notePreUse(O, BO);
+
+ Visit(BO->getLHS());
+
+ if (isa<CompoundAssignOperator>(BO))
+ notePostUse(O, BO);
+
+ Visit(BO->getRHS());
+
+ notePostMod(O, BO, UK_ModAsValue);
+ }
+ void VisitCompoundAssignOperator(CompoundAssignOperator *CAO) {
+ VisitBinAssign(CAO);
+ }
+
+ void VisitUnaryPreInc(UnaryOperator *UO) { VisitUnaryPreIncDec(UO); }
+ void VisitUnaryPreDec(UnaryOperator *UO) { VisitUnaryPreIncDec(UO); }
+ void VisitUnaryPreIncDec(UnaryOperator *UO) {
+ Object O = getObject(UO->getSubExpr(), true);
+ if (!O)
+ return VisitExpr(UO);
+
+ notePreMod(O, UO);
+ Visit(UO->getSubExpr());
+ notePostMod(O, UO, UK_ModAsValue);
+ }
+
+ void VisitUnaryPostInc(UnaryOperator *UO) { VisitUnaryPostIncDec(UO); }
+ void VisitUnaryPostDec(UnaryOperator *UO) { VisitUnaryPostIncDec(UO); }
+ void VisitUnaryPostIncDec(UnaryOperator *UO) {
+ Object O = getObject(UO->getSubExpr(), true);
+ if (!O)
+ return VisitExpr(UO);
+
+ notePreMod(O, UO);
+ Visit(UO->getSubExpr());
+ notePostMod(O, UO, UK_ModAsSideEffect);
+ }
+
+ /// Don't visit the RHS of '&&' or '||' if it might not be evaluated.
+ void VisitBinLOr(BinaryOperator *BO) {
+ // The side-effects of the LHS of an '&&' are sequenced before the
+ // value computation of the RHS, and hence before the value computation
+ // of the '&&' itself, unless the LHS evaluates to zero. We treat them
+ // as if they were unconditionally sequenced.
+ {
+ SequencedSubexpression Sequenced(*this);
+ Visit(BO->getLHS());
+ }
+
+ bool Result;
+ if (!BO->getLHS()->isValueDependent() &&
+ BO->getLHS()->EvaluateAsBooleanCondition(Result, SemaRef.Context)) {
+ if (!Result)
+ Visit(BO->getRHS());
+ } else {
+ // Check for unsequenced operations in the RHS, treating it as an
+ // entirely separate evaluation.
+ //
+ // FIXME: If there are operations in the RHS which are unsequenced
+ // with respect to operations outside the RHS, and those operations
+ // are unconditionally evaluated, diagnose them.
+ WorkList.push_back(BO->getRHS());
+ }
+ }
+ void VisitBinLAnd(BinaryOperator *BO) {
+ {
+ SequencedSubexpression Sequenced(*this);
+ Visit(BO->getLHS());
+ }
+
+ bool Result;
+ if (!BO->getLHS()->isValueDependent() &&
+ BO->getLHS()->EvaluateAsBooleanCondition(Result, SemaRef.Context)) {
+ if (Result)
+ Visit(BO->getRHS());
+ } else {
+ WorkList.push_back(BO->getRHS());
+ }
+ }
+
+ // Only visit the condition, unless we can be sure which subexpression will
+ // be chosen.
+ void VisitAbstractConditionalOperator(AbstractConditionalOperator *CO) {
+ SequencedSubexpression Sequenced(*this);
+ Visit(CO->getCond());
+
+ bool Result;
+ if (!CO->getCond()->isValueDependent() &&
+ CO->getCond()->EvaluateAsBooleanCondition(Result, SemaRef.Context))
+ Visit(Result ? CO->getTrueExpr() : CO->getFalseExpr());
+ else {
+ WorkList.push_back(CO->getTrueExpr());
+ WorkList.push_back(CO->getFalseExpr());
+ }
+ }
+
+ void VisitCXXConstructExpr(CXXConstructExpr *CCE) {
+ if (!CCE->isListInitialization())
+ return VisitExpr(CCE);
+
+ // In C++11, list initializations are sequenced.
+ llvm::SmallVector<SequenceTree::Seq, 32> Elts;
+ SequenceTree::Seq Parent = Region;
+ for (CXXConstructExpr::arg_iterator I = CCE->arg_begin(),
+ E = CCE->arg_end();
+ I != E; ++I) {
+ Region = Tree.allocate(Parent);
+ Elts.push_back(Region);
+ Visit(*I);
+ }
+
+ // Forget that the initializers are sequenced.
+ Region = Parent;
+ for (unsigned I = 0; I < Elts.size(); ++I)
+ Tree.merge(Elts[I]);
+ }
+
+ void VisitInitListExpr(InitListExpr *ILE) {
+ if (!SemaRef.getLangOpts().CPlusPlus11)
+ return VisitExpr(ILE);
+
+ // In C++11, list initializations are sequenced.
+ llvm::SmallVector<SequenceTree::Seq, 32> Elts;
+ SequenceTree::Seq Parent = Region;
+ for (unsigned I = 0; I < ILE->getNumInits(); ++I) {
+ Expr *E = ILE->getInit(I);
+ if (!E) continue;
+ Region = Tree.allocate(Parent);
+ Elts.push_back(Region);
+ Visit(E);
+ }
+
+ // Forget that the initializers are sequenced.
+ Region = Parent;
+ for (unsigned I = 0; I < Elts.size(); ++I)
+ Tree.merge(Elts[I]);
+ }
+};
+}
+
+void Sema::CheckUnsequencedOperations(Expr *E) {
+ llvm::SmallVector<Expr*, 8> WorkList;
+ WorkList.push_back(E);
+ while (!WorkList.empty()) {
+ Expr *Item = WorkList.back();
+ WorkList.pop_back();
+ SequenceChecker(*this, Item, WorkList);
+ }
+}
+
+void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc,
+ bool IsConstexpr) {
+ CheckImplicitConversions(E, CheckLoc);
+ CheckUnsequencedOperations(E);
+ if (!IsConstexpr && !E->isValueDependent())
+ CheckForIntOverflow(E);
+}
+
void Sema::CheckBitFieldInitialization(SourceLocation InitLoc,
FieldDecl *BitField,
Expr *Init) {
@@ -5091,7 +5701,7 @@ bool Sema::CheckParmsForFunctionDef(ParmVarDecl **P, ParmVarDecl **PEnd,
QualType PType = Param->getOriginalType();
if (const ArrayType *AT = Context.getAsArrayType(PType)) {
if (AT->getSizeModifier() == ArrayType::Star) {
- // FIXME: This diagnosic should point the '[*]' if source-location
+ // FIXME: This diagnostic should point the '[*]' if source-location
// information is added for it.
Diag(Param->getLocation(), diag::err_array_star_in_function_definition);
}
@@ -5174,16 +5784,16 @@ static bool IsTailPaddedMemberArray(Sema &S, llvm::APInt Size,
while (TInfo) {
TypeLoc TL = TInfo->getTypeLoc();
// Look through typedefs.
- const TypedefTypeLoc *TTL = dyn_cast<TypedefTypeLoc>(&TL);
- if (TTL) {
- const TypedefNameDecl *TDL = TTL->getTypedefNameDecl();
+ if (TypedefTypeLoc TTL = TL.getAs<TypedefTypeLoc>()) {
+ const TypedefNameDecl *TDL = TTL.getTypedefNameDecl();
TInfo = TDL->getTypeSourceInfo();
continue;
}
- ConstantArrayTypeLoc CTL = cast<ConstantArrayTypeLoc>(TL);
- const Expr *SizeExpr = dyn_cast<IntegerLiteral>(CTL.getSizeExpr());
- if (!SizeExpr || SizeExpr->getExprLoc().isMacroID())
- return false;
+ if (ConstantArrayTypeLoc CTL = TL.getAs<ConstantArrayTypeLoc>()) {
+ const Expr *SizeExpr = dyn_cast<IntegerLiteral>(CTL.getSizeExpr());
+ if (!SizeExpr || SizeExpr->getExprLoc().isMacroID())
+ return false;
+ }
break;
}
@@ -5574,7 +6184,7 @@ static bool isSetterLikeSelector(Selector sel) {
return false;
if (str.empty()) return true;
- return !islower(str.front());
+ return !isLowercase(str.front());
}
/// Check a message send to see if it's likely to cause a retain cycle.
@@ -5625,21 +6235,59 @@ void Sema::checkRetainCycles(VarDecl *Var, Expr *Init) {
diagnoseRetainCycle(*this, Capturer, Owner);
}
-bool Sema::checkUnsafeAssigns(SourceLocation Loc,
- QualType LHS, Expr *RHS) {
- Qualifiers::ObjCLifetime LT = LHS.getObjCLifetime();
- if (LT != Qualifiers::OCL_Weak && LT != Qualifiers::OCL_ExplicitNone)
+static bool checkUnsafeAssignLiteral(Sema &S, SourceLocation Loc,
+ Expr *RHS, bool isProperty) {
+ // Check if RHS is an Objective-C object literal, which also can get
+ // immediately zapped in a weak reference. Note that we explicitly
+ // allow ObjCStringLiterals, since those are designed to never really die.
+ RHS = RHS->IgnoreParenImpCasts();
+
+ // This enum needs to match with the 'select' in
+ // warn_objc_arc_literal_assign (off-by-1).
+ Sema::ObjCLiteralKind Kind = S.CheckLiteralKind(RHS);
+ if (Kind == Sema::LK_String || Kind == Sema::LK_None)
return false;
- // strip off any implicit cast added to get to the one arc-specific
+
+ S.Diag(Loc, diag::warn_arc_literal_assign)
+ << (unsigned) Kind
+ << (isProperty ? 0 : 1)
+ << RHS->getSourceRange();
+
+ return true;
+}
+
+static bool checkUnsafeAssignObject(Sema &S, SourceLocation Loc,
+ Qualifiers::ObjCLifetime LT,
+ Expr *RHS, bool isProperty) {
+ // Strip off any implicit cast added to get to the one ARC-specific.
while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) {
if (cast->getCastKind() == CK_ARCConsumeObject) {
- Diag(Loc, diag::warn_arc_retained_assign)
- << (LT == Qualifiers::OCL_ExplicitNone) << 1
+ S.Diag(Loc, diag::warn_arc_retained_assign)
+ << (LT == Qualifiers::OCL_ExplicitNone)
+ << (isProperty ? 0 : 1)
<< RHS->getSourceRange();
return true;
}
RHS = cast->getSubExpr();
}
+
+ if (LT == Qualifiers::OCL_Weak &&
+ checkUnsafeAssignLiteral(S, Loc, RHS, isProperty))
+ return true;
+
+ return false;
+}
+
+bool Sema::checkUnsafeAssigns(SourceLocation Loc,
+ QualType LHS, Expr *RHS) {
+ Qualifiers::ObjCLifetime LT = LHS.getObjCLifetime();
+
+ if (LT != Qualifiers::OCL_Weak && LT != Qualifiers::OCL_ExplicitNone)
+ return false;
+
+ if (checkUnsafeAssignObject(*this, Loc, LT, RHS, false))
+ return true;
+
return false;
}
@@ -5702,14 +6350,8 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc,
}
}
else if (Attributes & ObjCPropertyDecl::OBJC_PR_weak) {
- while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) {
- if (cast->getCastKind() == CK_ARCConsumeObject) {
- Diag(Loc, diag::warn_arc_retained_assign)
- << 0 << 0<< RHS->getSourceRange();
- return;
- }
- RHS = cast->getSubExpr();
- }
+ if (checkUnsafeAssignObject(*this, Loc, Qualifiers::OCL_Weak, RHS, true))
+ return;
}
}
}
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index b1aead8..2db1e2a 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -11,18 +11,19 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/Overload.h"
-#include "clang/Sema/CodeCompleteConsumer.h"
-#include "clang/Sema/ExternalSemaSource.h"
-#include "clang/Sema/Scope.h"
-#include "clang/Sema/ScopeInfo.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
+#include "clang/Sema/ExternalSemaSource.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Overload.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/ScopeInfo.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -45,7 +46,7 @@ namespace {
/// name-lookup routines to specify which declarations should be included in
/// the result set (when it returns true) and which declarations should be
/// filtered out (returns false).
- typedef bool (ResultBuilder::*LookupFilter)(NamedDecl *) const;
+ typedef bool (ResultBuilder::*LookupFilter)(const NamedDecl *) const;
typedef CodeCompletionResult Result;
@@ -56,9 +57,9 @@ namespace {
/// \brief A record of all of the declarations we have found and placed
/// into the result set, used to ensure that no declaration ever gets into
/// the result set twice.
- llvm::SmallPtrSet<Decl*, 16> AllDeclsFound;
+ llvm::SmallPtrSet<const Decl*, 16> AllDeclsFound;
- typedef std::pair<NamedDecl *, unsigned> DeclIndexPair;
+ typedef std::pair<const NamedDecl *, unsigned> DeclIndexPair;
/// \brief An entry in the shadow map, which is optimized to store
/// a single (declaration, index) mapping (the common case) but
@@ -68,7 +69,7 @@ namespace {
/// \brief Contains either the solitary NamedDecl * or a vector
/// of (declaration, index) pairs.
- llvm::PointerUnion<NamedDecl *, DeclIndexPairVector*> DeclOrVector;
+ llvm::PointerUnion<const NamedDecl *, DeclIndexPairVector*> DeclOrVector;
/// \brief When the entry contains a single declaration, this is
/// the index associated with that entry.
@@ -77,7 +78,7 @@ namespace {
public:
ShadowMapEntry() : DeclOrVector(), SingleDeclIndex(0) { }
- void Add(NamedDecl *ND, unsigned Index) {
+ void Add(const NamedDecl *ND, unsigned Index) {
if (DeclOrVector.isNull()) {
// 0 - > 1 elements: just set the single element information.
DeclOrVector = ND;
@@ -85,7 +86,8 @@ namespace {
return;
}
- if (NamedDecl *PrevND = DeclOrVector.dyn_cast<NamedDecl *>()) {
+ if (const NamedDecl *PrevND =
+ DeclOrVector.dyn_cast<const NamedDecl *>()) {
// 1 -> 2 elements: create the vector of results and push in the
// existing declaration.
DeclIndexPairVector *Vec = new DeclIndexPairVector;
@@ -161,7 +163,7 @@ namespace {
/// \brief If we are in an instance method definition, the \@implementation
/// object.
ObjCImplementationDecl *ObjCImplementation;
-
+
void AdjustResultPriorityForDecl(Result &R);
void MaybeAddConstructorResults(Result R);
@@ -195,7 +197,10 @@ namespace {
break;
}
}
-
+
+ /// \brief Determine the priority for a reference to the given declaration.
+ unsigned getBasePriority(const NamedDecl *D);
+
/// \brief Whether we should include code patterns in the completion
/// results.
bool includeCodePatterns() const {
@@ -265,7 +270,8 @@ namespace {
///
/// \param AsNestedNameSpecifier will be set true if this declaration is
/// only interesting when it is a nested-name-specifier.
- bool isInterestingDecl(NamedDecl *ND, bool &AsNestedNameSpecifier) const;
+ bool isInterestingDecl(const NamedDecl *ND,
+ bool &AsNestedNameSpecifier) const;
/// \brief Check whether the result is hidden by the Hiding declaration.
///
@@ -274,7 +280,7 @@ namespace {
/// modified to describe how the result can be found (e.g., via extra
/// qualification).
bool CheckHiddenResult(Result &R, DeclContext *CurContext,
- NamedDecl *Hiding);
+ const NamedDecl *Hiding);
/// \brief Add a new result to this result set (if it isn't already in one
/// of the shadow maps), or replace an existing result (for, e.g., a
@@ -309,7 +315,7 @@ namespace {
void ExitScope();
/// \brief Ignore this declaration, if it is seen again.
- void Ignore(Decl *D) { AllDeclsFound.insert(D->getCanonicalDecl()); }
+ void Ignore(const Decl *D) { AllDeclsFound.insert(D->getCanonicalDecl()); }
/// \name Name lookup predicates
///
@@ -317,29 +323,29 @@ namespace {
/// results of name lookup. All of the predicates have the same type, so that
///
//@{
- bool IsOrdinaryName(NamedDecl *ND) const;
- bool IsOrdinaryNonTypeName(NamedDecl *ND) const;
- bool IsIntegralConstantValue(NamedDecl *ND) const;
- bool IsOrdinaryNonValueName(NamedDecl *ND) const;
- bool IsNestedNameSpecifier(NamedDecl *ND) const;
- bool IsEnum(NamedDecl *ND) const;
- bool IsClassOrStruct(NamedDecl *ND) const;
- bool IsUnion(NamedDecl *ND) const;
- bool IsNamespace(NamedDecl *ND) const;
- bool IsNamespaceOrAlias(NamedDecl *ND) const;
- bool IsType(NamedDecl *ND) const;
- bool IsMember(NamedDecl *ND) const;
- bool IsObjCIvar(NamedDecl *ND) const;
- bool IsObjCMessageReceiver(NamedDecl *ND) const;
- bool IsObjCMessageReceiverOrLambdaCapture(NamedDecl *ND) const;
- bool IsObjCCollection(NamedDecl *ND) const;
- bool IsImpossibleToSatisfy(NamedDecl *ND) const;
+ bool IsOrdinaryName(const NamedDecl *ND) const;
+ bool IsOrdinaryNonTypeName(const NamedDecl *ND) const;
+ bool IsIntegralConstantValue(const NamedDecl *ND) const;
+ bool IsOrdinaryNonValueName(const NamedDecl *ND) const;
+ bool IsNestedNameSpecifier(const NamedDecl *ND) const;
+ bool IsEnum(const NamedDecl *ND) const;
+ bool IsClassOrStruct(const NamedDecl *ND) const;
+ bool IsUnion(const NamedDecl *ND) const;
+ bool IsNamespace(const NamedDecl *ND) const;
+ bool IsNamespaceOrAlias(const NamedDecl *ND) const;
+ bool IsType(const NamedDecl *ND) const;
+ bool IsMember(const NamedDecl *ND) const;
+ bool IsObjCIvar(const NamedDecl *ND) const;
+ bool IsObjCMessageReceiver(const NamedDecl *ND) const;
+ bool IsObjCMessageReceiverOrLambdaCapture(const NamedDecl *ND) const;
+ bool IsObjCCollection(const NamedDecl *ND) const;
+ bool IsImpossibleToSatisfy(const NamedDecl *ND) const;
//@}
};
}
class ResultBuilder::ShadowMapEntry::iterator {
- llvm::PointerUnion<NamedDecl*, const DeclIndexPair*> DeclOrIterator;
+ llvm::PointerUnion<const NamedDecl *, const DeclIndexPair *> DeclOrIterator;
unsigned SingleDeclIndex;
public:
@@ -361,14 +367,14 @@ public:
iterator() : DeclOrIterator((NamedDecl *)0), SingleDeclIndex(0) { }
- iterator(NamedDecl *SingleDecl, unsigned Index)
+ iterator(const NamedDecl *SingleDecl, unsigned Index)
: DeclOrIterator(SingleDecl), SingleDeclIndex(Index) { }
iterator(const DeclIndexPair *Iterator)
: DeclOrIterator(Iterator), SingleDeclIndex(0) { }
iterator &operator++() {
- if (DeclOrIterator.is<NamedDecl *>()) {
+ if (DeclOrIterator.is<const NamedDecl *>()) {
DeclOrIterator = (NamedDecl *)0;
SingleDeclIndex = 0;
return *this;
@@ -387,7 +393,7 @@ public:
}*/
reference operator*() const {
- if (NamedDecl *ND = DeclOrIterator.dyn_cast<NamedDecl *>())
+ if (const NamedDecl *ND = DeclOrIterator.dyn_cast<const NamedDecl *>())
return reference(ND, SingleDeclIndex);
return *DeclOrIterator.get<const DeclIndexPair*>();
@@ -413,7 +419,7 @@ ResultBuilder::ShadowMapEntry::begin() const {
if (DeclOrVector.isNull())
return iterator();
- if (NamedDecl *ND = DeclOrVector.dyn_cast<NamedDecl *>())
+ if (const NamedDecl *ND = DeclOrVector.dyn_cast<const NamedDecl *>())
return iterator(ND, SingleDeclIndex);
return iterator(DeclOrVector.get<DeclIndexPairVector *>()->begin());
@@ -421,7 +427,7 @@ ResultBuilder::ShadowMapEntry::begin() const {
ResultBuilder::ShadowMapEntry::iterator
ResultBuilder::ShadowMapEntry::end() const {
- if (DeclOrVector.is<NamedDecl *>() || DeclOrVector.isNull())
+ if (DeclOrVector.is<const NamedDecl *>() || DeclOrVector.isNull())
return iterator();
return iterator(DeclOrVector.get<DeclIndexPairVector *>()->end());
@@ -442,11 +448,11 @@ ResultBuilder::ShadowMapEntry::end() const {
/// NULL if no qualification is needed.
static NestedNameSpecifier *
getRequiredQualification(ASTContext &Context,
- DeclContext *CurContext,
- DeclContext *TargetContext) {
- SmallVector<DeclContext *, 4> TargetParents;
+ const DeclContext *CurContext,
+ const DeclContext *TargetContext) {
+ SmallVector<const DeclContext *, 4> TargetParents;
- for (DeclContext *CommonAncestor = TargetContext;
+ for (const DeclContext *CommonAncestor = TargetContext;
CommonAncestor && !CommonAncestor->Encloses(CurContext);
CommonAncestor = CommonAncestor->getLookupParent()) {
if (CommonAncestor->isTransparentContext() ||
@@ -458,16 +464,16 @@ getRequiredQualification(ASTContext &Context,
NestedNameSpecifier *Result = 0;
while (!TargetParents.empty()) {
- DeclContext *Parent = TargetParents.back();
+ const DeclContext *Parent = TargetParents.back();
TargetParents.pop_back();
- if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(Parent)) {
+ if (const NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(Parent)) {
if (!Namespace->getIdentifier())
continue;
Result = NestedNameSpecifier::Create(Context, Result, Namespace);
}
- else if (TagDecl *TD = dyn_cast<TagDecl>(Parent))
+ else if (const TagDecl *TD = dyn_cast<TagDecl>(Parent))
Result = NestedNameSpecifier::Create(Context, Result,
false,
Context.getTypeDeclType(TD).getTypePtr());
@@ -475,7 +481,7 @@ getRequiredQualification(ASTContext &Context,
return Result;
}
-bool ResultBuilder::isInterestingDecl(NamedDecl *ND,
+bool ResultBuilder::isInterestingDecl(const NamedDecl *ND,
bool &AsNestedNameSpecifier) const {
AsNestedNameSpecifier = false;
@@ -547,14 +553,15 @@ bool ResultBuilder::isInterestingDecl(NamedDecl *ND,
}
bool ResultBuilder::CheckHiddenResult(Result &R, DeclContext *CurContext,
- NamedDecl *Hiding) {
+ const NamedDecl *Hiding) {
// In C, there is no way to refer to a hidden name.
// FIXME: This isn't true; we can find a tag name hidden by an ordinary
// name if we introduce the tag type.
if (!SemaRef.getLangOpts().CPlusPlus)
return true;
- DeclContext *HiddenCtx = R.Declaration->getDeclContext()->getRedeclContext();
+ const DeclContext *HiddenCtx =
+ R.Declaration->getDeclContext()->getRedeclContext();
// There is no way to qualify a name declared in a function or method.
if (HiddenCtx->isFunctionOrMethod())
@@ -645,26 +652,27 @@ SimplifiedTypeClass clang::getSimplifiedTypeClass(CanQualType T) {
/// \brief Get the type that a given expression will have if this declaration
/// is used as an expression in its "typical" code-completion form.
-QualType clang::getDeclUsageType(ASTContext &C, NamedDecl *ND) {
+QualType clang::getDeclUsageType(ASTContext &C, const NamedDecl *ND) {
ND = cast<NamedDecl>(ND->getUnderlyingDecl());
- if (TypeDecl *Type = dyn_cast<TypeDecl>(ND))
+ if (const TypeDecl *Type = dyn_cast<TypeDecl>(ND))
return C.getTypeDeclType(Type);
- if (ObjCInterfaceDecl *Iface = dyn_cast<ObjCInterfaceDecl>(ND))
+ if (const ObjCInterfaceDecl *Iface = dyn_cast<ObjCInterfaceDecl>(ND))
return C.getObjCInterfaceType(Iface);
QualType T;
- if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND))
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(ND))
T = Function->getCallResultType();
- else if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND))
+ else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND))
T = Method->getSendResultType();
- else if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND))
+ else if (const FunctionTemplateDecl *FunTmpl =
+ dyn_cast<FunctionTemplateDecl>(ND))
T = FunTmpl->getTemplatedDecl()->getCallResultType();
- else if (EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(ND))
+ else if (const EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(ND))
T = C.getTypeDeclType(cast<EnumDecl>(Enumerator->getDeclContext()));
- else if (ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND))
+ else if (const ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND))
T = Property->getType();
- else if (ValueDecl *Value = dyn_cast<ValueDecl>(ND))
+ else if (const ValueDecl *Value = dyn_cast<ValueDecl>(ND))
T = Value->getType();
else
return QualType();
@@ -703,11 +711,48 @@ QualType clang::getDeclUsageType(ASTContext &C, NamedDecl *ND) {
return T;
}
+unsigned ResultBuilder::getBasePriority(const NamedDecl *ND) {
+ if (!ND)
+ return CCP_Unlikely;
+
+ // Context-based decisions.
+ const DeclContext *DC = ND->getDeclContext()->getRedeclContext();
+ if (DC->isFunctionOrMethod() || isa<BlockDecl>(DC)) {
+ // _cmd is relatively rare
+ if (const ImplicitParamDecl *ImplicitParam =
+ dyn_cast<ImplicitParamDecl>(ND))
+ if (ImplicitParam->getIdentifier() &&
+ ImplicitParam->getIdentifier()->isStr("_cmd"))
+ return CCP_ObjC_cmd;
+
+ return CCP_LocalDeclaration;
+ }
+ if (DC->isRecord() || isa<ObjCContainerDecl>(DC))
+ return CCP_MemberDeclaration;
+
+ // Content-based decisions.
+ if (isa<EnumConstantDecl>(ND))
+ return CCP_Constant;
+
+ // Use CCP_Type for type declarations unless we're in a statement, Objective-C
+ // message receiver, or parenthesized expression context. There, it's as
+ // likely that the user will want to write a type as other declarations.
+ if ((isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND)) &&
+ !(CompletionContext.getKind() == CodeCompletionContext::CCC_Statement ||
+ CompletionContext.getKind()
+ == CodeCompletionContext::CCC_ObjCMessageReceiver ||
+ CompletionContext.getKind()
+ == CodeCompletionContext::CCC_ParenthesizedExpression))
+ return CCP_Type;
+
+ return CCP_Declaration;
+}
+
void ResultBuilder::AdjustResultPriorityForDecl(Result &R) {
// If this is an Objective-C method declaration whose selector matches our
// preferred selector, give it a priority boost.
if (!PreferredSelector.isNull())
- if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(R.Declaration))
+ if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(R.Declaration))
if (PreferredSelector == Method->getSelector())
R.Priority += CCD_SelectorMatch;
@@ -735,9 +780,9 @@ void ResultBuilder::MaybeAddConstructorResults(Result R) {
return;
ASTContext &Context = SemaRef.Context;
- NamedDecl *D = R.Declaration;
- CXXRecordDecl *Record = 0;
- if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(D))
+ const NamedDecl *D = R.Declaration;
+ const CXXRecordDecl *Record = 0;
+ if (const ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(D))
Record = ClassTemplate->getTemplatedDecl();
else if ((Record = dyn_cast<CXXRecordDecl>(D))) {
// Skip specializations and partial specializations.
@@ -757,9 +802,11 @@ void ResultBuilder::MaybeAddConstructorResults(Result R) {
DeclarationName ConstructorName
= Context.DeclarationNames.getCXXConstructorName(
Context.getCanonicalType(RecordTy));
- for (DeclContext::lookup_result Ctors = Record->lookup(ConstructorName);
- Ctors.first != Ctors.second; ++Ctors.first) {
- R.Declaration = *Ctors.first;
+ DeclContext::lookup_const_result Ctors = Record->lookup(ConstructorName);
+ for (DeclContext::lookup_const_iterator I = Ctors.begin(),
+ E = Ctors.end();
+ I != E; ++I) {
+ R.Declaration = *I;
R.CursorKind = getCursorKindForDecl(R.Declaration);
Results.push_back(R);
}
@@ -775,12 +822,16 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
}
// Look through using declarations.
- if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(R.Declaration)) {
- MaybeAddResult(Result(Using->getTargetDecl(), R.Qualifier), CurContext);
+ if (const UsingShadowDecl *Using =
+ dyn_cast<UsingShadowDecl>(R.Declaration)) {
+ MaybeAddResult(Result(Using->getTargetDecl(),
+ getBasePriority(Using->getTargetDecl()),
+ R.Qualifier),
+ CurContext);
return;
}
- Decl *CanonDecl = R.Declaration->getCanonicalDecl();
+ const Decl *CanonDecl = R.Declaration->getCanonicalDecl();
unsigned IDNS = CanonDecl->getIdentifierNamespace();
bool AsNestedNameSpecifier = false;
@@ -800,7 +851,7 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
}
for (; I != IEnd; ++I) {
- NamedDecl *ND = I->first;
+ const NamedDecl *ND = I->first;
unsigned Index = I->second;
if (ND->getCanonicalDecl() == CanonDecl) {
// This is a redeclaration. Always pick the newer declaration.
@@ -859,10 +910,10 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) {
// If this result is supposed to have an informative qualifier, add one.
if (R.QualifierIsInformative && !R.Qualifier &&
!R.StartsNestedNameSpecifier) {
- DeclContext *Ctx = R.Declaration->getDeclContext();
- if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(Ctx))
+ const DeclContext *Ctx = R.Declaration->getDeclContext();
+ if (const NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(Ctx))
R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, Namespace);
- else if (TagDecl *Tag = dyn_cast<TagDecl>(Ctx))
+ else if (const TagDecl *Tag = dyn_cast<TagDecl>(Ctx))
R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, false,
SemaRef.Context.getTypeDeclType(Tag).getTypePtr());
else
@@ -887,8 +938,11 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
}
// Look through using declarations.
- if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(R.Declaration)) {
- AddResult(Result(Using->getTargetDecl(), R.Qualifier), CurContext, Hiding);
+ if (const UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(R.Declaration)) {
+ AddResult(Result(Using->getTargetDecl(),
+ getBasePriority(Using->getTargetDecl()),
+ R.Qualifier),
+ CurContext, Hiding);
return;
}
@@ -921,10 +975,10 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
// If this result is supposed to have an informative qualifier, add one.
if (R.QualifierIsInformative && !R.Qualifier &&
!R.StartsNestedNameSpecifier) {
- DeclContext *Ctx = R.Declaration->getDeclContext();
- if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(Ctx))
+ const DeclContext *Ctx = R.Declaration->getDeclContext();
+ if (const NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(Ctx))
R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, Namespace);
- else if (TagDecl *Tag = dyn_cast<TagDecl>(Ctx))
+ else if (const TagDecl *Tag = dyn_cast<TagDecl>(Ctx))
R.Qualifier = NestedNameSpecifier::Create(SemaRef.Context, 0, false,
SemaRef.Context.getTypeDeclType(Tag).getTypePtr());
else
@@ -938,7 +992,7 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext,
AdjustResultPriorityForDecl(R);
if (HasObjectTypeQualifiers)
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(R.Declaration))
+ if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(R.Declaration))
if (Method->isInstance()) {
Qualifiers MethodQuals
= Qualifiers::fromCVRMask(Method->getTypeQualifiers());
@@ -982,7 +1036,7 @@ void ResultBuilder::ExitScope() {
/// \brief Determines whether this given declaration will be found by
/// ordinary name lookup.
-bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const {
+bool ResultBuilder::IsOrdinaryName(const NamedDecl *ND) const {
ND = cast<NamedDecl>(ND->getUnderlyingDecl());
unsigned IDNS = Decl::IDNS_Ordinary;
@@ -998,7 +1052,7 @@ bool ResultBuilder::IsOrdinaryName(NamedDecl *ND) const {
/// \brief Determines whether this given declaration will be found by
/// ordinary name lookup but is not a type name.
-bool ResultBuilder::IsOrdinaryNonTypeName(NamedDecl *ND) const {
+bool ResultBuilder::IsOrdinaryNonTypeName(const NamedDecl *ND) const {
ND = cast<NamedDecl>(ND->getUnderlyingDecl());
if (isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND))
return false;
@@ -1014,11 +1068,11 @@ bool ResultBuilder::IsOrdinaryNonTypeName(NamedDecl *ND) const {
return ND->getIdentifierNamespace() & IDNS;
}
-bool ResultBuilder::IsIntegralConstantValue(NamedDecl *ND) const {
+bool ResultBuilder::IsIntegralConstantValue(const NamedDecl *ND) const {
if (!IsOrdinaryNonTypeName(ND))
return 0;
- if (ValueDecl *VD = dyn_cast<ValueDecl>(ND->getUnderlyingDecl()))
+ if (const ValueDecl *VD = dyn_cast<ValueDecl>(ND->getUnderlyingDecl()))
if (VD->getType()->isIntegralOrEnumerationType())
return true;
@@ -1027,7 +1081,7 @@ bool ResultBuilder::IsIntegralConstantValue(NamedDecl *ND) const {
/// \brief Determines whether this given declaration will be found by
/// ordinary name lookup.
-bool ResultBuilder::IsOrdinaryNonValueName(NamedDecl *ND) const {
+bool ResultBuilder::IsOrdinaryNonValueName(const NamedDecl *ND) const {
ND = cast<NamedDecl>(ND->getUnderlyingDecl());
unsigned IDNS = Decl::IDNS_Ordinary;
@@ -1041,27 +1095,27 @@ bool ResultBuilder::IsOrdinaryNonValueName(NamedDecl *ND) const {
/// \brief Determines whether the given declaration is suitable as the
/// start of a C++ nested-name-specifier, e.g., a class or namespace.
-bool ResultBuilder::IsNestedNameSpecifier(NamedDecl *ND) const {
+bool ResultBuilder::IsNestedNameSpecifier(const NamedDecl *ND) const {
// Allow us to find class templates, too.
- if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))
+ if (const ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))
ND = ClassTemplate->getTemplatedDecl();
return SemaRef.isAcceptableNestedNameSpecifier(ND);
}
/// \brief Determines whether the given declaration is an enumeration.
-bool ResultBuilder::IsEnum(NamedDecl *ND) const {
+bool ResultBuilder::IsEnum(const NamedDecl *ND) const {
return isa<EnumDecl>(ND);
}
/// \brief Determines whether the given declaration is a class or struct.
-bool ResultBuilder::IsClassOrStruct(NamedDecl *ND) const {
+bool ResultBuilder::IsClassOrStruct(const NamedDecl *ND) const {
// Allow us to find class templates, too.
- if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))
+ if (const ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))
ND = ClassTemplate->getTemplatedDecl();
// For purposes of this check, interfaces match too.
- if (RecordDecl *RD = dyn_cast<RecordDecl>(ND))
+ if (const RecordDecl *RD = dyn_cast<RecordDecl>(ND))
return RD->getTagKind() == TTK_Class ||
RD->getTagKind() == TTK_Struct ||
RD->getTagKind() == TTK_Interface;
@@ -1070,31 +1124,31 @@ bool ResultBuilder::IsClassOrStruct(NamedDecl *ND) const {
}
/// \brief Determines whether the given declaration is a union.
-bool ResultBuilder::IsUnion(NamedDecl *ND) const {
+bool ResultBuilder::IsUnion(const NamedDecl *ND) const {
// Allow us to find class templates, too.
- if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))
+ if (const ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))
ND = ClassTemplate->getTemplatedDecl();
- if (RecordDecl *RD = dyn_cast<RecordDecl>(ND))
+ if (const RecordDecl *RD = dyn_cast<RecordDecl>(ND))
return RD->getTagKind() == TTK_Union;
return false;
}
/// \brief Determines whether the given declaration is a namespace.
-bool ResultBuilder::IsNamespace(NamedDecl *ND) const {
+bool ResultBuilder::IsNamespace(const NamedDecl *ND) const {
return isa<NamespaceDecl>(ND);
}
/// \brief Determines whether the given declaration is a namespace or
/// namespace alias.
-bool ResultBuilder::IsNamespaceOrAlias(NamedDecl *ND) const {
+bool ResultBuilder::IsNamespaceOrAlias(const NamedDecl *ND) const {
return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND);
}
/// \brief Determines whether the given declaration is a type.
-bool ResultBuilder::IsType(NamedDecl *ND) const {
- if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(ND))
+bool ResultBuilder::IsType(const NamedDecl *ND) const {
+ if (const UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(ND))
ND = Using->getTargetDecl();
return isa<TypeDecl>(ND) || isa<ObjCInterfaceDecl>(ND);
@@ -1103,8 +1157,8 @@ bool ResultBuilder::IsType(NamedDecl *ND) const {
/// \brief Determines which members of a class should be visible via
/// "." or "->". Only value declarations, nested name specifiers, and
/// using declarations thereof should show up.
-bool ResultBuilder::IsMember(NamedDecl *ND) const {
- if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(ND))
+bool ResultBuilder::IsMember(const NamedDecl *ND) const {
+ if (const UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(ND))
ND = Using->getTargetDecl();
return isa<ValueDecl>(ND) || isa<FunctionTemplateDecl>(ND) ||
@@ -1144,7 +1198,7 @@ static bool isObjCReceiverType(ASTContext &C, QualType T) {
return T->isDependentType() || T->isRecordType();
}
-bool ResultBuilder::IsObjCMessageReceiver(NamedDecl *ND) const {
+bool ResultBuilder::IsObjCMessageReceiver(const NamedDecl *ND) const {
QualType T = getDeclUsageType(SemaRef.Context, ND);
if (T.isNull())
return false;
@@ -1153,18 +1207,18 @@ bool ResultBuilder::IsObjCMessageReceiver(NamedDecl *ND) const {
return isObjCReceiverType(SemaRef.Context, T);
}
-bool ResultBuilder::IsObjCMessageReceiverOrLambdaCapture(NamedDecl *ND) const {
+bool ResultBuilder::IsObjCMessageReceiverOrLambdaCapture(const NamedDecl *ND) const {
if (IsObjCMessageReceiver(ND))
return true;
- VarDecl *Var = dyn_cast<VarDecl>(ND);
+ const VarDecl *Var = dyn_cast<VarDecl>(ND);
if (!Var)
return false;
return Var->hasLocalStorage() && !Var->hasAttr<BlocksAttr>();
}
-bool ResultBuilder::IsObjCCollection(NamedDecl *ND) const {
+bool ResultBuilder::IsObjCCollection(const NamedDecl *ND) const {
if ((SemaRef.getLangOpts().CPlusPlus && !IsOrdinaryName(ND)) ||
(!SemaRef.getLangOpts().CPlusPlus && !IsOrdinaryNonTypeName(ND)))
return false;
@@ -1179,13 +1233,13 @@ bool ResultBuilder::IsObjCCollection(NamedDecl *ND) const {
(SemaRef.getLangOpts().CPlusPlus && T->isRecordType());
}
-bool ResultBuilder::IsImpossibleToSatisfy(NamedDecl *ND) const {
+bool ResultBuilder::IsImpossibleToSatisfy(const NamedDecl *ND) const {
return false;
}
/// \brief Determines whether the given declaration is an Objective-C
/// instance variable.
-bool ResultBuilder::IsObjCIvar(NamedDecl *ND) const {
+bool ResultBuilder::IsObjCIvar(const NamedDecl *ND) const {
return isa<ObjCIvarDecl>(ND);
}
@@ -1206,7 +1260,8 @@ namespace {
if (Ctx)
Accessible = Results.getSema().IsSimplyAccessible(ND, Ctx);
- ResultBuilder::Result Result(ND, 0, false, Accessible);
+ ResultBuilder::Result Result(ND, Results.getBasePriority(ND), 0, false,
+ Accessible);
Results.AddResult(Result, CurContext, Hiding, InBaseClass);
}
};
@@ -1256,7 +1311,7 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts,
Builder.AddPlaceholderChunk("name");
Results.AddResult(Result(Builder.TakeString()));
- if (LangOpts.CPlusPlus0x) {
+ if (LangOpts.CPlusPlus11) {
Results.AddResult(Result("auto", CCP_Type));
Results.AddResult(Result("char16_t", CCP_Type));
Results.AddResult(Result("char32_t", CCP_Type));
@@ -1421,7 +1476,7 @@ static const char *GetCompletionTypeString(QualType T,
// Anonymous tag types are constant strings.
if (const TagType *TagT = dyn_cast<TagType>(T))
if (TagDecl *Tag = TagT->getDecl())
- if (!Tag->getIdentifier() && !Tag->getTypedefNameForAnonDecl()) {
+ if (!Tag->hasNameForLinkage()) {
switch (Tag->getTagKind()) {
case TTK_Struct: return "struct <anonymous>";
case TTK_Interface: return "__interface <anonymous>";
@@ -1906,7 +1961,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
// FIXME: Rethrow?
- if (SemaRef.getLangOpts().CPlusPlus0x) {
+ if (SemaRef.getLangOpts().CPlusPlus11) {
// nullptr
Builder.AddResultTypeChunk("std::nullptr_t");
Builder.AddTypedTextChunk("nullptr");
@@ -1997,7 +2052,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
/// type chunk.
static void AddResultTypeChunk(ASTContext &Context,
const PrintingPolicy &Policy,
- NamedDecl *ND,
+ const NamedDecl *ND,
CodeCompletionBuilder &Result) {
if (!ND)
return;
@@ -2009,19 +2064,20 @@ static void AddResultTypeChunk(ASTContext &Context,
// Determine the type of the declaration (if it has a type).
QualType T;
- if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND))
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(ND))
T = Function->getResultType();
- else if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND))
+ else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND))
T = Method->getResultType();
- else if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND))
+ else if (const FunctionTemplateDecl *FunTmpl =
+ dyn_cast<FunctionTemplateDecl>(ND))
T = FunTmpl->getTemplatedDecl()->getResultType();
- else if (EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(ND))
+ else if (const EnumConstantDecl *Enumerator = dyn_cast<EnumConstantDecl>(ND))
T = Context.getTypeDeclType(cast<TypeDecl>(Enumerator->getDeclContext()));
else if (isa<UnresolvedUsingValueDecl>(ND)) {
/* Do nothing: ignore unresolved using declarations*/
- } else if (ValueDecl *Value = dyn_cast<ValueDecl>(ND)) {
+ } else if (const ValueDecl *Value = dyn_cast<ValueDecl>(ND)) {
T = Value->getType();
- } else if (ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND))
+ } else if (const ObjCPropertyDecl *Property = dyn_cast<ObjCPropertyDecl>(ND))
T = Property->getType();
if (T.isNull() || Context.hasSameType(T, Context.DependentTy))
@@ -2031,7 +2087,8 @@ static void AddResultTypeChunk(ASTContext &Context,
Result.getAllocator()));
}
-static void MaybeAddSentinel(ASTContext &Context, NamedDecl *FunctionOrMethod,
+static void MaybeAddSentinel(ASTContext &Context,
+ const NamedDecl *FunctionOrMethod,
CodeCompletionBuilder &Result) {
if (SentinelAttr *Sentinel = FunctionOrMethod->getAttr<SentinelAttr>())
if (Sentinel->getSentinel() == 0) {
@@ -2064,7 +2121,7 @@ static std::string formatObjCParamQualifiers(unsigned ObjCQuals) {
static std::string FormatFunctionParameter(ASTContext &Context,
const PrintingPolicy &Policy,
- ParmVarDecl *Param,
+ const ParmVarDecl *Param,
bool SuppressName = false,
bool SuppressBlock = false) {
bool ObjCMethodParam = isa<ObjCMethodDecl>(Param->getDeclContext());
@@ -2090,36 +2147,35 @@ static std::string FormatFunctionParameter(ASTContext &Context,
// The argument for a block pointer parameter is a block literal with
// the appropriate type.
- FunctionTypeLoc *Block = 0;
- FunctionProtoTypeLoc *BlockProto = 0;
+ FunctionTypeLoc Block;
+ FunctionProtoTypeLoc BlockProto;
TypeLoc TL;
if (TypeSourceInfo *TSInfo = Param->getTypeSourceInfo()) {
TL = TSInfo->getTypeLoc().getUnqualifiedLoc();
while (true) {
// Look through typedefs.
if (!SuppressBlock) {
- if (TypedefTypeLoc *TypedefTL = dyn_cast<TypedefTypeLoc>(&TL)) {
- if (TypeSourceInfo *InnerTSInfo
- = TypedefTL->getTypedefNameDecl()->getTypeSourceInfo()) {
+ if (TypedefTypeLoc TypedefTL = TL.getAs<TypedefTypeLoc>()) {
+ if (TypeSourceInfo *InnerTSInfo =
+ TypedefTL.getTypedefNameDecl()->getTypeSourceInfo()) {
TL = InnerTSInfo->getTypeLoc().getUnqualifiedLoc();
continue;
}
}
// Look through qualified types
- if (QualifiedTypeLoc *QualifiedTL = dyn_cast<QualifiedTypeLoc>(&TL)) {
- TL = QualifiedTL->getUnqualifiedLoc();
+ if (QualifiedTypeLoc QualifiedTL = TL.getAs<QualifiedTypeLoc>()) {
+ TL = QualifiedTL.getUnqualifiedLoc();
continue;
}
}
// Try to get the function prototype behind the block pointer type,
// then we're done.
- if (BlockPointerTypeLoc *BlockPtr
- = dyn_cast<BlockPointerTypeLoc>(&TL)) {
- TL = BlockPtr->getPointeeLoc().IgnoreParens();
- Block = dyn_cast<FunctionTypeLoc>(&TL);
- BlockProto = dyn_cast<FunctionProtoTypeLoc>(&TL);
+ if (BlockPointerTypeLoc BlockPtr = TL.getAs<BlockPointerTypeLoc>()) {
+ TL = BlockPtr.getPointeeLoc().IgnoreParens();
+ Block = TL.getAs<FunctionTypeLoc>();
+ BlockProto = TL.getAs<FunctionProtoTypeLoc>();
}
break;
}
@@ -2147,27 +2203,27 @@ static std::string FormatFunctionParameter(ASTContext &Context,
// We have the function prototype behind the block pointer type, as it was
// written in the source.
std::string Result;
- QualType ResultType = Block->getTypePtr()->getResultType();
+ QualType ResultType = Block.getTypePtr()->getResultType();
if (!ResultType->isVoidType() || SuppressBlock)
ResultType.getAsStringInternal(Result, Policy);
// Format the parameter list.
std::string Params;
- if (!BlockProto || Block->getNumArgs() == 0) {
- if (BlockProto && BlockProto->getTypePtr()->isVariadic())
+ if (!BlockProto || Block.getNumArgs() == 0) {
+ if (BlockProto && BlockProto.getTypePtr()->isVariadic())
Params = "(...)";
else
Params = "(void)";
} else {
Params += "(";
- for (unsigned I = 0, N = Block->getNumArgs(); I != N; ++I) {
+ for (unsigned I = 0, N = Block.getNumArgs(); I != N; ++I) {
if (I)
Params += ", ";
- Params += FormatFunctionParameter(Context, Policy, Block->getArg(I),
+ Params += FormatFunctionParameter(Context, Policy, Block.getArg(I),
/*SuppressName=*/false,
/*SuppressBlock=*/true);
- if (I == N - 1 && BlockProto->getTypePtr()->isVariadic())
+ if (I == N - 1 && BlockProto.getTypePtr()->isVariadic())
Params += ", ...";
}
Params += ")";
@@ -2195,14 +2251,14 @@ static std::string FormatFunctionParameter(ASTContext &Context,
/// \brief Add function parameter chunks to the given code completion string.
static void AddFunctionParameterChunks(ASTContext &Context,
const PrintingPolicy &Policy,
- FunctionDecl *Function,
+ const FunctionDecl *Function,
CodeCompletionBuilder &Result,
unsigned Start = 0,
bool InOptional = false) {
bool FirstParameter = true;
for (unsigned P = Start, N = Function->getNumParams(); P != N; ++P) {
- ParmVarDecl *Param = Function->getParamDecl(P);
+ const ParmVarDecl *Param = Function->getParamDecl(P);
if (Param->hasDefaultArg() && !InOptional) {
// When we see an optional default argument, put that argument and
@@ -2248,7 +2304,7 @@ static void AddFunctionParameterChunks(ASTContext &Context,
/// \brief Add template parameter chunks to the given code completion string.
static void AddTemplateParameterChunks(ASTContext &Context,
const PrintingPolicy &Policy,
- TemplateDecl *Template,
+ const TemplateDecl *Template,
CodeCompletionBuilder &Result,
unsigned MaxParameters = 0,
unsigned Start = 0,
@@ -2346,7 +2402,7 @@ AddQualifierToCompletionString(CodeCompletionBuilder &Result,
static void
AddFunctionTypeQualsToCompletionString(CodeCompletionBuilder &Result,
- FunctionDecl *Function) {
+ const FunctionDecl *Function) {
const FunctionProtoType *Proto
= Function->getType()->getAs<FunctionProtoType>();
if (!Proto || !Proto->getTypeQuals())
@@ -2383,7 +2439,8 @@ AddFunctionTypeQualsToCompletionString(CodeCompletionBuilder &Result,
/// \brief Add the name of the given declaration
static void AddTypedNameChunk(ASTContext &Context, const PrintingPolicy &Policy,
- NamedDecl *ND, CodeCompletionBuilder &Result) {
+ const NamedDecl *ND,
+ CodeCompletionBuilder &Result) {
DeclarationName Name = ND->getDeclName();
if (!Name)
return;
@@ -2484,6 +2541,27 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
if (Declaration) {
Result.addParentContext(Declaration->getDeclContext());
Pattern->ParentName = Result.getParentName();
+ // Provide code completion comment for self.GetterName where
+ // GetterName is the getter method for a property with name
+ // different from the property name (declared via a property
+ // getter attribute.
+ const NamedDecl *ND = Declaration;
+ if (const ObjCMethodDecl *M = dyn_cast<ObjCMethodDecl>(ND))
+ if (M->isPropertyAccessor())
+ if (const ObjCPropertyDecl *PDecl = M->findPropertyDecl())
+ if (PDecl->getGetterName() == M->getSelector() &&
+ PDecl->getIdentifier() != M->getIdentifier()) {
+ if (const RawComment *RC =
+ Ctx.getRawCommentForAnyRedecl(M)) {
+ Result.addBriefComment(RC->getBriefText(Ctx));
+ Pattern->BriefComment = Result.getBriefComment();
+ }
+ else if (const RawComment *RC =
+ Ctx.getRawCommentForAnyRedecl(PDecl)) {
+ Result.addBriefComment(RC->getBriefText(Ctx));
+ Pattern->BriefComment = Result.getBriefComment();
+ }
+ }
}
return Pattern;
@@ -2495,8 +2573,9 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
}
if (Kind == RK_Macro) {
- MacroInfo *MI = PP.getMacroInfoHistory(Macro);
- assert(MI && "Not a macro?");
+ const MacroDirective *MD = PP.getMacroDirectiveHistory(Macro);
+ assert(MD && "Not a macro?");
+ const MacroInfo *MI = MD->getMacroInfo();
Result.AddTypedTextChunk(
Result.getAllocator().CopyString(Macro->getName()));
@@ -2540,14 +2619,19 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
}
assert(Kind == RK_Declaration && "Missed a result kind?");
- NamedDecl *ND = Declaration;
+ const NamedDecl *ND = Declaration;
Result.addParentContext(ND->getDeclContext());
if (IncludeBriefComments) {
// Add documentation comment, if it exists.
if (const RawComment *RC = Ctx.getRawCommentForAnyRedecl(ND)) {
Result.addBriefComment(RC->getBriefText(Ctx));
- }
+ }
+ else if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(ND))
+ if (OMD->isPropertyAccessor())
+ if (const ObjCPropertyDecl *PDecl = OMD->findPropertyDecl())
+ if (const RawComment *RC = Ctx.getRawCommentForAnyRedecl(PDecl))
+ Result.addBriefComment(RC->getBriefText(Ctx));
}
if (StartsNestedNameSpecifier) {
@@ -2565,7 +2649,7 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
AddResultTypeChunk(Ctx, Policy, ND, Result);
- if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) {
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) {
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
Ctx, Policy);
AddTypedNameChunk(Ctx, Policy, ND, Result);
@@ -2576,7 +2660,7 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
return Result.TakeString();
}
- if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND)) {
+ if (const FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND)) {
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
Ctx, Policy);
FunctionDecl *Function = FunTmpl->getTemplatedDecl();
@@ -2630,7 +2714,7 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
return Result.TakeString();
}
- if (TemplateDecl *Template = dyn_cast<TemplateDecl>(ND)) {
+ if (const TemplateDecl *Template = dyn_cast<TemplateDecl>(ND)) {
AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative,
Ctx, Policy);
Result.AddTypedTextChunk(
@@ -2641,7 +2725,7 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
return Result.TakeString();
}
- if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND)) {
+ if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND)) {
Selector Sel = Method->getSelector();
if (Sel.isUnarySelector()) {
Result.AddTypedTextChunk(Result.getAllocator().CopyString(
@@ -2662,8 +2746,8 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx,
Result.AddTypedTextChunk("");
}
unsigned Idx = 0;
- for (ObjCMethodDecl::param_iterator P = Method->param_begin(),
- PEnd = Method->param_end();
+ for (ObjCMethodDecl::param_const_iterator P = Method->param_begin(),
+ PEnd = Method->param_end();
P != PEnd; (void)++P, ++Idx) {
if (Idx > 0) {
std::string Keyword;
@@ -2827,7 +2911,7 @@ unsigned clang::getMacroUsagePriority(StringRef MacroName,
return Priority;
}
-CXCursorKind clang::getCursorKindForDecl(Decl *D) {
+CXCursorKind clang::getCursorKindForDecl(const Decl *D) {
if (!D)
return CXCursor_UnexposedDecl;
@@ -2887,7 +2971,7 @@ CXCursorKind clang::getCursorKindForDecl(Decl *D) {
return CXCursor_ModuleImportDecl;
default:
- if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
+ if (const TagDecl *TD = dyn_cast<TagDecl>(D)) {
switch (TD->getTagKind()) {
case TTK_Interface: // fall through
case TTK_Struct: return CXCursor_StructDecl;
@@ -2930,7 +3014,7 @@ static void AddPrettyFunctionResults(const LangOptions &LangOpts,
Results.AddResult(Result("__PRETTY_FUNCTION__", CCP_Constant));
Results.AddResult(Result("__FUNCTION__", CCP_Constant));
- if (LangOpts.C99 || LangOpts.CPlusPlus0x)
+ if (LangOpts.C99 || LangOpts.CPlusPlus11)
Results.AddResult(Result("__func__", CCP_Constant));
Results.ExitScope();
}
@@ -3036,7 +3120,7 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext,
M != MEnd; ++M) {
CodeCompletionBuilder Builder(Results.getAllocator(),
Results.getCodeCompletionTUInfo());
- CXXMethodDecl *Overridden = const_cast<CXXMethodDecl *>(*M);
+ const CXXMethodDecl *Overridden = *M;
if (Overridden->getCanonicalDecl() == Method->getCanonicalDecl())
continue;
@@ -3092,7 +3176,7 @@ void Sema::CodeCompleteModuleImport(SourceLocation ImportLoc,
typedef CodeCompletionResult Result;
if (Path.empty()) {
// Enumerate all top-level modules.
- llvm::SmallVector<Module *, 8> Modules;
+ SmallVector<Module *, 8> Modules;
PP.getHeaderSearchInfo().collectAllModules(Modules);
for (unsigned I = 0, N = Modules.size(); I != N; ++I) {
Builder.AddTypedTextChunk(
@@ -3265,7 +3349,7 @@ void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS,
// the initial opening bracket '[' missing. Add appropriate completions.
if (AllowNonIdentifiers && !AllowNestedNameSpecifiers &&
DS.getTypeSpecType() == DeclSpec::TST_typename &&
- DS.getStorageClassSpecAsWritten() == DeclSpec::SCS_unspecified &&
+ DS.getStorageClassSpec() == DeclSpec::SCS_unspecified &&
!DS.isThreadSpecified() && !DS.isExternInLinkageSpec() &&
DS.getTypeSpecComplex() == DeclSpec::TSC_unspecified &&
DS.getTypeSpecSign() == DeclSpec::TSS_unspecified &&
@@ -3395,7 +3479,8 @@ static void AddObjCProperties(ObjCContainerDecl *Container,
P != PEnd;
++P) {
if (AddedProperties.insert(P->getIdentifier()))
- Results.MaybeAddResult(Result(*P, 0), CurContext);
+ Results.MaybeAddResult(Result(*P, Results.getBasePriority(*P), 0),
+ CurContext);
}
// Add nullary methods
@@ -3432,9 +3517,11 @@ static void AddObjCProperties(ObjCContainerDecl *Container,
} else if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container)){
if (AllowCategories) {
// Look through categories.
- for (ObjCCategoryDecl *Category = IFace->getCategoryList();
- Category; Category = Category->getNextClassCategory())
- AddObjCProperties(Category, AllowCategories, AllowNullaryMethods,
+ for (ObjCInterfaceDecl::known_categories_iterator
+ Cat = IFace->known_categories_begin(),
+ CatEnd = IFace->known_categories_end();
+ Cat != CatEnd; ++Cat)
+ AddObjCProperties(*Cat, AllowCategories, AllowNullaryMethods,
CurContext, AddedProperties, Results);
}
@@ -3642,6 +3729,9 @@ void Sema::CodeCompleteTypeQualifiers(DeclSpec &DS) {
if (getLangOpts().C99 &&
!(DS.getTypeQualifiers() & DeclSpec::TQ_restrict))
Results.AddResult("restrict");
+ if (getLangOpts().C11 &&
+ !(DS.getTypeQualifiers() & DeclSpec::TQ_atomic))
+ Results.AddResult("_Atomic");
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter,
Results.getCompletionContext(),
@@ -3724,8 +3814,7 @@ void Sema::CodeCompleteCase(Scope *S) {
if (EnumeratorsSeen.count(*E))
continue;
- CodeCompletionResult R(*E, Qualifier);
- R.Priority = CCP_EnumInCase;
+ CodeCompletionResult R(*E, CCP_EnumInCase, Qualifier);
Results.AddResult(R, CurContext, 0, false);
}
Results.ExitScope();
@@ -4094,7 +4183,8 @@ void Sema::CodeCompleteNamespaceDecl(Scope *S) {
NS = OrigToLatest.begin(),
NSEnd = OrigToLatest.end();
NS != NSEnd; ++NS)
- Results.AddResult(CodeCompletionResult(NS->second, 0),
+ Results.AddResult(CodeCompletionResult(
+ NS->second, Results.getBasePriority(NS->second), 0),
CurContext, 0, false);
Results.ExitScope();
}
@@ -4308,7 +4398,8 @@ void Sema::CodeCompleteLambdaIntroducer(Scope *S, LambdaIntroducer &Intro,
continue;
if (Known.insert(Var->getIdentifier()))
- Results.AddResult(CodeCompletionResult(Var), CurContext, 0, false);
+ Results.AddResult(CodeCompletionResult(Var, CCP_LocalDeclaration),
+ CurContext, 0, false);
}
}
@@ -4410,6 +4501,14 @@ static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) {
Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
Builder.AddPlaceholderChunk("class");
Results.AddResult(Result(Builder.TakeString()));
+
+ if (Results.getSema().getLangOpts().Modules) {
+ // @import name
+ Builder.AddTypedTextChunk(OBJC_AT_KEYWORD_NAME(NeedAt, "import"));
+ Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+ Builder.AddPlaceholderChunk("module");
+ Results.AddResult(Result(Builder.TakeString()));
+ }
}
void Sema::CodeCompleteObjCAtDirective(Scope *S) {
@@ -4757,10 +4856,15 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
bool InOriginalClass = true) {
typedef CodeCompletionResult Result;
Container = getContainerDef(Container);
+ ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container);
+ bool isRootClass = IFace && !IFace->getSuperClass();
for (ObjCContainerDecl::method_iterator M = Container->meth_begin(),
MEnd = Container->meth_end();
M != MEnd; ++M) {
- if (M->isInstanceMethod() == WantInstanceMethods) {
+ // The instance methods on the root class can be messaged via the
+ // metaclass.
+ if (M->isInstanceMethod() == WantInstanceMethods ||
+ (isRootClass && !WantInstanceMethods)) {
// Check whether the selector identifiers we've been given are a
// subset of the identifiers for this particular method.
if (!isAcceptableObjCMethod(*M, WantKind, SelIdents, NumSelIdents,
@@ -4770,7 +4874,7 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
if (!Selectors.insert(M->getSelector()))
continue;
- Result R = Result(*M, 0);
+ Result R = Result(*M, Results.getBasePriority(*M), 0);
R.StartParameter = NumSelIdents;
R.AllParametersAreInformative = (WantKind != MK_Any);
if (!InOriginalClass)
@@ -4793,7 +4897,6 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
}
}
- ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container);
if (!IFace || !IFace->hasDefinition())
return;
@@ -4805,9 +4908,13 @@ static void AddObjCMethods(ObjCContainerDecl *Container,
CurContext, Selectors, AllowSameLength, Results, false);
// Add methods in categories.
- for (ObjCCategoryDecl *CatDecl = IFace->getCategoryList(); CatDecl;
- CatDecl = CatDecl->getNextClassCategory()) {
- AddObjCMethods(CatDecl, WantInstanceMethods, WantKind, SelIdents,
+ for (ObjCInterfaceDecl::known_categories_iterator
+ Cat = IFace->known_categories_begin(),
+ CatEnd = IFace->known_categories_end();
+ Cat != CatEnd; ++Cat) {
+ ObjCCategoryDecl *CatDecl = *Cat;
+
+ AddObjCMethods(CatDecl, WantInstanceMethods, WantKind, SelIdents,
NumSelIdents, CurContext, Selectors, AllowSameLength,
Results, InOriginalClass);
@@ -4946,6 +5053,11 @@ void Sema::CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS,
Builder.AddTextChunk("sender");
Results.AddResult(CodeCompletionResult(Builder.TakeString()));
}
+
+ // If we're completing the return type, provide 'instancetype'.
+ if (!IsParameter) {
+ Results.AddResult(CodeCompletionResult("instancetype"));
+ }
// Add various builtin type names and specifiers.
AddOrdinaryNameResults(PCC_Type, S, *this, Results);
@@ -5075,11 +5187,14 @@ static ObjCMethodDecl *AddSuperSendCompletion(Sema &S, bool NeedSuperKeyword,
// Check in categories or class extensions.
if (!SuperMethod) {
- for (ObjCCategoryDecl *Category = Class->getCategoryList(); Category;
- Category = Category->getNextClassCategory())
- if ((SuperMethod = Category->getMethod(CurMethod->getSelector(),
+ for (ObjCInterfaceDecl::known_categories_iterator
+ Cat = Class->known_categories_begin(),
+ CatEnd = Class->known_categories_end();
+ Cat != CatEnd; ++Cat) {
+ if ((SuperMethod = Cat->getMethod(CurMethod->getSelector(),
CurMethod->isInstanceMethod())))
break;
+ }
}
}
@@ -5163,7 +5278,7 @@ void Sema::CodeCompleteObjCMessageReceiver(Scope *S) {
ResultBuilder Results(*this, CodeCompleter->getAllocator(),
CodeCompleter->getCodeCompletionTUInfo(),
CodeCompletionContext::CCC_ObjCMessageReceiver,
- getLangOpts().CPlusPlus0x
+ getLangOpts().CPlusPlus11
? &ResultBuilder::IsObjCMessageReceiverOrLambdaCapture
: &ResultBuilder::IsObjCMessageReceiver);
@@ -5182,7 +5297,7 @@ void Sema::CodeCompleteObjCMessageReceiver(Scope *S) {
AddSuperSendCompletion(*this, /*NeedSuperKeyword=*/true, 0, 0, Results);
}
- if (getLangOpts().CPlusPlus0x)
+ if (getLangOpts().CPlusPlus11)
addThisCompletion(*this, Results);
Results.ExitScope();
@@ -5224,7 +5339,7 @@ void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc,
} else {
// "super" may be the name of a type or variable. Figure out which
// it is.
- IdentifierInfo *Super = &Context.Idents.get("super");
+ IdentifierInfo *Super = getSuperIdentifier();
NamedDecl *ND = LookupSingleName(S, Super, SuperLoc,
LookupOrdinaryName);
if ((CDecl = dyn_cast_or_null<ObjCInterfaceDecl>(ND))) {
@@ -5274,7 +5389,7 @@ static QualType getPreferredArgumentTypeForMessageSend(ResultBuilder &Results,
if (R.Kind == Result::RK_Declaration &&
isa<ObjCMethodDecl>(R.Declaration)) {
if (R.Priority <= BestPriority) {
- ObjCMethodDecl *Method = cast<ObjCMethodDecl>(R.Declaration);
+ const ObjCMethodDecl *Method = cast<ObjCMethodDecl>(R.Declaration);
if (NumSelIdents <= Method->param_size()) {
QualType MyPreferredType = Method->param_begin()[NumSelIdents - 1]
->getType();
@@ -5362,7 +5477,7 @@ static void AddClassMessageCompletions(Sema &SemaRef, Scope *S,
NumSelIdents))
continue;
- Result R(MethList->Method, 0);
+ Result R(MethList->Method, Results.getBasePriority(MethList->Method),0);
R.StartParameter = NumSelIdents;
R.AllParametersAreInformative = false;
Results.MaybeAddResult(R, SemaRef.CurContext);
@@ -5538,7 +5653,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver,
if (!Selectors.insert(MethList->Method->getSelector()))
continue;
- Result R(MethList->Method, 0);
+ Result R(MethList->Method, Results.getBasePriority(MethList->Method),0);
R.StartParameter = NumSelIdents;
R.AllParametersAreInformative = false;
Results.MaybeAddResult(R, CurContext);
@@ -5656,7 +5771,8 @@ static void AddProtocolResults(DeclContext *Ctx, DeclContext *CurContext,
// Record any protocols we find.
if (ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(*D))
if (!OnlyForwardDeclarations || !Proto->hasDefinition())
- Results.AddResult(Result(Proto, 0), CurContext, 0, false);
+ Results.AddResult(Result(Proto, Results.getBasePriority(Proto), 0),
+ CurContext, 0, false);
}
}
@@ -5724,7 +5840,8 @@ static void AddInterfaceResults(DeclContext *Ctx, DeclContext *CurContext,
if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(*D))
if ((!OnlyForwardDeclarations || !Class->hasDefinition()) &&
(!OnlyUnimplemented || !Class->getImplementation()))
- Results.AddResult(Result(Class, 0), CurContext, 0, false);
+ Results.AddResult(Result(Class, Results.getBasePriority(Class), 0),
+ CurContext, 0, false);
}
}
@@ -5806,11 +5923,15 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S,
llvm::SmallPtrSet<IdentifierInfo *, 16> CategoryNames;
NamedDecl *CurClass
= LookupSingleName(TUScope, ClassName, ClassNameLoc, LookupOrdinaryName);
- if (ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(CurClass))
- for (ObjCCategoryDecl *Category = Class->getCategoryList(); Category;
- Category = Category->getNextClassCategory())
- CategoryNames.insert(Category->getIdentifier());
-
+ if (ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(CurClass)){
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = Class->visible_categories_begin(),
+ CatEnd = Class->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
+ CategoryNames.insert(Cat->getIdentifier());
+ }
+ }
+
// Add all of the categories we know about.
Results.EnterNewScope();
TranslationUnitDecl *TU = Context.getTranslationUnitDecl();
@@ -5819,7 +5940,8 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S,
D != DEnd; ++D)
if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(*D))
if (CategoryNames.insert(Category->getIdentifier()))
- Results.AddResult(Result(Category, 0), CurContext, 0, false);
+ Results.AddResult(Result(Category, Results.getBasePriority(Category),0),
+ CurContext, 0, false);
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter,
@@ -5852,11 +5974,15 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S,
Results.EnterNewScope();
bool IgnoreImplemented = true;
while (Class) {
- for (ObjCCategoryDecl *Category = Class->getCategoryList(); Category;
- Category = Category->getNextClassCategory())
- if ((!IgnoreImplemented || !Category->getImplementation()) &&
- CategoryNames.insert(Category->getIdentifier()))
- Results.AddResult(Result(Category, 0), CurContext, 0, false);
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = Class->visible_categories_begin(),
+ CatEnd = Class->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
+ if ((!IgnoreImplemented || !Cat->getImplementation()) &&
+ CategoryNames.insert(Cat->getIdentifier()))
+ Results.AddResult(Result(*Cat, Results.getBasePriority(*Cat), 0),
+ CurContext, 0, false);
+ }
Class = Class->getSuperClass();
IgnoreImplemented = false;
@@ -5956,7 +6082,8 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S,
for(; Class; Class = Class->getSuperClass()) {
for (ObjCIvarDecl *Ivar = Class->all_declared_ivar_begin(); Ivar;
Ivar = Ivar->getNextIvar()) {
- Results.AddResult(Result(Ivar, 0), CurContext, 0, false);
+ Results.AddResult(Result(Ivar, Results.getBasePriority(Ivar), 0),
+ CurContext, 0, false);
// Determine whether we've seen an ivar with a name similar to the
// property.
@@ -6032,12 +6159,14 @@ static void FindImplementableMethods(ASTContext &Context,
KnownMethods, InOriginalClass);
// Add methods from any class extensions and categories.
- for (const ObjCCategoryDecl *Cat = IFace->getCategoryList(); Cat;
- Cat = Cat->getNextClassCategory())
- FindImplementableMethods(Context, const_cast<ObjCCategoryDecl*>(Cat),
- WantInstanceMethods, ReturnType,
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = IFace->visible_categories_begin(),
+ CatEnd = IFace->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
+ FindImplementableMethods(Context, *Cat, WantInstanceMethods, ReturnType,
KnownMethods, false);
-
+ }
+
// Visit the superclass.
if (IFace->getSuperClass())
FindImplementableMethods(Context, IFace->getSuperClass(),
@@ -6167,7 +6296,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
// The uppercased name of the property name.
std::string UpperKey = PropName->getName();
if (!UpperKey.empty())
- UpperKey[0] = toupper(UpperKey[0]);
+ UpperKey[0] = toUppercase(UpperKey[0]);
bool ReturnTypeMatchesProperty = ReturnType.isNull() ||
Context.hasSameUnqualifiedType(ReturnType.getNonReferenceType(),
@@ -6897,9 +7026,12 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
IFace = Category->getClassInterface();
if (IFace) {
- for (ObjCCategoryDecl *Category = IFace->getCategoryList(); Category;
- Category = Category->getNextClassCategory())
- Containers.push_back(Category);
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = IFace->visible_categories_begin(),
+ CatEnd = IFace->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
+ Containers.push_back(*Cat);
+ }
}
for (unsigned I = 0, N = Containers.size(); I != N; ++I) {
@@ -6975,7 +7107,7 @@ void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S,
continue;
}
- Result R(MethList->Method, 0);
+ Result R(MethList->Method, Results.getBasePriority(MethList->Method), 0);
R.StartParameter = NumSelIdents;
R.AllParametersAreInformative = false;
R.DeclaringEntity = true;
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 0092d5d..adf3505 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -12,15 +12,11 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Initialization.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/CXXFieldCollector.h"
-#include "clang/Sema/Scope.h"
-#include "clang/Sema/ScopeInfo.h"
#include "TypeLocBuilder.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/CommentDiagnostic.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
@@ -28,18 +24,21 @@
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
-#include "clang/AST/CharUnits.h"
-#include "clang/Sema/DeclSpec.h"
-#include "clang/Sema/ParsedTemplate.h"
-#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Basic/PartialDiagnostic.h"
-#include "clang/Sema/DelayedDiagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
-// FIXME: layering (ideally, Sema shouldn't be dependent on Lex API's)
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/HeaderSearch.h"
-#include "clang/Lex/ModuleLoader.h"
+#include "clang/Lex/HeaderSearch.h" // FIXME: Sema shouldn't depend on Lex
+#include "clang/Lex/ModuleLoader.h" // FIXME: Sema shouldn't depend on Lex
+#include "clang/Lex/Preprocessor.h" // FIXME: Sema shouldn't depend on Lex
+#include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Sema/CXXFieldCollector.h"
+#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/DelayedDiagnostic.h"
+#include "clang/Sema/Initialization.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/ParsedTemplate.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/ScopeInfo.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Triple.h"
#include <algorithm>
@@ -677,9 +676,9 @@ Corrected:
(isa<TypeDecl>(UnderlyingFirstDecl) ||
isa<ObjCInterfaceDecl>(UnderlyingFirstDecl) ||
isa<ObjCCompatibleAliasDecl>(UnderlyingFirstDecl))) {
- UnqualifiedDiag = diag::err_unknown_typename_suggest;
- QualifiedDiag = diag::err_unknown_nested_typename_suggest;
- }
+ UnqualifiedDiag = diag::err_unknown_typename_suggest;
+ QualifiedDiag = diag::err_unknown_nested_typename_suggest;
+ }
if (SS.isEmpty())
Diag(NameLoc, UnqualifiedDiag)
@@ -1097,7 +1096,7 @@ void Sema::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) {
bool Sema::isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S,
bool ExplicitInstantiationOrSpecialization) {
- return IdResolver.isDeclInScope(D, Ctx, Context, S,
+ return IdResolver.isDeclInScope(D, Ctx, S,
ExplicitInstantiationOrSpecialization);
}
@@ -1175,6 +1174,31 @@ static bool IsDisallowedCopyOrAssign(const CXXMethodDecl *D) {
return false;
}
+// We need this to handle
+//
+// typedef struct {
+// void *foo() { return 0; }
+// } A;
+//
+// When we see foo we don't know if after the typedef we will get 'A' or '*A'
+// for example. If 'A', foo will have external linkage. If we have '*A',
+// foo will have no linkage. Since we can't know untill we get to the end
+// of the typedef, this function finds out if D might have non external linkage.
+// Callers should verify at the end of the TU if it D has external linkage or
+// not.
+bool Sema::mightHaveNonExternalLinkage(const DeclaratorDecl *D) {
+ const DeclContext *DC = D->getDeclContext();
+ while (!DC->isTranslationUnit()) {
+ if (const RecordDecl *RD = dyn_cast<RecordDecl>(DC)){
+ if (!RD->hasNameForLinkage())
+ return true;
+ }
+ DC = DC->getParent();
+ }
+
+ return !D->hasExternalLinkage();
+}
+
bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const {
assert(D);
@@ -1224,10 +1248,7 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const {
}
// Only warn for unused decls internal to the translation unit.
- if (D->getLinkage() == ExternalLinkage)
- return false;
-
- return true;
+ return mightHaveNonExternalLinkage(D);
}
void Sema::MarkUnusedFileScopedDecl(const DeclaratorDecl *D) {
@@ -1368,7 +1389,7 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
if (!D->getDeclName()) continue;
// Diagnose unused variables in this scope.
- if (!S->hasErrorOccurred())
+ if (!S->hasUnrecoverableErrorOccurred())
DiagnoseUnusedDecl(D);
// If this was a forward reference to a label, verify it was defined.
@@ -1465,6 +1486,24 @@ Scope *Sema::getNonFieldDeclScope(Scope *S) {
return S;
}
+/// \brief Looks up the declaration of "struct objc_super" and
+/// saves it for later use in building builtin declaration of
+/// objc_msgSendSuper and objc_msgSendSuper_stret. If no such
+/// pre-existing declaration exists no action takes place.
+static void LookupPredefedObjCSuperType(Sema &ThisSema, Scope *S,
+ IdentifierInfo *II) {
+ if (!II->isStr("objc_msgSendSuper"))
+ return;
+ ASTContext &Context = ThisSema.Context;
+
+ LookupResult Result(ThisSema, &Context.Idents.get("objc_super"),
+ SourceLocation(), Sema::LookupTagName);
+ ThisSema.LookupName(Result, S);
+ if (Result.getResultKind() == LookupResult::Found)
+ if (const TagDecl *TD = Result.getAsSingle<TagDecl>())
+ Context.setObjCSuperType(Context.getTagDeclType(TD));
+}
+
/// LazilyCreateBuiltin - The specified Builtin-ID was first used at
/// file scope. lazily create a decl for it. ForRedeclaration is true
/// if we're creating this built-in in anticipation of redeclaring the
@@ -1472,6 +1511,8 @@ Scope *Sema::getNonFieldDeclScope(Scope *S) {
NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
Scope *S, bool ForRedeclaration,
SourceLocation Loc) {
+ LookupPredefedObjCSuperType(*this, S, II);
+
Builtin::ID BID = (Builtin::ID)bid;
ASTContext::GetBuiltinTypeError Error;
@@ -1516,7 +1557,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
Context.getTranslationUnitDecl(),
Loc, Loc, II, R, /*TInfo=*/0,
SC_Extern,
- SC_None, false,
+ false,
/*hasPrototype=*/true);
New->setImplicit();
@@ -1529,7 +1570,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
ParmVarDecl::Create(Context, New, SourceLocation(),
SourceLocation(), 0,
FT->getArgType(i), /*TInfo=*/0,
- SC_None, SC_None, 0);
+ SC_None, 0);
parm->setScopeInfo(0, i);
Params.push_back(parm);
}
@@ -1549,6 +1590,49 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
return New;
}
+/// \brief Filter out any previous declarations that the given declaration
+/// should not consider because they are not permitted to conflict, e.g.,
+/// because they come from hidden sub-modules and do not refer to the same
+/// entity.
+static void filterNonConflictingPreviousDecls(ASTContext &context,
+ NamedDecl *decl,
+ LookupResult &previous){
+ // This is only interesting when modules are enabled.
+ if (!context.getLangOpts().Modules)
+ return;
+
+ // Empty sets are uninteresting.
+ if (previous.empty())
+ return;
+
+ LookupResult::Filter filter = previous.makeFilter();
+ while (filter.hasNext()) {
+ NamedDecl *old = filter.next();
+
+ // Non-hidden declarations are never ignored.
+ if (!old->isHidden())
+ continue;
+
+ // If either has no-external linkage, ignore the old declaration.
+ // If this declaration would have external linkage if it were the first
+ // declaration of this name, then it may in fact be a redeclaration of
+ // some hidden declaration, so include those too. We don't need to worry
+ // about some previous visible declaration giving this declaration external
+ // linkage, because in that case, we'll mark this declaration as a redecl
+ // of the visible decl, and that decl will already be a redecl of the
+ // hidden declaration if that's appropriate.
+ //
+ // Don't cache this linkage computation, because it's not yet correct: we
+ // may later give this declaration a previous declaration which changes
+ // its linkage.
+ if (old->getLinkage() != ExternalLinkage ||
+ !decl->hasExternalLinkageUncached())
+ filter.erase();
+ }
+
+ filter.done();
+}
+
bool Sema::isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New) {
QualType OldType;
if (TypedefNameDecl *OldTypedef = dyn_cast<TypedefNameDecl>(Old))
@@ -1769,26 +1853,164 @@ DeclHasAttr(const Decl *D, const Attr *A) {
return false;
}
-bool Sema::mergeDeclAttribute(Decl *D, InheritableAttr *Attr) {
+static bool isAttributeTargetADefinition(Decl *D) {
+ if (VarDecl *VD = dyn_cast<VarDecl>(D))
+ return VD->isThisDeclarationADefinition();
+ if (TagDecl *TD = dyn_cast<TagDecl>(D))
+ return TD->isCompleteDefinition() || TD->isBeingDefined();
+ return true;
+}
+
+/// Merge alignment attributes from \p Old to \p New, taking into account the
+/// special semantics of C11's _Alignas specifier and C++11's alignas attribute.
+///
+/// \return \c true if any attributes were added to \p New.
+static bool mergeAlignedAttrs(Sema &S, NamedDecl *New, Decl *Old) {
+ // Look for alignas attributes on Old, and pick out whichever attribute
+ // specifies the strictest alignment requirement.
+ AlignedAttr *OldAlignasAttr = 0;
+ AlignedAttr *OldStrictestAlignAttr = 0;
+ unsigned OldAlign = 0;
+ for (specific_attr_iterator<AlignedAttr>
+ I = Old->specific_attr_begin<AlignedAttr>(),
+ E = Old->specific_attr_end<AlignedAttr>(); I != E; ++I) {
+ // FIXME: We have no way of representing inherited dependent alignments
+ // in a case like:
+ // template<int A, int B> struct alignas(A) X;
+ // template<int A, int B> struct alignas(B) X {};
+ // For now, we just ignore any alignas attributes which are not on the
+ // definition in such a case.
+ if (I->isAlignmentDependent())
+ return false;
+
+ if (I->isAlignas())
+ OldAlignasAttr = *I;
+
+ unsigned Align = I->getAlignment(S.Context);
+ if (Align > OldAlign) {
+ OldAlign = Align;
+ OldStrictestAlignAttr = *I;
+ }
+ }
+
+ // Look for alignas attributes on New.
+ AlignedAttr *NewAlignasAttr = 0;
+ unsigned NewAlign = 0;
+ for (specific_attr_iterator<AlignedAttr>
+ I = New->specific_attr_begin<AlignedAttr>(),
+ E = New->specific_attr_end<AlignedAttr>(); I != E; ++I) {
+ if (I->isAlignmentDependent())
+ return false;
+
+ if (I->isAlignas())
+ NewAlignasAttr = *I;
+
+ unsigned Align = I->getAlignment(S.Context);
+ if (Align > NewAlign)
+ NewAlign = Align;
+ }
+
+ if (OldAlignasAttr && NewAlignasAttr && OldAlign != NewAlign) {
+ // Both declarations have 'alignas' attributes. We require them to match.
+ // C++11 [dcl.align]p6 and C11 6.7.5/7 both come close to saying this, but
+ // fall short. (If two declarations both have alignas, they must both match
+ // every definition, and so must match each other if there is a definition.)
+
+ // If either declaration only contains 'alignas(0)' specifiers, then it
+ // specifies the natural alignment for the type.
+ if (OldAlign == 0 || NewAlign == 0) {
+ QualType Ty;
+ if (ValueDecl *VD = dyn_cast<ValueDecl>(New))
+ Ty = VD->getType();
+ else
+ Ty = S.Context.getTagDeclType(cast<TagDecl>(New));
+
+ if (OldAlign == 0)
+ OldAlign = S.Context.getTypeAlign(Ty);
+ if (NewAlign == 0)
+ NewAlign = S.Context.getTypeAlign(Ty);
+ }
+
+ if (OldAlign != NewAlign) {
+ S.Diag(NewAlignasAttr->getLocation(), diag::err_alignas_mismatch)
+ << (unsigned)S.Context.toCharUnitsFromBits(OldAlign).getQuantity()
+ << (unsigned)S.Context.toCharUnitsFromBits(NewAlign).getQuantity();
+ S.Diag(OldAlignasAttr->getLocation(), diag::note_previous_declaration);
+ }
+ }
+
+ if (OldAlignasAttr && !NewAlignasAttr && isAttributeTargetADefinition(New)) {
+ // C++11 [dcl.align]p6:
+ // if any declaration of an entity has an alignment-specifier,
+ // every defining declaration of that entity shall specify an
+ // equivalent alignment.
+ // C11 6.7.5/7:
+ // If the definition of an object does not have an alignment
+ // specifier, any other declaration of that object shall also
+ // have no alignment specifier.
+ S.Diag(New->getLocation(), diag::err_alignas_missing_on_definition)
+ << OldAlignasAttr->isC11();
+ S.Diag(OldAlignasAttr->getLocation(), diag::note_alignas_on_declaration)
+ << OldAlignasAttr->isC11();
+ }
+
+ bool AnyAdded = false;
+
+ // Ensure we have an attribute representing the strictest alignment.
+ if (OldAlign > NewAlign) {
+ AlignedAttr *Clone = OldStrictestAlignAttr->clone(S.Context);
+ Clone->setInherited(true);
+ New->addAttr(Clone);
+ AnyAdded = true;
+ }
+
+ // Ensure we have an alignas attribute if the old declaration had one.
+ if (OldAlignasAttr && !NewAlignasAttr &&
+ !(AnyAdded && OldStrictestAlignAttr->isAlignas())) {
+ AlignedAttr *Clone = OldAlignasAttr->clone(S.Context);
+ Clone->setInherited(true);
+ New->addAttr(Clone);
+ AnyAdded = true;
+ }
+
+ return AnyAdded;
+}
+
+static bool mergeDeclAttribute(Sema &S, NamedDecl *D, InheritableAttr *Attr,
+ bool Override) {
InheritableAttr *NewAttr = NULL;
+ unsigned AttrSpellingListIndex = Attr->getSpellingListIndex();
if (AvailabilityAttr *AA = dyn_cast<AvailabilityAttr>(Attr))
- NewAttr = mergeAvailabilityAttr(D, AA->getRange(), AA->getPlatform(),
- AA->getIntroduced(), AA->getDeprecated(),
- AA->getObsoleted(), AA->getUnavailable(),
- AA->getMessage());
+ NewAttr = S.mergeAvailabilityAttr(D, AA->getRange(), AA->getPlatform(),
+ AA->getIntroduced(), AA->getDeprecated(),
+ AA->getObsoleted(), AA->getUnavailable(),
+ AA->getMessage(), Override,
+ AttrSpellingListIndex);
else if (VisibilityAttr *VA = dyn_cast<VisibilityAttr>(Attr))
- NewAttr = mergeVisibilityAttr(D, VA->getRange(), VA->getVisibility());
+ NewAttr = S.mergeVisibilityAttr(D, VA->getRange(), VA->getVisibility(),
+ AttrSpellingListIndex);
+ else if (TypeVisibilityAttr *VA = dyn_cast<TypeVisibilityAttr>(Attr))
+ NewAttr = S.mergeTypeVisibilityAttr(D, VA->getRange(), VA->getVisibility(),
+ AttrSpellingListIndex);
else if (DLLImportAttr *ImportA = dyn_cast<DLLImportAttr>(Attr))
- NewAttr = mergeDLLImportAttr(D, ImportA->getRange());
+ NewAttr = S.mergeDLLImportAttr(D, ImportA->getRange(),
+ AttrSpellingListIndex);
else if (DLLExportAttr *ExportA = dyn_cast<DLLExportAttr>(Attr))
- NewAttr = mergeDLLExportAttr(D, ExportA->getRange());
+ NewAttr = S.mergeDLLExportAttr(D, ExportA->getRange(),
+ AttrSpellingListIndex);
else if (FormatAttr *FA = dyn_cast<FormatAttr>(Attr))
- NewAttr = mergeFormatAttr(D, FA->getRange(), FA->getType(),
- FA->getFormatIdx(), FA->getFirstArg());
+ NewAttr = S.mergeFormatAttr(D, FA->getRange(), FA->getType(),
+ FA->getFormatIdx(), FA->getFirstArg(),
+ AttrSpellingListIndex);
else if (SectionAttr *SA = dyn_cast<SectionAttr>(Attr))
- NewAttr = mergeSectionAttr(D, SA->getRange(), SA->getName());
+ NewAttr = S.mergeSectionAttr(D, SA->getRange(), SA->getName(),
+ AttrSpellingListIndex);
+ else if (isa<AlignedAttr>(Attr))
+ // AlignedAttrs are handled separately, because we need to handle all
+ // such attributes on a declaration at the same time.
+ NewAttr = 0;
else if (!DeclHasAttr(D, Attr))
- NewAttr = cast<InheritableAttr>(Attr->clone(Context));
+ NewAttr = cast<InheritableAttr>(Attr->clone(S.Context));
if (NewAttr) {
NewAttr->setInherited(true);
@@ -1839,6 +2061,31 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
++I;
continue; // regular attr merging will take care of validating this.
}
+
+ if (isa<C11NoReturnAttr>(NewAttribute)) {
+ // C's _Noreturn is allowed to be added to a function after it is defined.
+ ++I;
+ continue;
+ } else if (const AlignedAttr *AA = dyn_cast<AlignedAttr>(NewAttribute)) {
+ if (AA->isAlignas()) {
+ // C++11 [dcl.align]p6:
+ // if any declaration of an entity has an alignment-specifier,
+ // every defining declaration of that entity shall specify an
+ // equivalent alignment.
+ // C11 6.7.5/7:
+ // If the definition of an object does not have an alignment
+ // specifier, any other declaration of that object shall also
+ // have no alignment specifier.
+ S.Diag(Def->getLocation(), diag::err_alignas_missing_on_definition)
+ << AA->isC11();
+ S.Diag(NewAttribute->getLocation(), diag::note_alignas_on_declaration)
+ << AA->isC11();
+ NewAttributes.erase(NewAttributes.begin() + I);
+ --E;
+ continue;
+ }
+ }
+
S.Diag(NewAttribute->getLocation(),
diag::warn_attribute_precede_definition);
S.Diag(Def->getLocation(), diag::note_previous_definition);
@@ -1848,8 +2095,11 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
}
/// mergeDeclAttributes - Copy attributes from the Old decl to the New one.
-void Sema::mergeDeclAttributes(Decl *New, Decl *Old,
- bool MergeDeprecation) {
+void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old,
+ AvailabilityMergeKind AMK) {
+ if (!Old->hasAttrs() && !New->hasAttrs())
+ return;
+
// attributes declared post-definition are currently ignored
checkNewAttributesAfterDef(*this, New, Old);
@@ -1866,17 +2116,31 @@ void Sema::mergeDeclAttributes(Decl *New, Decl *Old,
i = Old->specific_attr_begin<InheritableAttr>(),
e = Old->specific_attr_end<InheritableAttr>();
i != e; ++i) {
+ bool Override = false;
// Ignore deprecated/unavailable/availability attributes if requested.
- if (!MergeDeprecation &&
- (isa<DeprecatedAttr>(*i) ||
- isa<UnavailableAttr>(*i) ||
- isa<AvailabilityAttr>(*i)))
- continue;
+ if (isa<DeprecatedAttr>(*i) ||
+ isa<UnavailableAttr>(*i) ||
+ isa<AvailabilityAttr>(*i)) {
+ switch (AMK) {
+ case AMK_None:
+ continue;
- if (mergeDeclAttribute(New, *i))
+ case AMK_Redeclaration:
+ break;
+
+ case AMK_Override:
+ Override = true;
+ break;
+ }
+ }
+
+ if (mergeDeclAttribute(*this, New, *i, Override))
foundAny = true;
}
+ if (mergeAlignedAttrs(*this, New, Old))
+ foundAny = true;
+
if (!foundAny) New->dropAttrs();
}
@@ -1884,7 +2148,25 @@ void Sema::mergeDeclAttributes(Decl *New, Decl *Old,
/// to the new one.
static void mergeParamDeclAttributes(ParmVarDecl *newDecl,
const ParmVarDecl *oldDecl,
- ASTContext &C) {
+ Sema &S) {
+ // C++11 [dcl.attr.depend]p2:
+ // The first declaration of a function shall specify the
+ // carries_dependency attribute for its declarator-id if any declaration
+ // of the function specifies the carries_dependency attribute.
+ if (newDecl->hasAttr<CarriesDependencyAttr>() &&
+ !oldDecl->hasAttr<CarriesDependencyAttr>()) {
+ S.Diag(newDecl->getAttr<CarriesDependencyAttr>()->getLocation(),
+ diag::err_carries_dependency_missing_on_first_decl) << 1/*Param*/;
+ // Find the first declaration of the parameter.
+ // FIXME: Should we build redeclaration chains for function parameters?
+ const FunctionDecl *FirstFD =
+ cast<FunctionDecl>(oldDecl->getDeclContext())->getFirstDeclaration();
+ const ParmVarDecl *FirstVD =
+ FirstFD->getParamDecl(oldDecl->getFunctionScopeIndex());
+ S.Diag(FirstVD->getLocation(),
+ diag::note_carries_dependency_missing_first_decl) << 1/*Param*/;
+ }
+
if (!oldDecl->hasAttrs())
return;
@@ -1898,7 +2180,8 @@ static void mergeParamDeclAttributes(ParmVarDecl *newDecl,
i = oldDecl->specific_attr_begin<InheritableParamAttr>(),
e = oldDecl->specific_attr_end<InheritableParamAttr>(); i != e; ++i) {
if (!DeclHasAttr(newDecl, *i)) {
- InheritableAttr *newAttr = cast<InheritableParamAttr>((*i)->clone(C));
+ InheritableAttr *newAttr =
+ cast<InheritableParamAttr>((*i)->clone(S.Context));
newAttr->setInherited(true);
newDecl->addAttr(newAttr);
foundAny = true;
@@ -1966,6 +2249,22 @@ static bool isABIDefaultCC(Sema &S, CallingConv CC, FunctionDecl *D) {
return ABIDefaultCC == CC;
}
+template <typename T>
+static bool haveIncompatibleLanguageLinkages(const T *Old, const T *New) {
+ const DeclContext *DC = Old->getDeclContext();
+ if (DC->isRecord())
+ return false;
+
+ LanguageLinkage OldLinkage = Old->getLanguageLinkage();
+ if (OldLinkage == CXXLanguageLinkage &&
+ New->getDeclContext()->isExternCContext())
+ return true;
+ if (OldLinkage == CLanguageLinkage &&
+ New->getDeclContext()->isExternCXXContext())
+ return true;
+ return false;
+}
+
/// 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,
@@ -1987,6 +2286,15 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
Old = dyn_cast<FunctionDecl>(OldD);
if (!Old) {
if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(OldD)) {
+ if (New->getFriendObjectKind()) {
+ Diag(New->getLocation(), diag::err_using_decl_friend);
+ Diag(Shadow->getTargetDecl()->getLocation(),
+ diag::note_using_decl_target);
+ Diag(Shadow->getUsingDecl()->getLocation(),
+ diag::note_using_decl) << 0;
+ return true;
+ }
+
Diag(New->getLocation(), diag::err_using_decl_conflict_reverse);
Diag(Shadow->getTargetDecl()->getLocation(),
diag::note_using_decl_target);
@@ -2016,9 +2324,12 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
// Don't complain about this if we're in GNU89 mode and the old function
// is an extern inline function.
+ // Don't complain about specializations. They are not supposed to have
+ // storage classes.
if (!isa<CXXMethodDecl>(New) && !isa<CXXMethodDecl>(Old) &&
New->getStorageClass() == SC_Static &&
- Old->getStorageClass() != SC_Static &&
+ isExternalLinkage(Old->getLinkage()) &&
+ !New->getTemplateSpecializationInfo() &&
!canRedefineFunction(Old, getLangOpts())) {
if (getLangOpts().MicrosoftExt) {
Diag(New->getLocation(), diag::warn_static_non_static) << New;
@@ -2060,9 +2371,10 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
RequiresAdjustment = true;
// Don't complain about mismatches when the default CC is
- // effectively the same as the explict one.
+ // effectively the same as the explict one. Only Old decl contains correct
+ // information about storage class of CXXMethod.
} else if (OldTypeInfo.getCC() == CC_Default &&
- isABIDefaultCC(*this, NewTypeInfo.getCC(), New)) {
+ isABIDefaultCC(*this, NewTypeInfo.getCC(), Old)) {
NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC());
RequiresAdjustment = true;
@@ -2116,6 +2428,23 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
New->setType(QualType(NewType, 0));
NewQType = Context.getCanonicalType(New->getType());
}
+
+ // If this redeclaration makes the function inline, we may need to add it to
+ // UndefinedButUsed.
+ if (!Old->isInlined() && New->isInlined() &&
+ !New->hasAttr<GNUInlineAttr>() &&
+ (getLangOpts().CPlusPlus || !getLangOpts().GNUInline) &&
+ Old->isUsed(false) &&
+ !Old->isDefined() && !New->isThisDeclarationADefinition())
+ UndefinedButUsed.insert(std::make_pair(Old->getCanonicalDecl(),
+ SourceLocation()));
+
+ // If this redeclaration makes it newly gnu_inline, we don't want to warn
+ // about it.
+ if (New->hasAttr<GNUInlineAttr>() &&
+ Old->isInlined() && !Old->hasAttr<GNUInlineAttr>()) {
+ UndefinedButUsed.erase(Old->getCanonicalDecl());
+ }
if (getLangOpts().CPlusPlus) {
// (C++98 13.1p2):
@@ -2211,6 +2540,30 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
}
}
+ // C++11 [dcl.attr.noreturn]p1:
+ // The first declaration of a function shall specify the noreturn
+ // attribute if any declaration of that function specifies the noreturn
+ // attribute.
+ if (New->hasAttr<CXX11NoReturnAttr>() &&
+ !Old->hasAttr<CXX11NoReturnAttr>()) {
+ Diag(New->getAttr<CXX11NoReturnAttr>()->getLocation(),
+ diag::err_noreturn_missing_on_first_decl);
+ Diag(Old->getFirstDeclaration()->getLocation(),
+ diag::note_noreturn_missing_first_decl);
+ }
+
+ // C++11 [dcl.attr.depend]p2:
+ // The first declaration of a function shall specify the
+ // carries_dependency attribute for its declarator-id if any declaration
+ // of the function specifies the carries_dependency attribute.
+ if (New->hasAttr<CarriesDependencyAttr>() &&
+ !Old->hasAttr<CarriesDependencyAttr>()) {
+ Diag(New->getAttr<CarriesDependencyAttr>()->getLocation(),
+ diag::err_carries_dependency_missing_on_first_decl) << 0/*Function*/;
+ Diag(Old->getFirstDeclaration()->getLocation(),
+ diag::note_carries_dependency_missing_first_decl) << 0/*Function*/;
+ }
+
// (C++98 8.3.5p3):
// All declarations for a function shall agree exactly in both the
// return type and the parameter-type-list.
@@ -2226,6 +2579,12 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
assert(OldQTypeForComparison.isCanonical());
}
+ if (haveIncompatibleLanguageLinkages(Old, New)) {
+ Diag(New->getLocation(), diag::err_different_language_linkage) << New;
+ Diag(Old->getLocation(), PrevDiag);
+ return true;
+ }
+
if (OldQTypeForComparison == NewQType)
return MergeCompatibleFunctionDecls(New, Old, S);
@@ -2247,7 +2606,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
SmallVector<QualType, 16> ParamTypes(OldProto->arg_type_begin(),
OldProto->arg_type_end());
NewQType = Context.getFunctionType(NewFuncType->getResultType(),
- ParamTypes.data(), ParamTypes.size(),
+ ParamTypes,
OldProto->getExtProtoInfo());
New->setType(NewQType);
New->setHasInheritedPrototype();
@@ -2262,7 +2621,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
SourceLocation(),
SourceLocation(), 0,
*ParamType, /*TInfo=*/0,
- SC_None, SC_None,
+ SC_None,
0);
Param->setScopeInfo(0, Params.size());
Param->setImplicit();
@@ -2330,8 +2689,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) {
diag::note_previous_declaration);
}
- New->setType(Context.getFunctionType(MergedReturn, &ArgTypes[0],
- ArgTypes.size(),
+ New->setType(Context.getFunctionType(MergedReturn, ArgTypes,
OldProto->getExtProtoInfo()));
return MergeCompatibleFunctionDecls(New, Old, S);
}
@@ -2379,25 +2737,30 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old,
// Merge the attributes
mergeDeclAttributes(New, Old);
- // Merge the storage class.
- if (Old->getStorageClass() != SC_Extern &&
- Old->getStorageClass() != SC_None)
- New->setStorageClass(Old->getStorageClass());
-
// Merge "pure" flag.
if (Old->isPure())
New->setPure();
+ // Merge "used" flag.
+ if (Old->isUsed(false))
+ New->setUsed();
+
// Merge attributes from the parameters. These can mismatch with K&R
// declarations.
if (New->getNumParams() == Old->getNumParams())
for (unsigned i = 0, e = New->getNumParams(); i != e; ++i)
mergeParamDeclAttributes(New->getParamDecl(i), Old->getParamDecl(i),
- Context);
+ *this);
if (getLangOpts().CPlusPlus)
return MergeCXXFunctionDecl(New, Old, S);
+ // Merge the function types so the we get the composite types for the return
+ // and argument types.
+ QualType Merged = Context.mergeTypes(Old->getType(), New->getType());
+ if (!Merged.isNull())
+ New->setType(Merged);
+
return false;
}
@@ -2406,7 +2769,7 @@ void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod,
ObjCMethodDecl *oldMethod) {
// Merge the attributes, including deprecated/unavailable
- mergeDeclAttributes(newMethod, oldMethod, /* mergeDeprecation */true);
+ mergeDeclAttributes(newMethod, oldMethod, AMK_Override);
// Merge attributes from the parameters.
ObjCMethodDecl::param_const_iterator oi = oldMethod->param_begin(),
@@ -2414,9 +2777,9 @@ void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod,
for (ObjCMethodDecl::param_iterator
ni = newMethod->param_begin(), ne = newMethod->param_end();
ni != ne && oi != oe; ++ni, ++oi)
- mergeParamDeclAttributes(*ni, *oi, Context);
+ mergeParamDeclAttributes(*ni, *oi, *this);
- CheckObjCMethodOverride(newMethod, oldMethod, true);
+ CheckObjCMethodOverride(newMethod, oldMethod);
}
/// MergeVarDeclTypes - We parsed a variable 'New' which has the same name and
@@ -2426,7 +2789,7 @@ void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod,
/// Declarations using the auto type specifier (C++ [decl.spec.auto]) call back
/// to here in AddInitializerToDecl. We can't check them before the initializer
/// is attached.
-void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old) {
+void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool OldWasHidden) {
if (New->isInvalidDecl() || Old->isInvalidDecl())
return;
@@ -2447,19 +2810,17 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old) {
// absence of a major array bound (8.3.4).
else if (Old->getType()->isIncompleteArrayType() &&
New->getType()->isArrayType()) {
- CanQual<ArrayType> OldArray
- = Context.getCanonicalType(Old->getType())->getAs<ArrayType>();
- CanQual<ArrayType> NewArray
- = Context.getCanonicalType(New->getType())->getAs<ArrayType>();
- if (OldArray->getElementType() == NewArray->getElementType())
+ const ArrayType *OldArray = Context.getAsArrayType(Old->getType());
+ const ArrayType *NewArray = Context.getAsArrayType(New->getType());
+ if (Context.hasSameType(OldArray->getElementType(),
+ NewArray->getElementType()))
MergedT = New->getType();
} else if (Old->getType()->isArrayType() &&
New->getType()->isIncompleteArrayType()) {
- CanQual<ArrayType> OldArray
- = Context.getCanonicalType(Old->getType())->getAs<ArrayType>();
- CanQual<ArrayType> NewArray
- = Context.getCanonicalType(New->getType())->getAs<ArrayType>();
- if (OldArray->getElementType() == NewArray->getElementType())
+ const ArrayType *OldArray = Context.getAsArrayType(Old->getType());
+ const ArrayType *NewArray = Context.getAsArrayType(New->getType());
+ if (Context.hasSameType(OldArray->getElementType(),
+ NewArray->getElementType()))
MergedT = Old->getType();
} else if (New->getType()->isObjCObjectPointerType()
&& Old->getType()->isObjCObjectPointerType()) {
@@ -2475,7 +2836,11 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old) {
Diag(Old->getLocation(), diag::note_previous_definition);
return New->setInvalidDecl();
}
- New->setType(MergedT);
+
+ // Don't actually update the type on the new declaration if the old
+ // declaration was a extern declaration in a different scope.
+ if (!OldWasHidden)
+ New->setType(MergedT);
}
/// MergeVarDecl - We just parsed a variable 'New' which has the same name
@@ -2486,7 +2851,8 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old) {
/// FinalizeDeclaratorGroup. Unfortunately, we can't analyze tentative
/// definitions here, since the initializer hasn't been attached.
///
-void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
+void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous,
+ bool PreviousWasHidden) {
// If the new decl is already invalid, don't do any other checking.
if (New->isInvalidDecl())
return;
@@ -2526,13 +2892,14 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
}
// Merge the types.
- MergeVarDeclTypes(New, Old);
+ MergeVarDeclTypes(New, Old, PreviousWasHidden);
if (New->isInvalidDecl())
return;
- // C99 6.2.2p4: Check if we have a static decl followed by a non-static.
+ // [dcl.stc]p8: Check if we have a non-static decl followed by a static.
if (New->getStorageClass() == SC_Static &&
- (Old->getStorageClass() == SC_None || Old->hasExternalStorage())) {
+ !New->isStaticDataMember() &&
+ isExternalLinkage(Old->getLinkage())) {
Diag(New->getLocation(), diag::err_static_non_static) << New->getDeclName();
Diag(Old->getLocation(), diag::note_previous_definition);
return New->setInvalidDecl();
@@ -2548,8 +2915,9 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
// identifier has external linkage.
if (New->hasExternalStorage() && Old->hasLinkage())
/* Okay */;
- else if (New->getStorageClass() != SC_Static &&
- Old->getStorageClass() == SC_Static) {
+ else if (New->getCanonicalDecl()->getStorageClass() != SC_Static &&
+ !New->isStaticDataMember() &&
+ Old->getCanonicalDecl()->getStorageClass() == SC_Static) {
Diag(New->getLocation(), diag::err_non_static_static) << New->getDeclName();
Diag(Old->getLocation(), diag::note_previous_definition);
return New->setInvalidDecl();
@@ -2562,8 +2930,8 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
Diag(Old->getLocation(), diag::note_previous_definition);
return New->setInvalidDecl();
}
- if (Old->hasExternalStorage() &&
- !New->hasLinkage() && New->isLocalVarDecl()) {
+ if (Old->hasLinkage() && New->isLocalVarDecl() &&
+ !New->hasExternalStorage()) {
Diag(New->getLocation(), diag::err_non_extern_extern) << New->getDeclName();
Diag(Old->getLocation(), diag::note_previous_definition);
return New->setInvalidDecl();
@@ -2601,17 +2969,17 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
New->setInvalidDecl();
return;
}
- // c99 6.2.2 P4.
- // For an identifier declared with the storage-class specifier extern in a
- // scope in which a prior declaration of that identifier is visible, if
- // the prior declaration specifies internal or external linkage, the linkage
- // of the identifier at the later declaration is the same as the linkage
- // specified at the prior declaration.
- // FIXME. revisit this code.
- if (New->hasExternalStorage() &&
- Old->getLinkage() == InternalLinkage &&
- New->getDeclContext() == Old->getDeclContext())
- New->setStorageClass(Old->getStorageClass());
+
+ if (haveIncompatibleLanguageLinkages(Old, New)) {
+ Diag(New->getLocation(), diag::err_different_language_linkage) << New;
+ Diag(Old->getLocation(), diag::note_previous_definition);
+ New->setInvalidDecl();
+ return;
+ }
+
+ // Merge "used" flag.
+ if (Old->isUsed(false))
+ New->setUsed();
// Keep a chain of previous declarations.
New->setPreviousDeclaration(Old);
@@ -2628,11 +2996,12 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
}
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
-/// no declarator (e.g. "struct foo;") is parsed. It also accopts template
+/// no declarator (e.g. "struct foo;") is parsed. It also accepts template
/// parameters to cope with template friend declarations.
Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
DeclSpec &DS,
- MultiTemplateParamsArg TemplateParams) {
+ MultiTemplateParamsArg TemplateParams,
+ bool IsExplicitInstantiation) {
Decl *TagD = 0;
TagDecl *Tag = 0;
if (DS.getTypeSpecType() == DeclSpec::TST_class ||
@@ -2655,6 +3024,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
}
if (Tag) {
+ getASTContext().addUnnamedTag(Tag);
Tag->setFreeStanding();
if (Tag->isInvalidDecl())
return Tag;
@@ -2684,6 +3054,8 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
return TagD;
}
+ DiagnoseFunctionSpecifiers(DS);
+
if (DS.isFriendSpecified()) {
// If we're dealing with a decl but not a TagDecl, assume that
// whatever routines created it handled the friendship aspect.
@@ -2692,10 +3064,28 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
return ActOnFriendTypeDecl(S, DS, TemplateParams);
}
- // Track whether we warned about the fact that there aren't any
- // declarators.
- bool emittedWarning = false;
-
+ CXXScopeSpec &SS = DS.getTypeSpecScope();
+ bool IsExplicitSpecialization =
+ !TemplateParams.empty() && TemplateParams.back()->size() == 0;
+ if (Tag && SS.isNotEmpty() && !Tag->isCompleteDefinition() &&
+ !IsExplicitInstantiation && !IsExplicitSpecialization) {
+ // Per C++ [dcl.type.elab]p1, a class declaration cannot have a
+ // nested-name-specifier unless it is an explicit instantiation
+ // or an explicit specialization.
+ // Per C++ [dcl.enum]p1, an opaque-enum-declaration can't either.
+ Diag(SS.getBeginLoc(), diag::err_standalone_class_nested_name_specifier)
+ << (DS.getTypeSpecType() == DeclSpec::TST_class ? 0 :
+ DS.getTypeSpecType() == DeclSpec::TST_struct ? 1 :
+ DS.getTypeSpecType() == DeclSpec::TST_interface ? 2 :
+ DS.getTypeSpecType() == DeclSpec::TST_union ? 3 : 4)
+ << SS.getRange();
+ return 0;
+ }
+
+ // Track whether this decl-specifier declares anything.
+ bool DeclaresAnything = true;
+
+ // Handle anonymous struct definitions.
if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag)) {
if (!Record->getDeclName() && Record->isCompleteDefinition() &&
DS.getStorageClassSpec() != DeclSpec::SCS_typedef) {
@@ -2703,13 +3093,11 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
Record->getDeclContext()->isRecord())
return BuildAnonymousStructOrUnion(S, DS, AS, Record);
- Diag(DS.getLocStart(), diag::ext_no_declarators)
- << DS.getSourceRange();
- emittedWarning = true;
+ DeclaresAnything = false;
}
}
- // Check for Microsoft C extension: anonymous struct.
+ // Check for Microsoft C extension: anonymous struct member.
if (getLangOpts().MicrosoftExt && !getLangOpts().CPlusPlus &&
CurContext->isRecord() &&
DS.getStorageClassSpec() == DeclSpec::SCS_unspecified) {
@@ -2726,70 +3114,82 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
return BuildMicrosoftCAnonymousStruct(S, DS, Record);
}
}
-
- if (getLangOpts().CPlusPlus &&
+
+ // Skip all the checks below if we have a type error.
+ if (DS.getTypeSpecType() == DeclSpec::TST_error ||
+ (TagD && TagD->isInvalidDecl()))
+ return TagD;
+
+ if (getLangOpts().CPlusPlus &&
DS.getStorageClassSpec() != DeclSpec::SCS_typedef)
if (EnumDecl *Enum = dyn_cast_or_null<EnumDecl>(Tag))
if (Enum->enumerator_begin() == Enum->enumerator_end() &&
- !Enum->getIdentifier() && !Enum->isInvalidDecl()) {
- Diag(Enum->getLocation(), diag::ext_no_declarators)
- << DS.getSourceRange();
- emittedWarning = true;
- }
+ !Enum->getIdentifier() && !Enum->isInvalidDecl())
+ DeclaresAnything = false;
- // Skip all the checks below if we have a type error.
- if (DS.getTypeSpecType() == DeclSpec::TST_error) return TagD;
-
if (!DS.isMissingDeclaratorOk()) {
- // Warn about typedefs of enums without names, since this is an
- // extension in both Microsoft and GNU.
- if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef &&
- Tag && isa<EnumDecl>(Tag)) {
+ // Customize diagnostic for a typedef missing a name.
+ if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef)
Diag(DS.getLocStart(), diag::ext_typedef_without_a_name)
<< DS.getSourceRange();
- return Tag;
- }
-
- Diag(DS.getLocStart(), diag::ext_no_declarators)
- << DS.getSourceRange();
- emittedWarning = true;
+ else
+ DeclaresAnything = false;
}
- // We're going to complain about a bunch of spurious specifiers;
- // only do this if we're declaring a tag, because otherwise we
- // should be getting diag::ext_no_declarators.
- if (emittedWarning || (TagD && TagD->isInvalidDecl()))
+ if (DS.isModulePrivateSpecified() &&
+ Tag && Tag->getDeclContext()->isFunctionOrMethod())
+ Diag(DS.getModulePrivateSpecLoc(), diag::err_module_private_local_class)
+ << Tag->getTagKind()
+ << FixItHint::CreateRemoval(DS.getModulePrivateSpecLoc());
+
+ ActOnDocumentableDecl(TagD);
+
+ // C 6.7/2:
+ // A declaration [...] shall declare at least a declarator [...], a tag,
+ // or the members of an enumeration.
+ // C++ [dcl.dcl]p3:
+ // [If there are no declarators], and except for the declaration of an
+ // unnamed bit-field, the decl-specifier-seq shall introduce one or more
+ // names into the program, or shall redeclare a name introduced by a
+ // previous declaration.
+ if (!DeclaresAnything) {
+ // In C, we allow this as a (popular) extension / bug. Don't bother
+ // producing further diagnostics for redundant qualifiers after this.
+ Diag(DS.getLocStart(), diag::ext_no_declarators) << DS.getSourceRange();
return TagD;
+ }
+
+ // C++ [dcl.stc]p1:
+ // If a storage-class-specifier appears in a decl-specifier-seq, [...] the
+ // init-declarator-list of the declaration shall not be empty.
+ // C++ [dcl.fct.spec]p1:
+ // If a cv-qualifier appears in a decl-specifier-seq, the
+ // init-declarator-list of the declaration shall not be empty.
+ //
+ // Spurious qualifiers here appear to be valid in C.
+ unsigned DiagID = diag::warn_standalone_specifier;
+ if (getLangOpts().CPlusPlus)
+ DiagID = diag::ext_standalone_specifier;
// Note that a linkage-specification sets a storage class, but
// 'extern "C" struct foo;' is actually valid and not theoretically
// useless.
- if (DeclSpec::SCS scs = DS.getStorageClassSpec())
- if (!DS.isExternInLinkageSpec())
- Diag(DS.getStorageClassSpecLoc(), diag::warn_standalone_specifier)
- << DeclSpec::getSpecifierName(scs);
+ if (DeclSpec::SCS SCS = DS.getStorageClassSpec())
+ if (!DS.isExternInLinkageSpec() && SCS != DeclSpec::SCS_typedef)
+ Diag(DS.getStorageClassSpecLoc(), DiagID)
+ << DeclSpec::getSpecifierName(SCS);
if (DS.isThreadSpecified())
- Diag(DS.getThreadSpecLoc(), diag::warn_standalone_specifier) << "__thread";
+ Diag(DS.getThreadSpecLoc(), DiagID) << "__thread";
if (DS.getTypeQualifiers()) {
if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
- Diag(DS.getConstSpecLoc(), diag::warn_standalone_specifier) << "const";
+ Diag(DS.getConstSpecLoc(), DiagID) << "const";
if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile)
- Diag(DS.getConstSpecLoc(), diag::warn_standalone_specifier) << "volatile";
+ Diag(DS.getConstSpecLoc(), DiagID) << "volatile";
// Restrict is covered above.
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic)
+ Diag(DS.getAtomicSpecLoc(), DiagID) << "_Atomic";
}
- if (DS.isInlineSpecified())
- Diag(DS.getInlineSpecLoc(), diag::warn_standalone_specifier) << "inline";
- if (DS.isVirtualSpecified())
- Diag(DS.getVirtualSpecLoc(), diag::warn_standalone_specifier) << "virtual";
- if (DS.isExplicitSpecified())
- Diag(DS.getExplicitSpecLoc(), diag::warn_standalone_specifier) <<"explicit";
-
- if (DS.isModulePrivateSpecified() &&
- Tag && Tag->getDeclContext()->isFunctionOrMethod())
- Diag(DS.getModulePrivateSpecLoc(), diag::err_module_private_local_class)
- << Tag->getTagKind()
- << FixItHint::CreateRemoval(DS.getModulePrivateSpecLoc());
// Warn about ignored type attributes, for example:
// __attribute__((aligned)) struct A;
@@ -2814,8 +3214,6 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
}
}
- ActOnDocumentableDecl(TagD);
-
return TagD;
}
@@ -2950,25 +3348,6 @@ StorageClassSpecToVarDeclStorageClass(DeclSpec::SCS StorageClassSpec) {
llvm_unreachable("unknown storage class specifier");
}
-/// StorageClassSpecToFunctionDeclStorageClass - Maps a DeclSpec::SCS to
-/// a StorageClass. Any error reporting is up to the caller:
-/// illegal input values are mapped to SC_None.
-static StorageClass
-StorageClassSpecToFunctionDeclStorageClass(DeclSpec::SCS StorageClassSpec) {
- switch (StorageClassSpec) {
- case DeclSpec::SCS_unspecified: return SC_None;
- case DeclSpec::SCS_extern: return SC_Extern;
- case DeclSpec::SCS_static: return SC_Static;
- case DeclSpec::SCS_private_extern: return SC_PrivateExtern;
- // Illegal SCSs map to None: error reporting is up to the caller.
- case DeclSpec::SCS_auto: // Fall through.
- case DeclSpec::SCS_mutable: // Fall through.
- case DeclSpec::SCS_register: // Fall through.
- case DeclSpec::SCS_typedef: return SC_None;
- }
- llvm_unreachable("unknown storage class specifier");
-}
-
/// BuildAnonymousStructOrUnion - Handle the declaration of an
/// anonymous structure or union. Anonymous unions are a C++ feature
/// (C++ [class.union]) and a C11 feature; anonymous structures
@@ -3027,18 +3406,23 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
if (DS.getTypeQualifiers()) {
if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
Diag(DS.getConstSpecLoc(), diag::ext_anonymous_struct_union_qualified)
- << Record->isUnion() << 0
+ << Record->isUnion() << "const"
<< FixItHint::CreateRemoval(DS.getConstSpecLoc());
if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile)
- Diag(DS.getVolatileSpecLoc(),
+ Diag(DS.getVolatileSpecLoc(),
diag::ext_anonymous_struct_union_qualified)
- << Record->isUnion() << 1
+ << Record->isUnion() << "volatile"
<< FixItHint::CreateRemoval(DS.getVolatileSpecLoc());
if (DS.getTypeQualifiers() & DeclSpec::TQ_restrict)
- Diag(DS.getRestrictSpecLoc(),
+ Diag(DS.getRestrictSpecLoc(),
diag::ext_anonymous_struct_union_qualified)
- << Record->isUnion() << 2
+ << Record->isUnion() << "restrict"
<< FixItHint::CreateRemoval(DS.getRestrictSpecLoc());
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic)
+ Diag(DS.getAtomicSpecLoc(),
+ diag::ext_anonymous_struct_union_qualified)
+ << Record->isUnion() << "_Atomic"
+ << FixItHint::CreateRemoval(DS.getAtomicSpecLoc());
DS.ClearTypeQualifiers();
}
@@ -3088,6 +3472,13 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
<< (int)Record->isUnion();
Invalid = true;
}
+ } else {
+ // This is an anonymous type definition within another anonymous type.
+ // This is a popular extension, provided by Plan9, MSVC and GCC, but
+ // not part of standard C++.
+ Diag(MemRecord->getLocation(),
+ diag::ext_anonymous_record_with_anonymous_type)
+ << (int)Record->isUnion();
}
} else if (isa<AccessSpecDecl>(*Mem)) {
// Any access specifier is fine.
@@ -3153,15 +3544,12 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
Invalid = true;
SC = SC_None;
}
- SCSpec = DS.getStorageClassSpecAsWritten();
- VarDecl::StorageClass SCAsWritten
- = StorageClassSpecToVarDeclStorageClass(SCSpec);
Anon = VarDecl::Create(Context, Owner,
DS.getLocStart(),
Record->getLocation(), /*IdentifierInfo=*/0,
Context.getTypeDeclType(Record),
- TInfo, SC, SCAsWritten);
+ TInfo, SC);
// Default-initialize the implicit variable. This initialization will be
// trivial in almost all cases, except if a union member has an in-class
@@ -3383,7 +3771,7 @@ static QualType getCoreType(QualType Ty) {
static bool hasSimilarParameters(ASTContext &Context,
FunctionDecl *Declaration,
FunctionDecl *Definition,
- llvm::SmallVectorImpl<unsigned> &Params) {
+ SmallVectorImpl<unsigned> &Params) {
Params.clear();
if (Declaration->param_size() != Definition->param_size())
return false;
@@ -3609,8 +3997,8 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC,
return false;
}
-Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
- MultiTemplateParamsArg TemplateParamLists) {
+NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
+ MultiTemplateParamsArg TemplateParamLists) {
// TODO: consider using NameInfo for diagnostic.
DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
DeclarationName Name = NameInfo.getName();
@@ -3690,8 +4078,6 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef)
return 0;
- NamedDecl *New;
-
TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
QualType R = TInfo->getType();
@@ -3776,6 +4162,13 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef)
Previous.clear();
+ // Check that there are no default arguments other than in the parameters
+ // of a function declaration (C++ only).
+ if (getLangOpts().CPlusPlus)
+ CheckExtraCXXDefaultArguments(D);
+
+ NamedDecl *New;
+
bool AddToScope = true;
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
if (TemplateParamLists.size()) {
@@ -3877,29 +4270,29 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T,
static void
FixInvalidVariablyModifiedTypeLoc(TypeLoc SrcTL, TypeLoc DstTL) {
- if (PointerTypeLoc* SrcPTL = dyn_cast<PointerTypeLoc>(&SrcTL)) {
- PointerTypeLoc* DstPTL = cast<PointerTypeLoc>(&DstTL);
- FixInvalidVariablyModifiedTypeLoc(SrcPTL->getPointeeLoc(),
- DstPTL->getPointeeLoc());
- DstPTL->setStarLoc(SrcPTL->getStarLoc());
+ if (PointerTypeLoc SrcPTL = SrcTL.getAs<PointerTypeLoc>()) {
+ PointerTypeLoc DstPTL = DstTL.castAs<PointerTypeLoc>();
+ FixInvalidVariablyModifiedTypeLoc(SrcPTL.getPointeeLoc(),
+ DstPTL.getPointeeLoc());
+ DstPTL.setStarLoc(SrcPTL.getStarLoc());
return;
}
- if (ParenTypeLoc* SrcPTL = dyn_cast<ParenTypeLoc>(&SrcTL)) {
- ParenTypeLoc* DstPTL = cast<ParenTypeLoc>(&DstTL);
- FixInvalidVariablyModifiedTypeLoc(SrcPTL->getInnerLoc(),
- DstPTL->getInnerLoc());
- DstPTL->setLParenLoc(SrcPTL->getLParenLoc());
- DstPTL->setRParenLoc(SrcPTL->getRParenLoc());
+ if (ParenTypeLoc SrcPTL = SrcTL.getAs<ParenTypeLoc>()) {
+ ParenTypeLoc DstPTL = DstTL.castAs<ParenTypeLoc>();
+ FixInvalidVariablyModifiedTypeLoc(SrcPTL.getInnerLoc(),
+ DstPTL.getInnerLoc());
+ DstPTL.setLParenLoc(SrcPTL.getLParenLoc());
+ DstPTL.setRParenLoc(SrcPTL.getRParenLoc());
return;
}
- ArrayTypeLoc* SrcATL = cast<ArrayTypeLoc>(&SrcTL);
- ArrayTypeLoc* DstATL = cast<ArrayTypeLoc>(&DstTL);
- TypeLoc SrcElemTL = SrcATL->getElementLoc();
- TypeLoc DstElemTL = DstATL->getElementLoc();
+ ArrayTypeLoc SrcATL = SrcTL.castAs<ArrayTypeLoc>();
+ ArrayTypeLoc DstATL = DstTL.castAs<ArrayTypeLoc>();
+ TypeLoc SrcElemTL = SrcATL.getElementLoc();
+ TypeLoc DstElemTL = DstATL.getElementLoc();
DstElemTL.initializeFullCopy(SrcElemTL);
- DstATL->setLBracketLoc(SrcATL->getLBracketLoc());
- DstATL->setSizeExpr(SrcATL->getSizeExpr());
- DstATL->setRBracketLoc(SrcATL->getRBracketLoc());
+ DstATL.setLBracketLoc(SrcATL.getLBracketLoc());
+ DstATL.setSizeExpr(SrcATL.getSizeExpr());
+ DstATL.setRBracketLoc(SrcATL.getRBracketLoc());
}
/// Helper method to turn variable array types into constant array
@@ -3921,7 +4314,7 @@ TryToFixInvalidVariablyModifiedTypeSourceInfo(TypeSourceInfo *TInfo,
return FixedTInfo;
}
-/// \brief Register the given locally-scoped external C declaration so
+/// \brief Register the given locally-scoped extern "C" declaration so
/// that it can be found later for redeclarations
void
Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND,
@@ -3930,15 +4323,15 @@ Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND,
assert(ND->getLexicalDeclContext()->isFunctionOrMethod() &&
"Decl is not a locally-scoped decl!");
// Note that we have a locally-scoped external with this name.
- LocallyScopedExternalDecls[ND->getDeclName()] = ND;
+ LocallyScopedExternCDecls[ND->getDeclName()] = ND;
if (!Previous.isSingleResult())
return;
NamedDecl *PrevDecl = Previous.getFoundDecl();
- // If there was a previous declaration of this variable, it may be
- // in our identifier chain. Update the identifier chain with the new
+ // If there was a previous declaration of this entity, it may be in
+ // our identifier chain. Update the identifier chain with the new
// declaration.
if (S && IdResolver.ReplaceDecl(PrevDecl, ND)) {
// The previous declaration was found on the identifer resolver
@@ -3962,38 +4355,42 @@ Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND,
}
llvm::DenseMap<DeclarationName, NamedDecl *>::iterator
-Sema::findLocallyScopedExternalDecl(DeclarationName Name) {
+Sema::findLocallyScopedExternCDecl(DeclarationName Name) {
if (ExternalSource) {
// Load locally-scoped external decls from the external source.
SmallVector<NamedDecl *, 4> Decls;
- ExternalSource->ReadLocallyScopedExternalDecls(Decls);
+ ExternalSource->ReadLocallyScopedExternCDecls(Decls);
for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos
- = LocallyScopedExternalDecls.find(Decls[I]->getDeclName());
- if (Pos == LocallyScopedExternalDecls.end())
- LocallyScopedExternalDecls[Decls[I]->getDeclName()] = Decls[I];
+ = LocallyScopedExternCDecls.find(Decls[I]->getDeclName());
+ if (Pos == LocallyScopedExternCDecls.end())
+ LocallyScopedExternCDecls[Decls[I]->getDeclName()] = Decls[I];
}
}
- return LocallyScopedExternalDecls.find(Name);
+ return LocallyScopedExternCDecls.find(Name);
}
/// \brief Diagnose function specifiers on a declaration of an identifier that
/// does not identify a function.
-void Sema::DiagnoseFunctionSpecifiers(Declarator& D) {
+void Sema::DiagnoseFunctionSpecifiers(const DeclSpec &DS) {
// FIXME: We should probably indicate the identifier in question to avoid
// confusion for constructs like "inline int a(), b;"
- if (D.getDeclSpec().isInlineSpecified())
- Diag(D.getDeclSpec().getInlineSpecLoc(),
+ if (DS.isInlineSpecified())
+ Diag(DS.getInlineSpecLoc(),
diag::err_inline_non_function);
- if (D.getDeclSpec().isVirtualSpecified())
- Diag(D.getDeclSpec().getVirtualSpecLoc(),
+ if (DS.isVirtualSpecified())
+ Diag(DS.getVirtualSpecLoc(),
diag::err_virtual_non_function);
- if (D.getDeclSpec().isExplicitSpecified())
- Diag(D.getDeclSpec().getExplicitSpecLoc(),
+ if (DS.isExplicitSpecified())
+ Diag(DS.getExplicitSpecLoc(),
diag::err_explicit_non_function);
+
+ if (DS.isNoreturnSpecified())
+ Diag(DS.getNoreturnSpecLoc(),
+ diag::err_noreturn_non_function);
}
NamedDecl*
@@ -4009,12 +4406,7 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
Previous.clear();
}
- if (getLangOpts().CPlusPlus) {
- // Check that there are no default arguments (C++ only).
- CheckExtraCXXDefaultArguments(D);
- }
-
- DiagnoseFunctionSpecifiers(D);
+ DiagnoseFunctionSpecifiers(D.getDeclSpec());
if (D.getDeclSpec().isThreadSpecified())
Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
@@ -4090,6 +4482,7 @@ Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD,
// in an outer scope, it isn't the same thing.
FilterLookupForScope(Previous, DC, S, /*ConsiderLinkage*/ false,
/*ExplicitInstantiationOrSpecialization=*/false);
+ filterNonConflictingPreviousDecls(Context, NewTD, Previous);
if (!Previous.empty()) {
Redeclaration = true;
MergeTypedefNameDecl(NewTD, Previous);
@@ -4220,6 +4613,74 @@ bool Sema::inferObjCARCLifetime(ValueDecl *decl) {
return false;
}
+static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) {
+ // 'weak' only applies to declarations with external linkage.
+ if (WeakAttr *Attr = ND.getAttr<WeakAttr>()) {
+ if (ND.getLinkage() != ExternalLinkage) {
+ S.Diag(Attr->getLocation(), diag::err_attribute_weak_static);
+ ND.dropAttr<WeakAttr>();
+ }
+ }
+ if (WeakRefAttr *Attr = ND.getAttr<WeakRefAttr>()) {
+ if (ND.hasExternalLinkage()) {
+ S.Diag(Attr->getLocation(), diag::err_attribute_weakref_not_static);
+ ND.dropAttr<WeakRefAttr>();
+ }
+ }
+}
+
+/// Given that we are within the definition of the given function,
+/// will that definition behave like C99's 'inline', where the
+/// definition is discarded except for optimization purposes?
+static bool isFunctionDefinitionDiscarded(Sema &S, FunctionDecl *FD) {
+ // Try to avoid calling GetGVALinkageForFunction.
+
+ // All cases of this require the 'inline' keyword.
+ if (!FD->isInlined()) return false;
+
+ // This is only possible in C++ with the gnu_inline attribute.
+ if (S.getLangOpts().CPlusPlus && !FD->hasAttr<GNUInlineAttr>())
+ return false;
+
+ // Okay, go ahead and call the relatively-more-expensive function.
+
+#ifndef NDEBUG
+ // AST quite reasonably asserts that it's working on a function
+ // definition. We don't really have a way to tell it that we're
+ // currently defining the function, so just lie to it in +Asserts
+ // builds. This is an awful hack.
+ FD->setLazyBody(1);
+#endif
+
+ bool isC99Inline = (S.Context.GetGVALinkageForFunction(FD) == GVA_C99Inline);
+
+#ifndef NDEBUG
+ FD->setLazyBody(0);
+#endif
+
+ return isC99Inline;
+}
+
+static bool shouldConsiderLinkage(const VarDecl *VD) {
+ const DeclContext *DC = VD->getDeclContext()->getRedeclContext();
+ if (DC->isFunctionOrMethod())
+ return VD->hasExternalStorage();
+ if (DC->isFileContext())
+ return true;
+ if (DC->isRecord())
+ return false;
+ llvm_unreachable("Unexpected context");
+}
+
+static bool shouldConsiderLinkage(const FunctionDecl *FD) {
+ const DeclContext *DC = FD->getDeclContext()->getRedeclContext();
+ if (DC->isFileContext() || DC->isFunctionOrMethod())
+ return true;
+ if (DC->isRecord())
+ return false;
+ llvm_unreachable("Unexpected context");
+}
+
NamedDecl*
Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
TypeSourceInfo *TInfo, LookupResult &Previous,
@@ -4227,14 +4688,21 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
QualType R = TInfo->getType();
DeclarationName Name = GetNameForDeclarator(D).getName();
- // Check that there are no default arguments (C++ only).
- if (getLangOpts().CPlusPlus)
- CheckExtraCXXDefaultArguments(D);
-
DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec();
assert(SCSpec != DeclSpec::SCS_typedef &&
"Parser allowed 'typedef' as storage class VarDecl.");
VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec);
+
+ if (getLangOpts().OpenCL && !getOpenCLOptions().cl_khr_fp16)
+ {
+ // OpenCL v1.2 s6.1.1.1: reject declaring variables of the half and
+ // half array type (unless the cl_khr_fp16 extension is enabled).
+ if (Context.getBaseElementType(R)->isHalfType()) {
+ Diag(D.getIdentifierLoc(), diag::err_opencl_half_declaration) << R;
+ D.setInvalidType();
+ }
+ }
+
if (SCSpec == DeclSpec::SCS_mutable) {
// mutable can only appear on non-static class members, so it's always
// an error here
@@ -4242,9 +4710,6 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
D.setInvalidType();
SC = SC_None;
}
- SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten();
- VarDecl::StorageClass SCAsWritten
- = StorageClassSpecToVarDeclStorageClass(SCSpec);
IdentifierInfo *II = Name.getAsIdentifierInfo();
if (!II) {
@@ -4253,7 +4718,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
return 0;
}
- DiagnoseFunctionSpecifiers(D);
+ DiagnoseFunctionSpecifiers(D.getDeclSpec());
if (!DC->isRecord() && S->getFnParent() == 0) {
// C99 6.9p2: The storage-class specifiers auto and register shall not
@@ -4273,8 +4738,33 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (getLangOpts().OpenCL) {
// Set up the special work-group-local storage class for variables in the
// OpenCL __local address space.
- if (R.getAddressSpace() == LangAS::opencl_local)
+ if (R.getAddressSpace() == LangAS::opencl_local) {
SC = SC_OpenCLWorkGroupLocal;
+ }
+
+ // OpenCL v1.2 s6.9.b p4:
+ // The sampler type cannot be used with the __local and __global address
+ // space qualifiers.
+ if (R->isSamplerT() && (R.getAddressSpace() == LangAS::opencl_local ||
+ R.getAddressSpace() == LangAS::opencl_global)) {
+ Diag(D.getIdentifierLoc(), diag::err_wrong_sampler_addressspace);
+ }
+
+ // OpenCL 1.2 spec, p6.9 r:
+ // The event type cannot be used to declare a program scope variable.
+ // The event type cannot be used with the __local, __constant and __global
+ // address space qualifiers.
+ if (R->isEventT()) {
+ if (S->getParent() == 0) {
+ Diag(D.getLocStart(), diag::err_event_t_global_var);
+ D.setInvalidType();
+ }
+
+ if (R.getAddressSpace()) {
+ Diag(D.getLocStart(), diag::err_event_t_addr_space_qual);
+ D.setInvalidType();
+ }
+ }
}
bool isExplicitSpecialization = false;
@@ -4282,7 +4772,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (!getLangOpts().CPlusPlus) {
NewVD = VarDecl::Create(Context, DC, D.getLocStart(),
D.getIdentifierLoc(), II,
- R, TInfo, SC, SCAsWritten);
+ R, TInfo, SC);
if (D.isInvalidType())
NewVD->setInvalidDecl();
@@ -4293,8 +4783,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
Diag(D.getDeclSpec().getStorageClassSpecLoc(),
diag::err_static_out_of_line)
<< FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc());
- } else if (SC == SC_None)
- SC = SC_Static;
+ }
}
if (SC == SC_Static && CurContext->isRecord()) {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) {
@@ -4307,7 +4796,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// the program is ill-formed. C++11 drops this restriction.
if (RD->isUnion())
Diag(D.getIdentifierLoc(),
- getLangOpts().CPlusPlus0x
+ getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_static_data_member_in_union
: diag::ext_static_data_member_in_union) << Name;
// We conservatively disallow static data members in anonymous structs.
@@ -4352,7 +4841,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewVD = VarDecl::Create(Context, DC, D.getLocStart(),
D.getIdentifierLoc(), II,
- R, TInfo, SC, SCAsWritten);
+ R, TInfo, SC);
// If this decl has an auto type in need of deduction, make a note of the
// Decl so we can diagnose uses of it in its own initializer.
@@ -4388,6 +4877,25 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewVD->setThreadSpecified(true);
}
+ // C99 6.7.4p3
+ // An inline definition of a function with external linkage shall
+ // not contain a definition of a modifiable object with static or
+ // thread storage duration...
+ // We only apply this when the function is required to be defined
+ // elsewhere, i.e. when the function is not 'extern inline'. Note
+ // that a local variable with thread storage duration still has to
+ // be marked 'static'. Also note that it's possible to get these
+ // semantics in C++ using __attribute__((gnu_inline)).
+ if (SC == SC_Static && S->getFnParent() != 0 &&
+ !NewVD->getType().isConstQualified()) {
+ FunctionDecl *CurFD = getCurFunctionDecl();
+ if (CurFD && isFunctionDefinitionDiscarded(*this, CurFD)) {
+ Diag(D.getDeclSpec().getStorageClassSpecLoc(),
+ diag::warn_static_local_in_extern_inline);
+ MaybeSuggestAddingStaticToDecl(CurFD);
+ }
+ }
+
if (D.getDeclSpec().isModulePrivateSpecified()) {
if (isExplicitSpecialization)
Diag(NewVD->getLocation(), diag::err_module_private_specialization)
@@ -4405,12 +4913,17 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Handle attributes prior to checking for duplicates in MergeVarDecl
ProcessDeclAttributes(S, NewVD, D);
+ if (NewVD->hasAttrs())
+ CheckAlignasUnderalignment(NewVD);
+
if (getLangOpts().CUDA) {
// CUDA B.2.5: "__shared__ and __constant__ variables have implied static
// storage [duration]."
if (SC == SC_None && S->getFnParent() != 0 &&
- (NewVD->hasAttr<CUDASharedAttr>() || NewVD->hasAttr<CUDAConstantAttr>()))
+ (NewVD->hasAttr<CUDASharedAttr>() ||
+ NewVD->hasAttr<CUDAConstantAttr>())) {
NewVD->setStorageClass(SC_Static);
+ }
}
// In auto-retain/release, infer strong retension for variables of
@@ -4459,7 +4972,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Don't consider existing declarations that are in a different
// scope and are out-of-semantic-context declarations (if the new
// declaration has linkage).
- FilterLookupForScope(Previous, DC, S, NewVD->hasLinkage(),
+ FilterLookupForScope(Previous, DC, S, shouldConsiderLinkage(NewVD),
isExplicitSpecialization);
if (!getLangOpts().CPlusPlus) {
@@ -4493,19 +5006,15 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewVD->setInvalidDecl();
}
+ ProcessPragmaWeak(S, NewVD);
+ checkAttributesAfterMerging(*this, *NewVD);
+
// If this is a locally-scoped extern C variable, update the map of
// such variables.
if (CurContext->isFunctionOrMethod() && NewVD->isExternC() &&
!NewVD->isInvalidDecl())
RegisterLocallyScopedExternCDecl(NewVD, Previous, S);
- // If there's a #pragma GCC visibility in scope, and this isn't a class
- // member, set the visibility of this variable.
- if (NewVD->getLinkage() == ExternalLinkage && !DC->isRecord())
- AddPushedVisibilityAttribute(NewVD);
-
- MarkUnusedFileScopedDecl(NewVD);
-
return NewVD;
}
@@ -4604,6 +5113,32 @@ void Sema::CheckShadow(Scope *S, VarDecl *D) {
CheckShadow(S, D, R);
}
+template<typename T>
+static bool mayConflictWithNonVisibleExternC(const T *ND) {
+ const DeclContext *DC = ND->getDeclContext();
+ if (DC->getRedeclContext()->isTranslationUnit())
+ return true;
+
+ // We know that is the first decl we see, other than function local
+ // extern C ones. If this is C++ and the decl is not in a extern C context
+ // it cannot have C language linkage. Avoid calling isExternC in that case.
+ // We need to this because of code like
+ //
+ // namespace { struct bar {}; }
+ // auto foo = bar();
+ //
+ // This code runs before the init of foo is set, and therefore before
+ // the type of foo is known. Not knowing the type we cannot know its linkage
+ // unless it is in an extern C block.
+ if (!DC->isExternCContext()) {
+ const ASTContext &Context = ND->getASTContext();
+ if (Context.getLangOpts().CPlusPlus)
+ return false;
+ }
+
+ return ND->isExternC();
+}
+
/// \brief Perform semantic checking on a newly-created variable
/// declaration.
///
@@ -4706,16 +5241,44 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
NewVD->setTypeSourceInfo(FixedTInfo);
}
- if (Previous.empty() && NewVD->isExternC()) {
- // Since we did not find anything by this name and we're declaring
- // an extern "C" variable, look for a non-visible extern "C"
- // declaration with the same name.
+ // If we did not find anything by this name, look for a non-visible
+ // extern "C" declaration with the same name.
+ //
+ // Clang has a lot of problems with extern local declarations.
+ // The actual standards text here is:
+ //
+ // C++11 [basic.link]p6:
+ // The name of a function declared in block scope and the name
+ // of a variable declared by a block scope extern declaration
+ // have linkage. If there is a visible declaration of an entity
+ // with linkage having the same name and type, ignoring entities
+ // declared outside the innermost enclosing namespace scope, the
+ // block scope declaration declares that same entity and
+ // receives the linkage of the previous declaration.
+ //
+ // C11 6.2.7p4:
+ // For an identifier with internal or external linkage declared
+ // in a scope in which a prior declaration of that identifier is
+ // visible, if the prior declaration specifies internal or
+ // external linkage, the type of the identifier at the later
+ // declaration becomes the composite type.
+ //
+ // The most important point here is that we're not allowed to
+ // update our understanding of the type according to declarations
+ // not in scope.
+ bool PreviousWasHidden = false;
+ if (Previous.empty() && mayConflictWithNonVisibleExternC(NewVD)) {
llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos
- = findLocallyScopedExternalDecl(NewVD->getDeclName());
- if (Pos != LocallyScopedExternalDecls.end())
+ = findLocallyScopedExternCDecl(NewVD->getDeclName());
+ if (Pos != LocallyScopedExternCDecls.end()) {
Previous.addDecl(Pos->second);
+ PreviousWasHidden = true;
+ }
}
+ // Filter out any non-conflicting previous declarations.
+ filterNonConflictingPreviousDecls(Context, NewVD, Previous);
+
if (T->isVoidType() && !NewVD->hasExternalStorage()) {
Diag(NewVD->getLocation(), diag::err_typecheck_decl_incomplete_type)
<< T;
@@ -4743,7 +5306,7 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD,
}
if (!Previous.empty()) {
- MergeVarDecl(NewVD, Previous);
+ MergeVarDecl(NewVD, Previous, PreviousWasHidden);
return true;
}
return false;
@@ -4778,9 +5341,9 @@ static bool FindOverriddenMethod(const CXXBaseSpecifier *Specifier,
}
for (Path.Decls = BaseRecord->lookup(Name);
- Path.Decls.first != Path.Decls.second;
- ++Path.Decls.first) {
- NamedDecl *D = *Path.Decls.first;
+ !Path.Decls.empty();
+ Path.Decls = Path.Decls.slice(1)) {
+ NamedDecl *D = Path.Decls.front();
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
if (MD->isVirtual() && !Data->S->IsOverload(Data->Method, MD, false))
return true;
@@ -4832,6 +5395,7 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
if (CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(*I)) {
MD->addOverriddenMethod(OldMD->getCanonicalDecl());
if (!CheckOverridingFunctionReturnType(MD, OldMD) &&
+ !CheckOverridingFunctionAttributes(MD, OldMD) &&
!CheckOverridingFunctionExceptionSpec(MD, OldMD) &&
!CheckIfOverriddenFunctionIsMarkedFinal(MD, OldMD)) {
hasDeletedOverridenMethods |= OldMD->isDeleted();
@@ -4878,7 +5442,7 @@ class DifferentNameValidatorCCC : public CorrectionCandidateCallback {
if (candidate.getEditDistance() == 0)
return false;
- llvm::SmallVector<unsigned, 1> MismatchedParams;
+ SmallVector<unsigned, 1> MismatchedParams;
for (TypoCorrection::const_decl_iterator CDecl = candidate.begin(),
CDeclEnd = candidate.end();
CDecl != CDeclEnd; ++CDecl) {
@@ -4924,8 +5488,8 @@ static NamedDecl* DiagnoseInvalidRedeclaration(
DeclContext *NewDC = NewFD->getDeclContext();
LookupResult Prev(SemaRef, Name, NewFD->getLocation(),
Sema::LookupOrdinaryName, Sema::ForRedeclaration);
- llvm::SmallVector<unsigned, 1> MismatchedParams;
- llvm::SmallVector<std::pair<FunctionDecl*, unsigned>, 1> NearMatches;
+ SmallVector<unsigned, 1> MismatchedParams;
+ SmallVector<std::pair<FunctionDecl *, unsigned>, 1> NearMatches;
TypoCorrection Correction;
bool isFriendDecl = (SemaRef.getLangOpts().CPlusPlus &&
ExtraArgs.D.getDeclSpec().isFriendSpecified());
@@ -5029,7 +5593,7 @@ static NamedDecl* DiagnoseInvalidRedeclaration(
if (CXXMethodDecl *NewMD = dyn_cast<CXXMethodDecl>(NewFD))
NewFDisConst = NewMD->isConst();
- for (llvm::SmallVector<std::pair<FunctionDecl*, unsigned>, 1>::iterator
+ for (SmallVector<std::pair<FunctionDecl *, unsigned>, 1>::iterator
NearMatch = NearMatches.begin(), NearMatchEnd = NearMatches.end();
NearMatch != NearMatchEnd; ++NearMatch) {
FunctionDecl *FD = NearMatch->first;
@@ -5098,9 +5662,6 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
FunctionDecl *NewFD = 0;
bool isInline = D.getDeclSpec().isInlineSpecified();
- DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten();
- FunctionDecl::StorageClass SCAsWritten
- = StorageClassSpecToFunctionDeclStorageClass(SCSpec);
if (!SemaRef.getLangOpts().CPlusPlus) {
// Determine whether the function was written with a
@@ -5114,8 +5675,8 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
NewFD = FunctionDecl::Create(SemaRef.Context, DC,
D.getLocStart(), NameInfo, R,
- TInfo, SC, SCAsWritten, isInline,
- HasPrototype);
+ TInfo, SC, isInline,
+ HasPrototype, false);
if (D.isInvalidType())
NewFD->setInvalidDecl();
@@ -5164,7 +5725,7 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
// If the class is complete, then we now create the implicit exception
// specification. If the class is incomplete or dependent, we can't do
// it yet.
- if (SemaRef.getLangOpts().CPlusPlus0x && !Record->isDependentType() &&
+ if (SemaRef.getLangOpts().CPlusPlus11 && !Record->isDependentType() &&
Record->getDefinition() && !Record->isBeingDefined() &&
R->getAs<FunctionProtoType>()->getExceptionSpecType() == EST_None) {
SemaRef.AdjustDestructorExceptionSpec(Record, NewDD);
@@ -5182,7 +5743,7 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
return FunctionDecl::Create(SemaRef.Context, DC,
D.getLocStart(),
D.getIdentifierLoc(), Name, R, TInfo,
- SC, SCAsWritten, isInline,
+ SC, isInline,
/*hasPrototype=*/true, isConstexpr);
}
@@ -5213,36 +5774,21 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
return 0;
}
- bool isStatic = SC == SC_Static;
-
- // [class.free]p1:
- // Any allocation function for a class T is a static member
- // (even if not explicitly declared static).
- if (Name.getCXXOverloadedOperator() == OO_New ||
- Name.getCXXOverloadedOperator() == OO_Array_New)
- isStatic = true;
-
- // [class.free]p6 Any deallocation function for a class X is a static member
- // (even if not explicitly declared static).
- if (Name.getCXXOverloadedOperator() == OO_Delete ||
- Name.getCXXOverloadedOperator() == OO_Array_Delete)
- isStatic = true;
-
- IsVirtualOkay = !isStatic;
-
// This is a C++ method declaration.
- return CXXMethodDecl::Create(SemaRef.Context, cast<CXXRecordDecl>(DC),
- D.getLocStart(), NameInfo, R,
- TInfo, isStatic, SCAsWritten, isInline,
- isConstexpr, SourceLocation());
-
+ CXXMethodDecl *Ret = CXXMethodDecl::Create(SemaRef.Context,
+ cast<CXXRecordDecl>(DC),
+ D.getLocStart(), NameInfo, R,
+ TInfo, SC, isInline,
+ isConstexpr, SourceLocation());
+ IsVirtualOkay = !Ret->isStatic();
+ return Ret;
} else {
// Determine whether the function was written with a
// prototype. This true when:
// - we're in C++ (where every function has a prototype),
return FunctionDecl::Create(SemaRef.Context, DC,
D.getLocStart(),
- NameInfo, R, TInfo, SC, SCAsWritten, isInline,
+ NameInfo, R, TInfo, SC, isInline,
true/*HasPrototype*/, isConstexpr);
}
}
@@ -5291,8 +5837,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
T = Context.getObjCObjectPointerType(T);
if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(R)) {
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
- R = Context.getFunctionType(T, FPT->arg_type_begin(),
- FPT->getNumArgs(), EPI);
+ R = Context.getFunctionType(T,
+ ArrayRef<QualType>(FPT->arg_type_begin(),
+ FPT->getNumArgs()),
+ EPI);
}
else if (isa<FunctionNoProtoType>(R))
R = Context.getFunctionNoProtoType(T);
@@ -5504,11 +6052,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
if (isConstexpr) {
- // C++0x [dcl.constexpr]p2: constexpr functions and constexpr constructors
+ // C++11 [dcl.constexpr]p2: constexpr functions and constexpr constructors
// are implicitly inline.
NewFD->setImplicitlyInline();
- // C++0x [dcl.constexpr]p3: functions declared constexpr are required to
+ // C++11 [dcl.constexpr]p3: functions declared constexpr are required to
// be either constructors or to return a literal type. Therefore,
// destructors cannot be declared constexpr.
if (isa<CXXDestructorDecl>(NewFD))
@@ -5583,17 +6131,18 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
const FunctionProtoType *FPT = R->getAs<FunctionProtoType>();
if ((Name.getCXXOverloadedOperator() == OO_Delete ||
Name.getCXXOverloadedOperator() == OO_Array_Delete) &&
- getLangOpts().CPlusPlus0x && FPT && !FPT->hasExceptionSpec()) {
+ getLangOpts().CPlusPlus11 && 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));
+ ArrayRef<QualType>(FPT->arg_type_begin(),
+ FPT->getNumArgs()),
+ EPI));
}
}
// Filter out previous declarations that don't match the scope.
- FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(),
+ FilterLookupForScope(Previous, DC, S, shouldConsiderLinkage(NewFD),
isExplicitSpecialization ||
isFunctionTemplateSpecialization);
@@ -5675,6 +6224,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewFD->setDeclsInPrototypeScope(DeclsInPrototypeScope);
DeclsInPrototypeScope.clear();
+ if (D.getDeclSpec().isNoreturnSpecified())
+ NewFD->addAttr(
+ ::new(Context) C11NoReturnAttr(D.getDeclSpec().getNoreturnSpecLoc(),
+ Context));
+
// Process the non-inheritable attributes on this declaration.
ProcessDeclAttributes(S, NewFD, D,
/*NonInheritable=*/true, /*Inheritable=*/false);
@@ -5691,6 +6245,18 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
ProcessDeclAttributes(S, NewFD, D,
/*NonInheritable=*/false, /*Inheritable=*/true);
+ QualType RetType = NewFD->getResultType();
+ const CXXRecordDecl *Ret = RetType->isRecordType() ?
+ RetType->getAsCXXRecordDecl() : RetType->getPointeeCXXRecordDecl();
+ if (!NewFD->isInvalidDecl() && !NewFD->hasAttr<WarnUnusedResultAttr>() &&
+ Ret && Ret->hasAttr<WarnUnusedResultAttr>()) {
+ const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);
+ if (!(MD && MD->getCorrespondingMethodInClass(Ret, true))) {
+ NewFD->addAttr(new (Context) WarnUnusedResultAttr(SourceRange(),
+ Context));
+ }
+ }
+
if (!getLangOpts().CPlusPlus) {
// Perform semantic checking on the function declaration.
bool isExplicitSpecialization=false;
@@ -5788,7 +6354,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// A storage-class-specifier shall not be specified in an explicit
// specialization (14.7.3)
if (SC != SC_None) {
- if (SC != NewFD->getStorageClass())
+ if (SC != NewFD->getTemplateSpecializationInfo()->getTemplate()->getTemplatedDecl()->getStorageClass())
Diag(NewFD->getLocation(),
diag::err_explicit_specialization_inconsistent_storage_class)
<< SC
@@ -5938,6 +6504,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
+ ProcessPragmaWeak(S, NewFD);
+ checkAttributesAfterMerging(*this, *NewFD);
+
AddKnownFunctionAttributes(NewFD);
if (NewFD->hasAttr<OverloadableAttr>() &&
@@ -5952,13 +6521,15 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
EPI.Variadic = true;
EPI.ExtInfo = FT->getExtInfo();
- QualType R = Context.getFunctionType(FT->getResultType(), 0, 0, EPI);
+ QualType R = Context.getFunctionType(FT->getResultType(),
+ ArrayRef<QualType>(),
+ EPI);
NewFD->setType(R);
}
// If there's a #pragma GCC visibility in scope, and this isn't a class
// member, set the visibility of this function.
- if (NewFD->getLinkage() == ExternalLinkage && !DC->isRecord())
+ if (!DC->isRecord() && NewFD->hasExternalLinkage())
AddPushedVisibilityAttribute(NewFD);
// If there's a #pragma clang arc_cf_code_audited in scope, consider
@@ -5982,12 +6553,42 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
}
- // OpenCL v1.2 s6.8 static is invalid for kernel functions.
- if ((getLangOpts().OpenCLVersion >= 120)
- && NewFD->hasAttr<OpenCLKernelAttr>()
- && (SC == SC_Static)) {
- Diag(D.getIdentifierLoc(), diag::err_static_kernel);
- D.setInvalidType();
+ if (NewFD->hasAttr<OpenCLKernelAttr>()) {
+ // OpenCL v1.2 s6.8 static is invalid for kernel functions.
+ if ((getLangOpts().OpenCLVersion >= 120)
+ && (SC == SC_Static)) {
+ Diag(D.getIdentifierLoc(), diag::err_static_kernel);
+ D.setInvalidType();
+ }
+
+ // OpenCL v1.2, s6.9 -- Kernels can only have return type void.
+ if (!NewFD->getResultType()->isVoidType()) {
+ Diag(D.getIdentifierLoc(),
+ diag::err_expected_kernel_void_return_type);
+ D.setInvalidType();
+ }
+
+ for (FunctionDecl::param_iterator PI = NewFD->param_begin(),
+ PE = NewFD->param_end(); PI != PE; ++PI) {
+ ParmVarDecl *Param = *PI;
+ QualType PT = Param->getType();
+
+ // OpenCL v1.2 s6.9.a:
+ // A kernel function argument cannot be declared as a
+ // pointer to a pointer type.
+ if (PT->isPointerType() && PT->getPointeeType()->isPointerType()) {
+ Diag(Param->getLocation(), diag::err_opencl_ptrptr_kernel_arg);
+ D.setInvalidType();
+ }
+
+ // OpenCL v1.2 s6.8 n:
+ // A kernel function argument cannot be declared
+ // of event_t type.
+ if (PT->isEventT()) {
+ Diag(Param->getLocation(), diag::err_event_t_kernel_arg);
+ D.setInvalidType();
+ }
+ }
}
MarkUnusedFileScopedDecl(NewFD);
@@ -6043,17 +6644,20 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
&& "Variably modified return types are not handled here");
// Check for a previous declaration of this name.
- if (Previous.empty() && NewFD->isExternC()) {
- // Since we did not find anything by this name and we're declaring
- // an extern "C" function, look for a non-visible extern "C"
- // declaration with the same name.
+ if (Previous.empty() && mayConflictWithNonVisibleExternC(NewFD)) {
+ // Since we did not find anything by this name, look for a non-visible
+ // extern "C" declaration with the same name.
llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos
- = findLocallyScopedExternalDecl(NewFD->getDeclName());
- if (Pos != LocallyScopedExternalDecls.end())
+ = findLocallyScopedExternCDecl(NewFD->getDeclName());
+ if (Pos != LocallyScopedExternCDecls.end())
Previous.addDecl(Pos->second);
}
+ // Filter out any non-conflicting previous declarations.
+ filterNonConflictingPreviousDecls(Context, NewFD, Previous);
+
bool Redeclaration = false;
+ NamedDecl *OldDecl = 0;
// Merge or overload the declaration with an existing declaration of
// the same name, if appropriate.
@@ -6062,8 +6666,6 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// a declaration that requires merging. If it's an overload,
// there's no more work to do here; we'll just add the new
// function to the scope.
-
- NamedDecl *OldDecl = 0;
if (!AllowOverloadingOfFunction(Previous, Context)) {
Redeclaration = true;
OldDecl = Previous.getFoundDecl();
@@ -6100,42 +6702,90 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
Context));
}
}
+ }
- if (Redeclaration) {
- // NewFD and OldDecl represent declarations that need to be
- // merged.
- if (MergeFunctionDecl(NewFD, OldDecl, S)) {
- NewFD->setInvalidDecl();
- return Redeclaration;
- }
+ // C++11 [dcl.constexpr]p8:
+ // A constexpr specifier for a non-static member function that is not
+ // a constructor declares that member function to be const.
+ //
+ // This needs to be delayed until we know whether this is an out-of-line
+ // definition of a static member function.
+ CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);
+ if (MD && MD->isConstexpr() && !MD->isStatic() &&
+ !isa<CXXConstructorDecl>(MD) &&
+ (MD->getTypeQualifiers() & Qualifiers::Const) == 0) {
+ CXXMethodDecl *OldMD = dyn_cast_or_null<CXXMethodDecl>(OldDecl);
+ if (FunctionTemplateDecl *OldTD =
+ dyn_cast_or_null<FunctionTemplateDecl>(OldDecl))
+ OldMD = dyn_cast<CXXMethodDecl>(OldTD->getTemplatedDecl());
+ if (!OldMD || !OldMD->isStatic()) {
+ const FunctionProtoType *FPT =
+ MD->getType()->castAs<FunctionProtoType>();
+ FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
+ EPI.TypeQuals |= Qualifiers::Const;
+ MD->setType(Context.getFunctionType(FPT->getResultType(),
+ ArrayRef<QualType>(FPT->arg_type_begin(),
+ FPT->getNumArgs()),
+ EPI));
+ }
+ }
- Previous.clear();
- Previous.addDecl(OldDecl);
-
- if (FunctionTemplateDecl *OldTemplateDecl
- = dyn_cast<FunctionTemplateDecl>(OldDecl)) {
- NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl());
- FunctionTemplateDecl *NewTemplateDecl
- = NewFD->getDescribedFunctionTemplate();
- assert(NewTemplateDecl && "Template/non-template mismatch");
- if (CXXMethodDecl *Method
- = dyn_cast<CXXMethodDecl>(NewTemplateDecl->getTemplatedDecl())) {
- Method->setAccess(OldTemplateDecl->getAccess());
- NewTemplateDecl->setAccess(OldTemplateDecl->getAccess());
- }
-
- // If this is an explicit specialization of a member that is a function
- // template, mark it as a member specialization.
- if (IsExplicitSpecialization &&
- NewTemplateDecl->getInstantiatedFromMemberTemplate()) {
- NewTemplateDecl->setMemberSpecialization();
- assert(OldTemplateDecl->isMemberSpecialization());
+ if (Redeclaration) {
+ // NewFD and OldDecl represent declarations that need to be
+ // merged.
+ if (MergeFunctionDecl(NewFD, OldDecl, S)) {
+ NewFD->setInvalidDecl();
+ return Redeclaration;
+ }
+
+ Previous.clear();
+ Previous.addDecl(OldDecl);
+
+ if (FunctionTemplateDecl *OldTemplateDecl
+ = dyn_cast<FunctionTemplateDecl>(OldDecl)) {
+ NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl());
+ FunctionTemplateDecl *NewTemplateDecl
+ = NewFD->getDescribedFunctionTemplate();
+ assert(NewTemplateDecl && "Template/non-template mismatch");
+ if (CXXMethodDecl *Method
+ = dyn_cast<CXXMethodDecl>(NewTemplateDecl->getTemplatedDecl())) {
+ Method->setAccess(OldTemplateDecl->getAccess());
+ NewTemplateDecl->setAccess(OldTemplateDecl->getAccess());
+ }
+
+ // If this is an explicit specialization of a member that is a function
+ // template, mark it as a member specialization.
+ if (IsExplicitSpecialization &&
+ NewTemplateDecl->getInstantiatedFromMemberTemplate()) {
+ NewTemplateDecl->setMemberSpecialization();
+ assert(OldTemplateDecl->isMemberSpecialization());
+ }
+
+ } else {
+ // This needs to happen first so that 'inline' propagates.
+ NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
+
+ if (isa<CXXMethodDecl>(NewFD)) {
+ // A valid redeclaration of a C++ method must be out-of-line,
+ // but (unfortunately) it's not necessarily a definition
+ // because of templates, which means that the previous
+ // declaration is not necessarily from the class definition.
+
+ // For just setting the access, that doesn't matter.
+ CXXMethodDecl *oldMethod = cast<CXXMethodDecl>(OldDecl);
+ NewFD->setAccess(oldMethod->getAccess());
+
+ // Update the key-function state if necessary for this ABI.
+ if (NewFD->isInlined() &&
+ !Context.getTargetInfo().getCXXABI().canKeyFunctionBeInline()) {
+ // setNonKeyFunction needs to work with the original
+ // declaration from the class definition, and isVirtual() is
+ // just faster in that case, so map back to that now.
+ oldMethod = cast<CXXMethodDecl>(oldMethod->getFirstDeclaration());
+ if (oldMethod->isVirtual()) {
+ Context.setNonKeyFunction(oldMethod);
+ }
}
-
- } else {
- if (isa<CXXMethodDecl>(NewFD)) // Set access for out-of-line definitions
- NewFD->setAccess(OldDecl->getAccess());
- NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
}
}
}
@@ -6208,6 +6858,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// declaration against the expected type for the builtin.
if (unsigned BuiltinID = NewFD->getBuiltinID()) {
ASTContext::GetBuiltinTypeError Error;
+ LookupPredefedObjCSuperType(*this, S, NewFD->getIdentifier());
QualType T = Context.GetBuiltinType(BuiltinID, Error);
if (!T.isNull() && !Context.hasSameType(T, NewFD->getType())) {
// The type of this function differs from the type of the builtin,
@@ -6219,7 +6870,8 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// If this function is declared as being extern "C", then check to see if
// the function returns a UDT (class, struct, or union type) that is not C
// compatible, and if it does, warn the user.
- if (NewFD->isExternC()) {
+ // But, issue any diagnostic on the first declaration only.
+ if (NewFD->isExternC() && Previous.empty()) {
QualType R = NewFD->getResultType();
if (R->isIncompleteType() && !R->isVoidType())
Diag(NewFD->getLocation(), diag::warn_return_value_udt_incomplete)
@@ -6232,12 +6884,30 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
return Redeclaration;
}
+static SourceRange getResultSourceRange(const FunctionDecl *FD) {
+ const TypeSourceInfo *TSI = FD->getTypeSourceInfo();
+ if (!TSI)
+ return SourceRange();
+
+ TypeLoc TL = TSI->getTypeLoc();
+ FunctionTypeLoc FunctionTL = TL.getAs<FunctionTypeLoc>();
+ if (!FunctionTL)
+ return SourceRange();
+
+ TypeLoc ResultTL = FunctionTL.getResultLoc();
+ if (ResultTL.getUnqualifiedLoc().getAs<BuiltinTypeLoc>())
+ return ResultTL.getSourceRange();
+
+ return SourceRange();
+}
+
void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) {
// C++11 [basic.start.main]p3: A program that declares main to be inline,
// static or constexpr is ill-formed.
- // C99 6.7.4p4: In a hosted environment, the inline function specifier
- // shall not appear in a declaration of main.
+ // C11 6.7.4p4: In a hosted environment, no function specifier(s) shall
+ // appear in a declaration of main.
// static main is not an error under C99, but we should warn about it.
+ // We accept _Noreturn main as an extension.
if (FD->getStorageClass() == SC_Static)
Diag(DS.getStorageClassSpecLoc(), getLangOpts().CPlusPlus
? diag::err_static_main : diag::warn_static_main)
@@ -6245,6 +6915,14 @@ void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) {
if (FD->isInlineSpecified())
Diag(DS.getInlineSpecLoc(), diag::err_inline_main)
<< FixItHint::CreateRemoval(DS.getInlineSpecLoc());
+ if (DS.isNoreturnSpecified()) {
+ SourceLocation NoreturnLoc = DS.getNoreturnSpecLoc();
+ SourceRange NoreturnRange(NoreturnLoc,
+ PP.getLocForEndOfToken(NoreturnLoc));
+ Diag(NoreturnLoc, diag::ext_noreturn_main);
+ Diag(NoreturnLoc, diag::note_main_remove_noreturn)
+ << FixItHint::CreateRemoval(NoreturnRange);
+ }
if (FD->isConstexpr()) {
Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_main)
<< FixItHint::CreateRemoval(DS.getConstexprSpecLoc());
@@ -6268,9 +6946,20 @@ void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) {
} else if (getLangOpts().GNUMode && !getLangOpts().CPlusPlus) {
Diag(FD->getTypeSpecStartLoc(), diag::ext_main_returns_nonint);
+ SourceRange ResultRange = getResultSourceRange(FD);
+ if (ResultRange.isValid())
+ Diag(ResultRange.getBegin(), diag::note_main_change_return_type)
+ << FixItHint::CreateReplacement(ResultRange, "int");
+
// Otherwise, this is just a flat-out error.
} else {
- Diag(FD->getTypeSpecStartLoc(), diag::err_main_returns_nonint);
+ SourceRange ResultRange = getResultSourceRange(FD);
+ if (ResultRange.isValid())
+ Diag(FD->getTypeSpecStartLoc(), diag::err_main_returns_nonint)
+ << FixItHint::CreateReplacement(ResultRange, "int");
+ else
+ Diag(FD->getTypeSpecStartLoc(), diag::err_main_returns_nonint);
+
FD->setInvalidDecl(true);
}
@@ -6319,7 +7008,8 @@ void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) {
const PointerType* PT;
if ((PT = qs.strip(AT)->getAs<PointerType>()) &&
(PT = qs.strip(PT->getPointeeType())->getAs<PointerType>()) &&
- (QualType(qs.strip(PT->getPointeeType()), 0) == Context.CharTy)) {
+ Context.hasSameType(QualType(qs.strip(PT->getPointeeType()), 0),
+ Context.CharTy)) {
qs.removeConst();
mismatch = !qs.empty();
}
@@ -6457,6 +7147,14 @@ namespace {
Visit(Base);
}
+ void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
+ if (E->getNumArgs() > 0)
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->getArg(0)))
+ HandleDeclRefExpr(DRE);
+
+ Inherited::VisitCXXOperatorCallExpr(E);
+ }
+
void VisitUnaryOperator(UnaryOperator *E) {
// For POD record types, addresses of its own members are well-defined.
if (E->getOpcode() == UO_AddrOf && isRecordType &&
@@ -6471,11 +7169,17 @@ namespace {
void VisitObjCMessageExpr(ObjCMessageExpr *E) { return; }
void HandleDeclRefExpr(DeclRefExpr *DRE) {
- Decl* ReferenceDecl = DRE->getDecl();
+ Decl* ReferenceDecl = DRE->getDecl();
if (OrigDecl != ReferenceDecl) return;
- unsigned diag = isReferenceType
- ? diag::warn_uninit_self_reference_in_reference_init
- : diag::warn_uninit_self_reference_in_init;
+ unsigned diag;
+ if (isReferenceType) {
+ diag = diag::warn_uninit_self_reference_in_reference_init;
+ } else if (cast<VarDecl>(OrigDecl)->isStaticLocal()) {
+ diag = diag::warn_static_self_reference_in_init;
+ } else {
+ diag = diag::warn_uninit_self_reference_in_init;
+ }
+
S.DiagRuntimeBehavior(DRE->getLocStart(), DRE,
S.PDiag(diag)
<< DRE->getNameInfo().getName()
@@ -6572,6 +7276,20 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
DeduceInit = CXXDirectInit->getExpr(0);
}
}
+
+ // Expressions default to 'id' when we're in a debugger.
+ bool DefaultedToAuto = false;
+ if (getLangOpts().DebuggerCastResultToId &&
+ Init->getType() == Context.UnknownAnyTy) {
+ ExprResult Result = forceUnknownAnyToType(Init, Context.getObjCIdType());
+ if (Result.isInvalid()) {
+ VDecl->setInvalidDecl();
+ return;
+ }
+ Init = Result.take();
+ DefaultedToAuto = true;
+ }
+
TypeSourceInfo *DeducedType = 0;
if (DeduceAutoType(VDecl->getTypeSourceInfo(), DeduceInit, DeducedType) ==
DAR_Failed)
@@ -6582,8 +7300,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
}
VDecl->setTypeSourceInfo(DeducedType);
VDecl->setType(DeducedType->getType());
- VDecl->ClearLinkageCache();
-
+ assert(VDecl->isLinkageValid());
+
// In ARC, infer lifetime.
if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(VDecl))
VDecl->setInvalidDecl();
@@ -6592,7 +7310,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// 'id' instead of a specific object type prevents most of our usual checks.
// We only want to warn outside of template instantiations, though:
// inside a template, the 'id' could have come from a parameter.
- if (ActiveTemplateInstantiations.empty() &&
+ if (ActiveTemplateInstantiations.empty() && !DefaultedToAuto &&
DeducedType->getType()->isObjCIdType()) {
SourceLocation Loc = DeducedType->getTypeLoc().getBeginLoc();
Diag(Loc, diag::warn_auto_var_is_id)
@@ -6602,7 +7320,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// If this is a redeclaration, check that the type we just deduced matches
// the previously declared type.
if (VarDecl *Old = VDecl->getPreviousDecl())
- MergeVarDeclTypes(VDecl, Old);
+ MergeVarDeclTypes(VDecl, Old, /*OldWasHidden*/ false);
}
if (VDecl->isLocalVarDecl() && VDecl->hasExternalStorage()) {
@@ -6683,17 +7401,17 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// CheckInitializerTypes may change it.
QualType DclT = VDecl->getType(), SavT = DclT;
- // Top-level message sends default to 'id' when we're in a debugger
- // and we are assigning it to a variable of 'id' type.
- if (getLangOpts().DebuggerCastResultToId && DclT->isObjCIdType())
- if (Init->getType() == Context.UnknownAnyTy && isa<ObjCMessageExpr>(Init)) {
- ExprResult Result = forceUnknownAnyToType(Init, Context.getObjCIdType());
- if (Result.isInvalid()) {
- VDecl->setInvalidDecl();
- return;
- }
- Init = Result.take();
+ // Expressions default to 'id' when we're in a debugger
+ // and we are assigning it to a variable of Objective-C pointer type.
+ if (getLangOpts().DebuggerCastResultToId && DclT->isObjCObjectPointerType() &&
+ Init->getType() == Context.UnknownAnyTy) {
+ ExprResult Result = forceUnknownAnyToType(Init, Context.getObjCIdType());
+ if (Result.isInvalid()) {
+ VDecl->setInvalidDecl();
+ return;
}
+ Init = Result.take();
+ }
// Perform the initialization.
if (!VDecl->isInvalidDecl()) {
@@ -6740,9 +7458,6 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
if (!VDecl->isInvalidDecl() && (DclT != SavT))
VDecl->setType(DclT);
- // Check any implicit conversions within the expression.
- CheckImplicitConversions(Init, VDecl->getLocation());
-
if (!VDecl->isInvalidDecl()) {
checkUnsafeAssigns(VDecl->getLocation(), VDecl->getType(), Init);
@@ -6765,7 +7480,26 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
}
}
- Init = MaybeCreateExprWithCleanups(Init);
+ // The initialization is usually a full-expression.
+ //
+ // FIXME: If this is a braced initialization of an aggregate, it is not
+ // an expression, and each individual field initializer is a separate
+ // full-expression. For instance, in:
+ //
+ // struct Temp { ~Temp(); };
+ // struct S { S(Temp); };
+ // struct T { S a, b; } t = { Temp(), Temp() }
+ //
+ // we should destroy the first Temp before constructing the second.
+ ExprResult Result = ActOnFinishFullExpr(Init, VDecl->getLocation(),
+ false,
+ VDecl->isConstexpr());
+ if (Result.isInvalid()) {
+ VDecl->setInvalidDecl();
+ return;
+ }
+ Init = Result.take();
+
// Attach the initializer to the decl.
VDecl->setInit(Init);
@@ -6817,7 +7551,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
} else if (DclT->isIntegralOrEnumerationType()) {
// Check whether the expression is a constant expression.
SourceLocation Loc;
- if (getLangOpts().CPlusPlus0x && DclT.isVolatileQualified())
+ if (getLangOpts().CPlusPlus11 && DclT.isVolatileQualified())
// In C++11, a non-constexpr const static data member with an
// in-class initializer cannot be volatile.
Diag(VDecl->getLocation(), diag::err_in_class_initializer_volatile);
@@ -6840,21 +7574,28 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// We allow foldable floating-point constants as an extension.
} else if (DclT->isFloatingType()) { // also permits complex, which is ok
- Diag(VDecl->getLocation(), diag::ext_in_class_initializer_float_type)
- << DclT << Init->getSourceRange();
- if (getLangOpts().CPlusPlus0x)
+ // In C++98, this is a GNU extension. In C++11, it is not, but we support
+ // it anyway and provide a fixit to add the 'constexpr'.
+ if (getLangOpts().CPlusPlus11) {
Diag(VDecl->getLocation(),
- diag::note_in_class_initializer_float_type_constexpr)
- << FixItHint::CreateInsertion(VDecl->getLocStart(), "constexpr ");
+ diag::ext_in_class_initializer_float_type_cxx11)
+ << DclT << Init->getSourceRange();
+ Diag(VDecl->getLocStart(),
+ diag::note_in_class_initializer_float_type_cxx11)
+ << FixItHint::CreateInsertion(VDecl->getLocStart(), "constexpr ");
+ } else {
+ Diag(VDecl->getLocation(), diag::ext_in_class_initializer_float_type)
+ << DclT << Init->getSourceRange();
- if (!Init->isValueDependent() && !Init->isEvaluatable(Context)) {
- Diag(Init->getExprLoc(), diag::err_in_class_initializer_non_constant)
- << Init->getSourceRange();
- VDecl->setInvalidDecl();
+ if (!Init->isValueDependent() && !Init->isEvaluatable(Context)) {
+ Diag(Init->getExprLoc(), diag::err_in_class_initializer_non_constant)
+ << Init->getSourceRange();
+ VDecl->setInvalidDecl();
+ }
}
// Suggest adding 'constexpr' in C++11 for literal types.
- } else if (getLangOpts().CPlusPlus0x && DclT->isLiteralType()) {
+ } else if (getLangOpts().CPlusPlus11 && DclT->isLiteralType()) {
Diag(VDecl->getLocation(), diag::err_in_class_initializer_literal_type)
<< DclT << Init->getSourceRange()
<< FixItHint::CreateInsertion(VDecl->getLocStart(), "constexpr ");
@@ -6866,9 +7607,10 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
VDecl->setInvalidDecl();
}
} else if (VDecl->isFileVarDecl()) {
- if (VDecl->getStorageClassAsWritten() == SC_Extern &&
+ if (VDecl->getStorageClass() == SC_Extern &&
(!getLangOpts().CPlusPlus ||
- !Context.getBaseElementType(VDecl->getType()).isConstQualified()))
+ !(Context.getBaseElementType(VDecl->getType()).isConstQualified() ||
+ VDecl->isExternC())))
Diag(VDecl->getLocation(), diag::warn_extern_init);
// C99 6.7.8p4. All file scoped initializers need to be constant.
@@ -7155,7 +7897,7 @@ void Sema::ActOnCXXForRangeDecl(Decl *D) {
// for-range-declaration cannot be given a storage class specifier.
int Error = -1;
- switch (VD->getStorageClassAsWritten()) {
+ switch (VD->getStorageClass()) {
case SC_None:
break;
case SC_Extern:
@@ -7206,7 +7948,10 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
}
if (var->isThisDeclarationADefinition() &&
- var->getLinkage() == ExternalLinkage) {
+ var->hasExternalLinkage() &&
+ getDiagnostics().getDiagnosticLevel(
+ diag::warn_missing_variable_declarations,
+ var->getLocation())) {
// Find a previous declaration that's not a definition.
VarDecl *prev = var->getPreviousDecl();
while (prev && prev->isThisDeclarationADefinition())
@@ -7230,12 +7975,13 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
// Regardless, we don't want to ignore array nesting when
// constructing this copy.
if (type->isStructureOrClassType()) {
+ EnterExpressionEvaluationContext scope(*this, PotentiallyEvaluated);
SourceLocation poi = var->getLocation();
Expr *varRef =new (Context) DeclRefExpr(var, false, type, VK_LValue, poi);
- ExprResult result =
- PerformCopyInitialization(
- InitializedEntity::InitializeBlock(poi, type, false),
- poi, Owned(varRef));
+ ExprResult result
+ = PerformMoveOrCopyInitialization(
+ InitializedEntity::InitializeBlock(poi, type, false),
+ var, var->getType(), varRef, /*AllowNRVO=*/true);
if (!result.isInvalid()) {
result = MaybeCreateExprWithCleanups(result);
Expr *init = result.takeAs<Expr>();
@@ -7259,7 +8005,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
<< Init->getSourceRange();
if (var->isConstexpr()) {
- llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ SmallVector<PartialDiagnosticAt, 8> Notes;
if (!var->evaluateValue(Notes) || !var->isInitICE()) {
SourceLocation DiagLoc = var->getLocation();
// If the note doesn't add any useful information other than a source
@@ -7294,40 +8040,52 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
// Note that we are no longer parsing the initializer for this declaration.
ParsingInitForAutoVars.erase(ThisDecl);
+ VarDecl *VD = dyn_cast_or_null<VarDecl>(ThisDecl);
+ if (!VD)
+ return;
+
+ const DeclContext *DC = VD->getDeclContext();
+ // If there's a #pragma GCC visibility in scope, and this isn't a class
+ // member, set the visibility of this variable.
+ if (!DC->isRecord() && VD->hasExternalLinkage())
+ AddPushedVisibilityAttribute(VD);
+
+ if (VD->isFileVarDecl())
+ MarkUnusedFileScopedDecl(VD);
+
// Now we have parsed the initializer and can update the table of magic
// tag values.
- if (ThisDecl && ThisDecl->hasAttr<TypeTagForDatatypeAttr>()) {
- const VarDecl *VD = dyn_cast<VarDecl>(ThisDecl);
- if (VD && VD->getType()->isIntegralOrEnumerationType()) {
- for (specific_attr_iterator<TypeTagForDatatypeAttr>
- I = ThisDecl->specific_attr_begin<TypeTagForDatatypeAttr>(),
- E = ThisDecl->specific_attr_end<TypeTagForDatatypeAttr>();
- I != E; ++I) {
- const Expr *MagicValueExpr = VD->getInit();
- if (!MagicValueExpr) {
- continue;
- }
- llvm::APSInt MagicValueInt;
- if (!MagicValueExpr->isIntegerConstantExpr(MagicValueInt, Context)) {
- Diag(I->getRange().getBegin(),
- diag::err_type_tag_for_datatype_not_ice)
- << LangOpts.CPlusPlus << MagicValueExpr->getSourceRange();
- continue;
- }
- if (MagicValueInt.getActiveBits() > 64) {
- Diag(I->getRange().getBegin(),
- diag::err_type_tag_for_datatype_too_large)
- << LangOpts.CPlusPlus << MagicValueExpr->getSourceRange();
- continue;
- }
- uint64_t MagicValue = MagicValueInt.getZExtValue();
- RegisterTypeTagForDatatype(I->getArgumentKind(),
- MagicValue,
- I->getMatchingCType(),
- I->getLayoutCompatible(),
- I->getMustBeNull());
- }
+ if (!VD->hasAttr<TypeTagForDatatypeAttr>() ||
+ !VD->getType()->isIntegralOrEnumerationType())
+ return;
+
+ for (specific_attr_iterator<TypeTagForDatatypeAttr>
+ I = ThisDecl->specific_attr_begin<TypeTagForDatatypeAttr>(),
+ E = ThisDecl->specific_attr_end<TypeTagForDatatypeAttr>();
+ I != E; ++I) {
+ const Expr *MagicValueExpr = VD->getInit();
+ if (!MagicValueExpr) {
+ continue;
+ }
+ llvm::APSInt MagicValueInt;
+ if (!MagicValueExpr->isIntegerConstantExpr(MagicValueInt, Context)) {
+ Diag(I->getRange().getBegin(),
+ diag::err_type_tag_for_datatype_not_ice)
+ << LangOpts.CPlusPlus << MagicValueExpr->getSourceRange();
+ continue;
+ }
+ if (MagicValueInt.getActiveBits() > 64) {
+ Diag(I->getRange().getBegin(),
+ diag::err_type_tag_for_datatype_too_large)
+ << LangOpts.CPlusPlus << MagicValueExpr->getSourceRange();
+ continue;
}
+ uint64_t MagicValue = MagicValueInt.getZExtValue();
+ RegisterTypeTagForDatatype(I->getArgumentKind(),
+ MagicValue,
+ I->getMatchingCType(),
+ I->getLayoutCompatible(),
+ I->getMustBeNull());
}
}
@@ -7343,6 +8101,10 @@ Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
if (Decl *D = Group[i])
Decls.push_back(D);
+ if (DeclSpec::isDeclRep(DS.getTypeSpecType()))
+ if (const TagDecl *Tag = dyn_cast_or_null<TagDecl>(DS.getRepAsDecl()))
+ getASTContext().addUnnamedTag(Tag);
+
return BuildDeclaratorGroup(Decls.data(), Decls.size(),
DS.getTypeSpecType() == DeclSpec::TST_auto);
}
@@ -7449,14 +8211,11 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
// Verify C99 6.7.5.3p2: The only SCS allowed is 'register'.
// C++03 [dcl.stc]p2 also permits 'auto'.
VarDecl::StorageClass StorageClass = SC_None;
- VarDecl::StorageClass StorageClassAsWritten = SC_None;
if (DS.getStorageClassSpec() == DeclSpec::SCS_register) {
StorageClass = SC_Register;
- StorageClassAsWritten = SC_Register;
} else if (getLangOpts().CPlusPlus &&
DS.getStorageClassSpec() == DeclSpec::SCS_auto) {
StorageClass = SC_Auto;
- StorageClassAsWritten = SC_Auto;
} else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) {
Diag(DS.getStorageClassSpecLoc(),
diag::err_invalid_storage_class_in_func_decl);
@@ -7469,7 +8228,7 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr)
<< 0;
- DiagnoseFunctionSpecifiers(D);
+ DiagnoseFunctionSpecifiers(D.getDeclSpec());
TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
QualType parmDeclType = TInfo->getType();
@@ -7529,7 +8288,7 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
D.getLocStart(),
D.getIdentifierLoc(), II,
parmDeclType, TInfo,
- StorageClass, StorageClassAsWritten);
+ StorageClass);
if (D.isInvalidType())
New->setInvalidDecl();
@@ -7568,7 +8327,7 @@ ParmVarDecl *Sema::BuildParmVarDeclForTypedef(DeclContext *DC,
location for the unnamed parameters, embedding the parameter's type? */
ParmVarDecl *Param = ParmVarDecl::Create(Context, DC, Loc, Loc, 0,
T, Context.getTrivialTypeSourceInfo(T, Loc),
- SC_None, SC_None, 0);
+ SC_None, 0);
Param->setImplicit();
return Param;
}
@@ -7621,8 +8380,7 @@ void Sema::DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Param,
ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
SourceLocation NameLoc, IdentifierInfo *Name,
QualType T, TypeSourceInfo *TSInfo,
- VarDecl::StorageClass StorageClass,
- VarDecl::StorageClass StorageClassAsWritten) {
+ VarDecl::StorageClass StorageClass) {
// In ARC, infer a lifetime qualifier for appropriate parameter types.
if (getLangOpts().ObjCAutoRefCount &&
T.getObjCLifetime() == Qualifiers::OCL_None &&
@@ -7649,8 +8407,7 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
ParmVarDecl *New = ParmVarDecl::Create(Context, DC, StartLoc, NameLoc, Name,
Context.getAdjustedParameterType(T),
TSInfo,
- StorageClass, StorageClassAsWritten,
- 0);
+ StorageClass, 0);
// Parameters can not be abstract class types.
// For record types, this is done by the AbstractClassUsageDiagnoser once
@@ -7730,7 +8487,8 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) {
return ActOnStartOfFunctionDef(FnBodyScope, DP);
}
-static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD) {
+static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD,
+ const FunctionDecl*& PossibleZeroParamPrototype) {
// Don't warn about invalid declarations.
if (FD->isInvalidDecl())
return false;
@@ -7772,6 +8530,8 @@ static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD) {
continue;
MissingPrototype = !Prev->getType()->isFunctionProtoType();
+ if (FD->getNumParams() == 0)
+ PossibleZeroParamPrototype = Prev;
break;
}
@@ -7837,8 +8597,22 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
// prototype declaration. This warning is issued even if the
// definition itself provides a prototype. The aim is to detect
// global functions that fail to be declared in header files.
- if (ShouldWarnAboutMissingPrototype(FD))
+ const FunctionDecl *PossibleZeroParamPrototype = 0;
+ if (ShouldWarnAboutMissingPrototype(FD, PossibleZeroParamPrototype)) {
Diag(FD->getLocation(), diag::warn_missing_prototype) << FD;
+
+ if (PossibleZeroParamPrototype) {
+ // We found a declaration that is not a prototype,
+ // but that could be a zero-parameter prototype
+ TypeSourceInfo* TI = PossibleZeroParamPrototype->getTypeSourceInfo();
+ TypeLoc TL = TI->getTypeLoc();
+ if (FunctionNoProtoTypeLoc FTL = TL.getAs<FunctionNoProtoTypeLoc>())
+ Diag(PossibleZeroParamPrototype->getLocation(),
+ diag::note_declaration_not_a_prototype)
+ << PossibleZeroParamPrototype
+ << FixItHint::CreateInsertion(FTL.getRParenLoc(), "void");
+ }
+ }
if (FnBodyScope)
PushDeclContext(FnBodyScope, FD);
@@ -7913,7 +8687,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
diag::err_attribute_can_be_applied_only_to_symbol_declaration)
<< "dllimport";
FD->setInvalidDecl();
- return FD;
+ return D;
}
// Visual C++ appears to not think this is an issue, so only issue
@@ -7930,7 +8704,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) {
// We want to attach documentation to original Decl (which might be
// a function template).
ActOnDocumentableDecl(D);
- return FD;
+ return D;
}
/// \brief Given the set of return statements within a function body,
@@ -7967,6 +8741,33 @@ void Sema::computeNRVO(Stmt *Body, FunctionScopeInfo *Scope) {
const_cast<VarDecl*>(NRVOCandidate)->setNRVOVariable(true);
}
+bool Sema::canSkipFunctionBody(Decl *D) {
+ if (!Consumer.shouldSkipFunctionBody(D))
+ return false;
+
+ if (isa<ObjCMethodDecl>(D))
+ return true;
+
+ FunctionDecl *FD = 0;
+ if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(D))
+ FD = FTD->getTemplatedDecl();
+ else
+ FD = cast<FunctionDecl>(D);
+
+ // We cannot skip the body of a function (or function template) which is
+ // constexpr, since we may need to evaluate its body in order to parse the
+ // rest of the file.
+ return !FD->isConstexpr();
+}
+
+Decl *Sema::ActOnSkippedFunctionBody(Decl *Decl) {
+ if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Decl))
+ FD->setHasSkippedBody();
+ else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(Decl))
+ MD->setHasSkippedBody();
+ return ActOnFinishFunctionBody(Decl, 0);
+}
+
Decl *Sema::ActOnFinishFunctionBody(Decl *D, Stmt *BodyArg) {
return ActOnFinishFunctionBody(D, BodyArg, false);
}
@@ -7986,6 +8787,18 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
if (FD) {
FD->setBody(Body);
+ // The only way to be included in UndefinedButUsed is if there is an
+ // ODR use before the definition. Avoid the expensive map lookup if this
+ // is the first declaration.
+ if (FD->getPreviousDecl() != 0 && FD->getPreviousDecl()->isUsed()) {
+ if (FD->getLinkage() != ExternalLinkage)
+ UndefinedButUsed.erase(FD);
+ else if (FD->isInlined() &&
+ (LangOpts.CPlusPlus || !LangOpts.GNUInline) &&
+ (!FD->getPreviousDecl()->hasAttr<GNUInlineAttr>()))
+ UndefinedButUsed.erase(FD);
+ }
+
// If the function implicitly returns zero (like 'main') or is naked,
// don't complain about missing return statements.
if (FD->hasImplicitReturnZero() || FD->hasAttr<NakedAttr>())
@@ -8068,7 +8881,9 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
if (PP.getDiagnostics().hasErrorOccurred() ||
PP.getDiagnostics().getSuppressAllDiagnostics()) {
DiscardCleanupsInEvaluationContext();
- } else if (!isa<FunctionTemplateDecl>(dcl)) {
+ }
+ if (!PP.getDiagnostics().hasUncompilableErrorOccurred() &&
+ !isa<FunctionTemplateDecl>(dcl)) {
// Since the body is valid, issue any analysis-based warnings that are
// enabled.
ActivePolicy = &WP;
@@ -8125,8 +8940,8 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
// this name as a function or variable. If so, use that
// (non-visible) declaration, and complain about it.
llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos
- = findLocallyScopedExternalDecl(&II);
- if (Pos != LocallyScopedExternalDecls.end()) {
+ = findLocallyScopedExternCDecl(&II);
+ if (Pos != LocallyScopedExternCDecls.end()) {
Diag(Loc, diag::warn_use_out_of_scope_declaration) << Pos->second;
Diag(Pos->second->getLocation(), diag::note_previous_declaration);
return Pos->second;
@@ -8202,7 +9017,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
DeclContext *PrevDC = CurContext;
CurContext = Context.getTranslationUnitDecl();
- FunctionDecl *FD = dyn_cast<FunctionDecl>(ActOnDeclarator(TUScope, D));
+ FunctionDecl *FD = cast<FunctionDecl>(ActOnDeclarator(TUScope, D));
FD->setImplicit();
CurContext = PrevDC;
@@ -8376,9 +9191,13 @@ bool Sema::CheckEnumUnderlyingType(TypeSourceInfo *TI) {
SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc();
QualType T = TI->getType();
- if (T->isDependentType() || T->isIntegralType(Context))
+ if (T->isDependentType())
return false;
+ if (const BuiltinType *BT = T->getAs<BuiltinType>())
+ if (BT->isInteger())
+ return false;
+
Diag(UnderlyingLoc, diag::err_enum_invalid_underlying) << T;
return true;
}
@@ -8575,6 +9394,11 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
TUK == TUK_Friend,
isExplicitSpecialization,
Invalid)) {
+ if (Kind == TTK_Enum) {
+ Diag(KWLoc, diag::err_enum_template);
+ return 0;
+ }
+
if (TemplateParams->size() > 0) {
// This is a declaration or definition of a class template (which may
// be a member of another template).
@@ -8703,6 +9527,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// shouldn't be diagnosing.
LookupName(Previous, S);
+ // When declaring or defining a tag, ignore ambiguities introduced
+ // by types using'ed into this scope.
if (Previous.isAmbiguous() &&
(TUK == TUK_Definition || TUK == TUK_Declaration)) {
LookupResult::Filter F = Previous.makeFilter();
@@ -8713,6 +9539,27 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
}
F.done();
}
+
+ // C++11 [namespace.memdef]p3:
+ // If the name in a friend declaration is neither qualified nor
+ // a template-id and the declaration is a function or an
+ // elaborated-type-specifier, the lookup to determine whether
+ // the entity has been previously declared shall not consider
+ // any scopes outside the innermost enclosing namespace.
+ //
+ // Does it matter that this should be by scope instead of by
+ // semantic context?
+ if (!Previous.empty() && TUK == TUK_Friend) {
+ DeclContext *EnclosingNS = SearchDC->getEnclosingNamespaceContext();
+ LookupResult::Filter F = Previous.makeFilter();
+ while (F.hasNext()) {
+ NamedDecl *ND = F.next();
+ DeclContext *DC = ND->getDeclContext()->getRedeclContext();
+ if (DC->isFileContext() && !EnclosingNS->Encloses(ND->getDeclContext()))
+ F.erase();
+ }
+ F.done();
+ }
// Note: there used to be some attempt at recovery here.
if (Previous.isAmbiguous())
@@ -9070,7 +9917,8 @@ CreateNewDecl:
// If this is an undefined enum, warn.
if (TUK != TUK_Definition && !Invalid) {
TagDecl *Def;
- if (getLangOpts().CPlusPlus0x && cast<EnumDecl>(New)->isFixed()) {
+ if ((getLangOpts().CPlusPlus11 || getLangOpts().ObjC2) &&
+ cast<EnumDecl>(New)->isFixed()) {
// C++0x: 7.2p2: opaque-enum-declaration.
// Conflicts are diagnosed above. Do nothing.
}
@@ -9250,7 +10098,9 @@ CreateNewDecl:
AddPushedVisibilityAttribute(New);
OwnedDecl = true;
- return New;
+ // In C++, don't return an invalid declaration. We can't recover well from
+ // the cases where we make the type anonymous.
+ return (Invalid && getLangOpts().CPlusPlus) ? 0 : New;
}
void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) {
@@ -9330,7 +10180,11 @@ void Sema::ActOnTagFinishDefinition(Scope *S, Decl *TagD,
// Exit this scope of this tag's definition.
PopDeclContext();
-
+
+ if (getCurLexicalContext()->isObjCContainer() &&
+ Tag->getDeclContext()->isFileContext())
+ Tag->setTopLevelDeclInObjCContainer();
+
// Notify the consumer that we've defined a tag.
Consumer.HandleTagDeclDefinition(Tag);
}
@@ -9479,14 +10333,24 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
}
}
- DiagnoseFunctionSpecifiers(D);
+ // TR 18037 does not allow fields to be declared with address spaces.
+ if (T.getQualifiers().hasAddressSpace()) {
+ Diag(Loc, diag::err_field_with_address_space);
+ D.setInvalidType();
+ }
+
+ // OpenCL 1.2 spec, s6.9 r:
+ // The event type cannot be used to declare a structure or union field.
+ if (LangOpts.OpenCL && T->isEventT()) {
+ Diag(Loc, diag::err_event_t_struct_field);
+ D.setInvalidType();
+ }
+
+ DiagnoseFunctionSpecifiers(D.getDeclSpec());
if (D.getDeclSpec().isThreadSpecified())
Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
- if (D.getDeclSpec().isConstexprSpecified())
- Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr)
- << 2;
-
+
// Check to see if this name was declared as a member previously
NamedDecl *PrevDecl = 0;
LookupResult Previous(*this, II, Loc, LookupMemberName, ForRedeclaration);
@@ -9587,6 +10451,12 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
}
}
+ // OpenCL v1.2 s6.9.c: bitfields are not supported.
+ if (BitWidth && getLangOpts().OpenCL) {
+ Diag(Loc, diag::err_opencl_bitfields);
+ InvalidDecl = true;
+ }
+
// C99 6.7.2.1p8: A member of a structure or union may have any type other
// than a variably modified type.
if (!InvalidDecl && T->isVariablyModifiedType()) {
@@ -9686,10 +10556,14 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T,
// FIXME: We need to pass in the attributes given an AST
// representation, not a parser representation.
- if (D)
+ if (D) {
// FIXME: What to pass instead of TUScope?
ProcessDeclAttributes(TUScope, NewFD, *D);
+ if (NewFD->hasAttrs())
+ CheckAlignasUnderalignment(NewFD);
+ }
+
// In auto-retain/release, infer strong retension for fields of
// retainable type.
if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(NewFD))
@@ -9711,24 +10585,29 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) {
QualType EltTy = Context.getBaseElementType(FD->getType());
if (const RecordType *RT = EltTy->getAs<RecordType>()) {
- CXXRecordDecl* RDecl = cast<CXXRecordDecl>(RT->getDecl());
+ CXXRecordDecl *RDecl = cast<CXXRecordDecl>(RT->getDecl());
if (RDecl->getDefinition()) {
// We check for copy constructors before constructors
// because otherwise we'll never get complaints about
// copy constructors.
CXXSpecialMember member = CXXInvalid;
- if (!RDecl->hasTrivialCopyConstructor())
+ // We're required to check for any non-trivial constructors. Since the
+ // implicit default constructor is suppressed if there are any
+ // user-declared constructors, we just need to check that there is a
+ // trivial default constructor and a trivial copy constructor. (We don't
+ // worry about move constructors here, since this is a C++98 check.)
+ if (RDecl->hasNonTrivialCopyConstructor())
member = CXXCopyConstructor;
else if (!RDecl->hasTrivialDefaultConstructor())
member = CXXDefaultConstructor;
- else if (!RDecl->hasTrivialCopyAssignment())
+ else if (RDecl->hasNonTrivialCopyAssignment())
member = CXXCopyAssignment;
- else if (!RDecl->hasTrivialDestructor())
+ else if (RDecl->hasNonTrivialDestructor())
member = CXXDestructor;
if (member != CXXInvalid) {
- if (!getLangOpts().CPlusPlus0x &&
+ if (!getLangOpts().CPlusPlus11 &&
getLangOpts().ObjCAutoRefCount && RDecl->hasObjectMember()) {
// Objective-C++ ARC: it is an error to have a non-trivial field of
// a union. However, system headers in Objective-C programs
@@ -9744,192 +10623,17 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) {
}
}
- Diag(FD->getLocation(), getLangOpts().CPlusPlus0x ?
+ Diag(FD->getLocation(), getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_nontrivial_union_or_anon_struct_member :
diag::err_illegal_union_or_anon_struct_member)
<< (int)FD->getParent()->isUnion() << FD->getDeclName() << member;
- DiagnoseNontrivial(RT, member);
- return !getLangOpts().CPlusPlus0x;
- }
- }
- }
-
- return false;
-}
-
-/// If the given constructor is user-declared, produce a diagnostic explaining
-/// that it makes the class non-trivial.
-static bool diagnoseNonTrivialUserDeclaredCtor(Sema &S, QualType QT,
- CXXConstructorDecl *CD,
- Sema::CXXSpecialMember CSM) {
- if (CD->isImplicit())
- return false;
-
- SourceLocation CtorLoc = CD->getLocation();
- S.Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << CSM;
- return true;
-}
-
-/// DiagnoseNontrivial - Given that a class has a non-trivial
-/// special member, figure out why.
-void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) {
- QualType QT(T, 0U);
- CXXRecordDecl* RD = cast<CXXRecordDecl>(T->getDecl());
-
- // Check whether the member was user-declared.
- switch (member) {
- case CXXInvalid:
- break;
-
- case CXXDefaultConstructor:
- if (RD->hasUserDeclaredConstructor()) {
- typedef CXXRecordDecl::ctor_iterator ctor_iter;
- for (ctor_iter CI = RD->ctor_begin(), CE = RD->ctor_end(); CI != CE; ++CI)
- if (diagnoseNonTrivialUserDeclaredCtor(*this, QT, *CI, member))
- return;
-
- // No user-delcared constructors; look for constructor templates.
- typedef CXXRecordDecl::specific_decl_iterator<FunctionTemplateDecl>
- tmpl_iter;
- for (tmpl_iter TI(RD->decls_begin()), TE(RD->decls_end());
- TI != TE; ++TI) {
- CXXConstructorDecl *CD =
- dyn_cast<CXXConstructorDecl>(TI->getTemplatedDecl());
- if (CD && diagnoseNonTrivialUserDeclaredCtor(*this, QT, CD, member))
- return;
- }
- }
- break;
-
- case CXXCopyConstructor:
- if (RD->hasUserDeclaredCopyConstructor()) {
- SourceLocation CtorLoc =
- RD->getCopyConstructor(0)->getLocation();
- Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member;
- return;
- }
- break;
-
- case CXXMoveConstructor:
- if (RD->hasUserDeclaredMoveConstructor()) {
- SourceLocation CtorLoc = RD->getMoveConstructor()->getLocation();
- Diag(CtorLoc, diag::note_nontrivial_user_defined) << QT << member;
- return;
- }
- break;
-
- case CXXCopyAssignment:
- if (RD->hasUserDeclaredCopyAssignment()) {
- SourceLocation AssignLoc =
- RD->getCopyAssignmentOperator(0)->getLocation();
- Diag(AssignLoc, diag::note_nontrivial_user_defined) << QT << member;
- return;
- }
- break;
-
- case CXXMoveAssignment:
- if (RD->hasUserDeclaredMoveAssignment()) {
- SourceLocation AssignLoc = RD->getMoveAssignmentOperator()->getLocation();
- Diag(AssignLoc, diag::note_nontrivial_user_defined) << QT << member;
- return;
- }
- break;
-
- case CXXDestructor:
- if (RD->hasUserDeclaredDestructor()) {
- SourceLocation DtorLoc = LookupDestructor(RD)->getLocation();
- Diag(DtorLoc, diag::note_nontrivial_user_defined) << QT << member;
- return;
- }
- break;
- }
-
- typedef CXXRecordDecl::base_class_iterator base_iter;
-
- // Virtual bases and members inhibit trivial copying/construction,
- // but not trivial destruction.
- if (member != CXXDestructor) {
- // Check for virtual bases. vbases includes indirect virtual bases,
- // so we just iterate through the direct bases.
- for (base_iter bi = RD->bases_begin(), be = RD->bases_end(); bi != be; ++bi)
- if (bi->isVirtual()) {
- SourceLocation BaseLoc = bi->getLocStart();
- Diag(BaseLoc, diag::note_nontrivial_has_virtual) << QT << 1;
- return;
- }
-
- // Check for virtual methods.
- typedef CXXRecordDecl::method_iterator meth_iter;
- for (meth_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
- ++mi) {
- if (mi->isVirtual()) {
- SourceLocation MLoc = mi->getLocStart();
- Diag(MLoc, diag::note_nontrivial_has_virtual) << QT << 0;
- return;
- }
- }
- }
-
- bool (CXXRecordDecl::*hasTrivial)() const;
- switch (member) {
- case CXXDefaultConstructor:
- hasTrivial = &CXXRecordDecl::hasTrivialDefaultConstructor; break;
- case CXXCopyConstructor:
- hasTrivial = &CXXRecordDecl::hasTrivialCopyConstructor; break;
- case CXXCopyAssignment:
- hasTrivial = &CXXRecordDecl::hasTrivialCopyAssignment; break;
- case CXXDestructor:
- hasTrivial = &CXXRecordDecl::hasTrivialDestructor; break;
- default:
- llvm_unreachable("unexpected special member");
- }
-
- // Check for nontrivial bases (and recurse).
- for (base_iter bi = RD->bases_begin(), be = RD->bases_end(); bi != be; ++bi) {
- const RecordType *BaseRT = bi->getType()->getAs<RecordType>();
- assert(BaseRT && "Don't know how to handle dependent bases");
- CXXRecordDecl *BaseRecTy = cast<CXXRecordDecl>(BaseRT->getDecl());
- if (!(BaseRecTy->*hasTrivial)()) {
- SourceLocation BaseLoc = bi->getLocStart();
- Diag(BaseLoc, diag::note_nontrivial_has_nontrivial) << QT << 1 << member;
- DiagnoseNontrivial(BaseRT, member);
- return;
- }
- }
-
- // Check for nontrivial members (and recurse).
- typedef RecordDecl::field_iterator field_iter;
- for (field_iter fi = RD->field_begin(), fe = RD->field_end(); fi != fe;
- ++fi) {
- QualType EltTy = Context.getBaseElementType(fi->getType());
- if (const RecordType *EltRT = EltTy->getAs<RecordType>()) {
- CXXRecordDecl* EltRD = cast<CXXRecordDecl>(EltRT->getDecl());
-
- if (!(EltRD->*hasTrivial)()) {
- SourceLocation FLoc = fi->getLocation();
- Diag(FLoc, diag::note_nontrivial_has_nontrivial) << QT << 0 << member;
- DiagnoseNontrivial(EltRT, member);
- return;
- }
- }
-
- if (EltTy->isObjCLifetimeType()) {
- switch (EltTy.getObjCLifetime()) {
- case Qualifiers::OCL_None:
- case Qualifiers::OCL_ExplicitNone:
- break;
-
- case Qualifiers::OCL_Autoreleasing:
- case Qualifiers::OCL_Weak:
- case Qualifiers::OCL_Strong:
- Diag(fi->getLocation(), diag::note_nontrivial_objc_ownership)
- << QT << EltTy.getObjCLifetime();
- return;
+ DiagnoseNontrivial(RDecl, member);
+ return !getLangOpts().CPlusPlus11;
}
}
}
- llvm_unreachable("found no explanation for non-trivial member");
+ return false;
}
/// TranslateIvarVisibility - Translate visibility from a token ID to an
@@ -10058,8 +10762,8 @@ Decl *Sema::ActOnIvar(Scope *S,
}
/// ActOnLastBitfield - This routine handles synthesized bitfields rules for
-/// class and class extensions. For every class @interface and class
-/// extension @interface, if the last ivar is a bitfield of any type,
+/// class and class extensions. For every class \@interface and class
+/// extension \@interface, if the last ivar is a bitfield of any type,
/// then add an implicit `char :0` ivar to the end of that interface.
void Sema::ActOnLastBitfield(SourceLocation DeclLoc,
SmallVectorImpl<Decl *> &AllIvarDecls) {
@@ -10259,52 +10963,54 @@ void Sema::ActOnFields(Scope* S,
}
if (Record && FDTTy->getDecl()->hasObjectMember())
Record->setHasObjectMember(true);
+ if (Record && FDTTy->getDecl()->hasVolatileMember())
+ Record->setHasVolatileMember(true);
} else if (FDTy->isObjCObjectType()) {
/// A field cannot be an Objective-c object
Diag(FD->getLocation(), diag::err_statically_allocated_object)
<< FixItHint::CreateInsertion(FD->getLocation(), "*");
QualType T = Context.getObjCObjectPointerType(FD->getType());
FD->setType(T);
- } else if (!getLangOpts().CPlusPlus) {
- if (getLangOpts().ObjCAutoRefCount && Record && !ARCErrReported) {
- // It's an error in ARC if a field has lifetime.
- // We don't want to report this in a system header, though,
- // so we just make the field unavailable.
- // FIXME: that's really not sufficient; we need to make the type
- // itself invalid to, say, initialize or copy.
- QualType T = FD->getType();
- Qualifiers::ObjCLifetime lifetime = T.getObjCLifetime();
- if (lifetime && lifetime != Qualifiers::OCL_ExplicitNone) {
- SourceLocation loc = FD->getLocation();
- if (getSourceManager().isInSystemHeader(loc)) {
- if (!FD->hasAttr<UnavailableAttr>()) {
- FD->addAttr(new (Context) UnavailableAttr(loc, Context,
- "this system field has retaining ownership"));
- }
- } else {
- Diag(FD->getLocation(), diag::err_arc_objc_object_in_struct)
- << T->isBlockPointerType();
+ } else if (getLangOpts().ObjCAutoRefCount && Record && !ARCErrReported &&
+ (!getLangOpts().CPlusPlus || Record->isUnion())) {
+ // It's an error in ARC if a field has lifetime.
+ // We don't want to report this in a system header, though,
+ // so we just make the field unavailable.
+ // FIXME: that's really not sufficient; we need to make the type
+ // itself invalid to, say, initialize or copy.
+ QualType T = FD->getType();
+ Qualifiers::ObjCLifetime lifetime = T.getObjCLifetime();
+ if (lifetime && lifetime != Qualifiers::OCL_ExplicitNone) {
+ SourceLocation loc = FD->getLocation();
+ if (getSourceManager().isInSystemHeader(loc)) {
+ if (!FD->hasAttr<UnavailableAttr>()) {
+ FD->addAttr(new (Context) UnavailableAttr(loc, Context,
+ "this system field has retaining ownership"));
}
- ARCErrReported = true;
+ } else {
+ Diag(FD->getLocation(), diag::err_arc_objc_object_in_tag)
+ << T->isBlockPointerType() << Record->getTagKind();
}
+ ARCErrReported = true;
}
- else if (getLangOpts().ObjC1 &&
+ } else if (getLangOpts().ObjC1 &&
getLangOpts().getGC() != LangOptions::NonGC &&
Record && !Record->hasObjectMember()) {
- if (FD->getType()->isObjCObjectPointerType() ||
- FD->getType().isObjCGCStrong())
+ if (FD->getType()->isObjCObjectPointerType() ||
+ FD->getType().isObjCGCStrong())
+ Record->setHasObjectMember(true);
+ else if (Context.getAsArrayType(FD->getType())) {
+ QualType BaseType = Context.getBaseElementType(FD->getType());
+ if (BaseType->isRecordType() &&
+ BaseType->getAs<RecordType>()->getDecl()->hasObjectMember())
Record->setHasObjectMember(true);
- else if (Context.getAsArrayType(FD->getType())) {
- QualType BaseType = Context.getBaseElementType(FD->getType());
- if (BaseType->isRecordType() &&
- BaseType->getAs<RecordType>()->getDecl()->hasObjectMember())
- Record->setHasObjectMember(true);
- else if (BaseType->isObjCObjectPointerType() ||
- BaseType.isObjCGCStrong())
- Record->setHasObjectMember(true);
- }
+ else if (BaseType->isObjCObjectPointerType() ||
+ BaseType.isObjCGCStrong())
+ Record->setHasObjectMember(true);
}
}
+ if (Record && FD->getType().isVolatileQualified())
+ Record->setHasVolatileMember(true);
// Keep track of the number of named members.
if (FD->getIdentifier())
++NumNamedMembers;
@@ -10316,14 +11022,14 @@ void Sema::ActOnFields(Scope* S,
if (CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(Record)) {
if (!CXXRecord->isInvalidDecl()) {
// Set access bits correctly on the directly-declared conversions.
- UnresolvedSetImpl *Convs = CXXRecord->getConversionFunctions();
- for (UnresolvedSetIterator I = Convs->begin(), E = Convs->end();
- I != E; ++I)
- Convs->setAccess(I, (*I)->getAccess());
+ for (CXXRecordDecl::conversion_iterator
+ I = CXXRecord->conversion_begin(),
+ E = CXXRecord->conversion_end(); I != E; ++I)
+ I.setAccess((*I)->getAccess());
if (!CXXRecord->isDependentType()) {
// Adjust user-defined destructor exception spec.
- if (getLangOpts().CPlusPlus0x &&
+ if (getLangOpts().CPlusPlus11 &&
CXXRecord->hasUserDeclaredDestructor())
AdjustDestructorExceptionSpec(CXXRecord,CXXRecord->getDestructor());
@@ -10376,6 +11082,8 @@ void Sema::ActOnFields(Scope* S,
if (!Completed)
Record->completeDefinition();
+ if (Record->hasAttrs())
+ CheckAlignasUnderalignment(Record);
} else {
ObjCIvarDecl **ClsFields =
reinterpret_cast<ObjCIvarDecl**>(RecFields.data());
@@ -10418,11 +11126,12 @@ void Sema::ActOnFields(Scope* S,
Diag(ClsIvar->getLocation(), diag::note_previous_definition);
continue;
}
- for (const ObjCCategoryDecl *ClsExtDecl =
- IDecl->getFirstClassExtension();
- ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) {
- if (const ObjCIvarDecl *ClsExtIvar =
- ClsExtDecl->getIvarDecl(ClsFields[i]->getIdentifier())) {
+ for (ObjCInterfaceDecl::known_extensions_iterator
+ Ext = IDecl->known_extensions_begin(),
+ ExtEnd = IDecl->known_extensions_end();
+ Ext != ExtEnd; ++Ext) {
+ if (const ObjCIvarDecl *ClsExtIvar
+ = Ext->getIvarDecl(ClsFields[i]->getIdentifier())) {
Diag(ClsFields[i]->getLocation(),
diag::err_duplicate_ivar_declaration);
Diag(ClsExtIvar->getLocation(), diag::note_previous_definition);
@@ -10503,7 +11212,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
EltTy = Context.DependentTy;
else {
SourceLocation ExpLoc;
- if (getLangOpts().CPlusPlus0x && Enum->isFixed() &&
+ if (getLangOpts().CPlusPlus11 && Enum->isFixed() &&
!getLangOpts().MicrosoftMode) {
// C++11 [dcl.enum]p5: If the underlying type is fixed, [...] the
// constant-expression in the enumerator-definition shall be a converted
@@ -10722,6 +11431,182 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
return New;
}
+// Returns true when the enum initial expression does not trigger the
+// duplicate enum warning. A few common cases are exempted as follows:
+// Element2 = Element1
+// Element2 = Element1 + 1
+// Element2 = Element1 - 1
+// Where Element2 and Element1 are from the same enum.
+static bool ValidDuplicateEnum(EnumConstantDecl *ECD, EnumDecl *Enum) {
+ Expr *InitExpr = ECD->getInitExpr();
+ if (!InitExpr)
+ return true;
+ InitExpr = InitExpr->IgnoreImpCasts();
+
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(InitExpr)) {
+ if (!BO->isAdditiveOp())
+ return true;
+ IntegerLiteral *IL = dyn_cast<IntegerLiteral>(BO->getRHS());
+ if (!IL)
+ return true;
+ if (IL->getValue() != 1)
+ return true;
+
+ InitExpr = BO->getLHS();
+ }
+
+ // This checks if the elements are from the same enum.
+ DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(InitExpr);
+ if (!DRE)
+ return true;
+
+ EnumConstantDecl *EnumConstant = dyn_cast<EnumConstantDecl>(DRE->getDecl());
+ if (!EnumConstant)
+ return true;
+
+ if (cast<EnumDecl>(TagDecl::castFromDeclContext(ECD->getDeclContext())) !=
+ Enum)
+ return true;
+
+ return false;
+}
+
+struct DupKey {
+ int64_t val;
+ bool isTombstoneOrEmptyKey;
+ DupKey(int64_t val, bool isTombstoneOrEmptyKey)
+ : val(val), isTombstoneOrEmptyKey(isTombstoneOrEmptyKey) {}
+};
+
+static DupKey GetDupKey(const llvm::APSInt& Val) {
+ return DupKey(Val.isSigned() ? Val.getSExtValue() : Val.getZExtValue(),
+ false);
+}
+
+struct DenseMapInfoDupKey {
+ static DupKey getEmptyKey() { return DupKey(0, true); }
+ static DupKey getTombstoneKey() { return DupKey(1, true); }
+ static unsigned getHashValue(const DupKey Key) {
+ return (unsigned)(Key.val * 37);
+ }
+ static bool isEqual(const DupKey& LHS, const DupKey& RHS) {
+ return LHS.isTombstoneOrEmptyKey == RHS.isTombstoneOrEmptyKey &&
+ LHS.val == RHS.val;
+ }
+};
+
+// Emits a warning when an element is implicitly set a value that
+// a previous element has already been set to.
+static void CheckForDuplicateEnumValues(Sema &S, Decl **Elements,
+ unsigned NumElements, EnumDecl *Enum,
+ QualType EnumType) {
+ if (S.Diags.getDiagnosticLevel(diag::warn_duplicate_enum_values,
+ Enum->getLocation()) ==
+ DiagnosticsEngine::Ignored)
+ return;
+ // Avoid anonymous enums
+ if (!Enum->getIdentifier())
+ return;
+
+ // Only check for small enums.
+ if (Enum->getNumPositiveBits() > 63 || Enum->getNumNegativeBits() > 64)
+ return;
+
+ typedef SmallVector<EnumConstantDecl *, 3> ECDVector;
+ typedef SmallVector<ECDVector *, 3> DuplicatesVector;
+
+ typedef llvm::PointerUnion<EnumConstantDecl*, ECDVector*> DeclOrVector;
+ typedef llvm::DenseMap<DupKey, DeclOrVector, DenseMapInfoDupKey>
+ ValueToVectorMap;
+
+ DuplicatesVector DupVector;
+ ValueToVectorMap EnumMap;
+
+ // Populate the EnumMap with all values represented by enum constants without
+ // an initialier.
+ for (unsigned i = 0; i < NumElements; ++i) {
+ EnumConstantDecl *ECD = cast<EnumConstantDecl>(Elements[i]);
+
+ // Null EnumConstantDecl means a previous diagnostic has been emitted for
+ // this constant. Skip this enum since it may be ill-formed.
+ if (!ECD) {
+ return;
+ }
+
+ if (ECD->getInitExpr())
+ continue;
+
+ DupKey Key = GetDupKey(ECD->getInitVal());
+ DeclOrVector &Entry = EnumMap[Key];
+
+ // First time encountering this value.
+ if (Entry.isNull())
+ Entry = ECD;
+ }
+
+ // Create vectors for any values that has duplicates.
+ for (unsigned i = 0; i < NumElements; ++i) {
+ EnumConstantDecl *ECD = cast<EnumConstantDecl>(Elements[i]);
+ if (!ValidDuplicateEnum(ECD, Enum))
+ continue;
+
+ DupKey Key = GetDupKey(ECD->getInitVal());
+
+ DeclOrVector& Entry = EnumMap[Key];
+ if (Entry.isNull())
+ continue;
+
+ if (EnumConstantDecl *D = Entry.dyn_cast<EnumConstantDecl*>()) {
+ // Ensure constants are different.
+ if (D == ECD)
+ continue;
+
+ // Create new vector and push values onto it.
+ ECDVector *Vec = new ECDVector();
+ Vec->push_back(D);
+ Vec->push_back(ECD);
+
+ // Update entry to point to the duplicates vector.
+ Entry = Vec;
+
+ // Store the vector somewhere we can consult later for quick emission of
+ // diagnostics.
+ DupVector.push_back(Vec);
+ continue;
+ }
+
+ ECDVector *Vec = Entry.get<ECDVector*>();
+ // Make sure constants are not added more than once.
+ if (*Vec->begin() == ECD)
+ continue;
+
+ Vec->push_back(ECD);
+ }
+
+ // Emit diagnostics.
+ for (DuplicatesVector::iterator DupVectorIter = DupVector.begin(),
+ DupVectorEnd = DupVector.end();
+ DupVectorIter != DupVectorEnd; ++DupVectorIter) {
+ ECDVector *Vec = *DupVectorIter;
+ assert(Vec->size() > 1 && "ECDVector should have at least 2 elements.");
+
+ // Emit warning for one enum constant.
+ ECDVector::iterator I = Vec->begin();
+ S.Diag((*I)->getLocation(), diag::warn_duplicate_enum_values)
+ << (*I)->getName() << (*I)->getInitVal().toString(10)
+ << (*I)->getSourceRange();
+ ++I;
+
+ // Emit one note for each of the remaining enum constants with
+ // the same value.
+ for (ECDVector::iterator E = Vec->end(); I != E; ++I)
+ S.Diag((*I)->getLocation(), diag::note_duplicate_element)
+ << (*I)->getName() << (*I)->getInitVal().toString(10)
+ << (*I)->getSourceRange();
+ delete Vec;
+ }
+}
+
void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
SourceLocation RBraceLoc, Decl *EnumDeclX,
Decl **Elements, unsigned NumElements,
@@ -10944,6 +11829,12 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
// it needs to go into the function scope.
if (InFunctionDeclarator)
DeclsInPrototypeScope.push_back(Enum);
+
+ CheckForDuplicateEnumValues(*this, Elements, NumElements, Enum, EnumType);
+
+ // Now that the enum type is defined, ensure it's not been underaligned.
+ if (Enum->hasAttrs())
+ CheckAlignasUnderalignment(Enum);
}
Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr,
@@ -10967,7 +11858,7 @@ DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc,
if (!Mod)
return true;
- llvm::SmallVector<SourceLocation, 2> IdentifierLocs;
+ SmallVector<SourceLocation, 2> IdentifierLocs;
Module *ModCheck = Mod;
for (unsigned I = 0, N = Path.size(); I != N; ++I) {
// If we've run out of module parents, just drop the remaining identifiers.
@@ -10987,6 +11878,19 @@ DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc,
return Import;
}
+void Sema::createImplicitModuleImport(SourceLocation Loc, Module *Mod) {
+ // Create the implicit import declaration.
+ TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl();
+ ImportDecl *ImportD = ImportDecl::CreateImplicit(getASTContext(), TU,
+ Loc, Mod, Loc);
+ TU->addDecl(ImportD);
+ Consumer.HandleImplicitImportDecl(ImportD);
+
+ // Make the module visible.
+ PP.getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, Loc,
+ /*Complain=*/false);
+}
+
void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name,
IdentifierInfo* AliasName,
SourceLocation PragmaLoc,
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index e326a20..982e7a5 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -16,14 +16,17 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/Mangle.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/DelayedDiagnostic.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Scope.h"
#include "llvm/ADT/StringExtras.h"
using namespace clang;
using namespace sema;
@@ -37,6 +40,7 @@ enum AttributeDeclKind {
ExpectedFunctionOrMethod,
ExpectedParameter,
ExpectedFunctionMethodOrBlock,
+ ExpectedFunctionMethodOrClass,
ExpectedFunctionMethodOrParameter,
ExpectedClass,
ExpectedVariable,
@@ -44,7 +48,11 @@ enum AttributeDeclKind {
ExpectedVariableFunctionOrLabel,
ExpectedFieldOrGlobalVar,
ExpectedStruct,
- ExpectedTLSVar
+ ExpectedVariableFunctionOrTag,
+ ExpectedTLSVar,
+ ExpectedVariableOrField,
+ ExpectedVariableFieldOrTag,
+ ExpectedTypeOrNamespace
};
//===----------------------------------------------------------------------===//
@@ -293,12 +301,12 @@ static bool isIntOrBool(Expr *Exp) {
static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordType* RT) {
DeclContextLookupConstResult Res1 = RT->getDecl()->lookup(
S.Context.DeclarationNames.getCXXOperatorName(OO_Star));
- if (Res1.first == Res1.second)
+ if (Res1.empty())
return false;
DeclContextLookupConstResult Res2 = RT->getDecl()->lookup(
S.Context.DeclarationNames.getCXXOperatorName(OO_Arrow));
- if (Res2.first == Res2.second)
+ if (Res2.empty())
return false;
return true;
@@ -503,18 +511,22 @@ static void handleGuardedVarAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!checkGuardedVarAttrCommon(S, D, Attr))
return;
- D->addAttr(::new (S.Context) GuardedVarAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ GuardedVarAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handlePtGuardedVarAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
+ const AttributeList &Attr) {
if (!checkGuardedVarAttrCommon(S, D, Attr))
return;
if (!threadSafetyCheckIsPointer(S, D, Attr))
return;
- D->addAttr(::new (S.Context) PtGuardedVarAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ PtGuardedVarAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static bool checkGuardedByAttrCommon(Sema &S, Decl *D,
@@ -594,11 +606,13 @@ static void handleScopedLockableAttr(Sema &S, Decl *D,
if (!checkLockableAttrCommon(S, D, Attr))
return;
- D->addAttr(::new (S.Context) ScopedLockableAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ ScopedLockableAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
-static void handleNoThreadSafetyAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
+static void handleNoThreadSafetyAnalysis(Sema &S, Decl *D,
+ const AttributeList &Attr) {
assert(!Attr.isInvalid());
if (!checkAttributeNumArgs(S, Attr, 0))
@@ -614,7 +628,7 @@ static void handleNoThreadSafetyAttr(Sema &S, Decl *D,
S.Context));
}
-static void handleNoAddressSafetyAttr(Sema &S, Decl *D,
+static void handleNoSanitizeAddressAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
assert(!Attr.isInvalid());
@@ -622,13 +636,48 @@ static void handleNoAddressSafetyAttr(Sema &S, Decl *D,
return;
if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedFunctionOrMethod;
+ return;
+ }
+
+ D->addAttr(::new (S.Context)
+ NoSanitizeAddressAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
+}
+
+static void handleNoSanitizeMemory(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ assert(!Attr.isInvalid());
+
+ if (!checkAttributeNumArgs(S, Attr, 0))
+ return;
+
+ if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedFunctionOrMethod;
+ return;
+ }
+
+ D->addAttr(::new (S.Context) NoSanitizeMemoryAttr(Attr.getRange(),
+ S.Context));
+}
+
+static void handleNoSanitizeThread(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ assert(!Attr.isInvalid());
+
+ if (!checkAttributeNumArgs(S, Attr, 0))
+ return;
+
+ if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunctionOrMethod;
return;
}
- D->addAttr(::new (S.Context) NoAddressSafetyAnalysisAttr(Attr.getRange(),
- S.Context));
+ D->addAttr(::new (S.Context) NoSanitizeThreadAttr(Attr.getRange(),
+ S.Context));
}
static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D,
@@ -673,8 +722,10 @@ static void handleAcquiredAfterAttr(Sema &S, Decl *D,
return;
Expr **StartArg = &Args[0];
- D->addAttr(::new (S.Context) AcquiredAfterAttr(Attr.getRange(), S.Context,
- StartArg, Args.size()));
+ D->addAttr(::new (S.Context)
+ AcquiredAfterAttr(Attr.getRange(), S.Context,
+ StartArg, Args.size(),
+ Attr.getAttributeSpellingListIndex()));
}
static void handleAcquiredBeforeAttr(Sema &S, Decl *D,
@@ -684,8 +735,10 @@ static void handleAcquiredBeforeAttr(Sema &S, Decl *D,
return;
Expr **StartArg = &Args[0];
- D->addAttr(::new (S.Context) AcquiredBeforeAttr(Attr.getRange(), S.Context,
- StartArg, Args.size()));
+ D->addAttr(::new (S.Context)
+ AcquiredBeforeAttr(Attr.getRange(), S.Context,
+ StartArg, Args.size(),
+ Attr.getAttributeSpellingListIndex()));
}
static bool checkLockFunAttrCommon(Sema &S, Decl *D,
@@ -716,9 +769,9 @@ static void handleSharedLockFunctionAttr(Sema &S, Decl *D,
unsigned Size = Args.size();
Expr **StartArg = Size == 0 ? 0 : &Args[0];
- D->addAttr(::new (S.Context) SharedLockFunctionAttr(Attr.getRange(),
- S.Context,
- StartArg, Size));
+ D->addAttr(::new (S.Context)
+ SharedLockFunctionAttr(Attr.getRange(), S.Context, StartArg, Size,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleExclusiveLockFunctionAttr(Sema &S, Decl *D,
@@ -729,9 +782,10 @@ static void handleExclusiveLockFunctionAttr(Sema &S, Decl *D,
unsigned Size = Args.size();
Expr **StartArg = Size == 0 ? 0 : &Args[0];
- D->addAttr(::new (S.Context) ExclusiveLockFunctionAttr(Attr.getRange(),
- S.Context,
- StartArg, Size));
+ D->addAttr(::new (S.Context)
+ ExclusiveLockFunctionAttr(Attr.getRange(), S.Context,
+ StartArg, Size,
+ Attr.getAttributeSpellingListIndex()));
}
static bool checkTryLockFunAttrCommon(Sema &S, Decl *D,
@@ -768,10 +822,10 @@ static void handleSharedTrylockFunctionAttr(Sema &S, Decl *D,
unsigned Size = Args.size();
Expr **StartArg = Size == 0 ? 0 : &Args[0];
- D->addAttr(::new (S.Context) SharedTrylockFunctionAttr(Attr.getRange(),
- S.Context,
- Attr.getArg(0),
- StartArg, Size));
+ D->addAttr(::new (S.Context)
+ SharedTrylockFunctionAttr(Attr.getRange(), S.Context,
+ Attr.getArg(0), StartArg, Size,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleExclusiveTrylockFunctionAttr(Sema &S, Decl *D,
@@ -782,10 +836,10 @@ static void handleExclusiveTrylockFunctionAttr(Sema &S, Decl *D,
unsigned Size = Args.size();
Expr **StartArg = Size == 0 ? 0 : &Args[0];
- D->addAttr(::new (S.Context) ExclusiveTrylockFunctionAttr(Attr.getRange(),
- S.Context,
- Attr.getArg(0),
- StartArg, Size));
+ D->addAttr(::new (S.Context)
+ ExclusiveTrylockFunctionAttr(Attr.getRange(), S.Context,
+ Attr.getArg(0), StartArg, Size,
+ Attr.getAttributeSpellingListIndex()));
}
static bool checkLocksRequiredCommon(Sema &S, Decl *D,
@@ -817,10 +871,10 @@ static void handleExclusiveLocksRequiredAttr(Sema &S, Decl *D,
return;
Expr **StartArg = &Args[0];
- D->addAttr(::new (S.Context) ExclusiveLocksRequiredAttr(Attr.getRange(),
- S.Context,
- StartArg,
- Args.size()));
+ D->addAttr(::new (S.Context)
+ ExclusiveLocksRequiredAttr(Attr.getRange(), S.Context,
+ StartArg, Args.size(),
+ Attr.getAttributeSpellingListIndex()));
}
static void handleSharedLocksRequiredAttr(Sema &S, Decl *D,
@@ -830,10 +884,10 @@ static void handleSharedLocksRequiredAttr(Sema &S, Decl *D,
return;
Expr **StartArg = &Args[0];
- D->addAttr(::new (S.Context) SharedLocksRequiredAttr(Attr.getRange(),
- S.Context,
- StartArg,
- Args.size()));
+ D->addAttr(::new (S.Context)
+ SharedLocksRequiredAttr(Attr.getRange(), S.Context,
+ StartArg, Args.size(),
+ Attr.getAttributeSpellingListIndex()));
}
static void handleUnlockFunAttr(Sema &S, Decl *D,
@@ -854,8 +908,9 @@ static void handleUnlockFunAttr(Sema &S, Decl *D,
unsigned Size = Args.size();
Expr **StartArg = Size == 0 ? 0 : &Args[0];
- D->addAttr(::new (S.Context) UnlockFunctionAttr(Attr.getRange(), S.Context,
- StartArg, Size));
+ D->addAttr(::new (S.Context)
+ UnlockFunctionAttr(Attr.getRange(), S.Context, StartArg, Size,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleLockReturnedAttr(Sema &S, Decl *D,
@@ -878,8 +933,9 @@ static void handleLockReturnedAttr(Sema &S, Decl *D,
if (Size == 0)
return;
- D->addAttr(::new (S.Context) LockReturnedAttr(Attr.getRange(), S.Context,
- Args[0]));
+ D->addAttr(::new (S.Context)
+ LockReturnedAttr(Attr.getRange(), S.Context, Args[0],
+ Attr.getAttributeSpellingListIndex()));
}
static void handleLocksExcludedAttr(Sema &S, Decl *D,
@@ -903,54 +959,24 @@ static void handleLocksExcludedAttr(Sema &S, Decl *D,
return;
Expr **StartArg = &Args[0];
- D->addAttr(::new (S.Context) LocksExcludedAttr(Attr.getRange(), S.Context,
- StartArg, Size));
+ D->addAttr(::new (S.Context)
+ LocksExcludedAttr(Attr.getRange(), S.Context, StartArg, Size,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleExtVectorTypeAttr(Sema &S, Scope *scope, Decl *D,
const AttributeList &Attr) {
- TypedefNameDecl *tDecl = dyn_cast<TypedefNameDecl>(D);
- if (tDecl == 0) {
+ TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D);
+ if (TD == 0) {
+ // __attribute__((ext_vector_type(N))) can only be applied to typedefs
+ // and type-ids.
S.Diag(Attr.getLoc(), diag::err_typecheck_ext_vector_not_typedef);
return;
}
- QualType curType = tDecl->getUnderlyingType();
-
- Expr *sizeExpr;
-
- // Special case where the argument is a template id.
- if (Attr.getParameterName()) {
- CXXScopeSpec SS;
- SourceLocation TemplateKWLoc;
- UnqualifiedId id;
- id.setIdentifier(Attr.getParameterName(), Attr.getLoc());
-
- ExprResult Size = S.ActOnIdExpression(scope, SS, TemplateKWLoc, id,
- false, false);
- if (Size.isInvalid())
- return;
-
- sizeExpr = Size.get();
- } else {
- // check the attribute arguments.
- if (!checkAttributeNumArgs(S, Attr, 1))
- return;
-
- sizeExpr = Attr.getArg(0);
- }
-
- // Instantiate/Install the vector type, and let Sema build the type for us.
- // This will run the reguired checks.
- QualType T = S.BuildExtVectorType(curType, sizeExpr, Attr.getLoc());
- if (!T.isNull()) {
- // FIXME: preserve the old source info.
- tDecl->setTypeSourceInfo(S.Context.getTrivialTypeSourceInfo(T));
-
- // Remember this typedef decl, we will need it later for diagnostics.
- S.ExtVectorDecls.push_back(tDecl);
- }
+ // Remember this typedef decl, we will need it later for diagnostics.
+ S.ExtVectorDecls.push_back(TD);
}
static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -969,14 +995,18 @@ static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored_for_field_of_type)
<< Attr.getName() << FD->getType();
else
- FD->addAttr(::new (S.Context) PackedAttr(Attr.getRange(), S.Context));
+ FD->addAttr(::new (S.Context)
+ PackedAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
} else
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
}
static void handleMsStructAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (RecordDecl *RD = dyn_cast<RecordDecl>(D))
- RD->addAttr(::new (S.Context) MsStructAttr(Attr.getRange(), S.Context));
+ RD->addAttr(::new (S.Context)
+ MsStructAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
else
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
}
@@ -989,7 +1019,9 @@ static void handleIBAction(Sema &S, Decl *D, const AttributeList &Attr) {
// The IBAction attributes only apply to instance methods.
if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
if (MD->isInstanceMethod()) {
- D->addAttr(::new (S.Context) IBActionAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ IBActionAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
return;
}
@@ -1030,7 +1062,9 @@ static void handleIBOutlet(Sema &S, Decl *D, const AttributeList &Attr) {
if (!checkIBOutletCommon(S, D, Attr))
return;
- D->addAttr(::new (S.Context) IBOutletAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ IBOutletAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleIBOutletCollection(Sema &S, Decl *D,
@@ -1064,8 +1098,10 @@ static void handleIBOutletCollection(Sema &S, Decl *D,
S.Diag(Attr.getLoc(), diag::err_iboutletcollection_type) << II;
return;
}
- D->addAttr(::new (S.Context) IBOutletCollectionAttr(Attr.getRange(),S.Context,
- QT, Attr.getParameterLoc()));
+ D->addAttr(::new (S.Context)
+ IBOutletCollectionAttr(Attr.getRange(),S.Context,
+ QT, Attr.getParameterLoc(),
+ Attr.getAttributeSpellingListIndex()));
}
static void possibleTransparentUnionPointerType(QualType &T) {
@@ -1096,7 +1132,11 @@ static void handleAllocSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// In C++ the implicit 'this' function parameter also counts, and they are
// counted from one.
bool HasImplicitThisParam = isInstanceMethod(D);
- unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
+ unsigned NumArgs;
+ if (hasFunctionProto(D))
+ NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
+ else
+ NumArgs = 0;
SmallVector<unsigned, 8> SizeArgs;
@@ -1148,8 +1188,10 @@ static void handleAllocSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
<< "alloc_size" << 0 /*function*/<< 1 /*pointer*/ << D->getSourceRange();
}
- D->addAttr(::new (S.Context) AllocSizeAttr(Attr.getRange(), S.Context,
- SizeArgs.data(), SizeArgs.size()));
+ D->addAttr(::new (S.Context)
+ AllocSizeAttr(Attr.getRange(), S.Context,
+ SizeArgs.data(), SizeArgs.size(),
+ Attr.getAttributeSpellingListIndex()));
}
static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1164,15 +1206,13 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// In C++ the implicit 'this' function parameter also counts, and they are
// counted from one.
bool HasImplicitThisParam = isInstanceMethod(D);
- unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
+ unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
// The nonnull attribute only applies to pointers.
SmallVector<unsigned, 10> NonNullArgs;
- for (AttributeList::arg_iterator I=Attr.arg_begin(),
- E=Attr.arg_end(); I!=E; ++I) {
-
-
+ for (AttributeList::arg_iterator I = Attr.arg_begin(),
+ E = Attr.arg_end(); I != E; ++I) {
// The argument must be an integer constant expression.
Expr *Ex = *I;
llvm::APSInt ArgNum(32);
@@ -1219,11 +1259,11 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// If no arguments were specified to __attribute__((nonnull)) then all pointer
// arguments have a nonnull attribute.
if (NonNullArgs.empty()) {
- for (unsigned I = 0, E = getFunctionOrMethodNumArgs(D); I != E; ++I) {
- QualType T = getFunctionOrMethodArgType(D, I).getNonReferenceType();
+ for (unsigned i = 0, e = getFunctionOrMethodNumArgs(D); i != e; ++i) {
+ QualType T = getFunctionOrMethodArgType(D, i).getNonReferenceType();
possibleTransparentUnionPointerType(T);
if (T->isAnyPointerType() || T->isBlockPointerType())
- NonNullArgs.push_back(I);
+ NonNullArgs.push_back(i);
}
// No pointer arguments?
@@ -1236,11 +1276,12 @@ static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
}
- unsigned* start = &NonNullArgs[0];
+ unsigned *start = &NonNullArgs[0];
unsigned size = NonNullArgs.size();
llvm::array_pod_sort(start, start + size);
- D->addAttr(::new (S.Context) NonNullAttr(Attr.getRange(), S.Context, start,
- size));
+ D->addAttr(::new (S.Context)
+ NonNullAttr(Attr.getRange(), S.Context, start, size,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) {
@@ -1395,27 +1436,9 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const AttributeList &AL) {
return;
}
- D->addAttr(::new (S.Context) OwnershipAttr(AL.getLoc(), S.Context, K, Module,
- start, size));
-}
-
-/// Whether this declaration has internal linkage for the purposes of
-/// things that want to complain about things not have internal linkage.
-static bool hasEffectivelyInternalLinkage(NamedDecl *D) {
- switch (D->getLinkage()) {
- case NoLinkage:
- case InternalLinkage:
- return true;
-
- // Template instantiations that go from external to unique-external
- // shouldn't get diagnosed.
- case UniqueExternalLinkage:
- return true;
-
- case ExternalLinkage:
- return false;
- }
- llvm_unreachable("unknown linkage kind!");
+ D->addAttr(::new (S.Context)
+ OwnershipAttr(AL.getLoc(), S.Context, K, Module, start, size,
+ AL.getAttributeSpellingListIndex()));
}
static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1468,11 +1491,6 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// This looks like a bug in gcc. We reject that for now. We should revisit
// it if this behaviour is actually used.
- if (!hasEffectivelyInternalLinkage(nd)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_weakref_not_static);
- return;
- }
-
// GCC rejects
// static ((alias ("y"), weakref)).
// Should we? How to check that weakref is before or after alias?
@@ -1493,7 +1511,9 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) {
Str->getString()));
}
- D->addAttr(::new (S.Context) WeakRefAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ WeakRefAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1521,7 +1541,8 @@ static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// FIXME: check if target symbol exists in current file
D->addAttr(::new (S.Context) AliasAttr(Attr.getRange(), S.Context,
- Str->getString()));
+ Str->getString(),
+ Attr.getAttributeSpellingListIndex()));
}
static void handleMinSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1535,7 +1556,9 @@ static void handleMinSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) MinSizeAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ MinSizeAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleColdAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1555,7 +1578,8 @@ static void handleColdAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) ColdAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context) ColdAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleHotAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1575,7 +1599,8 @@ static void handleHotAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) HotAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context) HotAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1589,7 +1614,9 @@ static void handleNakedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) NakedAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ NakedAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleAlwaysInlineAttr(Sema &S, Decl *D,
@@ -1606,7 +1633,9 @@ static void handleAlwaysInlineAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context) AlwaysInlineAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ AlwaysInlineAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleTLSModelAttr(Sema &S, Decl *D,
@@ -1641,8 +1670,9 @@ static void handleTLSModelAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context) TLSModelAttr(Attr.getRange(), S.Context,
- Model));
+ D->addAttr(::new (S.Context)
+ TLSModelAttr(Attr.getRange(), S.Context, Model,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleMallocAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1655,7 +1685,9 @@ static void handleMallocAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
QualType RetTy = FD->getResultType();
if (RetTy->isAnyPointerType() || RetTy->isBlockPointerType()) {
- D->addAttr(::new (S.Context) MallocAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ MallocAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
return;
}
}
@@ -1668,13 +1700,17 @@ static void handleMayAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!checkAttributeNumArgs(S, Attr, 0))
return;
- D->addAttr(::new (S.Context) MayAliasAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ MayAliasAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleNoCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) {
assert(!Attr.isInvalid());
if (isa<VarDecl>(D))
- D->addAttr(::new (S.Context) NoCommonAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ NoCommonAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
else
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedVariable;
@@ -1683,7 +1719,9 @@ static void handleNoCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) {
static void handleCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) {
assert(!Attr.isInvalid());
if (isa<VarDecl>(D))
- D->addAttr(::new (S.Context) CommonAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ CommonAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
else
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedVariable;
@@ -1700,7 +1738,9 @@ static void handleNoReturnAttr(Sema &S, Decl *D, const AttributeList &attr) {
return;
}
- D->addAttr(::new (S.Context) NoReturnAttr(attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ NoReturnAttr(attr.getRange(), S.Context,
+ attr.getAttributeSpellingListIndex()));
}
bool Sema::CheckNoReturnAttr(const AttributeList &attr) {
@@ -1727,14 +1767,33 @@ static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D,
if (VD == 0 || (!VD->getType()->isBlockPointerType()
&& !VD->getType()->isFunctionPointerType())) {
S.Diag(Attr.getLoc(),
- Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type
+ Attr.isCXX11Attribute() ? diag::err_attribute_wrong_decl_type
: diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunctionMethodOrBlock;
return;
}
}
- D->addAttr(::new (S.Context) AnalyzerNoReturnAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ AnalyzerNoReturnAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
+}
+
+static void handleCXX11NoReturnAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ // C++11 [dcl.attr.noreturn]p1:
+ // The attribute may be applied to the declarator-id in a function
+ // declaration.
+ FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
+ if (!FD) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedFunctionOrMethod;
+ return;
+ }
+
+ D->addAttr(::new (S.Context)
+ CXX11NoReturnAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
// PS3 PPU-specific.
@@ -1795,16 +1854,30 @@ static void handleVecReturnAttr(Sema &S, Decl *D, const AttributeList &Attr) {
count++;
}
- D->addAttr(::new (S.Context) VecReturnAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ VecReturnAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
-static void handleDependencyAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (!isFunctionOrMethod(D) && !isa<ParmVarDecl>(D)) {
+static void handleDependencyAttr(Sema &S, Scope *Scope, Decl *D,
+ const AttributeList &Attr) {
+ if (isa<ParmVarDecl>(D)) {
+ // [[carries_dependency]] can only be applied to a parameter if it is a
+ // parameter of a function declaration or lambda.
+ if (!(Scope->getFlags() & clang::Scope::FunctionDeclarationScope)) {
+ S.Diag(Attr.getLoc(),
+ diag::err_carries_dependency_param_not_function_decl);
+ return;
+ }
+ } else if (!isa<FunctionDecl>(D)) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedFunctionMethodOrParameter;
return;
}
- // FIXME: Actually store the attribute on the declaration
+
+ D->addAttr(::new (S.Context) CarriesDependencyAttr(
+ Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1821,7 +1894,9 @@ static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) UnusedAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ UnusedAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleReturnsTwiceAttr(Sema &S, Decl *D,
@@ -1838,7 +1913,9 @@ static void handleReturnsTwiceAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context) ReturnsTwiceAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ ReturnsTwiceAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1859,7 +1936,9 @@ static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) UsedAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ UsedAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleConstructorAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1888,8 +1967,9 @@ static void handleConstructorAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) ConstructorAttr(Attr.getRange(), S.Context,
- priority));
+ D->addAttr(::new (S.Context)
+ ConstructorAttr(Attr.getRange(), S.Context, priority,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleDestructorAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -1918,8 +1998,9 @@ static void handleDestructorAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) DestructorAttr(Attr.getRange(), S.Context,
- priority));
+ D->addAttr(::new (S.Context)
+ DestructorAttr(Attr.getRange(), S.Context, priority,
+ Attr.getAttributeSpellingListIndex()));
}
template <typename AttrTy>
@@ -1943,7 +2024,8 @@ static void handleAttrWithMessage(Sema &S, Decl *D, const AttributeList &Attr,
Str = SE->getString();
}
- D->addAttr(::new (S.Context) AttrTy(Attr.getRange(), S.Context, Str));
+ D->addAttr(::new (S.Context) AttrTy(Attr.getRange(), S.Context, Str,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleArcWeakrefUnavailableAttr(Sema &S, Decl *D,
@@ -1954,8 +2036,9 @@ static void handleArcWeakrefUnavailableAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context) ArcWeakrefUnavailableAttr(
- Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ ArcWeakrefUnavailableAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleObjCRootClassAttr(Sema &S, Decl *D,
@@ -1971,11 +2054,13 @@ static void handleObjCRootClassAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context) ObjCRootClassAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ ObjCRootClassAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
-static void handleObjCRequiresPropertyDefsAttr(Sema &S, Decl *D,
- const AttributeList &Attr) {
+static void handleObjCRequiresPropertyDefsAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
if (!isa<ObjCInterfaceDecl>(D)) {
S.Diag(Attr.getLoc(), diag::err_suppress_autosynthesis);
return;
@@ -1987,8 +2072,9 @@ static void handleObjCRequiresPropertyDefsAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context) ObjCRequiresPropertyDefsAttr(
- Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ ObjCRequiresPropertyDefsAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static bool checkAvailabilityAttr(Sema &S, SourceRange Range,
@@ -2030,13 +2116,33 @@ static bool checkAvailabilityAttr(Sema &S, SourceRange Range,
return false;
}
-AvailabilityAttr *Sema::mergeAvailabilityAttr(Decl *D, SourceRange Range,
+/// \brief Check whether the two versions match.
+///
+/// If either version tuple is empty, then they are assumed to match. If
+/// \p BeforeIsOkay is true, then \p X can be less than or equal to \p Y.
+static bool versionsMatch(const VersionTuple &X, const VersionTuple &Y,
+ bool BeforeIsOkay) {
+ if (X.empty() || Y.empty())
+ return true;
+
+ if (X == Y)
+ return true;
+
+ if (BeforeIsOkay && X < Y)
+ return true;
+
+ return false;
+}
+
+AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range,
IdentifierInfo *Platform,
VersionTuple Introduced,
VersionTuple Deprecated,
VersionTuple Obsoleted,
bool IsUnavailable,
- StringRef Message) {
+ StringRef Message,
+ bool Override,
+ unsigned AttrSpellingListIndex) {
VersionTuple MergedIntroduced = Introduced;
VersionTuple MergedDeprecated = Deprecated;
VersionTuple MergedObsoleted = Obsoleted;
@@ -2062,18 +2168,47 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(Decl *D, SourceRange Range,
VersionTuple OldDeprecated = OldAA->getDeprecated();
VersionTuple OldObsoleted = OldAA->getObsoleted();
bool OldIsUnavailable = OldAA->getUnavailable();
- StringRef OldMessage = OldAA->getMessage();
-
- if ((!OldIntroduced.empty() && !Introduced.empty() &&
- OldIntroduced != Introduced) ||
- (!OldDeprecated.empty() && !Deprecated.empty() &&
- OldDeprecated != Deprecated) ||
- (!OldObsoleted.empty() && !Obsoleted.empty() &&
- OldObsoleted != Obsoleted) ||
- (OldIsUnavailable != IsUnavailable) ||
- (OldMessage != Message)) {
- Diag(OldAA->getLocation(), diag::warn_mismatched_availability);
- Diag(Range.getBegin(), diag::note_previous_attribute);
+
+ if (!versionsMatch(OldIntroduced, Introduced, Override) ||
+ !versionsMatch(Deprecated, OldDeprecated, Override) ||
+ !versionsMatch(Obsoleted, OldObsoleted, Override) ||
+ !(OldIsUnavailable == IsUnavailable ||
+ (Override && !OldIsUnavailable && IsUnavailable))) {
+ if (Override) {
+ int Which = -1;
+ VersionTuple FirstVersion;
+ VersionTuple SecondVersion;
+ if (!versionsMatch(OldIntroduced, Introduced, Override)) {
+ Which = 0;
+ FirstVersion = OldIntroduced;
+ SecondVersion = Introduced;
+ } else if (!versionsMatch(Deprecated, OldDeprecated, Override)) {
+ Which = 1;
+ FirstVersion = Deprecated;
+ SecondVersion = OldDeprecated;
+ } else if (!versionsMatch(Obsoleted, OldObsoleted, Override)) {
+ Which = 2;
+ FirstVersion = Obsoleted;
+ SecondVersion = OldObsoleted;
+ }
+
+ if (Which == -1) {
+ Diag(OldAA->getLocation(),
+ diag::warn_mismatched_availability_override_unavail)
+ << AvailabilityAttr::getPrettyPlatformName(Platform->getName());
+ } else {
+ Diag(OldAA->getLocation(),
+ diag::warn_mismatched_availability_override)
+ << Which
+ << AvailabilityAttr::getPrettyPlatformName(Platform->getName())
+ << FirstVersion.getAsString() << SecondVersion.getAsString();
+ }
+ Diag(Range.getBegin(), diag::note_overridden_method);
+ } else {
+ Diag(OldAA->getLocation(), diag::warn_mismatched_availability);
+ Diag(Range.getBegin(), diag::note_previous_attribute);
+ }
+
Attrs.erase(Attrs.begin() + i);
--e;
continue;
@@ -2115,7 +2250,8 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(Decl *D, SourceRange Range,
MergedDeprecated, MergedObsoleted)) {
return ::new (Context) AvailabilityAttr(Range, Context, Platform,
Introduced, Deprecated,
- Obsoleted, IsUnavailable, Message);
+ Obsoleted, IsUnavailable, Message,
+ AttrSpellingListIndex);
}
return NULL;
}
@@ -2124,11 +2260,18 @@ static void handleAvailabilityAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
IdentifierInfo *Platform = Attr.getParameterName();
SourceLocation PlatformLoc = Attr.getParameterLoc();
-
+ unsigned Index = Attr.getAttributeSpellingListIndex();
+
if (AvailabilityAttr::getPrettyPlatformName(Platform->getName()).empty())
S.Diag(PlatformLoc, diag::warn_availability_unknown_platform)
<< Platform;
+ NamedDecl *ND = dyn_cast<NamedDecl>(D);
+ if (!ND) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
+ return;
+ }
+
AvailabilityChange Introduced = Attr.getAvailabilityIntroduced();
AvailabilityChange Deprecated = Attr.getAvailabilityDeprecated();
AvailabilityChange Obsoleted = Attr.getAvailabilityObsoleted();
@@ -2139,37 +2282,69 @@ static void handleAvailabilityAttr(Sema &S, Decl *D,
if (SE)
Str = SE->getString();
- AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(D, Attr.getRange(),
+ AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, Attr.getRange(),
Platform,
Introduced.Version,
Deprecated.Version,
Obsoleted.Version,
- IsUnavailable, Str);
+ IsUnavailable, Str,
+ /*Override=*/false,
+ Index);
if (NewAttr)
D->addAttr(NewAttr);
}
+template <class T>
+static T *mergeVisibilityAttr(Sema &S, Decl *D, SourceRange range,
+ typename T::VisibilityType value,
+ unsigned attrSpellingListIndex) {
+ T *existingAttr = D->getAttr<T>();
+ if (existingAttr) {
+ typename T::VisibilityType existingValue = existingAttr->getVisibility();
+ if (existingValue == value)
+ return NULL;
+ S.Diag(existingAttr->getLocation(), diag::err_mismatched_visibility);
+ S.Diag(range.getBegin(), diag::note_previous_attribute);
+ D->dropAttr<T>();
+ }
+ return ::new (S.Context) T(range, S.Context, value, attrSpellingListIndex);
+}
+
VisibilityAttr *Sema::mergeVisibilityAttr(Decl *D, SourceRange Range,
- VisibilityAttr::VisibilityType Vis) {
+ VisibilityAttr::VisibilityType Vis,
+ unsigned AttrSpellingListIndex) {
+ return ::mergeVisibilityAttr<VisibilityAttr>(*this, D, Range, Vis,
+ AttrSpellingListIndex);
+}
+
+TypeVisibilityAttr *Sema::mergeTypeVisibilityAttr(Decl *D, SourceRange Range,
+ TypeVisibilityAttr::VisibilityType Vis,
+ unsigned AttrSpellingListIndex) {
+ return ::mergeVisibilityAttr<TypeVisibilityAttr>(*this, D, Range, Vis,
+ AttrSpellingListIndex);
+}
+
+static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr,
+ bool isTypeVisibility) {
+ // Visibility attributes don't mean anything on a typedef.
if (isa<TypedefNameDecl>(D)) {
- Diag(Range.getBegin(), diag::warn_attribute_ignored) << "visibility";
- return NULL;
+ S.Diag(Attr.getRange().getBegin(), diag::warn_attribute_ignored)
+ << Attr.getName();
+ return;
}
- VisibilityAttr *ExistingAttr = D->getAttr<VisibilityAttr>();
- if (ExistingAttr) {
- VisibilityAttr::VisibilityType ExistingVis = ExistingAttr->getVisibility();
- if (ExistingVis == Vis)
- return NULL;
- Diag(ExistingAttr->getLocation(), diag::err_mismatched_visibility);
- Diag(Range.getBegin(), diag::note_previous_attribute);
- D->dropAttr<VisibilityAttr>();
+
+ // 'type_visibility' can only go on a type or namespace.
+ if (isTypeVisibility &&
+ !(isa<TagDecl>(D) ||
+ isa<ObjCInterfaceDecl>(D) ||
+ isa<NamespaceDecl>(D))) {
+ S.Diag(Attr.getRange().getBegin(), diag::err_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedTypeOrNamespace;
+ return;
}
- return ::new (Context) VisibilityAttr(Range, Context, Vis);
-}
-static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// check the attribute arguments.
- if(!checkAttributeNumArgs(S, Attr, 1))
+ if (!checkAttributeNumArgs(S, Attr, 1))
return;
Expr *Arg = Attr.getArg(0);
@@ -2178,13 +2353,13 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!Str || !Str->isAscii()) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string)
- << "visibility" << 1;
+ << (isTypeVisibility ? "type_visibility" : "visibility") << 1;
return;
}
StringRef TypeStr = Str->getString();
VisibilityAttr::VisibilityType type;
-
+
if (TypeStr == "default")
type = VisibilityAttr::Default;
else if (TypeStr == "hidden")
@@ -2205,9 +2380,17 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- VisibilityAttr *NewAttr = S.mergeVisibilityAttr(D, Attr.getRange(), type);
- if (NewAttr)
- D->addAttr(NewAttr);
+ unsigned Index = Attr.getAttributeSpellingListIndex();
+ clang::Attr *newAttr;
+ if (isTypeVisibility) {
+ newAttr = S.mergeTypeVisibilityAttr(D, Attr.getRange(),
+ (TypeVisibilityAttr::VisibilityType) type,
+ Index);
+ } else {
+ newAttr = S.mergeVisibilityAttr(D, Attr.getRange(), type, Index);
+ }
+ if (newAttr)
+ D->addAttr(newAttr);
}
static void handleObjCMethodFamilyAttr(Sema &S, Decl *decl,
@@ -2274,7 +2457,9 @@ static void handleObjCExceptionAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context) ObjCExceptionAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ ObjCExceptionAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -2305,7 +2490,9 @@ static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) {
// case.
S.Diag(D->getLocation(), diag::warn_nsobject_attribute);
}
- D->addAttr(::new (S.Context) ObjCNSObjectAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ ObjCNSObjectAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void
@@ -2320,7 +2507,9 @@ handleOverloadableAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) OverloadableAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ OverloadableAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleBlocksAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -2344,7 +2533,9 @@ static void handleBlocksAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) BlocksAttr(Attr.getRange(), S.Context, type));
+ D->addAttr(::new (S.Context)
+ BlocksAttr(Attr.getRange(), S.Context, type,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -2436,8 +2627,9 @@ static void handleSentinelAttr(Sema &S, Decl *D, const AttributeList &Attr) {
<< Attr.getName() << ExpectedFunctionMethodOrBlock;
return;
}
- D->addAttr(::new (S.Context) SentinelAttr(Attr.getRange(), S.Context, sentinel,
- nullPos));
+ D->addAttr(::new (S.Context)
+ SentinelAttr(Attr.getRange(), S.Context, sentinel, nullPos,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -2445,9 +2637,9 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr)
if (!checkAttributeNumArgs(S, Attr, 0))
return;
- if (!isFunction(D) && !isa<ObjCMethodDecl>(D)) {
+ if (!isFunction(D) && !isa<ObjCMethodDecl>(D) && !isa<CXXRecordDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << ExpectedFunctionOrMethod;
+ << Attr.getName() << ExpectedFunctionMethodOrClass;
return;
}
@@ -2463,7 +2655,9 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr)
return;
}
- D->addAttr(::new (S.Context) WarnUnusedResultAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ WarnUnusedResultAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleWeakAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -2485,13 +2679,9 @@ static void handleWeakAttr(Sema &S, Decl *D, const AttributeList &Attr) {
NamedDecl *nd = cast<NamedDecl>(D);
- // 'weak' only applies to declarations with external linkage.
- if (hasEffectivelyInternalLinkage(nd)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_weak_static);
- return;
- }
-
- nd->addAttr(::new (S.Context) WeakAttr(Attr.getRange(), S.Context));
+ nd->addAttr(::new (S.Context)
+ WeakAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -2518,7 +2708,9 @@ static void handleWeakImportAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) WeakImportAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ WeakImportAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
// Handles reqd_work_group_size and work_group_size_hint.
@@ -2568,15 +2760,57 @@ static void handleWorkGroupSize(Sema &S, Decl *D,
if (Attr.getKind() == AttributeList::AT_ReqdWorkGroupSize)
D->addAttr(::new (S.Context)
ReqdWorkGroupSizeAttr(Attr.getRange(), S.Context,
- WGSize[0], WGSize[1], WGSize[2]));
+ WGSize[0], WGSize[1], WGSize[2],
+ Attr.getAttributeSpellingListIndex()));
else
D->addAttr(::new (S.Context)
WorkGroupSizeHintAttr(Attr.getRange(), S.Context,
- WGSize[0], WGSize[1], WGSize[2]));
+ WGSize[0], WGSize[1], WGSize[2],
+ Attr.getAttributeSpellingListIndex()));
+}
+
+static void handleVecTypeHint(Sema &S, Decl *D, const AttributeList &Attr) {
+ assert(Attr.getKind() == AttributeList::AT_VecTypeHint);
+
+ // Attribute has 1 argument.
+ if (!checkAttributeNumArgs(S, Attr, 1))
+ return;
+
+ QualType ParmType = S.GetTypeFromParser(Attr.getTypeArg());
+
+ if (!ParmType->isExtVectorType() && !ParmType->isFloatingType() &&
+ (ParmType->isBooleanType() ||
+ !ParmType->isIntegralType(S.getASTContext()))) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_vec_type_hint)
+ << ParmType;
+ return;
+ }
+
+ if (Attr.getKind() == AttributeList::AT_VecTypeHint &&
+ D->hasAttr<VecTypeHintAttr>()) {
+ VecTypeHintAttr *A = D->getAttr<VecTypeHintAttr>();
+ if (A->getTypeHint() != ParmType) {
+ S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) << Attr.getName();
+ return;
+ }
+ }
+
+ D->addAttr(::new (S.Context) VecTypeHintAttr(Attr.getLoc(), S.Context,
+ ParmType, Attr.getLoc()));
+}
+
+static void handleEndianAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (!dyn_cast<VarDecl>(D))
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << "endian"
+ << 9;
+ StringRef EndianType = Attr.getParameterName()->getName();
+ if (EndianType != "host" && EndianType != "device")
+ S.Diag(Attr.getLoc(), diag::warn_attribute_unknown_endian) << EndianType;
}
SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range,
- StringRef Name) {
+ StringRef Name,
+ unsigned AttrSpellingListIndex) {
if (SectionAttr *ExistingAttr = D->getAttr<SectionAttr>()) {
if (ExistingAttr->getName() == Name)
return NULL;
@@ -2584,7 +2818,8 @@ SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range,
Diag(Range.getBegin(), diag::note_previous_attribute);
return NULL;
}
- return ::new (Context) SectionAttr(Range, Context, Name);
+ return ::new (Context) SectionAttr(Range, Context, Name,
+ AttrSpellingListIndex);
}
static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -2614,8 +2849,10 @@ static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) {
S.Diag(SE->getLocStart(), diag::err_attribute_section_local_variable);
return;
}
+
+ unsigned Index = Attr.getAttributeSpellingListIndex();
SectionAttr *NewAttr = S.mergeSectionAttr(D, Attr.getRange(),
- SE->getString());
+ SE->getString(), Index);
if (NewAttr)
D->addAttr(NewAttr);
}
@@ -2632,7 +2869,9 @@ static void handleNothrowAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (Existing->getLocation().isInvalid())
Existing->setRange(Attr.getRange());
} else {
- D->addAttr(::new (S.Context) NoThrowAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ NoThrowAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
}
@@ -2647,7 +2886,9 @@ static void handleConstAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (Existing->getLocation().isInvalid())
Existing->setRange(Attr.getRange());
} else {
- D->addAttr(::new (S.Context) ConstAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ ConstAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex() ));
}
}
@@ -2656,7 +2897,9 @@ static void handlePureAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!checkAttributeNumArgs(S, Attr, 0))
return;
- D->addAttr(::new (S.Context) PureAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ PureAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -2715,8 +2958,11 @@ static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) CleanupAttr(Attr.getRange(), S.Context, FD));
+ D->addAttr(::new (S.Context)
+ CleanupAttr(Attr.getRange(), S.Context, FD,
+ Attr.getAttributeSpellingListIndex()));
S.MarkFunctionReferenced(Attr.getParameterLoc(), FD);
+ S.DiagnoseUseOfDecl(FD, Attr.getParameterLoc());
}
/// Handle __attribute__((format_arg((idx)))) attribute based on
@@ -2790,8 +3036,9 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) FormatArgAttr(Attr.getRange(), S.Context,
- Idx.getZExtValue()));
+ D->addAttr(::new (S.Context)
+ FormatArgAttr(Attr.getRange(), S.Context, Idx.getZExtValue(),
+ Attr.getAttributeSpellingListIndex()));
}
enum FormatAttrKind {
@@ -2866,12 +3113,14 @@ static void handleInitPriorityAttr(Sema &S, Decl *D,
Attr.setInvalid();
return;
}
- D->addAttr(::new (S.Context) InitPriorityAttr(Attr.getRange(), S.Context,
- prioritynum));
+ D->addAttr(::new (S.Context)
+ InitPriorityAttr(Attr.getRange(), S.Context, prioritynum,
+ Attr.getAttributeSpellingListIndex()));
}
FormatAttr *Sema::mergeFormatAttr(Decl *D, SourceRange Range, StringRef Format,
- int FormatIdx, int FirstArg) {
+ int FormatIdx, int FirstArg,
+ unsigned AttrSpellingListIndex) {
// Check whether we already have an equivalent format attribute.
for (specific_attr_iterator<FormatAttr>
i = D->specific_attr_begin<FormatAttr>(),
@@ -2889,8 +3138,8 @@ FormatAttr *Sema::mergeFormatAttr(Decl *D, SourceRange Range, StringRef Format,
}
}
- return ::new (Context) FormatAttr(Range, Context, Format, FormatIdx,
- FirstArg);
+ return ::new (Context) FormatAttr(Range, Context, Format, FormatIdx, FirstArg,
+ AttrSpellingListIndex);
}
/// Handle __attribute__((format(type,idx,firstarg))) attributes based on
@@ -3030,7 +3279,8 @@ static void handleFormatAttr(Sema &S, Decl *D, const AttributeList &Attr) {
FormatAttr *NewAttr = S.mergeFormatAttr(D, Attr.getRange(), Format,
Idx.getZExtValue(),
- FirstArg.getZExtValue());
+ FirstArg.getZExtValue(),
+ Attr.getAttributeSpellingListIndex());
if (NewAttr)
D->addAttr(NewAttr);
}
@@ -3099,7 +3349,9 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D,
}
}
- RD->addAttr(::new (S.Context) TransparentUnionAttr(Attr.getRange(), S.Context));
+ RD->addAttr(::new (S.Context)
+ TransparentUnionAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleAnnotateAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -3124,8 +3376,10 @@ static void handleAnnotateAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if ((*i)->getAnnotation() == SE->getString())
return;
}
- D->addAttr(::new (S.Context) AnnotateAttr(Attr.getRange(), S.Context,
- SE->getString()));
+
+ D->addAttr(::new (S.Context)
+ AnnotateAttr(Attr.getRange(), S.Context, SE->getString(),
+ Attr.getAttributeSpellingListIndex()));
}
static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -3135,34 +3389,77 @@ static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- //FIXME: The C++0x version of this attribute has more limited applicabilty
- // than GNU's, and should error out when it is used to specify a
- // weaker alignment, rather than being silently ignored.
-
if (Attr.getNumArgs() == 0) {
- D->addAttr(::new (S.Context) AlignedAttr(Attr.getRange(), S.Context,
- true, 0, Attr.isDeclspecAttribute()));
+ D->addAttr(::new (S.Context) AlignedAttr(Attr.getRange(), S.Context,
+ true, 0, Attr.getAttributeSpellingListIndex()));
return;
}
- S.AddAlignedAttr(Attr.getRange(), D, Attr.getArg(0),
- Attr.isDeclspecAttribute());
-}
+ Expr *E = Attr.getArg(0);
+ if (Attr.isPackExpansion() && !E->containsUnexpandedParameterPack()) {
+ S.Diag(Attr.getEllipsisLoc(),
+ diag::err_pack_expansion_without_parameter_packs);
+ return;
+ }
-void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
- bool isDeclSpec) {
- // FIXME: Handle pack-expansions here.
- if (DiagnoseUnexpandedParameterPack(E))
+ if (!Attr.isPackExpansion() && S.DiagnoseUnexpandedParameterPack(E))
return;
+ S.AddAlignedAttr(Attr.getRange(), D, E, Attr.getAttributeSpellingListIndex(),
+ Attr.isPackExpansion());
+}
+
+void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
+ unsigned SpellingListIndex, bool IsPackExpansion) {
+ AlignedAttr TmpAttr(AttrRange, Context, true, E, SpellingListIndex);
+ SourceLocation AttrLoc = AttrRange.getBegin();
+
+ // C++11 alignas(...) and C11 _Alignas(...) have additional requirements.
+ if (TmpAttr.isAlignas()) {
+ // C++11 [dcl.align]p1:
+ // An alignment-specifier may be applied to a variable or to a class
+ // data member, but it shall not be applied to a bit-field, a function
+ // parameter, the formal parameter of a catch clause, or a variable
+ // declared with the register storage class specifier. An
+ // alignment-specifier may also be applied to the declaration of a class
+ // or enumeration type.
+ // C11 6.7.5/2:
+ // An alignment attribute shall not be specified in a declaration of
+ // a typedef, or a bit-field, or a function, or a parameter, or an
+ // object declared with the register storage-class specifier.
+ int DiagKind = -1;
+ if (isa<ParmVarDecl>(D)) {
+ DiagKind = 0;
+ } else if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (VD->getStorageClass() == SC_Register)
+ DiagKind = 1;
+ if (VD->isExceptionVariable())
+ DiagKind = 2;
+ } else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
+ if (FD->isBitField())
+ DiagKind = 3;
+ } else if (!isa<TagDecl>(D)) {
+ Diag(AttrLoc, diag::err_attribute_wrong_decl_type)
+ << (TmpAttr.isC11() ? "'_Alignas'" : "'alignas'")
+ << (TmpAttr.isC11() ? ExpectedVariableOrField
+ : ExpectedVariableFieldOrTag);
+ return;
+ }
+ if (DiagKind != -1) {
+ Diag(AttrLoc, diag::err_alignas_attribute_wrong_decl_type)
+ << TmpAttr.isC11() << DiagKind;
+ return;
+ }
+ }
+
if (E->isTypeDependent() || E->isValueDependent()) {
// Save dependent expressions in the AST to be instantiated.
- D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, true, E,
- isDeclSpec));
+ AlignedAttr *AA = ::new (Context) AlignedAttr(TmpAttr);
+ AA->setPackExpansion(IsPackExpansion);
+ D->addAttr(AA);
return;
}
-
- SourceLocation AttrLoc = AttrRange.getBegin();
+
// FIXME: Cache the number on the Attr object?
llvm::APSInt Alignment(32);
ExprResult ICE
@@ -3171,32 +3468,79 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E,
/*AllowFold*/ false);
if (ICE.isInvalid())
return;
- if (!llvm::isPowerOf2_64(Alignment.getZExtValue())) {
+
+ // C++11 [dcl.align]p2:
+ // -- if the constant expression evaluates to zero, the alignment
+ // specifier shall have no effect
+ // C11 6.7.5p6:
+ // An alignment specification of zero has no effect.
+ if (!(TmpAttr.isAlignas() && !Alignment) &&
+ !llvm::isPowerOf2_64(Alignment.getZExtValue())) {
Diag(AttrLoc, diag::err_attribute_aligned_not_power_of_two)
<< E->getSourceRange();
return;
}
- if (isDeclSpec) {
+
+ if (TmpAttr.isDeclspec()) {
// We've already verified it's a power of 2, now let's make sure it's
// 8192 or less.
if (Alignment.getZExtValue() > 8192) {
- Diag(AttrLoc, diag::err_attribute_aligned_greater_than_8192)
+ Diag(AttrLoc, diag::err_attribute_aligned_greater_than_8192)
<< E->getSourceRange();
return;
}
}
- D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, true, ICE.take(),
- isDeclSpec));
+ AlignedAttr *AA = ::new (Context) AlignedAttr(AttrRange, Context, true,
+ ICE.take(), SpellingListIndex);
+ AA->setPackExpansion(IsPackExpansion);
+ D->addAttr(AA);
}
-void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *TS,
- bool isDeclSpec) {
+void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *TS,
+ unsigned SpellingListIndex, bool IsPackExpansion) {
// FIXME: Cache the number on the Attr object if non-dependent?
// FIXME: Perform checking of type validity
- D->addAttr(::new (Context) AlignedAttr(AttrRange, Context, false, TS,
- isDeclSpec));
- return;
+ AlignedAttr *AA = ::new (Context) AlignedAttr(AttrRange, Context, false, TS,
+ SpellingListIndex);
+ AA->setPackExpansion(IsPackExpansion);
+ D->addAttr(AA);
+}
+
+void Sema::CheckAlignasUnderalignment(Decl *D) {
+ assert(D->hasAttrs() && "no attributes on decl");
+
+ QualType Ty;
+ if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
+ Ty = VD->getType();
+ else
+ Ty = Context.getTagDeclType(cast<TagDecl>(D));
+ if (Ty->isDependentType() || Ty->isIncompleteType())
+ return;
+
+ // C++11 [dcl.align]p5, C11 6.7.5/4:
+ // The combined effect of all alignment attributes in a declaration shall
+ // not specify an alignment that is less strict than the alignment that
+ // would otherwise be required for the entity being declared.
+ AlignedAttr *AlignasAttr = 0;
+ unsigned Align = 0;
+ for (specific_attr_iterator<AlignedAttr>
+ I = D->specific_attr_begin<AlignedAttr>(),
+ E = D->specific_attr_end<AlignedAttr>(); I != E; ++I) {
+ if (I->isAlignmentDependent())
+ return;
+ if (I->isAlignas())
+ AlignasAttr = *I;
+ Align = std::max(Align, I->getAlignment(Context));
+ }
+
+ if (AlignasAttr && Align) {
+ CharUnits RequestedAlign = Context.toCharUnitsFromBits(Align);
+ CharUnits NaturalAlign = Context.getTypeAlignInChars(Ty);
+ if (NaturalAlign > RequestedAlign)
+ Diag(AlignasAttr->getLocation(), diag::err_alignas_underaligned)
+ << Ty << (unsigned)NaturalAlign.getQuantity();
+ }
}
/// handleModeAttr - This attribute modifies the width of a decl with primitive
@@ -3260,6 +3604,10 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (Str == "pointer")
DestWidth = S.Context.getTargetInfo().getPointerWidth(0);
break;
+ case 11:
+ if (Str == "unwind_word")
+ DestWidth = S.Context.getTargetInfo().getUnwindWordWidth();
+ break;
}
QualType OldTy;
@@ -3386,7 +3734,9 @@ static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) NoDebugAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ NoDebugAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleNoInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -3401,7 +3751,9 @@ static void handleNoInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) NoInlineAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ NoInlineAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleNoInstrumentFunctionAttr(Sema &S, Decl *D,
@@ -3417,8 +3769,9 @@ static void handleNoInstrumentFunctionAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context) NoInstrumentFunctionAttr(Attr.getRange(),
- S.Context));
+ D->addAttr(::new (S.Context)
+ NoInstrumentFunctionAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleConstantAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -3435,7 +3788,9 @@ static void handleConstantAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) CUDAConstantAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ CUDAConstantAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
} else {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "constant";
}
@@ -3455,7 +3810,9 @@ static void handleDeviceAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) CUDADeviceAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ CUDADeviceAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
} else {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "device";
}
@@ -3476,10 +3833,10 @@ static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) {
FunctionDecl *FD = cast<FunctionDecl>(D);
if (!FD->getResultType()->isVoidType()) {
TypeLoc TL = FD->getTypeSourceInfo()->getTypeLoc().IgnoreParens();
- if (FunctionTypeLoc* FTL = dyn_cast<FunctionTypeLoc>(&TL)) {
+ if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) {
S.Diag(FD->getTypeSpecStartLoc(), diag::err_kern_type_not_void_return)
<< FD->getType()
- << FixItHint::CreateReplacement(FTL->getResultLoc().getSourceRange(),
+ << FixItHint::CreateReplacement(FTL.getResultLoc().getSourceRange(),
"void");
} else {
S.Diag(FD->getTypeSpecStartLoc(), diag::err_kern_type_not_void_return)
@@ -3488,7 +3845,9 @@ static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) CUDAGlobalAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ CUDAGlobalAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
} else {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "global";
}
@@ -3507,7 +3866,9 @@ static void handleHostAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) CUDAHostAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ CUDAHostAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
} else {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "host";
}
@@ -3519,14 +3880,15 @@ static void handleSharedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!checkAttributeNumArgs(S, Attr, 0))
return;
-
if (!isa<VarDecl>(D)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << ExpectedVariable;
return;
}
- D->addAttr(::new (S.Context) CUDASharedAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ CUDASharedAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
} else {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "shared";
}
@@ -3549,16 +3911,19 @@ static void handleGNUInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) GNUInlineAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ GNUInlineAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (hasDeclarator(D)) return;
+ const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
// Diagnostic is emitted elsewhere: here we store the (valid) Attr
// in the Decl node for syntactic reasoning, e.g., pretty-printing.
CallingConv CC;
- if (S.CheckCallingConvAttr(Attr, CC))
+ if (S.CheckCallingConvAttr(Attr, CC, FD))
return;
if (!isa<ObjCMethodDecl>(D)) {
@@ -3569,19 +3934,29 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) {
switch (Attr.getKind()) {
case AttributeList::AT_FastCall:
- D->addAttr(::new (S.Context) FastCallAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ FastCallAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
return;
case AttributeList::AT_StdCall:
- D->addAttr(::new (S.Context) StdCallAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ StdCallAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
return;
case AttributeList::AT_ThisCall:
- D->addAttr(::new (S.Context) ThisCallAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ ThisCallAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
return;
case AttributeList::AT_CDecl:
- D->addAttr(::new (S.Context) CDeclAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ CDeclAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
return;
case AttributeList::AT_Pascal:
- D->addAttr(::new (S.Context) PascalAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ PascalAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
return;
case AttributeList::AT_Pcs: {
PcsAttr::PCSType PCS;
@@ -3596,11 +3971,20 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) {
llvm_unreachable("unexpected calling convention in pcs attribute");
}
- D->addAttr(::new (S.Context) PcsAttr(Attr.getRange(), S.Context, PCS));
+ D->addAttr(::new (S.Context)
+ PcsAttr(Attr.getRange(), S.Context, PCS,
+ Attr.getAttributeSpellingListIndex()));
return;
}
case AttributeList::AT_PnaclCall:
- D->addAttr(::new (S.Context) PnaclCallAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ PnaclCallAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
+ return;
+ case AttributeList::AT_IntelOclBicc:
+ D->addAttr(::new (S.Context)
+ IntelOclBiccAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
return;
default:
@@ -3613,7 +3997,24 @@ static void handleOpenCLKernelAttr(Sema &S, Decl *D, const AttributeList &Attr){
D->addAttr(::new (S.Context) OpenCLKernelAttr(Attr.getRange(), S.Context));
}
-bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) {
+static void handleOpenCLImageAccessAttr(Sema &S, Decl *D, const AttributeList &Attr){
+ assert(!Attr.isInvalid());
+
+ Expr *E = Attr.getArg(0);
+ llvm::APSInt ArgNum(32);
+ if (E->isTypeDependent() || E->isValueDependent() ||
+ !E->isIntegerConstantExpr(ArgNum, S.Context)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
+ << Attr.getName()->getName() << E->getSourceRange();
+ return;
+ }
+
+ D->addAttr(::new (S.Context) OpenCLImageAccessAttr(
+ Attr.getRange(), S.Context, ArgNum.getZExtValue()));
+}
+
+bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
+ const FunctionDecl *FD) {
if (attr.isInvalid())
return true;
@@ -3656,6 +4057,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) {
return true;
}
case AttributeList::AT_PnaclCall: CC = CC_PnaclCall; break;
+ case AttributeList::AT_IntelOclBicc: CC = CC_IntelOclBicc; break;
default: llvm_unreachable("unexpected attribute kind");
}
@@ -3663,7 +4065,12 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) {
TargetInfo::CallingConvCheckResult A = TI.checkCallingConvention(CC);
if (A == TargetInfo::CCCR_Warning) {
Diag(attr.getLoc(), diag::warn_cconv_ignored) << attr.getName();
- CC = TI.getDefaultCallingConv();
+
+ TargetInfo::CallingConvMethodType MT = TargetInfo::CCMT_Unknown;
+ if (FD)
+ MT = FD->isCXXInstanceMember() ? TargetInfo::CCMT_Member :
+ TargetInfo::CCMT_NonMember;
+ CC = TI.getDefaultCallingConv(MT);
}
return false;
@@ -3682,7 +4089,9 @@ static void handleRegparmAttr(Sema &S, Decl *D, const AttributeList &Attr) {
return;
}
- D->addAttr(::new (S.Context) RegparmAttr(Attr.getRange(), S.Context, numParams));
+ D->addAttr(::new (S.Context)
+ RegparmAttr(Attr.getRange(), S.Context, numParams,
+ Attr.getAttributeSpellingListIndex()));
}
/// Checks a regparm attribute, returning true if it is ill-formed and
@@ -3762,9 +4171,11 @@ static void handleLaunchBoundsAttr(Sema &S, Decl *D, const AttributeList &Attr){
}
}
- D->addAttr(::new (S.Context) CUDALaunchBoundsAttr(Attr.getRange(), S.Context,
- MaxThreads.getZExtValue(),
- MinBlocks.getZExtValue()));
+ D->addAttr(::new (S.Context)
+ CUDALaunchBoundsAttr(Attr.getRange(), S.Context,
+ MaxThreads.getZExtValue(),
+ MinBlocks.getZExtValue(),
+ Attr.getAttributeSpellingListIndex()));
} else {
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "launch_bounds";
}
@@ -3815,12 +4226,10 @@ static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D,
}
}
- D->addAttr(::new (S.Context) ArgumentWithTypeTagAttr(Attr.getRange(),
- S.Context,
- ArgumentKind,
- ArgumentIdx,
- TypeTagIdx,
- IsPointer));
+ D->addAttr(::new (S.Context)
+ ArgumentWithTypeTagAttr(Attr.getRange(), S.Context, ArgumentKind,
+ ArgumentIdx, TypeTagIdx, IsPointer,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D,
@@ -3834,13 +4243,12 @@ static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D,
QualType MatchingCType = S.GetTypeFromParser(Attr.getMatchingCType(), NULL);
- D->addAttr(::new (S.Context) TypeTagForDatatypeAttr(
- Attr.getRange(),
- S.Context,
- PointerKind,
- MatchingCType,
- Attr.getLayoutCompatible(),
- Attr.getMustBeNull()));
+ D->addAttr(::new (S.Context)
+ TypeTagForDatatypeAttr(Attr.getRange(), S.Context, PointerKind,
+ MatchingCType,
+ Attr.getLayoutCompatible(),
+ Attr.getMustBeNull(),
+ Attr.getAttributeSpellingListIndex()));
}
//===----------------------------------------------------------------------===//
@@ -3882,9 +4290,13 @@ static void handleNSConsumedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
if (cf)
- param->addAttr(::new (S.Context) CFConsumedAttr(Attr.getRange(), S.Context));
+ param->addAttr(::new (S.Context)
+ CFConsumedAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
else
- param->addAttr(::new (S.Context) NSConsumedAttr(Attr.getRange(), S.Context));
+ param->addAttr(::new (S.Context)
+ NSConsumedAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleNSConsumesSelfAttr(Sema &S, Decl *D,
@@ -3895,7 +4307,9 @@ static void handleNSConsumesSelfAttr(Sema &S, Decl *D,
return;
}
- D->addAttr(::new (S.Context) NSConsumesSelfAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ NSConsumesSelfAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
@@ -3947,24 +4361,29 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
default:
llvm_unreachable("invalid ownership attribute");
case AttributeList::AT_NSReturnsAutoreleased:
- D->addAttr(::new (S.Context) NSReturnsAutoreleasedAttr(Attr.getRange(),
- S.Context));
+ D->addAttr(::new (S.Context)
+ NSReturnsAutoreleasedAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
return;
case AttributeList::AT_CFReturnsNotRetained:
- D->addAttr(::new (S.Context) CFReturnsNotRetainedAttr(Attr.getRange(),
- S.Context));
+ D->addAttr(::new (S.Context)
+ CFReturnsNotRetainedAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
return;
case AttributeList::AT_NSReturnsNotRetained:
- D->addAttr(::new (S.Context) NSReturnsNotRetainedAttr(Attr.getRange(),
- S.Context));
+ D->addAttr(::new (S.Context)
+ NSReturnsNotRetainedAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
return;
case AttributeList::AT_CFReturnsRetained:
- D->addAttr(::new (S.Context) CFReturnsRetainedAttr(Attr.getRange(),
- S.Context));
+ D->addAttr(::new (S.Context)
+ CFReturnsRetainedAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
return;
case AttributeList::AT_NSReturnsRetained:
- D->addAttr(::new (S.Context) NSReturnsRetainedAttr(Attr.getRange(),
- S.Context));
+ D->addAttr(::new (S.Context)
+ NSReturnsRetainedAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
return;
};
}
@@ -3994,8 +4413,9 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D,
return;
}
- method->addAttr(
- ::new (S.Context) ObjCReturnsInnerPointerAttr(attr.getRange(), S.Context));
+ method->addAttr(::new (S.Context)
+ ObjCReturnsInnerPointerAttr(attr.getRange(), S.Context,
+ attr.getAttributeSpellingListIndex()));
}
static void handleObjCRequiresSuperAttr(Sema &S, Decl *D,
@@ -4021,8 +4441,9 @@ static void handleObjCRequiresSuperAttr(Sema &S, Decl *D,
return;
}
- method->addAttr(
- ::new (S.Context) ObjCRequiresSuperAttr(attr.getRange(), S.Context));
+ method->addAttr(::new (S.Context)
+ ObjCRequiresSuperAttr(attr.getRange(), S.Context,
+ attr.getAttributeSpellingListIndex()));
}
/// Handle cf_audited_transfer and cf_unknown_transfer.
@@ -4052,11 +4473,13 @@ static void handleCFTransferAttr(Sema &S, Decl *D, const AttributeList &A) {
// All clear; add the attribute.
if (IsAudited) {
- D->addAttr(
- ::new (S.Context) CFAuditedTransferAttr(A.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ CFAuditedTransferAttr(A.getRange(), S.Context,
+ A.getAttributeSpellingListIndex()));
} else {
- D->addAttr(
- ::new (S.Context) CFUnknownTransferAttr(A.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ CFUnknownTransferAttr(A.getRange(), S.Context,
+ A.getAttributeSpellingListIndex()));
}
}
@@ -4086,8 +4509,9 @@ static void handleNSBridgedAttr(Sema &S, Scope *Sc, Decl *D,
}
}
- D->addAttr(::new (S.Context) NSBridgedAttr(Attr.getRange(), S.Context,
- ParmName));
+ D->addAttr(::new (S.Context)
+ NSBridgedAttr(Attr.getRange(), S.Context, ParmName,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleObjCOwnershipAttr(Sema &S, Decl *D,
@@ -4141,7 +4565,8 @@ static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D,
}
D->addAttr(::new (S.Context)
- ObjCPreciseLifetimeAttr(Attr.getRange(), S.Context));
+ ObjCPreciseLifetimeAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
//===----------------------------------------------------------------------===//
@@ -4189,15 +4614,16 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) {
S.Diag(Attr.getLoc(), diag::err_attribute_uuid_malformed_guid);
return;
}
- } else if (!isxdigit(*I)) {
+ } else if (!isHexDigit(*I)) {
S.Diag(Attr.getLoc(), diag::err_attribute_uuid_malformed_guid);
return;
}
I++;
}
- D->addAttr(::new (S.Context) UuidAttr(Attr.getRange(), S.Context,
- Str->getString()));
+ D->addAttr(::new (S.Context)
+ UuidAttr(Attr.getRange(), S.Context, Str->getString(),
+ Attr.getAttributeSpellingListIndex()));
} else
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "uuid";
}
@@ -4211,13 +4637,19 @@ static void handleInheritanceAttr(Sema &S, Decl *D, const AttributeList &Attr) {
AttributeList::Kind Kind = Attr.getKind();
if (Kind == AttributeList::AT_SingleInheritance)
D->addAttr(
- ::new (S.Context) SingleInheritanceAttr(Attr.getRange(), S.Context));
+ ::new (S.Context)
+ SingleInheritanceAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
else if (Kind == AttributeList::AT_MultipleInheritance)
D->addAttr(
- ::new (S.Context) MultipleInheritanceAttr(Attr.getRange(), S.Context));
+ ::new (S.Context)
+ MultipleInheritanceAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
else if (Kind == AttributeList::AT_VirtualInheritance)
D->addAttr(
- ::new (S.Context) VirtualInheritanceAttr(Attr.getRange(), S.Context));
+ ::new (S.Context)
+ VirtualInheritanceAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
}
static void handlePortabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -4225,20 +4657,25 @@ static void handlePortabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) {
AttributeList::Kind Kind = Attr.getKind();
if (Kind == AttributeList::AT_Ptr32)
D->addAttr(
- ::new (S.Context) Ptr32Attr(Attr.getRange(), S.Context));
+ ::new (S.Context) Ptr32Attr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
else if (Kind == AttributeList::AT_Ptr64)
D->addAttr(
- ::new (S.Context) Ptr64Attr(Attr.getRange(), S.Context));
+ ::new (S.Context) Ptr64Attr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
else if (Kind == AttributeList::AT_Win64)
D->addAttr(
- ::new (S.Context) Win64Attr(Attr.getRange(), S.Context));
+ ::new (S.Context) Win64Attr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
} else
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
}
static void handleForceInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (S.LangOpts.MicrosoftExt)
- D->addAttr(::new (S.Context) ForceInlineAttr(Attr.getRange(), S.Context));
+ D->addAttr(::new (S.Context)
+ ForceInlineAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
else
S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
}
@@ -4261,12 +4698,11 @@ static void ProcessNonInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
const AttributeList &Attr) {
switch (Attr.getKind()) {
- case AttributeList::AT_IBAction: handleIBAction(S, D, Attr); break;
- case AttributeList::AT_IBOutlet: handleIBOutlet(S, D, Attr); break;
- case AttributeList::AT_IBOutletCollection:
- handleIBOutletCollection(S, D, Attr); break;
+ case AttributeList::AT_IBAction: handleIBAction(S, D, Attr); break;
+ case AttributeList::AT_IBOutlet: handleIBOutlet(S, D, Attr); break;
+ case AttributeList::AT_IBOutletCollection:
+ handleIBOutletCollection(S, D, Attr); break;
case AttributeList::AT_AddressSpace:
- case AttributeList::AT_OpenCLImageAccess:
case AttributeList::AT_ObjCGC:
case AttributeList::AT_VectorSize:
case AttributeList::AT_NeonVectorType:
@@ -4291,10 +4727,14 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_Annotate: handleAnnotateAttr (S, D, Attr); break;
case AttributeList::AT_Availability:handleAvailabilityAttr(S, D, Attr); break;
case AttributeList::AT_CarriesDependency:
- handleDependencyAttr (S, D, Attr); break;
+ handleDependencyAttr(S, scope, D, Attr);
+ break;
case AttributeList::AT_Common: handleCommonAttr (S, D, Attr); break;
case AttributeList::AT_CUDAConstant:handleConstantAttr (S, D, Attr); break;
case AttributeList::AT_Constructor: handleConstructorAttr (S, D, Attr); break;
+ case AttributeList::AT_CXX11NoReturn:
+ handleCXX11NoReturnAttr(S, D, Attr);
+ break;
case AttributeList::AT_Deprecated:
handleAttrWithMessage<DeprecatedAttr>(S, D, Attr, "deprecated");
break;
@@ -4364,6 +4804,13 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_ReqdWorkGroupSize:
handleWorkGroupSize(S, D, Attr); break;
+ case AttributeList::AT_VecTypeHint:
+ handleVecTypeHint(S, D, Attr); break;
+
+ case AttributeList::AT_Endian:
+ handleEndianAttr(S, D, Attr);
+ break;
+
case AttributeList::AT_InitPriority:
handleInitPriorityAttr(S, D, Attr); break;
@@ -4386,7 +4833,12 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
handleReturnsTwiceAttr(S, D, Attr);
break;
case AttributeList::AT_Used: handleUsedAttr (S, D, Attr); break;
- case AttributeList::AT_Visibility: handleVisibilityAttr (S, D, Attr); break;
+ case AttributeList::AT_Visibility:
+ handleVisibilityAttr(S, D, Attr, false);
+ break;
+ case AttributeList::AT_TypeVisibility:
+ handleVisibilityAttr(S, D, Attr, true);
+ break;
case AttributeList::AT_WarnUnusedResult: handleWarnUnusedResult(S, D, Attr);
break;
case AttributeList::AT_Weak: handleWeakAttr (S, D, Attr); break;
@@ -4423,11 +4875,15 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_Pascal:
case AttributeList::AT_Pcs:
case AttributeList::AT_PnaclCall:
+ case AttributeList::AT_IntelOclBicc:
handleCallConvAttr(S, D, Attr);
break;
case AttributeList::AT_OpenCLKernel:
handleOpenCLKernelAttr(S, D, Attr);
break;
+ case AttributeList::AT_OpenCLImageAccess:
+ handleOpenCLImageAccessAttr(S, D, Attr);
+ break;
// Microsoft attributes:
case AttributeList::AT_MsStruct:
@@ -4460,11 +4916,17 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_ScopedLockable:
handleScopedLockableAttr(S, D, Attr);
break;
- case AttributeList::AT_NoAddressSafetyAnalysis:
- handleNoAddressSafetyAttr(S, D, Attr);
+ case AttributeList::AT_NoSanitizeAddress:
+ handleNoSanitizeAddressAttr(S, D, Attr);
break;
case AttributeList::AT_NoThreadSafetyAnalysis:
- handleNoThreadSafetyAttr(S, D, Attr);
+ handleNoThreadSafetyAnalysis(S, D, Attr);
+ break;
+ case AttributeList::AT_NoSanitizeThread:
+ handleNoSanitizeThread(S, D, Attr);
+ break;
+ case AttributeList::AT_NoSanitizeMemory:
+ handleNoSanitizeMemory(S, D, Attr);
break;
case AttributeList::AT_Lockable:
handleLockableAttr(S, D, Attr);
@@ -4530,19 +4992,17 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D,
/// ProcessDeclAttribute - Apply the specific attribute to the specified decl if
/// the attribute applies to decls. If the attribute is a type attribute, just
-/// silently ignore it if a GNU attribute. FIXME: Applying a C++0x attribute to
-/// the wrong thing is illegal (C++0x [dcl.attr.grammar]/4).
+/// silently ignore it if a GNU attribute.
static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
const AttributeList &Attr,
- bool NonInheritable, bool Inheritable) {
+ bool NonInheritable, bool Inheritable,
+ bool IncludeCXX11Attributes) {
if (Attr.isInvalid())
return;
- // Type attributes are still treated as declaration attributes by
- // ParseMicrosoftTypeAttributes and ParseBorlandTypeAttributes. We don't
- // want to process them, however, because we will simply warn about ignoring
- // them. So instead, we will bail out early.
- if (Attr.isMSTypespecAttribute())
+ // Ignore C++11 attributes on declarator chunks: they appertain to the type
+ // instead.
+ if (Attr.isCXX11Attribute() && !IncludeCXX11Attributes)
return;
if (NonInheritable)
@@ -4556,17 +5016,19 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
/// attribute list to the specified decl, ignoring any type attributes.
void Sema::ProcessDeclAttributeList(Scope *S, Decl *D,
const AttributeList *AttrList,
- bool NonInheritable, bool Inheritable) {
- for (const AttributeList* l = AttrList; l; l = l->getNext()) {
- ProcessDeclAttribute(*this, S, D, *l, NonInheritable, Inheritable);
- }
+ bool NonInheritable, bool Inheritable,
+ bool IncludeCXX11Attributes) {
+ for (const AttributeList* l = AttrList; l; l = l->getNext())
+ ProcessDeclAttribute(*this, S, D, *l, NonInheritable, Inheritable,
+ IncludeCXX11Attributes);
// GCC accepts
// static int a9 __attribute__((weakref));
// but that looks really pointless. We reject it.
if (Inheritable && D->hasAttr<WeakRefAttr>() && !D->hasAttr<AliasAttr>()) {
Diag(AttrList->getLoc(), diag::err_attribute_weakref_without_alias) <<
- dyn_cast<NamedDecl>(D)->getNameAsString();
+ cast<NamedDecl>(D)->getNameAsString();
+ D->dropAttr<WeakRefAttr>();
return;
}
}
@@ -4592,7 +5054,7 @@ bool Sema::ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl,
static void checkUnusedDeclAttributes(Sema &S, const AttributeList *A) {
for ( ; A; A = A->getNext()) {
// Only warn if the attribute is an unignored, non-type attribute.
- if (A->isUsedAsTypeAttr()) continue;
+ if (A->isUsedAsTypeAttr() || A->isInvalid()) continue;
if (A->getKind() == AttributeList::IgnoredAttribute) continue;
if (A->getKind() == AttributeList::UnknownAttribute) {
@@ -4630,8 +5092,7 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II,
NewFD = FunctionDecl::Create(FD->getASTContext(), FD->getDeclContext(),
Loc, Loc, DeclarationName(II),
FD->getType(), FD->getTypeSourceInfo(),
- SC_None, SC_None,
- false/*isInlineSpecified*/,
+ SC_None, false/*isInlineSpecified*/,
FD->hasPrototype(),
false/*isConstexprSpecified*/);
NewD = NewFD;
@@ -4656,8 +5117,7 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II,
NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(),
VD->getInnerLocStart(), VD->getLocation(), II,
VD->getType(), VD->getTypeSourceInfo(),
- VD->getStorageClass(),
- VD->getStorageClassAsWritten());
+ VD->getStorageClass());
if (VD->getQualifier()) {
VarDecl *NewVD = cast<VarDecl>(NewD);
NewVD->setQualifierInfo(VD->getQualifierLoc());
@@ -4689,30 +5149,37 @@ void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) {
}
}
-/// ProcessDeclAttributes - Given a declarator (PD) with attributes indicated in
-/// it, apply them to D. This is a bit tricky because PD can have attributes
-/// specified in many different places, and we need to find and apply them all.
-void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD,
- bool NonInheritable, bool Inheritable) {
+void Sema::ProcessPragmaWeak(Scope *S, Decl *D) {
// It's valid to "forward-declare" #pragma weak, in which case we
// have to do this.
- if (Inheritable) {
- LoadExternalWeakUndeclaredIdentifiers();
- if (!WeakUndeclaredIdentifiers.empty()) {
- if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
- if (IdentifierInfo *Id = ND->getIdentifier()) {
- llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator I
- = WeakUndeclaredIdentifiers.find(Id);
- if (I != WeakUndeclaredIdentifiers.end() && ND->hasLinkage()) {
- WeakInfo W = I->second;
- DeclApplyPragmaWeak(S, ND, W);
- WeakUndeclaredIdentifiers[Id] = W;
- }
+ LoadExternalWeakUndeclaredIdentifiers();
+ if (!WeakUndeclaredIdentifiers.empty()) {
+ NamedDecl *ND = NULL;
+ if (VarDecl *VD = dyn_cast<VarDecl>(D))
+ if (VD->isExternC())
+ ND = VD;
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ if (FD->isExternC())
+ ND = FD;
+ if (ND) {
+ if (IdentifierInfo *Id = ND->getIdentifier()) {
+ llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator I
+ = WeakUndeclaredIdentifiers.find(Id);
+ if (I != WeakUndeclaredIdentifiers.end()) {
+ WeakInfo W = I->second;
+ DeclApplyPragmaWeak(S, ND, W);
+ WeakUndeclaredIdentifiers[Id] = W;
}
}
}
}
+}
+/// ProcessDeclAttributes - Given a declarator (PD) with attributes indicated in
+/// it, apply them to D. This is a bit tricky because PD can have attributes
+/// specified in many different places, and we need to find and apply them all.
+void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD,
+ bool NonInheritable, bool Inheritable) {
// Apply decl attributes from the DeclSpec if present.
if (const AttributeList *Attrs = PD.getDeclSpec().getAttributes().getList())
ProcessDeclAttributeList(S, D, Attrs, NonInheritable, Inheritable);
@@ -4723,7 +5190,8 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD,
// when X is a decl attribute.
for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i)
if (const AttributeList *Attrs = PD.getTypeObject(i).getAttrs())
- ProcessDeclAttributeList(S, D, Attrs, NonInheritable, Inheritable);
+ ProcessDeclAttributeList(S, D, Attrs, NonInheritable, Inheritable,
+ /*IncludeCXX11Attributes=*/false);
// Finally, apply any attributes on the decl itself.
if (const AttributeList *Attrs = PD.getAttributes())
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 16eddf8..35890e6 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -12,16 +12,11 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/CXXFieldCollector.h"
-#include "clang/Sema/Scope.h"
-#include "clang/Sema/Initialization.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/ScopeInfo.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
-#include "clang/AST/CharUnits.h"
#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/ExprCXX.h"
@@ -30,12 +25,18 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeOrdering.h"
-#include "clang/Sema/DeclSpec.h"
-#include "clang/Sema/ParsedTemplate.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
-#include "llvm/ADT/SmallString.h"
+#include "clang/Sema/CXXFieldCollector.h"
+#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/Initialization.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/ParsedTemplate.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/ScopeInfo.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
#include <map>
#include <set>
@@ -251,7 +252,7 @@ Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg,
return true;
Arg = Result.takeAs<Expr>();
- CheckImplicitConversions(Arg, EqualLoc);
+ CheckCompletedExpr(Arg, EqualLoc);
Arg = MaybeCreateExprWithCleanups(Arg);
// Okay: add the default argument to the parameter
@@ -351,16 +352,25 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) {
// parameter pack. If it is specified in a
// parameter-declaration-clause, it shall not occur within a
// declarator or abstract-declarator of a parameter-declaration.
+ bool MightBeFunction = D.isFunctionDeclarationContext();
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
DeclaratorChunk &chunk = D.getTypeObject(i);
if (chunk.Kind == DeclaratorChunk::Function) {
+ if (MightBeFunction) {
+ // This is a function declaration. It can have default arguments, but
+ // keep looking in case its return type is a function type with default
+ // arguments.
+ MightBeFunction = false;
+ continue;
+ }
for (unsigned argIdx = 0, e = chunk.Fun.NumArgs; argIdx != e; ++argIdx) {
ParmVarDecl *Param =
cast<ParmVarDecl>(chunk.Fun.ArgInfo[argIdx].Param);
if (Param->hasUnparsedDefaultArg()) {
CachedTokens *Toks = chunk.Fun.ArgInfo[argIdx].DefaultArgTokens;
Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc)
- << SourceRange((*Toks)[1].getLocation(), Toks->back().getLocation());
+ << SourceRange((*Toks)[1].getLocation(),
+ Toks->back().getLocation());
delete Toks;
chunk.Fun.ArgInfo[argIdx].DefaultArgTokens = 0;
} else if (Param->getDefaultArg()) {
@@ -369,6 +379,8 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) {
Param->setDefaultArg(0);
}
}
+ } else if (chunk.Kind != DeclaratorChunk::Paren) {
+ MightBeFunction = false;
}
}
}
@@ -517,19 +529,26 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
diag::err_param_default_argument_member_template_redecl)
<< WhichKind
<< NewParam->getDefaultArgRange();
- } else if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(New)) {
- CXXSpecialMember NewSM = getSpecialMember(Ctor),
- OldSM = getSpecialMember(cast<CXXConstructorDecl>(Old));
- if (NewSM != OldSM) {
- Diag(NewParam->getLocation(),diag::warn_default_arg_makes_ctor_special)
- << NewParam->getDefaultArgRange() << NewSM;
- Diag(Old->getLocation(), diag::note_previous_declaration_special)
- << OldSM;
- }
}
}
}
+ // DR1344: If a default argument is added outside a class definition and that
+ // default argument makes the function a special member function, the program
+ // is ill-formed. This can only happen for constructors.
+ if (isa<CXXConstructorDecl>(New) &&
+ New->getMinRequiredArguments() < Old->getMinRequiredArguments()) {
+ CXXSpecialMember NewSM = getSpecialMember(cast<CXXMethodDecl>(New)),
+ OldSM = getSpecialMember(cast<CXXMethodDecl>(Old));
+ if (NewSM != OldSM) {
+ ParmVarDecl *NewParam = New->getParamDecl(New->getMinRequiredArguments());
+ assert(NewParam->hasDefaultArg());
+ Diag(NewParam->getLocation(), diag::err_default_arg_makes_ctor_special)
+ << NewParam->getDefaultArgRange() << NewSM;
+ Diag(Old->getLocation(), diag::note_previous_declaration);
+ }
+ }
+
// C++11 [dcl.constexpr]p1: If any declaration of a function or function
// template has a constexpr specifier then all its declarations shall
// contain the constexpr specifier.
@@ -875,7 +894,7 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
// - its function-body shall be [...] a compound-statement that contains only
CompoundStmt *CompBody = cast<CompoundStmt>(Body);
- llvm::SmallVector<SourceLocation, 4> ReturnStmts;
+ SmallVector<SourceLocation, 4> ReturnStmts;
for (CompoundStmt::body_iterator BodyIt = CompBody->body_begin(),
BodyEnd = CompBody->body_end(); BodyIt != BodyEnd; ++BodyIt) {
switch ((*BodyIt)->getStmtClass()) {
@@ -985,13 +1004,14 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) {
// C++11 [dcl.constexpr]p4:
// - every constructor involved in initializing non-static data members and
// base class sub-objects shall be a constexpr constructor.
- llvm::SmallVector<PartialDiagnosticAt, 8> Diags;
+ SmallVector<PartialDiagnosticAt, 8> Diags;
if (!Expr::isPotentialConstantExpr(Dcl, Diags)) {
- Diag(Dcl->getLocation(), diag::err_constexpr_function_never_constant_expr)
+ Diag(Dcl->getLocation(), diag::ext_constexpr_function_never_constant_expr)
<< isa<CXXConstructorDecl>(Dcl);
for (size_t I = 0, N = Diags.size(); I != N; ++I)
Diag(Diags[I].first, Diags[I].second);
- return false;
+ // Don't return false here: we allow this for compatibility in
+ // system headers.
}
return true;
@@ -1163,6 +1183,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
/// 'public bar' and 'virtual private baz' are each base-specifiers.
BaseResult
Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange,
+ ParsedAttributes &Attributes,
bool Virtual, AccessSpecifier Access,
ParsedType basetype, SourceLocation BaseLoc,
SourceLocation EllipsisLoc) {
@@ -1174,6 +1195,22 @@ Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange,
if (!Class)
return true;
+ // We do not support any C++11 attributes on base-specifiers yet.
+ // Diagnose any attributes we see.
+ if (!Attributes.empty()) {
+ for (AttributeList *Attr = Attributes.getList(); Attr;
+ Attr = Attr->getNext()) {
+ if (Attr->isInvalid() ||
+ Attr->getKind() == AttributeList::IgnoredAttribute)
+ continue;
+ Diag(Attr->getLoc(),
+ Attr->getKind() == AttributeList::UnknownAttribute
+ ? diag::warn_unknown_attribute_ignored
+ : diag::err_base_specifier_attribute)
+ << Attr->getName();
+ }
+ }
+
TypeSourceInfo *TInfo = 0;
GetTypeFromParser(basetype, &TInfo);
@@ -1274,29 +1311,25 @@ void Sema::ActOnBaseSpecifiers(Decl *ClassDecl, CXXBaseSpecifier **Bases,
(CXXBaseSpecifier**)(Bases), NumBases);
}
-static CXXRecordDecl *GetClassForType(QualType T) {
- if (const RecordType *RT = T->getAs<RecordType>())
- return cast<CXXRecordDecl>(RT->getDecl());
- else if (const InjectedClassNameType *ICT = T->getAs<InjectedClassNameType>())
- return ICT->getDecl();
- else
- return 0;
-}
-
/// \brief Determine whether the type \p Derived is a C++ class that is
/// derived from the type \p Base.
bool Sema::IsDerivedFrom(QualType Derived, QualType Base) {
if (!getLangOpts().CPlusPlus)
return false;
- CXXRecordDecl *DerivedRD = GetClassForType(Derived);
+ CXXRecordDecl *DerivedRD = Derived->getAsCXXRecordDecl();
if (!DerivedRD)
return false;
- CXXRecordDecl *BaseRD = GetClassForType(Base);
+ CXXRecordDecl *BaseRD = Base->getAsCXXRecordDecl();
if (!BaseRD)
return false;
-
+
+ // If either the base or the derived type is invalid, don't try to
+ // check whether one is derived from the other.
+ if (BaseRD->isInvalidDecl() || DerivedRD->isInvalidDecl())
+ return false;
+
// FIXME: instantiate DerivedRD if necessary. We need a PoI for this.
return DerivedRD->hasDefinition() && DerivedRD->isDerivedFrom(BaseRD);
}
@@ -1307,11 +1340,11 @@ bool Sema::IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths) {
if (!getLangOpts().CPlusPlus)
return false;
- CXXRecordDecl *DerivedRD = GetClassForType(Derived);
+ CXXRecordDecl *DerivedRD = Derived->getAsCXXRecordDecl();
if (!DerivedRD)
return false;
- CXXRecordDecl *BaseRD = GetClassForType(Base);
+ CXXRecordDecl *BaseRD = Base->getAsCXXRecordDecl();
if (!BaseRD)
return false;
@@ -1556,7 +1589,7 @@ static bool InitializationHasSideEffects(const FieldDecl &FD) {
/// bitfield width if there is one, 'InitExpr' specifies the initializer if
/// one has been parsed, and 'InitStyle' is set if an in-class initializer is
/// present (but parsing it has been deferred).
-Decl *
+NamedDecl *
Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
MultiTemplateParamsArg TemplateParameterLists,
Expr *BW, const VirtSpecifiers &VS,
@@ -1657,7 +1690,36 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
DS.getStorageClassSpec() == DeclSpec::SCS_mutable) &&
!isFunc);
- Decl *Member;
+ if (DS.isConstexprSpecified() && isInstField) {
+ SemaDiagnosticBuilder B =
+ Diag(DS.getConstexprSpecLoc(), diag::err_invalid_constexpr_member);
+ SourceLocation ConstexprLoc = DS.getConstexprSpecLoc();
+ if (InitStyle == ICIS_NoInit) {
+ B << 0 << 0 << FixItHint::CreateReplacement(ConstexprLoc, "const");
+ D.getMutableDeclSpec().ClearConstexprSpec();
+ const char *PrevSpec;
+ unsigned DiagID;
+ bool Failed = D.getMutableDeclSpec().SetTypeQual(DeclSpec::TQ_const, ConstexprLoc,
+ PrevSpec, DiagID, getLangOpts());
+ (void)Failed;
+ assert(!Failed && "Making a constexpr member const shouldn't fail");
+ } else {
+ B << 1;
+ const char *PrevSpec;
+ unsigned DiagID;
+ if (D.getMutableDeclSpec().SetStorageClassSpec(
+ *this, DeclSpec::SCS_static, ConstexprLoc, PrevSpec, DiagID)) {
+ assert(DS.getStorageClassSpec() == DeclSpec::SCS_mutable &&
+ "This is the only DeclSpec that should fail to be applied");
+ B << 1;
+ } else {
+ B << 0 << FixItHint::CreateInsertion(ConstexprLoc, "static ");
+ isInstField = false;
+ }
+ }
+ }
+
+ NamedDecl *Member;
if (isInstField) {
CXXScopeSpec &SS = D.getCXXScopeSpec();
@@ -1711,7 +1773,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
InitStyle, AS);
assert(Member && "HandleField never returns null");
} else {
- assert(InitStyle == ICIS_NoInit);
+ assert(InitStyle == ICIS_NoInit || D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static);
Member = HandleDeclarator(S, D, TemplateParameterLists);
if (!Member) {
@@ -1795,7 +1857,11 @@ namespace {
public:
typedef EvaluatedExprVisitor<UninitializedFieldVisitor> Inherited;
UninitializedFieldVisitor(Sema &S, ValueDecl *VD) : Inherited(S.Context),
- S(S), VD(VD) {
+ S(S) {
+ if (IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(VD))
+ this->VD = IFD->getAnonField();
+ else
+ this->VD = VD;
}
void HandleExpr(Expr *E) {
@@ -1812,23 +1878,33 @@ namespace {
if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
if (isa<EnumConstantDecl>(ME->getMemberDecl()))
- return;
+ return;
+
+ // FieldME is the inner-most MemberExpr that is not an anonymous struct
+ // or union.
+ MemberExpr *FieldME = ME;
+
Expr *Base = E;
while (isa<MemberExpr>(Base)) {
- ME = dyn_cast<MemberExpr>(Base);
- if (VarDecl *VarD = dyn_cast<VarDecl>(ME->getMemberDecl()))
- if (VarD->hasGlobalStorage())
- return;
+ ME = cast<MemberExpr>(Base);
+
+ if (isa<VarDecl>(ME->getMemberDecl()))
+ return;
+
+ if (FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
+ if (!FD->isAnonymousStructOrUnion())
+ FieldME = ME;
+
Base = ME->getBase();
}
- if (VD == ME->getMemberDecl() && isa<CXXThisExpr>(Base)) {
+ if (VD == FieldME->getMemberDecl() && isa<CXXThisExpr>(Base)) {
unsigned diag = VD->getType()->isReferenceType()
? diag::warn_reference_field_is_uninit
: diag::warn_field_is_uninit;
- S.Diag(ME->getExprLoc(), diag) << ME->getMemberNameInfo().getName();
- return;
+ S.Diag(FieldME->getExprLoc(), diag) << VD;
}
+ return;
}
if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
@@ -1909,11 +1985,7 @@ Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation InitLoc,
}
ExprResult Init = InitExpr;
- 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 (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent()) {
if (isa<InitListExpr>(InitExpr) && isStdInitializerList(FD->getType(), 0)) {
Diag(FD->getLocation(), diag::warn_dangling_std_initializer_list)
<< /*at end of ctor*/1 << InitExpr->getSourceRange();
@@ -1930,14 +2002,12 @@ Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation InitLoc,
FD->setInvalidDecl();
return;
}
-
- CheckImplicitConversions(Init.get(), InitLoc);
}
- // C++0x [class.base.init]p7:
+ // C++11 [class.base.init]p7:
// The initialization of each base and member constitutes a
// full-expression.
- Init = MaybeCreateExprWithCleanups(Init);
+ Init = ActOnFinishFullExpr(Init.take(), InitLoc);
if (Init.isInvalid()) {
FD->setInvalidDecl();
return;
@@ -2096,10 +2166,10 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
// Look for a member, first.
DeclContext::lookup_result Result
= ClassDecl->lookup(MemberOrBase);
- if (Result.first != Result.second) {
+ if (!Result.empty()) {
ValueDecl *Member;
- if ((Member = dyn_cast<FieldDecl>(*Result.first)) ||
- (Member = dyn_cast<IndirectFieldDecl>(*Result.first))) {
+ if ((Member = dyn_cast<FieldDecl>(Result.front())) ||
+ (Member = dyn_cast<IndirectFieldDecl>(Result.front()))) {
if (EllipsisLoc.isValid())
Diag(EllipsisLoc, diag::err_pack_expansion_member_init)
<< MemberOrBase
@@ -2295,10 +2365,13 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init,
if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) {
Args = ParenList->getExprs();
NumArgs = ParenList->getNumExprs();
- } else {
- InitListExpr *InitList = cast<InitListExpr>(Init);
+ } else if (InitListExpr *InitList = dyn_cast<InitListExpr>(Init)) {
Args = InitList->getInits();
NumArgs = InitList->getNumInits();
+ } else {
+ // Template instantiation doesn't reconstruct ParenListExprs for us.
+ Args = &Init;
+ NumArgs = 1;
}
if (getDiagnostics().getDiagnosticLevel(diag::warn_field_is_uninit, IdLoc)
@@ -2349,29 +2422,15 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init,
if (MemberInit.isInvalid())
return true;
- CheckImplicitConversions(MemberInit.get(),
- InitRange.getBegin());
-
- // C++0x [class.base.init]p7:
+ // C++11 [class.base.init]p7:
// The initialization of each base and member constitutes a
// full-expression.
- MemberInit = MaybeCreateExprWithCleanups(MemberInit);
+ MemberInit = ActOnFinishFullExpr(MemberInit.get(), InitRange.getBegin());
if (MemberInit.isInvalid())
return true;
- // If we are in a dependent context, template instantiation will
- // perform this type-checking again. Just save the arguments that we
- // received.
- // FIXME: This isn't quite ideal, since our ASTs don't capture all
- // of the information that we have about the member
- // initializer. However, deconstructing the ASTs is a dicey process,
- // and this approach is far more likely to get the corner cases right.
- if (CurContext->isDependentContext()) {
- // The existing Init will do fine.
- } else {
- Init = MemberInit.get();
- CheckForDanglingReferenceOrPointer(*this, Member, Init, IdLoc);
- }
+ Init = MemberInit.get();
+ CheckForDanglingReferenceOrPointer(*this, Member, Init, IdLoc);
}
if (DirectMember) {
@@ -2389,7 +2448,7 @@ MemInitResult
Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init,
CXXRecordDecl *ClassDecl) {
SourceLocation NameLoc = TInfo->getTypeLoc().getLocalSourceRange().getBegin();
- if (!LangOpts.CPlusPlus0x)
+ if (!LangOpts.CPlusPlus11)
return Diag(NameLoc, diag::err_delegating_ctor)
<< TInfo->getTypeLoc().getLocalSourceRange();
Diag(NameLoc, diag::warn_cxx98_compat_delegating_ctor);
@@ -2421,12 +2480,11 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init,
assert(cast<CXXConstructExpr>(DelegationInit.get())->getConstructor() &&
"Delegating constructor with no target?");
- CheckImplicitConversions(DelegationInit.get(), InitRange.getBegin());
-
- // C++0x [class.base.init]p7:
+ // C++11 [class.base.init]p7:
// The initialization of each base and member constitutes a
// full-expression.
- DelegationInit = MaybeCreateExprWithCleanups(DelegationInit);
+ DelegationInit = ActOnFinishFullExpr(DelegationInit.get(),
+ InitRange.getBegin());
if (DelegationInit.isInvalid())
return true;
@@ -2555,12 +2613,10 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
if (BaseInit.isInvalid())
return true;
- CheckImplicitConversions(BaseInit.get(), InitRange.getBegin());
-
- // C++0x [class.base.init]p7:
- // The initialization of each base and member constitutes a
+ // C++11 [class.base.init]p7:
+ // The initialization of each base and member constitutes a
// full-expression.
- BaseInit = MaybeCreateExprWithCleanups(BaseInit);
+ BaseInit = ActOnFinishFullExpr(BaseInit.get(), InitRange.getBegin());
if (BaseInit.isInvalid())
return true;
@@ -2582,9 +2638,10 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
}
// Create a static_cast\<T&&>(expr).
-static Expr *CastForMoving(Sema &SemaRef, Expr *E) {
- QualType ExprType = E->getType();
- QualType TargetType = SemaRef.Context.getRValueReferenceType(ExprType);
+static Expr *CastForMoving(Sema &SemaRef, Expr *E, QualType T = QualType()) {
+ if (T.isNull()) T = E->getType();
+ QualType TargetType = SemaRef.BuildReferenceType(
+ T, /*SpelledAsLValue*/false, SourceLocation(), DeclarationName());
SourceLocation ExprLoc = E->getLocStart();
TypeSourceInfo *TargetLoc = SemaRef.Context.getTrivialTypeSourceInfo(
TargetType, ExprLoc);
@@ -2599,7 +2656,8 @@ static Expr *CastForMoving(Sema &SemaRef, Expr *E) {
enum ImplicitInitializerKind {
IIK_Default,
IIK_Copy,
- IIK_Move
+ IIK_Move,
+ IIK_Inherit
};
static bool
@@ -2615,6 +2673,35 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
ExprResult BaseInit;
switch (ImplicitInitKind) {
+ case IIK_Inherit: {
+ const CXXRecordDecl *Inherited =
+ Constructor->getInheritedConstructor()->getParent();
+ const CXXRecordDecl *Base = BaseSpec->getType()->getAsCXXRecordDecl();
+ if (Base && Inherited->getCanonicalDecl() == Base->getCanonicalDecl()) {
+ // C++11 [class.inhctor]p8:
+ // Each expression in the expression-list is of the form
+ // static_cast<T&&>(p), where p is the name of the corresponding
+ // constructor parameter and T is the declared type of p.
+ SmallVector<Expr*, 16> Args;
+ for (unsigned I = 0, E = Constructor->getNumParams(); I != E; ++I) {
+ ParmVarDecl *PD = Constructor->getParamDecl(I);
+ ExprResult ArgExpr =
+ SemaRef.BuildDeclRefExpr(PD, PD->getType().getNonReferenceType(),
+ VK_LValue, SourceLocation());
+ if (ArgExpr.isInvalid())
+ return true;
+ Args.push_back(CastForMoving(SemaRef, ArgExpr.take(), PD->getType()));
+ }
+
+ InitializationKind InitKind = InitializationKind::CreateDirect(
+ Constructor->getLocation(), SourceLocation(), SourceLocation());
+ InitializationSequence InitSeq(SemaRef, InitEntity, InitKind,
+ Args.data(), Args.size());
+ BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, Args);
+ break;
+ }
+ }
+ // Fall through.
case IIK_Default: {
InitializationKind InitKind
= InitializationKind::CreateDefault(Constructor->getLocation());
@@ -2765,7 +2852,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
= VarDecl::Create(SemaRef.Context, SemaRef.CurContext, Loc, Loc,
IterationVarName, SizeType,
SemaRef.Context.getTrivialTypeSourceInfo(SizeType, Loc),
- SC_None, SC_None);
+ SC_None);
IndexVariables.push_back(IterationVar);
// Create a reference to the iteration variable.
@@ -2837,7 +2924,8 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
return false;
}
- assert(ImplicitInitKind == IIK_Default && "Unhandled implicit init kind!");
+ assert((ImplicitInitKind == IIK_Default || ImplicitInitKind == IIK_Inherit) &&
+ "Unhandled implicit init kind!");
QualType FieldBaseElementType =
SemaRef.Context.getBaseElementType(Field->getType());
@@ -2928,6 +3016,8 @@ struct BaseAndFieldInfo {
IIK = IIK_Copy;
else if (Generated && Ctor->isMoveConstructor())
IIK = IIK_Move;
+ else if (Ctor->getInheritedConstructor())
+ IIK = IIK_Inherit;
else
IIK = IIK_Default;
}
@@ -2939,6 +3029,7 @@ struct BaseAndFieldInfo {
return true;
case IIK_Default:
+ case IIK_Inherit:
return false;
}
@@ -3059,19 +3150,17 @@ Sema::SetDelegatingInitializer(CXXConstructorDecl *Constructor,
return false;
}
-bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor,
- CXXCtorInitializer **Initializers,
- unsigned NumInitializers,
- bool AnyErrors) {
+bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors,
+ ArrayRef<CXXCtorInitializer *> Initializers) {
if (Constructor->isDependentContext()) {
// Just store the initializers as written, they will be checked during
// instantiation.
- if (NumInitializers > 0) {
- Constructor->setNumCtorInitializers(NumInitializers);
+ if (!Initializers.empty()) {
+ Constructor->setNumCtorInitializers(Initializers.size());
CXXCtorInitializer **baseOrMemberInitializers =
- new (Context) CXXCtorInitializer*[NumInitializers];
- memcpy(baseOrMemberInitializers, Initializers,
- NumInitializers * sizeof(CXXCtorInitializer*));
+ new (Context) CXXCtorInitializer*[Initializers.size()];
+ memcpy(baseOrMemberInitializers, Initializers.data(),
+ Initializers.size() * sizeof(CXXCtorInitializer*));
Constructor->setCtorInitializers(baseOrMemberInitializers);
}
@@ -3092,7 +3181,7 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor,
bool HadError = false;
- for (unsigned i = 0; i < NumInitializers; i++) {
+ for (unsigned i = 0; i < Initializers.size(); i++) {
CXXCtorInitializer *Member = Initializers[i];
if (Member->isBaseInitializer())
@@ -3168,7 +3257,7 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor,
// If we're not generating the implicit copy/move constructor, then we'll
// handle anonymous struct/union fields based on their individual
// indirect fields.
- if (F->isAnonymousStructOrUnion() && Info.IIK == IIK_Default)
+ if (F->isAnonymousStructOrUnion() && !Info.isImplicitCopyOrMove())
continue;
if (CollectFieldInitializer(*this, Info, F))
@@ -3177,7 +3266,7 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor,
}
// Beyond this point, we only consider default initialization.
- if (Info.IIK != IIK_Default)
+ if (Info.isImplicitCopyOrMove())
continue;
if (IndirectFieldDecl *F = dyn_cast<IndirectFieldDecl>(*Mem)) {
@@ -3195,7 +3284,7 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor,
}
}
- NumInitializers = Info.AllToInit.size();
+ unsigned NumInitializers = Info.AllToInit.size();
if (NumInitializers > 0) {
Constructor->setNumCtorInitializers(NumInitializers);
CXXCtorInitializer **baseOrMemberInitializers =
@@ -3213,13 +3302,17 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor,
return HadError;
}
-static void *GetKeyForTopLevelField(FieldDecl *Field) {
- // For anonymous unions, use the class declaration as the key.
+static void PopulateKeysForFields(FieldDecl *Field, SmallVectorImpl<const void*> &IdealInits) {
if (const RecordType *RT = Field->getType()->getAs<RecordType>()) {
- if (RT->getDecl()->isAnonymousStructOrUnion())
- return static_cast<void *>(RT->getDecl());
+ const RecordDecl *RD = RT->getDecl();
+ if (RD->isAnonymousStructOrUnion()) {
+ for (RecordDecl::field_iterator Field = RD->field_begin(),
+ E = RD->field_end(); Field != E; ++Field)
+ PopulateKeysForFields(*Field, IdealInits);
+ return;
+ }
}
- return static_cast<void *>(Field);
+ IdealInits.push_back(Field);
}
static void *GetKeyForBase(ASTContext &Context, QualType BaseType) {
@@ -3231,40 +3324,19 @@ static void *GetKeyForMember(ASTContext &Context,
if (!Member->isAnyMemberInitializer())
return GetKeyForBase(Context, QualType(Member->getBaseClass(), 0));
- // For fields injected into the class via declaration of an anonymous union,
- // use its anonymous union class declaration as the unique key.
- FieldDecl *Field = Member->getAnyMember();
-
- // If the field is a member of an anonymous struct or union, our key
- // is the anonymous record decl that's a direct child of the class.
- RecordDecl *RD = Field->getParent();
- if (RD->isAnonymousStructOrUnion()) {
- while (true) {
- RecordDecl *Parent = cast<RecordDecl>(RD->getDeclContext());
- if (Parent->isAnonymousStructOrUnion())
- RD = Parent;
- else
- break;
- }
-
- return static_cast<void *>(RD);
- }
-
- return static_cast<void *>(Field);
+ return Member->getAnyMember();
}
-static void
-DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef,
- const CXXConstructorDecl *Constructor,
- CXXCtorInitializer **Inits,
- unsigned NumInits) {
+static void DiagnoseBaseOrMemInitializerOrder(
+ Sema &SemaRef, const CXXConstructorDecl *Constructor,
+ ArrayRef<CXXCtorInitializer *> Inits) {
if (Constructor->getDeclContext()->isDependentContext())
return;
// Don't check initializers order unless the warning is enabled at the
// location of at least one initializer.
bool ShouldCheckOrder = false;
- for (unsigned InitIndex = 0; InitIndex != NumInits; ++InitIndex) {
+ for (unsigned InitIndex = 0; InitIndex != Inits.size(); ++InitIndex) {
CXXCtorInitializer *Init = Inits[InitIndex];
if (SemaRef.Diags.getDiagnosticLevel(diag::warn_initializer_out_of_order,
Init->getSourceLocation())
@@ -3303,14 +3375,14 @@ DiagnoseBaseOrMemInitializerOrder(Sema &SemaRef,
if (Field->isUnnamedBitfield())
continue;
- IdealInitKeys.push_back(GetKeyForTopLevelField(*Field));
+ PopulateKeysForFields(*Field, IdealInitKeys);
}
unsigned NumIdealInits = IdealInitKeys.size();
unsigned IdealIndex = 0;
CXXCtorInitializer *PrevInit = 0;
- for (unsigned InitIndex = 0; InitIndex != NumInits; ++InitIndex) {
+ for (unsigned InitIndex = 0; InitIndex != Inits.size(); ++InitIndex) {
CXXCtorInitializer *Init = Inits[InitIndex];
void *InitKey = GetKeyForMember(SemaRef.Context, Init);
@@ -3360,7 +3432,7 @@ bool CheckRedundantInit(Sema &S,
return false;
}
- if (FieldDecl *Field = Init->getMember())
+ if (FieldDecl *Field = Init->getAnyMember())
S.Diag(Init->getSourceLocation(),
diag::err_multiple_mem_initialization)
<< Field->getDeclName()
@@ -3420,8 +3492,7 @@ bool CheckRedundantUnionInit(Sema &S,
/// ActOnMemInitializers - Handle the member initializers for a constructor.
void Sema::ActOnMemInitializers(Decl *ConstructorDecl,
SourceLocation ColonLoc,
- CXXCtorInitializer **meminits,
- unsigned NumMemInits,
+ ArrayRef<CXXCtorInitializer*> MemInits,
bool AnyErrors) {
if (!ConstructorDecl)
return;
@@ -3436,9 +3507,6 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl,
return;
}
- CXXCtorInitializer **MemInits =
- reinterpret_cast<CXXCtorInitializer **>(meminits);
-
// Mapping for the duplicate initializers check.
// For member initializers, this is keyed with a FieldDecl*.
// For base initializers, this is keyed with a Type*.
@@ -3448,7 +3516,7 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl,
RedundantUnionMap MemberUnions;
bool HadError = false;
- for (unsigned i = 0; i < NumMemInits; i++) {
+ for (unsigned i = 0; i < MemInits.size(); i++) {
CXXCtorInitializer *Init = MemInits[i];
// Set the source order index.
@@ -3466,7 +3534,7 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl,
} else {
assert(Init->isDelegatingInitializer());
// This must be the only initializer
- if (NumMemInits != 1) {
+ if (MemInits.size() != 1) {
Diag(Init->getSourceLocation(),
diag::err_delegating_initializer_alone)
<< Init->getSourceRange() << MemInits[i ? 0 : 1]->getSourceRange();
@@ -3481,9 +3549,9 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl,
if (HadError)
return;
- DiagnoseBaseOrMemInitializerOrder(*this, Constructor, MemInits, NumMemInits);
+ DiagnoseBaseOrMemInitializerOrder(*this, Constructor, MemInits);
- SetCtorInitializers(Constructor, MemInits, NumMemInits, AnyErrors);
+ SetCtorInitializers(Constructor, AnyErrors, MemInits);
}
void
@@ -3605,7 +3673,7 @@ void Sema::ActOnDefaultCtorInitializers(Decl *CDtorDecl) {
if (CXXConstructorDecl *Constructor
= dyn_cast<CXXConstructorDecl>(CDtorDecl))
- SetCtorInitializers(Constructor, 0, 0, /*AnyErrors=*/false);
+ SetCtorInitializers(Constructor, /*AnyErrors=*/false);
}
bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T,
@@ -3748,7 +3816,7 @@ struct CheckAbstractUsage {
switch (TL.getTypeLocClass()) {
#define ABSTRACT_TYPELOC(CLASS, PARENT)
#define TYPELOC(CLASS, PARENT) \
- case TypeLoc::CLASS: Check(cast<CLASS##TypeLoc>(TL), Sel); break;
+ case TypeLoc::CLASS: Check(TL.castAs<CLASS##TypeLoc>(), Sel); break;
#include "clang/AST/TypeLocNodes.def"
}
}
@@ -3933,9 +4001,10 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
// C++ [class.mem]p14:
// In addition, if class T has a user-declared constructor (12.1), every
// non-static data member of class T shall have a name different from T.
- for (DeclContext::lookup_result R = Record->lookup(Record->getDeclName());
- R.first != R.second; ++R.first) {
- NamedDecl *D = *R.first;
+ DeclContext::lookup_result R = Record->lookup(Record->getDeclName());
+ for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E;
+ ++I) {
+ NamedDecl *D = *I;
if ((isa<FieldDecl>(D) && Record->hasUserDeclaredConstructor()) ||
isa<IndirectFieldDecl>(D)) {
Diag(D->getLocation(), diag::err_member_name_of_class)
@@ -3958,18 +4027,34 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
DiagnoseAbstractType(Record);
}
- // See if a method overloads virtual methods in a base
- /// class without overriding any.
if (!Record->isDependentType()) {
for (CXXRecordDecl::method_iterator M = Record->method_begin(),
MEnd = Record->method_end();
M != MEnd; ++M) {
+ // See if a method overloads virtual methods in a base
+ // class without overriding any.
if (!M->isStatic())
DiagnoseHiddenVirtualMethods(Record, *M);
+
+ // Check whether the explicitly-defaulted special members are valid.
+ if (!M->isInvalidDecl() && M->isExplicitlyDefaulted())
+ CheckExplicitlyDefaultedSpecialMember(*M);
+
+ // For an explicitly defaulted or deleted special member, we defer
+ // determining triviality until the class is complete. That time is now!
+ if (!M->isImplicit() && !M->isUserProvided()) {
+ CXXSpecialMember CSM = getSpecialMember(*M);
+ if (CSM != CXXInvalid) {
+ M->setTrivial(SpecialMemberIsTrivial(*M, CSM));
+
+ // Inform the class that we've finished declaring this member.
+ Record->finishedDefaultedOrDeletedMember(*M);
+ }
+ }
}
}
- // C++0x [dcl.constexpr]p8: A constexpr specifier for a non-static member
+ // C++11 [dcl.constexpr]p8: A constexpr specifier for a non-static member
// function that is not a constructor declares that member function to be
// const. [...] The class of which that function is a member shall be
// a literal type.
@@ -3977,7 +4062,10 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
// If the class has virtual bases, any constexpr members will already have
// been diagnosed by the checks performed on the member declaration, so
// suppress this (less useful) diagnostic.
- if (LangOpts.CPlusPlus0x && !Record->isDependentType() &&
+ //
+ // We delay this until we know whether an explicitly-defaulted (or deleted)
+ // destructor for the class is trivial.
+ if (LangOpts.CPlusPlus11 && !Record->isDependentType() &&
!Record->isLiteral() && !Record->getNumVBases()) {
for (CXXRecordDecl::method_iterator M = Record->method_begin(),
MEnd = Record->method_end();
@@ -4005,22 +4093,14 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
}
}
- // Declare inherited constructors. We do this eagerly here because:
- // - The standard requires an eager diagnostic for conflicting inherited
+ // Declare inheriting constructors. We do this eagerly here because:
+ // - The standard requires an eager diagnostic for conflicting inheriting
// constructors from different classes.
// - The lazy declaration of the other implicit constructors is so as to not
// waste space and performance on classes that are not meant to be
// instantiated (e.g. meta-functions). This doesn't apply to classes that
- // have inherited constructors.
- DeclareInheritedConstructors(Record);
-}
-
-void Sema::CheckExplicitlyDefaultedMethods(CXXRecordDecl *Record) {
- for (CXXRecordDecl::method_iterator MI = Record->method_begin(),
- ME = Record->method_end();
- MI != ME; ++MI)
- if (!MI->isInvalidDecl() && MI->isExplicitlyDefaulted())
- CheckExplicitlyDefaultedSpecialMember(*MI);
+ // have inheriting constructors.
+ DeclareInheritingConstructors(Record);
}
/// Is the special member function which would be selected to perform the
@@ -4043,7 +4123,7 @@ static bool specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
Sema::CXXSpecialMember CSM,
bool ConstArg) {
- if (!S.getLangOpts().CPlusPlus0x)
+ if (!S.getLangOpts().CPlusPlus11)
return false;
// C++11 [dcl.constexpr]p4:
@@ -4136,7 +4216,9 @@ computeImplicitExceptionSpec(Sema &S, SourceLocation Loc, CXXMethodDecl *MD) {
case Sema::CXXInvalid:
break;
}
- llvm_unreachable("only special members have implicit exception specs");
+ assert(cast<CXXConstructorDecl>(MD)->getInheritedConstructor() &&
+ "only special members have implicit exception specs");
+ return S.ComputeInheritingCtorExceptionSpec(cast<CXXConstructorDecl>(MD));
}
static void
@@ -4145,8 +4227,7 @@ updateExceptionSpec(Sema &S, FunctionDecl *FD, const FunctionProtoType *FPT,
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
ExceptSpec.getEPI(EPI);
const FunctionProtoType *NewFPT = cast<FunctionProtoType>(
- S.Context.getFunctionType(FPT->getResultType(), FPT->arg_type_begin(),
- FPT->getNumArgs(), EPI));
+ S.Context.getFunctionType(FPT->getResultType(), FPT->getArgTypes(), EPI));
FD->setType(QualType(NewFPT, 0));
}
@@ -4172,9 +4253,6 @@ void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD)
CanonicalFPT, ExceptSpec);
}
-static bool isImplicitCopyCtorArgConst(Sema &S, CXXRecordDecl *ClassDecl);
-static bool isImplicitCopyAssignmentArgConst(Sema &S, CXXRecordDecl *ClassDecl);
-
void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
CXXRecordDecl *RD = MD->getParent();
CXXSpecialMember CSM = getSpecialMember(MD);
@@ -4205,37 +4283,19 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
Diag(MD->getLocation(), diag::err_defaulted_special_member_params)
<< CSM << MD->getSourceRange();
HadError = true;
+ } else if (MD->isVariadic()) {
+ Diag(MD->getLocation(), diag::err_defaulted_special_member_variadic)
+ << CSM << MD->getSourceRange();
+ HadError = true;
}
const FunctionProtoType *Type = MD->getType()->getAs<FunctionProtoType>();
- // Compute argument constness, constexpr, and triviality.
bool CanHaveConstParam = false;
- bool Trivial = false;
- switch (CSM) {
- case CXXDefaultConstructor:
- Trivial = RD->hasTrivialDefaultConstructor();
- break;
- case CXXCopyConstructor:
- CanHaveConstParam = isImplicitCopyCtorArgConst(*this, RD);
- Trivial = RD->hasTrivialCopyConstructor();
- break;
- case CXXCopyAssignment:
- CanHaveConstParam = isImplicitCopyAssignmentArgConst(*this, RD);
- Trivial = RD->hasTrivialCopyAssignment();
- break;
- case CXXMoveConstructor:
- Trivial = RD->hasTrivialMoveConstructor();
- break;
- case CXXMoveAssignment:
- Trivial = RD->hasTrivialMoveAssignment();
- break;
- case CXXDestructor:
- Trivial = RD->hasTrivialDestructor();
- break;
- case CXXInvalid:
- llvm_unreachable("non-special member explicitly defaulted!");
- }
+ if (CSM == CXXCopyConstructor)
+ CanHaveConstParam = RD->implicitCopyConstructorHasConstParam();
+ else if (CSM == CXXCopyAssignment)
+ CanHaveConstParam = RD->implicitCopyAssignmentHasConstParam();
QualType ReturnType = Context.VoidTy;
if (CSM == CXXCopyAssignment || CSM == CXXMoveAssignment) {
@@ -4284,14 +4344,6 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
}
HadError = true;
}
-
- // If a function is explicitly defaulted on its first declaration, it shall
- // have the same parameter type as if it had been implicitly declared.
- // (Presumably this is to prevent it from being trivial?)
- if (!HasConstParam && CanHaveConstParam && First)
- Diag(MD->getLocation(),
- diag::err_defaulted_special_member_copy_non_const_param)
- << (CSM == CXXCopyAssignment);
} else if (ExpectedParams) {
// A copy assignment operator can take its argument by value, but a
// defaulted one cannot.
@@ -4300,16 +4352,6 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
HadError = true;
}
- // Rebuild the type with the implicit exception specification added, if we
- // are going to need it.
- const FunctionProtoType *ImplicitType = 0;
- if (First || Type->hasExceptionSpec()) {
- FunctionProtoType::ExtProtoInfo EPI = Type->getExtProtoInfo();
- computeImplicitExceptionSpec(*this, MD->getLocation(), MD).getEPI(EPI);
- ImplicitType = cast<FunctionProtoType>(
- Context.getFunctionType(ReturnType, &ArgType, ExpectedParams, EPI));
- }
-
// C++11 [dcl.fct.def.default]p2:
// An explicitly-defaulted function may be declared constexpr only if it
// would have been implicitly declared as constexpr,
@@ -4324,13 +4366,23 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
// FIXME: Explain why the constructor can't be constexpr.
HadError = true;
}
+
// and may have an explicit exception-specification only if it is compatible
// with the exception-specification on the implicit declaration.
- if (Type->hasExceptionSpec() &&
- CheckEquivalentExceptionSpec(
- PDiag(diag::err_incorrect_defaulted_exception_spec) << CSM,
- PDiag(), ImplicitType, SourceLocation(), Type, MD->getLocation()))
- HadError = true;
+ if (Type->hasExceptionSpec()) {
+ // Delay the check if this is the first declaration of the special member,
+ // since we may not have parsed some necessary in-class initializers yet.
+ if (First) {
+ // If the exception specification needs to be instantiated, do so now,
+ // before we clobber it with an EST_Unevaluated specification below.
+ if (Type->getExceptionSpecType() == EST_Uninstantiated) {
+ InstantiateExceptionSpec(MD->getLocStart(), MD);
+ Type = MD->getType()->getAs<FunctionProtoType>();
+ }
+ DelayedDefaultedMemberExceptionSpecs.push_back(std::make_pair(MD, Type));
+ } else
+ CheckExplicitlyDefaultedMemberExceptionSpec(MD, Type);
+ }
// If a function is explicitly defaulted on its first declaration,
if (First) {
@@ -4340,16 +4392,18 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
// -- it is implicitly considered to have the same exception-specification
// as if it had been implicitly declared,
- MD->setType(QualType(ImplicitType, 0));
-
- // Such a function is also trivial if the implicitly-declared function
- // would have been.
- MD->setTrivial(Trivial);
+ FunctionProtoType::ExtProtoInfo EPI = Type->getExtProtoInfo();
+ EPI.ExceptionSpecType = EST_Unevaluated;
+ EPI.ExceptionSpecDecl = MD;
+ MD->setType(Context.getFunctionType(ReturnType,
+ ArrayRef<QualType>(&ArgType,
+ ExpectedParams),
+ EPI));
}
if (ShouldDeleteSpecialMember(MD, CSM)) {
if (First) {
- MD->setDeletedAsWritten();
+ SetDeclDeleted(MD, MD->getLocation());
} else {
// C++11 [dcl.fct.def.default]p4:
// [For a] user-provided explicitly-defaulted function [...] if such a
@@ -4363,6 +4417,36 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
MD->setInvalidDecl();
}
+/// Check whether the exception specification provided for an
+/// explicitly-defaulted special member matches the exception specification
+/// that would have been generated for an implicit special member, per
+/// C++11 [dcl.fct.def.default]p2.
+void Sema::CheckExplicitlyDefaultedMemberExceptionSpec(
+ CXXMethodDecl *MD, const FunctionProtoType *SpecifiedType) {
+ // Compute the implicit exception specification.
+ FunctionProtoType::ExtProtoInfo EPI;
+ computeImplicitExceptionSpec(*this, MD->getLocation(), MD).getEPI(EPI);
+ const FunctionProtoType *ImplicitType = cast<FunctionProtoType>(
+ Context.getFunctionType(Context.VoidTy, ArrayRef<QualType>(), EPI));
+
+ // Ensure that it matches.
+ CheckEquivalentExceptionSpec(
+ PDiag(diag::err_incorrect_defaulted_exception_spec)
+ << getSpecialMember(MD), PDiag(),
+ ImplicitType, SourceLocation(),
+ SpecifiedType, MD->getLocation());
+}
+
+void Sema::CheckDelayedExplicitlyDefaultedMemberExceptionSpecs() {
+ for (unsigned I = 0, N = DelayedDefaultedMemberExceptionSpecs.size();
+ I != N; ++I)
+ CheckExplicitlyDefaultedMemberExceptionSpec(
+ DelayedDefaultedMemberExceptionSpecs[I].first,
+ DelayedDefaultedMemberExceptionSpecs[I].second);
+
+ DelayedDefaultedMemberExceptionSpecs.clear();
+}
+
namespace {
struct SpecialMemberDeletionInfo {
Sema &S;
@@ -4688,7 +4772,7 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
return false;
CXXRecordDecl *RD = MD->getParent();
assert(!RD->isDependentType() && "do deletion after instantiation");
- if (!LangOpts.CPlusPlus0x || RD->isInvalidDecl())
+ if (!LangOpts.CPlusPlus11 || RD->isInvalidDecl())
return false;
// C++11 [expr.lambda.prim]p19:
@@ -4722,12 +4806,28 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
if (RD->hasUserDeclaredMoveConstructor() &&
(!getLangOpts().MicrosoftMode || CSM == CXXCopyConstructor)) {
if (!Diagnose) return true;
- UserDeclaredMove = RD->getMoveConstructor();
+
+ // Find any user-declared move constructor.
+ for (CXXRecordDecl::ctor_iterator I = RD->ctor_begin(),
+ E = RD->ctor_end(); I != E; ++I) {
+ if (I->isMoveConstructor()) {
+ UserDeclaredMove = *I;
+ break;
+ }
+ }
assert(UserDeclaredMove);
} else if (RD->hasUserDeclaredMoveAssignment() &&
(!getLangOpts().MicrosoftMode || CSM == CXXCopyAssignment)) {
if (!Diagnose) return true;
- UserDeclaredMove = RD->getMoveAssignmentOperator();
+
+ // Find any user-declared move assignment operator.
+ for (CXXRecordDecl::method_iterator I = RD->method_begin(),
+ E = RD->method_end(); I != E; ++I) {
+ if (I->isMoveAssignmentOperator()) {
+ UserDeclaredMove = *I;
+ break;
+ }
+ }
assert(UserDeclaredMove);
}
@@ -4783,6 +4883,422 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
return false;
}
+/// Perform lookup for a special member of the specified kind, and determine
+/// whether it is trivial. If the triviality can be determined without the
+/// lookup, skip it. This is intended for use when determining whether a
+/// special member of a containing object is trivial, and thus does not ever
+/// perform overload resolution for default constructors.
+///
+/// If \p Selected is not \c NULL, \c *Selected will be filled in with the
+/// member that was most likely to be intended to be trivial, if any.
+static bool findTrivialSpecialMember(Sema &S, CXXRecordDecl *RD,
+ Sema::CXXSpecialMember CSM, unsigned Quals,
+ CXXMethodDecl **Selected) {
+ if (Selected)
+ *Selected = 0;
+
+ switch (CSM) {
+ case Sema::CXXInvalid:
+ llvm_unreachable("not a special member");
+
+ case Sema::CXXDefaultConstructor:
+ // C++11 [class.ctor]p5:
+ // A default constructor is trivial if:
+ // - all the [direct subobjects] have trivial default constructors
+ //
+ // Note, no overload resolution is performed in this case.
+ if (RD->hasTrivialDefaultConstructor())
+ return true;
+
+ if (Selected) {
+ // If there's a default constructor which could have been trivial, dig it
+ // out. Otherwise, if there's any user-provided default constructor, point
+ // to that as an example of why there's not a trivial one.
+ CXXConstructorDecl *DefCtor = 0;
+ if (RD->needsImplicitDefaultConstructor())
+ S.DeclareImplicitDefaultConstructor(RD);
+ for (CXXRecordDecl::ctor_iterator CI = RD->ctor_begin(),
+ CE = RD->ctor_end(); CI != CE; ++CI) {
+ if (!CI->isDefaultConstructor())
+ continue;
+ DefCtor = *CI;
+ if (!DefCtor->isUserProvided())
+ break;
+ }
+
+ *Selected = DefCtor;
+ }
+
+ return false;
+
+ case Sema::CXXDestructor:
+ // C++11 [class.dtor]p5:
+ // A destructor is trivial if:
+ // - all the direct [subobjects] have trivial destructors
+ if (RD->hasTrivialDestructor())
+ return true;
+
+ if (Selected) {
+ if (RD->needsImplicitDestructor())
+ S.DeclareImplicitDestructor(RD);
+ *Selected = RD->getDestructor();
+ }
+
+ return false;
+
+ case Sema::CXXCopyConstructor:
+ // C++11 [class.copy]p12:
+ // A copy constructor is trivial if:
+ // - the constructor selected to copy each direct [subobject] is trivial
+ if (RD->hasTrivialCopyConstructor()) {
+ if (Quals == Qualifiers::Const)
+ // We must either select the trivial copy constructor or reach an
+ // ambiguity; no need to actually perform overload resolution.
+ return true;
+ } else if (!Selected) {
+ return false;
+ }
+ // In C++98, we are not supposed to perform overload resolution here, but we
+ // treat that as a language defect, as suggested on cxx-abi-dev, to treat
+ // cases like B as having a non-trivial copy constructor:
+ // struct A { template<typename T> A(T&); };
+ // struct B { mutable A a; };
+ goto NeedOverloadResolution;
+
+ case Sema::CXXCopyAssignment:
+ // C++11 [class.copy]p25:
+ // A copy assignment operator is trivial if:
+ // - the assignment operator selected to copy each direct [subobject] is
+ // trivial
+ if (RD->hasTrivialCopyAssignment()) {
+ if (Quals == Qualifiers::Const)
+ return true;
+ } else if (!Selected) {
+ return false;
+ }
+ // In C++98, we are not supposed to perform overload resolution here, but we
+ // treat that as a language defect.
+ goto NeedOverloadResolution;
+
+ case Sema::CXXMoveConstructor:
+ case Sema::CXXMoveAssignment:
+ NeedOverloadResolution:
+ Sema::SpecialMemberOverloadResult *SMOR =
+ S.LookupSpecialMember(RD, CSM,
+ Quals & Qualifiers::Const,
+ Quals & Qualifiers::Volatile,
+ /*RValueThis*/false, /*ConstThis*/false,
+ /*VolatileThis*/false);
+
+ // The standard doesn't describe how to behave if the lookup is ambiguous.
+ // We treat it as not making the member non-trivial, just like the standard
+ // mandates for the default constructor. This should rarely matter, because
+ // the member will also be deleted.
+ if (SMOR->getKind() == Sema::SpecialMemberOverloadResult::Ambiguous)
+ return true;
+
+ if (!SMOR->getMethod()) {
+ assert(SMOR->getKind() ==
+ Sema::SpecialMemberOverloadResult::NoMemberOrDeleted);
+ return false;
+ }
+
+ // We deliberately don't check if we found a deleted special member. We're
+ // not supposed to!
+ if (Selected)
+ *Selected = SMOR->getMethod();
+ return SMOR->getMethod()->isTrivial();
+ }
+
+ llvm_unreachable("unknown special method kind");
+}
+
+static CXXConstructorDecl *findUserDeclaredCtor(CXXRecordDecl *RD) {
+ for (CXXRecordDecl::ctor_iterator CI = RD->ctor_begin(), CE = RD->ctor_end();
+ CI != CE; ++CI)
+ if (!CI->isImplicit())
+ return *CI;
+
+ // Look for constructor templates.
+ typedef CXXRecordDecl::specific_decl_iterator<FunctionTemplateDecl> tmpl_iter;
+ for (tmpl_iter TI(RD->decls_begin()), TE(RD->decls_end()); TI != TE; ++TI) {
+ if (CXXConstructorDecl *CD =
+ dyn_cast<CXXConstructorDecl>(TI->getTemplatedDecl()))
+ return CD;
+ }
+
+ return 0;
+}
+
+/// The kind of subobject we are checking for triviality. The values of this
+/// enumeration are used in diagnostics.
+enum TrivialSubobjectKind {
+ /// The subobject is a base class.
+ TSK_BaseClass,
+ /// The subobject is a non-static data member.
+ TSK_Field,
+ /// The object is actually the complete object.
+ TSK_CompleteObject
+};
+
+/// Check whether the special member selected for a given type would be trivial.
+static bool checkTrivialSubobjectCall(Sema &S, SourceLocation SubobjLoc,
+ QualType SubType,
+ Sema::CXXSpecialMember CSM,
+ TrivialSubobjectKind Kind,
+ bool Diagnose) {
+ CXXRecordDecl *SubRD = SubType->getAsCXXRecordDecl();
+ if (!SubRD)
+ return true;
+
+ CXXMethodDecl *Selected;
+ if (findTrivialSpecialMember(S, SubRD, CSM, SubType.getCVRQualifiers(),
+ Diagnose ? &Selected : 0))
+ return true;
+
+ if (Diagnose) {
+ if (!Selected && CSM == Sema::CXXDefaultConstructor) {
+ S.Diag(SubobjLoc, diag::note_nontrivial_no_def_ctor)
+ << Kind << SubType.getUnqualifiedType();
+ if (CXXConstructorDecl *CD = findUserDeclaredCtor(SubRD))
+ S.Diag(CD->getLocation(), diag::note_user_declared_ctor);
+ } else if (!Selected)
+ S.Diag(SubobjLoc, diag::note_nontrivial_no_copy)
+ << Kind << SubType.getUnqualifiedType() << CSM << SubType;
+ else if (Selected->isUserProvided()) {
+ if (Kind == TSK_CompleteObject)
+ S.Diag(Selected->getLocation(), diag::note_nontrivial_user_provided)
+ << Kind << SubType.getUnqualifiedType() << CSM;
+ else {
+ S.Diag(SubobjLoc, diag::note_nontrivial_user_provided)
+ << Kind << SubType.getUnqualifiedType() << CSM;
+ S.Diag(Selected->getLocation(), diag::note_declared_at);
+ }
+ } else {
+ if (Kind != TSK_CompleteObject)
+ S.Diag(SubobjLoc, diag::note_nontrivial_subobject)
+ << Kind << SubType.getUnqualifiedType() << CSM;
+
+ // Explain why the defaulted or deleted special member isn't trivial.
+ S.SpecialMemberIsTrivial(Selected, CSM, Diagnose);
+ }
+ }
+
+ return false;
+}
+
+/// Check whether the members of a class type allow a special member to be
+/// trivial.
+static bool checkTrivialClassMembers(Sema &S, CXXRecordDecl *RD,
+ Sema::CXXSpecialMember CSM,
+ bool ConstArg, bool Diagnose) {
+ for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
+ FE = RD->field_end(); FI != FE; ++FI) {
+ if (FI->isInvalidDecl() || FI->isUnnamedBitfield())
+ continue;
+
+ QualType FieldType = S.Context.getBaseElementType(FI->getType());
+
+ // Pretend anonymous struct or union members are members of this class.
+ if (FI->isAnonymousStructOrUnion()) {
+ if (!checkTrivialClassMembers(S, FieldType->getAsCXXRecordDecl(),
+ CSM, ConstArg, Diagnose))
+ return false;
+ continue;
+ }
+
+ // C++11 [class.ctor]p5:
+ // A default constructor is trivial if [...]
+ // -- no non-static data member of its class has a
+ // brace-or-equal-initializer
+ if (CSM == Sema::CXXDefaultConstructor && FI->hasInClassInitializer()) {
+ if (Diagnose)
+ S.Diag(FI->getLocation(), diag::note_nontrivial_in_class_init) << *FI;
+ return false;
+ }
+
+ // Objective C ARC 4.3.5:
+ // [...] nontrivally ownership-qualified types are [...] not trivially
+ // default constructible, copy constructible, move constructible, copy
+ // assignable, move assignable, or destructible [...]
+ if (S.getLangOpts().ObjCAutoRefCount &&
+ FieldType.hasNonTrivialObjCLifetime()) {
+ if (Diagnose)
+ S.Diag(FI->getLocation(), diag::note_nontrivial_objc_ownership)
+ << RD << FieldType.getObjCLifetime();
+ return false;
+ }
+
+ if (ConstArg && !FI->isMutable())
+ FieldType.addConst();
+ if (!checkTrivialSubobjectCall(S, FI->getLocation(), FieldType, CSM,
+ TSK_Field, Diagnose))
+ return false;
+ }
+
+ return true;
+}
+
+/// Diagnose why the specified class does not have a trivial special member of
+/// the given kind.
+void Sema::DiagnoseNontrivial(const CXXRecordDecl *RD, CXXSpecialMember CSM) {
+ QualType Ty = Context.getRecordType(RD);
+ if (CSM == CXXCopyConstructor || CSM == CXXCopyAssignment)
+ Ty.addConst();
+
+ checkTrivialSubobjectCall(*this, RD->getLocation(), Ty, CSM,
+ TSK_CompleteObject, /*Diagnose*/true);
+}
+
+/// Determine whether a defaulted or deleted special member function is trivial,
+/// as specified in C++11 [class.ctor]p5, C++11 [class.copy]p12,
+/// C++11 [class.copy]p25, and C++11 [class.dtor]p5.
+bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM,
+ bool Diagnose) {
+ assert(!MD->isUserProvided() && CSM != CXXInvalid && "not special enough");
+
+ CXXRecordDecl *RD = MD->getParent();
+
+ bool ConstArg = false;
+
+ // C++11 [class.copy]p12, p25:
+ // A [special member] is trivial if its declared parameter type is the same
+ // as if it had been implicitly declared [...]
+ switch (CSM) {
+ case CXXDefaultConstructor:
+ case CXXDestructor:
+ // Trivial default constructors and destructors cannot have parameters.
+ break;
+
+ case CXXCopyConstructor:
+ case CXXCopyAssignment: {
+ // Trivial copy operations always have const, non-volatile parameter types.
+ ConstArg = true;
+ const ParmVarDecl *Param0 = MD->getParamDecl(0);
+ const ReferenceType *RT = Param0->getType()->getAs<ReferenceType>();
+ if (!RT || RT->getPointeeType().getCVRQualifiers() != Qualifiers::Const) {
+ if (Diagnose)
+ Diag(Param0->getLocation(), diag::note_nontrivial_param_type)
+ << Param0->getSourceRange() << Param0->getType()
+ << Context.getLValueReferenceType(
+ Context.getRecordType(RD).withConst());
+ return false;
+ }
+ break;
+ }
+
+ case CXXMoveConstructor:
+ case CXXMoveAssignment: {
+ // Trivial move operations always have non-cv-qualified parameters.
+ const ParmVarDecl *Param0 = MD->getParamDecl(0);
+ const RValueReferenceType *RT =
+ Param0->getType()->getAs<RValueReferenceType>();
+ if (!RT || RT->getPointeeType().getCVRQualifiers()) {
+ if (Diagnose)
+ Diag(Param0->getLocation(), diag::note_nontrivial_param_type)
+ << Param0->getSourceRange() << Param0->getType()
+ << Context.getRValueReferenceType(Context.getRecordType(RD));
+ return false;
+ }
+ break;
+ }
+
+ case CXXInvalid:
+ llvm_unreachable("not a special member");
+ }
+
+ // FIXME: We require that the parameter-declaration-clause is equivalent to
+ // that of an implicit declaration, not just that the declared parameter type
+ // matches, in order to prevent absuridities like a function simultaneously
+ // being a trivial copy constructor and a non-trivial default constructor.
+ // This issue has not yet been assigned a core issue number.
+ if (MD->getMinRequiredArguments() < MD->getNumParams()) {
+ if (Diagnose)
+ Diag(MD->getParamDecl(MD->getMinRequiredArguments())->getLocation(),
+ diag::note_nontrivial_default_arg)
+ << MD->getParamDecl(MD->getMinRequiredArguments())->getSourceRange();
+ return false;
+ }
+ if (MD->isVariadic()) {
+ if (Diagnose)
+ Diag(MD->getLocation(), diag::note_nontrivial_variadic);
+ return false;
+ }
+
+ // C++11 [class.ctor]p5, C++11 [class.dtor]p5:
+ // A copy/move [constructor or assignment operator] is trivial if
+ // -- the [member] selected to copy/move each direct base class subobject
+ // is trivial
+ //
+ // C++11 [class.copy]p12, C++11 [class.copy]p25:
+ // A [default constructor or destructor] is trivial if
+ // -- all the direct base classes have trivial [default constructors or
+ // destructors]
+ for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),
+ BE = RD->bases_end(); BI != BE; ++BI)
+ if (!checkTrivialSubobjectCall(*this, BI->getLocStart(),
+ ConstArg ? BI->getType().withConst()
+ : BI->getType(),
+ CSM, TSK_BaseClass, Diagnose))
+ return false;
+
+ // C++11 [class.ctor]p5, C++11 [class.dtor]p5:
+ // A copy/move [constructor or assignment operator] for a class X is
+ // trivial if
+ // -- for each non-static data member of X that is of class type (or array
+ // thereof), the constructor selected to copy/move that member is
+ // trivial
+ //
+ // C++11 [class.copy]p12, C++11 [class.copy]p25:
+ // A [default constructor or destructor] is trivial if
+ // -- for all of the non-static data members of its class that are of class
+ // type (or array thereof), each such class has a trivial [default
+ // constructor or destructor]
+ if (!checkTrivialClassMembers(*this, RD, CSM, ConstArg, Diagnose))
+ return false;
+
+ // C++11 [class.dtor]p5:
+ // A destructor is trivial if [...]
+ // -- the destructor is not virtual
+ if (CSM == CXXDestructor && MD->isVirtual()) {
+ if (Diagnose)
+ Diag(MD->getLocation(), diag::note_nontrivial_virtual_dtor) << RD;
+ return false;
+ }
+
+ // C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25:
+ // A [special member] for class X is trivial if [...]
+ // -- class X has no virtual functions and no virtual base classes
+ if (CSM != CXXDestructor && MD->getParent()->isDynamicClass()) {
+ if (!Diagnose)
+ return false;
+
+ if (RD->getNumVBases()) {
+ // Check for virtual bases. We already know that the corresponding
+ // member in all bases is trivial, so vbases must all be direct.
+ CXXBaseSpecifier &BS = *RD->vbases_begin();
+ assert(BS.isVirtual());
+ Diag(BS.getLocStart(), diag::note_nontrivial_has_virtual) << RD << 1;
+ return false;
+ }
+
+ // Must have a virtual method.
+ for (CXXRecordDecl::method_iterator MI = RD->method_begin(),
+ ME = RD->method_end(); MI != ME; ++MI) {
+ if (MI->isVirtual()) {
+ SourceLocation MLoc = MI->getLocStart();
+ Diag(MLoc, diag::note_nontrivial_has_virtual) << RD << 0;
+ return false;
+ }
+ }
+
+ llvm_unreachable("dynamic class with no vbases and no virtual functions");
+ }
+
+ // Looks like it's trivial!
+ return true;
+}
+
/// \brief Data used with FindHiddenVirtualMethod
namespace {
struct FindHiddenVirtualMethodData {
@@ -4823,9 +5339,9 @@ static bool FindHiddenVirtualMethod(const CXXBaseSpecifier *Specifier,
bool foundSameNameMethod = false;
SmallVector<CXXMethodDecl *, 8> overloadedMethods;
for (Path.Decls = BaseRecord->lookup(Name);
- Path.Decls.first != Path.Decls.second;
- ++Path.Decls.first) {
- NamedDecl *D = *Path.Decls.first;
+ !Path.Decls.empty();
+ Path.Decls = Path.Decls.slice(1)) {
+ NamedDecl *D = Path.Decls.front();
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
MD = MD->getCanonicalDecl();
foundSameNameMethod = true;
@@ -4877,10 +5393,10 @@ void Sema::DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
// Keep the base methods that were overriden or introduced in the subclass
// by 'using' in a set. A base method not in this set is hidden.
- for (DeclContext::lookup_result res = DC->lookup(MD->getDeclName());
- res.first != res.second; ++res.first) {
- NamedDecl *ND = *res.first;
- if (UsingShadowDecl *shad = dyn_cast<UsingShadowDecl>(*res.first))
+ DeclContext::lookup_result R = DC->lookup(MD->getDeclName());
+ for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E; ++I) {
+ NamedDecl *ND = *I;
+ if (UsingShadowDecl *shad = dyn_cast<UsingShadowDecl>(*I))
ND = shad->getTargetDecl();
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ND))
AddMostOverridenMethods(MD, Data.OverridenAndUsingBaseMethods);
@@ -4935,39 +5451,53 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
if (!ClassDecl->hasUserDeclaredConstructor())
++ASTContext::NumImplicitDefaultConstructors;
- if (!ClassDecl->hasUserDeclaredCopyConstructor())
+ if (!ClassDecl->hasUserDeclaredCopyConstructor()) {
++ASTContext::NumImplicitCopyConstructors;
- if (getLangOpts().CPlusPlus0x && ClassDecl->needsImplicitMoveConstructor())
+ // If the properties or semantics of the copy constructor couldn't be
+ // determined while the class was being declared, force a declaration
+ // of it now.
+ if (ClassDecl->needsOverloadResolutionForCopyConstructor())
+ DeclareImplicitCopyConstructor(ClassDecl);
+ }
+
+ if (getLangOpts().CPlusPlus11 && ClassDecl->needsImplicitMoveConstructor()) {
++ASTContext::NumImplicitMoveConstructors;
+ if (ClassDecl->needsOverloadResolutionForMoveConstructor())
+ DeclareImplicitMoveConstructor(ClassDecl);
+ }
+
if (!ClassDecl->hasUserDeclaredCopyAssignment()) {
++ASTContext::NumImplicitCopyAssignmentOperators;
-
- // If we have a dynamic class, then the copy assignment operator may be
+
+ // If we have a dynamic class, then the copy assignment operator may be
// virtual, so we have to declare it immediately. This ensures that, e.g.,
- // it shows up in the right place in the vtable and that we diagnose
- // problems with the implicit exception specification.
- if (ClassDecl->isDynamicClass())
+ // it shows up in the right place in the vtable and that we diagnose
+ // problems with the implicit exception specification.
+ if (ClassDecl->isDynamicClass() ||
+ ClassDecl->needsOverloadResolutionForCopyAssignment())
DeclareImplicitCopyAssignment(ClassDecl);
}
- if (getLangOpts().CPlusPlus0x && ClassDecl->needsImplicitMoveAssignment()) {
+ if (getLangOpts().CPlusPlus11 && ClassDecl->needsImplicitMoveAssignment()) {
++ASTContext::NumImplicitMoveAssignmentOperators;
// Likewise for the move assignment operator.
- if (ClassDecl->isDynamicClass())
+ if (ClassDecl->isDynamicClass() ||
+ ClassDecl->needsOverloadResolutionForMoveAssignment())
DeclareImplicitMoveAssignment(ClassDecl);
}
if (!ClassDecl->hasUserDeclaredDestructor()) {
++ASTContext::NumImplicitDestructors;
-
- // If we have a dynamic class, then the destructor may be virtual, so we
+
+ // If we have a dynamic class, then the destructor may be virtual, so we
// have to declare the destructor immediately. This ensures that, e.g., it
// shows up in the right place in the vtable and that we diagnose problems
// with the implicit exception specification.
- if (ClassDecl->isDynamicClass())
+ if (ClassDecl->isDynamicClass() ||
+ ClassDecl->needsOverloadResolutionForDestructor())
DeclareImplicitDestructor(ClassDecl);
}
}
@@ -5150,8 +5680,7 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R,
EPI.TypeQuals = 0;
EPI.RefQualifier = RQ_None;
- return Context.getFunctionType(Context.VoidTy, Proto->arg_type_begin(),
- Proto->getNumArgs(), EPI);
+ return Context.getFunctionType(Context.VoidTy, Proto->getArgTypes(), EPI);
}
/// CheckConstructor - Checks a fully-formed constructor for
@@ -5331,7 +5860,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R,
EPI.Variadic = false;
EPI.TypeQuals = 0;
EPI.RefQualifier = RQ_None;
- return Context.getFunctionType(Context.VoidTy, 0, 0, EPI);
+ return Context.getFunctionType(Context.VoidTy, ArrayRef<QualType>(), EPI);
}
/// CheckConversionDeclarator - Called by ActOnDeclarator to check the
@@ -5412,12 +5941,13 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
// of the errors above fired) and with the conversion type as the
// return type.
if (D.isInvalidType())
- R = Context.getFunctionType(ConvType, 0, 0, Proto->getExtProtoInfo());
+ R = Context.getFunctionType(ConvType, ArrayRef<QualType>(),
+ Proto->getExtProtoInfo());
// C++0x explicit conversion operators.
if (D.getDeclSpec().isExplicitSpecified())
Diag(D.getDeclSpec().getExplicitSpecLoc(),
- getLangOpts().CPlusPlus0x ?
+ getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_explicit_conversion_functions :
diag::ext_explicit_conversion_functions)
<< SourceRange(D.getDeclSpec().getExplicitSpecLoc());
@@ -5551,11 +6081,11 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
Decl::IDNS_Type | Decl::IDNS_Using | Decl::IDNS_Tag |
Decl::IDNS_Namespace;
NamedDecl *PrevDecl = 0;
- for (DeclContext::lookup_result R
- = CurContext->getRedeclContext()->lookup(II);
- R.first != R.second; ++R.first) {
- if ((*R.first)->getIdentifierNamespace() & IDNS) {
- PrevDecl = *R.first;
+ DeclContext::lookup_result R = CurContext->getRedeclContext()->lookup(II);
+ for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E;
+ ++I) {
+ if ((*I)->getIdentifierNamespace() & IDNS) {
+ PrevDecl = *I;
break;
}
}
@@ -5978,7 +6508,9 @@ Decl *Sema::ActOnUsingDirective(Scope *S,
Diag(IdentLoc, diag::err_expected_namespace_name) << SS.getRange();
}
- // FIXME: We ignore attributes for now.
+ if (UDir)
+ ProcessDeclAttributeList(S, UDir, AttrList);
+
return UDir;
}
@@ -6019,14 +6551,12 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S,
case UnqualifiedId::IK_ConstructorTemplateId:
// C++11 inheriting constructors.
Diag(Name.getLocStart(),
- getLangOpts().CPlusPlus0x ?
- // FIXME: Produce warn_cxx98_compat_using_decl_constructor
- // instead once inheriting constructors work.
- diag::err_using_decl_constructor_unsupported :
+ getLangOpts().CPlusPlus11 ?
+ diag::warn_cxx98_compat_using_decl_constructor :
diag::err_using_decl_constructor)
<< SS.getRange();
- if (getLangOpts().CPlusPlus0x) break;
+ if (getLangOpts().CPlusPlus11) break;
return 0;
@@ -6046,7 +6576,7 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S,
if (!TargetName)
return 0;
- // Warn about using declarations.
+ // Warn about access declarations.
// TODO: store that the declaration was written without 'using' and
// talk about access decls instead of using decls in the
// diagnostics.
@@ -6116,7 +6646,7 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig,
// specialization. The UsingShadowDecl in D<T> then points directly
// to A::foo, which will look well-formed when we instantiate.
// The right solution is to not collapse the shadow-decl chain.
- if (!getLangOpts().CPlusPlus0x && CurContext->isRecord()) {
+ if (!getLangOpts().CPlusPlus11 && CurContext->isRecord()) {
DeclContext *OrigDC = Orig->getDeclContext();
// Handle enums and anonymous structs.
@@ -6605,7 +7135,7 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc,
RequireCompleteDeclContext(const_cast<CXXScopeSpec&>(SS), NamedContext))
return true;
- if (getLangOpts().CPlusPlus0x) {
+ if (getLangOpts().CPlusPlus11) {
// C++0x [namespace.udecl]p3:
// In a using-declaration used as a member-declaration, the
// nested-name-specifier shall name a base class of the class
@@ -6694,6 +7224,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
MultiTemplateParamsArg TemplateParamLists,
SourceLocation UsingLoc,
UnqualifiedId &Name,
+ AttributeList *AttrList,
TypeResult Type) {
// Skip up to the relevant declaration scope.
while (S->getFlags() & Scope::TemplateParamScope)
@@ -6740,6 +7271,8 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
if (Invalid)
NewTD->setInvalidDecl();
+ ProcessDeclAttributeList(S, NewTD, AttrList);
+
CheckTypedefForVariablyModifiedType(S, NewTD);
Invalid |= NewTD->isInvalidDecl();
@@ -6969,6 +7502,43 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc,
return ExceptSpec;
}
+Sema::ImplicitExceptionSpecification
+Sema::ComputeInheritingCtorExceptionSpec(CXXMethodDecl *MD) {
+ ImplicitExceptionSpecification ExceptSpec(*this);
+ // FIXME: Compute the exception spec.
+ return ExceptSpec;
+}
+
+namespace {
+/// RAII object to register a special member as being currently declared.
+struct DeclaringSpecialMember {
+ Sema &S;
+ Sema::SpecialMemberDecl D;
+ bool WasAlreadyBeingDeclared;
+
+ DeclaringSpecialMember(Sema &S, CXXRecordDecl *RD, Sema::CXXSpecialMember CSM)
+ : S(S), D(RD, CSM) {
+ WasAlreadyBeingDeclared = !S.SpecialMembersBeingDeclared.insert(D);
+ if (WasAlreadyBeingDeclared)
+ // This almost never happens, but if it does, ensure that our cache
+ // doesn't contain a stale result.
+ S.SpecialMemberCache.clear();
+
+ // FIXME: Register a note to be produced if we encounter an error while
+ // declaring the special member.
+ }
+ ~DeclaringSpecialMember() {
+ if (!WasAlreadyBeingDeclared)
+ S.SpecialMembersBeingDeclared.erase(D);
+ }
+
+ /// \brief Are we already trying to declare this special member?
+ bool isAlreadyBeingDeclared() const {
+ return WasAlreadyBeingDeclared;
+ }
+};
+}
+
CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
CXXRecordDecl *ClassDecl) {
// C++ [class.ctor]p5:
@@ -6977,9 +7547,13 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
// user-declared constructor for class X, a default constructor is
// implicitly declared. An implicitly-declared default constructor
// is an inline public member of its class.
- assert(!ClassDecl->hasUserDeclaredConstructor() &&
+ assert(ClassDecl->needsImplicitDefaultConstructor() &&
"Should not build implicit default constructor!");
+ DeclaringSpecialMember DSM(*this, ClassDecl, CXXDefaultConstructor);
+ if (DSM.isAlreadyBeingDeclared())
+ return 0;
+
bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl,
CXXDefaultConstructor,
false);
@@ -6998,24 +7572,29 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
DefaultCon->setAccess(AS_public);
DefaultCon->setDefaulted();
DefaultCon->setImplicit();
- DefaultCon->setTrivial(ClassDecl->hasTrivialDefaultConstructor());
// Build an exception specification pointing back at this constructor.
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = DefaultCon;
- DefaultCon->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
+ DefaultCon->setType(Context.getFunctionType(Context.VoidTy,
+ ArrayRef<QualType>(),
+ EPI));
+
+ // We don't need to use SpecialMemberIsTrivial here; triviality for default
+ // constructors is easy to compute.
+ DefaultCon->setTrivial(ClassDecl->hasTrivialDefaultConstructor());
+
+ if (ShouldDeleteSpecialMember(DefaultCon, CXXDefaultConstructor))
+ SetDeclDeleted(DefaultCon, ClassLoc);
// Note that we have declared this constructor.
++ASTContext::NumImplicitDefaultConstructorsDeclared;
-
+
if (Scope *S = getScopeForContext(ClassDecl))
PushOnScopeChains(DefaultCon, S, false);
ClassDecl->addDecl(DefaultCon);
- if (ShouldDeleteSpecialMember(DefaultCon, CXXDefaultConstructor))
- DefaultCon->setDeletedAsWritten();
-
return DefaultCon;
}
@@ -7031,7 +7610,7 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
SynthesizedFunctionScope Scope(*this, Constructor);
DiagnosticErrorTrap Trap(Diags);
- if (SetCtorInitializers(Constructor, 0, 0, /*AnyErrors=*/false) ||
+ if (SetCtorInitializers(Constructor, /*AnyErrors=*/false) ||
Trap.hasErrorOccurred()) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
<< CXXDefaultConstructor << Context.getTagDeclType(ClassDecl);
@@ -7051,16 +7630,12 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation,
}
void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) {
- if (!D) return;
- AdjustDeclIfTemplate(D);
-
- CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D);
-
- if (!ClassDecl->isDependentType())
- CheckExplicitlyDefaultedMethods(ClassDecl);
+ // Check that any explicitly-defaulted methods have exception specifications
+ // compatible with their implicit exception specifications.
+ CheckDelayedExplicitlyDefaultedMemberExceptionSpecs();
}
-void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
+void Sema::DeclareInheritingConstructors(CXXRecordDecl *ClassDecl) {
// We start with an initial pass over the base classes to collect those that
// inherit constructors from. If there are none, we can forgo all further
// processing.
@@ -7075,6 +7650,8 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
// If we inherit constructors from anything that is dependent, just
// abort processing altogether. We'll get another chance for the
// instantiations.
+ // FIXME: We need to ensure that any call to a constructor of this class
+ // is considered instantiation-dependent in this case.
return;
}
BasesToInheritFrom.push_back(Base->castAs<RecordType>());
@@ -7083,18 +7660,19 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
if (BasesToInheritFrom.empty())
return;
+ // FIXME: Constructor templates.
+
// Now collect the constructors that we already have in the current class.
// Those take precedence over inherited constructors.
- // C++0x [class.inhctor]p3: [...] a constructor is implicitly declared [...]
+ // C++11 [class.inhctor]p3: [...] a constructor is implicitly declared [...]
// unless there is a user-declared constructor with the same signature in
// the class where the using-declaration appears.
llvm::SmallSet<const Type *, 8> ExistingConstructors;
for (CXXRecordDecl::ctor_iterator CtorIt = ClassDecl->ctor_begin(),
CtorE = ClassDecl->ctor_end();
- CtorIt != CtorE; ++CtorIt) {
+ CtorIt != CtorE; ++CtorIt)
ExistingConstructors.insert(
Context.getCanonicalType(CtorIt->getType()).getTypePtr());
- }
DeclarationName CreatedCtorName =
Context.DeclarationNames.getCXXConstructorName(
@@ -7126,62 +7704,71 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
SourceLocation UsingLoc = UD ? UD->getLocation() :
ClassDecl->getLocation();
- // C++0x [class.inhctor]p1: The candidate set of inherited constructors
- // from the class X named in the using-declaration consists of actual
- // constructors and notional constructors that result from the
- // transformation of defaulted parameters as follows:
- // - all non-template default constructors of X, and
+ // C++11 [class.inhctor]p1:
+ // The candidate set of inherited constructors from the class X named in
+ // the using-declaration consists of actual constructors and notional
+ // constructors that result from the transformation of defaulted
+ // parameters as follows:
+ // - all non-template constructors of X, and
// - for each non-template constructor of X that has at least one
// parameter with a default argument, the set of constructors that
// results from omitting any ellipsis parameter specification and
// successively omitting parameters with a default argument from the
- // end of the parameter-type-list.
+ // end of the parameter-type-list, and
+ // FIXME: ...also constructor templates.
CXXConstructorDecl *BaseCtor = *CtorIt;
bool CanBeCopyOrMove = BaseCtor->isCopyOrMoveConstructor();
const FunctionProtoType *BaseCtorType =
BaseCtor->getType()->getAs<FunctionProtoType>();
- for (unsigned params = BaseCtor->getMinRequiredArguments(),
- maxParams = BaseCtor->getNumParams();
- params <= maxParams; ++params) {
+ // Determine whether this would be a copy or move constructor for the
+ // derived class.
+ if (BaseCtorType->getNumArgs() >= 1 &&
+ BaseCtorType->getArgType(0)->isReferenceType() &&
+ Context.hasSameUnqualifiedType(
+ BaseCtorType->getArgType(0)->getPointeeType(),
+ Context.getTagDeclType(ClassDecl)))
+ CanBeCopyOrMove = true;
+
+ ArrayRef<QualType> ArgTypes(BaseCtorType->getArgTypes());
+ FunctionProtoType::ExtProtoInfo EPI = BaseCtorType->getExtProtoInfo();
+ // Core issue (no number yet): the ellipsis is always discarded.
+ if (EPI.Variadic) {
+ Diag(UsingLoc, diag::warn_using_decl_constructor_ellipsis);
+ Diag(BaseCtor->getLocation(),
+ diag::note_using_decl_constructor_ellipsis);
+ EPI.Variadic = false;
+ }
+
+ for (unsigned Params = BaseCtor->getMinRequiredArguments(),
+ MaxParams = BaseCtor->getNumParams();
+ Params <= MaxParams; ++Params) {
// Skip default constructors. They're never inherited.
- if (params == 0)
+ if (Params == 0)
continue;
- // Skip copy and move constructors for the same reason.
- if (CanBeCopyOrMove && params == 1)
+
+ // Skip copy and move constructors for both base and derived class
+ // for the same reason.
+ if (CanBeCopyOrMove && Params == 1)
continue;
// Build up a function type for this particular constructor.
- // FIXME: The working paper does not consider that the exception spec
- // for the inheriting constructor might be larger than that of the
- // source. This code doesn't yet, either. When it does, this code will
- // need to be delayed until after exception specifications and in-class
- // member initializers are attached.
- const Type *NewCtorType;
- if (params == maxParams)
- NewCtorType = BaseCtorType;
- else {
- SmallVector<QualType, 16> Args;
- for (unsigned i = 0; i < params; ++i) {
- Args.push_back(BaseCtorType->getArgType(i));
- }
- FunctionProtoType::ExtProtoInfo ExtInfo =
- BaseCtorType->getExtProtoInfo();
- ExtInfo.Variadic = false;
- NewCtorType = Context.getFunctionType(BaseCtorType->getResultType(),
- Args.data(), params, ExtInfo)
- .getTypePtr();
- }
+ QualType NewCtorType =
+ Context.getFunctionType(Context.VoidTy, ArgTypes.slice(0, Params),
+ EPI);
const Type *CanonicalNewCtorType =
- Context.getCanonicalType(NewCtorType);
+ Context.getCanonicalType(NewCtorType).getTypePtr();
- // Now that we have the type, first check if the class already has a
- // constructor with this signature.
+ // C++11 [class.inhctor]p3:
+ // ... a constructor is implicitly declared with the same constructor
+ // characteristics unless there is a user-declared constructor with
+ // the same signature in the class where the using-declaration appears
if (ExistingConstructors.count(CanonicalNewCtorType))
continue;
- // Then we check if we have already declared an inherited constructor
- // with this signature.
+ // C++11 [class.inhctor]p7:
+ // If two using-declarations declare inheriting constructors with the
+ // same signature, the program is ill-formed
std::pair<ConstructorToSourceMap::iterator, bool> result =
InheritedConstructors.insert(std::make_pair(
CanonicalNewCtorType,
@@ -7203,35 +7790,47 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
diag::note_using_decl_constructor_conflict_previous_ctor);
Diag(PrevCtor->getLocation(),
diag::note_using_decl_constructor_conflict_previous_using);
+ } else {
+ // Core issue (no number): if the same inheriting constructor is
+ // produced by multiple base class constructors from the same base
+ // class, the inheriting constructor is defined as deleted.
+ SetDeclDeleted(result.first->second.second, UsingLoc);
}
continue;
}
// OK, we're there, now add the constructor.
- // C++0x [class.inhctor]p8: [...] that would be performed by a
- // user-written inline constructor [...]
DeclarationNameInfo DNI(CreatedCtorName, UsingLoc);
CXXConstructorDecl *NewCtor = CXXConstructorDecl::Create(
- Context, ClassDecl, UsingLoc, DNI, QualType(NewCtorType, 0),
+ Context, ClassDecl, UsingLoc, DNI, NewCtorType,
/*TInfo=*/0, BaseCtor->isExplicit(), /*Inline=*/true,
- /*ImplicitlyDeclared=*/true,
- // FIXME: Due to a defect in the standard, we treat inherited
- // constructors as constexpr even if that makes them ill-formed.
- /*Constexpr=*/BaseCtor->isConstexpr());
+ /*ImplicitlyDeclared=*/true, /*Constexpr=*/BaseCtor->isConstexpr());
NewCtor->setAccess(BaseCtor->getAccess());
+ // Build an unevaluated exception specification for this constructor.
+ EPI.ExceptionSpecType = EST_Unevaluated;
+ EPI.ExceptionSpecDecl = NewCtor;
+ NewCtor->setType(Context.getFunctionType(Context.VoidTy,
+ ArgTypes.slice(0, Params),
+ EPI));
+
// Build up the parameter decls and add them.
SmallVector<ParmVarDecl *, 16> ParamDecls;
- for (unsigned i = 0; i < params; ++i) {
- ParamDecls.push_back(ParmVarDecl::Create(Context, NewCtor,
- UsingLoc, UsingLoc,
- /*IdentifierInfo=*/0,
- BaseCtorType->getArgType(i),
- /*TInfo=*/0, SC_None,
- SC_None, /*DefaultArg=*/0));
+ for (unsigned i = 0; i < Params; ++i) {
+ ParmVarDecl *PD = ParmVarDecl::Create(Context, NewCtor,
+ UsingLoc, UsingLoc,
+ /*IdentifierInfo=*/0,
+ BaseCtorType->getArgType(i),
+ /*TInfo=*/0, SC_None,
+ /*DefaultArg=*/0);
+ PD->setScopeInfo(0, i);
+ PD->setImplicit();
+ ParamDecls.push_back(PD);
}
NewCtor->setParams(ParamDecls);
NewCtor->setInheritedConstructor(BaseCtor);
+ if (BaseCtor->isDeleted())
+ SetDeclDeleted(NewCtor, UsingLoc);
ClassDecl->addDecl(NewCtor);
result.first->second.second = NewCtor;
@@ -7240,6 +7839,35 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) {
}
}
+void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation,
+ CXXConstructorDecl *Constructor) {
+ CXXRecordDecl *ClassDecl = Constructor->getParent();
+ assert(Constructor->getInheritedConstructor() &&
+ !Constructor->doesThisDeclarationHaveABody() &&
+ !Constructor->isDeleted());
+
+ SynthesizedFunctionScope Scope(*this, Constructor);
+ DiagnosticErrorTrap Trap(Diags);
+ if (SetCtorInitializers(Constructor, /*AnyErrors=*/false) ||
+ Trap.hasErrorOccurred()) {
+ Diag(CurrentLocation, diag::note_inhctor_synthesized_at)
+ << Context.getTagDeclType(ClassDecl);
+ Constructor->setInvalidDecl();
+ return;
+ }
+
+ SourceLocation Loc = Constructor->getLocation();
+ Constructor->setBody(new (Context) CompoundStmt(Loc));
+
+ Constructor->setUsed();
+ MarkVTableUsed(CurrentLocation, ClassDecl);
+
+ if (ASTMutationListener *L = getASTMutationListener()) {
+ L->CompletedImplicitDefinition(Constructor);
+ }
+}
+
+
Sema::ImplicitExceptionSpecification
Sema::ComputeDefaultedDtorExceptionSpec(CXXMethodDecl *MD) {
CXXRecordDecl *ClassDecl = MD->getParent();
@@ -7290,6 +7918,11 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
// If a class has no user-declared destructor, a destructor is
// declared implicitly. An implicitly-declared destructor is an
// inline public member of its class.
+ assert(ClassDecl->needsImplicitDestructor());
+
+ DeclaringSpecialMember DSM(*this, ClassDecl, CXXDestructor);
+ if (DSM.isAlreadyBeingDeclared())
+ return 0;
// Create the actual destructor declaration.
CanQualType ClassType
@@ -7305,13 +7938,23 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
Destructor->setAccess(AS_public);
Destructor->setDefaulted();
Destructor->setImplicit();
- Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
// Build an exception specification pointing back at this destructor.
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = Destructor;
- Destructor->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
+ Destructor->setType(Context.getFunctionType(Context.VoidTy,
+ ArrayRef<QualType>(),
+ EPI));
+
+ AddOverriddenMethods(ClassDecl, Destructor);
+
+ // We don't need to use SpecialMemberIsTrivial here; triviality for
+ // destructors is easy to compute.
+ Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
+
+ if (ShouldDeleteSpecialMember(Destructor, CXXDestructor))
+ SetDeclDeleted(Destructor, ClassLoc);
// Note that we have declared this destructor.
++ASTContext::NumImplicitDestructorsDeclared;
@@ -7321,11 +7964,6 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
PushOnScopeChains(Destructor, S, false);
ClassDecl->addDecl(Destructor);
- AddOverriddenMethods(ClassDecl, Destructor);
-
- if (ShouldDeleteSpecialMember(Destructor, CXXDestructor))
- Destructor->setDeletedAsWritten();
-
return Destructor;
}
@@ -7369,6 +8007,14 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation,
/// \brief Perform any semantic analysis which needs to be delayed until all
/// pending class member declarations have been parsed.
void Sema::ActOnFinishCXXMemberDecls() {
+ // If the context is an invalid C++ class, just suppress these checks.
+ if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(CurContext)) {
+ if (Record->isInvalidDecl()) {
+ DelayedDestructorExceptionSpecChecks.clear();
+ return;
+ }
+ }
+
// Perform any deferred checking of exception specifications for virtual
// destructors.
for (unsigned i = 0, e = DelayedDestructorExceptionSpecChecks.size();
@@ -7385,7 +8031,7 @@ void Sema::ActOnFinishCXXMemberDecls() {
void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl,
CXXDestructorDecl *Destructor) {
- assert(getLangOpts().CPlusPlus0x &&
+ assert(getLangOpts().CPlusPlus11 &&
"adjusting dtor exception specs was introduced in c++11");
// C++11 [class.dtor]p3:
@@ -7403,7 +8049,9 @@ void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl,
FunctionProtoType::ExtProtoInfo EPI = DtorType->getExtProtoInfo();
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = Destructor;
- Destructor->setType(Context.getFunctionType(Context.VoidTy, 0, 0, EPI));
+ Destructor->setType(Context.getFunctionType(Context.VoidTy,
+ ArrayRef<QualType>(),
+ EPI));
// FIXME: If the destructor has a body that could throw, and the newly created
// spec doesn't allow exceptions, we should emit a warning, because this
@@ -7412,6 +8060,60 @@ void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl,
// needs to be done somewhere else.
}
+/// When generating a defaulted copy or move assignment operator, if a field
+/// should be copied with __builtin_memcpy rather than via explicit assignments,
+/// do so. This optimization only applies for arrays of scalars, and for arrays
+/// of class type where the selected copy/move-assignment operator is trivial.
+static StmtResult
+buildMemcpyForAssignmentOp(Sema &S, SourceLocation Loc, QualType T,
+ Expr *To, Expr *From) {
+ // Compute the size of the memory buffer to be copied.
+ QualType SizeType = S.Context.getSizeType();
+ llvm::APInt Size(S.Context.getTypeSize(SizeType),
+ S.Context.getTypeSizeInChars(T).getQuantity());
+
+ // Take the address of the field references for "from" and "to". We
+ // directly construct UnaryOperators here because semantic analysis
+ // does not permit us to take the address of an xvalue.
+ From = new (S.Context) UnaryOperator(From, UO_AddrOf,
+ S.Context.getPointerType(From->getType()),
+ VK_RValue, OK_Ordinary, Loc);
+ To = new (S.Context) UnaryOperator(To, UO_AddrOf,
+ S.Context.getPointerType(To->getType()),
+ VK_RValue, OK_Ordinary, Loc);
+
+ const Type *E = T->getBaseElementTypeUnsafe();
+ bool NeedsCollectableMemCpy =
+ E->isRecordType() && E->getAs<RecordType>()->getDecl()->hasObjectMember();
+
+ // Create a reference to the __builtin_objc_memmove_collectable function
+ StringRef MemCpyName = NeedsCollectableMemCpy ?
+ "__builtin_objc_memmove_collectable" :
+ "__builtin_memcpy";
+ LookupResult R(S, &S.Context.Idents.get(MemCpyName), Loc,
+ Sema::LookupOrdinaryName);
+ S.LookupName(R, S.TUScope, true);
+
+ FunctionDecl *MemCpy = R.getAsSingle<FunctionDecl>();
+ if (!MemCpy)
+ // Something went horribly wrong earlier, and we will have complained
+ // about it.
+ return StmtError();
+
+ ExprResult MemCpyRef = S.BuildDeclRefExpr(MemCpy, S.Context.BuiltinFnTy,
+ VK_RValue, Loc, 0);
+ assert(MemCpyRef.isUsable() && "Builtin reference cannot fail");
+
+ Expr *CallArgs[] = {
+ To, From, IntegerLiteral::Create(S.Context, Size, SizeType, Loc)
+ };
+ ExprResult Call = S.ActOnCallExpr(/*Scope=*/0, MemCpyRef.take(),
+ Loc, CallArgs, Loc);
+
+ assert(!Call.isInvalid() && "Call to __builtin_memcpy cannot fail!");
+ return S.Owned(Call.takeAs<Stmt>());
+}
+
/// \brief Builds a statement that copies/moves the given entity from \p From to
/// \c To.
///
@@ -7437,13 +8139,14 @@ void Sema::AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl,
///
/// \param Depth Internal parameter recording the depth of the recursion.
///
-/// \returns A statement or a loop that copies the expressions.
+/// \returns A statement or a loop that copies the expressions, or StmtResult(0)
+/// if a memcpy should be used instead.
static StmtResult
-BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
- Expr *To, Expr *From,
- bool CopyingBaseSubobject, bool Copying,
- unsigned Depth = 0) {
- // C++0x [class.copy]p28:
+buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
+ Expr *To, Expr *From,
+ bool CopyingBaseSubobject, bool Copying,
+ unsigned Depth = 0) {
+ // C++11 [class.copy]p28:
// Each subobject is assigned in the manner appropriate to its type:
//
// - if the subobject is of class type, as if by a call to operator= with
@@ -7451,32 +8154,41 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
// subobject of x as a single function argument (as if by explicit
// qualification; that is, ignoring any possible virtual overriding
// functions in more derived classes);
+ //
+ // C++03 [class.copy]p13:
+ // - if the subobject is of class type, the copy assignment operator for
+ // the class is used (as if by explicit qualification; that is,
+ // ignoring any possible virtual overriding functions in more derived
+ // classes);
if (const RecordType *RecordTy = T->getAs<RecordType>()) {
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
-
+
// Look for operator=.
DeclarationName Name
= S.Context.DeclarationNames.getCXXOperatorName(OO_Equal);
LookupResult OpLookup(S, Name, Loc, Sema::LookupOrdinaryName);
S.LookupQualifiedName(OpLookup, ClassDecl, false);
-
- // Filter out any result that isn't a copy/move-assignment operator.
- LookupResult::Filter F = OpLookup.makeFilter();
- while (F.hasNext()) {
- NamedDecl *D = F.next();
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
- if (Method->isCopyAssignmentOperator() ||
- (!Copying && Method->isMoveAssignmentOperator()))
- continue;
- F.erase();
+ // Prior to C++11, filter out any result that isn't a copy/move-assignment
+ // operator.
+ if (!S.getLangOpts().CPlusPlus11) {
+ LookupResult::Filter F = OpLookup.makeFilter();
+ while (F.hasNext()) {
+ NamedDecl *D = F.next();
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))
+ if (Method->isCopyAssignmentOperator() ||
+ (!Copying && Method->isMoveAssignmentOperator()))
+ continue;
+
+ F.erase();
+ }
+ F.done();
}
- F.done();
-
+
// Suppress the protected check (C++ [class.protected]) for each of the
- // assignment operators we found. This strange dance is required when
+ // assignment operators we found. This strange dance is required when
// we're assigning via a base classes's copy-assignment operator. To
- // ensure that we're getting the right base class subobject (without
+ // ensure that we're getting the right base class subobject (without
// ambiguities), we need to cast "this" to that subobject type; to
// ensure that we don't go through the virtual call mechanism, we need
// to qualify the operator= name with the base class (see below). However,
@@ -7491,20 +8203,20 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
L.setAccess(AS_public);
}
}
-
+
// Create the nested-name-specifier that will be used to qualify the
// reference to operator=; this is required to suppress the virtual
// call mechanism.
CXXScopeSpec SS;
const Type *CanonicalT = S.Context.getCanonicalType(T.getTypePtr());
- SS.MakeTrivial(S.Context,
- NestedNameSpecifier::Create(S.Context, 0, false,
+ SS.MakeTrivial(S.Context,
+ NestedNameSpecifier::Create(S.Context, 0, false,
CanonicalT),
Loc);
-
+
// Create the reference to operator=.
ExprResult OpEqualRef
- = S.BuildMemberReferenceExpr(To, T, Loc, /*isArrow=*/false, SS,
+ = S.BuildMemberReferenceExpr(To, T, Loc, /*isArrow=*/false, SS,
/*TemplateKWLoc=*/SourceLocation(),
/*FirstQualifierInScope=*/0,
OpLookup,
@@ -7512,39 +8224,46 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
/*SuppressQualifierCheck=*/true);
if (OpEqualRef.isInvalid())
return StmtError();
-
+
// Build the call to the assignment operator.
- ExprResult Call = S.BuildCallToMemberFunction(/*Scope=*/0,
+ ExprResult Call = S.BuildCallToMemberFunction(/*Scope=*/0,
OpEqualRef.takeAs<Expr>(),
Loc, &From, 1, Loc);
if (Call.isInvalid())
return StmtError();
-
- return S.Owned(Call.takeAs<Stmt>());
+
+ // If we built a call to a trivial 'operator=' while copying an array,
+ // bail out. We'll replace the whole shebang with a memcpy.
+ CXXMemberCallExpr *CE = dyn_cast<CXXMemberCallExpr>(Call.get());
+ if (CE && CE->getMethodDecl()->isTrivial() && Depth)
+ return StmtResult((Stmt*)0);
+
+ // Convert to an expression-statement, and clean up any produced
+ // temporaries.
+ return S.ActOnExprStmt(Call);
}
- // - if the subobject is of scalar type, the built-in assignment
+ // - if the subobject is of scalar type, the built-in assignment
// operator is used.
- const ConstantArrayType *ArrayTy = S.Context.getAsConstantArrayType(T);
+ const ConstantArrayType *ArrayTy = S.Context.getAsConstantArrayType(T);
if (!ArrayTy) {
ExprResult Assignment = S.CreateBuiltinBinOp(Loc, BO_Assign, To, From);
if (Assignment.isInvalid())
return StmtError();
-
- return S.Owned(Assignment.takeAs<Stmt>());
+ return S.ActOnExprStmt(Assignment);
}
-
- // - if the subobject is an array, each element is assigned, in the
+
+ // - if the subobject is an array, each element is assigned, in the
// manner appropriate to the element type;
-
+
// Construct a loop over the array bounds, e.g.,
//
// for (__SIZE_TYPE__ i0 = 0; i0 != array-size; ++i0)
//
// that will copy each of the array elements.
QualType SizeType = S.Context.getSizeType();
-
+
// Create the iteration variable.
IdentifierInfo *IterationVarName = 0;
{
@@ -7556,8 +8275,8 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
VarDecl *IterationVar = VarDecl::Create(S.Context, S.CurContext, Loc, Loc,
IterationVarName, SizeType,
S.Context.getTrivialTypeSourceInfo(SizeType, Loc),
- SC_None, SC_None);
-
+ SC_None);
+
// Initialize the iteration variable to zero.
llvm::APInt Zero(S.Context.getTypeSize(SizeType), 0);
IterationVar->setInit(IntegerLiteral::Create(S.Context, Zero, SizeType, Loc));
@@ -7572,7 +8291,26 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
// Create the DeclStmt that holds the iteration variable.
Stmt *InitStmt = new (S.Context) DeclStmt(DeclGroupRef(IterationVar),Loc,Loc);
-
+
+ // Subscript the "from" and "to" expressions with the iteration variable.
+ From = AssertSuccess(S.CreateBuiltinArraySubscriptExpr(From, Loc,
+ IterationVarRefRVal,
+ Loc));
+ To = AssertSuccess(S.CreateBuiltinArraySubscriptExpr(To, Loc,
+ IterationVarRefRVal,
+ Loc));
+ if (!Copying) // Cast to rvalue
+ From = CastForMoving(S, From);
+
+ // Build the copy/move for an individual element of the array.
+ StmtResult Copy =
+ buildSingleCopyAssignRecursively(S, Loc, ArrayTy->getElementType(),
+ To, From, CopyingBaseSubobject,
+ Copying, Depth + 1);
+ // Bail out if copying fails or if we determined that we should use memcpy.
+ if (Copy.isInvalid() || !Copy.get())
+ return Copy;
+
// Create the comparison against the array bound.
llvm::APInt Upper
= ArrayTy->getSize().zextOrTrunc(S.Context.getTypeSize(SizeType));
@@ -7581,104 +8319,38 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
IntegerLiteral::Create(S.Context, Upper, SizeType, Loc),
BO_NE, S.Context.BoolTy,
VK_RValue, OK_Ordinary, Loc, false);
-
+
// Create the pre-increment of the iteration variable.
Expr *Increment
= new (S.Context) UnaryOperator(IterationVarRef, UO_PreInc, SizeType,
VK_LValue, OK_Ordinary, Loc);
-
- // Subscript the "from" and "to" expressions with the iteration variable.
- From = AssertSuccess(S.CreateBuiltinArraySubscriptExpr(From, Loc,
- IterationVarRefRVal,
- Loc));
- To = AssertSuccess(S.CreateBuiltinArraySubscriptExpr(To, Loc,
- IterationVarRefRVal,
- Loc));
- if (!Copying) // Cast to rvalue
- From = CastForMoving(S, From);
- // Build the copy/move for an individual element of the array.
- StmtResult Copy = BuildSingleCopyAssign(S, Loc, ArrayTy->getElementType(),
- To, From, CopyingBaseSubobject,
- Copying, Depth + 1);
- if (Copy.isInvalid())
- return StmtError();
-
// Construct the loop that copies all elements of this array.
return S.ActOnForStmt(Loc, Loc, InitStmt,
S.MakeFullExpr(Comparison),
- 0, S.MakeFullExpr(Increment),
+ 0, S.MakeFullDiscardedValueExpr(Increment),
Loc, Copy.take());
}
-/// Determine whether an implicit copy assignment operator for ClassDecl has a
-/// const argument.
-/// FIXME: It ought to be possible to store this on the record.
-static bool isImplicitCopyAssignmentArgConst(Sema &S,
- CXXRecordDecl *ClassDecl) {
- if (ClassDecl->isInvalidDecl())
- return true;
+static StmtResult
+buildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T,
+ Expr *To, Expr *From,
+ bool CopyingBaseSubobject, bool Copying) {
+ // Maybe we should use a memcpy?
+ if (T->isArrayType() && !T.isConstQualified() && !T.isVolatileQualified() &&
+ T.isTriviallyCopyableType(S.Context))
+ return buildMemcpyForAssignmentOp(S, Loc, T, To, From);
- // C++ [class.copy]p10:
- // If the class definition does not explicitly declare a copy
- // assignment operator, one is declared implicitly.
- // The implicitly-defined copy assignment operator for a class X
- // will have the form
- //
- // X& X::operator=(const X&)
- //
- // if
- // -- each direct base class B of X has a copy assignment operator
- // whose parameter is of type const B&, const volatile B& or B,
- // and
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
- BaseEnd = ClassDecl->bases_end();
- Base != BaseEnd; ++Base) {
- // We'll handle this below
- if (S.getLangOpts().CPlusPlus0x && Base->isVirtual())
- continue;
+ StmtResult Result(buildSingleCopyAssignRecursively(S, Loc, T, To, From,
+ CopyingBaseSubobject,
+ Copying, 0));
- assert(!Base->getType()->isDependentType() &&
- "Cannot generate implicit members for class with dependent bases.");
- CXXRecordDecl *BaseClassDecl = Base->getType()->getAsCXXRecordDecl();
- if (!S.LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const, false, 0))
- return false;
- }
+ // If we ended up picking a trivial assignment operator for an array of a
+ // non-trivially-copyable class type, just emit a memcpy.
+ if (!Result.isInvalid() && !Result.get())
+ return buildMemcpyForAssignmentOp(S, Loc, T, To, From);
- // In C++11, the above citation has "or virtual" added
- if (S.getLangOpts().CPlusPlus0x) {
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
- BaseEnd = ClassDecl->vbases_end();
- Base != BaseEnd; ++Base) {
- assert(!Base->getType()->isDependentType() &&
- "Cannot generate implicit members for class with dependent bases.");
- CXXRecordDecl *BaseClassDecl = Base->getType()->getAsCXXRecordDecl();
- if (!S.LookupCopyingAssignment(BaseClassDecl, Qualifiers::Const,
- false, 0))
- return false;
- }
- }
-
- // -- for all the nonstatic data members of X that are of a class
- // type M (or array thereof), each such class type has a copy
- // assignment operator whose parameter is of type const M&,
- // const volatile M& or M.
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd; ++Field) {
- QualType FieldType = S.Context.getBaseElementType(Field->getType());
- if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl())
- if (!S.LookupCopyingAssignment(FieldClassDecl, Qualifiers::Const,
- false, 0))
- return false;
- }
-
- // Otherwise, the implicitly declared copy assignment operator will
- // have the form
- //
- // X& X::operator=(X&)
-
- return true;
+ return Result;
}
Sema::ImplicitExceptionSpecification
@@ -7748,10 +8420,15 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
// constructor rules. Note that virtual bases are not taken into account
// for determining the argument type of the operator. Note also that
// operators taking an object instead of a reference are allowed.
+ assert(ClassDecl->needsImplicitCopyAssignment());
+
+ DeclaringSpecialMember DSM(*this, ClassDecl, CXXCopyAssignment);
+ if (DSM.isAlreadyBeingDeclared())
+ return 0;
QualType ArgType = Context.getTypeDeclType(ClassDecl);
QualType RetType = Context.getLValueReferenceType(ArgType);
- if (isImplicitCopyAssignmentArgConst(*this, ClassDecl))
+ if (ClassDecl->implicitCopyAssignmentHasConstParam())
ArgType = ArgType.withConst();
ArgType = Context.getLValueReferenceType(ArgType);
@@ -7762,45 +8439,49 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
DeclarationNameInfo NameInfo(Name, ClassLoc);
CXXMethodDecl *CopyAssignment
= CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(),
- /*TInfo=*/0, /*isStatic=*/false,
- /*StorageClassAsWritten=*/SC_None,
+ /*TInfo=*/0,
+ /*StorageClass=*/SC_None,
/*isInline=*/true, /*isConstexpr=*/false,
SourceLocation());
CopyAssignment->setAccess(AS_public);
CopyAssignment->setDefaulted();
CopyAssignment->setImplicit();
- CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment());
// Build an exception specification pointing back at this member.
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = CopyAssignment;
- CopyAssignment->setType(Context.getFunctionType(RetType, &ArgType, 1, EPI));
+ CopyAssignment->setType(Context.getFunctionType(RetType, ArgType, EPI));
// Add the parameter to the operator.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment,
ClassLoc, ClassLoc, /*Id=*/0,
ArgType, /*TInfo=*/0,
- SC_None,
SC_None, 0);
CopyAssignment->setParams(FromParam);
-
- // Note that we have added this copy-assignment operator.
- ++ASTContext::NumImplicitCopyAssignmentOperatorsDeclared;
- if (Scope *S = getScopeForContext(ClassDecl))
- PushOnScopeChains(CopyAssignment, S, false);
- ClassDecl->addDecl(CopyAssignment);
-
+ AddOverriddenMethods(ClassDecl, CopyAssignment);
+
+ CopyAssignment->setTrivial(
+ ClassDecl->needsOverloadResolutionForCopyAssignment()
+ ? SpecialMemberIsTrivial(CopyAssignment, CXXCopyAssignment)
+ : ClassDecl->hasTrivialCopyAssignment());
+
// C++0x [class.copy]p19:
// .... If the class definition does not explicitly declare a copy
// assignment operator, there is no user-declared move constructor, and
// there is no user-declared move assignment operator, a copy assignment
// operator is implicitly declared as defaulted.
if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment))
- CopyAssignment->setDeletedAsWritten();
+ SetDeclDeleted(CopyAssignment, ClassLoc);
+
+ // Note that we have added this copy-assignment operator.
+ ++ASTContext::NumImplicitCopyAssignmentOperatorsDeclared;
+
+ if (Scope *S = getScopeForContext(ClassDecl))
+ PushOnScopeChains(CopyAssignment, S, false);
+ ClassDecl->addDecl(CopyAssignment);
- AddOverriddenMethods(ClassDecl, CopyAssignment);
return CopyAssignment;
}
@@ -7892,7 +8573,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
VK_LValue, &BasePath);
// Build the copy.
- StmtResult Copy = BuildSingleCopyAssign(*this, Loc, BaseType,
+ StmtResult Copy = buildSingleCopyAssign(*this, Loc, BaseType,
To.get(), From,
/*CopyingBaseSubobject=*/true,
/*Copying=*/true);
@@ -7907,11 +8588,6 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
Statements.push_back(Copy.takeAs<Expr>());
}
- // \brief Reference to the __builtin_memcpy function.
- Expr *BuiltinMemCpyRef = 0;
- // \brief Reference to the __builtin_objc_memmove_collectable function.
- Expr *CollectableMemCpyRef = 0;
-
// Assign non-static members.
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
FieldEnd = ClassDecl->field_end();
@@ -7969,99 +8645,9 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation,
MemberLookup, 0);
assert(!From.isInvalid() && "Implicit field reference cannot fail");
assert(!To.isInvalid() && "Implicit field reference cannot fail");
-
- // If the field should be copied with __builtin_memcpy rather than via
- // explicit assignments, do so. This optimization only applies for arrays
- // of scalars and arrays of class type with trivial copy-assignment
- // operators.
- if (FieldType->isArrayType() && !FieldType.isVolatileQualified()
- && BaseType.hasTrivialAssignment(Context, /*Copying=*/true)) {
- // Compute the size of the memory buffer to be copied.
- QualType SizeType = Context.getSizeType();
- llvm::APInt Size(Context.getTypeSize(SizeType),
- Context.getTypeSizeInChars(BaseType).getQuantity());
- for (const ConstantArrayType *Array
- = Context.getAsConstantArrayType(FieldType);
- Array;
- Array = Context.getAsConstantArrayType(Array->getElementType())) {
- llvm::APInt ArraySize
- = Array->getSize().zextOrTrunc(Size.getBitWidth());
- Size *= ArraySize;
- }
-
- // Take the address of the field references for "from" and "to".
- From = CreateBuiltinUnaryOp(Loc, UO_AddrOf, From.get());
- To = CreateBuiltinUnaryOp(Loc, UO_AddrOf, To.get());
-
- bool NeedsCollectableMemCpy =
- (BaseType->isRecordType() &&
- BaseType->getAs<RecordType>()->getDecl()->hasObjectMember());
-
- if (NeedsCollectableMemCpy) {
- if (!CollectableMemCpyRef) {
- // Create a reference to the __builtin_objc_memmove_collectable function.
- LookupResult R(*this,
- &Context.Idents.get("__builtin_objc_memmove_collectable"),
- Loc, LookupOrdinaryName);
- LookupName(R, TUScope, true);
-
- FunctionDecl *CollectableMemCpy = R.getAsSingle<FunctionDecl>();
- if (!CollectableMemCpy) {
- // Something went horribly wrong earlier, and we will have
- // complained about it.
- Invalid = true;
- continue;
- }
-
- CollectableMemCpyRef = BuildDeclRefExpr(CollectableMemCpy,
- Context.BuiltinFnTy,
- VK_RValue, Loc, 0).take();
- assert(CollectableMemCpyRef && "Builtin reference cannot fail");
- }
- }
- // Create a reference to the __builtin_memcpy builtin function.
- else if (!BuiltinMemCpyRef) {
- LookupResult R(*this, &Context.Idents.get("__builtin_memcpy"), Loc,
- LookupOrdinaryName);
- LookupName(R, TUScope, true);
-
- FunctionDecl *BuiltinMemCpy = R.getAsSingle<FunctionDecl>();
- if (!BuiltinMemCpy) {
- // Something went horribly wrong earlier, and we will have complained
- // about it.
- Invalid = true;
- continue;
- }
- BuiltinMemCpyRef = BuildDeclRefExpr(BuiltinMemCpy,
- Context.BuiltinFnTy,
- VK_RValue, Loc, 0).take();
- assert(BuiltinMemCpyRef && "Builtin reference cannot fail");
- }
-
- SmallVector<Expr*, 8> CallArgs;
- CallArgs.push_back(To.takeAs<Expr>());
- CallArgs.push_back(From.takeAs<Expr>());
- CallArgs.push_back(IntegerLiteral::Create(Context, Size, SizeType, Loc));
- ExprResult Call = ExprError();
- if (NeedsCollectableMemCpy)
- Call = ActOnCallExpr(/*Scope=*/0,
- CollectableMemCpyRef,
- Loc, CallArgs,
- Loc);
- else
- Call = ActOnCallExpr(/*Scope=*/0,
- BuiltinMemCpyRef,
- Loc, CallArgs,
- Loc);
-
- assert(!Call.isInvalid() && "Call to __builtin_memcpy cannot fail!");
- Statements.push_back(Call.takeAs<Expr>());
- continue;
- }
-
// Build the copy of this field.
- StmtResult Copy = BuildSingleCopyAssign(*this, Loc, FieldType,
+ StmtResult Copy = buildSingleCopyAssign(*this, Loc, FieldType,
To.get(), From.get(),
/*CopyingBaseSubobject=*/false,
/*Copying=*/true);
@@ -8188,10 +8774,7 @@ hasVirtualBaseWithNonTrivialMoveAssignment(Sema &S, CXXRecordDecl *ClassDecl) {
if (BaseClass->needsImplicitMoveAssignment())
S.DeclareImplicitMoveAssignment(BaseClass);
- // If the class has both a trivial move assignment and a non-trivial move
- // assignment, hasTrivialMoveAssignment() is false.
- if (BaseClass->hasDeclaredMoveAssignment() &&
- !BaseClass->hasTrivialMoveAssignment())
+ if (BaseClass->hasNonTrivialMoveAssignment())
return true;
}
@@ -8215,14 +8798,18 @@ hasMoveOrIsTriviallyCopyable(Sema &S, QualType Type, bool IsConstructor) {
return true;
if (IsConstructor) {
+ // FIXME: Need this because otherwise hasMoveConstructor isn't guaranteed to
+ // give the right answer.
if (ClassDecl->needsImplicitMoveConstructor())
S.DeclareImplicitMoveConstructor(ClassDecl);
- return ClassDecl->hasDeclaredMoveConstructor();
+ return ClassDecl->hasMoveConstructor();
}
+ // FIXME: Need this because otherwise hasMoveAssignment isn't guaranteed to
+ // give the right answer.
if (ClassDecl->needsImplicitMoveAssignment())
S.DeclareImplicitMoveAssignment(ClassDecl);
- return ClassDecl->hasDeclaredMoveAssignment();
+ return ClassDecl->hasMoveAssignment();
}
/// Determine whether all non-static data members and direct or virtual bases
@@ -8266,6 +8853,10 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
// - [first 4 bullets]
assert(ClassDecl->needsImplicitMoveAssignment());
+ DeclaringSpecialMember DSM(*this, ClassDecl, CXXMoveAssignment);
+ if (DSM.isAlreadyBeingDeclared())
+ return 0;
+
// [Checked after we build the declaration]
// - the move assignment operator would not be implicitly defined as
// deleted,
@@ -8296,32 +8887,34 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
DeclarationNameInfo NameInfo(Name, ClassLoc);
CXXMethodDecl *MoveAssignment
= CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(),
- /*TInfo=*/0, /*isStatic=*/false,
- /*StorageClassAsWritten=*/SC_None,
+ /*TInfo=*/0,
+ /*StorageClass=*/SC_None,
/*isInline=*/true,
/*isConstexpr=*/false,
SourceLocation());
MoveAssignment->setAccess(AS_public);
MoveAssignment->setDefaulted();
MoveAssignment->setImplicit();
- MoveAssignment->setTrivial(ClassDecl->hasTrivialMoveAssignment());
// Build an exception specification pointing back at this member.
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = MoveAssignment;
- MoveAssignment->setType(Context.getFunctionType(RetType, &ArgType, 1, EPI));
+ MoveAssignment->setType(Context.getFunctionType(RetType, ArgType, EPI));
// Add the parameter to the operator.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveAssignment,
ClassLoc, ClassLoc, /*Id=*/0,
ArgType, /*TInfo=*/0,
- SC_None,
SC_None, 0);
MoveAssignment->setParams(FromParam);
- // Note that we have added this copy-assignment operator.
- ++ASTContext::NumImplicitMoveAssignmentOperatorsDeclared;
+ AddOverriddenMethods(ClassDecl, MoveAssignment);
+
+ MoveAssignment->setTrivial(
+ ClassDecl->needsOverloadResolutionForMoveAssignment()
+ ? SpecialMemberIsTrivial(MoveAssignment, CXXMoveAssignment)
+ : ClassDecl->hasTrivialMoveAssignment());
// C++0x [class.copy]p9:
// If the definition of a class X does not explicitly declare a move
@@ -8337,11 +8930,13 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
return 0;
}
+ // Note that we have added this copy-assignment operator.
+ ++ASTContext::NumImplicitMoveAssignmentOperatorsDeclared;
+
if (Scope *S = getScopeForContext(ClassDecl))
PushOnScopeChains(MoveAssignment, S, false);
ClassDecl->addDecl(MoveAssignment);
- AddOverriddenMethods(ClassDecl, MoveAssignment);
return MoveAssignment;
}
@@ -8431,7 +9026,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
VK_LValue, &BasePath);
// Build the move.
- StmtResult Move = BuildSingleCopyAssign(*this, Loc, BaseType,
+ StmtResult Move = buildSingleCopyAssign(*this, Loc, BaseType,
To.get(), From,
/*CopyingBaseSubobject=*/true,
/*Copying=*/false);
@@ -8446,11 +9041,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
Statements.push_back(Move.takeAs<Expr>());
}
- // \brief Reference to the __builtin_memcpy function.
- Expr *BuiltinMemCpyRef = 0;
- // \brief Reference to the __builtin_objc_memmove_collectable function.
- Expr *CollectableMemCpyRef = 0;
-
// Assign non-static members.
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
FieldEnd = ClassDecl->field_end();
@@ -8513,104 +9103,8 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
"Member reference with rvalue base must be rvalue except for reference "
"members, which aren't allowed for move assignment.");
- // If the field should be copied with __builtin_memcpy rather than via
- // explicit assignments, do so. This optimization only applies for arrays
- // of scalars and arrays of class type with trivial move-assignment
- // operators.
- if (FieldType->isArrayType() && !FieldType.isVolatileQualified()
- && BaseType.hasTrivialAssignment(Context, /*Copying=*/false)) {
- // Compute the size of the memory buffer to be copied.
- QualType SizeType = Context.getSizeType();
- llvm::APInt Size(Context.getTypeSize(SizeType),
- Context.getTypeSizeInChars(BaseType).getQuantity());
- for (const ConstantArrayType *Array
- = Context.getAsConstantArrayType(FieldType);
- Array;
- Array = Context.getAsConstantArrayType(Array->getElementType())) {
- llvm::APInt ArraySize
- = Array->getSize().zextOrTrunc(Size.getBitWidth());
- Size *= ArraySize;
- }
-
- // Take the address of the field references for "from" and "to". We
- // directly construct UnaryOperators here because semantic analysis
- // does not permit us to take the address of an xvalue.
- From = new (Context) UnaryOperator(From.get(), UO_AddrOf,
- Context.getPointerType(From.get()->getType()),
- VK_RValue, OK_Ordinary, Loc);
- To = new (Context) UnaryOperator(To.get(), UO_AddrOf,
- Context.getPointerType(To.get()->getType()),
- VK_RValue, OK_Ordinary, Loc);
-
- bool NeedsCollectableMemCpy =
- (BaseType->isRecordType() &&
- BaseType->getAs<RecordType>()->getDecl()->hasObjectMember());
-
- if (NeedsCollectableMemCpy) {
- if (!CollectableMemCpyRef) {
- // Create a reference to the __builtin_objc_memmove_collectable function.
- LookupResult R(*this,
- &Context.Idents.get("__builtin_objc_memmove_collectable"),
- Loc, LookupOrdinaryName);
- LookupName(R, TUScope, true);
-
- FunctionDecl *CollectableMemCpy = R.getAsSingle<FunctionDecl>();
- if (!CollectableMemCpy) {
- // Something went horribly wrong earlier, and we will have
- // complained about it.
- Invalid = true;
- continue;
- }
-
- CollectableMemCpyRef = BuildDeclRefExpr(CollectableMemCpy,
- Context.BuiltinFnTy,
- VK_RValue, Loc, 0).take();
- assert(CollectableMemCpyRef && "Builtin reference cannot fail");
- }
- }
- // Create a reference to the __builtin_memcpy builtin function.
- else if (!BuiltinMemCpyRef) {
- LookupResult R(*this, &Context.Idents.get("__builtin_memcpy"), Loc,
- LookupOrdinaryName);
- LookupName(R, TUScope, true);
-
- FunctionDecl *BuiltinMemCpy = R.getAsSingle<FunctionDecl>();
- if (!BuiltinMemCpy) {
- // Something went horribly wrong earlier, and we will have complained
- // about it.
- Invalid = true;
- continue;
- }
-
- BuiltinMemCpyRef = BuildDeclRefExpr(BuiltinMemCpy,
- Context.BuiltinFnTy,
- VK_RValue, Loc, 0).take();
- assert(BuiltinMemCpyRef && "Builtin reference cannot fail");
- }
-
- SmallVector<Expr*, 8> CallArgs;
- CallArgs.push_back(To.takeAs<Expr>());
- CallArgs.push_back(From.takeAs<Expr>());
- CallArgs.push_back(IntegerLiteral::Create(Context, Size, SizeType, Loc));
- ExprResult Call = ExprError();
- if (NeedsCollectableMemCpy)
- Call = ActOnCallExpr(/*Scope=*/0,
- CollectableMemCpyRef,
- Loc, CallArgs,
- Loc);
- else
- Call = ActOnCallExpr(/*Scope=*/0,
- BuiltinMemCpyRef,
- Loc, CallArgs,
- Loc);
-
- assert(!Call.isInvalid() && "Call to __builtin_memcpy cannot fail!");
- Statements.push_back(Call.takeAs<Expr>());
- continue;
- }
-
// Build the move of this field.
- StmtResult Move = BuildSingleCopyAssign(*this, Loc, FieldType,
+ StmtResult Move = buildSingleCopyAssign(*this, Loc, FieldType,
To.get(), From.get(),
/*CopyingBaseSubobject=*/false,
/*Copying=*/false);
@@ -8620,7 +9114,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
MoveAssignOperator->setInvalidDecl();
return;
}
-
+
// Success! Record the copy.
Statements.push_back(Move.takeAs<Stmt>());
}
@@ -8662,70 +9156,6 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation,
}
}
-/// Determine whether an implicit copy constructor for ClassDecl has a const
-/// argument.
-/// FIXME: It ought to be possible to store this on the record.
-static bool isImplicitCopyCtorArgConst(Sema &S, CXXRecordDecl *ClassDecl) {
- if (ClassDecl->isInvalidDecl())
- return true;
-
- // C++ [class.copy]p5:
- // The implicitly-declared copy constructor for a class X will
- // have the form
- //
- // X::X(const X&)
- //
- // if
- // -- each direct or virtual base class B of X has a copy
- // constructor whose first parameter is of type const B& or
- // const volatile B&, and
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
- BaseEnd = ClassDecl->bases_end();
- Base != BaseEnd; ++Base) {
- // Virtual bases are handled below.
- if (Base->isVirtual())
- continue;
-
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- // FIXME: This lookup is wrong. If the copy ctor for a member or base is
- // ambiguous, we should still produce a constructor with a const-qualified
- // parameter.
- if (!S.LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const))
- return false;
- }
-
- for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(),
- BaseEnd = ClassDecl->vbases_end();
- Base != BaseEnd; ++Base) {
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- if (!S.LookupCopyingConstructor(BaseClassDecl, Qualifiers::Const))
- return false;
- }
-
- // -- for all the nonstatic data members of X that are of a
- // class type M (or array thereof), each such class type
- // has a copy constructor whose first parameter is of type
- // const M& or const volatile M&.
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd; ++Field) {
- QualType FieldType = S.Context.getBaseElementType(Field->getType());
- if (CXXRecordDecl *FieldClassDecl = FieldType->getAsCXXRecordDecl()) {
- if (!S.LookupCopyingConstructor(FieldClassDecl, Qualifiers::Const))
- return false;
- }
- }
-
- // Otherwise, the implicitly declared copy constructor will have
- // the form
- //
- // X::X(X&)
-
- return true;
-}
-
Sema::ImplicitExceptionSpecification
Sema::ComputeDefaultedCopyCtorExceptionSpec(CXXMethodDecl *MD) {
CXXRecordDecl *ClassDecl = MD->getParent();
@@ -8786,10 +9216,15 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
// C++ [class.copy]p4:
// If the class definition does not explicitly declare a copy
// constructor, one is declared implicitly.
+ assert(ClassDecl->needsImplicitCopyConstructor());
+
+ DeclaringSpecialMember DSM(*this, ClassDecl, CXXCopyConstructor);
+ if (DSM.isAlreadyBeingDeclared())
+ return 0;
QualType ClassType = Context.getTypeDeclType(ClassDecl);
QualType ArgType = ClassType;
- bool Const = isImplicitCopyCtorArgConst(*this, ClassDecl);
+ bool Const = ClassDecl->implicitCopyConstructorHasConstParam();
if (Const)
ArgType = ArgType.withConst();
ArgType = Context.getLValueReferenceType(ArgType);
@@ -8812,30 +9247,26 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
Constexpr);
CopyConstructor->setAccess(AS_public);
CopyConstructor->setDefaulted();
- CopyConstructor->setTrivial(ClassDecl->hasTrivialCopyConstructor());
// Build an exception specification pointing back at this member.
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = CopyConstructor;
CopyConstructor->setType(
- Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI));
+ Context.getFunctionType(Context.VoidTy, ArgType, EPI));
- // Note that we have declared this constructor.
- ++ASTContext::NumImplicitCopyConstructorsDeclared;
-
// Add the parameter to the constructor.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyConstructor,
ClassLoc, ClassLoc,
/*IdentifierInfo=*/0,
ArgType, /*TInfo=*/0,
- SC_None,
SC_None, 0);
CopyConstructor->setParams(FromParam);
- if (Scope *S = getScopeForContext(ClassDecl))
- PushOnScopeChains(CopyConstructor, S, false);
- ClassDecl->addDecl(CopyConstructor);
+ CopyConstructor->setTrivial(
+ ClassDecl->needsOverloadResolutionForCopyConstructor()
+ ? SpecialMemberIsTrivial(CopyConstructor, CXXCopyConstructor)
+ : ClassDecl->hasTrivialCopyConstructor());
// C++11 [class.copy]p8:
// ... If the class definition does not explicitly declare a copy
@@ -8843,7 +9274,14 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
// user-declared move assignment operator, a copy constructor is implicitly
// declared as defaulted.
if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor))
- CopyConstructor->setDeletedAsWritten();
+ SetDeclDeleted(CopyConstructor, ClassLoc);
+
+ // Note that we have declared this constructor.
+ ++ASTContext::NumImplicitCopyConstructorsDeclared;
+
+ if (Scope *S = getScopeForContext(ClassDecl))
+ PushOnScopeChains(CopyConstructor, S, false);
+ ClassDecl->addDecl(CopyConstructor);
return CopyConstructor;
}
@@ -8862,7 +9300,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
SynthesizedFunctionScope Scope(*this, CopyConstructor);
DiagnosticErrorTrap Trap(Diags);
- if (SetCtorInitializers(CopyConstructor, 0, 0, /*AnyErrors=*/false) ||
+ if (SetCtorInitializers(CopyConstructor, /*AnyErrors=*/false) ||
Trap.hasErrorOccurred()) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
<< CXXCopyConstructor << Context.getTagDeclType(ClassDecl);
@@ -8957,6 +9395,10 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
// - [first 4 bullets]
assert(ClassDecl->needsImplicitMoveConstructor());
+ DeclaringSpecialMember DSM(*this, ClassDecl, CXXMoveConstructor);
+ if (DSM.isAlreadyBeingDeclared())
+ return 0;
+
// [Checked after we build the declaration]
// - the move assignment operator would not be implicitly defined as
// deleted,
@@ -8991,24 +9433,27 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
Constexpr);
MoveConstructor->setAccess(AS_public);
MoveConstructor->setDefaulted();
- MoveConstructor->setTrivial(ClassDecl->hasTrivialMoveConstructor());
// Build an exception specification pointing back at this member.
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = MoveConstructor;
MoveConstructor->setType(
- Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI));
+ Context.getFunctionType(Context.VoidTy, ArgType, EPI));
// Add the parameter to the constructor.
ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveConstructor,
ClassLoc, ClassLoc,
/*IdentifierInfo=*/0,
ArgType, /*TInfo=*/0,
- SC_None,
SC_None, 0);
MoveConstructor->setParams(FromParam);
+ MoveConstructor->setTrivial(
+ ClassDecl->needsOverloadResolutionForMoveConstructor()
+ ? SpecialMemberIsTrivial(MoveConstructor, CXXMoveConstructor)
+ : ClassDecl->hasTrivialMoveConstructor());
+
// C++0x [class.copy]p9:
// If the definition of a class X does not explicitly declare a move
// constructor, one will be implicitly declared as defaulted if and only if:
@@ -9045,7 +9490,7 @@ void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation,
SynthesizedFunctionScope Scope(*this, MoveConstructor);
DiagnosticErrorTrap Trap(Diags);
- if (SetCtorInitializers(MoveConstructor, 0, 0, /*AnyErrors=*/false) ||
+ if (SetCtorInitializers(MoveConstructor, /*AnyErrors=*/false) ||
Trap.hasErrorOccurred()) {
Diag(CurrentLocation, diag::note_member_synthesized_at)
<< CXXMoveConstructor << Context.getTagDeclType(ClassDecl);
@@ -9077,8 +9522,8 @@ bool Sema::isImplicitlyDeleted(FunctionDecl *FD) {
static void markLambdaCallOperatorUsed(Sema &S, CXXRecordDecl *Lambda) {
CXXMethodDecl *CallOperator
= cast<CXXMethodDecl>(
- *Lambda->lookup(
- S.Context.DeclarationNames.getCXXOperatorName(OO_Call)).first);
+ Lambda->lookup(
+ S.Context.DeclarationNames.getCXXOperatorName(OO_Call)).front());
CallOperator->setReferenced();
CallOperator->setUsed();
}
@@ -9100,12 +9545,12 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion(
// Return the address of the __invoke function.
DeclarationName InvokeName = &Context.Idents.get("__invoke");
CXXMethodDecl *Invoke
- = cast<CXXMethodDecl>(*Lambda->lookup(InvokeName).first);
+ = cast<CXXMethodDecl>(Lambda->lookup(InvokeName).front());
Expr *FunctionRef = BuildDeclRefExpr(Invoke, Invoke->getType(),
VK_LValue, Conv->getLocation()).take();
assert(FunctionRef && "Can't refer to __invoke function?");
Stmt *Return = ActOnReturnStmt(Conv->getLocation(), FunctionRef).take();
- Conv->setBody(new (Context) CompoundStmt(Context, &Return, 1,
+ Conv->setBody(new (Context) CompoundStmt(Context, Return,
Conv->getLocation(),
Conv->getLocation()));
@@ -9164,7 +9609,7 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion(
// Set the body of the conversion function.
Stmt *ReturnS = Return.take();
- Conv->setBody(new (Context) CompoundStmt(Context, &ReturnS, 1,
+ Conv->setBody(new (Context) CompoundStmt(Context, ReturnS,
Conv->getLocation(),
Conv->getLocation()));
@@ -9198,6 +9643,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CXXConstructorDecl *Constructor,
MultiExprArg ExprArgs,
bool HadMultipleCandidates,
+ bool IsListInitialization,
bool RequiresZeroInit,
unsigned ConstructKind,
SourceRange ParenRange) {
@@ -9221,7 +9667,8 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor,
Elidable, ExprArgs, HadMultipleCandidates,
- RequiresZeroInit, ConstructKind, ParenRange);
+ IsListInitialization, RequiresZeroInit,
+ ConstructKind, ParenRange);
}
/// BuildCXXConstructExpr - Creates a complete call to a constructor,
@@ -9231,39 +9678,19 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CXXConstructorDecl *Constructor, bool Elidable,
MultiExprArg ExprArgs,
bool HadMultipleCandidates,
+ bool IsListInitialization,
bool RequiresZeroInit,
unsigned ConstructKind,
SourceRange ParenRange) {
MarkFunctionReferenced(ConstructLoc, Constructor);
return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc,
Constructor, Elidable, ExprArgs,
- HadMultipleCandidates, /*FIXME*/false,
- RequiresZeroInit,
+ HadMultipleCandidates,
+ IsListInitialization, RequiresZeroInit,
static_cast<CXXConstructExpr::ConstructionKind>(ConstructKind),
ParenRange));
}
-bool Sema::InitializeVarWithConstructor(VarDecl *VD,
- CXXConstructorDecl *Constructor,
- MultiExprArg Exprs,
- bool HadMultipleCandidates) {
- // FIXME: Provide the correct paren SourceRange when available.
- ExprResult TempResult =
- BuildCXXConstructExpr(VD->getLocation(), VD->getType(), Constructor,
- Exprs, HadMultipleCandidates, false,
- CXXConstructExpr::CK_Complete, SourceRange());
- if (TempResult.isInvalid())
- return true;
-
- Expr *Temp = TempResult.takeAs<Expr>();
- CheckImplicitConversions(Temp, VD->getLocation());
- MarkFunctionReferenced(VD->getLocation(), Constructor);
- Temp = MaybeCreateExprWithCleanups(Temp);
- VD->setInit(Temp);
-
- return false;
-}
-
void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
if (VD->isInvalidDecl()) return;
@@ -9301,7 +9728,8 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
MultiExprArg ArgsPtr,
SourceLocation Loc,
SmallVectorImpl<Expr*> &ConvertedArgs,
- bool AllowExplicit) {
+ bool AllowExplicit,
+ bool IsListInitialization) {
// FIXME: This duplicates a lot of code from Sema::ConvertArgumentsForCall.
unsigned NumArgs = ArgsPtr.size();
Expr **Args = ArgsPtr.data();
@@ -9322,12 +9750,15 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor,
SmallVector<Expr *, 8> AllArgs;
bool Invalid = GatherArgumentsForCall(Loc, Constructor,
Proto, 0, Args, NumArgs, AllArgs,
- CallType, AllowExplicit);
+ CallType, AllowExplicit,
+ IsListInitialization);
ConvertedArgs.append(AllArgs.begin(), AllArgs.end());
DiagnoseSentinelCalls(Constructor, Loc, AllArgs.data(), AllArgs.size());
- CheckConstructorCall(Constructor, AllArgs.data(), AllArgs.size(),
+ CheckConstructorCall(Constructor,
+ llvm::makeArrayRef<const Expr *>(AllArgs.data(),
+ AllArgs.size()),
Proto, Loc);
return Invalid;
@@ -9766,6 +10197,19 @@ Decl *Sema::ActOnFinishLinkageSpecification(Scope *S,
return LinkageSpec;
}
+Decl *Sema::ActOnEmptyDeclaration(Scope *S,
+ AttributeList *AttrList,
+ SourceLocation SemiLoc) {
+ Decl *ED = EmptyDecl::Create(Context, CurContext, SemiLoc);
+ // Attribute declarations appertain to empty declaration so we handle
+ // them here.
+ if (AttrList)
+ ProcessDeclAttributeList(S, ED, AttrList);
+
+ CurContext->addDecl(ED);
+ return ED;
+}
+
/// \brief Perform semantic analysis for the variable declaration that
/// occurs within a C++ catch clause, returning the newly-created
/// variable.
@@ -9833,7 +10277,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
}
VarDecl *ExDecl = VarDecl::Create(Context, CurContext, StartLoc, Loc, Name,
- ExDeclType, TInfo, SC_None, SC_None);
+ ExDeclType, TInfo, SC_None);
ExDecl->setExceptionVariable(true);
// In ARC, infer 'retaining' for variables of retainable type.
@@ -9842,6 +10286,9 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
if (!Invalid && !ExDeclType->isDependentType()) {
if (const RecordType *recordType = ExDeclType->getAs<RecordType>()) {
+ // Insulate this from anything else we might currently be parsing.
+ EnterExpressionEvaluationContext scope(*this, PotentiallyEvaluated);
+
// C++ [except.handle]p16:
// The object declared in an exception-declaration or, if the
// exception-declaration does not specify a name, a temporary (12.2) is
@@ -9893,8 +10340,8 @@ Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) {
bool Invalid = D.isInvalidType();
// Check for unexpanded parameter packs.
- if (TInfo && DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo,
- UPPC_ExceptionType)) {
+ if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo,
+ UPPC_ExceptionType)) {
TInfo = Context.getTrivialTypeSourceInfo(Context.IntTy,
D.getIdentifierLoc());
Invalid = true;
@@ -9970,7 +10417,7 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
Failed = true;
if (!Failed && !Cond) {
- llvm::SmallString<256> MsgBuffer;
+ SmallString<256> MsgBuffer;
llvm::raw_svector_ostream Msg(MsgBuffer);
AssertMessage->printPretty(Msg, 0, getPrintingPolicy());
Diag(StaticAssertLoc, diag::err_static_assert_failed)
@@ -10007,47 +10454,49 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart,
// Do not complain about the form of friend template types during
// template instantiation; we will already have complained when the
// template was declared.
- } else if (!T->isElaboratedTypeSpecifier()) {
- // If we evaluated the type to a record type, suggest putting
- // a tag in front.
- if (const RecordType *RT = T->getAs<RecordType>()) {
- RecordDecl *RD = RT->getDecl();
+ } else {
+ if (!T->isElaboratedTypeSpecifier()) {
+ // If we evaluated the type to a record type, suggest putting
+ // a tag in front.
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ RecordDecl *RD = RT->getDecl();
- std::string InsertionText = std::string(" ") + RD->getKindName();
+ std::string InsertionText = std::string(" ") + RD->getKindName();
- Diag(TypeRange.getBegin(),
- getLangOpts().CPlusPlus0x ?
- diag::warn_cxx98_compat_unelaborated_friend_type :
- diag::ext_unelaborated_friend_type)
- << (unsigned) RD->getTagKind()
- << T
- << FixItHint::CreateInsertion(PP.getLocForEndOfToken(FriendLoc),
- InsertionText);
- } else {
+ Diag(TypeRange.getBegin(),
+ getLangOpts().CPlusPlus11 ?
+ diag::warn_cxx98_compat_unelaborated_friend_type :
+ diag::ext_unelaborated_friend_type)
+ << (unsigned) RD->getTagKind()
+ << T
+ << FixItHint::CreateInsertion(PP.getLocForEndOfToken(FriendLoc),
+ InsertionText);
+ } else {
+ Diag(FriendLoc,
+ getLangOpts().CPlusPlus11 ?
+ diag::warn_cxx98_compat_nonclass_type_friend :
+ diag::ext_nonclass_type_friend)
+ << T
+ << TypeRange;
+ }
+ } else if (T->getAs<EnumType>()) {
Diag(FriendLoc,
- getLangOpts().CPlusPlus0x ?
- diag::warn_cxx98_compat_nonclass_type_friend :
- diag::ext_nonclass_type_friend)
+ getLangOpts().CPlusPlus11 ?
+ diag::warn_cxx98_compat_enum_friend :
+ diag::ext_enum_friend)
<< T
<< TypeRange;
}
- } else if (T->getAs<EnumType>()) {
- Diag(FriendLoc,
- getLangOpts().CPlusPlus0x ?
- diag::warn_cxx98_compat_enum_friend :
- diag::ext_enum_friend)
- << T
- << TypeRange;
- }
- // 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;
+ // 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().CPlusPlus11 && 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,
@@ -10060,7 +10509,8 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart,
Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
unsigned TagSpec, SourceLocation TagLoc,
CXXScopeSpec &SS,
- IdentifierInfo *Name, SourceLocation NameLoc,
+ IdentifierInfo *Name,
+ SourceLocation NameLoc,
AttributeList *Attr,
MultiTemplateParamsArg TempParamLists) {
TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
@@ -10132,19 +10582,20 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
if (isa<DependentNameType>(T)) {
- DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc());
+ DependentNameTypeLoc TL =
+ TSI->getTypeLoc().castAs<DependentNameTypeLoc>();
TL.setElaboratedKeywordLoc(TagLoc);
TL.setQualifierLoc(QualifierLoc);
TL.setNameLoc(NameLoc);
} else {
- ElaboratedTypeLoc TL = cast<ElaboratedTypeLoc>(TSI->getTypeLoc());
+ ElaboratedTypeLoc TL = TSI->getTypeLoc().castAs<ElaboratedTypeLoc>();
TL.setElaboratedKeywordLoc(TagLoc);
TL.setQualifierLoc(QualifierLoc);
- cast<TypeSpecTypeLoc>(TL.getNamedTypeLoc()).setNameLoc(NameLoc);
+ TL.getNamedTypeLoc().castAs<TypeSpecTypeLoc>().setNameLoc(NameLoc);
}
FriendDecl *Friend = FriendDecl::Create(Context, CurContext, NameLoc,
- TSI, FriendLoc);
+ TSI, FriendLoc, TempParamLists);
Friend->setAccess(AS_public);
CurContext->addDecl(Friend);
return Friend;
@@ -10160,13 +10611,13 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,
ElaboratedTypeKeyword ETK = TypeWithKeyword::getKeywordForTagTypeKind(Kind);
QualType T = Context.getDependentNameType(ETK, SS.getScopeRep(), Name);
TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
- DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc());
+ DependentNameTypeLoc TL = TSI->getTypeLoc().castAs<DependentNameTypeLoc>();
TL.setElaboratedKeywordLoc(TagLoc);
TL.setQualifierLoc(SS.getWithLocInContext(Context));
TL.setNameLoc(NameLoc);
FriendDecl *Friend = FriendDecl::Create(Context, CurContext, NameLoc,
- TSI, FriendLoc);
+ TSI, FriendLoc, TempParamLists);
Friend->setAccess(AS_public);
Friend->setUnsupportedFriend(true);
CurContext->addDecl(Friend);
@@ -10260,8 +10711,8 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
return D;
}
-Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
- MultiTemplateParamsArg TemplateParams) {
+NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
+ MultiTemplateParamsArg TemplateParams) {
const DeclSpec &DS = D.getDeclSpec();
assert(DS.isFriendSpecified());
@@ -10372,17 +10823,6 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
DC = DC->getParent();
}
- // C++ [class.friend]p1: A friend of a class is a function or
- // class that is not a member of the class . . .
- // C++11 changes this for both friend types and functions.
- // Most C++ 98 compilers do seem to give an error here, so
- // we do, too.
- if (!Previous.empty() && DC->Equals(CurContext))
- Diag(DS.getFriendSpecLoc(),
- getLangOpts().CPlusPlus0x ?
- diag::warn_cxx98_compat_friend_is_member :
- diag::err_friend_is_member);
-
DCScope = getScopeForDeclContext(S, DC);
// C++ [class.friend]p6:
@@ -10427,7 +10867,7 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
// class that is not a member of the class . . .
if (DC->Equals(CurContext))
Diag(DS.getFriendSpecLoc(),
- getLangOpts().CPlusPlus0x ?
+ getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_friend_is_member :
diag::err_friend_is_member);
@@ -10534,11 +10974,12 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D,
void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
AdjustDeclIfTemplate(Dcl);
- FunctionDecl *Fn = dyn_cast<FunctionDecl>(Dcl);
+ FunctionDecl *Fn = dyn_cast_or_null<FunctionDecl>(Dcl);
if (!Fn) {
Diag(DelLoc, diag::err_deleted_non_function);
return;
}
+
if (const FunctionDecl *Prev = Fn->getPreviousDecl()) {
// Don't consider the implicit declaration we generate for explicit
// specializations. FIXME: Do not generate these implicit declarations.
@@ -10549,41 +10990,34 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
}
// If the declaration wasn't the first, we delete the function anyway for
// recovery.
+ Fn = Fn->getCanonicalDecl();
}
- Fn->setDeletedAsWritten();
- CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Dcl);
- if (!MD)
+ if (Fn->isDeleted())
return;
- // A deleted special member function is trivial if the corresponding
- // implicitly-declared function would have been.
- switch (getSpecialMember(MD)) {
- case CXXInvalid:
- break;
- case CXXDefaultConstructor:
- MD->setTrivial(MD->getParent()->hasTrivialDefaultConstructor());
- break;
- case CXXCopyConstructor:
- MD->setTrivial(MD->getParent()->hasTrivialCopyConstructor());
- break;
- case CXXMoveConstructor:
- MD->setTrivial(MD->getParent()->hasTrivialMoveConstructor());
- break;
- case CXXCopyAssignment:
- MD->setTrivial(MD->getParent()->hasTrivialCopyAssignment());
- break;
- case CXXMoveAssignment:
- MD->setTrivial(MD->getParent()->hasTrivialMoveAssignment());
- break;
- case CXXDestructor:
- MD->setTrivial(MD->getParent()->hasTrivialDestructor());
- break;
+ // See if we're deleting a function which is already known to override a
+ // non-deleted virtual function.
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Fn)) {
+ bool IssuedDiagnostic = false;
+ for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
+ E = MD->end_overridden_methods();
+ I != E; ++I) {
+ if (!(*MD->begin_overridden_methods())->isDeleted()) {
+ if (!IssuedDiagnostic) {
+ Diag(DelLoc, diag::err_deleted_override) << MD->getDeclName();
+ IssuedDiagnostic = true;
+ }
+ Diag((*I)->getLocation(), diag::note_overridden_virtual_function);
+ }
+ }
}
+
+ Fn->setDeletedAsWritten();
}
void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
- CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Dcl);
+ CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(Dcl);
if (MD) {
if (MD->getParent()->isDependentType()) {
@@ -10609,11 +11043,19 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
// on it.
Pattern->isDefined(Primary);
+ // If the method was defaulted on its first declaration, we will have
+ // already performed the checking in CheckCompletedCXXClass. Such a
+ // declaration doesn't trigger an implicit definition.
if (Primary == Primary->getCanonicalDecl())
return;
CheckExplicitlyDefaultedSpecialMember(MD);
+ // The exception specification is needed because we are defining the
+ // function.
+ ResolveExceptionSpec(DefaultLoc,
+ MD->getType()->castAs<FunctionProtoType>());
+
switch (Member) {
case CXXDefaultConstructor: {
CXXConstructorDecl *CD = cast<CXXConstructorDecl>(MD);
@@ -10683,6 +11125,40 @@ void Sema::DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock) {
}
}
+bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
+ const CXXMethodDecl *Old) {
+ const FunctionType *NewFT = New->getType()->getAs<FunctionType>();
+ const FunctionType *OldFT = Old->getType()->getAs<FunctionType>();
+
+ CallingConv NewCC = NewFT->getCallConv(), OldCC = OldFT->getCallConv();
+
+ // If the calling conventions match, everything is fine
+ if (NewCC == OldCC)
+ return false;
+
+ // If either of the calling conventions are set to "default", we need to pick
+ // something more sensible based on the target. This supports code where the
+ // one method explicitly sets thiscall, and another has no explicit calling
+ // convention.
+ CallingConv Default =
+ Context.getTargetInfo().getDefaultCallingConv(TargetInfo::CCMT_Member);
+ if (NewCC == CC_Default)
+ NewCC = Default;
+ if (OldCC == CC_Default)
+ OldCC = Default;
+
+ // If the calling conventions still don't match, then report the error
+ if (NewCC != OldCC) {
+ Diag(New->getLocation(),
+ diag::err_conflicting_overriding_cc_attributes)
+ << New->getDeclName() << New->getType() << Old->getType();
+ Diag(Old->getLocation(), diag::note_overridden_virtual_function);
+ return true;
+ }
+
+ return false;
+}
+
bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
const CXXMethodDecl *Old) {
QualType NewTy = New->getType()->getAs<FunctionType>()->getResultType();
@@ -10949,7 +11425,7 @@ bool Sema::DefineUsedVTables() {
// If this class has a key function, but that key function is
// defined in another translation unit, we don't need to emit the
// vtable even though we're using it.
- const CXXMethodDecl *KeyFunction = Context.getKeyFunction(Class);
+ const CXXMethodDecl *KeyFunction = Context.getCurrentKeyFunction(Class);
if (KeyFunction && !KeyFunction->hasBody()) {
switch (KeyFunction->getTemplateSpecializationKind()) {
case TSK_Undeclared:
@@ -11006,7 +11482,7 @@ bool Sema::DefineUsedVTables() {
Consumer.HandleVTable(Class, VTablesUsed[Canonical]);
// Optionally warn if we're emitting a weak vtable.
- if (Class->getLinkage() == ExternalLinkage &&
+ if (Class->hasExternalLinkage() &&
Class->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) {
const FunctionDecl *KeyFunctionDef = 0;
if (!KeyFunction ||
@@ -11228,7 +11704,7 @@ bool Sema::checkThisInStaticMemberFunctionType(CXXMethodDecl *Method) {
return false;
TypeLoc TL = TSInfo->getTypeLoc();
- FunctionProtoTypeLoc *ProtoTL = dyn_cast<FunctionProtoTypeLoc>(&TL);
+ FunctionProtoTypeLoc ProtoTL = TL.getAs<FunctionProtoTypeLoc>();
if (!ProtoTL)
return false;
@@ -11239,12 +11715,12 @@ bool Sema::checkThisInStaticMemberFunctionType(CXXMethodDecl *Method) {
// within a static member function as they are within a non-static member
// function). [ Note: this is because declaration matching does not occur
// until the complete declarator is known. - end note ]
- const FunctionProtoType *Proto = ProtoTL->getTypePtr();
+ const FunctionProtoType *Proto = ProtoTL.getTypePtr();
FindCXXThisExpr Finder(*this);
// If the return type came after the cv-qualifier-seq, check it now.
if (Proto->hasTrailingReturn() &&
- !Finder.TraverseTypeLoc(ProtoTL->getResultLoc()))
+ !Finder.TraverseTypeLoc(ProtoTL.getResultLoc()))
return true;
// Check the exception specification.
@@ -11260,11 +11736,11 @@ bool Sema::checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method) {
return false;
TypeLoc TL = TSInfo->getTypeLoc();
- FunctionProtoTypeLoc *ProtoTL = dyn_cast<FunctionProtoTypeLoc>(&TL);
+ FunctionProtoTypeLoc ProtoTL = TL.getAs<FunctionProtoTypeLoc>();
if (!ProtoTL)
return false;
- const FunctionProtoType *Proto = ProtoTL->getTypePtr();
+ const FunctionProtoType *Proto = ProtoTL.getTypePtr();
FindCXXThisExpr Finder(*this);
switch (Proto->getExceptionSpecType()) {
@@ -11354,7 +11830,7 @@ Sema::checkExceptionSpecification(ExceptionSpecificationType EST,
ArrayRef<ParsedType> DynamicExceptions,
ArrayRef<SourceRange> DynamicExceptionRanges,
Expr *NoexceptExpr,
- llvm::SmallVectorImpl<QualType> &Exceptions,
+ SmallVectorImpl<QualType> &Exceptions,
FunctionProtoType::ExtProtoInfo &EPI) {
Exceptions.clear();
EPI.ExceptionSpecType = EST;
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index c4e91e8..5c26d7f 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -12,19 +12,19 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/ExternalSemaSource.h"
-#include "clang/Sema/Scope.h"
-#include "clang/Sema/ScopeInfo.h"
#include "clang/AST/ASTConsumer.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/ExprObjC.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclObjC.h"
#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprObjC.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Sema/DeclSpec.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/ExternalSemaSource.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/ScopeInfo.h"
#include "llvm/ADT/DenseSet.h"
using namespace clang;
@@ -109,8 +109,7 @@ bool Sema::checkInitMethod(ObjCMethodDecl *method,
}
void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
- const ObjCMethodDecl *Overridden,
- bool IsImplementation) {
+ const ObjCMethodDecl *Overridden) {
if (Overridden->hasRelatedResultType() &&
!NewMethod->hasRelatedResultType()) {
// This can only happen when the method follows a naming convention that
@@ -152,7 +151,8 @@ void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
if (ObjCMethodFamily Family = Overridden->getMethodFamily())
Diag(Overridden->getLocation(),
- diag::note_related_result_type_overridden_family)
+ diag::note_related_result_type_family)
+ << /*overridden method*/ 0
<< Family;
else
Diag(Overridden->getLocation(),
@@ -193,7 +193,7 @@ void Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
/// \brief Check a method declaration for compatibility with the Objective-C
/// ARC conventions.
-static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) {
+bool Sema::CheckARCMethodDecl(ObjCMethodDecl *method) {
ObjCMethodFamily family = method->getMethodFamily();
switch (family) {
case OMF_None:
@@ -207,17 +207,17 @@ static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) {
return false;
case OMF_dealloc:
- if (!S.Context.hasSameType(method->getResultType(), S.Context.VoidTy)) {
+ if (!Context.hasSameType(method->getResultType(), Context.VoidTy)) {
SourceRange ResultTypeRange;
if (const TypeSourceInfo *ResultTypeInfo
= method->getResultTypeSourceInfo())
ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange();
if (ResultTypeRange.isInvalid())
- S.Diag(method->getLocation(), diag::error_dealloc_bad_result_type)
+ Diag(method->getLocation(), diag::error_dealloc_bad_result_type)
<< method->getResultType()
<< FixItHint::CreateInsertion(method->getSelectorLoc(0), "(void)");
else
- S.Diag(method->getLocation(), diag::error_dealloc_bad_result_type)
+ Diag(method->getLocation(), diag::error_dealloc_bad_result_type)
<< method->getResultType()
<< FixItHint::CreateReplacement(ResultTypeRange, "void");
return true;
@@ -226,11 +226,11 @@ static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) {
case OMF_init:
// If the method doesn't obey the init rules, don't bother annotating it.
- if (S.checkInitMethod(method, QualType()))
+ if (checkInitMethod(method, QualType()))
return true;
- method->addAttr(new (S.Context) NSConsumesSelfAttr(SourceLocation(),
- S.Context));
+ method->addAttr(new (Context) NSConsumesSelfAttr(SourceLocation(),
+ Context));
// Don't add a second copy of this attribute, but otherwise don't
// let it be suppressed.
@@ -249,8 +249,8 @@ static bool CheckARCMethodDecl(Sema &S, ObjCMethodDecl *method) {
break;
}
- method->addAttr(new (S.Context) NSReturnsRetainedAttr(SourceLocation(),
- S.Context));
+ method->addAttr(new (Context) NSReturnsRetainedAttr(SourceLocation(),
+ Context));
return false;
}
@@ -373,16 +373,29 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
ObjCMethodDecl *IMD =
IC->lookupMethod(MDecl->getSelector(), MDecl->isInstanceMethod());
- if (IMD)
- DiagnoseObjCImplementedDeprecations(*this,
+ if (IMD) {
+ ObjCImplDecl *ImplDeclOfMethodDef =
+ dyn_cast<ObjCImplDecl>(MDecl->getDeclContext());
+ ObjCContainerDecl *ContDeclOfMethodDecl =
+ dyn_cast<ObjCContainerDecl>(IMD->getDeclContext());
+ ObjCImplDecl *ImplDeclOfMethodDecl = 0;
+ if (ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(ContDeclOfMethodDecl))
+ ImplDeclOfMethodDecl = OID->getImplementation();
+ else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContDeclOfMethodDecl))
+ ImplDeclOfMethodDecl = CD->getImplementation();
+ // No need to issue deprecated warning if deprecated mehod in class/category
+ // is being implemented in its own implementation (no overriding is involved).
+ if (!ImplDeclOfMethodDecl || ImplDeclOfMethodDecl != ImplDeclOfMethodDef)
+ DiagnoseObjCImplementedDeprecations(*this,
dyn_cast<NamedDecl>(IMD),
MDecl->getLocation(), 0);
+ }
// If this is "dealloc" or "finalize", set some bit here.
// Then in ActOnSuperMessage() (SemaExprObjC), set it back to false.
// Finally, in ActOnFinishFunctionBody() (SemaDecl), warn if flag is set.
// Only do this if the current class actually has a superclass.
- if (IC->getSuperClass()) {
+ if (const ObjCInterfaceDecl *SuperClass = IC->getSuperClass()) {
ObjCMethodFamily Family = MDecl->getMethodFamily();
if (Family == OMF_dealloc) {
if (!(getLangOpts().ObjCAutoRefCount ||
@@ -395,8 +408,8 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
} else {
const ObjCMethodDecl *SuperMethod =
- IC->getSuperClass()->lookupMethod(MDecl->getSelector(),
- MDecl->isInstanceMethod());
+ SuperClass->lookupMethod(MDecl->getSelector(),
+ MDecl->isInstanceMethod());
getCurFunction()->ObjCShouldCallSuper =
(SuperMethod && SuperMethod->hasAttr<ObjCRequiresSuperAttr>());
}
@@ -508,8 +521,14 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) {
QualType T = TDecl->getUnderlyingType();
if (T->isObjCObjectType()) {
- if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface())
+ if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) {
SuperClassDecl = dyn_cast<ObjCInterfaceDecl>(IDecl);
+ // This handles the following case:
+ // @interface NewI @end
+ // typedef NewI DeprI __attribute__((deprecated("blah")))
+ // @interface SI : DeprI /* warn here */ @end
+ (void)DiagnoseUseOfDecl(const_cast<TypedefNameDecl*>(TDecl), SuperLoc);
+ }
}
}
@@ -731,7 +750,9 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
// If this is a forward declaration and we are supposed to warn in this
// case, do it.
- if (WarnOnDeclarations && !PDecl->hasDefinition())
+ // FIXME: Recover nicely in the hidden case.
+ if (WarnOnDeclarations &&
+ (!PDecl->hasDefinition() || PDecl->getDefinition()->isHidden()))
Diag(ProtocolId[i].second, diag::warn_undef_protocolref)
<< ProtocolId[i].first;
Protocols.push_back(PDecl);
@@ -837,16 +858,12 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
if (CategoryName) {
/// Check for duplicate interface declaration for this category
- ObjCCategoryDecl *CDeclChain;
- for (CDeclChain = IDecl->getCategoryList(); CDeclChain;
- CDeclChain = CDeclChain->getNextClassCategory()) {
- if (CDeclChain->getIdentifier() == CategoryName) {
- // Class extensions can be declared multiple times.
- Diag(CategoryLoc, diag::warn_dup_category_def)
- << ClassName << CategoryName;
- Diag(CDeclChain->getLocation(), diag::note_previous_definition);
- break;
- }
+ if (ObjCCategoryDecl *Previous
+ = IDecl->FindCategoryDeclaration(CategoryName)) {
+ // Class extensions can be declared multiple times, categories cannot.
+ Diag(CategoryLoc, diag::warn_dup_category_def)
+ << ClassName << CategoryName;
+ Diag(Previous->getLocation(), diag::note_previous_definition);
}
}
@@ -1155,16 +1172,29 @@ void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl,
void Sema::WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method,
bool &IncompleteImpl, unsigned DiagID) {
// No point warning no definition of method which is 'unavailable'.
- if (method->hasAttr<UnavailableAttr>())
+ switch (method->getAvailability()) {
+ case AR_Available:
+ case AR_Deprecated:
+ break;
+
+ // Don't warn about unavailable or not-yet-introduced methods.
+ case AR_NotYetIntroduced:
+ case AR_Unavailable:
return;
- if (!IncompleteImpl) {
- Diag(ImpLoc, diag::warn_incomplete_impl);
- IncompleteImpl = true;
}
- if (DiagID == diag::warn_unimplemented_protocol_method)
- Diag(ImpLoc, DiagID) << method->getDeclName();
- else
- Diag(method->getLocation(), DiagID) << method->getDeclName();
+
+ // FIXME: For now ignore 'IncompleteImpl'.
+ // Previously we grouped all unimplemented methods under a single
+ // warning, but some users strongly voiced that they would prefer
+ // separate warnings. We will give that approach a try, as that
+ // matches what we do with protocols.
+
+ Diag(ImpLoc, DiagID) << method->getDeclName();
+
+ // Issue a note to the original declaration.
+ SourceLocation MethodLoc = method->getLocStart();
+ if (MethodLoc.isValid())
+ Diag(MethodLoc, diag::note_method_declared_at) << method;
}
/// Determines if type B can be substituted for type A. Returns true if we can
@@ -1571,6 +1601,11 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
NSIDecl = IDecl->lookupInheritedClass(&Context.Idents.get("NSProxy"));
}
+ // If this is a forward protocol declaration, get its definition.
+ if (!PDecl->isThisDeclarationADefinition() &&
+ PDecl->getDefinition())
+ PDecl = PDecl->getDefinition();
+
// If a method lookup fails locally we still need to look and see if
// the method was implemented by a base class or an inherited
// protocol. This lookup is slow, but occurs rarely in correct code
@@ -1603,8 +1638,6 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
if (Diags.getDiagnosticLevel(DIAG, ImpLoc)
!= DiagnosticsEngine::Ignored) {
WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG);
- Diag(method->getLocation(), diag::note_method_declared_at)
- << method->getDeclName();
Diag(CDecl->getLocation(), diag::note_required_for_protocol_at)
<< PDecl->getDeclName();
}
@@ -1626,8 +1659,6 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc,
if (Diags.getDiagnosticLevel(DIAG, ImpLoc) !=
DiagnosticsEngine::Ignored) {
WarnUndefinedMethod(ImpLoc, method, IncompleteImpl, DIAG);
- Diag(method->getLocation(), diag::note_method_declared_at)
- << method->getDeclName();
Diag(IDecl->getLocation(), diag::note_required_for_protocol_at) <<
PDecl->getDeclName();
}
@@ -1662,7 +1693,7 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
!InsMap.count((*I)->getSelector())) {
if (ImmediateClass)
WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl,
- diag::note_undef_method_impl);
+ diag::warn_undef_method_impl);
continue;
} else {
ObjCMethodDecl *ImpMethodDecl =
@@ -1692,7 +1723,7 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
if (!ClsMap.count((*I)->getSelector())) {
if (ImmediateClass)
WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl,
- diag::note_undef_method_impl);
+ diag::warn_undef_method_impl);
} else {
ObjCMethodDecl *ImpMethodDecl =
IMPDecl->getClassMethod((*I)->getSelector());
@@ -1712,24 +1743,27 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
// 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())
+ if (!WarnCategoryMethodImpl) {
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = I->visible_categories_begin(),
+ CatEnd = I->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
- IMPDecl,
- const_cast<ObjCCategoryDecl *>(CDeclChain),
- IncompleteImpl, false,
+ IMPDecl, *Cat, IncompleteImpl, false,
WarnCategoryMethodImpl);
- else
+ }
+ } else {
// Also methods in class extensions need be looked at next.
- for (const ObjCCategoryDecl *ClsExtDecl = I->getFirstClassExtension();
- ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension())
+ for (ObjCInterfaceDecl::visible_extensions_iterator
+ Ext = I->visible_extensions_begin(),
+ ExtEnd = I->visible_extensions_end();
+ Ext != ExtEnd; ++Ext) {
MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen,
- IMPDecl,
- const_cast<ObjCCategoryDecl *>(ClsExtDecl),
- IncompleteImpl, false,
+ IMPDecl, *Ext, IncompleteImpl, false,
WarnCategoryMethodImpl);
-
+ }
+ }
+
// Check for any implementation of a methods declared in protocol.
for (ObjCInterfaceDecl::all_protocol_iterator
PI = I->all_referenced_protocol_begin(),
@@ -1832,11 +1866,12 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl,
CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl,
InsMap, ClsMap, I);
// Check class extensions (unnamed categories)
- for (const ObjCCategoryDecl *Categories = I->getFirstClassExtension();
- Categories; Categories = Categories->getNextClassExtension())
- ImplMethodsVsClassMethods(S, IMPDecl,
- const_cast<ObjCCategoryDecl*>(Categories),
- IncompleteImpl);
+ for (ObjCInterfaceDecl::visible_extensions_iterator
+ Ext = I->visible_extensions_begin(),
+ ExtEnd = I->visible_extensions_end();
+ Ext != ExtEnd; ++Ext) {
+ ImplMethodsVsClassMethods(S, IMPDecl, *Ext, IncompleteImpl);
+ }
} else if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) {
// For extended class, unimplemented methods in its protocols will
// be reported in the primary class.
@@ -2017,6 +2052,10 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left,
left->getResultType(), right->getResultType()))
return false;
+ // If either is hidden, it is not considered to match.
+ if (left->isHidden() || right->isHidden())
+ return false;
+
if (getLangOpts().ObjCAutoRefCount &&
(left->hasAttr<NSReturnsRetainedAttr>()
!= right->hasAttr<NSReturnsRetainedAttr>() ||
@@ -2141,61 +2180,79 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R,
if (Pos == MethodPool.end())
return 0;
+ // Gather the non-hidden methods.
ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second;
+ llvm::SmallVector<ObjCMethodDecl *, 4> Methods;
+ for (ObjCMethodList *M = &MethList; M; M = M->Next) {
+ if (M->Method && !M->Method->isHidden()) {
+ // If we're not supposed to warn about mismatches, we're done.
+ if (!warn)
+ return M->Method;
+
+ Methods.push_back(M->Method);
+ }
+ }
- if (warn && MethList.Method && MethList.Next) {
- bool issueDiagnostic = false, issueError = false;
-
- // We support a warning which complains about *any* difference in
- // method signature.
- bool strictSelectorMatch =
- (receiverIdOrClass && warn &&
- (Diags.getDiagnosticLevel(diag::warn_strict_multiple_method_decl,
- R.getBegin()) !=
- DiagnosticsEngine::Ignored));
- if (strictSelectorMatch)
- for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) {
- if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method,
- MMS_strict)) {
- issueDiagnostic = true;
- break;
- }
+ // If there aren't any visible methods, we're done.
+ // FIXME: Recover if there are any known-but-hidden methods?
+ if (Methods.empty())
+ return 0;
+
+ if (Methods.size() == 1)
+ return Methods[0];
+
+ // We found multiple methods, so we may have to complain.
+ bool issueDiagnostic = false, issueError = false;
+
+ // We support a warning which complains about *any* difference in
+ // method signature.
+ bool strictSelectorMatch =
+ (receiverIdOrClass && warn &&
+ (Diags.getDiagnosticLevel(diag::warn_strict_multiple_method_decl,
+ R.getBegin())
+ != DiagnosticsEngine::Ignored));
+ if (strictSelectorMatch) {
+ for (unsigned I = 1, N = Methods.size(); I != N; ++I) {
+ if (!MatchTwoMethodDeclarations(Methods[0], Methods[I], MMS_strict)) {
+ issueDiagnostic = true;
+ break;
}
+ }
+ }
- // If we didn't see any strict differences, we won't see any loose
- // differences. In ARC, however, we also need to check for loose
- // mismatches, because most of them are errors.
- if (!strictSelectorMatch ||
- (issueDiagnostic && getLangOpts().ObjCAutoRefCount))
- for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) {
- // This checks if the methods differ in type mismatch.
- if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method,
- MMS_loose) &&
- !isAcceptableMethodMismatch(MethList.Method, Next->Method)) {
- issueDiagnostic = true;
- if (getLangOpts().ObjCAutoRefCount)
- issueError = true;
- break;
- }
+ // If we didn't see any strict differences, we won't see any loose
+ // differences. In ARC, however, we also need to check for loose
+ // mismatches, because most of them are errors.
+ if (!strictSelectorMatch ||
+ (issueDiagnostic && getLangOpts().ObjCAutoRefCount))
+ for (unsigned I = 1, N = Methods.size(); I != N; ++I) {
+ // This checks if the methods differ in type mismatch.
+ if (!MatchTwoMethodDeclarations(Methods[0], Methods[I], MMS_loose) &&
+ !isAcceptableMethodMismatch(Methods[0], Methods[I])) {
+ issueDiagnostic = true;
+ if (getLangOpts().ObjCAutoRefCount)
+ issueError = true;
+ break;
}
+ }
- if (issueDiagnostic) {
- if (issueError)
- Diag(R.getBegin(), diag::err_arc_multiple_method_decl) << Sel << R;
- else if (strictSelectorMatch)
- Diag(R.getBegin(), diag::warn_strict_multiple_method_decl) << Sel << R;
- else
- Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R;
+ if (issueDiagnostic) {
+ if (issueError)
+ Diag(R.getBegin(), diag::err_arc_multiple_method_decl) << Sel << R;
+ else if (strictSelectorMatch)
+ Diag(R.getBegin(), diag::warn_strict_multiple_method_decl) << Sel << R;
+ else
+ Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R;
- Diag(MethList.Method->getLocStart(),
- issueError ? diag::note_possibility : diag::note_using)
- << MethList.Method->getSourceRange();
- for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next)
- Diag(Next->Method->getLocStart(), diag::note_also_found)
- << Next->Method->getSourceRange();
- }
+ Diag(Methods[0]->getLocStart(),
+ issueError ? diag::note_possibility : diag::note_using)
+ << Methods[0]->getSourceRange();
+ for (unsigned I = 1, N = Methods.size(); I != N; ++I) {
+ Diag(Methods[I]->getLocStart(), diag::note_also_found)
+ << Methods[I]->getSourceRange();
}
- return MethList.Method;
+ }
+ return Methods[0];
}
ObjCMethodDecl *Sema::LookupImplementedMethodInGlobalPool(Selector Sel) {
@@ -2334,18 +2391,13 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
}
}
}
- if (ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) {
- // Compares properties declared in this class to those of its
- // super class.
- ComparePropertiesInBaseAndSuper(I);
- CompareProperties(I, I);
+ if (isa<ObjCInterfaceDecl>(ClassDecl)) {
+ // Nothing to do here.
} else if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
// Categories are used to extend the class by declaring new methods.
// By the same token, they are also used to add new properties. No
// need to compare the added property to those in the class.
- // Compare protocol properties with those in category
- CompareProperties(C, C);
if (C->IsClassExtension()) {
ObjCInterfaceDecl *CCPrimary = C->getClassInterface();
DiagnoseClassExtensionDupMethods(C, CCPrimary);
@@ -2370,11 +2422,12 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
// of the other class extensions. Mark them as synthesized as
// property will be synthesized when property with same name is
// seen in the @implementation.
- for (const ObjCCategoryDecl *ClsExtDecl =
- IDecl->getFirstClassExtension();
- ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) {
- for (ObjCContainerDecl::prop_iterator I = ClsExtDecl->prop_begin(),
- E = ClsExtDecl->prop_end(); I != E; ++I) {
+ for (ObjCInterfaceDecl::visible_extensions_iterator
+ Ext = IDecl->visible_extensions_begin(),
+ ExtEnd = IDecl->visible_extensions_end();
+ Ext != ExtEnd; ++Ext) {
+ for (ObjCContainerDecl::prop_iterator I = Ext->prop_begin(),
+ E = Ext->prop_end(); I != E; ++I) {
ObjCPropertyDecl *Property = *I;
// Skip over properties declared @dynamic
if (const ObjCPropertyImplDecl *PIDecl
@@ -2382,18 +2435,19 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
if (PIDecl->getPropertyImplementation()
== ObjCPropertyImplDecl::Dynamic)
continue;
-
- for (const ObjCCategoryDecl *CExtDecl =
- IDecl->getFirstClassExtension();
- CExtDecl; CExtDecl = CExtDecl->getNextClassExtension()) {
- if (ObjCMethodDecl *GetterMethod =
- CExtDecl->getInstanceMethod(Property->getGetterName()))
+
+ for (ObjCInterfaceDecl::visible_extensions_iterator
+ Ext = IDecl->visible_extensions_begin(),
+ ExtEnd = IDecl->visible_extensions_end();
+ Ext != ExtEnd; ++Ext) {
+ if (ObjCMethodDecl *GetterMethod
+ = Ext->getInstanceMethod(Property->getGetterName()))
GetterMethod->setPropertyAccessor(true);
if (!Property->isReadOnly())
- if (ObjCMethodDecl *SetterMethod =
- CExtDecl->getInstanceMethod(Property->getSetterName()))
+ if (ObjCMethodDecl *SetterMethod
+ = Ext->getInstanceMethod(Property->getSetterName()))
SetterMethod->setPropertyAccessor(true);
- }
+ }
}
}
ImplMethodsVsClassMethods(S, IC, IDecl);
@@ -2442,12 +2496,9 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd,
// Find category interface decl and then check that all methods declared
// in this interface are implemented in the category @implementation.
if (ObjCInterfaceDecl* IDecl = CatImplClass->getClassInterface()) {
- for (ObjCCategoryDecl *Categories = IDecl->getCategoryList();
- Categories; Categories = Categories->getNextClassCategory()) {
- if (Categories->getIdentifier() == CatImplClass->getIdentifier()) {
- ImplMethodsVsClassMethods(S, CatImplClass, Categories);
- break;
- }
+ if (ObjCCategoryDecl *Cat
+ = IDecl->FindCategoryDeclaration(CatImplClass->getIdentifier())) {
+ ImplMethodsVsClassMethods(S, CatImplClass, Cat);
}
}
}
@@ -2682,9 +2733,12 @@ private:
return;
// - categories,
- for (ObjCCategoryDecl *category = iface->getCategoryList();
- category; category = category->getNextClassCategory())
- search(category);
+ for (ObjCInterfaceDecl::known_categories_iterator
+ cat = iface->known_categories_begin(),
+ catEnd = iface->known_categories_end();
+ cat != catEnd; ++cat) {
+ search(*cat);
+ }
// - the super class, and
if (ObjCInterfaceDecl *super = iface->getSuperClass())
@@ -2711,7 +2765,8 @@ private:
void search(ObjCContainerDecl *container) {
// Check for a method in this container which matches this selector.
ObjCMethodDecl *meth = container->getMethod(Method->getSelector(),
- Method->isInstanceMethod());
+ Method->isInstanceMethod(),
+ /*AllowHidden=*/true);
// If we find one, record it and bail out.
if (meth) {
@@ -2858,8 +2913,6 @@ Decl *Sema::ActOnMethodDeclaration(
DI = 0;
} else {
ArgType = GetTypeFromParser(ArgInfo[i].Type, &DI);
- // Perform the default array/function conversions (C99 6.7.5.3p[7,8]).
- ArgType = Context.getAdjustedParameterType(ArgType);
}
LookupResult R(*this, ArgInfo[i].Name, ArgInfo[i].NameLoc,
@@ -2883,7 +2936,7 @@ Decl *Sema::ActOnMethodDeclaration(
ParmVarDecl* Param = CheckParameter(ObjCMethod, StartLoc,
ArgInfo[i].NameLoc, ArgInfo[i].Name,
- ArgType, DI, SC_None, SC_None);
+ ArgType, DI, SC_None);
Param->setObjCMethodScopeInfo(i);
@@ -2985,7 +3038,7 @@ Decl *Sema::ActOnMethodDeclaration(
bool ARCError = false;
if (getLangOpts().ObjCAutoRefCount)
- ARCError = CheckARCMethodDecl(*this, ObjCMethod);
+ ARCError = CheckARCMethodDecl(ObjCMethod);
// Infer the related result type when possible.
if (!ARCError && RTC == Sema::RTC_Compatible &&
@@ -3114,7 +3167,7 @@ VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType T,
}
VarDecl *New = VarDecl::Create(Context, CurContext, StartLoc, IdLoc, Id,
- T, TInfo, SC_None, SC_None);
+ T, TInfo, SC_None);
New->setExceptionVariable(true);
// In ARC, infer 'retaining' for variables of retainable type.
@@ -3142,7 +3195,7 @@ Decl *Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) {
Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
D.getMutableDeclSpec().ClearStorageClassSpecs();
- DiagnoseFunctionSpecifiers(D);
+ DiagnoseFunctionSpecifiers(D.getDeclSpec());
// Check that there are no default arguments inside the type of this
// exception object (C++ only).
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index e1f4888..26c3d35 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -16,9 +16,9 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/TypeLoc.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
@@ -38,43 +38,55 @@ static const FunctionProtoType *GetUnderlyingFunction(QualType T)
/// CheckSpecifiedExceptionType - Check if the given type is valid in an
/// exception specification. Incomplete types, or pointers to incomplete types
/// other than void are not allowed.
-bool Sema::CheckSpecifiedExceptionType(QualType T, const SourceRange &Range) {
-
- // This check (and the similar one below) deals with issue 437, that changes
- // C++ 9.2p2 this way:
- // Within the class member-specification, the class is regarded as complete
- // within function bodies, default arguments, exception-specifications, and
- // constructor ctor-initializers (including such things in nested classes).
- if (T->isRecordType() && T->getAs<RecordType>()->isBeingDefined())
- return false;
-
- // C++ 15.4p2: A type denoted in an exception-specification shall not denote
- // an incomplete type.
- if (RequireCompleteType(Range.getBegin(), T,
- diag::err_incomplete_in_exception_spec,
- /*direct*/0, Range))
- return true;
-
- // C++ 15.4p2: A type denoted in an exception-specification shall not denote
- // an incomplete type a pointer or reference to an incomplete type, other
- // than (cv) void*.
- int kind;
- if (const PointerType* IT = T->getAs<PointerType>()) {
- T = IT->getPointeeType();
- kind = 1;
- } else if (const ReferenceType* IT = T->getAs<ReferenceType>()) {
- T = IT->getPointeeType();
- kind = 2;
- } else
- return false;
+///
+/// \param[in,out] T The exception type. This will be decayed to a pointer type
+/// when the input is an array or a function type.
+bool Sema::CheckSpecifiedExceptionType(QualType &T, const SourceRange &Range) {
+ // C++11 [except.spec]p2:
+ // A type cv T, "array of T", or "function returning T" denoted
+ // in an exception-specification is adjusted to type T, "pointer to T", or
+ // "pointer to function returning T", respectively.
+ //
+ // We also apply this rule in C++98.
+ if (T->isArrayType())
+ T = Context.getArrayDecayedType(T);
+ else if (T->isFunctionType())
+ T = Context.getPointerType(T);
+
+ int Kind = 0;
+ QualType PointeeT = T;
+ if (const PointerType *PT = T->getAs<PointerType>()) {
+ PointeeT = PT->getPointeeType();
+ Kind = 1;
+
+ // cv void* is explicitly permitted, despite being a pointer to an
+ // incomplete type.
+ if (PointeeT->isVoidType())
+ return false;
+ } else if (const ReferenceType *RT = T->getAs<ReferenceType>()) {
+ PointeeT = RT->getPointeeType();
+ Kind = 2;
+
+ if (RT->isRValueReferenceType()) {
+ // C++11 [except.spec]p2:
+ // A type denoted in an exception-specification shall not denote [...]
+ // an rvalue reference type.
+ Diag(Range.getBegin(), diag::err_rref_in_exception_spec)
+ << T << Range;
+ return true;
+ }
+ }
- // Again as before
- if (T->isRecordType() && T->getAs<RecordType>()->isBeingDefined())
- return false;
-
- if (!T->isVoidType() &&
- RequireCompleteType(Range.getBegin(), T,
- diag::err_incomplete_in_exception_spec, kind, Range))
+ // C++11 [except.spec]p2:
+ // A type denoted in an exception-specification shall not denote an
+ // incomplete type other than a class currently being defined [...].
+ // A type denoted in an exception-specification shall not denote a
+ // pointer or reference to an incomplete type, other than (cv) void* or a
+ // pointer or reference to a class currently being defined.
+ if (!(PointeeT->isRecordType() &&
+ PointeeT->getAs<RecordType>()->isBeingDefined()) &&
+ RequireCompleteType(Range.getBegin(), PointeeT,
+ diag::err_incomplete_in_exception_spec, Kind, Range))
return true;
return false;
@@ -112,7 +124,7 @@ Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {
return SourceFPT;
// Compute or instantiate the exception specification now.
- if (FPT->getExceptionSpecType() == EST_Unevaluated)
+ if (SourceFPT->getExceptionSpecType() == EST_Unevaluated)
EvaluateImplicitExceptionSpec(Loc, cast<CXXMethodDecl>(SourceDecl));
else
InstantiateExceptionSpec(Loc, SourceDecl);
@@ -159,7 +171,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
// 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 &&
+ if (getLangOpts().CPlusPlus11 &&
hasImplicitExceptionSpec(Old) != hasImplicitExceptionSpec(New)) {
Diag(New->getLocation(), diag::ext_implicit_exception_spec_mismatch)
<< hasImplicitExceptionSpec(Old);
@@ -191,10 +203,11 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
Old->isExternC()) {
FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo();
EPI.ExceptionSpecType = EST_DynamicNone;
- QualType NewType = Context.getFunctionType(NewProto->getResultType(),
- NewProto->arg_type_begin(),
- NewProto->getNumArgs(),
- EPI);
+ QualType NewType =
+ Context.getFunctionType(NewProto->getResultType(),
+ ArrayRef<QualType>(NewProto->arg_type_begin(),
+ NewProto->getNumArgs()),
+ EPI);
New->setType(NewType);
return false;
}
@@ -215,10 +228,11 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
// Update the type of the function with the appropriate exception
// specification.
- QualType NewType = Context.getFunctionType(NewProto->getResultType(),
- NewProto->arg_type_begin(),
- NewProto->getNumArgs(),
- EPI);
+ QualType NewType =
+ Context.getFunctionType(NewProto->getResultType(),
+ ArrayRef<QualType>(NewProto->arg_type_begin(),
+ NewProto->getNumArgs()),
+ EPI);
New->setType(NewType);
// If exceptions are disabled, suppress the warning about missing
@@ -282,8 +296,8 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
SourceLocation FixItLoc;
if (TypeSourceInfo *TSInfo = New->getTypeSourceInfo()) {
TypeLoc TL = TSInfo->getTypeLoc().IgnoreParens();
- if (const FunctionTypeLoc *FTLoc = dyn_cast<FunctionTypeLoc>(&TL))
- FixItLoc = PP.getLocForEndOfToken(FTLoc->getLocalRangeEnd());
+ if (FunctionTypeLoc FTLoc = TL.getAs<FunctionTypeLoc>())
+ FixItLoc = PP.getLocForEndOfToken(FTLoc.getLocalRangeEnd());
}
if (FixItLoc.isInvalid())
@@ -442,7 +456,7 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
// As a special compatibility feature, under C++0x we accept no spec and
// throw(std::bad_alloc) as equivalent for operator new and operator new[].
// This is because the implicit declaration changed, but old code would break.
- if (getLangOpts().CPlusPlus0x && IsOperatorNew) {
+ if (getLangOpts().CPlusPlus11 && IsOperatorNew) {
const FunctionProtoType *WithExceptions = 0;
if (OldEST == EST_None && NewEST == EST_Dynamic)
WithExceptions = New;
@@ -773,7 +787,7 @@ bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType)
bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
const CXXMethodDecl *Old) {
- if (getLangOpts().CPlusPlus0x && isa<CXXDestructorDecl>(New)) {
+ if (getLangOpts().CPlusPlus11 && isa<CXXDestructorDecl>(New)) {
// Don't check uninstantiated template destructors at all. We can only
// synthesize correct specs after the template is instantiated.
if (New->getParent()->isDependentType())
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index bf4abfc..76330f5 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -12,13 +12,9 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/DelayedDiagnostic.h"
-#include "clang/Sema/Initialization.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/ScopeInfo.h"
-#include "clang/Sema/AnalysisBasedWarnings.h"
-#include "clang/AST/ASTContext.h"
+#include "TreeTransform.h"
#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclObjC.h"
@@ -34,14 +30,17 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/AnalysisBasedWarnings.h"
#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/DelayedDiagnostic.h"
#include "clang/Sema/Designator.h"
+#include "clang/Sema/Initialization.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
-#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/SemaFixItUtils.h"
#include "clang/Sema/Template.h"
-#include "TreeTransform.h"
using namespace clang;
using namespace sema;
@@ -163,7 +162,7 @@ static bool hasAnyExplicitStorageClass(const FunctionDecl *D) {
for (FunctionDecl::redecl_iterator I = D->redecls_begin(),
E = D->redecls_end();
I != E; ++I) {
- if (I->getStorageClassAsWritten() != SC_None)
+ if (I->getStorageClass() != SC_None)
return true;
}
return false;
@@ -215,19 +214,24 @@ static void diagnoseUseOfInternalDeclInInlineFunction(Sema &S,
: diag::warn_internal_in_extern_inline)
<< /*IsVar=*/!UsedFn << D;
- // Suggest "static" on the inline function, if possible.
- if (!hasAnyExplicitStorageClass(Current)) {
- const FunctionDecl *FirstDecl = Current->getCanonicalDecl();
- SourceLocation DeclBegin = FirstDecl->getSourceRange().getBegin();
- S.Diag(DeclBegin, diag::note_convert_inline_to_static)
- << Current << FixItHint::CreateInsertion(DeclBegin, "static ");
- }
+ S.MaybeSuggestAddingStaticToDecl(Current);
S.Diag(D->getCanonicalDecl()->getLocation(),
diag::note_internal_decl_declared_here)
<< D;
}
+void Sema::MaybeSuggestAddingStaticToDecl(const FunctionDecl *Cur) {
+ const FunctionDecl *First = Cur->getFirstDeclaration();
+
+ // Suggest "static" on the function, if possible.
+ if (!hasAnyExplicitStorageClass(First)) {
+ SourceLocation DeclBegin = First->getSourceRange().getBegin();
+ Diag(DeclBegin, diag::note_convert_inline_to_static)
+ << Cur << FixItHint::CreateInsertion(DeclBegin, "static ");
+ }
+}
+
/// \brief Determine whether the use of this declaration is valid, and
/// emit any corresponding diagnostics.
///
@@ -288,12 +292,6 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
/// diagnostic complaining about the given function being deleted or
/// unavailable.
std::string Sema::getDeletedOrUnavailableSuffix(const FunctionDecl *FD) {
- // FIXME: C++0x implicitly-deleted special member functions could be
- // detected here so that we could improve diagnostics to say, e.g.,
- // "base class 'A' had a deleted copy constructor".
- if (FD->isDeleted())
- return std::string();
-
std::string Message;
if (FD->getAvailability(&Message))
return ": " + Message;
@@ -457,6 +455,62 @@ static void CheckForNullPointerDereference(Sema &S, Expr *E) {
}
}
+static void DiagnoseDirectIsaAccess(Sema &S, const ObjCIvarRefExpr *OIRE,
+ SourceLocation AssignLoc,
+ const Expr* RHS) {
+ const ObjCIvarDecl *IV = OIRE->getDecl();
+ if (!IV)
+ return;
+
+ DeclarationName MemberName = IV->getDeclName();
+ IdentifierInfo *Member = MemberName.getAsIdentifierInfo();
+ if (!Member || !Member->isStr("isa"))
+ return;
+
+ const Expr *Base = OIRE->getBase();
+ QualType BaseType = Base->getType();
+ if (OIRE->isArrow())
+ BaseType = BaseType->getPointeeType();
+ if (const ObjCObjectType *OTy = BaseType->getAs<ObjCObjectType>())
+ if (ObjCInterfaceDecl *IDecl = OTy->getInterface()) {
+ ObjCInterfaceDecl *ClassDeclared = 0;
+ ObjCIvarDecl *IV = IDecl->lookupInstanceVariable(Member, ClassDeclared);
+ if (!ClassDeclared->getSuperClass()
+ && (*ClassDeclared->ivar_begin()) == IV) {
+ if (RHS) {
+ NamedDecl *ObjectSetClass =
+ S.LookupSingleName(S.TUScope,
+ &S.Context.Idents.get("object_setClass"),
+ SourceLocation(), S.LookupOrdinaryName);
+ if (ObjectSetClass) {
+ SourceLocation RHSLocEnd = S.PP.getLocForEndOfToken(RHS->getLocEnd());
+ S.Diag(OIRE->getExprLoc(), diag::warn_objc_isa_assign) <<
+ FixItHint::CreateInsertion(OIRE->getLocStart(), "object_setClass(") <<
+ FixItHint::CreateReplacement(SourceRange(OIRE->getOpLoc(),
+ AssignLoc), ",") <<
+ FixItHint::CreateInsertion(RHSLocEnd, ")");
+ }
+ else
+ S.Diag(OIRE->getLocation(), diag::warn_objc_isa_assign);
+ } else {
+ NamedDecl *ObjectGetClass =
+ S.LookupSingleName(S.TUScope,
+ &S.Context.Idents.get("object_getClass"),
+ SourceLocation(), S.LookupOrdinaryName);
+ if (ObjectGetClass)
+ S.Diag(OIRE->getExprLoc(), diag::warn_objc_isa_use) <<
+ FixItHint::CreateInsertion(OIRE->getLocStart(), "object_getClass(") <<
+ FixItHint::CreateReplacement(
+ SourceRange(OIRE->getOpLoc(),
+ OIRE->getLocEnd()), ")");
+ else
+ S.Diag(OIRE->getLocation(), diag::warn_objc_isa_use);
+ }
+ S.Diag(IV->getLocation(), diag::note_ivar_decl);
+ }
+ }
+}
+
ExprResult Sema::DefaultLvalueConversion(Expr *E) {
// Handle any placeholder expressions which made it here.
if (E->getType()->isPlaceholderType()) {
@@ -489,8 +543,31 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
if (T->isVoidType())
return Owned(E);
- CheckForNullPointerDereference(*this, E);
+ // OpenCL usually rejects direct accesses to values of 'half' type.
+ if (getLangOpts().OpenCL && !getOpenCLOptions().cl_khr_fp16 &&
+ T->isHalfType()) {
+ Diag(E->getExprLoc(), diag::err_opencl_half_load_store)
+ << 0 << T;
+ return ExprError();
+ }
+ CheckForNullPointerDereference(*this, E);
+ if (const ObjCIsaExpr *OISA = dyn_cast<ObjCIsaExpr>(E->IgnoreParenCasts())) {
+ NamedDecl *ObjectGetClass = LookupSingleName(TUScope,
+ &Context.Idents.get("object_getClass"),
+ SourceLocation(), LookupOrdinaryName);
+ if (ObjectGetClass)
+ Diag(E->getExprLoc(), diag::warn_objc_isa_use) <<
+ FixItHint::CreateInsertion(OISA->getLocStart(), "object_getClass(") <<
+ FixItHint::CreateReplacement(
+ SourceRange(OISA->getOpLoc(), OISA->getIsaMemberLoc()), ")");
+ else
+ Diag(E->getExprLoc(), diag::warn_objc_isa_use);
+ }
+ else if (const ObjCIvarRefExpr *OIRE =
+ dyn_cast<ObjCIvarRefExpr>(E->IgnoreParenCasts()))
+ DiagnoseDirectIsaAccess(*this, OIRE, SourceLocation(), /* Expr*/0);
+
// C++ [conv.lval]p1:
// [...] If T is a non-class type, the type of the prvalue is the
// cv-unqualified version of T. Otherwise, the type of the
@@ -504,6 +581,12 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
T = T.getUnqualifiedType();
UpdateMarkingForLValueToRValue(E);
+
+ // Loading a __weak object implicitly retains the value, so we need a cleanup to
+ // balance that.
+ if (getLangOpts().ObjCAutoRefCount &&
+ E->getType().getObjCLifetime() == Qualifiers::OCL_Weak)
+ ExprNeedsCleanups = true;
ExprResult Res = Owned(ImplicitCastExpr::Create(Context, T, CK_LValueToRValue,
E, 0, VK_RValue));
@@ -540,15 +623,14 @@ ExprResult Sema::UsualUnaryConversions(Expr *E) {
// First, convert to an r-value.
ExprResult Res = DefaultFunctionArrayLvalueConversion(E);
if (Res.isInvalid())
- return Owned(E);
+ return ExprError();
E = Res.take();
QualType Ty = E->getType();
assert(!Ty.isNull() && "UsualUnaryConversions - missing type");
- // Half FP is a bit different: it's a storage-only type, meaning that any
- // "use" of it should be promoted to float.
- if (Ty->isHalfType())
+ // Half FP have to be promoted to float unless it is natively supported
+ if (Ty->isHalfType() && !getLangOpts().NativeHalfType)
return ImpCastExprToType(Res.take(), Context.FloatTy, CK_FloatingCast);
// Try to perform integral promotions if the object has a theoretically
@@ -583,19 +665,23 @@ ExprResult Sema::UsualUnaryConversions(Expr *E) {
}
/// DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that
-/// do not have a prototype. Arguments that have type float are promoted to
-/// double. All other argument types are converted by UsualUnaryConversions().
+/// do not have a prototype. Arguments that have type float or __fp16
+/// are promoted to double. All other argument types are converted by
+/// UsualUnaryConversions().
ExprResult Sema::DefaultArgumentPromotion(Expr *E) {
QualType Ty = E->getType();
assert(!Ty.isNull() && "DefaultArgumentPromotion - missing type");
ExprResult Res = UsualUnaryConversions(E);
if (Res.isInvalid())
- return Owned(E);
+ return ExprError();
E = Res.take();
- // If this is a 'float' (CVR qualified or typedef) promote to double.
- if (Ty->isSpecificBuiltinType(BuiltinType::Float))
+ // If this is a 'float' or '__fp16' (CVR qualified or typedef) promote to
+ // double.
+ const BuiltinType *BTy = Ty->getAs<BuiltinType>();
+ if (BTy && (BTy->getKind() == BuiltinType::Half ||
+ BTy->getKind() == BuiltinType::Float))
E = ImpCastExprToType(E, Context.DoubleTy, CK_FloatingCast).take();
// C++ performs lvalue-to-rvalue conversion as a default argument
@@ -635,16 +721,16 @@ Sema::VarArgKind Sema::isValidVarArgType(const QualType &Ty) {
if (Ty.isCXX98PODType(Context))
return VAK_Valid;
- // C++0x [expr.call]p7:
- // Passing a potentially-evaluated argument of class type (Clause 9)
+ // C++11 [expr.call]p7:
+ // Passing a potentially-evaluated argument of class type (Clause 9)
// having a non-trivial copy constructor, a non-trivial move constructor,
- // or a non-trivial destructor, with no corresponding parameter,
+ // or a non-trivial destructor, with no corresponding parameter,
// is conditionally-supported with implementation-defined semantics.
- if (getLangOpts().CPlusPlus0x && !Ty->isDependentType())
+ if (getLangOpts().CPlusPlus11 && !Ty->isDependentType())
if (CXXRecordDecl *Record = Ty->getAsCXXRecordDecl())
- if (Record->hasTrivialCopyConstructor() &&
- Record->hasTrivialMoveConstructor() &&
- Record->hasTrivialDestructor())
+ if (!Record->hasNonTrivialCopyConstructor() &&
+ !Record->hasNonTrivialMoveConstructor() &&
+ !Record->hasNonTrivialDestructor())
return VAK_ValidInCXX11;
if (getLangOpts().ObjCAutoRefCount && Ty->isObjCLifetimeType())
@@ -673,7 +759,7 @@ bool Sema::variadicArgumentPODCheck(const Expr *E, VariadicCallType CT) {
return DiagRuntimeBehavior(E->getLocStart(), 0,
PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg)
- << getLangOpts().CPlusPlus0x << Ty << CT);
+ << getLangOpts().CPlusPlus11 << Ty << CT);
}
}
// c++ rules are enforced elsewhere.
@@ -938,54 +1024,24 @@ static QualType handleFloatConversion(Sema &S, ExprResult &LHS,
/*convertFloat=*/!IsCompAssign);
}
-/// \brief Handle conversions with GCC complex int extension. Helper function
-/// of UsualArithmeticConversions()
-// FIXME: if the operands are (int, _Complex long), we currently
-// don't promote the complex. Also, signedness?
-static QualType handleComplexIntConversion(Sema &S, ExprResult &LHS,
- ExprResult &RHS, QualType LHSType,
- QualType RHSType,
- bool IsCompAssign) {
- const ComplexType *LHSComplexInt = LHSType->getAsComplexIntegerType();
- const ComplexType *RHSComplexInt = RHSType->getAsComplexIntegerType();
+typedef ExprResult PerformCastFn(Sema &S, Expr *operand, QualType toType);
- if (LHSComplexInt && RHSComplexInt) {
- int order = S.Context.getIntegerTypeOrder(LHSComplexInt->getElementType(),
- RHSComplexInt->getElementType());
- assert(order && "inequal types with equal element ordering");
- if (order > 0) {
- // _Complex int -> _Complex long
- RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_IntegralComplexCast);
- return LHSType;
- }
-
- if (!IsCompAssign)
- LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_IntegralComplexCast);
- return RHSType;
- }
-
- if (LHSComplexInt) {
- // int -> _Complex int
- // FIXME: This needs to take integer ranks into account
- RHS = S.ImpCastExprToType(RHS.take(), LHSComplexInt->getElementType(),
- CK_IntegralCast);
- RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_IntegralRealToComplex);
- return LHSType;
- }
+namespace {
+/// These helper callbacks are placed in an anonymous namespace to
+/// permit their use as function template parameters.
+ExprResult doIntegralCast(Sema &S, Expr *op, QualType toType) {
+ return S.ImpCastExprToType(op, toType, CK_IntegralCast);
+}
- assert(RHSComplexInt);
- // int -> _Complex int
- // FIXME: This needs to take integer ranks into account
- if (!IsCompAssign) {
- LHS = S.ImpCastExprToType(LHS.take(), RHSComplexInt->getElementType(),
- CK_IntegralCast);
- LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_IntegralRealToComplex);
- }
- return RHSType;
+ExprResult doComplexIntegralCast(Sema &S, Expr *op, QualType toType) {
+ return S.ImpCastExprToType(op, S.Context.getComplexType(toType),
+ CK_IntegralComplexCast);
+}
}
/// \brief Handle integer arithmetic conversions. Helper function of
/// UsualArithmeticConversions()
+template <PerformCastFn doLHSCast, PerformCastFn doRHSCast>
static QualType handleIntegerConversion(Sema &S, ExprResult &LHS,
ExprResult &RHS, QualType LHSType,
QualType RHSType, bool IsCompAssign) {
@@ -996,29 +1052,29 @@ static QualType handleIntegerConversion(Sema &S, ExprResult &LHS,
if (LHSSigned == RHSSigned) {
// Same signedness; use the higher-ranked type
if (order >= 0) {
- RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_IntegralCast);
+ RHS = (*doRHSCast)(S, RHS.take(), LHSType);
return LHSType;
} else if (!IsCompAssign)
- LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_IntegralCast);
+ LHS = (*doLHSCast)(S, LHS.take(), RHSType);
return RHSType;
} else if (order != (LHSSigned ? 1 : -1)) {
// The unsigned type has greater than or equal rank to the
// signed type, so use the unsigned type
if (RHSSigned) {
- RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_IntegralCast);
+ RHS = (*doRHSCast)(S, RHS.take(), LHSType);
return LHSType;
} else if (!IsCompAssign)
- LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_IntegralCast);
+ LHS = (*doLHSCast)(S, LHS.take(), RHSType);
return RHSType;
} else if (S.Context.getIntWidth(LHSType) != S.Context.getIntWidth(RHSType)) {
// The two types are different widths; if we are here, that
// means the signed type is larger than the unsigned type, so
// use the signed type.
if (LHSSigned) {
- RHS = S.ImpCastExprToType(RHS.take(), LHSType, CK_IntegralCast);
+ RHS = (*doRHSCast)(S, RHS.take(), LHSType);
return LHSType;
} else if (!IsCompAssign)
- LHS = S.ImpCastExprToType(LHS.take(), RHSType, CK_IntegralCast);
+ LHS = (*doLHSCast)(S, LHS.take(), RHSType);
return RHSType;
} else {
// The signed type is higher-ranked than the unsigned type,
@@ -1027,19 +1083,62 @@ static QualType handleIntegerConversion(Sema &S, ExprResult &LHS,
// to the signed type.
QualType result =
S.Context.getCorrespondingUnsignedType(LHSSigned ? LHSType : RHSType);
- RHS = S.ImpCastExprToType(RHS.take(), result, CK_IntegralCast);
+ RHS = (*doRHSCast)(S, RHS.take(), result);
if (!IsCompAssign)
- LHS = S.ImpCastExprToType(LHS.take(), result, CK_IntegralCast);
+ LHS = (*doLHSCast)(S, LHS.take(), result);
return result;
}
}
+/// \brief Handle conversions with GCC complex int extension. Helper function
+/// of UsualArithmeticConversions()
+static QualType handleComplexIntConversion(Sema &S, ExprResult &LHS,
+ ExprResult &RHS, QualType LHSType,
+ QualType RHSType,
+ bool IsCompAssign) {
+ const ComplexType *LHSComplexInt = LHSType->getAsComplexIntegerType();
+ const ComplexType *RHSComplexInt = RHSType->getAsComplexIntegerType();
+
+ if (LHSComplexInt && RHSComplexInt) {
+ QualType LHSEltType = LHSComplexInt->getElementType();
+ QualType RHSEltType = RHSComplexInt->getElementType();
+ QualType ScalarType =
+ handleIntegerConversion<doComplexIntegralCast, doComplexIntegralCast>
+ (S, LHS, RHS, LHSEltType, RHSEltType, IsCompAssign);
+
+ return S.Context.getComplexType(ScalarType);
+ }
+
+ if (LHSComplexInt) {
+ QualType LHSEltType = LHSComplexInt->getElementType();
+ QualType ScalarType =
+ handleIntegerConversion<doComplexIntegralCast, doIntegralCast>
+ (S, LHS, RHS, LHSEltType, RHSType, IsCompAssign);
+ QualType ComplexType = S.Context.getComplexType(ScalarType);
+ RHS = S.ImpCastExprToType(RHS.take(), ComplexType,
+ CK_IntegralRealToComplex);
+
+ return ComplexType;
+ }
+
+ assert(RHSComplexInt);
+
+ QualType RHSEltType = RHSComplexInt->getElementType();
+ QualType ScalarType =
+ handleIntegerConversion<doIntegralCast, doComplexIntegralCast>
+ (S, LHS, RHS, LHSType, RHSEltType, IsCompAssign);
+ QualType ComplexType = S.Context.getComplexType(ScalarType);
+
+ if (!IsCompAssign)
+ LHS = S.ImpCastExprToType(LHS.take(), ComplexType,
+ CK_IntegralRealToComplex);
+ return ComplexType;
+}
+
/// UsualArithmeticConversions - Performs various conversions that are common to
/// binary operators (C99 6.3.1.8). If both operands aren't arithmetic, this
/// routine returns the first non-arithmetic type found. The client is
/// responsible for emitting appropriate error diagnostics.
-/// FIXME: verify the conversion rules for "complex int" are consistent with
-/// GCC.
QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
bool IsCompAssign) {
if (!IsCompAssign) {
@@ -1104,10 +1203,11 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
IsCompAssign);
// Finally, we have two differing integer types.
- return handleIntegerConversion(*this, LHS, RHS, LHSType, RHSType,
- IsCompAssign);
+ return handleIntegerConversion<doIntegralCast, doIntegralCast>
+ (*this, LHS, RHS, LHSType, RHSType, IsCompAssign);
}
+
//===----------------------------------------------------------------------===//
// Semantic Analysis for various Expression Types
//===----------------------------------------------------------------------===//
@@ -1149,6 +1249,12 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
TypeSourceInfo **Types,
Expr **Exprs,
unsigned NumAssocs) {
+ if (ControllingExpr->getType()->isPlaceholderType()) {
+ ExprResult result = CheckPlaceholderExpr(ControllingExpr);
+ if (result.isInvalid()) return ExprError();
+ ControllingExpr = result.take();
+ }
+
bool TypeErrorFound = false,
IsResultDependent = ControllingExpr->isTypeDependent(),
ContainsUnexpandedParameterPack
@@ -1401,7 +1507,7 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
ExprResult
Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
const DeclarationNameInfo &NameInfo,
- const CXXScopeSpec *SS) {
+ const CXXScopeSpec *SS, NamedDecl *FoundD) {
if (getLangOpts().CUDA)
if (const FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext))
if (const FunctionDecl *Callee = dyn_cast<FunctionDecl>(D)) {
@@ -1425,7 +1531,7 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
: NestedNameSpecifierLoc(),
SourceLocation(),
D, refersToEnclosingScope,
- NameInfo, Ty, VK);
+ NameInfo, Ty, VK, FoundD);
MarkDeclRefReferenced(E);
@@ -1533,9 +1639,10 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(
CallsUndergoingInstantiation.back()->getCallee());
-
CXXMethodDecl *DepMethod;
- if (CurMethod->getTemplatedKind() ==
+ if (CurMethod->isDependentContext())
+ DepMethod = CurMethod;
+ else if (CurMethod->getTemplatedKind() ==
FunctionDecl::TK_FunctionTemplateSpecialization)
DepMethod = cast<CXXMethodDecl>(CurMethod->getPrimaryTemplate()->
getInstantiatedFromMemberTemplate()->getTemplatedDecl());
@@ -1642,9 +1749,13 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
<< SS.getRange()
<< FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
CorrectedStr);
- if (ND)
- Diag(ND->getLocation(), diag::note_previous_decl)
- << CorrectedQuotedStr;
+
+ unsigned diag = isa<ImplicitParamDecl>(ND)
+ ? diag::note_implicit_param_decl
+ : diag::note_previous_decl;
+
+ Diag(ND->getLocation(), diag)
+ << CorrectedQuotedStr;
// Tell the callee to try to recover.
return false;
@@ -1946,6 +2057,10 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
IdentifierInfo *II, bool AllowBuiltinCreation) {
SourceLocation Loc = Lookup.getNameLoc();
ObjCMethodDecl *CurMethod = getCurMethodDecl();
+
+ // Check for error condition which is already reported.
+ if (!CurMethod)
+ return ExprError();
// There are two cases to handle here. 1) scoped lookup could have failed,
// in which case we should look for an ivar. 2) scoped lookup could have
@@ -2009,14 +2124,15 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S,
if (SelfExpr.isInvalid())
return ExprError();
- MarkAnyDeclReferenced(Loc, IV);
+ MarkAnyDeclReferenced(Loc, IV, true);
ObjCMethodFamily MF = CurMethod->getMethodFamily();
- if (MF != OMF_init && MF != OMF_dealloc && MF != OMF_finalize)
+ if (MF != OMF_init && MF != OMF_dealloc && MF != OMF_finalize &&
+ !IvarBacksCurrentMethodAccessor(IFace, CurMethod, IV))
Diag(Loc, diag::warn_direct_ivar_access) << IV->getDeclName();
ObjCIvarRefExpr *Result = new (Context) ObjCIvarRefExpr(IV, IV->getType(),
- Loc,
+ Loc, IV->getLocation(),
SelfExpr.take(),
true, true);
@@ -2321,8 +2437,8 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
// If this is a single, fully-resolved result and we don't need ADL,
// just build an ordinary singleton decl ref.
if (!NeedsADL && R.isSingleResult() && !R.getAsSingle<FunctionTemplateDecl>())
- return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(),
- R.getFoundDecl());
+ return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), R.getFoundDecl(),
+ R.getRepresentativeDecl());
// We only need to check the declaration if there's exactly one
// result, because in the overloaded case the results can only be
@@ -2350,7 +2466,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
ExprResult
Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
const DeclarationNameInfo &NameInfo,
- NamedDecl *D) {
+ NamedDecl *D, NamedDecl *FoundD) {
assert(D && "Cannot refer to a NULL declaration");
assert(!isa<FunctionTemplateDecl>(D) &&
"Cannot refer unambiguously to a function template");
@@ -2546,7 +2662,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
break;
}
- return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS);
+ return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS, FoundD);
}
}
@@ -2565,8 +2681,14 @@ ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
// string.
Decl *currentDecl = getCurFunctionOrMethodDecl();
- if (!currentDecl && getCurBlock())
- currentDecl = getCurBlock()->TheDecl;
+ // Blocks and lambdas can occur at global scope. Don't emit a warning.
+ if (!currentDecl) {
+ if (const BlockScopeInfo *BSI = getCurBlock())
+ currentDecl = BSI->TheDecl;
+ else if (const LambdaScopeInfo *LSI = getCurLambda())
+ currentDecl = LSI->CallOperator;
+ }
+
if (!currentDecl) {
Diag(Loc, diag::ext_predef_outside_function);
currentDecl = Context.getTranslationUnitDecl();
@@ -2764,7 +2886,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
SourceLocation TokLoc = Tok.getLocation();
unsigned Length = Literal.getUDSuffixOffset();
QualType StrTy = Context.getConstantArrayType(
- Context.CharTy, llvm::APInt(32, Length + 1),
+ Context.CharTy.withConst(), llvm::APInt(32, Length + 1),
ArrayType::Normal, 0);
Expr *Lit = StringLiteral::Create(
Context, StringRef(TokSpelling.data(), Length), StringLiteral::Ascii,
@@ -2825,7 +2947,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
if (!getLangOpts().C99 && Literal.isLongLong) {
if (getLangOpts().CPlusPlus)
Diag(Tok.getLocation(),
- getLangOpts().CPlusPlus0x ?
+ getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong);
else
Diag(Tok.getLocation(), diag::ext_c99_longlong);
@@ -2835,7 +2957,10 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
unsigned MaxWidth = Context.getTargetInfo().getIntMaxTWidth();
// The microsoft literal suffix extensions support 128-bit literals, which
// may be wider than [u]intmax_t.
- if (Literal.isMicrosoftInteger && MaxWidth < 128)
+ // FIXME: Actually, they don't. We seem to have accidentally invented the
+ // i128 suffix.
+ if (Literal.isMicrosoftInteger && MaxWidth < 128 &&
+ PP.getTargetInfo().hasInt128Type())
MaxWidth = 128;
llvm::APInt ResultVal(MaxWidth, 0);
@@ -2905,7 +3030,8 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
// If it doesn't fit in unsigned long long, and we're using Microsoft
// extensions, then its a 128-bit integer literal.
- if (Ty.isNull() && Literal.isMicrosoftInteger) {
+ if (Ty.isNull() && Literal.isMicrosoftInteger &&
+ PP.getTargetInfo().hasInt128Type()) {
if (Literal.isUnsigned)
Ty = Context.UnsignedInt128Ty;
else
@@ -2963,16 +3089,17 @@ static bool CheckExtensionTraitOperandType(Sema &S, QualType T,
SourceRange ArgRange,
UnaryExprOrTypeTrait TraitKind) {
// C99 6.5.3.4p1:
- if (T->isFunctionType()) {
- // alignof(function) is allowed as an extension.
- if (TraitKind == UETT_SizeOf)
- S.Diag(Loc, diag::ext_sizeof_function_type) << ArgRange;
+ if (T->isFunctionType() &&
+ (TraitKind == UETT_SizeOf || TraitKind == UETT_AlignOf)) {
+ // sizeof(function)/alignof(function) is allowed as an extension.
+ S.Diag(Loc, diag::ext_sizeof_alignof_function_type)
+ << TraitKind << ArgRange;
return false;
}
// Allow sizeof(void)/alignof(void) as an extension.
if (T->isVoidType()) {
- S.Diag(Loc, diag::ext_sizeof_void_type) << TraitKind << ArgRange;
+ S.Diag(Loc, diag::ext_sizeof_alignof_void_type) << TraitKind << ArgRange;
return false;
}
@@ -2995,6 +3122,24 @@ static bool CheckObjCTraitOperandConstraints(Sema &S, QualType T,
return false;
}
+/// \brief Check whether E is a pointer from a decayed array type (the decayed
+/// pointer type is equal to T) and emit a warning if it is.
+static void warnOnSizeofOnArrayDecay(Sema &S, SourceLocation Loc, QualType T,
+ Expr *E) {
+ // Don't warn if the operation changed the type.
+ if (T != E->getType())
+ return;
+
+ // Now look for array decays.
+ ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E);
+ if (!ICE || ICE->getCastKind() != CK_ArrayToPointerDecay)
+ return;
+
+ S.Diag(Loc, diag::warn_sizeof_array_decay) << ICE->getSourceRange()
+ << ICE->getType()
+ << ICE->getSubExpr()->getType();
+}
+
/// \brief Check the constrains on expression operands to unary type expression
/// and type traits.
///
@@ -3048,6 +3193,16 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E,
}
}
}
+
+ // Warn on "sizeof(array op x)" and "sizeof(x op array)", where the array
+ // decays into a pointer and returns an unintended result. This is most
+ // likely a typo for "sizeof(array) op x".
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E->IgnoreParens())) {
+ warnOnSizeofOnArrayDecay(*this, BO->getOperatorLoc(), BO->getType(),
+ BO->getLHS());
+ warnOnSizeofOnArrayDecay(*this, BO->getOperatorLoc(), BO->getType(),
+ BO->getRHS());
+ }
}
return false;
@@ -3189,7 +3344,7 @@ Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc,
return ExprError();
if (ExprKind == UETT_SizeOf && E->getType()->isVariableArrayType()) {
- PE = TranformToPotentiallyEvaluated(E);
+ PE = TransformToPotentiallyEvaluated(E);
if (PE.isInvalid()) return ExprError();
E = PE.take();
}
@@ -3292,33 +3447,56 @@ static bool checkArithmeticOnObjCPointer(Sema &S,
}
ExprResult
-Sema::ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc,
- Expr *Idx, SourceLocation RLoc) {
+Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
+ Expr *idx, SourceLocation rbLoc) {
// Since this might be a postfix expression, get rid of ParenListExprs.
- ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Base);
- if (Result.isInvalid()) return ExprError();
- Base = Result.take();
+ if (isa<ParenListExpr>(base)) {
+ ExprResult result = MaybeConvertParenListExprToParenExpr(S, base);
+ if (result.isInvalid()) return ExprError();
+ base = result.take();
+ }
- Expr *LHSExp = Base, *RHSExp = Idx;
+ // Handle any non-overload placeholder types in the base and index
+ // expressions. We can't handle overloads here because the other
+ // operand might be an overloadable type, in which case the overload
+ // resolution for the operator overload should get the first crack
+ // at the overload.
+ if (base->getType()->isNonOverloadPlaceholderType()) {
+ ExprResult result = CheckPlaceholderExpr(base);
+ if (result.isInvalid()) return ExprError();
+ base = result.take();
+ }
+ if (idx->getType()->isNonOverloadPlaceholderType()) {
+ ExprResult result = CheckPlaceholderExpr(idx);
+ if (result.isInvalid()) return ExprError();
+ idx = result.take();
+ }
+ // Build an unanalyzed expression if either operand is type-dependent.
if (getLangOpts().CPlusPlus &&
- (LHSExp->isTypeDependent() || RHSExp->isTypeDependent())) {
- return Owned(new (Context) ArraySubscriptExpr(LHSExp, RHSExp,
+ (base->isTypeDependent() || idx->isTypeDependent())) {
+ return Owned(new (Context) ArraySubscriptExpr(base, idx,
Context.DependentTy,
VK_LValue, OK_Ordinary,
- RLoc));
+ rbLoc));
}
+ // Use C++ overloaded-operator rules if either operand has record
+ // type. The spec says to do this if either type is *overloadable*,
+ // but enum types can't declare subscript operators or conversion
+ // operators, so there's nothing interesting for overload resolution
+ // to do if there aren't any record types involved.
+ //
+ // ObjC pointers have their own subscripting logic that is not tied
+ // to overload resolution and so should not take this path.
if (getLangOpts().CPlusPlus &&
- (LHSExp->getType()->isRecordType() ||
- LHSExp->getType()->isEnumeralType() ||
- RHSExp->getType()->isRecordType() ||
- RHSExp->getType()->isEnumeralType()) &&
- !LHSExp->getType()->isObjCObjectPointerType()) {
- return CreateOverloadedArraySubscriptExpr(LLoc, RLoc, Base, Idx);
+ (base->getType()->isRecordType() ||
+ (!base->getType()->isObjCObjectPointerType() &&
+ idx->getType()->isRecordType()))) {
+ return CreateOverloadedArraySubscriptExpr(lbLoc, rbLoc, base, idx);
}
- return CreateBuiltinArraySubscriptExpr(Base, LLoc, Idx, RLoc);
+ return CreateBuiltinArraySubscriptExpr(base, lbLoc, idx, rbLoc);
}
ExprResult
@@ -3525,7 +3703,7 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
return ExprError();
Expr *Arg = Result.takeAs<Expr>();
- CheckImplicitConversions(Arg, Param->getOuterLocStart());
+ CheckCompletedExpr(Arg, Param->getOuterLocStart());
// Build the default argument expression.
return Owned(CXXDefaultArgExpr::Create(Context, CallLoc, Param, Arg));
}
@@ -3687,7 +3865,8 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
Expr **Args, unsigned NumArgs,
SmallVector<Expr *, 8> &AllArgs,
VariadicCallType CallType,
- bool AllowExplicit) {
+ bool AllowExplicit,
+ bool IsListInitialization) {
unsigned NumArgsInProto = Proto->getNumArgs();
unsigned NumArgsToCheck = NumArgs;
bool Invalid = false;
@@ -3720,20 +3899,21 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
(!Param || !Param->hasAttr<CFConsumedAttr>()))
Arg = stripARCUnbridgedCast(Arg);
- InitializedEntity Entity =
- Param? InitializedEntity::InitializeParameter(Context, Param)
- : InitializedEntity::InitializeParameter(Context, ProtoArgType,
- Proto->isArgConsumed(i));
+ InitializedEntity Entity = Param ?
+ InitializedEntity::InitializeParameter(Context, Param, ProtoArgType)
+ : InitializedEntity::InitializeParameter(Context, ProtoArgType,
+ Proto->isArgConsumed(i));
ExprResult ArgE = PerformCopyInitialization(Entity,
SourceLocation(),
Owned(Arg),
- /*TopLevelOfInitList=*/false,
+ IsListInitialization,
AllowExplicit);
if (ArgE.isInvalid())
return true;
Arg = ArgE.takeAs<Expr>();
} else {
+ assert(FDecl && "can't use default arguments without a known callee");
Param = FDecl->getParamDecl(i);
ExprResult ArgExpr =
@@ -3762,11 +3942,8 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
if (Proto->getResultType() == Context.UnknownAnyTy &&
FDecl && FDecl->isExternC()) {
for (unsigned i = ArgIx; i != NumArgs; ++i) {
- ExprResult arg;
- if (isa<ExplicitCastExpr>(Args[i]->IgnoreParens()))
- arg = DefaultFunctionArrayLvalueConversion(Args[i]);
- else
- arg = DefaultVariadicArgumentPromotion(Args[i], CallType, FDecl);
+ QualType paramType; // ignored
+ ExprResult arg = checkUnknownAnyArg(CallLoc, Args[i], paramType);
Invalid |= arg.isInvalid();
AllArgs.push_back(arg.take());
}
@@ -3790,9 +3967,9 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc,
static void DiagnoseCalleeStaticArrayParam(Sema &S, ParmVarDecl *PVD) {
TypeLoc TL = PVD->getTypeSourceInfo()->getTypeLoc();
- if (ArrayTypeLoc *ATL = dyn_cast<ArrayTypeLoc>(&TL))
+ if (ArrayTypeLoc ATL = TL.getAs<ArrayTypeLoc>())
S.Diag(PVD->getLocation(), diag::note_callee_static_array)
- << ATL->getLocalSourceRange();
+ << ATL.getLocalSourceRange();
}
/// CheckStaticArrayArgument - If the given argument corresponds to a static
@@ -4593,10 +4770,15 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc,
Expr **exprs;
unsigned numExprs;
Expr *subExpr;
+ SourceLocation LiteralLParenLoc, LiteralRParenLoc;
if (ParenListExpr *PE = dyn_cast<ParenListExpr>(E)) {
+ LiteralLParenLoc = PE->getLParenLoc();
+ LiteralRParenLoc = PE->getRParenLoc();
exprs = PE->getExprs();
numExprs = PE->getNumExprs();
- } else {
+ } else { // isa<ParenExpr> by assertion at function entrance
+ LiteralLParenLoc = cast<ParenExpr>(E)->getLParen();
+ LiteralRParenLoc = cast<ParenExpr>(E)->getRParen();
subExpr = cast<ParenExpr>(E)->getSubExpr();
exprs = &subExpr;
numExprs = 1;
@@ -4653,8 +4835,8 @@ 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, RParenLoc);
+ InitListExpr *initE = new (Context) InitListExpr(Context, LiteralLParenLoc,
+ initExprs, LiteralRParenLoc);
initE->setType(Ty);
return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, initE);
}
@@ -4681,7 +4863,6 @@ Sema::MaybeConvertParenListExprToParenExpr(Scope *S, Expr *OrigExpr) {
ExprResult Sema::ActOnParenListExpr(SourceLocation L,
SourceLocation R,
MultiExprArg Val) {
- assert(Val.data() != 0 && "ActOnParenOrParenListExpr() missing expr list");
Expr *expr = new (Context) ParenListExpr(Context, L, Val, R);
return Owned(expr);
}
@@ -4720,7 +4901,7 @@ bool Sema::DiagnoseConditionalForNull(Expr *LHSExpr, Expr *RHSExpr,
return false;
}
- int DiagType = (NullKind == Expr::NPCK_CXX0X_nullptr);
+ int DiagType = (NullKind == Expr::NPCK_CXX11_nullptr);
Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands_null)
<< NonPointerExpr->getType() << DiagType
<< NonPointerExpr->getSourceRange();
@@ -4734,7 +4915,7 @@ static bool checkCondition(Sema &S, Expr *Cond) {
// C99 6.5.15p2
if (CondTy->isScalarType()) return false;
- // OpenCL: Sec 6.3.i says the condition is allowed to be a vector or scalar.
+ // OpenCL v1.1 s6.3.i says the condition is allowed to be a vector or scalar.
if (S.getLangOpts().OpenCL && CondTy->isVectorType())
return false;
@@ -4995,9 +5176,9 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
if (LHSTy->isVectorType() || RHSTy->isVectorType())
return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/false);
- // OpenCL: If the condition is a vector, and both operands are scalar,
+ // If the condition is a vector, and both operands are scalar,
// attempt to implicity convert them to the vector type to act like the
- // built in select.
+ // built in select. (OpenCL v1.1 s6.3.i)
if (getLangOpts().OpenCL && CondTy->isVectorType())
if (checkConditionalConvertScalarsToVectors(*this, LHS, RHS, CondTy))
return QualType();
@@ -5264,7 +5445,8 @@ static bool IsArithmeticBinaryExpr(Expr *E, BinaryOperatorKind *Opcode,
// Make sure this is really a binary operator that is safe to pass into
// BinaryOperator::getOverloadedOpcode(), e.g. it's not a subscript op.
OverloadedOperatorKind OO = Call->getOperator();
- if (OO < OO_Plus || OO > OO_Arrow)
+ if (OO < OO_Plus || OO > OO_Arrow ||
+ OO == OO_PlusPlus || OO == OO_MinusMinus)
return false;
BinaryOperatorKind OpKind = BinaryOperator::getOverloadedOpcode(OO);
@@ -5625,7 +5807,6 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
LHSType = Context.getCanonicalType(LHSType).getUnqualifiedType();
RHSType = Context.getCanonicalType(RHSType).getUnqualifiedType();
-
// Common case: no conversion required.
if (LHSType == RHSType) {
Kind = CK_NoOp;
@@ -6570,6 +6751,11 @@ static bool isScopedEnumerationType(QualType T) {
static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc, unsigned Opc,
QualType LHSType) {
+ // OpenCL 6.3j: shift values are effectively % word size of LHS (more defined),
+ // so skip remaining warnings as we don't want to modify values within Sema.
+ if (S.getLangOpts().OpenCL)
+ return;
+
llvm::APSInt Right;
// Check right/shifter operand
if (RHS.get()->isValueDependent() ||
@@ -6689,10 +6875,10 @@ static bool IsWithinTemplateSpecialization(Decl *D) {
}
/// If two different enums are compared, raise a warning.
-static void checkEnumComparison(Sema &S, SourceLocation Loc, ExprResult &LHS,
- ExprResult &RHS) {
- QualType LHSStrippedType = LHS.get()->IgnoreParenImpCasts()->getType();
- QualType RHSStrippedType = RHS.get()->IgnoreParenImpCasts()->getType();
+static void checkEnumComparison(Sema &S, SourceLocation Loc, Expr *LHS,
+ Expr *RHS) {
+ QualType LHSStrippedType = LHS->IgnoreParenImpCasts()->getType();
+ QualType RHSStrippedType = RHS->IgnoreParenImpCasts()->getType();
const EnumType *LHSEnumType = LHSStrippedType->getAs<EnumType>();
if (!LHSEnumType)
@@ -6712,7 +6898,7 @@ static void checkEnumComparison(Sema &S, SourceLocation Loc, ExprResult &LHS,
S.Diag(Loc, diag::warn_comparison_of_mixed_enum_types)
<< LHSStrippedType << RHSStrippedType
- << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
+ << LHS->getSourceRange() << RHS->getSourceRange();
}
/// \brief Diagnose bad pointer comparisons.
@@ -6796,18 +6982,18 @@ static bool isObjCObjectLiteral(ExprResult &E) {
}
static bool hasIsEqualMethod(Sema &S, const Expr *LHS, const Expr *RHS) {
- // Get the LHS object's interface type.
- QualType Type = LHS->getType();
- QualType InterfaceType;
- if (const ObjCObjectPointerType *PTy = Type->getAs<ObjCObjectPointerType>()) {
- InterfaceType = PTy->getPointeeType();
- if (const ObjCObjectType *iQFaceTy =
- InterfaceType->getAsObjCQualifiedInterfaceType())
- InterfaceType = iQFaceTy->getBaseType();
- } else {
- // If this is not actually an Objective-C object, bail out.
+ const ObjCObjectPointerType *Type =
+ LHS->getType()->getAs<ObjCObjectPointerType>();
+
+ // If this is not actually an Objective-C object, bail out.
+ if (!Type)
return false;
- }
+
+ // Get the LHS object's interface type.
+ QualType InterfaceType = Type->getPointeeType();
+ if (const ObjCObjectType *iQFaceTy =
+ InterfaceType->getAsObjCQualifiedInterfaceType())
+ InterfaceType = iQFaceTy->getBaseType();
// If the RHS isn't an Objective-C object, bail out.
if (!RHS->getType()->isObjCObjectPointerType())
@@ -6826,8 +7012,7 @@ static bool hasIsEqualMethod(Sema &S, const Expr *LHS, const Expr *RHS) {
/*warn=*/false);
} else {
// Check protocols.
- Method = S.LookupMethodInQualifiedType(IsEqualSel,
- cast<ObjCObjectPointerType>(Type),
+ Method = S.LookupMethodInQualifiedType(IsEqualSel, Type,
/*instance=*/true);
}
}
@@ -6846,6 +7031,48 @@ static bool hasIsEqualMethod(Sema &S, const Expr *LHS, const Expr *RHS) {
return true;
}
+Sema::ObjCLiteralKind Sema::CheckLiteralKind(Expr *FromE) {
+ FromE = FromE->IgnoreParenImpCasts();
+ switch (FromE->getStmtClass()) {
+ default:
+ break;
+ case Stmt::ObjCStringLiteralClass:
+ // "string literal"
+ return LK_String;
+ case Stmt::ObjCArrayLiteralClass:
+ // "array literal"
+ return LK_Array;
+ case Stmt::ObjCDictionaryLiteralClass:
+ // "dictionary literal"
+ return LK_Dictionary;
+ case Stmt::BlockExprClass:
+ return LK_Block;
+ case Stmt::ObjCBoxedExprClass: {
+ Expr *Inner = cast<ObjCBoxedExpr>(FromE)->getSubExpr()->IgnoreParens();
+ switch (Inner->getStmtClass()) {
+ case Stmt::IntegerLiteralClass:
+ case Stmt::FloatingLiteralClass:
+ case Stmt::CharacterLiteralClass:
+ case Stmt::ObjCBoolLiteralExprClass:
+ case Stmt::CXXBoolLiteralExprClass:
+ // "numeric literal"
+ return LK_Numeric;
+ case Stmt::ImplicitCastExprClass: {
+ CastKind CK = cast<CastExpr>(Inner)->getCastKind();
+ // Boolean literals can be represented by implicit casts.
+ if (CK == CK_IntegralToBoolean || CK == CK_IntegralCast)
+ return LK_Numeric;
+ break;
+ }
+ default:
+ break;
+ }
+ return LK_Boxed;
+ }
+ }
+ return LK_None;
+}
+
static void diagnoseObjCLiteralComparison(Sema &S, SourceLocation Loc,
ExprResult &LHS, ExprResult &RHS,
BinaryOperator::Opcode Opc){
@@ -6866,61 +7093,15 @@ static void diagnoseObjCLiteralComparison(Sema &S, SourceLocation Loc,
return;
// This should be kept in sync with warn_objc_literal_comparison.
- // LK_String should always be last, since it has its own warning flag.
- enum {
- LK_Array,
- LK_Dictionary,
- LK_Numeric,
- LK_Boxed,
- LK_String
- } LiteralKind;
-
- Literal = Literal->IgnoreParenImpCasts();
- switch (Literal->getStmtClass()) {
- case Stmt::ObjCStringLiteralClass:
- // "string literal"
- LiteralKind = LK_String;
- break;
- case Stmt::ObjCArrayLiteralClass:
- // "array literal"
- LiteralKind = LK_Array;
- break;
- case Stmt::ObjCDictionaryLiteralClass:
- // "dictionary literal"
- LiteralKind = LK_Dictionary;
- break;
- case Stmt::ObjCBoxedExprClass: {
- Expr *Inner = cast<ObjCBoxedExpr>(Literal)->getSubExpr();
- switch (Inner->getStmtClass()) {
- case Stmt::IntegerLiteralClass:
- case Stmt::FloatingLiteralClass:
- case Stmt::CharacterLiteralClass:
- case Stmt::ObjCBoolLiteralExprClass:
- case Stmt::CXXBoolLiteralExprClass:
- // "numeric literal"
- LiteralKind = LK_Numeric;
- break;
- case Stmt::ImplicitCastExprClass: {
- CastKind CK = cast<CastExpr>(Inner)->getCastKind();
- // Boolean literals can be represented by implicit casts.
- if (CK == CK_IntegralToBoolean || CK == CK_IntegralCast) {
- LiteralKind = LK_Numeric;
- break;
- }
- // FALLTHROUGH
- }
- default:
- // "boxed expression"
- LiteralKind = LK_Boxed;
- break;
- }
- break;
- }
- default:
+ // LK_String should always be after the other literals, since it has its own
+ // warning flag.
+ Sema::ObjCLiteralKind LiteralKind = S.CheckLiteralKind(Literal);
+ assert(LiteralKind != Sema::LK_Block);
+ if (LiteralKind == Sema::LK_None) {
llvm_unreachable("Unknown Objective-C object literal kind");
}
- if (LiteralKind == LK_String)
+ if (LiteralKind == Sema::LK_String)
S.Diag(Loc, diag::warn_objc_string_literal_comparison)
<< Literal->getSourceRange();
else
@@ -6931,11 +7112,12 @@ static void diagnoseObjCLiteralComparison(Sema &S, SourceLocation Loc,
hasIsEqualMethod(S, LHS.get(), RHS.get())) {
SourceLocation Start = LHS.get()->getLocStart();
SourceLocation End = S.PP.getLocForEndOfToken(RHS.get()->getLocEnd());
- SourceRange OpRange(Loc, S.PP.getLocForEndOfToken(Loc));
+ CharSourceRange OpRange =
+ CharSourceRange::getCharRange(Loc, S.PP.getLocForEndOfToken(Loc));
S.Diag(Loc, diag::note_objc_literal_comparison_isequal)
<< FixItHint::CreateInsertion(Start, Opc == BO_EQ ? "[" : "![")
- << FixItHint::CreateReplacement(OpRange, "isEqual:")
+ << FixItHint::CreateReplacement(OpRange, " isEqual:")
<< FixItHint::CreateInsertion(End, "]");
}
}
@@ -6959,7 +7141,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
Expr *LHSStripped = LHS.get()->IgnoreParenImpCasts();
Expr *RHSStripped = RHS.get()->IgnoreParenImpCasts();
- checkEnumComparison(*this, Loc, LHS, RHS);
+ checkEnumComparison(*this, Loc, LHS.get(), RHS.get());
if (!LHSType->hasFloatingRepresentation() &&
!(LHSType->isBlockPointerType() && IsRelational) &&
@@ -7109,7 +7291,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
if ((LCanPointeeTy->isFunctionType() || RCanPointeeTy->isFunctionType())
&& !LHSIsNull && !RHSIsNull) {
diagnoseFunctionPointerToVoidComparison(
- *this, Loc, LHS, RHS, /*isError*/ isSFINAEContext());
+ *this, Loc, LHS, RHS, /*isError*/ (bool)isSFINAEContext());
if (isSFINAEContext())
return QualType();
@@ -7396,7 +7578,10 @@ QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS,
// Ensure that either both operands are of the same vector type, or
// one operand is of a vector type and the other is of its element type.
QualType vType = CheckVectorOperands(LHS, RHS, Loc, false);
- if (vType.isNull() || vType->isFloatingType())
+ if (vType.isNull())
+ return InvalidOperands(Loc, LHS, RHS);
+ if (getLangOpts().OpenCL && getLangOpts().OpenCLVersion < 120 &&
+ vType->hasFloatingRepresentation())
return InvalidOperands(Loc, LHS, RHS);
return GetSignedVectorType(LHS.get()->getType());
@@ -7472,8 +7657,17 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
RHS.get()->getLocEnd()));
}
}
-
+
if (!Context.getLangOpts().CPlusPlus) {
+ // OpenCL v1.1 s6.3.g: The logical operators and (&&), or (||) do
+ // not operate on the built-in scalar and vector float types.
+ if (Context.getLangOpts().OpenCL &&
+ Context.getLangOpts().OpenCLVersion < 120) {
+ if (LHS.get()->getType()->isFloatingType() ||
+ RHS.get()->getType()->isFloatingType())
+ return InvalidOperands(Loc, LHS, RHS);
+ }
+
LHS = UsualUnaryConversions(LHS.take());
if (LHS.isInvalid())
return QualType();
@@ -7999,7 +8193,9 @@ static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp,
if (const BuiltinType *PTy = OrigOp.get()->getType()->getAsPlaceholderType()){
if (PTy->getKind() == BuiltinType::Overload) {
if (!isa<OverloadExpr>(OrigOp.get()->IgnoreParens())) {
- S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof)
+ assert(cast<UnaryOperator>(OrigOp.get()->IgnoreParens())->getOpcode()
+ == UO_AddrOf);
+ S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof_addrof_function)
<< OrigOp.get()->getSourceRange();
return QualType();
}
@@ -8043,10 +8239,10 @@ static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp,
Expr::LValueClassification lval = op->ClassifyLValue(S.Context);
unsigned AddressOfError = AO_No_Error;
- if (lval == Expr::LV_ClassTemporary) {
- bool sfinae = S.isSFINAEContext();
- S.Diag(OpLoc, sfinae ? diag::err_typecheck_addrof_class_temporary
- : diag::ext_typecheck_addrof_class_temporary)
+ if (lval == Expr::LV_ClassTemporary || lval == Expr::LV_ArrayTemporary) {
+ bool sfinae = (bool)S.isSFINAEContext();
+ S.Diag(OpLoc, S.isSFINAEContext() ? diag::err_typecheck_addrof_temporary
+ : diag::ext_typecheck_addrof_temporary)
<< op->getType() << op->getSourceRange();
if (sfinae)
return QualType();
@@ -8094,9 +8290,8 @@ static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp,
if (isa<PseudoObjectExpr>(op)) {
AddressOfError = AO_Property_Expansion;
} else {
- // FIXME: emit more specific diag...
S.Diag(OpLoc, diag::err_typecheck_invalid_lvalue_addrof)
- << op->getSourceRange();
+ << op->getType() << op->getSourceRange();
return QualType();
}
}
@@ -8312,7 +8507,7 @@ static void DiagnoseSelfAssignment(Sema &S, Expr *LHSExpr, Expr *RHSExpr,
ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
BinaryOperatorKind Opc,
Expr *LHSExpr, Expr *RHSExpr) {
- if (getLangOpts().CPlusPlus0x && isa<InitListExpr>(RHSExpr)) {
+ if (getLangOpts().CPlusPlus11 && isa<InitListExpr>(RHSExpr)) {
// The syntax only allows initializer lists on the RHS of assignment,
// so we don't need to worry about accepting invalid code for
// non-assignment operators.
@@ -8445,6 +8640,24 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
CheckArrayAccess(LHS.get());
CheckArrayAccess(RHS.get());
+ if (const ObjCIsaExpr *OISA = dyn_cast<ObjCIsaExpr>(LHS.get()->IgnoreParenCasts())) {
+ NamedDecl *ObjectSetClass = LookupSingleName(TUScope,
+ &Context.Idents.get("object_setClass"),
+ SourceLocation(), LookupOrdinaryName);
+ if (ObjectSetClass && isa<ObjCIsaExpr>(LHS.get())) {
+ SourceLocation RHSLocEnd = PP.getLocForEndOfToken(RHS.get()->getLocEnd());
+ Diag(LHS.get()->getExprLoc(), diag::warn_objc_isa_assign) <<
+ FixItHint::CreateInsertion(LHS.get()->getLocStart(), "object_setClass(") <<
+ FixItHint::CreateReplacement(SourceRange(OISA->getOpLoc(), OpLoc), ",") <<
+ FixItHint::CreateInsertion(RHSLocEnd, ")");
+ }
+ else
+ Diag(LHS.get()->getExprLoc(), diag::warn_objc_isa_assign);
+ }
+ else if (const ObjCIvarRefExpr *OIRE =
+ dyn_cast<ObjCIvarRefExpr>(LHS.get()->IgnoreParenCasts()))
+ DiagnoseDirectIsaAccess(*this, OIRE, OpLoc, RHS.get());
+
if (CompResultTy.isNull())
return Owned(new (Context) BinaryOperator(LHS.take(), RHS.take(), Opc,
ResultTy, VK, OK, OpLoc,
@@ -8467,46 +8680,38 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperatorKind Opc,
SourceLocation OpLoc, Expr *LHSExpr,
Expr *RHSExpr) {
- typedef BinaryOperator BinOp;
- BinOp::Opcode LHSopc = static_cast<BinOp::Opcode>(-1),
- RHSopc = static_cast<BinOp::Opcode>(-1);
- if (BinOp *BO = dyn_cast<BinOp>(LHSExpr))
- LHSopc = BO->getOpcode();
- if (BinOp *BO = dyn_cast<BinOp>(RHSExpr))
- RHSopc = BO->getOpcode();
-
- // Subs are not binary operators.
- if (LHSopc == -1 && RHSopc == -1)
+ BinaryOperator *LHSBO = dyn_cast<BinaryOperator>(LHSExpr);
+ BinaryOperator *RHSBO = dyn_cast<BinaryOperator>(RHSExpr);
+
+ // Check that one of the sides is a comparison operator.
+ bool isLeftComp = LHSBO && LHSBO->isComparisonOp();
+ bool isRightComp = RHSBO && RHSBO->isComparisonOp();
+ if (!isLeftComp && !isRightComp)
return;
// Bitwise operations are sometimes used as eager logical ops.
// Don't diagnose this.
- if ((BinOp::isComparisonOp(LHSopc) || BinOp::isBitwiseOp(LHSopc)) &&
- (BinOp::isComparisonOp(RHSopc) || BinOp::isBitwiseOp(RHSopc)))
+ bool isLeftBitwise = LHSBO && LHSBO->isBitwiseOp();
+ bool isRightBitwise = RHSBO && RHSBO->isBitwiseOp();
+ if ((isLeftComp || isLeftBitwise) && (isRightComp || isRightBitwise))
return;
- bool isLeftComp = BinOp::isComparisonOp(LHSopc);
- bool isRightComp = BinOp::isComparisonOp(RHSopc);
- if (!isLeftComp && !isRightComp) return;
-
SourceRange DiagRange = isLeftComp ? SourceRange(LHSExpr->getLocStart(),
OpLoc)
: SourceRange(OpLoc, RHSExpr->getLocEnd());
- StringRef OpStr = isLeftComp ? BinOp::getOpcodeStr(LHSopc)
- : BinOp::getOpcodeStr(RHSopc);
+ StringRef OpStr = isLeftComp ? LHSBO->getOpcodeStr() : RHSBO->getOpcodeStr();
SourceRange ParensRange = isLeftComp ?
- SourceRange(cast<BinOp>(LHSExpr)->getRHS()->getLocStart(),
- RHSExpr->getLocEnd())
- : SourceRange(LHSExpr->getLocStart(),
- cast<BinOp>(RHSExpr)->getLHS()->getLocStart());
+ SourceRange(LHSBO->getRHS()->getLocStart(), RHSExpr->getLocEnd())
+ : SourceRange(LHSExpr->getLocStart(), RHSBO->getLHS()->getLocStart());
Self.Diag(OpLoc, diag::warn_precedence_bitwise_rel)
- << DiagRange << BinOp::getOpcodeStr(Opc) << OpStr;
+ << DiagRange << BinaryOperator::getOpcodeStr(Opc) << OpStr;
SuggestParentheses(Self, OpLoc,
Self.PDiag(diag::note_precedence_silence) << OpStr,
(isLeftComp ? LHSExpr : RHSExpr)->getSourceRange());
SuggestParentheses(Self, OpLoc,
- Self.PDiag(diag::note_precedence_bitwise_first) << BinOp::getOpcodeStr(Opc),
+ Self.PDiag(diag::note_precedence_bitwise_first)
+ << BinaryOperator::getOpcodeStr(Opc),
ParensRange);
}
@@ -8806,7 +9011,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
case UO_Not: // bitwise complement
Input = UsualUnaryConversions(Input.take());
- if (Input.isInvalid()) return ExprError();
+ if (Input.isInvalid())
+ return ExprError();
resultType = Input.get()->getType();
if (resultType->isDependentType())
break;
@@ -8814,12 +9020,22 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
if (resultType->isComplexType() || resultType->isComplexIntegerType())
// C99 does not support '~' for complex conjugation.
Diag(OpLoc, diag::ext_integer_complement_complex)
- << resultType << Input.get()->getSourceRange();
+ << resultType << Input.get()->getSourceRange();
else if (resultType->hasIntegerRepresentation())
break;
- else {
+ else if (resultType->isExtVectorType()) {
+ if (Context.getLangOpts().OpenCL) {
+ // OpenCL v1.1 s6.3.f: The bitwise operator not (~) does not operate
+ // on vector float types.
+ QualType T = resultType->getAs<ExtVectorType>()->getElementType();
+ if (!T->isIntegerType())
+ return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
+ << resultType << Input.get()->getSourceRange());
+ }
+ break;
+ } else {
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
- << resultType << Input.get()->getSourceRange());
+ << resultType << Input.get()->getSourceRange());
}
break;
@@ -8830,7 +9046,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
resultType = Input.get()->getType();
// Though we still have to promote half FP to float...
- if (resultType->isHalfType()) {
+ if (resultType->isHalfType() && !Context.getLangOpts().NativeHalfType) {
Input = ImpCastExprToType(Input.take(), Context.FloatTy, CK_FloatingCast).take();
resultType = Context.FloatTy;
}
@@ -8844,8 +9060,24 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
// operand contextually converted to bool.
Input = ImpCastExprToType(Input.take(), Context.BoolTy,
ScalarTypeToBooleanCastKind(resultType));
+ } else if (Context.getLangOpts().OpenCL &&
+ Context.getLangOpts().OpenCLVersion < 120) {
+ // OpenCL v1.1 6.3.h: The logical operator not (!) does not
+ // operate on scalar float types.
+ if (!resultType->isIntegerType())
+ return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
+ << resultType << Input.get()->getSourceRange());
}
} else if (resultType->isExtVectorType()) {
+ if (Context.getLangOpts().OpenCL &&
+ Context.getLangOpts().OpenCLVersion < 120) {
+ // OpenCL v1.1 6.3.h: The logical operator not (!) does not
+ // operate on vector float types.
+ QualType T = resultType->getAs<ExtVectorType>()->getElementType();
+ if (!T->isIntegerType())
+ return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
+ << resultType << Input.get()->getSourceRange());
+ }
// Vector logical not returns the signed variant of the operand type.
resultType = GetSignedVectorType(resultType);
break;
@@ -9210,9 +9442,9 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
// If type is not a standard-layout class (Clause 9), the results are
// undefined.
if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
- bool IsSafe = LangOpts.CPlusPlus0x? CRD->isStandardLayout() : CRD->isPOD();
+ bool IsSafe = LangOpts.CPlusPlus11? CRD->isStandardLayout() : CRD->isPOD();
unsigned DiagID =
- LangOpts.CPlusPlus0x? diag::warn_offsetof_non_standardlayout_type
+ LangOpts.CPlusPlus11? diag::warn_offsetof_non_standardlayout_type
: diag::warn_offsetof_non_pod_type;
if (!IsSafe && !DidWarnAboutNonPOD &&
@@ -9379,8 +9611,7 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
FunctionProtoType::ExtProtoInfo EPI;
EPI.HasTrailingReturn = false;
EPI.TypeQuals |= DeclSpec::TQ_const;
- T = Context.getFunctionType(Context.DependentTy, /*Args=*/0, /*NumArgs=*/0,
- EPI);
+ T = Context.getFunctionType(Context.DependentTy, ArrayRef<QualType>(), EPI);
Sig = Context.getTrivialTypeSourceInfo(T);
}
@@ -9394,8 +9625,7 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
FunctionProtoTypeLoc ExplicitSignature;
TypeLoc tmp = Sig->getTypeLoc().IgnoreParens();
- if (isa<FunctionProtoTypeLoc>(tmp)) {
- ExplicitSignature = cast<FunctionProtoTypeLoc>(tmp);
+ if ((ExplicitSignature = tmp.getAs<FunctionProtoTypeLoc>())) {
// Check whether that explicit signature was synthesized by
// GetTypeForDeclarator. If so, don't save that as part of the
@@ -9560,7 +9790,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
if (isa<FunctionNoProtoType>(FTy)) {
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExtInfo = Ext;
- BlockTy = Context.getFunctionType(RetTy, 0, 0, EPI);
+ BlockTy = Context.getFunctionType(RetTy, ArrayRef<QualType>(), EPI);
// Otherwise, if we don't need to change anything about the function type,
// preserve its sugar structure.
@@ -9574,17 +9804,18 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.TypeQuals = 0; // FIXME: silently?
EPI.ExtInfo = Ext;
- BlockTy = Context.getFunctionType(RetTy,
- FPT->arg_type_begin(),
- FPT->getNumArgs(),
- EPI);
+ BlockTy =
+ Context.getFunctionType(RetTy,
+ ArrayRef<QualType>(FPT->arg_type_begin(),
+ FPT->getNumArgs()),
+ EPI);
}
// If we don't have a function type, just build one from nothing.
} else {
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExtInfo = FunctionType::ExtInfo().withNoReturn(NoReturn);
- BlockTy = Context.getFunctionType(RetTy, 0, 0, EPI);
+ BlockTy = Context.getFunctionType(RetTy, ArrayRef<QualType>(), EPI);
}
DiagnoseUnusedParameters(BSI->TheDecl->param_begin(),
@@ -9715,11 +9946,11 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc,
if (TInfo->getType()->isSpecificBuiltinType(BuiltinType::Float))
PromoteType = Context.DoubleTy;
if (!PromoteType.isNull())
- Diag(TInfo->getTypeLoc().getBeginLoc(),
- diag::warn_second_parameter_to_va_arg_never_compatible)
- << TInfo->getType()
- << PromoteType
- << TInfo->getTypeLoc().getSourceRange();
+ DiagRuntimeBehavior(TInfo->getTypeLoc().getBeginLoc(), E,
+ PDiag(diag::warn_second_parameter_to_va_arg_never_compatible)
+ << TInfo->getType()
+ << PromoteType
+ << TInfo->getTypeLoc().getSourceRange());
}
QualType T = TInfo->getType().getNonLValueExprType(Context);
@@ -9932,6 +10163,9 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
if (CheckInferredResultType)
EmitRelatedResultTypeNote(SrcExpr);
+
+ if (Action == AA_Returning && ConvTy == IncompatiblePointer)
+ EmitRelatedResultTypeNoteForReturn(DstType);
if (Complained)
*Complained = true;
@@ -9980,7 +10214,7 @@ Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
bool AllowFold) {
SourceLocation DiagLoc = E->getLocStart();
- if (getLangOpts().CPlusPlus0x) {
+ if (getLangOpts().CPlusPlus11) {
// C++11 [expr.const]p5:
// If an expression of literal class type is used in a context where an
// integral constant expression is required, then that class type shall
@@ -10107,14 +10341,14 @@ Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
// Circumvent ICE checking in C++11 to avoid evaluating the expression twice
// in the non-ICE case.
- if (!getLangOpts().CPlusPlus0x && E->isIntegerConstantExpr(Context)) {
+ if (!getLangOpts().CPlusPlus11 && E->isIntegerConstantExpr(Context)) {
if (Result)
*Result = E->EvaluateKnownConstInt(Context);
return Owned(E);
}
Expr::EvalResult EvalResult;
- llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ SmallVector<PartialDiagnosticAt, 8> Notes;
EvalResult.Diag = &Notes;
// Try to evaluate the expression, and produce diagnostics explaining why it's
@@ -10125,7 +10359,7 @@ Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
// In C++11, we can rely on diagnostics being produced for any expression
// which is not a constant expression. If no diagnostics were produced, then
// this is a constant expression.
- if (Folded && getLangOpts().CPlusPlus0x && Notes.empty()) {
+ if (Folded && getLangOpts().CPlusPlus11 && Notes.empty()) {
if (Result)
*Result = EvalResult.Val.getInt();
return Owned(E);
@@ -10211,7 +10445,7 @@ namespace {
};
}
-ExprResult Sema::TranformToPotentiallyEvaluated(Expr *E) {
+ExprResult Sema::TransformToPotentiallyEvaluated(Expr *E) {
assert(ExprEvalContexts.back().Context == Unevaluated &&
"Should only transform unevaluated expressions");
ExprEvalContexts.back().Context =
@@ -10302,7 +10536,7 @@ void Sema::DiscardCleanupsInEvaluationContext() {
ExprResult Sema::HandleExprEvaluationContextForTypeof(Expr *E) {
if (!E->getType()->isVariablyModifiedType())
return E;
- return TranformToPotentiallyEvaluated(E);
+ return TransformToPotentiallyEvaluated(E);
}
static bool IsPotentiallyEvaluatedContext(Sema &SemaRef) {
@@ -10395,6 +10629,9 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
if (!Constructor->isUsed(false))
DefineImplicitMoveConstructor(Loc, Constructor);
}
+ } else if (Constructor->getInheritedConstructor()) {
+ if (!Constructor->isUsed(false))
+ DefineInheritingConstructor(Loc, Constructor);
}
MarkVTableUsed(Loc, Constructor->getParent());
@@ -10488,13 +10725,26 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) {
}
// Keep track of used but undefined functions.
- if (!Func->isPure() && !Func->hasBody() &&
- Func->getLinkage() != ExternalLinkage) {
- SourceLocation &old = UndefinedInternals[Func->getCanonicalDecl()];
- if (old.isInvalid()) old = Loc;
+ if (!Func->isDefined()) {
+ if (mightHaveNonExternalLinkage(Func))
+ UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc));
+ else if (Func->getMostRecentDecl()->isInlined() &&
+ (LangOpts.CPlusPlus || !LangOpts.GNUInline) &&
+ !Func->getMostRecentDecl()->hasAttr<GNUInlineAttr>())
+ UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc));
+ }
+
+ // Normally the must current decl is marked used while processing the use and
+ // any subsequent decls are marked used by decl merging. This fails with
+ // template instantiation since marking can happen at the end of the file
+ // and, because of the two phase lookup, this function is called with at
+ // decl in the middle of a decl chain. We loop to maintain the invariant
+ // that once a decl is used, all decls after it are also used.
+ for (FunctionDecl *F = Func->getMostRecentDecl();; F = F->getPreviousDecl()) {
+ F->setUsed(true);
+ if (F == Func)
+ break;
}
-
- Func->setUsed(true);
}
static void
@@ -10572,7 +10822,7 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI,
// Introduce a new evaluation context for the initialization, so
// that temporaries introduced as part of the capture are retained
// to be re-"exported" from the lambda expression itself.
- S.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated);
+ EnterExpressionEvaluationContext scope(S, Sema::PotentiallyEvaluated);
// C++ [expr.prim.labda]p12:
// An entity captured by a lambda-expression is odr-used (3.2) in
@@ -10604,7 +10854,7 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI,
= VarDecl::Create(S.Context, S.CurContext, Loc, Loc,
IterationVarName, SizeType,
S.Context.getTrivialTypeSourceInfo(SizeType, Loc),
- SC_None, SC_None);
+ SC_None);
IndexVariables.push_back(IterationVar);
LSI->ArrayIndexVars.push_back(IterationVar);
@@ -10623,7 +10873,6 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI,
if (Subscript.isInvalid()) {
S.CleanupVarDeclMarking();
S.DiscardCleanupsInEvaluationContext();
- S.PopExpressionEvaluationContext();
return ExprError();
}
@@ -10659,7 +10908,6 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI,
// Exit the expression evaluation context used for the capture.
S.CleanupVarDeclMarking();
S.DiscardCleanupsInEvaluationContext();
- S.PopExpressionEvaluationContext();
return Result;
}
@@ -10748,7 +10996,22 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
}
return true;
}
-
+ // Prohibit structs with flexible array members too.
+ // We cannot capture what is in the tail end of the struct.
+ if (const RecordType *VTTy = Var->getType()->getAs<RecordType>()) {
+ if (VTTy->getDecl()->hasFlexibleArrayMember()) {
+ if (BuildAndDiagnose) {
+ if (IsBlock)
+ Diag(Loc, diag::err_ref_flexarray_type);
+ else
+ Diag(Loc, diag::err_lambda_capture_flexarray_type)
+ << Var->getDeclName();
+ Diag(Var->getLocation(), diag::note_previous_decl)
+ << Var->getDeclName();
+ }
+ return true;
+ }
+ }
// Lambdas are not allowed to capture __block variables; they don't
// support the expected semantics.
if (IsLambda && HasBlocksAttr) {
@@ -10830,13 +11093,18 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
// actually requires the destructor.
if (isa<ParmVarDecl>(Var))
FinalizeVarWithDestructor(Var, Record);
-
+
+ // Enter a new evaluation context to insulate the copy
+ // full-expression.
+ EnterExpressionEvaluationContext scope(*this, PotentiallyEvaluated);
+
// According to the blocks spec, the capture of a variable from
// the stack requires a const copy constructor. This is not true
// of the copy/move done to move a __block variable to the heap.
- Expr *DeclRef = new (Context) DeclRefExpr(Var, false,
+ Expr *DeclRef = new (Context) DeclRefExpr(Var, Nested,
DeclRefType.withConst(),
VK_LValue, Loc);
+
ExprResult Result
= PerformCopyInitialization(
InitializedEntity::InitializeBlock(Var->getLocation(),
@@ -10921,7 +11189,7 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc,
if (BuildAndDiagnose) {
ExprResult Result = captureInLambda(*this, LSI, Var, CaptureType,
DeclRefType, Loc,
- I == N-1);
+ Nested);
if (!Result.isInvalid())
CopyExpr = Result.take();
}
@@ -10978,7 +11246,7 @@ static void MarkVarDeclODRUsed(Sema &SemaRef, VarDecl *Var,
if (Var->hasDefinition(SemaRef.Context) == VarDecl::DeclarationOnly &&
Var->getLinkage() != ExternalLinkage &&
!(Var->isStaticDataMember() && Var->hasInit())) {
- SourceLocation &old = SemaRef.UndefinedInternals[Var->getCanonicalDecl()];
+ SourceLocation &old = SemaRef.UndefinedButUsed[Var->getCanonicalDecl()];
if (old.isInvalid()) old = Loc;
}
@@ -11090,13 +11358,13 @@ void Sema::MarkVariableReferenced(SourceLocation Loc, VarDecl *Var) {
}
static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc,
- Decl *D, Expr *E) {
+ Decl *D, Expr *E, bool OdrUse) {
if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
DoMarkVarDeclReferenced(SemaRef, Loc, Var, E);
return;
}
- SemaRef.MarkAnyDeclReferenced(Loc, D);
+ SemaRef.MarkAnyDeclReferenced(Loc, D, OdrUse);
// If this is a call to a method via a cast, also mark the method in the
// derived class used in case codegen can devirtualize the call.
@@ -11111,32 +11379,58 @@ static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc,
if (!MostDerivedClassDecl)
return;
CXXMethodDecl *DM = MD->getCorrespondingMethodInClass(MostDerivedClassDecl);
- if (!DM)
+ if (!DM || DM->isPure())
return;
- SemaRef.MarkAnyDeclReferenced(Loc, DM);
+ SemaRef.MarkAnyDeclReferenced(Loc, DM, OdrUse);
}
/// \brief Perform reference-marking and odr-use handling for a DeclRefExpr.
void Sema::MarkDeclRefReferenced(DeclRefExpr *E) {
- MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E);
+ // TODO: update this with DR# once a defect report is filed.
+ // C++11 defect. The address of a pure member should not be an ODR use, even
+ // if it's a qualified reference.
+ bool OdrUse = true;
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(E->getDecl()))
+ if (Method->isVirtual())
+ OdrUse = false;
+ MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse);
}
/// \brief Perform reference-marking and odr-use handling for a MemberExpr.
void Sema::MarkMemberReferenced(MemberExpr *E) {
- MarkExprReferenced(*this, E->getMemberLoc(), E->getMemberDecl(), E);
+ // C++11 [basic.def.odr]p2:
+ // A non-overloaded function whose name appears as a potentially-evaluated
+ // expression or a member of a set of candidate functions, if selected by
+ // overload resolution when referred to from a potentially-evaluated
+ // expression, is odr-used, unless it is a pure virtual function and its
+ // name is not explicitly qualified.
+ bool OdrUse = true;
+ if (!E->hasQualifier()) {
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(E->getMemberDecl()))
+ if (Method->isPure())
+ OdrUse = false;
+ }
+ SourceLocation Loc = E->getMemberLoc().isValid() ?
+ E->getMemberLoc() : E->getLocStart();
+ MarkExprReferenced(*this, Loc, E->getMemberDecl(), E, OdrUse);
}
/// \brief Perform marking for a reference to an arbitrary declaration. It
/// marks the declaration referenced, and performs odr-use checking for functions
/// and variables. This method should not be used when building an normal
/// expression which refers to a variable.
-void Sema::MarkAnyDeclReferenced(SourceLocation Loc, Decl *D) {
- if (VarDecl *VD = dyn_cast<VarDecl>(D))
- MarkVariableReferenced(Loc, VD);
- else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- MarkFunctionReferenced(Loc, FD);
- else
- D->setReferenced();
+void Sema::MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, bool OdrUse) {
+ if (OdrUse) {
+ if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ MarkVariableReferenced(Loc, VD);
+ return;
+ }
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ MarkFunctionReferenced(Loc, FD);
+ return;
+ }
+ }
+ D->setReferenced();
}
namespace {
@@ -11161,7 +11455,7 @@ bool MarkReferencedDecls::TraverseTemplateArgument(
const TemplateArgument &Arg) {
if (Arg.getKind() == TemplateArgument::Declaration) {
if (Decl *D = Arg.getAsDecl())
- S.MarkAnyDeclReferenced(Loc, D);
+ S.MarkAnyDeclReferenced(Loc, D, true);
}
return Inherited::TraverseTemplateArgument(Arg);
@@ -11685,10 +11979,11 @@ ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *E) {
// Rebuild the function type, replacing the result type with DestType.
if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FnType))
- DestType = S.Context.getFunctionType(DestType,
- Proto->arg_type_begin(),
- Proto->getNumArgs(),
- Proto->getExtProtoInfo());
+ DestType =
+ S.Context.getFunctionType(DestType,
+ ArrayRef<QualType>(Proto->arg_type_begin(),
+ Proto->getNumArgs()),
+ Proto->getExtProtoInfo());
else
DestType = S.Context.getFunctionNoProtoType(DestType,
FnType->getExtInfo());
@@ -11850,6 +12145,29 @@ ExprResult Sema::forceUnknownAnyToType(Expr *E, QualType ToType) {
return RebuildUnknownAnyExpr(*this, ToType).Visit(E);
}
+ExprResult Sema::checkUnknownAnyArg(SourceLocation callLoc,
+ Expr *arg, QualType &paramType) {
+ // If the syntactic form of the argument is not an explicit cast of
+ // any sort, just do default argument promotion.
+ ExplicitCastExpr *castArg = dyn_cast<ExplicitCastExpr>(arg->IgnoreParens());
+ if (!castArg) {
+ ExprResult result = DefaultArgumentPromotion(arg);
+ if (result.isInvalid()) return ExprError();
+ paramType = result.get()->getType();
+ return result;
+ }
+
+ // Otherwise, use the type that was written in the explicit cast.
+ assert(!arg->hasPlaceholderType());
+ paramType = castArg->getTypeAsWritten();
+
+ // Copy-initialize a parameter of that type.
+ InitializedEntity entity =
+ InitializedEntity::InitializeParameter(Context, paramType,
+ /*consumed*/ false);
+ return PerformCopyInitialization(entity, callLoc, Owned(arg));
+}
+
static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *E) {
Expr *orig = E;
unsigned diagID = diag::err_uncasted_use_of_unknown_any;
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 0919bc5..3f2cb02 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -13,30 +13,68 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/DeclSpec.h"
-#include "clang/Sema/Initialization.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/ParsedTemplate.h"
-#include "clang/Sema/ScopeInfo.h"
-#include "clang/Sema/Scope.h"
-#include "clang/Sema/TemplateDeduction.h"
+#include "TypeLocBuilder.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/CharUnits.h"
#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
-#include "TypeLocBuilder.h"
+#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/Initialization.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/ParsedTemplate.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/TemplateDeduction.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
using namespace sema;
+/// \brief Handle the result of the special case name lookup for inheriting
+/// constructor declarations. 'NS::X::X' and 'NS::X<...>::X' are treated as
+/// constructor names in member using declarations, even if 'X' is not the
+/// name of the corresponding type.
+ParsedType Sema::getInheritingConstructorName(CXXScopeSpec &SS,
+ SourceLocation NameLoc,
+ IdentifierInfo &Name) {
+ NestedNameSpecifier *NNS = SS.getScopeRep();
+
+ // Convert the nested-name-specifier into a type.
+ QualType Type;
+ switch (NNS->getKind()) {
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ Type = QualType(NNS->getAsType(), 0);
+ break;
+
+ case NestedNameSpecifier::Identifier:
+ // Strip off the last layer of the nested-name-specifier and build a
+ // typename type for it.
+ assert(NNS->getAsIdentifier() == &Name && "not a constructor name");
+ Type = Context.getDependentNameType(ETK_None, NNS->getPrefix(),
+ NNS->getAsIdentifier());
+ break;
+
+ case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Namespace:
+ case NestedNameSpecifier::NamespaceAlias:
+ llvm_unreachable("Nested name specifier is not a type for inheriting ctor");
+ }
+
+ // This reference to the type is located entirely at the location of the
+ // final identifier in the qualified-id.
+ return CreateParsedType(Type,
+ Context.getTrivialTypeSourceInfo(Type, NameLoc));
+}
+
ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
IdentifierInfo &II,
SourceLocation NameLoc,
@@ -263,8 +301,16 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
} else if (ObjectTypePtr)
Diag(NameLoc, diag::err_ident_in_dtor_not_a_type)
<< &II;
- else
- Diag(NameLoc, diag::err_destructor_class_name);
+ else {
+ SemaDiagnosticBuilder DtorDiag = Diag(NameLoc,
+ diag::err_destructor_class_name);
+ if (S) {
+ const DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity());
+ if (const CXXRecordDecl *Class = dyn_cast_or_null<CXXRecordDecl>(Ctx))
+ DtorDiag << FixItHint::CreateReplacement(SourceRange(NameLoc),
+ Class->getNameAsString());
+ }
+ }
return ParsedType();
}
@@ -336,7 +382,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
if (RecordD->isPolymorphic() && E->isGLValue()) {
// The subexpression is potentially evaluated; switch the context
// and recheck the subexpression.
- ExprResult Result = TranformToPotentiallyEvaluated(E);
+ ExprResult Result = TransformToPotentiallyEvaluated(E);
if (Result.isInvalid()) return ExprError();
E = Result.take();
@@ -1041,13 +1087,6 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
} else if (Initializer && isa<InitListExpr>(Initializer))
initStyle = CXXNewExpr::ListInit;
else {
- // In template instantiation, the initializer could be a CXXDefaultArgExpr
- // unwrapped from a CXXConstructExpr that was implicitly built. There is no
- // particularly sane way we can handle this (especially since it can even
- // occur for array new), so we throw the initializer away and have it be
- // rebuilt.
- if (Initializer && isa<CXXDefaultArgExpr>(Initializer))
- Initializer = 0;
assert((!Initializer || isa<ImplicitValueInitExpr>(Initializer) ||
isa<CXXConstructExpr>(Initializer)) &&
"Initializer expression that cannot have been implicitly created.");
@@ -1056,20 +1095,20 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
Expr **Inits = &Initializer;
unsigned NumInits = Initializer ? 1 : 0;
- if (initStyle == CXXNewExpr::CallInit) {
- if (ParenListExpr *List = dyn_cast<ParenListExpr>(Initializer)) {
- Inits = List->getExprs();
- NumInits = List->getNumExprs();
- } else if (CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Initializer)){
- if (!isa<CXXTemporaryObjectExpr>(CCE)) {
- // Can happen in template instantiation. Since this is just an implicit
- // construction, we just take it apart and rebuild it.
- Inits = CCE->getArgs();
- NumInits = CCE->getNumArgs();
- }
- }
+ if (ParenListExpr *List = dyn_cast_or_null<ParenListExpr>(Initializer)) {
+ assert(initStyle == CXXNewExpr::CallInit && "paren init for non-call init");
+ Inits = List->getExprs();
+ NumInits = List->getNumExprs();
}
+ // Determine whether we've already built the initializer.
+ bool HaveCompleteInit = false;
+ if (Initializer && isa<CXXConstructExpr>(Initializer) &&
+ !isa<CXXTemporaryObjectExpr>(Initializer))
+ HaveCompleteInit = true;
+ else if (Initializer && isa<ImplicitValueInitExpr>(Initializer))
+ HaveCompleteInit = true;
+
// C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
AutoType *AT = 0;
if (TypeMayContainAuto &&
@@ -1147,7 +1186,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
virtual DiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc,
QualType T) {
return S.Diag(Loc, diag::err_array_size_not_integral)
- << S.getLangOpts().CPlusPlus0x << T;
+ << S.getLangOpts().CPlusPlus11 << T;
}
virtual DiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc,
@@ -1185,7 +1224,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
QualType T,
QualType ConvTy) {
return S.Diag(Loc,
- S.getLangOpts().CPlusPlus0x
+ S.getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_array_size_conversion
: diag::ext_array_size_conversion)
<< T << ConvTy->isEnumeralType() << ConvTy;
@@ -1221,7 +1260,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
if (Value < llvm::APSInt(
llvm::APInt::getNullValue(Value.getBitWidth()),
Value.isUnsigned())) {
- if (getLangOpts().CPlusPlus0x)
+ if (getLangOpts().CPlusPlus11)
Diag(ArraySize->getLocStart(),
diag::warn_typecheck_negative_array_new_size)
<< ArraySize->getSourceRange();
@@ -1233,7 +1272,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
unsigned ActiveSizeBits =
ConstantArrayType::getNumAddressingBits(Context, AllocType, Value);
if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) {
- if (getLangOpts().CPlusPlus0x)
+ if (getLangOpts().CPlusPlus11)
Diag(ArraySize->getLocStart(),
diag::warn_array_new_too_large)
<< Value.toString(10)
@@ -1341,9 +1380,12 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
}
}
+ // If we can perform the initialization, and we've not already done so,
+ // do it now.
if (!AllocType->isDependentType() &&
!Expr::hasAnyTypeDependentArguments(
- llvm::makeArrayRef(Inits, NumInits))) {
+ llvm::makeArrayRef(Inits, NumInits)) &&
+ !HaveCompleteInit) {
// C++11 [expr.new]p15:
// A new-expression that creates an object of type T initializes that
// object as follows:
@@ -1379,10 +1421,14 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
}
// Mark the new and delete operators as referenced.
- if (OperatorNew)
+ if (OperatorNew) {
+ DiagnoseUseOfDecl(OperatorNew, StartLoc);
MarkFunctionReferenced(StartLoc, OperatorNew);
- if (OperatorDelete)
+ }
+ if (OperatorDelete) {
+ DiagnoseUseOfDecl(OperatorDelete, StartLoc);
MarkFunctionReferenced(StartLoc, OperatorDelete);
+ }
// C++0x [expr.new]p17:
// If the new expression creates an array of objects of class type,
@@ -1594,8 +1640,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
EPI.Variadic = Proto->isVariadic();
ExpectedFunctionType
- = Context.getFunctionType(Context.VoidTy, ArgTypes.data(),
- ArgTypes.size(), EPI);
+ = Context.getFunctionType(Context.VoidTy, ArgTypes, EPI);
}
for (LookupResult::iterator D = FoundDelete.begin(),
@@ -1641,7 +1686,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
// as a placement deallocation function, would have been
// selected as a match for the allocation function, the program
// is ill-formed.
- if (NumPlaceArgs && getLangOpts().CPlusPlus0x &&
+ if (NumPlaceArgs && getLangOpts().CPlusPlus11 &&
isNonPlacementDeallocationFunction(OperatorDelete)) {
Diag(StartLoc, diag::err_placement_new_non_placement_delete)
<< SourceRange(PlaceArgs[0]->getLocStart(),
@@ -1817,7 +1862,7 @@ void Sema::DeclareGlobalNewDelete() {
// lookup.
// Note that the C++0x versions of operator delete are deallocation functions,
// and thus are implicitly noexcept.
- if (!StdBadAlloc && !getLangOpts().CPlusPlus0x) {
+ if (!StdBadAlloc && !getLangOpts().CPlusPlus11) {
// The "std::bad_alloc" class has not yet been declared, so build it
// implicitly.
StdBadAlloc = CXXRecordDecl::Create(Context, TTK_Class,
@@ -1857,8 +1902,8 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
// Check if this function is already declared.
{
- DeclContext::lookup_iterator Alloc, AllocEnd;
- for (llvm::tie(Alloc, AllocEnd) = GlobalCtx->lookup(Name);
+ DeclContext::lookup_result R = GlobalCtx->lookup(Name);
+ for (DeclContext::lookup_iterator Alloc = R.begin(), AllocEnd = R.end();
Alloc != AllocEnd; ++Alloc) {
// Only look at non-template functions, as it is the predefined,
// non-templated allocation function we are trying to declare here.
@@ -1880,29 +1925,28 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
bool HasBadAllocExceptionSpec
= (Name.getCXXOverloadedOperator() == OO_New ||
Name.getCXXOverloadedOperator() == OO_Array_New);
- if (HasBadAllocExceptionSpec && !getLangOpts().CPlusPlus0x) {
+ if (HasBadAllocExceptionSpec && !getLangOpts().CPlusPlus11) {
assert(StdBadAlloc && "Must have std::bad_alloc declared");
BadAllocType = Context.getTypeDeclType(getStdBadAlloc());
}
FunctionProtoType::ExtProtoInfo EPI;
if (HasBadAllocExceptionSpec) {
- if (!getLangOpts().CPlusPlus0x) {
+ if (!getLangOpts().CPlusPlus11) {
EPI.ExceptionSpecType = EST_Dynamic;
EPI.NumExceptions = 1;
EPI.Exceptions = &BadAllocType;
}
} else {
- EPI.ExceptionSpecType = getLangOpts().CPlusPlus0x ?
+ EPI.ExceptionSpecType = getLangOpts().CPlusPlus11 ?
EST_BasicNoexcept : EST_DynamicNone;
}
- QualType FnType = Context.getFunctionType(Return, &Argument, 1, EPI);
+ QualType FnType = Context.getFunctionType(Return, Argument, EPI);
FunctionDecl *Alloc =
FunctionDecl::Create(Context, GlobalCtx, SourceLocation(),
SourceLocation(), Name,
- FnType, /*TInfo=*/0, SC_None,
- SC_None, false, true);
+ FnType, /*TInfo=*/0, SC_None, false, true);
Alloc->setImplicit();
if (AddMallocAttr)
@@ -1911,7 +1955,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(),
SourceLocation(), 0,
Argument, /*TInfo=*/0,
- SC_None, SC_None, 0);
+ SC_None, 0);
Alloc->setParams(Param);
// FIXME: Also add this declaration to the IdentifierResolver, but
@@ -2030,6 +2074,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
if (!Ex.get()->isTypeDependent()) {
// Perform lvalue-to-rvalue cast, if needed.
Ex = DefaultLvalueConversion(Ex.take());
+ if (Ex.isInvalid())
+ return ExprError();
QualType Type = Ex.get()->getType();
@@ -2041,9 +2087,11 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
SmallVector<CXXConversionDecl*, 4> ObjectPtrConversions;
CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
- const UnresolvedSetImpl *Conversions = RD->getVisibleConversionFunctions();
- for (UnresolvedSetImpl::iterator I = Conversions->begin(),
- E = Conversions->end(); I != E; ++I) {
+ std::pair<CXXRecordDecl::conversion_iterator,
+ CXXRecordDecl::conversion_iterator>
+ Conversions = RD->getVisibleConversionFunctions();
+ for (CXXRecordDecl::conversion_iterator
+ I = Conversions.first, E = Conversions.second; I != E; ++I) {
NamedDecl *D = I.getDecl();
if (isa<UsingShadowDecl>(D))
D = cast<UsingShadowDecl>(D)->getTargetDecl();
@@ -2323,11 +2371,11 @@ static ExprResult BuildCXXCastArgument(Sema &S,
S.CheckConstructorAccess(CastLoc, Constructor,
InitializedEntity::InitializeTemporary(Ty),
Constructor->getAccess());
-
+
ExprResult Result
= S.BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method),
- ConstructorArgs,
- HadMultipleCandidates, /*ZeroInit*/ false,
+ ConstructorArgs, HadMultipleCandidates,
+ /*ListInit*/ false, /*ZeroInit*/ false,
CXXConstructExpr::CK_Complete, SourceRange());
if (Result.isInvalid())
return ExprError();
@@ -2479,14 +2527,14 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
ToType, SCS.CopyConstructor,
ConstructorArgs,
/*HadMultipleCandidates*/ false,
- /*ZeroInit*/ false,
+ /*ListInit*/ false, /*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
SourceRange());
}
return BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(),
ToType, SCS.CopyConstructor,
From, /*HadMultipleCandidates*/ false,
- /*ZeroInit*/ false,
+ /*ListInit*/ false, /*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
SourceRange());
}
@@ -2782,6 +2830,12 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
break;
}
+ case ICK_Zero_Event_Conversion:
+ From = ImpCastExprToType(From, ToType,
+ CK_ZeroToOCLEvent,
+ From->getValueKind()).take();
+ break;
+
case ICK_Lvalue_To_Rvalue:
case ICK_Array_To_Pointer:
case ICK_Function_To_Pointer:
@@ -2920,10 +2974,13 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S,
// type due to the overarching C++0x type predicates being implemented
// requiring the complete type.
case UTT_HasNothrowAssign:
+ case UTT_HasNothrowMoveAssign:
case UTT_HasNothrowConstructor:
case UTT_HasNothrowCopy:
case UTT_HasTrivialAssign:
+ case UTT_HasTrivialMoveAssign:
case UTT_HasTrivialDefaultConstructor:
+ case UTT_HasTrivialMoveConstructor:
case UTT_HasTrivialCopy:
case UTT_HasTrivialDestructor:
case UTT_HasVirtualDestructor:
@@ -2942,6 +2999,42 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S,
llvm_unreachable("Type trait not handled by switch");
}
+static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op,
+ Sema &Self, SourceLocation KeyLoc, ASTContext &C,
+ bool (CXXRecordDecl::*HasTrivial)() const,
+ bool (CXXRecordDecl::*HasNonTrivial)() const,
+ bool (CXXMethodDecl::*IsDesiredOp)() const)
+{
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ if ((RD->*HasTrivial)() && !(RD->*HasNonTrivial)())
+ return true;
+
+ DeclarationName Name = C.DeclarationNames.getCXXOperatorName(Op);
+ DeclarationNameInfo NameInfo(Name, KeyLoc);
+ LookupResult Res(Self, NameInfo, Sema::LookupOrdinaryName);
+ if (Self.LookupQualifiedName(Res, RD)) {
+ bool FoundOperator = false;
+ Res.suppressDiagnostics();
+ for (LookupResult::iterator Op = Res.begin(), OpEnd = Res.end();
+ Op != OpEnd; ++Op) {
+ if (isa<FunctionTemplateDecl>(*Op))
+ continue;
+
+ CXXMethodDecl *Operator = cast<CXXMethodDecl>(*Op);
+ if((Operator->*IsDesiredOp)()) {
+ FoundOperator = true;
+ const FunctionProtoType *CPT =
+ Operator->getType()->getAs<FunctionProtoType>();
+ CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
+ if (!CPT || !CPT->isNothrow(Self.Context))
+ return false;
+ }
+ }
+ return FoundOperator;
+ }
+ return false;
+}
+
static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
SourceLocation KeyLoc, QualType T) {
assert(!T->isDependentType() && "Cannot evaluate traits of dependent type");
@@ -3060,6 +3153,13 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
//
// 1: http://gcc.gnu/.org/onlinedocs/gcc/Type-Traits.html
// 2: http://docwiki.embarcadero.com/RADStudio/XE/en/Type_Trait_Functions_(C%2B%2B0x)_Index
+ //
+ // Note that these builtins do not behave as documented in g++: if a class
+ // has both a trivial and a non-trivial special member of a particular kind,
+ // they return false! For now, we emulate this behavior.
+ // FIXME: This appears to be a g++ bug: more complex cases reveal that it
+ // does not correctly compute triviality in the presence of multiple special
+ // members of the same kind. Revisit this once the g++ bug is fixed.
case UTT_HasTrivialDefaultConstructor:
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
// If __is_pod (type) is true then the trait is true, else if type is
@@ -3067,9 +3167,18 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
// constructor ([class.ctor]) then the trait is true, else it is false.
if (T.isPODType(Self.Context))
return true;
- if (const RecordType *RT =
- C.getBaseElementType(T)->getAs<RecordType>())
- return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDefaultConstructor();
+ if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl())
+ return RD->hasTrivialDefaultConstructor() &&
+ !RD->hasNonTrivialDefaultConstructor();
+ return false;
+ case UTT_HasTrivialMoveConstructor:
+ // This trait is implemented by MSVC 2012 and needed to parse the
+ // standard library headers. Specifically this is used as the logic
+ // behind std::is_trivially_move_constructible (20.9.4.3).
+ if (T.isPODType(Self.Context))
+ return true;
+ if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl())
+ return RD->hasTrivialMoveConstructor() && !RD->hasNonTrivialMoveConstructor();
return false;
case UTT_HasTrivialCopy:
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
@@ -3079,8 +3188,18 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
// is true, else it is false.
if (T.isPODType(Self.Context) || T->isReferenceType())
return true;
- if (const RecordType *RT = T->getAs<RecordType>())
- return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyConstructor();
+ if (CXXRecordDecl *RD = T->getAsCXXRecordDecl())
+ return RD->hasTrivialCopyConstructor() &&
+ !RD->hasNonTrivialCopyConstructor();
+ return false;
+ case UTT_HasTrivialMoveAssign:
+ // This trait is implemented by MSVC 2012 and needed to parse the
+ // standard library headers. Specifically it is used as the logic
+ // behind std::is_trivially_move_assignable (20.9.4.3)
+ if (T.isPODType(Self.Context))
+ return true;
+ if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl())
+ return RD->hasTrivialMoveAssignment() && !RD->hasNonTrivialMoveAssignment();
return false;
case UTT_HasTrivialAssign:
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
@@ -3095,12 +3214,13 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
// errors if the copy assignment operator is actually used, q.v.
// [class.copy]p12).
- if (C.getBaseElementType(T).isConstQualified())
+ if (T.isConstQualified())
return false;
if (T.isPODType(Self.Context))
return true;
- if (const RecordType *RT = T->getAs<RecordType>())
- return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyAssignment();
+ if (CXXRecordDecl *RD = T->getAsCXXRecordDecl())
+ return RD->hasTrivialCopyAssignment() &&
+ !RD->hasNonTrivialCopyAssignment();
return false;
case UTT_HasTrivialDestructor:
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
@@ -3117,9 +3237,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
T.getObjCLifetime() == Qualifiers::OCL_Autoreleasing)
return true;
- if (const RecordType *RT =
- C.getBaseElementType(T)->getAs<RecordType>())
- return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor();
+ if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl())
+ return RD->hasTrivialDestructor();
return false;
// TODO: Propagate nothrowness for implicitly declared special members.
case UTT_HasNothrowAssign:
@@ -3135,39 +3254,26 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
if (T->isReferenceType())
return false;
if (T.isPODType(Self.Context) || T->isObjCLifetimeType())
- return true;
- if (const RecordType *RT = T->getAs<RecordType>()) {
- CXXRecordDecl* RD = cast<CXXRecordDecl>(RT->getDecl());
- if (RD->hasTrivialCopyAssignment())
- return true;
+ return true;
- bool FoundAssign = false;
- DeclarationName Name = C.DeclarationNames.getCXXOperatorName(OO_Equal);
- LookupResult Res(Self, DeclarationNameInfo(Name, KeyLoc),
- Sema::LookupOrdinaryName);
- if (Self.LookupQualifiedName(Res, RD)) {
- Res.suppressDiagnostics();
- for (LookupResult::iterator Op = Res.begin(), OpEnd = Res.end();
- Op != OpEnd; ++Op) {
- if (isa<FunctionTemplateDecl>(*Op))
- continue;
-
- CXXMethodDecl *Operator = cast<CXXMethodDecl>(*Op);
- if (Operator->isCopyAssignmentOperator()) {
- FoundAssign = true;
- const FunctionProtoType *CPT
- = Operator->getType()->getAs<FunctionProtoType>();
- CPT = Self.ResolveExceptionSpec(KeyLoc, CPT);
- if (!CPT)
- return false;
- if (!CPT->isNothrow(Self.Context))
- return false;
- }
- }
- }
-
- return FoundAssign;
- }
+ if (const RecordType *RT = T->getAs<RecordType>())
+ return HasNoThrowOperator(RT, OO_Equal, Self, KeyLoc, C,
+ &CXXRecordDecl::hasTrivialCopyAssignment,
+ &CXXRecordDecl::hasNonTrivialCopyAssignment,
+ &CXXMethodDecl::isCopyAssignmentOperator);
+ return false;
+ case UTT_HasNothrowMoveAssign:
+ // This trait is implemented by MSVC 2012 and needed to parse the
+ // standard library headers. Specifically this is used as the logic
+ // behind std::is_nothrow_move_assignable (20.9.4.3).
+ if (T.isPODType(Self.Context))
+ return true;
+
+ if (const RecordType *RT = C.getBaseElementType(T)->getAs<RecordType>())
+ return HasNoThrowOperator(RT, OO_Equal, Self, KeyLoc, C,
+ &CXXRecordDecl::hasTrivialMoveAssignment,
+ &CXXRecordDecl::hasNonTrivialMoveAssignment,
+ &CXXMethodDecl::isMoveAssignmentOperator);
return false;
case UTT_HasNothrowCopy:
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
@@ -3177,16 +3283,16 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
// false.
if (T.isPODType(C) || T->isReferenceType() || T->isObjCLifetimeType())
return true;
- if (const RecordType *RT = T->getAs<RecordType>()) {
- CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (RD->hasTrivialCopyConstructor())
+ if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) {
+ if (RD->hasTrivialCopyConstructor() &&
+ !RD->hasNonTrivialCopyConstructor())
return true;
bool FoundConstructor = false;
unsigned FoundTQs;
- DeclContext::lookup_const_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = Self.LookupConstructors(RD);
- Con != ConEnd; ++Con) {
+ DeclContext::lookup_const_result R = Self.LookupConstructors(RD);
+ for (DeclContext::lookup_const_iterator Con = R.begin(),
+ ConEnd = R.end(); Con != ConEnd; ++Con) {
// A template constructor is never a copy constructor.
// FIXME: However, it may actually be selected at the actual overload
// resolution point.
@@ -3218,14 +3324,14 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
// throw an exception then the trait is true, else it is false.
if (T.isPODType(C) || T->isObjCLifetimeType())
return true;
- if (const RecordType *RT = C.getBaseElementType(T)->getAs<RecordType>()) {
- CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (RD->hasTrivialDefaultConstructor())
+ if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) {
+ if (RD->hasTrivialDefaultConstructor() &&
+ !RD->hasNonTrivialDefaultConstructor())
return true;
- DeclContext::lookup_const_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = Self.LookupConstructors(RD);
- Con != ConEnd; ++Con) {
+ DeclContext::lookup_const_result R = Self.LookupConstructors(RD);
+ for (DeclContext::lookup_const_iterator Con = R.begin(),
+ ConEnd = R.end(); Con != ConEnd; ++Con) {
// FIXME: In C++0x, a constructor template can be a default constructor.
if (isa<FunctionTemplateDecl>(*Con))
continue;
@@ -3247,11 +3353,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
// http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
// If type is a class type with a virtual destructor ([class.dtor])
// then the trait is true, else it is false.
- if (const RecordType *Record = T->getAs<RecordType>()) {
- CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
+ if (CXXRecordDecl *RD = T->getAsCXXRecordDecl())
if (CXXDestructorDecl *Destructor = Self.LookupDestructor(RD))
return Destructor->isVirtual();
- }
return false;
// These type trait expressions are modeled on the specifications for the
@@ -3360,8 +3464,8 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc,
if (SawVoid)
return false;
- llvm::SmallVector<OpaqueValueExpr, 2> OpaqueArgExprs;
- llvm::SmallVector<Expr *, 2> ArgExprs;
+ SmallVector<OpaqueValueExpr, 2> OpaqueArgExprs;
+ SmallVector<Expr *, 2> ArgExprs;
ArgExprs.reserve(Args.size() - 1);
for (unsigned I = 1, N = Args.size(); I != N; ++I) {
QualType T = Args[I]->getType();
@@ -3428,7 +3532,7 @@ ExprResult Sema::BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc,
ExprResult Sema::ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc,
ArrayRef<ParsedType> Args,
SourceLocation RParenLoc) {
- llvm::SmallVector<TypeSourceInfo *, 4> ConvertedArgs;
+ SmallVector<TypeSourceInfo *, 4> ConvertedArgs;
ConvertedArgs.reserve(Args.size());
for (unsigned I = 0, N = Args.size(); I != N; ++I) {
@@ -4769,7 +4873,7 @@ Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) {
// a StmtExpr; currently this is only used for asm statements.
// This is hacky, either create a new CXXStmtWithTemporaries statement or
// a new AsmStmtWithTemporaries.
- CompoundStmt *CompStmt = new (Context) CompoundStmt(Context, &SubStmt, 1,
+ CompoundStmt *CompStmt = new (Context) CompoundStmt(Context, SubStmt,
SourceLocation(),
SourceLocation());
Expr *E = new (Context) StmtExpr(CompStmt, Context.VoidTy, SourceLocation(),
@@ -4782,8 +4886,7 @@ Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) {
/// are omitted for the 'topmost' call in the decltype expression. If the
/// topmost call bound a temporary, strip that temporary off the expression.
ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
- ExpressionEvaluationContextRecord &Rec = ExprEvalContexts.back();
- assert(Rec.IsDecltype && "not in a decltype expression");
+ assert(ExprEvalContexts.back().IsDecltype && "not in a decltype expression");
// C++11 [expr.call]p11:
// If a function call is a prvalue of object type,
@@ -4824,7 +4927,7 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
E = TopBind->getSubExpr();
// Disable the special decltype handling now.
- Rec.IsDecltype = false;
+ ExprEvalContexts.back().IsDecltype = false;
// In MS mode, don't perform any extra checking of call return types within a
// decltype expression.
@@ -4833,8 +4936,9 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
// Perform the semantic checks we delayed until this point.
CallExpr *TopCall = dyn_cast<CallExpr>(E);
- for (unsigned I = 0, N = Rec.DelayedDecltypeCalls.size(); I != N; ++I) {
- CallExpr *Call = Rec.DelayedDecltypeCalls[I];
+ for (unsigned I = 0, N = ExprEvalContexts.back().DelayedDecltypeCalls.size();
+ I != N; ++I) {
+ CallExpr *Call = ExprEvalContexts.back().DelayedDecltypeCalls[I];
if (Call == TopCall)
continue;
@@ -4846,8 +4950,10 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
// Now all relevant types are complete, check the destructors are accessible
// and non-deleted, and annotate them on the temporaries.
- for (unsigned I = 0, N = Rec.DelayedDecltypeBinds.size(); I != N; ++I) {
- CXXBindTemporaryExpr *Bind = Rec.DelayedDecltypeBinds[I];
+ for (unsigned I = 0, N = ExprEvalContexts.back().DelayedDecltypeBinds.size();
+ I != N; ++I) {
+ CXXBindTemporaryExpr *Bind =
+ ExprEvalContexts.back().DelayedDecltypeBinds[I];
if (Bind == TopBind)
continue;
@@ -5321,12 +5427,12 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
VK_RValue, OK_Ordinary);
if (HadMultipleCandidates)
ME->setHadMultipleCandidates(true);
+ MarkMemberReferenced(ME);
QualType ResultType = Method->getResultType();
ExprValueKind VK = Expr::getValueKindForType(ResultType);
ResultType = ResultType.getNonLValueExprType(Context);
- MarkFunctionReferenced(Exp.get()->getLocStart(), Method);
CXXMemberCallExpr *CE =
new (Context) CXXMemberCallExpr(Context, ME, MultiExprArg(), ResultType, VK,
Exp.get()->getLocEnd());
@@ -5429,7 +5535,7 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) {
// normally, we don't need to do anything to handle it, but if it is a
// volatile lvalue with a special form, we perform an lvalue-to-rvalue
// conversion.
- if (getLangOpts().CPlusPlus0x && E->isGLValue() &&
+ if (getLangOpts().CPlusPlus11 && E->isGLValue() &&
E->getType().isVolatileQualified() &&
IsSpecialDiscardedValue(E)) {
ExprResult Res = DefaultLvalueConversion(E);
@@ -5460,7 +5566,9 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) {
return Owned(E);
}
-ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC) {
+ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
+ bool DiscardedValue,
+ bool IsConstexpr) {
ExprResult FullExpr = Owned(FE);
if (!FullExpr.get())
@@ -5469,24 +5577,25 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC) {
if (DiagnoseUnexpandedParameterPack(FullExpr.get()))
return ExprError();
- // Top-level message sends default to 'id' when we're in a debugger.
- if (getLangOpts().DebuggerCastResultToId &&
- FullExpr.get()->getType() == Context.UnknownAnyTy &&
- isa<ObjCMessageExpr>(FullExpr.get())) {
+ // Top-level expressions default to 'id' when we're in a debugger.
+ if (DiscardedValue && getLangOpts().DebuggerCastResultToId &&
+ FullExpr.get()->getType() == Context.UnknownAnyTy) {
FullExpr = forceUnknownAnyToType(FullExpr.take(), Context.getObjCIdType());
if (FullExpr.isInvalid())
return ExprError();
}
-
- FullExpr = CheckPlaceholderExpr(FullExpr.take());
- if (FullExpr.isInvalid())
- return ExprError();
- FullExpr = IgnoredValueConversions(FullExpr.take());
- if (FullExpr.isInvalid())
- return ExprError();
+ if (DiscardedValue) {
+ FullExpr = CheckPlaceholderExpr(FullExpr.take());
+ if (FullExpr.isInvalid())
+ return ExprError();
+
+ FullExpr = IgnoredValueConversions(FullExpr.take());
+ if (FullExpr.isInvalid())
+ return ExprError();
+ }
- CheckImplicitConversions(FullExpr.get(), CC);
+ CheckCompletedExpr(FullExpr.get(), CC, IsConstexpr);
return MaybeCreateExprWithCleanups(FullExpr);
}
diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp
index a7fd471..847db24 100644
--- a/lib/Sema/SemaExprMember.cpp
+++ b/lib/Sema/SemaExprMember.cpp
@@ -11,43 +11,32 @@
//
//===----------------------------------------------------------------------===//
#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"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/ScopeInfo.h"
using namespace clang;
using namespace sema;
+typedef llvm::SmallPtrSet<const CXXRecordDecl*, 4> BaseSet;
+static bool BaseIsNotInSet(const CXXRecordDecl *Base, void *BasesPtr) {
+ const BaseSet &Bases = *reinterpret_cast<const BaseSet*>(BasesPtr);
+ return !Bases.count(Base->getCanonicalDecl());
+}
+
/// Determines if the given class is provably not derived from all of
/// the prospective base classes.
-static bool IsProvablyNotDerivedFrom(Sema &SemaRef,
- CXXRecordDecl *Record,
- const llvm::SmallPtrSet<CXXRecordDecl*, 4> &Bases) {
- if (Bases.count(Record->getCanonicalDecl()))
- return false;
-
- RecordDecl *RD = Record->getDefinition();
- if (!RD) return false;
- Record = cast<CXXRecordDecl>(RD);
-
- for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(),
- E = Record->bases_end(); I != E; ++I) {
- CanQualType BaseT = SemaRef.Context.getCanonicalType((*I).getType());
- CanQual<RecordType> BaseRT = BaseT->getAs<RecordType>();
- if (!BaseRT) return false;
-
- CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl());
- if (!IsProvablyNotDerivedFrom(SemaRef, BaseRecord, Bases))
- return false;
- }
-
- return true;
+static bool isProvablyNotDerivedFrom(Sema &SemaRef, CXXRecordDecl *Record,
+ const BaseSet &Bases) {
+ void *BasesPtr = const_cast<void*>(reinterpret_cast<const void*>(&Bases));
+ return BaseIsNotInSet(Record, BasesPtr) &&
+ Record->forallBases(BaseIsNotInSet, BasesPtr);
}
enum IMAKind {
@@ -111,7 +100,7 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
// Collect all the declaring classes of instance members we find.
bool hasNonInstance = false;
bool isField = false;
- llvm::SmallPtrSet<CXXRecordDecl*, 4> Classes;
+ BaseSet Classes;
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
NamedDecl *D = *I;
@@ -132,7 +121,7 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
return IMA_Static;
bool IsCXX11UnevaluatedField = false;
- if (SemaRef.getLangOpts().CPlusPlus0x && isField) {
+ if (SemaRef.getLangOpts().CPlusPlus11 && isField) {
// C++11 [expr.prim.general]p12:
// An id-expression that denotes a non-static data member or non-static
// member function of a class can only be used:
@@ -169,16 +158,18 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
// is ill-formed.
if (R.getNamingClass() &&
contextClass->getCanonicalDecl() !=
- R.getNamingClass()->getCanonicalDecl() &&
- contextClass->isProvablyNotDerivedFrom(R.getNamingClass()))
- return hasNonInstance ? IMA_Mixed_Unrelated :
- IsCXX11UnevaluatedField ? IMA_Field_Uneval_Context :
- IMA_Error_Unrelated;
+ R.getNamingClass()->getCanonicalDecl()) {
+ // If the naming class is not the current context, this was a qualified
+ // member name lookup, and it's sufficient to check that we have the naming
+ // class as a base class.
+ Classes.clear();
+ Classes.insert(R.getNamingClass()->getCanonicalDecl());
+ }
// If we can prove that the current context is unrelated to all the
// declaring classes, it can't be an implicit member reference (in
// which case it's an error if any of those members are selected).
- if (IsProvablyNotDerivedFrom(SemaRef, contextClass, Classes))
+ if (isProvablyNotDerivedFrom(SemaRef, contextClass, Classes))
return hasNonInstance ? IMA_Mixed_Unrelated :
IsCXX11UnevaluatedField ? IMA_Field_Uneval_Context :
IMA_Error_Unrelated;
@@ -491,14 +482,14 @@ bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr,
QualType BaseType,
const CXXScopeSpec &SS,
const LookupResult &R) {
- const RecordType *BaseRT = BaseType->getAs<RecordType>();
- if (!BaseRT) {
+ CXXRecordDecl *BaseRecord =
+ cast_or_null<CXXRecordDecl>(computeDeclContext(BaseType));
+ if (!BaseRecord) {
// We can't check this yet because the base type is still
// dependent.
assert(BaseType->isDependentType());
return false;
}
- CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl());
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
// If this is an implicit member reference and we find a
@@ -513,11 +504,10 @@ bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr,
if (!DC->isRecord())
continue;
-
- llvm::SmallPtrSet<CXXRecordDecl*,4> MemberRecord;
- MemberRecord.insert(cast<CXXRecordDecl>(DC)->getCanonicalDecl());
- if (!IsProvablyNotDerivedFrom(*this, BaseRecord, MemberRecord))
+ CXXRecordDecl *MemberRecord = cast<CXXRecordDecl>(DC)->getCanonicalDecl();
+ if (BaseRecord->getCanonicalDecl() == MemberRecord ||
+ !BaseRecord->isProvablyNotDerivedFrom(MemberRecord))
return false;
}
@@ -1140,30 +1130,15 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
// There's an implicit 'isa' ivar on all objects.
// But we only actually find it this way on objects of type 'id',
// apparently.
- if (OTy->isObjCId() && Member->isStr("isa")) {
- Diag(MemberLoc, diag::warn_objc_isa_use);
+ if (OTy->isObjCId() && Member->isStr("isa"))
return Owned(new (Context) ObjCIsaExpr(BaseExpr.take(), IsArrow, MemberLoc,
+ OpLoc,
Context.getObjCClassType()));
- }
-
if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr))
return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS,
ObjCImpDecl, HasTemplateArgs);
goto fail;
}
- else if (Member && Member->isStr("isa")) {
- // If an ivar is (1) the first ivar in a root class and (2) named `isa`,
- // then issue the same deprecated warning that id->isa gets.
- ObjCInterfaceDecl *ClassDeclared = 0;
- if (ObjCIvarDecl *IV =
- IDecl->lookupInstanceVariable(Member, ClassDeclared)) {
- if (!ClassDeclared->getSuperClass()
- && (*ClassDeclared->ivar_begin()) == IV) {
- Diag(MemberLoc, diag::warn_objc_isa_use);
- Diag(IV->getLocation(), diag::note_ivar_decl);
- }
- }
- }
if (RequireCompleteType(OpLoc, BaseType, diag::err_typecheck_incomplete_tag,
BaseExpr.get()))
@@ -1269,14 +1244,15 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
if (ObjCMethodDecl *MD = getCurMethodDecl()) {
ObjCMethodFamily MF = MD->getMethodFamily();
warn = (MF != OMF_init && MF != OMF_dealloc &&
- MF != OMF_finalize);
+ MF != OMF_finalize &&
+ !IvarBacksCurrentMethodAccessor(IDecl, MD, IV));
}
if (warn)
Diag(MemberLoc, diag::warn_direct_ivar_access) << IV->getDeclName();
}
ObjCIvarRefExpr *Result = new (Context) ObjCIvarRefExpr(IV, IV->getType(),
- MemberLoc,
+ MemberLoc, OpLoc,
BaseExpr.take(),
IsArrow);
@@ -1607,27 +1583,27 @@ BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
} else {
QualType BaseType = BaseExpr->getType();
if (IsArrow) BaseType = BaseType->getAs<PointerType>()->getPointeeType();
-
+
Qualifiers BaseQuals = BaseType.getQualifiers();
-
+
// GC attributes are never picked up by members.
BaseQuals.removeObjCGCAttr();
-
+
// CVR attributes from the base are picked up by members,
// except that 'mutable' members don't pick up 'const'.
if (Field->isMutable()) BaseQuals.removeConst();
-
+
Qualifiers MemberQuals
= S.Context.getCanonicalType(MemberType).getQualifiers();
-
- // TR 18037 does not allow fields to be declared with address spaces.
+
assert(!MemberQuals.hasAddressSpace());
-
+
+
Qualifiers Combined = BaseQuals + MemberQuals;
if (Combined != MemberQuals)
MemberType = S.Context.getQualifiedType(MemberType, Combined);
}
-
+
S.UnusedPrivateFields.remove(Field);
ExprResult Base =
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index e43b6bf..e7b5ec9 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -12,20 +12,20 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/Scope.h"
-#include "clang/Sema/ScopeInfo.h"
-#include "clang/Sema/Initialization.h"
-#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
-#include "clang/Edit/Rewriters.h"
-#include "clang/Edit/Commit.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeLoc.h"
-#include "llvm/ADT/SmallString.h"
+#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
+#include "clang/Edit/Commit.h"
+#include "clang/Edit/Rewriters.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Initialization.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/ScopeInfo.h"
+#include "llvm/ADT/SmallString.h"
using namespace clang;
using namespace sema;
@@ -170,9 +170,9 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
QualType NumberType,
bool isLiteral = false,
SourceRange R = SourceRange()) {
- llvm::Optional<NSAPI::NSNumberLiteralMethodKind> Kind
- = S.NSAPIObj->getNSNumberFactoryMethodKind(NumberType);
-
+ Optional<NSAPI::NSNumberLiteralMethodKind> Kind =
+ S.NSAPIObj->getNSNumberFactoryMethodKind(NumberType);
+
if (!Kind) {
if (isLiteral) {
S.Diag(Loc, diag::err_invalid_nsnumber_type)
@@ -238,7 +238,7 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc,
SourceLocation(), SourceLocation(),
&CX.Idents.get("value"),
NumberType, /*TInfo=*/0, SC_None,
- SC_None, 0);
+ 0);
Method->setMethodParams(S.Context, value, ArrayRef<SourceLocation>());
}
@@ -489,7 +489,7 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
&Context.Idents.get("value"),
Context.getPointerType(ConstCharType),
/*TInfo=*/0,
- SC_None, SC_None, 0);
+ SC_None, 0);
M->setMethodParams(Context, value, ArrayRef<SourceLocation>());
BoxingMethod = M;
}
@@ -656,16 +656,14 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) {
SourceLocation(),
&Context.Idents.get("objects"),
Context.getPointerType(IdT),
- /*TInfo=*/0, SC_None, SC_None,
- 0);
+ /*TInfo=*/0, SC_None, 0);
Params.push_back(objects);
ParmVarDecl *cnt = ParmVarDecl::Create(Context, Method,
SourceLocation(),
SourceLocation(),
&Context.Idents.get("cnt"),
Context.UnsignedLongTy,
- /*TInfo=*/0, SC_None, SC_None,
- 0);
+ /*TInfo=*/0, SC_None, 0);
Params.push_back(cnt);
Method->setMethodParams(Context, Params, ArrayRef<SourceLocation>());
}
@@ -774,24 +772,21 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
SourceLocation(),
&Context.Idents.get("objects"),
Context.getPointerType(IdT),
- /*TInfo=*/0, SC_None, SC_None,
- 0);
+ /*TInfo=*/0, SC_None, 0);
Params.push_back(objects);
ParmVarDecl *keys = ParmVarDecl::Create(Context, Method,
SourceLocation(),
SourceLocation(),
&Context.Idents.get("keys"),
Context.getPointerType(IdT),
- /*TInfo=*/0, SC_None, SC_None,
- 0);
+ /*TInfo=*/0, SC_None, 0);
Params.push_back(keys);
ParmVarDecl *cnt = ParmVarDecl::Create(Context, Method,
SourceLocation(),
SourceLocation(),
&Context.Idents.get("cnt"),
Context.UnsignedLongTy,
- /*TInfo=*/0, SC_None, SC_None,
- 0);
+ /*TInfo=*/0, SC_None, 0);
Params.push_back(cnt);
Method->setMethodParams(Context, Params, ArrayRef<SourceLocation>());
}
@@ -981,7 +976,7 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
llvm::DenseMap<Selector, SourceLocation>::iterator Pos
= ReferencedSelectors.find(Sel);
if (Pos == ReferencedSelectors.end())
- ReferencedSelectors.insert(std::make_pair(Sel, SelLoc));
+ ReferencedSelectors.insert(std::make_pair(Sel, AtLoc));
}
// In ARC, forbid the user from using @selector for
@@ -1094,6 +1089,73 @@ QualType Sema::getMessageSendResultType(QualType ReceiverType,
return ReceiverType;
}
+/// Look for an ObjC method whose result type exactly matches the given type.
+static const ObjCMethodDecl *
+findExplicitInstancetypeDeclarer(const ObjCMethodDecl *MD,
+ QualType instancetype) {
+ if (MD->getResultType() == instancetype) return MD;
+
+ // For these purposes, a method in an @implementation overrides a
+ // declaration in the @interface.
+ if (const ObjCImplDecl *impl =
+ dyn_cast<ObjCImplDecl>(MD->getDeclContext())) {
+ const ObjCContainerDecl *iface;
+ if (const ObjCCategoryImplDecl *catImpl =
+ dyn_cast<ObjCCategoryImplDecl>(impl)) {
+ iface = catImpl->getCategoryDecl();
+ } else {
+ iface = impl->getClassInterface();
+ }
+
+ const ObjCMethodDecl *ifaceMD =
+ iface->getMethod(MD->getSelector(), MD->isInstanceMethod());
+ if (ifaceMD) return findExplicitInstancetypeDeclarer(ifaceMD, instancetype);
+ }
+
+ SmallVector<const ObjCMethodDecl *, 4> overrides;
+ MD->getOverriddenMethods(overrides);
+ for (unsigned i = 0, e = overrides.size(); i != e; ++i) {
+ if (const ObjCMethodDecl *result =
+ findExplicitInstancetypeDeclarer(overrides[i], instancetype))
+ return result;
+ }
+
+ return 0;
+}
+
+void Sema::EmitRelatedResultTypeNoteForReturn(QualType destType) {
+ // Only complain if we're in an ObjC method and the required return
+ // type doesn't match the method's declared return type.
+ ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CurContext);
+ if (!MD || !MD->hasRelatedResultType() ||
+ Context.hasSameUnqualifiedType(destType, MD->getResultType()))
+ return;
+
+ // Look for a method overridden by this method which explicitly uses
+ // 'instancetype'.
+ if (const ObjCMethodDecl *overridden =
+ findExplicitInstancetypeDeclarer(MD, Context.getObjCInstanceType())) {
+ SourceLocation loc;
+ SourceRange range;
+ if (TypeSourceInfo *TSI = overridden->getResultTypeSourceInfo()) {
+ range = TSI->getTypeLoc().getSourceRange();
+ loc = range.getBegin();
+ }
+ if (loc.isInvalid())
+ loc = overridden->getLocation();
+ Diag(loc, diag::note_related_result_type_explicit)
+ << /*current method*/ 1 << range;
+ return;
+ }
+
+ // Otherwise, if we have an interesting method family, note that.
+ // This should always trigger if the above didn't.
+ if (ObjCMethodFamily family = MD->getMethodFamily())
+ Diag(MD->getLocation(), diag::note_related_result_type_family)
+ << /*current method*/ 1
+ << family;
+}
+
void Sema::EmitRelatedResultTypeNote(const Expr *E) {
E = E->IgnoreParenImpCasts();
const ObjCMessageExpr *MsgSend = dyn_cast<ObjCMessageExpr>(E);
@@ -1135,10 +1197,16 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
if (Args[i]->isTypeDependent())
continue;
- ExprResult Result = DefaultArgumentPromotion(Args[i]);
- if (Result.isInvalid())
+ ExprResult result;
+ if (getLangOpts().DebuggerSupport) {
+ QualType paramTy; // ignored
+ result = checkUnknownAnyArg(lbrac, Args[i], paramTy);
+ } else {
+ result = DefaultArgumentPromotion(Args[i]);
+ }
+ if (result.isInvalid())
return true;
- Args[i] = Result.take();
+ Args[i] = result.take();
}
unsigned DiagID;
@@ -1196,6 +1264,22 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
!param->hasAttr<CFConsumedAttr>())
argExpr = stripARCUnbridgedCast(argExpr);
+ // If the parameter is __unknown_anytype, infer its type
+ // from the argument.
+ if (param->getType() == Context.UnknownAnyTy) {
+ QualType paramType;
+ ExprResult argE = checkUnknownAnyArg(lbrac, argExpr, paramType);
+ if (argE.isInvalid()) {
+ IsError = true;
+ } else {
+ Args[i] = argE.take();
+
+ // Update the parameter type in-place.
+ param->setType(paramType);
+ }
+ continue;
+ }
+
if (RequireCompleteType(argExpr->getSourceRange().getBegin(),
param->getType(),
diag::err_call_incomplete_argument, argExpr))
@@ -1539,8 +1623,15 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
if (ObjCMethodDecl *CurMethod = tryCaptureObjCSelf(receiverNameLoc)) {
if (CurMethod->isInstanceMethod()) {
- QualType T =
- Context.getObjCInterfaceType(CurMethod->getClassInterface());
+ ObjCInterfaceDecl *Super =
+ CurMethod->getClassInterface()->getSuperClass();
+ if (!Super) {
+ // The current class does not have a superclass.
+ Diag(receiverNameLoc, diag::error_root_class_cannot_use_super)
+ << CurMethod->getClassInterface()->getIdentifier();
+ return ExprError();
+ }
+ QualType T = Context.getObjCInterfaceType(Super);
T = Context.getObjCObjectPointerType(T);
return HandleExprPropertyRefExpr(T->getAsObjCInterfacePointerType(),
@@ -1695,9 +1786,11 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S,
QualType T;
if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(ND))
T = Context.getObjCInterfaceType(Class);
- else if (TypeDecl *Type = dyn_cast<TypeDecl>(ND))
+ else if (TypeDecl *Type = dyn_cast<TypeDecl>(ND)) {
T = Context.getTypeDeclType(Type);
- else
+ DiagnoseUseOfDecl(Type, NameLoc);
+ }
+ else
return ObjCInstanceMessage;
// We have a class message, and T is the type we're
@@ -2106,8 +2199,46 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
return ExprError();
Receiver = Result.take();
ReceiverType = Receiver->getType();
+
+ // If the receiver is an ObjC pointer, a block pointer, or an
+ // __attribute__((NSObject)) pointer, we don't need to do any
+ // special conversion in order to look up a receiver.
+ if (ReceiverType->isObjCRetainableType()) {
+ // do nothing
+ } else if (!getLangOpts().ObjCAutoRefCount &&
+ !Context.getObjCIdType().isNull() &&
+ (ReceiverType->isPointerType() ||
+ ReceiverType->isIntegerType())) {
+ // Implicitly convert integers and pointers to 'id' but emit a warning.
+ // But not in ARC.
+ Diag(Loc, diag::warn_bad_receiver_type)
+ << ReceiverType
+ << Receiver->getSourceRange();
+ if (ReceiverType->isPointerType()) {
+ Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(),
+ CK_CPointerToObjCPointerCast).take();
+ } else {
+ // TODO: specialized warning on null receivers?
+ bool IsNull = Receiver->isNullPointerConstant(Context,
+ Expr::NPC_ValueDependentIsNull);
+ CastKind Kind = IsNull ? CK_NullToPointer : CK_IntegralToPointer;
+ Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(),
+ Kind).take();
+ }
+ ReceiverType = Receiver->getType();
+ } else if (getLangOpts().CPlusPlus) {
+ ExprResult result = PerformContextuallyConvertToObjCPointer(Receiver);
+ if (result.isUsable()) {
+ Receiver = result.take();
+ ReceiverType = Receiver->getType();
+ }
+ }
}
+ // There's a somewhat weird interaction here where we assume that we
+ // won't actually have a method unless we also don't need to do some
+ // of the more detailed type-checking on the receiver.
+
if (!Method) {
// Handle messages to id.
bool receiverIsId = ReceiverType->isObjCIdType();
@@ -2223,7 +2354,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
if (!Method && getLangOpts().ObjCAutoRefCount) {
Diag(Loc, diag::err_arc_may_not_respond)
- << OCIType->getPointeeType() << Sel;
+ << OCIType->getPointeeType() << Sel
+ << SourceRange(SelectorLocs.front(), SelectorLocs.back());
return ExprError();
}
@@ -2242,48 +2374,11 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
}
if (Method && DiagnoseUseOfDecl(Method, Loc, forwardClass))
return ExprError();
- } else if (!getLangOpts().ObjCAutoRefCount &&
- !Context.getObjCIdType().isNull() &&
- (ReceiverType->isPointerType() ||
- ReceiverType->isIntegerType())) {
- // Implicitly convert integers and pointers to 'id' but emit a warning.
- // But not in ARC.
- Diag(Loc, diag::warn_bad_receiver_type)
- << ReceiverType
- << Receiver->getSourceRange();
- if (ReceiverType->isPointerType())
- Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(),
- CK_CPointerToObjCPointerCast).take();
- else {
- // TODO: specialized warning on null receivers?
- bool IsNull = Receiver->isNullPointerConstant(Context,
- Expr::NPC_ValueDependentIsNull);
- CastKind Kind = IsNull ? CK_NullToPointer : CK_IntegralToPointer;
- Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(),
- Kind).take();
- }
- ReceiverType = Receiver->getType();
} else {
- ExprResult ReceiverRes;
- if (getLangOpts().CPlusPlus)
- ReceiverRes = PerformContextuallyConvertToObjCPointer(Receiver);
- if (ReceiverRes.isUsable()) {
- Receiver = ReceiverRes.take();
- return BuildInstanceMessage(Receiver,
- ReceiverType,
- SuperLoc,
- Sel,
- Method,
- LBracLoc,
- SelectorLocs,
- RBracLoc,
- ArgsIn);
- } else {
- // Reject other random receiver types (e.g. structs).
- Diag(Loc, diag::err_bad_receiver_type)
- << ReceiverType << Receiver->getSourceRange();
- return ExprError();
- }
+ // Reject other random receiver types (e.g. structs).
+ Diag(Loc, diag::err_bad_receiver_type)
+ << ReceiverType << Receiver->getSourceRange();
+ return ExprError();
}
}
}
@@ -2447,6 +2542,18 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
return MaybeBindToTemporary(Result);
}
+static void RemoveSelectorFromWarningCache(Sema &S, Expr* Arg) {
+ if (ObjCSelectorExpr *OSE =
+ dyn_cast<ObjCSelectorExpr>(Arg->IgnoreParenCasts())) {
+ Selector Sel = OSE->getSelector();
+ SourceLocation Loc = OSE->getAtLoc();
+ llvm::DenseMap<Selector, SourceLocation>::iterator Pos
+ = S.ReferencedSelectors.find(Sel);
+ if (Pos != S.ReferencedSelectors.end() && Pos->second == Loc)
+ S.ReferencedSelectors.erase(Pos);
+ }
+}
+
// ActOnInstanceMessage - used for both unary and keyword messages.
// ArgExprs is optional - if it is present, the number of expressions
// is obtained from Sel.getNumArgs().
@@ -2460,6 +2567,20 @@ ExprResult Sema::ActOnInstanceMessage(Scope *S,
if (!Receiver)
return ExprError();
+ // A ParenListExpr can show up while doing error recovery with invalid code.
+ if (isa<ParenListExpr>(Receiver)) {
+ ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Receiver);
+ if (Result.isInvalid()) return ExprError();
+ Receiver = Result.take();
+ }
+
+ if (RespondsToSelectorSel.isNull()) {
+ IdentifierInfo *SelectorId = &Context.Idents.get("respondsToSelector");
+ RespondsToSelectorSel = Context.Selectors.getUnarySelector(SelectorId);
+ }
+ if (Sel == RespondsToSelectorSel)
+ RemoveSelectorFromWarningCache(*this, Args[0]);
+
return BuildInstanceMessage(Receiver, Receiver->getType(),
/*SuperLoc=*/SourceLocation(), Sel, /*Method=*/0,
LBracLoc, SelectorLocs, RBracLoc, Args);
@@ -2770,19 +2891,36 @@ static void addFixitForObjCARCConversion(Sema &S,
SourceLocation afterLParen,
QualType castType,
Expr *castExpr,
+ Expr *realCast,
const char *bridgeKeyword,
const char *CFBridgeName) {
// We handle C-style and implicit casts here.
switch (CCK) {
case Sema::CCK_ImplicitConversion:
case Sema::CCK_CStyleCast:
+ case Sema::CCK_OtherCast:
break;
case Sema::CCK_FunctionalCast:
- case Sema::CCK_OtherCast:
return;
}
if (CFBridgeName) {
+ if (CCK == Sema::CCK_OtherCast) {
+ if (const CXXNamedCastExpr *NCE = dyn_cast<CXXNamedCastExpr>(realCast)) {
+ SourceRange range(NCE->getOperatorLoc(),
+ NCE->getAngleBrackets().getEnd());
+ SmallString<32> BridgeCall;
+
+ SourceManager &SM = S.getSourceManager();
+ char PrevChar = *SM.getCharacterData(range.getBegin().getLocWithOffset(-1));
+ if (Lexer::isIdentifierBodyChar(PrevChar, S.getLangOpts()))
+ BridgeCall += ' ';
+
+ BridgeCall += CFBridgeName;
+ DiagB.AddFixItHint(FixItHint::CreateReplacement(range, BridgeCall));
+ }
+ return;
+ }
Expr *castedE = castExpr;
if (CStyleCastExpr *CCE = dyn_cast<CStyleCastExpr>(castedE))
castedE = CCE->getSubExpr();
@@ -2814,6 +2952,16 @@ static void addFixitForObjCARCConversion(Sema &S,
if (CCK == Sema::CCK_CStyleCast) {
DiagB.AddFixItHint(FixItHint::CreateInsertion(afterLParen, bridgeKeyword));
+ } else if (CCK == Sema::CCK_OtherCast) {
+ if (const CXXNamedCastExpr *NCE = dyn_cast<CXXNamedCastExpr>(realCast)) {
+ std::string castCode = "(";
+ castCode += bridgeKeyword;
+ castCode += castType.getAsString();
+ castCode += ")";
+ SourceRange Range(NCE->getOperatorLoc(),
+ NCE->getAngleBrackets().getEnd());
+ DiagB.AddFixItHint(FixItHint::CreateReplacement(Range, castCode));
+ }
} else {
std::string castCode = "(";
castCode += bridgeKeyword;
@@ -2838,7 +2986,8 @@ static void addFixitForObjCARCConversion(Sema &S,
static void
diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
QualType castType, ARCConversionTypeClass castACTC,
- Expr *castExpr, ARCConversionTypeClass exprACTC,
+ Expr *castExpr, Expr *realCast,
+ ARCConversionTypeClass exprACTC,
Sema::CheckedConversionKind CCK) {
SourceLocation loc =
(castRange.isValid() ? castRange.getBegin() : castExpr->getExprLoc());
@@ -2885,17 +3034,24 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
assert(CreateRule != ACC_bottom && "This cast should already be accepted.");
if (CreateRule != ACC_plusOne)
{
- DiagnosticBuilder DiagB = S.Diag(noteLoc, diag::note_arc_bridge);
+ DiagnosticBuilder DiagB =
+ (CCK != Sema::CCK_OtherCast) ? S.Diag(noteLoc, diag::note_arc_bridge)
+ : S.Diag(noteLoc, diag::note_arc_cstyle_bridge);
+
addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen,
- castType, castExpr, "__bridge ", 0);
+ castType, castExpr, realCast, "__bridge ", 0);
}
if (CreateRule != ACC_plusZero)
{
- DiagnosticBuilder DiagB = S.Diag(br ? castExpr->getExprLoc() : noteLoc,
- diag::note_arc_bridge_transfer)
- << castExprType << br;
+ DiagnosticBuilder DiagB =
+ (CCK == Sema::CCK_OtherCast && !br) ?
+ S.Diag(noteLoc, diag::note_arc_cstyle_bridge_transfer) << castExprType :
+ S.Diag(br ? castExpr->getExprLoc() : noteLoc,
+ diag::note_arc_bridge_transfer)
+ << castExprType << br;
+
addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen,
- castType, castExpr, "__bridge_transfer ",
+ castType, castExpr, realCast, "__bridge_transfer ",
br ? "CFBridgingRelease" : 0);
}
@@ -2918,17 +3074,23 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
assert(CreateRule != ACC_bottom && "This cast should already be accepted.");
if (CreateRule != ACC_plusOne)
{
- DiagnosticBuilder DiagB = S.Diag(noteLoc, diag::note_arc_bridge);
+ DiagnosticBuilder DiagB =
+ (CCK != Sema::CCK_OtherCast) ? S.Diag(noteLoc, diag::note_arc_bridge)
+ : S.Diag(noteLoc, diag::note_arc_cstyle_bridge);
addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen,
- castType, castExpr, "__bridge ", 0);
+ castType, castExpr, realCast, "__bridge ", 0);
}
if (CreateRule != ACC_plusZero)
{
- DiagnosticBuilder DiagB = S.Diag(br ? castExpr->getExprLoc() : noteLoc,
- diag::note_arc_bridge_retained)
- << castType << br;
+ DiagnosticBuilder DiagB =
+ (CCK == Sema::CCK_OtherCast && !br) ?
+ S.Diag(noteLoc, diag::note_arc_cstyle_bridge_retained) << castType :
+ S.Diag(br ? castExpr->getExprLoc() : noteLoc,
+ diag::note_arc_bridge_retained)
+ << castType << br;
+
addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen,
- castType, castExpr, "__bridge_retained ",
+ castType, castExpr, realCast, "__bridge_retained ",
br ? "CFBridgingRetain" : 0);
}
@@ -3025,7 +3187,7 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
return ACR_unbridged;
diagnoseObjCARCConversion(*this, castRange, castType, castACTC,
- castExpr, exprACTC, CCK);
+ castExpr, castExpr, exprACTC, CCK);
return ACR_okay;
}
@@ -3060,7 +3222,7 @@ void Sema::diagnoseARCUnbridgedCast(Expr *e) {
assert(classifyTypeForARCConversion(castExpr->getType()) == ACTC_retainable);
diagnoseObjCARCConversion(*this, castRange, castType, castACTC,
- castExpr, ACTC_retainable, CCK);
+ castExpr, realCast, ACTC_retainable, CCK);
}
/// stripARCUnbridgedCast - Given an expression of ARCUnbridgedCast
diff --git a/lib/Sema/SemaFixItUtils.cpp b/lib/Sema/SemaFixItUtils.cpp
index b61b930..2a845ba 100644
--- a/lib/Sema/SemaFixItUtils.cpp
+++ b/lib/Sema/SemaFixItUtils.cpp
@@ -178,7 +178,7 @@ static std::string getScalarZeroExpressionForType(const Type& T, const Sema& S)
if (T.isBooleanType() && S.LangOpts.CPlusPlus)
return "false";
if (T.isPointerType() || T.isMemberPointerType()) {
- if (S.LangOpts.CPlusPlus0x)
+ if (S.LangOpts.CPlusPlus11)
return "nullptr";
if (isMacroDefined(S, "NULL"))
return "NULL";
@@ -205,7 +205,7 @@ std::string Sema::getFixItZeroInitializerForType(QualType T) const {
const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
if (!RD || !RD->hasDefinition())
return std::string();
- if (LangOpts.CPlusPlus0x && !RD->hasUserProvidedDefaultConstructor())
+ if (LangOpts.CPlusPlus11 && !RD->hasUserProvidedDefaultConstructor())
return "{}";
if (RD->isAggregate())
return " = {}";
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 3596bbf..63309e3 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -11,16 +11,16 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Sema/Designator.h"
#include "clang/Sema/Initialization.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/SemaInternal.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/TypeLoc.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Designator.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/ErrorHandling.h"
@@ -901,11 +901,11 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity,
if (Index >= IList->getNumInits()) {
if (!VerifyOnly)
SemaRef.Diag(IList->getLocStart(),
- SemaRef.getLangOpts().CPlusPlus0x ?
+ SemaRef.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_empty_scalar_initializer :
diag::err_empty_scalar_initializer)
<< IList->getSourceRange();
- hadError = !SemaRef.getLangOpts().CPlusPlus0x;
+ hadError = !SemaRef.getLangOpts().CPlusPlus11;
++Index;
++StructuredIndex;
return;
@@ -985,7 +985,7 @@ void InitListChecker::CheckReferenceType(const InitializedEntity &Entity,
}
Expr *expr = IList->getInit(Index);
- if (isa<InitListExpr>(expr) && !SemaRef.getLangOpts().CPlusPlus0x) {
+ if (isa<InitListExpr>(expr) && !SemaRef.getLangOpts().CPlusPlus11) {
if (!VerifyOnly)
SemaRef.Diag(IList->getLocStart(), diag::err_init_non_aggr_init_list)
<< DeclType << IList->getSourceRange();
@@ -1632,8 +1632,8 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
StructuredList = IsFirstDesignator? SyntacticToSemantic.lookup(IList)
: getStructuredSubobjectInit(IList, Index, CurrentObjectType,
StructuredList, StructuredIndex,
- SourceRange(D->getStartLocation(),
- DIE->getSourceRange().getEnd()));
+ SourceRange(D->getLocStart(),
+ DIE->getLocEnd()));
assert(StructuredList && "Expected a structured initializer list");
}
@@ -1706,7 +1706,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// struct/union.
DeclContext::lookup_result Lookup = RT->getDecl()->lookup(FieldName);
FieldDecl *ReplacementField = 0;
- if (Lookup.first == Lookup.second) {
+ if (Lookup.empty()) {
// Name lookup didn't find anything. Determine whether this
// was a typo for another field name.
FieldInitializerValidatorCCC Validator(RT->getDecl());
@@ -1739,7 +1739,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// Name lookup found something, but it wasn't a field.
SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_nonfield)
<< FieldName;
- SemaRef.Diag((*Lookup.first)->getLocation(),
+ SemaRef.Diag(Lookup.front()->getLocation(),
diag::note_field_designator_found);
++Index;
return true;
@@ -1801,10 +1801,10 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
if (!VerifyOnly) {
DesignatedInitExpr::Designator *NextD
= DIE->getDesignator(DesigIdx + 1);
- SemaRef.Diag(NextD->getStartLocation(),
+ SemaRef.Diag(NextD->getLocStart(),
diag::err_designator_into_flexible_array_member)
- << SourceRange(NextD->getStartLocation(),
- DIE->getSourceRange().getEnd());
+ << SourceRange(NextD->getLocStart(),
+ DIE->getLocEnd());
SemaRef.Diag(Field->getLocation(), diag::note_flexible_array_member)
<< *Field;
}
@@ -2424,6 +2424,8 @@ void InitializationSequence::Step::Destroy() {
case SK_PassByIndirectRestore:
case SK_ProduceObjCObject:
case SK_StdInitializerList:
+ case SK_OCLSamplerInit:
+ case SK_OCLZeroEvent:
break;
case SK_ConversionSequence:
@@ -2652,6 +2654,20 @@ void InitializationSequence::AddStdInitializerListConstructionStep(QualType T) {
Steps.push_back(S);
}
+void InitializationSequence::AddOCLSamplerInitStep(QualType T) {
+ Step S;
+ S.Kind = SK_OCLSamplerInit;
+ S.Type = T;
+ Steps.push_back(S);
+}
+
+void InitializationSequence::AddOCLZeroEventStep(QualType T) {
+ Step S;
+ S.Kind = SK_OCLZeroEvent;
+ S.Type = T;
+ Steps.push_back(S);
+}
+
void InitializationSequence::RewrapReferenceInitList(QualType T,
InitListExpr *Syntactic) {
assert(Syntactic->getNumInits() == 1 &&
@@ -2744,14 +2760,14 @@ static OverloadingResult
ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet &CandidateSet,
- DeclContext::lookup_iterator Con,
- DeclContext::lookup_iterator ConEnd,
+ ArrayRef<NamedDecl *> Ctors,
OverloadCandidateSet::iterator &Best,
bool CopyInitializing, bool AllowExplicit,
bool OnlyListConstructors, bool InitListSyntax) {
CandidateSet.clear();
- for (; Con != ConEnd; ++Con) {
+ for (ArrayRef<NamedDecl *>::iterator
+ Con = Ctors.begin(), ConEnd = Ctors.end(); Con != ConEnd; ++Con) {
NamedDecl *D = *Con;
DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
bool SuppressUserConversions = false;
@@ -2842,8 +2858,11 @@ static void TryConstructorInitialization(Sema &S,
// - Otherwise, if T is a class type, constructors are considered. The
// applicable constructors are enumerated, and the best one is chosen
// through overload resolution.
- DeclContext::lookup_iterator ConStart, ConEnd;
- llvm::tie(ConStart, ConEnd) = S.LookupConstructors(DestRecordDecl);
+ DeclContext::lookup_result R = S.LookupConstructors(DestRecordDecl);
+ // The container holding the constructors can under certain conditions
+ // be changed while iterating (e.g. because of deserialization).
+ // To be safe we copy the lookup results to a new container.
+ SmallVector<NamedDecl*, 16> Ctors(R.begin(), R.end());
OverloadingResult Result = OR_No_Viable_Function;
OverloadCandidateSet::iterator Best;
@@ -2861,11 +2880,9 @@ static void TryConstructorInitialization(Sema &S,
// If the initializer list has no elements and T has a default constructor,
// the first phase is omitted.
- if (ILE->getNumInits() != 0 ||
- (!DestRecordDecl->hasDeclaredDefaultConstructor() &&
- !DestRecordDecl->needsImplicitDefaultConstructor()))
+ if (ILE->getNumInits() != 0 || !DestRecordDecl->hasDefaultConstructor())
Result = ResolveConstructorOverload(S, Kind.getLocation(), Args, NumArgs,
- CandidateSet, ConStart, ConEnd, Best,
+ CandidateSet, Ctors, Best,
CopyInitialization, AllowExplicit,
/*OnlyListConstructor=*/true,
InitListSyntax);
@@ -2883,7 +2900,7 @@ static void TryConstructorInitialization(Sema &S,
if (Result == OR_No_Viable_Function) {
AsInitializerList = false;
Result = ResolveConstructorOverload(S, Kind.getLocation(), Args, NumArgs,
- CandidateSet, ConStart, ConEnd, Best,
+ CandidateSet, Ctors, Best,
CopyInitialization, AllowExplicit,
/*OnlyListConstructors=*/false,
InitListSyntax);
@@ -2983,7 +3000,7 @@ static void TryReferenceListInitialization(Sema &S,
InitializationSequence &Sequence)
{
// First, catch C++03 where this isn't possible.
- if (!S.getLangOpts().CPlusPlus0x) {
+ if (!S.getLangOpts().CPlusPlus11) {
Sequence.SetFailed(InitializationSequence::FK_ReferenceBindingToInitList);
return;
}
@@ -3023,6 +3040,10 @@ static void TryReferenceListInitialization(Sema &S,
Sequence.RewrapReferenceInitList(cv1T1, InitList);
return;
}
+
+ // Update the initializer if we've resolved an overloaded function.
+ if (Sequence.step_begin() != Sequence.step_end())
+ Sequence.RewrapReferenceInitList(cv1T1, InitList);
}
// Not reference-related. Create a temporary and bind to that.
@@ -3067,14 +3088,13 @@ static void TryListInitialization(Sema &S,
// C++11 [dcl.init.list]p3:
// - If T is an aggregate, aggregate initialization is performed.
if (!DestType->isAggregateType()) {
- if (S.getLangOpts().CPlusPlus0x) {
+ if (S.getLangOpts().CPlusPlus11) {
// - Otherwise, if the initializer list has no elements and T is a
// class type with a default constructor, the object is
// value-initialized.
if (InitList->getNumInits() == 0) {
CXXRecordDecl *RD = DestType->getAsCXXRecordDecl();
- if (RD->hasDeclaredDefaultConstructor() ||
- RD->needsImplicitDefaultConstructor()) {
+ if (RD->hasDefaultConstructor()) {
TryValueInitialization(S, Entity, Kind, Sequence, InitList);
return;
}
@@ -3099,7 +3119,7 @@ static void TryListInitialization(Sema &S,
InitListChecker CheckInitList(S, Entity, InitList,
DestType, /*VerifyOnly=*/true,
Kind.getKind() != InitializationKind::IK_DirectList ||
- !S.getLangOpts().CPlusPlus0x);
+ !S.getLangOpts().CPlusPlus11);
if (CheckInitList.HadError()) {
Sequence.SetFailed(InitializationSequence::FK_ListInitializationFailed);
return;
@@ -3152,10 +3172,14 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
// to see if there is a suitable conversion.
CXXRecordDecl *T1RecordDecl = cast<CXXRecordDecl>(T1RecordType->getDecl());
- DeclContext::lookup_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = S.LookupConstructors(T1RecordDecl);
- Con != ConEnd; ++Con) {
- NamedDecl *D = *Con;
+ DeclContext::lookup_result R = S.LookupConstructors(T1RecordDecl);
+ // The container holding the constructors can under certain conditions
+ // be changed while iterating (e.g. because of deserialization).
+ // To be safe we copy the lookup results to a new container.
+ SmallVector<NamedDecl*, 16> Ctors(R.begin(), R.end());
+ for (SmallVector<NamedDecl*, 16>::iterator
+ CI = Ctors.begin(), CE = Ctors.end(); CI != CE; ++CI) {
+ NamedDecl *D = *CI;
DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
// Find the constructor (which may be a template).
@@ -3191,10 +3215,11 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
// functions.
CXXRecordDecl *T2RecordDecl = cast<CXXRecordDecl>(T2RecordType->getDecl());
- const UnresolvedSetImpl *Conversions
- = T2RecordDecl->getVisibleConversionFunctions();
- for (UnresolvedSetImpl::const_iterator I = Conversions->begin(),
- E = Conversions->end(); I != E; ++I) {
+ std::pair<CXXRecordDecl::conversion_iterator,
+ CXXRecordDecl::conversion_iterator>
+ Conversions = T2RecordDecl->getVisibleConversionFunctions();
+ for (CXXRecordDecl::conversion_iterator
+ I = Conversions.first, E = Conversions.second; I != E; ++I) {
NamedDecl *D = *I;
CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext());
if (isa<UsingShadowDecl>(D))
@@ -3237,10 +3262,9 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
return Result;
FunctionDecl *Function = Best->Function;
-
- // This is the overload that will actually be used for the initialization, so
- // mark it as used.
- S.MarkFunctionReferenced(DeclLoc, Function);
+ // This is the overload that will be used for this initialization step if we
+ // use this initialization. Mark it as referenced.
+ Function->setReferenced();
// Compute the returned type of the conversion.
if (isa<CXXConversionDecl>(Function))
@@ -3456,9 +3480,9 @@ static void TryReferenceInitializationCore(Sema &S,
//
// The constructor that would be used to make the copy shall
// be callable whether or not the copy is actually done.
- if (!S.getLangOpts().CPlusPlus0x && !S.getLangOpts().MicrosoftExt)
+ if (!S.getLangOpts().CPlusPlus11 && !S.getLangOpts().MicrosoftExt)
Sequence.AddExtraneousCopyToTemporary(cv2T2);
- else if (S.getLangOpts().CPlusPlus0x)
+ else if (S.getLangOpts().CPlusPlus11)
CheckCXX98CompatAccessibleCopy(S, Entity, Initializer);
}
@@ -3494,6 +3518,14 @@ static void TryReferenceInitializationCore(Sema &S,
return;
}
+ if ((RefRelationship == Sema::Ref_Compatible ||
+ RefRelationship == Sema::Ref_Compatible_With_Added_Qualification) &&
+ isRValueRef && InitCategory.isLValue()) {
+ Sequence.SetFailed(
+ InitializationSequence::FK_RValueReferenceBindingToLValue);
+ return;
+ }
+
Sequence.SetFailed(InitializationSequence::FK_ReferenceInitDropsQualifiers);
return;
}
@@ -3589,7 +3621,7 @@ static void TryValueInitialization(Sema &S,
if (const RecordType *RT = T->getAs<RecordType>()) {
if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
bool NeedZeroInitialization = true;
- if (!S.getLangOpts().CPlusPlus0x) {
+ if (!S.getLangOpts().CPlusPlus11) {
// C++98:
// -- if T is a class type (clause 9) with a user-declared constructor
// (12.1), then the default constructor for T is called (and the
@@ -3616,6 +3648,22 @@ static void TryValueInitialization(Sema &S,
if (NeedZeroInitialization)
Sequence.AddZeroInitializationStep(Entity.getType());
+ // C++03:
+ // -- if T is a non-union class type without a user-declared constructor,
+ // then every non-static data member and base class component of T is
+ // value-initialized;
+ // [...] A program that calls for [...] value-initialization of an
+ // entity of reference type is ill-formed.
+ //
+ // C++11 doesn't need this handling, because value-initialization does not
+ // occur recursively there, and the implicit default constructor is
+ // defined as deleted in the problematic cases.
+ if (!S.getLangOpts().CPlusPlus11 &&
+ ClassDecl->hasUninitializedReferenceMember()) {
+ Sequence.SetFailed(InitializationSequence::FK_TooManyInitsForReference);
+ return;
+ }
+
// If this is list-value-initialization, pass the empty init list on when
// building the constructor call. This affects the semantics of a few
// things (such as whether an explicit default constructor can be called).
@@ -3700,12 +3748,11 @@ static void TryUserDefinedConversion(Sema &S,
// Try to complete the type we're converting to.
if (!S.RequireCompleteType(Kind.getLocation(), DestType, 0)) {
- DeclContext::lookup_iterator ConOrig, ConEndOrig;
- llvm::tie(ConOrig, ConEndOrig) = S.LookupConstructors(DestRecordDecl);
+ DeclContext::lookup_result R = S.LookupConstructors(DestRecordDecl);
// The container holding the constructors can under certain conditions
// be changed while iterating. To be safe we copy the lookup results
// to a new container.
- SmallVector<NamedDecl*, 8> CopyOfCon(ConOrig, ConEndOrig);
+ SmallVector<NamedDecl*, 8> CopyOfCon(R.begin(), R.end());
for (SmallVector<NamedDecl*, 8>::iterator
Con = CopyOfCon.begin(), ConEnd = CopyOfCon.end();
Con != ConEnd; ++Con) {
@@ -3750,11 +3797,11 @@ static void TryUserDefinedConversion(Sema &S,
CXXRecordDecl *SourceRecordDecl
= cast<CXXRecordDecl>(SourceRecordType->getDecl());
- const UnresolvedSetImpl *Conversions
- = SourceRecordDecl->getVisibleConversionFunctions();
- for (UnresolvedSetImpl::const_iterator I = Conversions->begin(),
- E = Conversions->end();
- I != E; ++I) {
+ std::pair<CXXRecordDecl::conversion_iterator,
+ CXXRecordDecl::conversion_iterator>
+ Conversions = SourceRecordDecl->getVisibleConversionFunctions();
+ for (CXXRecordDecl::conversion_iterator
+ I = Conversions.first, E = Conversions.second; I != E; ++I) {
NamedDecl *D = *I;
CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext());
if (isa<UsingShadowDecl>(D))
@@ -3791,7 +3838,7 @@ static void TryUserDefinedConversion(Sema &S,
}
FunctionDecl *Function = Best->Function;
- S.MarkFunctionReferenced(DeclLoc, Function);
+ Function->setReferenced();
bool HadMultipleCandidates = (CandidateSet.size() > 1);
if (isa<CXXConstructorDecl>(Function)) {
@@ -3837,14 +3884,15 @@ enum InvalidICRKind { IIK_okay, IIK_nonlocal, IIK_nonscalar };
/// Determines whether this expression is an acceptable ICR source.
static InvalidICRKind isInvalidICRSource(ASTContext &C, Expr *e,
- bool isAddressOf) {
+ bool isAddressOf, bool &isWeakAccess) {
// Skip parens.
e = e->IgnoreParens();
// Skip address-of nodes.
if (UnaryOperator *op = dyn_cast<UnaryOperator>(e)) {
if (op->getOpcode() == UO_AddrOf)
- return isInvalidICRSource(C, op->getSubExpr(), /*addressof*/ true);
+ return isInvalidICRSource(C, op->getSubExpr(), /*addressof*/ true,
+ isWeakAccess);
// Skip certain casts.
} else if (CastExpr *ce = dyn_cast<CastExpr>(e)) {
@@ -3853,7 +3901,7 @@ static InvalidICRKind isInvalidICRSource(ASTContext &C, Expr *e,
case CK_BitCast:
case CK_LValueBitCast:
case CK_NoOp:
- return isInvalidICRSource(C, ce->getSubExpr(), isAddressOf);
+ return isInvalidICRSource(C, ce->getSubExpr(), isAddressOf, isWeakAccess);
case CK_ArrayToPointerDecay:
return IIK_nonscalar;
@@ -3867,6 +3915,11 @@ static InvalidICRKind isInvalidICRSource(ASTContext &C, Expr *e,
// If we have a declaration reference, it had better be a local variable.
} else if (isa<DeclRefExpr>(e)) {
+ // set isWeakAccess to true, to mean that there will be an implicit
+ // load which requires a cleanup.
+ if (e->getType().getObjCLifetime() == Qualifiers::OCL_Weak)
+ isWeakAccess = true;
+
if (!isAddressOf) return IIK_nonlocal;
VarDecl *var = dyn_cast<VarDecl>(cast<DeclRefExpr>(e)->getDecl());
@@ -3876,10 +3929,11 @@ static InvalidICRKind isInvalidICRSource(ASTContext &C, Expr *e,
// If we have a conditional operator, check both sides.
} else if (ConditionalOperator *cond = dyn_cast<ConditionalOperator>(e)) {
- if (InvalidICRKind iik = isInvalidICRSource(C, cond->getLHS(), isAddressOf))
+ if (InvalidICRKind iik = isInvalidICRSource(C, cond->getLHS(), isAddressOf,
+ isWeakAccess))
return iik;
- return isInvalidICRSource(C, cond->getRHS(), isAddressOf);
+ return isInvalidICRSource(C, cond->getRHS(), isAddressOf, isWeakAccess);
// These are never scalar.
} else if (isa<ArraySubscriptExpr>(e)) {
@@ -3898,8 +3952,13 @@ static InvalidICRKind isInvalidICRSource(ASTContext &C, Expr *e,
/// indirect copy/restore.
static void checkIndirectCopyRestoreSource(Sema &S, Expr *src) {
assert(src->isRValue());
-
- InvalidICRKind iik = isInvalidICRSource(S.Context, src, false);
+ bool isWeakAccess = false;
+ InvalidICRKind iik = isInvalidICRSource(S.Context, src, false, isWeakAccess);
+ // If isWeakAccess to true, there will be an implicit
+ // load which requires a cleanup.
+ if (S.getLangOpts().ObjCAutoRefCount && isWeakAccess)
+ S.ExprNeedsCleanups = true;
+
if (iik == IIK_okay) return;
S.Diag(src->getExprLoc(), diag::err_arc_nonlocal_writeback)
@@ -3973,6 +4032,39 @@ static bool tryObjCWritebackConversion(Sema &S,
return true;
}
+static bool TryOCLSamplerInitialization(Sema &S,
+ InitializationSequence &Sequence,
+ QualType DestType,
+ Expr *Initializer) {
+ if (!S.getLangOpts().OpenCL || !DestType->isSamplerT() ||
+ !Initializer->isIntegerConstantExpr(S.getASTContext()))
+ return false;
+
+ Sequence.AddOCLSamplerInitStep(DestType);
+ return true;
+}
+
+//
+// OpenCL 1.2 spec, s6.12.10
+//
+// The event argument can also be used to associate the
+// async_work_group_copy with a previous async copy allowing
+// an event to be shared by multiple async copies; otherwise
+// event should be zero.
+//
+static bool TryOCLZeroEventInitialization(Sema &S,
+ InitializationSequence &Sequence,
+ QualType DestType,
+ Expr *Initializer) {
+ if (!S.getLangOpts().OpenCL || !DestType->isEventT() ||
+ !Initializer->isIntegerConstantExpr(S.getASTContext()) ||
+ (Initializer->EvaluateKnownConstInt(S.getASTContext()) != 0))
+ return false;
+
+ Sequence.AddOCLZeroEventStep(DestType);
+ return true;
+}
+
InitializationSequence::InitializationSequence(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
@@ -4115,7 +4207,13 @@ InitializationSequence::InitializationSequence(Sema &S,
tryObjCWritebackConversion(S, *this, Entity, Initializer)) {
return;
}
-
+
+ if (TryOCLSamplerInitialization(S, *this, DestType, Initializer))
+ return;
+
+ if (TryOCLZeroEventInitialization(S, *this, DestType, Initializer))
+ return;
+
// Handle initialization in C
AddCAssignmentStep(DestType);
MaybeProduceObjCObject(S, *this, Entity);
@@ -4258,7 +4356,7 @@ getAssignmentAction(const InitializedEntity &Entity) {
llvm_unreachable("Invalid EntityKind!");
}
-/// \brief Whether we should binding a created object as a temporary when
+/// \brief Whether we should bind a created object as a temporary when
/// initializing the given entity.
static bool shouldBindAsTemporary(const InitializedEntity &Entity) {
switch (Entity.getKind()) {
@@ -4288,7 +4386,6 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) {
/// created for that initialization, requires destruction.
static bool shouldDestroyTemporary(const InitializedEntity &Entity) {
switch (Entity.getKind()) {
- case InitializedEntity::EK_Member:
case InitializedEntity::EK_Result:
case InitializedEntity::EK_New:
case InitializedEntity::EK_Base:
@@ -4299,6 +4396,7 @@ static bool shouldDestroyTemporary(const InitializedEntity &Entity) {
case InitializedEntity::EK_LambdaCapture:
return false;
+ case InitializedEntity::EK_Member:
case InitializedEntity::EK_Variable:
case InitializedEntity::EK_Parameter:
case InitializedEntity::EK_Temporary:
@@ -4316,12 +4414,17 @@ static void LookupCopyAndMoveConstructors(Sema &S,
OverloadCandidateSet &CandidateSet,
CXXRecordDecl *Class,
Expr *CurInitExpr) {
- DeclContext::lookup_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = S.LookupConstructors(Class);
- Con != ConEnd; ++Con) {
+ DeclContext::lookup_result R = S.LookupConstructors(Class);
+ // The container holding the constructors can under certain conditions
+ // be changed while iterating (e.g. because of deserialization).
+ // To be safe we copy the lookup results to a new container.
+ SmallVector<NamedDecl*, 16> Ctors(R.begin(), R.end());
+ for (SmallVector<NamedDecl*, 16>::iterator
+ CI = Ctors.begin(), CE = Ctors.end(); CI != CE; ++CI) {
+ NamedDecl *D = *CI;
CXXConstructorDecl *Constructor = 0;
- if ((Constructor = dyn_cast<CXXConstructorDecl>(*Con))) {
+ if ((Constructor = dyn_cast<CXXConstructorDecl>(D))) {
// Handle copy/moveconstructors, only.
if (!Constructor || Constructor->isInvalidDecl() ||
!Constructor->isCopyOrMoveConstructor() ||
@@ -4336,7 +4439,7 @@ static void LookupCopyAndMoveConstructors(Sema &S,
}
// Handle constructor templates.
- FunctionTemplateDecl *ConstructorTmpl = cast<FunctionTemplateDecl>(*Con);
+ FunctionTemplateDecl *ConstructorTmpl = cast<FunctionTemplateDecl>(D);
if (ConstructorTmpl->isInvalidDecl())
continue;
@@ -4513,8 +4616,6 @@ static ExprResult CopyObject(Sema &S,
return S.Owned(CurInitExpr);
}
- S.MarkFunctionReferenced(Loc, Constructor);
-
// Determine the arguments required to actually perform the
// constructor call (we might have derived-to-base conversions, or
// the copy constructor may have default arguments).
@@ -4526,6 +4627,7 @@ static ExprResult CopyObject(Sema &S,
CurInit = S.BuildCXXConstructExpr(Loc, T, Constructor, Elidable,
ConstructorArgs,
HadMultipleCandidates,
+ /*ListInit*/ false,
/*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
SourceRange());
@@ -4542,7 +4644,7 @@ static ExprResult CopyObject(Sema &S,
static void CheckCXX98CompatAccessibleCopy(Sema &S,
const InitializedEntity &Entity,
Expr *CurInitExpr) {
- assert(S.getLangOpts().CPlusPlus0x);
+ assert(S.getLangOpts().CPlusPlus11);
const RecordType *Record = CurInitExpr->getType()->getAs<RecordType>();
if (!Record)
@@ -4615,7 +4717,8 @@ PerformConstructorInitialization(Sema &S,
const InitializationKind &Kind,
MultiExprArg Args,
const InitializationSequence::Step& Step,
- bool &ConstructorInitRequiresZeroInit) {
+ bool &ConstructorInitRequiresZeroInit,
+ bool IsListInitialization) {
unsigned NumArgs = Args.size();
CXXConstructorDecl *Constructor
= cast<CXXConstructorDecl>(Step.Function.Function);
@@ -4653,7 +4756,8 @@ PerformConstructorInitialization(Sema &S,
// call.
if (S.CompleteConstructorCall(Constructor, Args,
Loc, ConstructorArgs,
- AllowExplicitConv))
+ AllowExplicitConv,
+ IsListInitialization))
return ExprError();
@@ -4673,13 +4777,12 @@ PerformConstructorInitialization(Sema &S,
if (Kind.getKind() != InitializationKind::IK_DirectList)
ParenRange = Kind.getParenRange();
- CurInit = S.Owned(new (S.Context) CXXTemporaryObjectExpr(S.Context,
- Constructor,
- TSInfo,
- ConstructorArgs,
- ParenRange,
- HadMultipleCandidates,
- ConstructorInitRequiresZeroInit));
+ CurInit = S.Owned(
+ new (S.Context) CXXTemporaryObjectExpr(S.Context, Constructor,
+ TSInfo, ConstructorArgs,
+ ParenRange, IsListInitialization,
+ HadMultipleCandidates,
+ ConstructorInitRequiresZeroInit));
} else {
CXXConstructExpr::ConstructionKind ConstructKind =
CXXConstructExpr::CK_Complete;
@@ -4704,6 +4807,7 @@ PerformConstructorInitialization(Sema &S,
Constructor, /*Elidable=*/true,
ConstructorArgs,
HadMultipleCandidates,
+ IsListInitialization,
ConstructorInitRequiresZeroInit,
ConstructKind,
parenRange);
@@ -4712,6 +4816,7 @@ PerformConstructorInitialization(Sema &S,
Constructor,
ConstructorArgs,
HadMultipleCandidates,
+ IsListInitialization,
ConstructorInitRequiresZeroInit,
ConstructKind,
parenRange);
@@ -4802,9 +4907,9 @@ InitializationSequence::Perform(Sema &S,
if (DeclaratorDecl *DD = Entity.getDecl()) {
if (TypeSourceInfo *TInfo = DD->getTypeSourceInfo()) {
TypeLoc TL = TInfo->getTypeLoc();
- if (IncompleteArrayTypeLoc *ArrayLoc
- = dyn_cast<IncompleteArrayTypeLoc>(&TL))
- Brackets = ArrayLoc->getBracketsRange();
+ if (IncompleteArrayTypeLoc ArrayLoc =
+ TL.getAs<IncompleteArrayTypeLoc>())
+ Brackets = ArrayLoc.getBracketsRange();
}
}
@@ -4835,7 +4940,7 @@ InitializationSequence::Perform(Sema &S,
if (Steps.empty())
return S.Owned((Expr *)0);
- if (S.getLangOpts().CPlusPlus0x && Entity.getType()->isReferenceType() &&
+ if (S.getLangOpts().CPlusPlus11 && Entity.getType()->isReferenceType() &&
Args.size() == 1 && isa<InitListExpr>(Args[0]) &&
Entity.getKind() != InitializedEntity::EK_Parameter) {
// Produce a C++98 compatibility warning if we are initializing a reference
@@ -4895,7 +5000,9 @@ InitializationSequence::Perform(Sema &S,
case SK_PassByIndirectCopyRestore:
case SK_PassByIndirectRestore:
case SK_ProduceObjCObject:
- case SK_StdInitializerList: {
+ case SK_StdInitializerList:
+ case SK_OCLSamplerInit:
+ case SK_OCLZeroEvent: {
assert(Args.size() == 1);
CurInit = Args[0];
if (!CurInit.get()) return ExprError();
@@ -5047,6 +5154,7 @@ InitializationSequence::Perform(Sema &S,
CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, Constructor,
ConstructorArgs,
HadMultipleCandidates,
+ /*ListInit*/ false,
/*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
SourceRange());
@@ -5161,10 +5269,11 @@ InitializationSequence::Perform(Sema &S,
QualType Ty = ResultType ? ResultType->getNonReferenceType() : Step->Type;
bool IsTemporary = Entity.getType()->isReferenceType();
InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(Ty);
- InitListChecker PerformInitList(S, IsTemporary ? TempEntity : Entity,
+ InitializedEntity InitEntity = IsTemporary ? TempEntity : Entity;
+ InitListChecker PerformInitList(S, InitEntity,
InitList, Ty, /*VerifyOnly=*/false,
Kind.getKind() != InitializationKind::IK_DirectList ||
- !S.getLangOpts().CPlusPlus0x);
+ !S.getLangOpts().CPlusPlus11);
if (PerformInitList.HadError())
return ExprError();
@@ -5180,7 +5289,9 @@ InitializationSequence::Perform(Sema &S,
InitListExpr *StructuredInitList =
PerformInitList.getFullyStructuredList();
CurInit.release();
- CurInit = S.Owned(StructuredInitList);
+ CurInit = shouldBindAsTemporary(InitEntity)
+ ? S.MaybeBindToTemporary(StructuredInitList)
+ : S.Owned(StructuredInitList);
break;
}
@@ -5202,7 +5313,8 @@ InitializationSequence::Perform(Sema &S,
CurInit = PerformConstructorInitialization(S, UseTemporary ? TempEntity :
Entity,
Kind, Arg, *Step,
- ConstructorInitRequiresZeroInit);
+ ConstructorInitRequiresZeroInit,
+ /*IsListInitialization*/ true);
break;
}
@@ -5235,7 +5347,8 @@ InitializationSequence::Perform(Sema &S,
CurInit = PerformConstructorInitialization(S, UseTemporary ? TempEntity
: Entity,
Kind, Args, *Step,
- ConstructorInitRequiresZeroInit);
+ ConstructorInitRequiresZeroInit,
+ /*IsListInitialization*/ false);
break;
}
@@ -5359,7 +5472,7 @@ InitializationSequence::Perform(Sema &S,
case SK_StdInitializerList: {
QualType Dest = Step->Type;
QualType E;
- bool Success = S.isStdInitializerList(Dest, &E);
+ bool Success = S.isStdInitializerList(Dest.getNonReferenceType(), &E);
(void)Success;
assert(Success && "Destination type changed?");
@@ -5390,9 +5503,9 @@ InitializationSequence::Perform(Sema &S,
for (unsigned i = 0; i < NumInits; ++i) {
Element.setElementIndex(i);
ExprResult Init = S.Owned(ILE->getInit(i));
- ExprResult Res = S.PerformCopyInitialization(Element,
- Init.get()->getExprLoc(),
- Init);
+ ExprResult Res = S.PerformCopyInitialization(
+ Element, Init.get()->getExprLoc(), Init,
+ /*TopLevelOfInitList=*/ true);
assert(!Res.isInvalid() && "Result changed since try phase.");
Converted[i] = Res.take();
}
@@ -5405,6 +5518,32 @@ InitializationSequence::Perform(Sema &S,
CurInit = S.Owned(Semantic);
break;
}
+ case SK_OCLSamplerInit: {
+ assert(Step->Type->isSamplerT() &&
+ "Sampler initialization on non sampler type.");
+
+ QualType SourceType = CurInit.get()->getType();
+ InitializedEntity::EntityKind EntityKind = Entity.getKind();
+
+ if (EntityKind == InitializedEntity::EK_Parameter) {
+ if (!SourceType->isSamplerT())
+ S.Diag(Kind.getLocation(), diag::err_sampler_argument_required)
+ << SourceType;
+ } else if (EntityKind != InitializedEntity::EK_Variable) {
+ llvm_unreachable("Invalid EntityKind!");
+ }
+
+ break;
+ }
+ case SK_OCLZeroEvent: {
+ assert(Step->Type->isEventT() &&
+ "Event initialization on non event type.");
+
+ CurInit = S.ImpCastExprToType(CurInit.take(), Step->Type,
+ CK_ZeroToOCLEvent,
+ CurInit.get()->getValueKind());
+ break;
+ }
}
}
@@ -5418,9 +5557,67 @@ InitializationSequence::Perform(Sema &S,
return CurInit;
}
+/// Somewhere within T there is an uninitialized reference subobject.
+/// Dig it out and diagnose it.
+static bool DiagnoseUninitializedReference(Sema &S, SourceLocation Loc,
+ QualType T) {
+ if (T->isReferenceType()) {
+ S.Diag(Loc, diag::err_reference_without_init)
+ << T.getNonReferenceType();
+ return true;
+ }
+
+ CXXRecordDecl *RD = T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
+ if (!RD || !RD->hasUninitializedReferenceMember())
+ return false;
+
+ for (CXXRecordDecl::field_iterator FI = RD->field_begin(),
+ FE = RD->field_end(); FI != FE; ++FI) {
+ if (FI->isUnnamedBitfield())
+ continue;
+
+ if (DiagnoseUninitializedReference(S, FI->getLocation(), FI->getType())) {
+ S.Diag(Loc, diag::note_value_initialization_here) << RD;
+ return true;
+ }
+ }
+
+ for (CXXRecordDecl::base_class_iterator BI = RD->bases_begin(),
+ BE = RD->bases_end();
+ BI != BE; ++BI) {
+ if (DiagnoseUninitializedReference(S, BI->getLocStart(), BI->getType())) {
+ S.Diag(Loc, diag::note_value_initialization_here) << RD;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
//===----------------------------------------------------------------------===//
// Diagnose initialization failures
//===----------------------------------------------------------------------===//
+
+/// Emit notes associated with an initialization that failed due to a
+/// "simple" conversion failure.
+static void emitBadConversionNotes(Sema &S, const InitializedEntity &entity,
+ Expr *op) {
+ QualType destType = entity.getType();
+ if (destType.getNonReferenceType()->isObjCObjectPointerType() &&
+ op->getType()->isObjCObjectPointerType()) {
+
+ // Emit a possible note about the conversion failing because the
+ // operand is a message send with a related result type.
+ S.EmitRelatedResultTypeNote(op);
+
+ // Emit a possible note about a return failing because we're
+ // expecting a related result type.
+ if (entity.getKind() == InitializedEntity::EK_Result)
+ S.EmitRelatedResultTypeNoteForReturn(destType);
+ }
+}
+
bool InitializationSequence::Diagnose(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
@@ -5432,10 +5629,17 @@ bool InitializationSequence::Diagnose(Sema &S,
switch (Failure) {
case FK_TooManyInitsForReference:
// FIXME: Customize for the initialized entity?
- if (NumArgs == 0)
- S.Diag(Kind.getLocation(), diag::err_reference_without_init)
- << DestType.getNonReferenceType();
- else // FIXME: diagnostic below could be better!
+ if (NumArgs == 0) {
+ // Dig out the reference subobject which is uninitialized and diagnose it.
+ // If this is value-initialization, this could be nested some way within
+ // the target type.
+ assert(Kind.getKind() == InitializationKind::IK_Value ||
+ DestType->isReferenceType());
+ bool Diagnosed =
+ DiagnoseUninitializedReference(S, Kind.getLocation(), DestType);
+ assert(Diagnosed && "couldn't find uninitialized reference to diagnose");
+ (void)Diagnosed;
+ } else // FIXME: diagnostic below could be better!
S.Diag(Kind.getLocation(), diag::err_reference_has_multiple_inits)
<< SourceRange(Args[0]->getLocStart(), Args[NumArgs - 1]->getLocEnd());
break;
@@ -5558,9 +5762,7 @@ bool InitializationSequence::Diagnose(Sema &S,
<< Args[0]->isLValue()
<< Args[0]->getType()
<< Args[0]->getSourceRange();
- if (DestType.getNonReferenceType()->isObjCObjectPointerType() &&
- Args[0]->getType()->isObjCObjectPointerType())
- S.EmitRelatedResultTypeNote(Args[0]);
+ emitBadConversionNotes(S, Entity, Args[0]);
break;
case FK_ConversionFailed: {
@@ -5573,9 +5775,7 @@ bool InitializationSequence::Diagnose(Sema &S,
<< Args[0]->getSourceRange();
S.HandleFunctionTypeMismatch(PDiag, FromType, DestType);
S.Diag(Kind.getLocation(), PDiag);
- if (DestType.getNonReferenceType()->isObjCObjectPointerType() &&
- Args[0]->getType()->isObjCObjectPointerType())
- S.EmitRelatedResultTypeNote(Args[0]);
+ emitBadConversionNotes(S, Entity, Args[0]);
break;
}
@@ -5649,7 +5849,8 @@ bool InitializationSequence::Diagnose(Sema &S,
= cast<CXXConstructorDecl>(S.CurContext);
if (Entity.getKind() == InitializedEntity::EK_Base) {
S.Diag(Kind.getLocation(), diag::err_missing_default_ctor)
- << Constructor->isImplicit()
+ << (Constructor->getInheritedConstructor() ? 2 :
+ Constructor->isImplicit() ? 1 : 0)
<< S.Context.getTypeDeclType(Constructor->getParent())
<< /*base=*/0
<< Entity.getType();
@@ -5661,7 +5862,8 @@ bool InitializationSequence::Diagnose(Sema &S,
<< S.Context.getTagDeclType(BaseDecl);
} else {
S.Diag(Kind.getLocation(), diag::err_missing_default_ctor)
- << Constructor->isImplicit()
+ << (Constructor->getInheritedConstructor() ? 2 :
+ Constructor->isImplicit() ? 1 : 0)
<< S.Context.getTypeDeclType(Constructor->getParent())
<< /*member=*/1
<< Entity.getName();
@@ -5722,7 +5924,8 @@ bool InitializationSequence::Diagnose(Sema &S,
// initialized.
CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(S.CurContext);
S.Diag(Kind.getLocation(), diag::err_uninitialized_member_in_ctor)
- << Constructor->isImplicit()
+ << (Constructor->getInheritedConstructor() ? 2 :
+ Constructor->isImplicit() ? 1 : 0)
<< S.Context.getTypeDeclType(Constructor->getParent())
<< /*const=*/1
<< Entity.getName();
@@ -5746,7 +5949,7 @@ bool InitializationSequence::Diagnose(Sema &S,
InitListChecker DiagnoseInitList(S, Entity, InitList,
DestType, /*VerifyOnly=*/false,
Kind.getKind() != InitializationKind::IK_DirectList ||
- !S.getLangOpts().CPlusPlus0x);
+ !S.getLangOpts().CPlusPlus11);
assert(DiagnoseInitList.HadError() &&
"Inconsistent init list check result.");
break;
@@ -5763,7 +5966,7 @@ bool InitializationSequence::Diagnose(Sema &S,
unsigned NumInits = InitList->getNumInits();
QualType DestType = Entity.getType();
QualType E;
- bool Success = S.isStdInitializerList(DestType, &E);
+ bool Success = S.isStdInitializerList(DestType.getNonReferenceType(), &E);
(void)Success;
assert(Success && "Where did the std::initializer_list go?");
InitializedEntity HiddenArray = InitializedEntity::InitializeTemporary(
@@ -6047,8 +6250,20 @@ void InitializationSequence::dump(raw_ostream &OS) const {
case SK_StdInitializerList:
OS << "std::initializer_list from initializer list";
break;
+
+ case SK_OCLSamplerInit:
+ OS << "OpenCL sampler_t from integer constant";
+ break;
+
+ case SK_OCLZeroEvent:
+ OS << "OpenCL event_t from zero";
+ break;
}
+
+ OS << " [" << S->Type.getAsString() << ']';
}
+
+ OS << '\n';
}
void InitializationSequence::dump() const {
@@ -6104,7 +6319,7 @@ static void DiagnoseNarrowingInInitList(Sema &S, InitializationSequence &Seq,
// narrowing conversion even if the value is a constant and can be
// represented exactly as an integer.
S.Diag(PostInit->getLocStart(),
- S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus0x?
+ S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus11?
diag::warn_init_list_type_narrowing
: S.isSFINAEContext()?
diag::err_init_list_type_narrowing_sfinae
@@ -6117,7 +6332,7 @@ static void DiagnoseNarrowingInInitList(Sema &S, InitializationSequence &Seq,
case NK_Constant_Narrowing:
// A constant value was narrowed.
S.Diag(PostInit->getLocStart(),
- S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus0x?
+ S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus11?
diag::warn_init_list_constant_narrowing
: S.isSFINAEContext()?
diag::err_init_list_constant_narrowing_sfinae
@@ -6130,7 +6345,7 @@ static void DiagnoseNarrowingInInitList(Sema &S, InitializationSequence &Seq,
case NK_Variable_Narrowing:
// A variable's value may have been narrowed.
S.Diag(PostInit->getLocStart(),
- S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus0x?
+ S.getLangOpts().MicrosoftExt || !S.getLangOpts().CPlusPlus11?
diag::warn_init_list_variable_narrowing
: S.isSFINAEContext()?
diag::err_init_list_variable_narrowing_sfinae
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index 15cd2a7..53fa6da 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -11,13 +11,13 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Sema/DeclSpec.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/AST/ExprCXX.h"
using namespace clang;
using namespace sema;
@@ -55,7 +55,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
SourceRange IntroducerRange,
TypeSourceInfo *MethodType,
SourceLocation EndLoc,
- llvm::ArrayRef<ParmVarDecl *> Params) {
+ ArrayRef<ParmVarDecl *> Params) {
// C++11 [expr.prim.lambda]p5:
// The closure type for a lambda-expression has a public inline function
// call operator (13.5.4) whose parameters and return type are described by
@@ -74,7 +74,6 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
IntroducerRange.getBegin(),
MethodNameLoc),
MethodType->getType(), MethodType,
- /*isStatic=*/false,
SC_None,
/*isInline=*/true,
/*isConstExpr=*/false,
@@ -225,73 +224,153 @@ void Sema::addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope) {
}
}
-static bool checkReturnValueType(const ASTContext &Ctx, const Expr *E,
- QualType &DeducedType,
- QualType &AlternateType) {
- // Handle ReturnStmts with no expressions.
- if (!E) {
- if (AlternateType.isNull())
- AlternateType = Ctx.VoidTy;
+/// If this expression is an enumerator-like expression of some type
+/// T, return the type T; otherwise, return null.
+///
+/// Pointer comparisons on the result here should always work because
+/// it's derived from either the parent of an EnumConstantDecl
+/// (i.e. the definition) or the declaration returned by
+/// EnumType::getDecl() (i.e. the definition).
+static EnumDecl *findEnumForBlockReturn(Expr *E) {
+ // An expression is an enumerator-like expression of type T if,
+ // ignoring parens and parens-like expressions:
+ E = E->IgnoreParens();
+
+ // - it is an enumerator whose enum type is T or
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+ if (EnumConstantDecl *D
+ = dyn_cast<EnumConstantDecl>(DRE->getDecl())) {
+ return cast<EnumDecl>(D->getDeclContext());
+ }
+ return 0;
+ }
- return Ctx.hasSameType(DeducedType, Ctx.VoidTy);
+ // - it is a comma expression whose RHS is an enumerator-like
+ // expression of type T or
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+ if (BO->getOpcode() == BO_Comma)
+ return findEnumForBlockReturn(BO->getRHS());
+ return 0;
}
- QualType StrictType = E->getType();
- QualType LooseType = StrictType;
-
- // In C, enum constants have the type of their underlying integer type,
- // not the enum. When inferring block return types, we should allow
- // the enum type if an enum constant is used, unless the enum is
- // anonymous (in which case there can be no variables of its type).
- if (!Ctx.getLangOpts().CPlusPlus) {
- const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts());
- if (DRE) {
- const Decl *D = DRE->getDecl();
- if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) {
- const EnumDecl *Enum = cast<EnumDecl>(ECD->getDeclContext());
- if (Enum->getDeclName() || Enum->getTypedefNameForAnonDecl())
- LooseType = Ctx.getTypeDeclType(Enum);
- }
- }
+ // - it is a statement-expression whose value expression is an
+ // enumerator-like expression of type T or
+ if (StmtExpr *SE = dyn_cast<StmtExpr>(E)) {
+ if (Expr *last = dyn_cast_or_null<Expr>(SE->getSubStmt()->body_back()))
+ return findEnumForBlockReturn(last);
+ return 0;
}
- // Special case for the first return statement we find.
- // The return type has already been tentatively set, but we might still
- // have an alternate type we should prefer.
- if (AlternateType.isNull())
- AlternateType = LooseType;
-
- if (Ctx.hasSameType(DeducedType, StrictType)) {
- // FIXME: The loose type is different when there are constants from two
- // different enums. We could consider warning here.
- if (AlternateType != Ctx.DependentTy)
- if (!Ctx.hasSameType(AlternateType, LooseType))
- AlternateType = Ctx.VoidTy;
- return true;
+ // - it is a ternary conditional operator (not the GNU ?:
+ // extension) whose second and third operands are
+ // enumerator-like expressions of type T or
+ if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
+ if (EnumDecl *ED = findEnumForBlockReturn(CO->getTrueExpr()))
+ if (ED == findEnumForBlockReturn(CO->getFalseExpr()))
+ return ED;
+ return 0;
}
- if (Ctx.hasSameType(DeducedType, LooseType)) {
- // Use DependentTy to signal that we're using an alternate type and may
- // need to add casts somewhere.
- AlternateType = Ctx.DependentTy;
- return true;
+ // (implicitly:)
+ // - it is an implicit integral conversion applied to an
+ // enumerator-like expression of type T or
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
+ // We can only see integral conversions in valid enumerator-like
+ // expressions.
+ if (ICE->getCastKind() == CK_IntegralCast)
+ return findEnumForBlockReturn(ICE->getSubExpr());
+ return 0;
}
- if (Ctx.hasSameType(AlternateType, StrictType) ||
- Ctx.hasSameType(AlternateType, LooseType)) {
- DeducedType = AlternateType;
- // Use DependentTy to signal that we're using an alternate type and may
- // need to add casts somewhere.
- AlternateType = Ctx.DependentTy;
- return true;
+ // - it is an expression of that formal enum type.
+ if (const EnumType *ET = E->getType()->getAs<EnumType>()) {
+ return ET->getDecl();
}
- return false;
+ // Otherwise, nope.
+ return 0;
+}
+
+/// Attempt to find a type T for which the returned expression of the
+/// given statement is an enumerator-like expression of that type.
+static EnumDecl *findEnumForBlockReturn(ReturnStmt *ret) {
+ if (Expr *retValue = ret->getRetValue())
+ return findEnumForBlockReturn(retValue);
+ return 0;
+}
+
+/// Attempt to find a common type T for which all of the returned
+/// expressions in a block are enumerator-like expressions of that
+/// type.
+static EnumDecl *findCommonEnumForBlockReturns(ArrayRef<ReturnStmt*> returns) {
+ ArrayRef<ReturnStmt*>::iterator i = returns.begin(), e = returns.end();
+
+ // Try to find one for the first return.
+ EnumDecl *ED = findEnumForBlockReturn(*i);
+ if (!ED) return 0;
+
+ // Check that the rest of the returns have the same enum.
+ for (++i; i != e; ++i) {
+ if (findEnumForBlockReturn(*i) != ED)
+ return 0;
+ }
+
+ // Never infer an anonymous enum type.
+ if (!ED->hasNameForLinkage()) return 0;
+
+ return ED;
+}
+
+/// Adjust the given return statements so that they formally return
+/// the given type. It should require, at most, an IntegralCast.
+static void adjustBlockReturnsToEnum(Sema &S, ArrayRef<ReturnStmt*> returns,
+ QualType returnType) {
+ for (ArrayRef<ReturnStmt*>::iterator
+ i = returns.begin(), e = returns.end(); i != e; ++i) {
+ ReturnStmt *ret = *i;
+ Expr *retValue = ret->getRetValue();
+ if (S.Context.hasSameType(retValue->getType(), returnType))
+ continue;
+
+ // Right now we only support integral fixup casts.
+ assert(returnType->isIntegralOrUnscopedEnumerationType());
+ assert(retValue->getType()->isIntegralOrUnscopedEnumerationType());
+
+ ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(retValue);
+
+ Expr *E = (cleanups ? cleanups->getSubExpr() : retValue);
+ E = ImplicitCastExpr::Create(S.Context, returnType, CK_IntegralCast,
+ E, /*base path*/ 0, VK_RValue);
+ if (cleanups) {
+ cleanups->setSubExpr(E);
+ } else {
+ ret->setRetValue(E);
+ }
+ }
}
void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
assert(CSI.HasImplicitReturnType);
+ // C++ Core Issue #975, proposed resolution:
+ // If a lambda-expression does not include a trailing-return-type,
+ // it is as if the trailing-return-type denotes the following type:
+ // - if there are no return statements in the compound-statement,
+ // or all return statements return either an expression of type
+ // void or no expression or braced-init-list, the type void;
+ // - otherwise, if all return statements return an expression
+ // and the types of the returned expressions after
+ // lvalue-to-rvalue conversion (4.1 [conv.lval]),
+ // array-to-pointer conversion (4.2 [conv.array]), and
+ // function-to-pointer conversion (4.3 [conv.func]) are the
+ // same, that common type;
+ // - otherwise, the program is ill-formed.
+ //
+ // In addition, in blocks in non-C++ modes, if all of the return
+ // statements are enumerator-like expressions of some type T, where
+ // T has a name for linkage, then we infer the return type of the
+ // block to be that type.
+
// First case: no return statements, implicit void return type.
ASTContext &Ctx = getASTContext();
if (CSI.Returns.empty()) {
@@ -308,6 +387,17 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
if (CSI.ReturnType->isDependentType())
return;
+ // Try to apply the enum-fuzz rule.
+ if (!getLangOpts().CPlusPlus) {
+ assert(isa<BlockScopeInfo>(CSI));
+ const EnumDecl *ED = findCommonEnumForBlockReturns(CSI.Returns);
+ if (ED) {
+ CSI.ReturnType = Context.getTypeDeclType(ED);
+ adjustBlockReturnsToEnum(*this, CSI.Returns, CSI.ReturnType);
+ return;
+ }
+ }
+
// Third case: only one return statement. Don't bother doing extra work!
SmallVectorImpl<ReturnStmt*>::iterator I = CSI.Returns.begin(),
E = CSI.Returns.end();
@@ -316,47 +406,25 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
// General case: many return statements.
// Check that they all have compatible return types.
- // For now, that means "identical", with an exception for enum constants.
- // (In C, enum constants have the type of their underlying integer type,
- // not the type of the enum. C++ uses the type of the enum.)
- QualType AlternateType;
// We require the return types to strictly match here.
+ // Note that we've already done the required promotions as part of
+ // processing the return statement.
for (; I != E; ++I) {
const ReturnStmt *RS = *I;
const Expr *RetE = RS->getRetValue();
- if (!checkReturnValueType(Ctx, RetE, CSI.ReturnType, AlternateType)) {
- // FIXME: This is a poor diagnostic for ReturnStmts without expressions.
- Diag(RS->getLocStart(),
- diag::err_typecheck_missing_return_type_incompatible)
- << (RetE ? RetE->getType() : Ctx.VoidTy) << CSI.ReturnType
- << isa<LambdaScopeInfo>(CSI);
- // Don't bother fixing up the return statements in the block if some of
- // them are unfixable anyway.
- AlternateType = Ctx.VoidTy;
- // Continue iterating so that we keep emitting diagnostics.
- }
- }
- // If our return statements turned out to be compatible, but we needed to
- // pick a different return type, go through and fix the ones that need it.
- if (AlternateType == Ctx.DependentTy) {
- for (SmallVectorImpl<ReturnStmt*>::iterator I = CSI.Returns.begin(),
- E = CSI.Returns.end();
- I != E; ++I) {
- ReturnStmt *RS = *I;
- Expr *RetE = RS->getRetValue();
- if (RetE->getType() == CSI.ReturnType)
- continue;
+ QualType ReturnType = (RetE ? RetE->getType() : Context.VoidTy);
+ if (Context.hasSameType(ReturnType, CSI.ReturnType))
+ continue;
- // Right now we only support integral fixup casts.
- assert(CSI.ReturnType->isIntegralOrUnscopedEnumerationType());
- assert(RetE->getType()->isIntegralOrUnscopedEnumerationType());
- ExprResult Casted = ImpCastExprToType(RetE, CSI.ReturnType,
- CK_IntegralCast);
- assert(Casted.isUsable());
- RS->setRetValue(Casted.take());
- }
+ // FIXME: This is a poor diagnostic for ReturnStmts without expressions.
+ // TODO: It's possible that the *first* return is the divergent one.
+ Diag(RS->getLocStart(),
+ diag::err_typecheck_missing_return_type_incompatible)
+ << ReturnType << CSI.ReturnType
+ << isa<LambdaScopeInfo>(CSI);
+ // Continue iterating so that we keep emitting diagnostics.
}
}
@@ -376,7 +444,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
bool ExplicitResultType = true;
bool ContainsUnexpandedParameterPack = false;
SourceLocation EndLoc;
- llvm::SmallVector<ParmVarDecl *, 8> Params;
+ SmallVector<ParmVarDecl *, 8> Params;
if (ParamInfo.getNumTypeObjects() == 0) {
// C++11 [expr.prim.lambda]p4:
// If a lambda-expression does not include a lambda-declarator, it is as
@@ -385,7 +453,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
EPI.HasTrailingReturn = true;
EPI.TypeQuals |= DeclSpec::TQ_const;
QualType MethodTy = Context.getFunctionType(Context.DependentTy,
- /*Args=*/0, /*NumArgs=*/0, EPI);
+ ArrayRef<QualType>(),
+ EPI);
MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy);
ExplicitParams = false;
ExplicitResultType = false;
@@ -449,7 +518,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// Handle explicit captures.
SourceLocation PrevCaptureLoc
= Intro.Default == LCD_None? Intro.Range.getBegin() : Intro.DefaultLoc;
- for (llvm::SmallVector<LambdaCapture, 4>::const_iterator
+ for (SmallVector<LambdaCapture, 4>::const_iterator
C = Intro.Captures.begin(),
E = Intro.Captures.end();
C != E;
@@ -628,16 +697,18 @@ static void addFunctionPointerConversion(Sema &S,
{
FunctionProtoType::ExtProtoInfo ExtInfo = Proto->getExtProtoInfo();
ExtInfo.TypeQuals = 0;
- FunctionTy = S.Context.getFunctionType(Proto->getResultType(),
- Proto->arg_type_begin(),
- Proto->getNumArgs(),
- ExtInfo);
+ FunctionTy =
+ S.Context.getFunctionType(Proto->getResultType(),
+ ArrayRef<QualType>(Proto->arg_type_begin(),
+ Proto->getNumArgs()),
+ ExtInfo);
FunctionPtrTy = S.Context.getPointerType(FunctionTy);
}
FunctionProtoType::ExtProtoInfo ExtInfo;
ExtInfo.TypeQuals = Qualifiers::Const;
- QualType ConvTy = S.Context.getFunctionType(FunctionPtrTy, 0, 0, ExtInfo);
+ QualType ConvTy =
+ S.Context.getFunctionType(FunctionPtrTy, ArrayRef<QualType>(), ExtInfo);
SourceLocation Loc = IntroducerRange.getBegin();
DeclarationName Name
@@ -666,7 +737,7 @@ static void addFunctionPointerConversion(Sema &S,
= CXXMethodDecl::Create(S.Context, Class, Loc,
DeclarationNameInfo(Name, Loc), FunctionTy,
CallOperator->getTypeSourceInfo(),
- /*IsStatic=*/true, SC_Static, /*IsInline=*/true,
+ SC_Static, /*IsInline=*/true,
/*IsConstexpr=*/false,
CallOperator->getBody()->getLocEnd());
SmallVector<ParmVarDecl *, 4> InvokeParams;
@@ -679,7 +750,6 @@ static void addFunctionPointerConversion(Sema &S,
From->getType(),
From->getTypeSourceInfo(),
From->getStorageClass(),
- From->getStorageClassAsWritten(),
/*DefaultArg=*/0));
}
Invoke->setParams(InvokeParams);
@@ -701,15 +771,16 @@ static void addBlockPointerConversion(Sema &S,
ExtInfo.TypeQuals = 0;
QualType FunctionTy
= S.Context.getFunctionType(Proto->getResultType(),
- Proto->arg_type_begin(),
- Proto->getNumArgs(),
+ ArrayRef<QualType>(Proto->arg_type_begin(),
+ Proto->getNumArgs()),
ExtInfo);
BlockPtrTy = S.Context.getBlockPointerType(FunctionTy);
}
FunctionProtoType::ExtProtoInfo ExtInfo;
ExtInfo.TypeQuals = Qualifiers::Const;
- QualType ConvTy = S.Context.getFunctionType(BlockPtrTy, 0, 0, ExtInfo);
+ QualType ConvTy = S.Context.getFunctionType(BlockPtrTy, ArrayRef<QualType>(),
+ ExtInfo);
SourceLocation Loc = IntroducerRange.getBegin();
DeclarationName Name
@@ -734,8 +805,8 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
Scope *CurScope,
bool IsInstantiation) {
// Collect information from the lambda scope.
- llvm::SmallVector<LambdaExpr::Capture, 4> Captures;
- llvm::SmallVector<Expr *, 4> CaptureInits;
+ SmallVector<LambdaExpr::Capture, 4> Captures;
+ SmallVector<Expr *, 4> CaptureInits;
LambdaCaptureDefault CaptureDefault;
CXXRecordDecl *Class;
CXXMethodDecl *CallOperator;
@@ -744,8 +815,8 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
bool ExplicitResultType;
bool LambdaExprNeedsCleanups;
bool ContainsUnexpandedParameterPack;
- llvm::SmallVector<VarDecl *, 4> ArrayIndexVars;
- llvm::SmallVector<unsigned, 4> ArrayIndexStarts;
+ SmallVector<VarDecl *, 4> ArrayIndexVars;
+ SmallVector<unsigned, 4> ArrayIndexStarts;
{
LambdaScopeInfo *LSI = getCurLambda();
CallOperator = LSI->CallOperator;
@@ -821,8 +892,8 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
= CallOperator->getType()->getAs<FunctionProtoType>();
QualType FunctionTy
= Context.getFunctionType(LSI->ReturnType,
- Proto->arg_type_begin(),
- Proto->getNumArgs(),
+ ArrayRef<QualType>(Proto->arg_type_begin(),
+ Proto->getNumArgs()),
Proto->getExtProtoInfo());
CallOperator->setType(FunctionTy);
}
@@ -902,8 +973,8 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation,
CXXRecordDecl *Lambda = Conv->getParent();
CXXMethodDecl *CallOperator
= cast<CXXMethodDecl>(
- *Lambda->lookup(
- Context.DeclarationNames.getCXXOperatorName(OO_Call)).first);
+ Lambda->lookup(
+ Context.DeclarationNames.getCXXOperatorName(OO_Call)).front());
CallOperator->setReferenced();
CallOperator->setUsed();
@@ -937,7 +1008,6 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation,
From->getType(),
From->getTypeSourceInfo(),
From->getStorageClass(),
- From->getStorageClassAsWritten(),
/*DefaultArg=*/0));
}
Block->setParams(BlockParams);
@@ -952,7 +1022,7 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation,
VarDecl *CapVar = VarDecl::Create(Context, Block, ConvLocation,
ConvLocation, 0,
Src->getType(), CapVarTSI,
- SC_None, SC_None);
+ SC_None);
BlockDecl::Capture Capture(/*Variable=*/CapVar, /*ByRef=*/false,
/*Nested=*/false, /*Copy=*/Init.take());
Block->setCaptures(Context, &Capture, &Capture + 1,
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index f6987e7..f26b8ed 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -11,16 +11,7 @@
// Objective-C++.
//
//===----------------------------------------------------------------------===//
-#include "clang/Sema/Sema.h"
-#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Lookup.h"
-#include "clang/Sema/Overload.h"
-#include "clang/Sema/DeclSpec.h"
-#include "clang/Sema/Scope.h"
-#include "clang/Sema/ScopeInfo.h"
-#include "clang/Sema/TemplateDeduction.h"
-#include "clang/Sema/ExternalSemaSource.h"
-#include "clang/Sema/TypoCorrection.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Decl.h"
@@ -32,8 +23,17 @@
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/LangOptions.h"
-#include "llvm/ADT/SetVector.h"
+#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/ExternalSemaSource.h"
+#include "clang/Sema/Overload.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/TemplateDeduction.h"
+#include "clang/Sema/TypoCorrection.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/TinyPtrVector.h"
@@ -287,10 +287,10 @@ void LookupResult::configure() {
IDNS = getIDNS(LookupKind, SemaRef.getLangOpts().CPlusPlus,
isForRedeclaration());
- // If we're looking for one of the allocation or deallocation
- // operators, make sure that the implicitly-declared new and delete
- // operators can be found.
if (!isForRedeclaration()) {
+ // If we're looking for one of the allocation or deallocation
+ // operators, make sure that the implicitly-declared new and delete
+ // operators can be found.
switch (NameInfo.getName().getCXXOverloadedOperator()) {
case OO_New:
case OO_Delete:
@@ -302,6 +302,15 @@ void LookupResult::configure() {
default:
break;
}
+
+ // Compiler builtins are always visible, regardless of where they end
+ // up being declared.
+ if (IdentifierInfo *Id = NameInfo.getName().getAsIdentifierInfo()) {
+ if (unsigned BuiltinID = Id->getBuiltinID()) {
+ if (!SemaRef.Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
+ AllowHidden = true;
+ }
+ }
}
}
@@ -371,6 +380,12 @@ void LookupResult::resolveKind() {
NamedDecl *D = Decls[I]->getUnderlyingDecl();
D = cast<NamedDecl>(D->getCanonicalDecl());
+ // Ignore an invalid declaration unless it's the only one left.
+ if (D->isInvalidDecl() && I < N-1) {
+ Decls[I] = Decls[--N];
+ continue;
+ }
+
// Redeclarations of types via typedef can occur both within a scope
// and, through using declarations and directives, across scopes. There is
// no ambiguity if they all refer to the same type, so unique based on the
@@ -451,9 +466,9 @@ void LookupResult::resolveKind() {
void LookupResult::addDeclsFromBasePaths(const CXXBasePaths &P) {
CXXBasePaths::const_paths_iterator I, E;
- DeclContext::lookup_iterator DI, DE;
for (I = P.begin(), E = P.end(); I != E; ++I)
- for (llvm::tie(DI,DE) = I->Decls; DI != DE; ++DI)
+ for (DeclContext::lookup_iterator DI = I->Decls.begin(),
+ DE = I->Decls.end(); DI != DE; ++DI)
addDecl(*DI);
}
@@ -528,22 +543,17 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) {
/// \brief Determine whether we can declare a special member function within
/// the class at this point.
-static bool CanDeclareSpecialMemberFunction(ASTContext &Context,
- const CXXRecordDecl *Class) {
+static bool CanDeclareSpecialMemberFunction(const CXXRecordDecl *Class) {
// We need to have a definition for the class.
if (!Class->getDefinition() || Class->isDependentContext())
return false;
// We can't be in the middle of defining the class.
- if (const RecordType *RecordTy
- = Context.getTypeDeclType(Class)->getAs<RecordType>())
- return !RecordTy->isBeingDefined();
-
- return false;
+ return !Class->isBeingDefined();
}
void Sema::ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class) {
- if (!CanDeclareSpecialMemberFunction(Context, Class))
+ if (!CanDeclareSpecialMemberFunction(Class))
return;
// If the default constructor has not yet been declared, do so now.
@@ -551,14 +561,14 @@ void Sema::ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class) {
DeclareImplicitDefaultConstructor(Class);
// If the copy constructor has not yet been declared, do so now.
- if (!Class->hasDeclaredCopyConstructor())
+ if (Class->needsImplicitCopyConstructor())
DeclareImplicitCopyConstructor(Class);
// If the copy assignment operator has not yet been declared, do so now.
- if (!Class->hasDeclaredCopyAssignment())
+ if (Class->needsImplicitCopyAssignment())
DeclareImplicitCopyAssignment(Class);
- if (getLangOpts().CPlusPlus0x) {
+ if (getLangOpts().CPlusPlus11) {
// If the move constructor has not yet been declared, do so now.
if (Class->needsImplicitMoveConstructor())
DeclareImplicitMoveConstructor(Class); // might not actually do it
@@ -569,7 +579,7 @@ void Sema::ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class) {
}
// If the destructor has not yet been declared, do so now.
- if (!Class->hasDeclaredDestructor())
+ if (Class->needsImplicitDestructor())
DeclareImplicitDestructor(Class);
}
@@ -602,14 +612,13 @@ static void DeclareImplicitMemberFunctionsWithName(Sema &S,
switch (Name.getNameKind()) {
case DeclarationName::CXXConstructorName:
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC))
- if (Record->getDefinition() &&
- CanDeclareSpecialMemberFunction(S.Context, Record)) {
+ if (Record->getDefinition() && CanDeclareSpecialMemberFunction(Record)) {
CXXRecordDecl *Class = const_cast<CXXRecordDecl *>(Record);
if (Record->needsImplicitDefaultConstructor())
S.DeclareImplicitDefaultConstructor(Class);
- if (!Record->hasDeclaredCopyConstructor())
+ if (Record->needsImplicitCopyConstructor())
S.DeclareImplicitCopyConstructor(Class);
- if (S.getLangOpts().CPlusPlus0x &&
+ if (S.getLangOpts().CPlusPlus11 &&
Record->needsImplicitMoveConstructor())
S.DeclareImplicitMoveConstructor(Class);
}
@@ -617,8 +626,8 @@ static void DeclareImplicitMemberFunctionsWithName(Sema &S,
case DeclarationName::CXXDestructorName:
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC))
- if (Record->getDefinition() && !Record->hasDeclaredDestructor() &&
- CanDeclareSpecialMemberFunction(S.Context, Record))
+ if (Record->getDefinition() && Record->needsImplicitDestructor() &&
+ CanDeclareSpecialMemberFunction(Record))
S.DeclareImplicitDestructor(const_cast<CXXRecordDecl *>(Record));
break;
@@ -627,12 +636,11 @@ static void DeclareImplicitMemberFunctionsWithName(Sema &S,
break;
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC)) {
- if (Record->getDefinition() &&
- CanDeclareSpecialMemberFunction(S.Context, Record)) {
+ if (Record->getDefinition() && CanDeclareSpecialMemberFunction(Record)) {
CXXRecordDecl *Class = const_cast<CXXRecordDecl *>(Record);
- if (!Record->hasDeclaredCopyAssignment())
+ if (Record->needsImplicitCopyAssignment())
S.DeclareImplicitCopyAssignment(Class);
- if (S.getLangOpts().CPlusPlus0x &&
+ if (S.getLangOpts().CPlusPlus11 &&
Record->needsImplicitMoveAssignment())
S.DeclareImplicitMoveAssignment(Class);
}
@@ -654,8 +662,9 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
DeclareImplicitMemberFunctionsWithName(S, R.getLookupName(), DC);
// Perform lookup into this declaration context.
- DeclContext::lookup_const_iterator I, E;
- for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I) {
+ DeclContext::lookup_const_result DR = DC->lookup(R.getLookupName());
+ for (DeclContext::lookup_const_iterator I = DR.begin(), E = DR.end(); I != E;
+ ++I) {
NamedDecl *D = *I;
if ((D = R.getAcceptableDecl(D))) {
R.addDecl(D);
@@ -680,9 +689,8 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
if (!Record->isCompleteDefinition())
return Found;
- const UnresolvedSetImpl *Unresolved = Record->getConversionFunctions();
- for (UnresolvedSetImpl::iterator U = Unresolved->begin(),
- UEnd = Unresolved->end(); U != UEnd; ++U) {
+ for (CXXRecordDecl::conversion_iterator U = Record->conversion_begin(),
+ UEnd = Record->conversion_end(); U != UEnd; ++U) {
FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(*U);
if (!ConvTemplate)
continue;
@@ -723,7 +731,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
EPI.NumExceptions = 0;
QualType ExpectedType
= R.getSema().Context.getFunctionType(R.getLookupName().getCXXNameType(),
- 0, 0, EPI);
+ ArrayRef<QualType>(), EPI);
// Perform template argument deduction against the type that we would
// expect the function to have.
@@ -946,6 +954,21 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
continue;
}
+ // If this is a file context, we need to perform unqualified name
+ // lookup considering using directives.
+ if (Ctx->isFileContext()) {
+ UnqualUsingDirectiveSet UDirs;
+ UDirs.visit(Ctx, Ctx);
+ UDirs.done();
+
+ if (CppNamespaceLookup(*this, R, Context, Ctx, UDirs)) {
+ R.resolveKind();
+ return true;
+ }
+
+ continue;
+ }
+
// Perform qualified name lookup into this context.
// FIXME: In some cases, we know that every name that could be found by
// this qualified name lookup will also be on the identifier chain. For
@@ -980,7 +1003,6 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
// Unqualified name lookup in C++ requires looking into scopes
// that aren't strictly lexical, and therefore we walk through the
// context as well as walking through the scopes.
-
for (; S; S = S->getParent()) {
// Check whether the IdResolver has anything in this scope.
bool Found = false;
@@ -1344,7 +1366,7 @@ static bool LookupAnyMember(const CXXBaseSpecifier *Specifier,
DeclarationName N = DeclarationName::getFromOpaquePtr(Name);
Path.Decls = BaseRecord->lookup(N);
- return Path.Decls.first != Path.Decls.second;
+ return !Path.Decls.empty();
}
/// \brief Determine whether the given set of member declarations contains only
@@ -1530,13 +1552,13 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
// We found members of the given name in two subobjects of
// different types. If the declaration sets aren't the same, this
// this lookup is ambiguous.
- if (HasOnlyStaticMembers(Path->Decls.first, Path->Decls.second)) {
+ if (HasOnlyStaticMembers(Path->Decls.begin(), Path->Decls.end())) {
CXXBasePaths::paths_iterator FirstPath = Paths.begin();
- DeclContext::lookup_iterator FirstD = FirstPath->Decls.first;
- DeclContext::lookup_iterator CurrentD = Path->Decls.first;
+ DeclContext::lookup_iterator FirstD = FirstPath->Decls.begin();
+ DeclContext::lookup_iterator CurrentD = Path->Decls.begin();
- while (FirstD != FirstPath->Decls.second &&
- CurrentD != Path->Decls.second) {
+ while (FirstD != FirstPath->Decls.end() &&
+ CurrentD != Path->Decls.end()) {
if ((*FirstD)->getUnderlyingDecl()->getCanonicalDecl() !=
(*CurrentD)->getUnderlyingDecl()->getCanonicalDecl())
break;
@@ -1545,8 +1567,8 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
++CurrentD;
}
- if (FirstD == FirstPath->Decls.second &&
- CurrentD == Path->Decls.second)
+ if (FirstD == FirstPath->Decls.end() &&
+ CurrentD == Path->Decls.end())
continue;
}
@@ -1561,7 +1583,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
// A static member, a nested type or an enumerator defined in
// a base class T can unambiguously be found even if an object
// has more than one base class subobject of type T.
- if (HasOnlyStaticMembers(Path->Decls.first, Path->Decls.second))
+ if (HasOnlyStaticMembers(Path->Decls.begin(), Path->Decls.end()))
continue;
// We have found a nonstatic member name in multiple, distinct
@@ -1573,8 +1595,8 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
// Lookup in a base class succeeded; return these results.
- DeclContext::lookup_iterator I, E;
- for (llvm::tie(I,E) = Paths.front().Decls; I != E; ++I) {
+ DeclContext::lookup_result DR = Paths.front().Decls;
+ for (DeclContext::lookup_iterator I = DR.begin(), E = DR.end(); I != E; ++I) {
NamedDecl *D = *I;
AccessSpecifier AS = CXXRecordDecl::MergeAccess(SubobjectAccess,
D->getAccess());
@@ -1655,7 +1677,7 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) {
<< Name << SubobjectType << getAmbiguousPathsDisplayString(*Paths)
<< LookupRange;
- DeclContext::lookup_iterator Found = Paths->front().Decls.first;
+ DeclContext::lookup_iterator Found = Paths->front().Decls.begin();
while (isa<CXXMethodDecl>(*Found) &&
cast<CXXMethodDecl>(*Found)->isStatic())
++Found;
@@ -1674,7 +1696,7 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) {
for (CXXBasePaths::paths_iterator Path = Paths->begin(),
PathEnd = Paths->end();
Path != PathEnd; ++Path) {
- Decl *D = *Path->Decls.first;
+ Decl *D = Path->Decls.front();
if (DeclsPrinted.insert(D).second)
Diag(D->getLocation(), diag::note_ambiguous_member_found);
}
@@ -2233,9 +2255,9 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
bool RValueThis,
bool ConstThis,
bool VolatileThis) {
- RD = RD->getDefinition();
- assert((RD && !RD->isBeingDefined()) &&
+ assert(CanDeclareSpecialMemberFunction(RD) &&
"doing special member lookup into record that isn't fully complete");
+ RD = RD->getDefinition();
if (RValueThis || ConstThis || VolatileThis)
assert((SM == CXXCopyAssignment || SM == CXXMoveAssignment) &&
"constructors and destructors always have unqualified lvalue this");
@@ -2265,7 +2287,7 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
SpecialMemberCache.InsertNode(Result, InsertPoint);
if (SM == CXXDestructor) {
- if (!RD->hasDeclaredDestructor())
+ if (RD->needsImplicitDestructor())
DeclareImplicitDestructor(RD);
CXXDestructorDecl *DD = RD->getDestructor();
assert(DD && "record without a destructor");
@@ -2294,15 +2316,15 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
} else {
if (SM == CXXCopyConstructor || SM == CXXMoveConstructor) {
Name = Context.DeclarationNames.getCXXConstructorName(CanTy);
- if (!RD->hasDeclaredCopyConstructor())
+ if (RD->needsImplicitCopyConstructor())
DeclareImplicitCopyConstructor(RD);
- if (getLangOpts().CPlusPlus0x && RD->needsImplicitMoveConstructor())
+ if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveConstructor())
DeclareImplicitMoveConstructor(RD);
} else {
Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
- if (!RD->hasDeclaredCopyAssignment())
+ if (RD->needsImplicitCopyAssignment())
DeclareImplicitCopyAssignment(RD);
- if (getLangOpts().CPlusPlus0x && RD->needsImplicitMoveAssignment())
+ if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveAssignment())
DeclareImplicitMoveAssignment(RD);
}
@@ -2345,12 +2367,11 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
// resolution. Lookup is only performed directly into the class since there
// will always be a (possibly implicit) declaration to shadow any others.
OverloadCandidateSet OCS((SourceLocation()));
- DeclContext::lookup_iterator I, E;
+ DeclContext::lookup_result R = RD->lookup(Name);
- llvm::tie(I, E) = RD->lookup(Name);
- assert((I != E) &&
+ assert(!R.empty() &&
"lookup for a constructor or assignment operator was empty");
- for ( ; I != E; ++I) {
+ for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E; ++I) {
Decl *Cand = *I;
if (Cand->isInvalidDecl())
@@ -2451,12 +2472,12 @@ CXXConstructorDecl *Sema::LookupMovingConstructor(CXXRecordDecl *Class,
/// \brief Look up the constructors for the given class.
DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) {
// If the implicit constructors have not yet been declared, do so now.
- if (CanDeclareSpecialMemberFunction(Context, Class)) {
+ if (CanDeclareSpecialMemberFunction(Class)) {
if (Class->needsImplicitDefaultConstructor())
DeclareImplicitDefaultConstructor(Class);
- if (!Class->hasDeclaredCopyConstructor())
+ if (Class->needsImplicitCopyConstructor())
DeclareImplicitCopyConstructor(Class);
- if (getLangOpts().CPlusPlus0x && Class->needsImplicitMoveConstructor())
+ if (getLangOpts().CPlusPlus11 && Class->needsImplicitMoveConstructor())
DeclareImplicitMoveConstructor(Class);
}
@@ -2544,7 +2565,7 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
if (FD->getNumParams() == 1 &&
FD->getParamDecl(0)->getType()->getAs<PointerType>())
IsRaw = true;
- else {
+ else if (FD->getNumParams() == ArgTys.size()) {
IsExactMatch = true;
for (unsigned ArgIdx = 0; ArgIdx != ArgTys.size(); ++ArgIdx) {
QualType ParamTy = FD->getParamDecl(ArgIdx)->getType();
@@ -2690,8 +2711,9 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
// associated classes are visible within their respective
// namespaces even if they are not visible during an ordinary
// lookup (11.4).
- DeclContext::lookup_iterator I, E;
- for (llvm::tie(I, E) = (*NS)->lookup(Name); I != E; ++I) {
+ DeclContext::lookup_result R = (*NS)->lookup(Name);
+ for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E;
+ ++I) {
NamedDecl *D = *I;
// If the only declaration here is an ordinary friend, consider
// it only if it was declared in an associated classes.
@@ -2850,8 +2872,10 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
for (DeclContext::all_lookups_iterator L = Ctx->lookups_begin(),
LEnd = Ctx->lookups_end();
L != LEnd; ++L) {
- for (DeclContext::lookup_result R = *L; R.first != R.second; ++R.first) {
- if (NamedDecl *ND = dyn_cast<NamedDecl>(*R.first)) {
+ DeclContext::lookup_result R = *L;
+ for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E;
+ ++I) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(*I)) {
if ((ND = Result.getAcceptableDecl(ND))) {
Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
Visited.add(ND);
@@ -2918,10 +2942,12 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
// Traverse the contexts of Objective-C classes.
if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Ctx)) {
// Traverse categories.
- for (ObjCCategoryDecl *Category = IFace->getCategoryList();
- Category; Category = Category->getNextClassCategory()) {
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = IFace->visible_categories_begin(),
+ CatEnd = IFace->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
ShadowContextRAII Shadow(Visited);
- LookupVisibleDecls(Category, Result, QualifiedNameLookup, false,
+ LookupVisibleDecls(*Cat, Result, QualifiedNameLookup, false,
Consumer, Visited);
}
@@ -3135,7 +3161,7 @@ LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc,
namespace {
-typedef llvm::SmallVector<TypoCorrection, 1> TypoResultList;
+typedef SmallVector<TypoCorrection, 1> TypoResultList;
typedef llvm::StringMap<TypoResultList, llvm::BumpPtrAllocator> TypoResultsMap;
typedef std::map<unsigned, TypoResultsMap> TypoEditDistanceMap;
@@ -3560,7 +3586,7 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
Consumer.addKeywordResult("typename");
Consumer.addKeywordResult("wchar_t");
- if (SemaRef.getLangOpts().CPlusPlus0x) {
+ if (SemaRef.getLangOpts().CPlusPlus11) {
Consumer.addKeywordResult("char16_t");
Consumer.addKeywordResult("char32_t");
Consumer.addKeywordResult("constexpr");
@@ -3599,7 +3625,7 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
cast<CXXMethodDecl>(SemaRef.CurContext)->isInstance())
Consumer.addKeywordResult("this");
- if (SemaRef.getLangOpts().CPlusPlus0x) {
+ if (SemaRef.getLangOpts().CPlusPlus11) {
Consumer.addKeywordResult("alignof");
Consumer.addKeywordResult("nullptr");
}
@@ -3656,7 +3682,7 @@ static void AddKeywordsToConsumer(Sema &SemaRef,
if (SemaRef.getLangOpts().CPlusPlus) {
Consumer.addKeywordResult("using");
- if (SemaRef.getLangOpts().CPlusPlus0x)
+ if (SemaRef.getLangOpts().CPlusPlus11)
Consumer.addKeywordResult("static_assert");
}
}
@@ -3731,6 +3757,17 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
if (!ActiveTemplateInstantiations.empty())
return TypoCorrection();
+ // Don't try to correct 'super'.
+ if (S && S->isInObjcMethodScope() && Typo == getSuperIdentifier())
+ return TypoCorrection();
+
+ // This is for testing.
+ if (Diags.getWarnOnSpellCheck()) {
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Warning,
+ "spell-checking initiated for %0");
+ Diag(TypoName.getLoc(), DiagID) << TypoName.getName();
+ }
+
NamespaceSpecifierSet Namespaces(Context, CurContext, SS);
TypoCorrectionConsumer Consumer(*this, Typo);
@@ -3860,7 +3897,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
KnownNamespaces[ExternalKnownNamespaces[I]] = true;
}
- for (llvm::DenseMap<NamespaceDecl*, bool>::iterator
+ for (llvm::MapVector<NamespaceDecl*, bool>::iterator
KNI = KnownNamespaces.begin(),
KNIEnd = KnownNamespaces.end();
KNI != KNIEnd; ++KNI)
@@ -3869,7 +3906,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
// Weed out any names that could not be found by name lookup or, if a
// CorrectionCandidateCallback object was provided, failed validation.
- llvm::SmallVector<TypoCorrection, 16> QualifiedResults;
+ SmallVector<TypoCorrection, 16> QualifiedResults;
LookupResult TmpRes(*this, TypoName, LookupKind);
TmpRes.suppressDiagnostics();
while (!Consumer.empty()) {
@@ -3971,9 +4008,9 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
// Only perform the qualified lookups for C++
if (SearchNamespaces) {
TmpRes.suppressDiagnostics();
- for (llvm::SmallVector<TypoCorrection,
- 16>::iterator QRI = QualifiedResults.begin(),
- QRIEnd = QualifiedResults.end();
+ for (SmallVector<TypoCorrection,
+ 16>::iterator QRI = QualifiedResults.begin(),
+ QRIEnd = QualifiedResults.end();
QRI != QRIEnd; ++QRI) {
for (NamespaceSpecifierSet::iterator NI = Namespaces.begin(),
NIEnd = Namespaces.end();
@@ -4094,7 +4131,7 @@ void TypoCorrection::addCorrectionDecl(NamedDecl *CDecl) {
if (isKeyword())
CorrectionDecls.clear();
- CorrectionDecls.push_back(CDecl);
+ CorrectionDecls.push_back(CDecl->getUnderlyingDecl());
if (!CorrectionName)
CorrectionName = CDecl->getDeclName();
@@ -4111,3 +4148,21 @@ std::string TypoCorrection::getAsString(const LangOptions &LO) const {
return CorrectionName.getAsString();
}
+
+bool CorrectionCandidateCallback::ValidateCandidate(const TypoCorrection &candidate) {
+ if (!candidate.isResolved())
+ return true;
+
+ if (candidate.isKeyword())
+ return WantTypeSpecifiers || WantExpressionKeywords || WantCXXNamedCasts ||
+ WantRemainingKeywords || WantObjCSuper;
+
+ for (TypoCorrection::const_decl_iterator CDecl = candidate.begin(),
+ CDeclEnd = candidate.end();
+ CDecl != CDeclEnd; ++CDecl) {
+ if (!isa<TypeDecl>(*CDecl))
+ return true;
+ }
+
+ return WantTypeSpecifiers;
+}
diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp
index 8d70860..c348a9c 100644
--- a/lib/Sema/SemaObjCProperty.cpp
+++ b/lib/Sema/SemaObjCProperty.cpp
@@ -13,16 +13,16 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Initialization.h"
+#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/DeclObjC.h"
-#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprCXX.h"
-#include "clang/AST/ASTMutationListener.h"
-#include "clang/Lex/Lexer.h"
+#include "clang/AST/ExprObjC.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Initialization.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallString.h"
-#include "clang/Lex/Preprocessor.h"
using namespace clang;
@@ -112,6 +112,33 @@ static unsigned deduceWeakPropertyFromType(Sema &S, QualType T) {
return 0;
}
+/// \brief Check this Objective-C property against a property declared in the
+/// given protocol.
+static void
+CheckPropertyAgainstProtocol(Sema &S, ObjCPropertyDecl *Prop,
+ ObjCProtocolDecl *Proto,
+ llvm::SmallPtrSet<ObjCProtocolDecl *, 16> &Known) {
+ // Have we seen this protocol before?
+ if (!Known.insert(Proto))
+ return;
+
+ // Look for a property with the same name.
+ DeclContext::lookup_result R = Proto->lookup(Prop->getDeclName());
+ for (unsigned I = 0, N = R.size(); I != N; ++I) {
+ if (ObjCPropertyDecl *ProtoProp = dyn_cast<ObjCPropertyDecl>(R[I])) {
+ S.DiagnosePropertyMismatch(Prop, ProtoProp, Proto->getIdentifier());
+ return;
+ }
+ }
+
+ // Check this property against any protocols we inherit.
+ for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(),
+ PEnd = Proto->protocol_end();
+ P != PEnd; ++P) {
+ CheckPropertyAgainstProtocol(S, Prop, *P, Known);
+ }
+}
+
Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
SourceLocation LParenLoc,
FieldDeclarator &FD,
@@ -139,34 +166,31 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
!(Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) &&
!(Attributes & ObjCDeclSpec::DQ_PR_weak)));
- // Proceed with constructing the ObjCPropertDecls.
+ // Proceed with constructing the ObjCPropertyDecls.
ObjCContainerDecl *ClassDecl = cast<ObjCContainerDecl>(CurContext);
- if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl))
+ ObjCPropertyDecl *Res = 0;
+ if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
if (CDecl->IsClassExtension()) {
- Decl *Res = HandlePropertyInClassExtension(S, AtLoc, LParenLoc,
+ Res = HandlePropertyInClassExtension(S, AtLoc, LParenLoc,
FD, GetterSel, SetterSel,
isAssign, isReadWrite,
Attributes,
ODS.getPropertyAttributes(),
isOverridingProperty, TSI,
MethodImplKind);
- if (Res) {
- CheckObjCPropertyAttributes(Res, AtLoc, Attributes, false);
- if (getLangOpts().ObjCAutoRefCount)
- checkARCPropertyDecl(*this, cast<ObjCPropertyDecl>(Res));
- }
- ActOnDocumentableDecl(Res);
- return Res;
+ if (!Res)
+ return 0;
}
-
- ObjCPropertyDecl *Res = CreatePropertyDecl(S, ClassDecl, AtLoc, LParenLoc, FD,
- GetterSel, SetterSel,
- isAssign, isReadWrite,
- Attributes,
- ODS.getPropertyAttributes(),
- TSI, MethodImplKind);
- if (lexicalDC)
- Res->setLexicalDeclContext(lexicalDC);
+ }
+
+ if (!Res) {
+ Res = CreatePropertyDecl(S, ClassDecl, AtLoc, LParenLoc, FD,
+ GetterSel, SetterSel, isAssign, isReadWrite,
+ Attributes, ODS.getPropertyAttributes(),
+ TSI, MethodImplKind);
+ if (lexicalDC)
+ Res->setLexicalDeclContext(lexicalDC);
+ }
// Validate the attributes on the @property.
CheckObjCPropertyAttributes(Res, AtLoc, Attributes,
@@ -176,6 +200,52 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
if (getLangOpts().ObjCAutoRefCount)
checkARCPropertyDecl(*this, Res);
+ llvm::SmallPtrSet<ObjCProtocolDecl *, 16> KnownProtos;
+ if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) {
+ // For a class, compare the property against a property in our superclass.
+ bool FoundInSuper = false;
+ if (ObjCInterfaceDecl *Super = IFace->getSuperClass()) {
+ DeclContext::lookup_result R = Super->lookup(Res->getDeclName());
+ for (unsigned I = 0, N = R.size(); I != N; ++I) {
+ if (ObjCPropertyDecl *SuperProp = dyn_cast<ObjCPropertyDecl>(R[I])) {
+ DiagnosePropertyMismatch(Res, SuperProp, Super->getIdentifier());
+ FoundInSuper = true;
+ break;
+ }
+ }
+ }
+
+ if (FoundInSuper) {
+ // Also compare the property against a property in our protocols.
+ for (ObjCInterfaceDecl::protocol_iterator P = IFace->protocol_begin(),
+ PEnd = IFace->protocol_end();
+ P != PEnd; ++P) {
+ CheckPropertyAgainstProtocol(*this, Res, *P, KnownProtos);
+ }
+ } else {
+ // Slower path: look in all protocols we referenced.
+ for (ObjCInterfaceDecl::all_protocol_iterator
+ P = IFace->all_referenced_protocol_begin(),
+ PEnd = IFace->all_referenced_protocol_end();
+ P != PEnd; ++P) {
+ CheckPropertyAgainstProtocol(*this, Res, *P, KnownProtos);
+ }
+ }
+ } else if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
+ for (ObjCCategoryDecl::protocol_iterator P = Cat->protocol_begin(),
+ PEnd = Cat->protocol_end();
+ P != PEnd; ++P) {
+ CheckPropertyAgainstProtocol(*this, Res, *P, KnownProtos);
+ }
+ } else {
+ ObjCProtocolDecl *Proto = cast<ObjCProtocolDecl>(ClassDecl);
+ for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(),
+ PEnd = Proto->protocol_end();
+ P != PEnd; ++P) {
+ CheckPropertyAgainstProtocol(*this, Res, *P, KnownProtos);
+ }
+ }
+
ActOnDocumentableDecl(Res);
return Res;
}
@@ -251,7 +321,7 @@ static unsigned getOwnershipRule(unsigned attr) {
ObjCPropertyDecl::OBJC_PR_unsafe_unretained);
}
-Decl *
+ObjCPropertyDecl *
Sema::HandlePropertyInClassExtension(Scope *S,
SourceLocation AtLoc,
SourceLocation LParenLoc,
@@ -270,20 +340,22 @@ Sema::HandlePropertyInClassExtension(Scope *S,
IdentifierInfo *PropertyId = FD.D.getIdentifier();
ObjCInterfaceDecl *CCPrimary = CDecl->getClassInterface();
- if (CCPrimary)
+ if (CCPrimary) {
// Check for duplicate declaration of this property in current and
// other class extensions.
- for (const ObjCCategoryDecl *ClsExtDecl =
- CCPrimary->getFirstClassExtension();
- ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) {
- if (ObjCPropertyDecl *prevDecl =
- ObjCPropertyDecl::findPropertyDecl(ClsExtDecl, PropertyId)) {
+ for (ObjCInterfaceDecl::known_extensions_iterator
+ Ext = CCPrimary->known_extensions_begin(),
+ ExtEnd = CCPrimary->known_extensions_end();
+ Ext != ExtEnd; ++Ext) {
+ if (ObjCPropertyDecl *prevDecl
+ = ObjCPropertyDecl::findPropertyDecl(*Ext, PropertyId)) {
Diag(AtLoc, diag::err_duplicate_property);
Diag(prevDecl->getLocation(), diag::note_property_declare);
return 0;
}
}
-
+ }
+
// Create a new ObjCPropertyDecl with the DeclContext being
// the class extension.
// FIXME. We should really be using CreatePropertyDecl for this.
@@ -296,6 +368,10 @@ Sema::HandlePropertyInClassExtension(Scope *S,
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly);
if (Attributes & ObjCDeclSpec::DQ_PR_readwrite)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite);
+ if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic);
+ if (Attributes & ObjCDeclSpec::DQ_PR_atomic)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_atomic);
// Set setter/getter selector name. Needed later.
PDecl->setGetterName(GetterSel);
PDecl->setSetterName(SetterSel);
@@ -577,20 +653,20 @@ static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc,
switch (propertyLifetime) {
case Qualifiers::OCL_Strong:
- S.Diag(propertyImplLoc, diag::err_arc_strong_property_ownership)
+ S.Diag(ivar->getLocation(), diag::err_arc_strong_property_ownership)
<< property->getDeclName()
<< ivar->getDeclName()
<< ivarLifetime;
break;
case Qualifiers::OCL_Weak:
- S.Diag(propertyImplLoc, diag::error_weak_property)
+ S.Diag(ivar->getLocation(), diag::error_weak_property)
<< property->getDeclName()
<< ivar->getDeclName();
break;
case Qualifiers::OCL_ExplicitNone:
- S.Diag(propertyImplLoc, diag::err_arc_assign_property_ownership)
+ S.Diag(ivar->getLocation(), diag::err_arc_assign_property_ownership)
<< property->getDeclName()
<< ivar->getDeclName()
<< ((property->getPropertyAttributesAsWritten()
@@ -606,6 +682,8 @@ static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc,
}
S.Diag(property->getLocation(), diag::note_property_declare);
+ if (propertyImplLoc.isValid())
+ S.Diag(propertyImplLoc, diag::note_property_synthesize);
}
/// setImpliedPropertyAttributeForReadOnlyProperty -
@@ -644,16 +722,18 @@ DiagnoseClassAndClassExtPropertyMismatch(Sema &S, ObjCInterfaceDecl *ClassDecl,
ObjCPropertyDecl *property) {
unsigned Attributes = property->getPropertyAttributesAsWritten();
bool warn = (Attributes & ObjCDeclSpec::DQ_PR_readonly);
- for (const ObjCCategoryDecl *CDecl = ClassDecl->getFirstClassExtension();
- CDecl; CDecl = CDecl->getNextClassExtension()) {
+ for (ObjCInterfaceDecl::known_extensions_iterator
+ Ext = ClassDecl->known_extensions_begin(),
+ ExtEnd = ClassDecl->known_extensions_end();
+ Ext != ExtEnd; ++Ext) {
ObjCPropertyDecl *ClassExtProperty = 0;
- for (ObjCContainerDecl::prop_iterator P = CDecl->prop_begin(),
- E = CDecl->prop_end(); P != E; ++P) {
- if ((*P)->getIdentifier() == property->getIdentifier()) {
- ClassExtProperty = *P;
+ DeclContext::lookup_result R = Ext->lookup(property->getDeclName());
+ for (unsigned I = 0, N = R.size(); I != N; ++I) {
+ ClassExtProperty = dyn_cast<ObjCPropertyDecl>(R[0]);
+ if (ClassExtProperty)
break;
- }
}
+
if (ClassExtProperty) {
warn = false;
unsigned classExtPropertyAttr =
@@ -763,22 +843,40 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
return 0;
}
}
-
if (Synthesize&&
(PIkind & ObjCPropertyDecl::OBJC_PR_readonly) &&
property->hasAttr<IBOutletAttr>() &&
!AtLoc.isValid()) {
- Diag(IC->getLocation(), diag::warn_auto_readonly_iboutlet_property);
- Diag(property->getLocation(), diag::note_property_declare);
- SourceLocation readonlyLoc;
- if (LocPropertyAttribute(Context, "readonly",
- property->getLParenLoc(), readonlyLoc)) {
- SourceLocation endLoc =
- readonlyLoc.getLocWithOffset(strlen("readonly")-1);
- SourceRange ReadonlySourceRange(readonlyLoc, endLoc);
- Diag(property->getLocation(),
- diag::note_auto_readonly_iboutlet_fixup_suggest) <<
- FixItHint::CreateReplacement(ReadonlySourceRange, "readwrite");
+ bool ReadWriteProperty = false;
+ // Search into the class extensions and see if 'readonly property is
+ // redeclared 'readwrite', then no warning is to be issued.
+ for (ObjCInterfaceDecl::known_extensions_iterator
+ Ext = IDecl->known_extensions_begin(),
+ ExtEnd = IDecl->known_extensions_end(); Ext != ExtEnd; ++Ext) {
+ DeclContext::lookup_result R = Ext->lookup(property->getDeclName());
+ if (!R.empty())
+ if (ObjCPropertyDecl *ExtProp = dyn_cast<ObjCPropertyDecl>(R[0])) {
+ PIkind = ExtProp->getPropertyAttributesAsWritten();
+ if (PIkind & ObjCPropertyDecl::OBJC_PR_readwrite) {
+ ReadWriteProperty = true;
+ break;
+ }
+ }
+ }
+
+ if (!ReadWriteProperty) {
+ Diag(property->getLocation(), diag::warn_auto_readonly_iboutlet_property)
+ << property->getName();
+ SourceLocation readonlyLoc;
+ if (LocPropertyAttribute(Context, "readonly",
+ property->getLParenLoc(), readonlyLoc)) {
+ SourceLocation endLoc =
+ readonlyLoc.getLocWithOffset(strlen("readonly")-1);
+ SourceRange ReadonlySourceRange(readonlyLoc, endLoc);
+ Diag(property->getLocation(),
+ diag::note_auto_readonly_iboutlet_fixup_suggest) <<
+ FixItHint::CreateReplacement(ReadonlySourceRange, "readwrite");
+ }
}
}
@@ -1036,6 +1134,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
MarkDeclRefReferenced(SelfExpr);
Expr *IvarRefExpr =
new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), PropertyDiagLoc,
+ Ivar->getLocation(),
SelfExpr, true, true);
ExprResult Res =
PerformCopyInitialization(InitializedEntity::InitializeResult(
@@ -1071,6 +1170,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
MarkDeclRefReferenced(SelfExpr);
Expr *lhs =
new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), PropertyDiagLoc,
+ Ivar->getLocation(),
SelfExpr, true, true);
ObjCMethodDecl::param_iterator P = setterMethod->param_begin();
ParmVarDecl *Param = (*P);
@@ -1198,15 +1298,21 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property,
}
if ((CAttr & ObjCPropertyDecl::OBJC_PR_nonatomic)
- != (SAttr & ObjCPropertyDecl::OBJC_PR_nonatomic))
+ != (SAttr & ObjCPropertyDecl::OBJC_PR_nonatomic)) {
Diag(Property->getLocation(), diag::warn_property_attribute)
<< Property->getDeclName() << "atomic" << inheritedName;
- if (Property->getSetterName() != SuperProperty->getSetterName())
+ Diag(SuperProperty->getLocation(), diag::note_property_declare);
+ }
+ if (Property->getSetterName() != SuperProperty->getSetterName()) {
Diag(Property->getLocation(), diag::warn_property_attribute)
<< Property->getDeclName() << "setter" << inheritedName;
- if (Property->getGetterName() != SuperProperty->getGetterName())
+ Diag(SuperProperty->getLocation(), diag::note_property_declare);
+ }
+ if (Property->getGetterName() != SuperProperty->getGetterName()) {
Diag(Property->getLocation(), diag::warn_property_attribute)
<< Property->getDeclName() << "getter" << inheritedName;
+ Diag(SuperProperty->getLocation(), diag::note_property_declare);
+ }
QualType LHSType =
Context.getCanonicalType(SuperProperty->getType());
@@ -1270,119 +1376,56 @@ bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property,
return false;
}
-/// ComparePropertiesInBaseAndSuper - This routine compares property
-/// declarations in base and its super class, if any, and issues
-/// diagnostics in a variety of inconsistent situations.
-///
-void Sema::ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl) {
- ObjCInterfaceDecl *SDecl = IDecl->getSuperClass();
- if (!SDecl)
- return;
- // FIXME: O(N^2)
- for (ObjCInterfaceDecl::prop_iterator S = SDecl->prop_begin(),
- E = SDecl->prop_end(); S != E; ++S) {
- ObjCPropertyDecl *SuperPDecl = *S;
- // Does property in super class has declaration in current class?
- for (ObjCInterfaceDecl::prop_iterator I = IDecl->prop_begin(),
- E = IDecl->prop_end(); I != E; ++I) {
- ObjCPropertyDecl *PDecl = *I;
- if (SuperPDecl->getIdentifier() == PDecl->getIdentifier())
- DiagnosePropertyMismatch(PDecl, SuperPDecl,
- SDecl->getIdentifier());
- }
- }
-}
-
/// MatchOneProtocolPropertiesInClass - This routine goes thru the list
/// of properties declared in a protocol and compares their attribute against
/// the same property declared in the class or category.
void
-Sema::MatchOneProtocolPropertiesInClass(Decl *CDecl,
- ObjCProtocolDecl *PDecl) {
- ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl);
- if (!IDecl) {
- // Category
- ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl);
+Sema::MatchOneProtocolPropertiesInClass(Decl *CDecl, ObjCProtocolDecl *PDecl) {
+ if (!CDecl)
+ return;
+
+ // Category case.
+ if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) {
+ // FIXME: We should perform this check when the property in the category
+ // is declared.
assert (CatDecl && "MatchOneProtocolPropertiesInClass");
if (!CatDecl->IsClassExtension())
for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
E = PDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Pr = *P;
- ObjCCategoryDecl::prop_iterator CP, CE;
- // Is this property already in category's list of properties?
- for (CP = CatDecl->prop_begin(), CE = CatDecl->prop_end(); CP!=CE; ++CP)
- if (CP->getIdentifier() == Pr->getIdentifier())
- break;
- if (CP != CE)
- // Property protocol already exist in class. Diagnose any mismatch.
- DiagnosePropertyMismatch(*CP, Pr, PDecl->getIdentifier());
+ ObjCPropertyDecl *ProtoProp = *P;
+ DeclContext::lookup_result R
+ = CatDecl->lookup(ProtoProp->getDeclName());
+ for (unsigned I = 0, N = R.size(); I != N; ++I) {
+ if (ObjCPropertyDecl *CatProp = dyn_cast<ObjCPropertyDecl>(R[I])) {
+ if (CatProp != ProtoProp) {
+ // Property protocol already exist in class. Diagnose any mismatch.
+ DiagnosePropertyMismatch(CatProp, ProtoProp,
+ PDecl->getIdentifier());
+ }
+ }
+ }
}
return;
}
- for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
- E = PDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Pr = *P;
- ObjCInterfaceDecl::prop_iterator CP, CE;
- // Is this property already in class's list of properties?
- for (CP = IDecl->prop_begin(), CE = IDecl->prop_end(); CP != CE; ++CP)
- if (CP->getIdentifier() == Pr->getIdentifier())
- break;
- if (CP != CE)
- // Property protocol already exist in class. Diagnose any mismatch.
- DiagnosePropertyMismatch(*CP, Pr, PDecl->getIdentifier());
- }
-}
-/// CompareProperties - This routine compares properties
-/// declared in 'ClassOrProtocol' objects (which can be a class or an
-/// inherited protocol with the list of properties for class/category 'CDecl'
-///
-void Sema::CompareProperties(Decl *CDecl, Decl *ClassOrProtocol) {
- Decl *ClassDecl = ClassOrProtocol;
- ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl);
-
- if (!IDecl) {
- // Category
- ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl);
- assert (CatDecl && "CompareProperties");
- if (ObjCCategoryDecl *MDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
- for (ObjCCategoryDecl::protocol_iterator P = MDecl->protocol_begin(),
- E = MDecl->protocol_end(); P != E; ++P)
- // Match properties of category with those of protocol (*P)
- MatchOneProtocolPropertiesInClass(CatDecl, *P);
-
- // Go thru the list of protocols for this category and recursively match
- // their properties with those in the category.
- for (ObjCCategoryDecl::protocol_iterator P = CatDecl->protocol_begin(),
- E = CatDecl->protocol_end(); P != E; ++P)
- CompareProperties(CatDecl, *P);
- } else {
- ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl);
- for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(),
- E = MD->protocol_end(); P != E; ++P)
- MatchOneProtocolPropertiesInClass(CatDecl, *P);
+ // Class
+ // FIXME: We should perform this check when the property in the class
+ // is declared.
+ ObjCInterfaceDecl *IDecl = cast<ObjCInterfaceDecl>(CDecl);
+ for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
+ E = PDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *ProtoProp = *P;
+ DeclContext::lookup_result R
+ = IDecl->lookup(ProtoProp->getDeclName());
+ for (unsigned I = 0, N = R.size(); I != N; ++I) {
+ if (ObjCPropertyDecl *ClassProp = dyn_cast<ObjCPropertyDecl>(R[I])) {
+ if (ClassProp != ProtoProp) {
+ // Property protocol already exist in class. Diagnose any mismatch.
+ DiagnosePropertyMismatch(ClassProp, ProtoProp,
+ PDecl->getIdentifier());
+ }
+ }
}
- return;
- }
-
- if (ObjCInterfaceDecl *MDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) {
- for (ObjCInterfaceDecl::all_protocol_iterator
- P = MDecl->all_referenced_protocol_begin(),
- E = MDecl->all_referenced_protocol_end(); P != E; ++P)
- // Match properties of class IDecl with those of protocol (*P).
- MatchOneProtocolPropertiesInClass(IDecl, *P);
-
- // Go thru the list of protocols for this class and recursively match
- // their properties with those declared in the class.
- for (ObjCInterfaceDecl::all_protocol_iterator
- P = IDecl->all_referenced_protocol_begin(),
- E = IDecl->all_referenced_protocol_end(); P != E; ++P)
- CompareProperties(IDecl, *P);
- } else {
- ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl);
- for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(),
- E = MD->protocol_end(); P != E; ++P)
- MatchOneProtocolPropertiesInClass(IDecl, *P);
}
}
@@ -1402,14 +1445,14 @@ bool Sema::isPropertyReadonly(ObjCPropertyDecl *PDecl,
// Main class has the property as 'readonly'. Must search
// through the category list to see if the property's
// attribute has been over-ridden to 'readwrite'.
- for (ObjCCategoryDecl *Category = IDecl->getCategoryList();
- Category; Category = Category->getNextClassCategory()) {
- // Even if property is ready only, if a category has a user defined setter,
- // it is not considered read only.
- if (Category->getInstanceMethod(PDecl->getSetterName()))
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = IDecl->visible_categories_begin(),
+ CatEnd = IDecl->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
+ if (Cat->getInstanceMethod(PDecl->getSetterName()))
return false;
ObjCPropertyDecl *P =
- Category->FindPropertyDeclaration(PDecl->getIdentifier());
+ Cat->FindPropertyDeclaration(PDecl->getIdentifier());
if (P && !P->isReadOnly())
return false;
}
@@ -1438,7 +1481,7 @@ 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.
+/// the class and its conforming protocols; but not those in its super class.
void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
ObjCContainerDecl::PropertyMap &PropMap,
ObjCContainerDecl::PropertyMap &SuperPropMap) {
@@ -1493,36 +1536,84 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
static void CollectSuperClassPropertyImplementations(ObjCInterfaceDecl *CDecl,
ObjCInterfaceDecl::PropertyMap &PropMap) {
if (ObjCInterfaceDecl *SDecl = CDecl->getSuperClass()) {
+ ObjCInterfaceDecl::PropertyDeclOrder PO;
while (SDecl) {
- SDecl->collectPropertiesToImplement(PropMap);
+ SDecl->collectPropertiesToImplement(PropMap, PO);
SDecl = SDecl->getSuperClass();
}
}
}
+/// IvarBacksCurrentMethodAccessor - This routine returns 'true' if 'IV' is
+/// an ivar synthesized for 'Method' and 'Method' is a property accessor
+/// declared in class 'IFace'.
+bool
+Sema::IvarBacksCurrentMethodAccessor(ObjCInterfaceDecl *IFace,
+ ObjCMethodDecl *Method, ObjCIvarDecl *IV) {
+ if (!IV->getSynthesize())
+ return false;
+ ObjCMethodDecl *IMD = IFace->lookupMethod(Method->getSelector(),
+ Method->isInstanceMethod());
+ if (!IMD || !IMD->isPropertyAccessor())
+ return false;
+
+ // look up a property declaration whose one of its accessors is implemented
+ // by this method.
+ for (ObjCContainerDecl::prop_iterator P = IFace->prop_begin(),
+ E = IFace->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *property = *P;
+ if ((property->getGetterName() == IMD->getSelector() ||
+ property->getSetterName() == IMD->getSelector()) &&
+ (property->getPropertyIvarDecl() == IV))
+ return true;
+ }
+ return false;
+}
+
+
/// \brief Default synthesizes all properties which must be synthesized
/// in class's \@implementation.
void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl,
ObjCInterfaceDecl *IDecl) {
ObjCInterfaceDecl::PropertyMap PropMap;
- IDecl->collectPropertiesToImplement(PropMap);
+ ObjCInterfaceDecl::PropertyDeclOrder PropertyOrder;
+ IDecl->collectPropertiesToImplement(PropMap, PropertyOrder);
if (PropMap.empty())
return;
ObjCInterfaceDecl::PropertyMap SuperPropMap;
CollectSuperClassPropertyImplementations(IDecl, SuperPropMap);
- for (ObjCInterfaceDecl::PropertyMap::iterator
- P = PropMap.begin(), E = PropMap.end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = P->second;
+ for (unsigned i = 0, e = PropertyOrder.size(); i != e; i++) {
+ ObjCPropertyDecl *Prop = PropertyOrder[i];
// If property to be implemented in the super class, ignore.
- if (SuperPropMap[Prop->getIdentifier()])
+ if (SuperPropMap[Prop->getIdentifier()]) {
+ ObjCPropertyDecl *PropInSuperClass = SuperPropMap[Prop->getIdentifier()];
+ if ((Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readwrite) &&
+ (PropInSuperClass->getPropertyAttributes() &
+ ObjCPropertyDecl::OBJC_PR_readonly) &&
+ !IMPDecl->getInstanceMethod(Prop->getSetterName()) &&
+ !IDecl->HasUserDeclaredSetterMethod(Prop)) {
+ Diag(Prop->getLocation(), diag::warn_no_autosynthesis_property)
+ << Prop->getIdentifier()->getName();
+ Diag(PropInSuperClass->getLocation(), diag::note_property_declare);
+ }
continue;
+ }
// Is there a matching property synthesize/dynamic?
if (Prop->isInvalidDecl() ||
- Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||
- IMPDecl->FindPropertyImplIvarDecl(Prop->getIdentifier()))
+ Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional)
continue;
+ if (ObjCPropertyImplDecl *PID =
+ IMPDecl->FindPropertyImplIvarDecl(Prop->getIdentifier())) {
+ if (PID->getPropertyDecl() != Prop) {
+ Diag(Prop->getLocation(), diag::warn_no_autosynthesis_shared_ivar_property)
+ << Prop->getIdentifier()->getName();
+ if (!PID->getLocation().isInvalid())
+ Diag(PID->getLocation(), diag::note_property_synthesize);
+ }
+ continue;
+ }
// Property may have been synthesized by user.
if (IMPDecl->FindPropertyImplDecl(Prop->getIdentifier()))
continue;
@@ -1571,12 +1662,25 @@ void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) {
void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
ObjCContainerDecl *CDecl,
const SelectorSet &InsMap) {
- ObjCContainerDecl::PropertyMap SuperPropMap;
- if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl))
- CollectSuperClassPropertyImplementations(IDecl, SuperPropMap);
+ ObjCContainerDecl::PropertyMap NoNeedToImplPropMap;
+ ObjCInterfaceDecl *IDecl;
+ // Gather properties which need not be implemented in this class
+ // or category.
+ if (!(IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)))
+ if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) {
+ // For categories, no need to implement properties declared in
+ // its primary class (and its super classes) if property is
+ // declared in one of those containers.
+ if ((IDecl = C->getClassInterface())) {
+ ObjCInterfaceDecl::PropertyDeclOrder PO;
+ IDecl->collectPropertiesToImplement(NoNeedToImplPropMap, PO);
+ }
+ }
+ if (IDecl)
+ CollectSuperClassPropertyImplementations(IDecl, NoNeedToImplPropMap);
ObjCContainerDecl::PropertyMap PropMap;
- CollectImmediateProperties(CDecl, PropMap, SuperPropMap);
+ CollectImmediateProperties(CDecl, PropMap, NoNeedToImplPropMap);
if (PropMap.empty())
return;
@@ -1592,7 +1696,8 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
// Is there a matching propery synthesize/dynamic?
if (Prop->isInvalidDecl() ||
Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||
- PropImplMap.count(Prop) || Prop->hasAttr<UnavailableAttr>())
+ PropImplMap.count(Prop) ||
+ Prop->getAvailability() == AR_Unavailable)
continue;
if (!InsMap.count(Prop->getGetterName())) {
Diag(IMPDecl->getLocation(),
@@ -1829,6 +1934,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
if (property->hasAttr<NSReturnsNotRetainedAttr>())
GetterMethod->addAttr(
::new (Context) NSReturnsNotRetainedAttr(Loc, Context));
+
+ if (getLangOpts().ObjCAutoRefCount)
+ CheckARCMethodDecl(GetterMethod);
} else
// A user declared getter will be synthesize when @synthesize of
// the property with the same name is seen in the @implementation
@@ -1866,7 +1974,6 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
property->getType().getUnqualifiedType(),
/*TInfo=*/0,
SC_None,
- SC_None,
0);
SetterMethod->setMethodParams(Context, Argument,
ArrayRef<SourceLocation>());
@@ -1878,6 +1985,11 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
// and the real context should be the same.
if (lexicalDC)
SetterMethod->setLexicalDeclContext(lexicalDC);
+
+ // It's possible for the user to have set a very odd custom
+ // setter selector that causes it to have a method family.
+ if (getLangOpts().ObjCAutoRefCount)
+ CheckARCMethodDecl(SetterMethod);
} else
// A user declared setter will be synthesize when @synthesize of
// the property with the same name is seen in the @implementation
diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp
new file mode 100644
index 0000000..b8acb2d
--- /dev/null
+++ b/lib/Sema/SemaOpenMP.cpp
@@ -0,0 +1,181 @@
+//===--- SemaOpenMP.cpp - Semantic Analysis for OpenMP constructs ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// \brief This file implements semantic analysis for OpenMP directives and
+/// clauses
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/OpenMPKinds.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclOpenMP.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/Lookup.h"
+using namespace clang;
+
+namespace {
+
+ class VarDeclFilterCCC : public CorrectionCandidateCallback {
+ private:
+ Sema &Actions;
+ public:
+ VarDeclFilterCCC(Sema &S) : Actions(S) { }
+ virtual bool ValidateCandidate(const TypoCorrection &Candidate) {
+ NamedDecl *ND = Candidate.getCorrectionDecl();
+ if (VarDecl *VD = dyn_cast_or_null<VarDecl>(ND)) {
+ return VD->hasGlobalStorage() &&
+ Actions.isDeclInScope(ND, Actions.getCurLexicalContext(),
+ Actions.getCurScope());
+ }
+ return false;
+ }
+ };
+}
+Sema::DeclGroupPtrTy Sema::ActOnOpenMPThreadprivateDirective(
+ SourceLocation Loc,
+ Scope *CurScope,
+ ArrayRef<DeclarationNameInfo> IdList) {
+ SmallVector<DeclRefExpr *, 5> Vars;
+ for (ArrayRef<DeclarationNameInfo>::iterator I = IdList.begin(),
+ E = IdList.end();
+ I != E; ++I) {
+ LookupResult Lookup(*this, *I, LookupOrdinaryName);
+ LookupParsedName(Lookup, CurScope, NULL, true);
+
+ if (Lookup.isAmbiguous())
+ continue;
+
+ VarDecl *VD;
+ if (!Lookup.isSingleResult()) {
+ VarDeclFilterCCC Validator(*this);
+ TypoCorrection Corrected = CorrectTypo(*I, LookupOrdinaryName, CurScope,
+ 0, Validator);
+ std::string CorrectedStr = Corrected.getAsString(getLangOpts());
+ std::string CorrectedQuotedStr = Corrected.getQuoted(getLangOpts());
+ if (Lookup.empty()) {
+ if (Corrected.isResolved()) {
+ Diag(I->getLoc(), diag::err_undeclared_var_use_suggest)
+ << I->getName() << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(I->getLoc(), CorrectedStr);
+ } else {
+ Diag(I->getLoc(), diag::err_undeclared_var_use)
+ << I->getName();
+ }
+ } else {
+ Diag(I->getLoc(), diag::err_omp_expected_var_arg_suggest)
+ << I->getName() << Corrected.isResolved() << CorrectedQuotedStr
+ << FixItHint::CreateReplacement(I->getLoc(), CorrectedStr);
+ }
+ if (!Corrected.isResolved()) continue;
+ VD = Corrected.getCorrectionDeclAs<VarDecl>();
+ } else {
+ if (!(VD = Lookup.getAsSingle<VarDecl>())) {
+ Diag(I->getLoc(), diag::err_omp_expected_var_arg_suggest)
+ << I->getName() << 0;
+ Diag(Lookup.getFoundDecl()->getLocation(), diag::note_declared_at);
+ continue;
+ }
+ }
+
+ // OpenMP [2.9.2, Syntax, C/C++]
+ // Variables must be file-scope, namespace-scope, or static block-scope.
+ if (!VD->hasGlobalStorage()) {
+ Diag(I->getLoc(), diag::err_omp_global_var_arg)
+ << getOpenMPDirectiveName(OMPD_threadprivate)
+ << !VD->isStaticLocal();
+ Diag(VD->getLocation(), diag::note_forward_declaration) << VD;
+ continue;
+ }
+
+ // OpenMP [2.9.2, Restrictions, C/C++, p.2]
+ // A threadprivate directive for file-scope variables must appear outside
+ // any definition or declaration.
+ // OpenMP [2.9.2, Restrictions, C/C++, p.3]
+ // A threadprivate directive for static class member variables must appear
+ // in the class definition, in the same scope in which the member
+ // variables are declared.
+ // OpenMP [2.9.2, Restrictions, C/C++, p.4]
+ // A threadprivate directive for namespace-scope variables must appear
+ // outside any definition or declaration other than the namespace
+ // definition itself.
+ // OpenMP [2.9.2, Restrictions, C/C++, p.6]
+ // A threadprivate directive for static block-scope variables must appear
+ // in the scope of the variable and not in a nested scope.
+ NamedDecl *ND = cast<NamedDecl>(VD);
+ if (!isDeclInScope(ND, getCurLexicalContext(), CurScope)) {
+ Diag(I->getLoc(), diag::err_omp_var_scope)
+ << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
+ Diag(VD->getLocation(), diag::note_forward_declaration) << VD;
+ continue;
+ }
+
+ // OpenMP [2.9.2, Restrictions, C/C++, p.2-6]
+ // A threadprivate directive must lexically precede all references to any
+ // of the variables in its list.
+ if (VD->isUsed()) {
+ Diag(I->getLoc(), diag::err_omp_var_used)
+ << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
+ continue;
+ }
+
+ QualType ExprType = VD->getType().getNonReferenceType();
+ DeclRefExpr *Var = cast<DeclRefExpr>(BuildDeclRefExpr(VD,
+ ExprType,
+ VK_RValue,
+ I->getLoc()).take());
+ Vars.push_back(Var);
+ }
+ if (OMPThreadPrivateDecl *D = CheckOMPThreadPrivateDecl(Loc, Vars)) {
+ CurContext->addDecl(D);
+ return DeclGroupPtrTy::make(DeclGroupRef(D));
+ }
+ return DeclGroupPtrTy();
+}
+
+OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl(
+ SourceLocation Loc,
+ ArrayRef<DeclRefExpr *> VarList) {
+ SmallVector<DeclRefExpr *, 5> Vars;
+ for (ArrayRef<DeclRefExpr *>::iterator I = VarList.begin(),
+ E = VarList.end();
+ I != E; ++I) {
+ VarDecl *VD = cast<VarDecl>((*I)->getDecl());
+ SourceLocation ILoc = (*I)->getLocation();
+
+ // OpenMP [2.9.2, Restrictions, C/C++, p.10]
+ // A threadprivate variable must not have an incomplete type.
+ if (RequireCompleteType(ILoc, VD->getType(),
+ diag::err_omp_incomplete_type)) {
+ continue;
+ }
+
+ // OpenMP [2.9.2, Restrictions, C/C++, p.10]
+ // A threadprivate variable must not have a reference type.
+ if (VD->getType()->isReferenceType()) {
+ Diag(ILoc, diag::err_omp_ref_type_arg)
+ << getOpenMPDirectiveName(OMPD_threadprivate) << VD->getType();
+ Diag(VD->getLocation(), diag::note_forward_declaration) << VD;
+ continue;
+ }
+
+ // Check if threadspecified is set.
+ if (VD->isThreadSpecified()) {
+ Diag(ILoc, diag::err_omp_var_thread_local) << VD;
+ Diag(VD->getLocation(), diag::note_forward_declaration) << VD;
+ continue;
+ }
+
+ Vars.push_back(*I);
+ }
+ return Vars.empty() ?
+ 0 : OMPThreadPrivateDecl::Create(Context,
+ getCurLexicalContext(),
+ Loc, Vars);
+}
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 9111878..89d495d 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -1,4 +1,4 @@
-//===--- SemaOverload.cpp - C++ Overloading ---------------------*- C++ -*-===//
+//===--- SemaOverload.cpp - C++ Overloading -------------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -11,13 +11,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/Initialization.h"
-#include "clang/Sema/Template.h"
-#include "clang/Sema/TemplateDeduction.h"
-#include "clang/Basic/Diagnostic.h"
-#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Overload.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclObjC.h"
@@ -25,26 +19,37 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/TypeOrdering.h"
+#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Initialization.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/Template.h"
+#include "clang/Sema/TemplateDeduction.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/STLExtras.h"
#include <algorithm>
namespace clang {
using namespace sema;
-/// A convenience routine for creating a decayed reference to a
-/// function.
+/// A convenience routine for creating a decayed reference to a function.
static ExprResult
-CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, bool HadMultipleCandidates,
+CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl,
+ bool HadMultipleCandidates,
SourceLocation Loc = SourceLocation(),
const DeclarationNameLoc &LocInfo = DeclarationNameLoc()){
DeclRefExpr *DRE = new (S.Context) DeclRefExpr(Fn, false, Fn->getType(),
VK_LValue, Loc, LocInfo);
if (HadMultipleCandidates)
DRE->setHadMultipleCandidates(true);
+
+ S.MarkDeclRefReferenced(DRE);
+ S.DiagnoseUseOfDecl(FoundDecl, Loc);
+
ExprResult E = S.Owned(DRE);
E = S.DefaultFunctionArrayConversion(E.take());
if (E.isInvalid())
@@ -535,12 +540,16 @@ AmbiguousConversionSequence::copyFrom(const AmbiguousConversionSequence &O) {
namespace {
// Structure used by OverloadCandidate::DeductionFailureInfo to store
- // template parameter and template argument information.
- struct DFIParamWithArguments {
- TemplateParameter Param;
+ // template argument information.
+ struct DFIArguments {
TemplateArgument FirstArg;
TemplateArgument SecondArg;
};
+ // Structure used by OverloadCandidate::DeductionFailureInfo to store
+ // template parameter and template argument information.
+ struct DFIParamWithArguments : DFIArguments {
+ TemplateParameter Param;
+ };
}
/// \brief Convert from Sema's representation of template deduction information
@@ -566,6 +575,15 @@ static MakeDeductionFailureInfo(ASTContext &Context,
Result.Data = Info.Param.getOpaqueValue();
break;
+ case Sema::TDK_NonDeducedMismatch: {
+ // FIXME: Should allocate from normal heap so that we can free this later.
+ DFIArguments *Saved = new (Context) DFIArguments;
+ Saved->FirstArg = Info.FirstArg;
+ Saved->SecondArg = Info.SecondArg;
+ Result.Data = Saved;
+ break;
+ }
+
case Sema::TDK_Inconsistent:
case Sema::TDK_Underqualified: {
// FIXME: Should allocate from normal heap so that we can free this later.
@@ -587,8 +605,11 @@ static MakeDeductionFailureInfo(ASTContext &Context,
}
break;
- case Sema::TDK_NonDeducedMismatch:
case Sema::TDK_FailedOverloadResolution:
+ Result.Data = Info.Expression;
+ break;
+
+ case Sema::TDK_MiscellaneousDeductionFailure:
break;
}
@@ -604,10 +625,12 @@ void OverloadCandidate::DeductionFailureInfo::Destroy() {
case Sema::TDK_TooManyArguments:
case Sema::TDK_TooFewArguments:
case Sema::TDK_InvalidExplicitArguments:
+ case Sema::TDK_FailedOverloadResolution:
break;
case Sema::TDK_Inconsistent:
case Sema::TDK_Underqualified:
+ case Sema::TDK_NonDeducedMismatch:
// FIXME: Destroy the data?
Data = 0;
break;
@@ -622,8 +645,7 @@ void OverloadCandidate::DeductionFailureInfo::Destroy() {
break;
// Unhandled
- case Sema::TDK_NonDeducedMismatch:
- case Sema::TDK_FailedOverloadResolution:
+ case Sema::TDK_MiscellaneousDeductionFailure:
break;
}
}
@@ -644,6 +666,8 @@ OverloadCandidate::DeductionFailureInfo::getTemplateParameter() {
case Sema::TDK_TooManyArguments:
case Sema::TDK_TooFewArguments:
case Sema::TDK_SubstitutionFailure:
+ case Sema::TDK_NonDeducedMismatch:
+ case Sema::TDK_FailedOverloadResolution:
return TemplateParameter();
case Sema::TDK_Incomplete:
@@ -655,8 +679,7 @@ OverloadCandidate::DeductionFailureInfo::getTemplateParameter() {
return static_cast<DFIParamWithArguments*>(Data)->Param;
// Unhandled
- case Sema::TDK_NonDeducedMismatch:
- case Sema::TDK_FailedOverloadResolution:
+ case Sema::TDK_MiscellaneousDeductionFailure:
break;
}
@@ -666,24 +689,25 @@ OverloadCandidate::DeductionFailureInfo::getTemplateParameter() {
TemplateArgumentList *
OverloadCandidate::DeductionFailureInfo::getTemplateArgumentList() {
switch (static_cast<Sema::TemplateDeductionResult>(Result)) {
- case Sema::TDK_Success:
- case Sema::TDK_Invalid:
- case Sema::TDK_InstantiationDepth:
- case Sema::TDK_TooManyArguments:
- case Sema::TDK_TooFewArguments:
- case Sema::TDK_Incomplete:
- case Sema::TDK_InvalidExplicitArguments:
- case Sema::TDK_Inconsistent:
- case Sema::TDK_Underqualified:
- return 0;
+ case Sema::TDK_Success:
+ case Sema::TDK_Invalid:
+ case Sema::TDK_InstantiationDepth:
+ case Sema::TDK_TooManyArguments:
+ case Sema::TDK_TooFewArguments:
+ case Sema::TDK_Incomplete:
+ case Sema::TDK_InvalidExplicitArguments:
+ case Sema::TDK_Inconsistent:
+ case Sema::TDK_Underqualified:
+ case Sema::TDK_NonDeducedMismatch:
+ case Sema::TDK_FailedOverloadResolution:
+ return 0;
- case Sema::TDK_SubstitutionFailure:
- return static_cast<TemplateArgumentList*>(Data);
+ case Sema::TDK_SubstitutionFailure:
+ return static_cast<TemplateArgumentList*>(Data);
- // Unhandled
- case Sema::TDK_NonDeducedMismatch:
- case Sema::TDK_FailedOverloadResolution:
- break;
+ // Unhandled
+ case Sema::TDK_MiscellaneousDeductionFailure:
+ break;
}
return 0;
@@ -699,15 +723,16 @@ const TemplateArgument *OverloadCandidate::DeductionFailureInfo::getFirstArg() {
case Sema::TDK_TooFewArguments:
case Sema::TDK_InvalidExplicitArguments:
case Sema::TDK_SubstitutionFailure:
+ case Sema::TDK_FailedOverloadResolution:
return 0;
case Sema::TDK_Inconsistent:
case Sema::TDK_Underqualified:
- return &static_cast<DFIParamWithArguments*>(Data)->FirstArg;
+ case Sema::TDK_NonDeducedMismatch:
+ return &static_cast<DFIArguments*>(Data)->FirstArg;
// Unhandled
- case Sema::TDK_NonDeducedMismatch:
- case Sema::TDK_FailedOverloadResolution:
+ case Sema::TDK_MiscellaneousDeductionFailure:
break;
}
@@ -725,21 +750,31 @@ OverloadCandidate::DeductionFailureInfo::getSecondArg() {
case Sema::TDK_TooFewArguments:
case Sema::TDK_InvalidExplicitArguments:
case Sema::TDK_SubstitutionFailure:
+ case Sema::TDK_FailedOverloadResolution:
return 0;
case Sema::TDK_Inconsistent:
case Sema::TDK_Underqualified:
- return &static_cast<DFIParamWithArguments*>(Data)->SecondArg;
+ case Sema::TDK_NonDeducedMismatch:
+ return &static_cast<DFIArguments*>(Data)->SecondArg;
// Unhandled
- case Sema::TDK_NonDeducedMismatch:
- case Sema::TDK_FailedOverloadResolution:
+ case Sema::TDK_MiscellaneousDeductionFailure:
break;
}
return 0;
}
+Expr *
+OverloadCandidate::DeductionFailureInfo::getExpr() {
+ if (static_cast<Sema::TemplateDeductionResult>(Result) ==
+ Sema::TDK_FailedOverloadResolution)
+ return static_cast<Expr*>(Data);
+
+ return 0;
+}
+
void OverloadCandidateSet::destroyCandidates() {
for (iterator i = begin(), e = end(); i != e; ++i) {
for (unsigned ii = 0, ie = i->NumConversions; ii != ie; ++ii)
@@ -885,7 +920,8 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old,
// function templates hide function templates with different
// return types or template parameter lists.
bool UseMemberUsingDeclRules =
- (OldIsUsingDecl || NewIsUsingDecl) && CurContext->isRecord();
+ (OldIsUsingDecl || NewIsUsingDecl) && CurContext->isRecord() &&
+ !New->getFriendObjectKind();
if (FunctionTemplateDecl *OldT = dyn_cast<FunctionTemplateDecl>(OldD)) {
if (!IsOverload(New, OldT->getTemplatedDecl(), UseMemberUsingDeclRules)) {
@@ -929,13 +965,21 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old,
return Ovl_Overload;
}
-bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
- bool UseUsingDeclRules) {
- // If both of the functions are extern "C", then they are not
- // overloads.
- if (Old->isExternC() && New->isExternC())
+static bool canBeOverloaded(const FunctionDecl &D) {
+ if (D.getAttr<OverloadableAttr>())
+ return true;
+ if (D.isExternC())
+ return false;
+
+ // Main cannot be overloaded (basic.start.main).
+ if (D.isMain())
return false;
+ return true;
+}
+
+static bool shouldTryToOverload(Sema &S, FunctionDecl *New, FunctionDecl *Old,
+ bool UseUsingDeclRules) {
FunctionTemplateDecl *OldTemplate = Old->getDescribedFunctionTemplate();
FunctionTemplateDecl *NewTemplate = New->getDescribedFunctionTemplate();
@@ -946,8 +990,8 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
return true;
// Is the function New an overload of the function Old?
- QualType OldQType = Context.getCanonicalType(Old->getType());
- QualType NewQType = Context.getCanonicalType(New->getType());
+ QualType OldQType = S.Context.getCanonicalType(Old->getType());
+ QualType NewQType = S.Context.getCanonicalType(New->getType());
// Compare the signatures (C++ 1.3.10) of the two functions to
// determine whether they are overloads. If we find any mismatch
@@ -968,7 +1012,7 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
if (OldQType != NewQType &&
(OldType->getNumArgs() != NewType->getNumArgs() ||
OldType->isVariadic() != NewType->isVariadic() ||
- !FunctionArgTypesAreEqual(OldType, NewType)))
+ !S.FunctionArgTypesAreEqual(OldType, NewType)))
return true;
// C++ [temp.over.link]p4:
@@ -984,9 +1028,9 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
// However, we don't consider either of these when deciding whether
// a member introduced by a shadow declaration is hidden.
if (!UseUsingDeclRules && NewTemplate &&
- (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
- OldTemplate->getTemplateParameters(),
- false, TPL_TemplateMatch) ||
+ (!S.TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
+ OldTemplate->getTemplateParameters(),
+ false, S.TPL_TemplateMatch) ||
OldType->getResultType() != NewType->getResultType()))
return true;
@@ -998,34 +1042,55 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
// 13.1p2). While not part of the definition of the signature,
// this check is important to determine whether these functions
// can be overloaded.
- CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old);
- CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New);
+ CXXMethodDecl *OldMethod = dyn_cast<CXXMethodDecl>(Old);
+ CXXMethodDecl *NewMethod = dyn_cast<CXXMethodDecl>(New);
if (OldMethod && NewMethod &&
- !OldMethod->isStatic() && !NewMethod->isStatic() &&
- (OldMethod->getTypeQualifiers() != NewMethod->getTypeQualifiers() ||
- OldMethod->getRefQualifier() != NewMethod->getRefQualifier())) {
- if (!UseUsingDeclRules &&
- OldMethod->getRefQualifier() != NewMethod->getRefQualifier() &&
- (OldMethod->getRefQualifier() == RQ_None ||
- NewMethod->getRefQualifier() == RQ_None)) {
- // C++0x [over.load]p2:
- // - Member function declarations with the same name and the same
- // parameter-type-list as well as member function template
- // declarations with the same name, the same parameter-type-list, and
- // the same template parameter lists cannot be overloaded if any of
- // them, but not all, have a ref-qualifier (8.3.5).
- Diag(NewMethod->getLocation(), diag::err_ref_qualifier_overload)
- << NewMethod->getRefQualifier() << OldMethod->getRefQualifier();
- Diag(OldMethod->getLocation(), diag::note_previous_declaration);
+ !OldMethod->isStatic() && !NewMethod->isStatic()) {
+ if (OldMethod->getRefQualifier() != NewMethod->getRefQualifier()) {
+ if (!UseUsingDeclRules &&
+ (OldMethod->getRefQualifier() == RQ_None ||
+ NewMethod->getRefQualifier() == RQ_None)) {
+ // C++0x [over.load]p2:
+ // - Member function declarations with the same name and the same
+ // parameter-type-list as well as member function template
+ // declarations with the same name, the same parameter-type-list, and
+ // the same template parameter lists cannot be overloaded if any of
+ // them, but not all, have a ref-qualifier (8.3.5).
+ S.Diag(NewMethod->getLocation(), diag::err_ref_qualifier_overload)
+ << NewMethod->getRefQualifier() << OldMethod->getRefQualifier();
+ S.Diag(OldMethod->getLocation(), diag::note_previous_declaration);
+ }
+ return true;
}
- return true;
+ // We may not have applied the implicit const for a constexpr member
+ // function yet (because we haven't yet resolved whether this is a static
+ // or non-static member function). Add it now, on the assumption that this
+ // is a redeclaration of OldMethod.
+ unsigned NewQuals = NewMethod->getTypeQualifiers();
+ if (NewMethod->isConstexpr() && !isa<CXXConstructorDecl>(NewMethod))
+ NewQuals |= Qualifiers::Const;
+ if (OldMethod->getTypeQualifiers() != NewQuals)
+ return true;
}
// The signatures match; this is not an overload.
return false;
}
+bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
+ bool UseUsingDeclRules) {
+ if (!shouldTryToOverload(*this, New, Old, UseUsingDeclRules))
+ return false;
+
+ // If both of the functions are extern "C", then they are not
+ // overloads.
+ if (!canBeOverloaded(*Old) && !canBeOverloaded(*New))
+ return false;
+
+ return true;
+}
+
/// \brief Checks availability of the function depending on the current
/// function context. Inside an unavailable function, unavailability is ignored.
///
@@ -1577,6 +1642,11 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
// tryAtomicConversion has updated the standard conversion sequence
// appropriately.
return true;
+ } else if (ToType->isEventT() &&
+ From->isIntegerConstantExpr(S.getASTContext()) &&
+ (From->EvaluateKnownConstInt(S.getASTContext()) == 0)) {
+ SCS.Second = ICK_Zero_Event_Conversion;
+ FromType = ToType;
} else {
// No second conversion required.
SCS.Second = ICK_Identity;
@@ -1606,9 +1676,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
CanonTo = S.Context.getCanonicalType(ToType);
if (CanonFrom.getLocalUnqualifiedType()
== CanonTo.getLocalUnqualifiedType() &&
- (CanonFrom.getLocalCVRQualifiers() != CanonTo.getLocalCVRQualifiers()
- || CanonFrom.getObjCGCAttr() != CanonTo.getObjCGCAttr()
- || CanonFrom.getObjCLifetime() != CanonTo.getObjCLifetime())) {
+ CanonFrom.getLocalQualifiers() != CanonTo.getLocalQualifiers()) {
FromType = ToType;
CanonFrom = CanonTo;
}
@@ -1818,7 +1886,8 @@ bool Sema::IsFloatingPointPromotion(QualType FromType, QualType ToType) {
return true;
// Half can be promoted to float.
- if (FromBuiltin->getKind() == BuiltinType::Half &&
+ if (!getLangOpts().NativeHalfType &&
+ FromBuiltin->getKind() == BuiltinType::Half &&
ToBuiltin->getKind() == BuiltinType::Float)
return true;
}
@@ -2880,8 +2949,8 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType,
UserDefinedConversionSequence &User,
OverloadCandidateSet &CandidateSet,
bool AllowExplicit) {
- DeclContext::lookup_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = S.LookupConstructors(To);
+ DeclContext::lookup_result R = S.LookupConstructors(To);
+ for (DeclContext::lookup_iterator Con = R.begin(), ConEnd = R.end();
Con != ConEnd; ++Con) {
NamedDecl *D = *Con;
DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
@@ -2980,7 +3049,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
S.IsDerivedFrom(From->getType(), ToType)))
ConstructorsOnly = true;
- S.RequireCompleteType(From->getLocStart(), ToType, 0);
+ S.RequireCompleteType(From->getExprLoc(), ToType, 0);
// RequireCompleteType may have returned true due to some invalid decl
// during template instantiation, but ToType may be complete enough now
// to try to recover.
@@ -3008,8 +3077,8 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
ListInitializing = true;
}
- DeclContext::lookup_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = S.LookupConstructors(ToRecordDecl);
+ DeclContext::lookup_result R = S.LookupConstructors(ToRecordDecl);
+ for (DeclContext::lookup_iterator Con = R.begin(), ConEnd = R.end();
Con != ConEnd; ++Con) {
NamedDecl *D = *Con;
DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
@@ -3065,10 +3134,11 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
if (CXXRecordDecl *FromRecordDecl
= dyn_cast<CXXRecordDecl>(FromRecordType->getDecl())) {
// Add all of the conversion functions as candidates.
- const UnresolvedSetImpl *Conversions
- = FromRecordDecl->getVisibleConversionFunctions();
- for (UnresolvedSetImpl::iterator I = Conversions->begin(),
- E = Conversions->end(); I != E; ++I) {
+ std::pair<CXXRecordDecl::conversion_iterator,
+ CXXRecordDecl::conversion_iterator>
+ Conversions = FromRecordDecl->getVisibleConversionFunctions();
+ for (CXXRecordDecl::conversion_iterator
+ I = Conversions.first, E = Conversions.second; I != E; ++I) {
DeclAccessPair FoundDecl = I.getPair();
NamedDecl *D = FoundDecl.getDecl();
CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext());
@@ -3198,7 +3268,7 @@ static ImplicitConversionSequence::CompareKind
compareConversionFunctions(Sema &S,
FunctionDecl *Function1,
FunctionDecl *Function2) {
- if (!S.getLangOpts().ObjC1 || !S.getLangOpts().CPlusPlus0x)
+ if (!S.getLangOpts().ObjC1 || !S.getLangOpts().CPlusPlus11)
return ImplicitConversionSequence::Indistinguishable;
// Objective-C++:
@@ -3868,6 +3938,15 @@ CompareDerivedToBaseConversions(Sema &S,
return ImplicitConversionSequence::Indistinguishable;
}
+/// \brief Determine whether the given type is valid, e.g., it is not an invalid
+/// C++ class.
+static bool isTypeValid(QualType T) {
+ if (CXXRecordDecl *Record = T->getAsCXXRecordDecl())
+ return !Record->isInvalidDecl();
+
+ return true;
+}
+
/// CompareReferenceRelationship - Compare the two types T1 and T2 to
/// determine whether they are reference-related,
/// reference-compatible, reference-compatible with added
@@ -3901,7 +3980,8 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
if (UnqualT1 == UnqualT2) {
// Nothing to do.
} else if (!RequireCompleteType(Loc, OrigT2, 0) &&
- IsDerivedFrom(UnqualT2, UnqualT1))
+ isTypeValid(UnqualT1) && isTypeValid(UnqualT2) &&
+ IsDerivedFrom(UnqualT2, UnqualT1))
DerivedToBase = true;
else if (UnqualT1->isObjCObjectOrInterfaceType() &&
UnqualT2->isObjCObjectOrInterfaceType() &&
@@ -3959,10 +4039,11 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
= dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl());
OverloadCandidateSet CandidateSet(DeclLoc);
- const UnresolvedSetImpl *Conversions
- = T2RecordDecl->getVisibleConversionFunctions();
- for (UnresolvedSetImpl::iterator I = Conversions->begin(),
- E = Conversions->end(); I != E; ++I) {
+ std::pair<CXXRecordDecl::conversion_iterator,
+ CXXRecordDecl::conversion_iterator>
+ Conversions = T2RecordDecl->getVisibleConversionFunctions();
+ for (CXXRecordDecl::conversion_iterator
+ I = Conversions.first, E = Conversions.second; I != E; ++I) {
NamedDecl *D = *I;
CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext());
if (isa<UsingShadowDecl>(D))
@@ -4213,7 +4294,7 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
// allow the use of rvalue references in C++98/03 for the benefit of
// standard library implementors; therefore, we need the xvalue check here.
ICS.Standard.DirectBinding =
- S.getLangOpts().CPlusPlus0x ||
+ S.getLangOpts().CPlusPlus11 ||
(InitCategory.isPRValue() && !T2->isRecordType());
ICS.Standard.IsLvalueReference = !isRValRef;
ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
@@ -4374,7 +4455,7 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
bool toStdInitializerList = false;
QualType X;
if (ToType->isArrayType())
- X = S.Context.getBaseElementType(ToType);
+ X = S.Context.getAsArrayType(ToType)->getElementType();
else
toStdInitializerList = S.isStdInitializerList(ToType, &X);
if (!X.isNull()) {
@@ -4595,7 +4676,7 @@ static bool TryCopyInitialization(const CanQualType FromQTy,
/// parameter of the given member function (@c Method) from the
/// expression @p From.
static ImplicitConversionSequence
-TryObjectArgumentInitialization(Sema &S, QualType OrigFromType,
+TryObjectArgumentInitialization(Sema &S, QualType FromType,
Expr::Classification FromClassification,
CXXMethodDecl *Method,
CXXRecordDecl *ActingContext) {
@@ -4611,7 +4692,6 @@ TryObjectArgumentInitialization(Sema &S, QualType OrigFromType,
ImplicitConversionSequence ICS;
// We need to have an object of class type.
- QualType FromType = OrigFromType;
if (const PointerType *PT = FromType->getAs<PointerType>()) {
FromType = PT->getPointeeType();
@@ -4646,7 +4726,7 @@ TryObjectArgumentInitialization(Sema &S, QualType OrigFromType,
!= FromTypeCanon.getLocalCVRQualifiers() &&
!ImplicitParamType.isAtLeastAsQualifiedAs(FromTypeCanon)) {
ICS.setBad(BadConversionSequence::bad_qualifiers,
- OrigFromType, ImplicitParamType);
+ FromType, ImplicitParamType);
return ICS;
}
@@ -4811,6 +4891,7 @@ static bool CheckConvertedConstantConversions(Sema &S,
case ICK_Identity:
case ICK_Integral_Promotion:
case ICK_Integral_Conversion:
+ case ICK_Zero_Event_Conversion:
return true;
case ICK_Boolean_Conversion:
@@ -4857,7 +4938,7 @@ static bool CheckConvertedConstantConversions(Sema &S,
ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
llvm::APSInt &Value,
CCEKind CCE) {
- assert(LangOpts.CPlusPlus0x && "converted constant expression outside C++11");
+ assert(LangOpts.CPlusPlus11 && "converted constant expression outside C++11");
assert(T->isIntegralOrEnumerationType() && "unexpected converted const type");
if (checkPlaceholderForOverload(*this, From))
@@ -4939,7 +5020,7 @@ ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
}
// Check the expression is a constant expression.
- llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ SmallVector<PartialDiagnosticAt, 8> Notes;
Expr::EvalResult Eval;
Eval.Diag = &Notes;
@@ -5104,15 +5185,15 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From,
// Look for a conversion to an integral or enumeration type.
UnresolvedSet<4> ViableConversions;
UnresolvedSet<4> ExplicitConversions;
- const UnresolvedSetImpl *Conversions
+ std::pair<CXXRecordDecl::conversion_iterator,
+ CXXRecordDecl::conversion_iterator> Conversions
= cast<CXXRecordDecl>(RecordTy->getDecl())->getVisibleConversionFunctions();
- bool HadMultipleCandidates = (Conversions->size() > 1);
+ bool HadMultipleCandidates
+ = (std::distance(Conversions.first, Conversions.second) > 1);
- for (UnresolvedSetImpl::iterator I = Conversions->begin(),
- E = Conversions->end();
- I != E;
- ++I) {
+ for (CXXRecordDecl::conversion_iterator
+ I = Conversions.first, E = Conversions.second; I != E; ++I) {
if (CXXConversionDecl *Conversion
= dyn_cast<CXXConversionDecl>((*I)->getUnderlyingDecl())) {
if (isIntegralOrEnumerationType(
@@ -5230,7 +5311,7 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From,
void
Sema::AddOverloadCandidate(FunctionDecl *Function,
DeclAccessPair FoundDecl,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions,
bool PartialOverloading,
@@ -5353,7 +5434,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
/// \brief Add all of the function declarations in the given function set to
/// the overload canddiate set.
void Sema::AddFunctionCandidates(const UnresolvedSetImpl &Fns,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions,
TemplateArgumentListInfo *ExplicitTemplateArgs) {
@@ -5428,7 +5509,7 @@ void
Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, QualType ObjectType,
Expr::Classification ObjectClassification,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions) {
const FunctionProtoType* Proto
@@ -5532,7 +5613,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl,
TemplateArgumentListInfo *ExplicitTemplateArgs,
QualType ObjectType,
Expr::Classification ObjectClassification,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions) {
if (!CandidateSet.isNewCandidate(MethodTmpl))
@@ -5582,7 +5663,7 @@ void
Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
DeclAccessPair FoundDecl,
TemplateArgumentListInfo *ExplicitTemplateArgs,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions) {
if (!CandidateSet.isNewCandidate(FunctionTemplate))
@@ -5816,7 +5897,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
CXXRecordDecl *ActingContext,
const FunctionProtoType *Proto,
Expr *Object,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
OverloadCandidateSet& CandidateSet) {
if (!CandidateSet.isNewCandidate(Conversion))
return;
@@ -6286,10 +6367,11 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
return;
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl());
- const UnresolvedSetImpl *Conversions
- = ClassDecl->getVisibleConversionFunctions();
- for (UnresolvedSetImpl::iterator I = Conversions->begin(),
- E = Conversions->end(); I != E; ++I) {
+ std::pair<CXXRecordDecl::conversion_iterator,
+ CXXRecordDecl::conversion_iterator>
+ Conversions = ClassDecl->getVisibleConversionFunctions();
+ for (CXXRecordDecl::conversion_iterator
+ I = Conversions.first, E = Conversions.second; I != E; ++I) {
NamedDecl *D = I.getDecl();
if (isa<UsingShadowDecl>(D))
D = cast<UsingShadowDecl>(D)->getTargetDecl();
@@ -6355,11 +6437,12 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) {
if (!ClassDecl->hasDefinition())
return VRQuals;
- const UnresolvedSetImpl *Conversions =
- ClassDecl->getVisibleConversionFunctions();
+ std::pair<CXXRecordDecl::conversion_iterator,
+ CXXRecordDecl::conversion_iterator>
+ Conversions = ClassDecl->getVisibleConversionFunctions();
- for (UnresolvedSetImpl::iterator I = Conversions->begin(),
- E = Conversions->end(); I != E; ++I) {
+ for (CXXRecordDecl::conversion_iterator
+ I = Conversions.first, E = Conversions.second; I != E; ++I) {
NamedDecl *D = I.getDecl();
if (isa<UsingShadowDecl>(D))
D = cast<UsingShadowDecl>(D)->getTargetDecl();
@@ -7449,7 +7532,7 @@ public:
S.AddBuiltinCandidate(*MemPtr, ParamTypes, Args, 2, CandidateSet);
}
- if (S.getLangOpts().CPlusPlus0x) {
+ if (S.getLangOpts().CPlusPlus11) {
for (BuiltinCandidateTypeSet::iterator
Enum = CandidateTypes[ArgIdx].enumeration_begin(),
EnumEnd = CandidateTypes[ArgIdx].enumeration_end();
@@ -7667,7 +7750,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
void
Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
bool Operator, SourceLocation Loc,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
TemplateArgumentListInfo *ExplicitTemplateArgs,
OverloadCandidateSet& CandidateSet,
bool PartialOverloading) {
@@ -8380,7 +8463,7 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
case Sema::TDK_SubstitutionFailure: {
// Format the template argument list into the argument string.
- llvm::SmallString<128> TemplateArgString;
+ SmallString<128> TemplateArgString;
if (TemplateArgumentList *Args =
Cand->DeductionFailure.getTemplateArgumentList()) {
TemplateArgString = " ";
@@ -8402,7 +8485,7 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
// Format the SFINAE diagnostic into the argument string.
// FIXME: Add a general mechanism to include a PartialDiagnostic *'s
// formatted message in another diagnostic.
- llvm::SmallString<128> SFINAEArgString;
+ SmallString<128> SFINAEArgString;
SourceRange R;
if (PDiag) {
SFINAEArgString = ": ";
@@ -8416,10 +8499,25 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
return;
}
+ case Sema::TDK_FailedOverloadResolution: {
+ OverloadExpr::FindResult R =
+ OverloadExpr::find(Cand->DeductionFailure.getExpr());
+ S.Diag(Fn->getLocation(),
+ diag::note_ovl_candidate_failed_overload_resolution)
+ << R.Expression->getName();
+ return;
+ }
+
+ case Sema::TDK_NonDeducedMismatch:
+ // FIXME: Provide a source location to indicate what we couldn't match.
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_non_deduced_mismatch)
+ << *Cand->DeductionFailure.getFirstArg()
+ << *Cand->DeductionFailure.getSecondArg();
+ return;
+
// TODO: diagnose these individually, then kill off
// note_ovl_candidate_bad_deduction, which is uselessly vague.
- case Sema::TDK_NonDeducedMismatch:
- case Sema::TDK_FailedOverloadResolution:
+ case Sema::TDK_MiscellaneousDeductionFailure:
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_deduction);
MaybeEmitInheritedConstructorNote(S, Fn);
return;
@@ -8597,6 +8695,7 @@ RankDeductionFailure(const OverloadCandidate::DeductionFailureInfo &DFI) {
case Sema::TDK_SubstitutionFailure:
case Sema::TDK_NonDeducedMismatch:
+ case Sema::TDK_MiscellaneousDeductionFailure:
return 3;
case Sema::TDK_InstantiationDepth:
@@ -8721,7 +8820,7 @@ struct CompareOverloadCandidatesForDisplay {
/// CompleteNonViableCandidate - Normally, overload resolution only
/// computes up to the first. Produces the FixIt set if possible.
void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
- llvm::ArrayRef<Expr *> Args) {
+ ArrayRef<Expr *> Args) {
assert(!Cand->Viable);
// Don't do anything on failures other than bad conversion.
@@ -8809,7 +8908,7 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
/// set.
void OverloadCandidateSet::NoteCandidates(Sema &S,
OverloadCandidateDisplayKind OCD,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
StringRef Opc,
SourceLocation OpLoc) {
// Sort the candidates by viability and position. Sorting directly would
@@ -9400,7 +9499,7 @@ bool Sema::ResolveAndFixSingleFunctionTemplateSpecialization(
static void AddOverloadedCallCandidate(Sema &S,
DeclAccessPair FoundDecl,
TemplateArgumentListInfo *ExplicitTemplateArgs,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet,
bool PartialOverloading,
bool KnownValid) {
@@ -9431,7 +9530,7 @@ static void AddOverloadedCallCandidate(Sema &S,
/// \brief Add the overload candidates named by callee and/or found by argument
/// dependent lookup to the given overload set.
void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
- llvm::ArrayRef<Expr *> Args,
+ ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet,
bool PartialOverloading) {
@@ -9495,7 +9594,7 @@ static bool
DiagnoseTwoPhaseLookup(Sema &SemaRef, SourceLocation FnLoc,
const CXXScopeSpec &SS, LookupResult &R,
TemplateArgumentListInfo *ExplicitTemplateArgs,
- llvm::ArrayRef<Expr *> Args) {
+ ArrayRef<Expr *> Args) {
if (SemaRef.ActiveTemplateInstantiations.empty() || !SS.isEmpty())
return false;
@@ -9536,18 +9635,23 @@ DiagnoseTwoPhaseLookup(Sema &SemaRef, SourceLocation FnLoc,
SemaRef.FindAssociatedClassesAndNamespaces(FnLoc, Args,
AssociatedNamespaces,
AssociatedClasses);
- // Never suggest declaring a function within namespace 'std'.
Sema::AssociatedNamespaceSet SuggestedNamespaces;
- if (DeclContext *Std = SemaRef.getStdNamespace()) {
- for (Sema::AssociatedNamespaceSet::iterator
- it = AssociatedNamespaces.begin(),
- end = AssociatedNamespaces.end(); it != end; ++it) {
- if (!Std->Encloses(*it))
- SuggestedNamespaces.insert(*it);
- }
- } else {
- // Lacking the 'std::' namespace, use all of the associated namespaces.
- SuggestedNamespaces = AssociatedNamespaces;
+ DeclContext *Std = SemaRef.getStdNamespace();
+ for (Sema::AssociatedNamespaceSet::iterator
+ it = AssociatedNamespaces.begin(),
+ end = AssociatedNamespaces.end(); it != end; ++it) {
+ // Never suggest declaring a function within namespace 'std'.
+ if (Std && Std->Encloses(*it))
+ continue;
+
+ // Never suggest declaring a function within a namespace with a reserved
+ // name, like __gnu_cxx.
+ NamespaceDecl *NS = dyn_cast<NamespaceDecl>(*it);
+ if (NS &&
+ NS->getQualifiedNameAsString().find("__") != std::string::npos)
+ continue;
+
+ SuggestedNamespaces.insert(*it);
}
SemaRef.Diag(R.getNameLoc(), diag::err_not_found_by_two_phase_lookup)
@@ -9587,7 +9691,7 @@ DiagnoseTwoPhaseLookup(Sema &SemaRef, SourceLocation FnLoc,
static bool
DiagnoseTwoPhaseOperatorLookup(Sema &SemaRef, OverloadedOperatorKind Op,
SourceLocation OpLoc,
- llvm::ArrayRef<Expr *> Args) {
+ ArrayRef<Expr *> Args) {
DeclarationName OpName =
SemaRef.Context.DeclarationNames.getCXXOperatorName(Op);
LookupResult R(SemaRef, OpName, OpLoc, Sema::LookupOperatorName);
@@ -9827,7 +9931,6 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
switch (OverloadResult) {
case OR_Success: {
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);
@@ -10015,8 +10118,6 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
// We matched an overloaded operator. Build a call to that
// operator.
- MarkFunctionReferenced(OpLoc, FnDecl);
-
// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
CheckMemberOperatorAccess(OpLoc, Args[0], 0, Best->FoundDecl);
@@ -10040,15 +10141,13 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn,
Input = InputInit.take();
}
- DiagnoseUseOfDecl(Best->FoundDecl, OpLoc);
-
// Determine the result type.
QualType ResultTy = FnDecl->getResultType();
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
ResultTy = ResultTy.getNonLValueExprType(Context);
// Build the actual expression node.
- ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl,
+ ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, Best->FoundDecl,
HadMultipleCandidates, OpLoc);
if (FnExpr.isInvalid())
return ExprError();
@@ -10240,8 +10339,6 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// We matched an overloaded operator. Build a call to that
// operator.
- MarkFunctionReferenced(OpLoc, FnDecl);
-
// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
// Best->Access is only meaningful for class members.
@@ -10282,8 +10379,6 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
Args[1] = RHS = Arg1.takeAs<Expr>();
}
- DiagnoseUseOfDecl(Best->FoundDecl, OpLoc);
-
// Determine the result type.
QualType ResultTy = FnDecl->getResultType();
ExprValueKind VK = Expr::getValueKindForType(ResultTy);
@@ -10291,6 +10386,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// Build the actual expression node.
ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl,
+ Best->FoundDecl,
HadMultipleCandidates, OpLoc);
if (FnExpr.isInvalid())
return ExprError();
@@ -10304,6 +10400,13 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
FnDecl))
return ExprError();
+ ArrayRef<const Expr *> ArgsArray(Args, 2);
+ // Cut off the implicit 'this'.
+ if (isa<CXXMethodDecl>(FnDecl))
+ ArgsArray = ArgsArray.slice(1);
+ checkCall(FnDecl, ArgsArray, 0, isa<CXXMethodDecl>(FnDecl), OpLoc,
+ TheCall->getSourceRange(), VariadicDoesNotApply);
+
return MaybeBindToTemporary(TheCall);
} else {
// We matched a built-in operator. Convert the arguments, then
@@ -10376,16 +10479,13 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
if (isImplicitlyDeleted(Best->Function)) {
CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function);
Diag(OpLoc, diag::err_ovl_deleted_special_oper)
- << getSpecialMember(Method)
- << BinaryOperator::getOpcodeStr(Opc)
- << getDeletedOrUnavailableSuffix(Best->Function);
+ << Context.getRecordType(Method->getParent())
+ << getSpecialMember(Method);
- if (getSpecialMember(Method) != CXXInvalid) {
- // The user probably meant to call this special member. Just
- // explain why it's deleted.
- NoteDeletedFunction(Method);
- return ExprError();
- }
+ // The user probably meant to call this special member. Just
+ // explain why it's deleted.
+ NoteDeletedFunction(Method);
+ return ExprError();
} else {
Diag(OpLoc, diag::err_ovl_deleted_oper)
<< Best->Function->isDeleted()
@@ -10463,10 +10563,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// We matched an overloaded operator. Build a call to that
// operator.
- MarkFunctionReferenced(LLoc, FnDecl);
-
CheckMemberOperatorAccess(LLoc, Args[0], Args[1], Best->FoundDecl);
- DiagnoseUseOfDecl(Best->FoundDecl, LLoc);
// Convert the arguments.
CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl);
@@ -10498,6 +10595,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
DeclarationNameInfo OpLocInfo(OpName, LLoc);
OpLocInfo.setCXXOperatorNameRange(SourceRange(LLoc, RLoc));
ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl,
+ Best->FoundDecl,
HadMultipleCandidates,
OpLocInfo.getLoc(),
OpLocInfo.getInfo());
@@ -10715,7 +10813,6 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
Best)) {
case OR_Success:
Method = cast<CXXMethodDecl>(Best->Function);
- MarkFunctionReferenced(UnresExpr->getMemberLoc(), Method);
FoundDecl = Best->FoundDecl;
CheckUnresolvedMemberAccess(UnresExpr, Best->FoundDecl);
DiagnoseUseOfDecl(Best->FoundDecl, UnresExpr->getNameLoc());
@@ -10880,10 +10977,11 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
// functions for each conversion function declared in an
// accessible base class provided the function is not hidden
// within T by another intervening declaration.
- const UnresolvedSetImpl *Conversions
+ std::pair<CXXRecordDecl::conversion_iterator,
+ CXXRecordDecl::conversion_iterator> Conversions
= cast<CXXRecordDecl>(Record->getDecl())->getVisibleConversionFunctions();
- for (UnresolvedSetImpl::iterator I = Conversions->begin(),
- E = Conversions->end(); I != E; ++I) {
+ for (CXXRecordDecl::conversion_iterator
+ I = Conversions.first, E = Conversions.second; I != E; ++I) {
NamedDecl *D = *I;
CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext());
if (isa<UsingShadowDecl>(D))
@@ -10989,9 +11087,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
RParenLoc);
}
- MarkFunctionReferenced(LParenLoc, Best->Function);
CheckMemberOperatorAccess(LParenLoc, Object.get(), 0, Best->FoundDecl);
- DiagnoseUseOfDecl(Best->FoundDecl, LParenLoc);
// We found an overloaded operator(). Build a CXXOperatorCallExpr
// that calls this method, using Object for the implicit object
@@ -11025,7 +11121,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj,
DeclarationNameInfo OpLocInfo(
Context.DeclarationNames.getCXXOperatorName(OO_Call), LParenLoc);
OpLocInfo.setCXXOperatorNameRange(SourceRange(LParenLoc, RParenLoc));
- ExprResult NewFn = CreateFunctionRefExpr(*this, Method,
+ ExprResult NewFn = CreateFunctionRefExpr(*this, Method, Best->FoundDecl,
HadMultipleCandidates,
OpLocInfo.getLoc(),
OpLocInfo.getInfo());
@@ -11190,9 +11286,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) {
return ExprError();
}
- MarkFunctionReferenced(OpLoc, Best->Function);
CheckMemberOperatorAccess(OpLoc, Base, 0, Best->FoundDecl);
- DiagnoseUseOfDecl(Best->FoundDecl, OpLoc);
// Convert the object parameter.
CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function);
@@ -11204,7 +11298,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) {
Base = BaseResult.take();
// Build the operator call.
- ExprResult FnExpr = CreateFunctionRefExpr(*this, Method,
+ ExprResult FnExpr = CreateFunctionRefExpr(*this, Method, Best->FoundDecl,
HadMultipleCandidates, OpLoc);
if (FnExpr.isInvalid())
return ExprError();
@@ -11259,10 +11353,8 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R,
}
FunctionDecl *FD = Best->Function;
- MarkFunctionReferenced(UDSuffixLoc, FD);
- DiagnoseUseOfDecl(Best->FoundDecl, UDSuffixLoc);
-
- ExprResult Fn = CreateFunctionRefExpr(*this, FD, HadMultipleCandidates,
+ ExprResult Fn = CreateFunctionRefExpr(*this, FD, Best->FoundDecl,
+ HadMultipleCandidates,
SuffixInfo.getLoc(),
SuffixInfo.getInfo());
if (Fn.isInvalid())
diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp
index a8d75b2..b135507 100644
--- a/lib/Sema/SemaPseudoObject.cpp
+++ b/lib/Sema/SemaPseudoObject.cpp
@@ -31,10 +31,11 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/ScopeInfo.h"
-#include "clang/Sema/Initialization.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Initialization.h"
+#include "clang/Sema/ScopeInfo.h"
#include "llvm/ADT/SmallString.h"
using namespace clang;
@@ -113,7 +114,7 @@ namespace {
Expr *rebuildSpecific(ObjCPropertyRefExpr *refExpr) {
// Fortunately, the constraint that we're rebuilding something
// with a base limits the number of cases here.
- assert(refExpr->getBase());
+ assert(refExpr->isObjectReceiver());
if (refExpr->isExplicitProperty()) {
return new (S.Context)
@@ -562,8 +563,9 @@ bool ObjCPropertyOpBuilder::findSetter(bool warn) {
if (const ObjCInterfaceDecl *IFace =
dyn_cast<ObjCInterfaceDecl>(setter->getDeclContext())) {
const StringRef thisPropertyName(prop->getName());
+ // Try flipping the case of the first character.
char front = thisPropertyName.front();
- front = islower(front) ? toupper(front) : tolower(front);
+ front = isLowercase(front) ? toUppercase(front) : toLowercase(front);
SmallString<100> PropertyName = thisPropertyName;
PropertyName[0] = front;
IdentifierInfo *AltMember = &S.PP.getIdentifierTable().get(PropertyName);
@@ -713,10 +715,9 @@ ExprResult ObjCPropertyOpBuilder::buildSet(Expr *op, SourceLocation opcLoc,
ExprResult ObjCPropertyOpBuilder::buildRValueOperation(Expr *op) {
// Explicit properties always have getters, but implicit ones don't.
// Check that before proceeding.
- if (RefExpr->isImplicitProperty() &&
- !RefExpr->getImplicitPropertyGetter()) {
+ if (RefExpr->isImplicitProperty() && !RefExpr->getImplicitPropertyGetter()) {
S.Diag(RefExpr->getLocation(), diag::err_getter_not_found)
- << RefExpr->getBase()->getType();
+ << RefExpr->getSourceRange();
return ExprError();
}
@@ -954,16 +955,15 @@ Sema::ObjCSubscriptKind
// objective-C pointer type.
UnresolvedSet<4> ViableConversions;
UnresolvedSet<4> ExplicitConversions;
- const UnresolvedSetImpl *Conversions
+ std::pair<CXXRecordDecl::conversion_iterator,
+ CXXRecordDecl::conversion_iterator> Conversions
= cast<CXXRecordDecl>(RecordTy->getDecl())->getVisibleConversionFunctions();
int NoIntegrals=0, NoObjCIdPointers=0;
SmallVector<CXXConversionDecl *, 4> ConversionDecls;
- for (UnresolvedSetImpl::iterator I = Conversions->begin(),
- E = Conversions->end();
- I != E;
- ++I) {
+ for (CXXRecordDecl::conversion_iterator
+ I = Conversions.first, E = Conversions.second; I != E; ++I) {
if (CXXConversionDecl *Conversion
= dyn_cast<CXXConversionDecl>((*I)->getUnderlyingDecl())) {
QualType CT = Conversion->getConversionType().getNonReferenceType();
@@ -1087,7 +1087,6 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() {
: S.Context.getObjCIdType(),
/*TInfo=*/0,
SC_None,
- SC_None,
0);
AtIndexGetter->setMethodParams(S.Context, Argument,
ArrayRef<SourceLocation>());
@@ -1202,7 +1201,6 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() {
S.Context.getObjCIdType(),
/*TInfo=*/0,
SC_None,
- SC_None,
0);
Params.push_back(object);
ParmVarDecl *key = ParmVarDecl::Create(S.Context, AtIndexSetter,
@@ -1213,7 +1211,6 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() {
: S.Context.getObjCIdType(),
/*TInfo=*/0,
SC_None,
- SC_None,
0);
Params.push_back(key);
AtIndexSetter->setMethodParams(S.Context, Params, ArrayRef<SourceLocation>());
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index f55174e..ff1db82 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -12,21 +12,22 @@
//===----------------------------------------------------------------------===//
#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/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
-#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtObjC.h"
#include "clang/AST/TypeLoc.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Initialization.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/ScopeInfo.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -35,9 +36,13 @@
using namespace clang;
using namespace sema;
-StmtResult Sema::ActOnExprStmt(FullExprArg expr) {
- Expr *E = expr.get();
- if (!E) // FIXME: FullExprArg has no error state?
+StmtResult Sema::ActOnExprStmt(ExprResult FE) {
+ if (FE.isInvalid())
+ return StmtError();
+
+ FE = ActOnFinishFullExpr(FE.get(), FE.get()->getExprLoc(),
+ /*DiscardedValue*/ true);
+ if (FE.isInvalid())
return StmtError();
// C99 6.8.3p2: The expression in an expression statement is evaluated as a
@@ -45,10 +50,15 @@ StmtResult Sema::ActOnExprStmt(FullExprArg expr) {
// operand, even incomplete types.
// Same thing in for stmt first clause (when expr) and third clause.
- return Owned(static_cast<Stmt*>(E));
+ return Owned(static_cast<Stmt*>(FE.take()));
}
+StmtResult Sema::ActOnExprStmtError() {
+ DiscardCleanupsInEvaluationContext();
+ return StmtError();
+}
+
StmtResult Sema::ActOnNullStmt(SourceLocation SemiLoc,
bool HasLeadingEmptyMacro) {
return Owned(new (Context) NullStmt(SemiLoc, HasLeadingEmptyMacro));
@@ -125,7 +135,7 @@ static bool DiagnoseUnusedComparison(Sema &S, const Expr *E) {
// Suppress warnings when the operator, suspicious as it may be, comes from
// a macro expansion.
- if (Loc.isMacroID())
+ if (S.SourceMgr.isMacroBodyExpansion(Loc))
return false;
S.Diag(Loc, diag::warn_unused_comparison)
@@ -152,12 +162,20 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
const Expr *E = dyn_cast_or_null<Expr>(S);
if (!E)
return;
+ SourceLocation ExprLoc = E->IgnoreParens()->getExprLoc();
+ // In most cases, we don't want to warn if the expression is written in a
+ // macro body, or if the macro comes from a system header. If the offending
+ // expression is a call to a function with the warn_unused_result attribute,
+ // we warn no matter the location. Because of the order in which the various
+ // checks need to happen, we factor out the macro-related test here.
+ bool ShouldSuppress =
+ SourceMgr.isMacroBodyExpansion(ExprLoc) ||
+ SourceMgr.isInSystemMacro(ExprLoc);
const Expr *WarnExpr;
SourceLocation Loc;
SourceRange R1, R2;
- if (SourceMgr.isInSystemMacro(E->getExprLoc()) ||
- !E->isUnusedResultAWarning(WarnExpr, Loc, R1, R2, Context))
+ if (!E->isUnusedResultAWarning(WarnExpr, Loc, R1, R2, Context))
return;
// If this is a GNU statement expression expanded from a macro, it is probably
@@ -185,12 +203,16 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
return;
// If the callee has attribute pure, const, or warn_unused_result, warn with
- // a more specific message to make it clear what is happening.
+ // a more specific message to make it clear what is happening. If the call
+ // is written in a macro body, only warn if it has the warn_unused_result
+ // attribute.
if (const Decl *FD = CE->getCalleeDecl()) {
if (FD->getAttr<WarnUnusedResultAttr>()) {
Diag(Loc, diag::warn_unused_result) << R1 << R2;
return;
}
+ if (ShouldSuppress)
+ return;
if (FD->getAttr<PureAttr>()) {
Diag(Loc, diag::warn_unused_call) << R1 << R2 << "pure";
return;
@@ -200,7 +222,10 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
return;
}
}
- } else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) {
+ } else if (ShouldSuppress)
+ return;
+
+ if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) {
if (getLangOpts().ObjCAutoRefCount && ME->isDelegateInitCall()) {
Diag(Loc, diag::err_arc_unused_init_message) << R1;
return;
@@ -229,7 +254,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
// We really do want to use the non-canonical type here.
if (T == Context.VoidPtrTy) {
- PointerTypeLoc TL = cast<PointerTypeLoc>(TI->getTypeLoc());
+ PointerTypeLoc TL = TI->getTypeLoc().castAs<PointerTypeLoc>();
Diag(Loc, diag::warn_unused_voidptr)
<< FixItHint::CreateRemoval(TL.getStarLoc());
@@ -298,7 +323,9 @@ Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R,
DiagnoseEmptyLoopBody(Elts[i], Elts[i + 1]);
}
- return Owned(new (Context) CompoundStmt(Context, Elts, NumElts, L, R));
+ return Owned(new (Context) CompoundStmt(Context,
+ llvm::makeArrayRef(Elts, NumElts),
+ L, R));
}
StmtResult
@@ -312,7 +339,7 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal,
return StmtError();
}
- if (!getLangOpts().CPlusPlus0x) {
+ if (!getLangOpts().CPlusPlus11) {
// C99 6.8.4.2p3: The expression shall be an integer constant.
// However, GCC allows any evaluatable integer expression.
if (!LHSVal->isTypeDependent() && !LHSVal->isValueDependent()) {
@@ -328,6 +355,12 @@ Sema::ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal,
// Recover from an error by just forgetting about it.
}
}
+
+ LHSVal = ActOnFinishFullExpr(LHSVal, LHSVal->getExprLoc(), false,
+ getLangOpts().CPlusPlus11).take();
+ if (RHSVal)
+ RHSVal = ActOnFinishFullExpr(RHSVal, RHSVal->getExprLoc(), false,
+ getLangOpts().CPlusPlus11).take();
CaseStmt *CS = new (Context) CaseStmt(LHSVal, RHSVal, CaseLoc, DotDotDotLoc,
ColonLoc);
@@ -390,6 +423,13 @@ StmtResult
Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, Decl *CondVar,
Stmt *thenStmt, SourceLocation ElseLoc,
Stmt *elseStmt) {
+ // If the condition was invalid, discard the if statement. We could recover
+ // better by replacing it with a valid expr, but don't do that yet.
+ if (!CondVal.get() && !CondVar) {
+ getCurFunction()->setHasDroppedStmt();
+ return StmtError();
+ }
+
ExprResult CondResult(CondVal.release());
VarDecl *ConditionVar = 0;
@@ -595,8 +635,7 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond,
Cond = CondResult.take();
if (!CondVar) {
- CheckImplicitConversions(Cond, SwitchLoc);
- CondResult = MaybeCreateExprWithCleanups(Cond);
+ CondResult = ActOnFinishFullExpr(Cond, SwitchLoc);
if (CondResult.isInvalid())
return StmtError();
Cond = CondResult.take();
@@ -710,7 +749,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
llvm::APSInt LoVal;
- if (getLangOpts().CPlusPlus0x) {
+ if (getLangOpts().CPlusPlus11) {
// C++11 [stmt.switch]p2: the constant-expression shall be a converted
// constant expression of the promoted type of the switch condition.
ExprResult ConvLo =
@@ -792,7 +831,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(CurrCase)) {
CurrString = DeclRef->getDecl()->getName();
}
- llvm::SmallString<16> CaseValStr;
+ SmallString<16> CaseValStr;
CaseVals[i-1].first.toString(CaseValStr);
if (PrevString == CurrString)
@@ -830,7 +869,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
Expr *Hi = CR->getRHS();
llvm::APSInt HiVal;
- if (getLangOpts().CPlusPlus0x) {
+ if (getLangOpts().CPlusPlus11) {
// C++11 [stmt.switch]p2: the constant-expression shall be a converted
// constant expression of the promoted type of the switch condition.
ExprResult ConvHi =
@@ -1149,12 +1188,11 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, Stmt *Body,
assert(Cond && "ActOnDoStmt(): missing expression");
ExprResult CondResult = CheckBooleanCondition(Cond, DoLoc);
- if (CondResult.isInvalid() || CondResult.isInvalid())
+ if (CondResult.isInvalid())
return StmtError();
Cond = CondResult.take();
- CheckImplicitConversions(Cond, DoLoc);
- CondResult = MaybeCreateExprWithCleanups(Cond);
+ CondResult = ActOnFinishFullExpr(Cond, DoLoc);
if (CondResult.isInvalid())
return StmtError();
Cond = CondResult.take();
@@ -1170,13 +1208,13 @@ namespace {
// of the excluded constructs are used.
class DeclExtractor : public EvaluatedExprVisitor<DeclExtractor> {
llvm::SmallPtrSet<VarDecl*, 8> &Decls;
- llvm::SmallVector<SourceRange, 10> &Ranges;
+ SmallVector<SourceRange, 10> &Ranges;
bool Simple;
public:
typedef EvaluatedExprVisitor<DeclExtractor> Inherited;
DeclExtractor(Sema &S, llvm::SmallPtrSet<VarDecl*, 8> &Decls,
- llvm::SmallVector<SourceRange, 10> &Ranges) :
+ SmallVector<SourceRange, 10> &Ranges) :
Inherited(S.Context),
Decls(Decls),
Ranges(Ranges),
@@ -1325,7 +1363,7 @@ public:
PartialDiagnostic PDiag = S.PDiag(diag::warn_variables_not_in_loop_body);
llvm::SmallPtrSet<VarDecl*, 8> Decls;
- llvm::SmallVector<SourceRange, 10> Ranges;
+ SmallVector<SourceRange, 10> Ranges;
DeclExtractor DE(S, Decls, Ranges);
DE.Visit(Second);
@@ -1361,8 +1399,8 @@ public:
// Load SourceRanges into diagnostic if there is room.
// Otherwise, load the SourceRange of the conditional expression.
if (Ranges.size() <= PartialDiagnostic::MaxArguments)
- for (llvm::SmallVector<SourceRange, 10>::iterator I = Ranges.begin(),
- E = Ranges.end();
+ for (SmallVector<SourceRange, 10>::iterator I = Ranges.begin(),
+ E = Ranges.end();
I != E; ++I)
PDiag << *I;
else
@@ -1432,12 +1470,10 @@ StmtResult Sema::ActOnForEachLValueExpr(Expr *E) {
if (result.isInvalid()) return StmtError();
E = result.take();
- CheckImplicitConversions(E);
-
- result = MaybeCreateExprWithCleanups(E);
- if (result.isInvalid()) return StmtError();
-
- return Owned(static_cast<Stmt*>(result.take()));
+ ExprResult FullExpr = ActOnFinishFullExpr(E);
+ if (FullExpr.isInvalid())
+ return StmtError();
+ return StmtResult(static_cast<Stmt*>(FullExpr.take()));
}
ExprResult
@@ -1508,7 +1544,7 @@ Sema::CheckObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) {
}
// Wrap up any cleanups in the expression.
- return Owned(MaybeCreateExprWithCleanups(collection));
+ return Owned(collection);
}
StmtResult
@@ -1553,6 +1589,10 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
if (CollectionExprResult.isInvalid())
return StmtError();
+ CollectionExprResult = ActOnFinishFullExpr(CollectionExprResult.take());
+ if (CollectionExprResult.isInvalid())
+ return StmtError();
+
return Owned(new (Context) ObjCForCollectionStmt(First,
CollectionExprResult.take(), 0,
ForLoc, RParenLoc));
@@ -1625,7 +1665,7 @@ VarDecl *BuildForRangeVarDecl(Sema &SemaRef, SourceLocation Loc,
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);
+ TInfo, SC_None);
Decl->setImplicit();
return Decl;
}
@@ -1937,8 +1977,7 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
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));
+ CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Range);
}
// Return an error if no fix was discovered.
if (RangeStatus != FRS_Success)
@@ -2096,9 +2135,13 @@ Sema::ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc,
E = ExprRes.take();
if (DiagnoseAssignmentResult(ConvTy, StarLoc, DestTy, ETy, E, AA_Passing))
return StmtError();
- E = MaybeCreateExprWithCleanups(E);
}
+ ExprResult ExprRes = ActOnFinishFullExpr(E);
+ if (ExprRes.isInvalid())
+ return StmtError();
+ E = ExprRes.take();
+
getCurFunction()->setHasIndirectGoto();
return Owned(new (Context) IndirectGotoStmt(GotoLoc, StarLoc, E));
@@ -2370,8 +2413,10 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
}
if (RetValExp) {
- CheckImplicitConversions(RetValExp, ReturnLoc);
- RetValExp = MaybeCreateExprWithCleanups(RetValExp);
+ ExprResult ER = ActOnFinishFullExpr(RetValExp, ReturnLoc);
+ if (ER.isInvalid())
+ return StmtError();
+ RetValExp = ER.take();
}
ReturnStmt *Result = new (Context) ReturnStmt(ReturnLoc, RetValExp,
NRVOCandidate);
@@ -2400,8 +2445,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
QualType RelatedRetType;
if (const FunctionDecl *FD = getCurFunctionDecl()) {
FnRetType = FD->getResultType();
- if (FD->hasAttr<NoReturnAttr>() ||
- FD->getType()->getAs<FunctionType>()->getNoReturnAttr())
+ if (FD->isNoReturn())
Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr)
<< FD->getDeclName();
} else if (ObjCMethodDecl *MD = getCurMethodDecl()) {
@@ -2473,8 +2517,10 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
}
if (RetValExp) {
- CheckImplicitConversions(RetValExp, ReturnLoc);
- RetValExp = MaybeCreateExprWithCleanups(RetValExp);
+ ExprResult ER = ActOnFinishFullExpr(RetValExp, ReturnLoc);
+ if (ER.isInvalid())
+ return StmtError();
+ RetValExp = ER.take();
}
}
@@ -2490,24 +2536,12 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
Diag(ReturnLoc, DiagID) << getCurMethodDecl()->getDeclName() << 1/*meth*/;
Result = new (Context) ReturnStmt(ReturnLoc);
} else {
+ assert(RetValExp || FnRetType->isDependentType());
const VarDecl *NRVOCandidate = 0;
if (!FnRetType->isDependentType() && !RetValExp->isTypeDependent()) {
// we have a non-void function with an expression, continue checking
- if (!RelatedRetType.isNull()) {
- // If we have a related result type, perform an extra conversion here.
- // FIXME: The diagnostics here don't really describe what is happening.
- InitializedEntity Entity =
- InitializedEntity::InitializeTemporary(RelatedRetType);
-
- ExprResult Res = PerformCopyInitialization(Entity, SourceLocation(),
- RetValExp);
- if (Res.isInvalid()) {
- // FIXME: Cleanup temporaries here, anyway?
- return StmtError();
- }
- RetValExp = Res.takeAs<Expr>();
- }
+ QualType RetType = (RelatedRetType.isNull() ? FnRetType : RelatedRetType);
// C99 6.8.6.4p3(136): The return statement is not an assignment. The
// overlap restriction of subclause 6.5.16.1 does not apply to the case of
@@ -2517,23 +2551,40 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
// the C version of which boils down to CheckSingleAssignmentConstraints.
NRVOCandidate = getCopyElisionCandidate(FnRetType, RetValExp, false);
InitializedEntity Entity = InitializedEntity::InitializeResult(ReturnLoc,
- FnRetType,
+ RetType,
NRVOCandidate != 0);
ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOCandidate,
- FnRetType, RetValExp);
+ RetType, RetValExp);
if (Res.isInvalid()) {
- // FIXME: Cleanup temporaries here, anyway?
+ // FIXME: Clean up temporaries here anyway?
return StmtError();
}
-
RetValExp = Res.takeAs<Expr>();
- if (RetValExp)
- CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
+
+ // If we have a related result type, we need to implicitly
+ // convert back to the formal result type. We can't pretend to
+ // initialize the result again --- we might end double-retaining
+ // --- so instead we initialize a notional temporary; this can
+ // lead to less-than-great diagnostics, but this stage is much
+ // less likely to fail than the previous stage.
+ if (!RelatedRetType.isNull()) {
+ Entity = InitializedEntity::InitializeTemporary(FnRetType);
+ Res = PerformCopyInitialization(Entity, ReturnLoc, RetValExp);
+ if (Res.isInvalid()) {
+ // FIXME: Clean up temporaries here anyway?
+ return StmtError();
+ }
+ RetValExp = Res.takeAs<Expr>();
+ }
+
+ CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
}
if (RetValExp) {
- CheckImplicitConversions(RetValExp, ReturnLoc);
- RetValExp = MaybeCreateExprWithCleanups(RetValExp);
+ ExprResult ER = ActOnFinishFullExpr(RetValExp, ReturnLoc);
+ if (ER.isInvalid())
+ return StmtError();
+ RetValExp = ER.take();
}
Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, NRVOCandidate);
}
@@ -2583,7 +2634,11 @@ StmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw) {
if (Result.isInvalid())
return StmtError();
- Throw = MaybeCreateExprWithCleanups(Result.take());
+ Result = ActOnFinishFullExpr(Result.take());
+ if (Result.isInvalid())
+ return StmtError();
+ Throw = Result.take();
+
QualType ThrowType = Throw->getType();
// Make sure the expression type is an ObjC pointer or "void *".
if (!ThrowType->isDependentType() &&
@@ -2634,7 +2689,7 @@ Sema::ActOnObjCAtSynchronizedOperand(SourceLocation atLoc, Expr *operand) {
}
// The operand to @synchronized is a full-expression.
- return MaybeCreateExprWithCleanups(operand);
+ return ActOnFinishFullExpr(operand);
}
StmtResult
@@ -2756,7 +2811,7 @@ Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,
// and warns.
return Owned(CXXTryStmt::Create(Context, TryLoc, TryBlock,
- Handlers, NumHandlers));
+ llvm::makeArrayRef(Handlers, NumHandlers)));
}
StmtResult
diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp
index 7c2c766..da33bdf 100644
--- a/lib/Sema/SemaStmtAsm.cpp
+++ b/lib/Sema/SemaStmtAsm.cpp
@@ -12,25 +12,25 @@
//===----------------------------------------------------------------------===//
#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 "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Initialization.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/ScopeInfo.h"
#include "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/MCParser/MCAsmParser.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"
@@ -124,11 +124,14 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
// Check that the output exprs are valid lvalues.
Expr *OutputExpr = Exprs[i];
- if (CheckAsmLValue(OutputExpr, *this)) {
+ if (CheckAsmLValue(OutputExpr, *this))
return StmtError(Diag(OutputExpr->getLocStart(),
- diag::err_asm_invalid_lvalue_in_output)
- << OutputExpr->getSourceRange());
- }
+ diag::err_asm_invalid_lvalue_in_output)
+ << OutputExpr->getSourceRange());
+
+ if (RequireCompleteType(OutputExpr->getLocStart(), Exprs[i]->getType(),
+ diag::err_dereference_incomplete_type))
+ return StmtError();
OutputConstraintInfos.push_back(Info);
}
@@ -179,6 +182,22 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
Exprs[i] = Result.take();
InputConstraintInfos.push_back(Info);
+
+ const Type *Ty = Exprs[i]->getType().getTypePtr();
+ if (Ty->isDependentType())
+ continue;
+
+ if (!Ty->isVoidType() || !Info.allowsMemory())
+ if (RequireCompleteType(InputExpr->getLocStart(), Exprs[i]->getType(),
+ diag::err_dereference_incomplete_type))
+ return StmtError();
+
+ unsigned Size = Context.getTypeSize(Ty);
+ if (!Context.getTargetInfo().validateInputSize(Literal->getString(),
+ Size))
+ return StmtError(Diag(InputExpr->getLocStart(),
+ diag::err_asm_invalid_input_size)
+ << Info.getConstraintStr());
}
// Check that the clobbers are valid.
@@ -377,7 +396,7 @@ static StringRef getSpelling(Sema &SemaRef, Token AsmTok) {
static bool buildMSAsmString(Sema &SemaRef,
SourceLocation AsmLoc,
ArrayRef<Token> AsmToks,
- llvm::SmallVectorImpl<unsigned> &TokOffsets,
+ SmallVectorImpl<unsigned> &TokOffsets,
std::string &AsmString) {
assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!");
@@ -426,9 +445,14 @@ public:
: SemaRef(Ref), AsmLoc(Loc), AsmToks(Toks), TokOffsets(Offsets) { }
~MCAsmParserSemaCallbackImpl() {}
- void *LookupInlineAsmIdentifier(StringRef Name, void *SrcLoc, unsigned &Size){
+ void *LookupInlineAsmIdentifier(StringRef Name, void *SrcLoc,
+ unsigned &Length, unsigned &Size,
+ unsigned &Type, bool &IsVarDecl){
SourceLocation Loc = SourceLocation::getFromPtrEncoding(SrcLoc);
- NamedDecl *OpDecl = SemaRef.LookupInlineAsmIdentifier(Name, Loc, Size);
+
+ NamedDecl *OpDecl = SemaRef.LookupInlineAsmIdentifier(Name, Loc, Length,
+ Size, Type,
+ IsVarDecl);
return static_cast<void *>(OpDecl);
}
@@ -471,8 +495,12 @@ public:
}
NamedDecl *Sema::LookupInlineAsmIdentifier(StringRef Name, SourceLocation Loc,
- unsigned &Size) {
+ unsigned &Length, unsigned &Size,
+ unsigned &Type, bool &IsVarDecl) {
+ Length = 1;
Size = 0;
+ Type = 0;
+ IsVarDecl = false;
LookupResult Result(*this, &Context.Idents.get(Name), Loc,
Sema::LookupOrdinaryName);
@@ -487,12 +515,19 @@ NamedDecl *Sema::LookupInlineAsmIdentifier(StringRef Name, SourceLocation Loc,
return 0;
}
- NamedDecl *ND = Result.getFoundDecl();
- if (isa<VarDecl>(ND) || isa<FunctionDecl>(ND)) {
- if (VarDecl *Var = dyn_cast<VarDecl>(ND))
- Size = Context.getTypeInfo(Var->getType()).first;
-
- return ND;
+ NamedDecl *FoundDecl = Result.getFoundDecl();
+ if (isa<FunctionDecl>(FoundDecl))
+ return FoundDecl;
+ if (VarDecl *Var = dyn_cast<VarDecl>(FoundDecl)) {
+ QualType Ty = Var->getType();
+ Type = Size = Context.getTypeSizeInChars(Ty).getQuantity();
+ if (Ty->isArrayType()) {
+ const ArrayType *ATy = Context.getAsArrayType(Ty);
+ Type = Context.getTypeSizeInChars(ATy->getElementType()).getQuantity();
+ Length = Size / Type;
+ }
+ IsVarDecl = true;
+ return FoundDecl;
}
// FIXME: Handle other kinds of results? (FieldDecl, etc.)
@@ -512,13 +547,12 @@ bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member,
if (!BaseResult.isSingleResult())
return true;
- NamedDecl *FoundDecl = BaseResult.getFoundDecl();
const RecordType *RT = 0;
- if (VarDecl *VD = dyn_cast<VarDecl>(FoundDecl)) {
+ NamedDecl *FoundDecl = BaseResult.getFoundDecl();
+ if (VarDecl *VD = dyn_cast<VarDecl>(FoundDecl))
RT = VD->getType()->getAs<RecordType>();
- } else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(FoundDecl)) {
+ else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(FoundDecl))
RT = TD->getUnderlyingType()->getAs<RecordType>();
- }
if (!RT)
return true;
@@ -551,8 +585,15 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
SmallVector<Expr*, 4> Exprs;
SmallVector<StringRef, 4> ClobberRefs;
+ llvm::Triple TheTriple = Context.getTargetInfo().getTriple();
+ llvm::Triple::ArchType ArchTy = TheTriple.getArch();
+ bool UnsupportedArch = ArchTy != llvm::Triple::x86 &&
+ ArchTy != llvm::Triple::x86_64;
+ if (UnsupportedArch)
+ Diag(AsmLoc, diag::err_msasm_unsupported_arch) << TheTriple.getArchName();
+
// Empty asm statements don't need to instantiate the AsmParser, etc.
- if (AsmToks.empty()) {
+ if (UnsupportedArch || AsmToks.empty()) {
StringRef EmptyAsmStr;
MSAsmStmt *NS =
new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ true,
@@ -563,13 +604,13 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
}
std::string AsmString;
- llvm::SmallVector<unsigned, 8> TokOffsets;
+ SmallVector<unsigned, 8> TokOffsets;
if (buildMSAsmString(*this, AsmLoc, AsmToks, TokOffsets, AsmString))
return StmtError();
// Get the target specific parser.
std::string Error;
- const std::string &TT = Context.getTargetInfo().getTriple().getTriple();
+ const std::string &TT = TheTriple.getTriple();
const llvm::Target *TheTarget(llvm::TargetRegistry::lookupTarget(TT, Error));
OwningPtr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TT));
@@ -614,7 +655,7 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
SmallVector<std::pair<void *, bool>, 4> OpDecls;
SmallVector<std::string, 4> Constraints;
SmallVector<std::string, 4> Clobbers;
- if (Parser->ParseMSInlineAsm(AsmLoc.getPtrEncoding(), AsmStringIR,
+ if (Parser->parseMSInlineAsm(AsmLoc.getPtrEncoding(), AsmStringIR,
NumOutputs, NumInputs, OpDecls, Constraints,
Clobbers, MII, IP, MCAPSI))
return StmtError();
@@ -641,7 +682,7 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc,
if (OpExpr.isInvalid())
return StmtError();
- // Need offset of variable.
+ // Need address of variable.
if (OpDecls[i].second)
OpExpr = BuildUnaryOp(getCurScope(), AsmLoc, clang::UO_AddrOf,
OpExpr.take());
diff --git a/lib/Sema/SemaStmtAttr.cpp b/lib/Sema/SemaStmtAttr.cpp
index b268b45..eb0188a 100644
--- a/lib/Sema/SemaStmtAttr.cpp
+++ b/lib/Sema/SemaStmtAttr.cpp
@@ -58,8 +58,8 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A,
default:
// 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();
+ S.Diag(A.getRange().getBegin(), diag::err_attribute_invalid_on_stmt)
+ << A.getName() << St->getLocStart();
return 0;
}
}
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index f56b054..9906261 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -9,23 +9,23 @@
// This file implements semantic analysis for C++ templates.
//===----------------------------------------------------------------------===/
-#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/Scope.h"
-#include "clang/Sema/Template.h"
-#include "clang/Sema/TemplateDeduction.h"
#include "TreeTransform.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/ExprCXX.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/TypeVisitor.h"
-#include "clang/Sema/DeclSpec.h"
-#include "clang/Sema/ParsedTemplate.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/ParsedTemplate.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/Template.h"
+#include "clang/Sema/TemplateDeduction.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
@@ -356,7 +356,7 @@ void Sema::LookupTemplateName(LookupResult &Found,
}
if (S && !ObjectType.isNull() && !ObjectTypeSearchedInScope &&
- !(getLangOpts().CPlusPlus0x && !Found.empty())) {
+ !(getLangOpts().CPlusPlus11 && !Found.empty())) {
// C++03 [basic.lookup.classref]p1:
// [...] If the lookup in the class of the object expression finds a
// template, the name is also looked up in the context of the entire
@@ -510,7 +510,7 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef,
TemplateName Template = Arg.getAsTemplate().get();
TemplateArgument TArg;
if (Arg.getEllipsisLoc().isValid())
- TArg = TemplateArgument(Template, llvm::Optional<unsigned int>());
+ TArg = TemplateArgument(Template, Optional<unsigned int>());
else
TArg = Template;
return TemplateArgumentLoc(TArg,
@@ -1171,7 +1171,7 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S,
// template-argument, that declaration shall be a definition and shall be
// the only declaration of the function template in the translation unit.
// (C++98/03 doesn't have this wording; see DR226).
- S.Diag(ParamLoc, S.getLangOpts().CPlusPlus0x ?
+ S.Diag(ParamLoc, S.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_template_parameter_default_in_function_template
: diag::ext_template_parameter_default_in_function_template)
<< DefArgRange;
@@ -2359,7 +2359,7 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S,
TemplateTy &Result) {
if (TemplateKWLoc.isValid() && S && !S->getTemplateParamParent())
Diag(TemplateKWLoc,
- getLangOpts().CPlusPlus0x ?
+ getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_template_outside_of_template :
diag::ext_template_outside_of_template)
<< FixItHint::CreateRemoval(TemplateKWLoc);
@@ -2387,7 +2387,7 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S,
// "template" keyword is now permitted). We follow the C++0x
// rules, even in C++03 mode with a warning, retroactively applying the DR.
bool MemberOfUnknownSpecialization;
- TemplateNameKind TNK = isTemplateName(0, SS, TemplateKWLoc.isValid(), Name,
+ TemplateNameKind TNK = isTemplateName(S, SS, TemplateKWLoc.isValid(), Name,
ObjectType, EnteringContext, Result,
MemberOfUnknownSpecialization);
if (TNK == TNK_Non_template && LookupCtx->isDependentContext() &&
@@ -2972,7 +2972,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
// We have a template template parameter but the template
// argument does not refer to a template.
Diag(Arg.getLocation(), diag::err_template_arg_must_be_template)
- << getLangOpts().CPlusPlus0x;
+ << getLangOpts().CPlusPlus11;
return true;
case TemplateArgument::Declaration:
@@ -3023,7 +3023,7 @@ static bool diagnoseArityMismatch(Sema &S, TemplateDecl *Template,
///
/// In \c A<int,int>::B, \c NTs and \c TTs have expanded pack size 2, and \c Us
/// is not a pack expansion, so returns an empty Optional.
-static llvm::Optional<unsigned> getExpandedPackSize(NamedDecl *Param) {
+static Optional<unsigned> getExpandedPackSize(NamedDecl *Param) {
if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(Param)) {
if (NTTP->isExpandedParameterPack())
@@ -3036,7 +3036,7 @@ static llvm::Optional<unsigned> getExpandedPackSize(NamedDecl *Param) {
return TTP->getNumExpansionTemplateParameters();
}
- return llvm::Optional<unsigned>();
+ return None;
}
/// \brief Check that the given template argument list is well-formed
@@ -3068,7 +3068,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
Param != ParamEnd; /* increment in loop */) {
// If we have an expanded parameter pack, make sure we don't have too
// many arguments.
- if (llvm::Optional<unsigned> Expansions = getExpandedPackSize(*Param)) {
+ if (Optional<unsigned> Expansions = getExpandedPackSize(*Param)) {
if (*Expansions == ArgumentPack.size()) {
// We're done with this parameter pack. Pack up its arguments and add
// them to the list.
@@ -3486,16 +3486,16 @@ bool UnnamedLocalNoLinkageFinder::VisitAtomicType(const AtomicType* T) {
bool UnnamedLocalNoLinkageFinder::VisitTagDecl(const TagDecl *Tag) {
if (Tag->getDeclContext()->isFunctionOrMethod()) {
S.Diag(SR.getBegin(),
- S.getLangOpts().CPlusPlus0x ?
+ S.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_template_arg_local_type :
diag::ext_template_arg_local_type)
<< S.Context.getTypeDeclType(Tag) << SR;
return true;
}
- if (!Tag->getDeclName() && !Tag->getTypedefNameForAnonDecl()) {
+ if (!Tag->hasNameForLinkage()) {
S.Diag(SR.getBegin(),
- S.getLangOpts().CPlusPlus0x ?
+ S.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_template_arg_unnamed_type :
diag::ext_template_arg_unnamed_type) << SR;
S.Diag(Tag->getLocation(), diag::note_template_unnamed_type_here);
@@ -3549,7 +3549,7 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param,
//
// C++11 allows these, and even in C++03 we allow them as an extension with
// a warning.
- if (LangOpts.CPlusPlus0x ?
+ if (LangOpts.CPlusPlus11 ?
Diags.getDiagnosticLevel(diag::warn_cxx98_compat_template_arg_unnamed_type,
SR.getBegin()) != DiagnosticsEngine::Ignored ||
Diags.getDiagnosticLevel(diag::warn_cxx98_compat_template_arg_local_type,
@@ -3576,7 +3576,7 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param,
if (Arg->isValueDependent() || Arg->isTypeDependent())
return NPV_NotNullPointer;
- if (!S.getLangOpts().CPlusPlus0x)
+ if (!S.getLangOpts().CPlusPlus11)
return NPV_NotNullPointer;
// Determine whether we have a constant expression.
@@ -3586,7 +3586,7 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param,
Arg = ArgRV.take();
Expr::EvalResult EvalResult;
- llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ SmallVector<PartialDiagnosticAt, 8> Notes;
EvalResult.Diag = &Notes;
if (!Arg->EvaluateAsRValue(EvalResult, S.Context) ||
EvalResult.HasSideEffects) {
@@ -3704,7 +3704,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) {
if (!Invalid && !ExtraParens) {
S.Diag(Arg->getLocStart(),
- S.getLangOpts().CPlusPlus0x ?
+ S.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_template_arg_extra_parens :
diag::ext_template_arg_extra_parens)
<< Arg->getSourceRange();
@@ -3794,7 +3794,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
// Address / reference template args must have external linkage in C++98.
if (Entity->getLinkage() == InternalLinkage) {
- S.Diag(Arg->getLocStart(), S.getLangOpts().CPlusPlus0x ?
+ S.Diag(Arg->getLocStart(), S.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_template_arg_object_internal :
diag::ext_template_arg_object_internal)
<< !Func << Entity << Arg->getSourceRange();
@@ -3950,7 +3950,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S,
// Create the template argument.
Converted = TemplateArgument(cast<ValueDecl>(Entity->getCanonicalDecl()),
ParamType->isReferenceType());
- S.MarkAnyDeclReferenced(Arg->getLocStart(), Entity);
+ S.MarkAnyDeclReferenced(Arg->getLocStart(), Entity, false);
return false;
}
@@ -4010,7 +4010,7 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S,
while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) {
if (!Invalid && !ExtraParens) {
S.Diag(Arg->getLocStart(),
- S.getLangOpts().CPlusPlus0x ?
+ S.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_template_arg_extra_parens :
diag::ext_template_arg_extra_parens)
<< Arg->getSourceRange();
@@ -4139,7 +4139,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return ExprError();
}
- if (getLangOpts().CPlusPlus0x) {
+ if (getLangOpts().CPlusPlus11) {
// We can't check arbitrary value-dependent arguments.
// FIXME: If there's no viable conversion to the template parameter type,
// we should be able to diagnose that prior to instantiation.
@@ -4495,6 +4495,16 @@ ExprResult
Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
QualType ParamType,
SourceLocation Loc) {
+ // C++ [temp.param]p8:
+ //
+ // A non-type template-parameter of type "array of T" or
+ // "function returning T" is adjusted to be of type "pointer to
+ // T" or "pointer to function returning T", respectively.
+ if (ParamType->isArrayType())
+ ParamType = Context.getArrayDecayedType(ParamType);
+ else if (ParamType->isFunctionType())
+ ParamType = Context.getPointerType(ParamType);
+
// For a NULL non-type template argument, return nullptr casted to the
// parameter's type.
if (Arg.getKind() == TemplateArgument::NullPtr) {
@@ -4560,6 +4570,7 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
}
QualType T = VD->getType().getNonReferenceType();
+
if (ParamType->isPointerType()) {
// When the non-type template parameter is a pointer, take the
// address of the declaration.
@@ -4589,6 +4600,9 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
VK = VK_LValue;
T = Context.getQualifiedType(T,
TargetRef->getPointeeType().getQualifiers());
+ } else if (isa<FunctionDecl>(VD)) {
+ // References to functions are always lvalues.
+ VK = VK_LValue;
}
return BuildDeclRefExpr(VD, T, VK, Loc);
@@ -4606,7 +4620,18 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
SourceLocation Loc) {
assert(Arg.getKind() == TemplateArgument::Integral &&
"Operation is only valid for integral template arguments");
- QualType T = Arg.getIntegralType();
+ QualType OrigT = Arg.getIntegralType();
+
+ // If this is an enum type that we're instantiating, we need to use an integer
+ // type the same size as the enumerator. We don't want to build an
+ // IntegerLiteral with enum type. The integer type of an enum type can be of
+ // any integral type with C++11 enum classes, make sure we create the right
+ // type of literal for it.
+ QualType T = OrigT;
+ if (const EnumType *ET = OrigT->getAs<EnumType>())
+ T = ET->getDecl()->getIntegerType();
+
+ Expr *E;
if (T->isAnyCharacterType()) {
CharacterLiteral::CharacterKind Kind;
if (T->isWideCharType())
@@ -4618,34 +4643,22 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
else
Kind = CharacterLiteral::Ascii;
- return Owned(new (Context) CharacterLiteral(
- Arg.getAsIntegral().getZExtValue(),
- Kind, T, Loc));
+ E = new (Context) CharacterLiteral(Arg.getAsIntegral().getZExtValue(),
+ Kind, T, Loc);
+ } else if (T->isBooleanType()) {
+ E = new (Context) CXXBoolLiteralExpr(Arg.getAsIntegral().getBoolValue(),
+ T, Loc);
+ } else if (T->isNullPtrType()) {
+ E = new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc);
+ } else {
+ E = IntegerLiteral::Create(Context, Arg.getAsIntegral(), T, Loc);
}
- if (T->isBooleanType())
- return Owned(new (Context) CXXBoolLiteralExpr(
- Arg.getAsIntegral().getBoolValue(),
- T, Loc));
-
- if (T->isNullPtrType())
- return Owned(new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc));
-
- // If this is an enum type that we're instantiating, we need to use an integer
- // type the same size as the enumerator. We don't want to build an
- // IntegerLiteral with enum type.
- QualType BT;
- if (const EnumType *ET = T->getAs<EnumType>())
- BT = ET->getDecl()->getIntegerType();
- else
- BT = T;
-
- Expr *E = IntegerLiteral::Create(Context, Arg.getAsIntegral(), BT, Loc);
- if (T->isEnumeralType()) {
+ if (OrigT->isEnumeralType()) {
// FIXME: This is a hack. We need a better way to handle substituted
// non-type template parameters.
- E = CStyleCastExpr::Create(Context, T, VK_RValue, CK_IntegralCast, E, 0,
- Context.getTrivialTypeSourceInfo(T, Loc),
+ E = CStyleCastExpr::Create(Context, OrigT, VK_RValue, CK_IntegralCast, E, 0,
+ Context.getTrivialTypeSourceInfo(OrigT, Loc),
Loc, Loc);
}
@@ -4961,11 +4974,11 @@ static bool CheckTemplateSpecializationScope(Sema &S,
EntityKind = 4;
else if (isa<RecordDecl>(Specialized))
EntityKind = 5;
- else if (isa<EnumDecl>(Specialized) && S.getLangOpts().CPlusPlus0x)
+ else if (isa<EnumDecl>(Specialized) && S.getLangOpts().CPlusPlus11)
EntityKind = 6;
else {
S.Diag(Loc, diag::err_template_spec_unknown_kind)
- << S.getLangOpts().CPlusPlus0x;
+ << S.getLangOpts().CPlusPlus11;
S.Diag(Specialized->getLocation(), diag::note_specialized_entity);
return true;
}
@@ -5036,17 +5049,17 @@ static bool CheckTemplateSpecializationScope(Sema &S,
// An explicit specialization shall be declared in a namespace enclosing
// the specialized template.
if (!DC->InEnclosingNamespaceSetOf(SpecializedContext)) {
- bool IsCPlusPlus0xExtension = DC->Encloses(SpecializedContext);
+ bool IsCPlusPlus11Extension = DC->Encloses(SpecializedContext);
if (isa<TranslationUnitDecl>(SpecializedContext)) {
- assert(!IsCPlusPlus0xExtension &&
+ assert(!IsCPlusPlus11Extension &&
"DC encloses TU but isn't in enclosing namespace set");
S.Diag(Loc, diag::err_template_spec_decl_out_of_scope_global)
<< EntityKind << Specialized;
} else if (isa<NamespaceDecl>(SpecializedContext)) {
int Diag;
- if (!IsCPlusPlus0xExtension)
+ if (!IsCPlusPlus11Extension)
Diag = diag::err_template_spec_decl_out_of_scope;
- else if (!S.getLangOpts().CPlusPlus0x)
+ else if (!S.getLangOpts().CPlusPlus11)
Diag = diag::ext_template_spec_decl_out_of_scope;
else
Diag = diag::warn_cxx98_compat_template_spec_decl_out_of_scope;
@@ -5056,7 +5069,7 @@ static bool CheckTemplateSpecializationScope(Sema &S,
S.Diag(Specialized->getLocation(), diag::note_specialized_entity);
ComplainedAboutScope =
- !(IsCPlusPlus0xExtension && S.getLangOpts().CPlusPlus0x);
+ !(IsCPlusPlus11Extension && S.getLangOpts().CPlusPlus11);
}
}
@@ -5629,23 +5642,21 @@ Decl *Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
D.setFunctionDefinitionKind(FDK_Definition);
Decl *DP = HandleDeclarator(ParentScope, D,
TemplateParameterLists);
- if (FunctionTemplateDecl *FunctionTemplate
- = dyn_cast_or_null<FunctionTemplateDecl>(DP))
- return ActOnStartOfFunctionDef(FnBodyScope,
- FunctionTemplate->getTemplatedDecl());
- if (FunctionDecl *Function = dyn_cast_or_null<FunctionDecl>(DP))
- return ActOnStartOfFunctionDef(FnBodyScope, Function);
- return 0;
+ return ActOnStartOfFunctionDef(FnBodyScope, DP);
}
/// \brief Strips various properties off an implicit instantiation
/// that has just been explicitly specialized.
static void StripImplicitInstantiation(NamedDecl *D) {
- // FIXME: "make check" is clean if the call to dropAttrs() is commented out.
D->dropAttrs();
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
FD->setInlineSpecified(false);
+
+ for (FunctionDecl::param_iterator I = FD->param_begin(),
+ E = FD->param_end();
+ I != E; ++I)
+ (*I)->dropAttrs();
}
}
@@ -5803,7 +5814,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc,
// In C++98/03 mode, we only give an extension warning here, because it
// is not harmful to try to explicitly instantiate something that
// has been explicitly specialized.
- Diag(NewLoc, getLangOpts().CPlusPlus0x ?
+ Diag(NewLoc, getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_explicit_instantiation_after_specialization :
diag::ext_explicit_instantiation_after_specialization)
<< PrevDecl;
@@ -5925,6 +5936,26 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
Ovl->getDeclContext()->getRedeclContext()))
continue;
+ // When matching a constexpr member function template specialization
+ // against the primary template, we don't yet know whether the
+ // specialization has an implicit 'const' (because we don't know whether
+ // it will be a static member function until we know which template it
+ // specializes), so adjust it now assuming it specializes this template.
+ QualType FT = FD->getType();
+ if (FD->isConstexpr()) {
+ CXXMethodDecl *OldMD =
+ dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());
+ if (OldMD && OldMD->isConst()) {
+ const FunctionProtoType *FPT = FT->castAs<FunctionProtoType>();
+ FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
+ EPI.TypeQuals |= Qualifiers::Const;
+ FT = Context.getFunctionType(FPT->getResultType(),
+ ArrayRef<QualType>(FPT->arg_type_begin(),
+ FPT->getNumArgs()),
+ EPI);
+ }
+ }
+
// C++ [temp.expl.spec]p11:
// A trailing template-argument can be left unspecified in the
// template-id naming an explicit function template specialization
@@ -5935,10 +5966,8 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
TemplateDeductionInfo Info(FD->getLocation());
FunctionDecl *Specialization = 0;
if (TemplateDeductionResult TDK
- = DeduceTemplateArguments(FunTmpl, ExplicitTemplateArgs,
- FD->getType(),
- Specialization,
- Info)) {
+ = DeduceTemplateArguments(FunTmpl, ExplicitTemplateArgs, FT,
+ Specialization, Info)) {
// FIXME: Template argument deduction failed; record why it failed, so
// that we can provide nifty diagnostics.
(void)TDK;
@@ -6028,8 +6057,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
TemplArgs, /*InsertPos=*/0,
SpecInfo->getTemplateSpecializationKind(),
ExplicitTemplateArgs);
- FD->setStorageClass(Specialization->getStorageClass());
-
+
// The "previous declaration" for this function template specialization is
// the prior function template specialization.
Previous.clear();
@@ -6257,19 +6285,19 @@ static bool CheckExplicitInstantiationScope(Sema &S, NamedDecl *D,
if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(OrigContext)) {
if (WasQualifiedName)
S.Diag(InstLoc,
- S.getLangOpts().CPlusPlus0x?
+ S.getLangOpts().CPlusPlus11?
diag::err_explicit_instantiation_out_of_scope :
diag::warn_explicit_instantiation_out_of_scope_0x)
<< D << NS;
else
S.Diag(InstLoc,
- S.getLangOpts().CPlusPlus0x?
+ S.getLangOpts().CPlusPlus11?
diag::err_explicit_instantiation_unqualified_wrong_namespace :
diag::warn_explicit_instantiation_unqualified_wrong_namespace_0x)
<< D << NS;
} else
S.Diag(InstLoc,
- S.getLangOpts().CPlusPlus0x?
+ S.getLangOpts().CPlusPlus11?
diag::err_explicit_instantiation_must_be_global :
diag::warn_explicit_instantiation_must_be_global_0x)
<< D;
@@ -6663,7 +6691,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
// well.
if (D.getDeclSpec().isInlineSpecified())
Diag(D.getDeclSpec().getInlineSpecLoc(),
- getLangOpts().CPlusPlus0x ?
+ getLangOpts().CPlusPlus11 ?
diag::err_explicit_instantiation_inline :
diag::warn_explicit_instantiation_inline_0x)
<< FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc());
@@ -6920,7 +6948,7 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
if (TypenameLoc.isValid() && S && !S->getTemplateParamParent())
Diag(TypenameLoc,
- getLangOpts().CPlusPlus0x ?
+ getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_typename_outside_of_template :
diag::ext_typename_outside_of_template)
<< FixItHint::CreateRemoval(TypenameLoc);
@@ -6933,15 +6961,15 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc,
TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T);
if (isa<DependentNameType>(T)) {
- DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc());
+ DependentNameTypeLoc TL = TSI->getTypeLoc().castAs<DependentNameTypeLoc>();
TL.setElaboratedKeywordLoc(TypenameLoc);
TL.setQualifierLoc(QualifierLoc);
TL.setNameLoc(IdLoc);
} else {
- ElaboratedTypeLoc TL = cast<ElaboratedTypeLoc>(TSI->getTypeLoc());
+ ElaboratedTypeLoc TL = TSI->getTypeLoc().castAs<ElaboratedTypeLoc>();
TL.setElaboratedKeywordLoc(TypenameLoc);
TL.setQualifierLoc(QualifierLoc);
- cast<TypeSpecTypeLoc>(TL.getNamedTypeLoc()).setNameLoc(IdLoc);
+ TL.getNamedTypeLoc().castAs<TypeSpecTypeLoc>().setNameLoc(IdLoc);
}
return CreateParsedType(T, TSI);
@@ -6959,7 +6987,7 @@ Sema::ActOnTypenameType(Scope *S,
SourceLocation RAngleLoc) {
if (TypenameLoc.isValid() && S && !S->getTemplateParamParent())
Diag(TypenameLoc,
- getLangOpts().CPlusPlus0x ?
+ getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_typename_outside_of_template :
diag::ext_typename_outside_of_template)
<< FixItHint::CreateRemoval(TypenameLoc);
@@ -7031,12 +7059,12 @@ static bool isEnableIf(NestedNameSpecifierLoc NNS, const IdentifierInfo &II,
if (!NNS || !NNS.getNestedNameSpecifier()->getAsType())
return false;
TypeLoc EnableIfTy = NNS.getTypeLoc();
- TemplateSpecializationTypeLoc *EnableIfTSTLoc =
- dyn_cast<TemplateSpecializationTypeLoc>(&EnableIfTy);
- if (!EnableIfTSTLoc || EnableIfTSTLoc->getNumArgs() == 0)
+ TemplateSpecializationTypeLoc EnableIfTSTLoc =
+ EnableIfTy.getAs<TemplateSpecializationTypeLoc>();
+ if (!EnableIfTSTLoc || EnableIfTSTLoc.getNumArgs() == 0)
return false;
const TemplateSpecializationType *EnableIfTST =
- cast<TemplateSpecializationType>(EnableIfTSTLoc->getTypePtr());
+ cast<TemplateSpecializationType>(EnableIfTSTLoc.getTypePtr());
// ... which names a complete class template declaration...
const TemplateDecl *EnableIfDecl =
@@ -7051,7 +7079,7 @@ static bool isEnableIf(NestedNameSpecifierLoc NNS, const IdentifierInfo &II,
return false;
// Assume the first template argument is the condition.
- CondRange = EnableIfTSTLoc->getArgLoc(0).getSourceRange();
+ CondRange = EnableIfTSTLoc.getArgLoc(0).getSourceRange();
return true;
}
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index bf4533d..f3bbe8a 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -10,18 +10,18 @@
//
//===----------------------------------------------------------------------===/
-#include "clang/Sema/Sema.h"
-#include "clang/Sema/DeclSpec.h"
-#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"
+#include "TreeTransform.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/StmtVisitor.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Sema/DeclSpec.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/Template.h"
#include "llvm/ADT/SmallBitVector.h"
-#include "TreeTransform.h"
#include <algorithm>
namespace clang {
@@ -130,8 +130,7 @@ DeduceTemplateArguments(Sema &S,
const TemplateArgument *Params, unsigned NumParams,
const TemplateArgument *Args, unsigned NumArgs,
TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- bool NumberOfArgumentsMustMatch = true);
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced);
/// \brief If the given expression is of a form that permits the deduction
/// of a non-type template parameter, return the declaration of that
@@ -482,21 +481,26 @@ DeduceTemplateArguments(Sema &S,
return DeduceTemplateArguments(S, TemplateParams,
Param->getArgs(), Param->getNumArgs(),
SpecArg->getArgs(), SpecArg->getNumArgs(),
- Info, Deduced,
- /*NumberOfArgumentsMustMatch=*/false);
+ Info, Deduced);
}
// If the argument type is a class template specialization, we
// perform template argument deduction using its template
// arguments.
const RecordType *RecordArg = dyn_cast<RecordType>(Arg);
- if (!RecordArg)
+ if (!RecordArg) {
+ Info.FirstArg = TemplateArgument(QualType(Param, 0));
+ Info.SecondArg = TemplateArgument(Arg);
return Sema::TDK_NonDeducedMismatch;
+ }
ClassTemplateSpecializationDecl *SpecArg
= dyn_cast<ClassTemplateSpecializationDecl>(RecordArg->getDecl());
- if (!SpecArg)
+ if (!SpecArg) {
+ Info.FirstArg = TemplateArgument(QualType(Param, 0));
+ Info.SecondArg = TemplateArgument(Arg);
return Sema::TDK_NonDeducedMismatch;
+ }
// Perform template argument deduction for the template name.
if (Sema::TemplateDeductionResult Result
@@ -710,7 +714,7 @@ DeduceTemplateArguments(Sema &S,
if (NumParams != NumArgs &&
!(NumParams && isa<PackExpansionType>(Params[NumParams - 1])) &&
!(NumArgs && isa<PackExpansionType>(Args[NumArgs - 1])))
- return Sema::TDK_NonDeducedMismatch;
+ return Sema::TDK_MiscellaneousDeductionFailure;
// C++0x [temp.deduct.type]p10:
// Similarly, if P has a form that contains (T), then each parameter type
@@ -727,14 +731,14 @@ DeduceTemplateArguments(Sema &S,
// Make sure we have an argument.
if (ArgIdx >= NumArgs)
- return Sema::TDK_NonDeducedMismatch;
+ return Sema::TDK_MiscellaneousDeductionFailure;
if (isa<PackExpansionType>(Args[ArgIdx])) {
// C++0x [temp.deduct.type]p22:
// If the original function parameter associated with A is a function
// parameter pack and the function parameter associated with P is not
// a function parameter pack, then template argument deduction fails.
- return Sema::TDK_NonDeducedMismatch;
+ return Sema::TDK_MiscellaneousDeductionFailure;
}
if (Sema::TemplateDeductionResult Result
@@ -827,7 +831,7 @@ DeduceTemplateArguments(Sema &S,
// Make sure we don't have any extra arguments.
if (ArgIdx < NumArgs)
- return Sema::TDK_NonDeducedMismatch;
+ return Sema::TDK_MiscellaneousDeductionFailure;
return Sema::TDK_Success;
}
@@ -1749,8 +1753,7 @@ DeduceTemplateArguments(Sema &S,
const TemplateArgument *Params, unsigned NumParams,
const TemplateArgument *Args, unsigned NumArgs,
TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced,
- bool NumberOfArgumentsMustMatch) {
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
// C++0x [temp.deduct.type]p9:
// If the template argument list of P contains a pack expansion that is not
// the last template argument, the entire template argument list is a
@@ -1770,13 +1773,12 @@ DeduceTemplateArguments(Sema &S,
// Check whether we have enough arguments.
if (!hasTemplateArgumentForDeduction(Args, ArgIdx, NumArgs))
- return NumberOfArgumentsMustMatch? Sema::TDK_NonDeducedMismatch
- : Sema::TDK_Success;
+ return Sema::TDK_Success;
if (Args[ArgIdx].isPackExpansion()) {
// FIXME: We follow the logic of C++0x [temp.deduct.type]p22 here,
// but applied to pack expansions that are template arguments.
- return Sema::TDK_NonDeducedMismatch;
+ return Sema::TDK_MiscellaneousDeductionFailure;
}
// Perform deduction for this Pi/Ai pair.
@@ -1867,11 +1869,6 @@ DeduceTemplateArguments(Sema &S,
return Result;
}
- // If there is an argument remaining, then we had too many arguments.
- if (NumberOfArgumentsMustMatch &&
- hasTemplateArgumentForDeduction(Args, ArgIdx, NumArgs))
- return Sema::TDK_NonDeducedMismatch;
-
return Sema::TDK_Success;
}
@@ -2400,7 +2397,7 @@ Sema::SubstituteExplicitTemplateArguments(
}
CXXThisScopeRAII ThisScope(*this, ThisContext, ThisTypeQuals,
- getLangOpts().CPlusPlus0x);
+ getLangOpts().CPlusPlus11);
ResultType = SubstType(Proto->getResultType(),
MultiLevelTemplateArgumentList(*ExplicitArgumentList),
@@ -2420,15 +2417,10 @@ Sema::SubstituteExplicitTemplateArguments(
return TDK_SubstitutionFailure;
if (FunctionType) {
- *FunctionType = BuildFunctionType(ResultType,
- ParamTypes.data(), ParamTypes.size(),
- Proto->isVariadic(),
- Proto->hasTrailingReturn(),
- Proto->getTypeQuals(),
- Proto->getRefQualifier(),
+ *FunctionType = BuildFunctionType(ResultType, ParamTypes,
Function->getLocation(),
Function->getDeclName(),
- Proto->getExtInfo());
+ Proto->getExtProtoInfo());
if (FunctionType->isNull() || Trap.hasErrorOccurred())
return TDK_SubstitutionFailure;
}
@@ -2656,11 +2648,15 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
if (CurrentInstantiationScope &&
CurrentInstantiationScope->getPartiallySubstitutedPack(&ExplicitArgs,
&NumExplicitArgs)
- == Param)
+ == Param) {
Builder.push_back(TemplateArgument(ExplicitArgs, NumExplicitArgs));
- else
- Builder.push_back(TemplateArgument::getEmptyPack());
+ // Forget the partially-substituted pack; it's substitution is now
+ // complete.
+ CurrentInstantiationScope->ResetPartiallySubstitutedPack();
+ } else {
+ Builder.push_back(TemplateArgument::getEmptyPack());
+ }
continue;
}
@@ -2884,7 +2880,8 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
/// described in C++ [temp.deduct.call].
///
/// \returns true if the caller should not attempt to perform any template
-/// argument deduction based on this P/A pair.
+/// argument deduction based on this P/A pair because the argument is an
+/// overloaded function set that could not be resolved.
static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S,
TemplateParameterList *TemplateParams,
QualType &ParamType,
@@ -2900,7 +2897,7 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S,
if (ParamRefType) {
QualType PointeeType = ParamRefType->getPointeeType();
- // If the argument has incomplete array type, try to complete it's type.
+ // If the argument has incomplete array type, try to complete its type.
if (ArgType->isIncompleteArrayType() && !S.RequireCompleteExprType(Arg, 0))
ArgType = Arg->getType();
@@ -2998,8 +2995,8 @@ static bool hasDeducibleTemplateParameters(Sema &S,
/// \brief Perform template argument deduction by matching a parameter type
/// against a single expression, where the expression is an element of
-/// an initializer list that was originally matched against the argument
-/// type.
+/// an initializer list that was originally matched against a parameter
+/// of type \c initializer_list\<ParamType\>.
static Sema::TemplateDeductionResult
DeduceTemplateArgumentByListElement(Sema &S,
TemplateParameterList *TemplateParams,
@@ -3028,8 +3025,10 @@ DeduceTemplateArgumentByListElement(Sema &S,
// For all other cases, just match by type.
QualType ArgType = Arg->getType();
if (AdjustFunctionParmAndArgTypesForDeduction(S, TemplateParams, ParamType,
- ArgType, Arg, TDF))
+ ArgType, Arg, TDF)) {
+ Info.Expression = Arg;
return Sema::TDK_FailedOverloadResolution;
+ }
return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, ParamType,
ArgType, Info, Deduced, TDF);
}
@@ -3045,11 +3044,6 @@ DeduceTemplateArgumentByListElement(Sema &S,
///
/// \param Args the function call arguments
///
-/// \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
-/// the function to which
-///
/// \param Specialization if template argument deduction was successful,
/// this will be set to the function template specialization produced by
/// template argument deduction.
@@ -3372,7 +3366,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
// specialization, template argument deduction fails.
if (!ArgFunctionType.isNull() &&
!Context.hasSameType(ArgFunctionType, Specialization->getType()))
- return TDK_NonDeducedMismatch;
+ return TDK_MiscellaneousDeductionFailure;
return TDK_Success;
}
@@ -3772,15 +3766,15 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
// first argument of the free function, which seems to match
// existing practice.
SmallVector<QualType, 4> Args1;
- unsigned Skip1 = !S.getLangOpts().CPlusPlus0x && IsNonStatic2 && !Method1;
- if (S.getLangOpts().CPlusPlus0x && IsNonStatic1 && !Method2)
+ unsigned Skip1 = !S.getLangOpts().CPlusPlus11 && IsNonStatic2 && !Method1;
+ if (S.getLangOpts().CPlusPlus11 && IsNonStatic1 && !Method2)
AddImplicitObjectParameterType(S.Context, Method1, Args1);
Args1.insert(Args1.end(),
Proto1->arg_type_begin() + Skip1, Proto1->arg_type_end());
SmallVector<QualType, 4> Args2;
- Skip2 = !S.getLangOpts().CPlusPlus0x && IsNonStatic1 && !Method2;
- if (S.getLangOpts().CPlusPlus0x && IsNonStatic2 && !Method1)
+ Skip2 = !S.getLangOpts().CPlusPlus11 && IsNonStatic1 && !Method2;
+ if (S.getLangOpts().CPlusPlus11 && IsNonStatic2 && !Method1)
AddImplicitObjectParameterType(S.Context, Method2, Args2);
Args2.insert(Args2.end(),
Proto2->arg_type_begin() + Skip2, Proto2->arg_type_end());
@@ -3849,7 +3843,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S,
unsigned NumParams = std::min(NumCallArguments,
std::min(Proto1->getNumArgs(),
Proto2->getNumArgs()));
- if (S.getLangOpts().CPlusPlus0x && IsNonStatic2 && !IsNonStatic1)
+ if (S.getLangOpts().CPlusPlus11 && IsNonStatic2 && !IsNonStatic1)
::MarkUsedTemplateParameters(S.Context, Method2->getThisType(S.Context),
false,
TemplateParams->getDepth(), UsedParameters);
@@ -4052,10 +4046,6 @@ static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) {
/// in this diagnostic should be unbound, which will correspond to the string
/// describing the template arguments for the function template specialization.
///
-/// \param Index if non-NULL and the result of this function is non-nULL,
-/// receives the index corresponding to the resulting function template
-/// specialization.
-///
/// \returns the most specialized function template specialization, if
/// found. Otherwise, returns SpecEnd.
///
@@ -4618,7 +4608,7 @@ Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
/// call to the given function template.
void
Sema::MarkDeducedTemplateParameters(ASTContext &Ctx,
- FunctionTemplateDecl *FunctionTemplate,
+ const FunctionTemplateDecl *FunctionTemplate,
llvm::SmallBitVector &Deduced) {
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 665dd07..f755b8c 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -12,16 +12,16 @@
#include "clang/Sema/SemaInternal.h"
#include "TreeTransform.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
+#include "clang/Basic/LangOptions.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"
-#include "clang/AST/ASTConsumer.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/DeclTemplate.h"
-#include "clang/Basic/LangOptions.h"
using namespace clang;
using namespace sema;
@@ -182,7 +182,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
ActiveTemplateInstantiation Inst;
Inst.Kind = ActiveTemplateInstantiation::TemplateInstantiation;
Inst.PointOfInstantiation = PointOfInstantiation;
- Inst.Entity = reinterpret_cast<uintptr_t>(Entity);
+ Inst.Entity = Entity;
Inst.TemplateArgs = 0;
Inst.NumTemplateArgs = 0;
Inst.InstantiationRange = InstantiationRange;
@@ -205,7 +205,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
ActiveTemplateInstantiation Inst;
Inst.Kind = ActiveTemplateInstantiation::ExceptionSpecInstantiation;
Inst.PointOfInstantiation = PointOfInstantiation;
- Inst.Entity = reinterpret_cast<uintptr_t>(Entity);
+ Inst.Entity = Entity;
Inst.TemplateArgs = 0;
Inst.NumTemplateArgs = 0;
Inst.InstantiationRange = InstantiationRange;
@@ -230,7 +230,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
Inst.Kind
= ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation;
Inst.PointOfInstantiation = PointOfInstantiation;
- Inst.Entity = reinterpret_cast<uintptr_t>(Template);
+ Inst.Entity = Template;
Inst.TemplateArgs = TemplateArgs.data();
Inst.NumTemplateArgs = TemplateArgs.size();
Inst.InstantiationRange = InstantiationRange;
@@ -255,7 +255,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
ActiveTemplateInstantiation Inst;
Inst.Kind = Kind;
Inst.PointOfInstantiation = PointOfInstantiation;
- Inst.Entity = reinterpret_cast<uintptr_t>(FunctionTemplate);
+ Inst.Entity = FunctionTemplate;
Inst.TemplateArgs = TemplateArgs.data();
Inst.NumTemplateArgs = TemplateArgs.size();
Inst.DeductionInfo = &DeductionInfo;
@@ -283,7 +283,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
ActiveTemplateInstantiation Inst;
Inst.Kind = ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution;
Inst.PointOfInstantiation = PointOfInstantiation;
- Inst.Entity = reinterpret_cast<uintptr_t>(PartialSpec);
+ Inst.Entity = PartialSpec;
Inst.TemplateArgs = TemplateArgs.data();
Inst.NumTemplateArgs = TemplateArgs.size();
Inst.DeductionInfo = &DeductionInfo;
@@ -308,7 +308,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
Inst.Kind
= ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation;
Inst.PointOfInstantiation = PointOfInstantiation;
- Inst.Entity = reinterpret_cast<uintptr_t>(Param);
+ Inst.Entity = Param;
Inst.TemplateArgs = TemplateArgs.data();
Inst.NumTemplateArgs = TemplateArgs.size();
Inst.InstantiationRange = InstantiationRange;
@@ -332,7 +332,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution;
Inst.PointOfInstantiation = PointOfInstantiation;
Inst.Template = Template;
- Inst.Entity = reinterpret_cast<uintptr_t>(Param);
+ Inst.Entity = Param;
Inst.TemplateArgs = TemplateArgs.data();
Inst.NumTemplateArgs = TemplateArgs.size();
Inst.InstantiationRange = InstantiationRange;
@@ -356,7 +356,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
Inst.Kind = ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution;
Inst.PointOfInstantiation = PointOfInstantiation;
Inst.Template = Template;
- Inst.Entity = reinterpret_cast<uintptr_t>(Param);
+ Inst.Entity = Param;
Inst.TemplateArgs = TemplateArgs.data();
Inst.NumTemplateArgs = TemplateArgs.size();
Inst.InstantiationRange = InstantiationRange;
@@ -380,7 +380,7 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
Inst.Kind = ActiveTemplateInstantiation::DefaultTemplateArgumentChecking;
Inst.PointOfInstantiation = PointOfInstantiation;
Inst.Template = Template;
- Inst.Entity = reinterpret_cast<uintptr_t>(Param);
+ Inst.Entity = Param;
Inst.TemplateArgs = TemplateArgs.data();
Inst.NumTemplateArgs = TemplateArgs.size();
Inst.InstantiationRange = InstantiationRange;
@@ -454,7 +454,7 @@ void Sema::PrintInstantiationStack() {
switch (Active->Kind) {
case ActiveTemplateInstantiation::TemplateInstantiation: {
- Decl *D = reinterpret_cast<Decl *>(Active->Entity);
+ Decl *D = Active->Entity;
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) {
unsigned DiagID = diag::note_template_member_class_here;
if (isa<ClassTemplateSpecializationDecl>(Record))
@@ -491,22 +491,23 @@ void Sema::PrintInstantiationStack() {
}
case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation: {
- TemplateDecl *Template = cast<TemplateDecl>((Decl *)Active->Entity);
- std::string TemplateArgsStr
- = TemplateSpecializationType::PrintTemplateArgumentList(
+ TemplateDecl *Template = cast<TemplateDecl>(Active->Entity);
+ SmallVector<char, 128> TemplateArgsStr;
+ llvm::raw_svector_ostream OS(TemplateArgsStr);
+ Template->printName(OS);
+ TemplateSpecializationType::PrintTemplateArgumentList(OS,
Active->TemplateArgs,
Active->NumTemplateArgs,
getPrintingPolicy());
Diags.Report(Active->PointOfInstantiation,
diag::note_default_arg_instantiation_here)
- << (Template->getNameAsString() + TemplateArgsStr)
+ << OS.str()
<< Active->InstantiationRange;
break;
}
case ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution: {
- FunctionTemplateDecl *FnTmpl
- = cast<FunctionTemplateDecl>((Decl *)Active->Entity);
+ FunctionTemplateDecl *FnTmpl = cast<FunctionTemplateDecl>(Active->Entity);
Diags.Report(Active->PointOfInstantiation,
diag::note_explicit_template_arg_substitution_here)
<< FnTmpl
@@ -518,9 +519,8 @@ void Sema::PrintInstantiationStack() {
}
case ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution:
- if (ClassTemplatePartialSpecializationDecl *PartialSpec
- = dyn_cast<ClassTemplatePartialSpecializationDecl>(
- (Decl *)Active->Entity)) {
+ if (ClassTemplatePartialSpecializationDecl *PartialSpec =
+ dyn_cast<ClassTemplatePartialSpecializationDecl>(Active->Entity)) {
Diags.Report(Active->PointOfInstantiation,
diag::note_partial_spec_deduct_instantiation_here)
<< Context.getTypeDeclType(PartialSpec)
@@ -531,7 +531,7 @@ void Sema::PrintInstantiationStack() {
<< Active->InstantiationRange;
} else {
FunctionTemplateDecl *FnTmpl
- = cast<FunctionTemplateDecl>((Decl *)Active->Entity);
+ = cast<FunctionTemplateDecl>(Active->Entity);
Diags.Report(Active->PointOfInstantiation,
diag::note_function_template_deduction_instantiation_here)
<< FnTmpl
@@ -543,23 +543,25 @@ void Sema::PrintInstantiationStack() {
break;
case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation: {
- ParmVarDecl *Param = cast<ParmVarDecl>((Decl *)Active->Entity);
+ ParmVarDecl *Param = cast<ParmVarDecl>(Active->Entity);
FunctionDecl *FD = cast<FunctionDecl>(Param->getDeclContext());
- std::string TemplateArgsStr
- = TemplateSpecializationType::PrintTemplateArgumentList(
+ SmallVector<char, 128> TemplateArgsStr;
+ llvm::raw_svector_ostream OS(TemplateArgsStr);
+ FD->printName(OS);
+ TemplateSpecializationType::PrintTemplateArgumentList(OS,
Active->TemplateArgs,
Active->NumTemplateArgs,
getPrintingPolicy());
Diags.Report(Active->PointOfInstantiation,
diag::note_default_function_arg_instantiation_here)
- << (FD->getNameAsString() + TemplateArgsStr)
+ << OS.str()
<< Active->InstantiationRange;
break;
}
case ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution: {
- NamedDecl *Parm = cast<NamedDecl>((Decl *)Active->Entity);
+ NamedDecl *Parm = cast<NamedDecl>(Active->Entity);
std::string Name;
if (!Parm->getName().empty())
Name = std::string(" '") + Parm->getName().str() + "'";
@@ -603,16 +605,16 @@ void Sema::PrintInstantiationStack() {
case ActiveTemplateInstantiation::ExceptionSpecInstantiation:
Diags.Report(Active->PointOfInstantiation,
diag::note_template_exception_spec_instantiation_here)
- << cast<FunctionDecl>((Decl *)Active->Entity)
+ << cast<FunctionDecl>(Active->Entity)
<< Active->InstantiationRange;
break;
}
}
}
-llvm::Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
+Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
if (InNonInstantiationSFINAEContext)
- return llvm::Optional<TemplateDeductionInfo *>(0);
+ return Optional<TemplateDeductionInfo *>(0);
for (SmallVector<ActiveTemplateInstantiation, 16>::const_reverse_iterator
Active = ActiveTemplateInstantiations.rbegin(),
@@ -624,13 +626,13 @@ llvm::Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
case ActiveTemplateInstantiation::TemplateInstantiation:
// An instantiation of an alias template may or may not be a SFINAE
// context, depending on what else is on the stack.
- if (isa<TypeAliasTemplateDecl>(reinterpret_cast<Decl *>(Active->Entity)))
+ if (isa<TypeAliasTemplateDecl>(Active->Entity))
break;
// Fall through.
case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation:
case ActiveTemplateInstantiation::ExceptionSpecInstantiation:
// This is a template instantiation, so there is no SFINAE.
- return llvm::Optional<TemplateDeductionInfo *>();
+ return None;
case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation:
case ActiveTemplateInstantiation::PriorTemplateArgumentSubstitution:
@@ -649,7 +651,7 @@ llvm::Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
}
}
- return llvm::Optional<TemplateDeductionInfo *>();
+ return None;
}
/// \brief Retrieve the depth and index of a parameter pack.
@@ -709,7 +711,7 @@ namespace {
llvm::ArrayRef<UnexpandedParameterPack> Unexpanded,
bool &ShouldExpand,
bool &RetainExpansion,
- llvm::Optional<unsigned> &NumExpansions) {
+ Optional<unsigned> &NumExpansions) {
return getSema().CheckParameterPacksForExpansion(EllipsisLoc,
PatternRange, Unexpanded,
TemplateArgs,
@@ -829,7 +831,7 @@ namespace {
ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm,
int indexAdjustment,
- llvm::Optional<unsigned> NumExpansions,
+ Optional<unsigned> NumExpansions,
bool ExpectParameterPack);
/// \brief Transforms a template type parameter type by performing
@@ -1267,7 +1269,7 @@ TemplateInstantiator::TransformFunctionParmPackExpr(FunctionParmPackExpr *E) {
// Transform each of the parameter expansions into the corresponding
// parameters in the instantiation of the function decl.
- llvm::SmallVector<Decl*, 8> Parms;
+ SmallVector<Decl *, 8> Parms;
Parms.reserve(E->getNumExpansions());
for (FunctionParmPackExpr::iterator I = E->begin(), End = E->end();
I != End; ++I) {
@@ -1365,7 +1367,7 @@ QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB,
ParmVarDecl *
TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm,
int indexAdjustment,
- llvm::Optional<unsigned> NumExpansions,
+ Optional<unsigned> NumExpansions,
bool ExpectParameterPack) {
return SemaRef.SubstParmVarDecl(OldParm, TemplateArgs, indexAdjustment,
NumExpansions, ExpectParameterPack);
@@ -1568,10 +1570,10 @@ static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) {
return true;
TypeLoc TL = T->getTypeLoc().IgnoreParens();
- if (!isa<FunctionProtoTypeLoc>(TL))
+ if (!TL.getAs<FunctionProtoTypeLoc>())
return false;
- FunctionProtoTypeLoc FP = cast<FunctionProtoTypeLoc>(TL);
+ FunctionProtoTypeLoc FP = TL.castAs<FunctionProtoTypeLoc>();
for (unsigned I = 0, E = FP.getNumArgs(); I != E; ++I) {
ParmVarDecl *P = FP.getArg(I);
@@ -1615,9 +1617,9 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
TLB.reserve(TL.getFullDataSize());
QualType Result;
-
- if (FunctionProtoTypeLoc *Proto = dyn_cast<FunctionProtoTypeLoc>(&TL)) {
- Result = Instantiator.TransformFunctionProtoType(TLB, *Proto, ThisContext,
+
+ if (FunctionProtoTypeLoc Proto = TL.getAs<FunctionProtoTypeLoc>()) {
+ Result = Instantiator.TransformFunctionProtoType(TLB, Proto, ThisContext,
ThisTypeQuals);
} else {
Result = Instantiator.TransformType(TLB, TL);
@@ -1631,15 +1633,14 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
const MultiLevelTemplateArgumentList &TemplateArgs,
int indexAdjustment,
- llvm::Optional<unsigned> NumExpansions,
+ Optional<unsigned> NumExpansions,
bool ExpectParameterPack) {
TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
TypeSourceInfo *NewDI = 0;
TypeLoc OldTL = OldDI->getTypeLoc();
- if (isa<PackExpansionTypeLoc>(OldTL)) {
- PackExpansionTypeLoc ExpansionTL = cast<PackExpansionTypeLoc>(OldTL);
-
+ if (PackExpansionTypeLoc ExpansionTL = OldTL.getAs<PackExpansionTypeLoc>()) {
+
// We have a function parameter pack. Substitute into the pattern of the
// expansion.
NewDI = SubstType(ExpansionTL.getPatternLoc(), TemplateArgs,
@@ -1681,8 +1682,7 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
OldParm->getLocation(),
OldParm->getIdentifier(),
NewDI->getType(), NewDI,
- OldParm->getStorageClass(),
- OldParm->getStorageClassAsWritten());
+ OldParm->getStorageClass());
if (!NewParm)
return 0;
@@ -1715,7 +1715,9 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
NewParm->setScopeInfo(OldParm->getFunctionScopeDepth(),
OldParm->getFunctionScopeIndex() + indexAdjustment);
-
+
+ InstantiateAttrs(TemplateArgs, OldParm, NewParm);
+
return NewParm;
}
@@ -1767,7 +1769,7 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
Unexpanded);
bool ShouldExpand = false;
bool RetainExpansion = false;
- llvm::Optional<unsigned> NumExpansions;
+ Optional<unsigned> NumExpansions;
if (CheckParameterPacksForExpansion(Base->getEllipsisLoc(),
Base->getSourceRange(),
Unexpanded,
@@ -2047,6 +2049,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
CheckCompletedCXXClass(Instantiation);
// Attach any in-class member initializers now the class is complete.
+ // FIXME: We are supposed to defer instantiating these until they are needed.
if (!FieldsWithMemberInitializers.empty()) {
// C++11 [expr.prim.general]p4:
// Otherwise, if a member-declarator declares a non-static data member
@@ -2583,12 +2586,21 @@ Sema::SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs) {
return Instantiator.TransformExpr(E);
}
+ExprResult Sema::SubstInitializer(Expr *Init,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ bool CXXDirectInit) {
+ TemplateInstantiator Instantiator(*this, TemplateArgs,
+ SourceLocation(),
+ DeclarationName());
+ return Instantiator.TransformInitializer(Init, CXXDirectInit);
+}
+
bool Sema::SubstExprs(Expr **Exprs, unsigned NumExprs, bool IsCall,
const MultiLevelTemplateArgumentList &TemplateArgs,
SmallVectorImpl<Expr *> &Outputs) {
if (NumExprs == 0)
return false;
-
+
TemplateInstantiator Instantiator(*this, TemplateArgs,
SourceLocation(),
DeclarationName());
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 19c46ab..33e83d0 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -10,9 +10,6 @@
//
//===----------------------------------------------------------------------===/
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/PrettyDeclStackTrace.h"
-#include "clang/Sema/Template.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
@@ -22,6 +19,9 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/PrettyDeclStackTrace.h"
+#include "clang/Sema/Template.h"
using namespace clang;
@@ -60,6 +60,64 @@ bool TemplateDeclInstantiator::SubstQualifier(const TagDecl *OldDecl,
// Include attribute instantiation code.
#include "clang/Sema/AttrTemplateInstantiate.inc"
+static void instantiateDependentAlignedAttr(
+ Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
+ const AlignedAttr *Aligned, Decl *New, bool IsPackExpansion) {
+ if (Aligned->isAlignmentExpr()) {
+ // The alignment expression is a constant expression.
+ EnterExpressionEvaluationContext Unevaluated(S, Sema::ConstantEvaluated);
+ ExprResult Result = S.SubstExpr(Aligned->getAlignmentExpr(), TemplateArgs);
+ if (!Result.isInvalid())
+ S.AddAlignedAttr(Aligned->getLocation(), New, Result.takeAs<Expr>(),
+ Aligned->getSpellingListIndex(), IsPackExpansion);
+ } else {
+ TypeSourceInfo *Result = S.SubstType(Aligned->getAlignmentType(),
+ TemplateArgs, Aligned->getLocation(),
+ DeclarationName());
+ if (Result)
+ S.AddAlignedAttr(Aligned->getLocation(), New, Result,
+ Aligned->getSpellingListIndex(), IsPackExpansion);
+ }
+}
+
+static void instantiateDependentAlignedAttr(
+ Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
+ const AlignedAttr *Aligned, Decl *New) {
+ if (!Aligned->isPackExpansion()) {
+ instantiateDependentAlignedAttr(S, TemplateArgs, Aligned, New, false);
+ return;
+ }
+
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ if (Aligned->isAlignmentExpr())
+ S.collectUnexpandedParameterPacks(Aligned->getAlignmentExpr(),
+ Unexpanded);
+ else
+ S.collectUnexpandedParameterPacks(Aligned->getAlignmentType()->getTypeLoc(),
+ Unexpanded);
+ assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
+
+ // Determine whether we can expand this attribute pack yet.
+ bool Expand = true, RetainExpansion = false;
+ Optional<unsigned> NumExpansions;
+ // FIXME: Use the actual location of the ellipsis.
+ SourceLocation EllipsisLoc = Aligned->getLocation();
+ if (S.CheckParameterPacksForExpansion(EllipsisLoc, Aligned->getRange(),
+ Unexpanded, TemplateArgs, Expand,
+ RetainExpansion, NumExpansions))
+ return;
+
+ if (!Expand) {
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(S, -1);
+ instantiateDependentAlignedAttr(S, TemplateArgs, Aligned, New, true);
+ } else {
+ for (unsigned I = 0; I != *NumExpansions; ++I) {
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(S, I);
+ instantiateDependentAlignedAttr(S, TemplateArgs, Aligned, New, false);
+ }
+ }
+}
+
void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
const Decl *Tmpl, Decl *New,
LateInstantiatedAttrVec *LateAttrs,
@@ -69,31 +127,13 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
const Attr *TmplAttr = *i;
// FIXME: This should be generalized to more than just the AlignedAttr.
- if (const AlignedAttr *Aligned = dyn_cast<AlignedAttr>(TmplAttr)) {
- if (Aligned->isAlignmentDependent()) {
- if (Aligned->isAlignmentExpr()) {
- // The alignment expression is a constant expression.
- EnterExpressionEvaluationContext Unevaluated(*this,
- Sema::ConstantEvaluated);
-
- ExprResult Result = SubstExpr(Aligned->getAlignmentExpr(),
- TemplateArgs);
- if (!Result.isInvalid())
- AddAlignedAttr(Aligned->getLocation(), New, Result.takeAs<Expr>(),
- Aligned->getIsMSDeclSpec());
- } else {
- TypeSourceInfo *Result = SubstType(Aligned->getAlignmentType(),
- TemplateArgs,
- Aligned->getLocation(),
- DeclarationName());
- if (Result)
- AddAlignedAttr(Aligned->getLocation(), New, Result,
- Aligned->getIsMSDeclSpec());
- }
- continue;
- }
+ const AlignedAttr *Aligned = dyn_cast<AlignedAttr>(TmplAttr);
+ if (Aligned && Aligned->isAlignmentDependent()) {
+ instantiateDependentAlignedAttr(*this, TemplateArgs, Aligned, New);
+ continue;
}
+ assert(!TmplAttr->isPackExpansion());
if (TmplAttr->isLateParsed() && LateAttrs) {
// Late parsed attributes must be instantiated and attached after the
// enclosing class has been instantiated. See Sema::InstantiateClass.
@@ -189,9 +229,9 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D,
// tag decl, re-establish that relationship for the new typedef.
if (const TagType *oldTagType = D->getUnderlyingType()->getAs<TagType>()) {
TagDecl *oldTag = oldTagType->getDecl();
- if (oldTag->getTypedefNameForAnonDecl() == D) {
+ if (oldTag->getTypedefNameForAnonDecl() == D && !Invalid) {
TagDecl *newTag = DI->getType()->castAs<TagType>()->getDecl();
- assert(!newTag->getIdentifier() && !newTag->getTypedefNameForAnonDecl());
+ assert(!newTag->hasNameForLinkage());
newTag->setTypedefNameForAnonDecl(Typedef);
}
}
@@ -245,8 +285,8 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
TypeAliasTemplateDecl *PrevAliasTemplate = 0;
if (Pattern->getPreviousDecl()) {
DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName());
- if (Found.first != Found.second) {
- PrevAliasTemplate = dyn_cast<TypeAliasTemplateDecl>(*Found.first);
+ if (!Found.empty()) {
+ PrevAliasTemplate = dyn_cast<TypeAliasTemplateDecl>(Found.front());
}
}
@@ -298,8 +338,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
D->getInnerLocStart(),
D->getLocation(), D->getIdentifier(),
DI->getType(), DI,
- D->getStorageClass(),
- D->getStorageClassAsWritten());
+ D->getStorageClass());
Var->setThreadSpecified(D->isThreadSpecified());
Var->setInitStyle(D->getInitStyle());
Var->setCXXForRangeDecl(D->isCXXForRangeDecl());
@@ -322,6 +361,11 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
Var->setReferenced(D->isReferenced());
}
+ SemaRef.InstantiateAttrs(TemplateArgs, D, Var, LateAttrs, StartingScope);
+
+ if (Var->hasAttrs())
+ SemaRef.CheckAlignasUnderalignment(Var);
+
// FIXME: In theory, we could have a previous declaration for variables that
// are not static data members.
// FIXME: having to fake up a LookupResult is dumb.
@@ -345,7 +389,6 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
if (Owner->isFunctionOrMethod())
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Var);
}
- SemaRef.InstantiateAttrs(TemplateArgs, D, Var, LateAttrs, StartingScope);
// Link instantiations of static data members back to the template from
// which they were instantiated.
@@ -459,6 +502,9 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
SemaRef.InstantiateAttrs(TemplateArgs, D, Field, LateAttrs, StartingScope);
+ if (Field->hasAttrs())
+ SemaRef.CheckAlignasUnderalignment(Field);
+
if (Invalid)
Field->setInvalidDecl();
@@ -745,8 +791,8 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
if (!isFriend && Pattern->getPreviousDecl()) {
DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName());
- if (Found.first != Found.second) {
- PrevClassTemplate = dyn_cast<ClassTemplateDecl>(*Found.first);
+ if (!Found.empty()) {
+ PrevClassTemplate = dyn_cast<ClassTemplateDecl>(Found.front());
if (PrevClassTemplate)
PrevDecl = PrevClassTemplate->getTemplatedDecl();
}
@@ -911,11 +957,11 @@ TemplateDeclInstantiator::VisitClassTemplatePartialSpecializationDecl(
// of the class template and return that.
DeclContext::lookup_result Found
= Owner->lookup(ClassTemplate->getDeclName());
- if (Found.first == Found.second)
+ if (Found.empty())
return 0;
ClassTemplateDecl *InstClassTemplate
- = dyn_cast<ClassTemplateDecl>(*Found.first);
+ = dyn_cast<ClassTemplateDecl>(Found.front());
if (!InstClassTemplate)
return 0;
@@ -1043,8 +1089,8 @@ static QualType adjustFunctionTypeForInstantiation(ASTContext &Context,
FunctionProtoType::ExtProtoInfo NewEPI = NewFunc->getExtProtoInfo();
NewEPI.ExtInfo = OrigFunc->getExtInfo();
return Context.getFunctionType(NewFunc->getResultType(),
- NewFunc->arg_type_begin(),
- NewFunc->getNumArgs(),
+ ArrayRef<QualType>(NewFunc->arg_type_begin(),
+ NewFunc->getNumArgs()),
NewEPI);
}
@@ -1116,10 +1162,13 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
FunctionDecl *Function =
FunctionDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(),
D->getNameInfo(), T, TInfo,
- D->getStorageClass(), D->getStorageClassAsWritten(),
+ D->getStorageClass(),
D->isInlineSpecified(), D->hasWrittenPrototype(),
D->isConstexpr());
+ if (D->isInlined())
+ Function->setImplicitlyInline();
+
if (QualifierLoc)
Function->setQualifierInfo(QualifierLoc);
@@ -1287,7 +1336,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
//
// If -Wc++98-compat is enabled, we go through the motions of checking for a
// redefinition, but don't instantiate the function.
- if ((!SemaRef.getLangOpts().CPlusPlus0x ||
+ if ((!SemaRef.getLangOpts().CPlusPlus11 ||
SemaRef.Diags.getDiagnosticLevel(
diag::warn_cxx98_compat_friend_redefinition,
Function->getLocation())
@@ -1298,11 +1347,11 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
if (Function->isDefined(Definition) &&
Definition->getTemplateSpecializationKind() == TSK_Undeclared) {
SemaRef.Diag(Function->getLocation(),
- SemaRef.getLangOpts().CPlusPlus0x ?
+ SemaRef.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_friend_redefinition :
diag::err_redefinition) << Function->getDeclName();
SemaRef.Diag(Definition->getLocation(), diag::note_previous_definition);
- if (!SemaRef.getLangOpts().CPlusPlus0x)
+ if (!SemaRef.getLangOpts().CPlusPlus11)
Function->setInvalidDecl();
}
// Check for redefinitions due to other instantiations of this or
@@ -1314,7 +1363,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
continue;
switch (R->getFriendObjectKind()) {
case Decl::FOK_None:
- if (!SemaRef.getLangOpts().CPlusPlus0x &&
+ if (!SemaRef.getLangOpts().CPlusPlus11 &&
!queuedInstantiation && R->isUsed(false)) {
if (MemberSpecializationInfo *MSInfo
= Function->getMemberSpecializationInfo()) {
@@ -1333,12 +1382,12 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
= R->getTemplateInstantiationPattern())
if (RPattern->isDefined(RPattern)) {
SemaRef.Diag(Function->getLocation(),
- SemaRef.getLangOpts().CPlusPlus0x ?
+ SemaRef.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_friend_redefinition :
diag::err_redefinition)
<< Function->getDeclName();
SemaRef.Diag(R->getLocation(), diag::note_previous_definition);
- if (!SemaRef.getLangOpts().CPlusPlus0x)
+ if (!SemaRef.getLangOpts().CPlusPlus11)
Function->setInvalidDecl();
break;
}
@@ -1479,12 +1528,14 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
} else {
Method = CXXMethodDecl::Create(SemaRef.Context, Record,
StartLoc, NameInfo, T, TInfo,
- D->isStatic(),
- D->getStorageClassAsWritten(),
+ D->getStorageClass(),
D->isInlineSpecified(),
D->isConstexpr(), D->getLocEnd());
}
+ if (D->isInlined())
+ Method->setImplicitlyInline();
+
if (QualifierLoc)
Method->setQualifierInfo(QualifierLoc);
@@ -1581,10 +1632,10 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
SemaRef.CheckOverrideControl(Method);
// If a function is defined as defaulted or deleted, mark it as such now.
- if (D->isDefaulted())
- Method->setDefaulted();
+ if (D->isExplicitlyDefaulted())
+ SemaRef.SetDeclDefaulted(Method, Method->getLocation());
if (D->isDeletedAsWritten())
- Method->setDeletedAsWritten();
+ SemaRef.SetDeclDeleted(Method, Method->getLocation());
// If there's a function template, let our caller handle it.
if (FunctionTemplate) {
@@ -1610,13 +1661,6 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
Owner->addDecl(Method);
}
- if (D->isExplicitlyDefaulted()) {
- SemaRef.SetDeclDefaulted(Method, Method->getLocation());
- } else {
- assert(!D->isDefaulted() &&
- "should not implicitly default uninstantiated function");
- }
-
return Method;
}
@@ -1633,9 +1677,8 @@ Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) {
}
ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) {
- return SemaRef.SubstParmVarDecl(D, TemplateArgs, /*indexAdjustment*/ 0,
- llvm::Optional<unsigned>(),
- /*ExpectParameterPack=*/false);
+ return SemaRef.SubstParmVarDecl(D, TemplateArgs, /*indexAdjustment*/ 0, None,
+ /*ExpectParameterPack=*/ false);
}
Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
@@ -1701,7 +1744,7 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
// 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.
- PackExpansionTypeLoc Expansion = cast<PackExpansionTypeLoc>(TL);
+ PackExpansionTypeLoc Expansion = TL.castAs<PackExpansionTypeLoc>();
TypeLoc Pattern = Expansion.getPatternLoc();
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
SemaRef.collectUnexpandedParameterPacks(Pattern, Unexpanded);
@@ -1710,9 +1753,9 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
- llvm::Optional<unsigned> OrigNumExpansions
+ Optional<unsigned> OrigNumExpansions
= Expansion.getTypePtr()->getNumExpansions();
- llvm::Optional<unsigned> NumExpansions = OrigNumExpansions;
+ Optional<unsigned> NumExpansions = OrigNumExpansions;
if (SemaRef.CheckParameterPacksForExpansion(Expansion.getEllipsisLoc(),
Pattern.getSourceRange(),
Unexpanded,
@@ -1867,7 +1910,7 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
- llvm::Optional<unsigned> NumExpansions;
+ Optional<unsigned> NumExpansions;
if (SemaRef.CheckParameterPacksForExpansion(D->getLocation(),
TempParams->getSourceRange(),
Unexpanded,
@@ -2069,7 +2112,7 @@ Decl * TemplateDeclInstantiator
SS.Adopt(QualifierLoc);
// Since NameInfo refers to a typename, it cannot be a C++ special name.
- // Hence, no tranformation is required for it.
+ // Hence, no transformation is required for it.
DeclarationNameInfo NameInfo(D->getDeclName(), D->getLocation());
NamedDecl *UD =
SemaRef.BuildUsingDeclaration(/*Scope*/ 0, D->getAccess(),
@@ -2138,6 +2181,23 @@ Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl(
return NewFD;
}
+Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl(
+ OMPThreadPrivateDecl *D) {
+ SmallVector<DeclRefExpr *, 5> Vars;
+ for (ArrayRef<DeclRefExpr *>::iterator I = D->varlist_begin(),
+ E = D->varlist_end();
+ I != E; ++I) {
+ Expr *Var = SemaRef.SubstExpr(*I, TemplateArgs).take();
+ assert(isa<DeclRefExpr>(Var) && "threadprivate arg is not a DeclRefExpr");
+ Vars.push_back(cast<DeclRefExpr>(Var));
+ }
+
+ OMPThreadPrivateDecl *TD =
+ SemaRef.CheckOMPThreadPrivateDecl(D->getLocation(), Vars);
+
+ return TD;
+}
+
Decl *Sema::SubstDecl(Decl *D, DeclContext *Owner,
const MultiLevelTemplateArgumentList &TemplateArgs) {
TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs);
@@ -2330,18 +2390,17 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
if (NewTInfo != OldTInfo) {
// Get parameters from the new type info.
TypeLoc OldTL = OldTInfo->getTypeLoc().IgnoreParens();
- if (FunctionProtoTypeLoc *OldProtoLoc
- = dyn_cast<FunctionProtoTypeLoc>(&OldTL)) {
+ if (FunctionProtoTypeLoc OldProtoLoc =
+ OldTL.getAs<FunctionProtoTypeLoc>()) {
TypeLoc NewTL = NewTInfo->getTypeLoc().IgnoreParens();
- FunctionProtoTypeLoc *NewProtoLoc = cast<FunctionProtoTypeLoc>(&NewTL);
- assert(NewProtoLoc && "Missing prototype?");
+ FunctionProtoTypeLoc NewProtoLoc = NewTL.castAs<FunctionProtoTypeLoc>();
unsigned NewIdx = 0;
- for (unsigned OldIdx = 0, NumOldParams = OldProtoLoc->getNumArgs();
+ for (unsigned OldIdx = 0, NumOldParams = OldProtoLoc.getNumArgs();
OldIdx != NumOldParams; ++OldIdx) {
- ParmVarDecl *OldParam = OldProtoLoc->getArg(OldIdx);
+ ParmVarDecl *OldParam = OldProtoLoc.getArg(OldIdx);
LocalInstantiationScope *Scope = SemaRef.CurrentInstantiationScope;
- llvm::Optional<unsigned> NumArgumentsInExpansion;
+ Optional<unsigned> NumArgumentsInExpansion;
if (OldParam->isParameterPack())
NumArgumentsInExpansion =
SemaRef.getNumArgumentsInExpansion(OldParam->getType(),
@@ -2349,14 +2408,14 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
if (!NumArgumentsInExpansion) {
// Simple case: normal parameter, or a parameter pack that's
// instantiated to a (still-dependent) parameter pack.
- ParmVarDecl *NewParam = NewProtoLoc->getArg(NewIdx++);
+ ParmVarDecl *NewParam = NewProtoLoc.getArg(NewIdx++);
Params.push_back(NewParam);
Scope->InstantiatedLocal(OldParam, NewParam);
} else {
// Parameter pack expansion: make the instantiation an argument pack.
Scope->MakeInstantiatedLocalArgPack(OldParam);
for (unsigned I = 0; I != *NumArgumentsInExpansion; ++I) {
- ParmVarDecl *NewParam = NewProtoLoc->getArg(NewIdx++);
+ ParmVarDecl *NewParam = NewProtoLoc.getArg(NewIdx++);
Params.push_back(NewParam);
Scope->InstantiatedLocalPackArg(OldParam, NewParam);
}
@@ -2368,10 +2427,10 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
// substitution occurred. However, we still need to instantiate
// the function parameters themselves.
TypeLoc OldTL = OldTInfo->getTypeLoc().IgnoreParens();
- if (FunctionProtoTypeLoc *OldProtoLoc
- = dyn_cast<FunctionProtoTypeLoc>(&OldTL)) {
- for (unsigned i = 0, i_end = OldProtoLoc->getNumArgs(); i != i_end; ++i) {
- ParmVarDecl *Parm = VisitParmVarDecl(OldProtoLoc->getArg(i));
+ if (FunctionProtoTypeLoc OldProtoLoc =
+ OldTL.getAs<FunctionProtoTypeLoc>()) {
+ for (unsigned i = 0, i_end = OldProtoLoc.getNumArgs(); i != i_end; ++i) {
+ ParmVarDecl *Parm = VisitParmVarDecl(OldProtoLoc.getArg(i));
if (!Parm)
return 0;
Params.push_back(Parm);
@@ -2403,7 +2462,7 @@ static void addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function,
// Expand the parameter pack.
Scope.MakeInstantiatedLocalArgPack(PatternParam);
- llvm::Optional<unsigned> NumArgumentsInExpansion
+ Optional<unsigned> NumArgumentsInExpansion
= S.getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs);
assert(NumArgumentsInExpansion &&
"should only be called when all template arguments are known");
@@ -2434,7 +2493,7 @@ static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New,
ThisTypeQuals = Method->getTypeQualifiers();
}
Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, ThisTypeQuals,
- SemaRef.getLangOpts().CPlusPlus0x);
+ SemaRef.getLangOpts().CPlusPlus11);
// The function has an exception specification or a "noreturn"
// attribute. Substitute into each of the exception types.
@@ -2452,7 +2511,7 @@ static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New,
bool Expand = false;
bool RetainExpansion = false;
- llvm::Optional<unsigned> NumExpansions
+ Optional<unsigned> NumExpansions
= PackExpansion->getNumExpansions();
if (SemaRef.CheckParameterPacksForExpansion(New->getLocation(),
SourceRange(),
@@ -2541,8 +2600,8 @@ static void InstantiateExceptionSpec(Sema &SemaRef, FunctionDecl *New,
EPI.NoexceptExpr = NoexceptExpr;
New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(),
- NewProto->arg_type_begin(),
- NewProto->getNumArgs(),
+ ArrayRef<QualType>(NewProto->arg_type_begin(),
+ NewProto->getNumArgs()),
EPI));
}
@@ -2560,8 +2619,8 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo();
EPI.ExceptionSpecType = EST_None;
Decl->setType(Context.getFunctionType(Proto->getResultType(),
- Proto->arg_type_begin(),
- Proto->getNumArgs(),
+ ArrayRef<QualType>(Proto->arg_type_begin(),
+ Proto->getNumArgs()),
EPI));
return;
}
@@ -2605,12 +2664,12 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
if (ActiveInst.Kind == ActiveInstType::ExplicitTemplateArgumentSubstitution ||
ActiveInst.Kind == ActiveInstType::DeducedTemplateArgumentSubstitution) {
if (FunctionTemplateDecl *FunTmpl
- = dyn_cast<FunctionTemplateDecl>((Decl *)ActiveInst.Entity)) {
+ = dyn_cast<FunctionTemplateDecl>(ActiveInst.Entity)) {
assert(FunTmpl->getTemplatedDecl() == Tmpl &&
"Deduction from the wrong function template?");
(void) FunTmpl;
ActiveInst.Kind = ActiveInstType::TemplateInstantiation;
- ActiveInst.Entity = reinterpret_cast<uintptr_t>(New);
+ ActiveInst.Entity = New;
}
}
@@ -2622,7 +2681,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
// DR1330: In C++11, defer instantiation of a non-trivial
// exception specification.
- if (SemaRef.getLangOpts().CPlusPlus0x &&
+ if (SemaRef.getLangOpts().CPlusPlus11 &&
EPI.ExceptionSpecType != EST_None &&
EPI.ExceptionSpecType != EST_DynamicNone &&
EPI.ExceptionSpecType != EST_BasicNoexcept) {
@@ -2641,8 +2700,8 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
EPI.ExceptionSpecDecl = New;
EPI.ExceptionSpecTemplate = ExceptionSpecTemplate;
New->setType(SemaRef.Context.getFunctionType(NewProto->getResultType(),
- NewProto->arg_type_begin(),
- NewProto->getNumArgs(),
+ ArrayRef<QualType>(NewProto->arg_type_begin(),
+ NewProto->getNumArgs()),
EPI));
} else {
::InstantiateExceptionSpec(SemaRef, New, Proto, TemplateArgs);
@@ -2770,6 +2829,9 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
!PatternDecl->isInlined())
return;
+ if (PatternDecl->isInlined())
+ Function->setImplicitlyInline();
+
InstantiatingTemplate Inst(*this, PointOfInstantiation, Function);
if (Inst)
return;
@@ -2789,7 +2851,6 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
EnterExpressionEvaluationContext EvalContext(*this,
Sema::PotentiallyEvaluated);
- ActOnStartOfFunctionDef(0, Function);
// Introduce a new scope where local variable instantiations will be
// recorded, unless we're actually a member function within a local
@@ -2801,21 +2862,21 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
LocalInstantiationScope Scope(*this, MergeWithParentScope);
- // Enter the scope of this instantiation. We don't use
- // PushDeclContext because we don't have a scope.
- Sema::ContextRAII savedContext(*this, Function);
+ if (PatternDecl->isDefaulted())
+ SetDeclDefaulted(Function, PatternDecl->getLocation());
+ else {
+ ActOnStartOfFunctionDef(0, Function);
- MultiLevelTemplateArgumentList TemplateArgs =
- getTemplateInstantiationArgs(Function, 0, false, PatternDecl);
+ // Enter the scope of this instantiation. We don't use
+ // PushDeclContext because we don't have a scope.
+ Sema::ContextRAII savedContext(*this, Function);
- addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope,
- TemplateArgs);
+ MultiLevelTemplateArgumentList TemplateArgs =
+ getTemplateInstantiationArgs(Function, 0, false, PatternDecl);
- if (PatternDecl->isDefaulted()) {
- ActOnFinishFunctionBody(Function, 0, /*IsInstantiation=*/true);
+ addInstantiatedParametersToScope(*this, Function, PatternDecl, Scope,
+ TemplateArgs);
- SetDeclDefaulted(Function, PatternDecl->getLocation());
- } else {
// If this is a constructor, instantiate the member initializers.
if (const CXXConstructorDecl *Ctor =
dyn_cast<CXXConstructorDecl>(PatternDecl)) {
@@ -2831,11 +2892,11 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
ActOnFinishFunctionBody(Function, Body.get(),
/*IsInstantiation=*/true);
- }
- PerformDependentDiagnostics(PatternDecl, TemplateArgs);
+ PerformDependentDiagnostics(PatternDecl, TemplateArgs);
- savedContext.pop();
+ savedContext.pop();
+ }
DeclGroupRef DG(Function);
Consumer.HandleTopLevelDecl(DG);
@@ -2928,7 +2989,18 @@ void Sema::InstantiateStaticDataMemberDefinition(
if (TSK == TSK_ExplicitInstantiationDeclaration)
return;
- Consumer.HandleCXXStaticMemberVarInstantiation(Var);
+ // Make sure to pass the instantiated variable to the consumer at the end.
+ struct PassToConsumerRAII {
+ ASTConsumer &Consumer;
+ VarDecl *Var;
+
+ PassToConsumerRAII(ASTConsumer &Consumer, VarDecl *Var)
+ : Consumer(Consumer), Var(Var) { }
+
+ ~PassToConsumerRAII() {
+ Consumer.HandleCXXStaticMemberVarInstantiation(Var);
+ }
+ } PassToConsumerRAII(Consumer, Var);
// If we already have a definition, we're done.
if (VarDecl *Def = Var->getDefinition()) {
@@ -2965,12 +3037,11 @@ void Sema::InstantiateStaticDataMemberDefinition(
previousContext.pop();
if (Var) {
+ PassToConsumerRAII.Var = Var;
MemberSpecializationInfo *MSInfo = OldVar->getMemberSpecializationInfo();
assert(MSInfo && "Missing member specialization information?");
Var->setTemplateSpecializationKind(MSInfo->getTemplateSpecializationKind(),
MSInfo->getPointOfInstantiation());
- DeclGroupRef DG(Var);
- Consumer.HandleTopLevelDecl(DG);
}
Local.Exit();
@@ -3024,7 +3095,7 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
collectUnexpandedParameterPacks(BaseTL, Unexpanded);
bool ShouldExpand = false;
bool RetainExpansion = false;
- llvm::Optional<unsigned> NumExpansions;
+ Optional<unsigned> NumExpansions;
if (CheckParameterPacksForExpansion(Init->getEllipsisLoc(),
BaseTL.getSourceRange(),
Unexpanded,
@@ -3142,49 +3213,10 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
ActOnMemInitializers(New,
/*FIXME: ColonLoc */
SourceLocation(),
- NewInits.data(), NewInits.size(),
+ NewInits,
AnyErrors);
}
-ExprResult Sema::SubstInitializer(Expr *Init,
- const MultiLevelTemplateArgumentList &TemplateArgs,
- bool CXXDirectInit) {
- // Initializers are instantiated like expressions, except that various outer
- // layers are stripped.
- if (!Init)
- return Owned(Init);
-
- if (ExprWithCleanups *ExprTemp = dyn_cast<ExprWithCleanups>(Init))
- Init = ExprTemp->getSubExpr();
-
- while (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(Init))
- Init = Binder->getSubExpr();
-
- if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Init))
- Init = ICE->getSubExprAsWritten();
-
- // If this is a direct-initializer, we take apart CXXConstructExprs.
- // Everything else is passed through.
- CXXConstructExpr *Construct;
- if (!CXXDirectInit || !(Construct = dyn_cast<CXXConstructExpr>(Init)) ||
- isa<CXXTemporaryObjectExpr>(Construct))
- return SubstExpr(Init, TemplateArgs);
-
- SmallVector<Expr*, 8> NewArgs;
- if (SubstExprs(Construct->getArgs(), Construct->getNumArgs(), true,
- TemplateArgs, NewArgs))
- return ExprError();
-
- // Treat an empty initializer like none.
- if (NewArgs.empty())
- return Owned((Expr*)0);
-
- // Build a ParenListExpr to represent anything else.
- // FIXME: Fake locations!
- SourceLocation Loc = PP.getLocForEndOfToken(Init->getLocStart());
- return ActOnParenListExpr(Loc, Loc, NewArgs);
-}
-
// TODO: this could be templated if the various decl types used the
// same method name.
static bool isInstantiationOf(ClassTemplateDecl *Pattern,
@@ -3539,7 +3571,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D,
NamedDecl *Result = 0;
if (D->getDeclName()) {
DeclContext::lookup_result Found = ParentDC->lookup(D->getDeclName());
- Result = findInstantiationOf(Context, D, Found.first, Found.second);
+ Result = findInstantiationOf(Context, D, Found.begin(), Found.end());
} else {
// Since we don't have a name for the entity we're looking for,
// our only option is to walk through all of the declarations to
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index 6147d63..c0ad2be 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -10,14 +10,14 @@
//===----------------------------------------------------------------------===/
#include "clang/Sema/Sema.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/RecursiveASTVisitor.h"
-#include "clang/AST/TypeLoc.h"
using namespace clang;
@@ -443,17 +443,16 @@ TypeResult Sema::ActOnPackExpansion(ParsedType Type,
if (!TSInfo)
return true;
- TypeSourceInfo *TSResult = CheckPackExpansion(TSInfo, EllipsisLoc,
- llvm::Optional<unsigned>());
+ TypeSourceInfo *TSResult = CheckPackExpansion(TSInfo, EllipsisLoc, None);
if (!TSResult)
return true;
return CreateParsedType(TSResult->getType(), TSResult);
}
-TypeSourceInfo *Sema::CheckPackExpansion(TypeSourceInfo *Pattern,
- SourceLocation EllipsisLoc,
- llvm::Optional<unsigned> NumExpansions) {
+TypeSourceInfo *
+Sema::CheckPackExpansion(TypeSourceInfo *Pattern, SourceLocation EllipsisLoc,
+ Optional<unsigned> NumExpansions) {
// Create the pack expansion type and source-location information.
QualType Result = CheckPackExpansion(Pattern->getType(),
Pattern->getTypeLoc().getSourceRange(),
@@ -462,7 +461,8 @@ TypeSourceInfo *Sema::CheckPackExpansion(TypeSourceInfo *Pattern,
return 0;
TypeSourceInfo *TSResult = Context.CreateTypeSourceInfo(Result);
- PackExpansionTypeLoc TL = cast<PackExpansionTypeLoc>(TSResult->getTypeLoc());
+ PackExpansionTypeLoc TL =
+ TSResult->getTypeLoc().castAs<PackExpansionTypeLoc>();
TL.setEllipsisLoc(EllipsisLoc);
// Copy over the source-location information from the type.
@@ -472,10 +472,9 @@ TypeSourceInfo *Sema::CheckPackExpansion(TypeSourceInfo *Pattern,
return TSResult;
}
-QualType Sema::CheckPackExpansion(QualType Pattern,
- SourceRange PatternRange,
+QualType Sema::CheckPackExpansion(QualType Pattern, SourceRange PatternRange,
SourceLocation EllipsisLoc,
- llvm::Optional<unsigned> NumExpansions) {
+ Optional<unsigned> NumExpansions) {
// C++0x [temp.variadic]p5:
// The pattern of a pack expansion shall name one or more
// parameter packs that are not expanded by a nested pack
@@ -490,11 +489,11 @@ QualType Sema::CheckPackExpansion(QualType Pattern,
}
ExprResult Sema::ActOnPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc) {
- return CheckPackExpansion(Pattern, EllipsisLoc, llvm::Optional<unsigned>());
+ return CheckPackExpansion(Pattern, EllipsisLoc, None);
}
ExprResult Sema::CheckPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc,
- llvm::Optional<unsigned> NumExpansions) {
+ Optional<unsigned> NumExpansions) {
if (!Pattern)
return ExprError();
@@ -526,13 +525,11 @@ getDepthAndIndex(NamedDecl *ND) {
return std::make_pair(TTP->getDepth(), TTP->getIndex());
}
-bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc,
- SourceRange PatternRange,
- ArrayRef<UnexpandedParameterPack> Unexpanded,
- const MultiLevelTemplateArgumentList &TemplateArgs,
- bool &ShouldExpand,
- bool &RetainExpansion,
- llvm::Optional<unsigned> &NumExpansions) {
+bool Sema::CheckParameterPacksForExpansion(
+ SourceLocation EllipsisLoc, SourceRange PatternRange,
+ ArrayRef<UnexpandedParameterPack> Unexpanded,
+ const MultiLevelTemplateArgumentList &TemplateArgs, bool &ShouldExpand,
+ bool &RetainExpansion, Optional<unsigned> &NumExpansions) {
ShouldExpand = true;
RetainExpansion = false;
std::pair<IdentifierInfo *, SourceLocation> FirstPack;
@@ -636,13 +633,13 @@ bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc,
return false;
}
-llvm::Optional<unsigned> Sema::getNumArgumentsInExpansion(QualType T,
+Optional<unsigned> Sema::getNumArgumentsInExpansion(QualType T,
const MultiLevelTemplateArgumentList &TemplateArgs) {
QualType Pattern = cast<PackExpansionType>(T)->getPattern();
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseType(Pattern);
- llvm::Optional<unsigned> Result;
+ Optional<unsigned> Result;
for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
// Compute the depth and index for this parameter pack.
unsigned Depth;
@@ -664,7 +661,7 @@ llvm::Optional<unsigned> Sema::getNumArgumentsInExpansion(QualType T,
if (Instantiation->is<Decl*>())
// The pattern refers to an unexpanded pack. We're not ready to expand
// this pack yet.
- return llvm::Optional<unsigned>();
+ return None;
unsigned Size = Instantiation->get<DeclArgumentPack *>()->size();
assert((!Result || *Result == Size) && "inconsistent pack sizes");
@@ -678,7 +675,7 @@ llvm::Optional<unsigned> Sema::getNumArgumentsInExpansion(QualType T,
!TemplateArgs.hasTemplateArgument(Depth, Index))
// The pattern refers to an unknown template argument. We're not ready to
// expand this pack yet.
- return llvm::Optional<unsigned>();
+ return None;
// Determine the size of the argument pack.
unsigned Size = TemplateArgs(Depth, Index).pack_size();
@@ -731,6 +728,14 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
case TST_class:
case TST_auto:
case TST_unknown_anytype:
+ case TST_image1d_t:
+ case TST_image1d_array_t:
+ case TST_image1d_buffer_t:
+ case TST_image2d_t:
+ case TST_image2d_array_t:
+ case TST_image3d_t:
+ case TST_sampler_t:
+ case TST_event_t:
case TST_error:
break;
}
@@ -837,7 +842,7 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
return ExprError();
}
- MarkAnyDeclReferenced(OpLoc, ParameterPack);
+ MarkAnyDeclReferenced(OpLoc, ParameterPack, true);
return new (Context) SizeOfPackExpr(Context.getSizeType(), OpLoc,
ParameterPack, NameLoc, RParenLoc);
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 4b23167..7169eea 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -11,18 +11,16 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Template.h"
-#include "clang/Basic/OpenCL.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeLocVisitor.h"
-#include "clang/AST/Expr.h"
+#include "clang/Basic/OpenCL.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
@@ -30,7 +28,10 @@
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/DelayedDiagnostic.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/Template.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
@@ -106,7 +107,8 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr,
case AttributeList::AT_Pascal: \
case AttributeList::AT_Regparm: \
case AttributeList::AT_Pcs: \
- case AttributeList::AT_PnaclCall \
+ case AttributeList::AT_PnaclCall: \
+ case AttributeList::AT_IntelOclBicc \
namespace {
/// An object which stores processing state for the entire
@@ -149,6 +151,10 @@ namespace {
return declarator;
}
+ bool isProcessingDeclSpec() const {
+ return chunkIndex == declarator.getNumTypeObjects();
+ }
+
unsigned getCurrentChunkIndex() const {
return chunkIndex;
}
@@ -159,8 +165,7 @@ namespace {
}
AttributeList *&getCurrentAttrListRef() const {
- assert(chunkIndex <= declarator.getNumTypeObjects());
- if (chunkIndex == declarator.getNumTypeObjects())
+ if (isProcessingDeclSpec())
return getMutableDeclSpec().getAttributes().getListRef();
return declarator.getTypeObject(chunkIndex).getAttrListRef();
}
@@ -269,8 +274,18 @@ static void moveAttrFromListToList(AttributeList &attr,
spliceAttrIntoList(attr, toList);
}
+/// The location of a type attribute.
+enum TypeAttrLocation {
+ /// The attribute is in the decl-specifier-seq.
+ TAL_DeclSpec,
+ /// The attribute is part of a DeclaratorChunk.
+ TAL_DeclChunk,
+ /// The attribute is immediately after the declaration's name.
+ TAL_DeclName
+};
+
static void processTypeAttrs(TypeProcessingState &state,
- QualType &type, bool isDeclSpec,
+ QualType &type, TypeAttrLocation TAL,
AttributeList *attrs);
static bool handleFunctionTypeAttr(TypeProcessingState &state,
@@ -291,6 +306,66 @@ static bool handleObjCPointerTypeAttr(TypeProcessingState &state,
return handleObjCOwnershipTypeAttr(state, attr, type);
}
+/// Given the index of a declarator chunk, check whether that chunk
+/// directly specifies the return type of a function and, if so, find
+/// an appropriate place for it.
+///
+/// \param i - a notional index which the search will start
+/// immediately inside
+static DeclaratorChunk *maybeMovePastReturnType(Declarator &declarator,
+ unsigned i) {
+ assert(i <= declarator.getNumTypeObjects());
+
+ DeclaratorChunk *result = 0;
+
+ // First, look inwards past parens for a function declarator.
+ for (; i != 0; --i) {
+ DeclaratorChunk &fnChunk = declarator.getTypeObject(i-1);
+ switch (fnChunk.Kind) {
+ case DeclaratorChunk::Paren:
+ continue;
+
+ // If we find anything except a function, bail out.
+ case DeclaratorChunk::Pointer:
+ case DeclaratorChunk::BlockPointer:
+ case DeclaratorChunk::Array:
+ case DeclaratorChunk::Reference:
+ case DeclaratorChunk::MemberPointer:
+ return result;
+
+ // If we do find a function declarator, scan inwards from that,
+ // looking for a block-pointer declarator.
+ case DeclaratorChunk::Function:
+ for (--i; i != 0; --i) {
+ DeclaratorChunk &blockChunk = declarator.getTypeObject(i-1);
+ switch (blockChunk.Kind) {
+ case DeclaratorChunk::Paren:
+ case DeclaratorChunk::Pointer:
+ case DeclaratorChunk::Array:
+ case DeclaratorChunk::Function:
+ case DeclaratorChunk::Reference:
+ case DeclaratorChunk::MemberPointer:
+ continue;
+ case DeclaratorChunk::BlockPointer:
+ result = &blockChunk;
+ goto continue_outer;
+ }
+ llvm_unreachable("bad declarator chunk kind");
+ }
+
+ // If we run out of declarators doing that, we're done.
+ return result;
+ }
+ llvm_unreachable("bad declarator chunk kind");
+
+ // Okay, reconsider from our new point.
+ continue_outer: ;
+ }
+
+ // Ran out of chunks, bail out.
+ return result;
+}
+
/// Given that an objc_gc attribute was written somewhere on a
/// declaration *other* than on the declarator itself (for which, use
/// distributeObjCPointerTypeAttrFromDeclarator), and given that it
@@ -300,22 +375,44 @@ static void distributeObjCPointerTypeAttr(TypeProcessingState &state,
AttributeList &attr,
QualType type) {
Declarator &declarator = state.getDeclarator();
+
+ // Move it to the outermost normal or block pointer declarator.
for (unsigned i = state.getCurrentChunkIndex(); i != 0; --i) {
DeclaratorChunk &chunk = declarator.getTypeObject(i-1);
switch (chunk.Kind) {
case DeclaratorChunk::Pointer:
- case DeclaratorChunk::BlockPointer:
+ case DeclaratorChunk::BlockPointer: {
+ // But don't move an ARC ownership attribute to the return type
+ // of a block.
+ DeclaratorChunk *destChunk = 0;
+ if (state.isProcessingDeclSpec() &&
+ attr.getKind() == AttributeList::AT_ObjCOwnership)
+ destChunk = maybeMovePastReturnType(declarator, i - 1);
+ if (!destChunk) destChunk = &chunk;
+
moveAttrFromListToList(attr, state.getCurrentAttrListRef(),
- chunk.getAttrListRef());
+ destChunk->getAttrListRef());
return;
+ }
case DeclaratorChunk::Paren:
case DeclaratorChunk::Array:
continue;
+ // We may be starting at the return type of a block.
+ case DeclaratorChunk::Function:
+ if (state.isProcessingDeclSpec() &&
+ attr.getKind() == AttributeList::AT_ObjCOwnership) {
+ if (DeclaratorChunk *dest = maybeMovePastReturnType(declarator, i)) {
+ moveAttrFromListToList(attr, state.getCurrentAttrListRef(),
+ dest->getAttrListRef());
+ return;
+ }
+ }
+ goto error;
+
// Don't walk through these.
case DeclaratorChunk::Reference:
- case DeclaratorChunk::Function:
case DeclaratorChunk::MemberPointer:
goto error;
}
@@ -452,6 +549,15 @@ distributeFunctionTypeAttrFromDeclSpec(TypeProcessingState &state,
QualType &declSpecType) {
state.saveDeclSpecAttrs();
+ // C++11 attributes before the decl specifiers actually appertain to
+ // the declarators. Move them straight there. We don't support the
+ // 'put them wherever you like' semantics we allow for GNU attributes.
+ if (attr.isCXX11Attribute()) {
+ moveAttrFromListToList(attr, state.getCurrentAttrListRef(),
+ state.getDeclarator().getAttrListRef());
+ return;
+ }
+
// Try to distribute to the innermost.
if (distributeFunctionTypeAttrToInnermost(state, attr,
state.getCurrentAttrListRef(),
@@ -501,6 +607,11 @@ static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state,
do {
next = attr->getNext();
+ // Do not distribute C++11 attributes. They have strict rules for what
+ // they appertain to.
+ if (attr->isCXX11Attribute())
+ continue;
+
switch (attr->getKind()) {
OBJC_POINTER_TYPE_ATTRS_CASELIST:
distributeObjCPointerTypeAttrFromDeclarator(state, *attr, declSpecType);
@@ -712,7 +823,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
if (!S.getLangOpts().C99) {
if (S.getLangOpts().CPlusPlus)
S.Diag(DS.getTypeSpecWidthLoc(),
- S.getLangOpts().CPlusPlus0x ?
+ S.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong);
else
S.Diag(DS.getTypeSpecWidthLoc(), diag::ext_c99_longlong);
@@ -731,7 +842,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
if (!S.getLangOpts().C99) {
if (S.getLangOpts().CPlusPlus)
S.Diag(DS.getTypeSpecWidthLoc(),
- S.getLangOpts().CPlusPlus0x ?
+ S.getLangOpts().CPlusPlus11 ?
diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong);
else
S.Diag(DS.getTypeSpecWidthLoc(), diag::ext_c99_longlong);
@@ -742,6 +853,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
break;
}
case DeclSpec::TST_int128:
+ if (!S.PP.getTargetInfo().hasInt128Type())
+ S.Diag(DS.getTypeSpecTypeLoc(), diag::err_int128_unsupported);
if (DS.getTypeSpecSign() == DeclSpec::TSS_unsigned)
Result = Context.UnsignedInt128Ty;
else
@@ -901,6 +1014,38 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
}
break;
+ case DeclSpec::TST_image1d_t:
+ Result = Context.OCLImage1dTy;
+ break;
+
+ case DeclSpec::TST_image1d_array_t:
+ Result = Context.OCLImage1dArrayTy;
+ break;
+
+ case DeclSpec::TST_image1d_buffer_t:
+ Result = Context.OCLImage1dBufferTy;
+ break;
+
+ case DeclSpec::TST_image2d_t:
+ Result = Context.OCLImage2dTy;
+ break;
+
+ case DeclSpec::TST_image2d_array_t:
+ Result = Context.OCLImage2dArrayTy;
+ break;
+
+ case DeclSpec::TST_image3d_t:
+ Result = Context.OCLImage3dTy;
+ break;
+
+ case DeclSpec::TST_sampler_t:
+ Result = Context.OCLSamplerTy;
+ break;
+
+ case DeclSpec::TST_event_t:
+ Result = Context.OCLEventTy;
+ break;
+
case DeclSpec::TST_error:
Result = Context.IntTy;
declarator.setInvalidType(true);
@@ -936,57 +1081,27 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
// list of type attributes to be temporarily saved while the type
// attributes are pushed around.
if (AttributeList *attrs = DS.getAttributes().getList())
- processTypeAttrs(state, Result, true, attrs);
+ processTypeAttrs(state, Result, TAL_DeclSpec, attrs);
// Apply const/volatile/restrict qualifiers to T.
if (unsigned TypeQuals = DS.getTypeQualifiers()) {
- // Enforce C99 6.7.3p2: "Types other than pointer types derived from object
- // or incomplete types shall not be restrict-qualified." C++ also allows
- // restrict-qualified references.
- if (TypeQuals & DeclSpec::TQ_restrict) {
- if (Result->isAnyPointerType() || Result->isReferenceType()) {
- QualType EltTy;
- if (Result->isObjCObjectPointerType())
- EltTy = Result;
- else
- EltTy = Result->isPointerType() ?
- Result->getAs<PointerType>()->getPointeeType() :
- Result->getAs<ReferenceType>()->getPointeeType();
-
- // If we have a pointer or reference, the pointee must have an object
- // incomplete type.
- if (!EltTy->isIncompleteOrObjectType()) {
- S.Diag(DS.getRestrictSpecLoc(),
- diag::err_typecheck_invalid_restrict_invalid_pointee)
- << EltTy << DS.getSourceRange();
- TypeQuals &= ~DeclSpec::TQ_restrict; // Remove the restrict qualifier.
- }
- } else {
- S.Diag(DS.getRestrictSpecLoc(),
- diag::err_typecheck_invalid_restrict_not_pointer)
- << Result << DS.getSourceRange();
- TypeQuals &= ~DeclSpec::TQ_restrict; // Remove the restrict qualifier.
- }
- }
-
// Warn about CV qualifiers on functions: C99 6.7.3p8: "If the specification
// of a function type includes any type qualifiers, the behavior is
// undefined."
if (Result->isFunctionType() && TypeQuals) {
- // Get some location to point at, either the C or V location.
- SourceLocation Loc;
if (TypeQuals & DeclSpec::TQ_const)
- Loc = DS.getConstSpecLoc();
+ S.Diag(DS.getConstSpecLoc(), diag::warn_typecheck_function_qualifiers)
+ << Result << DS.getSourceRange();
else if (TypeQuals & DeclSpec::TQ_volatile)
- Loc = DS.getVolatileSpecLoc();
+ S.Diag(DS.getVolatileSpecLoc(), diag::warn_typecheck_function_qualifiers)
+ << Result << DS.getSourceRange();
else {
- assert((TypeQuals & DeclSpec::TQ_restrict) &&
- "Has CVR quals but not C, V, or R?");
- Loc = DS.getRestrictSpecLoc();
+ assert((TypeQuals & (DeclSpec::TQ_restrict | DeclSpec::TQ_atomic)) &&
+ "Has CVRA quals but not C, V, R, or A?");
+ // No diagnostic; we'll diagnose 'restrict' or '_Atomic' applied to a
+ // function type later, in BuildQualifiedType.
}
- S.Diag(Loc, diag::warn_typecheck_function_qualifiers)
- << Result << DS.getSourceRange();
}
// C++ [dcl.ref]p1:
@@ -999,6 +1114,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
TypeQuals && Result->isReferenceType()) {
TypeQuals &= ~DeclSpec::TQ_const;
TypeQuals &= ~DeclSpec::TQ_volatile;
+ TypeQuals &= ~DeclSpec::TQ_atomic;
}
// C90 6.5.3 constraints: "The same type qualifier shall not appear more
@@ -1016,12 +1132,17 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
<< "volatile";
}
- // C90 doesn't have restrict, so it doesn't force us to produce a warning
- // in this case.
+ // C90 doesn't have restrict nor _Atomic, so it doesn't force us to
+ // produce a warning in this case.
}
- Qualifiers Quals = Qualifiers::fromCVRMask(TypeQuals);
- Result = Context.getQualifiedType(Result, Quals);
+ QualType Qualified = S.BuildQualifiedType(Result, DeclLoc, TypeQuals, &DS);
+
+ // If adding qualifiers fails, just use the unqualified type.
+ if (Qualified.isNull())
+ declarator.setInvalidType(true);
+ else
+ Result = Qualified;
}
return Result;
@@ -1035,37 +1156,36 @@ static std::string getPrintableNameForEntity(DeclarationName Entity) {
}
QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
- Qualifiers Qs) {
+ Qualifiers Qs, const DeclSpec *DS) {
// Enforce C99 6.7.3p2: "Types other than pointer types derived from
// object or incomplete types shall not be restrict-qualified."
if (Qs.hasRestrict()) {
unsigned DiagID = 0;
QualType ProblemTy;
- const Type *Ty = T->getCanonicalTypeInternal().getTypePtr();
- if (const ReferenceType *RTy = dyn_cast<ReferenceType>(Ty)) {
- if (!RTy->getPointeeType()->isIncompleteOrObjectType()) {
- DiagID = diag::err_typecheck_invalid_restrict_invalid_pointee;
- ProblemTy = T->getAs<ReferenceType>()->getPointeeType();
- }
- } else if (const PointerType *PTy = dyn_cast<PointerType>(Ty)) {
- if (!PTy->getPointeeType()->isIncompleteOrObjectType()) {
- DiagID = diag::err_typecheck_invalid_restrict_invalid_pointee;
- ProblemTy = T->getAs<PointerType>()->getPointeeType();
- }
- } else if (const MemberPointerType *PTy = dyn_cast<MemberPointerType>(Ty)) {
- if (!PTy->getPointeeType()->isIncompleteOrObjectType()) {
+ if (T->isAnyPointerType() || T->isReferenceType() ||
+ T->isMemberPointerType()) {
+ QualType EltTy;
+ if (T->isObjCObjectPointerType())
+ EltTy = T;
+ else if (const MemberPointerType *PTy = T->getAs<MemberPointerType>())
+ EltTy = PTy->getPointeeType();
+ else
+ EltTy = T->getPointeeType();
+
+ // If we have a pointer or reference, the pointee must have an object
+ // incomplete type.
+ if (!EltTy->isIncompleteOrObjectType()) {
DiagID = diag::err_typecheck_invalid_restrict_invalid_pointee;
- ProblemTy = T->getAs<PointerType>()->getPointeeType();
+ ProblemTy = EltTy;
}
- } else if (!Ty->isDependentType()) {
- // FIXME: this deserves a proper diagnostic
- DiagID = diag::err_typecheck_invalid_restrict_invalid_pointee;
+ } else if (!T->isDependentType()) {
+ DiagID = diag::err_typecheck_invalid_restrict_not_pointer;
ProblemTy = T;
}
if (DiagID) {
- Diag(Loc, DiagID) << ProblemTy;
+ Diag(DS ? DS->getRestrictSpecLoc() : Loc, DiagID) << ProblemTy;
Qs.removeRestrict();
}
}
@@ -1073,6 +1193,39 @@ QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
return Context.getQualifiedType(T, Qs);
}
+QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
+ unsigned CVRA, const DeclSpec *DS) {
+ // Convert from DeclSpec::TQ to Qualifiers::TQ by just dropping TQ_atomic.
+ unsigned CVR = CVRA & ~DeclSpec::TQ_atomic;
+
+ // C11 6.7.3/5:
+ // If the same qualifier appears more than once in the same
+ // specifier-qualifier-list, either directly or via one or more typedefs,
+ // the behavior is the same as if it appeared only once.
+ //
+ // It's not specified what happens when the _Atomic qualifier is applied to
+ // a type specified with the _Atomic specifier, but we assume that this
+ // should be treated as if the _Atomic qualifier appeared multiple times.
+ if (CVRA & DeclSpec::TQ_atomic && !T->isAtomicType()) {
+ // C11 6.7.3/5:
+ // If other qualifiers appear along with the _Atomic qualifier in a
+ // specifier-qualifier-list, the resulting type is the so-qualified
+ // atomic type.
+ //
+ // Don't need to worry about array types here, since _Atomic can't be
+ // applied to such types.
+ SplitQualType Split = T.getSplitUnqualifiedType();
+ T = BuildAtomicType(QualType(Split.Ty, 0),
+ DS ? DS->getAtomicSpecLoc() : Loc);
+ if (T.isNull())
+ return T;
+ Split.Quals.addCVRQualifiers(CVR);
+ return BuildQualifiedType(T, Loc, Split.Quals);
+ }
+
+ return BuildQualifiedType(T, Loc, Qualifiers::fromCVRMask(CVR), DS);
+}
+
/// \brief Build a paren type including \p T.
QualType Sema::BuildParenType(QualType T) {
return Context.getParenType(T);
@@ -1338,7 +1491,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
// C99 6.7.5.2p1: The size expression shall have integer type.
// C++11 allows contextual conversions to such types.
- if (!getLangOpts().CPlusPlus0x &&
+ if (!getLangOpts().CPlusPlus11 &&
ArraySize && !ArraySize->isTypeDependent() &&
!ArraySize->getType()->isIntegralOrUnscopedEnumerationType()) {
Diag(ArraySize->getLocStart(), diag::err_array_size_non_int)
@@ -1359,7 +1512,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
isArraySizeVLA(*this, ArraySize, ConstVal)) {
// Even in C++11, don't allow contextual conversions in the array bound
// of a VLA.
- if (getLangOpts().CPlusPlus0x &&
+ if (getLangOpts().CPlusPlus11 &&
!ArraySize->getType()->isIntegralOrUnscopedEnumerationType()) {
Diag(ArraySize->getLocStart(), diag::err_array_size_non_int)
<< ArraySize->getType() << ArraySize->getSourceRange();
@@ -1409,6 +1562,12 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
T = Context.getConstantArrayType(T, ConstVal, ASM, Quals);
}
+
+ // OpenCL v1.2 s6.9.d: variable length arrays are not supported.
+ if (getLangOpts().OpenCL && T->isVariableArrayType()) {
+ Diag(Loc, diag::err_opencl_vla);
+ return QualType();
+ }
// If this is not C99, extwarn about VLA's and C99 array size modifiers.
if (!getLangOpts().C99) {
if (T->isVariableArrayType()) {
@@ -1435,6 +1594,11 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
: diag::ext_c99_array_usage) << ASM;
}
+ if (T->isVariableArrayType()) {
+ // Warn about VLAs for -Wvla.
+ Diag(Loc, diag::warn_vla_used);
+ }
+
return T;
}
@@ -1475,45 +1639,10 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize,
return Context.getDependentSizedExtVectorType(T, ArraySize, AttrLoc);
}
-/// \brief Build a function type.
-///
-/// This routine checks the function type according to C++ rules and
-/// under the assumption that the result type and parameter types have
-/// just been instantiated from a template. It therefore duplicates
-/// some of the behavior of GetTypeForDeclarator, but in a much
-/// simpler form that is only suitable for this narrow use case.
-///
-/// \param T The return type of the function.
-///
-/// \param ParamTypes The parameter types of the function. This array
-/// will be modified to account for adjustments to the types of the
-/// function parameters.
-///
-/// \param NumParamTypes The number of parameter types in ParamTypes.
-///
-/// \param Variadic Whether this is a variadic function type.
-///
-/// \param HasTrailingReturn Whether this function has a trailing return type.
-///
-/// \param Quals The cvr-qualifiers to be applied to the function type.
-///
-/// \param Loc The location of the entity whose type involves this
-/// function type or, if there is no such entity, the location of the
-/// type that will have function type.
-///
-/// \param Entity The name of the entity that involves the function
-/// type, if known.
-///
-/// \returns A suitable function type, if there are no
-/// errors. Otherwise, returns a NULL type.
QualType Sema::BuildFunctionType(QualType T,
- QualType *ParamTypes,
- unsigned NumParamTypes,
- bool Variadic, bool HasTrailingReturn,
- unsigned Quals,
- RefQualifierKind RefQualifier,
+ llvm::MutableArrayRef<QualType> ParamTypes,
SourceLocation Loc, DeclarationName Entity,
- FunctionType::ExtInfo Info) {
+ const FunctionProtoType::ExtProtoInfo &EPI) {
if (T->isArrayType() || T->isFunctionType()) {
Diag(Loc, diag::err_func_returning_array_function)
<< T->isFunctionType() << T;
@@ -1528,7 +1657,7 @@ QualType Sema::BuildFunctionType(QualType T,
}
bool Invalid = false;
- for (unsigned Idx = 0; Idx < NumParamTypes; ++Idx) {
+ for (unsigned Idx = 0, Cnt = ParamTypes.size(); Idx < Cnt; ++Idx) {
// FIXME: Loc is too inprecise here, should use proper locations for args.
QualType ParamType = Context.getAdjustedParameterType(ParamTypes[Idx]);
if (ParamType->isVoidType()) {
@@ -1547,14 +1676,7 @@ QualType Sema::BuildFunctionType(QualType T,
if (Invalid)
return QualType();
- FunctionProtoType::ExtProtoInfo EPI;
- EPI.Variadic = Variadic;
- EPI.HasTrailingReturn = HasTrailingReturn;
- EPI.TypeQuals = Quals;
- EPI.RefQualifier = RefQualifier;
- EPI.ExtInfo = Info;
-
- return Context.getFunctionType(T, ParamTypes, NumParamTypes, EPI);
+ return Context.getFunctionType(T, ParamTypes, EPI);
}
/// \brief Build a member pointer type \c T Class::*.
@@ -1601,13 +1723,33 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class,
return QualType();
}
- // In the Microsoft ABI, the class is allowed to be an incomplete
- // type. In such cases, the compiler makes a worst-case assumption.
- // We make no such assumption right now, so emit an error if the
- // class isn't a complete type.
- if (Context.getTargetInfo().getCXXABI() == CXXABI_Microsoft &&
- RequireCompleteType(Loc, Class, diag::err_incomplete_type))
- return QualType();
+ // C++ allows the class type in a member pointer to be an incomplete type.
+ // In the Microsoft ABI, the size of the member pointer can vary
+ // according to the class type, which means that we really need a
+ // complete type if possible, which means we need to instantiate templates.
+ //
+ // If template instantiation fails or the type is just incomplete, we have to
+ // add an extra slot to the member pointer. Yes, this does cause problems
+ // when passing pointers between TUs that disagree about the size.
+ if (Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+ CXXRecordDecl *RD = Class->getAsCXXRecordDecl();
+ if (RD && !RD->hasAttr<MSInheritanceAttr>()) {
+ // Lock in the inheritance model on the first use of a member pointer.
+ // Otherwise we may disagree about the size at different points in the TU.
+ // FIXME: MSVC picks a model on the first use that needs to know the size,
+ // rather than on the first mention of the type, e.g. typedefs.
+ if (RequireCompleteType(Loc, Class, 0) && !RD->isBeingDefined()) {
+ // We know it doesn't have an attribute and it's incomplete, so use the
+ // unspecified inheritance model. If we're in the record body, we can
+ // figure out the inheritance model.
+ for (CXXRecordDecl::redecl_iterator I = RD->redecls_begin(),
+ E = RD->redecls_end(); I != E; ++I) {
+ I->addAttr(::new (Context) UnspecifiedInheritanceAttr(
+ RD->getSourceRange(), Context));
+ }
+ }
+ }
+ }
return Context.getMemberPointerType(T, Class.getTypePtr());
}
@@ -1754,50 +1896,118 @@ static void inferARCWriteback(TypeProcessingState &state,
// TODO: mark whether we did this inference?
}
-static void DiagnoseIgnoredQualifiers(unsigned Quals,
- SourceLocation ConstQualLoc,
- SourceLocation VolatileQualLoc,
- SourceLocation RestrictQualLoc,
- Sema& S) {
- std::string QualStr;
+static void diagnoseIgnoredQualifiers(
+ Sema &S, unsigned Quals,
+ SourceLocation FallbackLoc,
+ SourceLocation ConstQualLoc = SourceLocation(),
+ SourceLocation VolatileQualLoc = SourceLocation(),
+ SourceLocation RestrictQualLoc = SourceLocation(),
+ SourceLocation AtomicQualLoc = SourceLocation()) {
+ if (!Quals)
+ return;
+
+ const SourceManager &SM = S.getSourceManager();
+
+ struct Qual {
+ unsigned Mask;
+ const char *Name;
+ SourceLocation Loc;
+ } const QualKinds[4] = {
+ { DeclSpec::TQ_const, "const", ConstQualLoc },
+ { DeclSpec::TQ_volatile, "volatile", VolatileQualLoc },
+ { DeclSpec::TQ_restrict, "restrict", RestrictQualLoc },
+ { DeclSpec::TQ_atomic, "_Atomic", AtomicQualLoc }
+ };
+
+ llvm::SmallString<32> QualStr;
unsigned NumQuals = 0;
SourceLocation Loc;
+ FixItHint FixIts[4];
+
+ // Build a string naming the redundant qualifiers.
+ for (unsigned I = 0; I != 4; ++I) {
+ if (Quals & QualKinds[I].Mask) {
+ if (!QualStr.empty()) QualStr += ' ';
+ QualStr += QualKinds[I].Name;
+
+ // If we have a location for the qualifier, offer a fixit.
+ SourceLocation QualLoc = QualKinds[I].Loc;
+ if (!QualLoc.isInvalid()) {
+ FixIts[NumQuals] = FixItHint::CreateRemoval(QualLoc);
+ if (Loc.isInvalid() || SM.isBeforeInTranslationUnit(QualLoc, Loc))
+ Loc = QualLoc;
+ }
- FixItHint ConstFixIt;
- FixItHint VolatileFixIt;
- FixItHint RestrictFixIt;
+ ++NumQuals;
+ }
+ }
- const SourceManager &SM = S.getSourceManager();
+ S.Diag(Loc.isInvalid() ? FallbackLoc : Loc, diag::warn_qual_return_type)
+ << QualStr << NumQuals << FixIts[0] << FixIts[1] << FixIts[2] << FixIts[3];
+}
+
+// Diagnose pointless type qualifiers on the return type of a function.
+static void diagnoseIgnoredFunctionQualifiers(Sema &S, QualType RetTy,
+ Declarator &D,
+ unsigned FunctionChunkIndex) {
+ if (D.getTypeObject(FunctionChunkIndex).Fun.hasTrailingReturnType()) {
+ // FIXME: TypeSourceInfo doesn't preserve location information for
+ // qualifiers.
+ diagnoseIgnoredQualifiers(S, RetTy.getLocalCVRQualifiers(),
+ D.getIdentifierLoc());
+ return;
+ }
+
+ for (unsigned OuterChunkIndex = FunctionChunkIndex + 1,
+ End = D.getNumTypeObjects();
+ OuterChunkIndex != End; ++OuterChunkIndex) {
+ DeclaratorChunk &OuterChunk = D.getTypeObject(OuterChunkIndex);
+ switch (OuterChunk.Kind) {
+ case DeclaratorChunk::Paren:
+ continue;
+
+ case DeclaratorChunk::Pointer: {
+ DeclaratorChunk::PointerTypeInfo &PTI = OuterChunk.Ptr;
+ diagnoseIgnoredQualifiers(
+ S, PTI.TypeQuals,
+ SourceLocation(),
+ SourceLocation::getFromRawEncoding(PTI.ConstQualLoc),
+ SourceLocation::getFromRawEncoding(PTI.VolatileQualLoc),
+ SourceLocation::getFromRawEncoding(PTI.RestrictQualLoc),
+ SourceLocation::getFromRawEncoding(PTI.AtomicQualLoc));
+ return;
+ }
+
+ case DeclaratorChunk::Function:
+ case DeclaratorChunk::BlockPointer:
+ case DeclaratorChunk::Reference:
+ case DeclaratorChunk::Array:
+ case DeclaratorChunk::MemberPointer:
+ // FIXME: We can't currently provide an accurate source location and a
+ // fix-it hint for these.
+ unsigned AtomicQual = RetTy->isAtomicType() ? DeclSpec::TQ_atomic : 0;
+ diagnoseIgnoredQualifiers(S, RetTy.getCVRQualifiers() | AtomicQual,
+ D.getIdentifierLoc());
+ return;
+ }
+
+ llvm_unreachable("unknown declarator chunk kind");
+ }
+
+ // If the qualifiers come from a conversion function type, don't diagnose
+ // them -- they're not necessarily redundant, since such a conversion
+ // operator can be explicitly called as "x.operator const int()".
+ if (D.getName().getKind() == UnqualifiedId::IK_ConversionFunctionId)
+ return;
- // FIXME: The locations here are set kind of arbitrarily. It'd be nicer to
- // find a range and grow it to encompass all the qualifiers, regardless of
- // the order in which they textually appear.
- if (Quals & Qualifiers::Const) {
- ConstFixIt = FixItHint::CreateRemoval(ConstQualLoc);
- QualStr = "const";
- ++NumQuals;
- if (!Loc.isValid() || SM.isBeforeInTranslationUnit(ConstQualLoc, Loc))
- Loc = ConstQualLoc;
- }
- if (Quals & Qualifiers::Volatile) {
- VolatileFixIt = FixItHint::CreateRemoval(VolatileQualLoc);
- QualStr += (NumQuals == 0 ? "volatile" : " volatile");
- ++NumQuals;
- if (!Loc.isValid() || SM.isBeforeInTranslationUnit(VolatileQualLoc, Loc))
- Loc = VolatileQualLoc;
- }
- if (Quals & Qualifiers::Restrict) {
- RestrictFixIt = FixItHint::CreateRemoval(RestrictQualLoc);
- QualStr += (NumQuals == 0 ? "restrict" : " restrict");
- ++NumQuals;
- if (!Loc.isValid() || SM.isBeforeInTranslationUnit(RestrictQualLoc, Loc))
- Loc = RestrictQualLoc;
- }
-
- assert(NumQuals > 0 && "No known qualifiers?");
-
- S.Diag(Loc, diag::warn_qual_return_type)
- << QualStr << NumQuals << ConstFixIt << VolatileFixIt << RestrictFixIt;
+ // Just parens all the way out to the decl specifiers. Diagnose any qualifiers
+ // which are present there.
+ diagnoseIgnoredQualifiers(S, D.getDeclSpec().getTypeQualifiers(),
+ D.getIdentifierLoc(),
+ D.getDeclSpec().getConstSpecLoc(),
+ D.getDeclSpec().getVolatileSpecLoc(),
+ D.getDeclSpec().getRestrictSpecLoc(),
+ D.getDeclSpec().getAtomicSpecLoc());
}
static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
@@ -1832,7 +2042,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
// "void" instead.
T = SemaRef.Context.VoidTy;
if (AttributeList *attrs = D.getDeclSpec().getAttributes().getList())
- processTypeAttrs(state, T, true, attrs);
+ processTypeAttrs(state, T, TAL_DeclSpec, attrs);
break;
case UnqualifiedId::IK_ConversionFunctionId:
@@ -1851,7 +2061,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
// type (this is checked later) and we can skip this. In other languages
// using auto, we need to check regardless.
if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto &&
- (!SemaRef.getLangOpts().CPlusPlus0x || !D.isFunctionDeclarator())) {
+ (!SemaRef.getLangOpts().CPlusPlus11 || !D.isFunctionDeclarator())) {
int Error = -1;
switch (D.getContext()) {
@@ -1917,7 +2127,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
// contains a trailing return type. That is only legal at the outermost
// level. Check all declarator chunks (outermost first) anyway, to give
// better diagnostics.
- if (SemaRef.getLangOpts().CPlusPlus0x && Error != -1) {
+ if (SemaRef.getLangOpts().CPlusPlus11 && Error != -1) {
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
unsigned chunkIndex = e - i - 1;
state.setCurrentChunkIndex(chunkIndex);
@@ -1969,6 +2179,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
SemaRef.Diag(OwnedTagDecl->getLocation(),
diag::err_type_defined_in_alias_template)
<< SemaRef.Context.getTypeDeclType(OwnedTagDecl);
+ D.setInvalidType(true);
break;
case Declarator::TypeNameContext:
case Declarator::TemplateParamContext:
@@ -1979,6 +2190,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
SemaRef.Diag(OwnedTagDecl->getLocation(),
diag::err_type_defined_in_type_specifier)
<< SemaRef.Context.getTypeDeclType(OwnedTagDecl);
+ D.setInvalidType(true);
break;
case Declarator::PrototypeContext:
case Declarator::ObjCParameterContext:
@@ -1989,6 +2201,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
SemaRef.Diag(OwnedTagDecl->getLocation(),
diag::err_type_defined_in_param_type)
<< SemaRef.Context.getTypeDeclType(OwnedTagDecl);
+ D.setInvalidType(true);
break;
case Declarator::ConditionContext:
// C++ 6.4p2:
@@ -1996,6 +2209,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
// a new class or enumeration.
SemaRef.Diag(OwnedTagDecl->getLocation(),
diag::err_type_defined_in_condition);
+ D.setInvalidType(true);
break;
}
}
@@ -2087,7 +2301,7 @@ static void warnAboutAmbiguousFunction(Sema &S, Declarator &D,
if (!D.isFunctionDeclarator() ||
D.getFunctionDefinitionKind() != FDK_Declaration ||
!S.CurContext->isFunctionOrMethod() ||
- D.getDeclSpec().getStorageClassSpecAsWritten()
+ D.getDeclSpec().getStorageClassSpec()
!= DeclSpec::SCS_unspecified)
return;
@@ -2150,7 +2364,7 @@ static void warnAboutAmbiguousFunction(Sema &S, Declarator &D,
<< FixItHint::CreateRemoval(ParenRange);
else {
std::string Init = S.getFixItZeroInitializerForType(RT);
- if (Init.empty() && S.LangOpts.CPlusPlus0x)
+ if (Init.empty() && S.LangOpts.CPlusPlus11)
Init = "{}";
if (!Init.empty())
S.Diag(DeclType.Loc, diag::note_empty_parens_zero_initialize)
@@ -2376,38 +2590,61 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// Do not allow returning half FP value.
// FIXME: This really should be in BuildFunctionType.
if (T->isHalfType()) {
- S.Diag(D.getIdentifierLoc(),
- diag::err_parameters_retval_cannot_have_fp16_type) << 1
- << FixItHint::CreateInsertion(D.getIdentifierLoc(), "*");
- D.setInvalidType(true);
+ if (S.getLangOpts().OpenCL) {
+ if (!S.getOpenCLOptions().cl_khr_fp16) {
+ S.Diag(D.getIdentifierLoc(), diag::err_opencl_half_return) << T;
+ D.setInvalidType(true);
+ }
+ } else {
+ S.Diag(D.getIdentifierLoc(),
+ diag::err_parameters_retval_cannot_have_fp16_type) << 1;
+ D.setInvalidType(true);
+ }
}
// cv-qualifiers on return types are pointless except when the type is a
// class type in C++.
- if (isa<PointerType>(T) && T.getLocalCVRQualifiers() &&
- (D.getName().getKind() != UnqualifiedId::IK_ConversionFunctionId) &&
- (!LangOpts.CPlusPlus || !T->isDependentType())) {
- assert(chunkIndex + 1 < e && "No DeclaratorChunk for the return type?");
- DeclaratorChunk ReturnTypeChunk = D.getTypeObject(chunkIndex + 1);
- assert(ReturnTypeChunk.Kind == DeclaratorChunk::Pointer);
-
- DeclaratorChunk::PointerTypeInfo &PTI = ReturnTypeChunk.Ptr;
-
- DiagnoseIgnoredQualifiers(PTI.TypeQuals,
- SourceLocation::getFromRawEncoding(PTI.ConstQualLoc),
- SourceLocation::getFromRawEncoding(PTI.VolatileQualLoc),
- SourceLocation::getFromRawEncoding(PTI.RestrictQualLoc),
- S);
-
- } else if (T.getCVRQualifiers() && D.getDeclSpec().getTypeQualifiers() &&
- (!LangOpts.CPlusPlus ||
- (!T->isDependentType() && !T->isRecordType()))) {
-
- DiagnoseIgnoredQualifiers(D.getDeclSpec().getTypeQualifiers(),
- D.getDeclSpec().getConstSpecLoc(),
- D.getDeclSpec().getVolatileSpecLoc(),
- D.getDeclSpec().getRestrictSpecLoc(),
- S);
+ if ((T.getCVRQualifiers() || T->isAtomicType()) &&
+ !(S.getLangOpts().CPlusPlus &&
+ (T->isDependentType() || T->isRecordType())))
+ diagnoseIgnoredFunctionQualifiers(S, T, D, chunkIndex);
+
+ // Objective-C ARC ownership qualifiers are ignored on the function
+ // return type (by type canonicalization). Complain if this attribute
+ // was written here.
+ if (T.getQualifiers().hasObjCLifetime()) {
+ SourceLocation AttrLoc;
+ if (chunkIndex + 1 < D.getNumTypeObjects()) {
+ DeclaratorChunk ReturnTypeChunk = D.getTypeObject(chunkIndex + 1);
+ for (const AttributeList *Attr = ReturnTypeChunk.getAttrs();
+ Attr; Attr = Attr->getNext()) {
+ if (Attr->getKind() == AttributeList::AT_ObjCOwnership) {
+ AttrLoc = Attr->getLoc();
+ break;
+ }
+ }
+ }
+ if (AttrLoc.isInvalid()) {
+ for (const AttributeList *Attr
+ = D.getDeclSpec().getAttributes().getList();
+ Attr; Attr = Attr->getNext()) {
+ if (Attr->getKind() == AttributeList::AT_ObjCOwnership) {
+ AttrLoc = Attr->getLoc();
+ break;
+ }
+ }
+ }
+
+ if (AttrLoc.isValid()) {
+ // The ownership attributes are almost always written via
+ // the predefined
+ // __strong/__weak/__autoreleasing/__unsafe_unretained.
+ if (AttrLoc.isMacroID())
+ AttrLoc = S.SourceMgr.getImmediateExpansionRange(AttrLoc).first;
+
+ S.Diag(AttrLoc, diag::warn_arc_lifetime_result_type)
+ << T.getQualifiers().getObjCLifetime();
+ }
}
if (LangOpts.CPlusPlus && D.getDeclSpec().isTypeSpecOwned()) {
@@ -2457,6 +2694,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// definition.
S.Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration);
D.setInvalidType(true);
+ // Recover by creating a K&R-style function type.
+ T = Context.getFunctionNoProtoType(T);
break;
}
@@ -2514,10 +2753,18 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
} else if (ArgTy->isHalfType()) {
// Disallow half FP arguments.
// FIXME: This really should be in BuildFunctionType.
- S.Diag(Param->getLocation(),
- diag::err_parameters_retval_cannot_have_fp16_type) << 0
- << FixItHint::CreateInsertion(Param->getLocation(), "*");
- D.setInvalidType();
+ if (S.getLangOpts().OpenCL) {
+ if (!S.getOpenCLOptions().cl_khr_fp16) {
+ S.Diag(Param->getLocation(),
+ diag::err_opencl_half_argument) << ArgTy;
+ D.setInvalidType();
+ Param->setInvalidDecl();
+ }
+ } else {
+ S.Diag(Param->getLocation(),
+ diag::err_parameters_retval_cannot_have_fp16_type) << 0;
+ D.setInvalidType();
+ }
} else if (!FTI.hasPrototype) {
if (ArgTy->isPromotableIntegerType()) {
ArgTy = Context.getPromotedIntegerType(ArgTy);
@@ -2568,7 +2815,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
Exceptions,
EPI);
- T = Context.getFunctionType(T, ArgTys.data(), ArgTys.size(), EPI);
+ T = Context.getFunctionType(T, ArgTys, EPI);
}
break;
@@ -2634,7 +2881,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// See if there are any attributes on this declarator chunk.
if (AttributeList *attrs = const_cast<AttributeList*>(DeclType.getAttrs()))
- processTypeAttrs(state, T, false, attrs);
+ processTypeAttrs(state, T, TAL_DeclChunk, attrs);
}
if (LangOpts.CPlusPlus && T->isFunctionType()) {
@@ -2659,30 +2906,6 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
FreeFunction = (DC && !DC->isRecord());
}
- // 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 &&
- D.getName().getKind() != UnqualifiedId::IK_ConstructorTemplateId &&
- !(FnTy->getTypeQuals() & DeclSpec::TQ_const)) {
- // Rebuild function type adding a 'const' qualifier.
- FunctionProtoType::ExtProtoInfo EPI = FnTy->getExtProtoInfo();
- EPI.TypeQuals |= DeclSpec::TQ_const;
- 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):
// An attempt to specify a function type with a cv-qualifier-seq or a
// ref-qualifier (including by typedef-name) is ill-formed unless it is:
@@ -2732,8 +2955,9 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
EPI.RefQualifier = RQ_None;
T = Context.getFunctionType(FnTy->getResultType(),
- FnTy->arg_type_begin(),
- FnTy->getNumArgs(), EPI);
+ ArrayRef<QualType>(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)
@@ -2746,7 +2970,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// Apply any undistributed attributes from the declarator.
if (!T.isNull())
if (AttributeList *attrs = D.getAttributes())
- processTypeAttrs(state, T, false, attrs);
+ processTypeAttrs(state, T, TAL_DeclName, attrs);
// Diagnose any ignored type attributes.
if (!T.isNull()) state.diagnoseIgnoredTypeAttrs(T);
@@ -2782,7 +3006,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
<< T << D.getSourceRange();
D.setEllipsisLoc(SourceLocation());
} else {
- T = Context.getPackExpansionType(T, llvm::Optional<unsigned>());
+ T = Context.getPackExpansionType(T, None);
}
break;
@@ -2796,10 +3020,10 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// parameter packs in the type of the non-type template parameter, then
// it expands those parameter packs.
if (T->containsUnexpandedParameterPack())
- T = Context.getPackExpansionType(T, llvm::Optional<unsigned>());
+ T = Context.getPackExpansionType(T, None);
else
S.Diag(D.getEllipsisLoc(),
- LangOpts.CPlusPlus0x
+ LangOpts.CPlusPlus11
? diag::warn_cxx98_compat_variadic_templates
: diag::ext_variadic_templates);
break;
@@ -3006,6 +3230,8 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) {
return AttributeList::AT_Pcs;
case AttributedType::attr_pnaclcall:
return AttributeList::AT_PnaclCall;
+ case AttributedType::attr_inteloclbicc:
+ return AttributeList::AT_IntelOclBicc;
}
llvm_unreachable("unexpected attribute kind!");
}
@@ -3099,13 +3325,13 @@ namespace {
TypeLoc OldTL = TInfo->getTypeLoc();
if (TInfo->getType()->getAs<ElaboratedType>()) {
- ElaboratedTypeLoc ElabTL = cast<ElaboratedTypeLoc>(OldTL);
- TemplateSpecializationTypeLoc NamedTL =
- cast<TemplateSpecializationTypeLoc>(ElabTL.getNamedTypeLoc());
+ ElaboratedTypeLoc ElabTL = OldTL.castAs<ElaboratedTypeLoc>();
+ TemplateSpecializationTypeLoc NamedTL = ElabTL.getNamedTypeLoc()
+ .castAs<TemplateSpecializationTypeLoc>();
TL.copy(NamedTL);
}
else
- TL.copy(cast<TemplateSpecializationTypeLoc>(OldTL));
+ TL.copy(OldTL.castAs<TemplateSpecializationTypeLoc>());
}
void VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
assert(DS.getTypeSpecType() == DeclSpec::TST_typeofExpr);
@@ -3153,7 +3379,7 @@ namespace {
TypeSourceInfo *TInfo = 0;
Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
if (TInfo) {
- TL.copy(cast<ElaboratedTypeLoc>(TInfo->getTypeLoc()));
+ TL.copy(TInfo->getTypeLoc().castAs<ElaboratedTypeLoc>());
return;
}
}
@@ -3169,7 +3395,7 @@ namespace {
TypeSourceInfo *TInfo = 0;
Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
assert(TInfo);
- TL.copy(cast<DependentNameTypeLoc>(TInfo->getTypeLoc()));
+ TL.copy(TInfo->getTypeLoc().castAs<DependentNameTypeLoc>());
}
void VisitDependentTemplateSpecializationTypeLoc(
DependentTemplateSpecializationTypeLoc TL) {
@@ -3177,19 +3403,29 @@ namespace {
TypeSourceInfo *TInfo = 0;
Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
assert(TInfo);
- TL.copy(cast<DependentTemplateSpecializationTypeLoc>(
- TInfo->getTypeLoc()));
+ TL.copy(
+ TInfo->getTypeLoc().castAs<DependentTemplateSpecializationTypeLoc>());
}
void VisitTagTypeLoc(TagTypeLoc TL) {
TL.setNameLoc(DS.getTypeSpecTypeNameLoc());
}
void VisitAtomicTypeLoc(AtomicTypeLoc TL) {
- TL.setKWLoc(DS.getTypeSpecTypeLoc());
- TL.setParensRange(DS.getTypeofParensRange());
+ // An AtomicTypeLoc can come from either an _Atomic(...) type specifier
+ // or an _Atomic qualifier.
+ if (DS.getTypeSpecType() == DeclSpec::TST_atomic) {
+ TL.setKWLoc(DS.getTypeSpecTypeLoc());
+ TL.setParensRange(DS.getTypeofParensRange());
- TypeSourceInfo *TInfo = 0;
- Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
- TL.getValueLoc().initializeFullCopy(TInfo->getTypeLoc());
+ TypeSourceInfo *TInfo = 0;
+ Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
+ assert(TInfo);
+ TL.getValueLoc().initializeFullCopy(TInfo->getTypeLoc());
+ } else {
+ TL.setKWLoc(DS.getAtomicSpecLoc());
+ // No parens, to indicate this was spelled as an _Atomic qualifier.
+ TL.setParensRange(SourceRange());
+ Visit(TL.getValueLoc());
+ }
}
void VisitTypeLoc(TypeLoc TL) {
@@ -3239,7 +3475,7 @@ namespace {
case NestedNameSpecifier::Identifier:
assert(isa<DependentNameType>(ClsTy) && "Unexpected TypeLoc");
{
- DependentNameTypeLoc DNTLoc = cast<DependentNameTypeLoc>(ClsTL);
+ DependentNameTypeLoc DNTLoc = ClsTL.castAs<DependentNameTypeLoc>();
DNTLoc.setElaboratedKeywordLoc(SourceLocation());
DNTLoc.setQualifierLoc(NNSLoc.getPrefix());
DNTLoc.setNameLoc(NNSLoc.getLocalBeginLoc());
@@ -3249,7 +3485,7 @@ namespace {
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
if (isa<ElaboratedType>(ClsTy)) {
- ElaboratedTypeLoc ETLoc = *cast<ElaboratedTypeLoc>(&ClsTL);
+ ElaboratedTypeLoc ETLoc = ClsTL.castAs<ElaboratedTypeLoc>();
ETLoc.setElaboratedKeywordLoc(SourceLocation());
ETLoc.setQualifierLoc(NNSLoc.getPrefix());
TypeLoc NamedTL = ETLoc.getNamedTypeLoc();
@@ -3312,6 +3548,29 @@ namespace {
};
}
+static void fillAtomicQualLoc(AtomicTypeLoc ATL, const DeclaratorChunk &Chunk) {
+ SourceLocation Loc;
+ switch (Chunk.Kind) {
+ case DeclaratorChunk::Function:
+ case DeclaratorChunk::Array:
+ case DeclaratorChunk::Paren:
+ llvm_unreachable("cannot be _Atomic qualified");
+
+ case DeclaratorChunk::Pointer:
+ Loc = SourceLocation::getFromRawEncoding(Chunk.Ptr.AtomicQualLoc);
+ break;
+
+ case DeclaratorChunk::BlockPointer:
+ case DeclaratorChunk::Reference:
+ case DeclaratorChunk::MemberPointer:
+ // FIXME: Provide a source location for the _Atomic keyword.
+ break;
+ }
+
+ ATL.setKWLoc(Loc);
+ ATL.setParensRange(SourceRange());
+}
+
/// \brief Create and instantiate a TypeSourceInfo with type source information.
///
/// \param T QualType referring to the type as written in source code.
@@ -3328,13 +3587,19 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
// Handle parameter packs whose type is a pack expansion.
if (isa<PackExpansionType>(T)) {
- cast<PackExpansionTypeLoc>(CurrTL).setEllipsisLoc(D.getEllipsisLoc());
+ CurrTL.castAs<PackExpansionTypeLoc>().setEllipsisLoc(D.getEllipsisLoc());
CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc();
}
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
- while (isa<AttributedTypeLoc>(CurrTL)) {
- AttributedTypeLoc TL = cast<AttributedTypeLoc>(CurrTL);
+ // An AtomicTypeLoc might be produced by an atomic qualifier in this
+ // declarator chunk.
+ if (AtomicTypeLoc ATL = CurrTL.getAs<AtomicTypeLoc>()) {
+ fillAtomicQualLoc(ATL, D.getTypeObject(i));
+ CurrTL = ATL.getValueLoc().getUnqualifiedLoc();
+ }
+
+ while (AttributedTypeLoc TL = CurrTL.getAs<AttributedTypeLoc>()) {
fillAttributedTypeLoc(TL, D.getTypeObject(i).getAttrs());
CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
}
@@ -3389,7 +3654,11 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
// Make sure there are no unused decl attributes on the declarator.
// We don't want to do this for ObjC parameters because we're going
// to apply them to the actual parameter declaration.
- if (D.getContext() != Declarator::ObjCParameterContext)
+ // Likewise, we don't want to do this for alias declarations, because
+ // we are actually going to build a declaration from this eventually.
+ if (D.getContext() != Declarator::ObjCParameterContext &&
+ D.getContext() != Declarator::AliasDeclContext &&
+ D.getContext() != Declarator::AliasTemplateContext)
checkUnusedDeclAttributes(D);
if (getLangOpts().CPlusPlus) {
@@ -3524,6 +3793,14 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
} else if (!type->isObjCRetainableType()) {
return false;
}
+
+ // Don't accept an ownership attribute in the declspec if it would
+ // just be the return type of a block pointer.
+ if (state.isProcessingDeclSpec()) {
+ Declarator &D = state.getDeclarator();
+ if (maybeMovePastReturnType(D, D.getNumTypeObjects()))
+ return false;
+ }
}
Sema &S = state.getSema();
@@ -3630,10 +3907,8 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
// Forbid __weak for class objects marked as
// objc_arc_weak_reference_unavailable
if (lifetime == Qualifiers::OCL_Weak) {
- QualType T = type;
- while (const PointerType *ptr = T->getAs<PointerType>())
- T = ptr->getPointeeType();
- if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) {
+ if (const ObjCObjectPointerType *ObjT =
+ type->getAs<ObjCObjectPointerType>()) {
if (ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl()) {
if (Class->isArcWeakrefUnavailable()) {
S.Diag(AttrLoc, diag::err_arc_unsupported_weak_class);
@@ -4141,7 +4416,7 @@ static void HandleNeonVectorTypeAttr(QualType& CurType,
}
static void processTypeAttrs(TypeProcessingState &state, QualType &type,
- bool isDeclSpec, AttributeList *attrs) {
+ TypeAttrLocation TAL, AttributeList *attrs) {
// Scan through and apply attributes to this type where it makes sense. Some
// attributes (such as __address_space__, __vector_size__, etc) apply to the
// type, but others can be present in the type specifiers even though they
@@ -4156,10 +4431,45 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
if (attr.isInvalid())
continue;
+ if (attr.isCXX11Attribute()) {
+ // [[gnu::...]] attributes are treated as declaration attributes, so may
+ // not appertain to a DeclaratorChunk, even if we handle them as type
+ // attributes.
+ if (attr.getScopeName() && attr.getScopeName()->isStr("gnu")) {
+ if (TAL == TAL_DeclChunk) {
+ state.getSema().Diag(attr.getLoc(),
+ diag::warn_cxx11_gnu_attribute_on_type)
+ << attr.getName();
+ continue;
+ }
+ } else if (TAL != TAL_DeclChunk) {
+ // Otherwise, only consider type processing for a C++11 attribute if
+ // it's actually been applied to a type.
+ continue;
+ }
+ }
+
// If this is an attribute we can handle, do so now,
// otherwise, add it to the FnAttrs list for rechaining.
switch (attr.getKind()) {
- default: break;
+ default:
+ // A C++11 attribute on a declarator chunk must appertain to a type.
+ if (attr.isCXX11Attribute() && TAL == TAL_DeclChunk) {
+ state.getSema().Diag(attr.getLoc(), diag::err_attribute_not_type_attr)
+ << attr.getName();
+ attr.setUsedAsTypeAttr();
+ }
+ break;
+
+ case AttributeList::UnknownAttribute:
+ if (attr.isCXX11Attribute() && TAL == TAL_DeclChunk)
+ state.getSema().Diag(attr.getLoc(),
+ diag::warn_unknown_attribute_ignored)
+ << attr.getName();
+ break;
+
+ case AttributeList::IgnoredAttribute:
+ break;
case AttributeList::AT_MayAlias:
// FIXME: This attribute needs to actually be handled, but if we ignore
@@ -4180,9 +4490,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
attr.setUsedAsTypeAttr();
break;
case AttributeList::AT_ExtVectorType:
- if (state.getDeclarator().getDeclSpec().getStorageClassSpec()
- != DeclSpec::SCS_typedef)
- HandleExtVectorTypeAttr(type, attr, state.getSema());
+ HandleExtVectorTypeAttr(type, attr, state.getSema());
attr.setUsedAsTypeAttr();
break;
case AttributeList::AT_NeonVectorType:
@@ -4204,13 +4512,14 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
case AttributeList::AT_Win64:
case AttributeList::AT_Ptr32:
case AttributeList::AT_Ptr64:
- // FIXME: don't ignore these
+ // FIXME: Don't ignore these. We have partial handling for them as
+ // declaration attributes in SemaDeclAttr.cpp; that should be moved here.
attr.setUsedAsTypeAttr();
break;
case AttributeList::AT_NSReturnsRetained:
if (!state.getSema().getLangOpts().ObjCAutoRefCount)
- break;
+ break;
// fallthrough into the function attrs
FUNCTION_TYPE_ATTRS_CASELIST:
@@ -4218,7 +4527,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
// Never process function type attributes as part of the
// declaration-specifiers.
- if (isDeclSpec)
+ if (TAL == TAL_DeclSpec)
distributeFunctionTypeAttrFromDeclSpec(state, attr, type);
// Otherwise, handle the possible delays.
@@ -4359,9 +4668,14 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T,
// repeating the diagnostic.
// FIXME: Add a Fix-It that imports the corresponding module or includes
// the header.
- if (isSFINAEContext() || HiddenDefinitions.insert(Def)) {
- Diag(Loc, diag::err_module_private_definition) << T;
- Diag(Def->getLocation(), diag::note_previous_definition);
+ Module *Owner = Def->getOwningModule();
+ Diag(Loc, diag::err_module_private_definition)
+ << T << Owner->getFullModuleName();
+ Diag(Def->getLocation(), diag::note_previous_definition);
+
+ if (!isSFINAEContext()) {
+ // Recover by implicitly importing this module.
+ createImplicitModuleImport(Loc, Owner);
}
}
@@ -4562,6 +4876,8 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T,
Diag(Dtor->getLocation(), Dtor->isUserProvided() ?
diag::note_non_literal_user_provided_dtor :
diag::note_non_literal_nontrivial_dtor) << RD;
+ if (!Dtor->isUserProvided())
+ SpecialMemberIsTrivial(Dtor, CXXDestructor, /*Diagnose*/true);
}
return true;
diff --git a/lib/Sema/TargetAttributesSema.cpp b/lib/Sema/TargetAttributesSema.cpp
index 25ace95..2f77012 100644
--- a/lib/Sema/TargetAttributesSema.cpp
+++ b/lib/Sema/TargetAttributesSema.cpp
@@ -13,9 +13,9 @@
//===----------------------------------------------------------------------===//
#include "TargetAttributesSema.h"
-#include "clang/Sema/SemaInternal.h"
-#include "clang/Basic/TargetInfo.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/Triple.h"
using namespace clang;
@@ -151,7 +151,8 @@ static void HandleX86ForceAlignArgPointerAttr(Decl *D,
S.Context));
}
-DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range) {
+DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range,
+ unsigned AttrSpellingListIndex) {
if (D->hasAttr<DLLExportAttr>()) {
Diag(Range.getBegin(), diag::warn_attribute_ignored) << "dllimport";
return NULL;
@@ -160,7 +161,8 @@ DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range) {
if (D->hasAttr<DLLImportAttr>())
return NULL;
- return ::new (Context) DLLImportAttr(Range, Context);
+ return ::new (Context) DLLImportAttr(Range, Context,
+ AttrSpellingListIndex);
}
static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
@@ -189,12 +191,14 @@ static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
return;
}
- DLLImportAttr *NewAttr = S.mergeDLLImportAttr(D, Attr.getRange());
+ unsigned Index = Attr.getAttributeSpellingListIndex();
+ DLLImportAttr *NewAttr = S.mergeDLLImportAttr(D, Attr.getRange(), Index);
if (NewAttr)
D->addAttr(NewAttr);
}
-DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, SourceRange Range) {
+DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, SourceRange Range,
+ unsigned AttrSpellingListIndex) {
if (DLLImportAttr *Import = D->getAttr<DLLImportAttr>()) {
Diag(Import->getLocation(), diag::warn_attribute_ignored) << "dllimport";
D->dropAttr<DLLImportAttr>();
@@ -203,7 +207,8 @@ DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D, SourceRange Range) {
if (D->hasAttr<DLLExportAttr>())
return NULL;
- return ::new (Context) DLLExportAttr(Range, Context);
+ return ::new (Context) DLLExportAttr(Range, Context,
+ AttrSpellingListIndex);
}
static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
@@ -229,7 +234,8 @@ static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
return;
}
- DLLExportAttr *NewAttr = S.mergeDLLExportAttr(D, Attr.getRange());
+ unsigned Index = Attr.getAttributeSpellingListIndex();
+ DLLExportAttr *NewAttr = S.mergeDLLExportAttr(D, Attr.getRange(), Index);
if (NewAttr)
D->addAttr(NewAttr);
}
@@ -262,6 +268,57 @@ namespace {
};
}
+static void HandleMips16Attr(Decl *D, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.hasParameterOrArguments()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+ // Attribute can only be applied to function types.
+ if (!isa<FunctionDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
+ << Attr.getName() << /* function */0;
+ return;
+ }
+ D->addAttr(::new (S.Context) Mips16Attr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
+}
+
+static void HandleNoMips16Attr(Decl *D, const AttributeList &Attr, Sema &S) {
+ // check the attribute arguments.
+ if (Attr.hasParameterOrArguments()) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ return;
+ }
+ // Attribute can only be applied to function types.
+ if (!isa<FunctionDecl>(D)) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
+ << Attr.getName() << /* function */0;
+ return;
+ }
+ D->addAttr(::new (S.Context)
+ NoMips16Attr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
+}
+
+namespace {
+ class MipsAttributesSema : public TargetAttributesSema {
+ public:
+ MipsAttributesSema() { }
+ bool ProcessDeclAttribute(Scope *scope, Decl *D, const AttributeList &Attr,
+ Sema &S) const {
+ if (Attr.getName()->getName() == "mips16") {
+ HandleMips16Attr(D, Attr, S);
+ return true;
+ } else if (Attr.getName()->getName() == "nomips16") {
+ HandleNoMips16Attr(D, Attr, S);
+ return true;
+ }
+ return false;
+ }
+ };
+}
+
const TargetAttributesSema &Sema::getTargetAttributesSema() const {
if (TheTargetAttributesSema)
return *TheTargetAttributesSema;
@@ -275,6 +332,9 @@ const TargetAttributesSema &Sema::getTargetAttributesSema() const {
case llvm::Triple::x86:
case llvm::Triple::x86_64:
return *(TheTargetAttributesSema = new X86AttributesSema);
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ return *(TheTargetAttributesSema = new MipsAttributesSema);
default:
return *(TheTargetAttributesSema = new TargetAttributesSema);
}
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 294d742..bdd68a7 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -14,11 +14,7 @@
#ifndef LLVM_CLANG_SEMA_TREETRANSFORM_H
#define LLVM_CLANG_SEMA_TREETRANSFORM_H
-#include "clang/Sema/SemaInternal.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/ParsedTemplate.h"
-#include "clang/Sema/SemaDiagnostic.h"
-#include "clang/Sema/ScopeInfo.h"
+#include "TypeLocBuilder.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
@@ -28,12 +24,16 @@
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
-#include "clang/Sema/Ownership.h"
-#include "clang/Sema/Designator.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Designator.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Ownership.h"
+#include "clang/Sema/ParsedTemplate.h"
+#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/ErrorHandling.h"
-#include "TypeLocBuilder.h"
#include <algorithm>
namespace clang {
@@ -247,10 +247,10 @@ public:
/// must be set.
bool TryExpandParameterPacks(SourceLocation EllipsisLoc,
SourceRange PatternRange,
- llvm::ArrayRef<UnexpandedParameterPack> Unexpanded,
+ ArrayRef<UnexpandedParameterPack> Unexpanded,
bool &ShouldExpand,
bool &RetainExpansion,
- llvm::Optional<unsigned> &NumExpansions) {
+ Optional<unsigned> &NumExpansions) {
ShouldExpand = false;
return false;
}
@@ -323,6 +323,15 @@ public:
/// \returns the transformed expression.
ExprResult TransformExpr(Expr *E);
+ /// \brief Transform the given initializer.
+ ///
+ /// By default, this routine transforms an initializer by stripping off the
+ /// semantic nodes added by initialization, then passing the result to
+ /// TransformExpr or TransformExprs.
+ ///
+ /// \returns the transformed initializer.
+ ExprResult TransformInitializer(Expr *Init, bool CXXDirectInit);
+
/// \brief Transform the given list of expressions.
///
/// This routine transforms a list of expressions by invoking
@@ -563,7 +572,7 @@ public:
/// scope index; can be negative
ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm,
int indexAdjustment,
- llvm::Optional<unsigned> NumExpansions,
+ Optional<unsigned> NumExpansions,
bool ExpectParameterPack);
QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL);
@@ -704,12 +713,8 @@ public:
/// By default, performs semantic analysis when building the function type.
/// Subclasses may override this routine to provide different behavior.
QualType RebuildFunctionProtoType(QualType T,
- QualType *ParamTypes,
- unsigned NumParamTypes,
- bool Variadic, bool HasTrailingReturn,
- unsigned Quals,
- RefQualifierKind RefQualifier,
- const FunctionType::ExtInfo &Info);
+ llvm::MutableArrayRef<QualType> ParamTypes,
+ const FunctionProtoType::ExtProtoInfo &EPI);
/// \brief Build a new unprototyped function type.
QualType RebuildFunctionNoProtoType(QualType ResultType);
@@ -941,7 +946,7 @@ public:
QualType RebuildPackExpansionType(QualType Pattern,
SourceRange PatternRange,
SourceLocation EllipsisLoc,
- llvm::Optional<unsigned> NumExpansions) {
+ Optional<unsigned> NumExpansions) {
return getSema().CheckPackExpansion(Pattern, PatternRange, EllipsisLoc,
NumExpansions);
}
@@ -2113,6 +2118,7 @@ public:
bool IsElidable,
MultiExprArg Args,
bool HadMultipleCandidates,
+ bool ListInitialization,
bool RequiresZeroInit,
CXXConstructExpr::ConstructionKind ConstructKind,
SourceRange ParenRange) {
@@ -2124,6 +2130,7 @@ public:
return getSema().BuildCXXConstructExpr(Loc, T, Constructor, IsElidable,
ConvertedArgs,
HadMultipleCandidates,
+ ListInitialization,
RequiresZeroInit, ConstructKind,
ParenRange);
}
@@ -2214,7 +2221,7 @@ public:
ExprResult RebuildSizeOfPackExpr(SourceLocation OperatorLoc, NamedDecl *Pack,
SourceLocation PackLoc,
SourceLocation RParenLoc,
- llvm::Optional<unsigned> Length) {
+ Optional<unsigned> Length) {
if (Length)
return new (SemaRef.Context) SizeOfPackExpr(SemaRef.Context.getSizeType(),
OperatorLoc, Pack, PackLoc,
@@ -2382,13 +2389,14 @@ public:
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
ExprResult RebuildObjCIsaExpr(Expr *BaseArg, SourceLocation IsaLoc,
+ SourceLocation OpLoc,
bool IsArrow) {
CXXScopeSpec SS;
ExprResult Base = getSema().Owned(BaseArg);
LookupResult R(getSema(), &getSema().Context.Idents.get("isa"), IsaLoc,
Sema::LookupMemberName);
ExprResult Result = getSema().LookupMemberExpr(R, Base, IsArrow,
- /*FIME:*/IsaLoc,
+ OpLoc,
SS, 0, false);
if (Result.isInvalid() || Base.isInvalid())
return ExprError();
@@ -2397,7 +2405,7 @@ public:
return Result;
return getSema().BuildMemberReferenceExpr(Base.get(), Base.get()->getType(),
- /*FIXME:*/IsaLoc, IsArrow,
+ OpLoc, IsArrow,
SS, SourceLocation(),
/*FirstQualifierInScope=*/0,
R,
@@ -2416,10 +2424,10 @@ public:
= SemaRef.Context.Idents.get("__builtin_shufflevector");
TranslationUnitDecl *TUDecl = SemaRef.Context.getTranslationUnitDecl();
DeclContext::lookup_result Lookup = TUDecl->lookup(DeclarationName(&Name));
- assert(Lookup.first != Lookup.second && "No __builtin_shufflevector?");
+ assert(!Lookup.empty() && "No __builtin_shufflevector?");
// Build a reference to the __builtin_shufflevector builtin
- FunctionDecl *Builtin = cast<FunctionDecl>(*Lookup.first);
+ FunctionDecl *Builtin = cast<FunctionDecl>(Lookup.front());
Expr *Callee = new (SemaRef.Context) DeclRefExpr(Builtin, false,
SemaRef.Context.BuiltinFnTy,
VK_RValue, BuiltinLoc);
@@ -2445,7 +2453,7 @@ public:
/// different behavior.
TemplateArgumentLoc RebuildPackExpansion(TemplateArgumentLoc Pattern,
SourceLocation EllipsisLoc,
- llvm::Optional<unsigned> NumExpansions) {
+ Optional<unsigned> NumExpansions) {
switch (Pattern.getArgument().getKind()) {
case TemplateArgument::Expression: {
ExprResult Result
@@ -2492,7 +2500,7 @@ public:
/// for an expression. Subclasses may override this routine to provide
/// different behavior.
ExprResult RebuildPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc,
- llvm::Optional<unsigned> NumExpansions) {
+ Optional<unsigned> NumExpansions) {
return getSema().CheckPackExpansion(Pattern, EllipsisLoc, NumExpansions);
}
@@ -2549,7 +2557,7 @@ StmtResult TreeTransform<Derived>::TransformStmt(Stmt *S) {
if (E.isInvalid())
return StmtError();
- return getSema().ActOnExprStmt(getSema().MakeFullExpr(E.take()));
+ return getSema().ActOnExprStmt(E);
}
}
@@ -2575,6 +2583,65 @@ ExprResult TreeTransform<Derived>::TransformExpr(Expr *E) {
}
template<typename Derived>
+ExprResult TreeTransform<Derived>::TransformInitializer(Expr *Init,
+ bool CXXDirectInit) {
+ // Initializers are instantiated like expressions, except that various outer
+ // layers are stripped.
+ if (!Init)
+ return SemaRef.Owned(Init);
+
+ if (ExprWithCleanups *ExprTemp = dyn_cast<ExprWithCleanups>(Init))
+ Init = ExprTemp->getSubExpr();
+
+ while (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(Init))
+ Init = Binder->getSubExpr();
+
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Init))
+ Init = ICE->getSubExprAsWritten();
+
+ // If this is not a direct-initializer, we only need to reconstruct
+ // InitListExprs. Other forms of copy-initialization will be a no-op if
+ // the initializer is already the right type.
+ CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(Init);
+ if (!CXXDirectInit && !(Construct && Construct->isListInitialization()))
+ return getDerived().TransformExpr(Init);
+
+ // Revert value-initialization back to empty parens.
+ if (CXXScalarValueInitExpr *VIE = dyn_cast<CXXScalarValueInitExpr>(Init)) {
+ SourceRange Parens = VIE->getSourceRange();
+ return getDerived().RebuildParenListExpr(Parens.getBegin(), MultiExprArg(),
+ Parens.getEnd());
+ }
+
+ // FIXME: We shouldn't build ImplicitValueInitExprs for direct-initialization.
+ if (isa<ImplicitValueInitExpr>(Init))
+ return getDerived().RebuildParenListExpr(SourceLocation(), MultiExprArg(),
+ SourceLocation());
+
+ // Revert initialization by constructor back to a parenthesized or braced list
+ // of expressions. Any other form of initializer can just be reused directly.
+ if (!Construct || isa<CXXTemporaryObjectExpr>(Construct))
+ return getDerived().TransformExpr(Init);
+
+ SmallVector<Expr*, 8> NewArgs;
+ bool ArgChanged = false;
+ if (getDerived().TransformExprs(Construct->getArgs(), Construct->getNumArgs(),
+ /*IsCall*/true, NewArgs, &ArgChanged))
+ return ExprError();
+
+ // If this was list initialization, revert to list form.
+ if (Construct->isListInitialization())
+ return getDerived().RebuildInitList(Construct->getLocStart(), NewArgs,
+ Construct->getLocEnd(),
+ Construct->getType());
+
+ // Build a ParenListExpr to represent anything else.
+ SourceRange Parens = Construct->getParenRange();
+ return getDerived().RebuildParenListExpr(Parens.getBegin(), NewArgs,
+ Parens.getEnd());
+}
+
+template<typename Derived>
bool TreeTransform<Derived>::TransformExprs(Expr **Inputs,
unsigned NumInputs,
bool IsCall,
@@ -2600,9 +2667,8 @@ bool TreeTransform<Derived>::TransformExprs(Expr **Inputs,
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
- llvm::Optional<unsigned> OrigNumExpansions
- = Expansion->getNumExpansions();
- llvm::Optional<unsigned> NumExpansions = OrigNumExpansions;
+ Optional<unsigned> OrigNumExpansions = Expansion->getNumExpansions();
+ Optional<unsigned> NumExpansions = OrigNumExpansions;
if (getDerived().TryExpandParameterPacks(Expansion->getEllipsisLoc(),
Pattern->getSourceRange(),
Unexpanded,
@@ -2656,7 +2722,9 @@ bool TreeTransform<Derived>::TransformExprs(Expr **Inputs,
continue;
}
- ExprResult Result = getDerived().TransformExpr(Inputs[I]);
+ ExprResult Result =
+ IsCall ? getDerived().TransformInitializer(Inputs[I], /*DirectInit*/false)
+ : getDerived().TransformExpr(Inputs[I]);
if (Result.isInvalid())
return true;
@@ -2732,7 +2800,7 @@ TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
return NestedNameSpecifierLoc();
if (TL.getType()->isDependentType() || TL.getType()->isRecordType() ||
- (SemaRef.getLangOpts().CPlusPlus0x &&
+ (SemaRef.getLangOpts().CPlusPlus11 &&
TL.getType()->isEnumeralType())) {
assert(!TL.getType().hasLocalQualifiers() &&
"Can't get cv-qualifiers here");
@@ -2745,8 +2813,8 @@ TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
}
// If the nested-name-specifier is an invalid type def, don't emit an
// error because a previous error should have already been emitted.
- TypedefTypeLoc* TTL = dyn_cast<TypedefTypeLoc>(&TL);
- if (!TTL || !TTL->getTypedefNameDecl()->isInvalidDecl()) {
+ TypedefTypeLoc TTL = TL.getAs<TypedefTypeLoc>();
+ if (!TTL || !TTL.getTypedefNameDecl()->isInvalidDecl()) {
SemaRef.Diag(TL.getBeginLoc(), diag::err_nested_name_spec_non_tag)
<< TL.getType() << SS.getRange();
}
@@ -3119,7 +3187,7 @@ bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First,
// We have a pack expansion, for which we will be substituting into
// the pattern.
SourceLocation Ellipsis;
- llvm::Optional<unsigned> OrigNumExpansions;
+ Optional<unsigned> OrigNumExpansions;
TemplateArgumentLoc Pattern
= In.getPackExpansionPattern(Ellipsis, OrigNumExpansions,
getSema().Context);
@@ -3132,7 +3200,7 @@ bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First,
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
- llvm::Optional<unsigned> NumExpansions = OrigNumExpansions;
+ Optional<unsigned> NumExpansions = OrigNumExpansions;
if (getDerived().TryExpandParameterPacks(Ellipsis,
Pattern.getSourceRange(),
Unexpanded,
@@ -3254,9 +3322,10 @@ QualType
TreeTransform<Derived>::TransformType(TypeLocBuilder &TLB, TypeLoc T) {
switch (T.getTypeLocClass()) {
#define ABSTRACT_TYPELOC(CLASS, PARENT)
-#define TYPELOC(CLASS, PARENT) \
- case TypeLoc::CLASS: \
- return getDerived().Transform##CLASS##Type(TLB, cast<CLASS##TypeLoc>(T));
+#define TYPELOC(CLASS, PARENT) \
+ case TypeLoc::CLASS: \
+ return getDerived().Transform##CLASS##Type(TLB, \
+ T.castAs<CLASS##TypeLoc>());
#include "clang/AST/TypeLocNodes.def"
}
@@ -3293,6 +3362,7 @@ TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB,
// Objective-C ARC:
// A lifetime qualifier applied to a substituted template parameter
// overrides the lifetime qualifier from the template argument.
+ const AutoType *AutoTy;
if (const SubstTemplateTypeParmType *SubstTypeParam
= dyn_cast<SubstTemplateTypeParmType>(Result)) {
QualType Replacement = SubstTypeParam->getReplacementType();
@@ -3305,6 +3375,15 @@ TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB,
SubstTypeParam->getReplacedParameter(),
Replacement);
TLB.TypeWasModifiedSafely(Result);
+ } else if ((AutoTy = dyn_cast<AutoType>(Result)) && AutoTy->isDeduced()) {
+ // 'auto' types behave the same way as template parameters.
+ QualType Deduced = AutoTy->getDeducedType();
+ Qualifiers Qs = Deduced.getQualifiers();
+ Qs.removeObjCLifetime();
+ Deduced = SemaRef.Context.getQualifiedType(Deduced.getUnqualifiedType(),
+ Qs);
+ Result = SemaRef.Context.getAutoType(Deduced);
+ TLB.TypeWasModifiedSafely(Result);
} else {
// Otherwise, complain about the addition of a qualifier to an
// already-qualified type.
@@ -3318,7 +3397,9 @@ TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB,
}
if (!Quals.empty()) {
Result = SemaRef.BuildQualifiedType(Result, T.getBeginLoc(), Quals);
- TLB.push<QualifiedTypeLoc>(Result);
+ // BuildQualifiedType might not add qualifiers if they are invalid.
+ if (Result.hasLocalQualifiers())
+ TLB.push<QualifiedTypeLoc>(Result);
// No location information to preserve.
}
@@ -3339,8 +3420,8 @@ TreeTransform<Derived>::TransformTypeInObjectScope(TypeLoc TL,
QualType Result;
if (isa<TemplateSpecializationType>(T)) {
- TemplateSpecializationTypeLoc SpecTL
- = cast<TemplateSpecializationTypeLoc>(TL);
+ TemplateSpecializationTypeLoc SpecTL =
+ TL.castAs<TemplateSpecializationTypeLoc>();
TemplateName Template =
getDerived().TransformTemplateName(SS,
@@ -3353,8 +3434,8 @@ TreeTransform<Derived>::TransformTypeInObjectScope(TypeLoc TL,
Result = getDerived().TransformTemplateSpecializationType(TLB, SpecTL,
Template);
} else if (isa<DependentTemplateSpecializationType>(T)) {
- DependentTemplateSpecializationTypeLoc SpecTL
- = cast<DependentTemplateSpecializationTypeLoc>(TL);
+ DependentTemplateSpecializationTypeLoc SpecTL =
+ TL.castAs<DependentTemplateSpecializationTypeLoc>();
TemplateName Template
= getDerived().RebuildTemplateName(SS,
@@ -3396,8 +3477,8 @@ TreeTransform<Derived>::TransformTypeInObjectScope(TypeSourceInfo *TSInfo,
TypeLoc TL = TSInfo->getTypeLoc();
if (isa<TemplateSpecializationType>(T)) {
- TemplateSpecializationTypeLoc SpecTL
- = cast<TemplateSpecializationTypeLoc>(TL);
+ TemplateSpecializationTypeLoc SpecTL =
+ TL.castAs<TemplateSpecializationTypeLoc>();
TemplateName Template
= getDerived().TransformTemplateName(SS,
@@ -3410,8 +3491,8 @@ TreeTransform<Derived>::TransformTypeInObjectScope(TypeSourceInfo *TSInfo,
Result = getDerived().TransformTemplateSpecializationType(TLB, SpecTL,
Template);
} else if (isa<DependentTemplateSpecializationType>(T)) {
- DependentTemplateSpecializationTypeLoc SpecTL
- = cast<DependentTemplateSpecializationTypeLoc>(TL);
+ DependentTemplateSpecializationTypeLoc SpecTL =
+ TL.castAs<DependentTemplateSpecializationTypeLoc>();
TemplateName Template
= getDerived().RebuildTemplateName(SS,
@@ -3864,12 +3945,10 @@ QualType TreeTransform<Derived>::TransformExtVectorType(TypeLocBuilder &TLB,
return Result;
}
-template<typename Derived>
-ParmVarDecl *
-TreeTransform<Derived>::TransformFunctionTypeParam(ParmVarDecl *OldParm,
- int indexAdjustment,
- llvm::Optional<unsigned> NumExpansions,
- bool ExpectParameterPack) {
+template <typename Derived>
+ParmVarDecl *TreeTransform<Derived>::TransformFunctionTypeParam(
+ ParmVarDecl *OldParm, int indexAdjustment, Optional<unsigned> NumExpansions,
+ bool ExpectParameterPack) {
TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
TypeSourceInfo *NewDI = 0;
@@ -3877,7 +3956,7 @@ TreeTransform<Derived>::TransformFunctionTypeParam(ParmVarDecl *OldParm,
// If we're substituting into a pack expansion type and we know the
// length we want to expand to, just substitute for the pattern.
TypeLoc OldTL = OldDI->getTypeLoc();
- PackExpansionTypeLoc OldExpansionTL = cast<PackExpansionTypeLoc>(OldTL);
+ PackExpansionTypeLoc OldExpansionTL = OldTL.castAs<PackExpansionTypeLoc>();
TypeLocBuilder TLB;
TypeLoc NewTL = OldDI->getTypeLoc();
@@ -3915,7 +3994,6 @@ TreeTransform<Derived>::TransformFunctionTypeParam(ParmVarDecl *OldParm,
NewDI->getType(),
NewDI,
OldParm->getStorageClass(),
- OldParm->getStorageClassAsWritten(),
/* DefArg */ NULL);
newParm->setScopeInfo(OldParm->getFunctionScopeDepth(),
OldParm->getFunctionScopeIndex() + indexAdjustment);
@@ -3935,7 +4013,7 @@ bool TreeTransform<Derived>::
if (ParmVarDecl *OldParm = Params[i]) {
assert(OldParm->getFunctionScopeIndex() == i);
- llvm::Optional<unsigned> NumExpansions;
+ Optional<unsigned> NumExpansions;
ParmVarDecl *NewParm = 0;
if (OldParm->isParameterPack()) {
// We have a function parameter pack that may need to be expanded.
@@ -3943,7 +4021,7 @@ bool TreeTransform<Derived>::
// Find the parameter packs that could be expanded.
TypeLoc TL = OldParm->getTypeSourceInfo()->getTypeLoc();
- PackExpansionTypeLoc ExpansionTL = cast<PackExpansionTypeLoc>(TL);
+ PackExpansionTypeLoc ExpansionTL = TL.castAs<PackExpansionTypeLoc>();
TypeLoc Pattern = ExpansionTL.getPatternLoc();
SemaRef.collectUnexpandedParameterPacks(Pattern, Unexpanded);
assert(Unexpanded.size() > 0 && "Could not find parameter packs!");
@@ -3951,8 +4029,8 @@ bool TreeTransform<Derived>::
// Determine whether we should expand the parameter packs.
bool ShouldExpand = false;
bool RetainExpansion = false;
- llvm::Optional<unsigned> OrigNumExpansions
- = ExpansionTL.getTypePtr()->getNumExpansions();
+ Optional<unsigned> OrigNumExpansions =
+ ExpansionTL.getTypePtr()->getNumExpansions();
NumExpansions = OrigNumExpansions;
if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(),
Pattern.getSourceRange(),
@@ -4017,10 +4095,8 @@ bool TreeTransform<Derived>::
NumExpansions,
/*ExpectParameterPack=*/true);
} else {
- NewParm = getDerived().TransformFunctionTypeParam(OldParm,
- indexAdjustment,
- llvm::Optional<unsigned>(),
- /*ExpectParameterPack=*/false);
+ NewParm = getDerived().TransformFunctionTypeParam(
+ OldParm, indexAdjustment, None, /*ExpectParameterPack=*/ false);
}
if (!NewParm)
@@ -4036,7 +4112,7 @@ bool TreeTransform<Derived>::
// declaration for this parameter.
QualType OldType = ParamTypes[i];
bool IsPackExpansion = false;
- llvm::Optional<unsigned> NumExpansions;
+ Optional<unsigned> NumExpansions;
QualType NewType;
if (const PackExpansionType *Expansion
= dyn_cast<PackExpansionType>(OldType)) {
@@ -4188,14 +4264,8 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
ResultType != T->getResultType() ||
T->getNumArgs() != ParamTypes.size() ||
!std::equal(T->arg_type_begin(), T->arg_type_end(), ParamTypes.begin())) {
- Result = getDerived().RebuildFunctionProtoType(ResultType,
- ParamTypes.data(),
- ParamTypes.size(),
- T->isVariadic(),
- T->hasTrailingReturn(),
- T->getTypeQuals(),
- T->getRefQualifier(),
- T->getExtInfo());
+ Result = getDerived().RebuildFunctionProtoType(ResultType, ParamTypes,
+ T->getExtProtoInfo());
if (Result.isNull())
return QualType();
}
@@ -4561,7 +4631,6 @@ QualType TreeTransform<Derived>::TransformAtomicType(TypeLocBuilder &TLB,
return Result;
}
-namespace {
/// \brief Simple iterator that traverses the template arguments in a
/// container that provides a \c getArgLoc() member function.
///
@@ -4625,7 +4694,6 @@ namespace {
return !(X == Y);
}
};
-}
template <typename Derived>
@@ -5379,7 +5447,7 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) {
if (Inc.isInvalid())
return StmtError();
- Sema::FullExprArg FullInc(getSema().MakeFullExpr(Inc.get()));
+ Sema::FullExprArg FullInc(getSema().MakeFullDiscardedValueExpr(Inc.get()));
if (S->getInc() && !FullInc.get())
return StmtError();
@@ -6946,17 +7014,13 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) {
Type == E->getTypeInfoAsWritten() &&
SubExpr.get() == E->getSubExpr())
return SemaRef.Owned(E);
-
- // FIXME: Poor source location information here.
- SourceLocation FakeLAngleLoc
- = SemaRef.PP.getLocForEndOfToken(E->getOperatorLoc());
- SourceLocation FakeRAngleLoc = E->getSubExpr()->getSourceRange().getBegin();
return getDerived().RebuildCXXNamedCastExpr(E->getOperatorLoc(),
E->getStmtClass(),
- FakeLAngleLoc,
+ E->getAngleBrackets().getBegin(),
Type,
- FakeRAngleLoc,
- FakeRAngleLoc,
+ E->getAngleBrackets().getEnd(),
+ // FIXME. this should be '(' location
+ E->getAngleBrackets().getEnd(),
SubExpr.get(),
E->getRParenLoc());
}
@@ -7105,9 +7169,14 @@ TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) {
QualType T;
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC))
T = MD->getThisType(getSema().Context);
- else
+ else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC)) {
T = getSema().Context.getPointerType(
- getSema().Context.getRecordType(cast<CXXRecordDecl>(DC)));
+ getSema().Context.getRecordType(Record));
+ } else {
+ assert(SemaRef.Context.getDiagnostics().hasErrorOccurred() &&
+ "this in the wrong scope?");
+ return ExprError();
+ }
if (!getDerived().AlwaysRebuild() && T == E->getType()) {
// Make sure that we capture 'this'.
@@ -7387,7 +7456,9 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
TypeSourceInfo *ScopeTypeInfo = 0;
if (E->getScopeTypeInfo()) {
- ScopeTypeInfo = getDerived().TransformType(E->getScopeTypeInfo());
+ CXXScopeSpec EmptySS;
+ ScopeTypeInfo = getDerived().TransformTypeInObjectScope(
+ E->getScopeTypeInfo(), ObjectType, 0, EmptySS);
if (!ScopeTypeInfo)
return ExprError();
}
@@ -7524,11 +7595,11 @@ template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) {
bool ArgChanged = false;
- llvm::SmallVector<TypeSourceInfo *, 4> Args;
+ SmallVector<TypeSourceInfo *, 4> Args;
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) {
TypeSourceInfo *From = E->getArg(I);
TypeLoc FromTL = From->getTypeLoc();
- if (!isa<PackExpansionTypeLoc>(FromTL)) {
+ if (!FromTL.getAs<PackExpansionTypeLoc>()) {
TypeLocBuilder TLB;
TLB.reserve(FromTL.getFullDataSize());
QualType To = getDerived().TransformType(TLB, FromTL);
@@ -7547,7 +7618,7 @@ TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) {
ArgChanged = true;
// We have a pack expansion. Instantiate it.
- PackExpansionTypeLoc ExpansionTL = cast<PackExpansionTypeLoc>(FromTL);
+ PackExpansionTypeLoc ExpansionTL = FromTL.castAs<PackExpansionTypeLoc>();
TypeLoc PatternTL = ExpansionTL.getPatternLoc();
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
SemaRef.collectUnexpandedParameterPacks(PatternTL, Unexpanded);
@@ -7556,9 +7627,9 @@ TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) {
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
- llvm::Optional<unsigned> OrigNumExpansions
- = ExpansionTL.getTypePtr()->getNumExpansions();
- llvm::Optional<unsigned> NumExpansions = OrigNumExpansions;
+ Optional<unsigned> OrigNumExpansions =
+ ExpansionTL.getTypePtr()->getNumExpansions();
+ Optional<unsigned> NumExpansions = OrigNumExpansions;
if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(),
PatternTL.getSourceRange(),
Unexpanded,
@@ -7747,10 +7818,13 @@ TreeTransform<Derived>::TransformDependentScopeDeclRefExpr(
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) {
- // CXXConstructExprs are always implicit, so when we have a
- // 1-argument construction we just transform that argument.
- if (E->getNumArgs() == 1 ||
- (E->getNumArgs() > 1 && getDerived().DropCallArgument(E->getArg(1))))
+ // CXXConstructExprs other than for list-initialization and
+ // CXXTemporaryObjectExpr are always implicit, so when we have
+ // a 1-argument construction we just transform that argument.
+ if ((E->getNumArgs() == 1 ||
+ (E->getNumArgs() > 1 && getDerived().DropCallArgument(E->getArg(1)))) &&
+ (!getDerived().DropCallArgument(E->getArg(0))) &&
+ !E->isListInitialization())
return getDerived().TransformExpr(E->getArg(0));
TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName());
@@ -7786,6 +7860,7 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) {
Constructor, E->isElidable(),
Args,
E->hadMultipleCandidates(),
+ E->isListInitialization(),
E->requiresZeroInitialization(),
E->getConstructionKind(),
E->getParenRange());
@@ -7843,6 +7918,7 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
return SemaRef.MaybeBindToTemporary(E);
}
+ // FIXME: Pass in E->isListInitialization().
return getDerived().RebuildCXXTemporaryObjectExpr(T,
/*FIXME:*/T->getTypeLoc().getEndLoc(),
Args,
@@ -7867,8 +7943,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
getDerived().transformedLocalDecl(E->getLambdaClass(), Class);
// Transform lambda parameters.
- llvm::SmallVector<QualType, 4> ParamTypes;
- llvm::SmallVector<ParmVarDecl *, 4> Params;
+ SmallVector<QualType, 4> ParamTypes;
+ SmallVector<ParmVarDecl *, 4> Params;
if (getDerived().TransformFunctionTypeParams(E->getLocStart(),
E->getCallOperator()->param_begin(),
E->getCallOperator()->param_size(),
@@ -7931,7 +8007,7 @@ TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E,
UnexpandedParameterPack Unexpanded(C->getCapturedVar(), C->getLocation());
bool ShouldExpand = false;
bool RetainExpansion = false;
- llvm::Optional<unsigned> NumExpansions;
+ Optional<unsigned> NumExpansions;
if (getDerived().TryExpandParameterPacks(C->getEllipsisLoc(),
C->getLocation(),
Unexpanded,
@@ -8274,7 +8350,7 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
UnexpandedParameterPack Unexpanded(E->getPack(), E->getPackLoc());
bool ShouldExpand = false;
bool RetainExpansion = false;
- llvm::Optional<unsigned> NumExpansions;
+ Optional<unsigned> NumExpansions;
if (getDerived().TryExpandParameterPacks(E->getOperatorLoc(), E->getPackLoc(),
Unexpanded,
ShouldExpand, RetainExpansion,
@@ -8360,7 +8436,7 @@ template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformObjCArrayLiteral(ObjCArrayLiteral *E) {
// Transform each of the elements.
- llvm::SmallVector<Expr *, 8> Elements;
+ SmallVector<Expr *, 8> Elements;
bool ArgChanged = false;
if (getDerived().TransformExprs(E->getElements(), E->getNumElements(),
/*IsCall=*/false, Elements, &ArgChanged))
@@ -8379,7 +8455,7 @@ ExprResult
TreeTransform<Derived>::TransformObjCDictionaryLiteral(
ObjCDictionaryLiteral *E) {
// Transform each of the elements.
- llvm::SmallVector<ObjCDictionaryElement, 8> Elements;
+ SmallVector<ObjCDictionaryElement, 8> Elements;
bool ArgChanged = false;
for (unsigned I = 0, N = E->getNumElements(); I != N; ++I) {
ObjCDictionaryElement OrigElement = E->getKeyValueElement(I);
@@ -8395,8 +8471,8 @@ TreeTransform<Derived>::TransformObjCDictionaryLiteral(
// and should be expanded.
bool Expand = true;
bool RetainExpansion = false;
- llvm::Optional<unsigned> OrigNumExpansions = OrigElement.NumExpansions;
- llvm::Optional<unsigned> NumExpansions = OrigNumExpansions;
+ Optional<unsigned> OrigNumExpansions = OrigElement.NumExpansions;
+ Optional<unsigned> NumExpansions = OrigNumExpansions;
SourceRange PatternRange(OrigElement.Key->getLocStart(),
OrigElement.Value->getLocEnd());
if (getDerived().TryExpandParameterPacks(OrigElement.EllipsisLoc,
@@ -8483,7 +8559,7 @@ TreeTransform<Derived>::TransformObjCDictionaryLiteral(
ArgChanged = true;
ObjCDictionaryElement Element = {
- Key.get(), Value.get(), SourceLocation(), llvm::Optional<unsigned>()
+ Key.get(), Value.get(), SourceLocation(), None
};
Elements.push_back(Element);
}
@@ -8712,6 +8788,7 @@ TreeTransform<Derived>::TransformObjCIsaExpr(ObjCIsaExpr *E) {
return SemaRef.Owned(E);
return getDerived().RebuildObjCIsaExpr(Base.get(), E->getIsaMemberLoc(),
+ E->getOpLoc(),
E->isArrow());
}
@@ -8758,7 +8835,7 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
return ExprError();
}
- const FunctionType *exprFunctionType = E->getFunctionType();
+ const FunctionProtoType *exprFunctionType = E->getFunctionType();
QualType exprResultType =
getDerived().TransformType(exprFunctionType->getResultType());
@@ -8771,13 +8848,9 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
return ExprError();
}
- QualType functionType = getDerived().RebuildFunctionProtoType(
- exprResultType,
- paramTypes.data(),
- paramTypes.size(),
- oldBlock->isVariadic(),
- false, 0, RQ_None,
- exprFunctionType->getExtInfo());
+ QualType functionType =
+ getDerived().RebuildFunctionProtoType(exprResultType, paramTypes,
+ exprFunctionType->getExtProtoInfo());
blockScope->FunctionType = functionType;
// Set the parameters on the block decl.
@@ -8993,19 +9066,14 @@ TreeTransform<Derived>::RebuildDependentSizedExtVectorType(QualType ElementType,
}
template<typename Derived>
-QualType TreeTransform<Derived>::RebuildFunctionProtoType(QualType T,
- QualType *ParamTypes,
- unsigned NumParamTypes,
- bool Variadic,
- bool HasTrailingReturn,
- unsigned Quals,
- RefQualifierKind RefQualifier,
- const FunctionType::ExtInfo &Info) {
- return SemaRef.BuildFunctionType(T, ParamTypes, NumParamTypes, Variadic,
- HasTrailingReturn, Quals, RefQualifier,
+QualType TreeTransform<Derived>::RebuildFunctionProtoType(
+ QualType T,
+ llvm::MutableArrayRef<QualType> ParamTypes,
+ const FunctionProtoType::ExtProtoInfo &EPI) {
+ return SemaRef.BuildFunctionType(T, ParamTypes,
getDerived().getBaseLocation(),
getDerived().getBaseEntity(),
- Info);
+ EPI);
}
template<typename Derived>
diff --git a/lib/Sema/TypeLocBuilder.h b/lib/Sema/TypeLocBuilder.h
index 7a5e43e..f36ec9f 100644
--- a/lib/Sema/TypeLocBuilder.h
+++ b/lib/Sema/TypeLocBuilder.h
@@ -15,8 +15,8 @@
#ifndef LLVM_CLANG_SEMA_TYPELOCBUILDER_H
#define LLVM_CLANG_SEMA_TYPELOCBUILDER_H
-#include "clang/AST/TypeLoc.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/TypeLoc.h"
namespace clang {
@@ -75,7 +75,7 @@ class TypeLocBuilder {
/// previously retrieved from this builder.
TypeSpecTypeLoc pushTypeSpec(QualType T) {
size_t LocalSize = TypeSpecTypeLoc::LocalDataSize;
- return cast<TypeSpecTypeLoc>(pushImpl(T, LocalSize));
+ return pushImpl(T, LocalSize).castAs<TypeSpecTypeLoc>();
}
/// Resets this builder to the newly-initialized state.
@@ -97,8 +97,8 @@ class TypeLocBuilder {
/// Pushes space for a new TypeLoc of the given type. Invalidates
/// any TypeLocs previously retrieved from this builder.
template <class TyLocType> TyLocType push(QualType T) {
- size_t LocalSize = cast<TyLocType>(TypeLoc(T, 0)).getLocalDataSize();
- return cast<TyLocType>(pushImpl(T, LocalSize));
+ size_t LocalSize = TypeLoc(T, 0).castAs<TyLocType>().getLocalDataSize();
+ return pushImpl(T, LocalSize).castAs<TyLocType>();
}
/// Creates a TypeSourceInfo for the given type.
diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp
index 0ec03cf..7bbe6b1 100644
--- a/lib/Serialization/ASTCommon.cpp
+++ b/lib/Serialization/ASTCommon.cpp
@@ -12,8 +12,9 @@
//===----------------------------------------------------------------------===//
#include "ASTCommon.h"
-#include "clang/Serialization/ASTDeserializationListener.h"
+#include "clang/AST/DeclObjC.h"
#include "clang/Basic/IdentifierTable.h"
+#include "clang/Serialization/ASTDeserializationListener.h"
#include "llvm/ADT/StringExtras.h"
using namespace clang;
@@ -60,6 +61,14 @@ 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::OCLImage1d: ID = PREDEF_TYPE_IMAGE1D_ID; break;
+ case BuiltinType::OCLImage1dArray: ID = PREDEF_TYPE_IMAGE1D_ARR_ID; break;
+ case BuiltinType::OCLImage1dBuffer: ID = PREDEF_TYPE_IMAGE1D_BUFF_ID; break;
+ case BuiltinType::OCLImage2d: ID = PREDEF_TYPE_IMAGE2D_ID; break;
+ case BuiltinType::OCLImage2dArray: ID = PREDEF_TYPE_IMAGE2D_ARR_ID; break;
+ case BuiltinType::OCLImage3d: ID = PREDEF_TYPE_IMAGE3D_ID; break;
+ case BuiltinType::OCLSampler: ID = PREDEF_TYPE_SAMPLER_ID; break;
+ case BuiltinType::OCLEvent: ID = PREDEF_TYPE_EVENT_ID; break;
case BuiltinType::BuiltinFn:
ID = PREDEF_TYPE_BUILTIN_FN; break;
@@ -78,3 +87,126 @@ unsigned serialization::ComputeHash(Selector Sel) {
R = llvm::HashString(II->getName(), R);
return R;
}
+
+const DeclContext *
+serialization::getDefinitiveDeclContext(const DeclContext *DC) {
+ switch (DC->getDeclKind()) {
+ // These entities may have multiple definitions.
+ case Decl::TranslationUnit:
+ case Decl::Namespace:
+ case Decl::LinkageSpec:
+ return 0;
+
+ // C/C++ tag types can only be defined in one place.
+ case Decl::Enum:
+ case Decl::Record:
+ if (const TagDecl *Def = cast<TagDecl>(DC)->getDefinition())
+ return Def;
+ return 0;
+
+ // FIXME: These can be defined in one place... except special member
+ // functions and out-of-line definitions.
+ case Decl::CXXRecord:
+ case Decl::ClassTemplateSpecialization:
+ case Decl::ClassTemplatePartialSpecialization:
+ return 0;
+
+ // Each function, method, and block declaration is its own DeclContext.
+ case Decl::Function:
+ case Decl::CXXMethod:
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor:
+ case Decl::CXXConversion:
+ case Decl::ObjCMethod:
+ case Decl::Block:
+ // Objective C categories, category implementations, and class
+ // implementations can only be defined in one place.
+ case Decl::ObjCCategory:
+ case Decl::ObjCCategoryImpl:
+ case Decl::ObjCImplementation:
+ return DC;
+
+ case Decl::ObjCProtocol:
+ if (const ObjCProtocolDecl *Def
+ = cast<ObjCProtocolDecl>(DC)->getDefinition())
+ return Def;
+ return 0;
+
+ // FIXME: These are defined in one place, but properties in class extensions
+ // end up being back-patched into the main interface. See
+ // Sema::HandlePropertyInClassExtension for the offending code.
+ case Decl::ObjCInterface:
+ return 0;
+
+ default:
+ llvm_unreachable("Unhandled DeclContext in AST reader");
+ }
+
+ llvm_unreachable("Unhandled decl kind");
+}
+
+bool serialization::isRedeclarableDeclKind(unsigned Kind) {
+ switch (static_cast<Decl::Kind>(Kind)) {
+ case Decl::TranslationUnit: // Special case of a "merged" declaration.
+ case Decl::Namespace:
+ case Decl::NamespaceAlias: // FIXME: Not yet redeclarable, but will be.
+ case Decl::Typedef:
+ case Decl::TypeAlias:
+ case Decl::Enum:
+ case Decl::Record:
+ case Decl::CXXRecord:
+ case Decl::ClassTemplateSpecialization:
+ case Decl::ClassTemplatePartialSpecialization:
+ case Decl::Function:
+ case Decl::CXXMethod:
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor:
+ case Decl::CXXConversion:
+ case Decl::Var:
+ case Decl::FunctionTemplate:
+ case Decl::ClassTemplate:
+ case Decl::TypeAliasTemplate:
+ case Decl::ObjCProtocol:
+ case Decl::ObjCInterface:
+ case Decl::Empty:
+ return true;
+
+ // Never redeclarable.
+ case Decl::UsingDirective:
+ case Decl::Label:
+ case Decl::UnresolvedUsingTypename:
+ case Decl::TemplateTypeParm:
+ case Decl::EnumConstant:
+ case Decl::UnresolvedUsingValue:
+ case Decl::IndirectField:
+ case Decl::Field:
+ case Decl::ObjCIvar:
+ case Decl::ObjCAtDefsField:
+ case Decl::ImplicitParam:
+ case Decl::ParmVar:
+ case Decl::NonTypeTemplateParm:
+ case Decl::TemplateTemplateParm:
+ case Decl::Using:
+ case Decl::UsingShadow:
+ case Decl::ObjCMethod:
+ case Decl::ObjCCategory:
+ case Decl::ObjCCategoryImpl:
+ case Decl::ObjCImplementation:
+ case Decl::ObjCProperty:
+ case Decl::ObjCCompatibleAlias:
+ case Decl::LinkageSpec:
+ case Decl::ObjCPropertyImpl:
+ case Decl::FileScopeAsm:
+ case Decl::AccessSpec:
+ case Decl::Friend:
+ case Decl::FriendTemplate:
+ case Decl::StaticAssert:
+ case Decl::Block:
+ case Decl::ClassScopeFunctionSpecialization:
+ case Decl::Import:
+ case Decl::OMPThreadPrivate:
+ return false;
+ }
+
+ llvm_unreachable("Unhandled declaration kind");
+}
diff --git a/lib/Serialization/ASTCommon.h b/lib/Serialization/ASTCommon.h
index eacb39d..76ef904 100644
--- a/lib/Serialization/ASTCommon.h
+++ b/lib/Serialization/ASTCommon.h
@@ -14,8 +14,8 @@
#ifndef LLVM_CLANG_SERIALIZATION_LIB_AST_COMMON_H
#define LLVM_CLANG_SERIALIZATION_LIB_AST_COMMON_H
-#include "clang/Serialization/ASTBitCodes.h"
#include "clang/AST/ASTContext.h"
+#include "clang/Serialization/ASTBitCodes.h"
namespace clang {
@@ -58,6 +58,21 @@ TypeID MakeTypeID(ASTContext &Context, QualType T, IdxForTypeTy IdxForType) {
unsigned ComputeHash(Selector Sel);
+/// \brief Retrieve the "definitive" declaration that provides all of the
+/// visible entries for the given declaration context, if there is one.
+///
+/// The "definitive" declaration is the only place where we need to look to
+/// find information about the declarations within the given declaration
+/// context. For example, C++ and Objective-C classes, C structs/unions, and
+/// Objective-C protocols, categories, and extensions are all defined in a
+/// single place in the source code, so they have definitive declarations
+/// associated with them. C++ namespaces, on the other hand, can have
+/// multiple definitions.
+const DeclContext *getDefinitiveDeclContext(const DeclContext *DC);
+
+/// \brief Determine whether the given declaration kind is redeclarable.
+bool isRedeclarableDeclKind(unsigned Kind);
+
} // namespace serialization
} // namespace clang
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index deba302..d984415 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -1,4 +1,4 @@
-//===--- ASTReader.cpp - AST File Reader ------------------------*- C++ -*-===//
+//===--- ASTReader.cpp - AST File Reader ----------------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -12,13 +12,8 @@
//===----------------------------------------------------------------------===//
#include "clang/Serialization/ASTReader.h"
-#include "clang/Serialization/ASTDeserializationListener.h"
-#include "clang/Serialization/ModuleManager.h"
-#include "clang/Serialization/SerializationDiagnostic.h"
#include "ASTCommon.h"
#include "ASTReaderInternals.h"
-#include "clang/Sema/Sema.h"
-#include "clang/Sema/Scope.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
@@ -27,37 +22,42 @@
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLocVisitor.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/Lex/HeaderSearchOptions.h"
-#include "clang/Basic/OnDiskHashTable.h"
+#include "clang/Basic/FileManager.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 "clang/Lex/HeaderSearch.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/Sema/Scope.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Serialization/ASTDeserializationListener.h"
+#include "clang/Serialization/GlobalModuleIndex.h"
+#include "clang/Serialization/ModuleManager.h"
+#include "clang/Serialization/SerializationDiagnostic.h"
+#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Bitcode/BitstreamReader.h"
-#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/system_error.h"
#include <algorithm>
-#include <iterator>
#include <cstdio>
-#include <sys/stat.h>
+#include <iterator>
using namespace clang;
using namespace clang::serialization;
using namespace clang::serialization::reader;
+using llvm::BitstreamCursor;
//===----------------------------------------------------------------------===//
// PCH validator implementation
@@ -109,6 +109,14 @@ static bool checkLanguageOptions(const LangOptions &LangOpts,
return true;
}
+ if (ExistingLangOpts.CommentOpts.BlockCommandNames !=
+ LangOpts.CommentOpts.BlockCommandNames) {
+ if (Diags)
+ Diags->Report(diag::err_pch_langopt_value_mismatch)
+ << "block command names";
+ return true;
+ }
+
return false;
}
@@ -440,22 +448,32 @@ ASTSelectorLookupTrait::ReadData(Selector, const unsigned char* d,
return Result;
}
-unsigned ASTIdentifierLookupTrait::ComputeHash(const internal_key_type& a) {
- return llvm::HashString(StringRef(a.first, a.second));
+unsigned ASTIdentifierLookupTraitBase::ComputeHash(const internal_key_type& a) {
+ return llvm::HashString(a);
}
std::pair<unsigned, unsigned>
-ASTIdentifierLookupTrait::ReadKeyDataLength(const unsigned char*& d) {
+ASTIdentifierLookupTraitBase::ReadKeyDataLength(const unsigned char*& d) {
using namespace clang::io;
unsigned DataLen = ReadUnalignedLE16(d);
unsigned KeyLen = ReadUnalignedLE16(d);
return std::make_pair(KeyLen, DataLen);
}
-std::pair<const char*, unsigned>
-ASTIdentifierLookupTrait::ReadKey(const unsigned char* d, unsigned n) {
+ASTIdentifierLookupTraitBase::internal_key_type
+ASTIdentifierLookupTraitBase::ReadKey(const unsigned char* d, unsigned n) {
assert(n >= 2 && d[n-1] == '\0');
- return std::make_pair((const char*) d, n-1);
+ return StringRef((const char*) d, n-1);
+}
+
+/// \brief Whether the given identifier is "interesting".
+static bool isInterestingIdentifier(IdentifierInfo &II) {
+ return II.isPoisoned() ||
+ II.isExtensionToken() ||
+ II.getObjCOrBuiltinID() ||
+ II.hasRevertedTokenIDToIdentifier() ||
+ II.hadMacroDefinition() ||
+ II.getFETokenInfo<void>();
}
IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
@@ -474,12 +492,17 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
// and associate it with the persistent ID.
IdentifierInfo *II = KnownII;
if (!II) {
- II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second));
+ II = &Reader.getIdentifierTable().getOwn(k);
KnownII = II;
}
Reader.SetIdentifierInfo(ID, II);
- II->setIsFromAST();
- Reader.markIdentifierUpToDate(II);
+ if (!II->isFromAST()) {
+ bool WasInteresting = isInterestingIdentifier(*II);
+ II->setIsFromAST();
+ if (WasInteresting)
+ II->setChangedSinceDeserialization();
+ }
+ Reader.markIdentifierUpToDate(II);
return II;
}
@@ -493,6 +516,8 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
Bits >>= 1;
bool ExtensionToken = Bits & 0x01;
Bits >>= 1;
+ bool hasSubmoduleMacros = Bits & 0x01;
+ Bits >>= 1;
bool hadMacroDefinition = Bits & 0x01;
Bits >>= 1;
@@ -503,15 +528,20 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
// the new IdentifierInfo.
IdentifierInfo *II = KnownII;
if (!II) {
- II = &Reader.getIdentifierTable().getOwn(StringRef(k.first, k.second));
+ II = &Reader.getIdentifierTable().getOwn(StringRef(k));
KnownII = II;
}
Reader.markIdentifierUpToDate(II);
- II->setIsFromAST();
+ if (!II->isFromAST()) {
+ bool WasInteresting = isInterestingIdentifier(*II);
+ II->setIsFromAST();
+ if (WasInteresting)
+ II->setChangedSinceDeserialization();
+ }
// Set or check the various bits in the IdentifierInfo structure.
// Token IDs are read-only.
- if (HasRevertedTokenIDToIdentifier)
+ if (HasRevertedTokenIDToIdentifier && II->getTokenID() != tok::identifier)
II->RevertTokenIDToIdentifier();
II->setObjCOrBuiltinID(ObjCOrBuiltinID);
assert(II->isExtensionToken() == ExtensionToken &&
@@ -526,13 +556,26 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
// If this identifier is a macro, deserialize the macro
// definition.
if (hadMacroDefinition) {
- SmallVector<MacroID, 4> MacroIDs;
- while (uint32_t LocalID = ReadUnalignedLE32(d)) {
- MacroIDs.push_back(Reader.getGlobalMacroID(F, LocalID));
+ uint32_t MacroDirectivesOffset = ReadUnalignedLE32(d);
+ DataLen -= 4;
+ SmallVector<uint32_t, 8> LocalMacroIDs;
+ if (hasSubmoduleMacros) {
+ while (uint32_t LocalMacroID = ReadUnalignedLE32(d)) {
+ DataLen -= 4;
+ LocalMacroIDs.push_back(LocalMacroID);
+ }
DataLen -= 4;
}
- DataLen -= 4;
- Reader.setIdentifierIsMacro(II, MacroIDs);
+
+ if (F.Kind == MK_Module) {
+ for (SmallVectorImpl<uint32_t>::iterator
+ I = LocalMacroIDs.begin(), E = LocalMacroIDs.end(); I != E; ++I) {
+ MacroID MacID = Reader.getGlobalMacroID(F, *I);
+ Reader.addPendingMacroFromModule(II, &F, MacID, F.DirectImportLoc);
+ }
+ } else {
+ Reader.addPendingMacroFromPCH(II, &F, MacroDirectivesOffset);
+ }
}
Reader.SetIdentifierInfo(ID, II);
@@ -656,12 +699,13 @@ ASTDeclContextNameLookupTrait::ReadData(internal_key_type,
unsigned DataLen) {
using namespace clang::io;
unsigned NumDecls = ReadUnalignedLE16(d);
- LE32DeclID *Start = (LE32DeclID *)d;
+ LE32DeclID *Start = reinterpret_cast<LE32DeclID *>(
+ const_cast<unsigned char *>(d));
return std::make_pair(Start, Start + NumDecls);
}
bool ASTReader::ReadDeclContextStorage(ModuleFile &M,
- llvm::BitstreamCursor &Cursor,
+ BitstreamCursor &Cursor,
const std::pair<uint64_t, uint64_t> &Offsets,
DeclContextInfo &Info) {
SavedStreamPosition SavedPosition(Cursor);
@@ -670,17 +714,16 @@ bool ASTReader::ReadDeclContextStorage(ModuleFile &M,
Cursor.JumpToBit(Offsets.first);
RecordData Record;
- const char *Blob;
- unsigned BlobLen;
+ StringRef Blob;
unsigned Code = Cursor.ReadCode();
- unsigned RecCode = Cursor.ReadRecord(Code, Record, &Blob, &BlobLen);
+ unsigned RecCode = Cursor.readRecord(Code, Record, &Blob);
if (RecCode != DECL_CONTEXT_LEXICAL) {
Error("Expected lexical block");
return true;
}
- Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair*>(Blob);
- Info.NumLexicalDecls = BlobLen / sizeof(KindDeclIDPair);
+ Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair*>(Blob.data());
+ Info.NumLexicalDecls = Blob.size() / sizeof(KindDeclIDPair);
}
// Now the lookup table.
@@ -688,18 +731,17 @@ bool ASTReader::ReadDeclContextStorage(ModuleFile &M,
Cursor.JumpToBit(Offsets.second);
RecordData Record;
- const char *Blob;
- unsigned BlobLen;
+ StringRef Blob;
unsigned Code = Cursor.ReadCode();
- unsigned RecCode = Cursor.ReadRecord(Code, Record, &Blob, &BlobLen);
+ unsigned RecCode = Cursor.readRecord(Code, Record, &Blob);
if (RecCode != DECL_CONTEXT_VISIBLE) {
Error("Expected visible lookup table block");
return true;
}
Info.NameLookupTableData
= ASTDeclContextNameLookupTable::Create(
- (const unsigned char *)Blob + Record[0],
- (const unsigned char *)Blob,
+ (const unsigned char *)Blob.data() + Record[0],
+ (const unsigned char *)Blob.data(),
ASTDeclContextNameLookupTrait(*this, M));
}
@@ -773,7 +815,7 @@ bool ASTReader::ParseLineTable(ModuleFile &F,
bool ASTReader::ReadSourceManagerBlock(ModuleFile &F) {
using namespace SrcMgr;
- llvm::BitstreamCursor &SLocEntryCursor = F.SLocEntryCursor;
+ BitstreamCursor &SLocEntryCursor = F.SLocEntryCursor;
// Set the source-location entry cursor to the current position in
// the stream. This cursor will be used to read the contents of the
@@ -795,35 +837,24 @@ bool ASTReader::ReadSourceManagerBlock(ModuleFile &F) {
RecordData Record;
while (true) {
- unsigned Code = SLocEntryCursor.ReadCode();
- if (Code == llvm::bitc::END_BLOCK) {
- if (SLocEntryCursor.ReadBlockEnd()) {
- Error("error at end of Source Manager block in AST file");
- return true;
- }
+ llvm::BitstreamEntry E = SLocEntryCursor.advanceSkippingSubblocks();
+
+ switch (E.Kind) {
+ case llvm::BitstreamEntry::SubBlock: // Handled for us already.
+ case llvm::BitstreamEntry::Error:
+ Error("malformed block record in AST file");
+ return true;
+ case llvm::BitstreamEntry::EndBlock:
return false;
+ case llvm::BitstreamEntry::Record:
+ // The interesting case.
+ break;
}
-
- if (Code == llvm::bitc::ENTER_SUBBLOCK) {
- // No known subblocks, always skip them.
- SLocEntryCursor.ReadSubBlockID();
- if (SLocEntryCursor.SkipBlock()) {
- Error("malformed block record in AST file");
- return true;
- }
- continue;
- }
-
- if (Code == llvm::bitc::DEFINE_ABBREV) {
- SLocEntryCursor.ReadAbbrevRecord();
- continue;
- }
-
+
// Read a record.
- const char *BlobStart;
- unsigned BlobLen;
Record.clear();
- switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
+ StringRef Blob;
+ switch (SLocEntryCursor.readRecord(E.ID, Record, &Blob)) {
default: // Default behavior: ignore.
break;
@@ -880,22 +911,19 @@ bool ASTReader::ReadSLocEntry(int ID) {
ModuleFile *F = GlobalSLocEntryMap.find(-ID)->second;
F->SLocEntryCursor.JumpToBit(F->SLocEntryOffsets[ID - F->SLocEntryBaseID]);
- llvm::BitstreamCursor &SLocEntryCursor = F->SLocEntryCursor;
+ BitstreamCursor &SLocEntryCursor = F->SLocEntryCursor;
unsigned BaseOffset = F->SLocEntryBaseOffset;
++NumSLocEntriesRead;
- unsigned Code = SLocEntryCursor.ReadCode();
- if (Code == llvm::bitc::END_BLOCK ||
- Code == llvm::bitc::ENTER_SUBBLOCK ||
- Code == llvm::bitc::DEFINE_ABBREV) {
+ llvm::BitstreamEntry Entry = SLocEntryCursor.advance();
+ if (Entry.Kind != llvm::BitstreamEntry::Record) {
Error("incorrectly-formatted source location entry in AST file");
return true;
}
-
+
RecordData Record;
- const char *BlobStart;
- unsigned BlobLen;
- switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
+ StringRef Blob;
+ switch (SLocEntryCursor.readRecord(Entry.ID, Record, &Blob)) {
default:
Error("incorrectly-formatted source location entry in AST file");
return true;
@@ -905,10 +933,13 @@ bool ASTReader::ReadSLocEntry(int ID) {
// we will also try to fail gracefully by setting up the SLocEntry.
unsigned InputID = Record[4];
InputFile IF = getInputFile(*F, InputID);
- const FileEntry *File = IF.getPointer();
- bool OverriddenBuffer = IF.getInt();
+ const FileEntry *File = IF.getFile();
+ bool OverriddenBuffer = IF.isOverridden();
- if (!IF.getPointer())
+ // Note that we only check if a File was returned. If it was out-of-date
+ // we have complained but we will continue creating a FileID to recover
+ // gracefully.
+ if (!File)
return true;
SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]);
@@ -941,8 +972,7 @@ bool ASTReader::ReadSLocEntry(int ID) {
ContentCache->ContentsEntry == ContentCache->OrigEntry) {
unsigned Code = SLocEntryCursor.ReadCode();
Record.clear();
- unsigned RecCode
- = SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen);
+ unsigned RecCode = SLocEntryCursor.readRecord(Code, Record, &Blob);
if (RecCode != SM_SLOC_BUFFER_BLOB) {
Error("AST record has invalid code");
@@ -950,8 +980,7 @@ bool ASTReader::ReadSLocEntry(int ID) {
}
llvm::MemoryBuffer *Buffer
- = llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1),
- File->getName());
+ = llvm::MemoryBuffer::getMemBuffer(Blob.drop_back(1), File->getName());
SourceMgr.overrideFileContents(File, Buffer);
}
@@ -959,15 +988,18 @@ bool ASTReader::ReadSLocEntry(int ID) {
}
case SM_SLOC_BUFFER_ENTRY: {
- const char *Name = BlobStart;
+ const char *Name = Blob.data();
unsigned Offset = Record[0];
SrcMgr::CharacteristicKind
FileCharacter = (SrcMgr::CharacteristicKind)Record[2];
SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]);
+ if (IncludeLoc.isInvalid() && F->Kind == MK_Module) {
+ IncludeLoc = getImportLocation(F);
+ }
unsigned Code = SLocEntryCursor.ReadCode();
Record.clear();
unsigned RecCode
- = SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen);
+ = SLocEntryCursor.readRecord(Code, Record, &Blob);
if (RecCode != SM_SLOC_BUFFER_BLOB) {
Error("AST record has invalid code");
@@ -975,8 +1007,7 @@ bool ASTReader::ReadSLocEntry(int ID) {
}
llvm::MemoryBuffer *Buffer
- = llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1),
- Name);
+ = llvm::MemoryBuffer::getMemBuffer(Blob.drop_back(1), Name);
SourceMgr.createFileIDForMemBuffer(Buffer, FileCharacter, ID,
BaseOffset + Offset, IncludeLoc);
break;
@@ -997,6 +1028,25 @@ bool ASTReader::ReadSLocEntry(int ID) {
return false;
}
+std::pair<SourceLocation, StringRef> ASTReader::getModuleImportLoc(int ID) {
+ if (ID == 0)
+ return std::make_pair(SourceLocation(), "");
+
+ if (unsigned(-ID) - 2 >= getTotalNumSLocs() || ID > 0) {
+ Error("source location entry ID out-of-range for AST file");
+ return std::make_pair(SourceLocation(), "");
+ }
+
+ // Find which module file this entry lands in.
+ ModuleFile *M = GlobalSLocEntryMap.find(-ID)->second;
+ if (M->Kind != MK_Module)
+ return std::make_pair(SourceLocation(), "");
+
+ // FIXME: Can we map this down to a particular submodule? That would be
+ // ideal.
+ return std::make_pair(M->ImportLoc, llvm::sys::path::stem(M->FileName));
+}
+
/// \brief Find the location where the module F is imported.
SourceLocation ASTReader::getImportLocation(ModuleFile *F) {
if (F->ImportLoc.isValid())
@@ -1019,8 +1069,7 @@ SourceLocation ASTReader::getImportLocation(ModuleFile *F) {
/// ReadBlockAbbrevs - Enter a subblock of the specified BlockID with the
/// specified cursor. Read the abbreviations that are at the top of the block
/// and then leave the cursor pointing into the block.
-bool ASTReader::ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor,
- unsigned BlockID) {
+bool ASTReader::ReadBlockAbbrevs(BitstreamCursor &Cursor, unsigned BlockID) {
if (Cursor.EnterSubBlock(BlockID)) {
Error("malformed block record in AST file");
return Failure;
@@ -1039,9 +1088,8 @@ bool ASTReader::ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor,
}
}
-void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset,
- MacroInfo *Hint) {
- llvm::BitstreamCursor &Stream = F.MacroCursor;
+MacroInfo *ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) {
+ BitstreamCursor &Stream = F.MacroCursor;
// Keep track of where we are in the stream, then jump back there
// after reading this macro.
@@ -1052,95 +1100,53 @@ void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset,
SmallVector<IdentifierInfo*, 16> MacroArgs;
MacroInfo *Macro = 0;
- // RAII object to add the loaded macro information once we're done
- // adding tokens.
- struct AddLoadedMacroInfoRAII {
- Preprocessor &PP;
- MacroInfo *Hint;
- MacroInfo *MI;
- IdentifierInfo *II;
-
- AddLoadedMacroInfoRAII(Preprocessor &PP, MacroInfo *Hint)
- : PP(PP), Hint(Hint), MI(), II() { }
- ~AddLoadedMacroInfoRAII( ) {
- if (MI) {
- // Finally, install the macro.
- PP.addLoadedMacroInfo(II, MI, Hint);
- }
- }
- } AddLoadedMacroInfo(PP, Hint);
-
while (true) {
- unsigned Code = Stream.ReadCode();
- switch (Code) {
- case llvm::bitc::END_BLOCK:
- return;
-
- case llvm::bitc::ENTER_SUBBLOCK:
- // No known subblocks, always skip them.
- Stream.ReadSubBlockID();
- if (Stream.SkipBlock()) {
- Error("malformed block record in AST file");
- return;
- }
- continue;
-
- case llvm::bitc::DEFINE_ABBREV:
- Stream.ReadAbbrevRecord();
- continue;
- default: break;
+ // Advance to the next record, but if we get to the end of the block, don't
+ // pop it (removing all the abbreviations from the cursor) since we want to
+ // be able to reseek within the block and read entries.
+ unsigned Flags = BitstreamCursor::AF_DontPopBlockAtEnd;
+ llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks(Flags);
+
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::SubBlock: // Handled for us already.
+ case llvm::BitstreamEntry::Error:
+ Error("malformed block record in AST file");
+ return Macro;
+ case llvm::BitstreamEntry::EndBlock:
+ return Macro;
+ case llvm::BitstreamEntry::Record:
+ // The interesting case.
+ break;
}
// Read a record.
- const char *BlobStart = 0;
- unsigned BlobLen = 0;
Record.clear();
PreprocessorRecordTypes RecType =
- (PreprocessorRecordTypes)Stream.ReadRecord(Code, Record, BlobStart,
- BlobLen);
+ (PreprocessorRecordTypes)Stream.readRecord(Entry.ID, Record);
switch (RecType) {
+ case PP_MACRO_DIRECTIVE_HISTORY:
+ return Macro;
+
case PP_MACRO_OBJECT_LIKE:
case PP_MACRO_FUNCTION_LIKE: {
// If we already have a macro, that means that we've hit the end
// of the definition of the macro we were looking for. We're
// done.
if (Macro)
- return;
+ return Macro;
- IdentifierInfo *II = getLocalIdentifier(F, Record[0]);
- if (II == 0) {
- Error("macro must have a name in AST file");
- return;
- }
-
- 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;
+ unsigned NextIndex = 1; // Skip identifier ID.
+ SubmoduleID SubModID = getGlobalSubmoduleID(F, Record[NextIndex++]);
SourceLocation Loc = ReadSourceLocation(F, Record, NextIndex);
- MacroInfo *MI = PP.AllocateMacroInfo(Loc);
-
- // Record this macro.
- MacrosLoaded[GlobalID - NUM_PREDEF_MACRO_IDS] = MI;
-
- SourceLocation UndefLoc = ReadSourceLocation(F, Record, NextIndex);
- if (UndefLoc.isValid())
- MI->setUndefLoc(UndefLoc);
-
+ MacroInfo *MI = PP.AllocateDeserializedMacroInfo(Loc, SubModID);
+ MI->setDefinitionEndLoc(ReadSourceLocation(F, Record, NextIndex));
MI->setIsUsed(Record[NextIndex++]);
- MI->setIsFromAST();
-
- 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++];
bool isGNUVarArgs = Record[NextIndex++];
+ bool hasCommaPasting = Record[NextIndex++];
MacroArgs.clear();
unsigned NumArgs = Record[NextIndex++];
for (unsigned i = 0; i != NumArgs; ++i)
@@ -1150,65 +1156,11 @@ void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset,
MI->setIsFunctionLike();
if (isC99VarArgs) MI->setIsC99Varargs();
if (isGNUVarArgs) MI->setIsGNUVarargs();
+ if (hasCommaPasting) MI->setHasCommaPasting();
MI->setArgumentList(MacroArgs.data(), MacroArgs.size(),
PP.getPreprocessorAllocator());
}
- 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.
Macro = MI;
@@ -1219,8 +1171,12 @@ void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset,
PreprocessedEntityID
GlobalID = getGlobalPreprocessedEntityID(F, Record[NextIndex]);
PreprocessingRecord &PPRec = *PP.getPreprocessingRecord();
- PPRec.RegisterMacroDefinition(Macro,
- PPRec.getPPEntityID(GlobalID-1, /*isLoaded=*/true));
+ PreprocessingRecord::PPEntityID
+ PPID = PPRec.getPPEntityID(GlobalID-1, /*isLoaded=*/true);
+ MacroDefinition *PPDef =
+ cast_or_null<MacroDefinition>(PPRec.getPreprocessedEntity(PPID));
+ if (PPDef)
+ PPRec.RegisterMacroDefinition(Macro, PPDef);
}
++NumMacrosRead;
@@ -1257,37 +1213,49 @@ ASTReader::getGlobalPreprocessedEntityID(ModuleFile &M, unsigned LocalID) const
return LocalID + I->second;
}
-unsigned HeaderFileInfoTrait::ComputeHash(const char *path) {
- return llvm::HashString(llvm::sys::path::filename(path));
+unsigned HeaderFileInfoTrait::ComputeHash(internal_key_ref ikey) {
+ return llvm::hash_combine(ikey.Size, ikey.ModTime);
}
HeaderFileInfoTrait::internal_key_type
-HeaderFileInfoTrait::GetInternalKey(const char *path) { return path; }
+HeaderFileInfoTrait::GetInternalKey(const FileEntry *FE) {
+ internal_key_type ikey = { FE->getSize(), FE->getModificationTime(),
+ FE->getName() };
+ return ikey;
+}
-bool HeaderFileInfoTrait::EqualKey(internal_key_type a, internal_key_type b) {
- if (strcmp(a, b) == 0)
- return true;
-
- if (llvm::sys::path::filename(a) != llvm::sys::path::filename(b))
+bool HeaderFileInfoTrait::EqualKey(internal_key_ref a, internal_key_ref b) {
+ if (a.Size != b.Size || a.ModTime != b.ModTime)
return false;
- // Determine whether the actual files are equivalent.
- bool Result = false;
- if (llvm::sys::fs::equivalent(a, b, Result))
- return false;
+ if (strcmp(a.Filename, b.Filename) == 0)
+ return true;
- return Result;
+ // Determine whether the actual files are equivalent.
+ FileManager &FileMgr = Reader.getFileManager();
+ const FileEntry *FEA = FileMgr.getFile(a.Filename);
+ const FileEntry *FEB = FileMgr.getFile(b.Filename);
+ return (FEA && FEA == FEB);
}
std::pair<unsigned, unsigned>
HeaderFileInfoTrait::ReadKeyDataLength(const unsigned char*& d) {
unsigned KeyLen = (unsigned) clang::io::ReadUnalignedLE16(d);
unsigned DataLen = (unsigned) *d++;
- return std::make_pair(KeyLen + 1, DataLen);
+ return std::make_pair(KeyLen, DataLen);
}
-
+
+HeaderFileInfoTrait::internal_key_type
+HeaderFileInfoTrait::ReadKey(const unsigned char *d, unsigned) {
+ internal_key_type ikey;
+ ikey.Size = off_t(clang::io::ReadUnalignedLE64(d));
+ ikey.ModTime = time_t(clang::io::ReadUnalignedLE64(d));
+ ikey.Filename = (const char *)d;
+ return ikey;
+}
+
HeaderFileInfoTrait::data_type
-HeaderFileInfoTrait::ReadData(const internal_key_type, const unsigned char *d,
+HeaderFileInfoTrait::ReadData(internal_key_ref key, const unsigned char *d,
unsigned DataLen) {
const unsigned char *End = d + DataLen;
using namespace clang::io;
@@ -1308,6 +1276,21 @@ HeaderFileInfoTrait::ReadData(const internal_key_type, const unsigned char *d,
HFI.Framework = HS->getUniqueFrameworkName(FrameworkName);
}
+ if (d != End) {
+ uint32_t LocalSMID = ReadUnalignedLE32(d);
+ if (LocalSMID) {
+ // This header is part of a module. Associate it with the module to enable
+ // implicit module import.
+ SubmoduleID GlobalSMID = Reader.getGlobalSubmoduleID(M, LocalSMID);
+ Module *Mod = Reader.getSubmodule(GlobalSMID);
+ HFI.isModuleHeader = true;
+ FileManager &FileMgr = Reader.getFileManager();
+ ModuleMap &ModMap =
+ Reader.getPreprocessor().getHeaderSearchInfo().getModuleMap();
+ ModMap.addHeader(Mod, FileMgr.getFile(key.Filename), /*Excluded=*/false);
+ }
+ }
+
assert(End == d && "Wrong data length in HeaderFileInfo deserialization");
(void)End;
@@ -1316,10 +1299,19 @@ HeaderFileInfoTrait::ReadData(const internal_key_type, const unsigned char *d,
return HFI;
}
-void ASTReader::setIdentifierIsMacro(IdentifierInfo *II, ArrayRef<MacroID> IDs){
- II->setHadMacroDefinition(true);
+void ASTReader::addPendingMacroFromModule(IdentifierInfo *II,
+ ModuleFile *M,
+ GlobalMacroID GMacID,
+ SourceLocation ImportLoc) {
assert(NumCurrentElementsDeserializing > 0 &&"Missing deserialization guard");
- PendingMacroIDs[II].append(IDs.begin(), IDs.end());
+ PendingMacroIDs[II].push_back(PendingMacroInfo(M, GMacID, ImportLoc));
+}
+
+void ASTReader::addPendingMacroFromPCH(IdentifierInfo *II,
+ ModuleFile *M,
+ uint64_t MacroDirectivesOffset) {
+ assert(NumCurrentElementsDeserializing > 0 &&"Missing deserialization guard");
+ PendingMacroIDs[II].push_back(PendingMacroInfo(M, MacroDirectivesOffset));
}
void ASTReader::ReadDefinedMacros() {
@@ -1328,54 +1320,46 @@ void ASTReader::ReadDefinedMacros() {
for (ModuleReverseIterator I = ModuleMgr.rbegin(),
E = ModuleMgr.rend(); I != E; ++I) {
- llvm::BitstreamCursor &MacroCursor = (*I)->MacroCursor;
+ BitstreamCursor &MacroCursor = (*I)->MacroCursor;
// If there was no preprocessor block, skip this file.
if (!MacroCursor.getBitStreamReader())
continue;
- llvm::BitstreamCursor Cursor = MacroCursor;
+ BitstreamCursor Cursor = MacroCursor;
Cursor.JumpToBit((*I)->MacroStartOffset);
RecordData Record;
while (true) {
- unsigned Code = Cursor.ReadCode();
- if (Code == llvm::bitc::END_BLOCK)
- break;
-
- if (Code == llvm::bitc::ENTER_SUBBLOCK) {
- // No known subblocks, always skip them.
- Cursor.ReadSubBlockID();
- if (Cursor.SkipBlock()) {
- Error("malformed block record in AST file");
- return;
+ llvm::BitstreamEntry E = Cursor.advanceSkippingSubblocks();
+
+ switch (E.Kind) {
+ case llvm::BitstreamEntry::SubBlock: // Handled for us already.
+ case llvm::BitstreamEntry::Error:
+ Error("malformed block record in AST file");
+ return;
+ case llvm::BitstreamEntry::EndBlock:
+ goto NextCursor;
+
+ case llvm::BitstreamEntry::Record:
+ Record.clear();
+ switch (Cursor.readRecord(E.ID, Record)) {
+ default: // Default behavior: ignore.
+ break;
+
+ case PP_MACRO_OBJECT_LIKE:
+ case PP_MACRO_FUNCTION_LIKE:
+ getLocalIdentifier(**I, Record[0]);
+ break;
+
+ case PP_TOKEN:
+ // Ignore tokens.
+ break;
}
- continue;
- }
-
- if (Code == llvm::bitc::DEFINE_ABBREV) {
- Cursor.ReadAbbrevRecord();
- continue;
- }
-
- // Read a record.
- const char *BlobStart;
- unsigned BlobLen;
- Record.clear();
- switch (Cursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
- default: // Default behavior: ignore.
- break;
-
- case PP_MACRO_OBJECT_LIKE:
- case PP_MACRO_FUNCTION_LIKE:
- getLocalIdentifier(**I, Record[0]);
- break;
-
- case PP_TOKEN:
- // Ignore tokens.
break;
}
}
+ NextCursor: ;
}
}
@@ -1384,10 +1368,20 @@ namespace {
class IdentifierLookupVisitor {
StringRef Name;
unsigned PriorGeneration;
+ unsigned &NumIdentifierLookups;
+ unsigned &NumIdentifierLookupHits;
IdentifierInfo *Found;
+
public:
- IdentifierLookupVisitor(StringRef Name, unsigned PriorGeneration)
- : Name(Name), PriorGeneration(PriorGeneration), Found() { }
+ IdentifierLookupVisitor(StringRef Name, unsigned PriorGeneration,
+ unsigned &NumIdentifierLookups,
+ unsigned &NumIdentifierLookupHits)
+ : Name(Name), PriorGeneration(PriorGeneration),
+ NumIdentifierLookups(NumIdentifierLookups),
+ NumIdentifierLookupHits(NumIdentifierLookupHits),
+ Found()
+ {
+ }
static bool visit(ModuleFile &M, void *UserData) {
IdentifierLookupVisitor *This
@@ -1396,7 +1390,7 @@ namespace {
// If we've already searched this module file, skip it now.
if (M.Generation <= This->PriorGeneration)
return true;
-
+
ASTIdentifierLookupTable *IdTable
= (ASTIdentifierLookupTable *)M.IdentifierLookupTable;
if (!IdTable)
@@ -1404,16 +1398,15 @@ namespace {
ASTIdentifierLookupTrait Trait(IdTable->getInfoObj().getReader(),
M, This->Found);
-
- std::pair<const char*, unsigned> Key(This->Name.begin(),
- This->Name.size());
- ASTIdentifierLookupTable::iterator Pos = IdTable->find(Key, &Trait);
+ ++This->NumIdentifierLookups;
+ ASTIdentifierLookupTable::iterator Pos = IdTable->find(This->Name,&Trait);
if (Pos == IdTable->end())
return false;
// Dereferencing the iterator has the effect of building the
// IdentifierInfo node and populating it with the various
// declarations it needs.
+ ++This->NumIdentifierLookupHits;
This->Found = *Pos;
return true;
}
@@ -1431,9 +1424,21 @@ void ASTReader::updateOutOfDateIdentifier(IdentifierInfo &II) {
unsigned PriorGeneration = 0;
if (getContext().getLangOpts().Modules)
PriorGeneration = IdentifierGeneration[&II];
-
- IdentifierLookupVisitor Visitor(II.getName(), PriorGeneration);
- ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor);
+
+ // If there is a global index, look there first to determine which modules
+ // provably do not have any results for this identifier.
+ GlobalModuleIndex::HitSet Hits;
+ GlobalModuleIndex::HitSet *HitsPtr = 0;
+ if (!loadGlobalIndex()) {
+ if (GlobalIndex->lookupIdentifier(II.getName(), Hits)) {
+ HitsPtr = &Hits;
+ }
+ }
+
+ IdentifierLookupVisitor Visitor(II.getName(), PriorGeneration,
+ NumIdentifierLookups,
+ NumIdentifierLookupHits);
+ ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor, HitsPtr);
markIdentifierUpToDate(&II);
}
@@ -1448,27 +1453,196 @@ void ASTReader::markIdentifierUpToDate(IdentifierInfo *II) {
IdentifierGeneration[II] = CurrentGeneration;
}
-llvm::PointerIntPair<const FileEntry *, 1, bool>
-ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
+void ASTReader::resolvePendingMacro(IdentifierInfo *II,
+ const PendingMacroInfo &PMInfo) {
+ assert(II);
+
+ if (PMInfo.M->Kind != MK_Module) {
+ installPCHMacroDirectives(II, *PMInfo.M,
+ PMInfo.PCHMacroData.MacroDirectivesOffset);
+ return;
+ }
+
+ // Module Macro.
+
+ GlobalMacroID GMacID = PMInfo.ModuleMacroData.GMacID;
+ SourceLocation ImportLoc =
+ SourceLocation::getFromRawEncoding(PMInfo.ModuleMacroData.ImportLoc);
+
+ assert(GMacID);
+ // If this macro has already been loaded, don't do so again.
+ if (MacrosLoaded[GMacID - NUM_PREDEF_MACRO_IDS])
+ return;
+
+ MacroInfo *MI = getMacro(GMacID);
+ SubmoduleID SubModID = MI->getOwningModuleID();
+ MacroDirective *MD = PP.AllocateDefMacroDirective(MI, ImportLoc,
+ /*isImported=*/true);
+
+ // Determine whether this macro definition is visible.
+ bool Hidden = false;
+ Module *Owner = 0;
+ if (SubModID) {
+ if ((Owner = getSubmodule(SubModID))) {
+ 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, MD));
+ }
+ }
+ }
+
+ if (!Hidden)
+ installImportedMacro(II, MD, Owner);
+}
+
+void ASTReader::installPCHMacroDirectives(IdentifierInfo *II,
+ ModuleFile &M, uint64_t Offset) {
+ assert(M.Kind != MK_Module);
+
+ BitstreamCursor &Cursor = M.MacroCursor;
+ SavedStreamPosition SavedPosition(Cursor);
+ Cursor.JumpToBit(Offset);
+
+ llvm::BitstreamEntry Entry =
+ Cursor.advance(BitstreamCursor::AF_DontPopBlockAtEnd);
+ if (Entry.Kind != llvm::BitstreamEntry::Record) {
+ Error("malformed block record in AST file");
+ return;
+ }
+
+ RecordData Record;
+ PreprocessorRecordTypes RecType =
+ (PreprocessorRecordTypes)Cursor.readRecord(Entry.ID, Record);
+ if (RecType != PP_MACRO_DIRECTIVE_HISTORY) {
+ Error("malformed block record in AST file");
+ return;
+ }
+
+ // Deserialize the macro directives history in reverse source-order.
+ MacroDirective *Latest = 0, *Earliest = 0;
+ unsigned Idx = 0, N = Record.size();
+ while (Idx < N) {
+ MacroDirective *MD = 0;
+ SourceLocation Loc = ReadSourceLocation(M, Record, Idx);
+ MacroDirective::Kind K = (MacroDirective::Kind)Record[Idx++];
+ switch (K) {
+ case MacroDirective::MD_Define: {
+ GlobalMacroID GMacID = getGlobalMacroID(M, Record[Idx++]);
+ MacroInfo *MI = getMacro(GMacID);
+ bool isImported = Record[Idx++];
+ bool isAmbiguous = Record[Idx++];
+ DefMacroDirective *DefMD =
+ PP.AllocateDefMacroDirective(MI, Loc, isImported);
+ DefMD->setAmbiguous(isAmbiguous);
+ MD = DefMD;
+ break;
+ }
+ case MacroDirective::MD_Undefine:
+ MD = PP.AllocateUndefMacroDirective(Loc);
+ break;
+ case MacroDirective::MD_Visibility: {
+ bool isPublic = Record[Idx++];
+ MD = PP.AllocateVisibilityMacroDirective(Loc, isPublic);
+ break;
+ }
+ }
+
+ if (!Latest)
+ Latest = MD;
+ if (Earliest)
+ Earliest->setPrevious(MD);
+ Earliest = MD;
+ }
+
+ PP.setLoadedMacroDirective(II, Latest);
+}
+
+/// \brief For the given macro definitions, check if they are both in system
+/// modules and if one of the two is in the clang builtin headers.
+static bool isSystemAndClangMacro(MacroInfo *PrevMI, MacroInfo *NewMI,
+ Module *NewOwner, ASTReader &Reader) {
+ assert(PrevMI && NewMI);
+ if (!NewOwner)
+ return false;
+ Module *PrevOwner = 0;
+ if (SubmoduleID PrevModID = PrevMI->getOwningModuleID())
+ PrevOwner = Reader.getSubmodule(PrevModID);
+ if (!PrevOwner)
+ return false;
+ if (PrevOwner == NewOwner)
+ return false;
+ if (!PrevOwner->IsSystem || !NewOwner->IsSystem)
+ return false;
+
+ SourceManager &SM = Reader.getSourceManager();
+ FileID PrevFID = SM.getFileID(PrevMI->getDefinitionLoc());
+ FileID NewFID = SM.getFileID(NewMI->getDefinitionLoc());
+ const FileEntry *PrevFE = SM.getFileEntryForID(PrevFID);
+ const FileEntry *NewFE = SM.getFileEntryForID(NewFID);
+ if (PrevFE == 0 || NewFE == 0)
+ return false;
+
+ Preprocessor &PP = Reader.getPreprocessor();
+ ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap();
+ const DirectoryEntry *BuiltinDir = ModMap.getBuiltinIncludeDir();
+
+ return (PrevFE->getDir() == BuiltinDir) != (NewFE->getDir() == BuiltinDir);
+}
+
+void ASTReader::installImportedMacro(IdentifierInfo *II, MacroDirective *MD,
+ Module *Owner) {
+ assert(II && MD);
+
+ DefMacroDirective *DefMD = cast<DefMacroDirective>(MD);
+ MacroDirective *Prev = PP.getMacroDirective(II);
+ if (Prev) {
+ MacroDirective::DefInfo PrevDef = Prev->getDefinition();
+ MacroInfo *PrevMI = PrevDef.getMacroInfo();
+ MacroInfo *NewMI = DefMD->getInfo();
+ if (NewMI != PrevMI && !PrevMI->isIdenticalTo(*NewMI, PP,
+ /*Syntactically=*/true)) {
+ // Before marking the macros as ambiguous, check if this is a case where
+ // the system macro uses a not identical definition compared to a macro
+ // from the clang headers. For example:
+ // #define LONG_MAX __LONG_MAX__ (clang's limits.h)
+ // #define LONG_MAX 0x7fffffffffffffffL (system's limits.h)
+ // in which case don't mark them to avoid the "ambiguous macro expansion"
+ // warning.
+ // FIXME: This should go away if the system headers get "fixed" to use
+ // identical definitions.
+ if (!isSystemAndClangMacro(PrevMI, NewMI, Owner, *this)) {
+ PrevDef.getDirective()->setAmbiguous(true);
+ DefMD->setAmbiguous(true);
+ }
+ }
+ }
+
+ PP.appendMacroDirective(II, MD);
+}
+
+InputFile 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())
+ if (F.InputFilesLoaded[ID-1].getFile())
return F.InputFilesLoaded[ID-1];
// Go find this input file.
- llvm::BitstreamCursor &Cursor = F.InputFilesCursor;
+ 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)) {
+ StringRef Blob;
+ switch ((InputFileRecordTypes)Cursor.readRecord(Code, Record, &Blob)) {
case INPUT_FILE: {
unsigned StoredID = Record[0];
assert(ID == StoredID && "Bogus stored ID or offset");
@@ -1478,7 +1652,7 @@ ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
bool Overridden = (bool)Record[3];
// Get the file entry for this input file.
- StringRef OrigFilename(BlobStart, BlobLen);
+ StringRef OrigFilename = Blob;
std::string Filename = OrigFilename;
MaybeAddSystemRootToFilename(F, Filename);
const FileEntry *File
@@ -1511,17 +1685,15 @@ ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
}
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);
+ if (Complain)
+ 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);
@@ -1532,33 +1704,29 @@ ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) {
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();
- }
+ bool IsOutOfDate = false;
- if ((StoredSize != StatBuf.st_size
+ // For an overridden file, there is nothing to validate.
+ if (!Overridden && (StoredSize != 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.
- || StoredTime != StatBuf.st_mtime
+ || StoredTime != File->getModificationTime()
#endif
)) {
- if (Complain)
- Error(diag::err_fe_pch_file_modified, Filename);
-
- return InputFile();
+ if (Complain) {
+ Error(diag::err_fe_pch_file_modified, Filename, F.FileName);
+ }
+
+ IsOutOfDate = true;
}
- return InputFile(File, Overridden);
+ InputFile IF = InputFile(File, Overridden, IsOutOfDate);
+
+ // Note that we've loaded this input file.
+ F.InputFilesLoaded[ID-1] = IF;
+ return IF;
}
}
@@ -1609,9 +1777,9 @@ void ASTReader::MaybeAddSystemRootToFilename(ModuleFile &M,
ASTReader::ASTReadResult
ASTReader::ReadControlBlock(ModuleFile &F,
- llvm::SmallVectorImpl<ModuleFile *> &Loaded,
+ SmallVectorImpl<ImportedModule> &Loaded,
unsigned ClientLoadCapabilities) {
- llvm::BitstreamCursor &Stream = F.Stream;
+ BitstreamCursor &Stream = F.Stream;
if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) {
Error("malformed block record in AST file");
@@ -1620,27 +1788,29 @@ ASTReader::ReadControlBlock(ModuleFile &F,
// 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 control block in AST file");
- return Failure;
- }
-
- // Validate all of the input files.
+ while (1) {
+ llvm::BitstreamEntry Entry = Stream.advance();
+
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::Error:
+ Error("malformed block record in AST file");
+ return Failure;
+ case llvm::BitstreamEntry::EndBlock:
+ // Validate all of the non-system 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())
+ // All user input files reside at the index range [0, Record[1]).
+ // Record is the one from INPUT_FILE_OFFSETS.
+ for (unsigned I = 0, N = Record[1]; I < N; ++I) {
+ InputFile IF = getInputFile(F, I+1, Complain);
+ if (!IF.getFile() || IF.isOutOfDate())
return OutOfDate;
+ }
}
-
return Success;
- }
-
- if (Code == llvm::bitc::ENTER_SUBBLOCK) {
- switch (Stream.ReadSubBlockID()) {
+
+ case llvm::BitstreamEntry::SubBlock:
+ switch (Entry.ID) {
case INPUT_FILES_BLOCK_ID:
F.InputFilesCursor = Stream;
if (Stream.SkipBlock() || // Skip with the main cursor
@@ -1650,28 +1820,24 @@ ASTReader::ReadControlBlock(ModuleFile &F,
return Failure;
}
continue;
-
+
default:
- if (!Stream.SkipBlock())
- continue;
- break;
+ if (Stream.SkipBlock()) {
+ Error("malformed block record in AST file");
+ return Failure;
+ }
+ continue;
}
-
- Error("malformed block record in AST file");
- return Failure;
- }
-
- if (Code == llvm::bitc::DEFINE_ABBREV) {
- Stream.ReadAbbrevRecord();
- continue;
+
+ case llvm::BitstreamEntry::Record:
+ // The interesting case.
+ break;
}
// Read and process a record.
Record.clear();
- const char *BlobStart = 0;
- unsigned BlobLen = 0;
- switch ((ControlRecordTypes)Stream.ReadRecord(Code, Record,
- &BlobStart, &BlobLen)) {
+ StringRef Blob;
+ switch ((ControlRecordTypes)Stream.readRecord(Entry.ID, Record, &Blob)) {
case METADATA: {
if (Record[0] != VERSION_MAJOR && !DisableValidation) {
if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0)
@@ -1689,7 +1855,7 @@ ASTReader::ReadControlBlock(ModuleFile &F,
F.RelocatablePCH = Record[4];
const std::string &CurBranch = getClangFullRepositoryVersion();
- StringRef ASTBranch(BlobStart, BlobLen);
+ StringRef ASTBranch = Blob;
if (StringRef(CurBranch) != ASTBranch && !DisableValidation) {
if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0)
Diag(diag::warn_pch_different_branch) << ASTBranch << CurBranch;
@@ -1704,16 +1870,25 @@ ASTReader::ReadControlBlock(ModuleFile &F,
while (Idx < N) {
// Read information about the AST file.
ModuleKind ImportedKind = (ModuleKind)Record[Idx++];
+ // The import location will be the local one for now; we will adjust
+ // all import locations of module imports after the global source
+ // location info are setup.
+ SourceLocation ImportLoc =
+ SourceLocation::getFromRawEncoding(Record[Idx++]);
+ off_t StoredSize = (off_t)Record[Idx++];
+ time_t StoredModTime = (time_t)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,
+ switch(ReadASTCore(ImportedFile, ImportedKind, ImportLoc, &F, Loaded,
+ StoredSize, StoredModTime,
ClientLoadCapabilities)) {
case Failure: return Failure;
// If we have to ignore the dependency, we'll have to ignore this too.
+ case Missing:
case OutOfDate: return OutOfDate;
case VersionMismatch: return VersionMismatch;
case ConfigurationMismatch: return ConfigurationMismatch;
@@ -1781,28 +1956,29 @@ ASTReader::ReadControlBlock(ModuleFile &F,
case ORIGINAL_FILE:
F.OriginalSourceFileID = FileID::get(Record[0]);
- F.ActualOriginalSourceFileName.assign(BlobStart, BlobLen);
+ F.ActualOriginalSourceFileName = Blob;
F.OriginalSourceFileName = F.ActualOriginalSourceFileName;
MaybeAddSystemRootToFilename(F, F.OriginalSourceFileName);
break;
+ case ORIGINAL_FILE_ID:
+ F.OriginalSourceFileID = FileID::get(Record[0]);
+ break;
+
case ORIGINAL_PCH_DIR:
- F.OriginalDir.assign(BlobStart, BlobLen);
+ F.OriginalDir = Blob;
break;
case INPUT_FILE_OFFSETS:
- F.InputFileOffsets = (const uint32_t *)BlobStart;
+ F.InputFileOffsets = (const uint32_t *)Blob.data();
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;
+ BitstreamCursor &Stream = F.Stream;
if (Stream.EnterSubBlock(AST_BLOCK_ID)) {
Error("malformed block record in AST file");
@@ -1811,23 +1987,28 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
// 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;
- }
-
+ while (1) {
+ llvm::BitstreamEntry Entry = Stream.advance();
+
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::Error:
+ Error("error at end of module block in AST file");
+ return true;
+ case llvm::BitstreamEntry::EndBlock: {
+ // Outside of C++, we do not store a lookup map for the translation unit.
+ // Instead, mark it as needing a lookup map to be built if this module
+ // contains any declarations lexically within it (which it always does!).
+ // This usually has no cost, since we very rarely need the lookup map for
+ // the translation unit outside C++.
DeclContext *DC = Context.getTranslationUnitDecl();
- if (!DC->hasExternalVisibleStorage() && DC->hasExternalLexicalStorage())
+ if (DC->hasExternalLexicalStorage() &&
+ !getContext().getLangOpts().CPlusPlus)
DC->setMustBuildLookupTable();
-
+
return false;
}
-
- if (Code == llvm::bitc::ENTER_SUBBLOCK) {
- switch (Stream.ReadSubBlockID()) {
+ case llvm::BitstreamEntry::SubBlock:
+ switch (Entry.ID) {
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
@@ -1841,19 +2022,19 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
return true;
}
break;
-
+
case DECL_UPDATES_BLOCK_ID:
if (Stream.SkipBlock()) {
Error("malformed block record in AST file");
return true;
}
break;
-
+
case PREPROCESSOR_BLOCK_ID:
F.MacroCursor = Stream;
if (!PP.getExternalSource())
PP.setExternalSource(this);
-
+
if (Stream.SkipBlock() ||
ReadBlockAbbrevs(F.MacroCursor, PREPROCESSOR_BLOCK_ID)) {
Error("malformed block record in AST file");
@@ -1861,20 +2042,20 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
}
F.MacroStartOffset = F.MacroCursor.GetCurrentBitNo();
break;
-
+
case PREPROCESSOR_DETAIL_BLOCK_ID:
F.PreprocessorDetailCursor = Stream;
if (Stream.SkipBlock() ||
- ReadBlockAbbrevs(F.PreprocessorDetailCursor,
+ ReadBlockAbbrevs(F.PreprocessorDetailCursor,
PREPROCESSOR_DETAIL_BLOCK_ID)) {
- Error("malformed preprocessor detail record in AST file");
- return true;
- }
+ Error("malformed preprocessor detail record in AST file");
+ return true;
+ }
F.PreprocessorDetailStartOffset
- = F.PreprocessorDetailCursor.GetCurrentBitNo();
-
+ = F.PreprocessorDetailCursor.GetCurrentBitNo();
+
if (!PP.getPreprocessingRecord())
- PP.createPreprocessingRecord(/*RecordConditionalDirectives=*/false);
+ PP.createPreprocessingRecord();
if (!PP.getPreprocessingRecord()->getExternalSource())
PP.getPreprocessingRecord()->SetExternalSource(*this);
break;
@@ -1883,14 +2064,14 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
if (ReadSourceManagerBlock(F))
return true;
break;
-
+
case SUBMODULE_BLOCK_ID:
if (ReadSubmoduleBlock(F))
return true;
break;
-
+
case COMMENTS_BLOCK_ID: {
- llvm::BitstreamCursor C = Stream;
+ BitstreamCursor C = Stream;
if (Stream.SkipBlock() ||
ReadBlockAbbrevs(C, COMMENTS_BLOCK_ID)) {
Error("malformed comments block in AST file");
@@ -1899,27 +2080,25 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
CommentsCursors.push_back(std::make_pair(C, &F));
break;
}
-
+
default:
- if (!Stream.SkipBlock())
- break;
- Error("malformed block record in AST file");
- return true;
+ if (Stream.SkipBlock()) {
+ Error("malformed block record in AST file");
+ return true;
+ }
+ break;
}
continue;
- }
-
- if (Code == llvm::bitc::DEFINE_ABBREV) {
- Stream.ReadAbbrevRecord();
- continue;
+
+ case llvm::BitstreamEntry::Record:
+ // The interesting case.
+ break;
}
// Read and process a record.
Record.clear();
- const char *BlobStart = 0;
- unsigned BlobLen = 0;
- switch ((ASTRecordTypes)Stream.ReadRecord(Code, Record,
- &BlobStart, &BlobLen)) {
+ StringRef Blob;
+ switch ((ASTRecordTypes)Stream.readRecord(Entry.ID, Record, &Blob)) {
default: // Default behavior: ignore.
break;
@@ -1928,7 +2107,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
Error("duplicate TYPE_OFFSET record in AST file");
return true;
}
- F.TypeOffsets = (const uint32_t *)BlobStart;
+ F.TypeOffsets = (const uint32_t *)Blob.data();
F.LocalNumTypes = Record[0];
unsigned LocalBaseTypeIndex = Record[1];
F.BaseTypeIndex = getTotalNumTypes();
@@ -1952,7 +2131,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
Error("duplicate DECL_OFFSET record in AST file");
return true;
}
- F.DeclOffsets = (const DeclOffset *)BlobStart;
+ F.DeclOffsets = (const DeclOffset *)Blob.data();
F.LocalNumDecls = Record[0];
unsigned LocalBaseDeclID = Record[1];
F.BaseDeclID = getTotalNumDecls();
@@ -1980,9 +2159,9 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case TU_UPDATE_LEXICAL: {
DeclContext *TU = Context.getTranslationUnitDecl();
DeclContextInfo &Info = F.DeclContextInfos[TU];
- Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair *>(BlobStart);
+ Info.LexicalDecls = reinterpret_cast<const KindDeclIDPair *>(Blob.data());
Info.NumLexicalDecls
- = static_cast<unsigned int>(BlobLen / sizeof(KindDeclIDPair));
+ = static_cast<unsigned int>(Blob.size() / sizeof(KindDeclIDPair));
TU->setHasExternalLexicalStorage(true);
break;
}
@@ -1992,8 +2171,8 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
serialization::DeclID ID = ReadDeclID(F, Record, Idx);
ASTDeclContextNameLookupTable *Table =
ASTDeclContextNameLookupTable::Create(
- (const unsigned char *)BlobStart + Record[Idx++],
- (const unsigned char *)BlobStart,
+ (const unsigned char *)Blob.data() + Record[Idx++],
+ (const unsigned char *)Blob.data(),
ASTDeclContextNameLookupTrait(*this, F));
if (ID == PREDEF_DECL_TRANSLATION_UNIT_ID) { // Is it the TU?
DeclContext *TU = Context.getTranslationUnitDecl();
@@ -2005,7 +2184,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
}
case IDENTIFIER_TABLE:
- F.IdentifierTableData = BlobStart;
+ F.IdentifierTableData = Blob.data();
if (Record[0]) {
F.IdentifierLookupTable
= ASTIdentifierLookupTable::Create(
@@ -2022,7 +2201,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
Error("duplicate IDENTIFIER_OFFSET record in AST file");
return true;
}
- F.IdentifierOffsets = (const uint32_t *)BlobStart;
+ F.IdentifierOffsets = (const uint32_t *)Blob.data();
F.LocalNumIdentifiers = Record[0];
unsigned LocalBaseIdentifierID = Record[1];
F.BaseIdentifierID = getTotalNumIdentifiers();
@@ -2051,8 +2230,24 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
break;
case SPECIAL_TYPES:
- for (unsigned I = 0, N = Record.size(); I != N; ++I)
- SpecialTypes.push_back(getGlobalTypeID(F, Record[I]));
+ if (SpecialTypes.empty()) {
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ SpecialTypes.push_back(getGlobalTypeID(F, Record[I]));
+ break;
+ }
+
+ if (SpecialTypes.size() != Record.size()) {
+ Error("invalid special-types record");
+ return true;
+ }
+
+ for (unsigned I = 0, N = Record.size(); I != N; ++I) {
+ serialization::TypeID ID = getGlobalTypeID(F, Record[I]);
+ if (!SpecialTypes[I])
+ SpecialTypes[I] = ID;
+ // FIXME: If ID && SpecialTypes[I] != ID, do we need a separate
+ // merge step?
+ }
break;
case STATISTICS:
@@ -2094,13 +2289,13 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
}
break;
- case LOCALLY_SCOPED_EXTERNAL_DECLS:
+ case LOCALLY_SCOPED_EXTERN_C_DECLS:
for (unsigned I = 0, N = Record.size(); I != N; ++I)
- LocallyScopedExternalDecls.push_back(getGlobalDeclID(F, Record[I]));
+ LocallyScopedExternCDecls.push_back(getGlobalDeclID(F, Record[I]));
break;
case SELECTOR_OFFSETS: {
- F.SelectorOffsets = (const uint32_t *)BlobStart;
+ F.SelectorOffsets = (const uint32_t *)Blob.data();
F.LocalNumSelectors = Record[0];
unsigned LocalBaseSelectorID = Record[1];
F.BaseSelectorID = getTotalNumSelectors();
@@ -2122,7 +2317,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
}
case METHOD_POOL:
- F.SelectorLookupTableData = (const unsigned char *)BlobStart;
+ F.SelectorLookupTableData = (const unsigned char *)Blob.data();
if (Record[0])
F.SelectorLookupTable
= ASTSelectorLookupTable::Create(
@@ -2149,12 +2344,12 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
break;
case FILE_SORTED_DECLS:
- F.FileSortedDecls = (const DeclID *)BlobStart;
+ F.FileSortedDecls = (const DeclID *)Blob.data();
F.NumFileSortedDecls = Record[0];
break;
case SOURCE_LOCATION_OFFSETS: {
- F.SLocEntryOffsets = (const uint32_t *)BlobStart;
+ F.SLocEntryOffsets = (const uint32_t *)Blob.data();
F.LocalNumSLocEntries = Record[0];
unsigned SLocSpaceSize = Record[1];
llvm::tie(F.SLocEntryBaseID, F.SLocEntryBaseOffset) =
@@ -2187,8 +2382,8 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
case MODULE_OFFSET_MAP: {
// Additional remapping information.
- const unsigned char *Data = (const unsigned char*)BlobStart;
- const unsigned char *DataEnd = Data + BlobLen;
+ const unsigned char *Data = (const unsigned char*)Blob.data();
+ const unsigned char *DataEnd = Data + Blob.size();
// Continuous range maps we may be updating in our module.
ContinuousRangeMap<uint32_t, int, 2>::Builder SLocRemap(F.SLocRemap);
@@ -2324,15 +2519,15 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
break;
case PPD_ENTITIES_OFFSETS: {
- F.PreprocessedEntityOffsets = (const PPEntityOffset *)BlobStart;
- assert(BlobLen % sizeof(PPEntityOffset) == 0);
- F.NumPreprocessedEntities = BlobLen / sizeof(PPEntityOffset);
+ F.PreprocessedEntityOffsets = (const PPEntityOffset *)Blob.data();
+ assert(Blob.size() % sizeof(PPEntityOffset) == 0);
+ F.NumPreprocessedEntities = Blob.size() / sizeof(PPEntityOffset);
unsigned LocalBasePreprocessedEntityID = Record[0];
unsigned StartingID;
if (!PP.getPreprocessingRecord())
- PP.createPreprocessingRecord(/*RecordConditionalDirectives=*/false);
+ PP.createPreprocessingRecord();
if (!PP.getPreprocessingRecord()->getExternalSource())
PP.getPreprocessingRecord()->SetExternalSource(*this);
StartingID
@@ -2384,7 +2579,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
}
F.LocalNumObjCCategoriesInMap = Record[0];
- F.ObjCCategoriesMap = (const ObjCCategoriesInfo *)BlobStart;
+ F.ObjCCategoriesMap = (const ObjCCategoriesInfo *)Blob.data();
break;
}
@@ -2399,7 +2594,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
}
F.LocalNumCXXBaseSpecifiers = Record[0];
- F.CXXBaseSpecifiersOffsets = (const uint32_t *)BlobStart;
+ F.CXXBaseSpecifiersOffsets = (const uint32_t *)Blob.data();
NumCXXBaseSpecifiersLoaded += F.LocalNumCXXBaseSpecifiers;
break;
}
@@ -2421,9 +2616,8 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
break;
case HEADER_SEARCH_TABLE: {
- F.HeaderFileInfoTableData = BlobStart;
+ F.HeaderFileInfoTableData = Blob.data();
F.LocalNumHeaderFileInfos = Record[1];
- F.HeaderFileFrameworkStrings = BlobStart + Record[2];
if (Record[0]) {
F.HeaderFileInfoTable
= HeaderFileInfoLookupTable::Create(
@@ -2431,7 +2625,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
(const unsigned char *)F.HeaderFileInfoTableData,
HeaderFileInfoTrait(*this, F,
&PP.getHeaderSearchInfo(),
- BlobStart + Record[2]));
+ Blob.data() + Record[2]));
PP.getHeaderSearchInfo().SetExternalSource(this);
if (!PP.getHeaderSearchInfo().getExternalLookup())
@@ -2459,7 +2653,24 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
for (unsigned I = 0, N = Record.size(); I != N; ++I)
KnownNamespaces.push_back(getGlobalDeclID(F, Record[I]));
break;
-
+
+ case UNDEFINED_BUT_USED:
+ if (UndefinedButUsed.size() % 2 != 0) {
+ Error("Invalid existing UndefinedButUsed");
+ return true;
+ }
+
+ if (Record.size() % 2 != 0) {
+ Error("invalid undefined-but-used record");
+ return true;
+ }
+ for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) {
+ UndefinedButUsed.push_back(getGlobalDeclID(F, Record[I++]));
+ UndefinedButUsed.push_back(
+ ReadSourceLocation(F, Record, I).getRawEncoding());
+ }
+ break;
+
case IMPORTED_MODULES: {
if (F.Kind != MK_Module) {
// If we aren't loading a module (which has its own exports), make
@@ -2485,7 +2696,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
}
F.LocalNumRedeclarationsInMap = Record[0];
- F.RedeclarationsMap = (const LocalRedeclarationsInfo *)BlobStart;
+ F.RedeclarationsMap = (const LocalRedeclarationsInfo *)Blob.data();
break;
}
@@ -2504,7 +2715,7 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
Error("duplicate MACRO_OFFSET record in AST file");
return true;
}
- F.MacroOffsets = (const uint32_t *)BlobStart;
+ F.MacroOffsets = (const uint32_t *)Blob.data();
F.LocalNumMacros = Record[0];
unsigned LocalBaseMacroID = Record[1];
F.BaseMacroID = getTotalNumMacros();
@@ -2523,60 +2734,73 @@ bool ASTReader::ReadASTBlock(ModuleFile &F) {
break;
}
- case MACRO_UPDATES: {
- for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) {
- MacroID ID = getGlobalMacroID(F, Record[I++]);
- if (I == N)
- break;
-
- 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));
- }
+ case MACRO_TABLE: {
+ // FIXME: Not used yet.
break;
}
}
}
- 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) {
- switch (Names[I].getKind()) {
- case HiddenName::Declaration:
- Names[I].getDecl()->Hidden = false;
- break;
+/// \brief Move the given method to the back of the global list of methods.
+static void moveMethodToBackOfGlobalList(Sema &S, ObjCMethodDecl *Method) {
+ // Find the entry for this selector in the method pool.
+ Sema::GlobalMethodPool::iterator Known
+ = S.MethodPool.find(Method->getSelector());
+ if (Known == S.MethodPool.end())
+ return;
- case HiddenName::MacroVisibility: {
- std::pair<IdentifierInfo *, MacroInfo *> Macro = Names[I].getMacro();
- Macro.second->setHidden(!Macro.second->isPublic());
- if (Macro.second->isDefined()) {
- PP.makeLoadedMacroInfoVisible(Macro.first, Macro.second);
+ // Retrieve the appropriate method list.
+ ObjCMethodList &Start = Method->isInstanceMethod()? Known->second.first
+ : Known->second.second;
+ bool Found = false;
+ for (ObjCMethodList *List = &Start; List; List = List->Next) {
+ if (!Found) {
+ if (List->Method == Method) {
+ Found = true;
+ } else {
+ // Keep searching.
+ continue;
}
- break;
}
- case HiddenName::MacroUndef: {
- std::pair<IdentifierInfo *, MacroInfo *> Macro = Names[I].getMacro();
- if (Macro.second->isDefined()) {
- Macro.second->setUndefLoc(Names[I].getMacroUndefLoc());
- if (PPMutationListener *Listener = PP.getPPMutationListener())
- Listener->UndefinedMacro(Macro.second);
- PP.makeLoadedMacroInfoVisible(Macro.first, Macro.second);
+ if (List->Next)
+ List->Method = List->Next->Method;
+ else
+ List->Method = Method;
+ }
+}
+
+void ASTReader::makeNamesVisible(const HiddenNames &Names, Module *Owner) {
+ for (unsigned I = 0, N = Names.size(); I != N; ++I) {
+ switch (Names[I].getKind()) {
+ case HiddenName::Declaration: {
+ Decl *D = Names[I].getDecl();
+ bool wasHidden = D->Hidden;
+ D->Hidden = false;
+
+ if (wasHidden && SemaObj) {
+ if (ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(D)) {
+ moveMethodToBackOfGlobalList(*SemaObj, Method);
+ }
}
break;
}
+ case HiddenName::MacroVisibility: {
+ std::pair<IdentifierInfo *, MacroDirective *> Macro = Names[I].getMacro();
+ installImportedMacro(Macro.first, Macro.second, Owner);
+ break;
+ }
}
}
}
void ASTReader::makeModuleVisible(Module *Mod,
- Module::NameVisibilityKind NameVisibility) {
+ Module::NameVisibilityKind NameVisibility,
+ SourceLocation ImportLoc,
+ bool Complain) {
llvm::SmallPtrSet<Module *, 4> Visited;
- llvm::SmallVector<Module *, 4> Stack;
+ SmallVector<Module *, 4> Stack;
Stack.push_back(Mod);
while (!Stack.empty()) {
Mod = Stack.back();
@@ -2600,7 +2824,7 @@ void ASTReader::makeModuleVisible(Module *Mod,
// mark them as visible.
HiddenNamesMapType::iterator Hidden = HiddenNamesMap.find(Mod);
if (Hidden != HiddenNamesMap.end()) {
- makeNamesVisible(Hidden->second);
+ makeNamesVisible(Hidden->second, Hidden->first);
HiddenNamesMap.erase(Hidden);
}
@@ -2614,80 +2838,86 @@ void ASTReader::makeModuleVisible(Module *Mod,
}
// Push any exported modules onto the stack to be marked as visible.
- bool AnyWildcard = false;
- bool UnrestrictedWildcard = false;
- llvm::SmallVector<Module *, 4> WildcardRestrictions;
- for (unsigned I = 0, N = Mod->Exports.size(); I != N; ++I) {
- Module *Exported = Mod->Exports[I].getPointer();
- if (!Mod->Exports[I].getInt()) {
- // Export a named module directly; no wildcards involved.
- if (Visited.insert(Exported))
- Stack.push_back(Exported);
-
- continue;
- }
-
- // Wildcard export: export all of the imported modules that match
- // the given pattern.
- AnyWildcard = true;
- if (UnrestrictedWildcard)
- continue;
-
- if (Module *Restriction = Mod->Exports[I].getPointer())
- WildcardRestrictions.push_back(Restriction);
- else {
- WildcardRestrictions.clear();
- UnrestrictedWildcard = true;
- }
- }
-
- // If there were any wildcards, push any imported modules that were
- // re-exported by the wildcard restriction.
- if (!AnyWildcard)
- continue;
-
- for (unsigned I = 0, N = Mod->Imports.size(); I != N; ++I) {
- Module *Imported = Mod->Imports[I];
- if (!Visited.insert(Imported))
- continue;
-
- bool Acceptable = UnrestrictedWildcard;
- if (!Acceptable) {
- // Check whether this module meets one of the restrictions.
- for (unsigned R = 0, NR = WildcardRestrictions.size(); R != NR; ++R) {
- Module *Restriction = WildcardRestrictions[R];
- if (Imported == Restriction || Imported->isSubModuleOf(Restriction)) {
- Acceptable = true;
- break;
- }
+ SmallVector<Module *, 16> Exports;
+ Mod->getExportedModules(Exports);
+ for (SmallVectorImpl<Module *>::iterator
+ I = Exports.begin(), E = Exports.end(); I != E; ++I) {
+ Module *Exported = *I;
+ if (Visited.insert(Exported))
+ Stack.push_back(Exported);
+ }
+
+ // Detect any conflicts.
+ if (Complain) {
+ assert(ImportLoc.isValid() && "Missing import location");
+ for (unsigned I = 0, N = Mod->Conflicts.size(); I != N; ++I) {
+ if (Mod->Conflicts[I].Other->NameVisibility >= NameVisibility) {
+ Diag(ImportLoc, diag::warn_module_conflict)
+ << Mod->getFullModuleName()
+ << Mod->Conflicts[I].Other->getFullModuleName()
+ << Mod->Conflicts[I].Message;
+ // FIXME: Need note where the other module was imported.
}
}
-
- if (!Acceptable)
- continue;
-
- Stack.push_back(Imported);
}
}
}
+bool ASTReader::loadGlobalIndex() {
+ if (GlobalIndex)
+ return false;
+
+ if (TriedLoadingGlobalIndex || !UseGlobalIndex ||
+ !Context.getLangOpts().Modules)
+ return true;
+
+ // Try to load the global index.
+ TriedLoadingGlobalIndex = true;
+ StringRef ModuleCachePath
+ = getPreprocessor().getHeaderSearchInfo().getModuleCachePath();
+ std::pair<GlobalModuleIndex *, GlobalModuleIndex::ErrorCode> Result
+ = GlobalModuleIndex::readIndex(ModuleCachePath);
+ if (!Result.first)
+ return true;
+
+ GlobalIndex.reset(Result.first);
+ ModuleMgr.setGlobalIndex(GlobalIndex.get());
+ return false;
+}
+
+bool ASTReader::isGlobalIndexUnavailable() const {
+ return Context.getLangOpts().Modules && UseGlobalIndex &&
+ !hasGlobalIndex() && TriedLoadingGlobalIndex;
+}
+
ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
ModuleKind Type,
+ SourceLocation ImportLoc,
unsigned ClientLoadCapabilities) {
// Bump the generation number.
unsigned PreviousGeneration = CurrentGeneration++;
unsigned NumModules = ModuleMgr.size();
- llvm::SmallVector<ModuleFile *, 4> Loaded;
- switch(ASTReadResult ReadResult = ReadASTCore(FileName, Type,
+ SmallVector<ImportedModule, 4> Loaded;
+ switch(ASTReadResult ReadResult = ReadASTCore(FileName, Type, ImportLoc,
/*ImportedBy=*/0, Loaded,
+ 0, 0,
ClientLoadCapabilities)) {
case Failure:
+ case Missing:
case OutOfDate:
case VersionMismatch:
case ConfigurationMismatch:
case HadErrors:
- ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, ModuleMgr.end());
+ ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, ModuleMgr.end(),
+ Context.getLangOpts().Modules
+ ? &PP.getHeaderSearchInfo().getModuleMap()
+ : 0);
+
+ // If we find that any modules are unusable, the global index is going
+ // to be out-of-date. Just remove it.
+ GlobalIndex.reset();
+ ModuleMgr.setGlobalIndex(0);
return ReadResult;
case Success:
@@ -2697,10 +2927,10 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
// Here comes stuff that we only do once the entire chain is loaded.
// Load the AST blocks of all of the modules that we loaded.
- for (llvm::SmallVectorImpl<ModuleFile *>::iterator M = Loaded.begin(),
- MEnd = Loaded.end();
+ for (SmallVectorImpl<ImportedModule>::iterator M = Loaded.begin(),
+ MEnd = Loaded.end();
M != MEnd; ++M) {
- ModuleFile &F = **M;
+ ModuleFile &F = *M->Mod;
// Read the AST block.
if (ReadASTBlock(F))
@@ -2723,6 +2953,24 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
}
}
+ // Setup the import locations and notify the module manager that we've
+ // committed to these module files.
+ for (SmallVectorImpl<ImportedModule>::iterator M = Loaded.begin(),
+ MEnd = Loaded.end();
+ M != MEnd; ++M) {
+ ModuleFile &F = *M->Mod;
+
+ ModuleMgr.moduleFileAccepted(&F);
+
+ // Set the import location.
+ F.DirectImportLoc = ImportLoc;
+ if (!M->ImportedBy)
+ F.ImportLoc = M->ImportLoc;
+ else
+ F.ImportLoc = ReadSourceLocation(*M->ImportedBy,
+ M->ImportLoc.getRawEncoding());
+ }
+
// 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
// identifier is used.
@@ -2732,22 +2980,34 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
Id->second->setOutOfDate(true);
// Resolve any unresolved module exports.
- for (unsigned I = 0, N = UnresolvedModuleImportExports.size(); I != N; ++I) {
- UnresolvedModuleImportExport &Unresolved = UnresolvedModuleImportExports[I];
+ for (unsigned I = 0, N = UnresolvedModuleRefs.size(); I != N; ++I) {
+ UnresolvedModuleRef &Unresolved = UnresolvedModuleRefs[I];
SubmoduleID GlobalID = getGlobalSubmoduleID(*Unresolved.File,Unresolved.ID);
Module *ResolvedMod = getSubmodule(GlobalID);
-
- if (Unresolved.IsImport) {
+
+ switch (Unresolved.Kind) {
+ case UnresolvedModuleRef::Conflict:
+ if (ResolvedMod) {
+ Module::Conflict Conflict;
+ Conflict.Other = ResolvedMod;
+ Conflict.Message = Unresolved.String.str();
+ Unresolved.Mod->Conflicts.push_back(Conflict);
+ }
+ continue;
+
+ case UnresolvedModuleRef::Import:
if (ResolvedMod)
Unresolved.Mod->Imports.push_back(ResolvedMod);
continue;
- }
- if (ResolvedMod || Unresolved.IsWildcard)
- Unresolved.Mod->Exports.push_back(
- Module::ExportDecl(ResolvedMod, Unresolved.IsWildcard));
+ case UnresolvedModuleRef::Export:
+ if (ResolvedMod || Unresolved.IsWildcard)
+ Unresolved.Mod->Exports.push_back(
+ Module::ExportDecl(ResolvedMod, Unresolved.IsWildcard));
+ continue;
+ }
}
- UnresolvedModuleImportExports.clear();
+ UnresolvedModuleRefs.clear();
InitializeContext();
@@ -2777,35 +3037,64 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
ObjCClassesLoaded[I],
PreviousGeneration);
}
-
+
return Success;
}
ASTReader::ASTReadResult
ASTReader::ReadASTCore(StringRef FileName,
ModuleKind Type,
+ SourceLocation ImportLoc,
ModuleFile *ImportedBy,
- llvm::SmallVectorImpl<ModuleFile *> &Loaded,
+ SmallVectorImpl<ImportedModule> &Loaded,
+ off_t ExpectedSize, time_t ExpectedModTime,
unsigned ClientLoadCapabilities) {
ModuleFile *M;
- bool NewModule;
std::string ErrorStr;
- llvm::tie(M, NewModule) = ModuleMgr.addModule(FileName, Type, ImportedBy,
- CurrentGeneration, ErrorStr);
-
- if (!M) {
- // We couldn't load the module.
- std::string Msg = "Unable to load module \"" + FileName.str() + "\": "
- + ErrorStr;
- Error(Msg);
- return Failure;
- }
+ ModuleManager::AddModuleResult AddResult
+ = ModuleMgr.addModule(FileName, Type, ImportLoc, ImportedBy,
+ CurrentGeneration, ExpectedSize, ExpectedModTime,
+ M, ErrorStr);
- if (!NewModule) {
- // We've already loaded this module.
+ switch (AddResult) {
+ case ModuleManager::AlreadyLoaded:
return Success;
+
+ case ModuleManager::NewlyLoaded:
+ // Load module file below.
+ break;
+
+ case ModuleManager::Missing:
+ // The module file was missing; if the client handle handle, that, return
+ // it.
+ if (ClientLoadCapabilities & ARR_Missing)
+ return Missing;
+
+ // Otherwise, return an error.
+ {
+ std::string Msg = "Unable to load module \"" + FileName.str() + "\": "
+ + ErrorStr;
+ Error(Msg);
+ }
+ return Failure;
+
+ case ModuleManager::OutOfDate:
+ // We couldn't load the module file because it is out-of-date. If the
+ // client can handle out-of-date, return it.
+ if (ClientLoadCapabilities & ARR_OutOfDate)
+ return OutOfDate;
+
+ // Otherwise, return an error.
+ {
+ std::string Msg = "Unable to load module \"" + FileName.str() + "\": "
+ + ErrorStr;
+ Error(Msg);
+ }
+ return Failure;
}
+ assert(M && "Missing module file");
+
// FIXME: This seems rather a hack. Should CurrentDir be part of the
// module?
if (FileName != "-") {
@@ -2814,7 +3103,7 @@ ASTReader::ReadASTCore(StringRef FileName,
}
ModuleFile &F = *M;
- llvm::BitstreamCursor &Stream = F.Stream;
+ BitstreamCursor &Stream = F.Stream;
Stream.init(F.StreamFile);
F.SizeInBits = F.Buffer->getBufferSize() * 8;
@@ -2827,18 +3116,25 @@ ASTReader::ReadASTCore(StringRef FileName,
return Failure;
}
- while (!Stream.AtEndOfStream()) {
- unsigned Code = Stream.ReadCode();
+ // This is used for compatibility with older PCH formats.
+ bool HaveReadControlBlock = false;
- if (Code != llvm::bitc::ENTER_SUBBLOCK) {
+ while (1) {
+ llvm::BitstreamEntry Entry = Stream.advance();
+
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::Error:
+ case llvm::BitstreamEntry::EndBlock:
+ case llvm::BitstreamEntry::Record:
Error("invalid record at top-level of AST file");
return Failure;
+
+ case llvm::BitstreamEntry::SubBlock:
+ break;
}
- unsigned BlockID = Stream.ReadSubBlockID();
-
// We only know the control subblock ID.
- switch (BlockID) {
+ switch (Entry.ID) {
case llvm::bitc::BLOCKINFO_BLOCK_ID:
if (Stream.ReadBlockInfoBlock()) {
Error("malformed BlockInfoBlock in AST file");
@@ -2846,11 +3142,13 @@ ASTReader::ReadASTCore(StringRef FileName,
}
break;
case CONTROL_BLOCK_ID:
+ HaveReadControlBlock = true;
switch (ReadControlBlock(F, Loaded, ClientLoadCapabilities)) {
case Success:
break;
case Failure: return Failure;
+ case Missing: return Missing;
case OutOfDate: return OutOfDate;
case VersionMismatch: return VersionMismatch;
case ConfigurationMismatch: return ConfigurationMismatch;
@@ -2858,8 +3156,14 @@ ASTReader::ReadASTCore(StringRef FileName,
}
break;
case AST_BLOCK_ID:
+ if (!HaveReadControlBlock) {
+ if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0)
+ Diag(diag::warn_pch_version_too_old);
+ return VersionMismatch;
+ }
+
// Record that we've loaded this module.
- Loaded.push_back(M);
+ Loaded.push_back(ImportedModule(M, ImportedBy, ImportLoc));
return Success;
default:
@@ -3004,7 +3308,9 @@ void ASTReader::InitializeContext() {
// Re-export any modules that were imported by a non-module AST file.
for (unsigned I = 0, N = ImportedModules.size(); I != N; ++I) {
if (Module *Imported = getSubmodule(ImportedModules[I]))
- makeModuleVisible(Imported, Module::AllVisible);
+ makeModuleVisible(Imported, Module::AllVisible,
+ /*ImportLoc=*/SourceLocation(),
+ /*Complain=*/false);
}
ImportedModules.clear();
}
@@ -3013,11 +3319,41 @@ void ASTReader::finalizeForWriting() {
for (HiddenNamesMapType::iterator Hidden = HiddenNamesMap.begin(),
HiddenEnd = HiddenNamesMap.end();
Hidden != HiddenEnd; ++Hidden) {
- makeNamesVisible(Hidden->second);
+ makeNamesVisible(Hidden->second, Hidden->first);
}
HiddenNamesMap.clear();
}
+/// SkipCursorToControlBlock - Given a cursor at the start of an AST file, scan
+/// ahead and drop the cursor into the start of the CONTROL_BLOCK, returning
+/// false on success and true on failure.
+static bool SkipCursorToControlBlock(BitstreamCursor &Cursor) {
+ while (1) {
+ llvm::BitstreamEntry Entry = Cursor.advance();
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::Error:
+ case llvm::BitstreamEntry::EndBlock:
+ return true;
+
+ case llvm::BitstreamEntry::Record:
+ // Ignore top-level records.
+ Cursor.skipRecord(Entry.ID);
+ break;
+
+ case llvm::BitstreamEntry::SubBlock:
+ if (Entry.ID == CONTROL_BLOCK_ID) {
+ if (Cursor.EnterSubBlock(CONTROL_BLOCK_ID))
+ return true;
+ // Found it!
+ return false;
+ }
+
+ if (Cursor.SkipBlock())
+ return true;
+ }
+ }
+}
+
/// \brief Retrieve the name of the original source file name
/// directly from the AST file, without actually loading the AST
/// file.
@@ -3035,7 +3371,7 @@ std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName,
// Initialize the stream
llvm::BitstreamReader StreamFile;
- llvm::BitstreamCursor Stream;
+ BitstreamCursor Stream;
StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
(const unsigned char *)Buffer->getBufferEnd());
Stream.init(StreamFile);
@@ -3048,54 +3384,30 @@ std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName,
Diags.Report(diag::err_fe_not_a_pch_file) << ASTFileName;
return std::string();
}
+
+ // Scan for the CONTROL_BLOCK_ID block.
+ if (SkipCursorToControlBlock(Stream)) {
+ Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName;
+ return std::string();
+ }
+ // Scan for ORIGINAL_FILE inside the control block.
RecordData Record;
- while (!Stream.AtEndOfStream()) {
- unsigned Code = Stream.ReadCode();
-
- if (Code == llvm::bitc::ENTER_SUBBLOCK) {
- unsigned BlockID = Stream.ReadSubBlockID();
-
- // We only know the AST subblock ID.
- switch (BlockID) {
- case CONTROL_BLOCK_ID:
- if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) {
- Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName;
- return std::string();
- }
- break;
-
- default:
- if (Stream.SkipBlock()) {
- Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName;
- return std::string();
- }
- break;
- }
- continue;
- }
-
- if (Code == llvm::bitc::END_BLOCK) {
- if (Stream.ReadBlockEnd()) {
- Diags.Report(diag::err_fe_pch_error_at_end_block) << ASTFileName;
- return std::string();
- }
- continue;
- }
-
- if (Code == llvm::bitc::DEFINE_ABBREV) {
- Stream.ReadAbbrevRecord();
- continue;
+ while (1) {
+ llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
+ if (Entry.Kind == llvm::BitstreamEntry::EndBlock)
+ return std::string();
+
+ if (Entry.Kind != llvm::BitstreamEntry::Record) {
+ Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName;
+ return std::string();
}
-
+
Record.clear();
- const char *BlobStart = 0;
- unsigned BlobLen = 0;
- if (Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen) == ORIGINAL_FILE)
- return std::string(BlobStart, BlobLen);
+ StringRef Blob;
+ if (Stream.readRecord(Entry.ID, Record, &Blob) == ORIGINAL_FILE)
+ return Blob.str();
}
-
- return std::string();
}
namespace {
@@ -3147,7 +3459,7 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename,
// Initialize the stream
llvm::BitstreamReader StreamFile;
- llvm::BitstreamCursor Stream;
+ BitstreamCursor Stream;
StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
(const unsigned char *)Buffer->getBufferEnd());
Stream.init(StreamFile);
@@ -3160,105 +3472,71 @@ bool ASTReader::readASTFileControlBlock(StringRef Filename,
return true;
}
+ // Scan for the CONTROL_BLOCK_ID block.
+ if (SkipCursorToControlBlock(Stream))
+ return true;
+
+ // Scan for ORIGINAL_FILE inside the control block.
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()) {
+ while (1) {
+ llvm::BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
+ if (Entry.Kind == llvm::BitstreamEntry::EndBlock)
+ return false;
+
+ if (Entry.Kind != llvm::BitstreamEntry::Record)
+ return true;
+
+ Record.clear();
+ StringRef Blob;
+ unsigned RecCode = Stream.readRecord(Entry.ID, Record, &Blob);
+ switch ((ControlRecordTypes)RecCode) {
+ case METADATA: {
+ if (Record[0] != VERSION_MAJOR)
return true;
- }
- InControlBlock = false;
- continue;
- }
-
- if (Code == llvm::bitc::DEFINE_ABBREV) {
- Stream.ReadAbbrevRecord();
- continue;
+ if (Listener.ReadFullVersionInformation(Blob))
+ return true;
+
+ break;
}
+ case LANGUAGE_OPTIONS:
+ if (ParseLanguageOptions(Record, false, Listener))
+ return true;
+ break;
- 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 TARGET_OPTIONS:
+ if (ParseTargetOptions(Record, false, Listener))
+ return true;
+ break;
- case DIAGNOSTIC_OPTIONS:
- if (ParseDiagnosticOptions(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 FILE_SYSTEM_OPTIONS:
+ if (ParseFileSystemOptions(Record, false, Listener))
+ return true;
+ break;
- case HEADER_SEARCH_OPTIONS:
- if (ParseHeaderSearchOptions(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;
- }
+ case PREPROCESSOR_OPTIONS: {
+ std::string IgnoredSuggestedPredefines;
+ if (ParsePreprocessorOptions(Record, false, Listener,
+ IgnoredSuggestedPredefines))
+ return true;
+ break;
+ }
- default:
- // No other validation to perform.
- break;
- }
+ default:
+ // No other validation to perform.
+ break;
}
}
-
- return false;
}
@@ -3283,35 +3561,24 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
Module *CurrentModule = 0;
RecordData Record;
while (true) {
- unsigned Code = F.Stream.ReadCode();
- if (Code == llvm::bitc::END_BLOCK) {
- if (F.Stream.ReadBlockEnd()) {
- Error("error at end of submodule block in AST file");
- return true;
- }
- return false;
- }
+ llvm::BitstreamEntry Entry = F.Stream.advanceSkippingSubblocks();
- if (Code == llvm::bitc::ENTER_SUBBLOCK) {
- // No known subblocks, always skip them.
- F.Stream.ReadSubBlockID();
- if (F.Stream.SkipBlock()) {
- Error("malformed block record in AST file");
- return true;
- }
- continue;
- }
-
- if (Code == llvm::bitc::DEFINE_ABBREV) {
- F.Stream.ReadAbbrevRecord();
- continue;
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::SubBlock: // Handled for us already.
+ case llvm::BitstreamEntry::Error:
+ Error("malformed block record in AST file");
+ return true;
+ case llvm::BitstreamEntry::EndBlock:
+ return false;
+ case llvm::BitstreamEntry::Record:
+ // The interesting case.
+ break;
}
-
+
// Read a record.
- const char *BlobStart;
- unsigned BlobLen;
+ StringRef Blob;
Record.clear();
- switch (F.Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen)) {
+ switch (F.Stream.readRecord(Entry.ID, Record, &Blob)) {
default: // Default behavior: ignore.
break;
@@ -3321,12 +3588,12 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
return true;
}
- if (Record.size() < 7) {
+ if (Record.size() < 8) {
Error("malformed module definition");
return true;
}
- StringRef Name(BlobStart, BlobLen);
+ StringRef Name = Blob;
SubmoduleID GlobalID = getGlobalSubmoduleID(F, Record[0]);
SubmoduleID Parent = getGlobalSubmoduleID(F, Record[1]);
bool IsFramework = Record[2];
@@ -3335,7 +3602,8 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
bool InferSubmodules = Record[5];
bool InferExplicitSubmodules = Record[6];
bool InferExportWildcard = Record[7];
-
+ bool ConfigMacrosExhaustive = Record[8];
+
Module *ParentModule = 0;
if (Parent)
ParentModule = getSubmodule(Parent);
@@ -3351,17 +3619,39 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
Error("too many submodules");
return true;
}
+
+ if (!ParentModule) {
+ if (const FileEntry *CurFile = CurrentModule->getASTFile()) {
+ if (CurFile != F.File) {
+ if (!Diags.isDiagnosticInFlight()) {
+ Diag(diag::err_module_file_conflict)
+ << CurrentModule->getTopLevelModuleName()
+ << CurFile->getName()
+ << F.File->getName();
+ }
+ return true;
+ }
+ }
+
+ CurrentModule->setASTFile(F.File);
+ }
- CurrentModule->setASTFile(F.File);
CurrentModule->IsFromModuleFile = true;
CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem;
CurrentModule->InferSubmodules = InferSubmodules;
CurrentModule->InferExplicitSubmodules = InferExplicitSubmodules;
CurrentModule->InferExportWildcard = InferExportWildcard;
+ CurrentModule->ConfigMacrosExhaustive = ConfigMacrosExhaustive;
if (DeserializationListener)
DeserializationListener->ModuleRead(GlobalID, CurrentModule);
SubmodulesLoaded[GlobalIndex] = CurrentModule;
+
+ // Clear out data that will be replaced by what is the module file.
+ CurrentModule->LinkLibraries.clear();
+ CurrentModule->ConfigMacros.clear();
+ CurrentModule->UnresolvedConflicts.clear();
+ CurrentModule->Conflicts.clear();
break;
}
@@ -3374,8 +3664,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
if (!CurrentModule)
break;
- StringRef FileName(BlobStart, BlobLen);
- if (const FileEntry *Umbrella = PP.getFileManager().getFile(FileName)) {
+ if (const FileEntry *Umbrella = PP.getFileManager().getFile(Blob)) {
if (!CurrentModule->getUmbrellaHeader())
ModMap.setUmbrellaHeader(CurrentModule, Umbrella);
else if (CurrentModule->getUmbrellaHeader() != Umbrella) {
@@ -3395,14 +3684,9 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
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, false);
- }
+ // We lazily associate headers with their modules via the HeaderInfoTable.
+ // FIXME: Re-evaluate this section; maybe only store InputFile IDs instead
+ // of complete filenames or remove it entirely.
break;
}
@@ -3415,14 +3699,9 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
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);
- }
+ // We lazily associate headers with their modules via the HeaderInfoTable.
+ // FIXME: Re-evaluate this section; maybe only store InputFile IDs instead
+ // of complete filenames or remove it entirely.
break;
}
@@ -3435,10 +3714,7 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
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);
+ CurrentModule->addTopHeaderFilename(Blob);
break;
}
@@ -3451,9 +3727,8 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
if (!CurrentModule)
break;
- StringRef DirName(BlobStart, BlobLen);
if (const DirectoryEntry *Umbrella
- = PP.getFileManager().getDirectory(DirName)) {
+ = PP.getFileManager().getDirectory(Blob)) {
if (!CurrentModule->getUmbrellaDir())
ModMap.setUmbrellaDir(CurrentModule, Umbrella);
else if (CurrentModule->getUmbrellaDir() != Umbrella) {
@@ -3500,13 +3775,13 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
break;
for (unsigned Idx = 0; Idx != Record.size(); ++Idx) {
- UnresolvedModuleImportExport Unresolved;
+ UnresolvedModuleRef Unresolved;
Unresolved.File = &F;
Unresolved.Mod = CurrentModule;
Unresolved.ID = Record[Idx];
- Unresolved.IsImport = true;
+ Unresolved.Kind = UnresolvedModuleRef::Import;
Unresolved.IsWildcard = false;
- UnresolvedModuleImportExports.push_back(Unresolved);
+ UnresolvedModuleRefs.push_back(Unresolved);
}
break;
}
@@ -3521,13 +3796,13 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
break;
for (unsigned Idx = 0; Idx + 1 < Record.size(); Idx += 2) {
- UnresolvedModuleImportExport Unresolved;
+ UnresolvedModuleRef Unresolved;
Unresolved.File = &F;
Unresolved.Mod = CurrentModule;
Unresolved.ID = Record[Idx];
- Unresolved.IsImport = false;
+ Unresolved.Kind = UnresolvedModuleRef::Export;
Unresolved.IsWildcard = Record[Idx + 1];
- UnresolvedModuleImportExports.push_back(Unresolved);
+ UnresolvedModuleRefs.push_back(Unresolved);
}
// Once we've loaded the set of exports, there's no reason to keep
@@ -3544,11 +3819,55 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) {
if (!CurrentModule)
break;
- CurrentModule->addRequirement(StringRef(BlobStart, BlobLen),
- Context.getLangOpts(),
+ CurrentModule->addRequirement(Blob, Context.getLangOpts(),
Context.getTargetInfo());
break;
}
+
+ case SUBMODULE_LINK_LIBRARY:
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return true;
+ }
+
+ if (!CurrentModule)
+ break;
+
+ CurrentModule->LinkLibraries.push_back(
+ Module::LinkLibrary(Blob, Record[0]));
+ break;
+
+ case SUBMODULE_CONFIG_MACRO:
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return true;
+ }
+
+ if (!CurrentModule)
+ break;
+
+ CurrentModule->ConfigMacros.push_back(Blob.str());
+ break;
+
+ case SUBMODULE_CONFLICT: {
+ if (First) {
+ Error("missing submodule metadata record at beginning of block");
+ return true;
+ }
+
+ if (!CurrentModule)
+ break;
+
+ UnresolvedModuleRef Unresolved;
+ Unresolved.File = &F;
+ Unresolved.Mod = CurrentModule;
+ Unresolved.ID = Record[0];
+ Unresolved.Kind = UnresolvedModuleRef::Conflict;
+ Unresolved.IsWildcard = false;
+ Unresolved.String = Blob;
+ UnresolvedModuleRefs.push_back(Unresolved);
+ break;
+ }
}
}
}
@@ -3570,6 +3889,8 @@ bool ASTReader::ParseLanguageOptions(const RecordData &Record,
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
LangOpts.set##Name(static_cast<LangOptions::Type>(Record[Idx++]));
#include "clang/Basic/LangOptions.def"
+#define SANITIZER(NAME, ID) LangOpts.Sanitize.ID = Record[Idx++];
+#include "clang/Basic/Sanitizers.def"
ObjCRuntime::Kind runtimeKind = (ObjCRuntime::Kind) Record[Idx++];
VersionTuple runtimeVersion = ReadVersionTuple(Record, Idx);
@@ -3578,6 +3899,15 @@ bool ASTReader::ParseLanguageOptions(const RecordData &Record,
unsigned Length = Record[Idx++];
LangOpts.CurrentModule.assign(Record.begin() + Idx,
Record.begin() + Idx + Length);
+
+ Idx += Length;
+
+ // Comment options.
+ for (unsigned N = Record[Idx++]; N; --N) {
+ LangOpts.CommentOpts.BlockCommandNames.push_back(
+ ReadString(Record, Idx));
+ }
+
return Listener.ReadLanguageOptions(LangOpts, Complain);
}
@@ -3637,14 +3967,10 @@ bool ASTReader::ParseHeaderSearchOptions(const RecordData &Record,
std::string Path = ReadString(Record, Idx);
frontend::IncludeDirGroup Group
= static_cast<frontend::IncludeDirGroup>(Record[Idx++]);
- bool IsUserSupplied = Record[Idx++];
bool IsFramework = Record[Idx++];
bool IgnoreSysRoot = Record[Idx++];
- bool IsInternal = Record[Idx++];
- bool ImplicitExternC = Record[Idx++];
HSOpts.UserEntries.push_back(
- HeaderSearchOptions::Entry(Path, Group, IsUserSupplied, IsFramework,
- IgnoreSysRoot, IsInternal, ImplicitExternC));
+ HeaderSearchOptions::Entry(Path, Group, IsFramework, IgnoreSysRoot));
}
// System header prefixes.
@@ -3735,41 +4061,28 @@ PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) {
unsigned LocalIndex = PPInfo.second;
const PPEntityOffset &PPOffs = M.PreprocessedEntityOffsets[LocalIndex];
- SavedStreamPosition SavedPosition(M.PreprocessorDetailCursor);
- M.PreprocessorDetailCursor.JumpToBit(PPOffs.BitOffset);
-
- unsigned Code = M.PreprocessorDetailCursor.ReadCode();
- switch (Code) {
- case llvm::bitc::END_BLOCK:
- return 0;
-
- case llvm::bitc::ENTER_SUBBLOCK:
- Error("unexpected subblock record in preprocessor detail block");
- return 0;
-
- case llvm::bitc::DEFINE_ABBREV:
- Error("unexpected abbrevation record in preprocessor detail block");
- return 0;
-
- default:
- break;
- }
-
if (!PP.getPreprocessingRecord()) {
Error("no preprocessing record");
return 0;
}
+ SavedStreamPosition SavedPosition(M.PreprocessorDetailCursor);
+ M.PreprocessorDetailCursor.JumpToBit(PPOffs.BitOffset);
+
+ llvm::BitstreamEntry Entry =
+ M.PreprocessorDetailCursor.advance(BitstreamCursor::AF_DontPopBlockAtEnd);
+ if (Entry.Kind != llvm::BitstreamEntry::Record)
+ return 0;
+
// Read the record.
SourceRange Range(ReadSourceLocation(M, PPOffs.Begin),
ReadSourceLocation(M, PPOffs.End));
PreprocessingRecord &PPRec = *PP.getPreprocessingRecord();
- const char *BlobStart = 0;
- unsigned BlobLen = 0;
+ StringRef Blob;
RecordData Record;
PreprocessorDetailRecordTypes RecType =
- (PreprocessorDetailRecordTypes)M.PreprocessorDetailCursor.ReadRecord(
- Code, Record, BlobStart, BlobLen);
+ (PreprocessorDetailRecordTypes)M.PreprocessorDetailCursor.readRecord(
+ Entry.ID, Record, &Blob);
switch (RecType) {
case PPD_MACRO_EXPANSION: {
bool isBuiltin = Record[0];
@@ -3806,8 +4119,8 @@ PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) {
}
case PPD_INCLUSION_DIRECTIVE: {
- const char *FullFileNameStart = BlobStart + Record[0];
- StringRef FullFileName(FullFileNameStart, BlobLen - Record[0]);
+ const char *FullFileNameStart = Blob.data() + Record[0];
+ StringRef FullFileName(FullFileNameStart, Blob.size() - Record[0]);
const FileEntry *File = 0;
if (!FullFileName.empty())
File = PP.getFileManager().getFile(FullFileName);
@@ -3817,7 +4130,7 @@ PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) {
= static_cast<InclusionDirective::InclusionKind>(Record[2]);
InclusionDirective *ID
= new (PPRec) InclusionDirective(PPRec, Kind,
- StringRef(BlobStart, Record[0]),
+ StringRef(Blob.data(), Record[0]),
Record[1], Record[3],
File,
Range);
@@ -3885,7 +4198,7 @@ ASTReader::findBeginPreprocessedEntity(SourceLocation BLoc) const {
GlobalSLocOffsetMapType::const_iterator
SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset -
- BLoc.getOffset());
+ BLoc.getOffset() - 1);
assert(SLocMapI != GlobalSLocOffsetMap.end() &&
"Corrupted global sloc offset map");
@@ -3933,7 +4246,7 @@ ASTReader::findEndPreprocessedEntity(SourceLocation ELoc) const {
GlobalSLocOffsetMapType::const_iterator
SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset -
- ELoc.getOffset());
+ ELoc.getOffset() - 1);
assert(SLocMapI != GlobalSLocOffsetMap.end() &&
"Corrupted global sloc offset map");
@@ -3969,7 +4282,7 @@ std::pair<unsigned, unsigned>
/// \brief Optionally returns true or false if the preallocated preprocessed
/// entity with index \arg Index came from file \arg FID.
-llvm::Optional<bool> ASTReader::isPreprocessedEntityInFileID(unsigned Index,
+Optional<bool> ASTReader::isPreprocessedEntityInFileID(unsigned Index,
FileID FID) {
if (FID.isInvalid())
return false;
@@ -3992,32 +4305,25 @@ llvm::Optional<bool> ASTReader::isPreprocessedEntityInFileID(unsigned Index,
namespace {
/// \brief Visitor used to search for information about a header file.
class HeaderFileInfoVisitor {
- ASTReader &Reader;
const FileEntry *FE;
- llvm::Optional<HeaderFileInfo> HFI;
+ Optional<HeaderFileInfo> HFI;
public:
- HeaderFileInfoVisitor(ASTReader &Reader, const FileEntry *FE)
- : Reader(Reader), FE(FE) { }
+ explicit HeaderFileInfoVisitor(const FileEntry *FE)
+ : FE(FE) { }
static bool visit(ModuleFile &M, void *UserData) {
HeaderFileInfoVisitor *This
= static_cast<HeaderFileInfoVisitor *>(UserData);
- HeaderFileInfoTrait Trait(This->Reader, M,
- &This->Reader.getPreprocessor().getHeaderSearchInfo(),
- M.HeaderFileFrameworkStrings,
- This->FE->getName());
-
HeaderFileInfoLookupTable *Table
= static_cast<HeaderFileInfoLookupTable *>(M.HeaderFileInfoTable);
if (!Table)
return false;
// Look in the on-disk hash table for an entry for this file name.
- HeaderFileInfoLookupTable::iterator Pos = Table->find(This->FE->getName(),
- &Trait);
+ HeaderFileInfoLookupTable::iterator Pos = Table->find(This->FE);
if (Pos == Table->end())
return false;
@@ -4025,14 +4331,14 @@ namespace {
return true;
}
- llvm::Optional<HeaderFileInfo> getHeaderFileInfo() const { return HFI; }
+ Optional<HeaderFileInfo> getHeaderFileInfo() const { return HFI; }
};
}
HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) {
- HeaderFileInfoVisitor Visitor(*this, FE);
+ HeaderFileInfoVisitor Visitor(FE);
ModuleMgr.visit(&HeaderFileInfoVisitor::visit, &Visitor);
- if (llvm::Optional<HeaderFileInfo> HFI = Visitor.getHeaderFileInfo()) {
+ if (Optional<HeaderFileInfo> HFI = Visitor.getHeaderFileInfo()) {
if (Listener)
Listener->ReadHeaderFileInfo(*HFI, FE->getUID());
return *HFI;
@@ -4043,7 +4349,7 @@ HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) {
void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
// FIXME: Make it work properly with modules.
- llvm::SmallVector<DiagnosticsEngine::DiagState *, 32> DiagStates;
+ SmallVector<DiagnosticsEngine::DiagState *, 32> DiagStates;
for (ModuleIterator I = ModuleMgr.begin(), E = ModuleMgr.end(); I != E; ++I) {
ModuleFile &F = *(*I);
unsigned Idx = 0;
@@ -4103,7 +4409,7 @@ ASTReader::RecordLocation ASTReader::TypeCursorForIndex(unsigned Index) {
/// IDs.
QualType ASTReader::readTypeRecord(unsigned Index) {
RecordLocation Loc = TypeCursorForIndex(Index);
- llvm::BitstreamCursor &DeclsCursor = Loc.F->DeclsCursor;
+ BitstreamCursor &DeclsCursor = Loc.F->DeclsCursor;
// Keep track of where we are in the stream, then jump back there
// after reading this type.
@@ -4118,7 +4424,7 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
DeclsCursor.JumpToBit(Loc.Offset);
RecordData Record;
unsigned Code = DeclsCursor.ReadCode();
- switch ((TypeCode)DeclsCursor.ReadRecord(Code, Record)) {
+ switch ((TypeCode)DeclsCursor.readRecord(Code, Record)) {
case TYPE_EXT_QUAL: {
if (Record.size() != 2) {
Error("Incorrect encoding of extended qualifier type");
@@ -4287,8 +4593,7 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
} else if (EST == EST_Unevaluated) {
EPI.ExceptionSpecDecl = ReadDeclAs<FunctionDecl>(*Loc.F, Record, Idx);
}
- return Context.getFunctionType(ResultType, ParamTypes.data(), NumParams,
- EPI);
+ return Context.getFunctionType(ResultType, ParamTypes, EPI);
}
case TYPE_UNRESOLVED_USING: {
@@ -4392,7 +4697,7 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
QualType Pattern = readType(*Loc.F, Record, Idx);
if (Pattern.isNull())
return QualType();
- llvm::Optional<unsigned> NumExpansions;
+ Optional<unsigned> NumExpansions;
if (Record[1])
NumExpansions = Record[1] - 1;
return Context.getPackExpansionType(Pattern, NumExpansions);
@@ -4834,6 +5139,14 @@ QualType ASTReader::GetType(TypeID ID) {
case PREDEF_TYPE_OBJC_ID: T = Context.ObjCBuiltinIdTy; break;
case PREDEF_TYPE_OBJC_CLASS: T = Context.ObjCBuiltinClassTy; break;
case PREDEF_TYPE_OBJC_SEL: T = Context.ObjCBuiltinSelTy; break;
+ case PREDEF_TYPE_IMAGE1D_ID: T = Context.OCLImage1dTy; break;
+ case PREDEF_TYPE_IMAGE1D_ARR_ID: T = Context.OCLImage1dArrayTy; break;
+ case PREDEF_TYPE_IMAGE1D_BUFF_ID: T = Context.OCLImage1dBufferTy; break;
+ case PREDEF_TYPE_IMAGE2D_ID: T = Context.OCLImage2dTy; break;
+ case PREDEF_TYPE_IMAGE2D_ARR_ID: T = Context.OCLImage2dArrayTy; break;
+ case PREDEF_TYPE_IMAGE3D_ID: T = Context.OCLImage3dTy; break;
+ case PREDEF_TYPE_SAMPLER_ID: T = Context.OCLSamplerTy; break;
+ case PREDEF_TYPE_EVENT_ID: T = Context.OCLEventTy; break;
case PREDEF_TYPE_AUTO_DEDUCT: T = Context.getAutoDeductType(); break;
case PREDEF_TYPE_AUTO_RREF_DEDUCT:
@@ -4957,13 +5270,13 @@ uint64_t ASTReader::readCXXBaseSpecifiers(ModuleFile &M, const RecordData &Recor
CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
RecordLocation Loc = getLocalBitOffset(Offset);
- llvm::BitstreamCursor &Cursor = Loc.F->DeclsCursor;
+ BitstreamCursor &Cursor = Loc.F->DeclsCursor;
SavedStreamPosition SavedPosition(Cursor);
Cursor.JumpToBit(Loc.Offset);
ReadingKindTracker ReadingKind(Read_Decl, *this);
RecordData Record;
unsigned Code = Cursor.ReadCode();
- unsigned RecCode = Cursor.ReadRecord(Code, Record);
+ unsigned RecCode = Cursor.readRecord(Code, Record);
if (RecCode != DECL_CXX_BASE_SPECIFIERS) {
Error("Malformed AST file: missing C++ base specifiers");
return 0;
@@ -4997,7 +5310,7 @@ bool ASTReader::isDeclIDFromModule(serialization::GlobalDeclID ID,
return &M == I->second;
}
-ModuleFile *ASTReader::getOwningModuleFile(Decl *D) {
+ModuleFile *ASTReader::getOwningModuleFile(const Decl *D) {
if (!D->isFromASTFile())
return 0;
GlobalDeclMapType::const_iterator I = GlobalDeclMap.find(D->getGlobalID());
@@ -5269,7 +5582,7 @@ namespace {
/// declaration context.
class DeclContextNameLookupVisitor {
ASTReader &Reader;
- llvm::SmallVectorImpl<const DeclContext *> &Contexts;
+ SmallVectorImpl<const DeclContext *> &Contexts;
DeclarationName Name;
SmallVectorImpl<NamedDecl *> &Decls;
@@ -5333,14 +5646,34 @@ namespace {
};
}
-DeclContext::lookup_result
+/// \brief Retrieve the "definitive" module file for the definition of the
+/// given declaration context, if there is one.
+///
+/// The "definitive" module file is the only place where we need to look to
+/// find information about the declarations within the given declaration
+/// context. For example, C++ and Objective-C classes, C structs/unions, and
+/// Objective-C protocols, categories, and extensions are all defined in a
+/// single place in the source code, so they have definitive module files
+/// associated with them. C++ namespaces, on the other hand, can have
+/// definitions in multiple different module files.
+///
+/// Note: this needs to be kept in sync with ASTWriter::AddedVisibleDecl's
+/// NDEBUG checking.
+static ModuleFile *getDefinitiveModuleFileFor(const DeclContext *DC,
+ ASTReader &Reader) {
+ if (const DeclContext *DefDC = getDefinitiveDeclContext(DC))
+ return Reader.getOwningModuleFile(cast<Decl>(DefDC));
+
+ return 0;
+}
+
+bool
ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC,
DeclarationName Name) {
assert(DC->hasExternalVisibleStorage() &&
"DeclContext has no visible decls in storage");
if (!Name)
- return DeclContext::lookup_result(DeclContext::lookup_iterator(0),
- DeclContext::lookup_iterator(0));
+ return false;
SmallVector<NamedDecl *, 64> Decls;
@@ -5361,10 +5694,19 @@ ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC,
}
DeclContextNameLookupVisitor Visitor(*this, Contexts, Name, Decls);
- ModuleMgr.visit(&DeclContextNameLookupVisitor::visit, &Visitor);
+
+ // If we can definitively determine which module file to look into,
+ // only look there. Otherwise, look in all module files.
+ ModuleFile *Definitive;
+ if (Contexts.size() == 1 &&
+ (Definitive = getDefinitiveModuleFileFor(DC, *this))) {
+ DeclContextNameLookupVisitor::visit(*Definitive, &Visitor);
+ } else {
+ ModuleMgr.visit(&DeclContextNameLookupVisitor::visit, &Visitor);
+ }
++NumVisibleDeclContextsRead;
SetExternalVisibleDeclsForName(DC, Name, Decls);
- return const_cast<DeclContext*>(DC)->lookup(Name);
+ return !Decls.empty();
}
namespace {
@@ -5372,15 +5714,17 @@ namespace {
/// declaration context.
class DeclContextAllNamesVisitor {
ASTReader &Reader;
- llvm::SmallVectorImpl<const DeclContext *> &Contexts;
+ SmallVectorImpl<const DeclContext *> &Contexts;
llvm::DenseMap<DeclarationName, SmallVector<NamedDecl *, 8> > &Decls;
+ bool VisitAll;
public:
DeclContextAllNamesVisitor(ASTReader &Reader,
SmallVectorImpl<const DeclContext *> &Contexts,
llvm::DenseMap<DeclarationName,
- SmallVector<NamedDecl *, 8> > &Decls)
- : Reader(Reader), Contexts(Contexts), Decls(Decls) { }
+ SmallVector<NamedDecl *, 8> > &Decls,
+ bool VisitAll)
+ : Reader(Reader), Contexts(Contexts), Decls(Decls), VisitAll(VisitAll) { }
static bool visit(ModuleFile &M, void *UserData) {
DeclContextAllNamesVisitor *This
@@ -5406,8 +5750,9 @@ namespace {
Info->second.NameLookupTableData;
bool FoundAnything = false;
for (ASTDeclContextNameLookupTable::data_iterator
- I = LookupTable->data_begin(), E = LookupTable->data_end();
- I != E; ++I) {
+ I = LookupTable->data_begin(), E = LookupTable->data_end();
+ I != E;
+ ++I) {
ASTDeclContextNameLookupTrait::data_type Data = *I;
for (; Data.first != Data.second; ++Data.first) {
NamedDecl *ND = This->Reader.GetLocalDeclAs<NamedDecl>(M,
@@ -5421,7 +5766,7 @@ namespace {
}
}
- return FoundAnything;
+ return FoundAnything && !This->VisitAll;
}
};
}
@@ -5429,7 +5774,7 @@ namespace {
void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) {
if (!DC->hasExternalVisibleStorage())
return;
- llvm::DenseMap<DeclarationName, llvm::SmallVector<NamedDecl*, 8> > Decls;
+ llvm::DenseMap<DeclarationName, SmallVector<NamedDecl *, 8> > Decls;
// Compute the declaration contexts we need to look into. Multiple such
// declaration contexts occur when two declaration contexts from disjoint
@@ -5447,12 +5792,13 @@ void ASTReader::completeVisibleDeclsMap(const DeclContext *DC) {
}
}
- DeclContextAllNamesVisitor Visitor(*this, Contexts, Decls);
+ DeclContextAllNamesVisitor Visitor(*this, Contexts, Decls,
+ /*VisitAll=*/DC->isFileContext());
ModuleMgr.visit(&DeclContextAllNamesVisitor::visit, &Visitor);
++NumVisibleDeclContextsRead;
for (llvm::DenseMap<DeclarationName,
- llvm::SmallVector<NamedDecl*, 8> >::iterator
+ SmallVector<NamedDecl *, 8> >::iterator
I = Decls.begin(), E = Decls.end(); I != E; ++I) {
SetExternalVisibleDeclsForName(DC, I->first, I->second);
}
@@ -5576,8 +5922,31 @@ void ASTReader::PrintStats() {
NumMethodPoolEntriesRead, TotalNumMethodPoolEntries,
((float)NumMethodPoolEntriesRead/TotalNumMethodPoolEntries
* 100));
- std::fprintf(stderr, " %u method pool misses\n", NumMethodPoolMisses);
}
+ if (NumMethodPoolLookups) {
+ std::fprintf(stderr, " %u/%u method pool lookups succeeded (%f%%)\n",
+ NumMethodPoolHits, NumMethodPoolLookups,
+ ((float)NumMethodPoolHits/NumMethodPoolLookups * 100.0));
+ }
+ if (NumMethodPoolTableLookups) {
+ std::fprintf(stderr, " %u/%u method pool table lookups succeeded (%f%%)\n",
+ NumMethodPoolTableHits, NumMethodPoolTableLookups,
+ ((float)NumMethodPoolTableHits/NumMethodPoolTableLookups
+ * 100.0));
+ }
+
+ if (NumIdentifierLookupHits) {
+ std::fprintf(stderr,
+ " %u / %u identifier table lookups succeeded (%f%%)\n",
+ NumIdentifierLookupHits, NumIdentifierLookups,
+ (double)NumIdentifierLookupHits*100.0/NumIdentifierLookups);
+ }
+
+ if (GlobalIndex) {
+ std::fprintf(stderr, "\n");
+ GlobalIndex->printStats();
+ }
+
std::fprintf(stderr, "\n");
dump();
std::fprintf(stderr, "\n");
@@ -5646,8 +6015,8 @@ void ASTReader::InitializeSema(Sema &S) {
// Makes sure any declarations that were deserialized "too early"
// still get added to the identifier's declaration chains.
for (unsigned I = 0, N = PreloadedDecls.size(); I != N; ++I) {
- SemaObj->pushExternalDeclIntoScope(PreloadedDecls[I],
- PreloadedDecls[I]->getDeclName());
+ NamedDecl *ND = cast<NamedDecl>(PreloadedDecls[I]->getMostRecentDecl());
+ SemaObj->pushExternalDeclIntoScope(ND, PreloadedDecls[I]->getDeclName());
}
PreloadedDecls.clear();
@@ -5678,10 +6047,21 @@ 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);
+ StringRef Name(NameStart, NameEnd - NameStart);
+
+ // If there is a global index, look there first to determine which modules
+ // provably do not have any results for this identifier.
+ GlobalModuleIndex::HitSet Hits;
+ GlobalModuleIndex::HitSet *HitsPtr = 0;
+ if (!loadGlobalIndex()) {
+ if (GlobalIndex->lookupIdentifier(Name, Hits)) {
+ HitsPtr = &Hits;
+ }
+ }
+ IdentifierLookupVisitor Visitor(Name, /*PriorGeneration=*/0,
+ NumIdentifierLookups,
+ NumIdentifierLookupHits);
+ ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor, HitsPtr);
IdentifierInfo *II = Visitor.getIdentifierInfo();
markIdentifierUpToDate(II);
return II;
@@ -5737,9 +6117,9 @@ StringRef ASTIdentifierIterator::Next() {
// We have any identifiers remaining in the current AST file; return
// the next one.
- std::pair<const char*, unsigned> Key = *Current;
+ StringRef Result = *Current;
++Current;
- return StringRef(Key.first, Key.second);
+ return Result;
}
IdentifierIterator *ASTReader::getIdentifiers() const {
@@ -5751,8 +6131,8 @@ namespace clang { namespace serialization {
ASTReader &Reader;
Selector Sel;
unsigned PriorGeneration;
- llvm::SmallVector<ObjCMethodDecl *, 4> InstanceMethods;
- llvm::SmallVector<ObjCMethodDecl *, 4> FactoryMethods;
+ SmallVector<ObjCMethodDecl *, 4> InstanceMethods;
+ SmallVector<ObjCMethodDecl *, 4> FactoryMethods;
public:
ReadMethodPoolVisitor(ASTReader &Reader, Selector Sel,
@@ -5770,12 +6150,14 @@ namespace clang { namespace serialization {
if (M.Generation <= This->PriorGeneration)
return true;
+ ++This->Reader.NumMethodPoolTableLookups;
ASTSelectorLookupTable *PoolTable
= (ASTSelectorLookupTable*)M.SelectorLookupTable;
ASTSelectorLookupTable::iterator Pos = PoolTable->find(This->Sel);
if (Pos == PoolTable->end())
return false;
-
+
+ ++This->Reader.NumMethodPoolTableHits;
++This->Reader.NumSelectorsRead;
// FIXME: Not quite happy with the statistics here. We probably should
// disable this tracking when called via LoadSelector.
@@ -5818,15 +6200,16 @@ void ASTReader::ReadMethodPool(Selector Sel) {
Generation = CurrentGeneration;
// Search for methods defined with this selector.
+ ++NumMethodPoolLookups;
ReadMethodPoolVisitor Visitor(*this, Sel, PriorGeneration);
ModuleMgr.visit(&ReadMethodPoolVisitor::visit, &Visitor);
if (Visitor.getInstanceMethods().empty() &&
- Visitor.getFactoryMethods().empty()) {
- ++NumMethodPoolMisses;
+ Visitor.getFactoryMethods().empty())
return;
- }
-
+
+ ++NumMethodPoolHits;
+
if (!getSema())
return;
@@ -5849,6 +6232,16 @@ void ASTReader::ReadKnownNamespaces(
}
}
+void ASTReader::ReadUndefinedButUsed(
+ llvm::DenseMap<NamedDecl*, SourceLocation> &Undefined) {
+ for (unsigned Idx = 0, N = UndefinedButUsed.size(); Idx != N;) {
+ NamedDecl *D = cast<NamedDecl>(GetDecl(UndefinedButUsed[Idx++]));
+ SourceLocation Loc =
+ SourceLocation::getFromRawEncoding(UndefinedButUsed[Idx++]);
+ Undefined.insert(std::make_pair(D, Loc));
+ }
+}
+
void ASTReader::ReadTentativeDefinitions(
SmallVectorImpl<VarDecl *> &TentativeDefs) {
for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) {
@@ -5902,14 +6295,14 @@ void ASTReader::ReadDynamicClasses(SmallVectorImpl<CXXRecordDecl *> &Decls) {
}
void
-ASTReader::ReadLocallyScopedExternalDecls(SmallVectorImpl<NamedDecl *> &Decls) {
- for (unsigned I = 0, N = LocallyScopedExternalDecls.size(); I != N; ++I) {
- NamedDecl *D
- = dyn_cast_or_null<NamedDecl>(GetDecl(LocallyScopedExternalDecls[I]));
+ASTReader::ReadLocallyScopedExternCDecls(SmallVectorImpl<NamedDecl *> &Decls) {
+ for (unsigned I = 0, N = LocallyScopedExternCDecls.size(); I != N; ++I) {
+ NamedDecl *D
+ = dyn_cast_or_null<NamedDecl>(GetDecl(LocallyScopedExternCDecls[I]));
if (D)
Decls.push_back(D);
}
- LocallyScopedExternalDecls.clear();
+ LocallyScopedExternCDecls.clear();
}
void ASTReader::ReadReferencedSelectors(
@@ -6000,28 +6393,32 @@ void ASTReader::SetIdentifierInfo(IdentifierID ID, IdentifierInfo *II) {
/// \param DeclIDs the set of declaration IDs with the name @p II that are
/// visible at global scope.
///
-/// \param Nonrecursive should be true to indicate that the caller knows that
-/// this call is non-recursive, and therefore the globally-visible declarations
-/// will not be placed onto the pending queue.
+/// \param Decls if non-null, this vector will be populated with the set of
+/// deserialized declarations. These declarations will not be pushed into
+/// scope.
void
ASTReader::SetGloballyVisibleDecls(IdentifierInfo *II,
const SmallVectorImpl<uint32_t> &DeclIDs,
- bool Nonrecursive) {
- if (NumCurrentElementsDeserializing && !Nonrecursive) {
- PendingIdentifierInfos.push_back(PendingIdentifierInfo());
- PendingIdentifierInfo &PII = PendingIdentifierInfos.back();
- PII.II = II;
- PII.DeclIDs.append(DeclIDs.begin(), DeclIDs.end());
+ SmallVectorImpl<Decl *> *Decls) {
+ if (NumCurrentElementsDeserializing && !Decls) {
+ PendingIdentifierInfos[II].append(DeclIDs.begin(), DeclIDs.end());
return;
}
for (unsigned I = 0, N = DeclIDs.size(); I != N; ++I) {
NamedDecl *D = cast<NamedDecl>(GetDecl(DeclIDs[I]));
if (SemaObj) {
+ // If we're simply supposed to record the declarations, do so now.
+ if (Decls) {
+ Decls->push_back(D);
+ continue;
+ }
+
// Introduce this declaration into the translation-unit scope
// and add it to the declaration chain for this identifier, so
// that (unqualified) name lookup will find it.
- SemaObj->pushExternalDeclIntoScope(D, II);
+ NamedDecl *ND = cast<NamedDecl>(D->getMostRecentDecl());
+ SemaObj->pushExternalDeclIntoScope(ND, II);
} else {
// Queue this declaration so that it will be added to the
// translation unit scope and identifier's declaration chain
@@ -6081,7 +6478,7 @@ IdentifierID ASTReader::getGlobalIdentifierID(ModuleFile &M, unsigned LocalID) {
return LocalID + I->second;
}
-MacroInfo *ASTReader::getMacro(MacroID ID, MacroInfo *Hint) {
+MacroInfo *ASTReader::getMacro(MacroID ID) {
if (ID == 0)
return 0;
@@ -6097,7 +6494,11 @@ MacroInfo *ASTReader::getMacro(MacroID ID, MacroInfo *Hint) {
assert(I != GlobalMacroMap.end() && "Corrupted global macro map");
ModuleFile *M = I->second;
unsigned Index = ID - M->BaseMacroID;
- ReadMacroRecord(*M, M->MacroOffsets[Index], Hint);
+ MacrosLoaded[ID] = ReadMacroRecord(*M, M->MacroOffsets[Index]);
+
+ if (DeserializationListener)
+ DeserializationListener->MacroRead(ID + NUM_PREDEF_MACRO_IDS,
+ MacrosLoaded[ID]);
}
return MacrosLoaded[ID];
@@ -6140,7 +6541,11 @@ Module *ASTReader::getSubmodule(SubmoduleID GlobalID) {
return SubmodulesLoaded[GlobalID - NUM_PREDEF_SUBMODULE_IDS];
}
-
+
+Module *ASTReader::getModule(unsigned ID) {
+ return getSubmodule(ID);
+}
+
Selector ASTReader::getLocalSelector(ModuleFile &M, unsigned LocalID) {
return DecodeSelector(getGlobalSelectorID(M, LocalID));
}
@@ -6370,7 +6775,7 @@ ASTReader::ReadTemplateArgument(ModuleFile &F,
return TemplateArgument(ReadTemplateName(F, Record, Idx));
case TemplateArgument::TemplateExpansion: {
TemplateName Name = ReadTemplateName(F, Record, Idx);
- llvm::Optional<unsigned> NumTemplateExpansions;
+ Optional<unsigned> NumTemplateExpansions;
if (unsigned NumExpansions = Record[Idx++])
NumTemplateExpansions = NumExpansions - 1;
return TemplateArgument(Name, NumTemplateExpansions);
@@ -6420,13 +6825,14 @@ ReadTemplateArgumentList(SmallVector<TemplateArgument, 8> &TemplArgs,
}
/// \brief Read a UnresolvedSet structure.
-void ASTReader::ReadUnresolvedSet(ModuleFile &F, UnresolvedSetImpl &Set,
+void ASTReader::ReadUnresolvedSet(ModuleFile &F, ASTUnresolvedSet &Set,
const RecordData &Record, unsigned &Idx) {
unsigned NumDecls = Record[Idx++];
+ Set.reserve(Context, NumDecls);
while (NumDecls--) {
NamedDecl *D = ReadDeclAs<NamedDecl>(F, Record, Idx);
AccessSpecifier AS = (AccessSpecifier)Record[Idx++];
- Set.addDecl(D, AS);
+ Set.addDecl(Context, D, AS);
}
}
@@ -6656,8 +7062,10 @@ llvm::APSInt ASTReader::ReadAPSInt(const RecordData &Record, unsigned &Idx) {
}
/// \brief Read a floating-point value
-llvm::APFloat ASTReader::ReadAPFloat(const RecordData &Record, unsigned &Idx) {
- return llvm::APFloat(ReadAPInt(Record, Idx));
+llvm::APFloat ASTReader::ReadAPFloat(const RecordData &Record,
+ const llvm::fltSemantics &Sem,
+ unsigned &Idx) {
+ return llvm::APFloat(Sem, ReadAPInt(Record, Idx));
}
// \brief Read a string
@@ -6721,39 +7129,35 @@ void ASTReader::ClearSwitchCaseIDs() {
void ASTReader::ReadComments() {
std::vector<RawComment *> Comments;
- for (SmallVectorImpl<std::pair<llvm::BitstreamCursor,
+ for (SmallVectorImpl<std::pair<BitstreamCursor,
serialization::ModuleFile *> >::iterator
I = CommentsCursors.begin(),
E = CommentsCursors.end();
I != E; ++I) {
- llvm::BitstreamCursor &Cursor = I->first;
+ BitstreamCursor &Cursor = I->first;
serialization::ModuleFile &F = *I->second;
SavedStreamPosition SavedPosition(Cursor);
RecordData Record;
while (true) {
- unsigned Code = Cursor.ReadCode();
- if (Code == llvm::bitc::END_BLOCK)
+ llvm::BitstreamEntry Entry =
+ Cursor.advanceSkippingSubblocks(BitstreamCursor::AF_DontPopBlockAtEnd);
+
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::SubBlock: // Handled for us already.
+ case llvm::BitstreamEntry::Error:
+ Error("malformed block record in AST file");
+ return;
+ case llvm::BitstreamEntry::EndBlock:
+ goto NextCursor;
+ case llvm::BitstreamEntry::Record:
+ // The interesting case.
break;
-
- if (Code == llvm::bitc::ENTER_SUBBLOCK) {
- // No known subblocks, always skip them.
- Cursor.ReadSubBlockID();
- if (Cursor.SkipBlock()) {
- Error("malformed block record in AST file");
- return;
- }
- continue;
- }
-
- if (Code == llvm::bitc::DEFINE_ABBREV) {
- Cursor.ReadAbbrevRecord();
- continue;
}
// Read a record.
Record.clear();
- switch ((CommentRecordTypes) Cursor.ReadRecord(Code, Record)) {
+ switch ((CommentRecordTypes)Cursor.readRecord(Entry.ID, Record)) {
case COMMENTS_RAW_COMMENT: {
unsigned Idx = 0;
SourceRange SR = ReadSourceRange(F, Record, Idx);
@@ -6768,19 +7172,24 @@ void ASTReader::ReadComments() {
}
}
}
+ NextCursor:;
}
Context.Comments.addCommentsToFront(Comments);
}
void ASTReader::finishPendingActions() {
while (!PendingIdentifierInfos.empty() || !PendingDeclChains.empty() ||
- !PendingMacroIDs.empty()) {
+ !PendingMacroIDs.empty() || !PendingDeclContextInfos.empty()) {
// If any identifiers with corresponding top-level declarations have
// been loaded, load those declarations now.
+ llvm::DenseMap<IdentifierInfo *, SmallVector<Decl *, 2> > TopLevelDecls;
while (!PendingIdentifierInfos.empty()) {
- SetGloballyVisibleDecls(PendingIdentifierInfos.front().II,
- PendingIdentifierInfos.front().DeclIDs, true);
- PendingIdentifierInfos.pop_front();
+ // FIXME: std::move
+ IdentifierInfo *II = PendingIdentifierInfos.back().first;
+ SmallVector<uint32_t, 4> DeclIDs = PendingIdentifierInfos.back().second;
+ PendingIdentifierInfos.pop_back();
+
+ SetGloballyVisibleDecls(II, DeclIDs, &TopLevelDecls[II]);
}
// Load pending declaration chains.
@@ -6790,17 +7199,48 @@ void ASTReader::finishPendingActions() {
}
PendingDeclChains.clear();
+ // Make the most recent of the top-level declarations visible.
+ for (llvm::DenseMap<IdentifierInfo *, SmallVector<Decl *, 2> >::iterator
+ TLD = TopLevelDecls.begin(), TLDEnd = TopLevelDecls.end();
+ TLD != TLDEnd; ++TLD) {
+ IdentifierInfo *II = TLD->first;
+ for (unsigned I = 0, N = TLD->second.size(); I != N; ++I) {
+ NamedDecl *ND = cast<NamedDecl>(TLD->second[I]->getMostRecentDecl());
+ SemaObj->pushExternalDeclIntoScope(ND, II);
+ }
+ }
+
// Load any pending macro definitions.
for (unsigned I = 0; I != PendingMacroIDs.size(); ++I) {
- // FIXME: std::move here
- SmallVector<MacroID, 2> GlobalIDs = PendingMacroIDs.begin()[I].second;
- MacroInfo *Hint = 0;
+ IdentifierInfo *II = PendingMacroIDs.begin()[I].first;
+ SmallVector<PendingMacroInfo, 2> GlobalIDs;
+ GlobalIDs.swap(PendingMacroIDs.begin()[I].second);
+ // Initialize the macro history from chained-PCHs ahead of module imports.
for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs;
++IDIdx) {
- Hint = getMacro(GlobalIDs[IDIdx], Hint);
+ const PendingMacroInfo &Info = GlobalIDs[IDIdx];
+ if (Info.M->Kind != MK_Module)
+ resolvePendingMacro(II, Info);
+ }
+ // Handle module imports.
+ for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs;
+ ++IDIdx) {
+ const PendingMacroInfo &Info = GlobalIDs[IDIdx];
+ if (Info.M->Kind == MK_Module)
+ resolvePendingMacro(II, Info);
}
}
PendingMacroIDs.clear();
+
+ // Wire up the DeclContexts for Decls that we delayed setting until
+ // recursive loading is completed.
+ while (!PendingDeclContextInfos.empty()) {
+ PendingDeclContextInfo Info = PendingDeclContextInfos.front();
+ PendingDeclContextInfos.pop_front();
+ DeclContext *SemaDC = cast<DeclContext>(GetDecl(Info.SemaDC));
+ DeclContext *LexicalDC = cast<DeclContext>(GetDecl(Info.LexicalDC));
+ Info.D->setDeclContextsImpl(SemaDC, LexicalDC, getContext());
+ }
}
// If we deserialized any C++ or Objective-C class definitions, any
@@ -6908,18 +7348,22 @@ void ASTReader::FinishedDeserializing() {
ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context,
StringRef isysroot, bool DisableValidation,
- bool AllowASTWithCompilerErrors)
+ bool AllowASTWithCompilerErrors, bool UseGlobalIndex)
: 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(PP.getFileManager()),
isysroot(isysroot), DisableValidation(DisableValidation),
- AllowASTWithCompilerErrors(AllowASTWithCompilerErrors),
+ AllowASTWithCompilerErrors(AllowASTWithCompilerErrors),
+ UseGlobalIndex(UseGlobalIndex), TriedLoadingGlobalIndex(false),
CurrentGeneration(0), CurrSwitchCaseStmts(&SwitchCaseStmts),
NumSLocEntriesRead(0), TotalNumSLocEntries(0),
- NumStatementsRead(0), TotalNumStatements(0), NumMacrosRead(0),
- TotalNumMacros(0), NumSelectorsRead(0), NumMethodPoolEntriesRead(0),
- NumMethodPoolMisses(0), TotalNumMethodPoolEntries(0),
+ NumStatementsRead(0), TotalNumStatements(0), NumMacrosRead(0),
+ TotalNumMacros(0), NumIdentifierLookups(0), NumIdentifierLookupHits(0),
+ NumSelectorsRead(0), NumMethodPoolEntriesRead(0),
+ NumMethodPoolLookups(0), NumMethodPoolHits(0),
+ NumMethodPoolTableLookups(0), NumMethodPoolTableHits(0),
+ TotalNumMethodPoolEntries(0),
NumLexicalDeclContextsRead(0), TotalLexicalDeclContexts(0),
NumVisibleDeclContextsRead(0), TotalVisibleDeclContexts(0),
TotalModulesSizeInBits(0), NumCurrentElementsDeserializing(0),
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index c42944d..0fbdd7e 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -12,19 +12,19 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Serialization/ASTReader.h"
#include "ASTCommon.h"
#include "ASTReaderInternals.h"
-#include "clang/Serialization/ASTReader.h"
-#include "clang/Sema/IdentifierResolver.h"
-#include "clang/Sema/Sema.h"
-#include "clang/Sema/SemaDiagnostic.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclVisitor.h"
-#include "clang/AST/DeclGroup.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclGroup.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/DeclVisitor.h"
#include "clang/AST/Expr.h"
+#include "clang/Sema/IdentifierResolver.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/Support/SaveAndRestore.h"
using namespace clang;
using namespace clang::serialization;
@@ -44,9 +44,6 @@ namespace clang {
unsigned &Idx;
TypeID TypeIDForTypeDecl;
- DeclID DeclContextIDForTemplateParmDecl;
- DeclID LexicalDeclContextIDForTemplateParmDecl;
-
bool HasPendingBody;
uint64_t GetCurrentCursorOffset();
@@ -116,29 +113,25 @@ namespace clang {
ASTReader &Reader;
GlobalDeclID FirstID;
mutable bool Owning;
+ Decl::Kind DeclKind;
void operator=(RedeclarableResult &) LLVM_DELETED_FUNCTION;
public:
- RedeclarableResult(ASTReader &Reader, GlobalDeclID FirstID)
- : Reader(Reader), FirstID(FirstID), Owning(true) { }
+ RedeclarableResult(ASTReader &Reader, GlobalDeclID FirstID,
+ Decl::Kind DeclKind)
+ : Reader(Reader), FirstID(FirstID), Owning(true), DeclKind(DeclKind) { }
RedeclarableResult(const RedeclarableResult &Other)
- : Reader(Other.Reader), FirstID(Other.FirstID), Owning(Other.Owning)
+ : Reader(Other.Reader), FirstID(Other.FirstID), Owning(Other.Owning) ,
+ DeclKind(Other.DeclKind)
{
Other.Owning = false;
}
~RedeclarableResult() {
- // FIXME: We want to suppress this when the declaration is local to
- // a function, since there's no reason to search other AST files
- // for redeclarations (they can't exist). However, this is hard to
- // do locally because the declaration hasn't necessarily loaded its
- // declaration context yet. Also, local externs still have the function
- // as their (semantic) declaration context, which is wrong and would
- // break this optimize.
-
- if (FirstID && Owning && Reader.PendingDeclChainsKnown.insert(FirstID))
+ if (FirstID && Owning && isRedeclarableDeclKind(DeclKind) &&
+ Reader.PendingDeclChainsKnown.insert(FirstID))
Reader.PendingDeclChains.push_back(FirstID);
}
@@ -151,7 +144,7 @@ namespace clang {
Owning = false;
}
};
-
+
/// \brief Class used to capture the result of searching for an existing
/// declaration of a specific kind and name, along with the ability
/// to update the place where this result was found (the declaration
@@ -272,6 +265,7 @@ namespace clang {
void VisitFriendTemplateDecl(FriendTemplateDecl *D);
void VisitStaticAssertDecl(StaticAssertDecl *D);
void VisitBlockDecl(BlockDecl *BD);
+ void VisitEmptyDecl(EmptyDecl *D);
std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC);
@@ -295,6 +289,7 @@ namespace clang {
void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D);
void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
+ void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
};
}
@@ -333,14 +328,6 @@ void ASTDeclReader::Visit(Decl *D) {
Reader.PendingBodies[FD] = GetCurrentCursorOffset();
HasPendingBody = true;
}
- } else if (D->isTemplateParameter()) {
- // If we have a fully initialized template parameter, we can now
- // set its DeclContext.
- DeclContext *SemaDC = cast<DeclContext>(
- Reader.GetDecl(DeclContextIDForTemplateParmDecl));
- DeclContext *LexicalDC = cast<DeclContext>(
- Reader.GetDecl(LexicalDeclContextIDForTemplateParmDecl));
- D->setDeclContextsImpl(SemaDC, LexicalDC, Reader.getContext());
}
}
@@ -350,8 +337,11 @@ void ASTDeclReader::VisitDecl(Decl *D) {
// parameter immediately, because the template parameter might be
// used in the formulation of its DeclContext. Use the translation
// unit DeclContext as a placeholder.
- DeclContextIDForTemplateParmDecl = ReadDeclID(Record, Idx);
- LexicalDeclContextIDForTemplateParmDecl = ReadDeclID(Record, Idx);
+ GlobalDeclID SemaDCIDForTemplateParmDecl = ReadDeclID(Record, Idx);
+ GlobalDeclID LexicalDCIDForTemplateParmDecl = ReadDeclID(Record, Idx);
+ Reader.addPendingDeclContextInfo(D,
+ SemaDCIDForTemplateParmDecl,
+ LexicalDCIDForTemplateParmDecl);
D->setDeclContext(Reader.getContext().getTranslationUnitDecl());
} else {
DeclContext *SemaDC = ReadDeclAs<DeclContext>(Record, Idx);
@@ -479,6 +469,7 @@ void ASTDeclReader::VisitRecordDecl(RecordDecl *RD) {
RD->setHasFlexibleArrayMember(Record[Idx++]);
RD->setAnonymousStructOrUnion(Record[Idx++]);
RD->setHasObjectMember(Record[Idx++]);
+ RD->setHasVolatileMember(Record[Idx++]);
}
void ASTDeclReader::VisitValueDecl(ValueDecl *VD) {
@@ -513,9 +504,8 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
// FunctionDecl's body is handled last at ASTDeclReader::Visit,
// after everything else is read.
-
+
FD->SClass = (StorageClass)Record[Idx++];
- FD->SClassAsWritten = (StorageClass)Record[Idx++];
FD->IsInline = Record[Idx++];
FD->IsInlineSpecified = Record[Idx++];
FD->IsVirtualAsWritten = Record[Idx++];
@@ -528,6 +518,9 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
FD->IsExplicitlyDefaulted = Record[Idx++];
FD->HasImplicitReturnZero = Record[Idx++];
FD->IsConstexpr = Record[Idx++];
+ FD->HasSkippedBody = Record[Idx++];
+ FD->HasCachedLinkage = true;
+ FD->CachedLinkage = Record[Idx++];
FD->EndRangeLoc = ReadSourceLocation(Record, Idx);
switch ((FunctionDecl::TemplatedKind)Record[Idx++]) {
@@ -652,6 +645,7 @@ void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) {
MD->setPropertyAccessor(Record[Idx++]);
MD->setDefined(Record[Idx++]);
MD->IsOverriding = Record[Idx++];
+ MD->HasSkippedBody = Record[Idx++];
MD->IsRedeclaration = Record[Idx++];
MD->HasRedeclaration = Record[Idx++];
@@ -899,9 +893,8 @@ void ASTDeclReader::VisitIndirectFieldDecl(IndirectFieldDecl *FD) {
void ASTDeclReader::VisitVarDecl(VarDecl *VD) {
RedeclarableResult Redecl = VisitRedeclarable(VD);
VisitDeclaratorDecl(VD);
-
+
VD->VarDeclBits.SClass = (StorageClass)Record[Idx++];
- VD->VarDeclBits.SClassAsWritten = (StorageClass)Record[Idx++];
VD->VarDeclBits.ThreadSpecified = Record[Idx++];
VD->VarDeclBits.InitStyle = Record[Idx++];
VD->VarDeclBits.ExceptionVar = Record[Idx++];
@@ -909,6 +902,8 @@ void ASTDeclReader::VisitVarDecl(VarDecl *VD) {
VD->VarDeclBits.CXXForRangeDecl = Record[Idx++];
VD->VarDeclBits.ARCPseudoStrong = Record[Idx++];
VD->VarDeclBits.IsConstexpr = Record[Idx++];
+ VD->HasCachedLinkage = true;
+ VD->CachedLinkage = Record[Idx++];
// Only true variables (not parameters or implicit parameters) can be merged.
if (VD->getKind() == Decl::Var)
@@ -1083,11 +1078,7 @@ void ASTDeclReader::ReadCXXDefinitionData(
const RecordData &Record, unsigned &Idx) {
// Note: the caller has deserialized the IsLambda bit already.
Data.UserDeclaredConstructor = Record[Idx++];
- Data.UserDeclaredCopyConstructor = Record[Idx++];
- Data.UserDeclaredMoveConstructor = Record[Idx++];
- Data.UserDeclaredCopyAssignment = Record[Idx++];
- Data.UserDeclaredMoveAssignment = Record[Idx++];
- Data.UserDeclaredDestructor = Record[Idx++];
+ Data.UserDeclaredSpecialMembers = Record[Idx++];
Data.Aggregate = Record[Idx++];
Data.PlainOldData = Record[Idx++];
Data.Empty = Record[Idx++];
@@ -1101,25 +1092,26 @@ void ASTDeclReader::ReadCXXDefinitionData(
Data.HasMutableFields = Record[Idx++];
Data.HasOnlyCMembers = Record[Idx++];
Data.HasInClassInitializer = Record[Idx++];
- Data.HasTrivialDefaultConstructor = Record[Idx++];
+ Data.HasUninitializedReferenceMember = Record[Idx++];
+ Data.NeedOverloadResolutionForMoveConstructor = Record[Idx++];
+ Data.NeedOverloadResolutionForMoveAssignment = Record[Idx++];
+ Data.NeedOverloadResolutionForDestructor = Record[Idx++];
+ Data.DefaultedMoveConstructorIsDeleted = Record[Idx++];
+ Data.DefaultedMoveAssignmentIsDeleted = Record[Idx++];
+ Data.DefaultedDestructorIsDeleted = Record[Idx++];
+ Data.HasTrivialSpecialMembers = Record[Idx++];
+ Data.HasIrrelevantDestructor = Record[Idx++];
Data.HasConstexprNonCopyMoveConstructor = Record[Idx++];
Data.DefaultedDefaultConstructorIsConstexpr = Record[Idx++];
Data.HasConstexprDefaultConstructor = Record[Idx++];
- Data.HasTrivialCopyConstructor = Record[Idx++];
- Data.HasTrivialMoveConstructor = Record[Idx++];
- Data.HasTrivialCopyAssignment = Record[Idx++];
- Data.HasTrivialMoveAssignment = Record[Idx++];
- Data.HasTrivialDestructor = Record[Idx++];
- Data.HasIrrelevantDestructor = Record[Idx++];
Data.HasNonLiteralTypeFieldsOrBases = Record[Idx++];
Data.ComputedVisibleConversions = Record[Idx++];
Data.UserProvidedDefaultConstructor = Record[Idx++];
- Data.DeclaredDefaultConstructor = Record[Idx++];
- Data.DeclaredCopyConstructor = Record[Idx++];
- Data.DeclaredMoveConstructor = Record[Idx++];
- Data.DeclaredCopyAssignment = Record[Idx++];
- Data.DeclaredMoveAssignment = Record[Idx++];
- Data.DeclaredDestructor = Record[Idx++];
+ Data.DeclaredSpecialMembers = Record[Idx++];
+ Data.ImplicitCopyConstructorHasConstParam = Record[Idx++];
+ Data.ImplicitCopyAssignmentHasConstParam = Record[Idx++];
+ Data.HasDeclaredCopyConstructorWithConstParam = Record[Idx++];
+ Data.HasDeclaredCopyAssignmentWithConstParam = Record[Idx++];
Data.FailedImplicitMoveConstructor = Record[Idx++];
Data.FailedImplicitMoveAssignment = Record[Idx++];
@@ -1266,10 +1258,12 @@ void ASTDeclReader::VisitAccessSpecDecl(AccessSpecDecl *D) {
void ASTDeclReader::VisitFriendDecl(FriendDecl *D) {
VisitDecl(D);
- if (Record[Idx++])
- D->Friend = GetTypeSourceInfo(Record, Idx);
- else
+ if (Record[Idx++]) // hasFriendDecl
D->Friend = ReadDeclAs<NamedDecl>(Record, Idx);
+ else
+ D->Friend = GetTypeSourceInfo(Record, Idx);
+ for (unsigned i = 0; i != D->NumTPLists; ++i)
+ D->getTPLists()[i] = Reader.ReadTemplateParameterList(F, Record, Idx);
D->NextFriend = Record[Idx++];
D->UnsupportedFriend = (Record[Idx++] != 0);
D->FriendLoc = ReadSourceLocation(Record, Idx);
@@ -1532,6 +1526,10 @@ void ASTDeclReader::VisitStaticAssertDecl(StaticAssertDecl *D) {
D->RParenLoc = ReadSourceLocation(Record, Idx);
}
+void ASTDeclReader::VisitEmptyDecl(EmptyDecl *D) {
+ VisitDecl(D);
+}
+
std::pair<uint64_t, uint64_t>
ASTDeclReader::VisitDeclContext(DeclContext *DC) {
uint64_t LexicalOffset = Record[Idx++];
@@ -1563,7 +1561,8 @@ ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) {
// The result structure takes care to note that we need to load the
// other declaration chains for this ID.
- return RedeclarableResult(Reader, FirstDeclID);
+ return RedeclarableResult(Reader, FirstDeclID,
+ static_cast<T *>(D)->getKind());
}
/// \brief Attempts to merge the given declaration (D) with another declaration
@@ -1626,6 +1625,17 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D,
}
}
+void ASTDeclReader::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
+ VisitDecl(D);
+ unsigned NumVars = D->varlist_size();
+ SmallVector<DeclRefExpr *, 16> Vars;
+ Vars.reserve(NumVars);
+ for (unsigned i = 0; i != NumVars; ++i) {
+ Vars.push_back(cast<DeclRefExpr>(Reader.ReadExpr(F)));
+ }
+ D->setVars(Vars);
+}
+
//===----------------------------------------------------------------------===//
// Attribute Reading
//===----------------------------------------------------------------------===//
@@ -1811,6 +1821,30 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
if (DC->isTranslationUnit() && Reader.SemaObj) {
IdentifierResolver &IdResolver = Reader.SemaObj->IdResolver;
+
+ // Temporarily consider the identifier to be up-to-date. We don't want to
+ // cause additional lookups here.
+ class UpToDateIdentifierRAII {
+ IdentifierInfo *II;
+ bool WasOutToDate;
+
+ public:
+ explicit UpToDateIdentifierRAII(IdentifierInfo *II)
+ : II(II), WasOutToDate(false)
+ {
+ if (II) {
+ WasOutToDate = II->isOutOfDate();
+ if (WasOutToDate)
+ II->setOutOfDate(false);
+ }
+ }
+
+ ~UpToDateIdentifierRAII() {
+ if (WasOutToDate)
+ II->setOutOfDate(true);
+ }
+ } UpToDate(Name.getAsIdentifierInfo());
+
for (IdentifierResolver::iterator I = IdResolver.begin(Name),
IEnd = IdResolver.end();
I != IEnd; ++I) {
@@ -1820,10 +1854,11 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
}
if (DC->isNamespace()) {
- for (DeclContext::lookup_result R = DC->lookup(Name);
- R.first != R.second; ++R.first) {
- if (isSameEntity(*R.first, D))
- return FindExistingResult(Reader, D, *R.first);
+ DeclContext::lookup_result R = DC->lookup(Name);
+ for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E;
+ ++I) {
+ if (isSameEntity(*I, D))
+ return FindExistingResult(Reader, D, *I);
}
}
@@ -1937,7 +1972,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
ASTDeclReader Reader(*this, *Loc.F, ID, RawLocation, Record,Idx);
Decl *D = 0;
- switch ((DeclCode)DeclsCursor.ReadRecord(Code, Record)) {
+ switch ((DeclCode)DeclsCursor.readRecord(Code, Record)) {
case DECL_CONTEXT_LEXICAL:
case DECL_CONTEXT_VISIBLE:
llvm_unreachable("Record cannot be de-serialized with ReadDeclRecord");
@@ -2005,7 +2040,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
D = AccessSpecDecl::CreateDeserialized(Context, ID);
break;
case DECL_FRIEND:
- D = FriendDecl::CreateDeserialized(Context, ID);
+ D = FriendDecl::CreateDeserialized(Context, ID, Record[Idx++]);
break;
case DECL_FRIEND_TEMPLATE:
D = FriendTemplateDecl::CreateDeserialized(Context, ID);
@@ -2109,6 +2144,12 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
// locations.
D = ImportDecl::CreateDeserialized(Context, ID, Record.back());
break;
+ case DECL_OMP_THREADPRIVATE:
+ D = OMPThreadPrivateDecl::CreateDeserialized(Context, ID, Record[Idx++]);
+ break;
+ case DECL_EMPTY:
+ D = EmptyDecl::CreateDeserialized(Context, ID);
+ break;
}
assert(D && "Unknown declaration reading AST file");
@@ -2122,12 +2163,18 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
// If this declaration is also a declaration context, get the
// offsets for its tables of lexical and visible declarations.
if (DeclContext *DC = dyn_cast<DeclContext>(D)) {
+ // FIXME: This should really be
+ // DeclContext *LookupDC = DC->getPrimaryContext();
+ // but that can walk the redeclaration chain, which might not work yet.
+ DeclContext *LookupDC = DC;
+ if (isa<NamespaceDecl>(DC))
+ LookupDC = DC->getPrimaryContext();
std::pair<uint64_t, uint64_t> Offsets = Reader.VisitDeclContext(DC);
if (Offsets.first || Offsets.second) {
if (Offsets.first != 0)
DC->setHasExternalLexicalStorage(true);
if (Offsets.second != 0)
- DC->setHasExternalVisibleStorage(true);
+ LookupDC->setHasExternalVisibleStorage(true);
if (ReadDeclContextStorage(*Loc.F, DeclsCursor, Offsets,
Loc.F->DeclContextInfos[DC]))
return 0;
@@ -2139,7 +2186,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
if (I != PendingVisibleUpdates.end()) {
// There are updates. This means the context has external visible
// storage, even if the original stored version didn't.
- DC->setHasExternalVisibleStorage(true);
+ LookupDC->setHasExternalVisibleStorage(true);
DeclContextVisibleUpdates &U = I->second;
for (DeclContextVisibleUpdates::iterator UI = U.begin(), UE = U.end();
UI != UE; ++UI) {
@@ -2149,9 +2196,6 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
}
PendingVisibleUpdates.erase(I);
}
-
- if (!DC->hasExternalVisibleStorage() && DC->hasExternalLexicalStorage())
- DC->setMustBuildLookupTable();
}
assert(Idx == Record.size());
@@ -2189,7 +2233,7 @@ void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) {
Cursor.JumpToBit(Offset);
RecordData Record;
unsigned Code = Cursor.ReadCode();
- unsigned RecCode = Cursor.ReadRecord(Code, Record);
+ unsigned RecCode = Cursor.readRecord(Code, Record);
(void)RecCode;
assert(RecCode == DECL_UPDATES && "Expected DECL_UPDATES record!");
@@ -2226,7 +2270,7 @@ namespace {
SmallVectorImpl<DeclID> &SearchDecls;
llvm::SmallPtrSet<Decl *, 16> &Deserialized;
GlobalDeclID CanonID;
- llvm::SmallVector<Decl *, 4> Chain;
+ SmallVector<Decl *, 4> Chain;
public:
RedeclChainVisitor(ASTReader &Reader, SmallVectorImpl<DeclID> &SearchDecls,
@@ -2307,7 +2351,7 @@ void ASTReader::loadPendingDeclChain(serialization::GlobalDeclID ID) {
Decl *CanonDecl = D->getCanonicalDecl();
// Determine the set of declaration IDs we'll be searching for.
- llvm::SmallVector<DeclID, 1> SearchDecls;
+ SmallVector<DeclID, 1> SearchDecls;
GlobalDeclID CanonID = 0;
if (D == CanonDecl) {
SearchDecls.push_back(ID); // Always first.
@@ -2404,7 +2448,7 @@ namespace {
if (Tail)
ASTDeclReader::setNextObjCCategory(Tail, Cat);
else
- Interface->setCategoryList(Cat);
+ Interface->setCategoryListRaw(Cat);
Tail = Cat;
}
@@ -2419,13 +2463,15 @@ namespace {
Tail(0)
{
// Populate the name -> category map with the set of known categories.
- for (ObjCCategoryDecl *Cat = Interface->getCategoryList(); Cat;
- Cat = Cat->getNextClassCategory()) {
+ for (ObjCInterfaceDecl::known_categories_iterator
+ Cat = Interface->known_categories_begin(),
+ CatEnd = Interface->known_categories_end();
+ Cat != CatEnd; ++Cat) {
if (Cat->getDeclName())
- NameCategoryMap[Cat->getDeclName()] = Cat;
+ NameCategoryMap[Cat->getDeclName()] = *Cat;
// Keep track of the tail of the category list.
- Tail = Cat;
+ Tail = *Cat;
}
}
diff --git a/lib/Serialization/ASTReaderInternals.h b/lib/Serialization/ASTReaderInternals.h
index e5159e9..327da44 100644
--- a/lib/Serialization/ASTReaderInternals.h
+++ b/lib/Serialization/ASTReaderInternals.h
@@ -13,17 +13,19 @@
#ifndef LLVM_CLANG_SERIALIZATION_ASTREADER_INTERNALS_H
#define LLVM_CLANG_SERIALIZATION_ASTREADER_INTERNALS_H
-#include "clang/Basic/OnDiskHashTable.h"
#include "clang/AST/DeclarationName.h"
+#include "clang/Basic/OnDiskHashTable.h"
+#include "clang/Serialization/ASTBitCodes.h"
#include "llvm/Support/Endian.h"
-#include <utility>
#include <sys/stat.h>
+#include <utility>
namespace clang {
class ASTReader;
class HeaderSearch;
struct HeaderFileInfo;
+class FileEntry;
namespace serialization {
@@ -77,8 +79,43 @@ public:
unsigned DataLen);
};
+/// \brief Base class for the trait describing the on-disk hash table for the
+/// identifiers in an AST file.
+///
+/// This class is not useful by itself; rather, it provides common
+/// functionality for accessing the on-disk hash table of identifiers
+/// in an AST file. Different subclasses customize that functionality
+/// based on what information they are interested in. Those subclasses
+/// must provide the \c data_type typedef and the ReadData operation,
+/// only.
+class ASTIdentifierLookupTraitBase {
+public:
+ typedef StringRef external_key_type;
+ typedef StringRef internal_key_type;
+
+
+ static bool EqualKey(const internal_key_type& a, const internal_key_type& b) {
+ return a == b;
+ }
+
+ static unsigned ComputeHash(const internal_key_type& a);
+
+ static std::pair<unsigned, unsigned>
+ ReadKeyDataLength(const unsigned char*& d);
+
+ // This hopefully will just get inlined and removed by the optimizer.
+ static const internal_key_type&
+ GetInternalKey(const external_key_type& x) { return x; }
+
+ // This hopefully will just get inlined and removed by the optimizer.
+ static const external_key_type&
+ GetExternalKey(const internal_key_type& x) { return x; }
+
+ static internal_key_type ReadKey(const unsigned char* d, unsigned n);
+};
+
/// \brief Class that performs lookup for an identifier stored in an AST file.
-class ASTIdentifierLookupTrait {
+class ASTIdentifierLookupTrait : public ASTIdentifierLookupTraitBase {
ASTReader &Reader;
ModuleFile &F;
@@ -90,42 +127,15 @@ class ASTIdentifierLookupTrait {
public:
typedef IdentifierInfo * data_type;
- typedef const std::pair<const char*, unsigned> external_key_type;
-
- typedef external_key_type internal_key_type;
-
ASTIdentifierLookupTrait(ASTReader &Reader, ModuleFile &F,
IdentifierInfo *II = 0)
: Reader(Reader), F(F), KnownII(II) { }
-
- static bool EqualKey(const internal_key_type& a,
- const internal_key_type& b) {
- return (a.second == b.second) ? memcmp(a.first, b.first, a.second) == 0
- : false;
- }
-
- static unsigned ComputeHash(const internal_key_type& a);
-
- // This hopefully will just get inlined and removed by the optimizer.
- static const internal_key_type&
- GetInternalKey(const external_key_type& x) { return x; }
-
- // This hopefully will just get inlined and removed by the optimizer.
- static const external_key_type&
- GetExternalKey(const internal_key_type& x) { return x; }
-
- static std::pair<unsigned, unsigned>
- ReadKeyDataLength(const unsigned char*& d);
-
- static std::pair<const char*, unsigned>
- ReadKey(const unsigned char* d, unsigned n);
-
- IdentifierInfo *ReadData(const internal_key_type& k,
- const unsigned char* d,
- unsigned DataLen);
+
+ data_type ReadData(const internal_key_type& k,
+ const unsigned char* d,
+ unsigned DataLen);
ASTReader &getReader() const { return Reader; }
-
};
/// \brief The on-disk hash table used to contain information about
@@ -142,8 +152,8 @@ class ASTSelectorLookupTrait {
public:
struct data_type {
SelectorID ID;
- llvm::SmallVector<ObjCMethodDecl *, 2> Instance;
- llvm::SmallVector<ObjCMethodDecl *, 2> Factory;
+ SmallVector<ObjCMethodDecl *, 2> Instance;
+ SmallVector<ObjCMethodDecl *, 2> Factory;
};
typedef Selector external_key_type;
@@ -187,47 +197,33 @@ class HeaderFileInfoTrait {
ModuleFile &M;
HeaderSearch *HS;
const char *FrameworkStrings;
- const char *SearchPath;
- struct stat SearchPathStatBuf;
- llvm::Optional<int> SearchPathStatResult;
-
- int StatSimpleCache(const char *Path, struct stat *StatBuf) {
- if (Path == SearchPath) {
- if (!SearchPathStatResult)
- SearchPathStatResult = stat(Path, &SearchPathStatBuf);
-
- *StatBuf = SearchPathStatBuf;
- return *SearchPathStatResult;
- }
-
- return stat(Path, StatBuf);
- }
-
+
public:
- typedef const char *external_key_type;
- typedef const char *internal_key_type;
+ typedef const FileEntry *external_key_type;
+
+ struct internal_key_type {
+ off_t Size;
+ time_t ModTime;
+ const char *Filename;
+ };
+ typedef const internal_key_type &internal_key_ref;
typedef HeaderFileInfo data_type;
HeaderFileInfoTrait(ASTReader &Reader, ModuleFile &M, HeaderSearch *HS,
- const char *FrameworkStrings,
- const char *SearchPath = 0)
- : Reader(Reader), M(M), HS(HS), FrameworkStrings(FrameworkStrings),
- SearchPath(SearchPath) { }
+ const char *FrameworkStrings)
+ : Reader(Reader), M(M), HS(HS), FrameworkStrings(FrameworkStrings) { }
- static unsigned ComputeHash(const char *path);
- static internal_key_type GetInternalKey(const char *path);
- bool EqualKey(internal_key_type a, internal_key_type b);
+ static unsigned ComputeHash(internal_key_ref ikey);
+ static internal_key_type GetInternalKey(const FileEntry *FE);
+ bool EqualKey(internal_key_ref a, internal_key_ref b);
static std::pair<unsigned, unsigned>
ReadKeyDataLength(const unsigned char*& d);
- static internal_key_type ReadKey(const unsigned char *d, unsigned) {
- return (const char *)d;
- }
+ static internal_key_type ReadKey(const unsigned char *d, unsigned);
- data_type ReadData(const internal_key_type, const unsigned char *d,
- unsigned DataLen);
+ data_type ReadData(internal_key_ref,const unsigned char *d, unsigned DataLen);
};
/// \brief The on-disk hash table used for known header files.
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index 367f75f..078ecb7 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -132,6 +132,8 @@ void ASTStmtReader::VisitCompoundStmt(CompoundStmt *S) {
void ASTStmtReader::VisitSwitchCase(SwitchCase *S) {
VisitStmt(S);
Reader.RecordSwitchCaseID(S, Record[Idx++]);
+ S->setKeywordLoc(ReadSourceLocation(Record, Idx));
+ S->setColonLoc(ReadSourceLocation(Record, Idx));
}
void ASTStmtReader::VisitCaseStmt(CaseStmt *S) {
@@ -139,16 +141,12 @@ void ASTStmtReader::VisitCaseStmt(CaseStmt *S) {
S->setLHS(Reader.ReadSubExpr());
S->setRHS(Reader.ReadSubExpr());
S->setSubStmt(Reader.ReadSubStmt());
- S->setCaseLoc(ReadSourceLocation(Record, Idx));
S->setEllipsisLoc(ReadSourceLocation(Record, Idx));
- S->setColonLoc(ReadSourceLocation(Record, Idx));
}
void ASTStmtReader::VisitDefaultStmt(DefaultStmt *S) {
VisitSwitchCase(S);
S->setSubStmt(Reader.ReadSubStmt());
- S->setDefaultLoc(ReadSourceLocation(Record, Idx));
- S->setColonLoc(ReadSourceLocation(Record, Idx));
}
void ASTStmtReader::VisitLabelStmt(LabelStmt *S) {
@@ -380,8 +378,10 @@ void ASTStmtReader::VisitIntegerLiteral(IntegerLiteral *E) {
void ASTStmtReader::VisitFloatingLiteral(FloatingLiteral *E) {
VisitExpr(E);
- E->setValue(Reader.getContext(), Reader.ReadAPFloat(Record, Idx));
+ E->setRawSemantics(static_cast<Stmt::APFloatSemantics>(Record[Idx++]));
E->setExact(Record[Idx++]);
+ E->setValue(Reader.getContext(),
+ Reader.ReadAPFloat(Record, E->getSemantics(), Idx));
E->setLocation(ReadSourceLocation(Record, Idx));
}
@@ -528,6 +528,7 @@ void ASTStmtReader::VisitObjCIsaExpr(ObjCIsaExpr *E) {
VisitExpr(E);
E->setBase(Reader.ReadSubExpr());
E->setIsaMemberLoc(ReadSourceLocation(Record, Idx));
+ E->setOpLoc(ReadSourceLocation(Record, Idx));
E->setArrow(Record[Idx++]);
}
@@ -892,6 +893,7 @@ void ASTStmtReader::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
VisitExpr(E);
E->setDecl(ReadDeclAs<ObjCIvarDecl>(Record, Idx));
E->setLocation(ReadSourceLocation(Record, Idx));
+ E->setOpLoc(ReadSourceLocation(Record, Idx));
E->setBase(Reader.ReadSubExpr());
E->setIsArrow(Record[Idx++]);
E->setIsFreeIvar(Record[Idx++]);
@@ -1102,6 +1104,7 @@ void ASTStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) {
E->setLocation(ReadSourceLocation(Record, Idx));
E->setElidable(Record[Idx++]);
E->setHadMultipleCandidates(Record[Idx++]);
+ E->setListInitialization(Record[Idx++]);
E->setRequiresZeroInitialization(Record[Idx++]);
E->setConstructionKind((CXXConstructExpr::ConstructionKind)Record[Idx++]);
E->ParenRange = ReadSourceRange(Record, Idx);
@@ -1146,6 +1149,8 @@ void ASTStmtReader::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) {
SourceRange R = ReadSourceRange(Record, Idx);
E->Loc = R.getBegin();
E->RParenLoc = R.getEnd();
+ R = ReadSourceRange(Record, Idx);
+ E->AngleBrackets = R;
}
void ASTStmtReader::VisitCXXStaticCastExpr(CXXStaticCastExpr *E) {
@@ -1596,36 +1601,27 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
Stmt::EmptyShell Empty;
while (true) {
- unsigned Code = Cursor.ReadCode();
- if (Code == llvm::bitc::END_BLOCK) {
- if (Cursor.ReadBlockEnd()) {
- Error("error at end of block in AST file");
- return 0;
- }
+ llvm::BitstreamEntry Entry = Cursor.advanceSkippingSubblocks();
+
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::SubBlock: // Handled for us already.
+ case llvm::BitstreamEntry::Error:
+ Error("malformed block record in AST file");
+ return 0;
+ case llvm::BitstreamEntry::EndBlock:
+ goto Done;
+ case llvm::BitstreamEntry::Record:
+ // The interesting case.
break;
}
- if (Code == llvm::bitc::ENTER_SUBBLOCK) {
- // No known subblocks, always skip them.
- Cursor.ReadSubBlockID();
- if (Cursor.SkipBlock()) {
- Error("malformed block record in AST file");
- return 0;
- }
- continue;
- }
-
- if (Code == llvm::bitc::DEFINE_ABBREV) {
- Cursor.ReadAbbrevRecord();
- continue;
- }
Stmt *S = 0;
Idx = 0;
Record.clear();
bool Finished = false;
bool IsStmtReference = false;
- switch ((StmtCode)Cursor.ReadRecord(Code, Record)) {
+ switch ((StmtCode)Cursor.readRecord(Entry.ID, Record)) {
case STMT_STOP:
Finished = true;
break;
@@ -1868,7 +1864,7 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
case EXPR_INIT_LIST:
- S = new (Context) InitListExpr(getContext(), Empty);
+ S = new (Context) InitListExpr(Empty);
break;
case EXPR_DESIGNATED_INIT:
@@ -2250,11 +2246,8 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
assert(Idx == Record.size() && "Invalid deserialization of statement");
StmtStack.push_back(S);
}
-
-#ifndef NDEBUG
+Done:
assert(StmtStack.size() > PrevNumStmts && "Read too many sub stmts!");
assert(StmtStack.size() == PrevNumStmts + 1 && "Extra expressions on stack!");
-#endif
-
return StmtStack.pop_back_val();
}
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index a2e8b71..cf93d1c 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -13,24 +13,15 @@
#include "clang/Serialization/ASTWriter.h"
#include "ASTCommon.h"
-#include "clang/Sema/Sema.h"
-#include "clang/Sema/IdentifierResolver.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclContextInternals.h"
-#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclFriend.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#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"
#include "clang/Basic/OnDiskHashTable.h"
@@ -40,8 +31,18 @@
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/Version.h"
#include "clang/Basic/VersionTuple.h"
+#include "clang/Lex/HeaderSearch.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/Sema/IdentifierResolver.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Serialization/ASTReader.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Bitcode/BitstreamWriter.h"
#include "llvm/Support/FileSystem.h"
@@ -353,7 +354,7 @@ ASTTypeWriter::VisitDependentTemplateSpecializationType(
void ASTTypeWriter::VisitPackExpansionType(const PackExpansionType *T) {
Writer.AddTypeRef(T->getPattern(), Record);
- if (llvm::Optional<unsigned> NumExpansions = T->getNumExpansions())
+ if (Optional<unsigned> NumExpansions = T->getNumExpansions())
Record.push_back(*NumExpansions + 1);
else
Record.push_back(0);
@@ -777,6 +778,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(TARGET_OPTIONS);
RECORD(ORIGINAL_FILE);
RECORD(ORIGINAL_PCH_DIR);
+ RECORD(ORIGINAL_FILE_ID);
RECORD(INPUT_FILE_OFFSETS);
RECORD(DIAGNOSTIC_OPTIONS);
RECORD(FILE_SYSTEM_OPTIONS);
@@ -797,7 +799,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(STATISTICS);
RECORD(TENTATIVE_DEFINITIONS);
RECORD(UNUSED_FILESCOPED_DECLS);
- RECORD(LOCALLY_SCOPED_EXTERNAL_DECLS);
+ RECORD(LOCALLY_SCOPED_EXTERN_C_DECLS);
RECORD(SELECTOR_OFFSETS);
RECORD(METHOD_POOL);
RECORD(PP_COUNTER_VALUE);
@@ -823,6 +825,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(OPENCL_EXTENSIONS);
RECORD(DELEGATING_CTORS);
RECORD(KNOWN_NAMESPACES);
+ RECORD(UNDEFINED_BUT_USED);
RECORD(MODULE_OFFSET_MAP);
RECORD(SOURCE_MANAGER_LINE_TABLE);
RECORD(OBJC_CATEGORIES_MAP);
@@ -832,7 +835,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(LOCAL_REDECLARATIONS);
RECORD(OBJC_CATEGORIES);
RECORD(MACRO_OFFSET);
- RECORD(MACRO_UPDATES);
+ RECORD(MACRO_TABLE);
// SourceManager Block.
BLOCK(SOURCE_MANAGER_BLOCK);
@@ -1020,7 +1023,7 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
// Imports
if (Chain) {
serialization::ModuleManager &Mgr = Chain->getModuleManager();
- llvm::SmallVector<char, 128> ModulePaths;
+ SmallVector<char, 128> ModulePaths;
Record.clear();
for (ModuleManager::ModuleIterator M = Mgr.begin(), MEnd = Mgr.end();
@@ -1030,7 +1033,9 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
continue;
Record.push_back((unsigned)(*M)->Kind); // FIXME: Stable encoding
- // FIXME: Write import location, once it matters.
+ AddSourceLocation((*M)->ImportLoc, Record);
+ Record.push_back((*M)->File->getSize());
+ Record.push_back((*M)->File->getModificationTime());
// FIXME: This writes the absolute path for AST files we depend on.
const std::string &FileName = (*M)->FileName;
Record.push_back(FileName.size());
@@ -1047,12 +1052,24 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \
Record.push_back(static_cast<unsigned>(LangOpts.get##Name()));
#include "clang/Basic/LangOptions.def"
+#define SANITIZER(NAME, ID) Record.push_back(LangOpts.Sanitize.ID);
+#include "clang/Basic/Sanitizers.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());
+
+ // Comment options.
+ Record.push_back(LangOpts.CommentOpts.BlockCommandNames.size());
+ for (CommentOptions::BlockCommandNamesTy::const_iterator
+ I = LangOpts.CommentOpts.BlockCommandNames.begin(),
+ IEnd = LangOpts.CommentOpts.BlockCommandNames.end();
+ I != IEnd; ++I) {
+ AddString(*I, Record);
+ }
+
Stream.EmitRecord(LANGUAGE_OPTIONS, Record);
// Target options.
@@ -1108,11 +1125,8 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
const HeaderSearchOptions::Entry &Entry = HSOpts.UserEntries[I];
AddString(Entry.Path, Record);
Record.push_back(static_cast<unsigned>(Entry.Group));
- Record.push_back(Entry.IsUserSupplied);
Record.push_back(Entry.IsFramework);
Record.push_back(Entry.IgnoreSysRoot);
- Record.push_back(Entry.IsInternal);
- Record.push_back(Entry.ImplicitExternC);
}
// System header prefixes.
@@ -1180,6 +1194,10 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr);
}
+ Record.clear();
+ Record.push_back(SM.getMainFileID().getOpaqueValue());
+ Stream.EmitRecord(ORIGINAL_FILE_ID, Record);
+
// Original PCH directory
if (!OutputFile.empty() && OutputFile != "-") {
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
@@ -1197,11 +1215,24 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context,
Stream.EmitRecordWithBlob(AbbrevCode, Record, origDir);
}
- WriteInputFiles(Context.SourceMgr, isysroot);
+ WriteInputFiles(Context.SourceMgr,
+ PP.getHeaderSearchInfo().getHeaderSearchOpts(),
+ isysroot);
Stream.ExitBlock();
}
-void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) {
+namespace {
+ /// \brief An input file.
+ struct InputFileEntry {
+ const FileEntry *File;
+ bool IsSystemFile;
+ bool BufferOverridden;
+ };
+}
+
+void ASTWriter::WriteInputFiles(SourceManager &SourceMgr,
+ HeaderSearchOptions &HSOpts,
+ StringRef isysroot) {
using namespace llvm;
Stream.EnterSubblock(INPUT_FILES_BLOCK_ID, 4);
RecordData Record;
@@ -1216,8 +1247,9 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) {
IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name
unsigned IFAbbrevCode = Stream.EmitAbbrev(IFAbbrev);
- // Write out all of the input files.
- std::vector<uint32_t> InputFileOffsets;
+ // Get all ContentCache objects for files, sorted by whether the file is a
+ // system one or not. System files go at the back, users files at the front.
+ std::deque<InputFileEntry> SortedFiles;
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);
@@ -1230,28 +1262,67 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) {
if (!Cache->OrigEntry)
continue;
+ InputFileEntry Entry;
+ Entry.File = Cache->OrigEntry;
+ Entry.IsSystemFile = Cache->IsSystemFile;
+ Entry.BufferOverridden = Cache->BufferOverridden;
+ if (Cache->IsSystemFile)
+ SortedFiles.push_back(Entry);
+ else
+ SortedFiles.push_front(Entry);
+ }
+
+ // If we have an isysroot for a Darwin SDK, include its SDKSettings.plist in
+ // the set of (non-system) input files. This is simple heuristic for
+ // detecting whether the system headers may have changed, because it is too
+ // expensive to stat() all of the system headers.
+ FileManager &FileMgr = SourceMgr.getFileManager();
+ if (!HSOpts.Sysroot.empty() && !Chain) {
+ llvm::SmallString<128> SDKSettingsFileName(HSOpts.Sysroot);
+ llvm::sys::path::append(SDKSettingsFileName, "SDKSettings.plist");
+ if (const FileEntry *SDKSettingsFile = FileMgr.getFile(SDKSettingsFileName)) {
+ InputFileEntry Entry = { SDKSettingsFile, false, false };
+ SortedFiles.push_front(Entry);
+ }
+ }
+
+ unsigned UserFilesNum = 0;
+ // Write out all of the input files.
+ std::vector<uint32_t> InputFileOffsets;
+ for (std::deque<InputFileEntry>::iterator
+ I = SortedFiles.begin(), E = SortedFiles.end(); I != E; ++I) {
+ const InputFileEntry &Entry = *I;
+
+ uint32_t &InputFileID = InputFileIDs[Entry.File];
+ if (InputFileID != 0)
+ continue; // already recorded this file.
+
// Record this entry's offset.
InputFileOffsets.push_back(Stream.GetCurrentBitNo());
- InputFileIDs[Cache->OrigEntry] = InputFileOffsets.size();
+
+ InputFileID = InputFileOffsets.size();
+
+ if (!Entry.IsSystemFile)
+ ++UserFilesNum;
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());
+ Record.push_back(Entry.File->getSize());
+ Record.push_back(Entry.File->getModificationTime());
// Whether this file was overridden.
- Record.push_back(Cache->BufferOverridden);
+ Record.push_back(Entry.BufferOverridden);
// Turn the file name into an absolute path, if it isn't already.
- const char *Filename = Cache->OrigEntry->getName();
+ const char *Filename = Entry.File->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);
+ FileMgr.FixupRelativePath(FilePath);
// FIXME: This call to make_absolute shouldn't be necessary, the
// call to FixupRelativePath should always return an absolute path.
@@ -1262,13 +1333,15 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) {
Stream.EmitRecordWithBlob(IFAbbrevCode, Record, Filename);
}
-
+
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::VBR, 6)); // # non-system
+ // input files
OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Array
unsigned OffsetsAbbrevCode = Stream.EmitAbbrev(OffsetsAbbrev);
@@ -1276,58 +1349,11 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) {
Record.clear();
Record.push_back(INPUT_FILE_OFFSETS);
Record.push_back(InputFileOffsets.size());
+ Record.push_back(UserFilesNum);
Stream.EmitRecordWithBlob(OffsetsAbbrevCode, Record, data(InputFileOffsets));
}
//===----------------------------------------------------------------------===//
-// stat cache Serialization
-//===----------------------------------------------------------------------===//
-
-namespace {
-// Trait used for the on-disk hash table of stat cache results.
-class ASTStatCacheTrait {
-public:
- typedef const char * key_type;
- typedef key_type key_type_ref;
-
- typedef struct stat data_type;
- typedef const data_type &data_type_ref;
-
- static unsigned ComputeHash(const char *path) {
- return llvm::HashString(path);
- }
-
- std::pair<unsigned,unsigned>
- EmitKeyDataLength(raw_ostream& Out, const char *path,
- data_type_ref Data) {
- unsigned StrLen = strlen(path);
- clang::io::Emit16(Out, StrLen);
- unsigned DataLen = 4 + 4 + 2 + 8 + 8;
- clang::io::Emit8(Out, DataLen);
- return std::make_pair(StrLen + 1, DataLen);
- }
-
- void EmitKey(raw_ostream& Out, const char *path, unsigned KeyLen) {
- Out.write(path, KeyLen);
- }
-
- void EmitData(raw_ostream &Out, key_type_ref,
- data_type_ref Data, unsigned DataLen) {
- using namespace clang::io;
- uint64_t Start = Out.tell(); (void)Start;
-
- Emit32(Out, (uint32_t) Data.st_ino);
- Emit32(Out, (uint32_t) Data.st_dev);
- Emit16(Out, (uint16_t) Data.st_mode);
- Emit64(Out, (uint64_t) Data.st_mtime);
- Emit64(Out, (uint64_t) Data.st_size);
-
- assert(Out.tell() - Start == DataLen && "Wrong data length");
- }
-};
-} // end anonymous namespace
-
-//===----------------------------------------------------------------------===//
// Source Manager Serialization
//===----------------------------------------------------------------------===//
@@ -1391,44 +1417,53 @@ namespace {
// Trait used for the on-disk hash table of header search information.
class HeaderFileInfoTrait {
ASTWriter &Writer;
+ const HeaderSearch &HS;
// Keep track of the framework names we've used during serialization.
SmallVector<char, 128> FrameworkStringData;
llvm::StringMap<unsigned> FrameworkNameOffset;
public:
- HeaderFileInfoTrait(ASTWriter &Writer)
- : Writer(Writer) { }
+ HeaderFileInfoTrait(ASTWriter &Writer, const HeaderSearch &HS)
+ : Writer(Writer), HS(HS) { }
- typedef const char *key_type;
- typedef key_type key_type_ref;
+ struct key_type {
+ const FileEntry *FE;
+ const char *Filename;
+ };
+ typedef const key_type &key_type_ref;
typedef HeaderFileInfo data_type;
typedef const data_type &data_type_ref;
- static unsigned ComputeHash(const char *path) {
- // The hash is based only on the filename portion of the key, so that the
- // reader can match based on filenames when symlinking or excess path
- // elements ("foo/../", "../") change the form of the name. However,
- // complete path is still the key.
- return llvm::HashString(llvm::sys::path::filename(path));
+ static unsigned ComputeHash(key_type_ref key) {
+ // The hash is based only on size/time of the file, so that the reader can
+ // match even when symlinking or excess path elements ("foo/../", "../")
+ // change the form of the name. However, complete path is still the key.
+ return llvm::hash_combine(key.FE->getSize(),
+ key.FE->getModificationTime());
}
std::pair<unsigned,unsigned>
- EmitKeyDataLength(raw_ostream& Out, const char *path,
- data_type_ref Data) {
- unsigned StrLen = strlen(path);
- clang::io::Emit16(Out, StrLen);
+ EmitKeyDataLength(raw_ostream& Out, key_type_ref key, data_type_ref Data) {
+ unsigned KeyLen = strlen(key.Filename) + 1 + 8 + 8;
+ clang::io::Emit16(Out, KeyLen);
unsigned DataLen = 1 + 2 + 4 + 4;
+ if (Data.isModuleHeader)
+ DataLen += 4;
clang::io::Emit8(Out, DataLen);
- return std::make_pair(StrLen + 1, DataLen);
+ return std::make_pair(KeyLen, DataLen);
}
- void EmitKey(raw_ostream& Out, const char *path, unsigned KeyLen) {
- Out.write(path, KeyLen);
+ void EmitKey(raw_ostream& Out, key_type_ref key, unsigned KeyLen) {
+ clang::io::Emit64(Out, key.FE->getSize());
+ KeyLen -= 8;
+ clang::io::Emit64(Out, key.FE->getModificationTime());
+ KeyLen -= 8;
+ Out.write(key.Filename, KeyLen);
}
- void EmitData(raw_ostream &Out, key_type_ref,
+ void EmitData(raw_ostream &Out, key_type_ref key,
data_type_ref Data, unsigned DataLen) {
using namespace clang::io;
uint64_t Start = Out.tell(); (void)Start;
@@ -1462,7 +1497,12 @@ namespace {
Offset = Pos->second;
}
Emit32(Out, Offset);
-
+
+ if (Data.isModuleHeader) {
+ Module *Mod = HS.findModuleForHeader(key.FE);
+ Emit32(Out, Writer.getExistingSubmoduleID(Mod));
+ }
+
assert(Out.tell() - Start == DataLen && "Wrong data length");
}
@@ -1481,7 +1521,7 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) {
if (FilesByUID.size() > HS.header_file_size())
FilesByUID.resize(HS.header_file_size());
- HeaderFileInfoTrait GeneratorTrait(*this);
+ HeaderFileInfoTrait GeneratorTrait(*this, HS);
OnDiskChainedHashTableGenerator<HeaderFileInfoTrait> Generator;
SmallVector<const char *, 4> SavedStrings;
unsigned NumHeaderSearchEntries = 0;
@@ -1507,7 +1547,8 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) {
SavedStrings.push_back(Filename);
}
- Generator.insert(Filename, HFI, GeneratorTrait);
+ HeaderFileInfoTrait::key_type key = { File, Filename };
+ Generator.insert(key, HFI, GeneratorTrait);
++NumHeaderSearchEntries;
}
@@ -1542,7 +1583,7 @@ void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) {
// Free all of the strings we had to duplicate.
for (unsigned I = 0, N = SavedStrings.size(); I != N; ++I)
- free((void*)SavedStrings[I]);
+ free(const_cast<char *>(SavedStrings[I]));
}
/// \brief Writes the block containing the serialized form of the
@@ -1746,14 +1787,67 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr,
// Preprocessor Serialization
//===----------------------------------------------------------------------===//
-static int compareMacroDefinitions(const void *XPtr, const void *YPtr) {
- const std::pair<const IdentifierInfo *, MacroInfo *> &X =
- *(const std::pair<const IdentifierInfo *, MacroInfo *>*)XPtr;
- const std::pair<const IdentifierInfo *, MacroInfo *> &Y =
- *(const std::pair<const IdentifierInfo *, MacroInfo *>*)YPtr;
+namespace {
+class ASTMacroTableTrait {
+public:
+ typedef IdentID key_type;
+ typedef key_type key_type_ref;
+
+ struct Data {
+ uint32_t MacroDirectivesOffset;
+ };
+
+ typedef Data data_type;
+ typedef const data_type &data_type_ref;
+
+ static unsigned ComputeHash(IdentID IdID) {
+ return llvm::hash_value(IdID);
+ }
+
+ std::pair<unsigned,unsigned>
+ static EmitKeyDataLength(raw_ostream& Out,
+ key_type_ref Key, data_type_ref Data) {
+ unsigned KeyLen = 4; // IdentID.
+ unsigned DataLen = 4; // MacroDirectivesOffset.
+ return std::make_pair(KeyLen, DataLen);
+ }
+
+ static void EmitKey(raw_ostream& Out, key_type_ref Key, unsigned KeyLen) {
+ clang::io::Emit32(Out, Key);
+ }
+
+ static void EmitData(raw_ostream& Out, key_type_ref Key, data_type_ref Data,
+ unsigned) {
+ clang::io::Emit32(Out, Data.MacroDirectivesOffset);
+ }
+};
+} // end anonymous namespace
+
+static int compareMacroDirectives(const void *XPtr, const void *YPtr) {
+ const std::pair<const IdentifierInfo *, MacroDirective *> &X =
+ *(const std::pair<const IdentifierInfo *, MacroDirective *>*)XPtr;
+ const std::pair<const IdentifierInfo *, MacroDirective *> &Y =
+ *(const std::pair<const IdentifierInfo *, MacroDirective *>*)YPtr;
return X.first->getName().compare(Y.first->getName());
}
+static bool shouldIgnoreMacro(MacroDirective *MD, bool IsModule,
+ const Preprocessor &PP) {
+ if (MacroInfo *MI = MD->getMacroInfo())
+ if (MI->isBuiltinMacro())
+ return true;
+
+ if (IsModule) {
+ SourceLocation Loc = MD->getLocation();
+ if (Loc.isInvalid())
+ return true;
+ if (PP.getSourceManager().getFileID(Loc) == PP.getPredefinesFileID())
+ return true;
+ }
+
+ return false;
+}
+
/// \brief Writes the block containing the serialized form of the
/// preprocessor.
///
@@ -1780,26 +1874,73 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
fprintf(stderr, "warning: precompiled header used __DATE__ or __TIME__.\n");
- // Loop over all the macro definitions that are live at the end of the file,
+ // Loop over all the macro directives that are live at the end of the file,
// emitting each to the PP section.
- // Construct the list of macro definitions that need to be serialized.
- SmallVector<std::pair<const IdentifierInfo *, MacroInfo *>, 2>
- MacrosToEmit;
- llvm::SmallPtrSet<const IdentifierInfo*, 4> MacroDefinitionsSeen;
- for (Preprocessor::macro_iterator I = PP.macro_begin(Chain == 0),
- E = PP.macro_end(Chain == 0);
+ // Construct the list of macro directives that need to be serialized.
+ SmallVector<std::pair<const IdentifierInfo *, MacroDirective *>, 2>
+ MacroDirectives;
+ for (Preprocessor::macro_iterator
+ I = PP.macro_begin(/*IncludeExternalMacros=*/false),
+ E = PP.macro_end(/*IncludeExternalMacros=*/false);
I != E; ++I) {
- if (!IsModule || I->second->isPublic()) {
- MacroDefinitionsSeen.insert(I->first);
- MacrosToEmit.push_back(std::make_pair(I->first, I->second));
- }
+ MacroDirectives.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(),
- &compareMacroDefinitions);
+ llvm::array_pod_sort(MacroDirectives.begin(), MacroDirectives.end(),
+ &compareMacroDirectives);
+
+ OnDiskChainedHashTableGenerator<ASTMacroTableTrait> Generator;
+
+ // Emit the macro directives as a list and associate the offset with the
+ // identifier they belong to.
+ for (unsigned I = 0, N = MacroDirectives.size(); I != N; ++I) {
+ const IdentifierInfo *Name = MacroDirectives[I].first;
+ uint64_t MacroDirectiveOffset = Stream.GetCurrentBitNo();
+ MacroDirective *MD = MacroDirectives[I].second;
+
+ // If the macro or identifier need no updates, don't write the macro history
+ // for this one.
+ // FIXME: Chain the macro history instead of re-writing it.
+ if (MD->isFromPCH() &&
+ Name->isFromAST() && !Name->hasChangedSinceDeserialization())
+ continue;
+
+ // Emit the macro directives in reverse source order.
+ for (; MD; MD = MD->getPrevious()) {
+ if (MD->isHidden())
+ continue;
+ if (shouldIgnoreMacro(MD, IsModule, PP))
+ continue;
+
+ AddSourceLocation(MD->getLocation(), Record);
+ Record.push_back(MD->getKind());
+ if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD)) {
+ MacroID InfoID = getMacroRef(DefMD->getInfo(), Name);
+ Record.push_back(InfoID);
+ Record.push_back(DefMD->isImported());
+ Record.push_back(DefMD->isAmbiguous());
+
+ } else if (VisibilityMacroDirective *
+ VisMD = dyn_cast<VisibilityMacroDirective>(MD)) {
+ Record.push_back(VisMD->isPublic());
+ }
+ }
+ if (Record.empty())
+ continue;
+
+ Stream.EmitRecord(PP_MACRO_DIRECTIVE_HISTORY, Record);
+ Record.clear();
+
+ IdentMacroDirectivesOffsetMap[Name] = MacroDirectiveOffset;
+
+ IdentID NameID = getIdentifierRef(Name);
+ ASTMacroTableTrait::Data data;
+ data.MacroDirectivesOffset = MacroDirectiveOffset;
+ Generator.insert(NameID, data);
+ }
/// \brief Offsets of each of the macros into the bitstream, indexed by
/// the local macro ID
@@ -1809,95 +1950,107 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) {
/// defined.
std::vector<uint32_t> MacroOffsets;
- for (unsigned I = 0, N = MacrosToEmit.size(); I != N; ++I) {
- const IdentifierInfo *Name = MacrosToEmit[I].first;
+ for (unsigned I = 0, N = MacroInfosToEmit.size(); I != N; ++I) {
+ const IdentifierInfo *Name = MacroInfosToEmit[I].Name;
+ MacroInfo *MI = MacroInfosToEmit[I].MI;
+ MacroID ID = MacroInfosToEmit[I].ID;
- for (MacroInfo *MI = MacrosToEmit[I].second; MI;
- MI = MI->getPreviousDefinition()) {
- MacroID ID = getMacroRef(MI);
- if (!ID)
- continue;
+ if (ID < FirstMacroID) {
+ assert(0 && "Loaded MacroInfo entered MacroInfosToEmit ?");
+ continue;
+ }
- // Skip macros from a AST file if we're chaining.
- if (Chain && MI->isFromAST() && !MI->hasChangedAfterLoad())
- continue;
+ // 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);
- if (ID < FirstMacroID) {
- // This will have been dealt with via an update record.
- assert(MacroUpdates.count(MI) > 0 && "Missing macro update");
- continue;
- }
+ MacroOffsets[Index] = Stream.GetCurrentBitNo();
+ }
- // 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);
+ AddIdentifierRef(Name, Record);
+ Record.push_back(inferSubmoduleIDFromLocation(MI->getDefinitionLoc()));
+ AddSourceLocation(MI->getDefinitionLoc(), Record);
+ AddSourceLocation(MI->getDefinitionEndLoc(), Record);
+ Record.push_back(MI->isUsed());
+ unsigned Code;
+ if (MI->isObjectLike()) {
+ Code = PP_MACRO_OBJECT_LIKE;
+ } else {
+ Code = PP_MACRO_FUNCTION_LIKE;
- MacroOffsets[Index] = Stream.GetCurrentBitNo();
- }
+ Record.push_back(MI->isC99Varargs());
+ Record.push_back(MI->isGNUVarargs());
+ Record.push_back(MI->hasCommaPasting());
+ Record.push_back(MI->getNumArgs());
+ for (MacroInfo::arg_iterator I = MI->arg_begin(), E = MI->arg_end();
+ I != E; ++I)
+ AddIdentifierRef(*I, Record);
+ }
- 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)]);
- // 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();
- Stream.EmitRecord(Code, Record);
+ // 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();
-
- // 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.
+ // Create the on-disk hash table in a buffer.
+ SmallString<4096> MacroTable;
+ uint32_t BucketOffset;
+ {
+ llvm::raw_svector_ostream Out(MacroTable);
+ // Make sure that no bucket is at offset 0
+ clang::io::Emit32(Out, 0);
+ BucketOffset = Generator.Emit(Out);
+ }
+
+ // Write the macro table
using namespace llvm;
BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(MACRO_TABLE));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned MacroTableAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Record.push_back(MACRO_TABLE);
+ Record.push_back(BucketOffset);
+ Stream.EmitRecordWithBlob(MacroTableAbbrev, Record, MacroTable.str());
+ Record.clear();
+
+ // Write the offsets table for macro IDs.
+ using namespace llvm;
+ Abbrev = new BitCodeAbbrev();
Abbrev->Add(BitCodeAbbrevOp(MACRO_OFFSET));
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of macros
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first ID
@@ -2019,6 +2172,18 @@ unsigned ASTWriter::getSubmoduleID(Module *Mod) {
return SubmoduleIDs[Mod] = NextSubmoduleID++;
}
+unsigned ASTWriter::getExistingSubmoduleID(Module *Mod) const {
+ if (!Mod)
+ return 0;
+
+ llvm::DenseMap<Module *, unsigned>::const_iterator
+ Known = SubmoduleIDs.find(Mod);
+ if (Known != SubmoduleIDs.end())
+ return Known->second;
+
+ return 0;
+}
+
/// \brief Compute the number of modules within the given tree (including the
/// given module).
static unsigned getNumberOfModules(Module *Mod) {
@@ -2062,6 +2227,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferSubmodules...
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExplicit...
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExportWild...
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ConfigMacrosExh...
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
unsigned DefinitionAbbrev = Stream.EmitAbbrev(Abbrev);
@@ -2095,6 +2261,23 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
unsigned ExcludedHeaderAbbrev = Stream.EmitAbbrev(Abbrev);
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_LINK_LIBRARY));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+ unsigned LinkLibraryAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_CONFIG_MACRO));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Macro name
+ unsigned ConfigMacroAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_CONFLICT));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Other module
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Message
+ unsigned ConflictAbbrev = Stream.EmitAbbrev(Abbrev);
+
// Write the submodule metadata block.
RecordData Record;
Record.push_back(getNumberOfModules(WritingModule));
@@ -2125,6 +2308,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Record.push_back(Mod->InferSubmodules);
Record.push_back(Mod->InferExplicitSubmodules);
Record.push_back(Mod->InferExportWildcard);
+ Record.push_back(Mod->ConfigMacrosExhaustive);
Stream.EmitRecordWithBlob(DefinitionAbbrev, Record, Mod->Name);
// Emit the requirements.
@@ -2163,11 +2347,13 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Stream.EmitRecordWithBlob(ExcludedHeaderAbbrev, Record,
Mod->ExcludedHeaders[I]->getName());
}
- for (unsigned I = 0, N = Mod->TopHeaders.size(); I != N; ++I) {
+ ArrayRef<const FileEntry *>
+ TopHeaders = Mod->getTopHeaders(PP->getFileManager());
+ for (unsigned I = 0, N = TopHeaders.size(); I != N; ++I) {
Record.clear();
Record.push_back(SUBMODULE_TOPHEADER);
Stream.EmitRecordWithBlob(TopHeaderAbbrev, Record,
- Mod->TopHeaders[I]->getName());
+ TopHeaders[I]->getName());
}
// Emit the imports.
@@ -2197,7 +2383,35 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
}
Stream.EmitRecord(SUBMODULE_EXPORTS, Record);
}
-
+
+ // Emit the link libraries.
+ for (unsigned I = 0, N = Mod->LinkLibraries.size(); I != N; ++I) {
+ Record.clear();
+ Record.push_back(SUBMODULE_LINK_LIBRARY);
+ Record.push_back(Mod->LinkLibraries[I].IsFramework);
+ Stream.EmitRecordWithBlob(LinkLibraryAbbrev, Record,
+ Mod->LinkLibraries[I].Library);
+ }
+
+ // Emit the conflicts.
+ for (unsigned I = 0, N = Mod->Conflicts.size(); I != N; ++I) {
+ Record.clear();
+ Record.push_back(SUBMODULE_CONFLICT);
+ unsigned OtherID = getSubmoduleID(Mod->Conflicts[I].Other);
+ assert(OtherID && "Unknown submodule!");
+ Record.push_back(OtherID);
+ Stream.EmitRecordWithBlob(ConflictAbbrev, Record,
+ Mod->Conflicts[I].Message);
+ }
+
+ // Emit the configuration macros.
+ for (unsigned I = 0, N = Mod->ConfigMacros.size(); I != N; ++I) {
+ Record.clear();
+ Record.push_back(SUBMODULE_CONFIG_MACRO);
+ Stream.EmitRecordWithBlob(ConfigMacroAbbrev, Record,
+ Mod->ConfigMacros[I]);
+ }
+
// Queue up the submodules of this module.
for (Module::submodule_iterator Sub = Mod->submodule_begin(),
SubEnd = Mod->submodule_end();
@@ -2230,8 +2444,14 @@ ASTWriter::inferSubmoduleIDFromLocation(SourceLocation Loc) {
return getSubmoduleID(OwningMod);
}
-void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag) {
- // FIXME: Make it work properly with modules.
+void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag,
+ bool isModule) {
+ // Make sure set diagnostic pragmas don't affect the translation unit that
+ // imports the module.
+ // FIXME: Make diagnostic pragma sections work properly with modules.
+ if (isModule)
+ return;
+
llvm::SmallDenseMap<const DiagnosticsEngine::DiagState *, unsigned, 64>
DiagStateIDMap;
unsigned CurrID = 0;
@@ -2664,7 +2884,7 @@ class ASTIdentifierTableTrait {
/// \brief Determines whether this is an "interesting" identifier
/// that needs a full IdentifierInfo structure written into the hash
/// table.
- bool isInterestingIdentifier(IdentifierInfo *II, MacroInfo *&Macro) {
+ bool isInterestingIdentifier(IdentifierInfo *II, MacroDirective *&Macro) {
if (II->isPoisoned() ||
II->isExtensionToken() ||
II->getObjCOrBuiltinID() ||
@@ -2675,16 +2895,101 @@ class ASTIdentifierTableTrait {
return hadMacroDefinition(II, Macro);
}
- bool hadMacroDefinition(IdentifierInfo *II, MacroInfo *&Macro) {
+ bool hadMacroDefinition(IdentifierInfo *II, MacroDirective *&Macro) {
if (!II->hadMacroDefinition())
return false;
- if (Macro || (Macro = PP.getMacroInfoHistory(II)))
- return !Macro->isBuiltinMacro() && (!IsModule || Macro->isPublic());
+ if (Macro || (Macro = PP.getMacroDirectiveHistory(II))) {
+ if (!IsModule)
+ return !shouldIgnoreMacro(Macro, IsModule, PP);
+ SubmoduleID ModID;
+ if (getFirstPublicSubmoduleMacro(Macro, ModID))
+ return true;
+ }
return false;
}
+ DefMacroDirective *getFirstPublicSubmoduleMacro(MacroDirective *MD,
+ SubmoduleID &ModID) {
+ ModID = 0;
+ if (DefMacroDirective *DefMD = getPublicSubmoduleMacro(MD, ModID))
+ if (!shouldIgnoreMacro(DefMD, IsModule, PP))
+ return DefMD;
+ return 0;
+ }
+
+ DefMacroDirective *getNextPublicSubmoduleMacro(DefMacroDirective *MD,
+ SubmoduleID &ModID) {
+ if (DefMacroDirective *
+ DefMD = getPublicSubmoduleMacro(MD->getPrevious(), ModID))
+ if (!shouldIgnoreMacro(DefMD, IsModule, PP))
+ return DefMD;
+ return 0;
+ }
+
+ /// \brief Traverses the macro directives history and returns the latest
+ /// macro that is public and not undefined in the same submodule.
+ /// A macro that is defined in submodule A and undefined in submodule B,
+ /// will still be considered as defined/exported from submodule A.
+ DefMacroDirective *getPublicSubmoduleMacro(MacroDirective *MD,
+ SubmoduleID &ModID) {
+ if (!MD)
+ return 0;
+
+ SubmoduleID OrigModID = ModID;
+ bool isUndefined = false;
+ Optional<bool> isPublic;
+ for (; MD; MD = MD->getPrevious()) {
+ if (MD->isHidden())
+ continue;
+
+ SubmoduleID ThisModID = getSubmoduleID(MD);
+ if (ThisModID == 0) {
+ isUndefined = false;
+ isPublic = Optional<bool>();
+ continue;
+ }
+ if (ThisModID != ModID){
+ ModID = ThisModID;
+ isUndefined = false;
+ isPublic = Optional<bool>();
+ }
+ // We are looking for a definition in a different submodule than the one
+ // that we started with. If a submodule has re-definitions of the same
+ // macro, only the last definition will be used as the "exported" one.
+ if (ModID == OrigModID)
+ continue;
+
+ if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD)) {
+ if (!isUndefined && (!isPublic.hasValue() || isPublic.getValue()))
+ return DefMD;
+ continue;
+ }
+
+ if (isa<UndefMacroDirective>(MD)) {
+ isUndefined = true;
+ continue;
+ }
+
+ VisibilityMacroDirective *VisMD = cast<VisibilityMacroDirective>(MD);
+ if (!isPublic.hasValue())
+ isPublic = VisMD->isPublic();
+ }
+
+ return 0;
+ }
+
+ SubmoduleID getSubmoduleID(MacroDirective *MD) {
+ if (DefMacroDirective *DefMD = dyn_cast<DefMacroDirective>(MD)) {
+ MacroInfo *MI = DefMD->getInfo();
+ if (unsigned ID = MI->getOwningModuleID())
+ return ID;
+ return Writer.inferSubmoduleIDFromLocation(MI->getDefinitionLoc());
+ }
+ return Writer.inferSubmoduleIDFromLocation(MD->getLocation());
+ }
+
public:
typedef IdentifierInfo* key_type;
typedef key_type key_type_ref;
@@ -2704,17 +3009,21 @@ public:
EmitKeyDataLength(raw_ostream& Out, IdentifierInfo* II, IdentID ID) {
unsigned KeyLen = II->getLength() + 1;
unsigned DataLen = 4; // 4 bytes for the persistent ID << 1
- MacroInfo *Macro = 0;
+ MacroDirective *Macro = 0;
if (isInterestingIdentifier(II, Macro)) {
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; // MacroDirectives offset.
+ if (IsModule) {
+ SubmoduleID ModID;
+ for (DefMacroDirective *
+ DefMD = getFirstPublicSubmoduleMacro(Macro, ModID);
+ DefMD; DefMD = getNextPublicSubmoduleMacro(DefMD, ModID)) {
+ DataLen += 4; // MacroInfo ID.
+ }
+ DataLen += 4;
}
-
- DataLen += 4;
}
for (IdentifierResolver::iterator D = IdResolver.begin(II),
@@ -2740,7 +3049,7 @@ public:
void EmitData(raw_ostream& Out, IdentifierInfo* II,
IdentID ID, unsigned) {
- MacroInfo *Macro = 0;
+ MacroDirective *Macro = 0;
if (!isInterestingIdentifier(II, Macro)) {
clang::io::Emit32(Out, ID << 1);
return;
@@ -2753,6 +3062,7 @@ public:
Bits = 0;
bool HadMacroDefinition = hadMacroDefinition(II, Macro);
Bits = (Bits << 1) | unsigned(HadMacroDefinition);
+ Bits = (Bits << 1) | unsigned(IsModule);
Bits = (Bits << 1) | unsigned(II->isExtensionToken());
Bits = (Bits << 1) | unsigned(II->isPoisoned());
Bits = (Bits << 1) | unsigned(II->hasRevertedTokenIDToIdentifier());
@@ -2760,13 +3070,19 @@ public:
clang::io::Emit16(Out, Bits);
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, Writer.getMacroDirectivesOffset(II));
+ if (IsModule) {
+ // Write the IDs of macros coming from different submodules.
+ SubmoduleID ModID;
+ for (DefMacroDirective *
+ DefMD = getFirstPublicSubmoduleMacro(Macro, ModID);
+ DefMD; DefMD = getNextPublicSubmoduleMacro(DefMD, ModID)) {
+ MacroID InfoID = Writer.getMacroID(DefMD->getInfo());
+ assert(InfoID);
+ clang::io::Emit32(Out, InfoID);
+ }
+ clang::io::Emit32(Out, 0);
}
-
- clang::io::Emit32(Out, 0);
}
// Emit the declaration IDs in reverse order, because the
@@ -2820,7 +3136,7 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP,
assert(ID->first && "NULL identifier in identifier table");
if (!Chain || !ID->first->isFromAST() ||
ID->first->hasChangedSinceDeserialization())
- Generator.insert(const_cast<IdentifierInfo *>(ID->first), ID->second,
+ Generator.insert(const_cast<IdentifierInfo *>(ID->first), ID->second,
Trait);
}
@@ -2857,6 +3173,11 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP,
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
unsigned IdentifierOffsetAbbrev = Stream.EmitAbbrev(Abbrev);
+#ifndef NDEBUG
+ for (unsigned I = 0, N = IdentifierOffsets.size(); I != N; ++I)
+ assert(IdentifierOffsets[I] && "Missing identifier offset?");
+#endif
+
RecordData Record;
Record.push_back(IDENTIFIER_OFFSET);
Record.push_back(IdentifierOffsets.size());
@@ -2936,7 +3257,7 @@ public:
clang::io::Emit16(Out, KeyLen);
// 2 bytes for num of decls and 4 for each DeclID.
- unsigned DataLen = 2 + 4 * (Lookup.second - Lookup.first);
+ unsigned DataLen = 2 + 4 * Lookup.size();
clang::io::Emit16(Out, DataLen);
return std::make_pair(KeyLen, DataLen);
@@ -2976,9 +3297,10 @@ public:
void EmitData(raw_ostream& Out, key_type_ref,
data_type Lookup, unsigned DataLen) {
uint64_t Start = Out.tell(); (void)Start;
- clang::io::Emit16(Out, Lookup.second - Lookup.first);
- for (; Lookup.first != Lookup.second; ++Lookup.first)
- clang::io::Emit32(Out, Writer.GetDeclRef(*Lookup.first));
+ clang::io::Emit16(Out, Lookup.size());
+ for (DeclContext::lookup_iterator I = Lookup.begin(), E = Lookup.end();
+ I != E; ++I)
+ clang::io::Emit32(Out, Writer.GetDeclRef(*I));
assert(Out.tell() - Start == DataLen && "Data length is wrong");
}
@@ -3002,8 +3324,6 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
// If not in C++, we perform name lookup for the translation unit via the
// IdentifierInfo chains, don't bother to build a visible-declarations table.
- // FIXME: In C++ we need the visible declarations in order to "see" the
- // friend declarations, is there a way to do this without writing the table ?
if (DC->isTranslationUnit() && !Context.getLangOpts().CPlusPlus)
return 0;
@@ -3022,12 +3342,12 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
// Create the on-disk hash table representation.
DeclarationName ConversionName;
- llvm::SmallVector<NamedDecl *, 4> ConversionDecls;
+ SmallVector<NamedDecl *, 4> ConversionDecls;
for (StoredDeclsMap::iterator D = Map->begin(), DEnd = Map->end();
D != DEnd; ++D) {
DeclarationName Name = D->first;
DeclContext::lookup_result Result = D->second.getLookupResult();
- if (Result.first != Result.second) {
+ if (!Result.empty()) {
if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) {
// Hash all conversion function names to the same name. The actual
// type information in conversion function name is not used in the
@@ -3036,7 +3356,7 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
// functions under a single key.
if (!ConversionName)
ConversionName = Name;
- ConversionDecls.append(Result.first, Result.second);
+ ConversionDecls.append(Result.begin(), Result.end());
continue;
}
@@ -3095,7 +3415,7 @@ void ASTWriter::WriteDeclContextVisibleUpdate(const DeclContext *DC) {
DeclContext::lookup_result Result = D->second.getLookupResult();
// For any name that appears in this table, the results are complete, i.e.
// they overwrite results from previous PCHs. Merging is always a mess.
- if (Result.first != Result.second)
+ if (!Result.empty())
Generator.insert(Name, Result, Trait);
}
@@ -3156,20 +3476,32 @@ void ASTWriter::WriteRedeclarations() {
LocalRedeclChains.push_back(0); // Placeholder for the size.
// Collect the set of local redeclarations of this declaration.
- for (Decl *Prev = MostRecent; Prev != First;
+ for (Decl *Prev = MostRecent; Prev != First;
Prev = Prev->getPreviousDecl()) {
if (!Prev->isFromASTFile()) {
AddDeclRef(Prev, LocalRedeclChains);
++Size;
}
}
+
+ if (!First->isFromASTFile() && Chain) {
+ Decl *FirstFromAST = MostRecent;
+ for (Decl *Prev = MostRecent; Prev; Prev = Prev->getPreviousDecl()) {
+ if (Prev->isFromASTFile())
+ FirstFromAST = Prev;
+ }
+
+ Chain->MergedDecls[FirstFromAST].push_back(getDeclID(First));
+ }
+
LocalRedeclChains[Offset] = Size;
// Reverse the set of local redeclarations, so that we store them in
// order (since we found them in reverse order).
std::reverse(LocalRedeclChains.end() - Size, LocalRedeclChains.end());
- // Add the mapping from the first ID to the set of local declarations.
+ // Add the mapping from the first ID from the AST to the set of local
+ // declarations.
LocalRedeclarationsInfo Info = { getDeclID(First), Offset };
LocalRedeclsMap.push_back(Info);
@@ -3204,7 +3536,7 @@ void ASTWriter::WriteRedeclarations() {
}
void ASTWriter::WriteObjCCategories() {
- llvm::SmallVector<ObjCCategoriesInfo, 2> CategoriesMap;
+ SmallVector<ObjCCategoriesInfo, 2> CategoriesMap;
RecordData Categories;
for (unsigned I = 0, N = ObjCClassesWithCategories.size(); I != N; ++I) {
@@ -3217,10 +3549,12 @@ void ASTWriter::WriteObjCCategories() {
Categories.push_back(0);
// Add the categories.
- for (ObjCCategoryDecl *Cat = Class->getCategoryList();
- Cat; Cat = Cat->getNextClassCategory(), ++Size) {
- assert(getDeclID(Cat) != 0 && "Bogus category");
- AddDeclRef(Cat, Categories);
+ for (ObjCInterfaceDecl::known_categories_iterator
+ Cat = Class->known_categories_begin(),
+ CatEnd = Class->known_categories_end();
+ Cat != CatEnd; ++Cat, ++Size) {
+ assert(getDeclID(*Cat) != 0 && "Bogus category");
+ AddDeclRef(*Cat, Categories);
}
// Update the size.
@@ -3300,11 +3634,11 @@ void ASTWriter::AddString(StringRef Str, RecordDataImpl &Record) {
void ASTWriter::AddVersionTuple(const VersionTuple &Version,
RecordDataImpl &Record) {
Record.push_back(Version.getMajor());
- if (llvm::Optional<unsigned> Minor = Version.getMinor())
+ if (Optional<unsigned> Minor = Version.getMinor())
Record.push_back(*Minor + 1);
else
Record.push_back(0);
- if (llvm::Optional<unsigned> Subminor = Version.getSubminor())
+ if (Optional<unsigned> Subminor = Version.getSubminor())
Record.push_back(*Subminor + 1);
else
Record.push_back(0);
@@ -3405,6 +3739,8 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
Module *WritingModule) {
using namespace llvm;
+ bool isModule = WritingModule != 0;
+
// Make sure that the AST reader knows to finalize itself.
if (Chain)
Chain->finalizeForWriting();
@@ -3447,11 +3783,19 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
// If there are any out-of-date identifiers, bring them up to date.
if (ExternalPreprocessorSource *ExtSource = PP.getExternalSource()) {
+ // Find out-of-date identifiers.
+ SmallVector<IdentifierInfo *, 4> OutOfDate;
for (IdentifierTable::iterator ID = PP.getIdentifierTable().begin(),
IDEnd = PP.getIdentifierTable().end();
- ID != IDEnd; ++ID)
+ ID != IDEnd; ++ID) {
if (ID->second->isOutOfDate())
- ExtSource->updateOutOfDateIdentifier(*ID->second);
+ OutOfDate.push_back(ID->second);
+ }
+
+ // Update the out-of-date identifiers.
+ for (unsigned I = 0, N = OutOfDate.size(); I != N; ++I) {
+ ExtSource->updateOutOfDateIdentifier(*OutOfDate[I]);
+ }
}
// Build a record containing all of the tentative definitions in this file, in
@@ -3462,13 +3806,15 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
// Build a record containing all of the file scoped decls in this file.
RecordData UnusedFileScopedDecls;
- AddLazyVectorDecls(*this, SemaRef.UnusedFileScopedDecls,
- UnusedFileScopedDecls);
+ if (!isModule)
+ AddLazyVectorDecls(*this, SemaRef.UnusedFileScopedDecls,
+ UnusedFileScopedDecls);
// Build a record containing all of the delegating constructors we still need
// to resolve.
RecordData DelegatingCtorDecls;
- AddLazyVectorDecls(*this, SemaRef.DelegatingCtorDecls, DelegatingCtorDecls);
+ if (!isModule)
+ AddLazyVectorDecls(*this, SemaRef.DelegatingCtorDecls, DelegatingCtorDecls);
// Write the set of weak, undeclared identifiers. We always write the
// entire table, since later PCH files in a PCH chain are only interested in
@@ -3485,18 +3831,18 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
}
}
- // Build a record containing all of the locally-scoped external
+ // Build a record containing all of the locally-scoped extern "C"
// declarations in this header file. Generally, this record will be
// empty.
- RecordData LocallyScopedExternalDecls;
+ RecordData LocallyScopedExternCDecls;
// FIXME: This is filling in the AST file in densemap order which is
// nondeterminstic!
for (llvm::DenseMap<DeclarationName, NamedDecl *>::iterator
- TD = SemaRef.LocallyScopedExternalDecls.begin(),
- TDEnd = SemaRef.LocallyScopedExternalDecls.end();
+ TD = SemaRef.LocallyScopedExternCDecls.begin(),
+ TDEnd = SemaRef.LocallyScopedExternCDecls.end();
TD != TDEnd; ++TD) {
if (!TD->second->isFromASTFile())
- AddDeclRef(TD->second, LocallyScopedExternalDecls);
+ AddDeclRef(TD->second, LocallyScopedExternCDecls);
}
// Build a record containing all of the ext_vector declarations.
@@ -3542,7 +3888,7 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
// Build a record containing all of the known namespaces.
RecordData KnownNamespaces;
- for (llvm::DenseMap<NamespaceDecl*, bool>::iterator
+ for (llvm::MapVector<NamespaceDecl*, bool>::iterator
I = SemaRef.KnownNamespaces.begin(),
IEnd = SemaRef.KnownNamespaces.end();
I != IEnd; ++I) {
@@ -3550,6 +3896,17 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
AddDeclRef(I->first, KnownNamespaces);
}
+ // Build a record of all used, undefined objects that require definitions.
+ RecordData UndefinedButUsed;
+
+ SmallVector<std::pair<NamedDecl *, SourceLocation>, 16> Undefined;
+ SemaRef.getUndefinedButUsed(Undefined);
+ for (SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> >::iterator
+ I = Undefined.begin(), E = Undefined.end(); I != E; ++I) {
+ AddDeclRef(I->first, UndefinedButUsed);
+ AddSourceLocation(I->second, UndefinedButUsed);
+ }
+
// Write the control block
WriteControlBlock(PP, Context, isysroot, OutputFile);
@@ -3557,6 +3914,12 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
RecordData Record;
Stream.EnterSubblock(AST_BLOCK_ID, 5);
+ // This is so that older clang versions, before the introduction
+ // of the control block, can read and reject the newer PCH format.
+ Record.clear();
+ Record.push_back(VERSION_MAJOR);
+ Stream.EmitRecord(METADATA_OLD_FORMAT, Record);
+
// Create a lexical update block containing all of the declarations in the
// translation unit that do not come from other AST files.
const TranslationUnitDecl *TU = Context.getTranslationUnitDecl();
@@ -3686,16 +4049,16 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
Stream.EmitRecordWithBlob(ModuleOffsetMapAbbrev, Record,
Buffer.data(), Buffer.size());
}
- WritePreprocessor(PP, WritingModule != 0);
+ WritePreprocessor(PP, isModule);
WriteHeaderSearch(PP.getHeaderSearchInfo(), isysroot);
WriteSelectors(SemaRef);
WriteReferencedSelectorsPool(SemaRef);
- WriteIdentifierTable(PP, SemaRef.IdResolver, WritingModule != 0);
+ WriteIdentifierTable(PP, SemaRef.IdResolver, isModule);
WriteFPPragmaOptions(SemaRef.getFPOptions());
WriteOpenCLExtensions(SemaRef);
WriteTypeDeclOffsets();
- WritePragmaDiagnosticMappings(Context.getDiagnostics());
+ WritePragmaDiagnosticMappings(Context.getDiagnostics(), isModule);
WriteCXXBaseSpecifiersOffsets();
@@ -3722,10 +4085,10 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
Stream.EmitRecord(WEAK_UNDECLARED_IDENTIFIERS,
WeakUndeclaredIdentifiers);
- // Write the record containing locally-scoped external definitions.
- if (!LocallyScopedExternalDecls.empty())
- Stream.EmitRecord(LOCALLY_SCOPED_EXTERNAL_DECLS,
- LocallyScopedExternalDecls);
+ // Write the record containing locally-scoped extern "C" definitions.
+ if (!LocallyScopedExternCDecls.empty())
+ Stream.EmitRecord(LOCALLY_SCOPED_EXTERN_C_DECLS,
+ LocallyScopedExternCDecls);
// Write the record containing ext_vector type names.
if (!ExtVectorDecls.empty())
@@ -3758,6 +4121,10 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
// Write the known namespaces.
if (!KnownNamespaces.empty())
Stream.EmitRecord(KNOWN_NAMESPACES, KnownNamespaces);
+
+ // Write the undefined internal functions and variables, and inline functions.
+ if (!UndefinedButUsed.empty())
+ Stream.EmitRecord(UNDEFINED_BUT_USED, UndefinedButUsed);
// Write the visible updates to DeclContexts.
for (llvm::SmallPtrSet<const DeclContext *, 16>::iterator
@@ -3788,11 +4155,10 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
}
}
- WriteMacroUpdates();
WriteDeclUpdatesBlocks();
WriteDeclReplacementsBlock();
- WriteMergedDecls();
WriteRedeclarations();
+ WriteMergedDecls();
WriteObjCCategories();
// Some simple statistics
@@ -3805,21 +4171,6 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
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() {
@@ -3915,10 +4266,6 @@ 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;
@@ -3929,7 +4276,7 @@ IdentID ASTWriter::getIdentifierRef(const IdentifierInfo *II) {
return ID;
}
-MacroID ASTWriter::getMacroRef(MacroInfo *MI) {
+MacroID ASTWriter::getMacroRef(MacroInfo *MI, const IdentifierInfo *Name) {
// 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).
@@ -3937,11 +4284,27 @@ MacroID ASTWriter::getMacroRef(MacroInfo *MI) {
return 0;
MacroID &ID = MacroIDs[MI];
- if (ID == 0)
+ if (ID == 0) {
ID = NextMacroID++;
+ MacroInfoToEmitData Info = { Name, MI, ID };
+ MacroInfosToEmit.push_back(Info);
+ }
return ID;
}
+MacroID ASTWriter::getMacroID(MacroInfo *MI) {
+ if (MI == 0 || MI->isBuiltinMacro())
+ return 0;
+
+ assert(MacroIDs.find(MI) != MacroIDs.end() && "Macro not emitted!");
+ return MacroIDs[MI];
+}
+
+uint64_t ASTWriter::getMacroDirectivesOffset(const IdentifierInfo *Name) {
+ assert(IdentMacroDirectivesOffsetMap[Name] && "not set!");
+ return IdentMacroDirectivesOffsetMap[Name];
+}
+
void ASTWriter::AddSelectorRef(const Selector SelRef, RecordDataImpl &Record) {
Record.push_back(getSelectorRef(SelRef));
}
@@ -3951,14 +4314,16 @@ SelectorID ASTWriter::getSelectorRef(Selector Sel) {
return 0;
}
- SelectorID &SID = SelectorIDs[Sel];
+ SelectorID SID = SelectorIDs[Sel];
if (SID == 0 && Chain) {
// This might trigger a ReadSelector callback, which will set the ID for
// this selector.
Chain->LoadSelector(Sel);
+ SID = SelectorIDs[Sel];
}
if (SID == 0) {
SID = NextSelectorID++;
+ SelectorIDs[Sel] = SID;
}
return SID;
}
@@ -4431,7 +4796,7 @@ void ASTWriter::AddTemplateArgument(const TemplateArgument &Arg,
break;
case TemplateArgument::TemplateExpansion:
AddTemplateName(Arg.getAsTemplateOrTemplatePattern(), Record);
- if (llvm::Optional<unsigned> NumExpansions = Arg.getNumTemplateExpansions())
+ if (Optional<unsigned> NumExpansions = Arg.getNumTemplateExpansions())
Record.push_back(*NumExpansions + 1);
else
Record.push_back(0);
@@ -4474,9 +4839,9 @@ ASTWriter::AddTemplateArgumentList(const TemplateArgumentList *TemplateArgs,
void
-ASTWriter::AddUnresolvedSet(const UnresolvedSetImpl &Set, RecordDataImpl &Record) {
+ASTWriter::AddUnresolvedSet(const ASTUnresolvedSet &Set, RecordDataImpl &Record) {
Record.push_back(Set.size());
- for (UnresolvedSetImpl::const_iterator
+ for (ASTUnresolvedSet::const_iterator
I = Set.begin(), E = Set.end(); I != E; ++I) {
AddDeclRef(I.getDecl(), Record);
Record.push_back(I.getAccess());
@@ -4568,11 +4933,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
struct CXXRecordDecl::DefinitionData &Data = *D->DefinitionData;
Record.push_back(Data.IsLambda);
Record.push_back(Data.UserDeclaredConstructor);
- Record.push_back(Data.UserDeclaredCopyConstructor);
- Record.push_back(Data.UserDeclaredMoveConstructor);
- Record.push_back(Data.UserDeclaredCopyAssignment);
- Record.push_back(Data.UserDeclaredMoveAssignment);
- Record.push_back(Data.UserDeclaredDestructor);
+ Record.push_back(Data.UserDeclaredSpecialMembers);
Record.push_back(Data.Aggregate);
Record.push_back(Data.PlainOldData);
Record.push_back(Data.Empty);
@@ -4586,25 +4947,26 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
Record.push_back(Data.HasMutableFields);
Record.push_back(Data.HasOnlyCMembers);
Record.push_back(Data.HasInClassInitializer);
- Record.push_back(Data.HasTrivialDefaultConstructor);
+ Record.push_back(Data.HasUninitializedReferenceMember);
+ Record.push_back(Data.NeedOverloadResolutionForMoveConstructor);
+ Record.push_back(Data.NeedOverloadResolutionForMoveAssignment);
+ Record.push_back(Data.NeedOverloadResolutionForDestructor);
+ Record.push_back(Data.DefaultedMoveConstructorIsDeleted);
+ Record.push_back(Data.DefaultedMoveAssignmentIsDeleted);
+ Record.push_back(Data.DefaultedDestructorIsDeleted);
+ Record.push_back(Data.HasTrivialSpecialMembers);
+ Record.push_back(Data.HasIrrelevantDestructor);
Record.push_back(Data.HasConstexprNonCopyMoveConstructor);
Record.push_back(Data.DefaultedDefaultConstructorIsConstexpr);
Record.push_back(Data.HasConstexprDefaultConstructor);
- Record.push_back(Data.HasTrivialCopyConstructor);
- Record.push_back(Data.HasTrivialMoveConstructor);
- Record.push_back(Data.HasTrivialCopyAssignment);
- Record.push_back(Data.HasTrivialMoveAssignment);
- Record.push_back(Data.HasTrivialDestructor);
- Record.push_back(Data.HasIrrelevantDestructor);
Record.push_back(Data.HasNonLiteralTypeFieldsOrBases);
Record.push_back(Data.ComputedVisibleConversions);
Record.push_back(Data.UserProvidedDefaultConstructor);
- Record.push_back(Data.DeclaredDefaultConstructor);
- Record.push_back(Data.DeclaredCopyConstructor);
- Record.push_back(Data.DeclaredMoveConstructor);
- Record.push_back(Data.DeclaredCopyAssignment);
- Record.push_back(Data.DeclaredMoveAssignment);
- Record.push_back(Data.DeclaredDestructor);
+ Record.push_back(Data.DeclaredSpecialMembers);
+ Record.push_back(Data.ImplicitCopyConstructorHasConstParam);
+ Record.push_back(Data.ImplicitCopyAssignmentHasConstParam);
+ Record.push_back(Data.HasDeclaredCopyConstructorWithConstParam);
+ Record.push_back(Data.HasDeclaredCopyAssignmentWithConstParam);
Record.push_back(Data.FailedImplicitMoveConstructor);
Record.push_back(Data.FailedImplicitMoveAssignment);
// IsLambda bit is already saved.
@@ -4676,11 +5038,17 @@ void ASTWriter::ReaderInitialized(ASTReader *Reader) {
}
void ASTWriter::IdentifierRead(IdentID ID, IdentifierInfo *II) {
- IdentifierIDs[II] = ID;
+ // Always keep the highest ID. See \p TypeRead() for more information.
+ IdentID &StoredID = IdentifierIDs[II];
+ if (ID > StoredID)
+ StoredID = ID;
}
void ASTWriter::MacroRead(serialization::MacroID ID, MacroInfo *MI) {
- MacroIDs[MI] = ID;
+ // Always keep the highest ID. See \p TypeRead() for more information.
+ MacroID &StoredID = MacroIDs[MI];
+ if (ID > StoredID)
+ StoredID = ID;
}
void ASTWriter::TypeRead(TypeIdx Idx, QualType T) {
@@ -4695,7 +5063,10 @@ void ASTWriter::TypeRead(TypeIdx Idx, QualType T) {
}
void ASTWriter::SelectorRead(SelectorID ID, Selector S) {
- SelectorIDs[S] = ID;
+ // Always keep the highest ID. See \p TypeRead() for more information.
+ SelectorID &StoredID = SelectorIDs[S];
+ if (ID > StoredID)
+ StoredID = ID;
}
void ASTWriter::MacroDefinitionRead(serialization::PreprocessedEntityID ID,
@@ -4709,10 +5080,6 @@ void ASTWriter::ModuleRead(serialization::SubmoduleID ID, Module *Mod) {
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!");
@@ -4737,6 +5104,7 @@ void ASTWriter::AddedVisibleDecl(const DeclContext *DC, const Decl *D) {
if (!(!D->isFromASTFile() && cast<Decl>(DC)->isFromASTFile()))
return; // Not a source decl added to a DeclContext from PCH.
+ assert(!getDefinitiveDeclContext(DC) && "DeclContext not definitive!");
AddUpdatedDeclContext(DC);
UpdatingVisibleDecls.push_back(D);
}
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 7486565..023599d 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -12,14 +12,14 @@
//===----------------------------------------------------------------------===//
#include "clang/Serialization/ASTWriter.h"
-#include "clang/Serialization/ASTReader.h"
#include "ASTCommon.h"
-#include "clang/AST/DeclVisitor.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclContextInternals.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/DeclVisitor.h"
#include "clang/AST/Expr.h"
-#include "clang/AST/DeclContextInternals.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Serialization/ASTReader.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Bitcode/BitstreamWriter.h"
#include "llvm/Support/ErrorHandling.h"
@@ -102,6 +102,7 @@ namespace clang {
void VisitFriendTemplateDecl(FriendTemplateDecl *D);
void VisitStaticAssertDecl(StaticAssertDecl *D);
void VisitBlockDecl(BlockDecl *D);
+ void VisitEmptyDecl(EmptyDecl *D);
void VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset,
uint64_t VisibleOffset);
@@ -122,6 +123,7 @@ namespace clang {
void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D);
void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
+ void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
};
}
@@ -252,6 +254,7 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
!D->isModulePrivate() &&
!CXXRecordDecl::classofKind(D->getKind()) &&
!D->getIntegerTypeSourceInfo() &&
+ !D->getMemberSpecializationInfo() &&
D->getDeclName().getNameKind() == DeclarationName::Identifier)
AbbrevToUse = Writer.getDeclEnumAbbrev();
@@ -263,6 +266,7 @@ void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) {
Record.push_back(D->hasFlexibleArrayMember());
Record.push_back(D->isAnonymousStructOrUnion());
Record.push_back(D->hasObjectMember());
+ Record.push_back(D->hasVolatileMember());
if (!D->hasAttrs() &&
!D->isImplicit() &&
@@ -315,7 +319,6 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
// after everything else is written.
Record.push_back(D->getStorageClass()); // FIXME: stable encoding
- Record.push_back(D->getStorageClassAsWritten());
Record.push_back(D->IsInline);
Record.push_back(D->isInlineSpecified());
Record.push_back(D->isVirtualAsWritten());
@@ -328,6 +331,8 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
Record.push_back(D->isExplicitlyDefaulted());
Record.push_back(D->hasImplicitReturnZero());
Record.push_back(D->isConstexpr());
+ Record.push_back(D->HasSkippedBody);
+ Record.push_back(D->getLinkage());
Writer.AddSourceLocation(D->getLocEnd(), Record);
Record.push_back(D->getTemplatedKind());
@@ -419,6 +424,7 @@ void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
Record.push_back(D->isPropertyAccessor());
Record.push_back(D->isDefined());
Record.push_back(D->IsOverriding);
+ Record.push_back(D->HasSkippedBody);
Record.push_back(D->IsRedeclaration);
Record.push_back(D->HasRedeclaration);
@@ -489,13 +495,14 @@ void ASTDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
PEnd = Data.AllReferencedProtocols.end();
P != PEnd; ++P)
Writer.AddDeclRef(*P, Record);
+
- if (ObjCCategoryDecl *Cat = D->getCategoryList()) {
+ if (ObjCCategoryDecl *Cat = D->getCategoryListRaw()) {
// Ensure that we write out the set of categories for this class.
Writer.ObjCClassesWithCategories.insert(D);
// Make sure that the categories get serialized.
- for (; Cat; Cat = Cat->getNextClassCategory())
+ for (; Cat; Cat = Cat->getNextClassCategoryRaw())
(void)Writer.GetDeclRef(Cat);
}
}
@@ -669,8 +676,7 @@ void ASTDeclWriter::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
VisitRedeclarable(D);
VisitDeclaratorDecl(D);
- Record.push_back(D->getStorageClass()); // FIXME: stable encoding
- Record.push_back(D->getStorageClassAsWritten());
+ Record.push_back(D->getStorageClass());
Record.push_back(D->isThreadSpecified());
Record.push_back(D->getInitStyle());
Record.push_back(D->isExceptionVariable());
@@ -678,6 +684,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
Record.push_back(D->isCXXForRangeDecl());
Record.push_back(D->isARCPseudoStrong());
Record.push_back(D->isConstexpr());
+ Record.push_back(D->getLinkage());
if (D->getInit()) {
Record.push_back(!D->isInitKnownICE() ? 1 : (D->isInitICE() ? 3 : 2));
@@ -774,6 +781,11 @@ void ASTDeclWriter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
Code = serialization::DECL_FILE_SCOPE_ASM;
}
+void ASTDeclWriter::VisitEmptyDecl(EmptyDecl *D) {
+ VisitDecl(D);
+ Code = serialization::DECL_EMPTY;
+}
+
void ASTDeclWriter::VisitBlockDecl(BlockDecl *D) {
VisitDecl(D);
Writer.AddStmt(D->getBody());
@@ -839,11 +851,10 @@ void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) {
if (StoredDeclsMap *Map = NS->buildLookup()) {
for (StoredDeclsMap::iterator D = Map->begin(), DEnd = Map->end();
D != DEnd; ++D) {
- DeclContext::lookup_result Result = D->second.getLookupResult();
- while (Result.first != Result.second) {
- Writer.GetDeclRef(*Result.first);
- ++Result.first;
- }
+ DeclContext::lookup_result R = D->second.getLookupResult();
+ for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E;
+ ++I)
+ Writer.GetDeclRef(*I);
}
}
}
@@ -940,10 +951,10 @@ void ASTDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) {
Record.push_back(CXXRecNotTemplate);
}
- // Store the key function to avoid deserializing every method so we can
- // compute it.
+ // Store (what we currently believe to be) the key function to avoid
+ // deserializing every method so we can compute it.
if (D->IsCompleteDefinition)
- Writer.AddDeclRef(Context.getKeyFunction(D), Record);
+ Writer.AddDeclRef(Context.getCurrentKeyFunction(D), Record);
Code = serialization::DECL_CXX_RECORD;
}
@@ -1014,12 +1025,19 @@ void ASTDeclWriter::VisitAccessSpecDecl(AccessSpecDecl *D) {
}
void ASTDeclWriter::VisitFriendDecl(FriendDecl *D) {
+ // Record the number of friend type template parameter lists here
+ // so as to simplify memory allocation during deserialization.
+ Record.push_back(D->NumTPLists);
VisitDecl(D);
- Record.push_back(D->Friend.is<TypeSourceInfo*>());
- if (D->Friend.is<TypeSourceInfo*>())
- Writer.AddTypeSourceInfo(D->Friend.get<TypeSourceInfo*>(), Record);
+ bool hasFriendDecl = D->Friend.is<NamedDecl*>();
+ Record.push_back(hasFriendDecl);
+ if (hasFriendDecl)
+ Writer.AddDeclRef(D->getFriendDecl(), Record);
else
- Writer.AddDeclRef(D->Friend.get<NamedDecl*>(), Record);
+ Writer.AddTypeSourceInfo(D->getFriendType(), Record);
+ for (unsigned i = 0; i < D->NumTPLists; ++i)
+ Writer.AddTemplateParameterList(D->getFriendTypeTemplateParameterList(i),
+ Record);
Writer.AddDeclRef(D->getNextFriend(), Record);
Record.push_back(D->UnsupportedFriend);
Writer.AddSourceLocation(D->FriendLoc, Record);
@@ -1275,7 +1293,10 @@ template <typename T>
void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) {
T *First = D->getFirstDeclaration();
if (First->getMostRecentDecl() != First) {
- // There is more than one declaration of this entity, so we will need to
+ assert(isRedeclarableDeclKind(static_cast<T *>(D)->getKind()) &&
+ "Not considered redeclarable?");
+
+ // There is more than one declaration of this entity, so we will need to
// write a redeclaration chain.
Writer.AddDeclRef(First, Record);
Writer.Redeclarations.insert(First);
@@ -1292,6 +1313,16 @@ void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) {
}
+void ASTDeclWriter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
+ Record.push_back(D->varlist_size());
+ VisitDecl(D);
+ for (OMPThreadPrivateDecl::varlist_iterator I = D->varlist_begin(),
+ E = D->varlist_end();
+ I != E; ++I)
+ Writer.AddStmt(*I);
+ Code = serialization::DECL_OMP_THREADPRIVATE;
+}
+
//===----------------------------------------------------------------------===//
// ASTWriter Implementation
//===----------------------------------------------------------------------===//
@@ -1451,6 +1482,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // FlexibleArrayMember
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // AnonymousStructUnion
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // hasObjectMember
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // hasVolatileMember
// DC
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalOffset
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // VisibleOffset
@@ -1483,7 +1515,6 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
// VarDecl
Abv->Add(BitCodeAbbrevOp(0)); // StorageClass
- Abv->Add(BitCodeAbbrevOp(0)); // StorageClassAsWritten
Abv->Add(BitCodeAbbrevOp(0)); // isThreadSpecified
Abv->Add(BitCodeAbbrevOp(0)); // hasCXXDirectInitializer
Abv->Add(BitCodeAbbrevOp(0)); // isExceptionVariable
@@ -1491,6 +1522,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // isCXXForRangeDecl
Abv->Add(BitCodeAbbrevOp(0)); // isARCPseudoStrong
Abv->Add(BitCodeAbbrevOp(0)); // isConstexpr
+ Abv->Add(BitCodeAbbrevOp(0)); // Linkage
Abv->Add(BitCodeAbbrevOp(0)); // HasInit
Abv->Add(BitCodeAbbrevOp(0)); // HasMemberSpecializationInfo
// ParmVarDecl
@@ -1562,7 +1594,6 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
// VarDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // StorageClass
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // StorageClassAsWritten
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isThreadSpecified
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // CXXDirectInitializer
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isExceptionVariable
@@ -1570,6 +1601,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isCXXForRangeDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isARCPseudoStrong
Abv->Add(BitCodeAbbrevOp(0)); // isConstexpr
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Linkage
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasInit
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasMemberSpecInfo
// Type Source Info
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index 7e8ce42..b6f1d54 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -78,6 +78,8 @@ void ASTStmtWriter::VisitCompoundStmt(CompoundStmt *S) {
void ASTStmtWriter::VisitSwitchCase(SwitchCase *S) {
VisitStmt(S);
Record.push_back(Writer.getSwitchCaseID(S));
+ Writer.AddSourceLocation(S->getKeywordLoc(), Record);
+ Writer.AddSourceLocation(S->getColonLoc(), Record);
}
void ASTStmtWriter::VisitCaseStmt(CaseStmt *S) {
@@ -85,17 +87,13 @@ void ASTStmtWriter::VisitCaseStmt(CaseStmt *S) {
Writer.AddStmt(S->getLHS());
Writer.AddStmt(S->getRHS());
Writer.AddStmt(S->getSubStmt());
- Writer.AddSourceLocation(S->getCaseLoc(), Record);
Writer.AddSourceLocation(S->getEllipsisLoc(), Record);
- Writer.AddSourceLocation(S->getColonLoc(), Record);
Code = serialization::STMT_CASE;
}
void ASTStmtWriter::VisitDefaultStmt(DefaultStmt *S) {
VisitSwitchCase(S);
Writer.AddStmt(S->getSubStmt());
- Writer.AddSourceLocation(S->getDefaultLoc(), Record);
- Writer.AddSourceLocation(S->getColonLoc(), Record);
Code = serialization::STMT_DEFAULT;
}
@@ -326,8 +324,9 @@ void ASTStmtWriter::VisitIntegerLiteral(IntegerLiteral *E) {
void ASTStmtWriter::VisitFloatingLiteral(FloatingLiteral *E) {
VisitExpr(E);
- Writer.AddAPFloat(E->getValue(), Record);
+ Record.push_back(E->getRawSemantics());
Record.push_back(E->isExact());
+ Writer.AddAPFloat(E->getValue(), Record);
Writer.AddSourceLocation(E->getLocation(), Record);
Code = serialization::EXPR_FLOATING_LITERAL;
}
@@ -499,6 +498,7 @@ void ASTStmtWriter::VisitObjCIsaExpr(ObjCIsaExpr *E) {
VisitExpr(E);
Writer.AddStmt(E->getBase());
Writer.AddSourceLocation(E->getIsaMemberLoc(), Record);
+ Writer.AddSourceLocation(E->getOpLoc(), Record);
Record.push_back(E->isArrow());
Code = serialization::EXPR_OBJC_ISA;
}
@@ -857,6 +857,7 @@ void ASTStmtWriter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
VisitExpr(E);
Writer.AddDeclRef(E->getDecl(), Record);
Writer.AddSourceLocation(E->getLocation(), Record);
+ Writer.AddSourceLocation(E->getOpLoc(), Record);
Writer.AddStmt(E->getBase());
Record.push_back(E->isArrow());
Record.push_back(E->isFreeIvar());
@@ -1076,6 +1077,7 @@ void ASTStmtWriter::VisitCXXConstructExpr(CXXConstructExpr *E) {
Writer.AddSourceLocation(E->getLocation(), Record);
Record.push_back(E->isElidable());
Record.push_back(E->hadMultipleCandidates());
+ Record.push_back(E->isListInitialization());
Record.push_back(E->requiresZeroInitialization());
Record.push_back(E->getConstructionKind()); // FIXME: stable encoding
Writer.AddSourceRange(E->getParenRange(), Record);
@@ -1124,6 +1126,7 @@ void ASTStmtWriter::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) {
VisitExplicitCastExpr(E);
Writer.AddSourceRange(SourceRange(E->getOperatorLoc(), E->getRParenLoc()),
Record);
+ Writer.AddSourceRange(E->getAngleBrackets(), Record);
}
void ASTStmtWriter::VisitCXXStaticCastExpr(CXXStaticCastExpr *E) {
diff --git a/lib/Serialization/CMakeLists.txt b/lib/Serialization/CMakeLists.txt
index 20999e1..3c68b64 100644
--- a/lib/Serialization/CMakeLists.txt
+++ b/lib/Serialization/CMakeLists.txt
@@ -1,3 +1,5 @@
+set(LLVM_LINK_COMPONENTS bitreader)
+
add_clang_library(clangSerialization
ASTCommon.h
ASTReaderInternals.h
@@ -9,6 +11,7 @@ add_clang_library(clangSerialization
ASTWriterDecl.cpp
ASTWriterStmt.cpp
GeneratePCH.cpp
+ GlobalModuleIndex.cpp
Module.cpp
ModuleManager.cpp
)
diff --git a/lib/Serialization/GeneratePCH.cpp b/lib/Serialization/GeneratePCH.cpp
index 870d654..32c2df3 100644
--- a/lib/Serialization/GeneratePCH.cpp
+++ b/lib/Serialization/GeneratePCH.cpp
@@ -13,11 +13,11 @@
//===----------------------------------------------------------------------===//
#include "clang/Serialization/ASTWriter.h"
-#include "clang/Sema/SemaConsumer.h"
-#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTConsumer.h"
-#include "clang/Lex/Preprocessor.h"
+#include "clang/AST/ASTContext.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/SemaConsumer.h"
#include "llvm/Bitcode/BitstreamWriter.h"
#include "llvm/Support/raw_ostream.h"
#include <string>
@@ -55,10 +55,6 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
Buffer.clear();
}
-PPMutationListener *PCHGenerator::GetPPMutationListener() {
- return &Writer;
-}
-
ASTMutationListener *PCHGenerator::GetASTMutationListener() {
return &Writer;
}
diff --git a/lib/Serialization/GlobalModuleIndex.cpp b/lib/Serialization/GlobalModuleIndex.cpp
new file mode 100644
index 0000000..f9acb84
--- /dev/null
+++ b/lib/Serialization/GlobalModuleIndex.cpp
@@ -0,0 +1,820 @@
+//===--- GlobalModuleIndex.cpp - Global Module Index ------------*- 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 GlobalModuleIndex class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ASTReaderInternals.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/OnDiskHashTable.h"
+#include "clang/Serialization/ASTBitCodes.h"
+#include "clang/Serialization/GlobalModuleIndex.h"
+#include "clang/Serialization/Module.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Bitcode/BitstreamReader.h"
+#include "llvm/Bitcode/BitstreamWriter.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/LockFileManager.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/PathV2.h"
+#include <cstdio>
+using namespace clang;
+using namespace serialization;
+
+//----------------------------------------------------------------------------//
+// Shared constants
+//----------------------------------------------------------------------------//
+namespace {
+ enum {
+ /// \brief The block containing the index.
+ GLOBAL_INDEX_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID
+ };
+
+ /// \brief Describes the record types in the index.
+ enum IndexRecordTypes {
+ /// \brief Contains version information and potentially other metadata,
+ /// used to determine if we can read this global index file.
+ INDEX_METADATA,
+ /// \brief Describes a module, including its file name and dependencies.
+ MODULE,
+ /// \brief The index for identifiers.
+ IDENTIFIER_INDEX
+ };
+}
+
+/// \brief The name of the global index file.
+static const char * const IndexFileName = "modules.idx";
+
+/// \brief The global index file version.
+static const unsigned CurrentVersion = 1;
+
+//----------------------------------------------------------------------------//
+// Global module index reader.
+//----------------------------------------------------------------------------//
+
+namespace {
+
+/// \brief Trait used to read the identifier index from the on-disk hash
+/// table.
+class IdentifierIndexReaderTrait {
+public:
+ typedef StringRef external_key_type;
+ typedef StringRef internal_key_type;
+ typedef SmallVector<unsigned, 2> data_type;
+
+ static bool EqualKey(const internal_key_type& a, const internal_key_type& b) {
+ return a == b;
+ }
+
+ static unsigned ComputeHash(const internal_key_type& a) {
+ return llvm::HashString(a);
+ }
+
+ static std::pair<unsigned, unsigned>
+ ReadKeyDataLength(const unsigned char*& d) {
+ using namespace clang::io;
+ unsigned KeyLen = ReadUnalignedLE16(d);
+ unsigned DataLen = ReadUnalignedLE16(d);
+ return std::make_pair(KeyLen, DataLen);
+ }
+
+ static const internal_key_type&
+ GetInternalKey(const external_key_type& x) { return x; }
+
+ static const external_key_type&
+ GetExternalKey(const internal_key_type& x) { return x; }
+
+ static internal_key_type ReadKey(const unsigned char* d, unsigned n) {
+ return StringRef((const char *)d, n);
+ }
+
+ static data_type ReadData(const internal_key_type& k,
+ const unsigned char* d,
+ unsigned DataLen) {
+ using namespace clang::io;
+
+ data_type Result;
+ while (DataLen > 0) {
+ unsigned ID = ReadUnalignedLE32(d);
+ Result.push_back(ID);
+ DataLen -= 4;
+ }
+
+ return Result;
+ }
+};
+
+typedef OnDiskChainedHashTable<IdentifierIndexReaderTrait> IdentifierIndexTable;
+
+}
+
+GlobalModuleIndex::GlobalModuleIndex(llvm::MemoryBuffer *Buffer,
+ llvm::BitstreamCursor Cursor)
+ : Buffer(Buffer), IdentifierIndex(),
+ NumIdentifierLookups(), NumIdentifierLookupHits()
+{
+ // Read the global index.
+ bool InGlobalIndexBlock = false;
+ bool Done = false;
+ while (!Done) {
+ llvm::BitstreamEntry Entry = Cursor.advance();
+
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::Error:
+ return;
+
+ case llvm::BitstreamEntry::EndBlock:
+ if (InGlobalIndexBlock) {
+ InGlobalIndexBlock = false;
+ Done = true;
+ continue;
+ }
+ return;
+
+
+ case llvm::BitstreamEntry::Record:
+ // Entries in the global index block are handled below.
+ if (InGlobalIndexBlock)
+ break;
+
+ return;
+
+ case llvm::BitstreamEntry::SubBlock:
+ if (!InGlobalIndexBlock && Entry.ID == GLOBAL_INDEX_BLOCK_ID) {
+ if (Cursor.EnterSubBlock(GLOBAL_INDEX_BLOCK_ID))
+ return;
+
+ InGlobalIndexBlock = true;
+ } else if (Cursor.SkipBlock()) {
+ return;
+ }
+ continue;
+ }
+
+ SmallVector<uint64_t, 64> Record;
+ StringRef Blob;
+ switch ((IndexRecordTypes)Cursor.readRecord(Entry.ID, Record, &Blob)) {
+ case INDEX_METADATA:
+ // Make sure that the version matches.
+ if (Record.size() < 1 || Record[0] != CurrentVersion)
+ return;
+ break;
+
+ case MODULE: {
+ unsigned Idx = 0;
+ unsigned ID = Record[Idx++];
+
+ // Make room for this module's information.
+ if (ID == Modules.size())
+ Modules.push_back(ModuleInfo());
+ else
+ Modules.resize(ID + 1);
+
+ // Size/modification time for this module file at the time the
+ // global index was built.
+ Modules[ID].Size = Record[Idx++];
+ Modules[ID].ModTime = Record[Idx++];
+
+ // File name.
+ unsigned NameLen = Record[Idx++];
+ Modules[ID].FileName.assign(Record.begin() + Idx,
+ Record.begin() + Idx + NameLen);
+ Idx += NameLen;
+
+ // Dependencies
+ unsigned NumDeps = Record[Idx++];
+ Modules[ID].Dependencies.insert(Modules[ID].Dependencies.end(),
+ Record.begin() + Idx,
+ Record.begin() + Idx + NumDeps);
+ Idx += NumDeps;
+
+ // Make sure we're at the end of the record.
+ assert(Idx == Record.size() && "More module info?");
+
+ // Record this module as an unresolved module.
+ UnresolvedModules[llvm::sys::path::stem(Modules[ID].FileName)] = ID;
+ break;
+ }
+
+ case IDENTIFIER_INDEX:
+ // Wire up the identifier index.
+ if (Record[0]) {
+ IdentifierIndex = IdentifierIndexTable::Create(
+ (const unsigned char *)Blob.data() + Record[0],
+ (const unsigned char *)Blob.data(),
+ IdentifierIndexReaderTrait());
+ }
+ break;
+ }
+ }
+}
+
+GlobalModuleIndex::~GlobalModuleIndex() { }
+
+std::pair<GlobalModuleIndex *, GlobalModuleIndex::ErrorCode>
+GlobalModuleIndex::readIndex(StringRef Path) {
+ // Load the index file, if it's there.
+ llvm::SmallString<128> IndexPath;
+ IndexPath += Path;
+ llvm::sys::path::append(IndexPath, IndexFileName);
+
+ llvm::OwningPtr<llvm::MemoryBuffer> Buffer;
+ if (llvm::MemoryBuffer::getFile(IndexPath, Buffer) != llvm::errc::success)
+ return std::make_pair((GlobalModuleIndex *)0, EC_NotFound);
+
+ /// \brief The bitstream reader from which we'll read the AST file.
+ llvm::BitstreamReader Reader((const unsigned char *)Buffer->getBufferStart(),
+ (const unsigned char *)Buffer->getBufferEnd());
+
+ /// \brief The main bitstream cursor for the main block.
+ llvm::BitstreamCursor Cursor(Reader);
+
+ // Sniff for the signature.
+ if (Cursor.Read(8) != 'B' ||
+ Cursor.Read(8) != 'C' ||
+ Cursor.Read(8) != 'G' ||
+ Cursor.Read(8) != 'I') {
+ return std::make_pair((GlobalModuleIndex *)0, EC_IOError);
+ }
+
+ return std::make_pair(new GlobalModuleIndex(Buffer.take(), Cursor), EC_None);
+}
+
+void
+GlobalModuleIndex::getKnownModules(SmallVectorImpl<ModuleFile *> &ModuleFiles) {
+ ModuleFiles.clear();
+ for (unsigned I = 0, N = Modules.size(); I != N; ++I) {
+ if (ModuleFile *MF = Modules[I].File)
+ ModuleFiles.push_back(MF);
+ }
+}
+
+void GlobalModuleIndex::getModuleDependencies(
+ ModuleFile *File,
+ SmallVectorImpl<ModuleFile *> &Dependencies) {
+ // Look for information about this module file.
+ llvm::DenseMap<ModuleFile *, unsigned>::iterator Known
+ = ModulesByFile.find(File);
+ if (Known == ModulesByFile.end())
+ return;
+
+ // Record dependencies.
+ Dependencies.clear();
+ ArrayRef<unsigned> StoredDependencies = Modules[Known->second].Dependencies;
+ for (unsigned I = 0, N = StoredDependencies.size(); I != N; ++I) {
+ if (ModuleFile *MF = Modules[I].File)
+ Dependencies.push_back(MF);
+ }
+}
+
+bool GlobalModuleIndex::lookupIdentifier(StringRef Name, HitSet &Hits) {
+ Hits.clear();
+
+ // If there's no identifier index, there is nothing we can do.
+ if (!IdentifierIndex)
+ return false;
+
+ // Look into the identifier index.
+ ++NumIdentifierLookups;
+ IdentifierIndexTable &Table
+ = *static_cast<IdentifierIndexTable *>(IdentifierIndex);
+ IdentifierIndexTable::iterator Known = Table.find(Name);
+ if (Known == Table.end()) {
+ return true;
+ }
+
+ SmallVector<unsigned, 2> ModuleIDs = *Known;
+ for (unsigned I = 0, N = ModuleIDs.size(); I != N; ++I) {
+ if (ModuleFile *MF = Modules[ModuleIDs[I]].File)
+ Hits.insert(MF);
+ }
+
+ ++NumIdentifierLookupHits;
+ return true;
+}
+
+bool GlobalModuleIndex::loadedModuleFile(ModuleFile *File) {
+ // Look for the module in the global module index based on the module name.
+ StringRef Name = llvm::sys::path::stem(File->FileName);
+ llvm::StringMap<unsigned>::iterator Known = UnresolvedModules.find(Name);
+ if (Known == UnresolvedModules.end()) {
+ return true;
+ }
+
+ // Rectify this module with the global module index.
+ ModuleInfo &Info = Modules[Known->second];
+
+ // If the size and modification time match what we expected, record this
+ // module file.
+ bool Failed = true;
+ if (File->File->getSize() == Info.Size &&
+ File->File->getModificationTime() == Info.ModTime) {
+ Info.File = File;
+ ModulesByFile[File] = Known->second;
+
+ Failed = false;
+ }
+
+ // One way or another, we have resolved this module file.
+ UnresolvedModules.erase(Known);
+ return Failed;
+}
+
+void GlobalModuleIndex::printStats() {
+ std::fprintf(stderr, "*** Global Module Index Statistics:\n");
+ if (NumIdentifierLookups) {
+ fprintf(stderr, " %u / %u identifier lookups succeeded (%f%%)\n",
+ NumIdentifierLookupHits, NumIdentifierLookups,
+ (double)NumIdentifierLookupHits*100.0/NumIdentifierLookups);
+ }
+ std::fprintf(stderr, "\n");
+}
+
+//----------------------------------------------------------------------------//
+// Global module index writer.
+//----------------------------------------------------------------------------//
+
+namespace {
+ /// \brief Provides information about a specific module file.
+ struct ModuleFileInfo {
+ /// \brief The numberic ID for this module file.
+ unsigned ID;
+
+ /// \brief The set of modules on which this module depends. Each entry is
+ /// a module ID.
+ SmallVector<unsigned, 4> Dependencies;
+ };
+
+ /// \brief Builder that generates the global module index file.
+ class GlobalModuleIndexBuilder {
+ FileManager &FileMgr;
+
+ /// \brief Mapping from files to module file information.
+ typedef llvm::MapVector<const FileEntry *, ModuleFileInfo> ModuleFilesMap;
+
+ /// \brief Information about each of the known module files.
+ ModuleFilesMap ModuleFiles;
+
+ /// \brief Mapping from identifiers to the list of module file IDs that
+ /// consider this identifier to be interesting.
+ typedef llvm::StringMap<SmallVector<unsigned, 2> > InterestingIdentifierMap;
+
+ /// \brief A mapping from all interesting identifiers to the set of module
+ /// files in which those identifiers are considered interesting.
+ InterestingIdentifierMap InterestingIdentifiers;
+
+ /// \brief Write the block-info block for the global module index file.
+ void emitBlockInfoBlock(llvm::BitstreamWriter &Stream);
+
+ /// \brief Retrieve the module file information for the given file.
+ ModuleFileInfo &getModuleFileInfo(const FileEntry *File) {
+ llvm::MapVector<const FileEntry *, ModuleFileInfo>::iterator Known
+ = ModuleFiles.find(File);
+ if (Known != ModuleFiles.end())
+ return Known->second;
+
+ unsigned NewID = ModuleFiles.size();
+ ModuleFileInfo &Info = ModuleFiles[File];
+ Info.ID = NewID;
+ return Info;
+ }
+
+ public:
+ explicit GlobalModuleIndexBuilder(FileManager &FileMgr) : FileMgr(FileMgr){}
+
+ /// \brief Load the contents of the given module file into the builder.
+ ///
+ /// \returns true if an error occurred, false otherwise.
+ bool loadModuleFile(const FileEntry *File);
+
+ /// \brief Write the index to the given bitstream.
+ void writeIndex(llvm::BitstreamWriter &Stream);
+ };
+}
+
+static void emitBlockID(unsigned ID, const char *Name,
+ llvm::BitstreamWriter &Stream,
+ SmallVectorImpl<uint64_t> &Record) {
+ Record.clear();
+ Record.push_back(ID);
+ Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
+
+ // Emit the block name if present.
+ if (Name == 0 || Name[0] == 0) return;
+ Record.clear();
+ while (*Name)
+ Record.push_back(*Name++);
+ Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
+}
+
+static void emitRecordID(unsigned ID, const char *Name,
+ llvm::BitstreamWriter &Stream,
+ SmallVectorImpl<uint64_t> &Record) {
+ Record.clear();
+ Record.push_back(ID);
+ while (*Name)
+ Record.push_back(*Name++);
+ Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
+}
+
+void
+GlobalModuleIndexBuilder::emitBlockInfoBlock(llvm::BitstreamWriter &Stream) {
+ SmallVector<uint64_t, 64> Record;
+ Stream.EnterSubblock(llvm::bitc::BLOCKINFO_BLOCK_ID, 3);
+
+#define BLOCK(X) emitBlockID(X ## _ID, #X, Stream, Record)
+#define RECORD(X) emitRecordID(X, #X, Stream, Record)
+ BLOCK(GLOBAL_INDEX_BLOCK);
+ RECORD(INDEX_METADATA);
+ RECORD(MODULE);
+ RECORD(IDENTIFIER_INDEX);
+#undef RECORD
+#undef BLOCK
+
+ Stream.ExitBlock();
+}
+
+namespace {
+ class InterestingASTIdentifierLookupTrait
+ : public serialization::reader::ASTIdentifierLookupTraitBase {
+
+ public:
+ /// \brief The identifier and whether it is "interesting".
+ typedef std::pair<StringRef, bool> data_type;
+
+ data_type ReadData(const internal_key_type& k,
+ const unsigned char* d,
+ unsigned DataLen) {
+ // The first bit indicates whether this identifier is interesting.
+ // That's all we care about.
+ using namespace clang::io;
+ unsigned RawID = ReadUnalignedLE32(d);
+ bool IsInteresting = RawID & 0x01;
+ return std::make_pair(k, IsInteresting);
+ }
+ };
+}
+
+bool GlobalModuleIndexBuilder::loadModuleFile(const FileEntry *File) {
+ // Open the module file.
+ OwningPtr<llvm::MemoryBuffer> Buffer;
+ std::string ErrorStr;
+ Buffer.reset(FileMgr.getBufferForFile(File, &ErrorStr, /*isVolatile=*/true));
+ if (!Buffer) {
+ return true;
+ }
+
+ // Initialize the input stream
+ llvm::BitstreamReader InStreamFile;
+ llvm::BitstreamCursor InStream;
+ InStreamFile.init((const unsigned char *)Buffer->getBufferStart(),
+ (const unsigned char *)Buffer->getBufferEnd());
+ InStream.init(InStreamFile);
+
+ // Sniff for the signature.
+ if (InStream.Read(8) != 'C' ||
+ InStream.Read(8) != 'P' ||
+ InStream.Read(8) != 'C' ||
+ InStream.Read(8) != 'H') {
+ return true;
+ }
+
+ // Record this module file and assign it a unique ID (if it doesn't have
+ // one already).
+ unsigned ID = getModuleFileInfo(File).ID;
+
+ // Search for the blocks and records we care about.
+ enum { Other, ControlBlock, ASTBlock } State = Other;
+ bool Done = false;
+ while (!Done) {
+ llvm::BitstreamEntry Entry = InStream.advance();
+ switch (Entry.Kind) {
+ case llvm::BitstreamEntry::Error:
+ Done = true;
+ continue;
+
+ case llvm::BitstreamEntry::Record:
+ // In the 'other' state, just skip the record. We don't care.
+ if (State == Other) {
+ InStream.skipRecord(Entry.ID);
+ continue;
+ }
+
+ // Handle potentially-interesting records below.
+ break;
+
+ case llvm::BitstreamEntry::SubBlock:
+ if (Entry.ID == CONTROL_BLOCK_ID) {
+ if (InStream.EnterSubBlock(CONTROL_BLOCK_ID))
+ return true;
+
+ // Found the control block.
+ State = ControlBlock;
+ continue;
+ }
+
+ if (Entry.ID == AST_BLOCK_ID) {
+ if (InStream.EnterSubBlock(AST_BLOCK_ID))
+ return true;
+
+ // Found the AST block.
+ State = ASTBlock;
+ continue;
+ }
+
+ if (InStream.SkipBlock())
+ return true;
+
+ continue;
+
+ case llvm::BitstreamEntry::EndBlock:
+ State = Other;
+ continue;
+ }
+
+ // Read the given record.
+ SmallVector<uint64_t, 64> Record;
+ StringRef Blob;
+ unsigned Code = InStream.readRecord(Entry.ID, Record, &Blob);
+
+ // Handle module dependencies.
+ if (State == ControlBlock && Code == IMPORTS) {
+ // Load each of the imported PCH files.
+ unsigned Idx = 0, N = Record.size();
+ while (Idx < N) {
+ // Read information about the AST file.
+
+ // Skip the imported kind
+ ++Idx;
+
+ // Skip the import location
+ ++Idx;
+
+ // Load stored size/modification time.
+ off_t StoredSize = (off_t)Record[Idx++];
+ time_t StoredModTime = (time_t)Record[Idx++];
+
+ // Retrieve the imported file name.
+ unsigned Length = Record[Idx++];
+ SmallString<128> ImportedFile(Record.begin() + Idx,
+ Record.begin() + Idx + Length);
+ Idx += Length;
+
+ // Find the imported module file.
+ const FileEntry *DependsOnFile
+ = FileMgr.getFile(ImportedFile, /*openFile=*/false,
+ /*cacheFailure=*/false);
+ if (!DependsOnFile ||
+ (StoredSize != DependsOnFile->getSize()) ||
+ (StoredModTime != DependsOnFile->getModificationTime()))
+ return true;
+
+ // Record the dependency.
+ unsigned DependsOnID = getModuleFileInfo(DependsOnFile).ID;
+ getModuleFileInfo(File).Dependencies.push_back(DependsOnID);
+ }
+
+ continue;
+ }
+
+ // Handle the identifier table
+ if (State == ASTBlock && Code == IDENTIFIER_TABLE && Record[0] > 0) {
+ typedef OnDiskChainedHashTable<InterestingASTIdentifierLookupTrait>
+ InterestingIdentifierTable;
+ llvm::OwningPtr<InterestingIdentifierTable>
+ Table(InterestingIdentifierTable::Create(
+ (const unsigned char *)Blob.data() + Record[0],
+ (const unsigned char *)Blob.data()));
+ for (InterestingIdentifierTable::data_iterator D = Table->data_begin(),
+ DEnd = Table->data_end();
+ D != DEnd; ++D) {
+ std::pair<StringRef, bool> Ident = *D;
+ if (Ident.second)
+ InterestingIdentifiers[Ident.first].push_back(ID);
+ else
+ (void)InterestingIdentifiers[Ident.first];
+ }
+ }
+
+ // We don't care about this record.
+ }
+
+ return false;
+}
+
+namespace {
+
+/// \brief Trait used to generate the identifier index as an on-disk hash
+/// table.
+class IdentifierIndexWriterTrait {
+public:
+ typedef StringRef key_type;
+ typedef StringRef key_type_ref;
+ typedef SmallVector<unsigned, 2> data_type;
+ typedef const SmallVector<unsigned, 2> &data_type_ref;
+
+ static unsigned ComputeHash(key_type_ref Key) {
+ return llvm::HashString(Key);
+ }
+
+ std::pair<unsigned,unsigned>
+ EmitKeyDataLength(raw_ostream& Out, key_type_ref Key, data_type_ref Data) {
+ unsigned KeyLen = Key.size();
+ unsigned DataLen = Data.size() * 4;
+ clang::io::Emit16(Out, KeyLen);
+ clang::io::Emit16(Out, DataLen);
+ return std::make_pair(KeyLen, DataLen);
+ }
+
+ void EmitKey(raw_ostream& Out, key_type_ref Key, unsigned KeyLen) {
+ Out.write(Key.data(), KeyLen);
+ }
+
+ void EmitData(raw_ostream& Out, key_type_ref Key, data_type_ref Data,
+ unsigned DataLen) {
+ for (unsigned I = 0, N = Data.size(); I != N; ++I)
+ clang::io::Emit32(Out, Data[I]);
+ }
+};
+
+}
+
+void GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) {
+ using namespace llvm;
+
+ // Emit the file header.
+ Stream.Emit((unsigned)'B', 8);
+ Stream.Emit((unsigned)'C', 8);
+ Stream.Emit((unsigned)'G', 8);
+ Stream.Emit((unsigned)'I', 8);
+
+ // Write the block-info block, which describes the records in this bitcode
+ // file.
+ emitBlockInfoBlock(Stream);
+
+ Stream.EnterSubblock(GLOBAL_INDEX_BLOCK_ID, 3);
+
+ // Write the metadata.
+ SmallVector<uint64_t, 2> Record;
+ Record.push_back(CurrentVersion);
+ Stream.EmitRecord(INDEX_METADATA, Record);
+
+ // Write the set of known module files.
+ for (ModuleFilesMap::iterator M = ModuleFiles.begin(),
+ MEnd = ModuleFiles.end();
+ M != MEnd; ++M) {
+ Record.clear();
+ Record.push_back(M->second.ID);
+ Record.push_back(M->first->getSize());
+ Record.push_back(M->first->getModificationTime());
+
+ // File name
+ StringRef Name(M->first->getName());
+ Record.push_back(Name.size());
+ Record.append(Name.begin(), Name.end());
+
+ // Dependencies
+ Record.push_back(M->second.Dependencies.size());
+ Record.append(M->second.Dependencies.begin(), M->second.Dependencies.end());
+ Stream.EmitRecord(MODULE, Record);
+ }
+
+ // Write the identifier -> module file mapping.
+ {
+ OnDiskChainedHashTableGenerator<IdentifierIndexWriterTrait> Generator;
+ IdentifierIndexWriterTrait Trait;
+
+ // Populate the hash table.
+ for (InterestingIdentifierMap::iterator I = InterestingIdentifiers.begin(),
+ IEnd = InterestingIdentifiers.end();
+ I != IEnd; ++I) {
+ Generator.insert(I->first(), I->second, Trait);
+ }
+
+ // Create the on-disk hash table in a buffer.
+ SmallString<4096> IdentifierTable;
+ uint32_t BucketOffset;
+ {
+ llvm::raw_svector_ostream Out(IdentifierTable);
+ // Make sure that no bucket is at offset 0
+ clang::io::Emit32(Out, 0);
+ BucketOffset = Generator.Emit(Out, Trait);
+ }
+
+ // Create a blob abbreviation
+ BitCodeAbbrev *Abbrev = new BitCodeAbbrev();
+ Abbrev->Add(BitCodeAbbrevOp(IDENTIFIER_INDEX));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32));
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));
+ unsigned IDTableAbbrev = Stream.EmitAbbrev(Abbrev);
+
+ // Write the identifier table
+ Record.clear();
+ Record.push_back(IDENTIFIER_INDEX);
+ Record.push_back(BucketOffset);
+ Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable.str());
+ }
+
+ Stream.ExitBlock();
+}
+
+GlobalModuleIndex::ErrorCode
+GlobalModuleIndex::writeIndex(FileManager &FileMgr, StringRef Path) {
+ llvm::SmallString<128> IndexPath;
+ IndexPath += Path;
+ llvm::sys::path::append(IndexPath, IndexFileName);
+
+ // Coordinate building the global index file with other processes that might
+ // try to do the same.
+ llvm::LockFileManager Locked(IndexPath);
+ switch (Locked) {
+ case llvm::LockFileManager::LFS_Error:
+ return EC_IOError;
+
+ case llvm::LockFileManager::LFS_Owned:
+ // We're responsible for building the index ourselves. Do so below.
+ break;
+
+ case llvm::LockFileManager::LFS_Shared:
+ // Someone else is responsible for building the index. We don't care
+ // when they finish, so we're done.
+ return EC_Building;
+ }
+
+ // The module index builder.
+ GlobalModuleIndexBuilder Builder(FileMgr);
+
+ // Load each of the module files.
+ llvm::error_code EC;
+ for (llvm::sys::fs::directory_iterator D(Path, EC), DEnd;
+ D != DEnd && !EC;
+ D.increment(EC)) {
+ // If this isn't a module file, we don't care.
+ if (llvm::sys::path::extension(D->path()) != ".pcm") {
+ // ... unless it's a .pcm.lock file, which indicates that someone is
+ // in the process of rebuilding a module. They'll rebuild the index
+ // at the end of that translation unit, so we don't have to.
+ if (llvm::sys::path::extension(D->path()) == ".pcm.lock")
+ return EC_Building;
+
+ continue;
+ }
+
+ // If we can't find the module file, skip it.
+ const FileEntry *ModuleFile = FileMgr.getFile(D->path());
+ if (!ModuleFile)
+ continue;
+
+ // Load this module file.
+ if (Builder.loadModuleFile(ModuleFile))
+ return EC_IOError;
+ }
+
+ // The output buffer, into which the global index will be written.
+ SmallVector<char, 16> OutputBuffer;
+ {
+ llvm::BitstreamWriter OutputStream(OutputBuffer);
+ Builder.writeIndex(OutputStream);
+ }
+
+ // Write the global index file to a temporary file.
+ llvm::SmallString<128> IndexTmpPath;
+ int TmpFD;
+ if (llvm::sys::fs::unique_file(IndexPath + "-%%%%%%%%", TmpFD, IndexTmpPath))
+ return EC_IOError;
+
+ // Open the temporary global index file for output.
+ llvm::raw_fd_ostream Out(TmpFD, true);
+ if (Out.has_error())
+ return EC_IOError;
+
+ // Write the index.
+ Out.write(OutputBuffer.data(), OutputBuffer.size());
+ Out.close();
+ if (Out.has_error())
+ return EC_IOError;
+
+ // Remove the old index file. It isn't relevant any more.
+ bool OldIndexExisted;
+ llvm::sys::fs::remove(IndexPath.str(), OldIndexExisted);
+
+ // Rename the newly-written index file to the proper name.
+ if (llvm::sys::fs::rename(IndexTmpPath.str(), IndexPath.str())) {
+ // Rename failed; just remove the
+ llvm::sys::fs::remove(IndexTmpPath.str(), OldIndexExisted);
+ return EC_IOError;
+ }
+
+ // We're done.
+ return EC_None;
+}
diff --git a/lib/Serialization/Module.cpp b/lib/Serialization/Module.cpp
index 5e42ab4..2eb3971 100644
--- a/lib/Serialization/Module.cpp
+++ b/lib/Serialization/Module.cpp
@@ -12,9 +12,9 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Serialization/Module.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/MemoryBuffer.h"
#include "ASTReaderInternals.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace serialization;
@@ -33,7 +33,7 @@ ModuleFile::ModuleFile(ModuleKind Kind, unsigned Generation)
PreprocessedEntityOffsets(0), NumPreprocessedEntities(0),
LocalNumHeaderFileInfos(0),
HeaderFileInfoTableData(0), HeaderFileInfoTable(0),
- HeaderFileFrameworkStrings(0), LocalNumSubmodules(0), BaseSubmoduleID(0),
+ LocalNumSubmodules(0), BaseSubmoduleID(0),
LocalNumSelectors(0), SelectorOffsets(0), BaseSelectorID(0),
SelectorLookupTableData(0), SelectorLookupTable(0), LocalNumDecls(0),
DeclOffsets(0), BaseDeclID(0),
diff --git a/lib/Serialization/ModuleManager.cpp b/lib/Serialization/ModuleManager.cpp
index efe4421..f3d53ad 100644
--- a/lib/Serialization/ModuleManager.cpp
+++ b/lib/Serialization/ModuleManager.cpp
@@ -11,8 +11,11 @@
// modules for the ASTReader.
//
//===----------------------------------------------------------------------===//
+#include "clang/Lex/ModuleMap.h"
#include "clang/Serialization/ModuleManager.h"
+#include "clang/Serialization/GlobalModuleIndex.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/PathV2.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
@@ -24,37 +27,63 @@ using namespace clang;
using namespace serialization;
ModuleFile *ModuleManager::lookup(StringRef Name) {
- const FileEntry *Entry = FileMgr.getFile(Name);
- return Modules[Entry];
+ const FileEntry *Entry = FileMgr.getFile(Name, /*openFile=*/false,
+ /*cacheFailure=*/false);
+ if (Entry)
+ return lookup(Entry);
+
+ return 0;
+}
+
+ModuleFile *ModuleManager::lookup(const FileEntry *File) {
+ llvm::DenseMap<const FileEntry *, ModuleFile *>::iterator Known
+ = Modules.find(File);
+ if (Known == Modules.end())
+ return 0;
+
+ return Known->second;
}
llvm::MemoryBuffer *ModuleManager::lookupBuffer(StringRef Name) {
- const FileEntry *Entry = FileMgr.getFile(Name);
+ const FileEntry *Entry = FileMgr.getFile(Name, /*openFile=*/false,
+ /*cacheFailure=*/false);
return InMemoryBuffers[Entry];
}
-std::pair<ModuleFile *, bool>
-ModuleManager::addModule(StringRef FileName, ModuleKind Type,
- ModuleFile *ImportedBy, unsigned Generation,
+ModuleManager::AddModuleResult
+ModuleManager::addModule(StringRef FileName, ModuleKind Type,
+ SourceLocation ImportLoc, ModuleFile *ImportedBy,
+ unsigned Generation,
+ off_t ExpectedSize, time_t ExpectedModTime,
+ ModuleFile *&Module,
std::string &ErrorStr) {
- const FileEntry *Entry = FileMgr.getFile(FileName);
+ Module = 0;
+
+ // Look for the file entry. This only fails if the expected size or
+ // modification time differ.
+ const FileEntry *Entry;
+ if (lookupModuleFile(FileName, ExpectedSize, ExpectedModTime, Entry))
+ return OutOfDate;
+
if (!Entry && FileName != "-") {
ErrorStr = "file not found";
- return std::make_pair(static_cast<ModuleFile*>(0), false);
+ return Missing;
}
-
- // Check whether we already loaded this module, before
+
+ // Check whether we already loaded this module, before
ModuleFile *&ModuleEntry = Modules[Entry];
bool NewModule = false;
if (!ModuleEntry) {
// Allocate a new module.
ModuleFile *New = new ModuleFile(Type, Generation);
+ New->Index = Chain.size();
New->FileName = FileName.str();
New->File = Entry;
+ New->ImportLoc = ImportLoc;
Chain.push_back(New);
NewModule = true;
ModuleEntry = New;
-
+
// Load the contents of the module
if (llvm::MemoryBuffer *Buffer = lookupBuffer(FileName)) {
// The buffer was already provided for us.
@@ -71,21 +100,26 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
New->Buffer.reset(FileMgr.getBufferForFile(FileName, &ErrorStr));
if (!New->Buffer)
- return std::make_pair(static_cast<ModuleFile*>(0), false);
+ return Missing;
}
// Initialize the stream
New->StreamFile.init((const unsigned char *)New->Buffer->getBufferStart(),
- (const unsigned char *)New->Buffer->getBufferEnd()); }
+ (const unsigned char *)New->Buffer->getBufferEnd());
+ }
if (ImportedBy) {
ModuleEntry->ImportedBy.insert(ImportedBy);
ImportedBy->Imports.insert(ModuleEntry);
} else {
+ if (!ModuleEntry->DirectlyImported)
+ ModuleEntry->ImportLoc = ImportLoc;
+
ModuleEntry->DirectlyImported = true;
}
-
- return std::make_pair(ModuleEntry, NewModule);
+
+ Module = ModuleEntry;
+ return NewModule? NewlyLoaded : AlreadyLoaded;
}
namespace {
@@ -104,7 +138,8 @@ namespace {
};
}
-void ModuleManager::removeModules(ModuleIterator first, ModuleIterator last) {
+void ModuleManager::removeModules(ModuleIterator first, ModuleIterator last,
+ ModuleMap *modMap) {
if (first == last)
return;
@@ -120,6 +155,14 @@ void ModuleManager::removeModules(ModuleIterator first, ModuleIterator last) {
// Delete the modules and erase them from the various structures.
for (ModuleIterator victim = first; victim != last; ++victim) {
Modules.erase((*victim)->File);
+
+ FileMgr.invalidateCache((*victim)->File);
+ if (modMap) {
+ StringRef ModuleName = llvm::sys::path::stem((*victim)->FileName);
+ if (Module *mod = modMap->findModule(ModuleName)) {
+ mod->setASTFile(0);
+ }
+ }
delete *victim;
}
@@ -135,79 +178,166 @@ void ModuleManager::addInMemoryBuffer(StringRef FileName,
InMemoryBuffers[Entry] = Buffer;
}
-ModuleManager::ModuleManager(FileManager &FileMgr) : FileMgr(FileMgr) { }
+ModuleManager::VisitState *ModuleManager::allocateVisitState() {
+ // Fast path: if we have a cached state, use it.
+ if (FirstVisitState) {
+ VisitState *Result = FirstVisitState;
+ FirstVisitState = FirstVisitState->NextState;
+ Result->NextState = 0;
+ return Result;
+ }
+
+ // Allocate and return a new state.
+ return new VisitState(size());
+}
+
+void ModuleManager::returnVisitState(VisitState *State) {
+ assert(State->NextState == 0 && "Visited state is in list?");
+ State->NextState = FirstVisitState;
+ FirstVisitState = State;
+}
+
+void ModuleManager::setGlobalIndex(GlobalModuleIndex *Index) {
+ GlobalIndex = Index;
+ if (!GlobalIndex) {
+ ModulesInCommonWithGlobalIndex.clear();
+ return;
+ }
+
+ // Notify the global module index about all of the modules we've already
+ // loaded.
+ for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
+ if (!GlobalIndex->loadedModuleFile(Chain[I])) {
+ ModulesInCommonWithGlobalIndex.push_back(Chain[I]);
+ }
+ }
+}
+
+void ModuleManager::moduleFileAccepted(ModuleFile *MF) {
+ if (!GlobalIndex || GlobalIndex->loadedModuleFile(MF))
+ return;
+
+ ModulesInCommonWithGlobalIndex.push_back(MF);
+}
+
+ModuleManager::ModuleManager(FileManager &FileMgr)
+ : FileMgr(FileMgr), GlobalIndex(), FirstVisitState(0) { }
ModuleManager::~ModuleManager() {
for (unsigned i = 0, e = Chain.size(); i != e; ++i)
delete Chain[e - i - 1];
+ delete FirstVisitState;
}
-void ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData),
- void *UserData) {
- unsigned N = size();
-
- // Record the number of incoming edges for each module. When we
- // encounter a module with no incoming edges, push it into the queue
- // to seed the queue.
- SmallVector<ModuleFile *, 4> Queue;
- Queue.reserve(N);
- llvm::DenseMap<ModuleFile *, unsigned> UnusedIncomingEdges;
- for (ModuleIterator M = begin(), MEnd = end(); M != MEnd; ++M) {
- if (unsigned Size = (*M)->ImportedBy.size())
- UnusedIncomingEdges[*M] = Size;
- else
- Queue.push_back(*M);
- }
-
- llvm::SmallPtrSet<ModuleFile *, 4> Skipped;
- unsigned QueueStart = 0;
- while (QueueStart < Queue.size()) {
- ModuleFile *CurrentModule = Queue[QueueStart++];
+void
+ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData),
+ void *UserData,
+ llvm::SmallPtrSet<ModuleFile *, 4> *ModuleFilesHit) {
+ // If the visitation order vector is the wrong size, recompute the order.
+ if (VisitOrder.size() != Chain.size()) {
+ unsigned N = size();
+ VisitOrder.clear();
+ VisitOrder.reserve(N);
- // Check whether this module should be skipped.
- if (Skipped.count(CurrentModule))
+ // Record the number of incoming edges for each module. When we
+ // encounter a module with no incoming edges, push it into the queue
+ // to seed the queue.
+ SmallVector<ModuleFile *, 4> Queue;
+ Queue.reserve(N);
+ llvm::SmallVector<unsigned, 4> UnusedIncomingEdges;
+ UnusedIncomingEdges.reserve(size());
+ for (ModuleIterator M = begin(), MEnd = end(); M != MEnd; ++M) {
+ if (unsigned Size = (*M)->ImportedBy.size())
+ UnusedIncomingEdges.push_back(Size);
+ else {
+ UnusedIncomingEdges.push_back(0);
+ Queue.push_back(*M);
+ }
+ }
+
+ // Traverse the graph, making sure to visit a module before visiting any
+ // of its dependencies.
+ unsigned QueueStart = 0;
+ while (QueueStart < Queue.size()) {
+ ModuleFile *CurrentModule = Queue[QueueStart++];
+ VisitOrder.push_back(CurrentModule);
+
+ // For any module that this module depends on, push it on the
+ // stack (if it hasn't already been marked as visited).
+ for (llvm::SetVector<ModuleFile *>::iterator
+ M = CurrentModule->Imports.begin(),
+ MEnd = CurrentModule->Imports.end();
+ M != MEnd; ++M) {
+ // Remove our current module as an impediment to visiting the
+ // module we depend on. If we were the last unvisited module
+ // that depends on this particular module, push it into the
+ // queue to be visited.
+ unsigned &NumUnusedEdges = UnusedIncomingEdges[(*M)->Index];
+ if (NumUnusedEdges && (--NumUnusedEdges == 0))
+ Queue.push_back(*M);
+ }
+ }
+
+ assert(VisitOrder.size() == N && "Visitation order is wrong?");
+
+ delete FirstVisitState;
+ FirstVisitState = 0;
+ }
+
+ VisitState *State = allocateVisitState();
+ unsigned VisitNumber = State->NextVisitNumber++;
+
+ // If the caller has provided us with a hit-set that came from the global
+ // module index, mark every module file in common with the global module
+ // index that is *not* in that set as 'visited'.
+ if (ModuleFilesHit && !ModulesInCommonWithGlobalIndex.empty()) {
+ for (unsigned I = 0, N = ModulesInCommonWithGlobalIndex.size(); I != N; ++I)
+ {
+ ModuleFile *M = ModulesInCommonWithGlobalIndex[I];
+ if (!ModuleFilesHit->count(M))
+ State->VisitNumber[M->Index] = VisitNumber;
+ }
+ }
+
+ for (unsigned I = 0, N = VisitOrder.size(); I != N; ++I) {
+ ModuleFile *CurrentModule = VisitOrder[I];
+ // Should we skip this module file?
+ if (State->VisitNumber[CurrentModule->Index] == VisitNumber)
continue;
-
- if (Visitor(*CurrentModule, UserData)) {
- // The visitor has requested that cut off visitation of any
- // module that the current module depends on. To indicate this
- // behavior, we mark all of the reachable modules as having N
- // incoming edges (which is impossible otherwise).
- SmallVector<ModuleFile *, 4> Stack;
- Stack.push_back(CurrentModule);
- Skipped.insert(CurrentModule);
- while (!Stack.empty()) {
- ModuleFile *NextModule = Stack.back();
- Stack.pop_back();
-
- // For any module that this module depends on, push it on the
- // stack (if it hasn't already been marked as visited).
- for (llvm::SetVector<ModuleFile *>::iterator
+
+ // Visit the module.
+ assert(State->VisitNumber[CurrentModule->Index] == VisitNumber - 1);
+ State->VisitNumber[CurrentModule->Index] = VisitNumber;
+ if (!Visitor(*CurrentModule, UserData))
+ continue;
+
+ // The visitor has requested that cut off visitation of any
+ // module that the current module depends on. To indicate this
+ // behavior, we mark all of the reachable modules as having been visited.
+ ModuleFile *NextModule = CurrentModule;
+ do {
+ // For any module that this module depends on, push it on the
+ // stack (if it hasn't already been marked as visited).
+ for (llvm::SetVector<ModuleFile *>::iterator
M = NextModule->Imports.begin(),
MEnd = NextModule->Imports.end();
- M != MEnd; ++M) {
- if (Skipped.insert(*M))
- Stack.push_back(*M);
+ M != MEnd; ++M) {
+ if (State->VisitNumber[(*M)->Index] != VisitNumber) {
+ State->Stack.push_back(*M);
+ State->VisitNumber[(*M)->Index] = VisitNumber;
}
}
- continue;
- }
-
- // For any module that this module depends on, push it on the
- // stack (if it hasn't already been marked as visited).
- for (llvm::SetVector<ModuleFile *>::iterator M = CurrentModule->Imports.begin(),
- MEnd = CurrentModule->Imports.end();
- M != MEnd; ++M) {
-
- // Remove our current module as an impediment to visiting the
- // module we depend on. If we were the last unvisited module
- // that depends on this particular module, push it into the
- // queue to be visited.
- unsigned &NumUnusedEdges = UnusedIncomingEdges[*M];
- if (NumUnusedEdges && (--NumUnusedEdges == 0))
- Queue.push_back(*M);
- }
+
+ if (State->Stack.empty())
+ break;
+
+ // Pop the next module off the stack.
+ NextModule = State->Stack.back();
+ State->Stack.pop_back();
+ } while (true);
}
+
+ returnVisitState(State);
}
/// \brief Perform a depth-first visit of the current module.
@@ -215,18 +345,19 @@ static bool visitDepthFirst(ModuleFile &M,
bool (*Visitor)(ModuleFile &M, bool Preorder,
void *UserData),
void *UserData,
- llvm::SmallPtrSet<ModuleFile *, 4> &Visited) {
+ SmallVectorImpl<bool> &Visited) {
// Preorder visitation
if (Visitor(M, /*Preorder=*/true, UserData))
return true;
// Visit children
for (llvm::SetVector<ModuleFile *>::iterator IM = M.Imports.begin(),
- IMEnd = M.Imports.end();
+ IMEnd = M.Imports.end();
IM != IMEnd; ++IM) {
- if (!Visited.insert(*IM))
+ if (Visited[(*IM)->Index])
continue;
-
+ Visited[(*IM)->Index] = true;
+
if (visitDepthFirst(**IM, Visitor, UserData, Visited))
return true;
}
@@ -238,16 +369,35 @@ static bool visitDepthFirst(ModuleFile &M,
void ModuleManager::visitDepthFirst(bool (*Visitor)(ModuleFile &M, bool Preorder,
void *UserData),
void *UserData) {
- llvm::SmallPtrSet<ModuleFile *, 4> Visited;
+ SmallVector<bool, 16> Visited(size(), false);
for (unsigned I = 0, N = Chain.size(); I != N; ++I) {
- if (!Visited.insert(Chain[I]))
+ if (Visited[Chain[I]->Index])
continue;
-
+ Visited[Chain[I]->Index] = true;
+
if (::visitDepthFirst(*Chain[I], Visitor, UserData, Visited))
return;
}
}
+bool ModuleManager::lookupModuleFile(StringRef FileName,
+ off_t ExpectedSize,
+ time_t ExpectedModTime,
+ const FileEntry *&File) {
+ File = FileMgr.getFile(FileName, /*openFile=*/false, /*cacheFailure=*/false);
+
+ if (!File && FileName != "-") {
+ return false;
+ }
+
+ if ((ExpectedSize && ExpectedSize != File->getSize()) ||
+ (ExpectedModTime && ExpectedModTime != File->getModificationTime())) {
+ return true;
+ }
+
+ return false;
+}
+
#ifndef NDEBUG
namespace llvm {
template<>
diff --git a/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp b/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
index aa6f97b..9af0a5a 100644
--- a/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
@@ -11,17 +11,17 @@
#define DEBUG_TYPE "StatsChecker"
#include "ClangSACheckers.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
-
-#include "clang/AST/DeclObjC.h"
-#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Statistic.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -60,7 +60,7 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
if (D != P.getLocationContext()->getDecl())
continue;
- if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
+ if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
const CFGBlock *CB = BE->getBlock();
reachable.insert(CB);
}
@@ -123,14 +123,14 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
const BlockEdge &BE = I->first;
const CFGBlock *Exit = BE.getDst();
const CFGElement &CE = Exit->front();
- if (const CFGStmt *CS = dyn_cast<CFGStmt>(&CE)) {
+ if (Optional<CFGStmt> CS = CE.getAs<CFGStmt>()) {
SmallString<128> bufI;
llvm::raw_svector_ostream outputI(bufI);
outputI << "(" << NameOfRootFunction << ")" <<
": The analyzer generated a sink at this point";
- B.EmitBasicReport(D, "Sink Point", "Internal Statistics", outputI.str(),
- PathDiagnosticLocation::createBegin(CS->getStmt(),
- SM, LC));
+ B.EmitBasicReport(
+ D, "Sink Point", "Internal Statistics", outputI.str(),
+ PathDiagnosticLocation::createBegin(CS->getStmt(), SM, LC));
}
}
}
diff --git a/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp b/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
index 535d8ee..312bc74 100644
--- a/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
@@ -13,10 +13,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
using namespace clang;
@@ -44,7 +44,7 @@ void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS,
return;
// Get the index of the accessed element.
- DefinedOrUnknownSVal Idx = cast<DefinedOrUnknownSVal>(ER->getIndex());
+ DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>();
// Zero index is always in bound, this also passes ElementRegions created for
// pointer casts.
diff --git a/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
index 457c870..5e4b824 100644
--- a/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
+++ b/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
@@ -13,14 +13,14 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/CharUnits.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/AST/CharUnits.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -53,7 +53,7 @@ public:
RegionRawOffsetV2(const SubRegion* base, SVal offset)
: baseRegion(base), byteOffset(offset) {}
- NonLoc getByteOffset() const { return cast<NonLoc>(byteOffset); }
+ NonLoc getByteOffset() const { return byteOffset.castAs<NonLoc>(); }
const SubRegion *getRegion() const { return baseRegion; }
static RegionRawOffsetV2 computeOffset(ProgramStateRef state,
@@ -110,13 +110,12 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
SVal extentBegin = computeExtentBegin(svalBuilder, rawOffset.getRegion());
- if (isa<NonLoc>(extentBegin)) {
- SVal lowerBound
- = svalBuilder.evalBinOpNN(state, BO_LT, rawOffset.getByteOffset(),
- cast<NonLoc>(extentBegin),
+ if (Optional<NonLoc> NV = extentBegin.getAs<NonLoc>()) {
+ SVal lowerBound =
+ svalBuilder.evalBinOpNN(state, BO_LT, rawOffset.getByteOffset(), *NV,
svalBuilder.getConditionType());
- NonLoc *lowerBoundToCheck = dyn_cast<NonLoc>(&lowerBound);
+ Optional<NonLoc> lowerBoundToCheck = lowerBound.getAs<NonLoc>();
if (!lowerBoundToCheck)
return;
@@ -140,15 +139,15 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
// we are doing a load/store after the last valid offset.
DefinedOrUnknownSVal extentVal =
rawOffset.getRegion()->getExtent(svalBuilder);
- if (!isa<NonLoc>(extentVal))
+ if (!extentVal.getAs<NonLoc>())
break;
SVal upperbound
= svalBuilder.evalBinOpNN(state, BO_GE, rawOffset.getByteOffset(),
- cast<NonLoc>(extentVal),
+ extentVal.castAs<NonLoc>(),
svalBuilder.getConditionType());
- NonLoc *upperboundToCheck = dyn_cast<NonLoc>(&upperbound);
+ Optional<NonLoc> upperboundToCheck = upperbound.getAs<NonLoc>();
if (!upperboundToCheck)
break;
@@ -235,7 +234,7 @@ static bool IsCompleteType(ASTContext &Ctx, QualType Ty) {
// is unknown or undefined, we lazily substitute '0'. Otherwise,
// return 'val'.
static inline SVal getValue(SVal val, SValBuilder &svalBuilder) {
- return isa<UndefinedVal>(val) ? svalBuilder.makeArrayIndex(0) : val;
+ return val.getAs<UndefinedVal>() ? svalBuilder.makeArrayIndex(0) : val;
}
// Scale a base value by a scaling factor, and return the scaled
@@ -256,9 +255,9 @@ static SVal addValue(ProgramStateRef state, SVal x, SVal y,
// only care about computing offsets.
if (x.isUnknownOrUndef() || y.isUnknownOrUndef())
return UnknownVal();
-
- return svalBuilder.evalBinOpNN(state, BO_Add,
- cast<NonLoc>(x), cast<NonLoc>(y),
+
+ return svalBuilder.evalBinOpNN(state, BO_Add, x.castAs<NonLoc>(),
+ y.castAs<NonLoc>(),
svalBuilder.getArrayIndexType());
}
@@ -284,7 +283,7 @@ RegionRawOffsetV2 RegionRawOffsetV2::computeOffset(ProgramStateRef state,
case MemRegion::ElementRegionKind: {
const ElementRegion *elemReg = cast<ElementRegion>(region);
SVal index = elemReg->getIndex();
- if (!isa<NonLoc>(index))
+ if (!index.getAs<NonLoc>())
return RegionRawOffsetV2();
QualType elemType = elemReg->getElementType();
// If the element is an incomplete type, go no further.
@@ -296,7 +295,7 @@ RegionRawOffsetV2 RegionRawOffsetV2::computeOffset(ProgramStateRef state,
offset = addValue(state,
getValue(offset, svalBuilder),
scaleValue(state,
- cast<NonLoc>(index),
+ index.castAs<NonLoc>(),
astContext.getTypeSizeInChars(elemType),
svalBuilder),
svalBuilder);
diff --git a/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp b/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp
deleted file mode 100644
index 81e8dd8..0000000
--- a/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp
+++ /dev/null
@@ -1,130 +0,0 @@
-//===--- AttrNonNullChecker.h - Undefined arguments checker ----*- C++ -*--===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This defines AttrNonNullChecker, a builtin check in ExprEngine that
-// performs checks for arguments declared to have nonnull attribute.
-//
-//===----------------------------------------------------------------------===//
-
-#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"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class AttrNonNullChecker
- : public Checker< check::PreCall > {
- mutable OwningPtr<BugType> BT;
-public:
-
- void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
-};
-} // end anonymous namespace
-
-void AttrNonNullChecker::checkPreCall(const CallEvent &Call,
- CheckerContext &C) const {
- const Decl *FD = Call.getDecl();
- if (!FD)
- return;
-
- const NonNullAttr *Att = FD->getAttr<NonNullAttr>();
- if (!Att)
- return;
-
- ProgramStateRef state = C.getState();
-
- // Iterate through the arguments of CE and check them for null.
- for (unsigned idx = 0, count = Call.getNumArgs(); idx != count; ++idx) {
- if (!Att->isNonNull(idx))
- continue;
-
- SVal V = Call.getArgSVal(idx);
- DefinedSVal *DV = dyn_cast<DefinedSVal>(&V);
-
- // If the value is unknown or undefined, we can't perform this check.
- if (!DV)
- continue;
-
- if (!isa<Loc>(*DV)) {
- // If the argument is a union type, we want to handle a potential
- // transparent_union GCC extension.
- const Expr *ArgE = Call.getArgExpr(idx);
- if (!ArgE)
- continue;
-
- QualType T = ArgE->getType();
- const RecordType *UT = T->getAsUnionType();
- if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>())
- continue;
-
- if (nonloc::CompoundVal *CSV = dyn_cast<nonloc::CompoundVal>(DV)) {
- nonloc::CompoundVal::iterator CSV_I = CSV->begin();
- assert(CSV_I != CSV->end());
- V = *CSV_I;
- DV = dyn_cast<DefinedSVal>(&V);
- assert(++CSV_I == CSV->end());
- if (!DV)
- continue;
- } else {
- // FIXME: Handle LazyCompoundVals?
- continue;
- }
- }
-
- ConstraintManager &CM = C.getConstraintManager();
- ProgramStateRef stateNotNull, stateNull;
- llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
-
- if (stateNull && !stateNotNull) {
- // Generate an error node. Check for a null node in case
- // we cache out.
- if (ExplodedNode *errorNode = C.generateSink(stateNull)) {
-
- // Lazily allocate the BugType object if it hasn't already been
- // created. Ownership is transferred to the BugReporter object once
- // the BugReport is passed to 'EmitWarning'.
- if (!BT)
- BT.reset(new BugType("Argument with 'nonnull' attribute passed null",
- "API"));
-
- BugReport *R =
- new BugReport(*BT, "Null pointer passed as an argument to a "
- "'nonnull' parameter", errorNode);
-
- // Highlight the range of the argument that was null.
- R->addRange(Call.getArgSourceRange(idx));
- if (const Expr *ArgE = Call.getArgExpr(idx))
- bugreporter::trackNullOrUndefValue(errorNode, ArgE, *R);
- // Emit the bug report.
- C.emitReport(R);
- }
-
- // Always return. Either we cached out or we just emitted an error.
- return;
- }
-
- // If a pointer value passed the check we should assume that it is
- // indeed not null from this point forward.
- assert(stateNotNull);
- state = stateNotNull;
- }
-
- // If we reach here all of the arguments passed the nonnull check.
- // If 'state' has been updated generated a new node.
- C.addTransition(state);
-}
-
-void ento::registerAttrNonNullChecker(CheckerManager &mgr) {
- mgr.registerChecker<AttrNonNullChecker>();
-}
diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index eba534e..533a324 100644
--- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -14,23 +14,24 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/StmtObjC.h"
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/ExprObjC.h"
-#include "clang/AST/StmtObjC.h"
-#include "clang/AST/ASTContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -82,10 +83,6 @@ static FoundationClass findKnownClass(const ObjCInterfaceDecl *ID) {
return result;
}
-static inline bool isNil(SVal X) {
- return isa<loc::ConcreteInt>(X);
-}
-
//===----------------------------------------------------------------------===//
// NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
//===----------------------------------------------------------------------===//
@@ -94,29 +91,55 @@ namespace {
class NilArgChecker : public Checker<check::PreObjCMessage> {
mutable OwningPtr<APIMisuse> BT;
- void WarnNilArg(CheckerContext &C,
- const ObjCMethodCall &msg, unsigned Arg) const;
+ void WarnIfNilArg(CheckerContext &C,
+ const ObjCMethodCall &msg, unsigned Arg,
+ FoundationClass Class,
+ bool CanBeSubscript = false) const;
public:
void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
};
}
-void NilArgChecker::WarnNilArg(CheckerContext &C,
- const ObjCMethodCall &msg,
- unsigned int Arg) const
-{
+void NilArgChecker::WarnIfNilArg(CheckerContext &C,
+ const ObjCMethodCall &msg,
+ unsigned int Arg,
+ FoundationClass Class,
+ bool CanBeSubscript) const {
+ // Check if the argument is nil.
+ ProgramStateRef State = C.getState();
+ if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue())
+ return;
+
if (!BT)
BT.reset(new APIMisuse("nil argument"));
-
+
if (ExplodedNode *N = C.generateSink()) {
SmallString<128> sbuf;
llvm::raw_svector_ostream os(sbuf);
- os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '"
- << msg.getSelector().getAsString() << "' cannot be nil";
+
+ if (CanBeSubscript && msg.getMessageKind() == OCM_Subscript) {
+
+ if (Class == FC_NSArray) {
+ os << "Array element cannot be nil";
+ } else if (Class == FC_NSDictionary) {
+ if (Arg == 0)
+ os << "Dictionary object cannot be nil";
+ else {
+ assert(Arg == 1);
+ os << "Dictionary key cannot be nil";
+ }
+ } else
+ llvm_unreachable("Missing foundation class for the subscript expr");
+
+ } else {
+ os << "Argument to '" << GetReceiverInterfaceName(msg) << "' method '"
+ << msg.getSelector().getAsString() << "' cannot be nil";
+ }
BugReport *R = new BugReport(*BT, os.str(), N);
R->addRange(msg.getArgSourceRange(Arg));
+ bugreporter::trackNullOrUndefValue(N, msg.getArgExpr(Arg), *R);
C.emitReport(R);
}
}
@@ -126,8 +149,14 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
const ObjCInterfaceDecl *ID = msg.getReceiverInterface();
if (!ID)
return;
+
+ FoundationClass Class = findKnownClass(ID);
+
+ static const unsigned InvalidArgIndex = UINT_MAX;
+ unsigned Arg = InvalidArgIndex;
+ bool CanBeSubscript = false;
- if (findKnownClass(ID) == FC_NSString) {
+ if (Class == FC_NSString) {
Selector S = msg.getSelector();
if (S.isUnarySelector())
@@ -151,10 +180,58 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
Name == "compare:options:range:locale:" ||
Name == "componentsSeparatedByCharactersInSet:" ||
Name == "initWithFormat:") {
- if (isNil(msg.getArgSVal(0)))
- WarnNilArg(C, msg, 0);
+ Arg = 0;
+ }
+ } else if (Class == FC_NSArray) {
+ Selector S = msg.getSelector();
+
+ if (S.isUnarySelector())
+ return;
+
+ if (S.getNameForSlot(0).equals("addObject")) {
+ Arg = 0;
+ } else if (S.getNameForSlot(0).equals("insertObject") &&
+ S.getNameForSlot(1).equals("atIndex")) {
+ Arg = 0;
+ } else if (S.getNameForSlot(0).equals("replaceObjectAtIndex") &&
+ S.getNameForSlot(1).equals("withObject")) {
+ Arg = 1;
+ } else if (S.getNameForSlot(0).equals("setObject") &&
+ S.getNameForSlot(1).equals("atIndexedSubscript")) {
+ Arg = 0;
+ CanBeSubscript = true;
+ } else if (S.getNameForSlot(0).equals("arrayByAddingObject")) {
+ Arg = 0;
+ }
+ } else if (Class == FC_NSDictionary) {
+ Selector S = msg.getSelector();
+
+ if (S.isUnarySelector())
+ return;
+
+ if (S.getNameForSlot(0).equals("dictionaryWithObject") &&
+ S.getNameForSlot(1).equals("forKey")) {
+ Arg = 0;
+ WarnIfNilArg(C, msg, /* Arg */1, Class);
+ } else if (S.getNameForSlot(0).equals("setObject") &&
+ S.getNameForSlot(1).equals("forKey")) {
+ Arg = 0;
+ WarnIfNilArg(C, msg, /* Arg */1, Class);
+ } else if (S.getNameForSlot(0).equals("setObject") &&
+ S.getNameForSlot(1).equals("forKeyedSubscript")) {
+ CanBeSubscript = true;
+ Arg = 0;
+ WarnIfNilArg(C, msg, /* Arg */1, Class, CanBeSubscript);
+ } else if (S.getNameForSlot(0).equals("removeObjectForKey")) {
+ Arg = 0;
}
}
+
+
+ // If argument is '0', report a warning.
+ if ((Arg != InvalidArgIndex))
+ WarnIfNilArg(C, msg, Arg, Class, CanBeSubscript);
+
}
//===----------------------------------------------------------------------===//
@@ -195,28 +272,6 @@ enum CFNumberType {
kCFNumberCGFloatType = 16
};
-namespace {
- template<typename T>
- class Optional {
- bool IsKnown;
- T Val;
- public:
- Optional() : IsKnown(false), Val(0) {}
- Optional(const T& val) : IsKnown(true), Val(val) {}
-
- bool isKnown() const { return IsKnown; }
-
- const T& getValue() const {
- assert (isKnown());
- return Val;
- }
-
- operator const T&() const {
- return getValue();
- }
- };
-}
-
static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
@@ -238,7 +293,7 @@ static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
case kCFNumberCGFloatType:
// FIXME: We need a way to map from names to Type*.
default:
- return Optional<uint64_t>();
+ return None;
}
return Ctx.getTypeSize(T);
@@ -289,17 +344,19 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
// FIXME: We really should allow ranges of valid theType values, and
// bifurcate the state appropriately.
- nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);
+ Optional<nonloc::ConcreteInt> V = TheTypeVal.getAs<nonloc::ConcreteInt>();
if (!V)
return;
uint64_t NumberKind = V->getValue().getLimitedValue();
- Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);
+ Optional<uint64_t> OptTargetSize = GetCFNumberSize(Ctx, NumberKind);
// FIXME: In some cases we can emit an error.
- if (!TargetSize.isKnown())
+ if (!OptTargetSize)
return;
+ uint64_t TargetSize = *OptTargetSize;
+
// Look at the value of the integer being passed by reference. Essentially
// we want to catch cases where the value passed in is not equal to the
// size of the type being created.
@@ -307,7 +364,7 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
// FIXME: Eventually we should handle arbitrary locations. We can do this
// by having an enhanced memory model that does low-level typing.
- loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);
+ Optional<loc::MemRegionVal> LV = TheValueExpr.getAs<loc::MemRegionVal>();
if (!LV)
return;
@@ -403,18 +460,19 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
return;
// FIXME: The rest of this just checks that the argument is non-null.
- // It should probably be refactored and combined with AttrNonNullChecker.
+ // It should probably be refactored and combined with NonNullParamChecker.
// Get the argument's value.
const Expr *Arg = CE->getArg(0);
SVal ArgVal = state->getSVal(Arg, C.getLocationContext());
- DefinedSVal *DefArgVal = dyn_cast<DefinedSVal>(&ArgVal);
+ Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
if (!DefArgVal)
return;
// Get a NULL value.
SValBuilder &svalBuilder = C.getSValBuilder();
- DefinedSVal zero = cast<DefinedSVal>(svalBuilder.makeZeroVal(Arg->getType()));
+ DefinedSVal zero =
+ svalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>();
// Make an expression asserting that they're equal.
DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
@@ -605,7 +663,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
return;
// Verify that all arguments have Objective-C types.
- llvm::Optional<ExplodedNode*> errorNode;
+ Optional<ExplodedNode*> errorNode;
ProgramStateRef state = C.getState();
for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
@@ -618,7 +676,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
continue;
// Ignore pointer constants.
- if (isa<loc::ConcreteInt>(msg.getArgSVal(I)))
+ if (msg.getArgSVal(I).getAs<loc::ConcreteInt>())
continue;
// Ignore pointer types annotated with 'NSObject' attribute.
@@ -715,12 +773,12 @@ void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
ElementVar = State->getSVal(Element, C.getLocationContext());
}
- if (!isa<Loc>(ElementVar))
+ if (!ElementVar.getAs<Loc>())
return;
// Go ahead and assume the value is non-nil.
- SVal Val = State->getSVal(cast<Loc>(ElementVar));
- State = State->assume(cast<DefinedOrUnknownSVal>(Val), true);
+ SVal Val = State->getSVal(ElementVar.castAs<Loc>());
+ State = State->assume(Val.castAs<DefinedOrUnknownSVal>(), true);
C.addTransition(State);
}
@@ -744,7 +802,7 @@ static ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
ProgramStateRef State,
CheckerContext &C) {
SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
- if (DefinedOrUnknownSVal *DV = dyn_cast<DefinedOrUnknownSVal>(&Val))
+ if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>())
return State->assume(*DV, true);
return State;
}
diff --git a/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp b/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
index 92edefe..5169244 100644
--- a/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
@@ -13,17 +13,17 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
using namespace clang;
using namespace ento;
namespace {
class BoolAssignmentChecker : public Checker< check::Bind > {
- mutable llvm::OwningPtr<BuiltinBug> BT;
+ mutable OwningPtr<BuiltinBug> BT;
void emitReport(ProgramStateRef state, CheckerContext &C) const;
public:
void checkBind(SVal loc, SVal val, const Stmt *S, CheckerContext &C) const;
@@ -69,7 +69,7 @@ void BoolAssignmentChecker::checkBind(SVal loc, SVal val, const Stmt *S,
// Get the value of the right-hand side. We only care about values
// that are defined (UnknownVals and UndefinedVals are handled by other
// checkers).
- const DefinedSVal *DV = dyn_cast<DefinedSVal>(&val);
+ Optional<DefinedSVal> DV = val.getAs<DefinedSVal>();
if (!DV)
return;
@@ -85,10 +85,10 @@ void BoolAssignmentChecker::checkBind(SVal loc, SVal val, const Stmt *S,
SVal greaterThanOrEqualToZeroVal =
svalBuilder.evalBinOp(state, BO_GE, *DV, zeroVal,
svalBuilder.getConditionType());
-
- DefinedSVal *greaterThanEqualToZero =
- dyn_cast<DefinedSVal>(&greaterThanOrEqualToZeroVal);
-
+
+ Optional<DefinedSVal> greaterThanEqualToZero =
+ greaterThanOrEqualToZeroVal.getAs<DefinedSVal>();
+
if (!greaterThanEqualToZero) {
// The SValBuilder cannot construct a valid SVal for this condition.
// This means we cannot properly reason about it.
@@ -121,10 +121,10 @@ void BoolAssignmentChecker::checkBind(SVal loc, SVal val, const Stmt *S,
SVal lessThanEqToOneVal =
svalBuilder.evalBinOp(state, BO_LE, *DV, OneVal,
svalBuilder.getConditionType());
-
- DefinedSVal *lessThanEqToOne =
- dyn_cast<DefinedSVal>(&lessThanEqToOneVal);
-
+
+ Optional<DefinedSVal> lessThanEqToOne =
+ lessThanEqToOneVal.getAs<DefinedSVal>();
+
if (!lessThanEqToOne) {
// The SValBuilder cannot construct a valid SVal for this condition.
// This means we cannot properly reason about it.
diff --git a/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp b/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
index 6ef022b..a3327d8 100644
--- a/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
@@ -12,10 +12,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/Basic/Builtins.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;
@@ -61,13 +61,14 @@ bool BuiltinFunctionChecker::evalCall(const CallExpr *CE,
// SVal of the argument directly. If we save the extent in bits, we
// cannot represent values like symbol*8.
DefinedOrUnknownSVal Size =
- cast<DefinedOrUnknownSVal>(state->getSVal(*(CE->arg_begin()), LCtx));
+ state->getSVal(*(CE->arg_begin()), LCtx).castAs<DefinedOrUnknownSVal>();
SValBuilder& svalBuilder = C.getSValBuilder();
DefinedOrUnknownSVal Extent = R->getExtent(svalBuilder);
DefinedOrUnknownSVal extentMatchesSizeArg =
svalBuilder.evalEQ(state, Extent, Size);
state = state->assume(extentMatchesSizeArg, true);
+ assert(state && "The region should not have any previous constraints");
C.addTransition(state->BindExpr(CE, LCtx, loc::MemRegionVal(R)));
return true;
diff --git a/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index 8e455de..b7df10e 100644
--- a/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -7,7 +7,6 @@ add_clang_library(clangStaticAnalyzerCheckers
AnalyzerStatsChecker.cpp
ArrayBoundChecker.cpp
ArrayBoundCheckerV2.cpp
- AttrNonNullChecker.cpp
BasicObjCFoundationChecks.cpp
BoolAssignmentChecker.cpp
BuiltinFunctionChecker.cpp
@@ -31,7 +30,6 @@ add_clang_library(clangStaticAnalyzerCheckers
DivZeroChecker.cpp
DynamicTypePropagation.cpp
ExprInspectionChecker.cpp
- SimpleStreamChecker.cpp
FixedAddressChecker.cpp
GenericTaintChecker.cpp
IdempotentOperationChecker.cpp
@@ -44,6 +42,7 @@ add_clang_library(clangStaticAnalyzerCheckers
MallocSizeofChecker.cpp
NSAutoreleasePoolChecker.cpp
NSErrorChecker.cpp
+ NonNullParamChecker.cpp
NoReturnFunctionChecker.cpp
ObjCAtSyncChecker.cpp
ObjCContainersASTChecker.cpp
@@ -57,6 +56,7 @@ add_clang_library(clangStaticAnalyzerCheckers
RetainCountChecker.cpp
ReturnPointerRangeChecker.cpp
ReturnUndefChecker.cpp
+ SimpleStreamChecker.cpp
StackAddrEscapeChecker.cpp
StreamChecker.cpp
TaintTesterChecker.cpp
diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index eae9ddf..cc55e9f 100644
--- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -14,14 +14,16 @@
#include "ClangSACheckers.h"
#include "InterCheckerAPI.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -63,7 +65,7 @@ public:
ProgramStateRef
checkRegionChanges(ProgramStateRef state,
- const StoreManager::InvalidatedSymbols *,
+ const InvalidatedSymbols *,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
const CallEvent *Call) const;
@@ -199,7 +201,7 @@ REGISTER_MAP_WITH_PROGRAMSTATE(CStringLength, const MemRegion *, SVal)
std::pair<ProgramStateRef , ProgramStateRef >
CStringChecker::assumeZero(CheckerContext &C, ProgramStateRef state, SVal V,
QualType Ty) {
- DefinedSVal *val = dyn_cast<DefinedSVal>(&V);
+ Optional<DefinedSVal> val = V.getAs<DefinedSVal>();
if (!val)
return std::pair<ProgramStateRef , ProgramStateRef >(state, state);
@@ -276,10 +278,10 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
SValBuilder &svalBuilder = C.getSValBuilder();
SVal Extent =
svalBuilder.convertToArrayIndex(superReg->getExtent(svalBuilder));
- DefinedOrUnknownSVal Size = cast<DefinedOrUnknownSVal>(Extent);
+ DefinedOrUnknownSVal Size = Extent.castAs<DefinedOrUnknownSVal>();
// Get the index of the accessed element.
- DefinedOrUnknownSVal Idx = cast<DefinedOrUnknownSVal>(ER->getIndex());
+ DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>();
ProgramStateRef StInBound = state->assumeInBound(Idx, Size, true);
ProgramStateRef StOutBound = state->assumeInBound(Idx, Size, false);
@@ -304,7 +306,7 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
SmallString<80> buf;
llvm::raw_svector_ostream os(buf);
- os << (char)toupper(CurrentFunctionDescription[0])
+ os << toUppercase(CurrentFunctionDescription[0])
<< &CurrentFunctionDescription[1]
<< " accesses out-of-bound array element";
report = new BugReport(*BT, os.str(), N);
@@ -357,18 +359,18 @@ ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C,
// FIXME: This assumes the caller has already checked that the access length
// is positive. And that it's unsigned.
SVal LengthVal = state->getSVal(Size, LCtx);
- NonLoc *Length = dyn_cast<NonLoc>(&LengthVal);
+ Optional<NonLoc> Length = LengthVal.getAs<NonLoc>();
if (!Length)
return state;
// Compute the offset of the last element to be accessed: size-1.
- NonLoc One = cast<NonLoc>(svalBuilder.makeIntVal(1, sizeTy));
- NonLoc LastOffset = cast<NonLoc>(svalBuilder.evalBinOpNN(state, BO_Sub,
- *Length, One, sizeTy));
+ NonLoc One = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>();
+ NonLoc LastOffset = svalBuilder
+ .evalBinOpNN(state, BO_Sub, *Length, One, sizeTy).castAs<NonLoc>();
// Check that the first buffer is sufficiently long.
SVal BufStart = svalBuilder.evalCast(BufVal, PtrTy, FirstBuf->getType());
- if (Loc *BufLoc = dyn_cast<Loc>(&BufStart)) {
+ if (Optional<Loc> BufLoc = BufStart.getAs<Loc>()) {
const Expr *warningExpr = (WarnAboutSize ? Size : FirstBuf);
SVal BufEnd = svalBuilder.evalBinOpLN(state, BO_Add, *BufLoc,
@@ -388,7 +390,7 @@ ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C,
return NULL;
BufStart = svalBuilder.evalCast(BufVal, PtrTy, SecondBuf->getType());
- if (Loc *BufLoc = dyn_cast<Loc>(&BufStart)) {
+ if (Optional<Loc> BufLoc = BufStart.getAs<Loc>()) {
const Expr *warningExpr = (WarnAboutSize ? Size : SecondBuf);
SVal BufEnd = svalBuilder.evalBinOpLN(state, BO_Add, *BufLoc,
@@ -424,11 +426,11 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
SVal firstVal = state->getSVal(First, LCtx);
SVal secondVal = state->getSVal(Second, LCtx);
- Loc *firstLoc = dyn_cast<Loc>(&firstVal);
+ Optional<Loc> firstLoc = firstVal.getAs<Loc>();
if (!firstLoc)
return state;
- Loc *secondLoc = dyn_cast<Loc>(&secondVal);
+ Optional<Loc> secondLoc = secondVal.getAs<Loc>();
if (!secondLoc)
return state;
@@ -451,7 +453,8 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
QualType cmpTy = svalBuilder.getConditionType();
SVal reverse = svalBuilder.evalBinOpLL(state, BO_GT,
*firstLoc, *secondLoc, cmpTy);
- DefinedOrUnknownSVal *reverseTest = dyn_cast<DefinedOrUnknownSVal>(&reverse);
+ Optional<DefinedOrUnknownSVal> reverseTest =
+ reverse.getAs<DefinedOrUnknownSVal>();
if (!reverseTest)
return state;
@@ -462,20 +465,16 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
return state;
} else {
// Switch the values so that firstVal is before secondVal.
- Loc *tmpLoc = firstLoc;
- firstLoc = secondLoc;
- secondLoc = tmpLoc;
+ std::swap(firstLoc, secondLoc);
// Switch the Exprs as well, so that they still correspond.
- const Expr *tmpExpr = First;
- First = Second;
- Second = tmpExpr;
+ std::swap(First, Second);
}
}
// Get the length, and make sure it too is known.
SVal LengthVal = state->getSVal(Size, LCtx);
- NonLoc *Length = dyn_cast<NonLoc>(&LengthVal);
+ Optional<NonLoc> Length = LengthVal.getAs<NonLoc>();
if (!Length)
return state;
@@ -485,21 +484,22 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy);
SVal FirstStart = svalBuilder.evalCast(*firstLoc, CharPtrTy,
First->getType());
- Loc *FirstStartLoc = dyn_cast<Loc>(&FirstStart);
+ Optional<Loc> FirstStartLoc = FirstStart.getAs<Loc>();
if (!FirstStartLoc)
return state;
// Compute the end of the first buffer. Bail out if THAT fails.
SVal FirstEnd = svalBuilder.evalBinOpLN(state, BO_Add,
*FirstStartLoc, *Length, CharPtrTy);
- Loc *FirstEndLoc = dyn_cast<Loc>(&FirstEnd);
+ Optional<Loc> FirstEndLoc = FirstEnd.getAs<Loc>();
if (!FirstEndLoc)
return state;
// Is the end of the first buffer past the start of the second buffer?
SVal Overlap = svalBuilder.evalBinOpLL(state, BO_GT,
*FirstEndLoc, *secondLoc, cmpTy);
- DefinedOrUnknownSVal *OverlapTest = dyn_cast<DefinedOrUnknownSVal>(&Overlap);
+ Optional<DefinedOrUnknownSVal> OverlapTest =
+ Overlap.getAs<DefinedOrUnknownSVal>();
if (!OverlapTest)
return state;
@@ -555,7 +555,7 @@ ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C,
NonLoc maxVal = svalBuilder.makeIntVal(maxValInt);
SVal maxMinusRight;
- if (isa<nonloc::ConcreteInt>(right)) {
+ if (right.getAs<nonloc::ConcreteInt>()) {
maxMinusRight = svalBuilder.evalBinOpNN(state, BO_Sub, maxVal, right,
sizeTy);
} else {
@@ -566,7 +566,7 @@ ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C,
left = right;
}
- if (NonLoc *maxMinusRightNL = dyn_cast<NonLoc>(&maxMinusRight)) {
+ if (Optional<NonLoc> maxMinusRightNL = maxMinusRight.getAs<NonLoc>()) {
QualType cmpTy = svalBuilder.getConditionType();
// If left > max - right, we have an overflow.
SVal willOverflow = svalBuilder.evalBinOpNN(state, BO_GT, left,
@@ -574,7 +574,7 @@ ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C,
ProgramStateRef stateOverflow, stateOkay;
llvm::tie(stateOverflow, stateOkay) =
- state->assume(cast<DefinedOrUnknownSVal>(willOverflow));
+ state->assume(willOverflow.castAs<DefinedOrUnknownSVal>());
if (stateOverflow && !stateOkay) {
// We have an overflow. Emit a bug report.
@@ -681,7 +681,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,
// If we can't get a region, see if it's something we /know/ isn't a
// C string. In the context of locations, the only time we can issue such
// a warning is for labels.
- if (loc::GotoLabel *Label = dyn_cast<loc::GotoLabel>(&Buf)) {
+ if (Optional<loc::GotoLabel> Label = Buf.getAs<loc::GotoLabel>()) {
if (!Filter.CheckCStringNotNullTerm)
return UndefinedVal();
@@ -796,14 +796,14 @@ const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &C,
ProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C,
ProgramStateRef state,
const Expr *E, SVal V) {
- Loc *L = dyn_cast<Loc>(&V);
+ Optional<Loc> L = V.getAs<Loc>();
if (!L)
return state;
// FIXME: This is a simplified version of what's in CFRefCount.cpp -- it makes
// some assumptions about the value that CFRefCount can't. Even so, it should
// probably be refactored.
- if (loc::MemRegionVal* MR = dyn_cast<loc::MemRegionVal>(L)) {
+ if (Optional<loc::MemRegionVal> MR = L->getAs<loc::MemRegionVal>()) {
const MemRegion *R = MR->getRegion()->StripCasts();
// Are we dealing with an ElementRegion? If so, we should be invalidating
@@ -815,7 +815,8 @@ ProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C,
// Invalidate this region.
const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
- return state->invalidateRegions(R, E, C.blockCount(), LCtx);
+ return state->invalidateRegions(R, E, C.blockCount(), LCtx,
+ /*CausesPointerEscape*/ false);
}
// If we have a non-region value by chance, just remove the binding.
@@ -926,16 +927,13 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
// If this is mempcpy, get the byte after the last byte copied and
// bind the expr.
if (IsMempcpy) {
- loc::MemRegionVal *destRegVal = dyn_cast<loc::MemRegionVal>(&destVal);
- assert(destRegVal && "Destination should be a known MemRegionVal here");
+ loc::MemRegionVal destRegVal = destVal.castAs<loc::MemRegionVal>();
// Get the length to copy.
- NonLoc *lenValNonLoc = dyn_cast<NonLoc>(&sizeVal);
-
- if (lenValNonLoc) {
+ if (Optional<NonLoc> lenValNonLoc = sizeVal.getAs<NonLoc>()) {
// Get the byte after the last byte copied.
SVal lastElement = C.getSValBuilder().evalBinOpLN(state, BO_Add,
- *destRegVal,
+ destRegVal,
*lenValNonLoc,
Dest->getType());
@@ -1051,9 +1049,9 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
// First, get the two buffers' addresses. Another checker will have already
// made sure they're not undefined.
DefinedOrUnknownSVal LV =
- cast<DefinedOrUnknownSVal>(state->getSVal(Left, LCtx));
+ state->getSVal(Left, LCtx).castAs<DefinedOrUnknownSVal>();
DefinedOrUnknownSVal RV =
- cast<DefinedOrUnknownSVal>(state->getSVal(Right, LCtx));
+ state->getSVal(Right, LCtx).castAs<DefinedOrUnknownSVal>();
// See if they are the same.
DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV);
@@ -1163,19 +1161,17 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
const Expr *maxlenExpr = CE->getArg(1);
SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
- NonLoc *strLengthNL = dyn_cast<NonLoc>(&strLength);
- NonLoc *maxlenValNL = dyn_cast<NonLoc>(&maxlenVal);
+ Optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>();
+ Optional<NonLoc> maxlenValNL = maxlenVal.getAs<NonLoc>();
if (strLengthNL && maxlenValNL) {
ProgramStateRef stateStringTooLong, stateStringNotTooLong;
// Check if the strLength is greater than the maxlen.
llvm::tie(stateStringTooLong, stateStringNotTooLong) =
- state->assume(cast<DefinedOrUnknownSVal>
- (C.getSValBuilder().evalBinOpNN(state, BO_GT,
- *strLengthNL,
- *maxlenValNL,
- cmpTy)));
+ state->assume(C.getSValBuilder().evalBinOpNN(
+ state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy)
+ .castAs<DefinedOrUnknownSVal>());
if (stateStringTooLong && !stateStringNotTooLong) {
// If the string is longer than maxlen, return maxlen.
@@ -1192,28 +1188,24 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
// All we know is the return value is the min of the string length
// and the limit. This is better than nothing.
result = C.getSValBuilder().conjureSymbolVal(0, CE, LCtx, C.blockCount());
- NonLoc *resultNL = cast<NonLoc>(&result);
+ NonLoc resultNL = result.castAs<NonLoc>();
if (strLengthNL) {
- state = state->assume(cast<DefinedOrUnknownSVal>
- (C.getSValBuilder().evalBinOpNN(state, BO_LE,
- *resultNL,
- *strLengthNL,
- cmpTy)), true);
+ state = state->assume(C.getSValBuilder().evalBinOpNN(
+ state, BO_LE, resultNL, *strLengthNL, cmpTy)
+ .castAs<DefinedOrUnknownSVal>(), true);
}
if (maxlenValNL) {
- state = state->assume(cast<DefinedOrUnknownSVal>
- (C.getSValBuilder().evalBinOpNN(state, BO_LE,
- *resultNL,
- *maxlenValNL,
- cmpTy)), true);
+ state = state->assume(C.getSValBuilder().evalBinOpNN(
+ state, BO_LE, resultNL, *maxlenValNL, cmpTy)
+ .castAs<DefinedOrUnknownSVal>(), true);
}
}
} else {
// This is a plain strlen(), not strnlen().
- result = cast<DefinedOrUnknownSVal>(strLength);
+ result = strLength.castAs<DefinedOrUnknownSVal>();
// If we don't know the length of the string, conjure a return
// value, so it can be used in constraints, at least.
@@ -1332,8 +1324,8 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// Protect against misdeclared strncpy().
lenVal = svalBuilder.evalCast(lenVal, sizeTy, lenExpr->getType());
- NonLoc *strLengthNL = dyn_cast<NonLoc>(&strLength);
- NonLoc *lenValNL = dyn_cast<NonLoc>(&lenVal);
+ Optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>();
+ Optional<NonLoc> lenValNL = lenVal.getAs<NonLoc>();
// If we know both values, we might be able to figure out how much
// we're copying.
@@ -1343,10 +1335,9 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// Check if the max number to copy is less than the length of the src.
// If the bound is equal to the source length, strncpy won't null-
// terminate the result!
- llvm::tie(stateSourceTooLong, stateSourceNotTooLong) =
- state->assume(cast<DefinedOrUnknownSVal>
- (svalBuilder.evalBinOpNN(state, BO_GE, *strLengthNL,
- *lenValNL, cmpTy)));
+ llvm::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume(
+ svalBuilder.evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy)
+ .castAs<DefinedOrUnknownSVal>());
if (stateSourceTooLong && !stateSourceNotTooLong) {
// Max number to copy is less than the length of the src, so the actual
@@ -1373,7 +1364,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
if (dstStrLength.isUndef())
return;
- if (NonLoc *dstStrLengthNL = dyn_cast<NonLoc>(&dstStrLength)) {
+ if (Optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>()) {
maxLastElementIndex = svalBuilder.evalBinOpNN(state, BO_Add,
*lenValNL,
*dstStrLengthNL,
@@ -1404,7 +1395,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// Otherwise, go ahead and figure out the last element we'll touch.
// We don't record the non-zero assumption here because we can't
// be sure. We won't warn on a possible zero.
- NonLoc one = cast<NonLoc>(svalBuilder.makeIntVal(1, sizeTy));
+ NonLoc one = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>();
maxLastElementIndex = svalBuilder.evalBinOpNN(state, BO_Sub, *lenValNL,
one, sizeTy);
boundWarning = "Size argument is greater than the length of the "
@@ -1422,15 +1413,15 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
amountCopied = getCStringLength(C, state, lenExpr, srcVal, true);
assert(!amountCopied.isUndef());
- if (NonLoc *amountCopiedNL = dyn_cast<NonLoc>(&amountCopied)) {
+ if (Optional<NonLoc> amountCopiedNL = amountCopied.getAs<NonLoc>()) {
if (lenValNL) {
// amountCopied <= lenVal
SVal copiedLessThanBound = svalBuilder.evalBinOpNN(state, BO_LE,
*amountCopiedNL,
*lenValNL,
cmpTy);
- state = state->assume(cast<DefinedOrUnknownSVal>(copiedLessThanBound),
- true);
+ state = state->assume(
+ copiedLessThanBound.castAs<DefinedOrUnknownSVal>(), true);
if (!state)
return;
}
@@ -1441,8 +1432,8 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
*amountCopiedNL,
*strLengthNL,
cmpTy);
- state = state->assume(cast<DefinedOrUnknownSVal>(copiedLessThanSrc),
- true);
+ state = state->assume(
+ copiedLessThanSrc.castAs<DefinedOrUnknownSVal>(), true);
if (!state)
return;
}
@@ -1472,8 +1463,8 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
if (dstStrLength.isUndef())
return;
- NonLoc *srcStrLengthNL = dyn_cast<NonLoc>(&amountCopied);
- NonLoc *dstStrLengthNL = dyn_cast<NonLoc>(&dstStrLength);
+ Optional<NonLoc> srcStrLengthNL = amountCopied.getAs<NonLoc>();
+ Optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>();
// If we know both string lengths, we might know the final string length.
if (srcStrLengthNL && dstStrLengthNL) {
@@ -1494,14 +1485,14 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
finalStrLength = getCStringLength(C, state, CE, DstVal, true);
assert(!finalStrLength.isUndef());
- if (NonLoc *finalStrLengthNL = dyn_cast<NonLoc>(&finalStrLength)) {
+ if (Optional<NonLoc> finalStrLengthNL = finalStrLength.getAs<NonLoc>()) {
if (srcStrLengthNL) {
// finalStrLength >= srcStrLength
SVal sourceInResult = svalBuilder.evalBinOpNN(state, BO_GE,
*finalStrLengthNL,
*srcStrLengthNL,
cmpTy);
- state = state->assume(cast<DefinedOrUnknownSVal>(sourceInResult),
+ state = state->assume(sourceInResult.castAs<DefinedOrUnknownSVal>(),
true);
if (!state)
return;
@@ -1513,8 +1504,8 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
*finalStrLengthNL,
*dstStrLengthNL,
cmpTy);
- state = state->assume(cast<DefinedOrUnknownSVal>(destInResult),
- true);
+ state =
+ state->assume(destInResult.castAs<DefinedOrUnknownSVal>(), true);
if (!state)
return;
}
@@ -1535,13 +1526,14 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// If the destination is a MemRegion, try to check for a buffer overflow and
// record the new string length.
- if (loc::MemRegionVal *dstRegVal = dyn_cast<loc::MemRegionVal>(&DstVal)) {
+ if (Optional<loc::MemRegionVal> dstRegVal =
+ DstVal.getAs<loc::MemRegionVal>()) {
QualType ptrTy = Dst->getType();
// If we have an exact value on a bounded copy, use that to check for
// overflows, rather than our estimate about how much is actually copied.
if (boundWarning) {
- if (NonLoc *maxLastNL = dyn_cast<NonLoc>(&maxLastElementIndex)) {
+ if (Optional<NonLoc> maxLastNL = maxLastElementIndex.getAs<NonLoc>()) {
SVal maxLastElement = svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal,
*maxLastNL, ptrTy);
state = CheckLocation(C, state, CE->getArg(2), maxLastElement,
@@ -1552,7 +1544,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
}
// Then, if the final length is known...
- if (NonLoc *knownStrLength = dyn_cast<NonLoc>(&finalStrLength)) {
+ if (Optional<NonLoc> knownStrLength = finalStrLength.getAs<NonLoc>()) {
SVal lastElement = svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal,
*knownStrLength, ptrTy);
@@ -1670,8 +1662,8 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
// If we know the two buffers are the same, we know the result is 0.
// First, get the two buffers' addresses. Another checker will have already
// made sure they're not undefined.
- DefinedOrUnknownSVal LV = cast<DefinedOrUnknownSVal>(s1Val);
- DefinedOrUnknownSVal RV = cast<DefinedOrUnknownSVal>(s2Val);
+ DefinedOrUnknownSVal LV = s1Val.castAs<DefinedOrUnknownSVal>();
+ DefinedOrUnknownSVal RV = s2Val.castAs<DefinedOrUnknownSVal>();
// See if they are the same.
SValBuilder &svalBuilder = C.getSValBuilder();
@@ -1856,8 +1848,8 @@ void CStringChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
SVal StrVal = state->getSVal(Init, C.getLocationContext());
assert(StrVal.isValid() && "Initializer string is unknown or undefined");
- DefinedOrUnknownSVal strLength
- = cast<DefinedOrUnknownSVal>(getCStringLength(C, state, Init, StrVal));
+ DefinedOrUnknownSVal strLength =
+ getCStringLength(C, state, Init, StrVal).castAs<DefinedOrUnknownSVal>();
state = state->set<CStringLength>(MR, strLength);
}
@@ -1872,7 +1864,7 @@ bool CStringChecker::wantsRegionChangeUpdate(ProgramStateRef state) const {
ProgramStateRef
CStringChecker::checkRegionChanges(ProgramStateRef state,
- const StoreManager::InvalidatedSymbols *,
+ const InvalidatedSymbols *,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
const CallEvent *Call) const {
diff --git a/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
index f1a3aac..3a57a56 100644
--- a/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp
@@ -13,14 +13,14 @@
//
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/Analysis/AnalysisContext.h"
#include "clang/AST/Expr.h"
#include "clang/AST/OperationKinds.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/Analysis/AnalysisContext.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TypeTraits.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "llvm/ADT/SmallString.h"
diff --git a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index 82bc136..4965d22 100644
--- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -13,14 +13,15 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/AST/ParentMap.h"
-#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -75,6 +76,8 @@ void CallAndMessageChecker::emitBadCall(BugType *BT, CheckerContext &C,
BugReport *R = new BugReport(*BT, BT->getName(), N);
if (BadE) {
R->addRange(BadE->getSourceRange());
+ if (BadE->isGLValue())
+ BadE = bugreporter::getDerefExpr(BadE);
bugreporter::trackNullOrUndefValue(N, BadE, *R);
}
C.emitReport(R);
@@ -130,9 +133,9 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
if (!checkUninitFields)
return false;
-
- if (const nonloc::LazyCompoundVal *LV =
- dyn_cast<nonloc::LazyCompoundVal>(&V)) {
+
+ if (Optional<nonloc::LazyCompoundVal> LV =
+ V.getAs<nonloc::LazyCompoundVal>()) {
class FindUninitializedField {
public:
@@ -233,7 +236,8 @@ void CallAndMessageChecker::checkPreStmt(const CallExpr *CE,
}
ProgramStateRef StNonNull, StNull;
- llvm::tie(StNonNull, StNull) = State->assume(cast<DefinedOrUnknownSVal>(L));
+ llvm::tie(StNonNull, StNull) =
+ State->assume(L.castAs<DefinedOrUnknownSVal>());
if (StNull && !StNonNull) {
if (!BT_call_null)
@@ -262,7 +266,8 @@ void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
}
ProgramStateRef StNonNull, StNull;
- llvm::tie(StNonNull, StNull) = State->assume(cast<DefinedOrUnknownSVal>(V));
+ llvm::tie(StNonNull, StNull) =
+ State->assume(V.castAs<DefinedOrUnknownSVal>());
if (StNull && !StNonNull) {
if (!BT_cxx_call_null)
@@ -341,7 +346,7 @@ void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
return;
} else {
// Bifurcate the state into nil and non-nil ones.
- DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
+ DefinedOrUnknownSVal receiverVal = recVal.castAs<DefinedOrUnknownSVal>();
ProgramStateRef state = C.getState();
ProgramStateRef notNilState, nilState;
@@ -361,17 +366,23 @@ void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
if (!BT_msg_ret)
BT_msg_ret.reset(
- new BuiltinBug("Receiver in message expression is "
- "'nil' and returns a garbage value"));
+ new BuiltinBug("Receiver in message expression is 'nil'"));
const ObjCMessageExpr *ME = msg.getOriginExpr();
+ QualType ResTy = msg.getResultType();
+
SmallString<200> buf;
llvm::raw_svector_ostream os(buf);
os << "The receiver of message '" << ME->getSelector().getAsString()
- << "' is nil and returns a value of type '";
- msg.getResultType().print(os, C.getLangOpts());
- os << "' that will be garbage";
+ << "' is nil";
+ if (ResTy->isReferenceType()) {
+ os << ", which results in forming a null reference";
+ } else {
+ os << " and returns a value of type '";
+ msg.getResultType().print(os, C.getLangOpts());
+ os << "' that will be garbage";
+ }
BugReport *report = new BugReport(*BT_msg_ret, os.str(), N);
report->addRange(ME->getReceiverRange());
@@ -392,6 +403,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
ProgramStateRef state,
const ObjCMethodCall &Msg) const {
ASTContext &Ctx = C.getASTContext();
+ static SimpleProgramPointTag Tag("CallAndMessageChecker : NilReceiver");
// Check the return type of the message expression. A message to nil will
// return different values depending on the return type and the architecture.
@@ -402,7 +414,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
if (CanRetTy->isStructureOrClassType()) {
// Structure returns are safe since the compiler zeroes them out.
SVal V = C.getSValBuilder().makeZeroVal(RetTy);
- C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V));
+ C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
return;
}
@@ -413,14 +425,15 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
- if (voidPtrSize < returnTypeSize &&
- !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) &&
- (Ctx.FloatTy == CanRetTy ||
- Ctx.DoubleTy == CanRetTy ||
- Ctx.LongDoubleTy == CanRetTy ||
- Ctx.LongLongTy == CanRetTy ||
- Ctx.UnsignedLongLongTy == CanRetTy))) {
- if (ExplodedNode *N = C.generateSink(state))
+ if (CanRetTy.getTypePtr()->isReferenceType()||
+ (voidPtrSize < returnTypeSize &&
+ !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) &&
+ (Ctx.FloatTy == CanRetTy ||
+ Ctx.DoubleTy == CanRetTy ||
+ Ctx.LongDoubleTy == CanRetTy ||
+ Ctx.LongLongTy == CanRetTy ||
+ Ctx.UnsignedLongLongTy == CanRetTy)))) {
+ if (ExplodedNode *N = C.generateSink(state, 0 , &Tag))
emitNilReceiverBug(C, Msg, N);
return;
}
@@ -439,7 +452,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
// of this case unless we have *a lot* more knowledge.
//
SVal V = C.getSValBuilder().makeZeroVal(RetTy);
- C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V));
+ C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
return;
}
diff --git a/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp b/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
index 1cb8a8d..5e6e1054 100644
--- a/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
@@ -12,11 +12,11 @@
//
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/CharUnits.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/AST/CharUnits.h"
using namespace clang;
using namespace ento;
diff --git a/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp b/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
index d6d0e3c..60348c7 100644
--- a/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp
@@ -14,10 +14,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
using namespace clang;
using namespace ento;
diff --git a/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
index 9087205..3f9b3cc 100644
--- a/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
@@ -14,14 +14,15 @@
//===----------------------------------------------------------------------===//
#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/Attr.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprObjC.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
diff --git a/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp b/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp
index 6df47b1..9cb1d2d 100644
--- a/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp
@@ -14,13 +14,12 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Type.h"
-#include "clang/AST/ASTContext.h"
-
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
index 5cd6194..7ef13ab 100644
--- a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
@@ -12,11 +12,11 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/Analysis/AnalysisContext.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/Analysis/AnalysisContext.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
@@ -36,13 +36,6 @@ static bool isArc4RandomAvailable(const ASTContext &Ctx) {
}
namespace {
-struct DefaultBool {
- bool val;
- DefaultBool() : val(false) {}
- operator bool() const { return val; }
- DefaultBool &operator=(bool b) { val = b; return *this; }
-};
-
struct ChecksFilter {
DefaultBool check_gets;
DefaultBool check_getpw;
diff --git a/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp b/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp
index cc7fd37..f2c5050 100644
--- a/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp
@@ -14,8 +14,8 @@
#include "ClangSACheckers.h"
#include "clang/AST/StmtVisitor.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
using namespace clang;
diff --git a/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp b/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
index efaec2b..a9dd19a 100644
--- a/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
+++ b/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp
@@ -13,10 +13,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
using namespace clang;
@@ -44,13 +44,15 @@ class CheckerDocumentation : public Checker< check::PreStmt<ReturnStmt>,
check::Location,
check::Bind,
check::DeadSymbols,
- check::EndPath,
+ check::EndFunction,
check::EndAnalysis,
check::EndOfTranslationUnit,
eval::Call,
eval::Assume,
check::LiveSymbols,
check::RegionChanges,
+ check::PointerEscape,
+ check::ConstPointerEscape,
check::Event<ImplicitNullDerefEvent>,
check::ASTDecl<FunctionDecl> > {
public:
@@ -152,11 +154,11 @@ public:
/// check::DeadSymbols
void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const {}
- /// \brief Called when the analyzer core reaches the end of the top-level
+ /// \brief Called when the analyzer core reaches the end of a
/// function being analyzed.
///
- /// check::EndPath
- void checkEndPath(CheckerContext &Ctx) const {}
+ /// check::EndFunction
+ void checkEndFunction(CheckerContext &Ctx) const {}
/// \brief Called after all the paths in the ExplodedGraph reach end of path
/// - the symbolic execution graph is fully explored.
@@ -246,13 +248,44 @@ public:
/// check::RegionChanges
ProgramStateRef
checkRegionChanges(ProgramStateRef State,
- const StoreManager::InvalidatedSymbols *Invalidated,
+ const InvalidatedSymbols *Invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
const CallEvent *Call) const {
return State;
}
+ /// \brief Called when pointers escape.
+ ///
+ /// This notifies the checkers about pointer escape, which occurs whenever
+ /// the analyzer cannot track the symbol any more. For example, as a
+ /// result of assigning a pointer into a global or when it's passed to a
+ /// function call the analyzer cannot model.
+ ///
+ /// \param State The state at the point of escape.
+ /// \param Escaped The list of escaped symbols.
+ /// \param Call The corresponding CallEvent, if the symbols escape as
+ /// parameters to the given call.
+ /// \param Kind How the symbols have escaped.
+ /// \returns Checkers can modify the state by returning a new state.
+ ProgramStateRef checkPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind) const {
+ return State;
+ }
+
+ /// \brief Called when const pointers escape.
+ ///
+ /// Note: in most cases checkPointerEscape callback is sufficient.
+ /// \sa checkPointerEscape
+ ProgramStateRef checkConstPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind) const {
+ return State;
+ }
+
/// check::Event<ImplicitNullDerefEvent>
void checkEvent(ImplicitNullDerefEvent Event) const {}
diff --git a/lib/StaticAnalyzer/Checkers/Checkers.td b/lib/StaticAnalyzer/Checkers/Checkers.td
index 235e633..3db3fb9 100644
--- a/lib/StaticAnalyzer/Checkers/Checkers.td
+++ b/lib/StaticAnalyzer/Checkers/Checkers.td
@@ -60,9 +60,9 @@ 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 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">;
+def NonNullParamChecker : Checker<"NonNullParamChecker">,
+ HelpText<"Check for null pointers passed as arguments to a function whose arguments are references or marked with the 'nonnull' attribute">,
+ DescFile<"NonNullParamChecker.cpp">;
def VLASizeChecker : Checker<"VLASize">,
HelpText<"Check for declarations of VLA of undefined or zero size">,
@@ -166,12 +166,19 @@ def ReturnUndefChecker : Checker<"UndefReturn">,
// C++ checkers.
//===----------------------------------------------------------------------===//
+let ParentPackage = Cplusplus in {
+} // end: "cplusplus"
+
let ParentPackage = CplusplusAlpha in {
def VirtualCallChecker : Checker<"VirtualCall">,
HelpText<"Check virtual function calls during construction or destruction">,
DescFile<"VirtualCallChecker.cpp">;
+def NewDeleteChecker : Checker<"NewDelete">,
+ HelpText<"Check for memory leaks, double free, and use-after-free problems. Traces memory managed by new/delete.">,
+ DescFile<"MallocChecker.cpp">;
+
} // end: "alpha.cplusplus"
//===----------------------------------------------------------------------===//
@@ -276,12 +283,16 @@ def UnixAPIChecker : Checker<"API">,
DescFile<"UnixAPIChecker.cpp">;
def MallocPessimistic : Checker<"Malloc">,
- HelpText<"Check for memory leaks, double free, and use-after-free problems.">,
+ HelpText<"Check for memory leaks, double free, and use-after-free problems. Traces memory managed by malloc()/free().">,
DescFile<"MallocChecker.cpp">;
def MallocSizeofChecker : Checker<"MallocSizeof">,
HelpText<"Check for dubious malloc arguments involving sizeof">,
DescFile<"MallocSizeofChecker.cpp">;
+
+def MismatchedDeallocatorChecker : Checker<"MismatchedDeallocator">,
+ HelpText<"Check for mismatched deallocators.">,
+ DescFile<"MallocChecker.cpp">;
} // end "unix"
@@ -292,7 +303,7 @@ def ChrootChecker : Checker<"Chroot">,
DescFile<"ChrootChecker.cpp">;
def MallocOptimistic : Checker<"MallocWithAnnotations">,
- HelpText<"Check for memory leaks, double free, and use-after-free problems. Assumes that all user-defined functions which might free a pointer are annotated.">,
+ HelpText<"Check for memory leaks, double free, and use-after-free problems. Traces memory managed by malloc()/free(). Assumes that all user-defined functions which might free a pointer are annotated.">,
DescFile<"MallocChecker.cpp">;
def PthreadLockChecker : Checker<"PthreadLock">,
@@ -343,7 +354,7 @@ let ParentPackage = OSX in {
def MacOSXAPIChecker : Checker<"API">,
InPackage<OSX>,
- HelpText<"Check for proper uses of various Mac OS X APIs">,
+ HelpText<"Check for proper uses of various Apple APIs">,
DescFile<"MacOSXAPIChecker.cpp">;
def MacOSKeychainAPIChecker : Checker<"SecKeychainAPI">,
@@ -351,7 +362,7 @@ def MacOSKeychainAPIChecker : Checker<"SecKeychainAPI">,
HelpText<"Check for proper uses of Secure Keychain APIs">,
DescFile<"MacOSKeychainAPIChecker.cpp">;
-} // end "macosx"
+} // end "osx"
let ParentPackage = Cocoa in {
@@ -412,12 +423,20 @@ def ObjCDeallocChecker : Checker<"Dealloc">,
HelpText<"Warn about Objective-C classes that lack a correct implementation of -dealloc">,
DescFile<"CheckObjCDealloc.cpp">;
-def IvarInvalidationChecker : Checker<"InstanceVariableInvalidation">,
+def InstanceVariableInvalidation : Checker<"InstanceVariableInvalidation">,
HelpText<"Check that the invalidatable instance variables are invalidated in the methods annotated with objc_instance_variable_invalidator">,
DescFile<"IvarInvalidationChecker.cpp">;
+def MissingInvalidationMethod : Checker<"MissingInvalidationMethod">,
+ HelpText<"Check that the invalidation methods are present in classes that contain invalidatable instance variables">,
+ 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">,
+ HelpText<"Check for direct assignments to instance variables">,
+ DescFile<"DirectIvarAssignment.cpp">;
+
+def DirectIvarAssignmentForAnnotatedFunctions : Checker<"DirectIvarAssignmentForAnnotatedFunctions">,
+ HelpText<"Check for direct assignments to instance variables in the methods annotated with objc_no_direct_instance_variable_assignment">,
DescFile<"DirectIvarAssignment.cpp">;
def ObjCSuperCallChecker : Checker<"MissingSuperCall">,
@@ -515,4 +534,3 @@ def ExprInspectionChecker : Checker<"ExprInspection">,
DescFile<"ExprInspectionChecker.cpp">;
} // end "debug"
-
diff --git a/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp b/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
index c885616..9912965 100644
--- a/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
@@ -12,10 +12,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
diff --git a/lib/StaticAnalyzer/Checkers/ClangSACheckers.h b/lib/StaticAnalyzer/Checkers/ClangSACheckers.h
index 230baa7..bea908d 100644
--- a/lib/StaticAnalyzer/Checkers/ClangSACheckers.h
+++ b/lib/StaticAnalyzer/Checkers/ClangSACheckers.h
@@ -12,11 +12,11 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Checkers/CommonBugCategories.h"
-
#ifndef LLVM_CLANG_SA_LIB_CHECKERS_CLANGSACHECKERS_H
#define LLVM_CLANG_SA_LIB_CHECKERS_CLANGSACHECKERS_H
+#include "clang/StaticAnalyzer/Checkers/CommonBugCategories.h"
+
namespace clang {
namespace ento {
diff --git a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
index 59e03ec..f2e3e6d 100644
--- a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
@@ -14,6 +14,7 @@
#include "ClangSACheckers.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
@@ -125,7 +126,7 @@ class DeadStoreObs : public LiveVariables::Observer {
llvm::SmallPtrSet<const VarDecl*, 20> Escaped;
OwningPtr<ReachableCode> reachableCode;
const CFGBlock *currentBlock;
- llvm::OwningPtr<llvm::DenseSet<const VarDecl *> > InEH;
+ OwningPtr<llvm::DenseSet<const VarDecl *> > InEH;
enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit };
@@ -418,6 +419,15 @@ class DeadStoresChecker : public Checker<check::ASTCodeBody> {
public:
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) const {
+
+ // Don't do anything for template instantiations.
+ // Proving that code in a template instantiation is "dead"
+ // means proving that it is dead in all instantiations.
+ // This same problem exists with -Wunreachable-code.
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ if (FD->isTemplateInstantiation())
+ return;
+
if (LiveVariables *L = mgr.getAnalysis<LiveVariables>(D)) {
CFG &cfg = *mgr.getCFG(D);
AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D);
diff --git a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
index 7ad9c59..29b4a63 100644
--- a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
+++ b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
@@ -12,11 +12,11 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
-#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/Analyses/Dominators.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/CallGraph.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "llvm/Support/Process.h"
using namespace clang;
diff --git a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
index 3ace4be..72d46c5 100644
--- a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
@@ -14,11 +14,12 @@
#include "ClangSACheckers.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -75,6 +76,14 @@ DereferenceChecker::AddDerefSource(raw_ostream &os,
Ranges.push_back(SourceRange(L, L));
break;
}
+ case Stmt::ObjCIvarRefExprClass: {
+ const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(Ex);
+ os << " (" << (loadedFrom ? "loaded from" : "via")
+ << " ivar '" << IV->getDecl()->getName() << "')";
+ SourceLocation L = IV->getLocation();
+ Ranges.push_back(SourceRange(L, L));
+ break;
+ }
}
}
@@ -156,7 +165,7 @@ void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S,
buf.empty() ? BT_null->getDescription() : buf.str(),
N);
- bugreporter::trackNullOrUndefValue(N, bugreporter::GetDerefExpr(N), *report);
+ bugreporter::trackNullOrUndefValue(N, bugreporter::getDerefExpr(S), *report);
for (SmallVectorImpl<SourceRange>::iterator
I = Ranges.begin(), E = Ranges.end(); I!=E; ++I)
@@ -175,17 +184,17 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
BugReport *report =
new BugReport(*BT_undef, BT_undef->getDescription(), N);
- bugreporter::trackNullOrUndefValue(N, bugreporter::GetDerefExpr(N),
+ bugreporter::trackNullOrUndefValue(N, bugreporter::getDerefExpr(S),
*report);
C.emitReport(report);
}
return;
}
- DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(l);
+ DefinedOrUnknownSVal location = l.castAs<DefinedOrUnknownSVal>();
// Check for null dereferences.
- if (!isa<Loc>(location))
+ if (!location.getAs<Loc>())
return;
ProgramStateRef state = C.getState();
@@ -230,7 +239,8 @@ void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S,
ProgramStateRef State = C.getState();
ProgramStateRef StNonNull, StNull;
- llvm::tie(StNonNull, StNull) = State->assume(cast<DefinedOrUnknownSVal>(V));
+ llvm::tie(StNonNull, StNull) =
+ State->assume(V.castAs<DefinedOrUnknownSVal>());
if (StNull) {
if (!StNonNull) {
diff --git a/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp b/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp
index dc90b67..6d3dd1e 100644
--- a/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp
+++ b/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp
@@ -7,18 +7,27 @@
//
//===----------------------------------------------------------------------===//
//
-// Check that Objective C properties follow the following rules:
-// - The property should be set with the setter, not though a direct
-// assignment.
+// Check that Objective C properties are set with the setter, not though a
+// direct assignment.
+//
+// Two versions of a checker exist: one that checks all methods and the other
+// that only checks the methods annotated with
+// __attribute__((annotate("objc_no_direct_instance_variable_assignment")))
+//
+// The checker does not warn about assignments to Ivars, annotated with
+// __attribute__((objc_allow_direct_instance_variable_assignment"))). This
+// annotation serves as a false positive suppression mechanism for the
+// checker. The annotation is allowed on properties and Ivars.
//
//===----------------------------------------------------------------------===//
#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/Attr.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "llvm/ADT/DenseMap.h"
using namespace clang;
@@ -26,6 +35,27 @@ using namespace ento;
namespace {
+/// The default method filter, which is used to filter out the methods on which
+/// the check should not be performed.
+///
+/// Checks for the init, dealloc, and any other functions that might be allowed
+/// to perform direct instance variable assignment based on their name.
+struct MethodFilter {
+ virtual ~MethodFilter() {}
+ virtual bool operator()(ObjCMethodDecl *M) {
+ if (M->getMethodFamily() == OMF_init ||
+ M->getMethodFamily() == OMF_dealloc ||
+ M->getMethodFamily() == OMF_copy ||
+ M->getMethodFamily() == OMF_mutableCopy ||
+ M->getSelector().getNameForSlot(0).find("init") != StringRef::npos ||
+ M->getSelector().getNameForSlot(0).find("Init") != StringRef::npos)
+ return true;
+ return false;
+ }
+};
+
+static MethodFilter DefaultMethodFilter;
+
class DirectIvarAssignment :
public Checker<check::ASTDecl<ObjCImplementationDecl> > {
@@ -59,6 +89,10 @@ class DirectIvarAssignment :
};
public:
+ MethodFilter *ShouldSkipMethod;
+
+ DirectIvarAssignment() : ShouldSkipMethod(&DefaultMethodFilter) {}
+
void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& Mgr,
BugReporter &BR) const;
};
@@ -118,14 +152,7 @@ void DirectIvarAssignment::checkASTDecl(const ObjCImplementationDecl *D,
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)
+ if ((*ShouldSkipMethod)(M))
continue;
const Stmt *Body = M->getBody();
@@ -136,6 +163,18 @@ void DirectIvarAssignment::checkASTDecl(const ObjCImplementationDecl *D,
}
}
+static bool isAnnotatedToAllowDirectAssignment(const Decl *D) {
+ for (specific_attr_iterator<AnnotateAttr>
+ AI = D->specific_attr_begin<AnnotateAttr>(),
+ AE = D->specific_attr_end<AnnotateAttr>(); AI != AE; ++AI) {
+ const AnnotateAttr *Ann = *AI;
+ if (Ann->getAnnotation() ==
+ "objc_allow_direct_instance_variable_assignment")
+ return true;
+ }
+ return false;
+}
+
void DirectIvarAssignment::MethodCrawler::VisitBinaryOperator(
const BinaryOperator *BO) {
if (!BO->isAssignmentOp())
@@ -149,8 +188,16 @@ void DirectIvarAssignment::MethodCrawler::VisitBinaryOperator(
if (const ObjCIvarDecl *D = IvarRef->getDecl()) {
IvarToPropertyMapTy::const_iterator I = IvarToPropMap.find(D);
+
if (I != IvarToPropMap.end()) {
const ObjCPropertyDecl *PD = I->second;
+ // Skip warnings on Ivars, annotated with
+ // objc_allow_direct_instance_variable_assignment. This annotation serves
+ // as a false positive suppression mechanism for the checker. The
+ // annotation is allowed on properties and ivars.
+ if (isAnnotatedToAllowDirectAssignment(PD) ||
+ isAnnotatedToAllowDirectAssignment(D))
+ return;
ObjCMethodDecl *GetterMethod =
InterfD->getInstanceMethod(PD->getGetterName());
@@ -175,6 +222,33 @@ void DirectIvarAssignment::MethodCrawler::VisitBinaryOperator(
}
}
+// Register the checker that checks for direct accesses in all functions,
+// except for the initialization and copy routines.
void ento::registerDirectIvarAssignment(CheckerManager &mgr) {
mgr.registerChecker<DirectIvarAssignment>();
}
+
+// Register the checker that checks for direct accesses in functions annotated
+// with __attribute__((annotate("objc_no_direct_instance_variable_assignment"))).
+namespace {
+struct InvalidatorMethodFilter : MethodFilter {
+ virtual ~InvalidatorMethodFilter() {}
+ virtual bool operator()(ObjCMethodDecl *M) {
+ for (specific_attr_iterator<AnnotateAttr>
+ AI = M->specific_attr_begin<AnnotateAttr>(),
+ AE = M->specific_attr_end<AnnotateAttr>(); AI != AE; ++AI) {
+ const AnnotateAttr *Ann = *AI;
+ if (Ann->getAnnotation() == "objc_no_direct_instance_variable_assignment")
+ return false;
+ }
+ return true;
+ }
+};
+
+InvalidatorMethodFilter AttrFilter;
+}
+
+void ento::registerDirectIvarAssignmentForAnnotatedFunctions(
+ CheckerManager &mgr) {
+ mgr.registerChecker<DirectIvarAssignment>()->ShouldSkipMethod = &AttrFilter;
+}
diff --git a/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
index 76fb3f2..93daf94 100644
--- a/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
@@ -13,10 +13,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
using namespace clang;
using namespace ento;
@@ -58,7 +58,7 @@ void DivZeroChecker::checkPreStmt(const BinaryOperator *B,
return;
SVal Denom = C.getState()->getSVal(B->getRHS(), C.getLocationContext());
- const DefinedSVal *DV = dyn_cast<DefinedSVal>(&Denom);
+ Optional<DefinedSVal> DV = Denom.getAs<DefinedSVal>();
// Divide-by-undefined handled in the generic checking for uses of
// undefined values.
diff --git a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
index b0a4bc6..9f176a4 100644
--- a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
+++ b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
@@ -12,13 +12,13 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/Basic/Builtins.h"
using namespace clang;
using namespace ento;
@@ -110,38 +110,40 @@ void DynamicTypePropagation::checkPostCall(const CallEvent &Call,
return;
ProgramStateRef State = C.getState();
-
- switch (Msg->getMethodFamily()) {
- default:
- break;
-
- // We assume that the type of the object returned by alloc and new are the
- // pointer to the object of the class specified in the receiver of the
- // message.
- case OMF_alloc:
- case OMF_new: {
- // Get the type of object that will get created.
- const ObjCMessageExpr *MsgE = Msg->getOriginExpr();
- const ObjCObjectType *ObjTy = getObjectTypeForAllocAndNew(MsgE, C);
- if (!ObjTy)
- return;
- QualType DynResTy =
+ const ObjCMethodDecl *D = Msg->getDecl();
+
+ if (D && D->hasRelatedResultType()) {
+ switch (Msg->getMethodFamily()) {
+ default:
+ break;
+
+ // We assume that the type of the object returned by alloc and new are the
+ // pointer to the object of the class specified in the receiver of the
+ // message.
+ case OMF_alloc:
+ case OMF_new: {
+ // Get the type of object that will get created.
+ const ObjCMessageExpr *MsgE = Msg->getOriginExpr();
+ const ObjCObjectType *ObjTy = getObjectTypeForAllocAndNew(MsgE, C);
+ if (!ObjTy)
+ return;
+ QualType DynResTy =
C.getASTContext().getObjCObjectPointerType(QualType(ObjTy, 0));
- C.addTransition(State->setDynamicTypeInfo(RetReg, DynResTy, false));
- break;
- }
- case OMF_init: {
- // Assume, the result of the init method has the same dynamic type as
- // the receiver and propagate the dynamic type info.
- const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion();
- if (!RecReg)
- return;
- DynamicTypeInfo RecDynType = State->getDynamicTypeInfo(RecReg);
- C.addTransition(State->setDynamicTypeInfo(RetReg, RecDynType));
- break;
- }
+ C.addTransition(State->setDynamicTypeInfo(RetReg, DynResTy, false));
+ break;
+ }
+ case OMF_init: {
+ // Assume, the result of the init method has the same dynamic type as
+ // the receiver and propagate the dynamic type info.
+ const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion();
+ if (!RecReg)
+ return;
+ DynamicTypeInfo RecDynType = State->getDynamicTypeInfo(RecReg);
+ C.addTransition(State->setDynamicTypeInfo(RetReg, RecDynType));
+ break;
+ }
+ }
}
-
return;
}
diff --git a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
index e7e3162..810473f 100644
--- a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
@@ -8,9 +8,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "llvm/ADT/StringSwitch.h"
using namespace clang;
using namespace ento;
@@ -64,7 +65,7 @@ static const char *getArgumentValueString(const CallExpr *CE,
ProgramStateRef StTrue, StFalse;
llvm::tie(StTrue, StFalse) =
- State->assume(cast<DefinedOrUnknownSVal>(AssertionVal));
+ State->assume(AssertionVal.castAs<DefinedOrUnknownSVal>());
if (StTrue) {
if (StFalse)
diff --git a/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp b/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
index 7fde689..085a991 100644
--- a/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
@@ -14,10 +14,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
using namespace clang;
using namespace ento;
diff --git a/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
index a9e0217..c67c597 100644
--- a/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
@@ -15,12 +15,13 @@
//
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/Attr.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/Basic/Builtins.h"
#include <climits>
using namespace clang;
@@ -102,7 +103,7 @@ private:
CheckerContext &C) const;
- typedef llvm::SmallVector<unsigned, 2> ArgVector;
+ typedef SmallVector<unsigned, 2> ArgVector;
/// \brief A struct used to specify taint propagation rules for a function.
///
@@ -430,7 +431,7 @@ SymbolRef GenericTaintChecker::getPointedToSymbol(CheckerContext &C,
if (AddrVal.isUnknownOrUndef())
return 0;
- Loc *AddrLoc = dyn_cast<Loc>(&AddrVal);
+ Optional<Loc> AddrLoc = AddrVal.getAs<Loc>();
if (!AddrLoc)
return 0;
diff --git a/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp b/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
index ffbbb8b..271ba47 100644
--- a/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp
@@ -43,23 +43,24 @@
// - Handling ~0 values
#include "ClangSACheckers.h"
-#include "clang/Analysis/CFGStmtMap.h"
-#include "clang/Analysis/Analyses/PseudoConstantAnalysis.h"
+#include "clang/AST/Stmt.h"
#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
+#include "clang/Analysis/Analyses/PseudoConstantAnalysis.h"
+#include "clang/Analysis/CFGStmtMap.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
-#include "clang/AST/Stmt.h"
+#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/BitVector.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -172,11 +173,11 @@ void IdempotentOperationChecker::checkPreStmt(const BinaryOperator *B,
case BO_ShrAssign:
case BO_Assign:
// Assign statements have one extra level of indirection
- if (!isa<Loc>(LHSVal)) {
+ if (!LHSVal.getAs<Loc>()) {
A = Impossible;
return;
}
- LHSVal = state->getSVal(cast<Loc>(LHSVal), LHS->getType());
+ LHSVal = state->getSVal(LHSVal.castAs<Loc>(), LHS->getType());
}
@@ -331,9 +332,9 @@ void IdempotentOperationChecker::checkPostStmt(const BinaryOperator *B,
// Add the ExplodedNode we just visited
BinaryOperatorData &Data = hash[B];
- const Stmt *predStmt
- = cast<StmtPoint>(C.getPredecessor()->getLocation()).getStmt();
-
+ const Stmt *predStmt =
+ C.getPredecessor()->getLocation().castAs<StmtPoint>().getStmt();
+
// Ignore implicit calls to setters.
if (!isa<BinaryOperator>(predStmt))
return;
@@ -422,12 +423,12 @@ void IdempotentOperationChecker::checkEndAnalysis(ExplodedGraph &G,
if (LHSRelevant) {
const Expr *LHS = i->first->getLHS();
report->addRange(LHS->getSourceRange());
- FindLastStoreBRVisitor::registerStatementVarDecls(*report, LHS);
+ FindLastStoreBRVisitor::registerStatementVarDecls(*report, LHS, false);
}
if (RHSRelevant) {
const Expr *RHS = i->first->getRHS();
report->addRange(i->first->getRHS()->getSourceRange());
- FindLastStoreBRVisitor::registerStatementVarDecls(*report, RHS);
+ FindLastStoreBRVisitor::registerStatementVarDecls(*report, RHS, false);
}
BR.emitReport(report);
@@ -581,16 +582,13 @@ IdempotentOperationChecker::pathWasCompletelyAnalyzed(AnalysisDeclContext *AC,
virtual bool visit(const WorkListUnit &U) {
ProgramPoint P = U.getNode()->getLocation();
const CFGBlock *B = 0;
- if (StmtPoint *SP = dyn_cast<StmtPoint>(&P)) {
+ if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) {
B = CBM->getBlock(SP->getStmt());
- }
- else if (BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
+ } else if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
B = BE->getDst();
- }
- else if (BlockEntrance *BEnt = dyn_cast<BlockEntrance>(&P)) {
+ } else if (Optional<BlockEntrance> BEnt = P.getAs<BlockEntrance>()) {
B = BEnt->getBlock();
- }
- else if (BlockExit *BExit = dyn_cast<BlockExit>(&P)) {
+ } else if (Optional<BlockExit> BExit = P.getAs<BlockExit>()) {
B = BExit->getBlock();
}
if (!B)
diff --git a/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
index bf256cd..5ed28e9 100644
--- a/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
@@ -20,25 +20,40 @@
// been called on them. An invalidation method should either invalidate all
// the ivars or call another invalidation method (on self).
//
+// Partial invalidor annotation allows to addess cases when ivars are
+// invalidated by other methods, which might or might not be called from
+// the invalidation method. The checker checks that each invalidation
+// method and all the partial methods cumulatively invalidate all ivars.
+// __attribute__((annotate("objc_instance_variable_invalidator_partial")));
+//
//===----------------------------------------------------------------------===//
#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/Attr.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallString.h"
using namespace clang;
using namespace ento;
namespace {
-class IvarInvalidationChecker :
- public Checker<check::ASTDecl<ObjCMethodDecl> > {
- typedef llvm::DenseSet<const ObjCMethodDecl*> MethodSet;
+struct ChecksFilter {
+ /// Check for missing invalidation method declarations.
+ DefaultBool check_MissingInvalidationMethod;
+ /// Check that all ivars are invalidated.
+ DefaultBool check_InstanceVariableInvalidation;
+};
+
+class IvarInvalidationCheckerImpl {
+
+ typedef llvm::SmallSetVector<const ObjCMethodDecl*, 2> MethodSet;
typedef llvm::DenseMap<const ObjCMethodDecl*,
const ObjCIvarDecl*> MethToIvarMapTy;
typedef llvm::DenseMap<const ObjCPropertyDecl*,
@@ -47,14 +62,14 @@ class IvarInvalidationChecker :
const ObjCPropertyDecl*> IvarToPropMapTy;
- struct IvarInfo {
+ struct InvalidationInfo {
/// Has the ivar been invalidated?
bool IsInvalidated;
/// The methods which can be used to invalidate the ivar.
MethodSet InvalidationMethods;
- IvarInfo() : IsInvalidated(false) {}
+ InvalidationInfo() : IsInvalidated(false) {}
void addInvalidationMethod(const ObjCMethodDecl *MD) {
InvalidationMethods.insert(MD);
}
@@ -63,11 +78,7 @@ class IvarInvalidationChecker :
return !InvalidationMethods.empty();
}
- void markInvalidated() {
- IsInvalidated = true;
- }
-
- bool markInvalidated(const ObjCMethodDecl *MD) {
+ bool hasMethod(const ObjCMethodDecl *MD) {
if (IsInvalidated)
return true;
for (MethodSet::iterator I = InvalidationMethods.begin(),
@@ -79,13 +90,9 @@ class IvarInvalidationChecker :
}
return false;
}
-
- bool isInvalidated() const {
- return IsInvalidated;
- }
};
- typedef llvm::DenseMap<const ObjCIvarDecl*, IvarInfo> IvarSet;
+ typedef llvm::DenseMap<const ObjCIvarDecl*, InvalidationInfo> IvarSet;
/// Statement visitor, which walks the method body and flags the ivars
/// referenced in it (either directly or via property).
@@ -168,12 +175,16 @@ class IvarInvalidationChecker :
/// Check if the any of the methods inside the interface are annotated with
/// the invalidation annotation, update the IvarInfo accordingly.
+ /// \param LookForPartial is set when we are searching for partial
+ /// invalidators.
static void containsInvalidationMethod(const ObjCContainerDecl *D,
- IvarInfo &Out);
+ InvalidationInfo &Out,
+ bool LookForPartial);
/// 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);
+ static bool trackIvar(const ObjCIvarDecl *Iv, IvarSet &TrackedIvars,
+ const ObjCIvarDecl **FirstIvarDecl);
/// Given the property declaration, and the list of tracked ivars, finds
/// the ivar backing the property when possible. Returns '0' when no such
@@ -181,54 +192,90 @@ class IvarInvalidationChecker :
static const ObjCIvarDecl *findPropertyBackingIvar(
const ObjCPropertyDecl *Prop,
const ObjCInterfaceDecl *InterfaceD,
- IvarSet &TrackedIvars);
+ IvarSet &TrackedIvars,
+ const ObjCIvarDecl **FirstIvarDecl);
+
+ /// Print ivar name or the property if the given ivar backs a property.
+ static void printIvar(llvm::raw_svector_ostream &os,
+ const ObjCIvarDecl *IvarDecl,
+ const IvarToPropMapTy &IvarToPopertyMap);
+
+ void reportNoInvalidationMethod(const ObjCIvarDecl *FirstIvarDecl,
+ const IvarToPropMapTy &IvarToPopertyMap,
+ const ObjCInterfaceDecl *InterfaceD,
+ bool MissingDeclaration) const;
+ void reportIvarNeedsInvalidation(const ObjCIvarDecl *IvarD,
+ const IvarToPropMapTy &IvarToPopertyMap,
+ const ObjCMethodDecl *MethodD) const;
+
+ AnalysisManager& Mgr;
+ BugReporter &BR;
+ /// Filter on the checks performed.
+ const ChecksFilter &Filter;
public:
- void checkASTDecl(const ObjCMethodDecl *D, AnalysisManager& Mgr,
- BugReporter &BR) const;
+ IvarInvalidationCheckerImpl(AnalysisManager& InMgr,
+ BugReporter &InBR,
+ const ChecksFilter &InFilter) :
+ Mgr (InMgr), BR(InBR), Filter(InFilter) {}
- // TODO: We are currently ignoring the ivars coming from class extensions.
+ void visit(const ObjCImplementationDecl *D) const;
};
-static bool isInvalidationMethod(const ObjCMethodDecl *M) {
+static bool isInvalidationMethod(const ObjCMethodDecl *M, bool LookForPartial) {
for (specific_attr_iterator<AnnotateAttr>
AI = M->specific_attr_begin<AnnotateAttr>(),
AE = M->specific_attr_end<AnnotateAttr>(); AI != AE; ++AI) {
const AnnotateAttr *Ann = *AI;
- if (Ann->getAnnotation() == "objc_instance_variable_invalidator")
+ if (!LookForPartial &&
+ Ann->getAnnotation() == "objc_instance_variable_invalidator")
+ return true;
+ if (LookForPartial &&
+ Ann->getAnnotation() == "objc_instance_variable_invalidator_partial")
return true;
}
return false;
}
-void IvarInvalidationChecker::containsInvalidationMethod(
- const ObjCContainerDecl *D, IvarInfo &OutInfo) {
-
- // TODO: Cache the results.
+void IvarInvalidationCheckerImpl::containsInvalidationMethod(
+ const ObjCContainerDecl *D, InvalidationInfo &OutInfo, bool Partial) {
if (!D)
return;
+ assert(!isa<ObjCImplementationDecl>(D));
+ // TODO: Cache the results.
+
// 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))
+ if (isInvalidationMethod(MDI, Partial))
OutInfo.addInvalidationMethod(
cast<ObjCMethodDecl>(MDI->getCanonicalDecl()));
}
// If interface, check all parent protocols and super.
- // TODO: Visit all categories in case the invalidation method is declared in
- // a category.
- if (const ObjCInterfaceDecl *InterfaceD = dyn_cast<ObjCInterfaceDecl>(D)) {
+ if (const ObjCInterfaceDecl *InterfD = dyn_cast<ObjCInterfaceDecl>(D)) {
+
+ // Visit all protocols.
for (ObjCInterfaceDecl::protocol_iterator
- I = InterfaceD->protocol_begin(),
- E = InterfaceD->protocol_end(); I != E; ++I) {
- containsInvalidationMethod(*I, OutInfo);
+ I = InterfD->protocol_begin(),
+ E = InterfD->protocol_end(); I != E; ++I) {
+ containsInvalidationMethod((*I)->getDefinition(), OutInfo, Partial);
+ }
+
+ // Visit all categories in case the invalidation method is declared in
+ // a category.
+ for (ObjCInterfaceDecl::visible_extensions_iterator
+ Ext = InterfD->visible_extensions_begin(),
+ ExtEnd = InterfD->visible_extensions_end();
+ Ext != ExtEnd; ++Ext) {
+ containsInvalidationMethod(*Ext, OutInfo, Partial);
}
- containsInvalidationMethod(InterfaceD->getSuperClass(), OutInfo);
+
+ containsInvalidationMethod(InterfD->getSuperClass(), OutInfo, Partial);
return;
}
@@ -237,45 +284,52 @@ void IvarInvalidationChecker::containsInvalidationMethod(
for (ObjCInterfaceDecl::protocol_iterator
I = ProtD->protocol_begin(),
E = ProtD->protocol_end(); I != E; ++I) {
- containsInvalidationMethod(*I, OutInfo);
+ containsInvalidationMethod((*I)->getDefinition(), OutInfo, Partial);
}
return;
}
- llvm_unreachable("One of the casts above should have succeeded.");
+ return;
}
-bool IvarInvalidationChecker::trackIvar(const ObjCIvarDecl *Iv,
- IvarSet &TrackedIvars) {
+bool IvarInvalidationCheckerImpl::trackIvar(const ObjCIvarDecl *Iv,
+ IvarSet &TrackedIvars,
+ const ObjCIvarDecl **FirstIvarDecl) {
QualType IvQTy = Iv->getType();
const ObjCObjectPointerType *IvTy = IvQTy->getAs<ObjCObjectPointerType>();
if (!IvTy)
return false;
const ObjCInterfaceDecl *IvInterf = IvTy->getInterfaceDecl();
- IvarInfo Info;
- containsInvalidationMethod(IvInterf, Info);
+ InvalidationInfo Info;
+ containsInvalidationMethod(IvInterf, Info, /*LookForPartial*/ false);
if (Info.needsInvalidation()) {
- TrackedIvars[cast<ObjCIvarDecl>(Iv->getCanonicalDecl())] = Info;
+ const ObjCIvarDecl *I = cast<ObjCIvarDecl>(Iv->getCanonicalDecl());
+ TrackedIvars[I] = Info;
+ if (!*FirstIvarDecl)
+ *FirstIvarDecl = I;
return true;
}
return false;
}
-const ObjCIvarDecl *IvarInvalidationChecker::findPropertyBackingIvar(
+const ObjCIvarDecl *IvarInvalidationCheckerImpl::findPropertyBackingIvar(
const ObjCPropertyDecl *Prop,
const ObjCInterfaceDecl *InterfaceD,
- IvarSet &TrackedIvars) {
+ IvarSet &TrackedIvars,
+ const ObjCIvarDecl **FirstIvarDecl) {
const ObjCIvarDecl *IvarD = 0;
// Lookup for the synthesized case.
IvarD = Prop->getPropertyIvarDecl();
- if (IvarD) {
+ // We only track the ivars/properties that are defined in the current
+ // class (not the parent).
+ if (IvarD && IvarD->getContainingInterface() == InterfaceD) {
if (TrackedIvars.count(IvarD)) {
return IvarD;
}
// If the ivar is synthesized we still want to track it.
- if (trackIvar(IvarD, TrackedIvars))
+ if (trackIvar(IvarD, TrackedIvars, FirstIvarDecl))
return IvarD;
}
@@ -304,22 +358,35 @@ const ObjCIvarDecl *IvarInvalidationChecker::findPropertyBackingIvar(
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;
+void IvarInvalidationCheckerImpl::printIvar(llvm::raw_svector_ostream &os,
+ const ObjCIvarDecl *IvarDecl,
+ const IvarToPropMapTy &IvarToPopertyMap) {
+ if (IvarDecl->getSynthesize()) {
+ const ObjCPropertyDecl *PD = IvarToPopertyMap.lookup(IvarDecl);
+ assert(PD &&"Do we synthesize ivars for something other than properties?");
+ os << "Property "<< PD->getName() << " ";
+ } else {
+ os << "Instance variable "<< IvarDecl->getName() << " ";
+ }
+}
+// Check that the invalidatable interfaces with ivars/properties implement the
+// invalidation methods.
+void IvarInvalidationCheckerImpl::
+visit(const ObjCImplementationDecl *ImplD) const {
// Collect all ivars that need cleanup.
IvarSet Ivars;
- const ObjCInterfaceDecl *InterfaceD = D->getClassInterface();
+ // Record the first Ivar needing invalidation; used in reporting when only
+ // one ivar is sufficient. Cannot grab the first on the Ivars set to ensure
+ // deterministic output.
+ const ObjCIvarDecl *FirstIvarDecl = 0;
+ const ObjCInterfaceDecl *InterfaceD = ImplD->getClassInterface();
// Collect ivars declared in this class, its extensions and its implementation
ObjCInterfaceDecl *IDecl = const_cast<ObjCInterfaceDecl *>(InterfaceD);
for (const ObjCIvarDecl *Iv = IDecl->all_declared_ivar_begin(); Iv;
Iv= Iv->getNextIvar())
- trackIvar(Iv, Ivars);
+ trackIvar(Iv, Ivars, &FirstIvarDecl);
// Construct Property/Property Accessor to Ivar maps to assist checking if an
// ivar which is backing a property has been reset.
@@ -329,16 +396,17 @@ void IvarInvalidationChecker::checkASTDecl(const ObjCMethodDecl *D,
IvarToPropMapTy IvarToPopertyMap;
ObjCInterfaceDecl::PropertyMap PropMap;
- InterfaceD->collectPropertiesToImplement(PropMap);
+ ObjCInterfaceDecl::PropertyDeclOrder PropOrder;
+ InterfaceD->collectPropertiesToImplement(PropMap, PropOrder);
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) {
+ const ObjCIvarDecl *ID = findPropertyBackingIvar(PD, InterfaceD, Ivars,
+ &FirstIvarDecl);
+ if (!ID)
continue;
- }
// Store the mappings.
PD = cast<ObjCPropertyDecl>(PD->getCanonicalDecl());
@@ -359,66 +427,159 @@ void IvarInvalidationChecker::checkASTDecl(const ObjCMethodDecl *D,
}
}
+ // If no ivars need invalidation, there is nothing to check here.
+ if (Ivars.empty())
+ return;
+
+ // Find all partial invalidation methods.
+ InvalidationInfo PartialInfo;
+ containsInvalidationMethod(InterfaceD, PartialInfo, /*LookForPartial*/ true);
+
+ // Remove ivars invalidated by the partial invalidation methods. They do not
+ // need to be invalidated in the regular invalidation methods.
+ for (MethodSet::iterator
+ I = PartialInfo.InvalidationMethods.begin(),
+ E = PartialInfo.InvalidationMethods.end(); I != E; ++I) {
+ const ObjCMethodDecl *InterfD = *I;
+
+ // Get the corresponding method in the @implementation.
+ const ObjCMethodDecl *D = ImplD->getMethod(InterfD->getSelector(),
+ InterfD->isInstanceMethod());
+ if (D && D->hasBody()) {
+ bool CalledAnotherInvalidationMethod = false;
+ // The MethodCrowler is going to remove the invalidated ivars.
+ MethodCrawler(Ivars,
+ CalledAnotherInvalidationMethod,
+ PropSetterToIvarMap,
+ PropGetterToIvarMap,
+ PropertyToIvarMap,
+ BR.getContext()).VisitStmt(D->getBody());
+ // If another invalidation method was called, trust that full invalidation
+ // has occurred.
+ if (CalledAnotherInvalidationMethod)
+ Ivars.clear();
+ }
+ }
- // 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 all ivars have been invalidated by partial invalidators, there is
+ // nothing to check here.
+ if (Ivars.empty())
+ return;
- if (CalledAnotherInvalidationMethod)
+ // Find all invalidation methods in this @interface declaration and parents.
+ InvalidationInfo Info;
+ containsInvalidationMethod(InterfaceD, Info, /*LookForPartial*/ false);
+
+ // Report an error in case none of the invalidation methods are declared.
+ if (!Info.needsInvalidation()) {
+ if (Filter.check_MissingInvalidationMethod)
+ reportNoInvalidationMethod(FirstIvarDecl, IvarToPopertyMap, InterfaceD,
+ /*MissingDeclaration*/ true);
+ // If there are no invalidation methods, there is no ivar validation work
+ // to be done.
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";
- }
+ // Only check if Ivars are invalidated when InstanceVariableInvalidation
+ // has been requested.
+ if (!Filter.check_InstanceVariableInvalidation)
+ return;
- BR.EmitBasicReport(D,
- "Incomplete invalidation",
- categories::CoreFoundationObjectiveC, os.str(),
- IvarDecLocation);
+ // Check that all ivars are invalidated by the invalidation methods.
+ bool AtImplementationContainsAtLeastOneInvalidationMethod = false;
+ for (MethodSet::iterator I = Info.InvalidationMethods.begin(),
+ E = Info.InvalidationMethods.end(); I != E; ++I) {
+ const ObjCMethodDecl *InterfD = *I;
+
+ // Get the corresponding method in the @implementation.
+ const ObjCMethodDecl *D = ImplD->getMethod(InterfD->getSelector(),
+ InterfD->isInstanceMethod());
+ if (D && D->hasBody()) {
+ AtImplementationContainsAtLeastOneInvalidationMethod = true;
+
+ // Get a copy of ivars needing invalidation.
+ IvarSet IvarsI = Ivars;
+
+ bool CalledAnotherInvalidationMethod = false;
+ MethodCrawler(IvarsI,
+ CalledAnotherInvalidationMethod,
+ PropSetterToIvarMap,
+ PropGetterToIvarMap,
+ PropertyToIvarMap,
+ BR.getContext()).VisitStmt(D->getBody());
+ // If another invalidation method was called, trust that full invalidation
+ // has occurred.
+ if (CalledAnotherInvalidationMethod)
+ continue;
+
+ // Warn on the ivars that were not invalidated by the method.
+ for (IvarSet::const_iterator
+ I = IvarsI.begin(), E = IvarsI.end(); I != E; ++I)
+ reportIvarNeedsInvalidation(I->first, IvarToPopertyMap, D);
}
}
+
+ // Report an error in case none of the invalidation methods are implemented.
+ if (!AtImplementationContainsAtLeastOneInvalidationMethod)
+ reportNoInvalidationMethod(FirstIvarDecl, IvarToPopertyMap, InterfaceD,
+ /*MissingDeclaration*/ false);
}
-void IvarInvalidationChecker::MethodCrawler::markInvalidated(
+void IvarInvalidationCheckerImpl::
+reportNoInvalidationMethod(const ObjCIvarDecl *FirstIvarDecl,
+ const IvarToPropMapTy &IvarToPopertyMap,
+ const ObjCInterfaceDecl *InterfaceD,
+ bool MissingDeclaration) const {
+ SmallString<128> sbuf;
+ llvm::raw_svector_ostream os(sbuf);
+ assert(FirstIvarDecl);
+ printIvar(os, FirstIvarDecl, IvarToPopertyMap);
+ os << "needs to be invalidated; ";
+ if (MissingDeclaration)
+ os << "no invalidation method is declared for ";
+ else
+ os << "no invalidation method is defined in the @implementation for ";
+ os << InterfaceD->getName();
+
+ PathDiagnosticLocation IvarDecLocation =
+ PathDiagnosticLocation::createBegin(FirstIvarDecl, BR.getSourceManager());
+
+ BR.EmitBasicReport(FirstIvarDecl, "Incomplete invalidation",
+ categories::CoreFoundationObjectiveC, os.str(),
+ IvarDecLocation);
+}
+
+void IvarInvalidationCheckerImpl::
+reportIvarNeedsInvalidation(const ObjCIvarDecl *IvarD,
+ const IvarToPropMapTy &IvarToPopertyMap,
+ const ObjCMethodDecl *MethodD) const {
+ SmallString<128> sbuf;
+ llvm::raw_svector_ostream os(sbuf);
+ printIvar(os, IvarD, IvarToPopertyMap);
+ os << "needs to be invalidated or set to nil";
+ PathDiagnosticLocation MethodDecLocation =
+ PathDiagnosticLocation::createEnd(MethodD->getBody(),
+ BR.getSourceManager(),
+ Mgr.getAnalysisDeclContext(MethodD));
+ BR.EmitBasicReport(MethodD, "Incomplete invalidation",
+ categories::CoreFoundationObjectiveC, os.str(),
+ MethodDecLocation);
+}
+
+void IvarInvalidationCheckerImpl::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();
+ if (!InvalidationMethod ||
+ (InvalidationMethod && I->second.hasMethod(InvalidationMethod)))
+ IVars.erase(I);
}
}
-const Expr *IvarInvalidationChecker::MethodCrawler::peel(const Expr *E) const {
+const Expr *IvarInvalidationCheckerImpl::MethodCrawler::peel(const Expr *E) const {
E = E->IgnoreParenCasts();
if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E))
E = POE->getSyntacticForm()->IgnoreParenCasts();
@@ -427,13 +588,13 @@ const Expr *IvarInvalidationChecker::MethodCrawler::peel(const Expr *E) const {
return E;
}
-void IvarInvalidationChecker::MethodCrawler::checkObjCIvarRefExpr(
+void IvarInvalidationCheckerImpl::MethodCrawler::checkObjCIvarRefExpr(
const ObjCIvarRefExpr *IvarRef) {
if (const Decl *D = IvarRef->getDecl())
markInvalidated(cast<ObjCIvarDecl>(D->getCanonicalDecl()));
}
-void IvarInvalidationChecker::MethodCrawler::checkObjCMessageExpr(
+void IvarInvalidationCheckerImpl::MethodCrawler::checkObjCMessageExpr(
const ObjCMessageExpr *ME) {
const ObjCMethodDecl *MD = ME->getMethodDecl();
if (MD) {
@@ -444,7 +605,7 @@ void IvarInvalidationChecker::MethodCrawler::checkObjCMessageExpr(
}
}
-void IvarInvalidationChecker::MethodCrawler::checkObjCPropertyRefExpr(
+void IvarInvalidationCheckerImpl::MethodCrawler::checkObjCPropertyRefExpr(
const ObjCPropertyRefExpr *PA) {
if (PA->isExplicitProperty()) {
@@ -470,14 +631,14 @@ void IvarInvalidationChecker::MethodCrawler::checkObjCPropertyRefExpr(
}
}
-bool IvarInvalidationChecker::MethodCrawler::isZero(const Expr *E) const {
+bool IvarInvalidationCheckerImpl::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) {
+void IvarInvalidationCheckerImpl::MethodCrawler::check(const Expr *E) {
E = peel(E);
if (const ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) {
@@ -496,28 +657,36 @@ void IvarInvalidationChecker::MethodCrawler::check(const Expr *E) {
}
}
-void IvarInvalidationChecker::MethodCrawler::VisitBinaryOperator(
+void IvarInvalidationCheckerImpl::MethodCrawler::VisitBinaryOperator(
const BinaryOperator *BO) {
VisitStmt(BO);
- if (BO->getOpcode() != BO_Assign)
+ // Do we assign/compare against zero? If yes, check the variable we are
+ // assigning to.
+ BinaryOperatorKind Opcode = BO->getOpcode();
+ if (Opcode != BO_Assign &&
+ Opcode != BO_EQ &&
+ Opcode != BO_NE)
return;
- // Do we assign zero?
- if (!isZero(BO->getRHS()))
- return;
+ if (isZero(BO->getRHS())) {
+ check(BO->getLHS());
+ return;
+ }
- // Check the variable we are assigning to.
- check(BO->getLHS());
+ if (Opcode != BO_Assign && isZero(BO->getLHS())) {
+ check(BO->getRHS());
+ return;
+ }
}
-void IvarInvalidationChecker::MethodCrawler::VisitObjCMessageExpr(
- const ObjCMessageExpr *ME) {
+void IvarInvalidationCheckerImpl::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 && isInvalidationMethod(MD, /*LookForPartial*/ false))
if (Receiver->isObjCSelfExpr()) {
CalledAnotherInvalidationMethod = true;
return;
@@ -544,7 +713,27 @@ void IvarInvalidationChecker::MethodCrawler::VisitObjCMessageExpr(
}
}
-// Register the checker.
-void ento::registerIvarInvalidationChecker(CheckerManager &mgr) {
- mgr.registerChecker<IvarInvalidationChecker>();
+// Register the checkers.
+namespace {
+
+class IvarInvalidationChecker :
+ public Checker<check::ASTDecl<ObjCImplementationDecl> > {
+public:
+ ChecksFilter Filter;
+public:
+ void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& Mgr,
+ BugReporter &BR) const {
+ IvarInvalidationCheckerImpl Walker(Mgr, BR, Filter);
+ Walker.visit(D);
+ }
+};
+}
+
+#define REGISTER_CHECKER(name) \
+void ento::register##name(CheckerManager &mgr) {\
+ mgr.registerChecker<IvarInvalidationChecker>()->Filter.check_##name = true;\
}
+
+REGISTER_CHECKER(InstanceVariableInvalidation)
+REGISTER_CHECKER(MissingInvalidationMethod)
+
diff --git a/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp b/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
index 757a4ce..02a7cc3 100644
--- a/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp
@@ -13,11 +13,12 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
diff --git a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
index 76f20b6..f1f06c7 100644
--- a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
@@ -13,22 +13,21 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
namespace {
class MacOSKeychainAPIChecker : public Checker<check::PreStmt<CallExpr>,
- check::PreStmt<ReturnStmt>,
check::PostStmt<CallExpr>,
- check::EndPath,
check::DeadSymbols> {
mutable OwningPtr<BugType> BT;
@@ -56,14 +55,12 @@ public:
};
void checkPreStmt(const CallExpr *S, CheckerContext &C) const;
- void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
void checkPostStmt(const CallExpr *S, CheckerContext &C) const;
void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
- void checkEndPath(CheckerContext &C) const;
private:
typedef std::pair<SymbolRef, const AllocationState*> AllocationPair;
- typedef llvm::SmallVector<AllocationPair, 2> AllocationPairVec;
+ typedef SmallVector<AllocationPair, 2> AllocationPairVec;
enum APIKind {
/// Denotes functions tracked by this checker.
@@ -94,7 +91,8 @@ private:
inline void initBugType() const {
if (!BT)
- BT.reset(new BugType("Improper use of SecKeychain API", "Mac OS API"));
+ BT.reset(new BugType("Improper use of SecKeychain API",
+ "API Misuse (Apple)"));
}
void generateDeallocatorMismatchReport(const AllocationPair &AP,
@@ -102,8 +100,8 @@ private:
CheckerContext &C) const;
/// Find the allocation site for Sym on the path leading to the node N.
- const Stmt *getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
- CheckerContext &C) const;
+ const ExplodedNode *getAllocationNode(const ExplodedNode *N, SymbolRef Sym,
+ CheckerContext &C) const;
BugReport *generateAllocatedDataNotReleasedReport(const AllocationPair &AP,
ExplodedNode *N,
@@ -220,7 +218,7 @@ static SymbolRef getAsPointeeSymbol(const Expr *Expr,
ProgramStateRef State = C.getState();
SVal ArgV = State->getSVal(Expr, C.getLocationContext());
- if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(&ArgV)) {
+ if (Optional<loc::MemRegionVal> X = ArgV.getAs<loc::MemRegionVal>()) {
StoreManager& SM = C.getStoreManager();
SymbolRef sym = SM.getBinding(State->getStore(), *X).getAsLocSymbol();
if (sym)
@@ -396,16 +394,18 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
return;
}
// If kCFAllocatorNull, which does not deallocate, we still have to
- // find the deallocator. Otherwise, assume that the user had written a
- // custom deallocator which does the right thing.
- if (DE->getFoundDecl()->getName() != "kCFAllocatorNull") {
- State = State->remove<AllocatedData>(ArgSM);
- C.addTransition(State);
+ // find the deallocator.
+ if (DE->getFoundDecl()->getName() == "kCFAllocatorNull")
return;
- }
}
+ // In all other cases, assume the user supplied a correct deallocator
+ // that will free memory so stop tracking.
+ State = State->remove<AllocatedData>(ArgSM);
+ C.addTransition(State);
+ return;
}
- return;
+
+ llvm_unreachable("We know of no other possible APIs.");
}
// The call is deallocating a value we previously allocated, so remove it
@@ -422,7 +422,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
// If the buffer can be null and the return status can be an error,
// report a bad call to free.
- if (State->assume(cast<DefinedSVal>(ArgSVal), false) &&
+ if (State->assume(ArgSVal.castAs<DefinedSVal>(), false) &&
!definitelyDidnotReturnError(AS->Region, State, C.getSValBuilder())) {
ExplodedNode *N = C.addTransition(State);
if (!N)
@@ -486,31 +486,9 @@ void MacOSKeychainAPIChecker::checkPostStmt(const CallExpr *CE,
}
}
-void MacOSKeychainAPIChecker::checkPreStmt(const ReturnStmt *S,
- CheckerContext &C) const {
- const Expr *retExpr = S->getRetValue();
- if (!retExpr)
- return;
-
- // If inside inlined call, skip it.
- const LocationContext *LC = C.getLocationContext();
- if (LC->getParent() != 0)
- return;
-
- // Check if the value is escaping through the return.
- ProgramStateRef state = C.getState();
- SymbolRef sym = state->getSVal(retExpr, LC).getAsLocSymbol();
- if (!sym)
- return;
- state = state->remove<AllocatedData>(sym);
-
- // Proceed from the new state.
- C.addTransition(state);
-}
-
// TODO: This logic is the same as in Malloc checker.
-const Stmt *
-MacOSKeychainAPIChecker::getAllocationSite(const ExplodedNode *N,
+const ExplodedNode *
+MacOSKeychainAPIChecker::getAllocationNode(const ExplodedNode *N,
SymbolRef Sym,
CheckerContext &C) const {
const LocationContext *LeakContext = N->getLocationContext();
@@ -528,12 +506,7 @@ MacOSKeychainAPIChecker::getAllocationSite(const ExplodedNode *N,
N = N->pred_empty() ? NULL : *(N->pred_begin());
}
- ProgramPoint P = AllocNode->getLocation();
- if (CallExitEnd *Exit = dyn_cast<CallExitEnd>(&P))
- return Exit->getCalleeContext()->getCallSite();
- if (clang::PostStmt *PS = dyn_cast<clang::PostStmt>(&P))
- return PS->getStmt();
- return 0;
+ return AllocNode;
}
BugReport *MacOSKeychainAPIChecker::
@@ -551,11 +524,22 @@ BugReport *MacOSKeychainAPIChecker::
// With leaks, we want to unique them by the location where they were
// allocated, and only report a single path.
PathDiagnosticLocation LocUsedForUniqueing;
- if (const Stmt *AllocStmt = getAllocationSite(N, AP.first, C))
+ const ExplodedNode *AllocNode = getAllocationNode(N, AP.first, C);
+ const Stmt *AllocStmt = 0;
+ ProgramPoint P = AllocNode->getLocation();
+ if (Optional<CallExitEnd> Exit = P.getAs<CallExitEnd>())
+ AllocStmt = Exit->getCalleeContext()->getCallSite();
+ else if (Optional<clang::PostStmt> PS = P.getAs<clang::PostStmt>())
+ AllocStmt = PS->getStmt();
+
+ if (AllocStmt)
LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocStmt,
- C.getSourceManager(), N->getLocationContext());
+ C.getSourceManager(),
+ AllocNode->getLocationContext());
+
+ BugReport *Report = new BugReport(*BT, os.str(), N, LocUsedForUniqueing,
+ AllocNode->getLocationContext()->getDecl());
- BugReport *Report = new BugReport(*BT, os.str(), N, LocUsedForUniqueing);
Report->addVisitor(new SecKeychainBugVisitor(AP.first));
markInteresting(Report, AP);
return Report;
@@ -604,55 +588,6 @@ void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR,
C.addTransition(State, N);
}
-// TODO: Remove this after we ensure that checkDeadSymbols are always called.
-void MacOSKeychainAPIChecker::checkEndPath(CheckerContext &C) const {
- ProgramStateRef state = C.getState();
-
- // If inside inlined call, skip it.
- if (C.getLocationContext()->getParent() != 0)
- return;
-
- AllocatedDataTy AS = state->get<AllocatedData>();
- if (AS.isEmpty())
- return;
-
- // Anything which has been allocated but not freed (nor escaped) will be
- // found here, so report it.
- bool Changed = false;
- AllocationPairVec Errors;
- for (AllocatedDataTy::iterator I = AS.begin(), E = AS.end(); I != E; ++I ) {
- Changed = true;
- state = state->remove<AllocatedData>(I->first);
- // If the allocated symbol is null or if error code was returned at
- // allocation, do not report.
- 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));
- }
-
- // If no change, do not generate a new state.
- if (!Changed) {
- C.addTransition(state);
- return;
- }
-
- static SimpleProgramPointTag Tag("MacOSKeychainAPIChecker : EndPathLeak");
- ExplodedNode *N = C.addTransition(C.getState(), C.getPredecessor(), &Tag);
-
- // Generate the error reports.
- for (AllocationPairVec::iterator I = Errors.begin(), E = Errors.end();
- I != E; ++I) {
- C.emitReport(generateAllocatedDataNotReleasedReport(*I, N, C));
- }
-
- C.addTransition(state, N);
-}
-
PathDiagnosticPiece *MacOSKeychainAPIChecker::SecKeychainBugVisitor::VisitNode(
const ExplodedNode *N,
@@ -668,8 +603,8 @@ PathDiagnosticPiece *MacOSKeychainAPIChecker::SecKeychainBugVisitor::VisitNode(
// (!ASPrev && AS) ~ We started tracking symbol in node N, it must be the
// allocation site.
- const CallExpr *CE = cast<CallExpr>(cast<StmtPoint>(N->getLocation())
- .getStmt());
+ const CallExpr *CE =
+ cast<CallExpr>(N->getLocation().castAs<StmtPoint>().getStmt());
const FunctionDecl *funDecl = CE->getDirectCallee();
assert(funDecl && "We do not support indirect function calls as of now.");
StringRef funName = funDecl->getName();
diff --git a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
index 467b8b1..32ebb51 100644
--- a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
//
// This defines MacOSXAPIChecker, which is an assortment of checks on calls
-// to various, widely used Mac OS X functions.
+// to various, widely used Apple APIs.
//
// FIXME: What's currently in BasicObjCFoundationChecks.cpp should be migrated
// to here, using the new Checker interface.
@@ -16,12 +16,12 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
-#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/raw_ostream.h"
@@ -68,7 +68,7 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
if (!BT_dispatchOnce)
BT_dispatchOnce.reset(new BugType("Improper use of 'dispatch_once'",
- "Mac OS X API"));
+ "API Misuse (Apple)"));
// 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.
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index caf70ca..4b0e766 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -14,18 +14,19 @@
#include "ClangSACheckers.h"
#include "InterCheckerAPI.h"
+#include "clang/AST/Attr.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
-#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/ImmutableMap.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include <climits>
@@ -34,6 +35,14 @@ using namespace ento;
namespace {
+// Used to check correspondence between allocators and deallocators.
+enum AllocationFamily {
+ AF_None,
+ AF_Malloc,
+ AF_CXXNew,
+ AF_CXXNewArray
+};
+
class RefState {
enum Kind { // Reference to allocated memory.
Allocated,
@@ -41,33 +50,55 @@ class RefState {
Released,
// The responsibility for freeing resources has transfered from
// this reference. A relinquished symbol should not be freed.
- Relinquished } K;
+ Relinquished };
+
const Stmt *S;
+ unsigned K : 2; // Kind enum, but stored as a bitfield.
+ unsigned Family : 30; // Rest of 32-bit word, currently just an allocation
+ // family.
+ RefState(Kind k, const Stmt *s, unsigned family)
+ : S(s), K(k), Family(family) {}
public:
- RefState(Kind k, const Stmt *s) : K(k), S(s) {}
-
bool isAllocated() const { return K == Allocated; }
bool isReleased() const { return K == Released; }
bool isRelinquished() const { return K == Relinquished; }
-
+ AllocationFamily getAllocationFamily() const {
+ return (AllocationFamily)Family;
+ }
const Stmt *getStmt() const { return S; }
bool operator==(const RefState &X) const {
- return K == X.K && S == X.S;
+ return K == X.K && S == X.S && Family == X.Family;
}
- static RefState getAllocated(const Stmt *s) {
- return RefState(Allocated, s);
+ static RefState getAllocated(unsigned family, const Stmt *s) {
+ return RefState(Allocated, s, family);
+ }
+ static RefState getReleased(unsigned family, const Stmt *s) {
+ return RefState(Released, s, family);
}
- static RefState getReleased(const Stmt *s) { return RefState(Released, s); }
- static RefState getRelinquished(const Stmt *s) {
- return RefState(Relinquished, s);
+ static RefState getRelinquished(unsigned family, const Stmt *s) {
+ return RefState(Relinquished, s, family);
}
void Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddInteger(K);
ID.AddPointer(S);
+ ID.AddInteger(Family);
+ }
+
+ void dump(raw_ostream &OS) const {
+ static const char *Table[] = {
+ "Allocated",
+ "Released",
+ "Relinquished"
+ };
+ OS << Table[(unsigned) K];
+ }
+
+ LLVM_ATTRIBUTE_USED void dump() const {
+ dump(llvm::errs());
}
};
@@ -99,24 +130,27 @@ struct ReallocPair {
}
};
-typedef std::pair<const Stmt*, const MemRegion*> LeakInfo;
+typedef std::pair<const ExplodedNode*, const MemRegion*> LeakInfo;
class MallocChecker : public Checker<check::DeadSymbols,
- check::EndPath,
+ check::PointerEscape,
+ check::ConstPointerEscape,
check::PreStmt<ReturnStmt>,
check::PreStmt<CallExpr>,
check::PostStmt<CallExpr>,
+ check::PostStmt<CXXNewExpr>,
+ check::PreStmt<CXXDeleteExpr>,
check::PostStmt<BlockExpr>,
check::PostObjCMessage,
check::Location,
- check::Bind,
- eval::Assume,
- check::RegionChanges>
+ eval::Assume>
{
mutable OwningPtr<BugType> BT_DoubleFree;
mutable OwningPtr<BugType> BT_Leak;
mutable OwningPtr<BugType> BT_UseFree;
mutable OwningPtr<BugType> BT_BadFree;
+ mutable OwningPtr<BugType> BT_MismatchedDealloc;
+ mutable OwningPtr<BugType> BT_OffsetFree;
mutable IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc,
*II_valloc, *II_reallocf, *II_strndup, *II_strdup;
@@ -129,32 +163,33 @@ public:
struct ChecksFilter {
DefaultBool CMallocPessimistic;
DefaultBool CMallocOptimistic;
+ DefaultBool CNewDeleteChecker;
+ DefaultBool CMismatchedDeallocatorChecker;
};
ChecksFilter Filter;
void checkPreStmt(const CallExpr *S, CheckerContext &C) const;
void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
+ void checkPostStmt(const CXXNewExpr *NE, CheckerContext &C) const;
+ void checkPreStmt(const CXXDeleteExpr *DE, 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;
void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond,
bool Assumption) const;
void checkLocation(SVal l, bool isLoad, const Stmt *S,
CheckerContext &C) const;
- void checkBind(SVal location, SVal val, const Stmt*S,
- CheckerContext &C) const;
- ProgramStateRef
- checkRegionChanges(ProgramStateRef state,
- const StoreManager::InvalidatedSymbols *invalidated,
- ArrayRef<const MemRegion *> ExplicitRegions,
- ArrayRef<const MemRegion *> Regions,
- const CallEvent *Call) const;
- bool wantsRegionChangeUpdate(ProgramStateRef state) const {
- return true;
- }
+
+ ProgramStateRef checkPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind) const;
+ ProgramStateRef checkConstPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind) const;
void printState(raw_ostream &Out, ProgramStateRef State,
const char *NL, const char *Sep) const;
@@ -162,31 +197,52 @@ public:
private:
void initIdentifierInfo(ASTContext &C) const;
+ /// \brief Determine family of a deallocation expression.
+ AllocationFamily getAllocationFamily(CheckerContext &C, const Stmt *S) const;
+
+ /// \brief Print names of allocators and deallocators.
+ ///
+ /// \returns true on success.
+ bool printAllocDeallocName(raw_ostream &os, CheckerContext &C,
+ const Expr *E) const;
+
+ /// \brief Print expected name of an allocator based on the deallocator's
+ /// family derived from the DeallocExpr.
+ void printExpectedAllocName(raw_ostream &os, CheckerContext &C,
+ const Expr *DeallocExpr) const;
+ /// \brief Print expected name of a deallocator based on the allocator's
+ /// family.
+ void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family) const;
+
+ ///@{
/// Check if this is one of the functions which can allocate/reallocate memory
/// pointed to by one of its arguments.
bool isMemFunction(const FunctionDecl *FD, ASTContext &C) const;
bool isFreeFunction(const FunctionDecl *FD, ASTContext &C) const;
bool isAllocationFunction(const FunctionDecl *FD, ASTContext &C) const;
-
+ bool isStandardNewDelete(const FunctionDecl *FD, ASTContext &C) const;
+ ///@}
static ProgramStateRef MallocMemReturnsAttr(CheckerContext &C,
const CallExpr *CE,
const OwnershipAttr* Att);
static ProgramStateRef MallocMemAux(CheckerContext &C, const CallExpr *CE,
const Expr *SizeEx, SVal Init,
- ProgramStateRef state) {
+ ProgramStateRef State,
+ AllocationFamily Family = AF_Malloc) {
return MallocMemAux(C, CE,
- state->getSVal(SizeEx, C.getLocationContext()),
- Init, state);
+ State->getSVal(SizeEx, C.getLocationContext()),
+ Init, State, Family);
}
static ProgramStateRef MallocMemAux(CheckerContext &C, const CallExpr *CE,
SVal SizeEx, SVal Init,
- ProgramStateRef state);
+ ProgramStateRef State,
+ AllocationFamily Family = AF_Malloc);
/// Update the RefState to reflect the new memory allocation.
- static ProgramStateRef MallocUpdateRefState(CheckerContext &C,
- const CallExpr *CE,
- ProgramStateRef state);
+ static ProgramStateRef
+ MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State,
+ AllocationFamily Family = AF_Malloc);
ProgramStateRef FreeMemAttr(CheckerContext &C, const CallExpr *CE,
const OwnershipAttr* Att) const;
@@ -209,17 +265,43 @@ private:
///\brief Check if the memory associated with this symbol was released.
bool isReleased(SymbolRef Sym, CheckerContext &C) const;
- bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C,
- const Stmt *S = 0) const;
-
- /// Check if the function is not known to us. So, for example, we could
- /// conservatively assume it can free/reallocate it's pointer arguments.
- bool doesNotFreeMemory(const CallEvent *Call,
- ProgramStateRef State) const;
+ bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const;
+
+ /// Check if the function is known not to free memory, or if it is
+ /// "interesting" and should be modeled explicitly.
+ ///
+ /// We assume that pointers do not escape through calls to system functions
+ /// not handled by this checker.
+ bool doesNotFreeMemOrInteresting(const CallEvent *Call,
+ ProgramStateRef State) const;
+
+ // Implementation of the checkPointerEscape callabcks.
+ ProgramStateRef checkPointerEscapeAux(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind,
+ bool(*CheckRefState)(const RefState*)) const;
+
+ // Used to suppress warnings if they are not related to the tracked family
+ // (derived from AllocDeallocStmt).
+ bool isTrackedFamily(AllocationFamily Family) const;
+ bool isTrackedFamily(CheckerContext &C, const Stmt *AllocDeallocStmt) const;
+ bool isTrackedFamily(CheckerContext &C, SymbolRef Sym) const;
static bool SummarizeValue(raw_ostream &os, SVal V);
static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR);
- void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange range) const;
+ void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange Range,
+ const Expr *DeallocExpr) const;
+ void ReportMismatchedDealloc(CheckerContext &C, SourceRange Range,
+ const Expr *DeallocExpr,
+ const RefState *RS) const;
+ void ReportOffsetFree(CheckerContext &C, SVal ArgVal, SourceRange Range,
+ const Expr *DeallocExpr,
+ const Expr *AllocExpr = 0) const;
+ void ReportUseAfterFree(CheckerContext &C, SourceRange Range,
+ SymbolRef Sym) const;
+ void ReportDoubleFree(CheckerContext &C, SourceRange Range, bool Released,
+ SymbolRef Sym, SymbolRef PrevSym) const;
/// Find the location of the allocation for Sym on the path leading to the
/// exploded node N.
@@ -264,14 +346,14 @@ private:
inline bool isAllocated(const RefState *S, const RefState *SPrev,
const Stmt *Stmt) {
// Did not track -> allocated. Other state (released) -> allocated.
- return (Stmt && isa<CallExpr>(Stmt) &&
+ return (Stmt && (isa<CallExpr>(Stmt) || isa<CXXNewExpr>(Stmt)) &&
(S && S->isAllocated()) && (!SPrev || !SPrev->isAllocated()));
}
inline bool isReleased(const RefState *S, const RefState *SPrev,
const Stmt *Stmt) {
// Did not track -> released. Other state (allocated) -> released.
- return (Stmt && isa<CallExpr>(Stmt) &&
+ return (Stmt && (isa<CallExpr>(Stmt) || isa<CXXDeleteExpr>(Stmt)) &&
(S && S->isReleased()) && (!SPrev || !SPrev->isReleased()));
}
@@ -381,6 +463,9 @@ bool MallocChecker::isMemFunction(const FunctionDecl *FD, ASTContext &C) const {
if (isAllocationFunction(FD, C))
return true;
+ if (isStandardNewDelete(FD, C))
+ return true;
+
return false;
}
@@ -432,6 +517,39 @@ bool MallocChecker::isFreeFunction(const FunctionDecl *FD, ASTContext &C) const
return false;
}
+// Tells if the callee is one of the following:
+// 1) A global non-placement new/delete operator function.
+// 2) A global placement operator function with the single placement argument
+// of type std::nothrow_t.
+bool MallocChecker::isStandardNewDelete(const FunctionDecl *FD,
+ ASTContext &C) const {
+ if (!FD)
+ return false;
+
+ OverloadedOperatorKind Kind = FD->getOverloadedOperator();
+ if (Kind != OO_New && Kind != OO_Array_New &&
+ Kind != OO_Delete && Kind != OO_Array_Delete)
+ return false;
+
+ // Skip all operator new/delete methods.
+ if (isa<CXXMethodDecl>(FD))
+ return false;
+
+ // Return true if tested operator is a standard placement nothrow operator.
+ if (FD->getNumParams() == 2) {
+ QualType T = FD->getParamDecl(1)->getType();
+ if (const IdentifierInfo *II = T.getBaseTypeIdentifier())
+ return II->getName().equals("nothrow_t");
+ }
+
+ // Skip placement operators.
+ if (FD->getNumParams() != 1 || FD->isVariadic())
+ return false;
+
+ // One of the standard new/new[]/delete/delete[] non-placement operators.
+ return true;
+}
+
void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
if (C.wasInlined)
return;
@@ -464,9 +582,26 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
} else if (FunI == II_strndup) {
State = MallocUpdateRefState(C, CE, State);
}
+ else if (isStandardNewDelete(FD, C.getASTContext())) {
+ // Process direct calls to operator new/new[]/delete/delete[] functions
+ // as distinct from new/new[]/delete/delete[] expressions that are
+ // processed by the checkPostStmt callbacks for CXXNewExpr and
+ // CXXDeleteExpr.
+ OverloadedOperatorKind K = FD->getOverloadedOperator();
+ if (K == OO_New)
+ State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State,
+ AF_CXXNew);
+ else if (K == OO_Array_New)
+ State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State,
+ AF_CXXNewArray);
+ else if (K == OO_Delete || K == OO_Array_Delete)
+ State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory);
+ else
+ llvm_unreachable("not a new/delete operator");
+ }
}
- if (Filter.CMallocOptimistic) {
+ if (Filter.CMallocOptimistic || Filter.CMismatchedDeallocatorChecker) {
// Check all the attributes, if there are any.
// There can be multiple of these attributes.
if (FD->hasAttrs())
@@ -488,37 +623,91 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
C.addTransition(State);
}
-static bool isFreeWhenDoneSetToZero(const ObjCMethodCall &Call) {
+void MallocChecker::checkPostStmt(const CXXNewExpr *NE,
+ CheckerContext &C) const {
+
+ if (NE->getNumPlacementArgs())
+ for (CXXNewExpr::const_arg_iterator I = NE->placement_arg_begin(),
+ E = NE->placement_arg_end(); I != E; ++I)
+ if (SymbolRef Sym = C.getSVal(*I).getAsSymbol())
+ checkUseAfterFree(Sym, C, *I);
+
+ if (!isStandardNewDelete(NE->getOperatorNew(), C.getASTContext()))
+ return;
+
+ ProgramStateRef State = C.getState();
+ // The return value from operator new is bound to a specified initialization
+ // value (if any) and we don't want to loose this value. So we call
+ // MallocUpdateRefState() instead of MallocMemAux() which breakes the
+ // existing binding.
+ State = MallocUpdateRefState(C, NE, State, NE->isArray() ? AF_CXXNewArray
+ : AF_CXXNew);
+ C.addTransition(State);
+}
+
+void MallocChecker::checkPreStmt(const CXXDeleteExpr *DE,
+ CheckerContext &C) const {
+
+ if (!Filter.CNewDeleteChecker)
+ if (SymbolRef Sym = C.getSVal(DE->getArgument()).getAsSymbol())
+ checkUseAfterFree(Sym, C, DE->getArgument());
+
+ if (!isStandardNewDelete(DE->getOperatorDelete(), C.getASTContext()))
+ return;
+
+ ProgramStateRef State = C.getState();
+ bool ReleasedAllocated;
+ State = FreeMemAux(C, DE->getArgument(), DE, State,
+ /*Hold*/false, ReleasedAllocated);
+
+ C.addTransition(State);
+}
+
+static bool isKnownDeallocObjCMethodName(const ObjCMethodCall &Call) {
+ // If the first selector piece is one of the names below, assume that the
+ // object takes ownership of the memory, promising to eventually deallocate it
+ // with free().
+ // Ex: [NSData dataWithBytesNoCopy:bytes length:10];
+ // (...unless a 'freeWhenDone' parameter is false, but that's checked later.)
+ StringRef FirstSlot = Call.getSelector().getNameForSlot(0);
+ if (FirstSlot == "dataWithBytesNoCopy" ||
+ FirstSlot == "initWithBytesNoCopy" ||
+ FirstSlot == "initWithCharactersNoCopy")
+ return true;
+
+ return false;
+}
+
+static Optional<bool> getFreeWhenDoneArg(const ObjCMethodCall &Call) {
Selector S = Call.getSelector();
+
+ // FIXME: We should not rely on fully-constrained symbols being folded.
for (unsigned i = 1; i < S.getNumArgs(); ++i)
if (S.getNameForSlot(i).equals("freeWhenDone"))
- if (Call.getArgSVal(i).isConstant(0))
- return true;
+ return !Call.getArgSVal(i).isZeroConstant();
- return false;
+ return None;
}
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;
- ProgramStateRef State = FreeMemAux(C, Call.getArgExpr(argIdx),
- Call.getOriginExpr(), C.getState(), true,
- ReleasedAllocatedMemory,
- /* RetNullOnFailure*/ true);
-
- C.addTransition(State);
- }
+ if (C.wasInlined)
+ return;
+
+ if (!isKnownDeallocObjCMethodName(Call))
+ return;
+
+ if (Optional<bool> FreeWhenDone = getFreeWhenDoneArg(Call))
+ if (!*FreeWhenDone)
+ return;
+
+ bool ReleasedAllocatedMemory;
+ ProgramStateRef State = FreeMemAux(C, Call.getArgExpr(0),
+ Call.getOriginExpr(), C.getState(),
+ /*Hold=*/true, ReleasedAllocatedMemory,
+ /*RetNullOnFailure=*/true);
+
+ C.addTransition(State);
}
ProgramStateRef MallocChecker::MallocMemReturnsAttr(CheckerContext &C,
@@ -537,7 +726,8 @@ ProgramStateRef MallocChecker::MallocMemReturnsAttr(CheckerContext &C,
ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
const CallExpr *CE,
SVal Size, SVal Init,
- ProgramStateRef state) {
+ ProgramStateRef State,
+ AllocationFamily Family) {
// 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
@@ -545,52 +735,52 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
unsigned Count = C.blockCount();
SValBuilder &svalBuilder = C.getSValBuilder();
const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
- DefinedSVal RetVal =
- cast<DefinedSVal>(svalBuilder.getConjuredHeapSymbolVal(CE, LCtx, Count));
- state = state->BindExpr(CE, C.getLocationContext(), RetVal);
+ DefinedSVal RetVal = svalBuilder.getConjuredHeapSymbolVal(CE, LCtx, Count)
+ .castAs<DefinedSVal>();
+ State = State->BindExpr(CE, C.getLocationContext(), RetVal);
// We expect the malloc functions to return a pointer.
- if (!isa<Loc>(RetVal))
+ if (!RetVal.getAs<Loc>())
return 0;
// Fill the region with the initialization value.
- state = state->bindDefault(RetVal, Init);
+ State = State->bindDefault(RetVal, Init);
// Set the region's extent equal to the Size parameter.
const SymbolicRegion *R =
dyn_cast_or_null<SymbolicRegion>(RetVal.getAsRegion());
if (!R)
return 0;
- if (isa<DefinedOrUnknownSVal>(Size)) {
+ if (Optional<DefinedOrUnknownSVal> DefinedSize =
+ Size.getAs<DefinedOrUnknownSVal>()) {
SValBuilder &svalBuilder = C.getSValBuilder();
DefinedOrUnknownSVal Extent = R->getExtent(svalBuilder);
- DefinedOrUnknownSVal DefinedSize = cast<DefinedOrUnknownSVal>(Size);
DefinedOrUnknownSVal extentMatchesSize =
- svalBuilder.evalEQ(state, Extent, DefinedSize);
+ svalBuilder.evalEQ(State, Extent, *DefinedSize);
- state = state->assume(extentMatchesSize, true);
- assert(state);
+ State = State->assume(extentMatchesSize, true);
+ assert(State);
}
- return MallocUpdateRefState(C, CE, state);
+ return MallocUpdateRefState(C, CE, State, Family);
}
ProgramStateRef MallocChecker::MallocUpdateRefState(CheckerContext &C,
- const CallExpr *CE,
- ProgramStateRef state) {
+ const Expr *E,
+ ProgramStateRef State,
+ AllocationFamily Family) {
// Get the return value.
- SVal retVal = state->getSVal(CE, C.getLocationContext());
+ SVal retVal = State->getSVal(E, C.getLocationContext());
// We expect the malloc functions to return a pointer.
- if (!isa<Loc>(retVal))
+ if (!retVal.getAs<Loc>())
return 0;
SymbolRef Sym = retVal.getAsLocSymbol();
assert(Sym);
// Set the symbol's state to Allocated.
- return state->set<RegionState>(Sym, RefState::getAllocated(CE));
-
+ return State->set<RegionState>(Sym, RefState::getAllocated(Family, E));
}
ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C,
@@ -629,8 +819,8 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
/// 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) {
+static bool didPreviousFreeFail(ProgramStateRef State,
+ SymbolRef Sym, SymbolRef &RetStatusSymbol) {
const SymbolRef *Ret = State->get<FreeReturnValue>(Sym);
if (Ret) {
assert(*Ret && "We should not store the null return symbol");
@@ -642,6 +832,107 @@ bool didPreviousFreeFail(ProgramStateRef State,
return false;
}
+AllocationFamily MallocChecker::getAllocationFamily(CheckerContext &C,
+ const Stmt *S) const {
+ if (!S)
+ return AF_None;
+
+ if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
+ const FunctionDecl *FD = C.getCalleeDecl(CE);
+
+ if (!FD)
+ FD = dyn_cast<FunctionDecl>(CE->getCalleeDecl());
+
+ ASTContext &Ctx = C.getASTContext();
+
+ if (isAllocationFunction(FD, Ctx) || isFreeFunction(FD, Ctx))
+ return AF_Malloc;
+
+ if (isStandardNewDelete(FD, Ctx)) {
+ OverloadedOperatorKind Kind = FD->getOverloadedOperator();
+ if (Kind == OO_New || Kind == OO_Delete)
+ return AF_CXXNew;
+ else if (Kind == OO_Array_New || Kind == OO_Array_Delete)
+ return AF_CXXNewArray;
+ }
+
+ return AF_None;
+ }
+
+ if (const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(S))
+ return NE->isArray() ? AF_CXXNewArray : AF_CXXNew;
+
+ if (const CXXDeleteExpr *DE = dyn_cast<CXXDeleteExpr>(S))
+ return DE->isArrayForm() ? AF_CXXNewArray : AF_CXXNew;
+
+ if (isa<ObjCMessageExpr>(S))
+ return AF_Malloc;
+
+ return AF_None;
+}
+
+bool MallocChecker::printAllocDeallocName(raw_ostream &os, CheckerContext &C,
+ const Expr *E) const {
+ if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
+ // FIXME: This doesn't handle indirect calls.
+ const FunctionDecl *FD = CE->getDirectCallee();
+ if (!FD)
+ return false;
+
+ os << *FD;
+ if (!FD->isOverloadedOperator())
+ os << "()";
+ return true;
+ }
+
+ if (const ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E)) {
+ if (Msg->isInstanceMessage())
+ os << "-";
+ else
+ os << "+";
+ os << Msg->getSelector().getAsString();
+ return true;
+ }
+
+ if (const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(E)) {
+ os << "'"
+ << getOperatorSpelling(NE->getOperatorNew()->getOverloadedOperator())
+ << "'";
+ return true;
+ }
+
+ if (const CXXDeleteExpr *DE = dyn_cast<CXXDeleteExpr>(E)) {
+ os << "'"
+ << getOperatorSpelling(DE->getOperatorDelete()->getOverloadedOperator())
+ << "'";
+ return true;
+ }
+
+ return false;
+}
+
+void MallocChecker::printExpectedAllocName(raw_ostream &os, CheckerContext &C,
+ const Expr *E) const {
+ AllocationFamily Family = getAllocationFamily(C, E);
+
+ switch(Family) {
+ case AF_Malloc: os << "malloc()"; return;
+ case AF_CXXNew: os << "'new'"; return;
+ case AF_CXXNewArray: os << "'new[]'"; return;
+ case AF_None: llvm_unreachable("not a deallocation expression");
+ }
+}
+
+void MallocChecker::printExpectedDeallocName(raw_ostream &os,
+ AllocationFamily Family) const {
+ switch(Family) {
+ case AF_Malloc: os << "free()"; return;
+ case AF_CXXNew: os << "'delete'"; return;
+ case AF_CXXNewArray: os << "'delete[]'"; return;
+ case AF_None: llvm_unreachable("suspicious AF_None argument");
+ }
+}
+
ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
const Expr *ArgExpr,
const Expr *ParentExpr,
@@ -651,12 +942,12 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
bool ReturnsNullOnFailure) const {
SVal ArgVal = State->getSVal(ArgExpr, C.getLocationContext());
- if (!isa<DefinedOrUnknownSVal>(ArgVal))
+ if (!ArgVal.getAs<DefinedOrUnknownSVal>())
return 0;
- DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(ArgVal);
+ DefinedOrUnknownSVal location = ArgVal.castAs<DefinedOrUnknownSVal>();
// Check for null dereferences.
- if (!isa<Loc>(location))
+ if (!location.getAs<Loc>())
return 0;
// The explicit NULL case, no operation is performed.
@@ -675,7 +966,7 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
// Nonlocs can't be freed, of course.
// Non-region locations (labels and fixed addresses) also shouldn't be freed.
if (!R) {
- ReportBadFree(C, ArgVal, ArgExpr->getSourceRange());
+ ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr);
return 0;
}
@@ -683,13 +974,14 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
// Blocks might show up as heap data, but should not be free()d
if (isa<BlockDataRegion>(R)) {
- ReportBadFree(C, ArgVal, ArgExpr->getSourceRange());
+ ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr);
return 0;
}
const MemSpaceRegion *MS = R->getMemorySpace();
- // Parameters, locals, statics, and globals shouldn't be freed.
+ // Parameters, locals, statics, globals, and memory returned by alloca()
+ // shouldn't be freed.
if (!(isa<UnknownSpaceRegion>(MS) || isa<HeapSpaceRegion>(MS))) {
// FIXME: at the time this code was written, malloc() regions were
// represented by conjured symbols, which are all in UnknownSpaceRegion.
@@ -699,46 +991,59 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
// function, so UnknownSpaceRegion is always a possibility.
// False negatives are better than false positives.
- ReportBadFree(C, ArgVal, ArgExpr->getSourceRange());
+ ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr);
return 0;
}
-
- const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R);
+
+ const SymbolicRegion *SrBase = dyn_cast<SymbolicRegion>(R->getBaseRegion());
// Various cases could lead to non-symbol values here.
// For now, ignore them.
- if (!SR)
+ if (!SrBase)
return 0;
- SymbolRef Sym = SR->getSymbol();
- const RefState *RS = State->get<RegionState>(Sym);
+ SymbolRef SymBase = SrBase->getSymbol();
+ const RefState *RsBase = State->get<RegionState>(SymBase);
SymbolRef PreviousRetStatusSymbol = 0;
- // Check double free.
- if (RS &&
- (RS->isReleased() || RS->isRelinquished()) &&
- !didPreviousFreeFail(State, Sym, PreviousRetStatusSymbol)) {
-
- if (ExplodedNode *N = C.generateSink()) {
- if (!BT_DoubleFree)
- BT_DoubleFree.reset(
- new BugType("Double free", "Memory Error"));
- BugReport *R = new BugReport(*BT_DoubleFree,
- (RS->isReleased() ? "Attempt to free released memory" :
- "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);
+ if (RsBase) {
+
+ bool DeallocMatchesAlloc =
+ RsBase->getAllocationFamily() == AF_None ||
+ RsBase->getAllocationFamily() == getAllocationFamily(C, ParentExpr);
+
+ // Check if an expected deallocation function matches the real one.
+ if (!DeallocMatchesAlloc && RsBase->isAllocated()) {
+ ReportMismatchedDealloc(C, ArgExpr->getSourceRange(), ParentExpr, RsBase);
+ return 0;
+ }
+
+ // Check double free.
+ if (DeallocMatchesAlloc &&
+ (RsBase->isReleased() || RsBase->isRelinquished()) &&
+ !didPreviousFreeFail(State, SymBase, PreviousRetStatusSymbol)) {
+ ReportDoubleFree(C, ParentExpr->getSourceRange(), RsBase->isReleased(),
+ SymBase, PreviousRetStatusSymbol);
+ return 0;
+ }
+
+ // Check if the memory location being freed is the actual location
+ // allocated, or an offset.
+ RegionOffset Offset = R->getAsOffset();
+ if (RsBase->isAllocated() &&
+ Offset.isValid() &&
+ !Offset.hasSymbolicOffset() &&
+ Offset.getOffset() != 0) {
+ const Expr *AllocExpr = cast<Expr>(RsBase->getStmt());
+ ReportOffsetFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
+ AllocExpr);
+ return 0;
}
- return 0;
}
- ReleasedAllocated = (RS != 0);
+ ReleasedAllocated = (RsBase != 0);
// Clean out the info on previous call to free return info.
- State = State->remove<FreeReturnValue>(Sym);
+ State = State->remove<FreeReturnValue>(SymBase);
// Keep track of the return value. If it is NULL, we will know that free
// failed.
@@ -746,23 +1051,60 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
SVal RetVal = C.getSVal(ParentExpr);
SymbolRef RetStatusSymbol = RetVal.getAsSymbol();
if (RetStatusSymbol) {
- C.getSymbolManager().addSymbolDependency(Sym, RetStatusSymbol);
- State = State->set<FreeReturnValue>(Sym, RetStatusSymbol);
+ C.getSymbolManager().addSymbolDependency(SymBase, RetStatusSymbol);
+ State = State->set<FreeReturnValue>(SymBase, RetStatusSymbol);
}
}
+ AllocationFamily Family = RsBase ? RsBase->getAllocationFamily() : AF_None;
// Normal free.
if (Hold)
- return State->set<RegionState>(Sym, RefState::getRelinquished(ParentExpr));
- return State->set<RegionState>(Sym, RefState::getReleased(ParentExpr));
+ return State->set<RegionState>(SymBase,
+ RefState::getRelinquished(Family,
+ ParentExpr));
+
+ return State->set<RegionState>(SymBase,
+ RefState::getReleased(Family, ParentExpr));
+}
+
+bool MallocChecker::isTrackedFamily(AllocationFamily Family) const {
+ switch (Family) {
+ case AF_Malloc: {
+ if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic)
+ return false;
+ return true;
+ }
+ case AF_CXXNew:
+ case AF_CXXNewArray: {
+ if (!Filter.CNewDeleteChecker)
+ return false;
+ return true;
+ }
+ case AF_None: {
+ return true;
+ }
+ }
+ llvm_unreachable("unhandled family");
+}
+
+bool MallocChecker::isTrackedFamily(CheckerContext &C,
+ const Stmt *AllocDeallocStmt) const {
+ return isTrackedFamily(getAllocationFamily(C, AllocDeallocStmt));
+}
+
+bool MallocChecker::isTrackedFamily(CheckerContext &C, SymbolRef Sym) const {
+ const RefState *RS = C.getState()->get<RegionState>(Sym);
+
+ return RS ? isTrackedFamily(RS->getAllocationFamily())
+ : isTrackedFamily(AF_None);
}
bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) {
- if (nonloc::ConcreteInt *IntVal = dyn_cast<nonloc::ConcreteInt>(&V))
+ if (Optional<nonloc::ConcreteInt> IntVal = V.getAs<nonloc::ConcreteInt>())
os << "an integer (" << IntVal->getValue() << ")";
- else if (loc::ConcreteInt *ConstAddr = dyn_cast<loc::ConcreteInt>(&V))
+ else if (Optional<loc::ConcreteInt> ConstAddr = V.getAs<loc::ConcreteInt>())
os << "a constant address (" << ConstAddr->getValue() << ")";
- else if (loc::GotoLabel *Label = dyn_cast<loc::GotoLabel>(&V))
+ else if (Optional<loc::GotoLabel> Label = V.getAs<loc::GotoLabel>())
os << "the address of the label '" << Label->getLabel()->getName() << "'";
else
return false;
@@ -844,41 +1186,192 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os,
}
}
-void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
- SourceRange range) const {
+void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
+ SourceRange Range,
+ const Expr *DeallocExpr) const {
+
+ if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic &&
+ !Filter.CNewDeleteChecker)
+ return;
+
+ if (!isTrackedFamily(C, DeallocExpr))
+ return;
+
if (ExplodedNode *N = C.generateSink()) {
if (!BT_BadFree)
BT_BadFree.reset(new BugType("Bad free", "Memory Error"));
SmallString<100> buf;
llvm::raw_svector_ostream os(buf);
-
+
const MemRegion *MR = ArgVal.getAsRegion();
- if (MR) {
- while (const ElementRegion *ER = dyn_cast<ElementRegion>(MR))
- MR = ER->getSuperRegion();
-
- // Special case for alloca()
- if (isa<AllocaRegion>(MR))
- os << "Argument to free() was allocated by alloca(), not malloc()";
- else {
- os << "Argument to free() is ";
- if (SummarizeRegion(os, MR))
- os << ", which is not memory allocated by malloc()";
- else
- os << "not memory allocated by malloc()";
- }
- } else {
- os << "Argument to free() is ";
- if (SummarizeValue(os, ArgVal))
- os << ", which is not memory allocated by malloc()";
+ while (const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(MR))
+ MR = ER->getSuperRegion();
+
+ if (MR && isa<AllocaRegion>(MR))
+ os << "Memory allocated by alloca() should not be deallocated";
+ else {
+ os << "Argument to ";
+ if (!printAllocDeallocName(os, C, DeallocExpr))
+ os << "deallocator";
+
+ os << " is ";
+ bool Summarized = MR ? SummarizeRegion(os, MR)
+ : SummarizeValue(os, ArgVal);
+ if (Summarized)
+ os << ", which is not memory allocated by ";
else
- os << "not memory allocated by malloc()";
+ os << "not memory allocated by ";
+
+ printExpectedAllocName(os, C, DeallocExpr);
}
-
+
BugReport *R = new BugReport(*BT_BadFree, os.str(), N);
R->markInteresting(MR);
- R->addRange(range);
+ R->addRange(Range);
+ C.emitReport(R);
+ }
+}
+
+void MallocChecker::ReportMismatchedDealloc(CheckerContext &C,
+ SourceRange Range,
+ const Expr *DeallocExpr,
+ const RefState *RS) const {
+
+ if (!Filter.CMismatchedDeallocatorChecker)
+ return;
+
+ if (ExplodedNode *N = C.generateSink()) {
+ if (!BT_MismatchedDealloc)
+ BT_MismatchedDealloc.reset(new BugType("Bad deallocator",
+ "Memory Error"));
+
+ SmallString<100> buf;
+ llvm::raw_svector_ostream os(buf);
+
+ const Expr *AllocExpr = cast<Expr>(RS->getStmt());
+ SmallString<20> AllocBuf;
+ llvm::raw_svector_ostream AllocOs(AllocBuf);
+ SmallString<20> DeallocBuf;
+ llvm::raw_svector_ostream DeallocOs(DeallocBuf);
+
+ os << "Memory";
+ if (printAllocDeallocName(AllocOs, C, AllocExpr))
+ os << " allocated by " << AllocOs.str();
+
+ os << " should be deallocated by ";
+ printExpectedDeallocName(os, RS->getAllocationFamily());
+
+ if (printAllocDeallocName(DeallocOs, C, DeallocExpr))
+ os << ", not " << DeallocOs.str();
+
+ BugReport *R = new BugReport(*BT_MismatchedDealloc, os.str(), N);
+ R->addRange(Range);
+ C.emitReport(R);
+ }
+}
+
+void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal,
+ SourceRange Range, const Expr *DeallocExpr,
+ const Expr *AllocExpr) const {
+
+ if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic &&
+ !Filter.CNewDeleteChecker)
+ return;
+
+ if (!isTrackedFamily(C, AllocExpr))
+ return;
+
+ ExplodedNode *N = C.generateSink();
+ if (N == NULL)
+ return;
+
+ if (!BT_OffsetFree)
+ BT_OffsetFree.reset(new BugType("Offset free", "Memory Error"));
+
+ SmallString<100> buf;
+ llvm::raw_svector_ostream os(buf);
+ SmallString<20> AllocNameBuf;
+ llvm::raw_svector_ostream AllocNameOs(AllocNameBuf);
+
+ const MemRegion *MR = ArgVal.getAsRegion();
+ assert(MR && "Only MemRegion based symbols can have offset free errors");
+
+ RegionOffset Offset = MR->getAsOffset();
+ assert((Offset.isValid() &&
+ !Offset.hasSymbolicOffset() &&
+ Offset.getOffset() != 0) &&
+ "Only symbols with a valid offset can have offset free errors");
+
+ int offsetBytes = Offset.getOffset() / C.getASTContext().getCharWidth();
+
+ os << "Argument to ";
+ if (!printAllocDeallocName(os, C, DeallocExpr))
+ os << "deallocator";
+ os << " is offset by "
+ << offsetBytes
+ << " "
+ << ((abs(offsetBytes) > 1) ? "bytes" : "byte")
+ << " from the start of ";
+ if (AllocExpr && printAllocDeallocName(AllocNameOs, C, AllocExpr))
+ os << "memory allocated by " << AllocNameOs.str();
+ else
+ os << "allocated memory";
+
+ BugReport *R = new BugReport(*BT_OffsetFree, os.str(), N);
+ R->markInteresting(MR->getBaseRegion());
+ R->addRange(Range);
+ C.emitReport(R);
+}
+
+void MallocChecker::ReportUseAfterFree(CheckerContext &C, SourceRange Range,
+ SymbolRef Sym) const {
+
+ if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic &&
+ !Filter.CNewDeleteChecker)
+ return;
+
+ if (!isTrackedFamily(C, Sym))
+ return;
+
+ if (ExplodedNode *N = C.generateSink()) {
+ if (!BT_UseFree)
+ BT_UseFree.reset(new BugType("Use-after-free", "Memory Error"));
+
+ BugReport *R = new BugReport(*BT_UseFree,
+ "Use of memory after it is freed", N);
+
+ R->markInteresting(Sym);
+ R->addRange(Range);
+ R->addVisitor(new MallocBugVisitor(Sym));
+ C.emitReport(R);
+ }
+}
+
+void MallocChecker::ReportDoubleFree(CheckerContext &C, SourceRange Range,
+ bool Released, SymbolRef Sym,
+ SymbolRef PrevSym) const {
+
+ if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic &&
+ !Filter.CNewDeleteChecker)
+ return;
+
+ if (!isTrackedFamily(C, Sym))
+ return;
+
+ if (ExplodedNode *N = C.generateSink()) {
+ if (!BT_DoubleFree)
+ BT_DoubleFree.reset(new BugType("Double free", "Memory Error"));
+
+ BugReport *R = new BugReport(*BT_DoubleFree,
+ (Released ? "Attempt to free released memory"
+ : "Attempt to free non-owned memory"),
+ N);
+ R->addRange(Range);
+ R->markInteresting(Sym);
+ if (PrevSym)
+ R->markInteresting(PrevSym);
+ R->addVisitor(new MallocBugVisitor(Sym));
C.emitReport(R);
}
}
@@ -893,9 +1386,9 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
const Expr *arg0Expr = CE->getArg(0);
const LocationContext *LCtx = C.getLocationContext();
SVal Arg0Val = state->getSVal(arg0Expr, LCtx);
- if (!isa<DefinedOrUnknownSVal>(Arg0Val))
+ if (!Arg0Val.getAs<DefinedOrUnknownSVal>())
return 0;
- DefinedOrUnknownSVal arg0Val = cast<DefinedOrUnknownSVal>(Arg0Val);
+ DefinedOrUnknownSVal arg0Val = Arg0Val.castAs<DefinedOrUnknownSVal>();
SValBuilder &svalBuilder = C.getSValBuilder();
@@ -909,9 +1402,9 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
// Get the value of the size argument.
SVal Arg1ValG = state->getSVal(Arg1, LCtx);
- if (!isa<DefinedOrUnknownSVal>(Arg1ValG))
+ if (!Arg1ValG.getAs<DefinedOrUnknownSVal>())
return 0;
- DefinedOrUnknownSVal Arg1Val = cast<DefinedOrUnknownSVal>(Arg1ValG);
+ DefinedOrUnknownSVal Arg1Val = Arg1ValG.castAs<DefinedOrUnknownSVal>();
// Compare the size argument to 0.
DefinedOrUnknownSVal SizeZero =
@@ -1032,18 +1525,19 @@ MallocChecker::getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
N = N->pred_empty() ? NULL : *(N->pred_begin());
}
- ProgramPoint P = AllocNode->getLocation();
- const Stmt *AllocationStmt = 0;
- if (CallExitEnd *Exit = dyn_cast<CallExitEnd>(&P))
- AllocationStmt = Exit->getCalleeContext()->getCallSite();
- else if (StmtPoint *SP = dyn_cast<StmtPoint>(&P))
- AllocationStmt = SP->getStmt();
-
- return LeakInfo(AllocationStmt, ReferenceRegion);
+ return LeakInfo(AllocNode, ReferenceRegion);
}
void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
CheckerContext &C) const {
+
+ if (!Filter.CMallocOptimistic && !Filter.CMallocPessimistic &&
+ !Filter.CNewDeleteChecker)
+ return;
+
+ if (!isTrackedFamily(C, Sym))
+ return;
+
assert(N);
if (!BT_Leak) {
BT_Leak.reset(new BugType("Memory leak", "Memory Error"));
@@ -1059,12 +1553,20 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
// With leaks, we want to unique them by the location where they were
// allocated, and only report a single path.
PathDiagnosticLocation LocUsedForUniqueing;
- const Stmt *AllocStmt = 0;
+ const ExplodedNode *AllocNode = 0;
const MemRegion *Region = 0;
- llvm::tie(AllocStmt, Region) = getAllocationSite(N, Sym, C);
- if (AllocStmt)
- LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocStmt,
- C.getSourceManager(), N->getLocationContext());
+ llvm::tie(AllocNode, Region) = getAllocationSite(N, Sym, C);
+
+ ProgramPoint P = AllocNode->getLocation();
+ const Stmt *AllocationStmt = 0;
+ if (Optional<CallExitEnd> Exit = P.getAs<CallExitEnd>())
+ AllocationStmt = Exit->getCalleeContext()->getCallSite();
+ else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>())
+ AllocationStmt = SP->getStmt();
+ if (AllocationStmt)
+ LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocationStmt,
+ C.getSourceManager(),
+ AllocNode->getLocationContext());
SmallString<200> buf;
llvm::raw_svector_ostream os(buf);
@@ -1075,7 +1577,9 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
os << '\'';
}
- BugReport *R = new BugReport(*BT_Leak, os.str(), N, LocUsedForUniqueing);
+ BugReport *R = new BugReport(*BT_Leak, os.str(), N,
+ LocUsedForUniqueing,
+ AllocNode->getLocationContext()->getDecl());
R->markInteresting(Sym);
R->addVisitor(new MallocBugVisitor(Sym, true));
C.emitReport(R);
@@ -1091,7 +1595,7 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
RegionStateTy RS = state->get<RegionState>();
RegionStateTy::Factory &F = state->get_context<RegionState>();
- llvm::SmallVector<SymbolRef, 2> Errors;
+ SmallVector<SymbolRef, 2> Errors;
for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
if (SymReaper.isDead(I->first)) {
if (I->second.isAllocated())
@@ -1125,7 +1629,7 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
if (!Errors.empty()) {
static SimpleProgramPointTag Tag("MallocChecker : DeadSymbolsLeak");
N = C.addTransition(C.getState(), C.getPredecessor(), &Tag);
- for (llvm::SmallVector<SymbolRef, 2>::iterator
+ for (SmallVector<SymbolRef, 2>::iterator
I = Errors.begin(), E = Errors.end(); I != E; ++I) {
reportLeak(*I, N, C);
}
@@ -1134,27 +1638,14 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
C.addTransition(state->set<RegionState>(RS), N);
}
-void MallocChecker::checkEndPath(CheckerContext &C) const {
- ProgramStateRef state = C.getState();
- RegionStateTy M = state->get<RegionState>();
-
- // If inside inlined call, skip it.
- if (C.getLocationContext()->getParent() != 0)
- return;
-
- for (RegionStateTy::iterator I = M.begin(), E = M.end(); I != E; ++I) {
- RefState RS = I->second;
- if (RS.isAllocated()) {
- ExplodedNode *N = C.addTransition(state);
- if (N)
- reportLeak(I->first, N, C);
- }
- }
-}
-
void MallocChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
// We will check for double free in the post visit.
- if (isFreeFunction(C.getCalleeDecl(CE), C.getASTContext()))
+ if ((Filter.CMallocOptimistic || Filter.CMallocPessimistic) &&
+ isFreeFunction(C.getCalleeDecl(CE), C.getASTContext()))
+ return;
+
+ if (Filter.CNewDeleteChecker &&
+ isStandardNewDelete(C.getCalleeDecl(CE), C.getASTContext()))
return;
// Check use after free, when a freed pointer is passed to a call.
@@ -1163,7 +1654,7 @@ void MallocChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
E = CE->arg_end(); I != E; ++I) {
const Expr *A = *I;
if (A->getType().getTypePtr()->isAnyPointerType()) {
- SymbolRef Sym = State->getSVal(A, C.getLocationContext()).getAsSymbol();
+ SymbolRef Sym = C.getSVal(A).getAsSymbol();
if (!Sym)
continue;
if (checkUseAfterFree(Sym, C, A))
@@ -1193,15 +1684,7 @@ void MallocChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const {
// Check if we are returning freed memory.
if (Sym)
- if (checkUseAfterFree(Sym, C, E))
- return;
-
- // If this function body is not inlined, stop tracking any returned symbols.
- if (C.getLocationContext()->getParent() == 0) {
- State =
- State->scanReachableSymbols<StopTrackingCallback>(RetVal).getState();
- C.addTransition(State);
- }
+ checkUseAfterFree(Sym, C, E);
}
// TODO: Blocks should be either inlined or should call invalidate regions
@@ -1231,7 +1714,7 @@ void MallocChecker::checkPostStmt(const BlockExpr *BE,
MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager();
for ( ; I != E; ++I) {
- const VarRegion *VR = *I;
+ const VarRegion *VR = I.getCapturedRegion();
if (VR->getSuperRegion() == R) {
VR = MemMgr.getVarRegion(VR->getDecl(), LC);
}
@@ -1252,21 +1735,12 @@ bool MallocChecker::isReleased(SymbolRef Sym, CheckerContext &C) const {
bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C,
const Stmt *S) const {
+
if (isReleased(Sym, C)) {
- if (ExplodedNode *N = C.generateSink()) {
- if (!BT_UseFree)
- BT_UseFree.reset(new BugType("Use-after-free", "Memory Error"));
-
- BugReport *R = new BugReport(*BT_UseFree,
- "Use of memory after it is freed",N);
- if (S)
- R->addRange(S->getSourceRange());
- R->markInteresting(Sym);
- R->addVisitor(new MallocBugVisitor(Sym));
- C.emitReport(R);
- return true;
- }
+ ReportUseAfterFree(C, S->getSourceRange(), Sym);
+ return true;
}
+
return false;
}
@@ -1278,51 +1752,6 @@ void MallocChecker::checkLocation(SVal l, bool isLoad, const Stmt *S,
checkUseAfterFree(Sym, C, S);
}
-//===----------------------------------------------------------------------===//
-// Check various ways a symbol can be invalidated.
-// TODO: This logic (the next 3 functions) is copied/similar to the
-// RetainRelease checker. We might want to factor this out.
-//===----------------------------------------------------------------------===//
-
-// 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 MallocChecker::checkBind(SVal loc, SVal val, const Stmt *S,
- CheckerContext &C) const {
- // Are we storing to something that causes the value to "escape"?
- bool escapes = true;
- ProgramStateRef state = C.getState();
-
- if (loc::MemRegionVal *regionLoc = dyn_cast<loc::MemRegionVal>(&loc)) {
- escapes = !regionLoc->getRegion()->hasStackStorage();
-
- if (!escapes) {
- // To test (3), generate a new state with the binding added. If it is
- // the same state, then it escapes (since the store cannot represent
- // the binding).
- // Do this only if we know that the store is not supposed to generate the
- // same state.
- SVal StoredVal = state->getSVal(regionLoc->getRegion());
- if (StoredVal != val)
- escapes = (state == (state->bindLoc(*regionLoc, val)));
- }
- }
-
- // If our store can represent the binding and we aren't storing to something
- // that doesn't have local storage then just return and have the simulation
- // state continue as is.
- if (!escapes)
- return;
-
- // Otherwise, find all symbols referenced by 'val' that we are tracking
- // and stop tracking them.
- state = state->scanReachableSymbols<StopTrackingCallback>(val).getState();
- C.addTransition(state);
-}
-
// If a symbolic region is assumed to NULL (or another constant), stop tracking
// it - assuming that allocation failed on this path.
ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state,
@@ -1352,7 +1781,7 @@ ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state,
if (RS->isReleased()) {
if (I.getData().Kind == RPToBeFreedAfterFailure)
state = state->set<RegionState>(ReallocSym,
- RefState::getAllocated(RS->getStmt()));
+ RefState::getAllocated(RS->getAllocationFamily(), RS->getStmt()));
else if (I.getData().Kind == RPDoNotTrackAfterFailure)
state = state->remove<RegionState>(ReallocSym);
else
@@ -1365,12 +1794,8 @@ ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state,
return state;
}
-// Check if the function is known to us. So, for example, we could
-// conservatively assume it can free/reallocate its pointer arguments.
-// (We assume that the pointers cannot escape through calls to system
-// functions not handled by this checker.)
-bool MallocChecker::doesNotFreeMemory(const CallEvent *Call,
- ProgramStateRef State) const {
+bool MallocChecker::doesNotFreeMemOrInteresting(const CallEvent *Call,
+ ProgramStateRef State) const {
assert(Call);
// For now, assume that any C++ call can free memory.
@@ -1387,24 +1812,23 @@ bool MallocChecker::doesNotFreeMemory(const CallEvent *Call,
if (!Call->isInSystemHeader() || Call->hasNonZeroCallbackArg())
return false;
- Selector S = Msg->getSelector();
-
- // Whitelist the ObjC methods which do free memory.
- // - Anything containing 'freeWhenDone' param set to 1.
- // Ex: dataWithBytesNoCopy:length:freeWhenDone.
- for (unsigned i = 1; i < S.getNumArgs(); ++i) {
- if (S.getNameForSlot(i).equals("freeWhenDone")) {
- if (Call->getArgSVal(i).isConstant(1))
- return false;
- else
- return true;
- }
- }
+ // If it's a method we know about, handle it explicitly post-call.
+ // This should happen before the "freeWhenDone" check below.
+ if (isKnownDeallocObjCMethodName(*Msg))
+ return true;
- // If the first selector ends with NoCopy, assume that the ownership is
- // transferred as well.
- // Ex: [NSData dataWithBytesNoCopy:bytes length:10];
- StringRef FirstSlot = S.getNameForSlot(0);
+ // If there's a "freeWhenDone" parameter, but the method isn't one we know
+ // about, we can't be sure that the object will use free() to deallocate the
+ // memory, so we can't model it explicitly. The best we can do is use it to
+ // decide whether the pointer escapes.
+ if (Optional<bool> FreeWhenDone = getFreeWhenDoneArg(*Msg))
+ return !*FreeWhenDone;
+
+ // If the first selector piece ends with "NoCopy", and there is no
+ // "freeWhenDone" parameter set to zero, we know ownership is being
+ // transferred. Again, though, we can't be sure that the object will use
+ // free() to deallocate the memory, so we can't model it explicitly.
+ StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);
if (FirstSlot.endswith("NoCopy"))
return false;
@@ -1509,41 +1933,50 @@ bool MallocChecker::doesNotFreeMemory(const CallEvent *Call,
return true;
}
-// If the symbol we are tracking is invalidated, but not explicitly (ex: the &p
-// escapes, when we are tracking p), do not track the symbol as we cannot reason
-// about it anymore.
-ProgramStateRef
-MallocChecker::checkRegionChanges(ProgramStateRef State,
- const StoreManager::InvalidatedSymbols *invalidated,
- ArrayRef<const MemRegion *> ExplicitRegions,
- ArrayRef<const MemRegion *> Regions,
- const CallEvent *Call) const {
- if (!invalidated || invalidated->empty())
- return State;
- llvm::SmallPtrSet<SymbolRef, 8> WhitelistedSymbols;
+static bool retTrue(const RefState *RS) {
+ return true;
+}
- // If it's a call which might free or reallocate memory, we assume that all
- // regions (explicit and implicit) escaped.
+static bool checkIfNewOrNewArrayFamily(const RefState *RS) {
+ return (RS->getAllocationFamily() == AF_CXXNewArray ||
+ RS->getAllocationFamily() == AF_CXXNew);
+}
- // Otherwise, whitelist explicit pointers; we still can track them.
- if (!Call || doesNotFreeMemory(Call, State)) {
- for (ArrayRef<const MemRegion *>::iterator I = ExplicitRegions.begin(),
- E = ExplicitRegions.end(); I != E; ++I) {
- if (const SymbolicRegion *R = (*I)->StripCasts()->getAs<SymbolicRegion>())
- WhitelistedSymbols.insert(R->getSymbol());
- }
+ProgramStateRef MallocChecker::checkPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind) const {
+ return checkPointerEscapeAux(State, Escaped, Call, Kind, &retTrue);
+}
+
+ProgramStateRef MallocChecker::checkConstPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind) const {
+ return checkPointerEscapeAux(State, Escaped, Call, Kind,
+ &checkIfNewOrNewArrayFamily);
+}
+
+ProgramStateRef MallocChecker::checkPointerEscapeAux(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind,
+ bool(*CheckRefState)(const RefState*)) const {
+ // If we know that the call does not free memory, or we want to process the
+ // call later, keep tracking the top level arguments.
+ if ((Kind == PSK_DirectEscapeOnCall ||
+ Kind == PSK_IndirectEscapeOnCall) &&
+ doesNotFreeMemOrInteresting(Call, State)) {
+ return State;
}
- for (StoreManager::InvalidatedSymbols::const_iterator I=invalidated->begin(),
- E = invalidated->end(); I!=E; ++I) {
+ for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
+ E = Escaped.end();
+ I != E; ++I) {
SymbolRef sym = *I;
- if (WhitelistedSymbols.count(sym))
- continue;
- // The symbol escaped. Note, we assume that if the symbol is released,
- // passing it out will result in a use after free. We also keep tracking
- // relinquished symbols.
+
if (const RefState *RS = State->get<RegionState>(sym)) {
- if (RS->isAllocated())
+ if (RS->isAllocated() && CheckRefState(RS))
State = State->remove<RegionState>(sym);
}
}
@@ -1584,16 +2017,16 @@ MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N,
// Retrieve the associated statement.
ProgramPoint ProgLoc = N->getLocation();
- if (StmtPoint *SP = dyn_cast<StmtPoint>(&ProgLoc))
+ if (Optional<StmtPoint> SP = ProgLoc.getAs<StmtPoint>()) {
S = SP->getStmt();
- else if (CallExitEnd *Exit = dyn_cast<CallExitEnd>(&ProgLoc))
+ } else if (Optional<CallExitEnd> Exit = ProgLoc.getAs<CallExitEnd>()) {
S = Exit->getCalleeContext()->getCallSite();
- // If an assumption was made on a branch, it should be caught
- // here by looking at the state transition.
- else if (BlockEdge *Edge = dyn_cast<BlockEdge>(&ProgLoc)) {
- const CFGBlock *srcBlk = Edge->getSrc();
- S = srcBlk->getTerminator();
+ } else if (Optional<BlockEdge> Edge = ProgLoc.getAs<BlockEdge>()) {
+ // If an assumption was made on a branch, it should be caught
+ // here by looking at the state transition.
+ S = Edge->getSrc()->getTerminator();
}
+
if (!S)
return 0;
@@ -1658,8 +2091,15 @@ void MallocChecker::printState(raw_ostream &Out, ProgramStateRef State,
RegionStateTy RS = State->get<RegionState>();
- if (!RS.isEmpty())
- Out << "Has Malloc data" << NL;
+ if (!RS.isEmpty()) {
+ Out << Sep << "MallocChecker:" << NL;
+ for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
+ I.getKey()->dumpToStream(Out);
+ Out << " : ";
+ I.getData().dump(Out);
+ Out << NL;
+ }
+ }
}
#define REGISTER_CHECKER(name) \
@@ -1670,3 +2110,5 @@ void ento::register##name(CheckerManager &mgr) {\
REGISTER_CHECKER(MallocPessimistic)
REGISTER_CHECKER(MallocOptimistic)
+REGISTER_CHECKER(NewDeleteChecker)
+REGISTER_CHECKER(MismatchedDeallocatorChecker)
diff --git a/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
index daec418..34425e3 100644
--- a/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
@@ -20,9 +20,9 @@
#include "ClangSACheckers.h"
#include "clang/AST/EvaluatedExprVisitor.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "llvm/ADT/SmallVector.h"
using namespace clang;
@@ -44,18 +44,18 @@ public:
BugReporter &BR) const;
void CheckMallocArgument(
- llvm::SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows,
+ SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows,
const Expr *TheArgument, ASTContext &Context) const;
void OutputPossibleOverflows(
- llvm::SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows,
+ SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows,
const Decl *D, BugReporter &BR, AnalysisManager &mgr) const;
};
} // end anonymous namespace
void MallocOverflowSecurityChecker::CheckMallocArgument(
- llvm::SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows,
+ SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows,
const Expr *TheArgument,
ASTContext &Context) const {
@@ -111,7 +111,7 @@ namespace {
class CheckOverflowOps :
public EvaluatedExprVisitor<CheckOverflowOps> {
public:
- typedef llvm::SmallVectorImpl<MallocOverflowCheck> theVecType;
+ typedef SmallVectorImpl<MallocOverflowCheck> theVecType;
private:
theVecType &toScanFor;
@@ -197,7 +197,7 @@ private:
// detect the most blatent cases of overflow and educate the
// programmer.
void MallocOverflowSecurityChecker::OutputPossibleOverflows(
- llvm::SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows,
+ SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows,
const Decl *D, BugReporter &BR, AnalysisManager &mgr) const {
// By far the most common case: nothing to check.
if (PossibleMallocOverflows.empty())
@@ -230,13 +230,13 @@ void MallocOverflowSecurityChecker::checkASTCodeBody(const Decl *D,
return;
// A list of variables referenced in possibly overflowing malloc operands.
- llvm::SmallVector<MallocOverflowCheck, 2> PossibleMallocOverflows;
+ SmallVector<MallocOverflowCheck, 2> PossibleMallocOverflows;
for (CFG::iterator it = cfg->begin(), ei = cfg->end(); it != ei; ++it) {
CFGBlock *block = *it;
for (CFGBlock::iterator bi = block->begin(), be = block->end();
bi != be; ++bi) {
- if (const CFGStmt *CS = bi->getAs<CFGStmt>()) {
+ if (Optional<CFGStmt> CS = bi->getAs<CFGStmt>()) {
if (const CallExpr *TheCall = dyn_cast<CallExpr>(CS->getStmt())) {
// Get the callee.
const FunctionDecl *FD = TheCall->getDirectCallee();
diff --git a/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp
index fb40f22..ce7d4cc 100644
--- a/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp
@@ -14,13 +14,14 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
-#include "clang/AST/StmtVisitor.h"
-#include "clang/AST/TypeLoc.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -225,7 +226,7 @@ public:
OS << " is converted to a pointer of type '"
<< PointeeType.getAsString() << "', which is incompatible with "
<< "sizeof operand type '" << SizeofType.getAsString() << "'";
- llvm::SmallVector<SourceRange, 4> Ranges;
+ SmallVector<SourceRange, 4> Ranges;
Ranges.push_back(i->AllocCall->getCallee()->getSourceRange());
Ranges.push_back(SFinder.Sizeofs[0]->getSourceRange());
if (TSI)
diff --git a/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp b/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
index 3331bc8..fc28e1f 100644
--- a/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
@@ -16,15 +16,15 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/Decl.h"
using namespace clang;
using namespace ento;
diff --git a/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
index 7a66ec3..9f01522 100644
--- a/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
@@ -16,14 +16,15 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/Decl.h"
-#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -185,7 +186,7 @@ static void setFlag(ProgramStateRef state, SVal val, CheckerContext &C) {
static QualType parameterTypeFromSVal(SVal val, CheckerContext &C) {
const StackFrameContext *
SFC = C.getLocationContext()->getCurrentStackFrame();
- if (const loc::MemRegionVal* X = dyn_cast<loc::MemRegionVal>(&val)) {
+ if (Optional<loc::MemRegionVal> X = val.getAs<loc::MemRegionVal>()) {
const MemRegion* R = X->getRegion();
if (const VarRegion *VR = R->getAs<VarRegion>())
if (const StackArgumentsSpaceRegion *
@@ -202,7 +203,7 @@ void NSOrCFErrorDerefChecker::checkLocation(SVal loc, bool isLoad,
CheckerContext &C) const {
if (!isLoad)
return;
- if (loc.isUndef() || !isa<Loc>(loc))
+ if (loc.isUndef() || !loc.getAs<Loc>())
return;
ASTContext &Ctx = C.getASTContext();
@@ -224,12 +225,12 @@ void NSOrCFErrorDerefChecker::checkLocation(SVal loc, bool isLoad,
CFErrorII = &Ctx.Idents.get("CFErrorRef");
if (ShouldCheckNSError && IsNSError(parmT, NSErrorII)) {
- setFlag<NSErrorOut>(state, state->getSVal(cast<Loc>(loc)), C);
+ setFlag<NSErrorOut>(state, state->getSVal(loc.castAs<Loc>()), C);
return;
}
if (ShouldCheckCFError && IsCFError(parmT, CFErrorII)) {
- setFlag<CFErrorOut>(state, state->getSVal(cast<Loc>(loc)), C);
+ setFlag<CFErrorOut>(state, state->getSVal(loc.castAs<Loc>()), C);
return;
}
}
@@ -251,18 +252,15 @@ void NSOrCFErrorDerefChecker::checkEvent(ImplicitNullDerefEvent event) const {
return;
// Storing to possible null NSError/CFErrorRef out parameter.
+ SmallString<128> Buf;
+ llvm::raw_svector_ostream os(Buf);
- // Emit an error.
- std::string err;
- llvm::raw_string_ostream os(err);
- os << "Potential null dereference. According to coding standards ";
-
- if (isNSError)
- os << "in 'Creating and Returning NSError Objects' the parameter '";
- else
- os << "documented in CoreFoundation/CFError.h the parameter '";
+ os << "Potential null dereference. According to coding standards ";
+ os << (isNSError
+ ? "in 'Creating and Returning NSError Objects' the parameter"
+ : "documented in CoreFoundation/CFError.h the parameter");
- os << "' may be null.";
+ os << " may be null";
BugType *bug = 0;
if (isNSError)
diff --git a/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp b/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
index efb7072..0009e1b 100644
--- a/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/Attr.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
@@ -47,7 +48,7 @@ void NoReturnFunctionChecker::checkPostStmt(const CallExpr *CE,
if (!FD)
return;
- if (FD->getAttr<AnalyzerNoReturnAttr>())
+ if (FD->getAttr<AnalyzerNoReturnAttr>() || FD->isNoReturn())
BuildSinks = true;
else if (const IdentifierInfo *II = FD->getIdentifier()) {
// HACK: Some functions are not marked noreturn, and don't return.
@@ -100,6 +101,15 @@ static bool END_WITH_NULL isMultiArgSelector(const Selector *Sel, ...) {
void NoReturnFunctionChecker::checkPostObjCMessage(const ObjCMethodCall &Msg,
CheckerContext &C) const {
+ // Check if the method is annotated with analyzer_noreturn.
+ if (const ObjCMethodDecl *MD = Msg.getDecl()) {
+ MD = MD->getCanonicalDecl();
+ if (MD->hasAttr<AnalyzerNoReturnAttr>()) {
+ C.generateSink();
+ return;
+ }
+ }
+
// HACK: This entire check is to handle two messages in the Cocoa frameworks:
// -[NSAssertionHandler
// handleFailureInMethod:object:file:lineNumber:description:]
diff --git a/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp b/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
new file mode 100644
index 0000000..273a7a3
--- /dev/null
+++ b/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
@@ -0,0 +1,193 @@
+//===--- NonNullParamChecker.cpp - Undefined arguments checker -*- C++ -*--===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines NonNullParamChecker, which checks for arguments expected not to
+// be null due to:
+// - the corresponding parameters being declared to have nonnull attribute
+// - the corresponding parameters being references; since the call would form
+// a reference to a null pointer
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.h"
+#include "clang/AST/Attr.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class NonNullParamChecker
+ : public Checker< check::PreCall > {
+ mutable OwningPtr<BugType> BTAttrNonNull;
+ mutable OwningPtr<BugType> BTNullRefArg;
+public:
+
+ void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
+
+ BugReport *genReportNullAttrNonNull(const ExplodedNode *ErrorN,
+ const Expr *ArgE) const;
+ BugReport *genReportReferenceToNullPointer(const ExplodedNode *ErrorN,
+ const Expr *ArgE) const;
+};
+} // end anonymous namespace
+
+void NonNullParamChecker::checkPreCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ const Decl *FD = Call.getDecl();
+ if (!FD)
+ return;
+
+ const NonNullAttr *Att = FD->getAttr<NonNullAttr>();
+
+ ProgramStateRef state = C.getState();
+
+ CallEvent::param_type_iterator TyI = Call.param_type_begin(),
+ TyE = Call.param_type_end();
+
+ for (unsigned idx = 0, count = Call.getNumArgs(); idx != count; ++idx){
+
+ // Check if the parameter is a reference. We want to report when reference
+ // to a null pointer is passed as a paramter.
+ bool haveRefTypeParam = false;
+ if (TyI != TyE) {
+ haveRefTypeParam = (*TyI)->isReferenceType();
+ TyI++;
+ }
+
+ bool haveAttrNonNull = Att && Att->isNonNull(idx);
+
+ if (!haveRefTypeParam && !haveAttrNonNull)
+ continue;
+
+ // If the value is unknown or undefined, we can't perform this check.
+ const Expr *ArgE = Call.getArgExpr(idx);
+ SVal V = Call.getArgSVal(idx);
+ Optional<DefinedSVal> DV = V.getAs<DefinedSVal>();
+ if (!DV)
+ continue;
+
+ // Process the case when the argument is not a location.
+ assert(!haveRefTypeParam || DV->getAs<Loc>());
+
+ if (haveAttrNonNull && !DV->getAs<Loc>()) {
+ // If the argument is a union type, we want to handle a potential
+ // transparent_union GCC extension.
+ if (!ArgE)
+ continue;
+
+ QualType T = ArgE->getType();
+ const RecordType *UT = T->getAsUnionType();
+ if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>())
+ continue;
+
+ if (Optional<nonloc::CompoundVal> CSV =
+ DV->getAs<nonloc::CompoundVal>()) {
+ nonloc::CompoundVal::iterator CSV_I = CSV->begin();
+ assert(CSV_I != CSV->end());
+ V = *CSV_I;
+ DV = V.getAs<DefinedSVal>();
+ assert(++CSV_I == CSV->end());
+ if (!DV)
+ continue;
+ // Retrieve the corresponding expression.
+ if (const CompoundLiteralExpr *CE = dyn_cast<CompoundLiteralExpr>(ArgE))
+ if (const InitListExpr *IE =
+ dyn_cast<InitListExpr>(CE->getInitializer()))
+ ArgE = dyn_cast<Expr>(*(IE->begin()));
+
+ } else {
+ // FIXME: Handle LazyCompoundVals?
+ continue;
+ }
+ }
+
+ ConstraintManager &CM = C.getConstraintManager();
+ ProgramStateRef stateNotNull, stateNull;
+ llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
+
+ if (stateNull && !stateNotNull) {
+ // Generate an error node. Check for a null node in case
+ // we cache out.
+ if (ExplodedNode *errorNode = C.generateSink(stateNull)) {
+
+ BugReport *R = 0;
+ if (haveAttrNonNull)
+ R = genReportNullAttrNonNull(errorNode, ArgE);
+ else if (haveRefTypeParam)
+ R = genReportReferenceToNullPointer(errorNode, ArgE);
+
+ // Highlight the range of the argument that was null.
+ R->addRange(Call.getArgSourceRange(idx));
+
+ // Emit the bug report.
+ C.emitReport(R);
+ }
+
+ // Always return. Either we cached out or we just emitted an error.
+ return;
+ }
+
+ // If a pointer value passed the check we should assume that it is
+ // indeed not null from this point forward.
+ assert(stateNotNull);
+ state = stateNotNull;
+ }
+
+ // If we reach here all of the arguments passed the nonnull check.
+ // If 'state' has been updated generated a new node.
+ C.addTransition(state);
+}
+
+BugReport *NonNullParamChecker::genReportNullAttrNonNull(
+ const ExplodedNode *ErrorNode, const Expr *ArgE) const {
+ // Lazily allocate the BugType object if it hasn't already been
+ // created. Ownership is transferred to the BugReporter object once
+ // the BugReport is passed to 'EmitWarning'.
+ if (!BTAttrNonNull)
+ BTAttrNonNull.reset(new BugType(
+ "Argument with 'nonnull' attribute passed null",
+ "API"));
+
+ BugReport *R = new BugReport(*BTAttrNonNull,
+ "Null pointer passed as an argument to a 'nonnull' parameter",
+ ErrorNode);
+ if (ArgE)
+ bugreporter::trackNullOrUndefValue(ErrorNode, ArgE, *R);
+
+ return R;
+}
+
+BugReport *NonNullParamChecker::genReportReferenceToNullPointer(
+ const ExplodedNode *ErrorNode, const Expr *ArgE) const {
+ if (!BTNullRefArg)
+ BTNullRefArg.reset(new BuiltinBug("Dereference of null pointer"));
+
+ BugReport *R = new BugReport(*BTNullRefArg,
+ "Forming reference to null pointer",
+ ErrorNode);
+ if (ArgE) {
+ const Expr *ArgEDeref = bugreporter::getDerefExpr(ArgE);
+ if (ArgEDeref == 0)
+ ArgEDeref = ArgE;
+ bugreporter::trackNullOrUndefValue(ErrorNode,
+ ArgEDeref,
+ *R);
+ }
+ return R;
+
+}
+
+void ento::registerNonNullParamChecker(CheckerManager &mgr) {
+ mgr.registerChecker<NonNullParamChecker>();
+}
diff --git a/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
index 9d84f52..4018a66 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
@@ -14,10 +14,10 @@
#include "ClangSACheckers.h"
#include "clang/AST/StmtObjC.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
using namespace clang;
@@ -42,7 +42,7 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
SVal V = state->getSVal(Ex, C.getLocationContext());
// Uninitialized value used for the mutex?
- if (isa<UndefinedVal>(V)) {
+ if (V.getAs<UndefinedVal>()) {
if (ExplodedNode *N = C.generateSink()) {
if (!BT_undef)
BT_undef.reset(new BuiltinBug("Uninitialized value used as mutex "
@@ -60,7 +60,7 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
// Check for null mutexes.
ProgramStateRef notNullState, nullState;
- llvm::tie(notNullState, nullState) = state->assume(cast<DefinedSVal>(V));
+ llvm::tie(notNullState, nullState) = state->assume(V.castAs<DefinedSVal>());
if (nullState) {
if (!notNullState) {
diff --git a/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
index 63a8480..4a0309d 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
@@ -12,11 +12,11 @@
//
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/Analysis/AnalysisContext.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/Analysis/AnalysisContext.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
index 999c994..b9e96ee 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp
@@ -17,12 +17,12 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/AST/ParentMap.h"
using namespace clang;
using namespace ento;
@@ -72,7 +72,8 @@ void ObjCContainersChecker::addSizeInfo(const Expr *Array, const Expr *Size,
if (!ArraySym)
return;
- C.addTransition(State->set<ArraySizeMap>(ArraySym, cast<DefinedSVal>(SizeV)));
+ C.addTransition(
+ State->set<ArraySizeMap>(ArraySym, SizeV.castAs<DefinedSVal>()));
return;
}
@@ -125,7 +126,7 @@ void ObjCContainersChecker::checkPreStmt(const CallExpr *CE,
SVal IdxVal = State->getSVal(IdxExpr, C.getLocationContext());
if (IdxVal.isUnknownOrUndef())
return;
- DefinedSVal Idx = cast<DefinedSVal>(IdxVal);
+ DefinedSVal Idx = IdxVal.castAs<DefinedSVal>();
// Now, check if 'Idx in [0, Size-1]'.
const QualType T = IdxExpr->getType();
diff --git a/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp
index e906e8a..789b9f4 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp
@@ -14,30 +14,26 @@
//===----------------------------------------------------------------------===//
#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/Expr.h"
+#include "clang/AST/ExprObjC.h"
#include "clang/AST/RecursiveASTVisitor.h"
-#include "llvm/ADT/SmallString.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallString.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;
+namespace {
+struct SelectorDescriptor {
+ const char *SelectorName;
+ unsigned ArgumentCount;
+};
}
//===----------------------------------------------------------------------===//
@@ -71,9 +67,102 @@ namespace {
class ObjCSuperCallChecker : public Checker<
check::ASTDecl<ObjCImplementationDecl> > {
public:
+ ObjCSuperCallChecker() : IsInitialized(false) {}
+
void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager &Mgr,
BugReporter &BR) const;
+private:
+ bool isCheckableClass(const ObjCImplementationDecl *D,
+ StringRef &SuperclassName) const;
+ void initializeSelectors(ASTContext &Ctx) const;
+ void fillSelectors(ASTContext &Ctx, ArrayRef<SelectorDescriptor> Sel,
+ StringRef ClassName) const;
+ mutable llvm::StringMap<llvm::SmallSet<Selector, 16> > SelectorsForClass;
+ mutable bool IsInitialized;
};
+
+}
+
+/// \brief Determine whether the given class has a superclass that we want
+/// to check. The name of the found superclass is stored in SuperclassName.
+///
+/// \param D The declaration to check for superclasses.
+/// \param[out] SuperclassName On return, the found superclass name.
+bool ObjCSuperCallChecker::isCheckableClass(const ObjCImplementationDecl *D,
+ StringRef &SuperclassName) const {
+ const ObjCInterfaceDecl *ID = D->getClassInterface();
+ for ( ; ID ; ID = ID->getSuperClass())
+ {
+ SuperclassName = ID->getIdentifier()->getName();
+ if (SelectorsForClass.count(SuperclassName))
+ return true;
+ }
+ return false;
+}
+
+void ObjCSuperCallChecker::fillSelectors(ASTContext &Ctx,
+ ArrayRef<SelectorDescriptor> Sel,
+ StringRef ClassName) const {
+ llvm::SmallSet<Selector, 16> &ClassSelectors = SelectorsForClass[ClassName];
+ // Fill the Selectors SmallSet with all selectors we want to check.
+ for (ArrayRef<SelectorDescriptor>::iterator I = Sel.begin(), E = Sel.end();
+ I != E; ++I) {
+ SelectorDescriptor Descriptor = *I;
+ assert(Descriptor.ArgumentCount <= 1); // No multi-argument selectors yet.
+
+ // Get the selector.
+ IdentifierInfo *II = &Ctx.Idents.get(Descriptor.SelectorName);
+
+ Selector Sel = Ctx.Selectors.getSelector(Descriptor.ArgumentCount, &II);
+ ClassSelectors.insert(Sel);
+ }
+}
+
+void ObjCSuperCallChecker::initializeSelectors(ASTContext &Ctx) const {
+
+ { // Initialize selectors for: UIViewController
+ const SelectorDescriptor Selectors[] = {
+ { "addChildViewController", 1 },
+ { "viewDidAppear", 1 },
+ { "viewDidDisappear", 1 },
+ { "viewWillAppear", 1 },
+ { "viewWillDisappear", 1 },
+ { "removeFromParentViewController", 0 },
+ { "didReceiveMemoryWarning", 0 },
+ { "viewDidUnload", 0 },
+ { "viewDidLoad", 0 },
+ { "viewWillUnload", 0 },
+ { "updateViewConstraints", 0 },
+ { "encodeRestorableStateWithCoder", 1 },
+ { "restoreStateWithCoder", 1 }};
+
+ fillSelectors(Ctx, Selectors, "UIViewController");
+ }
+
+ { // Initialize selectors for: UIResponder
+ const SelectorDescriptor Selectors[] = {
+ { "resignFirstResponder", 0 }};
+
+ fillSelectors(Ctx, Selectors, "UIResponder");
+ }
+
+ { // Initialize selectors for: NSResponder
+ const SelectorDescriptor Selectors[] = {
+ { "encodeRestorableStateWithCoder", 1 },
+ { "restoreStateWithCoder", 1 }};
+
+ fillSelectors(Ctx, Selectors, "NSResponder");
+ }
+
+ { // Initialize selectors for: NSDocument
+ const SelectorDescriptor Selectors[] = {
+ { "encodeRestorableStateWithCoder", 1 },
+ { "restoreStateWithCoder", 1 }};
+
+ fillSelectors(Ctx, Selectors, "NSDocument");
+ }
+
+ IsInitialized = true;
}
void ObjCSuperCallChecker::checkASTDecl(const ObjCImplementationDecl *D,
@@ -81,29 +170,15 @@ void ObjCSuperCallChecker::checkASTDecl(const ObjCImplementationDecl *D,
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);
+ // We need to initialize the selector table once.
+ if (!IsInitialized)
+ initializeSelectors(Ctx);
- // Fill the Selectors SmallSet with all selectors we want to check.
- llvm::SmallSet<Selector, 16> Selectors;
- for (size_t i = 0; i < SelectorCount; i++) {
- unsigned ArgumentCount = SelectorArgumentCounts[i];
- const char *SelectorCString = SelectorNames[i];
+ // Find out whether this class has a superclass that we are supposed to check.
+ StringRef SuperclassName;
+ if (!isCheckableClass(D, SuperclassName))
+ return;
- // 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(),
@@ -111,7 +186,7 @@ void ObjCSuperCallChecker::checkASTDecl(const ObjCImplementationDecl *D,
I != E; ++I) {
Selector S = (*I)->getSelector();
// Find out whether this is a selector that we want to check.
- if (!Selectors.count(S))
+ if (!SelectorsForClass[SuperclassName].count(S))
continue;
ObjCMethodDecl *MD = *I;
@@ -130,12 +205,12 @@ void ObjCSuperCallChecker::checkASTDecl(const ObjCImplementationDecl *D,
Mgr.getAnalysisDeclContext(D));
const char *Name = "Missing call to superclass";
- SmallString<256> Buf;
+ SmallString<320> Buf;
llvm::raw_svector_ostream os(Buf);
os << "The '" << S.getAsString()
- << "' instance method in UIViewController subclass '" << *D
- << "' is missing a [super " << S.getAsString() << "] call";
+ << "' instance method in " << SuperclassName.str() << " subclass '"
+ << *D << "' is missing a [super " << S.getAsString() << "] call";
BR.EmitBasicReport(MD, Name, categories::CoreFoundationObjectiveC,
os.str(), DLoc);
@@ -161,15 +236,6 @@ void ento::registerObjCSuperCallChecker(CheckerManager &Mgr) {
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)
diff --git a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
index 98d2a85a..8506e08 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
@@ -37,13 +37,14 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/AST/ParentMap.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -122,9 +123,10 @@ static SelfFlagEnum getSelfFlags(SVal val, CheckerContext &C) {
static void addSelfFlag(ProgramStateRef state, SVal val,
SelfFlagEnum flag, CheckerContext &C) {
// We tag the symbol that the SVal wraps.
- if (SymbolRef sym = val.getAsSymbol())
+ if (SymbolRef sym = val.getAsSymbol()) {
state = state->set<SelfFlag>(sym, getSelfFlags(val, state) | flag);
- C.addTransition(state);
+ C.addTransition(state);
+ }
}
static bool hasSelfFlag(SVal val, SelfFlagEnum flag, CheckerContext &C) {
@@ -253,7 +255,7 @@ void ObjCSelfInitChecker::checkPreCall(const CallEvent &CE,
for (unsigned i = 0; i < NumArgs; ++i) {
SVal argV = CE.getArgSVal(i);
if (isSelfVar(argV, C)) {
- unsigned selfFlags = getSelfFlags(state->getSVal(cast<Loc>(argV)), C);
+ unsigned selfFlags = getSelfFlags(state->getSVal(argV.castAs<Loc>()), C);
C.addTransition(state->set<PreCallSelfFlags>(selfFlags));
return;
} else if (hasSelfFlag(argV, SelfFlag_Self, C)) {
@@ -284,7 +286,7 @@ void ObjCSelfInitChecker::checkPostCall(const CallEvent &CE,
// If the address of 'self' is being passed to the call, assume that the
// 'self' after the call will have the same flags.
// EX: log(&self)
- addSelfFlag(state, state->getSVal(cast<Loc>(argV)), prevFlags, C);
+ addSelfFlag(state, state->getSVal(argV.castAs<Loc>()), prevFlags, C);
return;
} else if (hasSelfFlag(argV, SelfFlag_Self, C)) {
// If 'self' is passed to the call by value, assume that the function
@@ -302,11 +304,16 @@ void ObjCSelfInitChecker::checkPostCall(const CallEvent &CE,
void ObjCSelfInitChecker::checkLocation(SVal location, bool isLoad,
const Stmt *S,
CheckerContext &C) const {
+ if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>(
+ C.getCurrentAnalysisDeclContext()->getDecl())))
+ return;
+
// Tag the result of a load from 'self' so that we can easily know that the
// value is the object that 'self' points to.
ProgramStateRef state = C.getState();
if (isSelfVar(location, C))
- addSelfFlag(state, state->getSVal(cast<Loc>(location)), SelfFlag_Self, C);
+ addSelfFlag(state, state->getSVal(location.castAs<Loc>()), SelfFlag_Self,
+ C);
}
@@ -411,10 +418,10 @@ static bool isSelfVar(SVal location, CheckerContext &C) {
AnalysisDeclContext *analCtx = C.getCurrentAnalysisDeclContext();
if (!analCtx->getSelfDecl())
return false;
- if (!isa<loc::MemRegionVal>(location))
+ if (!location.getAs<loc::MemRegionVal>())
return false;
- loc::MemRegionVal MRV = cast<loc::MemRegionVal>(location);
+ loc::MemRegionVal MRV = location.castAs<loc::MemRegionVal>();
if (const DeclRegion *DR = dyn_cast<DeclRegion>(MRV.stripCasts()))
return (DR->getDecl() == analCtx->getSelfDecl());
diff --git a/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp
index 582269c..c66c7d0 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp
@@ -14,14 +14,15 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/Checker.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/Attr.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprObjC.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
using namespace clang;
using namespace ento;
@@ -88,10 +89,11 @@ static void Scan(IvarUsageMap& M, const ObjCContainerDecl *D) {
Scan(M, *I);
// Scan the associated categories as well.
- for (const ObjCCategoryDecl *CD =
- ID->getClassInterface()->getCategoryList(); CD ;
- CD = CD->getNextClassCategory()) {
- if (const ObjCCategoryImplDecl *CID = CD->getImplementation())
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = ID->getClassInterface()->visible_categories_begin(),
+ CatEnd = ID->getClassInterface()->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
+ if (const ObjCCategoryImplDecl *CID = Cat->getImplementation())
Scan(M, CID);
}
}
diff --git a/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp b/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
index b5d9959..bcbfacd 100644
--- a/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
@@ -13,10 +13,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
using namespace clang;
using namespace ento;
diff --git a/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
index 47da87f..07c82d4 100644
--- a/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
@@ -14,10 +14,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
using namespace clang;
using namespace ento;
diff --git a/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp b/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
index d9b6384..ffb8cf2 100644
--- a/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
@@ -13,10 +13,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "llvm/ADT/ImmutableList.h"
@@ -98,7 +98,7 @@ void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
if (X.isUnknownOrUndef())
return;
- DefinedSVal retVal = cast<DefinedSVal>(X);
+ DefinedSVal retVal = X.castAs<DefinedSVal>();
if (state->contains<LockSet>(lockR)) {
if (!BT_doublelock)
diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
index 304051c..79409e8 100644
--- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
@@ -13,16 +13,17 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
-#include "clang/AST/ParentMap.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
@@ -31,8 +32,8 @@
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableList.h"
#include "llvm/ADT/ImmutableMap.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include <cstdarg>
@@ -49,7 +50,6 @@ using llvm::StrInStrNoCase;
enum ArgEffect { DoNothing, Autorelease, Dealloc, DecRef, DecRefMsg,
DecRefBridgedTransfered,
IncRefMsg, IncRef, MakeCollectable, MayEscape,
- NewAutoreleasePool,
// Stop tracking the argument - the effect of the call is
// unknown.
@@ -782,6 +782,10 @@ public:
const RetainSummary *getStandardMethodSummary(const ObjCMethodDecl *MD,
Selector S, QualType RetTy);
+ /// Determine if there is a special return effect for this function or method.
+ Optional<RetEffect> getRetEffectFromAnnotations(QualType RetTy,
+ const Decl *D);
+
void updateSummaryFromAnnotations(const RetainSummary *&Summ,
const ObjCMethodDecl *MD);
@@ -894,7 +898,6 @@ static ArgEffect getStopTrackingHardEquivalent(ArgEffect E) {
case IncRefMsg:
case MakeCollectable:
case MayEscape:
- case NewAutoreleasePool:
case StopTracking:
case StopTrackingHard:
return StopTrackingHard;
@@ -1134,12 +1137,7 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
if (S)
break;
- if (RetTy->isPointerType()) {
- if (FD->getAttr<CFAuditedTransferAttr>()) {
- S = getCFCreateGetRuleSummary(FD);
- break;
- }
-
+ if (RetTy->isPointerType()) {
// For CoreFoundation ('CF') types.
if (cocoa::isRefType(RetTy, "CF", FName)) {
if (isRetain(FD, FName))
@@ -1170,6 +1168,11 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
break;
}
+ if (FD->getAttr<CFAuditedTransferAttr>()) {
+ S = getCFCreateGetRuleSummary(FD);
+ break;
+ }
+
break;
}
@@ -1272,6 +1275,30 @@ RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl *FD) {
// Summary creation for Selectors.
//===----------------------------------------------------------------------===//
+Optional<RetEffect>
+RetainSummaryManager::getRetEffectFromAnnotations(QualType RetTy,
+ const Decl *D) {
+ if (cocoa::isCocoaObjectRef(RetTy)) {
+ if (D->getAttr<NSReturnsRetainedAttr>())
+ return ObjCAllocRetE;
+
+ if (D->getAttr<NSReturnsNotRetainedAttr>() ||
+ D->getAttr<NSReturnsAutoreleasedAttr>())
+ return RetEffect::MakeNotOwned(RetEffect::ObjC);
+
+ } else if (!RetTy->isPointerType()) {
+ return None;
+ }
+
+ if (D->getAttr<CFReturnsRetainedAttr>())
+ return RetEffect::MakeOwned(RetEffect::CF, true);
+
+ if (D->getAttr<CFReturnsNotRetainedAttr>())
+ return RetEffect::MakeNotOwned(RetEffect::CF);
+
+ return None;
+}
+
void
RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
const FunctionDecl *FD) {
@@ -1286,39 +1313,15 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
for (FunctionDecl::param_const_iterator pi = FD->param_begin(),
pe = FD->param_end(); pi != pe; ++pi, ++parm_idx) {
const ParmVarDecl *pd = *pi;
- if (pd->getAttr<NSConsumedAttr>()) {
- if (!GCEnabled) {
- Template->addArg(AF, parm_idx, DecRef);
- }
- } else if (pd->getAttr<CFConsumedAttr>()) {
+ if (pd->getAttr<NSConsumedAttr>())
+ Template->addArg(AF, parm_idx, DecRefMsg);
+ else if (pd->getAttr<CFConsumedAttr>())
Template->addArg(AF, parm_idx, DecRef);
- }
}
QualType RetTy = FD->getResultType();
-
- // Determine if there is a special return effect for this method.
- if (cocoa::isCocoaObjectRef(RetTy)) {
- if (FD->getAttr<NSReturnsRetainedAttr>()) {
- Template->setRetEffect(ObjCAllocRetE);
- }
- else if (FD->getAttr<CFReturnsRetainedAttr>()) {
- Template->setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
- }
- else if (FD->getAttr<NSReturnsNotRetainedAttr>()) {
- Template->setRetEffect(RetEffect::MakeNotOwned(RetEffect::ObjC));
- }
- else if (FD->getAttr<CFReturnsNotRetainedAttr>()) {
- Template->setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF));
- }
- } else if (RetTy->getAs<PointerType>()) {
- if (FD->getAttr<CFReturnsRetainedAttr>()) {
- Template->setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
- }
- else if (FD->getAttr<CFReturnsNotRetainedAttr>()) {
- Template->setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF));
- }
- }
+ if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, FD))
+ Template->setRetEffect(*RetE);
}
void
@@ -1329,13 +1332,10 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
assert(Summ && "Must have a valid summary to add annotations to");
RetainSummaryTemplate Template(Summ, *this);
- bool isTrackedLoc = false;
// Effects on the receiver.
- if (MD->getAttr<NSConsumesSelfAttr>()) {
- if (!GCEnabled)
- Template->setReceiverEffect(DecRefMsg);
- }
+ if (MD->getAttr<NSConsumesSelfAttr>())
+ Template->setReceiverEffect(DecRefMsg);
// Effects on the parameters.
unsigned parm_idx = 0;
@@ -1343,37 +1343,16 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
pi=MD->param_begin(), pe=MD->param_end();
pi != pe; ++pi, ++parm_idx) {
const ParmVarDecl *pd = *pi;
- if (pd->getAttr<NSConsumedAttr>()) {
- if (!GCEnabled)
- Template->addArg(AF, parm_idx, DecRef);
- }
- else if(pd->getAttr<CFConsumedAttr>()) {
+ if (pd->getAttr<NSConsumedAttr>())
+ Template->addArg(AF, parm_idx, DecRefMsg);
+ else if (pd->getAttr<CFConsumedAttr>()) {
Template->addArg(AF, parm_idx, DecRef);
}
}
- // Determine if there is a special return effect for this method.
- if (cocoa::isCocoaObjectRef(MD->getResultType())) {
- if (MD->getAttr<NSReturnsRetainedAttr>()) {
- Template->setRetEffect(ObjCAllocRetE);
- return;
- }
- if (MD->getAttr<NSReturnsNotRetainedAttr>()) {
- Template->setRetEffect(RetEffect::MakeNotOwned(RetEffect::ObjC));
- return;
- }
-
- isTrackedLoc = true;
- } else {
- isTrackedLoc = MD->getResultType()->getAs<PointerType>() != NULL;
- }
-
- if (isTrackedLoc) {
- if (MD->getAttr<CFReturnsRetainedAttr>())
- Template->setRetEffect(RetEffect::MakeOwned(RetEffect::CF, true));
- else if (MD->getAttr<CFReturnsNotRetainedAttr>())
- Template->setRetEffect(RetEffect::MakeNotOwned(RetEffect::CF));
- }
+ QualType RetTy = MD->getResultType();
+ if (Optional<RetEffect> RetE = getRetEffectFromAnnotations(RetTy, MD))
+ Template->setRetEffect(*RetE);
}
const RetainSummary *
@@ -1567,10 +1546,6 @@ void RetainSummaryManager::InitializeMethodSummaries() {
Summ = getPersistentSummary(NoRet, DecRefMsg);
addNSObjectMethSummary(GetNullarySelector("release", Ctx), Summ);
- // Create the "drain" selector.
- Summ = getPersistentSummary(NoRet, isGCEnabled() ? DoNothing : DecRef);
- addNSObjectMethSummary(GetNullarySelector("drain", Ctx), Summ);
-
// Create the -dealloc summary.
Summ = getPersistentSummary(NoRet, Dealloc);
addNSObjectMethSummary(GetNullarySelector("dealloc", Ctx), Summ);
@@ -1579,10 +1554,6 @@ void RetainSummaryManager::InitializeMethodSummaries() {
Summ = getPersistentSummary(NoRet, Autorelease);
addNSObjectMethSummary(GetNullarySelector("autorelease", Ctx), Summ);
- // Specially handle NSAutoreleasePool.
- addInstMethSummary("NSAutoreleasePool", "init",
- getPersistentSummary(NoRet, NewAutoreleasePool));
-
// For NSWindow, allocated objects are (initially) self-owned.
// FIXME: For now we opt for false negatives with NSWindow, as these objects
// self-own themselves. However, they only do this once they are displayed.
@@ -1601,10 +1572,11 @@ void RetainSummaryManager::InitializeMethodSummaries() {
// as for NSWindow objects.
addClassMethSummary("NSPanel", "alloc", NoTrackYet);
- // Don't track allocated autorelease pools yet, as it is okay to prematurely
+ // Don't track allocated autorelease pools, as it is okay to prematurely
// exit a method.
addClassMethSummary("NSAutoreleasePool", "alloc", NoTrackYet);
addClassMethSummary("NSAutoreleasePool", "allocWithZone", NoTrackYet, false);
+ addClassMethSummary("NSAutoreleasePool", "new", NoTrackYet);
// Create summaries QCRenderer/QCView -createSnapShotImageOfType:
addInstMethSummary("QCRenderer", AllocSumm,
@@ -1872,7 +1844,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
BugReport &BR) {
// FIXME: We will eventually need to handle non-statement-based events
// (__attribute__((cleanup))).
- if (!isa<StmtPoint>(N->getLocation()))
+ if (!N->getLocation().getAs<StmtPoint>())
return NULL;
// Check if the type state has changed.
@@ -1894,7 +1866,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
// This is the allocation site since the previous node had no bindings
// for this symbol.
if (!PrevT) {
- const Stmt *S = cast<StmtPoint>(N->getLocation()).getStmt();
+ const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
if (isa<ObjCArrayLiteral>(S)) {
os << "NSArray literal is an object with a +0 retain count";
@@ -1984,7 +1956,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
if (const RetainSummary *Summ = SummaryLog.lookup(OrigNode)) {
// We only have summaries attached to nodes after evaluating CallExpr and
// ObjCMessageExprs.
- const Stmt *S = cast<StmtPoint>(N->getLocation()).getStmt();
+ const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
// Iterate through the parameter expressions and see if the symbol
@@ -2033,7 +2005,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
// Specially handle CFMakeCollectable and friends.
if (contains(AEffects, MakeCollectable)) {
// Get the name of the function.
- const Stmt *S = cast<StmtPoint>(N->getLocation()).getStmt();
+ const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
SVal X =
CurrSt->getSValAsScalarOrLoc(cast<CallExpr>(S)->getCallee(), LCtx);
const FunctionDecl *FD = X.getAsFunctionDecl();
@@ -2141,7 +2113,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
if (os.str().empty())
return 0; // We have nothing to say!
- const Stmt *S = cast<StmtPoint>(N->getLocation()).getStmt();
+ const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
N->getLocationContext());
PathDiagnosticPiece *P = new PathDiagnosticEventPiece(Pos, os.str());
@@ -2278,7 +2250,7 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
}
}
else if (RV->getKind() == RefVal::ErrorGCLeakReturned) {
- ObjCMethodDecl &MD = cast<ObjCMethodDecl>(EndN->getCodeDecl());
+ const ObjCMethodDecl &MD = cast<ObjCMethodDecl>(EndN->getCodeDecl());
os << " and returned from method '" << MD.getSelector().getAsString()
<< "' is potentially leaked when using garbage collection. Callers "
"of this method do not expect a returned object with a +1 retain "
@@ -2318,10 +2290,10 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts,
// implicit call. (Currently there are no such allocations in Cocoa, though.)
const Stmt *AllocStmt;
ProgramPoint P = AllocNode->getLocation();
- if (CallExitEnd *Exit = dyn_cast<CallExitEnd>(&P))
+ if (Optional<CallExitEnd> Exit = P.getAs<CallExitEnd>())
AllocStmt = Exit->getCalleeContext()->getCallSite();
else
- AllocStmt = cast<PostStmt>(P).getStmt();
+ AllocStmt = P.castAs<PostStmt>().getStmt();
assert(AllocStmt && "All allocations must come from explicit calls");
Location = PathDiagnosticLocation::createBegin(AllocStmt, SMgr,
n->getLocationContext());
@@ -2349,7 +2321,7 @@ class RetainCountChecker
: public Checker< check::Bind,
check::DeadSymbols,
check::EndAnalysis,
- check::EndPath,
+ check::EndFunction,
check::PostStmt<BlockExpr>,
check::PostStmt<CastExpr>,
check::PostStmt<ObjCArrayLiteral>,
@@ -2511,7 +2483,7 @@ public:
ProgramStateRef
checkRegionChanges(ProgramStateRef state,
- const StoreManager::InvalidatedSymbols *invalidated,
+ const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
const CallEvent *Call) const;
@@ -2526,7 +2498,7 @@ public:
SymbolRef Sym, ProgramStateRef state) const;
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
- void checkEndPath(CheckerContext &C) const;
+ void checkEndFunction(CheckerContext &C) const;
ProgramStateRef updateSymbol(ProgramStateRef state, SymbolRef sym,
RefVal V, ArgEffect E, RefVal::Kind &hasErr,
@@ -2544,7 +2516,7 @@ public:
SymbolRef sid, RefVal V,
SmallVectorImpl<SymbolRef> &Leaked) const;
- std::pair<ExplodedNode *, ProgramStateRef >
+ ProgramStateRef
handleAutoreleaseCounts(ProgramStateRef state, ExplodedNode *Pred,
const ProgramPointTag *Tag, CheckerContext &Ctx,
SymbolRef Sym, RefVal V) const;
@@ -2601,7 +2573,7 @@ void RetainCountChecker::checkPostStmt(const BlockExpr *BE,
MemRegionManager &MemMgr = C.getSValBuilder().getRegionManager();
for ( ; I != E; ++I) {
- const VarRegion *VR = *I;
+ const VarRegion *VR = I.getCapturedRegion();
if (VR->getSuperRegion() == R) {
VR = MemMgr.getVarRegion(VR->getDecl(), LC);
}
@@ -2940,9 +2912,6 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym,
case MakeCollectable:
E = C.isObjCGCEnabled() ? DecRef : DoNothing;
break;
- case NewAutoreleasePool:
- E = C.isObjCGCEnabled() ? DoNothing : NewAutoreleasePool;
- break;
}
// Handle all use-after-releases.
@@ -2982,10 +2951,6 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym,
}
break;
- case NewAutoreleasePool:
- assert(!C.isObjCGCEnabled());
- return state;
-
case MayEscape:
if (V.getKind() == RefVal::Owned) {
V = V ^ RefVal::NotOwned;
@@ -3175,7 +3140,8 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
Binding = getRefBinding(state, Sym);
// Invalidate the argument region.
- state = state->invalidateRegions(ArgRegion, CE, C.blockCount(), LCtx);
+ state = state->invalidateRegions(ArgRegion, CE, C.blockCount(), LCtx,
+ /*CausesPointerEscape*/ false);
// Restore the refcount status of the argument.
if (Binding)
@@ -3259,11 +3225,10 @@ void RetainCountChecker::checkPreStmt(const ReturnStmt *S,
// Update the autorelease counts.
static SimpleProgramPointTag
AutoreleaseTag("RetainCountChecker : Autorelease");
- llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Pred, &AutoreleaseTag,
- C, Sym, X);
+ state = handleAutoreleaseCounts(state, Pred, &AutoreleaseTag, C, Sym, X);
// Did we cache out?
- if (!Pred)
+ if (!state)
return;
// Get the updated binding.
@@ -3374,7 +3339,7 @@ void RetainCountChecker::checkBind(SVal loc, SVal val, const Stmt *S,
// does not understand.
ProgramStateRef state = C.getState();
- if (loc::MemRegionVal *regionLoc = dyn_cast<loc::MemRegionVal>(&loc)) {
+ if (Optional<loc::MemRegionVal> regionLoc = loc.getAs<loc::MemRegionVal>()) {
escapes = !regionLoc->getRegion()->hasStackStorage();
if (!escapes) {
@@ -3443,7 +3408,7 @@ ProgramStateRef RetainCountChecker::evalAssume(ProgramStateRef state,
ProgramStateRef
RetainCountChecker::checkRegionChanges(ProgramStateRef state,
- const StoreManager::InvalidatedSymbols *invalidated,
+ const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions,
const CallEvent *Call) const {
@@ -3457,7 +3422,7 @@ RetainCountChecker::checkRegionChanges(ProgramStateRef state,
WhitelistedSymbols.insert(SR->getSymbol());
}
- for (StoreManager::InvalidatedSymbols::const_iterator I=invalidated->begin(),
+ for (InvalidatedSymbols::const_iterator I=invalidated->begin(),
E = invalidated->end(); I!=E; ++I) {
SymbolRef sym = *I;
if (WhitelistedSymbols.count(sym))
@@ -3472,8 +3437,8 @@ RetainCountChecker::checkRegionChanges(ProgramStateRef state,
// Handle dead symbols and end-of-path.
//===----------------------------------------------------------------------===//
-std::pair<ExplodedNode *, ProgramStateRef >
-RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
+ProgramStateRef
+RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
ExplodedNode *Pred,
const ProgramPointTag *Tag,
CheckerContext &Ctx,
@@ -3482,7 +3447,7 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
// No autorelease counts? Nothing to be done.
if (!ACnt)
- return std::make_pair(Pred, state);
+ return state;
assert(!Ctx.isObjCGCEnabled() && "Autorelease counts in GC mode?");
unsigned Cnt = V.getCount();
@@ -3500,14 +3465,10 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
else
V = V ^ RefVal::NotOwned;
} else {
- V.setCount(Cnt - ACnt);
+ V.setCount(V.getCount() - ACnt);
V.setAutoreleaseCount(0);
}
- state = setRefBinding(state, Sym, V);
- ExplodedNode *N = Ctx.addTransition(state, Pred, Tag);
- if (N == 0)
- state = 0;
- return std::make_pair(N, state);
+ return setRefBinding(state, Sym, V);
}
// Woah! More autorelease counts then retain counts left.
@@ -3534,7 +3495,7 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
Ctx.emitReport(report);
}
- return std::make_pair((ExplodedNode *)0, (ProgramStateRef )0);
+ return 0;
}
ProgramStateRef
@@ -3559,9 +3520,6 @@ RetainCountChecker::processLeaks(ProgramStateRef state,
SmallVectorImpl<SymbolRef> &Leaked,
CheckerContext &Ctx,
ExplodedNode *Pred) const {
- if (Leaked.empty())
- return Pred;
-
// Generate an intermediate node representing the leak point.
ExplodedNode *N = Ctx.addTransition(state, Pred);
@@ -3584,14 +3542,14 @@ RetainCountChecker::processLeaks(ProgramStateRef state,
return N;
}
-void RetainCountChecker::checkEndPath(CheckerContext &Ctx) const {
+void RetainCountChecker::checkEndFunction(CheckerContext &Ctx) const {
ProgramStateRef state = Ctx.getState();
RefBindingsTy B = state->get<RefBindings>();
ExplodedNode *Pred = Ctx.getPredecessor();
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);
+ state = handleAutoreleaseCounts(state, Pred, /*Tag=*/0, Ctx,
+ I->first, I->second);
if (!state)
return;
}
@@ -3631,6 +3589,7 @@ void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper,
ProgramStateRef state = C.getState();
RefBindingsTy B = state->get<RefBindings>();
+ SmallVector<SymbolRef, 10> Leaked;
// Update counts from autorelease pools
for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
@@ -3640,20 +3599,19 @@ void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper,
// Use the symbol as the tag.
// FIXME: This might not be as unique as we would like.
const ProgramPointTag *Tag = getDeadSymbolTag(Sym);
- llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Pred, Tag, C,
- Sym, *T);
+ state = handleAutoreleaseCounts(state, Pred, Tag, C, Sym, *T);
if (!state)
return;
+
+ // Fetch the new reference count from the state, and use it to handle
+ // this symbol.
+ state = handleSymbolDeath(state, *I, *getRefBinding(state, Sym), Leaked);
}
}
- B = state->get<RefBindings>();
- SmallVector<SymbolRef, 10> Leaked;
-
- for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
- E = SymReaper.dead_end(); I != E; ++I) {
- if (const RefVal *T = B.lookup(*I))
- state = handleSymbolDeath(state, *I, *T, Leaked);
+ if (Leaked.empty()) {
+ C.addTransition(state);
+ return;
}
Pred = processLeaks(state, Leaked, C, Pred);
@@ -3663,10 +3621,13 @@ void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper,
return;
// Now generate a new node that nukes the old bindings.
+ // The only bindings left at this point are the leaked symbols.
RefBindingsTy::Factory &F = state->get_context<RefBindings>();
+ B = state->get<RefBindings>();
- for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
- E = SymReaper.dead_end(); I != E; ++I)
+ for (SmallVectorImpl<SymbolRef>::iterator I = Leaked.begin(),
+ E = Leaked.end();
+ I != E; ++I)
B = F.remove(B, *I);
state = state->set<RefBindings>(B);
@@ -3678,8 +3639,10 @@ void RetainCountChecker::printState(raw_ostream &Out, ProgramStateRef State,
RefBindingsTy B = State->get<RefBindings>();
- if (!B.isEmpty())
- Out << Sep << NL;
+ if (B.isEmpty())
+ return;
+
+ Out << Sep << NL;
for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
Out << I->first << " : ";
diff --git a/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp b/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
index f3560aa..fe253b7 100644
--- a/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
@@ -13,10 +13,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
using namespace clang;
@@ -46,7 +46,7 @@ void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS,
if (!ER)
return;
- DefinedOrUnknownSVal Idx = cast<DefinedOrUnknownSVal>(ER->getIndex());
+ DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>();
// Zero index is always in bound, this also passes ElementRegions created for
// pointer casts.
if (Idx.isZeroConstant())
diff --git a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
index 37ec1aa..7a5d993 100644
--- a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
@@ -14,19 +14,23 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
using namespace clang;
using namespace ento;
namespace {
-class ReturnUndefChecker :
- public Checker< check::PreStmt<ReturnStmt> > {
- mutable OwningPtr<BuiltinBug> BT;
+class ReturnUndefChecker : public Checker< check::PreStmt<ReturnStmt> > {
+ mutable OwningPtr<BuiltinBug> BT_Undef;
+ mutable OwningPtr<BuiltinBug> BT_NullReference;
+
+ void emitUndef(CheckerContext &C, const Expr *RetE) const;
+ void checkReference(CheckerContext &C, const Expr *RetE,
+ DefinedOrUnknownSVal RetVal) const;
public:
void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
};
@@ -34,43 +38,75 @@ public:
void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS,
CheckerContext &C) const {
-
const Expr *RetE = RS->getRetValue();
if (!RetE)
return;
-
- 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();
- // }
+ SVal RetVal = C.getSVal(RetE);
+
const StackFrameContext *SFC = C.getStackFrame();
QualType RT = CallEvent::getDeclaredResultType(SFC->getDecl());
- if (!RT.isNull() && RT->isSpecificBuiltinType(BuiltinType::Void))
+
+ if (RetVal.isUndef()) {
+ // "return;" is modeled to evaluate to an UndefinedVal. Allow UndefinedVal
+ // to be returned in functions returning void to support this pattern:
+ // void foo() {
+ // return;
+ // }
+ // void test() {
+ // return foo();
+ // }
+ if (RT.isNull() || !RT->isVoidType())
+ emitUndef(C, RetE);
return;
+ }
- ExplodedNode *N = C.generateSink();
+ if (RT.isNull())
+ return;
+
+ if (RT->isReferenceType()) {
+ checkReference(C, RetE, RetVal.castAs<DefinedOrUnknownSVal>());
+ return;
+ }
+}
+static void emitBug(CheckerContext &C, BuiltinBug &BT, const Expr *RetE,
+ const Expr *TrackingE = 0) {
+ ExplodedNode *N = C.generateSink();
if (!N)
return;
-
- if (!BT)
- BT.reset(new BuiltinBug("Garbage return value",
- "Undefined or garbage value returned to caller"));
-
- BugReport *report =
- new BugReport(*BT, BT->getDescription(), N);
-
- report->addRange(RetE->getSourceRange());
- bugreporter::trackNullOrUndefValue(N, RetE, *report);
-
- C.emitReport(report);
+
+ BugReport *Report = new BugReport(BT, BT.getDescription(), N);
+
+ Report->addRange(RetE->getSourceRange());
+ bugreporter::trackNullOrUndefValue(N, TrackingE ? TrackingE : RetE, *Report);
+
+ C.emitReport(Report);
+}
+
+void ReturnUndefChecker::emitUndef(CheckerContext &C, const Expr *RetE) const {
+ if (!BT_Undef)
+ BT_Undef.reset(new BuiltinBug("Garbage return value",
+ "Undefined or garbage value "
+ "returned to caller"));
+ emitBug(C, *BT_Undef, RetE);
+}
+
+void ReturnUndefChecker::checkReference(CheckerContext &C, const Expr *RetE,
+ DefinedOrUnknownSVal RetVal) const {
+ ProgramStateRef StNonNull, StNull;
+ llvm::tie(StNonNull, StNull) = C.getState()->assume(RetVal);
+
+ if (StNonNull) {
+ // Going forward, assume the location is non-null.
+ C.addTransition(StNonNull);
+ return;
+ }
+
+ // The return value is known to be null. Emit a bug report.
+ if (!BT_NullReference)
+ BT_NullReference.reset(new BuiltinBug("Returning null reference"));
+
+ emitBug(C, *BT_NullReference, RetE, bugreporter::getDerefExpr(RetE));
}
void ento::registerReturnUndefChecker(CheckerManager &mgr) {
diff --git a/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp b/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
index ee055ad..1ccf339 100644
--- a/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
@@ -16,8 +16,8 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
@@ -25,7 +25,7 @@ using namespace clang;
using namespace ento;
namespace {
-typedef llvm::SmallVector<SymbolRef, 2> SymbolVector;
+typedef SmallVector<SymbolRef, 2> SymbolVector;
struct StreamState {
private:
@@ -50,8 +50,7 @@ public:
class SimpleStreamChecker : public Checker<check::PostCall,
check::PreCall,
check::DeadSymbols,
- check::Bind,
- check::RegionChanges> {
+ check::PointerEscape> {
mutable IdentifierInfo *IIfopen, *IIfclose;
@@ -80,20 +79,11 @@ public:
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
- /// Deal with symbol escape as a byproduct of a bind.
- void checkBind(SVal location, SVal val, const Stmt*S,
- CheckerContext &C) const;
-
- /// Deal with symbol escape as a byproduct of a region change.
- ProgramStateRef
- checkRegionChanges(ProgramStateRef state,
- const StoreManager::InvalidatedSymbols *invalidated,
- ArrayRef<const MemRegion *> ExplicitRegions,
- ArrayRef<const MemRegion *> Regions,
- const CallEvent *Call) const;
- bool wantsRegionChangeUpdate(ProgramStateRef state) const {
- return true;
- }
+ /// Stop tracking addresses which escape.
+ ProgramStateRef checkPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind) const;
};
} // end anonymous namespace
@@ -237,7 +227,7 @@ void SimpleStreamChecker::reportLeaks(SymbolVector LeakedStreams,
ExplodedNode *ErrNode) const {
// Attach bug reports to the leak node.
// TODO: Identify the leaked file descriptor.
- for (llvm::SmallVector<SymbolRef, 2>::iterator
+ for (SmallVector<SymbolRef, 2>::iterator
I = LeakedStreams.begin(), E = LeakedStreams.end(); I != E; ++I) {
BugReport *R = new BugReport(*LeakBugType,
"Opened file is never closed; potential resource leak", ErrNode);
@@ -246,45 +236,6 @@ void SimpleStreamChecker::reportLeaks(SymbolVector LeakedStreams,
}
}
-// Check various ways a symbol can be invalidated.
-// Stop tracking symbols when a value escapes as a result of checkBind.
-// A value escapes in three possible cases:
-// (1) We are binding to something that is not a memory region.
-// (2) We are binding to a MemRegion that does not have stack storage
-// (3) We are binding to a MemRegion with stack storage that the store
-// does not understand.
-void SimpleStreamChecker::checkBind(SVal loc, SVal val, const Stmt *S,
- CheckerContext &C) const {
- // Are we storing to something that causes the value to "escape"?
- bool escapes = true;
- ProgramStateRef state = C.getState();
-
- if (loc::MemRegionVal *regionLoc = dyn_cast<loc::MemRegionVal>(&loc)) {
- escapes = !regionLoc->getRegion()->hasStackStorage();
-
- if (!escapes) {
- // To test (3), generate a new state with the binding added. If it is
- // the same state, then it escapes (since the store cannot represent
- // the binding). Do this only if we know that the store is not supposed
- // to generate the same state.
- SVal StoredVal = state->getSVal(regionLoc->getRegion());
- if (StoredVal != val)
- escapes = (state == (state->bindLoc(*regionLoc, val)));
- }
- }
-
- // If our store can represent the binding and we aren't storing to something
- // that doesn't have local storage then just return the state and
- // continue as is.
- if (!escapes)
- return;
-
- // Otherwise, find all symbols referenced by 'val' that we are tracking
- // and stop tracking them.
- state = state->scanReachableSymbols<StopTrackingCallback>(val).getState();
- C.addTransition(state);
-}
-
bool SimpleStreamChecker::guaranteedNotToCloseFile(const CallEvent &Call) const{
// If it's not in a system header, assume it might close a file.
if (!Call.isInSystemHeader())
@@ -300,38 +251,28 @@ bool SimpleStreamChecker::guaranteedNotToCloseFile(const CallEvent &Call) const{
return true;
}
-// If the symbol we are tracking is invalidated, do not track the symbol as
+// If the pointer we are tracking escaped, do not track the symbol as
// we cannot reason about it anymore.
ProgramStateRef
-SimpleStreamChecker::checkRegionChanges(ProgramStateRef State,
- const StoreManager::InvalidatedSymbols *invalidated,
- ArrayRef<const MemRegion *> ExplicitRegions,
- ArrayRef<const MemRegion *> Regions,
- const CallEvent *Call) const {
-
- if (!invalidated || invalidated->empty())
+SimpleStreamChecker::checkPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind) const {
+ // If we know that the call cannot close a file, there is nothing to do.
+ if ((Kind == PSK_DirectEscapeOnCall ||
+ Kind == PSK_IndirectEscapeOnCall) &&
+ guaranteedNotToCloseFile(*Call)) {
return State;
-
- // If it's a call which might close the file, we assume that all regions
- // (explicit and implicit) escaped. Otherwise, whitelist explicit pointers
- // (the parameters to the call); we still can track them.
- llvm::SmallPtrSet<SymbolRef, 8> WhitelistedSymbols;
- if (!Call || guaranteedNotToCloseFile(*Call)) {
- for (ArrayRef<const MemRegion *>::iterator I = ExplicitRegions.begin(),
- E = ExplicitRegions.end(); I != E; ++I) {
- if (const SymbolicRegion *R = (*I)->StripCasts()->getAs<SymbolicRegion>())
- WhitelistedSymbols.insert(R->getSymbol());
- }
}
- for (StoreManager::InvalidatedSymbols::const_iterator I=invalidated->begin(),
- E = invalidated->end(); I!=E; ++I) {
- SymbolRef sym = *I;
- if (WhitelistedSymbols.count(sym))
- continue;
+ for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
+ E = Escaped.end();
+ I != E; ++I) {
+ SymbolRef Sym = *I;
+
// The symbol escaped. Optimistically, assume that the corresponding file
// handle will be closed somewhere else.
- State = State->remove<StreamMap>(sym);
+ State = State->remove<StreamMap>(Sym);
}
return State;
}
diff --git a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index 0c2f266..4fd778e 100644
--- a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -13,38 +13,40 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
-#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
namespace {
class StackAddrEscapeChecker : public Checker< check::PreStmt<ReturnStmt>,
- check::EndPath > {
+ check::EndFunction > {
mutable OwningPtr<BuiltinBug> BT_stackleak;
mutable OwningPtr<BuiltinBug> BT_returnstack;
public:
void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
- void checkEndPath(CheckerContext &Ctx) const;
+ void checkEndFunction(CheckerContext &Ctx) const;
private:
void EmitStackError(CheckerContext &C, const MemRegion *R,
const Expr *RetE) const;
- static SourceRange GenName(raw_ostream &os, const MemRegion *R,
- SourceManager &SM);
+ static SourceRange genName(raw_ostream &os, const MemRegion *R,
+ ASTContext &Ctx);
};
}
-SourceRange StackAddrEscapeChecker::GenName(raw_ostream &os,
- const MemRegion *R,
- SourceManager &SM) {
+SourceRange StackAddrEscapeChecker::genName(raw_ostream &os, const MemRegion *R,
+ ASTContext &Ctx) {
// Get the base region, stripping away fields and elements.
R = R->getBaseRegion();
+ SourceManager &SM = Ctx.getSourceManager();
SourceRange range;
os << "Address of ";
@@ -77,8 +79,10 @@ SourceRange StackAddrEscapeChecker::GenName(raw_ostream &os,
range = VR->getDecl()->getSourceRange();
}
else if (const CXXTempObjectRegion *TOR = dyn_cast<CXXTempObjectRegion>(R)) {
- os << "stack memory associated with temporary object of type '"
- << TOR->getValueType().getAsString() << '\'';
+ QualType Ty = TOR->getValueType().getLocalUnqualifiedType();
+ os << "stack memory associated with temporary object of type '";
+ Ty.print(os, Ctx.getPrintingPolicy());
+ os << "'";
range = TOR->getExpr()->getSourceRange();
}
else {
@@ -102,7 +106,7 @@ void StackAddrEscapeChecker::EmitStackError(CheckerContext &C, const MemRegion *
// Generate a report for this bug.
SmallString<512> buf;
llvm::raw_svector_ostream os(buf);
- SourceRange range = GenName(os, R, C.getSourceManager());
+ SourceRange range = genName(os, R, C.getASTContext());
os << " returned to caller";
BugReport *report = new BugReport(*BT_returnstack, os.str(), N);
report->addRange(RetE->getSourceRange());
@@ -155,7 +159,7 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
EmitStackError(C, R, RetE);
}
-void StackAddrEscapeChecker::checkEndPath(CheckerContext &Ctx) const {
+void StackAddrEscapeChecker::checkEndFunction(CheckerContext &Ctx) const {
ProgramStateRef state = Ctx.getState();
// Iterate over all bindings to global variables and see if it contains
@@ -222,8 +226,7 @@ void StackAddrEscapeChecker::checkEndPath(CheckerContext &Ctx) const {
// Generate a report for this bug.
SmallString<512> buf;
llvm::raw_svector_ostream os(buf);
- SourceRange range = GenName(os, cb.V[i].second,
- Ctx.getSourceManager());
+ SourceRange range = genName(os, cb.V[i].second, Ctx.getASTContext());
os << " is still referred to by the global variable '";
const VarRegion *VR = cast<VarRegion>(cb.V[i].first->getBaseRegion());
os << *VR->getDecl()
diff --git a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index c06ba7c..ffdf2d5 100644
--- a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -12,10 +12,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
@@ -57,9 +57,7 @@ struct StreamState {
};
class StreamChecker : public Checker<eval::Call,
- check::DeadSymbols,
- check::EndPath,
- check::PreStmt<ReturnStmt> > {
+ check::DeadSymbols > {
mutable IdentifierInfo *II_fopen, *II_tmpfile, *II_fclose, *II_fread,
*II_fwrite,
*II_fseek, *II_ftell, *II_rewind, *II_fgetpos, *II_fsetpos,
@@ -75,8 +73,6 @@ public:
bool evalCall(const CallExpr *CE, CheckerContext &C) const;
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
- void checkEndPath(CheckerContext &Ctx) const;
- void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
private:
void Fopen(CheckerContext &C, const CallExpr *CE) const;
@@ -214,9 +210,8 @@ void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const {
ProgramStateRef state = C.getState();
SValBuilder &svalBuilder = C.getSValBuilder();
const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
- DefinedSVal RetVal =
- cast<DefinedSVal>(svalBuilder.conjureSymbolVal(0, CE, LCtx,
- C.blockCount()));
+ DefinedSVal RetVal = svalBuilder.conjureSymbolVal(0, CE, LCtx, C.blockCount())
+ .castAs<DefinedSVal>();
state = state->BindExpr(CE, C.getLocationContext(), RetVal);
ConstraintManager &CM = C.getConstraintManager();
@@ -264,7 +259,7 @@ void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) const {
return;
// Check the legality of the 'whence' argument of 'fseek'.
SVal Whence = state->getSVal(CE->getArg(2), C.getLocationContext());
- const nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&Whence);
+ Optional<nonloc::ConcreteInt> CI = Whence.getAs<nonloc::ConcreteInt>();
if (!CI)
return;
@@ -342,7 +337,7 @@ void StreamChecker::Fileno(CheckerContext &C, const CallExpr *CE) const {
ProgramStateRef StreamChecker::CheckNullStream(SVal SV, ProgramStateRef state,
CheckerContext &C) const {
- const DefinedSVal *DV = dyn_cast<DefinedSVal>(&SV);
+ Optional<DefinedSVal> DV = SV.getAs<DefinedSVal>();
if (!DV)
return 0;
@@ -405,9 +400,8 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper,
SymbolRef Sym = *I;
ProgramStateRef state = C.getState();
const StreamState *SS = state->get<StreamMap>(Sym);
- // TODO: Shouldn't we have a continue here?
if (!SS)
- return;
+ continue;
if (SS->isOpened()) {
ExplodedNode *N = C.generateSink();
@@ -423,47 +417,6 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper,
}
}
-void StreamChecker::checkEndPath(CheckerContext &Ctx) const {
- ProgramStateRef state = Ctx.getState();
- StreamMapTy M = state->get<StreamMap>();
-
- for (StreamMapTy::iterator I = M.begin(), E = M.end(); I != E; ++I) {
- StreamState SS = I->second;
- if (SS.isOpened()) {
- ExplodedNode *N = Ctx.addTransition(state);
- if (N) {
- if (!BT_ResourceLeak)
- BT_ResourceLeak.reset(new BuiltinBug("Resource Leak",
- "Opened File never closed. Potential Resource leak."));
- BugReport *R = new BugReport(*BT_ResourceLeak,
- BT_ResourceLeak->getDescription(), N);
- Ctx.emitReport(R);
- }
- }
- }
-}
-
-void StreamChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const {
- const Expr *RetE = S->getRetValue();
- if (!RetE)
- return;
-
- ProgramStateRef state = C.getState();
- SymbolRef Sym = state->getSVal(RetE, C.getLocationContext()).getAsSymbol();
-
- if (!Sym)
- return;
-
- const StreamState *SS = state->get<StreamMap>(Sym);
- if(!SS)
- return;
-
- if (SS->isOpened())
- state = state->set<StreamMap>(Sym, StreamState::getEscaped(S));
-
- C.addTransition(state);
-}
-
void ento::registerStreamChecker(CheckerManager &mgr) {
mgr.registerChecker<StreamChecker>();
}
diff --git a/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp b/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp
index 382be84..264f7f9 100644
--- a/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp
@@ -11,10 +11,10 @@
//
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
using namespace clang;
using namespace ento;
diff --git a/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp b/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp
index b97cd6c..57c9ed4 100644
--- a/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp
@@ -18,16 +18,17 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
namespace {
class TraversalDumper : public Checker< check::BranchCondition,
- check::EndPath > {
+ check::EndFunction > {
public:
void checkBranchCondition(const Stmt *Condition, CheckerContext &C) const;
- void checkEndPath(CheckerContext &C) const;
+ void checkEndFunction(CheckerContext &C) const;
};
}
@@ -49,8 +50,8 @@ void TraversalDumper::checkBranchCondition(const Stmt *Condition,
<< Parent->getStmtClassName() << "\n";
}
-void TraversalDumper::checkEndPath(CheckerContext &C) const {
- llvm::outs() << "--END PATH--\n";
+void TraversalDumper::checkEndFunction(CheckerContext &C) const {
+ llvm::outs() << "--END FUNCTION--\n";
}
void ento::registerTraversalDumper(CheckerManager &mgr) {
@@ -60,9 +61,11 @@ void ento::registerTraversalDumper(CheckerManager &mgr) {
//------------------------------------------------------------------------------
namespace {
-class CallDumper : public Checker< check::PreCall > {
+class CallDumper : public Checker< check::PreCall,
+ check::PostCall > {
public:
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
+ void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
};
}
@@ -79,6 +82,26 @@ void CallDumper::checkPreCall(const CallEvent &Call, CheckerContext &C) const {
Call.dump(llvm::outs());
}
+void CallDumper::checkPostCall(const CallEvent &Call, CheckerContext &C) const {
+ const Expr *CallE = Call.getOriginExpr();
+ if (!CallE)
+ return;
+
+ unsigned Indentation = 0;
+ for (const LocationContext *LC = C.getLocationContext()->getParent();
+ LC != 0; LC = LC->getParent())
+ ++Indentation;
+
+ // It is mildly evil to print directly to llvm::outs() rather than emitting
+ // warnings, but this ensures things do not get filtered out by the rest of
+ // the static analyzer machinery.
+ llvm::outs().indent(Indentation);
+ if (Call.getResultType()->isVoidType())
+ llvm::outs() << "Returning void\n";
+ else
+ llvm::outs() << "Returning " << C.getSVal(CallE) << "\n";
+}
+
void ento::registerCallDumper(CheckerManager &mgr) {
mgr.registerChecker<CallDumper>();
}
diff --git a/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
index 70e141e..8235e68 100644
--- a/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
@@ -13,10 +13,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
using namespace clang;
using namespace ento;
@@ -90,7 +90,7 @@ void UndefBranchChecker::checkBranchCondition(const Stmt *Condition,
ProgramPoint P = PrevN->getLocation();
ProgramStateRef St = N->getState();
- if (PostStmt *PS = dyn_cast<PostStmt>(&P))
+ if (Optional<PostStmt> PS = P.getAs<PostStmt>())
if (PS->getStmt() == Ex)
St = PrevN->getState();
diff --git a/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
index 30ccffa..93812f7 100644
--- a/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
@@ -12,11 +12,12 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/Attr.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
@@ -67,18 +68,15 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
for (; I != E; ++I) {
// This VarRegion is the region associated with the block; we need
// the one associated with the encompassing context.
- const VarRegion *VR = *I;
+ const VarRegion *VR = I.getCapturedRegion();
const VarDecl *VD = VR->getDecl();
if (VD->getAttr<BlocksAttr>() || !VD->hasLocalStorage())
continue;
// Get the VarRegion associated with VD in the local stack frame.
- const LocationContext *LC = C.getLocationContext();
- VR = C.getSValBuilder().getRegionManager().getVarRegion(VD, LC);
- SVal VRVal = state->getSVal(VR);
-
- if (VRVal.isUndef())
+ if (Optional<UndefinedVal> V =
+ state->getSVal(I.getOriginalRegion()).getAs<UndefinedVal>()) {
if (ExplodedNode *N = C.generateSink()) {
if (!BT)
BT.reset(new BuiltinBug("uninitialized variable captured by block"));
@@ -93,11 +91,13 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
BugReport *R = new BugReport(*BT, os.str(), N);
if (const Expr *Ex = FindBlockDeclRefExpr(BE->getBody(), VD))
R->addRange(Ex->getSourceRange());
- R->addVisitor(new FindLastStoreBRVisitor(VRVal, VR));
+ R->addVisitor(new FindLastStoreBRVisitor(*V, VR,
+ /*EnableNullFPSuppression*/false));
R->disablePathPruning();
// need location of block
C.emitReport(R);
}
+ }
}
}
diff --git a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
index 415bab5..6733563 100644
--- a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
@@ -13,12 +13,13 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
diff --git a/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
index b3a83e8..176ee48 100644
--- a/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
@@ -13,10 +13,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
using namespace clang;
using namespace ento;
@@ -34,18 +34,28 @@ public:
void
UndefinedArraySubscriptChecker::checkPreStmt(const ArraySubscriptExpr *A,
CheckerContext &C) const {
- if (C.getState()->getSVal(A->getIdx(), C.getLocationContext()).isUndef()) {
- if (ExplodedNode *N = C.generateSink()) {
- if (!BT)
- BT.reset(new BuiltinBug("Array subscript is undefined"));
-
- // Generate a report for this bug.
- BugReport *R = new BugReport(*BT, BT->getName(), N);
- R->addRange(A->getIdx()->getSourceRange());
- bugreporter::trackNullOrUndefValue(N, A->getIdx(), *R);
- C.emitReport(R);
- }
- }
+ const Expr *Index = A->getIdx();
+ if (!C.getSVal(Index).isUndef())
+ return;
+
+ // Sema generates anonymous array variables for copying array struct fields.
+ // Don't warn if we're in an implicitly-generated constructor.
+ const Decl *D = C.getLocationContext()->getDecl();
+ if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D))
+ if (Ctor->isImplicitlyDefined())
+ return;
+
+ ExplodedNode *N = C.generateSink();
+ if (!N)
+ return;
+ if (!BT)
+ BT.reset(new BuiltinBug("Array subscript is undefined"));
+
+ // Generate a report for this bug.
+ BugReport *R = new BugReport(*BT, BT->getName(), N);
+ R->addRange(A->getIdx()->getSourceRange());
+ bugreporter::trackNullOrUndefValue(N, A->getIdx(), *R);
+ C.emitReport(R);
}
void ento::registerUndefinedArraySubscriptChecker(CheckerManager &mgr) {
diff --git a/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
index 410010a..e04f49c 100644
--- a/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
@@ -13,10 +13,10 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
using namespace clang;
using namespace ento;
diff --git a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index 171e15b..4ea07e2 100644
--- a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -13,20 +13,20 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/raw_ostream.h"
#include <fcntl.h>
using namespace clang;
using namespace ento;
-using llvm::Optional;
namespace {
class UnixAPIChecker : public Checker< check::PreStmt<CallExpr> > {
@@ -102,21 +102,20 @@ void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const {
// Now check if oflags has O_CREAT set.
const Expr *oflagsEx = CE->getArg(1);
const SVal V = state->getSVal(oflagsEx, C.getLocationContext());
- if (!isa<NonLoc>(V)) {
+ if (!V.getAs<NonLoc>()) {
// The case where 'V' can be a location can only be due to a bad header,
// so in this case bail out.
return;
}
- NonLoc oflags = cast<NonLoc>(V);
- NonLoc ocreateFlag =
- cast<NonLoc>(C.getSValBuilder().makeIntVal(Val_O_CREAT.getValue(),
- oflagsEx->getType()));
+ NonLoc oflags = V.castAs<NonLoc>();
+ NonLoc ocreateFlag = C.getSValBuilder()
+ .makeIntVal(Val_O_CREAT.getValue(), oflagsEx->getType()).castAs<NonLoc>();
SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And,
oflags, ocreateFlag,
oflagsEx->getType());
if (maskedFlagsUC.isUnknownOrUndef())
return;
- DefinedSVal maskedFlags = cast<DefinedSVal>(maskedFlagsUC);
+ DefinedSVal maskedFlags = maskedFlagsUC.castAs<DefinedSVal>();
// Check if maskedFlags is non-zero.
ProgramStateRef trueState, falseState;
@@ -201,7 +200,7 @@ static bool IsZeroByteAllocation(ProgramStateRef state,
ProgramStateRef *trueState,
ProgramStateRef *falseState) {
llvm::tie(*trueState, *falseState) =
- state->assume(cast<DefinedSVal>(argVal));
+ state->assume(argVal.castAs<DefinedSVal>());
return (*falseState && !*trueState);
}
diff --git a/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp b/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
index 5a13ed0..91c2ffb 100644
--- a/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
@@ -14,16 +14,16 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
-#include "clang/AST/ParentMap.h"
-#include "clang/Basic/Builtins.h"
-#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallSet.h"
// The number of CFGBlock pointers we want to reserve memory for. This is used
@@ -76,7 +76,7 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
if (!PM)
PM = &LC->getParentMap();
- if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
+ if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
const CFGBlock *CB = BE->getBlock();
reachable.insert(CB->getBlockID());
}
@@ -131,7 +131,7 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
bool foundUnreachable = false;
for (CFGBlock::const_iterator ci = CB->begin(), ce = CB->end();
ci != ce; ++ci) {
- if (const CFGStmt *S = (*ci).getAs<CFGStmt>())
+ if (Optional<CFGStmt> S = (*ci).getAs<CFGStmt>())
if (const CallExpr *CE = dyn_cast<CallExpr>(S->getStmt())) {
if (CE->isBuiltinCall() == Builtin::BI__builtin_unreachable) {
foundUnreachable = true;
@@ -189,7 +189,7 @@ void UnreachableCodeChecker::FindUnreachableEntryPoints(const CFGBlock *CB,
// Find the Stmt* in a CFGBlock for reporting a warning
const Stmt *UnreachableCodeChecker::getUnreachableStmt(const CFGBlock *CB) {
for (CFGBlock::const_iterator I = CB->begin(), E = CB->end(); I != E; ++I) {
- if (const CFGStmt *S = I->getAs<CFGStmt>())
+ if (Optional<CFGStmt> S = I->getAs<CFGStmt>())
return S->getStmt();
}
if (const Stmt *S = CB->getTerminator())
diff --git a/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp b/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
index 58f9ec0..30aef06 100644
--- a/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
@@ -15,13 +15,14 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/CharUnits.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/AST/CharUnits.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -109,7 +110,7 @@ void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
}
// Check if the size is zero.
- DefinedSVal sizeD = cast<DefinedSVal>(sizeV);
+ DefinedSVal sizeD = sizeV.castAs<DefinedSVal>();
ProgramStateRef stateNotZero, stateZero;
llvm::tie(stateNotZero, stateZero) = state->assume(sizeD);
@@ -129,22 +130,22 @@ void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
// Convert the array length to size_t.
SValBuilder &svalBuilder = C.getSValBuilder();
QualType SizeTy = Ctx.getSizeType();
- NonLoc ArrayLength = cast<NonLoc>(svalBuilder.evalCast(sizeD, SizeTy,
- SE->getType()));
+ NonLoc ArrayLength =
+ svalBuilder.evalCast(sizeD, SizeTy, SE->getType()).castAs<NonLoc>();
// Get the element size.
CharUnits EleSize = Ctx.getTypeSizeInChars(VLA->getElementType());
SVal EleSizeVal = svalBuilder.makeIntVal(EleSize.getQuantity(), SizeTy);
// Multiply the array length by the element size.
- SVal ArraySizeVal = svalBuilder.evalBinOpNN(state, BO_Mul, ArrayLength,
- cast<NonLoc>(EleSizeVal), SizeTy);
+ SVal ArraySizeVal = svalBuilder.evalBinOpNN(
+ state, BO_Mul, ArrayLength, EleSizeVal.castAs<NonLoc>(), SizeTy);
// Finally, assume that the array's extent matches the given size.
const LocationContext *LC = C.getLocationContext();
DefinedOrUnknownSVal Extent =
state->getRegion(VD, LC)->getExtent(svalBuilder);
- DefinedOrUnknownSVal ArraySize = cast<DefinedOrUnknownSVal>(ArraySizeVal);
+ DefinedOrUnknownSVal ArraySize = ArraySizeVal.castAs<DefinedOrUnknownSVal>();
DefinedOrUnknownSVal sizeIsKnown =
svalBuilder.evalEQ(state, Extent, ArraySize);
state = state->assume(sizeIsKnown, true);
diff --git a/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp b/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
index bdc9627..06f01ad 100644
--- a/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
@@ -15,11 +15,12 @@
#include "ClangSACheckers.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/StmtVisitor.h"
-#include "llvm/Support/SaveAndRestore.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
-#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/SaveAndRestore.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
diff --git a/lib/StaticAnalyzer/Core/APSIntType.cpp b/lib/StaticAnalyzer/Core/APSIntType.cpp
index 884b0fa..c7e9526 100644
--- a/lib/StaticAnalyzer/Core/APSIntType.cpp
+++ b/lib/StaticAnalyzer/Core/APSIntType.cpp
@@ -13,20 +13,31 @@ using namespace clang;
using namespace ento;
APSIntType::RangeTestResultKind
-APSIntType::testInRange(const llvm::APSInt &Value) const {
+APSIntType::testInRange(const llvm::APSInt &Value,
+ bool AllowSignConversions) const {
+
// Negative numbers cannot be losslessly converted to unsigned type.
- if (IsUnsigned && Value.isSigned() && Value.isNegative())
+ if (IsUnsigned && !AllowSignConversions &&
+ Value.isSigned() && Value.isNegative())
return RTR_Below;
- // Signed integers can be converted to signed integers of the same width
- // or (if positive) unsigned integers with one fewer bit.
- // Unsigned integers can be converted to unsigned integers of the same width
- // or signed integers with one more bit.
unsigned MinBits;
- if (Value.isSigned())
- MinBits = Value.getMinSignedBits() - IsUnsigned;
- else
- MinBits = Value.getActiveBits() + !IsUnsigned;
+ if (AllowSignConversions) {
+ if (Value.isSigned() && !IsUnsigned)
+ MinBits = Value.getMinSignedBits();
+ else
+ MinBits = Value.getActiveBits();
+
+ } else {
+ // Signed integers can be converted to signed integers of the same width
+ // or (if positive) unsigned integers with one fewer bit.
+ // Unsigned integers can be converted to unsigned integers of the same width
+ // or signed integers with one more bit.
+ if (Value.isSigned())
+ MinBits = Value.getMinSignedBits() - IsUnsigned;
+ else
+ MinBits = Value.getActiveBits() + !IsUnsigned;
+ }
if (MinBits <= BitWidth)
return RTR_Within;
diff --git a/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/lib/StaticAnalyzer/Core/AnalysisManager.cpp
index 011d4c09..747b73c 100644
--- a/lib/StaticAnalyzer/Core/AnalysisManager.cpp
+++ b/lib/StaticAnalyzer/Core/AnalysisManager.cpp
@@ -25,7 +25,8 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
/*AddImplicitDtors=*/true,
/*AddInitializers=*/true,
Options.includeTemporaryDtorsInCFG(),
- Options.shouldSynthesizeBodies()),
+ Options.shouldSynthesizeBodies(),
+ Options.shouldConditionalizeStaticInitializers()),
Ctx(ctx),
Diags(diags),
LangOpts(lang),
diff --git a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
index da88589..ae70739 100644
--- a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
+++ b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -13,23 +13,68 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace llvm;
+AnalyzerOptions::UserModeKind AnalyzerOptions::getUserMode() {
+ if (UserMode == UMK_NotSet) {
+ StringRef ModeStr(Config.GetOrCreateValue("mode", "deep").getValue());
+ UserMode = llvm::StringSwitch<UserModeKind>(ModeStr)
+ .Case("shallow", UMK_Shallow)
+ .Case("deep", UMK_Deep)
+ .Default(UMK_NotSet);
+ assert(UserMode != UMK_NotSet && "User mode is invalid.");
+ }
+ return UserMode;
+}
+
+IPAKind AnalyzerOptions::getIPAMode() {
+ if (IPAMode == IPAK_NotSet) {
+
+ // Use the User Mode to set the default IPA value.
+ // Note, we have to add the string to the Config map for the ConfigDumper
+ // checker to function properly.
+ const char *DefaultIPA = 0;
+ UserModeKind HighLevelMode = getUserMode();
+ if (HighLevelMode == UMK_Shallow)
+ DefaultIPA = "inlining";
+ else if (HighLevelMode == UMK_Deep)
+ DefaultIPA = "dynamic-bifurcate";
+ assert(DefaultIPA);
+
+ // Lookup the ipa configuration option, use the default from User Mode.
+ StringRef ModeStr(Config.GetOrCreateValue("ipa", DefaultIPA).getValue());
+ IPAKind IPAConfig = llvm::StringSwitch<IPAKind>(ModeStr)
+ .Case("none", IPAK_None)
+ .Case("basic-inlining", IPAK_BasicInlining)
+ .Case("inlining", IPAK_Inlining)
+ .Case("dynamic", IPAK_DynamicDispatch)
+ .Case("dynamic-bifurcate", IPAK_DynamicDispatchBifurcate)
+ .Default(IPAK_NotSet);
+ assert(IPAConfig != IPAK_NotSet && "IPA Mode is invalid.");
+
+ // Set the member variable.
+ IPAMode = IPAConfig;
+ }
+
+ return IPAMode;
+}
+
bool
AnalyzerOptions::mayInlineCXXMemberFunction(CXXInlineableMemberKind K) {
- if (IPAMode < Inlining)
+ if (getIPAMode() < IPAK_Inlining)
return false;
if (!CXXMemberInliningMode) {
static const char *ModeKey = "c++-inlining";
StringRef ModeStr(Config.GetOrCreateValue(ModeKey,
- "methods").getValue());
+ "destructors").getValue());
CXXInlineableMemberKind &MutableMode =
const_cast<CXXInlineableMemberKind &>(CXXMemberInliningMode);
@@ -64,8 +109,7 @@ bool AnalyzerOptions::getBooleanOption(StringRef Name, bool DefaultVal) {
.Default(DefaultVal);
}
-bool AnalyzerOptions::getBooleanOption(llvm::Optional<bool> &V,
- StringRef Name,
+bool AnalyzerOptions::getBooleanOption(Optional<bool> &V, StringRef Name,
bool DefaultVal) {
if (!V.hasValue())
V = getBooleanOption(Name, DefaultVal);
@@ -90,14 +134,21 @@ bool AnalyzerOptions::mayInlineTemplateFunctions() {
/*Default=*/true);
}
+bool AnalyzerOptions::mayInlineCXXContainerCtorsAndDtors() {
+ return getBooleanOption(InlineCXXContainerCtorsAndDtors,
+ "c++-container-inlining",
+ /*Default=*/false);
+}
+
+
bool AnalyzerOptions::mayInlineObjCMethod() {
return getBooleanOption(ObjCInliningMode,
"objc-inlining",
/* Default = */ true);
}
-bool AnalyzerOptions::shouldPruneNullReturnPaths() {
- return getBooleanOption(PruneNullReturnPaths,
+bool AnalyzerOptions::shouldSuppressNullReturnPaths() {
+ return getBooleanOption(SuppressNullReturnPaths,
"suppress-null-return-paths",
/* Default = */ true);
}
@@ -108,8 +159,20 @@ bool AnalyzerOptions::shouldAvoidSuppressingNullArgumentPaths() {
/* Default = */ false);
}
+bool AnalyzerOptions::shouldSuppressInlinedDefensiveChecks() {
+ return getBooleanOption(SuppressInlinedDefensiveChecks,
+ "suppress-inlined-defensive-checks",
+ /* Default = */ true);
+}
+
+bool AnalyzerOptions::shouldSuppressFromCXXStandardLibrary() {
+ return getBooleanOption(SuppressFromCXXStandardLibrary,
+ "suppress-c++-stdlib",
+ /* Default = */ false);
+}
+
int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal) {
- llvm::SmallString<10> StrBuf;
+ SmallString<10> StrBuf;
llvm::raw_svector_ostream OS(StrBuf);
OS << DefaultVal;
@@ -127,12 +190,67 @@ unsigned AnalyzerOptions::getAlwaysInlineSize() {
return AlwaysInlineSize.getValue();
}
+unsigned AnalyzerOptions::getMaxInlinableSize() {
+ if (!MaxInlinableSize.hasValue()) {
+
+ int DefaultValue = 0;
+ UserModeKind HighLevelMode = getUserMode();
+ switch (HighLevelMode) {
+ default:
+ llvm_unreachable("Invalid mode.");
+ case UMK_Shallow:
+ DefaultValue = 4;
+ break;
+ case UMK_Deep:
+ DefaultValue = 50;
+ break;
+ }
+
+ MaxInlinableSize = getOptionAsInteger("max-inlinable-size", DefaultValue);
+ }
+ return MaxInlinableSize.getValue();
+}
+
unsigned AnalyzerOptions::getGraphTrimInterval() {
if (!GraphTrimInterval.hasValue())
GraphTrimInterval = getOptionAsInteger("graph-trim-interval", 1000);
return GraphTrimInterval.getValue();
}
+unsigned AnalyzerOptions::getMaxTimesInlineLarge() {
+ if (!MaxTimesInlineLarge.hasValue())
+ MaxTimesInlineLarge = getOptionAsInteger("max-times-inline-large", 32);
+ return MaxTimesInlineLarge.getValue();
+}
+
+unsigned AnalyzerOptions::getMaxNodesPerTopLevelFunction() {
+ if (!MaxNodesPerTopLevelFunction.hasValue()) {
+ int DefaultValue = 0;
+ UserModeKind HighLevelMode = getUserMode();
+ switch (HighLevelMode) {
+ default:
+ llvm_unreachable("Invalid mode.");
+ case UMK_Shallow:
+ DefaultValue = 75000;
+ break;
+ case UMK_Deep:
+ DefaultValue = 150000;
+ break;
+ }
+ MaxNodesPerTopLevelFunction = getOptionAsInteger("max-nodes", DefaultValue);
+ }
+ return MaxNodesPerTopLevelFunction.getValue();
+}
+
bool AnalyzerOptions::shouldSynthesizeBodies() {
return getBooleanOption("faux-bodies", true);
}
+
+bool AnalyzerOptions::shouldPrunePaths() {
+ return getBooleanOption("prune-paths", true);
+}
+
+bool AnalyzerOptions::shouldConditionalizeStaticInitializers() {
+ return getBooleanOption("cfg-conditional-static-initializers", true);
+}
+
diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp
index c898d65..8f8eb3b 100644
--- a/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -12,29 +12,38 @@
//
//===----------------------------------------------------------------------===//
+#define DEBUG_TYPE "BugReporter"
+
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/AST/ASTContext.h"
-#include "clang/Analysis/CFG.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtObjC.h"
-#include "clang/Basic/SourceManager.h"
+#include "clang/Analysis/CFG.h"
#include "clang/Analysis/ProgramPoint.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
-#include "llvm/Support/raw_ostream.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/Support/raw_ostream.h"
#include <queue>
using namespace clang;
using namespace ento;
+STATISTIC(MaxBugClassSize,
+ "The maximum number of bug reports in the same equivalence class");
+STATISTIC(MaxValidBugClassSize,
+ "The maximum number of bug reports in the same equivalence class "
+ "where at least one report is valid (not suppressed)");
+
BugReporterVisitor::~BugReporterVisitor() {}
void BugReporterContext::anchor() {}
@@ -44,13 +53,13 @@ void BugReporterContext::anchor() {}
//===----------------------------------------------------------------------===//
static inline const Stmt *GetStmt(const ProgramPoint &P) {
- if (const StmtPoint* SP = dyn_cast<StmtPoint>(&P))
+ if (Optional<StmtPoint> SP = P.getAs<StmtPoint>())
return SP->getStmt();
- else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P))
+ if (Optional<BlockEdge> BE = P.getAs<BlockEdge>())
return BE->getSrc()->getTerminator();
- else if (const CallEnter *CE = dyn_cast<CallEnter>(&P))
+ if (Optional<CallEnter> CE = P.getAs<CallEnter>())
return CE->getCallExpr();
- else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&P))
+ if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>())
return CEE->getCalleeContext()->getCallSite();
return 0;
@@ -191,9 +200,8 @@ static void removeRedundantMsgs(PathPieces &path) {
/// 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.
-bool BugReporter::RemoveUneededCalls(PathPieces &pieces, BugReport *R,
- PathDiagnosticCallPiece *CallWithLoc) {
+/// "interesting stuff" which means it shouldn't be pruned from the parent path.
+bool BugReporter::RemoveUnneededCalls(PathPieces &pieces, BugReport *R) {
bool containsSomethingInteresting = false;
const unsigned N = pieces.size();
@@ -203,7 +211,9 @@ bool BugReporter::RemoveUneededCalls(PathPieces &pieces, BugReport *R,
IntrusiveRefCntPtr<PathDiagnosticPiece> piece(pieces.front());
pieces.pop_front();
- // Throw away pieces with invalid locations.
+ // Throw away pieces with invalid locations. Note that we can't throw away
+ // calls just yet because they might have something interesting inside them.
+ // If so, their locations will be adjusted as necessary later.
if (piece->getKind() != PathDiagnosticPiece::Call &&
piece->getLocation().asLocation().isInvalid())
continue;
@@ -217,25 +227,16 @@ bool BugReporter::RemoveUneededCalls(PathPieces &pieces, BugReport *R,
containsSomethingInteresting = true;
break;
}
- // Recursively clean out the subclass. Keep this call around if
- // it contains any informative diagnostics.
- PathDiagnosticCallPiece *NewCallWithLoc =
- call->getLocation().asLocation().isValid()
- ? call : CallWithLoc;
-
- if (!RemoveUneededCalls(call->path, R, NewCallWithLoc))
- continue;
- if (NewCallWithLoc == CallWithLoc && CallWithLoc) {
- call->callEnter = CallWithLoc->callEnter;
- }
+ if (!RemoveUnneededCalls(call->path, R))
+ continue;
containsSomethingInteresting = true;
break;
}
case PathDiagnosticPiece::Macro: {
PathDiagnosticMacroPiece *macro = cast<PathDiagnosticMacroPiece>(piece);
- if (!RemoveUneededCalls(macro->subPieces, R))
+ if (!RemoveUnneededCalls(macro->subPieces, R))
continue;
containsSomethingInteresting = true;
break;
@@ -258,36 +259,66 @@ bool BugReporter::RemoveUneededCalls(PathPieces &pieces, BugReport *R,
return containsSomethingInteresting;
}
+/// Recursively scan through a path and make sure that all call pieces have
+/// valid locations. Note that all other pieces with invalid locations should
+/// have already been pruned out.
+static void adjustCallLocations(PathPieces &Pieces,
+ PathDiagnosticLocation *LastCallLocation = 0) {
+ for (PathPieces::iterator I = Pieces.begin(), E = Pieces.end(); I != E; ++I) {
+ PathDiagnosticCallPiece *Call = dyn_cast<PathDiagnosticCallPiece>(*I);
+
+ if (!Call) {
+ assert((*I)->getLocation().asLocation().isValid());
+ continue;
+ }
+
+ if (LastCallLocation) {
+ if (!Call->callEnter.asLocation().isValid() ||
+ Call->getCaller()->isImplicit())
+ Call->callEnter = *LastCallLocation;
+ if (!Call->callReturn.asLocation().isValid() ||
+ Call->getCaller()->isImplicit())
+ Call->callReturn = *LastCallLocation;
+ }
+
+ // Recursively clean out the subclass. Keep this call around if
+ // it contains any informative diagnostics.
+ PathDiagnosticLocation *ThisCallLocation;
+ if (Call->callEnterWithin.asLocation().isValid() &&
+ !Call->getCallee()->isImplicit())
+ ThisCallLocation = &Call->callEnterWithin;
+ else
+ ThisCallLocation = &Call->callEnter;
+
+ assert(ThisCallLocation && "Outermost call has an invalid location");
+ adjustCallLocations(Call->path, ThisCallLocation);
+ }
+}
+
//===----------------------------------------------------------------------===//
// PathDiagnosticBuilder and its associated routines and helper objects.
//===----------------------------------------------------------------------===//
-typedef llvm::DenseMap<const ExplodedNode*,
-const ExplodedNode*> NodeBackMap;
-
namespace {
class NodeMapClosure : public BugReport::NodeResolver {
- NodeBackMap& M;
+ InterExplodedGraphMap &M;
public:
- NodeMapClosure(NodeBackMap *m) : M(*m) {}
- ~NodeMapClosure() {}
+ NodeMapClosure(InterExplodedGraphMap &m) : M(m) {}
const ExplodedNode *getOriginalNode(const ExplodedNode *N) {
- NodeBackMap::iterator I = M.find(N);
- return I == M.end() ? 0 : I->second;
+ return M.lookup(N);
}
};
class PathDiagnosticBuilder : public BugReporterContext {
BugReport *R;
PathDiagnosticConsumer *PDC;
- OwningPtr<ParentMap> PM;
NodeMapClosure NMC;
public:
const LocationContext *LC;
PathDiagnosticBuilder(GRBugReporter &br,
- BugReport *r, NodeBackMap *Backmap,
+ BugReport *r, InterExplodedGraphMap &Backmap,
PathDiagnosticConsumer *pdc)
: BugReporterContext(br),
R(r), PDC(pdc), NMC(Backmap), LC(r->getErrorNode()->getLocationContext())
@@ -552,7 +583,7 @@ static bool GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
ProgramPoint P = N->getLocation();
do {
- if (const CallExitEnd *CE = dyn_cast<CallExitEnd>(&P)) {
+ if (Optional<CallExitEnd> CE = P.getAs<CallExitEnd>()) {
PathDiagnosticCallPiece *C =
PathDiagnosticCallPiece::construct(N, *CE, SMgr);
GRBugReporter& BR = PDB.getBugReporter();
@@ -563,7 +594,7 @@ static bool GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
break;
}
- if (const CallEnter *CE = dyn_cast<CallEnter>(&P)) {
+ if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
// Flush all locations, and pop the active path.
bool VisitedEntireCall = PD.isWithinCall();
PD.popActivePath();
@@ -591,7 +622,7 @@ static bool GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
break;
}
- if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
+ if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
const CFGBlock *Src = BE->getSrc();
const CFGBlock *Dst = BE->getDst();
const Stmt *T = Src->getTerminator();
@@ -1267,7 +1298,81 @@ static void reversePropagateInterestingSymbols(BugReport &R,
}
}
}
-
+
+//===----------------------------------------------------------------------===//
+// Functions for determining if a loop was executed 0 times.
+//===----------------------------------------------------------------------===//
+
+/// Return true if the terminator is a loop and the destination is the
+/// false branch.
+static bool isLoopJumpPastBody(const Stmt *Term, const BlockEdge *BE) {
+ switch (Term->getStmtClass()) {
+ case Stmt::ForStmtClass:
+ case Stmt::WhileStmtClass:
+ case Stmt::ObjCForCollectionStmtClass:
+ break;
+ default:
+ // Note that we intentionally do not include do..while here.
+ return false;
+ }
+
+ // Did we take the false branch?
+ const CFGBlock *Src = BE->getSrc();
+ assert(Src->succ_size() == 2);
+ return (*(Src->succ_begin()+1) == BE->getDst());
+}
+
+static bool isContainedByStmt(ParentMap &PM, const Stmt *S, const Stmt *SubS) {
+ while (SubS) {
+ if (SubS == S)
+ return true;
+ SubS = PM.getParent(SubS);
+ }
+ return false;
+}
+
+static const Stmt *getStmtBeforeCond(ParentMap &PM, const Stmt *Term,
+ const ExplodedNode *N) {
+ while (N) {
+ Optional<StmtPoint> SP = N->getLocation().getAs<StmtPoint>();
+ if (SP) {
+ const Stmt *S = SP->getStmt();
+ if (!isContainedByStmt(PM, Term, S))
+ return S;
+ }
+ N = GetPredecessorNode(N);
+ }
+ return 0;
+}
+
+static bool isInLoopBody(ParentMap &PM, const Stmt *S, const Stmt *Term) {
+ const Stmt *LoopBody = 0;
+ switch (Term->getStmtClass()) {
+ case Stmt::ForStmtClass: {
+ const ForStmt *FS = cast<ForStmt>(Term);
+ if (isContainedByStmt(PM, FS->getInc(), S))
+ return true;
+ LoopBody = FS->getBody();
+ break;
+ }
+ case Stmt::ObjCForCollectionStmtClass: {
+ const ObjCForCollectionStmt *FC = cast<ObjCForCollectionStmt>(Term);
+ LoopBody = FC->getBody();
+ break;
+ }
+ case Stmt::WhileStmtClass:
+ LoopBody = cast<WhileStmt>(Term)->getBody();
+ break;
+ default:
+ return false;
+ }
+ return isContainedByStmt(PM, LoopBody, S);
+}
+
+//===----------------------------------------------------------------------===//
+// Top-level logic for generating extensive path diagnostics.
+//===----------------------------------------------------------------------===//
+
static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
PathDiagnosticBuilder &PDB,
const ExplodedNode *N,
@@ -1284,14 +1389,14 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
ProgramPoint P = N->getLocation();
do {
- if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) {
+ if (Optional<PostStmt> PS = P.getAs<PostStmt>()) {
if (const Expr *Ex = PS->getStmtAs<Expr>())
reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE,
N->getState().getPtr(), Ex,
N->getLocationContext());
}
- if (const CallExitEnd *CE = dyn_cast<CallExitEnd>(&P)) {
+ if (Optional<CallExitEnd> CE = P.getAs<CallExitEnd>()) {
const Stmt *S = CE->getCalleeContext()->getCallSite();
if (const Expr *Ex = dyn_cast_or_null<Expr>(S)) {
reversePropagateIntererstingSymbols(*PDB.getBugReport(), IE,
@@ -1315,7 +1420,7 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
// Pop the call hierarchy if we are done walking the contents
// of a function call.
- if (const CallEnter *CE = dyn_cast<CallEnter>(&P)) {
+ if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
// Add an edge to the start of the function.
const Decl *D = CE->getCalleeContext()->getDecl();
PathDiagnosticLocation pos =
@@ -1360,7 +1465,7 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
PDB.LC = N->getLocationContext();
// Block edges.
- if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
+ if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
// Does this represent entering a call? If so, look at propagating
// interesting symbols across call boundaries.
if (NextNode) {
@@ -1397,16 +1502,39 @@ static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD,
EB.addEdge(BL);
}
}
-
- if (const Stmt *Term = BE->getSrc()->getTerminator())
+
+ const CFGBlock *BSrc = BE->getSrc();
+ ParentMap &PM = PDB.getParentMap();
+
+ if (const Stmt *Term = BSrc->getTerminator()) {
+ // Are we jumping past the loop body without ever executing the
+ // loop (because the condition was false)?
+ if (isLoopJumpPastBody(Term, &*BE) &&
+ !isInLoopBody(PM,
+ getStmtBeforeCond(PM,
+ BSrc->getTerminatorCondition(),
+ N),
+ Term)) {
+ PathDiagnosticLocation L(Term, SM, PDB.LC);
+ PathDiagnosticEventPiece *PE =
+ new PathDiagnosticEventPiece(L, "Loop body executed 0 times");
+ PE->setPrunable(true);
+
+ EB.addEdge(PE->getLocation(), true);
+ PD.getActivePath().push_front(PE);
+ }
+
+ // In any case, add the terminator as the current statement
+ // context for control edges.
EB.addContext(Term);
+ }
break;
}
- if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
- CFGElement First = BE->getFirstElement();
- if (const CFGStmt *S = First.getAs<CFGStmt>()) {
+ if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
+ Optional<CFGElement> First = BE->getFirstElement();
+ if (Optional<CFGStmt> S = First ? First->getAs<CFGStmt>() : None) {
const Stmt *stmt = S->getStmt();
if (IsControlFlowExpr(stmt)) {
// Add the proper context for '&&', '||', and '?'.
@@ -1502,8 +1630,9 @@ const Decl *BugReport::getDeclWithIssue() const {
void BugReport::Profile(llvm::FoldingSetNodeID& hash) const {
hash.AddPointer(&BT);
hash.AddString(Description);
- if (UniqueingLocation.isValid()) {
- UniqueingLocation.Profile(hash);
+ PathDiagnosticLocation UL = getUniqueingLocation();
+ if (UL.isValid()) {
+ UL.Profile(hash);
} else if (Location.isValid()) {
Location.Profile(hash);
} else {
@@ -1623,7 +1752,7 @@ const Stmt *BugReport::getStmt() const {
ProgramPoint ProgP = ErrorNode->getLocation();
const Stmt *S = NULL;
- if (BlockEntrance *BE = dyn_cast<BlockEntrance>(&ProgP)) {
+ if (Optional<BlockEntrance> BE = ProgP.getAs<BlockEntrance>()) {
CFGBlock &Exit = ProgP.getLocationContext()->getCFG()->getExit();
if (BE->getBlock() == &Exit)
S = GetPreviousStmt(ErrorNode);
@@ -1667,6 +1796,9 @@ PathDiagnosticLocation BugReport::getLocation(const SourceManager &SM) const {
if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S))
return PathDiagnosticLocation::createOperatorLoc(B, SM);
+ if (ErrorNode->getLocation().getAs<PostStmtPurgeDeadSymbols>())
+ return PathDiagnosticLocation::createEnd(S, SM, LC);
+
return PathDiagnosticLocation::createBegin(S, SM, LC);
}
} else {
@@ -1741,141 +1873,174 @@ void BugReporter::FlushReports() {
// PathDiagnostics generation.
//===----------------------------------------------------------------------===//
-static std::pair<std::pair<ExplodedGraph*, NodeBackMap*>,
- std::pair<ExplodedNode*, unsigned> >
-MakeReportGraph(const ExplodedGraph* G,
- SmallVectorImpl<const ExplodedNode*> &nodes) {
+namespace {
+/// A wrapper around a report graph, which contains only a single path, and its
+/// node maps.
+class ReportGraph {
+public:
+ InterExplodedGraphMap BackMap;
+ OwningPtr<ExplodedGraph> Graph;
+ const ExplodedNode *ErrorNode;
+ size_t Index;
+};
+
+/// A wrapper around a trimmed graph and its node maps.
+class TrimmedGraph {
+ InterExplodedGraphMap InverseMap;
+
+ typedef llvm::DenseMap<const ExplodedNode *, unsigned> PriorityMapTy;
+ PriorityMapTy PriorityMap;
+
+ typedef std::pair<const ExplodedNode *, size_t> NodeIndexPair;
+ SmallVector<NodeIndexPair, 32> ReportNodes;
- // Create the trimmed graph. It will contain the shortest paths from the
- // error nodes to the root. In the new graph we should only have one
- // error node unless there are two or more error nodes with the same minimum
- // path length.
- ExplodedGraph* GTrim;
- InterExplodedGraphMap* NMap;
+ OwningPtr<ExplodedGraph> G;
- llvm::DenseMap<const void*, const void*> InverseMap;
- llvm::tie(GTrim, NMap) = G->Trim(nodes.data(), nodes.data() + nodes.size(),
- &InverseMap);
+ /// A helper class for sorting ExplodedNodes by priority.
+ template <bool Descending>
+ class PriorityCompare {
+ const PriorityMapTy &PriorityMap;
- // Create owning pointers for GTrim and NMap just to ensure that they are
- // released when this function exists.
- OwningPtr<ExplodedGraph> AutoReleaseGTrim(GTrim);
- OwningPtr<InterExplodedGraphMap> AutoReleaseNMap(NMap);
+ public:
+ PriorityCompare(const PriorityMapTy &M) : PriorityMap(M) {}
+
+ bool operator()(const ExplodedNode *LHS, const ExplodedNode *RHS) const {
+ PriorityMapTy::const_iterator LI = PriorityMap.find(LHS);
+ PriorityMapTy::const_iterator RI = PriorityMap.find(RHS);
+ PriorityMapTy::const_iterator E = PriorityMap.end();
+
+ if (LI == E)
+ return Descending;
+ if (RI == E)
+ return !Descending;
+
+ return Descending ? LI->second > RI->second
+ : LI->second < RI->second;
+ }
+
+ bool operator()(const NodeIndexPair &LHS, const NodeIndexPair &RHS) const {
+ return (*this)(LHS.first, RHS.first);
+ }
+ };
+
+public:
+ TrimmedGraph(const ExplodedGraph *OriginalGraph,
+ ArrayRef<const ExplodedNode *> Nodes);
+
+ bool popNextReportGraph(ReportGraph &GraphWrapper);
+};
+}
+
+TrimmedGraph::TrimmedGraph(const ExplodedGraph *OriginalGraph,
+ ArrayRef<const ExplodedNode *> Nodes) {
+ // The trimmed graph is created in the body of the constructor to ensure
+ // that the DenseMaps have been initialized already.
+ InterExplodedGraphMap ForwardMap;
+ G.reset(OriginalGraph->trim(Nodes, &ForwardMap, &InverseMap));
// Find the (first) error node in the trimmed graph. We just need to consult
- // the node map (NMap) which maps from nodes in the original graph to nodes
+ // the node map which maps from nodes in the original graph to nodes
// in the new graph.
+ llvm::SmallPtrSet<const ExplodedNode *, 32> RemainingNodes;
- std::queue<const ExplodedNode*> WS;
- typedef llvm::DenseMap<const ExplodedNode*, unsigned> IndexMapTy;
- IndexMapTy IndexMap;
-
- for (unsigned nodeIndex = 0 ; nodeIndex < nodes.size(); ++nodeIndex) {
- const ExplodedNode *originalNode = nodes[nodeIndex];
- if (const ExplodedNode *N = NMap->getMappedNode(originalNode)) {
- WS.push(N);
- IndexMap[originalNode] = nodeIndex;
+ for (unsigned i = 0, count = Nodes.size(); i < count; ++i) {
+ if (const ExplodedNode *NewNode = ForwardMap.lookup(Nodes[i])) {
+ ReportNodes.push_back(std::make_pair(NewNode, i));
+ RemainingNodes.insert(NewNode);
}
}
- assert(!WS.empty() && "No error node found in the trimmed graph.");
-
- // Create a new (third!) graph with a single path. This is the graph
- // that will be returned to the caller.
- ExplodedGraph *GNew = new ExplodedGraph();
+ assert(!RemainingNodes.empty() && "No error node found in the trimmed graph");
- // Sometimes the trimmed graph can contain a cycle. Perform a reverse BFS
- // to the root node, and then construct a new graph that contains only
- // a single path.
- llvm::DenseMap<const void*,unsigned> Visited;
+ // Perform a forward BFS to find all the shortest paths.
+ std::queue<const ExplodedNode *> WS;
- unsigned cnt = 0;
- const ExplodedNode *Root = 0;
+ assert(G->num_roots() == 1);
+ WS.push(*G->roots_begin());
+ unsigned Priority = 0;
while (!WS.empty()) {
const ExplodedNode *Node = WS.front();
WS.pop();
- if (Visited.find(Node) != Visited.end())
- continue;
+ PriorityMapTy::iterator PriorityEntry;
+ bool IsNew;
+ llvm::tie(PriorityEntry, IsNew) =
+ PriorityMap.insert(std::make_pair(Node, Priority));
+ ++Priority;
- Visited[Node] = cnt++;
-
- if (Node->pred_empty()) {
- Root = Node;
- break;
+ if (!IsNew) {
+ assert(PriorityEntry->second <= Priority);
+ continue;
}
- for (ExplodedNode::const_pred_iterator I=Node->pred_begin(),
- E=Node->pred_end(); I!=E; ++I)
+ if (RemainingNodes.erase(Node))
+ if (RemainingNodes.empty())
+ break;
+
+ for (ExplodedNode::const_pred_iterator I = Node->succ_begin(),
+ E = Node->succ_end();
+ I != E; ++I)
WS.push(*I);
}
- assert(Root);
+ // Sort the error paths from longest to shortest.
+ std::sort(ReportNodes.begin(), ReportNodes.end(),
+ PriorityCompare<true>(PriorityMap));
+}
- // Now walk from the root down the BFS path, always taking the successor
- // with the lowest number.
- ExplodedNode *Last = 0, *First = 0;
- NodeBackMap *BM = new NodeBackMap();
- unsigned NodeIndex = 0;
+bool TrimmedGraph::popNextReportGraph(ReportGraph &GraphWrapper) {
+ if (ReportNodes.empty())
+ return false;
- for ( const ExplodedNode *N = Root ;;) {
- // Lookup the number associated with the current node.
- llvm::DenseMap<const void*,unsigned>::iterator I = Visited.find(N);
- assert(I != Visited.end());
+ const ExplodedNode *OrigN;
+ llvm::tie(OrigN, GraphWrapper.Index) = ReportNodes.pop_back_val();
+ assert(PriorityMap.find(OrigN) != PriorityMap.end() &&
+ "error node not accessible from root");
+ // Create a new graph with a single path. This is the graph
+ // that will be returned to the caller.
+ ExplodedGraph *GNew = new ExplodedGraph();
+ GraphWrapper.Graph.reset(GNew);
+ GraphWrapper.BackMap.clear();
+
+ // Now walk from the error node up the BFS path, always taking the
+ // predeccessor with the lowest number.
+ ExplodedNode *Succ = 0;
+ while (true) {
// Create the equivalent node in the new graph with the same state
// and location.
- ExplodedNode *NewN = GNew->getNode(N->getLocation(), N->getState());
+ ExplodedNode *NewN = GNew->getNode(OrigN->getLocation(), OrigN->getState());
// Store the mapping to the original node.
- llvm::DenseMap<const void*, const void*>::iterator IMitr=InverseMap.find(N);
+ InterExplodedGraphMap::const_iterator IMitr = InverseMap.find(OrigN);
assert(IMitr != InverseMap.end() && "No mapping to original node.");
- (*BM)[NewN] = (const ExplodedNode*) IMitr->second;
+ GraphWrapper.BackMap[NewN] = IMitr->second;
// Link up the new node with the previous node.
- if (Last)
- NewN->addPredecessor(Last, *GNew);
+ if (Succ)
+ Succ->addPredecessor(NewN, *GNew);
+ else
+ GraphWrapper.ErrorNode = NewN;
- Last = NewN;
+ Succ = NewN;
// Are we at the final node?
- IndexMapTy::iterator IMI =
- IndexMap.find((const ExplodedNode*)(IMitr->second));
- if (IMI != IndexMap.end()) {
- First = NewN;
- NodeIndex = IMI->second;
+ if (OrigN->pred_empty()) {
+ GNew->addRoot(NewN);
break;
}
- // Find the next successor node. We choose the node that is marked
- // with the lowest DFS number.
- ExplodedNode::const_succ_iterator SI = N->succ_begin();
- ExplodedNode::const_succ_iterator SE = N->succ_end();
- N = 0;
-
- for (unsigned MinVal = 0; SI != SE; ++SI) {
-
- I = Visited.find(*SI);
-
- if (I == Visited.end())
- continue;
-
- if (!N || I->second < MinVal) {
- N = *SI;
- MinVal = I->second;
- }
- }
-
- assert(N);
+ // Find the next predeccessor node. We choose the node that is marked
+ // with the lowest BFS number.
+ OrigN = *std::min_element(OrigN->pred_begin(), OrigN->pred_end(),
+ PriorityCompare<false>(PriorityMap));
}
- assert(First);
-
- return std::make_pair(std::make_pair(GNew, BM),
- std::make_pair(First, NodeIndex));
+ return true;
}
+
/// CompactPathDiagnostic - This function postprocesses a PathDiagnostic object
/// and collapses PathDiagosticPieces that are expanded by macros.
static void CompactPathDiagnostic(PathPieces &path, const SourceManager& SM) {
@@ -1978,128 +2143,128 @@ bool GRBugReporter::generatePathDiagnostic(PathDiagnostic& PD,
assert(!bugReports.empty());
bool HasValid = false;
- SmallVector<const ExplodedNode *, 10> errorNodes;
+ bool HasInvalid = false;
+ SmallVector<const ExplodedNode *, 32> errorNodes;
for (ArrayRef<BugReport*>::iterator I = bugReports.begin(),
E = bugReports.end(); I != E; ++I) {
if ((*I)->isValid()) {
HasValid = true;
errorNodes.push_back((*I)->getErrorNode());
} else {
+ // Keep the errorNodes list in sync with the bugReports list.
+ HasInvalid = true;
errorNodes.push_back(0);
}
}
- // If all the reports have been marked invalid, we're done.
+ // If all the reports have been marked invalid by a previous path generation,
+ // we're done.
if (!HasValid)
return false;
- // Construct a new graph that contains only a single path from the error
- // node to a root.
- const std::pair<std::pair<ExplodedGraph*, NodeBackMap*>,
- std::pair<ExplodedNode*, unsigned> >&
- GPair = MakeReportGraph(&getGraph(), errorNodes);
-
- // Find the BugReport with the original location.
- assert(GPair.second.second < bugReports.size());
- BugReport *R = bugReports[GPair.second.second];
- assert(R && "No original report found for sliced graph.");
- assert(R->isValid() && "Report selected from trimmed graph marked invalid.");
-
- OwningPtr<ExplodedGraph> ReportGraph(GPair.first.first);
- OwningPtr<NodeBackMap> BackMap(GPair.first.second);
- const ExplodedNode *N = GPair.second.first;
-
- // Start building the path diagnostic...
- PathDiagnosticBuilder PDB(*this, R, BackMap.get(), &PC);
-
- // Register additional node visitors.
- R->addVisitor(new NilReceiverBRVisitor());
- R->addVisitor(new ConditionBRVisitor());
-
- BugReport::VisitorList visitors;
- unsigned originalReportConfigToken, finalReportConfigToken;
-
- // While generating diagnostics, it's possible the visitors will decide
- // new symbols and regions are interesting, or add other visitors based on
- // the information they find. If they do, we need to regenerate the path
- // based on our new report configuration.
- do {
- // Get a clean copy of all the visitors.
- for (BugReport::visitor_iterator I = R->visitor_begin(),
- E = R->visitor_end(); I != E; ++I)
- visitors.push_back((*I)->clone());
-
- // Clear out the active path from any previous work.
- PD.resetPath();
- originalReportConfigToken = R->getConfigurationChangeToken();
-
- // Generate the very last diagnostic piece - the piece is visible before
- // the trace is expanded.
- if (PDB.getGenerationScheme() != PathDiagnosticConsumer::None) {
+ typedef PathDiagnosticConsumer::PathGenerationScheme PathGenerationScheme;
+ PathGenerationScheme ActiveScheme = PC.getGenerationScheme();
+
+ TrimmedGraph TrimG(&getGraph(), errorNodes);
+ ReportGraph ErrorGraph;
+
+ while (TrimG.popNextReportGraph(ErrorGraph)) {
+ // Find the BugReport with the original location.
+ assert(ErrorGraph.Index < bugReports.size());
+ BugReport *R = bugReports[ErrorGraph.Index];
+ assert(R && "No original report found for sliced graph.");
+ assert(R->isValid() && "Report selected by trimmed graph marked invalid.");
+
+ // Start building the path diagnostic...
+ PathDiagnosticBuilder PDB(*this, R, ErrorGraph.BackMap, &PC);
+ const ExplodedNode *N = ErrorGraph.ErrorNode;
+
+ // Register additional node visitors.
+ R->addVisitor(new NilReceiverBRVisitor());
+ R->addVisitor(new ConditionBRVisitor());
+ R->addVisitor(new LikelyFalsePositiveSuppressionBRVisitor());
+
+ BugReport::VisitorList visitors;
+ unsigned origReportConfigToken, finalReportConfigToken;
+
+ // While generating diagnostics, it's possible the visitors will decide
+ // new symbols and regions are interesting, or add other visitors based on
+ // the information they find. If they do, we need to regenerate the path
+ // based on our new report configuration.
+ do {
+ // Get a clean copy of all the visitors.
+ for (BugReport::visitor_iterator I = R->visitor_begin(),
+ E = R->visitor_end(); I != E; ++I)
+ visitors.push_back((*I)->clone());
+
+ // Clear out the active path from any previous work.
+ PD.resetPath();
+ origReportConfigToken = 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) {
+ I != E; ++I) {
if (PathDiagnosticPiece *Piece = (*I)->getEndPath(PDB, N, *R)) {
assert (!LastPiece &&
- "There can only be one final piece in a diagnostic.");
+ "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;
- }
- switch (PDB.getGenerationScheme()) {
- case PathDiagnosticConsumer::Extensive:
- 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:
- 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);
+ if (ActiveScheme != PathDiagnosticConsumer::None) {
+ if (!LastPiece)
+ LastPiece = BugReporterVisitor::getDefaultEndPath(PDB, N, *R);
+ assert(LastPiece);
+ PD.setEndOfPath(LastPiece);
}
- break;
- case PathDiagnosticConsumer::None:
- 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);
+
+ switch (ActiveScheme) {
+ case PathDiagnosticConsumer::Extensive:
+ GenerateExtensivePathDiagnostic(PD, PDB, N, visitors);
+ break;
+ case PathDiagnosticConsumer::Minimal:
+ GenerateMinimalPathDiagnostic(PD, PDB, N, visitors);
+ break;
+ case PathDiagnosticConsumer::None:
+ GenerateVisitorsOnlyPathDiagnostic(PD, PDB, N, visitors);
+ break;
}
- break;
- }
- // Clean up the visitors we used.
- llvm::DeleteContainerPointers(visitors);
+ // Clean up the visitors we used.
+ llvm::DeleteContainerPointers(visitors);
- // Did anything change while generating this path?
- finalReportConfigToken = R->getConfigurationChangeToken();
- } while(finalReportConfigToken != originalReportConfigToken);
+ // Did anything change while generating this path?
+ finalReportConfigToken = R->getConfigurationChangeToken();
+ } while (finalReportConfigToken != origReportConfigToken);
- // Finally, prune the diagnostic path of uninteresting stuff.
- if (!PD.path.empty()) {
- // Remove messages that are basically the same.
- removeRedundantMsgs(PD.getMutablePieces());
+ if (!R->isValid())
+ continue;
- if (R->shouldPrunePath()) {
- bool hasSomethingInteresting = RemoveUneededCalls(PD.getMutablePieces(),
- R);
- assert(hasSomethingInteresting);
- (void) hasSomethingInteresting;
+ // Finally, prune the diagnostic path of uninteresting stuff.
+ if (!PD.path.empty()) {
+ // Remove messages that are basically the same.
+ removeRedundantMsgs(PD.getMutablePieces());
+
+ if (R->shouldPrunePath() &&
+ getEngine().getAnalysisManager().options.shouldPrunePaths()) {
+ bool stillHasNotes = RemoveUnneededCalls(PD.getMutablePieces(), R);
+ assert(stillHasNotes);
+ (void)stillHasNotes;
+ }
+
+ adjustCallLocations(PD.getMutablePieces());
}
+
+ // We found a report and didn't suppress it.
+ return true;
}
- return true;
+ // We suppressed all the reports in this equivalence class.
+ assert(!HasInvalid && "Inconsistent suppression");
+ (void)HasInvalid;
+ return false;
}
void BugReporter::Register(BugType *BT) {
@@ -2265,7 +2430,12 @@ void BugReporter::FlushReport(BugReport *exampleReport,
exampleReport->getBugType().getName(),
exampleReport->getDescription(),
exampleReport->getShortDescription(/*Fallback=*/false),
- BT.getCategory()));
+ BT.getCategory(),
+ exampleReport->getUniqueingLocation(),
+ exampleReport->getUniqueingDecl()));
+
+ MaxBugClassSize = std::max(bugReports.size(),
+ static_cast<size_t>(MaxBugClassSize));
// Generate the full path diagnostic, using the generation scheme
// specified by the PathDiagnosticConsumer. Note that we have to generate
@@ -2275,6 +2445,9 @@ void BugReporter::FlushReport(BugReport *exampleReport,
if (!generatePathDiagnostic(*D.get(), PD, bugReports))
return;
+ MaxValidBugClassSize = std::max(bugReports.size(),
+ static_cast<size_t>(MaxValidBugClassSize));
+
// If the path is empty, generate a single step path with the location
// of the issue.
if (D->path.empty()) {
diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 328e8a6..f600362 100644
--- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -12,22 +12,23 @@
//
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h"
-
#include "clang/AST/Expr.h"
#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 "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
+using llvm::FoldingSetNodeID;
+
//===----------------------------------------------------------------------===//
// Utility functions.
//===----------------------------------------------------------------------===//
@@ -39,37 +40,33 @@ bool bugreporter::isDeclRefExprToReference(const Expr *E) {
return false;
}
-const Stmt *bugreporter::GetDerefExpr(const ExplodedNode *N) {
+const Expr *bugreporter::getDerefExpr(const Stmt *S) {
// Pattern match for a few useful cases (do something smarter later):
// a[0], p->f, *p
- const PostStmt *Loc = N->getLocationAs<PostStmt>();
- if (!Loc)
- return 0;
-
- const Expr *S = dyn_cast<Expr>(Loc->getStmt());
- if (!S)
+ const Expr *E = dyn_cast<Expr>(S);
+ if (!E)
return 0;
- S = S->IgnoreParenCasts();
+ E = E->IgnoreParenCasts();
while (true) {
- if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) {
+ if (const BinaryOperator *B = dyn_cast<BinaryOperator>(E)) {
assert(B->isAssignmentOp());
- S = B->getLHS()->IgnoreParenCasts();
+ E = B->getLHS()->IgnoreParenCasts();
continue;
}
- else if (const UnaryOperator *U = dyn_cast<UnaryOperator>(S)) {
+ else if (const UnaryOperator *U = dyn_cast<UnaryOperator>(E)) {
if (U->getOpcode() == UO_Deref)
return U->getSubExpr()->IgnoreParenCasts();
}
- else if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) {
+ else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
if (ME->isArrow() || isDeclRefExprToReference(ME->getBase())) {
return ME->getBase()->IgnoreParenCasts();
}
}
- else if (const ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(S)) {
+ else if (const ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) {
return IvarRef->getBase()->IgnoreParenCasts();
}
- else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(S)) {
+ else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(E)) {
return AE->getBase();
}
break;
@@ -137,13 +134,15 @@ class ReturnVisitor : public BugReporterVisitorImpl<ReturnVisitor> {
const StackFrameContext *StackFrame;
enum {
Initial,
- MaybeSuppress,
+ MaybeUnsuppress,
Satisfied
} Mode;
+ bool EnableNullFPSuppression;
+
public:
- ReturnVisitor(const StackFrameContext *Frame)
- : StackFrame(Frame), Mode(Initial) {}
+ ReturnVisitor(const StackFrameContext *Frame, bool Suppressed)
+ : StackFrame(Frame), Mode(Initial), EnableNullFPSuppression(Suppressed) {}
static void *getTag() {
static int Tag = 0;
@@ -153,6 +152,7 @@ public:
virtual void Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddPointer(ReturnVisitor::getTag());
ID.AddPointer(StackFrame);
+ ID.AddBoolean(EnableNullFPSuppression);
}
/// Adds a ReturnVisitor if the given statement represents a call that was
@@ -163,16 +163,17 @@ public:
/// 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) {
+ BugReport &BR,
+ bool InEnableNullFPSuppression) {
if (!CallEvent::isCallStmt(S))
return;
// First, find when we processed the statement.
do {
- if (const CallExitEnd *CEE = Node->getLocationAs<CallExitEnd>())
+ if (Optional<CallExitEnd> CEE = Node->getLocationAs<CallExitEnd>())
if (CEE->getCalleeContext()->getCallSite() == S)
break;
- if (const StmtPoint *SP = Node->getLocationAs<StmtPoint>())
+ if (Optional<StmtPoint> SP = Node->getLocationAs<StmtPoint>())
if (SP->getStmt() == S)
break;
@@ -180,19 +181,41 @@ public:
} while (Node);
// Next, step over any post-statement checks.
- while (Node && isa<PostStmt>(Node->getLocation()))
+ while (Node && Node->getLocation().getAs<PostStmt>())
Node = Node->getFirstPred();
+ if (!Node)
+ return;
// Finally, see if we inlined the call.
- if (Node) {
- if (const CallExitEnd *CEE = Node->getLocationAs<CallExitEnd>()) {
- const StackFrameContext *CalleeContext = CEE->getCalleeContext();
- if (CalleeContext->getCallSite() == S) {
- BR.markInteresting(CalleeContext);
- BR.addVisitor(new ReturnVisitor(CalleeContext));
- }
- }
- }
+ Optional<CallExitEnd> CEE = Node->getLocationAs<CallExitEnd>();
+ if (!CEE)
+ return;
+
+ const StackFrameContext *CalleeContext = CEE->getCalleeContext();
+ if (CalleeContext->getCallSite() != S)
+ return;
+
+ // Check the return value.
+ ProgramStateRef State = Node->getState();
+ SVal RetVal = State->getSVal(S, Node->getLocationContext());
+
+ // Handle cases where a reference is returned and then immediately used.
+ if (cast<Expr>(S)->isGLValue())
+ if (Optional<Loc> LValue = RetVal.getAs<Loc>())
+ RetVal = State->getSVal(*LValue);
+
+ // See if the return value is NULL. If so, suppress the report.
+ SubEngine *Eng = State->getStateManager().getOwningEngine();
+ assert(Eng && "Cannot file a bug report without an owning engine");
+ AnalyzerOptions &Options = Eng->getAnalysisManager().options;
+
+ bool EnableNullFPSuppression = false;
+ if (InEnableNullFPSuppression && Options.shouldSuppressNullReturnPaths())
+ if (Optional<Loc> RetLoc = RetVal.getAs<Loc>())
+ EnableNullFPSuppression = State->isNull(*RetLoc).isConstrainedTrue();
+
+ BR.markInteresting(CalleeContext);
+ BR.addVisitor(new ReturnVisitor(CalleeContext, EnableNullFPSuppression));
}
/// Returns true if any counter-suppression heuristics are enabled for
@@ -209,7 +232,7 @@ public:
if (N->getLocationContext() != StackFrame)
return 0;
- const StmtPoint *SP = N->getLocationAs<StmtPoint>();
+ Optional<StmtPoint> SP = N->getLocationAs<StmtPoint>();
if (!SP)
return 0;
@@ -229,35 +252,49 @@ public:
const Expr *RetE = Ret->getRetValue();
assert(RetE && "Tracking a return value for a void function");
+
+ // Handle cases where a reference is returned and then immediately used.
+ Optional<Loc> LValue;
+ if (RetE->isGLValue()) {
+ if ((LValue = V.getAs<Loc>())) {
+ SVal RValue = State->getRawSVal(*LValue, RetE->getType());
+ if (RValue.getAs<DefinedSVal>())
+ V = RValue;
+ }
+ }
+
+ // Ignore aggregate rvalues.
+ if (V.getAs<nonloc::LazyCompoundVal>() ||
+ V.getAs<nonloc::CompoundVal>())
+ return 0;
+
RetE = RetE->IgnoreParenCasts();
// If we can't prove the return value is 0, just mark it interesting, and
// make sure to track it into any further inner functions.
- if (State->assume(cast<DefinedSVal>(V), true)) {
+ if (!State->isNull(V).isConstrainedTrue()) {
BR.markInteresting(V);
- ReturnVisitor::addVisitorIfNecessary(N, RetE, BR);
+ ReturnVisitor::addVisitorIfNecessary(N, RetE, BR,
+ EnableNullFPSuppression);
return 0;
}
// If we're returning 0, we should track where that 0 came from.
- bugreporter::trackNullOrUndefValue(N, RetE, BR);
+ bugreporter::trackNullOrUndefValue(N, RetE, BR, /*IsArg*/ false,
+ EnableNullFPSuppression);
// Build an appropriate message based on the return value.
SmallString<64> Msg;
llvm::raw_svector_ostream Out(Msg);
- if (isa<Loc>(V)) {
- // If we are pruning null-return paths as unlikely error paths, mark the
- // report invalid. We still want to emit a path note, however, in case
+ if (V.getAs<Loc>()) {
+ // If we have counter-suppression enabled, make sure we keep visiting
+ // future nodes. We want to emit a path note as well, 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 (EnableNullFPSuppression && hasCounterSuppression(Options))
+ Mode = MaybeUnsuppress;
if (RetE->getType()->isObjCObjectPointerType())
Out << "Returning nil";
@@ -267,21 +304,37 @@ public:
Out << "Returning zero";
}
- // FIXME: We should have a more generalized location printing mechanism.
- if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetE))
- if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(DR->getDecl()))
- Out << " (loaded from '" << *DD << "')";
+ if (LValue) {
+ if (const MemRegion *MR = LValue->getAsRegion()) {
+ if (MR->canPrintPretty()) {
+ Out << " (reference to '";
+ MR->printPretty(Out);
+ Out << "')";
+ }
+ }
+ } else {
+ // FIXME: We should have a more generalized location printing mechanism.
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetE))
+ if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(DR->getDecl()))
+ Out << " (loaded from '" << *DD << "')";
+ }
PathDiagnosticLocation L(Ret, BRC.getSourceManager(), StackFrame);
return new PathDiagnosticEventPiece(L, Out.str());
}
- PathDiagnosticPiece *visitNodeMaybeSuppress(const ExplodedNode *N,
- const ExplodedNode *PrevN,
- BugReporterContext &BRC,
- BugReport &BR) {
+ PathDiagnosticPiece *visitNodeMaybeUnsuppress(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR) {
+#ifndef NDEBUG
+ ExprEngine &Eng = BRC.getBugReporter().getEngine();
+ AnalyzerOptions &Options = Eng.getAnalysisManager().options;
+ assert(hasCounterSuppression(Options));
+#endif
+
// Are we at the entry node for this call?
- const CallEnter *CE = N->getLocationAs<CallEnter>();
+ Optional<CallEnter> CE = N->getLocationAs<CallEnter>();
if (!CE)
return 0;
@@ -290,41 +343,36 @@ public:
Mode = Satisfied;
- ExprEngine &Eng = BRC.getBugReporter().getEngine();
- AnalyzerOptions &Options = Eng.getAnalysisManager().options;
- if (Options.shouldAvoidSuppressingNullArgumentPaths()) {
- // Don't automatically suppress a report if one of the arguments is
- // known to be a null pointer. Instead, start tracking /that/ null
- // value back to its origin.
- ProgramStateManager &StateMgr = BRC.getStateManager();
- CallEventManager &CallMgr = StateMgr.getCallEventManager();
-
- ProgramStateRef State = N->getState();
- CallEventRef<> Call = CallMgr.getCaller(StackFrame, State);
- for (unsigned I = 0, E = Call->getNumArgs(); I != E; ++I) {
- SVal ArgV = Call->getArgSVal(I);
- if (!isa<Loc>(ArgV))
- continue;
+ // 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();
- const Expr *ArgE = Call->getArgExpr(I);
- if (!ArgE)
- continue;
-
- // Is it possible for this argument to be non-null?
- if (State->assume(cast<Loc>(ArgV), true))
- continue;
-
- if (bugreporter::trackNullOrUndefValue(N, ArgE, BR, /*IsArg=*/true))
- return 0;
-
- // If we /can't/ track the null pointer, we should err on the side of
- // false negatives, and continue towards marking this report invalid.
- // (We will still look at the other arguments, though.)
- }
+ ProgramStateRef State = N->getState();
+ CallEventRef<> Call = CallMgr.getCaller(StackFrame, State);
+ for (unsigned I = 0, E = Call->getNumArgs(); I != E; ++I) {
+ Optional<Loc> ArgV = Call->getArgSVal(I).getAs<Loc>();
+ if (!ArgV)
+ continue;
+
+ const Expr *ArgE = Call->getArgExpr(I);
+ if (!ArgE)
+ continue;
+
+ // Is it possible for this argument to be non-null?
+ if (!State->isNull(*ArgV).isConstrainedTrue())
+ continue;
+
+ if (bugreporter::trackNullOrUndefValue(N, ArgE, BR, /*IsArg=*/true,
+ EnableNullFPSuppression))
+ BR.removeInvalidation(ReturnVisitor::getTag(), StackFrame);
+
+ // 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;
}
@@ -335,14 +383,22 @@ public:
switch (Mode) {
case Initial:
return visitNodeInitial(N, PrevN, BRC, BR);
- case MaybeSuppress:
- return visitNodeMaybeSuppress(N, PrevN, BRC, BR);
+ case MaybeUnsuppress:
+ return visitNodeMaybeUnsuppress(N, PrevN, BRC, BR);
case Satisfied:
return 0;
}
llvm_unreachable("Invalid visit mode!");
}
+
+ PathDiagnosticPiece *getEndPath(BugReporterContext &BRC,
+ const ExplodedNode *N,
+ BugReport &BR) {
+ if (EnableNullFPSuppression)
+ BR.markInvalid(ReturnVisitor::getTag(), StackFrame);
+ return 0;
+ }
};
} // end anonymous namespace
@@ -352,6 +408,7 @@ void FindLastStoreBRVisitor ::Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddPointer(&tag);
ID.AddPointer(R);
ID.Add(V);
+ ID.AddBoolean(EnableNullFPSuppression);
}
PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
@@ -359,7 +416,7 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
BugReporterContext &BRC,
BugReport &BR) {
- if (satisfied)
+ if (Satisfied)
return NULL;
const ExplodedNode *StoreSite = 0;
@@ -368,7 +425,7 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
// First see if we reached the declaration of the region.
if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
- if (const PostStmt *P = Pred->getLocationAs<PostStmt>()) {
+ if (Optional<PostStmt> P = Pred->getLocationAs<PostStmt>()) {
if (const DeclStmt *DS = P->getStmtAs<DeclStmt>()) {
if (DS->getSingleDecl() == VR->getDecl()) {
StoreSite = Pred;
@@ -378,19 +435,36 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
}
}
- // Otherwise, check that Succ has this binding and Pred does not, i.e. this is
- // where the binding first occurred.
+ // If this is a post initializer expression, initializing the region, we
+ // should track the initializer expression.
+ if (Optional<PostInitializer> PIP = Pred->getLocationAs<PostInitializer>()) {
+ const MemRegion *FieldReg = (const MemRegion *)PIP->getLocationValue();
+ if (FieldReg && FieldReg == R) {
+ StoreSite = Pred;
+ InitE = PIP->getInitializer()->getInit();
+ }
+ }
+
+ // Otherwise, see if this is the store site:
+ // (1) Succ has this binding and Pred does not, i.e. this is
+ // where the binding first occurred.
+ // (2) Succ has this binding and is a PostStore node for this region, i.e.
+ // the same binding was re-assigned here.
if (!StoreSite) {
if (Succ->getState()->getSVal(R) != V)
return NULL;
- if (Pred->getState()->getSVal(R) == V)
- return NULL;
+
+ if (Pred->getState()->getSVal(R) == V) {
+ Optional<PostStore> PS = Succ->getLocationAs<PostStore>();
+ if (!PS || PS->getLocationValue() != R)
+ return NULL;
+ }
StoreSite = Succ;
// If this is an assignment expression, we can track the value
// being assigned.
- if (const PostStmt *P = Succ->getLocationAs<PostStmt>())
+ if (Optional<PostStmt> P = Succ->getLocationAs<PostStmt>())
if (const BinaryOperator *BO = P->getStmtAs<BinaryOperator>())
if (BO->isAssignmentOp())
InitE = BO->getRHS();
@@ -399,34 +473,41 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
// FIXME: Handle CXXThisRegion as well. (This is not a priority because
// 'this' should never be NULL, but this visitor isn't just for NULL and
// UndefinedVal.)
- if (const CallEnter *CE = Succ->getLocationAs<CallEnter>()) {
- const VarRegion *VR = cast<VarRegion>(R);
- const ParmVarDecl *Param = cast<ParmVarDecl>(VR->getDecl());
-
- ProgramStateManager &StateMgr = BRC.getStateManager();
- CallEventManager &CallMgr = StateMgr.getCallEventManager();
-
- CallEventRef<> Call = CallMgr.getCaller(CE->getCalleeContext(),
- Succ->getState());
- InitE = Call->getArgExpr(Param->getFunctionScopeIndex());
- IsParam = true;
+ if (Optional<CallEnter> CE = Succ->getLocationAs<CallEnter>()) {
+ if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
+ const ParmVarDecl *Param = cast<ParmVarDecl>(VR->getDecl());
+
+ ProgramStateManager &StateMgr = BRC.getStateManager();
+ CallEventManager &CallMgr = StateMgr.getCallEventManager();
+
+ CallEventRef<> Call = CallMgr.getCaller(CE->getCalleeContext(),
+ Succ->getState());
+ InitE = Call->getArgExpr(Param->getFunctionScopeIndex());
+ IsParam = true;
+ }
}
+
+ // If this is a CXXTempObjectRegion, the Expr responsible for its creation
+ // is wrapped inside of it.
+ if (const CXXTempObjectRegion *TmpR = dyn_cast<CXXTempObjectRegion>(R))
+ InitE = TmpR->getExpr();
}
if (!StoreSite)
return NULL;
- satisfied = true;
+ Satisfied = true;
// If we have an expression that provided the value, try to track where it
// came from.
if (InitE) {
- if (V.isUndef() || isa<loc::ConcreteInt>(V)) {
+ if (V.isUndef() || V.getAs<loc::ConcreteInt>()) {
if (!IsParam)
InitE = InitE->IgnoreParenCasts();
- bugreporter::trackNullOrUndefValue(StoreSite, InitE, BR, IsParam);
+ bugreporter::trackNullOrUndefValue(StoreSite, InitE, BR, IsParam,
+ EnableNullFPSuppression);
} else {
ReturnVisitor::addVisitorIfNecessary(StoreSite, InitE->IgnoreParenCasts(),
- BR);
+ BR, EnableNullFPSuppression);
}
}
@@ -437,73 +518,103 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
SmallString<256> sbuf;
llvm::raw_svector_ostream os(sbuf);
- if (const PostStmt *PS = StoreSite->getLocationAs<PostStmt>()) {
- if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) {
-
- if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
- os << "Variable '" << *VR->getDecl() << "' ";
+ if (Optional<PostStmt> PS = StoreSite->getLocationAs<PostStmt>()) {
+ const Stmt *S = PS->getStmt();
+ const char *action = 0;
+ const DeclStmt *DS = dyn_cast<DeclStmt>(S);
+ const VarRegion *VR = dyn_cast<VarRegion>(R);
+
+ if (DS) {
+ action = "initialized to ";
+ } else if (isa<BlockExpr>(S)) {
+ action = "captured by block as ";
+ if (VR) {
+ // See if we can get the BlockVarRegion.
+ ProgramStateRef State = StoreSite->getState();
+ SVal V = State->getSVal(S, PS->getLocationContext());
+ if (const BlockDataRegion *BDR =
+ dyn_cast_or_null<BlockDataRegion>(V.getAsRegion())) {
+ if (const VarRegion *OriginalR = BDR->getOriginalRegion(VR)) {
+ if (Optional<KnownSVal> KV =
+ State->getSVal(OriginalR).getAs<KnownSVal>())
+ BR.addVisitor(new FindLastStoreBRVisitor(*KV, OriginalR,
+ EnableNullFPSuppression));
+ }
+ }
}
- else
- return NULL;
+ }
+
+ if (action) {
+ if (!R)
+ return 0;
- if (isa<loc::ConcreteInt>(V)) {
+ os << '\'';
+ R->printPretty(os);
+ os << "' ";
+
+ if (V.getAs<loc::ConcreteInt>()) {
bool b = false;
if (R->isBoundable()) {
if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) {
if (TR->getValueType()->isObjCObjectPointerType()) {
- os << "initialized to nil";
+ os << action << "nil";
b = true;
}
}
}
if (!b)
- os << "initialized to a null pointer value";
- }
- else if (isa<nonloc::ConcreteInt>(V)) {
- os << "initialized to " << cast<nonloc::ConcreteInt>(V).getValue();
+ os << action << "a null pointer value";
+ } else if (Optional<nonloc::ConcreteInt> CVal =
+ V.getAs<nonloc::ConcreteInt>()) {
+ os << action << CVal->getValue();
}
- else if (V.isUndef()) {
- if (isa<VarRegion>(R)) {
- const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
- if (VD->getInit())
- os << "initialized to a garbage value";
- else
- os << "declared without an initial value";
+ else if (DS) {
+ if (V.isUndef()) {
+ if (isa<VarRegion>(R)) {
+ const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
+ if (VD->getInit())
+ os << "initialized to a garbage value";
+ else
+ os << "declared without an initial value";
+ }
+ }
+ else {
+ os << "initialized here";
}
- }
- else {
- os << "initialized here";
}
}
- } else if (isa<CallEnter>(StoreSite->getLocation())) {
- const ParmVarDecl *Param = cast<ParmVarDecl>(cast<VarRegion>(R)->getDecl());
+ } else if (StoreSite->getLocation().getAs<CallEnter>()) {
+ if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
+ const ParmVarDecl *Param = cast<ParmVarDecl>(VR->getDecl());
- os << "Passing ";
+ os << "Passing ";
- if (isa<loc::ConcreteInt>(V)) {
- if (Param->getType()->isObjCObjectPointerType())
- os << "nil object reference";
- else
- os << "null pointer value";
- } else if (V.isUndef()) {
- os << "uninitialized value";
- } else if (isa<nonloc::ConcreteInt>(V)) {
- os << "the value " << cast<nonloc::ConcreteInt>(V).getValue();
- } else {
- os << "value";
- }
+ if (V.getAs<loc::ConcreteInt>()) {
+ if (Param->getType()->isObjCObjectPointerType())
+ os << "nil object reference";
+ else
+ os << "null pointer value";
+ } else if (V.isUndef()) {
+ os << "uninitialized value";
+ } else if (Optional<nonloc::ConcreteInt> CI =
+ V.getAs<nonloc::ConcreteInt>()) {
+ os << "the value " << CI->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 '";
+ // 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 << '\'';
+ R->printPretty(os);
+ os << '\'';
+ }
}
if (os.str().empty()) {
- if (isa<loc::ConcreteInt>(V)) {
+ if (V.getAs<loc::ConcreteInt>()) {
bool b = false;
if (R->isBoundable()) {
if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) {
@@ -519,10 +630,9 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
}
else if (V.isUndef()) {
os << "Uninitialized value stored to ";
- }
- else if (isa<nonloc::ConcreteInt>(V)) {
- os << "The value " << cast<nonloc::ConcreteInt>(V).getValue()
- << " is assigned to ";
+ } else if (Optional<nonloc::ConcreteInt> CV =
+ V.getAs<nonloc::ConcreteInt>()) {
+ os << "The value " << CV->getValue() << " is assigned to ";
}
else
os << "Value assigned to ";
@@ -535,7 +645,7 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
// Construct a new PathDiagnosticPiece.
ProgramPoint P = StoreSite->getLocation();
PathDiagnosticLocation L;
- if (isa<CallEnter>(P))
+ if (P.getAs<CallEnter>() && InitE)
L = PathDiagnosticLocation(InitE, BRC.getSourceManager(),
P.getLocationContext());
else
@@ -558,32 +668,38 @@ const char *TrackConstraintBRVisitor::getTag() {
return "TrackConstraintBRVisitor";
}
+bool TrackConstraintBRVisitor::isUnderconstrained(const ExplodedNode *N) const {
+ if (IsZeroCheck)
+ return N->getState()->isNull(Constraint).isUnderconstrained();
+ return N->getState()->assume(Constraint, !Assumption);
+}
+
PathDiagnosticPiece *
TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N,
const ExplodedNode *PrevN,
BugReporterContext &BRC,
BugReport &BR) {
- if (isSatisfied)
+ if (IsSatisfied)
return NULL;
// Check if in the previous state it was feasible for this constraint
// to *not* be true.
- if (PrevN->getState()->assume(Constraint, !Assumption)) {
+ if (isUnderconstrained(PrevN)) {
- isSatisfied = true;
+ IsSatisfied = true;
// As a sanity check, make sure that the negation of the constraint
// was infeasible in the current state. If it is feasible, we somehow
// missed the transition point.
- if (N->getState()->assume(Constraint, !Assumption))
+ if (isUnderconstrained(N))
return NULL;
// We found the transition point for the constraint. We now need to
// pretty-print the constraint. (work-in-progress)
- std::string sbuf;
- llvm::raw_string_ostream os(sbuf);
+ SmallString<64> sbuf;
+ llvm::raw_svector_ostream os(sbuf);
- if (isa<Loc>(Constraint)) {
+ if (Constraint.getAs<Loc>()) {
os << "Assuming pointer value is ";
os << (Assumption ? "non-null" : "null");
}
@@ -606,25 +722,151 @@ TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N,
return NULL;
}
-bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S,
- BugReport &report, bool IsArg) {
+SuppressInlineDefensiveChecksVisitor::
+SuppressInlineDefensiveChecksVisitor(DefinedSVal Value, const ExplodedNode *N)
+ : V(Value), IsSatisfied(false), IsTrackingTurnedOn(false) {
+
+ // Check if the visitor is disabled.
+ SubEngine *Eng = N->getState()->getStateManager().getOwningEngine();
+ assert(Eng && "Cannot file a bug report without an owning engine");
+ AnalyzerOptions &Options = Eng->getAnalysisManager().options;
+ if (!Options.shouldSuppressInlinedDefensiveChecks())
+ IsSatisfied = true;
+
+ assert(N->getState()->isNull(V).isConstrainedTrue() &&
+ "The visitor only tracks the cases where V is constrained to 0");
+}
+
+void SuppressInlineDefensiveChecksVisitor::Profile(FoldingSetNodeID &ID) const {
+ static int id = 0;
+ ID.AddPointer(&id);
+ ID.Add(V);
+}
+
+const char *SuppressInlineDefensiveChecksVisitor::getTag() {
+ return "IDCVisitor";
+}
+
+PathDiagnosticPiece *
+SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *Succ,
+ const ExplodedNode *Pred,
+ BugReporterContext &BRC,
+ BugReport &BR) {
+ if (IsSatisfied)
+ return 0;
+
+ // Start tracking after we see the first state in which the value is null.
+ if (!IsTrackingTurnedOn)
+ if (Succ->getState()->isNull(V).isConstrainedTrue())
+ IsTrackingTurnedOn = true;
+ if (!IsTrackingTurnedOn)
+ return 0;
+
+ // Check if in the previous state it was feasible for this value
+ // to *not* be null.
+ if (!Pred->getState()->isNull(V).isConstrainedTrue()) {
+ IsSatisfied = true;
+
+ assert(Succ->getState()->isNull(V).isConstrainedTrue());
+
+ // Check if this is inlined defensive checks.
+ const LocationContext *CurLC =Succ->getLocationContext();
+ const LocationContext *ReportLC = BR.getErrorNode()->getLocationContext();
+ if (CurLC != ReportLC && !CurLC->isParentOf(ReportLC))
+ BR.markInvalid("Suppress IDC", CurLC);
+ }
+ return 0;
+}
+
+static const MemRegion *getLocationRegionIfReference(const Expr *E,
+ const ExplodedNode *N) {
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
+ if (!VD->getType()->isReferenceType())
+ return 0;
+ ProgramStateManager &StateMgr = N->getState()->getStateManager();
+ MemRegionManager &MRMgr = StateMgr.getRegionManager();
+ return MRMgr.getVarRegion(VD, N->getLocationContext());
+ }
+ }
+
+ // FIXME: This does not handle other kinds of null references,
+ // for example, references from FieldRegions:
+ // struct Wrapper { int &ref; };
+ // Wrapper w = { *(int *)0 };
+ // w.ref = 1;
+
+ return 0;
+}
+
+static const Expr *peelOffOuterExpr(const Expr *Ex,
+ const ExplodedNode *N) {
+ Ex = Ex->IgnoreParenCasts();
+ if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Ex))
+ return peelOffOuterExpr(EWC->getSubExpr(), N);
+ if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(Ex))
+ return peelOffOuterExpr(OVE->getSourceExpr(), N);
+
+ // Peel off the ternary operator.
+ if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(Ex)) {
+ // Find a node where the branching occured and find out which branch
+ // we took (true/false) by looking at the ExplodedGraph.
+ const ExplodedNode *NI = N;
+ do {
+ ProgramPoint ProgPoint = NI->getLocation();
+ if (Optional<BlockEdge> BE = ProgPoint.getAs<BlockEdge>()) {
+ const CFGBlock *srcBlk = BE->getSrc();
+ if (const Stmt *term = srcBlk->getTerminator()) {
+ if (term == CO) {
+ bool TookTrueBranch = (*(srcBlk->succ_begin()) == BE->getDst());
+ if (TookTrueBranch)
+ return peelOffOuterExpr(CO->getTrueExpr(), N);
+ else
+ return peelOffOuterExpr(CO->getFalseExpr(), N);
+ }
+ }
+ }
+ NI = NI->getFirstPred();
+ } while (NI);
+ }
+ return Ex;
+}
+
+bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N,
+ const Stmt *S,
+ BugReport &report, bool IsArg,
+ bool EnableNullFPSuppression) {
if (!S || !N)
return false;
- if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(S))
- S = OVE->getSourceExpr();
+ if (const Expr *Ex = dyn_cast<Expr>(S)) {
+ Ex = Ex->IgnoreParenCasts();
+ const Expr *PeeledEx = peelOffOuterExpr(Ex, N);
+ if (Ex != PeeledEx)
+ S = PeeledEx;
+ }
+
+ const Expr *Inner = 0;
+ if (const Expr *Ex = dyn_cast<Expr>(S)) {
+ Ex = Ex->IgnoreParenCasts();
+ if (ExplodedGraph::isInterestingLValueExpr(Ex) || CallEvent::isCallStmt(Ex))
+ Inner = Ex;
+ }
if (IsArg) {
- assert(isa<CallEnter>(N->getLocation()) && "Tracking arg but not at call");
+ assert(N->getLocation().getAs<CallEnter>() && "Tracking arg but not at call");
} else {
// Walk through nodes until we get one that matches the statement exactly.
+ // Alternately, if we hit a known lvalue for the statement, we know we've
+ // gone too far (though we can likely track the lvalue better anyway).
do {
const ProgramPoint &pp = N->getLocation();
- if (const PostStmt *ps = dyn_cast<PostStmt>(&pp)) {
- if (ps->getStmt() == S)
+ if (Optional<StmtPoint> ps = pp.getAs<StmtPoint>()) {
+ if (ps->getStmt() == S || ps->getStmt() == Inner)
break;
- } else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&pp)) {
- if (CEE->getCalleeContext()->getCallSite() == S)
+ } else if (Optional<CallExitEnd> CEE = pp.getAs<CallExitEnd>()) {
+ if (CEE->getCalleeContext()->getCallSite() == S ||
+ CEE->getCalleeContext()->getCallSite() == Inner)
break;
}
N = N->getFirstPred();
@@ -636,129 +878,167 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S,
ProgramStateRef state = N->getState();
- // See if the expression we're interested refers to a variable.
+ // The message send could be nil due to the receiver being nil.
+ // At this point in the path, the receiver should be live since we are at the
+ // message send expr. If it is nil, start tracking it.
+ if (const Expr *Receiver = NilReceiverBRVisitor::getNilReceiver(S, N))
+ trackNullOrUndefValue(N, Receiver, report, IsArg, EnableNullFPSuppression);
+
+
+ // See if the expression we're interested refers to a variable.
// If so, we can track both its contents and constraints on its value.
- if (const Expr *Ex = dyn_cast<Expr>(S)) {
- // Strip off parens and casts. Note that this will never have issues with
- // C++ user-defined implicit conversions, because those have a constructor
- // or function call inside.
- Ex = Ex->IgnoreParenCasts();
- if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) {
- // FIXME: Right now we only track VarDecls because it's non-trivial to
- // get a MemRegion for any other DeclRefExprs. <rdar://problem/12114812>
- if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
- ProgramStateManager &StateMgr = state->getStateManager();
- MemRegionManager &MRMgr = StateMgr.getRegionManager();
- const VarRegion *R = MRMgr.getVarRegion(VD, N->getLocationContext());
-
- // Mark both the variable region and its contents as interesting.
- SVal V = state->getRawSVal(loc::MemRegionVal(R));
-
- // If the value matches the default for the variable region, that
- // might mean that it's been cleared out of the state. Fall back to
- // the full argument expression (with casts and such intact).
- if (IsArg) {
- bool UseArgValue = V.isUnknownOrUndef() || V.isZeroConstant();
- if (!UseArgValue) {
- const SymbolRegionValue *SRV =
- dyn_cast_or_null<SymbolRegionValue>(V.getAsLocSymbol());
- if (SRV)
- UseArgValue = (SRV->getRegion() == R);
- }
- if (UseArgValue)
- V = state->getSValAsScalarOrLoc(S, N->getLocationContext());
+ if (Inner && ExplodedGraph::isInterestingLValueExpr(Inner)) {
+ const MemRegion *R = 0;
+
+ // Find the ExplodedNode where the lvalue (the value of 'Ex')
+ // was computed. We need this for getting the location value.
+ const ExplodedNode *LVNode = N;
+ while (LVNode) {
+ if (Optional<PostStmt> P = LVNode->getLocation().getAs<PostStmt>()) {
+ if (P->getStmt() == Inner)
+ break;
+ }
+ LVNode = LVNode->getFirstPred();
+ }
+ assert(LVNode && "Unable to find the lvalue node.");
+ ProgramStateRef LVState = LVNode->getState();
+ SVal LVal = LVState->getSVal(Inner, LVNode->getLocationContext());
+
+ if (LVState->isNull(LVal).isConstrainedTrue()) {
+ // In case of C++ references, we want to differentiate between a null
+ // reference and reference to null pointer.
+ // If the LVal is null, check if we are dealing with null reference.
+ // For those, we want to track the location of the reference.
+ if (const MemRegion *RR = getLocationRegionIfReference(Inner, N))
+ R = RR;
+ } else {
+ R = LVState->getSVal(Inner, LVNode->getLocationContext()).getAsRegion();
+
+ // If this is a C++ reference to a null pointer, we are tracking the
+ // pointer. In additon, we should find the store at which the reference
+ // got initialized.
+ if (const MemRegion *RR = getLocationRegionIfReference(Inner, N)) {
+ if (Optional<KnownSVal> KV = LVal.getAs<KnownSVal>())
+ report.addVisitor(new FindLastStoreBRVisitor(*KV, RR,
+ EnableNullFPSuppression));
+ }
+ }
+
+ if (R) {
+ // Mark both the variable region and its contents as interesting.
+ SVal V = state->getRawSVal(loc::MemRegionVal(R));
+
+ // If the value matches the default for the variable region, that
+ // might mean that it's been cleared out of the state. Fall back to
+ // the full argument expression (with casts and such intact).
+ if (IsArg) {
+ bool UseArgValue = V.isUnknownOrUndef() || V.isZeroConstant();
+ if (!UseArgValue) {
+ const SymbolRegionValue *SRV =
+ dyn_cast_or_null<SymbolRegionValue>(V.getAsLocSymbol());
+ if (SRV)
+ UseArgValue = (SRV->getRegion() == R);
}
+ if (UseArgValue)
+ V = state->getSValAsScalarOrLoc(S, N->getLocationContext());
+ }
- report.markInteresting(R);
- report.markInteresting(V);
- report.addVisitor(new UndefOrNullArgVisitor(R));
+ 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<DefinedSVal>(V), false);
- report.addVisitor(ConstraintTracker);
- }
+ if (isa<SymbolicRegion>(R)) {
+ TrackConstraintBRVisitor *VI =
+ new TrackConstraintBRVisitor(loc::MemRegionVal(R), false);
+ report.addVisitor(VI);
+ }
- report.addVisitor(new FindLastStoreBRVisitor(V, R));
- return true;
+ // If the contents are symbolic, find out when they became null.
+ if (V.getAsLocSymbol()) {
+ BugReporterVisitor *ConstraintTracker =
+ new TrackConstraintBRVisitor(V.castAs<DefinedSVal>(), false);
+ report.addVisitor(ConstraintTracker);
+
+ // Add visitor, which will suppress inline defensive checks.
+ if (N->getState()->isNull(V).isConstrainedTrue() &&
+ EnableNullFPSuppression) {
+ BugReporterVisitor *IDCSuppressor =
+ new SuppressInlineDefensiveChecksVisitor(V.castAs<DefinedSVal>(),
+ N);
+ report.addVisitor(IDCSuppressor);
+ }
}
+
+ if (Optional<KnownSVal> KV = V.getAs<KnownSVal>())
+ report.addVisitor(new FindLastStoreBRVisitor(*KV, R,
+ EnableNullFPSuppression));
+ return true;
}
}
- // If the expression does NOT refer to a variable, we can still track
- // constraints on its contents.
+ // If the expression is not an "lvalue expression", we can still
+ // track the constraints on its contents.
SVal V = state->getSValAsScalarOrLoc(S, N->getLocationContext());
+ // If the value came from an inlined function call, we should at least make
+ // sure that function isn't pruned in our output.
+ if (const Expr *E = dyn_cast<Expr>(S))
+ S = E->IgnoreParenCasts();
+
+ ReturnVisitor::addVisitorIfNecessary(N, S, report, EnableNullFPSuppression);
+
// Uncomment this to find cases where we aren't properly getting the
// base value that was dereferenced.
// assert(!V.isUnknownOrUndef());
-
// Is it a symbolic value?
- if (loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&V)) {
+ if (Optional<loc::MemRegionVal> L = V.getAs<loc::MemRegionVal>()) {
// 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 (RegionRVal && isa<SymbolicRegion>(RegionRVal)) {
report.markInteresting(RegionRVal);
report.addVisitor(new TrackConstraintBRVisitor(
loc::MemRegionVal(RegionRVal), false));
}
- } else {
- // Otherwise, if the value came from an inlined function call,
- // we should at least make sure that function isn't pruned in our output.
- if (const Expr *E = dyn_cast<Expr>(S))
- S = E->IgnoreParenCasts();
- ReturnVisitor::addVisitorIfNecessary(N, S, report);
}
return true;
}
-BugReporterVisitor *
-FindLastStoreBRVisitor::createVisitorObject(const ExplodedNode *N,
- const MemRegion *R) {
- assert(R && "The memory region is null.");
-
- ProgramStateRef state = N->getState();
- SVal V = state->getSVal(R);
- if (V.isUnknown())
+const Expr *NilReceiverBRVisitor::getNilReceiver(const Stmt *S,
+ const ExplodedNode *N) {
+ const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S);
+ if (!ME)
return 0;
-
- return new FindLastStoreBRVisitor(V, R);
+ if (const Expr *Receiver = ME->getInstanceReceiver()) {
+ ProgramStateRef state = N->getState();
+ SVal V = state->getSVal(Receiver, N->getLocationContext());
+ if (state->isNull(V).isConstrainedTrue())
+ return Receiver;
+ }
+ return 0;
}
-
PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N,
const ExplodedNode *PrevN,
BugReporterContext &BRC,
BugReport &BR) {
- const PostStmt *P = N->getLocationAs<PostStmt>();
+ Optional<PreStmt> P = N->getLocationAs<PreStmt>();
if (!P)
return 0;
- const ObjCMessageExpr *ME = P->getStmtAs<ObjCMessageExpr>();
- if (!ME)
- return 0;
- const Expr *Receiver = ME->getInstanceReceiver();
+
+ const Expr *Receiver = getNilReceiver(P->getStmt(), N);
if (!Receiver)
return 0;
- ProgramStateRef state = N->getState();
- const SVal &V = state->getSVal(Receiver, N->getLocationContext());
- const DefinedOrUnknownSVal *DV = dyn_cast<DefinedOrUnknownSVal>(&V);
- if (!DV)
- return 0;
- state = state->assume(*DV, true);
- if (state)
- return 0;
// 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::trackNullOrUndefValue(N, Receiver, BR);
+ bugreporter::trackNullOrUndefValue(N, Receiver, BR, /*IsArg*/ false,
+ /*EnableNullFPSuppression*/ false);
// Issue a message saying that the method was skipped.
PathDiagnosticLocation L(Receiver, BRC.getSourceManager(),
N->getLocationContext());
@@ -768,7 +1048,8 @@ PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N,
// Registers every VarDecl inside a Stmt with a last store visitor.
void FindLastStoreBRVisitor::registerStatementVarDecls(BugReport &BR,
- const Stmt *S) {
+ const Stmt *S,
+ bool EnableNullFPSuppression) {
const ExplodedNode *N = BR.getErrorNode();
std::deque<const Stmt *> WorkList;
WorkList.push_back(S);
@@ -788,9 +1069,10 @@ void FindLastStoreBRVisitor::registerStatementVarDecls(BugReport &BR,
// What did we load?
SVal V = state->getSVal(S, N->getLocationContext());
- if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)) {
+ if (V.getAs<loc::ConcreteInt>() || V.getAs<nonloc::ConcreteInt>()) {
// Register a new visitor with the BugReport.
- BR.addVisitor(new FindLastStoreBRVisitor(V, R));
+ BR.addVisitor(new FindLastStoreBRVisitor(V.castAs<KnownSVal>(), R,
+ EnableNullFPSuppression));
}
}
}
@@ -842,14 +1124,14 @@ PathDiagnosticPiece *ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N,
// If an assumption was made on a branch, it should be caught
// here by looking at the state transition.
- if (const BlockEdge *BE = dyn_cast<BlockEdge>(&progPoint)) {
+ if (Optional<BlockEdge> BE = progPoint.getAs<BlockEdge>()) {
const CFGBlock *srcBlk = BE->getSrc();
if (const Stmt *term = srcBlk->getTerminator())
return VisitTerminator(term, N, srcBlk, BE->getDst(), BR, BRC);
return 0;
}
- if (const PostStmt *PS = dyn_cast<PostStmt>(&progPoint)) {
+ if (Optional<PostStmt> PS = progPoint.getAs<PostStmt>()) {
// FIXME: Assuming that BugReporter is a GRBugReporter is a layering
// violation.
const std::pair<const ProgramPointTag *, const ProgramPointTag *> &tags =
@@ -929,11 +1211,11 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
}
}
-bool ConditionBRVisitor::patternMatch(const Expr *Ex, llvm::raw_ostream &Out,
+bool ConditionBRVisitor::patternMatch(const Expr *Ex, raw_ostream &Out,
BugReporterContext &BRC,
BugReport &report,
const ExplodedNode *N,
- llvm::Optional<bool> &prunable) {
+ Optional<bool> &prunable) {
const Expr *OriginalExpr = Ex;
Ex = Ex->IgnoreParenCasts();
@@ -992,7 +1274,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
const ExplodedNode *N) {
bool shouldInvert = false;
- llvm::Optional<bool> shouldPrune;
+ Optional<bool> shouldPrune;
SmallString<128> LhsString, RhsString;
{
@@ -1161,6 +1443,58 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
return event;
}
+
+// FIXME: Copied from ExprEngineCallAndReturn.cpp.
+static bool isInStdNamespace(const Decl *D) {
+ const DeclContext *DC = D->getDeclContext()->getEnclosingNamespaceContext();
+ const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC);
+ if (!ND)
+ return false;
+
+ while (const NamespaceDecl *Parent = dyn_cast<NamespaceDecl>(ND->getParent()))
+ ND = Parent;
+
+ return ND->getName() == "std";
+}
+
+
+PathDiagnosticPiece *
+LikelyFalsePositiveSuppressionBRVisitor::getEndPath(BugReporterContext &BRC,
+ const ExplodedNode *N,
+ BugReport &BR) {
+ // Here we suppress false positives coming from system headers. This list is
+ // based on known issues.
+
+ // Skip reports within the 'std' namespace. Although these can sometimes be
+ // the user's fault, we currently don't report them very well, and
+ // Note that this will not help for any other data structure libraries, like
+ // TR1, Boost, or llvm/ADT.
+ ExprEngine &Eng = BRC.getBugReporter().getEngine();
+ AnalyzerOptions &Options = Eng.getAnalysisManager().options;
+ if (Options.shouldSuppressFromCXXStandardLibrary()) {
+ const LocationContext *LCtx = N->getLocationContext();
+ if (isInStdNamespace(LCtx->getDecl())) {
+ BR.markInvalid(getTag(), 0);
+ return 0;
+ }
+ }
+
+ // Skip reports within the sys/queue.h macros as we do not have the ability to
+ // reason about data structure shapes.
+ SourceManager &SM = BRC.getSourceManager();
+ FullSourceLoc Loc = BR.getLocation(SM).asLocation();
+ while (Loc.isMacroID()) {
+ if (SM.isInSystemMacro(Loc) &&
+ (SM.getFilename(SM.getSpellingLoc(Loc)).endswith("sys/queue.h"))) {
+ BR.markInvalid(getTag(), 0);
+ return 0;
+ }
+ Loc = Loc.getSpellingLoc();
+ }
+
+ return 0;
+}
+
PathDiagnosticPiece *
UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N,
const ExplodedNode *PrevN,
@@ -1171,7 +1505,7 @@ UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N,
ProgramPoint ProgLoc = N->getLocation();
// We are only interested in visiting CallEnter nodes.
- CallEnter *CEnter = dyn_cast<CallEnter>(&ProgLoc);
+ Optional<CallEnter> CEnter = ProgLoc.getAs<CallEnter>();
if (!CEnter)
return 0;
diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp
index c5cb317..45b2e21 100644
--- a/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -14,11 +14,12 @@
//===----------------------------------------------------------------------===//
#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 "clang/Analysis/ProgramPoint.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -124,7 +125,7 @@ static bool isPointerToConst(QualType Ty) {
// Try to retrieve the function declaration and find the function parameter
// types which are pointers/references to a non-pointer const.
// We will not invalidate the corresponding argument regions.
-static void findPtrToConstParams(llvm::SmallSet<unsigned, 1> &PreserveArgs,
+static void findPtrToConstParams(llvm::SmallSet<unsigned, 4> &PreserveArgs,
const CallEvent &Call) {
unsigned Idx = 0;
for (CallEvent::param_type_iterator I = Call.param_type_begin(),
@@ -136,69 +137,35 @@ static void findPtrToConstParams(llvm::SmallSet<unsigned, 1> &PreserveArgs,
}
ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
- ProgramStateRef Orig) const {
+ ProgramStateRef Orig) const {
ProgramStateRef Result = (Orig ? Orig : getState());
- SmallVector<const MemRegion *, 8> RegionsToInvalidate;
- getExtraInvalidatedRegions(RegionsToInvalidate);
+ SmallVector<SVal, 8> ConstValues;
+ SmallVector<SVal, 8> ValuesToInvalidate;
+
+ getExtraInvalidatedValues(ValuesToInvalidate);
// Indexes of arguments whose values will be preserved by the call.
- llvm::SmallSet<unsigned, 1> PreserveArgs;
+ llvm::SmallSet<unsigned, 4> PreserveArgs;
if (!argumentsMayEscape())
findPtrToConstParams(PreserveArgs, *this);
for (unsigned Idx = 0, Count = getNumArgs(); Idx != Count; ++Idx) {
+ // Mark this region for invalidation. We batch invalidate regions
+ // below for efficiency.
if (PreserveArgs.count(Idx))
- continue;
-
- SVal V = getArgSVal(Idx);
-
- // If we are passing a location wrapped as an integer, unwrap it and
- // invalidate the values referred by the location.
- if (nonloc::LocAsInteger *Wrapped = dyn_cast<nonloc::LocAsInteger>(&V))
- V = Wrapped->getLoc();
- else if (!isa<Loc>(V))
- continue;
-
- if (const MemRegion *R = V.getAsRegion()) {
- // Invalidate the value of the variable passed by reference.
-
- // Are we dealing with an ElementRegion? If the element type is
- // a basic integer type (e.g., char, int) and the underlying region
- // is a variable region then strip off the ElementRegion.
- // FIXME: We really need to think about this for the general case
- // as sometimes we are reasoning about arrays and other times
- // about (char*), etc., is just a form of passing raw bytes.
- // e.g., void *p = alloca(); foo((char*)p);
- if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
- // Checking for 'integral type' is probably too promiscuous, but
- // we'll leave it in for now until we have a systematic way of
- // handling all of these cases. Eventually we need to come up
- // with an interface to StoreManager so that this logic can be
- // appropriately delegated to the respective StoreManagers while
- // still allowing us to do checker-specific logic (e.g.,
- // invalidating reference counts), probably via callbacks.
- if (ER->getElementType()->isIntegralOrEnumerationType()) {
- const MemRegion *superReg = ER->getSuperRegion();
- if (isa<VarRegion>(superReg) || isa<FieldRegion>(superReg) ||
- isa<ObjCIvarRegion>(superReg))
- R = cast<TypedRegion>(superReg);
- }
- // FIXME: What about layers of ElementRegions?
- }
-
- // Mark this region for invalidation. We batch invalidate regions
- // below for efficiency.
- RegionsToInvalidate.push_back(R);
- }
+ ConstValues.push_back(getArgSVal(Idx));
+ else
+ ValuesToInvalidate.push_back(getArgSVal(Idx));
}
// Invalidate designated regions using the batch invalidation API.
// NOTE: Even if RegionsToInvalidate is empty, we may still invalidate
// global variables.
- return Result->invalidateRegions(RegionsToInvalidate, getOriginExpr(),
+ return Result->invalidateRegions(ValuesToInvalidate, getOriginExpr(),
BlockCount, getLocationContext(),
- /*Symbols=*/0, this);
+ /*CausedByPointerEscape*/ true,
+ /*Symbols=*/0, this, ConstValues);
}
ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit,
@@ -268,7 +235,6 @@ bool CallEvent::isCallStmt(const Stmt *S) {
|| isa<CXXNewExpr>(S);
}
-/// \brief Returns the result type, adjusted for references.
QualType CallEvent::getDeclaredResultType(const Decl *D) {
assert(D);
if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(D))
@@ -405,9 +371,8 @@ const FunctionDecl *CXXInstanceCall::getDecl() const {
return getSVal(CE->getCallee()).getAsFunctionDecl();
}
-void CXXInstanceCall::getExtraInvalidatedRegions(RegionList &Regions) const {
- if (const MemRegion *R = getCXXThisVal().getAsRegion())
- Regions.push_back(R);
+void CXXInstanceCall::getExtraInvalidatedValues(ValueList &Values) const {
+ Values.push_back(getCXXThisVal());
}
SVal CXXInstanceCall::getCXXThisVal() const {
@@ -417,7 +382,7 @@ SVal CXXInstanceCall::getCXXThisVal() const {
return UnknownVal();
SVal ThisVal = getSVal(Base);
- assert(ThisVal.isUnknownOrUndef() || isa<Loc>(ThisVal));
+ assert(ThisVal.isUnknownOrUndef() || ThisVal.getAs<Loc>());
return ThisVal;
}
@@ -560,10 +525,10 @@ CallEvent::param_iterator BlockCall::param_end() const {
return D->param_end();
}
-void BlockCall::getExtraInvalidatedRegions(RegionList &Regions) const {
+void BlockCall::getExtraInvalidatedValues(ValueList &Values) const {
// FIXME: This also needs to invalidate captured globals.
if (const MemRegion *R = getBlockRegion())
- Regions.push_back(R);
+ Values.push_back(loc::MemRegionVal(R));
}
void BlockCall::getInitialStackFrameContents(const StackFrameContext *CalleeCtx,
@@ -581,9 +546,9 @@ SVal CXXConstructorCall::getCXXThisVal() const {
return UnknownVal();
}
-void CXXConstructorCall::getExtraInvalidatedRegions(RegionList &Regions) const {
+void CXXConstructorCall::getExtraInvalidatedValues(ValueList &Values) const {
if (Data)
- Regions.push_back(static_cast<const MemRegion *>(Data));
+ Values.push_back(loc::MemRegionVal(static_cast<const MemRegion *>(Data)));
}
void CXXConstructorCall::getInitialStackFrameContents(
@@ -635,9 +600,8 @@ CallEvent::param_iterator ObjCMethodCall::param_end() const {
}
void
-ObjCMethodCall::getExtraInvalidatedRegions(RegionList &Regions) const {
- if (const MemRegion *R = getReceiverSVal().getAsRegion())
- Regions.push_back(R);
+ObjCMethodCall::getExtraInvalidatedValues(ValueList &Values) const {
+ Values.push_back(getReceiverSVal());
}
SVal ObjCMethodCall::getSelfSVal() const {
@@ -834,7 +798,34 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const {
// Lookup the method implementation.
if (ReceiverT)
if (ObjCInterfaceDecl *IDecl = ReceiverT->getInterfaceDecl()) {
- const ObjCMethodDecl *MD = IDecl->lookupPrivateMethod(Sel);
+ // Repeatedly calling lookupPrivateMethod() is expensive, especially
+ // when in many cases it returns null. We cache the results so
+ // that repeated queries on the same ObjCIntefaceDecl and Selector
+ // don't incur the same cost. On some test cases, we can see the
+ // same query being issued thousands of times.
+ //
+ // NOTE: This cache is essentially a "global" variable, but it
+ // only gets lazily created when we get here. The value of the
+ // cache probably comes from it being global across ExprEngines,
+ // where the same queries may get issued. If we are worried about
+ // concurrency, or possibly loading/unloading ASTs, etc., we may
+ // need to revisit this someday. In terms of memory, this table
+ // stays around until clang quits, which also may be bad if we
+ // need to release memory.
+ typedef std::pair<const ObjCInterfaceDecl*, Selector>
+ PrivateMethodKey;
+ typedef llvm::DenseMap<PrivateMethodKey,
+ Optional<const ObjCMethodDecl *> >
+ PrivateMethodCache;
+
+ static PrivateMethodCache PMC;
+ Optional<const ObjCMethodDecl *> &Val = PMC[std::make_pair(IDecl, Sel)];
+
+ // Query lookupPrivateMethod() if the cache does not hit.
+ if (!Val.hasValue())
+ Val = IDecl->lookupPrivateMethod(Sel);
+
+ const ObjCMethodDecl *MD = Val.getValue();
if (CanBeSubClassed)
return RuntimeDefinition(MD, Receiver);
else
@@ -931,8 +922,9 @@ CallEventManager::getCaller(const StackFrameContext *CalleeCtx,
// destructors, though this could change in the future.
const CFGBlock *B = CalleeCtx->getCallSiteBlock();
CFGElement E = (*B)[CalleeCtx->getIndex()];
- assert(isa<CFGImplicitDtor>(E) && "All other CFG elements should have exprs");
- assert(!isa<CFGTemporaryDtor>(E) && "We don't handle temporaries yet");
+ assert(E.getAs<CFGImplicitDtor>() &&
+ "All other CFG elements should have exprs");
+ assert(!E.getAs<CFGTemporaryDtor>() && "We don't handle temporaries yet");
SValBuilder &SVB = State->getStateManager().getSValBuilder();
const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CalleeCtx->getDecl());
@@ -940,11 +932,12 @@ CallEventManager::getCaller(const StackFrameContext *CalleeCtx,
SVal ThisVal = State->getSVal(ThisPtr);
const Stmt *Trigger;
- if (const CFGAutomaticObjDtor *AutoDtor = dyn_cast<CFGAutomaticObjDtor>(&E))
+ if (Optional<CFGAutomaticObjDtor> AutoDtor = E.getAs<CFGAutomaticObjDtor>())
Trigger = AutoDtor->getTriggerStmt();
else
Trigger = Dtor->getBody();
return getCXXDestructorCall(Dtor, Trigger, ThisVal.getAsRegion(),
- isa<CFGBaseDtor>(E), State, CallerCtx);
+ E.getAs<CFGBaseDtor>().hasValue(), State,
+ CallerCtx);
}
diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp
index 3672952..8adf326 100644
--- a/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -12,11 +12,11 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/Analysis/ProgramPoint.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
-#include "clang/Analysis/ProgramPoint.h"
-#include "clang/AST/DeclBase.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
using namespace clang;
using namespace ento;
@@ -30,7 +30,7 @@ bool CheckerManager::hasPathSensitiveCheckers() const {
!LocationCheckers.empty() ||
!BindCheckers.empty() ||
!EndAnalysisCheckers.empty() ||
- !EndPathCheckers.empty() ||
+ !EndFunctionCheckers.empty() ||
!BranchConditionCheckers.empty() ||
!LiveSymbolsCheckers.empty() ||
!DeadSymbolsCheckers.empty() ||
@@ -353,17 +353,17 @@ void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G,
/// \brief Run checkers for end of path.
// Note, We do not chain the checker output (like in expandGraphWithCheckers)
// for this callback since end of path nodes are expected to be final.
-void CheckerManager::runCheckersForEndPath(NodeBuilderContext &BC,
- ExplodedNodeSet &Dst,
- ExplodedNode *Pred,
- ExprEngine &Eng) {
+void CheckerManager::runCheckersForEndFunction(NodeBuilderContext &BC,
+ ExplodedNodeSet &Dst,
+ ExplodedNode *Pred,
+ ExprEngine &Eng) {
// 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
// autotransition for it.
NodeBuilder Bldr(Pred, Dst, BC);
- for (unsigned i = 0, e = EndPathCheckers.size(); i != e; ++i) {
- CheckEndPathFunc checkFn = EndPathCheckers[i];
+ for (unsigned i = 0, e = EndFunctionCheckers.size(); i != e; ++i) {
+ CheckEndFunctionFunc checkFn = EndFunctionCheckers[i];
const ProgramPoint &L = BlockEntrance(BC.Block,
Pred->getLocationContext(),
@@ -469,10 +469,10 @@ bool CheckerManager::wantsRegionChangeUpdate(ProgramStateRef state) {
/// \brief Run checkers for region changes.
ProgramStateRef
CheckerManager::runCheckersForRegionChanges(ProgramStateRef state,
- const StoreManager::InvalidatedSymbols *invalidated,
+ const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions,
- ArrayRef<const MemRegion *> Regions,
- const CallEvent *Call) {
+ ArrayRef<const MemRegion *> Regions,
+ const CallEvent *Call) {
for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i) {
// If any checker declares the state infeasible (or if it starts that way),
// bail out.
@@ -484,6 +484,27 @@ CheckerManager::runCheckersForRegionChanges(ProgramStateRef state,
return state;
}
+/// \brief Run checkers to process symbol escape event.
+ProgramStateRef
+CheckerManager::runCheckersForPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind,
+ bool IsConst) {
+ assert((Call != NULL ||
+ (Kind != PSK_DirectEscapeOnCall &&
+ Kind != PSK_IndirectEscapeOnCall)) &&
+ "Call must not be NULL when escaping on call");
+ for (unsigned i = 0, e = PointerEscapeCheckers.size(); i != e; ++i) {
+ // If any checker declares the state infeasible (or if it starts that
+ // way), bail out.
+ if (!State)
+ return NULL;
+ State = PointerEscapeCheckers[i](State, Escaped, Call, Kind, IsConst);
+ }
+ return State;
+}
+
/// \brief Run checkers for handling assumptions on symbolic values.
ProgramStateRef
CheckerManager::runCheckersForEvalAssume(ProgramStateRef state,
@@ -618,8 +639,8 @@ void CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn) {
EndAnalysisCheckers.push_back(checkfn);
}
-void CheckerManager::_registerForEndPath(CheckEndPathFunc checkfn) {
- EndPathCheckers.push_back(checkfn);
+void CheckerManager::_registerForEndFunction(CheckEndFunctionFunc checkfn) {
+ EndFunctionCheckers.push_back(checkfn);
}
void CheckerManager::_registerForBranchCondition(
@@ -641,6 +662,15 @@ void CheckerManager::_registerForRegionChanges(CheckRegionChangesFunc checkfn,
RegionChangesCheckers.push_back(info);
}
+void CheckerManager::_registerForPointerEscape(CheckPointerEscapeFunc checkfn){
+ PointerEscapeCheckers.push_back(checkfn);
+}
+
+void CheckerManager::_registerForConstPointerEscape(
+ CheckPointerEscapeFunc checkfn) {
+ PointerEscapeCheckers.push_back(checkfn);
+}
+
void CheckerManager::_registerForEvalAssume(EvalAssumeFunc checkfn) {
EvalAssumeCheckers.push_back(checkfn);
}
diff --git a/lib/StaticAnalyzer/Core/CheckerRegistry.cpp b/lib/StaticAnalyzer/Core/CheckerRegistry.cpp
index 9791e2ec..4729903 100644
--- a/lib/StaticAnalyzer/Core/CheckerRegistry.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerRegistry.cpp
@@ -10,6 +10,7 @@
#include "clang/StaticAnalyzer/Core/CheckerRegistry.h"
#include "clang/StaticAnalyzer/Core/CheckerOptInfo.h"
#include "llvm/ADT/SetVector.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -109,7 +110,7 @@ void CheckerRegistry::initializeManager(CheckerManager &checkerMgr,
}
}
-void CheckerRegistry::printHelp(llvm::raw_ostream &out,
+void CheckerRegistry::printHelp(raw_ostream &out,
size_t maxNameChars) const {
// FIXME: Alphabetical sort puts 'experimental' in the middle.
// Would it be better to name it '~experimental' or something else
diff --git a/lib/StaticAnalyzer/Core/CoreEngine.cpp b/lib/StaticAnalyzer/Core/CoreEngine.cpp
index ec23792..b09b2c2 100644
--- a/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ b/lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -14,14 +14,14 @@
#define DEBUG_TYPE "CoreEngine"
-#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/AST/Expr.h"
#include "clang/AST/StmtCXX.h"
-#include "llvm/Support/Casting.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Statistic.h"
+#include "llvm/Support/Casting.h"
using namespace clang;
using namespace ento;
@@ -114,7 +114,7 @@ namespace {
}
virtual void enqueue(const WorkListUnit& U) {
- if (isa<BlockEntrance>(U.getNode()->getLocation()))
+ if (U.getNode()->getLocation().getAs<BlockEntrance>())
Queue.push_front(U);
else
Stack.push_back(U);
@@ -230,11 +230,11 @@ void CoreEngine::dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc,
// Dispatch on the location type.
switch (Loc.getKind()) {
case ProgramPoint::BlockEdgeKind:
- HandleBlockEdge(cast<BlockEdge>(Loc), Pred);
+ HandleBlockEdge(Loc.castAs<BlockEdge>(), Pred);
break;
case ProgramPoint::BlockEntranceKind:
- HandleBlockEntrance(cast<BlockEntrance>(Loc), Pred);
+ HandleBlockEntrance(Loc.castAs<BlockEntrance>(), Pred);
break;
case ProgramPoint::BlockExitKind:
@@ -242,7 +242,7 @@ void CoreEngine::dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc,
break;
case ProgramPoint::CallEnterKind: {
- CallEnter CEnter = cast<CallEnter>(Loc);
+ CallEnter CEnter = Loc.castAs<CallEnter>();
SubEng.processCallEnter(CEnter, Pred);
break;
}
@@ -259,10 +259,10 @@ void CoreEngine::dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc,
break;
}
default:
- assert(isa<PostStmt>(Loc) ||
- isa<PostInitializer>(Loc) ||
- isa<PostImplicitCall>(Loc) ||
- isa<CallExitEnd>(Loc));
+ assert(Loc.getAs<PostStmt>() ||
+ Loc.getAs<PostInitializer>() ||
+ Loc.getAs<PostImplicitCall>() ||
+ Loc.getAs<CallExitEnd>());
HandlePostStmt(WU.getBlock(), WU.getIndex(), Pred);
break;
}
@@ -331,9 +331,9 @@ void CoreEngine::HandleBlockEntrance(const BlockEntrance &L,
WList->setBlockCounter(Counter);
// Process the entrance of the block.
- if (CFGElement E = L.getFirstElement()) {
+ if (Optional<CFGElement> E = L.getFirstElement()) {
NodeBuilderContext Ctx(*this, L.getBlock(), Pred);
- SubEng.processCFGElement(E, Pred, 0, &Ctx);
+ SubEng.processCFGElement(*E, Pred, 0, &Ctx);
}
else
HandleBlockExit(L.getBlock(), Pred);
@@ -346,6 +346,11 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) {
default:
llvm_unreachable("Analysis for this terminator not implemented.");
+ // Model static initializers.
+ case Stmt::DeclStmtClass:
+ HandleStaticInit(cast<DeclStmt>(Term), B, Pred);
+ return;
+
case Stmt::BinaryOperatorClass: // '&&' and '||'
HandleBranch(cast<BinaryOperator>(Term)->getLHS(), Term, B, Pred);
return;
@@ -456,6 +461,19 @@ void CoreEngine::HandleBranch(const Stmt *Cond, const Stmt *Term,
enqueue(Dst);
}
+
+void CoreEngine::HandleStaticInit(const DeclStmt *DS, const CFGBlock *B,
+ ExplodedNode *Pred) {
+ assert(B->succ_size() == 2);
+ NodeBuilderContext Ctx(*this, B, Pred);
+ ExplodedNodeSet Dst;
+ SubEng.processStaticInitializer(DS, Ctx, Pred, Dst,
+ *(B->succ_begin()), *(B->succ_begin()+1));
+ // Enqueue the new frontier onto the worklist.
+ enqueue(Dst);
+}
+
+
void CoreEngine::HandlePostStmt(const CFGBlock *B, unsigned StmtIdx,
ExplodedNode *Pred) {
assert(B);
@@ -495,7 +513,7 @@ void CoreEngine::enqueueStmtNode(ExplodedNode *N,
assert (!N->isSink());
// Check if this node entered a callee.
- if (isa<CallEnter>(N->getLocation())) {
+ if (N->getLocation().getAs<CallEnter>()) {
// Still use the index of the CallExpr. It's needed to create the callee
// StackFrameContext.
WList->enqueue(N, Block, Idx);
@@ -503,19 +521,19 @@ void CoreEngine::enqueueStmtNode(ExplodedNode *N,
}
// Do not create extra nodes. Move to the next CFG element.
- if (isa<PostInitializer>(N->getLocation()) ||
- isa<PostImplicitCall>(N->getLocation())) {
+ if (N->getLocation().getAs<PostInitializer>() ||
+ N->getLocation().getAs<PostImplicitCall>()) {
WList->enqueue(N, Block, Idx+1);
return;
}
- if (isa<EpsilonPoint>(N->getLocation())) {
+ if (N->getLocation().getAs<EpsilonPoint>()) {
WList->enqueue(N, Block, Idx);
return;
}
// At this point, we know we're processing a normal statement.
- CFGStmt CS = cast<CFGStmt>((*Block)[Idx]);
+ CFGStmt CS = (*Block)[Idx].castAs<CFGStmt>();
PostStmt Loc(CS.getStmt(), N->getLocationContext());
if (Loc == N->getLocation()) {
diff --git a/lib/StaticAnalyzer/Core/Environment.cpp b/lib/StaticAnalyzer/Core/Environment.cpp
index bab89c5..fe352aa 100644
--- a/lib/StaticAnalyzer/Core/Environment.cpp
+++ b/lib/StaticAnalyzer/Core/Environment.cpp
@@ -16,6 +16,7 @@
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -36,9 +37,6 @@ static const Expr *ignoreTransparentExprs(const Expr *E) {
case Stmt::SubstNonTypeTemplateParmExprClass:
E = cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement();
break;
- case Stmt::CXXDefaultArgExprClass:
- E = cast<CXXDefaultArgExpr>(E)->getExpr();
- break;
default:
// This is the base case: we can't look through more than we already have.
return E;
@@ -74,7 +72,6 @@ SVal Environment::getSVal(const EnvironmentEntry &Entry,
switch (S->getStmtClass()) {
case Stmt::CXXBindTemporaryExprClass:
- case Stmt::CXXDefaultArgExprClass:
case Stmt::ExprWithCleanupsClass:
case Stmt::GenericSelectionExprClass:
case Stmt::OpaqueValueExprClass:
@@ -149,19 +146,6 @@ Environment EnvironmentManager::bindExpr(Environment Env,
return Environment(F.add(Env.ExprBindings, E, V));
}
-EnvironmentEntry EnvironmentEntry::makeLocation() const {
- EnvironmentEntry Result = *this;
- reinterpret_cast<uintptr_t &>(Result.first) |= 0x1;
- return Result;
-}
-
-Environment EnvironmentManager::bindExprAndLocation(Environment Env,
- const EnvironmentEntry &E,
- SVal location, SVal V) {
- return Environment(F.add(F.add(Env.ExprBindings, E.makeLocation(), location),
- E, V));
-}
-
namespace {
class MarkLiveCallback : public SymbolVisitor {
SymbolReaper &SymReaper;
@@ -178,14 +162,6 @@ public:
};
} // end anonymous namespace
-// In addition to mapping from EnvironmentEntry - > SVals in the Environment,
-// we also maintain a mapping from EnvironmentEntry -> SVals (locations)
-// that were used during a load and store.
-static inline bool IsLocation(const EnvironmentEntry &E) {
- const Stmt *S = E.getStmt();
- return (bool) (((uintptr_t) S) & 0x1);
-}
-
// removeDeadBindings:
// - Remove subexpression bindings.
// - Remove dead block expression bindings.
@@ -202,8 +178,6 @@ EnvironmentManager::removeDeadBindings(Environment Env,
// individually removing all the subexpression bindings (which will greatly
// outnumber block-level expression bindings).
Environment NewEnv = getInitialEnvironment();
-
- SmallVector<std::pair<EnvironmentEntry, SVal>, 10> deferredLocations;
MarkLiveCallback CB(SymReaper);
ScanReachableSymbols RSScaner(ST, CB);
@@ -217,15 +191,6 @@ EnvironmentManager::removeDeadBindings(Environment Env,
I != E; ++I) {
const EnvironmentEntry &BlkExpr = I.getKey();
- // For recorded locations (used when evaluating loads and stores), we
- // consider them live only when their associated normal expression is
- // also live.
- // NOTE: This assumes that loads/stores that evaluated to UnknownVal
- // still have an entry in the map.
- if (IsLocation(BlkExpr)) {
- deferredLocations.push_back(std::make_pair(BlkExpr, I.getData()));
- continue;
- }
const SVal &X = I.getData();
if (SymReaper.isLive(BlkExpr.getStmt(), BlkExpr.getLocationContext())) {
@@ -233,26 +198,18 @@ EnvironmentManager::removeDeadBindings(Environment Env,
EBMapRef = EBMapRef.add(BlkExpr, X);
// If the block expr's value is a memory region, then mark that region.
- if (isa<loc::MemRegionVal>(X)) {
- const MemRegion *R = cast<loc::MemRegionVal>(X).getRegion();
- SymReaper.markLive(R);
- }
+ if (Optional<loc::MemRegionVal> R = X.getAs<loc::MemRegionVal>())
+ SymReaper.markLive(R->getRegion());
// Mark all symbols in the block expr's value live.
RSScaner.scan(X);
continue;
+ } else {
+ SymExpr::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end();
+ for (; SI != SE; ++SI)
+ SymReaper.maybeDead(*SI);
}
}
-
- // Go through he deferred locations and add them to the new environment if
- // the correspond Stmt* is in the map as well.
- for (SmallVectorImpl<std::pair<EnvironmentEntry, SVal> >::iterator
- I = deferredLocations.begin(), E = deferredLocations.end(); I != E; ++I) {
- const EnvironmentEntry &En = I->first;
- const Stmt *S = (Stmt*) (((uintptr_t) En.getStmt()) & (uintptr_t) ~0x1);
- if (EBMapRef.lookup(EnvironmentEntry(S, En.getLocationContext())))
- EBMapRef = EBMapRef.add(En, I->second);
- }
NewEnv.ExprBindings = EBMapRef.asImmutableMap();
return NewEnv;
@@ -260,30 +217,14 @@ EnvironmentManager::removeDeadBindings(Environment Env,
void Environment::print(raw_ostream &Out, const char *NL,
const char *Sep) const {
- printAux(Out, false, NL, Sep);
- printAux(Out, true, NL, Sep);
-}
-
-void Environment::printAux(raw_ostream &Out, bool printLocations,
- const char *NL,
- const char *Sep) const{
-
bool isFirst = true;
for (Environment::iterator I = begin(), E = end(); I != E; ++I) {
const EnvironmentEntry &En = I.getKey();
- if (IsLocation(En)) {
- if (!printLocations)
- continue;
- }
- else {
- if (printLocations)
- continue;
- }
if (isFirst) {
Out << NL << NL
- << (printLocations ? "Load/Store locations:" : "Expressions:")
+ << "Expressions:"
<< NL;
isFirst = false;
} else {
@@ -291,9 +232,6 @@ void Environment::printAux(raw_ostream &Out, bool printLocations,
}
const Stmt *S = En.getStmt();
- if (printLocations) {
- S = (Stmt*) (((uintptr_t) S) & ((uintptr_t) ~0x1));
- }
Out << " (" << (const void*) En.getLocationContext() << ','
<< (const void*) S << ") ";
diff --git a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
index c284bd7..af9518a 100644
--- a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
+++ b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
@@ -13,12 +13,12 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/AST/Stmt.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
-#include "clang/AST/Stmt.h"
-#include "clang/AST/ParentMap.h"
-#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include <vector>
@@ -56,19 +56,42 @@ ExplodedGraph::~ExplodedGraph() {}
// Node reclamation.
//===----------------------------------------------------------------------===//
+bool ExplodedGraph::isInterestingLValueExpr(const Expr *Ex) {
+ if (!Ex->isLValue())
+ return false;
+ return isa<DeclRefExpr>(Ex) ||
+ isa<MemberExpr>(Ex) ||
+ isa<ObjCIvarRefExpr>(Ex);
+}
+
bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
- // Reclaim all nodes that match *all* the following criteria:
+ // First, we only consider nodes for reclamation of the following
+ // conditions apply:
//
// (1) 1 predecessor (that has one successor)
// (2) 1 successor (that has one predecessor)
+ //
+ // If a node has no successor it is on the "frontier", while a node
+ // with no predecessor is a root.
+ //
+ // After these prerequisites, we discard all "filler" nodes that
+ // are used only for intermediate processing, and are not essential
+ // for analyzer history:
+ //
+ // (a) PreStmtPurgeDeadSymbols
+ //
+ // We then discard all other nodes where *all* of the following conditions
+ // apply:
+ //
// (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 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).
+ // (8) Expressions that are *not* lvalue expressions.
+ // (9) The PostStmt isn't for a non-consumed Stmt or Expr.
+ // (10) 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.
// Conditions 1 and 2.
@@ -83,14 +106,18 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
if (succ->pred_size() != 1)
return false;
- // Condition 3.
+ // Now reclaim any nodes that are (by definition) not essential to
+ // analysis history and are not consulted by any client code.
ProgramPoint progPoint = node->getLocation();
- if (!isa<PostStmt>(progPoint) || isa<PostStore>(progPoint))
+ if (progPoint.getAs<PreStmtPurgeDeadSymbols>())
+ return !progPoint.getTag();
+
+ // Condition 3.
+ if (!progPoint.getAs<PostStmt>() || progPoint.getAs<PostStore>())
return false;
// Condition 4.
- PostStmt ps = cast<PostStmt>(progPoint);
- if (ps.getTag())
+ if (progPoint.getTag())
return false;
// Conditions 5, 6, and 7.
@@ -99,23 +126,30 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
if (state->store != pred_state->store || state->GDM != pred_state->GDM ||
progPoint.getLocationContext() != pred->getLocationContext())
return false;
-
+
+ // All further checks require expressions. As per #3, we know that we have
+ // a PostStmt.
+ const Expr *Ex = dyn_cast<Expr>(progPoint.castAs<PostStmt>().getStmt());
+ if (!Ex)
+ return false;
+
// Condition 8.
+ // Do not collect nodes for "interesting" lvalue expressions since they are
+ // used extensively for generating path diagnostics.
+ if (isInterestingLValueExpr(Ex))
+ return false;
+
+ // Condition 9.
// Do not collect nodes for non-consumed Stmt or Expr to ensure precise
// diagnostic generation; specifically, so that we could anchor arrows
// pointing to the beginning of statements (as written in code).
- if (!isa<Expr>(ps.getStmt()))
+ ParentMap &PM = progPoint.getLocationContext()->getParentMap();
+ if (!PM.isConsumedExpr(Ex))
return false;
-
- if (const Expr *Ex = dyn_cast<Expr>(ps.getStmt())) {
- ParentMap &PM = progPoint.getLocationContext()->getParentMap();
- if (!PM.isConsumedExpr(Ex))
- return false;
- }
-
- // Condition 9.
+
+ // Condition 10.
const ProgramPoint SuccLoc = succ->getLocation();
- if (const StmtPoint *SP = dyn_cast<StmtPoint>(&SuccLoc))
+ if (Optional<StmtPoint> SP = SuccLoc.getAs<StmtPoint>())
if (CallEvent::isCallStmt(SP->getStmt()))
return false;
@@ -297,45 +331,31 @@ ExplodedNode *ExplodedGraph::getNode(const ProgramPoint &L,
return V;
}
-std::pair<ExplodedGraph*, InterExplodedGraphMap*>
-ExplodedGraph::Trim(const NodeTy* const* NBeg, const NodeTy* const* NEnd,
- llvm::DenseMap<const void*, const void*> *InverseMap) const {
-
- if (NBeg == NEnd)
- return std::make_pair((ExplodedGraph*) 0,
- (InterExplodedGraphMap*) 0);
+ExplodedGraph *
+ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks,
+ InterExplodedGraphMap *ForwardMap,
+ InterExplodedGraphMap *InverseMap) const{
- assert (NBeg < NEnd);
-
- OwningPtr<InterExplodedGraphMap> M(new InterExplodedGraphMap());
-
- ExplodedGraph* G = TrimInternal(NBeg, NEnd, M.get(), InverseMap);
-
- return std::make_pair(static_cast<ExplodedGraph*>(G), M.take());
-}
-
-ExplodedGraph*
-ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources,
- const ExplodedNode* const* EndSources,
- InterExplodedGraphMap* M,
- llvm::DenseMap<const void*, const void*> *InverseMap) const {
+ if (Nodes.empty())
+ return 0;
typedef llvm::DenseSet<const ExplodedNode*> Pass1Ty;
Pass1Ty Pass1;
- typedef llvm::DenseMap<const ExplodedNode*, ExplodedNode*> Pass2Ty;
- Pass2Ty& Pass2 = M->M;
+ typedef InterExplodedGraphMap Pass2Ty;
+ InterExplodedGraphMap Pass2Scratch;
+ Pass2Ty &Pass2 = ForwardMap ? *ForwardMap : Pass2Scratch;
SmallVector<const ExplodedNode*, 10> WL1, WL2;
// ===- Pass 1 (reverse DFS) -===
- for (const ExplodedNode* const* I = BeginSources; I != EndSources; ++I) {
+ for (ArrayRef<const NodeTy *>::iterator I = Sinks.begin(), E = Sinks.end();
+ I != E; ++I) {
if (*I)
WL1.push_back(*I);
}
- // Process the first worklist until it is empty. Because it is a std::list
- // it acts like a FIFO queue.
+ // Process the first worklist until it is empty.
while (!WL1.empty()) {
const ExplodedNode *N = WL1.back();
WL1.pop_back();
@@ -398,7 +418,7 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources,
if (PI == Pass2.end())
continue;
- NewN->addPredecessor(PI->second, *G);
+ NewN->addPredecessor(const_cast<ExplodedNode *>(PI->second), *G);
}
// In the case that some of the intended successors of NewN have already
@@ -409,7 +429,7 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources,
I != E; ++I) {
Pass2Ty::iterator PI = Pass2.find(*I);
if (PI != Pass2.end()) {
- PI->second->addPredecessor(NewN, *G);
+ const_cast<ExplodedNode *>(PI->second)->addPredecessor(NewN, *G);
continue;
}
@@ -422,13 +442,3 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources,
return G;
}
-void InterExplodedGraphMap::anchor() { }
-
-ExplodedNode*
-InterExplodedGraphMap::getMappedNode(const ExplodedNode *N) const {
- llvm::DenseMap<const ExplodedNode*, ExplodedNode*>::const_iterator I =
- M.find(N);
-
- return I == M.end() ? 0 : I->second;
-}
-
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 045591c..ab4dbd7 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -15,21 +15,21 @@
#define DEBUG_TYPE "ExprEngine"
-#include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/ParentMap.h"
-#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtObjC.h"
#include "clang/Basic/Builtins.h"
-#include "clang/Basic/SourceManager.h"
#include "clang/Basic/PrettyStackTrace.h"
-#include "llvm/Support/raw_ostream.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "llvm/ADT/ImmutableList.h"
#include "llvm/ADT/Statistic.h"
+#include "llvm/Support/raw_ostream.h"
#ifndef NDEBUG
#include "llvm/Support/GraphWriter.h"
@@ -56,7 +56,8 @@ STATISTIC(NumTimesRetriedWithoutInlining,
ExprEngine::ExprEngine(AnalysisManager &mgr, bool gcEnabled,
SetOfConstDecls *VisitedCalleesIn,
- FunctionSummariesTy *FS)
+ FunctionSummariesTy *FS,
+ InliningModes HowToInlineIn)
: AMgr(mgr),
AnalysisDeclContexts(mgr.getAnalysisDeclContextManager()),
Engine(*this, FS),
@@ -66,11 +67,11 @@ ExprEngine::ExprEngine(AnalysisManager &mgr, bool gcEnabled,
this),
SymMgr(StateMgr.getSymbolManager()),
svalBuilder(StateMgr.getSValBuilder()),
- EntryNode(NULL),
- currStmt(NULL), currStmtIdx(0), currBldrCtx(0),
+ currStmtIdx(0), currBldrCtx(0),
ObjCNoRet(mgr.getASTContext()),
ObjCGCEnabled(gcEnabled), BR(mgr, *this),
- VisitedCallees(VisitedCalleesIn)
+ VisitedCallees(VisitedCalleesIn),
+ HowToInline(HowToInlineIn)
{
unsigned TrimInterval = mgr.options.getGraphTrimInterval();
if (TrimInterval != 0) {
@@ -117,8 +118,8 @@ ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) {
svalBuilder.makeZeroVal(T),
getContext().IntTy);
- DefinedOrUnknownSVal *Constraint =
- dyn_cast<DefinedOrUnknownSVal>(&Constraint_untested);
+ Optional<DefinedOrUnknownSVal> Constraint =
+ Constraint_untested.getAs<DefinedOrUnknownSVal>();
if (!Constraint)
break;
@@ -137,7 +138,7 @@ ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) {
const MemRegion *R = state->getRegion(SelfD, InitLoc);
SVal V = state->getSVal(loc::MemRegionVal(R));
- if (const Loc *LV = dyn_cast<Loc>(&V)) {
+ if (Optional<Loc> LV = V.getAs<Loc>()) {
// Assume that the pointer value in 'self' is non-null.
state = state->assume(*LV, true);
assert(state && "'self' cannot be null");
@@ -153,7 +154,7 @@ ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) {
if (SFC->getParent() == 0) {
loc::MemRegionVal L = svalBuilder.getCXXThis(MD, SFC);
SVal V = state->getSVal(L);
- if (const Loc *LV = dyn_cast<Loc>(&V)) {
+ if (Optional<Loc> LV = V.getAs<Loc>()) {
state = state->assume(*LV, true);
assert(state && "'this' cannot be null");
}
@@ -164,20 +165,63 @@ ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) {
return state;
}
-/// If the value of the given expression is a NonLoc, copy it into a new
-/// temporary region, and replace the value of the expression with that.
-static ProgramStateRef createTemporaryRegionIfNeeded(ProgramStateRef State,
- const LocationContext *LC,
- const Expr *E) {
- SVal V = State->getSVal(E, LC);
-
- if (isa<NonLoc>(V)) {
- MemRegionManager &MRMgr = State->getStateManager().getRegionManager();
- const MemRegion *R = MRMgr.getCXXTempObjectRegion(E, LC);
- State = State->bindLoc(loc::MemRegionVal(R), V);
- State = State->BindExpr(E, LC, loc::MemRegionVal(R));
+ProgramStateRef
+ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State,
+ const LocationContext *LC,
+ const Expr *Ex,
+ const Expr *Result) {
+ SVal V = State->getSVal(Ex, LC);
+ if (!Result) {
+ // If we don't have an explicit result expression, we're in "if needed"
+ // mode. Only create a region if the current value is a NonLoc.
+ if (!V.getAs<NonLoc>())
+ return State;
+ Result = Ex;
+ } else {
+ // We need to create a region no matter what. For sanity, make sure we don't
+ // try to stuff a Loc into a non-pointer temporary region.
+ assert(!V.getAs<Loc>() || Loc::isLocType(Result->getType()));
}
+ ProgramStateManager &StateMgr = State->getStateManager();
+ MemRegionManager &MRMgr = StateMgr.getRegionManager();
+ StoreManager &StoreMgr = StateMgr.getStoreManager();
+
+ // We need to be careful about treating a derived type's value as
+ // bindings for a base type. Unless we're creating a temporary pointer region,
+ // start by stripping and recording base casts.
+ SmallVector<const CastExpr *, 4> Casts;
+ const Expr *Inner = Ex->IgnoreParens();
+ if (!Loc::isLocType(Result->getType())) {
+ while (const CastExpr *CE = dyn_cast<CastExpr>(Inner)) {
+ if (CE->getCastKind() == CK_DerivedToBase ||
+ CE->getCastKind() == CK_UncheckedDerivedToBase)
+ Casts.push_back(CE);
+ else if (CE->getCastKind() != CK_NoOp)
+ break;
+
+ Inner = CE->getSubExpr()->IgnoreParens();
+ }
+ }
+
+ // Create a temporary object region for the inner expression (which may have
+ // a more derived type) and bind the value into it.
+ const TypedValueRegion *TR = MRMgr.getCXXTempObjectRegion(Inner, LC);
+ SVal Reg = loc::MemRegionVal(TR);
+
+ if (V.isUnknown())
+ V = getSValBuilder().conjureSymbolVal(Result, LC, TR->getValueType(),
+ currBldrCtx->blockCount());
+ State = State->bindLoc(Reg, V);
+
+ // Re-apply the casts (from innermost to outermost) for type sanity.
+ for (SmallVectorImpl<const CastExpr *>::reverse_iterator I = Casts.rbegin(),
+ E = Casts.rend();
+ I != E; ++I) {
+ Reg = StoreMgr.evalDerivedToBase(Reg, *I);
+ }
+
+ State = State->BindExpr(Result, LC, Reg);
return State;
}
@@ -198,7 +242,7 @@ bool ExprEngine::wantsRegionChangeUpdate(ProgramStateRef state) {
ProgramStateRef
ExprEngine::processRegionChanges(ProgramStateRef state,
- const StoreManager::InvalidatedSymbols *invalidated,
+ const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> Explicits,
ArrayRef<const MemRegion *> Regions,
const CallEvent *Call) {
@@ -221,19 +265,17 @@ void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred,
currBldrCtx = Ctx;
switch (E.getKind()) {
- case CFGElement::Invalid:
- llvm_unreachable("Unexpected CFGElement kind.");
case CFGElement::Statement:
- ProcessStmt(const_cast<Stmt*>(E.getAs<CFGStmt>()->getStmt()), Pred);
+ ProcessStmt(const_cast<Stmt*>(E.castAs<CFGStmt>().getStmt()), Pred);
return;
case CFGElement::Initializer:
- ProcessInitializer(E.getAs<CFGInitializer>()->getInitializer(), Pred);
+ ProcessInitializer(E.castAs<CFGInitializer>().getInitializer(), Pred);
return;
case CFGElement::AutomaticObjectDtor:
case CFGElement::BaseDtor:
case CFGElement::MemberDtor:
case CFGElement::TemporaryDtor:
- ProcessImplicitDtor(*E.getAs<CFGImplicitDtor>(), Pred);
+ ProcessImplicitDtor(E.castAs<CFGImplicitDtor>(), Pred);
return;
}
currBldrCtx = 0;
@@ -249,7 +291,7 @@ static bool shouldRemoveDeadBindings(AnalysisManager &AMgr,
return false;
// Is this the beginning of a basic block?
- if (isa<BlockEntrance>(Pred->getLocation()))
+ if (Pred->getLocation().getAs<BlockEntrance>())
return true;
// Is this on a non-expression?
@@ -268,22 +310,39 @@ static bool shouldRemoveDeadBindings(AnalysisManager &AMgr,
void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out,
const Stmt *ReferenceStmt,
- const StackFrameContext *LC,
+ const LocationContext *LC,
const Stmt *DiagnosticStmt,
ProgramPoint::Kind K) {
assert((K == ProgramPoint::PreStmtPurgeDeadSymbolsKind ||
- ReferenceStmt == 0)
+ ReferenceStmt == 0 || isa<ReturnStmt>(ReferenceStmt))
&& "PostStmt is not generally supported by the SymbolReaper yet");
+ assert(LC && "Must pass the current (or expiring) LocationContext");
+
+ if (!DiagnosticStmt) {
+ DiagnosticStmt = ReferenceStmt;
+ assert(DiagnosticStmt && "Required for clearing a LocationContext");
+ }
+
NumRemoveDeadBindings++;
- CleanedState = Pred->getState();
- SymbolReaper SymReaper(LC, ReferenceStmt, SymMgr, getStoreManager());
+ ProgramStateRef CleanedState = Pred->getState();
+
+ // LC is the location context being destroyed, but SymbolReaper wants a
+ // location context that is still live. (If this is the top-level stack
+ // frame, this will be null.)
+ if (!ReferenceStmt) {
+ assert(K == ProgramPoint::PostStmtPurgeDeadSymbolsKind &&
+ "Use PostStmtPurgeDeadSymbolsKind for clearing a LocationContext");
+ LC = LC->getParent();
+ }
+
+ const StackFrameContext *SFC = LC ? LC->getCurrentStackFrame() : 0;
+ SymbolReaper SymReaper(SFC, ReferenceStmt, SymMgr, getStoreManager());
getCheckerManager().runCheckersForLiveSymbols(CleanedState, SymReaper);
// Create a state in which dead bindings are removed from the environment
// and the store. TODO: The function should just return new env and store,
// not a new state.
- const StackFrameContext *SFC = LC->getCurrentStackFrame();
CleanedState = StateMgr.removeDeadBindings(CleanedState, SFC, SymReaper);
// Process any special transfer function for dead symbols.
@@ -336,19 +395,17 @@ void ExprEngine::ProcessStmt(const CFGStmt S,
// Reclaim any unnecessary nodes in the ExplodedGraph.
G.reclaimRecentlyAllocatedNodes();
- currStmt = S.getStmt();
+ const Stmt *currStmt = S.getStmt();
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
currStmt->getLocStart(),
"Error evaluating statement");
// Remove dead bindings and symbols.
- EntryNode = Pred;
ExplodedNodeSet CleanedStates;
- if (shouldRemoveDeadBindings(AMgr, S, Pred, EntryNode->getLocationContext())){
- removeDead(EntryNode, CleanedStates, currStmt,
- Pred->getStackFrame(), currStmt);
+ if (shouldRemoveDeadBindings(AMgr, S, Pred, Pred->getLocationContext())){
+ removeDead(Pred, CleanedStates, currStmt, Pred->getLocationContext());
} else
- CleanedStates.Add(EntryNode);
+ CleanedStates.Add(Pred);
// Visit the statement.
ExplodedNodeSet Dst;
@@ -362,11 +419,6 @@ void ExprEngine::ProcessStmt(const CFGStmt S,
// Enqueue the new nodes onto the work list.
Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
-
- // NULL out these variables to cleanup.
- CleanedState = NULL;
- EntryNode = NULL;
- currStmt = 0;
}
void ExprEngine::ProcessInitializer(const CFGInitializer Init,
@@ -377,7 +429,7 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init,
BMI->getSourceLocation(),
"Error evaluating initializer");
- // We don't set EntryNode and currStmt. And we don't clean up state.
+ // We don't clean up dead bindings here.
const StackFrameContext *stackFrame =
cast<StackFrameContext>(Pred->getLocationContext());
const CXXConstructorDecl *decl =
@@ -386,24 +438,52 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init,
ProgramStateRef State = Pred->getState();
SVal thisVal = State->getSVal(svalBuilder.getCXXThis(decl, stackFrame));
- PostInitializer PP(BMI, stackFrame);
ExplodedNodeSet Tmp(Pred);
+ SVal FieldLoc;
// 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.
- const Expr *Init = BMI->getInit();
+ const Expr *Init = BMI->getInit()->IgnoreImplicit();
if (!isa<CXXConstructExpr>(Init)) {
- SVal FieldLoc;
- if (BMI->isIndirectMemberInitializer())
+ const ValueDecl *Field;
+ if (BMI->isIndirectMemberInitializer()) {
+ Field = BMI->getIndirectMember();
FieldLoc = State->getLValue(BMI->getIndirectMember(), thisVal);
- else
+ } else {
+ Field = BMI->getMember();
FieldLoc = State->getLValue(BMI->getMember(), thisVal);
+ }
- SVal InitVal = State->getSVal(BMI->getInit(), stackFrame);
+ SVal InitVal;
+ if (BMI->getNumArrayIndices() > 0) {
+ // Handle arrays of trivial type. We can represent this with a
+ // primitive load/copy from the base array region.
+ const ArraySubscriptExpr *ASE;
+ while ((ASE = dyn_cast<ArraySubscriptExpr>(Init)))
+ Init = ASE->getBase()->IgnoreImplicit();
+
+ SVal LValue = State->getSVal(Init, stackFrame);
+ if (Optional<Loc> LValueLoc = LValue.getAs<Loc>())
+ InitVal = State->getSVal(*LValueLoc);
+
+ // If we fail to get the value for some reason, use a symbolic value.
+ if (InitVal.isUnknownOrUndef()) {
+ SValBuilder &SVB = getSValBuilder();
+ InitVal = SVB.conjureSymbolVal(BMI->getInit(), stackFrame,
+ Field->getType(),
+ currBldrCtx->blockCount());
+ }
+ } else {
+ InitVal = State->getSVal(BMI->getInit(), stackFrame);
+ }
+ assert(Tmp.size() == 1 && "have not generated any new nodes yet");
+ assert(*Tmp.begin() == Pred && "have not generated any new nodes yet");
Tmp.clear();
+
+ PostInitializer PP(BMI, FieldLoc.getAsRegion(), stackFrame);
evalBind(Tmp, Init, Pred, FieldLoc, InitVal, /*isInit=*/true, &PP);
}
} else {
@@ -413,6 +493,7 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init,
// Construct PostInitializer nodes whether the state changed or not,
// so that the diagnostics don't get confused.
+ PostInitializer PP(BMI, FieldLoc.getAsRegion(), stackFrame);
ExplodedNodeSet Dst;
NodeBuilder Bldr(Tmp, Dst, *currBldrCtx);
for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) {
@@ -429,16 +510,16 @@ void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D,
ExplodedNodeSet Dst;
switch (D.getKind()) {
case CFGElement::AutomaticObjectDtor:
- ProcessAutomaticObjDtor(cast<CFGAutomaticObjDtor>(D), Pred, Dst);
+ ProcessAutomaticObjDtor(D.castAs<CFGAutomaticObjDtor>(), Pred, Dst);
break;
case CFGElement::BaseDtor:
- ProcessBaseDtor(cast<CFGBaseDtor>(D), Pred, Dst);
+ ProcessBaseDtor(D.castAs<CFGBaseDtor>(), Pred, Dst);
break;
case CFGElement::MemberDtor:
- ProcessMemberDtor(cast<CFGMemberDtor>(D), Pred, Dst);
+ ProcessMemberDtor(D.castAs<CFGMemberDtor>(), Pred, Dst);
break;
case CFGElement::TemporaryDtor:
- ProcessTemporaryDtor(cast<CFGTemporaryDtor>(D), Pred, Dst);
+ ProcessTemporaryDtor(D.castAs<CFGTemporaryDtor>(), Pred, Dst);
break;
default:
llvm_unreachable("Unexpected dtor kind.");
@@ -451,18 +532,20 @@ void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D,
void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor,
ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
- ProgramStateRef state = Pred->getState();
const VarDecl *varDecl = Dtor.getVarDecl();
-
QualType varType = varDecl->getType();
- if (const ReferenceType *refType = varType->getAs<ReferenceType>())
- varType = refType->getPointeeType();
+ ProgramStateRef state = Pred->getState();
+ SVal dest = state->getLValue(varDecl, Pred->getLocationContext());
+ const MemRegion *Region = dest.castAs<loc::MemRegionVal>().getRegion();
- Loc dest = state->getLValue(varDecl, Pred->getLocationContext());
+ if (const ReferenceType *refType = varType->getAs<ReferenceType>()) {
+ varType = refType->getPointeeType();
+ Region = state->getSVal(Region).getAsRegion();
+ }
- VisitCXXDestructor(varType, cast<loc::MemRegionVal>(dest).getRegion(),
- Dtor.getTriggerStmt(), /*IsBase=*/false, Pred, Dst);
+ VisitCXXDestructor(varType, Region, Dtor.getTriggerStmt(), /*IsBase=*/ false,
+ Pred, Dst);
}
void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D,
@@ -476,11 +559,13 @@ void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D,
SVal ThisVal = Pred->getState()->getSVal(ThisPtr);
// Create the base object region.
- QualType BaseTy = D.getBaseSpecifier()->getType();
- SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, BaseTy);
+ const CXXBaseSpecifier *Base = D.getBaseSpecifier();
+ QualType BaseTy = Base->getType();
+ SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, BaseTy,
+ Base->isVirtual());
- VisitCXXDestructor(BaseTy, cast<loc::MemRegionVal>(BaseVal).getRegion(),
- CurDtor->getBody(), /*IsBase=*/true, Pred, Dst);
+ VisitCXXDestructor(BaseTy, BaseVal.castAs<loc::MemRegionVal>().getRegion(),
+ CurDtor->getBody(), /*IsBase=*/ true, Pred, Dst);
}
void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D,
@@ -492,10 +577,11 @@ void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D,
const CXXDestructorDecl *CurDtor = cast<CXXDestructorDecl>(LCtx->getDecl());
Loc ThisVal = getSValBuilder().getCXXThis(CurDtor,
LCtx->getCurrentStackFrame());
- SVal FieldVal = State->getLValue(Member, cast<Loc>(State->getSVal(ThisVal)));
+ SVal FieldVal =
+ State->getLValue(Member, State->getSVal(ThisVal).castAs<Loc>());
VisitCXXDestructor(Member->getType(),
- cast<loc::MemRegionVal>(FieldVal).getRegion(),
+ FieldVal.castAs<loc::MemRegionVal>().getRegion(),
CurDtor->getBody(), /*IsBase=*/false, Pred, Dst);
}
@@ -511,16 +597,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
ExplodedNodeSet Dst;
StmtNodeBuilder Bldr(Pred, DstTop, *currBldrCtx);
- // Expressions to ignore.
- if (const Expr *Ex = dyn_cast<Expr>(S))
- S = Ex->IgnoreParens();
-
- // FIXME: add metadata to the CFG so that we can disable
- // this check when we KNOW that there is no block-level subexpression.
- // The motivation is that this check requires a hashtable lookup.
-
- if (S != currStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(S))
- return;
+ assert(!isa<Expr>(S) || S == cast<Expr>(S)->IgnoreParens());
switch (S->getStmtClass()) {
// C++ and ARC stuff we don't support yet.
@@ -637,7 +714,6 @@ 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);
@@ -648,6 +724,43 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
break;
}
+ case Stmt::CXXDefaultArgExprClass: {
+ Bldr.takeNodes(Pred);
+ ExplodedNodeSet PreVisit;
+ getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this);
+
+ ExplodedNodeSet Tmp;
+ StmtNodeBuilder Bldr2(PreVisit, Tmp, *currBldrCtx);
+
+ const LocationContext *LCtx = Pred->getLocationContext();
+ const CXXDefaultArgExpr *DefaultE = cast<CXXDefaultArgExpr>(S);
+ const Expr *ArgE = DefaultE->getExpr();
+
+ // Avoid creating and destroying a lot of APSInts.
+ SVal V;
+ llvm::APSInt Result;
+
+ for (ExplodedNodeSet::iterator I = PreVisit.begin(), E = PreVisit.end();
+ I != E; ++I) {
+ ProgramStateRef State = (*I)->getState();
+
+ if (ArgE->EvaluateAsInt(Result, getContext()))
+ V = svalBuilder.makeIntVal(Result);
+ else
+ V = State->getSVal(ArgE, LCtx);
+
+ State = State->BindExpr(DefaultE, LCtx, V);
+ if (DefaultE->isGLValue())
+ State = createTemporaryRegionIfNeeded(State, LCtx, DefaultE,
+ DefaultE);
+ Bldr2.generateNode(S, *I, State);
+ }
+
+ getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this);
+ Bldr.addNodes(Dst);
+ break;
+ }
+
case Expr::ObjCArrayLiteralClass:
case Expr::ObjCDictionaryLiteralClass:
// FIXME: explicitly model with a region and the actual contents
@@ -780,16 +893,23 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::CXXNewExprClass: {
Bldr.takeNodes(Pred);
- const CXXNewExpr *NE = cast<CXXNewExpr>(S);
- VisitCXXNewExpr(NE, Pred, Dst);
+ ExplodedNodeSet PostVisit;
+ VisitCXXNewExpr(cast<CXXNewExpr>(S), Pred, PostVisit);
+ getCheckerManager().runCheckersForPostStmt(Dst, PostVisit, S, *this);
Bldr.addNodes(Dst);
break;
}
case Stmt::CXXDeleteExprClass: {
Bldr.takeNodes(Pred);
+ ExplodedNodeSet PreVisit;
const CXXDeleteExpr *CDE = cast<CXXDeleteExpr>(S);
- VisitCXXDeleteExpr(CDE, Pred, Dst);
+ getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this);
+
+ for (ExplodedNodeSet::iterator i = PreVisit.begin(),
+ e = PreVisit.end(); i != e ; ++i)
+ VisitCXXDeleteExpr(CDE, *i, Dst);
+
Bldr.addNodes(Dst);
break;
}
@@ -1012,11 +1132,11 @@ bool ExprEngine::replayWithoutInlining(ExplodedNode *N,
// processing the call.
if (L.isPurgeKind())
continue;
- if (isa<PreImplicitCall>(&L))
+ if (L.getAs<PreImplicitCall>())
continue;
- if (isa<CallEnter>(&L))
+ if (L.getAs<CallEnter>())
continue;
- if (const StmtPoint *SP = dyn_cast<StmtPoint>(&L))
+ if (Optional<StmtPoint> SP = L.getAs<StmtPoint>())
if (SP->getStmt() == CE)
continue;
break;
@@ -1034,7 +1154,8 @@ bool ExprEngine::replayWithoutInlining(ExplodedNode *N,
// Add the special flag to GDM to signal retrying with no inlining.
// Note, changing the state ensures that we are not going to cache out.
ProgramStateRef NewNodeState = BeforeProcessingCall->getState();
- NewNodeState = NewNodeState->set<ReplayWithoutInlining>((void*)CE);
+ NewNodeState =
+ NewNodeState->set<ReplayWithoutInlining>(const_cast<Stmt *>(CE));
// Make the new node a successor of BeforeProcessingCall.
bool IsNew = false;
@@ -1155,7 +1276,7 @@ static const Stmt *ResolveCondition(const Stmt *Condition,
CFGBlock::const_reverse_iterator I = B->rbegin(), E = B->rend();
for (; I != E; ++I) {
CFGElement Elem = *I;
- CFGStmt *CS = dyn_cast<CFGStmt>(&Elem);
+ Optional<CFGStmt> CS = Elem.getAs<CFGStmt>();
if (!CS)
continue;
if (CS->getStmt() != Condition)
@@ -1215,8 +1336,8 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term,
if (PredI->isSink())
continue;
- ProgramStateRef PrevState = Pred->getState();
- SVal X = PrevState->getSVal(Condition, Pred->getLocationContext());
+ ProgramStateRef PrevState = PredI->getState();
+ SVal X = PrevState->getSVal(Condition, PredI->getLocationContext());
if (X.isUnknownOrUndef()) {
// Give it a chance to recover from unknown.
@@ -1228,7 +1349,7 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term,
// underlying value and use that instead.
SVal recovered = RecoverCastedSymbol(getStateManager(),
PrevState, Condition,
- Pred->getLocationContext(),
+ PredI->getLocationContext(),
getContext());
if (!recovered.isUnknown()) {
@@ -1245,20 +1366,23 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term,
continue;
}
- DefinedSVal V = cast<DefinedSVal>(X);
+ DefinedSVal V = X.castAs<DefinedSVal>();
+
+ ProgramStateRef StTrue, StFalse;
+ tie(StTrue, StFalse) = PrevState->assume(V);
// Process the true branch.
if (builder.isFeasible(true)) {
- if (ProgramStateRef state = PrevState->assume(V, true))
- builder.generateNode(state, true, PredI);
+ if (StTrue)
+ builder.generateNode(StTrue, true, PredI);
else
builder.markInfeasible(true);
}
// Process the false branch.
if (builder.isFeasible(false)) {
- if (ProgramStateRef state = PrevState->assume(V, false))
- builder.generateNode(state, false, PredI);
+ if (StFalse)
+ builder.generateNode(StFalse, false, PredI);
else
builder.markInfeasible(false);
}
@@ -1266,6 +1390,34 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term,
currBldrCtx = 0;
}
+/// The GDM component containing the set of global variables which have been
+/// previously initialized with explicit initializers.
+REGISTER_TRAIT_WITH_PROGRAMSTATE(InitializedGlobalsSet,
+ llvm::ImmutableSet<const VarDecl *>)
+
+void ExprEngine::processStaticInitializer(const DeclStmt *DS,
+ NodeBuilderContext &BuilderCtx,
+ ExplodedNode *Pred,
+ clang::ento::ExplodedNodeSet &Dst,
+ const CFGBlock *DstT,
+ const CFGBlock *DstF) {
+ currBldrCtx = &BuilderCtx;
+
+ const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
+ ProgramStateRef state = Pred->getState();
+ bool initHasRun = state->contains<InitializedGlobalsSet>(VD);
+ BranchNodeBuilder builder(Pred, Dst, BuilderCtx, DstT, DstF);
+
+ if (!initHasRun) {
+ state = state->add<InitializedGlobalsSet>(VD);
+ }
+
+ builder.generateNode(state, initHasRun, Pred);
+ builder.markInfeasible(!initHasRun);
+
+ currBldrCtx = 0;
+}
+
/// processIndirectGoto - Called by CoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a computed goto jump.
void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) {
@@ -1282,8 +1434,8 @@ void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) {
typedef IndirectGotoNodeBuilder::iterator iterator;
- if (isa<loc::GotoLabel>(V)) {
- const LabelDecl *L = cast<loc::GotoLabel>(V).getLabel();
+ if (Optional<loc::GotoLabel> LV = V.getAs<loc::GotoLabel>()) {
+ const LabelDecl *L = LV->getLabel();
for (iterator I = builder.begin(), E = builder.end(); I != E; ++I) {
if (I.getLabel() == L) {
@@ -1295,7 +1447,7 @@ void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) {
llvm_unreachable("No block with label.");
}
- if (isa<loc::ConcreteInt>(V) || isa<UndefinedVal>(V)) {
+ if (V.getAs<loc::ConcreteInt>() || V.getAs<UndefinedVal>()) {
// Dispatch to the first target and mark it as a sink.
//ExplodedNode* N = builder.generateNode(builder.begin(), state, true);
// FIXME: add checker visit.
@@ -1325,10 +1477,10 @@ void ExprEngine::processEndOfFunction(NodeBuilderContext& BC,
// Notify checkers.
for (ExplodedNodeSet::iterator I = AfterRemovedDead.begin(),
E = AfterRemovedDead.end(); I != E; ++I) {
- getCheckerManager().runCheckersForEndPath(BC, Dst, *I, *this);
+ getCheckerManager().runCheckersForEndFunction(BC, Dst, *I, *this);
}
} else {
- getCheckerManager().runCheckersForEndPath(BC, Dst, Pred, *this);
+ getCheckerManager().runCheckersForEndFunction(BC, Dst, Pred, *this);
}
Engine.enqueueEndOfFunction(Dst);
@@ -1349,7 +1501,7 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
return;
}
- DefinedOrUnknownSVal CondV = cast<DefinedOrUnknownSVal>(CondV_untested);
+ DefinedOrUnknownSVal CondV = CondV_untested.castAs<DefinedOrUnknownSVal>();
ProgramStateRef DefaultSt = state;
@@ -1390,7 +1542,7 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
// If CondV evaluates to a constant, then we know that this
// is the *only* case that we can take, so stop evaluating the
// others.
- if (isa<nonloc::ConcreteInt>(CondV))
+ if (CondV.getAs<nonloc::ConcreteInt>())
return;
}
@@ -1484,7 +1636,7 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
// results in boolean contexts.
SVal V = svalBuilder.conjureSymbolVal(Ex, LCtx, getContext().VoidPtrTy,
currBldrCtx->blockCount());
- state = state->assume(cast<DefinedOrUnknownSVal>(V), true);
+ state = state->assume(V.castAs<DefinedOrUnknownSVal>(), true);
Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), 0,
ProgramPoint::PostLValueKind);
return;
@@ -1576,6 +1728,122 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
}
}
+namespace {
+class CollectReachableSymbolsCallback : public SymbolVisitor {
+ InvalidatedSymbols Symbols;
+public:
+ CollectReachableSymbolsCallback(ProgramStateRef State) {}
+ const InvalidatedSymbols &getSymbols() const { return Symbols; }
+
+ bool VisitSymbol(SymbolRef Sym) {
+ Symbols.insert(Sym);
+ return true;
+ }
+};
+} // end anonymous namespace
+
+// A value escapes in three possible cases:
+// (1) We are binding to something that is not a memory region.
+// (2) We are binding to a MemrRegion that does not have stack storage.
+// (3) We are binding to a MemRegion with stack storage that the store
+// does not understand.
+ProgramStateRef ExprEngine::processPointerEscapedOnBind(ProgramStateRef State,
+ SVal Loc, SVal Val) {
+ // Are we storing to something that causes the value to "escape"?
+ bool escapes = true;
+
+ // TODO: Move to StoreManager.
+ if (Optional<loc::MemRegionVal> regionLoc = Loc.getAs<loc::MemRegionVal>()) {
+ 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 and have the simulation
+ // state continue as is.
+ if (!escapes)
+ return State;
+
+ // Otherwise, find all symbols referenced by 'val' that we are tracking
+ // and stop tracking them.
+ CollectReachableSymbolsCallback Scanner =
+ State->scanReachableSymbols<CollectReachableSymbolsCallback>(Val);
+ const InvalidatedSymbols &EscapedSymbols = Scanner.getSymbols();
+ State = getCheckerManager().runCheckersForPointerEscape(State,
+ EscapedSymbols,
+ /*CallEvent*/ 0,
+ PSK_EscapeOnBind);
+
+ return State;
+}
+
+ProgramStateRef
+ExprEngine::notifyCheckersOfPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols *Invalidated,
+ ArrayRef<const MemRegion *> ExplicitRegions,
+ ArrayRef<const MemRegion *> Regions,
+ const CallEvent *Call,
+ bool IsConst) {
+
+ if (!Invalidated || Invalidated->empty())
+ return State;
+
+ if (!Call)
+ return getCheckerManager().runCheckersForPointerEscape(State,
+ *Invalidated,
+ 0,
+ PSK_EscapeOther);
+
+ // Note: Due to current limitations of RegionStore, we only process the top
+ // level const pointers correctly. The lower level const pointers are
+ // currently treated as non-const.
+ if (IsConst)
+ return getCheckerManager().runCheckersForPointerEscape(State,
+ *Invalidated,
+ Call,
+ PSK_DirectEscapeOnCall,
+ true);
+
+ // If the symbols were invalidated by a call, we want to find out which ones
+ // were invalidated directly due to being arguments to the call.
+ InvalidatedSymbols SymbolsDirectlyInvalidated;
+ for (ArrayRef<const MemRegion *>::iterator I = ExplicitRegions.begin(),
+ E = ExplicitRegions.end(); I != E; ++I) {
+ if (const SymbolicRegion *R = (*I)->StripCasts()->getAs<SymbolicRegion>())
+ SymbolsDirectlyInvalidated.insert(R->getSymbol());
+ }
+
+ InvalidatedSymbols SymbolsIndirectlyInvalidated;
+ for (InvalidatedSymbols::const_iterator I=Invalidated->begin(),
+ E = Invalidated->end(); I!=E; ++I) {
+ SymbolRef sym = *I;
+ if (SymbolsDirectlyInvalidated.count(sym))
+ continue;
+ SymbolsIndirectlyInvalidated.insert(sym);
+ }
+
+ if (!SymbolsDirectlyInvalidated.empty())
+ State = getCheckerManager().runCheckersForPointerEscape(State,
+ SymbolsDirectlyInvalidated, Call, PSK_DirectEscapeOnCall);
+
+ // Notify about the symbols that get indirectly invalidated by the call.
+ if (!SymbolsIndirectlyInvalidated.empty())
+ State = getCheckerManager().runCheckersForPointerEscape(State,
+ SymbolsIndirectlyInvalidated, Call, PSK_IndirectEscapeOnCall);
+
+ return State;
+}
+
/// evalBind - Handle the semantics of binding a value to a specific location.
/// This method is used by evalStore and (soon) VisitDeclStmt, and others.
void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE,
@@ -1593,36 +1861,42 @@ void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE,
getCheckerManager().runCheckersForBind(CheckedSet, Pred, location, Val,
StoreE, *this, *PP);
+
+ StmtNodeBuilder Bldr(CheckedSet, Dst, *currBldrCtx);
+
// If the location is not a 'Loc', it will already be handled by
// the checkers. There is nothing left to do.
- if (!isa<Loc>(location)) {
- Dst = CheckedSet;
+ if (!location.getAs<Loc>()) {
+ const ProgramPoint L = PostStore(StoreE, LC, /*Loc*/0, /*tag*/0);
+ ProgramStateRef state = Pred->getState();
+ state = processPointerEscapedOnBind(state, location, Val);
+ Bldr.generateNode(L, state, Pred);
return;
}
- ExplodedNodeSet TmpDst;
- StmtNodeBuilder Bldr(CheckedSet, TmpDst, *currBldrCtx);
for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
I!=E; ++I) {
ExplodedNode *PredI = *I;
ProgramStateRef state = PredI->getState();
+ state = processPointerEscapedOnBind(state, location, Val);
+
// When binding the value, pass on the hint that this is a initialization.
// For initializations, we do not need to inform clients of region
// changes.
- state = state->bindLoc(cast<Loc>(location),
+ state = state->bindLoc(location.castAs<Loc>(),
Val, /* notifyChanges = */ !atDeclInit);
-
+
const MemRegion *LocReg = 0;
- if (loc::MemRegionVal *LocRegVal = dyn_cast<loc::MemRegionVal>(&location)) {
+ if (Optional<loc::MemRegionVal> LocRegVal =
+ location.getAs<loc::MemRegionVal>()) {
LocReg = LocRegVal->getRegion();
}
const ProgramPoint L = PostStore(StoreE, LC, LocReg, 0);
Bldr.generateNode(L, state, PredI);
}
- Dst.insert(TmpDst);
}
/// evalStore - Handle the semantics of a store via an assignment.
@@ -1665,7 +1939,7 @@ void ExprEngine::evalLoad(ExplodedNodeSet &Dst,
const ProgramPointTag *tag,
QualType LoadTy)
{
- assert(!isa<NonLoc>(location) && "location cannot be a NonLoc.");
+ assert(!location.getAs<NonLoc>() && "location cannot be a NonLoc.");
// Are we loading from a region? This actually results in two loads; one
// to fetch the address of the referenced value and one to fetch the
@@ -1720,20 +1994,15 @@ void ExprEngine::evalLoadCommon(ExplodedNodeSet &Dst,
state = (*NI)->getState();
const LocationContext *LCtx = (*NI)->getLocationContext();
- if (location.isUnknown()) {
- // This is important. We must nuke the old binding.
- Bldr.generateNode(NodeEx, *NI,
- state->BindExpr(BoundEx, LCtx, UnknownVal()),
- tag, ProgramPoint::PostLoadKind);
- }
- else {
+ SVal V = UnknownVal();
+ if (location.isValid()) {
if (LoadTy.isNull())
LoadTy = BoundEx->getType();
- SVal V = state->getSVal(cast<Loc>(location), LoadTy);
- Bldr.generateNode(NodeEx, *NI,
- state->bindExprAndLocation(BoundEx, LCtx, location, V),
- tag, ProgramPoint::PostLoadKind);
+ V = state->getSVal(location.castAs<Loc>(), LoadTy);
}
+
+ Bldr.generateNode(NodeEx, *NI, state->BindExpr(BoundEx, LCtx, V), tag,
+ ProgramPoint::PostLoadKind);
}
}
@@ -1793,26 +2062,29 @@ void ExprEngine::evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst,
// when the expression fails to evaluate to anything meaningful and
// (as an optimization) we don't generate a node.
ProgramPoint P = Pred->getLocation();
- if (!isa<PostStmt>(P) || cast<PostStmt>(P).getStmt() != Ex) {
+ if (!P.getAs<PostStmt>() || P.castAs<PostStmt>().getStmt() != Ex) {
continue;
}
ProgramStateRef state = Pred->getState();
SVal V = state->getSVal(Ex, Pred->getLocationContext());
- nonloc::SymbolVal *SEV = dyn_cast<nonloc::SymbolVal>(&V);
+ Optional<nonloc::SymbolVal> SEV = V.getAs<nonloc::SymbolVal>();
if (SEV && SEV->isExpression()) {
const std::pair<const ProgramPointTag *, const ProgramPointTag*> &tags =
geteagerlyAssumeBinOpBifurcationTags();
+ ProgramStateRef StateTrue, StateFalse;
+ tie(StateTrue, StateFalse) = state->assume(*SEV);
+
// First assume that the condition is true.
- if (ProgramStateRef StateTrue = state->assume(*SEV, true)) {
+ if (StateTrue) {
SVal Val = svalBuilder.makeIntVal(1U, Ex->getType());
StateTrue = StateTrue->BindExpr(Ex, Pred->getLocationContext(), Val);
Bldr.generateNode(Ex, Pred, StateTrue, tags.first);
}
// Next, assume that the condition is false.
- if (ProgramStateRef StateFalse = state->assume(*SEV, false)) {
+ if (StateFalse) {
SVal Val = svalBuilder.makeIntVal(0U, Ex->getType());
StateFalse = StateFalse->BindExpr(Ex, Pred->getLocationContext(), Val);
Bldr.generateNode(Ex, Pred, StateFalse, tags.second);
@@ -1836,10 +2108,10 @@ void ExprEngine::VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred,
for (GCCAsmStmt::const_outputs_iterator OI = A->begin_outputs(),
OE = A->end_outputs(); OI != OE; ++OI) {
SVal X = state->getSVal(*OI, Pred->getLocationContext());
- assert (!isa<NonLoc>(X)); // Should be an Lval, or unknown, undef.
+ assert (!X.getAs<NonLoc>()); // Should be an Lval, or unknown, undef.
- if (isa<Loc>(X))
- state = state->bindLoc(cast<Loc>(X), UnknownVal());
+ if (Optional<Loc> LV = X.getAs<Loc>())
+ state = state->bindLoc(*LV, UnknownVal());
}
Bldr.generateNode(A, Pred, state);
@@ -1889,7 +2161,7 @@ struct DOTGraphTraits<ExplodedNode*> :
return "";
}
- static void printLocation(llvm::raw_ostream &Out, SourceLocation SLoc) {
+ static void printLocation(raw_ostream &Out, SourceLocation SLoc) {
if (SLoc.isFileID()) {
Out << "\\lline="
<< GraphPrintSourceManager->getExpansionLineNumber(SLoc)
@@ -1910,7 +2182,7 @@ struct DOTGraphTraits<ExplodedNode*> :
switch (Loc.getKind()) {
case ProgramPoint::BlockEntranceKind: {
Out << "Block Entrance: B"
- << cast<BlockEntrance>(Loc).getBlock()->getBlockID();
+ << Loc.castAs<BlockEntrance>().getBlock()->getBlockID();
if (const NamedDecl *ND =
dyn_cast<NamedDecl>(Loc.getLocationContext()->getDecl())) {
Out << " (";
@@ -1949,73 +2221,46 @@ struct DOTGraphTraits<ExplodedNode*> :
break;
case ProgramPoint::PreImplicitCallKind: {
- ImplicitCallPoint *PC = cast<ImplicitCallPoint>(&Loc);
+ ImplicitCallPoint PC = Loc.castAs<ImplicitCallPoint>();
Out << "PreCall: ";
// FIXME: Get proper printing options.
- PC->getDecl()->print(Out, LangOptions());
- printLocation(Out, PC->getLocation());
+ PC.getDecl()->print(Out, LangOptions());
+ printLocation(Out, PC.getLocation());
break;
}
case ProgramPoint::PostImplicitCallKind: {
- ImplicitCallPoint *PC = cast<ImplicitCallPoint>(&Loc);
+ ImplicitCallPoint PC = Loc.castAs<ImplicitCallPoint>();
Out << "PostCall: ";
// FIXME: Get proper printing options.
- PC->getDecl()->print(Out, LangOptions());
- printLocation(Out, PC->getLocation());
+ PC.getDecl()->print(Out, LangOptions());
+ printLocation(Out, PC.getLocation());
break;
}
- default: {
- if (StmtPoint *L = dyn_cast<StmtPoint>(&Loc)) {
- const Stmt *S = L->getStmt();
-
- Out << S->getStmtClassName() << ' ' << (const void*) S << ' ';
+ case ProgramPoint::PostInitializerKind: {
+ Out << "PostInitializer: ";
+ const CXXCtorInitializer *Init =
+ Loc.castAs<PostInitializer>().getInitializer();
+ if (const FieldDecl *FD = Init->getAnyMember())
+ Out << *FD;
+ else {
+ QualType Ty = Init->getTypeSourceInfo()->getType();
+ Ty = Ty.getLocalUnqualifiedType();
LangOptions LO; // FIXME.
- S->printPretty(Out, 0, PrintingPolicy(LO));
- printLocation(Out, S->getLocStart());
-
- if (isa<PreStmt>(Loc))
- Out << "\\lPreStmt\\l;";
- else if (isa<PostLoad>(Loc))
- Out << "\\lPostLoad\\l;";
- else if (isa<PostStore>(Loc))
- Out << "\\lPostStore\\l";
- else if (isa<PostLValue>(Loc))
- Out << "\\lPostLValue\\l";
-
-#if 0
- // FIXME: Replace with a general scheme to determine
- // the name of the check.
- if (GraphPrintCheckerState->isImplicitNullDeref(N))
- Out << "\\|Implicit-Null Dereference.\\l";
- else if (GraphPrintCheckerState->isExplicitNullDeref(N))
- Out << "\\|Explicit-Null Dereference.\\l";
- else if (GraphPrintCheckerState->isUndefDeref(N))
- Out << "\\|Dereference of undefialied value.\\l";
- else if (GraphPrintCheckerState->isUndefStore(N))
- Out << "\\|Store to Undefined Loc.";
- else if (GraphPrintCheckerState->isUndefResult(N))
- Out << "\\|Result of operation is undefined.";
- else if (GraphPrintCheckerState->isNoReturnCall(N))
- Out << "\\|Call to function marked \"noreturn\".";
- else if (GraphPrintCheckerState->isBadCall(N))
- Out << "\\|Call to NULL/Undefined.";
- else if (GraphPrintCheckerState->isUndefArg(N))
- Out << "\\|Argument in call is undefined";
-#endif
-
- break;
+ Ty.print(Out, LO);
}
+ break;
+ }
- const BlockEdge &E = cast<BlockEdge>(Loc);
+ case ProgramPoint::BlockEdgeKind: {
+ const BlockEdge &E = Loc.castAs<BlockEdge>();
Out << "Edge: (B" << E.getSrc()->getBlockID() << ", B"
<< E.getDst()->getBlockID() << ')';
if (const Stmt *T = E.getSrc()->getTerminator()) {
-
SourceLocation SLoc = T->getLocStart();
Out << "\\|Terminator: ";
@@ -2074,6 +2319,48 @@ struct DOTGraphTraits<ExplodedNode*> :
Out << "\\|Control-flow based on\\lUndefined value.\\l";
}
#endif
+ break;
+ }
+
+ default: {
+ const Stmt *S = Loc.castAs<StmtPoint>().getStmt();
+
+ Out << S->getStmtClassName() << ' ' << (const void*) S << ' ';
+ LangOptions LO; // FIXME.
+ S->printPretty(Out, 0, PrintingPolicy(LO));
+ printLocation(Out, S->getLocStart());
+
+ if (Loc.getAs<PreStmt>())
+ Out << "\\lPreStmt\\l;";
+ else if (Loc.getAs<PostLoad>())
+ Out << "\\lPostLoad\\l;";
+ else if (Loc.getAs<PostStore>())
+ Out << "\\lPostStore\\l";
+ else if (Loc.getAs<PostLValue>())
+ Out << "\\lPostLValue\\l";
+
+#if 0
+ // FIXME: Replace with a general scheme to determine
+ // the name of the check.
+ if (GraphPrintCheckerState->isImplicitNullDeref(N))
+ Out << "\\|Implicit-Null Dereference.\\l";
+ else if (GraphPrintCheckerState->isExplicitNullDeref(N))
+ Out << "\\|Explicit-Null Dereference.\\l";
+ else if (GraphPrintCheckerState->isUndefDeref(N))
+ Out << "\\|Dereference of undefialied value.\\l";
+ else if (GraphPrintCheckerState->isUndefStore(N))
+ Out << "\\|Store to Undefined Loc.";
+ else if (GraphPrintCheckerState->isUndefResult(N))
+ Out << "\\|Result of operation is undefined.";
+ else if (GraphPrintCheckerState->isNoReturnCall(N))
+ Out << "\\|Call to function marked \"noreturn\".";
+ else if (GraphPrintCheckerState->isBadCall(N))
+ Out << "\\|Call to NULL/Undefined.";
+ else if (GraphPrintCheckerState->isUndefArg(N))
+ Out << "\\|Argument in call is undefined";
+#endif
+
+ break;
}
}
@@ -2108,7 +2395,7 @@ GetGraphNode<llvm::DenseMap<ExplodedNode*, Expr*>::iterator>
void ExprEngine::ViewGraph(bool trim) {
#ifndef NDEBUG
if (trim) {
- std::vector<ExplodedNode*> Src;
+ std::vector<const ExplodedNode*> Src;
// Flush any outstanding reports to make sure we cover all the nodes.
// This does not cause them to get displayed.
@@ -2122,7 +2409,7 @@ void ExprEngine::ViewGraph(bool trim) {
if (N) Src.push_back(N);
}
- ViewGraph(&Src[0], &Src[0]+Src.size());
+ ViewGraph(Src);
}
else {
GraphPrintCheckerState = this;
@@ -2136,12 +2423,12 @@ void ExprEngine::ViewGraph(bool trim) {
#endif
}
-void ExprEngine::ViewGraph(ExplodedNode** Beg, ExplodedNode** End) {
+void ExprEngine::ViewGraph(ArrayRef<const ExplodedNode*> Nodes) {
#ifndef NDEBUG
GraphPrintCheckerState = this;
GraphPrintSourceManager = &getContext().getSourceManager();
- std::auto_ptr<ExplodedGraph> TrimmedG(G.Trim(Beg, End).first);
+ OwningPtr<ExplodedGraph> TrimmedG(G.trim(Nodes));
if (!TrimmedG.get())
llvm::errs() << "warning: Trimmed ExplodedGraph is empty.\n";
diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 00b2f4a..3a3c971 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/ExprCXX.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
@@ -66,12 +67,12 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
// TODO: This can be removed after we enable history tracking with
// SymSymExpr.
unsigned Count = currBldrCtx->blockCount();
- if (isa<Loc>(LeftV) &&
+ if (LeftV.getAs<Loc>() &&
RHS->getType()->isIntegerType() && RightV.isUnknown()) {
RightV = svalBuilder.conjureSymbolVal(RHS, LCtx, RHS->getType(),
Count);
}
- if (isa<Loc>(RightV) &&
+ if (RightV.getAs<Loc>() &&
LHS->getType()->isIntegerType() && LeftV.isUnknown()) {
LeftV = svalBuilder.conjureSymbolVal(LHS, LCtx, LHS->getType(),
Count);
@@ -305,7 +306,8 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
case CK_CPointerToObjCPointerCast:
case CK_BlockPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
- case CK_ObjCObjectLValueCast: {
+ case CK_ObjCObjectLValueCast:
+ case CK_ZeroToOCLEvent: {
// Delegate to SValBuilder to process.
SVal V = state->getSVal(Ex, LCtx);
V = svalBuilder.evalCast(V, T, ExTy);
@@ -423,15 +425,10 @@ void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL,
void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
ExplodedNodeSet &Dst) {
-
- // FIXME: static variables may have an initializer, but the second
- // time a function is called those values may not be current.
- // This may need to be reflected in the CFG.
-
// Assumption: The CFG has one DeclStmt per Decl.
- const Decl *D = *DS->decl_begin();
-
- if (!D || !isa<VarDecl>(D)) {
+ const VarDecl *VD = dyn_cast_or_null<VarDecl>(*DS->decl_begin());
+
+ if (!VD) {
//TODO:AZ: remove explicit insertion after refactoring is done.
Dst.insert(Pred);
return;
@@ -442,31 +439,33 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, DS, *this);
StmtNodeBuilder B(dstPreVisit, Dst, *currBldrCtx);
- const VarDecl *VD = dyn_cast<VarDecl>(D);
for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end();
I!=E; ++I) {
ExplodedNode *N = *I;
ProgramStateRef state = N->getState();
-
- // Decls without InitExpr are not initialized explicitly.
const LocationContext *LC = N->getLocationContext();
-
+
+ // Decls without InitExpr are not initialized explicitly.
if (const Expr *InitEx = VD->getInit()) {
+
+ // Note in the state that the initialization has occurred.
+ ExplodedNode *UpdatedN = N;
SVal InitVal = state->getSVal(InitEx, LC);
- if (InitVal == state->getLValue(VD, LC) ||
- (VD->getType()->isArrayType() &&
- isa<CXXConstructExpr>(InitEx->IgnoreImplicit()))) {
+ if (isa<CXXConstructExpr>(InitEx->IgnoreImplicit())) {
// We constructed the object directly in the variable.
// No need to bind anything.
- B.generateNode(DS, N, state);
+ B.generateNode(DS, UpdatedN, state);
} else {
// We bound the temp obj region to the CXXConstructExpr. Now recover
// the lazy compound value when the variable is not a reference.
- if (AMgr.getLangOpts().CPlusPlus && VD->getType()->isRecordType() &&
- !VD->getType()->isReferenceType() && isa<loc::MemRegionVal>(InitVal)){
- InitVal = state->getSVal(cast<loc::MemRegionVal>(InitVal).getRegion());
- assert(isa<nonloc::LazyCompoundVal>(InitVal));
+ if (AMgr.getLangOpts().CPlusPlus && VD->getType()->isRecordType() &&
+ !VD->getType()->isReferenceType()) {
+ if (Optional<loc::MemRegionVal> M =
+ InitVal.getAs<loc::MemRegionVal>()) {
+ InitVal = state->getSVal(M->getRegion());
+ assert(InitVal.getAs<nonloc::LazyCompoundVal>());
+ }
}
// Recover some path-sensitivity if a scalar value evaluated to
@@ -480,9 +479,11 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
InitVal = svalBuilder.conjureSymbolVal(0, InitEx, LC, Ty,
currBldrCtx->blockCount());
}
- B.takeNodes(N);
+
+
+ B.takeNodes(UpdatedN);
ExplodedNodeSet Dst2;
- evalBind(Dst2, DS, N, state->getLValue(VD, LC), InitVal, true);
+ evalBind(Dst2, DS, UpdatedN, state->getLValue(VD, LC), InitVal, true);
B.addNodes(Dst2);
}
}
@@ -501,16 +502,16 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
ProgramStateRef state = Pred->getState();
ExplodedNode *N = Pred;
- while (!isa<BlockEntrance>(N->getLocation())) {
+ while (!N->getLocation().getAs<BlockEntrance>()) {
ProgramPoint P = N->getLocation();
- assert(isa<PreStmt>(P)|| isa<PreStmtPurgeDeadSymbols>(P));
+ assert(P.getAs<PreStmt>()|| P.getAs<PreStmtPurgeDeadSymbols>());
(void) P;
assert(N->pred_size() == 1);
N = *N->pred_begin();
}
assert(N->pred_size() == 1);
N = *N->pred_begin();
- BlockEdge BE = cast<BlockEdge>(N->getLocation());
+ BlockEdge BE = N->getLocation().castAs<BlockEdge>();
SVal X;
// Determine the value of the expression by introspecting how we
@@ -532,28 +533,32 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
// in SrcBlock is the value of the enclosing expression.
// However, we still need to constrain that value to be 0 or 1.
assert(!SrcBlock->empty());
- CFGStmt Elem = cast<CFGStmt>(*SrcBlock->rbegin());
+ CFGStmt Elem = SrcBlock->rbegin()->castAs<CFGStmt>();
const Expr *RHS = cast<Expr>(Elem.getStmt());
SVal RHSVal = N->getState()->getSVal(RHS, Pred->getLocationContext());
- DefinedOrUnknownSVal DefinedRHS = cast<DefinedOrUnknownSVal>(RHSVal);
- ProgramStateRef StTrue, StFalse;
- llvm::tie(StTrue, StFalse) = N->getState()->assume(DefinedRHS);
- if (StTrue) {
- if (StFalse) {
- // We can't constrain the value to 0 or 1; the best we can do is a cast.
- X = getSValBuilder().evalCast(RHSVal, B->getType(), RHS->getType());
+ if (RHSVal.isUndef()) {
+ X = RHSVal;
+ } else {
+ DefinedOrUnknownSVal DefinedRHS = RHSVal.castAs<DefinedOrUnknownSVal>();
+ 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 true.
- X = getSValBuilder().makeIntVal(1, B->getType());
+ // The value is known to be false.
+ assert(StFalse && "Infeasible path!");
+ X = getSValBuilder().makeIntVal(0, 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));
}
@@ -581,8 +586,10 @@ void ExprEngine::VisitInitListExpr(const InitListExpr *IE,
for (InitListExpr::const_reverse_iterator it = IE->rbegin(),
ei = IE->rend(); it != ei; ++it) {
- vals = getBasicVals().consVals(state->getSVal(cast<Expr>(*it), LCtx),
- vals);
+ SVal V = state->getSVal(cast<Expr>(*it), LCtx);
+ if (dyn_cast_or_null<CXXTempObjectRegion>(V.getAsRegion()))
+ V = UnknownVal();
+ vals = getBasicVals().consVals(V, vals);
}
B.generateNode(IE, Pred,
@@ -615,14 +622,16 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex,
for (const ExplodedNode *N = Pred ; N ; N = *N->pred_begin()) {
ProgramPoint PP = N->getLocation();
- if (isa<PreStmtPurgeDeadSymbols>(PP) || isa<BlockEntrance>(PP)) {
+ if (PP.getAs<PreStmtPurgeDeadSymbols>() || PP.getAs<BlockEntrance>()) {
assert(N->pred_size() == 1);
continue;
}
- SrcBlock = cast<BlockEdge>(&PP)->getSrc();
+ SrcBlock = PP.castAs<BlockEdge>().getSrc();
break;
}
+ assert(SrcBlock && "missing function entry");
+
// Find the last expression in the predecessor block. That is the
// expression that is used for the value of the ternary expression.
bool hasValue = false;
@@ -631,7 +640,7 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex,
for (CFGBlock::const_reverse_iterator I = SrcBlock->rbegin(),
E = SrcBlock->rend(); I != E; ++I) {
CFGElement CE = *I;
- if (CFGStmt *CS = dyn_cast<CFGStmt>(&CE)) {
+ if (Optional<CFGStmt> CS = CE.getAs<CFGStmt>()) {
const Expr *ValEx = cast<Expr>(CS->getStmt());
hasValue = true;
V = state->getSVal(ValEx, LCtx);
@@ -785,11 +794,11 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
llvm_unreachable("Invalid Opcode.");
case UO_Not:
// FIXME: Do we need to handle promotions?
- state = state->BindExpr(U, LCtx, evalComplement(cast<NonLoc>(V)));
+ state = state->BindExpr(U, LCtx, evalComplement(V.castAs<NonLoc>()));
break;
case UO_Minus:
// FIXME: Do we need to handle promotions?
- state = state->BindExpr(U, LCtx, evalMinus(cast<NonLoc>(V)));
+ state = state->BindExpr(U, LCtx, evalMinus(V.castAs<NonLoc>()));
break;
case UO_LNot:
// C99 6.5.3.3: "The expression !E is equivalent to (0==E)."
@@ -797,14 +806,16 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
// Note: technically we do "E == 0", but this is the same in the
// transfer functions as "0 == E".
SVal Result;
- if (isa<Loc>(V)) {
+ if (Optional<Loc> LV = V.getAs<Loc>()) {
Loc X = svalBuilder.makeNull();
- Result = evalBinOp(state, BO_EQ, cast<Loc>(V), X,
- U->getType());
+ Result = evalBinOp(state, BO_EQ, *LV, X, U->getType());
}
- else {
+ else if (Ex->getType()->isFloatingType()) {
+ // FIXME: handle floating point types.
+ Result = UnknownVal();
+ } else {
nonloc::ConcreteInt X(getBasicVals().getValue(0, Ex->getType()));
- Result = evalBinOp(state, BO_EQ, cast<NonLoc>(V), X,
+ Result = evalBinOp(state, BO_EQ, V.castAs<NonLoc>(), X,
U->getType());
}
@@ -846,7 +857,7 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
Bldr.generateNode(U, *I, state->BindExpr(U, LCtx, V2_untested));
continue;
}
- DefinedSVal V2 = cast<DefinedSVal>(V2_untested);
+ DefinedSVal V2 = V2_untested.castAs<DefinedSVal>();
// Handle all other values.
BinaryOperator::Opcode Op = U->isIncrementOp() ? BO_Add : BO_Sub;
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index b3baa79..ed90dc5 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -11,13 +11,13 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Basic/PrettyStackTrace.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
using namespace clang;
using namespace ento;
@@ -30,23 +30,90 @@ void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME,
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, LCtx);
// If the value is already a CXXTempObjectRegion, it is fine as it is.
// Otherwise, create a new CXXTempObjectRegion, and copy the value into it.
+ // This is an optimization for when an rvalue is constructed and then
+ // immediately materialized.
const MemRegion *MR = V.getAsRegion();
- if (!MR || !isa<CXXTempObjectRegion>(MR)) {
- const MemRegion *R =
- svalBuilder.getRegionManager().getCXXTempObjectRegion(ME, LCtx);
+ if (const CXXTempObjectRegion *TR =
+ dyn_cast_or_null<CXXTempObjectRegion>(MR)) {
+ if (getContext().hasSameUnqualifiedType(TR->getValueType(), ME->getType()))
+ state = state->BindExpr(ME, LCtx, V);
+ }
+
+ if (state == Pred->getState())
+ state = createTemporaryRegionIfNeeded(state, LCtx, tempExpr, ME);
+ Bldr.generateNode(ME, Pred, state);
+}
+
+// FIXME: This is the sort of code that should eventually live in a Core
+// checker rather than as a special case in ExprEngine.
+void ExprEngine::performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred,
+ const CallEvent &Call) {
+ SVal ThisVal;
+ bool AlwaysReturnsLValue;
+ if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) {
+ assert(Ctor->getDecl()->isTrivial());
+ assert(Ctor->getDecl()->isCopyOrMoveConstructor());
+ ThisVal = Ctor->getCXXThisVal();
+ AlwaysReturnsLValue = false;
+ } else {
+ assert(cast<CXXMethodDecl>(Call.getDecl())->isTrivial());
+ assert(cast<CXXMethodDecl>(Call.getDecl())->getOverloadedOperator() ==
+ OO_Equal);
+ ThisVal = cast<CXXInstanceCall>(Call).getCXXThisVal();
+ AlwaysReturnsLValue = true;
+ }
- SVal L = loc::MemRegionVal(R);
- state = state->bindLoc(L, V);
- V = L;
+ const LocationContext *LCtx = Pred->getLocationContext();
+
+ ExplodedNodeSet Dst;
+ Bldr.takeNodes(Pred);
+
+ SVal V = Call.getArgSVal(0);
+
+ // If the value being copied is not unknown, load from its location to get
+ // an aggregate rvalue.
+ if (Optional<Loc> L = V.getAs<Loc>())
+ V = Pred->getState()->getSVal(*L);
+ else
+ assert(V.isUnknown());
+
+ const Expr *CallExpr = Call.getOriginExpr();
+ evalBind(Dst, CallExpr, Pred, ThisVal, V, true);
+
+ PostStmt PS(CallExpr, LCtx);
+ for (ExplodedNodeSet::iterator I = Dst.begin(), E = Dst.end();
+ I != E; ++I) {
+ ProgramStateRef State = (*I)->getState();
+ if (AlwaysReturnsLValue)
+ State = State->BindExpr(CallExpr, LCtx, ThisVal);
+ else
+ State = bindReturnValue(Call, LCtx, State);
+ Bldr.generateNode(PS, State, *I);
+ }
+}
+
+
+/// Returns a region representing the first element of a (possibly
+/// multi-dimensional) array.
+///
+/// On return, \p Ty will be set to the base type of the array.
+///
+/// If the type is not an array type at all, the original value is returned.
+static SVal makeZeroElementRegion(ProgramStateRef State, SVal LValue,
+ QualType &Ty) {
+ SValBuilder &SVB = State->getStateManager().getSValBuilder();
+ ASTContext &Ctx = SVB.getContext();
+
+ while (const ArrayType *AT = Ctx.getAsArrayType(Ty)) {
+ Ty = AT->getElementType();
+ LValue = State->getLValue(Ty, SVB.makeZeroArrayIndex(), LValue);
}
- Bldr.generateNode(ME, Pred, state->BindExpr(ME, LCtx, V));
+ return LValue;
}
void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
@@ -57,6 +124,10 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
const MemRegion *Target = 0;
+ // FIXME: Handle arrays, which run the same constructor for every element.
+ // For now, we just run the first constructor (which should still invalidate
+ // the entire array).
+
switch (CE->getConstructionKind()) {
case CXXConstructExpr::CK_Complete: {
// See if we're constructing an existing region by looking at the next
@@ -66,29 +137,21 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
CFGElement Next = (*B)[currStmtIdx+1];
// Is this a constructor for a local variable?
- if (const CFGStmt *StmtElem = dyn_cast<CFGStmt>(&Next)) {
+ if (Optional<CFGStmt> StmtElem = Next.getAs<CFGStmt>()) {
if (const DeclStmt *DS = dyn_cast<DeclStmt>(StmtElem->getStmt())) {
if (const VarDecl *Var = dyn_cast<VarDecl>(DS->getSingleDecl())) {
if (Var->getInit()->IgnoreImplicit() == CE) {
+ SVal LValue = State->getLValue(Var, LCtx);
QualType Ty = Var->getType();
- if (const ArrayType *AT = getContext().getAsArrayType(Ty)) {
- // FIXME: Handle arrays, which run the same constructor for
- // every element. This workaround will just run the first
- // constructor (which should still invalidate the entire array).
- SVal Base = State->getLValue(Var, LCtx);
- Target = State->getLValue(AT->getElementType(),
- getSValBuilder().makeZeroArrayIndex(),
- Base).getAsRegion();
- } else {
- Target = State->getLValue(Var, LCtx).getAsRegion();
- }
+ LValue = makeZeroElementRegion(State, LValue, Ty);
+ Target = LValue.getAsRegion();
}
}
}
}
// Is this a constructor for a member?
- if (const CFGInitializer *InitElem = dyn_cast<CFGInitializer>(&Next)) {
+ if (Optional<CFGInitializer> InitElem = Next.getAs<CFGInitializer>()) {
const CXXCtorInitializer *Init = InitElem->getInitializer();
assert(Init->isAnyMemberInitializer());
@@ -97,13 +160,19 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
LCtx->getCurrentStackFrame());
SVal ThisVal = State->getSVal(ThisPtr);
+ const ValueDecl *Field;
+ SVal FieldVal;
if (Init->isIndirectMemberInitializer()) {
- SVal Field = State->getLValue(Init->getIndirectMember(), ThisVal);
- Target = Field.getAsRegion();
+ Field = Init->getIndirectMember();
+ FieldVal = State->getLValue(Init->getIndirectMember(), ThisVal);
} else {
- SVal Field = State->getLValue(Init->getMember(), ThisVal);
- Target = Field.getAsRegion();
+ Field = Init->getMember();
+ FieldVal = State->getLValue(Init->getMember(), ThisVal);
}
+
+ QualType Ty = Field->getType();
+ FieldVal = makeZeroElementRegion(State, FieldVal, Ty);
+ Target = FieldVal.getAsRegion();
}
// FIXME: This will eventually need to handle new-expressions as well.
@@ -130,8 +199,10 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
Target = ThisVal.getAsRegion();
} else {
// Cast to the base type.
- QualType BaseTy = CE->getType();
- SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, BaseTy);
+ bool IsVirtual =
+ (CE->getConstructionKind() == CXXConstructExpr::CK_VirtualBase);
+ SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, CE->getType(),
+ IsVirtual);
Target = BaseVal.getAsRegion();
}
break;
@@ -148,14 +219,26 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
getCheckerManager().runCheckersForPreCall(DstPreCall, DstPreVisit,
*Call, *this);
- ExplodedNodeSet DstInvalidated;
- StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx);
- for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
- I != E; ++I)
- defaultEvalCall(Bldr, *I, *Call);
+ ExplodedNodeSet DstEvaluated;
+ StmtNodeBuilder Bldr(DstPreCall, DstEvaluated, *currBldrCtx);
+
+ bool IsArray = isa<ElementRegion>(Target);
+ if (CE->getConstructor()->isTrivial() &&
+ CE->getConstructor()->isCopyOrMoveConstructor() &&
+ !IsArray) {
+ // FIXME: Handle other kinds of trivial constructors as well.
+ for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
+ I != E; ++I)
+ performTrivialCopy(Bldr, *I, *Call);
+
+ } else {
+ for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
+ I != E; ++I)
+ defaultEvalCall(Bldr, *I, *Call);
+ }
ExplodedNodeSet DstPostCall;
- getCheckerManager().runCheckersForPostCall(DstPostCall, DstInvalidated,
+ getCheckerManager().runCheckersForPostCall(DstPostCall, DstEvaluated,
*Call, *this);
getCheckerManager().runCheckersForPostStmt(destNodes, DstPostCall, CE, *this);
}
@@ -172,11 +255,9 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType,
// FIXME: We need to run the same destructor on every element of the array.
// This workaround will just run the first destructor (which will still
// invalidate the entire array).
- if (const ArrayType *AT = getContext().getAsArrayType(ObjectType)) {
- ObjectType = AT->getElementType();
- Dest = State->getLValue(ObjectType, getSValBuilder().makeZeroArrayIndex(),
- loc::MemRegionVal(Dest)).getAsRegion();
- }
+ SVal DestVal = loc::MemRegionVal(Dest);
+ DestVal = makeZeroElementRegion(State, DestVal, ObjectType);
+ Dest = DestVal.getAsRegion();
const CXXRecordDecl *RecordDecl = ObjectType->getAsCXXRecordDecl();
assert(RecordDecl && "Only CXXRecordDecls should have destructors");
@@ -211,15 +292,35 @@ 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, *currBldrCtx);
unsigned blockCount = currBldrCtx->blockCount();
const LocationContext *LCtx = Pred->getLocationContext();
- DefinedOrUnknownSVal symVal = svalBuilder.conjureSymbolVal(0, CNE, LCtx,
- CNE->getType(),
- blockCount);
- ProgramStateRef State = Pred->getState();
+ DefinedOrUnknownSVal symVal = UnknownVal();
+ FunctionDecl *FD = CNE->getOperatorNew();
+
+ bool IsStandardGlobalOpNewFunction = false;
+ if (FD && !isa<CXXMethodDecl>(FD) && !FD->isVariadic()) {
+ if (FD->getNumParams() == 2) {
+ QualType T = FD->getParamDecl(1)->getType();
+ if (const IdentifierInfo *II = T.getBaseTypeIdentifier())
+ // NoThrow placement new behaves as a standard new.
+ IsStandardGlobalOpNewFunction = II->getName().equals("nothrow_t");
+ }
+ else
+ // Placement forms are considered non-standard.
+ IsStandardGlobalOpNewFunction = (FD->getNumParams() == 1);
+ }
+ // We assume all standard global 'operator new' functions allocate memory in
+ // heap. We realize this is an approximation that might not correctly model
+ // a custom global allocator.
+ if (IsStandardGlobalOpNewFunction)
+ symVal = svalBuilder.getConjuredHeapSymbolVal(CNE, LCtx, blockCount);
+ else
+ symVal = svalBuilder.conjureSymbolVal(0, CNE, LCtx, CNE->getType(),
+ blockCount);
+
+ ProgramStateRef State = Pred->getState();
CallEventManager &CEMgr = getStateManager().getCallEventManager();
CallEventRef<CXXAllocatorCall> Call =
CEMgr.getCXXAllocatorCall(CNE, State, LCtx);
@@ -228,12 +329,13 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
// FIXME: Once we figure out how we want allocators to work,
// we should be using the usual pre-/(default-)eval-/post-call checks here.
State = Call->invalidateRegions(blockCount);
+ if (!State)
+ return;
// If we're compiling with exceptions enabled, and this allocation function
// is not declared as non-throwing, failures /must/ be signalled by
// exceptions, and thus the return value will never be NULL.
// C++11 [basic.stc.dynamic.allocation]p3.
- FunctionDecl *FD = CNE->getOperatorNew();
if (FD && getContext().getLangOpts().CXXExceptions) {
QualType Ty = FD->getType();
if (const FunctionProtoType *ProtoType = Ty->getAs<FunctionProtoType>())
@@ -241,10 +343,12 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
State = State->assume(symVal, true);
}
+ StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
+
if (CNE->isArray()) {
// FIXME: allocating an array requires simulating the constructors.
// For now, just return a symbolicated region.
- const MemRegion *NewReg = cast<loc::MemRegionVal>(symVal).getRegion();
+ const MemRegion *NewReg = symVal.castAs<loc::MemRegionVal>().getRegion();
QualType ObjTy = CNE->getType()->getAs<PointerType>()->getPointeeType();
const ElementRegion *EleReg =
getStoreManager().GetElementZeroRegion(NewReg, ObjTy);
@@ -258,30 +362,32 @@ 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.)
+ SVal Result = symVal;
if (FD && FD->isReservedGlobalPlacementOperator()) {
// Non-array placement new should always return the placement location.
SVal PlacementLoc = State->getSVal(CNE->getPlacementArg(0), LCtx);
- SVal Result = svalBuilder.evalCast(PlacementLoc, CNE->getType(),
- CNE->getPlacementArg(0)->getType());
- State = State->BindExpr(CNE, LCtx, Result);
- } else {
- State = State->BindExpr(CNE, LCtx, symVal);
+ Result = svalBuilder.evalCast(PlacementLoc, CNE->getType(),
+ CNE->getPlacementArg(0)->getType());
}
+ // Bind the address of the object, then check to see if we cached out.
+ State = State->BindExpr(CNE, LCtx, Result);
+ ExplodedNode *NewN = Bldr.generateNode(CNE, Pred, State);
+ if (!NewN)
+ return;
+
// If the type is not a record, we won't have a CXXConstructExpr as an
// initializer. Copy the value over.
if (const Expr *Init = CNE->getInitializer()) {
if (!isa<CXXConstructExpr>(Init)) {
- QualType ObjTy = CNE->getType()->getAs<PointerType>()->getPointeeType();
- (void)ObjTy;
- assert(!ObjTy->isRecordType());
- SVal Location = State->getSVal(CNE, LCtx);
- if (isa<Loc>(Location))
- State = State->bindLoc(cast<Loc>(Location), State->getSVal(Init, LCtx));
+ assert(Bldr.getResults().size() == 1);
+ Bldr.takeNodes(NewN);
+
+ assert(!CNE->getType()->getPointeeCXXRecordDecl());
+ evalBind(Dst, CNE, NewN, Result, State->getSVal(Init, LCtx),
+ /*FirstInit=*/IsStandardGlobalOpNewFunction);
}
}
-
- Bldr.generateNode(CNE, Pred, State);
}
void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE,
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 3ead081..f01e4e7 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -13,13 +13,13 @@
#define DEBUG_TYPE "ExprEngine"
-#include "clang/Analysis/Analyses/LiveVariables.h"
-#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 "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/SaveAndRestore.h"
@@ -33,6 +33,9 @@ STATISTIC(NumOfDynamicDispatchPathSplits,
STATISTIC(NumInlinedCalls,
"The # of times we inlined a call");
+STATISTIC(NumReachedInlineCountMax,
+ "The # of times we reached inline count maximum");
+
void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) {
// Get the entry block in the CFG of the callee.
const StackFrameContext *calleeCtx = CE.getCalleeContext();
@@ -64,6 +67,7 @@ void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) {
static std::pair<const Stmt*,
const CFGBlock*> getLastStmt(const ExplodedNode *Node) {
const Stmt *S = 0;
+ const CFGBlock *Blk = 0;
const StackFrameContext *SF =
Node->getLocation().getLocationContext()->getCurrentStackFrame();
@@ -73,10 +77,10 @@ static std::pair<const Stmt*,
const ProgramPoint &PP = Node->getLocation();
if (PP.getLocationContext()->getCurrentStackFrame() == SF) {
- if (const StmtPoint *SP = dyn_cast<StmtPoint>(&PP)) {
+ if (Optional<StmtPoint> SP = PP.getAs<StmtPoint>()) {
S = SP->getStmt();
break;
- } else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&PP)) {
+ } else if (Optional<CallExitEnd> CEE = PP.getAs<CallExitEnd>()) {
S = CEE->getCalleeContext()->getCallSite();
if (S)
break;
@@ -84,15 +88,17 @@ static std::pair<const Stmt*,
// 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;
+ Optional<CallEnter> CE;
do {
Node = Node->getFirstPred();
CE = Node->getLocationAs<CallEnter>();
} while (!CE || CE->getCalleeContext() != CEE->getCalleeContext());
// Continue searching the graph.
+ } else if (Optional<BlockEdge> BE = PP.getAs<BlockEdge>()) {
+ Blk = BE->getSrc();
}
- } else if (const CallEnter *CE = dyn_cast<CallEnter>(&PP)) {
+ } else if (Optional<CallEnter> CE = PP.getAs<CallEnter>()) {
// If we reached the CallEnter for this function, it has no statements.
if (CE->getCalleeContext() == SF)
break;
@@ -104,24 +110,6 @@ static std::pair<const Stmt*,
Node = *Node->pred_begin();
}
- const CFGBlock *Blk = 0;
- if (S) {
- // Now, get the enclosing basic block.
- while (Node) {
- const ProgramPoint &PP = Node->getLocation();
- if (isa<BlockEdge>(PP) &&
- (PP.getLocationContext()->getCurrentStackFrame() == SF)) {
- BlockEdge &EPP = cast<BlockEdge>(PP);
- Blk = EPP.getDst();
- break;
- }
- if (Node->pred_empty())
- return std::pair<const Stmt*, const CFGBlock*>(S, (CFGBlock*)0);
-
- Node = *Node->pred_begin();
- }
- }
-
return std::pair<const Stmt*, const CFGBlock*>(S, Blk);
}
@@ -133,7 +121,7 @@ static std::pair<const Stmt*,
static SVal adjustReturnValue(SVal V, QualType ExpectedTy, QualType ActualTy,
StoreManager &StoreMgr) {
// For now, the only adjustments we handle apply only to locations.
- if (!isa<Loc>(V))
+ if (!V.getAs<Loc>())
return V;
// If the types already match, don't do any unnecessary work.
@@ -168,27 +156,25 @@ static SVal adjustReturnValue(SVal V, QualType ExpectedTy, QualType ActualTy,
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) {
+ Dst.Add(Pred);
return;
}
-
- // If the last statement is return, everything it references should stay live.
- if (isa<ReturnStmt>(LastSt))
- return;
- // Here, we call the Symbol Reaper with 0 stack context telling it to clean up
- // everything on the stack. We use LastStmt as a diagnostic statement, with
- // which the PreStmtPurgeDead point will be associated.
- currBldrCtx = &BC;
- removeDead(Pred, Dst, 0, 0, LastSt,
+ // Here, we destroy the current location context. We use the current
+ // function's entire body as a diagnostic statement, with which the program
+ // point will be associated. However, we only want to use LastStmt as a
+ // reference for what to clean up if it's a ReturnStmt; otherwise, everything
+ // is dead.
+ SaveAndRestore<const NodeBuilderContext *> NodeContextRAII(currBldrCtx, &BC);
+ const LocationContext *LCtx = Pred->getLocationContext();
+ removeDead(Pred, Dst, dyn_cast<ReturnStmt>(LastSt), LCtx,
+ LCtx->getAnalysisDeclContext()->getBody(),
ProgramPoint::PostStmtPurgeDeadSymbolsKind);
- currBldrCtx = 0;
}
static bool wasDifferentDeclUsedForInlining(CallEventRef<> Call,
@@ -201,6 +187,23 @@ static bool wasDifferentDeclUsedForInlining(CallEventRef<> Call,
return RuntimeCallee->getCanonicalDecl() != StaticDecl->getCanonicalDecl();
}
+/// Returns true if the CXXConstructExpr \p E was intended to construct a
+/// prvalue for the region in \p V.
+///
+/// Note that we can't just test for rvalue vs. glvalue because
+/// CXXConstructExprs embedded in DeclStmts and initializers are considered
+/// rvalues by the AST, and the analyzer would like to treat them as lvalues.
+static bool isTemporaryPRValue(const CXXConstructExpr *E, SVal V) {
+ if (E->isGLValue())
+ return false;
+
+ const MemRegion *MR = V.getAsRegion();
+ if (!MR)
+ return false;
+
+ return isa<CXXTempObjectRegion>(MR);
+}
+
/// 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:
@@ -261,13 +264,9 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
svalBuilder.getCXXThis(CCE->getConstructor()->getParent(), calleeCtx);
SVal ThisV = state->getSVal(This);
- // If the constructed object is a prvalue, get its bindings.
- // Note that we have to be careful here because constructors embedded
- // in DeclStmts are not marked as lvalues.
- if (!CCE->isGLValue())
- if (const MemRegion *MR = ThisV.getAsRegion())
- if (isa<CXXTempObjectRegion>(MR))
- ThisV = state->getSVal(cast<Loc>(ThisV));
+ // If the constructed object is a temporary prvalue, get its bindings.
+ if (isTemporaryPRValue(CCE, ThisV))
+ ThisV = state->getSVal(ThisV.castAs<Loc>());
state = state->BindExpr(CCE, callerCtx, ThisV);
}
@@ -290,11 +289,12 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
NodeBuilderContext Ctx(getCoreEngine(), Blk, BindedRetNode);
currBldrCtx = &Ctx;
- // Here, we call the Symbol Reaper with 0 statement and caller location
+ // Here, we call the Symbol Reaper with 0 statement and callee 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,
+ // (and its children). We use the callee's function body as a diagnostic
+ // statement, with which the program point will be associated.
+ removeDead(BindedRetNode, CleanedNodes, 0, calleeCtx,
+ calleeCtx->getAnalysisDeclContext()->getBody(),
ProgramPoint::PostStmtPurgeDeadSymbolsKind);
currBldrCtx = 0;
} else {
@@ -394,63 +394,6 @@ static bool IsInStdNamespace(const FunctionDecl *FD) {
return ND->getName() == "std";
}
-// Determine if we should inline the call.
-bool ExprEngine::shouldInlineDecl(const Decl *D, ExplodedNode *Pred) {
- AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(D);
- const CFG *CalleeCFG = CalleeADC->getCFG();
-
- // It is possible that the CFG cannot be constructed.
- // Be safe, and check if the CalleeCFG is valid.
- if (!CalleeCFG)
- return false;
-
- 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.options.InlineMaxFunctionSize)
- return false;
-
- // Do not inline variadic calls (for now).
- if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
- if (BD->isVariadic())
- return false;
- }
- else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- if (FD->isVariadic())
- return false;
- }
-
- if (getContext().getLangOpts().CPlusPlus) {
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- // Conditionally allow the inlining of template functions.
- if (!getAnalysisManager().options.mayInlineTemplateFunctions())
- if (FD->getTemplatedKind() != FunctionDecl::TK_NonTemplate)
- return false;
-
- // Conditionally allow the inlining of C++ standard library functions.
- if (!getAnalysisManager().options.mayInlineCXXStandardLibrary())
- if (getContext().getSourceManager().isInSystemHeader(FD->getLocation()))
- if (IsInStdNamespace(FD))
- return false;
- }
- }
-
- // It is possible that the live variables analysis cannot be
- // run. If so, bail out.
- if (!CalleeADC->getAnalysis<RelaxedLiveVariables>())
- return false;
-
- 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
@@ -474,107 +417,16 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
const LocationContext *CurLC = Pred->getLocationContext();
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 (!Opts.mayInlineCXXMemberFunction(CIMK_MemberFunctions))
- return false;
- break;
- case CE_CXXConstructor: {
- if (!Opts.mayInlineCXXMemberFunction(CIMK_Constructors))
- return false;
-
- const CXXConstructorCall &Ctor = cast<CXXConstructorCall>(Call);
-
- // FIXME: We don't handle constructors or destructors for arrays properly.
- const MemRegion *Target = Ctor.getCXXThisVal().getAsRegion();
- if (Target && isa<ElementRegion>(Target))
- return false;
-
- // FIXME: This is a hack. We don't use the correct region for a new
- // expression, so if we inline the constructor its result will just be
- // thrown away. This short-term hack is tracked in <rdar://problem/12180598>
- // and the longer-term possible fix is discussed in PR12014.
- const CXXConstructExpr *CtorExpr = Ctor.getOriginExpr();
- if (const Stmt *Parent = CurLC->getParentMap().getParent(CtorExpr))
- if (isa<CXXNewExpr>(Parent))
- return false;
-
- // Inlining constructors requires including initializers in the CFG.
- const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext();
- assert(ADC->getCFGBuildOptions().AddInitializers && "No CFG initializers");
- (void)ADC;
-
- // If the destructor is trivial, it's always safe to inline the constructor.
- if (Ctor.getDecl()->getParent()->hasTrivialDestructor())
- break;
-
- // For other types, only inline constructors if destructor inlining is
- // also enabled.
- if (!Opts.mayInlineCXXMemberFunction(CIMK_Destructors))
- return false;
-
- // FIXME: This is a hack. We don't handle temporary destructors
- // right now, so we shouldn't inline their constructors.
- if (CtorExpr->getConstructionKind() == CXXConstructExpr::CK_Complete)
- if (!Target || !isa<DeclRegion>(Target))
- return false;
-
- break;
- }
- case CE_CXXDestructor: {
- if (!Opts.mayInlineCXXMemberFunction(CIMK_Destructors))
- return false;
-
- // Inlining destructors requires building the CFG correctly.
- const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext();
- assert(ADC->getCFGBuildOptions().AddImplicitDtors && "No CFG destructors");
- (void)ADC;
-
- const CXXDestructorCall &Dtor = cast<CXXDestructorCall>(Call);
-
- // FIXME: We don't handle constructors or destructors for arrays properly.
- const MemRegion *Target = Dtor.getCXXThisVal().getAsRegion();
- if (Target && isa<ElementRegion>(Target))
- return false;
-
- break;
- }
- case CE_CXXAllocator:
- // Do not inline allocators until we model deallocators.
- // This is unfortunate, but basically necessary for smart pointers and such.
- return false;
- case CE_Block: {
+ const LocationContext *ParentOfCallee = CallerSFC;
+ if (Call.getKind() == CE_Block) {
const BlockDataRegion *BR = cast<BlockCall>(Call).getBlockRegion();
assert(BR && "If we have the block definition we should have its region");
AnalysisDeclContext *BlockCtx = AMgr.getAnalysisDeclContext(D);
ParentOfCallee = BlockCtx->getBlockInvocationContext(CallerSFC,
cast<BlockDecl>(D),
BR);
- break;
- }
- case CE_ObjCMessage:
- if (!Opts.mayInlineObjCMethod())
- return false;
- if (!(getAnalysisManager().options.IPAMode == DynamicDispatch ||
- getAnalysisManager().options.IPAMode == DynamicDispatchBifurcate))
- return false;
- break;
}
-
- if (!shouldInlineDecl(D, Pred))
- return false;
- if (!ParentOfCallee)
- ParentOfCallee = CallerSFC;
-
// This may be NULL, but that's fine.
const Expr *CallE = Call.getOriginExpr();
@@ -585,6 +437,7 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
currBldrCtx->getBlock(),
currStmtIdx);
+
CallEnter Loc(CallE, CalleeSFC, CurLC);
// Construct a new state which contains the mapping from actual to
@@ -613,11 +466,11 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
static ProgramStateRef getInlineFailedState(ProgramStateRef State,
const Stmt *CallE) {
- void *ReplayState = State->get<ReplayWithoutInlining>();
+ const void *ReplayState = State->get<ReplayWithoutInlining>();
if (!ReplayState)
return 0;
- assert(ReplayState == (const void*)CallE && "Backtracked to the wrong call.");
+ assert(ReplayState == CallE && "Backtracked to the wrong call.");
(void)CallE;
return State->remove<ReplayWithoutInlining>();
@@ -696,7 +549,13 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call,
}
}
} else if (const CXXConstructorCall *C = dyn_cast<CXXConstructorCall>(&Call)){
- return State->BindExpr(E, LCtx, C->getCXXThisVal());
+ SVal ThisV = C->getCXXThisVal();
+
+ // If the constructed object is a temporary prvalue, get its bindings.
+ if (isTemporaryPRValue(cast<CXXConstructExpr>(E), ThisV))
+ ThisV = State->getSVal(ThisV.castAs<Loc>());
+
+ return State->BindExpr(E, LCtx, ThisV);
}
// Conjure a symbol if the return value is unknown.
@@ -710,7 +569,8 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call,
// Conservatively evaluate call by invalidating regions and binding
// a conjured return value.
void ExprEngine::conservativeEvalCall(const CallEvent &Call, NodeBuilder &Bldr,
- ExplodedNode *Pred, ProgramStateRef State) {
+ ExplodedNode *Pred,
+ ProgramStateRef State) {
State = Call.invalidateRegions(currBldrCtx->blockCount(), State);
State = bindReturnValue(Call, Pred->getLocationContext(), State);
@@ -718,38 +578,332 @@ void ExprEngine::conservativeEvalCall(const CallEvent &Call, NodeBuilder &Bldr,
Bldr.generateNode(Call.getProgramPoint(), State, Pred);
}
+enum CallInlinePolicy {
+ CIP_Allowed,
+ CIP_DisallowedOnce,
+ CIP_DisallowedAlways
+};
+
+static CallInlinePolicy mayInlineCallKind(const CallEvent &Call,
+ const ExplodedNode *Pred,
+ AnalyzerOptions &Opts) {
+ const LocationContext *CurLC = Pred->getLocationContext();
+ const StackFrameContext *CallerSFC = CurLC->getCurrentStackFrame();
+ switch (Call.getKind()) {
+ case CE_Function:
+ case CE_Block:
+ break;
+ case CE_CXXMember:
+ case CE_CXXMemberOperator:
+ if (!Opts.mayInlineCXXMemberFunction(CIMK_MemberFunctions))
+ return CIP_DisallowedAlways;
+ break;
+ case CE_CXXConstructor: {
+ if (!Opts.mayInlineCXXMemberFunction(CIMK_Constructors))
+ return CIP_DisallowedAlways;
+
+ const CXXConstructorCall &Ctor = cast<CXXConstructorCall>(Call);
+
+ // FIXME: We don't handle constructors or destructors for arrays properly.
+ // Even once we do, we still need to be careful about implicitly-generated
+ // initializers for array fields in default move/copy constructors.
+ const MemRegion *Target = Ctor.getCXXThisVal().getAsRegion();
+ if (Target && isa<ElementRegion>(Target))
+ return CIP_DisallowedOnce;
+
+ // FIXME: This is a hack. We don't use the correct region for a new
+ // expression, so if we inline the constructor its result will just be
+ // thrown away. This short-term hack is tracked in <rdar://problem/12180598>
+ // and the longer-term possible fix is discussed in PR12014.
+ const CXXConstructExpr *CtorExpr = Ctor.getOriginExpr();
+ if (const Stmt *Parent = CurLC->getParentMap().getParent(CtorExpr))
+ if (isa<CXXNewExpr>(Parent))
+ return CIP_DisallowedOnce;
+
+ // 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 CIP_DisallowedAlways;
+
+ // FIXME: This is a hack. We don't handle temporary destructors
+ // right now, so we shouldn't inline their constructors.
+ if (CtorExpr->getConstructionKind() == CXXConstructExpr::CK_Complete)
+ if (!Target || !isa<DeclRegion>(Target))
+ return CIP_DisallowedOnce;
+
+ break;
+ }
+ case CE_CXXDestructor: {
+ if (!Opts.mayInlineCXXMemberFunction(CIMK_Destructors))
+ return CIP_DisallowedAlways;
+
+ // Inlining destructors requires building the CFG correctly.
+ const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext();
+ assert(ADC->getCFGBuildOptions().AddImplicitDtors && "No CFG destructors");
+ (void)ADC;
+
+ const CXXDestructorCall &Dtor = cast<CXXDestructorCall>(Call);
+
+ // FIXME: We don't handle constructors or destructors for arrays properly.
+ const MemRegion *Target = Dtor.getCXXThisVal().getAsRegion();
+ if (Target && isa<ElementRegion>(Target))
+ return CIP_DisallowedOnce;
+
+ break;
+ }
+ case CE_CXXAllocator:
+ // Do not inline allocators until we model deallocators.
+ // This is unfortunate, but basically necessary for smart pointers and such.
+ return CIP_DisallowedAlways;
+ case CE_ObjCMessage:
+ if (!Opts.mayInlineObjCMethod())
+ return CIP_DisallowedAlways;
+ if (!(Opts.getIPAMode() == IPAK_DynamicDispatch ||
+ Opts.getIPAMode() == IPAK_DynamicDispatchBifurcate))
+ return CIP_DisallowedAlways;
+ break;
+ }
+
+ return CIP_Allowed;
+}
+
+/// Returns true if the given C++ class is a container.
+///
+/// Our heuristic for this is whether it contains a method named 'begin()' or a
+/// nested type named 'iterator'.
+static bool isContainerClass(const ASTContext &Ctx, const CXXRecordDecl *RD) {
+ // Don't record any path information.
+ CXXBasePaths Paths(false, false, false);
+
+ const IdentifierInfo &BeginII = Ctx.Idents.get("begin");
+ DeclarationName BeginName = Ctx.DeclarationNames.getIdentifier(&BeginII);
+ DeclContext::lookup_const_result BeginDecls = RD->lookup(BeginName);
+ if (!BeginDecls.empty())
+ return true;
+ if (RD->lookupInBases(&CXXRecordDecl::FindOrdinaryMember,
+ BeginName.getAsOpaquePtr(),
+ Paths))
+ return true;
+
+ const IdentifierInfo &IterII = Ctx.Idents.get("iterator");
+ DeclarationName IteratorName = Ctx.DeclarationNames.getIdentifier(&IterII);
+ DeclContext::lookup_const_result IterDecls = RD->lookup(IteratorName);
+ if (!IterDecls.empty())
+ return true;
+ if (RD->lookupInBases(&CXXRecordDecl::FindOrdinaryMember,
+ IteratorName.getAsOpaquePtr(),
+ Paths))
+ return true;
+
+ return false;
+}
+
+/// Returns true if the given function refers to a constructor or destructor of
+/// a C++ container.
+///
+/// We generally do a poor job modeling most containers right now, and would
+/// prefer not to inline their methods.
+static bool isContainerCtorOrDtor(const ASTContext &Ctx,
+ const FunctionDecl *FD) {
+ // Heuristic: a type is a container if it contains a "begin()" method
+ // or a type named "iterator".
+ if (!(isa<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD)))
+ return false;
+
+ const CXXRecordDecl *RD = cast<CXXMethodDecl>(FD)->getParent();
+ return isContainerClass(Ctx, RD);
+}
+
+/// Returns true if the function in \p CalleeADC may be inlined in general.
+///
+/// This checks static properties of the function, such as its signature and
+/// CFG, to determine whether the analyzer should ever consider inlining it,
+/// in any context.
+static bool mayInlineDecl(const CallEvent &Call, AnalysisDeclContext *CalleeADC,
+ AnalyzerOptions &Opts) {
+ // FIXME: Do not inline variadic calls.
+ if (Call.isVariadic())
+ return false;
+
+ // Check certain C++-related inlining policies.
+ ASTContext &Ctx = CalleeADC->getASTContext();
+ if (Ctx.getLangOpts().CPlusPlus) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CalleeADC->getDecl())) {
+ // Conditionally control the inlining of template functions.
+ if (!Opts.mayInlineTemplateFunctions())
+ if (FD->getTemplatedKind() != FunctionDecl::TK_NonTemplate)
+ return false;
+
+ // Conditionally control the inlining of C++ standard library functions.
+ if (!Opts.mayInlineCXXStandardLibrary())
+ if (Ctx.getSourceManager().isInSystemHeader(FD->getLocation()))
+ if (IsInStdNamespace(FD))
+ return false;
+
+ // Conditionally control the inlining of methods on objects that look
+ // like C++ containers.
+ if (!Opts.mayInlineCXXContainerCtorsAndDtors())
+ if (!Ctx.getSourceManager().isFromMainFile(FD->getLocation()))
+ if (isContainerCtorOrDtor(Ctx, FD))
+ return false;
+ }
+ }
+
+ // It is possible that the CFG cannot be constructed.
+ // Be safe, and check if the CalleeCFG is valid.
+ const CFG *CalleeCFG = CalleeADC->getCFG();
+ if (!CalleeCFG)
+ return false;
+
+ // Do not inline large functions.
+ if (CalleeCFG->getNumBlockIDs() > Opts.getMaxInlinableSize())
+ return false;
+
+ // It is possible that the live variables analysis cannot be
+ // run. If so, bail out.
+ if (!CalleeADC->getAnalysis<RelaxedLiveVariables>())
+ return false;
+
+ return true;
+}
+
+bool ExprEngine::shouldInlineCall(const CallEvent &Call, const Decl *D,
+ const ExplodedNode *Pred) {
+ if (!D)
+ return false;
+
+ AnalysisManager &AMgr = getAnalysisManager();
+ AnalyzerOptions &Opts = AMgr.options;
+ AnalysisDeclContextManager &ADCMgr = AMgr.getAnalysisDeclContextManager();
+ AnalysisDeclContext *CalleeADC = ADCMgr.getContext(D);
+
+ // The auto-synthesized bodies are essential to inline as they are
+ // usually small and commonly used. Note: we should do this check early on to
+ // ensure we always inline these calls.
+ if (CalleeADC->isBodyAutosynthesized())
+ return true;
+
+ if (!AMgr.shouldInlineCall())
+ return false;
+
+ // Check if this function has been marked as non-inlinable.
+ Optional<bool> MayInline = Engine.FunctionSummaries->mayInline(D);
+ if (MayInline.hasValue()) {
+ if (!MayInline.getValue())
+ return false;
+
+ } else {
+ // We haven't actually checked the static properties of this function yet.
+ // Do that now, and record our decision in the function summaries.
+ if (mayInlineDecl(Call, CalleeADC, Opts)) {
+ Engine.FunctionSummaries->markMayInline(D);
+ } else {
+ Engine.FunctionSummaries->markShouldNotInline(D);
+ return false;
+ }
+ }
+
+ // Check if we should inline a call based on its kind.
+ // FIXME: this checks both static and dynamic properties of the call, which
+ // means we're redoing a bit of work that could be cached in the function
+ // summary.
+ CallInlinePolicy CIP = mayInlineCallKind(Call, Pred, Opts);
+ if (CIP != CIP_Allowed) {
+ if (CIP == CIP_DisallowedAlways) {
+ assert(!MayInline.hasValue() || MayInline.getValue());
+ Engine.FunctionSummaries->markShouldNotInline(D);
+ }
+ return false;
+ }
+
+ const CFG *CalleeCFG = CalleeADC->getCFG();
+
+ // Do not inline if recursive or we've reached max stack frame count.
+ bool IsRecursive = false;
+ unsigned StackDepth = 0;
+ examineStackFrames(D, Pred->getLocationContext(), IsRecursive, StackDepth);
+ if ((StackDepth >= Opts.InlineMaxStackDepth) &&
+ ((CalleeCFG->getNumBlockIDs() > Opts.getAlwaysInlineSize())
+ || IsRecursive))
+ return false;
+
+ // Do not inline large functions too many times.
+ if ((Engine.FunctionSummaries->getNumTimesInlined(D) >
+ Opts.getMaxTimesInlineLarge()) &&
+ CalleeCFG->getNumBlockIDs() > 13) {
+ NumReachedInlineCountMax++;
+ return false;
+ }
+
+ if (HowToInline == Inline_Minimal &&
+ (CalleeCFG->getNumBlockIDs() > Opts.getAlwaysInlineSize()
+ || IsRecursive))
+ return false;
+
+ Engine.FunctionSummaries->bumpNumTimesInlined(D);
+
+ return true;
+}
+
+static bool isTrivialObjectAssignment(const CallEvent &Call) {
+ const CXXInstanceCall *ICall = dyn_cast<CXXInstanceCall>(&Call);
+ if (!ICall)
+ return false;
+
+ const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(ICall->getDecl());
+ if (!MD)
+ return false;
+ if (!(MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()))
+ return false;
+
+ return MD->isTrivial();
+}
+
void ExprEngine::defaultEvalCall(NodeBuilder &Bldr, ExplodedNode *Pred,
const CallEvent &CallTemplate) {
// Make sure we have the most recent state attached to the call.
ProgramStateRef State = Pred->getState();
CallEventRef<> Call = CallTemplate.cloneWithState(State);
- if (!getAnalysisManager().shouldInlineCall()) {
- conservativeEvalCall(*Call, Bldr, Pred, State);
+ // Special-case trivial assignment operators.
+ if (isTrivialObjectAssignment(*Call)) {
+ performTrivialCopy(Bldr, Pred, *Call);
return;
}
+
// Try to inline the call.
// The origin expression here is just used as a kind of checksum;
// this should still be safe even for CallEvents that don't come from exprs.
const Expr *E = Call->getOriginExpr();
- ProgramStateRef InlinedFailedState = getInlineFailedState(State, E);
+ ProgramStateRef InlinedFailedState = getInlineFailedState(State, E);
if (InlinedFailedState) {
// If we already tried once and failed, make sure we don't retry later.
State = InlinedFailedState;
} else {
RuntimeDefinition RD = Call->getRuntimeDefinition();
const Decl *D = RD.getDecl();
- if (D) {
+ if (shouldInlineCall(*Call, D, Pred)) {
if (RD.mayHaveOtherDefinitions()) {
+ AnalyzerOptions &Options = getAnalysisManager().options;
+
// Explore with and without inlining the call.
- if (getAnalysisManager().options.IPAMode == DynamicDispatchBifurcate) {
+ if (Options.getIPAMode() == IPAK_DynamicDispatchBifurcate) {
BifurcateCall(RD.getDispatchRegion(), *Call, D, Bldr, Pred);
return;
}
// Don't inline if we're not in any dynamic dispatch mode.
- if (getAnalysisManager().options.IPAMode != DynamicDispatch) {
+ if (Options.getIPAMode() != IPAK_DynamicDispatch) {
conservativeEvalCall(*Call, Bldr, Pred, State);
return;
}
diff --git a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
index 51dda19b..d276d92 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
@@ -103,8 +103,8 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
// Handle the case where the container has no elements.
SVal FalseV = svalBuilder.makeTruthVal(0);
ProgramStateRef noElems = state->BindExpr(S, LCtx, FalseV);
-
- if (loc::MemRegionVal *MV = dyn_cast<loc::MemRegionVal>(&elementV))
+
+ if (Optional<loc::MemRegionVal> MV = elementV.getAs<loc::MemRegionVal>())
if (const TypedValueRegion *R =
dyn_cast<TypedValueRegion>(MV->getRegion())) {
// FIXME: The proper thing to do is to really iterate over the
@@ -161,8 +161,9 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
SVal recVal = UpdatedMsg->getReceiverSVal();
if (!recVal.isUndef()) {
// Bifurcate the state into nil and non-nil ones.
- DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
-
+ DefinedOrUnknownSVal receiverVal =
+ recVal.castAs<DefinedOrUnknownSVal>();
+
ProgramStateRef notNilState, nilState;
llvm::tie(notNilState, nilState) = State->assume(receiverVal);
@@ -179,13 +180,13 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
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, State);
+ Bldr.generateSink(ME, Pred, State);
continue;
}
// Generate a transition to non-Nil state.
if (notNilState != State) {
- Pred = Bldr.generateNode(currStmt, Pred, notNilState);
+ Pred = Bldr.generateNode(ME, Pred, notNilState);
assert(Pred && "Should have cached out already!");
}
}
@@ -195,7 +196,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
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());
+ Bldr.generateSink(ME, Pred, Pred->getState());
continue;
}
}
diff --git a/lib/StaticAnalyzer/Core/FunctionSummary.cpp b/lib/StaticAnalyzer/Core/FunctionSummary.cpp
index c227aac..c21735b 100644
--- a/lib/StaticAnalyzer/Core/FunctionSummary.cpp
+++ b/lib/StaticAnalyzer/Core/FunctionSummary.cpp
@@ -1,4 +1,4 @@
-//== FunctionSummary.h - Stores summaries of functions. ------------*- C++ -*-//
+//== FunctionSummary.cpp - Stores summaries of functions. ----------*- C++ -*-//
//
// The LLVM Compiler Infrastructure
//
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines a summary of a function gathered/used by static analyzes.
+// This file defines a summary of a function gathered/used by static analysis.
//
//===----------------------------------------------------------------------===//
@@ -15,16 +15,10 @@
using namespace clang;
using namespace ento;
-FunctionSummariesTy::~FunctionSummariesTy() {
- for (MapTy::iterator I = Map.begin(), E = Map.end(); I != E; ++I) {
- delete(I->second);
- }
-}
-
unsigned FunctionSummariesTy::getTotalNumBasicBlocks() {
unsigned Total = 0;
for (MapTy::iterator I = Map.begin(), E = Map.end(); I != E; ++I) {
- Total += I->second->TotalBasicBlocks;
+ Total += I->second.TotalBasicBlocks;
}
return Total;
}
@@ -32,7 +26,7 @@ unsigned FunctionSummariesTy::getTotalNumBasicBlocks() {
unsigned FunctionSummariesTy::getTotalNumVisitedBasicBlocks() {
unsigned Total = 0;
for (MapTy::iterator I = Map.begin(), E = Map.end(); I != E; ++I) {
- Total += I->second->VisitedBasicBlocks.count();
+ Total += I->second.VisitedBasicBlocks.count();
}
return Total;
}
diff --git a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
index fd875f6..73426da 100644
--- a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
@@ -12,19 +12,19 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
-#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
-#include "clang/Rewrite/Core/Rewriter.h"
-#include "clang/Rewrite/Core/HTMLRewrite.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Rewrite/Core/HTMLRewrite.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -76,7 +76,8 @@ HTMLDiagnostics::HTMLDiagnostics(const std::string& prefix,
FilePrefix.appendComponent("report");
}
-void ento::createHTMLDiagnosticConsumer(PathDiagnosticConsumers &C,
+void ento::createHTMLDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
+ PathDiagnosticConsumers &C,
const std::string& prefix,
const Preprocessor &PP) {
C.push_back(new HTMLDiagnostics(prefix, PP));
diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp
index fab10cf..b3a1e65 100644
--- a/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ b/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -14,13 +14,14 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
-#include "clang/Analysis/AnalysisContext.h"
-#include "clang/Analysis/Support/BumpVector.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/RecordLayout.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Analysis/Support/BumpVector.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -194,6 +195,10 @@ DefinedOrUnknownSVal TypedValueRegion::getExtent(SValBuilder &svalBuilder) const
}
DefinedOrUnknownSVal FieldRegion::getExtent(SValBuilder &svalBuilder) const {
+ // Force callers to deal with bitfields explicitly.
+ if (getDecl()->isBitField())
+ return UnknownVal();
+
DefinedOrUnknownSVal Extent = DeclRegion::getExtent(svalBuilder);
// A zero-length array at the end of a struct often stands for dynamically-
@@ -233,7 +238,7 @@ QualType ObjCIvarRegion::getValueType() const {
}
QualType CXXBaseObjectRegion::getValueType() const {
- return QualType(decl->getTypeForDecl(), 0);
+ return QualType(getDecl()->getTypeForDecl(), 0);
}
//===----------------------------------------------------------------------===//
@@ -272,10 +277,11 @@ void ObjCStringRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
void AllocaRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
const Expr *Ex, unsigned cnt,
- const MemRegion *) {
+ const MemRegion *superRegion) {
ID.AddInteger((unsigned) AllocaRegionKind);
ID.AddPointer(Ex);
ID.AddInteger(cnt);
+ ID.AddPointer(superRegion);
}
void AllocaRegion::Profile(llvm::FoldingSetNodeID& ID) const {
@@ -400,14 +406,16 @@ void CXXTempObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const {
}
void CXXBaseObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
- const CXXRecordDecl *decl,
- const MemRegion *sReg) {
- ID.AddPointer(decl);
- ID.AddPointer(sReg);
+ const CXXRecordDecl *RD,
+ bool IsVirtual,
+ const MemRegion *SReg) {
+ ID.AddPointer(RD);
+ ID.AddBoolean(IsVirtual);
+ ID.AddPointer(SReg);
}
void CXXBaseObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const {
- ProfileRegion(ID, decl, superRegion);
+ ProfileRegion(ID, getDecl(), isVirtual(), superRegion);
}
//===----------------------------------------------------------------------===//
@@ -470,7 +478,7 @@ void CXXTempObjectRegion::dumpToStream(raw_ostream &os) const {
}
void CXXBaseObjectRegion::dumpToStream(raw_ostream &os) const {
- os << "base{" << superRegion << ',' << decl->getName() << '}';
+ os << "base{" << superRegion << ',' << getDecl()->getName() << '}';
}
void CXXThisRegion::dumpToStream(raw_ostream &os) const {
@@ -562,6 +570,14 @@ void VarRegion::printPretty(raw_ostream &os) const {
os << getDecl()->getName();
}
+bool ObjCIvarRegion::canPrintPretty() const {
+ return true;
+}
+
+void ObjCIvarRegion::printPretty(raw_ostream &os) const {
+ os << getDecl()->getName();
+}
+
bool FieldRegion::canPrintPretty() const {
return superRegion->canPrintPretty();
}
@@ -883,41 +899,50 @@ MemRegionManager::getCXXTempObjectRegion(Expr const *E,
return getSubRegion<CXXTempObjectRegion>(E, getStackLocalsRegion(SFC));
}
-const CXXBaseObjectRegion *
-MemRegionManager::getCXXBaseObjectRegion(const CXXRecordDecl *decl,
- const MemRegion *superRegion) {
- // Check that the base class is actually a direct base of this region.
- if (const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(superRegion)) {
- if (const CXXRecordDecl *Class = TVR->getValueType()->getAsCXXRecordDecl()){
- if (Class->isVirtuallyDerivedFrom(decl)) {
- // Virtual base regions should not be layered, since the layout rules
- // are different.
- while (const CXXBaseObjectRegion *Base =
- dyn_cast<CXXBaseObjectRegion>(superRegion)) {
- superRegion = Base->getSuperRegion();
- }
- assert(superRegion && !isa<MemSpaceRegion>(superRegion));
+/// Checks whether \p BaseClass is a valid virtual or direct non-virtual base
+/// class of the type of \p Super.
+static bool isValidBaseClass(const CXXRecordDecl *BaseClass,
+ const TypedValueRegion *Super,
+ bool IsVirtual) {
+ BaseClass = BaseClass->getCanonicalDecl();
- } else {
- // Non-virtual bases should always be direct bases.
-#ifndef NDEBUG
- bool FoundBase = false;
- for (CXXRecordDecl::base_class_const_iterator I = Class->bases_begin(),
- E = Class->bases_end();
- I != E; ++I) {
- if (I->getType()->getAsCXXRecordDecl() == decl) {
- FoundBase = true;
- break;
- }
- }
+ const CXXRecordDecl *Class = Super->getValueType()->getAsCXXRecordDecl();
+ if (!Class)
+ return true;
+
+ if (IsVirtual)
+ return Class->isVirtuallyDerivedFrom(BaseClass);
+
+ for (CXXRecordDecl::base_class_const_iterator I = Class->bases_begin(),
+ E = Class->bases_end();
+ I != E; ++I) {
+ if (I->getType()->getAsCXXRecordDecl()->getCanonicalDecl() == BaseClass)
+ return true;
+ }
+
+ return false;
+}
- assert(FoundBase && "Not a direct base class of this region");
-#endif
+const CXXBaseObjectRegion *
+MemRegionManager::getCXXBaseObjectRegion(const CXXRecordDecl *RD,
+ const MemRegion *Super,
+ bool IsVirtual) {
+ if (isa<TypedValueRegion>(Super)) {
+ assert(isValidBaseClass(RD, dyn_cast<TypedValueRegion>(Super), IsVirtual));
+ (void)isValidBaseClass;
+
+ if (IsVirtual) {
+ // Virtual base regions should not be layered, since the layout rules
+ // are different.
+ while (const CXXBaseObjectRegion *Base =
+ dyn_cast<CXXBaseObjectRegion>(Super)) {
+ Super = Base->getSuperRegion();
}
+ assert(Super && !isa<MemSpaceRegion>(Super));
}
}
- return getSubRegion<CXXBaseObjectRegion>(decl, superRegion);
+ return getSubRegion<CXXBaseObjectRegion>(RD, IsVirtual, Super);
}
const CXXThisRegion*
@@ -1042,7 +1067,7 @@ RegionRawOffset ElementRegion::getAsArrayOffset() const {
// FIXME: generalize to symbolic offsets.
SVal index = ER->getIndex();
- if (nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&index)) {
+ if (Optional<nonloc::ConcreteInt> CI = index.getAs<nonloc::ConcreteInt>()) {
// Update the offset.
int64_t i = CI->getValue().getSExtValue();
@@ -1071,6 +1096,23 @@ RegionRawOffset ElementRegion::getAsArrayOffset() const {
return RegionRawOffset(superR, offset);
}
+
+/// Returns true if \p Base is an immediate base class of \p Child
+static bool isImmediateBase(const CXXRecordDecl *Child,
+ const CXXRecordDecl *Base) {
+ // Note that we do NOT canonicalize the base class here, because
+ // ASTRecordLayout doesn't either. If that leads us down the wrong path,
+ // so be it; at least we won't crash.
+ for (CXXRecordDecl::base_class_const_iterator I = Child->bases_begin(),
+ E = Child->bases_end();
+ I != E; ++I) {
+ if (I->getType()->getAsCXXRecordDecl() == Base)
+ return true;
+ }
+
+ return false;
+}
+
RegionOffset MemRegion::getAsOffset() const {
const MemRegion *R = this;
const MemRegion *SymbolicOffsetBase = 0;
@@ -1078,16 +1120,37 @@ RegionOffset MemRegion::getAsOffset() const {
while (1) {
switch (R->getKind()) {
- default:
- return RegionOffset(R, RegionOffset::Symbolic);
+ case GenericMemSpaceRegionKind:
+ case StackLocalsSpaceRegionKind:
+ case StackArgumentsSpaceRegionKind:
+ case HeapSpaceRegionKind:
+ case UnknownSpaceRegionKind:
+ case StaticGlobalSpaceRegionKind:
+ case GlobalInternalSpaceRegionKind:
+ case GlobalSystemSpaceRegionKind:
+ case GlobalImmutableSpaceRegionKind:
+ // Stores can bind directly to a region space to set a default value.
+ assert(Offset == 0 && !SymbolicOffsetBase);
+ goto Finish;
+
+ case FunctionTextRegionKind:
+ case BlockTextRegionKind:
+ case BlockDataRegionKind:
+ // These will never have bindings, but may end up having values requested
+ // if the user does some strange casting.
+ if (Offset != 0)
+ SymbolicOffsetBase = R;
+ goto Finish;
case SymbolicRegionKind:
case AllocaRegionKind:
case CompoundLiteralRegionKind:
case CXXThisRegionKind:
case StringRegionKind:
+ case ObjCStringRegionKind:
case VarRegionKind:
case CXXTempObjectRegionKind:
+ // Usual base regions.
goto Finish;
case ObjCIvarRegionKind:
@@ -1103,6 +1166,7 @@ RegionOffset MemRegion::getAsOffset() const {
R = BOR->getSuperRegion();
QualType Ty;
+ bool RootIsSymbolic = false;
if (const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(R)) {
Ty = TVR->getDesugaredValueType(getContext());
} else if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) {
@@ -1110,6 +1174,7 @@ RegionOffset MemRegion::getAsOffset() const {
// 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()->getPointeeType();
+ RootIsSymbolic = true;
}
const CXXRecordDecl *Child = Ty->getAsCXXRecordDecl();
@@ -1118,19 +1183,30 @@ RegionOffset MemRegion::getAsOffset() const {
SymbolicOffsetBase = R;
}
+ if (RootIsSymbolic) {
+ // Base layers on symbolic regions may not be type-correct.
+ // Double-check the inheritance here, and revert to a symbolic offset
+ // if it's invalid (e.g. due to a reinterpret_cast).
+ if (BOR->isVirtual()) {
+ if (!Child->isVirtuallyDerivedFrom(BOR->getDecl()))
+ SymbolicOffsetBase = R;
+ } else {
+ if (!isImmediateBase(Child, BOR->getDecl()))
+ SymbolicOffsetBase = R;
+ }
+ }
+
// Don't bother calculating precise offsets if we already have a
// symbolic offset somewhere in the chain.
if (SymbolicOffsetBase)
continue;
- const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Child);
-
CharUnits BaseOffset;
- const CXXRecordDecl *Base = BOR->getDecl();
- if (Child->isVirtuallyDerivedFrom(Base))
- BaseOffset = Layout.getVBaseClassOffset(Base);
+ const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Child);
+ if (BOR->isVirtual())
+ BaseOffset = Layout.getVBaseClassOffset(BOR->getDecl());
else
- BaseOffset = Layout.getBaseClassOffset(Base);
+ BaseOffset = Layout.getBaseClassOffset(BOR->getDecl());
// The base offset is in chars, not in bits.
Offset += BaseOffset.getQuantity() * getContext().getCharWidth();
@@ -1148,7 +1224,8 @@ RegionOffset MemRegion::getAsOffset() const {
}
SVal Index = ER->getIndex();
- if (const nonloc::ConcreteInt *CI=dyn_cast<nonloc::ConcreteInt>(&Index)) {
+ if (Optional<nonloc::ConcreteInt> CI =
+ Index.getAs<nonloc::ConcreteInt>()) {
// Don't bother calculating precise offsets if we already have a
// symbolic offset somewhere in the chain.
if (SymbolicOffsetBase)
@@ -1207,6 +1284,29 @@ RegionOffset MemRegion::getAsOffset() const {
// BlockDataRegion
//===----------------------------------------------------------------------===//
+std::pair<const VarRegion *, const VarRegion *>
+BlockDataRegion::getCaptureRegions(const VarDecl *VD) {
+ MemRegionManager &MemMgr = *getMemRegionManager();
+ const VarRegion *VR = 0;
+ const VarRegion *OriginalVR = 0;
+
+ if (!VD->getAttr<BlocksAttr>() && VD->hasLocalStorage()) {
+ VR = MemMgr.getVarRegion(VD, this);
+ OriginalVR = MemMgr.getVarRegion(VD, LC);
+ }
+ else {
+ if (LC) {
+ VR = MemMgr.getVarRegion(VD, LC);
+ OriginalVR = VR;
+ }
+ else {
+ VR = MemMgr.getVarRegion(VD, MemMgr.getUnknownRegion());
+ OriginalVR = MemMgr.getVarRegion(VD, LC);
+ }
+ }
+ return std::make_pair(VR, OriginalVR);
+}
+
void BlockDataRegion::LazyInitializeReferencedVars() {
if (ReferencedVars)
return;
@@ -1231,25 +1331,9 @@ void BlockDataRegion::LazyInitializeReferencedVars() {
new (BVOriginal) VarVec(BC, E - I);
for ( ; I != E; ++I) {
- const VarDecl *VD = *I;
const VarRegion *VR = 0;
const VarRegion *OriginalVR = 0;
-
- if (!VD->getAttr<BlocksAttr>() && VD->hasLocalStorage()) {
- VR = MemMgr.getVarRegion(VD, this);
- OriginalVR = MemMgr.getVarRegion(VD, LC);
- }
- else {
- if (LC) {
- VR = MemMgr.getVarRegion(VD, LC);
- OriginalVR = VR;
- }
- else {
- VR = MemMgr.getVarRegion(VD, MemMgr.getUnknownRegion());
- OriginalVR = MemMgr.getVarRegion(VD, LC);
- }
- }
-
+ llvm::tie(VR, OriginalVR) = getCaptureRegions(*I);
assert(VR);
assert(OriginalVR);
BV->push_back(VR, BC);
@@ -1293,3 +1377,13 @@ BlockDataRegion::referenced_vars_end() const {
return BlockDataRegion::referenced_vars_iterator(Vec->end(),
VecOriginal->end());
}
+
+const VarRegion *BlockDataRegion::getOriginalRegion(const VarRegion *R) const {
+ for (referenced_vars_iterator I = referenced_vars_begin(),
+ E = referenced_vars_end();
+ I != E; ++I) {
+ if (I.getCapturedRegion() == R)
+ return I.getOriginalRegion();
+ }
+ return 0;
+}
diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
index 0f48d1e..7c0fb14 100644
--- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
+++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
@@ -12,16 +12,17 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/AST/Expr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -106,12 +107,16 @@ PathDiagnostic::~PathDiagnostic() {}
PathDiagnostic::PathDiagnostic(const Decl *declWithIssue,
StringRef bugtype, StringRef verboseDesc,
- StringRef shortDesc, StringRef category)
+ StringRef shortDesc, StringRef category,
+ PathDiagnosticLocation LocationToUnique,
+ const Decl *DeclToUnique)
: DeclWithIssue(declWithIssue),
BugType(StripTrailingDots(bugtype)),
VerboseDesc(StripTrailingDots(verboseDesc)),
ShortDesc(StripTrailingDots(shortDesc)),
Category(StripTrailingDots(category)),
+ UniqueingLoc(LocationToUnique),
+ UniqueingDecl(DeclToUnique),
path(pathImpl) {}
void PathDiagnosticConsumer::anchor() { }
@@ -125,7 +130,7 @@ PathDiagnosticConsumer::~PathDiagnosticConsumer() {
}
void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
- llvm::OwningPtr<PathDiagnostic> OwningD(D);
+ OwningPtr<PathDiagnostic> OwningD(D);
if (!D || D->path.empty())
return;
@@ -141,7 +146,7 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
// Verify that the entire path is from the same FileID.
FileID FID;
const SourceManager &SMgr = (*D->path.begin())->getLocation().getManager();
- llvm::SmallVector<const PathPieces *, 5> WorkList;
+ SmallVector<const PathPieces *, 5> WorkList;
WorkList.push_back(&D->path);
while (!WorkList.empty()) {
@@ -208,9 +213,8 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) {
Diags.InsertNode(OwningD.take());
}
-static llvm::Optional<bool> comparePath(const PathPieces &X,
- const PathPieces &Y);
-static llvm::Optional<bool>
+static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y);
+static Optional<bool>
compareControlFlow(const PathDiagnosticControlFlowPiece &X,
const PathDiagnosticControlFlowPiece &Y) {
FullSourceLoc XSL = X.getStartLocation().asLocation();
@@ -221,18 +225,16 @@ compareControlFlow(const PathDiagnosticControlFlowPiece &X,
FullSourceLoc YEL = Y.getEndLocation().asLocation();
if (XEL != YEL)
return XEL.isBeforeInTranslationUnitThan(YEL);
- return llvm::Optional<bool>();
+ return None;
}
-static llvm::Optional<bool>
-compareMacro(const PathDiagnosticMacroPiece &X,
- const PathDiagnosticMacroPiece &Y) {
+static Optional<bool> compareMacro(const PathDiagnosticMacroPiece &X,
+ const PathDiagnosticMacroPiece &Y) {
return comparePath(X.subPieces, Y.subPieces);
}
-static llvm::Optional<bool>
-compareCall(const PathDiagnosticCallPiece &X,
- const PathDiagnosticCallPiece &Y) {
+static Optional<bool> compareCall(const PathDiagnosticCallPiece &X,
+ const PathDiagnosticCallPiece &Y) {
FullSourceLoc X_CEL = X.callEnter.asLocation();
FullSourceLoc Y_CEL = Y.callEnter.asLocation();
if (X_CEL != Y_CEL)
@@ -248,8 +250,8 @@ compareCall(const PathDiagnosticCallPiece &X,
return comparePath(X.path, Y.path);
}
-static llvm::Optional<bool> comparePiece(const PathDiagnosticPiece &X,
- const PathDiagnosticPiece &Y) {
+static Optional<bool> comparePiece(const PathDiagnosticPiece &X,
+ const PathDiagnosticPiece &Y) {
if (X.getKind() != Y.getKind())
return X.getKind() < Y.getKind();
@@ -281,7 +283,7 @@ static llvm::Optional<bool> comparePiece(const PathDiagnosticPiece &X,
return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X),
cast<PathDiagnosticControlFlowPiece>(Y));
case clang::ento::PathDiagnosticPiece::Event:
- return llvm::Optional<bool>();
+ return None;
case clang::ento::PathDiagnosticPiece::Macro:
return compareMacro(cast<PathDiagnosticMacroPiece>(X),
cast<PathDiagnosticMacroPiece>(Y));
@@ -292,16 +294,15 @@ static llvm::Optional<bool> comparePiece(const PathDiagnosticPiece &X,
llvm_unreachable("all cases handled");
}
-static llvm::Optional<bool> comparePath(const PathPieces &X,
- const PathPieces &Y) {
+static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) {
if (X.size() != Y.size())
return X.size() < Y.size();
for (unsigned i = 0, n = X.size(); i != n; ++i) {
- llvm::Optional<bool> b = comparePiece(*X[i], *Y[i]);
+ Optional<bool> b = comparePiece(*X[i], *Y[i]);
if (b.hasValue())
return b.getValue();
}
- return llvm::Optional<bool>();
+ return None;
}
static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) {
@@ -339,7 +340,7 @@ static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) {
if (*XI != *YI)
return (*XI) < (*YI);
}
- llvm::Optional<bool> b = comparePath(X.path, Y.path);
+ Optional<bool> b = comparePath(X.path, Y.path);
assert(b.hasValue());
return b.getValue();
}
@@ -475,18 +476,16 @@ getLocationForCaller(const StackFrameContext *SFC,
CFGElement Source = Block[SFC->getIndex()];
switch (Source.getKind()) {
- case CFGElement::Invalid:
- llvm_unreachable("Invalid CFGElement");
case CFGElement::Statement:
- return PathDiagnosticLocation(cast<CFGStmt>(Source).getStmt(),
+ return PathDiagnosticLocation(Source.castAs<CFGStmt>().getStmt(),
SM, CallerCtx);
case CFGElement::Initializer: {
- const CFGInitializer &Init = cast<CFGInitializer>(Source);
+ const CFGInitializer &Init = Source.castAs<CFGInitializer>();
return PathDiagnosticLocation(Init.getInitializer()->getInit(),
SM, CallerCtx);
}
case CFGElement::AutomaticObjectDtor: {
- const CFGAutomaticObjDtor &Dtor = cast<CFGAutomaticObjDtor>(Source);
+ const CFGAutomaticObjDtor &Dtor = Source.castAs<CFGAutomaticObjDtor>();
return PathDiagnosticLocation::createEnd(Dtor.getTriggerStmt(),
SM, CallerCtx);
}
@@ -582,27 +581,27 @@ PathDiagnosticLocation
const SourceManager &SMng) {
const Stmt* S = 0;
- if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
+ if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
const CFGBlock *BSrc = BE->getSrc();
S = BSrc->getTerminatorCondition();
- }
- else if (const StmtPoint *SP = dyn_cast<StmtPoint>(&P)) {
+ } else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) {
S = SP->getStmt();
- }
- else if (const PostImplicitCall *PIE = dyn_cast<PostImplicitCall>(&P)) {
+ if (P.getAs<PostStmtPurgeDeadSymbols>())
+ return PathDiagnosticLocation::createEnd(S, SMng, P.getLocationContext());
+ } else if (Optional<PostInitializer> PIP = P.getAs<PostInitializer>()) {
+ return PathDiagnosticLocation(PIP->getInitializer()->getSourceLocation(),
+ SMng);
+ } else if (Optional<PostImplicitCall> PIE = P.getAs<PostImplicitCall>()) {
return PathDiagnosticLocation(PIE->getLocation(), SMng);
- }
- else if (const CallEnter *CE = dyn_cast<CallEnter>(&P)) {
+ } else if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
return getLocationForCaller(CE->getCalleeContext(),
CE->getLocationContext(),
SMng);
- }
- else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&P)) {
+ } else if (Optional<CallExitEnd> CEE = P.getAs<CallExitEnd>()) {
return getLocationForCaller(CEE->getCalleeContext(),
CEE->getLocationContext(),
SMng);
- }
- else {
+ } else {
llvm_unreachable("Unexpected ProgramPoint");
}
@@ -619,12 +618,16 @@ PathDiagnosticLocation
while (NI) {
ProgramPoint P = NI->getLocation();
- if (const StmtPoint *PS = dyn_cast<StmtPoint>(&P))
+ if (Optional<StmtPoint> PS = P.getAs<StmtPoint>()) {
S = PS->getStmt();
- else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P))
+ if (P.getAs<PostStmtPurgeDeadSymbols>())
+ return PathDiagnosticLocation::createEnd(S, SM,
+ NI->getLocationContext());
+ break;
+ } else if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
S = BE->getSrc()->getTerminator();
- if (S)
break;
+ }
NI = NI->succ_empty() ? 0 : *(NI->succ_begin());
}
@@ -777,48 +780,129 @@ void PathDiagnosticCallPiece::setCallee(const CallEnter &CE,
callEnter = getLocationForCaller(CalleeCtx, CE.getLocationContext(), SM);
}
+static inline void describeClass(raw_ostream &Out, const CXXRecordDecl *D,
+ StringRef Prefix = StringRef()) {
+ if (!D->getIdentifier())
+ return;
+ Out << Prefix << '\'' << *D << '\'';
+}
+
+static bool describeCodeDecl(raw_ostream &Out, const Decl *D,
+ bool ExtendedDescription,
+ StringRef Prefix = StringRef()) {
+ if (!D)
+ return false;
+
+ if (isa<BlockDecl>(D)) {
+ if (ExtendedDescription)
+ Out << Prefix << "anonymous block";
+ return ExtendedDescription;
+ }
+
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
+ Out << Prefix;
+ if (ExtendedDescription && !MD->isUserProvided()) {
+ if (MD->isExplicitlyDefaulted())
+ Out << "defaulted ";
+ else
+ Out << "implicit ";
+ }
+
+ if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(MD)) {
+ if (CD->isDefaultConstructor())
+ Out << "default ";
+ else if (CD->isCopyConstructor())
+ Out << "copy ";
+ else if (CD->isMoveConstructor())
+ Out << "move ";
+
+ Out << "constructor";
+ describeClass(Out, MD->getParent(), " for ");
+
+ } else if (isa<CXXDestructorDecl>(MD)) {
+ if (!MD->isUserProvided()) {
+ Out << "destructor";
+ describeClass(Out, MD->getParent(), " for ");
+ } else {
+ // Use ~Foo for explicitly-written destructors.
+ Out << "'" << *MD << "'";
+ }
+
+ } else if (MD->isCopyAssignmentOperator()) {
+ Out << "copy assignment operator";
+ describeClass(Out, MD->getParent(), " for ");
+
+ } else if (MD->isMoveAssignmentOperator()) {
+ Out << "move assignment operator";
+ describeClass(Out, MD->getParent(), " for ");
+
+ } else {
+ if (MD->getParent()->getIdentifier())
+ Out << "'" << *MD->getParent() << "::" << *MD << "'";
+ else
+ Out << "'" << *MD << "'";
+ }
+
+ return true;
+ }
+
+ Out << Prefix << '\'' << cast<NamedDecl>(*D) << '\'';
+ return true;
+}
+
IntrusiveRefCntPtr<PathDiagnosticEventPiece>
PathDiagnosticCallPiece::getCallEnterEvent() const {
if (!Callee)
return 0;
+
SmallString<256> buf;
llvm::raw_svector_ostream Out(buf);
- if (isa<BlockDecl>(Callee))
- Out << "Calling anonymous block";
- else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Callee))
- Out << "Calling '" << *ND << "'";
- StringRef msg = Out.str();
- if (msg.empty())
- return 0;
- return new PathDiagnosticEventPiece(callEnter, msg);
+
+ Out << "Calling ";
+ describeCodeDecl(Out, Callee, /*ExtendedDescription=*/true);
+
+ assert(callEnter.asLocation().isValid());
+ return new PathDiagnosticEventPiece(callEnter, Out.str());
}
IntrusiveRefCntPtr<PathDiagnosticEventPiece>
PathDiagnosticCallPiece::getCallEnterWithinCallerEvent() const {
+ if (!callEnterWithin.asLocation().isValid())
+ return 0;
+ if (Callee->isImplicit())
+ return 0;
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee))
+ if (MD->isDefaulted())
+ return 0;
+
SmallString<256> buf;
llvm::raw_svector_ostream Out(buf);
- if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Caller))
- Out << "Entered call from '" << *ND << "'";
- else
- Out << "Entered call";
- StringRef msg = Out.str();
- if (msg.empty())
- return 0;
- return new PathDiagnosticEventPiece(callEnterWithin, msg);
+
+ Out << "Entered call";
+ describeCodeDecl(Out, Caller, /*ExtendedDescription=*/false, " from ");
+
+ return new PathDiagnosticEventPiece(callEnterWithin, Out.str());
}
IntrusiveRefCntPtr<PathDiagnosticEventPiece>
PathDiagnosticCallPiece::getCallExitEvent() const {
if (NoExit)
return 0;
+
SmallString<256> buf;
llvm::raw_svector_ostream Out(buf);
- if (!CallStackMessage.empty())
+
+ if (!CallStackMessage.empty()) {
Out << CallStackMessage;
- else if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Callee))
- Out << "Returning from '" << *ND << "'";
- else
- Out << "Returning to caller";
+ } else {
+ bool DidDescribe = describeCodeDecl(Out, Callee,
+ /*ExtendedDescription=*/false,
+ "Returning from ");
+ if (!DidDescribe)
+ Out << "Returning to caller";
+ }
+
+ assert(callReturn.asLocation().isValid());
return new PathDiagnosticEventPiece(callReturn, Out.str());
}
@@ -910,11 +994,10 @@ StackHintGenerator::~StackHintGenerator() {}
std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
ProgramPoint P = N->getLocation();
- const CallExitEnd *CExit = dyn_cast<CallExitEnd>(&P);
- assert(CExit && "Stack Hints should be constructed at CallExitEnd points.");
+ CallExitEnd CExit = P.castAs<CallExitEnd>();
// FIXME: Use CallEvent to abstract this over all calls.
- const Stmt *CallSite = CExit->getCalleeContext()->getCallSite();
+ const Stmt *CallSite = CExit.getCalleeContext()->getCallSite();
const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite);
if (!CE)
return "";
@@ -937,7 +1020,7 @@ std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){
}
// Check if the parameter is a pointer to the symbol.
- if (const loc::MemRegionVal *Reg = dyn_cast<loc::MemRegionVal>(&SV)) {
+ if (Optional<loc::MemRegionVal> Reg = SV.getAs<loc::MemRegionVal>()) {
SVal PSV = State->getSVal(Reg->getRegion());
SymbolRef AS = PSV.getAsLocSymbol();
if (AS == Sym) {
diff --git a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
index 17ef4cf..7dcc088 100644
--- a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
@@ -11,16 +11,17 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/Core/AnalyzerOptions.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"
+#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -33,7 +34,9 @@ namespace {
const LangOptions &LangOpts;
const bool SupportsCrossFileDiagnostics;
public:
- PlistDiagnostics(const std::string& prefix, const LangOptions &LangOpts,
+ PlistDiagnostics(AnalyzerOptions &AnalyzerOpts,
+ const std::string& prefix,
+ const LangOptions &LangOpts,
bool supportsMultipleFiles);
virtual ~PlistDiagnostics() {}
@@ -54,22 +57,28 @@ namespace {
};
} // end anonymous namespace
-PlistDiagnostics::PlistDiagnostics(const std::string& output,
+PlistDiagnostics::PlistDiagnostics(AnalyzerOptions &AnalyzerOpts,
+ const std::string& output,
const LangOptions &LO,
bool supportsMultipleFiles)
- : OutputFile(output), LangOpts(LO),
+ : OutputFile(output),
+ LangOpts(LO),
SupportsCrossFileDiagnostics(supportsMultipleFiles) {}
-void ento::createPlistDiagnosticConsumer(PathDiagnosticConsumers &C,
+void ento::createPlistDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
+ PathDiagnosticConsumers &C,
const std::string& s,
const Preprocessor &PP) {
- C.push_back(new PlistDiagnostics(s, PP.getLangOpts(), false));
+ C.push_back(new PlistDiagnostics(AnalyzerOpts, s,
+ PP.getLangOpts(), false));
}
-void ento::createPlistMultiFileDiagnosticConsumer(PathDiagnosticConsumers &C,
+void ento::createPlistMultiFileDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
+ PathDiagnosticConsumers &C,
const std::string &s,
const Preprocessor &PP) {
- C.push_back(new PlistDiagnostics(s, PP.getLangOpts(), true));
+ C.push_back(new PlistDiagnostics(AnalyzerOpts, s,
+ PP.getLangOpts(), true));
}
static void AddFID(FIDMap &FIDs, SmallVectorImpl<FileID> &V,
@@ -360,7 +369,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
const PathDiagnostic *D = *DI;
- llvm::SmallVector<const PathPieces *, 5> WorkList;
+ SmallVector<const PathPieces *, 5> WorkList;
WorkList.push_back(&D->path);
while (!WorkList.empty()) {
@@ -486,12 +495,32 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
// Output the bug hash for issue unique-ing. Currently, it's just an
// offset from the beginning of the function.
if (const Stmt *Body = DeclWithIssue->getBody()) {
- FullSourceLoc Loc(SM->getExpansionLoc(D->getLocation().asLocation()),
+
+ // If the bug uniqueing location exists, use it for the hash.
+ // For example, this ensures that two leaks reported on the same line
+ // will have different issue_hashes and that the hash will identify
+ // the leak location even after code is added between the allocation
+ // site and the end of scope (leak report location).
+ PathDiagnosticLocation UPDLoc = D->getUniqueingLoc();
+ if (UPDLoc.isValid()) {
+ FullSourceLoc UL(SM->getExpansionLoc(UPDLoc.asLocation()),
+ *SM);
+ FullSourceLoc UFunL(SM->getExpansionLoc(
+ D->getUniqueingDecl()->getBody()->getLocStart()), *SM);
+ o << " <key>issue_hash</key><string>"
+ << UL.getExpansionLineNumber() - UFunL.getExpansionLineNumber()
+ << "</string>\n";
+
+ // Otherwise, use the location on which the bug is reported.
+ } else {
+ FullSourceLoc L(SM->getExpansionLoc(D->getLocation().asLocation()),
*SM);
- FullSourceLoc FunLoc(SM->getExpansionLoc(Body->getLocStart()), *SM);
- o << " <key>issue_hash</key><integer>"
- << Loc.getExpansionLineNumber() - FunLoc.getExpansionLineNumber()
- << "</integer>\n";
+ FullSourceLoc FunL(SM->getExpansionLoc(Body->getLocStart()), *SM);
+ o << " <key>issue_hash</key><string>"
+ << L.getExpansionLineNumber() - FunL.getExpansionLineNumber()
+ << "</string>\n";
+ }
+
}
}
}
diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp
index b49a11e..bff2242 100644
--- a/lib/StaticAnalyzer/Core/ProgramState.cpp
+++ b/lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -11,10 +11,10 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/Analysis/CFG.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h"
#include "llvm/Support/raw_ostream.h"
@@ -132,7 +132,7 @@ ProgramStateRef ProgramState::bindLoc(Loc LV, SVal V, bool notifyChanges) const
ProgramStateRef ProgramState::bindDefault(SVal loc, SVal V) const {
ProgramStateManager &Mgr = getStateManager();
- const MemRegion *R = cast<loc::MemRegionVal>(loc).getRegion();
+ const MemRegion *R = loc.castAs<loc::MemRegionVal>().getRegion();
const StoreRef &newStore = Mgr.StoreMgr->BindDefault(getStore(), R, V);
ProgramStateRef new_state = makeWithStore(newStore);
return Mgr.getOwningEngine() ?
@@ -140,46 +140,108 @@ ProgramStateRef ProgramState::bindDefault(SVal loc, SVal V) const {
new_state;
}
+typedef ArrayRef<const MemRegion *> RegionList;
+typedef ArrayRef<SVal> ValueList;
+
ProgramStateRef
-ProgramState::invalidateRegions(ArrayRef<const MemRegion *> Regions,
+ProgramState::invalidateRegions(RegionList Regions,
const Expr *E, unsigned Count,
const LocationContext *LCtx,
- StoreManager::InvalidatedSymbols *IS,
- const CallEvent *Call) const {
+ bool CausedByPointerEscape,
+ InvalidatedSymbols *IS,
+ const CallEvent *Call,
+ RegionList ConstRegions) const {
+ SmallVector<SVal, 8> Values;
+ for (RegionList::const_iterator I = Regions.begin(),
+ End = Regions.end(); I != End; ++I)
+ Values.push_back(loc::MemRegionVal(*I));
+
+ SmallVector<SVal, 8> ConstValues;
+ for (RegionList::const_iterator I = ConstRegions.begin(),
+ End = ConstRegions.end(); I != End; ++I)
+ ConstValues.push_back(loc::MemRegionVal(*I));
+
if (!IS) {
- StoreManager::InvalidatedSymbols invalidated;
- return invalidateRegionsImpl(Regions, E, Count, LCtx,
- invalidated, Call);
+ InvalidatedSymbols invalidated;
+ return invalidateRegionsImpl(Values, E, Count, LCtx,
+ CausedByPointerEscape,
+ invalidated, Call, ConstValues);
}
- return invalidateRegionsImpl(Regions, E, Count, LCtx, *IS, Call);
+ return invalidateRegionsImpl(Values, E, Count, LCtx, CausedByPointerEscape,
+ *IS, Call, ConstValues);
}
-ProgramStateRef
-ProgramState::invalidateRegionsImpl(ArrayRef<const MemRegion *> Regions,
+ProgramStateRef
+ProgramState::invalidateRegions(ValueList Values,
+ const Expr *E, unsigned Count,
+ const LocationContext *LCtx,
+ bool CausedByPointerEscape,
+ InvalidatedSymbols *IS,
+ const CallEvent *Call,
+ ValueList ConstValues) const {
+ if (!IS) {
+ InvalidatedSymbols invalidated;
+ return invalidateRegionsImpl(Values, E, Count, LCtx,
+ CausedByPointerEscape,
+ invalidated, Call, ConstValues);
+ }
+ return invalidateRegionsImpl(Values, E, Count, LCtx, CausedByPointerEscape,
+ *IS, Call, ConstValues);
+}
+
+ProgramStateRef
+ProgramState::invalidateRegionsImpl(ValueList Values,
const Expr *E, unsigned Count,
const LocationContext *LCtx,
- StoreManager::InvalidatedSymbols &IS,
- const CallEvent *Call) const {
+ bool CausedByPointerEscape,
+ InvalidatedSymbols &IS,
+ const CallEvent *Call,
+ ValueList ConstValues) const {
ProgramStateManager &Mgr = getStateManager();
SubEngine* Eng = Mgr.getOwningEngine();
-
- if (Eng && Eng->wantsRegionChangeUpdate(this)) {
+ InvalidatedSymbols ConstIS;
+
+ if (Eng) {
+ StoreManager::InvalidatedRegions TopLevelInvalidated;
+ StoreManager::InvalidatedRegions TopLevelConstInvalidated;
StoreManager::InvalidatedRegions Invalidated;
const StoreRef &newStore
- = Mgr.StoreMgr->invalidateRegions(getStore(), Regions, E, Count, LCtx, IS,
- Call, &Invalidated);
+ = Mgr.StoreMgr->invalidateRegions(getStore(), Values, ConstValues,
+ E, Count, LCtx, Call,
+ IS, ConstIS,
+ &TopLevelInvalidated,
+ &TopLevelConstInvalidated,
+ &Invalidated);
+
ProgramStateRef newState = makeWithStore(newStore);
- return Eng->processRegionChanges(newState, &IS, Regions, Invalidated, Call);
+
+ if (CausedByPointerEscape) {
+ newState = Eng->notifyCheckersOfPointerEscape(newState, &IS,
+ TopLevelInvalidated,
+ Invalidated, Call);
+ if (!ConstValues.empty()) {
+ StoreManager::InvalidatedRegions Empty;
+ newState = Eng->notifyCheckersOfPointerEscape(newState, &ConstIS,
+ TopLevelConstInvalidated,
+ Empty, Call,
+ true);
+ }
+ }
+
+ return Eng->processRegionChanges(newState, &IS,
+ TopLevelInvalidated, Invalidated,
+ Call);
}
const StoreRef &newStore =
- Mgr.StoreMgr->invalidateRegions(getStore(), Regions, E, Count, LCtx, IS,
- Call, NULL);
+ Mgr.StoreMgr->invalidateRegions(getStore(), Values, ConstValues,
+ E, Count, LCtx, Call,
+ IS, ConstIS, NULL, NULL, NULL);
return makeWithStore(newStore);
}
ProgramStateRef ProgramState::killBinding(Loc LV) const {
- assert(!isa<loc::MemRegionVal>(LV) && "Use invalidateRegion instead.");
+ assert(!LV.getAs<loc::MemRegionVal>() && "Use invalidateRegion instead.");
Store OldStore = getStore();
const StoreRef &newStore =
@@ -243,7 +305,7 @@ SVal ProgramState::getSVal(Loc location, QualType T) const {
// not unsigned.
const llvm::APSInt &NewV = getBasicVals().Convert(T, *Int);
- if (isa<Loc>(V))
+ if (V.getAs<Loc>())
return loc::ConcreteInt(NewV);
else
return nonloc::ConcreteInt(NewV);
@@ -268,23 +330,6 @@ ProgramStateRef ProgramState::BindExpr(const Stmt *S,
return getStateManager().getPersistentState(NewSt);
}
-ProgramStateRef
-ProgramState::bindExprAndLocation(const Stmt *S, const LocationContext *LCtx,
- SVal location,
- SVal V) const {
- Environment NewEnv =
- getStateManager().EnvMgr.bindExprAndLocation(Env,
- EnvironmentEntry(S, LCtx),
- location, V);
-
- if (NewEnv == Env)
- return this;
-
- ProgramState NewSt = *this;
- NewSt.Env = NewEnv;
- return getStateManager().getPersistentState(NewSt);
-}
-
ProgramStateRef ProgramState::assumeInBound(DefinedOrUnknownSVal Idx,
DefinedOrUnknownSVal UpperBound,
bool Assumption,
@@ -308,28 +353,41 @@ ProgramStateRef ProgramState::assumeInBound(DefinedOrUnknownSVal Idx,
// Adjust the index.
SVal newIdx = svalBuilder.evalBinOpNN(this, BO_Add,
- cast<NonLoc>(Idx), Min, indexTy);
+ Idx.castAs<NonLoc>(), Min, indexTy);
if (newIdx.isUnknownOrUndef())
return this;
// Adjust the upper bound.
SVal newBound =
- svalBuilder.evalBinOpNN(this, BO_Add, cast<NonLoc>(UpperBound),
+ svalBuilder.evalBinOpNN(this, BO_Add, UpperBound.castAs<NonLoc>(),
Min, indexTy);
if (newBound.isUnknownOrUndef())
return this;
// Build the actual comparison.
- SVal inBound = svalBuilder.evalBinOpNN(this, BO_LT,
- cast<NonLoc>(newIdx), cast<NonLoc>(newBound),
- Ctx.IntTy);
+ SVal inBound = svalBuilder.evalBinOpNN(this, BO_LT, newIdx.castAs<NonLoc>(),
+ newBound.castAs<NonLoc>(), Ctx.IntTy);
if (inBound.isUnknownOrUndef())
return this;
// Finally, let the constraint manager take care of it.
ConstraintManager &CM = SM.getConstraintManager();
- return CM.assume(this, cast<DefinedSVal>(inBound), Assumption);
+ return CM.assume(this, inBound.castAs<DefinedSVal>(), Assumption);
+}
+
+ConditionTruthVal ProgramState::isNull(SVal V) const {
+ if (V.isZeroConstant())
+ return true;
+
+ if (V.isConstant())
+ return false;
+
+ SymbolRef Sym = V.getAsSymbol();
+ if (!Sym)
+ return ConditionTruthVal();
+
+ return getStateManager().ConstraintMgr->isNull(this, Sym);
}
ProgramStateRef ProgramStateManager::getInitialState(const LocationContext *InitLoc) {
@@ -516,13 +574,22 @@ bool ScanReachableSymbols::scan(const SymExpr *sym) {
}
bool ScanReachableSymbols::scan(SVal val) {
- if (loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(&val))
+ if (Optional<loc::MemRegionVal> X = val.getAs<loc::MemRegionVal>())
return scan(X->getRegion());
- if (nonloc::LazyCompoundVal *X = dyn_cast<nonloc::LazyCompoundVal>(&val))
- return scan(X->getRegion());
+ if (Optional<nonloc::LazyCompoundVal> X =
+ val.getAs<nonloc::LazyCompoundVal>()) {
+ StoreManager &StoreMgr = state->getStateManager().getStoreManager();
+ // FIXME: We don't really want to use getBaseRegion() here because pointer
+ // arithmetic doesn't apply, but scanReachableSymbols only accepts base
+ // regions right now.
+ if (!StoreMgr.scanReachableSymbols(X->getStore(),
+ X->getRegion()->getBaseRegion(),
+ *this))
+ return false;
+ }
- if (nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(&val))
+ if (Optional<nonloc::LocAsInteger> X = val.getAs<nonloc::LocAsInteger>())
return scan(X->getLoc());
if (SymbolRef Sym = val.getAsSymbol())
@@ -531,7 +598,7 @@ bool ScanReachableSymbols::scan(SVal val) {
if (const SymExpr *Sym = val.getAsSymbolicExpression())
return scan(Sym);
- if (nonloc::CompoundVal *X = dyn_cast<nonloc::CompoundVal>(&val))
+ if (Optional<nonloc::CompoundVal> X = val.getAs<nonloc::CompoundVal>())
return scan(*X);
return true;
diff --git a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 411094b..3606e09 100644
--- a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -16,9 +16,9 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
-#include "llvm/Support/Debug.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableSet.h"
+#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -153,8 +153,8 @@ private:
// The function returns false if the described range is entirely outside
// the range of values for the associated symbol.
APSIntType Type(getMinValue());
- APSIntType::RangeTestResultKind LowerTest = Type.testInRange(Lower);
- APSIntType::RangeTestResultKind UpperTest = Type.testInRange(Upper);
+ APSIntType::RangeTestResultKind LowerTest = Type.testInRange(Lower, true);
+ APSIntType::RangeTestResultKind UpperTest = Type.testInRange(Upper, true);
switch (LowerTest) {
case APSIntType::RTR_Below:
@@ -285,8 +285,8 @@ namespace {
class RangeConstraintManager : public SimpleConstraintManager{
RangeSet GetRange(ProgramStateRef state, SymbolRef sym);
public:
- RangeConstraintManager(SubEngine *subengine, BasicValueFactory &BVF)
- : SimpleConstraintManager(subengine, BVF) {}
+ RangeConstraintManager(SubEngine *subengine, SValBuilder &SVB)
+ : SimpleConstraintManager(subengine, SVB) {}
ProgramStateRef assumeSymNE(ProgramStateRef state, SymbolRef sym,
const llvm::APSInt& Int,
@@ -328,7 +328,7 @@ private:
ConstraintManager *
ento::CreateRangeConstraintManager(ProgramStateManager &StMgr, SubEngine *Eng) {
- return new RangeConstraintManager(Eng, StMgr.getBasicVals());
+ return new RangeConstraintManager(Eng, StMgr.getSValBuilder());
}
const llvm::APSInt* RangeConstraintManager::getSymVal(ProgramStateRef St,
@@ -419,7 +419,7 @@ RangeConstraintManager::assumeSymNE(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Adjustment) {
// Before we do any real work, see if the value can even show up.
APSIntType AdjustmentType(Adjustment);
- if (AdjustmentType.testInRange(Int) != APSIntType::RTR_Within)
+ if (AdjustmentType.testInRange(Int, true) != APSIntType::RTR_Within)
return St;
llvm::APSInt Lower = AdjustmentType.convert(Int) - Adjustment;
@@ -439,7 +439,7 @@ RangeConstraintManager::assumeSymEQ(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Adjustment) {
// Before we do any real work, see if the value can even show up.
APSIntType AdjustmentType(Adjustment);
- if (AdjustmentType.testInRange(Int) != APSIntType::RTR_Within)
+ if (AdjustmentType.testInRange(Int, true) != APSIntType::RTR_Within)
return NULL;
// [Int-Adjustment, Int-Adjustment]
@@ -454,7 +454,7 @@ RangeConstraintManager::assumeSymLT(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Adjustment) {
// Before we do any real work, see if the value can even show up.
APSIntType AdjustmentType(Adjustment);
- switch (AdjustmentType.testInRange(Int)) {
+ switch (AdjustmentType.testInRange(Int, true)) {
case APSIntType::RTR_Below:
return NULL;
case APSIntType::RTR_Within:
@@ -483,7 +483,7 @@ RangeConstraintManager::assumeSymGT(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Adjustment) {
// Before we do any real work, see if the value can even show up.
APSIntType AdjustmentType(Adjustment);
- switch (AdjustmentType.testInRange(Int)) {
+ switch (AdjustmentType.testInRange(Int, true)) {
case APSIntType::RTR_Below:
return St;
case APSIntType::RTR_Within:
@@ -512,7 +512,7 @@ RangeConstraintManager::assumeSymGE(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Adjustment) {
// Before we do any real work, see if the value can even show up.
APSIntType AdjustmentType(Adjustment);
- switch (AdjustmentType.testInRange(Int)) {
+ switch (AdjustmentType.testInRange(Int, true)) {
case APSIntType::RTR_Below:
return St;
case APSIntType::RTR_Within:
@@ -541,7 +541,7 @@ RangeConstraintManager::assumeSymLE(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Adjustment) {
// Before we do any real work, see if the value can even show up.
APSIntType AdjustmentType(Adjustment);
- switch (AdjustmentType.testInRange(Int)) {
+ switch (AdjustmentType.testInRange(Int, true)) {
case APSIntType::RTR_Below:
return NULL;
case APSIntType::RTR_Within:
diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp
index aed994d..0f4a682 100644
--- a/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -14,14 +14,15 @@
// parameters are created lazily.
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/Attr.h"
#include "clang/AST/CharUnits.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
#include "llvm/ADT/ImmutableList.h"
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/Optional.h"
@@ -29,7 +30,6 @@
using namespace clang;
using namespace ento;
-using llvm::Optional;
//===----------------------------------------------------------------------===//
// Representation of binding keys.
@@ -45,11 +45,15 @@ private:
llvm::PointerIntPair<const MemRegion *, 2> P;
uint64_t Data;
- explicit BindingKey(const MemRegion *r, const MemRegion *Base, Kind k)
+ /// Create a key for a binding to region \p r, which has a symbolic offset
+ /// from region \p Base.
+ explicit BindingKey(const SubRegion *r, const SubRegion *Base, Kind k)
: P(r, k | Symbolic), Data(reinterpret_cast<uintptr_t>(Base)) {
assert(r && Base && "Must have known regions.");
assert(getConcreteOffsetRegion() == Base && "Failed to store base region");
}
+
+ /// Create a key for a binding at \p offset from base region \p r.
explicit BindingKey(const MemRegion *r, uint64_t offset, Kind k)
: P(r, k), Data(offset) {
assert(r && "Must have known regions.");
@@ -67,9 +71,9 @@ public:
return Data;
}
- const MemRegion *getConcreteOffsetRegion() const {
+ const SubRegion *getConcreteOffsetRegion() const {
assert(hasSymbolicOffset());
- return reinterpret_cast<const MemRegion *>(static_cast<uintptr_t>(Data));
+ return reinterpret_cast<const SubRegion *>(static_cast<uintptr_t>(Data));
}
const MemRegion *getBaseRegion() const {
@@ -105,7 +109,7 @@ public:
BindingKey BindingKey::Make(const MemRegion *R, Kind k) {
const RegionOffset &RO = R->getAsOffset();
if (RO.hasSymbolicOffset())
- return BindingKey(R, RO.getRegion(), k);
+ return BindingKey(cast<SubRegion>(R), cast<SubRegion>(RO.getRegion()), k);
return BindingKey(RO.getRegion(), RO.getOffset(), k);
}
@@ -120,6 +124,11 @@ namespace llvm {
<< ')';
return os;
}
+
+ template <typename T> struct isPodLike;
+ template <> struct isPodLike<BindingKey> {
+ static const bool value = true;
+ };
} // end llvm namespace
void BindingKey::dump() const {
@@ -130,8 +139,156 @@ void BindingKey::dump() const {
// Actual Store type.
//===----------------------------------------------------------------------===//
-typedef llvm::ImmutableMap<BindingKey, SVal> ClusterBindings;
-typedef llvm::ImmutableMap<const MemRegion *, ClusterBindings> RegionBindings;
+typedef llvm::ImmutableMap<BindingKey, SVal> ClusterBindings;
+typedef llvm::ImmutableMapRef<BindingKey, SVal> ClusterBindingsRef;
+typedef std::pair<BindingKey, SVal> BindingPair;
+
+typedef llvm::ImmutableMap<const MemRegion *, ClusterBindings>
+ RegionBindings;
+
+namespace {
+class RegionBindingsRef : public llvm::ImmutableMapRef<const MemRegion *,
+ ClusterBindings> {
+ ClusterBindings::Factory &CBFactory;
+public:
+ typedef llvm::ImmutableMapRef<const MemRegion *, ClusterBindings>
+ ParentTy;
+
+ RegionBindingsRef(ClusterBindings::Factory &CBFactory,
+ const RegionBindings::TreeTy *T,
+ RegionBindings::TreeTy::Factory *F)
+ : llvm::ImmutableMapRef<const MemRegion *, ClusterBindings>(T, F),
+ CBFactory(CBFactory) {}
+
+ RegionBindingsRef(const ParentTy &P, ClusterBindings::Factory &CBFactory)
+ : llvm::ImmutableMapRef<const MemRegion *, ClusterBindings>(P),
+ CBFactory(CBFactory) {}
+
+ RegionBindingsRef add(key_type_ref K, data_type_ref D) const {
+ return RegionBindingsRef(static_cast<const ParentTy*>(this)->add(K, D),
+ CBFactory);
+ }
+
+ RegionBindingsRef remove(key_type_ref K) const {
+ return RegionBindingsRef(static_cast<const ParentTy*>(this)->remove(K),
+ CBFactory);
+ }
+
+ RegionBindingsRef addBinding(BindingKey K, SVal V) const;
+
+ RegionBindingsRef addBinding(const MemRegion *R,
+ BindingKey::Kind k, SVal V) const;
+
+ RegionBindingsRef &operator=(const RegionBindingsRef &X) {
+ *static_cast<ParentTy*>(this) = X;
+ return *this;
+ }
+
+ const SVal *lookup(BindingKey K) const;
+ const SVal *lookup(const MemRegion *R, BindingKey::Kind k) const;
+ const ClusterBindings *lookup(const MemRegion *R) const {
+ return static_cast<const ParentTy*>(this)->lookup(R);
+ }
+
+ RegionBindingsRef removeBinding(BindingKey K);
+
+ RegionBindingsRef removeBinding(const MemRegion *R,
+ BindingKey::Kind k);
+
+ RegionBindingsRef removeBinding(const MemRegion *R) {
+ return removeBinding(R, BindingKey::Direct).
+ removeBinding(R, BindingKey::Default);
+ }
+
+ Optional<SVal> getDirectBinding(const MemRegion *R) const;
+
+ /// getDefaultBinding - Returns an SVal* representing an optional default
+ /// binding associated with a region and its subregions.
+ Optional<SVal> getDefaultBinding(const MemRegion *R) const;
+
+ /// Return the internal tree as a Store.
+ Store asStore() const {
+ return asImmutableMap().getRootWithoutRetain();
+ }
+
+ void dump(raw_ostream &OS, const char *nl) const {
+ for (iterator I = begin(), E = end(); I != E; ++I) {
+ const ClusterBindings &Cluster = I.getData();
+ for (ClusterBindings::iterator CI = Cluster.begin(), CE = Cluster.end();
+ CI != CE; ++CI) {
+ OS << ' ' << CI.getKey() << " : " << CI.getData() << nl;
+ }
+ OS << nl;
+ }
+ }
+
+ LLVM_ATTRIBUTE_USED void dump() const {
+ dump(llvm::errs(), "\n");
+ }
+};
+} // end anonymous namespace
+
+typedef const RegionBindingsRef& RegionBindingsConstRef;
+
+Optional<SVal> RegionBindingsRef::getDirectBinding(const MemRegion *R) const {
+ return Optional<SVal>::create(lookup(R, BindingKey::Direct));
+}
+
+Optional<SVal> RegionBindingsRef::getDefaultBinding(const MemRegion *R) const {
+ if (R->isBoundable())
+ if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R))
+ if (TR->getValueType()->isUnionType())
+ return UnknownVal();
+
+ return Optional<SVal>::create(lookup(R, BindingKey::Default));
+}
+
+RegionBindingsRef RegionBindingsRef::addBinding(BindingKey K, SVal V) const {
+ const MemRegion *Base = K.getBaseRegion();
+
+ const ClusterBindings *ExistingCluster = lookup(Base);
+ ClusterBindings Cluster = (ExistingCluster ? *ExistingCluster
+ : CBFactory.getEmptyMap());
+
+ ClusterBindings NewCluster = CBFactory.add(Cluster, K, V);
+ return add(Base, NewCluster);
+}
+
+
+RegionBindingsRef RegionBindingsRef::addBinding(const MemRegion *R,
+ BindingKey::Kind k,
+ SVal V) const {
+ return addBinding(BindingKey::Make(R, k), V);
+}
+
+const SVal *RegionBindingsRef::lookup(BindingKey K) const {
+ const ClusterBindings *Cluster = lookup(K.getBaseRegion());
+ if (!Cluster)
+ return 0;
+ return Cluster->lookup(K);
+}
+
+const SVal *RegionBindingsRef::lookup(const MemRegion *R,
+ BindingKey::Kind k) const {
+ return lookup(BindingKey::Make(R, k));
+}
+
+RegionBindingsRef RegionBindingsRef::removeBinding(BindingKey K) {
+ const MemRegion *Base = K.getBaseRegion();
+ const ClusterBindings *Cluster = lookup(Base);
+ if (!Cluster)
+ return *this;
+
+ ClusterBindings NewCluster = CBFactory.remove(*Cluster, K);
+ if (NewCluster.isEmpty())
+ return remove(Base);
+ return add(Base, NewCluster);
+}
+
+RegionBindingsRef RegionBindingsRef::removeBinding(const MemRegion *R,
+ BindingKey::Kind k){
+ return removeBinding(BindingKey::Make(R, k));
+}
//===----------------------------------------------------------------------===//
// Fine-grained control of RegionStoreManager.
@@ -161,26 +318,38 @@ public:
//===----------------------------------------------------------------------===//
namespace {
+class invalidateRegionsWorker;
class RegionStoreManager : public StoreManager {
+public:
const RegionStoreFeatures Features;
RegionBindings::Factory RBFactory;
- ClusterBindings::Factory CBFactory;
+ mutable ClusterBindings::Factory CBFactory;
+
+ typedef std::vector<SVal> SValListTy;
+private:
+ typedef llvm::DenseMap<const LazyCompoundValData *,
+ SValListTy> LazyBindingsMapTy;
+ LazyBindingsMapTy LazyBindingsMap;
+
+ /// \brief A helper used to populate the work list with the given set of
+ /// regions.
+ void populateWorkList(invalidateRegionsWorker &W,
+ ArrayRef<SVal> Values,
+ bool IsArrayOfConstRegions,
+ InvalidatedRegions *TopLevelRegions);
public:
RegionStoreManager(ProgramStateManager& mgr, const RegionStoreFeatures &f)
: StoreManager(mgr), Features(f),
RBFactory(mgr.getAllocator()), CBFactory(mgr.getAllocator()) {}
- Optional<SVal> getDirectBinding(RegionBindings B, const MemRegion *R);
- /// getDefaultBinding - Returns an SVal* representing an optional default
- /// binding associated with a region and its subregions.
- Optional<SVal> getDefaultBinding(RegionBindings B, const MemRegion *R);
/// setImplicitDefaultValue - Set the default binding for the provided
/// MemRegion to the value implicitly defined for compound literals when
/// the value is not specified.
- StoreRef setImplicitDefaultValue(Store store, const MemRegion *R, QualType T);
+ RegionBindingsRef setImplicitDefaultValue(RegionBindingsConstRef B,
+ const MemRegion *R, QualType T);
/// ArrayToPointer - Emulates the "decay" of an array to a pointer
/// type. 'Array' represents the lvalue of the array being decayed
@@ -197,57 +366,47 @@ public:
//===-------------------------------------------------------------------===//
// Binding values to regions.
//===-------------------------------------------------------------------===//
- RegionBindings invalidateGlobalRegion(MemRegion::Kind K,
- const Expr *Ex,
- unsigned Count,
- const LocationContext *LCtx,
- RegionBindings B,
- InvalidatedRegions *Invalidated);
-
- StoreRef invalidateRegions(Store store, ArrayRef<const MemRegion *> Regions,
+ RegionBindingsRef invalidateGlobalRegion(MemRegion::Kind K,
+ const Expr *Ex,
+ unsigned Count,
+ const LocationContext *LCtx,
+ RegionBindingsRef B,
+ InvalidatedRegions *Invalidated);
+
+ StoreRef invalidateRegions(Store store,
+ ArrayRef<SVal> Values,
+ ArrayRef<SVal> ConstValues,
const Expr *E, unsigned Count,
const LocationContext *LCtx,
- InvalidatedSymbols &IS,
const CallEvent *Call,
- InvalidatedRegions *Invalidated);
+ InvalidatedSymbols &IS,
+ InvalidatedSymbols &ConstIS,
+ InvalidatedRegions *Invalidated,
+ InvalidatedRegions *InvalidatedTopLevel,
+ InvalidatedRegions *InvalidatedTopLevelConst);
bool scanReachableSymbols(Store S, const MemRegion *R,
ScanReachableSymbols &Callbacks);
-public: // Made public for helper classes.
-
- RegionBindings removeSubRegionBindings(RegionBindings B, const SubRegion *R);
-
- RegionBindings addBinding(RegionBindings B, BindingKey K, SVal V);
-
- RegionBindings addBinding(RegionBindings B, const MemRegion *R,
- BindingKey::Kind k, SVal V);
-
- const SVal *lookup(RegionBindings B, BindingKey K);
- const SVal *lookup(RegionBindings B, const MemRegion *R, BindingKey::Kind k);
+ RegionBindingsRef removeSubRegionBindings(RegionBindingsConstRef B,
+ const SubRegion *R);
- RegionBindings removeBinding(RegionBindings B, BindingKey K);
- RegionBindings removeBinding(RegionBindings B, const MemRegion *R,
- BindingKey::Kind k);
+public: // Part of public interface to class.
- RegionBindings removeBinding(RegionBindings B, const MemRegion *R) {
- return removeBinding(removeBinding(B, R, BindingKey::Direct), R,
- BindingKey::Default);
+ virtual StoreRef Bind(Store store, Loc LV, SVal V) {
+ return StoreRef(bind(getRegionBindings(store), LV, V).asStore(), *this);
}
- RegionBindings removeCluster(RegionBindings B, const MemRegion *R);
-
-public: // Part of public interface to class.
-
- StoreRef Bind(Store store, Loc LV, SVal V);
+ RegionBindingsRef bind(RegionBindingsConstRef B, Loc LV, SVal V);
// BindDefault is only used to initialize a region with a default value.
StoreRef BindDefault(Store store, const MemRegion *R, SVal V) {
- RegionBindings B = GetRegionBindings(store);
- assert(!lookup(B, R, BindingKey::Default));
- assert(!lookup(B, R, BindingKey::Direct));
- return StoreRef(addBinding(B, R, BindingKey::Default, V)
- .getRootWithoutRetain(), *this);
+ RegionBindingsRef B = getRegionBindings(store);
+ assert(!B.lookup(R, BindingKey::Default));
+ assert(!B.lookup(R, BindingKey::Direct));
+ return StoreRef(B.addBinding(R, BindingKey::Default, V)
+ .asImmutableMap()
+ .getRootWithoutRetain(), *this);
}
/// \brief Create a new store that binds a value to a compound literal.
@@ -265,31 +424,37 @@ public: // Part of public interface to class.
const LocationContext *LC, SVal V);
/// BindStruct - Bind a compound value to a structure.
- StoreRef BindStruct(Store store, const TypedValueRegion* R, SVal V);
+ RegionBindingsRef bindStruct(RegionBindingsConstRef B,
+ const TypedValueRegion* R, SVal V);
/// BindVector - Bind a compound value to a vector.
- StoreRef BindVector(Store store, const TypedValueRegion* R, SVal V);
+ RegionBindingsRef bindVector(RegionBindingsConstRef B,
+ const TypedValueRegion* R, SVal V);
- StoreRef BindArray(Store store, const TypedValueRegion* R, SVal V);
+ RegionBindingsRef bindArray(RegionBindingsConstRef B,
+ const TypedValueRegion* R,
+ SVal V);
/// Clears out all bindings in the given region and assigns a new value
/// as a Default binding.
- StoreRef BindAggregate(Store store, const TypedRegion *R, SVal DefaultVal);
+ RegionBindingsRef bindAggregate(RegionBindingsConstRef B,
+ const TypedRegion *R,
+ SVal DefaultVal);
/// \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);
+ virtual StoreRef killBinding(Store ST, Loc L);
void incrementReferenceCount(Store store) {
- GetRegionBindings(store).manualRetain();
+ getRegionBindings(store).manualRetain();
}
/// If the StoreManager supports it, decrement the reference count of
/// the specified Store object. If the reference count hits 0, the memory
/// associated with the object is recycled.
void decrementReferenceCount(Store store) {
- GetRegionBindings(store).manualRelease();
+ getRegionBindings(store).manualRelease();
}
bool includedInBindings(Store store, const MemRegion *region) const;
@@ -307,45 +472,64 @@ public: // Part of public interface to class.
/// return undefined
/// else
/// return symbolic
- SVal getBinding(Store store, Loc L, QualType T = QualType());
+ virtual SVal getBinding(Store S, Loc L, QualType T) {
+ return getBinding(getRegionBindings(S), L, T);
+ }
- SVal getBindingForElement(Store store, const ElementRegion *R);
+ SVal getBinding(RegionBindingsConstRef B, Loc L, QualType T = QualType());
- SVal getBindingForField(Store store, const FieldRegion *R);
+ SVal getBindingForElement(RegionBindingsConstRef B, const ElementRegion *R);
- SVal getBindingForObjCIvar(Store store, const ObjCIvarRegion *R);
+ SVal getBindingForField(RegionBindingsConstRef B, const FieldRegion *R);
- SVal getBindingForVar(Store store, const VarRegion *R);
+ SVal getBindingForObjCIvar(RegionBindingsConstRef B, const ObjCIvarRegion *R);
+
+ SVal getBindingForVar(RegionBindingsConstRef B, const VarRegion *R);
SVal getBindingForLazySymbol(const TypedValueRegion *R);
- SVal getBindingForFieldOrElementCommon(Store store, const TypedValueRegion *R,
- QualType Ty, const MemRegion *superR);
+ SVal getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
+ const TypedValueRegion *R,
+ QualType Ty,
+ const MemRegion *superR);
- SVal getLazyBinding(const MemRegion *lazyBindingRegion,
- Store lazyBindingStore);
+ SVal getLazyBinding(const SubRegion *LazyBindingRegion,
+ RegionBindingsRef LazyBinding);
/// Get bindings for the values in a struct and return a CompoundVal, used
/// when doing struct copy:
/// struct s x, y;
/// x = y;
/// y's value is retrieved by this method.
- SVal getBindingForStruct(Store store, const TypedValueRegion* R);
-
- SVal getBindingForArray(Store store, const TypedValueRegion* R);
+ SVal getBindingForStruct(RegionBindingsConstRef B, const TypedValueRegion *R);
+ SVal getBindingForArray(RegionBindingsConstRef B, const TypedValueRegion *R);
+ NonLoc createLazyBinding(RegionBindingsConstRef B, const TypedValueRegion *R);
/// Used to lazily generate derived symbols for bindings that are defined
- /// implicitly by default bindings in a super region.
- Optional<SVal> getBindingForDerivedDefaultValue(RegionBindings B,
+ /// implicitly by default bindings in a super region.
+ ///
+ /// Note that callers may need to specially handle LazyCompoundVals, which
+ /// are returned as is in case the caller needs to treat them differently.
+ Optional<SVal> getBindingForDerivedDefaultValue(RegionBindingsConstRef B,
const MemRegion *superR,
const TypedValueRegion *R,
QualType Ty);
- /// Get the state and region whose binding this region R corresponds to.
- std::pair<Store, const MemRegion*>
- GetLazyBinding(RegionBindings B, const MemRegion *R,
- const MemRegion *originalRegion,
- bool includeSuffix = false);
+ /// Get the state and region whose binding this region \p R corresponds to.
+ ///
+ /// If there is no lazy binding for \p R, the returned value will have a null
+ /// \c second. Note that a null pointer can represents a valid Store.
+ std::pair<Store, const SubRegion *>
+ findLazyBinding(RegionBindingsConstRef B, const SubRegion *R,
+ const SubRegion *originalRegion);
+
+ /// Returns the cached set of interesting SVals contained within a lazy
+ /// binding.
+ ///
+ /// The precise value of "interesting" is determined for the purposes of
+ /// RegionStore's internal analysis. It must always contain all regions and
+ /// symbols, but may omit constants and other kinds of SVal.
+ const SValListTy &getInterestingValues(nonloc::LazyCompoundVal LCV);
//===------------------------------------------------------------------===//
// State pruning.
@@ -368,16 +552,18 @@ public: // Part of public interface to class.
// Utility methods.
//===------------------------------------------------------------------===//
- static inline RegionBindings GetRegionBindings(Store store) {
- return RegionBindings(static_cast<const RegionBindings::TreeTy*>(store));
+ RegionBindingsRef getRegionBindings(Store store) const {
+ return RegionBindingsRef(CBFactory,
+ static_cast<const RegionBindings::TreeTy*>(store),
+ RBFactory.getTreeFactory());
}
void print(Store store, raw_ostream &Out, const char* nl,
const char *sep);
void iterBindings(Store store, BindingsHandler& f) {
- RegionBindings B = GetRegionBindings(store);
- for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
+ RegionBindingsRef B = getRegionBindings(store);
+ for (RegionBindingsRef::iterator I = B.begin(), E = B.end(); I != E; ++I) {
const ClusterBindings &Cluster = I.getData();
for (ClusterBindings::iterator CI = Cluster.begin(), CE = Cluster.end();
CI != CE; ++CI) {
@@ -422,7 +608,8 @@ template <typename DERIVED>
class ClusterAnalysis {
protected:
typedef llvm::DenseMap<const MemRegion *, const ClusterBindings *> ClusterMap;
- typedef SmallVector<const MemRegion *, 10> WorkList;
+ typedef llvm::PointerIntPair<const MemRegion *, 1, bool> WorkListElement;
+ typedef SmallVector<WorkListElement, 10> WorkList;
llvm::SmallPtrSet<const ClusterBindings *, 16> Visited;
@@ -432,7 +619,7 @@ protected:
ASTContext &Ctx;
SValBuilder &svalBuilder;
- RegionBindings B;
+ RegionBindingsRef B;
const bool includeGlobals;
@@ -442,12 +629,12 @@ protected:
public:
ClusterAnalysis(RegionStoreManager &rm, ProgramStateManager &StateMgr,
- RegionBindings b, const bool includeGlobals)
+ RegionBindingsRef b, const bool includeGlobals)
: RM(rm), Ctx(StateMgr.getContext()),
svalBuilder(StateMgr.getSValBuilder()),
B(b), includeGlobals(includeGlobals) {}
- RegionBindings getRegionBindings() const { return B; }
+ RegionBindingsRef getRegionBindings() const { return B; }
bool isVisited(const MemRegion *R) {
return Visited.count(getCluster(R));
@@ -455,7 +642,8 @@ public:
void GenerateClusters() {
// Scan the entire set of bindings and record the region clusters.
- for (RegionBindings::iterator RI = B.begin(), RE = B.end(); RI != RE; ++RI){
+ for (RegionBindingsRef::iterator RI = B.begin(), RE = B.end();
+ RI != RE; ++RI){
const MemRegion *Base = RI.getKey();
const ClusterBindings &Cluster = RI.getData();
@@ -468,35 +656,35 @@ public:
}
}
- bool AddToWorkList(const MemRegion *R, const ClusterBindings *C) {
+ bool AddToWorkList(WorkListElement E, const ClusterBindings *C) {
if (C && !Visited.insert(C))
return false;
- WL.push_back(R);
+ WL.push_back(E);
return true;
}
- bool AddToWorkList(const MemRegion *R) {
- const MemRegion *baseR = R->getBaseRegion();
- return AddToWorkList(baseR, getCluster(baseR));
+ bool AddToWorkList(const MemRegion *R, bool Flag = false) {
+ const MemRegion *BaseR = R->getBaseRegion();
+ return AddToWorkList(WorkListElement(BaseR, Flag), getCluster(BaseR));
}
void RunWorkList() {
while (!WL.empty()) {
- const MemRegion *baseR = WL.pop_back_val();
+ WorkListElement E = WL.pop_back_val();
+ const MemRegion *BaseR = E.getPointer();
- // First visit the cluster.
- if (const ClusterBindings *Cluster = getCluster(baseR))
- static_cast<DERIVED*>(this)->VisitCluster(baseR, *Cluster);
-
- // Next, visit the base region.
- static_cast<DERIVED*>(this)->VisitBaseRegion(baseR);
+ static_cast<DERIVED*>(this)->VisitCluster(BaseR, getCluster(BaseR),
+ E.getInt());
}
}
-public:
void VisitAddedToCluster(const MemRegion *baseR, const ClusterBindings &C) {}
- void VisitCluster(const MemRegion *baseR, const ClusterBindings &C) {}
- void VisitBaseRegion(const MemRegion *baseR) {}
+ void VisitCluster(const MemRegion *baseR, const ClusterBindings *C) {}
+
+ void VisitCluster(const MemRegion *BaseR, const ClusterBindings *C,
+ bool Flag) {
+ static_cast<DERIVED*>(this)->VisitCluster(BaseR, C);
+ }
};
}
@@ -507,7 +695,7 @@ public:
bool RegionStoreManager::scanReachableSymbols(Store S, const MemRegion *R,
ScanReachableSymbols &Callbacks) {
assert(R == R->getBaseRegion() && "Should only be called for base regions");
- RegionBindings B = GetRegionBindings(S);
+ RegionBindingsRef B = getRegionBindings(S);
const ClusterBindings *Cluster = B.lookup(R);
if (!Cluster)
@@ -562,98 +750,141 @@ static bool isCompatibleWithFields(BindingKey K, const FieldVector &Fields) {
Fields.begin() - Delta);
}
-RegionBindings RegionStoreManager::removeSubRegionBindings(RegionBindings B,
- const SubRegion *R) {
- BindingKey SRKey = BindingKey::Make(R, BindingKey::Default);
- const MemRegion *ClusterHead = SRKey.getBaseRegion();
- if (R == ClusterHead) {
- // We can remove an entire cluster's bindings all in one go.
- return RBFactory.remove(B, R);
- }
-
+/// Collects all bindings in \p Cluster that may refer to bindings within
+/// \p Top.
+///
+/// Each binding is a pair whose \c first is the key (a BindingKey) and whose
+/// \c second is the value (an SVal).
+///
+/// The \p IncludeAllDefaultBindings parameter specifies whether to include
+/// default bindings that may extend beyond \p Top itself, e.g. if \p Top is
+/// an aggregate within a larger aggregate with a default binding.
+static void
+collectSubRegionBindings(SmallVectorImpl<BindingPair> &Bindings,
+ SValBuilder &SVB, const ClusterBindings &Cluster,
+ const SubRegion *Top, BindingKey TopKey,
+ bool IncludeAllDefaultBindings) {
FieldVector FieldsInSymbolicSubregions;
- bool HasSymbolicOffset = SRKey.hasSymbolicOffset();
- if (HasSymbolicOffset) {
- getSymbolicOffsetFields(SRKey, FieldsInSymbolicSubregions);
- R = cast<SubRegion>(SRKey.getConcreteOffsetRegion());
- SRKey = BindingKey::Make(R, BindingKey::Default);
+ if (TopKey.hasSymbolicOffset()) {
+ getSymbolicOffsetFields(TopKey, FieldsInSymbolicSubregions);
+ Top = cast<SubRegion>(TopKey.getConcreteOffsetRegion());
+ TopKey = BindingKey::Make(Top, BindingKey::Default);
}
- // This assumes the region being invalidated is char-aligned. This isn't
- // true for bitfields, but since bitfields have no subregions they shouldn't
- // be using this function anyway.
+ // Find the length (in bits) of the region being invalidated.
uint64_t Length = UINT64_MAX;
-
- SVal Extent = R->getExtent(svalBuilder);
- if (nonloc::ConcreteInt *ExtentCI = dyn_cast<nonloc::ConcreteInt>(&Extent)) {
+ SVal Extent = Top->getExtent(SVB);
+ if (Optional<nonloc::ConcreteInt> ExtentCI =
+ Extent.getAs<nonloc::ConcreteInt>()) {
const llvm::APSInt &ExtentInt = ExtentCI->getValue();
assert(ExtentInt.isNonNegative() || ExtentInt.isUnsigned());
// Extents are in bytes but region offsets are in bits. Be careful!
- Length = ExtentInt.getLimitedValue() * Ctx.getCharWidth();
+ Length = ExtentInt.getLimitedValue() * SVB.getContext().getCharWidth();
+ } else if (const FieldRegion *FR = dyn_cast<FieldRegion>(Top)) {
+ if (FR->getDecl()->isBitField())
+ Length = FR->getDecl()->getBitWidthValue(SVB.getContext());
}
- const ClusterBindings *Cluster = B.lookup(ClusterHead);
- if (!Cluster)
- return B;
-
- ClusterBindings Result = *Cluster;
-
- // It is safe to iterate over the bindings as they are being changed
- // because they are in an ImmutableMap.
- for (ClusterBindings::iterator I = Cluster->begin(), E = Cluster->end();
+ for (ClusterBindings::iterator I = Cluster.begin(), E = Cluster.end();
I != E; ++I) {
BindingKey NextKey = I.getKey();
- if (NextKey.getRegion() == SRKey.getRegion()) {
+ if (NextKey.getRegion() == TopKey.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) {
+ if (NextKey.getOffset() > TopKey.getOffset() &&
+ NextKey.getOffset() - TopKey.getOffset() < Length) {
// Case 1: The next binding is inside the region we're invalidating.
- // Remove it.
- Result = CBFactory.remove(Result, NextKey);
+ // Include it.
+ Bindings.push_back(*I);
- } else if (NextKey.getOffset() == SRKey.getOffset()) {
+ } else if (NextKey.getOffset() == TopKey.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,
// since they may be providing a default value for a regions beyond what
// we're invalidating.
// FIXME: This is probably incorrect; consider invalidating an outer
// struct whose first field is bound to a LazyCompoundVal.
- if (NextKey.isDirect())
- Result = CBFactory.remove(Result, NextKey);
+ if (IncludeAllDefaultBindings || NextKey.isDirect())
+ Bindings.push_back(*I);
}
-
+
} else if (NextKey.hasSymbolicOffset()) {
const MemRegion *Base = NextKey.getConcreteOffsetRegion();
- if (R->isSubRegionOf(Base)) {
+ if (Top->isSubRegionOf(Base)) {
// Case 3: The next key is symbolic and we just changed something within
// its concrete region. We don't know if the binding is still valid, so
- // we'll be conservative and remove it.
- if (NextKey.isDirect())
+ // we'll be conservative and include it.
+ if (IncludeAllDefaultBindings || NextKey.isDirect())
if (isCompatibleWithFields(NextKey, FieldsInSymbolicSubregions))
- Result = CBFactory.remove(Result, NextKey);
+ Bindings.push_back(*I);
} else if (const SubRegion *BaseSR = dyn_cast<SubRegion>(Base)) {
// Case 4: The next key is symbolic, but we changed a known
- // super-region. In this case the binding is certainly no longer valid.
- if (R == Base || BaseSR->isSubRegionOf(R))
+ // super-region. In this case the binding is certainly included.
+ if (Top == Base || BaseSR->isSubRegionOf(Top))
if (isCompatibleWithFields(NextKey, FieldsInSymbolicSubregions))
- Result = CBFactory.remove(Result, NextKey);
+ Bindings.push_back(*I);
}
}
}
+}
+
+static void
+collectSubRegionBindings(SmallVectorImpl<BindingPair> &Bindings,
+ SValBuilder &SVB, const ClusterBindings &Cluster,
+ const SubRegion *Top, bool IncludeAllDefaultBindings) {
+ collectSubRegionBindings(Bindings, SVB, Cluster, Top,
+ BindingKey::Make(Top, BindingKey::Default),
+ IncludeAllDefaultBindings);
+}
+
+RegionBindingsRef
+RegionStoreManager::removeSubRegionBindings(RegionBindingsConstRef B,
+ const SubRegion *Top) {
+ BindingKey TopKey = BindingKey::Make(Top, BindingKey::Default);
+ const MemRegion *ClusterHead = TopKey.getBaseRegion();
+
+ if (Top == ClusterHead) {
+ // We can remove an entire cluster's bindings all in one go.
+ return B.remove(Top);
+ }
+
+ const ClusterBindings *Cluster = B.lookup(ClusterHead);
+ if (!Cluster) {
+ // 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.
+ if (TopKey.hasSymbolicOffset()) {
+ const SubRegion *Concrete = TopKey.getConcreteOffsetRegion();
+ return B.addBinding(Concrete, BindingKey::Default, UnknownVal());
+ }
+ return B;
+ }
+
+ SmallVector<BindingPair, 32> Bindings;
+ collectSubRegionBindings(Bindings, svalBuilder, *Cluster, Top, TopKey,
+ /*IncludeAllDefaultBindings=*/false);
+
+ ClusterBindingsRef Result(*Cluster, CBFactory);
+ for (SmallVectorImpl<BindingPair>::const_iterator I = Bindings.begin(),
+ E = Bindings.end();
+ I != E; ++I)
+ Result = Result.remove(I->first);
// 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());
+ // FIXME: This isn't very precise; see the example in
+ // collectSubRegionBindings.
+ if (TopKey.hasSymbolicOffset()) {
+ const SubRegion *Concrete = TopKey.getConcreteOffsetRegion();
+ Result = Result.add(BindingKey::Make(Concrete, BindingKey::Default),
+ UnknownVal());
+ }
if (Result.isEmpty())
- return RBFactory.remove(B, ClusterHead);
- return RBFactory.add(B, ClusterHead, Result);
+ return B.remove(ClusterHead);
+ return B.add(ClusterHead, Result.asImmutableMap());
}
namespace {
@@ -662,24 +893,26 @@ class invalidateRegionsWorker : public ClusterAnalysis<invalidateRegionsWorker>
const Expr *Ex;
unsigned Count;
const LocationContext *LCtx;
- StoreManager::InvalidatedSymbols &IS;
+ InvalidatedSymbols &IS;
+ InvalidatedSymbols &ConstIS;
StoreManager::InvalidatedRegions *Regions;
public:
invalidateRegionsWorker(RegionStoreManager &rm,
ProgramStateManager &stateMgr,
- RegionBindings b,
+ RegionBindingsRef b,
const Expr *ex, unsigned count,
const LocationContext *lctx,
- StoreManager::InvalidatedSymbols &is,
+ InvalidatedSymbols &is,
+ InvalidatedSymbols &inConstIS,
StoreManager::InvalidatedRegions *r,
bool includeGlobals)
: ClusterAnalysis<invalidateRegionsWorker>(rm, stateMgr, b, includeGlobals),
- Ex(ex), Count(count), LCtx(lctx), IS(is), Regions(r) {}
+ Ex(ex), Count(count), LCtx(lctx), IS(is), ConstIS(inConstIS), Regions(r){}
- void VisitCluster(const MemRegion *baseR, const ClusterBindings &C);
- void VisitBaseRegion(const MemRegion *baseR);
-
-private:
+ /// \param IsConst Specifies if the region we are invalidating is constant.
+ /// If it is, we invalidate all subregions, but not the base region itself.
+ void VisitCluster(const MemRegion *baseR, const ClusterBindings *C,
+ bool IsConst);
void VisitBinding(SVal V);
};
}
@@ -695,43 +928,30 @@ void invalidateRegionsWorker::VisitBinding(SVal V) {
}
// Is it a LazyCompoundVal? All references get invalidated as well.
- if (const nonloc::LazyCompoundVal *LCS =
- dyn_cast<nonloc::LazyCompoundVal>(&V)) {
+ if (Optional<nonloc::LazyCompoundVal> LCS =
+ V.getAs<nonloc::LazyCompoundVal>()) {
- const MemRegion *LazyR = LCS->getRegion();
- RegionBindings B = RegionStoreManager::GetRegionBindings(LCS->getStore());
+ const RegionStoreManager::SValListTy &Vals = RM.getInterestingValues(*LCS);
- // FIXME: This should not have to walk all bindings in the old store.
- for (RegionBindings::iterator RI = B.begin(), RE = B.end(); RI != RE; ++RI){
- const ClusterBindings &Cluster = RI.getData();
- for (ClusterBindings::iterator CI = Cluster.begin(), CE = Cluster.end();
- CI != CE; ++CI) {
- BindingKey K = CI.getKey();
- if (const SubRegion *BaseR = dyn_cast<SubRegion>(K.getRegion())) {
- if (BaseR == LazyR)
- VisitBinding(CI.getData());
- else if (K.hasSymbolicOffset() && BaseR->isSubRegionOf(LazyR))
- VisitBinding(CI.getData());
- }
- }
- }
+ for (RegionStoreManager::SValListTy::const_iterator I = Vals.begin(),
+ E = Vals.end();
+ I != E; ++I)
+ VisitBinding(*I);
return;
}
}
-void invalidateRegionsWorker::VisitCluster(const MemRegion *BaseR,
- const ClusterBindings &C) {
- for (ClusterBindings::iterator I = C.begin(), E = C.end(); I != E; ++I)
- VisitBinding(I.getData());
-
- B = RM.removeCluster(B, BaseR);
-}
+void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
+ const ClusterBindings *C,
+ bool IsConst) {
+ if (C) {
+ for (ClusterBindings::iterator I = C->begin(), E = C->end(); I != E; ++I)
+ VisitBinding(I.getData());
-void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
- // Symbolic region? Mark that symbol touched by the invalidation.
- if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR))
- IS.insert(SR->getSymbol());
+ if (!IsConst)
+ B = B.remove(baseR);
+ }
// BlockDataRegion? If so, invalidate captured variables that are passed
// by reference.
@@ -739,7 +959,7 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
for (BlockDataRegion::referenced_vars_iterator
BI = BR->referenced_vars_begin(), BE = BR->referenced_vars_end() ;
BI != BE; ++BI) {
- const VarRegion *VR = *BI;
+ const VarRegion *VR = BI.getCapturedRegion();
const VarDecl *VD = VR->getDecl();
if (VD->getAttr<BlocksAttr>() || !VD->hasLocalStorage()) {
AddToWorkList(VR);
@@ -750,9 +970,8 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
// invalidate that region. This is because a block may capture
// a pointer value, but the thing pointed by that pointer may
// get invalidated.
- Store store = B.getRootWithoutRetain();
- SVal V = RM.getBinding(store, loc::MemRegionVal(VR));
- if (const Loc *L = dyn_cast<Loc>(&V)) {
+ SVal V = RM.getBinding(B, loc::MemRegionVal(VR));
+ if (Optional<Loc> L = V.getAs<Loc>()) {
if (const MemRegion *LR = L->getAsRegion())
AddToWorkList(LR);
}
@@ -761,6 +980,20 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
return;
}
+ // Symbolic region?
+ SymbolRef RegionSym = 0;
+ if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR))
+ RegionSym = SR->getSymbol();
+
+ if (IsConst) {
+ // Mark that symbol touched by the invalidation.
+ ConstIS.insert(RegionSym);
+ return;
+ }
+
+ // Mark that symbol touched by the invalidation.
+ IS.insert(RegionSym);
+
// Otherwise, we have a normal data region. Record that we touched the region.
if (Regions)
Regions->push_back(baseR);
@@ -770,7 +1003,7 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
// conjured symbol. The type of the symbol is irrelavant.
DefinedOrUnknownSVal V =
svalBuilder.conjureSymbolVal(baseR, Ex, LCtx, Ctx.IntTy, Count);
- B = RM.addBinding(B, baseR, BindingKey::Default, V);
+ B = B.addBinding(baseR, BindingKey::Default, V);
return;
}
@@ -786,7 +1019,7 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
// conjured symbol. The type of the symbol is irrelavant.
DefinedOrUnknownSVal V = svalBuilder.conjureSymbolVal(baseR, Ex, LCtx,
Ctx.IntTy, Count);
- B = RM.addBinding(B, baseR, BindingKey::Default, V);
+ B = B.addBinding(baseR, BindingKey::Default, V);
return;
}
@@ -795,7 +1028,7 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
DefinedOrUnknownSVal V =
svalBuilder.conjureSymbolVal(baseR, Ex, LCtx,
AT->getElementType(), Count);
- B = RM.addBinding(B, baseR, BindingKey::Default, V);
+ B = B.addBinding(baseR, BindingKey::Default, V);
return;
}
@@ -804,7 +1037,7 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
// If the region is a global and we are invalidating all globals,
// just erase the entry. This causes all globals to be lazily
// symbolicated from the same base symbol.
- B = RM.removeBinding(B, baseR);
+ B = B.removeBinding(baseR);
return;
}
@@ -812,15 +1045,16 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
DefinedOrUnknownSVal V = svalBuilder.conjureSymbolVal(baseR, Ex, LCtx,
T,Count);
assert(SymbolManager::canSymbolicate(T) || V.isUnknown());
- B = RM.addBinding(B, baseR, BindingKey::Direct, V);
+ B = B.addBinding(baseR, BindingKey::Direct, V);
}
-RegionBindings RegionStoreManager::invalidateGlobalRegion(MemRegion::Kind K,
- const Expr *Ex,
- unsigned Count,
- const LocationContext *LCtx,
- RegionBindings B,
- InvalidatedRegions *Invalidated) {
+RegionBindingsRef
+RegionStoreManager::invalidateGlobalRegion(MemRegion::Kind K,
+ const Expr *Ex,
+ unsigned Count,
+ const LocationContext *LCtx,
+ RegionBindingsRef B,
+ InvalidatedRegions *Invalidated) {
// 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);
@@ -828,8 +1062,8 @@ RegionBindings RegionStoreManager::invalidateGlobalRegion(MemRegion::Kind K,
/* type does not matter */ Ctx.IntTy,
Count);
- B = removeBinding(B, GS);
- B = addBinding(B, BindingKey::Make(GS, BindingKey::Default), V);
+ B = B.removeBinding(GS)
+ .addBinding(BindingKey::Make(GS, BindingKey::Default), V);
// Even if there are no bindings in the global scope, we still need to
// record that we touched it.
@@ -839,47 +1073,82 @@ RegionBindings RegionStoreManager::invalidateGlobalRegion(MemRegion::Kind K,
return B;
}
-StoreRef RegionStoreManager::invalidateRegions(Store store,
- ArrayRef<const MemRegion *> Regions,
- const Expr *Ex, unsigned Count,
- const LocationContext *LCtx,
- InvalidatedSymbols &IS,
- const CallEvent *Call,
- InvalidatedRegions *Invalidated) {
- invalidateRegionsWorker W(*this, StateMgr,
- RegionStoreManager::GetRegionBindings(store),
- Ex, Count, LCtx, IS, Invalidated, false);
+void RegionStoreManager::populateWorkList(invalidateRegionsWorker &W,
+ ArrayRef<SVal> Values,
+ bool IsArrayOfConstRegions,
+ InvalidatedRegions *TopLevelRegions) {
+ for (ArrayRef<SVal>::iterator I = Values.begin(),
+ E = Values.end(); I != E; ++I) {
+ SVal V = *I;
+ if (Optional<nonloc::LazyCompoundVal> LCS =
+ V.getAs<nonloc::LazyCompoundVal>()) {
+
+ const SValListTy &Vals = getInterestingValues(*LCS);
+
+ for (SValListTy::const_iterator I = Vals.begin(),
+ E = Vals.end(); I != E; ++I) {
+ // Note: the last argument is false here because these are
+ // non-top-level regions.
+ if (const MemRegion *R = (*I).getAsRegion())
+ W.AddToWorkList(R, /*IsConst=*/ false);
+ }
+ continue;
+ }
+
+ if (const MemRegion *R = V.getAsRegion()) {
+ if (TopLevelRegions)
+ TopLevelRegions->push_back(R);
+ W.AddToWorkList(R, /*IsConst=*/ IsArrayOfConstRegions);
+ continue;
+ }
+ }
+}
+
+StoreRef
+RegionStoreManager::invalidateRegions(Store store,
+ ArrayRef<SVal> Values,
+ ArrayRef<SVal> ConstValues,
+ const Expr *Ex, unsigned Count,
+ const LocationContext *LCtx,
+ const CallEvent *Call,
+ InvalidatedSymbols &IS,
+ InvalidatedSymbols &ConstIS,
+ InvalidatedRegions *TopLevelRegions,
+ InvalidatedRegions *TopLevelConstRegions,
+ InvalidatedRegions *Invalidated) {
+ RegionBindingsRef B = RegionStoreManager::getRegionBindings(store);
+ invalidateRegionsWorker W(*this, StateMgr, B, Ex, Count, LCtx, IS, ConstIS,
+ Invalidated, false);
// Scan the bindings and generate the clusters.
W.GenerateClusters();
// Add the regions to the worklist.
- for (ArrayRef<const MemRegion *>::iterator
- I = Regions.begin(), E = Regions.end(); I != E; ++I)
- W.AddToWorkList(*I);
+ populateWorkList(W, Values, /*IsArrayOfConstRegions*/ false,
+ TopLevelRegions);
+ populateWorkList(W, ConstValues, /*IsArrayOfConstRegions*/ true,
+ TopLevelConstRegions);
W.RunWorkList();
// Return the new bindings.
- RegionBindings B = W.getRegionBindings();
+ B = W.getRegionBindings();
- // For all globals which are not static nor immutable: determine which global
- // regions should be invalidated and invalidate them.
+ // For calls, determine which global regions should be invalidated and
+ // invalidate them. (Note that function-static and immutable globals are never
+ // invalidated by this.)
// TODO: This could possibly be more precise with modules.
- //
- // System calls invalidate only system globals.
- if (Call && Call->isInSystemHeader()) {
+ if (Call) {
B = invalidateGlobalRegion(MemRegion::GlobalSystemSpaceRegionKind,
Ex, Count, LCtx, B, Invalidated);
- // Internal calls might invalidate both system and internal globals.
- } else {
- B = invalidateGlobalRegion(MemRegion::GlobalSystemSpaceRegionKind,
- Ex, Count, LCtx, B, Invalidated);
- B = invalidateGlobalRegion(MemRegion::GlobalInternalSpaceRegionKind,
- Ex, Count, LCtx, B, Invalidated);
+
+ if (!Call->isInSystemHeader()) {
+ B = invalidateGlobalRegion(MemRegion::GlobalInternalSpaceRegionKind,
+ Ex, Count, LCtx, B, Invalidated);
+ }
}
- return StoreRef(B.getRootWithoutRetain(), *this);
+ return StoreRef(B.asStore(), *this);
}
//===----------------------------------------------------------------------===//
@@ -923,10 +1192,10 @@ RegionStoreManager::getSizeInElements(ProgramStateRef state,
/// the array). This is called by ExprEngine when evaluating casts
/// from arrays to pointers.
SVal RegionStoreManager::ArrayToPointer(Loc Array) {
- if (!isa<loc::MemRegionVal>(Array))
+ if (!Array.getAs<loc::MemRegionVal>())
return UnknownVal();
- const MemRegion* R = cast<loc::MemRegionVal>(&Array)->getRegion();
+ const MemRegion* R = Array.castAs<loc::MemRegionVal>().getRegion();
const TypedValueRegion* ArrayR = dyn_cast<TypedValueRegion>(R);
if (!ArrayR)
@@ -945,31 +1214,9 @@ SVal RegionStoreManager::ArrayToPointer(Loc Array) {
// Loading values from regions.
//===----------------------------------------------------------------------===//
-Optional<SVal> RegionStoreManager::getDirectBinding(RegionBindings B,
- const MemRegion *R) {
-
- if (const SVal *V = lookup(B, R, BindingKey::Direct))
- return *V;
-
- return Optional<SVal>();
-}
-
-Optional<SVal> RegionStoreManager::getDefaultBinding(RegionBindings B,
- const MemRegion *R) {
- if (R->isBoundable())
- if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R))
- if (TR->getValueType()->isUnionType())
- return UnknownVal();
-
- if (const SVal *V = lookup(B, R, BindingKey::Default))
- return *V;
-
- return Optional<SVal>();
-}
-
-SVal RegionStoreManager::getBinding(Store store, Loc L, QualType T) {
- assert(!isa<UnknownVal>(L) && "location unknown");
- assert(!isa<UndefinedVal>(L) && "location undefined");
+SVal RegionStoreManager::getBinding(RegionBindingsConstRef B, Loc L, QualType T) {
+ assert(!L.getAs<UnknownVal>() && "location unknown");
+ assert(!L.getAs<UndefinedVal>() && "location undefined");
// For access to concrete addresses, return UnknownVal. Checks
// for null dereferences (and similar errors) are done by checkers, not
@@ -977,14 +1224,14 @@ SVal RegionStoreManager::getBinding(Store store, Loc L, QualType T) {
// FIXME: We can consider lazily symbolicating such memory, but we really
// should defer this when we can reason easily about symbolicating arrays
// of bytes.
- if (isa<loc::ConcreteInt>(L)) {
+ if (L.getAs<loc::ConcreteInt>()) {
return UnknownVal();
}
- if (!isa<loc::MemRegionVal>(L)) {
+ if (!L.getAs<loc::MemRegionVal>()) {
return UnknownVal();
}
- const MemRegion *MR = cast<loc::MemRegionVal>(L).getRegion();
+ const MemRegion *MR = L.castAs<loc::MemRegionVal>().getRegion();
if (isa<AllocaRegion>(MR) ||
isa<SymbolicRegion>(MR) ||
@@ -1005,6 +1252,11 @@ SVal RegionStoreManager::getBinding(Store store, Loc L, QualType T) {
const TypedValueRegion *R = cast<TypedValueRegion>(MR);
QualType RTy = R->getValueType();
+ // FIXME: we do not yet model the parts of a complex type, so treat the
+ // whole thing as "unknown".
+ if (RTy->isAnyComplexType())
+ return UnknownVal();
+
// FIXME: We should eventually handle funny addressing. e.g.:
//
// int x = ...;
@@ -1013,9 +1265,8 @@ SVal RegionStoreManager::getBinding(Store store, Loc L, QualType T) {
// char c = *q; // returns the first byte of 'x'.
//
// Such funny addressing will occur due to layering of regions.
-
if (RTy->isStructureOrClassType())
- return getBindingForStruct(store, R);
+ return getBindingForStruct(B, R);
// FIXME: Handle unions.
if (RTy->isUnionType())
@@ -1023,7 +1274,7 @@ SVal RegionStoreManager::getBinding(Store store, Loc L, QualType T) {
if (RTy->isArrayType()) {
if (RTy->isConstantArrayType())
- return getBindingForArray(store, R);
+ return getBindingForArray(B, R);
else
return UnknownVal();
}
@@ -1033,7 +1284,7 @@ SVal RegionStoreManager::getBinding(Store store, Loc L, QualType T) {
return UnknownVal();
if (const FieldRegion* FR = dyn_cast<FieldRegion>(R))
- return CastRetrievedVal(getBindingForField(store, FR), FR, T, false);
+ return CastRetrievedVal(getBindingForField(B, FR), FR, T, false);
if (const ElementRegion* ER = dyn_cast<ElementRegion>(R)) {
// FIXME: Here we actually perform an implicit conversion from the loaded
@@ -1041,7 +1292,7 @@ SVal RegionStoreManager::getBinding(Store store, Loc L, QualType T) {
// more intelligently. For example, an 'element' can encompass multiple
// bound regions (e.g., several bound bytes), or could be a subset of
// a larger value.
- return CastRetrievedVal(getBindingForElement(store, ER), ER, T, false);
+ return CastRetrievedVal(getBindingForElement(B, ER), ER, T, false);
}
if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R)) {
@@ -1051,7 +1302,7 @@ SVal RegionStoreManager::getBinding(Store store, Loc L, QualType T) {
// reinterpretted, it is possible we stored a different value that could
// fit within the ivar. Either we need to cast these when storing them
// or reinterpret them lazily (as we do here).
- return CastRetrievedVal(getBindingForObjCIvar(store, IVR), IVR, T, false);
+ return CastRetrievedVal(getBindingForObjCIvar(B, IVR), IVR, T, false);
}
if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
@@ -1061,11 +1312,10 @@ SVal RegionStoreManager::getBinding(Store store, Loc L, QualType T) {
// variable is reinterpretted, it is possible we stored a different value
// that could fit within the variable. Either we need to cast these when
// storing them or reinterpret them lazily (as we do here).
- return CastRetrievedVal(getBindingForVar(store, VR), VR, T, false);
+ return CastRetrievedVal(getBindingForVar(B, VR), VR, T, false);
}
- RegionBindings B = GetRegionBindings(store);
- const SVal *V = lookup(B, R, BindingKey::Direct);
+ const SVal *V = B.lookup(R, BindingKey::Direct);
// Check if the region has a binding.
if (V)
@@ -1086,69 +1336,109 @@ SVal RegionStoreManager::getBinding(Store store, Loc L, QualType T) {
return svalBuilder.getRegionValueSymbolVal(R);
}
-std::pair<Store, const MemRegion *>
-RegionStoreManager::GetLazyBinding(RegionBindings B, const MemRegion *R,
- const MemRegion *originalRegion,
- bool includeSuffix) {
-
+static QualType getUnderlyingType(const SubRegion *R) {
+ QualType RegionTy;
+ if (const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(R))
+ RegionTy = TVR->getValueType();
+
+ if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R))
+ RegionTy = SR->getSymbol()->getType();
+
+ return RegionTy;
+}
+
+/// Checks to see if store \p B has a lazy binding for region \p R.
+///
+/// If \p AllowSubregionBindings is \c false, a lazy binding will be rejected
+/// if there are additional bindings within \p R.
+///
+/// Note that unlike RegionStoreManager::findLazyBinding, this will not search
+/// for lazy bindings for super-regions of \p R.
+static Optional<nonloc::LazyCompoundVal>
+getExistingLazyBinding(SValBuilder &SVB, RegionBindingsConstRef B,
+ const SubRegion *R, bool AllowSubregionBindings) {
+ Optional<SVal> V = B.getDefaultBinding(R);
+ if (!V)
+ return None;
+
+ Optional<nonloc::LazyCompoundVal> LCV = V->getAs<nonloc::LazyCompoundVal>();
+ if (!LCV)
+ return None;
+
+ // If the LCV is for a subregion, the types might not match, and we shouldn't
+ // reuse the binding.
+ QualType RegionTy = getUnderlyingType(R);
+ if (!RegionTy.isNull() &&
+ !RegionTy->isVoidPointerType()) {
+ QualType SourceRegionTy = LCV->getRegion()->getValueType();
+ if (!SVB.getContext().hasSameUnqualifiedType(RegionTy, SourceRegionTy))
+ return None;
+ }
+
+ if (!AllowSubregionBindings) {
+ // If there are any other bindings within this region, we shouldn't reuse
+ // the top-level binding.
+ SmallVector<BindingPair, 16> Bindings;
+ collectSubRegionBindings(Bindings, SVB, *B.lookup(R->getBaseRegion()), R,
+ /*IncludeAllDefaultBindings=*/true);
+ if (Bindings.size() > 1)
+ return None;
+ }
+
+ return *LCV;
+}
+
+
+std::pair<Store, const SubRegion *>
+RegionStoreManager::findLazyBinding(RegionBindingsConstRef B,
+ const SubRegion *R,
+ const SubRegion *originalRegion) {
if (originalRegion != R) {
- if (Optional<SVal> OV = getDefaultBinding(B, R)) {
- if (const nonloc::LazyCompoundVal *V =
- dyn_cast<nonloc::LazyCompoundVal>(OV.getPointer()))
- return std::make_pair(V->getStore(), V->getRegion());
- }
+ if (Optional<nonloc::LazyCompoundVal> V =
+ getExistingLazyBinding(svalBuilder, B, R, true))
+ return std::make_pair(V->getStore(), V->getRegion());
}
-
+
+ typedef std::pair<Store, const SubRegion *> StoreRegionPair;
+ StoreRegionPair Result = StoreRegionPair();
+
if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
- const std::pair<Store, const MemRegion *> &X =
- GetLazyBinding(B, ER->getSuperRegion(), originalRegion);
-
- if (X.second)
- return std::make_pair(X.first,
- MRMgr.getElementRegionWithSuper(ER, X.second));
- }
- else if (const FieldRegion *FR = dyn_cast<FieldRegion>(R)) {
- const std::pair<Store, const MemRegion *> &X =
- GetLazyBinding(B, FR->getSuperRegion(), originalRegion);
-
- if (X.second) {
- if (includeSuffix)
- return std::make_pair(X.first,
- MRMgr.getFieldRegionWithSuper(FR, X.second));
- return X;
- }
-
- }
- // C++ base object region is another kind of region that we should blast
- // through to look for lazy compound value. It is like a field region.
- else if (const CXXBaseObjectRegion *baseReg =
- dyn_cast<CXXBaseObjectRegion>(R)) {
- const std::pair<Store, const MemRegion *> &X =
- GetLazyBinding(B, baseReg->getSuperRegion(), originalRegion);
+ Result = findLazyBinding(B, cast<SubRegion>(ER->getSuperRegion()),
+ originalRegion);
+
+ if (Result.second)
+ Result.second = MRMgr.getElementRegionWithSuper(ER, Result.second);
+
+ } else if (const FieldRegion *FR = dyn_cast<FieldRegion>(R)) {
+ Result = findLazyBinding(B, cast<SubRegion>(FR->getSuperRegion()),
+ originalRegion);
+
+ if (Result.second)
+ Result.second = MRMgr.getFieldRegionWithSuper(FR, Result.second);
+
+ } else if (const CXXBaseObjectRegion *BaseReg =
+ dyn_cast<CXXBaseObjectRegion>(R)) {
+ // C++ base object region is another kind of region that we should blast
+ // through to look for lazy compound value. It is like a field region.
+ Result = findLazyBinding(B, cast<SubRegion>(BaseReg->getSuperRegion()),
+ originalRegion);
- if (X.second) {
- if (includeSuffix)
- return std::make_pair(X.first,
- MRMgr.getCXXBaseObjectRegionWithSuper(baseReg,
- X.second));
- return X;
- }
+ if (Result.second)
+ Result.second = MRMgr.getCXXBaseObjectRegionWithSuper(BaseReg,
+ Result.second);
}
- // The NULL MemRegion indicates an non-existent lazy binding. A NULL Store is
- // possible for a valid lazy binding.
- return std::make_pair((Store) 0, (const MemRegion *) 0);
+ return Result;
}
-SVal RegionStoreManager::getBindingForElement(Store store,
+SVal RegionStoreManager::getBindingForElement(RegionBindingsConstRef B,
const ElementRegion* R) {
// We do not currently model bindings of the CompoundLiteralregion.
if (isa<CompoundLiteralRegion>(R->getBaseRegion()))
return UnknownVal();
// Check if the region has a binding.
- RegionBindings B = GetRegionBindings(store);
- if (const Optional<SVal> &V = getDirectBinding(B, R))
+ if (const Optional<SVal> &V = B.getDirectBinding(R))
return *V;
const MemRegion* superR = R->getSuperRegion();
@@ -1163,7 +1453,7 @@ SVal RegionStoreManager::getBindingForElement(Store store,
const StringLiteral *Str = StrR->getStringLiteral();
SVal Idx = R->getIndex();
- if (nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&Idx)) {
+ if (Optional<nonloc::ConcreteInt> CI = Idx.getAs<nonloc::ConcreteInt>()) {
int64_t i = CI->getValue().getSExtValue();
// Abort on string underrun. This can be possible by arbitrary
// clients of getBindingForElement().
@@ -1202,7 +1492,7 @@ SVal RegionStoreManager::getBindingForElement(Store store,
QualType elemT = R->getElementType();
if (elemT->isScalarType()) {
if (Ctx.getTypeSizeInChars(baseT) >= Ctx.getTypeSizeInChars(elemT)) {
- if (const Optional<SVal> &V = getDirectBinding(B, superR)) {
+ if (const Optional<SVal> &V = B.getDirectBinding(superR)) {
if (SymbolRef parentSym = V->getAsSymbol())
return svalBuilder.getDerivedRegionValueSymbolVal(parentSym, R);
@@ -1216,29 +1506,27 @@ SVal RegionStoreManager::getBindingForElement(Store store,
}
}
}
- return getBindingForFieldOrElementCommon(store, R, R->getElementType(),
- superR);
+ return getBindingForFieldOrElementCommon(B, R, R->getElementType(),superR);
}
-SVal RegionStoreManager::getBindingForField(Store store,
- const FieldRegion* R) {
+SVal RegionStoreManager::getBindingForField(RegionBindingsConstRef B,
+ const FieldRegion* R) {
// Check if the region has a binding.
- RegionBindings B = GetRegionBindings(store);
- if (const Optional<SVal> &V = getDirectBinding(B, R))
+ if (const Optional<SVal> &V = B.getDirectBinding(R))
return *V;
QualType Ty = R->getValueType();
- return getBindingForFieldOrElementCommon(store, R, Ty, R->getSuperRegion());
+ return getBindingForFieldOrElementCommon(B, R, Ty, R->getSuperRegion());
}
Optional<SVal>
-RegionStoreManager::getBindingForDerivedDefaultValue(RegionBindings B,
+RegionStoreManager::getBindingForDerivedDefaultValue(RegionBindingsConstRef B,
const MemRegion *superR,
const TypedValueRegion *R,
QualType Ty) {
- if (const Optional<SVal> &D = getDefaultBinding(B, superR)) {
+ if (const Optional<SVal> &D = B.getDefaultBinding(superR)) {
const SVal &val = D.getValue();
if (SymbolRef parentSym = val.getAsSymbol())
return svalBuilder.getDerivedRegionValueSymbolVal(parentSym, R);
@@ -1249,53 +1537,95 @@ RegionStoreManager::getBindingForDerivedDefaultValue(RegionBindings B,
if (val.isUnknownOrUndef())
return val;
- // Lazy bindings are handled later.
- if (isa<nonloc::LazyCompoundVal>(val))
- return Optional<SVal>();
+ // Lazy bindings are usually handled through getExistingLazyBinding().
+ // We should unify these two code paths at some point.
+ if (val.getAs<nonloc::LazyCompoundVal>())
+ return val;
llvm_unreachable("Unknown default value");
}
- return Optional<SVal>();
+ return None;
}
-SVal RegionStoreManager::getLazyBinding(const MemRegion *lazyBindingRegion,
- Store lazyBindingStore) {
- if (const ElementRegion *ER = dyn_cast<ElementRegion>(lazyBindingRegion))
- return getBindingForElement(lazyBindingStore, ER);
-
- return getBindingForField(lazyBindingStore,
- cast<FieldRegion>(lazyBindingRegion));
+SVal RegionStoreManager::getLazyBinding(const SubRegion *LazyBindingRegion,
+ RegionBindingsRef LazyBinding) {
+ SVal Result;
+ if (const ElementRegion *ER = dyn_cast<ElementRegion>(LazyBindingRegion))
+ Result = getBindingForElement(LazyBinding, ER);
+ else
+ Result = getBindingForField(LazyBinding,
+ cast<FieldRegion>(LazyBindingRegion));
+
+ // FIXME: This is a hack to deal with RegionStore's inability to distinguish a
+ // default value for /part/ of an aggregate from a default value for the
+ // /entire/ aggregate. The most common case of this is when struct Outer
+ // has as its first member a struct Inner, which is copied in from a stack
+ // variable. In this case, even if the Outer's default value is symbolic, 0,
+ // or unknown, it gets overridden by the Inner's default value of undefined.
+ //
+ // This is a general problem -- if the Inner is zero-initialized, the Outer
+ // will now look zero-initialized. The proper way to solve this is with a
+ // new version of RegionStore that tracks the extent of a binding as well
+ // as the offset.
+ //
+ // This hack only takes care of the undefined case because that can very
+ // quickly result in a warning.
+ if (Result.isUndef())
+ Result = UnknownVal();
+
+ return Result;
}
-SVal RegionStoreManager::getBindingForFieldOrElementCommon(Store store,
+SVal
+RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
const TypedValueRegion *R,
QualType Ty,
const MemRegion *superR) {
// At this point we have already checked in either getBindingForElement or
// getBindingForField if 'R' has a direct binding.
- RegionBindings B = GetRegionBindings(store);
// Lazy binding?
Store lazyBindingStore = NULL;
- const MemRegion *lazyBindingRegion = NULL;
- llvm::tie(lazyBindingStore, lazyBindingRegion) = GetLazyBinding(B, R, R,
- true);
-
+ const SubRegion *lazyBindingRegion = NULL;
+ llvm::tie(lazyBindingStore, lazyBindingRegion) = findLazyBinding(B, R, R);
if (lazyBindingRegion)
- return getLazyBinding(lazyBindingRegion, lazyBindingStore);
+ return getLazyBinding(lazyBindingRegion,
+ getRegionBindings(lazyBindingStore));
// Record whether or not we see a symbolic index. That can completely
// be out of scope of our lookup.
bool hasSymbolicIndex = false;
- while (superR) {
- if (const Optional<SVal> &D =
- getBindingForDerivedDefaultValue(B, superR, R, Ty))
+ // FIXME: This is a hack to deal with RegionStore's inability to distinguish a
+ // default value for /part/ of an aggregate from a default value for the
+ // /entire/ aggregate. The most common case of this is when struct Outer
+ // has as its first member a struct Inner, which is copied in from a stack
+ // variable. In this case, even if the Outer's default value is symbolic, 0,
+ // or unknown, it gets overridden by the Inner's default value of undefined.
+ //
+ // This is a general problem -- if the Inner is zero-initialized, the Outer
+ // will now look zero-initialized. The proper way to solve this is with a
+ // new version of RegionStore that tracks the extent of a binding as well
+ // as the offset.
+ //
+ // This hack only takes care of the undefined case because that can very
+ // quickly result in a warning.
+ bool hasPartialLazyBinding = false;
+
+ const SubRegion *Base = dyn_cast<SubRegion>(superR);
+ while (Base) {
+ if (Optional<SVal> D = getBindingForDerivedDefaultValue(B, Base, R, Ty)) {
+ if (D->getAs<nonloc::LazyCompoundVal>()) {
+ hasPartialLazyBinding = true;
+ break;
+ }
+
return *D;
+ }
- if (const ElementRegion *ER = dyn_cast<ElementRegion>(superR)) {
+ if (const ElementRegion *ER = dyn_cast<ElementRegion>(Base)) {
NonLoc index = ER->getIndex();
if (!index.isConstant())
hasSymbolicIndex = true;
@@ -1303,11 +1633,7 @@ SVal RegionStoreManager::getBindingForFieldOrElementCommon(Store store,
// If our super region is a field or element itself, walk up the region
// hierarchy to see if there is a default value installed in an ancestor.
- if (const SubRegion *SR = dyn_cast<SubRegion>(superR)) {
- superR = SR->getSuperRegion();
- continue;
- }
- break;
+ Base = dyn_cast<SubRegion>(Base->getSuperRegion());
}
if (R->hasStackNonParametersStorage()) {
@@ -1327,27 +1653,25 @@ SVal RegionStoreManager::getBindingForFieldOrElementCommon(Store store,
// a symbolic offset.
if (hasSymbolicIndex)
return UnknownVal();
-
- return UndefinedVal();
+
+ if (!hasPartialLazyBinding)
+ return UndefinedVal();
}
// All other values are symbolic.
return svalBuilder.getRegionValueSymbolVal(R);
}
-SVal RegionStoreManager::getBindingForObjCIvar(Store store,
+SVal RegionStoreManager::getBindingForObjCIvar(RegionBindingsConstRef B,
const ObjCIvarRegion* R) {
-
- // Check if the region has a binding.
- RegionBindings B = GetRegionBindings(store);
-
- if (const Optional<SVal> &V = getDirectBinding(B, R))
+ // Check if the region has a binding.
+ if (const Optional<SVal> &V = B.getDirectBinding(R))
return *V;
const MemRegion *superR = R->getSuperRegion();
// Check if the super region has a default binding.
- if (const Optional<SVal> &V = getDefaultBinding(B, superR)) {
+ if (const Optional<SVal> &V = B.getDefaultBinding(superR)) {
if (SymbolRef parentSym = V->getAsSymbol())
return svalBuilder.getDerivedRegionValueSymbolVal(parentSym, R);
@@ -1358,51 +1682,64 @@ SVal RegionStoreManager::getBindingForObjCIvar(Store store,
return getBindingForLazySymbol(R);
}
-SVal RegionStoreManager::getBindingForVar(Store store, const VarRegion *R) {
+static Optional<SVal> getConstValue(SValBuilder &SVB, const VarDecl *VD) {
+ ASTContext &Ctx = SVB.getContext();
+ if (!VD->getType().isConstQualified())
+ return None;
- // Check if the region has a binding.
- RegionBindings B = GetRegionBindings(store);
+ const Expr *Init = VD->getInit();
+ if (!Init)
+ return None;
+
+ llvm::APSInt Result;
+ if (!Init->isGLValue() && Init->EvaluateAsInt(Result, Ctx))
+ return SVB.makeIntVal(Result);
+
+ if (Init->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull))
+ return SVB.makeNull();
- if (const Optional<SVal> &V = getDirectBinding(B, R))
+ // FIXME: Handle other possible constant expressions.
+ return None;
+}
+
+SVal RegionStoreManager::getBindingForVar(RegionBindingsConstRef B,
+ const VarRegion *R) {
+
+ // Check if the region has a binding.
+ if (const Optional<SVal> &V = B.getDirectBinding(R))
return *V;
// Lazily derive a value for the VarRegion.
const VarDecl *VD = R->getDecl();
- QualType T = VD->getType();
const MemSpaceRegion *MS = R->getMemorySpace();
- if (isa<UnknownSpaceRegion>(MS) ||
- isa<StackArgumentsSpaceRegion>(MS))
+ // Arguments are always symbolic.
+ if (isa<StackArgumentsSpaceRegion>(MS))
+ return svalBuilder.getRegionValueSymbolVal(R);
+
+ // Is 'VD' declared constant? If so, retrieve the constant value.
+ if (Optional<SVal> V = getConstValue(svalBuilder, VD))
+ return *V;
+
+ // This must come after the check for constants because closure-captured
+ // constant variables may appear in UnknownSpaceRegion.
+ if (isa<UnknownSpaceRegion>(MS))
return svalBuilder.getRegionValueSymbolVal(R);
if (isa<GlobalsSpaceRegion>(MS)) {
- if (isa<NonStaticGlobalSpaceRegion>(MS)) {
- // Is 'VD' declared constant? If so, retrieve the constant value.
- QualType CT = Ctx.getCanonicalType(T);
- if (CT.isConstQualified()) {
- const Expr *Init = VD->getInit();
- // Do the null check first, as we want to call 'IgnoreParenCasts'.
- if (Init)
- if (const IntegerLiteral *IL =
- dyn_cast<IntegerLiteral>(Init->IgnoreParenCasts())) {
- const nonloc::ConcreteInt &V = svalBuilder.makeIntVal(IL);
- return svalBuilder.evalCast(V, Init->getType(), IL->getType());
- }
- }
+ QualType T = VD->getType();
- if (const Optional<SVal> &V
- = getBindingForDerivedDefaultValue(B, MS, R, CT))
- return V.getValue();
+ // Function-scoped static variables are default-initialized to 0; if they
+ // have an initializer, it would have been processed by now.
+ if (isa<StaticGlobalSpaceRegion>(MS))
+ return svalBuilder.makeZeroVal(T);
- return svalBuilder.getRegionValueSymbolVal(R);
+ if (Optional<SVal> V = getBindingForDerivedDefaultValue(B, MS, R, T)) {
+ assert(!V->getAs<nonloc::LazyCompoundVal>());
+ return V.getValue();
}
- if (T->isIntegerType())
- return svalBuilder.makeIntVal(0, T);
- if (T->isPointerType())
- return svalBuilder.makeNull();
-
- return UnknownVal();
+ return svalBuilder.getRegionValueSymbolVal(R);
}
return UndefinedVal();
@@ -1413,55 +1750,77 @@ SVal RegionStoreManager::getBindingForLazySymbol(const TypedValueRegion *R) {
return svalBuilder.getRegionValueSymbolVal(R);
}
-static bool mayHaveLazyBinding(QualType Ty) {
- return Ty->isArrayType() || Ty->isStructureOrClassType();
+const RegionStoreManager::SValListTy &
+RegionStoreManager::getInterestingValues(nonloc::LazyCompoundVal LCV) {
+ // First, check the cache.
+ LazyBindingsMapTy::iterator I = LazyBindingsMap.find(LCV.getCVData());
+ if (I != LazyBindingsMap.end())
+ return I->second;
+
+ // If we don't have a list of values cached, start constructing it.
+ SValListTy List;
+
+ const SubRegion *LazyR = LCV.getRegion();
+ RegionBindingsRef B = getRegionBindings(LCV.getStore());
+
+ // If this region had /no/ bindings at the time, there are no interesting
+ // values to return.
+ const ClusterBindings *Cluster = B.lookup(LazyR->getBaseRegion());
+ if (!Cluster)
+ return (LazyBindingsMap[LCV.getCVData()] = llvm_move(List));
+
+ SmallVector<BindingPair, 32> Bindings;
+ collectSubRegionBindings(Bindings, svalBuilder, *Cluster, LazyR,
+ /*IncludeAllDefaultBindings=*/true);
+ for (SmallVectorImpl<BindingPair>::const_iterator I = Bindings.begin(),
+ E = Bindings.end();
+ I != E; ++I) {
+ SVal V = I->second;
+ if (V.isUnknownOrUndef() || V.isConstant())
+ continue;
+
+ if (Optional<nonloc::LazyCompoundVal> InnerLCV =
+ V.getAs<nonloc::LazyCompoundVal>()) {
+ const SValListTy &InnerList = getInterestingValues(*InnerLCV);
+ List.insert(List.end(), InnerList.begin(), InnerList.end());
+ continue;
+ }
+
+ List.push_back(V);
+ }
+
+ return (LazyBindingsMap[LCV.getCVData()] = llvm_move(List));
+}
+
+NonLoc RegionStoreManager::createLazyBinding(RegionBindingsConstRef B,
+ const TypedValueRegion *R) {
+ if (Optional<nonloc::LazyCompoundVal> V =
+ getExistingLazyBinding(svalBuilder, B, R, false))
+ return *V;
+
+ return svalBuilder.makeLazyCompoundVal(StoreRef(B.asStore(), *this), R);
}
-SVal RegionStoreManager::getBindingForStruct(Store store,
- const TypedValueRegion* R) {
+SVal RegionStoreManager::getBindingForStruct(RegionBindingsConstRef B,
+ const TypedValueRegion *R) {
const RecordDecl *RD = R->getValueType()->castAs<RecordType>()->getDecl();
if (RD->field_empty())
return UnknownVal();
- // If we already have a lazy binding, don't create a new one,
- // unless the first field might have a lazy binding of its own.
- // (Right now we can't tell the difference.)
- QualType FirstFieldType = RD->field_begin()->getType();
- if (!mayHaveLazyBinding(FirstFieldType)) {
- RegionBindings B = GetRegionBindings(store);
- BindingKey K = BindingKey::Make(R, BindingKey::Default);
- if (const nonloc::LazyCompoundVal *V =
- dyn_cast_or_null<nonloc::LazyCompoundVal>(lookup(B, K))) {
- return *V;
- }
- }
-
- return svalBuilder.makeLazyCompoundVal(StoreRef(store, *this), R);
+ return createLazyBinding(B, R);
}
-SVal RegionStoreManager::getBindingForArray(Store store,
- const TypedValueRegion * R) {
- const ConstantArrayType *Ty = Ctx.getAsConstantArrayType(R->getValueType());
- assert(Ty && "Only constant array types can have compound bindings.");
+SVal RegionStoreManager::getBindingForArray(RegionBindingsConstRef B,
+ const TypedValueRegion *R) {
+ assert(Ctx.getAsConstantArrayType(R->getValueType()) &&
+ "Only constant array types can have compound bindings.");
- // If we already have a lazy binding, don't create a new one,
- // unless the first element might have a lazy binding of its own.
- // (Right now we can't tell the difference.)
- if (!mayHaveLazyBinding(Ty->getElementType())) {
- RegionBindings B = GetRegionBindings(store);
- BindingKey K = BindingKey::Make(R, BindingKey::Default);
- if (const nonloc::LazyCompoundVal *V =
- dyn_cast_or_null<nonloc::LazyCompoundVal>(lookup(B, K))) {
- return *V;
- }
- }
-
- return svalBuilder.makeLazyCompoundVal(StoreRef(store, *this), R);
+ return createLazyBinding(B, R);
}
bool RegionStoreManager::includedInBindings(Store store,
const MemRegion *region) const {
- RegionBindings B = GetRegionBindings(store);
+ RegionBindingsRef B = getRegionBindings(store);
region = region->getBaseRegion();
// Quick path: if the base is the head of a cluster, the region is live.
@@ -1469,7 +1828,7 @@ bool RegionStoreManager::includedInBindings(Store store,
return true;
// Slow path: if the region is the VALUE of any binding, it is live.
- for (RegionBindings::iterator RI = B.begin(), RE = B.end(); RI != RE; ++RI) {
+ for (RegionBindingsRef::iterator RI = B.begin(), RE = B.end(); RI != RE; ++RI) {
const ClusterBindings &Cluster = RI.getData();
for (ClusterBindings::iterator CI = Cluster.begin(), CE = Cluster.end();
CI != CE; ++CI) {
@@ -1488,31 +1847,33 @@ bool RegionStoreManager::includedInBindings(Store store,
//===----------------------------------------------------------------------===//
StoreRef RegionStoreManager::killBinding(Store ST, Loc L) {
- if (isa<loc::MemRegionVal>(L))
- if (const MemRegion* R = cast<loc::MemRegionVal>(L).getRegion())
- return StoreRef(removeBinding(GetRegionBindings(ST),
- R).getRootWithoutRetain(),
+ if (Optional<loc::MemRegionVal> LV = L.getAs<loc::MemRegionVal>())
+ if (const MemRegion* R = LV->getRegion())
+ return StoreRef(getRegionBindings(ST).removeBinding(R)
+ .asImmutableMap()
+ .getRootWithoutRetain(),
*this);
return StoreRef(ST, *this);
}
-StoreRef RegionStoreManager::Bind(Store store, Loc L, SVal V) {
- if (isa<loc::ConcreteInt>(L))
- return StoreRef(store, *this);
+RegionBindingsRef
+RegionStoreManager::bind(RegionBindingsConstRef B, Loc L, SVal V) {
+ if (L.getAs<loc::ConcreteInt>())
+ return B;
// If we get here, the location should be a region.
- const MemRegion *R = cast<loc::MemRegionVal>(L).getRegion();
+ const MemRegion *R = L.castAs<loc::MemRegionVal>().getRegion();
// Check if the region is a struct region.
if (const TypedValueRegion* TR = dyn_cast<TypedValueRegion>(R)) {
QualType Ty = TR->getValueType();
if (Ty->isArrayType())
- return BindArray(store, TR, V);
+ return bindArray(B, TR, V);
if (Ty->isStructureOrClassType())
- return BindStruct(store, TR, V);
+ return bindStruct(B, TR, V);
if (Ty->isVectorType())
- return BindVector(store, TR, V);
+ return bindVector(B, TR, V);
}
if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) {
@@ -1526,12 +1887,8 @@ StoreRef RegionStoreManager::Bind(Store store, Loc L, SVal V) {
}
// Clear out bindings that may overlap with this binding.
-
- // Perform the binding.
- RegionBindings B = GetRegionBindings(store);
- B = removeSubRegionBindings(B, cast<SubRegion>(R));
- BindingKey Key = BindingKey::Make(R, BindingKey::Direct);
- return StoreRef(addBinding(B, Key, V).getRootWithoutRetain(), *this);
+ RegionBindingsRef NewB = removeSubRegionBindings(B, cast<SubRegion>(R));
+ return NewB.addBinding(BindingKey::Make(R, BindingKey::Direct), V);
}
// FIXME: this method should be merged into Bind().
@@ -1542,10 +1899,10 @@ StoreRef RegionStoreManager::bindCompoundLiteral(Store ST,
return Bind(ST, loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)), V);
}
-StoreRef RegionStoreManager::setImplicitDefaultValue(Store store,
- const MemRegion *R,
- QualType T) {
- RegionBindings B = GetRegionBindings(store);
+RegionBindingsRef
+RegionStoreManager::setImplicitDefaultValue(RegionBindingsConstRef B,
+ const MemRegion *R,
+ QualType T) {
SVal V;
if (Loc::isLocType(T))
@@ -1566,12 +1923,13 @@ StoreRef RegionStoreManager::setImplicitDefaultValue(Store store,
V = UnknownVal();
}
- return StoreRef(addBinding(B, R, BindingKey::Default,
- V).getRootWithoutRetain(), *this);
+ return B.addBinding(R, BindingKey::Default, V);
}
-StoreRef RegionStoreManager::BindArray(Store store, const TypedValueRegion* R,
- SVal Init) {
+RegionBindingsRef
+RegionStoreManager::bindArray(RegionBindingsConstRef B,
+ const TypedValueRegion* R,
+ SVal Init) {
const ArrayType *AT =cast<ArrayType>(Ctx.getCanonicalType(R->getValueType()));
QualType ElementTy = AT->getElementType();
@@ -1581,30 +1939,31 @@ StoreRef RegionStoreManager::BindArray(Store store, const TypedValueRegion* R,
Size = CAT->getSize().getZExtValue();
// Check if the init expr is a string literal.
- if (loc::MemRegionVal *MRV = dyn_cast<loc::MemRegionVal>(&Init)) {
+ if (Optional<loc::MemRegionVal> MRV = Init.getAs<loc::MemRegionVal>()) {
const StringRegion *S = cast<StringRegion>(MRV->getRegion());
// Treat the string as a lazy compound value.
- nonloc::LazyCompoundVal LCV =
- cast<nonloc::LazyCompoundVal>(svalBuilder.
- makeLazyCompoundVal(StoreRef(store, *this), S));
- return BindAggregate(store, R, LCV);
+ StoreRef store(B.asStore(), *this);
+ nonloc::LazyCompoundVal LCV = svalBuilder.makeLazyCompoundVal(store, S)
+ .castAs<nonloc::LazyCompoundVal>();
+ return bindAggregate(B, R, LCV);
}
// Handle lazy compound values.
- if (isa<nonloc::LazyCompoundVal>(Init))
- return BindAggregate(store, R, Init);
+ if (Init.getAs<nonloc::LazyCompoundVal>())
+ return bindAggregate(B, R, Init);
// Remaining case: explicit compound values.
if (Init.isUnknown())
- return setImplicitDefaultValue(store, R, ElementTy);
+ return setImplicitDefaultValue(B, R, ElementTy);
- nonloc::CompoundVal& CV = cast<nonloc::CompoundVal>(Init);
+ const nonloc::CompoundVal& CV = Init.castAs<nonloc::CompoundVal>();
nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
uint64_t i = 0;
- StoreRef newStore(store, *this);
+ RegionBindingsRef NewB(B);
+
for (; Size.hasValue() ? i < Size.getValue() : true ; ++i, ++VI) {
// The init list might be shorter than the array length.
if (VI == VE)
@@ -1614,44 +1973,45 @@ StoreRef RegionStoreManager::BindArray(Store store, const TypedValueRegion* R,
const ElementRegion *ER = MRMgr.getElementRegion(ElementTy, Idx, R, Ctx);
if (ElementTy->isStructureOrClassType())
- newStore = BindStruct(newStore.getStore(), ER, *VI);
+ NewB = bindStruct(NewB, ER, *VI);
else if (ElementTy->isArrayType())
- newStore = BindArray(newStore.getStore(), ER, *VI);
+ NewB = bindArray(NewB, ER, *VI);
else
- newStore = Bind(newStore.getStore(), svalBuilder.makeLoc(ER), *VI);
+ NewB = bind(NewB, svalBuilder.makeLoc(ER), *VI);
}
// If the init list is shorter than the array length, set the
// array default value.
if (Size.hasValue() && i < Size.getValue())
- newStore = setImplicitDefaultValue(newStore.getStore(), R, ElementTy);
+ NewB = setImplicitDefaultValue(NewB, R, ElementTy);
- return newStore;
+ return NewB;
}
-StoreRef RegionStoreManager::BindVector(Store store, const TypedValueRegion* R,
- SVal V) {
+RegionBindingsRef RegionStoreManager::bindVector(RegionBindingsConstRef B,
+ const TypedValueRegion* R,
+ SVal V) {
QualType T = R->getValueType();
assert(T->isVectorType());
const VectorType *VT = T->getAs<VectorType>(); // Use getAs for typedefs.
// Handle lazy compound values and symbolic values.
- if (isa<nonloc::LazyCompoundVal>(V) || isa<nonloc::SymbolVal>(V))
- return BindAggregate(store, R, V);
+ if (V.getAs<nonloc::LazyCompoundVal>() || V.getAs<nonloc::SymbolVal>())
+ return bindAggregate(B, R, V);
// We may get non-CompoundVal accidentally due to imprecise cast logic or
// that we are binding symbolic struct value. Kill the field values, and if
// the value is symbolic go and bind it as a "default" binding.
- if (!isa<nonloc::CompoundVal>(V)) {
- return BindAggregate(store, R, UnknownVal());
+ if (!V.getAs<nonloc::CompoundVal>()) {
+ return bindAggregate(B, R, UnknownVal());
}
QualType ElemType = VT->getElementType();
- nonloc::CompoundVal& CV = cast<nonloc::CompoundVal>(V);
+ nonloc::CompoundVal CV = V.castAs<nonloc::CompoundVal>();
nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
unsigned index = 0, numElements = VT->getNumElements();
- StoreRef newStore(store, *this);
-
+ RegionBindingsRef NewB(B);
+
for ( ; index != numElements ; ++index) {
if (VI == VE)
break;
@@ -1660,20 +2020,20 @@ StoreRef RegionStoreManager::BindVector(Store store, const TypedValueRegion* R,
const ElementRegion *ER = MRMgr.getElementRegion(ElemType, Idx, R, Ctx);
if (ElemType->isArrayType())
- newStore = BindArray(newStore.getStore(), ER, *VI);
+ NewB = bindArray(NewB, ER, *VI);
else if (ElemType->isStructureOrClassType())
- newStore = BindStruct(newStore.getStore(), ER, *VI);
+ NewB = bindStruct(NewB, ER, *VI);
else
- newStore = Bind(newStore.getStore(), svalBuilder.makeLoc(ER), *VI);
+ NewB = bind(NewB, svalBuilder.makeLoc(ER), *VI);
}
- return newStore;
+ return NewB;
}
-StoreRef RegionStoreManager::BindStruct(Store store, const TypedValueRegion* R,
- SVal V) {
-
+RegionBindingsRef RegionStoreManager::bindStruct(RegionBindingsConstRef B,
+ const TypedValueRegion* R,
+ SVal V) {
if (!Features.supportsFields())
- return StoreRef(store, *this);
+ return B;
QualType T = R->getValueType();
assert(T->isStructureOrClassType());
@@ -1682,24 +2042,24 @@ StoreRef RegionStoreManager::BindStruct(Store store, const TypedValueRegion* R,
RecordDecl *RD = RT->getDecl();
if (!RD->isCompleteDefinition())
- return StoreRef(store, *this);
+ return B;
// Handle lazy compound values and symbolic values.
- if (isa<nonloc::LazyCompoundVal>(V) || isa<nonloc::SymbolVal>(V))
- return BindAggregate(store, R, V);
+ if (V.getAs<nonloc::LazyCompoundVal>() || V.getAs<nonloc::SymbolVal>())
+ return bindAggregate(B, R, V);
// We may get non-CompoundVal accidentally due to imprecise cast logic or
// that we are binding symbolic struct value. Kill the field values, and if
// the value is symbolic go and bind it as a "default" binding.
- if (V.isUnknown() || !isa<nonloc::CompoundVal>(V))
- return BindAggregate(store, R, UnknownVal());
+ if (V.isUnknown() || !V.getAs<nonloc::CompoundVal>())
+ return bindAggregate(B, R, UnknownVal());
- nonloc::CompoundVal& CV = cast<nonloc::CompoundVal>(V);
+ const nonloc::CompoundVal& CV = V.castAs<nonloc::CompoundVal>();
nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
RecordDecl::field_iterator FI, FE;
- StoreRef newStore(store, *this);
-
+ RegionBindingsRef NewB(B);
+
for (FI = RD->field_begin(), FE = RD->field_end(); FI != FE; ++FI) {
if (VI == VE)
@@ -1713,95 +2073,30 @@ StoreRef RegionStoreManager::BindStruct(Store store, const TypedValueRegion* R,
const FieldRegion* FR = MRMgr.getFieldRegion(*FI, R);
if (FTy->isArrayType())
- newStore = BindArray(newStore.getStore(), FR, *VI);
+ NewB = bindArray(NewB, FR, *VI);
else if (FTy->isStructureOrClassType())
- newStore = BindStruct(newStore.getStore(), FR, *VI);
+ NewB = bindStruct(NewB, FR, *VI);
else
- newStore = Bind(newStore.getStore(), svalBuilder.makeLoc(FR), *VI);
+ NewB = bind(NewB, svalBuilder.makeLoc(FR), *VI);
++VI;
}
// There may be fewer values in the initialize list than the fields of struct.
if (FI != FE) {
- RegionBindings B = GetRegionBindings(newStore.getStore());
- B = addBinding(B, R, BindingKey::Default, svalBuilder.makeIntVal(0, false));
- newStore = StoreRef(B.getRootWithoutRetain(), *this);
+ NewB = NewB.addBinding(R, BindingKey::Default,
+ svalBuilder.makeIntVal(0, false));
}
- return newStore;
+ return NewB;
}
-StoreRef RegionStoreManager::BindAggregate(Store store, const TypedRegion *R,
- SVal Val) {
+RegionBindingsRef
+RegionStoreManager::bindAggregate(RegionBindingsConstRef B,
+ const TypedRegion *R,
+ SVal Val) {
// Remove the old bindings, using 'R' as the root of all regions
// we will invalidate. Then add the new binding.
- RegionBindings B = GetRegionBindings(store);
-
- B = removeSubRegionBindings(B, R);
- B = addBinding(B, R, BindingKey::Default, Val);
-
- return StoreRef(B.getRootWithoutRetain(), *this);
-}
-
-//===----------------------------------------------------------------------===//
-// "Raw" retrievals and bindings.
-//===----------------------------------------------------------------------===//
-
-
-RegionBindings RegionStoreManager::addBinding(RegionBindings B, BindingKey K,
- SVal V) {
- const MemRegion *Base = K.getBaseRegion();
-
- const ClusterBindings *ExistingCluster = B.lookup(Base);
- ClusterBindings Cluster = (ExistingCluster ? *ExistingCluster
- : CBFactory.getEmptyMap());
-
- ClusterBindings NewCluster = CBFactory.add(Cluster, K, V);
- return RBFactory.add(B, Base, NewCluster);
-}
-
-RegionBindings RegionStoreManager::addBinding(RegionBindings B,
- const MemRegion *R,
- BindingKey::Kind k, SVal V) {
- return addBinding(B, BindingKey::Make(R, k), V);
-}
-
-const SVal *RegionStoreManager::lookup(RegionBindings B, BindingKey K) {
- const ClusterBindings *Cluster = B.lookup(K.getBaseRegion());
- if (!Cluster)
- return 0;
-
- return Cluster->lookup(K);
-}
-
-const SVal *RegionStoreManager::lookup(RegionBindings B,
- const MemRegion *R,
- BindingKey::Kind k) {
- return lookup(B, BindingKey::Make(R, k));
-}
-
-RegionBindings RegionStoreManager::removeBinding(RegionBindings B,
- BindingKey K) {
- const MemRegion *Base = K.getBaseRegion();
- const ClusterBindings *Cluster = B.lookup(Base);
- if (!Cluster)
- return B;
-
- ClusterBindings NewCluster = CBFactory.remove(*Cluster, K);
- if (NewCluster.isEmpty())
- return RBFactory.remove(B, Base);
- return RBFactory.add(B, Base, NewCluster);
-}
-
-RegionBindings RegionStoreManager::removeBinding(RegionBindings B,
- const MemRegion *R,
- BindingKey::Kind k){
- return removeBinding(B, BindingKey::Make(R, k));
-}
-
-RegionBindings RegionStoreManager::removeCluster(RegionBindings B,
- const MemRegion *Base) {
- return RBFactory.remove(B, Base);
+ return removeSubRegionBindings(B, R).addBinding(R, BindingKey::Default, Val);
}
//===----------------------------------------------------------------------===//
@@ -1818,7 +2113,7 @@ class removeDeadBindingsWorker :
public:
removeDeadBindingsWorker(RegionStoreManager &rm,
ProgramStateManager &stateMgr,
- RegionBindings b, SymbolReaper &symReaper,
+ RegionBindingsRef b, SymbolReaper &symReaper,
const StackFrameContext *LCtx)
: ClusterAnalysis<removeDeadBindingsWorker>(rm, stateMgr, b,
/* includeGlobals = */ false),
@@ -1826,7 +2121,8 @@ public:
// Called by ClusterAnalysis.
void VisitAddedToCluster(const MemRegion *baseR, const ClusterBindings &C);
- void VisitCluster(const MemRegion *baseR, const ClusterBindings &C);
+ void VisitCluster(const MemRegion *baseR, const ClusterBindings *C);
+ using ClusterAnalysis<removeDeadBindingsWorker>::VisitCluster;
bool UpdatePostponed();
void VisitBinding(SVal V);
@@ -1869,38 +2165,30 @@ void removeDeadBindingsWorker::VisitAddedToCluster(const MemRegion *baseR,
}
void removeDeadBindingsWorker::VisitCluster(const MemRegion *baseR,
- const ClusterBindings &C) {
+ const ClusterBindings *C) {
+ if (!C)
+ return;
+
// Mark the symbol for any SymbolicRegion with live bindings as live itself.
// This means we should continue to track that symbol.
if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(baseR))
SymReaper.markLive(SymR->getSymbol());
- for (ClusterBindings::iterator I = C.begin(), E = C.end(); I != E; ++I)
+ for (ClusterBindings::iterator I = C->begin(), E = C->end(); I != E; ++I)
VisitBinding(I.getData());
}
void removeDeadBindingsWorker::VisitBinding(SVal V) {
// Is it a LazyCompoundVal? All referenced regions are live as well.
- if (const nonloc::LazyCompoundVal *LCS =
- dyn_cast<nonloc::LazyCompoundVal>(&V)) {
+ if (Optional<nonloc::LazyCompoundVal> LCS =
+ V.getAs<nonloc::LazyCompoundVal>()) {
- const MemRegion *LazyR = LCS->getRegion();
- RegionBindings B = RegionStoreManager::GetRegionBindings(LCS->getStore());
+ const RegionStoreManager::SValListTy &Vals = RM.getInterestingValues(*LCS);
- // FIXME: This should not have to walk all bindings in the old store.
- for (RegionBindings::iterator RI = B.begin(), RE = B.end(); RI != RE; ++RI){
- const ClusterBindings &Cluster = RI.getData();
- for (ClusterBindings::iterator CI = Cluster.begin(), CE = Cluster.end();
- CI != CE; ++CI) {
- BindingKey K = CI.getKey();
- if (const SubRegion *BaseR = dyn_cast<SubRegion>(K.getRegion())) {
- if (BaseR == LazyR)
- VisitBinding(CI.getData());
- else if (K.hasSymbolicOffset() && BaseR->isSubRegionOf(LazyR))
- VisitBinding(CI.getData());
- }
- }
- }
+ for (RegionStoreManager::SValListTy::const_iterator I = Vals.begin(),
+ E = Vals.end();
+ I != E; ++I)
+ VisitBinding(*I);
return;
}
@@ -1946,7 +2234,7 @@ bool removeDeadBindingsWorker::UpdatePostponed() {
StoreRef RegionStoreManager::removeDeadBindings(Store store,
const StackFrameContext *LCtx,
SymbolReaper& SymReaper) {
- RegionBindings B = GetRegionBindings(store);
+ RegionBindingsRef B = getRegionBindings(store);
removeDeadBindingsWorker W(*this, StateMgr, B, SymReaper, LCtx);
W.GenerateClusters();
@@ -1961,7 +2249,7 @@ StoreRef RegionStoreManager::removeDeadBindings(Store store,
// We have now scanned the store, marking reachable regions and symbols
// as live. We now remove all the regions that are dead from the store
// as well as update DSymbols with the set symbols that are now dead.
- for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
+ for (RegionBindingsRef::iterator I = B.begin(), E = B.end(); I != E; ++I) {
const MemRegion *Base = I.getKey();
// If the cluster has been visited, we know the region has been marked.
@@ -1969,7 +2257,7 @@ StoreRef RegionStoreManager::removeDeadBindings(Store store,
continue;
// Remove the dead entry.
- B = removeCluster(B, Base);
+ B = B.remove(Base);
if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(Base))
SymReaper.maybeDead(SymR->getSymbol());
@@ -1985,7 +2273,7 @@ StoreRef RegionStoreManager::removeDeadBindings(Store store,
}
}
- return StoreRef(B.getRootWithoutRetain(), *this);
+ return StoreRef(B.asStore(), *this);
}
//===----------------------------------------------------------------------===//
@@ -1994,17 +2282,9 @@ StoreRef RegionStoreManager::removeDeadBindings(Store store,
void RegionStoreManager::print(Store store, raw_ostream &OS,
const char* nl, const char *sep) {
- RegionBindings B = GetRegionBindings(store);
+ RegionBindingsRef B = getRegionBindings(store);
OS << "Store (direct and default bindings), "
- << (void*) B.getRootWithoutRetain()
+ << B.asStore()
<< " :" << nl;
-
- for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
- const ClusterBindings &Cluster = I.getData();
- for (ClusterBindings::iterator CI = Cluster.begin(), CE = Cluster.end();
- CI != CE; ++CI) {
- OS << ' ' << CI.getKey() << " : " << CI.getData() << nl;
- }
- OS << nl;
- }
+ B.dump(OS, nl);
}
diff --git a/lib/StaticAnalyzer/Core/SValBuilder.cpp b/lib/StaticAnalyzer/Core/SValBuilder.cpp
index b87169a..c72e780 100644
--- a/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -12,13 +12,13 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/AST/ExprCXX.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
using namespace clang;
using namespace ento;
@@ -78,13 +78,13 @@ SVal SValBuilder::convertToArrayIndex(SVal val) {
return val;
// Common case: we have an appropriately sized integer.
- if (nonloc::ConcreteInt* CI = dyn_cast<nonloc::ConcreteInt>(&val)) {
+ if (Optional<nonloc::ConcreteInt> CI = val.getAs<nonloc::ConcreteInt>()) {
const llvm::APSInt& I = CI->getValue();
if (I.getBitWidth() == ArrayIndexWidth && I.isSigned())
return val;
}
- return evalCastFromNonLoc(cast<NonLoc>(val), ArrayIndexTy);
+ return evalCastFromNonLoc(val.castAs<NonLoc>(), ArrayIndexTy);
}
nonloc::ConcreteInt SValBuilder::makeBoolVal(const CXXBoolLiteralExpr *boolean){
@@ -237,11 +237,11 @@ SVal SValBuilder::makeSymExprValNN(ProgramStateRef State,
return makeNonLoc(symLHS, Op, symRHS, ResultTy);
if (symLHS && symLHS->computeComplexity() < MaxComp)
- if (const nonloc::ConcreteInt *rInt = dyn_cast<nonloc::ConcreteInt>(&RHS))
+ if (Optional<nonloc::ConcreteInt> rInt = RHS.getAs<nonloc::ConcreteInt>())
return makeNonLoc(symLHS, Op, rInt->getValue(), ResultTy);
if (symRHS && symRHS->computeComplexity() < MaxComp)
- if (const nonloc::ConcreteInt *lInt = dyn_cast<nonloc::ConcreteInt>(&LHS))
+ if (Optional<nonloc::ConcreteInt> lInt = LHS.getAs<nonloc::ConcreteInt>())
return makeNonLoc(lInt->getValue(), Op, symRHS, ResultTy);
return UnknownVal();
@@ -257,41 +257,42 @@ SVal SValBuilder::evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op,
if (lhs.isUnknown() || rhs.isUnknown())
return UnknownVal();
- if (isa<Loc>(lhs)) {
- if (isa<Loc>(rhs))
- return evalBinOpLL(state, op, cast<Loc>(lhs), cast<Loc>(rhs), type);
+ if (Optional<Loc> LV = lhs.getAs<Loc>()) {
+ if (Optional<Loc> RV = rhs.getAs<Loc>())
+ return evalBinOpLL(state, op, *LV, *RV, type);
- return evalBinOpLN(state, op, cast<Loc>(lhs), cast<NonLoc>(rhs), type);
+ return evalBinOpLN(state, op, *LV, rhs.castAs<NonLoc>(), type);
}
- if (isa<Loc>(rhs)) {
+ if (Optional<Loc> RV = rhs.getAs<Loc>()) {
// Support pointer arithmetic where the addend is on the left
// and the pointer on the right.
assert(op == BO_Add);
// Commute the operands.
- return evalBinOpLN(state, op, cast<Loc>(rhs), cast<NonLoc>(lhs), type);
+ return evalBinOpLN(state, op, *RV, lhs.castAs<NonLoc>(), type);
}
- return evalBinOpNN(state, op, cast<NonLoc>(lhs), cast<NonLoc>(rhs), type);
+ return evalBinOpNN(state, op, lhs.castAs<NonLoc>(), rhs.castAs<NonLoc>(),
+ type);
}
DefinedOrUnknownSVal SValBuilder::evalEQ(ProgramStateRef state,
DefinedOrUnknownSVal lhs,
DefinedOrUnknownSVal rhs) {
- return cast<DefinedOrUnknownSVal>(evalBinOp(state, BO_EQ, lhs, rhs,
- Context.IntTy));
+ return evalBinOp(state, BO_EQ, lhs, rhs, Context.IntTy)
+ .castAs<DefinedOrUnknownSVal>();
}
/// Recursively check if the pointer types are equal modulo const, volatile,
-/// and restrict qualifiers. Assumes the input types are canonical.
-/// TODO: This is based off of code in SemaCast; can we reuse it.
-static bool haveSimilarTypes(ASTContext &Context, QualType T1,
- QualType T2) {
- while (Context.UnwrapSimilarPointerTypes(T1, T2)) {
+/// and restrict qualifiers. Also, assume that all types are similar to 'void'.
+/// Assumes the input types are canonical.
+static bool shouldBeModeledWithNoOp(ASTContext &Context, QualType ToTy,
+ QualType FromTy) {
+ while (Context.UnwrapSimilarPointerTypes(ToTy, FromTy)) {
Qualifiers Quals1, Quals2;
- T1 = Context.getUnqualifiedArrayType(T1, Quals1);
- T2 = Context.getUnqualifiedArrayType(T2, Quals2);
+ ToTy = Context.getUnqualifiedArrayType(ToTy, Quals1);
+ FromTy = Context.getUnqualifiedArrayType(FromTy, Quals2);
// Make sure that non cvr-qualifiers the other qualifiers (e.g., address
// spaces) are identical.
@@ -301,7 +302,12 @@ static bool haveSimilarTypes(ASTContext &Context, QualType T1,
return false;
}
- if (T1 != T2)
+ // If we are casting to void, the 'From' value can be used to represent the
+ // 'To' value.
+ if (ToTy->isVoidType())
+ return true;
+
+ if (ToTy != FromTy)
return false;
return true;
@@ -314,19 +320,19 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
if (val.isUnknownOrUndef() || castTy == originalTy)
return val;
- // For const casts, just propagate the value.
+ // For const casts, casts to void, just propagate the value.
if (!castTy->isVariableArrayType() && !originalTy->isVariableArrayType())
- if (haveSimilarTypes(Context, Context.getPointerType(castTy),
- Context.getPointerType(originalTy)))
+ if (shouldBeModeledWithNoOp(Context, Context.getPointerType(castTy),
+ Context.getPointerType(originalTy)))
return val;
// Check for casts from pointers to integers.
if (castTy->isIntegerType() && Loc::isLocType(originalTy))
- return evalCastFromLoc(cast<Loc>(val), castTy);
+ return evalCastFromLoc(val.castAs<Loc>(), castTy);
// Check for casts from integers to pointers.
if (Loc::isLocType(castTy) && originalTy->isIntegerType()) {
- if (nonloc::LocAsInteger *LV = dyn_cast<nonloc::LocAsInteger>(&val)) {
+ if (Optional<nonloc::LocAsInteger> LV = val.getAs<nonloc::LocAsInteger>()) {
if (const MemRegion *R = LV->getLoc().getAsRegion()) {
StoreManager &storeMgr = StateMgr.getStoreManager();
R = storeMgr.castRegion(R, castTy);
@@ -346,7 +352,7 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
// Check for casts from array type to another type.
if (originalTy->isArrayType()) {
// We will always decay to a pointer.
- val = StateMgr.ArrayToPointer(cast<Loc>(val));
+ val = StateMgr.ArrayToPointer(val.castAs<Loc>());
// Are we casting from an array to a pointer? If so just pass on
// the decayed value.
@@ -361,7 +367,7 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
// need the original decayed type.
// QualType elemTy = cast<ArrayType>(originalTy)->getElementType();
// QualType pointerTy = C.getPointerType(elemTy);
- return evalCastFromLoc(cast<Loc>(val), castTy);
+ return evalCastFromLoc(val.castAs<Loc>(), castTy);
}
// Check for casts from a region to a specific type.
diff --git a/lib/StaticAnalyzer/Core/SVals.cpp b/lib/StaticAnalyzer/Core/SVals.cpp
index e34ab6a..38e216f 100644
--- a/lib/StaticAnalyzer/Core/SVals.cpp
+++ b/lib/StaticAnalyzer/Core/SVals.cpp
@@ -15,6 +15,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Basic/IdentifierTable.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
using llvm::APSInt;
@@ -29,13 +30,13 @@ using llvm::APSInt;
//===----------------------------------------------------------------------===//
bool SVal::hasConjuredSymbol() const {
- if (const nonloc::SymbolVal* SV = dyn_cast<nonloc::SymbolVal>(this)) {
+ if (Optional<nonloc::SymbolVal> SV = getAs<nonloc::SymbolVal>()) {
SymbolRef sym = SV->getSymbol();
if (isa<SymbolConjured>(sym))
return true;
}
- if (const loc::MemRegionVal *RV = dyn_cast<loc::MemRegionVal>(this)) {
+ if (Optional<loc::MemRegionVal> RV = getAs<loc::MemRegionVal>()) {
const MemRegion *R = RV->getRegion();
if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) {
SymbolRef sym = SR->getSymbol();
@@ -48,7 +49,7 @@ bool SVal::hasConjuredSymbol() const {
}
const FunctionDecl *SVal::getAsFunctionDecl() const {
- if (const loc::MemRegionVal* X = dyn_cast<loc::MemRegionVal>(this)) {
+ if (Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>()) {
const MemRegion* R = X->getRegion();
if (const FunctionTextRegion *CTR = R->getAs<FunctionTextRegion>())
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CTR->getDecl()))
@@ -65,10 +66,10 @@ const FunctionDecl *SVal::getAsFunctionDecl() const {
/// region. If that is the case, gets the underlining region.
SymbolRef SVal::getAsLocSymbol() const {
// FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
- if (const nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(this))
+ if (Optional<nonloc::LocAsInteger> X = getAs<nonloc::LocAsInteger>())
return X->getLoc().getAsLocSymbol();
- if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this)) {
+ if (Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>()) {
const MemRegion *R = X->stripCasts();
if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R))
return SymR->getSymbol();
@@ -78,7 +79,7 @@ SymbolRef SVal::getAsLocSymbol() const {
/// Get the symbol in the SVal or its base region.
SymbolRef SVal::getLocSymbolInBase() const {
- const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this);
+ Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>();
if (!X)
return 0;
@@ -101,7 +102,7 @@ SymbolRef SVal::getLocSymbolInBase() const {
/// Otherwise return 0.
SymbolRef SVal::getAsSymbol() const {
// FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
- if (const nonloc::SymbolVal *X = dyn_cast<nonloc::SymbolVal>(this))
+ if (Optional<nonloc::SymbolVal> X = getAs<nonloc::SymbolVal>())
return X->getSymbol();
return getAsLocSymbol();
@@ -110,7 +111,7 @@ SymbolRef SVal::getAsSymbol() const {
/// getAsSymbolicExpression - If this Sval wraps a symbolic expression then
/// return that expression. Otherwise return NULL.
const SymExpr *SVal::getAsSymbolicExpression() const {
- if (const nonloc::SymbolVal *X = dyn_cast<nonloc::SymbolVal>(this))
+ if (Optional<nonloc::SymbolVal> X = getAs<nonloc::SymbolVal>())
return X->getSymbol();
return getAsSymbol();
@@ -124,12 +125,11 @@ const SymExpr* SVal::getAsSymExpr() const {
}
const MemRegion *SVal::getAsRegion() const {
- if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this))
+ if (Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>())
return X->getRegion();
- if (const nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(this)) {
+ if (Optional<nonloc::LocAsInteger> X = getAs<nonloc::LocAsInteger>())
return X->getLoc().getAsRegion();
- }
return 0;
}
@@ -143,7 +143,7 @@ const void *nonloc::LazyCompoundVal::getStore() const {
return static_cast<const LazyCompoundValData*>(Data)->getStore();
}
-const TypedRegion *nonloc::LazyCompoundVal::getRegion() const {
+const TypedValueRegion *nonloc::LazyCompoundVal::getRegion() const {
return static_cast<const LazyCompoundValData*>(Data)->getRegion();
}
@@ -164,16 +164,15 @@ nonloc::CompoundVal::iterator nonloc::CompoundVal::end() const {
//===----------------------------------------------------------------------===//
bool SVal::isConstant() const {
- return isa<nonloc::ConcreteInt>(this) || isa<loc::ConcreteInt>(this);
+ return getAs<nonloc::ConcreteInt>() || getAs<loc::ConcreteInt>();
}
bool SVal::isConstant(int I) const {
- if (isa<loc::ConcreteInt>(*this))
- return cast<loc::ConcreteInt>(*this).getValue() == I;
- else if (isa<nonloc::ConcreteInt>(*this))
- return cast<nonloc::ConcreteInt>(*this).getValue() == I;
- else
- return false;
+ if (Optional<loc::ConcreteInt> LV = getAs<loc::ConcreteInt>())
+ return LV->getValue() == I;
+ if (Optional<nonloc::ConcreteInt> NV = getAs<nonloc::ConcreteInt>())
+ return NV->getValue() == I;
+ return false;
}
bool SVal::isZeroConstant() const {
@@ -215,13 +214,12 @@ SVal loc::ConcreteInt::evalBinOp(BasicValueFactory& BasicVals,
BinaryOperator::Opcode Op,
const loc::ConcreteInt& R) const {
- assert (Op == BO_Add || Op == BO_Sub ||
- (Op >= BO_LT && Op <= BO_NE));
+ assert(BinaryOperator::isComparisonOp(Op) || Op == BO_Sub);
- const llvm::APSInt* X = BasicVals.evalAPSInt(Op, getValue(), R.getValue());
+ const llvm::APSInt *X = BasicVals.evalAPSInt(Op, getValue(), R.getValue());
if (X)
- return loc::ConcreteInt(*X);
+ return nonloc::ConcreteInt(*X);
else
return UndefinedVal();
}
@@ -238,10 +236,10 @@ void SVal::dumpToStream(raw_ostream &os) const {
os << "Unknown";
break;
case NonLocKind:
- cast<NonLoc>(this)->dumpToStream(os);
+ castAs<NonLoc>().dumpToStream(os);
break;
case LocKind:
- cast<Loc>(this)->dumpToStream(os);
+ castAs<Loc>().dumpToStream(os);
break;
case UndefinedKind:
os << "Undefined";
@@ -252,7 +250,7 @@ void SVal::dumpToStream(raw_ostream &os) const {
void NonLoc::dumpToStream(raw_ostream &os) const {
switch (getSubKind()) {
case nonloc::ConcreteIntKind: {
- const nonloc::ConcreteInt& C = *cast<nonloc::ConcreteInt>(this);
+ const nonloc::ConcreteInt& C = castAs<nonloc::ConcreteInt>();
if (C.getValue().isUnsigned())
os << C.getValue().getZExtValue();
else
@@ -262,16 +260,16 @@ void NonLoc::dumpToStream(raw_ostream &os) const {
break;
}
case nonloc::SymbolValKind: {
- os << cast<nonloc::SymbolVal>(this)->getSymbol();
+ os << castAs<nonloc::SymbolVal>().getSymbol();
break;
}
case nonloc::LocAsIntegerKind: {
- const nonloc::LocAsInteger& C = *cast<nonloc::LocAsInteger>(this);
+ const nonloc::LocAsInteger& C = castAs<nonloc::LocAsInteger>();
os << C.getLoc() << " [as " << C.getNumBits() << " bit integer]";
break;
}
case nonloc::CompoundValKind: {
- const nonloc::CompoundVal& C = *cast<nonloc::CompoundVal>(this);
+ const nonloc::CompoundVal& C = castAs<nonloc::CompoundVal>();
os << "compoundVal{";
bool first = true;
for (nonloc::CompoundVal::iterator I=C.begin(), E=C.end(); I!=E; ++I) {
@@ -287,7 +285,7 @@ void NonLoc::dumpToStream(raw_ostream &os) const {
break;
}
case nonloc::LazyCompoundValKind: {
- const nonloc::LazyCompoundVal &C = *cast<nonloc::LazyCompoundVal>(this);
+ const nonloc::LazyCompoundVal &C = castAs<nonloc::LazyCompoundVal>();
os << "lazyCompoundVal{" << const_cast<void *>(C.getStore())
<< ',' << C.getRegion()
<< '}';
@@ -302,13 +300,13 @@ void NonLoc::dumpToStream(raw_ostream &os) const {
void Loc::dumpToStream(raw_ostream &os) const {
switch (getSubKind()) {
case loc::ConcreteIntKind:
- os << cast<loc::ConcreteInt>(this)->getValue().getZExtValue() << " (Loc)";
+ os << castAs<loc::ConcreteInt>().getValue().getZExtValue() << " (Loc)";
break;
case loc::GotoLabelKind:
- os << "&&" << cast<loc::GotoLabel>(this)->getLabel()->getName();
+ os << "&&" << castAs<loc::GotoLabel>().getLabel()->getName();
break;
case loc::MemRegionKind:
- os << '&' << cast<loc::MemRegionVal>(this)->getRegion()->getString();
+ os << '&' << castAs<loc::MemRegionVal>().getRegion()->getString();
break;
default:
llvm_unreachable("Pretty-printing not implemented for this Loc.");
diff --git a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
index 4236ee4..9b759df 100644
--- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
+++ b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
@@ -24,7 +24,7 @@ namespace ento {
SimpleConstraintManager::~SimpleConstraintManager() {}
bool SimpleConstraintManager::canReasonAbout(SVal X) const {
- nonloc::SymbolVal *SymVal = dyn_cast<nonloc::SymbolVal>(&X);
+ Optional<nonloc::SymbolVal> SymVal = X.getAs<nonloc::SymbolVal>();
if (SymVal && SymVal->isExpression()) {
const SymExpr *SE = SymVal->getSymbol();
@@ -49,6 +49,16 @@ bool SimpleConstraintManager::canReasonAbout(SVal X) const {
}
}
+ if (const SymSymExpr *SSE = dyn_cast<SymSymExpr>(SE)) {
+ if (BinaryOperator::isComparisonOp(SSE->getOpcode())) {
+ // We handle Loc <> Loc comparisons, but not (yet) NonLoc <> NonLoc.
+ if (Loc::isLocType(SSE->getLHS()->getType())) {
+ assert(Loc::isLocType(SSE->getRHS()->getType()));
+ return true;
+ }
+ }
+ }
+
return false;
}
@@ -58,10 +68,9 @@ bool SimpleConstraintManager::canReasonAbout(SVal X) const {
ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef state,
DefinedSVal Cond,
bool Assumption) {
- if (isa<NonLoc>(Cond))
- return assume(state, cast<NonLoc>(Cond), Assumption);
- else
- return assume(state, cast<Loc>(Cond), Assumption);
+ if (Optional<NonLoc> NV = Cond.getAs<NonLoc>())
+ return assume(state, *NV, Assumption);
+ return assume(state, Cond.castAs<Loc>(), Assumption);
}
ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef state, Loc cond,
@@ -82,7 +91,7 @@ ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef state,
case loc::MemRegionKind: {
// FIXME: Should this go into the storemanager?
- const MemRegion *R = cast<loc::MemRegionVal>(Cond).getRegion();
+ const MemRegion *R = Cond.castAs<loc::MemRegionVal>().getRegion();
const SubRegion *SubR = dyn_cast<SubRegion>(R);
while (SubR) {
@@ -104,7 +113,7 @@ ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef state,
return Assumption ? state : NULL;
case loc::ConcreteIntKind: {
- bool b = cast<loc::ConcreteInt>(Cond).getValue() != 0;
+ bool b = Cond.castAs<loc::ConcreteInt>().getValue() != 0;
bool isFeasible = b ? Assumption : !Assumption;
return isFeasible ? state : NULL;
}
@@ -120,21 +129,6 @@ ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef state,
return state;
}
-static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) {
- // FIXME: This should probably be part of BinaryOperator, since this isn't
- // the only place it's used. (This code was copied from SimpleSValBuilder.cpp.)
- switch (op) {
- default:
- llvm_unreachable("Invalid opcode.");
- case BO_LT: return BO_GE;
- case BO_GT: return BO_LE;
- case BO_LE: return BO_GT;
- case BO_GE: return BO_LT;
- case BO_EQ: return BO_NE;
- case BO_NE: return BO_EQ;
- }
-}
-
ProgramStateRef
SimpleConstraintManager::assumeAuxForSymbol(ProgramStateRef State,
@@ -165,14 +159,12 @@ ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef state,
return assumeAuxForSymbol(state, sym, Assumption);
}
- BasicValueFactory &BasicVals = getBasicVals();
-
switch (Cond.getSubKind()) {
default:
llvm_unreachable("'Assume' not implemented for this NonLoc");
case nonloc::SymbolValKind: {
- nonloc::SymbolVal& SV = cast<nonloc::SymbolVal>(Cond);
+ nonloc::SymbolVal SV = Cond.castAs<nonloc::SymbolVal>();
SymbolRef sym = SV.getSymbol();
assert(sym);
@@ -181,36 +173,55 @@ ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef state,
return assumeAuxForSymbol(state, sym, Assumption);
// Handle symbolic expression.
- } else {
+ } else if (const SymIntExpr *SE = dyn_cast<SymIntExpr>(sym)) {
// We can only simplify expressions whose RHS is an integer.
- const SymIntExpr *SE = dyn_cast<SymIntExpr>(sym);
- if (!SE)
- return assumeAuxForSymbol(state, sym, Assumption);
BinaryOperator::Opcode op = SE->getOpcode();
- // Implicitly compare non-comparison expressions to 0.
- if (!BinaryOperator::isComparisonOp(op)) {
- QualType T = SE->getType();
- const llvm::APSInt &zero = BasicVals.getValue(0, T);
- op = (Assumption ? BO_NE : BO_EQ);
- return assumeSymRel(state, SE, op, zero);
+ if (BinaryOperator::isComparisonOp(op)) {
+ if (!Assumption)
+ op = BinaryOperator::negateComparisonOp(op);
+
+ return assumeSymRel(state, SE->getLHS(), op, SE->getRHS());
}
- // From here on out, op is the real comparison we'll be testing.
- if (!Assumption)
- op = NegateComparison(op);
- return assumeSymRel(state, SE->getLHS(), op, SE->getRHS());
+ } else if (const SymSymExpr *SSE = dyn_cast<SymSymExpr>(sym)) {
+ // Translate "a != b" to "(b - a) != 0".
+ // We invert the order of the operands as a heuristic for how loop
+ // conditions are usually written ("begin != end") as compared to length
+ // calculations ("end - begin"). The more correct thing to do would be to
+ // canonicalize "a - b" and "b - a", which would allow us to treat
+ // "a != b" and "b != a" the same.
+ SymbolManager &SymMgr = getSymbolManager();
+ BinaryOperator::Opcode Op = SSE->getOpcode();
+ assert(BinaryOperator::isComparisonOp(Op));
+
+ // For now, we only support comparing pointers.
+ assert(Loc::isLocType(SSE->getLHS()->getType()));
+ assert(Loc::isLocType(SSE->getRHS()->getType()));
+ QualType DiffTy = SymMgr.getContext().getPointerDiffType();
+ SymbolRef Subtraction = SymMgr.getSymSymExpr(SSE->getRHS(), BO_Sub,
+ SSE->getLHS(), DiffTy);
+
+ const llvm::APSInt &Zero = getBasicVals().getValue(0, DiffTy);
+ Op = BinaryOperator::reverseComparisonOp(Op);
+ if (!Assumption)
+ Op = BinaryOperator::negateComparisonOp(Op);
+ return assumeSymRel(state, Subtraction, Op, Zero);
}
+
+ // If we get here, there's nothing else we can do but treat the symbol as
+ // opaque.
+ return assumeAuxForSymbol(state, sym, Assumption);
}
case nonloc::ConcreteIntKind: {
- bool b = cast<nonloc::ConcreteInt>(Cond).getValue() != 0;
+ bool b = Cond.castAs<nonloc::ConcreteInt>().getValue() != 0;
bool isFeasible = b ? Assumption : !Assumption;
return isFeasible ? state : NULL;
}
case nonloc::LocAsIntegerKind:
- return assumeAux(state, cast<nonloc::LocAsInteger>(Cond).getLoc(),
+ return assumeAux(state, Cond.castAs<nonloc::LocAsInteger>().getLoc(),
Assumption);
} // end switch
}
@@ -258,10 +269,14 @@ ProgramStateRef SimpleConstraintManager::assumeSymRel(ProgramStateRef state,
APSIntType ComparisonType = std::max(WraparoundType, APSIntType(Int));
llvm::APSInt ConvertedInt = ComparisonType.convert(Int);
+ // Prefer unsigned comparisons.
+ if (ComparisonType.getBitWidth() == WraparoundType.getBitWidth() &&
+ ComparisonType.isUnsigned() && !WraparoundType.isUnsigned())
+ Adjustment.setIsSigned(false);
+
switch (op) {
default:
- // No logic yet for other operators. assume the constraint is feasible.
- return state;
+ llvm_unreachable("invalid operation not caught by assertion above");
case BO_EQ:
return assumeSymEQ(state, Sym, ConvertedInt, Adjustment);
diff --git a/lib/StaticAnalyzer/Core/SimpleConstraintManager.h b/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
index 01f0b4e..10ddef1 100644
--- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
+++ b/lib/StaticAnalyzer/Core/SimpleConstraintManager.h
@@ -23,10 +23,10 @@ namespace ento {
class SimpleConstraintManager : public ConstraintManager {
SubEngine *SU;
- BasicValueFactory &BVF;
+ SValBuilder &SVB;
public:
- SimpleConstraintManager(SubEngine *subengine, BasicValueFactory &BV)
- : SU(subengine), BVF(BV) {}
+ SimpleConstraintManager(SubEngine *subengine, SValBuilder &SB)
+ : SU(subengine), SVB(SB) {}
virtual ~SimpleConstraintManager();
//===------------------------------------------------------------------===//
@@ -81,7 +81,8 @@ protected:
// Internal implementation.
//===------------------------------------------------------------------===//
- BasicValueFactory &getBasicVals() const { return BVF; }
+ BasicValueFactory &getBasicVals() const { return SVB.getBasicValueFactory(); }
+ SymbolManager &getSymbolManager() const { return SVB.getSymbolManager(); }
bool canReasonAbout(SVal X) const;
diff --git a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index fbc6ba0..5cc8926 100644
--- a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
using namespace clang;
@@ -60,16 +60,16 @@ SValBuilder *ento::createSimpleSValBuilder(llvm::BumpPtrAllocator &alloc,
//===----------------------------------------------------------------------===//
SVal SimpleSValBuilder::dispatchCast(SVal Val, QualType CastTy) {
- assert(isa<Loc>(&Val) || isa<NonLoc>(&Val));
- return isa<Loc>(Val) ? evalCastFromLoc(cast<Loc>(Val), CastTy)
- : evalCastFromNonLoc(cast<NonLoc>(Val), CastTy);
+ assert(Val.getAs<Loc>() || Val.getAs<NonLoc>());
+ return Val.getAs<Loc>() ? evalCastFromLoc(Val.castAs<Loc>(), CastTy)
+ : evalCastFromNonLoc(Val.castAs<NonLoc>(), CastTy);
}
SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) {
bool isLocType = Loc::isLocType(castTy);
- if (nonloc::LocAsInteger *LI = dyn_cast<nonloc::LocAsInteger>(&val)) {
+ if (Optional<nonloc::LocAsInteger> LI = val.getAs<nonloc::LocAsInteger>()) {
if (isLocType)
return LI->getLoc();
@@ -98,15 +98,21 @@ SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) {
}
// If value is a non integer constant, produce unknown.
- if (!isa<nonloc::ConcreteInt>(val))
+ if (!val.getAs<nonloc::ConcreteInt>())
return UnknownVal();
+ // Handle casts to a boolean type.
+ if (castTy->isBooleanType()) {
+ bool b = val.castAs<nonloc::ConcreteInt>().getValue().getBoolValue();
+ return makeTruthVal(b, castTy);
+ }
+
// Only handle casts from integers to integers - if val is an integer constant
// being cast to a non integer type, produce unknown.
if (!isLocType && !castTy->isIntegerType())
return UnknownVal();
- llvm::APSInt i = cast<nonloc::ConcreteInt>(val).getValue();
+ llvm::APSInt i = val.castAs<nonloc::ConcreteInt>().getValue();
BasicVals.getAPSIntType(castTy).apply(i);
if (isLocType)
@@ -134,10 +140,10 @@ SVal SimpleSValBuilder::evalCastFromLoc(Loc val, QualType castTy) {
if (castTy->isIntegerType()) {
unsigned BitWidth = Context.getTypeSize(castTy);
- if (!isa<loc::ConcreteInt>(val))
+ if (!val.getAs<loc::ConcreteInt>())
return makeLocAsInteger(val, BitWidth);
- llvm::APSInt i = cast<loc::ConcreteInt>(val).getValue();
+ llvm::APSInt i = val.castAs<loc::ConcreteInt>().getValue();
BasicVals.getAPSIntType(castTy).apply(i);
return makeIntVal(i);
}
@@ -155,7 +161,7 @@ SVal SimpleSValBuilder::evalCastFromLoc(Loc val, QualType castTy) {
SVal SimpleSValBuilder::evalMinus(NonLoc val) {
switch (val.getSubKind()) {
case nonloc::ConcreteIntKind:
- return cast<nonloc::ConcreteInt>(val).evalMinus(*this);
+ return val.castAs<nonloc::ConcreteInt>().evalMinus(*this);
default:
return UnknownVal();
}
@@ -164,7 +170,7 @@ SVal SimpleSValBuilder::evalMinus(NonLoc val) {
SVal SimpleSValBuilder::evalComplement(NonLoc X) {
switch (X.getSubKind()) {
case nonloc::ConcreteIntKind:
- return cast<nonloc::ConcreteInt>(X).evalComplement(*this);
+ return X.castAs<nonloc::ConcreteInt>().evalComplement(*this);
default:
return UnknownVal();
}
@@ -174,33 +180,6 @@ SVal SimpleSValBuilder::evalComplement(NonLoc X) {
// Transfer function for binary operators.
//===----------------------------------------------------------------------===//
-static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) {
- switch (op) {
- default:
- llvm_unreachable("Invalid opcode.");
- case BO_LT: return BO_GE;
- case BO_GT: return BO_LE;
- case BO_LE: return BO_GT;
- case BO_GE: return BO_LT;
- case BO_EQ: return BO_NE;
- case BO_NE: return BO_EQ;
- }
-}
-
-static BinaryOperator::Opcode ReverseComparison(BinaryOperator::Opcode op) {
- switch (op) {
- default:
- llvm_unreachable("Invalid opcode.");
- case BO_LT: return BO_GT;
- case BO_GT: return BO_LT;
- case BO_LE: return BO_GE;
- case BO_GE: return BO_LE;
- case BO_EQ:
- case BO_NE:
- return op;
- }
-}
-
SVal SimpleSValBuilder::MakeSymIntVal(const SymExpr *LHS,
BinaryOperator::Opcode op,
const llvm::APSInt &RHS,
@@ -331,15 +310,15 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
default:
return makeSymExprValNN(state, op, lhs, rhs, resultTy);
case nonloc::LocAsIntegerKind: {
- Loc lhsL = cast<nonloc::LocAsInteger>(lhs).getLoc();
+ Loc lhsL = lhs.castAs<nonloc::LocAsInteger>().getLoc();
switch (rhs.getSubKind()) {
case nonloc::LocAsIntegerKind:
return evalBinOpLL(state, op, lhsL,
- cast<nonloc::LocAsInteger>(rhs).getLoc(),
+ rhs.castAs<nonloc::LocAsInteger>().getLoc(),
resultTy);
case nonloc::ConcreteIntKind: {
// Transform the integer into a location and compare.
- llvm::APSInt i = cast<nonloc::ConcreteInt>(rhs).getValue();
+ llvm::APSInt i = rhs.castAs<nonloc::ConcreteInt>().getValue();
BasicVals.getAPSIntType(Context.VoidPtrTy).apply(i);
return evalBinOpLL(state, op, lhsL, makeLoc(i), resultTy);
}
@@ -356,7 +335,7 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
}
}
case nonloc::ConcreteIntKind: {
- llvm::APSInt LHSValue = cast<nonloc::ConcreteInt>(lhs).getValue();
+ llvm::APSInt LHSValue = lhs.castAs<nonloc::ConcreteInt>().getValue();
// If we're dealing with two known constants, just perform the operation.
if (const llvm::APSInt *KnownRHSValue = getKnownValue(state, rhs)) {
@@ -392,7 +371,7 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
case BO_GT:
case BO_LE:
case BO_GE:
- op = ReverseComparison(op);
+ op = BinaryOperator::reverseComparisonOp(op);
// FALL-THROUGH
case BO_EQ:
case BO_NE:
@@ -419,7 +398,7 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
}
case nonloc::SymbolValKind: {
// We only handle LHS as simple symbols or SymIntExprs.
- SymbolRef Sym = cast<nonloc::SymbolVal>(lhs).getSymbol();
+ SymbolRef Sym = lhs.castAs<nonloc::SymbolVal>().getSymbol();
// LHS is a symbolic expression.
if (const SymIntExpr *symIntExpr = dyn_cast<SymIntExpr>(Sym)) {
@@ -460,7 +439,7 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
case BO_EQ:
case BO_NE:
// Negate the comparison and make a value.
- opc = NegateComparison(opc);
+ opc = BinaryOperator::negateComparisonOp(opc);
assert(symIntExpr->getType() == resultTy);
return makeNonLoc(symIntExpr->getLHS(), opc,
symIntExpr->getRHS(), resultTy);
@@ -502,22 +481,21 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
// Otherwise, make a SymIntExpr out of the expression.
return MakeSymIntVal(symIntExpr, op, *RHSValue, resultTy);
}
+ }
-
- } else if (isa<SymbolData>(Sym)) {
- // Does the symbol simplify to a constant? If so, "fold" the constant
- // by setting 'lhs' to a ConcreteInt and try again.
- if (const llvm::APSInt *Constant = state->getConstraintManager()
- .getSymVal(state, Sym)) {
- lhs = nonloc::ConcreteInt(*Constant);
- continue;
- }
-
- // Is the RHS a constant?
- if (const llvm::APSInt *RHSValue = getKnownValue(state, rhs))
- return MakeSymIntVal(Sym, op, *RHSValue, resultTy);
+ // Does the symbolic expression simplify to a constant?
+ // If so, "fold" the constant by setting 'lhs' to a ConcreteInt
+ // and try again.
+ ConstraintManager &CMgr = state->getConstraintManager();
+ if (const llvm::APSInt *Constant = CMgr.getSymVal(state, Sym)) {
+ lhs = nonloc::ConcreteInt(*Constant);
+ continue;
}
+ // Is the RHS a constant?
+ if (const llvm::APSInt *RHSValue = getKnownValue(state, rhs))
+ return MakeSymIntVal(Sym, op, *RHSValue, resultTy);
+
// Give up -- this is not a symbolic expression we can handle.
return makeSymExprValNN(state, op, InputLHS, InputRHS, resultTy);
}
@@ -595,25 +573,27 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
if (!BinaryOperator::isComparisonOp(op))
return UnknownVal();
- const llvm::APSInt &lVal = cast<loc::ConcreteInt>(lhs).getValue();
- return makeNonLoc(rSym, ReverseComparison(op), lVal, resultTy);
+ const llvm::APSInt &lVal = lhs.castAs<loc::ConcreteInt>().getValue();
+ op = BinaryOperator::reverseComparisonOp(op);
+ return makeNonLoc(rSym, op, lVal, resultTy);
}
// If both operands are constants, just perform the operation.
- if (loc::ConcreteInt *rInt = dyn_cast<loc::ConcreteInt>(&rhs)) {
- SVal ResultVal = cast<loc::ConcreteInt>(lhs).evalBinOp(BasicVals, op,
- *rInt);
- if (Loc *Result = dyn_cast<Loc>(&ResultVal))
- return evalCastFromLoc(*Result, resultTy);
- else
- return UnknownVal();
+ if (Optional<loc::ConcreteInt> rInt = rhs.getAs<loc::ConcreteInt>()) {
+ SVal ResultVal =
+ lhs.castAs<loc::ConcreteInt>().evalBinOp(BasicVals, op, *rInt);
+ if (Optional<NonLoc> Result = ResultVal.getAs<NonLoc>())
+ return evalCastFromNonLoc(*Result, resultTy);
+
+ assert(!ResultVal.getAs<Loc>() && "Loc-Loc ops should not produce Locs");
+ return UnknownVal();
}
// Special case comparisons against NULL.
// This must come after the test if the RHS is a symbol, which is used to
// build constraints. The address of any non-symbolic region is guaranteed
// to be non-NULL, as is any label.
- assert(isa<loc::MemRegionVal>(rhs) || isa<loc::GotoLabel>(rhs));
+ assert(rhs.getAs<loc::MemRegionVal>() || rhs.getAs<loc::GotoLabel>());
if (lhs.isZeroConstant()) {
switch (op) {
default:
@@ -634,7 +614,7 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
return UnknownVal();
}
case loc::MemRegionKind: {
- if (loc::ConcreteInt *rInt = dyn_cast<loc::ConcreteInt>(&rhs)) {
+ if (Optional<loc::ConcreteInt> rInt = rhs.getAs<loc::ConcreteInt>()) {
// If one of the operands is a symbol and the other is a constant,
// build an expression for use by the constraint manager.
if (SymbolRef lSym = lhs.getAsLocSymbol())
@@ -676,11 +656,11 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
// regions, though.
return UnknownVal();
- const MemSpaceRegion *LeftMS = LeftMR->getMemorySpace();
- const MemSpaceRegion *RightMS = RightMR->getMemorySpace();
- const MemSpaceRegion *UnknownMS = MemMgr.getUnknownRegion();
const MemRegion *LeftBase = LeftMR->getBaseRegion();
const MemRegion *RightBase = RightMR->getBaseRegion();
+ const MemSpaceRegion *LeftMS = LeftBase->getMemorySpace();
+ const MemSpaceRegion *RightMS = RightBase->getMemorySpace();
+ const MemSpaceRegion *UnknownMS = MemMgr.getUnknownRegion();
// If the two regions are from different known memory spaces they cannot be
// equal. Also, assume that no symbolic region (whose memory space is
@@ -732,21 +712,21 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
// Get the left index and cast it to the correct type.
// If the index is unknown or undefined, bail out here.
SVal LeftIndexVal = LeftER->getIndex();
- NonLoc *LeftIndex = dyn_cast<NonLoc>(&LeftIndexVal);
+ Optional<NonLoc> LeftIndex = LeftIndexVal.getAs<NonLoc>();
if (!LeftIndex)
return UnknownVal();
- LeftIndexVal = evalCastFromNonLoc(*LeftIndex, resultTy);
- LeftIndex = dyn_cast<NonLoc>(&LeftIndexVal);
+ LeftIndexVal = evalCastFromNonLoc(*LeftIndex, ArrayIndexTy);
+ LeftIndex = LeftIndexVal.getAs<NonLoc>();
if (!LeftIndex)
return UnknownVal();
// Do the same for the right index.
SVal RightIndexVal = RightER->getIndex();
- NonLoc *RightIndex = dyn_cast<NonLoc>(&RightIndexVal);
+ Optional<NonLoc> RightIndex = RightIndexVal.getAs<NonLoc>();
if (!RightIndex)
return UnknownVal();
- RightIndexVal = evalCastFromNonLoc(*RightIndex, resultTy);
- RightIndex = dyn_cast<NonLoc>(&RightIndexVal);
+ RightIndexVal = evalCastFromNonLoc(*RightIndex, ArrayIndexTy);
+ RightIndex = RightIndexVal.getAs<NonLoc>();
if (!RightIndex)
return UnknownVal();
@@ -783,7 +763,6 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
}
// If we get here, we have no way of comparing the ElementRegions.
- return UnknownVal();
}
// See if both regions are fields of the same structure.
@@ -836,6 +815,13 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
llvm_unreachable("Fields not found in parent record's definition");
}
+ // At this point we're not going to get a good answer, but we can try
+ // conjuring an expression instead.
+ SymbolRef LHSSym = lhs.getAsLocSymbol();
+ SymbolRef RHSSym = rhs.getAsLocSymbol();
+ if (LHSSym && RHSSym)
+ return makeNonLoc(LHSSym, op, RHSSym, resultTy);
+
// If we get here, we have no way of comparing the regions.
return UnknownVal();
}
@@ -852,11 +838,12 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
// Special case: 'rhs' is an integer that has the same width as a pointer and
// we are using the integer location in a comparison. Normally this cannot be
- // triggered, but transfer functions like those for OSCommpareAndSwapBarrier32
+ // triggered, but transfer functions like those for OSCompareAndSwapBarrier32
// can generate comparisons that trigger this code.
// FIXME: Are all locations guaranteed to have pointer width?
if (BinaryOperator::isComparisonOp(op)) {
- if (nonloc::ConcreteInt *rhsInt = dyn_cast<nonloc::ConcreteInt>(&rhs)) {
+ if (Optional<nonloc::ConcreteInt> rhsInt =
+ rhs.getAs<nonloc::ConcreteInt>()) {
const llvm::APSInt *x = &rhsInt->getValue();
ASTContext &ctx = Context;
if (ctx.getTypeSize(ctx.VoidPtrTy) == x->getBitWidth()) {
@@ -873,8 +860,8 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
// We are dealing with pointer arithmetic.
// Handle pointer arithmetic on constant values.
- if (nonloc::ConcreteInt *rhsInt = dyn_cast<nonloc::ConcreteInt>(&rhs)) {
- if (loc::ConcreteInt *lhsInt = dyn_cast<loc::ConcreteInt>(&lhs)) {
+ if (Optional<nonloc::ConcreteInt> rhsInt = rhs.getAs<nonloc::ConcreteInt>()) {
+ if (Optional<loc::ConcreteInt> lhsInt = lhs.getAs<loc::ConcreteInt>()) {
const llvm::APSInt &leftI = lhsInt->getValue();
assert(leftI.isUnsigned());
llvm::APSInt rightI(rhsInt->getValue(), /* isUnsigned */ true);
@@ -904,7 +891,7 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
// Handle cases where 'lhs' is a region.
if (const MemRegion *region = lhs.getAsRegion()) {
- rhs = cast<NonLoc>(convertToArrayIndex(rhs));
+ rhs = convertToArrayIndex(rhs).castAs<NonLoc>();
SVal index = UnknownVal();
const MemRegion *superR = 0;
QualType elementType;
@@ -923,7 +910,7 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
elementType = resultTy->getPointeeType();
}
- if (NonLoc *indexV = dyn_cast<NonLoc>(&index)) {
+ if (Optional<NonLoc> indexV = index.getAs<NonLoc>()) {
return loc::MemRegionVal(MemMgr.getElementRegion(elementType, *indexV,
superR, getContext()));
}
@@ -936,10 +923,10 @@ const llvm::APSInt *SimpleSValBuilder::getKnownValue(ProgramStateRef state,
if (V.isUnknownOrUndef())
return NULL;
- if (loc::ConcreteInt* X = dyn_cast<loc::ConcreteInt>(&V))
+ if (Optional<loc::ConcreteInt> X = V.getAs<loc::ConcreteInt>())
return &X->getValue();
- if (nonloc::ConcreteInt* X = dyn_cast<nonloc::ConcreteInt>(&V))
+ if (Optional<nonloc::ConcreteInt> X = V.getAs<nonloc::ConcreteInt>())
return &X->getValue();
if (SymbolRef Sym = V.getAsSymbol())
diff --git a/lib/StaticAnalyzer/Core/Store.cpp b/lib/StaticAnalyzer/Core/Store.cpp
index 939ae54..a0c24fe 100644
--- a/lib/StaticAnalyzer/Core/Store.cpp
+++ b/lib/StaticAnalyzer/Core/Store.cpp
@@ -12,11 +12,11 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
-#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/CharUnits.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
using namespace clang;
using namespace ento;
@@ -223,13 +223,38 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy)
llvm_unreachable("unreachable");
}
+static bool regionMatchesCXXRecordType(SVal V, QualType Ty) {
+ const MemRegion *MR = V.getAsRegion();
+ if (!MR)
+ return true;
+
+ const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(MR);
+ if (!TVR)
+ return true;
+
+ const CXXRecordDecl *RD = TVR->getValueType()->getAsCXXRecordDecl();
+ if (!RD)
+ return true;
+
+ const CXXRecordDecl *Expected = Ty->getPointeeCXXRecordDecl();
+ if (!Expected)
+ Expected = Ty->getAsCXXRecordDecl();
+
+ return Expected->getCanonicalDecl() == RD->getCanonicalDecl();
+}
+
SVal StoreManager::evalDerivedToBase(SVal Derived, const CastExpr *Cast) {
+ // Sanity check to avoid doing the wrong thing in the face of
+ // reinterpret_cast.
+ if (!regionMatchesCXXRecordType(Derived, Cast->getSubExpr()->getType()))
+ return UnknownVal();
+
// Walk through the cast path to create nested CXXBaseRegions.
SVal Result = Derived;
for (CastExpr::path_const_iterator I = Cast->path_begin(),
E = Cast->path_end();
I != E; ++I) {
- Result = evalDerivedToBase(Result, (*I)->getType());
+ Result = evalDerivedToBase(Result, (*I)->getType(), (*I)->isVirtual());
}
return Result;
}
@@ -239,13 +264,16 @@ SVal StoreManager::evalDerivedToBase(SVal Derived, const CXXBasePath &Path) {
SVal Result = Derived;
for (CXXBasePath::const_iterator I = Path.begin(), E = Path.end();
I != E; ++I) {
- Result = evalDerivedToBase(Result, I->Base->getType());
+ Result = evalDerivedToBase(Result, I->Base->getType(),
+ I->Base->isVirtual());
}
return Result;
}
-SVal StoreManager::evalDerivedToBase(SVal Derived, QualType BaseType) {
- loc::MemRegionVal *DerivedRegVal = dyn_cast<loc::MemRegionVal>(&Derived);
+SVal StoreManager::evalDerivedToBase(SVal Derived, QualType BaseType,
+ bool IsVirtual) {
+ Optional<loc::MemRegionVal> DerivedRegVal =
+ Derived.getAs<loc::MemRegionVal>();
if (!DerivedRegVal)
return Derived;
@@ -255,7 +283,8 @@ SVal StoreManager::evalDerivedToBase(SVal Derived, QualType BaseType) {
assert(BaseDecl && "not a C++ object?");
const MemRegion *BaseReg =
- MRMgr.getCXXBaseObjectRegion(BaseDecl, DerivedRegVal->getRegion());
+ MRMgr.getCXXBaseObjectRegion(BaseDecl, DerivedRegVal->getRegion(),
+ IsVirtual);
return loc::MemRegionVal(BaseReg);
}
@@ -264,7 +293,7 @@ SVal StoreManager::evalDynamicCast(SVal Base, QualType DerivedType,
bool &Failed) {
Failed = false;
- loc::MemRegionVal *BaseRegVal = dyn_cast<loc::MemRegionVal>(&Base);
+ Optional<loc::MemRegionVal> BaseRegVal = Base.getAs<loc::MemRegionVal>();
if (!BaseRegVal)
return UnknownVal();
const MemRegion *BaseRegion = BaseRegVal->stripCasts(/*StripBases=*/false);
@@ -348,12 +377,12 @@ SVal StoreManager::getLValueFieldOrIvar(const Decl *D, SVal Base) {
if (Base.isUnknownOrUndef())
return Base;
- Loc BaseL = cast<Loc>(Base);
+ Loc BaseL = Base.castAs<Loc>();
const MemRegion* BaseR = 0;
switch (BaseL.getSubKind()) {
case loc::MemRegionKind:
- BaseR = cast<loc::MemRegionVal>(BaseL).getRegion();
+ BaseR = BaseL.castAs<loc::MemRegionVal>().getRegion();
break;
case loc::GotoLabelKind:
@@ -390,16 +419,16 @@ SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset,
// FIXME: For absolute pointer addresses, we just return that value back as
// well, although in reality we should return the offset added to that
// value.
- if (Base.isUnknownOrUndef() || isa<loc::ConcreteInt>(Base))
+ if (Base.isUnknownOrUndef() || Base.getAs<loc::ConcreteInt>())
return Base;
- const MemRegion* BaseRegion = cast<loc::MemRegionVal>(Base).getRegion();
+ const MemRegion* BaseRegion = Base.castAs<loc::MemRegionVal>().getRegion();
// Pointer of any type can be cast and used as array base.
const ElementRegion *ElemR = dyn_cast<ElementRegion>(BaseRegion);
// Convert the offset to the appropriate size and signedness.
- Offset = cast<NonLoc>(svalBuilder.convertToArrayIndex(Offset));
+ Offset = svalBuilder.convertToArrayIndex(Offset).castAs<NonLoc>();
if (!ElemR) {
//
@@ -417,15 +446,16 @@ SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset,
SVal BaseIdx = ElemR->getIndex();
- if (!isa<nonloc::ConcreteInt>(BaseIdx))
+ if (!BaseIdx.getAs<nonloc::ConcreteInt>())
return UnknownVal();
- const llvm::APSInt& BaseIdxI = cast<nonloc::ConcreteInt>(BaseIdx).getValue();
+ const llvm::APSInt &BaseIdxI =
+ BaseIdx.castAs<nonloc::ConcreteInt>().getValue();
// Only allow non-integer offsets if the base region has no offset itself.
// FIXME: This is a somewhat arbitrary restriction. We should be using
// SValBuilder here to add the two offsets without checking their types.
- if (!isa<nonloc::ConcreteInt>(Offset)) {
+ if (!Offset.getAs<nonloc::ConcreteInt>()) {
if (isa<ElementRegion>(BaseRegion->StripCasts()))
return UnknownVal();
@@ -434,7 +464,7 @@ SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset,
Ctx));
}
- const llvm::APSInt& OffI = cast<nonloc::ConcreteInt>(Offset).getValue();
+ const llvm::APSInt& OffI = Offset.castAs<nonloc::ConcreteInt>().getValue();
assert(BaseIdxI.isSigned());
// Compute the new index.
diff --git a/lib/StaticAnalyzer/Core/SymbolManager.cpp b/lib/StaticAnalyzer/Core/SymbolManager.cpp
index 0c5098b..de2f5bc 100644
--- a/lib/StaticAnalyzer/Core/SymbolManager.cpp
+++ b/lib/StaticAnalyzer/Core/SymbolManager.cpp
@@ -27,52 +27,33 @@ void SymExpr::dump() const {
dumpToStream(llvm::errs());
}
-static void print(raw_ostream &os, BinaryOperator::Opcode Op) {
- switch (Op) {
- default:
- llvm_unreachable("operator printing not implemented");
- case BO_Mul: os << '*' ; break;
- case BO_Div: os << '/' ; break;
- case BO_Rem: os << '%' ; break;
- case BO_Add: os << '+' ; break;
- case BO_Sub: os << '-' ; break;
- case BO_Shl: os << "<<" ; break;
- case BO_Shr: os << ">>" ; break;
- case BO_LT: os << "<" ; break;
- case BO_GT: os << '>' ; break;
- case BO_LE: os << "<=" ; break;
- case BO_GE: os << ">=" ; break;
- case BO_EQ: os << "==" ; break;
- case BO_NE: os << "!=" ; break;
- case BO_And: os << '&' ; break;
- case BO_Xor: os << '^' ; break;
- case BO_Or: os << '|' ; break;
- }
-}
-
void SymIntExpr::dumpToStream(raw_ostream &os) const {
os << '(';
getLHS()->dumpToStream(os);
- os << ") ";
- print(os, getOpcode());
- os << ' ' << getRHS().getZExtValue();
- if (getRHS().isUnsigned()) os << 'U';
+ os << ") "
+ << BinaryOperator::getOpcodeStr(getOpcode()) << ' '
+ << getRHS().getZExtValue();
+ if (getRHS().isUnsigned())
+ os << 'U';
}
void IntSymExpr::dumpToStream(raw_ostream &os) const {
- os << ' ' << getLHS().getZExtValue();
- if (getLHS().isUnsigned()) os << 'U';
- print(os, getOpcode());
- os << '(';
+ os << getLHS().getZExtValue();
+ if (getLHS().isUnsigned())
+ os << 'U';
+ os << ' '
+ << BinaryOperator::getOpcodeStr(getOpcode())
+ << " (";
getRHS()->dumpToStream(os);
- os << ") ";
+ os << ')';
}
void SymSymExpr::dumpToStream(raw_ostream &os) const {
os << '(';
getLHS()->dumpToStream(os);
- os << ") ";
- os << '(';
+ os << ") "
+ << BinaryOperator::getOpcodeStr(getOpcode())
+ << " (";
getRHS()->dumpToStream(os);
os << ')';
}
@@ -468,9 +449,7 @@ bool SymbolReaper::isLive(SymbolRef sym) {
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;
+ KnownLive = isLiveRegion(cast<SymbolRegionValue>(sym)->getRegion());
break;
case SymExpr::ConjuredKind:
KnownLive = false;
diff --git a/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp b/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp
index e09f4e3..d5706d6 100644
--- a/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp
+++ b/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp
@@ -12,8 +12,8 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
@@ -46,7 +46,8 @@ public:
} // end anonymous namespace
-void ento::createTextPathDiagnosticConsumer(PathDiagnosticConsumers &C,
+void ento::createTextPathDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
+ PathDiagnosticConsumers &C,
const std::string& out,
const Preprocessor &PP) {
C.push_back(new TextPathDiagnostics(out, PP.getDiagnostics()));
diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index 7dbac3c..d71e528 100644
--- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -20,31 +20,30 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/CallGraph.h"
-#include "clang/Analysis/Analyses/LiveVariables.h"
-#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h"
-#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
+#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h"
-
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
-#include "clang/Lex/Preprocessor.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/Program.h"
-#include "llvm/Support/Timer.h"
+#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Statistic.h"
-
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
#include <queue>
using namespace clang;
@@ -54,9 +53,11 @@ using llvm::SmallPtrSet;
static ExplodedNode::Auditor* CreateUbiViz();
STATISTIC(NumFunctionTopLevel, "The # of functions at top level.");
-STATISTIC(NumFunctionsAnalyzed, "The # of functions analysed (as top level).");
+STATISTIC(NumFunctionsAnalyzed,
+ "The # of functions and blocks analyzed (as top level "
+ "with inlining turned on).");
STATISTIC(NumBlocksInAnalyzedFunctions,
- "The # of basic blocks in the analyzed functions.");
+ "The # of basic blocks in the analyzed functions.");
STATISTIC(PercentReachableBlocks, "The % of reachable basic blocks.");
STATISTIC(MaxCFGSize, "The maximum number of basic blocks in a function.");
@@ -64,11 +65,13 @@ STATISTIC(MaxCFGSize, "The maximum number of basic blocks in a function.");
// Special PathDiagnosticConsumers.
//===----------------------------------------------------------------------===//
-static void createPlistHTMLDiagnosticConsumer(PathDiagnosticConsumers &C,
+static void createPlistHTMLDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts,
+ PathDiagnosticConsumers &C,
const std::string &prefix,
const Preprocessor &PP) {
- createHTMLDiagnosticConsumer(C, llvm::sys::path::parent_path(prefix), PP);
- createPlistDiagnosticConsumer(C, prefix, PP);
+ createHTMLDiagnosticConsumer(AnalyzerOpts, C,
+ llvm::sys::path::parent_path(prefix), PP);
+ createPlistDiagnosticConsumer(AnalyzerOpts, C, prefix, PP);
}
namespace {
@@ -188,13 +191,14 @@ public:
switch (Opts->AnalysisDiagOpt) {
default:
#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \
- case PD_##NAME: CREATEFN(PathConsumers, OutDir, PP); break;
+ case PD_##NAME: CREATEFN(*Opts.getPtr(), PathConsumers, OutDir, PP);\
+ break;
#include "clang/StaticAnalyzer/Core/Analyses.def"
}
} else if (Opts->AnalysisDiagOpt == PD_TEXT) {
// Create the text client even without a specified output file since
// it just uses diagnostic notes.
- createTextPathDiagnosticConsumer(PathConsumers, "", PP);
+ createTextPathDiagnosticConsumer(*Opts.getPtr(), PathConsumers, "", PP);
}
// Create the analyzer component creators.
@@ -208,14 +212,15 @@ public:
switch (Opts->AnalysisConstraintsOpt) {
default:
- llvm_unreachable("Unknown store manager.");
+ llvm_unreachable("Unknown constraint manager.");
#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \
case NAME##Model: CreateConstraintMgr = CREATEFN; break;
#include "clang/StaticAnalyzer/Core/Analyses.def"
}
}
- void DisplayFunction(const Decl *D, AnalysisMode Mode) {
+ void DisplayFunction(const Decl *D, AnalysisMode Mode,
+ ExprEngine::InliningModes IMode) {
if (!Opts->AnalyzerDisplayProgress)
return;
@@ -226,8 +231,18 @@ public:
if (Mode == AM_Syntax)
llvm::errs() << " (Syntax)";
- else if (Mode == AM_Path)
- llvm::errs() << " (Path)";
+ else if (Mode == AM_Path) {
+ llvm::errs() << " (Path, ";
+ switch (IMode) {
+ case ExprEngine::Inline_Minimal:
+ llvm::errs() << " Inline_Minimal";
+ break;
+ case ExprEngine::Inline_Regular:
+ llvm::errs() << " Inline_Regular";
+ break;
+ }
+ llvm::errs() << ")";
+ }
else
assert(Mode == (AM_Syntax | AM_Path) && "Unexpected mode!");
@@ -268,6 +283,12 @@ public:
virtual void HandleTranslationUnit(ASTContext &C);
+ /// \brief Determine which inlining mode should be used when this function is
+ /// analyzed. This allows to redefine the default inlining policies when
+ /// analyzing a given function.
+ ExprEngine::InliningModes
+ getInliningModeForFunction(const Decl *D, SetOfConstDecls Visited);
+
/// \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 HandleDeclsCallGraph(const unsigned LocalTUDeclsSize);
@@ -279,10 +300,14 @@ public:
/// set of functions which should be considered analyzed after analyzing the
/// given root function.
void HandleCode(Decl *D, AnalysisMode Mode,
+ ExprEngine::InliningModes IMode = ExprEngine::Inline_Minimal,
SetOfConstDecls *VisitedCallees = 0);
- void RunPathSensitiveChecks(Decl *D, SetOfConstDecls *VisitedCallees);
+ void RunPathSensitiveChecks(Decl *D,
+ ExprEngine::InliningModes IMode,
+ SetOfConstDecls *VisitedCallees);
void ActionExprEngine(Decl *D, bool ObjCGCEnabled,
+ ExprEngine::InliningModes IMode,
SetOfConstDecls *VisitedCallees);
/// Visitors for the RecursiveASTVisitor.
@@ -305,14 +330,25 @@ public:
// only determined when they are instantiated.
if (FD->isThisDeclarationADefinition() &&
!FD->isDependentContext()) {
+ assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false);
HandleCode(FD, RecVisitorMode);
}
return true;
}
bool VisitObjCMethodDecl(ObjCMethodDecl *MD) {
- if (MD->isThisDeclarationADefinition())
+ if (MD->isThisDeclarationADefinition()) {
+ assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false);
HandleCode(MD, RecVisitorMode);
+ }
+ return true;
+ }
+
+ bool VisitBlockDecl(BlockDecl *BD) {
+ if (BD->hasBody()) {
+ assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false);
+ HandleCode(BD, RecVisitorMode);
+ }
return true;
}
@@ -352,95 +388,90 @@ void AnalysisConsumer::storeTopLevelDecls(DeclGroupRef DG) {
}
}
-static bool shouldSkipFunction(CallGraphNode *N,
- SmallPtrSet<CallGraphNode*,24> Visited) {
- // We want to re-analyse the functions as top level in several cases:
+static bool shouldSkipFunction(const Decl *D,
+ SetOfConstDecls Visited,
+ SetOfConstDecls VisitedAsTopLevel) {
+ if (VisitedAsTopLevel.count(D))
+ return true;
+
+ // We want to re-analyse the functions as top level in the following 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.
+ // 'nil' and unless we analyze the 'init' functions as top level, we will
+ // not catch errors within defensive code.
// - We want to reanalyze all ObjC methods as top level to report Retain
// Count naming convention errors more aggressively.
- if (isa<ObjCMethodDecl>(N->getDecl()))
+ if (isa<ObjCMethodDecl>(D))
return false;
// Otherwise, if we visited the function before, do not reanalyze it.
- return Visited.count(N);
+ return Visited.count(D);
}
-void AnalysisConsumer::HandleDeclsCallGraph(const unsigned LocalTUDeclsSize) {
- // Otherwise, use the Callgraph to derive the order.
- // Build the Call Graph.
- CallGraph CG;
+ExprEngine::InliningModes
+AnalysisConsumer::getInliningModeForFunction(const Decl *D,
+ SetOfConstDecls Visited) {
+ // We want to reanalyze all ObjC methods as top level to report Retain
+ // Count naming convention errors more aggressively. But we should tune down
+ // inlining when reanalyzing an already inlined function.
+ if (Visited.count(D)) {
+ assert(isa<ObjCMethodDecl>(D) &&
+ "We are only reanalyzing ObjCMethods.");
+ const ObjCMethodDecl *ObjCM = cast<ObjCMethodDecl>(D);
+ if (ObjCM->getMethodFamily() != OMF_init)
+ return ExprEngine::Inline_Minimal;
+ }
- // Add all the top level declarations to the graph.
+ return ExprEngine::Inline_Regular;
+}
+
+void AnalysisConsumer::HandleDeclsCallGraph(const unsigned LocalTUDeclsSize) {
+ // Build the Call Graph by adding all the top level declarations to the graph.
// Note: CallGraph can trigger deserialization of more items from a pch
// (though HandleInterestingDecl); triggering additions to LocalTUDecls.
// We rely on random access to add the initially processed Decls to CG.
+ CallGraph CG;
for (unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {
CG.addToCallGraph(LocalTUDecls[i]);
}
- // Find the top level nodes - children of root + the unreachable (parentless)
- // nodes.
- llvm::SmallVector<CallGraphNode*, 24> TopLevelFunctions;
- for (CallGraph::nodes_iterator TI = CG.parentless_begin(),
- TE = CG.parentless_end(); TI != TE; ++TI) {
- TopLevelFunctions.push_back(*TI);
+ // Walk over all of the call graph nodes in topological order, so that we
+ // analyze parents before the children. Skip the functions inlined into
+ // the previously processed functions. Use external Visited set to identify
+ // inlined functions. The topological order allows the "do not reanalyze
+ // previously inlined function" performance heuristic to be triggered more
+ // often.
+ SetOfConstDecls Visited;
+ SetOfConstDecls VisitedAsTopLevel;
+ llvm::ReversePostOrderTraversal<clang::CallGraph*> RPOT(&CG);
+ for (llvm::ReversePostOrderTraversal<clang::CallGraph*>::rpo_iterator
+ I = RPOT.begin(), E = RPOT.end(); I != E; ++I) {
NumFunctionTopLevel++;
- }
- CallGraphNode *Entry = CG.getRoot();
- for (CallGraphNode::iterator I = Entry->begin(),
- E = Entry->end(); I != E; ++I) {
- TopLevelFunctions.push_back(*I);
- NumFunctionTopLevel++;
- }
- // Make sure the nodes are sorted in order reverse of their definition in the
- // translation unit. This step is very important for performance. It ensures
- // that we analyze the root functions before the externally available
- // subroutines.
- std::deque<CallGraphNode*> BFSQueue;
- for (llvm::SmallVector<CallGraphNode*, 24>::reverse_iterator
- TI = TopLevelFunctions.rbegin(), TE = TopLevelFunctions.rend();
- TI != TE; ++TI)
- BFSQueue.push_back(*TI);
-
- // BFS over all of the functions, while skipping the ones inlined into
- // the previously processed functions. Use external Visited set, which is
- // also modified when we inline a function.
- SmallPtrSet<CallGraphNode*,24> Visited;
- while(!BFSQueue.empty()) {
- CallGraphNode *N = BFSQueue.front();
- BFSQueue.pop_front();
-
- // Push the children into the queue.
- for (CallGraphNode::const_iterator CI = N->begin(),
- CE = N->end(); CI != CE; ++CI) {
- if (!shouldSkipFunction(*CI, Visited))
- BFSQueue.push_back(*CI);
- }
+ CallGraphNode *N = *I;
+ Decl *D = N->getDecl();
+
+ // Skip the abstract root node.
+ if (!D)
+ continue;
// Skip the functions which have been processed already or previously
// inlined.
- if (shouldSkipFunction(N, Visited))
+ if (shouldSkipFunction(D, Visited, VisitedAsTopLevel))
continue;
// Analyze the function.
SetOfConstDecls VisitedCallees;
- Decl *D = N->getDecl();
- assert(D);
- HandleCode(D, AM_Path,
+
+ HandleCode(D, AM_Path, getInliningModeForFunction(D, Visited),
(Mgr->options.InliningMode == All ? 0 : &VisitedCallees));
// Add the visited callees to the global visited set.
for (SetOfConstDecls::iterator I = VisitedCallees.begin(),
E = VisitedCallees.end(); I != E; ++I) {
- CallGraphNode *VN = CG.getNode(*I);
- if (VN)
- Visited.insert(VN);
+ Visited.insert(*I);
}
- Visited.insert(N);
+ VisitedAsTopLevel.insert(D);
}
}
@@ -503,16 +534,6 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
}
-static void FindBlocks(DeclContext *D, SmallVectorImpl<Decl*> &WL) {
- if (BlockDecl *BD = dyn_cast<BlockDecl>(D))
- WL.push_back(BD);
-
- for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end();
- I!=E; ++I)
- if (DeclContext *DC = dyn_cast<DeclContext>(*I))
- FindBlocks(DC, WL);
-}
-
static std::string getFunctionName(const Decl *D) {
if (const ObjCMethodDecl *ID = dyn_cast<ObjCMethodDecl>(D)) {
return ID->getSelector().getAsString();
@@ -548,40 +569,32 @@ AnalysisConsumer::getModeForDecl(Decl *D, AnalysisMode Mode) {
}
void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode,
+ ExprEngine::InliningModes IMode,
SetOfConstDecls *VisitedCallees) {
+ if (!D->hasBody())
+ return;
Mode = getModeForDecl(D, Mode);
if (Mode == AM_None)
return;
- DisplayFunction(D, Mode);
+ DisplayFunction(D, Mode, IMode);
CFG *DeclCFG = Mgr->getCFG(D);
if (DeclCFG) {
unsigned CFGSize = DeclCFG->size();
MaxCFGSize = MaxCFGSize < CFGSize ? CFGSize : MaxCFGSize;
}
-
// Clear the AnalysisManager of old AnalysisDeclContexts.
Mgr->ClearContexts();
-
- // Dispatch on the actions.
- SmallVector<Decl*, 10> WL;
- WL.push_back(D);
-
- if (D->hasBody() && Opts->AnalyzeNestedBlocks)
- FindBlocks(cast<DeclContext>(D), WL);
-
BugReporter BR(*Mgr);
- for (SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end();
- WI != WE; ++WI)
- if ((*WI)->hasBody()) {
- if (Mode & AM_Syntax)
- checkerMgr->runCheckersOnASTBody(*WI, *Mgr, BR);
- if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) {
- RunPathSensitiveChecks(*WI, VisitedCallees);
- NumFunctionsAnalyzed++;
- }
- }
+
+ if (Mode & AM_Syntax)
+ checkerMgr->runCheckersOnASTBody(D, *Mgr, BR);
+ if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) {
+ RunPathSensitiveChecks(D, IMode, VisitedCallees);
+ if (IMode != ExprEngine::Inline_Minimal)
+ NumFunctionsAnalyzed++;
+ }
}
//===----------------------------------------------------------------------===//
@@ -589,6 +602,7 @@ void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode,
//===----------------------------------------------------------------------===//
void AnalysisConsumer::ActionExprEngine(Decl *D, bool ObjCGCEnabled,
+ ExprEngine::InliningModes IMode,
SetOfConstDecls *VisitedCallees) {
// Construct the analysis engine. First check if the CFG is valid.
// FIXME: Inter-procedural analysis will need to handle invalid CFGs.
@@ -599,7 +613,7 @@ void AnalysisConsumer::ActionExprEngine(Decl *D, bool ObjCGCEnabled,
if (!Mgr->getAnalysisDeclContext(D)->getAnalysis<RelaxedLiveVariables>())
return;
- ExprEngine Eng(*Mgr, ObjCGCEnabled, VisitedCallees, &FunctionSummaries);
+ ExprEngine Eng(*Mgr, ObjCGCEnabled, VisitedCallees, &FunctionSummaries,IMode);
// Set the graph auditor.
OwningPtr<ExplodedNode::Auditor> Auditor;
@@ -610,7 +624,7 @@ void AnalysisConsumer::ActionExprEngine(Decl *D, bool ObjCGCEnabled,
// Execute the worklist algorithm.
Eng.ExecuteWorkList(Mgr->getAnalysisDeclContextManager().getStackFrame(D),
- Mgr->options.MaxNodes);
+ Mgr->options.getMaxNodesPerTopLevelFunction());
// Release the auditor (if any) so that it doesn't monitor the graph
// created BugReporter.
@@ -625,20 +639,21 @@ void AnalysisConsumer::ActionExprEngine(Decl *D, bool ObjCGCEnabled,
}
void AnalysisConsumer::RunPathSensitiveChecks(Decl *D,
+ ExprEngine::InliningModes IMode,
SetOfConstDecls *Visited) {
switch (Mgr->getLangOpts().getGC()) {
case LangOptions::NonGC:
- ActionExprEngine(D, false, Visited);
+ ActionExprEngine(D, false, IMode, Visited);
break;
case LangOptions::GCOnly:
- ActionExprEngine(D, true, Visited);
+ ActionExprEngine(D, true, IMode, Visited);
break;
case LangOptions::HybridGC:
- ActionExprEngine(D, false, Visited);
- ActionExprEngine(D, true, Visited);
+ ActionExprEngine(D, false, IMode, Visited);
+ ActionExprEngine(D, true, IMode, Visited);
break;
}
}
diff --git a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
index e8daa65..4fad5a8 100644
--- a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
+++ b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp
@@ -12,19 +12,19 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h"
-#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/StaticAnalyzer/Checkers/ClangCheckers.h"
+#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/CheckerOptInfo.h"
#include "clang/StaticAnalyzer/Core/CheckerRegistry.h"
-#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
-#include "clang/Frontend/FrontendDiagnostic.h"
-#include "clang/Basic/Diagnostic.h"
+#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/ADT/OwningPtr.h"
-#include "llvm/ADT/SmallVector.h"
using namespace clang;
using namespace ento;
diff --git a/lib/StaticAnalyzer/Frontend/FrontendActions.cpp b/lib/StaticAnalyzer/Frontend/FrontendActions.cpp
index 85a18ec..13971af 100644
--- a/lib/StaticAnalyzer/Frontend/FrontendActions.cpp
+++ b/lib/StaticAnalyzer/Frontend/FrontendActions.cpp
@@ -8,8 +8,8 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
-#include "clang/Frontend/CompilerInstance.h"
#include "AnalysisConsumer.h"
+#include "clang/Frontend/CompilerInstance.h"
using namespace clang;
using namespace ento;
diff --git a/lib/Tooling/CommonOptionsParser.cpp b/lib/Tooling/CommonOptionsParser.cpp
index 15091c7..99aff9f 100644
--- a/lib/Tooling/CommonOptionsParser.cpp
+++ b/lib/Tooling/CommonOptionsParser.cpp
@@ -38,8 +38,8 @@ const char *const CommonOptionsParser::HelpMessage =
"\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"
+ "\ta search for compile_commands.json will be attempted through all\n"
+ "\tparent paths 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"
diff --git a/lib/Tooling/CompilationDatabase.cpp b/lib/Tooling/CompilationDatabase.cpp
index 4149cda..b5b99cb 100644
--- a/lib/Tooling/CompilationDatabase.cpp
+++ b/lib/Tooling/CompilationDatabase.cpp
@@ -12,13 +12,13 @@
//
//===----------------------------------------------------------------------===//
-#include <sstream>
#include "clang/Tooling/CompilationDatabase.h"
#include "clang/Tooling/CompilationDatabasePluginRegistry.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/system_error.h"
+#include <sstream>
namespace clang {
namespace tooling {
@@ -72,7 +72,7 @@ findCompilationDatabaseFromDirectory(StringRef Directory,
CompilationDatabase *
CompilationDatabase::autoDetectFromSource(StringRef SourceFile,
std::string &ErrorMessage) {
- llvm::SmallString<1024> AbsolutePath(getAbsolutePath(SourceFile));
+ SmallString<1024> AbsolutePath(getAbsolutePath(SourceFile));
StringRef Directory = llvm::sys::path::parent_path(AbsolutePath);
CompilationDatabase *DB = findCompilationDatabaseFromDirectory(Directory,
@@ -87,7 +87,7 @@ CompilationDatabase::autoDetectFromSource(StringRef SourceFile,
CompilationDatabase *
CompilationDatabase::autoDetectFromDirectory(StringRef SourceDir,
std::string &ErrorMessage) {
- llvm::SmallString<1024> AbsolutePath(getAbsolutePath(SourceDir));
+ SmallString<1024> AbsolutePath(getAbsolutePath(SourceDir));
CompilationDatabase *DB = findCompilationDatabaseFromDirectory(AbsolutePath,
ErrorMessage);
@@ -132,6 +132,11 @@ FixedCompilationDatabase::getAllFiles() const {
return std::vector<std::string>();
}
+std::vector<CompileCommand>
+FixedCompilationDatabase::getAllCompileCommands() const {
+ return std::vector<CompileCommand>();
+}
+
// This anchor is used to force the linker to link in the generated object file
// and thus register the JSONCompilationDatabasePlugin.
extern volatile int JSONAnchorSource;
diff --git a/lib/Tooling/FileMatchTrie.cpp b/lib/Tooling/FileMatchTrie.cpp
index 8f25a8c..5eb4bb9 100644
--- a/lib/Tooling/FileMatchTrie.cpp
+++ b/lib/Tooling/FileMatchTrie.cpp
@@ -11,12 +11,12 @@
//
//===----------------------------------------------------------------------===//
-#include <sstream>
#include "clang/Tooling/FileMatchTrie.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/PathV2.h"
#include "llvm/Support/raw_ostream.h"
+#include <sstream>
namespace clang {
namespace tooling {
@@ -172,7 +172,7 @@ void FileMatchTrie::insert(StringRef NewPath) {
}
StringRef FileMatchTrie::findEquivalent(StringRef FileName,
- llvm::raw_ostream &Error) const {
+ raw_ostream &Error) const {
if (llvm::sys::path::is_relative(FileName)) {
Error << "Cannot resolve relative paths";
return StringRef();
diff --git a/lib/Tooling/JSONCompilationDatabase.cpp b/lib/Tooling/JSONCompilationDatabase.cpp
index cf35a25..254b069 100644
--- a/lib/Tooling/JSONCompilationDatabase.cpp
+++ b/lib/Tooling/JSONCompilationDatabase.cpp
@@ -12,7 +12,6 @@
//===----------------------------------------------------------------------===//
#include "clang/Tooling/JSONCompilationDatabase.h"
-
#include "clang/Tooling/CompilationDatabase.h"
#include "clang/Tooling/CompilationDatabasePluginRegistry.h"
#include "clang/Tooling/Tooling.h"
@@ -50,7 +49,9 @@ class CommandLineArgumentParser {
bool parseStringInto(std::string &String) {
do {
if (*Position == '"') {
- if (!parseQuotedStringInto(String)) return false;
+ if (!parseDoubleQuotedStringInto(String)) return false;
+ } else if (*Position == '\'') {
+ if (!parseSingleQuotedStringInto(String)) return false;
} else {
if (!parseFreeStringInto(String)) return false;
}
@@ -58,7 +59,7 @@ class CommandLineArgumentParser {
return true;
}
- bool parseQuotedStringInto(std::string &String) {
+ bool parseDoubleQuotedStringInto(std::string &String) {
if (!next()) return false;
while (*Position != '"') {
if (!skipEscapeCharacter()) return false;
@@ -68,12 +69,21 @@ class CommandLineArgumentParser {
return next();
}
+ bool parseSingleQuotedStringInto(std::string &String) {
+ if (!next()) return false;
+ while (*Position != '\'') {
+ 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 != '"');
+ } while (*Position != ' ' && *Position != '"' && *Position != '\'');
return true;
}
@@ -112,9 +122,9 @@ std::vector<std::string> unescapeCommandLine(
class JSONCompilationDatabasePlugin : public CompilationDatabasePlugin {
virtual CompilationDatabase *loadFromDirectory(
StringRef Directory, std::string &ErrorMessage) {
- llvm::SmallString<1024> JSONDatabasePath(Directory);
+ SmallString<1024> JSONDatabasePath(Directory);
llvm::sys::path::append(JSONDatabasePath, "compile_commands.json");
- llvm::OwningPtr<CompilationDatabase> Database(
+ OwningPtr<CompilationDatabase> Database(
JSONCompilationDatabase::loadFromFile(JSONDatabasePath, ErrorMessage));
if (!Database)
return NULL;
@@ -134,14 +144,14 @@ volatile int JSONAnchorSource = 0;
JSONCompilationDatabase *
JSONCompilationDatabase::loadFromFile(StringRef FilePath,
std::string &ErrorMessage) {
- llvm::OwningPtr<llvm::MemoryBuffer> DatabaseBuffer;
+ OwningPtr<llvm::MemoryBuffer> DatabaseBuffer;
llvm::error_code Result =
llvm::MemoryBuffer::getFile(FilePath, DatabaseBuffer);
if (Result != 0) {
ErrorMessage = "Error while opening JSON database: " + Result.message();
return NULL;
}
- llvm::OwningPtr<JSONCompilationDatabase> Database(
+ OwningPtr<JSONCompilationDatabase> Database(
new JSONCompilationDatabase(DatabaseBuffer.take()));
if (!Database->parse(ErrorMessage))
return NULL;
@@ -151,10 +161,10 @@ JSONCompilationDatabase::loadFromFile(StringRef FilePath,
JSONCompilationDatabase *
JSONCompilationDatabase::loadFromBuffer(StringRef DatabaseString,
std::string &ErrorMessage) {
- llvm::OwningPtr<llvm::MemoryBuffer> DatabaseBuffer(
+ OwningPtr<llvm::MemoryBuffer> DatabaseBuffer(
llvm::MemoryBuffer::getMemBuffer(DatabaseString));
- llvm::OwningPtr<JSONCompilationDatabase> Database(
- new JSONCompilationDatabase(DatabaseBuffer.take()));
+ OwningPtr<JSONCompilationDatabase> Database(
+ new JSONCompilationDatabase(DatabaseBuffer.take()));
if (!Database->parse(ErrorMessage))
return NULL;
return Database.take();
@@ -162,32 +172,20 @@ JSONCompilationDatabase::loadFromBuffer(StringRef DatabaseString,
std::vector<CompileCommand>
JSONCompilationDatabase::getCompileCommands(StringRef FilePath) const {
- llvm::SmallString<128> NativeFilePath;
+ SmallString<128> NativeFilePath;
llvm::sys::path::native(FilePath, NativeFilePath);
std::vector<StringRef> PossibleMatches;
std::string Error;
llvm::raw_string_ostream ES(Error);
StringRef Match = MatchTrie.findEquivalent(NativeFilePath.str(), ES);
- if (Match.empty()) {
- if (Error.empty())
- Error = "No match found.";
- llvm::outs() << Error << "\n";
+ if (Match.empty())
return std::vector<CompileCommand>();
- }
llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
CommandsRefI = IndexByFile.find(Match);
if (CommandsRefI == IndexByFile.end())
return std::vector<CompileCommand>();
- const std::vector<CompileCommandRef> &CommandsRef = CommandsRefI->getValue();
std::vector<CompileCommand> Commands;
- for (int I = 0, E = CommandsRef.size(); I != E; ++I) {
- llvm::SmallString<8> DirectoryStorage;
- llvm::SmallString<1024> CommandStorage;
- Commands.push_back(CompileCommand(
- // FIXME: Escape correctly:
- CommandsRef[I].first->getValue(DirectoryStorage),
- unescapeCommandLine(CommandsRef[I].second->getValue(CommandStorage))));
- }
+ getCommands(CommandsRefI->getValue(), Commands);
return Commands;
}
@@ -206,6 +204,30 @@ JSONCompilationDatabase::getAllFiles() const {
return Result;
}
+std::vector<CompileCommand>
+JSONCompilationDatabase::getAllCompileCommands() const {
+ std::vector<CompileCommand> Commands;
+ for (llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
+ CommandsRefI = IndexByFile.begin(), CommandsRefEnd = IndexByFile.end();
+ CommandsRefI != CommandsRefEnd; ++CommandsRefI) {
+ getCommands(CommandsRefI->getValue(), Commands);
+ }
+ return Commands;
+}
+
+void JSONCompilationDatabase::getCommands(
+ ArrayRef<CompileCommandRef> CommandsRef,
+ std::vector<CompileCommand> &Commands) const {
+ for (int I = 0, E = CommandsRef.size(); I != E; ++I) {
+ SmallString<8> DirectoryStorage;
+ SmallString<1024> CommandStorage;
+ Commands.push_back(CompileCommand(
+ // FIXME: Escape correctly:
+ CommandsRef[I].first->getValue(DirectoryStorage),
+ unescapeCommandLine(CommandsRef[I].second->getValue(CommandStorage))));
+ }
+}
+
bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
llvm::yaml::document_iterator I = YAMLStream.begin();
if (I == YAMLStream.end()) {
@@ -217,8 +239,7 @@ bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
ErrorMessage = "Error while parsing YAML.";
return false;
}
- llvm::yaml::SequenceNode *Array =
- llvm::dyn_cast<llvm::yaml::SequenceNode>(Root);
+ llvm::yaml::SequenceNode *Array = dyn_cast<llvm::yaml::SequenceNode>(Root);
if (Array == NULL) {
ErrorMessage = "Expected array.";
return false;
@@ -226,8 +247,7 @@ bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
for (llvm::yaml::SequenceNode::iterator AI = Array->begin(),
AE = Array->end();
AI != AE; ++AI) {
- llvm::yaml::MappingNode *Object =
- llvm::dyn_cast<llvm::yaml::MappingNode>(&*AI);
+ llvm::yaml::MappingNode *Object = dyn_cast<llvm::yaml::MappingNode>(&*AI);
if (Object == NULL) {
ErrorMessage = "Expected object.";
return false;
@@ -244,18 +264,18 @@ bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
return false;
}
llvm::yaml::ScalarNode *ValueString =
- llvm::dyn_cast<llvm::yaml::ScalarNode>(Value);
+ dyn_cast<llvm::yaml::ScalarNode>(Value);
if (ValueString == NULL) {
ErrorMessage = "Expected string as value.";
return false;
}
llvm::yaml::ScalarNode *KeyString =
- llvm::dyn_cast<llvm::yaml::ScalarNode>((*KVI).getKey());
+ dyn_cast<llvm::yaml::ScalarNode>((*KVI).getKey());
if (KeyString == NULL) {
ErrorMessage = "Expected strings as key.";
return false;
}
- llvm::SmallString<8> KeyStorage;
+ SmallString<8> KeyStorage;
if (KeyString->getValue(KeyStorage) == "directory") {
Directory = ValueString;
} else if (KeyString->getValue(KeyStorage) == "command") {
@@ -280,12 +300,12 @@ bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
ErrorMessage = "Missing key: \"directory\".";
return false;
}
- llvm::SmallString<8> FileStorage;
+ SmallString<8> FileStorage;
StringRef FileName = File->getValue(FileStorage);
- llvm::SmallString<128> NativeFilePath;
+ SmallString<128> NativeFilePath;
if (llvm::sys::path::is_relative(FileName)) {
- llvm::SmallString<8> DirectoryStorage;
- llvm::SmallString<128> AbsolutePath(
+ SmallString<8> DirectoryStorage;
+ SmallString<128> AbsolutePath(
Directory->getValue(DirectoryStorage));
llvm::sys::path::append(AbsolutePath, FileName);
llvm::sys::path::native(AbsolutePath.str(), NativeFilePath);
diff --git a/lib/Tooling/Refactoring.cpp b/lib/Tooling/Refactoring.cpp
index c5002ef..d8440d6 100644
--- a/lib/Tooling/Refactoring.cpp
+++ b/lib/Tooling/Refactoring.cpp
@@ -28,18 +28,18 @@ static const char * const InvalidLocation = "";
Replacement::Replacement()
: FilePath(InvalidLocation), Offset(0), Length(0) {}
-Replacement::Replacement(llvm::StringRef FilePath, unsigned Offset,
- unsigned Length, llvm::StringRef ReplacementText)
+Replacement::Replacement(StringRef FilePath, unsigned Offset,
+ unsigned Length, StringRef ReplacementText)
: FilePath(FilePath), Offset(Offset),
Length(Length), ReplacementText(ReplacementText) {}
Replacement::Replacement(SourceManager &Sources, SourceLocation Start,
- unsigned Length, llvm::StringRef ReplacementText) {
+ unsigned Length, StringRef ReplacementText) {
setFromSourceLocation(Sources, Start, Length, ReplacementText);
}
Replacement::Replacement(SourceManager &Sources, const CharSourceRange &Range,
- llvm::StringRef ReplacementText) {
+ StringRef ReplacementText) {
setFromSourceRange(Sources, Range, ReplacementText);
}
@@ -89,7 +89,7 @@ bool Replacement::Less::operator()(const Replacement &R1,
void Replacement::setFromSourceLocation(SourceManager &Sources,
SourceLocation Start, unsigned Length,
- llvm::StringRef ReplacementText) {
+ StringRef ReplacementText) {
const std::pair<FileID, unsigned> DecomposedLocation =
Sources.getDecomposedLoc(Start);
const FileEntry *Entry = Sources.getFileEntryForID(DecomposedLocation.first);
@@ -116,7 +116,7 @@ static int getRangeSize(SourceManager &Sources, const CharSourceRange &Range) {
void Replacement::setFromSourceRange(SourceManager &Sources,
const CharSourceRange &Range,
- llvm::StringRef ReplacementText) {
+ StringRef ReplacementText) {
setFromSourceLocation(Sources, Sources.getSpellingLoc(Range.getBegin()),
getRangeSize(Sources, Range), ReplacementText);
}
@@ -135,7 +135,38 @@ bool applyAllReplacements(Replacements &Replaces, Rewriter &Rewrite) {
return Result;
}
-bool saveRewrittenFiles(Rewriter &Rewrite) {
+RefactoringTool::RefactoringTool(const CompilationDatabase &Compilations,
+ ArrayRef<std::string> SourcePaths)
+ : ClangTool(Compilations, SourcePaths) {}
+
+Replacements &RefactoringTool::getReplacements() { return Replace; }
+
+int RefactoringTool::runAndSave(FrontendActionFactory *ActionFactory) {
+ if (int Result = run(ActionFactory)) {
+ return Result;
+ }
+
+ LangOptions DefaultLangOptions;
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), &*DiagOpts);
+ DiagnosticsEngine Diagnostics(
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
+ &*DiagOpts, &DiagnosticPrinter, false);
+ SourceManager Sources(Diagnostics, getFiles());
+ Rewriter Rewrite(Sources, DefaultLangOptions);
+
+ if (!applyAllReplacements(Rewrite)) {
+ llvm::errs() << "Skipped some replacements.\n";
+ }
+
+ return saveRewrittenFiles(Rewrite);
+}
+
+bool RefactoringTool::applyAllReplacements(Rewriter &Rewrite) {
+ return tooling::applyAllReplacements(Replace, Rewrite);
+}
+
+int RefactoringTool::saveRewrittenFiles(Rewriter &Rewrite) {
for (Rewriter::buffer_iterator I = Rewrite.buffer_begin(),
E = Rewrite.buffer_end();
I != E; ++I) {
@@ -148,37 +179,11 @@ bool saveRewrittenFiles(Rewriter &Rewrite) {
llvm::raw_fd_ostream FileStream(
Entry->getName(), ErrorInfo, llvm::raw_fd_ostream::F_Binary);
if (!ErrorInfo.empty())
- return false;
+ return 1;
I->second.write(FileStream);
FileStream.flush();
}
- return true;
-}
-
-RefactoringTool::RefactoringTool(const CompilationDatabase &Compilations,
- ArrayRef<std::string> SourcePaths)
- : Tool(Compilations, SourcePaths) {}
-
-Replacements &RefactoringTool::getReplacements() { return Replace; }
-
-int RefactoringTool::run(FrontendActionFactory *ActionFactory) {
- int Result = Tool.run(ActionFactory);
- LangOptions DefaultLangOptions;
- IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
- TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), &*DiagOpts);
- DiagnosticsEngine Diagnostics(
- llvm::IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
- &*DiagOpts, &DiagnosticPrinter, false);
- SourceManager Sources(Diagnostics, Tool.getFiles());
- Rewriter Rewrite(Sources, DefaultLangOptions);
- if (!applyAllReplacements(Replace, Rewrite)) {
- llvm::errs() << "Skipped some replacements.\n";
- }
- if (!saveRewrittenFiles(Rewrite)) {
- llvm::errs() << "Could not save rewritten files.\n";
- return 1;
- }
- return Result;
+ return 0;
}
} // end namespace tooling
diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp
index af20254..52855f6 100644
--- a/lib/Tooling/Tooling.cpp
+++ b/lib/Tooling/Tooling.cpp
@@ -12,16 +12,17 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Tooling/ArgumentsAdjusters.h"
#include "clang/Tooling/Tooling.h"
-#include "clang/Tooling/CompilationDatabase.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Tool.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Tooling/ArgumentsAdjusters.h"
+#include "clang/Tooling/CompilationDatabase.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/raw_ostream.h"
@@ -48,7 +49,7 @@ static clang::driver::Driver *newDriver(clang::DiagnosticsEngine *Diagnostics,
const std::string DefaultOutputName = "a.out";
clang::driver::Driver *CompilerDriver = new clang::driver::Driver(
BinaryName, llvm::sys::getDefaultTargetTriple(),
- DefaultOutputName, false, *Diagnostics);
+ DefaultOutputName, *Diagnostics);
CompilerDriver->setTitle("clang_based_tool");
return CompilerDriver;
}
@@ -63,7 +64,7 @@ static const clang::driver::ArgStringList *getCC1Arguments(
// failed. Extract that job from the Compilation.
const clang::driver::JobList &Jobs = Compilation->getJobs();
if (Jobs.size() != 1 || !isa<clang::driver::Command>(*Jobs.begin())) {
- llvm::SmallString<256> error_msg;
+ SmallString<256> error_msg;
llvm::raw_svector_ostream error_stream(error_msg);
Compilation->PrintJob(error_stream, Compilation->getJobs(), "; ", true);
Diagnostics->Report(clang::diag::err_fe_expected_compiler_job)
@@ -121,7 +122,7 @@ bool runToolOnCodeWithArgs(clang::FrontendAction *ToolAction, const Twine &Code,
}
std::string getAbsolutePath(StringRef File) {
- llvm::SmallString<1024> BaseDirectory;
+ SmallString<1024> BaseDirectory;
if (const char *PWD = ::getenv("PWD"))
BaseDirectory = PWD;
else
@@ -136,7 +137,7 @@ std::string getAbsolutePath(StringRef File) {
if (RelativePath.startswith("./")) {
RelativePath = RelativePath.substr(strlen("./"));
}
- llvm::SmallString<1024> AbsolutePath(BaseDirectory);
+ SmallString<1024> AbsolutePath(BaseDirectory);
llvm::sys::path::append(AbsolutePath, RelativePath);
llvm::sys::path::native(Twine(AbsolutePath), PathStorage);
return PathStorage.str();
@@ -163,31 +164,29 @@ bool ToolInvocation::run() {
TextDiagnosticPrinter DiagnosticPrinter(
llvm::errs(), &*DiagOpts);
DiagnosticsEngine Diagnostics(
- llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs>(new DiagnosticIDs()),
+ IntrusiveRefCntPtr<clang::DiagnosticIDs>(new DiagnosticIDs()),
&*DiagOpts, &DiagnosticPrinter, false);
- const llvm::OwningPtr<clang::driver::Driver> Driver(
+ const OwningPtr<clang::driver::Driver> Driver(
newDriver(&Diagnostics, BinaryName));
// Since the input might only be virtual, don't check whether it exists.
Driver->setCheckInputsExist(false);
- const llvm::OwningPtr<clang::driver::Compilation> Compilation(
+ const OwningPtr<clang::driver::Compilation> Compilation(
Driver->BuildCompilation(llvm::makeArrayRef(Argv)));
const clang::driver::ArgStringList *const CC1Args = getCC1Arguments(
&Diagnostics, Compilation.get());
if (CC1Args == NULL) {
return false;
}
- llvm::OwningPtr<clang::CompilerInvocation> Invocation(
+ OwningPtr<clang::CompilerInvocation> Invocation(
newInvocation(&Diagnostics, *CC1Args));
- return runInvocation(BinaryName, Compilation.get(), Invocation.take(),
- *CC1Args);
+ return runInvocation(BinaryName, Compilation.get(), Invocation.take());
}
bool ToolInvocation::runInvocation(
const char *BinaryName,
clang::driver::Compilation *Compilation,
- clang::CompilerInvocation *Invocation,
- const clang::driver::ArgStringList &CC1Args) {
+ clang::CompilerInvocation *Invocation) {
// Show the invocation, with -v.
if (Invocation->getHeaderSearchOpts().Verbose) {
llvm::errs() << "clang Invocation:\n";
@@ -204,11 +203,10 @@ bool ToolInvocation::runInvocation(
// ToolAction can have lifetime requirements for Compiler or its members, and
// we need to ensure it's deleted earlier than Compiler. So we pass it to an
// OwningPtr declared after the Compiler variable.
- llvm::OwningPtr<FrontendAction> ScopedToolAction(ToolAction.take());
+ OwningPtr<FrontendAction> ScopedToolAction(ToolAction.take());
// Create the compilers actual diagnostics engine.
- Compiler.createDiagnostics(CC1Args.size(),
- const_cast<char**>(CC1Args.data()));
+ Compiler.createDiagnostics();
if (!Compiler.hasDiagnostics())
return false;
@@ -241,7 +239,7 @@ ClangTool::ClangTool(const CompilationDatabase &Compilations,
: Files((FileSystemOptions())),
ArgsAdjuster(new ClangSyntaxOnlyAdjuster()) {
for (unsigned I = 0, E = SourcePaths.size(); I != E; ++I) {
- llvm::SmallString<1024> File(getAbsolutePath(SourcePaths[I]));
+ SmallString<1024> File(getAbsolutePath(SourcePaths[I]));
std::vector<CompileCommand> CompileCommandsForFile =
Compilations.getCompileCommands(File.str());
@@ -298,14 +296,19 @@ int ClangTool::run(FrontendActionFactory *ActionFactory) {
ArgsAdjuster->Adjust(CompileCommands[I].second.CommandLine);
assert(!CommandLine.empty());
CommandLine[0] = MainExecutable;
- llvm::outs() << "Processing: " << File << ".\n";
+ // FIXME: We need a callback mechanism for the tool writer to output a
+ // customized message for each file.
+ DEBUG({
+ llvm::dbgs() << "Processing: " << File << ".\n";
+ });
ToolInvocation Invocation(CommandLine, ActionFactory->create(), &Files);
for (int I = 0, E = MappedFileContents.size(); I != E; ++I) {
Invocation.mapVirtualFile(MappedFileContents[I].first,
MappedFileContents[I].second);
}
if (!Invocation.run()) {
- llvm::outs() << "Error while processing " << File << ".\n";
+ // FIXME: Diagnostics should be used instead.
+ llvm::errs() << "Error while processing " << File << ".\n";
ProcessingFailed = true;
}
}
diff --git a/runtime/compiler-rt/Makefile b/runtime/compiler-rt/Makefile
index 68b2941..e946de2 100644
--- a/runtime/compiler-rt/Makefile
+++ b/runtime/compiler-rt/Makefile
@@ -76,7 +76,8 @@ RuntimeDirs += darwin
RuntimeLibrary.darwin.Configs := \
eprintf.a 10.4.a osx.a ios.a cc_kext.a cc_kext_ios5.a \
asan_osx.a asan_osx_dynamic.dylib \
- profile_osx.a profile_ios.a
+ profile_osx.a profile_ios.a \
+ ubsan_osx.a
endif
# On Linux, include a library which has all the runtime functions.
@@ -98,19 +99,23 @@ TryCompile = \
# We currently only try to generate runtime libraries on x86.
ifeq ($(ARCH),x86)
RuntimeLibrary.linux.Configs += \
- full-i386.a profile-i386.a asan-i386.a
+ full-i386.a profile-i386.a san-i386.a asan-i386.a ubsan-i386.a \
+ ubsan_cxx-i386.a
endif
ifeq ($(ARCH),x86_64)
RuntimeLibrary.linux.Configs += \
- 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.
+ full-x86_64.a profile-x86_64.a san-x86_64.a asan-x86_64.a \
+ tsan-x86_64.a msan-x86_64.a ubsan-x86_64.a ubsan_cxx-x86_64.a
+# We need to build 32-bit ASan/UBsan libraries on 64-bit platform, and add them
+# to the list of runtime libraries to make
+# "clang -fsanitize=(address|undefined) -m32" work.
# 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
+RuntimeLibrary.linux.Configs += san-i386.a asan-i386.a ubsan-i386.a \
+ ubsan_cxx-i386.a
endif
ifneq ($(LLVM_ANDROID_TOOLCHAIN_DIR),)
RuntimeLibrary.linux.Configs += asan-arm-android.so
diff --git a/test/ARCMT/Common.h b/test/ARCMT/Common.h
index ed48949..b388eca 100644
--- a/test/ARCMT/Common.h
+++ b/test/ARCMT/Common.h
@@ -10,6 +10,7 @@
#define NS_INLINE static __inline__ __attribute__((always_inline))
#define nil ((void*) 0)
+#define NULL ((void*)0)
typedef int BOOL;
typedef unsigned NSUInteger;
@@ -102,3 +103,8 @@ NS_INLINE id CFBridgingRelease(CFTypeRef CF_CONSUMED X) {
}
#endif
+
+void *_Block_copy(const void *aBlock);
+void _Block_release(const void *aBlock);
+#define Block_copy(...) ((__typeof(__VA_ARGS__))_Block_copy((const void *)(__VA_ARGS__)))
+#define Block_release(...) _Block_release((const void *)(__VA_ARGS__))
diff --git a/test/ARCMT/autoreleases.m b/test/ARCMT/autoreleases.m
index a131bc5..543bcf6 100644
--- a/test/ARCMT/autoreleases.m
+++ b/test/ARCMT/autoreleases.m
@@ -64,3 +64,13 @@ void test(A *prevVal, A *newVal) {
[prevVal autorelease];
prevVal = [newVal retain];
}
+
+id test2(A* val) {
+ [[val retain] autorelease];
+ return val;
+}
+
+id test3() {
+ id a = [[A alloc] init];
+ [a autorelease];
+}
diff --git a/test/ARCMT/autoreleases.m.result b/test/ARCMT/autoreleases.m.result
index 6593fc9..9b71ff8 100644
--- a/test/ARCMT/autoreleases.m.result
+++ b/test/ARCMT/autoreleases.m.result
@@ -60,3 +60,11 @@ int main (int argc, const char * argv[]) {
void test(A *prevVal, A *newVal) {
prevVal = newVal;
}
+
+id test2(A* val) {
+ return val;
+}
+
+id test3() {
+ id a = [[A alloc] init];
+}
diff --git a/test/ARCMT/block_copy_release.m b/test/ARCMT/block_copy_release.m
new file mode 100644
index 0000000..ae3b826
--- /dev/null
+++ b/test/ARCMT/block_copy_release.m
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fblocks -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+typedef void (^blk)(int);
+
+void func(blk b) {
+ blk c = Block_copy(b);
+ Block_release(c);
+}
+
+void func2(id b) {
+ id c = Block_copy(b);
+ Block_release(c);
+}
diff --git a/test/ARCMT/block_copy_release.m.result b/test/ARCMT/block_copy_release.m.result
new file mode 100644
index 0000000..b292b64
--- /dev/null
+++ b/test/ARCMT/block_copy_release.m.result
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fblocks -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fblocks -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+
+#include "Common.h"
+
+typedef void (^blk)(int);
+
+void func(blk b) {
+ blk c = [b copy];
+}
+
+void func2(id b) {
+ id c = [b copy];
+}
diff --git a/test/ARCMT/check-with-pch.m b/test/ARCMT/check-with-pch.m
new file mode 100644
index 0000000..7867002
--- /dev/null
+++ b/test/ARCMT/check-with-pch.m
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -x objective-c -triple x86_64-apple-darwin10 %S/Common.h -emit-pch -o %t.pch
+// RUN: %clang_cc1 -include-pch %t.pch -arcmt-check -verify -triple x86_64-apple-darwin10 -fblocks -Werror %s
+// DISABLE: mingw32
+
+// rdar://9601437
+@interface I9601437 {
+ __unsafe_unretained id x;
+}
+-(void)Meth;
+@end
+
+@implementation I9601437
+-(void)Meth {
+ self->x = [NSObject new]; // expected-error {{assigning retained object}}
+}
+@end
diff --git a/test/ARCMT/checking.m b/test/ARCMT/checking.m
index 3ad911e..b06f4a7 100644
--- a/test/ARCMT/checking.m
+++ b/test/ARCMT/checking.m
@@ -117,7 +117,7 @@ void test1(A *a, BOOL b, struct UnsafeS *unsafeS) {
}
struct S {
- A* a; // expected-error {{ARC forbids Objective-C objects in structs or unions}}
+ A* a; // expected-error {{ARC forbids Objective-C objects in struct}}
};
@interface B
@@ -178,13 +178,13 @@ void test12(id collection) {
}
void test6(unsigned cond) {
- // FIXME: Fix this automatically ?
switch (cond) {
case 0:
;
id x; // expected-note {{jump bypasses initialization of retaining variable}}
case 1: // expected-error {{switch case is in protected scope}}
+ x = 0;
break;
}
}
@@ -293,10 +293,10 @@ id test9(Test9 *v) {
void rdar9491791(int p) {
switch (p) {
case 3:;
- NSObject *o = [[NSObject alloc] init]; // expected-note {{jump bypasses initialization of retaining variable}}
+ NSObject *o = [[NSObject alloc] init];
[o release];
break;
- default: // expected-error {{switch case is in protected scope}}
+ default:
break;
}
}
diff --git a/test/ARCMT/migrate-with-pch.m b/test/ARCMT/migrate-with-pch.m
new file mode 100644
index 0000000..7dca8be
--- /dev/null
+++ b/test/ARCMT/migrate-with-pch.m
@@ -0,0 +1,7 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c %S/Common.h -emit-pch -o %t.pch
+// RUN: %clang_cc1 -arcmt-migrate -mt-migrate-directory %t %S/Inputs/test1.m.in -x objective-c -include-pch %t.pch
+// RUN: %clang_cc1 -arcmt-migrate -mt-migrate-directory %t %S/Inputs/test2.m.in -x objective-c -include-pch %t.pch
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %S/Inputs/test1.m.in.result %S/Inputs/test2.m.in.result %S/Inputs/test.h.result
+// RUN: rm -rf %t
+// DISABLE: mingw32
diff --git a/test/ARCMT/nonobjc-to-objc-cast-2.m b/test/ARCMT/nonobjc-to-objc-cast-2.m
index 80d694e..e554c7d 100644
--- a/test/ARCMT/nonobjc-to-objc-cast-2.m
+++ b/test/ARCMT/nonobjc-to-objc-cast-2.m
@@ -54,3 +54,12 @@ CFStringRef f3() {
return (CFStringRef)[[[NSString alloc] init] autorelease]; // expected-error {{it is not safe to cast to 'CFStringRef' the result of 'autorelease' message; a __bridge cast may result in a pointer to a destroyed object and a __bridge_retained may leak the object}} \
// expected-note {{remove the cast and change return type of function to 'NSString *' to have the object automatically autoreleased}}
}
+
+extern void NSLog(NSString *format, ...);
+
+// rdar://13192395
+void f4(NSString *s) {
+ NSLog(@"%@", (CFStringRef)s); // expected-error {{cast of Objective-C pointer type 'NSString *' to C pointer type 'CFStringRef' (aka 'const struct __CFString *') requires a bridged cast}} \
+ // expected-note{{use __bridge to convert directly (no change in ownership)}} \
+ // expected-note{{use CFBridgingRetain call to make an ARC object available as a +1 'CFStringRef' (aka 'const struct __CFString *')}}
+}
diff --git a/test/ARCMT/objcmt-subscripting-literals-in-arc.m b/test/ARCMT/objcmt-subscripting-literals-in-arc.m
index 4d94162..1f56f4a 100644
--- a/test/ARCMT/objcmt-subscripting-literals-in-arc.m
+++ b/test/ARCMT/objcmt-subscripting-literals-in-arc.m
@@ -101,6 +101,8 @@ typedef const struct __CFString * CFStringRef;
dict = [NSDictionary dictionaryWithObjectsAndKeys: @"value1", @"key1", @"value2", @"key2", nil];
dict = [[NSDictionary alloc] initWithObjectsAndKeys: @"value1", @"key1", @"value2", @"key2", nil];
+ dict = [[NSDictionary alloc] initWithObjects:[[NSArray alloc] initWithObjects:@"1", @"2", nil] forKeys:[NSArray arrayWithObjects:@"A", @"B", nil]];
+
NSNumber *n = [[NSNumber alloc] initWithInt:2];
}
@end
diff --git a/test/ARCMT/objcmt-subscripting-literals-in-arc.m.result b/test/ARCMT/objcmt-subscripting-literals-in-arc.m.result
index 6f7a723..d974a25 100644
--- a/test/ARCMT/objcmt-subscripting-literals-in-arc.m.result
+++ b/test/ARCMT/objcmt-subscripting-literals-in-arc.m.result
@@ -101,6 +101,8 @@ typedef const struct __CFString * CFStringRef;
dict = @{@"key1": @"value1", @"key2": @"value2"};
dict = @{@"key1": @"value1", @"key2": @"value2"};
+ dict = @{@"A": @"1", @"B": @"2"};
+
NSNumber *n = @2;
}
@end
diff --git a/test/ARCMT/objcmt-subscripting-literals.m b/test/ARCMT/objcmt-subscripting-literals.m
index 0174fcf..8cef091 100644
--- a/test/ARCMT/objcmt-subscripting-literals.m
+++ b/test/ARCMT/objcmt-subscripting-literals.m
@@ -153,6 +153,10 @@ typedef const struct __CFString * CFStringRef;
void *hd;
o = [(NSArray*)hd objectAtIndex:2];
o = [ivarArr objectAtIndex:2];
+
+ dict = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"1", [NSArray array], nil] forKeys:[NSArray arrayWithObjects:@"A", [arr objectAtIndex:2], nil]];
+ dict = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"1", @"2", nil] forKeys:arr];
+ dict = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"1", @"2", nil] forKeys:@[@"A", @"B"]];
}
@end
diff --git a/test/ARCMT/objcmt-subscripting-literals.m.result b/test/ARCMT/objcmt-subscripting-literals.m.result
index 9975996..0ca6dca 100644
--- a/test/ARCMT/objcmt-subscripting-literals.m.result
+++ b/test/ARCMT/objcmt-subscripting-literals.m.result
@@ -153,6 +153,10 @@ typedef const struct __CFString * CFStringRef;
void *hd;
o = ((NSArray*)hd)[2];
o = ivarArr[2];
+
+ dict = @{@"A": @"1", arr[2]: @[]};
+ dict = [NSDictionary dictionaryWithObjects:@[@"1", @"2"] forKeys:arr];
+ dict = @{@"A": @"1", @"B": @"2"};
}
@end
diff --git a/test/ARCMT/objcmt-with-pch.m b/test/ARCMT/objcmt-with-pch.m
new file mode 100644
index 0000000..fac42c8
--- /dev/null
+++ b/test/ARCMT/objcmt-with-pch.m
@@ -0,0 +1,16 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -x objective-c %S/Common.h -emit-pch -o %t.pch
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -objcmt-migrate-literals -objcmt-migrate-subscripting -mt-migrate-directory %t %s -x objective-c -include-pch %t.pch
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c %s.result -include-pch %t.pch
+
+@interface NSNumber : NSObject
+@end
+
+@interface NSNumber (NSNumberCreation)
++ (NSNumber *)numberWithInt:(int)value;
+@end
+
+void foo() {
+ NSNumber *n = [NSNumber numberWithInt:1];
+}
diff --git a/test/ARCMT/objcmt-with-pch.m.result b/test/ARCMT/objcmt-with-pch.m.result
new file mode 100644
index 0000000..04eadc9
--- /dev/null
+++ b/test/ARCMT/objcmt-with-pch.m.result
@@ -0,0 +1,16 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -x objective-c %S/Common.h -emit-pch -o %t.pch
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -objcmt-migrate-literals -objcmt-migrate-subscripting -mt-migrate-directory %t %s -x objective-c -include-pch %t.pch
+// RUN: c-arcmt-test -mt-migrate-directory %t | arcmt-test -verify-transformed-files %s.result
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c %s.result -include-pch %t.pch
+
+@interface NSNumber : NSObject
+@end
+
+@interface NSNumber (NSNumberCreation)
++ (NSNumber *)numberWithInt:(int)value;
+@end
+
+void foo() {
+ NSNumber *n = @1;
+}
diff --git a/test/ARCMT/protected-scope.m b/test/ARCMT/protected-scope.m
new file mode 100644
index 0000000..8aece44
--- /dev/null
+++ b/test/ARCMT/protected-scope.m
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+// DISABLE: mingw32
+
+#include "Common.h"
+
+void test(id p, int x) {
+ int v;
+ switch(x) {
+ case 0:
+ v++;
+ id w1 = p;
+ id w2 = p;
+ break;
+ case 1:
+ v++;
+ id w3 = p;
+ break;
+ case 2:
+ case 3:
+ break;
+ default:
+ break;
+ }
+}
+
+void test2(int p) {
+ switch (p) {
+ case 3:;
+ NSObject *o = [[NSObject alloc] init];
+ [o release];
+ break;
+ default:
+ break;
+ }
+}
diff --git a/test/ARCMT/protected-scope.m.result b/test/ARCMT/protected-scope.m.result
new file mode 100644
index 0000000..f385d88
--- /dev/null
+++ b/test/ARCMT/protected-scope.m.result
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -fobjc-arc -x objective-c %s.result
+// RUN: arcmt-test --args -triple x86_64-apple-darwin10 -fsyntax-only -x objective-c %s > %t
+// RUN: diff %t %s.result
+// DISABLE: mingw32
+
+#include "Common.h"
+
+void test(id p, int x) {
+ int v;
+ switch(x) {
+ case 0: {
+ v++;
+ id w1 = p;
+ id w2 = p;
+ break;
+ }
+ case 1: {
+ v++;
+ id w3 = p;
+ break;
+ }
+ case 2:
+ case 3:
+ break;
+ default:
+ break;
+ }
+}
+
+void test2(int p) {
+ switch (p) {
+ case 3: {;
+ NSObject *o = [[NSObject alloc] init];
+ break;
+ }
+ default:
+ break;
+ }
+}
diff --git a/test/ASTMerge/Inputs/class1.cpp b/test/ASTMerge/Inputs/class1.cpp
index b600cdb..0cd6565 100644
--- a/test/ASTMerge/Inputs/class1.cpp
+++ b/test/ASTMerge/Inputs/class1.cpp
@@ -13,3 +13,7 @@ struct C {
C &operator=(C&);
~C();
};
+
+enum E {
+ b = 1
+};
diff --git a/test/ASTMerge/Inputs/class2.cpp b/test/ASTMerge/Inputs/class2.cpp
index fa38916..5d5d9ca 100644
--- a/test/ASTMerge/Inputs/class2.cpp
+++ b/test/ASTMerge/Inputs/class2.cpp
@@ -7,3 +7,7 @@ struct B : A {
int foo();
};
+enum E {
+ a = 0,
+ b = 1
+};
diff --git a/test/ASTMerge/class.cpp b/test/ASTMerge/class.cpp
index 114687f..885b65e 100644
--- a/test/ASTMerge/class.cpp
+++ b/test/ASTMerge/class.cpp
@@ -1,9 +1,14 @@
// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/class1.cpp
// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/class2.cpp
// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 -Wno-odr | count 0
// CHECK: class1.cpp:5:8: warning: type 'B' has incompatible definitions in different translation units
// CHECK: class1.cpp:6:9: note: field 'y' has type 'float' here
// CHECK: class2.cpp:6:7: note: field 'y' has type 'int' here
// FIXME: we should also complain about mismatched types on the method
+
+// CHECK: class1.cpp:17:6: warning: type 'E' has incompatible definitions in different translation units
+// CHECK: class1.cpp:18:3: note: enumerator 'b' with value 1 here
+// CHECK: class2.cpp:11:3: note: enumerator 'a' with value 0 here
diff --git a/test/Analysis/Inputs/system-header-simulator-cxx.h b/test/Analysis/Inputs/system-header-simulator-cxx.h
index e762d0a..eee0e31 100644
--- a/test/Analysis/Inputs/system-header-simulator-cxx.h
+++ b/test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -1,3 +1,8 @@
+// Like the compiler, the static analyzer treats some functions differently if
+// they come from a system header -- for example, it is assumed that system
+// functions do not arbitrarily free() their parameters, and that some bugs
+// found in system headers cannot be fixed by the user and should be
+// suppressed.
#pragma clang system_header
namespace std {
@@ -54,4 +59,35 @@ namespace std {
return 0;
}
};
+
+ class bad_alloc : public exception {
+ public:
+ bad_alloc() throw();
+ bad_alloc(const bad_alloc&) throw();
+ bad_alloc& operator=(const bad_alloc&) throw();
+ virtual const char* what() const throw() {
+ return 0;
+ }
+ };
+
+ struct nothrow_t {};
+
+ extern const nothrow_t nothrow;
+
+ template<class InputIter, class OutputIter>
+ OutputIter copy(InputIter II, InputIter IE, OutputIter OI) {
+ while (II != IE)
+ *OI++ = *II++;
+ return OI;
+ }
}
+
+void* operator new(std::size_t, const std::nothrow_t&) throw();
+void* operator new[](std::size_t, const std::nothrow_t&) throw();
+void operator delete(void*, const std::nothrow_t&) throw();
+void operator delete[](void*, const std::nothrow_t&) throw();
+
+void* operator new (std::size_t size, void* ptr) throw() { return ptr; };
+void* operator new[] (std::size_t size, void* ptr) throw() { return ptr; };
+void operator delete (void* ptr, void*) throw() {};
+void operator delete[] (void* ptr, void*) throw() {};
diff --git a/test/Analysis/Inputs/system-header-simulator-for-malloc.h b/test/Analysis/Inputs/system-header-simulator-for-malloc.h
new file mode 100644
index 0000000..e764556
--- /dev/null
+++ b/test/Analysis/Inputs/system-header-simulator-for-malloc.h
@@ -0,0 +1,34 @@
+// Like the compiler, the static analyzer treats some functions differently if
+// they come from a system header -- for example, it is assumed that system
+// functions do not arbitrarily free() their parameters, and that some bugs
+// found in system headers cannot be fixed by the user and should be
+// suppressed.
+#pragma clang system_header
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+void *calloc(size_t, size_t);
+void free(void *);
+
+
+#if __OBJC__
+
+#import "system-header-simulator-objc.h"
+
+@interface Wrapper : NSData
+- (id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)len;
+@end
+
+@implementation Wrapper
+- (id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)len {
+ return [self initWithBytesNoCopy:bytes length:len freeWhenDone:1]; // no-warning
+}
+@end
+
+@interface CustomData : NSData
++ (id)somethingNoCopy:(char *)bytes;
++ (id)somethingNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)freeBuffer;
++ (id)something:(char *)bytes freeWhenDone:(BOOL)freeBuffer;
+@end
+
+#endif
diff --git a/test/Analysis/Inputs/system-header-simulator-for-simple-stream.h b/test/Analysis/Inputs/system-header-simulator-for-simple-stream.h
index 99986f4..b65b7a6 100644
--- a/test/Analysis/Inputs/system-header-simulator-for-simple-stream.h
+++ b/test/Analysis/Inputs/system-header-simulator-for-simple-stream.h
@@ -1,4 +1,8 @@
-
+// Like the compiler, the static analyzer treats some functions differently if
+// they come from a system header -- for example, it is assumed that system
+// functions do not arbitrarily free() their parameters, and that some bugs
+// found in system headers cannot be fixed by the user and should be
+// suppressed.
#pragma clang system_header
typedef struct __sFILE {
@@ -9,3 +13,9 @@ int fputc(int, FILE *);
int fputs(const char * restrict, FILE * restrict) __asm("_" "fputs" );
int fclose(FILE *);
void exit(int);
+
+// The following is a fake system header function
+typedef struct __FileStruct {
+ FILE * p;
+} FileStruct;
+void fakeSystemHeaderCall(FileStruct *);
diff --git a/test/Analysis/Inputs/system-header-simulator-objc.h b/test/Analysis/Inputs/system-header-simulator-objc.h
index a647b37..ecc99e1 100644
--- a/test/Analysis/Inputs/system-header-simulator-objc.h
+++ b/test/Analysis/Inputs/system-header-simulator-objc.h
@@ -1,3 +1,8 @@
+// Like the compiler, the static analyzer treats some functions differently if
+// they come from a system header -- for example, it is assumed that system
+// functions do not arbitrarily free() their parameters, and that some bugs
+// found in system headers cannot be fixed by the user and should be
+// suppressed.
#pragma clang system_header
typedef unsigned int UInt32;
diff --git a/test/Analysis/Inputs/system-header-simulator.h b/test/Analysis/Inputs/system-header-simulator.h
index e28b890..04688c78 100644
--- a/test/Analysis/Inputs/system-header-simulator.h
+++ b/test/Analysis/Inputs/system-header-simulator.h
@@ -1,3 +1,8 @@
+// Like the compiler, the static analyzer treats some functions differently if
+// they come from a system header -- for example, it is assumed that system
+// functions do not arbitrarily free() their parameters, and that some bugs
+// found in system headers cannot be fixed by the user and should be
+// suppressed.
#pragma clang system_header
typedef struct _FILE FILE;
@@ -62,3 +67,11 @@ 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);
+
+//The following is a fake system header function
+void fakeSystemHeaderCallInt(int *);
+
+typedef struct __SomeStruct {
+ char * p;
+} SomeStruct;
+void fakeSystemHeaderCall(SomeStruct *);
diff --git a/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp b/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp
new file mode 100644
index 0000000..b0bb173
--- /dev/null
+++ b/test/Analysis/Malloc+MismatchedDeallocator+NewDelete.cpp
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator,alpha.cplusplus.NewDelete -analyzer-store region -std=c++11 -verify %s
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+void free(void *);
+
+//--------------------------------------------------
+// Check that unix.Malloc catches all types of bugs.
+//--------------------------------------------------
+void testMallocDoubleFree() {
+ int *p = (int *)malloc(sizeof(int));
+ free(p);
+ free(p); // expected-warning{{Attempt to free released memory}}
+}
+
+void testMallocLeak() {
+ int *p = (int *)malloc(sizeof(int));
+} // expected-warning{{Memory is never released; potential leak of memory pointed to by 'p'}}
+
+void testMallocUseAfterFree() {
+ int *p = (int *)malloc(sizeof(int));
+ free(p);
+ int j = *p; // expected-warning{{Use of memory after it is freed}}
+}
+
+void testMallocBadFree() {
+ int i;
+ free(&i); // expected-warning{{Argument to free() is the address of the local variable 'i', which is not memory allocated by malloc()}}
+}
+
+void testMallocOffsetFree() {
+ int *p = (int *)malloc(sizeof(int));
+ free(++p); // expected-warning{{Argument to free() is offset by 4 bytes from the start of memory allocated by malloc()}}
+}
+
+//-----------------------------------------------------------------
+// Check that unix.MismatchedDeallocator catches all types of bugs.
+//-----------------------------------------------------------------
+void testMismatchedDeallocator() {
+ int *x = (int *)malloc(sizeof(int));
+ delete x; // expected-warning{{Memory allocated by malloc() should be deallocated by free(), not 'delete'}}
+}
+
+//----------------------------------------------------------------
+// Check that alpha.cplusplus.NewDelete catches all types of bugs.
+//----------------------------------------------------------------
+void testNewDoubleFree() {
+ int *p = new int;
+ delete p;
+ delete p; // expected-warning{{Attempt to free released memory}}
+}
+
+void testNewLeak() {
+ int *p = new int;
+} // expected-warning{{Memory is never released; potential leak of memory pointed to by 'p'}}
+
+void testNewUseAfterFree() {
+ int *p = (int *)operator new(0);
+ delete p;
+ int j = *p; // expected-warning{{Use of memory after it is freed}}
+}
+
+void testNewBadFree() {
+ int i;
+ delete &i; // expected-warning{{Argument to 'delete' is the address of the local variable 'i', which is not memory allocated by 'new'}}
+}
+
+void testNewOffsetFree() {
+ int *p = new int;
+ operator delete(++p); // expected-warning{{Argument to operator delete is offset by 4 bytes from the start of memory allocated by 'new'}}
+}
diff --git a/test/Analysis/Malloc+MismatchedDeallocator_intersections.cpp b/test/Analysis/Malloc+MismatchedDeallocator_intersections.cpp
new file mode 100644
index 0000000..639790d
--- /dev/null
+++ b/test/Analysis/Malloc+MismatchedDeallocator_intersections.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,unix.MismatchedDeallocator -analyzer-store region -std=c++11 -verify %s
+// expected-no-diagnostics
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+void free(void *);
+
+//--------------------------------------------------------------------
+// Check that unix.Malloc + unix.MismatchedDeallocator does not enable
+// warnings produced by the alpha.cplusplus.NewDelete checker.
+//--------------------------------------------------------------------
+void testNewDeleteNoWarn() {
+ int i;
+ delete &i; // no-warning
+
+ int *p1 = new int;
+ delete ++p1; // no-warning
+
+ int *p2 = new int;
+ delete p2;
+ delete p2; // no-warning
+
+ int *p3 = new int; // no-warning
+
+ int *p4 = new int;
+ delete p4;
+ int j = *p4; // no-warning
+}
diff --git a/test/Analysis/Malloc+NewDelete_intersections.cpp b/test/Analysis/Malloc+NewDelete_intersections.cpp
new file mode 100644
index 0000000..7a0ef8e
--- /dev/null
+++ b/test/Analysis/Malloc+NewDelete_intersections.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,alpha.cplusplus.NewDelete -analyzer-store region -std=c++11 -verify %s
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+void free(void *);
+
+//-------------------------------------------------------------------
+// Check that unix.Malloc + alpha.cplusplus.NewDelete does not enable
+// warnings produced by unix.MismatchedDeallocator.
+//-------------------------------------------------------------------
+void testMismatchedDeallocator() {
+ int *p = (int *)malloc(sizeof(int));
+ delete p;
+} // expected-warning{{Memory is never released; potential leak of memory pointed to by 'p'}}
diff --git a/test/Analysis/NSContainers.m b/test/Analysis/NSContainers.m
new file mode 100644
index 0000000..d6fded5
--- /dev/null
+++ b/test/Analysis/NSContainers.m
@@ -0,0 +1,200 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.NilArg -verify -Wno-objc-root-class %s
+typedef unsigned long NSUInteger;
+typedef signed char BOOL;
+typedef struct _NSZone NSZone;
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+@protocol NSObject
+@end
+@protocol NSCopying
+- (id)copyWithZone:(NSZone *)zone;
+@end
+@protocol NSMutableCopying
+- (id)mutableCopyWithZone:(NSZone *)zone;
+@end
+@protocol NSCoding
+- (void)encodeWithCoder:(NSCoder *)aCoder;
+@end
+@protocol NSFastEnumeration
+@end
+@protocol NSSecureCoding <NSCoding>
+@required
++ (BOOL)supportsSecureCoding;
+@end
+@interface NSObject <NSObject> {}
+- (id)init;
++ (id)alloc;
+@end
+@interface NSArray : NSObject <NSCopying, NSMutableCopying, NSSecureCoding, NSFastEnumeration>
+
+- (NSUInteger)count;
+- (id)objectAtIndex:(NSUInteger)index;
+
+@end
+
+@interface NSArray (NSExtendedArray)
+- (NSArray *)arrayByAddingObject:(id)anObject;
+- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx __attribute__((availability(macosx,introduced=10.8)));
+@end
+
+@interface NSMutableArray : NSArray
+
+- (void)addObject:(id)anObject;
+- (void)insertObject:(id)anObject atIndex:(NSUInteger)index;
+- (void)removeLastObject;
+- (void)removeObjectAtIndex:(NSUInteger)index;
+- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject;
+
+@end
+
+@interface NSDictionary : NSObject <NSCopying, NSMutableCopying, NSSecureCoding, NSFastEnumeration>
+
+- (NSUInteger)count;
+- (id)objectForKey:(id)aKey;
+- (NSEnumerator *)keyEnumerator;
+
+@end
+
+@interface NSDictionary (NSDictionaryCreation)
+
++ (id)dictionary;
++ (id)dictionaryWithObject:(id)object forKey:(id <NSCopying>)key;
+@end
+
+@interface NSMutableDictionary : NSDictionary
+
+- (void)removeObjectForKey:(id)aKey;
+- (void)setObject:(id)anObject forKey:(id <NSCopying>)aKey;
+
+@end
+
+@interface NSMutableDictionary (NSExtendedMutableDictionary)
+
+- (void)addEntriesFromDictionary:(NSDictionary *)otherDictionary;
+- (void)removeAllObjects;
+- (void)removeObjectsForKeys:(NSArray *)keyArray;
+- (void)setDictionary:(NSDictionary *)otherDictionary;
+- (void)setObject:(id)obj forKeyedSubscript:(id <NSCopying>)key __attribute__((availability(macosx,introduced=10.8)));
+
+@end
+
+@interface NSString : NSObject <NSCopying, NSMutableCopying, NSSecureCoding>
+
+@end
+
+// NSMutableArray API
+void testNilArgNSMutableArray1() {
+ NSMutableArray *marray = [[NSMutableArray alloc] init];
+ [marray addObject:0]; // expected-warning {{Argument to 'NSMutableArray' method 'addObject:' cannot be nil}}
+}
+
+void testNilArgNSMutableArray2() {
+ NSMutableArray *marray = [[NSMutableArray alloc] init];
+ [marray insertObject:0 atIndex:1]; // expected-warning {{Argument to 'NSMutableArray' method 'insertObject:atIndex:' cannot be nil}}
+}
+
+void testNilArgNSMutableArray3() {
+ NSMutableArray *marray = [[NSMutableArray alloc] init];
+ [marray replaceObjectAtIndex:1 withObject:0]; // expected-warning {{Argument to 'NSMutableArray' method 'replaceObjectAtIndex:withObject:' cannot be nil}}
+}
+
+void testNilArgNSMutableArray4() {
+ NSMutableArray *marray = [[NSMutableArray alloc] init];
+ [marray setObject:0 atIndexedSubscript:1]; // expected-warning {{Argument to 'NSMutableArray' method 'setObject:atIndexedSubscript:' cannot be nil}}
+}
+
+void testNilArgNSMutableArray5() {
+ NSMutableArray *marray = [[NSMutableArray alloc] init];
+ marray[1] = 0; // expected-warning {{Array element cannot be nil}}
+}
+
+// NSArray API
+void testNilArgNSArray1() {
+ NSArray *array = [[NSArray alloc] init];
+ NSArray *copyArray = [array arrayByAddingObject:0]; // expected-warning {{Argument to 'NSArray' method 'arrayByAddingObject:' cannot be nil}}
+}
+
+// NSMutableDictionary and NSDictionary APIs.
+void testNilArgNSMutableDictionary1(NSMutableDictionary *d, NSString* key) {
+ [d setObject:0 forKey:key]; // expected-warning {{Argument to 'NSMutableDictionary' method 'setObject:forKey:' cannot be nil}}
+}
+
+void testNilArgNSMutableDictionary2(NSMutableDictionary *d, NSObject *obj) {
+ [d setObject:obj forKey:0]; // expected-warning {{Argument to 'NSMutableDictionary' method 'setObject:forKey:' cannot be nil}}
+}
+
+void testNilArgNSMutableDictionary3(NSMutableDictionary *d) {
+ [d removeObjectForKey:0]; // expected-warning {{Argument to 'NSMutableDictionary' method 'removeObjectForKey:' cannot be nil}}
+}
+
+void testNilArgNSMutableDictionary5(NSMutableDictionary *d, NSString* key) {
+ d[key] = 0; // expected-warning {{Dictionary object cannot be nil}}
+}
+void testNilArgNSMutableDictionary6(NSMutableDictionary *d, NSString *key) {
+ if (key)
+ ;
+ d[key] = 0; // expected-warning {{Dictionary key cannot be nil}}
+ // expected-warning@-1 {{Dictionary object cannot be nil}}
+}
+
+NSDictionary *testNilArgNSDictionary1(NSString* key) {
+ return [NSDictionary dictionaryWithObject:0 forKey:key]; // expected-warning {{Argument to 'NSDictionary' method 'dictionaryWithObject:forKey:' cannot be nil}}
+}
+NSDictionary *testNilArgNSDictionary2(NSObject *obj) {
+ return [NSDictionary dictionaryWithObject:obj forKey:0]; // expected-warning {{Argument to 'NSDictionary' method 'dictionaryWithObject:forKey:' cannot be nil}}
+}
+
+// Test inline defensive checks suppression.
+void idc(id x) {
+ if (x)
+ ;
+}
+void testIDC(NSMutableDictionary *d, NSString *key) {
+ idc(key);
+ d[key] = @"abc"; // no-warning
+}
+
+@interface Foo {
+@public
+ int x;
+}
+- (int *)getPtr;
+- (int)getInt;
+- (NSMutableDictionary *)getDictPtr;
+@property (retain, readonly, nonatomic) Foo* data;
+- (NSString*) stringForKeyFE: (id<NSCopying>)key;
+@end
+
+void idc2(id x) {
+ if (!x)
+ return;
+}
+Foo *retNil() {
+ return 0;
+}
+
+void testIDC2(Foo *obj) {
+ idc2(obj);
+ *[obj getPtr] = 1; // no-warning
+}
+
+int testIDC3(Foo *obj) {
+ idc2(obj);
+ return 1/[obj getInt];
+}
+
+void testNilReceiverIDC(Foo *obj, NSString *key) {
+ NSMutableDictionary *D = [obj getDictPtr];
+ idc(D);
+ D[key] = @"abc"; // no-warning
+}
+
+void testNilReceiverRetNil2(NSMutableDictionary *D, Foo *FooPtrIn, id value) {
+ NSString* const kKeyIdentifier = @"key";
+ Foo *FooPtr = retNil();
+ NSString *key = [[FooPtr data] stringForKeyFE: kKeyIdentifier];
+ // key is nil because FooPtr is nil. However, FooPtr is set to nil inside an
+ // inlined function, so this error report should be suppressed.
+ [D setObject: value forKey: key]; // no-warning
+}
+
+
diff --git a/test/Analysis/NSString.m b/test/Analysis/NSString.m
index 9339069..e390033 100644
--- a/test/Analysis/NSString.m
+++ b/test/Analysis/NSString.m
@@ -1,4 +1,5 @@
// 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 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,alpha.core -analyzer-store=region -analyzer-constraints=range -analyzer-config mode=shallow -verify -Wno-objc-root-class %s
// RUN: %clang_cc1 -DTEST_64 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.NilArg,osx.cocoa.RetainCount,alpha.core -analyzer-store=region -analyzer-constraints=range -verify -Wno-objc-root-class %s
@@ -404,3 +405,27 @@ void testOSCompareAndSwapXXBarrier_parameter_no_direct_release(NSString **old) {
else
return;
}
+
+@interface AlwaysInlineBodyFarmBodies : NSObject {
+ NSString *_value;
+}
+ - (NSString *)_value;
+ - (void)callValue;
+@end
+
+@implementation AlwaysInlineBodyFarmBodies
+
+- (NSString *)_value {
+ if (!_value) {
+ NSString *s = [[NSString alloc] init];
+ if (!OSAtomicCompareAndSwapPtr(0, s, (void**)&_value)) {
+ [s release];
+ }
+ }
+ return _value;
+}
+
+- (void)callValue {
+ [self _value];
+}
+@end \ No newline at end of file
diff --git a/test/Analysis/NewDelete+MismatchedDeallocator_intersections.cpp b/test/Analysis/NewDelete+MismatchedDeallocator_intersections.cpp
new file mode 100644
index 0000000..23b70b8
--- /dev/null
+++ b/test/Analysis/NewDelete+MismatchedDeallocator_intersections.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.cplusplus.NewDelete,unix.MismatchedDeallocator -analyzer-store region -std=c++11 -verify %s
+// expected-no-diagnostics
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+void free(void *);
+
+//------------------------------------------------------------------
+// Check that alpha.cplusplus.NewDelete + unix.MismatchedDeallocator
+// does not enable warnings produced by the unix.Malloc checker.
+//------------------------------------------------------------------
+void testMallocFreeNoWarn() {
+ int i;
+ free(&i); // no warn
+
+ int *p1 = (int *)malloc(sizeof(int));
+ free(++p1); // no warn
+
+ int *p2 = (int *)malloc(sizeof(int));
+ free(p2);
+ free(p2); // no warn
+
+ int *p3 = (int *)malloc(sizeof(int)); // no warn
+
+ int *p4 = (int *)malloc(sizeof(int));
+ free(p4);
+ int j = *p4; // no warn
+}
diff --git a/test/Analysis/NewDelete-checker-test.cpp b/test/Analysis/NewDelete-checker-test.cpp
new file mode 100644
index 0000000..c31d7f3
--- /dev/null
+++ b/test/Analysis/NewDelete-checker-test.cpp
@@ -0,0 +1,145 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.cplusplus.NewDelete -analyzer-store region -std=c++11 -fblocks -verify %s
+#include "Inputs/system-header-simulator-cxx.h"
+
+typedef __typeof__(sizeof(int)) size_t;
+extern "C" void *malloc(size_t);
+int *global;
+
+//------------------
+// check for leaks
+//------------------
+
+//----- Standard non-placement operators
+void testGlobalOpNew() {
+ void *p = operator new(0);
+} // expected-warning{{Memory is never released; potential leak}}
+
+void testGlobalOpNewArray() {
+ void *p = operator new[](0);
+} // expected-warning{{Memory is never released; potential leak}}
+
+void testGlobalNewExpr() {
+ int *p = new int;
+} // expected-warning{{Memory is never released; potential leak}}
+
+void testGlobalNewExprArray() {
+ int *p = new int[0];
+} // expected-warning{{Memory is never released; potential leak}}
+
+//----- Standard nothrow placement operators
+void testGlobalNoThrowPlacementOpNewBeforeOverload() {
+ void *p = operator new(0, std::nothrow);
+} // expected-warning{{Memory is never released; potential leak}}
+
+void testGlobalNoThrowPlacementExprNewBeforeOverload() {
+ int *p = new(std::nothrow) int;
+} // expected-warning{{Memory is never released; potential leak}}
+
+
+//----- Standard pointer placement operators
+void testGlobalPointerPlacementNew() {
+ int i;
+
+ void *p1 = operator new(0, &i); // no warn
+
+ void *p2 = operator new[](0, &i); // no warn
+
+ int *p3 = new(&i) int; // no warn
+
+ int *p4 = new(&i) int[0]; // no warn
+}
+
+//----- Other cases
+void testNewMemoryIsInHeap() {
+ int *p = new int;
+ if (global != p) // condition is always true as 'p' wraps a heap region that
+ // is different from a region wrapped by 'global'
+ global = p; // pointer escapes
+}
+
+struct PtrWrapper {
+ int *x;
+
+ PtrWrapper(int *input) : x(input) {}
+};
+
+void testNewInvalidationPlacement(PtrWrapper *w) {
+ // Ensure that we don't consider this a leak.
+ new (w) PtrWrapper(new int); // no warn
+}
+
+//---------------
+// other checks
+//---------------
+
+void f(int *);
+
+void testUseAfterDelete() {
+ int *p = new int;
+ delete p;
+ f(p); // expected-warning{{Use of memory after it is freed}}
+}
+
+void testDeleteAlloca() {
+ int *p = (int *)__builtin_alloca(sizeof(int));
+ delete p; // expected-warning{{Memory allocated by alloca() should not be deallocated}}
+}
+
+void testDoubleDelete() {
+ int *p = new int;
+ delete p;
+ delete p; // expected-warning{{Attempt to free released memory}}
+}
+
+void testExprDeleteArg() {
+ int i;
+ delete &i; // expected-warning{{Argument to 'delete' is the address of the local variable 'i', which is not memory allocated by 'new'}}
+}
+
+void testExprDeleteArrArg() {
+ int i;
+ delete[] &i; // expected-warning{{Argument to 'delete[]' is the address of the local variable 'i', which is not memory allocated by 'new[]'}}
+}
+
+void testAllocDeallocNames() {
+ int *p = new(std::nothrow) int[1];
+ delete[] (++p); // expected-warning{{Argument to 'delete[]' is offset by 4 bytes from the start of memory allocated by 'new[]'}}
+}
+
+//--------------------------------
+// Test escape of newed const pointer. Note, a const pointer can be deleted.
+//--------------------------------
+struct StWithConstPtr {
+ const int *memp;
+};
+void escape(const int &x);
+void escapeStruct(const StWithConstPtr &x);
+void escapePtr(const StWithConstPtr *x);
+void escapeVoidPtr(const void *x);
+
+void testConstEscape() {
+ int *p = new int(1);
+ escape(*p);
+} // no-warning
+
+void testConstEscapeStruct() {
+ StWithConstPtr *St = new StWithConstPtr();
+ escapeStruct(*St);
+} // no-warning
+
+void testConstEscapeStructPtr() {
+ StWithConstPtr *St = new StWithConstPtr();
+ escapePtr(St);
+} // no-warning
+
+void testConstEscapeMember() {
+ StWithConstPtr St;
+ St.memp = new int(2);
+ escapeVoidPtr(St.memp);
+} // no-warning
+
+void testConstEscapePlacementNew() {
+ int *x = (int *)malloc(sizeof(int));
+ void *y = new (x) int;
+ escapeVoidPtr(y);
+} // no-warning
diff --git a/test/Analysis/NewDelete-custom.cpp b/test/Analysis/NewDelete-custom.cpp
new file mode 100644
index 0000000..7d7796b
--- /dev/null
+++ b/test/Analysis/NewDelete-custom.cpp
@@ -0,0 +1,57 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.cplusplus.NewDelete,unix.Malloc -analyzer-store region -std=c++11 -fblocks -verify %s
+#include "Inputs/system-header-simulator-cxx.h"
+
+void *allocator(std::size_t size);
+
+void *operator new[](std::size_t size) throw() { return allocator(size); }
+void *operator new(std::size_t size) throw() { return allocator(size); }
+void *operator new(std::size_t size, std::nothrow_t& nothrow) throw() { return allocator(size); }
+void *operator new(std::size_t, double d);
+
+class C {
+public:
+ void *operator new(std::size_t);
+};
+
+void testNewMethod() {
+ void *p1 = C::operator new(0); // no warn
+
+ C *p2 = new C; // no warn
+
+ C *c3 = ::new C;
+} // expected-warning{{Memory is never released; potential leak}}
+
+void testOpNewArray() {
+ void *p = operator new[](0); // call is inlined, no warn
+}
+
+void testNewExprArray() {
+ int *p = new int[0];
+} // expected-warning{{Memory is never released; potential leak}}
+
+//----- Custom non-placement operators
+void testOpNew() {
+ void *p = operator new(0); // call is inlined, no warn
+}
+
+void testNewExpr() {
+ int *p = new int;
+} // expected-warning{{Memory is never released; potential leak}}
+
+//----- Custom NoThrow placement operators
+void testOpNewNoThrow() {
+ void *p = operator new(0, std::nothrow);
+} // expected-warning{{Memory is never released; potential leak}}
+
+void testNewExprNoThrow() {
+ int *p = new(std::nothrow) int;
+} // expected-warning{{Memory is never released; potential leak}}
+
+//----- Custom placement operators
+void testOpNewPlacement() {
+ void *p = operator new(0, 0.1); // no warn
+}
+
+void testNewExprPlacement() {
+ int *p = new(0.1) int; // no warn
+}
diff --git a/test/Analysis/NewDelete-intersections.mm b/test/Analysis/NewDelete-intersections.mm
new file mode 100644
index 0000000..3a87e4f
--- /dev/null
+++ b/test/Analysis/NewDelete-intersections.mm
@@ -0,0 +1,64 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.cplusplus.NewDelete -analyzer-store region -std=c++11 -fblocks -verify %s
+#include "Inputs/system-header-simulator-cxx.h"
+#include "Inputs/system-header-simulator-objc.h"
+
+typedef __typeof__(sizeof(int)) size_t;
+extern "C" void *malloc(size_t);
+extern "C" void free(void *);
+
+//----------------------------------------------------------------------------
+// Check for intersections with unix.Malloc and unix.MallocWithAnnotations
+// checkers bounded with cplusplus.NewDelete.
+//----------------------------------------------------------------------------
+
+//----- malloc()/free() are subjects of unix.Malloc and unix.MallocWithAnnotations
+void testMallocFreeNoWarn() {
+ int i;
+ free(&i); // no warn
+
+ int *p1 = (int *)malloc(sizeof(int));
+ free(++p1); // no warn
+
+ int *p2 = (int *)malloc(sizeof(int));
+ free(p2);
+ free(p2); // no warn
+
+ int *p3 = (int *)malloc(sizeof(int)); // no warn
+
+ int *p4 = (int *)malloc(sizeof(int));
+ free(p4);
+ int j = *p4; // no warn
+}
+
+void testDeleteMalloced() {
+ int *p = (int *)malloc(sizeof(int));
+ delete p; // no warn
+}
+
+//----- Test free standard new
+void testFreeOpNew() {
+ void *p = operator new(0);
+ free(p);
+} // expected-warning{{Memory is never released; potential leak}}
+
+void testFreeNewExpr() {
+ int *p = new int;
+ free(p);
+} // expected-warning{{Memory is never released; potential leak}}
+
+void testObjcFreeNewed() {
+ int *p = new int;
+ NSData *nsdata = [NSData dataWithBytesNoCopy:p length:sizeof(int) freeWhenDone:1]; // expected-warning{{Memory is never released; potential leak}}
+}
+
+void testFreeAfterDelete() {
+ int *p = new int;
+ delete p;
+ free(p); // expected-warning{{Use of memory after it is freed}}
+}
+
+void testStandardPlacementNewAfterDelete() {
+ int *p = new int;
+ delete p;
+ p = new(p) int; // expected-warning{{Use of memory after it is freed}}
+}
diff --git a/test/Analysis/NewDelete-path-notes.cpp b/test/Analysis/NewDelete-path-notes.cpp
new file mode 100644
index 0000000..eeb6105
--- /dev/null
+++ b/test/Analysis/NewDelete-path-notes.cpp
@@ -0,0 +1,323 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.cplusplus.NewDelete,unix.Malloc -analyzer-output=text -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.cplusplus.NewDelete,unix.Malloc -analyzer-output=plist %s -o %t.plist
+// RUN: FileCheck --input-file=%t.plist %s
+
+void test() {
+ int *p = new int;
+ // expected-note@-1 {{Memory is allocated}}
+ if (p)
+ // expected-note@-1 {{Assuming 'p' is non-null}}
+ // expected-note@-2 {{Taking true branch}}
+ delete p;
+ // expected-note@-1 {{Memory is released}}
+
+ delete p; // expected-warning {{Attempt to free released memory}}
+ // expected-note@-1 {{Attempt to free released memory}}
+}
+
+// CHECK: <key>diagnostics</key>
+// CHECK-NEXT:<array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>6</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>6</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>6</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>6</integer>
+// CHECK-NEXT: <key>col</key><integer>14</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>6</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>6</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>6</integer>
+// CHECK-NEXT: <key>col</key><integer>18</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Memory is allocated</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Memory is allocated</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>6</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>6</integer>
+// CHECK-NEXT: <key>col</key><integer>14</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>8</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>8</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>8</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>8</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>8</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>8</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>8</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>8</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>8</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Assuming &apos;p&apos; is non-null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;p&apos; is non-null</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>8</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>8</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Memory is released</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Memory is released</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>14</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>14</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>14</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>14</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>14</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Attempt to free released memory</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Attempt to free released memory</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Attempt to free released memory</string>
+// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>type</key><string>Double free</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test</string>
+// CHECK-NEXT: <key>issue_hash</key><string>9</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>14</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT:</array>
diff --git a/test/Analysis/NewDelete-variadic.cpp b/test/Analysis/NewDelete-variadic.cpp
new file mode 100644
index 0000000..129af1f
--- /dev/null
+++ b/test/Analysis/NewDelete-variadic.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.cplusplus.NewDelete,unix.Malloc -analyzer-store region -std=c++11 -fblocks -verify %s
+// expected-no-diagnostics
+
+namespace std {
+ typedef __typeof__(sizeof(int)) size_t;
+}
+
+void *operator new(std::size_t, ...);
+void *operator new[](std::size_t, ...);
+
+void testGlobalCustomVariadicNew() {
+ void *p1 = operator new(0); // no warn
+
+ void *p2 = operator new[](0); // no warn
+
+ int *p3 = new int; // no warn
+
+ int *p4 = new int[0]; // no warn
+}
diff --git a/test/Analysis/NoReturn.m b/test/Analysis/NoReturn.m
index 6d547f4..a58efdd 100644
--- a/test/Analysis/NoReturn.m
+++ b/test/Analysis/NoReturn.m
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -analyzer-constraints=range -verify %s
-// expected-no-diagnostics
+// RUN: %clang --analyze -Xclang -analyzer-checker=alpha.core -Xclang -verify %s
#include <stdarg.h>
@@ -88,3 +87,39 @@ int testCustomException(int *x) {
return *x; // no-warning
}
+// Test that __attribute__((analyzer_noreturn)) has the intended
+// effect on Objective-C methods.
+
+@interface Radar11634353
++ (void) doesNotReturn __attribute__((analyzer_noreturn));
+- (void) alsoDoesNotReturn __attribute__((analyzer_noreturn));
+@end
+
+void test_rdar11634353() {
+ [Radar11634353 doesNotReturn];
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+}
+
+void test_rdar11634352_instance(Radar11634353 *o) {
+ [o alsoDoesNotReturn];
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+}
+
+void test_rdar11634353_positive() {
+ int *p = 0;
+ *p = 0xDEADBEEF; // expected-warning {{null pointer}}
+}
+
+// Test analyzer_noreturn on category methods.
+@interface NSException (OBExtensions)
++ (void)raise:(NSString *)name reason:(NSString *)reason __attribute__((analyzer_noreturn));
+@end
+
+void PR11959(int *p) {
+ if (!p)
+ [NSException raise:@"Bad Pointer" reason:@"Who knows?"];
+ *p = 0xDEADBEEF; // no-warning
+}
+
diff --git a/test/Analysis/PR3991.m b/test/Analysis/PR3991.m
index 4d76fd3..5f0919d 100644
--- a/test/Analysis/PR3991.m
+++ b/test/Analysis/PR3991.m
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.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 -Wno-incomplete-implementation %s
+// expected-no-diagnostics
//===----------------------------------------------------------------------===//
// Delta-debugging produced forward declarations.
@@ -32,16 +33,16 @@ typedef struct _NSZone NSZone;
@protocol IHGoogleDocsAdapterDelegate - (void)googleDocsAdapter:(IHGoogleDocsAdapter*)inGoogleDocsAdapter accountVerifyIsValid:(BOOL)inIsValid error:(NSError *)inError;
@end @interface IHGoogleDocsAdapter : NSObject {
}
-- (NSArray *)entries; // expected-note {{method definition for 'entries' not found}}
+- (NSArray *)entries;
@end extern Class const kGDataUseRegisteredClass ;
-@interface IHGoogleDocsAdapter () - (GDataFeedDocList *)feedDocList; // expected-note {{method definition for 'feedDocList' not found}}
-- (NSArray *)directoryPathComponents; // expected-note {{method definition for 'directoryPathComponents' not found}}
-- (unsigned int)currentPathComponentIndex; // expected-note {{method definition for 'currentPathComponentIndex' not found}}
-- (void)setCurrentPathComponentIndex:(unsigned int)aCurrentPathComponentIndex; // expected-note {{method definition for 'setCurrentPathComponentIndex:' not found}}
-- (NSURL *)folderFeedURL; // expected-note {{method definition for 'folderFeedURL' not found}}
+@interface IHGoogleDocsAdapter () - (GDataFeedDocList *)feedDocList;
+- (NSArray *)directoryPathComponents;
+- (unsigned int)currentPathComponentIndex;
+- (void)setCurrentPathComponentIndex:(unsigned int)aCurrentPathComponentIndex;
+- (NSURL *)folderFeedURL;
@end
-@implementation IHGoogleDocsAdapter - (id)initWithUsername:(NSString *)inUsername password:(NSString *)inPassword owner:(NSObject <IHGoogleDocsAdapterDelegate> *)owner { // expected-warning {{incomplete implementation}}
+@implementation IHGoogleDocsAdapter - (id)initWithUsername:(NSString *)inUsername password:(NSString *)inPassword owner:(NSObject <IHGoogleDocsAdapterDelegate> *)owner {
return 0;
}
diff --git a/test/Analysis/additive-folding-range-constraints.c b/test/Analysis/additive-folding-range-constraints.c
index 7eb55ab..b22eb2a 100644
--- a/test/Analysis/additive-folding-range-constraints.c
+++ b/test/Analysis/additive-folding-range-constraints.c
@@ -170,3 +170,135 @@ void mixedComparisons9(signed char a) {
clang_analyzer_eval(a == 0x7F); // expected-warning{{UNKNOWN}}
clang_analyzer_eval(a == -0x80); // expected-warning{{UNKNOWN}}
}
+
+
+void mixedSignedness1(int a) {
+ unsigned max = UINT_MAX;
+ clang_analyzer_eval(a < max); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval((a + 2) < max); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval((a + 2U) < max); // expected-warning{{UNKNOWN}}
+}
+
+void mixedSignedness2(int a) {
+ unsigned max = UINT_MAX;
+ clang_analyzer_eval(a <= max); // expected-warning{{TRUE}}
+ clang_analyzer_eval((a + 2) <= max); // expected-warning{{TRUE}}
+ clang_analyzer_eval((a + 2U) <= max); // expected-warning{{TRUE}}
+}
+
+void mixedSignedness3(unsigned a) {
+ int max = INT_MAX;
+ clang_analyzer_eval(a < max); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval((a + 2) < max); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval((a + 2U) < max); // expected-warning{{UNKNOWN}}
+}
+
+void mixedSignedness4(unsigned a) {
+ int max = INT_MAX;
+ clang_analyzer_eval(a <= max); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval((a + 2) <= max); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval((a + 2U) <= max); // expected-warning{{UNKNOWN}}
+}
+
+void mixedSignedness5(unsigned a) {
+ int min = INT_MIN;
+ clang_analyzer_eval(a < min); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval((a + 2) < min); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval((a + 2U) < min); // expected-warning{{UNKNOWN}}
+}
+
+void mixedSignedness6(unsigned a) {
+ int min = INT_MIN;
+ clang_analyzer_eval(a <= min); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval((a + 2) <= min); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval((a + 2U) <= min); // expected-warning{{UNKNOWN}}
+}
+
+void mixedSignedness7(unsigned a) {
+ unsigned min = 0;
+ clang_analyzer_eval(a < min); // expected-warning{{FALSE}}
+ clang_analyzer_eval((a + 2) < min); // expected-warning{{FALSE}}
+ clang_analyzer_eval((a + 2U) < min); // expected-warning{{FALSE}}
+}
+
+void mixedSignedness8(unsigned a) {
+ unsigned min = 0;
+ clang_analyzer_eval(a <= min); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval((a + 2) <= min); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval((a + 2U) <= min); // expected-warning{{UNKNOWN}}
+}
+
+void mixedSignedness9(unsigned a) {
+ int min = 0;
+ clang_analyzer_eval(a < min); // expected-warning{{FALSE}}
+ clang_analyzer_eval((a + 2) < min); // expected-warning{{FALSE}}
+ clang_analyzer_eval((a + 2U) < min); // expected-warning{{FALSE}}
+}
+
+void mixedSignedness10(unsigned a) {
+ int min = 0;
+ clang_analyzer_eval(a <= min); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval((a + 2) <= min); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval((a + 2U) <= min); // expected-warning{{UNKNOWN}}
+}
+
+void mixedSignedness11(int a) {
+ int min = 0;
+ clang_analyzer_eval(a < min); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval((a + 2) < min); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval((a + 2U) < min); // expected-warning{{FALSE}}
+}
+
+void mixedSignedness12(int a) {
+ int min = 0;
+ clang_analyzer_eval(a <= min); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval((a + 2) <= min); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval((a + 2U) <= min); // expected-warning{{UNKNOWN}}
+}
+
+void mixedSignedness13(int a) {
+ unsigned max = INT_MAX;
+ clang_analyzer_eval(a < max); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval((a + 2) < max); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval((a + 2U) < max); // expected-warning{{UNKNOWN}}
+}
+
+void mixedSignedness14(int a) {
+ unsigned max = INT_MAX;
+ clang_analyzer_eval(a <= max); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval((a + 2) <= max); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval((a + 2U) <= max); // expected-warning{{UNKNOWN}}
+}
+
+void mixedSignedness15(int a) {
+ unsigned min = INT_MIN;
+ clang_analyzer_eval(a < min); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval((a + 2) < min); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval((a + 2U) < min); // expected-warning{{UNKNOWN}}
+}
+
+void mixedSignedness16(int a) {
+ unsigned min = INT_MIN;
+ clang_analyzer_eval(a <= min); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval((a + 2) <= min); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval((a + 2U) <= min); // expected-warning{{UNKNOWN}}
+}
+
+void mixedSignedness17(int a) {
+ unsigned max = INT_MAX;
+ if (a < max)
+ return;
+
+ clang_analyzer_eval(a < 0); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(a == 0); // expected-warning{{FALSE}}
+ clang_analyzer_eval(a == INT_MAX); // expected-warning{{UNKNOWN}}
+}
+
+void mixedSignedness18(int a) {
+ if (a >= 0)
+ return;
+
+ clang_analyzer_eval(a < 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(a == (unsigned)INT_MIN); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(a == UINT_MAX); // expected-warning{{UNKNOWN}}
+}
diff --git a/test/Analysis/additive-folding.cpp b/test/Analysis/additive-folding.cpp
index 4d58f1c..c2e5026 100644
--- a/test/Analysis/additive-folding.cpp
+++ b/test/Analysis/additive-folding.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -analyzer-constraints=range -Wno-tautological-compare -Wtautological-constant-out-of-range-compare %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -analyzer-constraints=range -Wno-tautological-compare %s
void clang_analyzer_eval(bool);
@@ -128,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{{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{{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 != -1); // expected-warning{{TRUE}}
clang_analyzer_eval(a > -1); // expected-warning{{TRUE}}
@@ -184,6 +184,18 @@ void mixedSignedness(int a, unsigned b) {
clang_analyzer_eval(b == uMin && b != sMin); // expected-warning{{FALSE}}
}
+void mixedSignedness2(int a) {
+ if (a != -1)
+ return;
+ clang_analyzer_eval(a == UINT_MAX); // expected-warning{{TRUE}}
+}
+
+void mixedSignedness3(unsigned a) {
+ if (a != UINT_MAX)
+ return;
+ clang_analyzer_eval(a == -1); // expected-warning{{TRUE}}
+}
+
void multiplicativeSanityTest(int x) {
// At one point we were ignoring the *4 completely -- the constraint manager
diff --git a/test/Analysis/alloc-match-dealloc.mm b/test/Analysis/alloc-match-dealloc.mm
new file mode 100644
index 0000000..56d46d9
--- /dev/null
+++ b/test/Analysis/alloc-match-dealloc.mm
@@ -0,0 +1,221 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.MismatchedDeallocator -fblocks -verify %s
+
+#include "Inputs/system-header-simulator-objc.h"
+#include "Inputs/system-header-simulator-cxx.h"
+
+typedef __typeof__(sizeof(int)) size_t;
+void *malloc(size_t);
+void *realloc(void *ptr, size_t size);
+void *calloc(size_t nmemb, size_t size);
+char *strdup(const char *s);
+void __attribute((ownership_returns(malloc))) *my_malloc(size_t);
+
+void free(void *);
+void __attribute((ownership_takes(malloc, 1))) my_free(void *);
+
+//---------------------------------------------------------------
+// Test if an allocation function matches deallocation function
+//---------------------------------------------------------------
+
+//--------------- test malloc family
+void testMalloc1() {
+ int *p = (int *)malloc(sizeof(int));
+ delete p; // expected-warning{{Memory allocated by malloc() should be deallocated by free(), not 'delete'}}
+}
+
+void testMalloc2() {
+ int *p = (int *)malloc(8);
+ int *q = (int *)realloc(p, 16);
+ delete q; // expected-warning{{Memory allocated by realloc() should be deallocated by free(), not 'delete'}}
+}
+
+void testMalloc3() {
+ int *p = (int *)calloc(1, sizeof(int));
+ delete p; // expected-warning{{Memory allocated by calloc() should be deallocated by free(), not 'delete'}}
+}
+
+void testMalloc4(const char *s) {
+ char *p = strdup(s);
+ delete p; // expected-warning{{Memory allocated by strdup() should be deallocated by free(), not 'delete'}}
+}
+
+void testMalloc5() {
+ int *p = (int *)my_malloc(sizeof(int));
+ delete p; // expected-warning{{Memory allocated by my_malloc() should be deallocated by free(), not 'delete'}}
+}
+
+void testMalloc6() {
+ int *p = (int *)malloc(sizeof(int));
+ operator delete(p); // expected-warning{{Memory allocated by malloc() should be deallocated by free(), not operator delete}}
+}
+
+void testMalloc7() {
+ int *p = (int *)malloc(sizeof(int));
+ delete[] p; // expected-warning{{Memory allocated by malloc() should be deallocated by free(), not 'delete[]'}}
+}
+
+void testMalloc8() {
+ int *p = (int *)malloc(sizeof(int));
+ operator delete[](p); // expected-warning{{Memory allocated by malloc() should be deallocated by free(), not operator delete[]}}
+}
+
+//--------------- test new family
+void testNew1() {
+ int *p = new int;
+ free(p); // expected-warning{{Memory allocated by 'new' should be deallocated by 'delete', not free()}}
+}
+
+void testNew2() {
+ int *p = (int *)operator new(0);
+ free(p); // expected-warning{{Memory allocated by operator new should be deallocated by 'delete', not free()}}
+}
+
+void testNew3() {
+ int *p = new int[1];
+ free(p); // expected-warning{{Memory allocated by 'new[]' should be deallocated by 'delete[]', not free()}}
+}
+
+void testNew4() {
+ int *p = new int;
+ realloc(p, sizeof(long)); // expected-warning{{Memory allocated by 'new' should be deallocated by 'delete', not realloc()}}
+}
+
+void testNew5() {
+ int *p = (int *)operator new(0);
+ realloc(p, sizeof(long)); // expected-warning{{Memory allocated by operator new should be deallocated by 'delete', not realloc()}}
+}
+
+void testNew6() {
+ int *p = new int[1];
+ realloc(p, sizeof(long)); // expected-warning{{Memory allocated by 'new[]' should be deallocated by 'delete[]', not realloc()}}
+}
+
+void testNew7() {
+ int *p = new int;
+ delete[] p; // expected-warning{{Memory allocated by 'new' should be deallocated by 'delete', not 'delete[]'}}
+}
+
+void testNew8() {
+ int *p = (int *)operator new(0);
+ delete[] p; // expected-warning{{Memory allocated by operator new should be deallocated by 'delete', not 'delete[]'}}
+}
+
+void testNew9() {
+ int *p = new int[1];
+ delete p; // expected-warning{{Memory allocated by 'new[]' should be deallocated by 'delete[]', not 'delete'}}
+}
+
+void testNew10() {
+ int *p = (int *)operator new[](0);
+ delete p; // expected-warning{{Memory allocated by operator new[] should be deallocated by 'delete[]', not 'delete'}}
+}
+
+void testNew11(NSUInteger dataLength) {
+ int *p = new int;
+ NSData *d = [NSData dataWithBytesNoCopy:p length:sizeof(int) freeWhenDone:1]; // expected-warning{{Memory allocated by 'new' should be deallocated by 'delete', not +dataWithBytesNoCopy:length:freeWhenDone:}}
+ // FIXME: should be "+dataWithBytesNoCopy:length:freeWhenDone: cannot take ownership of memory allocated by 'new'."
+}
+
+//-------------------------------------------------------
+// Check for intersection with unix.Malloc bounded with
+// unix.MismatchedDeallocator
+//-------------------------------------------------------
+
+// new/delete oparators are subjects of cplusplus.NewDelete.
+void testNewDeleteNoWarn() {
+ int i;
+ delete &i; // no-warning
+
+ int *p1 = new int;
+ delete ++p1; // no-warning
+
+ int *p2 = new int;
+ delete p2;
+ delete p2; // no-warning
+
+ int *p3 = new int; // no-warning
+}
+
+void testDeleteOpAfterFree() {
+ int *p = (int *)malloc(sizeof(int));
+ free(p);
+ operator delete(p); // no-warning
+}
+
+void testDeleteAfterFree() {
+ int *p = (int *)malloc(sizeof(int));
+ free(p);
+ delete p; // no-warning
+}
+
+void testStandardPlacementNewAfterFree() {
+ int *p = (int *)malloc(sizeof(int));
+ free(p);
+ p = new(p) int; // no-warning
+}
+
+//---------------------------------------------------------------
+// Check for intersection with cplusplus.NewDelete bounded with
+// unix.MismatchedDeallocator
+//---------------------------------------------------------------
+
+// malloc()/free() are subjects of unix.Malloc and unix.MallocWithAnnotations
+void testMallocFreeNoWarn() {
+ int i;
+ free(&i); // no-warning
+
+ int *p1 = (int *)malloc(sizeof(int));
+ free(++p1); // no-warning
+
+ int *p2 = (int *)malloc(sizeof(int));
+ free(p2);
+ free(p2); // no-warning
+
+ int *p3 = (int *)malloc(sizeof(int)); // no-warning
+}
+
+void testFreeAfterDelete() {
+ int *p = new int;
+ delete p;
+ free(p); // no-warning
+}
+
+void testStandardPlacementNewAfterDelete() {
+ int *p = new int;
+ delete p;
+ p = new(p) int; // no-warning
+}
+
+
+// Smart pointer example
+template <typename T>
+struct SimpleSmartPointer {
+ T *ptr;
+
+ explicit SimpleSmartPointer(T *p = 0) : ptr(p) {}
+ ~SimpleSmartPointer() {
+ delete ptr;
+ // expected-warning@-1 {{Memory allocated by 'new[]' should be deallocated by 'delete[]', not 'delete'}}
+ // expected-warning@-2 {{Memory allocated by malloc() should be deallocated by free(), not 'delete'}}
+ }
+};
+
+void testSimpleSmartPointerArrayNew() {
+ {
+ SimpleSmartPointer<int> a(new int);
+ } // no-warning
+
+ {
+ SimpleSmartPointer<int> a(new int[4]);
+ }
+}
+
+void testSimpleSmartPointerMalloc() {
+ {
+ SimpleSmartPointer<int> a(new int);
+ } // no-warning
+
+ {
+ SimpleSmartPointer<int> a((int *)malloc(4));
+ }
+}
diff --git a/test/Analysis/analyzer-config.c b/test/Analysis/analyzer-config.c
index 990f578..96b9483 100644
--- a/test/Analysis/analyzer-config.c
+++ b/test/Analysis/analyzer-config.c
@@ -5,9 +5,16 @@ void bar() {}
void foo() { bar(); }
// CHECK: [config]
+// CHECK-NEXT: cfg-conditional-static-initializers = true
// CHECK-NEXT: cfg-temporary-dtors = false
// CHECK-NEXT: faux-bodies = true
// CHECK-NEXT: graph-trim-interval = 1000
+// CHECK-NEXT: ipa = dynamic-bifurcate
// CHECK-NEXT: ipa-always-inline-size = 3
+// CHECK-NEXT: max-inlinable-size = 50
+// CHECK-NEXT: max-nodes = 150000
+// CHECK-NEXT: max-times-inline-large = 32
+// CHECK-NEXT: mode = deep
// CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 4
+// CHECK-NEXT: num-entries = 10
+
diff --git a/test/Analysis/analyzer-config.cpp b/test/Analysis/analyzer-config.cpp
index fb14266..1224204 100644
--- a/test/Analysis/analyzer-config.cpp
+++ b/test/Analysis/analyzer-config.cpp
@@ -11,12 +11,19 @@ public:
};
// CHECK: [config]
-// CHECK-NEXT: c++-inlining = methods
+// CHECK-NEXT: c++-container-inlining = false
+// CHECK-NEXT: c++-inlining = destructors
// CHECK-NEXT: c++-stdlib-inlining = true
// CHECK-NEXT: c++-template-inlining = true
+// CHECK-NEXT: cfg-conditional-static-initializers = true
// CHECK-NEXT: cfg-temporary-dtors = false
// CHECK-NEXT: faux-bodies = true
// CHECK-NEXT: graph-trim-interval = 1000
+// CHECK-NEXT: ipa = dynamic-bifurcate
// CHECK-NEXT: ipa-always-inline-size = 3
+// CHECK-NEXT: max-inlinable-size = 50
+// CHECK-NEXT: max-nodes = 150000
+// CHECK-NEXT: max-times-inline-large = 32
+// CHECK-NEXT: mode = deep
// CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 7
+// CHECK-NEXT: num-entries = 14
diff --git a/test/Analysis/analyzer-stats.c b/test/Analysis/analyzer-stats.c
index 9eeaade..63073b7 100644
--- a/test/Analysis/analyzer-stats.c
+++ b/test/Analysis/analyzer-stats.c
@@ -2,7 +2,7 @@
int foo();
-int test() { // expected-warning{{Total CFGBlocks}}
+int test() { // expected-warning-re{{test -> Total CFGBlocks: [0-9]+ \| Unreachable CFGBlocks: 0 \| Exhausted Block: no \| Empty WorkList: yes}}
int a = 1;
a = 34 / 12;
diff --git a/test/Analysis/array-struct-region.c b/test/Analysis/array-struct-region.c
index d628c47..6817124 100644
--- a/test/Analysis/array-struct-region.c
+++ b/test/Analysis/array-struct-region.c
@@ -253,6 +253,70 @@ int testStructFieldChainsNested(int index, int anotherIndex) {
return 0;
}
+typedef struct {
+ int zoomLevel;
+ struct point center;
+} Outer;
+
+extern int test13116945(struct point x);
+static void radar13116945(struct point centerCoordinate) {
+ Outer zoomRegion;
+ zoomRegion.zoomLevel = 0;
+ zoomRegion.center = centerCoordinate;
+ Outer r = zoomRegion;
+ test13116945(r.center); // no-warning
+}
+
+
+typedef struct {
+ char data[4];
+} ShortString;
+
+typedef struct {
+ ShortString str;
+ int length;
+} ShortStringWrapper;
+
+void testArrayStructCopy() {
+ ShortString s = { "abc" };
+ ShortString s2 = s;
+ ShortString s3 = s2;
+
+ clang_analyzer_eval(s3.data[0] == 'a'); // expected-warning{{TRUE}}
+ clang_analyzer_eval(s3.data[1] == 'b'); // expected-warning{{TRUE}}
+ clang_analyzer_eval(s3.data[2] == 'c'); // expected-warning{{TRUE}}
+
+ s3.data[0] = 'z';
+ ShortString s4 = s3;
+
+ clang_analyzer_eval(s4.data[0] == 'z'); // expected-warning{{TRUE}}
+ clang_analyzer_eval(s4.data[1] == 'b'); // expected-warning{{TRUE}}
+ clang_analyzer_eval(s4.data[2] == 'c'); // expected-warning{{TRUE}}
+}
+
+void testArrayStructCopyNested() {
+ ShortString s = { "abc" };
+ ShortString s2 = s;
+
+ ShortStringWrapper w = { s2, 0 };
+
+ clang_analyzer_eval(w.str.data[0] == 'a'); // expected-warning{{TRUE}}
+ clang_analyzer_eval(w.str.data[1] == 'b'); // expected-warning{{TRUE}}
+ clang_analyzer_eval(w.str.data[2] == 'c'); // expected-warning{{TRUE}}
+ clang_analyzer_eval(w.length == 0); // expected-warning{{TRUE}}
+
+ ShortStringWrapper w2 = w;
+ clang_analyzer_eval(w2.str.data[0] == 'a'); // expected-warning{{TRUE}}
+ clang_analyzer_eval(w2.str.data[1] == 'b'); // expected-warning{{TRUE}}
+ clang_analyzer_eval(w2.str.data[2] == 'c'); // expected-warning{{TRUE}}
+ clang_analyzer_eval(w2.length == 0); // expected-warning{{TRUE}}
+
+ ShortStringWrapper w3 = w2;
+ clang_analyzer_eval(w3.str.data[0] == 'a'); // expected-warning{{TRUE}}
+ clang_analyzer_eval(w3.str.data[1] == 'b'); // expected-warning{{TRUE}}
+ clang_analyzer_eval(w3.str.data[2] == 'c'); // expected-warning{{TRUE}}
+ clang_analyzer_eval(w3.length == 0); // expected-warning{{TRUE}}
+}
// --------------------
// False positives
@@ -289,4 +353,3 @@ void testFieldChainIsNotEnough(int index) {
// FIXME: Should be TRUE.
clang_analyzer_eval(vals[index].a[0].x == 42); // expected-warning{{UNKNOWN}}
}
-
diff --git a/test/Analysis/auto-obj-dtors-cfg-output.cpp b/test/Analysis/auto-obj-dtors-cfg-output.cpp
index e4b49dc..0fc6517 100644
--- a/test/Analysis/auto-obj-dtors-cfg-output.cpp
+++ b/test/Analysis/auto-obj-dtors-cfg-output.cpp
@@ -1,6 +1,5 @@
// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-checker=debug.DumpCFG %s > %t 2>&1
// RUN: FileCheck --input-file=%t %s
-// XPASS: *
class A {
public:
diff --git a/test/Analysis/base-init.cpp b/test/Analysis/base-init.cpp
index 34e01aa..3c870e1 100644
--- a/test/Analysis/base-init.cpp
+++ b/test/Analysis/base-init.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=inlining -analyzer-config c++-inlining=constructors -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config c++-inlining=constructors -verify %s
void clang_analyzer_eval(bool);
diff --git a/test/Analysis/blocks-no-inline.c b/test/Analysis/blocks-no-inline.c
index 1ec14e8..de6f959 100644
--- a/test/Analysis/blocks-no-inline.c
+++ b/test/Analysis/blocks-no-inline.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=none -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=none -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=none -fblocks -verify -x c++ %s
void clang_analyzer_eval(int);
@@ -11,3 +12,29 @@ void testInvalidation() {
// Under inlining, we will know that i == 1.
clang_analyzer_eval(i == 0); // expected-warning{{UNKNOWN}}
}
+
+
+const int globalConstant = 1;
+void testCapturedConstants() {
+ const int localConstant = 2;
+ static const int staticConstant = 3;
+
+ ^{
+ clang_analyzer_eval(globalConstant == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(localConstant == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(staticConstant == 3); // expected-warning{{TRUE}}
+ }();
+}
+
+typedef const int constInt;
+constInt anotherGlobalConstant = 1;
+void testCapturedConstantsTypedef() {
+ constInt localConstant = 2;
+ static constInt staticConstant = 3;
+
+ ^{
+ clang_analyzer_eval(anotherGlobalConstant == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(localConstant == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(staticConstant == 3); // expected-warning{{TRUE}}
+ }();
+}
diff --git a/test/Analysis/blocks.m b/test/Analysis/blocks.m
index 54ff58c..2fa5a8e 100644
--- a/test/Analysis/blocks.m
+++ b/test/Analysis/blocks.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core -analyzer-store=region -fblocks -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core -analyzer-store=region -fblocks -analyzer-opt-analyze-nested-blocks -verify %s
//===----------------------------------------------------------------------===//
// The following code is reduced using delta-debugging from Mac OS X headers:
@@ -26,6 +26,7 @@ typedef struct _NSZone NSZone;
@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end
@interface NSObject <NSObject> {}
+ (id)alloc;
+- (id)init;
- (id)copy;
@end
extern id NSAllocateObject(Class aClass, NSUInteger extraBytes, NSZone *zone);
@@ -94,3 +95,31 @@ void testMessaging() {
// <rdar://problem/12119814>
[[^(){} copy] release];
}
+
+
+@interface rdar12415065 : NSObject
+@end
+
+@implementation rdar12415065
+- (void)test {
+ // At one point this crashed because we created a path note at a
+ // PreStmtPurgeDeadSymbols point but only knew how to deal with PostStmt
+ // points. <rdar://problem/12687586>
+
+ extern dispatch_queue_t queue;
+
+ if (!queue)
+ return;
+
+ // This previously was a false positive with 'x' being flagged as being
+ // uninitialized when captured by the exterior block (when it is only
+ // captured by the interior block).
+ dispatch_async(queue, ^{
+ double x = 0.0;
+ if (24.0f < x) {
+ dispatch_async(queue, ^{ (void)x; });
+ [self test];
+ }
+ });
+}
+@end
diff --git a/test/Analysis/call-invalidation.cpp b/test/Analysis/call-invalidation.cpp
new file mode 100644
index 0000000..54281cc
--- /dev/null
+++ b/test/Analysis/call-invalidation.cpp
@@ -0,0 +1,91 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
+
+void clang_analyzer_eval(bool);
+
+void usePointer(int * const *);
+void useReference(int * const &);
+
+void testPointer() {
+ int x;
+ int *p;
+
+ p = &x;
+ x = 42;
+ clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
+ usePointer(&p);
+ clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}}
+
+ p = &x;
+ x = 42;
+ clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
+ useReference(p);
+ clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}}
+
+ int * const cp1 = &x;
+ x = 42;
+ clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
+ usePointer(&cp1);
+ clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}}
+
+ int * const cp2 = &x;
+ x = 42;
+ clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
+ useReference(cp2);
+ clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}}
+}
+
+
+struct Wrapper {
+ int *ptr;
+};
+
+void useStruct(Wrapper &w);
+void useConstStruct(const Wrapper &w);
+
+void testPointerStruct() {
+ int x;
+ Wrapper w;
+
+ w.ptr = &x;
+ x = 42;
+ clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
+ useStruct(w);
+ clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}}
+
+ w.ptr = &x;
+ x = 42;
+ clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
+ useConstStruct(w);
+ clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}}
+}
+
+
+struct RefWrapper {
+ int &ref;
+};
+
+void useStruct(RefWrapper &w);
+void useConstStruct(const RefWrapper &w);
+
+void testReferenceStruct() {
+ int x;
+ RefWrapper w = { x };
+
+ x = 42;
+ clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
+ useStruct(w);
+ clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}}
+}
+
+// FIXME: This test is split into two functions because region invalidation
+// does not preserve reference bindings. <rdar://problem/13320347>
+void testConstReferenceStruct() {
+ int x;
+ RefWrapper w = { x };
+
+ x = 42;
+ clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
+ useConstStruct(w);
+ clang_analyzer_eval(x == 42); // expected-warning{{UNKNOWN}}
+}
+
diff --git a/test/Analysis/casts.c b/test/Analysis/casts.c
index 1c0f357..087bd97 100644
--- a/test/Analysis/casts.c
+++ b/test/Analysis/casts.c
@@ -74,3 +74,14 @@ char ttt(int intSeconds) {
return 0;
return 0;
}
+
+int foo (int* p) {
+ int y = 0;
+ if (p == 0) {
+ if ((*((void**)&p)) == (void*)0) // Test that the cast to void preserves the symbolic region.
+ return 0;
+ else
+ return 5/y; // This code should be unreachable: no-warning.
+ }
+ return 0;
+}
diff --git a/test/Analysis/cfg.cpp b/test/Analysis/cfg.cpp
new file mode 100644
index 0000000..8c1c765
--- /dev/null
+++ b/test/Analysis/cfg.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -fsyntax-only -analyze -analyzer-checker=debug.DumpCFG %s 2>&1 | FileCheck %s
+// Check the wrapping behavior when dumping the CFG.
+
+// CHECK: ENTRY
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B1]
+// CHECK: Succs (21): B2 B3 B4 B5 B6 B7 B8 B9
+// CHECK: B10 B11 B12 B13 B14 B15 B16 B17 B18 B19
+// CHECK: B20 B21 B0
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (21): B2 B3 B4 B5 B6 B7 B8 B9
+// CHECK-NEXT: B10 B11 B12 B13 B14 B15 B16 B17 B18 B19
+// CHECK-NEXT: B20 B21 B1
+void test(int i) {
+ switch(i) {
+ case 0: break;
+ case 1: break;
+ case 2: break;
+ case 3: break;
+ case 4: break;
+ case 5: break;
+ case 6: break;
+ case 7: break;
+ case 8: break;
+ case 9: break;
+ case 10: break;
+ case 11: break;
+ case 12: break;
+ case 13: break;
+ case 14: break;
+ case 15: break;
+ case 16: break;
+ case 17: break;
+ case 18: break;
+ case 19: break;
+ }
+}
diff --git a/test/Analysis/conditional-operator-path-notes.c b/test/Analysis/conditional-operator-path-notes.c
index de313a7..c781ddf 100644
--- a/test/Analysis/conditional-operator-path-notes.c
+++ b/test/Analysis/conditional-operator-path-notes.c
@@ -6,7 +6,7 @@ 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}}
+ // expected-note@-3 {{'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')}}
}
@@ -40,7 +40,7 @@ void testRHSProblem(int *p) {
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}}
+ // expected-note@-2 {{'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')}}
}
@@ -216,9 +216,9 @@ void testBinaryLHSProblem(int *p) {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;x&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;x&apos; initialized to a null pointer value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;x&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;x&apos; initialized to a null pointer value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -289,7 +289,7 @@ void testBinaryLHSProblem(int *p) {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testCondOp</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>10</integer>
@@ -432,7 +432,7 @@ void testBinaryLHSProblem(int *p) {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testCondProblem</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>19</integer>
@@ -575,7 +575,7 @@ void testBinaryLHSProblem(int *p) {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testLHSProblem</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>25</integer>
@@ -718,7 +718,7 @@ void testBinaryLHSProblem(int *p) {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testRHSProblem</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>33</integer>
@@ -856,9 +856,9 @@ void testBinaryLHSProblem(int *p) {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;x&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;x&apos; initialized to a null pointer value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;x&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;x&apos; initialized to a null pointer value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -929,7 +929,7 @@ void testBinaryLHSProblem(int *p) {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testBinaryCondOp</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>44</integer>
@@ -1072,7 +1072,7 @@ void testBinaryLHSProblem(int *p) {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testBinaryLHSProblem</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>53</integer>
diff --git a/test/Analysis/coverage.c b/test/Analysis/coverage.c
index 66f0a5e..38e84e1 100644
--- a/test/Analysis/coverage.c
+++ b/test/Analysis/coverage.c
@@ -32,27 +32,27 @@ static void function_which_doesnt_give_up_nested(int *x, int *y) {
void coverage1(int *x) {
function_which_gives_up(x);
- char *m = (char*)malloc(12); // expected-warning {{potential leak}}
-}
+ char *m = (char*)malloc(12);
+} // expected-warning {{potential leak}}
void coverage2(int *x) {
if (x) {
function_which_gives_up(x);
- char *m = (char*)malloc(12);// expected-warning {{potential leak}}
+ char *m = (char*)malloc(12);
}
-}
+} // expected-warning {{potential leak}}
void coverage3(int *x) {
x++;
function_which_gives_up(x);
- char *m = (char*)malloc(12);// expected-warning {{potential leak}}
-}
+ char *m = (char*)malloc(12);
+} // expected-warning {{potential leak}}
void coverage4(int *x) {
*x += another_function(x);
function_which_gives_up(x);
- char *m = (char*)malloc(12);// expected-warning {{potential leak}}
-}
+ char *m = (char*)malloc(12);
+} // expected-warning {{potential leak}}
void coverage5(int *x) {
for (int i = 0; i<7; ++i)
@@ -65,8 +65,8 @@ void coverage6(int *x) {
for (int i = 0; i<3; ++i) {
function_which_gives_up(x);
}
- char *m = (char*)malloc(12); // expected-warning {{potential leak}}
-}
+ char *m = (char*)malloc(12);
+} // expected-warning {{potential leak}}
int coverage7_inline(int *i) {
function_which_doesnt_give_up(&i);
@@ -77,8 +77,8 @@ void coverage8(int *x) {
int y;
function_which_doesnt_give_up_nested(x, &y);
y = (*x)/y; // expected-warning {{Division by zero}}
- char *m = (char*)malloc(12); // expected-warning {{potential leak}}
-}
+ char *m = (char*)malloc(12);
+} // expected-warning {{potential leak}}
void function_which_gives_up_settonull(int **x) {
*x = 0;
diff --git a/test/Analysis/ctor-inlining.mm b/test/Analysis/ctor-inlining.mm
index ac963e5..8cdb005 100644
--- a/test/Analysis/ctor-inlining.mm
+++ b/test/Analysis/ctor-inlining.mm
@@ -1,8 +1,15 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-ipa=inlining -analyzer-config c++-inlining=constructors -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-config c++-inlining=constructors -Wno-null-dereference -std=c++11 -verify %s
void clang_analyzer_eval(bool);
void clang_analyzer_checkInlined(bool);
+// A simplified version of std::move.
+template <typename T>
+T &&move(T &obj) {
+ return static_cast<T &&>(obj);
+}
+
+
struct Wrapper {
__strong id obj;
};
@@ -117,3 +124,379 @@ namespace ConstructorUsedAsRValue {
clang_analyzer_eval(result); // expected-warning{{TRUE}}
}
}
+
+namespace PODUninitialized {
+ class POD {
+ public:
+ int x, y;
+ };
+
+ class PODWrapper {
+ public:
+ POD p;
+ };
+
+ class NonPOD {
+ public:
+ int x, y;
+
+ NonPOD() {}
+ NonPOD(const NonPOD &Other)
+ : x(Other.x), y(Other.y) // expected-warning {{undefined}}
+ {
+ }
+ NonPOD(NonPOD &&Other)
+ : x(Other.x), y(Other.y) // expected-warning {{undefined}}
+ {
+ }
+
+ NonPOD &operator=(const NonPOD &Other)
+ {
+ x = Other.x;
+ y = Other.y; // expected-warning {{undefined}}
+ return *this;
+ }
+ NonPOD &operator=(NonPOD &&Other)
+ {
+ x = Other.x;
+ y = Other.y; // expected-warning {{undefined}}
+ return *this;
+ }
+ };
+
+ class NonPODWrapper {
+ public:
+ class Inner {
+ public:
+ int x, y;
+
+ Inner() {}
+ Inner(const Inner &Other)
+ : x(Other.x), y(Other.y) // expected-warning {{undefined}}
+ {
+ }
+ Inner(Inner &&Other)
+ : x(Other.x), y(Other.y) // expected-warning {{undefined}}
+ {
+ }
+
+ Inner &operator=(const Inner &Other)
+ {
+ x = Other.x; // expected-warning {{undefined}}
+ y = Other.y;
+ return *this;
+ }
+ Inner &operator=(Inner &&Other)
+ {
+ x = Other.x; // expected-warning {{undefined}}
+ y = Other.y;
+ return *this;
+ }
+ };
+
+ Inner p;
+ };
+
+ void testPOD() {
+ POD p;
+ p.x = 1;
+ POD p2 = p; // no-warning
+ clang_analyzer_eval(p2.x == 1); // expected-warning{{TRUE}}
+ POD p3 = move(p); // no-warning
+ clang_analyzer_eval(p3.x == 1); // expected-warning{{TRUE}}
+
+ // Use rvalues as well.
+ clang_analyzer_eval(POD(p3).x == 1); // expected-warning{{TRUE}}
+
+ PODWrapper w;
+ w.p.y = 1;
+ PODWrapper w2 = w; // no-warning
+ clang_analyzer_eval(w2.p.y == 1); // expected-warning{{TRUE}}
+ PODWrapper w3 = move(w); // no-warning
+ clang_analyzer_eval(w3.p.y == 1); // expected-warning{{TRUE}}
+
+ // Use rvalues as well.
+ clang_analyzer_eval(PODWrapper(w3).p.y == 1); // expected-warning{{TRUE}}
+ }
+
+ void testNonPOD() {
+ NonPOD p;
+ p.x = 1;
+ NonPOD p2 = p;
+ }
+
+ void testNonPODMove() {
+ NonPOD p;
+ p.x = 1;
+ NonPOD p2 = move(p);
+ }
+
+ void testNonPODWrapper() {
+ NonPODWrapper w;
+ w.p.y = 1;
+ NonPODWrapper w2 = w;
+ }
+
+ void testNonPODWrapperMove() {
+ NonPODWrapper w;
+ w.p.y = 1;
+ NonPODWrapper w2 = move(w);
+ }
+
+ // Not strictly about constructors, but trivial assignment operators should
+ // essentially work the same way.
+ namespace AssignmentOperator {
+ void testPOD() {
+ POD p;
+ p.x = 1;
+ POD p2;
+ p2 = p; // no-warning
+ clang_analyzer_eval(p2.x == 1); // expected-warning{{TRUE}}
+ POD p3;
+ p3 = move(p); // no-warning
+ clang_analyzer_eval(p3.x == 1); // expected-warning{{TRUE}}
+
+ PODWrapper w;
+ w.p.y = 1;
+ PODWrapper w2;
+ w2 = w; // no-warning
+ clang_analyzer_eval(w2.p.y == 1); // expected-warning{{TRUE}}
+ PODWrapper w3;
+ w3 = move(w); // no-warning
+ clang_analyzer_eval(w3.p.y == 1); // expected-warning{{TRUE}}
+ }
+
+ void testReturnValue() {
+ POD p;
+ p.x = 1;
+ POD p2;
+ clang_analyzer_eval(&(p2 = p) == &p2); // expected-warning{{TRUE}}
+
+ PODWrapper w;
+ w.p.y = 1;
+ PODWrapper w2;
+ clang_analyzer_eval(&(w2 = w) == &w2); // expected-warning{{TRUE}}
+ }
+
+ void testNonPOD() {
+ NonPOD p;
+ p.x = 1;
+ NonPOD p2;
+ p2 = p;
+ }
+
+ void testNonPODMove() {
+ NonPOD p;
+ p.x = 1;
+ NonPOD p2;
+ p2 = move(p);
+ }
+
+ void testNonPODWrapper() {
+ NonPODWrapper w;
+ w.p.y = 1;
+ NonPODWrapper w2;
+ w2 = w;
+ }
+
+ void testNonPODWrapperMove() {
+ NonPODWrapper w;
+ w.p.y = 1;
+ NonPODWrapper w2;
+ w2 = move(w);
+ }
+ }
+}
+
+namespace ArrayMembers {
+ struct Primitive {
+ int values[3];
+ };
+
+ void testPrimitive() {
+ Primitive a = { { 1, 2, 3 } };
+
+ clang_analyzer_eval(a.values[0] == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(a.values[1] == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(a.values[2] == 3); // expected-warning{{TRUE}}
+
+ Primitive b = a;
+
+ clang_analyzer_eval(b.values[0] == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(b.values[1] == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(b.values[2] == 3); // expected-warning{{TRUE}}
+
+ Primitive c;
+ c = b;
+
+ clang_analyzer_eval(c.values[0] == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(c.values[1] == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(c.values[2] == 3); // expected-warning{{TRUE}}
+ }
+
+ struct NestedPrimitive {
+ int values[2][3];
+ };
+
+ void testNestedPrimitive() {
+ NestedPrimitive a = { { { 0, 0, 0 }, { 1, 2, 3 } } };
+
+ clang_analyzer_eval(a.values[1][0] == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(a.values[1][1] == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(a.values[1][2] == 3); // expected-warning{{TRUE}}
+
+ NestedPrimitive b = a;
+
+ clang_analyzer_eval(b.values[1][0] == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(b.values[1][1] == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(b.values[1][2] == 3); // expected-warning{{TRUE}}
+
+ NestedPrimitive c;
+ c = b;
+
+ clang_analyzer_eval(c.values[1][0] == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(c.values[1][1] == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(c.values[1][2] == 3); // expected-warning{{TRUE}}
+ }
+
+ struct POD {
+ IntWrapper values[3];
+ };
+
+ void testPOD() {
+ POD a = { { { 1 }, { 2 }, { 3 } } };
+
+ clang_analyzer_eval(a.values[0].x == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(a.values[1].x == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(a.values[2].x == 3); // expected-warning{{TRUE}}
+
+ POD b = a;
+
+ clang_analyzer_eval(b.values[0].x == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(b.values[1].x == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(b.values[2].x == 3); // expected-warning{{TRUE}}
+
+ POD c;
+ c = b;
+
+ clang_analyzer_eval(c.values[0].x == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(c.values[1].x == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(c.values[2].x == 3); // expected-warning{{TRUE}}
+ }
+
+ struct NestedPOD {
+ IntWrapper values[2][3];
+ };
+
+ void testNestedPOD() {
+ NestedPOD a = { { { { 0 }, { 0 }, { 0 } }, { { 1 }, { 2 }, { 3 } } } };
+
+ clang_analyzer_eval(a.values[1][0].x == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(a.values[1][1].x == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(a.values[1][2].x == 3); // expected-warning{{TRUE}}
+
+ NestedPOD b = a;
+
+ clang_analyzer_eval(b.values[1][0].x == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(b.values[1][1].x == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(b.values[1][2].x == 3); // expected-warning{{TRUE}}
+
+ NestedPOD c;
+ c = b;
+
+ clang_analyzer_eval(c.values[1][0].x == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(c.values[1][1].x == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(c.values[1][2].x == 3); // expected-warning{{TRUE}}
+ }
+
+ struct NonPOD {
+ NonPODIntWrapper values[3];
+ };
+
+ void testNonPOD() {
+ NonPOD a;
+ a.values[0].x = 1;
+ a.values[1].x = 2;
+ a.values[2].x = 3;
+
+ clang_analyzer_eval(a.values[0].x == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(a.values[1].x == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(a.values[2].x == 3); // expected-warning{{TRUE}}
+
+ NonPOD b = a;
+
+ clang_analyzer_eval(b.values[0].x == 1); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(b.values[1].x == 2); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(b.values[2].x == 3); // expected-warning{{UNKNOWN}}
+
+ NonPOD c;
+ c = b;
+
+ clang_analyzer_eval(c.values[0].x == 1); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(c.values[1].x == 2); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(c.values[2].x == 3); // expected-warning{{UNKNOWN}}
+ }
+
+ struct NestedNonPOD {
+ NonPODIntWrapper values[2][3];
+ };
+
+ void testNestedNonPOD() {
+ NestedNonPOD a;
+ a.values[0][0].x = 0;
+ a.values[0][1].x = 0;
+ a.values[0][2].x = 0;
+ a.values[1][0].x = 1;
+ a.values[1][1].x = 2;
+ a.values[1][2].x = 3;
+
+ clang_analyzer_eval(a.values[1][0].x == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(a.values[1][1].x == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(a.values[1][2].x == 3); // expected-warning{{TRUE}}
+
+ NestedNonPOD b = a;
+
+ clang_analyzer_eval(b.values[1][0].x == 1); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(b.values[1][1].x == 2); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(b.values[1][2].x == 3); // expected-warning{{UNKNOWN}}
+
+ NestedNonPOD c;
+ c = b;
+
+ clang_analyzer_eval(c.values[1][0].x == 1); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(c.values[1][1].x == 2); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(c.values[1][2].x == 3); // expected-warning{{UNKNOWN}}
+ }
+
+ struct NonPODDefaulted {
+ NonPODIntWrapper values[3];
+
+ NonPODDefaulted() = default;
+ NonPODDefaulted(const NonPODDefaulted &) = default;
+ NonPODDefaulted &operator=(const NonPODDefaulted &) = default;
+ };
+
+ void testNonPODDefaulted() {
+ NonPODDefaulted a;
+ a.values[0].x = 1;
+ a.values[1].x = 2;
+ a.values[2].x = 3;
+
+ clang_analyzer_eval(a.values[0].x == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(a.values[1].x == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(a.values[2].x == 3); // expected-warning{{TRUE}}
+
+ NonPODDefaulted b = a;
+
+ clang_analyzer_eval(b.values[0].x == 1); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(b.values[1].x == 2); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(b.values[2].x == 3); // expected-warning{{UNKNOWN}}
+
+ NonPODDefaulted c;
+ c = b;
+
+ clang_analyzer_eval(c.values[0].x == 1); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(c.values[1].x == 2); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(c.values[2].x == 3); // expected-warning{{UNKNOWN}}
+ }
+};
diff --git a/test/Analysis/dead-stores.cpp b/test/Analysis/dead-stores.cpp
index 86d84f0..d442c62 100644
--- a/test/Analysis/dead-stores.cpp
+++ b/test/Analysis/dead-stores.cpp
@@ -1,5 +1,5 @@
-// 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=range -analyzer-checker=deadcode.DeadStores -verify -Wno-unreachable-code %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -std=c++11 -analyze -analyzer-checker=deadcode.DeadStores -verify -Wno-unreachable-code %s
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -std=c++11 -analyze -analyzer-store=region -analyzer-constraints=range -analyzer-checker=deadcode.DeadStores -verify -Wno-unreachable-code %s
//===----------------------------------------------------------------------===//
// Basic dead store checking (but in C++ mode).
@@ -149,3 +149,28 @@ void test_6b() {
}
catch (void *) {}
}
+
+
+void testCXX11Using() {
+ using Int = int;
+ Int value;
+ value = 1; // expected-warning {{never read}}
+}
+
+//===----------------------------------------------------------------------===//
+// Dead stores in template instantiations (do not warn).
+//===----------------------------------------------------------------------===//
+
+template <bool f> int radar13213575_testit(int i) {
+ int x = 5+i; // warning: Value stored to 'x' during its initialization is never read
+ int y = 7;
+ if (f)
+ return x;
+ else
+ return y;
+}
+
+int radar_13213575() {
+ return radar13213575_testit<true>(5) + radar13213575_testit<false>(3);
+}
+
diff --git a/test/Analysis/debug-CallGraph.c b/test/Analysis/debug-CallGraph.c
index b7c7c8a..4523c78 100644
--- a/test/Analysis/debug-CallGraph.c
+++ b/test/Analysis/debug-CallGraph.c
@@ -1,9 +1,9 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCallGraph %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCallGraph %s -fblocks 2>&1 | FileCheck %s
static void mmm(int y) {
if (y != 0)
y++;
- y = y/0;
+ y = y/y;
}
static int foo(int x, int y) {
@@ -17,5 +17,17 @@ void aaa() {
foo(1,2);
}
+void bbb(int y) {
+ int x = (y > 2);
+ ^ {
+ foo(x, y);
+ }();
+}
+
// CHECK:--- Call graph Dump ---
-// CHECK: Function: < root > calls: aaa
+// CHECK: Function: < root > calls: mmm foo aaa < > bbb
+// CHECK: Function: bbb calls: < >
+// CHECK: Function: < > calls: foo
+// CHECK: Function: aaa calls: foo
+// CHECK: Function: foo calls: mmm
+// CHECK: Function: mmm calls:
diff --git a/test/Analysis/default-diagnostic-visitors.c b/test/Analysis/default-diagnostic-visitors.c
index 9cb9ba8..0bc6a03 100644
--- a/test/Analysis/default-diagnostic-visitors.c
+++ b/test/Analysis/default-diagnostic-visitors.c
@@ -5,7 +5,7 @@
int getPasswordAndItem()
{
int err = 0;
- int *password; // expected-note {{Variable 'password' declared without an initial value}}
+ int *password; // expected-note {{'password' declared without an initial value}}
if (password == 0) { // expected-warning {{The left operand of '==' is a garbage value}} // expected-note {{The left operand of '==' is a garbage value}}
err = *password;
}
diff --git a/test/Analysis/derived-to-base.cpp b/test/Analysis/derived-to-base.cpp
index 30e7a31..b846d2c 100644
--- a/test/Analysis/derived-to-base.cpp
+++ b/test/Analysis/derived-to-base.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=inlining -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -DCONSTRUCTORS=1 -analyzer-config c++-inlining=constructors -verify %s
void clang_analyzer_eval(bool);
@@ -135,3 +136,230 @@ namespace DynamicMultipleInheritanceUpcast {
clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}}
}
}
+
+namespace LazyBindings {
+ struct Base {
+ int x;
+ };
+
+ struct Derived : public Base {
+ int y;
+ };
+
+ struct DoubleDerived : public Derived {
+ int z;
+ };
+
+ int getX(const Base &obj) {
+ return obj.x;
+ }
+
+ int getY(const Derived &obj) {
+ return obj.y;
+ }
+
+ void testDerived() {
+ Derived d;
+ d.x = 1;
+ d.y = 2;
+ clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
+
+ Base b(d);
+ clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
+
+ Derived d2(d);
+ clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
+ }
+
+ void testDoubleDerived() {
+ DoubleDerived d;
+ d.x = 1;
+ d.y = 2;
+ clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
+
+ Base b(d);
+ clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
+
+ Derived d2(d);
+ clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
+
+ DoubleDerived d3(d);
+ clang_analyzer_eval(getX(d3) == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(getY(d3) == 2); // expected-warning{{TRUE}}
+ }
+
+ namespace WithOffset {
+ struct Offset {
+ int padding;
+ };
+
+ struct OffsetDerived : private Offset, public Base {
+ int y;
+ };
+
+ struct DoubleOffsetDerived : public OffsetDerived {
+ int z;
+ };
+
+ int getY(const OffsetDerived &obj) {
+ return obj.y;
+ }
+
+ void testDerived() {
+ OffsetDerived d;
+ d.x = 1;
+ d.y = 2;
+ clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
+
+ Base b(d);
+ clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
+
+ OffsetDerived d2(d);
+ clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
+ }
+
+ void testDoubleDerived() {
+ DoubleOffsetDerived d;
+ d.x = 1;
+ d.y = 2;
+ clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
+
+ Base b(d);
+ clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
+
+ OffsetDerived d2(d);
+ clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
+
+ DoubleOffsetDerived d3(d);
+ clang_analyzer_eval(getX(d3) == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(getY(d3) == 2); // expected-warning{{TRUE}}
+ }
+ }
+
+ namespace WithVTable {
+ struct DerivedVTBL : public Base {
+ int y;
+ virtual void method();
+ };
+
+ struct DoubleDerivedVTBL : public DerivedVTBL {
+ int z;
+ };
+
+ int getY(const DerivedVTBL &obj) {
+ return obj.y;
+ }
+
+ int getZ(const DoubleDerivedVTBL &obj) {
+ return obj.z;
+ }
+
+ void testDerived() {
+ DerivedVTBL d;
+ d.x = 1;
+ d.y = 2;
+ clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
+
+ Base b(d);
+ clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
+
+#if CONSTRUCTORS
+ DerivedVTBL d2(d);
+ clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
+#endif
+ }
+
+#if CONSTRUCTORS
+ void testDoubleDerived() {
+ DoubleDerivedVTBL d;
+ d.x = 1;
+ d.y = 2;
+ d.z = 3;
+ clang_analyzer_eval(getX(d) == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(getY(d) == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(getZ(d) == 3); // expected-warning{{TRUE}}
+
+ Base b(d);
+ clang_analyzer_eval(getX(b) == 1); // expected-warning{{TRUE}}
+
+ DerivedVTBL d2(d);
+ clang_analyzer_eval(getX(d2) == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(getY(d2) == 2); // expected-warning{{TRUE}}
+
+ DoubleDerivedVTBL d3(d);
+ clang_analyzer_eval(getX(d3) == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(getY(d3) == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(getZ(d3) == 3); // expected-warning{{TRUE}}
+ }
+#endif
+ }
+
+#if CONSTRUCTORS
+ namespace Nested {
+ struct NonTrivialCopy {
+ int padding;
+ NonTrivialCopy() {}
+ NonTrivialCopy(const NonTrivialCopy &) {}
+ };
+
+ struct FullyDerived : private NonTrivialCopy, public Derived {
+ int z;
+ };
+
+ struct Wrapper {
+ FullyDerived d;
+ int zz;
+
+ Wrapper(const FullyDerived &d) : d(d), zz(0) {}
+ };
+
+ void test5() {
+ Wrapper w((FullyDerived()));
+ w.d.x = 1;
+
+ Wrapper w2(w);
+ clang_analyzer_eval(getX(w2.d) == 1); // expected-warning{{TRUE}}
+ }
+ }
+#endif
+}
+
+namespace Redeclaration {
+ class Base;
+
+ class Base {
+ public:
+ virtual int foo();
+ int get() { return value; }
+
+ int value;
+ };
+
+ class Derived : public Base {
+ public:
+ virtual int bar();
+ };
+
+ void test(Derived d) {
+ d.foo(); // don't crash
+ d.bar(); // sanity check
+
+ Base &b = d;
+ b.foo(); // don't crash
+
+ d.value = 42; // don't crash
+ clang_analyzer_eval(d.get() == 42); // expected-warning{{TRUE}}
+ clang_analyzer_eval(b.get() == 42); // expected-warning{{TRUE}}
+ }
+};
+
diff --git a/test/Analysis/diagnostics/Inputs/include/sys/queue.h b/test/Analysis/diagnostics/Inputs/include/sys/queue.h
new file mode 100644
index 0000000..e5698ed
--- /dev/null
+++ b/test/Analysis/diagnostics/Inputs/include/sys/queue.h
@@ -0,0 +1,5 @@
+#pragma clang system_header
+
+void free(void *);
+#define FREE_POINTER(x) free(x)
+
diff --git a/test/Analysis/diagnostics/deref-track-symbolic-region.c b/test/Analysis/diagnostics/deref-track-symbolic-region.c
index 3ba2707..94774dd 100644
--- a/test/Analysis/diagnostics/deref-track-symbolic-region.c
+++ b/test/Analysis/diagnostics/deref-track-symbolic-region.c
@@ -1,5 +1,6 @@
// 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
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file %s -o %t.plist
+// RUN: FileCheck --input-file=%t.plist %s
struct S {
int *x;
@@ -8,347 +9,297 @@ struct S {
int *foo();
-void inlined(struct S *s, int m) {
- if (s->x)
+void test(struct S syz, int *pp) {
+ int m = 0;
+ syz.x = foo(); // expected-note{{Value assigned to 'syz.x'}}
+
+ struct S *ps = &syz;
+ if (ps->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')}}
+ // expected-note@-1{{Dereference of null pointer (loaded from field 'x')}}
}
-//CHECK: <dict>
-//CHECK: <key>files</key>
-//CHECK: <array>
-//CHECK: </array>
-//CHECK: <key>diagnostics</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>path</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>kind</key><string>control</string>
-//CHECK: <key>edges</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>start</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>20</integer>
-//CHECK: <key>col</key><integer>3</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>20</integer>
-//CHECK: <key>col</key><integer>5</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: <key>end</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>22</integer>
-//CHECK: <key>col</key><integer>3</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>22</integer>
-//CHECK: <key>col</key><integer>9</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>kind</key><string>event</string>
-//CHECK: <key>location</key>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>22</integer>
-//CHECK: <key>col</key><integer>3</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <key>ranges</key>
-//CHECK: <array>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>22</integer>
-//CHECK: <key>col</key><integer>3</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>22</integer>
-//CHECK: <key>col</key><integer>18</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </array>
-//CHECK: <key>depth</key><integer>0</integer>
-//CHECK: <key>extended_message</key>
-//CHECK: <string>Calling &apos;inlined&apos;</string>
-//CHECK: <key>message</key>
-//CHECK: <string>Calling &apos;inlined&apos;</string>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>kind</key><string>event</string>
-//CHECK: <key>location</key>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>11</integer>
-//CHECK: <key>col</key><integer>1</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <key>depth</key><integer>1</integer>
-//CHECK: <key>extended_message</key>
-//CHECK: <string>Entered call from &apos;test&apos;</string>
-//CHECK: <key>message</key>
-//CHECK: <string>Entered call from &apos;test&apos;</string>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>kind</key><string>control</string>
-//CHECK: <key>edges</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>start</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>11</integer>
-//CHECK: <key>col</key><integer>1</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>11</integer>
-//CHECK: <key>col</key><integer>4</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: <key>end</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>12</integer>
-//CHECK: <key>col</key><integer>3</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>12</integer>
-//CHECK: <key>col</key><integer>4</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>kind</key><string>control</string>
-//CHECK: <key>edges</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>start</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>12</integer>
-//CHECK: <key>col</key><integer>3</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>12</integer>
-//CHECK: <key>col</key><integer>4</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: <key>end</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>12</integer>
-//CHECK: <key>col</key><integer>7</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>12</integer>
-//CHECK: <key>col</key><integer>7</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>kind</key><string>event</string>
-//CHECK: <key>location</key>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>12</integer>
-//CHECK: <key>col</key><integer>7</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <key>ranges</key>
-//CHECK: <array>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>12</integer>
-//CHECK: <key>col</key><integer>7</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>12</integer>
-//CHECK: <key>col</key><integer>10</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </array>
-//CHECK: <key>depth</key><integer>1</integer>
-//CHECK: <key>extended_message</key>
-//CHECK: <string>Assuming pointer value is null</string>
-//CHECK: <key>message</key>
-//CHECK: <string>Assuming pointer value is null</string>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>kind</key><string>event</string>
-//CHECK: <key>location</key>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>22</integer>
-//CHECK: <key>col</key><integer>3</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <key>ranges</key>
-//CHECK: <array>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>22</integer>
-//CHECK: <key>col</key><integer>3</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>22</integer>
-//CHECK: <key>col</key><integer>18</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </array>
-//CHECK: <key>depth</key><integer>1</integer>
-//CHECK: <key>extended_message</key>
-//CHECK: <string>Returning from &apos;inlined&apos;</string>
-//CHECK: <key>message</key>
-//CHECK: <string>Returning from &apos;inlined&apos;</string>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>kind</key><string>control</string>
-//CHECK: <key>edges</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>start</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>22</integer>
-//CHECK: <key>col</key><integer>3</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>22</integer>
-//CHECK: <key>col</key><integer>9</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: <key>end</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>25</integer>
-//CHECK: <key>col</key><integer>3</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>25</integer>
-//CHECK: <key>col</key><integer>3</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>kind</key><string>control</string>
-//CHECK: <key>edges</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>start</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>25</integer>
-//CHECK: <key>col</key><integer>3</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>25</integer>
-//CHECK: <key>col</key><integer>3</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: <key>end</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>25</integer>
-//CHECK: <key>col</key><integer>8</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>25</integer>
-//CHECK: <key>col</key><integer>8</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>kind</key><string>event</string>
-//CHECK: <key>location</key>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>25</integer>
-//CHECK: <key>col</key><integer>8</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <key>ranges</key>
-//CHECK: <array>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>25</integer>
-//CHECK: <key>col</key><integer>13</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>25</integer>
-//CHECK: <key>col</key><integer>13</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </array>
-//CHECK: <key>depth</key><integer>0</integer>
-//CHECK: <key>extended_message</key>
-//CHECK: <string>Dereference of null pointer (loaded from field &apos;x&apos;)</string>
-//CHECK: <key>message</key>
-//CHECK: <string>Dereference of null pointer (loaded from field &apos;x&apos;)</string>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: <key>description</key><string>Dereference of null pointer (loaded from field &apos;x&apos;)</string>
-//CHECK: <key>category</key><string>Logic error</string>
-//CHECK: <key>type</key><string>Dereference of null pointer</string>
-//CHECK: <key>issue_context_kind</key><string>function</string>
-//CHECK: <key>issue_context</key><string>test</string>
-//CHECK: <key>issue_hash</key><integer>6</integer>
-//CHECK: <key>location</key>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>25</integer>
-//CHECK: <key>col</key><integer>8</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: </plist>
+// CHECK: <key>diagnostics</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>13</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>13</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>14</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>14</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>14</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>14</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>14</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Value assigned to &apos;syz.x&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Value assigned to &apos;syz.x&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>14</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>14</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Assuming pointer value is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming pointer value is null</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>23</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>23</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>23</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>23</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>23</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>23</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>23</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>23</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>23</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from field &apos;x&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from field &apos;x&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from field &apos;x&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test</string>
+// CHECK-NEXT: <key>issue_hash</key><string>11</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>23</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </plist>
diff --git a/test/Analysis/diagnostics/deref-track-symbolic-region.cpp b/test/Analysis/diagnostics/deref-track-symbolic-region.cpp
index fb493d7..6d34841 100644
--- a/test/Analysis/diagnostics/deref-track-symbolic-region.cpp
+++ b/test/Analysis/diagnostics/deref-track-symbolic-region.cpp
@@ -7,10 +7,37 @@ struct S {
S &getSomeReference();
void test(S *p) {
- S &r = *p; //expected-note {{Variable 'r' initialized here}}
+ S &r = *p; //expected-note {{'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')}}
}
+
+void testRefParam(int *ptr) {
+ int &ref = *ptr; // expected-note {{'ref' initialized here}}
+ if (ptr)
+ // expected-note@-1{{Assuming 'ptr' is null}}
+ // expected-note@-2{{Taking false branch}}
+ return;
+
+ extern void use(int &ref);
+ use(ref); // expected-warning{{Forming reference to null pointer}}
+ // expected-note@-1{{Forming reference to null pointer}}
+}
+
+int testRefToNullPtr() {
+ int *p = 0; // expected-note {{'p' initialized to a null pointer value}}
+ int *const &p2 = p; // expected-note{{'p2' initialized here}}
+ int *p3 = p2; // expected-note {{'p3' initialized to a null pointer value}}
+ return *p3; // expected-warning {{Dereference of null pointer}}
+ // expected-note@-1{{Dereference of null pointer}}
+}
+
+int testRefToNullPtr2() {
+ int *p = 0; // expected-note {{'p' initialized to a null pointer value}}
+ int *const &p2 = p;// expected-note{{'p2' initialized here}}
+ return *p2; //expected-warning {{Dereference of null pointer}}
+ // expected-note@-1{{Dereference of null pointer}}
+} \ No newline at end of file
diff --git a/test/Analysis/diagnostics/explicit-suppression.cpp b/test/Analysis/diagnostics/explicit-suppression.cpp
new file mode 100644
index 0000000..79afeed
--- /dev/null
+++ b/test/Analysis/diagnostics/explicit-suppression.cpp
@@ -0,0 +1,80 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config suppress-c++-stdlib=false -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config suppress-c++-stdlib=true -DSUPPRESSED=1 -verify %s
+
+#ifdef SUPPRESSED
+// expected-no-diagnostics
+#endif
+
+#include "../Inputs/system-header-simulator-cxx.h"
+
+void clang_analyzer_eval(bool);
+
+void testCopyNull(int *I, int *E) {
+ std::copy(I, E, (int *)0);
+#ifndef SUPPRESSED
+ // This line number comes from system-header-simulator-cxx.h.
+ // expected-warning@79 {{Dereference of null pointer}}
+#endif
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// PR15613: expected-* can't refer to diagnostics in other source files.
+// The current implementation only matches line numbers, but has an upper limit
+// of the number of lines in the main source file.
diff --git a/test/Analysis/diagnostics/false-positive-suppression.c b/test/Analysis/diagnostics/false-positive-suppression.c
new file mode 100644
index 0000000..cdcd7cc
--- /dev/null
+++ b/test/Analysis/diagnostics/false-positive-suppression.c
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -I %S/Inputs -analyze -analyzer-checker=core,unix -verify %s
+// expected-no-diagnostics
+
+#include "include/sys/queue.h"
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+
+int radar12491259() {
+ int *p = malloc(12);
+ FREE_POINTER(p);
+ FREE_POINTER(p); // no-warning: we are suppressing errors coming from sys/queue macros.
+ return 0;
+}
+
+#define MYMACRO(p) FREE_POINTER(p)
+
+int radar12491259_inside_macro() {
+ int *p = malloc(12);
+ MYMACRO(p);
+ MYMACRO(p); // no-warning: we are suppressing errors coming from sys/queue macros.
+ return 0;
+}
diff --git a/test/Analysis/diagnostics/no-prune-paths.c b/test/Analysis/diagnostics/no-prune-paths.c
new file mode 100644
index 0000000..fab5cf8
--- /dev/null
+++ b/test/Analysis/diagnostics/no-prune-paths.c
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -analyzer-config prune-paths=false -DNPRUNE=1 -verify %s
+
+// "prune-paths" is a debug option only; this is just a simple test to see that
+// it's being honored.
+
+void helper() {
+ extern void foo();
+ foo();
+}
+
+void test() {
+ helper();
+#if NPRUNE
+ // expected-note@-2 {{Calling 'helper'}}
+ // expected-note@-3 {{Returning from 'helper'}}
+#endif
+
+ *(volatile int *)0 = 1; // expected-warning {{Dereference of null pointer}}
+ // expected-note@-1 {{Dereference of null pointer}}
+}
diff --git a/test/Analysis/diagnostics/shortest-path-suppression.c b/test/Analysis/diagnostics/shortest-path-suppression.c
new file mode 100644
index 0000000..4f648b9
--- /dev/null
+++ b/test/Analysis/diagnostics/shortest-path-suppression.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config suppress-null-return-paths=true -analyzer-output=text -verify %s
+// expected-no-diagnostics
+
+int *returnNull() { return 0; }
+int coin();
+
+// Use a float parameter to ensure that the value is unknown. This will create
+// a cycle in the generated ExplodedGraph.
+void testCycle(float i) {
+ int *x = returnNull();
+ int y;
+ while (i > 0) {
+ x = returnNull();
+ y = 2;
+ i -= 1;
+ }
+ *x = 1; // no-warning
+ y += 1;
+}
diff --git a/test/Analysis/diagnostics/undef-value-caller.c b/test/Analysis/diagnostics/undef-value-caller.c
index 627b334..adfdd43 100644
--- a/test/Analysis/diagnostics/undef-value-caller.c
+++ b/test/Analysis/diagnostics/undef-value-caller.c
@@ -11,155 +11,149 @@ int test_calling_unimportant_callee(int argc, char *argv[]) {
return x; // expected-warning {{Undefined or garbage value returned to caller}}
}
-//CHECK: <dict>
-//CHECK: <key>files</key>
-//CHECK: <array>
-//CHECK: </array>
-//CHECK: <key>diagnostics</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>path</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>kind</key><string>event</string>
-//CHECK: <key>location</key>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>9</integer>
-//CHECK: <key>col</key><integer>3</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <key>ranges</key>
-//CHECK: <array>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>9</integer>
-//CHECK: <key>col</key><integer>3</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>9</integer>
-//CHECK: <key>col</key><integer>7</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </array>
-//CHECK: <key>depth</key><integer>0</integer>
-//CHECK: <key>extended_message</key>
-//CHECK: <string>Variable &apos;x&apos; declared without an initial value</string>
-//CHECK: <key>message</key>
-//CHECK: <string>Variable &apos;x&apos; declared without an initial value</string>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>kind</key><string>control</string>
-//CHECK: <key>edges</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>start</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>9</integer>
-//CHECK: <key>col</key><integer>3</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>9</integer>
-//CHECK: <key>col</key><integer>5</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: <key>end</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>10</integer>
-//CHECK: <key>col</key><integer>3</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>10</integer>
-//CHECK: <key>col</key><integer>8</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>kind</key><string>control</string>
-//CHECK: <key>edges</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>start</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>10</integer>
-//CHECK: <key>col</key><integer>3</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>10</integer>
-//CHECK: <key>col</key><integer>8</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: <key>end</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>11</integer>
-//CHECK: <key>col</key><integer>3</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>11</integer>
-//CHECK: <key>col</key><integer>8</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>kind</key><string>event</string>
-//CHECK: <key>location</key>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>11</integer>
-//CHECK: <key>col</key><integer>3</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <key>ranges</key>
-//CHECK: <array>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>11</integer>
-//CHECK: <key>col</key><integer>10</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>11</integer>
-//CHECK: <key>col</key><integer>10</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </array>
-//CHECK: <key>depth</key><integer>0</integer>
-//CHECK: <key>extended_message</key>
-//CHECK: <string>Undefined or garbage value returned to caller</string>
-//CHECK: <key>message</key>
-//CHECK: <string>Undefined or garbage value returned to caller</string>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: <key>description</key><string>Undefined or garbage value returned to caller</string>
-//CHECK: <key>category</key><string>Logic error</string>
-//CHECK: <key>type</key><string>Garbage return value</string>
-//CHECK: <key>issue_context_kind</key><string>function</string>
-//CHECK: <key>issue_context</key><string>test_calling_unimportant_callee</string>
-//CHECK: <key>issue_hash</key><integer>3</integer>
-//CHECK: <key>location</key>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>11</integer>
-//CHECK: <key>col</key><integer>3</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: </plist>
+// CHECK: <key>diagnostics</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>9</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>9</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>9</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;x&apos; declared without an initial value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;x&apos; declared without an initial value</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>9</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>9</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Undefined or garbage value returned to caller</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Undefined or garbage value returned to caller</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Undefined or garbage value returned to caller</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Garbage return value</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_calling_unimportant_callee</string>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
diff --git a/test/Analysis/diagnostics/undef-value-param.c b/test/Analysis/diagnostics/undef-value-param.c
index 88d87cf..597bf91 100644
--- a/test/Analysis/diagnostics/undef-value-param.c
+++ b/test/Analysis/diagnostics/undef-value-param.c
@@ -1,5 +1,6 @@
// 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
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file %s -o %t.plist
+// RUN: FileCheck --input-file=%t.plist %s
void foo_irrelevant(int c) {
if (c)
@@ -16,7 +17,7 @@ void foo(int c, int *x) {
}
int use(int c) {
- int xx; //expected-note{{Variable 'xx' declared without an initial value}}
+ int xx; //expected-note {{'xx' declared without an initial value}}
int *y = &xx;
foo (c, y);
//expected-note@-1{{Calling 'foo'}}
@@ -55,7 +56,7 @@ void initStruct(int x, struct WithFields *X) {
}
double testPassingParentRegionStruct(int x) {
struct WithFields st;
- st.f1 = 0;
+ st.f1 = 0; // expected-note {{Null pointer value stored to 'st.f1'}}
initStruct(x, &st); //expected-note {{Calling 'initStruct'}}
//expected-note@-1 {{Returning from 'initStruct'}}
return (*st.f1); //expected-warning {{Dereference of null pointer}}
@@ -71,7 +72,7 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
+// CHECK-NEXT: <key>line</key><integer>20</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -79,12 +80,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
+// CHECK-NEXT: <key>line</key><integer>20</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
+// CHECK-NEXT: <key>line</key><integer>20</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -92,9 +93,9 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;xx&apos; declared without an initial value</string>
+// CHECK-NEXT: <string>&apos;xx&apos; declared without an initial value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;xx&apos; declared without an initial value</string>
+// CHECK-NEXT: <string>&apos;xx&apos; declared without an initial value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -104,12 +105,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
+// CHECK-NEXT: <key>line</key><integer>20</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
+// CHECK-NEXT: <key>line</key><integer>20</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -117,12 +118,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>22</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>22</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -134,7 +135,7 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>22</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -142,12 +143,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>22</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>22</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -163,7 +164,7 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>line</key><integer>11</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -181,12 +182,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>line</key><integer>11</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>line</key><integer>11</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -194,12 +195,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>line</key><integer>12</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>line</key><integer>12</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -215,12 +216,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>line</key><integer>12</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>line</key><integer>12</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -228,12 +229,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>line</key><integer>12</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>line</key><integer>12</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -245,7 +246,7 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>line</key><integer>12</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -253,12 +254,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>line</key><integer>12</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>line</key><integer>12</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -278,12 +279,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>line</key><integer>12</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>11</integer>
+// CHECK-NEXT: <key>line</key><integer>12</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -291,12 +292,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>14</integer>
+// CHECK-NEXT: <key>line</key><integer>15</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>14</integer>
+// CHECK-NEXT: <key>line</key><integer>15</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -308,7 +309,7 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>22</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -316,12 +317,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>22</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>22</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -341,12 +342,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>22</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
+// CHECK-NEXT: <key>line</key><integer>22</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -354,12 +355,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>line</key><integer>25</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>line</key><integer>25</integer>
// CHECK-NEXT: <key>col</key><integer>18</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -375,12 +376,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>line</key><integer>25</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>line</key><integer>25</integer>
// CHECK-NEXT: <key>col</key><integer>18</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -388,12 +389,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
+// CHECK-NEXT: <key>line</key><integer>26</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
+// CHECK-NEXT: <key>line</key><integer>26</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -409,12 +410,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
+// CHECK-NEXT: <key>line</key><integer>26</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
+// CHECK-NEXT: <key>line</key><integer>26</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -422,12 +423,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
+// CHECK-NEXT: <key>line</key><integer>26</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
+// CHECK-NEXT: <key>line</key><integer>26</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -439,7 +440,7 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
+// CHECK-NEXT: <key>line</key><integer>26</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -447,12 +448,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
+// CHECK-NEXT: <key>line</key><integer>26</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
+// CHECK-NEXT: <key>line</key><integer>26</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -470,10 +471,10 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>type</key><string>Result of operation is garbage or undefined</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>use</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>7</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>7</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
+// CHECK-NEXT: <key>line</key><integer>26</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -489,12 +490,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>38</integer>
+// CHECK-NEXT: <key>line</key><integer>39</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>38</integer>
+// CHECK-NEXT: <key>line</key><integer>39</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -502,12 +503,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>39</integer>
+// CHECK-NEXT: <key>line</key><integer>40</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>39</integer>
+// CHECK-NEXT: <key>line</key><integer>40</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -519,7 +520,7 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>39</integer>
+// CHECK-NEXT: <key>line</key><integer>40</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -527,12 +528,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>39</integer>
+// CHECK-NEXT: <key>line</key><integer>40</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>39</integer>
+// CHECK-NEXT: <key>line</key><integer>40</integer>
// CHECK-NEXT: <key>col</key><integer>21</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -548,7 +549,7 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>29</integer>
+// CHECK-NEXT: <key>line</key><integer>30</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -566,12 +567,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>29</integer>
+// CHECK-NEXT: <key>line</key><integer>30</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>29</integer>
+// CHECK-NEXT: <key>line</key><integer>30</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -579,12 +580,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>30</integer>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>30</integer>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -600,12 +601,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>30</integer>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>30</integer>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -613,12 +614,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>30</integer>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>30</integer>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -630,7 +631,7 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>30</integer>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -638,12 +639,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>30</integer>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>30</integer>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -663,12 +664,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>30</integer>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>30</integer>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -676,12 +677,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>32</integer>
+// CHECK-NEXT: <key>line</key><integer>33</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>32</integer>
+// CHECK-NEXT: <key>line</key><integer>33</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -693,7 +694,7 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>39</integer>
+// CHECK-NEXT: <key>line</key><integer>40</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -701,12 +702,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>39</integer>
+// CHECK-NEXT: <key>line</key><integer>40</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>39</integer>
+// CHECK-NEXT: <key>line</key><integer>40</integer>
// CHECK-NEXT: <key>col</key><integer>21</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -726,12 +727,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>39</integer>
+// CHECK-NEXT: <key>line</key><integer>40</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>39</integer>
+// CHECK-NEXT: <key>line</key><integer>40</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -739,12 +740,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>line</key><integer>42</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>line</key><integer>42</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -760,12 +761,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>line</key><integer>42</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>line</key><integer>42</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -773,12 +774,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>line</key><integer>42</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>line</key><integer>42</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -790,7 +791,7 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>line</key><integer>42</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -798,12 +799,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>line</key><integer>42</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>line</key><integer>42</integer>
// CHECK-NEXT: <key>col</key><integer>21</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -821,10 +822,10 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>type</key><string>Result of operation is garbage or undefined</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testPassingParentRegionArray</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>line</key><integer>42</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -840,12 +841,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>57</integer>
+// CHECK-NEXT: <key>line</key><integer>58</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>57</integer>
+// CHECK-NEXT: <key>line</key><integer>58</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -859,7 +860,7 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>59</integer>
-// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
@@ -884,6 +885,69 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>59</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;st.f1&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;st.f1&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>59</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>59</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -899,7 +963,7 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>49</integer>
+// CHECK-NEXT: <key>line</key><integer>50</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -917,12 +981,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>49</integer>
+// CHECK-NEXT: <key>line</key><integer>50</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>49</integer>
+// CHECK-NEXT: <key>line</key><integer>50</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -930,12 +994,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>50</integer>
+// CHECK-NEXT: <key>line</key><integer>51</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>50</integer>
+// CHECK-NEXT: <key>line</key><integer>51</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -951,12 +1015,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>50</integer>
+// CHECK-NEXT: <key>line</key><integer>51</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>50</integer>
+// CHECK-NEXT: <key>line</key><integer>51</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -964,12 +1028,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>50</integer>
+// CHECK-NEXT: <key>line</key><integer>51</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>50</integer>
+// CHECK-NEXT: <key>line</key><integer>51</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -981,7 +1045,7 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>50</integer>
+// CHECK-NEXT: <key>line</key><integer>51</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -989,12 +1053,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>50</integer>
+// CHECK-NEXT: <key>line</key><integer>51</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>50</integer>
+// CHECK-NEXT: <key>line</key><integer>51</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1014,12 +1078,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>50</integer>
+// CHECK-NEXT: <key>line</key><integer>51</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>50</integer>
+// CHECK-NEXT: <key>line</key><integer>51</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1027,12 +1091,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>53</integer>
+// CHECK-NEXT: <key>line</key><integer>54</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>53</integer>
+// CHECK-NEXT: <key>line</key><integer>54</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1044,7 +1108,7 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>59</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1052,12 +1116,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>59</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>59</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1077,12 +1141,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>59</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>59</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1090,12 +1154,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>62</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>62</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1111,12 +1175,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>62</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>62</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1124,12 +1188,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>62</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>62</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1141,7 +1205,7 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>62</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1149,12 +1213,12 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>62</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>62</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1172,10 +1236,10 @@ double testPassingParentRegionStruct(int x) {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testPassingParentRegionStruct</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>62</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
diff --git a/test/Analysis/diagnostics/undef-value-param.m b/test/Analysis/diagnostics/undef-value-param.m
index d2a7a08..d6c8a16 100644
--- a/test/Analysis/diagnostics/undef-value-param.m
+++ b/test/Analysis/diagnostics/undef-value-param.m
@@ -26,451 +26,910 @@ extern void CFRelease(CFTypeRef cf);
typedef SpecialString* SCDynamicStoreRef;
static void CreateRef(SCDynamicStoreRef *storeRef, unsigned x);
+static void CreateRefUndef(SCDynamicStoreRef *storeRef, unsigned x);
SCDynamicStoreRef anotherCreateRef(unsigned *err, unsigned x);
@implementation Cell
- (void) test {
- SCDynamicStoreRef storeRef = 0; //expected-note{{Variable 'storeRef' initialized to nil}}
+ SCDynamicStoreRef storeRef = 0;
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}}
}
+
+- (void)test2 {
+ SCDynamicStoreRef storeRef; // expected-note {{'storeRef' declared without an initial value}}
+ CreateRefUndef(&storeRef, 4);
+ //expected-note@-1{{Calling 'CreateRefUndef'}}
+ //expected-note@-2{{Returning from 'CreateRefUndef'}}
+ CFRelease(storeRef); //expected-warning {{Function call argument is an uninitialized value}}
+ //expected-note@-1{{Function call argument is an uninitialized value}}
+}
@end
static void CreateRef(SCDynamicStoreRef *storeRef, unsigned x) {
unsigned err = 0;
- SCDynamicStoreRef ref = anotherCreateRef(&err, x); // why this is being inlined?
+ SCDynamicStoreRef ref = anotherCreateRef(&err, x);
if (err) {
//expected-note@-1{{Assuming 'err' is not equal to 0}}
//expected-note@-2{{Taking true branch}}
CFRelease(ref);
- ref = 0;
+ ref = 0; // expected-note{{nil object reference stored to 'ref'}}
}
- *storeRef = ref;
+ *storeRef = ref; // expected-note{{nil object reference stored to 'storeRef'}}
+}
+
+static void CreateRefUndef(SCDynamicStoreRef *storeRef, unsigned x) {
+ unsigned err = 0;
+ SCDynamicStoreRef ref = anotherCreateRef(&err, x);
+ if (err) {
+ //expected-note@-1{{Assuming 'err' is not equal to 0}}
+ //expected-note@-2{{Taking true branch}}
+ CFRelease(ref);
+ return;
+ }
+ *storeRef = ref;
}
-//CHECK: <dict>
-//CHECK: <key>files</key>
-//CHECK: <array>
-//CHECK: </array>
-//CHECK: <key>diagnostics</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>path</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>kind</key><string>event</string>
-//CHECK: <key>location</key>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>33</integer>
-//CHECK: <key>col</key><integer>5</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <key>ranges</key>
-//CHECK: <array>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>33</integer>
-//CHECK: <key>col</key><integer>5</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>33</integer>
-//CHECK: <key>col</key><integer>30</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </array>
-//CHECK: <key>depth</key><integer>0</integer>
-//CHECK: <key>extended_message</key>
-//CHECK: <string>Variable &apos;storeRef&apos; initialized to nil</string>
-//CHECK: <key>message</key>
-//CHECK: <string>Variable &apos;storeRef&apos; initialized to nil</string>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>kind</key><string>control</string>
-//CHECK: <key>edges</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>start</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>33</integer>
-//CHECK: <key>col</key><integer>5</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>33</integer>
-//CHECK: <key>col</key><integer>21</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: <key>end</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>34</integer>
-//CHECK: <key>col</key><integer>5</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>34</integer>
-//CHECK: <key>col</key><integer>13</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>kind</key><string>event</string>
-//CHECK: <key>location</key>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>34</integer>
-//CHECK: <key>col</key><integer>5</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <key>ranges</key>
-//CHECK: <array>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>34</integer>
-//CHECK: <key>col</key><integer>5</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>34</integer>
-//CHECK: <key>col</key><integer>27</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </array>
-//CHECK: <key>depth</key><integer>0</integer>
-//CHECK: <key>extended_message</key>
-//CHECK: <string>Calling &apos;CreateRef&apos;</string>
-//CHECK: <key>message</key>
-//CHECK: <string>Calling &apos;CreateRef&apos;</string>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>kind</key><string>event</string>
-//CHECK: <key>location</key>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>42</integer>
-//CHECK: <key>col</key><integer>1</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <key>depth</key><integer>1</integer>
-//CHECK: <key>extended_message</key>
-//CHECK: <string>Entered call from &apos;test&apos;</string>
-//CHECK: <key>message</key>
-//CHECK: <string>Entered call from &apos;test&apos;</string>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>kind</key><string>control</string>
-//CHECK: <key>edges</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>start</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>42</integer>
-//CHECK: <key>col</key><integer>1</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>42</integer>
-//CHECK: <key>col</key><integer>6</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: <key>end</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>43</integer>
-//CHECK: <key>col</key><integer>5</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>43</integer>
-//CHECK: <key>col</key><integer>12</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>kind</key><string>control</string>
-//CHECK: <key>edges</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>start</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>43</integer>
-//CHECK: <key>col</key><integer>5</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>43</integer>
-//CHECK: <key>col</key><integer>12</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: <key>end</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>45</integer>
-//CHECK: <key>col</key><integer>5</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>45</integer>
-//CHECK: <key>col</key><integer>6</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>kind</key><string>control</string>
-//CHECK: <key>edges</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>start</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>45</integer>
-//CHECK: <key>col</key><integer>5</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>45</integer>
-//CHECK: <key>col</key><integer>6</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: <key>end</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>45</integer>
-//CHECK: <key>col</key><integer>9</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>45</integer>
-//CHECK: <key>col</key><integer>11</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>kind</key><string>event</string>
-//CHECK: <key>location</key>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>45</integer>
-//CHECK: <key>col</key><integer>9</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <key>ranges</key>
-//CHECK: <array>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>45</integer>
-//CHECK: <key>col</key><integer>9</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>45</integer>
-//CHECK: <key>col</key><integer>11</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </array>
-//CHECK: <key>depth</key><integer>1</integer>
-//CHECK: <key>extended_message</key>
-//CHECK: <string>Assuming &apos;err&apos; is not equal to 0</string>
-//CHECK: <key>message</key>
-//CHECK: <string>Assuming &apos;err&apos; is not equal to 0</string>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>kind</key><string>control</string>
-//CHECK: <key>edges</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>start</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>45</integer>
-//CHECK: <key>col</key><integer>9</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>45</integer>
-//CHECK: <key>col</key><integer>11</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: <key>end</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>48</integer>
-//CHECK: <key>col</key><integer>9</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>48</integer>
-//CHECK: <key>col</key><integer>17</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>kind</key><string>control</string>
-//CHECK: <key>edges</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>start</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>48</integer>
-//CHECK: <key>col</key><integer>9</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>48</integer>
-//CHECK: <key>col</key><integer>17</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: <key>end</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>51</integer>
-//CHECK: <key>col</key><integer>5</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>51</integer>
-//CHECK: <key>col</key><integer>5</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>kind</key><string>event</string>
-//CHECK: <key>location</key>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>34</integer>
-//CHECK: <key>col</key><integer>5</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <key>ranges</key>
-//CHECK: <array>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>34</integer>
-//CHECK: <key>col</key><integer>5</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>34</integer>
-//CHECK: <key>col</key><integer>27</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </array>
-//CHECK: <key>depth</key><integer>1</integer>
-//CHECK: <key>extended_message</key>
-//CHECK: <string>Returning from &apos;CreateRef&apos;</string>
-//CHECK: <key>message</key>
-//CHECK: <string>Returning from &apos;CreateRef&apos;</string>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>kind</key><string>control</string>
-//CHECK: <key>edges</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>start</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>34</integer>
-//CHECK: <key>col</key><integer>5</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>34</integer>
-//CHECK: <key>col</key><integer>13</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: <key>end</key>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>37</integer>
-//CHECK: <key>col</key><integer>5</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>37</integer>
-//CHECK: <key>col</key><integer>13</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>kind</key><string>event</string>
-//CHECK: <key>location</key>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>37</integer>
-//CHECK: <key>col</key><integer>5</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <key>ranges</key>
-//CHECK: <array>
-//CHECK: <array>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>37</integer>
-//CHECK: <key>col</key><integer>15</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>37</integer>
-//CHECK: <key>col</key><integer>22</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </array>
-//CHECK: <key>depth</key><integer>0</integer>
-//CHECK: <key>extended_message</key>
-//CHECK: <string>Null pointer argument in call to CFRelease</string>
-//CHECK: <key>message</key>
-//CHECK: <string>Null pointer argument in call to CFRelease</string>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: <key>description</key><string>Null pointer argument in call to CFRelease</string>
-//CHECK: <key>category</key><string>API Misuse (Apple)</string>
-//CHECK: <key>type</key><string>null passed to CFRetain/CFRelease/CFMakeCollectable</string>
-//CHECK: <key>issue_context_kind</key><string>Objective-C method</string>
-//CHECK: <key>issue_context</key><string>test</string>
-//CHECK: <key>issue_hash</key><integer>5</integer>
-//CHECK: <key>location</key>
-//CHECK: <dict>
-//CHECK: <key>line</key><integer>37</integer>
-//CHECK: <key>col</key><integer>5</integer>
-//CHECK: <key>file</key><integer>0</integer>
-//CHECK: </dict>
-//CHECK: </dict>
-//CHECK: </array>
-//CHECK: </dict>
-//CHECK: </plist>
+// CHECK: <key>diagnostics</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>34</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>34</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>35</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>35</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>35</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>35</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>35</integer>
+// CHECK-NEXT: <key>col</key><integer>27</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling &apos;CreateRef&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;CreateRef&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>52</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from &apos;test&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;test&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>52</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>52</integer>
+// CHECK-NEXT: <key>col</key><integer>6</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>53</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>53</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>53</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>53</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>55</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>55</integer>
+// CHECK-NEXT: <key>col</key><integer>6</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>55</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>55</integer>
+// CHECK-NEXT: <key>col</key><integer>6</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>55</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>55</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>55</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>55</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>55</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Assuming &apos;err&apos; is not equal to 0</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;err&apos; is not equal to 0</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>55</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>55</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>58</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>58</integer>
+// CHECK-NEXT: <key>col</key><integer>17</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>58</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>58</integer>
+// CHECK-NEXT: <key>col</key><integer>17</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>59</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>59</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>59</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>59</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>59</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>nil object reference stored to &apos;ref&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>nil object reference stored to &apos;ref&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>59</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>59</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>nil object reference stored to &apos;storeRef&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>nil object reference stored to &apos;storeRef&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>35</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>35</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>35</integer>
+// CHECK-NEXT: <key>col</key><integer>27</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning from &apos;CreateRef&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning from &apos;CreateRef&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>35</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>35</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>38</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>38</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>38</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>38</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>38</integer>
+// CHECK-NEXT: <key>col</key><integer>22</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Null pointer argument in call to CFRelease</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Null pointer argument in call to CFRelease</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Null pointer argument in call to CFRelease</string>
+// CHECK-NEXT: <key>category</key><string>API Misuse (Apple)</string>
+// CHECK-NEXT: <key>type</key><string>null passed to CFRetain/CFRelease/CFMakeCollectable</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
+// CHECK-NEXT: <key>issue_context</key><string>test</string>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>38</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>43</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>43</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>43</integer>
+// CHECK-NEXT: <key>col</key><integer>30</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;storeRef&apos; declared without an initial value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;storeRef&apos; declared without an initial value</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>43</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>43</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>44</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>44</integer>
+// CHECK-NEXT: <key>col</key><integer>18</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>44</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>44</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>44</integer>
+// CHECK-NEXT: <key>col</key><integer>32</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling &apos;CreateRefUndef&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;CreateRefUndef&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from &apos;test2&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;test2&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>col</key><integer>6</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>67</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>67</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>67</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>67</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>67</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>67</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>67</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>67</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>67</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Assuming &apos;err&apos; is not equal to 0</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;err&apos; is not equal to 0</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>67</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>67</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>70</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>70</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>44</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>44</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>44</integer>
+// CHECK-NEXT: <key>col</key><integer>32</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning from &apos;CreateRefUndef&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning from &apos;CreateRefUndef&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>44</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>44</integer>
+// CHECK-NEXT: <key>col</key><integer>18</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>47</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>47</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>47</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>47</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>47</integer>
+// CHECK-NEXT: <key>col</key><integer>22</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Function call argument is an uninitialized value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Function call argument is an uninitialized value</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Function call argument is an uninitialized value</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Uninitialized argument value</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
+// CHECK-NEXT: <key>issue_context</key><string>test2</string>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>47</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
diff --git a/test/Analysis/dtor.cpp b/test/Analysis/dtor.cpp
index f461945..18cd985 100644
--- a/test/Analysis/dtor.cpp
+++ b/test/Analysis/dtor.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-ipa=inlining -analyzer-config c++-inlining=destructors -Wno-null-dereference -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-inlining=destructors -Wno-null-dereference -verify %s
void clang_analyzer_eval(bool);
void clang_analyzer_checkInlined(bool);
@@ -301,3 +301,103 @@ namespace ExplicitDestructorCall {
obj->VirtualDtor::~VirtualDtor();
}
}
+
+
+namespace MultidimensionalArrays {
+ void testArrayInvalidation() {
+ int i = 42;
+ int j = 42;
+
+ {
+ IntWrapper arr[2][2];
+
+ // There should be no undefined value warnings here.
+ // Eventually these should be TRUE as well, but right now
+ // we can't handle array constructors.
+ clang_analyzer_eval(arr[0][0].x == 0); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(arr[1][1].x == 0); // expected-warning{{UNKNOWN}}
+
+ arr[0][0].x = &i;
+ arr[1][1].x = &j;
+ clang_analyzer_eval(*arr[0][0].x == 42); // expected-warning{{TRUE}}
+ clang_analyzer_eval(*arr[1][1].x == 42); // expected-warning{{TRUE}}
+ }
+
+ // The destructors should have invalidated i and j.
+ clang_analyzer_eval(i == 42); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(j == 42); // expected-warning{{UNKNOWN}}
+ }
+}
+
+namespace LifetimeExtension {
+ struct IntWrapper {
+ int x;
+ IntWrapper(int y) : x(y) {}
+ IntWrapper() {
+ extern void use(int);
+ use(x); // no-warning
+ }
+ };
+
+ struct DerivedWrapper : public IntWrapper {
+ DerivedWrapper(int y) : IntWrapper(y) {}
+ };
+
+ DerivedWrapper get() {
+ return DerivedWrapper(1);
+ }
+
+ void test() {
+ const DerivedWrapper &d = get(); // lifetime extended here
+ }
+
+
+ class SaveOnDestruct {
+ public:
+ static int lastOutput;
+ int value;
+
+ SaveOnDestruct();
+ ~SaveOnDestruct() {
+ lastOutput = value;
+ }
+ };
+
+ void testSimple() {
+ {
+ const SaveOnDestruct &obj = SaveOnDestruct();
+ if (obj.value != 42)
+ return;
+ // destructor called here
+ }
+
+ clang_analyzer_eval(SaveOnDestruct::lastOutput == 42); // expected-warning{{TRUE}}
+ }
+
+ class VirtualDtorBase {
+ public:
+ int value;
+ virtual ~VirtualDtorBase() {}
+ };
+
+ class SaveOnVirtualDestruct : public VirtualDtorBase {
+ public:
+ static int lastOutput;
+
+ SaveOnVirtualDestruct();
+ virtual ~SaveOnVirtualDestruct() {
+ lastOutput = value;
+ }
+ };
+
+ void testVirtual() {
+ {
+ const VirtualDtorBase &obj = SaveOnVirtualDestruct();
+ if (obj.value != 42)
+ return;
+ // destructor called here
+ }
+
+ clang_analyzer_eval(SaveOnVirtualDestruct::lastOutput == 42); // expected-warning{{TRUE}}
+ }
+}
diff --git a/test/Analysis/dtors-in-dtor-cfg-output.cpp b/test/Analysis/dtors-in-dtor-cfg-output.cpp
index f0546fc..ceda58c 100644
--- a/test/Analysis/dtors-in-dtor-cfg-output.cpp
+++ b/test/Analysis/dtors-in-dtor-cfg-output.cpp
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG %s 2>&1 | FileCheck %s
-// XPASS: *
class A {
public:
diff --git a/test/Analysis/dynamic-cast.cpp b/test/Analysis/dynamic-cast.cpp
index b1133ac..6bb571d 100644
--- a/test/Analysis/dynamic-cast.cpp
+++ b/test/Analysis/dynamic-cast.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=none -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=none -verify %s
void clang_analyzer_eval(bool);
diff --git a/test/Analysis/engine/replay-without-inlining.c b/test/Analysis/engine/replay-without-inlining.c
index 0602973..14b2b81 100644
--- a/test/Analysis/engine/replay-without-inlining.c
+++ b/test/Analysis/engine/replay-without-inlining.c
@@ -16,7 +16,7 @@ typedef struct {
int cur;
int end;
} IB;
-inline unsigned long gl(IB *input);
+unsigned long gl(IB *input);
inline void gbs(IB *input, unsigned char *buf, int count);
void getB(IB *st, Hdr2 *usedtobeundef);
inline unsigned char gb(IB *input) {
diff --git a/test/Analysis/fields.c b/test/Analysis/fields.c
index 12e8bbf..863a21a 100644
--- a/test/Analysis/fields.c
+++ b/test/Analysis/fields.c
@@ -29,6 +29,10 @@ void test() {
(void)(p = getit()).x;
}
+#define true ((bool)1)
+#define false ((bool)0)
+typedef _Bool bool;
+
void testLazyCompoundVal() {
Point p = {42, 0};
@@ -36,3 +40,86 @@ void testLazyCompoundVal() {
clang_analyzer_eval((q = p).x == 42); // expected-warning{{TRUE}}
clang_analyzer_eval(q.x == 42); // expected-warning{{TRUE}}
}
+
+
+struct Bits {
+ unsigned a : 1;
+ unsigned b : 2;
+ unsigned c : 1;
+
+ bool x;
+
+ struct InnerBits {
+ bool y;
+
+ unsigned d : 16;
+ unsigned e : 6;
+ unsigned f : 2;
+ } inner;
+};
+
+void testBitfields() {
+ struct Bits bits;
+
+ if (foo() && bits.b) // expected-warning {{garbage}}
+ return;
+ if (foo() && bits.inner.e) // expected-warning {{garbage}}
+ return;
+
+ bits.c = 1;
+ clang_analyzer_eval(bits.c == 1); // expected-warning {{TRUE}}
+
+ if (foo() && bits.b) // expected-warning {{garbage}}
+ return;
+ if (foo() && bits.x) // expected-warning {{garbage}}
+ return;
+
+ bits.x = true;
+ clang_analyzer_eval(bits.x == true); // expected-warning{{TRUE}}
+ bits.b = 2;
+ clang_analyzer_eval(bits.x == true); // expected-warning{{TRUE}}
+ if (foo() && bits.c) // no-warning
+ return;
+
+ bits.inner.e = 50;
+ if (foo() && bits.inner.e) // no-warning
+ return;
+ if (foo() && bits.inner.y) // expected-warning {{garbage}}
+ return;
+ if (foo() && bits.inner.f) // expected-warning {{garbage}}
+ return;
+
+ extern struct InnerBits getInner();
+ bits.inner = getInner();
+
+ if (foo() && bits.inner.e) // no-warning
+ return;
+ if (foo() && bits.inner.y) // no-warning
+ return;
+ if (foo() && bits.inner.f) // no-warning
+ return;
+
+ bits.inner.f = 1;
+
+ if (foo() && bits.inner.e) // no-warning
+ return;
+ if (foo() && bits.inner.y) // no-warning
+ return;
+ if (foo() && bits.inner.f) // no-warning
+ return;
+
+ if (foo() && bits.a) // expected-warning {{garbage}}
+ return;
+}
+
+
+//-----------------------------------------------------------------------------
+// Incorrect behavior
+//-----------------------------------------------------------------------------
+
+void testTruncation() {
+ struct Bits bits;
+ bits.c = 0x11; // expected-warning{{implicit truncation}}
+ // FIXME: We don't model truncation of bitfields.
+ clang_analyzer_eval(bits.c == 1); // expected-warning {{FALSE}}
+}
diff --git a/test/Analysis/free.c b/test/Analysis/free.c
index 0b283ee..1dfc108 100644
--- a/test/Analysis/free.c
+++ b/test/Analysis/free.c
@@ -50,7 +50,7 @@ void t10 () {
void t11 () {
char *p = (char*)__builtin_alloca(2);
- free(p); // expected-warning {{Argument to free() was allocated by alloca(), not malloc()}}
+ free(p); // expected-warning {{Memory allocated by alloca() should not be deallocated}}
}
void t12 () {
diff --git a/test/Analysis/global-region-invalidation.c b/test/Analysis/global-region-invalidation.c
index 2d64b49..77de9dd 100644
--- a/test/Analysis/global-region-invalidation.c
+++ b/test/Analysis/global-region-invalidation.c
@@ -67,15 +67,29 @@ int constIntGlob() {
return 3 / *m; // expected-warning {{Division by zero}}
}
-extern const int x;
+extern const int y;
int constIntGlobExtern() {
- if (x == 0) {
+ if (y == 0) {
foo();
- return 5 / x; // expected-warning {{Division by zero}}
+ return 5 / y; // expected-warning {{Division by zero}}
}
return 0;
}
+static void * const ptr = 0;
+void constPtrGlob() {
+ clang_analyzer_eval(ptr == 0); // expected-warning{{TRUE}}
+ foo();
+ clang_analyzer_eval(ptr == 0); // expected-warning{{TRUE}}
+}
+
+static const int x2 = x;
+void constIntGlob2() {
+ clang_analyzer_eval(x2 == 0); // expected-warning{{TRUE}}
+ foo();
+ clang_analyzer_eval(x2 == 0); // expected-warning{{TRUE}}
+}
+
void testAnalyzerEvalIsPure() {
extern int someGlobal;
if (someGlobal == 0) {
@@ -84,3 +98,27 @@ void testAnalyzerEvalIsPure() {
}
}
+// Test that static variables with initializers do not get reinitialized on
+// recursive calls.
+void Function2(void);
+int *getPtr();
+void Function1(void) {
+ static unsigned flag;
+ static int *p = 0;
+ if (!flag) {
+ flag = 1;
+ p = getPtr();
+ }
+ int m = *p; // no-warning: p is never null.
+ m++;
+ Function2();
+}
+void Function2(void) {
+ Function1();
+}
+
+void SetToNonZero(void) {
+ static int g = 5;
+ clang_analyzer_eval(g == 5); // expected-warning{{TRUE}}
+}
+
diff --git a/test/Analysis/global_region_invalidation.mm b/test/Analysis/global_region_invalidation.mm
new file mode 100644
index 0000000..f853470
--- /dev/null
+++ b/test/Analysis/global_region_invalidation.mm
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
+
+void clang_analyzer_eval(int);
+
+void use(int);
+id foo(int x) {
+ if (x)
+ return 0;
+ static id p = foo(1);
+ clang_analyzer_eval(p == 0); // expected-warning{{TRUE}}
+ return p;
+}
+
+const int &globalIntRef = 42;
+
+void testGlobalRef() {
+ // FIXME: Should be TRUE, but should at least not crash.
+ clang_analyzer_eval(globalIntRef == 42); // expected-warning{{UNKNOWN}}
+}
+
+extern int globalInt;
+extern void invalidateGlobals();
+
+void testGlobalInvalidation() {
+ if (globalInt != 42)
+ return;
+ clang_analyzer_eval(globalInt == 42); // expected-warning{{TRUE}}
+
+ invalidateGlobals();
+ clang_analyzer_eval(globalInt == 42); // expected-warning{{UNKNOWN}}
+}
+
+
+//---------------------------------
+// False negatives
+//---------------------------------
+
+void testGlobalInvalidationWithDirectBinding() {
+ globalInt = 42;
+ clang_analyzer_eval(globalInt == 42); // expected-warning{{TRUE}}
+
+ invalidateGlobals();
+ // FIXME: Should be UNKNOWN.
+ clang_analyzer_eval(globalInt == 42); // expected-warning{{TRUE}}
+}
diff --git a/test/Analysis/html-diags-multifile.c b/test/Analysis/html-diags-multifile.c
index 611dd07..6e89fae 100644
--- a/test/Analysis/html-diags-multifile.c
+++ b/test/Analysis/html-diags-multifile.c
@@ -2,7 +2,6 @@
// RUN: %clang_cc1 -analyze -analyzer-output=html -analyzer-checker=core -o %t.dir
// RUN: ls %t.dir | grep report | count 0
// RUN: rm -fR %t.dir
-// REQUIRES: shell
// This tests that we do not currently emit HTML diagnostics for reports that
// cross file boundaries.
diff --git a/test/Analysis/html-diags.c b/test/Analysis/html-diags.c
index 7c15df6..1ec4d18 100644
--- a/test/Analysis/html-diags.c
+++ b/test/Analysis/html-diags.c
@@ -1,6 +1,6 @@
+// RUN: rm -fR %T/dir
// RUN: mkdir %T/dir
// RUN: %clang_cc1 -analyze -analyzer-output=html -analyzer-checker=core -o %T/dir %s
-// RUN: rm -fR %T/dir
// Currently this test mainly checks that the HTML diagnostics doesn't crash
// when handling macros will calls with macros. We should actually validate
diff --git a/test/Analysis/initializer.cpp b/test/Analysis/initializer.cpp
index 92d581b..3f7802c 100644
--- a/test/Analysis/initializer.cpp
+++ b/test/Analysis/initializer.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-ipa=inlining -analyzer-config c++-inlining=constructors -std=c++11 -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-inlining=constructors -std=c++11 -verify %s
void clang_analyzer_eval(bool);
@@ -68,8 +68,7 @@ void testReferenceMember() {
void testReferenceMember2() {
int *p = 0;
- // FIXME: We should warn here, since we're creating the reference here.
- RefWrapper X(*p); // expected-warning@-12 {{Dereference of null pointer}}
+ RefWrapper X(*p); // expected-warning {{Forming reference to null pointer}}
}
@@ -80,3 +79,33 @@ class StringWrapper {
public:
StringWrapper(const char *input) : str(strdup(input)) {} // no-warning
};
+
+
+// PR15070 - Constructing a type containing a non-POD array mistakenly
+// tried to perform a bind instead of relying on the CXXConstructExpr,
+// which caused a cast<> failure in RegionStore.
+namespace DefaultConstructorWithCleanups {
+ class Element {
+ public:
+ int value;
+
+ class Helper {
+ public:
+ ~Helper();
+ };
+ Element(Helper h = Helper());
+ };
+ class Wrapper {
+ public:
+ Element arr[2];
+
+ Wrapper();
+ };
+
+ Wrapper::Wrapper() /* initializers synthesized */ {}
+
+ int test() {
+ Wrapper w;
+ return w.arr[0].value; // no-warning
+ }
+}
diff --git a/test/Analysis/initializers-cfg-output.cpp b/test/Analysis/initializers-cfg-output.cpp
index 8aaa94c..b62d979 100644
--- a/test/Analysis/initializers-cfg-output.cpp
+++ b/test/Analysis/initializers-cfg-output.cpp
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG %s 2>&1 | FileCheck %s
-// XPASS: *
class A {
public:
diff --git a/test/Analysis/inline-plist.c b/test/Analysis/inline-plist.c
index 999ebdb..a2dd98a 100644
--- a/test/Analysis/inline-plist.c
+++ b/test/Analysis/inline-plist.c
@@ -55,7 +55,7 @@ void bar(int *p) {
// ========================================================================== //
void test_block__capture_null() {
- int *p = 0; // expected-note{{Variable 'p' initialized to a null pointer value}}
+ int *p = 0; // expected-note{{'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')}}
}();
@@ -63,8 +63,8 @@ void test_block__capture_null() {
}
void test_block_ret() {
- 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}}
+ int *p = ^int*(){ // expected-note {{Calling anonymous block}} expected-note{{Returning to caller}} expected-note {{'p' initialized to a null pointer value}}
+ int *q = 0; // expected-note {{'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')}}
@@ -291,7 +291,7 @@ void test_block_arg() {
// CHECK-NEXT: <key>type</key><string>Division by zero</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>foo</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>7</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>7</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>18</integer>
@@ -477,7 +477,7 @@ void test_block_arg() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>has_bug</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>23</integer>
@@ -794,7 +794,7 @@ void test_block_arg() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>triggers_bug</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>33</integer>
@@ -830,9 +830,9 @@ void test_block_arg() {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -1124,9 +1124,9 @@ void test_block_arg() {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>1</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;q&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;q&apos; initialized to a null pointer value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;q&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;q&apos; initialized to a null pointer value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -1313,9 +1313,9 @@ void test_block_arg() {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -1386,7 +1386,7 @@ void test_block_arg() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_block_ret</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>70</integer>
@@ -1635,7 +1635,7 @@ void test_block_arg() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_block_blockvar</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>78</integer>
@@ -1884,7 +1884,7 @@ void test_block_arg() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_block_arg</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>86</integer>
diff --git a/test/Analysis/inline-unique-reports.c b/test/Analysis/inline-unique-reports.c
index 356ab72..9a8cd7f 100644
--- a/test/Analysis/inline-unique-reports.c
+++ b/test/Analysis/inline-unique-reports.c
@@ -172,7 +172,7 @@ void test_bug_2() {
// CHECK: <key>type</key><string>Dereference of null pointer</string>
// CHECK: <key>issue_context_kind</key><string>function</string>
// CHECK: <key>issue_context</key><string>bug</string>
-// CHECK: <key>issue_hash</key><integer>1</integer>
+// CHECK: <key>issue_hash</key><string>1</string>
// CHECK: <key>location</key>
// CHECK: <dict>
// CHECK: <key>line</key><integer>5</integer>
diff --git a/test/Analysis/inline.cpp b/test/Analysis/inline.cpp
index ddcf5d0..a16fa00 100644
--- a/test/Analysis/inline.cpp
+++ b/test/Analysis/inline.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-ipa=inlining -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config ipa=inlining -verify %s
void clang_analyzer_eval(bool);
void clang_analyzer_checkInlined(bool);
@@ -192,7 +192,7 @@ namespace Invalidation {
virtual void touchV2(int &x) const;
int test() const {
- // We were accidentally not invalidating under -analyzer-ipa=inlining
+ // We were accidentally not invalidating under inlining
// at one point for virtual methods with visible definitions.
int a, b, c, d;
touch(a);
@@ -216,7 +216,7 @@ namespace DefaultArgs {
class Secret {
public:
- static const int value = 42;
+ static const int value = 40 + 2;
int get(int i = value) {
return i;
}
@@ -225,16 +225,49 @@ namespace DefaultArgs {
void testMethod() {
Secret obj;
clang_analyzer_eval(obj.get(1) == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(obj.get() == 42); // expected-warning{{TRUE}}
+ clang_analyzer_eval(Secret::value == 42); // expected-warning{{TRUE}}
+ }
- // FIXME: Should be 'TRUE'. See PR13673 or <rdar://problem/11720796>.
- clang_analyzer_eval(obj.get() == 42); // expected-warning{{UNKNOWN}}
+ enum ABC {
+ A = 0,
+ B = 1,
+ C = 2
+ };
- // FIXME: Even if we constrain the variable, we still have a problem.
- // See PR13385 or <rdar://problem/12156507>.
- if (Secret::value != 42)
- return;
- clang_analyzer_eval(Secret::value == 42); // expected-warning{{TRUE}}
- clang_analyzer_eval(obj.get() == 42); // expected-warning{{UNKNOWN}}
+ int enumUser(ABC input = B) {
+ return static_cast<int>(input);
+ }
+
+ void testEnum() {
+ clang_analyzer_eval(enumUser(C) == 2); // expected-warning{{TRUE}}
+ clang_analyzer_eval(enumUser() == 1); // expected-warning{{TRUE}}
+ }
+
+
+ int exprUser(int input = 2 * 4) {
+ return input;
+ }
+
+ int complicatedExprUser(int input = 2 * Secret::value) {
+ return input;
+ }
+
+ void testExprs() {
+ clang_analyzer_eval(exprUser(1) == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(exprUser() == 8); // expected-warning{{TRUE}}
+
+ clang_analyzer_eval(complicatedExprUser(1) == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(complicatedExprUser() == 84); // expected-warning{{TRUE}}
+ }
+
+ int defaultReference(const int &input = 42) {
+ return input;
+ }
+
+ void testReference() {
+ clang_analyzer_eval(defaultReference(1) == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(defaultReference() == 42); // expected-warning{{TRUE}}
}
}
@@ -255,6 +288,7 @@ namespace OperatorNew {
IntWrapper *obj = new IntWrapper(42);
// should be TRUE
clang_analyzer_eval(obj->value == 42); // expected-warning{{UNKNOWN}}
+ delete obj;
}
void testPlacement() {
diff --git a/test/Analysis/inlining/DynDispatchBifurcate.m b/test/Analysis/inlining/DynDispatchBifurcate.m
index 1fffb65..ab1dfc5 100644
--- a/test/Analysis/inlining/DynDispatchBifurcate.m
+++ b/test/Analysis/inlining/DynDispatchBifurcate.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx -analyzer-ipa=dynamic-bifurcate -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx -analyzer-config ipa=dynamic-bifurcate -verify %s
#include "InlineObjCInstanceMethod.h"
diff --git a/test/Analysis/inlining/InlineObjCClassMethod.m b/test/Analysis/inlining/InlineObjCClassMethod.m
index 814d437..90ce3c0 100644
--- a/test/Analysis/inlining/InlineObjCClassMethod.m
+++ b/test/Analysis/inlining/InlineObjCClassMethod.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 -analyzer-config ipa=dynamic-bifurcate -verify %s
// Test inlining of ObjC class methods.
diff --git a/test/Analysis/inlining/ObjCDynTypePopagation.m b/test/Analysis/inlining/ObjCDynTypePopagation.m
index 4faaa2c..ccc2471 100644
--- a/test/Analysis/inlining/ObjCDynTypePopagation.m
+++ b/test/Analysis/inlining/ObjCDynTypePopagation.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=dynamic-bifurcate -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=dynamic-bifurcate -verify %s
#include "InlineObjCInstanceMethod.h"
@@ -82,3 +82,20 @@ int testDynamicClass(BOOL coin) {
return [x getZero];
return 1;
}
+
+@interface UserClass : NSObject
+- (PublicSubClass2 *) _newPublicSubClass2;
+- (int) getZero;
+- (void) callNew;
+@end
+
+@implementation UserClass
+- (PublicSubClass2 *) _newPublicSubClass2 {
+ return [[PublicSubClass2 alloc] init];
+}
+- (int) getZero { return 5; }
+- (void) callNew {
+ PublicSubClass2 *x = [self _newPublicSubClass2];
+ clang_analyzer_eval([x getZero] == 0); //expected-warning{{TRUE}}
+}
+@end \ No newline at end of file
diff --git a/test/Analysis/inlining/ObjCImproperDynamictallyDetectableCast.m b/test/Analysis/inlining/ObjCImproperDynamictallyDetectableCast.m
index 739e10f..06b271a 100644
--- a/test/Analysis/inlining/ObjCImproperDynamictallyDetectableCast.m
+++ b/test/Analysis/inlining/ObjCImproperDynamictallyDetectableCast.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=dynamic-bifurcate -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=dynamic-bifurcate -verify %s
typedef signed char BOOL;
@protocol NSObject - (BOOL)isEqual:(id)object; @end
diff --git a/test/Analysis/inlining/RetainCountExamples.m b/test/Analysis/inlining/RetainCountExamples.m
index 276ab52..41479af 100644
--- a/test/Analysis/inlining/RetainCountExamples.m
+++ b/test/Analysis/inlining/RetainCountExamples.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-ipa=dynamic-bifurcate -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -analyzer-config ipa=dynamic-bifurcate -verify %s
typedef signed char BOOL;
typedef struct objc_class *Class;
diff --git a/test/Analysis/inlining/assume-super-init-does-not-return-nil.m b/test/Analysis/inlining/assume-super-init-does-not-return-nil.m
index cda1e87..fba3e2d 100644
--- a/test/Analysis/inlining/assume-super-init-does-not-return-nil.m
+++ b/test/Analysis/inlining/assume-super-init-does-not-return-nil.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-ipa=dynamic-bifurcate -analyzer-checker=core,osx -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx -verify %s
typedef signed char BOOL;
diff --git a/test/Analysis/inlining/containers.cpp b/test/Analysis/inlining/containers.cpp
new file mode 100644
index 0000000..4500dff
--- /dev/null
+++ b/test/Analysis/inlining/containers.cpp
@@ -0,0 +1,234 @@
+// RUN: %clang_cc1 -analyze -std=c++11 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-inlining=destructors -analyzer-config c++-container-inlining=false -verify %s
+// RUN: %clang_cc1 -analyze -std=c++11 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-inlining=destructors -analyzer-config c++-container-inlining=true -DINLINE=1 -verify %s
+
+#ifndef HEADER
+
+void clang_analyzer_eval(bool);
+void clang_analyzer_checkInlined(bool);
+
+#define HEADER
+#include "containers.cpp"
+#undef HEADER
+
+void test() {
+ MySet set(0);
+
+ clang_analyzer_eval(set.isEmpty());
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#else
+ // expected-warning@-4 {{UNKNOWN}}
+#endif
+
+ clang_analyzer_eval(set.raw_begin() == set.raw_end());
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#else
+ // expected-warning@-4 {{UNKNOWN}}
+#endif
+
+ clang_analyzer_eval(set.begin().impl == set.end().impl);
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#else
+ // expected-warning@-4 {{UNKNOWN}}
+#endif
+}
+
+void testSubclass(MySetSubclass &sub) {
+ sub.useIterator(sub.begin());
+
+ MySetSubclass local;
+}
+
+void testWrappers(BeginOnlySet &w1, IteratorStructOnlySet &w2,
+ IteratorTypedefOnlySet &w3, IteratorUsingOnlySet &w4) {
+ BeginOnlySet local1;
+ IteratorStructOnlySet local2;
+ IteratorTypedefOnlySet local3;
+ IteratorUsingOnlySet local4;
+
+ clang_analyzer_eval(w1.begin().impl.impl == w1.begin().impl.impl);
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#else
+ // expected-warning@-4 {{UNKNOWN}}
+#endif
+
+ clang_analyzer_eval(w2.start().impl == w2.start().impl);
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#else
+ // expected-warning@-4 {{UNKNOWN}}
+#endif
+
+ clang_analyzer_eval(w3.start().impl == w3.start().impl);
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#else
+ // expected-warning@-4 {{UNKNOWN}}
+#endif
+
+ clang_analyzer_eval(w4.start().impl == w4.start().impl);
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#else
+ // expected-warning@-4 {{UNKNOWN}}
+#endif
+}
+
+
+#else
+
+class MySet {
+ int *storage;
+ unsigned size;
+public:
+ MySet() : storage(0), size(0) {
+ clang_analyzer_checkInlined(true);
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#endif
+ }
+
+ MySet(unsigned n) : storage(new int[n]), size(n) {
+ clang_analyzer_checkInlined(true);
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#endif
+ }
+
+ ~MySet() { delete[] storage; }
+
+ bool isEmpty() {
+ clang_analyzer_checkInlined(true); // expected-warning {{TRUE}}
+ return size == 0;
+ }
+
+ struct iterator {
+ int *impl;
+
+ iterator(int *p) : impl(p) {}
+ };
+
+ iterator begin() {
+ clang_analyzer_checkInlined(true); // expected-warning {{TRUE}}
+ return iterator(storage);
+ }
+
+ iterator end() {
+ clang_analyzer_checkInlined(true); // expected-warning {{TRUE}}
+ return iterator(storage+size);
+ }
+
+ typedef int *raw_iterator;
+
+ raw_iterator raw_begin() {
+ clang_analyzer_checkInlined(true); // expected-warning {{TRUE}}
+ return storage;
+ }
+ raw_iterator raw_end() {
+ clang_analyzer_checkInlined(true); // expected-warning {{TRUE}}
+ return storage + size;
+ }
+};
+
+class MySetSubclass : public MySet {
+public:
+ MySetSubclass() {
+ clang_analyzer_checkInlined(true);
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#endif
+ }
+
+ void useIterator(iterator i) {
+ clang_analyzer_checkInlined(true); // expected-warning {{TRUE}}
+ }
+};
+
+class BeginOnlySet {
+ MySet impl;
+public:
+ struct IterImpl {
+ MySet::iterator impl;
+ IterImpl(MySet::iterator i) : impl(i) {
+ clang_analyzer_checkInlined(true); // expected-warning {{TRUE}}
+ }
+ };
+
+ BeginOnlySet() {
+ clang_analyzer_checkInlined(true);
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#endif
+ }
+
+ typedef IterImpl wrapped_iterator;
+
+ wrapped_iterator begin() {
+ clang_analyzer_checkInlined(true); // expected-warning {{TRUE}}
+ return IterImpl(impl.begin());
+ }
+};
+
+class IteratorTypedefOnlySet {
+ MySet impl;
+public:
+
+ IteratorTypedefOnlySet() {
+ clang_analyzer_checkInlined(true);
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#endif
+ }
+
+ typedef MySet::iterator iterator;
+
+ iterator start() {
+ clang_analyzer_checkInlined(true); // expected-warning {{TRUE}}
+ return impl.begin();
+ }
+};
+
+class IteratorUsingOnlySet {
+ MySet impl;
+public:
+
+ IteratorUsingOnlySet() {
+ clang_analyzer_checkInlined(true);
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#endif
+ }
+
+ using iterator = MySet::iterator;
+
+ iterator start() {
+ clang_analyzer_checkInlined(true); // expected-warning {{TRUE}}
+ return impl.begin();
+ }
+};
+
+class IteratorStructOnlySet {
+ MySet impl;
+public:
+
+ IteratorStructOnlySet() {
+ clang_analyzer_checkInlined(true);
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#endif
+ }
+
+ struct iterator {
+ int *impl;
+ };
+
+ iterator start() {
+ clang_analyzer_checkInlined(true); // expected-warning {{TRUE}}
+ return iterator{impl.begin().impl};
+ }
+};
+
+#endif
diff --git a/test/Analysis/inlining/dyn-dispatch-bifurcate.cpp b/test/Analysis/inlining/dyn-dispatch-bifurcate.cpp
index 3771348..890e564 100644
--- a/test/Analysis/inlining/dyn-dispatch-bifurcate.cpp
+++ b/test/Analysis/inlining/dyn-dispatch-bifurcate.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=dynamic-bifurcate -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=dynamic-bifurcate -verify %s
void clang_analyzer_eval(bool);
diff --git a/test/Analysis/inlining/eager-reclamation-path-notes.c b/test/Analysis/inlining/eager-reclamation-path-notes.c
index 6c7c05a..f3e7376 100644
--- a/test/Analysis/inlining/eager-reclamation-path-notes.c
+++ b/test/Analysis/inlining/eager-reclamation-path-notes.c
@@ -17,7 +17,7 @@ int compute() {
void testSimple() {
int *p = 0;
- // expected-note@-1 {{Variable 'p' initialized to a null pointer value}}
+ // expected-note@-1 {{'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'}}
@@ -37,7 +37,7 @@ void passThrough(int *p) {
void testChainedCalls() {
int *ptr = 0;
- // expected-note@-1 {{Variable 'ptr' initialized to a null pointer value}}
+ // expected-note@-1 {{'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'}}
@@ -73,9 +73,9 @@ void testChainedCalls() {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -320,7 +320,7 @@ void testChainedCalls() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>use</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>6</integer>
@@ -356,9 +356,9 @@ void testChainedCalls() {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;ptr&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;ptr&apos; initialized to a null pointer value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;ptr&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;ptr&apos; initialized to a null pointer value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -777,7 +777,7 @@ void testChainedCalls() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>use2</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>28</integer>
diff --git a/test/Analysis/inlining/eager-reclamation-path-notes.cpp b/test/Analysis/inlining/eager-reclamation-path-notes.cpp
new file mode 100644
index 0000000..3ee9d92
--- /dev/null
+++ b/test/Analysis/inlining/eager-reclamation-path-notes.cpp
@@ -0,0 +1,419 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -analyzer-config graph-trim-interval=5 -analyzer-config suppress-null-return-paths=false -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config graph-trim-interval=5 -analyzer-config suppress-null-return-paths=false %s -o %t.plist
+// RUN: FileCheck --input-file=%t.plist %s
+
+typedef struct {
+ int getValue();
+} IntWrapper;
+
+IntWrapper *getNullWrapper() {
+ return 0;
+ // expected-note@-1 {{Returning null pointer}}
+}
+
+int memberCallBaseDisappears() {
+ // In this case, we need the lvalue-to-rvalue cast for 'ptr' to disappear,
+ // which means we need to trigger reclamation between that and the ->
+ // operator.
+ //
+ // Note that this test is EXTREMELY brittle because it's a negative test:
+ // we want to show that even if the node for the rvalue of 'ptr' disappears,
+ // we get the same results as if it doesn't. The test should never fail even
+ // if our node reclamation policy changes, but it could easily not be testing
+ // anything at that point.
+ IntWrapper *ptr = getNullWrapper();
+ // expected-note@-1 {{Calling 'getNullWrapper'}}
+ // expected-note@-2 {{Returning from 'getNullWrapper'}}
+ // expected-note@-3 {{'ptr' initialized to a null pointer value}}
+
+ // Burn some nodes to trigger reclamation.
+ int unused = 1;
+ (void)unused;
+
+ return ptr->getValue(); // expected-warning {{Called C++ object pointer is null}}
+ // expected-note@-1 {{Called C++ object pointer is null}}
+}
+
+// CHECK: <key>diagnostics</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>34</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>36</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling &apos;getNullWrapper&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;getNullWrapper&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>9</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from &apos;memberCallBaseDisappears&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;memberCallBaseDisappears&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>9</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>9</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning null pointer</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning null pointer</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>36</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning from &apos;getNullWrapper&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning from &apos;getNullWrapper&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>34</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>34</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>17</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;ptr&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;ptr&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Called C++ object pointer is null</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Called C++ object pointer is null</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Called C++ object pointer is null</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Called C++ object pointer is null</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>memberCallBaseDisappears</string>
+// CHECK-NEXT: <key>issue_hash</key><string>19</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>33</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
diff --git a/test/Analysis/inlining/false-positive-suppression.c b/test/Analysis/inlining/false-positive-suppression.c
index 20cc311..a836d9c 100644
--- a/test/Analysis/inlining/false-positive-suppression.c
+++ b/test/Analysis/inlining/false-positive-suppression.c
@@ -9,6 +9,8 @@ int *getNull() {
return 0;
}
+int* getPtr();
+
int *dynCastToInt(void *ptr) {
if (opaquePropertyCheck(ptr))
return (int *)ptr;
@@ -73,6 +75,15 @@ void testBranchReversed(void *p) {
*casted = 1; // expected-warning {{Dereference of null pointer}}
}
+void testMultipleStore(void *p) {
+ int *casted = 0;
+ casted = dynCastToInt(p);
+ *casted = 1;
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+}
+
// --------------------------
// "Suppression suppression"
@@ -182,3 +193,77 @@ void testAlwaysReturnNull(void *input) {
#endif
}
+int derefArg(int *p) {
+ return *p;
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+}
+void ternaryArg(char cond) {
+ static int x;
+ derefArg(cond ? &x : getNull());
+}
+
+int derefArgCast(char *p) {
+ return *p;
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+}
+void ternaryArgCast(char cond) {
+ static int x;
+ derefArgCast((char*)((unsigned)cond ? &x : getNull()));
+}
+
+int derefAssignment(int *p) {
+ return *p;
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+}
+
+void ternaryAssignment(char cond) {
+ static int x;
+ int *p = cond ? getNull() : getPtr();
+ derefAssignment(p);
+}
+
+int *retNull(char cond) {
+ static int x;
+ return cond ? &x : getNull();
+}
+int ternaryRetNull(char cond) {
+ int *p = retNull(cond);
+ return *p;
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+}
+
+// Test suppression of nested conditional operators.
+int testConditionalOperatorSuppress(int x) {
+ return *(x ? getNull() : getPtr());
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+}
+int testNestedConditionalOperatorSuppress(int x) {
+ return *(x ? (x ? getNull() : getPtr()) : getPtr());
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+}
+int testConditionalOperator(int x) {
+ return *(x ? 0 : getPtr()); // expected-warning {{Dereference of null pointer}}
+}
+int testNestedConditionalOperator(int x) {
+ return *(x ? (x ? 0 : getPtr()) : getPtr()); // expected-warning {{Dereference of null pointer}}
+}
+
+int testConditionalOperatorSuppressFloatCond(float x) {
+ return *(x ? getNull() : getPtr());
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+}
+
diff --git a/test/Analysis/inlining/false-positive-suppression.cpp b/test/Analysis/inlining/false-positive-suppression.cpp
new file mode 100644
index 0000000..bff6907
--- /dev/null
+++ b/test/Analysis/inlining/false-positive-suppression.cpp
@@ -0,0 +1,212 @@
+// 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
+
+namespace rdar12676053 {
+ // Delta-reduced from a preprocessed file.
+ template<class T>
+ class RefCount {
+ T *ref;
+ public:
+ T *operator->() const {
+ return ref ? ref : 0;
+ }
+ };
+
+ class string {};
+
+ class ParserInputState {
+ public:
+ string filename;
+ };
+
+ class Parser {
+ void setFilename(const string& f) {
+ inputState->filename = f;
+#ifndef SUPPRESSED
+// expected-warning@-2 {{Called C++ object pointer is null}}
+#endif
+ }
+ protected:
+ RefCount<ParserInputState> inputState;
+ };
+}
+
+
+// This is the standard placement new.
+inline void* operator new(__typeof__(sizeof(int)), void* __p) throw()
+{
+ return __p;
+}
+
+extern bool coin();
+
+class SomeClass {
+public:
+ void doSomething();
+};
+
+namespace References {
+ class Map {
+ int *&getNewBox();
+ int *firstBox;
+
+ public:
+ int *&getValue(int key) {
+ if (coin()) {
+ return firstBox;
+ } else {
+ int *&newBox = getNewBox();
+ newBox = 0;
+ return newBox;
+ }
+ }
+
+ int *&getValueIndirectly(int key) {
+ int *&valueBox = getValue(key);
+ return valueBox;
+ }
+ };
+
+ void testMap(Map &m, int i) {
+ *m.getValue(i) = 1;
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+
+ *m.getValueIndirectly(i) = 1;
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+
+ int *&box = m.getValue(i);
+ extern int *getPointer();
+ box = getPointer();
+ *box = 1; // no-warning
+
+ int *&box2 = m.getValue(i);
+ box2 = 0;
+ *box2 = 1; // expected-warning {{Dereference of null pointer}}
+ }
+
+ SomeClass *&getSomeClass() {
+ if (coin()) {
+ extern SomeClass *&opaqueClass();
+ return opaqueClass();
+ } else {
+ static SomeClass *sharedClass;
+ sharedClass = 0;
+ return sharedClass;
+ }
+ }
+
+ void testClass() {
+ getSomeClass()->doSomething();
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Called C++ object pointer is null}}
+#endif
+
+ // Separate the lvalue-to-rvalue conversion from the subsequent dereference.
+ SomeClass *object = getSomeClass();
+ object->doSomething();
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Called C++ object pointer is null}}
+#endif
+ }
+
+ SomeClass *getNull() {
+ return 0;
+ }
+
+ SomeClass &returnNullReference() {
+ SomeClass *x = getNull();
+ return *x;
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Returning null reference}}
+#endif
+ }
+}
+
+class X{
+public:
+ void get();
+};
+
+X *getNull() {
+ return 0;
+}
+
+void deref1(X *const &p) {
+ return p->get();
+ #ifndef SUPPRESSED
+ // expected-warning@-2 {{Called C++ object pointer is null}}
+ #endif
+}
+
+void test1() {
+ return deref1(getNull());
+}
+
+void deref2(X *p3) {
+ p3->get();
+ #ifndef SUPPRESSED
+ // expected-warning@-2 {{Called C++ object pointer is null}}
+ #endif
+}
+
+void pass2(X *const &p2) {
+ deref2(p2);
+}
+
+void test2() {
+ pass2(getNull());
+}
+
+void deref3(X *const &p2) {
+ X *p3 = p2;
+ p3->get();
+ #ifndef SUPPRESSED
+ // expected-warning@-2 {{Called C++ object pointer is null}}
+ #endif
+}
+
+void test3() {
+ deref3(getNull());
+}
+
+
+namespace Cleanups {
+ class NonTrivial {
+ public:
+ ~NonTrivial();
+
+ SomeClass *getNull() {
+ return 0;
+ }
+ };
+
+ void testImmediate() {
+ NonTrivial().getNull()->doSomething();
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Called C++ object pointer is null}}
+#endif
+ }
+
+ void testAssignment() {
+ SomeClass *ptr = NonTrivial().getNull();
+ ptr->doSomething();
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Called C++ object pointer is null}}
+#endif
+ }
+
+ void testArgumentHelper(SomeClass *arg) {
+ arg->doSomething();
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Called C++ object pointer is null}}
+#endif
+ }
+
+ void testArgument() {
+ testArgumentHelper(NonTrivial().getNull());
+ }
+}
diff --git a/test/Analysis/inlining/inline-defensive-checks.c b/test/Analysis/inlining/inline-defensive-checks.c
new file mode 100644
index 0000000..df3a8f2
--- /dev/null
+++ b/test/Analysis/inlining/inline-defensive-checks.c
@@ -0,0 +1,99 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config suppress-inlined-defensive-checks=true -verify %s
+
+// Perform inline defensive checks.
+void idc(int *p) {
+ if (p)
+ ;
+}
+
+int test01(int *p) {
+ if (p)
+ ;
+ return *p; // expected-warning {{Dereference of null pointer}}
+}
+
+int test02(int *p, int *x) {
+ if (p)
+ ;
+ idc(p);
+ if (x)
+ ;
+ return *p; // expected-warning {{Dereference of null pointer}}
+}
+
+int test03(int *p, int *x) {
+ idc(p);
+ if (p)
+ ;
+ return *p; // False negative
+}
+
+int deref04(int *p) {
+ return *p; // expected-warning {{Dereference of null pointer}}
+}
+
+int test04(int *p) {
+ if (p)
+ ;
+ idc(p);
+ return deref04(p);
+}
+
+int test11(int *q, int *x) {
+ int *p = q;
+ if (q)
+ ;
+ if (x)
+ ;
+ return *p; // expected-warning{{Dereference of null pointer}}
+}
+
+int test12(int *q) {
+ int *p = q;
+ idc(q);
+ return *p;
+}
+
+int test13(int *q) {
+ int *p = q;
+ idc(p);
+ return *p;
+}
+
+int test21(int *q, int *x) {
+ if (q)
+ ;
+ if (x)
+ ;
+ int *p = q;
+ return *p; // expected-warning{{Dereference of null pointer}}
+}
+
+int test22(int *q, int *x) {
+ idc(q);
+ if (x)
+ ;
+ int *p = q;
+ return *p;
+}
+
+int test23(int *q, int *x) {
+ idc(q);
+ if (x)
+ ;
+ int *p = q;
+ if (!p)
+ ;
+ return *p; // False negative
+}
+
+void use(char *p) {
+ if (!p)
+ return;
+ p[0] = 'a';
+}
+
+void test24(char *buffer) {
+ use(buffer);
+ buffer[1] = 'b';
+}
diff --git a/test/Analysis/inlining/inline-defensive-checks.cpp b/test/Analysis/inlining/inline-defensive-checks.cpp
new file mode 100644
index 0000000..37bccbd
--- /dev/null
+++ b/test/Analysis/inlining/inline-defensive-checks.cpp
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify %s
+// expected-no-diagnostics
+
+extern void __assert_fail (__const char *__assertion, __const char *__file,
+ unsigned int __line, __const char *__function)
+__attribute__ ((__noreturn__));
+#define assert(expr) \
+((expr) ? (void)(0) : __assert_fail (#expr, __FILE__, __LINE__, __func__))
+
+class ButterFly {
+private:
+ ButterFly() { }
+public:
+ int triggerderef() {
+ return 0;
+ }
+};
+ButterFly *getInP();
+class X{
+ ButterFly *p;
+ void setP(ButterFly *inP) {
+ if(inP)
+ ;
+ p = inP;
+ };
+ void subtest1() {
+ ButterFly *inP = getInP();
+ setP(inP);
+ }
+ int subtest2() {
+ int c = p->triggerderef(); // no-warning
+ return c;
+ }
+ int test() {
+ subtest1();
+ return subtest2();
+ }
+};
+
+typedef const int *Ty;
+extern
+Ty notNullArg(Ty cf) __attribute__((nonnull));
+typedef const void *CFTypeRef;
+extern Ty getTyVal();
+inline void radar13224271_callee(Ty def, Ty& result ) {
+ result = def;
+ // Clearly indicates that result cannot be 0 if def is not NULL.
+ assert( (result != 0) || (def == 0) );
+}
+void radar13224271_caller()
+{
+ Ty value;
+ radar13224271_callee(getTyVal(), value );
+ notNullArg(value); // no-warning
+} \ No newline at end of file
diff --git a/test/Analysis/inlining/inline-defensive-checks.m b/test/Analysis/inlining/inline-defensive-checks.m
new file mode 100644
index 0000000..0404ee6
--- /dev/null
+++ b/test/Analysis/inlining/inline-defensive-checks.m
@@ -0,0 +1,129 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config suppress-inlined-defensive-checks=true -verify %s
+
+typedef signed char BOOL;
+typedef struct objc_class *Class;
+typedef struct objc_object {
+ Class isa;
+} *id;
+@protocol NSObject - (BOOL)isEqual:(id)object; @end
+@interface NSObject <NSObject> {}
++(id)alloc;
++(id)new;
+-(id)init;
+-(id)autorelease;
+-(id)copy;
+- (Class)class;
+-(id)retain;
+@end
+
+// Check that inline defensive checks is triggered for null expressions
+// within CompoundLiteralExpr.
+typedef union {
+ struct dispatch_object_s *_do;
+ struct dispatch_source_s *_ds;
+} dispatch_object_t __attribute__((__transparent_union__));
+typedef struct dispatch_source_s *dispatch_source_t;
+
+extern __attribute__((visibility("default"))) __attribute__((__nonnull__)) __attribute__((__nothrow__))
+void
+dispatch_resume(dispatch_object_t object);
+
+@interface AppDelegate : NSObject {
+@protected
+ dispatch_source_t p;
+}
+@end
+@implementation AppDelegate
+- (void)updateDeleteTimer {
+ if (p != ((void*)0))
+ ;
+}
+- (void)createAndStartDeleteTimer {
+ [self updateDeleteTimer];
+ dispatch_resume(p); // no warning
+}
+@end
+
+// Test nil receiver suppression.
+// We only suppress on nil receiver if the nil value is directly causing the bug.
+@interface Foo {
+@public
+ int x;
+}
+- (Foo *)getFooPtr;
+@end
+
+Foo *retNil() {
+ return 0;
+}
+
+Foo *retInputOrNil(Foo *p) {
+ if (p)
+ return p;
+ return 0;
+}
+
+void idc(Foo *p) {
+ if (p)
+ ;
+}
+
+int testNilReceiver(Foo* fPtr) {
+ if (fPtr)
+ ;
+ // On a path where fPtr is nil, mem should be nil.
+ Foo *mem = [fPtr getFooPtr];
+ return mem->x; // expected-warning {{Access to instance variable 'x' results in a dereference of a null pointer}}
+}
+
+int suppressNilReceiverRetNullCond(Foo* fPtr) {
+ unsigned zero = 0;
+ fPtr = retInputOrNil(fPtr);
+ // On a path where fPtr is nzil, mem should be nil.
+ Foo *mem = [fPtr getFooPtr];
+ return mem->x;
+}
+
+int suppressNilReceiverRetNullCondCast(id fPtr) {
+ unsigned zero = 0;
+ fPtr = retInputOrNil(fPtr);
+ // On a path where fPtr is nzil, mem should be nil.
+ Foo *mem = ((id)([(Foo*)(fPtr) getFooPtr]));
+ return mem->x;
+}
+
+int dontSuppressNilReceiverRetNullCond(Foo* fPtr) {
+ unsigned zero = 0;
+ fPtr = retInputOrNil(fPtr);
+ // On a path where fPtr is nil, mem should be nil.
+ // The warning is not suppressed because the receiver being nil is not
+ // directly related to the value that triggers the warning.
+ Foo *mem = [fPtr getFooPtr];
+ if (!mem)
+ return 5/zero; // expected-warning {{Division by zero}}
+ return 0;
+}
+
+int dontSuppressNilReceiverRetNull(Foo* fPtr) {
+ unsigned zero = 0;
+ fPtr = retNil();
+ // On a path where fPtr is nil, mem should be nil.
+ // The warning is not suppressed because the receiver being nil is not
+ // directly related to the value that triggers the warning.
+ Foo *mem = [fPtr getFooPtr];
+ if (!mem)
+ return 5/zero; // expected-warning {{Division by zero}}
+ return 0;
+}
+
+int dontSuppressNilReceiverIDC(Foo* fPtr) {
+ unsigned zero = 0;
+ idc(fPtr);
+ // On a path where fPtr is nil, mem should be nil.
+ // The warning is not suppressed because the receiver being nil is not
+ // directly related to the value that triggers the warning.
+ Foo *mem = [fPtr getFooPtr];
+ if (!mem)
+ return 5/zero; // expected-warning {{Division by zero}}
+ return 0;
+}
diff --git a/test/Analysis/inlining/path-notes.c b/test/Analysis/inlining/path-notes.c
index 9e70802..b128aab 100644
--- a/test/Analysis/inlining/path-notes.c
+++ b/test/Analysis/inlining/path-notes.c
@@ -15,20 +15,12 @@ void testZero(int *a) {
// expected-note@-1 {{Dereference of null pointer (loaded from variable 'a')}}
}
-
-void check(int *p) {
- if (p) {
- // expected-note@-1 + {{Assuming 'p' is null}}
+void testCheck(int *a) {
+ if (a) {
+ // expected-note@-1 + {{Assuming 'a' is null}}
// expected-note@-2 + {{Taking false branch}}
- return;
+ ;
}
- return;
-}
-
-void testCheck(int *a) {
- check(a);
- // expected-note@-1 {{Calling 'check'}}
- // expected-note@-2 {{Returning from 'check'}}
*a = 1; // expected-warning{{Dereference of null pointer}}
// expected-note@-1 {{Dereference of null pointer (loaded from variable 'a')}}
}
@@ -38,10 +30,12 @@ int *getPointer();
void testInitCheck() {
int *a = getPointer();
- // expected-note@-1 {{Variable 'a' initialized here}}
- check(a);
- // expected-note@-1 {{Calling 'check'}}
- // expected-note@-2 {{Returning from 'check'}}
+ // expected-note@-1 {{'a' initialized here}}
+ if (a) {
+ // expected-note@-1 + {{Assuming 'a' is null}}
+ // expected-note@-2 + {{Taking false branch}}
+ ;
+ }
*a = 1; // expected-warning{{Dereference of null pointer}}
// expected-note@-1 {{Dereference of null pointer (loaded from variable 'a')}}
}
@@ -49,9 +43,11 @@ void testInitCheck() {
void testStoreCheck(int *a) {
a = getPointer();
// expected-note@-1 {{Value assigned to 'a'}}
- check(a);
- // expected-note@-1 {{Calling 'check'}}
- // expected-note@-2 {{Returning from 'check'}}
+ if (a) {
+ // expected-note@-1 + {{Assuming 'a' is null}}
+ // expected-note@-2 + {{Taking false branch}}
+ ;
+ }
*a = 1; // expected-warning{{Dereference of null pointer}}
// expected-note@-1 {{Dereference of null pointer (loaded from variable 'a')}}
}
@@ -59,7 +55,7 @@ void testStoreCheck(int *a) {
int *getZero() {
int *p = 0;
- // expected-note@-1 + {{Variable 'p' initialized to a null pointer value}}
+ // expected-note@-1 + {{'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')}}
@@ -83,7 +79,7 @@ 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}}
+ // expected-note@-3 {{'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')}}
}
@@ -320,7 +316,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testZero</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>14</integer>
@@ -332,49 +328,6 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>path</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>29</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>29</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>29</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Calling &apos;check&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Calling &apos;check&apos;</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testCheck&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testCheck&apos;</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
// CHECK-NEXT: <key>edges</key>
// CHECK-NEXT: <array>
@@ -383,45 +336,11 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -429,12 +348,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -446,7 +365,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -454,22 +373,22 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Assuming &apos;p&apos; is null</string>
+// CHECK-NEXT: <string>Assuming &apos;a&apos; is null</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Assuming &apos;p&apos; is null</string>
+// CHECK-NEXT: <string>Assuming &apos;a&apos; is null</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -479,75 +398,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
-// CHECK-NEXT: <key>col</key><integer>8</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>29</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>29</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>29</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Returning from &apos;check&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Returning from &apos;check&apos;</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>29</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>29</integer>
+// CHECK-NEXT: <key>line</key><integer>19</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -555,12 +411,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>32</integer>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>32</integer>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -572,7 +428,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>32</integer>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -580,12 +436,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>32</integer>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>32</integer>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -603,10 +459,10 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testCheck</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>6</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>32</integer>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -618,7 +474,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>40</integer>
+// CHECK-NEXT: <key>line</key><integer>32</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -626,12 +482,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>40</integer>
+// CHECK-NEXT: <key>line</key><integer>32</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>40</integer>
+// CHECK-NEXT: <key>line</key><integer>32</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -639,9 +495,9 @@ void testUseOfNullPointer() {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;a&apos; initialized here</string>
+// CHECK-NEXT: <string>&apos;a&apos; initialized here</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;a&apos; initialized here</string>
+// CHECK-NEXT: <string>&apos;a&apos; initialized here</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -651,12 +507,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>40</integer>
+// CHECK-NEXT: <key>line</key><integer>32</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>40</integer>
+// CHECK-NEXT: <key>line</key><integer>32</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -664,89 +520,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Calling &apos;check&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Calling &apos;check&apos;</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testInitCheck&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testInitCheck&apos;</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>34</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>34</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -762,12 +541,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>34</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>34</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -775,12 +554,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>34</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>34</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -792,7 +571,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>34</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -800,22 +579,22 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>34</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>34</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Assuming &apos;p&apos; is null</string>
+// CHECK-NEXT: <string>Assuming &apos;a&apos; is null</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Assuming &apos;p&apos; is null</string>
+// CHECK-NEXT: <string>Assuming &apos;a&apos; is null</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -825,75 +604,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>34</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
-// CHECK-NEXT: <key>col</key><integer>8</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Returning from &apos;check&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Returning from &apos;check&apos;</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
+// CHECK-NEXT: <key>line</key><integer>34</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -901,12 +617,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>45</integer>
+// CHECK-NEXT: <key>line</key><integer>39</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>45</integer>
+// CHECK-NEXT: <key>line</key><integer>39</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -918,7 +634,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>45</integer>
+// CHECK-NEXT: <key>line</key><integer>39</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -926,12 +642,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>45</integer>
+// CHECK-NEXT: <key>line</key><integer>39</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>45</integer>
+// CHECK-NEXT: <key>line</key><integer>39</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -949,10 +665,10 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testInitCheck</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>6</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>8</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>45</integer>
+// CHECK-NEXT: <key>line</key><integer>39</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -964,7 +680,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>50</integer>
+// CHECK-NEXT: <key>line</key><integer>44</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -972,12 +688,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>50</integer>
+// CHECK-NEXT: <key>line</key><integer>44</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>50</integer>
+// CHECK-NEXT: <key>line</key><integer>44</integer>
// CHECK-NEXT: <key>col</key><integer>18</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -997,12 +713,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>50</integer>
+// CHECK-NEXT: <key>line</key><integer>44</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>50</integer>
+// CHECK-NEXT: <key>line</key><integer>44</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1010,89 +726,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Calling &apos;check&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Calling &apos;check&apos;</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testStoreCheck&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testStoreCheck&apos;</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1108,12 +747,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1121,12 +760,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1138,7 +777,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1146,22 +785,22 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Assuming &apos;p&apos; is null</string>
+// CHECK-NEXT: <string>Assuming &apos;a&apos; is null</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Assuming &apos;p&apos; is null</string>
+// CHECK-NEXT: <string>Assuming &apos;a&apos; is null</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -1171,75 +810,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>20</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>25</integer>
-// CHECK-NEXT: <key>col</key><integer>8</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Returning from &apos;check&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Returning from &apos;check&apos;</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1247,12 +823,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>55</integer>
+// CHECK-NEXT: <key>line</key><integer>51</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>55</integer>
+// CHECK-NEXT: <key>line</key><integer>51</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1264,7 +840,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>55</integer>
+// CHECK-NEXT: <key>line</key><integer>51</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1272,12 +848,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>55</integer>
+// CHECK-NEXT: <key>line</key><integer>51</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>55</integer>
+// CHECK-NEXT: <key>line</key><integer>51</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1295,10 +871,10 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testStoreCheck</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>6</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>8</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>55</integer>
+// CHECK-NEXT: <key>line</key><integer>51</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1314,12 +890,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1327,12 +903,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1344,7 +920,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1352,12 +928,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1373,7 +949,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1391,12 +967,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1404,12 +980,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1421,7 +997,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1429,12 +1005,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1442,9 +1018,9 @@ void testUseOfNullPointer() {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>1</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -1454,12 +1030,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1467,12 +1043,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1484,7 +1060,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1492,12 +1068,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1513,7 +1089,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1521,12 +1097,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1546,12 +1122,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1559,12 +1135,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1580,12 +1156,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1593,12 +1169,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1610,7 +1186,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1618,12 +1194,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1641,10 +1217,10 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testReturnZero</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>69</integer>
+// CHECK-NEXT: <key>line</key><integer>65</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1660,12 +1236,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1673,12 +1249,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1690,7 +1266,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1698,12 +1274,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1719,7 +1295,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1737,12 +1313,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1750,12 +1326,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1767,7 +1343,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1775,12 +1351,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1788,9 +1364,9 @@ void testUseOfNullPointer() {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>1</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -1800,12 +1376,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1813,12 +1389,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1830,7 +1406,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1838,12 +1414,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1859,7 +1435,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1867,12 +1443,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1892,12 +1468,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1905,12 +1481,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1926,12 +1502,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1939,12 +1515,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1956,7 +1532,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1964,12 +1540,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1987,10 +1563,10 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testReturnZero2</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>76</integer>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2006,12 +1582,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2019,12 +1595,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>18</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2036,7 +1612,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2044,12 +1620,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2065,7 +1641,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2083,12 +1659,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2096,12 +1672,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2113,7 +1689,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2121,12 +1697,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2134,9 +1710,9 @@ void testUseOfNullPointer() {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>1</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -2146,12 +1722,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2159,12 +1735,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2176,7 +1752,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2184,12 +1760,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2205,7 +1781,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2213,12 +1789,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2238,12 +1814,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2251,12 +1827,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>18</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2272,12 +1848,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>18</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2285,12 +1861,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2302,7 +1878,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2310,12 +1886,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2323,9 +1899,9 @@ void testUseOfNullPointer() {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;a&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;a&apos; initialized to a null pointer value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;a&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;a&apos; initialized to a null pointer value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -2335,12 +1911,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>line</key><integer>79</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2348,12 +1924,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>87</integer>
+// CHECK-NEXT: <key>line</key><integer>83</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>87</integer>
+// CHECK-NEXT: <key>line</key><integer>83</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2365,7 +1941,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>87</integer>
+// CHECK-NEXT: <key>line</key><integer>83</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2373,12 +1949,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>87</integer>
+// CHECK-NEXT: <key>line</key><integer>83</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>87</integer>
+// CHECK-NEXT: <key>line</key><integer>83</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2396,10 +1972,10 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testInitZero</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>87</integer>
+// CHECK-NEXT: <key>line</key><integer>83</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2415,12 +1991,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2428,12 +2004,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2445,7 +2021,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2453,12 +2029,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2474,7 +2050,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2492,12 +2068,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2505,12 +2081,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2522,7 +2098,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2530,12 +2106,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2543,9 +2119,9 @@ void testUseOfNullPointer() {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>1</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -2555,12 +2131,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2568,12 +2144,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2585,7 +2161,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2593,12 +2169,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2614,7 +2190,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2622,12 +2198,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2647,12 +2223,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2660,12 +2236,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2681,12 +2257,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2694,12 +2270,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2711,7 +2287,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2719,12 +2295,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2744,12 +2320,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>92</integer>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2757,12 +2333,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>96</integer>
+// CHECK-NEXT: <key>line</key><integer>92</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>96</integer>
+// CHECK-NEXT: <key>line</key><integer>92</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2774,7 +2350,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>96</integer>
+// CHECK-NEXT: <key>line</key><integer>92</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2782,12 +2358,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>96</integer>
+// CHECK-NEXT: <key>line</key><integer>92</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>96</integer>
+// CHECK-NEXT: <key>line</key><integer>92</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2805,10 +2381,10 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testStoreZero</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>96</integer>
+// CHECK-NEXT: <key>line</key><integer>92</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2824,12 +2400,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2837,12 +2413,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2854,7 +2430,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2862,12 +2438,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2883,7 +2459,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2901,12 +2477,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2914,12 +2490,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2931,7 +2507,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2939,12 +2515,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2952,9 +2528,9 @@ void testUseOfNullPointer() {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>1</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -2964,12 +2540,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>line</key><integer>57</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2977,12 +2553,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2994,7 +2570,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3002,12 +2578,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>64</integer>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3023,7 +2599,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3031,12 +2607,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3056,12 +2632,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3069,12 +2645,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3086,7 +2662,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3094,12 +2670,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3115,7 +2691,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3123,12 +2699,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>line</key><integer>103</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3144,7 +2720,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>100</integer>
+// CHECK-NEXT: <key>line</key><integer>96</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3162,12 +2738,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>100</integer>
+// CHECK-NEXT: <key>line</key><integer>96</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>100</integer>
+// CHECK-NEXT: <key>line</key><integer>96</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3175,12 +2751,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>101</integer>
+// CHECK-NEXT: <key>line</key><integer>97</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>101</integer>
+// CHECK-NEXT: <key>line</key><integer>97</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3192,7 +2768,7 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>101</integer>
+// CHECK-NEXT: <key>line</key><integer>97</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3200,12 +2776,12 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>101</integer>
+// CHECK-NEXT: <key>line</key><integer>97</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>101</integer>
+// CHECK-NEXT: <key>line</key><integer>97</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3223,10 +2799,10 @@ void testUseOfNullPointer() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>usePointer</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>101</integer>
+// CHECK-NEXT: <key>line</key><integer>97</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
diff --git a/test/Analysis/inlining/path-notes.cpp b/test/Analysis/inlining/path-notes.cpp
new file mode 100644
index 0000000..895ee28
--- /dev/null
+++ b/test/Analysis/inlining/path-notes.cpp
@@ -0,0 +1,3711 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -analyzer-config c++-inlining=destructors -std=c++11 -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config c++-inlining=destructors -std=c++11 %s -o %t.plist
+// RUN: FileCheck --input-file=%t.plist %s
+
+class Foo {
+public:
+ static void use(int *p) {
+ *p = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'p')}}
+ // expected-note@-1 {{Dereference of null pointer (loaded from variable 'p')}}
+ }
+
+ Foo(int *p) {
+ use(p);
+ // expected-note@-1 {{Passing null pointer value via 1st parameter 'p'}}
+ // expected-note@-2 {{Calling 'Foo::use'}}
+ }
+};
+
+static int *globalPtr;
+
+class Bar {
+public:
+ ~Bar() {
+ Foo f(globalPtr);
+ // expected-note@-1 {{Passing null pointer value via 1st parameter 'p'}}
+ // expected-note@-2 {{Calling constructor for 'Foo'}}
+ }
+};
+
+void test() {
+ Bar b;
+ globalPtr = 0;
+ // expected-note@-1 {{Null pointer value stored to 'globalPtr'}}
+} // expected-note {{Calling '~Bar'}}
+
+
+void testAnonymous() {
+ class {
+ public:
+ void method(int *p) {
+ *p = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'p')}}
+ // expected-note@-1 {{Dereference of null pointer (loaded from variable 'p')}}
+ }
+ } anonymous;
+
+ anonymous.method(0);
+ // expected-note@-1 {{Passing null pointer value via 1st parameter 'p'}}
+ // expected-note@-2 {{Calling 'method'}}
+}
+
+
+// A simplified version of std::move.
+template <typename T>
+T &&move(T &obj) {
+ return static_cast<T &&>(obj);
+}
+
+
+namespace defaulted {
+ class Dereferencer {
+ public:
+ Dereferencer() {
+ *globalPtr = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'globalPtr')}}
+ // expected-note@-1 {{Dereference of null pointer (loaded from variable 'globalPtr')}}
+ }
+
+ Dereferencer(const Dereferencer &Other) {
+ *globalPtr = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'globalPtr')}}
+ // expected-note@-1 {{Dereference of null pointer (loaded from variable 'globalPtr')}}
+ }
+
+ Dereferencer(Dereferencer &&Other) {
+ *globalPtr = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'globalPtr')}}
+ // expected-note@-1 {{Dereference of null pointer (loaded from variable 'globalPtr')}}
+ }
+
+ void operator=(const Dereferencer &Other) {
+ *globalPtr = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'globalPtr')}}
+ // expected-note@-1 {{Dereference of null pointer (loaded from variable 'globalPtr')}}
+ }
+
+ void operator=(Dereferencer &&Other) {
+ *globalPtr = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'globalPtr')}}
+ // expected-note@-1 {{Dereference of null pointer (loaded from variable 'globalPtr')}}
+ }
+
+ ~Dereferencer() {
+ *globalPtr = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'globalPtr')}}
+ // expected-note@-1 {{Dereference of null pointer (loaded from variable 'globalPtr')}}
+ }
+ };
+
+ class Wrapper {
+ Dereferencer d;
+ };
+
+ class MovableWrapper {
+ Dereferencer d;
+ public:
+ MovableWrapper() = default;
+
+ MovableWrapper(MovableWrapper &&Other) = default;
+ // expected-note@-1 {{Calling move constructor for 'Dereferencer'}}
+
+ MovableWrapper &operator=(MovableWrapper &&Other) = default;
+ // expected-note@-1 {{Calling move assignment operator for 'Dereferencer'}}
+ };
+
+ void testDefaultConstruction() {
+ globalPtr = 0;
+ // expected-note@-1 {{Null pointer value stored to 'globalPtr'}}
+ Wrapper w;
+ // expected-note@-1 {{Calling implicit default constructor for 'Wrapper'}}
+ // expected-note@-2 {{Calling default constructor for 'Dereferencer'}}
+ }
+
+ void testCopyConstruction(const Wrapper &input) {
+ globalPtr = 0;
+ // expected-note@-1 {{Null pointer value stored to 'globalPtr'}}
+ Wrapper w{input};
+ // expected-note@-1 {{Calling implicit copy constructor for 'Wrapper'}}
+ // expected-note@-2 {{Calling copy constructor for 'Dereferencer'}}
+ }
+
+ void testMoveConstruction(MovableWrapper &&input) {
+ globalPtr = 0;
+ // expected-note@-1 {{Null pointer value stored to 'globalPtr'}}
+ MovableWrapper w{move(input)};
+ // expected-note@-1 {{Calling defaulted move constructor for 'MovableWrapper'}}
+ }
+
+ void testCopyAssignment(const Wrapper &input) {
+ Wrapper w;
+ globalPtr = 0;
+ // expected-note@-1 {{Null pointer value stored to 'globalPtr'}}
+ w = input;
+ // expected-note@-1 {{Calling implicit copy assignment operator for 'Wrapper'}}
+ // expected-note@-2 {{Calling copy assignment operator for 'Dereferencer'}}
+ }
+
+ void testMoveAssignment(MovableWrapper &&input) {
+ MovableWrapper w;
+ globalPtr = 0;
+ // expected-note@-1 {{Null pointer value stored to 'globalPtr'}}
+ w = move(input);
+ // expected-note@-1 {{Calling defaulted move assignment operator for 'MovableWrapper'}}
+ }
+
+ void testDestruction() {
+ Wrapper w;
+ globalPtr = 0;
+ // expected-note@-1 {{Null pointer value stored to 'globalPtr'}}
+ }
+ // expected-note@-1 {{Calling implicit destructor for 'Wrapper'}}
+ // expected-note@-2 {{Calling '~Dereferencer'}}
+}
+
+namespace ReturnZeroNote {
+ int getZero() {
+ return 0;
+ // expected-note@-1 {{Returning zero}}
+ }
+
+ const int &getZeroByRef() {
+ static int zeroVar;
+ zeroVar = 0;
+ // expected-note@-1 {{The value 0 is assigned to 'zeroVar'}}
+ return zeroVar;
+ // expected-note@-1 {{Returning zero (reference to 'zeroVar')}}
+ }
+
+ void test() {
+ int problem = 1 / getZero(); // expected-warning {{Division by zero}}
+ // expected-note@-1 {{Calling 'getZero'}}
+ // expected-note@-2 {{Returning from 'getZero'}}
+ // expected-note@-3 {{Division by zero}}
+ }
+
+ void testRef() {
+ int problem = 1 / getZeroByRef(); // expected-warning {{Division by zero}}
+ // expected-note@-1 {{Calling 'getZeroByRef'}}
+ // expected-note@-2 {{Returning from 'getZeroByRef'}}
+ // expected-note@-3 {{Division by zero}}
+ }
+}
+
+int &returnNullReference() {
+ int *x = 0;
+ // expected-note@-1 {{'x' initialized to a null pointer value}}
+ return *x; // expected-warning{{Returning null reference}}
+ // expected-note@-1 {{Returning null reference}}
+}
+
+struct FooWithInitializer {
+ int *ptr;
+ FooWithInitializer(int *p) : ptr(p) { // expected-note {{Null pointer value stored to 'f.ptr'}}
+ *ptr = 1; // expected-note {{Dereference of null pointer (loaded from field 'ptr')}}
+ // expected-warning@-1 {{Dereference of null pointer (loaded from field 'ptr')}}
+ }
+};
+
+void testPathNoteOnInitializer() {
+ int *p = 0; // expected-note {{'p' initialized to a null pointer value}}
+
+ FooWithInitializer f(p); // expected-note {{Passing null pointer value via 1st parameter 'p'}}
+ // expected-note@-1 {{Calling constructor for 'FooWithInitializer'}}
+}
+
+// CHECK: <key>diagnostics</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>31</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>32</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>32</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>32</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>32</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>32</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;globalPtr&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;globalPtr&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>32</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>32</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>34</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>34</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>34</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling &apos;~Bar&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;~Bar&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>23</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from &apos;test&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;test&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>23</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>23</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Passing null pointer value via 1st parameter &apos;p&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Passing null pointer value via 1st parameter &apos;p&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>24</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling constructor for &apos;Foo&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling constructor for &apos;Foo&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>12</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from &apos;~Bar&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;~Bar&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>12</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>12</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>13</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>13</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>13</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>13</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>13</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>13</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>13</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>13</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>13</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Passing null pointer value via 1st parameter &apos;p&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Passing null pointer value via 1st parameter &apos;p&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>13</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>13</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>13</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling &apos;Foo::use&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;Foo::use&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>7</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>3</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from constructor for &apos;Foo&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from constructor for &apos;Foo&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>7</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>7</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>8</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>8</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>8</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>8</integer>
+// CHECK-NEXT: <key>col</key><integer>6</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>8</integer>
+// CHECK-NEXT: <key>col</key><integer>6</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>3</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>C++ method</string>
+// CHECK-NEXT: <key>issue_context</key><string>use</string>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>8</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>38</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>38</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>44</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>44</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>44</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>44</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Passing null pointer value via 1st parameter &apos;p&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Passing null pointer value via 1st parameter &apos;p&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>46</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling &apos;method&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;method&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>40</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testAnonymous&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testAnonymous&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>40</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>40</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>C++ method</string>
+// CHECK-NEXT: <key>issue_context</key><string>method</string>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>110</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>110</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>110</integer>
+// CHECK-NEXT: <key>col</key><integer>17</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;globalPtr&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;globalPtr&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>110</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>110</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>112</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>112</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>112</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>112</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>112</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling implicit default constructor for &apos;Wrapper&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling implicit default constructor for &apos;Wrapper&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>112</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>112</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>112</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling default constructor for &apos;Dereferencer&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling default constructor for &apos;Dereferencer&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>62</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from default constructor for &apos;Wrapper&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from default constructor for &apos;Wrapper&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>62</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>62</integer>
+// CHECK-NEXT: <key>col</key><integer>16</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>63</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>63</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>63</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>63</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>63</integer>
+// CHECK-NEXT: <key>col</key><integer>16</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;globalPtr&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;globalPtr&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;globalPtr&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>63</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>118</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>118</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>118</integer>
+// CHECK-NEXT: <key>col</key><integer>17</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;globalPtr&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;globalPtr&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>118</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>118</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>120</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>120</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>120</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>120</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>120</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling implicit copy constructor for &apos;Wrapper&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling implicit copy constructor for &apos;Wrapper&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>120</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>120</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>120</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling copy constructor for &apos;Dereferencer&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling copy constructor for &apos;Dereferencer&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>67</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from copy constructor for &apos;Wrapper&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from copy constructor for &apos;Wrapper&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>67</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>67</integer>
+// CHECK-NEXT: <key>col</key><integer>16</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>68</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>68</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>68</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>68</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>68</integer>
+// CHECK-NEXT: <key>col</key><integer>16</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;globalPtr&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;globalPtr&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;globalPtr&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>68</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>126</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>126</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>126</integer>
+// CHECK-NEXT: <key>col</key><integer>17</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;globalPtr&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;globalPtr&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>126</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>126</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>128</integer>
+// CHECK-NEXT: <key>col</key><integer>22</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>128</integer>
+// CHECK-NEXT: <key>col</key><integer>25</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>128</integer>
+// CHECK-NEXT: <key>col</key><integer>22</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>128</integer>
+// CHECK-NEXT: <key>col</key><integer>25</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>128</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>128</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>128</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>128</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>128</integer>
+// CHECK-NEXT: <key>col</key><integer>32</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling defaulted move constructor for &apos;MovableWrapper&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling defaulted move constructor for &apos;MovableWrapper&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>102</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>102</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>102</integer>
+// CHECK-NEXT: <key>col</key><integer>18</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling move constructor for &apos;Dereferencer&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling move constructor for &apos;Dereferencer&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from move constructor for &apos;MovableWrapper&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from move constructor for &apos;MovableWrapper&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>72</integer>
+// CHECK-NEXT: <key>col</key><integer>16</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>73</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>73</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>73</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>73</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>73</integer>
+// CHECK-NEXT: <key>col</key><integer>16</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;globalPtr&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;globalPtr&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;globalPtr&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>73</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>133</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>133</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>133</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>133</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>133</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>133</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>134</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>134</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>134</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>134</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>134</integer>
+// CHECK-NEXT: <key>col</key><integer>17</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;globalPtr&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;globalPtr&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>134</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>134</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>136</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>136</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>136</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>136</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>136</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling implicit copy assignment operator for &apos;Wrapper&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling implicit copy assignment operator for &apos;Wrapper&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>136</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>136</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>136</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling copy assignment operator for &apos;Dereferencer&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling copy assignment operator for &apos;Dereferencer&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>77</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from copy assignment operator for &apos;Wrapper&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from copy assignment operator for &apos;Wrapper&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>77</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>77</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>78</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>78</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>78</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>78</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>78</integer>
+// CHECK-NEXT: <key>col</key><integer>16</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;globalPtr&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;globalPtr&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;globalPtr&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>C++ method</string>
+// CHECK-NEXT: <key>issue_context</key><string>operator=</string>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>78</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>142</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>142</integer>
+// CHECK-NEXT: <key>col</key><integer>18</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>142</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>142</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>142</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>142</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>143</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>143</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>143</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>143</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>143</integer>
+// CHECK-NEXT: <key>col</key><integer>17</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;globalPtr&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;globalPtr&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>143</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>143</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>145</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>145</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>145</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>145</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>145</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>145</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>145</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>145</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>145</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling defaulted move assignment operator for &apos;MovableWrapper&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling defaulted move assignment operator for &apos;MovableWrapper&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>105</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>105</integer>
+// CHECK-NEXT: <key>col</key><integer>18</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>105</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>105</integer>
+// CHECK-NEXT: <key>col</key><integer>28</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>105</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>105</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>105</integer>
+// CHECK-NEXT: <key>col</key><integer>28</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling move assignment operator for &apos;Dereferencer&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling move assignment operator for &apos;Dereferencer&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>82</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from move assignment operator for &apos;MovableWrapper&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from move assignment operator for &apos;MovableWrapper&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>82</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>82</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>col</key><integer>16</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;globalPtr&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;globalPtr&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;globalPtr&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>C++ method</string>
+// CHECK-NEXT: <key>issue_context</key><string>operator=</string>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>83</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>150</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>150</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>150</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>150</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>150</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>150</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>151</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>151</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>151</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>151</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>151</integer>
+// CHECK-NEXT: <key>col</key><integer>17</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;globalPtr&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;globalPtr&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>151</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>151</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>153</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>153</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>153</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling implicit destructor for &apos;Wrapper&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling implicit destructor for &apos;Wrapper&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>153</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling &apos;~Dereferencer&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;~Dereferencer&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>87</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from destructor for &apos;Wrapper&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from destructor for &apos;Wrapper&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>87</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>87</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
+// CHECK-NEXT: <key>col</key><integer>16</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;globalPtr&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;globalPtr&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;globalPtr&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>88</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>29</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>31</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling &apos;getZero&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;getZero&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>159</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from &apos;test&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;test&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>159</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>159</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>160</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>160</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>160</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>160</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>160</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning zero</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning zero</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>31</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning from &apos;getZero&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning from &apos;getZero&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>29</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>29</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>31</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Division by zero</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Division by zero</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Division by zero</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Division by zero</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test</string>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>173</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>34</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>36</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling &apos;getZeroByRef&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;getZeroByRef&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>164</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testRef&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testRef&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>164</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>164</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>165</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>165</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>165</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>165</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>166</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>166</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>166</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>166</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>166</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>The value 0 is assigned to &apos;zeroVar&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>The value 0 is assigned to &apos;zeroVar&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>166</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>166</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>168</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>168</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>168</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>168</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>168</integer>
+// CHECK-NEXT: <key>col</key><integer>18</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning zero (reference to &apos;zeroVar&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning zero (reference to &apos;zeroVar&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>36</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning from &apos;getZeroByRef&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning from &apos;getZeroByRef&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>34</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>34</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>36</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Division by zero</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Division by zero</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Division by zero</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Division by zero</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>testRef</string>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>180</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>188</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>188</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>188</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;x&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;x&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>188</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>188</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>190</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>190</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>190</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>190</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>190</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning null reference</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning null reference</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Returning null reference</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Returning null reference</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>returnNullReference</string>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>190</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>203</integer>
+// CHECK-NEXT: <key>col</key><integer>2</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>203</integer>
+// CHECK-NEXT: <key>col</key><integer>2</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>203</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>203</integer>
+// CHECK-NEXT: <key>col</key><integer>2</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>203</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>205</integer>
+// CHECK-NEXT: <key>col</key><integer>2</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>205</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>205</integer>
+// CHECK-NEXT: <key>col</key><integer>2</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>205</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>205</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>205</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>205</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>205</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>205</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Passing null pointer value via 1st parameter &apos;p&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Passing null pointer value via 1st parameter &apos;p&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>205</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>205</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>205</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>205</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>205</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>205</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>205</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling constructor for &apos;FooWithInitializer&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling constructor for &apos;FooWithInitializer&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>196</integer>
+// CHECK-NEXT: <key>col</key><integer>2</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testPathNoteOnInitializer&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testPathNoteOnInitializer&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>196</integer>
+// CHECK-NEXT: <key>col</key><integer>2</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>196</integer>
+// CHECK-NEXT: <key>col</key><integer>19</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>196</integer>
+// CHECK-NEXT: <key>col</key><integer>35</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>196</integer>
+// CHECK-NEXT: <key>col</key><integer>35</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>196</integer>
+// CHECK-NEXT: <key>col</key><integer>35</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>196</integer>
+// CHECK-NEXT: <key>col</key><integer>35</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>196</integer>
+// CHECK-NEXT: <key>col</key><integer>31</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>196</integer>
+// CHECK-NEXT: <key>col</key><integer>33</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>196</integer>
+// CHECK-NEXT: <key>col</key><integer>31</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;f.ptr&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;f.ptr&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>196</integer>
+// CHECK-NEXT: <key>col</key><integer>31</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>196</integer>
+// CHECK-NEXT: <key>col</key><integer>33</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>197</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>197</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>197</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>197</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>197</integer>
+// CHECK-NEXT: <key>col</key><integer>6</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from field &apos;ptr&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from field &apos;ptr&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from field &apos;ptr&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>197</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
diff --git a/test/Analysis/inlining/path-notes.m b/test/Analysis/inlining/path-notes.m
index b15b869..f3a7b6c 100644
--- a/test/Analysis/inlining/path-notes.m
+++ b/test/Analysis/inlining/path-notes.m
@@ -1,7 +1,12 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -analyzer-config suppress-null-return-paths=false -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config suppress-null-return-paths=false %s -o %t.plist
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -analyzer-config suppress-null-return-paths=false -fblocks -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config suppress-null-return-paths=false -fblocks %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
+typedef struct dispatch_queue_s *dispatch_queue_t;
+typedef void (^dispatch_block_t)(void);
+void dispatch_sync(dispatch_queue_t, dispatch_block_t);
+
+
@interface Test
@property int *p;
@end
@@ -21,6 +26,45 @@ void testReturnZeroIfNil() {
}
+int testDispatchSyncInlining() {
+ extern dispatch_queue_t globalQueue;
+
+ __block int x;
+
+ // expected-note@+2 {{Calling 'dispatch_sync'}}
+ // expected-note@+1 {{Returning from 'dispatch_sync'}}
+ dispatch_sync(globalQueue, ^{
+ // expected-note@7 {{Calling anonymous block}}
+ x = 0;
+ // expected-note@-1 {{The value 0 is assigned to 'x'}}
+ // expected-note@7 {{Returning to caller}}
+ });
+
+ return 1 / x; // expected-warning{{Division by zero}}
+ // expected-note@-1 {{Division by zero}}
+}
+
+int testDispatchSyncInliningNoPruning(int coin) {
+ // This tests exactly the same case as above, except on a bug report where
+ // path pruning is disabled (an uninitialized variable capture).
+ // In this case
+ extern dispatch_queue_t globalQueue;
+
+ __block int y;
+
+ // expected-note@+1 {{Calling 'dispatch_sync'}}
+ dispatch_sync(globalQueue, ^{
+ // expected-note@7 {{Calling anonymous block}}
+ int x;
+ // expected-note@-1 {{'x' declared without an initial value}}
+ ^{ y = x; }(); // expected-warning{{Variable 'x' is uninitialized when captured by block}}
+ // expected-note@-1 {{'x' is uninitialized when captured by block}}
+ });
+
+ return y;
+}
+
+
// CHECK: <key>diagnostics</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
@@ -34,12 +78,12 @@ void testReturnZeroIfNil() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -47,12 +91,12 @@ void testReturnZeroIfNil() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -64,7 +108,7 @@ void testReturnZeroIfNil() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -72,12 +116,12 @@ void testReturnZeroIfNil() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -97,12 +141,12 @@ void testReturnZeroIfNil() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -110,12 +154,12 @@ void testReturnZeroIfNil() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -127,7 +171,7 @@ void testReturnZeroIfNil() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -135,12 +179,12 @@ void testReturnZeroIfNil() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>18</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -156,7 +200,7 @@ void testReturnZeroIfNil() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>9</integer>
+// CHECK-NEXT: <key>line</key><integer>14</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -174,12 +218,12 @@ void testReturnZeroIfNil() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>9</integer>
+// CHECK-NEXT: <key>line</key><integer>14</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>9</integer>
+// CHECK-NEXT: <key>line</key><integer>14</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -187,12 +231,12 @@ void testReturnZeroIfNil() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>line</key><integer>15</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>line</key><integer>15</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -208,12 +252,12 @@ void testReturnZeroIfNil() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>line</key><integer>15</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>line</key><integer>15</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -221,12 +265,12 @@ void testReturnZeroIfNil() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>line</key><integer>15</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>line</key><integer>15</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -238,7 +282,7 @@ void testReturnZeroIfNil() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>line</key><integer>15</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -246,12 +290,12 @@ void testReturnZeroIfNil() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>line</key><integer>15</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>line</key><integer>15</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -271,12 +315,12 @@ void testReturnZeroIfNil() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>line</key><integer>15</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>line</key><integer>15</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -284,12 +328,12 @@ void testReturnZeroIfNil() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>line</key><integer>15</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>line</key><integer>15</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -301,7 +345,7 @@ void testReturnZeroIfNil() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>line</key><integer>15</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -309,12 +353,12 @@ void testReturnZeroIfNil() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>line</key><integer>15</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
+// CHECK-NEXT: <key>line</key><integer>15</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -330,7 +374,7 @@ void testReturnZeroIfNil() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -338,12 +382,12 @@ void testReturnZeroIfNil() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>18</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -363,12 +407,12 @@ void testReturnZeroIfNil() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -376,12 +420,12 @@ void testReturnZeroIfNil() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -397,12 +441,12 @@ void testReturnZeroIfNil() {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -410,12 +454,12 @@ void testReturnZeroIfNil() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -427,7 +471,7 @@ void testReturnZeroIfNil() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -435,12 +479,12 @@ void testReturnZeroIfNil() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -458,12 +502,582 @@ void testReturnZeroIfNil() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testReturnZeroIfNil</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>30</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>30</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>36</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>36</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>36</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>36</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling &apos;dispatch_sync&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;dispatch_sync&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>7</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testDispatchSyncInlining&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testDispatchSyncInlining&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>7</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling anonymous block</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling anonymous block</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>36</integer>
+// CHECK-NEXT: <key>col</key><integer>30</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from &apos;dispatch_sync&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;dispatch_sync&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>36</integer>
+// CHECK-NEXT: <key>col</key><integer>30</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>36</integer>
+// CHECK-NEXT: <key>col</key><integer>30</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>38</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>38</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>38</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>38</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>38</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>The value 0 is assigned to &apos;x&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>The value 0 is assigned to &apos;x&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>7</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning to caller</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning to caller</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>36</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>36</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning from &apos;dispatch_sync&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning from &apos;dispatch_sync&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>36</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>36</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>43</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>43</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>43</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>43</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>43</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>43</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>43</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>43</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>43</integer>
+// CHECK-NEXT: <key>col</key><integer>14</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Division by zero</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Division by zero</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Division by zero</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Division by zero</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>testDispatchSyncInlining</string>
+// CHECK-NEXT: <key>issue_hash</key><string>14</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>43</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>51</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>51</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>62</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling &apos;dispatch_sync&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;dispatch_sync&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>7</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testDispatchSyncInliningNoPruning&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testDispatchSyncInliningNoPruning&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>7</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling anonymous block</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling anonymous block</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
+// CHECK-NEXT: <key>col</key><integer>30</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from &apos;dispatch_sync&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;dispatch_sync&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
+// CHECK-NEXT: <key>col</key><integer>30</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>56</integer>
+// CHECK-NEXT: <key>col</key><integer>30</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>58</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>58</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>58</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>58</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>58</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;x&apos; declared without an initial value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;x&apos; declared without an initial value</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>58</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>58</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>2</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Variable &apos;x&apos; is uninitialized when captured by block</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Variable &apos;x&apos; is uninitialized when captured by block</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Variable &apos;x&apos; is uninitialized when captured by block</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>uninitialized variable captured by block</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
diff --git a/test/Analysis/inlining/retain-count-self-init.m b/test/Analysis/inlining/retain-count-self-init.m
index ee8dbe3..97379db 100644
--- a/test/Analysis/inlining/retain-count-self-init.m
+++ b/test/Analysis/inlining/retain-count-self-init.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,osx.cocoa.SelfInit -analyzer-ipa=dynamic-bifurcate -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,osx.cocoa.SelfInit -analyzer-config ipa=dynamic-bifurcate -verify %s
typedef signed char BOOL;
typedef struct objc_class *Class;
diff --git a/test/Analysis/inlining/stl.cpp b/test/Analysis/inlining/stl.cpp
index cec7821..6053daa 100644
--- a/test/Analysis/inlining/stl.cpp
+++ b/test/Analysis/inlining/stl.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-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
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-container-inlining=true -analyzer-config c++-stdlib-inlining=false -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-container-inlining=true -analyzer-config c++-stdlib-inlining=true -DINLINE=1 -verify %s
#include "../Inputs/system-header-simulator-cxx.h"
diff --git a/test/Analysis/inlining/test_objc_inlining_option.m b/test/Analysis/inlining/test_objc_inlining_option.m
index 34502c4..61408c1 100644
--- a/test/Analysis/inlining/test_objc_inlining_option.m
+++ b/test/Analysis/inlining/test_objc_inlining_option.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=dynamic-bifurcate -analyzer-config objc-inlining=false -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config ipa=dynamic-bifurcate -analyzer-config objc-inlining=false -verify %s
// expected-no-diagnostics
typedef signed char BOOL;
diff --git a/test/Analysis/keychainAPI.m b/test/Analysis/keychainAPI.m
index fe6c61d..4fc48c0 100644
--- a/test/Analysis/keychainAPI.m
+++ b/test/Analysis/keychainAPI.m
@@ -76,9 +76,9 @@ void errRetVal() {
UInt32 length;
void *outData;
st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);
- if (st == GenericError) // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeContent'}}
+ if (st == GenericError)
SecKeychainItemFreeContent(ptr, outData); // expected-warning{{Only call free if a valid (non-NULL) buffer was returned}}
-}
+} // expected-warning{{Allocated data is not released: missing a call to 'SecKeychainItemFreeContent'}}
// If null is passed in, the data is not allocated, so no need for the matching free.
void fooDoNotReportNull() {
@@ -305,6 +305,25 @@ void DellocWithCFStringCreate4(CFAllocatorRef alloc) {
}
}
+static CFAllocatorRef gKeychainDeallocator = 0;
+
+static CFAllocatorRef GetKeychainDeallocator() {
+ return gKeychainDeallocator;
+}
+
+CFStringRef DellocWithCFStringCreate5(CFAllocatorRef alloc) {
+ unsigned int *ptr = 0;
+ OSStatus st = 0;
+ UInt32 length;
+ void *bytes;
+ char * x;
+ st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &bytes);
+ if (st == noErr) {
+ return CFStringCreateWithBytesNoCopy(alloc, bytes, length, 5, 0, GetKeychainDeallocator()); // no-warning
+ }
+ return 0;
+}
+
void radar10508828() {
UInt32 pwdLen = 0;
void* pwdBytes = 0;
diff --git a/test/Analysis/malloc-annotations.c b/test/Analysis/malloc-annotations.c
index 2a078b6..3a260c3 100644
--- a/test/Analysis/malloc-annotations.c
+++ b/test/Analysis/malloc-annotations.c
@@ -63,8 +63,8 @@ void af1() {
}
void af1_b() {
- int *p = my_malloc(12); // expected-warning{{Memory is never released; potential leak}}
-}
+ int *p = my_malloc(12);
+} // expected-warning{{Memory is never released; potential leak}}
void af1_c() {
myglobalpointer = my_malloc(12); // no-warning
@@ -72,8 +72,8 @@ void af1_c() {
void af1_d() {
struct stuff mystuff;
- mystuff.somefield = my_malloc(12); // expected-warning{{Memory is never released; potential leak}}
-}
+ mystuff.somefield = my_malloc(12);
+} // expected-warning{{Memory is never released; potential leak}}
// Test that we can pass out allocated memory via pointer-to-pointer.
void af1_e(void **pp) {
diff --git a/test/Analysis/malloc-interprocedural.c b/test/Analysis/malloc-interprocedural.c
index 79cbf24..3c7bab6 100644
--- a/test/Analysis/malloc-interprocedural.c
+++ b/test/Analysis/malloc-interprocedural.c
@@ -31,8 +31,8 @@ static void my_free1(void *p) {
static void test1() {
void *data = 0;
- my_malloc1(&data, 4); // expected-warning {{Memory is never released; potential leak of memory pointed to by 'data'}}
-}
+ my_malloc1(&data, 4);
+} // expected-warning {{Memory is never released; potential leak of memory pointed to by 'data'}}
static void test11() {
void *data = 0;
@@ -44,8 +44,8 @@ static void testUniqueingByallocationSiteInTopLevelFunction() {
void *data = my_malloc2(1, 4);
data = 0;
int x = 5;// expected-warning {{Memory is never released; potential leak of memory pointed to by 'data'}}
- data = my_malloc2(1, 4);// expected-warning {{Memory is never released; potential leak of memory pointed to by 'data'}}
-}
+ data = my_malloc2(1, 4);
+} // expected-warning {{Memory is never released; potential leak of memory pointed to by 'data'}}
static void test3() {
void *data = my_malloc2(1, 4);
@@ -122,10 +122,14 @@ char *strndup(const char *str, size_t n) {
}
void useStrndup(size_t n) {
- if (n == 0)
+ if (n == 0) {
(void)strndup(0, 20); // no-warning
- else if (n < 5)
+ return;
+ } else if (n < 5) {
(void)strndup("hi there", n); // no-warning
- else
- (void)strndup("hi there", n); // expected-warning{{leak}}
+ return;
+ } else {
+ (void)strndup("hi there", n);
+ return; // expected-warning{{leak}}
+ }
}
diff --git a/test/Analysis/malloc-plist.c b/test/Analysis/malloc-plist.c
index 12430a6..ddd09db 100644
--- a/test/Analysis/malloc-plist.c
+++ b/test/Analysis/malloc-plist.c
@@ -235,7 +235,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Assuming &apos;in&apos; is &gt; 5</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Assuming &apos;in&apos; is &gt; 5</string>
+// CHECK-NEXT: <string>Assuming &apos;in&apos; is &gt; 5</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -332,7 +332,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is allocated</string>
+// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -380,7 +380,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;p&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;p&apos;</string>
+// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;p&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;p&apos;</string>
@@ -388,7 +388,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>diagnosticTest</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>15</integer>
@@ -494,7 +494,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is allocated</string>
+// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -542,7 +542,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;A&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;A&apos;</string>
+// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;A&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;A&apos;</string>
@@ -550,7 +550,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>myArrayAllocation</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>22</integer>
@@ -622,7 +622,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is allocated</string>
+// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -719,7 +719,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Attempt to reallocate memory</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Attempt to reallocate memory</string>
+// CHECK-NEXT: <string>Attempt to reallocate memory</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -816,7 +816,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Assuming &apos;tmp&apos; is null</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Assuming &apos;tmp&apos; is null</string>
+// CHECK-NEXT: <string>Assuming &apos;tmp&apos; is null</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -879,7 +879,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Reallocation failed</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Reallocation failed</string>
+// CHECK-NEXT: <string>Reallocation failed</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -927,7 +927,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
+// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
@@ -935,7 +935,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>reallocDiagnostics</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>29</integer>
@@ -1007,7 +1007,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Calling &apos;wrapper&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Calling &apos;wrapper&apos;</string>
+// CHECK-NEXT: <string>Calling &apos;wrapper&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>event</string>
@@ -1021,7 +1021,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Entered call from &apos;test_wrapper&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;test_wrapper&apos;</string>
+// CHECK-NEXT: <string>Entered call from &apos;test_wrapper&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -1118,7 +1118,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is allocated</string>
+// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -1215,7 +1215,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Assuming &apos;x&apos; is non-null</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Assuming &apos;x&apos; is non-null</string>
+// CHECK-NEXT: <string>Assuming &apos;x&apos; is non-null</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -1278,7 +1278,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Returned allocated memory</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Returned allocated memory</string>
+// CHECK-NEXT: <string>Returned allocated memory</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -1326,7 +1326,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
+// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
@@ -1334,7 +1334,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_wrapper</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>46</integer>
@@ -1406,7 +1406,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Calling &apos;my_malloc_and_free&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Calling &apos;my_malloc_and_free&apos;</string>
+// CHECK-NEXT: <string>Calling &apos;my_malloc_and_free&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>event</string>
@@ -1420,7 +1420,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Entered call from &apos;test_double_action_call&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;test_double_action_call&apos;</string>
+// CHECK-NEXT: <string>Entered call from &apos;test_double_action_call&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -1517,7 +1517,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is allocated</string>
+// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -1614,7 +1614,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Calling &apos;my_free&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Calling &apos;my_free&apos;</string>
+// CHECK-NEXT: <string>Calling &apos;my_free&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>event</string>
@@ -1628,7 +1628,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Entered call from &apos;my_malloc_and_free&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;my_malloc_and_free&apos;</string>
+// CHECK-NEXT: <string>Entered call from &apos;my_malloc_and_free&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -1691,7 +1691,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is released</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is released</string>
+// CHECK-NEXT: <string>Memory is released</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>event</string>
@@ -1720,7 +1720,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Returned released memory via 1st parameter</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Returned released memory via 1st parameter</string>
+// CHECK-NEXT: <string>Returned released memory via 1st parameter</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -1783,7 +1783,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Returned released memory via 1st parameter</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Returned released memory via 1st parameter</string>
+// CHECK-NEXT: <string>Returned released memory via 1st parameter</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -1846,7 +1846,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Use of memory after it is freed</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Use of memory after it is freed</string>
+// CHECK-NEXT: <string>Use of memory after it is freed</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Use of memory after it is freed</string>
@@ -1854,7 +1854,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>type</key><string>Use-after-free</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_double_action_call</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>62</integer>
@@ -1926,7 +1926,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is allocated</string>
+// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -1989,7 +1989,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Calling &apos;my_realloc&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Calling &apos;my_realloc&apos;</string>
+// CHECK-NEXT: <string>Calling &apos;my_realloc&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>event</string>
@@ -2003,7 +2003,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Entered call from &apos;reallocIntra&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;reallocIntra&apos;</string>
+// CHECK-NEXT: <string>Entered call from &apos;reallocIntra&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -2134,7 +2134,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Attempt to reallocate memory</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Attempt to reallocate memory</string>
+// CHECK-NEXT: <string>Attempt to reallocate memory</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -2231,7 +2231,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Assuming &apos;tmp&apos; is null</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Assuming &apos;tmp&apos; is null</string>
+// CHECK-NEXT: <string>Assuming &apos;tmp&apos; is null</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -2294,7 +2294,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Reallocation failed</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Reallocation failed</string>
+// CHECK-NEXT: <string>Reallocation failed</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -2357,7 +2357,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Reallocation of 1st parameter failed</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Reallocation of 1st parameter failed</string>
+// CHECK-NEXT: <string>Reallocation of 1st parameter failed</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -2405,7 +2405,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
+// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;buf&apos;</string>
@@ -2413,7 +2413,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>reallocIntra</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>77</integer>
@@ -2485,7 +2485,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Calling &apos;malloc_wrapper_ret&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Calling &apos;malloc_wrapper_ret&apos;</string>
+// CHECK-NEXT: <string>Calling &apos;malloc_wrapper_ret&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>event</string>
@@ -2499,7 +2499,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Entered call from &apos;use_ret&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;use_ret&apos;</string>
+// CHECK-NEXT: <string>Entered call from &apos;use_ret&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -2596,7 +2596,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is allocated</string>
+// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>event</string>
@@ -2625,7 +2625,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Returned allocated memory</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Returned allocated memory</string>
+// CHECK-NEXT: <string>Returned allocated memory</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -2673,7 +2673,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;v&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;v&apos;</string>
+// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;v&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;v&apos;</string>
@@ -2681,7 +2681,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>use_ret</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>87</integer>
@@ -2787,7 +2787,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is allocated</string>
+// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -2835,7 +2835,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;m&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;m&apos;</string>
+// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;m&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;m&apos;</string>
@@ -2843,7 +2843,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>LeakedSymbol</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>8</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>98</integer>
@@ -2881,7 +2881,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Calling &apos;function_with_leak1&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Calling &apos;function_with_leak1&apos;</string>
+// CHECK-NEXT: <string>Calling &apos;function_with_leak1&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>event</string>
@@ -2895,7 +2895,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Entered call from &apos;use_function_with_leak1&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;use_function_with_leak1&apos;</string>
+// CHECK-NEXT: <string>Entered call from &apos;use_function_with_leak1&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -2992,7 +2992,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is allocated</string>
+// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -3015,13 +3015,13 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>103</integer>
-// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>line</key><integer>104</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>103</integer>
-// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>line</key><integer>104</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
@@ -3032,15 +3032,15 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>103</integer>
-// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>line</key><integer>104</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <key>depth</key><integer>1</integer>
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
+// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
@@ -3048,11 +3048,11 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>function_with_leak1</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>103</integer>
-// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>line</key><integer>104</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </dict>
@@ -3086,7 +3086,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Calling &apos;function_with_leak2&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Calling &apos;function_with_leak2&apos;</string>
+// CHECK-NEXT: <string>Calling &apos;function_with_leak2&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>event</string>
@@ -3100,7 +3100,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Entered call from &apos;use_function_with_leak2&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;use_function_with_leak2&apos;</string>
+// CHECK-NEXT: <string>Entered call from &apos;use_function_with_leak2&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -3197,7 +3197,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is allocated</string>
+// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -3245,7 +3245,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
+// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
@@ -3253,7 +3253,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>function_with_leak2</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>112</integer>
@@ -3291,7 +3291,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Calling &apos;function_with_leak3&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Calling &apos;function_with_leak3&apos;</string>
+// CHECK-NEXT: <string>Calling &apos;function_with_leak3&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>event</string>
@@ -3305,7 +3305,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Entered call from &apos;use_function_with_leak3&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;use_function_with_leak3&apos;</string>
+// CHECK-NEXT: <string>Entered call from &apos;use_function_with_leak3&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -3402,7 +3402,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is allocated</string>
+// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -3499,7 +3499,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Assuming &apos;y&apos; is not equal to 0</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Assuming &apos;y&apos; is not equal to 0</string>
+// CHECK-NEXT: <string>Assuming &apos;y&apos; is not equal to 0</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -3547,7 +3547,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
+// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
@@ -3555,7 +3555,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>function_with_leak3</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>121</integer>
@@ -3593,7 +3593,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Calling &apos;function_with_leak4&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Calling &apos;function_with_leak4&apos;</string>
+// CHECK-NEXT: <string>Calling &apos;function_with_leak4&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>event</string>
@@ -3607,7 +3607,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Entered call from &apos;use_function_with_leak4&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;use_function_with_leak4&apos;</string>
+// CHECK-NEXT: <string>Entered call from &apos;use_function_with_leak4&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -3704,7 +3704,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is allocated</string>
+// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -3801,7 +3801,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Assuming &apos;y&apos; is 0</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Assuming &apos;y&apos; is 0</string>
+// CHECK-NEXT: <string>Assuming &apos;y&apos; is 0</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -3849,7 +3849,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
+// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
@@ -3857,7 +3857,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>function_with_leak4</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>132</integer>
@@ -3895,7 +3895,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Calling &apos;function_with_leak5&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Calling &apos;function_with_leak5&apos;</string>
+// CHECK-NEXT: <string>Calling &apos;function_with_leak5&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>event</string>
@@ -3909,7 +3909,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Entered call from &apos;use_function_with_leak5&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;use_function_with_leak5&apos;</string>
+// CHECK-NEXT: <string>Entered call from &apos;use_function_with_leak5&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -4006,7 +4006,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is allocated</string>
+// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -4054,7 +4054,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
+// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
@@ -4062,7 +4062,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>function_with_leak5</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>143</integer>
@@ -4100,7 +4100,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Calling &apos;function_with_leak6&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Calling &apos;function_with_leak6&apos;</string>
+// CHECK-NEXT: <string>Calling &apos;function_with_leak6&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>event</string>
@@ -4114,7 +4114,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Entered call from &apos;use_function_with_leak6&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;use_function_with_leak6&apos;</string>
+// CHECK-NEXT: <string>Entered call from &apos;use_function_with_leak6&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -4211,7 +4211,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is allocated</string>
+// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -4259,7 +4259,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
+// CHECK-NEXT: <string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Memory is never released; potential leak of memory pointed to by &apos;x&apos;</string>
@@ -4267,7 +4267,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>function_with_leak6</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>154</integer>
@@ -4305,7 +4305,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Calling &apos;function_with_leak7&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Calling &apos;function_with_leak7&apos;</string>
+// CHECK-NEXT: <string>Calling &apos;function_with_leak7&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>event</string>
@@ -4319,7 +4319,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Entered call from &apos;use_function_with_leak7&apos;</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;use_function_with_leak7&apos;</string>
+// CHECK-NEXT: <string>Entered call from &apos;use_function_with_leak7&apos;</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -4416,7 +4416,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is allocated</string>
+// CHECK-NEXT: <string>Memory is allocated</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>event</string>
@@ -4445,7 +4445,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Returned allocated memory</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Returned allocated memory</string>
+// CHECK-NEXT: <string>Returned allocated memory</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -4493,7 +4493,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Memory is never released; potential leak</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Memory is never released; potential leak</string>
+// CHECK-NEXT: <string>Memory is never released; potential leak</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Memory is never released; potential leak</string>
@@ -4501,7 +4501,7 @@ void use_function_with_leak7() {
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>use_function_with_leak7</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>170</integer>
@@ -4510,3 +4510,5 @@ void use_function_with_leak7() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </plist>
diff --git a/test/Analysis/malloc.c b/test/Analysis/malloc.c
index 68308fd..7790b32 100644
--- a/test/Analysis/malloc.c
+++ b/test/Analysis/malloc.c
@@ -1,5 +1,4 @@
// 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"
@@ -14,6 +13,7 @@ void *reallocf(void *ptr, size_t size);
void *calloc(size_t nmemb, size_t size);
char *strdup(const char *s);
char *strndup(const char *s, size_t n);
+int memcmp(const void *s1, const void *s2, size_t n);
void myfoo(int *p);
void myfooint(int p);
@@ -104,8 +104,8 @@ void reallocSizeZero5() {
}
void reallocPtrZero1() {
- char *r = realloc(0, 12); // expected-warning {{Memory is never released; potential leak of memory pointed to by 'r'}}
-}
+ char *r = realloc(0, 12);
+} // expected-warning {{Memory is never released; potential leak of memory pointed to by 'r'}}
void reallocPtrZero2() {
char *r = realloc(0, 12);
@@ -130,12 +130,12 @@ void reallocRadar6337483_1() {
void reallocRadar6337483_2() {
char *buf = malloc(100);
char *buf2 = (char*)realloc(buf, 0x1000000);
- if (!buf2) { // expected-warning {{Memory is never released; potential leak}}
+ if (!buf2) {
;
} else {
free(buf2);
}
-}
+} // expected-warning {{Memory is never released; potential leak}}
void reallocRadar6337483_3() {
char * buf = malloc(100);
@@ -188,8 +188,8 @@ void reallocfRadar6337483_3() {
}
void reallocfPtrZero1() {
- char *r = reallocf(0, 12); // expected-warning {{Memory is never released; potential leak}}
-}
+ char *r = reallocf(0, 12);
+} // expected-warning {{Memory is never released; potential leak}}
// This case tests that storing malloc'ed memory to a static variable which is
@@ -386,13 +386,13 @@ void mallocBindFreeUse() {
void mallocEscapeMalloc() {
int *p = malloc(12);
myfoo(p);
- p = malloc(12); // expected-warning{{Memory is never released; potential leak}}
-}
+ p = malloc(12);
+} // expected-warning{{Memory is never released; potential leak}}
void mallocMalloc() {
int *p = malloc(12);
- p = malloc(12); // expected-warning {{Memory is never released; potential leak}}
-}
+ p = malloc(12);
+} // expected-warning {{Memory is never released; potential leak}}
void mallocFreeMalloc() {
int *p = malloc(12);
@@ -456,8 +456,8 @@ void mallocFailedOrNotLeak() {
void mallocAssignment() {
char *p = malloc(12);
- p = fooRetPtr(); // expected-warning {{leak}}
-}
+ p = fooRetPtr();
+} // expected-warning {{leak}}
int vallocTest() {
char *mem = valloc(12);
@@ -626,8 +626,8 @@ void mallocAssert(int *g) {
void doNotInvalidateWhenPassedToSystemCalls(char *s) {
char *p = malloc(12);
strlen(p);
- strcpy(p, s); // expected-warning {{leak}}
-}
+ strcpy(p, s);
+} // expected-warning {{leak}}
// Rely on the CString checker evaluation of the strcpy API to convey that the result of strcpy is equal to p.
void symbolLostWithStrcpy(char *s) {
@@ -673,8 +673,8 @@ int *specialMallocWithStruct() {
// Test various allocation/deallocation functions.
void testStrdup(const char *s, unsigned validIndex) {
char *s2 = strdup(s);
- s2[validIndex + 1] = 'b';// expected-warning {{Memory is never released; potential leak}}
-}
+ s2[validIndex + 1] = 'b';
+} // expected-warning {{Memory is never released; potential leak}}
int testStrndup(const char *s, unsigned validIndex, unsigned size) {
char *s2 = strndup(s, size);
@@ -782,10 +782,11 @@ void radar10978247_positive(int myValueSize) {
buffer = malloc(myValueSize);
// do stuff with the buffer
- if (buffer == stackBuffer) // expected-warning {{leak}}
+ if (buffer == stackBuffer)
return;
-}
-
+ else
+ return; // expected-warning {{leak}}
+}
// <rdar://problem/11269741> Previously this triggered a false positive
// because malloc() is known to return uninitialized memory and the binding
// of 'o' to 'p->n' was not getting propertly handled. Now we report a leak.
@@ -821,8 +822,8 @@ void radar11270219(void) {
void radar_11358224_test_double_assign_ints_positive_2()
{
void *ptr = malloc(16);
- ptr = ptr; // expected-warning {{leak}}
-}
+ ptr = ptr;
+} // expected-warning {{leak}}
// Assume that functions which take a function pointer can free memory even if
// they are defined in system headers and take the const pointer to the
@@ -836,8 +837,8 @@ void r11160612_1() {
// Null is passed as callback.
void r11160612_2() {
char *x = malloc(12);
- const_ptr_and_callback(0, x, 12, 0); // expected-warning {{leak}}
-}
+ const_ptr_and_callback(0, x, 12, 0);
+} // expected-warning {{leak}}
// Callback is passed to a function defined in a system header.
void r11160612_4() {
@@ -937,29 +938,33 @@ int cmpHeapAllocationToUnknown() {
void localArrayTest() {
char *p = (char*)malloc(12);
char *ArrayL[12];
- ArrayL[0] = p; // expected-warning {{leak}}
-}
+ ArrayL[0] = p;
+} // expected-warning {{leak}}
void localStructTest() {
StructWithPtr St;
StructWithPtr *pSt = &St;
- pSt->memP = malloc(12); // expected-warning{{Memory is never released; potential leak}}
-}
+ pSt->memP = malloc(12);
+} // expected-warning{{Memory is never released; potential leak}}
+#ifdef __INTPTR_TYPE__
// Test double assignment through integers.
-static long glob;
+typedef __INTPTR_TYPE__ intptr_t;
+typedef unsigned __INTPTR_TYPE__ uintptr_t;
+
+static intptr_t glob;
void test_double_assign_ints()
{
void *ptr = malloc (16); // no-warning
- glob = (long)(unsigned long)ptr;
+ glob = (intptr_t)(uintptr_t)ptr;
}
void test_double_assign_ints_positive()
{
void *ptr = malloc(16);
- (void*)(long)(unsigned long)ptr; // expected-warning {{unused}} expected-warning {{leak}}
-}
-
+ (void*)(intptr_t)(uintptr_t)ptr; // expected-warning {{unused}}
+} // expected-warning {{leak}}
+#endif
void testCGContextNoLeak()
{
@@ -1032,15 +1037,166 @@ void *test(void *ptr) {
return newPtr;
}
+
+char *testLeakWithinReturn(char *str) {
+ return strdup(strdup(str)); // expected-warning{{leak}}
+}
+
+void passConstPtr(const char * ptr);
+
+void testPassConstPointer() {
+ char * string = malloc(sizeof(char)*10);
+ passConstPtr(string);
+ return; // expected-warning {{leak}}
+}
+
+void testPassConstPointerIndirectly() {
+ char *p = malloc(1);
+ p++;
+ memcmp(p, p, sizeof(&p));
+ return; // expected-warning {{leak}}
+}
+
+void testPassToSystemHeaderFunctionIndirectly() {
+ int *p = malloc(4);
+ p++;
+ fakeSystemHeaderCallInt(p);
+} // expected-warning {{leak}}
+
+void testPassConstPointerIndirectlyStruct() {
+ struct HasPtr hp;
+ hp.p = malloc(10);
+ memcmp(&hp, &hp, sizeof(hp));
+ return; // expected-warning {{Memory is never released; potential leak of memory pointed to by 'hp.p'}}
+}
+
+void testPassToSystemHeaderFunctionIndirectlyStruct() {
+ SomeStruct ss;
+ ss.p = malloc(1);
+ fakeSystemHeaderCall(&ss);
+} // expected-warning {{Memory is never released; potential leak of memory pointed to by 'ss.p'}}
+
+int *testOffsetAllocate(size_t size) {
+ int *memoryBlock = (int *)malloc(size + sizeof(int));
+ return &memoryBlock[1]; // no-warning
+}
+
+void testOffsetDeallocate(int *memoryBlock) {
+ free(&memoryBlock[-1]); // no-warning
+}
+
+void testOffsetOfRegionFreed() {
+ __int64_t * array = malloc(sizeof(__int64_t)*2);
+ array += 1;
+ free(&array[0]); // expected-warning{{Argument to free() is offset by 8 bytes from the start of memory allocated by malloc()}}
+}
+
+void testOffsetOfRegionFreed2() {
+ __int64_t *p = malloc(sizeof(__int64_t)*2);
+ p += 1;
+ free(p); // expected-warning{{Argument to free() is offset by 8 bytes from the start of memory allocated by malloc()}}
+}
+
+void testOffsetOfRegionFreed3() {
+ char *r = malloc(sizeof(char));
+ r = r - 10;
+ free(r); // expected-warning {{Argument to free() is offset by -10 bytes from the start of memory allocated by malloc()}}
+}
+
+void testOffsetOfRegionFreedAfterFunctionCall() {
+ int *p = malloc(sizeof(int)*2);
+ p += 1;
+ myfoo(p);
+ free(p); // no-warning
+}
+
+void testFixManipulatedPointerBeforeFree() {
+ int * array = malloc(sizeof(int)*2);
+ array += 1;
+ free(&array[-1]); // no-warning
+}
+
+void testFixManipulatedPointerBeforeFree2() {
+ char *r = malloc(sizeof(char));
+ r = r + 10;
+ free(r-10); // no-warning
+}
+
+void freeOffsetPointerPassedToFunction() {
+ __int64_t *p = malloc(sizeof(__int64_t)*2);
+ p[1] = 0;
+ p += 1;
+ myfooint(*p); // not passing the pointer, only a value pointed by pointer
+ free(p); // expected-warning {{Argument to free() is offset by 8 bytes from the start of memory allocated by malloc()}}
+}
+
+int arbitraryInt();
+void freeUnknownOffsetPointer() {
+ char *r = malloc(sizeof(char));
+ r = r + arbitraryInt(); // unable to reason about what the offset might be
+ free(r); // no-warning
+}
+
+void testFreeNonMallocPointerWithNoOffset() {
+ char c;
+ char *r = &c;
+ r = r + 10;
+ free(r-10); // expected-warning {{Argument to free() is the address of the local variable 'c', which is not memory allocated by malloc()}}
+}
+
+void testFreeNonMallocPointerWithOffset() {
+ char c;
+ char *r = &c;
+ free(r+1); // expected-warning {{Argument to free() is the address of the local variable 'c', which is not memory allocated by malloc()}}
+}
+
+void testOffsetZeroDoubleFree() {
+ int *array = malloc(sizeof(int)*2);
+ int *p = &array[0];
+ free(p);
+ free(&array[0]); // expected-warning{{Attempt to free released memory}}
+}
+
+void testOffsetPassedToStrlen() {
+ char * string = malloc(sizeof(char)*10);
+ string += 1;
+ int length = strlen(string); // expected-warning {{Memory is never released; potential leak of memory pointed to by 'string'}}
+}
+
+void testOffsetPassedToStrlenThenFree() {
+ char * string = malloc(sizeof(char)*10);
+ string += 1;
+ int length = strlen(string);
+ free(string); // expected-warning {{Argument to free() is offset by 1 byte from the start of memory allocated by malloc()}}
+}
+
+void testOffsetPassedAsConst() {
+ char * string = malloc(sizeof(char)*10);
+ string += 1;
+ passConstPtr(string);
+ free(string); // expected-warning {{Argument to free() is offset by 1 byte from the start of memory allocated by malloc()}}
+}
+
+char **_vectorSegments;
+int _nVectorSegments;
+
+void poolFreeC(void* s) {
+ free(s); // no-warning
+}
+void freeMemory() {
+ while (_nVectorSegments) {
+ poolFreeC(_vectorSegments[_nVectorSegments++]);
+ }
+}
+
// ----------------------------------------------------------------------------
// False negatives.
-// TODO: This is another false negative.
void testMallocWithParam(int **p) {
*p = (int*) malloc(sizeof(int));
- *p = 0;
+ *p = 0; // FIXME: should warn here
}
void testMallocWithParam_2(int **p) {
- *p = (int*) malloc(sizeof(int));
+ *p = (int*) malloc(sizeof(int)); // no-warning
}
diff --git a/test/Analysis/malloc.cpp b/test/Analysis/malloc.cpp
index 220d746..54efa1c 100644
--- a/test/Analysis/malloc.cpp
+++ b/test/Analysis/malloc.cpp
@@ -5,11 +5,11 @@ void *malloc(size_t);
void free(void *);
void *realloc(void *ptr, size_t size);
void *calloc(size_t nmemb, size_t size);
-
+char *strdup(const char *s);
void checkThatMallocCheckerIsRunning() {
- malloc(4); // expected-warning{{leak}}
-}
+ malloc(4);
+} // expected-warning{{leak}}
// Test for radar://11110132.
struct Foo {
@@ -60,3 +60,43 @@ namespace PR13751 {
}
}
+struct X { void *a; };
+
+struct X get() {
+ struct X result;
+ result.a = malloc(4);
+ return result; // no-warning
+}
+
+// Ensure that regions accessible through a LazyCompoundVal trigger region escape.
+// Malloc checker used to report leaks for the following two test cases.
+struct Property {
+ char* getterName;
+ Property(char* n)
+ : getterName(n) {}
+
+};
+void append(Property x);
+
+void appendWrapper(char *getterName) {
+ append(Property(getterName));
+}
+void foo(const char* name) {
+ char* getterName = strdup(name);
+ appendWrapper(getterName); // no-warning
+}
+
+struct NestedProperty {
+ Property prop;
+ NestedProperty(Property p)
+ : prop(p) {}
+};
+void appendNested(NestedProperty x);
+
+void appendWrapperNested(char *getterName) {
+ appendNested(NestedProperty(Property(getterName)));
+}
+void fooNested(const char* name) {
+ char* getterName = strdup(name);
+ appendWrapperNested(getterName); // no-warning
+} \ No newline at end of file
diff --git a/test/Analysis/malloc.mm b/test/Analysis/malloc.mm
index c92c966..bd9d2d2 100644
--- a/test/Analysis/malloc.mm
+++ b/test/Analysis/malloc.mm
@@ -1,9 +1,6 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc -analyzer-store=region -verify -fblocks %s
-#include "Inputs/system-header-simulator-objc.h"
-
-typedef __typeof(sizeof(int)) size_t;
-void *malloc(size_t);
-void free(void *);
+#import "Inputs/system-header-simulator-objc.h"
+#import "Inputs/system-header-simulator-for-malloc.h"
// Done with headers. Start testing.
void testNSDatafFreeWhenDoneNoError(NSUInteger dataLength) {
@@ -21,6 +18,11 @@ void testNSDataFreeWhenDoneYES2(NSUInteger dataLength) {
NSData *nsdata = [[NSData alloc] initWithBytesNoCopy:data length:dataLength freeWhenDone:1]; // no-warning
}
+void testNSDataFreeWhenDoneYES2_with_wrapper(NSUInteger dataLength) {
+ unsigned char *data = (unsigned char *)malloc(42);
+ Wrapper *nsdata = [[Wrapper alloc] initWithBytesNoCopy:data length:dataLength]; // no-warning
+}
+
void testNSStringFreeWhenDoneYES3(NSUInteger dataLength) {
unsigned char *data = (unsigned char *)malloc(42);
NSString *nsstr = [[NSString alloc] initWithBytesNoCopy:data length:dataLength encoding:NSUTF8StringEncoding freeWhenDone:1];
@@ -64,6 +66,11 @@ void testNSStringFreeWhenDoneNO2(NSUInteger dataLength) {
NSString *nsstr = [[NSString alloc] initWithCharactersNoCopy:data length:dataLength freeWhenDone:0]; // expected-warning{{leak}}
}
+void testOffsetFree() {
+ int *p = (int *)malloc(sizeof(int));
+ NSData *nsdata = [NSData dataWithBytesNoCopy:++p length:sizeof(int) freeWhenDone:1]; // expected-warning{{Argument to +dataWithBytesNoCopy:length:freeWhenDone: is offset by 4 bytes from the start of memory allocated by malloc()}}
+}
+
void testRelinquished1() {
void *data = malloc(42);
NSData *nsdata = [NSData dataWithBytesNoCopy:data length:42 freeWhenDone:1];
@@ -77,6 +84,31 @@ void testRelinquished2() {
[NSData dataWithBytesNoCopy:data length:42]; // expected-warning {{Attempt to free released memory}}
}
+void testNoCopy() {
+ char *p = (char *)calloc(sizeof(int), 1);
+ CustomData *w = [CustomData somethingNoCopy:p]; // no-warning
+}
+
+void testFreeWhenDone() {
+ char *p = (char *)calloc(sizeof(int), 1);
+ CustomData *w = [CustomData something:p freeWhenDone:1]; // no-warning
+}
+
+void testFreeWhenDonePositive() {
+ char *p = (char *)calloc(sizeof(int), 1);
+ CustomData *w = [CustomData something:p freeWhenDone:0]; // expected-warning{{leak}}
+}
+
+void testFreeWhenDoneNoCopy() {
+ int *p = (int *)malloc(sizeof(int));
+ CustomData *w = [CustomData somethingNoCopy:p length:sizeof(int) freeWhenDone:1]; // no-warning
+}
+
+void testFreeWhenDoneNoCopyPositive() {
+ int *p = (int *)malloc(sizeof(int));
+ CustomData *w = [CustomData somethingNoCopy:p length:sizeof(int) freeWhenDone:0]; // expected-warning{{leak}}
+}
+
// Test CF/NS...NoCopy. PR12100: Pointers can escape when custom deallocators are provided.
void testNSDatafFreeWhenDone(NSUInteger dataLength) {
CFStringRef str;
diff --git a/test/Analysis/method-arg-decay.m b/test/Analysis/method-arg-decay.m
index a36d81e..0af9e3e 100644
--- a/test/Analysis/method-arg-decay.m
+++ b/test/Analysis/method-arg-decay.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyzer-checker=core -verify %s
+// RUN: %clang_cc1 -analyzer-checker=core -verify %s -Wno-incomplete-implementation
typedef signed char BOOL;
typedef int NSInteger;
typedef unsigned int NSUInteger;
@@ -70,9 +70,9 @@ extern NSMutableArray *XCFindPossibleKeyModules(PBXModule *module, BOOL useExpos
@interface XCPerspectiveModule : PBXProjectModule <PBXSelectionTarget> { // expected-note {{required for direct or indirect protocol 'PBXSelectionTarget'}}
XCExtendedTabView *_perspectivesTabView;
}
-- (PBXModule *) moduleForTab:(NSTabViewItem *)item; // expected-note {{method definition for 'moduleForTab:' not found}}
+- (PBXModule *) moduleForTab:(NSTabViewItem *)item;
@end
-@implementation XCPerspectiveModule // expected-warning {{incomplete implementation}} expected-warning {{method 'performAction:withSelection:' in protocol not implemented}}}
+@implementation XCPerspectiveModule // expected-warning {{method 'performAction:withSelection:' in protocol not implemented}}}
+ (void) openForProjectDocument:(PBXProjectDocument *)projectDocument {
}
- (PBXModule *) type:(Class)type inPerspective:(id)perspectiveIdentifer matchingFunction:(BOOL (void *, void *))comparator usingData:(void *)data {
diff --git a/test/Analysis/method-call-path-notes.cpp b/test/Analysis/method-call-path-notes.cpp
index a41a786..f946b32 100644
--- a/test/Analysis/method-call-path-notes.cpp
+++ b/test/Analysis/method-call-path-notes.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-output=text -verify %s
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=inlining -analyzer-output=plist-multi-file %s -o %t.plist
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=text -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-output=plist-multi-file %s -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
// Test warning about null or uninitialized pointer values used as instance member
@@ -10,12 +10,12 @@ public:
};
void test_ic() {
- TestInstanceCall *p; // expected-note {{Variable 'p' declared without an initial value}}
+ TestInstanceCall *p; // expected-note {{'p' declared without an initial value}}
p->foo(); // expected-warning {{Called C++ object pointer is uninitialized}} expected-note {{Called C++ object pointer is uninitialized}}
}
void test_ic_null() {
- TestInstanceCall *p = 0; // expected-note {{Variable 'p' initialized to a null pointer value}}
+ TestInstanceCall *p = 0; // expected-note {{'p' initialized to a null pointer value}}
p->foo(); // expected-warning {{Called C++ object pointer is null}} expected-note {{Called C++ object pointer is null}}
}
@@ -31,7 +31,7 @@ void test_ic_null(TestInstanceCall *p) {
}
void test_ic_member_ptr() {
- TestInstanceCall *p = 0; // expected-note {{Variable 'p' initialized to a null pointer value}}
+ TestInstanceCall *p = 0; // expected-note {{'p' initialized to a null pointer value}}
typedef void (TestInstanceCall::*IC_Ptr)();
IC_Ptr bar = &TestInstanceCall::foo;
(p->*bar)(); // expected-warning {{Called C++ object pointer is null}} expected-note{{Called C++ object pointer is null}}
@@ -72,9 +72,9 @@ void test_cast(const TestInstanceCall *p) {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; declared without an initial value</string>
+// CHECK-NEXT: <string>&apos;p&apos; declared without an initial value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; declared without an initial value</string>
+// CHECK-NEXT: <string>&apos;p&apos; declared without an initial value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -145,7 +145,7 @@ void test_cast(const TestInstanceCall *p) {
// CHECK-NEXT: <key>type</key><string>Called C++ object pointer is uninitialized</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_ic</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>14</integer>
@@ -181,9 +181,9 @@ void test_cast(const TestInstanceCall *p) {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -254,7 +254,7 @@ void test_cast(const TestInstanceCall *p) {
// CHECK-NEXT: <key>type</key><string>Called C++ object pointer is null</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_ic_null</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>19</integer>
@@ -397,7 +397,7 @@ void test_cast(const TestInstanceCall *p) {
// CHECK-NEXT: <key>type</key><string>Called C++ object pointer is null</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_ic_set_to_null</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>25</integer>
@@ -540,7 +540,7 @@ void test_cast(const TestInstanceCall *p) {
// CHECK-NEXT: <key>type</key><string>Called C++ object pointer is null</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_ic_null</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>30</integer>
@@ -576,9 +576,9 @@ void test_cast(const TestInstanceCall *p) {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -649,7 +649,7 @@ void test_cast(const TestInstanceCall *p) {
// CHECK-NEXT: <key>type</key><string>Called C++ object pointer is null</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_ic_member_ptr</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>37</integer>
@@ -792,7 +792,7 @@ void test_cast(const TestInstanceCall *p) {
// CHECK-NEXT: <key>type</key><string>Called C++ object pointer is null</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_cast</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>42</integer>
diff --git a/test/Analysis/method-call.cpp b/test/Analysis/method-call.cpp
index 1a2fedd..95db452 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-config c++-inlining=constructors -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config c++-inlining=constructors -verify %s
void clang_analyzer_eval(bool);
diff --git a/test/Analysis/misc-ps-region-store.cpp b/test/Analysis/misc-ps-region-store.cpp
index a106cf0..902a5e5 100644
--- a/test/Analysis/misc-ps-region-store.cpp
+++ b/test/Analysis/misc-ps-region-store.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,alpha.core -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
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s -fexceptions -fcxx-exceptions
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s -fexceptions -fcxx-exceptions
// Test basic handling of references.
char &test1_aux();
@@ -628,3 +628,115 @@ void test_inline() {
a.bar();
}
+void test_alloca_in_a_recursive_function(int p1) {
+ __builtin_alloca (p1);
+ test_alloca_in_a_recursive_function(1);
+ test_alloca_in_a_recursive_function(2);
+}
+
+//===---------------------------------------------------------------------===//
+// Random tests.
+//===---------------------------------------------------------------------===//
+
+// Tests assigning using a C-style initializer to a struct
+// variable whose sub-field is also a struct. This currently
+// results in a CXXTempObjectRegion being created, but not
+// properly handled. For now, we just ignore that value
+// to avoid a crash (<rdar://problem/12753384>).
+struct RDar12753384_ClassA {
+ unsigned z;
+};
+struct RDar12753384_ClassB {
+ unsigned x;
+ RDar12753384_ClassA y[ 8 ] ;
+};
+unsigned RDar12753384() {
+ RDar12753384_ClassB w = { 0x00 };
+ RDar12753384_ClassA y[8];
+ return w.x;
+}
+
+// This testcase tests whether we treat the anonymous union and union
+// the same way. This previously resulted in a "return of stack address"
+// warning because the anonymous union resulting in a temporary object
+// getting put into the initializer. We still aren't handling this correctly,
+// but now if a temporary object appears in an initializer we just ignore it.
+// Fixes <rdar://problem/12755044>.
+
+struct Rdar12755044_foo
+{
+ struct Rdar12755044_bar
+ {
+ union baz
+ {
+ int i;
+ };
+ } aBar;
+};
+
+struct Rdar12755044_foo_anon
+{
+ struct Rdar12755044_bar
+ {
+ union
+ {
+ int i;
+ };
+ } aBar;
+};
+
+const Rdar12755044_foo_anon *radar12755044_anon() {
+ static const Rdar12755044_foo_anon Rdar12755044_foo_list[] = { { { } } };
+ return Rdar12755044_foo_list; // no-warning
+}
+
+const Rdar12755044_foo *radar12755044() {
+ static const Rdar12755044_foo Rdar12755044_foo_list[] = { { { } } };
+ return Rdar12755044_foo_list; // no-warning
+}
+
+// Test the correct handling of integer to bool conversions. Previously
+// this resulted in a false positive because integers were being truncated
+// and not tested for non-zero.
+void rdar12759044() {
+ int flag = 512;
+ if (!(flag & 512)) {
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+ }
+}
+
+// The analyzer currently does not model complex types. Test that the load
+// from 'x' is not flagged as being uninitialized.
+typedef __complex__ float _ComplexT;
+void rdar12964481(_ComplexT *y) {
+ _ComplexT x;
+ __real__ x = 1.0;
+ __imag__ x = 1.0;
+ *y *= x; // no-warning
+}
+void rdar12964481_b(_ComplexT *y) {
+ _ComplexT x;
+ // Eventually this should be a warning.
+ *y *= x; // no-warning
+}
+
+// Test case for PR 12921. This previously produced
+// a bogus warning.
+static const int pr12921_arr[] = { 0, 1 };
+static const int pr12921_arrcount = sizeof(pr12921_arr)/sizeof(int);
+
+int pr12921(int argc, char **argv) {
+ int i, retval;
+ for (i = 0; i < pr12921_arrcount; i++) {
+ if (argc == i) {
+ retval = i;
+ break;
+ }
+ }
+
+ // No match
+ if (i == pr12921_arrcount) return 66;
+ return pr12921_arr[retval];
+}
+
diff --git a/test/Analysis/misc-ps-region-store.m b/test/Analysis/misc-ps-region-store.m
index f772894..ba88dec 100644
--- a/test/Analysis/misc-ps-region-store.m
+++ b/test/Analysis/misc-ps-region-store.m
@@ -920,7 +920,7 @@ int rdar_7770737_pos(void)
void pr6302(id x, Class y) {
// This previously crashed the analyzer (reported in PR 6302)
- x->isa = y; // expected-warning {{direct access to objective-c's isa is deprecated in favor of object_setClass() and object_getClass()}}
+ x->isa = y; // expected-warning {{assignment to Objective-C's isa is deprecated in favor of object_setClass()}}
}
//===----------------------------------------------------------------------===//
@@ -1193,7 +1193,7 @@ static void RDar8424269_B(RDar8424269_A *p, unsigned char *RDar8424269_D,
tmp2 = tmp2t[2];
}
-// <rdar://problem/8642434> - Handle transparent unions with the AttrNonNullChecker.
+// <rdar://problem/8642434> - Handle transparent unions with the NonNullParamChecker.
typedef union {
struct rdar_8642434_typeA *_dq;
}
diff --git a/test/Analysis/misc-ps.c b/test/Analysis/misc-ps.c
index ef89321..5369ab1 100644
--- a/test/Analysis/misc-ps.c
+++ b/test/Analysis/misc-ps.c
@@ -151,3 +151,15 @@ int rdar_12075238_(unsigned long count) {
return 0;
}
+// Test that we handle an uninitialized value within a logical expression.
+void PR14635(int *p) {
+ int a = 0, b;
+ *p = a || b; // expected-warning {{Assigned value is garbage or undefined}}
+}
+
+// Test handling floating point values with unary '!'.
+int PR14634(int x) {
+ double y = (double)x;
+ return !y;
+}
+
diff --git a/test/Analysis/new.cpp b/test/Analysis/new.cpp
index fdd16da3..44ae980 100644
--- a/test/Analysis/new.cpp
+++ b/test/Analysis/new.cpp
@@ -1,9 +1,11 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-store region -std=c++11 -verify %s
+#include "Inputs/system-header-simulator-cxx.h"
void clang_analyzer_eval(bool);
typedef __typeof__(sizeof(int)) size_t;
extern "C" void *malloc(size_t);
+extern "C" void free(void *);
int someGlobal;
void testImplicitlyDeclaredGlobalNew() {
@@ -19,13 +21,6 @@ void testImplicitlyDeclaredGlobalNew() {
clang_analyzer_eval(someGlobal == 0); // expected-warning{{TRUE}}
}
-
-// This is the standard placement new.
-inline void* operator new(size_t, void* __p) throw()
-{
- return __p;
-}
-
void *testPlacementNew() {
int *x = (int *)malloc(sizeof(int));
*x = 1;
@@ -73,7 +68,6 @@ void testScalarInitialization() {
clang_analyzer_eval(*n == 0); // expected-warning{{TRUE}}
}
-
struct PtrWrapper {
int *x;
@@ -82,10 +76,82 @@ struct PtrWrapper {
PtrWrapper *testNewInvalidation() {
// Ensure that we don't consider this a leak.
- return new PtrWrapper(static_cast<int *>(malloc(4)));
+ return new PtrWrapper(static_cast<int *>(malloc(4))); // no-warning
+}
+
+void testNewInvalidationPlacement(PtrWrapper *w) {
+ // Ensure that we don't consider this a leak.
+ new (w) PtrWrapper(static_cast<int *>(malloc(4))); // no-warning
+}
+
+int **testNewInvalidationScalar() {
+ // Ensure that we don't consider this a leak.
+ return new (int *)(static_cast<int *>(malloc(4))); // no-warning
+}
+
+void testNewInvalidationScalarPlacement(int **p) {
+ // Ensure that we don't consider this a leak.
+ new (p) (int *)(static_cast<int *>(malloc(4))); // no-warning
+}
+
+void testCacheOut(PtrWrapper w) {
+ extern bool coin();
+ if (coin())
+ w.x = 0;
+ new (&w.x) (int*)(0); // we cache out here; don't crash
}
+//--------------------------------------------------------------------
+// Check for intersection with other checkers from MallocChecker.cpp
+// bounded with unix.Malloc
+//--------------------------------------------------------------------
+
+// new/delete oparators are subjects of cplusplus.NewDelete.
+void testNewDeleteNoWarn() {
+ int i;
+ delete &i; // no-warning
+
+ int *p1 = new int;
+ delete ++p1; // no-warning
+
+ int *p2 = new int;
+ delete p2;
+ delete p2; // no-warning
+
+ int *p3 = new int; // no-warning
+}
+
+// unix.Malloc does not know about operators new/delete.
+void testDeleteMallocked() {
+ int *x = (int *)malloc(sizeof(int));
+ delete x; // FIXME: Shoud detect pointer escape and keep silent after 'delete' is modeled properly.
+} // expected-warning{{Memory is never released; potential leak}}
+
+void testDeleteOpAfterFree() {
+ int *p = (int *)malloc(sizeof(int));
+ free(p);
+ operator delete(p); // expected-warning{{Use of memory after it is freed}}
+}
+
+void testDeleteAfterFree() {
+ int *p = (int *)malloc(sizeof(int));
+ free(p);
+ delete p; // expected-warning{{Use of memory after it is freed}}
+}
+
+void testStandardPlacementNewAfterFree() {
+ int *p = (int *)malloc(sizeof(int));
+ free(p);
+ p = new(p) int; // expected-warning{{Use of memory after it is freed}}
+}
+
+void testCustomPlacementNewAfterFree() {
+ int *p = (int *)malloc(sizeof(int));
+ free(p);
+ p = new(0, p) int; // expected-warning{{Use of memory after it is freed}}
+}
+
//--------------------------------
// Incorrectly-modelled behavior
//--------------------------------
@@ -95,8 +161,10 @@ int testNoInitialization() {
// Should warn that *n is uninitialized.
if (*n) { // no-warning
+ delete n;
return 0;
}
+ delete n;
return 1;
}
diff --git a/test/Analysis/null-deref-path-notes.m b/test/Analysis/null-deref-path-notes.m
index 993f633..6651454 100644
--- a/test/Analysis/null-deref-path-notes.m
+++ b/test/Analysis/null-deref-path-notes.m
@@ -15,7 +15,7 @@ int testNull(Root *obj) {
// 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}}
+ int *x = &obj->uniqueID; // expected-note{{'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')}}
}
@@ -36,6 +36,20 @@ int testNull(Root *obj) {
@end
+void repeatedStores(int coin) {
+ int *p = 0;
+ if (coin) {
+ // expected-note@-1 {{Assuming 'coin' is 0}}
+ // expected-note@-2 {{Taking false branch}}
+ extern int *getPointer();
+ p = getPointer();
+ } else {
+ p = 0; // expected-note {{Null pointer value stored to 'p'}}
+ }
+
+ *p = 1; // expected-warning{{Dereference of null pointer}} expected-note{{Dereference of null pointer}}
+}
+
// CHECK: <key>diagnostics</key>
// CHECK-NEXT: <array>
@@ -164,9 +178,9 @@ int testNull(Root *obj) {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;x&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;x&apos; initialized to a null pointer value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;x&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;x&apos; initialized to a null pointer value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -271,7 +285,7 @@ int testNull(Root *obj) {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testNull</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>6</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>6</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>19</integer>
@@ -477,7 +491,7 @@ int testNull(Root *obj) {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
// CHECK-NEXT: <key>issue_context</key><string>initWithID:</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>6</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>6</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>33</integer>
@@ -485,4 +499,244 @@ int testNull(Root *obj) {
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>40</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>40</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Assuming &apos;coin&apos; is 0</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;coin&apos; is 0</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>41</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>47</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>47</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>47</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>47</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>47</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;p&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;p&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>47</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>47</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>50</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>50</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>50</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>50</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>50</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>repeatedStores</string>
+// CHECK-NEXT: <key>issue_hash</key><string>11</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>50</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
diff --git a/test/Analysis/objc-method-coverage.m b/test/Analysis/objc-method-coverage.m
index 3088a29..489c19b 100644
--- a/test/Analysis/objc-method-coverage.m
+++ b/test/Analysis/objc-method-coverage.m
@@ -1,6 +1,5 @@
+// REQUIRES: asserts
// 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
int f() {
return 0;
@@ -14,4 +13,5 @@ int f() {
@end
// CHECK: ... Statistics Collected ...
-// CHECK: 2 AnalysisConsumer - The # of functions analysed (as top level). \ No newline at end of file
+// CHECK: 2 AnalysisConsumer - The # of functions and blocks analyzed (as top level with inlining turned on).
+// CHECK: 100 AnalysisConsumer - The % of reachable basic blocks.
diff --git a/test/Analysis/objc/direct-ivar-assignment-in-annotated-functions.m b/test/Analysis/objc/direct-ivar-assignment-in-annotated-functions.m
new file mode 100644
index 0000000..f449786
--- /dev/null
+++ b/test/Analysis/objc/direct-ivar-assignment-in-annotated-functions.m
@@ -0,0 +1,63 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.osx.cocoa.DirectIvarAssignmentForAnnotatedFunctions -fobjc-default-synthesize-properties -verify -fblocks %s
+
+typedef signed char BOOL;
+@protocol NSObject - (BOOL)isEqual:(id)object; @end
+@interface NSObject <NSObject> {}
++(id)alloc;
+-(id)init;
+-(id)autorelease;
+-(id)copy;
+-(id)retain;
+@end
+
+@interface MyClass;
+@end
+
+@interface AnnotatedClass : NSObject {
+}
+ - (void) someMethod: (MyClass*)In __attribute__((annotate("objc_no_direct_instance_variable_assignment")));
+ - (void) someMethodNotAnnaotated: (MyClass*)In;
+@end
+
+
+@interface TestProperty : AnnotatedClass {
+ MyClass *_Z;
+ id _nonSynth;
+ MyClass* _NotA __attribute__((annotate("objc_allow_direct_instance_variable_assignment")));
+}
+
+ @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
+
+ @property (assign) MyClass* NotA; // warnings should be suppressed, backing ivar is annotated
+ @property (assign) MyClass* NotX __attribute__((annotate("objc_allow_direct_instance_variable_assignment"))); // warnings should be suppressed
+
+ @end
+
+@implementation TestProperty
+ @synthesize A = __A;
+
+ - (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}}
+ _NotX = 0; // no-warning
+ _NotA = 0; // no-warning
+ }
+ - (void) someMethodNotAnnaotated: (MyClass*)In {
+ (__A) = In;
+ _X = In; // no-warning
+ _Y = In; // no-warning
+ _Z = In; // no-warning
+ _nonSynth = 0; // no-warning
+ }
+
+@end \ No newline at end of file
diff --git a/test/Analysis/objc_invalidation.m b/test/Analysis/objc_invalidation.m
index 357c5e8..a6f5ec3 100644
--- a/test/Analysis/objc_invalidation.m
+++ b/test/Analysis/objc_invalidation.m
@@ -1,4 +1,11 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.osx.cocoa.InstanceVariableInvalidation -fobjc-default-synthesize-properties -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.osx.cocoa.InstanceVariableInvalidation -DRUN_IVAR_INVALIDATION -fobjc-default-synthesize-properties -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.osx.cocoa.MissingInvalidationMethod -DRUN_MISSING_INVALIDATION_METHOD -fobjc-default-synthesize-properties -verify %s
+extern void __assert_fail (__const char *__assertion, __const char *__file,
+ unsigned int __line, __const char *__function)
+ __attribute__ ((__noreturn__));
+
+#define assert(expr) \
+ ((expr) ? (void)(0) : __assert_fail (#expr, __FILE__, __LINE__, __func__))
@protocol NSObject
@end
@@ -29,12 +36,22 @@ extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1,
- (void) invalidate2 __attribute__((annotate("objc_instance_variable_invalidator")));
@end
+@protocol Invalidation3;
+@protocol Invalidation2;
+
@interface Invalidation2Class <Invalidation2>
@end
@interface Invalidation1Class <Invalidation1>
@end
+@interface ClassWithInvalidationMethodInCategory <NSObject>
+@end
+
+@interface ClassWithInvalidationMethodInCategory ()
+- (void) invalidate __attribute__((annotate("objc_instance_variable_invalidator")));
+@end
+
@interface SomeInvalidationImplementingObject: NSObject <Invalidation3, Invalidation2> {
SomeInvalidationImplementingObject *ObjA; // invalidation in the parent
}
@@ -65,6 +82,11 @@ extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1,
SomeInvalidationImplementingObject *_Prop5; // property with @synthesize, invalidate via getter method
SomeInvalidationImplementingObject *_Prop8;
+ // Ivars invalidated by the partial invalidator.
+ SomeInvalidationImplementingObject *Ivar9;
+ SomeInvalidationImplementingObject *_Prop10;
+ SomeInvalidationImplementingObject *Ivar11;
+
// No warnings on these as they are not invalidatable.
NSObject *NIvar1;
NSObject *NObj2;
@@ -92,15 +114,21 @@ extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1,
-(void)invalidate;
+// Partial invalidators invalidate only some ivars. They are guaranteed to be
+// called before the invalidation methods.
+-(void)partialInvalidator1 __attribute__((annotate("objc_instance_variable_invalidator_partial")));
+-(void)partialInvalidator2 __attribute__((annotate("objc_instance_variable_invalidator_partial")));
@end
@interface SomeSubclassInvalidatableObject()
@property (assign) SomeInvalidationImplementingObject* Prop8;
+@property (assign) SomeInvalidationImplementingObject* Prop10;
@end
@implementation SomeSubclassInvalidatableObject{
@private
SomeInvalidationImplementingObject *Ivar5;
+ ClassWithInvalidationMethodInCategory *Ivar13;
}
@synthesize Prop7 = _propIvar;
@@ -108,6 +136,7 @@ extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1,
@synthesize Prop5 = _Prop5;
@synthesize Prop4 = _Prop4;
@synthesize Prop8 = _Prop8;
+@synthesize Prop10 = _Prop10;
- (void) setProp1: (SomeInvalidationImplementingObject*) InObj {
@@ -143,11 +172,165 @@ extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1,
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}}
+#if RUN_IVAR_INVALIDATION
+// expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated}}
+// expected-warning@-3 {{Instance variable MultipleProtocols needs to be invalidated}}
+// expected-warning@-4 {{Instance variable MultInheritance needs to be invalidated}}
+// expected-warning@-5 {{Property SynthIvarProp needs to be invalidated or set to nil}}
+// expected-warning@-6 {{Instance variable _Ivar3 needs to be invalidated}}
+// expected-warning@-7 {{Instance variable _Ivar4 needs to be invalidated}}
+// expected-warning@-8 {{Instance variable Ivar5 needs to be invalidated or set to nil}}
+// expected-warning@-9 {{Instance variable Ivar13 needs to be invalidated or set to nil}}
+#endif
+
+-(void)partialInvalidator1 {
+ [Ivar9 invalidate];
+ [_Prop10 invalidate];
+}
+
+-(void)partialInvalidator2 {
+ [Ivar11 invalidate];
+}
+
+@end
+
+// Example, where the same property is inherited through
+// the parent and directly through a protocol. If a property backing ivar is
+// synthesized in the parent, let the parent invalidate it.
+
+@protocol IDEBuildable <NSObject>
+@property (readonly, strong) id <Invalidation2> ObjB;
+@end
+
+@interface Parent : NSObject <IDEBuildable, Invalidation2> {
+ Invalidation2Class *_ObjB; // Invalidation of ObjB happens in the parent.
+}
+@end
+
+@interface Child: Parent <Invalidation2, IDEBuildable>
+@end
+
+@implementation Parent{
+ @private
+ Invalidation2Class *Ivar10;
+ Invalidation2Class *Ivar11;
+ Invalidation2Class *Ivar12;
+}
+
+@synthesize ObjB = _ObjB;
+- (void)invalidate{
+ _ObjB = ((void*)0);
+
+ assert(Ivar10 == 0);
+
+ if (__builtin_expect(!(Ivar11 == ((void*)0)), 0))
+ assert(0);
+
+ assert(0 == Ivar12);
+
+}
+@end
+
+@implementation Child
+- (void)invalidate{
+ // no-warning
+}
+@end
+
+@protocol Invalidation <NSObject>
+- (void)invalidate __attribute__((annotate("objc_instance_variable_invalidator")));
+@end
+
+@interface Foo : NSObject <Invalidation>
+@end
+
+@class FooBar;
+@protocol FooBar_Protocol <NSObject>
+@end
+
+@interface MissingInvalidationMethod : Foo <FooBar_Protocol>
+@property (assign) MissingInvalidationMethod *foobar15_warn;
+#if RUN_IVAR_INVALIDATION
+// expected-warning@-2 {{Property foobar15_warn needs to be invalidated; no invalidation method is defined in the @implementation for MissingInvalidationMethod}}
+#endif
+@end
+@implementation MissingInvalidationMethod
+@end
+
+@interface MissingInvalidationMethod2 : Foo <FooBar_Protocol> {
+ Foo *Ivar1;
+#if RUN_IVAR_INVALIDATION
+// expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated; no invalidation method is defined in the @implementation for MissingInvalidationMethod2}}
+#endif
+}
+@end
+@implementation MissingInvalidationMethod2
+@end
+
+@interface MissingInvalidationMethodDecl : NSObject {
+ Foo *Ivar1;
+#if RUN_MISSING_INVALIDATION_METHOD
+// expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated; no invalidation method is declared for MissingInvalidationMethodDecl}}
+#endif
+}
+@end
+@implementation MissingInvalidationMethodDecl
+@end
+
+@interface MissingInvalidationMethodDecl2 : NSObject {
+@private
+ Foo *_foo1;
+#if RUN_MISSING_INVALIDATION_METHOD
+// expected-warning@-2 {{Instance variable _foo1 needs to be invalidated; no invalidation method is declared for MissingInvalidationMethodDecl2}}
+#endif
+}
+@property (strong) Foo *bar1;
@end
+@implementation MissingInvalidationMethodDecl2
+@end
+
+@interface InvalidatedInPartial : SomeInvalidationImplementingObject {
+ SomeInvalidationImplementingObject *Ivar1;
+ SomeInvalidationImplementingObject *Ivar2;
+}
+-(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial")));
+@end
+@implementation InvalidatedInPartial
+-(void)partialInvalidator {
+ [Ivar1 invalidate];
+ Ivar2 = 0;
+}
+@end
+
+@interface NotInvalidatedInPartial : SomeInvalidationImplementingObject {
+ SomeInvalidationImplementingObject *Ivar1;
+}
+-(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial")));
+-(void)partialInvalidatorCallsPartial __attribute__((annotate("objc_instance_variable_invalidator_partial")));
+@end
+@implementation NotInvalidatedInPartial
+-(void)partialInvalidator {
+}
+-(void)partialInvalidatorCallsPartial {
+ [self partialInvalidator];
+}
+
+-(void)invalidate {
+}
+#if RUN_IVAR_INVALIDATION
+// expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated or set to nil}}
+#endif
+@end
+
+// False negative.
+@interface PartialCallsFull : SomeInvalidationImplementingObject {
+ SomeInvalidationImplementingObject *Ivar1;
+}
+-(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial")));
+@end
+@implementation PartialCallsFull
+-(void)partialInvalidator {
+ [self invalidate];
+} // TODO: It would be nice to check that the full invalidation method actually invalidates the ivar.
+@end
+
diff --git a/test/Analysis/operator-calls.cpp b/test/Analysis/operator-calls.cpp
index 066f6a3..4f686e5 100644
--- a/test/Analysis/operator-calls.cpp
+++ b/test/Analysis/operator-calls.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-ipa=inlining -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.core,debug.ExprInspection -verify %s
void clang_analyzer_eval(bool);
struct X0 { };
diff --git a/test/Analysis/plist-output-alternate.m b/test/Analysis/plist-output-alternate.m
index 423574d..bc9e103 100644
--- a/test/Analysis/plist-output-alternate.m
+++ b/test/Analysis/plist-output-alternate.m
@@ -87,9 +87,9 @@ void rdar8331641(int x) {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -160,7 +160,7 @@ void rdar8331641(int x) {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_null_init</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>6</integer>
@@ -303,7 +303,7 @@ void rdar8331641(int x) {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_null_assign</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>12</integer>
@@ -436,9 +436,9 @@ void rdar8331641(int x) {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;q&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;q&apos; initialized to a null pointer value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;q&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;q&apos; initialized to a null pointer value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -509,7 +509,7 @@ void rdar8331641(int x) {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_null_assign_transitive</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>19</integer>
@@ -652,7 +652,7 @@ void rdar8331641(int x) {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_null_cond</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>24</integer>
@@ -785,9 +785,9 @@ void rdar8331641(int x) {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -858,7 +858,7 @@ void rdar8331641(int x) {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_null_cond_transitive</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>31</integer>
@@ -924,6 +924,69 @@ void rdar8331641(int x) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>37</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>37</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>37</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>37</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>37</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;x.p&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;x.p&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>37</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>37</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>38</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
@@ -972,7 +1035,7 @@ void rdar8331641(int x) {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_null_field</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>38</integer>
@@ -1265,7 +1328,7 @@ void rdar8331641(int x) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>rdar8331641</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>6</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>6</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>58</integer>
diff --git a/test/Analysis/plist-output.m b/test/Analysis/plist-output.m
index cefa762..80ce453 100644
--- a/test/Analysis/plist-output.m
+++ b/test/Analysis/plist-output.m
@@ -100,6 +100,90 @@ void rdar12280665() {
}
}
+// Test for a "loop executed 0 times" diagnostic.
+int *radar12322528_bar();
+
+void radar12322528_for(int x) {
+ int *p = 0;
+ for (unsigned i = 0; i < x; ++i) {
+ p = radar12322528_bar();
+ }
+ *p = 0xDEADBEEF;
+}
+
+void radar12322528_while(int x) {
+ int *p = 0;
+ unsigned i = 0;
+ for ( ; i < x ; ) {
+ ++i;
+ p = radar12322528_bar();
+ }
+ *p = 0xDEADBEEF;
+}
+
+void radar12322528_foo_2() {
+ int *p = 0;
+ for (unsigned i = 0; i < 2; ++i) {
+ if (i == 1)
+ break;
+ }
+ *p = 0xDEADBEEF;
+}
+
+void test_loop_diagnostics() {
+ int *p = 0;
+ for (int i = 0; i < 2; ++i) { p = 0; }
+ *p = 1;
+}
+
+void test_loop_diagnostics_2() {
+ int *p = 0;
+ for (int i = 0; i < 2; ) {
+ ++i;
+ p = 0;
+ }
+ *p = 1;
+}
+
+void test_loop_diagnostics_3() {
+ int *p = 0;
+ int i = 0;
+ while (i < 2) {
+ ++i;
+ p = 0;
+ }
+ *p = 1;
+}
+
+void test_loop_fast_enumeration(id arr) {
+ int x;
+ for (id obj in arr) {
+ x = 1;
+ }
+ x += 1;
+}
+
+@interface RDar12114812 { char *p; }
+@end
+
+@implementation RDar12114812
+- (void)test {
+ p = 0;
+ *p = 1;
+}
+@end
+
+// Test diagnostics for initialization of structs.
+void RDar13295437_f(void *i) __attribute__((__nonnull__));
+
+struct RDar13295437_S { int *i; };
+
+int RDar13295437() {
+ struct RDar13295437_S s = {0};
+ struct RDar13295437_S *sp = &s;
+ RDar13295437_f(sp->i);
+}
+
// CHECK: <key>diagnostics</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
@@ -130,9 +214,9 @@ void rdar12280665() {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -203,7 +287,7 @@ void rdar12280665() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_null_init</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>6</integer>
@@ -346,7 +430,7 @@ void rdar12280665() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_null_assign</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>12</integer>
@@ -479,9 +563,9 @@ void rdar12280665() {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;q&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;q&apos; initialized to a null pointer value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;q&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;q&apos; initialized to a null pointer value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -552,7 +636,7 @@ void rdar12280665() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_null_assign_transitive</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>19</integer>
@@ -695,7 +779,7 @@ void rdar12280665() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_null_cond</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>24</integer>
@@ -828,9 +912,9 @@ void rdar12280665() {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -901,7 +985,7 @@ void rdar12280665() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_null_cond_transitive</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>31</integer>
@@ -967,6 +1051,69 @@ void rdar12280665() {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>37</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>37</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>37</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>37</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>37</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;x.p&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;x.p&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>37</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>37</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>38</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
@@ -1015,7 +1162,7 @@ void rdar12280665() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_null_field</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>38</integer>
@@ -1245,9 +1392,9 @@ void rdar12280665() {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -1318,7 +1465,7 @@ void rdar12280665() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_assumptions</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>8</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>8</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>50</integer>
@@ -1587,7 +1734,7 @@ void rdar12280665() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_cond_assign</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>58</integer>
@@ -1657,9 +1804,9 @@ void rdar12280665() {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -1730,7 +1877,7 @@ void rdar12280665() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
// CHECK-NEXT: <key>issue_context</key><string>test</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>77</integer>
@@ -1788,7 +1935,7 @@ void rdar12280665() {
// CHECK-NEXT: <key>type</key><string>Dead initialization</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
// CHECK-NEXT: <key>issue_context</key><string>test2</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>86</integer>
@@ -1950,7 +2097,7 @@ void rdar12280665() {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
// CHECK-NEXT: <key>issue_context</key><string>test2</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>88</integer>
@@ -2185,9 +2332,9 @@ void rdar12280665() {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -2258,7 +2405,7 @@ void rdar12280665() {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>rdar12280665</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>98</integer>
@@ -2266,4 +2413,2603 @@ void rdar12280665() {
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>107</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>108</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>108</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>108</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>108</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>108</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>108</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>108</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>108</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>108</integer>
+// CHECK-NEXT: <key>col</key><integer>28</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Assuming &apos;i&apos; is &gt;= &apos;x&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;i&apos; is &gt;= &apos;x&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>108</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>108</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>108</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>108</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>108</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>108</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>108</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>108</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>108</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>111</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>111</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>111</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>111</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>111</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>radar12322528_for</string>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>111</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>115</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>115</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>115</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>115</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>115</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>117</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>117</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>117</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>117</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>117</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>117</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>117</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>117</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>117</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Assuming &apos;i&apos; is &gt;= &apos;x&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;i&apos; is &gt;= &apos;x&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>117</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>117</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>117</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>117</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>117</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>117</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>117</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>117</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>117</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>121</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>121</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>121</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>121</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>121</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>radar12322528_while</string>
+// CHECK-NEXT: <key>issue_hash</key><string>7</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>121</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>125</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>125</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>125</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>125</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>125</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>126</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>126</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>126</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>126</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>127</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>127</integer>
+// CHECK-NEXT: <key>col</key><integer>6</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>127</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>127</integer>
+// CHECK-NEXT: <key>col</key><integer>6</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>129</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>129</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>129</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>129</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>126</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>126</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>126</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>126</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>126</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>126</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>126</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>127</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>127</integer>
+// CHECK-NEXT: <key>col</key><integer>6</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>127</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>127</integer>
+// CHECK-NEXT: <key>col</key><integer>6</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>128</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>128</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>128</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>128</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>130</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>130</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>130</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>130</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>130</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>radar12322528_foo_2</string>
+// CHECK-NEXT: <key>issue_hash</key><string>6</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>130</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>134</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>134</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>33</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>33</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>33</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>33</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>40</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>40</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>40</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>40</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>33</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>33</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>33</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>33</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>37</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;p&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;p&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>33</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>33</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>40</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>40</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>40</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>40</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>135</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>136</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>136</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>136</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>136</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>136</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_loop_diagnostics</string>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>136</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>140</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>140</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>141</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>141</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>141</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>141</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>142</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>142</integer>
+// CHECK-NEXT: <key>col</key><integer>6</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>142</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>142</integer>
+// CHECK-NEXT: <key>col</key><integer>6</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>144</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>144</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>144</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>144</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>141</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>141</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>141</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>141</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>141</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>141</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>141</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>142</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>142</integer>
+// CHECK-NEXT: <key>col</key><integer>6</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>142</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>142</integer>
+// CHECK-NEXT: <key>col</key><integer>6</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>143</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>143</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>143</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>143</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>143</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;p&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;p&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>143</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>143</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>144</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>144</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>144</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>144</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>141</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>141</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>141</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>141</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>141</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>141</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>141</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>145</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>145</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>145</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>145</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>145</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_loop_diagnostics_2</string>
+// CHECK-NEXT: <key>issue_hash</key><string>6</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>145</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>149</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>149</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>151</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>151</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>151</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>151</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>152</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>152</integer>
+// CHECK-NEXT: <key>col</key><integer>6</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>152</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>152</integer>
+// CHECK-NEXT: <key>col</key><integer>6</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>154</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>154</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>154</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>154</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>151</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>151</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>151</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>151</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>151</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>151</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>151</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>152</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>152</integer>
+// CHECK-NEXT: <key>col</key><integer>6</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>152</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>152</integer>
+// CHECK-NEXT: <key>col</key><integer>6</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>153</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>153</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>153</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>153</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>153</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;p&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;p&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>153</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>153</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>154</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>154</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>154</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>154</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>151</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>151</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>151</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>151</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>151</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Looping back to the head of the loop</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>151</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>151</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>155</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>155</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>155</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>155</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>155</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from variable &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_loop_diagnostics_3</string>
+// CHECK-NEXT: <key>issue_hash</key><string>7</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>155</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>159</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>159</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>159</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;x&apos; declared without an initial value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;x&apos; declared without an initial value</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>159</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>159</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>160</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>160</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>160</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>160</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>160</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Loop body executed 0 times</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>160</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>160</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>163</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>163</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>163</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>163</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>163</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>The left expression of the compound assignment is an uninitialized value. The computed value will also be garbage</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Assigned value is garbage or undefined</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_loop_fast_enumeration</string>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>163</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>163</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>163</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>163</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Value stored to &apos;x&apos; is never read</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Value stored to &apos;x&apos; is never read</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Value stored to &apos;x&apos; is never read</string>
+// CHECK-NEXT: <key>category</key><string>Dead store</string>
+// CHECK-NEXT: <key>type</key><string>Dead increment</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_loop_fast_enumeration</string>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>163</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>171</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>171</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>171</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;p&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;p&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>171</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>171</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>172</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>172</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>172</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>172</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>172</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from ivar &apos;p&apos;)</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Dereference of null pointer (loaded from ivar &apos;p&apos;)</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Dereference of null pointer (loaded from ivar &apos;p&apos;)</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
+// CHECK-NEXT: <key>issue_context</key><string>test</string>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>172</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>182</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>182</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>182</integer>
+// CHECK-NEXT: <key>col</key><integer>25</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;s.i&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;s.i&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>182</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>182</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>184</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>184</integer>
+// CHECK-NEXT: <key>col</key><integer>16</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>184</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>184</integer>
+// CHECK-NEXT: <key>col</key><integer>18</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>184</integer>
+// CHECK-NEXT: <key>col</key><integer>22</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Null pointer passed as an argument to a &apos;nonnull&apos; parameter</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Null pointer passed as an argument to a &apos;nonnull&apos; parameter</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Null pointer passed as an argument to a &apos;nonnull&apos; parameter</string>
+// CHECK-NEXT: <key>category</key><string>API</string>
+// CHECK-NEXT: <key>type</key><string>Argument with &apos;nonnull&apos; attribute passed null</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>RDar13295437</string>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>184</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
diff --git a/test/Analysis/pointer-to-member.cpp b/test/Analysis/pointer-to-member.cpp
index cef5dc5..84dfe30 100644
--- a/test/Analysis/pointer-to-member.cpp
+++ b/test/Analysis/pointer-to-member.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=inlining -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
void clang_analyzer_eval(bool);
diff --git a/test/Analysis/pr4209.m b/test/Analysis/pr4209.m
index a5e7db5..29abe94 100644
--- a/test/Analysis/pr4209.m
+++ b/test/Analysis/pr4209.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -analyze -analyzer-checker=core,alpha.core -analyzer-store=region -Wno-incomplete-implementation -verify %s
// This test case was crashing due to how CFRefCount.cpp resolved the
// ObjCInterfaceDecl* and ClassName in EvalObjCMessageExpr.
@@ -47,14 +47,14 @@ CMProfileLocation;
@interface GBCategoryChooserPanelController : NSWindowController {
GSEbayCategory *rootCategory;
}
-- (NSMutableDictionary*)categoryDictionaryForCategoryID:(int)inID inRootTreeCategories:(NSMutableArray*)inRootTreeCategories; // expected-note {{method definition for 'categoryDictionaryForCategoryID:inRootTreeCategories:' not found}}
--(NSString*) categoryID; // expected-note {{method definition for 'categoryID' not found}} expected-note {{using}}
+- (NSMutableDictionary*)categoryDictionaryForCategoryID:(int)inID inRootTreeCategories:(NSMutableArray*)inRootTreeCategories;
+-(NSString*) categoryID; // expected-note {{using}}
@end @interface GSEbayCategory : NSObject <NSCoding> {
}
- (int) categoryID; // expected-note {{also found}}
- (GSEbayCategory *) parent;
- (GSEbayCategory*) subcategoryWithID:(int) inID;
-@end @implementation GBCategoryChooserPanelController + (int) chooseCategoryIDFromCategories:(NSArray*) inCategories searchRequest:(GBSearchRequest*)inRequest parentWindow:(NSWindow*) inParent { // expected-warning {{incomplete implementation}}
+@end @implementation GBCategoryChooserPanelController + (int) chooseCategoryIDFromCategories:(NSArray*) inCategories searchRequest:(GBSearchRequest*)inRequest parentWindow:(NSWindow*) inParent {
return 0;
}
- (void) addCategory:(EBayCategoryType*)inCategory toRootTreeCategory:(NSMutableArray*)inRootTreeCategories {
diff --git a/test/Analysis/ptr-arith.c b/test/Analysis/ptr-arith.c
index 9294c18..35faff4 100644
--- a/test/Analysis/ptr-arith.c
+++ b/test/Analysis/ptr-arith.c
@@ -167,3 +167,116 @@ void PR7527 (int *p) {
if (((int) p) & 1) // not crash
return;
}
+
+void use_symbols(int *lhs, int *rhs) {
+ clang_analyzer_eval(lhs < rhs); // expected-warning{{UNKNOWN}}
+ if (lhs < rhs)
+ return;
+ clang_analyzer_eval(lhs < rhs); // expected-warning{{FALSE}}
+
+ clang_analyzer_eval(lhs - rhs); // expected-warning{{UNKNOWN}}
+ if ((lhs - rhs) != 5)
+ return;
+ clang_analyzer_eval((lhs - rhs) == 5); // expected-warning{{TRUE}}
+}
+
+void equal_implies_zero(int *lhs, int *rhs) {
+ clang_analyzer_eval(lhs == rhs); // expected-warning{{UNKNOWN}}
+ if (lhs == rhs) {
+ clang_analyzer_eval(lhs != rhs); // expected-warning{{FALSE}}
+ clang_analyzer_eval((rhs - lhs) == 0); // expected-warning{{TRUE}}
+ return;
+ }
+ clang_analyzer_eval(lhs == rhs); // expected-warning{{FALSE}}
+ clang_analyzer_eval(lhs != rhs); // expected-warning{{TRUE}}
+ clang_analyzer_eval((rhs - lhs) == 0); // expected-warning{{FALSE}}
+}
+
+void zero_implies_equal(int *lhs, int *rhs) {
+ clang_analyzer_eval((rhs - lhs) == 0); // expected-warning{{UNKNOWN}}
+ if ((rhs - lhs) == 0) {
+ clang_analyzer_eval(lhs != rhs); // expected-warning{{FALSE}}
+ clang_analyzer_eval(lhs == rhs); // expected-warning{{TRUE}}
+ return;
+ }
+ clang_analyzer_eval((rhs - lhs) == 0); // expected-warning{{FALSE}}
+ clang_analyzer_eval(lhs == rhs); // expected-warning{{FALSE}}
+ clang_analyzer_eval(lhs != rhs); // expected-warning{{TRUE}}
+}
+
+void comparisons_imply_size(int *lhs, int *rhs) {
+ clang_analyzer_eval(lhs <= rhs); // expected-warning{{UNKNOWN}}
+
+ if (lhs > rhs) {
+ clang_analyzer_eval((rhs - lhs) == 0); // expected-warning{{FALSE}}
+ return;
+ }
+
+ clang_analyzer_eval(lhs <= rhs); // expected-warning{{TRUE}}
+ clang_analyzer_eval((rhs - lhs) >= 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval((rhs - lhs) > 0); // expected-warning{{UNKNOWN}}
+
+ if (lhs >= rhs) {
+ clang_analyzer_eval((rhs - lhs) == 0); // expected-warning{{TRUE}}
+ return;
+ }
+
+ clang_analyzer_eval(lhs == rhs); // expected-warning{{FALSE}}
+ clang_analyzer_eval(lhs < rhs); // expected-warning{{TRUE}}
+ clang_analyzer_eval((rhs - lhs) > 0); // expected-warning{{TRUE}}
+}
+
+void size_implies_comparison(int *lhs, int *rhs) {
+ clang_analyzer_eval(lhs <= rhs); // expected-warning{{UNKNOWN}}
+
+ if ((rhs - lhs) < 0) {
+ clang_analyzer_eval(lhs == rhs); // expected-warning{{FALSE}}
+ return;
+ }
+
+ clang_analyzer_eval(lhs <= rhs); // expected-warning{{TRUE}}
+ clang_analyzer_eval((rhs - lhs) >= 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval((rhs - lhs) > 0); // expected-warning{{UNKNOWN}}
+
+ if ((rhs - lhs) <= 0) {
+ clang_analyzer_eval(lhs == rhs); // expected-warning{{TRUE}}
+ return;
+ }
+
+ clang_analyzer_eval(lhs == rhs); // expected-warning{{FALSE}}
+ clang_analyzer_eval(lhs < rhs); // expected-warning{{TRUE}}
+ clang_analyzer_eval((rhs - lhs) > 0); // expected-warning{{TRUE}}
+}
+
+//-------------------------------
+// False positives
+//-------------------------------
+
+void zero_implies_reversed_equal(int *lhs, int *rhs) {
+ clang_analyzer_eval((rhs - lhs) == 0); // expected-warning{{UNKNOWN}}
+ if ((rhs - lhs) == 0) {
+ // FIXME: Should be FALSE.
+ clang_analyzer_eval(rhs != lhs); // expected-warning{{UNKNOWN}}
+ // FIXME: Should be TRUE.
+ clang_analyzer_eval(rhs == lhs); // expected-warning{{UNKNOWN}}
+ return;
+ }
+ clang_analyzer_eval((rhs - lhs) == 0); // expected-warning{{FALSE}}
+ // FIXME: Should be FALSE.
+ clang_analyzer_eval(rhs == lhs); // expected-warning{{UNKNOWN}}
+ // FIXME: Should be TRUE.
+ clang_analyzer_eval(rhs != lhs); // expected-warning{{UNKNOWN}}
+}
+
+void canonical_equal(int *lhs, int *rhs) {
+ clang_analyzer_eval(lhs == rhs); // expected-warning{{UNKNOWN}}
+ if (lhs == rhs) {
+ // FIXME: Should be TRUE.
+ clang_analyzer_eval(rhs == lhs); // expected-warning{{UNKNOWN}}
+ return;
+ }
+ clang_analyzer_eval(lhs == rhs); // expected-warning{{FALSE}}
+
+ // FIXME: Should be FALSE.
+ clang_analyzer_eval(rhs == lhs); // expected-warning{{UNKNOWN}}
+}
diff --git a/test/Analysis/refcnt_naming.m b/test/Analysis/refcnt_naming.m
index 7a83fc1..cff5970 100644
--- a/test/Analysis/refcnt_naming.m
+++ b/test/Analysis/refcnt_naming.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core -analyzer-ipa=none -analyzer-store=region -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,osx.cocoa.RetainCount,alpha.core -analyzer-config ipa=none -analyzer-store=region -verify %s
typedef const struct __CFString * CFStringRef;
typedef const struct __CFAllocator * CFAllocatorRef;
diff --git a/test/Analysis/reference.cpp b/test/Analysis/reference.cpp
index ce0ee8e..8dd0baf 100644
--- a/test/Analysis/reference.cpp
+++ b/test/Analysis/reference.cpp
@@ -135,21 +135,92 @@ void testFunctionPointerReturn(void *opaque) {
clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
}
+int &testReturnNullReference() {
+ int *x = 0;
+ return *x; // expected-warning{{Returning null reference}}
+}
+
+char &refFromPointer() {
+ return *ptr();
+}
+
+void testReturnReference() {
+ clang_analyzer_eval(ptr() == 0); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(&refFromPointer() == 0); // expected-warning{{FALSE}}
+}
+
+void intRefParam(int &r) {
+ ;
+}
-// ------------------------------------
-// False negatives
-// ------------------------------------
+void test(int *ptr) {
+ clang_analyzer_eval(ptr == 0); // expected-warning{{UNKNOWN}}
+
+ extern void use(int &ref);
+ use(*ptr);
+
+ clang_analyzer_eval(ptr == 0); // expected-warning{{FALSE}}
+}
+
+void testIntRefParam() {
+ int i = 0;
+ intRefParam(i); // no-warning
+}
+
+int refParam(int &byteIndex) {
+ return byteIndex;
+}
+
+void testRefParam(int *p) {
+ if (p)
+ ;
+ refParam(*p); // expected-warning {{Forming reference to null pointer}}
+}
+
+int ptrRefParam(int *&byteIndex) {
+ return *byteIndex; // expected-warning {{Dereference of null pointer}}
+}
+void testRefParam2() {
+ int *p = 0;
+ int *&rp = p;
+ ptrRefParam(rp);
+}
+
+int *maybeNull() {
+ extern bool coin();
+ static int x;
+ return coin() ? &x : 0;
+}
+
+void use(int &x) {
+ x = 1; // no-warning
+}
+
+void testSuppression() {
+ use(*maybeNull());
+}
namespace rdar11212286 {
class B{};
B test() {
B *x = 0;
- return *x; // should warn here!
+ return *x; // expected-warning {{Forming reference to null pointer}}
}
- B &testRef() {
- B *x = 0;
- return *x; // should warn here!
+ B testif(B *x) {
+ if (x)
+ ;
+ return *x; // expected-warning {{Forming reference to null pointer}}
+ }
+
+ void idc(B *x) {
+ if (x)
+ ;
+ }
+
+ B testidc(B *x) {
+ idc(x);
+ return *x; // no-warning
}
}
diff --git a/test/Analysis/reference.mm b/test/Analysis/reference.mm
new file mode 100644
index 0000000..c5546aa
--- /dev/null
+++ b/test/Analysis/reference.mm
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -Wno-null-dereference %s
+
+@interface Foo
+- (int &)ref;
+@end
+
+Foo *getFoo() { return 0; }
+
+void testNullPointerSuppression() {
+ getFoo().ref = 1;
+}
+
+void testPositiveNullReference() {
+ Foo *x = 0;
+ x.ref = 1; // expected-warning {{The receiver of message 'ref' is nil, which results in forming a null reference}}
+}
+
diff --git a/test/Analysis/region-store.c b/test/Analysis/region-store.c
index d620150..70bda11 100644
--- a/test/Analysis/region-store.c
+++ b/test/Analysis/region-store.c
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix -verify %s
-// expected-no-diagnostics
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix,debug.ExprInspection -verify %s
int printf(const char *restrict,...);
@@ -22,3 +21,36 @@ int compoundLiteralTest2() {
}
return 0;
}
+
+int concreteOffsetBindingIsInvalidatedBySymbolicOffsetAssignment(int length,
+ int i) {
+ int values[length];
+ values[i] = 4;
+ return values[0]; // no-warning
+}
+
+struct X{
+ int mem;
+};
+int initStruct(struct X *st);
+int structOffsetBindingIsInvalidated(int length, int i){
+ struct X l;
+ initStruct(&l);
+ return l.mem; // no-warning
+}
+
+void clang_analyzer_eval(int);
+void testConstraintOnRegionOffset(int *values, int length, int i){
+ if (values[1] == 4) {
+ values[i] = 5;
+ clang_analyzer_eval(values[1] == 4);// expected-warning {{UNKNOWN}}
+ }
+}
+
+int initArray(int *values);
+void testConstraintOnRegionOffsetStack(int *values, int length, int i) {
+ if (values[0] == 4) {
+ initArray(values);
+ clang_analyzer_eval(values[0] == 4);// expected-warning {{UNKNOWN}}
+ }
+}
diff --git a/test/Analysis/region-store.cpp b/test/Analysis/region-store.cpp
new file mode 100644
index 0000000..5ea5c3f
--- /dev/null
+++ b/test/Analysis/region-store.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix -verify %s
+// expected-no-diagnostics
+
+class Loc {
+ int x;
+};
+class P1 {
+public:
+ Loc l;
+ void setLoc(Loc L) {
+ l = L;
+ }
+
+};
+class P2 {
+public:
+ int m;
+ int accessBase() {
+ return m;
+ }
+};
+class Derived: public P1, public P2 {
+};
+int radar13445834(Derived *Builder, Loc l) {
+ Builder->setLoc(l);
+ return Builder->accessBase();
+
+} \ No newline at end of file
diff --git a/test/Analysis/reinterpret-cast.cpp b/test/Analysis/reinterpret-cast.cpp
index 73f2e2d..59e6a53 100644
--- a/test/Analysis/reinterpret-cast.cpp
+++ b/test/Analysis/reinterpret-cast.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=inlining -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify %s
void clang_analyzer_eval(bool);
@@ -18,3 +18,71 @@ void test(Data data) {
wrapper->set();
clang_analyzer_eval(wrapper->x == 42); // expected-warning{{TRUE}}
}
+
+namespace PR14872 {
+ class Base1 {};
+ class Derived1 : public Base1 {};
+
+ Derived1 *f1();
+
+ class Base2 {};
+ class Derived2 : public Base2 {};
+
+ void f2(Base2 *foo);
+
+ void f3(void** out)
+ {
+ Base1 *v;
+ v = f1();
+ *out = v;
+ }
+
+ void test()
+ {
+ Derived2 *p;
+ f3(reinterpret_cast<void**>(&p));
+ // Don't crash when upcasting here.
+ // In this case, 'p' actually refers to a Derived1.
+ f2(p);
+ }
+}
+
+namespace rdar13249297 {
+ struct IntWrapperSubclass : public IntWrapper {};
+
+ struct IntWrapperWrapper {
+ IntWrapper w;
+ };
+
+ void test(IntWrapperWrapper *ww) {
+ reinterpret_cast<IntWrapperSubclass *>(ww)->x = 42;
+ clang_analyzer_eval(reinterpret_cast<IntWrapperSubclass *>(ww)->x == 42); // expected-warning{{TRUE}}
+
+ clang_analyzer_eval(ww->w.x == 42); // expected-warning{{TRUE}}
+ ww->w.x = 0;
+
+ clang_analyzer_eval(reinterpret_cast<IntWrapperSubclass *>(ww)->x == 42); // expected-warning{{FALSE}}
+ }
+}
+
+namespace PR15345 {
+ class C {};
+
+ class Base {
+ public:
+ void (*f)();
+ int x;
+ };
+
+ class Derived : public Base {};
+
+ void test() {
+ Derived* p;
+ *(reinterpret_cast<void**>(&p)) = new C;
+ p->f();
+
+ // We should still be able to do some reasoning about bindings.
+ p->x = 42;
+ clang_analyzer_eval(p->x == 42); // expected-warning{{TRUE}}
+ };
+}
diff --git a/test/Analysis/retain-release-cf-audited.m b/test/Analysis/retain-release-cf-audited.m
new file mode 100644
index 0000000..c89172f
--- /dev/null
+++ b/test/Analysis/retain-release-cf-audited.m
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,osx.cocoa.RetainCount -verify %s -x objective-c++
+
+// The special thing about this file is that CFRetain and CFRelease are marked
+// as cf_audited_transfer.
+
+#pragma clang arc_cf_code_audited begin
+typedef const void * CFTypeRef;
+extern CFTypeRef CFRetain(CFTypeRef cf);
+extern void CFRelease(CFTypeRef cf);
+
+extern CFTypeRef CFCreateSomethingAudited();
+#pragma clang arc_cf_code_audited end
+
+extern CFTypeRef CFCreateSomethingUnaudited();
+
+void testAudited() {
+ CFTypeRef obj = CFCreateSomethingAudited(); // no-warning
+ CFRelease(obj); // no-warning
+
+ CFTypeRef obj2 = CFCreateSomethingAudited(); // expected-warning{{leak}}
+ CFRetain(obj2); // no-warning
+ CFRelease(obj2); // no-warning
+}
+
+void testUnaudited() {
+ CFTypeRef obj = CFCreateSomethingUnaudited(); // no-warning
+ CFRelease(obj); // no-warning
+
+ CFTypeRef obj2 = CFCreateSomethingUnaudited(); // expected-warning{{leak}}
+ CFRetain(obj2); // no-warning
+ CFRelease(obj2); // no-warning
+}
diff --git a/test/Analysis/retain-release-inline.m b/test/Analysis/retain-release-inline.m
index 6ff9e9a..8809c8c 100644
--- a/test/Analysis/retain-release-inline.m
+++ b/test/Analysis/retain-release-inline.m
@@ -361,3 +361,35 @@ CFStringRef testCovariantReturnType() {
}
return Str;
}
+
+// Test that we reanalyze ObjC methods which have been inlined. When reanalyzing
+// them, make sure we inline very small functions.
+id returnInputParam(id x) {
+ return x;
+}
+
+@interface MyClass : NSObject
+- (id)test_reanalyze_as_top_level;
+- (void)test_inline_tiny_when_reanalyzing;
+- (void)inline_test_reanalyze_as_top_level;
+@end
+
+@implementation MyClass
+- (void)test_inline_tiny_when_reanalyzing {
+ id x = [[NSString alloc] init]; // no-warning
+ x = returnInputParam(x);
+ [x release];
+}
+
+- (id)test_reanalyze_as_top_level {
+ // This method does not follow naming conventions, so a warning will be
+ // reported when it is reanalyzed at top level.
+ return [[NSString alloc] init]; // expected-warning {{leak}}
+}
+
+- (void)inline_test_reanalyze_as_top_level {
+ id x = [self test_reanalyze_as_top_level];
+ [x release];
+ [self test_inline_tiny_when_reanalyzing];
+}
+@end
diff --git a/test/Analysis/retain-release-path-notes-gc.m b/test/Analysis/retain-release-path-notes-gc.m
index c24bf70..913714e 100644
--- a/test/Analysis/retain-release-path-notes-gc.m
+++ b/test/Analysis/retain-release-path-notes-gc.m
@@ -210,7 +210,7 @@ void retainReleaseIgnored () {
// CHECK-NEXT: <key>type</key><string>Leak of object when using garbage collection</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>creationViaCFCreate</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>44</integer>
@@ -653,7 +653,7 @@ void retainReleaseIgnored () {
// CHECK-NEXT: <key>type</key><string>Leak of object when using garbage collection</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>makeCollectable</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>6</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>6</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>53</integer>
@@ -1021,7 +1021,7 @@ void retainReleaseIgnored () {
// CHECK-NEXT: <key>type</key><string>Bad release</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>retainReleaseIgnored</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>61</integer>
@@ -1205,7 +1205,7 @@ void retainReleaseIgnored () {
// CHECK-NEXT: <key>type</key><string>Leak of returned object when using garbage collection</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
// CHECK-NEXT: <key>issue_context</key><string>getViolation</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>67</integer>
@@ -1389,7 +1389,7 @@ void retainReleaseIgnored () {
// CHECK-NEXT: <key>type</key><string>Leak of returned object when using garbage collection</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
// CHECK-NEXT: <key>issue_context</key><string>copyViolation</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>72</integer>
diff --git a/test/Analysis/retain-release-path-notes.m b/test/Analysis/retain-release-path-notes.m
index 0daeecb..8809c57 100644
--- a/test/Analysis/retain-release-path-notes.m
+++ b/test/Analysis/retain-release-path-notes.m
@@ -138,7 +138,7 @@ CFTypeRef CFGetRuleViolation () {
- (id)copyAutorelease {
id result = [[Foo alloc] init]; // expected-note{{Method returns an Objective-C object with a +1 retain count}}
[result autorelease]; // expected-note{{Object sent -autorelease message}}
- return result; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object returned to caller with a +0 retain count}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
+ return result; // expected-warning{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}} expected-note{{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
}
@end
@@ -328,7 +328,7 @@ void testDictionary(id key, id value) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>creationViaAlloc</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>47</integer>
@@ -471,7 +471,7 @@ void testDictionary(id key, id value) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>creationViaCFCreate</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>52</integer>
@@ -839,7 +839,7 @@ void testDictionary(id key, id value) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>acquisitionViaMethod</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>60</integer>
@@ -1057,7 +1057,7 @@ void testDictionary(id key, id value) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>acquisitionViaProperty</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>66</integer>
@@ -1275,7 +1275,7 @@ void testDictionary(id key, id value) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>acquisitionViaCFFunction</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>72</integer>
@@ -1493,7 +1493,7 @@ void testDictionary(id key, id value) {
// CHECK-NEXT: <key>type</key><string>Use-after-release</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>explicitDealloc</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>78</integer>
@@ -1711,7 +1711,7 @@ void testDictionary(id key, id value) {
// CHECK-NEXT: <key>type</key><string>Use-after-release</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>implicitDealloc</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>84</integer>
@@ -2004,7 +2004,7 @@ void testDictionary(id key, id value) {
// CHECK-NEXT: <key>type</key><string>Object sent -autorelease too many times</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>overAutorelease</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>91</integer>
@@ -2222,7 +2222,7 @@ void testDictionary(id key, id value) {
// CHECK-NEXT: <key>type</key><string>Object sent -autorelease too many times</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>autoreleaseUnowned</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>97</integer>
@@ -2515,7 +2515,7 @@ void testDictionary(id key, id value) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>makeCollectableIgnored</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>104</integer>
@@ -2699,7 +2699,7 @@ void testDictionary(id key, id value) {
// CHECK-NEXT: <key>type</key><string>Method should return an owned object</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>CFCopyRuleViolation</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>109</integer>
@@ -2883,7 +2883,7 @@ void testDictionary(id key, id value) {
// CHECK-NEXT: <key>type</key><string>Leak of returned object</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>CFGetRuleViolation</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>114</integer>
@@ -3067,7 +3067,7 @@ void testDictionary(id key, id value) {
// CHECK-NEXT: <key>type</key><string>Method should return an owned object</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
// CHECK-NEXT: <key>issue_context</key><string>copyViolation</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>120</integer>
@@ -3251,7 +3251,7 @@ void testDictionary(id key, id value) {
// CHECK-NEXT: <key>type</key><string>Method should return an owned object</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
// CHECK-NEXT: <key>issue_context</key><string>copyViolationIndexedSubscript</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>125</integer>
@@ -3435,7 +3435,7 @@ void testDictionary(id key, id value) {
// CHECK-NEXT: <key>type</key><string>Method should return an owned object</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
// CHECK-NEXT: <key>issue_context</key><string>copyViolationKeyedSubscript</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>130</integer>
@@ -3619,7 +3619,7 @@ void testDictionary(id key, id value) {
// CHECK-NEXT: <key>type</key><string>Leak of returned object</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
// CHECK-NEXT: <key>issue_context</key><string>getViolation</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>135</integer>
@@ -3824,47 +3824,6 @@ void testDictionary(id key, id value) {
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>141</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>141</integer>
-// CHECK-NEXT: <key>col</key><integer>15</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Object returned to caller with a +0 retain count</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Object returned to caller with a +0 retain count</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>141</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>141</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>141</integer>
-// CHECK-NEXT: <key>col</key><integer>15</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
@@ -3878,7 +3837,7 @@ void testDictionary(id key, id value) {
// CHECK-NEXT: <key>type</key><string>Method should return an owned object</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
// CHECK-NEXT: <key>issue_context</key><string>copyAutorelease</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>141</integer>
@@ -4021,7 +3980,7 @@ void testDictionary(id key, id value) {
// CHECK-NEXT: <key>type</key><string>Bad release</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testNumericLiteral</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>170</integer>
@@ -4164,7 +4123,7 @@ void testDictionary(id key, id value) {
// CHECK-NEXT: <key>type</key><string>Bad release</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testBoxedInt</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>175</integer>
@@ -4307,7 +4266,7 @@ void testDictionary(id key, id value) {
// CHECK-NEXT: <key>type</key><string>Bad release</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testBoxedString</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>180</integer>
@@ -4450,7 +4409,7 @@ void testDictionary(id key, id value) {
// CHECK-NEXT: <key>type</key><string>Bad release</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testArray</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>185</integer>
@@ -4593,7 +4552,7 @@ void testDictionary(id key, id value) {
// CHECK-NEXT: <key>type</key><string>Bad release</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testDictionary</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>190</integer>
diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m
index eb2554f..5841650 100644
--- a/test/Analysis/retain-release.m
+++ b/test/Analysis/retain-release.m
@@ -25,6 +25,9 @@
#if __has_feature(attribute_cf_consumed)
#define CF_CONSUMED __attribute__((cf_consumed))
#endif
+#if __has_attribute(ns_returns_autoreleased)
+#define NS_RETURNS_AUTORELEASED __attribute__((ns_returns_autoreleased))
+#endif
//===----------------------------------------------------------------------===//
// The following code is reduced using delta-debugging from Mac OS X headers:
@@ -132,6 +135,7 @@ typedef struct _NSZone NSZone;
@interface NSObject <NSObject> {}
+ (id)allocWithZone:(NSZone *)zone;
+ (id)alloc;
++ (id)new;
- (void)dealloc;
@end
@interface NSObject (NSCoderMethods)
@@ -474,8 +478,8 @@ void f13_autorelease() {
void f13_autorelease_b() {
CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks);
[(id) A autorelease];
- [(id) A autorelease]; // expected-warning{{Object sent -autorelease too many times}}
-}
+ [(id) A autorelease];
+} // expected-warning{{Object sent -autorelease too many times}}
CFMutableArrayRef f13_autorelease_c() {
CFMutableArrayRef A = CFArrayCreateMutable(0, 10, &kCFTypeArrayCallBacks);
@@ -862,6 +866,13 @@ static void PR4230(void)
return;
}
+static void PR4230_new(void)
+{
+ NSAutoreleasePool *pool = [NSAutoreleasePool new]; // no-warning
+ NSString *object = [[[NSString alloc] init] autorelease]; // no-warning
+ return;
+}
+
//===----------------------------------------------------------------------===//
// Method name that has a null IdentifierInfo* for its first selector slot.
// This test just makes sure that we handle it.
@@ -1300,6 +1311,7 @@ typedef NSString* MyStringTy;
- (NSString*) returnsAnOwnedCFString CF_RETURNS_RETAINED; // no-warning
- (MyStringTy) returnsAnOwnedTypedString NS_RETURNS_RETAINED; // no-warning
- (NSString*) newString NS_RETURNS_NOT_RETAINED; // no-warning
+- (NSString*) newString_auto NS_RETURNS_AUTORELEASED; // no-warning
- (NSString*) newStringNoAttr;
- (int) returnsAnOwnedInt NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to methods that return an Objective-C object}}
- (id) pseudoInit NS_CONSUMES_SELF NS_RETURNS_RETAINED;
@@ -1320,6 +1332,8 @@ void test_attr_1b(TestOwnershipAttr *X) {
void test_attr1c(TestOwnershipAttr *X) {
NSString *str = [X newString]; // no-warning
NSString *str2 = [X newStringNoAttr]; // expected-warning{{leak}}
+ NSString *str3 = [X newString_auto]; // no-warning
+ NSString *str4 = [[X newString_auto] retain]; // expected-warning {{leak}}
}
void testattr2_a() {
@@ -1770,6 +1784,13 @@ extern id NSApp;
id contextObject = (id)contextInfo;
[contextObject release];
}
+
+- (id)copyAutoreleaseRadar13081402 {
+ id x = [[[NSString alloc] initWithUTF8String:"foo"] autorelease];
+ [x retain];
+ return x; // no warning
+}
+
@end
//===----------------------------------------------------------------------===//
// Test returning allocated memory in a struct.
@@ -1932,6 +1953,37 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
CFPlugInInstanceCreate(kCFAllocatorDefault, factoryUUID, typeUUID); // no-warning
}
+//===----------------------------------------------------------------------===//
+// PR14927: -drain only has retain-count semantics on NSAutoreleasePool.
+//===----------------------------------------------------------------------===//
+
+@interface PR14927 : NSObject
+- (void)drain;
+@end
+
+void test_drain() {
+ PR14927 *obj = [[PR14927 alloc] init];
+ [obj drain];
+ [obj release]; // no-warning
+}
+
+//===----------------------------------------------------------------------===//
+// Allow cf_returns_retained and cf_returns_not_retained to mark a return
+// value as tracked, even if the object isn't a known CF type.
+//===----------------------------------------------------------------------===//
+
+MyCFType getCustom() __attribute__((cf_returns_not_retained));
+MyCFType makeCustom() __attribute__((cf_returns_retained));
+
+void testCustomReturnsRetained() {
+ MyCFType obj = makeCustom(); // expected-warning {{leak of an object stored into 'obj'}}
+}
+
+void testCustomReturnsNotRetained() {
+ CFRelease(getCustom()); // expected-warning {{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
+}
+
+
// CHECK: <key>diagnostics</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
@@ -1945,12 +1997,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>319</integer>
+// CHECK-NEXT: <key>line</key><integer>324</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>319</integer>
+// CHECK-NEXT: <key>line</key><integer>324</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1958,12 +2010,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>320</integer>
+// CHECK-NEXT: <key>line</key><integer>325</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>320</integer>
+// CHECK-NEXT: <key>line</key><integer>325</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1979,12 +2031,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>320</integer>
+// CHECK-NEXT: <key>line</key><integer>325</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>320</integer>
+// CHECK-NEXT: <key>line</key><integer>325</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1992,12 +2044,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>320</integer>
+// CHECK-NEXT: <key>line</key><integer>325</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>320</integer>
+// CHECK-NEXT: <key>line</key><integer>325</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2009,7 +2061,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>320</integer>
+// CHECK-NEXT: <key>line</key><integer>325</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2017,12 +2069,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>320</integer>
+// CHECK-NEXT: <key>line</key><integer>325</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>320</integer>
+// CHECK-NEXT: <key>line</key><integer>325</integer>
// CHECK-NEXT: <key>col</key><integer>37</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2042,12 +2094,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>320</integer>
+// CHECK-NEXT: <key>line</key><integer>325</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>320</integer>
+// CHECK-NEXT: <key>line</key><integer>325</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2055,12 +2107,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>321</integer>
+// CHECK-NEXT: <key>line</key><integer>326</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>321</integer>
+// CHECK-NEXT: <key>line</key><integer>326</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2072,7 +2124,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>321</integer>
+// CHECK-NEXT: <key>line</key><integer>326</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2080,24 +2132,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>321</integer>
+// CHECK-NEXT: <key>line</key><integer>326</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>321</integer>
+// CHECK-NEXT: <key>line</key><integer>326</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>321</integer>
+// CHECK-NEXT: <key>line</key><integer>326</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>321</integer>
+// CHECK-NEXT: <key>line</key><integer>326</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2117,12 +2169,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>321</integer>
+// CHECK-NEXT: <key>line</key><integer>326</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>321</integer>
+// CHECK-NEXT: <key>line</key><integer>326</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2130,12 +2182,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>322</integer>
+// CHECK-NEXT: <key>line</key><integer>327</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>322</integer>
+// CHECK-NEXT: <key>line</key><integer>327</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2147,7 +2199,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>322</integer>
+// CHECK-NEXT: <key>line</key><integer>327</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2155,24 +2207,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>322</integer>
+// CHECK-NEXT: <key>line</key><integer>327</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>322</integer>
+// CHECK-NEXT: <key>line</key><integer>327</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>322</integer>
+// CHECK-NEXT: <key>line</key><integer>327</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>322</integer>
+// CHECK-NEXT: <key>line</key><integer>327</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2192,12 +2244,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>322</integer>
+// CHECK-NEXT: <key>line</key><integer>327</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>322</integer>
+// CHECK-NEXT: <key>line</key><integer>327</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2205,12 +2257,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>324</integer>
+// CHECK-NEXT: <key>line</key><integer>329</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>324</integer>
+// CHECK-NEXT: <key>line</key><integer>329</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2222,7 +2274,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>324</integer>
+// CHECK-NEXT: <key>line</key><integer>329</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2230,24 +2282,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>324</integer>
+// CHECK-NEXT: <key>line</key><integer>329</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>324</integer>
+// CHECK-NEXT: <key>line</key><integer>329</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>324</integer>
+// CHECK-NEXT: <key>line</key><integer>329</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>324</integer>
+// CHECK-NEXT: <key>line</key><integer>329</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2267,12 +2319,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>324</integer>
+// CHECK-NEXT: <key>line</key><integer>329</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>324</integer>
+// CHECK-NEXT: <key>line</key><integer>329</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2280,12 +2332,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>325</integer>
+// CHECK-NEXT: <key>line</key><integer>330</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>325</integer>
+// CHECK-NEXT: <key>line</key><integer>330</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2301,12 +2353,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>325</integer>
+// CHECK-NEXT: <key>line</key><integer>330</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>325</integer>
+// CHECK-NEXT: <key>line</key><integer>330</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2314,12 +2366,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>325</integer>
+// CHECK-NEXT: <key>line</key><integer>330</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>325</integer>
+// CHECK-NEXT: <key>line</key><integer>330</integer>
// CHECK-NEXT: <key>col</key><integer>27</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2331,7 +2383,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>325</integer>
+// CHECK-NEXT: <key>line</key><integer>330</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2339,12 +2391,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>325</integer>
+// CHECK-NEXT: <key>line</key><integer>330</integer>
// CHECK-NEXT: <key>col</key><integer>29</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>325</integer>
+// CHECK-NEXT: <key>line</key><integer>330</integer>
// CHECK-NEXT: <key>col</key><integer>32</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2362,10 +2414,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Use-after-release</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>f1</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>7</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>7</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>325</integer>
+// CHECK-NEXT: <key>line</key><integer>330</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2381,12 +2433,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>330</integer>
+// CHECK-NEXT: <key>line</key><integer>335</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>330</integer>
+// CHECK-NEXT: <key>line</key><integer>335</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2394,12 +2446,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>331</integer>
+// CHECK-NEXT: <key>line</key><integer>336</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>331</integer>
+// CHECK-NEXT: <key>line</key><integer>336</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2415,12 +2467,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>331</integer>
+// CHECK-NEXT: <key>line</key><integer>336</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>331</integer>
+// CHECK-NEXT: <key>line</key><integer>336</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2428,12 +2480,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>331</integer>
+// CHECK-NEXT: <key>line</key><integer>336</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>331</integer>
+// CHECK-NEXT: <key>line</key><integer>336</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2445,7 +2497,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>331</integer>
+// CHECK-NEXT: <key>line</key><integer>336</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2453,12 +2505,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>331</integer>
+// CHECK-NEXT: <key>line</key><integer>336</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>331</integer>
+// CHECK-NEXT: <key>line</key><integer>336</integer>
// CHECK-NEXT: <key>col</key><integer>37</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2478,12 +2530,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>331</integer>
+// CHECK-NEXT: <key>line</key><integer>336</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>331</integer>
+// CHECK-NEXT: <key>line</key><integer>336</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2491,12 +2543,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>332</integer>
+// CHECK-NEXT: <key>line</key><integer>337</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>332</integer>
+// CHECK-NEXT: <key>line</key><integer>337</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2508,7 +2560,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>332</integer>
+// CHECK-NEXT: <key>line</key><integer>337</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2516,24 +2568,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>332</integer>
+// CHECK-NEXT: <key>line</key><integer>337</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>332</integer>
+// CHECK-NEXT: <key>line</key><integer>337</integer>
// CHECK-NEXT: <key>col</key><integer>27</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>332</integer>
+// CHECK-NEXT: <key>line</key><integer>337</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>332</integer>
+// CHECK-NEXT: <key>line</key><integer>337</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2553,12 +2605,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>332</integer>
+// CHECK-NEXT: <key>line</key><integer>337</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>332</integer>
+// CHECK-NEXT: <key>line</key><integer>337</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2566,12 +2618,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>333</integer>
+// CHECK-NEXT: <key>line</key><integer>338</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>333</integer>
+// CHECK-NEXT: <key>line</key><integer>338</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2583,7 +2635,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>333</integer>
+// CHECK-NEXT: <key>line</key><integer>338</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2591,24 +2643,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>333</integer>
+// CHECK-NEXT: <key>line</key><integer>338</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>333</integer>
+// CHECK-NEXT: <key>line</key><integer>338</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>333</integer>
+// CHECK-NEXT: <key>line</key><integer>338</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>333</integer>
+// CHECK-NEXT: <key>line</key><integer>338</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2628,12 +2680,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>333</integer>
+// CHECK-NEXT: <key>line</key><integer>338</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>333</integer>
+// CHECK-NEXT: <key>line</key><integer>338</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2641,12 +2693,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>335</integer>
+// CHECK-NEXT: <key>line</key><integer>340</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>335</integer>
+// CHECK-NEXT: <key>line</key><integer>340</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2658,7 +2710,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>335</integer>
+// CHECK-NEXT: <key>line</key><integer>340</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2666,24 +2718,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>335</integer>
+// CHECK-NEXT: <key>line</key><integer>340</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>335</integer>
+// CHECK-NEXT: <key>line</key><integer>340</integer>
// CHECK-NEXT: <key>col</key><integer>28</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>335</integer>
+// CHECK-NEXT: <key>line</key><integer>340</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>335</integer>
+// CHECK-NEXT: <key>line</key><integer>340</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2703,12 +2755,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>335</integer>
+// CHECK-NEXT: <key>line</key><integer>340</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>335</integer>
+// CHECK-NEXT: <key>line</key><integer>340</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2716,12 +2768,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>336</integer>
+// CHECK-NEXT: <key>line</key><integer>341</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>336</integer>
+// CHECK-NEXT: <key>line</key><integer>341</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2737,12 +2789,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>336</integer>
+// CHECK-NEXT: <key>line</key><integer>341</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>336</integer>
+// CHECK-NEXT: <key>line</key><integer>341</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2750,12 +2802,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>336</integer>
+// CHECK-NEXT: <key>line</key><integer>341</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>336</integer>
+// CHECK-NEXT: <key>line</key><integer>341</integer>
// CHECK-NEXT: <key>col</key><integer>27</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2767,7 +2819,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>336</integer>
+// CHECK-NEXT: <key>line</key><integer>341</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2775,12 +2827,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>336</integer>
+// CHECK-NEXT: <key>line</key><integer>341</integer>
// CHECK-NEXT: <key>col</key><integer>29</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>336</integer>
+// CHECK-NEXT: <key>line</key><integer>341</integer>
// CHECK-NEXT: <key>col</key><integer>32</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2798,10 +2850,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Use-after-release</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>f2</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>7</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>7</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>336</integer>
+// CHECK-NEXT: <key>line</key><integer>341</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2817,12 +2869,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>366</integer>
+// CHECK-NEXT: <key>line</key><integer>371</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>366</integer>
+// CHECK-NEXT: <key>line</key><integer>371</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2830,12 +2882,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>367</integer>
+// CHECK-NEXT: <key>line</key><integer>372</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>367</integer>
+// CHECK-NEXT: <key>line</key><integer>372</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2851,12 +2903,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>367</integer>
+// CHECK-NEXT: <key>line</key><integer>372</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>367</integer>
+// CHECK-NEXT: <key>line</key><integer>372</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2864,12 +2916,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>367</integer>
+// CHECK-NEXT: <key>line</key><integer>372</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>367</integer>
+// CHECK-NEXT: <key>line</key><integer>372</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2881,7 +2933,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>367</integer>
+// CHECK-NEXT: <key>line</key><integer>372</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2889,12 +2941,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>367</integer>
+// CHECK-NEXT: <key>line</key><integer>372</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>367</integer>
+// CHECK-NEXT: <key>line</key><integer>372</integer>
// CHECK-NEXT: <key>col</key><integer>37</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2914,12 +2966,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>367</integer>
+// CHECK-NEXT: <key>line</key><integer>372</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>367</integer>
+// CHECK-NEXT: <key>line</key><integer>372</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2927,12 +2979,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>369</integer>
+// CHECK-NEXT: <key>line</key><integer>374</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>369</integer>
+// CHECK-NEXT: <key>line</key><integer>374</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2948,12 +3000,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>369</integer>
+// CHECK-NEXT: <key>line</key><integer>374</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>369</integer>
+// CHECK-NEXT: <key>line</key><integer>374</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2961,12 +3013,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>369</integer>
+// CHECK-NEXT: <key>line</key><integer>374</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>369</integer>
+// CHECK-NEXT: <key>line</key><integer>374</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2978,7 +3030,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>369</integer>
+// CHECK-NEXT: <key>line</key><integer>374</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -2986,12 +3038,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>369</integer>
+// CHECK-NEXT: <key>line</key><integer>374</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>369</integer>
+// CHECK-NEXT: <key>line</key><integer>374</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3011,12 +3063,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>369</integer>
+// CHECK-NEXT: <key>line</key><integer>374</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>369</integer>
+// CHECK-NEXT: <key>line</key><integer>374</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3024,12 +3076,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>372</integer>
+// CHECK-NEXT: <key>line</key><integer>377</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>372</integer>
+// CHECK-NEXT: <key>line</key><integer>377</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3045,12 +3097,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>372</integer>
+// CHECK-NEXT: <key>line</key><integer>377</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>372</integer>
+// CHECK-NEXT: <key>line</key><integer>377</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3058,12 +3110,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>372</integer>
+// CHECK-NEXT: <key>line</key><integer>377</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>372</integer>
+// CHECK-NEXT: <key>line</key><integer>377</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3075,7 +3127,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>372</integer>
+// CHECK-NEXT: <key>line</key><integer>377</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3083,12 +3135,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>372</integer>
+// CHECK-NEXT: <key>line</key><integer>377</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>372</integer>
+// CHECK-NEXT: <key>line</key><integer>377</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3106,10 +3158,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>f5</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>7</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>7</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>372</integer>
+// CHECK-NEXT: <key>line</key><integer>377</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3125,12 +3177,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>378</integer>
+// CHECK-NEXT: <key>line</key><integer>383</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>378</integer>
+// CHECK-NEXT: <key>line</key><integer>383</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3138,12 +3190,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>378</integer>
+// CHECK-NEXT: <key>line</key><integer>383</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>378</integer>
+// CHECK-NEXT: <key>line</key><integer>383</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3155,7 +3207,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>378</integer>
+// CHECK-NEXT: <key>line</key><integer>383</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3163,12 +3215,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>378</integer>
+// CHECK-NEXT: <key>line</key><integer>383</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>378</integer>
+// CHECK-NEXT: <key>line</key><integer>383</integer>
// CHECK-NEXT: <key>col</key><integer>62</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3188,12 +3240,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>378</integer>
+// CHECK-NEXT: <key>line</key><integer>383</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>378</integer>
+// CHECK-NEXT: <key>line</key><integer>383</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3201,12 +3253,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>379</integer>
+// CHECK-NEXT: <key>line</key><integer>384</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>379</integer>
+// CHECK-NEXT: <key>line</key><integer>384</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3218,7 +3270,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>379</integer>
+// CHECK-NEXT: <key>line</key><integer>384</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3226,24 +3278,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>379</integer>
+// CHECK-NEXT: <key>line</key><integer>384</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>379</integer>
+// CHECK-NEXT: <key>line</key><integer>384</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>379</integer>
+// CHECK-NEXT: <key>line</key><integer>384</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>379</integer>
+// CHECK-NEXT: <key>line</key><integer>384</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3263,12 +3315,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>379</integer>
+// CHECK-NEXT: <key>line</key><integer>384</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>379</integer>
+// CHECK-NEXT: <key>line</key><integer>384</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3276,12 +3328,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>380</integer>
+// CHECK-NEXT: <key>line</key><integer>385</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>380</integer>
+// CHECK-NEXT: <key>line</key><integer>385</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3293,7 +3345,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>380</integer>
+// CHECK-NEXT: <key>line</key><integer>385</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3301,24 +3353,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>380</integer>
+// CHECK-NEXT: <key>line</key><integer>385</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>380</integer>
+// CHECK-NEXT: <key>line</key><integer>385</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>380</integer>
+// CHECK-NEXT: <key>line</key><integer>385</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>380</integer>
+// CHECK-NEXT: <key>line</key><integer>385</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3338,12 +3390,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>380</integer>
+// CHECK-NEXT: <key>line</key><integer>385</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>380</integer>
+// CHECK-NEXT: <key>line</key><integer>385</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3351,12 +3403,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>381</integer>
+// CHECK-NEXT: <key>line</key><integer>386</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>381</integer>
+// CHECK-NEXT: <key>line</key><integer>386</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3368,7 +3420,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>381</integer>
+// CHECK-NEXT: <key>line</key><integer>386</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3384,10 +3436,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>f6</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>381</integer>
+// CHECK-NEXT: <key>line</key><integer>386</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3403,12 +3455,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>386</integer>
+// CHECK-NEXT: <key>line</key><integer>391</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>386</integer>
+// CHECK-NEXT: <key>line</key><integer>391</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3416,12 +3468,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>386</integer>
+// CHECK-NEXT: <key>line</key><integer>391</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>386</integer>
+// CHECK-NEXT: <key>line</key><integer>391</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3433,7 +3485,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>386</integer>
+// CHECK-NEXT: <key>line</key><integer>391</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3441,12 +3493,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>386</integer>
+// CHECK-NEXT: <key>line</key><integer>391</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>386</integer>
+// CHECK-NEXT: <key>line</key><integer>391</integer>
// CHECK-NEXT: <key>col</key><integer>62</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3466,12 +3518,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>386</integer>
+// CHECK-NEXT: <key>line</key><integer>391</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>386</integer>
+// CHECK-NEXT: <key>line</key><integer>391</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3479,12 +3531,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>387</integer>
+// CHECK-NEXT: <key>line</key><integer>392</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>387</integer>
+// CHECK-NEXT: <key>line</key><integer>392</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3496,7 +3548,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>387</integer>
+// CHECK-NEXT: <key>line</key><integer>392</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3504,24 +3556,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>387</integer>
+// CHECK-NEXT: <key>line</key><integer>392</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>387</integer>
+// CHECK-NEXT: <key>line</key><integer>392</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>387</integer>
+// CHECK-NEXT: <key>line</key><integer>392</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>387</integer>
+// CHECK-NEXT: <key>line</key><integer>392</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3541,12 +3593,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>387</integer>
+// CHECK-NEXT: <key>line</key><integer>392</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>387</integer>
+// CHECK-NEXT: <key>line</key><integer>392</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3554,12 +3606,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>389</integer>
+// CHECK-NEXT: <key>line</key><integer>394</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>389</integer>
+// CHECK-NEXT: <key>line</key><integer>394</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3571,7 +3623,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>389</integer>
+// CHECK-NEXT: <key>line</key><integer>394</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3579,12 +3631,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>389</integer>
+// CHECK-NEXT: <key>line</key><integer>394</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>389</integer>
+// CHECK-NEXT: <key>line</key><integer>394</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3602,10 +3654,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>f7</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>389</integer>
+// CHECK-NEXT: <key>line</key><integer>394</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3621,12 +3673,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>386</integer>
+// CHECK-NEXT: <key>line</key><integer>391</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>386</integer>
+// CHECK-NEXT: <key>line</key><integer>391</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3634,12 +3686,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>388</integer>
+// CHECK-NEXT: <key>line</key><integer>393</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>388</integer>
+// CHECK-NEXT: <key>line</key><integer>393</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3655,12 +3707,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>388</integer>
+// CHECK-NEXT: <key>line</key><integer>393</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>388</integer>
+// CHECK-NEXT: <key>line</key><integer>393</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3668,12 +3720,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>388</integer>
+// CHECK-NEXT: <key>line</key><integer>393</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>388</integer>
+// CHECK-NEXT: <key>line</key><integer>393</integer>
// CHECK-NEXT: <key>col</key><integer>21</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3685,7 +3737,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>388</integer>
+// CHECK-NEXT: <key>line</key><integer>393</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3693,12 +3745,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>388</integer>
+// CHECK-NEXT: <key>line</key><integer>393</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>388</integer>
+// CHECK-NEXT: <key>line</key><integer>393</integer>
// CHECK-NEXT: <key>col</key><integer>52</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3718,12 +3770,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>388</integer>
+// CHECK-NEXT: <key>line</key><integer>393</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>388</integer>
+// CHECK-NEXT: <key>line</key><integer>393</integer>
// CHECK-NEXT: <key>col</key><integer>21</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3731,12 +3783,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>389</integer>
+// CHECK-NEXT: <key>line</key><integer>394</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>389</integer>
+// CHECK-NEXT: <key>line</key><integer>394</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3748,7 +3800,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>389</integer>
+// CHECK-NEXT: <key>line</key><integer>394</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3756,24 +3808,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>389</integer>
+// CHECK-NEXT: <key>line</key><integer>394</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>389</integer>
+// CHECK-NEXT: <key>line</key><integer>394</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>389</integer>
+// CHECK-NEXT: <key>line</key><integer>394</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>389</integer>
+// CHECK-NEXT: <key>line</key><integer>394</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3789,7 +3841,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>389</integer>
+// CHECK-NEXT: <key>line</key><integer>394</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3797,12 +3849,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>389</integer>
+// CHECK-NEXT: <key>line</key><integer>394</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>389</integer>
+// CHECK-NEXT: <key>line</key><integer>394</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3820,10 +3872,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak of returned object</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>f7</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>389</integer>
+// CHECK-NEXT: <key>line</key><integer>394</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3839,12 +3891,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>397</integer>
+// CHECK-NEXT: <key>line</key><integer>402</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>397</integer>
+// CHECK-NEXT: <key>line</key><integer>402</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3852,12 +3904,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>397</integer>
+// CHECK-NEXT: <key>line</key><integer>402</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>397</integer>
+// CHECK-NEXT: <key>line</key><integer>402</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3869,7 +3921,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>397</integer>
+// CHECK-NEXT: <key>line</key><integer>402</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3877,12 +3929,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>397</integer>
+// CHECK-NEXT: <key>line</key><integer>402</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>397</integer>
+// CHECK-NEXT: <key>line</key><integer>402</integer>
// CHECK-NEXT: <key>col</key><integer>33</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3902,12 +3954,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>397</integer>
+// CHECK-NEXT: <key>line</key><integer>402</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>397</integer>
+// CHECK-NEXT: <key>line</key><integer>402</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3915,12 +3967,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>398</integer>
+// CHECK-NEXT: <key>line</key><integer>403</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>398</integer>
+// CHECK-NEXT: <key>line</key><integer>403</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3932,7 +3984,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>398</integer>
+// CHECK-NEXT: <key>line</key><integer>403</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3940,24 +3992,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>398</integer>
+// CHECK-NEXT: <key>line</key><integer>403</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>398</integer>
+// CHECK-NEXT: <key>line</key><integer>403</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>398</integer>
+// CHECK-NEXT: <key>line</key><integer>403</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>398</integer>
+// CHECK-NEXT: <key>line</key><integer>403</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3977,12 +4029,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>398</integer>
+// CHECK-NEXT: <key>line</key><integer>403</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>398</integer>
+// CHECK-NEXT: <key>line</key><integer>403</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -3990,12 +4042,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>399</integer>
+// CHECK-NEXT: <key>line</key><integer>404</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>399</integer>
+// CHECK-NEXT: <key>line</key><integer>404</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4007,7 +4059,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>399</integer>
+// CHECK-NEXT: <key>line</key><integer>404</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4015,24 +4067,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>399</integer>
+// CHECK-NEXT: <key>line</key><integer>404</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>399</integer>
+// CHECK-NEXT: <key>line</key><integer>404</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>399</integer>
+// CHECK-NEXT: <key>line</key><integer>404</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>399</integer>
+// CHECK-NEXT: <key>line</key><integer>404</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4052,12 +4104,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>399</integer>
+// CHECK-NEXT: <key>line</key><integer>404</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>399</integer>
+// CHECK-NEXT: <key>line</key><integer>404</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4065,12 +4117,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>400</integer>
+// CHECK-NEXT: <key>line</key><integer>405</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>400</integer>
+// CHECK-NEXT: <key>line</key><integer>405</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4082,7 +4134,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>400</integer>
+// CHECK-NEXT: <key>line</key><integer>405</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4098,10 +4150,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>f8</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>400</integer>
+// CHECK-NEXT: <key>line</key><integer>405</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4117,12 +4169,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>403</integer>
+// CHECK-NEXT: <key>line</key><integer>408</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>403</integer>
+// CHECK-NEXT: <key>line</key><integer>408</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4130,12 +4182,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>404</integer>
+// CHECK-NEXT: <key>line</key><integer>409</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>404</integer>
+// CHECK-NEXT: <key>line</key><integer>409</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4147,7 +4199,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>404</integer>
+// CHECK-NEXT: <key>line</key><integer>409</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4155,12 +4207,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>404</integer>
+// CHECK-NEXT: <key>line</key><integer>409</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>404</integer>
+// CHECK-NEXT: <key>line</key><integer>409</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4180,12 +4232,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>404</integer>
+// CHECK-NEXT: <key>line</key><integer>409</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>404</integer>
+// CHECK-NEXT: <key>line</key><integer>409</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4193,12 +4245,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>406</integer>
+// CHECK-NEXT: <key>line</key><integer>411</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>406</integer>
+// CHECK-NEXT: <key>line</key><integer>411</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4214,12 +4266,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>406</integer>
+// CHECK-NEXT: <key>line</key><integer>411</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>406</integer>
+// CHECK-NEXT: <key>line</key><integer>411</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4227,12 +4279,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>406</integer>
+// CHECK-NEXT: <key>line</key><integer>411</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>406</integer>
+// CHECK-NEXT: <key>line</key><integer>411</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4244,7 +4296,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>406</integer>
+// CHECK-NEXT: <key>line</key><integer>411</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4252,12 +4304,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>406</integer>
+// CHECK-NEXT: <key>line</key><integer>411</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>406</integer>
+// CHECK-NEXT: <key>line</key><integer>411</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4277,12 +4329,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>406</integer>
+// CHECK-NEXT: <key>line</key><integer>411</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>406</integer>
+// CHECK-NEXT: <key>line</key><integer>411</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4290,12 +4342,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>406</integer>
+// CHECK-NEXT: <key>line</key><integer>411</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>406</integer>
+// CHECK-NEXT: <key>line</key><integer>411</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4307,7 +4359,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>406</integer>
+// CHECK-NEXT: <key>line</key><integer>411</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4315,12 +4367,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>406</integer>
+// CHECK-NEXT: <key>line</key><integer>411</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>406</integer>
+// CHECK-NEXT: <key>line</key><integer>411</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4338,10 +4390,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>f9</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>406</integer>
+// CHECK-NEXT: <key>line</key><integer>411</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4357,12 +4409,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>415</integer>
+// CHECK-NEXT: <key>line</key><integer>420</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>415</integer>
+// CHECK-NEXT: <key>line</key><integer>420</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4370,12 +4422,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>415</integer>
+// CHECK-NEXT: <key>line</key><integer>420</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>415</integer>
+// CHECK-NEXT: <key>line</key><integer>420</integer>
// CHECK-NEXT: <key>col</key><integer>42</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4387,7 +4439,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>415</integer>
+// CHECK-NEXT: <key>line</key><integer>420</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4395,12 +4447,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>415</integer>
+// CHECK-NEXT: <key>line</key><integer>420</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>415</integer>
+// CHECK-NEXT: <key>line</key><integer>420</integer>
// CHECK-NEXT: <key>col</key><integer>75</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4420,12 +4472,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>415</integer>
+// CHECK-NEXT: <key>line</key><integer>420</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>415</integer>
+// CHECK-NEXT: <key>line</key><integer>420</integer>
// CHECK-NEXT: <key>col</key><integer>42</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4433,12 +4485,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4454,12 +4506,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4467,12 +4519,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4484,7 +4536,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4492,12 +4544,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4517,12 +4569,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4530,12 +4582,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4551,12 +4603,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4564,12 +4616,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4585,12 +4637,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4598,12 +4650,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4619,12 +4671,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4632,12 +4684,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4649,7 +4701,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4657,12 +4709,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4682,12 +4734,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4695,12 +4747,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4716,12 +4768,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4729,12 +4781,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>48</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>48</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4746,7 +4798,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>48</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4754,12 +4806,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>48</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>48</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4777,10 +4829,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>f10</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>7</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>7</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>48</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4796,12 +4848,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>415</integer>
+// CHECK-NEXT: <key>line</key><integer>420</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>415</integer>
+// CHECK-NEXT: <key>line</key><integer>420</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4809,12 +4861,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4830,12 +4882,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4843,12 +4895,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4860,7 +4912,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4868,12 +4920,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4893,12 +4945,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4906,12 +4958,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4927,12 +4979,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4940,12 +4992,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4961,12 +5013,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4974,12 +5026,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4991,7 +5043,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -4999,12 +5051,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5024,12 +5076,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5037,12 +5089,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5058,12 +5110,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5071,12 +5123,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>46</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5088,7 +5140,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5096,12 +5148,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>49</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5121,12 +5173,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>46</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5134,12 +5186,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5155,12 +5207,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5168,12 +5220,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5185,7 +5237,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5193,12 +5245,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5218,12 +5270,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5231,12 +5283,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5252,12 +5304,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5265,12 +5317,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5282,7 +5334,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5290,12 +5342,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5313,10 +5365,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>f10</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>8</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>8</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5332,12 +5384,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>415</integer>
+// CHECK-NEXT: <key>line</key><integer>420</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>415</integer>
+// CHECK-NEXT: <key>line</key><integer>420</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5345,12 +5397,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5366,12 +5418,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5379,12 +5431,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5396,7 +5448,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5404,12 +5456,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5429,12 +5481,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5442,12 +5494,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5463,12 +5515,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5476,12 +5528,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5497,12 +5549,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5510,12 +5562,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5527,7 +5579,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5535,12 +5587,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5560,12 +5612,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5573,12 +5625,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5594,12 +5646,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5607,12 +5659,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5628,12 +5680,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5641,12 +5693,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5658,7 +5710,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5666,12 +5718,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5691,12 +5743,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5704,12 +5756,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>424</integer>
+// CHECK-NEXT: <key>line</key><integer>429</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>424</integer>
+// CHECK-NEXT: <key>line</key><integer>429</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5725,12 +5777,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>424</integer>
+// CHECK-NEXT: <key>line</key><integer>429</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>424</integer>
+// CHECK-NEXT: <key>line</key><integer>429</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5738,12 +5790,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>424</integer>
+// CHECK-NEXT: <key>line</key><integer>429</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>424</integer>
+// CHECK-NEXT: <key>line</key><integer>429</integer>
// CHECK-NEXT: <key>col</key><integer>28</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5755,7 +5807,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>424</integer>
+// CHECK-NEXT: <key>line</key><integer>429</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5763,12 +5815,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>424</integer>
+// CHECK-NEXT: <key>line</key><integer>429</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>424</integer>
+// CHECK-NEXT: <key>line</key><integer>429</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5788,12 +5840,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>424</integer>
+// CHECK-NEXT: <key>line</key><integer>429</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>424</integer>
+// CHECK-NEXT: <key>line</key><integer>429</integer>
// CHECK-NEXT: <key>col</key><integer>28</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5801,12 +5853,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5822,12 +5874,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5835,12 +5887,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5852,7 +5904,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5860,12 +5912,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5885,12 +5937,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5898,12 +5950,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5919,12 +5971,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5932,12 +5984,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5949,7 +6001,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5957,12 +6009,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5980,10 +6032,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>f10</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>11</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>11</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -5999,12 +6051,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>415</integer>
+// CHECK-NEXT: <key>line</key><integer>420</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>415</integer>
+// CHECK-NEXT: <key>line</key><integer>420</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6012,12 +6064,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6033,12 +6085,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6046,12 +6098,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6063,7 +6115,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6071,12 +6123,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6096,12 +6148,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6109,12 +6161,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6130,12 +6182,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6143,12 +6195,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>32</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6160,7 +6212,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6168,12 +6220,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>63</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6193,12 +6245,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>32</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6206,12 +6258,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6227,12 +6279,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6240,12 +6292,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6257,7 +6309,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6265,12 +6317,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6290,12 +6342,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6303,12 +6355,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6324,12 +6376,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6337,12 +6389,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6358,12 +6410,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6371,12 +6423,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6392,12 +6444,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6405,12 +6457,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6422,7 +6474,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6430,12 +6482,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6455,12 +6507,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6468,12 +6520,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>424</integer>
+// CHECK-NEXT: <key>line</key><integer>429</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>424</integer>
+// CHECK-NEXT: <key>line</key><integer>429</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6489,12 +6541,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>424</integer>
+// CHECK-NEXT: <key>line</key><integer>429</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>424</integer>
+// CHECK-NEXT: <key>line</key><integer>429</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6502,12 +6554,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6523,12 +6575,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6536,12 +6588,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6553,7 +6605,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6561,12 +6613,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6586,12 +6638,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6599,12 +6651,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>427</integer>
+// CHECK-NEXT: <key>line</key><integer>432</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>427</integer>
+// CHECK-NEXT: <key>line</key><integer>432</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6620,12 +6672,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>427</integer>
+// CHECK-NEXT: <key>line</key><integer>432</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>427</integer>
+// CHECK-NEXT: <key>line</key><integer>432</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6633,12 +6685,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>428</integer>
+// CHECK-NEXT: <key>line</key><integer>433</integer>
// CHECK-NEXT: <key>col</key><integer>67</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>428</integer>
+// CHECK-NEXT: <key>line</key><integer>433</integer>
// CHECK-NEXT: <key>col</key><integer>67</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6650,7 +6702,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>428</integer>
+// CHECK-NEXT: <key>line</key><integer>433</integer>
// CHECK-NEXT: <key>col</key><integer>67</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6658,12 +6710,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>428</integer>
+// CHECK-NEXT: <key>line</key><integer>433</integer>
// CHECK-NEXT: <key>col</key><integer>67</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>428</integer>
+// CHECK-NEXT: <key>line</key><integer>433</integer>
// CHECK-NEXT: <key>col</key><integer>67</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6681,10 +6733,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>f10</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>14</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>14</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>428</integer>
+// CHECK-NEXT: <key>line</key><integer>433</integer>
// CHECK-NEXT: <key>col</key><integer>67</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6700,12 +6752,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>415</integer>
+// CHECK-NEXT: <key>line</key><integer>420</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>415</integer>
+// CHECK-NEXT: <key>line</key><integer>420</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6713,12 +6765,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6734,12 +6786,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6747,12 +6799,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6764,7 +6816,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6772,12 +6824,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6797,12 +6849,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6810,12 +6862,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6831,12 +6883,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6844,12 +6896,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6865,12 +6917,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6878,12 +6930,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6895,7 +6947,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6903,12 +6955,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6928,12 +6980,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6941,12 +6993,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6962,12 +7014,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6975,12 +7027,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -6996,12 +7048,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7009,12 +7061,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7026,7 +7078,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7034,12 +7086,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7059,12 +7111,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7072,12 +7124,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>424</integer>
+// CHECK-NEXT: <key>line</key><integer>429</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>424</integer>
+// CHECK-NEXT: <key>line</key><integer>429</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7093,12 +7145,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>424</integer>
+// CHECK-NEXT: <key>line</key><integer>429</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>424</integer>
+// CHECK-NEXT: <key>line</key><integer>429</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7106,12 +7158,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7127,12 +7179,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7140,12 +7192,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7157,7 +7209,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7165,12 +7217,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7190,12 +7242,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7203,12 +7255,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>427</integer>
+// CHECK-NEXT: <key>line</key><integer>432</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>427</integer>
+// CHECK-NEXT: <key>line</key><integer>432</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7224,12 +7276,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>427</integer>
+// CHECK-NEXT: <key>line</key><integer>432</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>427</integer>
+// CHECK-NEXT: <key>line</key><integer>432</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7237,12 +7289,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>427</integer>
+// CHECK-NEXT: <key>line</key><integer>432</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>427</integer>
+// CHECK-NEXT: <key>line</key><integer>432</integer>
// CHECK-NEXT: <key>col</key><integer>46</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7254,7 +7306,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>427</integer>
+// CHECK-NEXT: <key>line</key><integer>432</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7262,12 +7314,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>427</integer>
+// CHECK-NEXT: <key>line</key><integer>432</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>428</integer>
+// CHECK-NEXT: <key>line</key><integer>433</integer>
// CHECK-NEXT: <key>col</key><integer>68</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7287,12 +7339,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>427</integer>
+// CHECK-NEXT: <key>line</key><integer>432</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>427</integer>
+// CHECK-NEXT: <key>line</key><integer>432</integer>
// CHECK-NEXT: <key>col</key><integer>46</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7300,12 +7352,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7321,12 +7373,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7334,12 +7386,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7351,7 +7403,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7359,12 +7411,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7384,12 +7436,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7397,12 +7449,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>18</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7418,12 +7470,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>18</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7431,12 +7483,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>28</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7448,7 +7500,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7456,12 +7508,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>28</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7479,10 +7531,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>f10</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>15</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>15</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7498,12 +7550,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>415</integer>
+// CHECK-NEXT: <key>line</key><integer>420</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>415</integer>
+// CHECK-NEXT: <key>line</key><integer>420</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7511,12 +7563,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7532,12 +7584,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7545,12 +7597,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7562,7 +7614,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7570,12 +7622,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7595,12 +7647,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>416</integer>
+// CHECK-NEXT: <key>line</key><integer>421</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7608,12 +7660,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7629,12 +7681,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>418</integer>
+// CHECK-NEXT: <key>line</key><integer>423</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7642,12 +7694,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7663,12 +7715,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7676,12 +7728,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7693,7 +7745,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7701,12 +7753,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7726,12 +7778,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>419</integer>
+// CHECK-NEXT: <key>line</key><integer>424</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7739,12 +7791,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7760,12 +7812,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>421</integer>
+// CHECK-NEXT: <key>line</key><integer>426</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7773,12 +7825,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7794,12 +7846,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7807,12 +7859,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7824,7 +7876,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7832,12 +7884,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7857,12 +7909,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>422</integer>
+// CHECK-NEXT: <key>line</key><integer>427</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7870,12 +7922,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>424</integer>
+// CHECK-NEXT: <key>line</key><integer>429</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>424</integer>
+// CHECK-NEXT: <key>line</key><integer>429</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7891,12 +7943,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>424</integer>
+// CHECK-NEXT: <key>line</key><integer>429</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>424</integer>
+// CHECK-NEXT: <key>line</key><integer>429</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7904,12 +7956,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7925,12 +7977,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7938,12 +7990,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7955,7 +8007,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7963,12 +8015,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -7988,12 +8040,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>425</integer>
+// CHECK-NEXT: <key>line</key><integer>430</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8001,12 +8053,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>427</integer>
+// CHECK-NEXT: <key>line</key><integer>432</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>427</integer>
+// CHECK-NEXT: <key>line</key><integer>432</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8022,12 +8074,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>427</integer>
+// CHECK-NEXT: <key>line</key><integer>432</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>427</integer>
+// CHECK-NEXT: <key>line</key><integer>432</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8035,12 +8087,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8056,12 +8108,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8069,12 +8121,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8086,7 +8138,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8094,12 +8146,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8119,12 +8171,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>429</integer>
+// CHECK-NEXT: <key>line</key><integer>434</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8132,12 +8184,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>431</integer>
+// CHECK-NEXT: <key>line</key><integer>436</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>431</integer>
+// CHECK-NEXT: <key>line</key><integer>436</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8153,12 +8205,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>431</integer>
+// CHECK-NEXT: <key>line</key><integer>436</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>431</integer>
+// CHECK-NEXT: <key>line</key><integer>436</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8166,12 +8218,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>431</integer>
+// CHECK-NEXT: <key>line</key><integer>436</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>431</integer>
+// CHECK-NEXT: <key>line</key><integer>436</integer>
// CHECK-NEXT: <key>col</key><integer>40</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8183,7 +8235,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>431</integer>
+// CHECK-NEXT: <key>line</key><integer>436</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8191,12 +8243,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>431</integer>
+// CHECK-NEXT: <key>line</key><integer>436</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>431</integer>
+// CHECK-NEXT: <key>line</key><integer>436</integer>
// CHECK-NEXT: <key>col</key><integer>61</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8216,12 +8268,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>431</integer>
+// CHECK-NEXT: <key>line</key><integer>436</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>431</integer>
+// CHECK-NEXT: <key>line</key><integer>436</integer>
// CHECK-NEXT: <key>col</key><integer>40</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8229,12 +8281,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>432</integer>
+// CHECK-NEXT: <key>line</key><integer>437</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>432</integer>
+// CHECK-NEXT: <key>line</key><integer>437</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8250,12 +8302,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>432</integer>
+// CHECK-NEXT: <key>line</key><integer>437</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>432</integer>
+// CHECK-NEXT: <key>line</key><integer>437</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8263,12 +8315,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>432</integer>
+// CHECK-NEXT: <key>line</key><integer>437</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>432</integer>
+// CHECK-NEXT: <key>line</key><integer>437</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8280,7 +8332,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>432</integer>
+// CHECK-NEXT: <key>line</key><integer>437</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8288,12 +8340,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>432</integer>
+// CHECK-NEXT: <key>line</key><integer>437</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>432</integer>
+// CHECK-NEXT: <key>line</key><integer>437</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8313,12 +8365,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>432</integer>
+// CHECK-NEXT: <key>line</key><integer>437</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>432</integer>
+// CHECK-NEXT: <key>line</key><integer>437</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8326,12 +8378,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>432</integer>
+// CHECK-NEXT: <key>line</key><integer>437</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>432</integer>
+// CHECK-NEXT: <key>line</key><integer>437</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8347,12 +8399,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>432</integer>
+// CHECK-NEXT: <key>line</key><integer>437</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>432</integer>
+// CHECK-NEXT: <key>line</key><integer>437</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8360,12 +8412,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>432</integer>
+// CHECK-NEXT: <key>line</key><integer>437</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>432</integer>
+// CHECK-NEXT: <key>line</key><integer>437</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8377,7 +8429,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>432</integer>
+// CHECK-NEXT: <key>line</key><integer>437</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8385,12 +8437,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>432</integer>
+// CHECK-NEXT: <key>line</key><integer>437</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>432</integer>
+// CHECK-NEXT: <key>line</key><integer>437</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8408,10 +8460,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>f10</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>18</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>18</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>432</integer>
+// CHECK-NEXT: <key>line</key><integer>437</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8427,12 +8479,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>438</integer>
+// CHECK-NEXT: <key>line</key><integer>443</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>438</integer>
+// CHECK-NEXT: <key>line</key><integer>443</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8440,12 +8492,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>451</integer>
+// CHECK-NEXT: <key>line</key><integer>456</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>451</integer>
+// CHECK-NEXT: <key>line</key><integer>456</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8461,12 +8513,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>451</integer>
+// CHECK-NEXT: <key>line</key><integer>456</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>451</integer>
+// CHECK-NEXT: <key>line</key><integer>456</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8474,12 +8526,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>451</integer>
+// CHECK-NEXT: <key>line</key><integer>456</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>451</integer>
+// CHECK-NEXT: <key>line</key><integer>456</integer>
// CHECK-NEXT: <key>col</key><integer>43</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8491,7 +8543,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>451</integer>
+// CHECK-NEXT: <key>line</key><integer>456</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8499,12 +8551,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>451</integer>
+// CHECK-NEXT: <key>line</key><integer>456</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>451</integer>
+// CHECK-NEXT: <key>line</key><integer>456</integer>
// CHECK-NEXT: <key>col</key><integer>49</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8524,12 +8576,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>451</integer>
+// CHECK-NEXT: <key>line</key><integer>456</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>451</integer>
+// CHECK-NEXT: <key>line</key><integer>456</integer>
// CHECK-NEXT: <key>col</key><integer>43</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8537,12 +8589,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>457</integer>
+// CHECK-NEXT: <key>line</key><integer>462</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>457</integer>
+// CHECK-NEXT: <key>line</key><integer>462</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8554,7 +8606,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>457</integer>
+// CHECK-NEXT: <key>line</key><integer>462</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8562,12 +8614,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>457</integer>
+// CHECK-NEXT: <key>line</key><integer>462</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>457</integer>
+// CHECK-NEXT: <key>line</key><integer>462</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8585,10 +8637,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Bad release</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>f11</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>21</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>21</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>457</integer>
+// CHECK-NEXT: <key>line</key><integer>462</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8604,12 +8656,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>465</integer>
+// CHECK-NEXT: <key>line</key><integer>470</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>465</integer>
+// CHECK-NEXT: <key>line</key><integer>470</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8617,12 +8669,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>465</integer>
+// CHECK-NEXT: <key>line</key><integer>470</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>465</integer>
+// CHECK-NEXT: <key>line</key><integer>470</integer>
// CHECK-NEXT: <key>col</key><integer>27</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8634,7 +8686,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>465</integer>
+// CHECK-NEXT: <key>line</key><integer>470</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8642,12 +8694,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>465</integer>
+// CHECK-NEXT: <key>line</key><integer>470</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>465</integer>
+// CHECK-NEXT: <key>line</key><integer>470</integer>
// CHECK-NEXT: <key>col</key><integer>29</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8667,12 +8719,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>465</integer>
+// CHECK-NEXT: <key>line</key><integer>470</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>465</integer>
+// CHECK-NEXT: <key>line</key><integer>470</integer>
// CHECK-NEXT: <key>col</key><integer>27</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8680,12 +8732,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>466</integer>
+// CHECK-NEXT: <key>line</key><integer>471</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>466</integer>
+// CHECK-NEXT: <key>line</key><integer>471</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8697,7 +8749,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>466</integer>
+// CHECK-NEXT: <key>line</key><integer>471</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8713,10 +8765,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>f12</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>466</integer>
+// CHECK-NEXT: <key>line</key><integer>471</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8732,12 +8784,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>474</integer>
+// CHECK-NEXT: <key>line</key><integer>479</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>474</integer>
+// CHECK-NEXT: <key>line</key><integer>479</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8745,12 +8797,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>474</integer>
+// CHECK-NEXT: <key>line</key><integer>479</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>474</integer>
+// CHECK-NEXT: <key>line</key><integer>479</integer>
// CHECK-NEXT: <key>col</key><integer>44</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8762,7 +8814,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>474</integer>
+// CHECK-NEXT: <key>line</key><integer>479</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8770,12 +8822,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>474</integer>
+// CHECK-NEXT: <key>line</key><integer>479</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>474</integer>
+// CHECK-NEXT: <key>line</key><integer>479</integer>
// CHECK-NEXT: <key>col</key><integer>75</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8795,12 +8847,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>474</integer>
+// CHECK-NEXT: <key>line</key><integer>479</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>474</integer>
+// CHECK-NEXT: <key>line</key><integer>479</integer>
// CHECK-NEXT: <key>col</key><integer>44</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8808,12 +8860,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>475</integer>
+// CHECK-NEXT: <key>line</key><integer>480</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>475</integer>
+// CHECK-NEXT: <key>line</key><integer>480</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8825,7 +8877,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>475</integer>
+// CHECK-NEXT: <key>line</key><integer>480</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8833,24 +8885,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>475</integer>
+// CHECK-NEXT: <key>line</key><integer>480</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>475</integer>
+// CHECK-NEXT: <key>line</key><integer>480</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>475</integer>
+// CHECK-NEXT: <key>line</key><integer>480</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>475</integer>
+// CHECK-NEXT: <key>line</key><integer>480</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8870,12 +8922,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>475</integer>
+// CHECK-NEXT: <key>line</key><integer>480</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>475</integer>
+// CHECK-NEXT: <key>line</key><integer>480</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8883,12 +8935,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>476</integer>
+// CHECK-NEXT: <key>line</key><integer>481</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>476</integer>
+// CHECK-NEXT: <key>line</key><integer>481</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8900,7 +8952,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>476</integer>
+// CHECK-NEXT: <key>line</key><integer>481</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8908,24 +8960,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>476</integer>
+// CHECK-NEXT: <key>line</key><integer>481</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>476</integer>
+// CHECK-NEXT: <key>line</key><integer>481</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>476</integer>
+// CHECK-NEXT: <key>line</key><integer>481</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>476</integer>
+// CHECK-NEXT: <key>line</key><integer>481</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8945,12 +8997,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>476</integer>
+// CHECK-NEXT: <key>line</key><integer>481</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>476</integer>
+// CHECK-NEXT: <key>line</key><integer>481</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8958,12 +9010,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>477</integer>
+// CHECK-NEXT: <key>line</key><integer>482</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>477</integer>
+// CHECK-NEXT: <key>line</key><integer>482</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -8975,25 +9027,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>477</integer>
+// CHECK-NEXT: <key>line</key><integer>482</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>476</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>476</integer>
-// CHECK-NEXT: <key>col</key><integer>22</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Object over-autoreleased: object was sent -autorelease 2 times but the object has a +1 retain count</string>
@@ -9006,10 +9043,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Object sent -autorelease too many times</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>f13_autorelease_b</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>477</integer>
+// CHECK-NEXT: <key>line</key><integer>482</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9025,12 +9062,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>480</integer>
+// CHECK-NEXT: <key>line</key><integer>485</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>480</integer>
+// CHECK-NEXT: <key>line</key><integer>485</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9038,12 +9075,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>480</integer>
+// CHECK-NEXT: <key>line</key><integer>485</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>480</integer>
+// CHECK-NEXT: <key>line</key><integer>485</integer>
// CHECK-NEXT: <key>col</key><integer>44</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9055,7 +9092,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>480</integer>
+// CHECK-NEXT: <key>line</key><integer>485</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9063,12 +9100,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>480</integer>
+// CHECK-NEXT: <key>line</key><integer>485</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>480</integer>
+// CHECK-NEXT: <key>line</key><integer>485</integer>
// CHECK-NEXT: <key>col</key><integer>75</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9088,12 +9125,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>480</integer>
+// CHECK-NEXT: <key>line</key><integer>485</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>480</integer>
+// CHECK-NEXT: <key>line</key><integer>485</integer>
// CHECK-NEXT: <key>col</key><integer>44</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9101,12 +9138,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>481</integer>
+// CHECK-NEXT: <key>line</key><integer>486</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>481</integer>
+// CHECK-NEXT: <key>line</key><integer>486</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9118,7 +9155,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>481</integer>
+// CHECK-NEXT: <key>line</key><integer>486</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9126,24 +9163,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>481</integer>
+// CHECK-NEXT: <key>line</key><integer>486</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>481</integer>
+// CHECK-NEXT: <key>line</key><integer>486</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>481</integer>
+// CHECK-NEXT: <key>line</key><integer>486</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>481</integer>
+// CHECK-NEXT: <key>line</key><integer>486</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9163,12 +9200,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>481</integer>
+// CHECK-NEXT: <key>line</key><integer>486</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>481</integer>
+// CHECK-NEXT: <key>line</key><integer>486</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9176,12 +9213,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>482</integer>
+// CHECK-NEXT: <key>line</key><integer>487</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>482</integer>
+// CHECK-NEXT: <key>line</key><integer>487</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9193,7 +9230,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>482</integer>
+// CHECK-NEXT: <key>line</key><integer>487</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9201,24 +9238,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>482</integer>
+// CHECK-NEXT: <key>line</key><integer>487</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>482</integer>
+// CHECK-NEXT: <key>line</key><integer>487</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>482</integer>
+// CHECK-NEXT: <key>line</key><integer>487</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>482</integer>
+// CHECK-NEXT: <key>line</key><integer>487</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9238,12 +9275,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>482</integer>
+// CHECK-NEXT: <key>line</key><integer>487</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>482</integer>
+// CHECK-NEXT: <key>line</key><integer>487</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9251,12 +9288,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>483</integer>
+// CHECK-NEXT: <key>line</key><integer>488</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>483</integer>
+// CHECK-NEXT: <key>line</key><integer>488</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9268,7 +9305,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>483</integer>
+// CHECK-NEXT: <key>line</key><integer>488</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9276,12 +9313,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>483</integer>
+// CHECK-NEXT: <key>line</key><integer>488</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>483</integer>
+// CHECK-NEXT: <key>line</key><integer>488</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9299,10 +9336,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Object sent -autorelease too many times</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>f13_autorelease_c</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>483</integer>
+// CHECK-NEXT: <key>line</key><integer>488</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9318,12 +9355,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>487</integer>
+// CHECK-NEXT: <key>line</key><integer>492</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>487</integer>
+// CHECK-NEXT: <key>line</key><integer>492</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9331,12 +9368,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>487</integer>
+// CHECK-NEXT: <key>line</key><integer>492</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>487</integer>
+// CHECK-NEXT: <key>line</key><integer>492</integer>
// CHECK-NEXT: <key>col</key><integer>44</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9348,7 +9385,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>487</integer>
+// CHECK-NEXT: <key>line</key><integer>492</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9356,12 +9393,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>487</integer>
+// CHECK-NEXT: <key>line</key><integer>492</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>487</integer>
+// CHECK-NEXT: <key>line</key><integer>492</integer>
// CHECK-NEXT: <key>col</key><integer>75</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9381,12 +9418,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>487</integer>
+// CHECK-NEXT: <key>line</key><integer>492</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>487</integer>
+// CHECK-NEXT: <key>line</key><integer>492</integer>
// CHECK-NEXT: <key>col</key><integer>44</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9394,12 +9431,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>488</integer>
+// CHECK-NEXT: <key>line</key><integer>493</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>488</integer>
+// CHECK-NEXT: <key>line</key><integer>493</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9411,7 +9448,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>488</integer>
+// CHECK-NEXT: <key>line</key><integer>493</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9419,24 +9456,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>488</integer>
+// CHECK-NEXT: <key>line</key><integer>493</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>488</integer>
+// CHECK-NEXT: <key>line</key><integer>493</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>488</integer>
+// CHECK-NEXT: <key>line</key><integer>493</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>488</integer>
+// CHECK-NEXT: <key>line</key><integer>493</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9456,12 +9493,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>488</integer>
+// CHECK-NEXT: <key>line</key><integer>493</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>488</integer>
+// CHECK-NEXT: <key>line</key><integer>493</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9469,12 +9506,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>489</integer>
+// CHECK-NEXT: <key>line</key><integer>494</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>489</integer>
+// CHECK-NEXT: <key>line</key><integer>494</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9486,7 +9523,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>489</integer>
+// CHECK-NEXT: <key>line</key><integer>494</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9494,24 +9531,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>489</integer>
+// CHECK-NEXT: <key>line</key><integer>494</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>489</integer>
+// CHECK-NEXT: <key>line</key><integer>494</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>489</integer>
+// CHECK-NEXT: <key>line</key><integer>494</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>489</integer>
+// CHECK-NEXT: <key>line</key><integer>494</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9531,12 +9568,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>489</integer>
+// CHECK-NEXT: <key>line</key><integer>494</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>489</integer>
+// CHECK-NEXT: <key>line</key><integer>494</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9544,12 +9581,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>490</integer>
+// CHECK-NEXT: <key>line</key><integer>495</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>490</integer>
+// CHECK-NEXT: <key>line</key><integer>495</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9565,12 +9602,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>490</integer>
+// CHECK-NEXT: <key>line</key><integer>495</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>490</integer>
+// CHECK-NEXT: <key>line</key><integer>495</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9578,12 +9615,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>490</integer>
+// CHECK-NEXT: <key>line</key><integer>495</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>490</integer>
+// CHECK-NEXT: <key>line</key><integer>495</integer>
// CHECK-NEXT: <key>col</key><integer>44</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9595,7 +9632,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>490</integer>
+// CHECK-NEXT: <key>line</key><integer>495</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9603,12 +9640,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>490</integer>
+// CHECK-NEXT: <key>line</key><integer>495</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>490</integer>
+// CHECK-NEXT: <key>line</key><integer>495</integer>
// CHECK-NEXT: <key>col</key><integer>75</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9626,10 +9663,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Object sent -autorelease too many times</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>f13_autorelease_d</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>490</integer>
+// CHECK-NEXT: <key>line</key><integer>495</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9641,7 +9678,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>498</integer>
+// CHECK-NEXT: <key>line</key><integer>503</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9649,12 +9686,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>498</integer>
+// CHECK-NEXT: <key>line</key><integer>503</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>498</integer>
+// CHECK-NEXT: <key>line</key><integer>503</integer>
// CHECK-NEXT: <key>col</key><integer>53</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9674,12 +9711,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>498</integer>
+// CHECK-NEXT: <key>line</key><integer>503</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>498</integer>
+// CHECK-NEXT: <key>line</key><integer>503</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9687,12 +9724,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>499</integer>
+// CHECK-NEXT: <key>line</key><integer>504</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>499</integer>
+// CHECK-NEXT: <key>line</key><integer>504</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9704,7 +9741,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>499</integer>
+// CHECK-NEXT: <key>line</key><integer>504</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9720,10 +9757,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>f14_leakimmediately</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>499</integer>
+// CHECK-NEXT: <key>line</key><integer>504</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9739,12 +9776,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>513</integer>
+// CHECK-NEXT: <key>line</key><integer>518</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>513</integer>
+// CHECK-NEXT: <key>line</key><integer>518</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9752,12 +9789,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>513</integer>
+// CHECK-NEXT: <key>line</key><integer>518</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>513</integer>
+// CHECK-NEXT: <key>line</key><integer>518</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9769,7 +9806,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>513</integer>
+// CHECK-NEXT: <key>line</key><integer>518</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9777,12 +9814,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>513</integer>
+// CHECK-NEXT: <key>line</key><integer>518</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>513</integer>
+// CHECK-NEXT: <key>line</key><integer>518</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9795,10 +9832,78 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <string>Assuming &apos;p&apos; is null</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>518</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>518</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>513</integer>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9806,12 +9911,155 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>513</integer>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>513</integer>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Assuming &apos;x&apos; is &gt; 0</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;x&apos; is &gt; 0</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>522</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>522</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>522</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>522</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>522</integer>
+// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Null pointer argument in call to CFRelease</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Null pointer argument in call to CFRelease</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Null pointer argument in call to CFRelease</string>
+// CHECK-NEXT: <key>category</key><string>API Misuse (Apple)</string>
+// CHECK-NEXT: <key>type</key><string>null passed to CFRetain/CFRelease/CFMakeCollectable</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>f16</string>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>522</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>518</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>518</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>518</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>518</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>518</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>518</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>518</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9819,9 +10067,9 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Assuming pointer value is null</string>
+// CHECK-NEXT: <string>Assuming &apos;p&apos; is null</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Assuming pointer value is null</string>
+// CHECK-NEXT: <string>Assuming &apos;p&apos; is null</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -9831,12 +10079,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>513</integer>
+// CHECK-NEXT: <key>line</key><integer>518</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>513</integer>
+// CHECK-NEXT: <key>line</key><integer>518</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9844,12 +10092,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>516</integer>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>516</integer>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9865,12 +10113,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>516</integer>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>516</integer>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9878,12 +10126,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>516</integer>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>516</integer>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9895,7 +10143,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>516</integer>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9903,22 +10151,22 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>516</integer>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>516</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Assuming &apos;x&apos; is not equal to 0</string>
+// CHECK-NEXT: <string>Assuming &apos;x&apos; is &lt;= 0</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Assuming &apos;x&apos; is not equal to 0</string>
+// CHECK-NEXT: <string>Assuming &apos;x&apos; is &lt;= 0</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -9928,12 +10176,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>516</integer>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>516</integer>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9941,13 +10189,110 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>517</integer>
+// CHECK-NEXT: <key>line</key><integer>524</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>524</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>524</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>524</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>524</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>524</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>524</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>524</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>524</integer>
+// CHECK-NEXT: <key>col</key><integer>16</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Assuming &apos;x&apos; is &lt; 0</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Assuming &apos;x&apos; is &lt; 0</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>524</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>524</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>525</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>517</integer>
-// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>line</key><integer>525</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
@@ -9958,7 +10303,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>517</integer>
+// CHECK-NEXT: <key>line</key><integer>525</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -9966,33 +10311,33 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>517</integer>
-// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>line</key><integer>525</integer>
+// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>517</integer>
-// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>line</key><integer>525</integer>
+// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Null pointer argument in call to CFRelease</string>
+// CHECK-NEXT: <string>Null pointer argument in call to CFRetain</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Null pointer argument in call to CFRelease</string>
+// CHECK-NEXT: <string>Null pointer argument in call to CFRetain</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>Null pointer argument in call to CFRelease</string>
+// CHECK-NEXT: <key>description</key><string>Null pointer argument in call to CFRetain</string>
// CHECK-NEXT: <key>category</key><string>API Misuse (Apple)</string>
-// CHECK-NEXT: <key>type</key><string>null passed to CFRetain/CFRelease</string>
+// CHECK-NEXT: <key>type</key><string>null passed to CFRetain/CFRelease/CFMakeCollectable</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>f16</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>8</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>517</integer>
+// CHECK-NEXT: <key>line</key><integer>525</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10008,12 +10353,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>513</integer>
+// CHECK-NEXT: <key>line</key><integer>518</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>513</integer>
+// CHECK-NEXT: <key>line</key><integer>518</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10021,12 +10366,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>513</integer>
+// CHECK-NEXT: <key>line</key><integer>518</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>513</integer>
+// CHECK-NEXT: <key>line</key><integer>518</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10038,7 +10383,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>513</integer>
+// CHECK-NEXT: <key>line</key><integer>518</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10046,12 +10391,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>513</integer>
+// CHECK-NEXT: <key>line</key><integer>518</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>513</integer>
+// CHECK-NEXT: <key>line</key><integer>518</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10064,10 +10409,78 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <string>Assuming &apos;p&apos; is null</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>518</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>518</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
+// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
+// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>513</integer>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10075,22 +10488,22 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>513</integer>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>513</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
+// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Assuming pointer value is null</string>
+// CHECK-NEXT: <string>Assuming &apos;x&apos; is &lt;= 0</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Assuming pointer value is null</string>
+// CHECK-NEXT: <string>Assuming &apos;x&apos; is &lt;= 0</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -10100,12 +10513,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>513</integer>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>513</integer>
+// CHECK-NEXT: <key>line</key><integer>521</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10113,13 +10526,13 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>516</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>line</key><integer>524</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>516</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>line</key><integer>524</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
@@ -10134,26 +10547,26 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>516</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>line</key><integer>524</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>516</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
+// CHECK-NEXT: <key>line</key><integer>524</integer>
+// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>516</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>line</key><integer>524</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>516</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>line</key><integer>524</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
@@ -10164,30 +10577,30 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>516</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>line</key><integer>524</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <key>ranges</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>516</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>line</key><integer>524</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>516</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>line</key><integer>524</integer>
+// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Assuming &apos;x&apos; is 0</string>
+// CHECK-NEXT: <string>Assuming &apos;x&apos; is &gt;= 0</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Assuming &apos;x&apos; is 0</string>
+// CHECK-NEXT: <string>Assuming &apos;x&apos; is &gt;= 0</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -10197,26 +10610,26 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>516</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>line</key><integer>524</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>516</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
+// CHECK-NEXT: <key>line</key><integer>524</integer>
+// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>520</integer>
+// CHECK-NEXT: <key>line</key><integer>528</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>520</integer>
-// CHECK-NEXT: <key>col</key><integer>12</integer>
+// CHECK-NEXT: <key>line</key><integer>528</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
@@ -10227,7 +10640,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>520</integer>
+// CHECK-NEXT: <key>line</key><integer>528</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10235,33 +10648,33 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>520</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
+// CHECK-NEXT: <key>line</key><integer>528</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>520</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
+// CHECK-NEXT: <key>line</key><integer>528</integer>
+// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Null pointer argument in call to CFRetain</string>
+// CHECK-NEXT: <string>Null pointer argument in call to CFMakeCollectable</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Null pointer argument in call to CFRetain</string>
+// CHECK-NEXT: <string>Null pointer argument in call to CFMakeCollectable</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>Null pointer argument in call to CFRetain</string>
+// CHECK-NEXT: <key>description</key><string>Null pointer argument in call to CFMakeCollectable</string>
// CHECK-NEXT: <key>category</key><string>API Misuse (Apple)</string>
-// CHECK-NEXT: <key>type</key><string>null passed to CFRetain/CFRelease</string>
+// CHECK-NEXT: <key>type</key><string>null passed to CFRetain/CFRelease/CFMakeCollectable</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>f16</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>8</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>11</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>520</integer>
+// CHECK-NEXT: <key>line</key><integer>528</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10277,12 +10690,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>561</integer>
+// CHECK-NEXT: <key>line</key><integer>574</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>561</integer>
+// CHECK-NEXT: <key>line</key><integer>574</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10290,12 +10703,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>561</integer>
+// CHECK-NEXT: <key>line</key><integer>574</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>561</integer>
+// CHECK-NEXT: <key>line</key><integer>574</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10307,7 +10720,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>561</integer>
+// CHECK-NEXT: <key>line</key><integer>574</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10315,12 +10728,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>561</integer>
+// CHECK-NEXT: <key>line</key><integer>574</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>561</integer>
+// CHECK-NEXT: <key>line</key><integer>574</integer>
// CHECK-NEXT: <key>col</key><integer>55</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10340,12 +10753,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>561</integer>
+// CHECK-NEXT: <key>line</key><integer>574</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>561</integer>
+// CHECK-NEXT: <key>line</key><integer>574</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10353,12 +10766,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>562</integer>
+// CHECK-NEXT: <key>line</key><integer>575</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>562</integer>
+// CHECK-NEXT: <key>line</key><integer>575</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10370,7 +10783,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>562</integer>
+// CHECK-NEXT: <key>line</key><integer>575</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10378,24 +10791,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>562</integer>
+// CHECK-NEXT: <key>line</key><integer>575</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>562</integer>
+// CHECK-NEXT: <key>line</key><integer>575</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>562</integer>
+// CHECK-NEXT: <key>line</key><integer>575</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>562</integer>
+// CHECK-NEXT: <key>line</key><integer>575</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10411,7 +10824,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>562</integer>
+// CHECK-NEXT: <key>line</key><integer>575</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10419,12 +10832,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>562</integer>
+// CHECK-NEXT: <key>line</key><integer>575</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>562</integer>
+// CHECK-NEXT: <key>line</key><integer>575</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10442,10 +10855,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Method should return an owned object</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
// CHECK-NEXT: <key>issue_context</key><string>newString</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>562</integer>
+// CHECK-NEXT: <key>line</key><integer>575</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10461,12 +10874,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>575</integer>
+// CHECK-NEXT: <key>line</key><integer>588</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>575</integer>
+// CHECK-NEXT: <key>line</key><integer>588</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10474,12 +10887,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>575</integer>
+// CHECK-NEXT: <key>line</key><integer>588</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>575</integer>
+// CHECK-NEXT: <key>line</key><integer>588</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10491,7 +10904,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>575</integer>
+// CHECK-NEXT: <key>line</key><integer>588</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10499,12 +10912,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>575</integer>
+// CHECK-NEXT: <key>line</key><integer>588</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>575</integer>
+// CHECK-NEXT: <key>line</key><integer>588</integer>
// CHECK-NEXT: <key>col</key><integer>63</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10524,12 +10937,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>575</integer>
+// CHECK-NEXT: <key>line</key><integer>588</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>575</integer>
+// CHECK-NEXT: <key>line</key><integer>588</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10537,12 +10950,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10558,12 +10971,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10571,12 +10984,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10588,7 +11001,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10596,12 +11009,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10621,12 +11034,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10634,12 +11047,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>583</integer>
+// CHECK-NEXT: <key>line</key><integer>596</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>583</integer>
+// CHECK-NEXT: <key>line</key><integer>596</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10651,7 +11064,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>583</integer>
+// CHECK-NEXT: <key>line</key><integer>596</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10659,12 +11072,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>583</integer>
+// CHECK-NEXT: <key>line</key><integer>596</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>583</integer>
+// CHECK-NEXT: <key>line</key><integer>596</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10682,10 +11095,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>rdar_6659160</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>13</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>13</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>583</integer>
+// CHECK-NEXT: <key>line</key><integer>596</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10701,12 +11114,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>575</integer>
+// CHECK-NEXT: <key>line</key><integer>588</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>575</integer>
+// CHECK-NEXT: <key>line</key><integer>588</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10714,12 +11127,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10735,12 +11148,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10748,12 +11161,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10765,7 +11178,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10773,12 +11186,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10798,12 +11211,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10811,12 +11224,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>585</integer>
+// CHECK-NEXT: <key>line</key><integer>598</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>585</integer>
+// CHECK-NEXT: <key>line</key><integer>598</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10828,7 +11241,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>585</integer>
+// CHECK-NEXT: <key>line</key><integer>598</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10836,12 +11249,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>585</integer>
+// CHECK-NEXT: <key>line</key><integer>598</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>585</integer>
+// CHECK-NEXT: <key>line</key><integer>598</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10861,12 +11274,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>585</integer>
+// CHECK-NEXT: <key>line</key><integer>598</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>585</integer>
+// CHECK-NEXT: <key>line</key><integer>598</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10874,12 +11287,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>593</integer>
+// CHECK-NEXT: <key>line</key><integer>606</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>593</integer>
+// CHECK-NEXT: <key>line</key><integer>606</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10895,12 +11308,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>593</integer>
+// CHECK-NEXT: <key>line</key><integer>606</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>593</integer>
+// CHECK-NEXT: <key>line</key><integer>606</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10908,12 +11321,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>593</integer>
+// CHECK-NEXT: <key>line</key><integer>606</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>593</integer>
+// CHECK-NEXT: <key>line</key><integer>606</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10925,7 +11338,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>593</integer>
+// CHECK-NEXT: <key>line</key><integer>606</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10933,12 +11346,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>593</integer>
+// CHECK-NEXT: <key>line</key><integer>606</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>593</integer>
+// CHECK-NEXT: <key>line</key><integer>606</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10958,12 +11371,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>593</integer>
+// CHECK-NEXT: <key>line</key><integer>606</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>593</integer>
+// CHECK-NEXT: <key>line</key><integer>606</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10971,12 +11384,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>595</integer>
+// CHECK-NEXT: <key>line</key><integer>608</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>595</integer>
+// CHECK-NEXT: <key>line</key><integer>608</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -10992,12 +11405,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>595</integer>
+// CHECK-NEXT: <key>line</key><integer>608</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>595</integer>
+// CHECK-NEXT: <key>line</key><integer>608</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11005,12 +11418,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>596</integer>
+// CHECK-NEXT: <key>line</key><integer>609</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>596</integer>
+// CHECK-NEXT: <key>line</key><integer>609</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11026,12 +11439,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>596</integer>
+// CHECK-NEXT: <key>line</key><integer>609</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>596</integer>
+// CHECK-NEXT: <key>line</key><integer>609</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11039,12 +11452,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>597</integer>
+// CHECK-NEXT: <key>line</key><integer>610</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>597</integer>
+// CHECK-NEXT: <key>line</key><integer>610</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11060,12 +11473,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>597</integer>
+// CHECK-NEXT: <key>line</key><integer>610</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>597</integer>
+// CHECK-NEXT: <key>line</key><integer>610</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11073,12 +11486,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>597</integer>
+// CHECK-NEXT: <key>line</key><integer>610</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>597</integer>
+// CHECK-NEXT: <key>line</key><integer>610</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11090,7 +11503,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>597</integer>
+// CHECK-NEXT: <key>line</key><integer>610</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11098,12 +11511,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>597</integer>
+// CHECK-NEXT: <key>line</key><integer>610</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>597</integer>
+// CHECK-NEXT: <key>line</key><integer>610</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11121,10 +11534,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>rdar_6659160</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>27</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>27</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>597</integer>
+// CHECK-NEXT: <key>line</key><integer>610</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11140,12 +11553,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>575</integer>
+// CHECK-NEXT: <key>line</key><integer>588</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>575</integer>
+// CHECK-NEXT: <key>line</key><integer>588</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11153,12 +11566,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>581</integer>
+// CHECK-NEXT: <key>line</key><integer>594</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>581</integer>
+// CHECK-NEXT: <key>line</key><integer>594</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11174,12 +11587,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>581</integer>
+// CHECK-NEXT: <key>line</key><integer>594</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>581</integer>
+// CHECK-NEXT: <key>line</key><integer>594</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11187,12 +11600,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>581</integer>
+// CHECK-NEXT: <key>line</key><integer>594</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>581</integer>
+// CHECK-NEXT: <key>line</key><integer>594</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11204,7 +11617,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>581</integer>
+// CHECK-NEXT: <key>line</key><integer>594</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11212,12 +11625,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>581</integer>
+// CHECK-NEXT: <key>line</key><integer>594</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>581</integer>
+// CHECK-NEXT: <key>line</key><integer>594</integer>
// CHECK-NEXT: <key>col</key><integer>57</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11237,12 +11650,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>581</integer>
+// CHECK-NEXT: <key>line</key><integer>594</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>581</integer>
+// CHECK-NEXT: <key>line</key><integer>594</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11250,12 +11663,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11271,12 +11684,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11284,12 +11697,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11301,7 +11714,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11309,12 +11722,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11334,12 +11747,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>582</integer>
+// CHECK-NEXT: <key>line</key><integer>595</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11347,12 +11760,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>585</integer>
+// CHECK-NEXT: <key>line</key><integer>598</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>585</integer>
+// CHECK-NEXT: <key>line</key><integer>598</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11368,12 +11781,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>585</integer>
+// CHECK-NEXT: <key>line</key><integer>598</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>585</integer>
+// CHECK-NEXT: <key>line</key><integer>598</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11381,12 +11794,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>593</integer>
+// CHECK-NEXT: <key>line</key><integer>606</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>593</integer>
+// CHECK-NEXT: <key>line</key><integer>606</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11402,12 +11815,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>593</integer>
+// CHECK-NEXT: <key>line</key><integer>606</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>593</integer>
+// CHECK-NEXT: <key>line</key><integer>606</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11415,12 +11828,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>593</integer>
+// CHECK-NEXT: <key>line</key><integer>606</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>593</integer>
+// CHECK-NEXT: <key>line</key><integer>606</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11432,7 +11845,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>593</integer>
+// CHECK-NEXT: <key>line</key><integer>606</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11440,12 +11853,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>593</integer>
+// CHECK-NEXT: <key>line</key><integer>606</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>593</integer>
+// CHECK-NEXT: <key>line</key><integer>606</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11465,12 +11878,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>593</integer>
+// CHECK-NEXT: <key>line</key><integer>606</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>593</integer>
+// CHECK-NEXT: <key>line</key><integer>606</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11478,12 +11891,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>594</integer>
+// CHECK-NEXT: <key>line</key><integer>607</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>594</integer>
+// CHECK-NEXT: <key>line</key><integer>607</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11499,12 +11912,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>594</integer>
+// CHECK-NEXT: <key>line</key><integer>607</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>594</integer>
+// CHECK-NEXT: <key>line</key><integer>607</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11512,12 +11925,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>595</integer>
+// CHECK-NEXT: <key>line</key><integer>608</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>595</integer>
+// CHECK-NEXT: <key>line</key><integer>608</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11533,12 +11946,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>595</integer>
+// CHECK-NEXT: <key>line</key><integer>608</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>595</integer>
+// CHECK-NEXT: <key>line</key><integer>608</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11546,12 +11959,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>596</integer>
+// CHECK-NEXT: <key>line</key><integer>609</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>596</integer>
+// CHECK-NEXT: <key>line</key><integer>609</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11567,12 +11980,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>596</integer>
+// CHECK-NEXT: <key>line</key><integer>609</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>596</integer>
+// CHECK-NEXT: <key>line</key><integer>609</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11580,12 +11993,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>597</integer>
+// CHECK-NEXT: <key>line</key><integer>610</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>597</integer>
+// CHECK-NEXT: <key>line</key><integer>610</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11601,12 +12014,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>597</integer>
+// CHECK-NEXT: <key>line</key><integer>610</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>597</integer>
+// CHECK-NEXT: <key>line</key><integer>610</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11614,12 +12027,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>599</integer>
+// CHECK-NEXT: <key>line</key><integer>612</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>599</integer>
+// CHECK-NEXT: <key>line</key><integer>612</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11635,12 +12048,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>599</integer>
+// CHECK-NEXT: <key>line</key><integer>612</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>599</integer>
+// CHECK-NEXT: <key>line</key><integer>612</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11648,12 +12061,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>602</integer>
+// CHECK-NEXT: <key>line</key><integer>615</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>602</integer>
+// CHECK-NEXT: <key>line</key><integer>615</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11669,12 +12082,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>602</integer>
+// CHECK-NEXT: <key>line</key><integer>615</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>602</integer>
+// CHECK-NEXT: <key>line</key><integer>615</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11682,12 +12095,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>603</integer>
+// CHECK-NEXT: <key>line</key><integer>616</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>603</integer>
+// CHECK-NEXT: <key>line</key><integer>616</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11699,7 +12112,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>603</integer>
+// CHECK-NEXT: <key>line</key><integer>616</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11707,12 +12120,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>603</integer>
+// CHECK-NEXT: <key>line</key><integer>616</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>603</integer>
+// CHECK-NEXT: <key>line</key><integer>616</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11730,10 +12143,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Bad release</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>rdar_6659160</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>33</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>33</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>603</integer>
+// CHECK-NEXT: <key>line</key><integer>616</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11749,12 +12162,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>625</integer>
+// CHECK-NEXT: <key>line</key><integer>638</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>625</integer>
+// CHECK-NEXT: <key>line</key><integer>638</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11762,12 +12175,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>625</integer>
+// CHECK-NEXT: <key>line</key><integer>638</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>625</integer>
+// CHECK-NEXT: <key>line</key><integer>638</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11779,7 +12192,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>625</integer>
+// CHECK-NEXT: <key>line</key><integer>638</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11787,12 +12200,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>625</integer>
+// CHECK-NEXT: <key>line</key><integer>638</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>625</integer>
+// CHECK-NEXT: <key>line</key><integer>638</integer>
// CHECK-NEXT: <key>col</key><integer>34</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11812,12 +12225,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>625</integer>
+// CHECK-NEXT: <key>line</key><integer>638</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>625</integer>
+// CHECK-NEXT: <key>line</key><integer>638</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11825,12 +12238,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>626</integer>
+// CHECK-NEXT: <key>line</key><integer>639</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>626</integer>
+// CHECK-NEXT: <key>line</key><integer>639</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11842,7 +12255,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>626</integer>
+// CHECK-NEXT: <key>line</key><integer>639</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11850,24 +12263,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>626</integer>
+// CHECK-NEXT: <key>line</key><integer>639</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>626</integer>
+// CHECK-NEXT: <key>line</key><integer>639</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>626</integer>
+// CHECK-NEXT: <key>line</key><integer>639</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>626</integer>
+// CHECK-NEXT: <key>line</key><integer>639</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11887,12 +12300,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>626</integer>
+// CHECK-NEXT: <key>line</key><integer>639</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>626</integer>
+// CHECK-NEXT: <key>line</key><integer>639</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11900,12 +12313,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>627</integer>
+// CHECK-NEXT: <key>line</key><integer>640</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>627</integer>
+// CHECK-NEXT: <key>line</key><integer>640</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11917,7 +12330,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>627</integer>
+// CHECK-NEXT: <key>line</key><integer>640</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11925,12 +12338,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>627</integer>
+// CHECK-NEXT: <key>line</key><integer>640</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>627</integer>
+// CHECK-NEXT: <key>line</key><integer>640</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11948,10 +12361,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Use-after-release</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>pr3820_ReleaseAfterDealloc</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>627</integer>
+// CHECK-NEXT: <key>line</key><integer>640</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11967,12 +12380,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>633</integer>
+// CHECK-NEXT: <key>line</key><integer>646</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>633</integer>
+// CHECK-NEXT: <key>line</key><integer>646</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -11980,12 +12393,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>634</integer>
+// CHECK-NEXT: <key>line</key><integer>647</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>634</integer>
+// CHECK-NEXT: <key>line</key><integer>647</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12001,12 +12414,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>634</integer>
+// CHECK-NEXT: <key>line</key><integer>647</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>634</integer>
+// CHECK-NEXT: <key>line</key><integer>647</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12014,12 +12427,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>634</integer>
+// CHECK-NEXT: <key>line</key><integer>647</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>634</integer>
+// CHECK-NEXT: <key>line</key><integer>647</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12031,7 +12444,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>634</integer>
+// CHECK-NEXT: <key>line</key><integer>647</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12039,12 +12452,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>634</integer>
+// CHECK-NEXT: <key>line</key><integer>647</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>634</integer>
+// CHECK-NEXT: <key>line</key><integer>647</integer>
// CHECK-NEXT: <key>col</key><integer>34</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12064,12 +12477,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>634</integer>
+// CHECK-NEXT: <key>line</key><integer>647</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>634</integer>
+// CHECK-NEXT: <key>line</key><integer>647</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12077,12 +12490,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>635</integer>
+// CHECK-NEXT: <key>line</key><integer>648</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>635</integer>
+// CHECK-NEXT: <key>line</key><integer>648</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12094,7 +12507,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>635</integer>
+// CHECK-NEXT: <key>line</key><integer>648</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12102,24 +12515,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>635</integer>
+// CHECK-NEXT: <key>line</key><integer>648</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>635</integer>
+// CHECK-NEXT: <key>line</key><integer>648</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>635</integer>
+// CHECK-NEXT: <key>line</key><integer>648</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>635</integer>
+// CHECK-NEXT: <key>line</key><integer>648</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12139,12 +12552,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>635</integer>
+// CHECK-NEXT: <key>line</key><integer>648</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>635</integer>
+// CHECK-NEXT: <key>line</key><integer>648</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12152,12 +12565,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>636</integer>
+// CHECK-NEXT: <key>line</key><integer>649</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>636</integer>
+// CHECK-NEXT: <key>line</key><integer>649</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12169,7 +12582,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>636</integer>
+// CHECK-NEXT: <key>line</key><integer>649</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12177,12 +12590,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>636</integer>
+// CHECK-NEXT: <key>line</key><integer>649</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>636</integer>
+// CHECK-NEXT: <key>line</key><integer>649</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12200,10 +12613,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Use-after-release</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>pr3820_DeallocAfterRelease</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>636</integer>
+// CHECK-NEXT: <key>line</key><integer>649</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12219,12 +12632,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>688</integer>
+// CHECK-NEXT: <key>line</key><integer>701</integer>
// CHECK-NEXT: <key>col</key><integer>2</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>688</integer>
+// CHECK-NEXT: <key>line</key><integer>701</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12232,12 +12645,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>688</integer>
+// CHECK-NEXT: <key>line</key><integer>701</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>688</integer>
+// CHECK-NEXT: <key>line</key><integer>701</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12249,7 +12662,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>688</integer>
+// CHECK-NEXT: <key>line</key><integer>701</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12257,12 +12670,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>688</integer>
+// CHECK-NEXT: <key>line</key><integer>701</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>688</integer>
+// CHECK-NEXT: <key>line</key><integer>701</integer>
// CHECK-NEXT: <key>col</key><integer>76</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12282,12 +12695,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>688</integer>
+// CHECK-NEXT: <key>line</key><integer>701</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>688</integer>
+// CHECK-NEXT: <key>line</key><integer>701</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12295,12 +12708,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>688</integer>
+// CHECK-NEXT: <key>line</key><integer>701</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>688</integer>
+// CHECK-NEXT: <key>line</key><integer>701</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12312,7 +12725,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>688</integer>
+// CHECK-NEXT: <key>line</key><integer>701</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12320,24 +12733,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>688</integer>
+// CHECK-NEXT: <key>line</key><integer>701</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>688</integer>
+// CHECK-NEXT: <key>line</key><integer>701</integer>
// CHECK-NEXT: <key>col</key><integer>84</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>688</integer>
+// CHECK-NEXT: <key>line</key><integer>701</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>688</integer>
+// CHECK-NEXT: <key>line</key><integer>701</integer>
// CHECK-NEXT: <key>col</key><integer>76</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12357,12 +12770,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>688</integer>
+// CHECK-NEXT: <key>line</key><integer>701</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>688</integer>
+// CHECK-NEXT: <key>line</key><integer>701</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12370,12 +12783,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>693</integer>
+// CHECK-NEXT: <key>line</key><integer>706</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>693</integer>
+// CHECK-NEXT: <key>line</key><integer>706</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12387,7 +12800,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>693</integer>
+// CHECK-NEXT: <key>line</key><integer>706</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12403,10 +12816,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
// CHECK-NEXT: <key>issue_context</key><string>applicationDidFinishLaunching:</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>6</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>6</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>693</integer>
+// CHECK-NEXT: <key>line</key><integer>706</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12422,12 +12835,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>700</integer>
+// CHECK-NEXT: <key>line</key><integer>713</integer>
// CHECK-NEXT: <key>col</key><integer>2</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>700</integer>
+// CHECK-NEXT: <key>line</key><integer>713</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12435,12 +12848,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>700</integer>
+// CHECK-NEXT: <key>line</key><integer>713</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>700</integer>
+// CHECK-NEXT: <key>line</key><integer>713</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12452,7 +12865,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>700</integer>
+// CHECK-NEXT: <key>line</key><integer>713</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12460,12 +12873,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>700</integer>
+// CHECK-NEXT: <key>line</key><integer>713</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>700</integer>
+// CHECK-NEXT: <key>line</key><integer>713</integer>
// CHECK-NEXT: <key>col</key><integer>76</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12485,12 +12898,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>700</integer>
+// CHECK-NEXT: <key>line</key><integer>713</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>700</integer>
+// CHECK-NEXT: <key>line</key><integer>713</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12498,12 +12911,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>700</integer>
+// CHECK-NEXT: <key>line</key><integer>713</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>700</integer>
+// CHECK-NEXT: <key>line</key><integer>713</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12515,7 +12928,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>700</integer>
+// CHECK-NEXT: <key>line</key><integer>713</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12523,24 +12936,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>700</integer>
+// CHECK-NEXT: <key>line</key><integer>713</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>700</integer>
+// CHECK-NEXT: <key>line</key><integer>713</integer>
// CHECK-NEXT: <key>col</key><integer>84</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>700</integer>
+// CHECK-NEXT: <key>line</key><integer>713</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>700</integer>
+// CHECK-NEXT: <key>line</key><integer>713</integer>
// CHECK-NEXT: <key>col</key><integer>76</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12560,12 +12973,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>700</integer>
+// CHECK-NEXT: <key>line</key><integer>713</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>700</integer>
+// CHECK-NEXT: <key>line</key><integer>713</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12573,12 +12986,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>701</integer>
+// CHECK-NEXT: <key>line</key><integer>714</integer>
// CHECK-NEXT: <key>col</key><integer>2</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>701</integer>
+// CHECK-NEXT: <key>line</key><integer>714</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12594,12 +13007,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>701</integer>
+// CHECK-NEXT: <key>line</key><integer>714</integer>
// CHECK-NEXT: <key>col</key><integer>2</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>701</integer>
+// CHECK-NEXT: <key>line</key><integer>714</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12607,12 +13020,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>703</integer>
+// CHECK-NEXT: <key>line</key><integer>716</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>703</integer>
+// CHECK-NEXT: <key>line</key><integer>716</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12624,7 +13037,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>703</integer>
+// CHECK-NEXT: <key>line</key><integer>716</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12640,10 +13053,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
// CHECK-NEXT: <key>issue_context</key><string>radar10102244</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>703</integer>
+// CHECK-NEXT: <key>line</key><integer>716</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12659,12 +13072,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>711</integer>
+// CHECK-NEXT: <key>line</key><integer>724</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>711</integer>
+// CHECK-NEXT: <key>line</key><integer>724</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12672,12 +13085,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>712</integer>
+// CHECK-NEXT: <key>line</key><integer>725</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>712</integer>
+// CHECK-NEXT: <key>line</key><integer>725</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12693,12 +13106,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>712</integer>
+// CHECK-NEXT: <key>line</key><integer>725</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>712</integer>
+// CHECK-NEXT: <key>line</key><integer>725</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12706,12 +13119,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>712</integer>
+// CHECK-NEXT: <key>line</key><integer>725</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>712</integer>
+// CHECK-NEXT: <key>line</key><integer>725</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12723,7 +13136,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>712</integer>
+// CHECK-NEXT: <key>line</key><integer>725</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12731,12 +13144,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>712</integer>
+// CHECK-NEXT: <key>line</key><integer>725</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>712</integer>
+// CHECK-NEXT: <key>line</key><integer>725</integer>
// CHECK-NEXT: <key>col</key><integer>34</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12756,12 +13169,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>712</integer>
+// CHECK-NEXT: <key>line</key><integer>725</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>712</integer>
+// CHECK-NEXT: <key>line</key><integer>725</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12769,12 +13182,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>713</integer>
+// CHECK-NEXT: <key>line</key><integer>726</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>713</integer>
+// CHECK-NEXT: <key>line</key><integer>726</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12786,7 +13199,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>713</integer>
+// CHECK-NEXT: <key>line</key><integer>726</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12794,12 +13207,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>713</integer>
+// CHECK-NEXT: <key>line</key><integer>726</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>713</integer>
+// CHECK-NEXT: <key>line</key><integer>726</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12817,10 +13230,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Bad release</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>rdar_6257780_Case1</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>713</integer>
+// CHECK-NEXT: <key>line</key><integer>726</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12836,12 +13249,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>788</integer>
+// CHECK-NEXT: <key>line</key><integer>801</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>788</integer>
+// CHECK-NEXT: <key>line</key><integer>801</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12849,12 +13262,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>789</integer>
+// CHECK-NEXT: <key>line</key><integer>802</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>789</integer>
+// CHECK-NEXT: <key>line</key><integer>802</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12866,7 +13279,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>789</integer>
+// CHECK-NEXT: <key>line</key><integer>802</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12874,12 +13287,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>789</integer>
+// CHECK-NEXT: <key>line</key><integer>802</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>789</integer>
+// CHECK-NEXT: <key>line</key><integer>802</integer>
// CHECK-NEXT: <key>col</key><integer>36</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12899,12 +13312,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>789</integer>
+// CHECK-NEXT: <key>line</key><integer>802</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>789</integer>
+// CHECK-NEXT: <key>line</key><integer>802</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12912,13 +13325,13 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>791</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>line</key><integer>803</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>791</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>line</key><integer>803</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
@@ -12929,10 +13342,25 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>791</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>line</key><integer>803</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>803</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>803</integer>
+// CHECK-NEXT: <key>col</key><integer>13</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1</string>
@@ -12945,11 +13373,11 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
// CHECK-NEXT: <key>issue_context</key><string>_initReturningNewClassBad</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>791</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>line</key><integer>803</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </dict>
@@ -12964,12 +13392,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>793</integer>
+// CHECK-NEXT: <key>line</key><integer>806</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>793</integer>
+// CHECK-NEXT: <key>line</key><integer>806</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12977,12 +13405,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>794</integer>
+// CHECK-NEXT: <key>line</key><integer>807</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>794</integer>
+// CHECK-NEXT: <key>line</key><integer>807</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -12998,12 +13426,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>794</integer>
+// CHECK-NEXT: <key>line</key><integer>807</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>794</integer>
+// CHECK-NEXT: <key>line</key><integer>807</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13011,12 +13439,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>794</integer>
+// CHECK-NEXT: <key>line</key><integer>807</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>794</integer>
+// CHECK-NEXT: <key>line</key><integer>807</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13028,7 +13456,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>794</integer>
+// CHECK-NEXT: <key>line</key><integer>807</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13036,12 +13464,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>794</integer>
+// CHECK-NEXT: <key>line</key><integer>807</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>794</integer>
+// CHECK-NEXT: <key>line</key><integer>807</integer>
// CHECK-NEXT: <key>col</key><integer>43</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13061,12 +13489,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>794</integer>
+// CHECK-NEXT: <key>line</key><integer>807</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>794</integer>
+// CHECK-NEXT: <key>line</key><integer>807</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13074,12 +13502,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>795</integer>
+// CHECK-NEXT: <key>line</key><integer>808</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>795</integer>
+// CHECK-NEXT: <key>line</key><integer>808</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13095,12 +13523,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>795</integer>
+// CHECK-NEXT: <key>line</key><integer>808</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>795</integer>
+// CHECK-NEXT: <key>line</key><integer>808</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13108,12 +13536,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>795</integer>
+// CHECK-NEXT: <key>line</key><integer>808</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>795</integer>
+// CHECK-NEXT: <key>line</key><integer>808</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13125,7 +13553,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>795</integer>
+// CHECK-NEXT: <key>line</key><integer>808</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13133,24 +13561,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>795</integer>
+// CHECK-NEXT: <key>line</key><integer>808</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>795</integer>
+// CHECK-NEXT: <key>line</key><integer>808</integer>
// CHECK-NEXT: <key>col</key><integer>27</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>795</integer>
+// CHECK-NEXT: <key>line</key><integer>808</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>795</integer>
+// CHECK-NEXT: <key>line</key><integer>808</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13170,12 +13598,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>795</integer>
+// CHECK-NEXT: <key>line</key><integer>808</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>795</integer>
+// CHECK-NEXT: <key>line</key><integer>808</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13183,12 +13611,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>795</integer>
+// CHECK-NEXT: <key>line</key><integer>808</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>795</integer>
+// CHECK-NEXT: <key>line</key><integer>808</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13200,7 +13628,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>795</integer>
+// CHECK-NEXT: <key>line</key><integer>808</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13208,53 +13636,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>795</integer>
+// CHECK-NEXT: <key>line</key><integer>808</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>795</integer>
-// CHECK-NEXT: <key>col</key><integer>27</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>795</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>795</integer>
-// CHECK-NEXT: <key>col</key><integer>27</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Object returned to caller with a +0 retain count</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Object returned to caller with a +0 retain count</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>795</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>795</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>795</integer>
+// CHECK-NEXT: <key>line</key><integer>808</integer>
// CHECK-NEXT: <key>col</key><integer>27</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13272,10 +13659,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Method should return an owned object</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
// CHECK-NEXT: <key>issue_context</key><string>initReturningNewClassBad2</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>795</integer>
+// CHECK-NEXT: <key>line</key><integer>808</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13291,12 +13678,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>833</integer>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>833</integer>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
// CHECK-NEXT: <key>col</key><integer>35</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13304,12 +13691,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>833</integer>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
// CHECK-NEXT: <key>col</key><integer>37</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>833</integer>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
// CHECK-NEXT: <key>col</key><integer>37</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13321,7 +13708,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>833</integer>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
// CHECK-NEXT: <key>col</key><integer>37</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13329,12 +13716,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>833</integer>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
// CHECK-NEXT: <key>col</key><integer>37</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>833</integer>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
// CHECK-NEXT: <key>col</key><integer>59</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13354,12 +13741,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>833</integer>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
// CHECK-NEXT: <key>col</key><integer>37</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>833</integer>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
// CHECK-NEXT: <key>col</key><integer>37</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13367,12 +13754,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>833</integer>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>833</integer>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
// CHECK-NEXT: <key>col</key><integer>35</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13384,7 +13771,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>833</integer>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13392,24 +13779,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>833</integer>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>833</integer>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
// CHECK-NEXT: <key>col</key><integer>59</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>833</integer>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
// CHECK-NEXT: <key>col</key><integer>37</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>833</integer>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
// CHECK-NEXT: <key>col</key><integer>59</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13425,7 +13812,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>833</integer>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13433,12 +13820,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>833</integer>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>833</integer>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
// CHECK-NEXT: <key>col</key><integer>59</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13456,10 +13843,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak of returned object</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
// CHECK-NEXT: <key>issue_context</key><string>NoCopyString</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>0</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>0</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>833</integer>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13475,12 +13862,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>35</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13488,12 +13875,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>37</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>37</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13505,7 +13892,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>37</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13513,12 +13900,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>37</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>59</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13538,12 +13925,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>37</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>37</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13551,12 +13938,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>35</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13568,7 +13955,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13576,24 +13963,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>59</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>37</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>59</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13609,7 +13996,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13617,12 +14004,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>59</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13640,10 +14027,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak of returned object</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
// CHECK-NEXT: <key>issue_context</key><string>noCopyString</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>0</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>0</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13652,6 +14039,255 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>path</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>851</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>851</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>851</integer>
+// CHECK-NEXT: <key>col</key><integer>18</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling &apos;NoCopyString&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;NoCopyString&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from &apos;test_RDar6859457&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;test_RDar6859457&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
+// CHECK-NEXT: <key>col</key><integer>30</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
+// CHECK-NEXT: <key>col</key><integer>35</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
+// CHECK-NEXT: <key>col</key><integer>30</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
+// CHECK-NEXT: <key>col</key><integer>35</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
+// CHECK-NEXT: <key>col</key><integer>37</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
+// CHECK-NEXT: <key>col</key><integer>37</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
+// CHECK-NEXT: <key>col</key><integer>37</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
+// CHECK-NEXT: <key>col</key><integer>37</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>846</integer>
+// CHECK-NEXT: <key>col</key><integer>59</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Method returns an Objective-C object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Method returns an Objective-C object with a +1 retain count</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>851</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>851</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>851</integer>
+// CHECK-NEXT: <key>col</key><integer>18</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Returning from &apos;NoCopyString&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Returning from &apos;NoCopyString&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>851</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>851</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>852</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>852</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>852</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>852</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>852</integer>
+// CHECK-NEXT: <key>col</key><integer>18</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Potential leak of an object</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Leak</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_RDar6859457</string>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>852</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
// CHECK-NEXT: <key>edges</key>
// CHECK-NEXT: <array>
@@ -13659,12 +14295,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>838</integer>
+// CHECK-NEXT: <key>line</key><integer>851</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>838</integer>
+// CHECK-NEXT: <key>line</key><integer>851</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13672,12 +14308,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>839</integer>
+// CHECK-NEXT: <key>line</key><integer>852</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>839</integer>
+// CHECK-NEXT: <key>line</key><integer>852</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13689,7 +14325,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>839</integer>
+// CHECK-NEXT: <key>line</key><integer>852</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13697,12 +14333,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>839</integer>
+// CHECK-NEXT: <key>line</key><integer>852</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>839</integer>
+// CHECK-NEXT: <key>line</key><integer>852</integer>
// CHECK-NEXT: <key>col</key><integer>18</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13718,7 +14354,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13736,12 +14372,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13749,12 +14385,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>35</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13770,12 +14406,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>35</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13783,12 +14419,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>37</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>37</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13800,7 +14436,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>37</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13808,12 +14444,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>37</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>834</integer>
+// CHECK-NEXT: <key>line</key><integer>847</integer>
// CHECK-NEXT: <key>col</key><integer>59</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13829,7 +14465,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>839</integer>
+// CHECK-NEXT: <key>line</key><integer>852</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13837,12 +14473,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>839</integer>
+// CHECK-NEXT: <key>line</key><integer>852</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>839</integer>
+// CHECK-NEXT: <key>line</key><integer>852</integer>
// CHECK-NEXT: <key>col</key><integer>18</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13862,12 +14498,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>839</integer>
+// CHECK-NEXT: <key>line</key><integer>852</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>839</integer>
+// CHECK-NEXT: <key>line</key><integer>852</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13875,13 +14511,13 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>842</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>line</key><integer>853</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>842</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>line</key><integer>853</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
@@ -13892,10 +14528,25 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>842</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>line</key><integer>853</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>853</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>853</integer>
+// CHECK-NEXT: <key>col</key><integer>54</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1</string>
@@ -13908,11 +14559,11 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_RDar6859457</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>842</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>line</key><integer>853</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </dict>
@@ -13927,12 +14578,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>866</integer>
+// CHECK-NEXT: <key>line</key><integer>886</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>866</integer>
+// CHECK-NEXT: <key>line</key><integer>886</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13940,12 +14591,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>866</integer>
+// CHECK-NEXT: <key>line</key><integer>886</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>866</integer>
+// CHECK-NEXT: <key>line</key><integer>886</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13957,7 +14608,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>866</integer>
+// CHECK-NEXT: <key>line</key><integer>886</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13965,12 +14616,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>866</integer>
+// CHECK-NEXT: <key>line</key><integer>886</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>866</integer>
+// CHECK-NEXT: <key>line</key><integer>886</integer>
// CHECK-NEXT: <key>col</key><integer>32</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -13990,12 +14641,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>866</integer>
+// CHECK-NEXT: <key>line</key><integer>886</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>866</integer>
+// CHECK-NEXT: <key>line</key><integer>886</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14003,12 +14654,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>866</integer>
+// CHECK-NEXT: <key>line</key><integer>886</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>866</integer>
+// CHECK-NEXT: <key>line</key><integer>886</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14020,7 +14671,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>866</integer>
+// CHECK-NEXT: <key>line</key><integer>886</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14028,24 +14679,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>866</integer>
+// CHECK-NEXT: <key>line</key><integer>886</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>866</integer>
+// CHECK-NEXT: <key>line</key><integer>886</integer>
// CHECK-NEXT: <key>col</key><integer>32</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>866</integer>
+// CHECK-NEXT: <key>line</key><integer>886</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>866</integer>
+// CHECK-NEXT: <key>line</key><integer>886</integer>
// CHECK-NEXT: <key>col</key><integer>32</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14061,7 +14712,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>866</integer>
+// CHECK-NEXT: <key>line</key><integer>886</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14069,12 +14720,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>866</integer>
+// CHECK-NEXT: <key>line</key><integer>886</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>866</integer>
+// CHECK-NEXT: <key>line</key><integer>886</integer>
// CHECK-NEXT: <key>col</key><integer>32</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14092,10 +14743,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak of returned object</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
// CHECK-NEXT: <key>issue_context</key><string>:</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>866</integer>
+// CHECK-NEXT: <key>line</key><integer>886</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14107,7 +14758,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>896</integer>
+// CHECK-NEXT: <key>line</key><integer>916</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14115,12 +14766,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>896</integer>
+// CHECK-NEXT: <key>line</key><integer>916</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>896</integer>
+// CHECK-NEXT: <key>line</key><integer>916</integer>
// CHECK-NEXT: <key>col</key><integer>38</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14140,12 +14791,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>896</integer>
+// CHECK-NEXT: <key>line</key><integer>916</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>896</integer>
+// CHECK-NEXT: <key>line</key><integer>916</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14153,12 +14804,441 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>900</integer>
+// CHECK-NEXT: <key>line</key><integer>917</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>917</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>917</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>917</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>917</integer>
+// CHECK-NEXT: <key>col</key><integer>42</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Potential leak of an object</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Leak</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>rdar6902710</string>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>917</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>916</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>916</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>917</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>917</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>917</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>917</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>917</integer>
+// CHECK-NEXT: <key>col</key><integer>42</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Method returns an Objective-C object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Method returns an Objective-C object with a +1 retain count</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>917</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>917</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>918</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>918</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>918</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>918</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>918</integer>
+// CHECK-NEXT: <key>col</key><integer>43</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Potential leak of an object</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Leak</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>rdar6902710</string>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>918</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>916</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>916</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>918</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>918</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>918</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>918</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>918</integer>
+// CHECK-NEXT: <key>col</key><integer>43</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Method returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Method returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>918</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>918</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>919</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>919</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>919</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>919</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>919</integer>
+// CHECK-NEXT: <key>col</key><integer>69</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Potential leak of an object</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Leak</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>rdar6902710</string>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>919</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>916</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>916</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>919</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>919</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>919</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>919</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>919</integer>
+// CHECK-NEXT: <key>col</key><integer>69</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Method returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Method returns a Core Foundation object with a +1 retain count</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>919</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>919</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>920</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>900</integer>
+// CHECK-NEXT: <key>line</key><integer>920</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14170,7 +15250,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>900</integer>
+// CHECK-NEXT: <key>line</key><integer>920</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14186,10 +15266,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>rdar6902710</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>900</integer>
+// CHECK-NEXT: <key>line</key><integer>920</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14201,7 +15281,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>908</integer>
+// CHECK-NEXT: <key>line</key><integer>928</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14209,12 +15289,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>908</integer>
+// CHECK-NEXT: <key>line</key><integer>928</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>908</integer>
+// CHECK-NEXT: <key>line</key><integer>928</integer>
// CHECK-NEXT: <key>col</key><integer>45</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14234,12 +15314,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>908</integer>
+// CHECK-NEXT: <key>line</key><integer>928</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>908</integer>
+// CHECK-NEXT: <key>line</key><integer>928</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14247,12 +15327,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>909</integer>
+// CHECK-NEXT: <key>line</key><integer>929</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>909</integer>
+// CHECK-NEXT: <key>line</key><integer>929</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14264,7 +15344,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>909</integer>
+// CHECK-NEXT: <key>line</key><integer>929</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14280,10 +15360,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>rdar6945561</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>909</integer>
+// CHECK-NEXT: <key>line</key><integer>929</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14295,7 +15375,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>917</integer>
+// CHECK-NEXT: <key>line</key><integer>937</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14303,12 +15383,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>917</integer>
+// CHECK-NEXT: <key>line</key><integer>937</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>917</integer>
+// CHECK-NEXT: <key>line</key><integer>937</integer>
// CHECK-NEXT: <key>col</key><integer>49</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14328,12 +15408,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>917</integer>
+// CHECK-NEXT: <key>line</key><integer>937</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>917</integer>
+// CHECK-NEXT: <key>line</key><integer>937</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14341,12 +15421,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>918</integer>
+// CHECK-NEXT: <key>line</key><integer>938</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>918</integer>
+// CHECK-NEXT: <key>line</key><integer>938</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14358,7 +15438,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>918</integer>
+// CHECK-NEXT: <key>line</key><integer>938</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14374,10 +15454,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>IOBSDNameMatching_wrapper</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>918</integer>
+// CHECK-NEXT: <key>line</key><integer>938</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14389,7 +15469,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>921</integer>
+// CHECK-NEXT: <key>line</key><integer>941</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14397,12 +15477,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>921</integer>
+// CHECK-NEXT: <key>line</key><integer>941</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>921</integer>
+// CHECK-NEXT: <key>line</key><integer>941</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14422,12 +15502,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>921</integer>
+// CHECK-NEXT: <key>line</key><integer>941</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>921</integer>
+// CHECK-NEXT: <key>line</key><integer>941</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14435,12 +15515,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>922</integer>
+// CHECK-NEXT: <key>line</key><integer>942</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>922</integer>
+// CHECK-NEXT: <key>line</key><integer>942</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14452,7 +15532,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>922</integer>
+// CHECK-NEXT: <key>line</key><integer>942</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14468,10 +15548,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>IOServiceMatching_wrapper</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>922</integer>
+// CHECK-NEXT: <key>line</key><integer>942</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14483,7 +15563,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>925</integer>
+// CHECK-NEXT: <key>line</key><integer>945</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14491,12 +15571,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>925</integer>
+// CHECK-NEXT: <key>line</key><integer>945</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>925</integer>
+// CHECK-NEXT: <key>line</key><integer>945</integer>
// CHECK-NEXT: <key>col</key><integer>29</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14516,12 +15596,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>925</integer>
+// CHECK-NEXT: <key>line</key><integer>945</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>925</integer>
+// CHECK-NEXT: <key>line</key><integer>945</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14529,12 +15609,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>926</integer>
+// CHECK-NEXT: <key>line</key><integer>946</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>926</integer>
+// CHECK-NEXT: <key>line</key><integer>946</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14546,7 +15626,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>926</integer>
+// CHECK-NEXT: <key>line</key><integer>946</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14562,10 +15642,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>IOServiceNameMatching_wrapper</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>926</integer>
+// CHECK-NEXT: <key>line</key><integer>946</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14581,12 +15661,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>933</integer>
+// CHECK-NEXT: <key>line</key><integer>953</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>933</integer>
+// CHECK-NEXT: <key>line</key><integer>953</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14594,12 +15674,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>933</integer>
+// CHECK-NEXT: <key>line</key><integer>953</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>933</integer>
+// CHECK-NEXT: <key>line</key><integer>953</integer>
// CHECK-NEXT: <key>col</key><integer>39</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14611,7 +15691,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>933</integer>
+// CHECK-NEXT: <key>line</key><integer>953</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14619,12 +15699,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>933</integer>
+// CHECK-NEXT: <key>line</key><integer>953</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>933</integer>
+// CHECK-NEXT: <key>line</key><integer>953</integer>
// CHECK-NEXT: <key>col</key><integer>41</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14644,12 +15724,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>933</integer>
+// CHECK-NEXT: <key>line</key><integer>953</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>933</integer>
+// CHECK-NEXT: <key>line</key><integer>953</integer>
// CHECK-NEXT: <key>col</key><integer>39</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14657,12 +15737,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>934</integer>
+// CHECK-NEXT: <key>line</key><integer>954</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>934</integer>
+// CHECK-NEXT: <key>line</key><integer>954</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14674,7 +15754,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>934</integer>
+// CHECK-NEXT: <key>line</key><integer>954</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14682,24 +15762,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>934</integer>
+// CHECK-NEXT: <key>line</key><integer>954</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>934</integer>
+// CHECK-NEXT: <key>line</key><integer>954</integer>
// CHECK-NEXT: <key>col</key><integer>21</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>934</integer>
+// CHECK-NEXT: <key>line</key><integer>954</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>934</integer>
+// CHECK-NEXT: <key>line</key><integer>954</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14719,12 +15799,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>934</integer>
+// CHECK-NEXT: <key>line</key><integer>954</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>934</integer>
+// CHECK-NEXT: <key>line</key><integer>954</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14732,12 +15812,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>935</integer>
+// CHECK-NEXT: <key>line</key><integer>955</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>935</integer>
+// CHECK-NEXT: <key>line</key><integer>955</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14749,7 +15829,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>935</integer>
+// CHECK-NEXT: <key>line</key><integer>955</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14757,12 +15837,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>935</integer>
+// CHECK-NEXT: <key>line</key><integer>955</integer>
// CHECK-NEXT: <key>col</key><integer>58</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>935</integer>
+// CHECK-NEXT: <key>line</key><integer>955</integer>
// CHECK-NEXT: <key>col</key><integer>65</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14780,10 +15860,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Use-after-release</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>IOServiceAddNotification_wrapper</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>935</integer>
+// CHECK-NEXT: <key>line</key><integer>955</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14795,7 +15875,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>940</integer>
+// CHECK-NEXT: <key>line</key><integer>960</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14803,12 +15883,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>940</integer>
+// CHECK-NEXT: <key>line</key><integer>960</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>940</integer>
+// CHECK-NEXT: <key>line</key><integer>960</integer>
// CHECK-NEXT: <key>col</key><integer>36</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14828,12 +15908,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>940</integer>
+// CHECK-NEXT: <key>line</key><integer>960</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>940</integer>
+// CHECK-NEXT: <key>line</key><integer>960</integer>
// CHECK-NEXT: <key>col</key><integer>27</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14841,12 +15921,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>941</integer>
+// CHECK-NEXT: <key>line</key><integer>961</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>941</integer>
+// CHECK-NEXT: <key>line</key><integer>961</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14858,7 +15938,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>941</integer>
+// CHECK-NEXT: <key>line</key><integer>961</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14874,10 +15954,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>IORegistryEntryIDMatching_wrapper</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>941</integer>
+// CHECK-NEXT: <key>line</key><integer>961</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14889,7 +15969,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>945</integer>
+// CHECK-NEXT: <key>line</key><integer>965</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14897,12 +15977,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>945</integer>
+// CHECK-NEXT: <key>line</key><integer>965</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>945</integer>
+// CHECK-NEXT: <key>line</key><integer>965</integer>
// CHECK-NEXT: <key>col</key><integer>55</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14922,12 +16002,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>945</integer>
+// CHECK-NEXT: <key>line</key><integer>965</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>945</integer>
+// CHECK-NEXT: <key>line</key><integer>965</integer>
// CHECK-NEXT: <key>col</key><integer>28</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14935,12 +16015,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>946</integer>
+// CHECK-NEXT: <key>line</key><integer>966</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>946</integer>
+// CHECK-NEXT: <key>line</key><integer>966</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14952,7 +16032,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>946</integer>
+// CHECK-NEXT: <key>line</key><integer>966</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14968,10 +16048,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>IOOpenFirmwarePathMatching_wrapper</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>946</integer>
+// CHECK-NEXT: <key>line</key><integer>966</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -14987,12 +16067,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>949</integer>
+// CHECK-NEXT: <key>line</key><integer>969</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>949</integer>
+// CHECK-NEXT: <key>line</key><integer>969</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15000,12 +16080,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>949</integer>
+// CHECK-NEXT: <key>line</key><integer>969</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>949</integer>
+// CHECK-NEXT: <key>line</key><integer>969</integer>
// CHECK-NEXT: <key>col</key><integer>39</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15017,7 +16097,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>949</integer>
+// CHECK-NEXT: <key>line</key><integer>969</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15025,12 +16105,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>949</integer>
+// CHECK-NEXT: <key>line</key><integer>969</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>949</integer>
+// CHECK-NEXT: <key>line</key><integer>969</integer>
// CHECK-NEXT: <key>col</key><integer>41</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15050,12 +16130,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>949</integer>
+// CHECK-NEXT: <key>line</key><integer>969</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>949</integer>
+// CHECK-NEXT: <key>line</key><integer>969</integer>
// CHECK-NEXT: <key>col</key><integer>39</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15063,12 +16143,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>950</integer>
+// CHECK-NEXT: <key>line</key><integer>970</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>950</integer>
+// CHECK-NEXT: <key>line</key><integer>970</integer>
// CHECK-NEXT: <key>col</key><integer>29</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15080,7 +16160,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>950</integer>
+// CHECK-NEXT: <key>line</key><integer>970</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15088,24 +16168,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>950</integer>
+// CHECK-NEXT: <key>line</key><integer>970</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>950</integer>
+// CHECK-NEXT: <key>line</key><integer>970</integer>
// CHECK-NEXT: <key>col</key><integer>51</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>950</integer>
+// CHECK-NEXT: <key>line</key><integer>970</integer>
// CHECK-NEXT: <key>col</key><integer>43</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>950</integer>
+// CHECK-NEXT: <key>line</key><integer>970</integer>
// CHECK-NEXT: <key>col</key><integer>50</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15125,12 +16205,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>950</integer>
+// CHECK-NEXT: <key>line</key><integer>970</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>950</integer>
+// CHECK-NEXT: <key>line</key><integer>970</integer>
// CHECK-NEXT: <key>col</key><integer>29</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15138,12 +16218,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>951</integer>
+// CHECK-NEXT: <key>line</key><integer>971</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>951</integer>
+// CHECK-NEXT: <key>line</key><integer>971</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15155,7 +16235,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>951</integer>
+// CHECK-NEXT: <key>line</key><integer>971</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15163,12 +16243,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>951</integer>
+// CHECK-NEXT: <key>line</key><integer>971</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>951</integer>
+// CHECK-NEXT: <key>line</key><integer>971</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15186,10 +16266,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Use-after-release</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>IOServiceGetMatchingService_wrapper</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>951</integer>
+// CHECK-NEXT: <key>line</key><integer>971</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15205,12 +16285,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>955</integer>
+// CHECK-NEXT: <key>line</key><integer>975</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>955</integer>
+// CHECK-NEXT: <key>line</key><integer>975</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15218,12 +16298,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>955</integer>
+// CHECK-NEXT: <key>line</key><integer>975</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>955</integer>
+// CHECK-NEXT: <key>line</key><integer>975</integer>
// CHECK-NEXT: <key>col</key><integer>39</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15235,7 +16315,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>955</integer>
+// CHECK-NEXT: <key>line</key><integer>975</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15243,12 +16323,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>955</integer>
+// CHECK-NEXT: <key>line</key><integer>975</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>955</integer>
+// CHECK-NEXT: <key>line</key><integer>975</integer>
// CHECK-NEXT: <key>col</key><integer>41</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15268,12 +16348,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>955</integer>
+// CHECK-NEXT: <key>line</key><integer>975</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>955</integer>
+// CHECK-NEXT: <key>line</key><integer>975</integer>
// CHECK-NEXT: <key>col</key><integer>39</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15281,12 +16361,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>956</integer>
+// CHECK-NEXT: <key>line</key><integer>976</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>956</integer>
+// CHECK-NEXT: <key>line</key><integer>976</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15298,7 +16378,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>956</integer>
+// CHECK-NEXT: <key>line</key><integer>976</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15306,24 +16386,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>956</integer>
+// CHECK-NEXT: <key>line</key><integer>976</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>956</integer>
+// CHECK-NEXT: <key>line</key><integer>976</integer>
// CHECK-NEXT: <key>col</key><integer>62</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>956</integer>
+// CHECK-NEXT: <key>line</key><integer>976</integer>
// CHECK-NEXT: <key>col</key><integer>44</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>956</integer>
+// CHECK-NEXT: <key>line</key><integer>976</integer>
// CHECK-NEXT: <key>col</key><integer>51</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15343,12 +16423,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>956</integer>
+// CHECK-NEXT: <key>line</key><integer>976</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>956</integer>
+// CHECK-NEXT: <key>line</key><integer>976</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15356,12 +16436,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>957</integer>
+// CHECK-NEXT: <key>line</key><integer>977</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>957</integer>
+// CHECK-NEXT: <key>line</key><integer>977</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15373,7 +16453,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>957</integer>
+// CHECK-NEXT: <key>line</key><integer>977</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15381,12 +16461,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>957</integer>
+// CHECK-NEXT: <key>line</key><integer>977</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>957</integer>
+// CHECK-NEXT: <key>line</key><integer>977</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15404,10 +16484,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Use-after-release</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>IOServiceGetMatchingServices_wrapper</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>957</integer>
+// CHECK-NEXT: <key>line</key><integer>977</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15423,12 +16503,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>963</integer>
+// CHECK-NEXT: <key>line</key><integer>983</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>963</integer>
+// CHECK-NEXT: <key>line</key><integer>983</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15436,12 +16516,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>963</integer>
+// CHECK-NEXT: <key>line</key><integer>983</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>963</integer>
+// CHECK-NEXT: <key>line</key><integer>983</integer>
// CHECK-NEXT: <key>col</key><integer>39</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15453,7 +16533,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>963</integer>
+// CHECK-NEXT: <key>line</key><integer>983</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15461,12 +16541,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>963</integer>
+// CHECK-NEXT: <key>line</key><integer>983</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>963</integer>
+// CHECK-NEXT: <key>line</key><integer>983</integer>
// CHECK-NEXT: <key>col</key><integer>41</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15486,12 +16566,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>963</integer>
+// CHECK-NEXT: <key>line</key><integer>983</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>963</integer>
+// CHECK-NEXT: <key>line</key><integer>983</integer>
// CHECK-NEXT: <key>col</key><integer>39</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15499,12 +16579,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>964</integer>
+// CHECK-NEXT: <key>line</key><integer>984</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>964</integer>
+// CHECK-NEXT: <key>line</key><integer>984</integer>
// CHECK-NEXT: <key>col</key><integer>34</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15516,7 +16596,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>964</integer>
+// CHECK-NEXT: <key>line</key><integer>984</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15524,24 +16604,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>964</integer>
+// CHECK-NEXT: <key>line</key><integer>984</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>964</integer>
+// CHECK-NEXT: <key>line</key><integer>984</integer>
// CHECK-NEXT: <key>col</key><integer>106</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>964</integer>
+// CHECK-NEXT: <key>line</key><integer>984</integer>
// CHECK-NEXT: <key>col</key><integer>66</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>964</integer>
+// CHECK-NEXT: <key>line</key><integer>984</integer>
// CHECK-NEXT: <key>col</key><integer>73</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15561,12 +16641,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>964</integer>
+// CHECK-NEXT: <key>line</key><integer>984</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>964</integer>
+// CHECK-NEXT: <key>line</key><integer>984</integer>
// CHECK-NEXT: <key>col</key><integer>34</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15574,12 +16654,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>965</integer>
+// CHECK-NEXT: <key>line</key><integer>985</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>965</integer>
+// CHECK-NEXT: <key>line</key><integer>985</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15591,7 +16671,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>965</integer>
+// CHECK-NEXT: <key>line</key><integer>985</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15599,12 +16679,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>965</integer>
+// CHECK-NEXT: <key>line</key><integer>985</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>965</integer>
+// CHECK-NEXT: <key>line</key><integer>985</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15622,10 +16702,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Use-after-release</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>IOServiceAddMatchingNotification_wrapper</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>965</integer>
+// CHECK-NEXT: <key>line</key><integer>985</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15641,12 +16721,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1003</integer>
+// CHECK-NEXT: <key>line</key><integer>1023</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1003</integer>
+// CHECK-NEXT: <key>line</key><integer>1023</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15654,12 +16734,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1006</integer>
+// CHECK-NEXT: <key>line</key><integer>1026</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1006</integer>
+// CHECK-NEXT: <key>line</key><integer>1026</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15675,12 +16755,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1006</integer>
+// CHECK-NEXT: <key>line</key><integer>1026</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1006</integer>
+// CHECK-NEXT: <key>line</key><integer>1026</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15688,12 +16768,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1006</integer>
+// CHECK-NEXT: <key>line</key><integer>1026</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1006</integer>
+// CHECK-NEXT: <key>line</key><integer>1026</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15705,7 +16785,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1006</integer>
+// CHECK-NEXT: <key>line</key><integer>1026</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15713,12 +16793,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1006</integer>
+// CHECK-NEXT: <key>line</key><integer>1026</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1006</integer>
+// CHECK-NEXT: <key>line</key><integer>1026</integer>
// CHECK-NEXT: <key>col</key><integer>53</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15738,12 +16818,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1006</integer>
+// CHECK-NEXT: <key>line</key><integer>1026</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1006</integer>
+// CHECK-NEXT: <key>line</key><integer>1026</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15751,12 +16831,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1007</integer>
+// CHECK-NEXT: <key>line</key><integer>1027</integer>
// CHECK-NEXT: <key>col</key><integer>46</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1007</integer>
+// CHECK-NEXT: <key>line</key><integer>1027</integer>
// CHECK-NEXT: <key>col</key><integer>56</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15772,12 +16852,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1007</integer>
+// CHECK-NEXT: <key>line</key><integer>1027</integer>
// CHECK-NEXT: <key>col</key><integer>46</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1007</integer>
+// CHECK-NEXT: <key>line</key><integer>1027</integer>
// CHECK-NEXT: <key>col</key><integer>56</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15785,12 +16865,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1008</integer>
+// CHECK-NEXT: <key>line</key><integer>1028</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1008</integer>
+// CHECK-NEXT: <key>line</key><integer>1028</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15802,7 +16882,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1008</integer>
+// CHECK-NEXT: <key>line</key><integer>1028</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15810,24 +16890,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1008</integer>
+// CHECK-NEXT: <key>line</key><integer>1028</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1008</integer>
+// CHECK-NEXT: <key>line</key><integer>1028</integer>
// CHECK-NEXT: <key>col</key><integer>18</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1008</integer>
+// CHECK-NEXT: <key>line</key><integer>1028</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1008</integer>
+// CHECK-NEXT: <key>line</key><integer>1028</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15847,12 +16927,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1008</integer>
+// CHECK-NEXT: <key>line</key><integer>1028</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1008</integer>
+// CHECK-NEXT: <key>line</key><integer>1028</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15860,12 +16940,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1009</integer>
+// CHECK-NEXT: <key>line</key><integer>1029</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1009</integer>
+// CHECK-NEXT: <key>line</key><integer>1029</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15877,7 +16957,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1009</integer>
+// CHECK-NEXT: <key>line</key><integer>1029</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15885,24 +16965,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1009</integer>
+// CHECK-NEXT: <key>line</key><integer>1029</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1009</integer>
+// CHECK-NEXT: <key>line</key><integer>1029</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1009</integer>
+// CHECK-NEXT: <key>line</key><integer>1029</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1009</integer>
+// CHECK-NEXT: <key>line</key><integer>1029</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15922,12 +17002,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1009</integer>
+// CHECK-NEXT: <key>line</key><integer>1029</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1009</integer>
+// CHECK-NEXT: <key>line</key><integer>1029</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15935,12 +17015,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1010</integer>
+// CHECK-NEXT: <key>line</key><integer>1030</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1010</integer>
+// CHECK-NEXT: <key>line</key><integer>1030</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15952,7 +17032,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1010</integer>
+// CHECK-NEXT: <key>line</key><integer>1030</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15960,12 +17040,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1010</integer>
+// CHECK-NEXT: <key>line</key><integer>1030</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1010</integer>
+// CHECK-NEXT: <key>line</key><integer>1030</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -15983,10 +17063,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>rdar_7152619</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>8</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>8</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1010</integer>
+// CHECK-NEXT: <key>line</key><integer>1030</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16002,12 +17082,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1019</integer>
+// CHECK-NEXT: <key>line</key><integer>1039</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1019</integer>
+// CHECK-NEXT: <key>line</key><integer>1039</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16015,12 +17095,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1030</integer>
+// CHECK-NEXT: <key>line</key><integer>1050</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1030</integer>
+// CHECK-NEXT: <key>line</key><integer>1050</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16036,12 +17116,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1030</integer>
+// CHECK-NEXT: <key>line</key><integer>1050</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1030</integer>
+// CHECK-NEXT: <key>line</key><integer>1050</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16049,12 +17129,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1031</integer>
+// CHECK-NEXT: <key>line</key><integer>1051</integer>
// CHECK-NEXT: <key>col</key><integer>41</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1031</integer>
+// CHECK-NEXT: <key>line</key><integer>1051</integer>
// CHECK-NEXT: <key>col</key><integer>67</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16066,7 +17146,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1031</integer>
+// CHECK-NEXT: <key>line</key><integer>1051</integer>
// CHECK-NEXT: <key>col</key><integer>41</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16074,12 +17154,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1031</integer>
+// CHECK-NEXT: <key>line</key><integer>1051</integer>
// CHECK-NEXT: <key>col</key><integer>41</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1031</integer>
+// CHECK-NEXT: <key>line</key><integer>1051</integer>
// CHECK-NEXT: <key>col</key><integer>69</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16099,12 +17179,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1031</integer>
+// CHECK-NEXT: <key>line</key><integer>1051</integer>
// CHECK-NEXT: <key>col</key><integer>41</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1031</integer>
+// CHECK-NEXT: <key>line</key><integer>1051</integer>
// CHECK-NEXT: <key>col</key><integer>67</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16112,12 +17192,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1030</integer>
+// CHECK-NEXT: <key>line</key><integer>1050</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1030</integer>
+// CHECK-NEXT: <key>line</key><integer>1050</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16129,7 +17209,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1030</integer>
+// CHECK-NEXT: <key>line</key><integer>1050</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16137,12 +17217,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1030</integer>
+// CHECK-NEXT: <key>line</key><integer>1050</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1030</integer>
+// CHECK-NEXT: <key>line</key><integer>1050</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16160,10 +17240,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>rdar_7184450</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>12</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>12</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1030</integer>
+// CHECK-NEXT: <key>line</key><integer>1050</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16179,12 +17259,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1041</integer>
+// CHECK-NEXT: <key>line</key><integer>1061</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1041</integer>
+// CHECK-NEXT: <key>line</key><integer>1061</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16192,12 +17272,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1052</integer>
+// CHECK-NEXT: <key>line</key><integer>1072</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1052</integer>
+// CHECK-NEXT: <key>line</key><integer>1072</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16213,12 +17293,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1052</integer>
+// CHECK-NEXT: <key>line</key><integer>1072</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1052</integer>
+// CHECK-NEXT: <key>line</key><integer>1072</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16226,12 +17306,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1053</integer>
+// CHECK-NEXT: <key>line</key><integer>1073</integer>
// CHECK-NEXT: <key>col</key><integer>40</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1053</integer>
+// CHECK-NEXT: <key>line</key><integer>1073</integer>
// CHECK-NEXT: <key>col</key><integer>66</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16243,7 +17323,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1053</integer>
+// CHECK-NEXT: <key>line</key><integer>1073</integer>
// CHECK-NEXT: <key>col</key><integer>40</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16251,12 +17331,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1053</integer>
+// CHECK-NEXT: <key>line</key><integer>1073</integer>
// CHECK-NEXT: <key>col</key><integer>40</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1053</integer>
+// CHECK-NEXT: <key>line</key><integer>1073</integer>
// CHECK-NEXT: <key>col</key><integer>68</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16276,12 +17356,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1053</integer>
+// CHECK-NEXT: <key>line</key><integer>1073</integer>
// CHECK-NEXT: <key>col</key><integer>40</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1053</integer>
+// CHECK-NEXT: <key>line</key><integer>1073</integer>
// CHECK-NEXT: <key>col</key><integer>66</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16289,12 +17369,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1052</integer>
+// CHECK-NEXT: <key>line</key><integer>1072</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1052</integer>
+// CHECK-NEXT: <key>line</key><integer>1072</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16306,7 +17386,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1052</integer>
+// CHECK-NEXT: <key>line</key><integer>1072</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16314,12 +17394,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1052</integer>
+// CHECK-NEXT: <key>line</key><integer>1072</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1052</integer>
+// CHECK-NEXT: <key>line</key><integer>1072</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16337,10 +17417,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>rdar_7184450_pos</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>12</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>12</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1052</integer>
+// CHECK-NEXT: <key>line</key><integer>1072</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16356,12 +17436,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1041</integer>
+// CHECK-NEXT: <key>line</key><integer>1061</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1041</integer>
+// CHECK-NEXT: <key>line</key><integer>1061</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16369,12 +17449,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1052</integer>
+// CHECK-NEXT: <key>line</key><integer>1072</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1052</integer>
+// CHECK-NEXT: <key>line</key><integer>1072</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16390,12 +17470,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1052</integer>
+// CHECK-NEXT: <key>line</key><integer>1072</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1052</integer>
+// CHECK-NEXT: <key>line</key><integer>1072</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16403,12 +17483,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1053</integer>
+// CHECK-NEXT: <key>line</key><integer>1073</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1053</integer>
+// CHECK-NEXT: <key>line</key><integer>1073</integer>
// CHECK-NEXT: <key>col</key><integer>38</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16420,7 +17500,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1053</integer>
+// CHECK-NEXT: <key>line</key><integer>1073</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16428,12 +17508,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1053</integer>
+// CHECK-NEXT: <key>line</key><integer>1073</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1053</integer>
+// CHECK-NEXT: <key>line</key><integer>1073</integer>
// CHECK-NEXT: <key>col</key><integer>107</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16453,12 +17533,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1053</integer>
+// CHECK-NEXT: <key>line</key><integer>1073</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1053</integer>
+// CHECK-NEXT: <key>line</key><integer>1073</integer>
// CHECK-NEXT: <key>col</key><integer>38</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16466,12 +17546,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1057</integer>
+// CHECK-NEXT: <key>line</key><integer>1077</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1057</integer>
+// CHECK-NEXT: <key>line</key><integer>1077</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16483,7 +17563,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1057</integer>
+// CHECK-NEXT: <key>line</key><integer>1077</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16499,10 +17579,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>rdar_7184450_pos</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>17</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>17</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1057</integer>
+// CHECK-NEXT: <key>line</key><integer>1077</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16518,12 +17598,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1091</integer>
+// CHECK-NEXT: <key>line</key><integer>1111</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1091</integer>
+// CHECK-NEXT: <key>line</key><integer>1111</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16531,12 +17611,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1091</integer>
+// CHECK-NEXT: <key>line</key><integer>1111</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1091</integer>
+// CHECK-NEXT: <key>line</key><integer>1111</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16548,7 +17628,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1091</integer>
+// CHECK-NEXT: <key>line</key><integer>1111</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16556,12 +17636,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1091</integer>
+// CHECK-NEXT: <key>line</key><integer>1111</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1091</integer>
+// CHECK-NEXT: <key>line</key><integer>1111</integer>
// CHECK-NEXT: <key>col</key><integer>53</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16581,12 +17661,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1091</integer>
+// CHECK-NEXT: <key>line</key><integer>1111</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1091</integer>
+// CHECK-NEXT: <key>line</key><integer>1111</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16594,12 +17674,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1092</integer>
+// CHECK-NEXT: <key>line</key><integer>1112</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1092</integer>
+// CHECK-NEXT: <key>line</key><integer>1112</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16611,7 +17691,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1092</integer>
+// CHECK-NEXT: <key>line</key><integer>1112</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16627,10 +17707,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>rdar_7299394_positive</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1092</integer>
+// CHECK-NEXT: <key>line</key><integer>1112</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16646,12 +17726,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1224</integer>
+// CHECK-NEXT: <key>line</key><integer>1244</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1224</integer>
+// CHECK-NEXT: <key>line</key><integer>1244</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16659,12 +17739,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1226</integer>
+// CHECK-NEXT: <key>line</key><integer>1246</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1226</integer>
+// CHECK-NEXT: <key>line</key><integer>1246</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16676,7 +17756,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1226</integer>
+// CHECK-NEXT: <key>line</key><integer>1246</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16684,12 +17764,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1226</integer>
+// CHECK-NEXT: <key>line</key><integer>1246</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1227</integer>
+// CHECK-NEXT: <key>line</key><integer>1247</integer>
// CHECK-NEXT: <key>col</key><integer>60</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16709,12 +17789,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1226</integer>
+// CHECK-NEXT: <key>line</key><integer>1246</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1226</integer>
+// CHECK-NEXT: <key>line</key><integer>1246</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16722,12 +17802,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1228</integer>
+// CHECK-NEXT: <key>line</key><integer>1248</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1228</integer>
+// CHECK-NEXT: <key>line</key><integer>1248</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16739,7 +17819,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1228</integer>
+// CHECK-NEXT: <key>line</key><integer>1248</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16755,10 +17835,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>rdar_7358899</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>9</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>9</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1228</integer>
+// CHECK-NEXT: <key>line</key><integer>1248</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16774,12 +17854,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1244</integer>
+// CHECK-NEXT: <key>line</key><integer>1264</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1244</integer>
+// CHECK-NEXT: <key>line</key><integer>1264</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16787,12 +17867,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1244</integer>
+// CHECK-NEXT: <key>line</key><integer>1264</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1244</integer>
+// CHECK-NEXT: <key>line</key><integer>1264</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16804,7 +17884,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1244</integer>
+// CHECK-NEXT: <key>line</key><integer>1264</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16812,12 +17892,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1244</integer>
+// CHECK-NEXT: <key>line</key><integer>1264</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1244</integer>
+// CHECK-NEXT: <key>line</key><integer>1264</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16837,12 +17917,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1244</integer>
+// CHECK-NEXT: <key>line</key><integer>1264</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1244</integer>
+// CHECK-NEXT: <key>line</key><integer>1264</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16850,12 +17930,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1245</integer>
+// CHECK-NEXT: <key>line</key><integer>1265</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1245</integer>
+// CHECK-NEXT: <key>line</key><integer>1265</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16867,7 +17947,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1245</integer>
+// CHECK-NEXT: <key>line</key><integer>1265</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16883,10 +17963,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>rdar7265711_a</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1245</integer>
+// CHECK-NEXT: <key>line</key><integer>1265</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16902,12 +17982,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1264</integer>
+// CHECK-NEXT: <key>line</key><integer>1284</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1264</integer>
+// CHECK-NEXT: <key>line</key><integer>1284</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16915,12 +17995,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1265</integer>
+// CHECK-NEXT: <key>line</key><integer>1285</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1265</integer>
+// CHECK-NEXT: <key>line</key><integer>1285</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16936,12 +18016,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1265</integer>
+// CHECK-NEXT: <key>line</key><integer>1285</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1265</integer>
+// CHECK-NEXT: <key>line</key><integer>1285</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16949,12 +18029,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1265</integer>
+// CHECK-NEXT: <key>line</key><integer>1285</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1265</integer>
+// CHECK-NEXT: <key>line</key><integer>1285</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16966,7 +18046,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1265</integer>
+// CHECK-NEXT: <key>line</key><integer>1285</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16974,12 +18054,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1265</integer>
+// CHECK-NEXT: <key>line</key><integer>1285</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1265</integer>
+// CHECK-NEXT: <key>line</key><integer>1285</integer>
// CHECK-NEXT: <key>col</key><integer>53</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -16999,12 +18079,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1265</integer>
+// CHECK-NEXT: <key>line</key><integer>1285</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1265</integer>
+// CHECK-NEXT: <key>line</key><integer>1285</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17012,12 +18092,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1266</integer>
+// CHECK-NEXT: <key>line</key><integer>1286</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1266</integer>
+// CHECK-NEXT: <key>line</key><integer>1286</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17029,7 +18109,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1266</integer>
+// CHECK-NEXT: <key>line</key><integer>1286</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17045,10 +18125,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>rdar7306898</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1266</integer>
+// CHECK-NEXT: <key>line</key><integer>1286</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17060,7 +18140,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1275</integer>
+// CHECK-NEXT: <key>line</key><integer>1295</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17068,12 +18148,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1275</integer>
+// CHECK-NEXT: <key>line</key><integer>1295</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1275</integer>
+// CHECK-NEXT: <key>line</key><integer>1295</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17091,10 +18171,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>message incorrectly sent to class instead of class instance</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>rdar7252064</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1275</integer>
+// CHECK-NEXT: <key>line</key><integer>1295</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17110,12 +18190,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1275</integer>
+// CHECK-NEXT: <key>line</key><integer>1295</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1275</integer>
+// CHECK-NEXT: <key>line</key><integer>1295</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17123,12 +18203,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1276</integer>
+// CHECK-NEXT: <key>line</key><integer>1296</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1276</integer>
+// CHECK-NEXT: <key>line</key><integer>1296</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17140,7 +18220,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1276</integer>
+// CHECK-NEXT: <key>line</key><integer>1296</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17148,12 +18228,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1276</integer>
+// CHECK-NEXT: <key>line</key><integer>1296</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1276</integer>
+// CHECK-NEXT: <key>line</key><integer>1296</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17171,10 +18251,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>message incorrectly sent to class instead of class instance</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>rdar7252064</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1276</integer>
+// CHECK-NEXT: <key>line</key><integer>1296</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17190,12 +18270,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1275</integer>
+// CHECK-NEXT: <key>line</key><integer>1295</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1275</integer>
+// CHECK-NEXT: <key>line</key><integer>1295</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17203,12 +18283,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1277</integer>
+// CHECK-NEXT: <key>line</key><integer>1297</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1277</integer>
+// CHECK-NEXT: <key>line</key><integer>1297</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17220,7 +18300,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1277</integer>
+// CHECK-NEXT: <key>line</key><integer>1297</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17228,12 +18308,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1277</integer>
+// CHECK-NEXT: <key>line</key><integer>1297</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1277</integer>
+// CHECK-NEXT: <key>line</key><integer>1297</integer>
// CHECK-NEXT: <key>col</key><integer>27</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17251,10 +18331,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>message incorrectly sent to class instead of class instance</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>rdar7252064</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1277</integer>
+// CHECK-NEXT: <key>line</key><integer>1297</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17270,12 +18350,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1275</integer>
+// CHECK-NEXT: <key>line</key><integer>1295</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1275</integer>
+// CHECK-NEXT: <key>line</key><integer>1295</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17283,12 +18363,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1278</integer>
+// CHECK-NEXT: <key>line</key><integer>1298</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1278</integer>
+// CHECK-NEXT: <key>line</key><integer>1298</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17300,7 +18380,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1278</integer>
+// CHECK-NEXT: <key>line</key><integer>1298</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17308,12 +18388,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1278</integer>
+// CHECK-NEXT: <key>line</key><integer>1298</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1278</integer>
+// CHECK-NEXT: <key>line</key><integer>1298</integer>
// CHECK-NEXT: <key>col</key><integer>27</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17331,10 +18411,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>message incorrectly sent to class instead of class instance</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>rdar7252064</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>4</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>4</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1278</integer>
+// CHECK-NEXT: <key>line</key><integer>1298</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17350,12 +18430,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1304</integer>
+// CHECK-NEXT: <key>line</key><integer>1325</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1304</integer>
+// CHECK-NEXT: <key>line</key><integer>1325</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17363,12 +18443,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1304</integer>
+// CHECK-NEXT: <key>line</key><integer>1325</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1304</integer>
+// CHECK-NEXT: <key>line</key><integer>1325</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17380,7 +18460,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1304</integer>
+// CHECK-NEXT: <key>line</key><integer>1325</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17388,12 +18468,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1304</integer>
+// CHECK-NEXT: <key>line</key><integer>1325</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1304</integer>
+// CHECK-NEXT: <key>line</key><integer>1325</integer>
// CHECK-NEXT: <key>col</key><integer>42</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17413,12 +18493,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1304</integer>
+// CHECK-NEXT: <key>line</key><integer>1325</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1304</integer>
+// CHECK-NEXT: <key>line</key><integer>1325</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17426,12 +18506,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1305</integer>
+// CHECK-NEXT: <key>line</key><integer>1326</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1305</integer>
+// CHECK-NEXT: <key>line</key><integer>1326</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17443,7 +18523,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1305</integer>
+// CHECK-NEXT: <key>line</key><integer>1326</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17459,10 +18539,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_attr_1</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1305</integer>
+// CHECK-NEXT: <key>line</key><integer>1326</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17478,12 +18558,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1308</integer>
+// CHECK-NEXT: <key>line</key><integer>1329</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1308</integer>
+// CHECK-NEXT: <key>line</key><integer>1329</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17491,12 +18571,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1308</integer>
+// CHECK-NEXT: <key>line</key><integer>1329</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1308</integer>
+// CHECK-NEXT: <key>line</key><integer>1329</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17508,7 +18588,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1308</integer>
+// CHECK-NEXT: <key>line</key><integer>1329</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17516,12 +18596,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1308</integer>
+// CHECK-NEXT: <key>line</key><integer>1329</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1308</integer>
+// CHECK-NEXT: <key>line</key><integer>1329</integer>
// CHECK-NEXT: <key>col</key><integer>44</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17541,12 +18621,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1308</integer>
+// CHECK-NEXT: <key>line</key><integer>1329</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1308</integer>
+// CHECK-NEXT: <key>line</key><integer>1329</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17554,12 +18634,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1309</integer>
+// CHECK-NEXT: <key>line</key><integer>1330</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1309</integer>
+// CHECK-NEXT: <key>line</key><integer>1330</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17571,7 +18651,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1309</integer>
+// CHECK-NEXT: <key>line</key><integer>1330</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17587,10 +18667,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_attr_1b</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1309</integer>
+// CHECK-NEXT: <key>line</key><integer>1330</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17606,12 +18686,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1312</integer>
+// CHECK-NEXT: <key>line</key><integer>1333</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1312</integer>
+// CHECK-NEXT: <key>line</key><integer>1333</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17619,12 +18699,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1313</integer>
+// CHECK-NEXT: <key>line</key><integer>1334</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1313</integer>
+// CHECK-NEXT: <key>line</key><integer>1334</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17640,12 +18720,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1313</integer>
+// CHECK-NEXT: <key>line</key><integer>1334</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1313</integer>
+// CHECK-NEXT: <key>line</key><integer>1334</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17653,12 +18733,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1313</integer>
+// CHECK-NEXT: <key>line</key><integer>1334</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1313</integer>
+// CHECK-NEXT: <key>line</key><integer>1334</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17670,7 +18750,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1313</integer>
+// CHECK-NEXT: <key>line</key><integer>1334</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17678,12 +18758,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1313</integer>
+// CHECK-NEXT: <key>line</key><integer>1334</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1313</integer>
+// CHECK-NEXT: <key>line</key><integer>1334</integer>
// CHECK-NEXT: <key>col</key><integer>38</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17703,12 +18783,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1313</integer>
+// CHECK-NEXT: <key>line</key><integer>1334</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1313</integer>
+// CHECK-NEXT: <key>line</key><integer>1334</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17716,13 +18796,47 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1314</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>line</key><integer>1335</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1314</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>line</key><integer>1335</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1335</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1335</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1335</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1335</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
@@ -17733,10 +18847,25 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1314</integer>
-// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>line</key><integer>1335</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1335</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1335</integer>
+// CHECK-NEXT: <key>col</key><integer>37</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Object leaked: object allocated and stored into &apos;str2&apos; is not referenced later in this execution path and has a retain count of +1</string>
@@ -17749,10 +18878,247 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_attr1c</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1335</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1333</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1333</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1336</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1336</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1336</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1336</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1336</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1336</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1336</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1336</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1336</integer>
+// CHECK-NEXT: <key>col</key><integer>38</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Method returns an Objective-C object with a +0 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Method returns an Objective-C object with a +0 retain count</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1336</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1336</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1336</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1336</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1336</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1336</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1336</integer>
+// CHECK-NEXT: <key>col</key><integer>46</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1336</integer>
+// CHECK-NEXT: <key>col</key><integer>21</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1336</integer>
+// CHECK-NEXT: <key>col</key><integer>38</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Reference count incremented. The object now has a +1 retain count</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Reference count incremented. The object now has a +1 retain count</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1336</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1336</integer>
+// CHECK-NEXT: <key>col</key><integer>20</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1337</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1337</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>1337</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Object leaked: object allocated and stored into &apos;str4&apos; is not referenced later in this execution path and has a retain count of +1</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Object leaked: object allocated and stored into &apos;str4&apos; is not referenced later in this execution path and has a retain count of +1</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Potential leak of an object stored into &apos;str4&apos;</string>
+// CHECK-NEXT: <key>category</key><string>Memory (Core Foundation/Objective-C)</string>
+// CHECK-NEXT: <key>type</key><string>Leak</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
+// CHECK-NEXT: <key>issue_context</key><string>test_attr1c</string>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1314</integer>
+// CHECK-NEXT: <key>line</key><integer>1337</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17768,12 +19134,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1317</integer>
+// CHECK-NEXT: <key>line</key><integer>1340</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1317</integer>
+// CHECK-NEXT: <key>line</key><integer>1340</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17781,12 +19147,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1317</integer>
+// CHECK-NEXT: <key>line</key><integer>1340</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1317</integer>
+// CHECK-NEXT: <key>line</key><integer>1340</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17798,7 +19164,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1317</integer>
+// CHECK-NEXT: <key>line</key><integer>1340</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17806,12 +19172,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1317</integer>
+// CHECK-NEXT: <key>line</key><integer>1340</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1317</integer>
+// CHECK-NEXT: <key>line</key><integer>1340</integer>
// CHECK-NEXT: <key>col</key><integer>50</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17831,12 +19197,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1317</integer>
+// CHECK-NEXT: <key>line</key><integer>1340</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1317</integer>
+// CHECK-NEXT: <key>line</key><integer>1340</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17844,12 +19210,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1318</integer>
+// CHECK-NEXT: <key>line</key><integer>1341</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1318</integer>
+// CHECK-NEXT: <key>line</key><integer>1341</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17861,7 +19227,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1318</integer>
+// CHECK-NEXT: <key>line</key><integer>1341</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17877,10 +19243,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testattr2_a</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1318</integer>
+// CHECK-NEXT: <key>line</key><integer>1341</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17896,12 +19262,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1321</integer>
+// CHECK-NEXT: <key>line</key><integer>1344</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1321</integer>
+// CHECK-NEXT: <key>line</key><integer>1344</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17909,12 +19275,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1321</integer>
+// CHECK-NEXT: <key>line</key><integer>1344</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1321</integer>
+// CHECK-NEXT: <key>line</key><integer>1344</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17926,7 +19292,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1321</integer>
+// CHECK-NEXT: <key>line</key><integer>1344</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17934,12 +19300,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1321</integer>
+// CHECK-NEXT: <key>line</key><integer>1344</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1321</integer>
+// CHECK-NEXT: <key>line</key><integer>1344</integer>
// CHECK-NEXT: <key>col</key><integer>63</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17959,12 +19325,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1321</integer>
+// CHECK-NEXT: <key>line</key><integer>1344</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1321</integer>
+// CHECK-NEXT: <key>line</key><integer>1344</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17972,12 +19338,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1322</integer>
+// CHECK-NEXT: <key>line</key><integer>1345</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1322</integer>
+// CHECK-NEXT: <key>line</key><integer>1345</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -17989,7 +19355,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1322</integer>
+// CHECK-NEXT: <key>line</key><integer>1345</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18005,10 +19371,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testattr2_b</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1322</integer>
+// CHECK-NEXT: <key>line</key><integer>1345</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18024,12 +19390,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1325</integer>
+// CHECK-NEXT: <key>line</key><integer>1348</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1325</integer>
+// CHECK-NEXT: <key>line</key><integer>1348</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18037,12 +19403,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1325</integer>
+// CHECK-NEXT: <key>line</key><integer>1348</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1325</integer>
+// CHECK-NEXT: <key>line</key><integer>1348</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18054,7 +19420,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1325</integer>
+// CHECK-NEXT: <key>line</key><integer>1348</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18062,12 +19428,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1325</integer>
+// CHECK-NEXT: <key>line</key><integer>1348</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1325</integer>
+// CHECK-NEXT: <key>line</key><integer>1348</integer>
// CHECK-NEXT: <key>col</key><integer>63</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18087,12 +19453,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1325</integer>
+// CHECK-NEXT: <key>line</key><integer>1348</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1325</integer>
+// CHECK-NEXT: <key>line</key><integer>1348</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18100,12 +19466,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1327</integer>
+// CHECK-NEXT: <key>line</key><integer>1350</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1327</integer>
+// CHECK-NEXT: <key>line</key><integer>1350</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18117,7 +19483,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1327</integer>
+// CHECK-NEXT: <key>line</key><integer>1350</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18133,10 +19499,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testattr2_b_11358224_self_assign_looses_the_leak</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1327</integer>
+// CHECK-NEXT: <key>line</key><integer>1350</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18152,12 +19518,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1357</integer>
+// CHECK-NEXT: <key>line</key><integer>1380</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1357</integer>
+// CHECK-NEXT: <key>line</key><integer>1380</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18165,12 +19531,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1357</integer>
+// CHECK-NEXT: <key>line</key><integer>1380</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1357</integer>
+// CHECK-NEXT: <key>line</key><integer>1380</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18182,7 +19548,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1357</integer>
+// CHECK-NEXT: <key>line</key><integer>1380</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18190,12 +19556,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1357</integer>
+// CHECK-NEXT: <key>line</key><integer>1380</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1357</integer>
+// CHECK-NEXT: <key>line</key><integer>1380</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18215,12 +19581,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1357</integer>
+// CHECK-NEXT: <key>line</key><integer>1380</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1357</integer>
+// CHECK-NEXT: <key>line</key><integer>1380</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18228,12 +19594,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1357</integer>
+// CHECK-NEXT: <key>line</key><integer>1380</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1357</integer>
+// CHECK-NEXT: <key>line</key><integer>1380</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18245,7 +19611,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1357</integer>
+// CHECK-NEXT: <key>line</key><integer>1380</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18253,24 +19619,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1357</integer>
+// CHECK-NEXT: <key>line</key><integer>1380</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1357</integer>
+// CHECK-NEXT: <key>line</key><integer>1380</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1357</integer>
+// CHECK-NEXT: <key>line</key><integer>1380</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1357</integer>
+// CHECK-NEXT: <key>line</key><integer>1380</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18286,7 +19652,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1357</integer>
+// CHECK-NEXT: <key>line</key><integer>1380</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18294,12 +19660,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1357</integer>
+// CHECK-NEXT: <key>line</key><integer>1380</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1357</integer>
+// CHECK-NEXT: <key>line</key><integer>1380</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18317,10 +19683,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak of returned object</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
// CHECK-NEXT: <key>issue_context</key><string>newString</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1357</integer>
+// CHECK-NEXT: <key>line</key><integer>1380</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18336,12 +19702,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18349,12 +19715,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18366,7 +19732,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18374,12 +19740,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>53</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18395,7 +19761,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1381</integer>
+// CHECK-NEXT: <key>line</key><integer>1404</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18413,12 +19779,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1381</integer>
+// CHECK-NEXT: <key>line</key><integer>1404</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1381</integer>
+// CHECK-NEXT: <key>line</key><integer>1404</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18426,12 +19792,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1382</integer>
+// CHECK-NEXT: <key>line</key><integer>1405</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1382</integer>
+// CHECK-NEXT: <key>line</key><integer>1405</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18447,12 +19813,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1382</integer>
+// CHECK-NEXT: <key>line</key><integer>1405</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1382</integer>
+// CHECK-NEXT: <key>line</key><integer>1405</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18460,12 +19826,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1382</integer>
+// CHECK-NEXT: <key>line</key><integer>1405</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1382</integer>
+// CHECK-NEXT: <key>line</key><integer>1405</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18477,7 +19843,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1382</integer>
+// CHECK-NEXT: <key>line</key><integer>1405</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18485,12 +19851,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1382</integer>
+// CHECK-NEXT: <key>line</key><integer>1405</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1382</integer>
+// CHECK-NEXT: <key>line</key><integer>1405</integer>
// CHECK-NEXT: <key>col</key><integer>32</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18506,7 +19872,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1371</integer>
+// CHECK-NEXT: <key>line</key><integer>1394</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18524,12 +19890,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1373</integer>
+// CHECK-NEXT: <key>line</key><integer>1396</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1373</integer>
+// CHECK-NEXT: <key>line</key><integer>1396</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18537,12 +19903,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1373</integer>
+// CHECK-NEXT: <key>line</key><integer>1396</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1373</integer>
+// CHECK-NEXT: <key>line</key><integer>1396</integer>
// CHECK-NEXT: <key>col</key><integer>21</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18554,7 +19920,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1373</integer>
+// CHECK-NEXT: <key>line</key><integer>1396</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18562,12 +19928,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1373</integer>
+// CHECK-NEXT: <key>line</key><integer>1396</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1373</integer>
+// CHECK-NEXT: <key>line</key><integer>1396</integer>
// CHECK-NEXT: <key>col</key><integer>52</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18583,7 +19949,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1382</integer>
+// CHECK-NEXT: <key>line</key><integer>1405</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18591,12 +19957,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1382</integer>
+// CHECK-NEXT: <key>line</key><integer>1405</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1382</integer>
+// CHECK-NEXT: <key>line</key><integer>1405</integer>
// CHECK-NEXT: <key>col</key><integer>32</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18612,7 +19978,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18620,12 +19986,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>53</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18645,12 +20011,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18658,12 +20024,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18679,12 +20045,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18692,12 +20058,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>21</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>21</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18709,7 +20075,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>21</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18717,24 +20083,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>21</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>66</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>53</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18754,12 +20120,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>21</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>21</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18767,12 +20133,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18784,7 +20150,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18792,53 +20158,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
-// CHECK-NEXT: <key>col</key><integer>66</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
-// CHECK-NEXT: <key>col</key><integer>66</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Object returned to caller with a +0 retain count</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Object returned to caller with a +0 retain count</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>66</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18856,10 +20181,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Method should return an owned object</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
// CHECK-NEXT: <key>issue_context</key><string>newCFRetainedAsCFNoAttr</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1390</integer>
+// CHECK-NEXT: <key>line</key><integer>1413</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18875,12 +20200,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// CHECK-NEXT: <key>line</key><integer>1417</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// CHECK-NEXT: <key>line</key><integer>1417</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18888,12 +20213,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// CHECK-NEXT: <key>line</key><integer>1417</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// CHECK-NEXT: <key>line</key><integer>1417</integer>
// CHECK-NEXT: <key>col</key><integer>40</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18905,7 +20230,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// CHECK-NEXT: <key>line</key><integer>1417</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18913,12 +20238,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// CHECK-NEXT: <key>line</key><integer>1417</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// CHECK-NEXT: <key>line</key><integer>1417</integer>
// CHECK-NEXT: <key>col</key><integer>42</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18934,7 +20259,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1371</integer>
+// CHECK-NEXT: <key>line</key><integer>1394</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18952,12 +20277,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1373</integer>
+// CHECK-NEXT: <key>line</key><integer>1396</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1373</integer>
+// CHECK-NEXT: <key>line</key><integer>1396</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18965,12 +20290,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1373</integer>
+// CHECK-NEXT: <key>line</key><integer>1396</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1373</integer>
+// CHECK-NEXT: <key>line</key><integer>1396</integer>
// CHECK-NEXT: <key>col</key><integer>21</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18982,7 +20307,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1373</integer>
+// CHECK-NEXT: <key>line</key><integer>1396</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -18990,12 +20315,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1373</integer>
+// CHECK-NEXT: <key>line</key><integer>1396</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1373</integer>
+// CHECK-NEXT: <key>line</key><integer>1396</integer>
// CHECK-NEXT: <key>col</key><integer>52</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19011,7 +20336,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// CHECK-NEXT: <key>line</key><integer>1417</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19019,12 +20344,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// CHECK-NEXT: <key>line</key><integer>1417</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// CHECK-NEXT: <key>line</key><integer>1417</integer>
// CHECK-NEXT: <key>col</key><integer>42</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19044,12 +20369,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// CHECK-NEXT: <key>line</key><integer>1417</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// CHECK-NEXT: <key>line</key><integer>1417</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19057,12 +20382,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// CHECK-NEXT: <key>line</key><integer>1417</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// CHECK-NEXT: <key>line</key><integer>1417</integer>
// CHECK-NEXT: <key>col</key><integer>40</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19078,12 +20403,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// CHECK-NEXT: <key>line</key><integer>1417</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// CHECK-NEXT: <key>line</key><integer>1417</integer>
// CHECK-NEXT: <key>col</key><integer>40</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19091,12 +20416,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// CHECK-NEXT: <key>line</key><integer>1417</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// CHECK-NEXT: <key>line</key><integer>1417</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19108,7 +20433,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// CHECK-NEXT: <key>line</key><integer>1417</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19116,24 +20441,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// CHECK-NEXT: <key>line</key><integer>1417</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// CHECK-NEXT: <key>line</key><integer>1417</integer>
// CHECK-NEXT: <key>col</key><integer>42</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// CHECK-NEXT: <key>line</key><integer>1417</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// CHECK-NEXT: <key>line</key><integer>1417</integer>
// CHECK-NEXT: <key>col</key><integer>42</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19149,7 +20474,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// CHECK-NEXT: <key>line</key><integer>1417</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19157,12 +20482,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// CHECK-NEXT: <key>line</key><integer>1417</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// CHECK-NEXT: <key>line</key><integer>1417</integer>
// CHECK-NEXT: <key>col</key><integer>42</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19180,10 +20505,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak of returned object</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
// CHECK-NEXT: <key>issue_context</key><string>alsoReturnsRetained</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1394</integer>
+// CHECK-NEXT: <key>line</key><integer>1417</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19199,12 +20524,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1398</integer>
+// CHECK-NEXT: <key>line</key><integer>1421</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1398</integer>
+// CHECK-NEXT: <key>line</key><integer>1421</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19212,12 +20537,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1398</integer>
+// CHECK-NEXT: <key>line</key><integer>1421</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1398</integer>
+// CHECK-NEXT: <key>line</key><integer>1421</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19229,7 +20554,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1398</integer>
+// CHECK-NEXT: <key>line</key><integer>1421</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19237,12 +20562,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1398</integer>
+// CHECK-NEXT: <key>line</key><integer>1421</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1398</integer>
+// CHECK-NEXT: <key>line</key><integer>1421</integer>
// CHECK-NEXT: <key>col</key><integer>32</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19258,7 +20583,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1371</integer>
+// CHECK-NEXT: <key>line</key><integer>1394</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19276,12 +20601,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1373</integer>
+// CHECK-NEXT: <key>line</key><integer>1396</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1373</integer>
+// CHECK-NEXT: <key>line</key><integer>1396</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19289,12 +20614,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1373</integer>
+// CHECK-NEXT: <key>line</key><integer>1396</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1373</integer>
+// CHECK-NEXT: <key>line</key><integer>1396</integer>
// CHECK-NEXT: <key>col</key><integer>21</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19306,7 +20631,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1373</integer>
+// CHECK-NEXT: <key>line</key><integer>1396</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19314,12 +20639,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1373</integer>
+// CHECK-NEXT: <key>line</key><integer>1396</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1373</integer>
+// CHECK-NEXT: <key>line</key><integer>1396</integer>
// CHECK-NEXT: <key>col</key><integer>52</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19335,7 +20660,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1398</integer>
+// CHECK-NEXT: <key>line</key><integer>1421</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19343,12 +20668,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1398</integer>
+// CHECK-NEXT: <key>line</key><integer>1421</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1398</integer>
+// CHECK-NEXT: <key>line</key><integer>1421</integer>
// CHECK-NEXT: <key>col</key><integer>32</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19368,12 +20693,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1398</integer>
+// CHECK-NEXT: <key>line</key><integer>1421</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1398</integer>
+// CHECK-NEXT: <key>line</key><integer>1421</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19381,12 +20706,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1398</integer>
+// CHECK-NEXT: <key>line</key><integer>1421</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1398</integer>
+// CHECK-NEXT: <key>line</key><integer>1421</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19402,12 +20727,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1398</integer>
+// CHECK-NEXT: <key>line</key><integer>1421</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1398</integer>
+// CHECK-NEXT: <key>line</key><integer>1421</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19415,12 +20740,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1398</integer>
+// CHECK-NEXT: <key>line</key><integer>1421</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1398</integer>
+// CHECK-NEXT: <key>line</key><integer>1421</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19432,7 +20757,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1398</integer>
+// CHECK-NEXT: <key>line</key><integer>1421</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19440,24 +20765,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1398</integer>
+// CHECK-NEXT: <key>line</key><integer>1421</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1398</integer>
+// CHECK-NEXT: <key>line</key><integer>1421</integer>
// CHECK-NEXT: <key>col</key><integer>32</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1398</integer>
+// CHECK-NEXT: <key>line</key><integer>1421</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1398</integer>
+// CHECK-NEXT: <key>line</key><integer>1421</integer>
// CHECK-NEXT: <key>col</key><integer>32</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19473,7 +20798,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1398</integer>
+// CHECK-NEXT: <key>line</key><integer>1421</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19481,12 +20806,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1398</integer>
+// CHECK-NEXT: <key>line</key><integer>1421</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1398</integer>
+// CHECK-NEXT: <key>line</key><integer>1421</integer>
// CHECK-NEXT: <key>col</key><integer>32</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19504,10 +20829,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak of returned object</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
// CHECK-NEXT: <key>issue_context</key><string>alsoReturnsRetainedAsCF</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1398</integer>
+// CHECK-NEXT: <key>line</key><integer>1421</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19523,12 +20848,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1418</integer>
+// CHECK-NEXT: <key>line</key><integer>1441</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1418</integer>
+// CHECK-NEXT: <key>line</key><integer>1441</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19536,12 +20861,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1419</integer>
+// CHECK-NEXT: <key>line</key><integer>1442</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1419</integer>
+// CHECK-NEXT: <key>line</key><integer>1442</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19557,12 +20882,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1419</integer>
+// CHECK-NEXT: <key>line</key><integer>1442</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1419</integer>
+// CHECK-NEXT: <key>line</key><integer>1442</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19570,12 +20895,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1419</integer>
+// CHECK-NEXT: <key>line</key><integer>1442</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1419</integer>
+// CHECK-NEXT: <key>line</key><integer>1442</integer>
// CHECK-NEXT: <key>col</key><integer>36</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19587,7 +20912,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1419</integer>
+// CHECK-NEXT: <key>line</key><integer>1442</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19595,12 +20920,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1419</integer>
+// CHECK-NEXT: <key>line</key><integer>1442</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1419</integer>
+// CHECK-NEXT: <key>line</key><integer>1442</integer>
// CHECK-NEXT: <key>col</key><integer>82</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19620,12 +20945,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1419</integer>
+// CHECK-NEXT: <key>line</key><integer>1442</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1419</integer>
+// CHECK-NEXT: <key>line</key><integer>1442</integer>
// CHECK-NEXT: <key>col</key><integer>36</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19633,12 +20958,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1420</integer>
+// CHECK-NEXT: <key>line</key><integer>1443</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1420</integer>
+// CHECK-NEXT: <key>line</key><integer>1443</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19650,7 +20975,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1420</integer>
+// CHECK-NEXT: <key>line</key><integer>1443</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19666,10 +20991,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_panic_negative</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1420</integer>
+// CHECK-NEXT: <key>line</key><integer>1443</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19685,12 +21010,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1429</integer>
+// CHECK-NEXT: <key>line</key><integer>1452</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1429</integer>
+// CHECK-NEXT: <key>line</key><integer>1452</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19698,12 +21023,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1430</integer>
+// CHECK-NEXT: <key>line</key><integer>1453</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1430</integer>
+// CHECK-NEXT: <key>line</key><integer>1453</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19719,12 +21044,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1430</integer>
+// CHECK-NEXT: <key>line</key><integer>1453</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1430</integer>
+// CHECK-NEXT: <key>line</key><integer>1453</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19732,12 +21057,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1430</integer>
+// CHECK-NEXT: <key>line</key><integer>1453</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1430</integer>
+// CHECK-NEXT: <key>line</key><integer>1453</integer>
// CHECK-NEXT: <key>col</key><integer>36</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19749,7 +21074,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1430</integer>
+// CHECK-NEXT: <key>line</key><integer>1453</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19757,12 +21082,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1430</integer>
+// CHECK-NEXT: <key>line</key><integer>1453</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1430</integer>
+// CHECK-NEXT: <key>line</key><integer>1453</integer>
// CHECK-NEXT: <key>col</key><integer>82</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19782,12 +21107,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1430</integer>
+// CHECK-NEXT: <key>line</key><integer>1453</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1430</integer>
+// CHECK-NEXT: <key>line</key><integer>1453</integer>
// CHECK-NEXT: <key>col</key><integer>36</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19795,12 +21120,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1431</integer>
+// CHECK-NEXT: <key>line</key><integer>1454</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1431</integer>
+// CHECK-NEXT: <key>line</key><integer>1454</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19816,12 +21141,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1431</integer>
+// CHECK-NEXT: <key>line</key><integer>1454</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1431</integer>
+// CHECK-NEXT: <key>line</key><integer>1454</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19829,12 +21154,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1431</integer>
+// CHECK-NEXT: <key>line</key><integer>1454</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1431</integer>
+// CHECK-NEXT: <key>line</key><integer>1454</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19846,7 +21171,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1431</integer>
+// CHECK-NEXT: <key>line</key><integer>1454</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19854,12 +21179,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1431</integer>
+// CHECK-NEXT: <key>line</key><integer>1454</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1431</integer>
+// CHECK-NEXT: <key>line</key><integer>1454</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19879,12 +21204,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1431</integer>
+// CHECK-NEXT: <key>line</key><integer>1454</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1431</integer>
+// CHECK-NEXT: <key>line</key><integer>1454</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19892,12 +21217,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1433</integer>
+// CHECK-NEXT: <key>line</key><integer>1456</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1433</integer>
+// CHECK-NEXT: <key>line</key><integer>1456</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19909,7 +21234,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1433</integer>
+// CHECK-NEXT: <key>line</key><integer>1456</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19925,10 +21250,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_panic_neg_2</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1433</integer>
+// CHECK-NEXT: <key>line</key><integer>1456</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19944,12 +21269,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1453</integer>
+// CHECK-NEXT: <key>line</key><integer>1476</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1453</integer>
+// CHECK-NEXT: <key>line</key><integer>1476</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19957,12 +21282,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1453</integer>
+// CHECK-NEXT: <key>line</key><integer>1476</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1453</integer>
+// CHECK-NEXT: <key>line</key><integer>1476</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19974,7 +21299,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1453</integer>
+// CHECK-NEXT: <key>line</key><integer>1476</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -19982,12 +21307,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1453</integer>
+// CHECK-NEXT: <key>line</key><integer>1476</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1453</integer>
+// CHECK-NEXT: <key>line</key><integer>1476</integer>
// CHECK-NEXT: <key>col</key><integer>53</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20007,12 +21332,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1453</integer>
+// CHECK-NEXT: <key>line</key><integer>1476</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1453</integer>
+// CHECK-NEXT: <key>line</key><integer>1476</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20020,12 +21345,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1454</integer>
+// CHECK-NEXT: <key>line</key><integer>1477</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1454</integer>
+// CHECK-NEXT: <key>line</key><integer>1477</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20037,7 +21362,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1454</integer>
+// CHECK-NEXT: <key>line</key><integer>1477</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20045,12 +21370,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1454</integer>
+// CHECK-NEXT: <key>line</key><integer>1477</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1454</integer>
+// CHECK-NEXT: <key>line</key><integer>1477</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20068,10 +21393,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_blocks_1_pos</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1454</integer>
+// CHECK-NEXT: <key>line</key><integer>1477</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20087,12 +21412,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1474</integer>
+// CHECK-NEXT: <key>line</key><integer>1497</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1474</integer>
+// CHECK-NEXT: <key>line</key><integer>1497</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20100,12 +21425,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1474</integer>
+// CHECK-NEXT: <key>line</key><integer>1497</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1474</integer>
+// CHECK-NEXT: <key>line</key><integer>1497</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20117,7 +21442,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1474</integer>
+// CHECK-NEXT: <key>line</key><integer>1497</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20125,12 +21450,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1474</integer>
+// CHECK-NEXT: <key>line</key><integer>1497</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1474</integer>
+// CHECK-NEXT: <key>line</key><integer>1497</integer>
// CHECK-NEXT: <key>col</key><integer>53</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20150,12 +21475,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1474</integer>
+// CHECK-NEXT: <key>line</key><integer>1497</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1474</integer>
+// CHECK-NEXT: <key>line</key><integer>1497</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20163,12 +21488,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1475</integer>
+// CHECK-NEXT: <key>line</key><integer>1498</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1475</integer>
+// CHECK-NEXT: <key>line</key><integer>1498</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20180,7 +21505,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1475</integer>
+// CHECK-NEXT: <key>line</key><integer>1498</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20188,12 +21513,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1475</integer>
+// CHECK-NEXT: <key>line</key><integer>1498</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1475</integer>
+// CHECK-NEXT: <key>line</key><integer>1498</integer>
// CHECK-NEXT: <key>col</key><integer>39</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20209,7 +21534,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1475</integer>
+// CHECK-NEXT: <key>line</key><integer>1498</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20227,12 +21552,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1475</integer>
+// CHECK-NEXT: <key>line</key><integer>1498</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1475</integer>
+// CHECK-NEXT: <key>line</key><integer>1498</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20240,12 +21565,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1475</integer>
+// CHECK-NEXT: <key>line</key><integer>1498</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1475</integer>
+// CHECK-NEXT: <key>line</key><integer>1498</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20257,7 +21582,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1475</integer>
+// CHECK-NEXT: <key>line</key><integer>1498</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20265,24 +21590,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1475</integer>
+// CHECK-NEXT: <key>line</key><integer>1498</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1475</integer>
+// CHECK-NEXT: <key>line</key><integer>1498</integer>
// CHECK-NEXT: <key>col</key><integer>28</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1475</integer>
+// CHECK-NEXT: <key>line</key><integer>1498</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1475</integer>
+// CHECK-NEXT: <key>line</key><integer>1498</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20298,7 +21623,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1475</integer>
+// CHECK-NEXT: <key>line</key><integer>1498</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20306,12 +21631,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1475</integer>
+// CHECK-NEXT: <key>line</key><integer>1498</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1475</integer>
+// CHECK-NEXT: <key>line</key><integer>1498</integer>
// CHECK-NEXT: <key>col</key><integer>39</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20331,12 +21656,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1475</integer>
+// CHECK-NEXT: <key>line</key><integer>1498</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1475</integer>
+// CHECK-NEXT: <key>line</key><integer>1498</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20344,12 +21669,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1476</integer>
+// CHECK-NEXT: <key>line</key><integer>1499</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1476</integer>
+// CHECK-NEXT: <key>line</key><integer>1499</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20361,7 +21686,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1476</integer>
+// CHECK-NEXT: <key>line</key><integer>1499</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20377,10 +21702,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_blocks_1_indirect_retain_via_call</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1476</integer>
+// CHECK-NEXT: <key>line</key><integer>1499</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20396,12 +21721,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1526</integer>
+// CHECK-NEXT: <key>line</key><integer>1549</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1526</integer>
+// CHECK-NEXT: <key>line</key><integer>1549</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20409,12 +21734,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1529</integer>
+// CHECK-NEXT: <key>line</key><integer>1552</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1529</integer>
+// CHECK-NEXT: <key>line</key><integer>1552</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20430,12 +21755,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1529</integer>
+// CHECK-NEXT: <key>line</key><integer>1552</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1529</integer>
+// CHECK-NEXT: <key>line</key><integer>1552</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20443,12 +21768,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1530</integer>
+// CHECK-NEXT: <key>line</key><integer>1553</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1530</integer>
+// CHECK-NEXT: <key>line</key><integer>1553</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20464,12 +21789,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1530</integer>
+// CHECK-NEXT: <key>line</key><integer>1553</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1530</integer>
+// CHECK-NEXT: <key>line</key><integer>1553</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20477,12 +21802,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1532</integer>
+// CHECK-NEXT: <key>line</key><integer>1555</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1532</integer>
+// CHECK-NEXT: <key>line</key><integer>1555</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20498,12 +21823,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1532</integer>
+// CHECK-NEXT: <key>line</key><integer>1555</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1532</integer>
+// CHECK-NEXT: <key>line</key><integer>1555</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20511,12 +21836,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1532</integer>
+// CHECK-NEXT: <key>line</key><integer>1555</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1532</integer>
+// CHECK-NEXT: <key>line</key><integer>1555</integer>
// CHECK-NEXT: <key>col</key><integer>34</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20528,7 +21853,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1532</integer>
+// CHECK-NEXT: <key>line</key><integer>1555</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20536,12 +21861,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1532</integer>
+// CHECK-NEXT: <key>line</key><integer>1555</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1532</integer>
+// CHECK-NEXT: <key>line</key><integer>1555</integer>
// CHECK-NEXT: <key>col</key><integer>49</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20561,12 +21886,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1532</integer>
+// CHECK-NEXT: <key>line</key><integer>1555</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1532</integer>
+// CHECK-NEXT: <key>line</key><integer>1555</integer>
// CHECK-NEXT: <key>col</key><integer>34</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20574,12 +21899,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1534</integer>
+// CHECK-NEXT: <key>line</key><integer>1557</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1534</integer>
+// CHECK-NEXT: <key>line</key><integer>1557</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20595,12 +21920,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1534</integer>
+// CHECK-NEXT: <key>line</key><integer>1557</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1534</integer>
+// CHECK-NEXT: <key>line</key><integer>1557</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20608,12 +21933,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1534</integer>
+// CHECK-NEXT: <key>line</key><integer>1557</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1534</integer>
+// CHECK-NEXT: <key>line</key><integer>1557</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20625,7 +21950,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1534</integer>
+// CHECK-NEXT: <key>line</key><integer>1557</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20633,12 +21958,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1534</integer>
+// CHECK-NEXT: <key>line</key><integer>1557</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1534</integer>
+// CHECK-NEXT: <key>line</key><integer>1557</integer>
// CHECK-NEXT: <key>col</key><integer>30</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20658,12 +21983,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1534</integer>
+// CHECK-NEXT: <key>line</key><integer>1557</integer>
// CHECK-NEXT: <key>col</key><integer>13</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1534</integer>
+// CHECK-NEXT: <key>line</key><integer>1557</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20671,12 +21996,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1537</integer>
+// CHECK-NEXT: <key>line</key><integer>1560</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1537</integer>
+// CHECK-NEXT: <key>line</key><integer>1560</integer>
// CHECK-NEXT: <key>col</key><integer>21</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20688,7 +22013,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1537</integer>
+// CHECK-NEXT: <key>line</key><integer>1560</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20696,12 +22021,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1537</integer>
+// CHECK-NEXT: <key>line</key><integer>1560</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1537</integer>
+// CHECK-NEXT: <key>line</key><integer>1560</integer>
// CHECK-NEXT: <key>col</key><integer>91</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20719,10 +22044,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>rdar_8724287</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>12</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>12</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1537</integer>
+// CHECK-NEXT: <key>line</key><integer>1560</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20738,12 +22063,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1582</integer>
+// CHECK-NEXT: <key>line</key><integer>1605</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1582</integer>
+// CHECK-NEXT: <key>line</key><integer>1605</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20751,12 +22076,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1582</integer>
+// CHECK-NEXT: <key>line</key><integer>1605</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1582</integer>
+// CHECK-NEXT: <key>line</key><integer>1605</integer>
// CHECK-NEXT: <key>col</key><integer>29</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20768,7 +22093,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1582</integer>
+// CHECK-NEXT: <key>line</key><integer>1605</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20776,12 +22101,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1582</integer>
+// CHECK-NEXT: <key>line</key><integer>1605</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1582</integer>
+// CHECK-NEXT: <key>line</key><integer>1605</integer>
// CHECK-NEXT: <key>col</key><integer>60</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20801,12 +22126,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1582</integer>
+// CHECK-NEXT: <key>line</key><integer>1605</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1582</integer>
+// CHECK-NEXT: <key>line</key><integer>1605</integer>
// CHECK-NEXT: <key>col</key><integer>29</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20814,12 +22139,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1582</integer>
+// CHECK-NEXT: <key>line</key><integer>1605</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1582</integer>
+// CHECK-NEXT: <key>line</key><integer>1605</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20831,7 +22156,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1582</integer>
+// CHECK-NEXT: <key>line</key><integer>1605</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20839,24 +22164,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1582</integer>
+// CHECK-NEXT: <key>line</key><integer>1605</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1582</integer>
+// CHECK-NEXT: <key>line</key><integer>1605</integer>
// CHECK-NEXT: <key>col</key><integer>60</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1582</integer>
+// CHECK-NEXT: <key>line</key><integer>1605</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1582</integer>
+// CHECK-NEXT: <key>line</key><integer>1605</integer>
// CHECK-NEXT: <key>col</key><integer>60</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20872,7 +22197,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1582</integer>
+// CHECK-NEXT: <key>line</key><integer>1605</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20880,12 +22205,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1582</integer>
+// CHECK-NEXT: <key>line</key><integer>1605</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1582</integer>
+// CHECK-NEXT: <key>line</key><integer>1605</integer>
// CHECK-NEXT: <key>col</key><integer>60</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20903,10 +22228,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak of returned object</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>camelcase_createno</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1582</integer>
+// CHECK-NEXT: <key>line</key><integer>1605</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20922,12 +22247,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1590</integer>
+// CHECK-NEXT: <key>line</key><integer>1613</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1590</integer>
+// CHECK-NEXT: <key>line</key><integer>1613</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20935,12 +22260,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1590</integer>
+// CHECK-NEXT: <key>line</key><integer>1613</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1590</integer>
+// CHECK-NEXT: <key>line</key><integer>1613</integer>
// CHECK-NEXT: <key>col</key><integer>29</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20952,7 +22277,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1590</integer>
+// CHECK-NEXT: <key>line</key><integer>1613</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20960,12 +22285,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1590</integer>
+// CHECK-NEXT: <key>line</key><integer>1613</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1590</integer>
+// CHECK-NEXT: <key>line</key><integer>1613</integer>
// CHECK-NEXT: <key>col</key><integer>60</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20985,12 +22310,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1590</integer>
+// CHECK-NEXT: <key>line</key><integer>1613</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1590</integer>
+// CHECK-NEXT: <key>line</key><integer>1613</integer>
// CHECK-NEXT: <key>col</key><integer>29</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -20998,12 +22323,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1590</integer>
+// CHECK-NEXT: <key>line</key><integer>1613</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1590</integer>
+// CHECK-NEXT: <key>line</key><integer>1613</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21015,7 +22340,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1590</integer>
+// CHECK-NEXT: <key>line</key><integer>1613</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21023,24 +22348,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1590</integer>
+// CHECK-NEXT: <key>line</key><integer>1613</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1590</integer>
+// CHECK-NEXT: <key>line</key><integer>1613</integer>
// CHECK-NEXT: <key>col</key><integer>60</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1590</integer>
+// CHECK-NEXT: <key>line</key><integer>1613</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1590</integer>
+// CHECK-NEXT: <key>line</key><integer>1613</integer>
// CHECK-NEXT: <key>col</key><integer>60</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21056,7 +22381,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1590</integer>
+// CHECK-NEXT: <key>line</key><integer>1613</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21064,12 +22389,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1590</integer>
+// CHECK-NEXT: <key>line</key><integer>1613</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1590</integer>
+// CHECK-NEXT: <key>line</key><integer>1613</integer>
// CHECK-NEXT: <key>col</key><integer>60</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21087,10 +22412,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak of returned object</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>camelcase_copying</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1590</integer>
+// CHECK-NEXT: <key>line</key><integer>1613</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21106,12 +22431,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1611</integer>
+// CHECK-NEXT: <key>line</key><integer>1634</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1611</integer>
+// CHECK-NEXT: <key>line</key><integer>1634</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21119,12 +22444,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1611</integer>
+// CHECK-NEXT: <key>line</key><integer>1634</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1611</integer>
+// CHECK-NEXT: <key>line</key><integer>1634</integer>
// CHECK-NEXT: <key>col</key><integer>29</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21136,7 +22461,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1611</integer>
+// CHECK-NEXT: <key>line</key><integer>1634</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21144,12 +22469,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1611</integer>
+// CHECK-NEXT: <key>line</key><integer>1634</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1611</integer>
+// CHECK-NEXT: <key>line</key><integer>1634</integer>
// CHECK-NEXT: <key>col</key><integer>60</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21169,12 +22494,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1611</integer>
+// CHECK-NEXT: <key>line</key><integer>1634</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1611</integer>
+// CHECK-NEXT: <key>line</key><integer>1634</integer>
// CHECK-NEXT: <key>col</key><integer>29</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21182,12 +22507,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1611</integer>
+// CHECK-NEXT: <key>line</key><integer>1634</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1611</integer>
+// CHECK-NEXT: <key>line</key><integer>1634</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21199,7 +22524,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1611</integer>
+// CHECK-NEXT: <key>line</key><integer>1634</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21207,24 +22532,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1611</integer>
+// CHECK-NEXT: <key>line</key><integer>1634</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1611</integer>
+// CHECK-NEXT: <key>line</key><integer>1634</integer>
// CHECK-NEXT: <key>col</key><integer>60</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1611</integer>
+// CHECK-NEXT: <key>line</key><integer>1634</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1611</integer>
+// CHECK-NEXT: <key>line</key><integer>1634</integer>
// CHECK-NEXT: <key>col</key><integer>60</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21240,7 +22565,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1611</integer>
+// CHECK-NEXT: <key>line</key><integer>1634</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21248,12 +22573,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1611</integer>
+// CHECK-NEXT: <key>line</key><integer>1634</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1611</integer>
+// CHECK-NEXT: <key>line</key><integer>1634</integer>
// CHECK-NEXT: <key>col</key><integer>60</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21271,10 +22596,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak of returned object</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>camel_creat</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1611</integer>
+// CHECK-NEXT: <key>line</key><integer>1634</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21290,12 +22615,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1623</integer>
+// CHECK-NEXT: <key>line</key><integer>1646</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1623</integer>
+// CHECK-NEXT: <key>line</key><integer>1646</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21303,12 +22628,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1623</integer>
+// CHECK-NEXT: <key>line</key><integer>1646</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1623</integer>
+// CHECK-NEXT: <key>line</key><integer>1646</integer>
// CHECK-NEXT: <key>col</key><integer>29</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21320,7 +22645,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1623</integer>
+// CHECK-NEXT: <key>line</key><integer>1646</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21328,12 +22653,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1623</integer>
+// CHECK-NEXT: <key>line</key><integer>1646</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1623</integer>
+// CHECK-NEXT: <key>line</key><integer>1646</integer>
// CHECK-NEXT: <key>col</key><integer>60</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21353,12 +22678,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1623</integer>
+// CHECK-NEXT: <key>line</key><integer>1646</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1623</integer>
+// CHECK-NEXT: <key>line</key><integer>1646</integer>
// CHECK-NEXT: <key>col</key><integer>29</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21366,12 +22691,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1623</integer>
+// CHECK-NEXT: <key>line</key><integer>1646</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1623</integer>
+// CHECK-NEXT: <key>line</key><integer>1646</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21383,7 +22708,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1623</integer>
+// CHECK-NEXT: <key>line</key><integer>1646</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21391,24 +22716,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1623</integer>
+// CHECK-NEXT: <key>line</key><integer>1646</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1623</integer>
+// CHECK-NEXT: <key>line</key><integer>1646</integer>
// CHECK-NEXT: <key>col</key><integer>60</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1623</integer>
+// CHECK-NEXT: <key>line</key><integer>1646</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1623</integer>
+// CHECK-NEXT: <key>line</key><integer>1646</integer>
// CHECK-NEXT: <key>col</key><integer>60</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21424,7 +22749,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1623</integer>
+// CHECK-NEXT: <key>line</key><integer>1646</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21432,12 +22757,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1623</integer>
+// CHECK-NEXT: <key>line</key><integer>1646</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1623</integer>
+// CHECK-NEXT: <key>line</key><integer>1646</integer>
// CHECK-NEXT: <key>col</key><integer>60</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21455,10 +22780,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak of returned object</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>camel_copymachine</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1623</integer>
+// CHECK-NEXT: <key>line</key><integer>1646</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21474,12 +22799,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1643</integer>
+// CHECK-NEXT: <key>line</key><integer>1666</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1643</integer>
+// CHECK-NEXT: <key>line</key><integer>1666</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21487,12 +22812,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1644</integer>
+// CHECK-NEXT: <key>line</key><integer>1667</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1644</integer>
+// CHECK-NEXT: <key>line</key><integer>1667</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21508,12 +22833,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1644</integer>
+// CHECK-NEXT: <key>line</key><integer>1667</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1644</integer>
+// CHECK-NEXT: <key>line</key><integer>1667</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21521,12 +22846,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1644</integer>
+// CHECK-NEXT: <key>line</key><integer>1667</integer>
// CHECK-NEXT: <key>col</key><integer>24</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1644</integer>
+// CHECK-NEXT: <key>line</key><integer>1667</integer>
// CHECK-NEXT: <key>col</key><integer>35</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21538,7 +22863,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1644</integer>
+// CHECK-NEXT: <key>line</key><integer>1667</integer>
// CHECK-NEXT: <key>col</key><integer>24</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21546,12 +22871,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1644</integer>
+// CHECK-NEXT: <key>line</key><integer>1667</integer>
// CHECK-NEXT: <key>col</key><integer>24</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1644</integer>
+// CHECK-NEXT: <key>line</key><integer>1667</integer>
// CHECK-NEXT: <key>col</key><integer>41</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21571,12 +22896,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1644</integer>
+// CHECK-NEXT: <key>line</key><integer>1667</integer>
// CHECK-NEXT: <key>col</key><integer>24</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1644</integer>
+// CHECK-NEXT: <key>line</key><integer>1667</integer>
// CHECK-NEXT: <key>col</key><integer>35</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21584,12 +22909,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1645</integer>
+// CHECK-NEXT: <key>line</key><integer>1668</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1645</integer>
+// CHECK-NEXT: <key>line</key><integer>1668</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21601,7 +22926,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1645</integer>
+// CHECK-NEXT: <key>line</key><integer>1668</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21617,10 +22942,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>rdar6582778</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1645</integer>
+// CHECK-NEXT: <key>line</key><integer>1668</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21636,12 +22961,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1669</integer>
+// CHECK-NEXT: <key>line</key><integer>1692</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1669</integer>
+// CHECK-NEXT: <key>line</key><integer>1692</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21649,12 +22974,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1671</integer>
+// CHECK-NEXT: <key>line</key><integer>1694</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1671</integer>
+// CHECK-NEXT: <key>line</key><integer>1694</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21670,12 +22995,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1671</integer>
+// CHECK-NEXT: <key>line</key><integer>1694</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1671</integer>
+// CHECK-NEXT: <key>line</key><integer>1694</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21683,12 +23008,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1671</integer>
+// CHECK-NEXT: <key>line</key><integer>1694</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1671</integer>
+// CHECK-NEXT: <key>line</key><integer>1694</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21700,7 +23025,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1671</integer>
+// CHECK-NEXT: <key>line</key><integer>1694</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21708,12 +23033,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1671</integer>
+// CHECK-NEXT: <key>line</key><integer>1694</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1671</integer>
+// CHECK-NEXT: <key>line</key><integer>1694</integer>
// CHECK-NEXT: <key>col</key><integer>64</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21733,12 +23058,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1671</integer>
+// CHECK-NEXT: <key>line</key><integer>1694</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1671</integer>
+// CHECK-NEXT: <key>line</key><integer>1694</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21746,12 +23071,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1672</integer>
+// CHECK-NEXT: <key>line</key><integer>1695</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1672</integer>
+// CHECK-NEXT: <key>line</key><integer>1695</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21763,7 +23088,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1672</integer>
+// CHECK-NEXT: <key>line</key><integer>1695</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21771,24 +23096,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1672</integer>
+// CHECK-NEXT: <key>line</key><integer>1695</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1672</integer>
+// CHECK-NEXT: <key>line</key><integer>1695</integer>
// CHECK-NEXT: <key>col</key><integer>18</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1672</integer>
+// CHECK-NEXT: <key>line</key><integer>1695</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1672</integer>
+// CHECK-NEXT: <key>line</key><integer>1695</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21808,12 +23133,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1672</integer>
+// CHECK-NEXT: <key>line</key><integer>1695</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1672</integer>
+// CHECK-NEXT: <key>line</key><integer>1695</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21821,12 +23146,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1674</integer>
+// CHECK-NEXT: <key>line</key><integer>1697</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1674</integer>
+// CHECK-NEXT: <key>line</key><integer>1697</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21842,12 +23167,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1674</integer>
+// CHECK-NEXT: <key>line</key><integer>1697</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1674</integer>
+// CHECK-NEXT: <key>line</key><integer>1697</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21855,12 +23180,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1674</integer>
+// CHECK-NEXT: <key>line</key><integer>1697</integer>
// CHECK-NEXT: <key>col</key><integer>27</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1674</integer>
+// CHECK-NEXT: <key>line</key><integer>1697</integer>
// CHECK-NEXT: <key>col</key><integer>27</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21872,7 +23197,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1674</integer>
+// CHECK-NEXT: <key>line</key><integer>1697</integer>
// CHECK-NEXT: <key>col</key><integer>27</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21880,12 +23205,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1674</integer>
+// CHECK-NEXT: <key>line</key><integer>1697</integer>
// CHECK-NEXT: <key>col</key><integer>28</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1674</integer>
+// CHECK-NEXT: <key>line</key><integer>1697</integer>
// CHECK-NEXT: <key>col</key><integer>33</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21903,10 +23228,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Use-after-release</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>rdar10232019_positive</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>6</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>6</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1674</integer>
+// CHECK-NEXT: <key>line</key><integer>1697</integer>
// CHECK-NEXT: <key>col</key><integer>27</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21922,12 +23247,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1793</integer>
+// CHECK-NEXT: <key>line</key><integer>1816</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1793</integer>
+// CHECK-NEXT: <key>line</key><integer>1816</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21935,12 +23260,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1794</integer>
+// CHECK-NEXT: <key>line</key><integer>1817</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1794</integer>
+// CHECK-NEXT: <key>line</key><integer>1817</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21956,12 +23281,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1794</integer>
+// CHECK-NEXT: <key>line</key><integer>1817</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1794</integer>
+// CHECK-NEXT: <key>line</key><integer>1817</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21969,12 +23294,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1795</integer>
+// CHECK-NEXT: <key>line</key><integer>1818</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1795</integer>
+// CHECK-NEXT: <key>line</key><integer>1818</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -21990,12 +23315,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1795</integer>
+// CHECK-NEXT: <key>line</key><integer>1818</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1795</integer>
+// CHECK-NEXT: <key>line</key><integer>1818</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22003,12 +23328,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1795</integer>
+// CHECK-NEXT: <key>line</key><integer>1818</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1795</integer>
+// CHECK-NEXT: <key>line</key><integer>1818</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22020,7 +23345,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1795</integer>
+// CHECK-NEXT: <key>line</key><integer>1818</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22028,12 +23353,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1795</integer>
+// CHECK-NEXT: <key>line</key><integer>1818</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1795</integer>
+// CHECK-NEXT: <key>line</key><integer>1818</integer>
// CHECK-NEXT: <key>col</key><integer>66</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22053,12 +23378,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1795</integer>
+// CHECK-NEXT: <key>line</key><integer>1818</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1795</integer>
+// CHECK-NEXT: <key>line</key><integer>1818</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22066,12 +23391,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1798</integer>
+// CHECK-NEXT: <key>line</key><integer>1821</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1798</integer>
+// CHECK-NEXT: <key>line</key><integer>1821</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22083,7 +23408,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1798</integer>
+// CHECK-NEXT: <key>line</key><integer>1821</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22091,12 +23416,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1798</integer>
+// CHECK-NEXT: <key>line</key><integer>1821</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1798</integer>
+// CHECK-NEXT: <key>line</key><integer>1821</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22114,10 +23439,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_objc_arrays</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>6</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>6</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1798</integer>
+// CHECK-NEXT: <key>line</key><integer>1821</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22133,12 +23458,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1793</integer>
+// CHECK-NEXT: <key>line</key><integer>1816</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1793</integer>
+// CHECK-NEXT: <key>line</key><integer>1816</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22146,12 +23471,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1794</integer>
+// CHECK-NEXT: <key>line</key><integer>1817</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1794</integer>
+// CHECK-NEXT: <key>line</key><integer>1817</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22167,12 +23492,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1794</integer>
+// CHECK-NEXT: <key>line</key><integer>1817</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1794</integer>
+// CHECK-NEXT: <key>line</key><integer>1817</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22180,12 +23505,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1804</integer>
+// CHECK-NEXT: <key>line</key><integer>1827</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1804</integer>
+// CHECK-NEXT: <key>line</key><integer>1827</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22201,12 +23526,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1804</integer>
+// CHECK-NEXT: <key>line</key><integer>1827</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1804</integer>
+// CHECK-NEXT: <key>line</key><integer>1827</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22214,12 +23539,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1804</integer>
+// CHECK-NEXT: <key>line</key><integer>1827</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1804</integer>
+// CHECK-NEXT: <key>line</key><integer>1827</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22231,7 +23556,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1804</integer>
+// CHECK-NEXT: <key>line</key><integer>1827</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22239,12 +23564,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1804</integer>
+// CHECK-NEXT: <key>line</key><integer>1827</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1804</integer>
+// CHECK-NEXT: <key>line</key><integer>1827</integer>
// CHECK-NEXT: <key>col</key><integer>56</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22264,12 +23589,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1804</integer>
+// CHECK-NEXT: <key>line</key><integer>1827</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1804</integer>
+// CHECK-NEXT: <key>line</key><integer>1827</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22277,12 +23602,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1807</integer>
+// CHECK-NEXT: <key>line</key><integer>1830</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1807</integer>
+// CHECK-NEXT: <key>line</key><integer>1830</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22294,7 +23619,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1807</integer>
+// CHECK-NEXT: <key>line</key><integer>1830</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22302,12 +23627,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1807</integer>
+// CHECK-NEXT: <key>line</key><integer>1830</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1807</integer>
+// CHECK-NEXT: <key>line</key><integer>1830</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22325,10 +23650,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_objc_arrays</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>15</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>15</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1807</integer>
+// CHECK-NEXT: <key>line</key><integer>1830</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22344,12 +23669,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1793</integer>
+// CHECK-NEXT: <key>line</key><integer>1816</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1793</integer>
+// CHECK-NEXT: <key>line</key><integer>1816</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22357,12 +23682,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1794</integer>
+// CHECK-NEXT: <key>line</key><integer>1817</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1794</integer>
+// CHECK-NEXT: <key>line</key><integer>1817</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22378,12 +23703,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1794</integer>
+// CHECK-NEXT: <key>line</key><integer>1817</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1794</integer>
+// CHECK-NEXT: <key>line</key><integer>1817</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22391,12 +23716,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1812</integer>
+// CHECK-NEXT: <key>line</key><integer>1835</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1812</integer>
+// CHECK-NEXT: <key>line</key><integer>1835</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22412,12 +23737,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1812</integer>
+// CHECK-NEXT: <key>line</key><integer>1835</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1812</integer>
+// CHECK-NEXT: <key>line</key><integer>1835</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22425,12 +23750,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1812</integer>
+// CHECK-NEXT: <key>line</key><integer>1835</integer>
// CHECK-NEXT: <key>col</key><integer>24</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1812</integer>
+// CHECK-NEXT: <key>line</key><integer>1835</integer>
// CHECK-NEXT: <key>col</key><integer>24</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22442,7 +23767,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1812</integer>
+// CHECK-NEXT: <key>line</key><integer>1835</integer>
// CHECK-NEXT: <key>col</key><integer>24</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22450,12 +23775,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1812</integer>
+// CHECK-NEXT: <key>line</key><integer>1835</integer>
// CHECK-NEXT: <key>col</key><integer>24</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1812</integer>
+// CHECK-NEXT: <key>line</key><integer>1835</integer>
// CHECK-NEXT: <key>col</key><integer>27</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22475,12 +23800,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1812</integer>
+// CHECK-NEXT: <key>line</key><integer>1835</integer>
// CHECK-NEXT: <key>col</key><integer>24</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1812</integer>
+// CHECK-NEXT: <key>line</key><integer>1835</integer>
// CHECK-NEXT: <key>col</key><integer>24</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22488,12 +23813,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1812</integer>
+// CHECK-NEXT: <key>line</key><integer>1835</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1812</integer>
+// CHECK-NEXT: <key>line</key><integer>1835</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22505,7 +23830,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1812</integer>
+// CHECK-NEXT: <key>line</key><integer>1835</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22513,24 +23838,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1812</integer>
+// CHECK-NEXT: <key>line</key><integer>1835</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1812</integer>
+// CHECK-NEXT: <key>line</key><integer>1835</integer>
// CHECK-NEXT: <key>col</key><integer>35</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1812</integer>
+// CHECK-NEXT: <key>line</key><integer>1835</integer>
// CHECK-NEXT: <key>col</key><integer>24</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1812</integer>
+// CHECK-NEXT: <key>line</key><integer>1835</integer>
// CHECK-NEXT: <key>col</key><integer>27</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22550,12 +23875,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1812</integer>
+// CHECK-NEXT: <key>line</key><integer>1835</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1812</integer>
+// CHECK-NEXT: <key>line</key><integer>1835</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22563,12 +23888,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1815</integer>
+// CHECK-NEXT: <key>line</key><integer>1838</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1815</integer>
+// CHECK-NEXT: <key>line</key><integer>1838</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22580,7 +23905,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1815</integer>
+// CHECK-NEXT: <key>line</key><integer>1838</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22588,12 +23913,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1815</integer>
+// CHECK-NEXT: <key>line</key><integer>1838</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1815</integer>
+// CHECK-NEXT: <key>line</key><integer>1838</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22611,10 +23936,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_objc_arrays</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>23</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>23</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1815</integer>
+// CHECK-NEXT: <key>line</key><integer>1838</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22630,12 +23955,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1793</integer>
+// CHECK-NEXT: <key>line</key><integer>1816</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1793</integer>
+// CHECK-NEXT: <key>line</key><integer>1816</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22643,12 +23968,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1794</integer>
+// CHECK-NEXT: <key>line</key><integer>1817</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1794</integer>
+// CHECK-NEXT: <key>line</key><integer>1817</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22664,12 +23989,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1794</integer>
+// CHECK-NEXT: <key>line</key><integer>1817</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1794</integer>
+// CHECK-NEXT: <key>line</key><integer>1817</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22677,12 +24002,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1820</integer>
+// CHECK-NEXT: <key>line</key><integer>1843</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1820</integer>
+// CHECK-NEXT: <key>line</key><integer>1843</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22698,12 +24023,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1820</integer>
+// CHECK-NEXT: <key>line</key><integer>1843</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1820</integer>
+// CHECK-NEXT: <key>line</key><integer>1843</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22711,12 +24036,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1820</integer>
+// CHECK-NEXT: <key>line</key><integer>1843</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1820</integer>
+// CHECK-NEXT: <key>line</key><integer>1843</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22728,7 +24053,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1820</integer>
+// CHECK-NEXT: <key>line</key><integer>1843</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22736,12 +24061,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1820</integer>
+// CHECK-NEXT: <key>line</key><integer>1843</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1820</integer>
+// CHECK-NEXT: <key>line</key><integer>1843</integer>
// CHECK-NEXT: <key>col</key><integer>57</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22761,12 +24086,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1820</integer>
+// CHECK-NEXT: <key>line</key><integer>1843</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1820</integer>
+// CHECK-NEXT: <key>line</key><integer>1843</integer>
// CHECK-NEXT: <key>col</key><integer>22</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22774,12 +24099,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1824</integer>
+// CHECK-NEXT: <key>line</key><integer>1847</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1824</integer>
+// CHECK-NEXT: <key>line</key><integer>1847</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22791,7 +24116,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1824</integer>
+// CHECK-NEXT: <key>line</key><integer>1847</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22799,12 +24124,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1824</integer>
+// CHECK-NEXT: <key>line</key><integer>1847</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1824</integer>
+// CHECK-NEXT: <key>line</key><integer>1847</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22822,10 +24147,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_objc_arrays</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>32</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>32</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1824</integer>
+// CHECK-NEXT: <key>line</key><integer>1847</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22841,12 +24166,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1793</integer>
+// CHECK-NEXT: <key>line</key><integer>1816</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1793</integer>
+// CHECK-NEXT: <key>line</key><integer>1816</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22854,12 +24179,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1794</integer>
+// CHECK-NEXT: <key>line</key><integer>1817</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1794</integer>
+// CHECK-NEXT: <key>line</key><integer>1817</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22875,12 +24200,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1794</integer>
+// CHECK-NEXT: <key>line</key><integer>1817</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1794</integer>
+// CHECK-NEXT: <key>line</key><integer>1817</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22888,12 +24213,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1829</integer>
+// CHECK-NEXT: <key>line</key><integer>1852</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1829</integer>
+// CHECK-NEXT: <key>line</key><integer>1852</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22909,12 +24234,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1829</integer>
+// CHECK-NEXT: <key>line</key><integer>1852</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1829</integer>
+// CHECK-NEXT: <key>line</key><integer>1852</integer>
// CHECK-NEXT: <key>col</key><integer>20</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22922,12 +24247,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1829</integer>
+// CHECK-NEXT: <key>line</key><integer>1852</integer>
// CHECK-NEXT: <key>col</key><integer>28</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1829</integer>
+// CHECK-NEXT: <key>line</key><integer>1852</integer>
// CHECK-NEXT: <key>col</key><integer>28</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22939,7 +24264,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1829</integer>
+// CHECK-NEXT: <key>line</key><integer>1852</integer>
// CHECK-NEXT: <key>col</key><integer>28</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22947,12 +24272,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1829</integer>
+// CHECK-NEXT: <key>line</key><integer>1852</integer>
// CHECK-NEXT: <key>col</key><integer>28</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1829</integer>
+// CHECK-NEXT: <key>line</key><integer>1852</integer>
// CHECK-NEXT: <key>col</key><integer>35</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22972,12 +24297,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1829</integer>
+// CHECK-NEXT: <key>line</key><integer>1852</integer>
// CHECK-NEXT: <key>col</key><integer>28</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1829</integer>
+// CHECK-NEXT: <key>line</key><integer>1852</integer>
// CHECK-NEXT: <key>col</key><integer>28</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -22985,12 +24310,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1829</integer>
+// CHECK-NEXT: <key>line</key><integer>1852</integer>
// CHECK-NEXT: <key>col</key><integer>27</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1829</integer>
+// CHECK-NEXT: <key>line</key><integer>1852</integer>
// CHECK-NEXT: <key>col</key><integer>27</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23002,7 +24327,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1829</integer>
+// CHECK-NEXT: <key>line</key><integer>1852</integer>
// CHECK-NEXT: <key>col</key><integer>27</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23010,24 +24335,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1829</integer>
+// CHECK-NEXT: <key>line</key><integer>1852</integer>
// CHECK-NEXT: <key>col</key><integer>27</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1829</integer>
+// CHECK-NEXT: <key>line</key><integer>1852</integer>
// CHECK-NEXT: <key>col</key><integer>43</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1829</integer>
+// CHECK-NEXT: <key>line</key><integer>1852</integer>
// CHECK-NEXT: <key>col</key><integer>28</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1829</integer>
+// CHECK-NEXT: <key>line</key><integer>1852</integer>
// CHECK-NEXT: <key>col</key><integer>35</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23047,12 +24372,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1829</integer>
+// CHECK-NEXT: <key>line</key><integer>1852</integer>
// CHECK-NEXT: <key>col</key><integer>27</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1829</integer>
+// CHECK-NEXT: <key>line</key><integer>1852</integer>
// CHECK-NEXT: <key>col</key><integer>27</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23060,12 +24385,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1833</integer>
+// CHECK-NEXT: <key>line</key><integer>1856</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1833</integer>
+// CHECK-NEXT: <key>line</key><integer>1856</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23077,7 +24402,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1833</integer>
+// CHECK-NEXT: <key>line</key><integer>1856</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23085,12 +24410,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1833</integer>
+// CHECK-NEXT: <key>line</key><integer>1856</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1833</integer>
+// CHECK-NEXT: <key>line</key><integer>1856</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23108,10 +24433,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_objc_arrays</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>41</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>41</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1833</integer>
+// CHECK-NEXT: <key>line</key><integer>1856</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23127,12 +24452,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1838</integer>
+// CHECK-NEXT: <key>line</key><integer>1861</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1838</integer>
+// CHECK-NEXT: <key>line</key><integer>1861</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23140,12 +24465,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1838</integer>
+// CHECK-NEXT: <key>line</key><integer>1861</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1838</integer>
+// CHECK-NEXT: <key>line</key><integer>1861</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23157,7 +24482,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1838</integer>
+// CHECK-NEXT: <key>line</key><integer>1861</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23165,12 +24490,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1838</integer>
+// CHECK-NEXT: <key>line</key><integer>1861</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1838</integer>
+// CHECK-NEXT: <key>line</key><integer>1861</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23190,12 +24515,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1838</integer>
+// CHECK-NEXT: <key>line</key><integer>1861</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1838</integer>
+// CHECK-NEXT: <key>line</key><integer>1861</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23203,12 +24528,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1838</integer>
+// CHECK-NEXT: <key>line</key><integer>1861</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1838</integer>
+// CHECK-NEXT: <key>line</key><integer>1861</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23220,7 +24545,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1838</integer>
+// CHECK-NEXT: <key>line</key><integer>1861</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23228,24 +24553,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1838</integer>
+// CHECK-NEXT: <key>line</key><integer>1861</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1838</integer>
+// CHECK-NEXT: <key>line</key><integer>1861</integer>
// CHECK-NEXT: <key>col</key><integer>24</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1838</integer>
+// CHECK-NEXT: <key>line</key><integer>1861</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1838</integer>
+// CHECK-NEXT: <key>line</key><integer>1861</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23265,12 +24590,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1838</integer>
+// CHECK-NEXT: <key>line</key><integer>1861</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1838</integer>
+// CHECK-NEXT: <key>line</key><integer>1861</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23278,12 +24603,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1840</integer>
+// CHECK-NEXT: <key>line</key><integer>1863</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1840</integer>
+// CHECK-NEXT: <key>line</key><integer>1863</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23295,7 +24620,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1840</integer>
+// CHECK-NEXT: <key>line</key><integer>1863</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23311,10 +24636,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_objc_integer_literals</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>3</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>3</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1840</integer>
+// CHECK-NEXT: <key>line</key><integer>1863</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23330,12 +24655,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1843</integer>
+// CHECK-NEXT: <key>line</key><integer>1866</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1843</integer>
+// CHECK-NEXT: <key>line</key><integer>1866</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23343,12 +24668,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1843</integer>
+// CHECK-NEXT: <key>line</key><integer>1866</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1843</integer>
+// CHECK-NEXT: <key>line</key><integer>1866</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23360,7 +24685,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1843</integer>
+// CHECK-NEXT: <key>line</key><integer>1866</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23368,12 +24693,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1843</integer>
+// CHECK-NEXT: <key>line</key><integer>1866</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1843</integer>
+// CHECK-NEXT: <key>line</key><integer>1866</integer>
// CHECK-NEXT: <key>col</key><integer>18</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23393,12 +24718,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1843</integer>
+// CHECK-NEXT: <key>line</key><integer>1866</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1843</integer>
+// CHECK-NEXT: <key>line</key><integer>1866</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23406,12 +24731,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1843</integer>
+// CHECK-NEXT: <key>line</key><integer>1866</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1843</integer>
+// CHECK-NEXT: <key>line</key><integer>1866</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23423,7 +24748,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1843</integer>
+// CHECK-NEXT: <key>line</key><integer>1866</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23431,24 +24756,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1843</integer>
+// CHECK-NEXT: <key>line</key><integer>1866</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1843</integer>
+// CHECK-NEXT: <key>line</key><integer>1866</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1843</integer>
+// CHECK-NEXT: <key>line</key><integer>1866</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1843</integer>
+// CHECK-NEXT: <key>line</key><integer>1866</integer>
// CHECK-NEXT: <key>col</key><integer>18</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23468,12 +24793,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1843</integer>
+// CHECK-NEXT: <key>line</key><integer>1866</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1843</integer>
+// CHECK-NEXT: <key>line</key><integer>1866</integer>
// CHECK-NEXT: <key>col</key><integer>14</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23481,12 +24806,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1847</integer>
+// CHECK-NEXT: <key>line</key><integer>1870</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1847</integer>
+// CHECK-NEXT: <key>line</key><integer>1870</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23498,7 +24823,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1847</integer>
+// CHECK-NEXT: <key>line</key><integer>1870</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23506,12 +24831,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1847</integer>
+// CHECK-NEXT: <key>line</key><integer>1870</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1847</integer>
+// CHECK-NEXT: <key>line</key><integer>1870</integer>
// CHECK-NEXT: <key>col</key><integer>21</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23529,10 +24854,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_objc_boxed_expressions</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>5</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>5</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1847</integer>
+// CHECK-NEXT: <key>line</key><integer>1870</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23548,12 +24873,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1843</integer>
+// CHECK-NEXT: <key>line</key><integer>1866</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1843</integer>
+// CHECK-NEXT: <key>line</key><integer>1866</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23561,12 +24886,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1846</integer>
+// CHECK-NEXT: <key>line</key><integer>1869</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1846</integer>
+// CHECK-NEXT: <key>line</key><integer>1869</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23582,12 +24907,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1846</integer>
+// CHECK-NEXT: <key>line</key><integer>1869</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1846</integer>
+// CHECK-NEXT: <key>line</key><integer>1869</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23595,12 +24920,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1846</integer>
+// CHECK-NEXT: <key>line</key><integer>1869</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1846</integer>
+// CHECK-NEXT: <key>line</key><integer>1869</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23612,7 +24937,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1846</integer>
+// CHECK-NEXT: <key>line</key><integer>1869</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23620,12 +24945,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1846</integer>
+// CHECK-NEXT: <key>line</key><integer>1869</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1846</integer>
+// CHECK-NEXT: <key>line</key><integer>1869</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23645,12 +24970,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1846</integer>
+// CHECK-NEXT: <key>line</key><integer>1869</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1846</integer>
+// CHECK-NEXT: <key>line</key><integer>1869</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23658,12 +24983,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1846</integer>
+// CHECK-NEXT: <key>line</key><integer>1869</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1846</integer>
+// CHECK-NEXT: <key>line</key><integer>1869</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23675,7 +25000,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1846</integer>
+// CHECK-NEXT: <key>line</key><integer>1869</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23683,24 +25008,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1846</integer>
+// CHECK-NEXT: <key>line</key><integer>1869</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1846</integer>
+// CHECK-NEXT: <key>line</key><integer>1869</integer>
// CHECK-NEXT: <key>col</key><integer>23</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1846</integer>
+// CHECK-NEXT: <key>line</key><integer>1869</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1846</integer>
+// CHECK-NEXT: <key>line</key><integer>1869</integer>
// CHECK-NEXT: <key>col</key><integer>15</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23720,12 +25045,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1846</integer>
+// CHECK-NEXT: <key>line</key><integer>1869</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1846</integer>
+// CHECK-NEXT: <key>line</key><integer>1869</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23733,12 +25058,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1848</integer>
+// CHECK-NEXT: <key>line</key><integer>1871</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1848</integer>
+// CHECK-NEXT: <key>line</key><integer>1871</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23750,7 +25075,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1848</integer>
+// CHECK-NEXT: <key>line</key><integer>1871</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23766,10 +25091,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_objc_boxed_expressions</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>6</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>6</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1848</integer>
+// CHECK-NEXT: <key>line</key><integer>1871</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23785,12 +25110,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1853</integer>
+// CHECK-NEXT: <key>line</key><integer>1876</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1853</integer>
+// CHECK-NEXT: <key>line</key><integer>1876</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23798,12 +25123,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1854</integer>
+// CHECK-NEXT: <key>line</key><integer>1877</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1854</integer>
+// CHECK-NEXT: <key>line</key><integer>1877</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23819,12 +25144,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1854</integer>
+// CHECK-NEXT: <key>line</key><integer>1877</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1854</integer>
+// CHECK-NEXT: <key>line</key><integer>1877</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23832,12 +25157,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1855</integer>
+// CHECK-NEXT: <key>line</key><integer>1878</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1855</integer>
+// CHECK-NEXT: <key>line</key><integer>1878</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23853,12 +25178,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1855</integer>
+// CHECK-NEXT: <key>line</key><integer>1878</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1855</integer>
+// CHECK-NEXT: <key>line</key><integer>1878</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23866,12 +25191,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1855</integer>
+// CHECK-NEXT: <key>line</key><integer>1878</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1855</integer>
+// CHECK-NEXT: <key>line</key><integer>1878</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23883,7 +25208,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1855</integer>
+// CHECK-NEXT: <key>line</key><integer>1878</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23891,12 +25216,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1855</integer>
+// CHECK-NEXT: <key>line</key><integer>1878</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1855</integer>
+// CHECK-NEXT: <key>line</key><integer>1878</integer>
// CHECK-NEXT: <key>col</key><integer>12</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23916,12 +25241,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1855</integer>
+// CHECK-NEXT: <key>line</key><integer>1878</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1855</integer>
+// CHECK-NEXT: <key>line</key><integer>1878</integer>
// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23929,12 +25254,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1858</integer>
+// CHECK-NEXT: <key>line</key><integer>1881</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1858</integer>
+// CHECK-NEXT: <key>line</key><integer>1881</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23950,12 +25275,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1858</integer>
+// CHECK-NEXT: <key>line</key><integer>1881</integer>
// CHECK-NEXT: <key>col</key><integer>7</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1858</integer>
+// CHECK-NEXT: <key>line</key><integer>1881</integer>
// CHECK-NEXT: <key>col</key><integer>17</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23963,12 +25288,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1858</integer>
+// CHECK-NEXT: <key>line</key><integer>1881</integer>
// CHECK-NEXT: <key>col</key><integer>21</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1858</integer>
+// CHECK-NEXT: <key>line</key><integer>1881</integer>
// CHECK-NEXT: <key>col</key><integer>21</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23980,7 +25305,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1858</integer>
+// CHECK-NEXT: <key>line</key><integer>1881</integer>
// CHECK-NEXT: <key>col</key><integer>21</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -23988,12 +25313,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1858</integer>
+// CHECK-NEXT: <key>line</key><integer>1881</integer>
// CHECK-NEXT: <key>col</key><integer>21</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1858</integer>
+// CHECK-NEXT: <key>line</key><integer>1881</integer>
// CHECK-NEXT: <key>col</key><integer>43</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24013,12 +25338,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1858</integer>
+// CHECK-NEXT: <key>line</key><integer>1881</integer>
// CHECK-NEXT: <key>col</key><integer>21</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1858</integer>
+// CHECK-NEXT: <key>line</key><integer>1881</integer>
// CHECK-NEXT: <key>col</key><integer>21</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24026,12 +25351,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1859</integer>
+// CHECK-NEXT: <key>line</key><integer>1882</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1859</integer>
+// CHECK-NEXT: <key>line</key><integer>1882</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24047,12 +25372,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1859</integer>
+// CHECK-NEXT: <key>line</key><integer>1882</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1859</integer>
+// CHECK-NEXT: <key>line</key><integer>1882</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24060,12 +25385,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1860</integer>
+// CHECK-NEXT: <key>line</key><integer>1883</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1860</integer>
+// CHECK-NEXT: <key>line</key><integer>1883</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24077,7 +25402,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1860</integer>
+// CHECK-NEXT: <key>line</key><integer>1883</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24085,24 +25410,24 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1860</integer>
+// CHECK-NEXT: <key>line</key><integer>1883</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1860</integer>
+// CHECK-NEXT: <key>line</key><integer>1883</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1860</integer>
+// CHECK-NEXT: <key>line</key><integer>1883</integer>
// CHECK-NEXT: <key>col</key><integer>6</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1860</integer>
+// CHECK-NEXT: <key>line</key><integer>1883</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24122,12 +25447,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1860</integer>
+// CHECK-NEXT: <key>line</key><integer>1883</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1860</integer>
+// CHECK-NEXT: <key>line</key><integer>1883</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24135,12 +25460,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1861</integer>
+// CHECK-NEXT: <key>line</key><integer>1884</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1861</integer>
+// CHECK-NEXT: <key>line</key><integer>1884</integer>
// CHECK-NEXT: <key>col</key><integer>9</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24152,7 +25477,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1861</integer>
+// CHECK-NEXT: <key>line</key><integer>1884</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24160,12 +25485,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1861</integer>
+// CHECK-NEXT: <key>line</key><integer>1884</integer>
// CHECK-NEXT: <key>col</key><integer>25</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1861</integer>
+// CHECK-NEXT: <key>line</key><integer>1884</integer>
// CHECK-NEXT: <key>col</key><integer>35</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24183,10 +25508,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Use-after-release</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>rdar11400885</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>9</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>9</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1861</integer>
+// CHECK-NEXT: <key>line</key><integer>1884</integer>
// CHECK-NEXT: <key>col</key><integer>5</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24202,12 +25527,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1880</integer>
+// CHECK-NEXT: <key>line</key><integer>1903</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1880</integer>
+// CHECK-NEXT: <key>line</key><integer>1903</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24215,12 +25540,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1888</integer>
+// CHECK-NEXT: <key>line</key><integer>1911</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1888</integer>
+// CHECK-NEXT: <key>line</key><integer>1911</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24236,12 +25561,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1888</integer>
+// CHECK-NEXT: <key>line</key><integer>1911</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1888</integer>
+// CHECK-NEXT: <key>line</key><integer>1911</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24249,12 +25574,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1888</integer>
+// CHECK-NEXT: <key>line</key><integer>1911</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1888</integer>
+// CHECK-NEXT: <key>line</key><integer>1911</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24266,7 +25591,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1888</integer>
+// CHECK-NEXT: <key>line</key><integer>1911</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24274,12 +25599,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1888</integer>
+// CHECK-NEXT: <key>line</key><integer>1911</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1888</integer>
+// CHECK-NEXT: <key>line</key><integer>1911</integer>
// CHECK-NEXT: <key>col</key><integer>21</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24299,12 +25624,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1888</integer>
+// CHECK-NEXT: <key>line</key><integer>1911</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1888</integer>
+// CHECK-NEXT: <key>line</key><integer>1911</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24312,12 +25637,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1889</integer>
+// CHECK-NEXT: <key>line</key><integer>1912</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1889</integer>
+// CHECK-NEXT: <key>line</key><integer>1912</integer>
// CHECK-NEXT: <key>col</key><integer>24</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24329,7 +25654,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1889</integer>
+// CHECK-NEXT: <key>line</key><integer>1912</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24337,12 +25662,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1889</integer>
+// CHECK-NEXT: <key>line</key><integer>1912</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1889</integer>
+// CHECK-NEXT: <key>line</key><integer>1912</integer>
// CHECK-NEXT: <key>col</key><integer>35</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24360,10 +25685,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Bad release</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testConsumeAndStopTracking</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>10</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>10</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1889</integer>
+// CHECK-NEXT: <key>line</key><integer>1912</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24379,12 +25704,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1893</integer>
+// CHECK-NEXT: <key>line</key><integer>1916</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1893</integer>
+// CHECK-NEXT: <key>line</key><integer>1916</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24392,12 +25717,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1901</integer>
+// CHECK-NEXT: <key>line</key><integer>1924</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1901</integer>
+// CHECK-NEXT: <key>line</key><integer>1924</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24413,12 +25738,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1901</integer>
+// CHECK-NEXT: <key>line</key><integer>1924</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1901</integer>
+// CHECK-NEXT: <key>line</key><integer>1924</integer>
// CHECK-NEXT: <key>col</key><integer>4</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24426,12 +25751,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1901</integer>
+// CHECK-NEXT: <key>line</key><integer>1924</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1901</integer>
+// CHECK-NEXT: <key>line</key><integer>1924</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24443,7 +25768,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1901</integer>
+// CHECK-NEXT: <key>line</key><integer>1924</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24451,12 +25776,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1901</integer>
+// CHECK-NEXT: <key>line</key><integer>1924</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1901</integer>
+// CHECK-NEXT: <key>line</key><integer>1924</integer>
// CHECK-NEXT: <key>col</key><integer>21</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24476,12 +25801,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1901</integer>
+// CHECK-NEXT: <key>line</key><integer>1924</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1901</integer>
+// CHECK-NEXT: <key>line</key><integer>1924</integer>
// CHECK-NEXT: <key>col</key><integer>19</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24489,12 +25814,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1902</integer>
+// CHECK-NEXT: <key>line</key><integer>1925</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1902</integer>
+// CHECK-NEXT: <key>line</key><integer>1925</integer>
// CHECK-NEXT: <key>col</key><integer>26</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24506,7 +25831,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1902</integer>
+// CHECK-NEXT: <key>line</key><integer>1925</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24514,12 +25839,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1902</integer>
+// CHECK-NEXT: <key>line</key><integer>1925</integer>
// CHECK-NEXT: <key>col</key><integer>28</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1902</integer>
+// CHECK-NEXT: <key>line</key><integer>1925</integer>
// CHECK-NEXT: <key>col</key><integer>48</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24537,10 +25862,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Bad release</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>testCFConsumeAndStopTracking</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>10</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>10</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1902</integer>
+// CHECK-NEXT: <key>line</key><integer>1925</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24556,12 +25881,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1914</integer>
+// CHECK-NEXT: <key>line</key><integer>1937</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1914</integer>
+// CHECK-NEXT: <key>line</key><integer>1937</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24569,12 +25894,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1914</integer>
+// CHECK-NEXT: <key>line</key><integer>1937</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1914</integer>
+// CHECK-NEXT: <key>line</key><integer>1937</integer>
// CHECK-NEXT: <key>col</key><integer>29</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24586,7 +25911,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1914</integer>
+// CHECK-NEXT: <key>line</key><integer>1937</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24594,12 +25919,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <array>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1914</integer>
+// CHECK-NEXT: <key>line</key><integer>1937</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1914</integer>
+// CHECK-NEXT: <key>line</key><integer>1937</integer>
// CHECK-NEXT: <key>col</key><integer>31</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24619,12 +25944,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>start</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1914</integer>
+// CHECK-NEXT: <key>line</key><integer>1937</integer>
// CHECK-NEXT: <key>col</key><integer>16</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1914</integer>
+// CHECK-NEXT: <key>line</key><integer>1937</integer>
// CHECK-NEXT: <key>col</key><integer>29</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24632,12 +25957,12 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>end</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1915</integer>
+// CHECK-NEXT: <key>line</key><integer>1938</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1915</integer>
+// CHECK-NEXT: <key>line</key><integer>1938</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24649,7 +25974,7 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1915</integer>
+// CHECK-NEXT: <key>line</key><integer>1938</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -24665,10 +25990,10 @@ void test_CFPlugInInstanceCreate(CFUUIDRef factoryUUID, CFUUIDRef typeUUID) {
// CHECK-NEXT: <key>type</key><string>Leak</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_custom_cf</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>1915</integer>
+// CHECK-NEXT: <key>line</key><integer>1938</integer>
// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
diff --git a/test/Analysis/retain-release.mm b/test/Analysis/retain-release.mm
index d92237b..47d67ea 100644
--- a/test/Analysis/retain-release.mm
+++ b/test/Analysis/retain-release.mm
@@ -64,6 +64,8 @@ extern const CFArrayCallBacks kCFTypeArrayCallBacks;
typedef const struct __CFArray * CFArrayRef;
typedef struct __CFArray * CFMutableArrayRef;
extern CFMutableArrayRef CFArrayCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFArrayCallBacks *callBacks);
+void abort(void) __attribute__((noreturn));
+CFArrayRef CFArrayCreate(CFAllocatorRef allocator, const void **values, CFIndex numValues, const CFArrayCallBacks *callBacks);
extern const void *CFArrayGetValueAtIndex(CFArrayRef theArray, CFIndex idx);
extern void CFArrayAppendValue(CFMutableArrayRef theArray, const void *value);
typedef struct {
@@ -385,3 +387,24 @@ void testCallback() {
val >> process;
}
+//===----------------------------------------------------------------------===//
+// Test handling static initializers.
+//===----------------------------------------------------------------------===//
+
+@interface radar13227740 : NSObject
+@end
+
+@implementation radar13227740
+- (CFArrayRef)test {
+ static CFArrayRef array = ::CFArrayCreate(0, 0, 0, 0);
+ do { if (!((0 != array)/1)) { abort(); } } while (false);
+ return array;
+}
+
+// Previously this reported a bogus leak.
+- (void)test2 {
+ (void)[self test];
+ (void)[self test];
+}
+@end
+
diff --git a/test/Analysis/self-init.m b/test/Analysis/self-init.m
index b0c51a2..5a4354f 100644
--- a/test/Analysis/self-init.m
+++ b/test/Analysis/self-init.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.SelfInit -fobjc-default-synthesize-properties -analyzer-ipa=dynamic -fno-builtin %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.SelfInit -fobjc-default-synthesize-properties -analyzer-config ipa=dynamic -fno-builtin %s -verify
// RUN: %clang_cc1 -analyze -analyzer-checker=osx.cocoa.SelfInit -fobjc-default-synthesize-properties -fno-builtin %s -verify
@class NSZone, NSCoder;
@@ -281,3 +281,28 @@ typedef signed char BOOL;
}
@end
+// Test for radar://12838705.
+@interface ABCClass : NSObject
+@property (nonatomic, strong) NSString *foo;
+@property (nonatomic, strong) NSString *bar;
+@property (nonatomic, strong) NSString *baz;
+@end
+
+@implementation ABCClass
+@synthesize foo = foo_;
+@synthesize bar = bar_;
+@synthesize baz = baz_;
+
+- (id)initWithABC:(ABCClass *)abc {
+ self = [super init];
+ baz_ = abc->baz_;
+ return self;
+}
+
+- (ABCClass *)abcWithFoo:(NSString *)foo {
+ ABCClass *copy = [[ABCClass alloc] initWithABC:self];
+ return copy;
+}
+
+@end
+
diff --git a/test/Analysis/shallow-mode.m b/test/Analysis/shallow-mode.m
new file mode 100644
index 0000000..23df699
--- /dev/null
+++ b/test/Analysis/shallow-mode.m
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config mode=shallow -verify %s
+// expected-no-diagnostics
+
+void clang_analyzer_checkInlined(unsigned);
+
+typedef signed char BOOL;
+typedef struct objc_class *Class;
+typedef struct objc_object {
+ Class isa;
+} *id;
+@protocol NSObject - (BOOL)isEqual:(id)object; @end
+@interface NSObject <NSObject> {}
++(id)alloc;
+-(id)init;
+@end
+
+@interface MyClass : NSObject
++ (void)callee;
++ (void)caller;
+@end
+
+@implementation MyClass
++ (void)caller {
+ [MyClass callee];
+}
++ (void)callee {
+ clang_analyzer_checkInlined(0); // The call is not inlined.
+}
+@end \ No newline at end of file
diff --git a/test/Analysis/simple-stream-checks.c b/test/Analysis/simple-stream-checks.c
index 2f09e5d..ce57fa7 100644
--- a/test/Analysis/simple-stream-checks.c
+++ b/test/Analysis/simple-stream-checks.c
@@ -44,8 +44,8 @@ void CloseOnlyOnValidFileHandle() {
}
void leakOnEnfOfPath1(int *Data) {
- FILE *F = fopen("myfile.txt", "w");// expected-warning {{Opened file is never closed; potential resource leak}}
-}
+ 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");
@@ -76,3 +76,16 @@ void SymbolDoesNotEscapeThoughStringAPIs(char *Data) {
fputc(*Data, F);
return; // expected-warning {{Opened file is never closed; potential resource leak}}
}
+
+void passConstPointer(const FILE * F);
+void testPassConstPointer() {
+ FILE *F = fopen("myfile.txt", "w");
+ passConstPointer(F);
+ return; // expected-warning {{Opened file is never closed; potential resource leak}}
+}
+
+void testPassToSystemHeaderFunctionIndirectly() {
+ FileStruct fs;
+ fs.p = fopen("myfile.txt", "w");
+ fakeSystemHeaderCall(&fs);
+} // expected-warning {{Opened file is never closed; potential resource leak}}
diff --git a/test/Analysis/stack-addr-ps.cpp b/test/Analysis/stack-addr-ps.cpp
index a27bef7..7aefea5 100644
--- a/test/Analysis/stack-addr-ps.cpp
+++ b/test/Analysis/stack-addr-ps.cpp
@@ -22,17 +22,17 @@ const int& g3() {
int get_value();
-const int &get_reference1() { return get_value(); } // expected-warning{{Address of stack memory associated with temporary object of type 'const int' returned}} expected-warning {{returning reference to local temporary}}
+const int &get_reference1() { return get_value(); } // expected-warning{{Address of stack memory associated with temporary object of type 'int' returned}} expected-warning {{returning reference to local temporary}}
const int &get_reference2() {
const int &x = get_value(); // expected-note {{binding reference variable 'x' here}}
- return x; // expected-warning{{Address of stack memory associated with temporary object of type 'const int' returned}} expected-warning {{returning reference to local temporary}}
+ return x; // expected-warning{{Address of stack memory associated with temporary object of type 'int' returned}} expected-warning {{returning reference to local temporary}}
}
const int &get_reference3() {
const int &x1 = get_value(); // expected-note {{binding reference variable 'x1' here}}
const int &x2 = x1; // expected-note {{binding reference variable 'x2' here}}
- return x2; // expected-warning{{Address of stack memory associated with temporary object of type 'const int' returned}} expected-warning {{returning reference to local temporary}}
+ return x2; // expected-warning{{Address of stack memory associated with temporary object of type 'int' returned}} expected-warning {{returning reference to local temporary}}
}
int global_var;
@@ -56,7 +56,7 @@ int *f3() {
const int *f4() {
const int &x1 = get_value(); // expected-note {{binding reference variable 'x1' here}}
const int &x2 = x1; // expected-note {{binding reference variable 'x2' here}}
- return &x2; // expected-warning{{Address of stack memory associated with temporary object of type 'const int' returned}} expected-warning {{returning address of local temporary}}
+ return &x2; // expected-warning{{Address of stack memory associated with temporary object of type 'int' returned}} expected-warning {{returning address of local temporary}}
}
struct S {
@@ -90,3 +90,9 @@ int* f5() {
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}}
}
+
+void *radar13226577() {
+ void *p = &p;
+ return p; // expected-warning {{stack memory associated with local variable 'p' returned to caller}}
+}
+
diff --git a/test/Analysis/stackaddrleak.c b/test/Analysis/stackaddrleak.c
index ada0cc1..10564fa 100644
--- a/test/Analysis/stackaddrleak.c
+++ b/test/Analysis/stackaddrleak.c
@@ -4,8 +4,8 @@ char const *p;
void f0() {
char const str[] = "This will change";
- p = str; // expected-warning{{Address of stack memory associated with local variable 'str' is still referred to by the global variable 'p' upon returning to the caller. This will be a dangling reference}}
-}
+ p = str;
+} // expected-warning{{Address of stack memory associated with local variable 'str' is still referred to by the global variable 'p' upon returning to the caller. This will be a dangling reference}}
void f1() {
char const str[] = "This will change";
@@ -14,8 +14,8 @@ void f1() {
}
void f2() {
- p = (const char *) __builtin_alloca(12); // expected-warning{{Address of stack memory allocated by call to alloca() on line 17 is still referred to by the global variable 'p' upon returning to the caller. This will be a dangling reference}}
-}
+ p = (const char *) __builtin_alloca(12);
+} // expected-warning{{Address of stack memory allocated by call to alloca() on line 17 is still referred to by the global variable 'p' upon returning to the caller. This will be a dangling reference}}
// PR 7383 - previosly the stack address checker would crash on this example
// because it would attempt to do a direct load from 'pr7383_list'.
@@ -30,5 +30,5 @@ void test_multi_return() {
static int *a, *b;
int x;
a = &x;
- b = &x; // expected-warning{{Address of stack memory associated with local variable 'x' is still referred to by the global variable 'a' upon returning}} expected-warning{{Address of stack memory associated with local variable 'x' is still referred to by the global variable 'b' upon returning}}
-}
+ b = &x;
+} // expected-warning{{Address of stack memory associated with local variable 'x' is still referred to by the global variable 'a' upon returning}} expected-warning{{Address of stack memory associated with local variable 'x' is still referred to by the global variable 'b' upon returning}}
diff --git a/test/Analysis/stats.c b/test/Analysis/stats.c
index 6beadbe..5701dc7 100644
--- a/test/Analysis/stats.c
+++ b/test/Analysis/stats.c
@@ -1,3 +1,4 @@
+// REQUIRES: asserts
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-stats %s 2>&1 | FileCheck %s
void foo() {
diff --git a/test/Analysis/string.c b/test/Analysis/string.c
index fd836c4..74cf33c 100644
--- a/test/Analysis/string.c
+++ b/test/Analysis/string.c
@@ -279,12 +279,16 @@ void strcpy_fn_const(char *x) {
strcpy(x, (const char*)&strcpy_fn); // expected-warning{{Argument to string copy function is the address of the function 'strcpy_fn', which is not a null-terminated string}}
}
+extern int globalInt;
void strcpy_effects(char *x, char *y) {
char a = x[0];
+ if (globalInt != 42)
+ return;
clang_analyzer_eval(strcpy(x, y) == x); // expected-warning{{TRUE}}
clang_analyzer_eval(strlen(x) == strlen(y)); // expected-warning{{TRUE}}
clang_analyzer_eval(a == x[0]); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(globalInt == 42); // expected-warning{{TRUE}}
}
void strcpy_overflow(char *y) {
@@ -410,12 +414,6 @@ void strcat_symbolic_dst_length(char *dst) {
clang_analyzer_eval(strlen(dst) >= 4); // expected-warning{{TRUE}}
}
-void strcat_symbolic_src_length(char *src) {
- char dst[8] = "1234";
- strcat(dst, src);
- clang_analyzer_eval(strlen(dst) >= 4); // expected-warning{{TRUE}}
-}
-
void strcat_symbolic_dst_length_taint(char *dst) {
scanf("%s", dst); // Taint data.
strcat(dst, "1234");
@@ -521,17 +519,6 @@ void strncpy_exactly_matching_buffer(char *y) {
clang_analyzer_eval(strlen(x) > 4); // expected-warning{{UNKNOWN}}
}
-void strncpy_exactly_matching_buffer2(char *y) {
- if (strlen(y) >= 4)
- return;
-
- char x[4];
- strncpy(x, y, 4); // no-warning
-
- // This time, we know that y fits in x anyway.
- clang_analyzer_eval(strlen(x) <= 3); // expected-warning{{TRUE}}
-}
-
void strncpy_zero(char *src) {
char dst[] = "123";
strncpy(dst, src, 0); // no-warning
@@ -1039,3 +1026,30 @@ void strncasecmp_diff_length_6() {
void strncasecmp_embedded_null () {
clang_analyzer_eval(strncasecmp("ab\0zz", "ab\0yy", 4) == 0); // expected-warning{{TRUE}}
}
+
+//===----------------------------------------------------------------------===
+// FIXMEs
+//===----------------------------------------------------------------------===
+
+// The analyzer_eval call below should evaluate to true. We are being too
+// aggressive in marking the (length of) src symbol dead. The length of dst
+// depends on src. This could be explicitely specified in the checker or the
+// logic for handling MetadataSymbol in SymbolManager needs to change.
+void strcat_symbolic_src_length(char *src) {
+ char dst[8] = "1234";
+ strcat(dst, src);
+ clang_analyzer_eval(strlen(dst) >= 4); // expected-warning{{UNKNOWN}}
+}
+
+// The analyzer_eval call below should evaluate to true. Most likely the same
+// issue as the test above.
+void strncpy_exactly_matching_buffer2(char *y) {
+ if (strlen(y) >= 4)
+ return;
+
+ char x[4];
+ strncpy(x, y, 4); // no-warning
+
+ // This time, we know that y fits in x anyway.
+ clang_analyzer_eval(strlen(x) <= 3); // expected-warning{{UNKNOWN}}
+}
diff --git a/test/Analysis/viewcontroller.m b/test/Analysis/superclass.m
index a8c4580..ba5ea40 100644
--- a/test/Analysis/viewcontroller.m
+++ b/test/Analysis/superclass.m
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -fblocks -analyze -analyzer-checker=alpha.osx.cocoa.MissingSuperCall -verify -Wno-objc-root-class %s
+// Define used Classes
@protocol NSObject
- (id)retain;
- (oneway void)release;
@@ -8,13 +9,15 @@
- (id)init;
+ (id)alloc;
@end
-
typedef char BOOL;
typedef double NSTimeInterval;
typedef enum UIViewAnimationOptions {
UIViewAnimationOptionLayoutSubviews = 1 << 0
} UIViewAnimationOptions;
+@interface NSCoder : NSObject {}
+@end
+// Define the Superclasses for our Checks
@interface UIViewController : NSObject {}
- (void)addChildViewController:(UIViewController *)childController;
- (void)viewDidAppear:(BOOL)animated;
@@ -32,8 +35,21 @@ typedef enum UIViewAnimationOptions {
animations:(void (^)(void))animations
completion:(void (^)(BOOL finished))completion;
@end
+@interface UIResponder : NSObject {}
+- (BOOL)resignFirstResponder;
+@end
+@interface NSResponder : NSObject {}
+- (void)restoreStateWithCoder:(NSCoder *)coder;
+- (void)encodeRestorableStateWithCoder:(NSCoder *)coder;
+@end
+@interface NSDocument : NSObject {}
+- (void)restoreStateWithCoder:(NSCoder *)coder;
+- (void)encodeRestorableStateWithCoder:(NSCoder *)coder;
+@end
-// Do not warn if UIViewController isn't our superclass
+// Checks
+
+// Do not warn if UIViewController/*Responder/NSDocument is not our superclass
@interface TestA
@end
@implementation TestA
@@ -48,7 +64,9 @@ typedef enum UIViewAnimationOptions {
- (void)viewWillDisappear:(BOOL)animated {}
- (void)didReceiveMemoryWarning {}
- (void)removeFromParentViewController {}
-
+- (BOOL)resignFirstResponder { return 0; }
+- (void)restoreStateWithCoder:(NSCoder *)coder {}
+- (void)encodeRestorableStateWithCoder:(NSCoder *)coder {}
@end
// Warn if UIViewController is our superclass and we do not call super
@@ -72,7 +90,7 @@ typedef enum UIViewAnimationOptions {
- (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 {};
+- (void)shouldAutorotate {}
@end
// Do not warn if UIViewController is our superclass but we did call super
@@ -133,3 +151,72 @@ typedef enum UIViewAnimationOptions {
[self methodDoingStuff];
} // expected-warning {{The 'removeFromParentViewController' instance method in UIViewController subclass 'TestC' is missing a [super removeFromParentViewController] call}}
@end
+
+
+// Do warn for UIResponder subclasses that don't call super
+@interface TestD : UIResponder {}
+@end
+@implementation TestD
+
+- (BOOL)resignFirstResponder {
+ return 0;
+} // expected-warning {{The 'resignFirstResponder' instance method in UIResponder subclass 'TestD' is missing a [super resignFirstResponder] call}}
+@end
+
+// Do not warn for UIResponder subclasses that do the right thing
+@interface TestE : UIResponder {}
+@end
+@implementation TestE
+
+- (BOOL)resignFirstResponder {
+ return [super resignFirstResponder];
+}
+@end
+
+// Do warn for NSResponder subclasses that don't call super
+@interface TestF : NSResponder {}
+@end
+@implementation TestF
+
+- (void)restoreStateWithCoder:(NSCoder *)coder {
+} // expected-warning {{The 'restoreStateWithCoder:' instance method in NSResponder subclass 'TestF' is missing a [super restoreStateWithCoder:] call}}
+- (void)encodeRestorableStateWithCoder:(NSCoder *)coder {
+} // expected-warning {{The 'encodeRestorableStateWithCoder:' instance method in NSResponder subclass 'TestF' is missing a [super encodeRestorableStateWithCoder:] call}}
+@end
+
+// Do not warn for NSResponder subclasses that do the right thing
+@interface TestG : NSResponder {}
+@end
+@implementation TestG
+
+- (void)restoreStateWithCoder:(NSCoder *)coder {
+ [super restoreStateWithCoder:coder];
+}
+- (void)encodeRestorableStateWithCoder:(NSCoder *)coder {
+ [super encodeRestorableStateWithCoder:coder];
+}
+@end
+
+// Do warn for NSDocument subclasses that don't call super
+@interface TestH : NSDocument {}
+@end
+@implementation TestH
+
+- (void)restoreStateWithCoder:(NSCoder *)coder {
+} // expected-warning {{The 'restoreStateWithCoder:' instance method in NSDocument subclass 'TestH' is missing a [super restoreStateWithCoder:] call}}
+- (void)encodeRestorableStateWithCoder:(NSCoder *)coder {
+} // expected-warning {{The 'encodeRestorableStateWithCoder:' instance method in NSDocument subclass 'TestH' is missing a [super encodeRestorableStateWithCoder:] call}}
+@end
+
+// Do not warn for NSDocument subclasses that do the right thing
+@interface TestI : NSDocument {}
+@end
+@implementation TestI
+
+- (void)restoreStateWithCoder:(NSCoder *)coder {
+ [super restoreStateWithCoder:coder];
+}
+- (void)encodeRestorableStateWithCoder:(NSCoder *)coder {
+ [super encodeRestorableStateWithCoder:coder];
+}
+@end \ No newline at end of file
diff --git a/test/Analysis/taint-generic.c b/test/Analysis/taint-generic.c
index 696db67..fe27070 100644
--- a/test/Analysis/taint-generic.c
+++ b/test/Analysis/taint-generic.c
@@ -212,3 +212,14 @@ int SymSymExprWithDiffTypes(void* p) {
return 5/j; // expected-warning {{Division by a tainted value, possibly zero}}
}
+
+void constraintManagerShouldTreatAsOpaque(int rhs) {
+ int i;
+ scanf("%d", &i);
+ // This comparison used to hit an assertion in the constraint manager,
+ // which didn't handle NonLoc sym-sym comparisons.
+ if (i < rhs)
+ return;
+ if (i < rhs)
+ *(volatile int *) 0; // no-warning
+}
diff --git a/test/Analysis/temp-obj-dtors-cfg-output.cpp b/test/Analysis/temp-obj-dtors-cfg-output.cpp
index c884475..1ddccb7 100644
--- a/test/Analysis/temp-obj-dtors-cfg-output.cpp
+++ b/test/Analysis/temp-obj-dtors-cfg-output.cpp
@@ -207,22 +207,22 @@ TestCtorInits::TestCtorInits()
// CHECK: 14: int a = int(A().operator int()) + int(B().operator int());
// CHECK: 15: ~B() (Temporary object destructor)
// CHECK: 16: ~A() (Temporary object destructor)
-// CHECK: 17: A() (CXXConstructExpr, class A)
-// CHECK: 18: [B1.17] (BindTemporary)
-// CHECK: 19: [B1.18].operator int
-// CHECK: 20: [B1.19]()
-// CHECK: 21: [B1.20] (ImplicitCastExpr, UserDefinedConversion, int)
-// CHECK: 22: int([B1.21]) (CXXFunctionalCastExpr, NoOp, int)
-// CHECK: 23: B() (CXXConstructExpr, class B)
-// CHECK: 24: [B1.23] (BindTemporary)
-// CHECK: 25: [B1.24].operator int
-// CHECK: 26: [B1.25]()
-// CHECK: 27: [B1.26] (ImplicitCastExpr, UserDefinedConversion, int)
-// CHECK: 28: int([B1.27]) (CXXFunctionalCastExpr, NoOp, int)
-// CHECK: 29: [B1.22] + [B1.28]
-// CHECK: 30: foo
-// CHECK: 31: [B1.30] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(int))
-// CHECK: 32: [B1.31]([B1.29])
+// CHECK: 17: foo
+// CHECK: 18: [B1.17] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(int))
+// CHECK: 19: A() (CXXConstructExpr, class A)
+// CHECK: 20: [B1.19] (BindTemporary)
+// CHECK: 21: [B1.20].operator int
+// CHECK: 22: [B1.21]()
+// CHECK: 23: [B1.22] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK: 24: int([B1.23]) (CXXFunctionalCastExpr, NoOp, int)
+// CHECK: 25: B() (CXXConstructExpr, class B)
+// CHECK: 26: [B1.25] (BindTemporary)
+// CHECK: 27: [B1.26].operator int
+// CHECK: 28: [B1.27]()
+// CHECK: 29: [B1.28] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK: 30: int([B1.29]) (CXXFunctionalCastExpr, NoOp, int)
+// CHECK: 31: [B1.24] + [B1.30]
+// CHECK: 32: [B1.18]([B1.31])
// CHECK: 33: ~B() (Temporary object destructor)
// CHECK: 34: ~A() (Temporary object destructor)
// CHECK: 35: int b;
@@ -242,11 +242,9 @@ TestCtorInits::TestCtorInits()
// CHECK: Preds (1): B3
// CHECK: Succs (1): B1
// CHECK: [B3]
-// CHECK: 1: [B5.6] && [B4.5]
-// CHECK: 2: foo
-// CHECK: 3: [B3.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(_Bool))
-// CHECK: 4: [B3.3]([B3.1])
-// CHECK: T: [B5.6] && ...
+// CHECK: 1: [B5.8] && [B4.5]
+// CHECK: 2: [B5.3]([B3.1])
+// CHECK: T: [B5.8] && ...
// CHECK: Preds (2): B4 B5
// CHECK: Succs (2): B2 B1
// CHECK: [B4]
@@ -259,12 +257,14 @@ TestCtorInits::TestCtorInits()
// CHECK: Succs (1): B3
// CHECK: [B5]
// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: A() (CXXConstructExpr, class A)
-// CHECK: 3: [B5.2] (BindTemporary)
-// CHECK: 4: [B5.3].operator _Bool
-// CHECK: 5: [B5.4]()
-// CHECK: 6: [B5.5] (ImplicitCastExpr, UserDefinedConversion, _Bool)
-// CHECK: T: [B5.6] && ...
+// CHECK: 2: foo
+// CHECK: 3: [B5.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(_Bool))
+// CHECK: 4: A() (CXXConstructExpr, class A)
+// CHECK: 5: [B5.4] (BindTemporary)
+// CHECK: 6: [B5.5].operator _Bool
+// CHECK: 7: [B5.6]()
+// CHECK: 8: [B5.7] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CHECK: T: [B5.8] && ...
// CHECK: Preds (2): B6 B7
// CHECK: Succs (2): B4 B3
// CHECK: [B6]
@@ -308,11 +308,9 @@ TestCtorInits::TestCtorInits()
// CHECK: Preds (1): B3
// CHECK: Succs (1): B1
// CHECK: [B3]
-// CHECK: 1: [B5.6] || [B4.5]
-// CHECK: 2: foo
-// CHECK: 3: [B3.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(_Bool))
-// CHECK: 4: [B3.3]([B3.1])
-// CHECK: T: [B5.6] || ...
+// CHECK: 1: [B5.8] || [B4.5]
+// CHECK: 2: [B5.3]([B3.1])
+// CHECK: T: [B5.8] || ...
// CHECK: Preds (2): B4 B5
// CHECK: Succs (2): B1 B2
// CHECK: [B4]
@@ -325,12 +323,14 @@ TestCtorInits::TestCtorInits()
// CHECK: Succs (1): B3
// CHECK: [B5]
// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: A() (CXXConstructExpr, class A)
-// CHECK: 3: [B5.2] (BindTemporary)
-// CHECK: 4: [B5.3].operator _Bool
-// CHECK: 5: [B5.4]()
-// CHECK: 6: [B5.5] (ImplicitCastExpr, UserDefinedConversion, _Bool)
-// CHECK: T: [B5.6] || ...
+// CHECK: 2: foo
+// CHECK: 3: [B5.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(_Bool))
+// CHECK: 4: A() (CXXConstructExpr, class A)
+// CHECK: 5: [B5.4] (BindTemporary)
+// CHECK: 6: [B5.5].operator _Bool
+// CHECK: 7: [B5.6]()
+// CHECK: 8: [B5.7] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CHECK: T: [B5.8] || ...
// CHECK: Preds (2): B6 B7
// CHECK: Succs (2): B3 B4
// CHECK: [B6]
@@ -370,17 +370,17 @@ TestCtorInits::TestCtorInits()
// CHECK: Preds (2): B2 B3
// CHECK: Succs (1): B0
// CHECK: [B2]
-// CHECK: 1: 0
-// CHECK: 2: foo
-// CHECK: 3: [B2.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(int))
-// CHECK: 4: [B2.3]([B2.1])
+// CHECK: 1: foo
+// CHECK: 2: [B2.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(int))
+// CHECK: 3: 0
+// CHECK: 4: [B2.2]([B2.3])
// CHECK: Preds (1): B4
// CHECK: Succs (1): B1
// CHECK: [B3]
-// CHECK: 1: 0
-// CHECK: 2: foo
-// CHECK: 3: [B3.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(int))
-// CHECK: 4: [B3.3]([B3.1])
+// CHECK: 1: foo
+// CHECK: 2: [B3.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(int))
+// CHECK: 3: 0
+// CHECK: 4: [B3.2]([B3.3])
// CHECK: Preds (1): B4
// CHECK: Succs (1): B1
// CHECK: [B4]
@@ -474,13 +474,11 @@ TestCtorInits::TestCtorInits()
// CHECK: Preds (1): B4
// CHECK: Succs (1): B1
// CHECK: [B4]
-// CHECK: 1: [B7.6] ? [B5.6] : [B6.15]
+// CHECK: 1: [B7.8] ? [B5.6] : [B6.15]
// CHECK: 2: [B4.1] (ImplicitCastExpr, NoOp, const class A)
// CHECK: 3: [B4.2]
-// CHECK: 4: foo
-// CHECK: 5: [B4.4] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
-// CHECK: 6: [B4.5]([B4.3])
-// CHECK: T: [B7.6] ? ... : ...
+// CHECK: 4: [B7.3]([B4.3])
+// CHECK: T: [B7.8] ? ... : ...
// CHECK: Preds (2): B5 B6
// CHECK: Succs (2): B2 B3
// CHECK: [B5]
@@ -512,12 +510,14 @@ TestCtorInits::TestCtorInits()
// CHECK: Succs (1): B4
// CHECK: [B7]
// CHECK: 1: ~B() (Temporary object destructor)
-// CHECK: 2: B() (CXXConstructExpr, class B)
-// CHECK: 3: [B7.2] (BindTemporary)
-// CHECK: 4: [B7.3].operator _Bool
-// CHECK: 5: [B7.4]()
-// CHECK: 6: [B7.5] (ImplicitCastExpr, UserDefinedConversion, _Bool)
-// CHECK: T: [B7.6] ? ... : ...
+// CHECK: 2: foo
+// CHECK: 3: [B7.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
+// CHECK: 4: B() (CXXConstructExpr, class B)
+// CHECK: 5: [B7.4] (BindTemporary)
+// CHECK: 6: [B7.5].operator _Bool
+// CHECK: 7: [B7.6]()
+// CHECK: 8: [B7.7] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CHECK: T: [B7.8] ? ... : ...
// CHECK: Preds (2): B8 B9
// CHECK: Succs (2): B5 B6
// CHECK: [B8]
@@ -647,17 +647,15 @@ TestCtorInits::TestCtorInits()
// CHECK: Preds (1): B4
// CHECK: Succs (1): B1
// CHECK: [B4]
-// CHECK: 1: [B7.3] ?: [B6.6]
+// CHECK: 1: [B7.5] ?: [B6.6]
// CHECK: 2: [B4.1] (ImplicitCastExpr, NoOp, const class A)
// CHECK: 3: [B4.2]
-// CHECK: 4: foo
-// CHECK: 5: [B4.4] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
-// CHECK: 6: [B4.5]([B4.3])
-// CHECK: T: [B7.6] ? ... : ...
+// CHECK: 4: [B7.3]([B4.3])
+// CHECK: T: [B7.8] ? ... : ...
// CHECK: Preds (2): B5 B6
// CHECK: Succs (2): B2 B3
// CHECK: [B5]
-// CHECK: 1: [B7.3] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 1: [B7.5] (ImplicitCastExpr, NoOp, const class A)
// CHECK: 2: [B5.1]
// CHECK: 3: [B5.2] (CXXConstructExpr, class A)
// CHECK: 4: [B5.3] (BindTemporary)
@@ -674,12 +672,14 @@ TestCtorInits::TestCtorInits()
// CHECK: Succs (1): B4
// CHECK: [B7]
// CHECK: 1: ~A() (Temporary object destructor)
-// CHECK: 2: A() (CXXConstructExpr, class A)
-// CHECK: 3: [B7.2] (BindTemporary)
-// CHECK: 4: [B7.3].operator _Bool
-// CHECK: 5: [B7.4]()
-// CHECK: 6: [B7.5] (ImplicitCastExpr, UserDefinedConversion, _Bool)
-// CHECK: T: [B7.6] ? ... : ...
+// CHECK: 2: foo
+// CHECK: 3: [B7.2] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
+// CHECK: 4: A() (CXXConstructExpr, class A)
+// CHECK: 5: [B7.4] (BindTemporary)
+// CHECK: 6: [B7.5].operator _Bool
+// CHECK: 7: [B7.6]()
+// CHECK: 8: [B7.7] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CHECK: T: [B7.8] ? ... : ...
// CHECK: Preds (2): B9 B8
// CHECK: Succs (2): B5 B6
// CHECK: [B8]
@@ -745,13 +745,13 @@ TestCtorInits::TestCtorInits()
// CHECK: 3: [B1.2] (ImplicitCastExpr, NoOp, const class A)
// CHECK: 4: [B1.3]
// CHECK: 5: const A &a = A();
-// CHECK: 6: A() (CXXConstructExpr, class A)
-// CHECK: 7: [B1.6] (BindTemporary)
-// CHECK: 8: [B1.7] (ImplicitCastExpr, NoOp, const class A)
-// CHECK: 9: [B1.8]
-// CHECK: 10: foo
-// CHECK: 11: [B1.10] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
-// CHECK: 12: [B1.11]([B1.9])
+// CHECK: 6: foo
+// CHECK: 7: [B1.6] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
+// CHECK: 8: A() (CXXConstructExpr, class A)
+// CHECK: 9: [B1.8] (BindTemporary)
+// CHECK: 10: [B1.9] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 11: [B1.10]
+// CHECK: 12: [B1.7]([B1.11])
// CHECK: 13: ~A() (Temporary object destructor)
// CHECK: 14: int b;
// CHECK: 15: [B1.5].~A() (Implicit destructor)
@@ -787,15 +787,15 @@ TestCtorInits::TestCtorInits()
// CHECK: 5: [B1.4] (ImplicitCastExpr, NoOp, const class A)
// CHECK: 6: [B1.5]
// CHECK: 7: const A &a = A::make();
-// CHECK: 8: A::make
-// CHECK: 9: [B1.8] (ImplicitCastExpr, FunctionToPointerDecay, class A (*)(void))
-// CHECK: 10: [B1.9]()
-// CHECK: 11: [B1.10] (BindTemporary)
-// CHECK: 12: [B1.11] (ImplicitCastExpr, NoOp, const class A)
-// CHECK: 13: [B1.12]
-// CHECK: 14: foo
-// CHECK: 15: [B1.14] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
-// CHECK: 16: [B1.15]([B1.13])
+// CHECK: 8: foo
+// CHECK: 9: [B1.8] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
+// CHECK: 10: A::make
+// CHECK: 11: [B1.10] (ImplicitCastExpr, FunctionToPointerDecay, class A (*)(void))
+// CHECK: 12: [B1.11]()
+// CHECK: 13: [B1.12] (BindTemporary)
+// CHECK: 14: [B1.13] (ImplicitCastExpr, NoOp, const class A)
+// CHECK: 15: [B1.14]
+// CHECK: 16: [B1.9]([B1.15])
// CHECK: 17: ~A() (Temporary object destructor)
// CHECK: 18: int b;
// CHECK: 19: [B1.7].~A() (Implicit destructor)
diff --git a/test/Analysis/temporaries.cpp b/test/Analysis/temporaries.cpp
index df1ab5a..32a4d3b 100644
--- a/test/Analysis/temporaries.cpp
+++ b/test/Analysis/temporaries.cpp
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-ipa=inlining -verify -w %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -w %s
+
+extern bool clang_analyzer_eval(bool);
struct Trivial {
Trivial(int x) : value(x) {}
@@ -16,7 +18,7 @@ Trivial getTrivial() {
}
const Trivial &getTrivialRef() {
- return Trivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'struct Trivial' returned to caller}}
+ return Trivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'Trivial' returned to caller}}
}
@@ -25,6 +27,52 @@ NonTrivial getNonTrivial() {
}
const NonTrivial &getNonTrivialRef() {
- return NonTrivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'struct NonTrivial' returned to caller}}
+ return NonTrivial(42); // expected-warning {{Address of stack memory associated with temporary object of type 'NonTrivial' returned to caller}}
+}
+
+namespace rdar13265460 {
+ struct TrivialSubclass : public Trivial {
+ TrivialSubclass(int x) : Trivial(x), anotherValue(-x) {}
+ int anotherValue;
+ };
+
+ TrivialSubclass getTrivialSub() {
+ TrivialSubclass obj(1);
+ obj.value = 42;
+ obj.anotherValue = -42;
+ return obj;
+ }
+
+ void testImmediate() {
+ TrivialSubclass obj = getTrivialSub();
+
+ clang_analyzer_eval(obj.value == 42); // expected-warning{{TRUE}}
+ clang_analyzer_eval(obj.anotherValue == -42); // expected-warning{{TRUE}}
+
+ clang_analyzer_eval(getTrivialSub().value == 42); // expected-warning{{TRUE}}
+ clang_analyzer_eval(getTrivialSub().anotherValue == -42); // expected-warning{{TRUE}}
+ }
+
+ void testMaterializeTemporaryExpr() {
+ const TrivialSubclass &ref = getTrivialSub();
+ clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}}
+
+ const Trivial &baseRef = getTrivialSub();
+ clang_analyzer_eval(baseRef.value == 42); // expected-warning{{TRUE}}
+ }
+}
+
+namespace rdar13281951 {
+ struct Derived : public Trivial {
+ Derived(int value) : Trivial(value), value2(-value) {}
+ int value2;
+ };
+
+ void test() {
+ Derived obj(1);
+ obj.value = 42;
+ const Trivial * const &pointerRef = &obj;
+ clang_analyzer_eval(pointerRef->value == 42); // expected-warning{{TRUE}}
+ }
}
diff --git a/test/Analysis/traversal-path-unification.c b/test/Analysis/traversal-path-unification.c
index f53d2ff..83e3b87 100644
--- a/test/Analysis/traversal-path-unification.c
+++ b/test/Analysis/traversal-path-unification.c
@@ -24,5 +24,5 @@ void testRemoveDeadBindings() {
c();
}
-// CHECK: --END PATH--
-// CHECK-NOT: --END PATH-- \ No newline at end of file
+// CHECK: --END FUNCTION--
+// CHECK-NOT: --END FUNCTION--
diff --git a/test/Analysis/uninit-sometimes.cpp b/test/Analysis/uninit-sometimes.cpp
index 7825e87..015b675 100644
--- a/test/Analysis/uninit-sometimes.cpp
+++ b/test/Analysis/uninit-sometimes.cpp
@@ -192,7 +192,7 @@ int test_logical_and_false(int k) {
return x; // expected-note {{uninitialized use}}
}
-// CHECK: fix-it:"{{.*}}":{189:3-191:9}:""
+// CHECK: fix-it:"{{.*}}":{189:3-191:10}:""
// CHECK: fix-it:"{{.*}}":{188:8-188:8}:" = 0"
@@ -232,7 +232,7 @@ int test_logical_or_true(int k) {
return x; // expected-note {{uninitialized use}}
}
-// CHECK: fix-it:"{{.*}}":{229:3-231:9}:""
+// CHECK: fix-it:"{{.*}}":{229:3-231:10}:""
// CHECK: fix-it:"{{.*}}":{228:8-228:8}:" = 0"
diff --git a/test/Analysis/uninit-vals.m b/test/Analysis/uninit-vals.m
index 1cd5759..5a97bef 100644
--- a/test/Analysis/uninit-vals.m
+++ b/test/Analysis/uninit-vals.m
@@ -1,7 +1,13 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store=region -verify %s
-// expected-no-diagnostics
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -verify %s
typedef unsigned int NSUInteger;
+typedef __typeof__(sizeof(int)) size_t;
+
+void *malloc(size_t);
+void *calloc(size_t nmemb, size_t size);
+void free(void *);
+
+void clang_analyzer_eval(int);
@interface A
- (NSUInteger)foo;
@@ -32,3 +38,106 @@ void PR10163 (void) {
float x[2] = {0};
test_PR10163(x[1]); // no-warning
}
+
+
+typedef struct {
+ float x;
+ float y;
+} Point;
+typedef struct {
+ Point origin;
+ int size;
+} Circle;
+
+Point makePoint(float x, float y) {
+ Point result;
+ result.x = x;
+ result.y = y;
+ return result;
+}
+
+void PR14765_test() {
+ Circle *testObj = calloc(sizeof(Circle), 1);
+
+ clang_analyzer_eval(testObj->size == 0); // expected-warning{{TRUE}}
+
+ testObj->origin = makePoint(0.0, 0.0);
+ if (testObj->size > 0) { ; } // warning occurs here
+
+ // FIXME: Assigning to 'testObj->origin' kills the default binding for the
+ // whole region, meaning that we've forgotten that testObj->size should also
+ // default to 0. Tracked by <rdar://problem/12701038>.
+ // This should be TRUE.
+ clang_analyzer_eval(testObj->size == 0); // expected-warning{{UNKNOWN}}
+
+ free(testObj);
+}
+
+void PR14765_argument(Circle *testObj) {
+ int oldSize = testObj->size;
+ clang_analyzer_eval(testObj->size == oldSize); // expected-warning{{TRUE}}
+
+ testObj->origin = makePoint(0.0, 0.0);
+ clang_analyzer_eval(testObj->size == oldSize); // expected-warning{{TRUE}}
+}
+
+
+typedef struct {
+ int x;
+ int y;
+} IntPoint;
+typedef struct {
+ IntPoint origin;
+ int size;
+} IntCircle;
+
+IntPoint makeIntPoint(int x, int y) {
+ IntPoint result;
+ result.x = x;
+ result.y = y;
+ return result;
+}
+
+void PR14765_test_int() {
+ IntCircle *testObj = calloc(sizeof(IntCircle), 1);
+
+ clang_analyzer_eval(testObj->size == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(testObj->origin.x == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(testObj->origin.y == 0); // expected-warning{{TRUE}}
+
+ testObj->origin = makeIntPoint(1, 2);
+ if (testObj->size > 0) { ; } // warning occurs here
+
+ // FIXME: Assigning to 'testObj->origin' kills the default binding for the
+ // whole region, meaning that we've forgotten that testObj->size should also
+ // default to 0. Tracked by <rdar://problem/12701038>.
+ // This should be TRUE.
+ clang_analyzer_eval(testObj->size == 0); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(testObj->origin.x == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(testObj->origin.y == 2); // expected-warning{{TRUE}}
+
+ free(testObj);
+}
+
+void PR14765_argument_int(IntCircle *testObj) {
+ int oldSize = testObj->size;
+ clang_analyzer_eval(testObj->size == oldSize); // expected-warning{{TRUE}}
+
+ testObj->origin = makeIntPoint(1, 2);
+ clang_analyzer_eval(testObj->size == oldSize); // expected-warning{{TRUE}}
+ clang_analyzer_eval(testObj->origin.x == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(testObj->origin.y == 2); // expected-warning{{TRUE}}
+}
+
+
+void rdar13292559(Circle input) {
+ extern void useCircle(Circle);
+
+ Circle obj = input;
+ useCircle(obj); // no-warning
+
+ // This generated an "uninitialized 'size' field" warning for a (short) while.
+ obj.origin = makePoint(0.0, 0.0);
+ useCircle(obj); // no-warning
+}
+
diff --git a/test/Analysis/unix-fns.c b/test/Analysis/unix-fns.c
index edab5e1..8daac1c 100644
--- a/test/Analysis/unix-fns.c
+++ b/test/Analysis/unix-fns.c
@@ -1,4 +1,4 @@
-// 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: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -analyzer-checker=core,unix.API,osx.API %s -analyzer-store=region -analyzer-output=plist -analyzer-eagerly-assume -analyzer-config faux-bodies=true -fblocks -verify -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
struct _opaque_pthread_once_t {
@@ -408,7 +408,7 @@ void test_inline_dispatch_once() {
// CHECK-NEXT: <key>type</key><string>Improper use of &apos;open&apos;</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_open</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>6</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>6</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>55</integer>
@@ -552,11 +552,11 @@ void test_inline_dispatch_once() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Call to &apos;dispatch_once&apos; uses the local variable &apos;pred&apos; for the predicate value. Using such transient memory for the predicate is potentially dangerous. Perhaps you intended to declare the variable as &apos;static&apos;?</string>
-// CHECK-NEXT: <key>category</key><string>Mac OS X API</string>
+// CHECK-NEXT: <key>category</key><string>API Misuse (Apple)</string>
// CHECK-NEXT: <key>type</key><string>Improper use of &apos;dispatch_once&apos;</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_dispatch_once</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>62</integer>
@@ -636,7 +636,7 @@ void test_inline_dispatch_once() {
// CHECK-NEXT: <key>type</key><string>Improper use of &apos;pthread_once&apos;</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_pthread_once</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>73</integer>
@@ -716,7 +716,7 @@ void test_inline_dispatch_once() {
// CHECK-NEXT: <key>type</key><string>Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>pr2899</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>82</integer>
@@ -796,7 +796,7 @@ void test_inline_dispatch_once() {
// CHECK-NEXT: <key>type</key><string>Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_calloc</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>94</integer>
@@ -876,7 +876,7 @@ void test_inline_dispatch_once() {
// CHECK-NEXT: <key>type</key><string>Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_calloc2</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>100</integer>
@@ -956,7 +956,7 @@ void test_inline_dispatch_once() {
// CHECK-NEXT: <key>type</key><string>Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_realloc</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>112</integer>
@@ -1036,7 +1036,7 @@ void test_inline_dispatch_once() {
// CHECK-NEXT: <key>type</key><string>Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_reallocf</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>118</integer>
@@ -1116,7 +1116,7 @@ void test_inline_dispatch_once() {
// CHECK-NEXT: <key>type</key><string>Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_alloca</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>136</integer>
@@ -1196,7 +1196,7 @@ void test_inline_dispatch_once() {
// CHECK-NEXT: <key>type</key><string>Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_builtin_alloca</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>148</integer>
@@ -1276,7 +1276,7 @@ void test_inline_dispatch_once() {
// CHECK-NEXT: <key>type</key><string>Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_valloc</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>1</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>1</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>160</integer>
@@ -1352,11 +1352,11 @@ void test_inline_dispatch_once() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Call to &apos;dispatch_once&apos; uses the local variable &apos;pred&apos; for the predicate value. Using such transient memory for the predicate is potentially dangerous. Perhaps you intended to declare the variable as &apos;static&apos;?</string>
-// CHECK-NEXT: <key>category</key><string>Mac OS X API</string>
+// CHECK-NEXT: <key>category</key><string>API Misuse (Apple)</string>
// CHECK-NEXT: <key>type</key><string>Improper use of &apos;dispatch_once&apos;</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>test_dispatch_once_in_macro</string>
-// CHECK-NEXT: <key>issue_hash</key><integer>2</integer>
+// CHECK-NEXT: <key>issue_hash</key><string>2</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>184</integer>
@@ -1392,9 +1392,9 @@ void test_inline_dispatch_once() {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>control</string>
@@ -1418,12 +1418,12 @@ void test_inline_dispatch_once() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>190</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>190</integer>
-// CHECK-NEXT: <key>col</key><integer>15</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
@@ -1435,6 +1435,35 @@ void test_inline_dispatch_once() {
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>190</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>190</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>194</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;p&apos; captured by block as a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;p&apos; captured by block as a null pointer value</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>190</integer>
// CHECK-NEXT: <key>col</key><integer>3</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -1477,25 +1506,10 @@ void test_inline_dispatch_once() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>190</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>line</key><integer>40</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>190</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>194</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>1</integer>
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Calling anonymous block</string>
@@ -1749,9 +1763,72 @@ void test_inline_dispatch_once() {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>&apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>200</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>200</integer>
+// CHECK-NEXT: <key>col</key><integer>5</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>201</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>201</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>201</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>201</integer>
+// CHECK-NEXT: <key>col</key><integer>24</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>203</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>&apos;p&apos; captured by block as a null pointer value</string>
// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Variable &apos;p&apos; initialized to a null pointer value</string>
+// CHECK-NEXT: <string>&apos;p&apos; captured by block as a null pointer value</string>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>event</string>
@@ -1877,25 +1954,10 @@ void test_inline_dispatch_once() {
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>177</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>line</key><integer>39</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>177</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>177</integer>
-// CHECK-NEXT: <key>col</key><integer>33</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
// CHECK-NEXT: <key>depth</key><integer>2</integer>
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Calling anonymous block</string>
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 8184c3d..a11b83a 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -26,24 +26,27 @@ if(CLANG_TEST_USE_VG)
set(CLANG_TEST_EXTRA_ARGS ${CLANG_TEST_EXTRA_ARGS} "--vg")
endif ()
-if( NOT CLANG_BUILT_STANDALONE )
+set(CLANG_TEST_DEPS
+ clang clang-headers
+ c-index-test diagtool arcmt-test c-arcmt-test
+ clang-check clang-format
+ )
+set(CLANG_TEST_PARAMS
+ clang_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+ )
- set(CLANG_TEST_DEPS
- clang clang-headers
- c-index-test diagtool arcmt-test c-arcmt-test
- clang-check
- llvm-dis llc opt FileCheck count not
+if(CLANG_INCLUDE_TESTS)
+ list(APPEND CLANG_TEST_DEPS ClangUnitTests)
+ list(APPEND CLANG_TEST_PARAMS
+ clang_unit_site_config=${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg
)
- set(CLANG_TEST_PARAMS
- clang_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+endif()
+
+if( NOT CLANG_BUILT_STANDALONE )
+ list(APPEND CLANG_TEST_DEPS
+ llc opt FileCheck count not llvm-symbolizer
)
- if(LLVM_INCLUDE_TESTS)
- list(APPEND CLANG_TEST_DEPS ClangUnitTests)
- list(APPEND CLANG_TEST_PARAMS
- clang_unit_site_config=${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg
- )
- endif()
add_lit_testsuite(check-clang "Running the Clang regression tests"
${CMAKE_CURRENT_BINARY_DIR}
PARAMS ${CLANG_TEST_PARAMS}
@@ -68,19 +71,21 @@ else()
set(LIT_ARGS "${CLANG_TEST_EXTRA_ARGS} ${LLVM_LIT_ARGS}")
separate_arguments(LIT_ARGS)
+
+ list(APPEND CLANG_TEST_PARAMS build_mode=${CMAKE_CFG_INTDIR})
+
+ foreach(param ${CLANG_TEST_PARAMS})
+ list(APPEND LIT_ARGS --param ${param})
+ endforeach()
add_custom_target(check-clang
COMMAND ${PYTHON_EXECUTABLE}
${LIT}
- --param clang_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
- --param build_config=${CMAKE_CFG_INTDIR}
- --param build_mode=${RUNTIME_BUILD_MODE}
${LIT_ARGS}
${CMAKE_CURRENT_BINARY_DIR}
+ ${CLANG_TEST_EXTRA_ARGS}
COMMENT "Running Clang regression tests"
- DEPENDS clang clang-headers
- c-index-test diagtool arcmt-test c-arcmt-test
- clang-check
+ DEPENDS ${CLANG_TEST_DEPS}
)
set_target_properties(check-clang PROPERTIES FOLDER "Clang tests")
endif()
diff --git a/test/CXX/basic/basic.link/p6.cpp b/test/CXX/basic/basic.link/p6.cpp
new file mode 100644
index 0000000..8faec76
--- /dev/null
+++ b/test/CXX/basic/basic.link/p6.cpp
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+// C++11 [basic.link]p6:
+// The name of a function declared in block scope and the name
+// of a variable declared by a block scope extern declaration
+// have linkage. If there is a visible declaration of an entity
+// with linkage having the same name and type, ignoring entities
+// declared outside the innermost enclosing namespace scope, the
+// block scope declaration declares that same entity and
+// receives the linkage of the previous declaration.
+
+// rdar://13535367
+namespace test0 {
+ extern "C" int test0_array[];
+ void declare() { extern int test0_array[100]; }
+ extern "C" int test0_array[];
+ int value = sizeof(test0_array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+}
+
+namespace test1 {
+ extern "C" int test1_array[];
+ void test() {
+ { extern int test1_array[100]; }
+ extern int test1_array[];
+ int x = sizeof(test1_array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+ }
+}
+
+namespace test2 {
+ void declare() { extern int test2_array[100]; }
+ extern int test2_array[];
+ int value = sizeof(test2_array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+}
+
+namespace test3 {
+ void test() {
+ { extern int test3_array[100]; }
+ extern int test3_array[];
+ int x = sizeof(test3_array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+ }
+}
+
+
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp b/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp
index 7ecedd5..1f78a73 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
struct X0 {
X0 f1();
X0 f2();
@@ -25,3 +26,92 @@ struct X0::X0 X0::f2() { return X0(); }
template<typename T> X1<T>::X1<T> X1<T>::f2() { } // expected-error{{qualified reference to 'X1' is a constructor name rather than a template name wherever a constructor can be declared}}
template<typename T> X1<T>::X1<T> (X1<T>::f2)(int) { } // expected-error{{qualified reference to 'X1' is a constructor name rather than a template name wherever a constructor can be declared}}
template<typename T> struct X1<T>::X1<T> (X1<T>::f2)(float) { }
+
+// We have a special case for lookup within using-declarations that are
+// member-declarations: foo::bar::baz::baz always names baz's constructor
+// in such a context, even if looking up 'baz' within foo::bar::baz would
+// not find the injected-class-name. Likewise foo::bar::baz<T>::baz also
+// names the constructor.
+namespace InhCtor {
+ struct A {
+ A(int);
+ protected:
+ int T();
+ };
+ typedef A T;
+ struct B : A {
+ // This is a using-declaration for 'int A::T()' in C++98, but is an
+ // inheriting constructor declaration in C++11.
+ using InhCtor::T::T;
+ };
+#if __cplusplus < 201103L
+ B b(123); // expected-error {{no matching constructor}}
+ // expected-note@-7 2{{candidate constructor}}
+ int n = b.T(); // ok, accessible
+#else
+ B b(123); // ok, inheriting constructor
+ int n = b.T(); // expected-error {{'T' is a protected member of 'InhCtor::A'}}
+ // expected-note@-15 {{declared protected here}}
+
+ template<typename T>
+ struct S : T {
+ struct U : S {
+ using S::S;
+ };
+ using T::T;
+ };
+
+ S<A>::U ua(0);
+ S<B>::U ub(0);
+
+ template<typename T>
+ struct X : T {
+ using T::Z::U::U;
+ };
+ template<typename T>
+ struct X2 : T {
+ using T::Z::template V<int>::V;
+ };
+ struct Y {
+ struct Z {
+ typedef Y U;
+ template<typename T> using V = Y;
+ };
+ Y(int);
+ };
+ X<Y> xy(0);
+
+ namespace Repeat {
+ struct A {
+ struct T {
+ T(int);
+ };
+ };
+ struct Z : A {
+ using A::A::A;
+ };
+ template<typename T>
+ struct ZT : T::T {
+ using T::T::T;
+ };
+ }
+
+ namespace NS {
+ struct NS {};
+ }
+ struct DerivedFromNS : NS::NS {
+ // No special case unless the NNS names a class.
+ using InhCtor::NS::NS; // expected-error {{using declaration in class refers into 'InhCtor::NS::', which is not a class}}
+
+ };
+
+ typedef int I;
+ struct UsingInt {
+ using I::I; // expected-error {{expected a class or namespace}}
+ };
+ template<typename T> struct UsingIntTemplate {
+ using T::T; // expected-error {{type 'int' cannot be used prior to '::' because it has no members}}
+ };
+ UsingIntTemplate<int> uit; // expected-note {{here}}
+#endif
+}
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 4ffe538..7da3087 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p14.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p14.cpp
@@ -17,3 +17,33 @@ namespace N {
int i = 2;
N::S N::j = i;
N::S N::j2(i);
+
+// <rdar://problem/13317030>
+namespace M {
+ class X { };
+ inline X operator-(int, X);
+
+ template<typename T>
+ class Y { };
+
+ typedef Y<float> YFloat;
+
+ namespace yfloat {
+ YFloat operator-(YFloat, YFloat);
+ }
+ using namespace yfloat;
+}
+
+using namespace M;
+
+namespace M {
+
+class Other {
+ void foo(YFloat a, YFloat b);
+};
+
+}
+
+void Other::foo(YFloat a, YFloat b) {
+ YFloat c = a - b;
+}
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp
index d2afd5d..9632fda 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.unqual/p7.cpp
@@ -33,5 +33,5 @@ namespace test1 {
// specifiers.
namespace test2 {
template <class T> struct bar {};
- template <class T> struct foo : bar<foo> {}; // expected-error {{use of class template foo requires template arguments}} expected-note {{template is declared here}}
+ template <class T> struct foo : bar<foo> {}; // expected-error {{use of class template 'foo' requires template arguments}} expected-note {{template is declared here}}
}
diff --git a/test/CXX/basic/basic.start/basic.start.main/p2.cpp b/test/CXX/basic/basic.start/basic.start.main/p2.cpp
new file mode 100644
index 0000000..a5386f1
--- /dev/null
+++ b/test/CXX/basic/basic.start/basic.start.main/p2.cpp
@@ -0,0 +1,101 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST1
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST2
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST3
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST4
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST5
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST6
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST7
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST8
+
+// RUN: cp %s %t
+// RUN: %clang_cc1 -x c++ %s -std=c++11 -fsyntax-only -verify -DTEST9
+// RUN: not %clang_cc1 -x c++ %t -std=c++11 -fixit -DTEST9
+// RUN: %clang_cc1 -x c++ %t -std=c++11 -fsyntax-only -DTEST9
+
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST10
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST11
+// RUN: %clang_cc1 -fsyntax-only -verify %s -DTEST12
+
+#if TEST1
+
+// expected-no-diagnostics
+typedef int Int;
+typedef char Char;
+typedef Char* Carp;
+
+Int main(Int argc, Carp argv[]) {
+}
+
+#elif TEST2
+
+// expected-no-diagnostics
+typedef int Int;
+typedef char Char;
+typedef Char* Carp;
+
+Int main(Int argc, Carp argv[], Char *env[]) {
+}
+
+#elif TEST3
+
+// expected-no-diagnostics
+int main() {
+}
+
+#elif TEST4
+
+static int main() { // expected-error {{'main' is not allowed to be declared static}}
+}
+
+#elif TEST5
+
+inline int main() { // expected-error {{'main' is not allowed to be declared inline}}
+}
+
+#elif TEST6
+
+void // expected-error {{'main' must return 'int'}}
+main( // expected-error {{first parameter of 'main' (argument count) must be of type 'int'}}
+ float a
+) {
+}
+
+#elif TEST7
+
+// expected-no-diagnostics
+int main(int argc, const char* const* argv) {
+}
+
+#elif TEST8
+
+template<typename T>
+int main() { } // expected-error{{'main' cannot be a template}}
+
+#elif TEST9
+
+constexpr int main() { } // expected-error{{'main' is not allowed to be declared constexpr}}
+
+#elif TEST10
+
+// PR15100
+// expected-no-diagnostics
+typedef char charT;
+int main(int, const charT**) {}
+
+#elif TEST11
+
+// expected-no-diagnostics
+typedef char charT;
+int main(int, charT* const *) {}
+
+#elif TEST12
+
+// expected-no-diagnostics
+typedef char charT;
+int main(int, const charT* const *) {}
+
+#else
+
+#error Unknown test mode
+
+#endif
diff --git a/test/CXX/basic/basic.start/basic.start.main/p2a.cpp b/test/CXX/basic/basic.start/basic.start.main/p2a.cpp
deleted file mode 100644
index b27d492..0000000
--- a/test/CXX/basic/basic.start/basic.start.main/p2a.cpp
+++ /dev/null
@@ -1,9 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-// expected-no-diagnostics
-
-typedef int Int;
-typedef char Char;
-typedef Char* Carp;
-
-Int main(Int argc, Carp argv[]) {
-}
diff --git a/test/CXX/basic/basic.start/basic.start.main/p2b.cpp b/test/CXX/basic/basic.start/basic.start.main/p2b.cpp
deleted file mode 100644
index 65cd202..0000000
--- a/test/CXX/basic/basic.start/basic.start.main/p2b.cpp
+++ /dev/null
@@ -1,9 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-// expected-no-diagnostics
-
-typedef int Int;
-typedef char Char;
-typedef Char* Carp;
-
-Int main(Int argc, Carp argv[], Char *env[]) {
-}
diff --git a/test/CXX/basic/basic.start/basic.start.main/p2c.cpp b/test/CXX/basic/basic.start/basic.start.main/p2c.cpp
deleted file mode 100644
index 2b082ec..0000000
--- a/test/CXX/basic/basic.start/basic.start.main/p2c.cpp
+++ /dev/null
@@ -1,5 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-// expected-no-diagnostics
-
-int main() {
-}
diff --git a/test/CXX/basic/basic.start/basic.start.main/p2d.cpp b/test/CXX/basic/basic.start/basic.start.main/p2d.cpp
deleted file mode 100644
index bcdbdb2..0000000
--- a/test/CXX/basic/basic.start/basic.start.main/p2d.cpp
+++ /dev/null
@@ -1,4 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-
-static int main() { // expected-error {{'main' is not allowed to be declared static}}
-}
diff --git a/test/CXX/basic/basic.start/basic.start.main/p2e.cpp b/test/CXX/basic/basic.start/basic.start.main/p2e.cpp
deleted file mode 100644
index 954fdbd..0000000
--- a/test/CXX/basic/basic.start/basic.start.main/p2e.cpp
+++ /dev/null
@@ -1,4 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-
-inline int main() { // expected-error {{'main' is not allowed to be declared inline}}
-}
diff --git a/test/CXX/basic/basic.start/basic.start.main/p2f.cpp b/test/CXX/basic/basic.start/basic.start.main/p2f.cpp
deleted file mode 100644
index ea5a752..0000000
--- a/test/CXX/basic/basic.start/basic.start.main/p2f.cpp
+++ /dev/null
@@ -1,7 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-
-void // expected-error {{'main' must return 'int'}}
-main( // expected-error {{first parameter of 'main' (argument count) must be of type 'int'}}
- float a
-) {
-}
diff --git a/test/CXX/basic/basic.start/basic.start.main/p2g.cpp b/test/CXX/basic/basic.start/basic.start.main/p2g.cpp
deleted file mode 100644
index 45f643f..0000000
--- a/test/CXX/basic/basic.start/basic.start.main/p2g.cpp
+++ /dev/null
@@ -1,5 +0,0 @@
-// 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.start/basic.start.main/p2h.cpp b/test/CXX/basic/basic.start/basic.start.main/p2h.cpp
deleted file mode 100644
index abf8faa..0000000
--- a/test/CXX/basic/basic.start/basic.start.main/p2h.cpp
+++ /dev/null
@@ -1,5 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-
-template<typename T>
-int main() { } // expected-error{{'main' cannot be a template}}
-
diff --git a/test/CXX/basic/basic.start/basic.start.main/p2i.cpp b/test/CXX/basic/basic.start/basic.start.main/p2i.cpp
deleted file mode 100644
index db8da3c..0000000
--- a/test/CXX/basic/basic.start/basic.start.main/p2i.cpp
+++ /dev/null
@@ -1,6 +0,0 @@
-// RUN: cp %s %t
-// RUN: %clang_cc1 -x c++ %s -std=c++11 -fsyntax-only -verify
-// RUN: not %clang_cc1 -x c++ %t -std=c++11 -fixit
-// RUN: %clang_cc1 -x c++ %t -std=c++11 -fsyntax-only
-
-constexpr int main() { } // expected-error{{'main' is not allowed to be declared constexpr}}
diff --git a/test/CXX/basic/basic.types/p10.cpp b/test/CXX/basic/basic.types/p10.cpp
index 191d42b..6401c29 100644
--- a/test/CXX/basic/basic.types/p10.cpp
+++ b/test/CXX/basic/basic.types/p10.cpp
@@ -39,7 +39,7 @@ struct UserProvDtor {
struct NonTrivDtor {
constexpr NonTrivDtor();
constexpr int f(); // expected-error {{non-literal type 'NonTrivDtor' cannot have constexpr members}}
- virtual ~NonTrivDtor() = default; // expected-note {{has a non-trivial destructor}}
+ virtual ~NonTrivDtor() = default; // expected-note {{has a non-trivial destructor}} expected-note {{because it is virtual}}
};
struct NonTrivDtorBase {
~NonTrivDtorBase();
diff --git a/test/CXX/class.access/class.access.base/p5.cpp b/test/CXX/class.access/class.access.base/p5.cpp
index 255fbfc..5b08a86 100644
--- a/test/CXX/class.access/class.access.base/p5.cpp
+++ b/test/CXX/class.access/class.access.base/p5.cpp
@@ -72,4 +72,27 @@ namespace test3 {
};
}
+// Don't crash. <rdar://12926092>
+// Note that 'field' is indeed a private member of X but that access
+// is indeed ultimately constrained by the protected inheritance from Y.
+// If someone wants to put the effort into improving this diagnostic,
+// they can feel free; even explaining it in person would be a pain.
+namespace test4 {
+ class Z;
+ class X {
+ public:
+ void f(Z *p);
+
+ private:
+ int field; // expected-note {{member is declared here}}
+ };
+
+ class Y : public X { };
+ class Z : protected Y { }; // expected-note 2 {{constrained by protected inheritance here}}
+
+ void X::f(Z *p) {
+ p->field = 0; // expected-error {{cannot cast 'test4::Z' to its protected base class 'test4::X'}} expected-error {{'field' is a private member of 'test4::X'}}
+ }
+}
+
// TODO: flesh out these cases
diff --git a/test/CXX/class.access/class.friend/p3-cxx0x.cpp b/test/CXX/class.access/class.friend/p3-cxx0x.cpp
index e4d5fd5..ea9d2ce 100644
--- a/test/CXX/class.access/class.friend/p3-cxx0x.cpp
+++ b/test/CXX/class.access/class.friend/p3-cxx0x.cpp
@@ -28,14 +28,19 @@ X1<Y2> x1a;
X1<Y3> x1b;
X1<Y1> x1c; // expected-note{{in instantiation of template class 'X1<Y1>' requested here}}
+template<typename T> class B;
+
template<typename T>
class A {
T x;
public:
class foo {};
static int y;
+ template <typename S> friend class B<S>::ty;
};
+template <typename T> class B { typedef int ty; };
+
struct {
// Ill-formed
int friend; // expected-error {{'friend' must appear first in a non-function declaration}}
@@ -53,3 +58,5 @@ struct {
float;
template<typename T> friend class A<T>::foo;
} a;
+
+void testA() { (void)sizeof(A<int>); }
diff --git a/test/CXX/class.access/class.protected/p1.cpp b/test/CXX/class.access/class.protected/p1.cpp
index 132ff61..825447e 100644
--- a/test/CXX/class.access/class.protected/p1.cpp
+++ b/test/CXX/class.access/class.protected/p1.cpp
@@ -329,7 +329,7 @@ namespace test8 {
namespace test9 {
class A { // expected-note {{member is declared here}}
- protected: int foo(); // expected-note 4 {{declared}} expected-note 2 {{can only access this member on an object of type}} expected-note {{member is declared here}}
+ protected: int foo(); // expected-note 4 {{declared}} expected-note 3 {{can only access this member on an object of type}} expected-note 2 {{member is declared here}}
};
class B : public A { // expected-note {{member is declared here}}
@@ -344,14 +344,15 @@ namespace test9 {
static void test(A &a) {
a.foo(); // expected-error {{'foo' is a protected member}}
a.A::foo(); // expected-error {{'foo' is a protected member}}
- a.B::foo();
+ a.B::foo(); // expected-error {{'foo' is a protected member}}
a.C::foo(); // expected-error {{'foo' is a protected member}}
+ a.D::foo(); // expected-error {{'foo' is a protected member}}
}
static void test(B &b) {
b.foo();
b.A::foo();
- b.B::foo();
+ b.B::foo(); // accessible as named in A
b.C::foo(); // expected-error {{'foo' is a protected member}}
}
diff --git a/test/CXX/class.derived/class.abstract/p16.cpp b/test/CXX/class.derived/class.abstract/p16.cpp
index 93f905c..c237ed9 100644
--- a/test/CXX/class.derived/class.abstract/p16.cpp
+++ b/test/CXX/class.derived/class.abstract/p16.cpp
@@ -14,3 +14,29 @@ struct C: A {
virtual void a();
virtual void b() = delete;
};
+
+struct E;
+struct F;
+struct G;
+struct H;
+struct D {
+ virtual E &operator=(const E &); // expected-note {{here}}
+ virtual F &operator=(const F &);
+ virtual G &operator=(G&&);
+ virtual H &operator=(H&&); // expected-note {{here}}
+ friend struct F;
+
+private:
+ D &operator=(const D&) = default;
+ D &operator=(D&&) = default;
+ virtual ~D(); // expected-note 2{{here}}
+};
+struct E : D {}; // expected-error {{deleted function '~E' cannot override a non-deleted function}} \
+ // expected-error {{deleted function 'operator=' cannot override a non-deleted function}}
+struct F : D {};
+// No move ctor here, because it would be deleted.
+struct G : D {}; // expected-error {{deleted function '~G' cannot override a non-deleted function}}
+struct H : D {
+ H &operator=(H&&) = default; // expected-error {{deleted function 'operator=' cannot override a non-deleted function}}
+ ~H();
+};
diff --git a/test/CXX/class.derived/class.virtual/p3-0x.cpp b/test/CXX/class.derived/class.virtual/p3-0x.cpp
index 16f9828..6a02a86 100644
--- a/test/CXX/class.derived/class.virtual/p3-0x.cpp
+++ b/test/CXX/class.derived/class.virtual/p3-0x.cpp
@@ -100,3 +100,33 @@ namespace PR13499 {
Y<X> y;
Z<X> z; // expected-note {{in instantiation of}}
}
+
+namespace MemberOfUnknownSpecialization {
+ template<typename T> struct A {
+ struct B {};
+ struct C : B {
+ void f() override;
+ };
+ };
+
+ template<> struct A<int>::B {
+ virtual void f();
+ };
+ // ok
+ A<int>::C c1;
+
+ template<> struct A<char>::B {
+ void f();
+ };
+ // expected-error@-13 {{only virtual member functions can be marked 'override'}}
+ // expected-note@+1 {{in instantiation of}}
+ A<char>::C c2;
+
+ template<> struct A<double>::B {
+ virtual void f() final;
+ };
+ // expected-error@-20 {{declaration of 'f' overrides a 'final' function}}
+ // expected-note@-3 {{here}}
+ // expected-note@+1 {{in instantiation of}}
+ A<double>::C c3;
+}
diff --git a/test/CXX/class/class.static/class.static.data/p3.cpp b/test/CXX/class/class.static/class.static.data/p3.cpp
index 117997e..1607bac 100644
--- a/test/CXX/class/class.static/class.static.data/p3.cpp
+++ b/test/CXX/class/class.static/class.static.data/p3.cpp
@@ -13,7 +13,7 @@ struct S {
static const int d2 = 0;
static constexpr double e = 0.0; // ok
- static const double f = 0.0; // expected-warning {{extension}} expected-note {{use 'constexpr' specifier}}
+ static const double f = 0.0; // expected-error {{requires 'constexpr' specifier}} expected-note {{add 'constexpr'}}
static char *const g = 0; // expected-error {{requires 'constexpr' specifier}}
static const NonLit h = NonLit(); // expected-error {{must be initialized out of line}}
};
diff --git a/test/CXX/class/class.union/p1.cpp b/test/CXX/class/class.union/p1.cpp
index ee97410..439cc9c 100644
--- a/test/CXX/class/class.union/p1.cpp
+++ b/test/CXX/class/class.union/p1.cpp
@@ -14,25 +14,25 @@ class VirtualBase : virtual Okay { // expected-note 4 {{because type 'VirtualBas
};
class Ctor {
- Ctor() { abort(); } // expected-note 4 {{because type 'Ctor' has a user-declared constructor}}
+ Ctor() { abort(); } // expected-note 2{{because type 'Ctor' has a user-provided default constructor}} expected-note 2{{here}}
};
class Ctor2 {
- Ctor2(); // expected-note 3 {{because type 'Ctor2' has a user-declared constructor}}
+ Ctor2(); // expected-note {{because type 'Ctor2' has a user-provided default constructor}} expected-note 2{{here}}
};
-class CtorTmpl {
- template<typename T> CtorTmpl(); // expected-note {{because type 'CtorTmpl' has a user-declared constructor}}
+class CtorTmpl { // expected-note {{because type 'CtorTmpl' has no default constructor}}
+ template<typename T> CtorTmpl(); // expected-note {{implicit default constructor suppressed by user-declared constructor}}
};
-class CopyCtor {
- CopyCtor(CopyCtor &cc) { abort(); } // expected-note 4 {{because type 'CopyCtor' has a user-declared copy constructor}}
+class CopyCtor { // expected-note 2{{because no constructor can be used to copy an object of type 'const CopyCtor'}}
+ CopyCtor(CopyCtor &cc) { abort(); }
};
-class CopyAssign {
- CopyAssign& operator=(CopyAssign& CA) { abort(); } // expected-note 4 {{because type 'CopyAssign' has a user-declared copy assignment operator}}
+class CopyAssign { // expected-note 2 {{because no assignment operator can be used to copy an object of type 'const CopyAssign'}}
+ CopyAssign& operator=(CopyAssign& CA) { abort(); }
};
class Dtor {
- ~Dtor() { abort(); } // expected-note 4 {{because type 'Dtor' has a user-declared destructor}}
+ ~Dtor() { abort(); } // expected-note 2 {{because type 'Dtor' has a user-provided destructor}} expected-note 2{{here}}
};
union U1 {
@@ -49,25 +49,25 @@ union U1 {
union U2 {
struct {
- Virtual v; // expected-note {{because type 'U2::<anonymous struct}}
+ Virtual v; // expected-note {{because the function selected to copy field of type 'Virtual' is not trivial}}
} m1; // expected-error {{union member 'm1' has a non-trivial copy constructor}}
struct {
- VirtualBase vbase; // expected-note {{because type 'U2::<anonymous struct}}
+ VirtualBase vbase; // expected-note {{because the function selected to copy field of type 'VirtualBase' is not trivial}}
} m2; // expected-error {{union member 'm2' has a non-trivial copy constructor}}
struct {
- Ctor ctor; // expected-note {{because type 'U2::<anonymous struct}}
+ Ctor ctor; // expected-note {{because field of type 'Ctor' has a user-provided default constructor}}
} m3; // expected-error {{union member 'm3' has a non-trivial constructor}}
struct {
- Ctor2 ctor2; // expected-note {{because type 'U2::<anonymous struct}}
+ Ctor2 ctor2; // expected-note {{because field of type 'Ctor2' has a user-provided default constructor}}
} m3a; // expected-error {{union member 'm3a' has a non-trivial constructor}}
- struct {
- CopyCtor copyctor; // expected-note {{because type 'U2::<anonymous struct}}
+ struct { // expected-note {{no constructor can be used to copy an object of type 'const}}
+ CopyCtor copyctor;
} m4; // expected-error {{union member 'm4' has a non-trivial copy constructor}}
- struct {
- CopyAssign copyassign; // expected-note {{because type 'U2::<anonymous struct}}
+ struct { // expected-note {{no assignment operator can be used to copy an object of type 'const}}
+ CopyAssign copyassign;
} m5; // expected-error {{union member 'm5' has a non-trivial copy assignment operator}}
struct {
- Dtor dtor; // expected-note {{because type 'U2::<anonymous struct}}
+ Dtor dtor; // expected-note {{because field of type 'Dtor' has a user-provided destructor}}
} m6; // expected-error {{union member 'm6' has a non-trivial destructor}}
struct {
Okay okay;
@@ -75,22 +75,25 @@ union U2 {
};
union U3 {
- struct s1 : Virtual { // expected-note {{because type 'U3::s1' has a base class with a non-trivial copy constructor}}
+ struct s1 : Virtual { // expected-note {{because the function selected to copy base class of type 'Virtual' is not trivial}}
} m1; // expected-error {{union member 'm1' has a non-trivial copy constructor}}
- struct s2 : VirtualBase { // expected-note {{because type 'U3::s2' has a base class with a non-trivial copy constructor}}
+ struct s2 : VirtualBase { // expected-note {{because the function selected to copy base class of type 'VirtualBase' is not trivial}}
} m2; // expected-error {{union member 'm2' has a non-trivial copy constructor}}
- struct s3 : Ctor { // expected-note {{because type 'U3::s3' has a base class with a non-trivial constructor}}
+ struct s3 : Ctor { // expected-note {{because base class of type 'Ctor' has a user-provided default constructor}}
} m3; // expected-error {{union member 'm3' has a non-trivial constructor}}
- struct s3a : Ctor2 { // expected-note {{because type 'U3::s3a' has a base class with a non-trivial constructor}}
+ struct s3a : Ctor2 { // expected-note {{because base class of type 'Ctor2' has a user-provided default constructor}}
} m3a; // expected-error {{union member 'm3a' has a non-trivial constructor}}
- struct s4 : CopyCtor { // expected-note {{because type 'U3::s4' has a base class with a non-trivial copy constructor}}
+ struct s4 : CopyCtor { // expected-note {{because no constructor can be used to copy an object of type 'const U3::s4'}}
} m4; // expected-error {{union member 'm4' has a non-trivial copy constructor}}
- struct s5 : CopyAssign { // expected-note {{because type 'U3::s5' has a base class with a non-trivial copy assignment operator}}
+ struct s5 : CopyAssign { // expected-note {{because no assignment operator can be used to copy an object of type 'const U3::s5'}}
} m5; // expected-error {{union member 'm5' has a non-trivial copy assignment operator}}
- struct s6 : Dtor { // expected-note {{because type 'U3::s6' has a base class with a non-trivial destructor}}
+ struct s6 : Dtor { // expected-note {{because base class of type 'Dtor' has a user-provided destructor}}
} m6; // expected-error {{union member 'm6' has a non-trivial destructor}}
struct s7 : Okay {
} m7;
+ struct s8 {
+ s8(...) = delete; // expected-note {{because it is a variadic function}} expected-warning {{C++11}}
+ } m8; // expected-error {{union member 'm8' has a non-trivial constructor}}
};
union U4 {
@@ -102,6 +105,12 @@ union U5 {
int& i1; // expected-error {{union member 'i1' has reference type 'int &'}}
};
+union U6 {
+ struct S {
+ int &i;
+ } s; // ok
+};
+
template <class A, class B> struct Either {
bool tag;
union { // expected-note 6 {{in instantiation of member class}}
diff --git a/test/CXX/class/class.union/p2-0x.cpp b/test/CXX/class/class.union/p2-0x.cpp
index b5c4109..5fb8a67 100644
--- a/test/CXX/class/class.union/p2-0x.cpp
+++ b/test/CXX/class/class.union/p2-0x.cpp
@@ -7,7 +7,7 @@ union U1 {
static const int k2 = k1;
static int k3 = k2; // expected-error {{non-const static data member must be initialized out of line}}
static constexpr double k4 = k2;
- static const double k5 = k4; // expected-warning {{GNU extension}} expected-note {{use 'constexpr'}}
+ static const double k5 = k4; // expected-error {{requires 'constexpr' specifier}} expected-note {{add 'constexpr'}}
int n[k1 + 3];
};
diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp
index 069ca0a..11372dd 100644
--- a/test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.memdef/p3.cpp
@@ -91,3 +91,104 @@ namespace test5 {
template void f<int>(int);
template void f<long>(long); //expected-note {{instantiation}}
}
+
+// rdar://13393749
+namespace test6 {
+ class A;
+ namespace ns {
+ class B {
+ static void foo(); // expected-note {{implicitly declared private here}}
+ friend union A;
+ };
+
+ union A {
+ void test() {
+ B::foo();
+ }
+ };
+ }
+
+ class A {
+ void test() {
+ ns::B::foo(); // expected-error {{'foo' is a private member of 'test6::ns::B'}}
+ }
+ };
+}
+
+// We seem to be following a correct interpretation with these, but
+// the standard could probably be a bit clearer.
+namespace test7a {
+ namespace ns {
+ class A;
+ }
+
+ using namespace ns;
+ class B {
+ static void foo();
+ friend class A;
+ };
+
+ class ns::A {
+ void test() {
+ B::foo();
+ }
+ };
+}
+namespace test7b {
+ namespace ns {
+ class A;
+ }
+
+ using ns::A;
+ class B {
+ static void foo();
+ friend class A;
+ };
+
+ class ns::A {
+ void test() {
+ B::foo();
+ }
+ };
+}
+namespace test7c {
+ namespace ns1 {
+ class A;
+ }
+
+ namespace ns2 {
+ // ns1::A appears as if declared in test7c according to [namespace.udir]p2.
+ // I think that means we aren't supposed to find it.
+ using namespace ns1;
+ class B {
+ static void foo(); // expected-note {{implicitly declared private here}}
+ friend class A;
+ };
+ }
+
+ class ns1::A {
+ void test() {
+ ns2::B::foo(); // expected-error {{'foo' is a private member of 'test7c::ns2::B'}}
+ }
+ };
+}
+namespace test7d {
+ namespace ns1 {
+ class A;
+ }
+
+ namespace ns2 {
+ // Honor the lexical context of a using-declaration, though.
+ using ns1::A;
+ class B {
+ static void foo();
+ friend class A;
+ };
+ }
+
+ class ns1::A {
+ void test() {
+ ns2::B::foo();
+ }
+ };
+}
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 ae40062..a38ff15 100644
--- a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p10.cpp
+++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p10.cpp
@@ -33,3 +33,12 @@ namespace test1 {
}
}
+// PR 14768
+namespace PR14768 {
+ template<typename eT> class Mat;
+ template<typename eT> class Col : public Mat<eT> {
+ using Mat<eT>::operator();
+ using Col<eT>::operator();
+ void operator() ();
+ };
+}
diff --git a/test/CXX/dcl.dcl/dcl.attr/dcl.align/p5.cpp b/test/CXX/dcl.dcl/dcl.attr/dcl.align/p5.cpp
new file mode 100644
index 0000000..10be98d
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.attr/dcl.align/p5.cpp
@@ -0,0 +1,74 @@
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -verify %s
+
+alignas(1) int n1; // expected-error {{requested alignment is less than minimum alignment of 4 for type 'int'}}
+alignas(1) alignas(2) int n2; // expected-error {{less than minimum alignment}}
+alignas(1) alignas(2) alignas(4) int n3; // ok
+alignas(1) alignas(2) alignas(0) int n4; // expected-error {{less than minimum alignment}}
+alignas(1) alignas(2) int n5 alignas(4); // ok
+alignas(1) alignas(4) int n6 alignas(2); // ok
+alignas(1) int n7 alignas(2), // expected-error {{less than minimum alignment}}
+ n8 alignas(4); // ok
+alignas(8) int n9 alignas(2); // ok, overaligned
+
+enum alignas(1) E1 {}; // expected-error {{requested alignment is less than minimum alignment of 4 for type 'E1'}}
+enum alignas(1) E2 : char {}; // ok
+enum alignas(4) E3 { e3 = 0 }; // ok
+enum alignas(4) E4 { e4 = 1ull << 33 }; // expected-error {{requested alignment is less than minimum alignment of 8 for type 'E4'}}
+
+struct S1 {
+ alignas(8) int n;
+};
+struct alignas(2) S2 { // expected-error {{requested alignment is less than minimum alignment of 4 for type 'S2'}}
+ int n;
+};
+struct alignas(2) S3 { // expected-error {{requested alignment is less than minimum alignment of 8 for type 'S3'}}
+ S1 s1;
+};
+struct alignas(2) S4 : S1 { // expected-error {{requested alignment is less than minimum alignment of 8 for type 'S4'}}
+};
+struct S5 : S1 {
+ alignas(2) S1 s1; // expected-error {{requested alignment is less than minimum alignment of 8 for type 'S1'}}
+};
+struct S6 {
+ S1 s1;
+};
+struct S7 : S1 {
+};
+struct alignas(2) alignas(8) alignas(1) S8 : S1 {
+};
+
+S1 s1 alignas(4); // expected-error {{requested alignment is less than minimum alignment of 8 for type 'S1'}}
+S6 s6 alignas(4); // expected-error {{requested alignment is less than minimum alignment of 8 for type 'S6'}}
+S7 s7 alignas(4); // expected-error {{requested alignment is less than minimum alignment of 8 for type 'S7'}}
+
+template<int N, int M, typename T>
+struct alignas(N) X { // expected-error 3{{requested alignment is less than minimum}}
+ alignas(M) T t; // expected-error 3{{requested alignment is less than minimum}}
+};
+
+template struct X<1, 1, char>;
+template struct X<4, 1, char>;
+template struct X<1, 2, char>; // expected-note {{instantiation}}
+template struct X<1, 1, short>; // expected-note {{instantiation}}
+template struct X<2, 1, short>; // expected-note {{instantiation}}
+template struct X<2, 2, short>;
+template struct X<16, 8, S1>;
+template struct X<4, 4, S1>; // expected-note {{instantiation}}
+
+template<int N, typename T>
+struct Y {
+ enum alignas(N) E : T {}; // expected-error {{requested alignment is less than minimum}}
+};
+template struct Y<1, char>;
+template struct Y<2, char>;
+template struct Y<1, short>; // expected-note {{instantiation}}
+template struct Y<2, short>;
+
+template<int N, typename T>
+void f() {
+ alignas(N) T v; // expected-error {{requested alignment is less than minimum}}
+};
+template void f<1, char>();
+template void f<2, char>();
+template void f<1, short>(); // expected-note {{instantiation}}
+template void f<2, short>();
diff --git a/test/CXX/dcl.dcl/dcl.attr/dcl.align/p6.cpp b/test/CXX/dcl.dcl/dcl.attr/dcl.align/p6.cpp
new file mode 100644
index 0000000..e788577
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.attr/dcl.align/p6.cpp
@@ -0,0 +1,86 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+alignas(4) extern int n1; // expected-note {{previous declaration}}
+alignas(8) int n1; // expected-error {{redeclaration has different alignment requirement (8 vs 4)}}
+
+alignas(8) int n2; // expected-note {{previous declaration}}
+alignas(4) extern int n2; // expected-error {{different alignment requirement (4 vs 8)}}
+
+alignas(8) extern int n3; // expected-note {{previous declaration}}
+alignas(4) extern int n3; // expected-error {{different alignment requirement (4 vs 8)}}
+
+extern int n4;
+alignas(8) extern int n4;
+
+alignas(8) extern int n5;
+extern int n5;
+
+int n6; // expected-error {{'alignas' must be specified on definition if it is specified on any declaration}}
+alignas(8) extern int n6; // expected-note {{declared with 'alignas' attribute here}}
+
+extern int n7;
+alignas(8) int n7;
+
+alignas(8) extern int n8; // expected-note {{declared with 'alignas' attribute here}}
+int n8; // expected-error {{'alignas' must be specified on definition if it is specified on any declaration}}
+
+int n9; // expected-error {{'alignas' must be specified on definition if it is specified on any declaration}}
+alignas(4) extern int n9; // expected-note {{declared with 'alignas' attribute here}}
+
+
+enum alignas(2) E : char; // expected-note {{declared with 'alignas' attribute here}}
+enum E : char {}; // expected-error {{'alignas' must be specified on definition if it is specified on any declaration}}
+
+enum alignas(4) F : char; // expected-note {{previous declaration is here}}
+enum alignas(2) F : char; // expected-error {{redeclaration has different alignment requirement (2 vs 4)}}
+
+enum G : char;
+enum alignas(8) G : char {};
+enum G : char;
+
+enum H : char {}; // expected-error {{'alignas' must be specified on definition if it is specified on any declaration}}
+enum alignas(1) H : char; // expected-note {{declared with 'alignas' attribute here}}
+
+
+struct S;
+struct alignas(16) S; // expected-note {{declared with 'alignas' attribute here}}
+struct S;
+struct S { int n; }; // expected-error {{'alignas' must be specified on definition if it is specified on any declaration}}
+
+struct alignas(2) T;
+struct alignas(2) T { char c; }; // expected-note {{previous declaration is here}}
+struct T;
+struct alignas(4) T; // expected-error {{redeclaration has different alignment requirement (4 vs 2)}}
+
+struct U;
+struct alignas(2) U {};
+
+struct V {}; // expected-error {{'alignas' must be specified on definition if it is specified on any declaration}}
+struct alignas(1) V; // expected-note {{declared with 'alignas' attribute here}}
+
+template<int M, int N> struct alignas(M) W;
+template<int M, int N> struct alignas(N) W {};
+W<4,4> w44; // ok
+// FIXME: We should reject this.
+W<1,2> w12;
+static_assert(alignof(W<4,4>) == 4, "");
+
+template<int M, int N, int O, int P> struct X {
+ alignas(M) alignas(N) static char Buffer[32]; // expected-note {{previous declaration is here}}
+};
+template<int M, int N, int O, int P>
+alignas(O) alignas(P) char X<M, N, O, P>::Buffer[32]; // expected-error {{redeclaration has different alignment requirement (8 vs 2)}}
+char *x1848 = X<1,8,4,8>::Buffer; // ok
+char *x1248 = X<1,2,4,8>::Buffer; // expected-note {{in instantiation of}}
+
+template<int M, int N, int O, int P> struct Y {
+ enum alignas(M) alignas(N) E : char;
+};
+template<int M, int N, int O, int P>
+enum alignas(O) alignas(P) Y<M,N,O,P>::E : char { e };
+int y1848 = Y<1,8,4,8>::e;
+// FIXME: We should reject this.
+int y1248 = Y<1,2,4,8>::e;
+
+// Don't crash here.
+alignas(4) struct Incomplete incomplete; // expected-error {{incomplete type}} expected-note {{forward declaration}}
diff --git a/test/CXX/dcl.dcl/dcl.attr/dcl.align/p7.cpp b/test/CXX/dcl.dcl/dcl.attr/dcl.align/p7.cpp
new file mode 100644
index 0000000..93b1c64
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.attr/dcl.align/p7.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+template<typename T, typename A, int N> struct X {
+ alignas(T) alignas(A) T buffer[N];
+};
+
+static_assert(alignof(X<char, int, sizeof(int)>) == alignof(int), "");
+static_assert(alignof(X<int, char, 1>) == alignof(int), "");
+
+
+template<typename T, typename A, int N> struct Y {
+ alignas(A) T buffer[N]; // expected-error {{requested alignment is less than minimum alignment of 4 for type 'int [1]'}}
+};
+
+static_assert(alignof(Y<char, int, sizeof(int)>) == alignof(int), "");
+static_assert(alignof(Y<int, char, 1>) == alignof(int), ""); // expected-note {{in instantiation of}}
diff --git a/test/CXX/dcl.dcl/dcl.attr/dcl.align/p8.cpp b/test/CXX/dcl.dcl/dcl.attr/dcl.align/p8.cpp
new file mode 100644
index 0000000..686aac2
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.attr/dcl.align/p8.cpp
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+alignas(double) void f(); // expected-error {{'alignas' attribute only applies to variables, data members and tag types}}
+alignas(double) unsigned char c[sizeof(double)]; // expected-note {{previous}}
+extern unsigned char c[sizeof(double)];
+alignas(float) extern unsigned char c[sizeof(double)]; // expected-error {{different alignment}}
diff --git a/test/CXX/dcl.dcl/dcl.attr/dcl.attr.depend/p1.cpp b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.depend/p1.cpp
new file mode 100644
index 0000000..9f7ef3a
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.depend/p1.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -verify -std=c++11 %s
+
+[[carries_dependency, carries_dependency]] int m1(); // expected-error {{attribute 'carries_dependency' cannot appear multiple times in an attribute specifier}}
+[[carries_dependency]] [[carries_dependency]] int m2(); // ok
+[[carries_dependency()]] int m3(); // expected-error {{attribute 'carries_dependency' cannot have an argument list}}
+
+[[carries_dependency]] void f1(); // FIXME: warn here
+[[carries_dependency]] int f2(); // ok
+int f3(int param [[carries_dependency]]); // ok
+[[carries_dependency]] int (*f4)(); // expected-error {{'carries_dependency' attribute only applies to functions, methods, and parameters}}
+int (*f5 [[carries_dependency]])(); // expected-error {{'carries_dependency' attribute only applies to functions, methods, and parameters}}
+int (*f6)() [[carries_dependency]]; // expected-error {{'carries_dependency' attribute cannot be applied to types}}
+int (*f7)(int n [[carries_dependency]]); // expected-error {{'[[carries_dependency]]' attribute only allowed on parameter in a function declaration}}
+int (((f8)))(int n [[carries_dependency]]); // ok
+int (*f9(int n))(int n [[carries_dependency]]); // expected-error {{'[[carries_dependency]]' attribute only allowed on parameter in a function declaration}}
+int typedef f10(int n [[carries_dependency]]); // expected-error {{'[[carries_dependency]]' attribute only allowed on parameter in a function declaration}}
+using T = int(int n [[carries_dependency]]); // expected-error {{'[[carries_dependency]]' attribute only allowed on parameter in a function declaration}}
+struct S {
+ [[carries_dependency]] int f(int n [[carries_dependency]]); // ok
+ int (*p)(int n [[carries_dependency]]); // expected-error {{'[[carries_dependency]]' attribute only allowed on parameter in a function declaration}}
+};
+void f() {
+ [[carries_dependency]] int f(int n [[carries_dependency]]); // ok
+ [[carries_dependency]] // expected-error {{'carries_dependency' attribute only applies to functions, methods, and parameters}}
+ int (*p)(int n [[carries_dependency]]); // expected-error {{'[[carries_dependency]]' attribute only allowed on parameter in a function declaration}}
+}
+
+auto l1 = [](int n [[carries_dependency]]) {};
+// There's no way to write a lambda such that the return value carries
+// a dependency, because an attribute applied to the lambda appertains to
+// the *type* of the operator() function, not to the function itself.
+auto l2 = []() [[carries_dependency]] {}; // expected-error {{'carries_dependency' attribute cannot be applied to types}}
diff --git a/test/CXX/dcl.dcl/dcl.attr/dcl.attr.depend/p2.cpp b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.depend/p2.cpp
new file mode 100644
index 0000000..d5b0ebf
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.depend/p2.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -verify -std=c++11 %s
+
+int f(int); // expected-note 2{{declaration missing '[[carries_dependency]]' attribute is here}}
+[[carries_dependency]] int f(int); // expected-error {{function declared '[[carries_dependency]]' after its first declaration}}
+int f(int n [[carries_dependency]]); // expected-error {{parameter declared '[[carries_dependency]]' after its first declaration}}
+
+int g([[carries_dependency]] int n); // expected-note {{declaration missing '[[carries_dependency]]' attribute is here}}
+int g(int);
+[[carries_dependency]] int g(int); // expected-error {{function declared '[[carries_dependency]]' after its first declaration}}
+int g(int n [[carries_dependency]]);
+
+int h [[carries_dependency]]();
+int h();
+[[carries_dependency]] int h();
diff --git a/test/CXX/dcl.dcl/dcl.attr/dcl.attr.noreturn/p1.cpp b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.noreturn/p1.cpp
new file mode 100644
index 0000000..0af241f
--- /dev/null
+++ b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.noreturn/p1.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -std=c++11 -verify -fcxx-exceptions %s
+
+[[noreturn]] void a() {
+ return; // expected-warning {{function 'a' declared 'noreturn' should not return}}
+}
+void a2 [[noreturn]] () {
+ return; // expected-warning {{function 'a2' declared 'noreturn' should not return}}
+}
+
+[[noreturn, noreturn]] void b() { throw 0; } // expected-error {{attribute 'noreturn' cannot appear multiple times in an attribute specifier}}
+[[noreturn]] [[noreturn]] void b2() { throw 0; } // ok
+
+[[noreturn()]] void c(); // expected-error {{attribute 'noreturn' cannot have an argument list}}
+
+void d() [[noreturn]]; // expected-error {{'noreturn' attribute cannot be applied to types}}
+int d2 [[noreturn]]; // expected-error {{'noreturn' attribute only applies to functions and methods}}
+
+[[noreturn]] int e() { b2(); } // ok
+
+int f(); // expected-note {{declaration missing '[[noreturn]]' attribute is here}}
+[[noreturn]] int f(); // expected-error {{function declared '[[noreturn]]' after its first declaration}}
+int f();
+
+[[noreturn]] int g();
+int g() { while (true) b(); } // ok
+[[noreturn]] int g();
+
+[[gnu::noreturn]] int h();
+
+template<typename T> void test_type(T) { T::error; } // expected-error {{has no members}}
+template<> void test_type(int (*)()) {}
+
+void check() {
+ // We do not consider [[noreturn]] to be part of the function's type.
+ // However, we do treat [[gnu::noreturn]] as being part of the type.
+ //
+ // This isn't quite GCC-compatible; it treats [[gnu::noreturn]] as
+ // being part of a function *pointer* type, but not being part of
+ // a function type.
+ test_type(e);
+ test_type(f);
+ test_type(g);
+ test_type(h); // expected-note {{instantiation}}
+}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
index 6820fc6..a3a964a 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
@@ -25,8 +25,9 @@ constexpr notlit nl1; // expected-error {{constexpr variable cannot have non-lit
void f2(constexpr int i) {} // expected-error {{function parameter cannot be constexpr}}
// non-static member
struct s2 {
- constexpr int mi1; // expected-error {{non-static data member cannot be constexpr}}
+ constexpr int mi1; // expected-error {{non-static data member cannot be constexpr; did you intend to make it const?}}
static constexpr int mi2; // expected-error {{requires an initializer}}
+ mutable constexpr int mi3 = 3; // expected-error-re {{non-static data member cannot be constexpr$}} expected-error {{'mutable' and 'const' cannot be mixed}}
};
// typedef
typedef constexpr int CI; // expected-error {{typedef cannot be constexpr}}
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
index dfc1d3d..ad156c8 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
@@ -272,9 +272,8 @@ namespace CtorLookup {
struct A {
constexpr A(const A&) {}
A(A&) {}
- constexpr A(int); // expected-note {{previous}}
+ constexpr A(int = 0);
};
- constexpr A::A(int = 0) {} // expected-warning {{default constructor}}
struct B : A {
B() = default;
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 3c1152c..bca73ee 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 -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
+// RUN: %clang_cc1 -fsyntax-only -triple x86_64-unknown-unknown -std=c++11 -fcxx-exceptions -Wno-invalid-constexpr %s -DNO_INVALID_CONSTEXPR
namespace StdExample {
@@ -110,3 +110,23 @@ int y1 = Y<int>().get(); // ok
int y2 = Y<Z>().get(); // ok
}
+
+#ifndef NO_INVALID_CONSTEXPR
+namespace PR14550 {
+ // As an "extension", we allow functions which can't produce constant
+ // expressions to be declared constexpr in system headers (libstdc++
+ // marks some functions as constexpr which use builtins which we don't
+ // support constant folding). Ensure that we don't mark those functions
+ // as invalid after suppressing the diagnostic.
+# 122 "p5.cpp" 1 3
+ int n;
+ struct A {
+ static constexpr int f() { return n; }
+ };
+ template<typename T> struct B {
+ B() { g(T::f()); } // expected-error {{undeclared identifier 'g'}}
+ };
+# 130 "p5.cpp" 2
+ template class B<A>; // expected-note {{here}}
+}
+#endif
diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp
index c4935b3..344f8ce 100644
--- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp
+++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p8.cpp
@@ -1,19 +1,39 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+using size_t = decltype(sizeof(int));
+
struct S {
constexpr int f();
constexpr int g() const;
+ constexpr int h();
+ int h();
static constexpr int Sf();
+ /*static*/ constexpr void *operator new(size_t) noexcept;
+ template<typename T> constexpr T tm();
+ template<typename T> static constexpr T ts();
};
void f(const S &s) {
s.f();
s.g();
- int (*f)() = &S::Sf;
+ int (*Sf)() = &S::Sf;
+ int (S::*f)() const = &S::f;
int (S::*g)() const = &S::g;
+ void *(*opNew)(size_t) = &S::operator new;
+ int (S::*tm)() const = &S::tm;
+ int (*ts)() = &S::ts;
}
+constexpr int S::f() const { return 0; }
+constexpr int S::g() { return 1; }
+constexpr int S::h() { return 0; }
+int S::h() { return 0; }
+constexpr int S::Sf() { return 2; }
+constexpr void *S::operator new(size_t) noexcept { return 0; }
+template<typename T> constexpr T S::tm() { return T(); }
+template<typename T> constexpr T S::ts() { return T(); }
+
namespace std_example {
class debug_flag { // expected-note {{not an aggregate and has no constexpr constructors}}
diff --git a/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p1.cpp b/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p1.cpp
new file mode 100644
index 0000000..5199330
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.fct.def/dcl.fct.def.default/p1.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -verify %s -std=c++11
+
+// A function that is explicitly defaulted shall
+struct A {
+ // -- be a special member function,
+ A(int) = default; // expected-error {{only special member functions may be defaulted}}
+
+ // -- have the same declared function type as if it had been implicitly
+ // declared
+ void operator=(const A &) = default; // expected-error {{must return 'A &'}}
+ A(...) = default; // expected-error {{cannot be variadic}}
+ A(const A &, ...) = default; // expected-error {{cannot be variadic}}
+
+ // (except for possibly differing ref-qualifiers
+ A &operator=(A &&) & = default;
+
+ // and except that in the case of a copy constructor or copy assignment
+ // operator, the parameter type may be "reference to non-const T")
+ A(A &) = default;
+ A &operator=(A &) = default;
+
+ // -- not have default arguments
+ A(double = 0.0) = default; // expected-error {{cannot have default arguments}}
+ A(const A & = 0) = default; // expected-error {{cannot have default arguments}}
+};
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp
index 3450003..d61f6e3 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.list/p3-0x.cpp
@@ -21,7 +21,7 @@ namespace std {
};
}
-namespace bullet2 {
+namespace bullet1 {
double ad[] = { 1, 2.0 };
int ai[] = { 1, 2.0 }; // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{override}}
@@ -62,12 +62,16 @@ namespace bullet4_example3 {
};
S s1 = { 1, 2, 3.0 };
- // FIXME: This is an ill-formed narrowing initialization.
- S s2 { 1.0, 2, 3 };
+ S s2 { 1.0, 2, 3 }; // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{override}}
S s3 {};
}
namespace bullet5 {
+ int x1 {2};
+ int x2 {2.0}; // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{override}}
+}
+
+namespace bullet6 {
struct S {
S(std::initializer_list<double>) {}
S(const std::string &) {}
@@ -75,17 +79,12 @@ namespace bullet5 {
const S& r1 = { 1, 2, 3.0 };
const S& r2 = { "Spinach" };
- S& r3 = { 1, 2, 3 }; // expected-error {{non-const lvalue reference to type 'bullet5::S' cannot bind to an initializer list temporary}}
+ S& r3 = { 1, 2, 3 }; // expected-error {{non-const lvalue reference to type 'bullet6::S' cannot bind to an initializer list temporary}}
const int& i1 = { 1 };
const int& i2 = { 1.1 }; // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{override}} expected-warning {{implicit conversion}}
const int (&iar)[2] = { 1, 2 };
}
-namespace bullet6 {
- int x1 {2};
- int x2 {2.0}; // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{override}}
-}
-
namespace bullet7 {
int** pp {};
}
@@ -99,15 +98,25 @@ namespace bullet8 {
B(std::initializer_list<int> i) {}
};
B b1 { 1, 2 };
- B b2 { 1, 2.0 };
+ B b2 { 1, 2.0 }; // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{override}}
struct C {
C(int i, double j) {}
};
C c1 = { 1, 2.2 };
- // FIXME: This is an ill-formed narrowing initialization.
- C c2 = { 1.1, 2 }; // expected-warning {{implicit conversion}}
+ // FIXME: Suppress the narrowing warning in the cases where we issue a narrowing error.
+ C c2 = { 1.1, 2 }; // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{override}} expected-warning {{implicit conversion}}
int j { 1 };
int k { };
}
+
+namespace rdar13395022 {
+ struct MoveOnly {
+ MoveOnly(MoveOnly&&); // expected-note{{copy constructor is implicitly deleted because 'MoveOnly' has a user-declared move constructor}}
+ };
+
+ void test(MoveOnly mo) {
+ auto &&list = {mo}; // expected-error{{call to implicitly-deleted copy constructor of 'rdar13395022::MoveOnly'}}
+ }
+}
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp
index adbdff6..812d0de 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-0x.cpp
@@ -192,3 +192,11 @@ namespace PR11003 {
Value y(Move(0));
}
}
+
+namespace rdar13278115 {
+ struct X { };
+ struct Y : X { };
+ X &&f0(X &x) { return x; } // expected-error{{rvalue reference to type 'rdar13278115::X' cannot bind to lvalue of type 'rdar13278115::X'}}
+ X &&f1(Y &y) { return y; } // expected-error{{rvalue reference to type 'rdar13278115::X' cannot bind to lvalue of type 'rdar13278115::Y'}}
+ const X &&f2(Y &y) { return y; } // expected-error{{rvalue reference to type 'const rdar13278115::X' cannot bind to lvalue of type 'rdar13278115::Y'}}
+}
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp
index 08d9639..be1113d 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-examples.cpp
@@ -3,10 +3,10 @@
// CHECK: example0
void example0() {
double d = 2.0;
- // CHECK: double &rd =
+ // CHECK: VarDecl{{.*}}rd 'double &'
// CHECK-NEXT: DeclRefExpr
double &rd = d;
- // CHECK: const double &rcd =
+ // CHECK: VarDecl{{.*}}rcd 'const double &'
// CHECK-NEXT: ImplicitCastExpr{{.*}}'const double' lvalue <NoOp>
const double &rcd = d;
}
@@ -16,10 +16,10 @@ struct B : A { } b;
// CHECK: example1
void example1() {
- // CHECK: A &ra =
+ // CHECK: VarDecl{{.*}}ra 'struct A &'
// CHECK: ImplicitCastExpr{{.*}}'struct A' lvalue <DerivedToBase (A)>
A &ra = b;
- // CHECK: const A &rca =
+ // CHECK: VarDecl{{.*}}rca 'const struct A &'
// CHECK: ImplicitCastExpr{{.*}}'const struct A' lvalue <NoOp>
// CHECK: ImplicitCastExpr{{.*}}'struct A' lvalue <DerivedToBase (A)>
const A& rca = b;
@@ -33,12 +33,12 @@ struct X {
// CHECK: example2
void example2() {
- // CHECK: const A &rca =
+ // CHECK: VarDecl{{.*}}rca 'const struct A &'
// CHECK: ImplicitCastExpr{{.*}}'const struct A' <NoOp>
// CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase (A)>
// CHECK: CallExpr{{.*}}B
const A &rca = f();
- // CHECK: const A &r =
+ // CHECK: VarDecl{{.*}}r 'const struct A &'
// CHECK: ImplicitCastExpr{{.*}}'const struct A' <NoOp>
// CHECK: ImplicitCastExpr{{.*}}'struct A' <DerivedToBase (A)>
// CHECK: CXXMemberCallExpr{{.*}}'struct B'
@@ -47,7 +47,7 @@ void example2() {
// CHECK: example3
void example3() {
- // CHECK: const double &rcd2 =
+ // CHECK: VarDecl{{.*}}rcd2 'const double &'
// CHECK: ImplicitCastExpr{{.*}} <IntegralToFloating>
const double& rcd2 = 2;
}
diff --git a/test/CXX/dcl.decl/dcl.init/p5.cpp b/test/CXX/dcl.decl/dcl.init/p5.cpp
index b50e8d7..e7ccb2e 100644
--- a/test/CXX/dcl.decl/dcl.init/p5.cpp
+++ b/test/CXX/dcl.decl/dcl.init/p5.cpp
@@ -1,20 +1,48 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-// FIXME: Very incomplete!
-
// A program that calls for default-initialization or value-initialization of
// an entity of reference type is illformed. If T is a cv-qualified type, the
// cv-unqualified version of T is used for these definitions of
// zero-initialization, default-initialization, and value-initialization.
-//
-// FIXME: The diagnostics for these errors are terrible because they fall out
-// of the AST representation rather than being explicitly issued during the
-// respective initialization forms.
-struct S { // expected-error {{implicit default constructor for 'S' must explicitly initialize the reference member}} \
- // expected-note {{candidate constructor (the implicit copy constructor) not viable}}
- int& x; // expected-note {{declared here}}
+
+struct S { // expected-error {{implicit default constructor for 'S' must explicitly initialize the reference member}}
+ int &x; // expected-note {{declared here}} expected-error 3{{reference to type 'int' requires an initializer}}
};
S s; // expected-note {{implicit default constructor for 'S' first required here}}
S f() {
- return S(); // expected-error {{no matching constructor for initialization of 'S'}}
+ return S(); // expected-note {{in value-initialization of type 'S' here}}
}
+
+struct T
+ : S { // expected-note 2{{in value-initialization of type 'S' here}}
+};
+T t = T(); // expected-note {{in value-initialization of type 'T' here}}
+
+struct U {
+ T t[3]; // expected-note {{in value-initialization of type 'T' here}}
+};
+U u = U(); // expected-note {{in value-initialization of type 'U' here}}
+
+// Ensure that we handle C++11 in-class initializers properly as an extension.
+// In this case, there is no user-declared default constructor, so we
+// recursively apply the value-initialization checks, but we will emit a
+// constructor call anyway, because the default constructor is not trivial.
+struct V {
+ int n;
+ int &r = n; // expected-warning {{C++11}}
+};
+V v = V(); // ok
+struct W {
+ int n;
+ S s = { n }; // expected-warning {{C++11}}
+};
+W w = W(); // ok
+
+// Ensure we're not faking this up by making the default constructor
+// non-trivial.
+#define static_assert(B, S) typedef int assert_failed[(B) ? 1 : -1];
+static_assert(__has_trivial_constructor(S), "");
+static_assert(__has_trivial_constructor(T), "");
+static_assert(__has_trivial_constructor(U), "");
+static_assert(!__has_trivial_constructor(V), "");
+static_assert(!__has_trivial_constructor(W), "");
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 5467a92..e03c216 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,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
void nondecl(int (*f)(int x = 5)) // expected-error {{default arguments can only be specified}}
{
@@ -8,6 +8,9 @@ void nondecl(int (*f)(int x = 5)) // expected-error {{default arguments can only
struct X0 {
int (*f)(int = 17); // expected-error{{default arguments can only be specified for parameters in a function declaration}}
+ void (*g())(int = 22); // expected-error{{default arguments can only be specified for parameters in a function declaration}}
+ void (*h(int = 49))(int);
+ auto i(int) -> void (*)(int = 9); // expected-error{{default arguments can only be specified for parameters in a function declaration}}
void mem8(int (*fp)(int) = (int (*)(int = 17))0); // expected-error{{default arguments can only be specified for parameters in a function declaration}}
};
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p2.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p2.cpp
index 9b5ef78..4227d82 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p2.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p2.cpp
@@ -38,8 +38,8 @@ namespace copy {
};
struct NonConst {
- NonConst(NonConst&) = default; // expected-error {{must be defaulted outside the class}}
- NonConst& operator=(NonConst&) = default; // expected-error {{must be defaulted outside the class}}
+ NonConst(NonConst&) = default;
+ NonConst& operator=(NonConst&) = default;
};
struct NonConst2 {
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p8.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p8.cpp
index 34a8c85..ec1ccbf 100644
--- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p8.cpp
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p8.cpp
@@ -1,10 +1,8 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
struct A { };
-A::A (enum { e1 }) {} // expected-error{{can not be defined in a parameter}} \
-// expected-error{{out-of-line definition}}
-void A::f(enum { e2 }) {} // expected-error{{can not be defined in a parameter}} \
-// expected-error{{out-of-line definition}}
+A::A (enum { e1 }) {} // expected-error{{can not be defined in a parameter}}
+void A::f(enum { e2 }) {} // expected-error{{can not be defined in a parameter}}
enum { e3 } A::g() { } // expected-error{{can not be defined in the result type}} \
// expected-error{{out-of-line definition}}
diff --git a/test/CXX/except/except.spec/p14-ir.cpp b/test/CXX/except/except.spec/p14-ir.cpp
index 81fbf7d..9b41f3d 100644
--- a/test/CXX/except/except.spec/p14-ir.cpp
+++ b/test/CXX/except/except.spec/p14-ir.cpp
@@ -27,12 +27,12 @@ struct X5 : X0, X4 { };
void test(X2 x2, X3 x3, X5 x5) {
// CHECK: define linkonce_odr void @_ZN2X2C1ERKS_(%struct.X2* %this, %struct.X2*) unnamed_addr
- // CHECK: call void @_ZN2X2C2ERKS_({{.*}}) nounwind
+ // CHECK: call void @_ZN2X2C2ERKS_({{.*}}) [[NUW:#[0-9]+]]
// CHECK-NEXT: ret void
// CHECK-NEXT: }
X2 x2a(x2);
// CHECK: define linkonce_odr void @_ZN2X3C1ERKS_(%struct.X3* %this, %struct.X3*) unnamed_addr
- // CHECK: call void @_ZN2X3C2ERKS_({{.*}}) nounwind
+ // CHECK: call void @_ZN2X3C2ERKS_({{.*}}) [[NUW]]
// CHECK-NEXT: ret void
// CHECK-NEXT: }
X3 x3a(x3);
@@ -56,7 +56,7 @@ struct X9 : X6, X7 { };
void test() {
// CHECK: define linkonce_odr void @_ZN2X8C1Ev(%struct.X8* %this) unnamed_addr
- // CHECK: call void @_ZN2X8C2Ev({{.*}}) nounwind
+ // CHECK: call void @_ZN2X8C2Ev({{.*}}) [[NUW]]
// CHECK-NEXT: ret void
X8();
@@ -67,13 +67,15 @@ void test() {
X9();
// CHECK: define linkonce_odr void @_ZN2X9C2Ev(%struct.X9* %this) unnamed_addr
- // CHECK: call void @_ZN2X6C2Ev({{.*}}) nounwind
+ // CHECK: call void @_ZN2X6C2Ev({{.*}}) [[NUW]]
// FIXME: and here:
// CHECK-NEXT: bitcast
// CHECK-NEXT: call void @_ZN2X7C2Ev({{.*}})
// CHECK: ret void
// CHECK: define linkonce_odr void @_ZN2X8C2Ev(%struct.X8* %this) unnamed_addr
- // CHECK: call void @_ZN2X6C2Ev({{.*}}) nounwind
+ // CHECK: call void @_ZN2X6C2Ev({{.*}}) [[NUW]]
// CHECK-NEXT: ret void
}
+
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CXX/except/except.spec/p14.cpp b/test/CXX/except/except.spec/p14.cpp
index ff21ab8..99ed2fd 100644
--- a/test/CXX/except/except.spec/p14.cpp
+++ b/test/CXX/except/except.spec/p14.cpp
@@ -101,3 +101,14 @@ namespace PR14141 {
~Derived3() noexcept(true) = default; // expected-error {{does not match the calculated}}
};
}
+
+namespace rdar13017229 {
+ struct Base {
+ virtual ~Base() {}
+ };
+
+ struct Derived : Base {
+ virtual ~Derived();
+ Typo foo(); // expected-error{{unknown type name 'Typo'}}
+ };
+}
diff --git a/test/CXX/except/except.spec/p9-noexcept.cpp b/test/CXX/except/except.spec/p9-noexcept.cpp
index 7c8d0ef..3fd45c5 100644
--- a/test/CXX/except/except.spec/p9-noexcept.cpp
+++ b/test/CXX/except/except.spec/p9-noexcept.cpp
@@ -7,9 +7,10 @@ void target() noexcept
// CHECK: invoke void @_Z8externalv()
external();
}
-// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+// CHECK: [[T0:%.*]] = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
// CHECK-NEXT: catch i8* null
-// CHECK-NEXT: call void @_ZSt9terminatev() noreturn nounwind
+// CHECK-NEXT: [[T1:%.*]] = extractvalue { i8*, i32 } [[T0]], 0
+// CHECK-NEXT: call void @__clang_call_terminate(i8* [[T1]]) [[NR_NUW:#[0-9]+]]
// CHECK-NEXT: unreachable
void reverse() noexcept(false)
@@ -17,3 +18,5 @@ void reverse() noexcept(false)
// CHECK: call void @_Z8externalv()
external();
}
+
+// CHECK: attributes [[NR_NUW]] = { noreturn nounwind }
diff --git a/test/CXX/expr/expr.const/p2-0x.cpp b/test/CXX/expr/expr.const/p2-0x.cpp
index 9e6716d..065a12b 100644
--- a/test/CXX/expr/expr.const/p2-0x.cpp
+++ b/test/CXX/expr/expr.const/p2-0x.cpp
@@ -594,3 +594,16 @@ static const bool or_value = and_or<true>::or_value;
static_assert(and_value == false, "");
static_assert(or_value == true, "");
+
+namespace rdar13090123 {
+ typedef __INTPTR_TYPE__ intptr_t;
+
+ constexpr intptr_t f(intptr_t x) {
+ return (((x) >> 21) * 8); // expected-note{{subexpression not valid in a constant expression}}
+ }
+
+ extern "C" int foo;
+
+ constexpr intptr_t i = f((intptr_t)&foo - 10); // expected-error{{constexpr variable 'i' must be initialized by a constant expression}} \
+ // expected-note{{in call to 'f((char*)&foo + -10)'}}
+}
diff --git a/test/CXX/expr/expr.post/expr.call/p7-0x.cpp b/test/CXX/expr/expr.post/expr.call/p7-0x.cpp
index d51ba09..018609d 100644
--- a/test/CXX/expr/expr.post/expr.call/p7-0x.cpp
+++ b/test/CXX/expr/expr.post/expr.call/p7-0x.cpp
@@ -9,11 +9,22 @@ struct X2 {
~X2();
};
+struct X3 {
+ X3(const X3&) = default;
+};
+
+struct X4 {
+ X4(const X4&) = default;
+ X4(X4&);
+};
+
void vararg(...);
-void f(X1 x1, X2 x2) {
- vararg(x1); // okay
+void f(X1 x1, X2 x2, X3 x3, X4 x4) {
+ vararg(x1); // OK
vararg(x2); // expected-error{{cannot pass object of non-trivial type 'X2' through variadic function; call will abort at runtime}}
+ vararg(x3); // OK
+ vararg(x4); // expected-error{{cannot pass object of non-trivial type 'X4' through variadic function; call will abort at runtime}}
}
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 b84cec6..6657991 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
@@ -61,9 +61,26 @@ namespace PR10036 {
}
}
+namespace PR15290 {
+ template<typename T>
+ class A {
+ T v_;
+ friend int add_to_v(A &t) noexcept(noexcept(v_ + 42))
+ {
+ return t.v_ + 42;
+ }
+ };
+ void f()
+ {
+ A<int> t;
+ add_to_v(t);
+ }
+}
+
namespace Static {
struct X1 {
int m;
+ // FIXME: This should be accepted.
static auto f() -> decltype(m); // expected-error{{'this' cannot be implicitly used in a static member function declaration}}
static auto g() -> decltype(this->m); // expected-error{{'this' cannot be used in a static member function declaration}}
@@ -99,3 +116,23 @@ namespace PR12564 {
void foo(Derived& d) noexcept(noexcept(d.bar(d))) {} // expected-error {{cannot bind to a value of unrelated type}}
};
}
+
+namespace rdar13473493 {
+ template <typename F>
+ class wrap
+ {
+ public:
+ template <typename... Args>
+ auto operator()(Args&&... args) const -> decltype(wrapped(args...)) // expected-note{{candidate template ignored: substitution failure [with Args = <int>]: use of undeclared identifier 'wrapped'}}
+ {
+ return wrapped(args...);
+ }
+
+ private:
+ F wrapped;
+ };
+
+ void test(wrap<int (*)(int)> w) {
+ w(5); // expected-error{{no matching function for call to object of type 'wrap<int (*)(int)>'}}
+ }
+}
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p19.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p19.cpp
index 6fe3b25..8a6e792 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p19.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p19.cpp
@@ -13,7 +13,7 @@ void test_special_member_functions(MoveOnly mo, int i) {
decltype(lambda1) lambda2; // expected-error{{call to implicitly-deleted default constructor of 'decltype(lambda1)' (aka '<lambda}}
// Copy assignment operator
- lambda1 = lambda1; // expected-error{{overload resolution selected implicitly-deleted copy assignment operator}}
+ lambda1 = lambda1; // expected-error{{copy assignment operator is implicitly deleted}}
// Move assignment operator
lambda1 = move(lambda1);
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp
index 68460f0..9dffc1f 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp
@@ -5,7 +5,8 @@
void test_attributes() {
auto nrl = [](int x) -> int { if (x > 0) return x; }; // expected-warning{{control may reach end of non-void lambda}}
- auto nrl2 = []() [[noreturn]] { return; }; // expected-error{{lambda declared 'noreturn' should not return}}
+ // FIXME: GCC accepts the [[gnu::noreturn]] attribute here.
+ auto nrl2 = []() [[gnu::noreturn]] { return; }; // expected-warning{{attribute 'noreturn' ignored}}
}
template<typename T>
diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp
index 49b9c66..407b083 100644
--- a/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp
+++ b/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp
@@ -2,10 +2,11 @@
template<typename T>
void test_attributes() {
- auto nrl = []() [[noreturn]] {}; // expected-error{{lambda declared 'noreturn' should not return}}
+ // FIXME: GCC accepts [[gnu::noreturn]] here.
+ auto nrl = []() [[gnu::noreturn]] {}; // expected-warning{{attribute 'noreturn' ignored}}
}
-template void test_attributes<int>(); // expected-note{{in instantiation of function}}
+template void test_attributes<int>();
template<typename T>
void call_with_zero() {
diff --git a/test/CXX/lex/lex.literal/lex.ext/p5.cpp b/test/CXX/lex/lex.literal/lex.ext/p5.cpp
index 4655aa17..06c091d 100644
--- a/test/CXX/lex/lex.literal/lex.ext/p5.cpp
+++ b/test/CXX/lex/lex.literal/lex.ext/p5.cpp
@@ -11,3 +11,10 @@ double &i3 = L"foo"_x1; // expected-error {{no matching literal operator}}
char &operator "" _x1(const wchar_t *, size_t);
char &i4 = L"foo"_x1; // ok
double &i5 = R"(foo)"_x1; // ok
+double &i6 = u\
+8\
+R\
+"(foo)"\
+_\
+x\
+1; // ok
diff --git a/test/CXX/lex/lex.pptoken/p3-0x.cpp b/test/CXX/lex/lex.pptoken/p3-0x.cpp
index 3d56ac1..418a0f3 100644
--- a/test/CXX/lex/lex.pptoken/p3-0x.cpp
+++ b/test/CXX/lex/lex.pptoken/p3-0x.cpp
@@ -9,3 +9,7 @@ template void f<::b>();
#define x a<:: ## : b :>
int d = x; // expected-error {{pasting formed ':::', an invalid preprocessing token}} expected-error {{expected unqualified-id}}
+
+const char xs[] = R"(\
+??=\U0000)";
+static_assert(sizeof(xs) == 12, "did not revert all changes");
diff --git a/test/CXX/over/over.oper/over.literal/p8.cpp b/test/CXX/over/over.oper/over.literal/p8.cpp
index 6f63610..70a1843 100644
--- a/test/CXX/over/over.oper/over.literal/p8.cpp
+++ b/test/CXX/over/over.oper/over.literal/p8.cpp
@@ -7,8 +7,7 @@ namespace std {
void operator "" _km(long double); // ok
string operator "" _i18n(const char*, std::size_t); // ok
-// FIXME: This should be accepted once we support UCNs
-template<char...> int operator "" \u03C0(); // ok, UCN for lowercase pi // expected-error {{expected identifier}}
+template<char...> int operator "" \u03C0(); // ok, UCN for lowercase pi // 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}}
diff --git a/test/CXX/special/class.copy/implicit-move.cpp b/test/CXX/special/class.copy/implicit-move.cpp
index 597e327..3337412 100644
--- a/test/CXX/special/class.copy/implicit-move.cpp
+++ b/test/CXX/special/class.copy/implicit-move.cpp
@@ -54,7 +54,7 @@ void test_basic_exclusion() {
static_assert(noexcept(HasMoveConstructor((HasMoveConstructor()))), "");
HasMoveConstructor hmc;
- hmc = HasMoveConstructor(); // expected-error {{selected implicitly-deleted copy assignment}}
+ hmc = HasMoveConstructor(); // expected-error {{object of type 'HasMoveConstructor' cannot be assigned because its copy assignment operator is implicitly deleted}}
(HasMoveAssignment(HasMoveAssignment())); // expected-error {{uses deleted function}}
HasMoveAssignment hma;
diff --git a/test/CXX/special/class.copy/p12-0x.cpp b/test/CXX/special/class.copy/p12-0x.cpp
new file mode 100644
index 0000000..17b3191
--- /dev/null
+++ b/test/CXX/special/class.copy/p12-0x.cpp
@@ -0,0 +1,216 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+// expected-no-diagnostics
+
+template<typename T, bool B> struct trivially_copyable_check {
+ static_assert(B == __has_trivial_copy(T), "");
+ static_assert(B == __is_trivially_constructible(T, T), "");
+ static_assert(B == __is_trivially_constructible(T, const T &), "");
+ static_assert(B == __is_trivially_constructible(T, T &&), "");
+ typedef void type;
+};
+template<typename T> using trivially_copyable =
+ typename trivially_copyable_check<T, true>::type;
+template<typename T> using not_trivially_copyable =
+ typename trivially_copyable_check<T, false>::type;
+
+struct Trivial {};
+using _ = trivially_copyable<Trivial>;
+
+// A copy/move constructor for class X is trivial if it is not user-provided,
+struct UserProvided {
+ UserProvided(const UserProvided &);
+};
+using _ = not_trivially_copyable<UserProvided>;
+
+// its declared parameter type is the same as if it had been implicitly
+// declared,
+struct NonConstCopy {
+ NonConstCopy(NonConstCopy &) = default;
+};
+using _ = not_trivially_copyable<NonConstCopy>;
+
+// class X has no virtual functions
+struct VFn {
+ virtual void f();
+};
+using _ = not_trivially_copyable<VFn>;
+
+// and no virtual base classes
+struct VBase : virtual Trivial {};
+using _ = not_trivially_copyable<VBase>;
+
+// and the constructor selected to copy/move each [direct subobject] is trivial
+struct TemplateCtor {
+ template<typename T> TemplateCtor(T &);
+};
+using _ = trivially_copyable<TemplateCtor>;
+struct TemplateCtorMember {
+ TemplateCtor tc;
+};
+using _ = trivially_copyable<TemplateCtorMember>;
+
+// We can select a non-trivial copy ctor even if there is a trivial one.
+struct MutableTemplateCtorMember {
+ mutable TemplateCtor mtc;
+};
+static_assert(!__is_trivially_constructible(MutableTemplateCtorMember, const MutableTemplateCtorMember &), "");
+static_assert(__is_trivially_constructible(MutableTemplateCtorMember, MutableTemplateCtorMember &&), "");
+struct MutableTemplateCtorMember2 {
+ MutableTemplateCtorMember2(const MutableTemplateCtorMember2 &) = default;
+ MutableTemplateCtorMember2(MutableTemplateCtorMember2 &&) = default;
+ mutable TemplateCtor mtc;
+};
+static_assert(!__is_trivially_constructible(MutableTemplateCtorMember2, const MutableTemplateCtorMember2 &), "");
+static_assert(__is_trivially_constructible(MutableTemplateCtorMember2, MutableTemplateCtorMember2 &&), "");
+
+// Both trivial and non-trivial special members.
+struct TNT {
+ TNT(const TNT &) = default; // trivial
+ TNT(TNT &); // non-trivial
+
+ TNT(TNT &&) = default; // trivial
+ TNT(const TNT &&); // non-trivial
+};
+
+static_assert(!__has_trivial_copy(TNT), "lie deliberately for gcc compatibility");
+static_assert(__is_trivially_constructible(TNT, TNT), "");
+static_assert(!__is_trivially_constructible(TNT, TNT &), "");
+static_assert(__is_trivially_constructible(TNT, const TNT &), "");
+static_assert(!__is_trivially_constructible(TNT, volatile TNT &), "");
+static_assert(__is_trivially_constructible(TNT, TNT &&), "");
+static_assert(!__is_trivially_constructible(TNT, const TNT &&), "");
+static_assert(!__is_trivially_constructible(TNT, volatile TNT &&), "");
+
+// This has only trivial special members.
+struct DerivedFromTNT : TNT {};
+
+static_assert(__has_trivial_copy(DerivedFromTNT), "");
+static_assert(__is_trivially_constructible(DerivedFromTNT, DerivedFromTNT), "");
+static_assert(__is_trivially_constructible(DerivedFromTNT, DerivedFromTNT &), "");
+static_assert(__is_trivially_constructible(DerivedFromTNT, const DerivedFromTNT &), "");
+static_assert(!__is_trivially_constructible(DerivedFromTNT, volatile DerivedFromTNT &), "");
+static_assert(__is_trivially_constructible(DerivedFromTNT, DerivedFromTNT &&), "");
+static_assert(__is_trivially_constructible(DerivedFromTNT, const DerivedFromTNT &&), "");
+static_assert(!__is_trivially_constructible(DerivedFromTNT, volatile DerivedFromTNT &&), "");
+
+// This has only trivial special members.
+struct TNTMember {
+ TNT tnt;
+};
+
+static_assert(__has_trivial_copy(TNTMember), "");
+static_assert(__is_trivially_constructible(TNTMember, TNTMember), "");
+static_assert(__is_trivially_constructible(TNTMember, TNTMember &), "");
+static_assert(__is_trivially_constructible(TNTMember, const TNTMember &), "");
+static_assert(!__is_trivially_constructible(TNTMember, volatile TNTMember &), "");
+static_assert(__is_trivially_constructible(TNTMember, TNTMember &&), "");
+static_assert(__is_trivially_constructible(TNTMember, const TNTMember &&), "");
+static_assert(!__is_trivially_constructible(TNTMember, volatile TNTMember &&), "");
+
+struct NCCTNT : NonConstCopy, TNT {};
+
+static_assert(!__has_trivial_copy(NCCTNT), "");
+static_assert(!__is_trivially_constructible(NCCTNT, NCCTNT), "");
+static_assert(!__is_trivially_constructible(NCCTNT, NCCTNT &), "");
+static_assert(!__is_trivially_constructible(NCCTNT, const NCCTNT &), "");
+static_assert(!__is_trivially_constructible(NCCTNT, volatile NCCTNT &), "");
+static_assert(!__is_trivially_constructible(NCCTNT, NCCTNT &&), "");
+static_assert(!__is_trivially_constructible(NCCTNT, const NCCTNT &&), "");
+static_assert(!__is_trivially_constructible(NCCTNT, volatile NCCTNT &&), "");
+
+struct TemplateCtorNoMove {
+ TemplateCtorNoMove(const TemplateCtorNoMove &) = default;
+ template<typename T> TemplateCtorNoMove(T &&);
+};
+static_assert(__is_trivially_constructible(TemplateCtorNoMove, const TemplateCtorNoMove &), "");
+static_assert(!__is_trivially_constructible(TemplateCtorNoMove, TemplateCtorNoMove &&), "");
+
+struct UseTemplateCtorNoMove {
+ TemplateCtorNoMove tcnm;
+};
+static_assert(__is_trivially_constructible(UseTemplateCtorNoMove, const UseTemplateCtorNoMove &), "");
+static_assert(!__is_trivially_constructible(UseTemplateCtorNoMove, UseTemplateCtorNoMove &&), "");
+
+struct TemplateCtorNoMoveSFINAE {
+ TemplateCtorNoMoveSFINAE(const TemplateCtorNoMoveSFINAE &) = default;
+ template<typename T, typename U = typename T::error> TemplateCtorNoMoveSFINAE(T &&);
+};
+static_assert(__is_trivially_constructible(TemplateCtorNoMoveSFINAE, const TemplateCtorNoMoveSFINAE &), "");
+static_assert(__is_trivially_constructible(TemplateCtorNoMoveSFINAE, TemplateCtorNoMoveSFINAE &&), "");
+
+struct UseTemplateCtorNoMoveSFINAE {
+ TemplateCtorNoMoveSFINAE tcnm;
+};
+static_assert(__is_trivially_constructible(UseTemplateCtorNoMoveSFINAE, const UseTemplateCtorNoMoveSFINAE &), "");
+static_assert(__is_trivially_constructible(UseTemplateCtorNoMoveSFINAE, UseTemplateCtorNoMoveSFINAE &&), "");
+
+namespace TrivialityDependsOnImplicitDeletion {
+ struct PrivateMove {
+ PrivateMove(const PrivateMove &) = default;
+ private:
+ PrivateMove(PrivateMove &&);
+ friend class Access;
+ };
+ static_assert(__is_trivially_constructible(PrivateMove, const PrivateMove &), "");
+ static_assert(!__is_trivially_constructible(PrivateMove, PrivateMove &&), "");
+
+ struct NoAccess {
+ PrivateMove pm;
+ // NoAccess's move would be deleted, so is suppressed,
+ // so moves of it use PrivateMove's copy ctor, which is trivial.
+ };
+ static_assert(__is_trivially_constructible(NoAccess, const NoAccess &), "");
+ static_assert(__is_trivially_constructible(NoAccess, NoAccess &&), "");
+ struct TopNoAccess : NoAccess {};
+ static_assert(__is_trivially_constructible(TopNoAccess, const TopNoAccess &), "");
+ static_assert(__is_trivially_constructible(TopNoAccess, TopNoAccess &&), "");
+
+ struct Access {
+ PrivateMove pm;
+ // NoAccess's move would *not* be deleted, so is *not* suppressed,
+ // so moves of it use PrivateMove's move ctor, which is not trivial.
+ };
+ static_assert(__is_trivially_constructible(Access, const Access &), "");
+ static_assert(!__is_trivially_constructible(Access, Access &&), "");
+ struct TopAccess : Access {};
+ static_assert(__is_trivially_constructible(TopAccess, const TopAccess &), "");
+ static_assert(!__is_trivially_constructible(TopAccess, TopAccess &&), "");
+}
+
+namespace TrivialityDependsOnDestructor {
+ class HasInaccessibleDestructor { ~HasInaccessibleDestructor() = default; };
+ struct HasImplicitlyDeletedDestructor : HasInaccessibleDestructor {};
+ struct HasImplicitlyDeletedCopyCtor : HasImplicitlyDeletedDestructor {
+ HasImplicitlyDeletedCopyCtor() = default;
+ template<typename T> HasImplicitlyDeletedCopyCtor(T &&);
+ // Copy ctor is deleted but trivial.
+ // Move ctor is suppressed.
+ HasImplicitlyDeletedCopyCtor(const HasImplicitlyDeletedCopyCtor&) = default;
+ HasImplicitlyDeletedCopyCtor(HasImplicitlyDeletedCopyCtor&&) = default;
+ };
+ struct Test : HasImplicitlyDeletedCopyCtor {
+ Test(const Test&) = default;
+ Test(Test&&) = default;
+ };
+ // Implicit copy ctor calls deleted trivial copy ctor.
+ static_assert(__has_trivial_copy(Test), "");
+ // This is false because the destructor is deleted.
+ static_assert(!__is_trivially_constructible(Test, const Test &), "");
+ // Implicit move ctor calls template ctor.
+ static_assert(!__is_trivially_constructible(Test, Test &&), "");
+
+ struct HasAccessibleDestructor { ~HasAccessibleDestructor() = default; };
+ struct HasImplicitlyDefaultedDestructor : HasAccessibleDestructor {};
+ struct HasImplicitlyDefaultedCopyCtor : HasImplicitlyDefaultedDestructor {
+ template<typename T> HasImplicitlyDefaultedCopyCtor(T &&);
+ // Copy ctor is trivial.
+ // Move ctor is trivial.
+ };
+ struct Test2 : HasImplicitlyDefaultedCopyCtor {};
+ // Implicit copy ctor calls trivial copy ctor.
+ static_assert(__has_trivial_copy(Test2), "");
+ static_assert(__is_trivially_constructible(Test2, const Test2 &), "");
+ // Implicit move ctor calls trivial move ctor.
+ static_assert(__is_trivially_constructible(Test2, Test2 &&), "");
+}
diff --git a/test/CXX/special/class.copy/p18-cxx11.cpp b/test/CXX/special/class.copy/p18-cxx11.cpp
new file mode 100644
index 0000000..7b09dd6
--- /dev/null
+++ b/test/CXX/special/class.copy/p18-cxx11.cpp
@@ -0,0 +1,62 @@
+// RUN: %clang_cc1 -std=c++11 %s -verify
+// expected-no-diagnostics
+
+// C++98 [class.copy]p10 / C++11 [class.copy]p18.
+
+// The implicitly-declared copy assignment operator for a class X will have the form
+// X& X::operator=(const X&)
+// if [every direct subobject] has a copy assignment operator whose first parameter is
+// of type 'const volatile[opt] T &' or 'T'. Otherwise, it will have the form
+// X &X::operator=(X&)
+
+struct ConstCopy {
+ ConstCopy &operator=(const ConstCopy &);
+};
+
+struct NonConstCopy {
+ NonConstCopy &operator=(NonConstCopy &);
+};
+
+struct DeletedConstCopy {
+ DeletedConstCopy &operator=(const DeletedConstCopy &) = delete;
+};
+
+struct DeletedNonConstCopy {
+ DeletedNonConstCopy &operator=(DeletedNonConstCopy &) = delete;
+};
+
+struct ImplicitlyDeletedConstCopy {
+ ImplicitlyDeletedConstCopy &operator=(ImplicitlyDeletedConstCopy &&);
+};
+
+struct ByValueCopy {
+ ByValueCopy &operator=(ByValueCopy);
+};
+
+struct AmbiguousConstCopy {
+ AmbiguousConstCopy &operator=(const AmbiguousConstCopy&);
+ AmbiguousConstCopy &operator=(AmbiguousConstCopy);
+};
+
+
+struct A : ConstCopy {};
+struct B : NonConstCopy { ConstCopy a; };
+struct C : ConstCopy { NonConstCopy a; };
+struct D : DeletedConstCopy {};
+struct E : DeletedNonConstCopy {};
+struct F { ImplicitlyDeletedConstCopy a; };
+struct G : virtual B {};
+struct H : ByValueCopy {};
+struct I : AmbiguousConstCopy {};
+
+struct Test {
+ friend A &A::operator=(const A &);
+ friend B &B::operator=(B &);
+ friend C &C::operator=(C &);
+ friend D &D::operator=(const D &);
+ friend E &E::operator=(E &);
+ friend F &F::operator=(const F &);
+ friend G &G::operator=(G &);
+ friend H &H::operator=(const H &);
+ friend I &I::operator=(const I &);
+};
diff --git a/test/CXX/special/class.copy/p23-cxx11.cpp b/test/CXX/special/class.copy/p23-cxx11.cpp
index 7c04a82..90945c5 100644
--- a/test/CXX/special/class.copy/p23-cxx11.cpp
+++ b/test/CXX/special/class.copy/p23-cxx11.cpp
@@ -143,6 +143,6 @@ namespace PR13381 {
};
void g() {
T t;
- t = T(); // expected-error{{implicitly-deleted copy assignment}}
+ t = T(); // expected-error{{object of type 'PR13381::T' cannot be assigned because its copy assignment operator is implicitly deleted}}
}
}
diff --git a/test/CXX/special/class.copy/p25-0x.cpp b/test/CXX/special/class.copy/p25-0x.cpp
new file mode 100644
index 0000000..c7224ae
--- /dev/null
+++ b/test/CXX/special/class.copy/p25-0x.cpp
@@ -0,0 +1,202 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+// expected-no-diagnostics
+
+template<typename T, bool B> struct trivially_assignable_check {
+ static_assert(B == __has_trivial_assign(T), "");
+ static_assert(B == __is_trivially_assignable(T&, T), "");
+ static_assert(B == __is_trivially_assignable(T&, const T &), "");
+ static_assert(B == __is_trivially_assignable(T&, T &&), "");
+ static_assert(B == __is_trivially_assignable(T&&, T), "");
+ static_assert(B == __is_trivially_assignable(T&&, const T &), "");
+ static_assert(B == __is_trivially_assignable(T&&, T &&), "");
+ typedef void type;
+};
+template<typename T> using trivially_assignable =
+ typename trivially_assignable_check<T, true>::type;
+template<typename T> using not_trivially_assignable =
+ typename trivially_assignable_check<T, false>::type;
+
+struct Trivial {};
+using _ = trivially_assignable<Trivial>;
+
+// A copy/move assignment operator for class X is trivial if it is not user-provided,
+struct UserProvided {
+ UserProvided &operator=(const UserProvided &);
+};
+using _ = not_trivially_assignable<UserProvided>;
+
+// its declared parameter type is the same as if it had been implicitly
+// declared,
+struct NonConstCopy {
+ NonConstCopy &operator=(NonConstCopy &) = default;
+};
+using _ = not_trivially_assignable<NonConstCopy>;
+
+// class X has no virtual functions
+struct VFn {
+ virtual void f();
+};
+using _ = not_trivially_assignable<VFn>;
+
+// and no virtual base classes
+struct VBase : virtual Trivial {};
+using _ = not_trivially_assignable<VBase>;
+
+// and the assignment operator selected to copy/move each [direct subobject] is trivial
+struct TemplateCtor {
+ template<typename T> TemplateCtor operator=(T &);
+};
+using _ = trivially_assignable<TemplateCtor>;
+struct TemplateCtorMember {
+ TemplateCtor tc;
+};
+using _ = trivially_assignable<TemplateCtorMember>;
+struct MutableTemplateCtorMember {
+ mutable TemplateCtor mtc;
+};
+static_assert(!__is_trivially_assignable(MutableTemplateCtorMember, const MutableTemplateCtorMember &), "");
+static_assert(__is_trivially_assignable(MutableTemplateCtorMember, MutableTemplateCtorMember &&), "");
+
+// Both trivial and non-trivial special members.
+struct TNT {
+ TNT &operator=(const TNT &) = default; // trivial
+ TNT &operator=(TNT &); // non-trivial
+
+ TNT &operator=(TNT &&) = default; // trivial
+ TNT &operator=(const TNT &&); // non-trivial
+};
+
+static_assert(!__has_trivial_assign(TNT), "lie deliberately for gcc compatibility");
+static_assert(__is_trivially_assignable(TNT, TNT), "");
+static_assert(!__is_trivially_assignable(TNT, TNT &), "");
+static_assert(__is_trivially_assignable(TNT, const TNT &), "");
+static_assert(!__is_trivially_assignable(TNT, volatile TNT &), "");
+static_assert(__is_trivially_assignable(TNT, TNT &&), "");
+static_assert(!__is_trivially_assignable(TNT, const TNT &&), "");
+static_assert(!__is_trivially_assignable(TNT, volatile TNT &&), "");
+
+// This has only trivial special members.
+struct DerivedFromTNT : TNT {};
+
+static_assert(__has_trivial_assign(DerivedFromTNT), "");
+static_assert(__is_trivially_assignable(DerivedFromTNT, DerivedFromTNT), "");
+static_assert(__is_trivially_assignable(DerivedFromTNT, DerivedFromTNT &), "");
+static_assert(__is_trivially_assignable(DerivedFromTNT, const DerivedFromTNT &), "");
+static_assert(!__is_trivially_assignable(DerivedFromTNT, volatile DerivedFromTNT &), "");
+static_assert(__is_trivially_assignable(DerivedFromTNT, DerivedFromTNT &&), "");
+static_assert(__is_trivially_assignable(DerivedFromTNT, const DerivedFromTNT &&), "");
+static_assert(!__is_trivially_assignable(DerivedFromTNT, volatile DerivedFromTNT &&), "");
+
+// This has only trivial special members.
+struct TNTMember {
+ TNT tnt;
+};
+
+static_assert(__has_trivial_assign(TNTMember), "");
+static_assert(__is_trivially_assignable(TNTMember, TNTMember), "");
+static_assert(__is_trivially_assignable(TNTMember, TNTMember &), "");
+static_assert(__is_trivially_assignable(TNTMember, const TNTMember &), "");
+static_assert(!__is_trivially_assignable(TNTMember, volatile TNTMember &), "");
+static_assert(__is_trivially_assignable(TNTMember, TNTMember &&), "");
+static_assert(__is_trivially_assignable(TNTMember, const TNTMember &&), "");
+static_assert(!__is_trivially_assignable(TNTMember, volatile TNTMember &&), "");
+
+struct NCCTNT : NonConstCopy, TNT {};
+
+static_assert(!__has_trivial_assign(NCCTNT), "");
+static_assert(!__is_trivially_assignable(NCCTNT, NCCTNT), "");
+static_assert(!__is_trivially_assignable(NCCTNT, NCCTNT &), "");
+static_assert(!__is_trivially_assignable(NCCTNT, const NCCTNT &), "");
+static_assert(!__is_trivially_assignable(NCCTNT, volatile NCCTNT &), "");
+static_assert(!__is_trivially_assignable(NCCTNT, NCCTNT &&), "");
+static_assert(!__is_trivially_assignable(NCCTNT, const NCCTNT &&), "");
+static_assert(!__is_trivially_assignable(NCCTNT, volatile NCCTNT &&), "");
+
+struct MultipleTrivial {
+ // All four of these are trivial.
+ MultipleTrivial &operator=(const MultipleTrivial &) & = default;
+ MultipleTrivial &operator=(const MultipleTrivial &) && = default;
+ MultipleTrivial &operator=(MultipleTrivial &&) & = default;
+ MultipleTrivial &operator=(MultipleTrivial &&) && = default;
+};
+
+using _ = trivially_assignable<MultipleTrivial>;
+
+struct RefQualifier {
+ RefQualifier &operator=(const RefQualifier &) & = default;
+ RefQualifier &operator=(const RefQualifier &) &&;
+ RefQualifier &operator=(RefQualifier &&) &;
+ RefQualifier &operator=(RefQualifier &&) && = default;
+};
+struct DerivedFromRefQualifier : RefQualifier {
+ // Both of these call the trivial copy operation.
+ DerivedFromRefQualifier &operator=(const DerivedFromRefQualifier &) & = default;
+ DerivedFromRefQualifier &operator=(const DerivedFromRefQualifier &) && = default;
+ // Both of these call the non-trivial move operation.
+ DerivedFromRefQualifier &operator=(DerivedFromRefQualifier &&) & = default;
+ DerivedFromRefQualifier &operator=(DerivedFromRefQualifier &&) && = default;
+};
+static_assert(__is_trivially_assignable(DerivedFromRefQualifier&, const DerivedFromRefQualifier&), "");
+static_assert(__is_trivially_assignable(DerivedFromRefQualifier&&, const DerivedFromRefQualifier&), "");
+static_assert(!__is_trivially_assignable(DerivedFromRefQualifier&, DerivedFromRefQualifier&&), "");
+static_assert(!__is_trivially_assignable(DerivedFromRefQualifier&&, DerivedFromRefQualifier&&), "");
+
+struct TemplateAssignNoMove {
+ TemplateAssignNoMove &operator=(const TemplateAssignNoMove &) = default;
+ template<typename T> TemplateAssignNoMove &operator=(T &&);
+};
+static_assert(__is_trivially_assignable(TemplateAssignNoMove, const TemplateAssignNoMove &), "");
+static_assert(!__is_trivially_assignable(TemplateAssignNoMove, TemplateAssignNoMove &&), "");
+
+struct UseTemplateAssignNoMove {
+ TemplateAssignNoMove tanm;
+};
+static_assert(__is_trivially_assignable(UseTemplateAssignNoMove, const UseTemplateAssignNoMove &), "");
+static_assert(!__is_trivially_assignable(UseTemplateAssignNoMove, UseTemplateAssignNoMove &&), "");
+
+struct TemplateAssignNoMoveSFINAE {
+ TemplateAssignNoMoveSFINAE &operator=(const TemplateAssignNoMoveSFINAE &) = default;
+ template<typename T, typename U = typename T::error> TemplateAssignNoMoveSFINAE &operator=(T &&);
+};
+static_assert(__is_trivially_assignable(TemplateAssignNoMoveSFINAE, const TemplateAssignNoMoveSFINAE &), "");
+static_assert(__is_trivially_assignable(TemplateAssignNoMoveSFINAE, TemplateAssignNoMoveSFINAE &&), "");
+
+struct UseTemplateAssignNoMoveSFINAE {
+ TemplateAssignNoMoveSFINAE tanm;
+};
+static_assert(__is_trivially_assignable(UseTemplateAssignNoMoveSFINAE, const UseTemplateAssignNoMoveSFINAE &), "");
+static_assert(__is_trivially_assignable(UseTemplateAssignNoMoveSFINAE, UseTemplateAssignNoMoveSFINAE &&), "");
+
+namespace TrivialityDependsOnImplicitDeletion {
+ struct PrivateMove {
+ PrivateMove &operator=(const PrivateMove &) = default;
+ private:
+ PrivateMove &operator=(PrivateMove &&);
+ friend class Access;
+ };
+ static_assert(__is_trivially_assignable(PrivateMove, const PrivateMove &), "");
+ static_assert(!__is_trivially_assignable(PrivateMove, PrivateMove &&), "");
+
+ struct NoAccess {
+ PrivateMove pm;
+ // NoAccess's move would be deleted, so is suppressed,
+ // so moves of it use PrivateMove's copy ctor, which is trivial.
+ };
+ static_assert(__is_trivially_assignable(NoAccess, const NoAccess &), "");
+ static_assert(__is_trivially_assignable(NoAccess, NoAccess &&), "");
+ struct TopNoAccess : NoAccess {};
+ static_assert(__is_trivially_assignable(TopNoAccess, const TopNoAccess &), "");
+ static_assert(__is_trivially_assignable(TopNoAccess, TopNoAccess &&), "");
+
+ struct Access {
+ PrivateMove pm;
+ // NoAccess's move would *not* be deleted, so is *not* suppressed,
+ // so moves of it use PrivateMove's move ctor, which is not trivial.
+ };
+ static_assert(__is_trivially_assignable(Access, const Access &), "");
+ static_assert(!__is_trivially_assignable(Access, Access &&), "");
+ struct TopAccess : Access {};
+ static_assert(__is_trivially_assignable(TopAccess, const TopAccess &), "");
+ static_assert(!__is_trivially_assignable(TopAccess, TopAccess &&), "");
+}
diff --git a/test/CXX/special/class.copy/p28-cxx11.cpp b/test/CXX/special/class.copy/p28-cxx11.cpp
new file mode 100644
index 0000000..dc501d9
--- /dev/null
+++ b/test/CXX/special/class.copy/p28-cxx11.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -std=c++98 %s -fsyntax-only
+// RUN: %clang_cc1 -std=c++11 %s -verify
+
+// In C++11, we must perform overload resolution to determine which function is
+// called by a defaulted assignment operator, and the selected operator might
+// not be a copy or move assignment (it might be a specialization of a templated
+// 'operator=', for instance).
+struct A {
+ A &operator=(const A &);
+
+ template<typename T>
+ A &operator=(T &&) { return T::error; } // expected-error {{no member named 'error' in 'A'}}
+};
+
+struct B : A {
+ B &operator=(B &&);
+};
+
+B &B::operator=(B &&) = default; // expected-note {{here}}
diff --git a/test/CXX/special/class.ctor/p1.cpp b/test/CXX/special/class.ctor/p1.cpp
index 4d82184..e19dc86 100644
--- a/test/CXX/special/class.ctor/p1.cpp
+++ b/test/CXX/special/class.ctor/p1.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-// expected-no-diagnostics
+
struct X0 {
struct type { };
@@ -41,3 +41,15 @@ template<typename T> X1<T>::X1() { }
template<typename T> (X1<T>::X1)(double) { }
template<typename T> X1<T> X1<T>::f1(int) { return 0; }
template<typename T> X1<T> (X1<T>::f1)(type) { return 0; }
+
+class X2 {
+ X2::X2(); // expected-error {{extra qualification on member 'X2'}}
+};
+
+// We used to parse 'X3::X3' as a member function declaration.
+// DR 1435 and DR 1310 made this invalid.
+typedef int T1;
+struct X3 {
+ X3::X3(T1()); // expected-error {{extra qualification on member 'X3'}}
+};
+
diff --git a/test/CXX/special/class.ctor/p5-0x.cpp b/test/CXX/special/class.ctor/p5-0x.cpp
index 1aaeef2..0f4add8 100644
--- a/test/CXX/special/class.ctor/p5-0x.cpp
+++ b/test/CXX/special/class.ctor/p5-0x.cpp
@@ -149,26 +149,41 @@ static_assert(__has_trivial_constructor(Trivial), "Trivial is nontrivial");
class NonTrivialDefCtor1 { NonTrivialDefCtor1(); };
static_assert(!__has_trivial_constructor(NonTrivialDefCtor1), "NonTrivialDefCtor1 is trivial");
+#define ASSERT_NONTRIVIAL_IMPL(Class, Bases, Body) \
+ class Class Bases { Body }; \
+ static_assert(!__has_trivial_constructor(Class), "");
+#define ASSERT_NONTRIVIAL(Class, Bases, Body) \
+ ASSERT_NONTRIVIAL_IMPL(Class, Bases, Body) \
+ ASSERT_NONTRIVIAL_IMPL(Def ## Class, Bases, Def ## Class() = default; Body) \
+ ASSERT_NONTRIVIAL_IMPL(Del ## Class, Bases, Del ## Class() = delete; Body)
+
// - its class has no virtual functions (10.3) and no virtual base classes (10.1), and
-class NonTrivialDefCtor2 { virtual void f(); };
-static_assert(!__has_trivial_constructor(NonTrivialDefCtor2), "NonTrivialDefCtor2 is trivial");
-class NonTrivialDefCtor3 : virtual Trivial {};
-static_assert(!__has_trivial_constructor(NonTrivialDefCtor3), "NonTrivialDefCtor3 is trivial");
+ASSERT_NONTRIVIAL(NonTrivialDefCtor2, , virtual void f();)
+ASSERT_NONTRIVIAL(NonTrivialDefCtor3, : virtual Trivial, )
// - no non-static data member of its class has a brace-or-equal-initializer, and
-class NonTrivialDefCtor4 { int m = 52; };
-static_assert(!__has_trivial_constructor(NonTrivialDefCtor4), "NonTrivialDefCtor4 is trivial");
+ASSERT_NONTRIVIAL(NonTrivialDefCtor4, , int m = 52;)
// - all the direct base classes of its class have trivial default constructors, and
-class NonTrivialDefCtor5 : NonTrivialDefCtor1 {};
-static_assert(!__has_trivial_constructor(NonTrivialDefCtor5), "NonTrivialDefCtor5 is trivial");
+ASSERT_NONTRIVIAL(NonTrivialDefCtor5, : NonTrivialDefCtor1, )
// - for all the non-static data members of its class that are of class type (or array thereof), each such class
// has a trivial default constructor.
-class NonTrivialDefCtor6 { NonTrivialDefCtor1 t; };
-static_assert(!__has_trivial_constructor(NonTrivialDefCtor6), "NonTrivialDefCtor5 is trivial");
+ASSERT_NONTRIVIAL(NonTrivialDefCtor6, , NonTrivialDefCtor1 t;)
+
+// FIXME: No core issue number yet.
+// - its parameter-declaration-clause is equivalent to that of an implicit declaration.
+struct NonTrivialDefCtor7 {
+ NonTrivialDefCtor7(...) = delete;
+};
+static_assert(!__has_trivial_constructor(NonTrivialDefCtor7), "");
+struct NonTrivialDefCtor8 {
+ NonTrivialDefCtor8(int = 0) = delete;
+};
+static_assert(!__has_trivial_constructor(NonTrivialDefCtor8), "");
// Otherwise, the default constructor is non-trivial.
+
class Trivial2 { Trivial2() = delete; };
static_assert(__has_trivial_constructor(Trivial2), "Trivial2 is trivial");
@@ -180,3 +195,15 @@ static_assert(__has_trivial_constructor(Trivial4<int>), "Trivial4 is trivial");
template<typename T> class Trivial5 { Trivial5() = delete; };
static_assert(__has_trivial_constructor(Trivial5<int>), "Trivial5 is trivial");
+
+namespace PR14558 {
+ // Ensure we determine whether an explicitly-defaulted or deleted special
+ // member is trivial before we return to parsing the containing class.
+ struct A {
+ struct B { B() = default; } b;
+ struct C { C() = delete; } c;
+ };
+
+ static_assert(__has_trivial_constructor(A), "");
+ static_assert(__has_trivial_constructor(A::B), "");
+}
diff --git a/test/CXX/special/class.dtor/p3-0x.cpp b/test/CXX/special/class.dtor/p3-0x.cpp
index 291353a..dc76e00 100644
--- a/test/CXX/special/class.dtor/p3-0x.cpp
+++ b/test/CXX/special/class.dtor/p3-0x.cpp
@@ -164,14 +164,16 @@ void tsw() {
Sw<int> swi;
Sw<B> swb;
}
-// CHECK-NOT: define linkonce_odr {{.*}} @_ZN2SwI1BED1Ev({{.*}} nounwind
+// CHECK-NOT: define linkonce_odr {{.*}} @_ZN2SwI1BED1Ev({{.*}} #
// CHECK: define linkonce_odr {{.*}} @_ZN2SwI1BED1Ev({{.*}}
// CHECK: _ZTIi
// CHECK: __cxa_call_unexpected
-// CHECK: define linkonce_odr {{.*}} @_ZN2SwIiED1Ev({{.*}} nounwind
+// CHECK: define linkonce_odr {{.*}} @_ZN2SwIiED1Ev({{.*}} [[ATTRGRP:#[0-9]+]]
template <typename T>
struct TVC : VX
{ virtual ~TVC(); };
template <typename T>
TVC<T>::~TVC() {}
+
+// CHECK: attributes [[ATTRGRP]] = { nounwind{{.*}} }
diff --git a/test/CXX/special/class.dtor/p5-0x.cpp b/test/CXX/special/class.dtor/p5-0x.cpp
index 0d073ce..e32279e 100644
--- a/test/CXX/special/class.dtor/p5-0x.cpp
+++ b/test/CXX/special/class.dtor/p5-0x.cpp
@@ -88,9 +88,10 @@ struct C4 : virtual InaccessibleDtor { C4(); } c4; // expected-error {{deleted f
class D1 {
void operator delete(void*);
public:
- virtual ~D1() = default;
+ virtual ~D1() = default; // expected-note {{here}}
} d1; // ok
-struct D2 : D1 { // expected-note {{virtual destructor requires an unambiguous, accessible 'operator delete'}}
+struct D2 : D1 { // expected-note {{virtual destructor requires an unambiguous, accessible 'operator delete'}} \
+ // expected-error {{deleted function '~D2' cannot override a non-deleted}}
// implicitly-virtual destructor
} d2; // expected-error {{deleted function}}
struct D3 { // expected-note {{virtual destructor requires an unambiguous, accessible 'operator delete'}}
diff --git a/test/CXX/special/class.inhctor/elsewhere.cpp b/test/CXX/special/class.inhctor/elsewhere.cpp
index 09fd3d5..184e902 100644
--- a/test/CXX/special/class.inhctor/elsewhere.cpp
+++ b/test/CXX/special/class.inhctor/elsewhere.cpp
@@ -9,49 +9,49 @@ struct B1 {
B1(int);
};
-using B1::B1; // expected-error {{using declaration can not refer to class member}} expected-error {{not supported}}
+using B1::B1; // expected-error {{using declaration can not refer to class member}}
-// C++0x [namespace.udecl]p10:
+// C++11 [namespace.udecl]p10:
// A using-declaration is a declaration and can therefore be used repeatedly
// where (and only where) multiple declarations are allowed.
struct I1 : B1 {
- using B1::B1; // expected-note {{previous using declaration}} expected-error {{not supported}}
- using B1::B1; // expected-error {{redeclaration of using decl}} expected-error {{not supported}}
+ using B1::B1; // expected-note {{previous using declaration}}
+ using B1::B1; // expected-error {{redeclaration of using decl}}
};
-// C++0x [namespace.udecl]p3:
+// C++11 [namespace.udecl]p3:
// In a using declaration used as a member-declaration, the nested-name-
// specifier shall name a base class of the class being defined.
// If such a using-declaration names a constructor, the nested-name-specifier
// shall name a direct base class of the class being defined.
struct D1 : I1 {
- using B1::B1; // expected-error {{'B1' is not a direct base of 'D1', can not inherit constructors}} expected-error {{not supported}}
+ using B1::B1; // expected-error {{'B1' is not a direct base of 'D1', can not inherit constructors}}
};
template<typename T> struct A {};
template<typename T> struct B : A<bool>, A<char> {
- using A<T>::A; // expected-error {{'A<double>::', which is not a base class of 'B<double>'}} expected-error {{not supported}}
+ using A<T>::A; // expected-error {{'A<double>::', which is not a base class of 'B<double>'}}
};
B<bool> bb;
B<char> bc;
B<double> bd; // expected-note {{here}}
template<typename T> struct C : A<T> {
- using A<bool>::A; // expected-error {{'A<bool>::', which is not a base class of 'C<char>'}} expected-error {{not supported}}
+ using A<bool>::A; // expected-error {{'A<bool>::', which is not a base class of 'C<char>'}}
};
C<bool> cb;
C<char> cc; // expected-note {{here}}
template<typename T> struct D : A<T> {};
template<typename T> struct E : D<T> {
- using A<bool>::A; // expected-error {{'A<bool>' is not a direct base of 'E<bool>', can not inherit}} expected-error {{not supported}}
+ using A<bool>::A; // expected-error {{'A<bool>' is not a direct base of 'E<bool>', can not inherit}}
};
E<bool> eb; // expected-note {{here}}
template<typename T> struct F : D<bool> {
- using A<T>::A; // expected-error {{'A<bool>' is not a direct base of 'F<bool>'}} expected-error {{not supported}}
+ using A<T>::A; // expected-error {{'A<bool>' is not a direct base of 'F<bool>'}}
};
F<bool> fb; // expected-note {{here}}
diff --git a/test/CXX/special/class.inhctor/p1.cpp b/test/CXX/special/class.inhctor/p1.cpp
new file mode 100644
index 0000000..57e9150
--- /dev/null
+++ b/test/CXX/special/class.inhctor/p1.cpp
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+// Per a core issue (no number yet), an ellipsis is always dropped.
+struct A {
+ A(...); // expected-note {{here}}
+ A(int = 0, int = 0, int = 0, int = 0, ...); // expected-note 5{{here}}
+ A(int = 0, int = 0, ...); // expected-note {{here}}
+};
+
+struct B : A { // expected-note 3{{candidate}}
+ using A::A; // expected-warning 3{{inheriting constructor does not inherit ellipsis}} expected-note 4{{candidate}} expected-note 2{{deleted}}
+};
+
+B b0{};
+// expected-error@-1 {{call to implicitly-deleted default constructor}}
+// expected-note@9 {{default constructor of 'B' is implicitly deleted because base class 'A' has multiple default constructors}}
+
+B b1{1};
+// FIXME: explain why the inheriting constructor was deleted
+// expected-error@-2 {{call to implicitly-deleted function of 'B'}}
+
+B b2{1,2};
+// expected-error@-1 {{call to implicitly-deleted function of 'B'}}
+
+B b3{1,2,3};
+// ok
+
+B b4{1,2,3,4};
+// ok
+
+B b5{1,2,3,4,5};
+// expected-error@-1 {{no matching constructor for initialization of 'B'}}
diff --git a/test/CXX/special/class.inhctor/p2.cpp b/test/CXX/special/class.inhctor/p2.cpp
new file mode 100644
index 0000000..e426738
--- /dev/null
+++ b/test/CXX/special/class.inhctor/p2.cpp
@@ -0,0 +1,87 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+template<int> struct X {};
+
+// Constructor characteristics are:
+// - the template parameter list [FIXME]
+// - the parameter-type-list
+// - absence or presence of explicit
+// - absence or presence of constexpr
+struct A {
+ A(X<0>) {} // expected-note 2{{here}}
+ constexpr A(X<1>) {}
+ explicit A(X<2>) {} // expected-note 3{{here}}
+ explicit constexpr A(X<3>) {} // expected-note 2{{here}}
+};
+
+A a0 { X<0>{} };
+A a0i = { X<0>{} };
+constexpr A a0c { X<0>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}
+constexpr A a0ic = { X<0>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}
+
+A a1 { X<1>{} };
+A a1i = { X<1>{} };
+constexpr A a1c { X<1>{} };
+constexpr A a1ic = { X<1>{} };
+
+A a2 { X<2>{} };
+A a2i = { X<2>{} }; // expected-error {{constructor is explicit}}
+constexpr A a2c { X<2>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}
+constexpr A a2ic = { X<2>{} }; // expected-error {{constructor is explicit}}
+
+A a3 { X<3>{} };
+A a3i = { X<3>{} }; // expected-error {{constructor is explicit}}
+constexpr A a3c { X<3>{} };
+constexpr A a3ic = { X<3>{} }; // expected-error {{constructor is explicit}}
+
+
+struct B : A {
+ using A::A; // expected-note 7{{here}}
+};
+
+B b0 { X<0>{} };
+B b0i = { X<0>{} };
+constexpr B b0c { X<0>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}
+constexpr B b0ic = { X<0>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}
+
+B b1 { X<1>{} };
+B b1i = { X<1>{} };
+constexpr B b1c { X<1>{} };
+constexpr B b1ic = { X<1>{} };
+
+B b2 { X<2>{} };
+B b2i = { X<2>{} }; // expected-error {{constructor is explicit}}
+constexpr B b2c { X<2>{} }; // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr}}
+constexpr B b2ic = { X<2>{} }; // expected-error {{constructor is explicit}}
+
+B b3 { X<3>{} };
+B b3i = { X<3>{} }; // expected-error {{constructor is explicit}}
+constexpr B b3c { X<3>{} };
+constexpr B b3ic = { X<3>{} }; // expected-error {{constructor is explicit}}
+
+
+// 'constexpr' is OK even if the constructor doesn't obey the constraints.
+struct NonLiteral { NonLiteral(); };
+struct NonConstexpr { NonConstexpr(); constexpr NonConstexpr(int); }; // expected-note {{here}}
+struct Constexpr { constexpr Constexpr(int) {} };
+
+struct BothNonLiteral : NonLiteral, Constexpr { using Constexpr::Constexpr; }; // expected-note {{base class 'NonLiteral' of non-literal type}}
+constexpr BothNonLiteral bothNL{42}; // expected-error {{constexpr variable cannot have non-literal type 'const BothNonLiteral'}}
+
+struct BothNonConstexpr : NonConstexpr, Constexpr { using Constexpr::Constexpr; }; // expected-note {{non-constexpr constructor 'NonConstexpr}}
+constexpr BothNonConstexpr bothNC{42}; // expected-error {{must be initialized by a constant expression}} expected-note {{in call to 'BothNonConstexpr(42)'}}
+
+
+struct ConstexprEval {
+ constexpr ConstexprEval(int a, const char *p) : k(p[a]) {}
+ char k;
+};
+struct ConstexprEval2 {
+ char k2 = 'x';
+};
+struct ConstexprEval3 : ConstexprEval, ConstexprEval2 {
+ using ConstexprEval::ConstexprEval;
+};
+constexpr ConstexprEval3 ce{4, "foobar"};
+static_assert(ce.k == 'a', "");
+static_assert(ce.k2 == 'x', "");
diff --git a/test/CXX/special/class.inhctor/p3.cpp b/test/CXX/special/class.inhctor/p3.cpp
index d7093fb..f71ab16 100644
--- a/test/CXX/special/class.inhctor/p3.cpp
+++ b/test/CXX/special/class.inhctor/p3.cpp
@@ -5,7 +5,7 @@ struct B1 {
B1(int, int);
};
struct D1 : B1 {
- using B1::B1; // expected-error {{not supported}}
+ using B1::B1;
};
D1 d1a(1), d1b(1, 1);
@@ -15,7 +15,7 @@ struct B2 {
explicit B2(int, int = 0, int = 0);
};
struct D2 : B2 { // expected-note 2 {{candidate constructor}}
- using B2::B2; // expected-error {{not supported}}
+ using B2::B2;
};
D2 d2a(1), d2b(1, 1), d2c(1, 1, 1);
@@ -25,18 +25,18 @@ struct B3 {
B3(void*); // expected-note {{inherited from here}}
};
struct D3 : B3 { // expected-note 2 {{candidate constructor}}
- using B3::B3; // expected-note {{candidate constructor (inherited)}} expected-error {{not supported}}
+ using B3::B3; // expected-note {{candidate constructor (inherited)}}
};
D3 fd3() { return 1; } // expected-error {{no viable conversion}}
template<typename T> struct T1 : B1 {
- using B1::B1; // expected-error {{not supported}}
+ using B1::B1;
};
template<typename T> struct T2 : T1<T> {
- using T1<int>::T1; // expected-error {{not supported}}
+ using T1<int>::T1;
};
template<typename T> struct T3 : T1<int> {
- using T1<T>::T1; // expected-error {{not supported}}
+ using T1<T>::T1;
};
struct U {
friend T1<int>::T1(int);
diff --git a/test/CXX/special/class.inhctor/p4.cpp b/test/CXX/special/class.inhctor/p4.cpp
new file mode 100644
index 0000000..eea3bf2
--- /dev/null
+++ b/test/CXX/special/class.inhctor/p4.cpp
@@ -0,0 +1,70 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+template<int> struct X {};
+
+// A[n inheriting] constructor [...] has the same access as the corresponding
+// constructor [in the base class].
+struct A {
+public:
+ A(X<0>) {}
+protected:
+ A(X<1>) {}
+private:
+ A(X<2>) {} // expected-note {{declared private here}}
+ friend class FA;
+};
+
+struct B : A {
+ using A::A; // expected-error {{private constructor}} expected-note {{implicitly declared protected here}}
+ friend class FB;
+};
+
+B b0{X<0>{}};
+B b1{X<1>{}}; // expected-error {{calling a protected constructor}}
+B b2{X<2>{}}; // expected-note {{first required here}}
+
+struct C : B {
+ C(X<0> x) : B(x) {}
+ C(X<1> x) : B(x) {}
+};
+
+struct FB {
+ B b0{X<0>{}};
+ B b1{X<1>{}};
+};
+
+struct FA : A {
+ using A::A; // expected-note 2{{here}}
+};
+FA fa0{X<0>{}};
+FA fa1{X<1>{}}; // expected-error {{calling a protected constructor}}
+FA fa2{X<2>{}}; // expected-error {{calling a private constructor}}
+
+
+// It is deleted if the corresponding constructor [...] is deleted.
+struct G {
+ G(int) = delete;
+};
+struct H : G {
+ using G::G; // expected-note {{marked deleted here}}
+};
+H h(5); // expected-error {{call to implicitly-deleted function of 'H'}}
+
+
+// Core defect: It is also deleted if multiple base constructors generate the
+// same signature.
+namespace DRnnnn {
+ struct A {
+ constexpr A(int, float = 0) {}
+ explicit A(int, int = 0) {}
+
+ A(int, int, int = 0) = delete;
+ };
+ struct B : A {
+ // FIXME: produce notes indicating why it was deleted
+ using A::A; // expected-note {{here}}
+ };
+
+ constexpr B b0(0, 0.0f); // ok, constexpr
+ B b1(0, 1); // expected-error {{call to implicitly-deleted}}
+}
diff --git a/test/CXX/special/class.inhctor/p7.cpp b/test/CXX/special/class.inhctor/p7.cpp
index bfaa3ac..9ae160f 100644
--- a/test/CXX/special/class.inhctor/p7.cpp
+++ b/test/CXX/special/class.inhctor/p7.cpp
@@ -8,12 +8,12 @@ struct B2 {
B2(int); // expected-note {{conflicting constructor}}
};
struct D1 : B1, B2 {
- using B1::B1; // expected-note {{inherited here}} expected-error {{not supported}}
- using B2::B2; // expected-error {{already inherited constructor with the same signature}} expected-error {{not supported}}
+ using B1::B1; // expected-note {{inherited here}}
+ using B2::B2; // expected-error {{already inherited constructor with the same signature}}
};
struct D2 : B1, B2 {
- using B1::B1; // expected-error {{not supported}}
- using B2::B2; // expected-error {{not supported}}
+ using B1::B1;
+ using B2::B2;
D2(int);
};
@@ -22,8 +22,8 @@ template<typename T> struct B3 {
};
template<typename T> struct B4 : B3<T>, B1 {
B4();
- using B3<T>::B3; // expected-note {{inherited here}} expected-error {{not supported}}
- using B1::B1; // expected-error {{already inherited}} expected-error {{not supported}}
+ using B3<T>::B3; // expected-note {{inherited here}}
+ using B1::B1; // expected-error {{already inherited}}
};
B4<char> b4c;
B4<int> b4i; // expected-note {{here}}
diff --git a/test/CXX/special/class.inhctor/p8.cpp b/test/CXX/special/class.inhctor/p8.cpp
new file mode 100644
index 0000000..e2b07df
--- /dev/null
+++ b/test/CXX/special/class.inhctor/p8.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+// expected-no-diagnostics
+struct A {
+ constexpr A(const int&) : rval(false) {}
+ constexpr A(const int&&) : rval(true) {}
+ bool rval;
+};
+struct B : A {
+ using A::A;
+};
+
+constexpr int k = 0;
+constexpr A a0{0};
+constexpr A a1{k};
+constexpr B b0{0};
+// This performs static_cast<(const int&)&&>(k), so calls the A(const int&)
+// constructor.
+constexpr B b1{k};
+
+static_assert(a0.rval && !a1.rval && b0.rval && !b1.rval, "");
diff --git a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
index 726e222..9453798 100644
--- a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
+++ b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
@@ -351,6 +351,15 @@ void test_unexpanded_exprs(Types ...values) {
// FIXME: Objective-C expressions will need to go elsewhere
for (auto t : values) { } // expected-error{{expression contains unexpanded parameter pack 'values'}}
+
+ switch (values) { } // expected-error{{expression contains unexpanded parameter pack 'values'}}
+
+ do { } while (values); // expected-error{{expression contains unexpanded parameter pack 'values'}}
+
+test:
+ goto *values; // expected-error{{expression contains unexpanded parameter pack 'values'}}
+
+ void f(int arg = values); // expected-error{{default argument contains unexpanded parameter pack 'values'}}
}
// Test unexpanded parameter packs in partial specializations.
diff --git a/test/CXX/temp/temp.decls/temp.variadic/p5.mm b/test/CXX/temp/temp.decls/temp.variadic/p5.mm
new file mode 100644
index 0000000..d059826
--- /dev/null
+++ b/test/CXX/temp/temp.decls/temp.variadic/p5.mm
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -fobjc-exceptions -fexceptions -std=c++11 -fblocks -fsyntax-only -verify %s
+
+template<typename...Types>
+void f(Types ...values) {
+ for (id x in values) { } // expected-error {{expression contains unexpanded parameter pack 'values'}}
+ @synchronized(values) { // expected-error {{expression contains unexpanded parameter pack 'values'}}
+ @throw values; // expected-error {{expression contains unexpanded parameter pack 'values'}}
+ }
+}
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 36b0700..dcf5a08 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
@@ -26,3 +26,24 @@ namespace ParameterPacksWithFunctions {
unsigned_c<2> uc2 = f<float, double>();
}
}
+
+namespace rdar12176336 {
+ typedef void (*vararg_func)(...);
+
+ struct method {
+ vararg_func implementation;
+
+ method(vararg_func implementation) : implementation(implementation) {}
+
+ template<typename TReturnType, typename... TArguments, typename TFunctionType = TReturnType (*)(TArguments...)>
+ auto getImplementation() const -> TFunctionType
+ {
+ return reinterpret_cast<TFunctionType>(implementation);
+ }
+ };
+
+ void f() {
+ method m(nullptr);
+ auto imp = m.getImplementation<int, int, int>();
+ }
+}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp
index 90d2949..33efac0 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp
@@ -15,8 +15,7 @@ void test_f1(int *ip, float fv) {
f1(ip, fv);
}
-// TODO: this diagnostic can and should improve
-template<typename T> void f2(T*, T*); // expected-note {{candidate template ignored: failed template argument deduction}} \
+template<typename T> void f2(T*, T*); // expected-note {{candidate template ignored: could not match 'T *' against 'ConvToIntPtr'}} \
// expected-note{{candidate template ignored: deduced conflicting types for parameter 'T' ('int' vs. 'float')}}
struct ConvToIntPtr {
@@ -28,3 +27,21 @@ void test_f2(int *ip, float *fp) {
f2(ip, ip); // okay
f2(ip, fp); // expected-error{{no matching function}}
}
+
+namespace test3 {
+ template<typename T>
+ struct bar { };
+
+ template<typename T>
+ struct foo {
+ operator bar<T>();
+ };
+
+ template<typename T>
+ void func(bar<T>) { // expected-note {{candidate template ignored: could not match 'bar' against 'foo'}}
+ }
+
+ void test() {
+ func(foo<int>()); // expected-error {{no matching function}}
+ }
+}
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp
index 8b192fa..cd1d9f1 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p1-0x.cpp
@@ -53,8 +53,9 @@ void test_simple_ref_deduction(int *ip, float *fp, double *dp) {
}
+// FIXME: Use the template parameter names in this diagnostic.
template<typename ...Args1, typename ...Args2>
-typename get_nth_type<0, Args1...>::type first_arg_pair(pair<Args1, Args2>...); // expected-note{{candidate template ignored: failed template argument deduction}}
+typename get_nth_type<0, Args1...>::type first_arg_pair(pair<Args1, Args2>...); // expected-note{{candidate template ignored: could not match 'pair<type-parameter-0-0, type-parameter-0-1>' against 'int'}}
template<typename ...Args1, typename ...Args2>
typename get_nth_type<1, Args1...>::type second_arg_pair(pair<Args1, Args2>...);
diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp
index 7774b5c..d7989e3 100644
--- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp
+++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p9-0x.cpp
@@ -53,3 +53,16 @@ namespace DeduceNonTypeTemplateArgsInArray {
tuple<unsigned_c<1>, unsigned_c<2>, unsigned_c<3>>
>::value? 1 : -1];
}
+
+namespace DeduceWithDefaultArgs {
+ template<template<typename...> class Container> void f(Container<int>); // expected-note {{substitution failure [with Container = X]}}
+ template<typename, typename = int> struct X {};
+ void g() {
+ // OK, use default argument for the second template parameter.
+ f(X<int>{});
+ f(X<int, int>{});
+
+ // Not OK.
+ f(X<int, double>{}); // expected-error {{no matching function for call to 'f'}}
+ }
+}
diff --git a/test/CXX/temp/temp.res/temp.dep/p3.cpp b/test/CXX/temp/temp.res/temp.dep/p3.cpp
index 88b4752..583fb4b 100644
--- a/test/CXX/temp/temp.res/temp.dep/p3.cpp
+++ b/test/CXX/temp/temp.res/temp.dep/p3.cpp
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-// expected-no-diagnostics
struct A0 {
struct K { };
};
@@ -42,3 +41,49 @@ namespace E2 {
Y<A> ya;
}
+
+namespace PR14402 {
+ template<typename T>
+ struct A {
+ typedef int n;
+ int f();
+
+ struct B {};
+ struct C : B {
+ // OK, can't be sure whether we derive from A yet.
+ using A::n;
+ int g() { return f(); }
+ };
+
+ struct D {
+ using A::n; // expected-error {{using declaration refers into 'A<T>::', which is not a base class of 'D'}}
+ int g() { return f(); } // expected-error {{call to non-static member function 'f' of 'A' from nested type 'D'}}
+ };
+
+ struct E { char &f(); };
+ struct F : E {
+ // FIXME: Reject this prior to instantiation; f() is known to return int.
+ char &g() { return f(); }
+ // expected-error@-1 {{'PR14402::A<int>::f' is not a member of class 'PR14402::A<int>::F'}}
+ // expected-error@-2 {{non-const lvalue reference to type 'char' cannot bind to a temporary of type 'int'}}
+ };
+ };
+
+ template<> struct A<int>::B : A<int> {};
+ A<int>::C::n n = A<int>::C().g();
+
+ // 'not a member'
+ char &r = A<int>::F().g(); // expected-note {{in instantiation of}}
+ template<> struct A<char>::E : A<char> {};
+ // 'cannot bind to a temporary'
+ char &s = A<char>::F().g(); // expected-note {{in instantiation of}}
+
+ struct X;
+ struct X { void f(); };
+ struct X;
+ template<typename T> struct Y : X {
+ void g() {
+ X::f();
+ }
+ };
+}
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp
index b0a19fb..75b198e 100644
--- a/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp
+++ b/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp
@@ -300,3 +300,8 @@ template<> template<typename T>
void has_inline_namespaces::X0<X4>::mem_func_template(T&) { }
template<> int has_inline_namespaces::X0<X4>::value = 13;
+
+namespace PR12938 {
+ template<typename> [[noreturn]] void func();
+ template<> void func<int>();
+}
diff --git a/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp b/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp
index 80f0598..e0c7b35 100644
--- a/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp
+++ b/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp
@@ -12,7 +12,7 @@ struct Y {
constexpr int f() { return 0; }
};
-template constexpr int Y<int>::f(); // expected-error{{explicit instantiation cannot be 'constexpr'}}
+template constexpr int Y<int>::f() const; // expected-error{{explicit instantiation cannot be 'constexpr'}}
template<typename T>
struct Z {
diff --git a/test/CodeCompletion/constexpr.cpp b/test/CodeCompletion/constexpr.cpp
new file mode 100644
index 0000000..12396c0
--- /dev/null
+++ b/test/CodeCompletion/constexpr.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -code-completion-at=%s:12:9 %s -o - | FileCheck %s
+
+// PR14381: need constexpr function bodies always, even if code-completing.
+template<int> struct S;
+template<> struct S<1> {
+ typedef int type;
+};
+constexpr int f() {
+ return 1;
+}
+
+S<f()>::
+// CHECK: COMPLETION: type : type
diff --git a/test/CodeGen/2006-01-13-StackSave.c b/test/CodeGen/2006-01-13-StackSave.c
index 7c506b3..82f4584 100644
--- a/test/CodeGen/2006-01-13-StackSave.c
+++ b/test/CodeGen/2006-01-13-StackSave.c
@@ -1,6 +1,6 @@
// PR691
-// RUN: %clang_cc1 %s -emit-llvm -o - | opt -std-compile-opts | \
-// RUN: llvm-dis | grep llvm.stacksave
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// CHECK: call i8* @llvm.stacksave()
void test(int N) {
int i;
diff --git a/test/CodeGen/2007-06-18-SextAttrAggregate.c b/test/CodeGen/2007-06-18-SextAttrAggregate.c
index 27ae6a9..f548951 100644
--- a/test/CodeGen/2007-06-18-SextAttrAggregate.c
+++ b/test/CodeGen/2007-06-18-SextAttrAggregate.c
@@ -1,6 +1,14 @@
// RUN: %clang_cc1 %s -o - -emit-llvm | FileCheck %s
+// XFAIL: aarch64
+
// PR1513
+// AArch64 ABI actually requires the reverse of what this is testing: the callee
+// does any extensions and remaining bits are unspecified.
+
+// Technically this test wasn't written to test that feature, but it's a
+// valuable check nevertheless.
+
struct s{
long a;
long b;
diff --git a/test/CodeGen/2008-01-07-UnusualIntSize.c b/test/CodeGen/2008-01-07-UnusualIntSize.c
index bf0ca55..c37c89e 100644
--- a/test/CodeGen/2008-01-07-UnusualIntSize.c
+++ b/test/CodeGen/2008-01-07-UnusualIntSize.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// FIXME: 32-bit target?
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -emit-llvm -o - | FileCheck %s
// PR1721
struct s {
@@ -8,8 +9,8 @@ struct s {
// This should have %0 and %1 truncated to 33 bits before any operation.
// This can be done using i33 or an explicit and.
_Bool test(void) {
- // CHECK: and i64 %[[TMP1:[0-9]+]], 8589934591
+ // CHECK: and i64 %[[TMP1:[^,]+]], 8589934591
// CHECK-NOT: and i64 [[TMP1]], 8589934591
- // CHECK: and i64 %{{[0-9]}}, 8589934591
+ // CHECK: and i64 %{{[^,]+}}, 8589934591
return a.u33 + b.u33 != 0;
}
diff --git a/test/CodeGen/2008-04-08-NoExceptions.c b/test/CodeGen/2008-04-08-NoExceptions.c
index ab2781b..1213492 100644
--- a/test/CodeGen/2008-04-08-NoExceptions.c
+++ b/test/CodeGen/2008-04-08-NoExceptions.c
@@ -2,9 +2,11 @@
void f(void);
void g(void) {
- // CHECK: define void @g() nounwind
+ // CHECK: define void @g() [[NUW:#[0-9]+]]
// CHECK-NOT: call void @f() nounwind
f();
}
-// CHECK-NOT: declare void @f() nounwind
+// CHECK-NOT: declare void @f() [[NUW]]
+
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGen/2008-07-30-implicit-initialization.c b/test/CodeGen/2008-07-30-implicit-initialization.c
index 8c719bb..e516259 100644
--- a/test/CodeGen/2008-07-30-implicit-initialization.c
+++ b/test/CodeGen/2008-07-30-implicit-initialization.c
@@ -1,6 +1,10 @@
-// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm-bc -o - %s | opt --std-compile-opts | llvm-dis > %t
-// RUN: grep "ret i32" %t | count 2
-// RUN: grep "ret i32 0" %t | count 2
+// RUN: %clang_cc1 -triple i386-unknown-unknown -O1 -emit-llvm -o - %s | FileCheck %s
+// CHECK: define i32 @f0()
+// CHECK: ret i32 0
+// CHECK: define i32 @f1()
+// CHECK: ret i32 0
+// CHECK: define i32 @f2()
+// CHECK: ret i32 0
// <rdar://problem/6113085>
struct s0 {
@@ -12,14 +16,10 @@ int f0() {
return x.y;
}
-#if 0
-/* Optimizer isn't smart enough to reduce this since we use
- memset. Hrm. */
int f1() {
struct s0 x[2] = { {0} };
return x[1].x;
}
-#endif
int f2() {
int x[2] = { 0 };
diff --git a/test/CodeGen/2008-07-31-promotion-of-compound-pointer-arithmetic.c b/test/CodeGen/2008-07-31-promotion-of-compound-pointer-arithmetic.c
index de06263..429fb1f 100644
--- a/test/CodeGen/2008-07-31-promotion-of-compound-pointer-arithmetic.c
+++ b/test/CodeGen/2008-07-31-promotion-of-compound-pointer-arithmetic.c
@@ -1,4 +1,10 @@
-// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm-bc -o - %s | opt -std-compile-opts | llvm-dis | grep "ret i32 1" | count 3
+// RUN: %clang_cc1 -triple i386-unknown-unknown -O1 -emit-llvm -o - %s | FileCheck %s
+// CHECK: define i32 @f0
+// CHECK: ret i32 1
+// CHECK: define i32 @f1
+// CHECK: ret i32 1
+// CHECK: define i32 @f2
+// CHECK: ret i32 1
// <rdr://6115726>
int f0() {
diff --git a/test/CodeGen/2009-10-20-GlobalDebug.c b/test/CodeGen/2009-10-20-GlobalDebug.c
index 8a9dfdd..c48ad28 100644
--- a/test/CodeGen/2009-10-20-GlobalDebug.c
+++ b/test/CodeGen/2009-10-20-GlobalDebug.c
@@ -6,5 +6,5 @@ int main() {
return 0;
}
-// CHECK: metadata !{i32 {{.*}}, i32 0, metadata !5, metadata !"localstatic", metadata !"localstatic", metadata !"", metadata !6, i32 5, metadata !9, i32 1, i32 1, i32* @main.localstatic} ; [ DW_TAG_variable ]
-// CHECK: metadata !{i32 {{.*}}, i32 0, null, metadata !"global", metadata !"global", metadata !"", metadata !6, i32 3, metadata !9, i32 0, i32 1, i32* @global} ; [ DW_TAG_variable ]
+// CHECK: metadata !{i32 {{.*}}, i32 0, metadata !{{.*}}, metadata !"localstatic", metadata !"localstatic", metadata !"", metadata !{{.*}}, i32 5, metadata !{{.*}}, i32 1, i32 1, i32* @main.localstatic, null} ; [ DW_TAG_variable ]
+// CHECK: metadata !{i32 {{.*}}, i32 0, null, metadata !"global", metadata !"global", metadata !"", metadata !{{.*}}, i32 3, metadata !{{.*}}, i32 0, i32 1, i32* @global, null} ; [ DW_TAG_variable ]
diff --git a/test/CodeGen/2010-02-16-DbgScopes.c b/test/CodeGen/2010-02-16-DbgScopes.c
index b11f920..36484a4 100644
--- a/test/CodeGen/2010-02-16-DbgScopes.c
+++ b/test/CodeGen/2010-02-16-DbgScopes.c
@@ -1,5 +1,9 @@
-// RUN: %clang_cc1 -emit-llvm -g < %s | grep lexical | count 5
+// RUN: %clang_cc1 -emit-llvm -g < %s | FileCheck %s
// Test to check number of lexical scope identified in debug info.
+// CHECK: DW_TAG_lexical_block
+// CHECK: DW_TAG_lexical_block
+// CHECK: DW_TAG_lexical_block
+// CHECK: DW_TAG_lexical_block
extern int bar();
extern void foobar();
diff --git a/test/CodeGen/2010-03-5-LexicalScope.c b/test/CodeGen/2010-03-5-LexicalScope.c
index 0f63ff6..e0e41dd 100644
--- a/test/CodeGen/2010-03-5-LexicalScope.c
+++ b/test/CodeGen/2010-03-5-LexicalScope.c
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -emit-llvm -O0 -g %s -o - | grep DW_TAG_lexical_block | count 3
+// RUN: %clang_cc1 -emit-llvm -O0 -g %s -o - | FileCheck %s
+// CHECK: DW_TAG_lexical_block
+// CHECK: DW_TAG_lexical_block
int foo(int i) {
if (i) {
int j = 2;
diff --git a/test/CodeGen/PR4611-bitfield-layout.c b/test/CodeGen/PR4611-bitfield-layout.c
index 3975ed0..a383f34 100644
--- a/test/CodeGen/PR4611-bitfield-layout.c
+++ b/test/CodeGen/PR4611-bitfield-layout.c
@@ -1,5 +1,6 @@
-// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o %t
-// RUN: grep "struct.object_entry = type { i8, \[2 x i8\], i8 }" %t
+// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s
+//
+// CHECK: struct.object_entry = type { [4 x i8] }
struct object_entry {
unsigned int type:3, pack_id:16, depth:13;
diff --git a/test/CodeGen/a5.c b/test/CodeGen/a5.c
new file mode 100644
index 0000000..b342d35
--- /dev/null
+++ b/test/CodeGen/a5.c
@@ -0,0 +1,5 @@
+// RUN: %clang -target armv7-none-linux-gnueabi -mcpu=cortex-a5 -emit-llvm -S %s -o /dev/null
+
+int main() {
+ return 0;
+}
diff --git a/test/CodeGen/aarch64-arguments.c b/test/CodeGen/aarch64-arguments.c
new file mode 100644
index 0000000..901e734
--- /dev/null
+++ b/test/CodeGen/aarch64-arguments.c
@@ -0,0 +1,194 @@
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -emit-llvm -w -o - %s | FileCheck -check-prefix=PCS %s
+
+// Sign extension is performed by the callee on AArch64, which means
+// that we *shouldn't* tag arguments and returns with their extension.
+
+// PCS: define i8 @f0(i16 %a)
+char f0(short a) {
+ return a;
+}
+
+// PCS: define [1 x i64] @f1()
+struct s1 { char f0; };
+struct s1 f1(void) {}
+
+// PCS: define [1 x i64] @f2()
+struct s2 { short f0; };
+struct s2 f2(void) {}
+
+// PCS: define [1 x i64] @f3()
+struct s3 { int f0; };
+struct s3 f3(void) {}
+
+// PCS: define [1 x i64] @f4()
+struct s4 { struct s4_0 { int f0; } f0; };
+struct s4 f4(void) {}
+
+// PCS: define [1 x i64] @f5()
+struct s5 { struct { } f0; int f1; };
+struct s5 f5(void) {}
+
+// PCS: define [1 x i64] @f6()
+struct s6 { int f0[1]; };
+struct s6 f6(void) {}
+
+// PCS: define void @f7()
+struct s7 { struct { int : 0; } f0; };
+struct s7 f7(void) {}
+
+// PCS: define void @f8()
+struct s8 { struct { int : 0; } f0[1]; };
+struct s8 f8(void) {}
+
+// PCS: define [1 x i64] @f9()
+struct s9 { long f0; int : 0; };
+struct s9 f9(void) {}
+
+// PCS: define [1 x i64] @f10()
+struct s10 { long f0; int : 0; int : 0; };
+struct s10 f10(void) {}
+
+// PCS: define [1 x i64] @f11()
+struct s11 { int : 0; long f0; };
+struct s11 f11(void) {}
+
+// PCS: define [1 x i64] @f12()
+union u12 { char f0; short f1; int f2; long f3; };
+union u12 f12(void) {}
+
+// PCS: define %struct.s13 @f13()
+struct s13 { float f0; };
+struct s13 f13(void) {}
+
+// PCS: define %union.u14 @f14()
+union u14 { float f0; };
+union u14 f14(void) {}
+
+// PCS: define void @f15()
+void f15(struct s7 a0) {}
+
+// PCS: define void @f16()
+void f16(struct s8 a0) {}
+
+// PCS: define [1 x i64] @f17()
+struct s17 { short f0 : 13; char f1 : 4; };
+struct s17 f17(void) {}
+
+// PCS: define [1 x i64] @f18()
+struct s18 { short f0; char f1 : 4; };
+struct s18 f18(void) {}
+
+// PCS: define [1 x i64] @f19()
+struct s19 { long f0; struct s8 f1; };
+struct s19 f19(void) {}
+
+// PCS: define [1 x i64] @f20()
+struct s20 { struct s8 f1; long f0; };
+struct s20 f20(void) {}
+
+// PCS: define [1 x i64] @f21()
+struct s21 { struct {} f1; long f0 : 4; };
+struct s21 f21(void) {}
+
+// PCS: define { float, float } @f22()
+// PCS: define { double, double } @f23(
+_Complex float f22(void) {}
+_Complex double f23(void) {}
+
+// PCS: define [1 x i64] @f24()
+struct s24 { _Complex char f0; };
+struct s24 f24() {}
+
+// PCS: define [1 x i64] @f25()
+struct s25 { _Complex short f0; };
+struct s25 f25() {}
+
+// PCS: define [1 x i64] @f26()
+struct s26 { _Complex int f0; };
+struct s26 f26() {}
+
+// PCS: define [2 x i64] @f27()
+struct s27 { _Complex long f0; };
+struct s27 f27() {}
+
+// PCS: define void @f28(i8 %a, i16 %b, i32 %c, i64 %d, float %e, double %f)
+void f28(char a, short b, int c, long d, float e, double f) {}
+
+// PCS: define void @f29([2 x i64] %a
+struct s29 { int arr[4]; };
+void f29(struct s29 a) {}
+
+// PCS: define void @f30(%struct.s30* %a)
+struct s30 { int arr[4]; char c;};
+void f30(struct s30 a) {}
+
+// PCS: define void @f31([4 x double] %a
+struct s31 { double arr[4]; };
+void f31(struct s31 a) {}
+
+// PCS: define void @f32(%struct.s32* %a)
+struct s32 { float arr[5]; };
+void f32(struct s32 a) {}
+
+// Not the only solution, but it *is* an HFA.
+// PCS: define void @f33([3 x float] %a.coerce0, float %a.coerce1)
+struct s33 { float arr[3]; float a; };
+void f33(struct s33 a) {}
+
+// PCS: define void @f34(%struct.s34* noalias sret
+struct s34 { int a[4]; char b };
+struct s34 f34(void) {}
+
+// PCS: define void @f35()
+struct s35 {};
+void f35(struct s35 a) {}
+
+// Check padding is added:
+// PCS: @f36(i32 %x0, i32 %x1, i32 %x2, i32 %x3, i32 %x4, i32 %x5, i32 %x6, [1 x i64], %struct.s36* byval align 8 %stacked)
+struct s36 { long a, b; };
+void f36(int x0, int x1, int x2, int x3, int x4, int x5, int x6, struct s36 stacked) {}
+
+// But only once:
+// PCS: @f37(i32 %x0, i32 %x1, i32 %x2, i32 %x3, i32 %x4, i32 %x5, i32 %x6, [1 x i64], %struct.s37* byval align 8 %stacked, %struct.s37* byval align 8 %stacked2)
+struct s37 { long a, b; };
+void f37(int x0, int x1, int x2, int x3, int x4, int x5, int x6, struct s37 stacked, struct s37 stacked2) {}
+
+// Check for HFA padding args. Also, they should not end up on the stack in a
+// way which will have holes in when lowered further by LLVM. In particular [3 x
+// float] would be unacceptable.
+
+// PCS: @f38(float %s0, double %d1, float %s2, float %s3, float %s4, float %s5, [2 x float], %struct.s38* byval align 4 %stacked)
+struct s38 { float a, b, c; };
+void f38(float s0, double d1, float s2, float s3, float s4, float s5, struct s38 stacked) {}
+
+// Check both VFP and integer arguments are padded (also that pointers and enums
+// get counted as integer types correctly).
+struct s39_int { long a, b; };
+struct s39_float { float a, b, c, d; };
+enum s39_enum { Val1, Val2 };
+// PCS: @f39(float %s0, i32 %x0, float %s1, i32* %x1, float %s2, i32 %x2, float %s3, float %s4, i32 %x3, [3 x float], %struct.s39_float* byval align 4 %stacked, i32 %x4, i32 %x5, i32 %x6, [1 x i64], %struct.s39_int* byval align 8 %stacked2)
+void f39(float s0, int x0, float s1, int *x1, float s2, enum s39_enum x2, float s3, float s4,
+ int x3, struct s39_float stacked, int x4, int x5, int x6,
+ struct s39_int stacked2) {}
+
+struct s40 { __int128 a; };
+// PCS: @f40(i32 %x0, [1 x i128] %x2_3.coerce, i32 %x4, i32 %x5, i32 %x6, [1 x i64], %struct.s40* byval align 16 %stacked)
+void f40(int x0, struct s40 x2_3, int x4, int x5, int x6, struct s40 stacked) {}
+
+// Checking: __int128 will get properly aligned type, with padding so big struct doesn't use x7.
+struct s41 { int arr[5]; };
+// PCS: @f41(i32 %x0, i32 %x1, i32 %x2, i32 %x3, i32 %x4, i32 %x5, i32 %x6, [1 x i64], i128* byval align 16, %struct.s41* %stacked2)
+int f41(int x0, int x1, int x2, int x3, int x4, int x5, int x6, __int128 stacked, struct s41 stacked2) {}
+
+// Checking: __int128 needing to be aligned in registers will consume correct
+// number. Previously padding was inserted before "stacked" because x6_7 was
+// "allocated" to x5 and x6 by clang.
+// PCS: @f42(i32 %x0, i32 %x1, i32 %x2, i32 %x3, i32 %x4, i128 %x6_7, i128* byval align 16)
+void f42(int x0, int x1, int x2, int x3, int x4, __int128 x6_7, __int128 stacked) {}
+
+// Checking: __fp16 is extended to double when calling variadic functions
+void variadic(int a, ...);
+void f43(__fp16 *in) {
+ variadic(42, *in);
+// CHECK: call void @variadic(i32 42, double
+}
diff --git a/test/CodeGen/aarch64-inline-asm.c b/test/CodeGen/aarch64-inline-asm.c
new file mode 100644
index 0000000..ca39c6e
--- /dev/null
+++ b/test/CodeGen/aarch64-inline-asm.c
@@ -0,0 +1,56 @@
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+// The only part clang really deals with is the lvalue/rvalue
+// distinction on constraints. It's sufficient to emit llvm and make
+// sure that's sane.
+
+long var;
+
+void test_generic_constraints(int var32, long var64) {
+ asm("add %0, %1, %1" : "=r"(var32) : "0"(var32));
+// CHECK: [[R32_ARG:%[a-zA-Z0-9]+]] = load i32*
+// CHECK: call i32 asm "add $0, $1, $1", "=r,0"(i32 [[R32_ARG]])
+
+ asm("add %0, %1, %1" : "=r"(var64) : "0"(var64));
+// CHECK: [[R32_ARG:%[a-zA-Z0-9]+]] = load i64*
+// CHECK: call i64 asm "add $0, $1, $1", "=r,0"(i64 [[R32_ARG]])
+
+ asm("ldr %0, %1" : "=r"(var32) : "m"(var));
+ asm("ldr %0, [%1]" : "=r"(var64) : "r"(&var));
+// CHECK: call i32 asm "ldr $0, $1", "=r,*m"(i64* @var)
+// CHECK: call i64 asm "ldr $0, [$1]", "=r,r"(i64* @var)
+}
+
+float f;
+double d;
+void test_constraint_w() {
+ asm("fadd %s0, %s1, %s1" : "=w"(f) : "w"(f));
+// CHECK: [[FLT_ARG:%[a-zA-Z_0-9]+]] = load float* @f
+// CHECK: call float asm "fadd ${0:s}, ${1:s}, ${1:s}", "=w,w"(float [[FLT_ARG]])
+
+ asm("fadd %d0, %d1, %d1" : "=w"(d) : "w"(d));
+// CHECK: [[DBL_ARG:%[a-zA-Z_0-9]+]] = load double* @d
+// CHECK: call double asm "fadd ${0:d}, ${1:d}, ${1:d}", "=w,w"(double [[DBL_ARG]])
+}
+
+void test_constraints_immed(void) {
+ asm("add x0, x0, %0" : : "I"(4095) : "x0");
+ asm("and w0, w0, %0" : : "K"(0xaaaaaaaa) : "w0");
+ asm("and x0, x0, %0" : : "L"(0xaaaaaaaaaaaaaaaa) : "x0");
+// CHECK: call void asm sideeffect "add x0, x0, $0", "I,~{x0}"(i32 4095)
+// CHECK: call void asm sideeffect "and w0, w0, $0", "K,~{w0}"(i32 -1431655766)
+// CHECK: call void asm sideeffect "and x0, x0, $0", "L,~{x0}"(i64 -6148914691236517206)
+}
+
+void test_constraint_S(void) {
+ int *addr;
+ asm("adrp %0, %A1\n\t"
+ "add %0, %0, %L1" : "=r"(addr) : "S"(&var));
+// CHECK: call i32* asm "adrp $0, ${1:A}\0A\09add $0, $0, ${1:L}", "=r,S"(i64* @var)
+}
+
+void test_constraint_Q(void) {
+ int val;
+ asm("ldxr %0, %1" : "=r"(val) : "Q"(var));
+// CHECK: call i32 asm "ldxr $0, $1", "=r,*Q"(i64* @var)
+}
diff --git a/test/CodeGen/aarch64-type-sizes.c b/test/CodeGen/aarch64-type-sizes.c
new file mode 100644
index 0000000..3b9c9fc
--- /dev/null
+++ b/test/CodeGen/aarch64-type-sizes.c
@@ -0,0 +1,90 @@
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -emit-llvm -w -o - %s | FileCheck %s
+
+// char by definition has size 1
+
+int check_short() {
+ return sizeof(short);
+// CHECK: ret i32 2
+}
+
+int check_int() {
+ return sizeof(int);
+// CHECK: ret i32 4
+}
+
+int check_long() {
+// Both 4 and 8 are permitted under the PCS, Linux says 8!
+ return sizeof(long);
+// CHECK: ret i32 8
+}
+
+int check_longlong() {
+ return sizeof(long long);
+// CHECK: ret i32 8
+}
+
+int check_int128() {
+ return sizeof(__int128);
+// CHECK: ret i32 16
+}
+
+int check_fp16() {
+ return sizeof(__fp16);
+// CHECK: ret i32 2
+}
+
+int check_float() {
+ return sizeof(float);
+// CHECK: ret i32 4
+}
+
+int check_double() {
+ return sizeof(double);
+// CHECK: ret i32 8
+}
+
+int check_longdouble() {
+ return sizeof(long double);
+// CHECK: ret i32 16
+}
+
+int check_floatComplex() {
+ return sizeof(float _Complex);
+// CHECK: ret i32 8
+}
+
+int check_doubleComplex() {
+ return sizeof(double _Complex);
+// CHECK: ret i32 16
+}
+
+int check_longdoubleComplex() {
+ return sizeof(long double _Complex);
+// CHECK: ret i32 32
+}
+
+int check_bool() {
+ return sizeof(_Bool);
+// CHECK: ret i32 1
+}
+
+int check_wchar() {
+// PCS allows either unsigned short or unsigned int. Linux again says "bigger!"
+ return sizeof(__WCHAR_TYPE__);
+// CHECK: ret i32 4
+}
+
+int check_wchar_unsigned() {
+ return (__WCHAR_TYPE__)-1 > (__WCHAR_TYPE__)0;
+// CHECK: ret i32 1
+}
+
+enum Small {
+ Item
+};
+
+int foo() {
+ return sizeof(enum Small);
+// CHECK: ret i32 4
+}
+
diff --git a/test/CodeGen/aarch64-varargs.c b/test/CodeGen/aarch64-varargs.c
new file mode 100644
index 0000000..324a070
--- /dev/null
+++ b/test/CodeGen/aarch64-varargs.c
@@ -0,0 +1,238 @@
+// RUN: %clang_cc1 -triple aarch64 -emit-llvm -o - %s | FileCheck %s
+#include <stdarg.h>
+
+// Obviously there's more than one way to implement va_arg. This test should at
+// least prevent unintentional regressions caused by refactoring.
+
+va_list the_list;
+
+int simple_int(void) {
+// CHECK: define i32 @simple_int
+ return va_arg(the_list, int);
+// CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 3)
+// CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
+// CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
+
+// CHECK: [[VAARG_MAYBE_REG]]
+// CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
+// CHECK: store i32 [[NEW_REG_OFFS]], i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 3)
+// CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
+// CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
+
+// CHECK: [[VAARG_IN_REG]]
+// CHECK: [[REG_TOP:%[a-z_0-9]+]] = load i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 1)
+// CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr i8* [[REG_TOP]], i32 [[GR_OFFS]]
+// CHECK: [[FROMREG_ADDR:%[a-z_0-9]+]] = bitcast i8* [[REG_ADDR]] to i32*
+// CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
+
+// CHECK: [[VAARG_ON_STACK]]
+// CHECK: [[STACK:%[a-z_0-9]+]] = load i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 0)
+// CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr i8* [[STACK]], i32 8
+// CHECK: store i8* [[NEW_STACK]], i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 0)
+// CHECK: [[FROMSTACK_ADDR:%[a-z_0-9]+]] = bitcast i8* [[STACK]] to i32*
+// CHECK: br label %[[VAARG_END]]
+
+// CHECK: [[VAARG_END]]
+// CHECK: [[ADDR:%[a-z._0-9]+]] = phi i32* [ [[FROMREG_ADDR]], %[[VAARG_IN_REG]] ], [ [[FROMSTACK_ADDR]], %[[VAARG_ON_STACK]] ]
+// CHECK: [[RESULT:%[a-z_0-9]+]] = load i32* [[ADDR]]
+// CHECK: ret i32 [[RESULT]]
+}
+
+__int128 aligned_int(void) {
+// CHECK: define i128 @aligned_int
+ return va_arg(the_list, __int128);
+// CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 3)
+// CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
+// CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
+
+// CHECK: [[VAARG_MAYBE_REG]]
+// CHECK: [[ALIGN_REGOFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 15
+// CHECK: [[ALIGNED_REGOFFS:%[a-z_0-9]+]] = and i32 [[ALIGN_REGOFFS]], -16
+// CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[ALIGNED_REGOFFS]], 16
+// CHECK: store i32 [[NEW_REG_OFFS]], i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 3)
+// CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
+// CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
+
+// CHECK: [[VAARG_IN_REG]]
+// CHECK: [[REG_TOP:%[a-z_0-9]+]] = load i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 1)
+// CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr i8* [[REG_TOP]], i32 [[ALIGNED_REGOFFS]]
+// CHECK: [[FROMREG_ADDR:%[a-z_0-9]+]] = bitcast i8* [[REG_ADDR]] to i128*
+// CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
+
+// CHECK: [[VAARG_ON_STACK]]
+// CHECK: [[STACK:%[a-z_0-9]+]] = load i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 0)
+// CHECK: [[STACKINT:%[a-z_0-9]+]] = ptrtoint i8* [[STACK]] to i64
+// CHECK: [[ALIGN_STACK:%[a-z_0-9]+]] = add i64 [[STACKINT]], 15
+// CHECK: [[ALIGNED_STACK_INT:%[a-z_0-9]+]] = and i64 [[ALIGN_STACK]], -16
+// CHECK: [[ALIGNED_STACK_PTR:%[a-z_0-9]+]] = inttoptr i64 [[ALIGNED_STACK_INT]] to i8*
+// CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr i8* [[ALIGNED_STACK_PTR]], i32 16
+// CHECK: store i8* [[NEW_STACK]], i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 0)
+// CHECK: [[FROMSTACK_ADDR:%[a-z_0-9]+]] = bitcast i8* [[ALIGNED_STACK_PTR]] to i128*
+// CHECK: br label %[[VAARG_END]]
+
+// CHECK: [[VAARG_END]]
+// CHECK: [[ADDR:%[a-z._0-9]+]] = phi i128* [ [[FROMREG_ADDR]], %[[VAARG_IN_REG]] ], [ [[FROMSTACK_ADDR]], %[[VAARG_ON_STACK]] ]
+// CHECK: [[RESULT:%[a-z_0-9]+]] = load i128* [[ADDR]]
+// CHECK: ret i128 [[RESULT]]
+}
+
+struct bigstruct {
+ int a[10];
+};
+
+struct bigstruct simple_indirect(void) {
+// CHECK: define void @simple_indirect
+ return va_arg(the_list, struct bigstruct);
+// CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 3)
+// CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
+// CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
+
+// CHECK: [[VAARG_MAYBE_REG]]
+// CHECK-NOT: and i32
+// CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
+// CHECK: store i32 [[NEW_REG_OFFS]], i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 3)
+// CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
+// CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
+
+// CHECK: [[VAARG_IN_REG]]
+// CHECK: [[REG_TOP:%[a-z_0-9]+]] = load i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 1)
+// CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr i8* [[REG_TOP]], i32 [[GR_OFFS]]
+// CHECK: [[FROMREG_ADDR:%[a-z_0-9]+]] = bitcast i8* [[REG_ADDR]] to %struct.bigstruct**
+// CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
+
+// CHECK: [[VAARG_ON_STACK]]
+// CHECK: [[STACK:%[a-z_0-9]+]] = load i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 0)
+// CHECK-NOT: and i64
+// CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr i8* [[STACK]], i32 8
+// CHECK: store i8* [[NEW_STACK]], i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 0)
+// CHECK: [[FROMSTACK_ADDR:%[a-z_0-9]+]] = bitcast i8* [[STACK]] to %struct.bigstruct**
+// CHECK: br label %[[VAARG_END]]
+
+// CHECK: [[VAARG_END]]
+// CHECK: [[ADDR:%[a-z._0-9]+]] = phi %struct.bigstruct** [ [[FROMREG_ADDR]], %[[VAARG_IN_REG]] ], [ [[FROMSTACK_ADDR]], %[[VAARG_ON_STACK]] ]
+// CHECK: load %struct.bigstruct** [[ADDR]]
+}
+
+struct aligned_bigstruct {
+ float a;
+ long double b;
+};
+
+struct aligned_bigstruct simple_aligned_indirect(void) {
+// CHECK: define void @simple_aligned_indirect
+ return va_arg(the_list, struct aligned_bigstruct);
+// CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 3)
+// CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0
+// CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
+
+// CHECK: [[VAARG_MAYBE_REG]]
+// CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[GR_OFFS]], 8
+// CHECK: store i32 [[NEW_REG_OFFS]], i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 3)
+// CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
+// CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
+
+// CHECK: [[VAARG_IN_REG]]
+// CHECK: [[REG_TOP:%[a-z_0-9]+]] = load i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 1)
+// CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr i8* [[REG_TOP]], i32 [[GR_OFFS]]
+// CHECK: [[FROMREG_ADDR:%[a-z_0-9]+]] = bitcast i8* [[REG_ADDR]] to %struct.aligned_bigstruct**
+// CHECK: br label %[[VAARG_END:[a-z._0-9]+]]
+
+// CHECK: [[VAARG_ON_STACK]]
+// CHECK: [[STACK:%[a-z_0-9]+]] = load i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 0)
+// CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr i8* [[STACK]], i32 8
+// CHECK: store i8* [[NEW_STACK]], i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 0)
+// CHECK: [[FROMSTACK_ADDR:%[a-z_0-9]+]] = bitcast i8* [[STACK]] to %struct.aligned_bigstruct**
+// CHECK: br label %[[VAARG_END]]
+
+// CHECK: [[VAARG_END]]
+// CHECK: [[ADDR:%[a-z._0-9]+]] = phi %struct.aligned_bigstruct** [ [[FROMREG_ADDR]], %[[VAARG_IN_REG]] ], [ [[FROMSTACK_ADDR]], %[[VAARG_ON_STACK]] ]
+// CHECK: load %struct.aligned_bigstruct** [[ADDR]]
+}
+
+double simple_double(void) {
+// CHECK: define double @simple_double
+ return va_arg(the_list, double);
+// CHECK: [[VR_OFFS:%[a-z_0-9]+]] = load i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 4)
+// CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[VR_OFFS]], 0
+// CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK]], label %[[VAARG_MAYBE_REG]]
+
+// CHECK: [[VAARG_MAYBE_REG]]
+// CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[VR_OFFS]], 16
+// CHECK: store i32 [[NEW_REG_OFFS]], i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 4)
+// CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
+// CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
+
+// CHECK: [[VAARG_IN_REG]]
+// CHECK: [[REG_TOP:%[a-z_0-9]+]] = load i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 2)
+// CHECK: [[REG_ADDR:%[a-z_0-9]+]] = getelementptr i8* [[REG_TOP]], i32 [[VR_OFFS]]
+// CHECK: [[FROMREG_ADDR:%[a-z_0-9]+]] = bitcast i8* [[REG_ADDR]] to double*
+// CHECK: br label %[[VAARG_END]]
+
+// CHECK: [[VAARG_ON_STACK]]
+// CHECK: [[STACK:%[a-z_0-9]+]] = load i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 0)
+// CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr i8* [[STACK]], i32 8
+// CHECK: store i8* [[NEW_STACK]], i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 0)
+// CHECK: [[FROMSTACK_ADDR:%[a-z_0-9]+]] = bitcast i8* [[STACK]] to double*
+// CHECK: br label %[[VAARG_END]]
+
+// CHECK: [[VAARG_END]]
+// CHECK: [[ADDR:%[a-z._0-9]+]] = phi double* [ [[FROMREG_ADDR]], %[[VAARG_IN_REG]] ], [ [[FROMSTACK_ADDR]], %[[VAARG_ON_STACK]] ]
+// CHECK: [[RESULT:%[a-z_0-9]+]] = load double* [[ADDR]]
+// CHECK: ret double [[RESULT]]
+}
+
+struct hfa {
+ float a, b;
+};
+
+struct hfa simple_hfa(void) {
+// CHECK: define %struct.hfa @simple_hfa
+ return va_arg(the_list, struct hfa);
+// CHECK: [[VR_OFFS:%[a-z_0-9]+]] = load i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 4)
+// CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[VR_OFFS]], 0
+// CHECK: br i1 [[EARLY_ONSTACK]], label %[[VAARG_ON_STACK:[a-z_.0-9]+]], label %[[VAARG_MAYBE_REG:[a-z_.0-9]+]]
+
+// CHECK: [[VAARG_MAYBE_REG]]
+// CHECK: [[NEW_REG_OFFS:%[a-z_0-9]+]] = add i32 [[VR_OFFS]], 32
+// CHECK: store i32 [[NEW_REG_OFFS]], i32* getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 4)
+// CHECK: [[INREG:%[a-z_0-9]+]] = icmp sle i32 [[NEW_REG_OFFS]], 0
+// CHECK: br i1 [[INREG]], label %[[VAARG_IN_REG:[a-z_.0-9]+]], label %[[VAARG_ON_STACK]]
+
+// CHECK: [[VAARG_IN_REG]]
+// CHECK: [[REG_TOP:%[a-z_0-9]+]] = load i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 2)
+// CHECK: [[FIRST_REG:%[a-z_0-9]+]] = getelementptr i8* [[REG_TOP]], i32 [[VR_OFFS]]
+// CHECK: [[EL_ADDR:%[a-z_0-9]+]] = getelementptr i8* [[FIRST_REG]], i32 0
+// CHECK: [[EL_TYPED:%[a-z_0-9]+]] = bitcast i8* [[EL_ADDR]] to float*
+// CHECK: [[EL_TMPADDR:%[a-z_0-9]+]] = getelementptr inbounds [2 x float]* %[[TMP_HFA:[a-z_.0-9]+]], i32 0, i32 0
+// CHECK: [[EL:%[a-z_0-9]+]] = load float* [[EL_TYPED]]
+// CHECK: store float [[EL]], float* [[EL_TMPADDR]]
+// CHECK: [[EL_ADDR:%[a-z_0-9]+]] = getelementptr i8* [[FIRST_REG]], i32 16
+// CHECK: [[EL_TYPED:%[a-z_0-9]+]] = bitcast i8* [[EL_ADDR]] to float*
+// CHECK: [[EL_TMPADDR:%[a-z_0-9]+]] = getelementptr inbounds [2 x float]* %[[TMP_HFA]], i32 0, i32 1
+// CHECK: [[EL:%[a-z_0-9]+]] = load float* [[EL_TYPED]]
+// CHECK: store float [[EL]], float* [[EL_TMPADDR]]
+// CHECK: [[FROMREG_ADDR:%[a-z_0-9]+]] = bitcast [2 x float]* %[[TMP_HFA]] to %struct.hfa*
+// CHECK: br label %[[VAARG_END:[a-z_.0-9]+]]
+
+// CHECK: [[VAARG_ON_STACK]]
+// CHECK: [[STACK:%[a-z_0-9]+]] = load i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 0)
+// CHECK: [[NEW_STACK:%[a-z_0-9]+]] = getelementptr i8* [[STACK]], i32 8
+// CHECK: store i8* [[NEW_STACK]], i8** getelementptr inbounds (%struct.__va_list* @the_list, i32 0, i32 0)
+// CHECK: [[FROMSTACK_ADDR:%[a-z_0-9]+]] = bitcast i8* [[STACK]] to %struct.hfa*
+// CHECK: br label %[[VAARG_END]]
+
+// CHECK: [[VAARG_END]]
+// CHECK: [[ADDR:%[a-z._0-9]+]] = phi %struct.hfa* [ [[FROMREG_ADDR]], %[[VAARG_IN_REG]] ], [ [[FROMSTACK_ADDR]], %[[VAARG_ON_STACK]] ]
+}
+
+void check_start(int n, ...) {
+// CHECK: define void @check_start(i32 %n, ...)
+
+ va_list the_list;
+ va_start(the_list, n);
+// CHECK: [[THE_LIST:%[a-z_0-9]+]] = alloca %struct.__va_list
+// CHECK: [[VOIDP_THE_LIST:%[a-z_0-9]+]] = bitcast %struct.__va_list* [[THE_LIST]] to i8*
+// CHECK: call void @llvm.va_start(i8* [[VOIDP_THE_LIST]])
+}
+
+
diff --git a/test/CodeGen/address-safety-attr.cpp b/test/CodeGen/address-safety-attr.cpp
index 5c9862d..f94efd6 100644
--- a/test/CodeGen/address-safety-attr.cpp
+++ b/test/CodeGen/address-safety-attr.cpp
@@ -1,41 +1,80 @@
-// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
-// RUN: %clang_cc1 -emit-llvm -o - %s -fsanitize=address | FileCheck -check-prefix ASAN %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck -check-prefix=WITHOUT %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=address | FileCheck -check-prefix=ASAN %s
+// RUN: echo "src:%s" > %t.file.blacklist
+// RUN: echo "fun:*BlacklistedFunction*" > %t.func.blacklist
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=address -fsanitize-blacklist=%t.file.blacklist | FileCheck -check-prefix=BLFILE %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=address -fsanitize-blacklist=%t.func.blacklist | FileCheck -check-prefix=BLFUNC %s
-// The address_safety attribute should be attached to functions
-// when AddressSanitizer is enabled, unless no_address_safety_analysis attribute
+// FIXME: %t.file.blacklist is like "src:x:\path\to\clang\test\CodeGen\address-safety-attr.cpp"
+// REQUIRES: shell
+
+// The sanitize_address attribute should be attached to functions
+// when AddressSanitizer is enabled, unless no_sanitize_address attribute
// is present.
-// CHECK-NOT: NoAddressSafety1{{.*}} address_safety
-// ASAN-NOT: NoAddressSafety1{{.*}} address_safety
-__attribute__((no_address_safety_analysis))
+// WITHOUT: NoAddressSafety1{{.*}}) [[NOATTR:#[0-9]+]]
+// BLFILE: NoAddressSafety1{{.*}}) [[NOATTR:#[0-9]+]]
+// BLFUNC: NoAddressSafety1{{.*}}) [[NOATTR:#[0-9]+]]
+// ASAN: NoAddressSafety1{{.*}}) [[NOATTR:#[0-9]+]]
+__attribute__((no_sanitize_address))
int NoAddressSafety1(int *a) { return *a; }
-// CHECK-NOT: NoAddressSafety2{{.*}} address_safety
-// ASAN-NOT: NoAddressSafety2{{.*}} address_safety
-__attribute__((no_address_safety_analysis))
+// WITHOUT: NoAddressSafety2{{.*}}) [[NOATTR]]
+// BLFILE: NoAddressSafety2{{.*}}) [[NOATTR]]
+// BLFUNC: NoAddressSafety2{{.*}}) [[NOATTR]]
+// ASAN: NoAddressSafety2{{.*}}) [[NOATTR]]
+__attribute__((no_sanitize_address))
int NoAddressSafety2(int *a);
int NoAddressSafety2(int *a) { return *a; }
-// CHECK-NOT: AddressSafetyOk{{.*}} address_safety
-// ASAN: AddressSafetyOk{{.*}} address_safety
+// WITHOUT: AddressSafetyOk{{.*}}) [[NOATTR]]
+// BLFILE: AddressSafetyOk{{.*}}) [[NOATTR]]
+// BLFUNC: AddressSafetyOk{{.*}}) [[WITH:#[0-9]+]]
+// ASAN: AddressSafetyOk{{.*}}) [[WITH:#[0-9]+]]
int AddressSafetyOk(int *a) { return *a; }
-// CHECK-NOT: TemplateNoAddressSafety{{.*}} address_safety
-// ASAN-NOT: TemplateNoAddressSafety{{.*}} address_safety
-template<int i>
-__attribute__((no_address_safety_analysis))
-int TemplateNoAddressSafety() { return i; }
+// WITHOUT: BlacklistedFunction{{.*}}) [[NOATTR]]
+// BLFILE: BlacklistedFunction{{.*}}) [[NOATTR]]
+// BLFUNC: BlacklistedFunction{{.*}}) [[NOATTR]]
+// ASAN: BlacklistedFunction{{.*}}) [[WITH]]
+int BlacklistedFunction(int *a) { return *a; }
-// CHECK-NOT: TemplateAddressSafetyOk{{.*}} address_safety
-// ASAN: TemplateAddressSafetyOk{{.*}} address_safety
+// WITHOUT: TemplateAddressSafetyOk{{.*}}) [[NOATTR]]
+// BLFILE: TemplateAddressSafetyOk{{.*}}) [[NOATTR]]
+// BLFUNC: TemplateAddressSafetyOk{{.*}}) [[WITH]]
+// ASAN: TemplateAddressSafetyOk{{.*}}) [[WITH]]
template<int i>
int TemplateAddressSafetyOk() { return i; }
+// WITHOUT: TemplateNoAddressSafety{{.*}}) [[NOATTR]]
+// BLFILE: TemplateNoAddressSafety{{.*}}) [[NOATTR]]
+// BLFUNC: TemplateNoAddressSafety{{.*}}) [[NOATTR]]
+// ASAN: TemplateNoAddressSafety{{.*}}) [[NOATTR]]
+template<int i>
+__attribute__((no_sanitize_address))
+int TemplateNoAddressSafety() { return i; }
+
int force_instance = TemplateAddressSafetyOk<42>()
+ TemplateNoAddressSafety<42>();
-// Check that __cxx_global_var_init* get the address_safety attribute.
+// Check that __cxx_global_var_init* get the sanitize_address attribute.
int global1 = 0;
int global2 = *(int*)((char*)&global1+1);
-// CHECK-NOT: @__cxx_global_var_init{{.*}}address_safety
-// ASAN: @__cxx_global_var_init{{.*}}address_safety
+// WITHOUT: @__cxx_global_var_init{{.*}}[[NOATTR_NO_TF:#[0-9]+]]
+// BLFILE: @__cxx_global_var_init{{.*}}[[NOATTR_NO_TF:#[0-9]+]]
+// BLFUNC: @__cxx_global_var_init{{.*}}[[WITH_NO_TF:#[0-9]+]]
+// ASAN: @__cxx_global_var_init{{.*}}[[WITH_NO_TF:#[0-9]+]]
+
+// WITHOUT: attributes [[NOATTR]] = { nounwind{{.*}} }
+// WITHOUT: attributes [[NOATTR_NO_TF]] = { nounwind }
+
+// BLFILE: attributes [[NOATTR]] = { nounwind{{.*}} }
+// BLFILE: attributes [[NOATTR_NO_TF]] = { nounwind }
+
+// BLFUNC: attributes [[NOATTR]] = { nounwind{{.*}} }
+// BLFUNC: attributes [[WITH]] = { nounwind sanitize_address{{.*}} }
+// BLFUNC: attributes [[WITH_NO_TF]] = { nounwind sanitize_address }
+
+// ASAN: attributes [[NOATTR]] = { nounwind{{.*}} }
+// ASAN: attributes [[WITH]] = { nounwind sanitize_address{{.*}} }
+// ASAN: attributes [[WITH_NO_TF]] = { nounwind sanitize_address }
diff --git a/test/CodeGen/address-space-field1.c b/test/CodeGen/address-space-field1.c
index e9c1871..c6b3181 100644
--- a/test/CodeGen/address-space-field1.c
+++ b/test/CodeGen/address-space-field1.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -emit-llvm -triple x86_64-apple-darwin10 < %s -o - | FileCheck %s
// CHECK:%struct.S = type { i32, i32 }
-// CHECK:define void @test_addrspace(%struct.S addrspace(1)* %p1, %struct.S addrspace(2)* %p2) nounwind
+// CHECK:define void @test_addrspace(%struct.S addrspace(1)* %p1, %struct.S addrspace(2)* %p2) [[NUW:#[0-9]+]]
// CHECK: [[p1addr:%.*]] = alloca %struct.S addrspace(1)*
// CHECK: [[p2addr:%.*]] = alloca %struct.S addrspace(2)*
// CHECK: store %struct.S addrspace(1)* %p1, %struct.S addrspace(1)** [[p1addr]]
@@ -36,3 +36,5 @@ void test_addrspace(__addr1 S* p1, __addr2 S*p2) {
p1->a = p2->b;
p1->b = p2->a;
}
+
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGen/alias.c b/test/CodeGen/alias.c
index 0ccbca6..a8380a3 100644
--- a/test/CodeGen/alias.c
+++ b/test/CodeGen/alias.c
@@ -14,7 +14,7 @@ void f0(void) { }
extern void f1(void);
extern void f1(void) __attribute((alias("f0")));
// CHECKBASIC: @f1 = alias void ()* @f0
-// CHECKBASIC: define void @f0() nounwind {
+// CHECKBASIC: define void @f0() [[NUW:#[0-9]+]] {
// Make sure that aliases cause referenced values to be emitted.
// PR3200
@@ -34,13 +34,17 @@ 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 {
+// CHECKCC: define internal arm_aapcs_vfpcc i32 @inner(i32 %a) [[NUW:#[0-9]+]] {
int outer(int a) { return inner(a); }
-// CHECKCC: define arm_aapcs_vfpcc i32 @outer(i32 %a) nounwind {
+// CHECKCC: define arm_aapcs_vfpcc i32 @outer(i32 %a) [[NUW]] {
// 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: define arm_aapcs_vfpcc i32 @outer_weak(i32 %a) [[NUW]] {
// CHECKCC: call arm_aapcs_vfpcc i32 @inner_weak(i32 %{{.*}})
-// CHECKCC: define internal arm_aapcs_vfpcc i32 @inner_weak(i32 %a) nounwind {
+// CHECKCC: define internal arm_aapcs_vfpcc i32 @inner_weak(i32 %a) [[NUW]] {
+
+// CHECKBASIC: attributes [[NUW]] = { nounwind{{.*}} }
+
+// CHECKCC: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGen/always-inline.c b/test/CodeGen/always-inline.c
index dc74be5..c9fd1ae 100644
--- a/test/CodeGen/always-inline.c
+++ b/test/CodeGen/always-inline.c
@@ -1,4 +1,7 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - | grep call | not grep foo
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fno-inline -emit-llvm %s -o - | FileCheck %s
+
+// CHECK-NOT: foo
void bar() {
}
diff --git a/test/CodeGen/arm-asm-warn.c b/test/CodeGen/arm-asm-warn.c
index 0c4e97a..9b52dd6 100644
--- a/test/CodeGen/arm-asm-warn.c
+++ b/test/CodeGen/arm-asm-warn.c
@@ -1,7 +1,20 @@
// REQUIRES: arm-registered-target
// RUN: %clang_cc1 -triple armv7 %s -emit-llvm -o /dev/null
-// <rdar://problem/12284092>
+char bar();
+
+void t1(int x, char y) {
+ __asm__ volatile("mcr p15, 0, %1, c9, c12, 5;"
+ "mrc p15, 0, %0, c9, c13, 2;"
+ : "=r" (x)
+ : "r" (bar())); // no warning
+ __asm__ volatile("foo %0, %1"
+ : "+r" (x),
+ "+r" (y)
+ :);
+}
+
+// <rdar://problem/12284092>
typedef __attribute__((neon_vector_type(2))) long long int64x2_t;
typedef struct int64x2x4_t {
int64x2_t val[4];
@@ -9,10 +22,10 @@ typedef struct int64x2x4_t {
int64x2x4_t t2(const long long a[]) {
int64x2x4_t r;
__asm__("vldm %[a], { %q[r0], %q[r1], %q[r2], %q[r3] }"
- : [r0] "=r"(r.val[0]), // expected-warning {{the 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}}
+ : [r0] "=r"(r.val[0]), // expected-warning {{the value is truncated when put into register, use a modifier to specify the size}}
+ [r1] "=r"(r.val[1]), // expected-warning {{the value is truncated when put into register, use a modifier to specify the size}}
+ [r2] "=r"(r.val[2]), // expected-warning {{the value is truncated when put into register, use a modifier to specify the size}}
+ [r3] "=r"(r.val[3]) // expected-warning {{the value is truncated when put into register, use a modifier to specify the size}}
: [a] "r"(a));
return r;
}
diff --git a/test/CodeGen/arm-neon-fma.c b/test/CodeGen/arm-neon-fma.c
new file mode 100644
index 0000000..994702d
--- /dev/null
+++ b/test/CodeGen/arm-neon-fma.c
@@ -0,0 +1,19 @@
+// REQUIRES: arm-registered-target
+// RUN: %clang_cc1 -triple thumbv7-none-linux-gnueabihf \
+// RUN: -target-abi aapcs \
+// RUN: -target-cpu cortex-a8 \
+// RUN: -mfloat-abi hard \
+// RUN: -ffreestanding \
+// RUN: -O3 -S -emit-llvm -o - %s | FileCheck %s
+
+#include <arm_neon.h>
+
+float32x2_t test_fma_order(float32x2_t accum, float32x2_t lhs, float32x2_t rhs) {
+ return vfma_f32(accum, lhs, rhs);
+// CHECK: call <2 x float> @llvm.fma.v2f32(<2 x float> %lhs, <2 x float> %rhs, <2 x float> %accum)
+}
+
+float32x4_t test_fmaq_order(float32x4_t accum, float32x4_t lhs, float32x4_t rhs) {
+ return vfmaq_f32(accum, lhs, rhs);
+// CHECK: call <4 x float> @llvm.fma.v4f32(<4 x float> %lhs, <4 x float> %rhs, <4 x float> %accum)
+}
diff --git a/test/CodeGen/atomic_ops.c b/test/CodeGen/atomic_ops.c
index 481d1e0..910e9b9 100644
--- a/test/CodeGen/atomic_ops.c
+++ b/test/CodeGen/atomic_ops.c
@@ -15,9 +15,4 @@ void foo(int x)
// CHECK: sdiv i32
// CHECK: cmpxchg i16*
- // These should be emitting atomicrmw instructions, but they aren't yet
- i += 2; // CHECK: cmpxchg
- i -= 2; // CHECK: cmpxchg
- i++; // CHECK: cmpxchg
- i--; // CHECK: cmpxchg
}
diff --git a/test/CodeGen/atomics-inlining.c b/test/CodeGen/atomics-inlining.c
new file mode 100644
index 0000000..9b0d413
--- /dev/null
+++ b/test/CodeGen/atomics-inlining.c
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -triple powerpc-linux-gnu -emit-llvm %s -o - | FileCheck %s -check-prefix=PPC32
+// RUN: %clang_cc1 -triple powerpc64-linux-gnu -emit-llvm %s -o - | FileCheck %s -check-prefix=PPC64
+// RUN: %clang_cc1 -triple mipsel-linux-gnu -emit-llvm %s -o - | FileCheck %s -check-prefix=MIPS32
+// RUN: %clang_cc1 -triple mips64el-linux-gnu -emit-llvm %s -o - | FileCheck %s -check-prefix=MIPS64
+
+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);
+
+// PPC32: define void @test1
+// PPC32: load atomic i8* @c1 seq_cst
+// PPC32: load atomic i16* @s1 seq_cst
+// PPC32: load atomic i32* @i1 seq_cst
+// PPC32: call void @__atomic_load(i32 8, i8* bitcast (i64* @ll1 to i8*)
+
+// PPC64: define void @test1
+// PPC64: load atomic i8* @c1 seq_cst
+// PPC64: load atomic i16* @s1 seq_cst
+// PPC64: load atomic i32* @i1 seq_cst
+// PPC64: load atomic i64* @ll1 seq_cst
+
+// MIPS32: define void @test1
+// MIPS32: load atomic i8* @c1 seq_cst
+// MIPS32: load atomic i16* @s1 seq_cst
+// MIPS32: load atomic i32* @i1 seq_cst
+// MIPS32: call void @__atomic_load(i32 8, i8* bitcast (i64* @ll1 to i8*)
+
+// MIPS64: define void @test1
+// MIPS64: load atomic i8* @c1 seq_cst
+// MIPS64: load atomic i16* @s1 seq_cst
+// MIPS64: load atomic i32* @i1 seq_cst
+// MIPS64: load atomic i64* @ll1 seq_cst
+}
diff --git a/test/CodeGen/attr-coldhot.c b/test/CodeGen/attr-coldhot.c
index b9bb299..a277119 100644
--- a/test/CodeGen/attr-coldhot.c
+++ b/test/CodeGen/attr-coldhot.c
@@ -4,6 +4,8 @@ int test1() __attribute__((__cold__)) {
return 42;
// Check that we set the optsize attribute on the function.
-// CHECK: @test1{{.*}}optsize
+// CHECK: @test1{{.*}}[[ATTR:#[0-9]+]]
// CHECK: ret
}
+
+// CHECK: attributes [[ATTR]] = { {{.*}}optsize{{.*}} }
diff --git a/test/CodeGen/attr-minsize.cpp b/test/CodeGen/attr-minsize.cpp
index a422a62..997194d 100644
--- a/test/CodeGen/attr-minsize.cpp
+++ b/test/CodeGen/attr-minsize.cpp
@@ -7,29 +7,29 @@
// Check that we set the minsize attribute on each function
// when Oz optimization level is set.
+__attribute__((minsize))
int test1() {
return 42;
-// Oz: @{{.*}}test1{{.*}}minsize
-// Oz: ret
-// OTHER: @{{.*}}test1
-// OTHER-NOT: minsize
-// OTHER: ret
+// Oz: @{{.*}}test1{{.*}}[[MINSIZE:#[0-9]+]]
+// OTHER: @{{.*}}test1{{.*}}[[MS:#[0-9]+]]
}
int test2() {
return 42;
-// Oz: @{{.*}}test2{{.*}}minsize
+// Oz: @{{.*}}test2{{.*}}[[MINSIZE]]
// Oz: ret
// OTHER: @{{.*}}test2
-// OTHER-NOT: minsize
+// OTHER-NOT: [[MS]]
// OTHER: ret
}
-__attribute__((minsize))
int test3() {
return 42;
-// Oz: @{{.*}}test3{{.*}}minsize
-// OTHER: @{{.*}}test3{{.*}}minsize
+// Oz: @{{.*}}test3{{.*}}[[MINSIZE]]
+// Oz: ret
+// OTHER: @{{.*}}test3
+// OTHER-NOT: [[MS]]
+// OTHER: ret
}
// Check that the minsize attribute is well propagated through
@@ -44,16 +44,16 @@ void test4(T arg) {
template
void test4<int>(int arg);
// Oz: define{{.*}}void @{{.*}}test4
-// Oz: minsize
+// Oz: [[MINSIZE]]
// OTHER: define{{.*}}void @{{.*}}test4
-// OTHER: minsize
+// OTHER: [[MS]]
template
void test4<float>(float arg);
// Oz: define{{.*}}void @{{.*}}test4
-// Oz: minsize
+// Oz: [[MINSIZE]]
// OTHER: define{{.*}}void @{{.*}}test4
-// OTHER: minsize
+// OTHER: [[MS]]
template<typename T>
void test5(T arg) {
@@ -63,13 +63,17 @@ void test5(T arg) {
template
void test5<int>(int arg);
// Oz: define{{.*}}void @{{.*}}test5
-// Oz: minsize
+// Oz: [[MINSIZE]]
// OTHER: define{{.*}}void @{{.*}}test5
-// OTHER-NOT: minsize
+// OTHER-NOT: define{{.*}}void @{{.*}}test5{{.*}}[[MS]]
template
void test5<float>(float arg);
// Oz: define{{.*}}void @{{.*}}test5
-// Oz: minsize
+// Oz: [[MINSIZE]]
// OTHER: define{{.*}}void @{{.*}}test5
-// OTHER-NOT: minsize
+// OTHER-NOT: define{{.*}}void @{{.*}}test5{{.*}}[[MS]]
+
+// Oz: attributes [[MINSIZE]] = { minsize{{.*}} }
+
+// OTHER: attributes [[MS]] = { minsize nounwind{{.*}} }
diff --git a/test/CodeGen/attr-naked.c b/test/CodeGen/attr-naked.c
index 2387d28..c07dd8d 100644
--- a/test/CodeGen/attr-naked.c
+++ b/test/CodeGen/attr-naked.c
@@ -4,13 +4,15 @@ void t1() __attribute__((naked));
// Basic functionality check
// (Note that naked needs to imply noinline to work properly.)
-// CHECK: define void @t1() nounwind noinline naked {
+// CHECK: define void @t1() [[NAKED:#[0-9]+]] {
void t1()
{
}
// Make sure this doesn't explode in the verifier.
// (It doesn't really make sense, but it isn't invalid.)
-// CHECK: define void @t2() nounwind noinline naked {
+// CHECK: define void @t2() [[NAKED]] {
__attribute((naked, always_inline)) void t2() {
}
+
+// CHECK: attributes [[NAKED]] = { naked noinline nounwind{{.*}} }
diff --git a/test/CodeGen/attributes.c b/test/CodeGen/attributes.c
index 00688dc..356a179 100644
--- a/test/CodeGen/attributes.c
+++ b/test/CodeGen/attributes.c
@@ -36,39 +36,39 @@ int t17() {
return t15() + t16;
}
-// CHECK: define void @t1() noreturn nounwind {
+// CHECK: define void @t1() [[NR:#[0-9]+]] {
void t1() __attribute__((noreturn));
void t1() { while (1) {} }
-// CHECK: define void @t2() nounwind {
+// CHECK: define void @t2() [[NUW:#[0-9]+]] {
void t2() __attribute__((nothrow));
void t2() {}
-// CHECK: define weak void @t3() nounwind {
+// CHECK: define weak void @t3() [[NUW]] {
void t3() __attribute__((weak));
void t3() {}
-// CHECK: define hidden void @t4() nounwind {
+// CHECK: define hidden void @t4() [[NUW]] {
void t4() __attribute__((visibility("hidden")));
void t4() {}
-// CHECK: define void @t7() noreturn nounwind {
+// CHECK: define void @t7() [[NR]] {
void t7() __attribute__((noreturn, nothrow));
void t7() { while (1) {} }
-// CHECK: define void @t10() nounwind section "SECT" {
+// CHECK: define void @t10() [[NUW]] section "SECT" {
void t10(void) __attribute__((section("SECT")));
void t10(void) {}
-// CHECK: define void @t11() nounwind section "SECT" {
+// CHECK: define void @t11() [[NUW]] section "SECT" {
void __attribute__((section("SECT"))) t11(void) {}
-// CHECK: define i32 @t19() nounwind {
+// CHECK: define i32 @t19() [[NUW]] {
extern int t19(void) __attribute__((weak_import));
int t19(void) {
return 10;
}
-// CHECK:define void @t20() nounwind {
+// CHECK:define void @t20() [[NUW]] {
// CHECK: call void @abort()
// CHECK-NEXT: unreachable
void t20(void) {
@@ -88,4 +88,7 @@ void t21(void) {
void __attribute__((section(".foo"))) t22(void);
void __attribute__((section(".bar"))) t22(void) {}
-// CHECK: define void @t22() nounwind section ".bar"
+// CHECK: define void @t22() [[NUW]] section ".bar"
+
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
+// CHECK: attributes [[NR]] = { noreturn nounwind{{.*}} }
diff --git a/test/CodeGen/bitfield-2.c b/test/CodeGen/bitfield-2.c
index 69ed5b1..bec55ff 100644
--- a/test/CodeGen/bitfield-2.c
+++ b/test/CodeGen/bitfield-2.c
@@ -9,17 +9,12 @@
// PR6176
// CHECK-RECORD: *** Dumping IRgen Record Layout
-// CHECK-RECORD: Record: struct s0
+// CHECK-RECORD: Record: RecordDecl{{.*}}s0
// CHECK-RECORD: Layout: <CGRecordLayout
// CHECK-RECORD: LLVMType:%struct.s0 = type <{ [3 x i8] }>
// CHECK-RECORD: IsZeroInitializable:1
// CHECK-RECORD: BitFields:[
-// CHECK-RECORD: <CGBitFieldInfo Size:24 IsSigned:1
-// CHECK-RECORD: NumComponents:2 Components: [
-// CHECK-RECORD: <AccessInfo FieldIndex:0 FieldByteOffset:0 FieldBitStart:0 AccessWidth:16
-// CHECK-RECORD: AccessAlignment:1 TargetBitOffset:0 TargetBitWidth:16>
-// CHECK-RECORD: <AccessInfo FieldIndex:0 FieldByteOffset:2 FieldBitStart:0 AccessWidth:8
-// CHECK-RECORD: AccessAlignment:1 TargetBitOffset:16 TargetBitWidth:8>
+// CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:24 IsSigned:1 StorageSize:24 StorageAlignment:1>
struct __attribute((packed)) s0 {
int f0 : 24;
};
@@ -54,22 +49,13 @@ unsigned long long test_0() {
// PR5591
// CHECK-RECORD: *** Dumping IRgen Record Layout
-// CHECK-RECORD: Record: struct s1
+// CHECK-RECORD: Record: RecordDecl{{.*}}s1
// CHECK-RECORD: Layout: <CGRecordLayout
-// CHECK-RECORD: LLVMType:%struct.s1 = type <{ [2 x i8], i8 }>
+// CHECK-RECORD: LLVMType:%struct.s1 = type <{ [3 x i8] }>
// CHECK-RECORD: IsZeroInitializable:1
// CHECK-RECORD: BitFields:[
-// CHECK-RECORD: <CGBitFieldInfo Size:10 IsSigned:1
-// CHECK-RECORD: NumComponents:1 Components: [
-// CHECK-RECORD: <AccessInfo FieldIndex:0 FieldByteOffset:0 FieldBitStart:0 AccessWidth:16
-// CHECK-RECORD: AccessAlignment:1 TargetBitOffset:0 TargetBitWidth:10>
-// CHECK-RECORD: ]>
-// CHECK-RECORD: <CGBitFieldInfo Size:10 IsSigned:1
-// CHECK-RECORD: NumComponents:2 Components: [
-// CHECK-RECORD: <AccessInfo FieldIndex:0 FieldByteOffset:0 FieldBitStart:10 AccessWidth:16
-// CHECK-RECORD: AccessAlignment:1 TargetBitOffset:0 TargetBitWidth:6>
-// CHECK-RECORD: <AccessInfo FieldIndex:0 FieldByteOffset:2 FieldBitStart:0 AccessWidth:8
-// CHECK-RECORD: AccessAlignment:1 TargetBitOffset:6 TargetBitWidth:4>
+// CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:10 IsSigned:1 StorageSize:24 StorageAlignment:1>
+// CHECK-RECORD: <CGBitFieldInfo Offset:10 Size:10 IsSigned:1 StorageSize:24 StorageAlignment:1>
#pragma pack(push)
#pragma pack(1)
@@ -111,15 +97,12 @@ unsigned long long test_1() {
// PR5567
// CHECK-RECORD: *** Dumping IRgen Record Layout
-// CHECK-RECORD: Record: union u2
+// CHECK-RECORD: Record: RecordDecl{{.*}}u2
// CHECK-RECORD: Layout: <CGRecordLayout
// CHECK-RECORD: LLVMType:%union.u2 = type <{ i8 }>
// CHECK-RECORD: IsZeroInitializable:1
// CHECK-RECORD: BitFields:[
-// CHECK-RECORD: <CGBitFieldInfo Size:3 IsSigned:0
-// CHECK-RECORD: NumComponents:1 Components: [
-// CHECK-RECORD: <AccessInfo FieldIndex:0 FieldByteOffset:0 FieldBitStart:0 AccessWidth:8
-// CHECK-RECORD: AccessAlignment:1 TargetBitOffset:0 TargetBitWidth:3>
+// CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:3 IsSigned:0 StorageSize:8 StorageAlignment:1>
union __attribute__((packed)) u2 {
unsigned long long f0 : 3;
@@ -286,20 +269,13 @@ _Bool test_6() {
// Check that we compute the best alignment possible for each access.
//
// CHECK-RECORD: *** Dumping IRgen Record Layout
-// CHECK-RECORD: Record: struct s7
+// CHECK-RECORD: Record: RecordDecl{{.*}}s7
// CHECK-RECORD: Layout: <CGRecordLayout
// CHECK-RECORD: LLVMType:%struct.s7 = type { i32, i32, i32, i8, [3 x i8], [4 x i8], [12 x i8] }
// CHECK-RECORD: IsZeroInitializable:1
// CHECK-RECORD: BitFields:[
-// CHECK-RECORD: <CGBitFieldInfo Size:5 IsSigned:1
-// CHECK-RECORD: NumComponents:1 Components: [
-// CHECK-RECORD: <AccessInfo FieldIndex:0 FieldByteOffset:12 FieldBitStart:0 AccessWidth:32
-// CHECK-RECORD: AccessAlignment:4 TargetBitOffset:0 TargetBitWidth:5>
-// CHECK-RECORD: ]>
-// CHECK-RECORD: <CGBitFieldInfo Size:29 IsSigned:1
-// CHECK-RECORD: NumComponents:1 Components: [
-// CHECK-RECORD: <AccessInfo FieldIndex:0 FieldByteOffset:16 FieldBitStart:0 AccessWidth:32
-// CHECK-RECORD: AccessAlignment:16 TargetBitOffset:0 TargetBitWidth:29>
+// CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:5 IsSigned:1 StorageSize:8 StorageAlignment:4>
+// CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:29 IsSigned:1 StorageSize:32 StorageAlignment:16>
struct __attribute__((aligned(16))) s7 {
int a, b, c;
diff --git a/test/CodeGen/blocks-seq.c b/test/CodeGen/blocks-seq.c
index 3557b48..8db9e60 100644
--- a/test/CodeGen/blocks-seq.c
+++ b/test/CodeGen/blocks-seq.c
@@ -1,13 +1,11 @@
-// FIXME: We forcibly strip the names so that the test doesn't vary between
-// builds with and without asserts. We need a better solution for this.
-
-// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin10 -emit-llvm-bc -o - %s | opt -strip | llvm-dis > %t
-// RUN: grep '%6 = call i32 (...)\* @rhs()' %t | count 1
-// RUN: grep '%7 = getelementptr inbounds %0\* %1, i32 0, i32 1' %t | count 1
-// RUN: grep '%8 = load %0\*\* %7' %t | count 1
-// RUN: grep '%10 = call i32 (...)\* @rhs()' %t | count 1
-// RUN: grep '%11 = getelementptr inbounds %0\* %1, i32 0, i32 1' %t | count 1
-// RUN: grep '%12 = load %0\*\* %11' %t | count 1
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+// CHECK: [[Vi:%.+]] = alloca %struct.__block_byref_i, align 8
+// CHECK: call i32 (...)* @rhs()
+// CHECK: [[V7:%.+]] = getelementptr inbounds %struct.__block_byref_i* [[Vi]], i32 0, i32 1
+// CHECK: load %struct.__block_byref_i** [[V7]]
+// CHECK: call i32 (...)* @rhs()
+// CHECK: [[V11:%.+]] = getelementptr inbounds %struct.__block_byref_i* [[Vi]], i32 0, i32 1
+// CHECK: load %struct.__block_byref_i** [[V11]]
int rhs();
diff --git a/test/CodeGen/bool_test.c b/test/CodeGen/bool_test.c
index 715f846..83d8330 100644
--- a/test/CodeGen/bool_test.c
+++ b/test/CodeGen/bool_test.c
@@ -1,6 +1,18 @@
// REQUIRES: ppc32-registered-target
-// RUN: %clang_cc1 -triple powerpc-apple-darwin -emit-llvm -o - %s| FileCheck -check-prefix=DARWINPPC-CHECK %s
+// RUN: %clang_cc1 -triple powerpc-apple-macosx10.4.0 -emit-llvm -o - %s -O2 -disable-llvm-optzns | FileCheck %s
int boolsize = sizeof(_Bool);
-//DARWINPPC-CHECK: boolsize = global i32 4, align 4
+// CHECK: boolsize = global i32 4, align 4
+void f(_Bool *x, _Bool *y) {
+ *x = *y;
+}
+
+// CHECK: define void @f(
+// CHECK: [[FROMMEM:%.*]] = load i32* %
+// CHECK: [[BOOLVAL:%.*]] = trunc i32 [[FROMMEM]] to i1
+// CHECK: [[TOMEM:%.*]] = zext i1 [[BOOLVAL]] to i32
+// CHECK: store i32 [[TOMEM]]
+// CHECK: ret void
+
+// CHECK: metadata !{i32 0, i32 2}
diff --git a/test/CodeGen/bounds-checking.c b/test/CodeGen/bounds-checking.c
index e278620..fa7541f 100644
--- a/test/CodeGen/bounds-checking.c
+++ b/test/CodeGen/bounds-checking.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fbounds-checking=4 -emit-llvm -triple x86_64-apple-darwin10 < %s | FileCheck %s
+// RUN: %clang_cc1 -fsanitize=bounds -emit-llvm -triple x86_64-apple-darwin10 < %s | FileCheck %s
// CHECK: @f
double f(int b, int i) {
diff --git a/test/CodeGen/builtin-attributes.c b/test/CodeGen/builtin-attributes.c
index 1d3a943..c5c35c3 100644
--- a/test/CodeGen/builtin-attributes.c
+++ b/test/CodeGen/builtin-attributes.c
@@ -12,7 +12,7 @@ void f1() {
exit(1);
}
-// CHECK: call i8* @strstr{{.*}} nounwind
+// CHECK: call i8* @strstr{{.*}} [[NUW:#[0-9]+]]
char* f2(char* a, char* b) {
return __builtin_strstr(a, b);
}
@@ -57,3 +57,5 @@ int f3(double x) {
__builtin_remquol(x, x, &e);
return e;
}
+
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGen/builtins-arm.c b/test/CodeGen/builtins-arm.c
index 3611650..e6c7ced 100644
--- a/test/CodeGen/builtins-arm.c
+++ b/test/CodeGen/builtins-arm.c
@@ -11,3 +11,10 @@ void f1(char *a, char *b) {
}
// CHECK: call {{.*}} @__clear_cache
+
+void test_eh_return_data_regno()
+{
+ volatile int res;
+ res = __builtin_eh_return_data_regno(0); // CHECK: store volatile i32 0
+ res = __builtin_eh_return_data_regno(1); // CHECK: store volatile i32 1
+}
diff --git a/test/CodeGen/builtins-mips.c b/test/CodeGen/builtins-mips.c
index ef4662c..c6be896 100644
--- a/test/CodeGen/builtins-mips.c
+++ b/test/CodeGen/builtins-mips.c
@@ -532,3 +532,10 @@ void foo() {
v4i8_r = __builtin_mips_subuh_r_qb(v4i8_a, v4i8_b);
// CHECK: call <4 x i8> @llvm.mips.subuh.r.qb
}
+
+void test_eh_return_data_regno()
+{
+ volatile int res;
+ res = __builtin_eh_return_data_regno(0); // CHECK: store volatile i32 4
+ res = __builtin_eh_return_data_regno(1); // CHECK: store volatile i32 5
+}
diff --git a/test/CodeGen/builtins-multiprecision.c b/test/CodeGen/builtins-multiprecision.c
new file mode 100644
index 0000000..172f683
--- /dev/null
+++ b/test/CodeGen/builtins-multiprecision.c
@@ -0,0 +1,150 @@
+// RUN: %clang_cc1 -triple "i686-unknown-unknown" -emit-llvm -x c %s -o - -O3 | FileCheck %s
+// RUN: %clang_cc1 -triple "x86_64-unknown-unknown" -emit-llvm -x c %s -o - -O3 | FileCheck %s
+// RUN: %clang_cc1 -triple "x86_64-mingw32" -emit-llvm -x c %s -o - -O3 | FileCheck %s
+
+unsigned short test_addcs(unsigned short x, unsigned short y,
+ unsigned short carryin, unsigned short *z) {
+ // CHECK: @test_addcs
+ // CHECK: %{{.+}} = {{.*}} call { i16, i1 } @llvm.uadd.with.overflow.i16(i16 %x, i16 %y)
+ // CHECK: %{{.+}} = extractvalue { i16, i1 } %{{.+}}, 1
+ // CHECK: %{{.+}} = extractvalue { i16, i1 } %{{.+}}, 0
+ // CHECK: %{{.+}} = {{.*}} call { i16, i1 } @llvm.uadd.with.overflow.i16(i16 %{{.+}}, i16 %carryin)
+ // CHECK: %{{.+}} = extractvalue { i16, i1 } %{{.+}}, 1
+ // CHECK: %{{.+}} = extractvalue { i16, i1 } %{{.+}}, 0
+ // CHECK: %{{.+}} = or i1 %{{.+}}, %{{.+}}
+ // CHECK: %{{.+}} = zext i1 %{{.+}} to i16
+ // CHECK: store i16 %{{.+}}, i16* %z, align 2
+
+ unsigned short carryout;
+ *z = __builtin_addcs(x, y, carryin, &carryout);
+
+ return carryout;
+}
+
+unsigned test_addc(unsigned x, unsigned y, unsigned carryin, unsigned *z) {
+ // CHECK: @test_addc
+ // CHECK: %{{.+}} = {{.*}} call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %x, i32 %y)
+ // CHECK: %{{.+}} = extractvalue { i32, i1 } %{{.+}}, 1
+ // CHECK: %{{.+}} = extractvalue { i32, i1 } %{{.+}}, 0
+ // CHECK: %{{.+}} = {{.*}} call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %{{.+}}, i32 %carryin)
+ // CHECK: %{{.+}} = extractvalue { i32, i1 } %{{.+}}, 1
+ // CHECK: %{{.+}} = extractvalue { i32, i1 } %{{.+}}, 0
+ // CHECK: %{{.+}} = or i1 %{{.+}}, %{{.+}}
+ // CHECK: %{{.+}} = zext i1 %{{.+}} to i32
+ // CHECK: store i32 %{{.+}}, i32* %z, align 4
+ unsigned carryout;
+ *z = __builtin_addc(x, y, carryin, &carryout);
+
+ return carryout;
+}
+
+unsigned long test_addcl(unsigned long x, unsigned long y,
+ unsigned long carryin, unsigned long *z) {
+ // long is i32 on i686, i64 on x86_64.
+ // CHECK: @test_addcl([[UL:i32|i64]] %x
+ // CHECK: %{{.+}} = {{.*}} call { [[UL]], i1 } @llvm.uadd.with.overflow.[[UL]]([[UL]] %x, [[UL]] %y)
+ // CHECK: %{{.+}} = extractvalue { [[UL]], i1 } %{{.+}}, 1
+ // CHECK: %{{.+}} = extractvalue { [[UL]], i1 } %{{.+}}, 0
+ // CHECK: %{{.+}} = {{.*}} call { [[UL]], i1 } @llvm.uadd.with.overflow.[[UL]]([[UL]] %{{.+}}, [[UL]] %carryin)
+ // CHECK: %{{.+}} = extractvalue { [[UL]], i1 } %{{.+}}, 1
+ // CHECK: %{{.+}} = extractvalue { [[UL]], i1 } %{{.+}}, 0
+ // CHECK: %{{.+}} = or i1 %{{.+}}, %{{.+}}
+ // CHECK: %{{.+}} = zext i1 %{{.+}} to [[UL]]
+ // CHECK: store [[UL]] %{{.+}}, [[UL]]* %z
+ unsigned long carryout;
+ *z = __builtin_addcl(x, y, carryin, &carryout);
+
+ return carryout;
+}
+
+unsigned long long test_addcll(unsigned long long x, unsigned long long y,
+ unsigned long long carryin,
+ unsigned long long *z) {
+ // CHECK: @test_addcll
+ // CHECK: %{{.+}} = {{.*}} call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %x, i64 %y)
+ // CHECK: %{{.+}} = extractvalue { i64, i1 } %{{.+}}, 1
+ // CHECK: %{{.+}} = extractvalue { i64, i1 } %{{.+}}, 0
+ // CHECK: %{{.+}} = {{.*}} call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %{{.+}}, i64 %carryin)
+ // CHECK: %{{.+}} = extractvalue { i64, i1 } %{{.+}}, 1
+ // CHECK: %{{.+}} = extractvalue { i64, i1 } %{{.+}}, 0
+ // CHECK: %{{.+}} = or i1 %{{.+}}, %{{.+}}
+ // CHECK: %{{.+}} = zext i1 %{{.+}} to i64
+ // CHECK: store i64 %{{.+}}, i64* %z
+ unsigned long long carryout;
+ *z = __builtin_addcll(x, y, carryin, &carryout);
+
+ return carryout;
+}
+
+unsigned short test_subcs(unsigned short x, unsigned short y,
+ unsigned short carryin, unsigned short *z) {
+ // CHECK: @test_subcs
+ // CHECK: %{{.+}} = {{.*}} call { i16, i1 } @llvm.usub.with.overflow.i16(i16 %x, i16 %y)
+ // CHECK: %{{.+}} = extractvalue { i16, i1 } %{{.+}}, 1
+ // CHECK: %{{.+}} = extractvalue { i16, i1 } %{{.+}}, 0
+ // CHECK: %{{.+}} = {{.*}} call { i16, i1 } @llvm.usub.with.overflow.i16(i16 %{{.+}}, i16 %carryin)
+ // CHECK: %{{.+}} = extractvalue { i16, i1 } %{{.+}}, 1
+ // CHECK: %{{.+}} = extractvalue { i16, i1 } %{{.+}}, 0
+ // CHECK: %{{.+}} = or i1 %{{.+}}, %{{.+}}
+ // CHECK: %{{.+}} = zext i1 %{{.+}} to i16
+ // CHECK: store i16 %{{.+}}, i16* %z, align 2
+
+ unsigned short carryout;
+ *z = __builtin_subcs(x, y, carryin, &carryout);
+
+ return carryout;
+}
+
+unsigned test_subc(unsigned x, unsigned y, unsigned carryin, unsigned *z) {
+ // CHECK: @test_subc
+ // CHECK: %{{.+}} = {{.*}} call { i32, i1 } @llvm.usub.with.overflow.i32(i32 %x, i32 %y)
+ // CHECK: %{{.+}} = extractvalue { i32, i1 } %{{.+}}, 1
+ // CHECK: %{{.+}} = extractvalue { i32, i1 } %{{.+}}, 0
+ // CHECK: %{{.+}} = {{.*}} call { i32, i1 } @llvm.usub.with.overflow.i32(i32 %{{.+}}, i32 %carryin)
+ // CHECK: %{{.+}} = extractvalue { i32, i1 } %{{.+}}, 1
+ // CHECK: %{{.+}} = extractvalue { i32, i1 } %{{.+}}, 0
+ // CHECK: %{{.+}} = or i1 %{{.+}}, %{{.+}}
+ // CHECK: %{{.+}} = zext i1 %{{.+}} to i32
+ // CHECK: store i32 %{{.+}}, i32* %z, align 4
+ unsigned carryout;
+ *z = __builtin_subc(x, y, carryin, &carryout);
+
+ return carryout;
+}
+
+unsigned long test_subcl(unsigned long x, unsigned long y,
+ unsigned long carryin, unsigned long *z) {
+ // CHECK: @test_subcl([[UL:i32|i64]] %x
+ // CHECK: %{{.+}} = {{.*}} call { [[UL]], i1 } @llvm.usub.with.overflow.[[UL]]([[UL]] %x, [[UL]] %y)
+ // CHECK: %{{.+}} = extractvalue { [[UL]], i1 } %{{.+}}, 1
+ // CHECK: %{{.+}} = extractvalue { [[UL]], i1 } %{{.+}}, 0
+ // CHECK: %{{.+}} = {{.*}} call { [[UL]], i1 } @llvm.usub.with.overflow.[[UL]]([[UL]] %{{.+}}, [[UL]] %carryin)
+ // CHECK: %{{.+}} = extractvalue { [[UL]], i1 } %{{.+}}, 1
+ // CHECK: %{{.+}} = extractvalue { [[UL]], i1 } %{{.+}}, 0
+ // CHECK: %{{.+}} = or i1 %{{.+}}, %{{.+}}
+ // CHECK: %{{.+}} = zext i1 %{{.+}} to [[UL]]
+ // CHECK: store [[UL]] %{{.+}}, [[UL]]* %z
+ unsigned long carryout;
+ *z = __builtin_subcl(x, y, carryin, &carryout);
+
+ return carryout;
+}
+
+unsigned long long test_subcll(unsigned long long x, unsigned long long y,
+ unsigned long long carryin,
+ unsigned long long *z) {
+ // CHECK: @test_subcll
+ // CHECK: %{{.+}} = {{.*}} call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %x, i64 %y)
+ // CHECK: %{{.+}} = extractvalue { i64, i1 } %{{.+}}, 1
+ // CHECK: %{{.+}} = extractvalue { i64, i1 } %{{.+}}, 0
+ // CHECK: %{{.+}} = {{.*}} call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %{{.+}}, i64 %carryin)
+ // CHECK: %{{.+}} = extractvalue { i64, i1 } %{{.+}}, 1
+ // CHECK: %{{.+}} = extractvalue { i64, i1 } %{{.+}}, 0
+ // CHECK: %{{.+}} = or i1 %{{.+}}, %{{.+}}
+ // CHECK: %{{.+}} = zext i1 %{{.+}} to i64
+ // CHECK: store i64 %{{.+}}, i64* %z
+ unsigned long long carryout;
+ *z = __builtin_subcll(x, y, carryin, &carryout);
+
+ return carryout;
+}
diff --git a/test/CodeGen/builtins-ppc-altivec.c b/test/CodeGen/builtins-ppc-altivec.c
index e885cb0..9427a8a 100644
--- a/test/CodeGen/builtins-ppc-altivec.c
+++ b/test/CodeGen/builtins-ppc-altivec.c
@@ -484,20 +484,20 @@ void test6() {
res_vf = vec_lvx(0, &param_f); // CHECK: @llvm.ppc.altivec.lvx
/* vec_lde */
- res_vsc = vec_lde(0, &vsc); // CHECK: @llvm.ppc.altivec.lvebx
- res_vuc = vec_lde(0, &vuc); // CHECK: @llvm.ppc.altivec.lvebx
- res_vs = vec_lde(0, &vs); // CHECK: @llvm.ppc.altivec.lvehx
- res_vus = vec_lde(0, &vus); // CHECK: @llvm.ppc.altivec.lvehx
- res_vi = vec_lde(0, &vi); // CHECK: @llvm.ppc.altivec.lvewx
- res_vui = vec_lde(0, &vui); // CHECK: @llvm.ppc.altivec.lvewx
- res_vf = vec_lde(0, &vf); // CHECK: @llvm.ppc.altivec.lvewx
- res_vsc = vec_lvebx(0, &vsc); // CHECK: @llvm.ppc.altivec.lvebx
- res_vuc = vec_lvebx(0, &vuc); // CHECK: @llvm.ppc.altivec.lvebx
- res_vs = vec_lvehx(0, &vs); // CHECK: @llvm.ppc.altivec.lvehx
- res_vus = vec_lvehx(0, &vus); // CHECK: @llvm.ppc.altivec.lvehx
- res_vi = vec_lvewx(0, &vi); // CHECK: @llvm.ppc.altivec.lvewx
- res_vui = vec_lvewx(0, &vui); // CHECK: @llvm.ppc.altivec.lvewx
- res_vf = vec_lvewx(0, &vf); // CHECK: @llvm.ppc.altivec.lvewx
+ res_vsc = vec_lde(0, &param_sc); // CHECK: @llvm.ppc.altivec.lvebx
+ res_vuc = vec_lde(0, &param_uc); // CHECK: @llvm.ppc.altivec.lvebx
+ res_vs = vec_lde(0, &param_s); // CHECK: @llvm.ppc.altivec.lvehx
+ res_vus = vec_lde(0, &param_us); // CHECK: @llvm.ppc.altivec.lvehx
+ res_vi = vec_lde(0, &param_i); // CHECK: @llvm.ppc.altivec.lvewx
+ res_vui = vec_lde(0, &param_ui); // CHECK: @llvm.ppc.altivec.lvewx
+ res_vf = vec_lde(0, &param_f); // CHECK: @llvm.ppc.altivec.lvewx
+ res_vsc = vec_lvebx(0, &param_sc); // CHECK: @llvm.ppc.altivec.lvebx
+ res_vuc = vec_lvebx(0, &param_uc); // CHECK: @llvm.ppc.altivec.lvebx
+ res_vs = vec_lvehx(0, &param_s); // CHECK: @llvm.ppc.altivec.lvehx
+ res_vus = vec_lvehx(0, &param_us); // CHECK: @llvm.ppc.altivec.lvehx
+ res_vi = vec_lvewx(0, &param_i); // CHECK: @llvm.ppc.altivec.lvewx
+ res_vui = vec_lvewx(0, &param_ui); // CHECK: @llvm.ppc.altivec.lvewx
+ res_vf = vec_lvewx(0, &param_f); // CHECK: @llvm.ppc.altivec.lvewx
/* vec_ldl */
res_vsc = vec_ldl(0, &vsc); // CHECK: @llvm.ppc.altivec.lvxl
diff --git a/test/CodeGen/builtins-ppc.c b/test/CodeGen/builtins-ppc.c
new file mode 100644
index 0000000..ee27a4c
--- /dev/null
+++ b/test/CodeGen/builtins-ppc.c
@@ -0,0 +1,9 @@
+// REQUIRES: ppc32-registered-target
+// RUN: %clang_cc1 -triple powerpc-unknown-unknown -emit-llvm %s -o - | FileCheck %s
+
+void test_eh_return_data_regno()
+{
+ volatile int res;
+ res = __builtin_eh_return_data_regno(0); // CHECK: store volatile i32 3
+ res = __builtin_eh_return_data_regno(1); // CHECK: store volatile i32 4
+}
diff --git a/test/CodeGen/builtinshufflevector2.c b/test/CodeGen/builtinshufflevector2.c
index faf7a3e..ac0e07a 100644
--- a/test/CodeGen/builtinshufflevector2.c
+++ b/test/CodeGen/builtinshufflevector2.c
@@ -16,14 +16,14 @@ void clang_shufflevector_v_v( float4* A, float4 x, uint4 mask ) {
// CHECK: [[I:%.*]] = extractelement <4 x i32> [[MASK]], i32 1
// CHECK: [[E:%.*]] = extractelement <4 x float> [[X]], i32 [[I]]
-// CHECK: [[V:%.*]] = insertelement <4 x float> [[V]], float [[E]], i32 1
+// CHECK: [[V2:%.*]] = insertelement <4 x float> [[V]], float [[E]], i32 1
// CHECK: [[I:%.*]] = extractelement <4 x i32> [[MASK]], i32 2
// CHECK: [[E:%.*]] = extractelement <4 x float> [[X]], i32 [[I]]
-// CHECK: [[V:%.*]] = insertelement <4 x float> [[V]], float [[E]], i32 2
+// CHECK: [[V3:%.*]] = insertelement <4 x float> [[V2]], float [[E]], i32 2
// CHECK: [[I:%.*]] = extractelement <4 x i32> [[MASK]], i32 3
// CHECK: [[E:%.*]] = extractelement <4 x float> [[X]], i32 [[I]]
-// CHECK: [[V:%.*]] = insertelement <4 x float> [[V]], float [[E]], i32 3
-// CHECK: store <4 x float> [[V]], <4 x float>* {{%.*}},
+// CHECK: [[V4:%.*]] = insertelement <4 x float> [[V3]], float [[E]], i32 3
+// CHECK: store <4 x float> [[V4]], <4 x float>* {{%.*}},
*A = __builtin_shufflevector( x, mask );
}
diff --git a/test/CodeGen/c-strings.c b/test/CodeGen/c-strings.c
index 4fbeb7b..1021010 100644
--- a/test/CodeGen/c-strings.c
+++ b/test/CodeGen/c-strings.c
@@ -1,36 +1,55 @@
-// RUN: %clang_cc1 -emit-llvm -o %t %s
-// RUN: grep "hello" %t | count 3
-// RUN: grep 'c"hello\\00"' %t | count 2
-// RUN: grep 'c"hello\\00\\00\\00"' %t | count 1
-// RUN: grep 'c"ola"' %t | count 1
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
-/* Should be 3 hello string, two global (of different sizes), the rest
- are shared. */
+// Should be 3 hello strings, two global (of different sizes), the rest are
+// shared.
+// CHECK: @.str = private unnamed_addr constant [6 x i8] c"hello\00"
+// CHECK: @f1.x = internal global i8* getelementptr inbounds ([6 x i8]* @.str, i32 0, i32 0)
+// CHECK: @f2.x = internal global [6 x i8] c"hello\00", align 1
+// CHECK: @f3.x = internal global [8 x i8] c"hello\00\00\00", align 1
+// CHECK: @f4.x = internal global %struct.s { i8* getelementptr inbounds ([6 x i8]* @.str, i32 0, i32 0) }
+// CHECK: @x = global [3 x i8] c"ola", align 1
+
+void bar(const char *);
+
+// CHECK: define void @f0()
void f0() {
bar("hello");
+ // CHECK: call void @bar({{.*}} @.str
}
+// CHECK: define void @f1()
void f1() {
static char *x = "hello";
bar(x);
+ // CHECK: [[T1:%.*]] = load i8** @f1.x
+ // CHECK: call void @bar(i8* [[T1:%.*]])
}
+// CHECK: define void @f2()
void f2() {
static char x[] = "hello";
bar(x);
+ // CHECK: call void @bar({{.*}} @f2.x
}
+// CHECK: define void @f3()
void f3() {
static char x[8] = "hello";
bar(x);
+ // CHECK: call void @bar({{.*}} @f3.x
}
+void gaz(void *);
+
+// CHECK: define void @f4()
void f4() {
static struct s {
char *name;
} x = { "hello" };
gaz(&x);
+ // CHECK: call void @gaz({{.*}} @f4.x
}
char x[3] = "ola";
+
diff --git a/test/CodeGen/c11atomics-ios.c b/test/CodeGen/c11atomics-ios.c
new file mode 100644
index 0000000..d1c9b14
--- /dev/null
+++ b/test/CodeGen/c11atomics-ios.c
@@ -0,0 +1,214 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple=armv7-apple-ios -std=c11 | FileCheck %s
+
+// There isn't really anything special about iOS; it just happens to
+// only deploy on processors with native atomics support, so it's a good
+// way to test those code-paths.
+
+// This work was done in pursuit of <rdar://13338582>.
+
+// CHECK: define arm_aapcscc void @testFloat(float*
+void testFloat(_Atomic(float) *fp) {
+// CHECK: [[FP:%.*]] = alloca float*
+// CHECK-NEXT: [[X:%.*]] = alloca float
+// CHECK-NEXT: [[F:%.*]] = alloca float
+// CHECK-NEXT: store float* {{%.*}}, float** [[FP]]
+
+// CHECK-NEXT: [[T0:%.*]] = load float** [[FP]]
+// CHECK-NEXT: store float 1.000000e+00, float* [[T0]], align 4
+ __c11_atomic_init(fp, 1.0f);
+
+// CHECK-NEXT: store float 2.000000e+00, float* [[X]], align 4
+ _Atomic(float) x = 2.0f;
+
+// CHECK-NEXT: [[T0:%.*]] = load float** [[FP]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast float* [[T0]] to i32*
+// CHECK-NEXT: [[T2:%.*]] = load atomic i32* [[T1]] seq_cst, align 4
+// CHECK-NEXT: [[T3:%.*]] = bitcast i32 [[T2]] to float
+// CHECK-NEXT: store float [[T3]], float* [[F]]
+ float f = *fp;
+
+// CHECK-NEXT: [[T0:%.*]] = load float* [[F]], align 4
+// CHECK-NEXT: [[T1:%.*]] = load float** [[FP]], align 4
+// CHECK-NEXT: [[T2:%.*]] = bitcast float [[T0]] to i32
+// CHECK-NEXT: [[T3:%.*]] = bitcast float* [[T1]] to i32*
+// CHECK-NEXT: store atomic i32 [[T2]], i32* [[T3]] seq_cst, align 4
+ *fp = f;
+
+// CHECK-NEXT: ret void
+}
+
+// CHECK: define arm_aapcscc void @testComplexFloat([[CF:{ float, float }]]*
+void testComplexFloat(_Atomic(_Complex float) *fp) {
+// CHECK: [[FP:%.*]] = alloca [[CF]]*, align 4
+// CHECK-NEXT: [[X:%.*]] = alloca [[CF]], align 8
+// CHECK-NEXT: [[F:%.*]] = alloca [[CF]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = alloca [[CF]], align 8
+// CHECK-NEXT: [[TMP1:%.*]] = alloca [[CF]], align 8
+// CHECK-NEXT: store [[CF]]*
+
+// CHECK-NEXT: [[P:%.*]] = load [[CF]]** [[FP]]
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[P]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[CF]]* [[P]], i32 0, i32 1
+// CHECK-NEXT: store float 1.000000e+00, float* [[T0]]
+// CHECK-NEXT: store float 0.000000e+00, float* [[T1]]
+ __c11_atomic_init(fp, 1.0f);
+
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[X]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[CF]]* [[X]], i32 0, i32 1
+// CHECK-NEXT: store float 2.000000e+00, float* [[T0]]
+// CHECK-NEXT: store float 0.000000e+00, float* [[T1]]
+ _Atomic(_Complex float) x = 2.0f;
+
+// CHECK-NEXT: [[T0:%.*]] = load [[CF]]** [[FP]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[CF]]* [[T0]] to i64*
+// CHECK-NEXT: [[T2:%.*]] = load atomic i64* [[T1]] seq_cst, align 8
+// CHECK-NEXT: [[T3:%.*]] = bitcast [[CF]]* [[TMP0]] to i64*
+// CHECK-NEXT: store i64 [[T2]], i64* [[T3]], align 8
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[TMP0]], i32 0, i32 0
+// CHECK-NEXT: [[R:%.*]] = load float* [[T0]]
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[TMP0]], i32 0, i32 1
+// CHECK-NEXT: [[I:%.*]] = load float* [[T0]]
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[F]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[CF]]* [[F]], i32 0, i32 1
+// CHECK-NEXT: store float [[R]], float* [[T0]]
+// CHECK-NEXT: store float [[I]], float* [[T1]]
+ _Complex float f = *fp;
+
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[F]], i32 0, i32 0
+// CHECK-NEXT: [[R:%.*]] = load float* [[T0]]
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[F]], i32 0, i32 1
+// CHECK-NEXT: [[I:%.*]] = load float* [[T0]]
+// CHECK-NEXT: [[DEST:%.*]] = load [[CF]]** [[FP]], align 4
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[TMP1]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[CF]]* [[TMP1]], i32 0, i32 1
+// CHECK-NEXT: store float [[R]], float* [[T0]]
+// CHECK-NEXT: store float [[I]], float* [[T1]]
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[CF]]* [[TMP1]] to i64*
+// CHECK-NEXT: [[T1:%.*]] = load i64* [[T0]], align 8
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[CF]]* [[DEST]] to i64*
+// CHECK-NEXT: store atomic i64 [[T1]], i64* [[T2]] seq_cst, align 8
+ *fp = f;
+
+// CHECK-NEXT: ret void
+}
+
+typedef struct { short x, y, z, w; } S;
+// CHECK: define arm_aapcscc void @testStruct([[S:.*]]*
+void testStruct(_Atomic(S) *fp) {
+// CHECK: [[FP:%.*]] = alloca [[S]]*, align 4
+// CHECK-NEXT: [[X:%.*]] = alloca [[S]], align 8
+// CHECK-NEXT: [[F:%.*]] = alloca [[S:%.*]], align 2
+// CHECK-NEXT: [[TMP0:%.*]] = alloca [[S]], align 8
+// CHECK-NEXT: store [[S]]*
+
+// CHECK-NEXT: [[P:%.*]] = load [[S]]** [[FP]]
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[S]]* [[P]] to i8*
+// CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 8, i32 8, i1 false)
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[P]], i32 0, i32 0
+// CHECK-NEXT: store i16 1, i16* [[T0]], align 2
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[P]], i32 0, i32 1
+// CHECK-NEXT: store i16 2, i16* [[T0]], align 2
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[P]], i32 0, i32 2
+// CHECK-NEXT: store i16 3, i16* [[T0]], align 2
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[P]], i32 0, i32 3
+// CHECK-NEXT: store i16 4, i16* [[T0]], align 2
+ __c11_atomic_init(fp, (S){1,2,3,4});
+
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[S]]* [[X]] to i8*
+// CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 8, i32 8, i1 false)
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[X]], i32 0, i32 0
+// CHECK-NEXT: store i16 1, i16* [[T0]], align 2
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[X]], i32 0, i32 1
+// CHECK-NEXT: store i16 2, i16* [[T0]], align 2
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[X]], i32 0, i32 2
+// CHECK-NEXT: store i16 3, i16* [[T0]], align 2
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[X]], i32 0, i32 3
+// CHECK-NEXT: store i16 4, i16* [[T0]], align 2
+ _Atomic(S) x = (S){1,2,3,4};
+
+// CHECK-NEXT: [[T0:%.*]] = load [[S]]** [[FP]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[S]]* [[T0]] to i64*
+// CHECK-NEXT: [[T2:%.*]] = load atomic i64* [[T1]] seq_cst, align 8
+// CHECK-NEXT: [[T3:%.*]] = bitcast [[S]]* [[F]] to i64*
+// CHECK-NEXT: store i64 [[T2]], i64* [[T3]], align 2
+ S f = *fp;
+
+// CHECK-NEXT: [[T0:%.*]] = load [[S]]** [[FP]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[S]]* [[TMP0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[S]]* [[F]] to i8*
+// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[T1]], i8* [[T2]], i32 8, i32 2, i1 false)
+// CHECK-NEXT: [[T3:%.*]] = bitcast [[S]]* [[TMP0]] to i64*
+// CHECK-NEXT: [[T4:%.*]] = load i64* [[T3]], align 8
+// CHECK-NEXT: [[T5:%.*]] = bitcast [[S]]* [[T0]] to i64*
+// CHECK-NEXT: store atomic i64 [[T4]], i64* [[T5]] seq_cst, align 8
+ *fp = f;
+
+// CHECK-NEXT: ret void
+}
+
+typedef struct { short x, y, z; } PS;
+// CHECK: define arm_aapcscc void @testPromotedStruct([[APS:.*]]*
+void testPromotedStruct(_Atomic(PS) *fp) {
+// CHECK: [[FP:%.*]] = alloca [[APS]]*, align 4
+// CHECK-NEXT: [[X:%.*]] = alloca [[APS]], align 8
+// CHECK-NEXT: [[F:%.*]] = alloca [[PS:%.*]], align 2
+// CHECK-NEXT: [[TMP0:%.*]] = alloca [[APS]], align 8
+// CHECK-NEXT: [[TMP1:%.*]] = alloca [[APS]], align 8
+// CHECK-NEXT: store [[APS]]*
+
+// CHECK-NEXT: [[P:%.*]] = load [[APS]]** [[FP]]
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[APS]]* [[P]] to i8*
+// CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 8, i32 8, i1 false)
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[APS]]* [[P]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[PS]]* [[T0]], i32 0, i32 0
+// CHECK-NEXT: store i16 1, i16* [[T1]], align 2
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[PS]]* [[T0]], i32 0, i32 1
+// CHECK-NEXT: store i16 2, i16* [[T1]], align 2
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[PS]]* [[T0]], i32 0, i32 2
+// CHECK-NEXT: store i16 3, i16* [[T1]], align 2
+ __c11_atomic_init(fp, (PS){1,2,3});
+
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[APS]]* [[X]] to i8*
+// CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 8, i32 8, i1 false)
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[APS]]* [[X]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[PS]]* [[T0]], i32 0, i32 0
+// CHECK-NEXT: store i16 1, i16* [[T1]], align 2
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[PS]]* [[T0]], i32 0, i32 1
+// CHECK-NEXT: store i16 2, i16* [[T1]], align 2
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[PS]]* [[T0]], i32 0, i32 2
+// CHECK-NEXT: store i16 3, i16* [[T1]], align 2
+ _Atomic(PS) x = (PS){1,2,3};
+
+// CHECK-NEXT: [[T0:%.*]] = load [[APS]]** [[FP]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[APS]]* [[T0]] to i64*
+// CHECK-NEXT: [[T2:%.*]] = load atomic i64* [[T1]] seq_cst, align 8
+// CHECK-NEXT: [[T3:%.*]] = bitcast [[APS]]* [[TMP0]] to i64*
+// CHECK-NEXT: store i64 [[T2]], i64* [[T3]], align 8
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[APS]]* [[TMP0]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[PS]]* [[F]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[PS]]* [[T0]] to i8*
+// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[T1]], i8* [[T2]], i32 6, i32 2, i1 false)
+ PS f = *fp;
+
+// CHECK-NEXT: [[T0:%.*]] = load [[APS]]** [[FP]]
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[APS]]* [[TMP1]], i32 0, i32 0
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[PS]]* [[T1]] to i8*
+// CHECK-NEXT: [[T3:%.*]] = bitcast [[PS]]* [[F]] to i8*
+// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[T2]], i8* [[T3]], i32 6, i32 2, i1 false)
+// CHECK-NEXT: [[T4:%.*]] = bitcast [[APS]]* [[TMP1]] to i64*
+// CHECK-NEXT: [[T5:%.*]] = load i64* [[T4]], align 8
+// CHECK-NEXT: [[T6:%.*]] = bitcast [[APS]]* [[T0]] to i64*
+// CHECK-NEXT: store atomic i64 [[T5]], i64* [[T6]] seq_cst, align 8
+ *fp = f;
+
+// CHECK-NEXT: ret void
+}
+
+void testPromotedStructOps(_Atomic(PS) *p) {
+ PS a = __c11_atomic_load(p, 5);
+ __c11_atomic_store(p, a, 5);
+ PS b = __c11_atomic_exchange(p, a, 5);
+
+ _Bool v = __c11_atomic_compare_exchange_strong(p, &b, a, 5, 5);
+ v = __c11_atomic_compare_exchange_weak(p, &b, a, 5, 5);
+}
diff --git a/test/CodeGen/c11atomics.c b/test/CodeGen/c11atomics.c
new file mode 100644
index 0000000..8d298af
--- /dev/null
+++ b/test/CodeGen/c11atomics.c
@@ -0,0 +1,344 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple=armv7-unknown-freebsd -std=c11 | FileCheck %s
+
+// Test that we are generating atomicrmw instructions, rather than
+// compare-exchange loops for common atomic ops. This makes a big difference
+// on RISC platforms, where the compare-exchange loop becomes a ll/sc pair for
+// the load and then another ll/sc in the loop, expanding to about 30
+// instructions when it should be only 4. It has a smaller, but still
+// noticeable, impact on platforms like x86 and RISC-V, where there are atomic
+// RMW instructions.
+//
+// We currently emit cmpxchg loops for most operations on _Bools, because
+// they're sufficiently rare that it's not worth making sure that the semantics
+// are correct.
+
+typedef int __attribute__((vector_size(16))) vector;
+
+_Atomic(_Bool) b;
+_Atomic(int) i;
+_Atomic(long long) l;
+_Atomic(short) s;
+_Atomic(char*) p;
+_Atomic(float) f;
+_Atomic(vector) v;
+
+// CHECK: testinc
+void testinc(void)
+{
+ // Special case for suffix bool++, sets to true and returns the old value.
+ // CHECK: atomicrmw xchg i8* @b, i8 1 seq_cst
+ b++;
+ // CHECK: atomicrmw add i32* @i, i32 1 seq_cst
+ i++;
+ // CHECK: atomicrmw add i64* @l, i64 1 seq_cst
+ l++;
+ // CHECK: atomicrmw add i16* @s, i16 1 seq_cst
+ s++;
+ // Prefix increment
+ // Special case for bool: set to true and return true
+ // CHECK: store atomic i8 1, i8* @b seq_cst, align 1
+ ++b;
+ // Currently, we have no variant of atomicrmw that returns the new value, so
+ // we have to generate an atomic add, which returns the old value, and then a
+ // non-atomic add.
+ // CHECK: atomicrmw add i32* @i, i32 1 seq_cst
+ // CHECK: add i32
+ ++i;
+ // CHECK: atomicrmw add i64* @l, i64 1 seq_cst
+ // CHECK: add i64
+ ++l;
+ // CHECK: atomicrmw add i16* @s, i16 1 seq_cst
+ // CHECK: add i16
+ ++s;
+}
+// CHECK: testdec
+void testdec(void)
+{
+ // CHECK: cmpxchg i8* @b
+ b--;
+ // CHECK: atomicrmw sub i32* @i, i32 1 seq_cst
+ i--;
+ // CHECK: atomicrmw sub i64* @l, i64 1 seq_cst
+ l--;
+ // CHECK: atomicrmw sub i16* @s, i16 1 seq_cst
+ s--;
+ // CHECK: cmpxchg i8* @b
+ --b;
+ // CHECK: atomicrmw sub i32* @i, i32 1 seq_cst
+ // CHECK: sub i32
+ --i;
+ // CHECK: atomicrmw sub i64* @l, i64 1 seq_cst
+ // CHECK: sub i64
+ --l;
+ // CHECK: atomicrmw sub i16* @s, i16 1 seq_cst
+ // CHECK: sub i16
+ --s;
+}
+// CHECK: testaddeq
+void testaddeq(void)
+{
+ // CHECK: cmpxchg i8* @b
+ // CHECK: atomicrmw add i32* @i, i32 42 seq_cst
+ // CHECK: atomicrmw add i64* @l, i64 42 seq_cst
+ // CHECK: atomicrmw add i16* @s, i16 42 seq_cst
+ b += 42;
+ i += 42;
+ l += 42;
+ s += 42;
+}
+// CHECK: testsubeq
+void testsubeq(void)
+{
+ // CHECK: cmpxchg i8* @b
+ // CHECK: atomicrmw sub i32* @i, i32 42 seq_cst
+ // CHECK: atomicrmw sub i64* @l, i64 42 seq_cst
+ // CHECK: atomicrmw sub i16* @s, i16 42 seq_cst
+ b -= 42;
+ i -= 42;
+ l -= 42;
+ s -= 42;
+}
+// CHECK: testxoreq
+void testxoreq(void)
+{
+ // CHECK: cmpxchg i8* @b
+ // CHECK: atomicrmw xor i32* @i, i32 42 seq_cst
+ // CHECK: atomicrmw xor i64* @l, i64 42 seq_cst
+ // CHECK: atomicrmw xor i16* @s, i16 42 seq_cst
+ b ^= 42;
+ i ^= 42;
+ l ^= 42;
+ s ^= 42;
+}
+// CHECK: testoreq
+void testoreq(void)
+{
+ // CHECK: cmpxchg i8* @b
+ // CHECK: atomicrmw or i32* @i, i32 42 seq_cst
+ // CHECK: atomicrmw or i64* @l, i64 42 seq_cst
+ // CHECK: atomicrmw or i16* @s, i16 42 seq_cst
+ b |= 42;
+ i |= 42;
+ l |= 42;
+ s |= 42;
+}
+// CHECK: testandeq
+void testandeq(void)
+{
+ // CHECK: cmpxchg i8* @b
+ // CHECK: atomicrmw and i32* @i, i32 42 seq_cst
+ // CHECK: atomicrmw and i64* @l, i64 42 seq_cst
+ // CHECK: atomicrmw and i16* @s, i16 42 seq_cst
+ b &= 42;
+ i &= 42;
+ l &= 42;
+ s &= 42;
+}
+
+// CHECK: define arm_aapcscc void @testFloat(float*
+void testFloat(_Atomic(float) *fp) {
+// CHECK: [[FP:%.*]] = alloca float*
+// CHECK-NEXT: [[X:%.*]] = alloca float
+// CHECK-NEXT: [[F:%.*]] = alloca float
+// CHECK-NEXT: [[TMP0:%.*]] = alloca float
+// CHECK-NEXT: [[TMP1:%.*]] = alloca float
+// CHECK-NEXT: store float* {{%.*}}, float** [[FP]]
+
+// CHECK-NEXT: [[T0:%.*]] = load float** [[FP]]
+// CHECK-NEXT: store float 1.000000e+00, float* [[T0]], align 4
+ __c11_atomic_init(fp, 1.0f);
+
+// CHECK-NEXT: store float 2.000000e+00, float* [[X]], align 4
+ _Atomic(float) x = 2.0f;
+
+// CHECK-NEXT: [[T0:%.*]] = load float** [[FP]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast float* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = bitcast float* [[TMP0]] to i8*
+// CHECK-NEXT: call arm_aapcscc void @__atomic_load(i32 4, i8* [[T1]], i8* [[T2]], i32 5)
+// CHECK-NEXT: [[T3:%.*]] = load float* [[TMP0]], align 4
+// CHECK-NEXT: store float [[T3]], float* [[F]]
+ float f = *fp;
+
+// CHECK-NEXT: [[T0:%.*]] = load float* [[F]], align 4
+// CHECK-NEXT: [[T1:%.*]] = load float** [[FP]], align 4
+// CHECK-NEXT: store float [[T0]], float* [[TMP1]], align 4
+// CHECK-NEXT: [[T2:%.*]] = bitcast float* [[T1]] to i8*
+// CHECK-NEXT: [[T3:%.*]] = bitcast float* [[TMP1]] to i8*
+// CHECK-NEXT: call arm_aapcscc void @__atomic_store(i32 4, i8* [[T2]], i8* [[T3]], i32 5)
+ *fp = f;
+
+// CHECK-NEXT: ret void
+}
+
+// CHECK: define arm_aapcscc void @testComplexFloat([[CF:{ float, float }]]*
+void testComplexFloat(_Atomic(_Complex float) *fp) {
+// CHECK: [[FP:%.*]] = alloca [[CF]]*, align 4
+// CHECK-NEXT: [[X:%.*]] = alloca [[CF]], align 8
+// CHECK-NEXT: [[F:%.*]] = alloca [[CF]], align 4
+// CHECK-NEXT: [[TMP0:%.*]] = alloca [[CF]], align 8
+// CHECK-NEXT: [[TMP1:%.*]] = alloca [[CF]], align 8
+// CHECK-NEXT: store [[CF]]*
+
+// CHECK-NEXT: [[P:%.*]] = load [[CF]]** [[FP]]
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[P]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[CF]]* [[P]], i32 0, i32 1
+// CHECK-NEXT: store float 1.000000e+00, float* [[T0]]
+// CHECK-NEXT: store float 0.000000e+00, float* [[T1]]
+ __c11_atomic_init(fp, 1.0f);
+
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[X]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[CF]]* [[X]], i32 0, i32 1
+// CHECK-NEXT: store float 2.000000e+00, float* [[T0]]
+// CHECK-NEXT: store float 0.000000e+00, float* [[T1]]
+ _Atomic(_Complex float) x = 2.0f;
+
+// CHECK-NEXT: [[T0:%.*]] = load [[CF]]** [[FP]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[CF]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[CF]]* [[TMP0]] to i8*
+// CHECK-NEXT: call arm_aapcscc void @__atomic_load(i32 8, i8* [[T1]], i8* [[T2]], i32 5)
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[TMP0]], i32 0, i32 0
+// CHECK-NEXT: [[R:%.*]] = load float* [[T0]]
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[TMP0]], i32 0, i32 1
+// CHECK-NEXT: [[I:%.*]] = load float* [[T0]]
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[F]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[CF]]* [[F]], i32 0, i32 1
+// CHECK-NEXT: store float [[R]], float* [[T0]]
+// CHECK-NEXT: store float [[I]], float* [[T1]]
+ _Complex float f = *fp;
+
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[F]], i32 0, i32 0
+// CHECK-NEXT: [[R:%.*]] = load float* [[T0]]
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[F]], i32 0, i32 1
+// CHECK-NEXT: [[I:%.*]] = load float* [[T0]]
+// CHECK-NEXT: [[DEST:%.*]] = load [[CF]]** [[FP]], align 4
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[CF]]* [[TMP1]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[CF]]* [[TMP1]], i32 0, i32 1
+// CHECK-NEXT: store float [[R]], float* [[T0]]
+// CHECK-NEXT: store float [[I]], float* [[T1]]
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[CF]]* [[DEST]] to i8*
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[CF]]* [[TMP1]] to i8*
+// CHECK-NEXT: call arm_aapcscc void @__atomic_store(i32 8, i8* [[T0]], i8* [[T1]], i32 5)
+ *fp = f;
+
+// CHECK-NEXT: ret void
+}
+
+typedef struct { short x, y, z, w; } S;
+// CHECK: define arm_aapcscc void @testStruct([[S:.*]]*
+void testStruct(_Atomic(S) *fp) {
+// CHECK: [[FP:%.*]] = alloca [[S]]*, align 4
+// CHECK-NEXT: [[X:%.*]] = alloca [[S]], align 8
+// CHECK-NEXT: [[F:%.*]] = alloca [[S:%.*]], align 2
+// CHECK-NEXT: [[TMP0:%.*]] = alloca [[S]], align 8
+// CHECK-NEXT: store [[S]]*
+
+// CHECK-NEXT: [[P:%.*]] = load [[S]]** [[FP]]
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[S]]* [[P]] to i8*
+// CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 8, i32 8, i1 false)
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[P]], i32 0, i32 0
+// CHECK-NEXT: store i16 1, i16* [[T0]], align 2
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[P]], i32 0, i32 1
+// CHECK-NEXT: store i16 2, i16* [[T0]], align 2
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[P]], i32 0, i32 2
+// CHECK-NEXT: store i16 3, i16* [[T0]], align 2
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[P]], i32 0, i32 3
+// CHECK-NEXT: store i16 4, i16* [[T0]], align 2
+ __c11_atomic_init(fp, (S){1,2,3,4});
+
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[S]]* [[X]] to i8*
+// CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 8, i32 8, i1 false)
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[X]], i32 0, i32 0
+// CHECK-NEXT: store i16 1, i16* [[T0]], align 2
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[X]], i32 0, i32 1
+// CHECK-NEXT: store i16 2, i16* [[T0]], align 2
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[X]], i32 0, i32 2
+// CHECK-NEXT: store i16 3, i16* [[T0]], align 2
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[S]]* [[X]], i32 0, i32 3
+// CHECK-NEXT: store i16 4, i16* [[T0]], align 2
+ _Atomic(S) x = (S){1,2,3,4};
+
+// CHECK-NEXT: [[T0:%.*]] = load [[S]]** [[FP]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[S]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[S]]* [[F]] to i8*
+// CHECK-NEXT: call arm_aapcscc void @__atomic_load(i32 8, i8* [[T1]], i8* [[T2]], i32 5)
+ S f = *fp;
+
+// CHECK-NEXT: [[T0:%.*]] = load [[S]]** [[FP]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[S]]* [[TMP0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[S]]* [[F]] to i8*
+// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[T1]], i8* [[T2]], i32 8, i32 2, i1 false)
+// CHECK-NEXT: [[T3:%.*]] = bitcast [[S]]* [[T0]] to i8*
+// CHECK-NEXT: [[T4:%.*]] = bitcast [[S]]* [[TMP0]] to i8*
+// CHECK-NEXT: call arm_aapcscc void @__atomic_store(i32 8, i8* [[T3]], i8* [[T4]], i32 5)
+ *fp = f;
+
+// CHECK-NEXT: ret void
+}
+
+typedef struct { short x, y, z; } PS;
+// CHECK: define arm_aapcscc void @testPromotedStruct([[APS:.*]]*
+void testPromotedStruct(_Atomic(PS) *fp) {
+// CHECK: [[FP:%.*]] = alloca [[APS]]*, align 4
+// CHECK-NEXT: [[X:%.*]] = alloca [[APS]], align 8
+// CHECK-NEXT: [[F:%.*]] = alloca [[PS:%.*]], align 2
+// CHECK-NEXT: [[TMP0:%.*]] = alloca [[APS]], align 8
+// CHECK-NEXT: [[TMP1:%.*]] = alloca [[APS]], align 8
+// CHECK-NEXT: store [[APS]]*
+
+// CHECK-NEXT: [[P:%.*]] = load [[APS]]** [[FP]]
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[APS]]* [[P]] to i8*
+// CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 8, i32 8, i1 false)
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[APS]]* [[P]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[PS]]* [[T0]], i32 0, i32 0
+// CHECK-NEXT: store i16 1, i16* [[T1]], align 2
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[PS]]* [[T0]], i32 0, i32 1
+// CHECK-NEXT: store i16 2, i16* [[T1]], align 2
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[PS]]* [[T0]], i32 0, i32 2
+// CHECK-NEXT: store i16 3, i16* [[T1]], align 2
+ __c11_atomic_init(fp, (PS){1,2,3});
+
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[APS]]* [[X]] to i8*
+// CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 8, i32 8, i1 false)
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[APS]]* [[X]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[PS]]* [[T0]], i32 0, i32 0
+// CHECK-NEXT: store i16 1, i16* [[T1]], align 2
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[PS]]* [[T0]], i32 0, i32 1
+// CHECK-NEXT: store i16 2, i16* [[T1]], align 2
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[PS]]* [[T0]], i32 0, i32 2
+// CHECK-NEXT: store i16 3, i16* [[T1]], align 2
+ _Atomic(PS) x = (PS){1,2,3};
+
+// CHECK-NEXT: [[T0:%.*]] = load [[APS]]** [[FP]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[APS]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[APS]]* [[TMP0]] to i8*
+// CHECK-NEXT: call arm_aapcscc void @__atomic_load(i32 8, i8* [[T1]], i8* [[T2]], i32 5)
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[APS]]* [[TMP0]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[PS]]* [[F]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[PS]]* [[T0]] to i8*
+// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[T1]], i8* [[T2]], i32 6, i32 2, i1 false)
+ PS f = *fp;
+
+// CHECK-NEXT: [[T0:%.*]] = load [[APS]]** [[FP]]
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[APS]]* [[TMP1]], i32 0, i32 0
+// CHECK-NEXT: [[T2:%.*]] = bitcast [[PS]]* [[T1]] to i8*
+// CHECK-NEXT: [[T3:%.*]] = bitcast [[PS]]* [[F]] to i8*
+// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[T2]], i8* [[T3]], i32 6, i32 2, i1 false)
+// CHECK-NEXT: [[T4:%.*]] = bitcast [[APS]]* [[T0]] to i8*
+// CHECK-NEXT: [[T5:%.*]] = bitcast [[APS]]* [[TMP1]] to i8*
+// CHECK-NEXT: call arm_aapcscc void @__atomic_store(i32 8, i8* [[T4]], i8* [[T5]], i32 5)
+ *fp = f;
+
+// CHECK-NEXT: ret void
+}
+
+// CHECK: define arm_aapcscc void @testPromotedStructOps([[APS:.*]]*
+
+// FIXME: none of these look right, but we can leave the "test" here
+// to make sure they at least don't crash.
+void testPromotedStructOps(_Atomic(PS) *p) {
+ PS a = __c11_atomic_load(p, 5);
+ __c11_atomic_store(p, a, 5);
+ PS b = __c11_atomic_exchange(p, a, 5);
+ _Bool v = __c11_atomic_compare_exchange_strong(p, &b, a, 5, 5);
+ v = __c11_atomic_compare_exchange_weak(p, &b, a, 5, 5);
+}
diff --git a/test/CodeGen/catch-undef-behavior.c b/test/CodeGen/catch-undef-behavior.c
index 4198b62..ebe39fe 100644
--- a/test/CodeGen/catch-undef-behavior.c
+++ b/test/CodeGen/catch-undef-behavior.c
@@ -1,14 +1,14 @@
-// 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=alignment,null,object-size,shift,return,signed-integer-overflow,vla-bound,float-cast-overflow,integer-divide-by-zero,bool -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
+// RUN: %clang_cc1 -fsanitize-undefined-trap-on-error -fsanitize=alignment,null,object-size,shift,return,signed-integer-overflow,vla-bound,float-cast-overflow,integer-divide-by-zero,bool -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK-TRAP
// 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_100:.*]] = private unnamed_addr global {{.*}}, 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_300:.*]] = {{.*}}, 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 }
@@ -19,49 +19,78 @@
// 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 {{.*}}
+// CHECK-NULL: @[[LINE_100:.*]] = private unnamed_addr global {{.*}}, i32 100, i32 5 {{.*}}
// PR6805
// CHECK: @foo
// CHECK-NULL: @foo
+// CHECK-TRAP: @foo
void foo() {
union { int i; } u;
// CHECK: %[[CHECK0:.*]] = icmp ne {{.*}}* %[[PTR:.*]], null
+ // CHECK-TRAP: %[[CHECK0:.*]] = icmp ne {{.*}}* %[[PTR:.*]], null
// CHECK: %[[I8PTR:.*]] = bitcast i32* %[[PTR]] to i8*
// CHECK-NEXT: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64(i8* %[[I8PTR]], i1 false)
// CHECK-NEXT: %[[CHECK1:.*]] = icmp uge i64 %[[SIZE]], 4
// CHECK-NEXT: %[[CHECK01:.*]] = and i1 %[[CHECK0]], %[[CHECK1]]
+ // CHECK-TRAP: %[[I8PTR:.*]] = bitcast i32* %[[PTR]] to i8*
+ // CHECK-TRAP-NEXT: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64(i8* %[[I8PTR]], i1 false)
+ // CHECK-TRAP-NEXT: %[[CHECK1:.*]] = icmp uge i64 %[[SIZE]], 4
+ // CHECK-TRAP-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-TRAP: %[[PTRTOINT:.*]] = ptrtoint {{.*}}* %[[PTR]] to i64
+ // CHECK-TRAP-NEXT: %[[MISALIGN:.*]] = and i64 %[[PTRTOINT]], 3
+ // CHECK-TRAP-NEXT: %[[CHECK2:.*]] = icmp eq i64 %[[MISALIGN]], 0
+
// CHECK: %[[OK:.*]] = and i1 %[[CHECK01]], %[[CHECK2]]
- // CHECK-NEXT: br i1 %[[OK]]
+ // CHECK-NEXT: br i1 %[[OK]], {{.*}} !prof ![[WEIGHT_MD:.*]]
+
+ // CHECK-TRAP: %[[OK:.*]] = and i1 %[[CHECK01]], %[[CHECK2]]
+ // CHECK-TRAP-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
+ // CHECK-NEXT: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_100]] to i8*), i64 %[[ARG]])
+
+ // CHECK-TRAP: call void @llvm.trap() [[NR_NUW:#[0-9]+]]
+ // CHECK-TRAP-NEXT: unreachable
// With -fsanitize=null, only perform the null check.
// CHECK-NULL: %[[NULL:.*]] = icmp ne {{.*}}, null
// CHECK-NULL: br i1 %[[NULL]]
- // CHECK-NULL: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_100]] to i8*), i64 %{{.*}}) noreturn nounwind
+ // CHECK-NULL: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_100]] to i8*), i64 %{{.*}})
#line 100
u.i=1;
}
// CHECK: @bar
+// CHECK-TRAP: @bar
int bar(int *a) {
// CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64
// CHECK-NEXT: icmp uge i64 %[[SIZE]], 4
+ // CHECK-TRAP: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64
+ // CHECK-TRAP-NEXT: icmp uge i64 %[[SIZE]], 4
+
// CHECK: %[[PTRINT:.*]] = ptrtoint
// CHECK-NEXT: %[[MISALIGN:.*]] = and i64 %[[PTRINT]], 3
// CHECK-NEXT: icmp eq i64 %[[MISALIGN]], 0
+ // CHECK-TRAP: %[[PTRINT:.*]] = ptrtoint
+ // CHECK-TRAP-NEXT: %[[MISALIGN:.*]] = and i64 %[[PTRINT]], 3
+ // CHECK-TRAP-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
+ // CHECK-NEXT: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_200]] to i8*), i64 %[[ARG]])
+
+ // CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
+ // CHECK-TRAP-NEXT: unreachable
+
#line 200
return *a;
}
@@ -73,55 +102,92 @@ int addr_space(int __attribute__((address_space(256))) *a) {
}
// CHECK: @lsh_overflow
+// CHECK-TRAP: @lsh_overflow
int lsh_overflow(int a, int b) {
// CHECK: %[[INBOUNDS:.*]] = icmp ule i32 %[[RHS:.*]], 31
- // CHECK-NEXT: br i1 %[[INBOUNDS]]
+ // CHECK-NEXT: br i1 %[[INBOUNDS]], label %[[CHECKBB:.*]], label %[[CONTBB:.*]]
- // 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-TRAP: %[[INBOUNDS:.*]] = icmp ule i32 %[[RHS:.*]], 31
+ // CHECK-TRAP-NEXT: br i1 %[[INBOUNDS]], label %[[CHECKBB:.*]], label %[[CONTBB:.*]]
// 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-NEXT: br label %[[CONTBB]]
+
+ // CHECK-TRAP: %[[SHIFTED_OUT_WIDTH:.*]] = sub nuw nsw i32 31, %[[RHS]]
+ // CHECK-TRAP-NEXT: %[[SHIFTED_OUT:.*]] = lshr i32 %[[LHS:.*]], %[[SHIFTED_OUT_WIDTH]]
+ // CHECK-TRAP-NEXT: %[[NO_OVERFLOW:.*]] = icmp eq i32 %[[SHIFTED_OUT]], 0
+ // CHECK-TRAP-NEXT: br label %[[CONTBB]]
+
+ // CHECK: %[[VALID:.*]] = phi i1 [ %[[INBOUNDS]], {{.*}} ], [ %[[NO_OVERFLOW]], %[[CHECKBB]] ]
+ // CHECK-NEXT: br i1 %[[VALID]], {{.*}} !prof ![[WEIGHT_MD]]
+
+ // CHECK-TRAP: %[[VALID:.*]] = phi i1 [ %[[INBOUNDS]], {{.*}} ], [ %[[NO_OVERFLOW]], %[[CHECKBB]] ]
+ // CHECK-TRAP-NEXT: br i1 %[[VALID]]
+
// 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-NEXT: call void @__ubsan_handle_shift_out_of_bounds(i8* bitcast ({{.*}} @[[LINE_300]] to i8*), i64 %[[ARG1]], i64 %[[ARG2]])
+ // CHECK-NOT: call void @__ubsan_handle_shift_out_of_bounds
+
+ // CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
+ // CHECK-TRAP: unreachable
+ // CHECK-TRAP-NOT: call void @llvm.trap()
// CHECK: %[[RET:.*]] = shl i32 %[[LHS]], %[[RHS]]
// CHECK-NEXT: ret i32 %[[RET]]
+
+ // CHECK-TRAP: %[[RET:.*]] = shl i32 %[[LHS]], %[[RHS]]
+ // CHECK-TRAP-NEXT: ret i32 %[[RET]]
#line 300
return a << b;
}
// CHECK: @rsh_inbounds
+// CHECK-TRAP: @rsh_inbounds
int rsh_inbounds(int a, int b) {
- // CHECK: %[[INBOUNDS:.*]] = icmp ult i32 %[[RHS:.*]], 32
+ // CHECK: %[[INBOUNDS:.*]] = icmp ule i32 %[[RHS:.*]], 31
// CHECK: br i1 %[[INBOUNDS]]
+ // CHECK-TRAP: %[[INBOUNDS:.*]] = icmp ule i32 %[[RHS:.*]], 31
+ // CHECK-TRAP: 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-NEXT: call void @__ubsan_handle_shift_out_of_bounds(i8* bitcast ({{.*}} @[[LINE_400]] to i8*), i64 %[[ARG1]], i64 %[[ARG2]])
+
+ // CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
+ // CHECK-TRAP-NEXT: unreachable
// CHECK: %[[RET:.*]] = ashr i32 %[[LHS]], %[[RHS]]
// CHECK-NEXT: ret i32 %[[RET]]
+
+ // CHECK-TRAP: %[[RET:.*]] = ashr i32 %[[LHS]], %[[RHS]]
+ // CHECK-TRAP-NEXT: ret i32 %[[RET]]
#line 400
return a >> b;
}
// CHECK: @load
+// CHECK-TRAP: @load
int load(int *p) {
- // CHECK: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_500]] to i8*), i64 %{{.*}}) noreturn nounwind
+ // CHECK: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_500]] to i8*), i64 %{{.*}})
+
+ // CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
+ // CHECK-TRAP-NEXT: unreachable
#line 500
return *p;
}
// CHECK: @store
+// CHECK-TRAP: @store
void store(int *p, int q) {
- // CHECK: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_600]] to i8*), i64 %{{.*}}) noreturn nounwind
+ // CHECK: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_600]] to i8*), i64 %{{.*}})
+
+ // CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
+ // CHECK-TRAP-NEXT: unreachable
#line 600
*p = q;
}
@@ -129,22 +195,31 @@ void store(int *p, int q) {
struct S { int k; };
// CHECK: @member_access
+// CHECK-TRAP: @member_access
int *member_access(struct S *p) {
- // CHECK: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_700]] to i8*), i64 %{{.*}}) noreturn nounwind
+ // CHECK: call void @__ubsan_handle_type_mismatch(i8* bitcast ({{.*}} @[[LINE_700]] to i8*), i64 %{{.*}})
+
+ // CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
+ // CHECK-TRAP-NEXT: unreachable
#line 700
return &p->k;
}
// CHECK: @signed_overflow
+// CHECK-TRAP: @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
+ // CHECK-NEXT: call void @__ubsan_handle_add_overflow(i8* bitcast ({{.*}} @[[LINE_800]] to i8*), i64 %[[ARG1]], i64 %[[ARG2]])
+
+ // CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
+ // CHECK-TRAP-NEXT: unreachable
#line 800
return a + b;
}
// CHECK: @no_return
+// CHECK-TRAP: @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
@@ -152,6 +227,10 @@ int no_return() {
// CHECK-NOT: call
// CHECK-NOT: unreachable
// CHECK: ret i32
+
+ // CHECK-TRAP-NOT: call
+ // CHECK-TRAP-NOT: unreachable
+ // CHECK-TRAP: ret i32
}
// CHECK: @vla_bound
@@ -159,7 +238,7 @@ 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
+ // CHECK-NEXT: call void @__ubsan_handle_vla_bound_not_positive(i8* bitcast ({{.*}} @[[LINE_900]] to i8*), i64 %[[ARG]])
#line 900
int arr[n * 3];
}
@@ -171,55 +250,135 @@ float int_float_no_overflow(__int128 n) {
}
// CHECK: @int_float_overflow
+// CHECK-TRAP: @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(
+
+ // CHECK-TRAP: %[[INBOUNDS:.*]] = icmp ule i128 %{{.*}}, -20282409603651670423947251286016
+ // CHECK-TRAP-NEXT: br i1 %[[INBOUNDS]]
+
+ // CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
+ // CHECK-TRAP-NEXT: unreachable
return n;
}
// CHECK: @int_fp16_overflow
+// CHECK-TRAP: @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(
+
+ // CHECK-TRAP: %[[GE:.*]] = icmp sge i32 %{{.*}}, -65504
+ // CHECK-TRAP: %[[LE:.*]] = icmp sle i32 %{{.*}}, 65504
+ // CHECK-TRAP: %[[INBOUNDS:.*]] = and i1 %[[GE]], %[[LE]]
+ // CHECK-TRAP-NEXT: br i1 %[[INBOUNDS]]
+
+ // CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
+ // CHECK-TRAP-NEXT: unreachable
*p = n;
}
// CHECK: @float_int_overflow
+// CHECK-TRAP: @float_int_overflow
int float_int_overflow(float f) {
- // CHECK: %[[GE:.*]] = fcmp oge float %[[F:.*]], 0xC1E0000000000000
- // CHECK: %[[LE:.*]] = fcmp ole float %[[F]], 0x41DFFFFFE0000000
+ // CHECK: %[[GE:.*]] = fcmp ogt float %[[F:.*]], 0xC1E0000020000000
+ // CHECK: %[[LE:.*]] = fcmp olt float %[[F]], 0x41E0000000000000
// CHECK: and i1 %[[GE]], %[[LE]]
- // CHECK: call void @__ubsan_handle_float_cast_overflow(
+
+ // CHECK: %[[CAST:.*]] = bitcast float %[[F]] to i32
+ // CHECK: %[[ARG:.*]] = zext i32 %[[CAST]] to i64
+ // CHECK: call void @__ubsan_handle_float_cast_overflow({{.*}}, i64 %[[ARG]]
+
+ // CHECK-TRAP: %[[GE:.*]] = fcmp ogt float %[[F:.*]], 0xC1E0000020000000
+ // CHECK-TRAP: %[[LE:.*]] = fcmp olt float %[[F]], 0x41E0000000000000
+ // CHECK-TRAP: %[[INBOUNDS:.*]] = and i1 %[[GE]], %[[LE]]
+ // CHECK-TRAP-NEXT: br i1 %[[INBOUNDS]]
+
+ // CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
+ // CHECK-TRAP-NEXT: unreachable
return f;
}
+// CHECK: @long_double_int_overflow
+// CHECK-TRAP: @long_double_int_overflow
+int long_double_int_overflow(long double ld) {
+ // CHECK: alloca x86_fp80
+ // CHECK: %[[GE:.*]] = fcmp ogt x86_fp80 %[[F:.*]], 0xKC01E8000000100000000
+ // CHECK: %[[LE:.*]] = fcmp olt x86_fp80 %[[F]], 0xK401E8000000000000000
+ // CHECK: and i1 %[[GE]], %[[LE]]
+
+ // CHECK: store x86_fp80 %[[F]], x86_fp80* %[[ALLOCA:.*]]
+ // CHECK: %[[ARG:.*]] = ptrtoint x86_fp80* %[[ALLOCA]] to i64
+ // CHECK: call void @__ubsan_handle_float_cast_overflow({{.*}}, i64 %[[ARG]]
+
+ // CHECK-TRAP: %[[GE:.*]] = fcmp ogt x86_fp80 %[[F:.*]], 0xKC01E800000010000000
+ // CHECK-TRAP: %[[LE:.*]] = fcmp olt x86_fp80 %[[F]], 0xK401E800000000000000
+ // CHECK-TRAP: %[[INBOUNDS:.*]] = and i1 %[[GE]], %[[LE]]
+ // CHECK-TRAP-NEXT: br i1 %[[INBOUNDS]]
+
+ // CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
+ // CHECK-TRAP-NEXT: unreachable
+ return ld;
+}
+
// CHECK: @float_uint_overflow
+// CHECK-TRAP: @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: %[[GE:.*]] = fcmp ogt float %[[F:.*]], -1.{{0*}}e+00
+ // CHECK: %[[LE:.*]] = fcmp olt float %[[F]], 0x41F0000000000000
// CHECK: and i1 %[[GE]], %[[LE]]
// CHECK: call void @__ubsan_handle_float_cast_overflow(
+
+ // CHECK-TRAP: %[[GE:.*]] = fcmp ogt float %[[F:.*]], -1.{{0*}}e+00
+ // CHECK-TRAP: %[[LE:.*]] = fcmp olt float %[[F]], 0x41F0000000000000
+ // CHECK-TRAP: %[[INBOUNDS:.*]] = and i1 %[[GE]], %[[LE]]
+ // CHECK-TRAP-NEXT: br i1 %[[INBOUNDS]]
+
+ // CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
+ // CHECK-TRAP-NEXT: unreachable
return f;
}
// CHECK: @fp16_char_overflow
+// CHECK-TRAP: @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: %[[GE:.*]] = fcmp ogt float %[[F:.*]], -1.29{{0*}}e+02
+ // CHECK: %[[LE:.*]] = fcmp olt float %[[F]], 1.28{{0*}}e+02
// CHECK: and i1 %[[GE]], %[[LE]]
// CHECK: call void @__ubsan_handle_float_cast_overflow(
+
+ // CHECK-TRAP: %[[GE:.*]] = fcmp ogt float %[[F:.*]], -1.29{{0*}}e+02
+ // CHECK-TRAP: %[[LE:.*]] = fcmp olt float %[[F]], 1.28{{0*}}e+02
+ // CHECK-TRAP: %[[INBOUNDS:.*]] = and i1 %[[GE]], %[[LE]]
+ // CHECK-TRAP-NEXT: br i1 %[[INBOUNDS]]
+
+ // CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
+ // CHECK-TRAP-NEXT: unreachable
return *p;
}
// CHECK: @float_float_overflow
+// CHECK-TRAP: @float_float_overflow
float float_float_overflow(double f) {
- // CHECK: %[[GE:.*]] = fcmp oge double %[[F:.*]], 0xC7EFFFFFE0000000
- // CHECK: %[[LE:.*]] = fcmp ole double %[[F]], 0x47EFFFFFE0000000
+ // CHECK: %[[F:.*]] = call double @llvm.fabs.f64(
+ // CHECK: %[[GE:.*]] = fcmp ogt double %[[F]], 0x47EFFFFFE0000000
+ // CHECK: %[[LE:.*]] = fcmp olt double %[[F]], 0x7FF0000000000000
// CHECK: and i1 %[[GE]], %[[LE]]
// CHECK: call void @__ubsan_handle_float_cast_overflow(
+
+ // CHECK-TRAP: %[[F:.*]] = call double @llvm.fabs.f64(
+ // CHECK-TRAP: %[[GE:.*]] = fcmp ogt double %[[F]], 0x47EFFFFFE0000000
+ // CHECK-TRAP: %[[LE:.*]] = fcmp olt double %[[F]], 0x7FF0000000000000
+ // CHECK-TRAP: %[[OUTOFBOUNDS:.*]] = and i1 %[[GE]], %[[LE]]
+ // CHECK-TRAP: %[[INBOUNDS:.*]] = xor i1 %[[OUTOFBOUNDS]], true
+ // CHECK-TRAP-NEXT: br i1 %[[INBOUNDS]]
+
+ // CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
+ // CHECK-TRAP-NEXT: unreachable
return f;
}
@@ -228,6 +387,7 @@ float float_float_overflow(double f) {
int int_divide_overflow(int a, int b) {
// CHECK: %[[ZERO:.*]] = icmp ne i32 %[[B:.*]], 0
// CHECK-OVERFLOW-NOT: icmp ne i32 %{{.*}}, 0
+ // CHECK-TRAP: %[[ZERO:.*]] = icmp ne i32 %[[B:.*]], 0
// CHECK: %[[AOK:.*]] = icmp ne i32 %[[A:.*]], -2147483648
// CHECK-NEXT: %[[BOK:.*]] = icmp ne i32 %[[B]], -1
@@ -237,12 +397,41 @@ int int_divide_overflow(int a, int b) {
// CHECK-OVERFLOW-NEXT: %[[BOK:.*]] = icmp ne i32 %[[B:.*]], -1
// CHECK-OVERFLOW-NEXT: %[[OK:.*]] = or i1 %[[AOK]], %[[BOK]]
+ // CHECK-TRAP: %[[AOK:.*]] = icmp ne i32 %[[A:.*]], -2147483648
+ // CHECK-TRAP-NEXT: %[[BOK:.*]] = icmp ne i32 %[[B]], -1
+ // CHECK-TRAP-NEXT: %[[OVER:.*]] = or i1 %[[AOK]], %[[BOK]]
+
// CHECK: %[[OK:.*]] = and i1 %[[ZERO]], %[[OVER]]
// CHECK: br i1 %[[OK]]
// CHECK-OVERFLOW: br i1 %[[OK]]
+
+ // CHECK-TRAP: %[[OK:.*]] = and i1 %[[ZERO]], %[[OVER]]
+ // CHECK-TRAP: br i1 %[[OK]]
+
+ // CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
+ // CHECK-TRAP: unreachable
return a / b;
// CHECK: }
// CHECK-OVERFLOW: }
+ // CHECK-TRAP: }
}
+
+// CHECK: @sour_bool
+_Bool sour_bool(_Bool *p) {
+ // CHECK: %[[OK:.*]] = icmp ule i8 {{.*}}, 1
+ // CHECK: br i1 %[[OK]]
+ // CHECK: call void @__ubsan_handle_load_invalid_value(i8* bitcast ({{.*}}), i64 {{.*}})
+
+ // CHECK-TRAP: %[[OK:.*]] = icmp ule i8 {{.*}}, 1
+ // CHECK-TRAP: br i1 %[[OK]]
+
+ // CHECK-TRAP: call void @llvm.trap() [[NR_NUW]]
+ // CHECK-TRAP: unreachable
+ return *p;
+}
+
+// CHECK: ![[WEIGHT_MD]] = metadata !{metadata !"branch_weights", i32 1048575, i32 1}
+
+// CHECK-TRAP: attributes [[NR_NUW]] = { noreturn nounwind }
diff --git a/test/CodeGen/code-coverage.c b/test/CodeGen/code-coverage.c
new file mode 100644
index 0000000..1b87d64
--- /dev/null
+++ b/test/CodeGen/code-coverage.c
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -emit-llvm -disable-red-zone -femit-coverage-data %s -o - | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -disable-red-zone -femit-coverage-data -coverage-no-function-names-in-data %s -o - | FileCheck %s --check-prefix WITHOUTNAMES
+
+// <rdar://problem/12843084>
+
+int test1(int a) {
+ switch (a % 2) {
+ case 0:
+ ++a;
+ case 1:
+ a /= 2;
+ }
+ return a;
+}
+
+// Check that the noredzone flag is set on the generated functions.
+
+// CHECK: void @__llvm_gcov_indirect_counter_increment(i32* %{{.*}}, i64** %{{.*}}) unnamed_addr [[NRZ:#[0-9]+]]
+
+// Inside llvm_gcov_writeout, check that -coverage-no-function-names-in-data
+// passes null as the function name.
+// CHECK: void @__llvm_gcov_writeout() unnamed_addr [[NRZ]]
+// CHECK: call void @llvm_gcda_emit_function({{.*}}, i8* getelementptr {{.*}}, {{.*}})
+// WITHOUTNAMES: void @__llvm_gcov_writeout() unnamed_addr
+// WITHOUTNAMES: call void @llvm_gcda_emit_function({{.*}}, i8* null, {{.*}})
+
+// CHECK: void @__llvm_gcov_flush() unnamed_addr [[NRZ]]
+// CHECK: void @__llvm_gcov_init() unnamed_addr [[NRZ]]
+
+// CHECK: attributes [[NRZ]] = { {{.*}}noredzone{{.*}} }
diff --git a/test/CodeGen/complex-convert.c b/test/CodeGen/complex-convert.c
new file mode 100644
index 0000000..aaa57a0
--- /dev/null
+++ b/test/CodeGen/complex-convert.c
@@ -0,0 +1,717 @@
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+
+// Test conversions between complex integer types and standard integer
+// types. Tests binary operator conversion and assignment conversion
+// with widening, narrowing, and equal-size operands. Signed and unsigned
+// variations. Attempts to work for all targets. Assumptions:
+//
+// * "char" and "long long" are of different lengths (CHSIZE and LLSIZE).
+// * Arithmetic is not performed directly on "char" type.
+
+void foo(signed char sc, unsigned char uc, signed long long sll,
+ unsigned long long ull, _Complex signed char csc,
+ _Complex unsigned char cuc, _Complex signed long long csll,
+ _Complex unsigned long long cull) {
+
+ signed char sc1;
+ unsigned char uc1;
+ signed long long sll1;
+ unsigned long long ull1;
+ _Complex signed char csc1;
+ _Complex unsigned char cuc1;
+ _Complex signed long long csll1;
+ _Complex unsigned long long cull1;
+ // CHECK: define void @foo(
+ // CHECK: alloca i[[CHSIZE:[0-9]+]], align [[CHALIGN:[0-9]+]]
+ // CHECK-NEXT: alloca i[[CHSIZE]], align [[CHALIGN]]
+ // CHECK-NEXT: alloca i[[LLSIZE:[0-9]+]], align [[LLALIGN:[0-9]+]]
+
+ sc1 = csc;
+ // CHECK: %[[VAR1:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC:[A-Za-z0-9.]+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR2:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR1]]
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR2]], i[[CHSIZE]]* %[[SC1:[A-Za-z0-9.]+]], align [[CHALIGN]]
+
+ sc1 = cuc;
+ // CHECK-NEXT: %[[VAR3:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC:[A-Za-z0-9.]+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR4:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR3]]
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR4]], i[[CHSIZE]]* %[[SC1]], align [[CHALIGN]]
+
+ sc1 = csll;
+ // CHECK-NEXT: %[[VAR5:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL:[A-Za-z0-9.]+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR6:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR5]]
+ // CHECK-NEXT: %[[VAR7:[A-Za-z0-9.]+]] = trunc i[[LLSIZE]] %[[VAR6]] to i[[CHSIZE]]
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR7]], i[[CHSIZE]]* %[[SC1]], align [[CHALIGN]]
+
+ sc1 = cull;
+ // CHECK-NEXT: %[[VAR8:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL:[A-Za-z0-9.]+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR9:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR8]]
+ // CHECK-NEXT: %[[VAR10:[A-Za-z0-9.]+]] = trunc i[[LLSIZE]] %[[VAR9]] to i[[CHSIZE]]
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR10]], i[[CHSIZE]]* %[[SC1]], align [[CHALIGN]]
+
+ uc1 = csc;
+ // CHECK-NEXT: %[[VAR11:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR12:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR11]]
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR12]], i[[CHSIZE]]* %[[UC1:[A-Za-z0-9.]+]], align [[CHALIGN]]
+
+ uc1 = cuc;
+ // CHECK-NEXT: %[[VAR13:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR14:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR13]]
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR14]], i[[CHSIZE]]* %[[UC1]], align [[CHALIGN]]
+
+ uc1 = csll;
+ // CHECK-NEXT: %[[VAR15:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR16:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR15]]
+ // CHECK-NEXT: %[[VAR17:[A-Za-z0-9.]+]] = trunc i[[LLSIZE]] %[[VAR16]] to i[[CHSIZE]]
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR17]], i[[CHSIZE]]* %[[UC1]], align [[CHALIGN]]
+
+ uc1 = cull;
+ // CHECK-NEXT: %[[VAR18:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR19:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR18]]
+ // CHECK-NEXT: %[[VAR20:[A-Za-z0-9.]+]] = trunc i[[LLSIZE]] %[[VAR19]] to i[[CHSIZE]]
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR20]], i[[CHSIZE]]* %[[UC1]], align [[CHALIGN]]
+
+ sll1 = csc;
+ // CHECK-NEXT: %[[VAR21:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR22:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR21]]
+ // CHECK-NEXT: %[[VAR23:[A-Za-z0-9.]+]] = sext i[[CHSIZE]] %[[VAR22]] to i[[LLSIZE]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR23]], i[[LLSIZE]]* %[[SLL1:[A-Za-z0-9]+]], align [[LLALIGN]]
+
+ sll1 = cuc;
+ // CHECK-NEXT: %[[VAR24:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR25:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR24]]
+ // CHECK-NEXT: %[[VAR26:[A-Za-z0-9.]+]] = zext i[[CHSIZE]] %[[VAR25]] to i[[LLSIZE]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR26]], i[[LLSIZE]]* %[[SLL1]], align [[LLALIGN]]
+
+ sll1 = csll;
+ // CHECK-NEXT: %[[VAR27:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR28:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR27]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR28]], i[[LLSIZE]]* %[[SLL1]], align [[LLALIGN]]
+
+ sll1 = cull;
+ // CHECK-NEXT: %[[VAR29:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR30:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR29]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR30]], i[[LLSIZE]]* %[[SLL1]], align [[LLALIGN]]
+
+ ull1 = csc;
+ // CHECK-NEXT: %[[VAR31:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR32:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR31]]
+ // CHECK-NEXT: %[[VAR33:[A-Za-z0-9.]+]] = sext i[[CHSIZE]] %[[VAR32]] to i[[LLSIZE]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR33]], i[[LLSIZE]]* %[[ULL1:[A-Za-z0-9]+]], align [[LLALIGN]]
+
+ ull1 = cuc;
+ // CHECK-NEXT: %[[VAR34:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR35:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR34]]
+ // CHECK-NEXT: %[[VAR36:[A-Za-z0-9.]+]] = zext i[[CHSIZE]] %[[VAR35]] to i[[LLSIZE]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR36]], i[[LLSIZE]]* %[[ULL1]], align [[LLALIGN]]
+
+ ull1 = csll;
+ // CHECK-NEXT: %[[VAR37:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR38:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR37]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR38]], i[[LLSIZE]]* %[[ULL1]], align [[LLALIGN]]
+
+ ull1 = cull;
+ // CHECK-NEXT: %[[VAR39:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR40:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR39]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR40]], i[[LLSIZE]]* %[[ULL1]], align [[LLALIGN]]
+
+ csc1 = sc;
+ // CHECK-NEXT: %[[VAR41:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[SCADDR:[A-Za-z0-9.]+]], align [[CHALIGN]]
+ // CHECK-NEXT: %[[VAR42:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC1:[A-Za-z0-9.]+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR43:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR41]], i[[CHSIZE]]* %[[VAR42]]
+ // CHECK-NEXT: store i[[CHSIZE]] 0, i[[CHSIZE]]* %[[VAR43]]
+
+ csc1 = uc;
+ // CHECK-NEXT: %[[VAR44:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[UCADDR:[A-Za-z0-9.]+]], align [[CHALIGN]]
+ // CHECK-NEXT: %[[VAR45:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR46:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR44]], i[[CHSIZE]]* %[[VAR45]]
+ // CHECK-NEXT: store i[[CHSIZE]] 0, i[[CHSIZE]]* %[[VAR46]]
+
+ csc1 = sll;
+ // CHECK-NEXT: %[[VAR47:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[SLLADDR:[A-Za-z0-9.]+]], align [[LLALIGN]]
+ // CHECK-NEXT: %[[VAR48:[A-Za-z0-9.]+]] = trunc i[[LLSIZE]] %[[VAR47]] to i[[CHSIZE]]
+ // CHECK-NEXT: %[[VAR49:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR50:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR48]], i[[CHSIZE]]* %[[VAR49]]
+ // CHECK-NEXT: store i[[CHSIZE]] 0, i[[CHSIZE]]* %[[VAR50]]
+
+ csc1 = ull;
+ // CHECK-NEXT: %[[VAR51:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[ULLADDR:[A-Za-z0-9.]+]], align [[LLALIGN]]
+ // CHECK-NEXT: %[[VAR52:[A-Za-z0-9.]+]] = trunc i[[LLSIZE]] %[[VAR51]] to i[[CHSIZE]]
+ // CHECK-NEXT: %[[VAR53:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR54:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR52]], i[[CHSIZE]]* %[[VAR53]]
+ // CHECK-NEXT: store i[[CHSIZE]] 0, i[[CHSIZE]]* %[[VAR54]]
+
+ cuc1 = sc;
+ // CHECK-NEXT: %[[VAR55:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[SCADDR]], align [[CHALIGN]]
+ // CHECK-NEXT: %[[VAR56:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC1:[A-Za-z0-9.]+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR57:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR55]], i[[CHSIZE]]* %[[VAR56]]
+ // CHECK-NEXT: store i[[CHSIZE]] 0, i[[CHSIZE]]* %[[VAR57]]
+
+ cuc1 = uc;
+ // CHECK-NEXT: %[[VAR58:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[UCADDR]], align [[CHALIGN]]
+ // CHECK-NEXT: %[[VAR59:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR60:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR58]], i[[CHSIZE]]* %[[VAR59]]
+ // CHECK-NEXT: store i[[CHSIZE]] 0, i[[CHSIZE]]* %[[VAR60]]
+
+ cuc1 = sll;
+ // CHECK-NEXT: %[[VAR61:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[SLLADDR]], align [[LLALIGN]]
+ // CHECK-NEXT: %[[VAR62:[A-Za-z0-9.]+]] = trunc i[[LLSIZE]] %[[VAR61]] to i[[CHSIZE]]
+ // CHECK-NEXT: %[[VAR63:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR64:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR62]], i[[CHSIZE]]* %[[VAR63]]
+ // CHECK-NEXT: store i[[CHSIZE]] 0, i[[CHSIZE]]* %[[VAR64]]
+
+ cuc1 = ull;
+ // CHECK-NEXT: %[[VAR65:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[ULLADDR]], align [[LLALIGN]]
+ // CHECK-NEXT: %[[VAR66:[A-Za-z0-9.]+]] = trunc i[[LLSIZE]] %[[VAR65]] to i[[CHSIZE]]
+ // CHECK-NEXT: %[[VAR67:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR68:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR66]], i[[CHSIZE]]* %[[VAR67]]
+ // CHECK-NEXT: store i[[CHSIZE]] 0, i[[CHSIZE]]* %[[VAR68]]
+
+ csll1 = sc;
+ // CHECK-NEXT: %[[VAR69:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[SCADDR]], align [[CHALIGN]]
+ // CHECK-NEXT: %[[VAR70:[A-Za-z0-9.]+]] = sext i[[CHSIZE]] %[[VAR69]] to i[[LLSIZE]]
+ // CHECK-NEXT: %[[VAR71:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1:[A-Za-z0-9.]+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR72:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR70]], i[[LLSIZE]]* %[[VAR71]]
+ // CHECK-NEXT: store i[[LLSIZE]] 0, i[[LLSIZE]]* %[[VAR72]]
+
+ csll1 = uc;
+ // CHECK-NEXT: %[[VAR73:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[UCADDR]], align [[CHALIGN]]
+ // CHECK-NEXT: %[[VAR74:[A-Za-z0-9.]+]] = zext i[[CHSIZE]] %[[VAR73]] to i[[LLSIZE]]
+ // CHECK-NEXT: %[[VAR75:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR76:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR74]], i[[LLSIZE]]* %[[VAR75]]
+ // CHECK-NEXT: store i[[LLSIZE]] 0, i[[LLSIZE]]* %[[VAR76]]
+
+ csll1 = sll;
+ // CHECK-NEXT: %[[VAR77:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[SLLADDR]], align [[LLALIGN]]
+ // CHECK-NEXT: %[[VAR78:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR79:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR77]], i[[LLSIZE]]* %[[VAR78]]
+ // CHECK-NEXT: store i[[LLSIZE]] 0, i[[LLSIZE]]* %[[VAR79]]
+
+ csll1 = ull;
+ // CHECK-NEXT: %[[VAR77:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[ULLADDR]], align [[LLALIGN]]
+ // CHECK-NEXT: %[[VAR78:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR79:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR77]], i[[LLSIZE]]* %[[VAR78]]
+ // CHECK-NEXT: store i[[LLSIZE]] 0, i[[LLSIZE]]* %[[VAR79]]
+
+ cull1 = sc;
+ // CHECK-NEXT: %[[VAR80:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[SCADDR]], align [[CHALIGN]]
+ // CHECK-NEXT: %[[VAR81:[A-Za-z0-9.]+]] = sext i[[CHSIZE]] %[[VAR80]] to i[[LLSIZE]]
+ // CHECK-NEXT: %[[VAR82:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL1:[A-Za-z0-9.]+]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR83:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR81]], i[[LLSIZE]]* %[[VAR82]]
+ // CHECK-NEXT: store i[[LLSIZE]] 0, i[[LLSIZE]]* %[[VAR83]]
+
+ cull1 = uc;
+ // CHECK-NEXT: %[[VAR84:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[UCADDR]], align [[CHALIGN]]
+ // CHECK-NEXT: %[[VAR85:[A-Za-z0-9.]+]] = zext i[[CHSIZE]] %[[VAR84]] to i[[LLSIZE]]
+ // CHECK-NEXT: %[[VAR86:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR87:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR85]], i[[LLSIZE]]* %[[VAR86]]
+ // CHECK-NEXT: store i[[LLSIZE]] 0, i[[LLSIZE]]* %[[VAR87]]
+
+ cull1 = sll;
+ // CHECK-NEXT: %[[VAR88:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[SLLADDR]], align [[LLALIGN]]
+ // CHECK-NEXT: %[[VAR89:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR90:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR88]], i[[LLSIZE]]* %[[VAR89]]
+ // CHECK-NEXT: store i[[LLSIZE]] 0, i[[LLSIZE]]* %[[VAR90]]
+
+ cull1 = ull;
+ // CHECK-NEXT: %[[VAR91:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[ULLADDR]], align [[LLALIGN]]
+ // CHECK-NEXT: %[[VAR92:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR93:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR91]], i[[LLSIZE]]* %[[VAR92]]
+ // CHECK-NEXT: store i[[LLSIZE]] 0, i[[LLSIZE]]* %[[VAR93]]
+
+ csc1 = sc + csc;
+ // CHECK-NEXT: %[[VAR94:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[SCADDR]], align [[CHALIGN]]
+ // CHECK-NEXT: %[[VAR95:[A-Za-z0-9.]+]] = sext i[[CHSIZE]] %[[VAR94]] to i[[ARSIZE:[0-9]+]]
+ // CHECK-NEXT: %[[VAR96:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR97:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR96]]
+ // CHECK-NEXT: %[[VAR98:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR99:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR98]]
+ // CHECK-NEXT: %[[VAR100:[A-Za-z0-9.]+]] = sext i[[CHSIZE]] %[[VAR97]] to i[[ARSIZE]]
+ // CHECK-NEXT: %[[VAR101:[A-Za-z0-9.]+]] = sext i[[CHSIZE]] %[[VAR99]] to i[[ARSIZE]]
+ // CHECK-NEXT: %[[VAR102:[A-Za-z0-9.]+]] = add i[[ARSIZE]] %[[VAR95]], %[[VAR100]]
+ // CHECK-NEXT: %[[VAR103:[A-Za-z0-9.]+]] = add i[[ARSIZE]] 0, %[[VAR101]]
+ // CHECK-NEXT: %[[VAR104:[A-Za-z0-9.]+]] = trunc i[[ARSIZE]] %[[VAR102]] to i[[CHSIZE]]
+ // CHECK-NEXT: %[[VAR105:[A-Za-z0-9.]+]] = trunc i[[ARSIZE]] %[[VAR103]] to i[[CHSIZE]]
+ // CHECK-NEXT: %[[VAR106:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR107:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR104]], i[[CHSIZE]]* %[[VAR106]]
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR105]], i[[CHSIZE]]* %[[VAR107]]
+
+ cuc1 = sc + cuc;
+ // CHECK-NEXT: %[[VAR108:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[SCADDR]], align [[CHALIGN]]
+ // CHECK-NEXT: %[[VAR109:[A-Za-z0-9.]+]] = sext i[[CHSIZE]] %[[VAR108]] to i[[ARSIZE]]
+ // CHECK-NEXT: %[[VAR110:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR111:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR110]]
+ // CHECK-NEXT: %[[VAR112:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR113:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR112]]
+ // CHECK-NEXT: %[[VAR114:[A-Za-z0-9.]+]] = zext i[[CHSIZE]] %[[VAR111]] to i[[ARSIZE]]
+ // CHECK-NEXT: %[[VAR115:[A-Za-z0-9.]+]] = zext i[[CHSIZE]] %[[VAR113]] to i[[ARSIZE]]
+ // CHECK-NEXT: %[[VAR116:[A-Za-z0-9.]+]] = add i[[ARSIZE]] %[[VAR109]], %[[VAR114]]
+ // CHECK-NEXT: %[[VAR117:[A-Za-z0-9.]+]] = add i[[ARSIZE]] 0, %[[VAR115]]
+ // CHECK-NEXT: %[[VAR118:[A-Za-z0-9.]+]] = trunc i[[ARSIZE]] %[[VAR116]] to i[[CHSIZE]]
+ // CHECK-NEXT: %[[VAR119:[A-Za-z0-9.]+]] = trunc i[[ARSIZE]] %[[VAR117]] to i[[CHSIZE]]
+ // CHECK-NEXT: %[[VAR120:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR121:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR118]], i[[CHSIZE]]* %[[VAR120]]
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR119]], i[[CHSIZE]]* %[[VAR121]]
+
+ csll1 = sc + csll;
+ // CHECK-NEXT: %[[VAR122:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[SCADDR]], align [[CHALIGN]]
+ // CHECK-NEXT: %[[VAR123:[A-Za-z0-9.]+]] = sext i[[CHSIZE]] %[[VAR122]] to i[[LLSIZE]]
+ // CHECK-NEXT: %[[VAR124:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR125:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR124]]
+ // CHECK-NEXT: %[[VAR126:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR127:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR126]]
+ // CHECK-NEXT: %[[VAR128:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR123]], %[[VAR125]]
+ // CHECK-NEXT: %[[VAR129:[A-Za-z0-9.]+]] = add i[[LLSIZE]] 0, %[[VAR127]]
+ // CHECK-NEXT: %[[VAR130:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR131:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR128]], i[[LLSIZE]]* %[[VAR130]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR129]], i[[LLSIZE]]* %[[VAR131]]
+
+ cull1 = sc + cull;
+ // CHECK-NEXT: %[[VAR132:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[SCADDR]], align [[CHALIGN]]
+ // CHECK-NEXT: %[[VAR133:[A-Za-z0-9.]+]] = sext i[[CHSIZE]] %[[VAR132]] to i[[LLSIZE]]
+ // CHECK-NEXT: %[[VAR134:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR135:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR134]]
+ // CHECK-NEXT: %[[VAR136:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR137:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR136]]
+ // CHECK-NEXT: %[[VAR138:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR133]], %[[VAR135]]
+ // CHECK-NEXT: %[[VAR139:[A-Za-z0-9.]+]] = add i[[LLSIZE]] 0, %[[VAR137]]
+ // CHECK-NEXT: %[[VAR140:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR141:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR138]], i[[LLSIZE]]* %[[VAR140]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR139]], i[[LLSIZE]]* %[[VAR141]]
+
+ csc1 = uc + csc;
+ // CHECK-NEXT: %[[VAR142:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[UCADDR]], align [[CHALIGN]]
+ // CHECK-NEXT: %[[VAR143:[A-Za-z0-9.]+]] = zext i[[CHSIZE]] %[[VAR142]] to i[[ARSIZE]]
+ // CHECK-NEXT: %[[VAR144:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR145:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR144]]
+ // CHECK-NEXT: %[[VAR146:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR147:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR146]]
+ // CHECK-NEXT: %[[VAR148:[A-Za-z0-9.]+]] = sext i[[CHSIZE]] %[[VAR145]] to i[[ARSIZE]]
+ // CHECK-NEXT: %[[VAR149:[A-Za-z0-9.]+]] = sext i[[CHSIZE]] %[[VAR147]] to i[[ARSIZE]]
+ // CHECK-NEXT: %[[VAR150:[A-Za-z0-9.]+]] = add i[[ARSIZE]] %[[VAR143]], %[[VAR148]]
+ // CHECK-NEXT: %[[VAR151:[A-Za-z0-9.]+]] = add i[[ARSIZE]] 0, %[[VAR149]]
+ // CHECK-NEXT: %[[VAR152:[A-Za-z0-9.]+]] = trunc i[[ARSIZE]] %[[VAR150]] to i[[CHSIZE]]
+ // CHECK-NEXT: %[[VAR153:[A-Za-z0-9.]+]] = trunc i[[ARSIZE]] %[[VAR151]] to i[[CHSIZE]]
+ // CHECK-NEXT: %[[VAR154:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR155:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR152]], i[[CHSIZE]]* %[[VAR154]]
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR153]], i[[CHSIZE]]* %[[VAR155]]
+
+ cuc1 = uc + cuc;
+ // CHECK-NEXT: %[[VAR156:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[UCADDR]], align [[CHALIGN]]
+ // CHECK-NEXT: %[[VAR157:[A-Za-z0-9.]+]] = zext i[[CHSIZE]] %[[VAR156]] to i[[ARSIZE]]
+ // CHECK-NEXT: %[[VAR158:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR159:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR158]]
+ // CHECK-NEXT: %[[VAR160:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR161:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR160]]
+ // CHECK-NEXT: %[[VAR162:[A-Za-z0-9.]+]] = zext i[[CHSIZE]] %[[VAR159]] to i[[ARSIZE]]
+ // CHECK-NEXT: %[[VAR163:[A-Za-z0-9.]+]] = zext i[[CHSIZE]] %[[VAR161]] to i[[ARSIZE]]
+ // CHECK-NEXT: %[[VAR164:[A-Za-z0-9.]+]] = add i[[ARSIZE]] %[[VAR157]], %[[VAR162]]
+ // CHECK-NEXT: %[[VAR165:[A-Za-z0-9.]+]] = add i[[ARSIZE]] 0, %[[VAR163]]
+ // CHECK-NEXT: %[[VAR166:[A-Za-z0-9.]+]] = trunc i[[ARSIZE]] %[[VAR164]] to i[[CHSIZE]]
+ // CHECK-NEXT: %[[VAR167:[A-Za-z0-9.]+]] = trunc i[[ARSIZE]] %[[VAR165]] to i[[CHSIZE]]
+ // CHECK-NEXT: %[[VAR168:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR169:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR166]], i[[CHSIZE]]* %[[VAR168]]
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR167]], i[[CHSIZE]]* %[[VAR169]]
+
+ csll1 = uc + csll;
+ // CHECK-NEXT: %[[VAR170:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[UCADDR]], align [[CHALIGN]]
+ // CHECK-NEXT: %[[VAR171:[A-Za-z0-9.]+]] = zext i[[CHSIZE]] %[[VAR170]] to i[[LLSIZE]]
+ // CHECK-NEXT: %[[VAR172:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR173:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR172]]
+ // CHECK-NEXT: %[[VAR174:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR175:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR174]]
+ // CHECK-NEXT: %[[VAR176:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR171]], %[[VAR173]]
+ // CHECK-NEXT: %[[VAR177:[A-Za-z0-9.]+]] = add i[[LLSIZE]] 0, %[[VAR175]]
+ // CHECK-NEXT: %[[VAR178:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR179:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR176]], i[[LLSIZE]]* %[[VAR178]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR177]], i[[LLSIZE]]* %[[VAR179]]
+
+ cull1 = uc + cull;
+ // CHECK-NEXT: %[[VAR180:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[UCADDR]], align [[CHALIGN]]
+ // CHECK-NEXT: %[[VAR181:[A-Za-z0-9.]+]] = zext i[[CHSIZE]] %[[VAR180]] to i[[LLSIZE]]
+ // CHECK-NEXT: %[[VAR182:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR183:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR182]]
+ // CHECK-NEXT: %[[VAR184:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR185:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR184]]
+ // CHECK-NEXT: %[[VAR186:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR181]], %[[VAR183]]
+ // CHECK-NEXT: %[[VAR187:[A-Za-z0-9.]+]] = add i[[LLSIZE]] 0, %[[VAR185]]
+ // CHECK-NEXT: %[[VAR188:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR189:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR186]], i[[LLSIZE]]* %[[VAR188]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR187]], i[[LLSIZE]]* %[[VAR189]]
+
+ csll1 = sll + csc;
+ // CHECK-NEXT: %[[VAR190:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[SLLADDR]], align [[LLALIGN]]
+ // CHECK-NEXT: %[[VAR191:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR192:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR191]]
+ // CHECK-NEXT: %[[VAR193:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR194:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR193]]
+ // CHECK-NEXT: %[[VAR195:[A-Za-z0-9.]+]] = sext i[[CHSIZE]] %[[VAR192]] to i[[LLSIZE]]
+ // CHECK-NEXT: %[[VAR196:[A-Za-z0-9.]+]] = sext i[[CHSIZE]] %[[VAR194]] to i[[LLSIZE]]
+ // CHECK-NEXT: %[[VAR197:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR190]], %[[VAR195]]
+ // CHECK-NEXT: %[[VAR198:[A-Za-z0-9.]+]] = add i[[LLSIZE]] 0, %[[VAR196]]
+ // CHECK-NEXT: %[[VAR199:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR200:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR197]], i[[LLSIZE]]* %[[VAR199]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR198]], i[[LLSIZE]]* %[[VAR200]]
+
+ csll1 = sll + cuc;
+ // CHECK-NEXT: %[[VAR201:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[SLLADDR]], align [[LLALIGN]]
+ // CHECK-NEXT: %[[VAR202:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR203:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR202]]
+ // CHECK-NEXT: %[[VAR204:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR205:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR204]]
+ // CHECK-NEXT: %[[VAR206:[A-Za-z0-9.]+]] = zext i[[CHSIZE]] %[[VAR203]] to i[[LLSIZE]]
+ // CHECK-NEXT: %[[VAR207:[A-Za-z0-9.]+]] = zext i[[CHSIZE]] %[[VAR205]] to i[[LLSIZE]]
+ // CHECK-NEXT: %[[VAR208:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR201]], %[[VAR206]]
+ // CHECK-NEXT: %[[VAR209:[A-Za-z0-9.]+]] = add i[[LLSIZE]] 0, %[[VAR207]]
+ // CHECK-NEXT: %[[VAR210:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR211:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR208]], i[[LLSIZE]]* %[[VAR210]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR209]], i[[LLSIZE]]* %[[VAR211]]
+
+ csll1 = sll + csll;
+ // CHECK-NEXT: %[[VAR212:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[SLLADDR]], align [[LLALIGN]]
+ // CHECK-NEXT: %[[VAR213:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR214:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR213]]
+ // CHECK-NEXT: %[[VAR215:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR216:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR215]]
+ // CHECK-NEXT: %[[VAR217:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR212]], %[[VAR214]]
+ // CHECK-NEXT: %[[VAR218:[A-Za-z0-9.]+]] = add i[[LLSIZE]] 0, %[[VAR216]]
+ // CHECK-NEXT: %[[VAR219:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR220:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR217]], i[[LLSIZE]]* %[[VAR219]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR218]], i[[LLSIZE]]* %[[VAR220]]
+
+ csll1 = sll + cull;
+ // CHECK-NEXT: %[[VAR221:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[SLLADDR]], align [[LLALIGN]]
+ // CHECK-NEXT: %[[VAR222:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR223:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR222]]
+ // CHECK-NEXT: %[[VAR224:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR225:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR224]]
+ // CHECK-NEXT: %[[VAR226:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR221]], %[[VAR223]]
+ // CHECK-NEXT: %[[VAR227:[A-Za-z0-9.]+]] = add i[[LLSIZE]] 0, %[[VAR225]]
+ // CHECK-NEXT: %[[VAR228:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR229:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR226]], i[[LLSIZE]]* %[[VAR228]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR227]], i[[LLSIZE]]* %[[VAR229]]
+
+ csll1 = ull + csc;
+ // CHECK-NEXT: %[[VAR230:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[ULLADDR]], align [[LLALIGN]]
+ // CHECK-NEXT: %[[VAR231:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR232:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR231]]
+ // CHECK-NEXT: %[[VAR233:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR234:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR233]]
+ // CHECK-NEXT: %[[VAR235:[A-Za-z0-9.]+]] = sext i[[CHSIZE]] %[[VAR232]] to i[[LLSIZE]]
+ // CHECK-NEXT: %[[VAR236:[A-Za-z0-9.]+]] = sext i[[CHSIZE]] %[[VAR234]] to i[[LLSIZE]]
+ // CHECK-NEXT: %[[VAR237:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR230]], %[[VAR235]]
+ // CHECK-NEXT: %[[VAR238:[A-Za-z0-9.]+]] = add i[[LLSIZE]] 0, %[[VAR236]]
+ // CHECK-NEXT: %[[VAR239:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR240:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR237]], i[[LLSIZE]]* %[[VAR239]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR238]], i[[LLSIZE]]* %[[VAR240]]
+
+ cull1 = ull + cuc;
+ // CHECK-NEXT: %[[VAR241:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[ULLADDR]], align [[LLALIGN]]
+ // CHECK-NEXT: %[[VAR242:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR243:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR242]]
+ // CHECK-NEXT: %[[VAR244:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR245:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR244]]
+ // CHECK-NEXT: %[[VAR246:[A-Za-z0-9.]+]] = zext i[[CHSIZE]] %[[VAR243]] to i[[LLSIZE]]
+ // CHECK-NEXT: %[[VAR247:[A-Za-z0-9.]+]] = zext i[[CHSIZE]] %[[VAR245]] to i[[LLSIZE]]
+ // CHECK-NEXT: %[[VAR248:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR241]], %[[VAR246]]
+ // CHECK-NEXT: %[[VAR249:[A-Za-z0-9.]+]] = add i[[LLSIZE]] 0, %[[VAR247]]
+ // CHECK-NEXT: %[[VAR250:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR251:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR248]], i[[LLSIZE]]* %[[VAR250]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR249]], i[[LLSIZE]]* %[[VAR251]]
+
+ csll1 = ull + csll;
+ // CHECK-NEXT: %[[VAR252:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[ULLADDR]], align [[LLALIGN]]
+ // CHECK-NEXT: %[[VAR253:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR254:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR253]]
+ // CHECK-NEXT: %[[VAR255:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR256:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR255]]
+ // CHECK-NEXT: %[[VAR257:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR252]], %[[VAR254]]
+ // CHECK-NEXT: %[[VAR258:[A-Za-z0-9.]+]] = add i[[LLSIZE]] 0, %[[VAR256]]
+ // CHECK-NEXT: %[[VAR259:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR260:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR257]], i[[LLSIZE]]* %[[VAR259]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR258]], i[[LLSIZE]]* %[[VAR260]]
+
+ cull1 = ull + cull;
+ // CHECK-NEXT: %[[VAR261:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[ULLADDR]], align [[LLALIGN]]
+ // CHECK-NEXT: %[[VAR262:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR263:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR262]]
+ // CHECK-NEXT: %[[VAR264:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR265:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR264]]
+ // CHECK-NEXT: %[[VAR266:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR261]], %[[VAR263]]
+ // CHECK-NEXT: %[[VAR267:[A-Za-z0-9.]+]] = add i[[LLSIZE]] 0, %[[VAR265]]
+ // CHECK-NEXT: %[[VAR268:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR269:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR266]], i[[LLSIZE]]* %[[VAR268]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR267]], i[[LLSIZE]]* %[[VAR269]]
+
+ csc1 = csc + sc;
+ // CHECK-NEXT: %[[VAR270:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR271:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR270]]
+ // CHECK-NEXT: %[[VAR272:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR273:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR272]]
+ // CHECK-NEXT: %[[VAR274:[A-Za-z0-9.]+]] = sext i[[CHSIZE]] %[[VAR271]] to i[[ARSIZE]]
+ // CHECK-NEXT: %[[VAR275:[A-Za-z0-9.]+]] = sext i[[CHSIZE]] %[[VAR273]] to i[[ARSIZE]]
+ // CHECK-NEXT: %[[VAR276:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[SCADDR]], align [[CHALIGN]]
+ // CHECK-NEXT: %[[VAR277:[A-Za-z0-9.]+]] = sext i[[CHSIZE]] %[[VAR276]] to i[[ARSIZE]]
+ // CHECK-NEXT: %[[VAR278:[A-Za-z0-9.]+]] = add i[[ARSIZE]] %[[VAR274]], %[[VAR277]]
+ // CHECK-NEXT: %[[VAR279:[A-Za-z0-9.]+]] = add i[[ARSIZE]] %[[VAR275]], 0
+ // CHECK-NEXT: %[[VAR280:[A-Za-z0-9.]+]] = trunc i[[ARSIZE]] %[[VAR278]] to i[[CHSIZE]]
+ // CHECK-NEXT: %[[VAR281:[A-Za-z0-9.]+]] = trunc i[[ARSIZE]] %[[VAR279]] to i[[CHSIZE]]
+ // CHECK-NEXT: %[[VAR282:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR283:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR280]], i[[CHSIZE]]* %[[VAR282]]
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR281]], i[[CHSIZE]]* %[[VAR283]]
+
+ csc1 = csc + uc;
+ // CHECK-NEXT: %[[VAR284:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR285:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR284]]
+ // CHECK-NEXT: %[[VAR286:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR287:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR286]]
+ // CHECK-NEXT: %[[VAR288:[A-Za-z0-9.]+]] = sext i[[CHSIZE]] %[[VAR285]] to i[[ARSIZE]]
+ // CHECK-NEXT: %[[VAR289:[A-Za-z0-9.]+]] = sext i[[CHSIZE]] %[[VAR287]] to i[[ARSIZE]]
+ // CHECK-NEXT: %[[VAR290:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[UCADDR]], align [[CHALIGN]]
+ // CHECK-NEXT: %[[VAR291:[A-Za-z0-9.]+]] = zext i[[CHSIZE]] %[[VAR290]] to i[[ARSIZE]]
+ // CHECK-NEXT: %[[VAR292:[A-Za-z0-9.]+]] = add i[[ARSIZE]] %[[VAR288]], %[[VAR291]]
+ // CHECK-NEXT: %[[VAR293:[A-Za-z0-9.]+]] = add i[[ARSIZE]] %[[VAR289]], 0
+ // CHECK-NEXT: %[[VAR294:[A-Za-z0-9.]+]] = trunc i[[ARSIZE]] %[[VAR292]] to i[[CHSIZE]]
+ // CHECK-NEXT: %[[VAR295:[A-Za-z0-9.]+]] = trunc i[[ARSIZE]] %[[VAR293]] to i[[CHSIZE]]
+ // CHECK-NEXT: %[[VAR296:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR297:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR294]], i[[CHSIZE]]* %[[VAR296]]
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR295]], i[[CHSIZE]]* %[[VAR297]]
+
+ csll1 = csc + sll;
+ // CHECK-NEXT: %[[VAR298:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR299:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR298]]
+ // CHECK-NEXT: %[[VAR300:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR301:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR300]]
+ // CHECK-NEXT: %[[VAR302:[A-Za-z0-9.]+]] = sext i[[CHSIZE]] %[[VAR299]] to i[[LLSIZE]]
+ // CHECK-NEXT: %[[VAR303:[A-Za-z0-9.]+]] = sext i[[CHSIZE]] %[[VAR301]] to i[[LLSIZE]]
+ // CHECK-NEXT: %[[VAR304:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[SLLADDR]], align [[LLALIGN]]
+ // CHECK-NEXT: %[[VAR305:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR302]], %[[VAR304]]
+ // CHECK-NEXT: %[[VAR306:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR303]], 0
+ // CHECK-NEXT: %[[VAR307:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR308:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR305]], i[[LLSIZE]]* %[[VAR307]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR306]], i[[LLSIZE]]* %[[VAR308]]
+
+ csll1 = csc + ull;
+ // CHECK-NEXT: %[[VAR309:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR310:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR309]]
+ // CHECK-NEXT: %[[VAR311:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR312:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR311]]
+ // CHECK-NEXT: %[[VAR313:[A-Za-z0-9.]+]] = sext i[[CHSIZE]] %[[VAR310]] to i[[LLSIZE]]
+ // CHECK-NEXT: %[[VAR314:[A-Za-z0-9.]+]] = sext i[[CHSIZE]] %[[VAR312]] to i[[LLSIZE]]
+ // CHECK-NEXT: %[[VAR315:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[ULLADDR]], align [[LLALIGN]]
+ // CHECK-NEXT: %[[VAR316:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR313]], %[[VAR315]]
+ // CHECK-NEXT: %[[VAR317:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR314]], 0
+ // CHECK-NEXT: %[[VAR318:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR319:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR316]], i[[LLSIZE]]* %[[VAR318]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR317]], i[[LLSIZE]]* %[[VAR319]]
+
+ csc1 = cuc + sc;
+ // CHECK-NEXT: %[[VAR320:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR321:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR320]]
+ // CHECK-NEXT: %[[VAR322:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR323:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR322]]
+ // CHECK-NEXT: %[[VAR324:[A-Za-z0-9.]+]] = zext i[[CHSIZE]] %[[VAR321]] to i[[ARSIZE]]
+ // CHECK-NEXT: %[[VAR325:[A-Za-z0-9.]+]] = zext i[[CHSIZE]] %[[VAR323]] to i[[ARSIZE]]
+ // CHECK-NEXT: %[[VAR326:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[SCADDR]], align [[CHALIGN]]
+ // CHECK-NEXT: %[[VAR327:[A-Za-z0-9.]+]] = sext i[[CHSIZE]] %[[VAR326]] to i[[ARSIZE]]
+ // CHECK-NEXT: %[[VAR328:[A-Za-z0-9.]+]] = add i[[ARSIZE]] %[[VAR324]], %[[VAR327]]
+ // CHECK-NEXT: %[[VAR329:[A-Za-z0-9.]+]] = add i[[ARSIZE]] %[[VAR325]], 0
+ // CHECK-NEXT: %[[VAR330:[A-Za-z0-9.]+]] = trunc i[[ARSIZE]] %[[VAR328]] to i[[CHSIZE]]
+ // CHECK-NEXT: %[[VAR331:[A-Za-z0-9.]+]] = trunc i[[ARSIZE]] %[[VAR329]] to i[[CHSIZE]]
+ // CHECK-NEXT: %[[VAR332:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR333:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CSC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR330]], i[[CHSIZE]]* %[[VAR332]]
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR331]], i[[CHSIZE]]* %[[VAR333]]
+
+ cuc1 = cuc + uc;
+ // CHECK-NEXT: %[[VAR334:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR335:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR334]]
+ // CHECK-NEXT: %[[VAR336:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR337:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR336]]
+ // CHECK-NEXT: %[[VAR338:[A-Za-z0-9.]+]] = zext i[[CHSIZE]] %[[VAR335]] to i[[ARSIZE]]
+ // CHECK-NEXT: %[[VAR339:[A-Za-z0-9.]+]] = zext i[[CHSIZE]] %[[VAR337]] to i[[ARSIZE]]
+ // CHECK-NEXT: %[[VAR340:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[UCADDR]], align [[CHALIGN]]
+ // CHECK-NEXT: %[[VAR341:[A-Za-z0-9.]+]] = zext i[[CHSIZE]] %[[VAR340]] to i[[ARSIZE]]
+ // CHECK-NEXT: %[[VAR342:[A-Za-z0-9.]+]] = add i[[ARSIZE]] %[[VAR338]], %[[VAR341]]
+ // CHECK-NEXT: %[[VAR343:[A-Za-z0-9.]+]] = add i[[ARSIZE]] %[[VAR339]], 0
+ // CHECK-NEXT: %[[VAR344:[A-Za-z0-9.]+]] = trunc i[[ARSIZE]] %[[VAR342]] to i[[CHSIZE]]
+ // CHECK-NEXT: %[[VAR345:[A-Za-z0-9.]+]] = trunc i[[ARSIZE]] %[[VAR343]] to i[[CHSIZE]]
+ // CHECK-NEXT: %[[VAR346:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR347:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR344]], i[[CHSIZE]]* %[[VAR346]]
+ // CHECK-NEXT: store i[[CHSIZE]] %[[VAR345]], i[[CHSIZE]]* %[[VAR347]]
+
+ csll1 = cuc + sll;
+ // CHECK-NEXT: %[[VAR348:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR349:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR348]]
+ // CHECK-NEXT: %[[VAR350:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR351:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR350]]
+ // CHECK-NEXT: %[[VAR352:[A-Za-z0-9.]+]] = zext i[[CHSIZE]] %[[VAR349]] to i[[LLSIZE]]
+ // CHECK-NEXT: %[[VAR353:[A-Za-z0-9.]+]] = zext i[[CHSIZE]] %[[VAR351]] to i[[LLSIZE]]
+ // CHECK-NEXT: %[[VAR354:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[SLLADDR]], align [[LLALIGN]]
+ // CHECK-NEXT: %[[VAR355:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR352]], %[[VAR354]]
+ // CHECK-NEXT: %[[VAR356:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR353]], 0
+ // CHECK-NEXT: %[[VAR357:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR358:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR355]], i[[LLSIZE]]* %[[VAR357]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR356]], i[[LLSIZE]]* %[[VAR358]]
+
+ cull1 = cuc + ull;
+ // CHECK-NEXT: %[[VAR357:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR358:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR357]]
+ // CHECK-NEXT: %[[VAR359:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[CHSIZE]], i[[CHSIZE]] }* %[[CUC]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR360:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[VAR359]]
+ // CHECK-NEXT: %[[VAR361:[A-Za-z0-9.]+]] = zext i[[CHSIZE]] %[[VAR358]] to i[[LLSIZE]]
+ // CHECK-NEXT: %[[VAR362:[A-Za-z0-9.]+]] = zext i[[CHSIZE]] %[[VAR360]] to i[[LLSIZE]]
+ // CHECK-NEXT: %[[VAR363:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[ULLADDR]], align [[LLALIGN]]
+ // CHECK-NEXT: %[[VAR364:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR361]], %[[VAR363]]
+ // CHECK-NEXT: %[[VAR365:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR362]], 0
+ // CHECK-NEXT: %[[VAR366:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR367:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR364]], i[[LLSIZE]]* %[[VAR366]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR365]], i[[LLSIZE]]* %[[VAR367]]
+
+ csll1 = csll + sc;
+ // CHECK-NEXT: %[[VAR368:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR369:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR368]]
+ // CHECK-NEXT: %[[VAR370:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR371:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR370]]
+ // CHECK-NEXT: %[[VAR372:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[SCADDR]], align [[CHALIGN]]
+ // CHECK-NEXT: %[[VAR373:[A-Za-z0-9.]+]] = sext i[[CHSIZE]] %[[VAR372]] to i[[LLSIZE]]
+ // CHECK-NEXT: %[[VAR374:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR369]], %[[VAR373]]
+ // CHECK-NEXT: %[[VAR375:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR371]], 0
+ // CHECK-NEXT: %[[VAR376:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR377:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR374]], i[[LLSIZE]]* %[[VAR376]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR375]], i[[LLSIZE]]* %[[VAR377]]
+
+ csll1 = csll + uc;
+ // CHECK-NEXT: %[[VAR378:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR379:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR378]]
+ // CHECK-NEXT: %[[VAR380:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR381:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR380]]
+ // CHECK-NEXT: %[[VAR382:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[UCADDR]], align [[CHALIGN]]
+ // CHECK-NEXT: %[[VAR383:[A-Za-z0-9.]+]] = zext i[[CHSIZE]] %[[VAR382]] to i[[LLSIZE]]
+ // CHECK-NEXT: %[[VAR384:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR379]], %[[VAR383]]
+ // CHECK-NEXT: %[[VAR385:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR381]], 0
+ // CHECK-NEXT: %[[VAR386:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR387:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR384]], i[[LLSIZE]]* %[[VAR386]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR385]], i[[LLSIZE]]* %[[VAR387]]
+
+ csll1 = csll + sll;
+ // CHECK-NEXT: %[[VAR388:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR389:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR388]]
+ // CHECK-NEXT: %[[VAR390:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR391:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR390]]
+ // CHECK-NEXT: %[[VAR392:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[SLLADDR]], align [[LLALIGN]]
+ // CHECK-NEXT: %[[VAR393:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR389]], %[[VAR392]]
+ // CHECK-NEXT: %[[VAR394:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR391]], 0
+ // CHECK-NEXT: %[[VAR395:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR396:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR393]], i[[LLSIZE]]* %[[VAR395]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR394]], i[[LLSIZE]]* %[[VAR396]]
+
+ csll1 = csll + ull;
+ // CHECK-NEXT: %[[VAR397:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR398:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR397]]
+ // CHECK-NEXT: %[[VAR399:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR400:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR399]]
+ // CHECK-NEXT: %[[VAR401:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[ULLADDR]], align [[LLALIGN]]
+ // CHECK-NEXT: %[[VAR402:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR398]], %[[VAR401]]
+ // CHECK-NEXT: %[[VAR403:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR400]], 0
+ // CHECK-NEXT: %[[VAR404:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR405:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR402]], i[[LLSIZE]]* %[[VAR404]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR403]], i[[LLSIZE]]* %[[VAR405]]
+
+ csll1 = cull + sc;
+ // CHECK-NEXT: %[[VAR406:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR407:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR406]]
+ // CHECK-NEXT: %[[VAR408:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR409:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR408]]
+ // CHECK-NEXT: %[[VAR410:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[SCADDR]], align [[CHALIGN]]
+ // CHECK-NEXT: %[[VAR411:[A-Za-z0-9.]+]] = sext i[[CHSIZE]] %[[VAR410]] to i[[LLSIZE]]
+ // CHECK-NEXT: %[[VAR412:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR407]], %[[VAR411]]
+ // CHECK-NEXT: %[[VAR413:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR409]], 0
+ // CHECK-NEXT: %[[VAR414:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR415:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR412]], i[[LLSIZE]]* %[[VAR414]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR413]], i[[LLSIZE]]* %[[VAR415]]
+
+ cull1 = cull + uc;
+ // CHECK-NEXT: %[[VAR416:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR417:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR416]]
+ // CHECK-NEXT: %[[VAR418:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR419:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR418]]
+ // CHECK-NEXT: %[[VAR420:[A-Za-z0-9.]+]] = load i[[CHSIZE]]* %[[UCADDR]], align [[CHALIGN]]
+ // CHECK-NEXT: %[[VAR421:[A-Za-z0-9.]+]] = zext i[[CHSIZE]] %[[VAR420]] to i[[LLSIZE]]
+ // CHECK-NEXT: %[[VAR422:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR417]], %[[VAR421]]
+ // CHECK-NEXT: %[[VAR423:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR419]], 0
+ // CHECK-NEXT: %[[VAR424:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR425:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR422]], i[[LLSIZE]]* %[[VAR424]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR423]], i[[LLSIZE]]* %[[VAR425]]
+
+ csll1 = cull + sll;
+ // CHECK-NEXT: %[[VAR426:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR427:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR426]]
+ // CHECK-NEXT: %[[VAR428:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR429:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR428]]
+ // CHECK-NEXT: %[[VAR430:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[SLLADDR]], align [[LLALIGN]]
+ // CHECK-NEXT: %[[VAR431:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR427]], %[[VAR430]]
+ // CHECK-NEXT: %[[VAR432:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR429]], 0
+ // CHECK-NEXT: %[[VAR433:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR434:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CSLL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR431]], i[[LLSIZE]]* %[[VAR433]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR432]], i[[LLSIZE]]* %[[VAR434]]
+
+ cull1 = cull + ull;
+ // CHECK-NEXT: %[[VAR435:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR436:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR435]]
+ // CHECK-NEXT: %[[VAR437:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: %[[VAR438:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[VAR437]]
+ // CHECK-NEXT: %[[VAR439:[A-Za-z0-9.]+]] = load i[[LLSIZE]]* %[[ULLADDR]], align [[LLALIGN]]
+ // CHECK-NEXT: %[[VAR440:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR436]], %[[VAR439]]
+ // CHECK-NEXT: %[[VAR441:[A-Za-z0-9.]+]] = add i[[LLSIZE]] %[[VAR438]], 0
+ // CHECK-NEXT: %[[VAR442:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 0
+ // CHECK-NEXT: %[[VAR443:[A-Za-z0-9.]+]] = getelementptr inbounds { i[[LLSIZE]], i[[LLSIZE]] }* %[[CULL1]], i{{[0-9]+}} 0, i{{[0-9]+}} 1
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR440]], i[[LLSIZE]]* %[[VAR442]]
+ // CHECK-NEXT: store i[[LLSIZE]] %[[VAR441]], i[[LLSIZE]]* %[[VAR443]]
+}
+
diff --git a/test/CodeGen/compound-assign-overflow.c b/test/CodeGen/compound-assign-overflow.c
new file mode 100644
index 0000000..e82061b
--- /dev/null
+++ b/test/CodeGen/compound-assign-overflow.c
@@ -0,0 +1,36 @@
+// Verify proper type emitted for compound assignments
+// RUN: %clang_cc1 -ffreestanding -triple x86_64-apple-darwin10 -emit-llvm -o - %s -fsanitize=signed-integer-overflow,unsigned-integer-overflow | FileCheck %s
+
+#include <stdint.h>
+
+// CHECK: @[[INT:.*]] = private unnamed_addr constant { i16, i16, [6 x i8] } { i16 0, i16 11, [6 x i8] c"'int'\00" }
+// CHECK: @[[LINE_100:.*]] = private unnamed_addr global {{.*}}, i32 100, i32 5 {{.*}} @[[INT]]
+// CHECK: @[[UINT:.*]] = private unnamed_addr constant { i16, i16, [15 x i8] } { i16 0, i16 10, [15 x i8] c"'unsigned int'\00" }
+// CHECK: @[[LINE_200:.*]] = private unnamed_addr global {{.*}}, i32 200, i32 5 {{.*}} @[[UINT]]
+// CHECK: @[[DIVINT:.*]] = private unnamed_addr constant { i16, i16, [6 x i8] } { i16 0, i16 11, [6 x i8] c"'int'\00" }
+// CHECK: @[[LINE_300:.*]] = private unnamed_addr global {{.*}}, i32 300, i32 5 {{.*}} @[[DIVINT]]
+
+int32_t x;
+
+// CHECK: @compaddsigned
+void compaddsigned() {
+#line 100
+ x += ((int32_t)1);
+ // CHECK: @__ubsan_handle_add_overflow(i8* bitcast ({{.*}} @[[LINE_100]] to i8*), {{.*}})
+}
+
+// CHECK: @compaddunsigned
+void compaddunsigned() {
+#line 200
+ x += ((uint32_t)1U);
+ // CHECK: @__ubsan_handle_add_overflow(i8* bitcast ({{.*}} @[[LINE_200]] to i8*), {{.*}})
+}
+
+int8_t a, b;
+
+// CHECK: @compdiv
+void compdiv() {
+#line 300
+ a /= b;
+ // CHECK: @__ubsan_handle_divrem_overflow(i8* bitcast ({{.*}} @[[LINE_300]] to i8*), {{.*}})
+}
diff --git a/test/CodeGen/compound-literal.c b/test/CodeGen/compound-literal.c
index a8eec61..e4bf962 100644
--- a/test/CodeGen/compound-literal.c
+++ b/test/CodeGen/compound-literal.c
@@ -32,3 +32,37 @@ void f() {
s = (S){s.y,s.x};
// CHECK-NEXT: ret void
}
+
+// CHECK: define i48 @g(
+struct G { short x, y, z; };
+struct G g(int x, int y, int z) {
+ // CHECK: [[RESULT:%.*]] = alloca [[G:%.*]], align 2
+ // CHECK-NEXT: [[X:%.*]] = alloca i32, align 4
+ // CHECK-NEXT: [[Y:%.*]] = alloca i32, align 4
+ // CHECK-NEXT: [[Z:%.*]] = alloca i32, align 4
+ // CHECK-NEXT: [[COERCE_TEMP:%.*]] = alloca i48
+ // CHECK-NEXT: store i32
+ // CHECK-NEXT: store i32
+ // CHECK-NEXT: store i32
+
+ // Evaluate the compound literal directly in the result value slot.
+ // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[G]]* [[RESULT]], i32 0, i32 0
+ // CHECK-NEXT: [[T1:%.*]] = load i32* [[X]], align 4
+ // CHECK-NEXT: [[T2:%.*]] = trunc i32 [[T1]] to i16
+ // CHECK-NEXT: store i16 [[T2]], i16* [[T0]], align 2
+ // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[G]]* [[RESULT]], i32 0, i32 1
+ // CHECK-NEXT: [[T1:%.*]] = load i32* [[Y]], align 4
+ // CHECK-NEXT: [[T2:%.*]] = trunc i32 [[T1]] to i16
+ // CHECK-NEXT: store i16 [[T2]], i16* [[T0]], align 2
+ // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[G]]* [[RESULT]], i32 0, i32 2
+ // CHECK-NEXT: [[T1:%.*]] = load i32* [[Z]], align 4
+ // CHECK-NEXT: [[T2:%.*]] = trunc i32 [[T1]] to i16
+ // CHECK-NEXT: store i16 [[T2]], i16* [[T0]], align 2
+ return (struct G) { x, y, z };
+
+ // CHECK-NEXT: [[T0:%.*]] = bitcast i48* [[COERCE_TEMP]] to i8*
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[G]]* [[RESULT]] to i8*
+ // CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[T0]], i8* [[T1]], i64 6
+ // CHECK-NEXT: [[T0:%.*]] = load i48* [[COERCE_TEMP]]
+ // CHECK-NEXT: ret i48 [[T0]]
+}
diff --git a/test/CodeGen/debug-info-args.c b/test/CodeGen/debug-info-args.c
index 1d4ea10..3312952 100644
--- a/test/CodeGen/debug-info-args.c
+++ b/test/CodeGen/debug-info-args.c
@@ -2,8 +2,8 @@
int somefunc(char *x, int y, double z) {
- // CHECK: {{.*metadata !8, i32 0, i32 0}.*DW_TAG_subroutine_type}}
- // CHECK: {{!8 = .*metadata ![^,]*, metadata ![^,]*, metadata ![^,]*, metadata ![^,]*}}
+ // CHECK: metadata ![[NUM:[^,]*]], i32 0, i32 0} ; [ DW_TAG_subroutine_type
+ // CHECK: ![[NUM]] = {{metadata !{metadata ![^,]*, metadata ![^,]*, metadata ![^,]*, metadata ![^,]*}}}
return y;
}
diff --git a/test/CodeGen/debug-info-line.c b/test/CodeGen/debug-info-line.c
index 9e6e971..8f869d0 100644
--- a/test/CodeGen/debug-info-line.c
+++ b/test/CodeGen/debug-info-line.c
@@ -1,9 +1,8 @@
// RUN: %clang -emit-llvm -S -g %s -o - | FileCheck %s
// Radar 8396182
-// There is only one lexical block, but we need a DILexicalBlock and two
-// DILexicalBlockFile to correctly represent file info. This means we have
-// two lexical blocks shown as the latter is also tagged as a lexical block.
+// There are no lexical blocks, but we need two DILexicalBlockFiles to
+// correctly represent file info.
int foo() {
int i = 1;
@@ -16,7 +15,6 @@ int foo() {
}
// CHECK: DW_TAG_lexical_block
-// CHECK: DW_TAG_lexical_block
// CHECK: !"m.h"
// CHECK: DW_TAG_lexical_block
// CHECK: !"m.c"
diff --git a/test/CodeGen/debug-info-scope.c b/test/CodeGen/debug-info-scope.c
index 6051e6e..9decaea 100644
--- a/test/CodeGen/debug-info-scope.c
+++ b/test/CodeGen/debug-info-scope.c
@@ -4,10 +4,12 @@
int main() {
int j = 0;
int k = 0;
-// CHECK: DW_TAG_auto_variable
+// CHECK: DW_TAG_auto_variable ] [i]
// CHECK-NEXT: DW_TAG_lexical_block
for (int i = 0; i < 10; i++)
j++;
+// CHECK: DW_TAG_auto_variable ] [i]
+// CHECK-NEXT: DW_TAG_lexical_block
for (int i = 0; i < 10; i++)
k++;
return 0;
diff --git a/test/CodeGen/debug-info-static.c b/test/CodeGen/debug-info-static.c
index e75d20f..931c9e2 100644
--- a/test/CodeGen/debug-info-static.c
+++ b/test/CodeGen/debug-info-static.c
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -g -emit-llvm -o - %s | FileCheck %s
-// CHECK: xyzzy} ; [ DW_TAG_variable ]
+// CHECK: xyzzy, null} ; [ DW_TAG_variable ]
void f(void)
{
static int xyzzy;
diff --git a/test/CodeGen/debug-info-vector.c b/test/CodeGen/debug-info-vector.c
new file mode 100644
index 0000000..b7135af
--- /dev/null
+++ b/test/CodeGen/debug-info-vector.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -emit-llvm -g %s -o - | FileCheck %s
+typedef int v4si __attribute__((__vector_size__(16)));
+
+v4si a;
+
+// Test that we get an array type that's also a vector out of debug.
+// CHECK: [ DW_TAG_array_type ] [line 0, size 128, align 128, offset 0] [vector] [from int]
diff --git a/test/CodeGen/exceptions.c b/test/CodeGen/exceptions.c
index 20eb706..311bc84 100644
--- a/test/CodeGen/exceptions.c
+++ b/test/CodeGen/exceptions.c
@@ -19,3 +19,12 @@ void test1() {
// CHECK-ARM: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gcc_personality_sj0 to i8*)
// CHECK-ARM-NEXT: cleanup
}
+
+void test2_helper();
+void test2() {
+ __block int x = 10;
+ test2_helper(5, 6, 7);
+}
+void test2_helper(int x, int y) {
+}
+// CHECK: invoke void @test2_helper(i32 5, i32 6)
diff --git a/test/CodeGen/fast-math.c b/test/CodeGen/fast-math.c
new file mode 100644
index 0000000..76cfbbd
--- /dev/null
+++ b/test/CodeGen/fast-math.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -ffast-math -emit-llvm -o - %s | FileCheck %s
+float f0, f1, f2;
+
+void foo(void) {
+ // CHECK: define void @foo()
+
+ // CHECK: fadd fast
+ f0 = f1 + f2;
+
+ // CHECK: ret
+}
diff --git a/test/CodeGen/finite-math.c b/test/CodeGen/finite-math.c
new file mode 100644
index 0000000..bf39cea
--- /dev/null
+++ b/test/CodeGen/finite-math.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -ffinite-math-only -emit-llvm -o - %s | FileCheck %s
+float f0, f1, f2;
+
+void foo(void) {
+ // CHECK: define void @foo()
+
+ // CHECK: fadd nnan ninf
+ f0 = f1 + f2;
+
+ // CHECK: ret
+}
diff --git a/test/CodeGen/frame-pointer-elim.c b/test/CodeGen/frame-pointer-elim.c
deleted file mode 100644
index b105a19..0000000
--- a/test/CodeGen/frame-pointer-elim.c
+++ /dev/null
@@ -1,40 +0,0 @@
-// REQUIRES: x86-registered-target
-
-// RUN: %clang -target i386-apple-darwin -S -o - %s | \
-// RUN: FileCheck --check-prefix=DARWIN %s
-// DARWIN: f0:
-// DARWIN: pushl %ebp
-// DARWIN: ret
-// DARWIN: f1:
-// DARWIN: pushl %ebp
-// DARWIN: ret
-
-// RUN: %clang -target i386-pc-linux-gnu -S -o - %s | \
-// RUN: FileCheck --check-prefix=LINUX %s
-// LINUX: f0:
-// LINUX-NOT: pushl %ebp
-// LINUX: ret
-// LINUX: f1:
-// LINUX: pushl %ebp
-// LINUX: ret
-
-// RUN: %clang -target i386-darwin -S -o - -fomit-frame-pointer %s | \
-// RUN: FileCheck --check-prefix=OMIT_ALL %s
-// OMIT_ALL: f0:
-// OMIT_ALL-NOT: pushl %ebp
-// OMIT_ALL: ret
-// OMIT_ALL: f1:
-// OMIT_ALL-NOT: pushl %ebp
-// OMIT_ALL: ret
-
-// RUN: %clang -target i386-darwin -S -o - -momit-leaf-frame-pointer %s | \
-// RUN: FileCheck --check-prefix=OMIT_LEAF %s
-// OMIT_LEAF: f0:
-// OMIT_LEAF-NOT: pushl %ebp
-// OMIT_LEAF: ret
-// OMIT_LEAF: f1:
-// OMIT_LEAF: pushl %ebp
-// OMIT_LEAF: ret
-
-void f0() {}
-void f1() { f0(); }
diff --git a/test/CodeGen/function-attributes.c b/test/CodeGen/function-attributes.c
index 6cbf40b..25ca916 100644
--- a/test/CodeGen/function-attributes.c
+++ b/test/CodeGen/function-attributes.c
@@ -1,12 +1,12 @@
// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -Os -o - %s | FileCheck %s
-// CHECK: define signext i8 @f0(i32 %x) nounwind
-// CHECK: define zeroext i8 @f1(i32 %x) nounwind
-// CHECK: define void @f2(i8 signext %x) nounwind
-// CHECK: define void @f3(i8 zeroext %x) nounwind
-// CHECK: define signext i16 @f4(i32 %x) nounwind
-// CHECK: define zeroext i16 @f5(i32 %x) nounwind
-// CHECK: define void @f6(i16 signext %x) nounwind
-// CHECK: define void @f7(i16 zeroext %x) nounwind
+// CHECK: define signext i8 @f0(i32 %x) [[NUW:#[0-9]+]]
+// CHECK: define zeroext i8 @f1(i32 %x) [[NUW]]
+// CHECK: define void @f2(i8 signext %x) [[NUW]]
+// CHECK: define void @f3(i8 zeroext %x) [[NUW]]
+// CHECK: define signext i16 @f4(i32 %x) [[NUW]]
+// CHECK: define zeroext i16 @f5(i32 %x) [[NUW]]
+// CHECK: define void @f6(i16 signext %x) [[NUW]]
+// CHECK: define void @f7(i16 zeroext %x) [[NUW]]
signed char f0(int x) { return x; }
@@ -25,20 +25,25 @@ void f6(signed short x) { }
void f7(unsigned short x) { }
// CHECK: define void @f8()
-// CHECK: nounwind
-// CHECK: alwaysinline
+// CHECK: [[AI:#[0-9]+]]
// CHECK: {
void __attribute__((always_inline)) f8(void) { }
// CHECK: call void @f9_t()
-// CHECK: noreturn
-// CHECK: {
+// CHECK: [[NR:#[0-9]+]]
+// CHECK: }
void __attribute__((noreturn)) f9_t(void);
void f9(void) { f9_t(); }
+// CHECK: call void @f9a()
+// CHECK: [[NR]]
+// CHECK: }
+_Noreturn void f9a(void);
+void f9b(void) { f9a(); }
+
// FIXME: We should be setting nounwind on calls.
// CHECK: call i32 @f10_t()
-// CHECK: readnone
+// CHECK: [[NUW_RN:#[0-9]+]]
// CHECK: {
int __attribute__((const)) f10_t(void);
int f10(void) { return f10_t(); }
@@ -50,7 +55,7 @@ int f12(int arg) {
return arg ? 0 : f10_t();
}
-// CHECK: define void @f13() nounwind readnone
+// CHECK: define void @f13() [[NUW]]
void f13(void) __attribute__((pure)) __attribute__((const));
void f13(void){}
@@ -77,24 +82,24 @@ void f14(int a) {
// <rdar://problem/7102668> [irgen] clang isn't setting the optsize bit on functions
// CHECK: define void @f15
-// CHECK: optsize
+// CHECK: [[NUW]]
// CHECK: {
void f15(void) {
}
// PR5254
// CHECK: define void @f16
-// CHECK: alignstack(16)
+// CHECK: [[ALIGN:#[0-9]+]]
// CHECK: {
void __attribute__((force_align_arg_pointer)) f16(void) {
}
// PR11038
// CHECK: define void @f18()
-// CHECK: returns_twice
+// CHECK: [[RT:#[0-9]+]]
// CHECK: {
// CHECK: call void @f17()
-// CHECK: returns_twice
+// CHECK: [[RT_CALL:#[0-9]+]]
// CHECK: ret void
__attribute__ ((returns_twice)) void f17(void);
__attribute__ ((returns_twice)) void f18(void) {
@@ -104,10 +109,18 @@ __attribute__ ((returns_twice)) void f18(void) {
// CHECK: define void @f19()
// CHECK: {
// CHECK: call i32 @setjmp(i32* null)
-// CHECK: returns_twice
+// CHECK: [[RT_CALL]]
// CHECK: ret void
typedef int jmp_buf[((9 * 2) + 3 + 16)];
int setjmp(jmp_buf);
void f19(void) {
setjmp(0);
}
+
+// CHECK: attributes [[NUW]] = { nounwind optsize readnone{{.*}} }
+// CHECK: attributes [[AI]] = { alwaysinline nounwind optsize readnone{{.*}} }
+// CHECK: attributes [[ALIGN]] = { nounwind optsize readnone alignstack=16{{.*}} }
+// CHECK: attributes [[RT]] = { nounwind optsize returns_twice{{.*}} }
+// CHECK: attributes [[NR]] = { noreturn nounwind optsize }
+// CHECK: attributes [[NUW_RN]] = { nounwind optsize readnone }
+// CHECK: attributes [[RT_CALL]] = { nounwind optsize returns_twice }
diff --git a/test/CodeGen/functions.c b/test/CodeGen/functions.c
index 28e4bd0..8241a3d 100644
--- a/test/CodeGen/functions.c
+++ b/test/CodeGen/functions.c
@@ -24,7 +24,7 @@ void f0() {}
void f1();
void f2(void) {
-// CHECK: call void bitcast (void ()* @f1 to void (i32, i32, i32)*)(i32 1, i32 2, i32 3)
+// CHECK: call void @f1()
f1(1, 2, 3);
}
// CHECK: define void @f1()
diff --git a/test/CodeGen/global-blocks-lines.c b/test/CodeGen/global-blocks-lines.c
new file mode 100644
index 0000000..36e4618
--- /dev/null
+++ b/test/CodeGen/global-blocks-lines.c
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -fblocks -g -emit-llvm %s -o - | FileCheck %s
+// Make sure we do not generate line info for debugging-related frame setup.
+// CHECK: define {{.*}}block_invoke
+// CHECK-NOT: store {{.*}}%struct.__block_descriptor*{{.*}}dbg
+// CHECK: store {{.*}}%struct.__block_descriptor*{{.*}}, align
+// CHECK: ret
+// CHECK: define {{.*}}block_invoke
+// CHECK-NOT: store {{.*}}%struct.__block_descriptor*{{.*}}dbg
+// CHECK: store {{.*}}%struct.__block_descriptor*{{.*}}, align
+// CHECK: ret
+// CHECK: define {{.*}}block_invoke
+// CHECK-NOT: store {{.*}}%struct.__block_descriptor*{{.*}}dbg
+// CHECK: store {{.*}}%struct.__block_descriptor*{{.*}}, align
+// CHECK: ret
+int printf(const char*, ...);
+
+static void* _NSConcreteGlobalBlock;
+
+
+typedef void (^ HelloBlock_t)(const char * name);
+
+ /* Breakpoint for first Block function. */
+HelloBlock_t helloBlock = ^(const char * name) {
+ printf("Hello there, %s!\n", name);
+};
+
+ /* Breakpoint for second Block function. */
+static HelloBlock_t s_helloBlock = ^(const char * name) {
+ printf("Hello there, %s!\n", name);
+};
+
+/* Breakpoint for third Block function. */
+int X = 1234;
+int (^CP)(void) = ^{ X = X+1; return X; };
+
+int
+main(int argc, char * argv[])
+{
+ helloBlock("world");
+ s_helloBlock("world");
+
+ CP();
+ printf ("X = %d\n", X);
+ return X - 1235;
+}
diff --git a/test/CodeGen/incomplete-function-type-2.c b/test/CodeGen/incomplete-function-type-2.c
new file mode 100644
index 0000000..41dd5fe
--- /dev/null
+++ b/test/CodeGen/incomplete-function-type-2.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck %s
+
+// PR14355: don't crash
+// Keep this test in its own file because CodeGenTypes has global state.
+// CHECK: define void @test10_foo({}* %p1.coerce) [[NUW:#[0-9]+]] {
+struct test10_B;
+typedef struct test10_B test10_F3(double);
+void test10_foo(test10_F3 p1);
+struct test10_B test10_b(double);
+void test10_bar() {
+ test10_foo(test10_b);
+}
+struct test10_B {};
+void test10_foo(test10_F3 p1)
+{
+ p1(0.0);
+}
+
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGen/init.c b/test/CodeGen/init.c
index 259d34d..1b0beae 100644
--- a/test/CodeGen/init.c
+++ b/test/CodeGen/init.c
@@ -130,5 +130,5 @@ void test13(int x) {
struct X { int a; int b : 10; int c; };
struct X y = {.c = x};
// CHECK: @test13
- // CHECK: and i32 {{.*}}, -1024
+ // CHECK: and i16 {{.*}}, -1024
}
diff --git a/test/CodeGen/inline.c b/test/CodeGen/inline.c
index addb30b..442b380 100644
--- a/test/CodeGen/inline.c
+++ b/test/CodeGen/inline.c
@@ -1,55 +1,55 @@
// RUN: echo "GNU89 tests:"
-// 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
-// RUN: grep "define void @unreferenced1()" %t
-// RUN: not grep unreferenced2 %t
-// RUN: grep "define void @gnu_inline()" %t
-// RUN: grep "define available_externally void @gnu_ei_inline()" %t
-// RUN: grep "define i32 @test1" %t
-// RUN: grep "define i32 @test2" %t
-// RUN: grep "define void @test3()" %t
-// RUN: grep "define available_externally i32 @test4" %t
-// RUN: grep "define available_externally i32 @test5" %t
-// RUN: grep "define i32 @test6" %t
-// RUN: grep "define void @test7" %t
-// RUN: grep "define i.. @strlcpy" %t
-// RUN: not grep test9 %t
-// RUN: grep "define void @testA" %t
-// RUN: grep "define void @testB" %t
-// RUN: grep "define void @testC" %t
+// RUN: %clang %s -target i386-unknown-unknown -O1 -emit-llvm -S -o - -std=gnu89 | FileCheck %s --check-prefix=CHECK1
+// CHECK1: define i32 @foo()
+// CHECK1: define i32 @bar()
+// CHECK1: define void @unreferenced1()
+// CHECK1-NOT: unreferenced2
+// CHECK1: define void @gnu_inline()
+// CHECK1: define i32 @test1
+// CHECK1: define i32 @test2
+// CHECK1: define void @test3()
+// CHECK1: define available_externally i32 @test4
+// CHECK1: define available_externally i32 @test5
+// CHECK1: define i32 @test6
+// CHECK1: define void @test7
+// CHECK1: define i{{..}} @strlcpy
+// CHECK1-NOT: test9
+// CHECK1: define void @testA
+// CHECK1: define void @testB
+// CHECK1: define void @testC
+// CHECK1: define available_externally void @gnu_ei_inline()
+// CHECK1: define available_externally i32 @ei()
// RUN: echo "C99 tests:"
-// 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
-// RUN: not grep unreferenced1 %t
-// RUN: grep "define void @unreferenced2()" %t
-// RUN: grep "define void @gnu_inline()" %t
-// RUN: grep "define available_externally void @gnu_ei_inline()" %t
-// RUN: grep "define i32 @test1" %t
-// RUN: grep "define i32 @test2" %t
-// RUN: grep "define void @test3" %t
-// RUN: grep "define available_externally i32 @test4" %t
-// RUN: grep "define available_externally i32 @test5" %t
-// RUN: grep "define i32 @test6" %t
-// RUN: grep "define void @test7" %t
-// RUN: grep "define available_externally i.. @strlcpy" %t
-// RUN: grep "define void @test9" %t
-// RUN: grep "define void @testA" %t
-// RUN: grep "define void @testB" %t
-// RUN: grep "define void @testC" %t
+// RUN: %clang %s -target i386-unknown-unknown -O1 -emit-llvm -S -o - -std=gnu99 | FileCheck %s --check-prefix=CHECK2
+// CHECK2: define i32 @ei()
+// CHECK2: define i32 @bar()
+// CHECK2-NOT: unreferenced1
+// CHECK2: define void @unreferenced2()
+// CHECK2: define void @gnu_inline()
+// CHECK2: define i32 @test1
+// CHECK2: define i32 @test2
+// CHECK2: define void @test3
+// CHECK2: define available_externally i32 @test4
+// CHECK2: define available_externally i32 @test5
+// CHECK2: define i32 @test6
+// CHECK2: define void @test7
+// CHECK2: define available_externally i{{..}} @strlcpy
+// CHECK2: define void @test9
+// CHECK2: define void @testA
+// CHECK2: define void @testB
+// CHECK2: define void @testC
+// CHECK2: define available_externally void @gnu_ei_inline()
+// CHECK2: define available_externally i32 @foo()
// RUN: echo "C++ tests:"
-// 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
-// RUN: not grep unreferenced %t
-// RUN: grep "define void @_Z10gnu_inlinev()" %t
-// RUN: grep "define available_externally void @_Z13gnu_ei_inlinev()" %t
+// RUN: %clang -x c++ %s -target i386-unknown-unknown -O1 -emit-llvm -S -o - -std=c++98 | FileCheck %s --check-prefix=CHECK3
+// CHECK3: define i32 @_Z3barv()
+// CHECK3: define linkonce_odr i32 @_Z3foov()
+// CHECK3-NOT: unreferenced
+// CHECK3: define void @_Z10gnu_inlinev()
+// CHECK3: define available_externally void @_Z13gnu_ei_inlinev()
+// CHECK3: define linkonce_odr i32 @_Z2eiv()
extern __inline int ei() { return 123; }
diff --git a/test/CodeGen/intel_ocl_bicc.c b/test/CodeGen/intel_ocl_bicc.c
new file mode 100644
index 0000000..c5c5229
--- /dev/null
+++ b/test/CodeGen/intel_ocl_bicc.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+
+void __attribute__((intel_ocl_bicc)) f1(void);
+
+void f2(void) {
+ f1();
+// CHECK: call intel_ocl_bicc void @f1()
+}
+
+// CHECK: declare intel_ocl_bicc void @f1()
diff --git a/test/CodeGen/le32-regparm.c b/test/CodeGen/le32-regparm.c
index 6ab5a11..8c1ae5e 100644
--- a/test/CodeGen/le32-regparm.c
+++ b/test/CodeGen/le32-regparm.c
@@ -34,7 +34,7 @@ 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
+ // CHECK: call void @reduced(i8 inreg signext 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
index 4517643..d07590f 100644
--- a/test/CodeGen/libcall-declarations.c
+++ b/test/CodeGen/libcall-declarations.c
@@ -86,106 +86,110 @@ void *use[] = {
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-NOERRNO: declare double @acos(double) [[NUW:#[0-9]+]]
+// CHECK-NOERRNO: declare x86_fp80 @acosl(x86_fp80) [[NUW]]
+// CHECK-NOERRNO: declare float @acosf(float) [[NUW]]
+// CHECK-NOERRNO: declare double @asin(double) [[NUW]]
+// CHECK-NOERRNO: declare x86_fp80 @asinl(x86_fp80) [[NUW]]
+// CHECK-NOERRNO: declare float @asinf(float) [[NUW]]
+// CHECK-NOERRNO: declare double @atan(double) [[NUW]]
+// CHECK-NOERRNO: declare x86_fp80 @atanl(x86_fp80) [[NUW]]
+// CHECK-NOERRNO: declare float @atanf(float) [[NUW]]
+// CHECK-NOERRNO: declare double @atan2(double, double) [[NUW]]
+// CHECK-NOERRNO: declare x86_fp80 @atan2l(x86_fp80, x86_fp80) [[NUW]]
+// CHECK-NOERRNO: declare float @atan2f(float, float) [[NUW]]
+// CHECK-NOERRNO: declare double @ceil(double) [[NUW]]
+// CHECK-NOERRNO: declare x86_fp80 @ceill(x86_fp80) [[NUW]]
+// CHECK-NOERRNO: declare float @ceilf(float) [[NUW]]
+// CHECK-NOERRNO: declare double @copysign(double, double) [[NUW]]
+// CHECK-NOERRNO: declare x86_fp80 @copysignl(x86_fp80, x86_fp80) [[NUW]]
+// CHECK-NOERRNO: declare float @copysignf(float, float) [[NUW]]
+// CHECK-NOERRNO: declare double @cos(double) [[NUW]]
+// CHECK-NOERRNO: declare x86_fp80 @cosl(x86_fp80) [[NUW]]
+// CHECK-NOERRNO: declare float @cosf(float) [[NUW]]
+// CHECK-NOERRNO: declare double @exp(double) [[NUW]]
+// CHECK-NOERRNO: declare x86_fp80 @expl(x86_fp80) [[NUW]]
+// CHECK-NOERRNO: declare float @expf(float) [[NUW]]
+// CHECK-NOERRNO: declare double @exp2(double) [[NUW]]
+// CHECK-NOERRNO: declare x86_fp80 @exp2l(x86_fp80) [[NUW]]
+// CHECK-NOERRNO: declare float @exp2f(float) [[NUW]]
+// CHECK-NOERRNO: declare double @fabs(double) [[NUW]]
+// CHECK-NOERRNO: declare x86_fp80 @fabsl(x86_fp80) [[NUW]]
+// CHECK-NOERRNO: declare float @fabsf(float) [[NUW]]
+// CHECK-NOERRNO: declare double @floor(double) [[NUW]]
+// CHECK-NOERRNO: declare x86_fp80 @floorl(x86_fp80) [[NUW]]
+// CHECK-NOERRNO: declare float @floorf(float) [[NUW]]
+// CHECK-NOERRNO: declare double @fma(double, double, double) [[NUW]]
+// CHECK-NOERRNO: declare x86_fp80 @fmal(x86_fp80, x86_fp80, x86_fp80) [[NUW]]
+// CHECK-NOERRNO: declare float @fmaf(float, float, float) [[NUW]]
+// CHECK-NOERRNO: declare double @fmax(double, double) [[NUW]]
+// CHECK-NOERRNO: declare x86_fp80 @fmaxl(x86_fp80, x86_fp80) [[NUW]]
+// CHECK-NOERRNO: declare float @fmaxf(float, float) [[NUW]]
+// CHECK-NOERRNO: declare double @fmin(double, double) [[NUW]]
+// CHECK-NOERRNO: declare x86_fp80 @fminl(x86_fp80, x86_fp80) [[NUW]]
+// CHECK-NOERRNO: declare float @fminf(float, float) [[NUW]]
+// CHECK-NOERRNO: declare double @log(double) [[NUW]]
+// CHECK-NOERRNO: declare x86_fp80 @logl(x86_fp80) [[NUW]]
+// CHECK-NOERRNO: declare float @logf(float) [[NUW]]
+// CHECK-NOERRNO: declare double @log2(double) [[NUW]]
+// CHECK-NOERRNO: declare x86_fp80 @log2l(x86_fp80) [[NUW]]
+// CHECK-NOERRNO: declare float @log2f(float) [[NUW]]
+// CHECK-NOERRNO: declare double @nearbyint(double) [[NUW]]
+// CHECK-NOERRNO: declare x86_fp80 @nearbyintl(x86_fp80) [[NUW]]
+// CHECK-NOERRNO: declare float @nearbyintf(float) [[NUW]]
+// CHECK-NOERRNO: declare double @pow(double, double) [[NUW]]
+// CHECK-NOERRNO: declare x86_fp80 @powl(x86_fp80, x86_fp80) [[NUW]]
+// CHECK-NOERRNO: declare float @powf(float, float) [[NUW]]
+// CHECK-NOERRNO: declare double @rint(double) [[NUW]]
+// CHECK-NOERRNO: declare x86_fp80 @rintl(x86_fp80) [[NUW]]
+// CHECK-NOERRNO: declare float @rintf(float) [[NUW]]
+// CHECK-NOERRNO: declare double @round(double) [[NUW]]
+// CHECK-NOERRNO: declare x86_fp80 @roundl(x86_fp80) [[NUW]]
+// CHECK-NOERRNO: declare float @roundf(float) [[NUW]]
+// CHECK-NOERRNO: declare double @sin(double) [[NUW]]
+// CHECK-NOERRNO: declare x86_fp80 @sinl(x86_fp80) [[NUW]]
+// CHECK-NOERRNO: declare float @sinf(float) [[NUW]]
+// CHECK-NOERRNO: declare double @sqrt(double) [[NUW]]
+// CHECK-NOERRNO: declare x86_fp80 @sqrtl(x86_fp80) [[NUW]]
+// CHECK-NOERRNO: declare float @sqrtf(float) [[NUW]]
+// CHECK-NOERRNO: declare double @tan(double) [[NUW]]
+// CHECK-NOERRNO: declare x86_fp80 @tanl(x86_fp80) [[NUW]]
+// CHECK-NOERRNO: declare float @tanf(float) [[NUW]]
+// CHECK-NOERRNO: declare double @trunc(double) [[NUW]]
+// CHECK-NOERRNO: declare x86_fp80 @truncl(x86_fp80) [[NUW]]
+// CHECK-NOERRNO: declare float @truncf(float) [[NUW]]
-// CHECK-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
+// CHECK-ERRNO: declare double @ceil(double) [[NUW:#[0-9]+]]
+// CHECK-ERRNO: declare x86_fp80 @ceill(x86_fp80) [[NUW]]
+// CHECK-ERRNO: declare float @ceilf(float) [[NUW]]
+// CHECK-ERRNO: declare double @copysign(double, double) [[NUW]]
+// CHECK-ERRNO: declare x86_fp80 @copysignl(x86_fp80, x86_fp80) [[NUW]]
+// CHECK-ERRNO: declare float @copysignf(float, float) [[NUW]]
+// CHECK-ERRNO: declare double @fabs(double) [[NUW]]
+// CHECK-ERRNO: declare x86_fp80 @fabsl(x86_fp80) [[NUW]]
+// CHECK-ERRNO: declare float @fabsf(float) [[NUW]]
+// CHECK-ERRNO: declare double @floor(double) [[NUW]]
+// CHECK-ERRNO: declare x86_fp80 @floorl(x86_fp80) [[NUW]]
+// CHECK-ERRNO: declare float @floorf(float) [[NUW]]
+// CHECK-ERRNO: declare double @fmax(double, double) [[NUW]]
+// CHECK-ERRNO: declare x86_fp80 @fmaxl(x86_fp80, x86_fp80) [[NUW]]
+// CHECK-ERRNO: declare float @fmaxf(float, float) [[NUW]]
+// CHECK-ERRNO: declare double @fmin(double, double) [[NUW]]
+// CHECK-ERRNO: declare x86_fp80 @fminl(x86_fp80, x86_fp80) [[NUW]]
+// CHECK-ERRNO: declare float @fminf(float, float) [[NUW]]
+// CHECK-ERRNO: declare double @nearbyint(double) [[NUW]]
+// CHECK-ERRNO: declare x86_fp80 @nearbyintl(x86_fp80) [[NUW]]
+// CHECK-ERRNO: declare float @nearbyintf(float) [[NUW]]
+// CHECK-ERRNO: declare double @rint(double) [[NUW]]
+// CHECK-ERRNO: declare x86_fp80 @rintl(x86_fp80) [[NUW]]
+// CHECK-ERRNO: declare float @rintf(float) [[NUW]]
+// CHECK-ERRNO: declare double @round(double) [[NUW]]
+// CHECK-ERRNO: declare x86_fp80 @roundl(x86_fp80) [[NUW]]
+// CHECK-ERRNO: declare float @roundf(float) [[NUW]]
+// CHECK-ERRNO: declare double @trunc(double) [[NUW]]
+// CHECK-ERRNO: declare x86_fp80 @truncl(x86_fp80) [[NUW]]
+// CHECK-ERRNO: declare float @truncf(float) [[NUW]]
+
+// CHECK-NOERRNO: attributes [[NUW]] = { nounwind readnone{{.*}} }
+
+// CHECK-ERRNO: attributes [[NUW]] = { nounwind readnone{{.*}} }
diff --git a/test/CodeGen/libcalls-complex.c b/test/CodeGen/libcalls-complex.c
new file mode 100644
index 0000000..7bcfa60
--- /dev/null
+++ b/test/CodeGen/libcalls-complex.c
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -fno-builtin -emit-llvm -o - %s -triple i386-unknown-unknown | FileCheck -check-prefix YES %s
+// RUN: %clang_cc1 -emit-llvm -o - %s -triple i386-unknown-unknown | FileCheck -check-prefix NO %s
+
+extern float crealf(float _Complex);
+extern double creal(double _Complex);
+extern long double creall(long double _Complex);
+
+extern float cimagf(float _Complex);
+extern double cimag(double _Complex);
+extern long double cimagl(long double _Complex);
+
+double test_creal(double _Complex z) {
+ return creal(z);
+ // CHECK-NO-NOT: call double @creal
+ // CHECK-YES: call double @creal
+}
+
+long double test_creall(double _Complex z) {
+ return creall(z);
+ // CHECK-NO-NOT: call x86_fp80 @creall
+ // CHECK-YES: call x86_fp80 @creall
+}
+
+float test_crealf(double _Complex z) {
+ return crealf(z);
+ // CHECK-NO-NOT: call float @crealf
+ // CHECK-YES: call float @crealf
+}
+
+double test_cimag(double _Complex z) {
+ return cimag(z);
+ // CHECK-NO-NOT: call double @cimag
+ // CHECK-YES: call double @cimag
+}
+
+long double test_cimagl(double _Complex z) {
+ return cimagl(z);
+ // CHECK-NO-NOT: call x86_fp80 @cimagl
+ // CHECK-YES: call x86_fp80 @cimagl
+}
+
+float test_cimagf(double _Complex z) {
+ return cimagf(z);
+ // CHECK-NO-NOT: call float @cimagf
+ // CHECK-YES: call float @cimagf
+}
diff --git a/test/CodeGen/libcalls.c b/test/CodeGen/libcalls.c
index ec895ac..8f8e182 100644
--- a/test/CodeGen/libcalls.c
+++ b/test/CodeGen/libcalls.c
@@ -24,9 +24,9 @@ void test_sqrt(float a0, double a1, long double a2) {
// CHECK-YES: declare float @sqrtf(float)
// CHECK-YES: declare double @sqrt(double)
// CHECK-YES: declare x86_fp80 @sqrtl(x86_fp80)
-// CHECK-NO: declare float @sqrtf(float) nounwind readnone
-// CHECK-NO: declare double @sqrt(double) nounwind readnone
-// CHECK-NO: declare x86_fp80 @sqrtl(x86_fp80) nounwind readnone
+// CHECK-NO: declare float @sqrtf(float) [[NUW_RN:#[0-9]+]]
+// CHECK-NO: declare double @sqrt(double) [[NUW_RN]]
+// CHECK-NO: declare x86_fp80 @sqrtl(x86_fp80) [[NUW_RN]]
// CHECK-YES: define void @test_pow
// CHECK-NO: define void @test_pow
@@ -47,9 +47,9 @@ void test_pow(float a0, double a1, long double a2) {
// CHECK-YES: declare float @powf(float, float)
// CHECK-YES: declare double @pow(double, double)
// CHECK-YES: declare x86_fp80 @powl(x86_fp80, x86_fp80)
-// CHECK-NO: declare float @llvm.pow.f32(float, float) nounwind readonly
-// CHECK-NO: declare double @llvm.pow.f64(double, double) nounwind readonly
-// CHECK-NO: declare x86_fp80 @llvm.pow.f80(x86_fp80, x86_fp80) nounwind readonly
+// CHECK-NO: declare float @llvm.pow.f32(float, float) [[NUW_RO:#[0-9]+]]
+// CHECK-NO: declare double @llvm.pow.f64(double, double) [[NUW_RO]]
+// CHECK-NO: declare x86_fp80 @llvm.pow.f80(x86_fp80, x86_fp80) [[NUW_RO]]
// CHECK-YES: define void @test_fma
// CHECK-NO: define void @test_fma
@@ -67,12 +67,12 @@ void test_fma(float a0, double a1, long double a2) {
long double l2 = fmal(a2, a2, a2);
}
-// CHECK-YES: declare float @llvm.fma.f32(float, float, float) nounwind readnone
-// CHECK-YES: declare double @llvm.fma.f64(double, double, double) nounwind readnone
-// CHECK-YES: declare x86_fp80 @llvm.fma.f80(x86_fp80, x86_fp80, x86_fp80) nounwind readnone
-// CHECK-NO: declare float @llvm.fma.f32(float, float, float) nounwind readnone
-// CHECK-NO: declare double @llvm.fma.f64(double, double, double) nounwind readnone
-// CHECK-NO: declare x86_fp80 @llvm.fma.f80(x86_fp80, x86_fp80, x86_fp80) nounwind readnone
+// CHECK-YES: declare float @llvm.fma.f32(float, float, float) [[NUW_RN:#[0-9]+]]
+// CHECK-YES: declare double @llvm.fma.f64(double, double, double) [[NUW_RN]]
+// CHECK-YES: declare x86_fp80 @llvm.fma.f80(x86_fp80, x86_fp80, x86_fp80) [[NUW_RN]]
+// CHECK-NO: declare float @llvm.fma.f32(float, float, float) [[NUW_RN2:#[0-9]+]]
+// CHECK-NO: declare double @llvm.fma.f64(double, double, double) [[NUW_RN2]]
+// CHECK-NO: declare x86_fp80 @llvm.fma.f80(x86_fp80, x86_fp80, x86_fp80) [[NUW_RN2]]
// Just checking to make sure these library functions are marked readnone
void test_builtins(double d, float f, long double ld) {
@@ -81,40 +81,45 @@ void test_builtins(double d, float f, long double ld) {
double atan_ = atan(d);
long double atanl_ = atanl(ld);
float atanf_ = atanf(f);
-// CHECK-NO: declare double @atan(double) nounwind readnone
-// CHECK-NO: declare x86_fp80 @atanl(x86_fp80) nounwind readnone
-// CHECK-NO: declare float @atanf(float) nounwind readnone
-// CHECK-YES-NOT: declare double @atan(double) nounwind readnone
-// CHECK-YES-NOT: declare x86_fp80 @atanl(x86_fp80) nounwind readnone
-// CHECK-YES-NOT: declare float @atanf(float) nounwind readnone
+// CHECK-NO: declare double @atan(double) [[NUW_RN]]
+// CHECK-NO: declare x86_fp80 @atanl(x86_fp80) [[NUW_RN]]
+// CHECK-NO: declare float @atanf(float) [[NUW_RN]]
+// CHECK-YES-NOT: declare double @atan(double) [[NUW_RN]]
+// CHECK-YES-NOT: declare x86_fp80 @atanl(x86_fp80) [[NUW_RN]]
+// CHECK-YES-NOT: declare float @atanf(float) [[NUW_RN]]
double atan2_ = atan2(d, 2);
long double atan2l_ = atan2l(ld, ld);
float atan2f_ = atan2f(f, f);
-// CHECK-NO: declare double @atan2(double, double) nounwind readnone
-// CHECK-NO: declare x86_fp80 @atan2l(x86_fp80, x86_fp80) nounwind readnone
-// CHECK-NO: declare float @atan2f(float, float) nounwind readnone
-// CHECK-YES-NOT: declare double @atan2(double, double) nounwind readnone
-// CHECK-YES-NOT: declare x86_fp80 @atan2l(x86_fp80, x86_fp80) nounwind readnone
-// CHECK-YES-NOT: declare float @atan2f(float, float) nounwind readnone
+// CHECK-NO: declare double @atan2(double, double) [[NUW_RN]]
+// CHECK-NO: declare x86_fp80 @atan2l(x86_fp80, x86_fp80) [[NUW_RN]]
+// CHECK-NO: declare float @atan2f(float, float) [[NUW_RN]]
+// CHECK-YES-NOT: declare double @atan2(double, double) [[NUW_RN]]
+// CHECK-YES-NOT: declare x86_fp80 @atan2l(x86_fp80, x86_fp80) [[NUW_RN]]
+// CHECK-YES-NOT: declare float @atan2f(float, float) [[NUW_RN]]
double exp_ = exp(d);
long double expl_ = expl(ld);
float expf_ = expf(f);
-// CHECK-NO: declare double @exp(double) nounwind readnone
-// CHECK-NO: declare x86_fp80 @expl(x86_fp80) nounwind readnone
-// CHECK-NO: declare float @expf(float) nounwind readnone
-// CHECK-YES-NOT: declare double @exp(double) nounwind readnone
-// CHECK-YES-NOT: declare x86_fp80 @expl(x86_fp80) nounwind readnone
-// CHECK-YES-NOT: declare float @expf(float) nounwind readnone
+// CHECK-NO: declare double @exp(double) [[NUW_RN]]
+// CHECK-NO: declare x86_fp80 @expl(x86_fp80) [[NUW_RN]]
+// CHECK-NO: declare float @expf(float) [[NUW_RN]]
+// CHECK-YES-NOT: declare double @exp(double) [[NUW_RN]]
+// CHECK-YES-NOT: declare x86_fp80 @expl(x86_fp80) [[NUW_RN]]
+// CHECK-YES-NOT: declare float @expf(float) [[NUW_RN]]
double log_ = log(d);
long double logl_ = logl(ld);
float logf_ = logf(f);
-// CHECK-NO: declare double @log(double) nounwind readnone
-// CHECK-NO: declare x86_fp80 @logl(x86_fp80) nounwind readnone
-// CHECK-NO: declare float @logf(float) nounwind readnone
-// CHECK-YES-NOT: declare double @log(double) nounwind readnone
-// CHECK-YES-NOT: declare x86_fp80 @logl(x86_fp80) nounwind readnone
-// CHECK-YES-NOT: declare float @logf(float) nounwind readnone
+// CHECK-NO: declare double @log(double) [[NUW_RN]]
+// CHECK-NO: declare x86_fp80 @logl(x86_fp80) [[NUW_RN]]
+// CHECK-NO: declare float @logf(float) [[NUW_RN]]
+// CHECK-YES-NOT: declare double @log(double) [[NUW_RN]]
+// CHECK-YES-NOT: declare x86_fp80 @logl(x86_fp80) [[NUW_RN]]
+// CHECK-YES-NOT: declare float @logf(float) [[NUW_RN]]
}
+
+// CHECK-YES: attributes [[NUW_RN]] = { nounwind readnone }
+
+// CHECK-NO: attributes [[NUW_RN]] = { nounwind readnone{{.*}} }
+// CHECK-NO: attributes [[NUW_RO]] = { nounwind readonly }
diff --git a/test/CodeGen/lifetime2.c b/test/CodeGen/lifetime2.c
new file mode 100644
index 0000000..ffff5cc
--- /dev/null
+++ b/test/CodeGen/lifetime2.c
@@ -0,0 +1,17 @@
+// RUN: %clang -S -emit-llvm -o - -O2 %s | FileCheck %s -check-prefix=O2
+// RUN: %clang -S -emit-llvm -o - -O0 %s | FileCheck %s -check-prefix=O0
+
+extern int bar(char *A, int n);
+
+// O0-NOT: @llvm.lifetime.start
+int foo (int n) {
+ if (n) {
+// O2: @llvm.lifetime.start
+ char A[100];
+ return bar(A, 1);
+ } else {
+// O2: @llvm.lifetime.start
+ char A[100];
+ return bar(A, 2);
+ }
+}
diff --git a/test/CodeGen/linkage-redecl.c b/test/CodeGen/linkage-redecl.c
index 09b51f0..14112fe 100644
--- a/test/CodeGen/linkage-redecl.c
+++ b/test/CodeGen/linkage-redecl.c
@@ -1,4 +1,11 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - |grep internal
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+
+// CHECK: @test2_i = internal global i32 99
+static int test2_i = 99;
+int test2_f() {
+ extern int test2_i;
+ return test2_i;
+}
// C99 6.2.2p3
// PR3425
@@ -9,3 +16,4 @@ void g0() {
}
extern void f(int x) { } // still has internal linkage
+// CHECK: define internal void @f
diff --git a/test/CodeGen/mips-constraint-regs.c b/test/CodeGen/mips-constraint-regs.c
index ea063b5..0d533f5 100644
--- a/test/CodeGen/mips-constraint-regs.c
+++ b/test/CodeGen/mips-constraint-regs.c
@@ -2,16 +2,14 @@
// RUN: | FileCheck %s
// This checks that the frontend will accept inline asm constraints
-// c', 'l' and 'x'. Semantic checking will happen in the
-// llvm backend. Any bad constraint letters will cause the frontend to
-// error out.
+// c', 'l' and 'x'.
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]+}}
+ // CHECK: %{{[0-9]+}} = call i32 asm sideeffect "addi $0,$1,$2 \0A\09\09", "=c,c,I"(i32 %{{[0-9]+}}, i32 %{{[0-9]+}}) [[NUW:#[0-9]+]], !srcloc !{{[0-9]+}}
int __s, __v = 17;
int __t;
__asm__ __volatile__(
@@ -22,7 +20,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]+}}
+ // CHECK: %{{[0-9]+}} = call i32 asm sideeffect "mtlo $1 \0A\09\09", "=l,r,~{lo}"(i32 %{{[0-9]+}}) [[NUW]], !srcloc !{{[0-9]+}}
int i_temp = 44;
int i_result;
__asm__ __volatile__(
@@ -34,7 +32,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]+}}
+ // 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]+}}) [[NUW]], !srcloc !{{[0-9]+}}
int i_hi = 3;
int i_lo = 2;
long long ll_result = 0;
@@ -47,3 +45,5 @@ int main()
return 0;
}
+
+// CHECK: attributes [[NUW]] = { nounwind }
diff --git a/test/CodeGen/mips-constraints-mem.c b/test/CodeGen/mips-constraints-mem.c
new file mode 100644
index 0000000..ea6bcaf
--- /dev/null
+++ b/test/CodeGen/mips-constraints-mem.c
@@ -0,0 +1,26 @@
+// RUN: %clang -target mipsel-unknown-linux -S -o - -emit-llvm %s \
+// RUN: | FileCheck %s
+
+// This checks that the frontend will accept inline asm memory constraints.
+
+int foo()
+{
+
+ // 'R': An address that can be used in a non-macro load or stor'
+ // This test will result in the higher and lower nibbles being
+ // switched due to the lwl/lwr instruction pairs.
+ // CHECK: %{{[0-9]+}} = call i32 asm sideeffect "lwl $0, 1 + $1\0A\09lwr $0, 2 + $1\0A\09", "=r,*R"(i32* %{{[0-9,a-f]+}}) #1, !srcloc !0
+
+ int c = 0xffbbccdd;
+
+ int *p = &c;
+ int out = 0;
+
+ __asm volatile (
+ "lwl %0, 1 + %1\n\t"
+ "lwr %0, 2 + %1\n\t"
+ : "=r"(out)
+ : "R"(*p)
+ );
+ return 0;
+}
diff --git a/test/CodeGen/mips-target-data.c b/test/CodeGen/mips-target-data.c
new file mode 100644
index 0000000..88eadcb
--- /dev/null
+++ b/test/CodeGen/mips-target-data.c
@@ -0,0 +1,14 @@
+// RUN: %clang -target mipsel-linux-gnu -o - -emit-llvm -S %s |\
+// RUN: FileCheck %s -check-prefix=32EL
+// RUN: %clang -target mips-linux-gnu -o - -emit-llvm -S %s |\
+// RUN: FileCheck %s -check-prefix=32EB
+// RUN: %clang -target mips64el-linux-gnu -o - -emit-llvm -S %s |\
+// RUN: FileCheck %s -check-prefix=64EL
+// RUN: %clang -target mips64-linux-gnu -o - -emit-llvm -S %s |\
+// RUN: FileCheck %s -check-prefix=64EB
+
+// 32EL: e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32-S64
+// 32EB: E-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32-S64
+// 64EL: e-p:64:64:64-i1:8:8-i8:8:32-i16:16:32-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f128:128:128-v64:64:64-n32:64-S128
+// 64EB: E-p:64:64:64-i1:8:8-i8:8:32-i16:16:32-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f128:128:128-v64:64:64-n32:64-S128
+
diff --git a/test/CodeGen/mips-vector-arg.c b/test/CodeGen/mips-vector-arg.c
index 584192f..6ffb043 100644
--- a/test/CodeGen/mips-vector-arg.c
+++ b/test/CodeGen/mips-vector-arg.c
@@ -8,21 +8,24 @@
typedef float v4sf __attribute__ ((__vector_size__ (16)));
typedef int v4i32 __attribute__ ((__vector_size__ (16)));
-// O32: define void @test_v4sf(i32 %a1.coerce0, i32 %a1.coerce1, i32 %a1.coerce2, i32 %a1.coerce3, i32 %a2, i32, i32 %a3.coerce0, i32 %a3.coerce1, i32 %a3.coerce2, i32 %a3.coerce3) nounwind
+// O32: define void @test_v4sf(i32 %a1.coerce0, i32 %a1.coerce1, i32 %a1.coerce2, i32 %a1.coerce3, i32 %a2, i32, i32 %a3.coerce0, i32 %a3.coerce1, i32 %a3.coerce2, i32 %a3.coerce3) [[NUW:#[0-9]+]]
// O32: declare i32 @test_v4sf_2(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32)
-// N64: define void @test_v4sf(i64 %a1.coerce0, i64 %a1.coerce1, i32 %a2, i64, i64 %a3.coerce0, i64 %a3.coerce1) nounwind
+// N64: define void @test_v4sf(i64 %a1.coerce0, i64 %a1.coerce1, i32 %a2, i64, i64 %a3.coerce0, i64 %a3.coerce1) [[NUW:#[0-9]+]]
// N64: declare i32 @test_v4sf_2(i64, i64, i32, i64, i64, i64)
extern test_v4sf_2(v4sf, int, v4sf);
void test_v4sf(v4sf a1, int a2, v4sf a3) {
test_v4sf_2(a3, a2, a1);
}
-// O32: define void @test_v4i32(i32 %a1.coerce0, i32 %a1.coerce1, i32 %a1.coerce2, i32 %a1.coerce3, i32 %a2, i32, i32 %a3.coerce0, i32 %a3.coerce1, i32 %a3.coerce2, i32 %a3.coerce3) nounwind
+// O32: define void @test_v4i32(i32 %a1.coerce0, i32 %a1.coerce1, i32 %a1.coerce2, i32 %a1.coerce3, i32 %a2, i32, i32 %a3.coerce0, i32 %a3.coerce1, i32 %a3.coerce2, i32 %a3.coerce3) [[NUW]]
// O32: declare i32 @test_v4i32_2(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32)
-// N64: define void @test_v4i32(i64 %a1.coerce0, i64 %a1.coerce1, i32 %a2, i64, i64 %a3.coerce0, i64 %a3.coerce1) nounwind
+// N64: define void @test_v4i32(i64 %a1.coerce0, i64 %a1.coerce1, i32 %a2, i64, i64 %a3.coerce0, i64 %a3.coerce1) [[NUW]]
// N64: declare i32 @test_v4i32_2(i64, i64, i32, i64, i64, i64)
extern test_v4i32_2(v4i32, int, v4i32);
void test_v4i32(v4i32 a1, int a2, v4i32 a3) {
test_v4i32_2(a3, a2, a1);
}
+// O32: attributes [[NUW]] = { nounwind{{.*}} }
+
+// N64: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGen/mips16-attr.c b/test/CodeGen/mips16-attr.c
new file mode 100644
index 0000000..18799be
--- /dev/null
+++ b/test/CodeGen/mips16-attr.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -triple mipsel-linux-gnu -emit-llvm -o - %s | FileCheck %s
+void __attribute__((mips16)) foo (void) {
+
+}
+
+// CHECK: define void @foo() [[MIPS16:#[0-9]+]]
+
+void __attribute__((nomips16)) nofoo (void) {
+
+}
+
+// CHECK: define void @nofoo() [[NOMIPS16:#[0-9]+]]
+
+// CHECK: attributes [[MIPS16]] = { nounwind {{.*}} "mips16" {{.*}} }
+
+// CHECK: attributes [[NOMIPS16]] = { nounwind {{.*}} "nomips16" {{.*}} }
+
diff --git a/test/CodeGen/mips64-padding-arg.c b/test/CodeGen/mips64-padding-arg.c
index 9d7f877..85dc00c 100644
--- a/test/CodeGen/mips64-padding-arg.c
+++ b/test/CodeGen/mips64-padding-arg.c
@@ -1,4 +1,5 @@
-// RUN: %clang -target mips64el-unknown-linux -O3 -S -mabi=n64 -o - -emit-llvm %s | FileCheck %s
+// 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 {
double d;
@@ -7,9 +8,9 @@ typedef struct {
// Insert padding to ensure arguments of type S0 are aligned to 16-byte boundaries.
-// CHECK: define void @foo1(i32 %a0, i64, double %a1.coerce0, i64 %a1.coerce1, i64 %a1.coerce2, i64 %a1.coerce3, double %a2.coerce0, i64 %a2.coerce1, i64 %a2.coerce2, i64 %a2.coerce3, i32 %b, i64, double %a3.coerce0, i64 %a3.coerce1, i64 %a3.coerce2, i64 %a3.coerce3)
-// CHECK: tail call void @foo2(i32 1, i32 2, i32 %a0, i64 undef, double %a1.coerce0, i64 %a1.coerce1, i64 %a1.coerce2, i64 %a1.coerce3, double %a2.coerce0, i64 %a2.coerce1, i64 %a2.coerce2, i64 %a2.coerce3, i32 3, i64 undef, double %a3.coerce0, i64 %a3.coerce1, i64 %a3.coerce2, i64 %a3.coerce3)
-// CHECK: declare void @foo2(i32, i32, i32, i64, double, i64, i64, i64, double, i64, i64, i64, i32, i64, double, i64, i64, i64)
+// N64: define void @foo1(i32 %a0, i64, double %a1.coerce0, i64 %a1.coerce1, i64 %a1.coerce2, i64 %a1.coerce3, double %a2.coerce0, i64 %a2.coerce1, i64 %a2.coerce2, i64 %a2.coerce3, i32 %b, i64, double %a3.coerce0, i64 %a3.coerce1, i64 %a3.coerce2, i64 %a3.coerce3)
+// N64: tail call void @foo2(i32 1, i32 2, i32 %a0, i64 undef, double %a1.coerce0, i64 %a1.coerce1, i64 %a1.coerce2, i64 %a1.coerce3, double %a2.coerce0, i64 %a2.coerce1, i64 %a2.coerce2, i64 %a2.coerce3, i32 3, i64 undef, double %a3.coerce0, i64 %a3.coerce1, i64 %a3.coerce2, i64 %a3.coerce3)
+// N64: declare void @foo2(i32, i32, i32, i64, double, i64, i64, i64, double, i64, i64, i64, i32, i64, double, i64, i64, i64)
extern void foo2(int, int, int, S0, S0, int, S0);
@@ -19,9 +20,9 @@ void foo1(int a0, S0 a1, S0 a2, int b, S0 a3) {
// Insert padding before long double argument.
//
-// CHECK: define void @foo3(i32 %a0, i64, fp128 %a1)
-// CHECK: tail call void @foo4(i32 1, i32 2, i32 %a0, i64 undef, fp128 %a1)
-// CHECK: declare void @foo4(i32, i32, i32, i64, fp128)
+// N64: define void @foo3(i32 %a0, i64, fp128 %a1)
+// N64: tail call void @foo4(i32 1, i32 2, i32 %a0, i64 undef, fp128 %a1)
+// N64: declare void @foo4(i32, i32, i32, i64, fp128)
extern void foo4(int, int, int, long double);
@@ -31,9 +32,9 @@ void foo3(int a0, long double a1) {
// Insert padding after hidden argument.
//
-// CHECK: define void @foo5(%struct.S0* noalias sret %agg.result, i64, fp128 %a0)
-// CHECK: call void @foo6(%struct.S0* sret %agg.result, i32 1, i32 2, i64 undef, fp128 %a0)
-// CHECK: declare void @foo6(%struct.S0* sret, i32, i32, i64, fp128)
+// N64: define void @foo5(%struct.S0* noalias sret %agg.result, i64, fp128 %a0)
+// N64: call void @foo6(%struct.S0* sret %agg.result, i32 1, i32 2, i64 undef, fp128 %a0)
+// N64: declare void @foo6(%struct.S0* sret, i32, i32, i64, fp128)
extern S0 foo6(int, int, long double);
@@ -41,3 +42,14 @@ S0 foo5(long double a0) {
return foo6(1, 2, a0);
}
+// Do not insert padding if ABI is O32.
+//
+// O32: define void @foo7(float %a0, double %a1)
+// O32: declare void @foo8(float, double)
+
+extern void foo8(float, double);
+
+void foo7(float a0, double a1) {
+ foo8(a0 + 1.0f, a1 + 2.0);
+}
+
diff --git a/test/CodeGen/mrtd.c b/test/CodeGen/mrtd.c
index d7729a5..a40a59a 100644
--- a/test/CodeGen/mrtd.c
+++ b/test/CodeGen/mrtd.c
@@ -2,7 +2,7 @@
void baz(int arg);
-// CHECK: define x86_stdcallcc void @foo(i32 %arg) nounwind
+// CHECK: define x86_stdcallcc void @foo(i32 %arg) [[NUW:#[0-9]+]]
void foo(int arg) {
// CHECK: call x86_stdcallcc i32 bitcast (i32 (...)* @bar to i32 (i32)*)(
bar(arg);
@@ -13,3 +13,5 @@ void foo(int arg) {
// CHECK: declare x86_stdcallcc i32 @bar(...)
// CHECK: declare x86_stdcallcc void @baz(i32)
+
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGen/ms-declspecs.c b/test/CodeGen/ms-declspecs.c
index 91862a7..26bdc58 100644
--- a/test/CodeGen/ms-declspecs.c
+++ b/test/CodeGen/ms-declspecs.c
@@ -8,17 +8,21 @@ union { struct S s; } u;
// CHECK: @u = {{.*}}zeroinitializer, align 16
-// CHECK: define void @t3() nounwind noinline naked {
+// CHECK: define void @t3() [[NAKED:#[0-9]+]] {
__declspec(naked) void t3() {}
-// CHECK: define void @t22() nounwind
+// CHECK: define void @t22() [[NUW:#[0-9]+]]
void __declspec(nothrow) t22();
void t22() {}
-// CHECK: define void @t2() nounwind noinline {
+// CHECK: define void @t2() [[NI:#[0-9]+]] {
__declspec(noinline) void t2() {}
-// CHECK: call void @f20_t()
-// CHECK: noreturn
+// CHECK: call void @f20_t() [[NR:#[0-9]+]]
__declspec(noreturn) void f20_t(void);
void f20(void) { f20_t(); }
+
+// CHECK: attributes [[NAKED]] = { naked noinline nounwind{{.*}} }
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
+// CHECK: attributes [[NI]] = { noinline nounwind{{.*}} }
+// CHECK: attributes [[NR]] = { noreturn }
diff --git a/test/CodeGen/ms-inline-asm-64.c b/test/CodeGen/ms-inline-asm-64.c
index a74ede0..8d2940d 100644
--- a/test/CodeGen/ms-inline-asm-64.c
+++ b/test/CodeGen/ms-inline-asm-64.c
@@ -1,16 +1,18 @@
// 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
+// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -O0 -fasm-blocks -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
+// CHECK: call void asm sideeffect inteldialect "mov rax, $0", "r,~{rax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}) [[NUW:#[0-9]+]]
}
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
+// CHECK: call void asm sideeffect inteldialect "mov [eax], $0", "r,~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}) [[NUW]]
}
+
+// CHECK: attributes [[NUW]] = { nounwind }
diff --git a/test/CodeGen/ms-inline-asm.c b/test/CodeGen/ms-inline-asm.c
index 7f43da8..d50ecfe 100644
--- a/test/CodeGen/ms-inline-asm.c
+++ b/test/CodeGen/ms-inline-asm.c
@@ -1,18 +1,18 @@
// 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
+// RUN: %clang_cc1 %s -triple i386-apple-darwin10 -O0 -fasm-blocks -emit-llvm -o - | FileCheck %s
void t1() {
// CHECK: @t1
-// CHECK: call void asm sideeffect inteldialect "", "~{dirflag},~{fpsr},~{flags}"() nounwind
+// CHECK: call void asm sideeffect inteldialect "", "~{dirflag},~{fpsr},~{flags}"()
// CHECK: ret void
__asm {}
}
void t2() {
// CHECK: @t2
-// 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: call void asm sideeffect inteldialect "nop", "~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "nop", "~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "nop", "~{dirflag},~{fpsr},~{flags}"()
// CHECK: ret void
__asm nop
__asm nop
@@ -21,15 +21,15 @@ void t2() {
void t3() {
// CHECK: @t3
-// CHECK: call void asm sideeffect inteldialect "nop\0A\09nop\0A\09nop", "~{dirflag},~{fpsr},~{flags}"() nounwind
+// CHECK: call void asm sideeffect inteldialect "nop\0A\09nop\0A\09nop", "~{dirflag},~{fpsr},~{flags}"()
// CHECK: ret void
__asm nop __asm nop __asm nop
}
void t4(void) {
// CHECK: @t4
-// 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: call void asm sideeffect inteldialect "mov ebx, eax", "~{ebx},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "mov ecx, ebx", "~{ecx},~{dirflag},~{fpsr},~{flags}"()
// CHECK: ret void
__asm mov ebx, eax
__asm mov ecx, ebx
@@ -37,7 +37,7 @@ void t4(void) {
void t5(void) {
// CHECK: @t5
-// CHECK: call void asm sideeffect inteldialect "mov ebx, eax\0A\09mov ecx, ebx", "~{ebx},~{ecx},~{dirflag},~{fpsr},~{flags}"() nounwind
+// CHECK: call void asm sideeffect inteldialect "mov ebx, eax\0A\09mov ecx, ebx", "~{ebx},~{ecx},~{dirflag},~{fpsr},~{flags}"()
// CHECK: ret void
__asm mov ebx, eax __asm mov ecx, ebx
}
@@ -45,7 +45,7 @@ void t5(void) {
void t6(void) {
__asm int 0x2c
// CHECK: t6
-// CHECK: call void asm sideeffect inteldialect "int $$0x2c", "~{dirflag},~{fpsr},~{flags}"() nounwind
+// CHECK: call void asm sideeffect inteldialect "int $$0x2c", "~{dirflag},~{fpsr},~{flags}"()
}
void t7() {
@@ -54,8 +54,8 @@ void t7() {
}
__asm {}
// CHECK: t7
-// CHECK: call void asm sideeffect inteldialect "int $$0x2c", "~{dirflag},~{fpsr},~{flags}"() nounwind
-// CHECK: call void asm sideeffect inteldialect "", "~{dirflag},~{fpsr},~{flags}"() nounwind
+// CHECK: call void asm sideeffect inteldialect "int $$0x2c", "~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "", "~{dirflag},~{fpsr},~{flags}"()
}
int t8() {
@@ -64,9 +64,9 @@ int t8() {
__asm int 4
return 10;
// 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: call void asm sideeffect inteldialect "int $$4", "~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "", "~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "int $$4", "~{dirflag},~{fpsr},~{flags}"()
// CHECK: ret i32 10
}
@@ -77,7 +77,7 @@ void t9() {
pop ebx
}
// CHECK: t9
-// CHECK: call void asm sideeffect inteldialect "push ebx\0A\09mov ebx, $$0x07\0A\09pop ebx", "~{ebx},~{dirflag},~{fpsr},~{flags}"() nounwind
+// CHECK: call void asm sideeffect inteldialect "push ebx\0A\09mov ebx, $$0x07\0A\09pop ebx", "~{ebx},~{dirflag},~{fpsr},~{flags}"()
}
unsigned t10(void) {
@@ -91,7 +91,7 @@ unsigned t10(void) {
// CHECK: [[I:%[a-zA-Z0-9]+]] = alloca i32, align 4
// CHECK: [[J:%[a-zA-Z0-9]+]] = alloca i32, align 4
// CHECK: store i32 1, i32* [[I]], align 4
-// CHECK: call 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: call void asm sideeffect inteldialect "mov eax, dword ptr $1\0A\09mov dword ptr $0, eax", "=*m,*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}, i32* %{{.*}})
// CHECK: [[RET:%[a-zA-Z0-9]+]] = load i32* [[J]], align 4
// CHECK: ret i32 [[RET]]
}
@@ -99,7 +99,7 @@ unsigned t10(void) {
void t11(void) {
__asm mov eax, 1
// CHECK: t11
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$1", "~{eax},~{dirflag},~{fpsr},~{flags}"() nounwind
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$1", "~{eax},~{dirflag},~{fpsr},~{flags}"()
}
unsigned t12(void) {
@@ -112,7 +112,7 @@ unsigned t12(void) {
}
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
+// 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* %{{.*}})
}
void t13() {
@@ -121,8 +121,8 @@ void t13() {
__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
+// CHECK: call void asm sideeffect inteldialect "movzx eax, byte ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i8* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "movzx eax, word ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i16* %{{.*}})
}
void t14() {
@@ -135,33 +135,38 @@ void t14() {
.endif
}
// CHECK: t14
-// CHECK: call void asm sideeffect inteldialect ".if 1\0A\09mov eax, dword ptr $0\0A\09.else\0A\09mov ebx, j\0A\09.endif", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}}) nounwind
+// 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* %{{.*}})
}
+int gvar = 10;
void t15() {
- int var = 10;
- __asm mov eax, var ; eax = 10
- __asm mov eax, offset var ; eax = address of myvar
+ int lvar = 10;
+ __asm mov eax, lvar ; eax = 10
+ __asm mov eax, offset lvar ; eax = address of lvar
+ __asm mov eax, offset gvar ; eax = address of gvar
// 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
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0", "r,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, $0", "r,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* @{{.*}})
}
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
+// CHECK: call void asm sideeffect inteldialect "mov [eax], $0", "r,~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
}
void t17() {
__asm _emit 0x4A
__asm _emit 0x43
__asm _emit 0x4B
+ __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
+// CHECK: call void asm sideeffect inteldialect ".byte 0x4A", "~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect ".byte 0x43", "~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect ".byte 0x4B", "~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect ".byte 0x4B", "~{dirflag},~{fpsr},~{flags}"()
}
struct t18_type { int a, b; };
@@ -177,7 +182,7 @@ int t18() {
}
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
+// CHECK: call void asm sideeffect inteldialect "lea ebx, qword ptr foo\0A\09mov eax, [ebx].0\0A\09mov [ebx].4, ecx", "~{eax},~{dirflag},~{fpsr},~{flags}"()
}
int t19() {
@@ -191,12 +196,197 @@ int t19() {
}
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
+// CHECK: call void asm sideeffect inteldialect "lea ebx, qword ptr foo\0A\09mov eax, [ebx].0\0A\09mov [ebx].4, ecx", "~{eax},~{dirflag},~{fpsr},~{flags}"()
}
void t20() {
+ char bar;
int foo;
- __asm mov eax, TYPE foo
+ char _bar[2];
+ int _foo[4];
+
+ __asm mov eax, LENGTH foo
+ __asm mov eax, LENGTH bar
+ __asm mov eax, LENGTH _foo
+ __asm mov eax, LENGTH _bar
// CHECK: t20
-// CHECK: call void asm sideeffect inteldialect "mov eax, $$4", "~{eax},~{dirflag},~{fpsr},~{flags}"() nounwind
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$1", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$1", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$4", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$2", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+
+ __asm mov eax, TYPE foo
+ __asm mov eax, TYPE bar
+ __asm mov eax, TYPE _foo
+ __asm mov eax, TYPE _bar
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$4", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$1", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$4", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$1", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+
+ __asm mov eax, SIZE foo
+ __asm mov eax, SIZE bar
+ __asm mov eax, SIZE _foo
+ __asm mov eax, SIZE _bar
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$4", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$1", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$16", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$2", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+}
+
+void t21() {
+ __asm {
+ __asm push ebx
+ __asm mov ebx, 0x07
+ __asm pop ebx
+ }
+// CHECK: t21
+// CHECK: call void asm sideeffect inteldialect "push ebx\0A\09mov ebx, $$0x07\0A\09pop ebx", "~{ebx},~{dirflag},~{fpsr},~{flags}"()
+}
+
+extern void t22_helper(int x);
+void t22() {
+ int x = 0;
+ __asm {
+ __asm push ebx
+ __asm mov ebx, esp
+ }
+ t22_helper(x);
+ __asm {
+ __asm mov esp, ebx
+ __asm pop ebx
+ }
+// CHECK: t22
+// CHECK: call void asm sideeffect inteldialect "push ebx\0A\09mov ebx, esp", "~{ebx},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void @t22_helper
+// CHECK: call void asm sideeffect inteldialect "mov esp, ebx\0A\09pop ebx", "~{ebx},~{esp},~{dirflag},~{fpsr},~{flags}"()
+}
+
+void t23() {
+ __asm {
+ the_label:
+ }
+// CHECK: t23
+// CHECK: call void asm sideeffect inteldialect "the_label:", "~{dirflag},~{fpsr},~{flags}"()
+}
+
+void t24_helper(void) {}
+void t24() {
+ __asm call t24_helper
+// CHECK: t24
+// CHECK: call void asm sideeffect inteldialect "call $0", "r,~{dirflag},~{fpsr},~{flags}"(void ()* @t24_helper)
+}
+
+void t25() {
+ __asm mov eax, 0ffffffffh
+ __asm mov eax, 0fh
+ __asm mov eax, 0a2h
+ __asm mov eax, 0xa2h
+ __asm mov eax, 0xa2
+// CHECK: t25
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$0ffffffffh", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$0fh", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$0a2h", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$0xa2h", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$0xa2", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+}
+
+void t26() {
+ __asm pushad
+ __asm mov eax, 0
+ __asm __emit 0fh
+ __asm __emit 0a2h
+ __asm __EMIT 0a2h
+ __asm popad
+// CHECK: t26
+// CHECK: call void asm sideeffect inteldialect "pushad", "~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "mov eax, $$0", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect ".byte 0fh", "~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect ".byte 0a2h", "~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect ".byte 0a2h", "~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "popad", "~{dirflag},~{fpsr},~{flags}"()
+}
+
+void t27() {
+ __asm mov eax, fs:[0h]
+// CHECK: t27
+// CHECK: call void asm sideeffect inteldialect "mov eax, fs:[0h]", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+}
+
+void t28() {
+ __asm align 8
+ __asm align 16;
+ __asm align 128;
+ __asm ALIGN 256;
+// CHECK: t28
+// CHECK: call void asm sideeffect inteldialect ".align 3", "~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect ".align 4", "~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect ".align 7", "~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect ".align 8", "~{dirflag},~{fpsr},~{flags}"()
+}
+
+void t29() {
+ int arr[2] = {0, 0};
+ int olen = 0, osize = 0, otype = 0;
+ __asm mov olen, LENGTH arr
+ __asm mov osize, SIZE arr
+ __asm mov otype, TYPE arr
+// CHECK: t29
+// CHECK: call void asm sideeffect inteldialect "mov dword ptr $0, $$2", "=*m,~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov dword ptr $0, $$8", "=*m,~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov dword ptr $0, $$4", "=*m,~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+}
+
+int results[2] = {13, 37};
+int *t30()
+{
+ int *res;
+ __asm lea edi, results
+ __asm mov res, edi
+ return res;
+// CHECK: t30
+// CHECK: call void asm sideeffect inteldialect "lea edi, dword ptr $0", "*m,~{edi},~{dirflag},~{fpsr},~{flags}"([2 x i32]* @{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov dword ptr $0, edi", "=*m,~{dirflag},~{fpsr},~{flags}"(i32** %{{.*}})
+}
+
+void t31() {
+ __asm pushad
+ __asm popad
+// CHECK: t31
+// CHECK: call void asm sideeffect inteldialect "pushad", "~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "popad", "~{dirflag},~{fpsr},~{flags}"()
+}
+
+void t32() {
+ int i;
+ __asm mov eax, i
+ __asm mov eax, dword ptr i
+ __asm mov ax, word ptr i
+ __asm mov al, byte ptr i
+// CHECK: t32
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov ax, word ptr $0", "*m,~{ax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov al, byte ptr $0", "*m,~{al},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+}
+
+void t33() {
+ int i;
+ __asm mov eax, [i]
+ __asm mov eax, dword ptr [i]
+ __asm mov ax, word ptr [i]
+ __asm mov al, byte ptr [i]
+// CHECK: t33
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $0", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov ax, word ptr $0", "*m,~{ax},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+// CHECK: call void asm sideeffect inteldialect "mov al, byte ptr $0", "*m,~{al},~{dirflag},~{fpsr},~{flags}"(i32* %{{.*}})
+}
+
+void t34() {
+ __asm prefetchnta 64[eax]
+ __asm mov eax, dword ptr 4[eax]
+// CHECK: t34
+// CHECK: call void asm sideeffect inteldialect "prefetchnta $$64[eax]", "~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr $$4[eax]", "~{eax},~{dirflag},~{fpsr},~{flags}"()
}
diff --git a/test/CodeGen/ms-inline-asm.cpp b/test/CodeGen/ms-inline-asm.cpp
new file mode 100644
index 0000000..9c160be
--- /dev/null
+++ b/test/CodeGen/ms-inline-asm.cpp
@@ -0,0 +1,26 @@
+// REQUIRES: x86-64-registered-target
+// RUN: %clang_cc1 -x c++ %s -triple i386-apple-darwin10 -O0 -fasm-blocks -emit-llvm -o - | FileCheck %s
+
+struct Foo {
+ static int *ptr;
+ static int a, b;
+ struct Bar {
+ static int *ptr;
+ };
+};
+
+void t1() {
+ Foo::ptr = (int *)0xDEADBEEF;
+ Foo::Bar::ptr = (int *)0xDEADBEEF;
+ __asm mov eax, Foo::ptr
+ __asm mov eax, Foo::Bar::ptr
+ __asm mov eax, [Foo::ptr]
+ __asm mov eax, dword ptr [Foo::ptr]
+ __asm mov eax, dword ptr [Foo::ptr]
+// CHECK: @_Z2t1v
+// CHECK: call void asm sideeffect inteldialect "mov eax, Foo::ptr", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "mov eax, Foo::Bar::ptr", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "mov eax, [Foo::ptr]", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr [Foo::ptr]", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+// CHECK: call void asm sideeffect inteldialect "mov eax, dword ptr [Foo::ptr]", "~{eax},~{dirflag},~{fpsr},~{flags}"()
+}
diff --git a/test/CodeGen/mult-alt-generic.c b/test/CodeGen/mult-alt-generic.c
index 1665f9c..6cf6f0a 100644
--- a/test/CodeGen/mult-alt-generic.c
+++ b/test/CodeGen/mult-alt-generic.c
@@ -1,7 +1,6 @@
// RUN: %clang_cc1 -triple i686 %s -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -triple x86_64 %s -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -triple arm %s -emit-llvm -o - | FileCheck %s
-// RUN: %clang_cc1 -triple cellspu %s -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -triple mblaze %s -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -triple mips %s -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 -triple mipsel %s -emit-llvm -o - | FileCheck %s
diff --git a/test/CodeGen/no-opt-volatile-memcpy.c b/test/CodeGen/no-opt-volatile-memcpy.c
new file mode 100644
index 0000000..0fab363
--- /dev/null
+++ b/test/CodeGen/no-opt-volatile-memcpy.c
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -O0 -triple=x86_64-apple-darwin -emit-llvm -o - %s | FileCheck %s
+// rdar://11861085
+
+struct s {
+ char filler [128];
+ volatile int x;
+};
+
+struct s gs;
+
+void foo (void) {
+ struct s ls;
+ ls = ls;
+ gs = gs;
+ ls = gs;
+}
+// CHECK: define void @foo()
+// CHECK: %[[LS:.*]] = alloca %struct.s, align 4
+// CHECK-NEXT: %[[ZERO:.*]] = bitcast %struct.s* %[[LS]] to i8*
+// CHECK-NEXT: %[[ONE:.*]] = bitcast %struct.s* %[[LS]] to i8*
+// CHECK-NEXT: call void @llvm.memcpy.{{.*}}(i8* %[[ZERO]], i8* %[[ONE]], i64 132, i32 4, i1 true)
+// CHECK-NEXT: call void @llvm.memcpy.{{.*}}(i8* getelementptr inbounds (%struct.s* @gs, i32 0, i32 0, i32 0), i8* getelementptr inbounds (%struct.s* @gs, i32 0, i32 0, i32 0), i64 132, i32 4, i1 true)
+// CHECK-NEXT: %[[TWO:.*]] = bitcast %struct.s* %[[LS]] to i8*
+// CHECK-NEXT: call void @llvm.memcpy.{{.*}}(i8* %[[TWO]], i8* getelementptr inbounds (%struct.s* @gs, i32 0, i32 0, i32 0), i64 132, i32 4, i1 true)
+
+
+struct s1 {
+ struct s y;
+};
+
+struct s1 s;
+
+void fee (void) {
+ s = s;
+ s.y = gs;
+}
+// CHECK: define void @fee()
+// CHECK: call void @llvm.memcpy.{{.*}}(i8* getelementptr inbounds (%struct.s1* @s, i32 0, i32 0, i32 0, i32 0), i8* getelementptr inbounds (%struct.s1* @s, i32 0, i32 0, i32 0, i32 0), i64 132, i32 4, i1 true)
+// CHECK-NEXT: call void @llvm.memcpy.{{.*}}(i8* getelementptr inbounds (%struct.s1* @s, i32 0, i32 0, i32 0, i32 0), i8* getelementptr inbounds (%struct.s* @gs, i32 0, i32 0, i32 0), i64 132, i32 4, i1 true)
+
diff --git a/test/CodeGen/nvptx-cpus.c b/test/CodeGen/nvptx-cpus.c
new file mode 100644
index 0000000..c9c7680
--- /dev/null
+++ b/test/CodeGen/nvptx-cpus.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -triple nvptx-unknown-unknown -target-cpu sm_20 -O3 -S -o %t %s -emit-llvm
+// RUN: %clang_cc1 -triple nvptx-unknown-unknown -target-cpu sm_21 -O3 -S -o %t %s -emit-llvm
+// RUN: %clang_cc1 -triple nvptx-unknown-unknown -target-cpu sm_30 -O3 -S -o %t %s -emit-llvm
+// RUN: %clang_cc1 -triple nvptx-unknown-unknown -target-cpu sm_35 -O3 -S -o %t %s -emit-llvm
+
+// Make sure clang accepts all supported architectures.
+
+void foo(float* a,
+ float* b) {
+ a[0] = b[0];
+}
diff --git a/test/CodeGen/packed-nest-unpacked.c b/test/CodeGen/packed-nest-unpacked.c
index 6097e3f..7f486c9 100644
--- a/test/CodeGen/packed-nest-unpacked.c
+++ b/test/CodeGen/packed-nest-unpacked.c
@@ -60,6 +60,6 @@ struct YBitfield gbitfield;
unsigned test7() {
// CHECK: @test7
- // CHECK: load i32* bitcast (%struct.XBitfield* getelementptr inbounds (%struct.YBitfield* @gbitfield, i32 0, i32 1) to i32*), align 1
+ // CHECK: load i32* bitcast (%struct.XBitfield* getelementptr inbounds (%struct.YBitfield* @gbitfield, i32 0, i32 1) to i32*), align 4
return gbitfield.y.b2;
}
diff --git a/test/CodeGen/packed-structure.c b/test/CodeGen/packed-structure.c
index 3aeaa23..ffd98db 100644
--- a/test/CodeGen/packed-structure.c
+++ b/test/CodeGen/packed-structure.c
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -triple x86_64 -emit-llvm -o - %s | opt -S -strip -o %t
-// RUX: llvm-gcc -flto -S -O3 -o %t %s
// RUN: FileCheck --check-prefix=CHECK-GLOBAL < %t %s
// RUN: FileCheck --check-prefix=CHECK-FUNCTIONS < %t %s
diff --git a/test/CodeGen/parameter-passing.c b/test/CodeGen/parameter-passing.c
index e48815b..40610af 100644
--- a/test/CodeGen/parameter-passing.c
+++ b/test/CodeGen/parameter-passing.c
@@ -5,14 +5,10 @@
// We also check _Bool and empty structures, as these can have annoying
// corner cases.
-// RUN: %clang_cc1 %s -triple i386-unknown-unknown -O3 -emit-llvm -o %t
-// RUN: not grep '@g0' %t
-
-// RUN: %clang_cc1 %s -triple x86_64-unknown-unknown -O3 -emit-llvm -o %t
-// RUN: not grep '@g0' %t
-
-// RUN: %clang_cc1 %s -triple powerpc-unknown-unknown -O3 -emit-llvm -o %t
-// RUN: not grep '@g0' %t
+// RUN: %clang_cc1 %s -triple i386-unknown-unknown -O3 -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple x86_64-unknown-unknown -O3 -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple powerpc-unknown-unknown -O3 -emit-llvm -o - | FileCheck %s
+// CHECK-NOT: @g0
typedef _Bool BoolTy;
typedef int ScalarTy;
diff --git a/test/CodeGen/ppc-atomics.c b/test/CodeGen/ppc-atomics.c
deleted file mode 100644
index 3fcb0fb..0000000
--- a/test/CodeGen/ppc-atomics.c
+++ /dev/null
@@ -1,35 +0,0 @@
-// 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-complex-parms.c b/test/CodeGen/ppc64-complex-parms.c
new file mode 100644
index 0000000..92a6fa5
--- /dev/null
+++ b/test/CodeGen/ppc64-complex-parms.c
@@ -0,0 +1,184 @@
+// REQUIRES: ppc64-registered-target
+// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+float crealf(_Complex float);
+double creal(_Complex double);
+long double creall(_Complex long double);
+
+float foo_float(_Complex float x) {
+ return crealf(x);
+}
+
+// CHECK: define float @foo_float(float {{[%A-Za-z0-9.]+}}, float {{[%A-Za-z0-9.]+}}) [[NUW:#[0-9]+]] {
+
+double foo_double(_Complex double x) {
+ return creal(x);
+}
+
+// CHECK: define double @foo_double(double {{[%A-Za-z0-9.]+}}, double {{[%A-Za-z0-9.]+}}) [[NUW]] {
+
+long double foo_long_double(_Complex long double x) {
+ return creall(x);
+}
+
+// CHECK: define ppc_fp128 @foo_long_double(ppc_fp128 {{[%A-Za-z0-9.]+}}, ppc_fp128 {{[%A-Za-z0-9.]+}}) [[NUW]] {
+
+int foo_int(_Complex int x) {
+ return __real__ x;
+}
+
+// CHECK: define signext i32 @foo_int(i32 {{[%A-Za-z0-9.]+}}, i32 {{[%A-Za-z0-9.]+}}) [[NUW]] {
+
+short foo_short(_Complex short x) {
+ return __real__ x;
+}
+
+// CHECK: define signext i16 @foo_short(i16 {{[%A-Za-z0-9.]+}}, i16 {{[%A-Za-z0-9.]+}}) [[NUW]] {
+
+signed char foo_char(_Complex signed char x) {
+ return __real__ x;
+}
+
+// CHECK: define signext i8 @foo_char(i8 {{[%A-Za-z0-9.]+}}, i8 {{[%A-Za-z0-9.]+}}) [[NUW]] {
+
+long foo_long(_Complex long x) {
+ return __real__ x;
+}
+
+// CHECK: define i64 @foo_long(i64 {{[%A-Za-z0-9.]+}}, i64 {{[%A-Za-z0-9.]+}}) [[NUW]] {
+
+long long foo_long_long(_Complex long long x) {
+ return __real__ x;
+}
+
+// CHECK: define i64 @foo_long_long(i64 {{[%A-Za-z0-9.]+}}, i64 {{[%A-Za-z0-9.]+}}) [[NUW]] {
+
+void bar_float(void) {
+ foo_float(2.0f - 2.5fi);
+}
+
+// CHECK: define void @bar_float() [[NUW]] {
+// CHECK: %[[VAR1:[A-Za-z0-9.]+]] = alloca { float, float }, align 4
+// CHECK: %[[VAR2:[A-Za-z0-9.]+]] = getelementptr inbounds { float, float }* %[[VAR1]], i32 0, i32 0
+// CHECK: %[[VAR3:[A-Za-z0-9.]+]] = getelementptr inbounds { float, float }* %[[VAR1]], i32 0, i32 1
+// CHECK: store float 2.000000e+00, float* %[[VAR2]]
+// CHECK: store float -2.500000e+00, float* %[[VAR3]]
+// CHECK: %[[VAR4:[A-Za-z0-9.]+]] = getelementptr { float, float }* %[[VAR1]], i32 0, i32 0
+// CHECK: %[[VAR5:[A-Za-z0-9.]+]] = load float* %[[VAR4]], align 1
+// CHECK: %[[VAR6:[A-Za-z0-9.]+]] = getelementptr { float, float }* %[[VAR1]], i32 0, i32 1
+// CHECK: %[[VAR7:[A-Za-z0-9.]+]] = load float* %[[VAR6]], align 1
+// CHECK: %{{[A-Za-z0-9.]+}} = call float @foo_float(float %[[VAR5]], float %[[VAR7]])
+
+void bar_double(void) {
+ foo_double(2.0 - 2.5i);
+}
+
+// CHECK: define void @bar_double() [[NUW]] {
+// CHECK: %[[VAR11:[A-Za-z0-9.]+]] = alloca { double, double }, align 8
+// CHECK: %[[VAR12:[A-Za-z0-9.]+]] = getelementptr inbounds { double, double }* %[[VAR11]], i32 0, i32 0
+// CHECK: %[[VAR13:[A-Za-z0-9.]+]] = getelementptr inbounds { double, double }* %[[VAR11]], i32 0, i32 1
+// CHECK: store double 2.000000e+00, double* %[[VAR12]]
+// CHECK: store double -2.500000e+00, double* %[[VAR13]]
+// CHECK: %[[VAR14:[A-Za-z0-9.]+]] = getelementptr { double, double }* %[[VAR11]], i32 0, i32 0
+// CHECK: %[[VAR15:[A-Za-z0-9.]+]] = load double* %[[VAR14]], align 1
+// CHECK: %[[VAR16:[A-Za-z0-9.]+]] = getelementptr { double, double }* %[[VAR11]], i32 0, i32 1
+// CHECK: %[[VAR17:[A-Za-z0-9.]+]] = load double* %[[VAR16]], align 1
+// CHECK: %{{[A-Za-z0-9.]+}} = call double @foo_double(double %[[VAR15]], double %[[VAR17]])
+
+void bar_long_double(void) {
+ foo_long_double(2.0L - 2.5Li);
+}
+
+// CHECK: define void @bar_long_double() [[NUW]] {
+// CHECK: %[[VAR21:[A-Za-z0-9.]+]] = alloca { ppc_fp128, ppc_fp128 }, align 16
+// CHECK: %[[VAR22:[A-Za-z0-9.]+]] = getelementptr inbounds { ppc_fp128, ppc_fp128 }* %[[VAR21]], i32 0, i32 0
+// CHECK: %[[VAR23:[A-Za-z0-9.]+]] = getelementptr inbounds { ppc_fp128, ppc_fp128 }* %[[VAR21]], i32 0, i32 1
+// CHECK: store ppc_fp128 0xM40000000000000000000000000000000, ppc_fp128* %[[VAR22]]
+// CHECK: store ppc_fp128 0xMC0040000000000000000000000000000, ppc_fp128* %[[VAR23]]
+// CHECK: %[[VAR24:[A-Za-z0-9.]+]] = getelementptr { ppc_fp128, ppc_fp128 }* %[[VAR21]], i32 0, i32 0
+// CHECK: %[[VAR25:[A-Za-z0-9.]+]] = load ppc_fp128* %[[VAR24]], align 1
+// CHECK: %[[VAR26:[A-Za-z0-9.]+]] = getelementptr { ppc_fp128, ppc_fp128 }* %[[VAR21]], i32 0, i32 1
+// CHECK: %[[VAR27:[A-Za-z0-9.]+]] = load ppc_fp128* %[[VAR26]], align 1
+// CHECK: %{{[A-Za-z0-9.]+}} = call ppc_fp128 @foo_long_double(ppc_fp128 %[[VAR25]], ppc_fp128 %[[VAR27]])
+
+void bar_int(void) {
+ foo_int(2 - 3i);
+}
+
+// CHECK: define void @bar_int() [[NUW]] {
+// CHECK: %[[VAR31:[A-Za-z0-9.]+]] = alloca { i32, i32 }, align 4
+// CHECK: %[[VAR32:[A-Za-z0-9.]+]] = getelementptr inbounds { i32, i32 }* %[[VAR31]], i32 0, i32 0
+// CHECK: %[[VAR33:[A-Za-z0-9.]+]] = getelementptr inbounds { i32, i32 }* %[[VAR31]], i32 0, i32 1
+// CHECK: store i32 2, i32* %[[VAR32]]
+// CHECK: store i32 -3, i32* %[[VAR33]]
+// CHECK: %[[VAR34:[A-Za-z0-9.]+]] = getelementptr { i32, i32 }* %[[VAR31]], i32 0, i32 0
+// CHECK: %[[VAR35:[A-Za-z0-9.]+]] = load i32* %[[VAR34]], align 1
+// CHECK: %[[VAR36:[A-Za-z0-9.]+]] = getelementptr { i32, i32 }* %[[VAR31]], i32 0, i32 1
+// CHECK: %[[VAR37:[A-Za-z0-9.]+]] = load i32* %[[VAR36]], align 1
+// CHECK: %{{[A-Za-z0-9.]+}} = call signext i32 @foo_int(i32 %[[VAR35]], i32 %[[VAR37]])
+
+void bar_short(void) {
+ foo_short(2 - 3i);
+}
+
+// CHECK: define void @bar_short() [[NUW]] {
+// CHECK: %[[VAR41:[A-Za-z0-9.]+]] = alloca { i16, i16 }, align 2
+// CHECK: %[[VAR42:[A-Za-z0-9.]+]] = getelementptr inbounds { i16, i16 }* %[[VAR41]], i32 0, i32 0
+// CHECK: %[[VAR43:[A-Za-z0-9.]+]] = getelementptr inbounds { i16, i16 }* %[[VAR41]], i32 0, i32 1
+// CHECK: store i16 2, i16* %[[VAR42]]
+// CHECK: store i16 -3, i16* %[[VAR43]]
+// CHECK: %[[VAR44:[A-Za-z0-9.]+]] = getelementptr { i16, i16 }* %[[VAR41]], i32 0, i32 0
+// CHECK: %[[VAR45:[A-Za-z0-9.]+]] = load i16* %[[VAR44]], align 1
+// CHECK: %[[VAR46:[A-Za-z0-9.]+]] = getelementptr { i16, i16 }* %[[VAR41]], i32 0, i32 1
+// CHECK: %[[VAR47:[A-Za-z0-9.]+]] = load i16* %[[VAR46]], align 1
+// CHECK: %{{[A-Za-z0-9.]+}} = call signext i16 @foo_short(i16 %[[VAR45]], i16 %[[VAR47]])
+
+void bar_char(void) {
+ foo_char(2 - 3i);
+}
+
+// CHECK: define void @bar_char() [[NUW]] {
+// CHECK: %[[VAR51:[A-Za-z0-9.]+]] = alloca { i8, i8 }, align 1
+// CHECK: %[[VAR52:[A-Za-z0-9.]+]] = getelementptr inbounds { i8, i8 }* %[[VAR51]], i32 0, i32 0
+// CHECK: %[[VAR53:[A-Za-z0-9.]+]] = getelementptr inbounds { i8, i8 }* %[[VAR51]], i32 0, i32 1
+// CHECK: store i8 2, i8* %[[VAR52]]
+// CHECK: store i8 -3, i8* %[[VAR53]]
+// CHECK: %[[VAR54:[A-Za-z0-9.]+]] = getelementptr { i8, i8 }* %[[VAR51]], i32 0, i32 0
+// CHECK: %[[VAR55:[A-Za-z0-9.]+]] = load i8* %[[VAR54]], align 1
+// CHECK: %[[VAR56:[A-Za-z0-9.]+]] = getelementptr { i8, i8 }* %[[VAR51]], i32 0, i32 1
+// CHECK: %[[VAR57:[A-Za-z0-9.]+]] = load i8* %[[VAR56]], align 1
+// CHECK: %{{[A-Za-z0-9.]+}} = call signext i8 @foo_char(i8 %[[VAR55]], i8 %[[VAR57]])
+
+void bar_long(void) {
+ foo_long(2L - 3Li);
+}
+
+// CHECK: define void @bar_long() [[NUW]] {
+// CHECK: %[[VAR61:[A-Za-z0-9.]+]] = alloca { i64, i64 }, align 8
+// CHECK: %[[VAR62:[A-Za-z0-9.]+]] = getelementptr inbounds { i64, i64 }* %[[VAR61]], i32 0, i32 0
+// CHECK: %[[VAR63:[A-Za-z0-9.]+]] = getelementptr inbounds { i64, i64 }* %[[VAR61]], i32 0, i32 1
+// CHECK: store i64 2, i64* %[[VAR62]]
+// CHECK: store i64 -3, i64* %[[VAR63]]
+// CHECK: %[[VAR64:[A-Za-z0-9.]+]] = getelementptr { i64, i64 }* %[[VAR61]], i32 0, i32 0
+// CHECK: %[[VAR65:[A-Za-z0-9.]+]] = load i64* %[[VAR64]], align 1
+// CHECK: %[[VAR66:[A-Za-z0-9.]+]] = getelementptr { i64, i64 }* %[[VAR61]], i32 0, i32 1
+// CHECK: %[[VAR67:[A-Za-z0-9.]+]] = load i64* %[[VAR66]], align 1
+// CHECK: %{{[A-Za-z0-9.]+}} = call i64 @foo_long(i64 %[[VAR65]], i64 %[[VAR67]])
+
+void bar_long_long(void) {
+ foo_long_long(2LL - 3LLi);
+}
+
+// CHECK: define void @bar_long_long() [[NUW]] {
+// CHECK: %[[VAR71:[A-Za-z0-9.]+]] = alloca { i64, i64 }, align 8
+// CHECK: %[[VAR72:[A-Za-z0-9.]+]] = getelementptr inbounds { i64, i64 }* %[[VAR71]], i32 0, i32 0
+// CHECK: %[[VAR73:[A-Za-z0-9.]+]] = getelementptr inbounds { i64, i64 }* %[[VAR71]], i32 0, i32 1
+// CHECK: store i64 2, i64* %[[VAR72]]
+// CHECK: store i64 -3, i64* %[[VAR73]]
+// CHECK: %[[VAR74:[A-Za-z0-9.]+]] = getelementptr { i64, i64 }* %[[VAR71]], i32 0, i32 0
+// CHECK: %[[VAR75:[A-Za-z0-9.]+]] = load i64* %[[VAR74]], align 1
+// CHECK: %[[VAR76:[A-Za-z0-9.]+]] = getelementptr { i64, i64 }* %[[VAR71]], i32 0, i32 1
+// CHECK: %[[VAR77:[A-Za-z0-9.]+]] = load i64* %[[VAR76]], align 1
+// CHECK: %{{[A-Za-z0-9.]+}} = call i64 @foo_long_long(i64 %[[VAR75]], i64 %[[VAR77]])
+
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGen/ppc64-complex-return.c b/test/CodeGen/ppc64-complex-return.c
new file mode 100644
index 0000000..b3fd549
--- /dev/null
+++ b/test/CodeGen/ppc64-complex-return.c
@@ -0,0 +1,129 @@
+// REQUIRES: ppc64-registered-target
+// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+float crealf(_Complex float);
+double creal(_Complex double);
+long double creall(_Complex long double);
+
+_Complex float foo_float(_Complex float x) {
+ return x;
+}
+
+// CHECK: define { float, float } @foo_float(float {{[%A-Za-z0-9.]+}}, float {{[%A-Za-z0-9.]+}}) [[NUW:#[0-9]+]] {
+
+_Complex double foo_double(_Complex double x) {
+ return x;
+}
+
+// CHECK: define { double, double } @foo_double(double {{[%A-Za-z0-9.]+}}, double {{[%A-Za-z0-9.]+}}) [[NUW]] {
+
+_Complex long double foo_long_double(_Complex long double x) {
+ return x;
+}
+
+// CHECK: define { ppc_fp128, ppc_fp128 } @foo_long_double(ppc_fp128 {{[%A-Za-z0-9.]+}}, ppc_fp128 {{[%A-Za-z0-9.]+}}) [[NUW]] {
+
+_Complex int foo_int(_Complex int x) {
+ return x;
+}
+
+// CHECK: define { i32, i32 } @foo_int(i32 {{[%A-Za-z0-9.]+}}, i32 {{[%A-Za-z0-9.]+}}) [[NUW]] {
+
+_Complex short foo_short(_Complex short x) {
+ return x;
+}
+
+// CHECK: define { i16, i16 } @foo_short(i16 {{[%A-Za-z0-9.]+}}, i16 {{[%A-Za-z0-9.]+}}) [[NUW]] {
+
+_Complex signed char foo_char(_Complex signed char x) {
+ return x;
+}
+
+// CHECK: define { i8, i8 } @foo_char(i8 {{[%A-Za-z0-9.]+}}, i8 {{[%A-Za-z0-9.]+}}) [[NUW]] {
+
+_Complex long foo_long(_Complex long x) {
+ return x;
+}
+
+// CHECK: define { i64, i64 } @foo_long(i64 {{[%A-Za-z0-9.]+}}, i64 {{[%A-Za-z0-9.]+}}) [[NUW]] {
+
+_Complex long long foo_long_long(_Complex long long x) {
+ return x;
+}
+
+// CHECK: define { i64, i64 } @foo_long_long(i64 {{[%A-Za-z0-9.]+}}, i64 {{[%A-Za-z0-9.]+}}) [[NUW]] {
+
+float bar_float(void) {
+ return crealf(foo_float(2.0f - 2.5fi));
+}
+
+// CHECK: define float @bar_float() [[NUW]] {
+// CHECK: [[VAR1:[%A-Za-z0-9.]+]] = call { float, float } @foo_float
+// CHECK: extractvalue { float, float } [[VAR1]], 0
+// CHECK: extractvalue { float, float } [[VAR1]], 1
+
+double bar_double(void) {
+ return creal(foo_double(2.0 - 2.5i));
+}
+
+// CHECK: define double @bar_double() [[NUW]] {
+// CHECK: [[VAR2:[%A-Za-z0-9.]+]] = call { double, double } @foo_double
+// CHECK: extractvalue { double, double } [[VAR2]], 0
+// CHECK: extractvalue { double, double } [[VAR2]], 1
+
+long double bar_long_double(void) {
+ return creall(foo_long_double(2.0L - 2.5Li));
+}
+
+// CHECK: define ppc_fp128 @bar_long_double() [[NUW]] {
+// CHECK: [[VAR3:[%A-Za-z0-9.]+]] = call { ppc_fp128, ppc_fp128 } @foo_long_double
+// CHECK: extractvalue { ppc_fp128, ppc_fp128 } [[VAR3]], 0
+// CHECK: extractvalue { ppc_fp128, ppc_fp128 } [[VAR3]], 1
+
+int bar_int(void) {
+ return __real__(foo_int(2 - 3i));
+}
+
+// CHECK: define signext i32 @bar_int() [[NUW]] {
+// CHECK: [[VAR4:[%A-Za-z0-9.]+]] = call { i32, i32 } @foo_int
+// CHECK: extractvalue { i32, i32 } [[VAR4]], 0
+// CHECK: extractvalue { i32, i32 } [[VAR4]], 1
+
+short bar_short(void) {
+ return __real__(foo_short(2 - 3i));
+}
+
+// CHECK: define signext i16 @bar_short() [[NUW]] {
+// CHECK: [[VAR5:[%A-Za-z0-9.]+]] = call { i16, i16 } @foo_short
+// CHECK: extractvalue { i16, i16 } [[VAR5]], 0
+// CHECK: extractvalue { i16, i16 } [[VAR5]], 1
+
+signed char bar_char(void) {
+ return __real__(foo_char(2 - 3i));
+}
+
+// CHECK: define signext i8 @bar_char() [[NUW]] {
+// CHECK: [[VAR6:[%A-Za-z0-9.]+]] = call { i8, i8 } @foo_char
+// CHECK: extractvalue { i8, i8 } [[VAR6]], 0
+// CHECK: extractvalue { i8, i8 } [[VAR6]], 1
+
+long bar_long(void) {
+ return __real__(foo_long(2L - 3Li));
+}
+
+// CHECK: define i64 @bar_long() [[NUW]] {
+// CHECK: [[VAR7:[%A-Za-z0-9.]+]] = call { i64, i64 } @foo_long
+// CHECK: extractvalue { i64, i64 } [[VAR7]], 0
+// CHECK: extractvalue { i64, i64 } [[VAR7]], 1
+
+long long bar_long_long(void) {
+ return __real__(foo_long_long(2LL - 3LLi));
+}
+
+// CHECK: define i64 @bar_long_long() [[NUW]] {
+// CHECK: [[VAR8:[%A-Za-z0-9.]+]] = call { i64, i64 } @foo_long_long
+// CHECK: extractvalue { i64, i64 } [[VAR8]], 0
+// CHECK: extractvalue { i64, i64 } [[VAR8]], 1
+
+
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGen/ppc64-extend.c b/test/CodeGen/ppc64-extend.c
index f4d6bf9..68d28c7 100644
--- a/test/CodeGen/ppc64-extend.c
+++ b/test/CodeGen/ppc64-extend.c
@@ -2,14 +2,15 @@
// 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
+// CHECK: define void @f1(i32 signext %x) [[NUW:#[0-9]+]]
void f2(unsigned int x) { return; }
-// CHECK: define void @f2(i32 zeroext %x) nounwind
+// CHECK: define void @f2(i32 zeroext %x) [[NUW]]
int f3(void) { return 0; }
-// CHECK: define signext i32 @f3() nounwind
+// CHECK: define signext i32 @f3() [[NUW]]
unsigned int f4(void) { return 0; }
-// CHECK: define zeroext i32 @f4() nounwind
+// CHECK: define zeroext i32 @f4() [[NUW]]
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGen/ppc64-varargs-complex.c b/test/CodeGen/ppc64-varargs-complex.c
new file mode 100644
index 0000000..b65a773
--- /dev/null
+++ b/test/CodeGen/ppc64-varargs-complex.c
@@ -0,0 +1,73 @@
+// REQUIRES: ppc64-registered-target
+// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+#include <stdarg.h>
+
+void testva (int n, ...)
+{
+ va_list ap;
+
+ _Complex int i = va_arg(ap, _Complex int);
+ // CHECK: %[[VAR40:[A-Za-z0-9.]+]] = load i8** %[[VAR100:[A-Za-z0-9.]+]]
+ // CHECK-NEXT: %[[VAR41:[A-Za-z0-9.]+]] = getelementptr i8* %[[VAR40]], i64 16
+ // CHECK-NEXT: store i8* %[[VAR41]], i8** %[[VAR100]]
+ // CHECK-NEXT: %[[VAR1:[A-Za-z0-9.]+]] = ptrtoint i8* %[[VAR40]] to i64
+ // CHECK-NEXT: %[[VAR2:[A-Za-z0-9.]+]] = add i64 %[[VAR1]], 4
+ // CHECK-NEXT: %[[VAR3:[A-Za-z0-9.]+]] = add i64 %[[VAR1]], 12
+ // CHECK-NEXT: %[[VAR4:[A-Za-z0-9.]+]] = inttoptr i64 %[[VAR2]] to i32*
+ // CHECK-NEXT: %[[VAR5:[A-Za-z0-9.]+]] = inttoptr i64 %[[VAR3]] to i32*
+ // CHECK-NEXT: %[[VAR6:[A-Za-z0-9.]+]] = load i32* %[[VAR4]]
+ // CHECK-NEXT: %[[VAR7:[A-Za-z0-9.]+]] = load i32* %[[VAR5]]
+ // CHECK-NEXT: %[[VAR8:[A-Za-z0-9.]+]] = getelementptr inbounds { i32, i32 }* %[[VAR0:[A-Za-z0-9.]+]], i32 0, i32 0
+ // CHECK-NEXT: %[[VAR9:[A-Za-z0-9.]+]] = getelementptr inbounds { i32, i32 }* %[[VAR0]], i32 0, i32 1
+ // CHECK-NEXT: store i32 %[[VAR6]], i32* %[[VAR8]]
+ // CHECK-NEXT: store i32 %[[VAR7]], i32* %[[VAR9]]
+
+ _Complex short s = va_arg(ap, _Complex short);
+ // CHECK: %[[VAR50:[A-Za-z0-9.]+]] = load i8** %[[VAR100:[A-Za-z0-9.]+]]
+ // CHECK-NEXT: %[[VAR51:[A-Za-z0-9.]+]] = getelementptr i8* %[[VAR50]], i64 16
+ // CHECK-NEXT: store i8* %[[VAR51]], i8** %[[VAR100]]
+ // CHECK: %[[VAR11:[A-Za-z0-9.]+]] = ptrtoint i8* %{{[A-Za-z0-9.]+}} to i64
+ // CHECK-NEXT: %[[VAR12:[A-Za-z0-9.]+]] = add i64 %[[VAR11]], 6
+ // CHECK-NEXT: %[[VAR13:[A-Za-z0-9.]+]] = add i64 %[[VAR11]], 14
+ // CHECK-NEXT: %[[VAR14:[A-Za-z0-9.]+]] = inttoptr i64 %[[VAR12]] to i16*
+ // CHECK-NEXT: %[[VAR15:[A-Za-z0-9.]+]] = inttoptr i64 %[[VAR13]] to i16*
+ // CHECK-NEXT: %[[VAR16:[A-Za-z0-9.]+]] = load i16* %[[VAR14]]
+ // CHECK-NEXT: %[[VAR17:[A-Za-z0-9.]+]] = load i16* %[[VAR15]]
+ // CHECK-NEXT: %[[VAR18:[A-Za-z0-9.]+]] = getelementptr inbounds { i16, i16 }* %[[VAR10:[A-Za-z0-9.]+]], i32 0, i32 0
+ // CHECK-NEXT: %[[VAR19:[A-Za-z0-9.]+]] = getelementptr inbounds { i16, i16 }* %[[VAR10]], i32 0, i32 1
+ // CHECK-NEXT: store i16 %[[VAR16]], i16* %[[VAR18]]
+ // CHECK-NEXT: store i16 %[[VAR17]], i16* %[[VAR19]]
+
+ _Complex char c = va_arg(ap, _Complex char);
+ // CHECK: %[[VAR60:[A-Za-z0-9.]+]] = load i8** %[[VAR100:[A-Za-z0-9.]+]]
+ // CHECK-NEXT: %[[VAR61:[A-Za-z0-9.]+]] = getelementptr i8* %[[VAR60]], i64 16
+ // CHECK-NEXT: store i8* %[[VAR61]], i8** %[[VAR100]]
+ // CHECK: %[[VAR21:[A-Za-z0-9.]+]] = ptrtoint i8* %{{[A-Za-z0-9.]+}} to i64
+ // CHECK-NEXT: %[[VAR22:[A-Za-z0-9.]+]] = add i64 %[[VAR21]], 7
+ // CHECK-NEXT: %[[VAR23:[A-Za-z0-9.]+]] = add i64 %[[VAR21]], 15
+ // CHECK-NEXT: %[[VAR24:[A-Za-z0-9.]+]] = inttoptr i64 %[[VAR22]] to i8*
+ // CHECK-NEXT: %[[VAR25:[A-Za-z0-9.]+]] = inttoptr i64 %[[VAR23]] to i8*
+ // CHECK-NEXT: %[[VAR26:[A-Za-z0-9.]+]] = load i8* %[[VAR24]]
+ // CHECK-NEXT: %[[VAR27:[A-Za-z0-9.]+]] = load i8* %[[VAR25]]
+ // CHECK-NEXT: %[[VAR28:[A-Za-z0-9.]+]] = getelementptr inbounds { i8, i8 }* %[[VAR20:[A-Za-z0-9.]+]], i32 0, i32 0
+ // CHECK-NEXT: %[[VAR29:[A-Za-z0-9.]+]] = getelementptr inbounds { i8, i8 }* %[[VAR20]], i32 0, i32 1
+ // CHECK-NEXT: store i8 %[[VAR26]], i8* %[[VAR28]]
+ // CHECK-NEXT: store i8 %[[VAR27]], i8* %[[VAR29]]
+
+ _Complex float f = va_arg(ap, _Complex float);
+ // CHECK: %[[VAR70:[A-Za-z0-9.]+]] = load i8** %[[VAR100:[A-Za-z0-9.]+]]
+ // CHECK-NEXT: %[[VAR71:[A-Za-z0-9.]+]] = getelementptr i8* %[[VAR70]], i64 16
+ // CHECK-NEXT: store i8* %[[VAR71]], i8** %[[VAR100]]
+ // CHECK: %[[VAR31:[A-Za-z0-9.]+]] = ptrtoint i8* %{{[A-Za-z0-9.]+}} to i64
+ // CHECK-NEXT: %[[VAR32:[A-Za-z0-9.]+]] = add i64 %[[VAR31]], 4
+ // CHECK-NEXT: %[[VAR33:[A-Za-z0-9.]+]] = add i64 %[[VAR31]], 12
+ // CHECK-NEXT: %[[VAR34:[A-Za-z0-9.]+]] = inttoptr i64 %[[VAR32]] to float*
+ // CHECK-NEXT: %[[VAR35:[A-Za-z0-9.]+]] = inttoptr i64 %[[VAR33]] to float*
+ // CHECK-NEXT: %[[VAR36:[A-Za-z0-9.]+]] = load float* %[[VAR34]]
+ // CHECK-NEXT: %[[VAR37:[A-Za-z0-9.]+]] = load float* %[[VAR35]]
+ // CHECK-NEXT: %[[VAR38:[A-Za-z0-9.]+]] = getelementptr inbounds { float, float }* %[[VAR30:[A-Za-z0-9.]+]], i32 0, i32 0
+ // CHECK-NEXT: %[[VAR39:[A-Za-z0-9.]+]] = getelementptr inbounds { float, float }* %[[VAR30]], i32 0, i32 1
+ // CHECK-NEXT: store float %[[VAR36]], float* %[[VAR38]]
+ // CHECK-NEXT: store float %[[VAR37]], float* %[[VAR39]]
+}
diff --git a/test/CodeGen/pr2394.c b/test/CodeGen/pr2394.c
index e43281a..f1091ec 100644
--- a/test/CodeGen/pr2394.c
+++ b/test/CodeGen/pr2394.c
@@ -1,7 +1,6 @@
// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
struct __attribute((packed)) x {int a : 24;};
int a(struct x* g) {
- // CHECK: load i16
- // CHECK: load i8
+ // CHECK: load i24
return g->a;
}
diff --git a/test/CodeGen/pragma-weak.c b/test/CodeGen/pragma-weak.c
index 2efc2eb..d4b1b9f 100644
--- a/test/CodeGen/pragma-weak.c
+++ b/test/CodeGen/pragma-weak.c
@@ -136,7 +136,7 @@ void __both3(void) {}
void __a1(void) __attribute((noinline));
#pragma weak a1 = __a1
void __a1(void) {}
-// CHECK: define void @__a1() {{.*}} noinline
+// CHECK: define void @__a1() [[NI:#[0-9]+]]
// attributes introduced BEFORE a combination of #pragma weak and alias()
// hold...
@@ -144,11 +144,11 @@ void __a3(void) __attribute((noinline));
#pragma weak a3 = __a3
void a3(void) __attribute((alias("__a3")));
void __a3(void) {}
-// CHECK: define void @__a3() {{.*}} noinline
+// CHECK: define void @__a3() [[NI]]
#pragma weak xxx = __xxx
__attribute((pure,noinline,const,fastcall)) void __xxx(void) { }
-// CHECK: void @__xxx() {{.*}} noinline
+// CHECK: void @__xxx() [[RN:#[0-9]+]]
///////////// PR10878: Make sure we can call a weak alias
void SHA512Pad(void *context) {}
@@ -179,3 +179,6 @@ void zzz(void){}
// CHECK: define void @yyy()
int correct_linkage;
+
+// CHECK: attributes [[NI]] = { noinline nounwind{{.*}} }
+// CHECK: attributes [[RN]] = { noinline nounwind readnone{{.*}} }
diff --git a/test/CodeGen/prefetchw-builtins.c b/test/CodeGen/prefetchw-builtins.c
new file mode 100644
index 0000000..9c5fdc7
--- /dev/null
+++ b/test/CodeGen/prefetchw-builtins.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-feature +prfchw -emit-llvm -o - %s | FileCheck %s
+
+// Don't include mm_malloc.h, it's system specific.
+#define __MM_MALLOC_H
+
+#include <x86intrin.h>
+
+void prefetch_w(void *p) {
+ return _m_prefetchw(p);
+// CHECK: @prefetch_w
+// CHECK: call void @llvm.prefetch({{.*}}, i32 1, i32 3, i32 1)
+}
diff --git a/test/CodeGen/r5.c b/test/CodeGen/r5.c
new file mode 100644
index 0000000..30a0c0d
--- /dev/null
+++ b/test/CodeGen/r5.c
@@ -0,0 +1,5 @@
+// RUN: %clang -target armv7-none-linux-gnueabi -mcpu=cortex-r5 -emit-llvm -S %s -o /dev/null
+
+int main() {
+ return 0;
+}
diff --git a/test/CodeGen/rdrand-builtins.c b/test/CodeGen/rdrand-builtins.c
index b7970f4..15414a3 100644
--- a/test/CodeGen/rdrand-builtins.c
+++ b/test/CodeGen/rdrand-builtins.c
@@ -1,9 +1,9 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-feature +rdrnd -emit-llvm -S -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-feature +rdrnd -target-feature +rdseed -emit-llvm -o - %s | FileCheck %s
// Don't include mm_malloc.h, it's system specific.
#define __MM_MALLOC_H
-#include <immintrin.h>
+#include <x86intrin.h>
int rdrand16(unsigned short *p) {
return _rdrand16_step(p);
@@ -25,3 +25,24 @@ int rdrand64(unsigned long long *p) {
// CHECK: call { i64, i32 } @llvm.x86.rdrand.64
// CHECK: store i64
}
+
+int rdseed16(unsigned short *p) {
+ return _rdseed16_step(p);
+// CHECK: @rdseed16
+// CHECK: call { i16, i32 } @llvm.x86.rdseed.16
+// CHECK: store i16
+}
+
+int rdseed32(unsigned *p) {
+ return _rdseed32_step(p);
+// CHECK: @rdseed32
+// CHECK: call { i32, i32 } @llvm.x86.rdseed.32
+// CHECK: store i32
+}
+
+int rdseed64(unsigned long long *p) {
+ return _rdseed64_step(p);
+// CHECK: @rdseed64
+// CHECK: call { i64, i32 } @llvm.x86.rdseed.64
+// CHECK: store i64
+}
diff --git a/test/CodeGen/regparm.c b/test/CodeGen/regparm.c
index d628b68..4c3752c 100644
--- a/test/CodeGen/regparm.c
+++ b/test/CodeGen/regparm.c
@@ -20,7 +20,7 @@ void f1(int i, int j, int k) { }
int
main(void) {
- // CHECK: call void @reduced(i8 signext inreg 0, {{.*}} %struct.foo* inreg null
+ // CHECK: call void @reduced(i8 inreg signext 0, {{.*}} %struct.foo* inreg null
reduced(0, 0.0, 0, 0.0, 0);
// CHECK: call x86_stdcallcc void {{.*}}(i32 inreg 1, i32 inreg 2)
bar(1,2);
diff --git a/test/CodeGen/rtm-builtins.c b/test/CodeGen/rtm-builtins.c
index c4939a9..5660d8e 100644
--- a/test/CodeGen/rtm-builtins.c
+++ b/test/CodeGen/rtm-builtins.c
@@ -21,3 +21,8 @@ test_xabort(void) {
// CHECK: void @llvm.x86.xabort(i8 2)
_xabort(2);
}
+
+unsigned int test_xtest(void) {
+ // CHECK: i32 @llvm.x86.xtest()
+ return _xtest();
+}
diff --git a/test/CodeGen/sanitize-init-order.cpp b/test/CodeGen/sanitize-init-order.cpp
new file mode 100644
index 0000000..3e94620
--- /dev/null
+++ b/test/CodeGen/sanitize-init-order.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -fsanitize=address,init-order -emit-llvm -o - %s | FileCheck %s
+
+struct PODStruct {
+ int x;
+};
+PODStruct s1;
+
+struct PODWithDtor {
+ ~PODWithDtor() { }
+ int x;
+};
+PODWithDtor s2;
+
+struct PODWithCtorAndDtor {
+ PODWithCtorAndDtor() { }
+ ~PODWithCtorAndDtor() { }
+ int x;
+};
+PODWithCtorAndDtor s3;
+
+// Check that ASan init-order checking ignores structs with trivial default
+// constructor.
+// CHECK: !llvm.asan.dynamically_initialized_globals = !{[[GLOB:![0-9]+]]}
+// CHECK: [[GLOB]] = metadata !{%struct.PODWithCtorAndDtor
diff --git a/test/CodeGen/sanitize-recover.c b/test/CodeGen/sanitize-recover.c
new file mode 100644
index 0000000..3c9c895
--- /dev/null
+++ b/test/CodeGen/sanitize-recover.c
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsanitize=unsigned-integer-overflow %s -emit-llvm -o - | FileCheck %s --check-prefix=RECOVER
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsanitize=unsigned-integer-overflow -fno-sanitize-recover %s -emit-llvm -o - | FileCheck %s --check-prefix=ABORT
+
+
+// RECOVER: @test
+// ABORT: @test
+void test() {
+ extern volatile unsigned x, y, z;
+
+ // RECOVER: uadd.with.overflow.i32
+ // RECOVER: ubsan_handle_add_overflow(
+ // RECOVER-NOT: unreachable
+ // ABORT: uadd.with.overflow.i32
+ // ABORT: ubsan_handle_add_overflow_abort(
+ // ABORT: unreachable
+ x = y + z;
+}
diff --git a/test/CodeGen/sanitize-thread-attr.cpp b/test/CodeGen/sanitize-thread-attr.cpp
new file mode 100644
index 0000000..fe5d810
--- /dev/null
+++ b/test/CodeGen/sanitize-thread-attr.cpp
@@ -0,0 +1,61 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck -check-prefix=WITHOUT %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=thread | FileCheck -check-prefix=TSAN %s
+// RUN: echo "src:%s" > %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -fsanitize=thread -fsanitize-blacklist=%t | FileCheck -check-prefix=BL %s
+
+// REQUIRES: shell
+
+// The sanitize_thread attribute should be attached to functions
+// when ThreadSanitizer is enabled, unless no_sanitize_thread attribute
+// is present.
+
+// WITHOUT: NoTSAN1{{.*}}) [[NOATTR:#[0-9]+]]
+// BL: NoTSAN1{{.*}}) [[NOATTR:#[0-9]+]]
+// TSAN: NoTSAN1{{.*}}) [[NOATTR:#[0-9]+]]
+__attribute__((no_sanitize_thread))
+int NoTSAN1(int *a) { return *a; }
+
+// WITHOUT: NoTSAN2{{.*}}) [[NOATTR]]
+// BL: NoTSAN2{{.*}}) [[NOATTR]]
+// TSAN: NoTSAN2{{.*}}) [[NOATTR]]
+__attribute__((no_sanitize_thread))
+int NoTSAN2(int *a);
+int NoTSAN2(int *a) { return *a; }
+
+// WITHOUT: TSANOk{{.*}}) [[NOATTR]]
+// BL: TSANOk{{.*}}) [[NOATTR]]
+// TSAN: TSANOk{{.*}}) [[WITH:#[0-9]+]]
+int TSANOk(int *a) { return *a; }
+
+// WITHOUT: TemplateTSANOk{{.*}}) [[NOATTR]]
+// BL: TemplateTSANOk{{.*}}) [[NOATTR]]
+// TSAN: TemplateTSANOk{{.*}}) [[WITH]]
+template<int i>
+int TemplateTSANOk() { return i; }
+
+// WITHOUT: TemplateNoTSAN{{.*}}) [[NOATTR]]
+// BL: TemplateNoTSAN{{.*}}) [[NOATTR]]
+// TSAN: TemplateNoTSAN{{.*}}) [[NOATTR]]
+template<int i>
+__attribute__((no_sanitize_thread))
+int TemplateNoTSAN() { return i; }
+
+int force_instance = TemplateTSANOk<42>()
+ + TemplateNoTSAN<42>();
+
+// Check that __cxx_global_var_init* get the sanitize_thread attribute.
+int global1 = 0;
+int global2 = *(int*)((char*)&global1+1);
+// WITHOUT: @__cxx_global_var_init{{.*}}[[NOATTR_NO_TF:#[0-9]+]]
+// BL: @__cxx_global_var_init{{.*}}[[NOATTR_NO_TF:#[0-9]+]]
+// TSAN: @__cxx_global_var_init{{.*}}[[WITH_NO_TF:#[0-9]+]]
+
+// WITHOUT: attributes [[NOATTR]] = { nounwind{{.*}} }
+// WITHOUT: attributes [[NOATTR_NO_TF]] = { nounwind }
+
+// BL: attributes [[NOATTR]] = { nounwind{{.*}} }
+// BL: attributes [[NOATTR_NO_TF]] = { nounwind{{.*}} }
+
+// TSAN: attributes [[NOATTR]] = { nounwind{{.*}} }
+// TSAN: attributes [[WITH]] = { nounwind sanitize_thread{{.*}} }
+// TSAN: attributes [[WITH_NO_TF]] = { nounwind sanitize_thread }
diff --git a/test/CodeGen/sanitize-use-after-scope.c b/test/CodeGen/sanitize-use-after-scope.c
new file mode 100644
index 0000000..8f92038
--- /dev/null
+++ b/test/CodeGen/sanitize-use-after-scope.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -S -emit-llvm -o - -fsanitize=address,use-after-scope %s \
+// RUN: | FileCheck %s -check-prefix=USE-AFTER-SCOPE
+// RUN: %clang_cc1 -S -emit-llvm -o - -fsanitize=address %s \
+// RUN: | FileCheck %s -check-prefix=ADDRESS-ONLY
+
+extern int bar(char *A, int n);
+
+// ADDRESS-ONLY-NOT: @llvm.lifetime.start
+int foo (int n) {
+ if (n) {
+ // USE-AFTER-SCOPE: @llvm.lifetime.start(i64 10, i8* {{.*}})
+ char A[10];
+ return bar(A, 1);
+ // USE-AFTER-SCOPE: @llvm.lifetime.end(i64 10, i8* {{.*}})
+ } else {
+ // USE-AFTER-SCOPE: @llvm.lifetime.start(i64 20, i8* {{.*}})
+ char A[20];
+ return bar(A, 2);
+ // USE-AFTER-SCOPE: @llvm.lifetime.end(i64 20, i8* {{.*}})
+ }
+}
+
diff --git a/test/CodeGen/split-debug-filename.c b/test/CodeGen/split-debug-filename.c
new file mode 100644
index 0000000..63970a8
--- /dev/null
+++ b/test/CodeGen/split-debug-filename.c
@@ -0,0 +1,7 @@
+// RUN: %clang -target x86_64-linux-gnu -gsplit-dwarf -S -emit-llvm -o - %s | FileCheck %s
+int main (void) {
+ return 0;
+}
+
+// Testing to ensure that the dwo name gets output into the compile unit.
+// CHECK: split-debug-filename.dwo
diff --git a/test/CodeGen/stack-protector.c b/test/CodeGen/stack-protector.c
index eb4cea2..e47e5b3 100644
--- a/test/CodeGen/stack-protector.c
+++ b/test/CodeGen/stack-protector.c
@@ -1,14 +1,24 @@
// RUN: %clang_cc1 -emit-llvm -o - %s -stack-protector 0 | FileCheck -check-prefix=NOSSP %s
-// NOSSP: define void @test1(i8* %msg) nounwind {
+// NOSSP: define void @test1(i8* %msg) #0 {
// RUN: %clang_cc1 -emit-llvm -o - %s -stack-protector 1 | FileCheck -check-prefix=WITHSSP %s
-// WITHSSP: define void @test1(i8* %msg) nounwind ssp {
+// WITHSSP: define void @test1(i8* %msg) #0 {
// RUN: %clang_cc1 -emit-llvm -o - %s -stack-protector 2 | FileCheck -check-prefix=SSPREQ %s
-// SSPREQ: define void @test1(i8* %msg) nounwind sspreq {
+// SSPREQ: define void @test1(i8* %msg) #0 {
+
+typedef __SIZE_TYPE__ size_t;
int printf(const char * _Format, ...);
+size_t strlen(const char *s);
+char *strcpy(char *s1, const char *s2);
void test1(const char *msg) {
char a[strlen(msg) + 1];
strcpy(a, msg);
printf("%s\n", a);
}
+
+// NOSSP: attributes #{{.*}} = { nounwind{{.*}} }
+
+// WITHSSP: attributes #{{.*}} = { nounwind ssp{{.*}} }
+
+// SSPREQ: attributes #{{.*}} = { nounwind sspreq{{.*}} }
diff --git a/test/CodeGen/string-literal.c b/test/CodeGen/string-literal.c
index 12d431a..8bc97f1 100644
--- a/test/CodeGen/string-literal.c
+++ b/test/CodeGen/string-literal.c
@@ -1,80 +1,107 @@
-// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix=C %s
-// RUN: %clang_cc1 -x c++ -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix=C %s
-// RUN: %clang_cc1 -x c++ -std=c++11 -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix=CPP0X %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-C %s
+// RUN: %clang_cc1 -x c++ -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-C %s
+// RUN: %clang_cc1 -x c++ -std=c++11 -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-CXX11 %s
+// RUN: %clang_cc1 -x c -std=c11 -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-C11 %s
#include <stddef.h>
+#ifndef __cplusplus
+typedef __WCHAR_TYPE__ wchar_t;
+typedef __CHAR16_TYPE__ char16_t;
+typedef __CHAR32_TYPE__ char32_t;
+#endif
+
int main() {
// CHECK-C: private unnamed_addr constant [10 x i8] c"abc\00\00\00\00\00\00\00", align 1
- // CHECK-CPP0X: private unnamed_addr constant [10 x i8] c"abc\00\00\00\00\00\00\00", align 1
+ // CHECK-C11: private unnamed_addr constant [10 x i8] c"abc\00\00\00\00\00\00\00", align 1
+ // CHECK-CXX11: private unnamed_addr constant [10 x i8] c"abc\00\00\00\00\00\00\00", align 1
char a[10] = "abc";
// This should convert to utf8.
// CHECK-C: private unnamed_addr constant [10 x i8] c"\E1\84\A0\C8\A0\F4\82\80\B0\00", align 1
- // CHECK-CPP0X: private unnamed_addr constant [10 x i8] c"\E1\84\A0\C8\A0\F4\82\80\B0\00", align 1
+ // CHECK-C11: private unnamed_addr constant [10 x i8] c"\E1\84\A0\C8\A0\F4\82\80\B0\00", align 1
+ // CHECK-CXX11: private unnamed_addr constant [10 x i8] c"\E1\84\A0\C8\A0\F4\82\80\B0\00", align 1
char b[10] = "\u1120\u0220\U00102030";
// CHECK-C: private unnamed_addr constant [3 x i32] [i32 65, i32 66, i32 0], align 4
- // CHECK-CPP0X: private unnamed_addr constant [3 x i32] [i32 65, i32 66, i32 0], align 4
+ // CHECK-C11: private unnamed_addr constant [3 x i32] [i32 65, i32 66, i32 0], align 4
+ // CHECK-CXX11: private unnamed_addr constant [3 x i32] [i32 65, i32 66, i32 0], align 4
const wchar_t *foo = L"AB";
// CHECK-C: private unnamed_addr constant [3 x i32] [i32 4660, i32 1110027, i32 0], align 4
- // CHECK-CPP0X: private unnamed_addr constant [3 x i32] [i32 4660, i32 1110027, i32 0], align 4
+ // CHECK-C11: private unnamed_addr constant [3 x i32] [i32 4660, i32 1110027, i32 0], align 4
+ // CHECK-CXX11: private unnamed_addr constant [3 x i32] [i32 4660, i32 1110027, i32 0], align 4
const wchar_t *bar = L"\u1234\U0010F00B";
// CHECK-C: private unnamed_addr constant [3 x i32] [i32 4660, i32 1110028, i32 0], align 4
- // CHECK-CPP0X: private unnamed_addr constant [3 x i32] [i32 4660, i32 1110028, i32 0], align 4
+ // CHECK-C11: private unnamed_addr constant [3 x i32] [i32 4660, i32 1110028, i32 0], align 4
+ // CHECK-CXX11: private unnamed_addr constant [3 x i32] [i32 4660, i32 1110028, i32 0], align 4
const wchar_t *baz = L"\u1234" "\U0010F00C";
-#if __cplusplus >= 201103L
- // CHECK-CPP0X: private unnamed_addr constant [3 x i32] [i32 67, i32 68, i32 0], align 4
+#if __cplusplus >= 201103L || __STDC_VERSION__ >= 201112L
+ // CHECK-C11: private unnamed_addr constant [3 x i32] [i32 67, i32 68, i32 0], align 4
+ // CHECK-CXX11: private unnamed_addr constant [3 x i32] [i32 67, i32 68, i32 0], align 4
const char32_t *c = U"CD";
- // CHECK-CPP0X: private unnamed_addr constant [3 x i32] [i32 4661, i32 1110028, i32 0], align 4
+ // CHECK-C11: private unnamed_addr constant [3 x i32] [i32 4661, i32 1110028, i32 0], align 4
+ // CHECK-CXX11: private unnamed_addr constant [3 x i32] [i32 4661, i32 1110028, i32 0], align 4
const char32_t *d = U"\u1235\U0010F00C";
- // CHECK-CPP0X: private unnamed_addr constant [3 x i32] [i32 4661, i32 1110027, i32 0], align 4
+ // CHECK-C11: private unnamed_addr constant [3 x i32] [i32 4661, i32 1110027, i32 0], align 4
+ // CHECK-CXX11: private unnamed_addr constant [3 x i32] [i32 4661, i32 1110027, i32 0], align 4
const char32_t *o = "\u1235" U"\U0010F00B";
- // CHECK-CPP0X: private unnamed_addr constant [3 x i16] [i16 69, i16 70, i16 0], align 2
+ // CHECK-C11: private unnamed_addr constant [3 x i16] [i16 69, i16 70, i16 0], align 2
+ // CHECK-CXX11: private unnamed_addr constant [3 x i16] [i16 69, i16 70, i16 0], align 2
const char16_t *e = u"EF";
// This should convert to utf16.
- // CHECK-CPP0X: private unnamed_addr constant [5 x i16] [i16 4384, i16 544, i16 -9272, i16 -9168, i16 0], align 2
+ // CHECK-C11: private unnamed_addr constant [5 x i16] [i16 4384, i16 544, i16 -9272, i16 -9168, i16 0], align 2
+ // CHECK-CXX11: private unnamed_addr constant [5 x i16] [i16 4384, i16 544, i16 -9272, i16 -9168, i16 0], align 2
const char16_t *f = u"\u1120\u0220\U00102030";
// This should convert to utf16.
- // CHECK-CPP0X: private unnamed_addr constant [5 x i16] [i16 4384, i16 800, i16 -9272, i16 -9168, i16 0], align 2
+ // CHECK-C11: private unnamed_addr constant [5 x i16] [i16 4384, i16 800, i16 -9272, i16 -9168, i16 0], align 2
+ // CHECK-CXX11: private unnamed_addr constant [5 x i16] [i16 4384, i16 800, i16 -9272, i16 -9168, i16 0], align 2
const char16_t *p = u"\u1120\u0320" "\U00102030";
- // CHECK-CPP0X: private unnamed_addr constant [4 x i8] c"def\00", align 1
+ // CHECK-C11: private unnamed_addr constant [4 x i8] c"def\00", align 1
+ // CHECK-CXX11: private unnamed_addr constant [4 x i8] c"def\00", align 1
const char *g = u8"def";
- // CHECK-CPP0X: private unnamed_addr constant [4 x i8] c"ghi\00", align 1
+#ifdef __cplusplus
+ // CHECK-CXX11: private unnamed_addr constant [4 x i8] c"ghi\00", align 1
const char *h = R"foo(ghi)foo";
- // CHECK-CPP0X: private unnamed_addr constant [4 x i8] c"jkl\00", align 1
+ // CHECK-CXX11: private unnamed_addr constant [4 x i8] c"jkl\00", align 1
const char *i = u8R"bar(jkl)bar";
- // CHECK-CPP0X: private unnamed_addr constant [3 x i16] [i16 71, i16 72, i16 0], align 2
+ // CHECK-CXX11: private unnamed_addr constant [3 x i16] [i16 71, i16 72, i16 0], align 2
const char16_t *j = uR"foo(GH)foo";
- // CHECK-CPP0X: private unnamed_addr constant [3 x i32] [i32 73, i32 74, i32 0], align 4
+ // CHECK-CXX11: private unnamed_addr constant [3 x i32] [i32 73, i32 74, i32 0], align 4
const char32_t *k = UR"bar(IJ)bar";
- // CHECK-CPP0X: private unnamed_addr constant [3 x i32] [i32 75, i32 76, i32 0], align 4
+ // CHECK-CXX11: private unnamed_addr constant [3 x i32] [i32 75, i32 76, i32 0], align 4
const wchar_t *l = LR"bar(KL)bar";
- // CHECK-CPP0X: private unnamed_addr constant [9 x i8] c"abc\5Cndef\00", align 1
+ // CHECK-CXX11: private unnamed_addr constant [9 x i8] c"abc\5Cndef\00", align 1
const char *m = R"(abc\ndef)";
- // CHECK-CPP0X: private unnamed_addr constant [8 x i8] c"abc\0Adef\00", align 1
+ // CHECK-CXX11: private unnamed_addr constant [8 x i8] c"abc\0Adef\00", align 1
const char *n = R"(abc
def)";
- // CHECK-CPP0X: private unnamed_addr constant [11 x i8] c"abc\0Adefghi\00", align 1
+ // CHECK-CXX11: private unnamed_addr constant [11 x i8] c"abc\0Adefghi\00", align 1
const char *q = R"(abc
def)" "ghi";
+ // CHECK-CXX11: private unnamed_addr constant [13 x i8] c"abc\5C\0A??=\0Adef\00", align 1
+ const char *r = R\
+"(abc\
+??=
+def)";
+
+#endif
#endif
}
diff --git a/test/CodeGen/struct-passing.c b/test/CodeGen/struct-passing.c
index efb00ef..d28fee2 100644
--- a/test/CodeGen/struct-passing.c
+++ b/test/CodeGen/struct-passing.c
@@ -16,9 +16,12 @@ void __attribute__((pure)) f5(T1 a);
void *ps[] = { f0, f1, f2, f3, f4, f5 };
-// CHECK: declare i32 @f0() nounwind readnone
-// CHECK: declare i32 @f1() nounwind readonly
+// CHECK: declare i32 @f0() [[RN:#[0-9]+]]
+// CHECK: declare i32 @f1() [[RO:#[0-9]+]]
// CHECK: declare void @f2({{.*}} sret)
// CHECK: declare void @f3({{.*}} sret)
// CHECK: declare void @f4({{.*}} byval align 4)
// CHECK: declare void @f5({{.*}} byval align 4)
+
+// CHECK: attributes [[RN]] = { nounwind readnone{{.*}} }
+// CHECK: attributes [[RO]] = { nounwind readonly{{.*}} }
diff --git a/test/CodeGen/tbaa-struct.cpp b/test/CodeGen/tbaa-struct.cpp
index 8b30aa0..12a6f4d 100644
--- a/test/CodeGen/tbaa-struct.cpp
+++ b/test/CodeGen/tbaa-struct.cpp
@@ -14,4 +14,33 @@ void copy(struct A *a, struct 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:!.*]]
+
+struct B {
+ char c1;
+ struct A a;
+ int ii;
+};
+
+void copy2(struct B *a, struct B *b) {
+ *a = *b;
+}
+
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i[[P]](i8* %{{.*}}, i8* %{{.*}}, i[[P]] 24, i32 4, i1 false), !tbaa.struct [[TS2:!.*]]
+
+typedef _Complex int T2;
+typedef _Complex char T5;
+typedef _Complex int T7;
+typedef struct T4 { T5 field0; T7 field1; } T4;
+typedef union T1 { T2 field0; T4 field1; } T1;
+
+void copy3 (T1 *a, T1 *b) {
+ *a = *b;
+}
+
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i[[P]](i8* %{{.*}}, i8* %{{.*}}, i[[P]] 12, i32 4, i1 false), !tbaa.struct [[TS3:!.*]]
+
// CHECK: [[TS]] = metadata !{i64 0, i64 2, metadata !{{.*}}, i64 4, i64 4, metadata !{{.*}}, i64 8, i64 1, metadata !{{.*}}, i64 12, i64 4, metadata !{{.*}}}
+// (offset, size) = (0,1) char; (4,2) short; (8,4) int; (12,1) char; (16,4) int; (20,4) int
+// CHECK: [[TS2]] = metadata !{i64 0, i64 1, metadata !{{.*}}, i64 4, i64 2, metadata !{{.*}}, i64 8, i64 4, metadata !{{.*}}, i64 12, i64 1, metadata !{{.*}}, i64 16, i64 4, metadata {{.*}}, i64 20, i64 4, metadata {{.*}}}
+// (offset, size) = (0,8) char; (0,2) char; (4,8) char
+// CHECK: [[TS3]] = metadata !{i64 0, i64 8, metadata !{{.*}}, i64 0, i64 2, metadata !{{.*}}, i64 4, i64 8, metadata !{{.*}}}
diff --git a/test/CodeGen/tbaa.cpp b/test/CodeGen/tbaa.cpp
new file mode 100644
index 0000000..c30e4a3
--- /dev/null
+++ b/test/CodeGen/tbaa.cpp
@@ -0,0 +1,217 @@
+// RUN: %clang_cc1 -O1 -disable-llvm-optzns %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -O1 -struct-path-tbaa -disable-llvm-optzns %s -emit-llvm -o - | FileCheck %s -check-prefix=PATH
+// Test TBAA metadata generated by front-end.
+
+#include <stdint.h>
+typedef struct
+{
+ uint16_t f16;
+ uint32_t f32;
+ uint16_t f16_2;
+ uint32_t f32_2;
+} StructA;
+typedef struct
+{
+ uint16_t f16;
+ StructA a;
+ uint32_t f32;
+} StructB;
+typedef struct
+{
+ uint16_t f16;
+ StructB b;
+ uint32_t f32;
+} StructC;
+typedef struct
+{
+ uint16_t f16;
+ StructB b;
+ uint32_t f32;
+ uint8_t f8;
+} StructD;
+
+typedef struct
+{
+ uint16_t f16;
+ uint32_t f32;
+} StructS;
+typedef struct
+{
+ uint16_t f16;
+ uint32_t f32;
+} StructS2;
+
+uint32_t g(uint32_t *s, StructA *A, uint64_t count) {
+// CHECK: define i32 @{{.*}}(
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// PATH: define i32 @{{.*}}(
+// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
+// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa !5
+ *s = 1;
+ A->f32 = 4;
+ return *s;
+}
+
+uint32_t g2(uint32_t *s, StructA *A, uint64_t count) {
+// CHECK: define i32 @{{.*}}(
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i16 4, i16* %{{.*}}, align 2, !tbaa !5
+// PATH: define i32 @{{.*}}(
+// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
+// PATH: store i16 4, i16* %{{.*}}, align 2, !tbaa !8
+ *s = 1;
+ A->f16 = 4;
+ return *s;
+}
+
+uint32_t g3(StructA *A, StructB *B, uint64_t count) {
+// CHECK: define i32 @{{.*}}(
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// PATH: define i32 @{{.*}}(
+// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa !5
+// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa !9
+ A->f32 = 1;
+ B->a.f32 = 4;
+ return A->f32;
+}
+
+uint32_t g4(StructA *A, StructB *B, uint64_t count) {
+// CHECK: define i32 @{{.*}}(
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i16 4, i16* %{{.*}}, align 2, !tbaa !5
+// PATH: define i32 @{{.*}}(
+// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa !5
+// PATH: store i16 4, i16* %{{.*}}, align 2, !tbaa !11
+ A->f32 = 1;
+ B->a.f16 = 4;
+ return A->f32;
+}
+
+uint32_t g5(StructA *A, StructB *B, uint64_t count) {
+// CHECK: define i32 @{{.*}}(
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// PATH: define i32 @{{.*}}(
+// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa !5
+// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa !12
+ A->f32 = 1;
+ B->f32 = 4;
+ return A->f32;
+}
+
+uint32_t g6(StructA *A, StructB *B, uint64_t count) {
+// CHECK: define i32 @{{.*}}(
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// PATH: define i32 @{{.*}}(
+// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa !5
+// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa !13
+ A->f32 = 1;
+ B->a.f32_2 = 4;
+ return A->f32;
+}
+
+uint32_t g7(StructA *A, StructS *S, uint64_t count) {
+// CHECK: define i32 @{{.*}}(
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// PATH: define i32 @{{.*}}(
+// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa !5
+// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa !14
+ A->f32 = 1;
+ S->f32 = 4;
+ return A->f32;
+}
+
+uint32_t g8(StructA *A, StructS *S, uint64_t count) {
+// CHECK: define i32 @{{.*}}(
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i16 4, i16* %{{.*}}, align 2, !tbaa !5
+// PATH: define i32 @{{.*}}(
+// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa !5
+// PATH: store i16 4, i16* %{{.*}}, align 2, !tbaa !16
+ A->f32 = 1;
+ S->f16 = 4;
+ return A->f32;
+}
+
+uint32_t g9(StructS *S, StructS2 *S2, uint64_t count) {
+// CHECK: define i32 @{{.*}}(
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// PATH: define i32 @{{.*}}(
+// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa !14
+// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa !17
+ S->f32 = 1;
+ S2->f32 = 4;
+ return S->f32;
+}
+
+uint32_t g10(StructS *S, StructS2 *S2, uint64_t count) {
+// CHECK: define i32 @{{.*}}(
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i16 4, i16* %{{.*}}, align 2, !tbaa !5
+// PATH: define i32 @{{.*}}(
+// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa !14
+// PATH: store i16 4, i16* %{{.*}}, align 2, !tbaa !19
+ S->f32 = 1;
+ S2->f16 = 4;
+ return S->f32;
+}
+
+uint32_t g11(StructC *C, StructD *D, uint64_t count) {
+// CHECK: define i32 @{{.*}}(
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// PATH: define i32 @{{.*}}(
+// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa !20
+// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa !22
+ C->b.a.f32 = 1;
+ D->b.a.f32 = 4;
+ return C->b.a.f32;
+}
+
+uint32_t g12(StructC *C, StructD *D, uint64_t count) {
+// CHECK: define i32 @{{.*}}(
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// TODO: differentiate the two accesses.
+// PATH: define i32 @{{.*}}(
+// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa !9
+// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa !9
+ StructB *b1 = &(C->b);
+ StructB *b2 = &(D->b);
+ // b1, b2 have different context.
+ b1->a.f32 = 1;
+ b2->a.f32 = 4;
+ return b1->a.f32;
+}
+
+// CHECK: !1 = metadata !{metadata !"omnipotent char", metadata !2}
+// CHECK: !2 = metadata !{metadata !"Simple C/C++ TBAA"}
+// CHECK: !4 = metadata !{metadata !"int", metadata !1}
+// CHECK: !5 = metadata !{metadata !"short", metadata !1}
+
+// PATH: !1 = metadata !{metadata !"omnipotent char", metadata !2}
+// PATH: !4 = metadata !{metadata !"int", metadata !1}
+// PATH: !5 = metadata !{metadata !6, metadata !4, i64 4}
+// PATH: !6 = metadata !{metadata !"_ZTS7StructA", i64 0, metadata !7, i64 4, metadata !4}
+// PATH: !7 = metadata !{metadata !"short", metadata !1}
+// PATH: !8 = metadata !{metadata !6, metadata !7, i64 0}
+// PATH: !9 = metadata !{metadata !10, metadata !4, i64 8}
+// PATH: !10 = metadata !{metadata !"_ZTS7StructB", i64 0, metadata !7, i64 4, metadata !6, i64 20, metadata !4}
+// PATH: !11 = metadata !{metadata !10, metadata !7, i64 4}
+// PATH: !12 = metadata !{metadata !10, metadata !4, i64 20}
+// PATH: !13 = metadata !{metadata !10, metadata !4, i64 16}
+// PATH: !14 = metadata !{metadata !15, metadata !4, i64 4}
+// PATH: !15 = metadata !{metadata !"_ZTS7StructS", i64 0, metadata !7, i64 4, metadata !4}
+// PATH: !16 = metadata !{metadata !15, metadata !7, i64 0}
+// PATH: !17 = metadata !{metadata !18, metadata !4, i64 4}
+// PATH: !18 = metadata !{metadata !"_ZTS8StructS2", i64 0, metadata !7, i64 4, metadata !4}
+// PATH: !19 = metadata !{metadata !18, metadata !7, i64 0}
+// PATH: !20 = metadata !{metadata !21, metadata !4, i64 12}
+// PATH: !21 = metadata !{metadata !"_ZTS7StructC", i64 0, metadata !7, i64 4, metadata !10, i64 28, metadata !4}
+// PATH: !22 = metadata !{metadata !23, metadata !4, i64 12}
+// PATH: !23 = metadata !{metadata !"_ZTS7StructD", i64 0, metadata !7, i64 4, metadata !10, i64 28, metadata !4, i64 32, metadata !1}
diff --git a/test/CodeGen/ubsan-blacklist.c b/test/CodeGen/ubsan-blacklist.c
new file mode 100644
index 0000000..6c67f02
--- /dev/null
+++ b/test/CodeGen/ubsan-blacklist.c
@@ -0,0 +1,31 @@
+// Verify ubsan doesn't emit checks for blacklisted functions and files
+// RUN: echo "fun:hash" > %t-func.blacklist
+// RUN: echo "src:%s" > %t-file.blacklist
+// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow -emit-llvm %s -o - | FileCheck %s --check-prefix=DEFAULT
+// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow -fsanitize-blacklist=%t-func.blacklist -emit-llvm %s -o - | FileCheck %s --check-prefix=FUNC
+// RUN: %clang_cc1 -fsanitize=unsigned-integer-overflow -fsanitize-blacklist=%t-file.blacklist -emit-llvm %s -o - | FileCheck %s --check-prefix=FILE
+
+// FIXME: %t-file.blacklist contains DOSish paths.
+// REQUIRES: shell
+
+unsigned i;
+
+// DEFAULT: @hash
+// FUNC: @hash
+// FILE: @hash
+unsigned hash() {
+// DEFAULT: call void @__ubsan
+// FUNC-NOT: call void @__ubsan
+// FILE-NOT: call void @__ubsan
+ return i * 37;
+}
+
+// DEFAULT: @add
+// FUNC: @add
+// FILE: @add
+unsigned add() {
+// DEFAULT: call void @__ubsan
+// FUNC: call void @__ubsan
+// FILE-NOT: call void @__ubsan
+ return i + 1;
+}
diff --git a/test/CodeGen/ucn-identifiers.c b/test/CodeGen/ucn-identifiers.c
new file mode 100644
index 0000000..56e3aa5
--- /dev/null
+++ b/test/CodeGen/ucn-identifiers.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 %s -emit-llvm -o /dev/null
+// RUN: %clang_cc1 %s -emit-llvm -o /dev/null -x c++
+// This file contains UTF-8; please do not fix!
+
+
+extern void \u00FCber(int);
+extern void \U000000FCber(int); // redeclaration, no warning
+
+void goodCalls() {
+ \u00FCber(0);
+ \u00fcber(1);
+ über(2);
+ \U000000FCber(3);
+}
diff --git a/test/CodeGen/unreachable.c b/test/CodeGen/unreachable.c
index 5e9fa6a..898f64e 100644
--- a/test/CodeGen/unreachable.c
+++ b/test/CodeGen/unreachable.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -emit-llvm -o %t %s
-// RUN: grep '@unreachable' %t | count 0
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
+// CHECK-NOT: @unreachable
extern void abort() __attribute__((noreturn));
extern int unreachable();
diff --git a/test/CodeGen/unsigned-overflow.c b/test/CodeGen/unsigned-overflow.c
new file mode 100644
index 0000000..341ea35
--- /dev/null
+++ b/test/CodeGen/unsigned-overflow.c
@@ -0,0 +1,125 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsanitize=unsigned-integer-overflow %s -emit-llvm -o - | FileCheck %s
+// Verify checked operations are emitted for integers and longs.
+// unsigned short/char's tested in unsigned-promotion.c
+
+unsigned long li, lj, lk;
+unsigned int ii, ij, ik;
+
+extern void opaquelong(unsigned long);
+extern void opaqueint(unsigned int);
+
+// CHECK: define void @testlongadd()
+void testlongadd() {
+
+ // CHECK: [[T1:%.*]] = load i64* @lj
+ // CHECK-NEXT: [[T2:%.*]] = load i64* @lk
+ // CHECK-NEXT: [[T3:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[T1]], i64 [[T2]])
+ // CHECK-NEXT: [[T4:%.*]] = extractvalue { i64, i1 } [[T3]], 0
+ // CHECK-NEXT: [[T5:%.*]] = extractvalue { i64, i1 } [[T3]], 1
+ // CHECK: call void @__ubsan_handle_add_overflow
+ li = lj + lk;
+}
+
+// CHECK: define void @testlongsub()
+void testlongsub() {
+
+ // CHECK: [[T1:%.*]] = load i64* @lj
+ // CHECK-NEXT: [[T2:%.*]] = load i64* @lk
+ // CHECK-NEXT: [[T3:%.*]] = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 [[T1]], i64 [[T2]])
+ // CHECK-NEXT: [[T4:%.*]] = extractvalue { i64, i1 } [[T3]], 0
+ // CHECK-NEXT: [[T5:%.*]] = extractvalue { i64, i1 } [[T3]], 1
+ // CHECK: call void @__ubsan_handle_sub_overflow
+ li = lj - lk;
+}
+
+// CHECK: define void @testlongmul()
+void testlongmul() {
+
+ // CHECK: [[T1:%.*]] = load i64* @lj
+ // CHECK-NEXT: [[T2:%.*]] = load i64* @lk
+ // CHECK-NEXT: [[T3:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[T1]], i64 [[T2]])
+ // CHECK-NEXT: [[T4:%.*]] = extractvalue { i64, i1 } [[T3]], 0
+ // CHECK-NEXT: [[T5:%.*]] = extractvalue { i64, i1 } [[T3]], 1
+ // CHECK: call void @__ubsan_handle_mul_overflow
+ li = lj * lk;
+}
+
+// CHECK: define void @testlongpostinc()
+void testlongpostinc() {
+ opaquelong(li++);
+
+ // CHECK: [[T1:%.*]] = load i64* @li
+ // CHECK-NEXT: [[T2:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[T1]], i64 1)
+ // CHECK-NEXT: [[T3:%.*]] = extractvalue { i64, i1 } [[T2]], 0
+ // CHECK-NEXT: [[T4:%.*]] = extractvalue { i64, i1 } [[T2]], 1
+ // CHECK: call void @__ubsan_handle_add_overflow
+}
+
+// CHECK: define void @testlongpreinc()
+void testlongpreinc() {
+ opaquelong(++li);
+
+ // CHECK: [[T1:%.*]] = load i64* @li
+ // CHECK-NEXT: [[T2:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[T1]], i64 1)
+ // CHECK-NEXT: [[T3:%.*]] = extractvalue { i64, i1 } [[T2]], 0
+ // CHECK-NEXT: [[T4:%.*]] = extractvalue { i64, i1 } [[T2]], 1
+ // CHECK: call void @__ubsan_handle_add_overflow
+}
+
+// CHECK: define void @testintadd()
+void testintadd() {
+
+ // CHECK: [[T1:%.*]] = load i32* @ij
+ // CHECK-NEXT: [[T2:%.*]] = load i32* @ik
+ // CHECK-NEXT: [[T3:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[T1]], i32 [[T2]])
+ // CHECK-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T3]], 0
+ // CHECK-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T3]], 1
+ // CHECK: call void @__ubsan_handle_add_overflow
+ ii = ij + ik;
+}
+
+// CHECK: define void @testintsub()
+void testintsub() {
+
+ // CHECK: [[T1:%.*]] = load i32* @ij
+ // CHECK-NEXT: [[T2:%.*]] = load i32* @ik
+ // CHECK-NEXT: [[T3:%.*]] = call { i32, i1 } @llvm.usub.with.overflow.i32(i32 [[T1]], i32 [[T2]])
+ // CHECK-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T3]], 0
+ // CHECK-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T3]], 1
+ // CHECK: call void @__ubsan_handle_sub_overflow
+ ii = ij - ik;
+}
+
+// CHECK: define void @testintmul()
+void testintmul() {
+
+ // CHECK: [[T1:%.*]] = load i32* @ij
+ // CHECK-NEXT: [[T2:%.*]] = load i32* @ik
+ // CHECK-NEXT: [[T3:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[T1]], i32 [[T2]])
+ // CHECK-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T3]], 0
+ // CHECK-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T3]], 1
+ // CHECK: call void @__ubsan_handle_mul_overflow
+ ii = ij * ik;
+}
+
+// CHECK: define void @testintpostinc()
+void testintpostinc() {
+ opaqueint(ii++);
+
+ // CHECK: [[T1:%.*]] = load i32* @ii
+ // CHECK-NEXT: [[T2:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[T1]], i32 1)
+ // CHECK-NEXT: [[T3:%.*]] = extractvalue { i32, i1 } [[T2]], 0
+ // CHECK-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T2]], 1
+ // CHECK: call void @__ubsan_handle_add_overflow
+}
+
+// CHECK: define void @testintpreinc()
+void testintpreinc() {
+ opaqueint(++ii);
+
+ // CHECK: [[T1:%.*]] = load i32* @ii
+ // CHECK-NEXT: [[T2:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[T1]], i32 1)
+ // CHECK-NEXT: [[T3:%.*]] = extractvalue { i32, i1 } [[T2]], 0
+ // CHECK-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T2]], 1
+ // CHECK: call void @__ubsan_handle_add_overflow
+}
diff --git a/test/CodeGen/unsigned-promotion.c b/test/CodeGen/unsigned-promotion.c
new file mode 100644
index 0000000..c263c0c
--- /dev/null
+++ b/test/CodeGen/unsigned-promotion.c
@@ -0,0 +1,143 @@
+// Check -fsanitize=signed-integer-overflow and
+// -fsanitize=unsigned-integer-overflow with promoted unsigned types
+//
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s \
+// RUN: -fsanitize=signed-integer-overflow | FileCheck %s --check-prefix=CHECKS
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s \
+// RUN: -fsanitize=unsigned-integer-overflow | FileCheck %s --check-prefix=CHECKU
+
+unsigned short si, sj, sk;
+unsigned char ci, cj, ck;
+
+extern void opaqueshort(unsigned short);
+extern void opaquechar(unsigned char);
+
+// CHECKS: define void @testshortadd()
+// CHECKU: define void @testshortadd()
+void testshortadd() {
+ // CHECKS: load i16* @sj
+ // CHECKS: load i16* @sk
+ // CHECKS: [[T1:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[T2:%.*]], i32 [[T3:%.*]])
+ // CHECKS-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T1]], 0
+ // CHECKS-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T1]], 1
+ // CHECKS: call void @__ubsan_handle_add_overflow
+ //
+ // CHECKU: [[T1:%.*]] = load i16* @sj
+ // CHECKU: [[T2:%.*]] = zext i16 [[T1]]
+ // CHECKU: [[T3:%.*]] = load i16* @sk
+ // CHECKU: [[T4:%.*]] = zext i16 [[T3]]
+ // CHECKU-NOT: llvm.sadd
+ // CHECKU-NOT: llvm.uadd
+ // CHECKU: [[T5:%.*]] = add nsw i32 [[T2]], [[T4]]
+
+ si = sj + sk;
+}
+
+// CHECKS: define void @testshortsub()
+// CHECKU: define void @testshortsub()
+void testshortsub() {
+
+ // CHECKS: load i16* @sj
+ // CHECKS: load i16* @sk
+ // CHECKS: [[T1:%.*]] = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[T2:%.*]], i32 [[T3:%.*]])
+ // CHECKS-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T1]], 0
+ // CHECKS-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T1]], 1
+ // CHECKS: call void @__ubsan_handle_sub_overflow
+ //
+ // CHECKU: [[T1:%.*]] = load i16* @sj
+ // CHECKU: [[T2:%.*]] = zext i16 [[T1]]
+ // CHECKU: [[T3:%.*]] = load i16* @sk
+ // CHECKU: [[T4:%.*]] = zext i16 [[T3]]
+ // CHECKU-NOT: llvm.ssub
+ // CHECKU-NOT: llvm.usub
+ // CHECKU: [[T5:%.*]] = sub nsw i32 [[T2]], [[T4]]
+
+ si = sj - sk;
+}
+
+// CHECKS: define void @testshortmul()
+// CHECKU: define void @testshortmul()
+void testshortmul() {
+
+ // CHECKS: load i16* @sj
+ // CHECKS: load i16* @sk
+ // CHECKS: [[T1:%.*]] = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[T2:%.*]], i32 [[T3:%.*]])
+ // CHECKS-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T1]], 0
+ // CHECKS-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T1]], 1
+ // CHECKS: call void @__ubsan_handle_mul_overflow
+ //
+ // CHECKU: [[T1:%.*]] = load i16* @sj
+ // CHECKU: [[T2:%.*]] = zext i16 [[T1]]
+ // CHECKU: [[T3:%.*]] = load i16* @sk
+ // CHECKU: [[T4:%.*]] = zext i16 [[T3]]
+ // CHECKU-NOT: llvm.smul
+ // CHECKU-NOT: llvm.umul
+ // CHECKU: [[T5:%.*]] = mul nsw i32 [[T2]], [[T4]]
+ si = sj * sk;
+}
+
+// CHECKS: define void @testcharadd()
+// CHECKU: define void @testcharadd()
+void testcharadd() {
+
+ // CHECKS: load i8* @cj
+ // CHECKS: load i8* @ck
+ // CHECKS: [[T1:%.*]] = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[T2:%.*]], i32 [[T3:%.*]])
+ // CHECKS-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T1]], 0
+ // CHECKS-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T1]], 1
+ // CHECKS: call void @__ubsan_handle_add_overflow
+ //
+ // CHECKU: [[T1:%.*]] = load i8* @cj
+ // CHECKU: [[T2:%.*]] = zext i8 [[T1]]
+ // CHECKU: [[T3:%.*]] = load i8* @ck
+ // CHECKU: [[T4:%.*]] = zext i8 [[T3]]
+ // CHECKU-NOT: llvm.sadd
+ // CHECKU-NOT: llvm.uadd
+ // CHECKU: [[T5:%.*]] = add nsw i32 [[T2]], [[T4]]
+
+ ci = cj + ck;
+}
+
+// CHECKS: define void @testcharsub()
+// CHECKU: define void @testcharsub()
+void testcharsub() {
+
+ // CHECKS: load i8* @cj
+ // CHECKS: load i8* @ck
+ // CHECKS: [[T1:%.*]] = call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[T2:%.*]], i32 [[T3:%.*]])
+ // CHECKS-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T1]], 0
+ // CHECKS-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T1]], 1
+ // CHECKS: call void @__ubsan_handle_sub_overflow
+ //
+ // CHECKU: [[T1:%.*]] = load i8* @cj
+ // CHECKU: [[T2:%.*]] = zext i8 [[T1]]
+ // CHECKU: [[T3:%.*]] = load i8* @ck
+ // CHECKU: [[T4:%.*]] = zext i8 [[T3]]
+ // CHECKU-NOT: llvm.ssub
+ // CHECKU-NOT: llvm.usub
+ // CHECKU: [[T5:%.*]] = sub nsw i32 [[T2]], [[T4]]
+
+ ci = cj - ck;
+}
+
+// CHECKS: define void @testcharmul()
+// CHECKU: define void @testcharmul()
+void testcharmul() {
+
+ // CHECKS: load i8* @cj
+ // CHECKS: load i8* @ck
+ // CHECKS: [[T1:%.*]] = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[T2:%.*]], i32 [[T3:%.*]])
+ // CHECKS-NEXT: [[T4:%.*]] = extractvalue { i32, i1 } [[T1]], 0
+ // CHECKS-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T1]], 1
+ // CHECKS: call void @__ubsan_handle_mul_overflow
+ //
+ // CHECKU: [[T1:%.*]] = load i8* @cj
+ // CHECKU: [[T2:%.*]] = zext i8 [[T1]]
+ // CHECKU: [[T3:%.*]] = load i8* @ck
+ // CHECKU: [[T4:%.*]] = zext i8 [[T3]]
+ // CHECKU-NOT: llvm.smul
+ // CHECKU-NOT: llvm.umul
+ // CHECKU: [[T5:%.*]] = mul nsw i32 [[T2]], [[T4]]
+
+ ci = cj * ck;
+}
diff --git a/test/CodeGen/unsigned-trapv.c b/test/CodeGen/unsigned-trapv.c
new file mode 100644
index 0000000..b7aed03
--- /dev/null
+++ b/test/CodeGen/unsigned-trapv.c
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -fsanitize=unsigned-integer-overflow | FileCheck %s --check-prefix=UNSIGNED
+// 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=unsigned-integer-overflow -ftrapv | FileCheck %s --check-prefix=BOTH
+// Verify that -ftrapv and -fsanitize=unsigned-integer-overflow
+// work together as expected
+
+
+// UNSIGNED: @test_signed
+// TRAPV: @test_signed
+// BOTH: @test_signed
+void test_signed() {
+ extern volatile int a, b, c;
+ // UNSIGNED: add nsw i32
+ // UNSIGNED-NOT: overflow
+ // TRAPV: sadd.with.overflow.i32
+ // TRAPV-NOT: ubsan
+ // TRAPV: llvm.trap
+ // BOTH: sadd.with.overflow.i32
+ // BOTH-NOT: ubsan
+ // BOTH: llvm.trap
+ a = b + c;
+}
+
+// UNSIGNED: @test_unsigned
+// TRAPV: @test_unsigned
+// BOTH: @test_unsigned
+void test_unsigned() {
+ extern volatile unsigned x, y, z;
+ // UNSIGNED: uadd.with.overflow.i32
+ // UNSIGNED-NOT: llvm.trap
+ // UNSIGNED: ubsan
+ // TRAPV-NOT: overflow
+ // TRAPV-NOT: llvm.trap
+ // BOTH: uadd.with.overflow.i32
+ // BOTH: ubsan
+ // BOTH-NOT: llvm.trap
+ x = y + z;
+}
diff --git a/test/CodeGen/unwind-attr.c b/test/CodeGen/unwind-attr.c
index 7a79cb6..e505a6e 100644
--- a/test/CodeGen/unwind-attr.c
+++ b/test/CodeGen/unwind-attr.c
@@ -3,22 +3,27 @@
int opaque();
-// CHECK: define [[INT:i.*]] @test0() {
-// CHECK-NOEXC: define [[INT:i.*]] @test0() nounwind {
+// CHECK: define [[INT:i.*]] @test0() [[TF:#[0-9]+]] {
+// CHECK-NOEXC: define [[INT:i.*]] @test0() [[NUW:#[0-9]+]] {
int test0(void) {
return opaque();
}
// <rdar://problem/8087431>: locally infer nounwind at -O0
-// CHECK: define [[INT:i.*]] @test1() nounwind {
-// CHECK-NOEXC: define [[INT:i.*]] @test1() nounwind {
+// CHECK: define [[INT:i.*]] @test1() [[NUW:#[0-9]+]] {
+// CHECK-NOEXC: define [[INT:i.*]] @test1() [[NUW]] {
int test1(void) {
return 0;
}
// <rdar://problem/8283071>: not for weak functions
-// CHECK: define weak [[INT:i.*]] @test2() {
-// CHECK-NOEXC: define weak [[INT:i.*]] @test2() nounwind {
+// CHECK: define weak [[INT:i.*]] @test2() [[TF]] {
+// CHECK-NOEXC: define weak [[INT:i.*]] @test2() [[NUW]] {
__attribute__((weak)) int test2(void) {
return 0;
}
+
+// CHECK: attributes [[TF]] = { "{{.*}} }
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
+
+// CHECK-NOEXC: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGen/visibility.c b/test/CodeGen/visibility.c
index fa4b599..3082b7b 100644
--- a/test/CodeGen/visibility.c
+++ b/test/CodeGen/visibility.c
@@ -67,3 +67,10 @@ __private_extern__ void test3(void) {}
// Top of file.
extern int test4;
__private_extern__ int test4 = 10;
+
+// rdar://12399248
+// CHECK-DEFAULT: define hidden void @test5()
+// CHECK-PROTECTED: define hidden void @test5()
+// CHECK-HIDDEN: define hidden void @test5()
+__attribute__((availability(macosx,introduced=10.5,deprecated=10.6)))
+__private_extern__ void test5(void) {}
diff --git a/test/CodeGen/vla.c b/test/CodeGen/vla.c
index e151827..f63796b 100644
--- a/test/CodeGen/vla.c
+++ b/test/CodeGen/vla.c
@@ -190,4 +190,8 @@ void test6(void)
// CHECK-NEXT: store i32 0, i32* [[IX2]], align 4
}
-
+// Follow gcc's behavior for VLAs in parameter lists. PR9559.
+void test7(int a[b(0)]) {
+ // CHECK: define void @test7(
+ // CHECK: call i32 @b(i8* null)
+}
diff --git a/test/CodeGen/volatile.c b/test/CodeGen/volatile.c
index 1a996de..0dcdc15 100644
--- a/test/CodeGen/volatile.c
+++ b/test/CodeGen/volatile.c
@@ -1,10 +1,4 @@
-// RUN: %clang_cc1 -emit-llvm < %s -o %t
-// RUN: grep volatile %t | count 28
-// RUN: grep memcpy %t | count 7
-
-// The number 28 comes from the current codegen for volatile loads;
-// if this number changes, it's not necessarily something wrong, but
-// something has changed to affect volatile load/store codegen
+// RUN: %clang_cc1 -emit-llvm < %s | FileCheck %s
int S;
volatile int vS;
@@ -43,58 +37,171 @@ volatile_int vtS;
int main() {
int i;
-
+// CHECK: [[I:%[a-zA-Z0-9_.]+]] = alloca i32
// load
i=S;
+// CHECK: load i32* @S
+// CHECK: store i32 {{.*}}, i32* [[I]]
i=vS;
+// CHECK: load volatile i32* @vS
+// CHECK: store i32 {{.*}}, i32* [[I]]
i=*pS;
+// CHECK: [[PS_VAL:%[a-zA-Z0-9_.]+]] = load i32** @pS
+// CHECK: load i32* [[PS_VAL]]
+// CHECK: store i32 {{.*}}, i32* [[I]]
i=*pvS;
+// CHECK: [[PVS_VAL:%[a-zA-Z0-9_.]+]] = load i32** @pvS
+// CHECK: load volatile i32* [[PVS_VAL]]
+// CHECK: store i32 {{.*}}, i32* [[I]]
i=A[2];
+// CHECK: load i32* getelementptr {{.*}} @A
+// CHECK: store i32 {{.*}}, i32* [[I]]
i=vA[2];
+// CHECK: load volatile i32* getelementptr {{.*}} @vA
+// CHECK: store i32 {{.*}}, i32* [[I]]
i=F.x;
+// CHECK: load i32* getelementptr {{.*}} @F
+// CHECK: store i32 {{.*}}, i32* [[I]]
i=vF.x;
+// CHECK: load volatile i32* getelementptr {{.*}} @vF
+// CHECK: store i32 {{.*}}, i32* [[I]]
i=F2.x;
+// CHECK: load i32* getelementptr {{.*}} @F2
+// CHECK: store i32 {{.*}}, i32* [[I]]
i=vF2.x;
+// CHECK: load volatile i32* getelementptr {{.*}} @vF2
+// CHECK: store i32 {{.*}}, i32* [[I]]
i=vpF2->x;
+// CHECK: [[VPF2_VAL:%[a-zA-Z0-9_.]+]] = load {{%[a-zA-Z0-9_.]+}}** @vpF2
+// CHECK: [[ELT:%[a-zA-Z0-9_.]+]] = getelementptr {{.*}} [[VPF2_VAL]]
+// CHECK: load volatile i32* [[ELT]]
+// CHECK: store i32 {{.*}}, i32* [[I]]
i=F3.x.y;
+// CHECK: load i32* getelementptr {{.*}} @F3
+// CHECK: store i32 {{.*}}, i32* [[I]]
i=vF3.x.y;
+// CHECK: load volatile i32* getelementptr {{.*}} @vF3
+// CHECK: store i32 {{.*}}, i32* [[I]]
i=BF.x;
+// CHECK: load i8* getelementptr {{.*}} @BF
+// CHECK: store i32 {{.*}}, i32* [[I]]
i=vBF.x;
+// CHECK: load volatile i8* getelementptr {{.*}} @vBF
+// CHECK: store i32 {{.*}}, i32* [[I]]
i=V[3];
+// CHECK: load <4 x i32>* @V
+// CHECK: store i32 {{.*}}, i32* [[I]]
i=vV[3];
+// CHECK: load volatile <4 x i32>* @vV
+// CHECK: store i32 {{.*}}, i32* [[I]]
i=VE.yx[1];
+// CHECK: load <4 x i32>* @VE
+// CHECK: store i32 {{.*}}, i32* [[I]]
i=vVE.zy[1];
+// CHECK: load volatile <4 x i32>* @vVE
+// CHECK: store i32 {{.*}}, i32* [[I]]
i = aggFct().x; // Note: not volatile
+ // N.b. Aggregate return is extremely target specific, all we can
+ // really say here is that there probably shouldn't be a volatile
+ // load.
+// CHECK-NOT: load volatile
+// CHECK: store i32 {{.*}}, i32* [[I]]
i=vtS;
+// CHECK: load volatile i32* @vtS
+// CHECK: store i32 {{.*}}, i32* [[I]]
// store
S=i;
+// CHECK: load i32* [[I]]
+// CHECK: store i32 {{.*}}, i32* @S
vS=i;
+// CHECK: load i32* [[I]]
+// CHECK: store volatile i32 {{.*}}, i32* @vS
*pS=i;
+// CHECK: load i32* [[I]]
+// CHECK: [[PS_VAL:%[a-zA-Z0-9_.]+]] = load i32** @pS
+// CHECK: store i32 {{.*}}, i32* [[PS_VAL]]
*pvS=i;
+// CHECK: load i32* [[I]]
+// CHECK: [[PVS_VAL:%[a-zA-Z0-9_.]+]] = load i32** @pvS
+// CHECK: store volatile i32 {{.*}}, i32* [[PVS_VAL]]
A[2]=i;
+// CHECK: load i32* [[I]]
+// CHECK: store i32 {{.*}}, i32* getelementptr {{.*}} @A
vA[2]=i;
+// CHECK: load i32* [[I]]
+// CHECK: store volatile i32 {{.*}}, i32* getelementptr {{.*}} @vA
F.x=i;
+// CHECK: load i32* [[I]]
+// CHECK: store i32 {{.*}}, i32* getelementptr {{.*}} @F
vF.x=i;
+// CHECK: load i32* [[I]]
+// CHECK: store volatile i32 {{.*}}, i32* getelementptr {{.*}} @vF
F2.x=i;
+// CHECK: load i32* [[I]]
+// CHECK: store i32 {{.*}}, i32* getelementptr {{.*}} @F2
vF2.x=i;
+// CHECK: load i32* [[I]]
+// CHECK: store volatile i32 {{.*}}, i32* getelementptr {{.*}} @vF2
vpF2->x=i;
+// CHECK: load i32* [[I]]
+// CHECK: [[VPF2_VAL:%[a-zA-Z0-9_.]+]] = load {{%[a-zA-Z0-9._]+}}** @vpF2
+// CHECK: [[ELT:%[a-zA-Z0-9_.]+]] = getelementptr {{.*}} [[VPF2_VAL]]
+// CHECK: store volatile i32 {{.*}}, i32* [[ELT]]
vF3.x.y=i;
+// CHECK: load i32* [[I]]
+// CHECK: store volatile i32 {{.*}}, i32* getelementptr {{.*}} @vF3
BF.x=i;
+// CHECK: load i32* [[I]]
+// CHECK: load i8* getelementptr {{.*}} @BF
+// CHECK: store i8 {{.*}}, i8* getelementptr {{.*}} @BF
vBF.x=i;
+// CHECK: load i32* [[I]]
+// CHECK: load volatile i8* getelementptr {{.*}} @vBF
+// CHECK: store volatile i8 {{.*}}, i8* getelementptr {{.*}} @vBF
V[3]=i;
+// CHECK: load i32* [[I]]
+// CHECK: load <4 x i32>* @V
+// CHECK: store <4 x i32> {{.*}}, <4 x i32>* @V
vV[3]=i;
+// CHECK: load i32* [[I]]
+// CHECK: load volatile <4 x i32>* @vV
+// CHECK: store volatile <4 x i32> {{.*}}, <4 x i32>* @vV
vtS=i;
+// CHECK: load i32* [[I]]
+// CHECK: store volatile i32 {{.*}}, i32* @vtS
// other ops:
++S;
+// CHECK: load i32* @S
+// CHECK: store i32 {{.*}}, i32* @S
++vS;
+// CHECK: load volatile i32* @vS
+// CHECK: store volatile i32 {{.*}}, i32* @vS
i+=S;
+// CHECK: load i32* @S
+// CHECK: load i32* [[I]]
+// CHECK: store i32 {{.*}}, i32* [[I]]
i+=vS;
+// CHECK: load volatile i32* @vS
+// CHECK: load i32* [[I]]
+// CHECK: store i32 {{.*}}, i32* [[I]]
++vtS;
+// CHECK: load volatile i32* @vtS
+// CHECK: store volatile i32 {{.*}}, i32* @vtS
(void)vF2;
+ // From vF2 to a temporary
+// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{.*}}, i8* {{.*}} @vF2 {{.*}}, i1 true)
vF2 = vF2;
+ // vF2 to itself
+// CHECK: call void @llvm.memcpy.{{.*}}(i8* {{.*@vF2.*}}, i8* {{.*@vF2.*}}, i1 true)
vF2 = vF2 = vF2;
+ // vF2 to itself twice
+// CHECK: call void @llvm.memcpy.{{.*}}(i8* {{.*@vF2.*}}, i8* {{.*@vF2.*}}, i1 true)
+// CHECK: call void @llvm.memcpy.{{.*}}(i8* {{.*@vF2.*}}, i8* {{.*@vF2.*}}, i1 true)
vF2 = (vF2, vF2);
+ // vF2 to a temporary, then vF2 to itself
+// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{.*}}, i8* {{.*@vF2.*}}, i1 true)
+// CHECK: call void @llvm.memcpy.{{.*}}(i8* {{.*@vF2.*}}, i8* {{.*@vF2.*}}, i1 true)
}
diff --git a/test/CodeGen/x86_32-arguments-darwin.c b/test/CodeGen/x86_32-arguments-darwin.c
index 5bbc80b..4aa4295 100644
--- a/test/CodeGen/x86_32-arguments-darwin.c
+++ b/test/CodeGen/x86_32-arguments-darwin.c
@@ -229,7 +229,7 @@ v4i32 f55(v4i32 arg) { return arg+arg; }
// CHECK: define void @f56(
// CHECK: i8 signext %a0, %struct.s56_0* byval align 4 %a1,
-// CHECK: x86_mmx %a2.coerce, %struct.s56_1* byval align 4,
+// CHECK: i64 %a2.coerce, %struct.s56_1* byval align 4,
// CHECK: i64 %a4.coerce, %struct.s56_2* byval align 4,
// CHECK: <4 x i32> %a6, %struct.s56_3* byval align 16 %a7,
// CHECK: <2 x double> %a8, %struct.s56_4* byval align 16 %a9,
@@ -238,7 +238,7 @@ v4i32 f55(v4i32 arg) { return arg+arg; }
// CHECK: call void (i32, ...)* @f56_0(i32 1,
// CHECK: i32 %{{[^ ]*}}, %struct.s56_0* byval align 4 %{{[^ ]*}},
-// CHECK: x86_mmx %{{[^ ]*}}, %struct.s56_1* byval align 4 %{{[^ ]*}},
+// CHECK: i64 %{{[^ ]*}}, %struct.s56_1* byval align 4 %{{[^ ]*}},
// CHECK: i64 %{{[^ ]*}}, %struct.s56_2* byval align 4 %{{[^ ]*}},
// CHECK: <4 x i32> %{{[^ ]*}}, %struct.s56_3* byval align 16 %{{[^ ]*}},
// CHECK: <2 x double> %{{[^ ]*}}, %struct.s56_4* byval align 16 %{{[^ ]*}},
@@ -337,3 +337,8 @@ T66 f66(int i, ...) {
__builtin_va_end(ap);
return v;
}
+
+// PR14453
+struct s67 { _Complex unsigned short int a; };
+void f67(struct s67 x) {}
+// CHECK: define void @f67(%struct.s67* byval align 4 %x)
diff --git a/test/CodeGen/x86_32-arguments-linux.c b/test/CodeGen/x86_32-arguments-linux.c
index 81dcaf6..e93f9dc 100644
--- a/test/CodeGen/x86_32-arguments-linux.c
+++ b/test/CodeGen/x86_32-arguments-linux.c
@@ -3,7 +3,7 @@
// CHECK: define void @f56(
// CHECK: i8 signext %a0, %struct.s56_0* byval align 4 %a1,
-// CHECK: x86_mmx %a2.coerce, %struct.s56_1* byval align 4,
+// CHECK: i64 %a2.coerce, %struct.s56_1* byval align 4,
// CHECK: <1 x double> %a4, %struct.s56_2* byval align 4,
// CHECK: <4 x i32> %a6, %struct.s56_3* byval align 4,
// CHECK: <2 x double> %a8, %struct.s56_4* byval align 4,
@@ -12,7 +12,7 @@
// CHECK: call void (i32, ...)* @f56_0(i32 1,
// CHECK: i32 %{{.*}}, %struct.s56_0* byval align 4 %{{[^ ]*}},
-// CHECK: x86_mmx %{{[^ ]*}}, %struct.s56_1* byval align 4 %{{[^ ]*}},
+// CHECK: i64 %{{[^ ]*}}, %struct.s56_1* byval align 4 %{{[^ ]*}},
// CHECK: <1 x double> %{{[^ ]*}}, %struct.s56_2* byval align 4 %{{[^ ]*}},
// CHECK: <4 x i32> %{{[^ ]*}}, %struct.s56_3* byval align 4 %{{[^ ]*}},
// CHECK: <2 x double> %{{[^ ]*}}, %struct.s56_4* byval align 4 %{{[^ ]*}},
diff --git a/test/CodeGen/x86_32-inline-asm.c b/test/CodeGen/x86_32-inline-asm.c
new file mode 100644
index 0000000..473f78e
--- /dev/null
+++ b/test/CodeGen/x86_32-inline-asm.c
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin9 -verify %s
+// <rdar://problem/12415959>
+
+typedef unsigned int u_int32_t;
+typedef u_int32_t uint32_t;
+
+typedef unsigned long long u_int64_t;
+typedef u_int64_t uint64_t;
+
+int func1() {
+ // Error out if size is > 32-bits.
+ uint32_t msr = 0x8b;
+ uint64_t val = 0;
+ __asm__ volatile("wrmsr"
+ :
+ : "c" (msr),
+ "a" ((val & 0xFFFFFFFFUL)), // expected-error {{invalid input size for constraint 'a'}}
+ "d" (((val >> 32) & 0xFFFFFFFFUL)));
+
+ // Don't error out if the size of the destination is <= 32 bits.
+ unsigned char data;
+ unsigned int port;
+ __asm__ volatile("outb %0, %w1" : : "a" (data), "Nd" (port)); // No error expected.
+}
diff --git a/test/CodeGen/x86_64-arguments.c b/test/CodeGen/x86_64-arguments.c
index f73e1f0..518ee84 100644
--- a/test/CodeGen/x86_64-arguments.c
+++ b/test/CodeGen/x86_64-arguments.c
@@ -354,3 +354,41 @@ void test46() { v46 x = {1,2}; f46(x,x,x,x,x,x,x,x,x,x); }
struct s47 { unsigned a; };
void f47(int,int,int,int,int,int,struct s47);
void test47(int a, struct s47 b) { f47(a, a, a, a, a, a, b); }
+
+// rdar://12723368
+// In the following example, there are holes in T4 at the 3rd byte and the 4th
+// byte, however, T2 does not have those holes. T4 is chosen to be the
+// representing type for union T1, but we can't use load or store of T4 since
+// it will skip the 3rd byte and the 4th byte.
+// In general, Since we don't accurately represent the data fields of a union,
+// do not use load or store of the representing llvm type for the union.
+typedef _Complex int T2;
+typedef _Complex char T5;
+typedef _Complex int T7;
+typedef struct T4 { T5 field0; T7 field1; } T4;
+typedef union T1 { T2 field0; T4 field1; } T1;
+extern T1 T1_retval;
+T1 test48(void) {
+// CHECK: @test48
+// CHECK: memcpy
+// CHECK: memcpy
+ return T1_retval;
+}
+
+void test49_helper(double, ...);
+void test49(double d, double e) {
+ test49_helper(d, e);
+}
+// CHECK: define void @test49(
+// CHECK: [[T0:%.*]] = load double*
+// CHECK-NEXT: [[T1:%.*]] = load double*
+// CHECK-NEXT: call void (double, ...)* @test49_helper(double [[T0]], double [[T1]])
+
+void test50_helper();
+void test50(double d, double e) {
+ test50_helper(d, e);
+}
+// CHECK: define void @test50(
+// CHECK: [[T0:%.*]] = load double*
+// CHECK-NEXT: [[T1:%.*]] = load double*
+// CHECK-NEXT: call void (double, double, ...)* bitcast (void (...)* @test50_helper to void (double, double, ...)*)(double [[T0]], double [[T1]])
diff --git a/test/CodeGenCUDA/ptx-kernels.cu b/test/CodeGenCUDA/ptx-kernels.cu
index f0bf295..8d34f4f 100644
--- a/test/CodeGenCUDA/ptx-kernels.cu
+++ b/test/CodeGenCUDA/ptx-kernels.cu
@@ -2,11 +2,15 @@
#include "../SemaCUDA/cuda.h"
-// CHECK: define ptx_device{{.*}}device_function
+// CHECK: define void @device_function
+extern "C"
__device__ void device_function() {}
-// CHECK: define ptx_kernel{{.*}}global_function
+// CHECK: define void @global_function
+extern "C"
__global__ void global_function() {
- // CHECK: call ptx_device{{.*}}device_function
+ // CHECK: call void @device_function
device_function();
}
+
+// CHECK: !{{[0-9]+}} = metadata !{void ()* @global_function, metadata !"kernel", i32 1}
diff --git a/test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp b/test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp
index 7acc07d..3828388 100644
--- a/test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp
+++ b/test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp
@@ -3,13 +3,19 @@ int c(void) __attribute__((const));
int p(void) __attribute__((pure));
int t(void);
-// CHECK: define i32 @_Z1fv() {
+// CHECK: define i32 @_Z1fv() [[TF:#[0-9]+]] {
int f(void) {
- // CHECK: call i32 @_Z1cv() nounwind readnone
- // CHECK: call i32 @_Z1pv() nounwind readonly
+ // CHECK: call i32 @_Z1cv() [[NUW_RN_CALL:#[0-9]+]]
+ // CHECK: call i32 @_Z1pv() [[NUW_RO_CALL:#[0-9]+]]
return c() + p() + t();
}
-// CHECK: declare i32 @_Z1cv() nounwind readnone
-// CHECK: declare i32 @_Z1pv() nounwind readonly
-// CHECK-NOT: declare i32 @_Z1tv() nounwind
+// CHECK: declare i32 @_Z1cv() [[NUW_RN:#[0-9]+]]
+// CHECK: declare i32 @_Z1pv() [[NUW_RO:#[0-9]+]]
+// CHECK: declare i32 @_Z1tv() [[TF]]
+
+// CHECK: attributes [[TF]] = { {{.*}} }
+// CHECK: attributes [[NUW_RN]] = { nounwind readnone{{.*}} }
+// CHECK: attributes [[NUW_RO]] = { nounwind readonly{{.*}} }
+// CHECK: attributes [[NUW_RN_CALL]] = { nounwind readnone }
+// CHECK: attributes [[NUW_RO_CALL]] = { nounwind readonly }
diff --git a/test/CodeGenCXX/2009-12-23-MissingSext.cpp b/test/CodeGenCXX/2009-12-23-MissingSext.cpp
index e6ff7b3..2b42367 100644
--- a/test/CodeGenCXX/2009-12-23-MissingSext.cpp
+++ b/test/CodeGenCXX/2009-12-23-MissingSext.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple x86_64-unknown-unknown -emit-llvm -o - | FileCheck %s
// The store of p.y into the temporary was not
// getting extended to 32 bits, so uninitialized
// bits of the temporary were used. 7366161.
@@ -8,8 +8,12 @@ struct foo {
};
int bar(struct foo p, int x) {
// CHECK: bar
-// CHECK: and {{.*}} 16777215
-// CHECK: and {{.*}} 16777215
+// CHECK: %[[val:.*]] = load i32* {{.*}}
+// CHECK-NEXT: ashr i32 %[[val]]
+// CHECK: = load i32* {{.*}}
+// CHECK: = load i32* {{.*}}
+// CHECK: %[[val:.*]] = load i32* {{.*}}
+// CHECK-NEXT: ashr i32 %[[val]]
x = (p.y > x ? x : p.y);
return x;
// CHECK: ret
diff --git a/test/CodeGenCXX/2010-07-23-DeclLoc.cpp b/test/CodeGenCXX/2010-07-23-DeclLoc.cpp
index 7405448..4c68902 100644
--- a/test/CodeGenCXX/2010-07-23-DeclLoc.cpp
+++ b/test/CodeGenCXX/2010-07-23-DeclLoc.cpp
@@ -1,9 +1,9 @@
// RUN: %clang_cc1 -emit-llvm -g %s -o - | FileCheck %s
// Require the template function declaration refer to the correct filename.
// First, locate the function decl in metadata, and pluck out the file handle:
-// CHECK: {{extract_dwarf_data_from_header.*extract_dwarf_data_from_header.*extract_dwarf_data_from_header.*[^ ]+", metadata !}}[[filehandle:[0-9]+]],
+// CHECK: metadata [[filehandle:![0-9]+]], {{[^,]*}}, {{.*extract_dwarf_data_from_header.*extract_dwarf_data_from_header.*extract_dwarf_data_from_header.*[^ ]+", }}
// Second: Require that filehandle refer to the correct filename:
-// CHECK: {{^!}}[[filehandle]] = metadata {{![{].*}} metadata !"decl_should_be_here.hpp",
+// CHECK: [[filehandle]] = {{.*}}decl_should_be_here.hpp"
typedef long unsigned int __darwin_size_t;
typedef __darwin_size_t size_t;
typedef unsigned char uint8_t;
diff --git a/test/CodeGenCXX/aarch64-arguments.cpp b/test/CodeGenCXX/aarch64-arguments.cpp
new file mode 100644
index 0000000..f56ad0b
--- /dev/null
+++ b/test/CodeGenCXX/aarch64-arguments.cpp
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -triple aarch64-none-linux -emit-llvm -w -o - %s | FileCheck -check-prefix=PCS %s
+
+// PCS: define void @{{.*}}(i8 %a
+struct s0 {};
+void f0(s0 a) {}
diff --git a/test/CodeGenCXX/aarch64-cxxabi.cpp b/test/CodeGenCXX/aarch64-cxxabi.cpp
new file mode 100644
index 0000000..04d9493
--- /dev/null
+++ b/test/CodeGenCXX/aarch64-cxxabi.cpp
@@ -0,0 +1,96 @@
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -emit-llvm -w -o - %s | FileCheck %s
+
+// Check differences between the generic Itanium ABI, the AArch32 version and
+// the AArch64 version.
+
+////////////////////////////////////////////////////////////////////////////////
+
+// The ABI says that the key function is the "textually first, non-inline,
+// non-pure, virtual member function". The generic version decides this after
+// the completion of the class definition; the AArch32 version decides this at
+// the end of the translation unit.
+
+// We construct a class which needs a VTable here under generic ABI, but not
+// AArch32.
+
+// (see next section for explanation of guard)
+// CHECK: @_ZGVZ15guard_variablesiE4mine = internal global i64 0
+
+// CHECK: @_ZTV16CheckKeyFunction =
+struct CheckKeyFunction {
+ virtual void foo();
+};
+
+// This is not inline when CheckKeyFunction is completed, so
+// CheckKeyFunction::foo is the key function. VTables should be emitted.
+inline void CheckKeyFunction::foo() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Guard variables only specify and use the low bit to determine status, rather
+// than the low byte as in the generic Itanium ABI. However, unlike 32-bit ARM,
+// they *are* 64-bits wide so check that in case confusion has occurred.
+
+class Guarded {
+public:
+ Guarded(int i);
+ ~Guarded();
+};
+
+void guard_variables(int a) {
+ static Guarded mine(a);
+// CHECK: [[GUARDBIT:%[0-9]+]] = and i64 {{%[0-9]+}}, 1
+// CHECK: icmp eq i64 [[GUARDBIT]], 0
+
+ // As guards are 64-bit, these helpers should take 64-bit pointers.
+// CHECK: call i32 @__cxa_guard_acquire(i64*
+// CHECK: call void @__cxa_guard_release(i64*
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Member function pointers use the adj field to distinguish between virtual and
+// nonvirtual members. As a result the adjustment is shifted (if ptr was used, a
+// mask would be expected instead).
+
+class C {
+ int a();
+ virtual int b();
+};
+
+
+int member_pointer(C &c, int (C::*func)()) {
+// CHECK: ashr i64 %[[MEMPTRADJ:[0-9a-z.]+]], 1
+// CHECK: %[[ISVIRTUAL:[0-9]+]] = and i64 %[[MEMPTRADJ]], 1
+// CHECK: icmp ne i64 %[[ISVIRTUAL]], 0
+ return (c.*func)();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+// AArch64 PCS says that va_list type is based on "struct __va_list ..." in the
+// std namespace, which means it should mangle as "St9__va_list".
+
+// CHECK: @_Z7va_funcSt9__va_list
+void va_func(__builtin_va_list l) {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+// AArch64 constructors (like generic Itanium, but unlike AArch32) do not return
+// "this".
+
+void test_constructor() {
+ Guarded g(42);
+// CHECK: call void @_ZN7GuardedC1Ei
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+// In principle the AArch32 ABI allows this to be accomplished via a call to
+// __aeabi_atexit instead of __cxa_atexit. Clang doesn't make use of this at the
+// moment, but it's definitely not allowed for AArch64.
+
+// CHECK: call i32 @__cxa_atexit
+Guarded g(42);
diff --git a/test/CodeGenCXX/arm.cpp b/test/CodeGenCXX/arm.cpp
index 6c60f30..48f2f00 100644
--- a/test/CodeGenCXX/arm.cpp
+++ b/test/CodeGenCXX/arm.cpp
@@ -56,15 +56,15 @@ namespace test1 {
// CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4
// CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]]
// CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]]
- // CHECK: call [[A]]* @_ZN5test11AC2Ei(
- // CHECK: ret [[A]]* [[THIS1]]
+ // CHECK: [[THIS2:%.*]] = call [[A]]* @_ZN5test11AC2Ei(
+ // CHECK: ret [[A]]* [[THIS2]]
// CHECK: define linkonce_odr [[A]]* @_ZN5test11AD1Ev([[A]]* %this) unnamed_addr
// CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4
// CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]]
// CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]]
- // CHECK: call [[A]]* @_ZN5test11AD2Ev(
- // CHECK: ret [[A]]* [[THIS1]]
+ // CHECK: [[THIS2:%.*]] = call [[A]]* @_ZN5test11AD2Ev(
+ // CHECK: ret [[A]]* [[THIS2]]
}
// Awkward virtual cases.
@@ -274,11 +274,11 @@ namespace test6 {
// CHECK-NEXT: [[V:%.*]] = load [[A]]** [[AVAR]], align 4
// CHECK-NEXT: [[ISNULL:%.*]] = icmp eq [[A]]* [[V]], null
// CHECK-NEXT: br i1 [[ISNULL]]
- // CHECK: [[T0:%.*]] = bitcast [[A]]* [[V]] to [[A]]* ([[A]]*)***
- // CHECK-NEXT: [[T1:%.*]] = load [[A]]* ([[A]]*)*** [[T0]]
- // CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[A]]* ([[A]]*)** [[T1]], i64 1
- // CHECK-NEXT: [[T3:%.*]] = load [[A]]* ([[A]]*)** [[T2]]
- // CHECK-NEXT: call [[A]]* [[T3]]([[A]]* [[V]])
+ // CHECK: [[T0:%.*]] = bitcast [[A]]* [[V]] to void ([[A]]*)***
+ // CHECK-NEXT: [[T1:%.*]] = load void ([[A]]*)*** [[T0]]
+ // CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds void ([[A]]*)** [[T1]], i64 1
+ // CHECK-NEXT: [[T3:%.*]] = load void ([[A]]*)** [[T2]]
+ // CHECK-NEXT: call void [[T3]]([[A]]* [[V]])
// CHECK-NEXT: br label
// CHECK: ret void
delete a;
@@ -357,6 +357,58 @@ namespace test8 {
}
}
+// rdar://12836470
+// Use a larger-than-mandated array cookie when allocating an
+// array whose type is overaligned.
+namespace test9 {
+ class __attribute__((aligned(16))) A {
+ float data[4];
+ public:
+ A();
+ ~A();
+ };
+
+ A *testNew(unsigned n) {
+ return new A[n];
+ }
+// CHECK: define [[TEST9:%.*]]* @_ZN5test97testNewEj(i32
+// CHECK: [[N_VAR:%.*]] = alloca i32, align 4
+// CHECK: [[N:%.*]] = load i32* [[N_VAR]], align 4
+// CHECK-NEXT: [[T0:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[N]], i32 16)
+// CHECK-NEXT: [[O0:%.*]] = extractvalue { i32, i1 } [[T0]], 1
+// CHECK-NEXT: [[T1:%.*]] = extractvalue { i32, i1 } [[T0]], 0
+// CHECK-NEXT: [[T2:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[T1]], i32 16)
+// CHECK-NEXT: [[O1:%.*]] = extractvalue { i32, i1 } [[T2]], 1
+// CHECK-NEXT: [[OVERFLOW:%.*]] = or i1 [[O0]], [[O1]]
+// CHECK-NEXT: [[T3:%.*]] = extractvalue { i32, i1 } [[T2]], 0
+// CHECK-NEXT: [[T4:%.*]] = select i1 [[OVERFLOW]], i32 -1, i32 [[T3]]
+// CHECK-NEXT: [[ALLOC:%.*]] = call noalias i8* @_Znam(i32 [[T4]])
+// CHECK-NEXT: [[T0:%.*]] = bitcast i8* [[ALLOC]] to i32*
+// CHECK-NEXT: store i32 16, i32* [[T0]]
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i32* [[T0]], i32 1
+// CHECK-NEXT: store i32 [[N]], i32* [[T1]]
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds i8* [[ALLOC]], i64 16
+// CHECK-NEXT: bitcast i8* [[T0]] to [[TEST9]]*
+// Array allocation follows.
+
+ void testDelete(A *array) {
+ delete[] array;
+ }
+// CHECK: define void @_ZN5test910testDeleteEPNS_1AE(
+// CHECK: [[BEGIN:%.*]] = load [[TEST9]]**
+// CHECK-NEXT: [[T0:%.*]] = icmp eq [[TEST9]]* [[BEGIN]], null
+// CHECK-NEXT: br i1 [[T0]],
+// CHECK: [[T0:%.*]] = bitcast [[TEST9]]* [[BEGIN]] to i8*
+// CHECK-NEXT: [[ALLOC:%.*]] = getelementptr inbounds i8* [[T0]], i64 -16
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds i8* [[ALLOC]], i64 4
+// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to i32*
+// CHECK-NEXT: [[N:%.*]] = load i32* [[T1]]
+// CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[TEST9]]* [[BEGIN]], i32 [[N]]
+// CHECK-NEXT: [[T0:%.*]] = icmp eq [[TEST9]]* [[BEGIN]], [[END]]
+// CHECK-NEXT: br i1 [[T0]],
+// Array deallocation follows.
+}
+
// CHECK: define linkonce_odr [[C:%.*]]* @_ZTv0_n12_N5test21CD1Ev(
// CHECK: call [[C]]* @_ZN5test21CD1Ev(
// CHECK: ret [[C]]* undef
diff --git a/test/CodeGenCXX/assign-operator.cpp b/test/CodeGenCXX/assign-operator.cpp
index e19df27..40695b7 100644
--- a/test/CodeGenCXX/assign-operator.cpp
+++ b/test/CodeGenCXX/assign-operator.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -verify -o - |FileCheck %s
+// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -o - -std=c++11 |FileCheck %s
class x {
public: int operator=(int);
@@ -28,3 +28,27 @@ namespace test1 {
A<int> a;
}
+
+// Ensure that we use memcpy when we would have selected a trivial assignment
+// operator, even for a non-trivially-copyable type.
+struct A {
+ A &operator=(const A&);
+};
+struct B {
+ B(const B&);
+ B &operator=(const B&) = default;
+ int n;
+};
+struct C {
+ A a;
+ B b[16];
+};
+void b(C &a, C &b) {
+ // CHECK: define {{.*}} @_ZN1CaSERKS_(
+ // CHECK: call {{.*}} @_ZN1AaSERKS_(
+ // CHECK-NOT: call {{.*}} @_ZN1BaSERKS_(
+ // CHECK: call {{.*}} @{{.*}}memcpy
+ // CHECK-NOT: call {{.*}} @_ZN1BaSERKS_(
+ // CHECK: }
+ a = b;
+}
diff --git a/test/CodeGenCXX/attr.cpp b/test/CodeGenCXX/attr.cpp
index a0dd748..4748cda 100644
--- a/test/CodeGenCXX/attr.cpp
+++ b/test/CodeGenCXX/attr.cpp
@@ -2,7 +2,7 @@
// CHECK: @test2 = alias i32 ()* @_Z5test1v
-// CHECK: define i32 @_Z3foov() nounwind align 1024
+// CHECK: define i32 @_Z3foov() [[NUW:#[0-9]+]] align 1024
int foo() __attribute__((aligned(1024)));
int foo() { }
@@ -13,16 +13,16 @@ class C {
void bar4() __attribute__((aligned(1024)));
} c;
-// CHECK: define void @_ZN1C4bar1Ev(%class.C* %this) unnamed_addr nounwind align 2
+// CHECK: define void @_ZN1C4bar1Ev(%class.C* %this) unnamed_addr [[NUW]] align 2
void C::bar1() { }
-// CHECK: define void @_ZN1C4bar2Ev(%class.C* %this) unnamed_addr nounwind align 2
+// CHECK: define void @_ZN1C4bar2Ev(%class.C* %this) unnamed_addr [[NUW]] align 2
void C::bar2() { }
-// CHECK: define void @_ZN1C4bar3Ev(%class.C* %this) unnamed_addr nounwind align 1024
+// CHECK: define void @_ZN1C4bar3Ev(%class.C* %this) unnamed_addr [[NUW]] align 1024
void C::bar3() { }
-// CHECK: define void @_ZN1C4bar4Ev(%class.C* %this) nounwind align 1024
+// CHECK: define void @_ZN1C4bar4Ev(%class.C* %this) [[NUW]] align 1024
void C::bar4() { }
// PR6635
@@ -30,3 +30,5 @@ void C::bar4() { }
int test1() { return 10; }
// CHECK at top of file
extern "C" int test2() __attribute__((alias("_Z5test1v")));
+
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGenCXX/bitfield.cpp b/test/CodeGenCXX/bitfield.cpp
new file mode 100644
index 0000000..1814aa2
--- /dev/null
+++ b/test/CodeGenCXX/bitfield.cpp
@@ -0,0 +1,428 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -verify -emit-llvm -o - %s \
+// RUN: | FileCheck -check-prefix=CHECK-X86-64 %s
+// RUN: %clang_cc1 -triple powerpc64-unknown-unknown -verify -emit-llvm -o - %s \
+// RUN: | FileCheck -check-prefix=CHECK-PPC64 %s
+//
+// Tests for bitfield access patterns in C++ with special attention to
+// conformance to C++11 memory model requirements.
+
+namespace N0 {
+ // Test basic bitfield layout access across interesting byte and word
+ // boundaries on both little endian and big endian platforms.
+ struct __attribute__((packed)) S {
+ unsigned b00 : 14;
+ unsigned b01 : 2;
+ unsigned b20 : 6;
+ unsigned b21 : 2;
+ unsigned b30 : 30;
+ unsigned b31 : 2;
+ unsigned b70 : 6;
+ unsigned b71 : 2;
+ };
+ unsigned read00(S* s) {
+ // CHECK-X86-64: define i32 @_ZN2N06read00
+ // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
+ // CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]]
+ // CHECK-X86-64: %[[and:.*]] = and i64 %[[val]], 16383
+ // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
+ // CHECK-X86-64: ret i32 %[[trunc]]
+ // CHECK-PPC64: define zeroext i32 @_ZN2N06read00
+ // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
+ // CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]]
+ // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 50
+ // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[shr]] to i32
+ // CHECK-PPC64: ret i32 %[[trunc]]
+ return s->b00;
+ }
+ unsigned read01(S* s) {
+ // CHECK-X86-64: define i32 @_ZN2N06read01
+ // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
+ // CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]]
+ // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 14
+ // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 3
+ // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
+ // CHECK-X86-64: ret i32 %[[trunc]]
+ // CHECK-PPC64: define zeroext i32 @_ZN2N06read01
+ // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
+ // CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]]
+ // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 48
+ // CHECK-PPC64: %[[and:.*]] = and i64 %[[shr]], 3
+ // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
+ // CHECK-PPC64: ret i32 %[[trunc]]
+ return s->b01;
+ }
+ unsigned read20(S* s) {
+ // CHECK-X86-64: define i32 @_ZN2N06read20
+ // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
+ // CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]]
+ // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 16
+ // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 63
+ // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
+ // CHECK-X86-64: ret i32 %[[trunc]]
+ // CHECK-PPC64: define zeroext i32 @_ZN2N06read20
+ // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
+ // CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]]
+ // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 42
+ // CHECK-PPC64: %[[and:.*]] = and i64 %[[shr]], 63
+ // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
+ // CHECK-PPC64: ret i32 %[[trunc]]
+ return s->b20;
+ }
+ unsigned read21(S* s) {
+ // CHECK-X86-64: define i32 @_ZN2N06read21
+ // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
+ // CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]]
+ // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 22
+ // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 3
+ // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
+ // CHECK-X86-64: ret i32 %[[trunc]]
+ // CHECK-PPC64: define zeroext i32 @_ZN2N06read21
+ // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
+ // CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]]
+ // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 40
+ // CHECK-PPC64: %[[and:.*]] = and i64 %[[shr]], 3
+ // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
+ // CHECK-PPC64: ret i32 %[[trunc]]
+ return s->b21;
+ }
+ unsigned read30(S* s) {
+ // CHECK-X86-64: define i32 @_ZN2N06read30
+ // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
+ // CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]]
+ // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 24
+ // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 1073741823
+ // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
+ // CHECK-X86-64: ret i32 %[[trunc]]
+ // CHECK-PPC64: define zeroext i32 @_ZN2N06read30
+ // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
+ // CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]]
+ // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 10
+ // CHECK-PPC64: %[[and:.*]] = and i64 %[[shr]], 1073741823
+ // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
+ // CHECK-PPC64: ret i32 %[[trunc]]
+ return s->b30;
+ }
+ unsigned read31(S* s) {
+ // CHECK-X86-64: define i32 @_ZN2N06read31
+ // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
+ // CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]]
+ // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 54
+ // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 3
+ // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
+ // CHECK-X86-64: ret i32 %[[trunc]]
+ // CHECK-PPC64: define zeroext i32 @_ZN2N06read31
+ // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
+ // CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]]
+ // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 8
+ // CHECK-PPC64: %[[and:.*]] = and i64 %[[shr]], 3
+ // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
+ // CHECK-PPC64: ret i32 %[[trunc]]
+ return s->b31;
+ }
+ unsigned read70(S* s) {
+ // CHECK-X86-64: define i32 @_ZN2N06read70
+ // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
+ // CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]]
+ // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 56
+ // CHECK-X86-64: %[[and:.*]] = and i64 %[[shr]], 63
+ // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
+ // CHECK-X86-64: ret i32 %[[trunc]]
+ // CHECK-PPC64: define zeroext i32 @_ZN2N06read70
+ // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
+ // CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]]
+ // CHECK-PPC64: %[[shr:.*]] = lshr i64 %[[val]], 2
+ // CHECK-PPC64: %[[and:.*]] = and i64 %[[shr]], 63
+ // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
+ // CHECK-PPC64: ret i32 %[[trunc]]
+ return s->b70;
+ }
+ unsigned read71(S* s) {
+ // CHECK-X86-64: define i32 @_ZN2N06read71
+ // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
+ // CHECK-X86-64: %[[val:.*]] = load i64* %[[ptr]]
+ // CHECK-X86-64: %[[shr:.*]] = lshr i64 %[[val]], 62
+ // CHECK-X86-64: %[[trunc:.*]] = trunc i64 %[[shr]] to i32
+ // CHECK-X86-64: ret i32 %[[trunc]]
+ // CHECK-PPC64: define zeroext i32 @_ZN2N06read71
+ // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i64*
+ // CHECK-PPC64: %[[val:.*]] = load i64* %[[ptr]]
+ // CHECK-PPC64: %[[and:.*]] = and i64 %[[val]], 3
+ // CHECK-PPC64: %[[trunc:.*]] = trunc i64 %[[and]] to i32
+ // CHECK-PPC64: ret i32 %[[trunc]]
+ return s->b71;
+ }
+}
+
+namespace N1 {
+ // Ensure that neither loads nor stores to bitfields are not widened into
+ // other memory locations. (PR13691)
+ //
+ // NOTE: We could potentially widen loads based on their alignment if we are
+ // comfortable requiring that subsequent memory locations within the
+ // alignment-widened load are not volatile.
+ struct S {
+ char a;
+ unsigned b : 1;
+ char c;
+ };
+ unsigned read(S* s) {
+ // CHECK-X86-64: define i32 @_ZN2N14read
+ // CHECK-X86-64: %[[ptr:.*]] = getelementptr inbounds %{{.*}}* %{{.*}}, i32 0, i32 1
+ // CHECK-X86-64: %[[val:.*]] = load i8* %[[ptr]]
+ // CHECK-X86-64: %[[and:.*]] = and i8 %[[val]], 1
+ // CHECK-X86-64: %[[ext:.*]] = zext i8 %[[and]] to i32
+ // CHECK-X86-64: ret i32 %[[ext]]
+ // CHECK-PPC64: define zeroext i32 @_ZN2N14read
+ // CHECK-PPC64: %[[ptr:.*]] = getelementptr inbounds %{{.*}}* %{{.*}}, i32 0, i32 1
+ // CHECK-PPC64: %[[val:.*]] = load i8* %[[ptr]]
+ // CHECK-PPC64: %[[shr:.*]] = lshr i8 %[[val]], 7
+ // CHECK-PPC64: %[[ext:.*]] = zext i8 %[[shr]] to i32
+ // CHECK-PPC64: ret i32 %[[ext]]
+ return s->b;
+ }
+ void write(S* s, unsigned x) {
+ // CHECK-X86-64: define void @_ZN2N15write
+ // CHECK-X86-64: %[[ptr:.*]] = getelementptr inbounds %{{.*}}* %{{.*}}, i32 0, i32 1
+ // CHECK-X86-64: %[[x_trunc:.*]] = trunc i32 %{{.*}} to i8
+ // CHECK-X86-64: %[[old:.*]] = load i8* %[[ptr]]
+ // CHECK-X86-64: %[[x_and:.*]] = and i8 %[[x_trunc]], 1
+ // CHECK-X86-64: %[[old_and:.*]] = and i8 %[[old]], -2
+ // CHECK-X86-64: %[[new:.*]] = or i8 %[[old_and]], %[[x_and]]
+ // CHECK-X86-64: store i8 %[[new]], i8* %[[ptr]]
+ // CHECK-PPC64: define void @_ZN2N15write
+ // CHECK-PPC64: %[[ptr:.*]] = getelementptr inbounds %{{.*}}* %{{.*}}, i32 0, i32 1
+ // CHECK-PPC64: %[[x_trunc:.*]] = trunc i32 %{{.*}} to i8
+ // CHECK-PPC64: %[[old:.*]] = load i8* %[[ptr]]
+ // CHECK-PPC64: %[[x_and:.*]] = and i8 %[[x_trunc]], 1
+ // CHECK-PPC64: %[[x_shl:.*]] = shl i8 %[[x_and]], 7
+ // CHECK-PPC64: %[[old_and:.*]] = and i8 %[[old]], 127
+ // CHECK-PPC64: %[[new:.*]] = or i8 %[[old_and]], %[[x_shl]]
+ // CHECK-PPC64: store i8 %[[new]], i8* %[[ptr]]
+ s->b = x;
+ }
+}
+
+namespace N2 {
+ // Do widen loads and stores to bitfields when those bitfields have padding
+ // within the struct following them.
+ struct S {
+ unsigned b : 24;
+ void *p;
+ };
+ unsigned read(S* s) {
+ // CHECK-X86-64: define i32 @_ZN2N24read
+ // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
+ // CHECK-X86-64: %[[val:.*]] = load i32* %[[ptr]]
+ // CHECK-X86-64: %[[and:.*]] = and i32 %[[val]], 16777215
+ // CHECK-X86-64: ret i32 %[[and]]
+ // CHECK-PPC64: define zeroext i32 @_ZN2N24read
+ // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
+ // CHECK-PPC64: %[[val:.*]] = load i32* %[[ptr]]
+ // CHECK-PPC64: %[[shr:.*]] = lshr i32 %[[val]], 8
+ // CHECK-PPC64: ret i32 %[[shr]]
+ return s->b;
+ }
+ void write(S* s, unsigned x) {
+ // CHECK-X86-64: define void @_ZN2N25write
+ // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
+ // CHECK-X86-64: %[[old:.*]] = load i32* %[[ptr]]
+ // CHECK-X86-64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215
+ // CHECK-X86-64: %[[old_and:.*]] = and i32 %[[old]], -16777216
+ // CHECK-X86-64: %[[new:.*]] = or i32 %[[old_and]], %[[x_and]]
+ // CHECK-X86-64: store i32 %[[new]], i32* %[[ptr]]
+ // CHECK-PPC64: define void @_ZN2N25write
+ // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
+ // CHECK-PPC64: %[[old:.*]] = load i32* %[[ptr]]
+ // CHECK-PPC64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215
+ // CHECK-PPC64: %[[x_shl:.*]] = shl i32 %[[x_and]], 8
+ // CHECK-PPC64: %[[old_and:.*]] = and i32 %[[old]], 255
+ // CHECK-PPC64: %[[new:.*]] = or i32 %[[old_and]], %[[x_shl]]
+ // CHECK-PPC64: store i32 %[[new]], i32* %[[ptr]]
+ s->b = x;
+ }
+}
+
+namespace N3 {
+ // Do widen loads and stores to bitfields through the trailing padding at the
+ // end of a struct.
+ struct S {
+ unsigned b : 24;
+ };
+ unsigned read(S* s) {
+ // CHECK-X86-64: define i32 @_ZN2N34read
+ // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
+ // CHECK-X86-64: %[[val:.*]] = load i32* %[[ptr]]
+ // CHECK-X86-64: %[[and:.*]] = and i32 %[[val]], 16777215
+ // CHECK-X86-64: ret i32 %[[and]]
+ // CHECK-PPC64: define zeroext i32 @_ZN2N34read
+ // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
+ // CHECK-PPC64: %[[val:.*]] = load i32* %[[ptr]]
+ // CHECK-PPC64: %[[shr:.*]] = lshr i32 %[[val]], 8
+ // CHECK-PPC64: ret i32 %[[shr]]
+ return s->b;
+ }
+ void write(S* s, unsigned x) {
+ // CHECK-X86-64: define void @_ZN2N35write
+ // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
+ // CHECK-X86-64: %[[old:.*]] = load i32* %[[ptr]]
+ // CHECK-X86-64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215
+ // CHECK-X86-64: %[[old_and:.*]] = and i32 %[[old]], -16777216
+ // CHECK-X86-64: %[[new:.*]] = or i32 %[[old_and]], %[[x_and]]
+ // CHECK-X86-64: store i32 %[[new]], i32* %[[ptr]]
+ // CHECK-PPC64: define void @_ZN2N35write
+ // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
+ // CHECK-PPC64: %[[old:.*]] = load i32* %[[ptr]]
+ // CHECK-PPC64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215
+ // CHECK-PPC64: %[[x_shl:.*]] = shl i32 %[[x_and]], 8
+ // CHECK-PPC64: %[[old_and:.*]] = and i32 %[[old]], 255
+ // CHECK-PPC64: %[[new:.*]] = or i32 %[[old_and]], %[[x_shl]]
+ // CHECK-PPC64: store i32 %[[new]], i32* %[[ptr]]
+ s->b = x;
+ }
+}
+
+namespace N4 {
+ // Do NOT widen loads and stores to bitfields into padding at the end of
+ // a class which might end up with members inside of it when inside a derived
+ // class.
+ struct Base {
+ virtual ~Base() {}
+
+ unsigned b : 24;
+ };
+ // Imagine some other translation unit introduces:
+#if 0
+ struct Derived : public Base {
+ char c;
+ };
+#endif
+ unsigned read(Base* s) {
+ // FIXME: We should widen this load as long as the function isn't being
+ // instrumented by thread-sanitizer.
+ //
+ // CHECK-X86-64: define i32 @_ZN2N44read
+ // CHECK-X86-64: %[[gep:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1
+ // CHECK-X86-64: %[[ptr:.*]] = bitcast [3 x i8]* %[[gep]] to i24*
+ // CHECK-X86-64: %[[val:.*]] = load i24* %[[ptr]]
+ // CHECK-X86-64: %[[ext:.*]] = zext i24 %[[val]] to i32
+ // CHECK-X86-64: ret i32 %[[ext]]
+ // CHECK-PPC64: define zeroext i32 @_ZN2N44read
+ // CHECK-PPC64: %[[gep:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1
+ // CHECK-PPC64: %[[ptr:.*]] = bitcast [3 x i8]* %[[gep]] to i24*
+ // CHECK-PPC64: %[[val:.*]] = load i24* %[[ptr]]
+ // CHECK-PPC64: %[[ext:.*]] = zext i24 %[[val]] to i32
+ // CHECK-PPC64: ret i32 %[[ext]]
+ return s->b;
+ }
+ void write(Base* s, unsigned x) {
+ // CHECK-X86-64: define void @_ZN2N45write
+ // CHECK-X86-64: %[[gep:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1
+ // CHECK-X86-64: %[[ptr:.*]] = bitcast [3 x i8]* %[[gep]] to i24*
+ // CHECK-X86-64: %[[new:.*]] = trunc i32 %{{.*}} to i24
+ // CHECK-X86-64: store i24 %[[new]], i24* %[[ptr]]
+ // CHECK-PPC64: define void @_ZN2N45write
+ // CHECK-PPC64: %[[gep:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1
+ // CHECK-PPC64: %[[ptr:.*]] = bitcast [3 x i8]* %[[gep]] to i24*
+ // CHECK-PPC64: %[[new:.*]] = trunc i32 %{{.*}} to i24
+ // CHECK-PPC64: store i24 %[[new]], i24* %[[ptr]]
+ s->b = x;
+ }
+}
+
+namespace N5 {
+ // Widen through padding at the end of a struct even if that struct
+ // participates in a union with another struct which has a separate field in
+ // that location. The reasoning is that if the operation is storing to that
+ // member of the union, it must be the active member, and thus we can write
+ // through the padding. If it is a load, it might be a load of a common
+ // prefix through a non-active member, but in such a case the extra bits
+ // loaded are masked off anyways.
+ union U {
+ struct X { unsigned b : 24; char c; } x;
+ struct Y { unsigned b : 24; } y;
+ };
+ unsigned read(U* u) {
+ // CHECK-X86-64: define i32 @_ZN2N54read
+ // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
+ // CHECK-X86-64: %[[val:.*]] = load i32* %[[ptr]]
+ // CHECK-X86-64: %[[and:.*]] = and i32 %[[val]], 16777215
+ // CHECK-X86-64: ret i32 %[[and]]
+ // CHECK-PPC64: define zeroext i32 @_ZN2N54read
+ // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
+ // CHECK-PPC64: %[[val:.*]] = load i32* %[[ptr]]
+ // CHECK-PPC64: %[[shr:.*]] = lshr i32 %[[val]], 8
+ // CHECK-PPC64: ret i32 %[[shr]]
+ return u->y.b;
+ }
+ void write(U* u, unsigned x) {
+ // CHECK-X86-64: define void @_ZN2N55write
+ // CHECK-X86-64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
+ // CHECK-X86-64: %[[old:.*]] = load i32* %[[ptr]]
+ // CHECK-X86-64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215
+ // CHECK-X86-64: %[[old_and:.*]] = and i32 %[[old]], -16777216
+ // CHECK-X86-64: %[[new:.*]] = or i32 %[[old_and]], %[[x_and]]
+ // CHECK-X86-64: store i32 %[[new]], i32* %[[ptr]]
+ // CHECK-PPC64: define void @_ZN2N55write
+ // CHECK-PPC64: %[[ptr:.*]] = bitcast %{{.*}}* %{{.*}} to i32*
+ // CHECK-PPC64: %[[old:.*]] = load i32* %[[ptr]]
+ // CHECK-PPC64: %[[x_and:.*]] = and i32 %{{.*}}, 16777215
+ // CHECK-PPC64: %[[x_shl:.*]] = shl i32 %[[x_and]], 8
+ // CHECK-PPC64: %[[old_and:.*]] = and i32 %[[old]], 255
+ // CHECK-PPC64: %[[new:.*]] = or i32 %[[old_and]], %[[x_shl]]
+ // CHECK-PPC64: store i32 %[[new]], i32* %[[ptr]]
+ u->y.b = x;
+ }
+}
+
+namespace N6 {
+ // Zero-length bitfields partition the memory locations of bitfields for the
+ // purposes of the memory model. That means stores must not span zero-length
+ // bitfields and loads may only span them when we are not instrumenting with
+ // thread sanitizer.
+ // FIXME: We currently don't widen loads even without thread sanitizer, even
+ // though we could.
+ struct S {
+ unsigned b1 : 24;
+ unsigned char : 0;
+ unsigned char b2 : 8;
+ };
+ unsigned read(S* s) {
+ // CHECK-X86-64: define i32 @_ZN2N64read
+ // CHECK-X86-64: %[[ptr1:.*]] = bitcast {{.*}}* %{{.*}} to i24*
+ // CHECK-X86-64: %[[val1:.*]] = load i24* %[[ptr1]]
+ // CHECK-X86-64: %[[ext1:.*]] = zext i24 %[[val1]] to i32
+ // CHECK-X86-64: %[[ptr2:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1
+ // CHECK-X86-64: %[[val2:.*]] = load i8* %[[ptr2]]
+ // CHECK-X86-64: %[[ext2:.*]] = zext i8 %[[val2]] to i32
+ // CHECK-X86-64: %[[add:.*]] = add nsw i32 %[[ext1]], %[[ext2]]
+ // CHECK-X86-64: ret i32 %[[add]]
+ // CHECK-PPC64: define zeroext i32 @_ZN2N64read
+ // CHECK-PPC64: %[[ptr1:.*]] = bitcast {{.*}}* %{{.*}} to i24*
+ // CHECK-PPC64: %[[val1:.*]] = load i24* %[[ptr1]]
+ // CHECK-PPC64: %[[ext1:.*]] = zext i24 %[[val1]] to i32
+ // CHECK-PPC64: %[[ptr2:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1
+ // CHECK-PPC64: %[[val2:.*]] = load i8* %[[ptr2]]
+ // CHECK-PPC64: %[[ext2:.*]] = zext i8 %[[val2]] to i32
+ // CHECK-PPC64: %[[add:.*]] = add nsw i32 %[[ext1]], %[[ext2]]
+ // CHECK-PPC64: ret i32 %[[add]]
+ return s->b1 + s->b2;
+ }
+ void write(S* s, unsigned x) {
+ // CHECK-X86-64: define void @_ZN2N65write
+ // CHECK-X86-64: %[[ptr1:.*]] = bitcast {{.*}}* %{{.*}} to i24*
+ // CHECK-X86-64: %[[new1:.*]] = trunc i32 %{{.*}} to i24
+ // CHECK-X86-64: store i24 %[[new1]], i24* %[[ptr1]]
+ // CHECK-X86-64: %[[new2:.*]] = trunc i32 %{{.*}} to i8
+ // CHECK-X86-64: %[[ptr2:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1
+ // CHECK-X86-64: store i8 %[[new2]], i8* %[[ptr2]]
+ // CHECK-PPC64: define void @_ZN2N65write
+ // CHECK-PPC64: %[[ptr1:.*]] = bitcast {{.*}}* %{{.*}} to i24*
+ // CHECK-PPC64: %[[new1:.*]] = trunc i32 %{{.*}} to i24
+ // CHECK-PPC64: store i24 %[[new1]], i24* %[[ptr1]]
+ // CHECK-PPC64: %[[new2:.*]] = trunc i32 %{{.*}} to i8
+ // CHECK-PPC64: %[[ptr2:.*]] = getelementptr inbounds {{.*}}* %{{.*}}, i32 0, i32 1
+ // CHECK-PPC64: store i8 %[[new2]], i8* %[[ptr2]]
+ s->b1 = x;
+ s->b2 = x;
+ }
+}
diff --git a/test/CodeGenCXX/blocks-cxx11.cpp b/test/CodeGenCXX/blocks-cxx11.cpp
index 996db1a..3f0380a 100644
--- a/test/CodeGenCXX/blocks-cxx11.cpp
+++ b/test/CodeGenCXX/blocks-cxx11.cpp
@@ -82,3 +82,33 @@ namespace test_complex_int_ref_mutable {
}
}
+// rdar://13295759
+namespace test_block_in_lambda {
+ void takeBlock(void (^block)());
+
+ // The captured variable has to be non-POD so that we have a copy expression.
+ struct A {
+ void *p;
+ A(const A &);
+ ~A();
+ void use() const;
+ };
+
+ void test(A a) {
+ auto lambda = [a]() {
+ takeBlock(^{ a.use(); });
+ };
+ lambda(); // make sure we emit the invocation function
+ }
+ // CHECK: define internal void @"_ZZN20test_block_in_lambda4testENS_1AEENK3$_0clEv"(
+ // CHECK: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8
+ // CHECK: [[THIS:%.*]] = load [[LAMBDA_T:%.*]]**
+ // CHECK: [[TO_DESTROY:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+ // CHECK: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+ // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[LAMBDA_T]]* [[THIS]], i32 0, i32 0
+ // CHECK-NEXT: call void @_ZN20test_block_in_lambda1AC1ERKS0_({{.*}}* [[T0]], {{.*}}* [[T1]])
+ // CHECK-NEXT: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
+ // CHECK-NEXT: call void @_ZN20test_block_in_lambda9takeBlockEU13block_pointerFvvE(void ()* [[T0]])
+ // CHECK-NEXT: call void @_ZN20test_block_in_lambda1AD1Ev({{.*}}* [[TO_DESTROY]])
+ // CHECK-NEXT: ret void
+}
diff --git a/test/CodeGenCXX/blocks.cpp b/test/CodeGenCXX/blocks.cpp
index 1500c0d..81eef0e 100644
--- a/test/CodeGenCXX/blocks.cpp
+++ b/test/CodeGenCXX/blocks.cpp
@@ -120,9 +120,11 @@ namespace test4 {
}
// CHECK: define void @_ZN5test44testEv()
// CHECK: define internal void @___ZN5test44testEv_block_invoke
- // CHECK: [[TMP:%.*]] = alloca [[A:%.*]], align 1
- // CHECK-NEXT: bitcast i8*
- // CHECK-NEXT: call void @_ZN5test41AC1Ev([[A]]* [[TMP]])
+ // CHECK: [[TMP:%.*]] = alloca [[A:%.*]], align 1
+ // CHECK-NEXT: store i8* [[BLOCKDESC:%.*]], i8** {{.*}}, align 8
+ // CHECK-NEXT: load i8*
+ // CHECK-NEXT: bitcast i8* [[BLOCKDESC]] to <{ i8*, i32, i32, i8*, %struct.__block_descriptor* }>*
+ // CHECK: call void @_ZN5test41AC1Ev([[A]]* [[TMP]])
// CHECK-NEXT: call void @_ZN5test43fooENS_1AE([[A]]* [[TMP]])
// CHECK-NEXT: call void @_ZN5test41AD1Ev([[A]]* [[TMP]])
// CHECK-NEXT: ret void
@@ -226,3 +228,28 @@ namespace test8 {
template int X::foo<int>();
}
+
+// rdar://13459289
+namespace test9 {
+ struct B {
+ void *p;
+ B();
+ B(const B&);
+ ~B();
+ };
+
+ void use_block(void (^)());
+ void use_block_2(void (^)(), const B &a);
+
+ // Ensuring that creating a non-trivial capture copy expression
+ // doesn't end up stealing the block registration for the block we
+ // just parsed. That block must have captures or else it won't
+ // force registration. Must occur within a block for some reason.
+ void test() {
+ B x;
+ use_block(^{
+ int y;
+ use_block_2(^{ (void)y; }, x);
+ });
+ }
+}
diff --git a/test/CodeGenCXX/bool-bitfield.cpp b/test/CodeGenCXX/bool-bitfield.cpp
new file mode 100644
index 0000000..06bdf2b
--- /dev/null
+++ b/test/CodeGenCXX/bool-bitfield.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -verify -emit-llvm -o - %s \
+// RUN: | FileCheck %s
+
+// PR14638; make sure this doesn't crash.
+struct A {
+ bool m_sorted : 1;
+};
+void func1(bool b, A& a1)
+{
+ if ((a1.m_sorted = b)) {}
+}
+// CHECK: define void @_Z5func1bR1A
+// CHECK: br i1
+// CHECK: ret void
diff --git a/test/CodeGenCXX/builtins.cpp b/test/CodeGenCXX/builtins.cpp
index 0629c31..c9b0bff 100644
--- a/test/CodeGenCXX/builtins.cpp
+++ b/test/CodeGenCXX/builtins.cpp
@@ -4,6 +4,6 @@
extern "C" char memmove();
int main() {
- // CHECK: call signext i8 @memmove()
+ // CHECK: call {{signext i8|i8}} @memmove()
return memmove();
}
diff --git a/test/CodeGenCXX/c-linkage.cpp b/test/CodeGenCXX/c-linkage.cpp
index b1f07b7..f6e64d9 100644
--- a/test/CodeGenCXX/c-linkage.cpp
+++ b/test/CodeGenCXX/c-linkage.cpp
@@ -11,3 +11,23 @@ extern "C" {
}
// CHECK: define void @_ZN1N1X1fEv
+
+extern "C" {
+ static void test2_f() {
+ }
+ // CHECK: define internal void @_Z7test2_fv
+ static void test2_f(int x) {
+ }
+ // CHECK: define internal void @_Z7test2_fi
+ void test2_use() {
+ test2_f();
+ test2_f(42);
+ }
+}
+
+extern "C" {
+ struct test3_s {
+ };
+ bool operator==(const int& a, const test3_s& b) {
+ }
+}
diff --git a/test/CodeGenCXX/catch-undef-behavior.cpp b/test/CodeGenCXX/catch-undef-behavior.cpp
index fd9e3d7..d6d0edfa 100644
--- a/test/CodeGenCXX/catch-undef-behavior.cpp
+++ b/test/CodeGenCXX/catch-undef-behavior.cpp
@@ -1,7 +1,15 @@
-// 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
+// RUN: %clang_cc1 -fsanitize=signed-integer-overflow,integer-divide-by-zero,float-divide-by-zero,shift,unreachable,return,vla-bound,alignment,null,vptr,object-size,float-cast-overflow,bool,enum,bounds -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
+
+struct S {
+ double d;
+ int a, b;
+ virtual int f();
+};
+
+struct T : S {};
// CHECK: @_Z17reference_binding
-void reference_binding(int *p) {
+void reference_binding(int *p, S *q) {
// 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
@@ -16,13 +24,11 @@ void reference_binding(int *p) {
// 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();
-};
+ // A reference is not required to refer to an object within its lifetime.
+ // CHECK-NOT: __ubsan_handle_dynamic_type_cache_miss
+ S &r2 = *q;
+}
// CHECK: @_Z13member_access
void member_access(S *p) {
@@ -70,6 +76,8 @@ void member_access(S *p) {
// CHECK-NEXT: br i1
// CHECK: call void @__ubsan_handle_dynamic_type_cache_miss({{.*}}, i64 %{{.*}}, i64 %[[HASH]])
+ // CHECK-NOT: unreachable
+ // CHECK: {{.*}}:
// (2) Check 'p->b' is appropriately sized and aligned for a load.
@@ -103,6 +111,8 @@ void member_access(S *p) {
// 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 %{{.*}})
+ // CHECK-NOT: unreachable
+ // CHECK: {{.*}}:
k = p->f();
}
@@ -120,7 +130,12 @@ int lsh_overflow(int a, int b) {
// 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: %[[VALID:.*]] = phi i1 [ %[[INBOUNDS]], {{.*}} ], [ %[[NO_OVERFLOW]], {{.*}} ]
+ // CHECK-NEXT: br i1 %[[VALID]]
+
+ // CHECK: call void @__ubsan_handle_shift_out_of_bounds
+ // CHECK-NOT: call void @__ubsan_handle_shift_out_of_bounds
// CHECK: %[[RET:.*]] = shl i32 %[[LHS]], %[[RHS]]
// CHECK-NEXT: ret i32 %[[RET]]
@@ -129,6 +144,181 @@ int lsh_overflow(int a, int b) {
// CHECK: @_Z9no_return
int no_return() {
- // CHECK: call void @__ubsan_handle_missing_return(i8* bitcast ({{.*}}* @{{.*}} to i8*)) noreturn nounwind
+ // CHECK: call void @__ubsan_handle_missing_return(i8* bitcast ({{.*}}* @{{.*}} to i8*)) [[NR_NUW:#[0-9]+]]
// CHECK-NEXT: unreachable
}
+
+// CHECK: @_Z9sour_bool
+bool sour_bool(bool *p) {
+ // CHECK: %[[OK:.*]] = icmp ule i8 {{.*}}, 1
+ // CHECK: br i1 %[[OK]]
+ // CHECK: call void @__ubsan_handle_load_invalid_value(i8* bitcast ({{.*}}), i64 {{.*}})
+ return *p;
+}
+
+enum E1 { e1a = 0, e1b = 127 } e1;
+enum E2 { e2a = -1, e2b = 64 } e2;
+enum E3 { e3a = (1u << 31) - 1 } e3;
+
+// CHECK: @_Z14bad_enum_value
+int bad_enum_value() {
+ // CHECK: %[[E1:.*]] = icmp ule i32 {{.*}}, 127
+ // CHECK: br i1 %[[E1]]
+ // CHECK: call void @__ubsan_handle_load_invalid_value(
+ int a = e1;
+
+ // CHECK: %[[E2HI:.*]] = icmp sle i32 {{.*}}, 127
+ // CHECK: %[[E2LO:.*]] = icmp sge i32 {{.*}}, -128
+ // CHECK: %[[E2:.*]] = and i1 %[[E2HI]], %[[E2LO]]
+ // CHECK: br i1 %[[E2]]
+ // CHECK: call void @__ubsan_handle_load_invalid_value(
+ int b = e2;
+
+ // CHECK: %[[E3:.*]] = icmp ule i32 {{.*}}, 2147483647
+ // CHECK: br i1 %[[E3]]
+ // CHECK: call void @__ubsan_handle_load_invalid_value(
+ int c = e3;
+ return a + b + c;
+}
+
+// CHECK: @_Z20bad_downcast_pointer
+void bad_downcast_pointer(S *p) {
+ // CHECK: %[[NONNULL:.*]] = icmp ne {{.*}}, null
+ // CHECK: br i1 %[[NONNULL]],
+
+ // CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64(
+ // CHECK: %[[E1:.*]] = icmp uge i64 %[[SIZE]], 24
+ // CHECK: %[[MISALIGN:.*]] = and i64 %{{.*}}, 7
+ // CHECK: %[[E2:.*]] = icmp eq i64 %[[MISALIGN]], 0
+ // CHECK: %[[E12:.*]] = and i1 %[[E1]], %[[E2]]
+ // CHECK: br i1 %[[E12]],
+
+ // CHECK: call void @__ubsan_handle_type_mismatch
+ // CHECK: br label
+
+ // CHECK: br i1 %{{.*}},
+
+ // CHECK: call void @__ubsan_handle_dynamic_type_cache_miss
+ // CHECK: br label
+ (void) static_cast<T*>(p);
+}
+
+// CHECK: @_Z22bad_downcast_reference
+void bad_downcast_reference(S &p) {
+ // CHECK: %[[E1:.*]] = icmp ne {{.*}}, null
+ // CHECK-NOT: br i1
+ // CHECK: %[[SIZE:.*]] = call i64 @llvm.objectsize.i64(
+ // CHECK: %[[E2:.*]] = icmp uge i64 %[[SIZE]], 24
+ // CHECK: %[[E12:.*]] = and i1 %[[E1]], %[[E2]]
+ // CHECK: %[[MISALIGN:.*]] = and i64 %{{.*}}, 7
+ // CHECK: %[[E3:.*]] = icmp eq i64 %[[MISALIGN]], 0
+ // CHECK: %[[E123:.*]] = and i1 %[[E12]], %[[E3]]
+ // CHECK: br i1 %[[E123]],
+
+ // CHECK: call void @__ubsan_handle_type_mismatch
+ // CHECK: br label
+
+ // CHECK: br i1 %{{.*}},
+
+ // CHECK: call void @__ubsan_handle_dynamic_type_cache_miss
+ // CHECK: br label
+ (void) static_cast<T&>(p);
+}
+
+// CHECK: @_Z11array_index
+int array_index(const int (&a)[4], int n) {
+ // CHECK: %[[K1_OK:.*]] = icmp ult i64 %{{.*}}, 4
+ // CHECK: br i1 %[[K1_OK]]
+ // CHECK: call void @__ubsan_handle_out_of_bounds(
+ int k1 = a[n];
+
+ // CHECK: %[[R1_OK:.*]] = icmp ule i64 %{{.*}}, 4
+ // CHECK: br i1 %[[R1_OK]]
+ // CHECK: call void @__ubsan_handle_out_of_bounds(
+ const int *r1 = &a[n];
+
+ // CHECK: %[[K2_OK:.*]] = icmp ult i64 %{{.*}}, 8
+ // CHECK: br i1 %[[K2_OK]]
+ // CHECK: call void @__ubsan_handle_out_of_bounds(
+ int k2 = ((const int(&)[8])a)[n];
+
+ // CHECK: %[[K3_OK:.*]] = icmp ult i64 %{{.*}}, 4
+ // CHECK: br i1 %[[K3_OK]]
+ // CHECK: call void @__ubsan_handle_out_of_bounds(
+ int k3 = n[a];
+
+ return k1 + *r1 + k2;
+}
+
+// CHECK: @_Z17multi_array_index
+int multi_array_index(int n, int m) {
+ int arr[4][6];
+
+ // CHECK: %[[IDX2_OK:.*]] = icmp ult i64 %{{.*}}, 6
+ // CHECK: br i1 %[[IDX2_OK]]
+ // CHECK: call void @__ubsan_handle_out_of_bounds(
+
+ // CHECK: %[[IDX1_OK:.*]] = icmp ult i64 %{{.*}}, 4
+ // CHECK: br i1 %[[IDX1_OK]]
+ // CHECK: call void @__ubsan_handle_out_of_bounds(
+ return arr[n][m];
+}
+
+// CHECK: @_Z11array_arith
+int array_arith(const int (&a)[4], int n) {
+ // CHECK: %[[K1_OK:.*]] = icmp ule i64 %{{.*}}, 4
+ // CHECK: br i1 %[[K1_OK]]
+ // CHECK: call void @__ubsan_handle_out_of_bounds(
+ const int *k1 = a + n;
+
+ // CHECK: %[[K2_OK:.*]] = icmp ule i64 %{{.*}}, 8
+ // CHECK: br i1 %[[K2_OK]]
+ // CHECK: call void @__ubsan_handle_out_of_bounds(
+ const int *k2 = (const int(&)[8])a + n;
+
+ return *k1 + *k2;
+}
+
+struct ArrayMembers {
+ int a1[5];
+ int a2[1];
+};
+// CHECK: @_Z18struct_array_index
+int struct_array_index(ArrayMembers *p, int n) {
+ // CHECK: %[[IDX_OK:.*]] = icmp ult i64 %{{.*}}, 5
+ // CHECK: br i1 %[[IDX_OK]]
+ // CHECK: call void @__ubsan_handle_out_of_bounds(
+ return p->a1[n];
+}
+
+// CHECK: @_Z16flex_array_index
+int flex_array_index(ArrayMembers *p, int n) {
+ // CHECK-NOT: call void @__ubsan_handle_out_of_bounds(
+ return p->a2[n];
+}
+
+extern int incomplete[];
+// CHECK: @_Z22incomplete_array_index
+int incomplete_array_index(int n) {
+ // CHECK-NOT: call void @__ubsan_handle_out_of_bounds(
+ return incomplete[n];
+}
+
+typedef __attribute__((ext_vector_type(4))) int V4I;
+// CHECK: @_Z12vector_index
+int vector_index(V4I v, int n) {
+ // CHECK: %[[IDX_OK:.*]] = icmp ult i64 %{{.*}}, 4
+ // CHECK: br i1 %[[IDX_OK]]
+ // CHECK: call void @__ubsan_handle_out_of_bounds(
+ return v[n];
+}
+
+// CHECK: @_Z12string_index
+char string_index(int n) {
+ // CHECK: %[[IDX_OK:.*]] = icmp ult i64 %{{.*}}, 6
+ // CHECK: br i1 %[[IDX_OK]]
+ // CHECK: call void @__ubsan_handle_out_of_bounds(
+ return "Hello"[n];
+}
+
+// CHECK: attributes [[NR_NUW]] = { noreturn nounwind }
diff --git a/test/CodeGenCXX/constructor-alias.cpp b/test/CodeGenCXX/constructor-alias.cpp
new file mode 100644
index 0000000..18a4777
--- /dev/null
+++ b/test/CodeGenCXX/constructor-alias.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-llvm -triple mipsel--linux-gnu -mconstructor-aliases -o - %s | FileCheck %s
+
+// The target attribute code used to get confused with aliases. Make sure
+// we don't crash when an alias is used.
+
+struct B {
+ B();
+};
+B::B() {
+}
+
+// CHECK: @_ZN1BC1Ev = alias void (%struct.B*)* @_ZN1BC2Ev
diff --git a/test/CodeGenCXX/constructor-destructor-return-this.cpp b/test/CodeGenCXX/constructor-destructor-return-this.cpp
new file mode 100644
index 0000000..1ff922d
--- /dev/null
+++ b/test/CodeGenCXX/constructor-destructor-return-this.cpp
@@ -0,0 +1,60 @@
+//RUN: %clang_cc1 %s -emit-llvm -o - -triple=thumbv7-apple-ios3.0 -target-abi apcs-gnu | FileCheck %s
+
+// For constructors/desctructors that return 'this', if there exists a callsite
+// that returns 'this' and is immediately before the return instruction, make
+// sure we are using the return value from the callsite.
+// rdar://12818789
+
+// CHECK: define linkonce_odr [[A:%.*]] @_ZN11ObjectCacheC1Ev([[A]] %this) unnamed_addr
+// CHECK: [[THIS1:%.*]] = call [[A]] @_ZN11ObjectCacheC2Ev(
+// CHECK-NEXT: ret [[A]] [[THIS1]]
+
+// CHECK: define linkonce_odr [[A:%.*]] @_ZN5TimerI11ObjectCacheEC1EPS0_MS0_FvPS1_E([[A]] %this
+// CHECK: [[THIS1:%.*]] = call [[A]] @_ZN5TimerI11ObjectCacheEC2EPS0_MS0_FvPS1_E(
+// CHECK-NEXT: ret [[A]] [[THIS1]]
+
+// CHECK: define linkonce_odr [[A:%.*]] @_ZN5TimerI11ObjectCacheED1Ev([[A]] %this) unnamed_addr
+// CHECK: [[THIS1:%.*]] = call [[A]] @_ZN5TimerI11ObjectCacheED2Ev(
+// CHECK-NEXT: ret [[A]] [[THIS1]]
+
+// CHECK: define linkonce_odr [[A:%.*]] @_ZN5TimerI11ObjectCacheED2Ev([[A]] %this) unnamed_addr
+// CHECK: [[THIS1:%.*]] = call [[B:%.*]] @_ZN9TimerBaseD2Ev(
+// CHECK-NEXT: [[THIS2:%.*]] = bitcast [[B]] [[THIS1]] to [[A]]
+// CHECK-NEXT: ret [[A]] [[THIS2]]
+
+class TimerBase {
+public:
+ TimerBase();
+ virtual ~TimerBase();
+};
+
+template <typename TimerFiredClass> class Timer : public TimerBase {
+public:
+ typedef void (TimerFiredClass::*TimerFiredFunction)(Timer*);
+
+ Timer(TimerFiredClass* o, TimerFiredFunction f)
+ : m_object(o), m_function(f) { }
+
+private:
+ virtual void fired() { (m_object->*m_function)(this); }
+
+ TimerFiredClass* m_object;
+ TimerFiredFunction m_function;
+};
+
+class ObjectCache {
+public:
+ explicit ObjectCache();
+ ~ObjectCache();
+
+private:
+ Timer<ObjectCache> m_notificationPostTimer;
+};
+
+inline ObjectCache::ObjectCache() : m_notificationPostTimer(this, 0) { }
+inline ObjectCache::~ObjectCache() { }
+
+ObjectCache *test() {
+ ObjectCache *dd = new ObjectCache();
+ return dd;
+}
diff --git a/test/CodeGenCXX/copy-assign-synthesis-1.cpp b/test/CodeGenCXX/copy-assign-synthesis-1.cpp
index 46d0483..5d09b54 100644
--- a/test/CodeGenCXX/copy-assign-synthesis-1.cpp
+++ b/test/CodeGenCXX/copy-assign-synthesis-1.cpp
@@ -96,14 +96,8 @@ int main() {
// CHECK-LP64: .globl __ZN1XaSERKS_
// CHECK-LP64: .weak_definition __ZN1XaSERKS_
// CHECK-LP64: __ZN1XaSERKS_:
-// CHECK-LP64: .globl __ZN1QaSERKS_
-// CHECK-LP64: .weak_definition __ZN1QaSERKS_
-// CHECK-LP64: __ZN1QaSERKS_:
// CHECK-LP32: .globl __ZN1XaSERKS_
// CHECK-LP32: .weak_definition __ZN1XaSERKS_
// CHECK-LP32: __ZN1XaSERKS_:
-// CHECK-LP32: .globl __ZN1QaSERKS_
-// CHECK-LP32: .weak_definition __ZN1QaSERKS_
-// CHECK-LP32: __ZN1QaSERKS_:
diff --git a/test/CodeGenCXX/coverage.cpp b/test/CodeGenCXX/coverage.cpp
new file mode 100644
index 0000000..1f1611b
--- /dev/null
+++ b/test/CodeGenCXX/coverage.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -test-coverage -femit-coverage-notes | FileCheck %s
+
+extern "C" void test_name1() {}
+void test_name2() {}
+
+// CHECK: metadata !"test_name1", metadata !"test_name1", metadata !"",{{.*}}DW_TAG_subprogram
+// CHECK: metadata !"test_name2", metadata !"test_name2", metadata !"_Z10test_name2v",{{.*}}DW_TAG_subprogram
diff --git a/test/CodeGenCXX/cp-blocks-linetables.cpp b/test/CodeGenCXX/cp-blocks-linetables.cpp
new file mode 100644
index 0000000..d5dd46c
--- /dev/null
+++ b/test/CodeGenCXX/cp-blocks-linetables.cpp
@@ -0,0 +1,61 @@
+// RUN: %clang_cc1 -fblocks -g -emit-llvm %s -o - | FileCheck %s
+// Ensure that we generate a line table entry for the block cleanup.
+// CHECK: define {{.*}} @__main_block_invoke
+// CHECK: _NSConcreteStackBlock
+// CHECK: = bitcast {{.*}}, !dbg ![[L1:[0-9]+]]
+// CHECK-NOT: call {{.*}} @_Block_object_dispose{{.*}}, !dbg ![[L1]]
+// CHECK: ret
+
+void * _NSConcreteStackBlock;
+#ifdef __cplusplus
+extern "C" void exit(int);
+#else
+extern void exit(int);
+#endif
+
+enum numbers {
+ zero, one, two, three, four
+};
+
+typedef enum numbers (^myblock)(enum numbers);
+
+
+double test(myblock I) {
+ return I(three);
+}
+
+int main() {
+ __block enum numbers x = one;
+ __block enum numbers y = two;
+
+ /* Breakpoint for first Block function. */
+ myblock CL = ^(enum numbers z)
+ { enum numbers savex = x;
+ { __block enum numbers x = savex;
+ y = z;
+ if (y != three)
+ exit (6);
+ test (
+ /* Breakpoint for second Block function. */
+ ^ (enum numbers z) {
+ if (y != three) {
+ exit(1);
+ }
+ if (x != one)
+ exit(2);
+ x = z;
+ if (x != three)
+ exit(3);
+ if (y != three)
+ exit(4);
+ return (enum numbers) four;
+ });}
+ return x;
+ };
+
+ enum numbers res = (enum numbers)test(CL);
+
+ if (res != one)
+ exit (5);
+ return 0;
+}
diff --git a/test/CodeGenCXX/cxx0x-delegating-ctors.cpp b/test/CodeGenCXX/cxx0x-delegating-ctors.cpp
index 338159c..e909f03 100644
--- a/test/CodeGenCXX/cxx0x-delegating-ctors.cpp
+++ b/test/CodeGenCXX/cxx0x-delegating-ctors.cpp
@@ -29,12 +29,12 @@ delegator::delegator(bool)
// CHECK: define {{.*}} @_ZN9delegatorC1Ec
// CHECK: {{.*}} @_ZN9delegatorC1Eb
// CHECK: void @__cxa_throw
-// CHECK: void @_ZSt9terminatev
+// CHECK: void @__clang_call_terminate
// CHECK: {{.*}} @_ZN9delegatorD1Ev
// CHECK: define {{.*}} @_ZN9delegatorC2Ec
// CHECK: {{.*}} @_ZN9delegatorC2Eb
// CHECK: void @__cxa_throw
-// CHECK: void @_ZSt9terminatev
+// CHECK: void @__clang_call_terminate
// CHECK: {{.*}} @_ZN9delegatorD2Ev
delegator::delegator(char)
: delegator(true) {
@@ -65,3 +65,37 @@ namespace PR12890 {
}
// CHECK: define {{.*}} @_ZN7PR128901XC1Ei(%"class.PR12890::X"* %this, i32)
// CHECK: call void @llvm.memset.p0i8.{{i32|i64}}(i8* {{.*}}, i8 0, {{i32|i64}} 4, i32 4, i1 false)
+
+namespace PR14588 {
+ void other();
+
+ class Base {
+ public:
+ Base() { squawk(); }
+ virtual ~Base() {}
+
+ virtual void squawk() { other(); }
+ };
+
+
+ class Foo : public virtual Base {
+ public:
+ Foo();
+ Foo(const void * inVoid);
+ virtual ~Foo() {}
+
+ virtual void squawk() { other(); }
+ };
+
+ // CHECK: define void @_ZN7PR145883FooC1Ev(%"class.PR14588::Foo"*
+ // CHECK: call void @_ZN7PR145883FooC1EPKv(
+ // CHECK: invoke void @_ZN7PR145885otherEv()
+ // CHECK: call void @_ZN7PR145883FooD1Ev
+ // CHECK: resume
+
+ Foo::Foo() : Foo(__null) { other(); }
+ Foo::Foo(const void *inVoid) {
+ squawk();
+ }
+
+}
diff --git a/test/CodeGenCXX/cxx0x-initializer-array.cpp b/test/CodeGenCXX/cxx0x-initializer-array.cpp
index df68997..3144e94 100644
--- a/test/CodeGenCXX/cxx0x-initializer-array.cpp
+++ b/test/CodeGenCXX/cxx0x-initializer-array.cpp
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -triple i386-unknown-unknown -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 -Wno-address-of-temporary | FileCheck %s
+
+// CHECK: @[[THREE_NULL_MEMPTRS:.*]] = private constant [3 x i32] [i32 -1, i32 -1, i32 -1]
struct A { int a[1]; };
typedef A x[];
@@ -7,4 +9,103 @@ int f() {
// CHECK: define i32 @_Z1fv
// CHECK: store i32 1
// (It's okay if the output changes here, as long as we don't crash.)
+ return 0;
+}
+
+namespace ValueInitArrayOfMemPtr {
+ struct S {};
+ typedef int (S::*p);
+ typedef p a[3];
+ void f(const a &);
+
+ struct Agg1 {
+ int n;
+ p x;
+ };
+
+ struct Agg2 {
+ int n;
+ a x;
+ };
+
+ struct S1 {
+ p x;
+ S1();
+ };
+
+ // CHECK: define void @_ZN22ValueInitArrayOfMemPtr1fEi
+ void f(int n) {
+ Agg1 a = { n };
+ // CHECK: store i32 -1,
+
+ Agg2 b = { n };
+ // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* %{{.*}}, i8* bitcast ([3 x i32]* @[[THREE_NULL_MEMPTRS]] to i8*), i32 12, i32 4, i1 false)
+ }
+
+ // CHECK: define void @_ZN22ValueInitArrayOfMemPtr1gEv
+ void g() {
+ // CHECK: store i32 -1,
+ f(a{});
+ }
+}
+
+namespace array_dtor {
+ struct S { S(); ~S(); };
+ using T = S[3];
+ void f(const T &);
+ void f(T *);
+ // CHECK: define void @_ZN10array_dtor1gEv(
+ void g() {
+ // CHECK: %[[ARRAY:.*]] = alloca [3 x
+ // CHECK: br
+
+ // Construct loop.
+ // CHECK: call void @_ZN10array_dtor1SC1Ev(
+ // CHECK: br i1
+
+ // CHECK: call void @_ZN10array_dtor1fERA3_KNS_1SE(
+ // CHECK: br
+
+ // Destruct loop.
+ // CHECK: call void @_ZN10array_dtor1SD1Ev(
+ // CHECK: br i1
+ f(T{});
+
+ // CHECK: ret void
+ }
+ // CHECK: define void @_ZN10array_dtor1hEv(
+ void h() {
+ // CHECK: %[[ARRAY:.*]] = alloca [3 x
+ // CHECK: br
+
+ // CHECK: call void @_ZN10array_dtor1SC1Ev(
+ // CHECK: br i1
+ T &&t = T{};
+
+ // CHECK: call void @_ZN10array_dtor1fERA3_KNS_1SE(
+ // CHECK: br
+ f(t);
+
+ // CHECK: call void @_ZN10array_dtor1SD1Ev(
+ // CHECK: br i1
+
+ // CHECK: ret void
+ }
+ // CHECK: define void @_ZN10array_dtor1iEv(
+ void i() {
+ // CHECK: %[[ARRAY:.*]] = alloca [3 x
+ // CHECK: br
+
+ // CHECK: call void @_ZN10array_dtor1SC1Ev(
+ // CHECK: br i1
+
+ // CHECK: call void @_ZN10array_dtor1fEPA3_NS_1SE(
+ // CHECK: br
+
+ // CHECK: call void @_ZN10array_dtor1SD1Ev(
+ // CHECK: br i1
+ f(&T{});
+
+ // CHECK: ret void
+ }
}
diff --git a/test/CodeGenCXX/cxx11-exception-spec.cpp b/test/CodeGenCXX/cxx11-exception-spec.cpp
index 194b80c..49ca861 100644
--- a/test/CodeGenCXX/cxx11-exception-spec.cpp
+++ b/test/CodeGenCXX/cxx11-exception-spec.cpp
@@ -10,99 +10,99 @@ template<typename T> struct S {
static void g() noexcept(sizeof(T) == 4);
};
-// CHECK: define {{.*}} @_Z1fIsEvv() {
+// CHECK: define {{.*}} @_Z1fIsEvv() [[NONE:#[0-9]+]] {
template<> void f<short>() { h(); }
-// CHECK: define {{.*}} @_Z1fIA2_sEvv() nounwind {
+// CHECK: define {{.*}} @_Z1fIA2_sEvv() [[NUW:#[0-9]+]] {
template<> void f<short[2]>() noexcept { h(); }
// CHECK: define {{.*}} @_ZN1SIsE1fEv()
-// CHECK-NOT: nounwind
+// CHECK-NOT: [[NUW]]
template<> void S<short>::f() { h(); }
-// CHECK: define {{.*}} @_ZN1SIA2_sE1fEv() nounwind
+// CHECK: define {{.*}} @_ZN1SIA2_sE1fEv() [[NUW]]
template<> void S<short[2]>::f() noexcept { h(); }
-// CHECK: define {{.*}} @_Z1fIDsEvv() {
+// CHECK: define {{.*}} @_Z1fIDsEvv() [[NONE]] {
template void f<char16_t>();
-// CHECK: define {{.*}} @_Z1fIA2_DsEvv() nounwind {
+// CHECK: define {{.*}} @_Z1fIA2_DsEvv() [[NUW]] {
template void f<char16_t[2]>();
// CHECK: define {{.*}} @_ZN1SIDsE1fEv()
-// CHECK-NOT: nounwind
+// CHECK-NOT: [[NUW]]
template void S<char16_t>::f();
-// CHECK: define {{.*}} @_ZN1SIA2_DsE1fEv() nounwind
+// CHECK: define {{.*}} @_ZN1SIA2_DsE1fEv() [[NUW]]
template void S<char16_t[2]>::f();
void h() {
- // CHECK: define {{.*}} @_Z1fIiEvv() nounwind {
+ // CHECK: define {{.*}} @_Z1fIiEvv() [[NUW]] {
f<int>();
- // CHECK: define {{.*}} @_Z1fIA2_iEvv() {
+ // CHECK: define {{.*}} @_Z1fIA2_iEvv() [[NONE]] {
f<int[2]>();
- // CHECK: define {{.*}} @_ZN1SIiE1fEv() nounwind
+ // CHECK: define {{.*}} @_ZN1SIiE1fEv() [[NUW]]
S<int>::f();
// CHECK: define {{.*}} @_ZN1SIA2_iE1fEv()
- // CHECK-NOT: nounwind
+ // CHECK-NOT: [[NUW]]
S<int[2]>::f();
- // CHECK: define {{.*}} @_Z1fIfEvv() nounwind {
+ // CHECK: define {{.*}} @_Z1fIfEvv() [[NUW]] {
void (*f1)() = &f<float>;
- // CHECK: define {{.*}} @_Z1fIdEvv() {
+ // CHECK: define {{.*}} @_Z1fIdEvv() [[NONE]] {
void (*f2)() = &f<double>;
- // CHECK: define {{.*}} @_ZN1SIfE1fEv() nounwind
+ // CHECK: define {{.*}} @_ZN1SIfE1fEv() [[NUW]]
void (*f3)() = &S<float>::f;
// CHECK: define {{.*}} @_ZN1SIdE1fEv()
- // CHECK-NOT: nounwind
+ // CHECK-NOT: [[NUW]]
void (*f4)() = &S<double>::f;
- // CHECK: define {{.*}} @_Z1fIA4_cEvv() nounwind {
+ // CHECK: define {{.*}} @_Z1fIA4_cEvv() [[NUW]] {
(void)&f<char[4]>;
- // CHECK: define {{.*}} @_Z1fIcEvv() {
+ // CHECK: define {{.*}} @_Z1fIcEvv() [[NONE]] {
(void)&f<char>;
- // CHECK: define {{.*}} @_ZN1SIA4_cE1fEv() nounwind
+ // CHECK: define {{.*}} @_ZN1SIA4_cE1fEv() [[NUW]]
(void)&S<char[4]>::f;
// CHECK: define {{.*}} @_ZN1SIcE1fEv()
- // CHECK-NOT: nounwind
+ // CHECK-NOT: [[NUW]]
(void)&S<char>::f;
}
// CHECK: define {{.*}} @_Z1iv
void i() {
- // CHECK: declare {{.*}} @_Z1gIiEvv() nounwind
+ // CHECK: declare {{.*}} @_Z1gIiEvv() [[NUW]]
g<int>();
// CHECK: declare {{.*}} @_Z1gIA2_iEvv()
- // CHECK-NOT: nounwind
+ // CHECK-NOT: [[NUW]]
g<int[2]>();
- // CHECK: declare {{.*}} @_ZN1SIiE1gEv() nounwind
+ // CHECK: declare {{.*}} @_ZN1SIiE1gEv() [[NUW]]
S<int>::g();
// CHECK: declare {{.*}} @_ZN1SIA2_iE1gEv()
- // CHECK-NOT: nounwind
+ // CHECK-NOT: [[NUW]]
S<int[2]>::g();
- // CHECK: declare {{.*}} @_Z1gIfEvv() nounwind
+ // CHECK: declare {{.*}} @_Z1gIfEvv() [[NUW]]
void (*g1)() = &g<float>;
// CHECK: declare {{.*}} @_Z1gIdEvv()
- // CHECK-NOT: nounwind
+ // CHECK-NOT: [[NUW]]
void (*g2)() = &g<double>;
- // CHECK: declare {{.*}} @_ZN1SIfE1gEv() nounwind
+ // CHECK: declare {{.*}} @_ZN1SIfE1gEv() [[NUW]]
void (*g3)() = &S<float>::g;
// CHECK: declare {{.*}} @_ZN1SIdE1gEv()
- // CHECK-NOT: nounwind
+ // CHECK-NOT: [[NUW]]
void (*g4)() = &S<double>::g;
- // CHECK: declare {{.*}} @_Z1gIA4_cEvv() nounwind
+ // CHECK: declare {{.*}} @_Z1gIA4_cEvv() [[NUW]]
(void)&g<char[4]>;
// CHECK: declare {{.*}} @_Z1gIcEvv()
- // CHECK-NOT: nounwind
+ // CHECK-NOT: [[NUW]]
(void)&g<char>;
- // CHECK: declare {{.*}} @_ZN1SIA4_cE1gEv() nounwind
+ // CHECK: declare {{.*}} @_ZN1SIA4_cE1gEv() [[NUW]]
(void)&S<char[4]>::g;
// CHECK: declare {{.*}} @_ZN1SIcE1gEv()
- // CHECK-NOT: nounwind
+ // CHECK-NOT: [[NUW]]
(void)&S<char>::g;
}
@@ -113,8 +113,11 @@ template<typename T> struct Nested {
// CHECK: define {{.*}} @_Z1jv
void j() {
// CHECK: declare {{.*}} @_ZN6NestedIiE1fILb1EcEEvv(
- // CHECK-NOT: nounwind
+ // CHECK-NOT: [[NUW]]
Nested<int>().f<true, char>();
- // CHECK: declare {{.*}} @_ZN6NestedIlE1fILb0ElEEvv({{.*}}) nounwind
+ // CHECK: declare {{.*}} @_ZN6NestedIlE1fILb0ElEEvv({{.*}}) [[NUW]]
Nested<long>().f<false, long>();
}
+
+// CHECK: attributes [[NONE]] = { {{.*}} }
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGenCXX/cxx11-noreturn.cpp b/test/CodeGenCXX/cxx11-noreturn.cpp
new file mode 100644
index 0000000..31c651d
--- /dev/null
+++ b/test/CodeGenCXX/cxx11-noreturn.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -emit-llvm -std=c++11 %s -o - | FileCheck %s
+
+int g();
+
+// CHECK: _Z1fv(){{.*}} [[NR:#[0-9]+]]
+[[noreturn]] int f() {
+ while (g()) {}
+}
+
+// CHECK: attributes [[NR]] = { noreturn nounwind{{.*}} }
diff --git a/test/CodeGenCXX/cxx11-trivial-initializer-struct.cpp b/test/CodeGenCXX/cxx11-trivial-initializer-struct.cpp
new file mode 100644
index 0000000..cded6da
--- /dev/null
+++ b/test/CodeGenCXX/cxx11-trivial-initializer-struct.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -std=c++11 -S -emit-llvm -o %t-c++11.ll %s -triple x86_64-apple-darwin10
+// RUN: FileCheck %s < %t-c++11.ll
+// RUN: %clang_cc1 -std=c++98 -S -emit-llvm -o %t.ll %s -triple x86_64-apple-darwin10
+// RUN: diff %t.ll %t-c++11.ll
+
+// rdar://12897704
+
+struct sAFSearchPos {
+ unsigned char *pos;
+ unsigned char count;
+};
+
+static volatile struct sAFSearchPos testPositions;
+// CHECK: @_ZL13testPositions = internal global %struct.sAFSearchPos zeroinitializer
+
+static volatile struct sAFSearchPos arrayPositions[100][10][5];
+// CHECK: @_ZL14arrayPositions = internal global [100 x [10 x [5 x %struct.sAFSearchPos]]] zeroinitializer
+
+int main() {
+ return testPositions.count + arrayPositions[10][4][3].count;
+}
diff --git a/test/CodeGenCXX/debug-info-artificial-arg.cpp b/test/CodeGenCXX/debug-info-artificial-arg.cpp
index ee93849..ff0f663 100644
--- a/test/CodeGenCXX/debug-info-artificial-arg.cpp
+++ b/test/CodeGenCXX/debug-info-artificial-arg.cpp
@@ -22,9 +22,8 @@ int main(int argc, char **argv) {
A reallyA (500);
}
-// FIXME: The numbers are truly awful.
-// 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 ]
-// CHECK: !44 = metadata !{null, metadata !16, metadata !9, metadata !32}
+// CHECK: ![[ARTARG:.*]] = {{.*}} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [artificial] [from A]
+// CHECK: ![[CLASSTYPE:.*]] = {{.*}} ; [ DW_TAG_class_type ] [A]
+// CHECK: metadata ![[CLASSTYPE]], {{.*}} ; [ DW_TAG_subprogram ] [line 12] [A]
+// CHECK: metadata [[FUNCTYPE:![0-9]*]], i32 0, i32 0} ; [ DW_TAG_subroutine_type ]
+// CHECK: [[FUNCTYPE]] = metadata !{null, metadata ![[ARTARG]], metadata !{{.*}}, metadata !{{.*}}}
diff --git a/test/CodeGenCXX/debug-info-byval.cpp b/test/CodeGenCXX/debug-info-byval.cpp
index 56ffe13..e6317fc 100644
--- a/test/CodeGenCXX/debug-info-byval.cpp
+++ b/test/CodeGenCXX/debug-info-byval.cpp
@@ -23,7 +23,7 @@ void foo(EVT e);
EVT bar();
void get(int *i, unsigned dl, VAL v, VAL *p, unsigned n, EVT missing_arg) {
-//CHECK: .asciz "missing_arg"
+//CHECK: .{{asciz|string}} "missing_arg"
EVT e = bar();
if (dl == n)
foo(missing_arg);
diff --git a/test/CodeGenCXX/debug-info-char16.cpp b/test/CodeGenCXX/debug-info-char16.cpp
index 24216f9..06a05b3 100644
--- a/test/CodeGenCXX/debug-info-char16.cpp
+++ b/test/CodeGenCXX/debug-info-char16.cpp
@@ -3,4 +3,4 @@
// 16 is DW_ATE_UTF (0x10) encoding attribute.
char16_t char_a = u'h';
-// CHECK: !7 = metadata !{i32 {{.*}}, null, metadata !"char16_t", null, i32 0, i64 16, i64 16, i64 0, i32 0, i32 16} ; [ DW_TAG_base_type ]
+// CHECK: !{{.*}} = {{.*}} ; [ DW_TAG_base_type ] [char16_t]
diff --git a/test/CodeGenCXX/debug-info-class.cpp b/test/CodeGenCXX/debug-info-class.cpp
index 062227a..df24926 100644
--- a/test/CodeGenCXX/debug-info-class.cpp
+++ b/test/CodeGenCXX/debug-info-class.cpp
@@ -1,24 +1,48 @@
-// RUN: %clang -emit-llvm -g -S %s -o - | FileCheck %s
struct foo;
-void func(foo *f) { // CHECK: DW_TAG_structure_type
+void func(foo *f) {
}
class bar;
-void func(bar *f) { // CHECK: DW_TAG_class_type
+void func(bar *f) {
}
union baz;
-void func(baz *f) { // CHECK: DW_TAG_union_type
+void func(baz *f) {
}
-struct A { // CHECK: DW_TAG_structure_type
+
+class B {
+public:
+ virtual ~B();
+};
+struct A {
int one;
- static const int HdrSize = 52; // CHECK: HdrSize
+ static const int HdrSize = 52;
int two;
A() {
int x = 1;
}
};
-class B { // CHECK: DW_TAG_class_type
-};
-int main() {
- A a;
+
+
+int main(int argc, char **argv) {
B b;
+ if (argc) {
+ A a;
+ }
+ return 0;
}
+
+// RUN: %clang -target x86_64-unknown_unknown -emit-llvm -g -S %s -o - | FileCheck %s
+// RUN: %clang -target i686-cygwin -emit-llvm -g -S %s -o - | FileCheck %s
+// RUN: %clang -target armv7l-unknown-linux-gnueabihf -emit-llvm -g -S %s -o - | FileCheck %s
+
+// CHECK: invoke {{.+}} @_ZN1BD1Ev(%class.B* %b)
+// CHECK-NEXT: unwind label %{{.+}}, !dbg ![[EXCEPTLOC:.*]]
+// CHECK: store i32 0, i32* %{{.+}}, !dbg ![[RETLOC:.*]]
+// CHECK: DW_TAG_structure_type ] [foo]
+// CHECK: DW_TAG_class_type ] [bar]
+// CHECK: DW_TAG_union_type ] [baz]
+// CHECK: DW_TAG_structure_type ] [A]
+// CHECK: HdrSize
+// CHECK: DW_TAG_class_type ] [B]
+// CHECK: metadata !"_vptr$B", {{.*}}, i32 64, metadata !{{.*}}} ; [ DW_TAG_member ]
+// CHECK: ![[EXCEPTLOC]] = metadata !{i32 31,
+// CHECK: ![[RETLOC]] = metadata !{i32 30,
diff --git a/test/CodeGenCXX/debug-info-dup-fwd-decl.cpp b/test/CodeGenCXX/debug-info-dup-fwd-decl.cpp
index e67987b..04fe7a0 100644
--- a/test/CodeGenCXX/debug-info-dup-fwd-decl.cpp
+++ b/test/CodeGenCXX/debug-info-dup-fwd-decl.cpp
@@ -19,6 +19,6 @@ protected:
Test t;
-// CHECK: metadata !"", null, i32 0, i64 64, i64 64, i64 0, i32 0, metadata {{.*}} [ DW_TAG_pointer_type ]
-// CHECK: metadata !"data", metadata !6, i32 14, i64 32, i64 32, i32 0, i32 0
-// CHECK-NOT: metadata !"data", metadata {{.*}}, i32 14, i64 0, i64 0, i32 0, i32 4,
+// CHECK: ; [ DW_TAG_pointer_type ]
+// CHECK: ; [ DW_TAG_structure_type ] [data]
+// CHECK-NOT: ; [ DW_TAG_structure_type ] [data]
diff --git a/test/CodeGenCXX/debug-info-enum-class.cpp b/test/CodeGenCXX/debug-info-enum-class.cpp
index fd243ab..929327b 100644
--- a/test/CodeGenCXX/debug-info-enum-class.cpp
+++ b/test/CodeGenCXX/debug-info-enum-class.cpp
@@ -9,10 +9,10 @@ B b;
C c;
D d;
-// CHECK: 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, null, i32 0} ; [ DW_TAG_enumeration_type ]
+// CHECK: ; [ DW_TAG_enumeration_type ] [A] [line 3, size 32, align 32, offset 0] [from int]
+// CHECK: ; [ DW_TAG_enumeration_type ] [B] [line 4, size 64, align 64, offset 0] [from long unsigned int]
+// CHECK: ; [ DW_TAG_enumeration_type ] [C] [line 5, size 32, align 32, offset 0] [from ]
+// CHECK: ; [ DW_TAG_enumeration_type ] [D] [line 6, size 16, align 16, offset 0] [fwd] [from ]
namespace PR14029 {
// Make sure this doesn't crash/assert.
diff --git a/test/CodeGenCXX/debug-info-flex-member.cpp b/test/CodeGenCXX/debug-info-flex-member.cpp
index b6aa6da..11329aa 100644
--- a/test/CodeGenCXX/debug-info-flex-member.cpp
+++ b/test/CodeGenCXX/debug-info-flex-member.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin %s -o - | FileCheck %s
-// CHECK: metadata !{i32 {{.*}}, i64 1, i64 0} ; [ DW_TAG_subrange_type ]
+// CHECK: metadata !{i32 {{.*}}, i64 0, i64 -1} ; [ DW_TAG_subrange_type ]
struct StructName {
int member[];
diff --git a/test/CodeGenCXX/debug-info-fwd-ref.cpp b/test/CodeGenCXX/debug-info-fwd-ref.cpp
index 9135032..c479506 100644
--- a/test/CodeGenCXX/debug-info-fwd-ref.cpp
+++ b/test/CodeGenCXX/debug-info-fwd-ref.cpp
@@ -18,8 +18,7 @@ int main(int argc, char** argv) {
// Make sure we have two DW_TAG_structure_types for baz and bar and no forward
// references.
-// 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 ]
-
+// CHECK-NOT: [fwd]
+// CHECK: [ DW_TAG_structure_type ] [bar]
+// CHECK: [ DW_TAG_structure_type ] [baz]
+// CHECK-NOT: [fwd]
diff --git a/test/CodeGenCXX/debug-info-method.cpp b/test/CodeGenCXX/debug-info-method.cpp
index cb022bc..3ee4d9b 100644
--- a/test/CodeGenCXX/debug-info-method.cpp
+++ b/test/CodeGenCXX/debug-info-method.cpp
@@ -1,6 +1,27 @@
-// RUN: %clang -fverbose-asm -g -S %s -o - | grep DW_ACCESS_protected
+// RUN: %clang_cc1 -emit-llvm -std=c++11 -g %s -o - | FileCheck %s
+// CHECK: ![[THISTYPE:[0-9]+]] = {{.*}} ; [ DW_TAG_pointer_type ] {{.*}} [artificial] [from A]
+// CHECK: metadata !"_ZN1A3fooEiS_3$_0", {{.*}} [protected]
+// CHECK: DW_TAG_ptr_to_member_type
+// CHECK: {{.*}}metadata ![[MEMFUNTYPE:[0-9]+]], metadata !{{.*}}} ; [ DW_TAG_ptr_to_member_type ] {{.*}} [from ]
+// CHECK: ![[MEMFUNTYPE]] = {{.*}}metadata ![[MEMFUNARGS:[0-9]+]], i32 0, i32 0} ; [ DW_TAG_subroutine_type ] {{.*}} [from ]
+// CHECK: ![[MEMFUNARGS]] = {{.*}}, metadata ![[THISTYPE]],
+// CHECK: ""{{.*}}DW_TAG_arg_variable
+// CHECK: ""{{.*}}DW_TAG_arg_variable
+// CHECK: ""{{.*}}DW_TAG_arg_variable
+union {
+ int a;
+ float b;
+} u;
+
class A {
protected:
- int foo();
+ void foo(int, A, decltype(u));
};
+
+void A::foo(int, A, decltype(u)) {
+}
+
A a;
+
+int A::*x = 0;
+int (A::*y)(int) = 0;
diff --git a/test/CodeGenCXX/debug-info-namespace.cpp b/test/CodeGenCXX/debug-info-namespace.cpp
index 27f5eae..262e996 100644
--- a/test/CodeGenCXX/debug-info-namespace.cpp
+++ b/test/CodeGenCXX/debug-info-namespace.cpp
@@ -1,12 +1,17 @@
-// RUN: %clang -g -S -fverbose-asm %s -o - | FileCheck %s
+// RUN: %clang -g -S -emit-llvm %s -o - | FileCheck %s
-// CHECK: TAG_namespace
namespace A {
- enum numbers {
- ZERO,
- ONE
- };
+#line 1 "foo.cpp"
+namespace B {
+int i;
}
+}
+
+// CHECK: [[FILE:![0-9]*]] {{.*}}debug-info-namespace.cpp"
+// CHECK: [[VAR:![0-9]*]] = {{.*}}, metadata [[NS:![0-9]*]], metadata !"i", {{.*}} ; [ DW_TAG_variable ] [i]
+// CHECK: [[NS]] = {{.*}}, metadata [[FILE2:![0-9]*]], metadata [[CTXT:![0-9]*]], {{.*}} ; [ DW_TAG_namespace ] [B] [line 1]
+// CHECK: [[CTXT]] = {{.*}}, metadata [[FILE]], null, {{.*}} ; [ DW_TAG_namespace ] [A] [line 3]
+// CHECK: [[FILE2]]} ; [ DW_TAG_file_type ] [{{.*}}foo.cpp]
-using namespace A;
-numbers n;
+// FIXME: It is confused on win32 to generate file entry when dosish filename is given.
+// REQUIRES: shell
diff --git a/test/CodeGenCXX/debug-info-nullptr.cpp b/test/CodeGenCXX/debug-info-nullptr.cpp
index 4cc7e54..42e9741 100644
--- a/test/CodeGenCXX/debug-info-nullptr.cpp
+++ b/test/CodeGenCXX/debug-info-nullptr.cpp
@@ -4,4 +4,4 @@ void foo() {
decltype(nullptr) t = 0;
}
-// CHECK: metadata !{i32 {{.*}}, null, metadata !"nullptr_t", null, i32 0, i64 0, i64 0, i64 0, i32 0, i32 0} ; [ DW_TAG_unspecified_type ]
+// CHECK: [ DW_TAG_unspecified_type ] [nullptr_t]
diff --git a/test/CodeGenCXX/debug-info-pubtypes.cpp b/test/CodeGenCXX/debug-info-pubtypes.cpp
index 612b6b5..6ca3da8 100644
--- a/test/CodeGenCXX/debug-info-pubtypes.cpp
+++ b/test/CodeGenCXX/debug-info-pubtypes.cpp
@@ -3,10 +3,10 @@
// RUN: FileCheck %s < %t
// FIXME: This testcase shouldn't rely on assembly emission.
-//CHECK: Lpubtypes_begin1:
+//CHECK: Lpubtypes_begin[[SECNUM:[0-9]:]]
//CHECK: .asciz "G"
//CHECK-NEXT: .long 0
-//CHECK-NEXT: Lpubtypes_end1:
+//CHECK-NEXT: Lpubtypes_end[[SECNUM]]
class G {
public:
diff --git a/test/CodeGenCXX/debug-info-rvalue-ref.cpp b/test/CodeGenCXX/debug-info-rvalue-ref.cpp
index b633c5c..142f587 100644
--- a/test/CodeGenCXX/debug-info-rvalue-ref.cpp
+++ b/test/CodeGenCXX/debug-info-rvalue-ref.cpp
@@ -8,4 +8,4 @@ void foo (int &&i)
printf("%d\n", i);
}
-// CHECK: metadata !{i32 {{.*}}, null, null, null, i32 0, i64 0, i64 0, i64 0, i32 0, metadata !10} ; [ DW_TAG_rvalue_reference_type ]
+// CHECK: metadata !{i32 {{.*}}, null, null, null, i32 0, i64 0, i64 0, i64 0, i32 0, metadata !{{.*}}} ; [ DW_TAG_rvalue_reference_type ]
diff --git a/test/CodeGenCXX/debug-info-same-line.cpp b/test/CodeGenCXX/debug-info-same-line.cpp
new file mode 100644
index 0000000..ad24503
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-same-line.cpp
@@ -0,0 +1,98 @@
+// RUN: %clang_cc1 -g -emit-llvm -o - %s | FileCheck %s
+
+// Make sure that clang outputs distinct debug info for a function
+// that is inlined twice on the same line. Otherwise it would appear
+// as if the function was only inlined once.
+
+#define INLINE inline __attribute__((always_inline))
+
+INLINE int
+product (int x, int y)
+{
+ int result = x * y;
+ return result;
+}
+
+INLINE int
+sum (int a, int b)
+{
+ int result = a + b;
+ return result;
+}
+
+int
+strange_max (int m, int n)
+{
+ if (m > n)
+ return m;
+ else if (n > m)
+ return n;
+ else
+ return 0;
+}
+
+int
+foo (int i, int j)
+{
+ if (strange_max (i, j) == i)
+ return product (i, j);
+ else if (strange_max (i, j) == j)
+ return sum (i, j);
+ else
+ return product (sum (i, i), sum (j, j));
+}
+
+int
+main(int argc, char const *argv[])
+{
+
+ int array[3];
+ int n;
+
+ array[0] = foo (1238, 78392);
+ array[1] = foo (379265, 23674);
+ array[2] = foo (872934, 234);
+
+ n = strange_max(array[0], strange_max(array[1], array[2]));
+
+ return n & 0xf;
+}
+
+// CHECK: define {{.*}} @_Z3fooii
+// i
+// CHECK: call void @llvm.dbg.declare
+// j
+// CHECK: call void @llvm.dbg.declare
+// x
+// CHECK: call void @llvm.dbg.declare
+// y
+// CHECK: call void @llvm.dbg.declare
+// result
+// CHECK: call void @llvm.dbg.declare
+
+// CHECK: call void @llvm.dbg.declare(metadata !{i32* %{{.*}}}, metadata ![[A_MD:[0-9]+]]), !dbg ![[A_DI:[0-9]+]]
+// CHECK: call void @llvm.dbg.declare(metadata !{i32* %{{.*}}}, metadata ![[B_MD:[0-9]+]]), !dbg ![[B_DI:[0-9]+]]
+// result
+// CHECK: call void @llvm.dbg.declare
+
+// We want to see a distinct !dbg node.
+// CHECK-NOT: call void @llvm.dbg.declare(metadata !{i32* %{{.*}}}, metadata ![[A_MD]]), !dbg ![[A_DI]]
+// CHECK: call void @llvm.dbg.declare(metadata !{i32* %{{.*}}}, metadata ![[A_MD]]), !dbg !{{.*}}
+// CHECK-NOT: call void @llvm.dbg.declare(metadata !{i32* %{{.*}}}, metadata ![[B_MD]]), !dbg ![[B_DI]]
+// CHECK: call void @llvm.dbg.declare(metadata !{i32* %{{.*}}}, metadata ![[B_MD]]), !dbg !{{.*}}
+// result
+// CHECK: call void @llvm.dbg.declare
+
+// CHECK: define {{.*}} @main
+// CHECK: call {{.*}} @_Z3fooii
+// CHECK: call {{.*}} @_Z3fooii
+// CHECK: call {{.*}} @_Z3fooii
+// CHECK: store
+// CHECK: getelementptr
+// We want to see the same !dbg node for non-inlined functions.
+// Needed for GDB compatibility.
+// CHECK: load {{.*}} !dbg ![[DBG:.*]]
+// CHECK: load {{.*}} !dbg ![[DBG]]
+// CHECK: load {{.*}} !dbg ![[DBG]]
+// CHECK: call {{.*}} @_Z11strange_maxii(i32 {{.*}}, i32 {{.*}}), !dbg ![[DBG]]
+// CHECK: call {{.*}} @_Z11strange_maxii(i32 {{.*}}, i32 {{.*}}), !dbg ![[DBG]]
diff --git a/test/CodeGenCXX/debug-info-static-fns.cpp b/test/CodeGenCXX/debug-info-static-fns.cpp
index ee46f25..136261c 100644
--- a/test/CodeGenCXX/debug-info-static-fns.cpp
+++ b/test/CodeGenCXX/debug-info-static-fns.cpp
@@ -7,4 +7,4 @@ namespace A {
}
// Verify that a is present and mangled.
-// CHECK: metadata !{i32 {{.*}}, i32 0, metadata !6, metadata !"a", metadata !"a", metadata !"_ZN1AL1aEi", metadata !7, i32 4, metadata !8, i1 true, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 (i32)* @_ZN1AL1aEi, null, null, metadata !1, i32 4} ; [ DW_TAG_subprogram ]
+// CHECK: metadata !"_ZN1AL1aEi", {{.*}}, i32 (i32)* @_ZN1AL1aEi, {{.*}} ; [ DW_TAG_subprogram ] [line 4] [local] [def] [a]
diff --git a/test/CodeGenCXX/debug-info-static-member.cpp b/test/CodeGenCXX/debug-info-static-member.cpp
new file mode 100644
index 0000000..774f7b1
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-static-member.cpp
@@ -0,0 +1,41 @@
+// RUN: %clangxx -target x86_64-unknown-unknown -g -O0 %s -emit-llvm -S -o - | FileCheck %s
+// PR14471
+
+
+class C
+{
+ static int a;
+ const static bool const_a = true;
+protected:
+ static int b;
+ const static float const_b = 3.14;
+public:
+ static int c;
+ const static int const_c = 18;
+ int d;
+};
+
+int C::a = 4;
+int C::b = 2;
+int C::c = 1;
+
+int main()
+{
+ C instance_C;
+ instance_C.d = 8;
+ return C::c;
+}
+
+// The definition of C::a drives the emission of class C, which is
+// why the definition of "a" comes before the declarations while
+// "b" and "c" come after.
+
+// CHECK: metadata !"a", {{.*}} @_ZN1C1aE, metadata ![[DECL_A:[0-9]+]]} ; [ DW_TAG_variable ] [a] {{.*}} [def]
+// CHECK: ![[DECL_A]] = metadata {{.*}} [ DW_TAG_member ] [a] [line {{.*}}, size 0, align 0, offset 0] [private] [static]
+// CHECK: metadata !"const_a", {{.*}}, i1 true} ; [ DW_TAG_member ] [const_a] [line {{.*}}, size 0, align 0, offset 0] [private] [static]
+// CHECK: ![[DECL_B:[0-9]+]] {{.*}} metadata !"b", {{.*}} [ DW_TAG_member ] [b] [line {{.*}}, size 0, align 0, offset 0] [protected] [static]
+// CHECK: metadata !"const_b", {{.*}}, float 0x{{.*}}} ; [ DW_TAG_member ] [const_b] [line {{.*}}, size 0, align 0, offset 0] [protected] [static]
+// CHECK: ![[DECL_C:[0-9]+]] {{.*}} metadata !"c", {{.*}} [ DW_TAG_member ] [c] [line {{.*}}, size 0, align 0, offset 0] [static]
+// CHECK: metadata !"const_c", {{.*}} [ DW_TAG_member ] [const_c] [line {{.*}}, size 0, align 0, offset 0] [static]
+// CHECK: metadata !"b", {{.*}} @_ZN1C1bE, metadata ![[DECL_B]]} ; [ DW_TAG_variable ] [b] {{.*}} [def]
+// CHECK: metadata !"c", {{.*}} @_ZN1C1cE, metadata ![[DECL_C]]} ; [ DW_TAG_variable ] [c] {{.*}} [def]
diff --git a/test/CodeGenCXX/debug-info-template-member.cpp b/test/CodeGenCXX/debug-info-template-member.cpp
index 6208c80..6be7f9b 100644
--- a/test/CodeGenCXX/debug-info-template-member.cpp
+++ b/test/CodeGenCXX/debug-info-template-member.cpp
@@ -16,6 +16,6 @@ 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:.*]], metadata {{.*}}}
-// CHECK: [[C_TEMP]] = metadata !{i32 {{.*}}, i32 0, metadata {{.*}}, metadata !"add<2>", metadata !"add<2>", metadata !"_ZN7MyClass3addILi2EEEii", metadata {{.*}}
+// CHECK: metadata [[C_MEM:![0-9]*]], i32 0, null, null} ; [ DW_TAG_class_type ] [MyClass]
+// CHECK: [[C_MEM]] = metadata !{metadata {{.*}}, metadata [[C_TEMP:![0-9]*]], metadata {{.*}}}
+// CHECK: [[C_TEMP]] = {{.*}} ; [ DW_TAG_subprogram ] [line 11] [private] [add<2>]
diff --git a/test/CodeGenCXX/debug-info-template-quals.cpp b/test/CodeGenCXX/debug-info-template-quals.cpp
index ffb1ca3..335c8ab 100644
--- a/test/CodeGenCXX/debug-info-template-quals.cpp
+++ b/test/CodeGenCXX/debug-info-template-quals.cpp
@@ -4,7 +4,7 @@ template<typename _CharT>
struct basic_string {
basic_string&
- assign(const _CharT* __s)
+ assign(const _CharT* __s, const basic_string<_CharT> &x)
{
return *this;
}
@@ -12,12 +12,16 @@ struct basic_string {
void foo (const char *c) {
basic_string<char> str;
- str.assign(c);
+ str.assign(c, str);
}
-// CHECK: [[P:.*]] = metadata !{i32 {{.*}}, metadata [[CON:.*]]} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [from ]
-// CHECK: [[CON]] = metadata !{i32 {{.*}}, metadata [[CH:.*]]} ; [ DW_TAG_const_type ] [line 0, size 0, align 0, offset 0] [from char]
-// 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 !24, metadata [[P]]}
+// CHECK: [[P:.*]] = {{.*}}, metadata [[CON:![0-9]*]]} ; [ DW_TAG_pointer_type ] [line 0, size 64, align 64, offset 0] [from ]
+// CHECK: [[CON]] = {{.*}}, metadata [[CH:![0-9]*]]} ; [ DW_TAG_const_type ] [line 0, size 0, align 0, offset 0] [from char]
+// CHECK: [[CH]] = {{.*}} ; [ DW_TAG_base_type ] [char] [line 0, size 8, align 8, offset 0, enc DW_ATE_signed_char]
+
+// CHECK: {{.*}} metadata [[TYPE:![0-9]*]], {{.*}}, metadata !{{[0-9]*}}, metadata !{{[0-9]*}}, i32 8} ; [ DW_TAG_subprogram ] [line 7] [def] [scope 8] [assign]
+// CHECK: [[TYPE]] = metadata !{i32 {{.*}}, metadata [[ARGS:.*]], i32 0, i32 0} ; [ DW_TAG_subroutine_type ]
+// CHECK: [[ARGS]] = metadata !{metadata !{{.*}}, metadata !{{.*}}, metadata [[P]], metadata [[R:.*]]}
+// CHECK: [[BS:.*]] = {{.*}} ; [ DW_TAG_structure_type ] [basic_string<char>] [line 4, size 8, align 8, offset 0] [from ]
+// CHECK: [[R]] = {{.*}}, metadata [[CON2:![0-9]*]]} ; [ DW_TAG_reference_type ] [line 0, size 0, align 0, offset 0] [from ]
+// CHECK: [[CON2]] = {{.*}}, metadata [[BS]]} ; [ DW_TAG_const_type ] [line 0, size 0, align 0, offset 0] [from basic_string<char>]
diff --git a/test/CodeGenCXX/debug-info-union-template.cpp b/test/CodeGenCXX/debug-info-union-template.cpp
new file mode 100644
index 0000000..f5e6e14
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-union-template.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-linux-gnu %s -o - | FileCheck %s
+
+// Make sure that the union type has template parameters.
+
+namespace PR15637 {
+ template <typename T> union Value { int a; };
+ void g(float value) {
+ Value<float> tempValue;
+ }
+ Value<float> f;
+}
+
+// CHECK: {{.*}}, metadata !"Value<float>", {{.*}}, null, metadata [[TTPARAM:.*]]} ; [ DW_TAG_union_type ] [Value<float>]
+// CHECK: [[TTPARAM]] = metadata !{metadata [[PARAMS:.*]]}
+// CHECK: [[PARAMS]] = metadata !{{{.*}}metadata !"T",{{.*}}} ; [ DW_TAG_template_type_parameter ]
diff --git a/test/CodeGenCXX/debug-info-union.cpp b/test/CodeGenCXX/debug-info-union.cpp
index 588fa20..0aa48dc 100644
--- a/test/CodeGenCXX/debug-info-union.cpp
+++ b/test/CodeGenCXX/debug-info-union.cpp
@@ -10,7 +10,7 @@ union E {
E e;
-// CHECK: metadata !{i32 {{.*}}, null, metadata !"E", metadata !{{.*}}, i32 3, i64 32, i64 32, i64 0, i32 0, null, metadata !{{.*}}, i32 0, null} ; [ DW_TAG_union_type ]
-// CHECK: metadata !{i32 {{.*}}, i32 0, metadata !{{.*}}, metadata !"bb", metadata !"bb", metadata !"_ZN1E2bbEv", metadata !{{.*}}, i32 6, metadata !{{.*}}, i1 false, i1 false, i32 0, i32 0, null, i32 256, i1 false, null, null, i32 0, metadata !{{.*}}, i32 6} ; [ DW_TAG_subprogram ]
-// CHECK: metadata !{i32 {{.*}}, i32 0, metadata !{{.*}}, metadata !"aa", metadata !"aa", metadata !"_ZN1E2aaEv", metadata !{{.*}}, i32 7, metadata !{{.*}}, i1 false, i1 false, i32 0, i32 0, null, i32 256, i1 false, null, null, i32 0, metadata !{{.*}}, i32 7} ; [ DW_TAG_subprogram ]
-// CHECK: metadata !{i32 {{.*}}, i32 0, metadata !{{.*}}, metadata !"E", metadata !"E", metadata !"", metadata !{{.*}}, i32 8, metadata !{{.*}}, i1 false, i1 false, i32 0, i32 0, null, i32 256, i1 false, null, null, i32 0, metadata !{{.*}}, i32 8} ; [ DW_TAG_subprogram ]
+// CHECK: {{.*}} ; [ DW_TAG_union_type ] [E] [line 3, size 32, align 32, offset 0]
+// CHECK: {{.*}} ; [ DW_TAG_subprogram ] [line 6] [bb]
+// CHECK: {{.*}} ; [ DW_TAG_subprogram ] [line 7] [aa]
+// CHECK: {{.*}} ; [ DW_TAG_subprogram ] [line 8] [E]
diff --git a/test/CodeGenCXX/debug-info-use-after-free.cpp b/test/CodeGenCXX/debug-info-use-after-free.cpp
index 9757ca4..852e148 100644
--- a/test/CodeGenCXX/debug-info-use-after-free.cpp
+++ b/test/CodeGenCXX/debug-info-use-after-free.cpp
@@ -192,6 +192,7 @@ __gnu_cxx {
public:
typedef _EqualKey
key_equal;
+ typedef void key_type;
};
using
std::equal_to;
@@ -217,7 +218,7 @@ __gnu_cxx {
_Alloc >
_Ht;
public:
- typename _Ht::key_type;
+ typedef typename _Ht::key_type key_type;
typedef typename
_Ht::key_equal
key_equal;
diff --git a/test/CodeGenCXX/debug-info-zero-length-arrays.cpp b/test/CodeGenCXX/debug-info-zero-length-arrays.cpp
new file mode 100644
index 0000000..fb47022
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-zero-length-arrays.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang -target x86_64-unknown-unknown -fverbose-asm -g -O0 -S -emit-llvm %s -o - | FileCheck %s
+// <rdar://problem/12566646>
+
+class A {
+ int x[];
+};
+A a;
+
+// CHECK: metadata [[ARRAY_TYPE:![0-9]*]]} ; [ DW_TAG_member ] [x]
+// CHECK: metadata [[ELEM_TYPE:![0-9]*]], i32 0, i32 0} ; [ DW_TAG_array_type ] [line 0, size 0, align 32, offset 0] [from int]
+// CHECK: [[ELEM_TYPE]] = metadata !{metadata [[SUBRANGE:.*]]}
+// CHECK: [[SUBRANGE]] = metadata !{i32 786465, i64 0, i64 -1} ; [ DW_TAG_subrange_type ] [unbounded]
diff --git a/test/CodeGenCXX/debug-lambda-expressions.cpp b/test/CodeGenCXX/debug-lambda-expressions.cpp
index 430371f..39c9a44 100644
--- a/test/CodeGenCXX/debug-lambda-expressions.cpp
+++ b/test/CodeGenCXX/debug-lambda-expressions.cpp
@@ -15,57 +15,57 @@ struct D { D(); D(const D&); int x; };
int d(int x) { D y[10]; [x,y] { return y[x].x; }(); }
// Randomness for file. -- 6
-// CHECK: [[FILE:.*]] = metadata !{i32 {{.*}}, metadata !{{.*}}debug-lambda-expressions.cpp{{.*}}; [ DW_TAG_file_type ]
+// CHECK: [[FILE:.*]] = {{.*}} [ DW_TAG_file_type ] [{{.*}}debug-lambda-expressions.cpp]
// A: 10
-// CHECK: [[A_FUNC:.*]] = metadata !{i32 {{.*}}, i32 0, metadata [[FILE]], metadata !"a", metadata !"a", metadata !"_Z1av", metadata {{.*}}, i32 [[A_LINE:.*]], metadata {{.*}}, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 ()* @_Z1av, null, null, {{.*}} [ DW_TAG_subprogram ]
+// CHECK: [[A_FUNC:.*]] = {{.*}} [ DW_TAG_subprogram ] [line [[A_LINE:.*]]] [def] [a]
// B: 14
-// CHECK: [[B_FUNC:.*]] = metadata !{i32 786478, i32 0, metadata [[FILE]], metadata !"b", metadata !"b", metadata !"_Z1bi", metadata [[FILE]], i32 [[B_LINE:.*]], metadata {{.*}}, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 (i32)* @_Z1bi, null, null, {{.*}} ; [ DW_TAG_subprogram ]
+// CHECK: [[B_FUNC:.*]] = {{.*}} [ DW_TAG_subprogram ] [line [[B_LINE:.*]]] [def] [b]
// C: 17
-// CHECK: [[C_FUNC:.*]] = metadata !{i32 {{.*}}, i32 0, metadata [[FILE]], metadata !"c", metadata !"c", metadata !"_Z1ci", metadata [[FILE]], i32 [[C_LINE:.*]], metadata {{.*}}, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 (i32)* @_Z1ci, null, null, metadata {{.*}} ; [ DW_TAG_subprogram ]
+// CHECK: [[C_FUNC:.*]] = {{.*}} [ DW_TAG_subprogram ] [line [[C_LINE:.*]]] [def] [c]
// D: 18
-// CHECK: [[D_FUNC:.*]] = metadata !{i32 {{.*}}, i32 0, metadata [[FILE]], metadata !"d", metadata !"d", metadata !"_Z1di", metadata [[FILE]], i32 [[D_LINE:.*]], metadata {{.*}}, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 (i32)* @_Z1di, null, null, metadata {{.*}} ; [ DW_TAG_subprogram ]
+// CHECK: [[D_FUNC:.*]] = {{.*}} [ DW_TAG_subprogram ] [line [[D_LINE:.*]]] [def] [d]
// 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:.*]] = {{.*}}, metadata [[D_FUNC]], {{.*}}, metadata [[LAM_D_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] [line [[D_LINE]],
// CHECK: [[LAM_D_ARGS]] = metadata !{metadata [[CAP_D_X:.*]], metadata [[CAP_D_Y:.*]], metadata [[CON_LAM_D:.*]], metadata [[DES_LAM_D:.*]]}
-// CHECK: [[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 ]
+// CHECK: [[CAP_D_X]] = {{.*}}, metadata [[LAM_D]], {{.*}} [ DW_TAG_member ] [x] [line [[D_LINE]],
+// CHECK: [[CAP_D_Y]] = {{.*}}, metadata [[LAM_D]], {{.*}} [ DW_TAG_member ] [y] [line [[D_LINE]],
+// CHECK: [[CON_LAM_D]] = {{.*}}, metadata [[LAM_D]], {{.*}} [ DW_TAG_subprogram ] [line [[D_LINE]]] [operator()]
+// CHECK: [[DES_LAM_D]] = {{.*}}, metadata [[LAM_D]], {{.*}} [ DW_TAG_subprogram ] [line [[D_LINE]]] [~]
// Back to C. -- 55
-// CHECK: [[LAM_C:.*]] = metadata !{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:.*]] = {{.*}}, metadata [[C_FUNC]], {{.*}}, metadata [[LAM_C_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] [line [[C_LINE]],
// CHECK: [[LAM_C_ARGS]] = metadata !{metadata [[CAP_C:.*]], metadata [[CON_LAM_C:.*]], metadata [[DES_LAM_C:.*]]}
// 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 ]
+// CHECK: [[CAP_C]] = {{.*}}, metadata [[LAM_C]], {{.*}}} ; [ DW_TAG_member ] [x] [line [[C_LINE]],
+// CHECK: [[CON_LAM_C]] = {{.*}}, metadata [[LAM_C]], {{.*}} [ DW_TAG_subprogram ] [line [[C_LINE]]] [operator()]
+// CHECK: [[DES_LAM_C]] = {{.*}}, metadata [[LAM_C]], {{.*}} [ DW_TAG_subprogram ] [line [[C_LINE]]] [~]
// Back to B. -- 67
-// CHECK: [[LAM_B:.*]] = metadata !{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:.*]] = {{.*}}, metadata [[B_FUNC]], {{.*}}, metadata [[LAM_B_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] [line [[B_LINE]],
// CHECK: [[LAM_B_ARGS]] = metadata !{metadata [[CAP_B:.*]], metadata [[CON_LAM_B:.*]], metadata [[DES_LAM_B:.*]]}
-// CHECK: [[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 ]
+// CHECK: [[CAP_B]] = {{.*}}, metadata [[LAM_B]], {{.*}}} ; [ DW_TAG_member ] [x] [line [[B_LINE]],
+// CHECK: [[CON_LAM_B]] = {{.*}}, metadata [[LAM_B]], {{.*}} [ DW_TAG_subprogram ] [line [[B_LINE]]] [operator()]
+// CHECK: [[DES_LAM_B]] = {{.*}}, metadata [[LAM_B]], {{.*}} [ DW_TAG_subprogram ] [line [[B_LINE]]] [~]
// Back to A. -- 78
-// CHECK: [[LAM_A:.*]] = metadata !{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:.*]] = {{.*}}, metadata [[A_FUNC]], {{.*}}, metadata [[LAM_A_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] [line [[A_LINE]],
// CHECK: [[LAM_A_ARGS]] = metadata !{metadata [[CON_LAM_A:.*]], metadata [[DES_LAM_A:.*]]}
-// CHECK: [[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 ]
+// CHECK: [[CON_LAM_A]] = {{.*}}, metadata [[LAM_A]], {{.*}} [ DW_TAG_subprogram ] [line [[A_LINE]]] [operator()]
+// CHECK: [[DES_LAM_A]] = {{.*}}, metadata [[LAM_A]], {{.*}} [ DW_TAG_subprogram ] [line [[A_LINE]]] [~]
// CVAR:
-// CHECK: metadata !{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: {{.*}} metadata [[CVAR_T:![0-9]*]], {{.*}} ; [ DW_TAG_variable ] [cvar] [line [[CVAR_LINE:[0-9]*]]]
+// CHECK: [[CVAR_T]] = {{.*}}, metadata ![[CVAR_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] [line [[CVAR_LINE]],
// CHECK: [[CVAR_ARGS]] = metadata !{metadata !{{.*}}, metadata !{{.*}}, metadata !{{.*}}}
// 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: {{.*}} metadata [[VAR_T:![0-9]*]], {{.*}} ; [ DW_TAG_variable ] [var] [line [[VAR_LINE:[0-9]*]]]
+// CHECK: [[VAR_T]] = {{.*}}, metadata [[VAR_ARGS:![0-9]*]], i32 0, null, null} ; [ DW_TAG_class_type ] [line [[VAR_LINE]],
// CHECK: [[VAR_ARGS]] = metadata !{metadata !{{.*}}, metadata !{{.*}}, metadata !{{.*}}}
diff --git a/test/CodeGenCXX/debug-lambda-this.cpp b/test/CodeGenCXX/debug-lambda-this.cpp
index 7c37fbe..e7155e7 100644
--- a/test/CodeGenCXX/debug-lambda-this.cpp
+++ b/test/CodeGenCXX/debug-lambda-this.cpp
@@ -12,4 +12,4 @@ int D::d(int 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 ]
+// CHECK: {{.*}} [ DW_TAG_member ] [this] [line 11, size 64, align 64, offset 0] [private] [from ]
diff --git a/test/CodeGenCXX/default-destructor-synthesis.cpp b/test/CodeGenCXX/default-destructor-synthesis.cpp
index fac5cc0..af78004 100644
--- a/test/CodeGenCXX/default-destructor-synthesis.cpp
+++ b/test/CodeGenCXX/default-destructor-synthesis.cpp
@@ -24,7 +24,7 @@ struct M : Q, P {
Q q_arr[2][3];
};
-// CHECK: define i32 @_Z1fv() nounwind
+// CHECK: define i32 @_Z1fv() [[NUW:#[0-9]+]]
int f() {
{
count = 1;
@@ -34,3 +34,5 @@ int f() {
// CHECK: ret i32 1
return count;
}
+
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGenCXX/delete.cpp b/test/CodeGenCXX/delete.cpp
index 7a91ca8..1299b29 100644
--- a/test/CodeGenCXX/delete.cpp
+++ b/test/CodeGenCXX/delete.cpp
@@ -129,7 +129,7 @@ namespace test4 {
// 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
+ // CHECK-NEXT: call void @_ZdlPv(i8* [[ALLOCATED]]) [[NUW:#[0-9]+]]
::delete xp;
}
}
@@ -144,3 +144,5 @@ namespace test5 {
delete [] p2;
}
}
+
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGenCXX/derived-to-base.cpp b/test/CodeGenCXX/derived-to-base.cpp
index 76b79fc..c69b456 100644
--- a/test/CodeGenCXX/derived-to-base.cpp
+++ b/test/CodeGenCXX/derived-to-base.cpp
@@ -15,7 +15,7 @@ void f() {
b.f();
}
-// CHECK: define %struct.B* @_Z1fP1A(%struct.A* %a) nounwind
+// CHECK: define %struct.B* @_Z1fP1A(%struct.A* %a) [[NUW:#[0-9]+]]
B *f(A *a) {
// CHECK-NOT: br label
// CHECK: ret %struct.B*
@@ -25,7 +25,7 @@ B *f(A *a) {
// PR5965
namespace PR5965 {
-// CHECK: define %struct.A* @_ZN6PR59651fEP1B(%struct.B* %b) nounwind
+// CHECK: define %struct.A* @_ZN6PR59651fEP1B(%struct.B* %b) [[NUW]]
A *f(B* b) {
// CHECK-NOT: br label
// CHECK: ret %struct.A*
@@ -45,3 +45,5 @@ namespace test3 {
foo(B());
}
}
+
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGenCXX/destructors.cpp b/test/CodeGenCXX/destructors.cpp
index d665445..7dc188b 100644
--- a/test/CodeGenCXX/destructors.cpp
+++ b/test/CodeGenCXX/destructors.cpp
@@ -370,11 +370,11 @@ namespace test9 {
// CHECK: define internal void @_ZN5test312_GLOBAL__N_11DD0Ev(%"struct.test3::<anonymous namespace>::D"* %this) unnamed_addr
// CHECK: invoke void @_ZN5test312_GLOBAL__N_11DD1Ev(
- // CHECK: call void @_ZdlPv({{.*}}) nounwind
+ // CHECK: call void @_ZdlPv({{.*}}) [[NUW:#[0-9]+]]
// CHECK: ret void
// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
// CHECK-NEXT: cleanup
- // CHECK: call void @_ZdlPv({{.*}}) nounwind
+ // CHECK: call void @_ZdlPv({{.*}}) [[NUW]]
// CHECK: resume { i8*, i32 }
// Checked at top of file:
@@ -401,11 +401,11 @@ namespace test9 {
// CHECK: define internal void @_ZN5test312_GLOBAL__N_11CD0Ev(%"struct.test3::<anonymous namespace>::C"* %this) unnamed_addr
// CHECK: invoke void @_ZN5test312_GLOBAL__N_11CD1Ev(
- // CHECK: call void @_ZdlPv({{.*}}) nounwind
+ // CHECK: call void @_ZdlPv({{.*}}) [[NUW]]
// CHECK: ret void
// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
// CHECK-NEXT: cleanup
- // CHECK: call void @_ZdlPv({{.*}}) nounwind
+ // CHECK: call void @_ZdlPv({{.*}}) [[NUW]]
// CHECK: resume { i8*, i32 }
// CHECK: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD1Ev(
@@ -417,3 +417,5 @@ namespace test9 {
// CHECK: getelementptr inbounds i8* {{.*}}, i64 -8
// CHECK: call void @_ZN5test312_GLOBAL__N_11CD0Ev(
// CHECK: ret void
+
+ // CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGenCXX/dynamic-cast-always-null.cpp b/test/CodeGenCXX/dynamic-cast-always-null.cpp
index 836cb11..db4346f 100644
--- a/test/CodeGenCXX/dynamic-cast-always-null.cpp
+++ b/test/CodeGenCXX/dynamic-cast-always-null.cpp
@@ -13,7 +13,7 @@ C *f(B* b) {
// CHECK: @_Z1fR1B
C &f(B& b) {
// CHECK-NOT: call i8* @__dynamic_cast
- // CHECK: call void @__cxa_bad_cast() noreturn
+ // CHECK: call void @__cxa_bad_cast() [[NR:#[0-9]+]]
// CHECK: ret %struct.C* undef
return dynamic_cast<C&>(b);
}
@@ -22,3 +22,5 @@ void dont_crash() {
(void) dynamic_cast<void*>((A*)0);
(void) dynamic_cast<void*>((B*)0);
}
+
+// CHECK: attributes [[NR]] = { noreturn }
diff --git a/test/CodeGenCXX/dynamic-cast-hint.cpp b/test/CodeGenCXX/dynamic-cast-hint.cpp
new file mode 100644
index 0000000..27b76e0
--- /dev/null
+++ b/test/CodeGenCXX/dynamic-cast-hint.cpp
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin12 -emit-llvm -o - %s | FileCheck %s
+
+class A { virtual ~A() {} };
+class B { virtual ~B() {} };
+
+class C : A { char x; };
+class D : public A { short y; };
+class E : public A, public B { int z; };
+class F : public virtual A { long long w; };
+class G : virtual A { long long w; };
+
+class H : public E { int a; };
+class I : public F { char b; };
+
+class J : public H { char q; };
+class K : public C, public B { char q; };
+
+class XA : public A { };
+class XB : public A { };
+class XC : public virtual A { };
+class X : public XA, public XB, public XC { };
+
+void test(A *a, B *b) {
+ volatile C *ac = dynamic_cast<C *>(a);
+// CHECK: i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI1C to i8*), i64 -2)
+ volatile D *ad = dynamic_cast<D *>(a);
+// CHECK: i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i8* bitcast ({ i8*, i8*, i8* }* @_ZTI1D to i8*), i64 0)
+ volatile E *ae = dynamic_cast<E *>(a);
+// CHECK: i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64 }* @_ZTI1E to i8*), i64 0)
+ volatile F *af = dynamic_cast<F *>(a);
+// CHECK: i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI1F to i8*), i64 -1)
+ volatile G *ag = dynamic_cast<G *>(a);
+// CHECK: i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI1G to i8*), i64 -2)
+ volatile H *ah = dynamic_cast<H *>(a);
+// CHECK: i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i8* bitcast ({ i8*, i8*, i8* }* @_ZTI1H to i8*), i64 0)
+ volatile I *ai = dynamic_cast<I *>(a);
+// CHECK: i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i8* bitcast ({ i8*, i8*, i8* }* @_ZTI1I to i8*), i64 -1)
+ volatile J *aj = dynamic_cast<J *>(a);
+// CHECK: i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i8* bitcast ({ i8*, i8*, i8* }* @_ZTI1J to i8*), i64 0)
+ volatile K *ak = dynamic_cast<K *>(a);
+// CHECK: i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64 }* @_ZTI1K to i8*), i64 -2)
+ volatile X *ax = dynamic_cast<X *>(a);
+// CHECK: i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64, i8*, i64 }* @_ZTI1X to i8*), i64 -1)
+
+ volatile E *be = dynamic_cast<E *>(b);
+// CHECK: i8* bitcast ({ i8*, i8* }* @_ZTI1B to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64 }* @_ZTI1E to i8*), i64 8)
+ volatile G *bg = dynamic_cast<G *>(b);
+// CHECK: i8* bitcast ({ i8*, i8* }* @_ZTI1B to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64 }* @_ZTI1G to i8*), i64 -2)
+ volatile J *bj = dynamic_cast<J *>(b);
+// CHECK: i8* bitcast ({ i8*, i8* }* @_ZTI1B to i8*), i8* bitcast ({ i8*, i8*, i8* }* @_ZTI1J to i8*), i64 8)
+ volatile K *bk = dynamic_cast<K *>(b);
+// CHECK: i8* bitcast ({ i8*, i8* }* @_ZTI1B to i8*), i8* bitcast ({ i8*, i8*, i32, i32, i8*, i64, i8*, i64 }* @_ZTI1K to i8*), i64 16)
+}
diff --git a/test/CodeGenCXX/dynamic-cast.cpp b/test/CodeGenCXX/dynamic-cast.cpp
index 813e36e..fe85e21 100644
--- a/test/CodeGenCXX/dynamic-cast.cpp
+++ b/test/CodeGenCXX/dynamic-cast.cpp
@@ -8,7 +8,7 @@ const B& f(A *a) {
try {
// CHECK: call i8* @__dynamic_cast
// CHECK: br i1
- // CHECK: invoke void @__cxa_bad_cast() noreturn
+ // CHECK: invoke void @__cxa_bad_cast() [[NR:#[0-9]+]]
dynamic_cast<const B&>(*a);
} catch (...) {
// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
@@ -16,3 +16,8 @@ const B& f(A *a) {
}
return fail;
}
+
+// CHECK: declare i8* @__dynamic_cast(i8*, i8*, i8*, i64) [[NUW_RO:#[0-9]+]]
+
+// CHECK: attributes [[NUW_RO]] = { nounwind readonly }
+// CHECK: attributes [[NR]] = { noreturn }
diff --git a/test/CodeGenCXX/eh.cpp b/test/CodeGenCXX/eh.cpp
index 584af40..70887f7 100644
--- a/test/CodeGenCXX/eh.cpp
+++ b/test/CodeGenCXX/eh.cpp
@@ -14,7 +14,7 @@ void test1() {
// CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[DSTAR:%[^*]*\*]]
// CHECK-NEXT: [[EXN2:%.*]] = bitcast [[DSTAR]] [[EXN]] to i8*
// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[EXN2]], i8* bitcast ([[DSTAR]] @d1 to i8*), i64 8, i32 8, i1 false)
-// CHECK-NEXT: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast ({ i8*, i8* }* @_ZTI7test1_D to i8*), i8* null) noreturn
+// CHECK-NEXT: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast ({ i8*, i8* }* @_ZTI7test1_D to i8*), i8* null) [[NR:#[0-9]+]]
// CHECK-NEXT: unreachable
@@ -37,7 +37,7 @@ void test2() {
// CHECK-NEXT: invoke void @_ZN7test2_DC1ERKS_([[DSTAR]] [[EXN]], [[DSTAR]] @d2)
// CHECK-NEXT: to label %[[CONT:.*]] unwind label %{{.*}}
// : [[CONT]]: (can't check this in Release-Asserts builds)
-// CHECK: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast ({{.*}}* @_ZTI7test2_D to i8*), i8* null) noreturn
+// CHECK: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast ({{.*}}* @_ZTI7test2_D to i8*), i8* null) [[NR]]
// CHECK-NEXT: unreachable
@@ -55,7 +55,7 @@ void test3() {
// CHECK: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 8)
// CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[D:%[^*]+]]**
// CHECK-NEXT: store [[D]]* null, [[D]]** [[EXN]]
-// CHECK-NEXT: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast ({ i8*, i8*, i32, i8* }* @_ZTIPV7test3_D to i8*), i8* null) noreturn
+// CHECK-NEXT: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast ({ i8*, i8*, i32, i8* }* @_ZTIPV7test3_D to i8*), i8* null) [[NR]]
// CHECK-NEXT: unreachable
@@ -64,7 +64,7 @@ void test4() {
}
// CHECK: define void @_Z5test4v()
-// CHECK: call void @__cxa_rethrow() noreturn
+// CHECK: call void @__cxa_rethrow() [[NR]]
// CHECK-NEXT: unreachable
@@ -83,7 +83,7 @@ namespace test5 {
// CHECK: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 1)
// CHECK: [[EXNCAST:%.*]] = bitcast i8* [[EXNOBJ]] to [[A:%[^*]*]]*
// CHECK-NEXT: invoke void @_ZN5test51AC1Ev([[A]]* [[EXNCAST]])
-// CHECK: invoke void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast ({{.*}}* @_ZTIN5test51AE to i8*), i8* bitcast (void ([[A]]*)* @_ZN5test51AD1Ev to i8*)) noreturn
+// CHECK: invoke void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast ({{.*}}* @_ZTIN5test51AE to i8*), i8* bitcast (void ([[A]]*)* @_ZN5test51AD1Ev to i8*)) [[NR]]
// CHECK-NEXT: to label {{%.*}} unwind label %[[HANDLER:[^ ]*]]
// : [[HANDLER]]: (can't check this in Release-Asserts builds)
// CHECK: {{%.*}} = call i32 @llvm.eh.typeid.for(i8* bitcast ({{.*}}* @_ZTIN5test51AE to i8*))
@@ -222,7 +222,7 @@ namespace test10 {
// CHECK-NEXT: bitcast
// CHECK-NEXT: load i32*
// CHECK-NEXT: store i32
- // CHECK-NEXT: call void @__cxa_end_catch() nounwind
+ // CHECK-NEXT: call void @__cxa_end_catch() [[NUW:#[0-9]+]]
} catch (B a) {
// CHECK: call i8* @__cxa_begin_catch
// CHECK-NEXT: bitcast
@@ -251,11 +251,11 @@ namespace test11 {
opaque();
} catch (int**&p) {
// CHECK: [[EXN:%.*]] = load i8**
- // CHECK-NEXT: call i8* @__cxa_begin_catch(i8* [[EXN]]) nounwind
+ // CHECK-NEXT: call i8* @__cxa_begin_catch(i8* [[EXN]]) [[NUW]]
// CHECK-NEXT: [[ADJ1:%.*]] = getelementptr i8* [[EXN]], i32 32
// CHECK-NEXT: [[ADJ2:%.*]] = bitcast i8* [[ADJ1]] to i32***
// CHECK-NEXT: store i32*** [[ADJ2]], i32**** [[P:%.*]]
- // CHECK-NEXT: call void @__cxa_end_catch() nounwind
+ // CHECK-NEXT: call void @__cxa_end_catch() [[NUW]]
}
}
@@ -272,11 +272,11 @@ namespace test11 {
opaque();
} catch (A*&p) {
// CHECK: [[EXN:%.*]] = load i8** [[EXNSLOT]]
- // CHECK-NEXT: [[ADJ1:%.*]] = call i8* @__cxa_begin_catch(i8* [[EXN]]) nounwind
+ // CHECK-NEXT: [[ADJ1:%.*]] = call i8* @__cxa_begin_catch(i8* [[EXN]]) [[NUW]]
// CHECK-NEXT: [[ADJ2:%.*]] = bitcast i8* [[ADJ1]] to [[A]]*
// CHECK-NEXT: store [[A]]* [[ADJ2]], [[A]]** [[TMP]]
// CHECK-NEXT: store [[A]]** [[TMP]], [[A]]*** [[P]]
- // CHECK-NEXT: call void @__cxa_end_catch() nounwind
+ // CHECK-NEXT: call void @__cxa_end_catch() [[NUW]]
}
}
}
@@ -444,3 +444,6 @@ namespace test16 {
// CHECK-NEXT: br label
}
}
+
+// CHECK: attributes [[NUW]] = { nounwind }
+// CHECK: attributes [[NR]] = { noreturn }
diff --git a/test/CodeGenCXX/exception-spec-decay.cpp b/test/CodeGenCXX/exception-spec-decay.cpp
new file mode 100644
index 0000000..4928353
--- /dev/null
+++ b/test/CodeGenCXX/exception-spec-decay.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions %s -triple=i686-unknown-linux -emit-llvm -o - | FileCheck %s
+typedef int Array[10];
+
+void foo() throw (Array) {
+ throw 0;
+ // CHECK: landingpad
+ // CHECK-NEXT: filter {{.*}} @_ZTIPi
+}
+
+struct S {
+ void foo() throw (S[10]) {
+ throw 0;
+ }
+};
+
+template <typename T>
+struct S2 {
+ void foo() throw (T) {
+ throw 0;
+ }
+};
+
+int main() {
+ S s;
+ s.foo();
+ // CHECK: landingpad
+ // CHECK-NEXT: filter {{.*}} @_ZTIP1S
+
+ S2 <int[10]> s2;
+ s2.foo();
+ // CHECK: landingpad
+ // CHECK-NEXT: filter {{.*}} @_ZTIPi
+}
diff --git a/test/CodeGenCXX/exceptions.cpp b/test/CodeGenCXX/exceptions.cpp
index 723e8d1..f6f5079 100644
--- a/test/CodeGenCXX/exceptions.cpp
+++ b/test/CodeGenCXX/exceptions.cpp
@@ -69,6 +69,13 @@ namespace test1 {
return new A(B().x);
}
+ // rdar://11904428
+ // Terminate landing pads should call __cxa_begin_catch first.
+ // CHECK: define linkonce_odr hidden void @__clang_call_terminate(i8*) [[NI_NR_NUW:#[0-9]+]]
+ // CHECK-NEXT: [[T0:%.*]] = call i8* @__cxa_begin_catch(i8* %0) [[NUW:#[0-9]+]]
+ // CHECK-NEXT: call void @_ZSt9terminatev() [[NR_NUW:#[0-9]+]]
+ // CHECK-NEXT: unreachable
+
A *d() {
// CHECK: define [[A:%.*]]* @_ZN5test11dEv()
// CHECK: [[ACTIVE:%.*]] = alloca i1
@@ -157,7 +164,7 @@ namespace test2 {
// CHECK-NEXT: invoke void @_ZN5test21AC1Ei([[A]]* [[CAST]], i32 5)
// CHECK: ret [[A]]* [[CAST]]
// CHECK: invoke void @_ZN5test21AdlEPvm(i8* [[NEW]], i64 8)
- // CHECK: call void @_ZSt9terminatev()
+ // CHECK: call void @__clang_call_terminate(i8* {{%.*}}) [[NR_NUW]]
return new A(5);
}
}
@@ -183,7 +190,7 @@ namespace test3 {
// CHECK-NEXT: invoke void @_ZN5test31AC1Ei([[A]]* [[CAST]], i32 5)
// CHECK: ret [[A]]* [[CAST]]
// CHECK: invoke void @_ZN5test31AdlEPvS1_d(i8* [[NEW]], i8* [[FOO]], double [[BAR]])
- // CHECK: call void @_ZSt9terminatev()
+ // CHECK: call void @__clang_call_terminate(i8* {{%.*}}) [[NR_NUW]]
return new(foo(),bar()) A(5);
}
@@ -274,7 +281,7 @@ namespace test5 {
// CHECK-NEXT: invoke void @_ZN5test51TC1Ev([[T_T]]* [[T]])
// CHECK: invoke void @_ZN5test51AC1ERKS0_RKNS_1TE([[A_T]]* [[A]], [[A_T]]* [[SRC]], [[T_T]]* [[T]])
// CHECK: invoke void @_ZN5test51TD1Ev([[T_T]]* [[T]])
- // CHECK: call i8* @__cxa_begin_catch(i8* [[EXN]]) nounwind
+ // CHECK: call i8* @__cxa_begin_catch(i8* [[EXN]]) [[NUW]]
// CHECK-NEXT: invoke void @_ZN5test51AD1Ev([[A_T]]* [[A]])
// CHECK: call void @__cxa_end_catch()
void test() {
@@ -451,3 +458,72 @@ namespace test10 {
// CHECK: invoke void @__cxa_rethrow()
// CHECK: unreachable
}
+
+// Ensure that an exception in a constructor destroys
+// already-constructed array members. PR14514
+namespace test11 {
+ struct A {
+ A();
+ ~A() {}
+ };
+
+ struct C {
+ A single;
+ A array[2][3];
+
+ C();
+ };
+
+ C::C() {
+ throw 0;
+ }
+ // CHECK: define void @_ZN6test111CC2Ev(
+ // CHECK: [[THIS:%.*]] = load [[C:%.*]]** {{%.*}}
+ // Construct single.
+ // CHECK-NEXT: [[SINGLE:%.*]] = getelementptr inbounds [[C]]* [[THIS]], i32 0, i32 0
+ // CHECK-NEXT: call void @_ZN6test111AC1Ev([[A:%.*]]* [[SINGLE]])
+ // Construct array.
+ // CHECK-NEXT: [[ARRAY:%.*]] = getelementptr inbounds [[C]]* [[THIS]], i32 0, i32 1
+ // CHECK-NEXT: [[ARRAYBEGIN:%.*]] = getelementptr inbounds [2 x [3 x [[A]]]]* [[ARRAY]], i32 0, i32 0, i32 0
+ // CHECK-NEXT: [[ARRAYEND:%.*]] = getelementptr inbounds [[A]]* [[ARRAYBEGIN]], i64 6
+ // CHECK-NEXT: br label
+ // CHECK: [[CUR:%.*]] = phi [[A]]* [ [[ARRAYBEGIN]], {{%.*}} ], [ [[NEXT:%.*]], {{%.*}} ]
+ // CHECK-NEXT: invoke void @_ZN6test111AC1Ev([[A:%.*]]* [[CUR]])
+ // CHECK: [[NEXT]] = getelementptr inbounds [[A]]* [[CUR]], i64 1
+ // CHECK-NEXT: [[DONE:%.*]] = icmp eq [[A]]* [[NEXT]], [[ARRAYEND]]
+ // CHECK-NEXT: br i1 [[DONE]],
+ // throw 0;
+ // CHECK: invoke void @__cxa_throw(
+ // Landing pad 1, from constructor in array-initialization loop:
+ // CHECK: landingpad
+ // - First, destroy already-constructed bits of array.
+ // CHECK: [[EMPTY:%.*]] = icmp eq [[A]]* [[ARRAYBEGIN]], [[CUR]]
+ // CHECK-NEXT: br i1 [[EMPTY]]
+ // CHECK: [[AFTER:%.*]] = phi [[A]]* [ [[CUR]], {{%.*}} ], [ [[ELT:%.*]], {{%.*}} ]
+ // CHECK-NEXT: [[ELT]] = getelementptr inbounds [[A]]* [[AFTER]], i64 -1
+ // CHECK-NEXT: invoke void @_ZN6test111AD1Ev([[A]]* [[ELT]])
+ // CHECK: [[DONE:%.*]] = icmp eq [[A]]* [[ELT]], [[ARRAYBEGIN]]
+ // CHECK-NEXT: br i1 [[DONE]],
+ // - Next, chain to cleanup for single.
+ // CHECK: br label
+ // Landing pad 2, from throw site.
+ // CHECK: landingpad
+ // - First, destroy all of array.
+ // CHECK: [[ARRAYBEGIN:%.*]] = getelementptr inbounds [2 x [3 x [[A]]]]* [[ARRAY]], i32 0, i32 0, i32 0
+ // CHECK-NEXT: [[ARRAYEND:%.*]] = getelementptr inbounds [[A]]* [[ARRAYBEGIN]], i64 6
+ // CHECK-NEXT: br label
+ // CHECK: [[AFTER:%.*]] = phi [[A]]* [ [[ARRAYEND]], {{%.*}} ], [ [[ELT:%.*]], {{%.*}} ]
+ // CHECK-NEXT: [[ELT]] = getelementptr inbounds [[A]]* [[AFTER]], i64 -1
+ // CHECK-NEXT: invoke void @_ZN6test111AD1Ev([[A]]* [[ELT]])
+ // CHECK: [[DONE:%.*]] = icmp eq [[A]]* [[ELT]], [[ARRAYBEGIN]]
+ // CHECK-NEXT: br i1 [[DONE]],
+ // - Next, chain to cleanup for single.
+ // CHECK: br label
+ // Finally, the cleanup for single.
+ // CHECK: invoke void @_ZN6test111AD1Ev([[A]]* [[SINGLE]])
+ // CHECK: br label
+ // CHECK: resume
+ // (After this is a terminate landingpad.)
+}
+
+// CHECK: attributes [[NI_NR_NUW]] = { noinline noreturn nounwind }
diff --git a/test/CodeGenCXX/extern-c.cpp b/test/CodeGenCXX/extern-c.cpp
index ca5cd73..a8c4f0c 100644
--- a/test/CodeGenCXX/extern-c.cpp
+++ b/test/CodeGenCXX/extern-c.cpp
@@ -1,16 +1,38 @@
-// RUN: %clang_cc1 -emit-llvm %s -o %t
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
namespace foo {
-// RUN: not grep "@a = global i32" %t
+// CHECK-NOT: @a = global i32
extern "C" int a;
-// RUN: not grep "@_ZN3foo1bE = global i32" %t
+// CHECK-NOT: @_ZN3foo1bE = global i32
extern int b;
-// RUN: grep "@_ZN3foo1cE = global i32" %t | count 1
+// CHECK: @_ZN3foo1cE = global i32
int c = 5;
-// RUN: not grep "@_ZN3foo1dE" %t
+// CHECK-NOT: @_ZN3foo1dE
extern "C" struct d;
}
+
+namespace test1 {
+ namespace {
+ struct X {};
+ }
+ extern "C" {
+ // CHECK: @test1_b = global
+ X test1_b = X();
+ }
+ void *use = &test1_b;
+ // CHECK: @_ZN5test13useE = global
+}
+
+namespace test2 {
+ namespace {
+ struct X {};
+ }
+
+ // CHECK: @test2_b = global
+ extern "C" X test2_b;
+ X test2_b;
+}
diff --git a/test/CodeGenCXX/global-array-destruction.cpp b/test/CodeGenCXX/global-array-destruction.cpp
index 076ef94..087d655 100644
--- a/test/CodeGenCXX/global-array-destruction.cpp
+++ b/test/CodeGenCXX/global-array-destruction.cpp
@@ -43,3 +43,20 @@ T t[2][3] = { 1.0, 2, 3.0, 4, 5.0, 6, 7.0, 8, 9.0, 10, 11.0, 12 };
// CHECK: call void @_ZN1TD1Ev
// CHECK: icmp eq {{.*}} @t
// CHECK: br i1 {{.*}}
+
+static T t2[2][3] = { 1.0, 2, 3.0, 4, 5.0, 6, 7.0, 8, 9.0, 10, 11.0, 12 };
+
+// CHECK: call {{.*}} @__cxa_atexit
+// CHECK: getelementptr inbounds ({{.*}} bitcast {{.*}}* @_ZL2t2 to %struct.T*), i64 6
+// CHECK: call void @_ZN1TD1Ev
+// CHECK: icmp eq {{.*}} @_ZL2t
+// CHECK: br i1 {{.*}}
+
+using U = T[2][3];
+U &&u = U{ {{1.0, 2}, {3.0, 4}, {5.0, 6}}, {{7.0, 8}, {9.0, 10}, {11.0, 12}} };
+
+// CHECK: call {{.*}} @__cxa_atexit
+// CHECK: getelementptr inbounds ([2 x [3 x {{.*}}]]* @_ZGR1u, i64 1, i64 0, i64 0)
+// CHECK: call void @_ZN1TD1Ev
+// CHECK: icmp eq {{.*}} @_ZGR1u
+// CHECK: br i1 {{.*}}
diff --git a/test/CodeGenCXX/global-dtor-no-atexit.cpp b/test/CodeGenCXX/global-dtor-no-atexit.cpp
index def97b2..7c4b6aa 100644
--- a/test/CodeGenCXX/global-dtor-no-atexit.cpp
+++ b/test/CodeGenCXX/global-dtor-no-atexit.cpp
@@ -5,12 +5,12 @@
// CHECK: call void @_ZN1AC1Ev([[A:%.*]]* @a)
// CHECK-NEXT: call i32 @atexit(void ()* @__dtor_a)
-// CHECK: define internal void @__dtor_a() nounwind
+// CHECK: define internal void @__dtor_a() [[NUW:#[0-9]+]]
// CHECK: call void @_ZN1AD1Ev([[A]]* @a)
// CHECK: call void @_ZN1AC1Ev([[A]]* @b)
// CHECK-NEXT: call i32 @atexit(void ()* @__dtor_b)
-// CHECK: define internal void @__dtor_b() nounwind
+// CHECK: define internal void @__dtor_b() [[NUW]]
// CHECK: call void @_ZN1AD1Ev([[A]]* @b)
class A {
@@ -33,12 +33,14 @@ A a, b;
// CHECK-NEXT: call i32 @atexit(void ()* @__dtor__ZZ4funcvE2a2)
// CHECK-NEXT: call void @__cxa_guard_release(i64* @_ZGVZ4funcvE2a2)
-// CHECK: define internal void @__dtor__ZZ4funcvE2a1() nounwind
+// CHECK: define internal void @__dtor__ZZ4funcvE2a1() [[NUW]]
// CHECK: call void @_ZN1AD1Ev([[A]]* @_ZZ4funcvE2a1)
-// CHECK: define internal void @__dtor__ZZ4funcvE2a2() nounwind
+// CHECK: define internal void @__dtor__ZZ4funcvE2a2() [[NUW]]
// CHECK: call void @_ZN1AD1Ev([[A]]* @_ZZ4funcvE2a2)
void func() {
static A a1, a2;
}
+
+// CHECK: attributes [[NUW]] = { nounwind }
diff --git a/test/CodeGenCXX/global-init.cpp b/test/CodeGenCXX/global-init.cpp
index 2a53ad9..426cf9c 100644
--- a/test/CodeGenCXX/global-init.cpp
+++ b/test/CodeGenCXX/global-init.cpp
@@ -200,4 +200,6 @@ namespace test7 {
// CHECK: call void [[TEST1_Z_INIT]]
// rdar://problem/8090834: this should be nounwind
-// CHECK-NOEXC: define internal void @_GLOBAL__I_a() nounwind section "__TEXT,__StaticInit,regular,pure_instructions" {
+// CHECK-NOEXC: define internal void @_GLOBAL__I_a() [[NUW:#[0-9]+]] section "__TEXT,__StaticInit,regular,pure_instructions" {
+
+// CHECK-NOEXC: attributes [[NUW]] = { nounwind }
diff --git a/test/CodeGenCXX/implicit-copy-assign-operator.cpp b/test/CodeGenCXX/implicit-copy-assign-operator.cpp
index 0ec89fc..79586fb 100644
--- a/test/CodeGenCXX/implicit-copy-assign-operator.cpp
+++ b/test/CodeGenCXX/implicit-copy-assign-operator.cpp
@@ -44,7 +44,7 @@ void test_D(D d1, D d2) {
// CHECK: {{call.*_ZN1AaSERS_}}
// CHECK: {{call.*_ZN1BaSERS_}}
// CHECK: {{call.*_ZN1CaSERKS_}}
-// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 24}}
+// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 28}}
// CHECK: {{call.*_ZN1BaSERS_}}
// CHECK: br
// CHECK: {{call.*_ZN1CaSERKS_}}
diff --git a/test/CodeGenCXX/implicit-copy-constructor.cpp b/test/CodeGenCXX/implicit-copy-constructor.cpp
index 8a3a422..24e84d5 100644
--- a/test/CodeGenCXX/implicit-copy-constructor.cpp
+++ b/test/CodeGenCXX/implicit-copy-constructor.cpp
@@ -46,7 +46,7 @@ void f(D d) {
// CHECK: call void @_ZN1AD1Ev
// CHECK: call void @_ZN1AC2ERS_
// CHECK: call void @_ZN1BC2ERS_
-// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 24}}
+// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 28}}
// CHECK: call void @_ZN1BC1ERS_
// CHECK: br
// CHECK: {{icmp ult.*, 2}}
@@ -54,8 +54,7 @@ void f(D d) {
// CHECK: call void @_ZN1AC1Ev
// CHECK: call void @_ZN1CC1ERS_1A
// CHECK: call void @_ZN1AD1Ev
-// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 288}}
-// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 12}}
+// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 300}}
// CHECK: ret void
diff --git a/test/CodeGenCXX/inheriting-constructor.cpp b/test/CodeGenCXX/inheriting-constructor.cpp
index a998402..adb9f6d 100644
--- a/test/CodeGenCXX/inheriting-constructor.cpp
+++ b/test/CodeGenCXX/inheriting-constructor.cpp
@@ -1,11 +1,18 @@
// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
-// XFAIL: *
-
// PR12219
struct A { A(int); virtual ~A(); };
struct B : A { using A::A; ~B(); };
B::~B() {}
+
+B b(123);
+
// CHECK: define void @_ZN1BD0Ev
// CHECK: define void @_ZN1BD1Ev
// CHECK: define void @_ZN1BD2Ev
+
+// CHECK: define linkonce_odr void @_ZN1BC1Ei(
+// CHECK: call void @_ZN1BC2Ei(
+
+// CHECK: define linkonce_odr void @_ZN1BC2Ei(
+// CHECK: call void @_ZN1AC2Ei(
diff --git a/test/CodeGenCXX/key-function-vtable.cpp b/test/CodeGenCXX/key-function-vtable.cpp
index 8e474bd..0ecd898 100644
--- a/test/CodeGenCXX/key-function-vtable.cpp
+++ b/test/CodeGenCXX/key-function-vtable.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-none-linux-gnu %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple arm-apple-darwin %s -emit-llvm -o - | FileCheck %s
// Simple key function test
struct testa { virtual void a(); };
diff --git a/test/CodeGenCXX/lambda-expressions.cpp b/test/CodeGenCXX/lambda-expressions.cpp
index cee4f17..68ae68f 100644
--- a/test/CodeGenCXX/lambda-expressions.cpp
+++ b/test/CodeGenCXX/lambda-expressions.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s -fexceptions -std=c++11 | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -fblocks -emit-llvm -o - %s -fexceptions -std=c++11 | FileCheck %s
// CHECK-NOT: @unused
auto unused = [](int i) { return i+1; };
@@ -80,6 +80,26 @@ int g() {
return [] { return r; } ();
};
+// PR14773
+// CHECK: [[ARRVAL:%[0-9a-zA-Z]*]] = load i32* getelementptr inbounds ([0 x i32]* bitcast (<{}>* @_ZZ14staticarrayrefvE5array to [0 x i32]*), i32 0, i64 0), align 4
+// CHECK-NEXT: store i32 [[ARRVAL]]
+void staticarrayref(){
+ static int array[] = {};
+ (void)[](){
+ int (&xxx)[0] = array;
+ int y = xxx[0];
+ }();
+}
+
+// CHECK: define internal void @"_ZZ1hvEN3$_88__invokeEv"(%struct.A* noalias sret %agg.result) {{.*}} {
+// CHECK-NOT: =
+// CHECK: call void @"_ZZ1hvENK3$_8clEv"(%struct.A* sret %agg.result,
+// CHECK-NEXT: ret void
+struct A { ~A(); };
+void h() {
+ A (*h)() = [] { return A(); };
+}
+
// CHECK: define internal i32 @"_ZZ1fvEN3$_58__invokeEii"
// CHECK: store i32
// CHECK-NEXT: store i32
@@ -89,3 +109,14 @@ int g() {
// CHECK-NEXT: ret i32
// CHECK: define internal void @"_ZZ1e1ES_bEN3$_4D2Ev"
+
+// <rdar://problem/12778708>
+struct XXX {};
+void nestedCapture () {
+ XXX localKey;
+ ^() {
+ [&]() {
+ ^{ XXX k = localKey; };
+ };
+ };
+}
diff --git a/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp b/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp
index 27b4768..fbc6492 100644
--- a/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp
+++ b/test/CodeGenCXX/mangle-ms-back-references-pr13207.cpp
@@ -1,7 +1,5 @@
// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
-// FIXME: add tests for return types with complex templates when PR13389 is fixed.
-
template<class X, class Y, class Z>
class A {};
template<class X>
@@ -15,6 +13,8 @@ void foo_abb(A<char, B<char>, B<char> >) {}
// CHECK: "\01?foo_abb@@YAXV?$A@DV?$B@D@@V1@@@@Z"
void foo_abc(A<char, B<char>, C<char> >) {}
// CHECK: "\01?foo_abc@@YAXV?$A@DV?$B@D@@V?$C@D@@@@@Z"
+void foo_bt(bool a, B<bool(bool)> b) {}
+// CHECK: "\01?foo_bt@@YAX_NV?$B@$$A6A_N_N@Z@@@Z"
namespace N {
template<class X, class Y, class Z>
diff --git a/test/CodeGenCXX/mangle-ms-templates.cpp b/test/CodeGenCXX/mangle-ms-templates.cpp
index e16fe93..d0e8af4 100644
--- a/test/CodeGenCXX/mangle-ms-templates.cpp
+++ b/test/CodeGenCXX/mangle-ms-templates.cpp
@@ -78,3 +78,16 @@ namespace space {
void use() {
space::foo(42);
}
+
+// PR13455
+typedef void (*FunctionPointer)(void);
+
+template <FunctionPointer function>
+void FunctionPointerTemplate() {
+ function();
+}
+
+void spam() {
+ FunctionPointerTemplate<spam>();
+// CHECK: "\01??$FunctionPointerTemplate@$1?spam@@YAXXZ@@YAXXZ"
+}
diff --git a/test/CodeGenCXX/mangle-ms-vector-types.cpp b/test/CodeGenCXX/mangle-ms-vector-types.cpp
new file mode 100644
index 0000000..64cb725
--- /dev/null
+++ b/test/CodeGenCXX/mangle-ms-vector-types.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -fms-extensions -ffreestanding -target-feature +avx -emit-llvm %s -o - -cxx-abi microsoft -triple=i686-pc-win32 | FileCheck %s
+
+#include <xmmintrin.h>
+#include <emmintrin.h>
+#include <immintrin.h>
+
+void foo64(__m64) {}
+// CHECK: define void @"\01?foo64@@YAXT__m64@@@Z"
+
+void foo128(__m128) {}
+// CHECK: define void @"\01?foo128@@YAXT__m128@@@Z"
+
+void foo128d(__m128d) {}
+// CHECK: define void @"\01?foo128d@@YAXU__m128d@@@Z"
+
+void foo128i(__m128i) {}
+// CHECK: define void @"\01?foo128i@@YAXT__m128i@@@Z"
+
+void foo256(__m256) {}
+// CHECK: define void @"\01?foo256@@YAXT__m256@@@Z"
+
+void foo256d(__m256d) {}
+// CHECK: define void @"\01?foo256d@@YAXU__m256d@@@Z"
+
+void foo256i(__m256i) {}
+// CHECK: define void @"\01?foo256i@@YAXT__m256i@@@Z"
+
+// We have a custom mangling for vector types not standardized by Intel.
+void foov8hi(__v8hi) {}
+// CHECK: define void @"\01?foov8hi@@YAXT__clang_vec8_F@@@Z"
+
+// Clang does not support vectors of complex types, so we can't test the
+// mangling of them.
diff --git a/test/CodeGenCXX/mangle-ms.cpp b/test/CodeGenCXX/mangle-ms.cpp
index 0edb4b4..6441d67 100644
--- a/test/CodeGenCXX/mangle-ms.cpp
+++ b/test/CodeGenCXX/mangle-ms.cpp
@@ -3,6 +3,7 @@
// CHECK: @"\01?a@@3HA"
// CHECK: @"\01?b@N@@3HA"
+// CHECK: @"\01?anonymous@?A@N@@3HA"
// CHECK: @c
// CHECK: @"\01?d@foo@@0FB"
// CHECK: @"\01?e@foo@@1JC"
@@ -24,10 +25,16 @@
int a;
-namespace N { int b; }
+namespace N {
+ int b;
+
+ namespace {
+ int anonymous;
+ }
+}
static int c;
-int _c(void) {return c;}
+int _c(void) {return N::anonymous + c;}
// CHECK: @"\01?_c@@YAHXZ"
class foo {
diff --git a/test/CodeGenCXX/mangle.cpp b/test/CodeGenCXX/mangle.cpp
index ba1b3bf..e7955a8 100644
--- a/test/CodeGenCXX/mangle.cpp
+++ b/test/CodeGenCXX/mangle.cpp
@@ -218,7 +218,7 @@ struct S7 {
// PR5139
// CHECK: @_ZN2S7C1Ev
// CHECK: @_ZN2S7C2Ev
-// CHECK: @"_ZN2S73$_0C1Ev"
+// CHECK: @_ZN2S7Ut_C1Ev
S7::S7() {}
// PR5063
@@ -852,3 +852,26 @@ namespace test36 {
// CHECK: define weak_odr {{.*}} @_ZN6test362f1IJifEEENS_1AIXsZfp_EEEDpT_
template A<2> f1(int, float);
}
+
+namespace test37 {
+ struct foo {
+ struct {
+ } a;
+ typedef struct { } b;
+ typedef struct { } *c;
+ struct {
+ } d;
+ };
+ template<typename T> void func(T) { }
+ void test() {
+ // CHECK: define linkonce_odr void @_ZN6test374funcINS_3fooUt_EEEvT_
+ func(foo().a);
+ // CHECK: define linkonce_odr void @_ZN6test374funcINS_3fooUt0_EEEvT_
+ func(*foo::c());
+ // CHECK: define linkonce_odr void @_ZN6test374funcINS_3fooUt1_EEEvT_
+ func(foo().d);
+ }
+}
+
+// CHECK: define void @_Z6ASfuncPU3AS3i
+void ASfunc(__attribute__((address_space(3))) int* x) {}
diff --git a/test/CodeGenCXX/member-functions.cpp b/test/CodeGenCXX/member-functions.cpp
index 1310eb0..75b354c 100644
--- a/test/CodeGenCXX/member-functions.cpp
+++ b/test/CodeGenCXX/member-functions.cpp
@@ -1,66 +1,85 @@
-// RUN: %clang_cc1 -emit-llvm %s -triple x86_64-apple-darwin9 -o %t
+// RUN: %clang_cc1 -emit-llvm -triple x86_64-apple-darwin9 -o - %s | FileCheck %s
+
struct C {
void f();
void g(int, ...);
};
-// RUN: grep "define void @_ZN1C1fEv" %t | count 1
+// CHECK: define void @_ZN1C1fEv
void C::f() {
}
+// CHECK: define void @_Z5test1v
void test1() {
C c;
-
-// RUN: grep "call void @_ZN1C1fEv" %t | count 1
+
+ // CHECK: call void @_ZN1C1fEv
c.f();
-
-// RUN: grep "call void (.struct.C\*, i32, ...)\* @_ZN1C1gEiz" %t | count 1
+
+ // CHECK: call void (%struct.C*, i32, ...)* @_ZN1C1gEiz
c.g(1, 2, 3);
}
struct S {
- // RUN: grep "define linkonce_odr void @_ZN1SC1Ev.*unnamed_addr" %t
inline S() { }
- // RUN: grep "define linkonce_odr void @_ZN1SC1Ev.*unnamed_addr" %t
inline ~S() { }
-
-
- // RUN: grep "define linkonce_odr void @_ZN1S9f_inline1Ev" %t
+
void f_inline1() { }
- // RUN: grep "define linkonce_odr void @_ZN1S9f_inline2Ev" %t
inline void f_inline2() { }
-
- // RUN: grep "define linkonce_odr void @_ZN1S1gEv" %t
+
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
+// CHECK: define void @_ZN1S1fEv
void S::f() {
}
void test2() {
S s;
-
+
s.f_inline1();
s.f_inline2();
-
+
S::g();
-
}
+// S::S()
+// CHECK: define linkonce_odr void @_ZN1SC1Ev{{.*}} unnamed_addr
+
+// S::f_inline1()
+// CHECK: define linkonce_odr void @_ZN1S9f_inline1Ev
+
+// S::f_inline2()
+// CHECK: define linkonce_odr void @_ZN1S9f_inline2Ev
+
+// S::g()
+// CHECK: define linkonce_odr void @_ZN1S1gEv
+
+// S::~S()
+// CHECK: define linkonce_odr void @_ZN1SD1Ev{{.*}} unnamed_addr
+
struct T {
T operator+(const T&);
};
+// CHECK: define void @_Z5test3v
void test3() {
T t1, t2;
-
- // RUN: grep "call void @_ZN1TplERKS_" %t
+
+ // CHECK: call void @_ZN1TplERKS_
T result = t1 + t2;
}
+
+// S::~S()
+// CHECK: define linkonce_odr void @_ZN1SD2Ev{{.*}} unnamed_addr
+
+// S::S()
+// CHECK: define linkonce_odr void @_ZN1SC2Ev{{.*}} unnamed_addr
+
+// S::v()
+// CHECK: define linkonce_odr void @_ZN1S1vEv{{.*}}unnamed_addr
+
diff --git a/test/CodeGenCXX/member-initializers.cpp b/test/CodeGenCXX/member-initializers.cpp
index 244a164..c22b99d 100644
--- a/test/CodeGenCXX/member-initializers.cpp
+++ b/test/CodeGenCXX/member-initializers.cpp
@@ -12,7 +12,7 @@ struct B : A {
int i;
};
-// CHECK: define i32 @_Z1fv() nounwind
+// CHECK: define i32 @_Z1fv() #0
int f() {
B b;
@@ -21,7 +21,7 @@ int f() {
}
// Test that we don't try to fold the default value of j when initializing i.
-// CHECK: define i32 @_Z9test_foldv() nounwind
+// CHECK: define i32 @_Z9test_foldv() [[NUW_RN:#[0-9]+]]
int test_fold() {
struct A {
A(const int j = 1) : i(j) { }
@@ -32,3 +32,4 @@ int test_fold() {
return A(2).i;
}
+// CHECK: attributes [[NUW_RN]] = { nounwind readnone{{.*}} }
diff --git a/test/CodeGenCXX/microsoft-abi-array-cookies.cpp b/test/CodeGenCXX/microsoft-abi-array-cookies.cpp
index e07b097..1ba1f6a 100644
--- a/test/CodeGenCXX/microsoft-abi-array-cookies.cpp
+++ b/test/CodeGenCXX/microsoft-abi-array-cookies.cpp
@@ -5,7 +5,7 @@ struct ClassWithoutDtor {
};
void check_array_no_cookies() {
-// CHECK: define void @"\01?check_array_no_cookies@@YAXXZ"() nounwind
+// CHECK: define void @"\01?check_array_no_cookies@@YAXXZ"() [[NUW:#[0-9]+]]
// CHECK: call noalias i8* @"\01??_U@YAPAXI@Z"(i32 42)
ClassWithoutDtor *array = new ClassWithoutDtor[42];
@@ -57,3 +57,5 @@ void check_array_cookies_aligned() {
// CHECK: [[ARRAY_AS_CHAR:%.*]] = bitcast [[CLASS]]*
// CHECK: getelementptr inbounds i8* [[ARRAY_AS_CHAR]], i64 -8
}
+
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGenCXX/microsoft-abi-constructors.cpp b/test/CodeGenCXX/microsoft-abi-constructors.cpp
deleted file mode 100644
index 89731ff..0000000
--- a/test/CodeGenCXX/microsoft-abi-constructors.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
-
-class A {
- public:
- A() { }
- ~A() { }
-};
-
-void no_contstructor_destructor_infinite_recursion() {
- A a;
-
-// 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
index d0d25ce..7f2fc0a 100644
--- a/test/CodeGenCXX/microsoft-abi-default-cc.cpp
+++ b/test/CodeGenCXX/microsoft-abi-default-cc.cpp
@@ -28,8 +28,8 @@ public:
void baz();
void METHOD_CC qux();
- void static_baz();
- void __cdecl static_qux();
+ static void static_baz();
+ static void __cdecl static_qux();
};
void METHOD_CC A::baz() {}
diff --git a/test/CodeGenCXX/microsoft-abi-member-pointers.cpp b/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
new file mode 100755
index 0000000..997e007
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
+
+struct POD {
+ int a;
+ int b;
+};
+
+void podMemPtrs() {
+ int POD::*memptr;
+ memptr = &POD::a;
+ memptr = &POD::b;
+ if (memptr)
+ memptr = 0;
+// Check that member pointers use the right offsets and that null is -1.
+// CHECK: define void @"\01?podMemPtrs@@YAXXZ"() #0 {
+// CHECK: %[[memptr:.*]] = alloca i32, align 4
+// CHECK-NEXT: store i32 0, i32* %[[memptr]], align 4
+// CHECK-NEXT: store i32 4, i32* %[[memptr]], align 4
+// CHECK-NEXT: %[[memptr_val:.*]] = load i32* %[[memptr]], align 4
+// CHECK-NEXT: %{{.*}} = icmp ne i32 %[[memptr_val]], -1
+// CHECK-NEXT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
+// CHECK: store i32 -1, i32* %[[memptr]], align 4
+// CHECK: ret void
+// CHECK: }
+}
+
+struct Polymorphic {
+ virtual void myVirtual();
+ int a;
+ int b;
+};
+
+void polymorphicMemPtrs() {
+ int Polymorphic::*memptr;
+ memptr = &Polymorphic::a;
+ memptr = &Polymorphic::b;
+ if (memptr)
+ memptr = 0;
+// Member pointers for polymorphic classes include the vtable slot in their
+// offset and use 0 to represent null.
+// CHECK: define void @"\01?polymorphicMemPtrs@@YAXXZ"() #0 {
+// CHECK: %[[memptr:.*]] = alloca i32, align 4
+// CHECK-NEXT: store i32 4, i32* %[[memptr]], align 4
+// CHECK-NEXT: store i32 8, i32* %[[memptr]], align 4
+// CHECK-NEXT: %[[memptr_val:.*]] = load i32* %[[memptr]], align 4
+// CHECK-NEXT: %{{.*}} = icmp ne i32 %[[memptr_val]], 0
+// CHECK-NEXT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
+// CHECK: store i32 0, i32* %[[memptr]], align 4
+// CHECK: ret void
+// CHECK: }
+}
diff --git a/test/CodeGenCXX/microsoft-abi-static-initializers.cpp b/test/CodeGenCXX/microsoft-abi-static-initializers.cpp
index 448f1ee..35e343b 100644
--- a/test/CodeGenCXX/microsoft-abi-static-initializers.cpp
+++ b/test/CodeGenCXX/microsoft-abi-static-initializers.cpp
@@ -5,12 +5,12 @@ struct S {
~S() {}
} s;
-// CHECK: define internal void [[INIT_s:@.*global_var.*]] nounwind
+// CHECK: define internal void [[INIT_s:@.*global_var.*]] [[NUW:#[0-9]+]]
// CHECK: %{{[.0-9A-Z_a-z]+}} = call x86_thiscallcc %struct.S* @"\01??0S@@QAE@XZ"
// CHECK: call i32 @atexit(void ()* @"__dtor_\01?s@@3US@@A")
// CHECK: ret void
-// CHECK: define internal void @"__dtor_\01?s@@3US@@A"() nounwind {
+// CHECK: define internal void @"__dtor_\01?s@@3US@@A"() [[NUW]] {
// CHECK: call x86_thiscallcc void @"\01??1S@@QAE@XZ"
// CHECK: ret void
@@ -33,7 +33,7 @@ void force_usage() {
(void)B<int>::foo; // (void) - force usage
}
-// CHECK: define internal void [[INIT_foo:@.*global_var.*]] nounwind
+// CHECK: define internal void [[INIT_foo:@.*global_var.*]] [[NUW]]
// CHECK: %{{[.0-9A-Z_a-z]+}} = call x86_thiscallcc %class.A* @"\01??0A@@QAE@XZ"
// CHECK: call i32 @atexit(void ()* [[FOO_DTOR:@"__dtor_.*foo@.*]])
// CHECK: ret void
@@ -46,7 +46,9 @@ void force_usage() {
// CHECK: call x86_thiscallcc void @"\01??1A@@QAE@XZ"{{.*}}foo
// CHECK: ret void
-// CHECK: define internal void @_GLOBAL__I_a() nounwind {
+// CHECK: define internal void @_GLOBAL__I_a() [[NUW]] {
// CHECK: call void [[INIT_s]]
// CHECK: call void [[INIT_foo]]
// CHECK: ret void
+
+// CHECK: attributes [[NUW]] = { nounwind }
diff --git a/test/CodeGenCXX/microsoft-abi-structors.cpp b/test/CodeGenCXX/microsoft-abi-structors.cpp
new file mode 100644
index 0000000..864540d
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-abi-structors.cpp
@@ -0,0 +1,215 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 -fno-rtti > %t 2>&1
+// RUN: FileCheck %s < %t
+// Using a different check prefix as the inline destructors might be placed
+// anywhere in the output.
+// RUN: FileCheck --check-prefix=DTORS %s < %t
+
+namespace basic {
+
+class A {
+ public:
+ A() { }
+ ~A() { }
+};
+
+void no_constructor_destructor_infinite_recursion() {
+ A a;
+
+// CHECK: define linkonce_odr x86_thiscallcc %"class.basic::A"* @"\01??0A@basic@@QAE@XZ"(%"class.basic::A"* %this)
+// CHECK: [[THIS_ADDR:%[.0-9A-Z_a-z]+]] = alloca %"class.basic::A"*, align 4
+// CHECK-NEXT: store %"class.basic::A"* %this, %"class.basic::A"** [[THIS_ADDR]], align 4
+// CHECK-NEXT: [[T1:%[.0-9A-Z_a-z]+]] = load %"class.basic::A"** [[THIS_ADDR]]
+// CHECK-NEXT: ret %"class.basic::A"* [[T1]]
+// CHECK-NEXT: }
+
+// Make sure that the destructor doesn't call itself:
+// CHECK: define {{.*}} @"\01??1A@basic@@QAE@XZ"
+// CHECK-NOT: call void @"\01??1A@basic@@QAE@XZ"
+// CHECK: ret
+}
+
+struct B {
+ B();
+};
+
+// Tests that we can define constructors outside the class (PR12784).
+B::B() {
+ // CHECK: define x86_thiscallcc %"struct.basic::B"* @"\01??0B@basic@@QAE@XZ"(%"struct.basic::B"* %this)
+ // CHECK: ret
+}
+
+struct C {
+ virtual ~C() {
+// Complete destructor first:
+// DTORS: define {{.*}} x86_thiscallcc void @"\01??1C@basic@@UAE@XZ"(%"struct.basic::C"* %this)
+
+// Then, the scalar deleting destructor (used in the vtable):
+// FIXME: add a test that verifies that the out-of-line scalar deleting
+// destructor is linkonce_odr too.
+// DTORS: define linkonce_odr x86_thiscallcc void @"\01??_GC@basic@@UAEPAXI@Z"(%"struct.basic::C"* %this, i1 zeroext %should_call_delete)
+// DTORS: %[[FROMBOOL:[0-9a-z]+]] = zext i1 %should_call_delete to i8
+// DTORS-NEXT: store i8 %[[FROMBOOL]], i8* %[[SHOULD_DELETE_VAR:[0-9a-z._]+]], align 1
+// DTORS: %[[SHOULD_DELETE_VALUE:[0-9a-z._]+]] = load i8* %[[SHOULD_DELETE_VAR]]
+// DTORS: call x86_thiscallcc void @"\01??1C@basic@@UAE@XZ"(%"struct.basic::C"* %[[THIS:[0-9a-z]+]])
+// DTORS-NEXT: %[[CONDITION:[0-9]+]] = icmp eq i8 %[[SHOULD_DELETE_VALUE]], 0
+// DTORS-NEXT: br i1 %[[CONDITION]], label %[[CONTINUE_LABEL:[0-9a-z._]+]], label %[[CALL_DELETE_LABEL:[0-9a-z._]+]]
+//
+// DTORS: [[CALL_DELETE_LABEL]]
+// DTORS-NEXT: %[[THIS_AS_VOID:[0-9a-z]+]] = bitcast %"struct.basic::C"* %[[THIS]] to i8*
+// DTORS-NEXT: call void @"\01??3@YAXPAX@Z"(i8* %[[THIS_AS_VOID]]) [[NUW:#[0-9]+]]
+// DTORS-NEXT: br label %[[CONTINUE_LABEL]]
+//
+// DTORS: [[CONTINUE_LABEL]]
+// DTORS-NEXT: ret void
+ }
+ virtual void foo();
+};
+
+// Emits the vftable in the output.
+void C::foo() {}
+
+void check_vftable_offset() {
+ C c;
+// The vftable pointer should point at the beginning of the vftable.
+// CHECK: [[THIS_PTR:%[0-9]+]] = bitcast %"struct.basic::C"* {{.*}} to i8***
+// CHECK: store i8** getelementptr inbounds ([2 x i8*]* @"\01??_7C@basic@@6B@", i64 0, i64 0), i8*** [[THIS_PTR]]
+}
+
+void call_complete_dtor(C *obj_ptr) {
+// CHECK: define void @"\01?call_complete_dtor@basic@@YAXPAUC@1@@Z"(%"struct.basic::C"* %obj_ptr)
+ obj_ptr->~C();
+// CHECK: %[[OBJ_PTR_VALUE:.*]] = load %"struct.basic::C"** %{{.*}}, align 4
+// CHECK-NEXT: %[[PVTABLE:.*]] = bitcast %"struct.basic::C"* %[[OBJ_PTR_VALUE]] to void (%"struct.basic::C"*, i1)***
+// CHECK-NEXT: %[[VTABLE:.*]] = load void (%"struct.basic::C"*, i1)*** %[[PVTABLE]]
+// CHECK-NEXT: %[[PVDTOR:.*]] = getelementptr inbounds void (%"struct.basic::C"*, i1)** %[[VTABLE]], i64 0
+// CHECK-NEXT: %[[VDTOR:.*]] = load void (%"struct.basic::C"*, i1)** %[[PVDTOR]]
+// CHECK-NEXT: call x86_thiscallcc void %[[VDTOR]](%"struct.basic::C"* %[[OBJ_PTR_VALUE]], i1 zeroext false)
+// CHECK-NEXT: ret void
+}
+
+void call_deleting_dtor(C *obj_ptr) {
+// CHECK: define void @"\01?call_deleting_dtor@basic@@YAXPAUC@1@@Z"(%"struct.basic::C"* %obj_ptr)
+ delete obj_ptr;
+// CHECK: %[[OBJ_PTR_VALUE:.*]] = load %"struct.basic::C"** %{{.*}}, align 4
+// CHECK: br i1 {{.*}}, label %[[DELETE_NULL:.*]], label %[[DELETE_NOTNULL:.*]]
+
+// CHECK: [[DELETE_NOTNULL]]
+// CHECK-NEXT: %[[PVTABLE:.*]] = bitcast %"struct.basic::C"* %[[OBJ_PTR_VALUE]] to void (%"struct.basic::C"*, i1)***
+// CHECK-NEXT: %[[VTABLE:.*]] = load void (%"struct.basic::C"*, i1)*** %[[PVTABLE]]
+// CHECK-NEXT: %[[PVDTOR:.*]] = getelementptr inbounds void (%"struct.basic::C"*, i1)** %[[VTABLE]], i64 0
+// CHECK-NEXT: %[[VDTOR:.*]] = load void (%"struct.basic::C"*, i1)** %[[PVDTOR]]
+// CHECK-NEXT: call x86_thiscallcc void %[[VDTOR]](%"struct.basic::C"* %[[OBJ_PTR_VALUE]], i1 zeroext true)
+// CHECK: ret void
+}
+
+struct D {
+ static int foo();
+
+ D() {
+ static int ctor_static = foo();
+ // CHECK that the static in the ctor gets mangled correctly:
+ // CHECK: @"\01?ctor_static@?1???0D@basic@@QAE@XZ@4HA"
+ }
+ ~D() {
+ static int dtor_static = foo();
+ // CHECK that the static in the dtor gets mangled correctly:
+ // CHECK: @"\01?dtor_static@?1???1D@basic@@QAE@XZ@4HA"
+ }
+};
+
+void use_D() { D c; }
+
+// DTORS: attributes [[NUW]] = { nounwind{{.*}} }
+
+} // end namespace basic
+
+
+namespace constructors {
+
+struct A {
+ A() {}
+};
+
+struct B : A {
+ B();
+ ~B();
+};
+
+B::B() {
+ // CHECK: define x86_thiscallcc %"struct.constructors::B"* @"\01??0B@constructors@@QAE@XZ"(%"struct.constructors::B"* %this)
+ // CHECK: call x86_thiscallcc %"struct.constructors::A"* @"\01??0A@constructors@@QAE@XZ"(%"struct.constructors::A"* %{{.*}})
+ // CHECK: ret
+}
+
+struct C : virtual A {
+ C();
+};
+
+C::C() {
+ // CHECK: define x86_thiscallcc %"struct.constructors::C"* @"\01??0C@constructors@@QAE@XZ"(%"struct.constructors::C"* %this, i32 %is_most_derived)
+ // TODO: make sure this works in the Release build too;
+ // CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4
+ // CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]]
+ // CHECK: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0
+ // CHECK: br i1 %[[SHOULD_CALL_VBASE_CTORS]], label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]]
+ //
+ // CHECK: [[INIT_VBASES]]
+ // CHECK-NEXT: bitcast %"struct.constructors::C"* %{{.*}} to %"struct.constructors::A"*
+ // CHECK-NEXT: call x86_thiscallcc %"struct.constructors::A"* @"\01??0A@constructors@@QAE@XZ"(%"struct.constructors::A"* %{{.*}})
+ // CHECK-NEXT: br label %[[SKIP_VBASES]]
+ //
+ // CHECK: [[SKIP_VBASES]]
+ // CHECK: @"\01??_7C@constructors@@6B@"
+ // CHECK: ret
+}
+
+void create_C() {
+ C c;
+ // CHECK: define void @"\01?create_C@constructors@@YAXXZ"()
+ // CHECK: call x86_thiscallcc %"struct.constructors::C"* @"\01??0C@constructors@@QAE@XZ"(%"struct.constructors::C"* %c, i32 1)
+ // CHECK: ret
+}
+
+struct D : C {
+ D();
+};
+
+D::D() {
+ // CHECK: define x86_thiscallcc %"struct.constructors::D"* @"\01??0D@constructors@@QAE@XZ"(%"struct.constructors::D"* %this, i32 %is_most_derived) unnamed_addr
+ // CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4
+ // CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]]
+ // CHECK: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0
+ // CHECK: br i1 %[[SHOULD_CALL_VBASE_CTORS]], label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]]
+ //
+ // CHECK: [[INIT_VBASES]]
+ // CHECK-NEXT: bitcast %"struct.constructors::D"* %{{.*}} to %"struct.constructors::A"*
+ // CHECK-NEXT: call x86_thiscallcc %"struct.constructors::A"* @"\01??0A@constructors@@QAE@XZ"(%"struct.constructors::A"* %{{.*}})
+ // CHECK-NEXT: br label %[[SKIP_VBASES]]
+ //
+ // CHECK: [[SKIP_VBASES]]
+ // CHECK: call x86_thiscallcc %"struct.constructors::C"* @"\01??0C@constructors@@QAE@XZ"(%"struct.constructors::C"* %{{.*}}, i32 0)
+ // CHECK: ret
+}
+
+struct E : virtual C {
+ E();
+};
+
+E::E() {
+ // CHECK: define x86_thiscallcc %"struct.constructors::E"* @"\01??0E@constructors@@QAE@XZ"(%"struct.constructors::E"* %this, i32 %is_most_derived) unnamed_addr
+ // CHECK: store i32 %is_most_derived, i32* %[[IS_MOST_DERIVED_VAR:.*]], align 4
+ // CHECK: %[[IS_MOST_DERIVED_VAL:.*]] = load i32* %[[IS_MOST_DERIVED_VAR]]
+ // CHECK: %[[SHOULD_CALL_VBASE_CTORS:.*]] = icmp ne i32 %[[IS_MOST_DERIVED_VAL]], 0
+ // CHECK: br i1 %[[SHOULD_CALL_VBASE_CTORS]], label %[[INIT_VBASES:.*]], label %[[SKIP_VBASES:.*]]
+ //
+ // CHECK: [[INIT_VBASES]]
+ // CHECK-NEXT: bitcast %"struct.constructors::E"* %{{.*}} to %"struct.constructors::A"*
+ // CHECK-NEXT: call x86_thiscallcc %"struct.constructors::A"* @"\01??0A@constructors@@QAE@XZ"(%"struct.constructors::A"* %{{.*}})
+ // CHECK: call x86_thiscallcc %"struct.constructors::C"* @"\01??0C@constructors@@QAE@XZ"(%"struct.constructors::C"* %{{.*}}, i32 0)
+ // CHECK-NEXT: br label %[[SKIP_VBASES]]
+ //
+ // CHECK: [[SKIP_VBASES]]
+ // CHECK: ret
+}
+
+} // end namespace constructors
diff --git a/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp
new file mode 100644
index 0000000..5d430db
--- /dev/null
+++ b/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp
@@ -0,0 +1,113 @@
+// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=i386-pc-win32 -emit-llvm -fdump-vtable-layouts -o - > %t 2>&1
+// RUN: FileCheck --check-prefix=EMITS-VTABLE %s < %t
+// RUN: FileCheck --check-prefix=CHECK-A %s < %t
+// RUN: FileCheck --check-prefix=CHECK-B %s < %t
+// RUN: FileCheck --check-prefix=CHECK-C %s < %t
+// RUN: FileCheck --check-prefix=CHECK-D %s < %t
+// RUN: FileCheck --check-prefix=CHECK-E %s < %t
+// RUN: FileCheck --check-prefix=CHECK-F %s < %t
+// RUN: FileCheck --check-prefix=CHECK-G %s < %t
+
+struct A {
+ // CHECK-A: Vtable for 'A' (3 entries)
+ // CHECK-A-NEXT: 0 | void A::f()
+ // CHECK-A-NEXT: 1 | void A::g()
+ // CHECK-A-NEXT: 2 | void A::h()
+ // EMITS-VTABLE: @"\01??_7A@@6B@" = unnamed_addr constant [3 x i8*]
+ virtual void f();
+ virtual void g();
+ virtual void h();
+ int ia;
+};
+void A::f() {}
+
+struct B : A {
+ // CHECK-B: Vtable for 'B' (5 entries)
+ // CHECK-B-NEXT: 0 | void B::f()
+ // CHECK-B-NEXT: 1 | void A::g()
+ // CHECK-B-NEXT: 2 | void A::h()
+ // CHECK-B-NEXT: 3 | void B::i()
+ // CHECK-B-NEXT: 4 | void B::j()
+ // EMITS-VTABLE: @"\01??_7B@@6B@" = unnamed_addr constant [5 x i8*]
+ virtual void f(); // overrides A::f()
+ virtual void i();
+ virtual void j();
+};
+void B::f() {}
+
+struct C {
+ // CHECK-C: Vtable for 'C' (2 entries)
+ // CHECK-C-NEXT: 0 | C::~C() [scalar deleting]
+ // CHECK-C-NEXT: 1 | void C::f()
+ // CHECK-C: VTable indices for 'C' (2 entries).
+ // CHECK-C-NEXT: 0 | C::~C() [scalar deleting]
+ // CHECK-C-NEXT: 1 | void C::f()
+ // Never used, so doesn't emit a vtable.
+ virtual ~C();
+
+ virtual void f();
+};
+void C::f() {}
+
+struct D {
+ // CHECK-D: Vtable for 'D' (2 entries)
+ // CHECK-D-NEXT: 0 | void D::f()
+ // CHECK-D-NEXT: 1 | D::~D() [scalar deleting]
+ // EMITS-VTABLE: @"\01??_7D@@6B@" = unnamed_addr constant [2 x i8*]
+ virtual void f();
+
+ virtual ~D();
+};
+void D::f() {}
+
+struct E : A {
+ // CHECK-E: Vtable for 'E' (5 entries)
+ // CHECK-E-NEXT: 0 | void A::f()
+ // CHECK-E-NEXT: 1 | void A::g()
+ // CHECK-E-NEXT: 2 | void A::h()
+ // CHECK-E-NEXT: 3 | E::~E() [scalar deleting]
+ // CHECK-E-NEXT: 4 | void E::i()
+ // CHECK-E: VTable indices for 'E' (2 entries).
+ // CHECK-E-NEXT: 3 | E::~E() [scalar deleting]
+ // CHECK-E-NEXT: 4 | void E::i()
+
+ // Never used, so doesn't emit a vtable.
+ virtual ~E();
+ virtual void i();
+};
+void E::i() {}
+
+struct F : A {
+ // CHECK-F: Vtable for 'F' (5 entries)
+ // CHECK-F-NEXT: 0 | void A::f()
+ // CHECK-F-NEXT: 1 | void A::g()
+ // CHECK-F-NEXT: 2 | void A::h()
+ // CHECK-F-NEXT: 3 | void F::i()
+ // CHECK-F-NEXT: 4 | F::~F() [scalar deleting]
+ // CHECK-F: VTable indices for 'F' (2 entries).
+ // CHECK-F-NEXT: 3 | void F::i()
+ // CHECK-F-NEXT: 4 | F::~F() [scalar deleting]
+ // EMITS-VTABLE: @"\01??_7F@@6B@" = unnamed_addr constant [5 x i8*]
+ virtual void i();
+ virtual ~F();
+};
+void F::i() {}
+
+struct G : E {
+ // CHECK-G: Vtable for 'G' (6 entries)
+ // CHECK-G-NEXT: 0 | void G::f()
+ // CHECK-G-NEXT: 1 | void A::g()
+ // CHECK-G-NEXT: 2 | void A::h()
+ // CHECK-G-NEXT: 3 | G::~G() [scalar deleting]
+ // CHECK-G-NEXT: 4 | void E::i()
+ // CHECK-G-NEXT: 5 | void G::j()
+ // CHECK-G: VTable indices for 'G' (3 entries).
+ // CHECK-G-NEXT: 0 | void G::f()
+ // CHECK-G-NEXT: 3 | G::~G() [scalar deleting]
+ // CHECK-G-NEXT: 5 | void G::j()
+ // Never used, so doesn't emit a vtable.
+ virtual void f(); // overrides A::f()
+ virtual ~G();
+ virtual void j();
+};
+void G::j() {}
diff --git a/test/CodeGenCXX/no-exceptions.cpp b/test/CodeGenCXX/no-exceptions.cpp
index da672c4..ceb3b8e 100644
--- a/test/CodeGenCXX/no-exceptions.cpp
+++ b/test/CodeGenCXX/no-exceptions.cpp
@@ -2,7 +2,7 @@
void g();
-// CHECK: define void @_Z1fv() nounwind
+// CHECK: define void @_Z1fv() [[NUW:#[0-9]+]]
void f() throw (int) {
// CHECK-NOT: invoke void @_Z1gv
@@ -10,3 +10,5 @@ void f() throw (int) {
// CHECK: call void @_Z1gv()
// CHECK: ret void
}
+
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGenCXX/no-opt-volatile-memcpy.cpp b/test/CodeGenCXX/no-opt-volatile-memcpy.cpp
new file mode 100644
index 0000000..e542e4a
--- /dev/null
+++ b/test/CodeGenCXX/no-opt-volatile-memcpy.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -O0 -triple=x86_64-apple-darwin -emit-llvm -o - %s | FileCheck %s
+// rdar://11861085
+
+struct s {
+ char filler [128];
+ volatile int x;
+};
+
+struct s gs;
+
+void foo (void) {
+ struct s ls;
+ ls = ls;
+ gs = gs;
+ ls = gs;
+}
+// CHECK: define void @_Z3foov()
+// CHECK: %[[LS:.*]] = alloca %struct.s, align 4
+// CHECK-NEXT: %[[ZERO:.*]] = bitcast %struct.s* %[[LS]] to i8*
+// CHECK-NEXT: %[[ONE:.*]] = bitcast %struct.s* %[[LS]] to i8*
+// CHECK-NEXT: call void @llvm.memcpy.{{.*}}(i8* %[[ZERO]], i8* %[[ONE]], i64 132, i32 4, i1 true)
+// CHECK-NEXT: call void @llvm.memcpy.{{.*}}(i8* getelementptr inbounds (%struct.s* @gs, i32 0, i32 0, i32 0), i8* getelementptr inbounds (%struct.s* @gs, i32 0, i32 0, i32 0), i64 132, i32 4, i1 true)
+// CHECK-NEXT: %[[TWO:.*]] = bitcast %struct.s* %[[LS]] to i8*
+// CHECK-NEXT: call void @llvm.memcpy.{{.*}}(i8* %[[TWO]], i8* getelementptr inbounds (%struct.s* @gs, i32 0, i32 0, i32 0), i64 132, i32 4, i1 true)
+
+
+struct s1 {
+ struct s y;
+};
+
+struct s1 s;
+
+void fee (void) {
+ s = s;
+ s.y = gs;
+}
+// CHECK: define void @_Z3feev()
+// CHECK: call void @llvm.memcpy.{{.*}}(i8* getelementptr inbounds (%struct.s1* @s, i32 0, i32 0, i32 0, i32 0), i8* getelementptr inbounds (%struct.s1* @s, i32 0, i32 0, i32 0, i32 0), i64 132, i32 4, i1 true)
+// CHECK-NEXT: call void @llvm.memcpy.{{.*}}(i8* getelementptr inbounds (%struct.s1* @s, i32 0, i32 0, i32 0, i32 0), i8* getelementptr inbounds (%struct.s* @gs, i32 0, i32 0, i32 0), i64 132, i32 4, i1 true)
+
+struct d : s1 {
+};
+
+d gd;
+
+void gorf(void) {
+ gd = gd;
+}
+// CHECK: define void @_Z4gorfv()
+// CHECK: call void @llvm.memcpy.{{.*}}(i8* getelementptr inbounds (%struct.d* @gd, i32 0, i32 0, i32 0, i32 0, i32 0), i8* getelementptr inbounds (%struct.d* @gd, i32 0, i32 0, i32 0, i32 0, i32 0), i64 132, i32 4, i1 true)
diff --git a/test/CodeGenCXX/noinline-template.cpp b/test/CodeGenCXX/noinline-template.cpp
index 6ee3935..51a84f7 100644
--- a/test/CodeGenCXX/noinline-template.cpp
+++ b/test/CodeGenCXX/noinline-template.cpp
@@ -3,7 +3,7 @@
// This was a problem in Sema, but only shows up as noinline missing
// in CodeGen.
-// CHECK: define linkonce_odr void @_ZN6VectorIiE13growStorageByEv(%struct.Vector* %this) nounwind noinline
+// CHECK: define linkonce_odr void @_ZN6VectorIiE13growStorageByEv(%struct.Vector* %this) [[NI:#[0-9]+]]
template <class Ty> struct Vector {
void growStorageBy();
@@ -14,3 +14,5 @@ void foo() {
Vector<int> strs;
strs.growStorageBy();
}
+
+// CHECK: attributes [[NI]] = { noinline nounwind{{.*}} }
diff --git a/test/CodeGenCXX/nrvo.cpp b/test/CodeGenCXX/nrvo.cpp
index 8ff7dd7..747ab6d 100644
--- a/test/CodeGenCXX/nrvo.cpp
+++ b/test/CodeGenCXX/nrvo.cpp
@@ -100,9 +100,10 @@ X test2(bool B) {
// CHECK-EH: resume { i8*, i32 }
// %terminate.lpad: terminate landing pad.
- // CHECK-EH: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+ // CHECK-EH: [[T0:%.*]] = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
// CHECK-EH-NEXT: catch i8* null
- // CHECK-EH-NEXT: call void @_ZSt9terminatev()
+ // CHECK-EH-NEXT: [[T1:%.*]] = extractvalue { i8*, i32 } [[T0]], 0
+ // CHECK-EH-NEXT: call void @__clang_call_terminate(i8* [[T1]]) [[NR_NUW:#[0-9]+]]
// CHECK-EH-NEXT: unreachable
}
@@ -159,3 +160,5 @@ X test6() {
// CHECK-NEXT: call {{.*}} @_ZN1XD1Ev([[X]]* [[A]])
// CHECK-NEXT: ret void
}
+
+// CHECK-EH: attributes [[NR_NUW]] = { noreturn nounwind }
diff --git a/test/CodeGenCXX/pod-member-memcpys.cpp b/test/CodeGenCXX/pod-member-memcpys.cpp
new file mode 100644
index 0000000..534d5d1
--- /dev/null
+++ b/test/CodeGenCXX/pod-member-memcpys.cpp
@@ -0,0 +1,256 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -std=c++03 -fexceptions -fcxx-exceptions -O1 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -emit-llvm -std=c++03 -O0 -o - %s | FileCheck --check-prefix=CHECK-2 %s
+
+struct POD {
+ int w, x, y, z;
+};
+
+struct PODLike {
+ int w, x, y, z;
+ PODLike();
+ ~PODLike();
+};
+
+struct NonPOD {
+ NonPOD();
+ NonPOD(const NonPOD&);
+ NonPOD& operator=(const NonPOD&);
+};
+
+struct Basic {
+ int a, b, c, d;
+ NonPOD np;
+ int w, x, y, z;
+};
+
+struct PODMember {
+ int a, b, c, d;
+ POD p;
+ NonPOD np;
+ int w, x, y, z;
+};
+
+struct PODLikeMember {
+ int a, b, c, d;
+ PODLike pl;
+ NonPOD np;
+ int w, x, y, z;
+};
+
+struct ArrayMember {
+ int a, b, c, d;
+ int e[12];
+ NonPOD np;
+ int f[12];
+ int w, x, y, z;
+};
+
+struct VolatileMember {
+ int a, b, c, d;
+ volatile int v;
+ NonPOD np;
+ int w, x, y, z;
+};
+
+struct BitfieldMember {
+ int a, b, c, d;
+ NonPOD np;
+ int w : 6;
+ int x : 6;
+ int y : 6;
+ int z : 6;
+};
+
+struct BitfieldMember2 {
+ unsigned a : 1;
+ unsigned b, c, d;
+ NonPOD np;
+};
+
+struct InnerClassMember {
+ struct {
+ int a, b, c, d;
+ } a;
+ int b, c, d, e;
+ NonPOD np;
+ int w, x, y, z;
+};
+
+struct ReferenceMember {
+ ReferenceMember(int &a, int &b, int &c, int &d)
+ : a(a), b(b), c(c), d(d) {}
+ int &a;
+ int &b;
+ NonPOD np;
+ int &c;
+ int &d;
+};
+
+struct __attribute__((packed)) PackedMembers {
+ char c;
+ NonPOD np;
+ int w, x, y, z;
+};
+
+// COPY-ASSIGNMENT OPERATORS:
+
+// Assignment operators are output in the order they're encountered.
+
+#define CALL_AO(T) void callAO##T(T& a, const T& b) { a = b; }
+
+CALL_AO(Basic)
+CALL_AO(PODMember)
+CALL_AO(PODLikeMember)
+CALL_AO(ArrayMember)
+CALL_AO(VolatileMember)
+CALL_AO(BitfieldMember)
+CALL_AO(InnerClassMember)
+CALL_AO(PackedMembers)
+
+// Basic copy-assignment:
+// CHECK: define linkonce_odr %struct.Basic* @_ZN5BasicaSERKS_(%struct.Basic* %this, %struct.Basic*)
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK: tail call %struct.NonPOD* @_ZN6NonPODaSERKS_
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK: ret %struct.Basic* %this
+
+// PODMember copy-assignment:
+// CHECK: define linkonce_odr %struct.PODMember* @_ZN9PODMemberaSERKS_(%struct.PODMember* %this, %struct.PODMember*)
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}})
+// CHECK: tail call %struct.NonPOD* @_ZN6NonPODaSERKS_
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK: ret %struct.PODMember* %this
+
+// PODLikeMember copy-assignment:
+// CHECK: define linkonce_odr %struct.PODLikeMember* @_ZN13PODLikeMemberaSERKS_(%struct.PODLikeMember* %this, %struct.PODLikeMember*)
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}})
+// CHECK: tail call %struct.NonPOD* @_ZN6NonPODaSERKS_
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK: ret %struct.PODLikeMember* %this
+
+// ArrayMember copy-assignment:
+// CHECK: define linkonce_odr %struct.ArrayMember* @_ZN11ArrayMemberaSERKS_(%struct.ArrayMember* %this, %struct.ArrayMember*)
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 64, i32 4{{.*}})
+// CHECK: tail call %struct.NonPOD* @_ZN6NonPODaSERKS_
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 64, i32 4{{.*}})
+// CHECK: ret %struct.ArrayMember* %this
+
+// VolatileMember copy-assignment:
+// CHECK: define linkonce_odr %struct.VolatileMember* @_ZN14VolatileMemberaSERKS_(%struct.VolatileMember* %this, %struct.VolatileMember*)
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK: load volatile i32* {{.*}}, align 4
+// CHECK: store volatile i32 {{.*}}, align 4
+// CHECK: tail call %struct.NonPOD* @_ZN6NonPODaSERKS_
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK: ret %struct.VolatileMember* %this
+
+// BitfieldMember copy-assignment:
+// CHECK: define linkonce_odr %struct.BitfieldMember* @_ZN14BitfieldMemberaSERKS_(%struct.BitfieldMember* %this, %struct.BitfieldMember*)
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK: tail call %struct.NonPOD* @_ZN6NonPODaSERKS_
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 3, i32 1{{.*}})
+// CHECK: ret %struct.BitfieldMember* %this
+
+// InnerClass copy-assignment:
+// CHECK: define linkonce_odr %struct.InnerClassMember* @_ZN16InnerClassMemberaSERKS_(%struct.InnerClassMember* %this, %struct.InnerClassMember*)
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}})
+// CHECK: tail call %struct.NonPOD* @_ZN6NonPODaSERKS_
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK: ret %struct.InnerClassMember* %this
+
+// PackedMembers copy-assignment:
+// CHECK: define linkonce_odr %struct.PackedMembers* @_ZN13PackedMembersaSERKS_(%struct.PackedMembers* %this, %struct.PackedMembers*)
+// CHECK: tail call %struct.NonPOD* @_ZN6NonPODaSERKS_
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 1{{.*}})
+// CHECK: ret %struct.PackedMembers* %this
+
+// COPY-CONSTRUCTORS:
+
+// Clang outputs copy-constructors in the reverse of the order that
+// copy-constructor calls are encountered. Add functions that call the copy
+// constructors of the classes above in reverse order here.
+
+#define CALL_CC(T) T callCC##T(const T& b) { return b; }
+
+CALL_CC(PackedMembers)
+CALL_CC(BitfieldMember2)
+CALL_CC(ReferenceMember)
+CALL_CC(InnerClassMember)
+CALL_CC(BitfieldMember)
+CALL_CC(VolatileMember)
+CALL_CC(ArrayMember)
+CALL_CC(PODLikeMember)
+CALL_CC(PODMember)
+CALL_CC(Basic)
+
+// Basic copy-constructor:
+// CHECK: define linkonce_odr void @_ZN5BasicC2ERKS_(%struct.Basic* %this, %struct.Basic*)
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK: tail call void @_ZN6NonPODC1ERKS_
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK: ret void
+
+// PODMember copy-constructor:
+// CHECK: define linkonce_odr void @_ZN9PODMemberC2ERKS_(%struct.PODMember* %this, %struct.PODMember*)
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}})
+// CHECK: tail call void @_ZN6NonPODC1ERKS_
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK: ret void
+
+// PODLikeMember copy-constructor:
+// CHECK: define linkonce_odr void @_ZN13PODLikeMemberC2ERKS_(%struct.PODLikeMember* %this, %struct.PODLikeMember*)
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}})
+// CHECK: invoke void @_ZN6NonPODC1ERKS_
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK: ret void
+// CHECK: landingpad
+// CHECK: invoke void @_ZN7PODLikeD1Ev
+
+// ArrayMember copy-constructor:
+// CHECK: define linkonce_odr void @_ZN11ArrayMemberC2ERKS_(%struct.ArrayMember* %this, %struct.ArrayMember*)
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 64, i32 4{{.*}})
+// CHECK: tail call void @_ZN6NonPODC1ERKS_
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 64, i32 4{{.*}})
+// CHECK: ret void
+
+// VolatileMember copy-constructor:
+// CHECK: define linkonce_odr void @_ZN14VolatileMemberC2ERKS_(%struct.VolatileMember* %this, %struct.VolatileMember*)
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK: load volatile i32* {{.*}}, align 4
+// CHECK: store volatile i32 {{.*}}, align 4
+// CHECK: tail call void @_ZN6NonPODC1ERKS_
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK: ret void
+
+// BitfieldMember copy-constructor:
+// CHECK: define linkonce_odr void @_ZN14BitfieldMemberC2ERKS_(%struct.BitfieldMember* %this, %struct.BitfieldMember*)
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK: tail call void @_ZN6NonPODC1ERKS_
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 3, i32 1{{.*}})
+// CHECK: ret void
+
+// InnerClass copy-constructor:
+// CHECK: define linkonce_odr void @_ZN16InnerClassMemberC2ERKS_(%struct.InnerClassMember* %this, %struct.InnerClassMember*)
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 32, i32 4{{.*}})
+// CHECK: tail call void @_ZN6NonPODC1ERKS_
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4{{.*}})
+// CHECK: ret void
+
+// ReferenceMember copy-constructor:
+// CHECK: define linkonce_odr void @_ZN15ReferenceMemberC2ERKS_(%struct.ReferenceMember* %this, %struct.ReferenceMember*)
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 8{{.*}})
+// CHECK: tail call void @_ZN6NonPODC1ERKS_
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 8{{.*}})
+// CHECK: ret void
+
+// BitfieldMember2 copy-constructor:
+// CHECK-2: define linkonce_odr void @_ZN15BitfieldMember2C2ERKS_(%struct.BitfieldMember2* %this, %struct.BitfieldMember2*)
+// CHECK-2: call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 4, i1 false)
+// CHECK-2: call void @_ZN6NonPODC1ERKS_
+// CHECK-2: ret void
+
+// PackedMembers copy-assignment:
+// CHECK: define linkonce_odr void @_ZN13PackedMembersC2ERKS_(%struct.PackedMembers* %this, %struct.PackedMembers*)
+// CHECK: tail call void @_ZN6NonPODC1ERKS_
+// CHECK: tail call void @llvm.memcpy.p0i8.p0i8.i64({{.*}}i64 16, i32 1{{.*}})
+// CHECK: ret void
diff --git a/test/CodeGenCXX/pointers-to-data-members.cpp b/test/CodeGenCXX/pointers-to-data-members.cpp
index fe69cd5..7335c97 100644
--- a/test/CodeGenCXX/pointers-to-data-members.cpp
+++ b/test/CodeGenCXX/pointers-to-data-members.cpp
@@ -151,13 +151,13 @@ struct A {
A() : a() {}
};
-// CHECK-O3: define zeroext i1 @_ZN6PR71395checkEv() nounwind readnone
+// CHECK-O3: define zeroext i1 @_ZN6PR71395checkEv() [[NUW:#[0-9]+]]
bool check() {
// CHECK-O3: ret i1 true
return A().a.data == 0;
}
-// CHECK-O3: define zeroext i1 @_ZN6PR71396check2Ev() nounwind readnone
+// CHECK-O3: define zeroext i1 @_ZN6PR71396check2Ev() [[NUW]]
bool check2() {
// CHECK-O3: ret i1 true
return ptr_to_member_type() == 0;
@@ -254,3 +254,5 @@ namespace PR13097 {
// CHECK-NOT: memcpy
// CHECK: call void @_ZN7PR130971XC1ERKS0_
}
+
+// CHECK-O3: attributes [[NUW]] = { nounwind readnone{{.*}} }
diff --git a/test/CodeGenCXX/pragma-weak.cpp b/test/CodeGenCXX/pragma-weak.cpp
new file mode 100644
index 0000000..ed537ff
--- /dev/null
+++ b/test/CodeGenCXX/pragma-weak.cpp
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s
+
+#pragma weak zex
+int zex;
+// GCC produces a weak symbol for this because it matches mangled names.
+// Different c++ ABIs may or may not mangle this, so we produce a strong
+// symbol.
+// CHECK: @zex = global i32
+
+#pragma weak foo
+struct S { void foo(); };
+void S::foo() {}
+// CHECK: define void @_ZN1S3fooEv(
+
+#pragma weak zed
+namespace bar { void zed() {} }
+// CHECK: define void @_ZN3bar3zedEv(
+
+#pragma weak bah
+void bah() {}
+// CHECK: define void @_Z3bahv(
+
+#pragma weak baz
+extern "C" void baz() {}
+// CHECK: define weak void @baz(
+
+#pragma weak _Z3baxv
+void bax() {}
+// GCC produces a weak symbol for this one, but it doesn't look like a good
+// idea to expose the mangling to the pragma unless we really have to.
+// CHECK: define void @_Z3baxv(
diff --git a/test/CodeGenCXX/predefined-expr.cpp b/test/CodeGenCXX/predefined-expr.cpp
index 1795ec8..24ead8f 100644
--- a/test/CodeGenCXX/predefined-expr.cpp
+++ b/test/CodeGenCXX/predefined-expr.cpp
@@ -142,7 +142,7 @@ public:
printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
}
- inline void inlineFunction() {
+ inline void (inlineFunction)() {
printf("__func__ %s\n", __func__);
printf("__FUNCTION__ %s\n", __FUNCTION__);
printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
diff --git a/test/CodeGenCXX/reference-cast.cpp b/test/CodeGenCXX/reference-cast.cpp
index 1d08b2b..f157ae9 100644
--- a/test/CodeGenCXX/reference-cast.cpp
+++ b/test/CodeGenCXX/reference-cast.cpp
@@ -3,7 +3,7 @@
// PR6024
extern int i;
-// CHECK: define i32* @_Z16lvalue_noop_castv() nounwind
+// CHECK: define i32* @_Z16lvalue_noop_castv() [[NUW:#[0-9]+]]
const int &lvalue_noop_cast() {
if (i == 0)
// CHECK: store i32 17, i32*
@@ -192,3 +192,5 @@ namespace PR10650 {
// CHECK: define i64 @_ZN7PR106504testEPNS_6HelperE
// CHECK: store i64
}
+
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGenCXX/references.cpp b/test/CodeGenCXX/references.cpp
index d315f71..df5a336 100644
--- a/test/CodeGenCXX/references.cpp
+++ b/test/CodeGenCXX/references.cpp
@@ -283,12 +283,11 @@ namespace PR9565 {
void f() {
// CHECK: call void @llvm.memcpy
a x = { 0, 0 };
- // CHECK: [[WITH_SEVENTEEN:%[a-zA-Z0-9]+]] = or i32 [[WITHOUT_SEVENTEEN:%[a-zA-Z0-9]+]], 17
- // CHECK: store i32 [[WITH_SEVENTEEN]], i32* [[XA:%[a-zA-Z0-9]+]]
+ // CHECK: [[WITH_SEVENTEEN:%[.a-zA-Z0-9]+]] = or i32 [[WITHOUT_SEVENTEEN:%[.a-zA-Z0-9]+]], 17
+ // CHECK: store i32 [[WITH_SEVENTEEN]], i32* [[XA:%[.a-zA-Z0-9]+]]
x.a = 17;
// CHECK-NEXT: bitcast
- // CHECK-NEXT: load
- // CHECK-NEXT: and
+ // CHECK-NEXT: load
// CHECK-NEXT: shl
// CHECK-NEXT: ashr
// CHECK-NEXT: store i32
@@ -297,7 +296,7 @@ namespace PR9565 {
// CHECK-NEXT: bitcast
// CHECK-NEXT: load
// CHECK-NEXT: and
- // CHECK-NEXT: or
+ // CHECK-NEXT: or i32 {{.*}}, 19456
// CHECK-NEXT: store i32
x.b = 19;
// CHECK-NEXT: ret void
diff --git a/test/CodeGenCXX/runtimecc.cpp b/test/CodeGenCXX/runtimecc.cpp
new file mode 100644
index 0000000..66d3f41
--- /dev/null
+++ b/test/CodeGenCXX/runtimecc.cpp
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 %s -triple=armv7-apple-darwin10 -emit-llvm -o - -fexceptions -fcxx-exceptions | FileCheck %s
+
+// Check that we annotate all compiler-synthesized runtime calls and
+// functions with the actual ABI-determined CC. This usually doesn't
+// matter as long as we're internally consistent (and the LLVM-default
+// CC is consistent with the real one), but it's possible for user
+// translation units to define these runtime functions (or, equivalently,
+// for us to get LTO'ed with such a translation unit), and then the
+// mismatch will kill us.
+//
+// rdar://12818655
+
+// CHECK: [[A:%.*]] = type { double }
+
+namespace test0 {
+ struct A {
+ double d;
+ A();
+ ~A();
+ };
+
+ A global;
+// CHECK: define internal arm_aapcscc void @__cxx_global_var_init()
+// CHECK: call arm_aapcscc [[A]]* @_ZN5test01AC1Ev([[A]]* @_ZN5test06globalE)
+// CHECK-NEXT: call arm_aapcscc i32 @__cxa_atexit(void (i8*)* bitcast ([[A]]* ([[A]]*)* @_ZN5test01AD1Ev to void (i8*)*), i8* bitcast ([[A]]* @_ZN5test06globalE to i8*), i8* @__dso_handle) [[NOUNWIND:#[0-9]+]]
+// CHECK-NEXT: ret void
+}
+
+// CHECK: declare arm_aapcscc i32 @__cxa_atexit(void (i8*)*, i8*, i8*) [[NOUNWIND]]
+
+namespace test1 {
+ void test() {
+ throw 0;
+ }
+
+// CHECK: define arm_aapcscc void @_ZN5test14testEv()
+// CHECK: [[T0:%.*]] = call arm_aapcscc i8* @__cxa_allocate_exception(i32 4) [[NOUNWIND]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to i32*
+// CHECK-NEXT: store i32 0, i32* [[T1]]
+// CHECK-NEXT: call arm_aapcscc void @__cxa_throw(i8* [[T0]], i8* bitcast (i8** @_ZTIi to i8*), i8* null) [[NORETURN:#[0-9]+]]
+// CHECK-NEXT: unreachable
+}
+
+// CHECK: declare arm_aapcscc i8* @__cxa_allocate_exception(i32)
+
+// CHECK: declare arm_aapcscc void @__cxa_throw(i8*, i8*, i8*)
+
+// CHECK: define internal arm_aapcscc void @_GLOBAL__I_a()
+// CHECK: call arm_aapcscc void @__cxx_global_var_init()
+
+
+// CHECK: attributes [[NOUNWIND]] = { nounwind }
+// CHECK: attributes [[NORETURN]] = { noreturn }
diff --git a/test/CodeGenCXX/sizeof-unwind-exception.cpp b/test/CodeGenCXX/sizeof-unwind-exception.cpp
index 5db4df7..95bb9d0 100644
--- a/test/CodeGenCXX/sizeof-unwind-exception.cpp
+++ b/test/CodeGenCXX/sizeof-unwind-exception.cpp
@@ -15,14 +15,19 @@ void test() {
// PR10789: different platforms have different sizes for struct UnwindException.
-// X86-64: [[T0:%.*]] = tail call i8* @__cxa_begin_catch(i8* [[EXN:%.*]]) nounwind
+// X86-64: [[T0:%.*]] = tail call i8* @__cxa_begin_catch(i8* [[EXN:%.*]]) [[NUW:#[0-9]+]]
// X86-64-NEXT: [[T1:%.*]] = getelementptr i8* [[EXN]], i64 32
-// X86-32: [[T0:%.*]] = tail call i8* @__cxa_begin_catch(i8* [[EXN:%.*]]) nounwind
+// X86-32: [[T0:%.*]] = tail call i8* @__cxa_begin_catch(i8* [[EXN:%.*]]) [[NUW:#[0-9]+]]
// X86-32-NEXT: [[T1:%.*]] = getelementptr i8* [[EXN]], i64 32
-// ARM-DARWIN: [[T0:%.*]] = tail call i8* @__cxa_begin_catch(i8* [[EXN:%.*]]) nounwind
+// ARM-DARWIN: [[T0:%.*]] = tail call i8* @__cxa_begin_catch(i8* [[EXN:%.*]]) [[NUW:#[0-9]+]]
// ARM-DARWIN-NEXT: [[T1:%.*]] = getelementptr i8* [[EXN]], i64 32
-// ARM-EABI: [[T0:%.*]] = tail call i8* @__cxa_begin_catch(i8* [[EXN:%.*]]) nounwind
+// ARM-EABI: [[T0:%.*]] = tail call i8* @__cxa_begin_catch(i8* [[EXN:%.*]]) [[NUW:#[0-9]+]]
// ARM-EABI-NEXT: [[T1:%.*]] = getelementptr i8* [[EXN]], i32 88
-// MIPS: [[T0:%.*]] = tail call i8* @__cxa_begin_catch(i8* [[EXN:%.*]]) nounwind
+// MIPS: [[T0:%.*]] = tail call i8* @__cxa_begin_catch(i8* [[EXN:%.*]]) [[NUW:#[0-9]+]]
// MIPS-NEXT: [[T1:%.*]] = getelementptr i8* [[EXN]], i32 24
+// X86-64: attributes [[NUW]] = { nounwind }
+// X86-32: attributes [[NUW]] = { nounwind }
+// ARM-DARWIN: attributes [[NUW]] = { nounwind }
+// ARM-EABI: attributes [[NUW]] = { nounwind }
+// MIPS: attributes [[NUW]] = { nounwind }
diff --git a/test/CodeGenCXX/temp-order.cpp b/test/CodeGenCXX/temp-order.cpp
index 341cd0c..67cd4b7 100644
--- a/test/CodeGenCXX/temp-order.cpp
+++ b/test/CodeGenCXX/temp-order.cpp
@@ -1,5 +1,5 @@
// Output file should have no calls to error() with folding.
-// RUN: %clang_cc1 -triple i386-unknown-unknown -O3 -emit-llvm -o %t %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -mllvm -inline-threshold=1024 -O3 -emit-llvm -o %t %s
// RUN: FileCheck %s < %t
static unsigned pow(unsigned Base, unsigned Power) {
diff --git a/test/CodeGenCXX/template-anonymous-types.cpp b/test/CodeGenCXX/template-anonymous-types.cpp
index 72fe090..3df487a 100644
--- a/test/CodeGenCXX/template-anonymous-types.cpp
+++ b/test/CodeGenCXX/template-anonymous-types.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -emit-llvm -w -o - | FileCheck %s
struct S {
enum { FOO = 42 };
@@ -17,21 +17,21 @@ template <typename T> int f(T t) {
}
void test() {
- // Look for two instantiations, entirely internal to this TU, one for FOO's
+ // Look for two instantiations, one for FOO's
// type and one for BAR's.
- // CHECK: define internal i32 @"_Z1fIN1S3$_0EEiT_"(i32 %t)
+ // CHECK: define linkonce_odr i32 @_Z1fIN1SUt_EEiT_(i32 %t)
(void)f(S::FOO);
- // CHECK: define internal i32 @"_Z1fIN1S3$_1EEiT_"(i32 %t)
+ // CHECK: define linkonce_odr i32 @_Z1fIN1SUt0_EEiT_(i32 %t)
(void)f(S::BAR);
// Now check for the class template instantiations. Annoyingly, they are in
// reverse order.
//
// BAR's instantiation of X:
- // CHECK: define internal i32 @"_ZN1XIN1S3$_1EE1fEv"(%struct.X* %this)
- // CHECK: define internal void @"_ZN1XIN1S3$_1EEC2ES1_"(%struct.X* %this, i32 %t) unnamed_addr
+ // CHECK: define linkonce_odr i32 @_ZN1XIN1SUt0_EE1fEv(%struct.X* %this)
+ // CHECK: define linkonce_odr void @_ZN1XIN1SUt0_EEC2ES1_(%struct.X* %this, i32 %t) unnamed_addr
//
// FOO's instantiation of X:
- // CHECK: define internal i32 @"_ZN1XIN1S3$_0EE1fEv"(%struct.X.0* %this)
- // CHECK: define internal void @"_ZN1XIN1S3$_0EEC2ES1_"(%struct.X.0* %this, i32 %t) unnamed_addr
+ // CHECK: define linkonce_odr i32 @_ZN1XIN1SUt_EE1fEv(%struct.X.0* %this)
+ // CHECK: define linkonce_odr void @_ZN1XIN1SUt_EEC2ES1_(%struct.X.0* %this, i32 %t) unnamed_addr
}
diff --git a/test/CodeGenCXX/template-linkage.cpp b/test/CodeGenCXX/template-linkage.cpp
index 20508c1..3acd12e 100644
--- a/test/CodeGenCXX/template-linkage.cpp
+++ b/test/CodeGenCXX/template-linkage.cpp
@@ -1,4 +1,7 @@
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+
+// CHECK: Outer5Inner{{.*}}localE6memberE = external global
+
template<typename T> struct A {
virtual void f(T) { }
inline void g() { }
@@ -42,3 +45,20 @@ void test_X1() {
X1<char> i1c;
}
+namespace PR14825 {
+struct Outer {
+ template <typename T> struct Inner {
+ static int member;
+ };
+ template <typename T> void Get() {
+ int m = Inner<T>::member;
+ }
+};
+
+void test() {
+ struct local {};
+ Outer o;
+ typedef void (Outer::*mptr)();
+ mptr method = &Outer::Get<local>;
+}
+}
diff --git a/test/CodeGenCXX/temporaries.cpp b/test/CodeGenCXX/temporaries.cpp
index e90c947..a369c2e 100644
--- a/test/CodeGenCXX/temporaries.cpp
+++ b/test/CodeGenCXX/temporaries.cpp
@@ -537,3 +537,24 @@ namespace PR11365 {
(void) (A [3]) {};
}
}
+
+namespace AssignmentOp {
+ struct A { ~A(); };
+ struct B { A operator=(const B&); };
+ struct C : B { B b1, b2; };
+ // CHECK: define void @_ZN12AssignmentOp1fE
+ void f(C &c1, const C &c2) {
+ // CHECK: call {{.*}} @_ZN12AssignmentOp1CaSERKS0_(
+ c1 = c2;
+ }
+
+ // Ensure that each 'A' temporary is destroyed before the next subobject is
+ // copied.
+ // CHECK: define {{.*}} @_ZN12AssignmentOp1CaSERKS0_(
+ // CHECK: call {{.*}} @_ZN12AssignmentOp1BaSERKS
+ // CHECK: call {{.*}} @_ZN12AssignmentOp1AD1Ev(
+ // CHECK: call {{.*}} @_ZN12AssignmentOp1BaSERKS
+ // CHECK: call {{.*}} @_ZN12AssignmentOp1AD1Ev(
+ // CHECK: call {{.*}} @_ZN12AssignmentOp1BaSERKS
+ // CHECK: call {{.*}} @_ZN12AssignmentOp1AD1Ev(
+}
diff --git a/test/CodeGenCXX/threadsafe-statics.cpp b/test/CodeGenCXX/threadsafe-statics.cpp
index 8afc274..9aecc2d 100644
--- a/test/CodeGenCXX/threadsafe-statics.cpp
+++ b/test/CodeGenCXX/threadsafe-statics.cpp
@@ -6,7 +6,7 @@ int f();
// WITH-TSS: @_ZZ1gvE1a = internal global i32 0, align 4
// WITH-TSS: @_ZGVZ1gvE1a = internal global i64 0
-// WITH-TSS: define void @_Z1gv() nounwind
+// WITH-TSS: define void @_Z1gv() [[NUW:#[0-9]+]]
// WITH-TSS: call i32 @__cxa_guard_acquire
// WITH-TSS: call void @__cxa_guard_release
// WITH-TSS: ret void
@@ -17,7 +17,11 @@ void g() {
// NO-TSS: @_ZZ1gvE1a = internal global i32 0, align 4
// NO-TSS: @_ZGVZ1gvE1a = internal global i8 0
-// NO-TSS: define void @_Z1gv() nounwind
+// NO-TSS: define void @_Z1gv() [[NUW:#[0-9]+]]
// NO-TSS-NOT: call i32 @__cxa_guard_acquire
// NO-TSS-NOT: call void @__cxa_guard_release
// NO-TSS: ret void
+
+// WITH-TSS: attributes [[NUW]] = { nounwind{{.*}} }
+
+// NO-TSS: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGenCXX/thunks.cpp b/test/CodeGenCXX/thunks.cpp
index 0659259..6e58830 100644
--- a/test/CodeGenCXX/thunks.cpp
+++ b/test/CodeGenCXX/thunks.cpp
@@ -339,7 +339,7 @@ namespace Test14 {
};
void C::f() {
}
- // CHECK: define void @_ZThn8_N6Test141C1fEv({{.*}}) {{.*}} uwtable
+ // CHECK: define void @_ZThn8_N6Test141C1fEv({{.*}}) unnamed_addr [[NUW:#[0-9]+]]
}
/**** The following has to go at the end of the file ****/
@@ -347,3 +347,5 @@ namespace Test14 {
// This is from Test5:
// CHECK: define linkonce_odr void @_ZTv0_n24_N5Test51B1fEv
// CHECK: define internal void @_ZThn8_N6Test4B12_GLOBAL__N_11C1fEv(
+
+// CHECK: attributes [[NUW]] = { nounwind uwtable{{.*}} }
diff --git a/test/CodeGenCXX/trivial-constructor-init.cpp b/test/CodeGenCXX/trivial-constructor-init.cpp
index 343dc65..65ed45e 100644
--- a/test/CodeGenCXX/trivial-constructor-init.cpp
+++ b/test/CodeGenCXX/trivial-constructor-init.cpp
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -S %s -o %t-64.s
-// RUN: %clang_cc1 -S %s -o %t-32.s
+// RUN: %clang_cc1 -emit-llvm %s -o - -std=c++11 | FileCheck %s
extern "C" int printf(...);
@@ -16,5 +15,20 @@ struct A {
A a;
+struct B {
+ B() = default;
+ B(const B&);
+};
+
+// CHECK-NOT: _ZL1b
+static B b;
+
+struct C {
+ ~C();
+};
+
+// CHECK: _ZL1c
+static C c[4];
+
int main() {
}
diff --git a/test/CodeGenCXX/type_visibility.cpp b/test/CodeGenCXX/type_visibility.cpp
new file mode 100644
index 0000000..5c45611
--- /dev/null
+++ b/test/CodeGenCXX/type_visibility.cpp
@@ -0,0 +1,170 @@
+// RUN: %clang_cc1 %s -std=c++11 -triple=x86_64-apple-darwin10 -emit-llvm -o %t.ll
+// RUN: FileCheck %s -check-prefix=FUNS < %t.ll
+// RUN: FileCheck %s -check-prefix=VARS < %t.ll
+// RUN: %clang_cc1 %s -std=c++11 -triple=x86_64-apple-darwin10 -fvisibility hidden -emit-llvm -o %t.ll
+// RUN: FileCheck %s -check-prefix=FUNS-HIDDEN < %t.ll
+// RUN: FileCheck %s -check-prefix=VARS-HIDDEN < %t.ll
+
+#define HIDDEN __attribute__((visibility("hidden")))
+#define PROTECTED __attribute__((visibility("protected")))
+#define DEFAULT __attribute__((visibility("default")))
+#define TYPE_HIDDEN __attribute__((type_visibility("hidden")))
+#define TYPE_PROTECTED __attribute__((type_visibility("protected")))
+#define TYPE_DEFAULT __attribute__((type_visibility("default")))
+
+// type_visibility is rdar://11880378
+
+#if !__has_attribute(type_visibility)
+#error No type_visibility attribute!
+#endif
+
+// The template tests come first because IR-gen reorders RTTI wierdly.
+namespace temp0 {
+ struct A;
+ template <class T> struct TYPE_DEFAULT B {
+ virtual void foo() {}
+ };
+
+ template struct B<A>;
+ // FUNS: define weak_odr void @_ZN5temp01BINS_1AEE3fooEv(
+ // VARS: @_ZTVN5temp01BINS_1AEEE = weak_odr unnamed_addr constant
+ // VARS: @_ZTSN5temp01BINS_1AEEE = weak_odr constant
+ // VARS: @_ZTIN5temp01BINS_1AEEE = weak_odr unnamed_addr constant
+ // FUNS-HIDDEN: define weak_odr hidden void @_ZN5temp01BINS_1AEE3fooEv(
+ // VARS-HIDDEN: @_ZTVN5temp01BINS_1AEEE = weak_odr hidden unnamed_addr constant
+ // VARS-HIDDEN: @_ZTSN5temp01BINS_1AEEE = weak_odr hidden constant
+ // VARS-HIDDEN: @_ZTIN5temp01BINS_1AEEE = weak_odr hidden unnamed_addr constant
+}
+
+namespace temp1 {
+ struct TYPE_DEFAULT A;
+ template <class T> struct TYPE_DEFAULT B {
+ virtual void foo() {}
+ };
+
+ template struct B<A>;
+ // FUNS: define weak_odr void @_ZN5temp11BINS_1AEE3fooEv(
+ // VARS: @_ZTVN5temp11BINS_1AEEE = weak_odr unnamed_addr constant
+ // VARS: @_ZTSN5temp11BINS_1AEEE = weak_odr constant
+ // VARS: @_ZTIN5temp11BINS_1AEEE = weak_odr unnamed_addr constant
+ // FUNS-HIDDEN: define weak_odr hidden void @_ZN5temp11BINS_1AEE3fooEv(
+ // VARS-HIDDEN: @_ZTVN5temp11BINS_1AEEE = weak_odr unnamed_addr constant
+ // VARS-HIDDEN: @_ZTSN5temp11BINS_1AEEE = weak_odr constant
+ // VARS-HIDDEN: @_ZTIN5temp11BINS_1AEEE = weak_odr unnamed_addr constant
+}
+
+namespace temp2 {
+ struct TYPE_DEFAULT A;
+ template <class T> struct B {
+ virtual void foo() {}
+ };
+
+ template struct B<A>;
+ // FUNS: define weak_odr void @_ZN5temp21BINS_1AEE3fooEv(
+ // VARS: @_ZTVN5temp21BINS_1AEEE = weak_odr unnamed_addr constant
+ // VARS: @_ZTSN5temp21BINS_1AEEE = weak_odr constant
+ // VARS: @_ZTIN5temp21BINS_1AEEE = weak_odr unnamed_addr constant
+ // FUNS-HIDDEN: define weak_odr hidden void @_ZN5temp21BINS_1AEE3fooEv(
+ // VARS-HIDDEN: @_ZTVN5temp21BINS_1AEEE = weak_odr hidden unnamed_addr constant
+ // VARS-HIDDEN: @_ZTSN5temp21BINS_1AEEE = weak_odr hidden constant
+ // VARS-HIDDEN: @_ZTIN5temp21BINS_1AEEE = weak_odr hidden unnamed_addr constant
+}
+
+namespace temp3 {
+ struct TYPE_HIDDEN A;
+ template <class T> struct TYPE_DEFAULT B {
+ virtual void foo() {}
+ };
+
+ template struct B<A>;
+ // FUNS: define weak_odr hidden void @_ZN5temp31BINS_1AEE3fooEv(
+ // VARS: @_ZTVN5temp31BINS_1AEEE = weak_odr hidden unnamed_addr constant
+ // VARS: @_ZTSN5temp31BINS_1AEEE = weak_odr hidden constant
+ // VARS: @_ZTIN5temp31BINS_1AEEE = weak_odr hidden unnamed_addr constant
+ // FUNS-HIDDEN: define weak_odr hidden void @_ZN5temp31BINS_1AEE3fooEv(
+ // VARS-HIDDEN: @_ZTVN5temp31BINS_1AEEE = weak_odr hidden unnamed_addr constant
+ // VARS-HIDDEN: @_ZTSN5temp31BINS_1AEEE = weak_odr hidden constant
+ // VARS-HIDDEN: @_ZTIN5temp31BINS_1AEEE = weak_odr hidden unnamed_addr constant
+}
+
+namespace temp4 {
+ struct TYPE_DEFAULT A;
+ template <class T> struct TYPE_HIDDEN B {
+ virtual void foo() {}
+ };
+
+ template struct B<A>;
+ // FUNS: define weak_odr void @_ZN5temp41BINS_1AEE3fooEv(
+ // VARS: @_ZTVN5temp41BINS_1AEEE = weak_odr hidden unnamed_addr constant
+ // VARS: @_ZTSN5temp41BINS_1AEEE = weak_odr hidden constant
+ // VARS: @_ZTIN5temp41BINS_1AEEE = weak_odr hidden unnamed_addr constant
+ // FUNS-HIDDEN: define weak_odr hidden void @_ZN5temp41BINS_1AEE3fooEv(
+ // VARS-HIDDEN: @_ZTVN5temp41BINS_1AEEE = weak_odr hidden unnamed_addr constant
+ // VARS-HIDDEN: @_ZTSN5temp41BINS_1AEEE = weak_odr hidden constant
+ // VARS-HIDDEN: @_ZTIN5temp41BINS_1AEEE = weak_odr hidden unnamed_addr constant
+}
+
+namespace type0 {
+ struct TYPE_DEFAULT A {
+ virtual void foo();
+ };
+
+ void A::foo() {}
+ // FUNS: define void @_ZN5type01A3fooEv(
+ // VARS: @_ZTVN5type01AE = unnamed_addr constant
+ // VARS: @_ZTSN5type01AE = constant
+ // VARS: @_ZTIN5type01AE = unnamed_addr constant
+ // FUNS-HIDDEN: define hidden void @_ZN5type01A3fooEv(
+ // VARS-HIDDEN: @_ZTVN5type01AE = unnamed_addr constant
+ // VARS-HIDDEN: @_ZTSN5type01AE = constant
+ // VARS-HIDDEN: @_ZTIN5type01AE = unnamed_addr constant
+}
+
+namespace type1 {
+ struct HIDDEN TYPE_DEFAULT A {
+ virtual void foo();
+ };
+
+ void A::foo() {}
+ // FUNS: define hidden void @_ZN5type11A3fooEv(
+ // VARS: @_ZTVN5type11AE = unnamed_addr constant
+ // VARS: @_ZTSN5type11AE = constant
+ // VARS: @_ZTIN5type11AE = unnamed_addr constant
+ // FUNS-HIDDEN: define hidden void @_ZN5type11A3fooEv(
+ // VARS-HIDDEN: @_ZTVN5type11AE = unnamed_addr constant
+ // VARS-HIDDEN: @_ZTSN5type11AE = constant
+ // VARS-HIDDEN: @_ZTIN5type11AE = unnamed_addr constant
+}
+
+namespace type2 {
+ struct TYPE_HIDDEN A {
+ virtual void foo();
+ };
+
+ void A::foo() {}
+ // FUNS: define void @_ZN5type21A3fooEv(
+ // VARS: @_ZTVN5type21AE = hidden unnamed_addr constant
+ // VARS: @_ZTSN5type21AE = hidden constant
+ // VARS: @_ZTIN5type21AE = hidden unnamed_addr constant
+ // FUNS-HIDDEN: define hidden void @_ZN5type21A3fooEv(
+ // VARS-HIDDEN: @_ZTVN5type21AE = hidden unnamed_addr constant
+ // VARS-HIDDEN: @_ZTSN5type21AE = hidden constant
+ // VARS-HIDDEN: @_ZTIN5type21AE = hidden unnamed_addr constant
+}
+
+namespace type3 {
+ struct DEFAULT TYPE_HIDDEN A {
+ virtual void foo();
+ };
+
+ void A::foo() {}
+ // FUNS: define void @_ZN5type31A3fooEv(
+ // VARS: @_ZTVN5type31AE = hidden unnamed_addr constant
+ // VARS: @_ZTSN5type31AE = hidden constant
+ // VARS: @_ZTIN5type31AE = hidden unnamed_addr constant
+ // FUNS-HIDDEN: define void @_ZN5type31A3fooEv(
+ // VARS-HIDDEN: @_ZTVN5type31AE = hidden unnamed_addr constant
+ // VARS-HIDDEN: @_ZTSN5type31AE = hidden constant
+ // VARS-HIDDEN: @_ZTIN5type31AE = hidden unnamed_addr constant
+}
+
diff --git a/test/CodeGenCXX/typeid.cpp b/test/CodeGenCXX/typeid.cpp
index fce3795..a1bc967 100644
--- a/test/CodeGenCXX/typeid.cpp
+++ b/test/CodeGenCXX/typeid.cpp
@@ -31,7 +31,7 @@ const std::type_info &a_ti = typeid(a);
const char *f() {
try {
// CHECK: br i1
- // CHECK: invoke void @__cxa_bad_typeid() noreturn
+ // CHECK: invoke void @__cxa_bad_typeid() [[NR:#[0-9]+]]
return typeid(*static_cast<A *>(0)).name();
} catch (...) {
// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
@@ -42,3 +42,5 @@ const char *f() {
}
}
+
+// CHECK: attributes [[NR]] = { noreturn }
diff --git a/test/CodeGenCXX/value-init.cpp b/test/CodeGenCXX/value-init.cpp
index 6e60f80..60dca99 100644
--- a/test/CodeGenCXX/value-init.cpp
+++ b/test/CodeGenCXX/value-init.cpp
@@ -256,6 +256,12 @@ namespace PR11124 {
// CHECK-NEXT: call void @_ZN7PR111242B2C2Ev
}
+// Ensure we produce an i1 here, and don't assert.
+// CHECK: define void @_Z9r170806_bv(
+// CHECK: call void @_Z9r170806_ab(i1 zeroext false)
+void r170806_a(bool b = bool());
+void r170806_b() { r170806_a(); }
+
// CHECK: define linkonce_odr void @_ZN8zeroinit2X3IiEC2Ev(%"struct.zeroinit::X3"* %this) unnamed_addr
// CHECK: call void @llvm.memset.p0i8.i64
// CHECK-NEXT: call void @_ZN8zeroinit2X2IiEC2Ev
diff --git a/test/CodeGenCXX/virtual-base-cast.cpp b/test/CodeGenCXX/virtual-base-cast.cpp
index 73b7c1c..f469636 100644
--- a/test/CodeGenCXX/virtual-base-cast.cpp
+++ b/test/CodeGenCXX/virtual-base-cast.cpp
@@ -11,23 +11,25 @@ struct D : virtual C, virtual CC { int e; };
D* x;
A* a() { return x; }
-// CHECK: @_Z1av() nounwind
+// CHECK: @_Z1av() [[NUW:#[0-9]+]]
// CHECK: [[VBASEOFFSETPTRA:%[a-zA-Z0-9\.]+]] = getelementptr i8* {{.*}}, i64 -16
// CHECK: [[CASTVBASEOFFSETPTRA:%[a-zA-Z0-9\.]+]] = bitcast i8* [[VBASEOFFSETPTRA]] to i32*
// CHECK: load i32* [[CASTVBASEOFFSETPTRA]]
// CHECK: }
B* b() { return x; }
-// CHECK: @_Z1bv() nounwind
+// CHECK: @_Z1bv() [[NUW]]
// CHECK: [[VBASEOFFSETPTRA:%[a-zA-Z0-9\.]+]] = getelementptr i8* {{.*}}, i64 -20
// CHECK: [[CASTVBASEOFFSETPTRA:%[a-zA-Z0-9\.]+]] = bitcast i8* [[VBASEOFFSETPTRA]] to i32*
// CHECK: load i32* [[CASTVBASEOFFSETPTRA]]
// CHECK: }
BB* c() { return x; }
-// CHECK: @_Z1cv() nounwind
+// CHECK: @_Z1cv() [[NUW]]
// CHECK: [[VBASEOFFSETPTRC:%[a-zA-Z0-9\.]+]] = getelementptr i8* {{.*}}, i64 -24
// CHECK: [[CASTVBASEOFFSETPTRC:%[a-zA-Z0-9\.]+]] = bitcast i8* [[VBASEOFFSETPTRC]] to i32*
// CHECK: [[VBASEOFFSETC:%[a-zA-Z0-9\.]+]] = load i32* [[CASTVBASEOFFSETPTRC]]
// CHECK: add i32 [[VBASEOFFSETC]], 8
// CHECK: }
+
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGenCXX/virtual-function-calls.cpp b/test/CodeGenCXX/virtual-function-calls.cpp
index 46e7b2d..e1b380f 100644
--- a/test/CodeGenCXX/virtual-function-calls.cpp
+++ b/test/CodeGenCXX/virtual-function-calls.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -std=c++11 -emit-llvm -o - | FileCheck %s
// PR5021
namespace PR5021 {
@@ -36,3 +36,16 @@ namespace Test1 {
b->f();
}
}
+
+namespace VirtualNoreturn {
+ struct A {
+ [[noreturn]] virtual void f();
+ };
+
+ // CHECK: @_ZN15VirtualNoreturn1f
+ void f(A *p) {
+ p->f();
+ // CHECK: call void %{{[^#]*$}}
+ // CHECK-NOT: unreachable
+ }
+}
diff --git a/test/CodeGenCXX/visibility-inlines-hidden.cpp b/test/CodeGenCXX/visibility-inlines-hidden.cpp
index 8519c8c..e5bc743 100644
--- a/test/CodeGenCXX/visibility-inlines-hidden.cpp
+++ b/test/CodeGenCXX/visibility-inlines-hidden.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple i386-unknown-unknown -fvisibility-inlines-hidden -emit-llvm -o - %s -O2 -disable-llvm-optzns | FileCheck %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -std=c++11 -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
@@ -135,3 +135,30 @@ namespace test4 {
}
// CHECK: define available_externally void @_ZN5test43fooE
}
+
+namespace test5 {
+ // just don't crash.
+ template <int> inline void Op();
+ class UnaryInstruction {
+ UnaryInstruction() {
+ Op<0>();
+ }
+ };
+ template <int Idx_nocapture> void Op() {
+ }
+}
+
+namespace test6 {
+ // just don't crash.
+ template <typename T>
+ void f(T x) {
+ }
+ struct C {
+ static void g() {
+ f([](){});
+ }
+ };
+ void g() {
+ C::g();
+ }
+}
diff --git a/test/CodeGenCXX/visibility-ms-compat.cpp b/test/CodeGenCXX/visibility-ms-compat.cpp
new file mode 100644
index 0000000..58a8fed
--- /dev/null
+++ b/test/CodeGenCXX/visibility-ms-compat.cpp
@@ -0,0 +1,112 @@
+// RUN: %clang_cc1 %s -std=c++11 -triple=x86_64-apple-darwin10 -fvisibility hidden -ftype-visibility default -emit-llvm -o %t
+// RUN: FileCheck %s < %t
+// RUN: FileCheck -check-prefix=CHECK-GLOBAL %s < %t
+
+// The two visibility options above are how we translate
+// -fvisibility-ms-compat in the driver.
+
+// rdar://13079314
+
+#define HIDDEN __attribute__((visibility("hidden")))
+#define PROTECTED __attribute__((visibility("protected")))
+#define DEFAULT __attribute__((visibility("default")))
+
+namespace std {
+ class type_info;
+};
+
+namespace test0 {
+ struct A {
+ static void foo();
+ static void bar();
+ };
+
+ void A::foo() { bar(); }
+ // CHECK: define hidden void @_ZN5test01A3fooEv()
+ // CHECK: declare void @_ZN5test01A3barEv()
+
+ const std::type_info &ti = typeid(A);
+ // CHECK-GLOBAL: @_ZTSN5test01AE = linkonce_odr constant
+ // CHECK-GLOBAL: @_ZTIN5test01AE = linkonce_odr unnamed_addr constant
+ // CHECK-GLOBAL: @_ZN5test02tiE = hidden constant
+}
+
+namespace test1 {
+ struct HIDDEN A {
+ static void foo();
+ static void bar();
+ };
+
+ void A::foo() { bar(); }
+ // CHECK: define hidden void @_ZN5test11A3fooEv()
+ // CHECK: declare hidden void @_ZN5test11A3barEv()
+
+ const std::type_info &ti = typeid(A);
+ // CHECK-GLOBAL: @_ZTSN5test11AE = linkonce_odr hidden constant
+ // CHECK-GLOBAL: @_ZTIN5test11AE = linkonce_odr hidden unnamed_addr constant
+ // CHECK-GLOBAL: @_ZN5test12tiE = hidden constant
+}
+
+namespace test2 {
+ struct DEFAULT A {
+ static void foo();
+ static void bar();
+ };
+
+ void A::foo() { bar(); }
+ // CHECK: define void @_ZN5test21A3fooEv()
+ // CHECK: declare void @_ZN5test21A3barEv()
+
+ const std::type_info &ti = typeid(A);
+ // CHECK-GLOBAL: @_ZTSN5test21AE = linkonce_odr constant
+ // CHECK-GLOBAL: @_ZTIN5test21AE = linkonce_odr unnamed_addr constant
+ // CHECK-GLOBAL: @_ZN5test22tiE = hidden constant
+}
+
+namespace test3 {
+ struct A { int x; };
+ template <class T> struct B {
+ static void foo() { bar(); }
+ static void bar();
+ };
+
+ template void B<A>::foo();
+ // CHECK: define weak_odr hidden void @_ZN5test31BINS_1AEE3fooEv()
+ // CHECK: declare void @_ZN5test31BINS_1AEE3barEv()
+
+ const std::type_info &ti = typeid(B<A>);
+ // CHECK-GLOBAL: @_ZTSN5test31BINS_1AEEE = linkonce_odr constant
+ // CHECK-GLOBAL: @_ZTIN5test31BINS_1AEEE = linkonce_odr unnamed_addr constant
+}
+
+namespace test4 {
+ struct A { int x; };
+ template <class T> struct DEFAULT B {
+ static void foo() { bar(); }
+ static void bar();
+ };
+
+ template void B<A>::foo();
+ // CHECK: define weak_odr void @_ZN5test41BINS_1AEE3fooEv()
+ // CHECK: declare void @_ZN5test41BINS_1AEE3barEv()
+
+ const std::type_info &ti = typeid(B<A>);
+ // CHECK-GLOBAL: @_ZTSN5test41BINS_1AEEE = linkonce_odr constant
+ // CHECK-GLOBAL: @_ZTIN5test41BINS_1AEEE = linkonce_odr unnamed_addr constant
+}
+
+namespace test5 {
+ struct A { int x; };
+ template <class T> struct HIDDEN B {
+ static void foo() { bar(); }
+ static void bar();
+ };
+
+ template void B<A>::foo();
+ // CHECK: define weak_odr hidden void @_ZN5test51BINS_1AEE3fooEv()
+ // CHECK: declare hidden void @_ZN5test51BINS_1AEE3barEv()
+
+ const std::type_info &ti = typeid(B<A>);
+ // CHECK-GLOBAL: @_ZTSN5test51BINS_1AEEE = linkonce_odr hidden constant
+ // CHECK-GLOBAL: @_ZTIN5test51BINS_1AEEE = linkonce_odr hidden unnamed_addr constant
+}
diff --git a/test/CodeGenCXX/visibility.cpp b/test/CodeGenCXX/visibility.cpp
index 0145039..87add44 100644
--- a/test/CodeGenCXX/visibility.cpp
+++ b/test/CodeGenCXX/visibility.cpp
@@ -47,7 +47,7 @@ namespace test29 {
struct RECT {
int top;
};
- __attribute__ ((visibility ("default"))) extern RECT data_rect;
+ DEFAULT extern RECT data_rect;
RECT data_rect = { -1};
#pragma GCC visibility pop
// CHECK: @_ZN6test299data_rectE = global
@@ -70,7 +70,7 @@ namespace test41 {
// Unlike gcc we propagate the information that foo not only is hidden, but
// has been explicitly marked as so. This lets us produce a hidden undefined
// reference to bar.
- struct __attribute__((visibility("hidden"))) foo {};
+ struct HIDDEN foo {};
extern foo bar;
foo *zed() {
return &bar;
@@ -119,7 +119,7 @@ namespace test48 {
namespace test27 {
template<typename T>
class C {
- class __attribute__((visibility("default"))) D {
+ class DEFAULT D {
void f();
};
};
@@ -526,7 +526,7 @@ namespace Test20 {
namespace test21 {
enum En { en };
template<En> struct A {
- __attribute__((visibility("default"))) void foo() {}
+ DEFAULT void foo() {}
};
// CHECK: define weak_odr void @_ZN6test211AILNS_2EnE0EE3fooEv(
@@ -580,9 +580,7 @@ namespace PR10113 {
};
template class foo::bar<zed>;
// CHECK: define weak_odr void @_ZN7PR101133foo3barINS_3zedEE3zedEv
-
- // FIXME: This should be hidden as zed is hidden.
- // CHECK-HIDDEN: define weak_odr void @_ZN7PR101133foo3barINS_3zedEE3zedEv
+ // CHECK-HIDDEN: define weak_odr hidden void @_ZN7PR101133foo3barINS_3zedEE3zedEv
}
namespace PR11690 {
@@ -613,9 +611,7 @@ namespace PR11690_2 {
};
template class foo::zed<baz>;
// CHECK: define weak_odr void @_ZN9PR11690_23foo3zedINS_3bazENS0_3barEE3barEv
-
- // FIXME: This should be hidden as baz is hidden.
- // CHECK-HIDDEN: define weak_odr void @_ZN9PR11690_23foo3zedINS_3bazENS0_3barEE3barEv
+ // CHECK-HIDDEN: define weak_odr hidden void @_ZN9PR11690_23foo3zedINS_3bazENS0_3barEE3barEv
}
namespace test23 {
@@ -670,7 +666,7 @@ namespace test24 {
namespace test26 {
template<typename T>
class C {
- __attribute__((visibility("default"))) void f();
+ DEFAULT void f();
};
template<>
@@ -729,10 +725,10 @@ namespace test34 {
namespace test35 {
// This is a really ugly testcase. GCC propagates the DEFAULT in zed's
- // definition. What we do instead is be conservative about merging
- // implicit visibilities.
- // FIXME: Maybe the best thing to do here is error? The test at least
- // makes sure we don't produce a hidden symbol for foo<zed>::bar.
+ // definition. It's not really clear what we can do here, because we
+ // produce the symbols before even seeing the DEFAULT definition of zed.
+ // FIXME: Maybe the best thing to do here is error? It's certainly hard
+ // to argue that this ought to be valid.
template<typename T>
struct DEFAULT foo {
void bar() {}
@@ -742,7 +738,7 @@ namespace test35 {
class DEFAULT zed {
};
// CHECK: define weak_odr void @_ZN6test353fooINS_3zedEE3barEv
- // CHECK-HIDDEN: define weak_odr void @_ZN6test353fooINS_3zedEE3barEv
+ // CHECK-HIDDEN: define weak_odr hidden void @_ZN6test353fooINS_3zedEE3barEv
}
namespace test36 {
@@ -821,8 +817,8 @@ namespace test42 {
};
void bar<foo>::zed() {
}
- // CHECK: define hidden void @_ZN6test423barINS_3fooEE3zedEv
- // CHECK-HIDDEN: define hidden void @_ZN6test423barINS_3fooEE3zedEv
+ // CHECK: define void @_ZN6test423barINS_3fooEE3zedEv
+ // CHECK-HIDDEN: define void @_ZN6test423barINS_3fooEE3zedEv
}
namespace test43 {
@@ -834,8 +830,8 @@ namespace test43 {
template <>
DEFAULT void bar<foo>() {
}
- // CHECK: define hidden void @_ZN6test433barINS_3fooEEEvv
- // CHECK-HIDDEN: define hidden void @_ZN6test433barINS_3fooEEEvv
+ // CHECK: define void @_ZN6test433barINS_3fooEEEvv
+ // CHECK-HIDDEN: define void @_ZN6test433barINS_3fooEEEvv
}
namespace test44 {
@@ -893,7 +889,7 @@ namespace test47 {
namespace {
struct zed;
}
- template __attribute__((visibility("default"))) void foo::bar<zed>();
+ template DEFAULT void foo::bar<zed>();
void baz() {
foo::bar<zed>();
}
@@ -1021,7 +1017,7 @@ namespace test54 {
namespace test55 {
template <class T>
- struct __attribute__((visibility("hidden"))) foo {
+ struct HIDDEN foo {
static void bar();
};
template <class T> struct foo;
@@ -1035,7 +1031,7 @@ namespace test55 {
namespace test56 {
template <class T> struct foo;
template <class T>
- struct __attribute__((visibility("hidden"))) foo {
+ struct HIDDEN foo {
static void bar();
};
void foobar() {
@@ -1066,7 +1062,7 @@ namespace test58 {
#pragma GCC visibility push(hidden)
struct foo;
template<typename T>
- struct __attribute__((visibility("default"))) bar {
+ struct DEFAULT bar {
static void zed() {
}
};
@@ -1097,9 +1093,9 @@ namespace test59 {
namespace test60 {
template<int i>
- class __attribute__((visibility("hidden"))) a {};
+ class HIDDEN a {};
template<int i>
- class __attribute__((visibility("default"))) b {};
+ class DEFAULT b {};
template<template<int> class x, template<int> class y>
void test() {}
void use() {
@@ -1112,3 +1108,172 @@ namespace test60 {
// CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test604testINS_1bENS_1aEEEvv
}
}
+
+namespace test61 {
+ template <typename T1>
+ struct Class1
+ {
+ void f1() { f2(); }
+ inline void f2();
+ };
+ template<>
+ inline void Class1<int>::f2()
+ {
+ }
+ void g(Class1<int> *x) {
+ x->f1();
+ }
+}
+namespace test61 {
+ // Just test that we don't crash. Currently we apply this attribute. Current
+ // gcc issues a warning about it being unused since "the type is already
+ // defined". We should probably do the same.
+ template class HIDDEN Class1<int>;
+}
+
+namespace test62 {
+ template <typename T1>
+ struct Class1
+ {
+ void f1() { f2(); }
+ inline void f2() {}
+ };
+ template<>
+ inline void Class1<int>::f2()
+ {
+ }
+ void g(Class1<int> *x) {
+ x->f2();
+ }
+}
+namespace test62 {
+ template class HIDDEN Class1<int>;
+ // Just test that we don't crash. Currently we apply this attribute. Current
+ // gcc issues a warning about it being unused since "the type is already
+ // defined". We should probably do the same.
+}
+
+namespace test63 {
+ enum HIDDEN E { E0 };
+ struct A {
+ template <E> static void foo() {}
+
+ template <E> struct B {
+ static void foo() {}
+ };
+ };
+
+ void test() {
+ A::foo<E0>();
+ A::B<E0>::foo();
+ }
+ // CHECK: define linkonce_odr hidden void @_ZN6test631A3fooILNS_1EE0EEEvv()
+ // CHECK: define linkonce_odr hidden void @_ZN6test631A1BILNS_1EE0EE3fooEv()
+}
+
+// Don't ignore the visibility of template arguments just because we
+// explicitly instantiated something.
+namespace test64 {
+ struct HIDDEN A {};
+ template <class P> struct B {
+ static DEFAULT void foo() {}
+ };
+
+ template class B<A>;
+ // CHECK: define weak_odr hidden void @_ZN6test641BINS_1AEE3fooEv()
+}
+
+namespace test65 {
+ class HIDDEN A {};
+ template <class T> struct B {
+ static void func();
+ template <class U> static void funcT1();
+ template <class U> static void funcT2();
+ class Inner {};
+ template <class U> class InnerT {};
+ };
+ template <template <class T> class Temp> struct C {
+ static void foo() {}
+ };
+
+ // CHECK: define void @_ZN6test651BINS_1AEE4funcEv()
+ template <> DEFAULT void B<A>::func() {}
+
+ // CHECK: define void @_ZN6test651BINS_1AEE6funcT2IS1_EEvv()
+ template <> template <> DEFAULT void B<A>::funcT2<A>() {}
+
+ // CHECK: define linkonce_odr void @_ZN6test651BINS_1AEE6funcT1IiEEvv()
+ // CHECK: define linkonce_odr hidden void @_ZN6test651BINS_1AEE6funcT1IS1_EEvv()
+ template <> template <class T> DEFAULT void B<A>::funcT1() {}
+
+ // CHECK: define linkonce_odr void @_ZN6test651BINS_1AEE5Inner3fooEv()
+ template <> struct DEFAULT B<A>::Inner {
+ static void foo() {}
+ };
+
+ // CHECK: define linkonce_odr void @_ZN6test651BINS_1AEE6InnerTIiE3fooEv()
+ // CHECK: define linkonce_odr hidden void @_ZN6test651BINS_1AEE6InnerTIS1_E3fooEv()
+ template <> template <class U> struct DEFAULT B<A>::InnerT {
+ static void foo() {}
+ };
+
+ void test() {
+ B<A>::funcT1<int>();
+ B<A>::funcT1<A>();
+ B<A>::Inner::foo();
+ B<A>::InnerT<int>::foo();
+ B<A>::InnerT<A>::foo();
+ }
+
+ template class C<B<A>::InnerT>;
+}
+
+namespace test66 {
+ template <typename T>
+ struct DEFAULT barT {
+ static void zed() {}
+ };
+ class foo;
+ class DEFAULT foo;
+ template struct barT<foo>;
+ // CHECK: define weak_odr void @_ZN6test664barTINS_3fooEE3zedEv
+ // CHECK-HIDDEN: define weak_odr void @_ZN6test664barTINS_3fooEE3zedEv
+
+ template <int* I>
+ struct DEFAULT barI {
+ static void zed() {}
+ };
+ extern int I;
+ extern int I DEFAULT;
+ template struct barI<&I>;
+ // CHECK: define weak_odr void @_ZN6test664barIIXadL_ZNS_1IEEEE3zedEv
+ // CHECK-HIDDEN: define weak_odr void @_ZN6test664barIIXadL_ZNS_1IEEEE3zedEv
+
+ typedef void (*fType)(void);
+ template<fType F>
+ struct DEFAULT barF {
+ static void zed() {}
+ };
+ void F();
+ void F() DEFAULT;
+ template struct barF<F>;
+ // CHECK: define weak_odr void @_ZN6test664barFIXadL_ZNS_1FEvEEE3zedEv
+ // CHECK-HIDDEN: define weak_odr void @_ZN6test664barFIXadL_ZNS_1FEvEEE3zedEv
+}
+
+namespace test67 {
+ template <typename T>
+ struct DEFAULT bar {
+ static void zed() {}
+ };
+
+ class foo;
+ class compute {
+ void f(foo *rootfoo);
+ };
+ class DEFAULT foo;
+
+ template struct bar<foo>;
+ // CHECK: define weak_odr void @_ZN6test673barINS_3fooEE3zedEv
+ // CHECK-HIDDEN: define weak_odr void @_ZN6test673barINS_3fooEE3zedEv
+}
diff --git a/test/CodeGenCXX/vtable-available-externally.cpp b/test/CodeGenCXX/vtable-available-externally.cpp
index 23baac9..693b36a 100644
--- a/test/CodeGenCXX/vtable-available-externally.cpp
+++ b/test/CodeGenCXX/vtable-available-externally.cpp
@@ -6,13 +6,14 @@
#include <typeinfo>
-// Test1::A's key function (f) is not defined in this translation unit, but in
-// order to devirtualize calls, we emit the class related data with
+// Test1::A's key function (f) is not defined in this translation
+// unit, but in order to devirtualize calls, we emit the v-table with
// available_externally linkage.
+//
+// There's no real reason to do this to the RTTI, though.
// CHECK-TEST1: @_ZTVN5Test11AE = available_externally
-// CHECK-TEST1: @_ZTSN5Test11AE = available_externally
-// CHECK-TEST1: @_ZTIN5Test11AE = available_externally
+// CHECK-TEST1: @_ZTIN5Test11AE = external constant i8*
namespace Test1 {
struct A {
diff --git a/test/CodeGenCXX/vtable-key-function-arm.cpp b/test/CodeGenCXX/vtable-key-function-arm.cpp
new file mode 100644
index 0000000..08efe8a
--- /dev/null
+++ b/test/CodeGenCXX/vtable-key-function-arm.cpp
@@ -0,0 +1,307 @@
+// RUN: %clang_cc1 %s -triple=armv7-unknown-unknown -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple=armv7-unknown-unknown -emit-llvm -o - | FileCheck -check-prefix=CHECK-LATE %s
+
+// The 'a' variants ask for the v-table first.
+// The 'b' variants ask for the v-table second.
+// The 'c' variants ask for the v-table third.
+// We do a separate CHECK-LATE pass because the RTTI defintion gets
+// changed after the fact, which causes reordering of the globals.
+
+// These are not separated into namespaces because the way that Sema
+// currently reports namespaces to IR-generation (i.e., en masse for
+// the entire namespace at once) subverts the ordering that we're
+// trying to test.
+
+namespace std { class type_info; }
+extern void use(const std::type_info &rtti);
+
+/*** Test0a ******************************************************************/
+
+struct Test0a {
+ Test0a();
+ virtual inline void foo();
+ virtual void bar();
+};
+
+// V-table should be defined externally.
+Test0a::Test0a() { use(typeid(Test0a)); }
+// CHECK: @_ZTV6Test0a = external unnamed_addr constant
+// CHECK: @_ZTI6Test0a = external constant
+
+// This is still not a key function.
+void Test0a::foo() {}
+
+/*** Test0b ******************************************************************/
+
+struct Test0b {
+ Test0b();
+ virtual inline void foo();
+ virtual void bar();
+};
+
+// This is still not a key function.
+void Test0b::foo() {}
+
+// V-table should be defined externally.
+Test0b::Test0b() { use(typeid(Test0b)); }
+// CHECK: @_ZTV6Test0b = external unnamed_addr constant
+// CHECK: @_ZTI6Test0b = external constant
+
+/*** Test1a ******************************************************************/
+
+struct Test1a {
+ Test1a();
+ virtual void foo();
+ virtual void bar();
+};
+
+// V-table should be defined externally.
+Test1a::Test1a() { use(typeid(Test1a)); }
+// CHECK: @_ZTV6Test1a = external unnamed_addr constant
+// CHECK: @_ZTI6Test1a = external constant
+
+// 'bar' becomes the key function when 'foo' is defined inline.
+inline void Test1a::foo() {}
+
+/*** Test1b ******************************************************************/
+
+struct Test1b {
+ Test1b();
+ virtual void foo();
+ virtual void bar();
+};
+
+// 'bar' becomes the key function when 'foo' is defined inline.
+inline void Test1b::foo() {}
+
+// V-table should be defined externally.
+Test1b::Test1b() { use(typeid(Test1b)); }
+// CHECK: @_ZTV6Test1b = external unnamed_addr constant
+// CHECK: @_ZTI6Test1b = external constant
+
+/*** Test2a ******************************************************************/
+
+struct Test2a {
+ Test2a();
+ virtual void foo();
+ virtual void bar();
+};
+
+// V-table should be defined with strong linkage.
+Test2a::Test2a() { use(typeid(Test2a)); }
+// CHECK: @_ZTV6Test2a = unnamed_addr constant
+// CHECK-LATE: @_ZTS6Test2a = constant
+// CHECK-LATE: @_ZTI6Test2a = unnamed_addr constant
+
+// 'bar' becomes the key function when 'foo' is defined inline.
+void Test2a::bar() {}
+inline void Test2a::foo() {}
+
+/*** Test2b ******************************************************************/
+
+struct Test2b {
+ Test2b();
+ virtual void foo();
+ virtual void bar();
+};
+
+// 'bar' becomes the key function when 'foo' is defined inline.
+void Test2b::bar() {}
+
+// V-table should be defined with strong linkage.
+Test2b::Test2b() { use(typeid(Test2b)); }
+// CHECK: @_ZTV6Test2b = unnamed_addr constant
+// CHECK-LATE: @_ZTS6Test2b = constant
+// CHECK-LATE: @_ZTI6Test2b = unnamed_addr constant
+
+inline void Test2b::foo() {}
+
+/*** Test2c ******************************************************************/
+
+struct Test2c {
+ Test2c();
+ virtual void foo();
+ virtual void bar();
+};
+
+// 'bar' becomes the key function when 'foo' is defined inline.
+void Test2c::bar() {}
+inline void Test2c::foo() {}
+
+// V-table should be defined with strong linkage.
+Test2c::Test2c() { use(typeid(Test2c)); }
+// CHECK: @_ZTV6Test2c = unnamed_addr constant
+// CHECK: @_ZTS6Test2c = constant
+// CHECK: @_ZTI6Test2c = unnamed_addr constant
+
+/*** Test3a ******************************************************************/
+
+struct Test3a {
+ Test3a();
+ virtual void foo();
+ virtual void bar();
+};
+
+// V-table should be defined with weak linkage.
+Test3a::Test3a() { use(typeid(Test3a)); }
+// CHECK: @_ZTV6Test3a = linkonce_odr unnamed_addr constant
+// CHECK-LATE: @_ZTS6Test3a = linkonce_odr constant
+// CHECK-LATE: @_ZTI6Test3a = linkonce_odr unnamed_addr constant
+
+// There ceases to be a key function after these declarations.
+inline void Test3a::bar() {}
+inline void Test3a::foo() {}
+
+/*** Test3b ******************************************************************/
+
+struct Test3b {
+ Test3b();
+ virtual void foo();
+ virtual void bar();
+};
+
+// There ceases to be a key function after these declarations.
+inline void Test3b::bar() {}
+
+// V-table should be defined with weak linkage.
+Test3b::Test3b() { use(typeid(Test3b)); }
+// CHECK: @_ZTV6Test3b = linkonce_odr unnamed_addr constant
+// CHECK-LATE: @_ZTS6Test3b = linkonce_odr constant
+// CHECK-LATE: @_ZTI6Test3b = linkonce_odr unnamed_addr constant
+
+inline void Test3b::foo() {}
+
+/*** Test3c ******************************************************************/
+
+struct Test3c {
+ Test3c();
+ virtual void foo();
+ virtual void bar();
+};
+
+// There ceases to be a key function after these declarations.
+inline void Test3c::bar() {}
+inline void Test3c::foo() {}
+
+// V-table should be defined with weak linkage.
+Test3c::Test3c() { use(typeid(Test3c)); }
+// CHECK: @_ZTV6Test3c = linkonce_odr unnamed_addr constant
+// CHECK: @_ZTS6Test3c = linkonce_odr constant
+// CHECK: @_ZTI6Test3c = linkonce_odr unnamed_addr constant
+
+/*** Test4a ******************************************************************/
+
+template <class T> struct Test4a {
+ Test4a();
+ virtual void foo();
+ virtual void bar();
+};
+
+// V-table should be defined with weak linkage.
+template <> Test4a<int>::Test4a() { use(typeid(Test4a)); }
+// CHECK: @_ZTV6Test4aIiE = linkonce_odr unnamed_addr constant
+// CHECK: @_ZTS6Test4aIiE = linkonce_odr constant
+// CHECK: @_ZTI6Test4aIiE = linkonce_odr unnamed_addr constant
+
+// There ceases to be a key function after these declarations.
+template <> inline void Test4a<int>::bar() {}
+template <> inline void Test4a<int>::foo() {}
+
+/*** Test4b ******************************************************************/
+
+template <class T> struct Test4b {
+ Test4b();
+ virtual void foo();
+ virtual void bar();
+};
+
+// There ceases to be a key function after these declarations.
+template <> inline void Test4b<int>::bar() {}
+
+// V-table should be defined with weak linkage.
+template <> Test4b<int>::Test4b() { use(typeid(Test4b)); }
+// CHECK: @_ZTV6Test4bIiE = linkonce_odr unnamed_addr constant
+// CHECK: @_ZTS6Test4bIiE = linkonce_odr constant
+// CHECK: @_ZTI6Test4bIiE = linkonce_odr unnamed_addr constant
+
+template <> inline void Test4b<int>::foo() {}
+
+/*** Test4c ******************************************************************/
+
+template <class T> struct Test4c {
+ Test4c();
+ virtual void foo();
+ virtual void bar();
+};
+
+// There ceases to be a key function after these declarations.
+template <> inline void Test4c<int>::bar() {}
+template <> inline void Test4c<int>::foo() {}
+
+// V-table should be defined with weak linkage.
+template <> Test4c<int>::Test4c() { use(typeid(Test4c)); }
+// CHECK: @_ZTV6Test4cIiE = linkonce_odr unnamed_addr constant
+// CHECK: @_ZTS6Test4cIiE = linkonce_odr constant
+// CHECK: @_ZTI6Test4cIiE = linkonce_odr unnamed_addr constant
+
+/*** Test5a ******************************************************************/
+
+template <class T> struct Test5a {
+ Test5a();
+ virtual void foo();
+ virtual void bar();
+};
+
+template <> inline void Test5a<int>::bar();
+template <> inline void Test5a<int>::foo();
+
+// V-table should be defined with weak linkage.
+template <> Test5a<int>::Test5a() { use(typeid(Test5a)); }
+// CHECK: @_ZTV6Test5aIiE = linkonce_odr unnamed_addr constant
+// CHECK: @_ZTS6Test5aIiE = linkonce_odr constant
+// CHECK: @_ZTI6Test5aIiE = linkonce_odr unnamed_addr constant
+
+// There ceases to be a key function after these declarations.
+template <> inline void Test5a<int>::bar() {}
+template <> inline void Test5a<int>::foo() {}
+
+/*** Test5b ******************************************************************/
+
+template <class T> struct Test5b {
+ Test5b();
+ virtual void foo();
+ virtual void bar();
+};
+
+// There ceases to be a key function after these declarations.
+template <> inline void Test5a<int>::bar();
+template <> inline void Test5b<int>::bar() {}
+
+// V-table should be defined with weak linkage.
+template <> Test5b<int>::Test5b() { use(typeid(Test5b)); }
+// CHECK: @_ZTV6Test5bIiE = linkonce_odr unnamed_addr constant
+// CHECK: @_ZTS6Test5bIiE = linkonce_odr constant
+// CHECK: @_ZTI6Test5bIiE = linkonce_odr unnamed_addr constant
+
+template <> inline void Test5a<int>::foo();
+template <> inline void Test5b<int>::foo() {}
+
+/*** Test5c ******************************************************************/
+
+template <class T> struct Test5c {
+ Test5c();
+ virtual void foo();
+ virtual void bar();
+};
+
+// There ceases to be a key function after these declarations.
+template <> inline void Test5a<int>::bar();
+template <> inline void Test5a<int>::foo();
+template <> inline void Test5c<int>::bar() {}
+template <> inline void Test5c<int>::foo() {}
+
+// V-table should be defined with weak linkage.
+template <> Test5c<int>::Test5c() { use(typeid(Test5c)); }
+// CHECK: @_ZTV6Test5cIiE = linkonce_odr unnamed_addr constant
+// CHECK: @_ZTS6Test5cIiE = linkonce_odr constant
+// CHECK: @_ZTI6Test5cIiE = linkonce_odr unnamed_addr constant
diff --git a/test/CodeGenCXX/vtable-key-function-ios.cpp b/test/CodeGenCXX/vtable-key-function-ios.cpp
new file mode 100644
index 0000000..bcd3e88
--- /dev/null
+++ b/test/CodeGenCXX/vtable-key-function-ios.cpp
@@ -0,0 +1,189 @@
+// RUN: %clang_cc1 %s -triple=armv7-apple-darwin -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple=armv7-apple-darwin -emit-llvm -o - | FileCheck -check-prefix=CHECK-LATE %s
+
+// The 'a' variants ask for the v-table first.
+// The 'b' variants ask for the v-table second.
+// The 'c' variants ask for the v-table third.
+// We do a separate CHECK-LATE pass because the RTTI defintion gets
+// changed after the fact, which causes reordering of the globals.
+
+// These are not separated into namespaces because the way that Sema
+// currently reports namespaces to IR-generation (i.e., en masse for
+// the entire namespace at once) subverts the ordering that we're
+// trying to test.
+
+namespace std { class type_info; }
+extern void use(const std::type_info &rtti);
+
+/*** Test0a ******************************************************************/
+
+struct Test0a {
+ Test0a();
+ virtual inline void foo();
+ virtual void bar();
+};
+
+// V-table should be defined externally.
+Test0a::Test0a() { use(typeid(Test0a)); }
+// CHECK: @_ZTV6Test0a = external unnamed_addr constant
+// CHECK: @_ZTI6Test0a = external constant
+
+// This is not a key function.
+void Test0a::foo() {}
+
+/*** Test0b ******************************************************************/
+
+struct Test0b {
+ Test0b();
+ virtual inline void foo();
+ virtual void bar();
+};
+
+// This is not a key function.
+void Test0b::foo() {}
+
+// V-table should be defined externally.
+Test0b::Test0b() { use(typeid(Test0b)); }
+// CHECK: @_ZTV6Test0b = external unnamed_addr constant
+// CHECK: @_ZTI6Test0b = external constant
+
+/*** Test1a ******************************************************************/
+
+struct Test1a {
+ Test1a();
+ virtual void foo();
+ virtual void bar();
+};
+
+// V-table needs to be defined weakly.
+Test1a::Test1a() { use(typeid(Test1a)); }
+// CHECK: @_ZTV6Test1a = linkonce_odr unnamed_addr constant
+// CHECK-LATE: @_ZTS6Test1a = linkonce_odr constant
+// CHECK-LATE: @_ZTI6Test1a = linkonce_odr unnamed_addr constant
+
+// This defines the key function.
+inline void Test1a::foo() {}
+
+/*** Test1b ******************************************************************/
+
+struct Test1b {
+ Test1b();
+ virtual void foo();
+ virtual void bar();
+};
+
+// This defines the key function.
+inline void Test1b::foo() {}
+
+// V-table should be defined weakly..
+Test1b::Test1b() { use(typeid(Test1b)); }
+// CHECK: @_ZTV6Test1b = linkonce_odr unnamed_addr constant
+// CHECK: @_ZTS6Test1b = linkonce_odr constant
+// CHECK: @_ZTI6Test1b = linkonce_odr unnamed_addr constant
+
+/*** Test2a ******************************************************************/
+
+struct Test2a {
+ Test2a();
+ virtual void foo();
+ virtual void bar();
+};
+
+// V-table should be defined with weak linkage.
+Test2a::Test2a() { use(typeid(Test2a)); }
+// CHECK: @_ZTV6Test2a = linkonce_odr unnamed_addr constant
+// CHECK-LATE: @_ZTS6Test2a = linkonce_odr constant
+// CHECK-LATE: @_ZTI6Test2a = linkonce_odr unnamed_addr constant
+
+void Test2a::bar() {}
+inline void Test2a::foo() {}
+
+/*** Test2b ******************************************************************/
+
+struct Test2b {
+ Test2b();
+ virtual void foo();
+ virtual void bar();
+};
+
+void Test2b::bar() {}
+
+// V-table should be defined with weak linkage.
+Test2b::Test2b() { use(typeid(Test2b)); }
+// CHECK: @_ZTV6Test2b = linkonce_odr unnamed_addr constant
+// CHECK-LATE: @_ZTS6Test2b = linkonce_odr constant
+// CHECK-LATE: @_ZTI6Test2b = linkonce_odr unnamed_addr constant
+
+inline void Test2b::foo() {}
+
+/*** Test2c ******************************************************************/
+
+struct Test2c {
+ Test2c();
+ virtual void foo();
+ virtual void bar();
+};
+
+void Test2c::bar() {}
+inline void Test2c::foo() {}
+
+// V-table should be defined with weak linkage.
+Test2c::Test2c() { use(typeid(Test2c)); }
+// CHECK: @_ZTV6Test2c = linkonce_odr unnamed_addr constant
+// CHECK: @_ZTS6Test2c = linkonce_odr constant
+// CHECK: @_ZTI6Test2c = linkonce_odr unnamed_addr constant
+
+/*** Test3a ******************************************************************/
+
+struct Test3a {
+ Test3a();
+ virtual void foo();
+ virtual void bar();
+};
+
+// V-table should be defined with weak linkage.
+Test3a::Test3a() { use(typeid(Test3a)); }
+// CHECK: @_ZTV6Test3a = linkonce_odr unnamed_addr constant
+// CHECK-LATE: @_ZTS6Test3a = linkonce_odr constant
+// CHECK-LATE: @_ZTI6Test3a = linkonce_odr unnamed_addr constant
+
+// This defines the key function.
+inline void Test3a::bar() {}
+inline void Test3a::foo() {}
+
+/*** Test3b ******************************************************************/
+
+struct Test3b {
+ Test3b();
+ virtual void foo();
+ virtual void bar();
+};
+
+inline void Test3b::bar() {}
+
+// V-table should be defined with weak linkage.
+Test3b::Test3b() { use(typeid(Test3b)); }
+// CHECK: @_ZTV6Test3b = linkonce_odr unnamed_addr constant
+// CHECK-LATE: @_ZTS6Test3b = linkonce_odr constant
+// CHECK-LATE: @_ZTI6Test3b = linkonce_odr unnamed_addr constant
+
+// This defines the key function.
+inline void Test3b::foo() {}
+
+/*** Test3c ******************************************************************/
+
+struct Test3c {
+ Test3c();
+ virtual void foo();
+ virtual void bar();
+};
+
+// This defines the key function.
+inline void Test3c::bar() {}
+inline void Test3c::foo() {}
+
+// V-table should be defined with weak linkage.
+Test3c::Test3c() { use(typeid(Test3c)); }
+// CHECK: @_ZTV6Test3c = linkonce_odr unnamed_addr constant
+// CHECK: @_ZTS6Test3c = linkonce_odr constant
+// CHECK: @_ZTI6Test3c = linkonce_odr unnamed_addr constant
diff --git a/test/CodeGenCXX/vtable-linkage.cpp b/test/CodeGenCXX/vtable-linkage.cpp
index 4633a3f..b945e56 100644
--- a/test/CodeGenCXX/vtable-linkage.cpp
+++ b/test/CodeGenCXX/vtable-linkage.cpp
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o %t
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -fhidden-weak-vtables -emit-llvm -o %t.hidden
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -disable-llvm-optzns -O3 -emit-llvm -o %t.opt
// RUN: FileCheck --check-prefix=CHECK-1 %s < %t
// RUN: FileCheck --check-prefix=CHECK-2 %s < %t
// RUN: FileCheck --check-prefix=CHECK-2-HIDDEN %s < %t.hidden
@@ -12,7 +13,9 @@
// RUN: FileCheck --check-prefix=CHECK-7 %s < %t
// RUN: FileCheck --check-prefix=CHECK-8 %s < %t
// RUN: FileCheck --check-prefix=CHECK-9 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-9-OPT %s < %t.opt
// RUN: FileCheck --check-prefix=CHECK-10 %s < %t
+// RUN: FileCheck --check-prefix=CHECK-10-OPT %s < %t.opt
// RUN: FileCheck --check-prefix=CHECK-11 %s < %t
// RUN: FileCheck --check-prefix=CHECK-12 %s < %t
// RUN: FileCheck --check-prefix=CHECK-13 %s < %t
@@ -160,11 +163,13 @@ void use_F() {
// F<int> is an explicit template instantiation declaration without a
// key function, so its vtable should have external linkage.
// CHECK-9: @_ZTV1FIiE = external unnamed_addr constant
+// CHECK-9-OPT: @_ZTV1FIiE = available_externally unnamed_addr constant
// E<int> is an explicit template instantiation declaration. It has a
// key function that is not instantiated, so we should only reference
// its vtable, not define it.
// CHECK-10: @_ZTV1EIiE = external unnamed_addr constant
+// CHECK-10-OPT: @_ZTV1EIiE = available_externally unnamed_addr constant
// The anonymous struct for e has no linkage, so the vtable should have
// internal linkage.
@@ -214,3 +219,24 @@ public:
void use_H() {
H<int> h;
}
+
+// RUN: FileCheck --check-prefix=CHECK-I %s < %t
+// RUN: FileCheck --check-prefix=CHECK-I-OPT %s < %t.opt
+
+// I<int> has an explicit instantiation declaration and needs a VTT and
+// construction vtables. We emit the VTT available_externally, but point it at
+// internal construction vtables because there is no way to form a reference to
+// the real construction vtables.
+
+// CHECK-I: @_ZTV1IIiE = external unnamed_addr constant
+// CHECK-I: @_ZTT1IIiE = external unnamed_addr constant
+// CHECK-I-NOT: @_ZTC1IIiE
+//
+// CHECK-I-OPT: @_ZTV1IIiE = available_externally unnamed_addr constant
+// CHECK-I-OPT: @_ZTT1IIiE = available_externally unnamed_addr constant {{.*}} @_ZTC1IIiE0_6VBase2
+// CHECK-I-OPT: @_ZTC1IIiE0_6VBase2 = internal unnamed_addr constant
+struct VBase1 { virtual void f(); }; struct VBase2 : virtual VBase1 {};
+template<typename T>
+struct I : VBase2 {};
+extern template struct I<int>;
+I<int> i;
diff --git a/test/CodeGenObjC/arc-arm.m b/test/CodeGenObjC/arc-arm.m
index 2ab8cb6..3989f56 100644
--- a/test/CodeGenObjC/arc-arm.m
+++ b/test/CodeGenObjC/arc-arm.m
@@ -11,9 +11,9 @@ void test1(void) {
extern id test1_helper(void);
// CHECK: [[T0:%.*]] = call arm_aapcscc i8* @test1_helper()
// CHECK-NEXT: call void asm sideeffect "mov\09r7, r7
- // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+ // CHECK-NEXT: [[T1:%.*]] = call arm_aapcscc i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
// CHECK-NEXT: store i8* [[T1]],
- // CHECK-NEXT: call void @objc_storeStrong(
+ // CHECK-NEXT: call arm_aapcscc void @objc_storeStrong(
// CHECK-NEXT: ret void
id x = test1_helper();
}
diff --git a/test/CodeGenObjC/arc-block-copy-escape.m b/test/CodeGenObjC/arc-block-copy-escape.m
index 15c0d1d..3ba7426 100644
--- a/test/CodeGenObjC/arc-block-copy-escape.m
+++ b/test/CodeGenObjC/arc-block-copy-escape.m
@@ -9,14 +9,16 @@ void use_int(int);
void test0(int i) {
block_t block = ^{ use_int(i); };
// CHECK: define void @test0(
- // CHECK: call i8* @objc_retainBlock(i8* {{%.*}}) nounwind, !clang.arc.copy_on_escape
+ // CHECK: call i8* @objc_retainBlock(i8* {{%.*}}) [[NUW:#[0-9]+]], !clang.arc.copy_on_escape
// CHECK: ret void
}
void test1(int i) {
id block = ^{ use_int(i); };
// CHECK: define void @test1(
- // CHECK: call i8* @objc_retainBlock(i8* {{%.*}}) nounwind
+ // CHECK: call i8* @objc_retainBlock(i8* {{%.*}}) [[NUW]]
// CHECK-NOT: !clang.arc.copy_on_escape
// CHECK: ret void
}
+
+// CHECK: attributes [[NUW]] = { nounwind }
diff --git a/test/CodeGenObjC/arc-blocks.m b/test/CodeGenObjC/arc-blocks.m
index e776517..3281b2a 100644
--- a/test/CodeGenObjC/arc-blocks.m
+++ b/test/CodeGenObjC/arc-blocks.m
@@ -13,10 +13,10 @@ int (^test1(int x))(void) {
// CHECK-NEXT: store i32 {{%.*}}, i32* [[X]]
// CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to i32 ()*
// CHECK-NEXT: [[T1:%.*]] = bitcast i32 ()* [[T0]] to i8*
- // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]]) nounwind
+ // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]]) [[NUW:#[0-9]+]]
// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to i32 ()*
// CHECK-NEXT: [[T4:%.*]] = bitcast i32 ()* [[T3]] to i8*
- // CHECK-NEXT: [[T5:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[T4]]) nounwind
+ // CHECK-NEXT: [[T5:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[T4]]) [[NUW]]
// CHECK-NEXT: [[T6:%.*]] = bitcast i8* [[T5]] to i32 ()*
// CHECK-NEXT: ret i32 ()* [[T6]]
return ^{ return x; };
@@ -36,9 +36,9 @@ void test2(id x) {
// CHECK-NEXT: bitcast
// CHECK-NEXT: call void @test2_helper(
// CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOTREL]]
-// CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
+// CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]], !clang.imprecise_release
// CHECK-NEXT: [[T0:%.*]] = load i8** [[X]]
-// CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
+// CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]], !clang.imprecise_release
// CHECK-NEXT: ret void
extern void test2_helper(id (^)(void));
test2_helper(^{ return x; });
@@ -50,7 +50,7 @@ void test2(id x) {
// 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: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) [[NUW]]
// CHECK-NEXT: ret void
// CHECK: define internal void @__destroy_helper_block_
@@ -80,13 +80,14 @@ void test3(void (^sink)(id*)) {
// CHECK-NEXT: bitcast
// CHECK-NEXT: getelementptr
// CHECK-NEXT: [[BLOCK:%.*]] = bitcast
- // CHECK-NEXT: [[T0:%.*]] = load i8** [[STRONG]]
- // CHECK-NEXT: store i8* [[T0]], i8** [[TEMP]]
+ // CHECK-NEXT: [[V:%.*]] = load i8** [[STRONG]]
+ // CHECK-NEXT: store i8* [[V]], i8** [[TEMP]]
// CHECK-NEXT: [[F0:%.*]] = load i8**
// CHECK-NEXT: [[F1:%.*]] = bitcast i8* [[F0]] to void (i8*, i8**)*
// CHECK-NEXT: call void [[F1]](i8* [[BLOCK]], i8** [[TEMP]])
// CHECK-NEXT: [[T0:%.*]] = load i8** [[TEMP]]
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
+ // CHECK-NEXT: call void (...)* @clang.arc.use(i8* [[V]]) [[NUW]]
// CHECK-NEXT: [[T2:%.*]] = load i8** [[STRONG]]
// CHECK-NEXT: store i8* [[T1]], i8** [[STRONG]]
// CHECK-NEXT: call void @objc_release(i8* [[T2]])
@@ -111,8 +112,8 @@ void test4(void) {
// CHECK: [[VAR:%.*]] = alloca [[BYREF_T:%.*]],
// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
// CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 2
- // 0x02000000 - has copy/dispose helpers
- // CHECK-NEXT: store i32 33554432, i32* [[T0]]
+ // 0x02000000 - has copy/dispose helpers strong
+ // CHECK-NEXT: store i32 838860800, i32* [[T0]]
// CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
// CHECK-NEXT: [[T0:%.*]] = call i8* @test4_source()
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
@@ -127,7 +128,7 @@ void test4(void) {
// CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
// CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]]
// CHECK-NEXT: call void @objc_release(i8* [[T0]])
- // CHECK-NEXT: ret void
+ // CHECK: ret void
// CHECK: define internal void @__Block_byref_object_copy_
// CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
@@ -190,8 +191,8 @@ void test6(void) {
// CHECK: [[VAR:%.*]] = alloca [[BYREF_T:%.*]],
// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
// CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 2
- // 0x02000000 - has copy/dispose helpers
- // CHECK-NEXT: store i32 33554432, i32* [[T0]]
+ // 0x02000000 - has copy/dispose helpers weak
+ // CHECK-NEXT: store i32 1107296256, i32* [[T0]]
// CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
// CHECK-NEXT: [[T0:%.*]] = call i8* @test6_source()
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
@@ -206,7 +207,7 @@ void test6(void) {
// CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
// CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
// CHECK-NEXT: call void @objc_destroyWeak(i8** [[SLOT]])
- // CHECK-NEXT: ret void
+ // CHECK: ret void
// CHECK: define internal void @__Block_byref_object_copy_
// CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
@@ -250,18 +251,19 @@ void test7(void) {
// 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: [[T0:%.*]] = call i8* @objc_loadWeakRetained(i8** [[VAR]])
// CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T0]])
// CHECK: call void @test7_helper(
// CHECK-NEXT: call void @objc_destroyWeak(i8** {{%.*}})
// CHECK-NEXT: call void @objc_destroyWeak(i8** [[VAR]])
- // CHECK-NEXT: ret void
+ // CHECK: ret void
// CHECK: define internal void @__test7_block_invoke
// CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* {{%.*}}, i32 0, i32 5
- // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_loadWeak(i8** [[SLOT]])
+ // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_loadWeakRetained(i8** [[SLOT]])
// CHECK-NEXT: call void @test7_consume(i8* [[T0]])
- // CHECK-NEXT: ret void
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]])
+ // CHECK: ret void
// CHECK: define internal void @__copy_helper_block_
// CHECK: getelementptr
@@ -294,7 +296,7 @@ void test7(void) {
// CHECK-NEXT: [[T1:%.*]] = load [[TEST8]]** [[D0]]
// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST8]]* [[T1]] to i8*
// CHECK-NEXT: call void @objc_release(i8* [[T2]])
-// CHECK-NEXT: ret void
+// CHECK: ret void
extern void test8_helper(void (^)(void));
test8_helper(^{ (void) self; });
@@ -313,7 +315,7 @@ id test9(void) {
// CHECK: load i8** getelementptr
// CHECK-NEXT: bitcast i8*
// CHECK-NEXT: call i8*
-// CHECK-NEXT: call i8* @objc_autoreleaseReturnValue
+// CHECK-NEXT: tail call i8* @objc_autoreleaseReturnValue
// CHECK-NEXT: ret i8*
// CHECK: call i8* @test9_produce()
@@ -352,7 +354,7 @@ void test10a(void) {
// CHECK-NEXT: [[T1:%.*]] = load void ()** [[SLOT]]
// CHECK-NEXT: [[T2:%.*]] = bitcast void ()* [[T1]] to i8*
// CHECK-NEXT: call void @objc_release(i8* [[T2]])
- // CHECK-NEXT: ret void
+ // CHECK: ret void
}
// <rdar://problem/10402698>: do this copy and dispose with
@@ -372,7 +374,7 @@ void test10a(void) {
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]])
// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()*
// CHECK-NEXT: store void ()* [[T3]], void ()** [[D2]], align 8
-// CHECK-NEXT: ret void
+// CHECK: ret void
// CHECK: define internal void @__Block_byref_object_dispose
// CHECK: [[T0:%.*]] = load i8** {{%.*}}
@@ -416,7 +418,7 @@ void test10b(void) {
// CHECK-NEXT: [[T1:%.*]] = load void ()** [[SLOT]]
// CHECK-NEXT: [[T2:%.*]] = bitcast void ()* [[T1]] to i8*
// CHECK-NEXT: call void @objc_release(i8* [[T2]])
- // CHECK-NEXT: ret void
+ // CHECK: ret void
}
// rdar://problem/10088932
@@ -436,7 +438,7 @@ void test11a(void) {
// CHECK-NEXT: call void @test11_helper(i8* [[T4]])
// CHECK-NEXT: [[T5:%.*]] = bitcast void ()* [[T3]] to i8*
// CHECK-NEXT: call void @objc_release(i8* [[T5]])
- // CHECK-NEXT: ret void
+ // CHECK: ret void
}
void test11b(void) {
int x;
@@ -454,7 +456,7 @@ void test11b(void) {
// CHECK-NEXT: store i8* [[T4]], i8** [[B]], align 8
// CHECK-NEXT: [[T5:%.*]] = load i8** [[B]]
// CHECK-NEXT: call void @objc_release(i8* [[T5]])
- // CHECK-NEXT: ret void
+ // CHECK: ret void
}
// rdar://problem/9979150
@@ -613,8 +615,8 @@ 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: store i8* null, i8** [[X]]
+// CHECK-UNOPT-NEXT: call void @objc_storeStrong(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]],
@@ -622,8 +624,8 @@ void test18(id x) {
// 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: call void @objc_storeStrong(i8** [[SLOTREL]], i8* null) [[NUW:#[0-9]+]]
+// CHECK-UNOPT-NEXT: call void @objc_storeStrong(i8** [[X]], i8* null) [[NUW]]
// CHECK-UNOPT-NEXT: ret void
extern void test18_helper(id (^)(void));
test18_helper(^{ return x; });
@@ -637,7 +639,7 @@ void test18(id x) {
// 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: call void @objc_storeStrong(i8** [[T1]], i8* [[T2]]) [[NUW]]
// CHECK-UNOPT-NEXT: ret void
// CHECK-UNOPT: define internal void @__destroy_helper_block_
@@ -647,3 +649,6 @@ void test18(id x) {
// CHECK-UNOPT-NEXT: call void @objc_storeStrong(i8** [[T2]], i8* null)
// CHECK-UNOPT-NEXT: ret void
}
+
+// CHECK: attributes [[NUW]] = { nounwind }
+// CHECK-UNOPT: attributes [[NUW]] = { nounwind }
diff --git a/test/CodeGenObjC/arc-captured-32bit-block-var-layout-2.m b/test/CodeGenObjC/arc-captured-32bit-block-var-layout-2.m
new file mode 100644
index 0000000..3072316
--- /dev/null
+++ b/test/CodeGenObjC/arc-captured-32bit-block-var-layout-2.m
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple i386-apple-darwin -O0 -print-ivar-layout -emit-llvm -o /dev/null %s > %t-32.layout
+// RUN: FileCheck --input-file=%t-32.layout %s
+// rdar://12184410
+// rdar://12752901
+
+@class NSString;
+extern void NSLog(NSString *format, ...);
+extern int printf(const char *, ...);
+
+int main() {
+ NSString *strong;
+ unsigned long long eightByte = 0x8001800181818181ull;
+ // Test1
+// CHECK: block variable layout: BL_NON_OBJECT_WORD:3, BL_STRONG:1, BL_OPERATOR:0
+ void (^block1)() = ^{ printf("%#llx", eightByte); NSLog(@"%@", strong); };
+
+ // Test2
+ int i = 1;
+// CHECK: block variable layout: BL_NON_OBJECT_WORD:3, BL_STRONG:1, BL_OPERATOR:0
+ void (^block2)() = ^{ printf("%#llx, %d", eightByte, i); NSLog(@"%@", strong); };
+
+ // Test3
+ char ch = 'a';
+// CHECK: block variable layout: BL_NON_OBJECT_WORD:3, BL_STRONG:1, BL_OPERATOR:0
+ void (^block3)() = ^{ printf("%c %#llx", ch, eightByte); NSLog(@"%@", strong); };
+
+ // Test4
+ unsigned long fourByte = 0x8001ul;
+// block variable layout: BL_NON_OBJECT_WORD:1, BL_STRONG:1, BL_OPERATOR:0
+// CHECK: Inline instruction for block variable layout: 0x0100
+ void (^block4)() = ^{ printf("%c %#lx", ch, fourByte); NSLog(@"%@", strong); };
+
+ // Test5
+// CHECK: block variable layout: BL_NON_OBJECT_WORD:3, BL_STRONG:1, BL_OPERATOR:0
+ void (^block5)() = ^{ NSLog(@"%@", strong); printf("%c %#llx", ch, eightByte); };
+
+ // Test6
+// CHECK: block variable layout: BL_OPERATOR:0
+ void (^block6)() = ^{ printf("%#llx", eightByte); };
+}
+
+/**
+struct __block_literal_generic { // 32bytes (64bit) and 20 bytes (32bit).
+0 void *__isa;
+4 int __flags;
+8 int __reserved;
+12 void (*__invoke)(void *);
+16 struct __block_descriptor *__descriptor;
+};
+*/
diff --git a/test/CodeGenObjC/arc-captured-32bit-block-var-layout.m b/test/CodeGenObjC/arc-captured-32bit-block-var-layout.m
index 6c72138..7ecdb4b 100644
--- a/test/CodeGenObjC/arc-captured-32bit-block-var-layout.m
+++ b/test/CodeGenObjC/arc-captured-32bit-block-var-layout.m
@@ -1,6 +1,7 @@
-// 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
+// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple i386-apple-darwin -O0 -print-ivar-layout -emit-llvm -o /dev/null %s > %t-32.layout
+// RUN: FileCheck --input-file=%t-32.layout %s
// rdar://12184410
+// rdar://12752901
void x(id y) {}
void y(int a) {}
@@ -32,8 +33,7 @@ void f() {
// 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"
+// CHECK: Inline instruction for block variable layout: 0x0320
void (^b)() = ^{
byref_int = sh + ch+ch1+ch2 ;
x(bar);
@@ -44,8 +44,7 @@ void f() {
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"
+// CHECK: Inline instruction for block variable layout: 0x0331
void (^c)() = ^{
byref_int = sh + ch+ch1+ch2 ;
x(bar);
@@ -66,8 +65,7 @@ void g() {
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"
+// CHECK: Inline instruction for block variable layout: 0x0401
void (^c)() = ^{
int j = i + bletch;
x(foo);
@@ -112,7 +110,7 @@ void h() {
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"
+// CHECK: block variable layout: BL_BYREF:1, BL_NON_OBJECT_WORD:1, BL_UNRETAINED:1, BL_NON_OBJECT_WORD:1, BL_UNRETAINED:1, BL_OPERATOR:0
void (^c)() = ^{
x(s2.ui.o1);
x(u2.o1);
@@ -127,8 +125,7 @@ void arr1() {
__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"
+// CHECK: block variable layout: BL_UNRETAINED:4, BL_OPERATOR:0
void (^c)() = ^{
x(imported_s.unsafe_unretained_var[2]);
};
@@ -143,8 +140,7 @@ void arr2() {
__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"
+// CHECK: block variable layout: BL_NON_OBJECT_WORD:1, BL_UNRETAINED:4, BL_OPERATOR:0
void (^c)() = ^{
x(imported_s.unsafe_unretained_var[2]);
};
@@ -159,8 +155,7 @@ void arr3() {
__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
+// CHECK: block variable layout: BL_OPERATOR:0
void (^c)() = ^{
int i = imported_s.a;
};
@@ -186,15 +181,7 @@ void arr4() {
} 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]
+// CHECK: block variable layout: BL_UNRETAINED:3, BL_NON_OBJECT_WORD:1, BL_UNRETAINED:1, BL_NON_OBJECT_WORD:1, BL_UNRETAINED:1, BL_NON_OBJECT_WORD:1, BL_UNRETAINED:1, BL_NON_OBJECT_WORD:1, BL_UNRETAINED:1, BL_OPERATOR:0
void (^c)() = ^{
id i = captured_s.f0.s_f1;
};
@@ -212,8 +199,7 @@ void bf1() {
int flag4: 24;
} s;
-// block variable layout: BL_OPERATOR:0
-// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+// CHECK: block variable layout: BL_OPERATOR:0
int (^c)() = ^{
return s.flag;
};
@@ -226,8 +212,7 @@ void bf2() {
int flag : 1;
} s;
-// block variable layout: BL_OPERATOR:0
-// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+// CHECK: block variable layout: BL_OPERATOR:0
int (^c)() = ^{
return s.flag;
};
@@ -258,8 +243,7 @@ void bf3() {
unsigned int _filler : 32;
} _flags;
-// block variable layout: BL_OPERATOR:0
-// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+// CHECK: block variable layout: BL_OPERATOR:0
unsigned char (^c)() = ^{
return _flags._draggedNodesAreDeletable;
};
@@ -294,8 +278,7 @@ void bf4() {
unsigned int _filler : 32;
} _flags;
-// block variable layout: BL_OPERATOR:0
-// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+// CHECK: block variable layout: BL_OPERATOR:0
unsigned char (^c)() = ^{
return _flags._draggedNodesAreDeletable;
};
@@ -313,8 +296,7 @@ void bf5() {
unsigned char flag1 : 1;
} _flags;
-// block variable layout: BL_OPERATOR:0
-// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+// CHECK: block variable layout: BL_OPERATOR:0
unsigned char (^c)() = ^{
return _flags.flag;
};
@@ -331,8 +313,7 @@ void bf6() {
unsigned char flag1 : 1;
} _flags;
-// block variable layout: BL_OPERATOR:0
-// CHECK: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+// CHECK: block variable layout: BL_OPERATOR:0
unsigned char (^c)() = ^{
return _flags.flag;
};
@@ -348,8 +329,7 @@ void Test7() {
__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"
+// CHECK: block variable layout: BL_STRONG:1, BL_WEAK:16, BL_OPERATOR:0
void (^b)() = ^{
x(bar);
x(wid1);
@@ -384,8 +364,7 @@ __weak id wid;
__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]
+// CHECK: block variable layout: BL_STRONG:1, BL_WEAK:16, BL_WEAK:16, BL_WEAK:1, BL_OPERATOR:0
void (^b)() = ^{
x(bar);
x(wid1);
diff --git a/test/CodeGenObjC/arc-captured-block-var-inlined-layout.m b/test/CodeGenObjC/arc-captured-block-var-inlined-layout.m
index b930737..28c5bb4 100644
--- a/test/CodeGenObjC/arc-captured-block-var-inlined-layout.m
+++ b/test/CodeGenObjC/arc-captured-block-var-inlined-layout.m
@@ -1,5 +1,7 @@
-// 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
+// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple x86_64-apple-darwin -O0 -print-ivar-layout -emit-llvm -o /dev/null %s > %t-64.layout
+// RUN: FileCheck --input-file=%t-64.layout %s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple i386-apple-darwin -O0 -print-ivar-layout -emit-llvm -o /dev/null %s > %t-32.layout
+// RUN: FileCheck -check-prefix=CHECK-i386 --input-file=%t-32.layout %s
// rdar://12184410
void x(id y) {}
@@ -15,25 +17,22 @@ void f() {
__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 }
+// CHECK: Inline instruction for block variable layout: 0x0100
+// CHECK-i386: Inline instruction for block variable layout: 0x0100
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 }
+// CHECK: Inline instruction for block variable layout: 0x0210
+// CHECK-i386: Inline instruction for block variable layout: 0x0210
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 }
+// CHECK: Inline instruction for block variable layout: 0x0230
+// CHECK-i386: Inline instruction for block variable layout: 0x0230
void (^d)() = ^{
x(bar);
x(baz);
@@ -42,9 +41,8 @@ void f() {
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 }
+// CHECK: Inline instruction for block variable layout: 0x0231
+// CHECK-i386: Inline instruction for block variable layout: 0x0231
__weak id wid;
id (^e)() = ^{
x(bar);
@@ -55,9 +53,8 @@ void f() {
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 }
+// CHECK: Inline instruction for block variable layout: 0x0235
+// CHECK-i386: Inline instruction for block variable layout: 0x0235
__weak id wid1, wid2, wid3, wid4;
id (^f)() = ^{
x(bar);
@@ -72,9 +69,8 @@ void f() {
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 }
+// CHECK: Inline instruction for block variable layout: 0x035
+// CHECK-i386: Inline instruction for block variable layout: 0x035
id (^g)() = ^{
byref_int = 1;
bl_var1 = 0;
@@ -86,27 +82,41 @@ void f() {
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 }
+// CHECK: Inline instruction for block variable layout: 0x01
+// CHECK-i386: Inline instruction for block variable layout: 0x01
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 }
+// CHECK: Inline instruction for block variable layout: 0x020
+// CHECK-i386: Inline instruction for block variable layout: 0x020
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 }
+// CHECK: Inline instruction for block variable layout: 0x0102
+// CHECK-i386: Inline instruction for block variable layout: 0x0102
void (^jj)() = ^{
x(bar);
x(wid1);
x(wid2);
};
}
+
+// rdar://12752901
+@class NSString;
+extern void NSLog(NSString *format, ...);
+typedef void (^dispatch_block_t)(void);
+int main() {
+ __strong NSString *s1 = 0;
+ __strong NSString *s2 = 0;
+ __weak NSString *w1 = 0;
+
+
+// CHECK: Inline instruction for block variable layout: 0x0201
+// CHECK-i386: Inline instruction for block variable layout: 0x0201
+ dispatch_block_t block2 = ^{
+ NSLog(@"%@, %@, %@", s1, w1, s2);
+ };
+}
diff --git a/test/CodeGenObjC/arc-captured-block-var-layout.m b/test/CodeGenObjC/arc-captured-block-var-layout.m
index 77f042e..bc20307 100644
--- a/test/CodeGenObjC/arc-captured-block-var-layout.m
+++ b/test/CodeGenObjC/arc-captured-block-var-layout.m
@@ -1,6 +1,7 @@
-// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple x86_64-apple-darwin -O0 -emit-llvm %s -o %t-64.s
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple x86_64-apple-darwin -O0 -print-ivar-layout -emit-llvm -o /dev/null %s > %t-64.layout
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.layout %s
// rdar://12184410
+// rdar://12752901
void x(id y) {}
void y(int a) {}
@@ -32,8 +33,8 @@ void f() {
// 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"
+// Inline instruction for block variable layout: 0x0320 (3 strong 2 byref)
+// CHECK-LP64: Inline instruction for block variable layout: 0x0320
void (^b)() = ^{
byref_int = sh + ch+ch1+ch2 ;
x(bar);
@@ -44,8 +45,8 @@ void f() {
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"
+// Inline instruction for block variable layout: 0x0331 (3 strong 3 byref 1 weak)
+// CHECK-LP64: Inline instruction for block variable layout: 0x0331
void (^c)() = ^{
byref_int = sh + ch+ch1+ch2 ;
x(bar);
@@ -66,8 +67,8 @@ void g() {
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"
+// Inline instruction for block variable layout: 0x0401 (4 strong 0 byref 1 weak)
+// CHECK-LP64: Inline instruction for block variable layout: 0x0401
void (^c)() = ^{
int j = i + bletch;
x(foo);
@@ -108,11 +109,7 @@ void h() {
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"
+// CHECK-LP64: block variable layout: BL_BYREF:1, BL_NON_OBJECT_WORD:1, BL_UNRETAINED:1, BL_NON_OBJECT_WORD:1, BL_UNRETAINED:1, BL_OPERATOR:0
void (^c)() = ^{
x(s2.ui.o1);
x(u2.o1);
@@ -127,8 +124,7 @@ void arr1() {
__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"
+// CHECK-LP64: block variable layout: BL_UNRETAINED:4, BL_OPERATOR:0
void (^c)() = ^{
x(imported_s.unsafe_unretained_var[2]);
};
@@ -143,8 +139,7 @@ void arr2() {
__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"
+// CHECK-LP64: block variable layout: BL_NON_OBJECT_WORD:1, BL_UNRETAINED:4, BL_OPERATOR:0
void (^c)() = ^{
x(imported_s.unsafe_unretained_var[2]);
};
@@ -159,8 +154,7 @@ void arr3() {
__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
+// CHECK-LP64: block variable layout: BL_OPERATOR:0
void (^c)() = ^{
int i = imported_s.a;
};
@@ -186,15 +180,7 @@ void arr4() {
} 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]
+// CHECK-LP64: block variable layout: BL_UNRETAINED:3, BL_NON_OBJECT_WORD:1, BL_UNRETAINED:1, BL_NON_OBJECT_WORD:1, BL_UNRETAINED:1, BL_NON_OBJECT_WORD:1, BL_UNRETAINED:1, BL_NON_OBJECT_WORD:1, BL_UNRETAINED:1, BL_OPERATOR:0
void (^c)() = ^{
id i = captured_s.f0.s_f1;
};
@@ -212,8 +198,7 @@ void bf1() {
int flag4: 24;
} s;
-// block variable layout: BL_OPERATOR:0
-// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+// CHECK-LP64: block variable layout: BL_OPERATOR:0
int (^c)() = ^{
return s.flag;
};
@@ -226,8 +211,7 @@ void bf2() {
int flag : 1;
} s;
-// block variable layout: BL_OPERATOR:0
-// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+// CHECK-LP64: block variable layout: BL_OPERATOR:0
int (^c)() = ^{
return s.flag;
};
@@ -258,8 +242,7 @@ void bf3() {
unsigned int _filler : 32;
} _flags;
-// block variable layout: BL_OPERATOR:0
-// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+// CHECK-LP64: block variable layout: BL_OPERATOR:0
unsigned char (^c)() = ^{
return _flags._draggedNodesAreDeletable;
};
@@ -294,8 +277,7 @@ void bf4() {
unsigned int _filler : 32;
} _flags;
-// block variable layout: BL_OPERATOR:0
-// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+// CHECK-LP64: block variable layout: BL_OPERATOR:0
unsigned char (^c)() = ^{
return _flags._draggedNodesAreDeletable;
};
@@ -313,8 +295,7 @@ void bf5() {
unsigned char flag1 : 1;
} _flags;
-// block variable layout: BL_OPERATOR:0
-// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+// CHECK-LP64: block variable layout: BL_OPERATOR:0
unsigned char (^c)() = ^{
return _flags.flag;
};
@@ -331,8 +312,7 @@ void bf6() {
unsigned char flag1 : 1;
} _flags;
-// block variable layout: BL_OPERATOR:0
-// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [1 x i8] zeroinitializer
+// CHECK-LP64: block variable layout: BL_OPERATOR:0
unsigned char (^c)() = ^{
return _flags.flag;
};
@@ -348,8 +328,7 @@ void Test7() {
__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"
+// CHECK-LP64: block variable layout: BL_STRONG:1, BL_WEAK:16, BL_OPERATOR:0
void (^b)() = ^{
x(bar);
x(wid1);
@@ -384,8 +363,7 @@ __weak id wid;
__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]
+// CHECK-LP64: block variable layout: BL_STRONG:1, BL_WEAK:16, BL_WEAK:16, BL_WEAK:1, BL_OPERATOR:0
void (^b)() = ^{
x(bar);
x(wid1);
diff --git a/test/CodeGenObjC/arc-exceptions.m b/test/CodeGenObjC/arc-exceptions.m
index 63945e3..aa3d2f3 100644
--- a/test/CodeGenObjC/arc-exceptions.m
+++ b/test/CodeGenObjC/arc-exceptions.m
@@ -17,12 +17,12 @@ void test0(void) {
// CHECK: [[T0:%.*]] = call i8* @objc_begin_catch(
// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[ETY]]*
// CHECK-NEXT: [[T2:%.*]] = bitcast [[ETY]]* [[T1]] to i8*
-// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]]) nounwind
+// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]]) [[NUW:#[0-9]+]]
// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[ETY]]*
// CHECK-NEXT: store [[ETY]]* [[T4]], [[ETY]]** [[E]]
// 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
+// CHECK-NEXT: call void @objc_storeStrong(i8** [[T0]], i8* null) [[NUW]]
+// CHECK-NEXT: call void @objc_end_catch() [[NUW]]
void test1_helper(void);
void test1(void) {
@@ -38,7 +38,9 @@ void test1(void) {
// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[ETY]]*
// CHECK-NEXT: [[T2:%.*]] = bitcast [[ETY]]** [[E]] to i8**
// CHECK-NEXT: [[T3:%.*]] = bitcast [[ETY]]* [[T1]] to i8*
-// CHECK-NEXT: call i8* @objc_initWeak(i8** [[T2]], i8* [[T3]]) nounwind
+// CHECK-NEXT: call i8* @objc_initWeak(i8** [[T2]], i8* [[T3]]) [[NUW]]
// CHECK-NEXT: [[T0:%.*]] = bitcast [[ETY]]** [[E]] to i8**
-// CHECK-NEXT: call void @objc_destroyWeak(i8** [[T0]]) nounwind
-// CHECK-NEXT: call void @objc_end_catch() nounwind
+// CHECK-NEXT: call void @objc_destroyWeak(i8** [[T0]]) [[NUW]]
+// CHECK-NEXT: call void @objc_end_catch() [[NUW]]
+
+// CHECK: attributes [[NUW]] = { nounwind }
diff --git a/test/CodeGenObjC/arc-foreach.m b/test/CodeGenObjC/arc-foreach.m
index b8d2d30..176b28d 100644
--- a/test/CodeGenObjC/arc-foreach.m
+++ b/test/CodeGenObjC/arc-foreach.m
@@ -30,10 +30,10 @@ void test0(NSArray *array) {
// CHECK-LP64-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
// Initialize 'array'.
-// CHECK-LP64-NEXT: [[T0:%.*]] = bitcast [[ARRAY_T:%.*]]* {{%.*}} to i8*
-// CHECK-LP64-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
-// CHECK-LP64-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to [[ARRAY_T]]*
-// CHECK-LP64-NEXT: store [[ARRAY_T]]* [[T2]], [[ARRAY_T]]** [[ARRAY]], align 8
+// CHECK-LP64-NEXT: store [[ARRAY_T]]* null, [[ARRAY_T]]** [[ARRAY]]
+// CHECK-LP64-NEXT: [[ZERO:%.*]] = bitcast [[ARRAY_T]]** [[ARRAY]] to i8**
+// CHECK-LP64-NEXT: [[ONE:%.*]] = bitcast [[ARRAY_T]]* {{%.*}} to i8*
+// CHECK-LP64-NEXT: call void @objc_storeStrong(i8** [[ZERO]], i8* [[ONE]]) [[NUW:#[0-9]+]]
// Initialize the fast enumaration state.
// CHECK-LP64-NEXT: [[T0:%.*]] = bitcast [[STATE_T]]* [[STATE]] to i8*
@@ -84,7 +84,8 @@ void test0(NSArray *array) {
// CHECK-LP64: define internal void @__test0_block_invoke
// CHECK-LP64: [[BLOCK:%.*]] = bitcast i8* {{%.*}} to [[BLOCK_T]]*
-// CHECK-LP64-NEXT: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+// CHECK-LP64-NOT: ret
+// CHECK-LP64: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
// CHECK-LP64-NEXT: [[T2:%.*]] = load i8** [[T0]], align 8
// CHECK-LP64-NEXT: call void @use(i8* [[T2]])
@@ -109,8 +110,9 @@ void test1(NSArray *array) {
// CHECK-LP64: [[D0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
// CHECK-LP64: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
-// CHECK-LP64-NEXT: [[T1:%.*]] = call i8* @objc_loadWeak(i8** [[X]])
+// CHECK-LP64-NEXT: [[T1:%.*]] = call i8* @objc_loadWeakRetained(i8** [[X]])
// CHECK-LP64-NEXT: call i8* @objc_initWeak(i8** [[T0]], i8* [[T1]])
+// CHECK-LP64-NEXT: call void @objc_release(i8* [[T1]])
// CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to
// CHECK-LP64: call void @use_block
// CHECK-LP64-NEXT: call void @objc_destroyWeak(i8** [[D0]])
@@ -169,3 +171,5 @@ void test3(NSArray *array) {
// CHECK-LP64-NEXT: call void @use(i8* [[T0]])
// CHECK-LP64-NEXT: br label [[L]]
}
+
+// CHECK: attributes [[NUW]] = { nounwind }
diff --git a/test/CodeGenObjC/arc-literals.m b/test/CodeGenObjC/arc-literals.m
index 203c2ad..78c5d9d 100644
--- a/test/CodeGenObjC/arc-literals.m
+++ b/test/CodeGenObjC/arc-literals.m
@@ -35,18 +35,28 @@ void test_numeric() {
// CHECK: define void @test_array
void test_array(id a, id b) {
+ // CHECK: [[A:%.*]] = alloca i8*,
+ // CHECK: [[B:%.*]] = alloca i8*,
+
// Retaining parameters
// CHECK: call i8* @objc_retain(i8*
// CHECK: call i8* @objc_retain(i8*
// Constructing the array
- // CHECK: getelementptr inbounds [2 x i8*]* [[OBJECTS:%[A-Za-z0-9]+]], i32 0, i32 0
- // CHECK: store i8*
- // CHECK: getelementptr inbounds [2 x i8*]* [[OBJECTS]], i32 0, i32 1
- // CHECK: store i8*
-
- // CHECK: {{call i8*.*objc_msgSend.*i64 2}}
- // CHECK: call i8* @objc_retainAutoreleasedReturnValue
+ // CHECK: [[T0:%.*]] = getelementptr inbounds [2 x i8*]* [[OBJECTS:%[A-Za-z0-9]+]], i32 0, i32 0
+ // CHECK-NEXT: [[V0:%.*]] = load i8** [[A]],
+ // CHECK-NEXT: store i8* [[V0]], i8** [[T0]]
+ // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [2 x i8*]* [[OBJECTS]], i32 0, i32 1
+ // CHECK-NEXT: [[V1:%.*]] = load i8** [[B]],
+ // CHECK-NEXT: store i8* [[V1]], i8** [[T0]]
+
+ // CHECK-NEXT: [[T0:%.*]] = load [[CLASS_T:%.*]]** @"\01L_OBJC_CLASSLIST
+ // CHECK-NEXT: [[SEL:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[CLASS_T]]* [[T0]] to i8*
+ // CHECK-NEXT: [[T2:%.*]] = bitcast [2 x i8*]* [[OBJECTS]] to i8**
+ // CHECK-NEXT: [[T3:%.*]] = call i8* bitcast ({{.*@objc_msgSend.*}})(i8* [[T1]], i8* [[SEL]], i8** [[T2]], i64 2)
+ // CHECK-NEXT: [[T4:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T3]])
+ // CHECK: call void (...)* @clang.arc.use(i8* [[V0]], i8* [[V1]])
id arr = @[a, b];
// CHECK: call void @objc_release
@@ -57,6 +67,11 @@ void test_array(id a, id b) {
// CHECK: define void @test_dictionary
void test_dictionary(id k1, id o1, id k2, id o2) {
+ // CHECK: [[K1:%.*]] = alloca i8*,
+ // CHECK: [[O1:%.*]] = alloca i8*,
+ // CHECK: [[K2:%.*]] = alloca i8*,
+ // CHECK: [[O2:%.*]] = alloca i8*,
+
// Retaining parameters
// CHECK: call i8* @objc_retain(i8*
// CHECK: call i8* @objc_retain(i8*
@@ -64,18 +79,29 @@ void test_dictionary(id k1, id o1, id k2, id o2) {
// CHECK: call i8* @objc_retain(i8*
// Constructing the arrays
- // CHECK: getelementptr inbounds [2 x i8*]* [[KEYS:%[A-Za-z0-9]+]], i32 0, i32 0
- // CHECK: store i8*
- // CHECK: getelementptr inbounds [2 x i8*]* [[OBJECTS:%[A-Za-z0-9]+]], i32 0, i32 0
- // CHECK: store i8*
- // CHECK: getelementptr inbounds [2 x i8*]* [[KEYS]], i32 0, i32 1
- // CHECK: store i8*
- // CHECK: getelementptr inbounds [2 x i8*]* [[OBJECTS]], i32 0, i32 1
- // CHECK: store i8*
+ // CHECK: [[T0:%.*]] = getelementptr inbounds [2 x i8*]* [[KEYS:%[A-Za-z0-9]+]], i32 0, i32 0
+ // CHECK-NEXT: [[V0:%.*]] = load i8** [[K1]],
+ // CHECK-NEXT: store i8* [[V0]], i8** [[T0]]
+ // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [2 x i8*]* [[OBJECTS:%[A-Za-z0-9]+]], i32 0, i32 0
+ // CHECK-NEXT: [[V1:%.*]] = load i8** [[O1]],
+ // CHECK-NEXT: store i8* [[V1]], i8** [[T0]]
+ // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [2 x i8*]* [[KEYS]], i32 0, i32 1
+ // CHECK-NEXT: [[V2:%.*]] = load i8** [[K2]],
+ // CHECK-NEXT: store i8* [[V2]], i8** [[T0]]
+ // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [2 x i8*]* [[OBJECTS]], i32 0, i32 1
+ // CHECK-NEXT: [[V3:%.*]] = load i8** [[O2]],
+ // CHECK-NEXT: store i8* [[V3]], i8** [[T0]]
// Constructing the dictionary
- // CHECK: {{call i8.*@objc_msgSend}}
- // CHECK: call i8* @objc_retainAutoreleasedReturnValue
+ // CHECK-NEXT: [[T0:%.*]] = load [[CLASS_T:%.*]]** @"\01L_OBJC_CLASSLIST
+ // CHECK-NEXT: [[SEL:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[CLASS_T]]* [[T0]] to i8*
+ // CHECK-NEXT: [[T2:%.*]] = bitcast [2 x i8*]* [[OBJECTS]] to i8**
+ // CHECK-NEXT: [[T3:%.*]] = bitcast [2 x i8*]* [[KEYS]] to i8**
+ // CHECK-NEXT: [[T4:%.*]] = call i8* bitcast ({{.*@objc_msgSend.*}})(i8* [[T1]], i8* [[SEL]], i8** [[T2]], i8** [[T3]], i64 2)
+ // CHECK-NEXT: [[T5:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T4]])
+ // CHECK-NEXT: call void (...)* @clang.arc.use(i8* [[V0]], i8* [[V1]], i8* [[V2]], i8* [[V3]])
+
id dict = @{ k1 : o1, k2 : o2 };
// CHECK: call void @objc_release
@@ -98,19 +124,36 @@ void test_property(B *b) {
// Retain parameter
// CHECK: call i8* @objc_retain
+ // CHECK: [[T0:%.*]] = getelementptr inbounds [1 x i8*]* [[OBJECTS:%.*]], i32 0, i32 0
+
// Invoke 'prop'
- // CHECK: load i8** @"\01L_OBJC_SELECTOR_REFERENCES
- // CHECK: {{call.*@objc_msgSend}}
- // CHECK: call i8* @objc_retainAutoreleasedReturnValue
+ // CHECK: [[SEL:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES
+ // CHECK-NEXT: [[T1:%.*]] = bitcast
+ // CHECK-NEXT: [[T2:%.*]] = call [[B:%.*]]* bitcast ({{.*}} @objc_msgSend to {{.*}})(i8* [[T1]], i8* [[SEL]])
+ // CHECK-NEXT: [[T3:%.*]] = bitcast [[B]]* [[T2]] to i8*
+ // CHECK-NEXT: [[T4:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T3]])
+ // CHECK-NEXT: [[V0:%.*]] = bitcast i8* [[T4]] to [[B]]*
+ // CHECK-NEXT: [[V1:%.*]] = bitcast [[B]]* [[V0]] to i8*
+
+ // Store to array.
+ // CHECK-NEXT: store i8* [[V1]], i8** [[T0]]
// Invoke arrayWithObjects:count:
- // CHECK: load i8** @"\01L_OBJC_SELECTOR_REFERENCES
- // CHECK: {{call.*objc_msgSend}}
- // CHECK: call i8* @objc_retainAutoreleasedReturnValue
+ // CHECK-NEXT: [[T0:%.*]] = load [[CLASS_T]]** @"\01L_OBJC_CLASSLIST
+ // CHECK-NEXT: [[SEL:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[CLASS_T]]* [[T0]] to i8*
+ // CHECK-NEXT: [[T2:%.*]] = bitcast [1 x i8*]* [[OBJECTS]] to i8**
+ // CHECK-NEXT: [[T3:%.*]] = call i8* bitcast ({{.*}} @objc_msgSend to {{.*}}(i8* [[T1]], i8* [[SEL]], i8** [[T2]], i64 1)
+ // CHECK-NEXT: call i8* @objc_retainAutoreleasedReturnValue(i8* [[T3]])
+ // CHECK-NEXT: call void (...)* @clang.arc.use(i8* [[V1]])
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: bitcast
+ // CHECK-NEXT: store
id arr = @[ b.prop ];
// Release b.prop
- // CHECK: call void @objc_release
+ // CHECK-NEXT: [[T0:%.*]] = bitcast [[B]]* [[V0]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]])
// Destroy arr
// CHECK: call void @objc_release
diff --git a/test/CodeGenObjC/arc-loadweakretained-release.m b/test/CodeGenObjC/arc-loadweakretained-release.m
new file mode 100644
index 0000000..00d25fa
--- /dev/null
+++ b/test/CodeGenObjC/arc-loadweakretained-release.m
@@ -0,0 +1,77 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck %s
+// rdar://10849570
+
+@interface NSObject @end
+
+@interface SomeClass : NSObject
+- (id) init;
+@end
+
+@implementation SomeClass
+- (void)foo {
+}
+- (id) init {
+ return 0;
+}
++ alloc { return 0; }
+@end
+
+int main (int argc, const char * argv[]) {
+ @autoreleasepool {
+ SomeClass *objPtr1 = [[SomeClass alloc] init];
+ __weak SomeClass *weakRef = objPtr1;
+
+ [weakRef foo];
+
+ objPtr1 = (void *)0;
+ return 0;
+ }
+}
+
+// CHECK: [[SIXTEEN:%.*]] = call i8* @objc_loadWeakRetained(i8** {{%.*}})
+// CHECK-NEXT: [[SEVENTEEN:%.*]] = bitcast i8* [[SIXTEEN]] to {{%.*}}
+// CHECK-NEXT: [[EIGHTEEN:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_6"
+// CHECK-NEXT: [[NINETEEN:%.*]] = bitcast %0* [[SEVENTEEN]] to i8*
+// CHECK-NEXT: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
+// CHECK-NEXT: [[TWENTY:%.*]] = bitcast %0* [[SEVENTEEN]] to i8*
+// CHECK-NEXT: call void @objc_release(i8* [[TWENTY]])
+
+void test1(int cond) {
+ extern void test34_sink(id *);
+ __weak id weak;
+ test34_sink(cond ? &weak : 0);
+}
+
+// CHECK: define void @test1(
+// CHECK: [[CONDADDR:%.*]] = alloca i32
+// CHECK-NEXT: [[WEAK:%.*]] = alloca i8*
+// CHECK-NEXT: [[INCRTEMP:%.*]] = alloca i8*
+// CHECK-NEXT: [[CONDCLEANUPSAVE:%.*]] = alloca i8*
+// CHECK-NEXT: [[CONDCLEANUP:%.*]] = alloca i1
+// CHECK-NEXT: store i32
+// CHECK-NEXT: store i8* null, i8** [[WEAK]]
+// CHECK: [[COND1:%.*]] = phi i8**
+// CHECK-NEXT: [[ICRISNULL:%.*]] = icmp eq i8** [[COND1]], null
+// CHECK-NEXT: [[ICRARGUMENT:%.*]] = select i1 [[ICRISNULL]], i8** null, i8** [[INCRTEMP]]
+// CHECK-NEXT: store i1 false, i1* [[CONDCLEANUP]]
+// CHECK-NEXT: br i1 [[ICRISNULL]], label [[ICRCONT:%.*]], label [[ICRCOPY:%.*]]
+// CHECK: [[ONE:%.*]] = call i8* @objc_loadWeakRetained(
+// CHECK-NEXT: store i8* [[ONE]], i8** [[CONDCLEANUPSAVE]]
+// CHECK-NEXT: store i1 true, i1* [[CONDCLEANUP]]
+// CHECK-NEXT: store i8* [[ONE]], i8** [[INCRTEMP]]
+// CHECK-NEXT: br label
+
+// CHECK: call void @test34_sink(
+// CHECK-NEXT: [[ICRISNULL1:%.*]] = icmp eq i8** [[COND1]], null
+// CHECK-NEXT: br i1 [[ICRISNULL1]], label [[ICRDONE:%.*]], label [[ICRWRITEBACK:%.*]]
+// CHECK: [[TWO:%.*]] = load i8** [[INCRTEMP]]
+// CHECK-NEXT: [[THREE:%.*]] = call i8* @objc_storeWeak(
+// CHECK-NEXT br label [[ICRDONE]]
+// CHECK: [[CLEANUPISACTIVE:%.*]] = load i1* [[CONDCLEANUP]]
+// CHECK-NEXT: br i1 [[CLEANUPISACTIVE]], label [[CLEASNUPACTION:%.*]], label [[CLEANUPDONE:%.*]]
+
+// CHECK: [[FOUR:%.*]] = load i8** [[CONDCLEANUPSAVE]]
+// CHECK-NEXT: call void @objc_release(i8* [[FOUR]])
+// CHECK-NEXT: br label
+// CHECK: call void @objc_destroyWeak(i8** [[WEAK]])
+// CHECK-NEXT: ret void
diff --git a/test/CodeGenObjC/arc-no-arc-exceptions.m b/test/CodeGenObjC/arc-no-arc-exceptions.m
index 7ae061f..008c848 100644
--- a/test/CodeGenObjC/arc-no-arc-exceptions.m
+++ b/test/CodeGenObjC/arc-no-arc-exceptions.m
@@ -10,7 +10,7 @@ void not(void) __attribute__((nothrow));
// CHECK: define void @test0(
// CHECK: call void @thrower(), !clang.arc.no_objc_arc_exceptions !
-// CHECK: call void @not() nounwind, !clang.arc.no_objc_arc_exceptions !
+// CHECK: call void @not() [[NUW:#[0-9]+]], !clang.arc.no_objc_arc_exceptions !
// NO-METADATA: define void @test0(
// NO-METADATA-NOT: !clang.arc.no_objc_arc_exceptions
// NO-METADATA: }
@@ -21,7 +21,7 @@ void test0(void) {
// CHECK: define void @test1(
// CHECK: call void @thrower(), !clang.arc.no_objc_arc_exceptions !
-// CHECK: call void @not() nounwind, !clang.arc.no_objc_arc_exceptions !
+// CHECK: call void @not() [[NUW]], !clang.arc.no_objc_arc_exceptions !
// NO-METADATA: define void @test1(
// NO-METADATA-NOT: !clang.arc.no_objc_arc_exceptions
// NO-METADATA: }
@@ -76,3 +76,5 @@ void test4(void) {
b();
}
}
+
+// CHECK: attributes [[NUW]] = { nounwind }
diff --git a/test/CodeGenObjC/arc-precise-lifetime.m b/test/CodeGenObjC/arc-precise-lifetime.m
new file mode 100644
index 0000000..595a4f9
--- /dev/null
+++ b/test/CodeGenObjC/arc-precise-lifetime.m
@@ -0,0 +1,120 @@
+// 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
+
+#define PRECISE_LIFETIME __attribute__((objc_precise_lifetime))
+
+id test0_helper(void) __attribute__((ns_returns_retained));
+void test0() {
+ PRECISE_LIFETIME id x = test0_helper();
+ x = 0;
+ // CHECK: [[X:%.*]] = alloca i8*
+ // CHECK-NEXT: [[CALL:%.*]] = call i8* @test0_helper()
+ // CHECK-NEXT: store i8* [[CALL]], i8** [[X]]
+
+ // CHECK-NEXT: [[T1:%.*]] = load i8** [[X]]
+ // CHECK-NEXT: store i8* null, i8** [[X]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW:#[0-9]+]]
+ // CHECK-NOT: clang.imprecise_release
+
+ // CHECK-NEXT: [[T1:%.*]] = load i8** [[X]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW:#[0-9]+]]
+ // CHECK-NOT: clang.imprecise_release
+
+ // CHECK-NEXT: ret void
+}
+
+// rdar://problem/9821110
+@interface Test1
+- (char*) interior __attribute__((objc_returns_inner_pointer));
+// Should we allow this on properties?
+@end
+extern Test1 *test1_helper(void);
+
+// CHECK: define void @test1a()
+void test1a(void) {
+ // CHECK: [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
+ // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
+ // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
+ // CHECK-NEXT: store [[TEST1]]* [[T3]]
+ // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]**
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
+ // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]])
+ // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
+ // CHECK-NEXT: [[T4:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: [[T5:%.*]] = bitcast [[TEST1]]* [[T3]] to i8*
+ // CHECK-NEXT: [[T6:%.*]] = call i8* bitcast
+ // CHECK-NEXT: store i8* [[T6]], i8**
+ // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]**
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release
+ // CHECK-NEXT: ret void
+ Test1 *ptr = test1_helper();
+ char *c = [(ptr) interior];
+}
+
+// CHECK: define void @test1b()
+void test1b(void) {
+ // CHECK: [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
+ // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
+ // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
+ // CHECK-NEXT: store [[TEST1]]* [[T3]]
+ // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]**
+ // CHECK-NEXT: [[T1:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
+ // CHECK-NEXT: [[T3:%.*]] = call i8* bitcast
+ // CHECK-NEXT: store i8* [[T3]], i8**
+ // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]**
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]]
+ // CHECK-NOT: clang.imprecise_release
+ // CHECK-NEXT: ret void
+ __attribute__((objc_precise_lifetime)) Test1 *ptr = test1_helper();
+ char *c = [ptr interior];
+}
+
+@interface Test2 {
+@public
+ id ivar;
+}
+@end
+// CHECK: define void @test2(
+void test2(Test2 *x) {
+ x->ivar = 0;
+ // CHECK: [[X:%.*]] = alloca [[TEST2:%.*]]*
+ // CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST2]]* {{%.*}} to i8*
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) [[NUW]]
+ // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to [[TEST2]]*
+ // CHECK-NEXT: store [[TEST2]]* [[T2]], [[TEST2]]** [[X]],
+
+ // CHECK-NEXT: [[T0:%.*]] = load [[TEST2]]** [[X]],
+ // CHECK-NEXT: [[OFFSET:%.*]] = load i64* @"OBJC_IVAR_$_Test2.ivar"
+ // 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: [[T4:%.*]] = load i8** [[T3]],
+ // CHECK-NEXT: store i8* null, i8** [[T3]],
+ // CHECK-NEXT: call void @objc_release(i8* [[T4]]) [[NUW]]
+ // CHECK-NOT: imprecise
+
+ // CHECK-NEXT: [[T0:%.*]] = load [[TEST2]]** [[X]]
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST2]]* [[T0]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release
+
+ // CHECK-NEXT: ret void
+}
+
+// CHECK: define void @test3(i8*
+void test3(PRECISE_LIFETIME id x) {
+ // CHECK: [[X:%.*]] = alloca i8*,
+ // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retain(i8* {{%.*}}) [[NUW]]
+ // CHECK-NEXT: store i8* [[T0]], i8** [[X]],
+
+ // CHECK-NEXT: [[T0:%.*]] = load i8** [[X]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]]
+ // CHECK-NOT: imprecise_release
+
+ // CHECK-NEXT: ret void
+}
+
+// CHECK: attributes [[NUW]] = { nounwind }
diff --git a/test/CodeGenObjC/arc-property.m b/test/CodeGenObjC/arc-property.m
index db00e36..dde02d7 100644
--- a/test/CodeGenObjC/arc-property.m
+++ b/test/CodeGenObjC/arc-property.m
@@ -8,8 +8,8 @@ void test0(Test0 *t0, id value) {
t0.value = value;
}
// CHECK: define void @test0(
-// CHECK: call i8* @objc_retain(
-// CHECK: call i8* @objc_retain(
+// CHECK: call void @objc_storeStrong
+// CHECK: call void @objc_storeStrong
// CHECK: @objc_msgSend
// CHECK: call void @objc_storeStrong(
// CHECK: call void @objc_storeStrong(
@@ -62,7 +62,7 @@ static Class theGlobalClass;
// 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: call void @objc_storeStrong(i8** [[T4]], i8* [[T0]]) [[NUW:#[0-9]+]]
// CHECK-NEXT: ret void
// CHECK: define internal i8* @"\01-[Test2 theClass]"(
@@ -83,5 +83,52 @@ static Class theGlobalClass;
// 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: call void @objc_storeStrong(i8** [[T3]], i8* null) [[NUW]]
// CHECK-NEXT: ret void
+
+// rdar://13115896
+@interface Test3
+@property id copyMachine;
+@end
+
+void test3(Test3 *t) {
+ id x = t.copyMachine;
+ x = [t copyMachine];
+}
+// CHECK: define void @test3([[TEST3:%.*]]*
+// Prologue.
+// CHECK: [[T:%.*]] = alloca [[TEST3]]*,
+// CHECK-NEXT: [[X:%.*]] = alloca i8*,
+// Property access.
+// CHECK: [[T0:%.*]] = load [[TEST3]]** [[T]],
+// CHECK-NEXT: [[SEL:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST3]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = call i8* bitcast ({{.*}} @objc_msgSend to {{.*}})(i8* [[T1]], i8* [[SEL]])
+// CHECK-NEXT: store i8* [[T2]], i8** [[X]],
+// Message send.
+// CHECK-NEXT: [[T0:%.*]] = load [[TEST3]]** [[T]],
+// CHECK-NEXT: [[SEL:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES
+// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST3]]* [[T0]] to i8*
+// CHECK-NEXT: [[T2:%.*]] = call i8* bitcast ({{.*}} @objc_msgSend to {{.*}})(i8* [[T1]], i8* [[SEL]])
+// CHECK-NEXT: [[T3:%.*]] = load i8** [[X]],
+// CHECK-NEXT: store i8* [[T2]], i8** [[X]],
+// CHECK-NEXT: call void @objc_release(i8* [[T3]])
+// Epilogue.
+// CHECK-NEXT: call void @objc_storeStrong(i8** [[X]], i8* null)
+// CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST3]]** [[T]] to i8**
+// CHECK-NEXT: call void @objc_storeStrong(i8** [[T0]], i8* null)
+// CHECK-NEXT: ret void
+
+@implementation Test3
+- (id) copyMachine {
+ extern id test3_helper(void);
+ return test3_helper();
+}
+// CHECK: define internal i8* @"\01-[Test3 copyMachine]"(
+// CHECK: [[T0:%.*]] = call i8* @test3_helper()
+// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+// CHECK-NEXT: ret i8* [[T1]]
+- (void) setCopyMachine: (id) x {}
+@end
+
+// CHECK: attributes [[NUW]] = { nounwind }
diff --git a/test/CodeGenObjC/arc-related-result-type.m b/test/CodeGenObjC/arc-related-result-type.m
index ee0a41d..e8b9701 100644
--- a/test/CodeGenObjC/arc-related-result-type.m
+++ b/test/CodeGenObjC/arc-related-result-type.m
@@ -9,10 +9,10 @@ void test0(Test0 *val) {
// CHECK: define void @test0(
// CHECK: [[VAL:%.*]] = alloca [[TEST0:%.*]]*
// CHECK-NEXT: [[X:%.*]] = alloca [[TEST0]]*
+// CHECK-NEXT: store [[TEST0]]* null
// CHECK-NEXT: bitcast
-// CHECK-NEXT: call i8* @objc_retain(
// CHECK-NEXT: bitcast
-// CHECK-NEXT: store
+// CHECK-NEXT: call void @objc_storeStrong(
// CHECK-NEXT: load [[TEST0]]** [[VAL]],
// CHECK-NEXT: load
// CHECK-NEXT: bitcast
diff --git a/test/CodeGenObjC/arc-ternary-op.m b/test/CodeGenObjC/arc-ternary-op.m
new file mode 100644
index 0000000..f70e886
--- /dev/null
+++ b/test/CodeGenObjC/arc-ternary-op.m
@@ -0,0 +1,138 @@
+// 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
+
+void test0(_Bool cond) {
+ id test0_helper(void) __attribute__((ns_returns_retained));
+
+ // CHECK: define void @test0(
+ // CHECK: [[COND:%.*]] = alloca i8,
+ // CHECK-NEXT: [[X:%.*]] = alloca i8*,
+ // CHECK-NEXT: [[RELVAL:%.*]] = alloca i8*
+ // CHECK-NEXT: [[RELCOND:%.*]] = alloca i1
+ // CHECK-NEXT: zext
+ // CHECK-NEXT: store
+ // CHECK-NEXT: [[T0:%.*]] = load i8* [[COND]]
+ // CHECK-NEXT: [[T1:%.*]] = trunc i8 [[T0]] to i1
+ // CHECK-NEXT: store i1 false, i1* [[RELCOND]]
+ // CHECK-NEXT: br i1 [[T1]],
+ // CHECK: br label
+ // CHECK: [[CALL:%.*]] = call i8* @test0_helper()
+ // CHECK-NEXT: store i8* [[CALL]], i8** [[RELVAL]]
+ // CHECK-NEXT: store i1 true, i1* [[RELCOND]]
+ // CHECK-NEXT: br label
+ // CHECK: [[T0:%.*]] = phi i8* [ null, {{%.*}} ], [ [[CALL]], {{%.*}} ]
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) [[NUW:#[0-9]+]]
+ // CHECK-NEXT: store i8* [[T1]], i8** [[X]],
+ // CHECK-NEXT: [[REL:%.*]] = load i1* [[RELCOND]]
+ // CHECK-NEXT: br i1 [[REL]],
+ // CHECK: [[T0:%.*]] = load i8** [[RELVAL]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]]
+ // CHECK-NEXT: br label
+ // CHECK: [[T0:%.*]] = load i8** [[X]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]]
+ // CHECK-NEXT: ret void
+ id x = (cond ? 0 : test0_helper());
+}
+
+void test1(int cond) {
+ __strong id strong;
+ __weak id weak;
+ extern void test1_sink(id *);
+ test1_sink(cond ? &strong : 0);
+ test1_sink(cond ? &weak : 0);
+
+ // CHECK: define void @test1(
+ // CHECK: [[COND:%.*]] = alloca i32
+ // CHECK-NEXT: [[STRONG:%.*]] = alloca i8*
+ // CHECK-NEXT: [[WEAK:%.*]] = alloca i8*
+ // CHECK-NEXT: [[TEMP1:%.*]] = alloca i8*
+ // CHECK-NEXT: [[TEMP2:%.*]] = alloca i8*
+ // CHECK-NEXT: [[CONDCLEANUPSAVE:%.*]] = alloca i8*
+ // CHECK-NEXT: [[CONDCLEANUP:%.*]] = alloca i1
+ // CHECK-NEXT: store i32
+ // CHECK-NEXT: store i8* null, i8** [[STRONG]]
+ // CHECK-NEXT: call i8* @objc_initWeak(i8** [[WEAK]], i8* null)
+
+ // CHECK-NEXT: [[T0:%.*]] = load i32* [[COND]]
+ // CHECK-NEXT: [[T1:%.*]] = icmp ne i32 [[T0]], 0
+ // CHECK: [[ARG:%.*]] = phi i8**
+ // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null
+ // CHECK-NEXT: [[T1:%.*]] = select i1 [[T0]], i8** null, i8** [[TEMP1]]
+ // CHECK-NEXT: br i1 [[T0]],
+ // CHECK: [[T0:%.*]] = load i8** [[ARG]]
+ // CHECK-NEXT: store i8* [[T0]], i8** [[TEMP1]]
+ // CHECK-NEXT: br label
+ // CHECK: [[W:%.*]] = phi i8* [ [[T0]], {{%.*}} ], [ undef, {{%.*}} ]
+ // CHECK-NEXT: call void @test1_sink(i8** [[T1]])
+ // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null
+ // CHECK-NEXT: br i1 [[T0]],
+ // CHECK: [[T0:%.*]] = load i8** [[TEMP1]]
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
+ // CHECK-NEXT: call void (...)* @clang.arc.use(i8* [[W]]) [[NUW]]
+ // CHECK-NEXT: [[T2:%.*]] = load i8** [[ARG]]
+ // CHECK-NEXT: store i8* [[T1]], i8** [[ARG]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T2]])
+ // CHECK-NEXT: br label
+
+ // CHECK: [[T0:%.*]] = load i32* [[COND]]
+ // CHECK-NEXT: [[T1:%.*]] = icmp ne i32 [[T0]], 0
+ // CHECK: [[ARG:%.*]] = phi i8**
+ // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null
+ // CHECK-NEXT: [[T1:%.*]] = select i1 [[T0]], i8** null, i8** [[TEMP2]]
+ // CHECK-NEXT: store i1 false, i1* [[CONDCLEANUP]]
+ // CHECK-NEXT: br i1 [[T0]],
+ // CHECK: [[T0:%.*]] = call i8* @objc_loadWeakRetained(i8** [[ARG]])
+ // CHECK-NEXT: store i8* [[T0]], i8** [[CONDCLEANUPSAVE]]
+ // CHECK-NEXT: store i1 true, i1* [[CONDCLEANUP]]
+ // CHECK-NEXT: store i8* [[T0]], i8** [[TEMP2]]
+ // CHECK-NEXT: br label
+ // CHECK: call void @test1_sink(i8** [[T1]])
+ // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null
+ // CHECK-NEXT: br i1 [[T0]],
+ // CHECK: [[T0:%.*]] = load i8** [[TEMP2]]
+ // CHECK-NEXT: call i8* @objc_storeWeak(i8** [[ARG]], i8* [[T0]])
+ // CHECK-NEXT: br label
+
+ // CHECK: call void @objc_destroyWeak(i8** [[WEAK]])
+ // CHECK: ret void
+}
+
+// rdar://13113981
+// Test that, when emitting an expression at +1 that we can't peephole,
+// we emit the retain inside the full-expression. If we ever peephole
+// +1s of conditional expressions (which we probably ought to), we'll
+// need to find another example of something we need to do this for.
+void test2(int cond) {
+ extern id test2_producer(void);
+ for (id obj in cond ? test2_producer() : (void*) 0) {
+ }
+
+ // CHECK: define void @test2(
+ // CHECK: [[COND:%.*]] = alloca i32,
+ // CHECK: alloca i8*
+ // CHECK: [[CLEANUP_SAVE:%.*]] = alloca i8*
+ // CHECK: [[RUN_CLEANUP:%.*]] = alloca i1
+ // Evaluate condition; cleanup disabled by default.
+ // CHECK: [[T0:%.*]] = load i32* [[COND]],
+ // CHECK-NEXT: icmp ne i32 [[T0]], 0
+ // CHECK-NEXT: store i1 false, i1* [[RUN_CLEANUP]]
+ // CHECK-NEXT: br i1
+ // Within true branch, cleanup enabled.
+ // CHECK: [[T0:%.*]] = call i8* @test2_producer()
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
+ // CHECK-NEXT: store i8* [[T1]], i8** [[CLEANUP_SAVE]]
+ // CHECK-NEXT: store i1 true, i1* [[RUN_CLEANUP]]
+ // CHECK-NEXT: br label
+ // Join point for conditional operator; retain immediately.
+ // CHECK: [[T0:%.*]] = phi i8* [ [[T1]], {{%.*}} ], [ null, {{%.*}} ]
+ // CHECK-NEXT: [[RESULT:%.*]] = call i8* @objc_retain(i8* [[T0]])
+ // Leaving full-expression; run conditional cleanup.
+ // CHECK-NEXT: [[T0:%.*]] = load i1* [[RUN_CLEANUP]]
+ // CHECK-NEXT: br i1 [[T0]]
+ // CHECK: [[T0:%.*]] = load i8** [[CLEANUP_SAVE]]
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]])
+ // CHECK-NEXT: br label
+ // And way down at the end of the loop:
+ // CHECK: call void @objc_release(i8* [[RESULT]])
+}
+
+// CHECK: attributes [[NUW]] = { nounwind }
diff --git a/test/CodeGenObjC/arc-unopt.m b/test/CodeGenObjC/arc-unopt.m
index c319bf2..84f5d34 100644
--- a/test/CodeGenObjC/arc-unopt.m
+++ b/test/CodeGenObjC/arc-unopt.m
@@ -9,7 +9,7 @@ Test0 *test0(void) {
// CHECK: [[LD:%.*]] = load [[TEST0:%.*]]** @test0_helper
// CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST0]]* [[LD]] to i8*
- // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleaseReturnValue(i8* [[T0]])
+ // CHECK-NEXT: [[T1:%.*]] = tail call i8* @objc_retainAutoreleaseReturnValue(i8* [[T0]])
// CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to [[TEST0]]*
// CHECK-NEXT: ret [[TEST0]]* [[T2]]
}
@@ -19,7 +19,7 @@ id test1(void) {
return test1_helper;
// CHECK: [[LD:%.*]] = load i8** @test1_helper
- // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retainAutoreleaseReturnValue(i8* [[LD]])
+ // CHECK-NEXT: [[T0:%.*]] = tail call i8* @objc_retainAutoreleaseReturnValue(i8* [[LD]])
// CHECK-NEXT: ret i8* [[T0]]
}
diff --git a/test/CodeGenObjC/arc-unoptimized-byref-var.m b/test/CodeGenObjC/arc-unoptimized-byref-var.m
new file mode 100644
index 0000000..d3189e1
--- /dev/null
+++ b/test/CodeGenObjC/arc-unoptimized-byref-var.m
@@ -0,0 +1,16 @@
+// 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
+// rdar://12530881
+
+void test19() {
+ __block id x;
+// CHECK-UNOPT: define internal void @__Block_byref_object_copy
+// CHECK-UNOPT: [[X:%.*]] = getelementptr inbounds [[BYREF_T:%.*]]* [[VAR:%.*]], i32 0, i32 6
+// CHECK-UNOPT: [[X2:%.*]] = getelementptr inbounds [[BYREF_T:%.*]]* [[VAR1:%.*]], i32 0, i32 6
+// CHECK-UNOPT-NEXT: [[SIX:%.*]] = load i8** [[X2]], align 8
+// CHECK-UNOPT-NEXT: store i8* null, i8** [[X]], align 8
+// CHECK-UNOPT-NEXT: call void @objc_storeStrong(i8** [[X]], i8* [[SIX]]) [[NUW:#[0-9]+]]
+// CHECK-UNOPT-NEXT: call void @objc_storeStrong(i8** [[X2]], i8* null) [[NUW]]
+// CHECK-UNOPT-NEXT: ret void
+}
+
+// CHECK: attributes [[NUW]] = { nounwind }
diff --git a/test/CodeGenObjC/arc-weak-property.m b/test/CodeGenObjC/arc-weak-property.m
index 0a6b2a6..e8d57bc 100644
--- a/test/CodeGenObjC/arc-weak-property.m
+++ b/test/CodeGenObjC/arc-weak-property.m
@@ -22,7 +22,7 @@
// CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8* [[T2]], i64 [[T1]]
// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to i8**
// CHECK-NEXT: [[T5:%.*]] = call i8* @objc_loadWeakRetained(i8** [[T4]])
-// CHECK-NEXT: [[T6:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[T5]])
+// CHECK-NEXT: [[T6:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[T5]])
// CHECK-NEXT: ret i8* [[T6]]
// CHECK: define internal void @"\01-[WeakPropertyTest setPROP:]"
diff --git a/test/CodeGenObjC/arc-with-atthrow.m b/test/CodeGenObjC/arc-with-atthrow.m
index 213b05b..2570376 100644
--- a/test/CodeGenObjC/arc-with-atthrow.m
+++ b/test/CodeGenObjC/arc-with-atthrow.m
@@ -13,5 +13,7 @@ void test() {
// CHECK: [[T0:%.*]] = call i8* @make()
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_autorelease(i8* [[T1]])
-// CHECK-NEXT: call void @objc_exception_throw(i8* [[T2]]) noreturn
+// CHECK-NEXT: call void @objc_exception_throw(i8* [[T2]]) [[NR:#[0-9]+]]
// CHECK-NEXT: unreachable
+
+// CHECK: attributes [[NR]] = { noreturn }
diff --git a/test/CodeGenObjC/arc.m b/test/CodeGenObjC/arc.m
index 8e38019..7262dc8 100644
--- a/test/CodeGenObjC/arc.m
+++ b/test/CodeGenObjC/arc.m
@@ -1,6 +1,37 @@
// 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-GLOBALS %s
+// rdar://13129783. Check both native/non-native arc platforms. Here we check
+// that they treat nonlazybind differently.
+// RUN: %clang_cc1 -fobjc-runtime=macosx-10.6.0 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=ARC-ALIEN %s
+// RUN: %clang_cc1 -fobjc-runtime=macosx-10.7.0 -triple x86_64-apple-darwin11 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=ARC-NATIVE %s
+
+// ARC-ALIEN: declare extern_weak void @objc_storeStrong(i8**, i8*)
+// ARC-ALIEN: declare extern_weak i8* @objc_retain(i8*)
+// ARC-ALIEN: declare extern_weak i8* @objc_autoreleaseReturnValue(i8*)
+// ARC-ALIEN: declare i8* @objc_msgSend(i8*, i8*, ...) [[NLB:#[0-9]+]]
+// ARC-ALIEN: declare extern_weak void @objc_release(i8*)
+// ARC-ALIEN: declare extern_weak i8* @objc_retainAutoreleasedReturnValue(i8*)
+// ARC-ALIEN: declare extern_weak i8* @objc_initWeak(i8**, i8*)
+// ARC-ALIEN: declare extern_weak i8* @objc_storeWeak(i8**, i8*)
+// ARC-ALIEN: declare extern_weak i8* @objc_loadWeakRetained(i8**)
+// ARC-ALIEN: declare extern_weak void @objc_destroyWeak(i8**)
+// ARC-ALIEN: declare extern_weak i8* @objc_autorelease(i8*)
+// ARC-ALIEN: declare extern_weak i8* @objc_retainAutorelease(i8*)
+
+// ARC-NATIVE: declare void @objc_storeStrong(i8**, i8*)
+// ARC-NATIVE: declare i8* @objc_retain(i8*) [[NLB:#[0-9]+]]
+// ARC-NATIVE: declare i8* @objc_autoreleaseReturnValue(i8*)
+// ARC-NATIVE: declare i8* @objc_msgSend(i8*, i8*, ...) [[NLB]]
+// ARC-NATIVE: declare void @objc_release(i8*) [[NLB]]
+// ARC-NATIVE: declare i8* @objc_retainAutoreleasedReturnValue(i8*)
+// ARC-NATIVE: declare i8* @objc_initWeak(i8**, i8*)
+// ARC-NATIVE: declare i8* @objc_storeWeak(i8**, i8*)
+// ARC-NATIVE: declare i8* @objc_loadWeakRetained(i8**)
+// ARC-NATIVE: declare void @objc_destroyWeak(i8**)
+// ARC-NATIVE: declare i8* @objc_autorelease(i8*)
+// ARC-NATIVE: declare i8* @objc_retainAutorelease(i8*)
+
// CHECK: define void @test0
void test0(id x) {
// CHECK: [[X:%.*]] = alloca i8*
@@ -9,9 +40,6 @@ void test0(id x) {
// CHECK-NEXT: [[TMP:%.*]] = load i8** [[X]]
// CHECK-NEXT: call void @objc_release(i8* [[TMP]])
// CHECK-NEXT: ret void
-// rdar://12040837
- // CHECK: declare extern_weak i8* @objc_retain(i8*) nonlazybind
- // CHECK: declare extern_weak void @objc_release(i8*) nonlazybind
}
// CHECK: define i8* @test1(i8*
@@ -29,7 +57,7 @@ id test1(id x) {
// CHECK-NEXT: call void @objc_release(i8* [[T0]])
// CHECK-NEXT: [[T1:%.*]] = load i8** [[X]]
// CHECK-NEXT: call void @objc_release(i8* [[T1]])
- // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[RET]])
+ // CHECK-NEXT: [[T1:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[RET]])
// CHECK-NEXT: ret i8* [[T1]]
id y;
return y;
@@ -88,12 +116,12 @@ void test3_unelided() {
// CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST3]]* [[T0]] to i8*
// CHECK-NEXT: [[COPY:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend {{.*}})(i8* [[T1]],
- // CHECK-NEXT: call void @objc_release(i8* [[COPY]]) nounwind
+ // CHECK-NEXT: call void @objc_release(i8* [[COPY]]) [[NUW:#[0-9]+]]
[x copy];
// CHECK-NEXT: [[T0:%.*]] = load [[TEST3]]** [[X]]
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST3]]* [[T0]] to i8*
- // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]]
// CHECK-NEXT: ret void
}
@@ -127,13 +155,13 @@ void test3() {
// Assignment to x.
// CHECK-NEXT: [[TMP:%.*]] = load i8** [[X]]
// CHECK-NEXT: store i8* [[COPY]], i8** [[X]]
- // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) nounwind
+ // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) [[NUW]]
x = [x copy];
// Cleanup for x.
// CHECK-NEXT: [[TMP:%.*]] = load i8** [[X]]
- // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) nounwind
+ // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) [[NUW]]
// CHECK-NEXT: ret void
}
@@ -156,7 +184,7 @@ id test4() {
// Retain/release elided.
// CHECK-NEXT: bitcast
// CHECK-NEXT: [[INIT:%.*]] = bitcast
- // CHECK-NEXT: [[RET:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[INIT]])
+ // CHECK-NEXT: [[RET:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[INIT]])
// CHECK-NEXT: ret i8* [[RET]]
@@ -188,7 +216,7 @@ void test5(Test5 *x, id y) {
// CHECK-NEXT: [[VAR:%.*]] = bitcast
// CHECK-NEXT: [[TMP:%.*]] = load i8** [[VAR]]
// CHECK-NEXT: store i8* null, i8** [[VAR]]
- // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) nounwind
+ // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) [[NUW]]
x->var = 0;
// CHECK-NEXT: [[YVAL:%.*]] = load i8** [[Y]]
@@ -197,18 +225,18 @@ void test5(Test5 *x, id y) {
// CHECK-NEXT: bitcast
// CHECK-NEXT: getelementptr
// CHECK-NEXT: [[VAR:%.*]] = bitcast
- // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retain(i8* [[YVAL]]) nounwind
+ // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retain(i8* [[YVAL]]) [[NUW]]
// CHECK-NEXT: [[TMP:%.*]] = load i8** [[VAR]]
// CHECK-NEXT: store i8* [[T0]], i8** [[VAR]]
- // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) nounwind
+ // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) [[NUW]]
x->var = y;
// Epilogue.
// CHECK-NEXT: [[TMP:%.*]] = load i8** [[Y]]
- // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) nounwind
+ // CHECK-NEXT: call void @objc_release(i8* [[TMP]]) [[NUW]]
// CHECK-NEXT: [[T0:%.*]] = load [[TEST5]]** [[X]]
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST5]]* [[T0]] to i8*
- // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]]
// CHECK-NEXT: ret void
}
@@ -219,7 +247,7 @@ void test6() {
// CHECK-NEXT: [[CALL:%.*]] = call i8* @test6_helper()
// CHECK-NEXT: store i8* [[CALL]], i8** [[X]]
// CHECK-NEXT: [[T1:%.*]] = load i8** [[X]]
- // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind, !clang.imprecise_release
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release
// CHECK-NEXT: ret void
id x = test6_helper();
}
@@ -230,10 +258,10 @@ void test7() {
// CHECK: [[X:%.*]] = alloca i8*
// CHECK-NEXT: store i8* null, i8** [[X]]
// CHECK-NEXT: [[T0:%.*]] = load i8** [[X]]
- // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) nounwind
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) [[NUW]]
// CHECK-NEXT: call void @test7_helper(i8* [[T1]])
// CHECK-NEXT: [[T1:%.*]] = load i8** [[X]]
- // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind, !clang.imprecise_release
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release
// CHECK-NEXT: ret void
id x;
test7_helper(x);
@@ -245,27 +273,7 @@ void test8() {
// CHECK: [[X:%.*]] = alloca i8*
// CHECK-NEXT: [[T0:%.*]] = call i8* @test8_helper()
// CHECK-NEXT: store i8* [[T0]], i8** [[X]]
- // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind
- // CHECK-NOT: imprecise_release
- // CHECK-NEXT: ret void
-}
-
-id test9_helper(void) __attribute__((ns_returns_retained));
-void test9() {
- id x __attribute__((objc_precise_lifetime)) = test9_helper();
- x = 0;
- // CHECK: [[X:%.*]] = alloca i8*
- // CHECK-NEXT: [[CALL:%.*]] = call i8* @test9_helper()
- // CHECK-NEXT: store i8* [[CALL]], i8** [[X]]
-
- // CHECK-NEXT: [[T1:%.*]] = load i8** [[X]]
- // CHECK-NEXT: store i8* null, i8** [[X]]
- // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind, !clang.imprecise_release
-
- // CHECK-NEXT: [[T1:%.*]] = load i8** [[X]]
- // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind
- // CHECK-NOT: clang.imprecise_release
-
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]], !clang.imprecise_release
// CHECK-NEXT: ret void
}
@@ -314,7 +322,7 @@ void test11(id (*f)(void) __attribute__((ns_returns_retained))) {
// CHECK-NEXT: [[T1:%.*]] = call i8* [[T0]]()
// CHECK-NEXT: store i8* [[T1]], i8** [[X]], align
// CHECK-NEXT: [[T3:%.*]] = load i8** [[X]]
- // CHECK-NEXT: call void @objc_release(i8* [[T3]]) nounwind, !clang.imprecise_release
+ // CHECK-NEXT: call void @objc_release(i8* [[T3]]) [[NUW]], !clang.imprecise_release
// CHECK-NEXT: ret void
id x = f();
}
@@ -343,9 +351,9 @@ void test12(void) {
// CHECK-NEXT: store i8* [[T2]], i8** [[Y]], align
// CHECK-NEXT: [[T4:%.*]] = load i8** [[Y]]
- // CHECK-NEXT: call void @objc_release(i8* [[T4]]) nounwind, !clang.imprecise_release
+ // CHECK-NEXT: call void @objc_release(i8* [[T4]]) [[NUW]], !clang.imprecise_release
// CHECK-NEXT: call void @objc_destroyWeak(i8** [[X]])
- // CHECK-NEXT: ret void
+ // CHECK: ret void
}
// Indirect consuming calls.
@@ -359,7 +367,7 @@ void test13(void) {
extern fnty *test13_func;
// CHECK-NEXT: [[FN:%.*]] = load void (i8*)** @test13_func, align
// CHECK-NEXT: [[X_VAL:%.*]] = load i8** [[X]], align
- // CHECK-NEXT: [[X_TMP:%.*]] = call i8* @objc_retain(i8* [[X_VAL]]) nounwind
+ // CHECK-NEXT: [[X_TMP:%.*]] = call i8* @objc_retain(i8* [[X_VAL]]) [[NUW]]
// CHECK-NEXT: call void [[FN]](i8* [[X_TMP]])
test13_func(x);
@@ -369,14 +377,14 @@ void test13(void) {
// CHECK-NEXT: [[BLOCK_FN_PTR:%.*]] = getelementptr inbounds [[BLOCKTY]]* [[BLOCK]], i32 0, i32 3
// CHECK-NEXT: [[BLOCK_OPAQUE:%.*]] = bitcast [[BLOCKTY]]* [[BLOCK]] to i8*
// CHECK-NEXT: [[X_VAL:%.*]] = load i8** [[X]], align
- // CHECK-NEXT: [[X_TMP:%.*]] = call i8* @objc_retain(i8* [[X_VAL]]) nounwind
+ // CHECK-NEXT: [[X_TMP:%.*]] = call i8* @objc_retain(i8* [[X_VAL]]) [[NUW]]
// CHECK-NEXT: [[BLOCK_FN_TMP:%.*]] = load i8** [[BLOCK_FN_PTR]]
// CHECK-NEXT: [[BLOCK_FN:%.*]] = bitcast i8* [[BLOCK_FN_TMP]] to void (i8*, i8*)*
// CHECK-NEXT: call void [[BLOCK_FN]](i8* [[BLOCK_OPAQUE]], i8* [[X_TMP]])
test13_block(x);
// CHECK-NEXT: [[T0:%.*]] = load i8** [[X]]
- // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]]
// CHECK-NEXT: ret void
}
@@ -426,14 +434,14 @@ void test13(void) {
// CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST16]]* [[BASE]] to i8*
// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i8* [[T0]], i64 [[Y_OFF]]
// CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to i8**
- // CHECK-NEXT: call void @objc_storeStrong(i8** [[T2]], i8* null) nounwind
+ // CHECK-NEXT: call void @objc_storeStrong(i8** [[T2]], i8* null) [[NUW]]
// Destroy z.
// CHECK-NEXT: [[Z_OFF:%.*]] = load i64* @"OBJC_IVAR_$_Test16.z"
// CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST16]]* [[BASE]] to i8*
// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i8* [[T0]], i64 [[Z_OFF]]
// CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to i8**
- // CHECK-NEXT: call void @objc_storeStrong(i8** [[T2]], i8* null) nounwind
+ // CHECK-NEXT: call void @objc_storeStrong(i8** [[T2]], i8* null) [[NUW]]
// CHECK-NEXT: ret void
@@ -452,19 +460,20 @@ void test13(void) {
void test19() {
// CHECK: define void @test19()
// CHECK: [[X:%.*]] = alloca [5 x i8*], align 16
+ // CHECK: call void @llvm.lifetime.start
// CHECK-NEXT: [[T0:%.*]] = bitcast [5 x i8*]* [[X]] to i8*
- // CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 40, i32 16, i1 false)
+ // CHECK: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 40, i32 16, i1 false)
id x[5];
extern id test19_helper(void);
x[2] = test19_helper();
// CHECK-NEXT: [[CALL:%.*]] = call i8* @test19_helper()
- // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[CALL]]) nounwind
+ // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[CALL]]) [[NUW]]
// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [5 x i8*]* [[X]], i32 0, i64 2
// CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]]
// CHECK-NEXT: store i8* [[T1]], i8** [[SLOT]]
- // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]]
// CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [5 x i8*]* [[X]], i32 0, i32 0
// CHECK-NEXT: [[END:%.*]] = getelementptr inbounds i8** [[BEGIN]], i64 5
@@ -473,7 +482,7 @@ void test19() {
// CHECK: [[AFTER:%.*]] = phi i8** [ [[END]], {{%.*}} ], [ [[NEXT:%.*]], {{%.*}} ]
// CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds i8** [[AFTER]], i64 -1
// CHECK-NEXT: [[T0:%.*]] = load i8** [[CUR]]
- // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]], !clang.imprecise_release
// CHECK-NEXT: [[EQ:%.*]] = icmp eq i8** [[CUR]], [[BEGIN]]
// CHECK-NEXT: br i1 [[EQ]],
@@ -512,7 +521,7 @@ void test20(unsigned n) {
// CHECK: [[AFTER:%.*]] = phi i8** [ [[END]], {{%.*}} ], [ [[CUR:%.*]], {{%.*}} ]
// CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds i8** [[AFTER]], i64 -1
// CHECK-NEXT: [[T0:%.*]] = load i8** [[CUR]]
- // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]], !clang.imprecise_release
// CHECK-NEXT: [[EQ:%.*]] = icmp eq i8** [[CUR]], [[VLA]]
// CHECK-NEXT: br i1 [[EQ]],
@@ -558,7 +567,7 @@ void test21(unsigned n) {
// CHECK: [[AFTER:%.*]] = phi i8** [ [[END]], {{%.*}} ], [ [[CUR:%.*]], {{%.*}} ]
// CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds i8** [[AFTER]], i64 -1
// CHECK-NEXT: [[T0:%.*]] = load i8** [[CUR]]
- // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
+ // CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]], !clang.imprecise_release
// CHECK-NEXT: [[EQ:%.*]] = icmp eq i8** [[CUR]], [[BEGIN]]
// CHECK-NEXT: br i1 [[EQ]],
@@ -567,39 +576,6 @@ void test21(unsigned n) {
// CHECK-NEXT: ret void
}
-void test22(_Bool cond) {
- id test22_helper(void) __attribute__((ns_returns_retained));
-
- // CHECK: define void @test22(
- // CHECK: [[COND:%.*]] = alloca i8,
- // CHECK-NEXT: [[X:%.*]] = alloca i8*,
- // CHECK-NEXT: [[RELVAL:%.*]] = alloca i8*
- // CHECK-NEXT: [[RELCOND:%.*]] = alloca i1
- // CHECK-NEXT: zext
- // CHECK-NEXT: store
- // CHECK-NEXT: [[T0:%.*]] = load i8* [[COND]]
- // CHECK-NEXT: [[T1:%.*]] = trunc i8 [[T0]] to i1
- // CHECK-NEXT: store i1 false, i1* [[RELCOND]]
- // CHECK-NEXT: br i1 [[T1]],
- // CHECK: br label
- // CHECK: [[CALL:%.*]] = call i8* @test22_helper()
- // CHECK-NEXT: store i8* [[CALL]], i8** [[RELVAL]]
- // CHECK-NEXT: store i1 true, i1* [[RELCOND]]
- // CHECK-NEXT: br label
- // CHECK: [[T0:%.*]] = phi i8* [ null, {{%.*}} ], [ [[CALL]], {{%.*}} ]
- // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) nounwind
- // CHECK-NEXT: store i8* [[T1]], i8** [[X]],
- // CHECK-NEXT: [[REL:%.*]] = load i1* [[RELCOND]]
- // CHECK-NEXT: br i1 [[REL]],
- // CHECK: [[T0:%.*]] = load i8** [[RELVAL]]
- // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind
- // CHECK-NEXT: br label
- // CHECK: [[T0:%.*]] = load i8** [[X]]
- // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind
- // CHECK-NEXT: ret void
- id x = (cond ? 0 : test22_helper());
-}
-
// rdar://problem/8922540
// Note that we no longer emit .release_ivars flags.
// rdar://problem/12492434
@@ -646,7 +622,9 @@ void test22(_Bool cond) {
// CHECK-NEXT: store i8* {{%.*}}, i8** [[CMD]]
// CHECK-NEXT: [[T0:%.*]] = load [[TEST27]]** [[SELF]]
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST27]]* [[T0]] to i8*
-// CHECK-NEXT: [[RET:%.*]] = call i8* @objc_retain(i8* [[T1]])
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
+// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST27]]*
+// CHECK-NEXT: [[RET:%.*]] = bitcast [[TEST27]]* [[T3]] to i8*
// CHECK-NEXT: store i32 {{[0-9]+}}, i32* [[DEST]]
// CHECK-NEXT: [[T0:%.*]] = load [[TEST27]]** [[SELF]]
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST27]]* [[T0]] to i8*
@@ -681,7 +659,7 @@ void test22(_Bool cond) {
@implementation Test29
static id _test29_allocator = 0;
- (id) init {
-// CHECK: define internal i8* @"\01-[Test29 init]"([[TEST29:%.*]]* {{%.*}},
+// CHECK: define internal i8* @"\01-[Test29 init]"([[TEST29:%[^*]*]]* {{%.*}},
// CHECK: [[SELF:%.*]] = alloca [[TEST29]]*, align 8
// CHECK-NEXT: [[CMD:%.*]] = alloca i8*, align 8
// CHECK-NEXT: [[CLEANUP:%.*]] = alloca i32
@@ -710,13 +688,15 @@ static id _test29_allocator = 0;
// Return statement.
// CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[CALL]]
// CHECK-NEXT: [[CALL:%.*]] = bitcast
-// CHECK-NEXT: [[RET:%.*]] = call i8* @objc_retain(i8* [[CALL]]) nounwind
+// CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retain(i8* [[CALL]]) [[NUW]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[TEST29]]*
+// CHECK-NEXT: [[RET:%.*]] = bitcast [[TEST29]]* [[T1]] to i8*
// CHECK-NEXT: store i32 1, i32* [[CLEANUP]]
// Cleanup.
// CHECK-NEXT: [[T0:%.*]] = load [[TEST29]]** [[SELF]]
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST29]]* [[T0]] to i8*
-// CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind, !clang.imprecise_release
+// CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release
// Return.
// CHECK-NEXT: ret i8* [[RET]]
@@ -754,7 +734,7 @@ static id _test29_allocator = 0;
// Assignment.
// CHECK-NEXT: [[T0:%.*]] = bitcast i8* [[CALL]] to [[TEST29]]*
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST29]]* [[T0]] to i8*
-// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) nounwind
+// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) [[NUW]]
// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST29]]*
// CHECK-NEXT: [[T4:%.*]] = load [[TEST29]]** [[SELF]], align
// CHECK-NEXT: store [[TEST29]]* [[T3]], [[TEST29]]** [[SELF]], align
@@ -764,16 +744,18 @@ static id _test29_allocator = 0;
// Return statement.
// CHECK-NEXT: [[T0:%.*]] = load [[TEST29]]** [[SELF]]
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST29]]* [[T0]] to i8*
-// CHECK-NEXT: [[RET:%.*]] = call i8* @objc_retain(i8* [[T1]]) nounwind
+// CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retain(i8* [[T1]]) [[NUW]]
+// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[TEST29]]*
+// CHECK-NEXT: [[RET:%.*]] = bitcast [[TEST29]]* [[T1]] to i8*
// CHECK-NEXT: store i32 1, i32* [[CLEANUP]]
// Cleanup.
// CHECK-NEXT: [[T0:%.*]] = load i8** [[ALLOCATOR]]
-// CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
+// CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]], !clang.imprecise_release
// CHECK-NEXT: [[T0:%.*]] = load [[TEST29]]** [[SELF]]
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST29]]* [[T0]] to i8*
-// CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind, !clang.imprecise_release
+// CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release
// Return.
// CHECK-NEXT: ret i8* [[RET]]
@@ -791,7 +773,7 @@ typedef struct Test30_helper Test30_helper;
char *helper;
}
- (id) init {
-// CHECK: define internal i8* @"\01-[Test30 init]"([[TEST30:%.*]]* {{%.*}},
+// CHECK: define internal i8* @"\01-[Test30 init]"([[TEST30:%[^*]*]]* {{%.*}},
// CHECK: [[RET:%.*]] = alloca [[TEST30]]*
// CHECK-NEXT: alloca i8*
// CHECK-NEXT: alloca i32
@@ -819,7 +801,9 @@ char *helper;
// Return.
// CHECK-NEXT: [[T0:%.*]] = load [[TEST30]]** [[SELF]]
// CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST30]]* [[T0]] to i8*
-// CHECK-NEXT: [[RET:%.*]] = call i8* @objc_retain(i8* [[T1]])
+// CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retain(i8* [[T1]])
+// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[TEST30]]*
+// CHECK-NEXT: [[RET:%.*]] = bitcast [[TEST30]]* [[T1]] to i8*
// CHECK-NEXT: store i32 1
// Cleanup.
@@ -882,8 +866,8 @@ void test33(Test33 *ptr) {
// CHECK-NEXT: store [[A_T]]* null, [[A_T]]** [[A]]
// CHECK-NEXT: load [[TEST33]]** [[PTR]]
- // CHECK-NEXT: [[T0:%.*]] = load [[A_T]]** [[A]]
- // CHECK-NEXT: store [[A_T]]* [[T0]], [[A_T]]** [[TEMP0]]
+ // CHECK-NEXT: [[W0:%.*]] = load [[A_T]]** [[A]]
+ // CHECK-NEXT: store [[A_T]]* [[W0]], [[A_T]]** [[TEMP0]]
// CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: bitcast
// CHECK-NEXT: objc_msgSend{{.*}}, [[A_T]]** [[TEMP0]])
@@ -891,14 +875,15 @@ void test33(Test33 *ptr) {
// CHECK-NEXT: [[T1:%.*]] = bitcast [[A_T]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A_T]]*
+ // CHECK-NEXT: call void (...)* @clang.arc.use([[A_T]]* [[W0]]) [[NUW]]
// CHECK-NEXT: [[T4:%.*]] = load [[A_T]]** [[A]]
// CHECK-NEXT: store [[A_T]]* [[T3]], [[A_T]]** [[A]]
// CHECK-NEXT: [[T5:%.*]] = bitcast [[A_T]]* [[T4]] to i8*
// CHECK-NEXT: call void @objc_release(i8* [[T5]])
// CHECK-NEXT: load [[TEST33]]** [[PTR]]
- // CHECK-NEXT: [[T0:%.*]] = load [[A_T]]** [[A]]
- // CHECK-NEXT: store [[A_T]]* [[T0]], [[A_T]]** [[TEMP1]]
+ // CHECK-NEXT: [[W0:%.*]] = load [[A_T]]** [[A]]
+ // CHECK-NEXT: store [[A_T]]* [[W0]], [[A_T]]** [[TEMP1]]
// CHECK-NEXT: load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
// CHECK-NEXT: bitcast
// CHECK-NEXT: objc_msgSend{{.*}}, [[A_T]]** [[TEMP1]])
@@ -906,6 +891,7 @@ void test33(Test33 *ptr) {
// CHECK-NEXT: [[T1:%.*]] = bitcast [[A_T]]* [[T0]] to i8*
// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A_T]]*
+ // CHECK-NEXT: call void (...)* @clang.arc.use([[A_T]]* [[W0]]) [[NUW]]
// CHECK-NEXT: [[T4:%.*]] = load [[A_T]]** [[A]]
// CHECK-NEXT: store [[A_T]]* [[T3]], [[A_T]]** [[A]]
// CHECK-NEXT: [[T5:%.*]] = bitcast [[A_T]]* [[T4]] to i8*
@@ -945,61 +931,6 @@ void test33(Test33 *ptr) {
// CHECK-NEXT: ret void
}
-void test34(int cond) {
- __strong id strong;
- __weak id weak;
- extern void test34_sink(id *);
- test34_sink(cond ? &strong : 0);
- test34_sink(cond ? &weak : 0);
-
- // CHECK: define void @test34(
- // CHECK: [[COND:%.*]] = alloca i32
- // CHECK-NEXT: [[STRONG:%.*]] = alloca i8*
- // CHECK-NEXT: [[WEAK:%.*]] = alloca i8*
- // CHECK-NEXT: [[TEMP1:%.*]] = alloca i8*
- // CHECK-NEXT: [[TEMP2:%.*]] = alloca i8*
- // CHECK-NEXT: store i32
- // CHECK-NEXT: store i8* null, i8** [[STRONG]]
- // CHECK-NEXT: call i8* @objc_initWeak(i8** [[WEAK]], i8* null)
-
- // CHECK-NEXT: [[T0:%.*]] = load i32* [[COND]]
- // CHECK-NEXT: [[T1:%.*]] = icmp ne i32 [[T0]], 0
- // CHECK: [[ARG:%.*]] = phi i8**
- // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null
- // CHECK-NEXT: [[T1:%.*]] = select i1 [[T0]], i8** null, i8** [[TEMP1]]
- // CHECK-NEXT: br i1 [[T0]],
- // CHECK: [[T0:%.*]] = load i8** [[ARG]]
- // CHECK-NEXT: store i8* [[T0]], i8** [[TEMP1]]
- // CHECK-NEXT: br label
- // CHECK: call void @test34_sink(i8** [[T1]])
- // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null
- // CHECK-NEXT: br i1 [[T0]],
- // CHECK: [[T0:%.*]] = load i8** [[TEMP1]]
- // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
- // CHECK-NEXT: [[T2:%.*]] = load i8** [[ARG]]
- // CHECK-NEXT: store i8* [[T1]], i8** [[ARG]]
- // CHECK-NEXT: call void @objc_release(i8* [[T2]])
- // CHECK-NEXT: br label
-
- // CHECK: [[T0:%.*]] = load i32* [[COND]]
- // CHECK-NEXT: [[T1:%.*]] = icmp ne i32 [[T0]], 0
- // CHECK: [[ARG:%.*]] = phi i8**
- // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null
- // CHECK-NEXT: [[T1:%.*]] = select i1 [[T0]], i8** null, i8** [[TEMP2]]
- // CHECK-NEXT: br i1 [[T0]],
- // CHECK: [[T0:%.*]] = call i8* @objc_loadWeak(i8** [[ARG]])
- // CHECK-NEXT: store i8* [[T0]], i8** [[TEMP2]]
- // CHECK-NEXT: br label
- // CHECK: call void @test34_sink(i8** [[T1]])
- // CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null
- // CHECK-NEXT: br i1 [[T0]],
- // CHECK: [[T0:%.*]] = load i8** [[TEMP2]]
- // CHECK-NEXT: call i8* @objc_storeWeak(i8** [[ARG]], i8* [[T0]])
- // CHECK-NEXT: br label
-
- // CHECK: call void @objc_destroyWeak(i8** [[WEAK]])
- // CHECK: ret void
-}
// CHECK: define void @test36
void test36(id x) {
@@ -1034,15 +965,16 @@ void test37(void) {
// CHECK-NEXT: [[TEMP:%.*]] = alloca i8*
// CHECK-NEXT: store [[TEST37]]* null, [[TEST37]]** [[VAR]]
- // CHECK-NEXT: [[T0:%.*]] = load [[TEST37]]** [[VAR]]
- // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST37]]* [[T0]] to i8*
- // CHECK-NEXT: store i8* [[T1]], i8** [[TEMP]]
+ // CHECK-NEXT: [[W0:%.*]] = load [[TEST37]]** [[VAR]]
+ // CHECK-NEXT: [[W1:%.*]] = bitcast [[TEST37]]* [[W0]] to i8*
+ // CHECK-NEXT: store i8* [[W1]], i8** [[TEMP]]
// CHECK-NEXT: call void @test37_helper(i8** [[TEMP]])
// CHECK-NEXT: [[T0:%.*]] = load i8** [[TEMP]]
// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[TEST37]]*
// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST37]]* [[T1]] to i8*
// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]])
// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[TEST37]]*
+ // CHECK-NEXT: call void (...)* @clang.arc.use(i8* [[W1]]) [[NUW]]
// CHECK-NEXT: [[T5:%.*]] = load [[TEST37]]** [[VAR]]
// CHECK-NEXT: store [[TEST37]]* [[T4]], [[TEST37]]** [[VAR]]
// CHECK-NEXT: [[T6:%.*]] = bitcast [[TEST37]]* [[T5]] to i8*
@@ -1186,7 +1118,7 @@ id test52(void) {
// CHECK-NEXT: store i32 5, i32* [[X]],
// CHECK-NEXT: [[T0:%.*]] = load i32* [[X]],
// CHECK-NEXT: [[T1:%.*]] = call i8* @test52_helper(i32 [[T0]])
-// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[T1]])
+// CHECK-NEXT: [[T2:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[T1]])
// CHECK-NEXT: ret i8* [[T2]]
}
@@ -1287,7 +1219,7 @@ void test56_test(void) {
// CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8* [[T2]], i64 [[T1]]
// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to i8**
// CHECK-NEXT: [[T5:%.*]] = call i8* @objc_loadWeakRetained(i8** [[T4]])
-// CHECK-NEXT: [[T6:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[T5]])
+// CHECK-NEXT: [[T6:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[T5]])
// CHECK-NEXT: ret i8* [[T6]]
// CHECK: define internal i8* @"\01-[Test57 unsafe]"(
@@ -1299,57 +1231,6 @@ void test56_test(void) {
// CHECK-NEXT: [[T5:%.*]] = load i8** [[T4]]
// CHECK-NEXT: ret i8* [[T5]]
-// rdar://problem/9821110
-@interface Test58
-- (char*) interior __attribute__((objc_returns_inner_pointer));
-// Should we allow this on properties?
-@end
-extern Test58 *test58_helper(void);
-
-// CHECK: define void @test58a()
-void test58a(void) {
- // CHECK: [[T0:%.*]] = call [[TEST58:%.*]]* @test58_helper()
- // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST58]]* [[T0]] to i8*
- // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
- // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST58]]*
- // CHECK-NEXT: store [[TEST58]]* [[T3]]
- // CHECK-NEXT: [[T0:%.*]] = load [[TEST58]]**
- // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST58]]* [[T0]] to i8*
- // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]])
- // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST58]]*
- // CHECK-NEXT: [[T4:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
- // CHECK-NEXT: [[T5:%.*]] = bitcast [[TEST58]]* [[T3]] to i8*
- // CHECK-NEXT: [[T6:%.*]] = call i8* bitcast
- // CHECK-NEXT: store i8* [[T6]], i8**
- // CHECK-NEXT: [[T0:%.*]] = load [[TEST58]]**
- // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST58]]* [[T0]] to i8*
- // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind, !clang.imprecise_release
- // CHECK-NEXT: ret void
- Test58 *ptr = test58_helper();
- char *c = [(ptr) interior];
-}
-
-// CHECK: define void @test58b()
-void test58b(void) {
- // CHECK: [[T0:%.*]] = call [[TEST58:%.*]]* @test58_helper()
- // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST58]]* [[T0]] to i8*
- // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
- // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST58]]*
- // CHECK-NEXT: store [[TEST58]]* [[T3]]
- // CHECK-NEXT: [[T0:%.*]] = load [[TEST58]]**
- // CHECK-NEXT: [[T1:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
- // CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST58]]* [[T0]] to i8*
- // CHECK-NEXT: [[T3:%.*]] = call i8* bitcast
- // CHECK-NEXT: store i8* [[T3]], i8**
- // CHECK-NEXT: [[T0:%.*]] = load [[TEST58]]**
- // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST58]]* [[T0]] to i8*
- // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind
- // CHECK-NOT: clang.imprecise_release
- // CHECK-NEXT: ret void
- __attribute__((objc_precise_lifetime)) Test58 *ptr = test58_helper();
- char *c = [ptr interior];
-}
-
// rdar://problem/9842343
void test59(void) {
extern id test59_getlock(void);
@@ -1491,7 +1372,7 @@ void test66(void) {
// CHECK-NEXT: br i1 [[SIX]], label [[NULINIT:%.*]], label [[CALL:%.*]]
// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i8*)*)(i8* [[T7]], i8* [[T6]], i8* [[T5]])
// CHECK-NEXT: br label [[CONT:%.*]]
-// CHECK: call void @objc_release(i8* [[T5]]) nounwind
+// CHECK: call void @objc_release(i8* [[T5]]) [[NUW]]
// CHECK-NEXT: br label [[CONT:%.*]]
// CHECK: [[T8:%.*]] = bitcast [[TEST66]]* [[T3]] to i8*
// CHECK-NEXT: call void @objc_release(i8* [[T8]])
@@ -1543,3 +1424,7 @@ void test70(id i) {
[2] = i
};
}
+
+// ARC-ALIEN: attributes [[NLB]] = { nonlazybind }
+// ARC-NATIVE: attributes [[NLB]] = { nonlazybind }
+// CHECK: attributes [[NUW]] = { nounwind }
diff --git a/test/CodeGenObjC/attr-exception.m b/test/CodeGenObjC/attr-exception.m
new file mode 100644
index 0000000..4d8c425
--- /dev/null
+++ b/test/CodeGenObjC/attr-exception.m
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fexceptions -fobjc-exceptions -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fexceptions -fobjc-exceptions -fvisibility hidden -o - %s | FileCheck -check-prefix=CHECK-HIDDEN %s
+
+__attribute__((objc_root_class))
+@interface Root {
+ Class isa;
+}
+@end
+
+__attribute__((objc_exception))
+@interface A : Root
+@end
+
+@implementation A
+@end
+// CHECK: @"OBJC_EHTYPE_$_A" = global {{%.*}} { i8** getelementptr (i8** @objc_ehtype_vtable, i32 2)
+// CHECK-HIDDEN: @"OBJC_EHTYPE_$_A" = hidden global {{%.*}} { i8** getelementptr (i8** @objc_ehtype_vtable, i32 2)
+
+__attribute__((objc_exception))
+__attribute__((visibility("default")))
+@interface B : Root
+@end
+
+@implementation B
+@end
+// CHECK: @"OBJC_EHTYPE_$_B" = global {{%.*}} { i8** getelementptr (i8** @objc_ehtype_vtable, i32 2)
+// CHECK-HIDDEN: @"OBJC_EHTYPE_$_B" = global {{%.*}} { i8** getelementptr (i8** @objc_ehtype_vtable, i32 2)
diff --git a/test/CodeGenObjC/bitfield-access.m b/test/CodeGenObjC/bitfield-access.m
index 6d4c82a..597fe35 100644
--- a/test/CodeGenObjC/bitfield-access.m
+++ b/test/CodeGenObjC/bitfield-access.m
@@ -15,8 +15,8 @@
// end of the structure.
//
// CHECK-I386: define i32 @f0(
-// CHECK-I386: [[t0_0:%.*]] = load i16* {{.*}}, align 1
-// CHECK-I386: lshr i16 [[t0_0]], 7
+// CHECK-I386: [[t0_0:%.*]] = load i8* {{.*}}, align 1
+// CHECK-I386: lshr i8 [[t0_0]], 7
// CHECK-I386: }
int f0(I0 *a) {
return a->y;
@@ -26,13 +26,11 @@ int f0(I0 *a) {
//
// CHECK-ARM: define i32 @f1(
// CHECK-ARM: [[t1_ptr:%.*]] = getelementptr
-// CHECK-ARM: [[t1_base:%.*]] = bitcast i8* [[t1_ptr]] to i32*
-// CHECK-ARM: [[t1_0:%.*]] = load i32* [[t1_base]], align 1
-// CHECK-ARM: lshr i32 [[t1_0]], 1
-// CHECK-ARM: [[t1_base_2_cast:%.*]] = bitcast i32* %{{.*}} to i8*
-// CHECK-ARM: [[t1_base_2:%.*]] = getelementptr i8* [[t1_base_2_cast]]
-// CHECK-ARM: [[t1_1:%.*]] = load i8* [[t1_base_2]], align 1
-// CHECK-ARM: and i8 [[t1_1:%.*]], 1
+// CHECK-ARM: [[t1_base:%.*]] = bitcast i8* [[t1_ptr]] to i40*
+// CHECK-ARM: [[t1_0:%.*]] = load i40* [[t1_base]], align 1
+// CHECK-ARM: [[t1_1:%.*]] = lshr i40 [[t1_0]], 1
+// CHECK-ARM: [[t1_2:%.*]] = and i40 [[t1_1]],
+// CHECK-ARM: trunc i40 [[t1_2]] to i32
// CHECK-ARM: }
@interface I1 {
@public
diff --git a/test/CodeGenObjC/bitfield-ivar-offsets.m b/test/CodeGenObjC/bitfield-ivar-offsets.m
index b0c848f..7a07f27 100644
--- a/test/CodeGenObjC/bitfield-ivar-offsets.m
+++ b/test/CodeGenObjC/bitfield-ivar-offsets.m
@@ -1,4 +1,3 @@
-// RUNX: llvm-gcc -m64 -emit-llvm -S -o %t %s &&
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o %t %s
// RUN: grep -F '@"OBJC_IVAR_$_I0._b0" = global i64 0, section "__DATA, __objc_ivar", align 8' %t
// RUN: grep -F '@"OBJC_IVAR_$_I0._b1" = global i64 0, section "__DATA, __objc_ivar", align 8' %t
diff --git a/test/CodeGenObjC/block-byref-variable-layout.m b/test/CodeGenObjC/block-byref-variable-layout.m
new file mode 100644
index 0000000..9c8f674
--- /dev/null
+++ b/test/CodeGenObjC/block-byref-variable-layout.m
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple x86_64-apple-darwin -O0 -emit-llvm %s -o - | FileCheck %s
+
+// rdar://12759433
+@class NSString;
+
+void Test12759433() {
+ __block __unsafe_unretained NSString *uuByref = (__bridge NSString *)(void*)0x102030405060708;
+ void (^block)() = ^{ uuByref = 0; };
+ block();
+}
+// CHECK: %struct.__block_byref_uuByref = type { i8*, %struct.__block_byref_uuByref*, i32, i32, [[ZERO:%.*]]* }
+int main() {
+ __block __weak id wid;
+ __block long XXX;
+ __block id ID;
+ __block struct S {
+ int iS;
+ double iD;
+ void *pv;
+ __unsafe_unretained id unsunr;
+ } import;
+ void (^c)() = ^{
+// Inline flag for BYREF variable layout (1107296256): BLOCK_BYREF_HAS_COPY_DISPOSE BLOCK_BYREF_LAYOUT_WEAK
+// CHECK: store i32 1107296256, i32* [[T0:%.*]]
+ wid = 0;
+
+// Inline flag for BYREF variable layout (536870912): BLOCK_BYREF_LAYOUT_NON_OBJECT
+// CHECK: store i32 536870912, i32* [[T1:%.*]]
+ XXX = 12345;
+
+// Inline flag for BYREF variable layout (838860800): BLOCK_BYREF_HAS_COPY_DISPOSE BLOCK_BYREF_LAYOUT_STRONG
+// CHECK: store i32 838860800, i32* [[T2:%.*]]
+ ID = 0;
+
+// Inline flag for BYREF variable layout (268435456): BLOCK_BYREF_LAYOUT_EXTENDED
+// BYREF variable layout: BL_NON_OBJECT_WORD:3, BL_UNRETAINED:1, BL_OPERATOR:0
+// CHECK: store i32 268435456, i32* [[T3:%.*]]
+ import.iD = 3.14;
+
+ };
+ c();
+}
+
+// rdar://12787751
+typedef char mds_path_t[1024];
+void directVolumePerfWaitForStoreState()
+{
+ __block mds_path_t path;
+}
diff --git a/test/CodeGenObjC/block-var-layout.m b/test/CodeGenObjC/block-var-layout.m
index 71b14da..ab95231 100644
--- a/test/CodeGenObjC/block-var-layout.m
+++ b/test/CodeGenObjC/block-var-layout.m
@@ -1,5 +1,6 @@
-// RUN: %clang_cc1 -fblocks -fobjc-gc -triple x86_64-apple-darwin -fobjc-runtime=macosx-fragile-10.5 -O0 -emit-llvm %s -o %t-64.s
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s
+// RUN: %clang_cc1 -fblocks -fobjc-gc -triple x86_64-apple-darwin -fobjc-runtime=macosx-fragile-10.5 -O0 -print-ivar-layout -emit-llvm -o /dev/null %s > %t-64.layout
+// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.layout %s
+// rdar://12752901
struct S {
int i1;
@@ -46,8 +47,7 @@ void f() {
// Test 1
// byref int, short, char, char, char, id, id, strong void*, byref id
-// 01 35 10 00
-// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [4 x i8] c"\015\10\00"
+// CHECK-LP64: block variable layout for block: 0x01, 0x35, 0x10, 0x00
void (^b)() = ^{
byref_int = sh + ch+ch1+ch2 ;
x(bar);
@@ -60,7 +60,7 @@ void f() {
// Test 2
// byref int, short, char, char, char, id, id, strong void*, byref void*, byref id
// 01 36 10 00
-// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [4 x i8] c"\016\10\00"
+// CHECK-LP64: block variable layout for block: 0x01, 0x36, 0x10, 0x00
void (^c)() = ^{
byref_int = sh + ch+ch1+ch2 ;
x(bar);
@@ -76,7 +76,7 @@ void f() {
// byref int, short, char, char, char, id, id, byref void*, int, double, byref id
// 01 34 11 30 00
// FIXME: we'd get a better format here if we sorted by scannability, not just alignment
-// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [5 x i8] c"\014\11 \00"
+// CHECK-LP64: block variable layout for block: 0x01, 0x35, 0x30, 0x00
void (^d)() = ^{
byref_int = sh + ch+ch1+ch2 ;
x(bar);
@@ -91,7 +91,7 @@ void f() {
// Test 4
// struct S (int, id, int, id, int, id)
// 01 41 11 11 00
-// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [5 x i8] c"\01A\11\11\00"
+// CHECK-LP64: block variable layout for block: 0x01, 0x41, 0x11, 0x11, 0x00
struct S s2;
void (^e)() = ^{
x(s2.o1);
@@ -129,7 +129,7 @@ void Test5() {
// struct s2 (int, id, int, id, int, id?), union u2 (id?)
// 01 41 11 12 00
-// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [5 x i8] c"\01A\11\12\00"
+// CHECK-LP64: block variable layout for block: 0x01, 0x41, 0x11, 0x12, 0x00
void (^c)() = ^{
x(s2.ui.o1);
x(u2.o1);
@@ -146,7 +146,7 @@ void notifyBlock(id dependentBlock) {
// id, id, void(^)()
// 01 33 00
-// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [3 x i8] c"\013\00"
+// CHECK-LP64: block variable layout for block: 0x01, 0x33, 0x00
void (^wrapperBlock)() = ^() {
CFRelease(singleObservationToken);
CFRelease(singleObservationToken);
@@ -159,7 +159,7 @@ void notifyBlock(id dependentBlock) {
void test_empty_block() {
// 01 00
-// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [2 x i8] c"\01\00"
+// CHECK-LP64: block variable layout for block: 0x01, 0x00
void (^wrapperBlock)() = ^() {
};
wrapperBlock();
diff --git a/test/CodeGenObjC/blocks.m b/test/CodeGenObjC/blocks.m
index 6c85da9..3718ad5 100644
--- a/test/CodeGenObjC/blocks.m
+++ b/test/CodeGenObjC/blocks.m
@@ -57,9 +57,9 @@ void test2(Test2 *x) {
// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[WEAK_T]]* [[WEAKX]], i32 0, i32 1
// CHECK-NEXT: store [[WEAK_T]]* [[WEAKX]], [[WEAK_T]]** [[T1]]
- // Flags. This is just BLOCK_HAS_COPY_DISPOSE.
+ // Flags. This is just BLOCK_HAS_COPY_DISPOSE BLOCK_BYREF_LAYOUT_UNRETAINED
// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[WEAK_T]]* [[WEAKX]], i32 0, i32 2
- // CHECK-NEXT: store i32 33554432, i32* [[T2]]
+ // CHECK-NEXT: store i32 1375731712, i32* [[T2]]
// Size.
// CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [[WEAK_T]]* [[WEAKX]], i32 0, i32 3
@@ -93,10 +93,43 @@ void test2(Test2 *x) {
// doesn't require a read barrier.
// CHECK: define internal void @__test2_block_invoke
// CHECK: [[BLOCK:%.*]] = bitcast i8* {{%.*}} to [[BLOCK_T]]*
-// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
+// CHECK-NOT: bitcast
+// CHECK: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
// CHECK-NEXT: [[T1:%.*]] = load i8** [[T0]]
// CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to [[WEAK_T]]{{.*}}*
// CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [[WEAK_T]]{{.*}}* [[T2]], i32 0, i32 1
// CHECK-NEXT: [[T4:%.*]] = load [[WEAK_T]]{{.*}}** [[T3]]
// CHECK-NEXT: [[WEAKX:%.*]] = getelementptr inbounds [[WEAK_T]]{{.*}}* [[T4]], i32 0, i32 6
// CHECK-NEXT: [[T0:%.*]] = load [[TEST2]]** [[WEAKX]], align 4
+
+// rdar://problem/12722954
+// Make sure that ... is appropriately positioned in a block call.
+void test3(void (^block)(int, ...)) {
+ block(0, 1, 2, 3);
+}
+// CHECK: define void @test3(
+// CHECK: [[BLOCK:%.*]] = alloca void (i32, ...)*, align 4
+// CHECK-NEXT: store void (i32, ...)*
+// CHECK-NEXT: [[T0:%.*]] = load void (i32, ...)** [[BLOCK]], align 4
+// CHECK-NEXT: [[T1:%.*]] = bitcast void (i32, ...)* [[T0]] to [[BLOCK_T:%.*]]*
+// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[T1]], i32 0, i32 3
+// CHECK-NEXT: [[T3:%.*]] = bitcast [[BLOCK_T]]* [[T1]] to i8*
+// CHECK-NEXT: [[T4:%.*]] = load i8** [[T2]]
+// CHECK-NEXT: [[T5:%.*]] = bitcast i8* [[T4]] to void (i8*, i32, ...)*
+// CHECK-NEXT: call void (i8*, i32, ...)* [[T5]](i8* [[T3]], i32 0, i32 1, i32 2, i32 3)
+// CHECK-NEXT: ret void
+
+void test4(void (^block)()) {
+ block(0, 1, 2, 3);
+}
+// CHECK: define void @test4(
+// CHECK: [[BLOCK:%.*]] = alloca void (...)*, align 4
+// CHECK-NEXT: store void (...)*
+// CHECK-NEXT: [[T0:%.*]] = load void (...)** [[BLOCK]], align 4
+// CHECK-NEXT: [[T1:%.*]] = bitcast void (...)* [[T0]] to [[BLOCK_T:%.*]]*
+// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[T1]], i32 0, i32 3
+// CHECK-NEXT: [[T3:%.*]] = bitcast [[BLOCK_T]]* [[T1]] to i8*
+// CHECK-NEXT: [[T4:%.*]] = load i8** [[T2]]
+// CHECK-NEXT: [[T5:%.*]] = bitcast i8* [[T4]] to void (i8*, i32, i32, i32, i32)*
+// CHECK-NEXT: call void [[T5]](i8* [[T3]], i32 0, i32 1, i32 2, i32 3)
+// CHECK-NEXT: ret void
diff --git a/test/CodeGenObjC/boxing.m b/test/CodeGenObjC/boxing.m
index 9664298..87ff0e7 100644
--- a/test/CodeGenObjC/boxing.m
+++ b/test/CodeGenObjC/boxing.m
@@ -54,17 +54,17 @@ typedef signed char BOOL;
@end
// CHECK: [[WithIntMeth:@".*"]] = internal global [15 x i8] c"numberWithInt:\00"
-// CHECK: [[WithIntSEL:@".*"]] = internal global i8* getelementptr inbounds ([15 x i8]* [[WithIntMeth]]
+// CHECK: [[WithIntSEL:@".*"]] = internal externally_initialized global i8* getelementptr inbounds ([15 x i8]* [[WithIntMeth]]
// CHECK: [[WithCharMeth:@".*"]] = internal global [16 x i8] c"numberWithChar:\00"
-// CHECK: [[WithCharSEL:@".*"]] = internal global i8* getelementptr inbounds ([16 x i8]* [[WithCharMeth]]
+// CHECK: [[WithCharSEL:@".*"]] = internal externally_initialized global i8* getelementptr inbounds ([16 x i8]* [[WithCharMeth]]
// CHECK: [[WithBoolMeth:@".*"]] = internal global [16 x i8] c"numberWithBool:\00"
-// CHECK: [[WithBoolSEL:@".*"]] = internal global i8* getelementptr inbounds ([16 x i8]* [[WithBoolMeth]]
+// CHECK: [[WithBoolSEL:@".*"]] = internal externally_initialized global i8* getelementptr inbounds ([16 x i8]* [[WithBoolMeth]]
// CHECK: [[WithIntegerMeth:@".*"]] = internal global [19 x i8] c"numberWithInteger:\00"
-// CHECK: [[WithIntegerSEL:@".*"]] = internal global i8* getelementptr inbounds ([19 x i8]* [[WithIntegerMeth]]
+// CHECK: [[WithIntegerSEL:@".*"]] = internal externally_initialized global i8* getelementptr inbounds ([19 x i8]* [[WithIntegerMeth]]
// CHECK: [[WithUnsignedIntegerMeth:@".*"]] = internal global [27 x i8] c"numberWithUnsignedInteger:\00"
-// CHECK: [[WithUnsignedIntegerSEL:@".*"]] = internal global i8* getelementptr inbounds ([27 x i8]* [[WithUnsignedIntegerMeth]]
+// CHECK: [[WithUnsignedIntegerSEL:@".*"]] = internal externally_initialized global i8* getelementptr inbounds ([27 x i8]* [[WithUnsignedIntegerMeth]]
// CHECK: [[stringWithUTF8StringMeth:@".*"]] = internal global [22 x i8] c"stringWithUTF8String:\00"
-// CHECK: [[stringWithUTF8StringSEL:@".*"]] = internal global i8* getelementptr inbounds ([22 x i8]* [[stringWithUTF8StringMeth]]
+// CHECK: [[stringWithUTF8StringSEL:@".*"]] = internal externally_initialized global i8* getelementptr inbounds ([22 x i8]* [[stringWithUTF8StringMeth]]
int main() {
// CHECK: load i8** [[WithIntSEL]]
diff --git a/test/CodeGenObjC/catch-lexical-block.m b/test/CodeGenObjC/catch-lexical-block.m
index f4a6a22..618d3a2 100644
--- a/test/CodeGenObjC/catch-lexical-block.m
+++ b/test/CodeGenObjC/catch-lexical-block.m
@@ -7,10 +7,9 @@ void f0() {
}
}
-// We should have 4 lexical blocks here at the moment, including one
+// We should have 3 lexical blocks here at the moment, including one
// for the catch block.
// CHECK: lexical_block
// CHECK: lexical_block
-// CHECK: lexical_block
// CHECK: auto_variable
// CHECK: lexical_block
diff --git a/test/CodeGenObjC/complex-double-abi.m b/test/CodeGenObjC/complex-double-abi.m
index 08246d5..6353520 100644
--- a/test/CodeGenObjC/complex-double-abi.m
+++ b/test/CodeGenObjC/complex-double-abi.m
@@ -9,8 +9,7 @@ double _Complex foo(CNumber *x) {
return [x sum];
}
-// CHECK: [[T4:%.*]] = phi double [ 0.000000e+00, [[NULLINIT:%.*]] ], [ [[R1:%.*]], [[MSGCALL:%.*]] ]
-// CHECK: [[T5:%.*]] = phi double [ 0.000000e+00, [[NULLINIT:%.*]] ], [ [[I1:%.*]], [[MSGCALL:%.*]] ]
-
-// CHECK: store double [[T4]]
-// CHECK: store double [[T5]]
+// CHECK: [[R:%.*]] = phi double [ [[R1:%.*]], [[MSGCALL:%.*]] ], [ 0.000000e+00, [[NULLINIT:%.*]] ]
+// CHECK-NEXT: [[I:%.*]] = phi double [ [[I1:%.*]], [[MSGCALL]] ], [ 0.000000e+00, [[NULLINIT]] ]
+// CHECK: store double [[R]]
+// CHECK: store double [[I]]
diff --git a/test/CodeGenObjC/debug-info-block-captured-self.m b/test/CodeGenObjC/debug-info-block-captured-self.m
new file mode 100644
index 0000000..0316013
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-block-captured-self.m
@@ -0,0 +1,70 @@
+// RUN: %clang_cc1 -fblocks -g -emit-llvm -triple x86_64-apple-darwin -o - %s | FileCheck %s
+//
+// Test that debug location is generated for a captured "self" inside
+// a block.
+//
+// This test is split into two parts, this one for the frontend, and
+// then llvm/test/DebugInfo/debug-info-block-captured-self.ll to
+// ensure that DW_AT_location is generated for the captured self.
+@class T;
+@interface S
+@end
+@interface Mode
+-(int) count;
+@end
+@interface Context
+@end
+@interface ViewController
+@property (nonatomic, readwrite, strong) Context *context;
+@end
+typedef enum {
+ Unknown = 0,
+} State;
+@interface Main : ViewController
+{
+ T * t1;
+ T * t2;
+}
+@property(readwrite, nonatomic) State state;
+@end
+@implementation Main
+- (id) initWithContext:(Context *) context
+{
+ t1 = [self.context withBlock:^(id obj){
+ id *mode1;
+ t2 = [mode1 withBlock:^(id object){
+ Mode *mode2 = object;
+ if ([mode2 count] != 0) {
+ self.state = 0;
+ }
+ }];
+ }];
+}
+@end
+// The important part of this test is that there is a dbg.value
+// intrinsic associated with the implicit .block_descriptor argument
+// of the block. We also test that this value gets alloca'd, so the
+// register llocator won't accidentally kill it.
+
+// outer block:
+// CHECK: define internal void {{.*}}_block_invoke{{.*}}
+
+// inner block:
+// CHECK: define internal void {{.*}}_block_invoke{{.*}}
+// CHECK: %[[MEM1:.*]] = alloca i8*, align 8
+// CHECK-NEXT: %[[MEM2:.*]] = alloca i8*, align 8
+// CHECK: store i8* [[BLOCK_DESC:%.*]], i8** %[[MEM1]], align 8
+// CHECK: %[[TMP0:.*]] = load i8** %[[MEM1]]
+// CHECK: call void @llvm.dbg.value(metadata !{i8* %[[TMP0]]}, i64 0, metadata ![[BDMD:[0-9]+]])
+// CHECK: call void @llvm.dbg.declare(metadata !{i8* [[BLOCK_DESC]]}, metadata ![[BDMD:[0-9]+]])
+// CHECK: %[[TMP1:.*]] = bitcast
+// CHECK-NEXT: store
+// CHECK-NEXT: %[[TMP2:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %[[TMP1]]
+// CHECK: call void @llvm.dbg.declare(metadata !{<{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>** {{.*}}}, metadata ![[SELF:.*]])
+// make sure we are still in the same function
+// CHECK: define {{.*}}__copy_helper_block_
+// Metadata
+// CHECK: ![[MAIN:.*]] = {{.*}}!"Main"{{.*}}DW_TAG_structure_type{{.*}}line 23
+// CHECK: ![[PMAIN:.*]] = {{.*}}![[MAIN]]} ; [ DW_TAG_pointer_type ]{{.*}}from Main
+// CHECK: ![[BDMD]] = metadata {{.*}}.block_descriptor
+// CHECK: ![[SELF]] = {{.*}}![[PMAIN]]{{.*}}[ DW_TAG_auto_variable ] [self] [line 40]
diff --git a/test/CodeGenObjC/debug-info-block-helper.m b/test/CodeGenObjC/debug-info-block-helper.m
index cf8c2a2..49c8c5d 100644
--- a/test/CodeGenObjC/debug-info-block-helper.m
+++ b/test/CodeGenObjC/debug-info-block-helper.m
@@ -2,7 +2,7 @@
// RUN: %clang_cc1 -emit-llvm -fblocks -g -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 %s -o - | FileCheck %s
extern void foo(void(^)(void));
-// CHECK: metadata !{i32 786478, i32 0, metadata !27, metadata !"__destroy_helper_block_", metadata !"__destroy_helper_block_", metadata !"", metadata !27, i32 24, metadata !37, i1 true, i1 true, i32 0, i32 0, null, i32 0, i1 false, void (i8*)* @__destroy_helper_block_, null, null, metadata !5, i32 24} ; [ DW_TAG_subprogram ]
+// CHECK: [ DW_TAG_subprogram ] {{.*}} [__destroy_helper_block_]
@interface NSObject {
struct objc_object *isa;
diff --git a/test/CodeGenObjC/debug-info-block-line.m b/test/CodeGenObjC/debug-info-block-line.m
new file mode 100644
index 0000000..c913a97
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-block-line.m
@@ -0,0 +1,89 @@
+// REQUIRES: x86-64-registered-target
+// RUN: %clang_cc1 -emit-llvm -fblocks -fobjc-default-synthesize-properties -fobjc-arc -O0 -g -triple x86_64-apple-darwin10 %s -o - | FileCheck %s
+
+// rdar://11562117
+typedef unsigned int NSUInteger;
+typedef long NSInteger;
+typedef signed char BOOL;
+
+#define nil ((void*) 0)
+#define YES ((BOOL)1)
+#define NO ((BOOL)0)
+
+@interface NSObject
+- (id)init;
+@end
+
+@interface NSError : NSObject
+@end
+
+@interface NSString : NSObject
+@end
+
+@interface NSString (NSStringExtensionMethods)
+- (void)enumerateLinesUsingBlock:(void (^)(NSString *line, BOOL *stop))block;
+@end
+
+@interface NSData : NSObject
+@end
+
+@interface NSData (ASBase64)
+- (NSString *)encodedString:(NSInteger)position;
+- (NSData *)compressedData;
+@end
+
+typedef void (^TDataCompletionBlock)(NSData *data, NSError *error);
+@interface TMap : NSObject
+- (NSString *)identifier;
+- (NSString *)name;
++ (TMap *)mapForID:(NSString *)identifier;
+- (void)dataWithCompletionBlock:(TDataCompletionBlock)block;
+@end
+
+typedef enum : NSUInteger {
+ TOK = 100,
+ TError = 125,
+} TResponseCode;
+
+@interface TConnection : NSObject
+- (void)sendString:(NSString *)string;
+- (void)sendFormat:(NSString *)format, ...;
+- (void)sendResponseCode:(TResponseCode)responseCode dataFollows:(BOOL)flag
+ format:(NSString *)format, ...;
+@end
+
+@interface TServer : NSObject
+@end
+
+@implementation TServer
+- (void)serverConnection:(TConnection *)connection getCommand:(NSString *)str
+{
+ NSString *mapID = nil;
+ TMap *map = [TMap mapForID:mapID];
+// Make sure we do not map code generated for the block to the above line.
+// CHECK: define internal void @"__39-[TServer serverConnection:getCommand:]_block_invoke"
+// CHECK: call void @objc_storeStrong(i8** [[ZERO:%.*]], i8* [[ONE:%.*]]) [[NUW:#[0-9]+]]
+// CHECK: call void @objc_storeStrong(i8** [[TWO:%.*]], i8* [[THREE:%.*]]) [[NUW]]
+// CHECK: bitcast %5** [[TMP:%.*]] to i8**
+// CHECK: call void @objc_storeStrong(i8** [[VAL1:%.*]], i8* null) [[NUW]], !dbg ![[MD1:.*]]
+// CHECK: bitcast %4** [[TMP:%.*]] to i8**
+// CHECK: call void @objc_storeStrong(i8** [[VAL2:%.*]], i8* null) [[NUW]], !dbg ![[MD1]]
+// CHECK-NEXT: ret
+// CHECK: attributes [[NUW]] = { nounwind }
+// CHECK: ![[MD1]] = metadata !{i32 87
+ [map dataWithCompletionBlock:^(NSData *data, NSError *error) {
+ if (data) {
+ NSString *encoded = [[data compressedData] encodedString:18];
+ [connection sendResponseCode:TOK dataFollows:YES
+ format:@"Sending \"%@\" (%@)", [map name], [map identifier]];
+ [encoded enumerateLinesUsingBlock:^(NSString *line, BOOL *stop) {
+ [connection sendFormat:@"%@\r\n", line];
+ }];
+ [connection sendString:@".\r\n"];
+ } else {
+ [connection sendResponseCode:TError dataFollows:NO
+ format:@"Failed \"%@\" (%@)", [map name], [map identifier]];
+ }
+ }];
+}
+@end
diff --git a/test/CodeGenObjC/debug-info-blocks.m b/test/CodeGenObjC/debug-info-blocks.m
index 71ae8a6..f50ddf0 100644
--- a/test/CodeGenObjC/debug-info-blocks.m
+++ b/test/CodeGenObjC/debug-info-blocks.m
@@ -1,9 +1,17 @@
-// REQUIRES: x86-64-registered-target
-// RUN: %clang_cc1 -masm-verbose -S -fblocks -g -triple x86_64-apple-darwin10 -fobjc-dispatch-method=mixed %s -o - | FileCheck %s
-
-//Radar 9279956
-//CHECK: ## DW_OP_deref
-//CHECK-NEXT: ## DW_OP_plus_uconst
+// RUN: %clang_cc1 -emit-llvm -fblocks -g -triple x86_64-apple-darwin10 -fobjc-dispatch-method=mixed %s -o - | FileCheck %s
+
+// rdar://problem/9279956
+// Test that we generate the proper debug location for a captured self.
+// The second half of this patch is in llvm/tests/DebugInfo/debug-info-blocks.ll
+
+// CHECK: define {{.*}}_block_invoke
+// CHECK: %[[BLOCK:.*]] = bitcast i8* %.block_descriptor to <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>*, !dbg
+// CHECK-NEXT: store <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %[[BLOCK]], <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>** %[[ALLOCA:.*]], align
+// CHECK-NEXT: getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %[[BLOCK]], i32 0, i32 5
+// CHECK-NEXT: call void @llvm.dbg.declare(metadata !{<{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>** %[[ALLOCA]]}, metadata ![[SELF:[0-9]+]])
+// CHECK-NEXT: call void @llvm.dbg.declare(metadata !{%1** %d}, metadata ![[D:[0-9]+]])
+// CHECK: ![[SELF]] = {{.*}} [ DW_TAG_auto_variable ] [self] [line 52]
+// CHECK: ![[D]] = {{.*}} [d] [line 50]
typedef unsigned int NSUInteger;
diff --git a/test/CodeGenObjC/debug-info-fwddecl.m b/test/CodeGenObjC/debug-info-fwddecl.m
index 8f2860c..b41c485 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, i64 0, i64 0, i32 0, i32 4, null, null, i32 16} ; [ DW_TAG_structure_type ]
+// CHECK: {{.*}} [ DW_TAG_structure_type ] [ForwardObjcClass] [line 2, size 0, align 0, offset 0] [fwd]
diff --git a/test/CodeGenObjC/debug-info-id-with-protocol.m b/test/CodeGenObjC/debug-info-id-with-protocol.m
new file mode 100644
index 0000000..db1a3ef
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-id-with-protocol.m
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-default-synthesize-properties -emit-llvm -g %s -o - | FileCheck %s
+__attribute((objc_root_class)) @interface NSObject {
+ id isa;
+}
++ (id)alloc;
+- (id)init;
+- (id)retain;
+@end
+
+void NSLog(id, ...);
+
+@protocol MyProtocol
+
+-(const char *)hello;
+
+@end
+
+@interface MyClass : NSObject {
+}
+
+@property (nonatomic, assign) id <MyProtocol> bad_carrier;
+@property (nonatomic, assign) id good_carrier;
+
+@end
+
+@implementation MyClass
+@end
+
+int main()
+{
+ @autoreleasepool
+ {
+ MyClass *my_class = [MyClass alloc];
+ NSLog(@"%p\n", my_class.bad_carrier);
+ NSLog(@"%p\n", my_class.good_carrier);
+ }
+}
+// Verify that the debug type for both variables is 'id'.
+// CHECK: metadata !{i32 {{[0-9]+}}, metadata !{{[0-9]+}}, metadata !"bad_carrier", metadata !{{[0-9]+}}, i32 {{[0-9]+}}, metadata ![[IDTYPE:[0-9]+]], i32 0, i32 0} ; [ DW_TAG_arg_variable ] [bad_carrier] [line 21]
+// CHECK: metadata !{i32 {{[0-9]+}}, metadata !{{[0-9]+}}, metadata !"good_carrier", metadata !{{[0-9]+}}, i32 {{[0-9]+}}, metadata !{{.*}}[[IDTYPE]], i32 0, i32 0} ; [ DW_TAG_arg_variable ] [good_carrier] [line 22]
+// CHECK !{{.*}}[[IDTYPE]] = metadata !{i32 {{[0-9]+}}, null, metadata !"id", metadata !{{[0-9]+}}, i32 !{{[0-9]+}}, i64 0, i64 0, i64 0, i32 0, metadata !{{[0-9]+}}} ; [ DW_TAG_typedef ] [id]
diff --git a/test/CodeGenObjC/debug-info-impl.m b/test/CodeGenObjC/debug-info-impl.m
index a8450dd..8991a88 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, i32 0} ; [ DW_TAG_structure_type ]
+// CHECK: {{.*}} [ DW_TAG_structure_type ] [Circle] [line 11,
@interface NSObject {
struct objc_object *isa;
}
diff --git a/test/CodeGenObjC/debug-info-ivars-extension.m b/test/CodeGenObjC/debug-info-ivars-extension.m
new file mode 100644
index 0000000..e43b598
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-ivars-extension.m
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -g %s -o - | FileCheck %s
+
+// Make sure we generate debug symbols for ivars added by a class extension.
+
+@interface I
+{
+ @public int a;
+}
+@end
+
+void foo(I* pi) {
+ // poking into pi for primary class ivars.
+ int _a = pi->a;
+}
+
+@interface I()
+{
+ @public int b;
+}
+@end
+
+void gorf (I* pg) {
+ // poking into pg for ivars for class extension
+ int _b = pg->b;
+}
+
+// CHECK: {{.*}} [ DW_TAG_structure_type ] [I]
+// Check for "a".
+// CHECK: {{.*}} [ DW_TAG_member ] [a] [line 7, size 32, align 32, offset 0] [from int]
+// Make sure we don't output the same type twice.
+// CHECK-NOT: {{.*}} [ DW_TAG_structure_type ] [I]
+// Check for "b".
+// CHECK: {{.*}} [ DW_TAG_member ] [b] [line 18, size 32, align 32, offset 0] [from int]
diff --git a/test/CodeGenObjC/debug-info-ivars-indirect.m b/test/CodeGenObjC/debug-info-ivars-indirect.m
new file mode 100644
index 0000000..1548ddd
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-ivars-indirect.m
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -g %s -o - | FileCheck %s
+
+// Make sure we generate debug symbols for an indirectly referenced
+// extension to an interface.
+
+@interface I
+{
+ @public int a;
+}
+@end
+
+void foo(I* pi) {
+ int _a = pi->a;
+}
+
+// another layer of indirection
+struct S
+{
+ I* i;
+};
+
+@interface I()
+{
+ @public int b;
+}
+@end
+
+void gorf (struct S* s) {
+ int _b = s->i->b;
+}
+
+// CHECK: {{.*}} [ DW_TAG_member ] [b] [line 24, size 32, align 32, offset 0] [from int]
diff --git a/test/CodeGenObjC/debug-info-ivars-private.m b/test/CodeGenObjC/debug-info-ivars-private.m
new file mode 100644
index 0000000..8505da1
--- /dev/null
+++ b/test/CodeGenObjC/debug-info-ivars-private.m
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -g %s -o - | FileCheck %s
+
+// Debug symbols for private ivars. This test ensures that we are
+// generating debug info for ivars added by the implementation.
+__attribute((objc_root_class)) @interface NSObject {
+ id isa;
+}
+@end
+
+@protocol Protocol
+@end
+
+@interface Delegate : NSObject<Protocol> {
+ @protected int foo;
+}
+@end
+
+@interface Delegate(NSObject)
+- (void)f;
+@end
+
+@implementation Delegate(NSObject)
+- (void)f { return; }
+@end
+
+@implementation Delegate {
+ int bar;
+}
+
+- (void)g:(NSObject*) anObject {
+ bar = foo;
+}
+@end
+
+// CHECK: {{.*}} [ DW_TAG_member ] [foo] [line 14, size 32, align 32, offset 0] [protected] [from int]
+// CHECK: {{.*}} [ DW_TAG_member ] [bar] [line 27, size 32, align 32, offset 0] [private] [from int]
diff --git a/test/CodeGenObjC/debug-info-ivars.m b/test/CodeGenObjC/debug-info-ivars.m
index 24705e1a..a0f2963 100644
--- a/test/CodeGenObjC/debug-info-ivars.m
+++ b/test/CodeGenObjC/debug-info-ivars.m
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -g %s -o - | FileCheck %s
__attribute((objc_root_class)) @interface NSObject {
- id isa;
+ id isa;
}
@end
@@ -10,15 +10,15 @@ __attribute((objc_root_class)) @interface NSObject {
int i;
unsigned flag_1 : 9;
unsigned flag_2 : 9;
- unsigned : 1;
- unsigned flag_3 : 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
+// CHECK: {{.*}} [ DW_TAG_member ] [i] [line 10, size 32, align 32, offset 0] [protected] [from int]
+// CHECK: {{.*}} [ DW_TAG_member ] [flag_1] [line 11, size 9, align 32, offset 0] [protected] [from unsigned int]
+// CHECK: {{.*}} [ DW_TAG_member ] [flag_2] [line 12, size 9, align 32, offset 1] [protected] [from unsigned int]
+// CHECK: {{.*}} [ DW_TAG_member ] [flag_3] [line 14, size 9, align 32, offset 3] [protected] [from unsigned int]
diff --git a/test/CodeGenObjC/debug-info-property3.m b/test/CodeGenObjC/debug-info-property3.m
index f96ec44..f63e744 100644
--- a/test/CodeGenObjC/debug-info-property3.m
+++ b/test/CodeGenObjC/debug-info-property3.m
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -S -emit-llvm -g %s -o - | FileCheck %s
-// CHECK: metadata !"p1", metadata !6, i32 5, metadata !"", metadata !"", i32 2316, metadata !9} ; [ DW_TAG_APPLE_property ]
+// CHECK: metadata !"p1", metadata !{{.*}}, i32 5, metadata !"", metadata !"", i32 2316, metadata !{{.*}}} ; [ DW_TAG_APPLE_property ]
@interface I1
@property int p1;
@end
diff --git a/test/CodeGenObjC/debug-info-pubtypes.m b/test/CodeGenObjC/debug-info-pubtypes.m
index 91d9cd1..8b7dfad 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
-// 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 ]
+// CHECK: {{.*}} [ DW_TAG_structure_type ] [H] [line 6,
@interface H
-(void) foo;
diff --git a/test/CodeGenObjC/debug-info-self.m b/test/CodeGenObjC/debug-info-self.m
index 9f23435..7803467 100644
--- a/test/CodeGenObjC/debug-info-self.m
+++ b/test/CodeGenObjC/debug-info-self.m
@@ -2,11 +2,6 @@
// self and _cmd are marked as DW_AT_artificial.
// 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;
@@ -18,3 +13,11 @@
return self;
}
@end
+
+// It's weird that the first two parameters are recorded as being in a
+// different, ("<unknown>") file compared to the third parameter which is 'in'
+// the actual source file. (see the metadata node after the arg name in each
+// line)
+// CHECK: metadata !{i32 {{.*}}, metadata ![[CTOR:.*]], metadata !"self", metadata ![[UNKFILE:.*]], i32 16777227, metadata !{{.*}}, i32 1088, i32 0} ; [ DW_TAG_arg_variable ] [self] [line 11]
+// CHECK: metadata !{i32 {{.*}}, metadata ![[CTOR]], metadata !"_cmd", metadata ![[UNKFILE]], i32 33554443, metadata !{{.*}}, i32 64, i32 0} ; [ DW_TAG_arg_variable ] [_cmd] [line 11]
+// CHECK: metadata !{i32 {{.*}}, metadata ![[CTOR]], metadata !"myarg", metadata !{{.*}}, i32 50331659, metadata !{{.*}}, i32 0, i32 0} ; [ DW_TAG_arg_variable ] [myarg] [line 11]
diff --git a/test/CodeGenObjC/debug-info-static-var.m b/test/CodeGenObjC/debug-info-static-var.m
index 8602ffb..2c10d59 100644
--- a/test/CodeGenObjC/debug-info-static-var.m
+++ b/test/CodeGenObjC/debug-info-static-var.m
@@ -1,14 +1,8 @@
-// REQUIRES: x86-64-registered-target
-// RUN: %clang_cc1 -g -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 -S -masm-verbose -o - %s | FileCheck %s
+// RUN: %clang_cc1 -g -emit-llvm -o - %s | FileCheck %s
// Radar 8801045
// Do not emit AT_MIPS_linkage_name for static variable i
-// CHECK: Lset6 = Lstring3-Lsection_str ## DW_AT_name
-// CHECK-NEXT: .long Lset6
-// CHECK-NEXT: DW_AT_type
-// CHECK-NEXT: DW_AT_decl_file
-// CHECK-NEXT: DW_AT_decl_line
-// CHECK-NEXT: DW_AT_location
+// CHECK: metadata !"i", metadata !"i", metadata !""
@interface A {
}
diff --git a/test/CodeGenObjC/debug-info-synthesis.m b/test/CodeGenObjC/debug-info-synthesis.m
index bf8e6d1..1bf7576 100644
--- a/test/CodeGenObjC/debug-info-synthesis.m
+++ b/test/CodeGenObjC/debug-info-synthesis.m
@@ -30,5 +30,5 @@ int main(int argc, char *argv[]) {
}
}
-// CHECK: !7 = metadata !{i32 {{.*}}, metadata !"./foo.h"
-// CHECK: !29 = metadata !{i32 {{.*}}, i32 0, metadata !7, metadata !"-[Foo dict]", metadata !"-[Foo dict]", metadata !"", metadata !7, i32 8, metadata !30, i1 true, i1 true, i32 0, i32 0, null, i32 320, i1 false, %1* (%0*, i8*)* @"\01-[Foo dict]", null, null, metadata !1, i32 8} ; [ DW_TAG_subprogram ]
+// CHECK: ![[FILE:.*]] = {{.*}}[ DW_TAG_file_type ] [{{.*}}/foo.h]
+// CHECK: metadata ![[FILE]], {{.*}} ; [ DW_TAG_subprogram ] [line 8] [local] [def] [-[Foo dict]]
diff --git a/test/CodeGenObjC/encode-test-6.m b/test/CodeGenObjC/encode-test-6.m
index 10681db..b7feb14 100644
--- a/test/CodeGenObjC/encode-test-6.m
+++ b/test/CodeGenObjC/encode-test-6.m
@@ -17,3 +17,21 @@ typedef struct {} Z;
// CHECK: internal global [14 x i8] c"v16@0:8{?=}16
// CHECK: internal global [26 x i8] c"v32@0:8{?=}16*16{?=}24d24
+
+// rdar://13190095
+@interface NSObject @end
+
+@class BABugExample;
+typedef BABugExample BABugExampleRedefinition;
+
+@interface BABugExample : NSObject {
+ BABugExampleRedefinition *_property; // .asciz "^{BABugExample=^{BABugExample}}"
+}
+@property (copy) BABugExampleRedefinition *property;
+@end
+
+@implementation BABugExample
+@synthesize property = _property;
+@end
+
+// CHECK: internal global [24 x i8] c"^{BABugExample=@}16
diff --git a/test/CodeGenObjC/encode-test.m b/test/CodeGenObjC/encode-test.m
index 3780068..e8d6541 100644
--- a/test/CodeGenObjC/encode-test.m
+++ b/test/CodeGenObjC/encode-test.m
@@ -165,3 +165,7 @@ const char g10[] = @encode(struct f);
// rdar://9622422
// CHECK: @g11 = constant [2 x i8] c"v\00"
const char g11[] = @encode(void);
+
+// PR14628
+// CHECK: @g12 = constant [3 x i8] c"Ai\00"
+const char g12[] = @encode(_Atomic(int));
diff --git a/test/CodeGenObjC/exceptions.m b/test/CodeGenObjC/exceptions.m
index 551e67c..408b94d 100644
--- a/test/CodeGenObjC/exceptions.m
+++ b/test/CodeGenObjC/exceptions.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 -emit-llvm -fexceptions -fobjc-exceptions -O2 -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 -emit-llvm -fobjc-exceptions -O2 -o - %s | FileCheck %s
//
// <rdar://problem/7471679> [irgen] [eh] Exception code built with clang (x86_64) crashes
@@ -28,7 +28,7 @@ void f1() {
// CHECK: call void asm sideeffect "", "*m"
// CHECK-NEXT: call void @foo()
foo();
- // CHECK-NEXT: call void @objc_exception_try_exit
+ // CHECK: call void @objc_exception_try_exit
// CHECK: call void asm sideeffect "", "=*m"
} @finally {
diff --git a/test/CodeGenObjC/extended-block-signature-encode.m b/test/CodeGenObjC/extended-block-signature-encode.m
new file mode 100644
index 0000000..a380856
--- /dev/null
+++ b/test/CodeGenObjC/extended-block-signature-encode.m
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin -fencode-extended-block-signature -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin -emit-llvm %s -o - | FileCheck %s -check-prefix=BRIEF
+// rdar://12109031
+
+@class NSString, NSArray;
+
+typedef NSString*(^BBB)(NSArray*);
+
+int main ()
+{
+ BBB b1;
+ ^(BBB arg1, double arg2){ return b1; }(0, 3.14);
+}
+// CHECK: @{{.*}} = private unnamed_addr constant [64 x i8] c"@?<@\22NSString\22@?@\22NSArray\22>24@?0@?<@\22NSString\22@?@\22NSArray\22>8d16\00"
+// CHECK-BRIEF: @{{.*}} = private unnamed_addr constant [14 x i8] c"@?24@?0@?8d16\00"
diff --git a/test/CodeGenObjC/externally-initialized-selectors.m b/test/CodeGenObjC/externally-initialized-selectors.m
new file mode 100644
index 0000000..87a7c04
--- /dev/null
+++ b/test/CodeGenObjC/externally-initialized-selectors.m
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -cc1 -fobjc-runtime=macosx-fragile-10.5 -o - -emit-llvm %s | FileCheck %s
+// RUN: %clang_cc1 -cc1 -o - -emit-llvm %s | FileCheck %s
+
+// CHECK: @"\01L_OBJC_SELECTOR_REFERENCES_" = internal externally_initialized global
+
+void test(id x) {
+ [x doSomething];
+}
diff --git a/test/CodeGenObjC/gc.m b/test/CodeGenObjC/gc.m
index b672181..ce2611e 100644
--- a/test/CodeGenObjC/gc.m
+++ b/test/CodeGenObjC/gc.m
@@ -9,6 +9,8 @@ void test0(void) {
// CHECK-NEXT: store i8* [[T0]], i8** [[X:%.*]], align 8
// CHECK-NEXT: call i8* @test0_helper()
// CHECK-NEXT: [[T0:%.*]] = load i8** [[X]], align 8
- // CHECK-NEXT: call void asm sideeffect "", "r"(i8* [[T0]]) nounwind
+ // CHECK-NEXT: call void asm sideeffect "", "r"(i8* [[T0]]) [[NUW:#[0-9]+]]
// CHECK-NEXT: ret void
}
+
+// CHECK: attributes [[NUW]] = { nounwind }
diff --git a/test/CodeGenObjC/gnu-exceptions.m b/test/CodeGenObjC/gnu-exceptions.m
index b7d0adb..7aa9709 100644
--- a/test/CodeGenObjC/gnu-exceptions.m
+++ b/test/CodeGenObjC/gnu-exceptions.m
@@ -1,11 +1,12 @@
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -fexceptions -fobjc-exceptions -fobjc-runtime=gcc -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-freebsd -emit-llvm -fexceptions -fobjc-exceptions -fobjc-runtime=gnustep-1.7 -o - %s | FileCheck -check-prefix=NEW-ABI %s
void opaque(void);
void log(int i);
@class C;
-// CHECK: define void @test0() {
+// CHECK: define void @test0() [[TF:#[0-9]+]] {
void test0() {
@try {
// CHECK: invoke void @opaque()
@@ -21,9 +22,13 @@ void test0() {
// CHECK: call void @log(i32 0)
// CHECK: resume
+ // NEW-ABI: objc_begin_catch
+ // NEW-ABI: objc_end_catch
log(0);
}
log(1);
}
+
+// CHECK: attributes [[TF]] = { "{{.*}} }
diff --git a/test/CodeGenObjC/interface-layout-64.m b/test/CodeGenObjC/interface-layout-64.m
index 16361a2..4b41cf8 100644
--- a/test/CodeGenObjC/interface-layout-64.m
+++ b/test/CodeGenObjC/interface-layout-64.m
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
-// RUNX: llvm-gcc -m64 -emit-llvm -S -o %t %s &&
// CHECK: @"OBJC_IVAR_$_I3._iv2" = global i64 8, section "__DATA, __objc_ivar", align 8
// CHECK: @"OBJC_IVAR_$_I3._iv3" = global i64 12, section "__DATA, __objc_ivar", align 8
diff --git a/test/CodeGenObjC/ivar-invariant.m b/test/CodeGenObjC/ivar-invariant.m
new file mode 100644
index 0000000..7cafee7
--- /dev/null
+++ b/test/CodeGenObjC/ivar-invariant.m
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fblocks -emit-llvm -o - %s | FileCheck %s
+
+@interface NSObject
++ (id) new;
+- (id) init;
+@end
+
+@interface Base : NSObject @end
+
+// @implementation Base
+// {
+// int dummy;
+// }
+// @end
+
+@interface Derived : Base
+{
+ @public int member;
+}
+@end
+
+@implementation Derived
+- (id) init
+{
+ self = [super init];
+ member = 42;
+ return self;
+}
+@end
+
+// CHECK: define internal i8* @"\01-[Derived init]"
+// CHECK: [[IVAR:%.*]] = load i64* @"OBJC_IVAR_$_Derived.member", !invariant.load
+
+void * variant_load_1(int i) {
+ void *ptr;
+ while (i--) {
+ Derived *d = [Derived new];
+ ptr = &d->member;
+ }
+ return ptr;
+}
+
+// CHECK: define i8* @variant_load_1(i32 %i)
+// CHECK: [[IVAR:%.*]] = load i64* @"OBJC_IVAR_$_Derived.member"{{$}}
+
+@interface Container : Derived @end
+@implementation Container
+- (void *) invariant_load_1
+{
+ return &self->member;
+}
+@end
+
+// CHECK: define internal i8* @"\01-[Container invariant_load_1]"
+// CHECK: [[IVAR:%.*]] = load i64* @"OBJC_IVAR_$_Derived.member", !invariant.load
+
+@interface ForBlock
+{
+@public
+ id foo;
+}
+@end
+
+// CHECK: define internal i8* @block_block_invoke
+// CHECK: load i64* @"OBJC_IVAR_$_ForBlock.foo"
+id (^block)(ForBlock*) = ^(ForBlock* a) {
+ return a->foo;
+};
diff --git a/test/CodeGenObjC/metadata-symbols-32.m b/test/CodeGenObjC/metadata-symbols-32.m
index 1df1560..e8d2512 100644
--- a/test/CodeGenObjC/metadata-symbols-32.m
+++ b/test/CodeGenObjC/metadata-symbols-32.m
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-runtime=macosx-fragile-10.5 -emit-llvm -o %t %s
-// RUNX: llvm-gcc -m32 -emit-llvm -S -o %t %s &&
// RUN: grep '@"\\01L_OBJC_CATEGORY_A_Cat" = internal global .*section "__OBJC,__category,regular,no_dead_strip", align 4' %t
// RUN: grep '@"\\01L_OBJC_CATEGORY_CLASS_METHODS_A_Cat" = internal global .*section "__OBJC,__cat_cls_meth,regular,no_dead_strip", align 4' %t
@@ -24,7 +23,7 @@
// RUN: grep '@"\\01L_OBJC_PROTOCOL_CLASS_METHODS_P" = internal global .*section "__OBJC,__cat_cls_meth,regular,no_dead_strip", align 4' %t
// RUN: grep '@"\\01L_OBJC_PROTOCOL_INSTANCE_METHODS_P" = internal global .*section "__OBJC,__cat_inst_meth,regular,no_dead_strip", align 4' %t
// RUN: grep '@"\\01L_OBJC_PROTOCOL_P" = internal global .*section "__OBJC,__protocol,regular,no_dead_strip", align 4' %t
-// RUN: grep '@"\\01L_OBJC_SELECTOR_REFERENCES_[0-9]*" = internal global .*section "__OBJC,__message_refs,literal_pointers,no_dead_strip", align 4' %t
+// RUN: grep '@"\\01L_OBJC_SELECTOR_REFERENCES_[0-9]*" = internal externally_initialized global .*section "__OBJC,__message_refs,literal_pointers,no_dead_strip", align 4' %t
// RUN: grep '@"\\01L_OBJC_SYMBOLS" = internal global .*section "__OBJC,__symbols,regular,no_dead_strip", align 4' %t
// RUN: grep '@"\\01l_OBJC_$_PROP_LIST_A" = internal global .*section "__OBJC,__property,regular,no_dead_strip", align 4' %t
// RUN: grep "\.lazy_reference \.objc_class_name_J0" %t
diff --git a/test/CodeGenObjC/metadata-symbols-64.m b/test/CodeGenObjC/metadata-symbols-64.m
index 57f5d50..27017b7 100644
--- a/test/CodeGenObjC/metadata-symbols-64.m
+++ b/test/CodeGenObjC/metadata-symbols-64.m
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-dispatch-method=mixed -emit-llvm -o %t %s
-// RUNX: llvm-gcc -m64 -emit-llvm -S -o %t %s &&
// RUN: grep '@"OBJC_CLASS_$_A" = global' %t
// RUN: grep '@"OBJC_CLASS_$_B" = external global' %t
@@ -13,7 +12,7 @@
// RUN: grep '@"\\01L_OBJC_METH_VAR_NAME_[0-9]*" = internal global .* section "__TEXT,__objc_methname,cstring_literals", align 1' %t
// RUN: grep '@"\\01L_OBJC_METH_VAR_TYPE_[0-9]*" = internal global .* section "__TEXT,__objc_methtype,cstring_literals", align 1' %t
// RUN: grep '@"\\01L_OBJC_PROP_NAME_ATTR_[0-9]*" = internal global .* section "__TEXT,__cstring,cstring_literals", align 1' %t
-// RUN: grep '@"\\01L_OBJC_SELECTOR_REFERENCES_*" = internal global .* section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"' %t
+// RUN: grep '@"\\01L_OBJC_SELECTOR_REFERENCES_*" = internal externally_initialized global .* section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip"' %t
// RUN: grep '@"\\01l_OBJC_$_CATEGORY_A_$_Cat" = internal global .* section "__DATA, __objc_const", align 8' %t
// RUN: grep '@"\\01l_OBJC_$_CATEGORY_CLASS_METHODS_A_$_Cat" = internal global .* section "__DATA, __objc_const", align 8' %t
// RUN: grep '@"\\01l_OBJC_$_CATEGORY_INSTANCE_METHODS_A_$_Cat" = internal global .* section "__DATA, __objc_const", align 8' %t
diff --git a/test/CodeGenObjC/mrr-captured-block-var-inlined-layout.m b/test/CodeGenObjC/mrr-captured-block-var-inlined-layout.m
index f1e02dd..bb3a20b 100644
--- a/test/CodeGenObjC/mrr-captured-block-var-inlined-layout.m
+++ b/test/CodeGenObjC/mrr-captured-block-var-inlined-layout.m
@@ -1,5 +1,8 @@
-// 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
+// RUN: %clang_cc1 -fblocks -fobjc-runtime-has-weak -triple x86_64-apple-darwin -O0 -print-ivar-layout -emit-llvm -o /dev/null %s > %t-64.layout
+// RUN: FileCheck --input-file=%t-64.layout %s
+// RUN: %clang_cc1 -fblocks -fobjc-runtime-has-weak -triple i386-apple-darwin -O0 -print-ivar-layout -emit-llvm -o /dev/null %s > %t-32.layout
+// RUN: FileCheck -check-prefix=CHECK-i386 --input-file=%t-32.layout %s
+// rdar://12184410
// rdar://12184410
void x(id y) {}
@@ -16,25 +19,25 @@ void f() {
__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"
+// block variable layout: BL_STRONG:1, BL_OPERATOR:0
+// CHECK: Inline instruction for block variable layout: 0x0100
+// CHECK-i386: Inline instruction for block variable layout: 0x0100
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"
+// block variable layout: BL_STRONG:2, BL_BYREF:1, BL_OPERATOR:0
+// CHECK: Inline instruction for block variable layout: 0x0210
+// CHECK-i386: Inline instruction for block variable layout: 0x0210
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
+// block variable layout: BL_STRONG:2, BL_BYREF:3, BL_OPERATOR:0
+// CHECK: Inline instruction for block variable layout: 0x0230
+// CHECK-i386: Inline instruction for block variable layout: 0x0230
void (^d)() = ^{
x(bar);
x(baz);
@@ -43,9 +46,9 @@ void f() {
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"
+// block variable layout: BL_STRONG:2, BL_BYREF:3, BL_OPERATOR:0
+// CHECK: Inline instruction for block variable layout: 0x0230
+// CHECK-i386: Inline instruction for block variable layout: 0x0230
id (^e)() = ^{
x(bar);
x(baz);
@@ -55,9 +58,8 @@ void f() {
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 }
+// CHECK: Inline instruction for block variable layout: 0x020
+// CHECK-i386: Inline instruction for block variable layout: 0x020
void (^ii)() = ^{
byref_int = 1;
byref_bab = 0;
diff --git a/test/CodeGenObjC/non-lazy-classes.m b/test/CodeGenObjC/non-lazy-classes.m
index 5d82901..d95cb78d 100644
--- a/test/CodeGenObjC/non-lazy-classes.m
+++ b/test/CodeGenObjC/non-lazy-classes.m
@@ -1,4 +1,3 @@
-// RUNX: llvm-gcc -m64 -emit-llvm -S -o %t %s &&
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o %t %s
// RUN: grep '@".01L_OBJC_LABEL_NONLAZY_CLASS_$" = internal global \[1 x .*\] .*@"OBJC_CLASS_$_A".*, section "__DATA, __objc_nlclslist, regular, no_dead_strip", align 8' %t
// RUN: grep '@".01L_OBJC_LABEL_NONLAZY_CATEGORY_$" = internal global \[1 x .*\] .*@".01l_OBJC_$_CATEGORY_A_$_Cat".*, section "__DATA, __objc_nlcatlist, regular, no_dead_strip", align 8' %t
diff --git a/test/CodeGenObjC/nonlazy-msgSend.m b/test/CodeGenObjC/nonlazy-msgSend.m
index 7c349b2..0ae9f11 100644
--- a/test/CodeGenObjC/nonlazy-msgSend.m
+++ b/test/CodeGenObjC/nonlazy-msgSend.m
@@ -1,6 +1,8 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-runtime=macosx-fragile-10.5 -emit-llvm -o %t %s
-// RUN: grep -F 'declare i8* @objc_msgSend(i8*, i8*, ...) nonlazybind' %t
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fobjc-runtime=macosx-fragile-10.5 -emit-llvm %s -o - | FileCheck %s
+// CHECK: declare i8* @objc_msgSend(i8*, i8*, ...) [[NLB:#[0-9]+]]
void f0(id x) {
[x foo];
}
+
+// CHECK: attributes [[NLB]] = { nonlazybind }
diff --git a/test/CodeGenObjC/ns_consume_null_check.m b/test/CodeGenObjC/ns_consume_null_check.m
index a8e5acd..6a31a80 100644
--- a/test/CodeGenObjC/ns_consume_null_check.m
+++ b/test/CodeGenObjC/ns_consume_null_check.m
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fobjc-dispatch-method=mixed -o - %s | FileCheck %s
-// rdar://10444476
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fobjc-dispatch-method=mixed -fobjc-runtime-has-weak -fexceptions -o - %s | FileCheck %s
@interface NSObject
- (id) new;
@@ -7,26 +6,80 @@
@interface MyObject : NSObject
- (char)isEqual:(id) __attribute__((ns_consumed)) object;
+- (_Complex float) asComplexWithArg: (id) __attribute__((ns_consumed)) object;
@end
MyObject *x;
-void foo()
-{
- id obj = [NSObject new];
- [x isEqual : obj];
+// rdar://10444476
+void test0(void) {
+ id obj = [NSObject new];
+ [x isEqual : obj];
}
-
-// CHECK: [[TMP:%.*]] = alloca i8{{$}}
-// CHECK: [[FIVE:%.*]] = call i8* @objc_retain
+// CHECK: define void @test0()
+// CHECK: [[FIVE:%.*]] = call i8* @objc_retain
// CHECK-NEXT: [[SIX:%.*]] = bitcast
// CHECK-NEXT: [[SEVEN:%.*]] = icmp eq i8* [[SIX]], null
// CHECK-NEXT: br i1 [[SEVEN]], label [[NULLINIT:%.*]], label [[CALL_LABEL:%.*]]
-// CHECK: [[FN:%.*]] = load i8** getelementptr inbounds
+// CHECK: [[FN:%.*]] = load i8** getelementptr inbounds
// CHECK-NEXT: [[EIGHT:%.*]] = bitcast i8* [[FN]]
// CHECK-NEXT: [[CALL:%.*]] = call signext i8 [[EIGHT]]
-// CHECK-NEXT: store i8 [[CALL]], i8* [[TMP]]
// CHECK-NEXT: br label [[CONT:%.*]]
-// CHECK: call void @objc_release(i8* [[FIVE]]) nounwind
-// CHECK-NEXT: call void @llvm.memset
+// CHECK: call void @objc_release(i8* [[FIVE]]) [[NUW:#[0-9]+]]
// CHECK-NEXT: br label [[CONT]]
+// CHECK: phi i8 [ [[CALL]], {{%.*}} ], [ 0, {{%.*}} ]
+
+// Ensure that we build PHIs correctly in the presence of cleanups.
+// rdar://12046763
+void test1(void) {
+ id obj = [NSObject new];
+ __weak id weakObj = obj;
+ _Complex float result = [x asComplexWithArg: obj];
+}
+// CHECK: define void @test1()
+// CHECK: [[OBJ:%.*]] = alloca i8*, align 8
+// CHECK-NEXT: [[WEAKOBJ:%.*]] = alloca i8*, align 8
+// CHECK-NEXT: [[RESULT:%.*]] = alloca { float, float }, align 4
+// Various initializations.
+// CHECK: [[T0:%.*]] = call i8* bitcast (
+// CHECK-NEXT: store i8* [[T0]], i8** [[OBJ]]
+// CHECK-NEXT: [[T0:%.*]] = load i8** [[OBJ]]
+// CHECK-NEXT: call i8* @objc_initWeak(i8** [[WEAKOBJ]], i8* [[T0]]) [[NUW]]
+// Okay, start the message-send.
+// CHECK-NEXT: [[T0:%.*]] = load [[MYOBJECT:%.*]]** @x
+// CHECK-NEXT: [[ARG:%.*]] = load i8** [[OBJ]]
+// CHECK-NEXT: [[ARG_RETAINED:%.*]] = call i8* @objc_retain(i8* [[ARG]])
+// CHECK-NEXT: load i8** @
+// CHECK-NEXT: [[SELF:%.*]] = bitcast [[MYOBJECT]]* [[T0]] to i8*
+// Null check.
+// CHECK-NEXT: [[T0:%.*]] = icmp eq i8* [[SELF]], null
+// CHECK-NEXT: br i1 [[T0]], label [[FORNULL:%.*]], label [[FORCALL:%.*]]
+// Invoke and produce the return values.
+// CHECK: [[CALL:%.*]] = invoke <2 x float> bitcast
+// CHECK-NEXT: to label [[INVOKE_CONT:%.*]] unwind label {{%.*}}
+// CHECK: [[T0:%.*]] = bitcast { float, float }* [[COERCE:%.*]] to <2 x float>*
+// CHECK-NEXT: store <2 x float> [[CALL]], <2 x float>* [[T0]],
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds { float, float }* [[COERCE]], i32 0, i32 0
+// CHECK-NEXT: [[REALCALL:%.*]] = load float* [[T0]]
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds { float, float }* [[COERCE]], i32 0, i32 1
+// CHECK-NEXT: [[IMAGCALL:%.*]] = load float* [[T0]]
+// CHECK-NEXT: br label [[CONT:%.*]]{{$}}
+// Null path.
+// CHECK: call void @objc_release(i8* [[ARG_RETAINED]]) [[NUW]]
+// CHECK-NEXT: br label [[CONT]]
+// Join point.
+// CHECK: [[REAL:%.*]] = phi float [ [[REALCALL]], [[INVOKE_CONT]] ], [ 0.000000e+00, [[FORNULL]] ]
+// CHECK-NEXT: [[IMAG:%.*]] = phi float [ [[IMAGCALL]], [[INVOKE_CONT]] ], [ 0.000000e+00, [[FORNULL]] ]
+// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds { float, float }* [[RESULT]], i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds { float, float }* [[RESULT]], i32 0, i32 1
+// CHECK-NEXT: store float [[REAL]], float* [[T0]]
+// CHECK-NEXT: store float [[IMAG]], float* [[T1]]
+// Epilogue.
+// CHECK-NEXT: call void @objc_destroyWeak(i8** [[WEAKOBJ]]) [[NUW]]
+// CHECK-NEXT: call void @objc_storeStrong(i8** [[OBJ]], i8* null) [[NUW]]
+// CHECK-NEXT: ret void
+// Cleanup.
+// CHECK: landingpad
+// CHECK: call void @objc_destroyWeak(i8** [[WEAKOBJ]]) [[NUW]]
+
+// CHECK: attributes [[NUW]] = { nounwind }
diff --git a/test/CodeGenObjC/objc-align.m b/test/CodeGenObjC/objc-align.m
index 324740c..1a9e882 100644
--- a/test/CodeGenObjC/objc-align.m
+++ b/test/CodeGenObjC/objc-align.m
@@ -1,6 +1,5 @@
// 32-bit
-// RUNX: llvm-gcc -m32 -emit-llvm -S -o %t %s &&
// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-runtime=macosx-fragile-10.5 -emit-llvm -o %t %s
// RUN: grep '@"\\01L_OBJC_CATEGORY_A_Cat" = internal global .*, section "__OBJC,__category,regular,no_dead_strip", align 4' %t
// RUN: grep '@"\\01L_OBJC_CLASS_A" = internal global .*, section "__OBJC,__class,regular,no_dead_strip", align 4' %t
diff --git a/test/CodeGenObjC/objc-arc-container-subscripting.m b/test/CodeGenObjC/objc-arc-container-subscripting.m
index 71339c7..1824562 100644
--- a/test/CodeGenObjC/objc-arc-container-subscripting.m
+++ b/test/CodeGenObjC/objc-arc-container-subscripting.m
@@ -12,9 +12,10 @@ id func() {
}
// CHECK: [[call:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend
-// CHECK: [[SIX:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[call]]) nounwind
+// CHECK: [[SIX:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[call]]) [[NUW:#[0-9]+]]
// 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: [[EIGHT:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[SIX]]) [[NUW]]
// CHECK: ret i8* [[EIGHT]]
+// CHECK: attributes [[NUW]] = { nounwind }
diff --git a/test/CodeGenObjC/objc-literal-debugger-test.m b/test/CodeGenObjC/objc-literal-debugger-test.m
index 5f69fd5..d4043aa 100644
--- a/test/CodeGenObjC/objc-literal-debugger-test.m
+++ b/test/CodeGenObjC/objc-literal-debugger-test.m
@@ -50,4 +50,6 @@ int main() {
#endif
}
-// CHECK: declare i8* @objc_msgSend(i8*, i8*, ...) nonlazybind
+// CHECK: declare i8* @objc_msgSend(i8*, i8*, ...) [[NLB:#[0-9]+]]
+
+// CHECK: attributes [[NLB]] = { nonlazybind }
diff --git a/test/CodeGenObjC/objc-literal-tests.m b/test/CodeGenObjC/objc-literal-tests.m
index c513d49..c53ee64 100644
--- a/test/CodeGenObjC/objc-literal-tests.m
+++ b/test/CodeGenObjC/objc-literal-tests.m
@@ -53,7 +53,7 @@ typedef signed char BOOL;
id NSUserName();
-// CHECK: define i32 @main() nounwind
+// CHECK: define i32 @main() [[NUW:#[0-9]+]]
int main() {
// CHECK: call{{.*}}@objc_msgSend{{.*}}i8 signext 97
NSNumber *aNumber = @'a';
@@ -93,3 +93,5 @@ extern void bar(foo a);
void baz(void) {
bar(^(void) { return YES; });
}
+
+// CHECK: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGenObjC/optimized-setter.m b/test/CodeGenObjC/optimized-setter.m
index 6f5cfb1..7e0a1d7 100644
--- a/test/CodeGenObjC/optimized-setter.m
+++ b/test/CodeGenObjC/optimized-setter.m
@@ -1,5 +1,6 @@
// 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
+// RUN: %clang_cc1 %s -emit-llvm -fobjc-runtime=gnustep-1.7 -triple x86_64-unknown-freebsd -o - | FileCheck %s
// rdar://10179974
@interface I
diff --git a/test/CodeGenObjC/property.m b/test/CodeGenObjC/property.m
index aab7c73..6a43826 100644
--- a/test/CodeGenObjC/property.m
+++ b/test/CodeGenObjC/property.m
@@ -1,8 +1,5 @@
// 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
int printf(const char *, ...);
diff --git a/test/CodeGenObjC/protocols-lazy.m b/test/CodeGenObjC/protocols-lazy.m
index 877d492..642f886 100644
--- a/test/CodeGenObjC/protocols-lazy.m
+++ b/test/CodeGenObjC/protocols-lazy.m
@@ -1,5 +1,4 @@
// RUN: %clang_cc1 -emit-llvm -triple i686-apple-darwin8 -fobjc-runtime=macosx-fragile-10.5 -o %t %s
-// RUNX: llvm-gcc -S -emit-llvm -o %t %s &&
// No object generated
// RUN: grep OBJC_PROTOCOL_P0 %t | count 0
diff --git a/test/CodeGenObjC/reorder-synthesized-ivars.m b/test/CodeGenObjC/reorder-synthesized-ivars.m
new file mode 100644
index 0000000..747265d
--- /dev/null
+++ b/test/CodeGenObjC/reorder-synthesized-ivars.m
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-default-synthesize-properties -emit-llvm -x objective-c %s -o - | FileCheck %s
+// rdar://13192366
+typedef signed char BOOL;
+@interface NSObject
+{
+ id isa;
+}
+@end
+
+@interface MyClass : NSObject
+
+@property (readwrite) BOOL boolean1;
+@property (readwrite, copy) id object1;
+@property (readwrite) BOOL boolean2;
+@property (readwrite, copy) id object2;
+@property (readwrite) BOOL boolean3;
+@property (readwrite, copy) id object3;
+@property (readwrite) BOOL boolean4;
+@property (readwrite, copy) id object4;
+@property (readwrite) BOOL boolean5;
+@property (readwrite, copy) id object5;
+@property (readwrite) BOOL boolean6;
+@property (readwrite, copy) id object6;
+@property (readwrite) BOOL boolean7;
+@property (readwrite) BOOL MyBool;
+@property (readwrite, copy) id object7;
+@property (readwrite) BOOL boolean8;
+@property (readwrite, copy) id object8;
+@property (readwrite) BOOL boolean9;
+@property (readwrite, copy) id object9;
+@end
+
+@implementation MyClass
+{
+ id MyIvar;
+ BOOL _MyBool;
+ char * pc;
+}
+@end
+
+// CHECK: @"{{.*}}" = internal global [10 x i8] c"_boolean1
+// CHECK-NEXT: @"{{.*}}" = internal global [10 x i8] c"_boolean2
+// CHECK-NEXT: @"{{.*}}" = internal global [10 x i8] c"_boolean3
+// CHECK-NEXT: @"{{.*}}" = internal global [10 x i8] c"_boolean4
+// CHECK-NEXT: @"{{.*}}" = internal global [10 x i8] c"_boolean5
+// CHECK-NEXT: @"{{.*}}" = internal global [10 x i8] c"_boolean6
+// CHECK-NEXT: @"{{.*}}" = internal global [10 x i8] c"_boolean7
+// CHECK-NEXT: @"{{.*}}" = internal global [10 x i8] c"_boolean8
+// CHECK-NEXT: @"{{.*}}" = internal global [10 x i8] c"_boolean9
+// CHECK-NEXT: @"{{.*}}" = internal global [9 x i8] c"_object1
+// CHECK-NEXT: @"{{.*}}" = internal global [9 x i8] c"_object2
+// CHECK-NEXT: @"{{.*}}" = internal global [9 x i8] c"_object3
+// CHECK-NEXT: @"{{.*}}" = internal global [9 x i8] c"_object4
+// CHECK-NEXT: @"{{.*}}" = internal global [9 x i8] c"_object5
+// CHECK-NEXT: @"{{.*}}" = internal global [9 x i8] c"_object6
+// CHECK-NEXT: @"{{.*}}" = internal global [9 x i8] c"_object7
+// CHECK-NEXT: @"{{.*}}" = internal global [9 x i8] c"_object8
+// CHECK-NEXT: @"{{.*}}" = internal global [9 x i8] c"_object9
diff --git a/test/CodeGenObjCXX/address-safety-attr.mm b/test/CodeGenObjCXX/address-safety-attr.mm
index a3824b9..1b6f0e8 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 -fsanitize=address | FileCheck -check-prefix ASAN %s
+// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck -check-prefix=WITHOUT %s
+// RUN: %clang_cc1 -emit-llvm -o - %s -fsanitize=address | FileCheck -check-prefix=ASAN %s
@interface MyClass
+ (int) addressSafety:(int*)a;
@@ -7,14 +7,15 @@
@implementation MyClass
-// CHECK-NOT: +[MyClass load]{{.*}} address_safety
-// CHECK: +[MyClass load]{{.*}}
-// ASAN: +[MyClass load]{{.*}} address_safety
+// WITHOUT: +[MyClass load]{{.*}}#0
+// ASAN: +[MyClass load]{{.*}}#0
+(void) load { }
-// CHECK-NOT: +[MyClass addressSafety:]{{.*}} address_safety
-// CHECK: +[MyClass addressSafety:]{{.*}}
-// ASAN: +[MyClass addressSafety:]{{.*}} address_safety
+// WITHOUT: +[MyClass addressSafety:]{{.*}}#0
+// ASAN: +[MyClass addressSafety:]{{.*}}#0
+ (int) addressSafety:(int*)a { return *a; }
@end
+
+// ASAN: attributes #0 = {{.*}}sanitize_address
+// WITHOUT-NOT: attributes #0 = {{.*}}sanitize_address
diff --git a/test/CodeGenObjCXX/arc-attrs.mm b/test/CodeGenObjCXX/arc-attrs.mm
new file mode 100644
index 0000000..57ccb6c
--- /dev/null
+++ b/test/CodeGenObjCXX/arc-attrs.mm
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -emit-llvm -fobjc-arc -O0 -o - %s | FileCheck %s
+
+id makeObject1() __attribute__((ns_returns_retained));
+id makeObject2() __attribute__((ns_returns_retained));
+void releaseObject(__attribute__((ns_consumed)) id);
+
+// CHECK: define void @_Z10sanityTestv
+void sanityTest() {
+ // CHECK: [[X:%.*]] = alloca i8*, align 8
+ // CHECK-NEXT: [[OBJ1:%.*]] = call i8* @_Z11makeObject1v()
+ // CHECK-NEXT: store i8* [[OBJ1]], i8** [[X]], align 8
+ id x = makeObject1();
+
+ // CHECK-NEXT: [[OBJ2:%.*]] = call i8* @_Z11makeObject2v()
+ // CHECK-NEXT: call void @_Z13releaseObjectP11objc_object(i8* [[OBJ2]])
+ releaseObject(makeObject2());
+
+ // CHECK-NEXT: call void @objc_storeStrong(i8** [[X]], i8* null)
+ // CHECK-NEXT: ret void
+}
+
+
+template <typename T>
+T makeObjectT1() __attribute__((ns_returns_retained));
+template <typename T>
+T makeObjectT2() __attribute__((ns_returns_retained));
+
+template <typename T>
+void releaseObjectT(__attribute__((ns_consumed)) T);
+
+// CHECK: define void @_Z12templateTestv
+void templateTest() {
+ // CHECK: [[X:%.*]] = alloca i8*, align 8
+ // CHECK-NEXT: [[OBJ1:%.*]] = call i8* @_Z12makeObjectT1IU8__strongP11objc_objectET_v()
+ // CHECK-NEXT: store i8* [[OBJ1]], i8** [[X]], align 8
+ id x = makeObjectT1<id>();
+
+ // CHECK-NEXT: [[OBJ2:%.*]] = call i8* @_Z12makeObjectT2IU8__strongP11objc_objectET_v()
+ // CHECK-NEXT: call void @_Z13releaseObjectP11objc_object(i8* [[OBJ2]])
+ releaseObject(makeObjectT2<id>());
+
+ // CHECK-NEXT: [[OBJ3:%.*]] = call i8* @_Z11makeObject1v()
+ // CHECK-NEXT: call void @_Z14releaseObjectTIU8__strongP11objc_objectEvT_(i8* [[OBJ3]])
+ releaseObjectT(makeObject1());
+
+ // CHECK-NEXT: call void @objc_storeStrong(i8** [[X]], i8* null)
+ // CHECK-NEXT: ret void
+}
diff --git a/test/CodeGenObjCXX/arc-blocks.mm b/test/CodeGenObjCXX/arc-blocks.mm
new file mode 100644
index 0000000..810c0e0
--- /dev/null
+++ b/test/CodeGenObjCXX/arc-blocks.mm
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-runtime-has-weak -fblocks -fobjc-arc -o - %s | FileCheck %s
+
+// CHECK: [[A:.*]] = type { i64, [10 x i8*] }
+
+// CHECK: [[LAYOUT0:@.*]] = internal global [3 x i8] c" 9\00"
+
+// rdar://13045269
+// If a __block variable requires extended layout information *and*
+// a copy/dispose helper, be sure to adjust the offsets used in copy/dispose.
+namespace test0 {
+ struct A {
+ unsigned long count;
+ id data[10];
+ };
+
+ void foo() {
+ __block A v;
+ }
+ // CHECK: define void @_ZN5test03fooEv()
+ // CHECK: [[V:%.*]] = alloca [[BYREF_A:%.*]], align 8
+ // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_A]]* [[V]], i32 0, i32 4
+ // CHECK-NEXT: store i8* bitcast (void (i8*, i8*)* [[COPY_HELPER:@.*]] to i8*), i8** [[T0]]
+ // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[BYREF_A]]* [[V]], i32 0, i32 5
+ // CHECK-NEXT: store i8* bitcast (void (i8*)* [[DISPOSE_HELPER:@.*]] to i8*), i8** [[T0]]
+ // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[BYREF_A]]* [[V]], i32 0, i32 6
+ // CHECK-NEXT: store i8* getelementptr inbounds ([3 x i8]* [[LAYOUT0]], i32 0, i32 0), i8** [[T0]]
+ // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[BYREF_A]]* [[V]], i32 0, i32 7
+ // CHECK-NEXT: call void @_ZN5test01AC1Ev([[A]]* [[T0]])
+ // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[BYREF_A]]* [[V]], i32 0, i32 7
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[BYREF_A]]* [[V]] to i8*
+ // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T1]], i32 8)
+ // CHECK-NEXT: call void @_ZN5test01AD1Ev([[A]]* [[T0]])
+ // CHECK-NEXT: ret void
+
+ // CHECK: define internal void [[COPY_HELPER]](
+ // CHECK: [[T0:%.*]] = bitcast i8* {{.*}} to [[BYREF_A]]*
+ // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[BYREF_A]]* [[T0]], i32 0, i32 7
+ // CHECK-NEXT: load
+ // CHECK-NEXT: [[T2:%.*]] = bitcast i8* {{.*}} to [[BYREF_A]]*
+ // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [[BYREF_A]]* [[T2]], i32 0, i32 7
+ // CHECK-NEXT: call void @_ZN5test01AC1ERKS0_([[A]]* [[T1]], [[A]]* [[T3]])
+ // CHECK-NEXT: ret void
+
+ // CHECK: define internal void [[DISPOSE_HELPER]](
+ // CHECK: [[T0:%.*]] = bitcast i8* {{.*}} to [[BYREF_A]]*
+ // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[BYREF_A]]* [[T0]], i32 0, i32 7
+ // CHECK-NEXT: call void @_ZN5test01AD1Ev([[A]]* [[T1]])
+ // CHECK-NEXT: ret void
+}
diff --git a/test/CodeGenObjCXX/arc-exceptions.mm b/test/CodeGenObjCXX/arc-exceptions.mm
index fb5300d..b5ed257 100644
--- a/test/CodeGenObjCXX/arc-exceptions.mm
+++ b/test/CodeGenObjCXX/arc-exceptions.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fexceptions -fobjc-exceptions -fcxx-exceptions -fobjc-runtime-has-weak -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fexceptions -fobjc-exceptions -fcxx-exceptions -fobjc-runtime-has-weak -o - -fobjc-arc-exceptions %s | FileCheck %s
@class Ety;
@@ -17,12 +17,12 @@ void test0(void) {
// CHECK: [[T0:%.*]] = call i8* @objc_begin_catch(
// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[ETY]]*
// CHECK-NEXT: [[T2:%.*]] = bitcast [[ETY]]* [[T1]] to i8*
-// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]]) nounwind
+// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]]) [[NUW:#[0-9]+]]
// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[ETY]]*
// CHECK-NEXT: store [[ETY]]* [[T4]], [[ETY]]** [[E]]
// 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
+// CHECK-NEXT: call void @objc_storeStrong(i8** [[T0]], i8* null) [[NUW]]
+// CHECK-NEXT: call void @objc_end_catch() [[NUW]]
void test1_helper(void);
void test1(void) {
@@ -38,10 +38,10 @@ void test1(void) {
// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[ETY]]*
// CHECK-NEXT: [[T2:%.*]] = bitcast [[ETY]]** [[E]] to i8**
// CHECK-NEXT: [[T3:%.*]] = bitcast [[ETY]]* [[T1]] to i8*
-// CHECK-NEXT: call i8* @objc_initWeak(i8** [[T2]], i8* [[T3]]) nounwind
+// CHECK-NEXT: call i8* @objc_initWeak(i8** [[T2]], i8* [[T3]]) [[NUW]]
// CHECK-NEXT: [[T0:%.*]] = bitcast [[ETY]]** [[E]] to i8**
-// CHECK-NEXT: call void @objc_destroyWeak(i8** [[T0]]) nounwind
-// CHECK-NEXT: call void @objc_end_catch() nounwind
+// CHECK-NEXT: call void @objc_destroyWeak(i8** [[T0]]) [[NUW]]
+// CHECK-NEXT: call void @objc_end_catch() [[NUW]]
void test2_helper(void);
void test2(void) {
@@ -56,12 +56,12 @@ void test2(void) {
// CHECK: [[T0:%.*]] = call i8* @__cxa_begin_catch(
// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[ETY]]*
// CHECK-NEXT: [[T2:%.*]] = bitcast [[ETY]]* [[T1]] to i8*
-// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]]) nounwind
+// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]]) [[NUW]]
// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[ETY]]*
// CHECK-NEXT: store [[ETY]]* [[T4]], [[ETY]]** [[E]]
// 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
+// CHECK-NEXT: call void @objc_storeStrong(i8** [[T0]], i8* null) [[NUW]]
+// CHECK-NEXT: call void @__cxa_end_catch() [[NUW]]
void test3_helper(void);
void test3(void) {
@@ -77,7 +77,48 @@ void test3(void) {
// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[ETY]]*
// CHECK-NEXT: [[T2:%.*]] = bitcast [[ETY]]** [[E]] to i8**
// CHECK-NEXT: [[T3:%.*]] = bitcast [[ETY]]* [[T1]] to i8*
-// CHECK-NEXT: call i8* @objc_initWeak(i8** [[T2]], i8* [[T3]]) nounwind
+// CHECK-NEXT: call i8* @objc_initWeak(i8** [[T2]], i8* [[T3]]) [[NUW]]
// CHECK-NEXT: [[T0:%.*]] = bitcast [[ETY]]** [[E]] to i8**
-// CHECK-NEXT: call void @objc_destroyWeak(i8** [[T0]]) nounwind
-// CHECK-NEXT: call void @__cxa_end_catch() nounwind
+// CHECK-NEXT: call void @objc_destroyWeak(i8** [[T0]]) [[NUW]]
+// CHECK-NEXT: call void @__cxa_end_catch() [[NUW]]
+
+namespace test4 {
+ struct A {
+ id single;
+ id array[2][3];
+
+ A();
+ };
+
+ A::A() {
+ throw 0;
+ }
+ // CHECK: define void @_ZN5test41AC2Ev(
+ // CHECK: [[THIS:%.*]] = load [[A:%.*]]** {{%.*}}
+ // Construct single.
+ // CHECK-NEXT: [[SINGLE:%.*]] = getelementptr inbounds [[A]]* [[THIS]], i32 0, i32 0
+ // CHECK-NEXT: store i8* null, i8** [[SINGLE]], align 8
+ // Construct array.
+ // CHECK-NEXT: [[ARRAY:%.*]] = getelementptr inbounds [[A]]* [[THIS]], i32 0, i32 1
+ // CHECK-NEXT: [[T0:%.*]] = bitcast [2 x [3 x i8*]]* [[ARRAY]] to i8*
+ // CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 48, i32 8, i1 false)
+ // throw 0;
+ // CHECK: invoke void @__cxa_throw(
+ // Landing pad from throw site:
+ // CHECK: landingpad
+ // - First, destroy all of array.
+ // CHECK: [[ARRAYBEGIN:%.*]] = getelementptr inbounds [2 x [3 x i8*]]* [[ARRAY]], i32 0, i32 0, i32 0
+ // CHECK-NEXT: [[ARRAYEND:%.*]] = getelementptr inbounds i8** [[ARRAYBEGIN]], i64 6
+ // CHECK-NEXT: br label
+ // CHECK: [[AFTER:%.*]] = phi i8** [ [[ARRAYEND]], {{%.*}} ], [ [[ELT:%.*]], {{%.*}} ]
+ // CHECK-NEXT: [[ELT]] = getelementptr inbounds i8** [[AFTER]], i64 -1
+ // CHECK-NEXT: call void @objc_storeStrong(i8** [[ELT]], i8* null) [[NUW]]
+ // CHECK-NEXT: [[DONE:%.*]] = icmp eq i8** [[ELT]], [[ARRAYBEGIN]]
+ // CHECK-NEXT: br i1 [[DONE]],
+ // - Next, destroy single.
+ // CHECK: call void @objc_storeStrong(i8** [[SINGLE]], i8* null) [[NUW]]
+ // CHECK: br label
+ // CHECK: resume
+}
+
+// CHECK: attributes [[NUW]] = { nounwind }
diff --git a/test/CodeGenObjCXX/arc-new-delete.mm b/test/CodeGenObjCXX/arc-new-delete.mm
index ce7eb3d..c061e5d 100644
--- a/test/CodeGenObjCXX/arc-new-delete.mm
+++ b/test/CodeGenObjCXX/arc-new-delete.mm
@@ -5,8 +5,9 @@ typedef __weak id weak_id;
// CHECK: define void @_Z8test_newP11objc_object
void test_new(id invalue) {
- // CHECK: alloca i8*
- // CHECK-NEXT: call i8* @objc_retain
+ // CHECK: [[INVALUEADDR:%.*]] = alloca i8*
+ // CHECK-NEXT: store i8* null, i8** [[INVALUEADDR]]
+ // CHECK-NEXT: call void @objc_storeStrong(i8** [[INVALUEADDR]], i8* [[INVALUE:%.*]])
// CHECK: call noalias i8* @_Znwm
// CHECK-NEXT: {{bitcast i8\*.*to i8\*\*}}
diff --git a/test/CodeGenObjCXX/arc.mm b/test/CodeGenObjCXX/arc.mm
index f31b993..1888dbe 100644
--- a/test/CodeGenObjCXX/arc.mm
+++ b/test/CodeGenObjCXX/arc.mm
@@ -61,6 +61,8 @@ void test34(int cond) {
// CHECK-NEXT: [[WEAK:%.*]] = alloca i8*
// CHECK-NEXT: [[TEMP1:%.*]] = alloca i8*
// CHECK-NEXT: [[TEMP2:%.*]] = alloca i8*
+ // CHECK-NEXT: [[CONDCLEANUPSAVE:%.*]] = alloca i8*
+ // CHECK-NEXT: [[CONDCLEANUP:%.*]] = alloca i1
// CHECK-NEXT: store i32
// CHECK-NEXT: store i8* null, i8** [[STRONG]]
// CHECK-NEXT: call i8* @objc_initWeak(i8** [[WEAK]], i8* null)
@@ -74,11 +76,13 @@ void test34(int cond) {
// CHECK: [[T0:%.*]] = load i8** [[ARG]]
// CHECK-NEXT: store i8* [[T0]], i8** [[TEMP1]]
// CHECK-NEXT: br label
+ // CHECK: [[W0:%.*]] = phi i8* [ [[T0]], {{%.*}} ], [ undef, {{%.*}} ]
// CHECK: call void @_Z11test34_sinkPU15__autoreleasingP11objc_object(i8** [[T1]])
// CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null
// CHECK-NEXT: br i1 [[T0]],
// CHECK: [[T0:%.*]] = load i8** [[TEMP1]]
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
+ // CHECK-NEXT: call void (...)* @clang.arc.use(i8* [[W0]])
// CHECK-NEXT: [[T2:%.*]] = load i8** [[ARG]]
// CHECK-NEXT: store i8* [[T1]], i8** [[ARG]]
// CHECK-NEXT: call void @objc_release(i8* [[T2]])
@@ -89,8 +93,11 @@ void test34(int cond) {
// CHECK: [[ARG:%.*]] = phi i8**
// CHECK-NEXT: [[T0:%.*]] = icmp eq i8** [[ARG]], null
// CHECK-NEXT: [[T1:%.*]] = select i1 [[T0]], i8** null, i8** [[TEMP2]]
+ // CHECK-NEXT: store i1 false, i1* [[CONDCLEANUP]]
// CHECK-NEXT: br i1 [[T0]],
- // CHECK: [[T0:%.*]] = call i8* @objc_loadWeak(i8** [[ARG]])
+ // CHECK: [[T0:%.*]] = call i8* @objc_loadWeakRetained(i8** [[ARG]])
+ // CHECK-NEXT: store i8* [[T0]], i8** [[CONDCLEANUPSAVE]]
+ // CHECK-NEXT: store i1 true, i1* [[CONDCLEANUP]]
// CHECK-NEXT: store i8* [[T0]], i8** [[TEMP2]]
// CHECK-NEXT: br label
// CHECK: call void @_Z11test34_sinkPU15__autoreleasingP11objc_object(i8** [[T1]])
diff --git a/test/CodeGenObjCXX/block-var-layout.mm b/test/CodeGenObjCXX/block-var-layout.mm
index f8b6b9c..08dbc02 100644
--- a/test/CodeGenObjCXX/block-var-layout.mm
+++ b/test/CodeGenObjCXX/block-var-layout.mm
@@ -1,5 +1,7 @@
-// RUN: %clang_cc1 -x objective-c++ -fblocks -fobjc-gc -triple x86_64-apple-darwin -fobjc-runtime=macosx-fragile-10.5 -emit-llvm %s -o %t-64.ll
-// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.ll %s
+// RUN: %clang_cc1 -x objective-c++ -fblocks -fobjc-gc -triple x86_64-apple-darwin -fobjc-runtime=macosx-fragile-10.5 -O0 -print-ivar-layout -emit-llvm -o /dev/null %s > %t-64.layout
+// RUN: FileCheck --input-file=%t-64.layout %s
+// rdar://12184410
+// rdar://12752901
// See commentary in test/CodeGenObjC/block-var-layout.m, from which
// this is largely cloned.
@@ -37,7 +39,7 @@ void f() {
// Test 1
// byref int, short, char, char, char, id, id, strong void*, byref id
// 01 35 10 00
-// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [4 x i8] c"\015\10\00"
+// CHECK: block variable layout for block: 0x01, 0x35, 0x10, 0x00
void (^b)() = ^{
byref_int = sh + ch+ch1+ch2 ;
x(bar);
@@ -50,7 +52,7 @@ void f() {
// Test 2
// byref int, short, char, char, char, id, id, strong void*, byref void*, byref id
// 01 36 10 00
-// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [4 x i8] c"\016\10\00"
+// CHECK: 0x01, 0x36, 0x10, 0x00
void (^c)() = ^{
byref_int = sh + ch+ch1+ch2 ;
x(bar);
@@ -65,8 +67,7 @@ void f() {
// Test 3
// byref int, short, char, char, char, id, id, byref void*, int, double, byref id
// 01 34 11 30 00
-// FIXME: we'd get a better format here if we sorted by scannability, not just alignment
-// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [5 x i8] c"\014\11 \00"
+// CHECK: block variable layout for block: 0x01, 0x35, 0x30, 0x00
void (^d)() = ^{
byref_int = sh + ch+ch1+ch2 ;
x(bar);
@@ -81,7 +82,7 @@ void (^d)() = ^{
// Test4
// struct S (int, id, int, id, int, id)
// 01 41 11 11 00
-// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [5 x i8] c"\01A\11\11\00"
+// CHECK: block variable layout for block: 0x01, 0x41, 0x11, 0x11, 0x00
struct S s2;
void (^e)() = ^{
x(s2.o1);
@@ -119,7 +120,7 @@ void Test5() {
// struct s2 (int, id, int, id, int, id?), union u2 (id?)
// 01 41 11 12 00
-// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [5 x i8] c"\01A\11\12\00"
+// CHECK: block variable layout for block: 0x01, 0x41, 0x11, 0x12, 0x00
void (^c)() = ^{
x(s2.ui.o1);
x(u2.o1);
@@ -137,7 +138,7 @@ void notifyBlock(id dependentBlock) {
// id, id, void(^)()
// 01 33 00
-// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [3 x i8] c"\013\00"
+// CHECK: block variable layout for block: 0x01, 0x33, 0x00
void (^wrapperBlock)() = ^() {
CFRelease(singleObservationToken);
CFRelease(singleObservationToken);
@@ -150,7 +151,7 @@ void notifyBlock(id dependentBlock) {
void test_empty_block() {
// 01 00
-// CHECK-LP64: @"\01L_OBJC_CLASS_NAME_{{.*}}" = internal global [2 x i8] c"\01\00"
+// CHECK: block variable layout for block: 0x01, 0x00
void (^wrapperBlock)() = ^() {
};
wrapperBlock();
diff --git a/test/CodeGenObjCXX/exceptions-legacy.mm b/test/CodeGenObjCXX/exceptions-legacy.mm
new file mode 100644
index 0000000..a31ba36
--- /dev/null
+++ b/test/CodeGenObjCXX/exceptions-legacy.mm
@@ -0,0 +1,80 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -fobjc-runtime=macosx-fragile-10.5 -emit-llvm -fexceptions -fobjc-exceptions -O2 -o - %s | FileCheck %s
+
+// Test we maintain at least a basic amount of interoperation between
+// ObjC and C++ exceptions in the legacy runtime.
+
+// rdar://12364847
+
+void foo(void);
+
+void test0(id obj) {
+ @synchronized(obj) {
+ foo();
+ }
+}
+// CHECK: define void @_Z5test0P11objc_object(
+// Enter the @synchronized block.
+// CHECK: call i32 @objc_sync_enter(i8* [[OBJ:%.*]])
+// CHECK: call void @objc_exception_try_enter([[BUF_T:%.*]]* [[BUF:%.*]])
+// CHECK-NEXT: [[T0:%.*]] = getelementptr [[BUF_T]]* [[BUF]], i32 0, i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = call i32 @_setjmp(i32* [[T0]])
+// CHECK-NEXT: [[T2:%.*]] = icmp eq i32 [[T1]], 0
+// CHECK-NEXT: br i1 [[T2]],
+
+// Body.
+// CHECK: invoke void @_Z3foov()
+
+// Leave the @synchronized. The reload of obj here is unnecessary.
+// CHECK: call void @objc_exception_try_exit([[BUF_T]]* [[BUF]])
+// CHECK-NEXT: [[T0:%.*]] = load i8**
+// CHECK-NEXT: call i32 @objc_sync_exit(i8* [[T0]])
+// CHECK-NEXT: ret void
+
+// Real EH cleanup.
+// CHECK: [[T0:%.*]] = landingpad
+// CHECK-NEXT: cleanup
+// CHECK-NEXT: call void @objc_exception_try_exit([[BUF_T]]* [[BUF]])
+// CHECK-NEXT: [[T0:%.*]] = load i8**
+// CHECK-NEXT: call i32 @objc_sync_exit(i8* [[T0]])
+// CHECK-NEXT: resume
+
+// ObjC EH "cleanup".
+// CHECK: [[T0:%.*]] = load i8**
+// CHECK-NEXT: call i32 @objc_sync_exit(i8* [[T0]])
+// CHECK-NEXT: [[T0:%.*]] = call i8* @objc_exception_extract([[BUF_T]]* [[BUF]])
+// CHECK-NEXT: call void @objc_exception_throw(i8* [[T0]])
+// CHECK-NEXT: unreachable
+
+void test1(id obj, bool *failed) {
+ @try {
+ foo();
+ } @catch (...) {
+ *failed = true;
+ }
+}
+// CHECK: define void @_Z5test1P11objc_objectPb(
+// Enter the @try block.
+// CHECK: call void @objc_exception_try_enter([[BUF_T]]* [[BUF:%.*]])
+// CHECK-NEXT: [[T0:%.*]] = getelementptr [[BUF_T]]* [[BUF]], i32 0, i32 0, i32 0
+// CHECK-NEXT: [[T1:%.*]] = call i32 @_setjmp(i32* [[T0]])
+// CHECK-NEXT: [[T2:%.*]] = icmp eq i32 [[T1]], 0
+// CHECK-NEXT: br i1 [[T2]],
+
+// Body.
+// CHECK: invoke void @_Z3foov()
+
+// Leave the @try.
+// CHECK: call void @objc_exception_try_exit([[BUF_T]]* [[BUF]])
+// CHECK-NEXT: br label
+// CHECK: ret void
+
+// Real EH cleanup.
+// CHECK: [[T0:%.*]] = landingpad
+// CHECK-NEXT: cleanup
+// CHECK-NEXT: call void @objc_exception_try_exit([[BUF_T]]* [[BUF]])
+// CHECK-NEXT: resume
+
+// Catch handler. Reload of 'failed' address is unnecessary.
+// CHECK: [[T0:%.*]] = load i8**
+// CHECK-NEXT: store i8 1, i8* [[T0]],
+// CHECK-NEXT: br label
diff --git a/test/CodeGenObjCXX/exceptions.mm b/test/CodeGenObjCXX/exceptions.mm
index ce6d20a..031c222 100644
--- a/test/CodeGenObjCXX/exceptions.mm
+++ b/test/CodeGenObjCXX/exceptions.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fcxx-exceptions -fexceptions -o - %s | FileCheck %s
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -emit-llvm -fcxx-exceptions -fexceptions -fobjc-exceptions -o - %s | FileCheck %s
@interface OCType @end
void opaque();
@@ -16,3 +16,21 @@ namespace test0 {
}
}
}
+
+// rdar://12605907
+@interface NSException
+ + new;
+@end
+namespace test1 {
+
+ void bar() {
+ @try {
+ throw [NSException new];
+ } @catch (id i) {
+ }
+ }
+// CHECK: invoke void @objc_exception_throw(i8* [[CALL:%.*]]) [[NR:#[0-9]+]]
+// CHECK: to label [[INVOKECONT1:%.*]] unwind label [[LPAD:%.*]]
+}
+
+// CHECK: attributes [[NR]] = { noreturn }
diff --git a/test/CodeGenObjCXX/externally-initialized-selectors.mm b/test/CodeGenObjCXX/externally-initialized-selectors.mm
new file mode 100644
index 0000000..87a7c04
--- /dev/null
+++ b/test/CodeGenObjCXX/externally-initialized-selectors.mm
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -cc1 -fobjc-runtime=macosx-fragile-10.5 -o - -emit-llvm %s | FileCheck %s
+// RUN: %clang_cc1 -cc1 -o - -emit-llvm %s | FileCheck %s
+
+// CHECK: @"\01L_OBJC_SELECTOR_REFERENCES_" = internal externally_initialized global
+
+void test(id x) {
+ [x doSomething];
+}
diff --git a/test/CodeGenObjCXX/lambda-expressions.mm b/test/CodeGenObjCXX/lambda-expressions.mm
index ec3eb1f..7c1e2e4 100644
--- a/test/CodeGenObjCXX/lambda-expressions.mm
+++ b/test/CodeGenObjCXX/lambda-expressions.mm
@@ -25,15 +25,19 @@ typedef int (^fp)();
fp global;
void f2() { global = []{ return 3; }; }
-// MRC: define void @_Z2f2v() nounwind {
+// MRC: define void @_Z2f2v() [[NUW:#[0-9]+]] {
// MRC: store i8* bitcast (i32 (i8*)* @___Z2f2v_block_invoke to i8*),
// MRC-NOT: call
// MRC: ret void
// ("global" contains a dangling pointer after this function runs.)
-// ARC: define void @_Z2f2v() nounwind {
+// ARC: define void @_Z2f2v() [[NUW:#[0-9]+]] {
// ARC: store i8* bitcast (i32 (i8*)* @___Z2f2v_block_invoke to i8*),
// ARC: call i8* @objc_retainBlock
// ARC: call void @objc_release
// ARC: define internal i32 @___Z2f2v_block_invoke
// ARC: call i32 @"_ZZ2f2vENK3$_1clEv
+
+// ARC: attributes [[NUW]] = { nounwind{{.*}} }
+
+// MRC: attributes [[NUW]] = { nounwind{{.*}} }
diff --git a/test/CodeGenObjCXX/message.mm b/test/CodeGenObjCXX/message.mm
new file mode 100644
index 0000000..1268a79
--- /dev/null
+++ b/test/CodeGenObjCXX/message.mm
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-10.7 -emit-llvm -o - %s | FileCheck %s
+
+// Properly instantiate a non-dependent message expression which
+// requires a contextual conversion to ObjC pointer type.
+// <rdar://13305374>
+@interface Test0
+- (void) foo;
+@end
+namespace test0 {
+ struct A {
+ operator Test0*();
+ };
+ template <class T> void foo() {
+ A a;
+ [a foo];
+ }
+ template void foo<int>();
+ // CHECK: define weak_odr void @_ZN5test03fooIiEEvv()
+ // CHECK: [[T0:%.*]] = call [[TEST0:%.*]]* @_ZN5test01AcvP5Test0Ev(
+ // CHECK-NEXT: [[T1:%.*]] = load i8**
+ // CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST0]]* [[T0]] to i8*
+ // CHECK-NEXT: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*)*)(i8* [[T2]], i8* [[T1]])
+ // CHECK-NEXT: ret void
+}
diff --git a/test/CodeGenObjCXX/pr14474-gline-tables-only.mm b/test/CodeGenObjCXX/pr14474-gline-tables-only.mm
new file mode 100644
index 0000000..e927ab9
--- /dev/null
+++ b/test/CodeGenObjCXX/pr14474-gline-tables-only.mm
@@ -0,0 +1,25 @@
+// PR 14474
+// RUN: %clang_cc1 -triple i386-apple-macosx10.6.0 -emit-llvm \
+// RUN: -gline-tables-only -x objective-c++ -o /dev/null %s
+
+typedef signed char BOOL;
+@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
+@protocol NSObject - (BOOL)isEqual:(id)object;
+@end
+@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder;
+@end
+@interface NSObject <NSObject> { }
+@end
+@interface NSResponder : NSObject <NSCoding> { }
+@end
+@protocol NSValidatedUserInterfaceItem - (SEL)action;
+@end
+@protocol NSUserInterfaceValidations - (BOOL)validateUserInterfaceItem:(id
+<NSValidatedUserInterfaceItem>)anItem;
+@end
+@interface NSRunningApplication : NSObject { }
+@end
+@interface NSApplication : NSResponder <NSUserInterfaceValidations> { }
+@end
+@implementation MockCrApp + (NSApplication*)sharedApplication { }
+@end
diff --git a/test/CodeGenObjCXX/property-object-reference-2.mm b/test/CodeGenObjCXX/property-object-reference-2.mm
index 2a38038..25bfdf8 100644
--- a/test/CodeGenObjCXX/property-object-reference-2.mm
+++ b/test/CodeGenObjCXX/property-object-reference-2.mm
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-10.7 -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple x86_64-unknown-freebsd -fobjc-runtime=gnustep-1.7 -emit-llvm -o - | FileCheck -check-prefix=CHECK-GNUSTEP %s
// rdar://6137845
extern int DEFAULT();
@@ -54,3 +55,6 @@ struct TCPPObject
// CHECK: [[THREE:%.*]] = bitcast %struct.TCPPObject* [[MYPROPERTY:%.*]] to i8*
// CHECK: call void @objc_copyCppObjectAtomic(i8* [[TWO]], i8* [[THREE]], i8* bitcast (void (%struct.TCPPObject*, %struct.TCPPObject*)* @__assign_helper_atomic_property_ to i8*))
// CHECK: ret void
+
+// CHECK-GNUSTEP: objc_getCppObjectAtomic
+// CHECK-GNUSTEP: objc_setCppObjectAtomic
diff --git a/test/CodeGenObjCXX/unknown-anytype.mm b/test/CodeGenObjCXX/unknown-anytype.mm
new file mode 100644
index 0000000..0e146d4
--- /dev/null
+++ b/test/CodeGenObjCXX/unknown-anytype.mm
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fdebugger-support -funknown-anytype -emit-llvm -o - %s | FileCheck %s
+
+// rdar://13025708
+
+@interface A @end
+void test0(A *a) {
+ (void) [a test0: (float) 2.0];
+}
+// CHECK: define void @_Z5test0P1A(
+// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, float)*)(
+
+@interface B
+- (void) test1: (__unknown_anytype) x;
+@end
+void test1(B *b) {
+ (void) [b test1: (float) 2.0];
+}
+// CHECK: define void @_Z5test1P1B(
+// CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, float)*)(
+
diff --git a/test/CodeGenOpenCL/addr-space-struct-arg.cl b/test/CodeGenOpenCL/addr-space-struct-arg.cl
new file mode 100644
index 0000000..f04923d
--- /dev/null
+++ b/test/CodeGenOpenCL/addr-space-struct-arg.cl
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -O0 -ffake-address-space-map -triple i686-pc-darwin | FileCheck %s
+
+typedef struct {
+ int cells[9];
+} Mat3X3;
+
+typedef struct {
+ int cells[16];
+} Mat4X4;
+
+Mat4X4 __attribute__((noinline)) foo(Mat3X3 in) {
+ Mat4X4 out;
+ return out;
+}
+
+kernel void ker(global Mat3X3 *in, global Mat4X4 *out) {
+ out[0] = foo(in[1]);
+}
+
+// Expect two mem copies: one for the argument "in", and one for
+// the return value.
+// CHECK: call void @llvm.memcpy.p0i8.p1i8.i32(i8*
+// CHECK: call void @llvm.memcpy.p1i8.p0i8.i32(i8 addrspace(1)*
diff --git a/test/CodeGenOpenCL/event_t.cl b/test/CodeGenOpenCL/event_t.cl
new file mode 100644
index 0000000..ddf12a9
--- /dev/null
+++ b/test/CodeGenOpenCL/event_t.cl
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -O0 | FileCheck %s
+
+void foo(event_t evt);
+
+void kernel ker() {
+ event_t e;
+// CHECK: alloca %opencl.event_t*,
+ foo(e);
+// CHECK: call void @foo(%opencl.event_t* %
+ foo(0);
+// CHECK: call void @foo(%opencl.event_t* null)
+}
diff --git a/test/CodeGenOpenCL/half.cl b/test/CodeGenOpenCL/half.cl
new file mode 100644
index 0000000..7ecae89
--- /dev/null
+++ b/test/CodeGenOpenCL/half.cl
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
+
+#pragma OPENCL EXTENSION cl_khr_fp16 : enable
+
+
+half test()
+{
+ half x = 0.1f;
+ x+=2.0f;
+ x-=2.0f;
+ half y = x + x;
+ half z = y * 1.0f;
+ return z;
+// CHECK: half 0xH3260
+}
diff --git a/test/CodeGenOpenCL/kernel-arg-info.cl b/test/CodeGenOpenCL/kernel-arg-info.cl
index 9d52736..c7e2049 100644
--- a/test/CodeGenOpenCL/kernel-arg-info.cl
+++ b/test/CodeGenOpenCL/kernel-arg-info.cl
@@ -1,7 +1,20 @@
-// RUN: %clang_cc1 %s -cl-kernel-arg-info -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -cl-kernel-arg-info -emit-llvm -o - -triple spir-unknown-unknown | FileCheck %s
-kernel void foo(int *X, int Y, int anotherArg) {
+kernel void foo(__global int * restrict X, const int Y,
+ volatile int anotherArg, __constant float * restrict Z) {
*X = Y + anotherArg;
}
-// CHECK: metadata !{metadata !"kernel_arg_name", metadata !"X", metadata !"Y", metadata !"anotherArg"}
+// CHECK: metadata !{metadata !"kernel_arg_addr_space", i32 1, i32 0, i32 0, i32 2}
+// CHECK: metadata !{metadata !"kernel_arg_access_qual", metadata !"none", metadata !"none", metadata !"none", metadata !"none"}
+// CHECK: metadata !{metadata !"kernel_arg_type", metadata !"int*", metadata !"int", metadata !"int", metadata !"float*"}
+// CHECK: metadata !{metadata !"kernel_arg_type_qual", metadata !"restrict", metadata !"const", metadata !"volatile", metadata !"restrict const"}
+// CHECK: metadata !{metadata !"kernel_arg_name", metadata !"X", metadata !"Y", metadata !"anotherArg", metadata !"Z"}
+
+kernel void foo2(read_only image1d_t img1, image2d_t img2, write_only image2d_array_t img3) {
+}
+// CHECK: metadata !{metadata !"kernel_arg_addr_space", i32 0, i32 0, i32 0}
+// CHECK: metadata !{metadata !"kernel_arg_access_qual", metadata !"read_only", metadata !"read_only", metadata !"write_only"}
+// CHECK: metadata !{metadata !"kernel_arg_type", metadata !"image1d_t", metadata !"image2d_t", metadata !"image2d_array_t"}
+// CHECK: metadata !{metadata !"kernel_arg_type_qual", metadata !"", metadata !"", metadata !""}
+// CHECK: metadata !{metadata !"kernel_arg_name", metadata !"img1", metadata !"img2", metadata !"img3"}
diff --git a/test/CodeGenOpenCL/kernel-attributes.cl b/test/CodeGenOpenCL/kernel-attributes.cl
index de16a41..1166f93 100644
--- a/test/CodeGenOpenCL/kernel-attributes.cl
+++ b/test/CodeGenOpenCL/kernel-attributes.cl
@@ -1,12 +1,16 @@
// RUN: %clang_cc1 -emit-llvm -O0 -o - %s | FileCheck %s
-kernel __attribute__((reqd_work_group_size(1,2,4))) void kernel1(int a) {}
+typedef unsigned int uint4 __attribute__((ext_vector_type(4)));
-kernel __attribute__((work_group_size_hint(8,16,32))) void kernel2(int a) {}
+kernel __attribute__((vec_type_hint(int))) __attribute__((reqd_work_group_size(1,2,4))) void kernel1(int a) {}
+
+kernel __attribute__((vec_type_hint(uint4))) __attribute__((work_group_size_hint(8,16,32))) void kernel2(int a) {}
// CHECK: opencl.kernels = !{[[MDNODE0:![0-9]+]], [[MDNODE3:![0-9]+]]}
-// CHECK: [[MDNODE0]] = metadata !{void (i32)* @kernel1, metadata [[MDNODE2:![0-9]+]]}
+// CHECK: [[MDNODE0]] = metadata !{void (i32)* @kernel1, metadata [[MDNODE1:![0-9]+]], metadata [[MDNODE2:![0-9]+]]}
+// CHECK: [[MDNODE1]] = metadata !{metadata !"vec_type_hint", i32 undef, i32 1}
// CHECK: [[MDNODE2]] = metadata !{metadata !"reqd_work_group_size", i32 1, i32 2, i32 4}
-// CHECK: [[MDNODE3]] = metadata !{void (i32)* @kernel2, metadata [[MDNODE5:![0-9]+]]}
+// CHECK: [[MDNODE3]] = metadata !{void (i32)* @kernel2, metadata [[MDNODE4:![0-9]+]], metadata [[MDNODE5:![0-9]+]]}
+// CHECK: [[MDNODE4]] = metadata !{metadata !"vec_type_hint", <4 x i32> undef, i32 0}
// CHECK: [[MDNODE5]] = metadata !{metadata !"work_group_size_hint", i32 8, i32 16, i32 32}
diff --git a/test/CodeGenOpenCL/local.cl b/test/CodeGenOpenCL/local.cl
index 32fa7be..b4bd008 100644
--- a/test/CodeGenOpenCL/local.cl
+++ b/test/CodeGenOpenCL/local.cl
@@ -5,3 +5,8 @@ __kernel void foo(void) {
__local int i;
++i;
}
+
+// CHECK: define void @_Z3barPU3AS2i
+__kernel void __attribute__((__overloadable__)) bar(local int *x) {
+ *x = 5;
+}
diff --git a/test/CodeGenOpenCL/logical-ops.cl b/test/CodeGenOpenCL/logical-ops.cl
new file mode 100644
index 0000000..ac1c1b5
--- /dev/null
+++ b/test/CodeGenOpenCL/logical-ops.cl
@@ -0,0 +1,56 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -cl-std=CL1.2 -O1 -triple x86_64-unknown-linux-gnu | FileCheck %s
+
+#pragma OPENCL EXTENSION cl_khr_fp64 : enable
+
+typedef int int4 __attribute((ext_vector_type(4)));
+typedef long long4 __attribute((ext_vector_type(4)));
+typedef float float4 __attribute((ext_vector_type(4)));
+typedef double double4 __attribute((ext_vector_type(4)));
+
+// CHECK: floatops
+kernel void floatops(global int4 *out, global float4 *fout) {
+ // CHECK: store <4 x i32> <i32 -1, i32 -1, i32 -1, i32 -1>
+ out[0] = (float4)(1, 1, 1, 1) && 1.0f;
+ // CHECK: store <4 x i32> zeroinitializer
+ out[1] = (float4)(0, 0, 0, 0) && (float4)(0, 0, 0, 0);
+
+ // CHECK: store <4 x i32> <i32 -1, i32 -1, i32 -1, i32 -1>
+ out[2] = (float4)(0, 0, 0, 0) || (float4)(1, 1, 1, 1);
+ // CHECK: store <4 x i32> zeroinitializer
+ out[3] = (float4)(0, 0, 0, 0) || 0.0f;
+
+ // CHECK: store <4 x i32> <i32 -1, i32 -1, i32 -1, i32 -1>
+ out[4] = !(float4)(0, 0, 0, 0);
+ // CHECK: store <4 x i32> zeroinitializer
+ out[5] = !(float4)(1, 2, 3, 4);
+ // CHECK: store <4 x i32> <i32 -1, i32 0, i32 -1, i32 0>
+ out[6] = !(float4)(0, 1, 0, 1);
+ // CHECK: store <4 x float> <float 1.000000e+00, float 1.000000e+00, float 1.000000e+00, float 1.000000e+00>
+ fout[0] = (float4)(!0.0f);
+ // CHECK: store <4 x float> zeroinitializer
+ fout[1] = (float4)(!1.0f);
+}
+
+// CHECK: doubleops
+kernel void doubleops(global long4 *out, global double4 *dout) {
+ // CHECK: store <4 x i64> <i64 -1, i64 -1, i64 -1, i64 -1>
+ out[0] = (double4)(1, 1, 1, 1) && 1.0;
+ // CHECK: store <4 x i64> zeroinitializer
+ out[1] = (double4)(0, 0, 0, 0) && (double4)(0, 0, 0, 0);
+
+ // CHECK: store <4 x i64> <i64 -1, i64 -1, i64 -1, i64 -1>
+ out[2] = (double4)(0, 0, 0, 0) || (double4)(1, 1, 1, 1);
+ // CHECK: store <4 x i64> zeroinitializer
+ out[3] = (double4)(0, 0, 0, 0) || 0.0f;
+
+ // CHECK: store <4 x i64> <i64 -1, i64 -1, i64 -1, i64 -1>
+ out[4] = !(double4)(0, 0, 0, 0);
+ // CHECK: store <4 x i64> zeroinitializer
+ out[5] = !(double4)(1, 2, 3, 4);
+ // CHECK: store <4 x i64> <i64 -1, i64 0, i64 -1, i64 0>
+ out[6] = !(double4)(0, 1, 0, 1);
+ // CHECK: store <4 x double> <double 1.000000e+00, double 1.000000e+00, double 1.000000e+00, double 1.000000e+00>
+ dout[0] = (double4)(!0.0f);
+ // CHECK: store <4 x double> zeroinitializer
+ dout[1] = (double4)(!1.0f);
+}
diff --git a/test/CodeGenOpenCL/opencl_types.cl b/test/CodeGenOpenCL/opencl_types.cl
new file mode 100644
index 0000000..b1e558d
--- /dev/null
+++ b/test/CodeGenOpenCL/opencl_types.cl
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 %s -emit-llvm -o - -O0 | FileCheck %s
+
+constant sampler_t glb_smp = 7;
+// CHECK: global i32 7
+
+void fnc1(image1d_t img) {}
+// CHECK: @fnc1(%opencl.image1d_t*
+
+void fnc1arr(image1d_array_t img) {}
+// CHECK: @fnc1arr(%opencl.image1d_array_t*
+
+void fnc1buff(image1d_buffer_t img) {}
+// CHECK: @fnc1buff(%opencl.image1d_buffer_t*
+
+void fnc2(image2d_t img) {}
+// CHECK: @fnc2(%opencl.image2d_t*
+
+void fnc2arr(image2d_array_t img) {}
+// CHECK: @fnc2arr(%opencl.image2d_array_t*
+
+void fnc3(image3d_t img) {}
+// CHECK: @fnc3(%opencl.image3d_t*
+
+void fnc4smp(sampler_t s) {}
+// CHECK: define void @fnc4smp(i32
+
+kernel void foo(image1d_t img) {
+ sampler_t smp = 5;
+// CHECK: alloca i32
+ event_t evt;
+// CHECK: alloca %opencl.event_t*
+// CHECK: store i32 5,
+ fnc4smp(smp);
+// CHECK: call void @fnc4smp(i32
+ fnc4smp(glb_smp);
+// CHECK: call void @fnc4smp(i32
+}
diff --git a/test/CodeGenOpenCL/ptx-calls.cl b/test/CodeGenOpenCL/ptx-calls.cl
index 34a21c6..d990451 100644
--- a/test/CodeGenOpenCL/ptx-calls.cl
+++ b/test/CodeGenOpenCL/ptx-calls.cl
@@ -2,11 +2,12 @@
void device_function() {
}
-// CHECK: define ptx_device void @device_function()
+// CHECK: define void @device_function()
__kernel void kernel_function() {
device_function();
}
-// CHECK: define ptx_kernel void @kernel_function()
-// CHECK: call ptx_device void @device_function()
+// CHECK: define void @kernel_function()
+// CHECK: call void @device_function()
+// CHECK: !{{[0-9]+}} = metadata !{void ()* @kernel_function, metadata !"kernel", i32 1}
diff --git a/test/CodeGenOpenCL/ptx-kernels.cl b/test/CodeGenOpenCL/ptx-kernels.cl
index 1d7e497..07648e4 100644
--- a/test/CodeGenOpenCL/ptx-kernels.cl
+++ b/test/CodeGenOpenCL/ptx-kernels.cl
@@ -2,9 +2,10 @@
void device_function() {
}
-// CHECK: define ptx_device void @device_function()
+// CHECK: define void @device_function()
__kernel void kernel_function() {
}
-// CHECK: define ptx_kernel void @kernel_function()
+// CHECK: define void @kernel_function()
+// CHECK: !{{[0-9]+}} = metadata !{void ()* @kernel_function, metadata !"kernel", i32 1}
diff --git a/test/CodeGenOpenCL/shifts.cl b/test/CodeGenOpenCL/shifts.cl
new file mode 100644
index 0000000..015a777
--- /dev/null
+++ b/test/CodeGenOpenCL/shifts.cl
@@ -0,0 +1,57 @@
+// RUN: %clang_cc1 -x cl -O1 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
+// OpenCL essentially reduces all shift amounts to the last word-size bits before evaluating.
+// Test this both for variables and constants evaluated in the front-end.
+
+
+//CHECK: @positiveShift32
+int positiveShift32(int a,int b) {
+ //CHECK: [[M32:%.+]] = and i32 %b, 31
+ //CHECK-NEXT: [[C32:%.+]] = shl i32 %a, [[M32]]
+ int c = a<<b;
+ int d = ((int)1)<<33;
+ //CHECK-NEXT: [[E32:%.+]] = add nsw i32 [[C32]], 2
+ int e = c + d;
+ //CHECK-NEXT: ret i32 [[E32]]
+ return e;
+}
+
+//CHECK: @positiveShift64
+long positiveShift64(long a,long b) {
+ //CHECK: [[M64:%.+]] = and i64 %b, 63
+ //CHECK-NEXT: [[C64:%.+]] = ashr i64 %a, [[M64]]
+ long c = a>>b;
+ long d = ((long)8)>>65;
+ //CHECK-NEXT: [[E64:%.+]] = add nsw i64 [[C64]], 4
+ long e = c + d;
+ //CHECK-NEXT: ret i64 [[E64]]
+ return e;
+}
+
+typedef __attribute__((ext_vector_type(4))) int int4;
+
+//CHECK: @vectorVectorTest
+int4 vectorVectorTest(int4 a,int4 b) {
+ //CHECK: [[VM:%.+]] = and <4 x i32> %b, <i32 31, i32 31, i32 31, i32 31>
+ //CHECK-NEXT: [[VC:%.+]] = shl <4 x i32> %a, [[VM]]
+ int4 c = a << b;
+ //CHECK-NEXT: [[VF:%.+]] = add <4 x i32> [[VC]], <i32 2, i32 4, i32 16, i32 8>
+ int4 d = {1, 1, 1, 1};
+ int4 e = {33, 34, -28, -29};
+ int4 f = c + (d << e);
+ //CHECK-NEXT: ret <4 x i32> [[VF]]
+ return f;
+}
+
+//CHECK: @vectorScalarTest
+int4 vectorScalarTest(int4 a,int b) {
+ //CHECK: [[SP0:%.+]] = insertelement <4 x i32> undef, i32 %b, i32 0
+ //CHECK: [[SP1:%.+]] = shufflevector <4 x i32> [[SP0]], <4 x i32> undef, <4 x i32> zeroinitializer
+ //CHECK: [[VSM:%.+]] = and <4 x i32> [[SP1]], <i32 31, i32 31, i32 31, i32 31>
+ //CHECK-NEXT: [[VSC:%.+]] = shl <4 x i32> %a, [[VSM]]
+ int4 c = a << b;
+ //CHECK-NEXT: [[VSF:%.+]] = add <4 x i32> [[VSC]], <i32 4, i32 4, i32 4, i32 4>
+ int4 d = {1, 1, 1, 1};
+ int4 f = c + (d << 34);
+ //CHECK-NEXT: ret <4 x i32> [[VSF]]
+ return f;
+}
diff --git a/test/CodeGenOpenCL/spir32_target.cl b/test/CodeGenOpenCL/spir32_target.cl
new file mode 100644
index 0000000..8f395b3
--- /dev/null
+++ b/test/CodeGenOpenCL/spir32_target.cl
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 %s -triple "spir-unknown-unknown" -emit-llvm -o - | FileCheck %s
+
+// CHECK: target triple = "spir-unknown-unknown"
+
+typedef struct {
+ char c;
+ void *v;
+ void *v2;
+} my_st;
+
+kernel void foo(global long *arg) {
+ int res1[sizeof(my_st) == 12 ? 1 : -1];
+ int res2[sizeof(void *) == 4 ? 1 : -1];
+ int res3[sizeof(arg) == 4 ? 1 : -1];
+
+ my_st *tmp = 0;
+
+ arg[0] = (long)(&tmp->v);
+//CHECK: store i64 4, i64 addrspace(1)*
+ arg[1] = (long)(&tmp->v2);
+//CHECK: store i64 8, i64 addrspace(1)*
+}
diff --git a/test/CodeGenOpenCL/spir64_target.cl b/test/CodeGenOpenCL/spir64_target.cl
new file mode 100644
index 0000000..245cd80
--- /dev/null
+++ b/test/CodeGenOpenCL/spir64_target.cl
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 %s -triple "spir64-unknown-unknown" -emit-llvm -o - | FileCheck %s
+
+// CHECK: target triple = "spir64-unknown-unknown"
+
+typedef struct {
+ char c;
+ void *v;
+ void *v2;
+} my_st;
+
+kernel void foo(global long *arg) {
+ int res1[sizeof(my_st) == 24 ? 1 : -1];
+ int res2[sizeof(void *) == 8 ? 1 : -1];
+ int res3[sizeof(arg) == 8 ? 1 : -1];
+
+ my_st *tmp = 0;
+ arg[3] = (long)(&tmp->v);
+//CHECK: store i64 8, i64 addrspace(1)*
+ arg[4] = (long)(&tmp->v2);
+//CHECK: store i64 16, i64 addrspace(1)*
+}
diff --git a/test/Coverage/objc-language-features.inc b/test/Coverage/objc-language-features.inc
index dbbf205..29d8298 100644
--- a/test/Coverage/objc-language-features.inc
+++ b/test/Coverage/objc-language-features.inc
@@ -9,6 +9,7 @@
@class B;
@interface Root
+@property(readonly) int p0;
@end
@interface A : Root <P1> {
diff --git a/test/Driver/Inputs/basic_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtbeginT.o b/test/Driver/Inputs/basic_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtbeginT.o
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Driver/Inputs/basic_linux_tree/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtbeginT.o
diff --git a/test/Driver/Inputs/hexagon_tree/gnu/bin/hexagon-as b/test/Driver/Inputs/hexagon_tree/gnu/bin/hexagon-as
new file mode 100755
index 0000000..331ef4a
--- /dev/null
+++ b/test/Driver/Inputs/hexagon_tree/gnu/bin/hexagon-as
@@ -0,0 +1 @@
+# placeholder for testing purposes \ No newline at end of file
diff --git a/test/Driver/Inputs/hexagon_tree/gnu/bin/hexagon-gcc b/test/Driver/Inputs/hexagon_tree/gnu/bin/hexagon-gcc
new file mode 100755
index 0000000..331ef4a
--- /dev/null
+++ b/test/Driver/Inputs/hexagon_tree/gnu/bin/hexagon-gcc
@@ -0,0 +1 @@
+# placeholder for testing purposes \ No newline at end of file
diff --git a/test/Driver/Inputs/hexagon_tree/gnu/bin/hexagon-ld b/test/Driver/Inputs/hexagon_tree/gnu/bin/hexagon-ld
new file mode 100755
index 0000000..331ef4a
--- /dev/null
+++ b/test/Driver/Inputs/hexagon_tree/gnu/bin/hexagon-ld
@@ -0,0 +1 @@
+# placeholder for testing purposes \ No newline at end of file
diff --git a/test/Driver/Inputs/hexagon_tree/gnu/hexagon/include/c++/4.4.0/ios b/test/Driver/Inputs/hexagon_tree/gnu/hexagon/include/c++/4.4.0/ios
new file mode 100644
index 0000000..777a4ec
--- /dev/null
+++ b/test/Driver/Inputs/hexagon_tree/gnu/hexagon/include/c++/4.4.0/ios
@@ -0,0 +1 @@
+// placeholder for testing purposes
diff --git a/test/Driver/Inputs/hexagon_tree/gnu/hexagon/include/stdio.h b/test/Driver/Inputs/hexagon_tree/gnu/hexagon/include/stdio.h
new file mode 100644
index 0000000..777a4ec
--- /dev/null
+++ b/test/Driver/Inputs/hexagon_tree/gnu/hexagon/include/stdio.h
@@ -0,0 +1 @@
+// placeholder for testing purposes
diff --git a/test/Driver/Inputs/hexagon_tree/gnu/lib/gcc/hexagon/4.4.0/include-fixed/limits.h b/test/Driver/Inputs/hexagon_tree/gnu/lib/gcc/hexagon/4.4.0/include-fixed/limits.h
new file mode 100644
index 0000000..777a4ec
--- /dev/null
+++ b/test/Driver/Inputs/hexagon_tree/gnu/lib/gcc/hexagon/4.4.0/include-fixed/limits.h
@@ -0,0 +1 @@
+// placeholder for testing purposes
diff --git a/test/Driver/Inputs/hexagon_tree/gnu/lib/gcc/hexagon/4.4.0/include/stddef.h b/test/Driver/Inputs/hexagon_tree/gnu/lib/gcc/hexagon/4.4.0/include/stddef.h
new file mode 100644
index 0000000..777a4ec
--- /dev/null
+++ b/test/Driver/Inputs/hexagon_tree/gnu/lib/gcc/hexagon/4.4.0/include/stddef.h
@@ -0,0 +1 @@
+// placeholder for testing purposes
diff --git a/test/Driver/Inputs/hexagon_tree/qc/bin/placeholder b/test/Driver/Inputs/hexagon_tree/qc/bin/placeholder
new file mode 100644
index 0000000..777a4ec
--- /dev/null
+++ b/test/Driver/Inputs/hexagon_tree/qc/bin/placeholder
@@ -0,0 +1 @@
+// placeholder for testing purposes
diff --git a/test/Driver/Inputs/lit.local.cfg b/test/Driver/Inputs/lit.local.cfg
new file mode 100644
index 0000000..e6f55ee
--- /dev/null
+++ b/test/Driver/Inputs/lit.local.cfg
@@ -0,0 +1 @@
+config.suffixes = []
diff --git a/test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.asan-i386.a.syms b/test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.asan-i386.a.syms
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.asan-i386.a.syms
diff --git a/test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.asan-x86_64.a.syms b/test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.asan-x86_64.a.syms
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.asan-x86_64.a.syms
diff --git a/test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.msan-x86_64.a.syms b/test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.msan-x86_64.a.syms
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.msan-x86_64.a.syms
diff --git a/test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.tsan-x86_64.a.syms b/test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.tsan-x86_64.a.syms
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.tsan-x86_64.a.syms
diff --git a/test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.ubsan-i386.a.syms b/test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.ubsan-i386.a.syms
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.ubsan-i386.a.syms
diff --git a/test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.ubsan-x86_64.a.syms b/test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.ubsan-x86_64.a.syms
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.ubsan-x86_64.a.syms
diff --git a/test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.ubsan_cxx-i386.a.syms b/test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.ubsan_cxx-i386.a.syms
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.ubsan_cxx-i386.a.syms
diff --git a/test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.ubsan_cxx-x86_64.a.syms b/test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.ubsan_cxx-x86_64.a.syms
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Driver/Inputs/resource_dir/lib/linux/libclang_rt.ubsan_cxx-x86_64.a.syms
diff --git a/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/lib/x86_64-linux-gnu/.keep b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/lib/x86_64-linux-gnu/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/lib/x86_64-linux-gnu/.keep
diff --git a/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/include/c++/4.7/backward/.keep b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/include/c++/4.7/backward/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/include/c++/4.7/backward/.keep
diff --git a/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/include/x86_64-linux-gnu/c++/4.7/.keep b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/include/x86_64-linux-gnu/c++/4.7/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/include/x86_64-linux-gnu/c++/4.7/.keep
diff --git a/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/include/x86_64-linux-gnu/c++/4.7/32/.keep b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/include/x86_64-linux-gnu/c++/4.7/32/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/include/x86_64-linux-gnu/c++/4.7/32/.keep
diff --git a/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/lib/gcc/x86_64-linux-gnu/4.7/32/.keep b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/lib/gcc/x86_64-linux-gnu/4.7/32/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/lib/gcc/x86_64-linux-gnu/4.7/32/.keep
diff --git a/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/lib/gcc/x86_64-linux-gnu/4.7/32/crtbegin.o b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/lib/gcc/x86_64-linux-gnu/4.7/32/crtbegin.o
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/lib/gcc/x86_64-linux-gnu/4.7/32/crtbegin.o
diff --git a/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/lib/gcc/x86_64-linux-gnu/4.7/crtbegin.o b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/lib/gcc/x86_64-linux-gnu/4.7/crtbegin.o
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Driver/Inputs/ubuntu_13.04_multiarch_tree/usr/lib/gcc/x86_64-linux-gnu/4.7/crtbegin.o
diff --git a/test/Driver/aarch64-features.c b/test/Driver/aarch64-features.c
new file mode 100644
index 0000000..2acb715
--- /dev/null
+++ b/test/Driver/aarch64-features.c
@@ -0,0 +1,5 @@
+// RUN: %clang -target aarch64-none-linux-gnu -### %s -fsyntax-only 2>&1 | FileCheck %s
+
+// The AArch64 PCS states that chars should be unsigned.
+// CHECK: fno-signed-char
+
diff --git a/test/Driver/altivec.cpp b/test/Driver/altivec.cpp
deleted file mode 100644
index 4e6fbe5..0000000
--- a/test/Driver/altivec.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-// Check that we error when -faltivec is specified on non-ppc platforms.
-
-// RUN: %clang -target powerpc-unk-unk -faltivec -fsyntax-only %s
-// RUN: %clang -target powerpc64-linux-gnu -faltivec -fsyntax-only %s
-// RUN: %clang -target powerpc64-linux-gnu -maltivec -fsyntax-only %s
-
-// RUN: %clang -target i386-pc-win32 -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
-// RUN: %clang -target x86_64-unknown-freebsd -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
-// RUN: %clang -target armv6-apple-darwin -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
-// RUN: %clang -target armv7-apple-darwin -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
-// RUN: %clang -target mips-linux-gnu -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
-// RUN: %clang -target mips64-linux-gnu -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
-// RUN: %clang -target sparc-unknown-solaris -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
-
-// CHECK: invalid argument '-faltivec' only allowed with 'ppc/ppc64'
diff --git a/test/Driver/apple-kext-mkernel.c b/test/Driver/apple-kext-mkernel.c
index f8b7b90..8282c05 100644
--- a/test/Driver/apple-kext-mkernel.c
+++ b/test/Driver/apple-kext-mkernel.c
@@ -8,11 +8,12 @@
// CHECK-X86: "-fno-common"
// RUN: %clang -target x86_64-apple-darwin10 \
-// RUN: -arch armv7 -mkernel -### -fsyntax-only %s 2> %t
+// RUN: -arch armv7 -mkernel -mstrict-align -### -fsyntax-only %s 2> %t
// RUN: FileCheck --check-prefix=CHECK-ARM < %t %s
// CHECK-ARM: "-backend-option" "-arm-long-calls"
// CHECK-ARM: "-backend-option" "-arm-strict-align"
+// CHECK-ARM-NOT: "-backend-option" "-arm-strict-align"
// CHECK-ARM: "-fno-builtin"
// CHECK-ARM: "-fno-rtti"
// CHECK-ARM: "-fno-common"
diff --git a/test/Driver/arm-cortex-cpus.c b/test/Driver/arm-cortex-cpus.c
new file mode 100644
index 0000000..6fa649a
--- /dev/null
+++ b/test/Driver/arm-cortex-cpus.c
@@ -0,0 +1,8 @@
+// RUN: %clang -target armv6m-apple-darwin -arch armv6m -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V6M %s
+// CHECK-V6M: "-cc1"{{.*}} "-triple" "thumbv6m-{{.*}} "-target-cpu" "cortex-m0"
+
+// RUN: %clang -target armv7m-apple-darwin -arch armv7m -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V7M %s
+// CHECK-V7M: "-cc1"{{.*}} "-triple" "thumbv7m-{{.*}} "-target-cpu" "cortex-m3"
+
+// RUN: %clang -target armv7em-apple-darwin -arch armv7em -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-V7EM %s
+// CHECK-V7EM: "-cc1"{{.*}} "-triple" "thumbv7em-{{.*}} "-target-cpu" "cortex-m4"
diff --git a/test/Driver/asan-ld.c b/test/Driver/asan-ld.c
deleted file mode 100644
index 59dbda1..0000000
--- a/test/Driver/asan-ld.c
+++ /dev/null
@@ -1,50 +0,0 @@
-// Test AddressSanitizer ld flags.
-
-// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-// 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"
-// CHECK-LINUX: "-lpthread"
-// CHECK-LINUX: "-ldl"
-// CHECK-LINUX: "-export-dynamic"
-
-// 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/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: 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/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: libclang_rt.asan-arm-android.so"
-// CHECK-ANDROID-SHARED-NOT: "-lpthread"
diff --git a/test/Driver/bounds-checking.c b/test/Driver/bounds-checking.c
index 95bb8af..a4f97e8 100644
--- a/test/Driver/bounds-checking.c
+++ b/test/Driver/bounds-checking.c
@@ -1,7 +1,11 @@
-// RUN: %clang -target x86_64-apple-darwin10 -fbounds-checking -### -fsyntax-only %s 2> %t
-// RUN: FileCheck < %t %s
-// RUN: %clang -target x86_64-apple-darwin10 -fbounds-checking=3 -### -fsyntax-only %s 2> %t
-// RUN: FileCheck -check-prefix=CHECK2 < %t %s
+// RUN: %clang -fsanitize=bounds -### -fsyntax-only %s 2> %t
+// RUN: FileCheck -check-prefix=CHECK < %t %s
+// CHECK: "-fsanitize=bounds"
-// CHECK: "-fbounds-checking=1"
-// CHECK2: "-fbounds-checking=3"
+// RUN: %clang -fbounds-checking -### -fsyntax-only %s 2> %t
+// RUN: FileCheck -check-prefix=CHECK-OLD < %t %s
+// CHECK-OLD: "-fsanitize=bounds"
+
+// RUN: %clang -fbounds-checking=3 -### -fsyntax-only %s 2> %t
+// RUN: FileCheck -check-prefix=CHECK-OLD2 < %t %s
+// CHECK-OLD2: "-fsanitize=bounds"
diff --git a/test/Driver/claim-unused.c b/test/Driver/claim-unused.c
new file mode 100644
index 0000000..c7b7989
--- /dev/null
+++ b/test/Driver/claim-unused.c
@@ -0,0 +1,3 @@
+// RUN: touch %t.o
+// RUN: %clang --param ssp-buffer-size=1 %t.o -### 2>&1 | FileCheck %s
+// CHECK-NOT: warning: argument unused during compilation: '--param ssp-buffer-size=1'
diff --git a/test/Driver/clang-g-opts.c b/test/Driver/clang-g-opts.c
index 4dbdf61..f5d09fd 100644
--- a/test/Driver/clang-g-opts.c
+++ b/test/Driver/clang-g-opts.c
@@ -1,5 +1,9 @@
-// RUN: %clang -S -v -o %t %s 2>&1 | not grep -w -- -g
-// RUN: %clang -S -v -o %t %s -g 2>&1 | grep -w -- -g
-// RUN: %clang -S -v -o %t %s -g0 2>&1 | not grep -w -- -g
-// RUN: %clang -S -v -o %t %s -g -g0 2>&1 | not grep -w -- -g
-// RUN: %clang -S -v -o %t %s -g0 -g 2>&1 | grep -w -- -g
+// RUN: %clang -### -S %s 2>&1 | FileCheck --check-prefix=CHECK-WITHOUT-G %s
+// RUN: %clang -### -S %s -g 2>&1 | FileCheck --check-prefix=CHECK-WITH-G %s
+// RUN: %clang -### -S %s -g0 2>&1 | FileCheck --check-prefix=CHECK-WITHOUT-G %s
+// RUN: %clang -### -S %s -g -g0 2>&1 | FileCheck --check-prefix=CHECK-WITHOUT-G %s
+// RUN: %clang -### -S %s -g0 -g 2>&1 | FileCheck --check-prefix=CHECK-WITH-G %s
+
+// CHECK-WITHOUT-G-NOT: "-g"
+// CHECK-WITH-G: "-g"
+
diff --git a/test/Driver/clang-translation.c b/test/Driver/clang-translation.c
index 3ddb189e..3b2b7e8 100644
--- a/test/Driver/clang-translation.c
+++ b/test/Driver/clang-translation.c
@@ -67,6 +67,108 @@
// PPCPWR7: "-target-cpu" "pwr7"
// RUN: %clang -target powerpc64-unknown-linux-gnu \
+// RUN: -### -S %s -mcpu=a2q 2>&1 | FileCheck -check-prefix=PPCA2Q %s
+// PPCA2Q: clang
+// PPCA2Q: "-cc1"
+// PPCA2Q: "-target-cpu" "a2q"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu \
+// RUN: -### -S %s -mcpu=630 2>&1 | FileCheck -check-prefix=PPC630 %s
+// PPC630: clang
+// PPC630: "-cc1"
+// PPC630: "-target-cpu" "pwr3"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu \
+// RUN: -### -S %s -mcpu=power3 2>&1 | FileCheck -check-prefix=PPCPOWER3 %s
+// PPCPOWER3: clang
+// PPCPOWER3: "-cc1"
+// PPCPOWER3: "-target-cpu" "pwr3"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu \
+// RUN: -### -S %s -mcpu=pwr3 2>&1 | FileCheck -check-prefix=PPCPWR3 %s
+// PPCPWR3: clang
+// PPCPWR3: "-cc1"
+// PPCPWR3: "-target-cpu" "pwr3"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu \
+// RUN: -### -S %s -mcpu=power4 2>&1 | FileCheck -check-prefix=PPCPOWER4 %s
+// PPCPOWER4: clang
+// PPCPOWER4: "-cc1"
+// PPCPOWER4: "-target-cpu" "pwr4"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu \
+// RUN: -### -S %s -mcpu=pwr4 2>&1 | FileCheck -check-prefix=PPCPWR4 %s
+// PPCPWR4: clang
+// PPCPWR4: "-cc1"
+// PPCPWR4: "-target-cpu" "pwr4"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu \
+// RUN: -### -S %s -mcpu=power5 2>&1 | FileCheck -check-prefix=PPCPOWER5 %s
+// PPCPOWER5: clang
+// PPCPOWER5: "-cc1"
+// PPCPOWER5: "-target-cpu" "pwr5"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu \
+// RUN: -### -S %s -mcpu=pwr5 2>&1 | FileCheck -check-prefix=PPCPWR5 %s
+// PPCPWR5: clang
+// PPCPWR5: "-cc1"
+// PPCPWR5: "-target-cpu" "pwr5"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu \
+// RUN: -### -S %s -mcpu=power5x 2>&1 | FileCheck -check-prefix=PPCPOWER5X %s
+// PPCPOWER5X: clang
+// PPCPOWER5X: "-cc1"
+// PPCPOWER5X: "-target-cpu" "pwr5x"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu \
+// RUN: -### -S %s -mcpu=pwr5x 2>&1 | FileCheck -check-prefix=PPCPWR5X %s
+// PPCPWR5X: clang
+// PPCPWR5X: "-cc1"
+// PPCPWR5X: "-target-cpu" "pwr5x"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu \
+// RUN: -### -S %s -mcpu=power6 2>&1 | FileCheck -check-prefix=PPCPOWER6 %s
+// PPCPOWER6: clang
+// PPCPOWER6: "-cc1"
+// PPCPOWER6: "-target-cpu" "pwr6"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu \
+// RUN: -### -S %s -mcpu=pwr6 2>&1 | FileCheck -check-prefix=PPCPWR6 %s
+// PPCPWR6: clang
+// PPCPWR6: "-cc1"
+// PPCPWR6: "-target-cpu" "pwr6"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu \
+// RUN: -### -S %s -mcpu=power6x 2>&1 | FileCheck -check-prefix=PPCPOWER6X %s
+// PPCPOWER6X: clang
+// PPCPOWER6X: "-cc1"
+// PPCPOWER6X: "-target-cpu" "pwr6x"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu \
+// RUN: -### -S %s -mcpu=pwr6x 2>&1 | FileCheck -check-prefix=PPCPWR6X %s
+// PPCPWR6X: clang
+// PPCPWR6X: "-cc1"
+// PPCPWR6X: "-target-cpu" "pwr6x"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu \
+// RUN: -### -S %s -mcpu=power7 2>&1 | FileCheck -check-prefix=PPCPOWER7 %s
+// PPCPOWER7: clang
+// PPCPOWER7: "-cc1"
+// PPCPOWER7: "-target-cpu" "pwr7"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu \
+// RUN: -### -S %s -mcpu=powerpc 2>&1 | FileCheck -check-prefix=PPCPOWERPC %s
+// PPCPOWERPC: clang
+// PPCPOWERPC: "-cc1"
+// PPCPOWERPC: "-target-cpu" "ppc"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu \
+// RUN: -### -S %s -mcpu=powerpc64 2>&1 | FileCheck -check-prefix=PPCPOWERPC64 %s
+// PPCPOWERPC64: clang
+// PPCPOWERPC64: "-cc1"
+// PPCPOWERPC64: "-target-cpu" "ppc64"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu \
// RUN: -### -S %s 2>&1 | FileCheck -check-prefix=PPC64NS %s
// PPC64NS: clang
// PPC64NS: "-cc1"
diff --git a/test/Driver/clang_f_opts.c b/test/Driver/clang_f_opts.c
index 0ee7d2da..c1431a1 100644
--- a/test/Driver/clang_f_opts.c
+++ b/test/Driver/clang_f_opts.c
@@ -1,6 +1,7 @@
-// RUN: %clang -### -S -fasm -fblocks -fbuiltin -fno-math-errno -fcommon -fpascal-strings -fno-blocks -fno-builtin -fmath-errno -fno-common -fno-pascal-strings -fblocks -fbuiltin -fmath-errno -fcommon -fpascal-strings %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS1 %s
+// RUN: %clang -### -S -fasm -fblocks -fbuiltin -fno-math-errno -fcommon -fpascal-strings -fno-blocks -fno-builtin -fmath-errno -fno-common -fno-pascal-strings -fblocks -fbuiltin -fmath-errno -fcommon -fpascal-strings -fsplit-stack %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS1 %s
// RUN: %clang -### -S -fasm -fblocks -fbuiltin -fno-math-errno -fcommon -fpascal-strings -fno-asm -fno-blocks -fno-builtin -fmath-errno -fno-common -fno-pascal-strings -fno-show-source-location -fshort-enums -fshort-wchar %s 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS2 %s
+// CHECK-OPTIONS1: -split-stacks
// CHECK-OPTIONS1: -fgnu-keywords
// CHECK-OPTIONS1: -fblocks
// CHECK-OPTIONS1: -fpascal-strings
@@ -36,5 +37,30 @@
// FP-CONTRACT-FAST-CHECK: -ffp-contract=fast
// FP-CONTRACT-OFF-CHECK: -ffp-contract=off
-// RUN: %clang -fms-extensions -fenable-experimental-ms-inline-asm %s -### 2>&1 | FileCheck -check-prefix=CHECK-OPTIONS3 %s
-// CHECK-OPTIONS3: -fenable-experimental-ms-inline-asm
+// RUN: %clang -### -S -fvectorize %s 2>&1 | FileCheck -check-prefix=CHECK-VECTORIZE %s
+// RUN: %clang -### -S -fno-vectorize -fvectorize %s 2>&1 | FileCheck -check-prefix=CHECK-VECTORIZE %s
+// RUN: %clang -### -S -fno-vectorize %s 2>&1 | FileCheck -check-prefix=CHECK-NO-VECTORIZE %s
+// RUN: %clang -### -S -fvectorize -fno-vectorize %s 2>&1 | FileCheck -check-prefix=CHECK-NO-VECTORIZE %s
+// RUN: %clang -### -S -ftree-vectorize %s 2>&1 | FileCheck -check-prefix=CHECK-VECTORIZE %s
+// RUN: %clang -### -S -fno-tree-vectorize -fvectorize %s 2>&1 | FileCheck -check-prefix=CHECK-VECTORIZE %s
+// RUN: %clang -### -S -fno-tree-vectorize %s 2>&1 | FileCheck -check-prefix=CHECK-NO-VECTORIZE %s
+// RUN: %clang -### -S -ftree-vectorize -fno-vectorize %s 2>&1 | FileCheck -check-prefix=CHECK-NO-VECTORIZE %s
+// CHECK-VECTORIZE: "-vectorize-loops"
+// CHECK-NO-VECTORIZE-NOT: "-vectorize-loops"
+
+// RUN: %clang -### -S -fslp-vectorize %s 2>&1 | FileCheck -check-prefix=CHECK-SLP-VECTORIZE %s
+// RUN: %clang -### -S -fno-slp-vectorize -fslp-vectorize %s 2>&1 | FileCheck -check-prefix=CHECK-SLP-VECTORIZE %s
+// RUN: %clang -### -S -fno-slp-vectorize %s 2>&1 | FileCheck -check-prefix=CHECK-NO-SLP-VECTORIZE %s
+// RUN: %clang -### -S -fslp-vectorize -fno-slp-vectorize %s 2>&1 | FileCheck -check-prefix=CHECK-NO-SLP-VECTORIZE %s
+// RUN: %clang -### -S -ftree-slp-vectorize %s 2>&1 | FileCheck -check-prefix=CHECK-SLP-VECTORIZE %s
+// RUN: %clang -### -S -fno-tree-slp-vectorize -fslp-vectorize %s 2>&1 | FileCheck -check-prefix=CHECK-SLP-VECTORIZE %s
+// RUN: %clang -### -S -fno-tree-slp-vectorize %s 2>&1 | FileCheck -check-prefix=CHECK-NO-SLP-VECTORIZE %s
+// RUN: %clang -### -S -ftree-slp-vectorize -fno-slp-vectorize %s 2>&1 | FileCheck -check-prefix=CHECK-NO-SLP-VECTORIZE %s
+// CHECK-SLP-VECTORIZE: "-vectorize"
+// CHECK-NO-SLP-VECTORIZE-NOT: "-vectorize"
+
+// RUN: %clang -### -S -fextended-identifiers %s 2>&1 | FileCheck -check-prefix=CHECK-EXTENDED-IDENTIFIERS %s
+// RUN: %clang -### -S -fno-extended-identifiers %s 2>&1 | FileCheck -check-prefix=CHECK-NO-EXTENDED-IDENTIFIERS %s
+// CHECK-EXTENDED-IDENTIFIERS: "-cc1"
+// CHECK-EXTENDED-IDENTIFIERS-NOT: "-fextended-identifiers"
+// CHECK-NO-EXTENDED-IDENTIFIERS: error: unsupported option '-fno-extended-identifiers'
diff --git a/test/Driver/constructors.c b/test/Driver/constructors.c
index ca2cac2..9ea91d9 100644
--- a/test/Driver/constructors.c
+++ b/test/Driver/constructors.c
@@ -1,14 +1,48 @@
+// Test whether or not the driver instructs the backend to use .init_array
+// sections for global constructors.
+//
+// CHECK-INIT-ARRAY: -fuse-init-array
+// CHECK-NO-INIT-ARRAY-NOT: -fuse-init-array
+//
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: --sysroot=%S/Inputs/fake_install_tree \
-// RUN: | FileCheck --check-prefix=CHECK-GCC-4-7 %s
-
-// CHECK-GCC-4-7: -fuse-init-array
-
+// RUN: | FileCheck --check-prefix=CHECK-INIT-ARRAY %s
+//
+// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
+// RUN: -fno-use-init-array \
+// RUN: -target i386-unknown-linux \
+// RUN: --sysroot=%S/Inputs/fake_install_tree \
+// RUN: | FileCheck --check-prefix=CHECK-NO-INIT-ARRAY %s
+//
+// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
+// RUN: -fno-use-init-array -fuse-init-array \
+// RUN: -target i386-unknown-linux \
+// RUN: --sysroot=%S/Inputs/fake_install_tree \
+// RUN: | FileCheck --check-prefix=CHECK-INIT-ARRAY %s
+//
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
-// RUN: | FileCheck --check-prefix=CHECK-GCC-4-6 %s
-
-
-// CHECK-GCC-4-6-NOT: -fuse-init-array
+// RUN: | FileCheck --check-prefix=CHECK-NO-INIT-ARRAY %s
+//
+// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
+// RUN: -fuse-init-array \
+// RUN: -target i386-unknown-linux \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-INIT-ARRAY %s
+//
+// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
+// RUN: -target arm-unknown-linux-androideabi \
+// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
+// RUN: | FileCheck --check-prefix=CHECK-INIT-ARRAY %s
+//
+// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
+// RUN: -target mipsel-unknown-linux-android \
+// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
+// RUN: | FileCheck --check-prefix=CHECK-INIT-ARRAY %s
+//
+// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
+// RUN: -target i386-unknown-linux-android \
+// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
+// RUN: | FileCheck --check-prefix=CHECK-INIT-ARRAY %s
diff --git a/test/Driver/crash-report.c b/test/Driver/crash-report.c
index bfcd573..975e9a8 100644
--- a/test/Driver/crash-report.c
+++ b/test/Driver/crash-report.c
@@ -9,6 +9,8 @@
// RUN: cat %t/crash-report-*.sh | FileCheck --check-prefix=CHECKSH %s
// REQUIRES: crash-recovery
+// RUN: env FORCE_CLANG_DIAGNOSTICS_CRASH=1 %clang -fsyntax-only -x c /dev/null 2>&1 | FileCheck %s
+
#pragma clang __debug parser_crash
// CHECK: Preprocessed source(s) and associated run script(s) are located at:
// CHECK-NEXT: note: diagnostic msg: {{.*}}.c
diff --git a/test/Driver/darwin-debug-flags.c b/test/Driver/darwin-debug-flags.c
index baf28475..f98e9ce 100644
--- a/test/Driver/darwin-debug-flags.c
+++ b/test/Driver/darwin-debug-flags.c
@@ -2,6 +2,8 @@
// <rdar://problem/7256886>
// RUN: touch %t.s
// RUN: env RC_DEBUG_OPTIONS=1 %clang -### -target i386-apple-darwin9 -c -g %t.s 2>&1 | FileCheck -check-prefix=S %s
+// <rdar://problem/12955296>
+// RUN: %clang -### -target i386-apple-darwin9 -c -g %t.s 2>&1 | FileCheck -check-prefix=P %s
// CHECK: !0 = metadata !{
// CHECK: -g -Os
@@ -11,3 +13,5 @@
int x;
// S: "-dwarf-debug-flags"
+
+// P: "-dwarf-debug-producer"
diff --git a/test/Driver/darwin-iphone-defaults.m b/test/Driver/darwin-iphone-defaults.m
index bba0cc0..3e2a912 100644
--- a/test/Driver/darwin-iphone-defaults.m
+++ b/test/Driver/darwin-iphone-defaults.m
@@ -1,6 +1,6 @@
// RUN: %clang -target i386-apple-darwin9 -miphoneos-version-min=3.0 -arch armv7 -flto -S -o - %s | FileCheck %s
-// CHECK: @f0() ssp
+// CHECK: @f0() [[F0:#[0-9]+]]
// CHECK: @__f0_block_invoke
// CHECK: void @f1
// CHECK-NOT: msgSend_fixup_alloc
@@ -26,3 +26,4 @@ void f1() {
[I1 alloc];
}
+// CHECK: attributes [[F0]] = { ssp{{.*}} }
diff --git a/test/Driver/darwin-sanitizer-ld.c b/test/Driver/darwin-sanitizer-ld.c
new file mode 100644
index 0000000..98b37e9
--- /dev/null
+++ b/test/Driver/darwin-sanitizer-ld.c
@@ -0,0 +1,52 @@
+// Test sanitizer link flags on Darwin.
+
+// RUN: %clang -no-canonical-prefixes -### -target x86_64-darwin \
+// RUN: -fsanitize=address %s -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-ASAN %s
+
+// CHECK-ASAN: "{{.*}}ld{{(.exe)?}}"
+// CHECK-ASAN: libclang_rt.asan_osx_dynamic.dylib"
+// CHECK-ASAN: stdc++
+
+// RUN: %clang -no-canonical-prefixes -### -target x86_64-darwin \
+// RUN: -fPIC -shared -fsanitize=address %s -o %t.so 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-DYN-ASAN %s
+
+// CHECK-DYN-ASAN: "{{.*}}ld{{(.exe)?}}"
+// CHECK-DYN-ASAN: "-dylib"
+// CHECK-DYN-ASAN-NOT: libclang_rt.asan_osx_dynamic.dylib
+// CHECK-DYN-ASAN: "-undefined"
+// CHECK-DYN-ASAN: "dynamic_lookup"
+// CHECK-DYN-ASAN-NOT: libclang_rt.asan_osx_dynamic.dylib
+
+// RUN: %clang -no-canonical-prefixes -### -target x86_64-darwin \
+// RUN: -fsanitize=undefined %s -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-UBSAN %s
+
+// CHECK-UBSAN: "{{.*}}ld{{(.exe)?}}"
+// CHECK-UBSAN: libclang_rt.ubsan_osx.a"
+// CHECK-UBSAN: stdc++
+
+// RUN: %clang -no-canonical-prefixes -### -target x86_64-darwin \
+// RUN: -fsanitize=bounds -fsanitize-undefined-trap-on-error \
+// RUN: %s -o %t.o 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-BOUNDS %s
+
+// CHECK-BOUNDS: "{{.*}}ld{{(.exe)?}}"
+// CHECK-BOUNDS-NOT: libclang_rt.ubsan_osx.a"
+
+// RUN: %clang -no-canonical-prefixes -### -target x86_64-darwin \
+// RUN: -fPIC -shared -fsanitize=undefined %s -o %t.so 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-DYN-UBSAN %s
+
+// CHECK-DYN-UBSAN: "{{.*}}ld{{(.exe)?}}"
+// CHECK-DYN-UBSAN: "-dylib"
+// CHECK-DYN-UBSAN: libclang_rt.ubsan_osx.a
+
+// RUN: %clang -no-canonical-prefixes -### -target x86_64-darwin \
+// RUN: -fsanitize=bounds -fsanitize-undefined-trap-on-error \
+// RUN: %s -o %t.so -fPIC -shared 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-DYN-BOUNDS %s
+
+// CHECK-DYN-BOUNDS: "{{.*}}ld{{(.exe)?}}"
+// CHECK-DYN-BOUNDS-NOT: libclang_rt.ubsan_osx.a
diff --git a/test/Driver/darwin-sdkroot.c b/test/Driver/darwin-sdkroot.c
index 5abf081..b727fa6 100644
--- a/test/Driver/darwin-sdkroot.c
+++ b/test/Driver/darwin-sdkroot.c
@@ -11,7 +11,7 @@
// 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
@@ -20,3 +20,16 @@
// CHECK-NONPATH: clang
// CHECK-NONPATH: "-cc1"
// CHECK-NONPATH-NOT: "-isysroot"
+
+// Check that we don't use SDKROOT as the default if it is just "/"
+//
+// RUN: env SDKROOT=/ %clang -target x86_64-apple-darwin10 \
+// RUN: -c %s -### 2> %t.log
+// RUN: FileCheck --check-prefix=CHECK-NONROOT < %t.log %s
+//
+// CHECK-NONROOT: clang
+// CHECK-NONROOT: "-cc1"
+// CHECK-NONROOT-NOT: "-isysroot"
+//
+// It doesn't make sense on msys bash.
+// REQUIRES: shell-preserves-root
diff --git a/test/Driver/debug-comp-dir.S b/test/Driver/debug-comp-dir.S
new file mode 100644
index 0000000..ca1ca30
--- /dev/null
+++ b/test/Driver/debug-comp-dir.S
@@ -0,0 +1,11 @@
+// RUN: cd %S && %clang -### -g %s -c 2>&1 | FileCheck -check-prefix=CHECK-PWD %s
+// CHECK-PWD: {{"-fdebug-compilation-dir" ".*Driver.*"}}
+
+// RUN: env PWD=/foo %clang -### -g %s -c 2>&1 | FileCheck -check-prefix=CHECK-FOO %s
+// CHECK-FOO: {{"-fdebug-compilation-dir" ".*foo"}}
+
+// "PWD=/foo gcc" wouldn't necessarily work. You would need to pick a different
+// path to the same directory (try a symlink).
+
+// This depends on host's behavior how $PWD would be set.
+// REQUIRES: shell
diff --git a/test/Driver/debug-main-file.S b/test/Driver/debug-main-file.S
new file mode 100644
index 0000000..8c154a3
--- /dev/null
+++ b/test/Driver/debug-main-file.S
@@ -0,0 +1,12 @@
+// REQUIRES: clang-driver
+// RUN: %clang -### -c -save-temps -integrated-as -g %s 2>&1 \
+// RUN: | FileCheck %s
+
+// CHECK: main-file-name
+
+#ifdef(1)
+foo:
+ nop
+ nop
+ nop
+#endif
diff --git a/test/Driver/debug-options-as.c b/test/Driver/debug-options-as.c
index 57036e4..0b639b2 100644
--- a/test/Driver/debug-options-as.c
+++ b/test/Driver/debug-options-as.c
@@ -1,5 +1,5 @@
// cygming have not supported integrated-as yet.
-// XFAIL: cygwin,mingw32
+// REQUIRES: clang-driver
//
// Check to make sure clang is somewhat picky about -g options.
// (Delived from debug-options.c)
@@ -14,7 +14,16 @@
// rdar://9275556
// RUN: touch %t.s
// RUN: %clang -### -c -integrated-as -g %t.s 2>&1 \
-// RUN: | FileCheck -check-prefix=S %s
+// RUN: | FileCheck %s
//
-// S: "-cc1as"
-// S: "-g"
+// CHECK: "-cc1as"
+// CHECK: "-g"
+
+// Check to make sure clang with -g on a .s file gets passed -dwarf-debug-producer.
+// rdar://12955296
+// RUN: touch %t.s
+// RUN: %clang -### -c -integrated-as -g %t.s 2>&1 \
+// RUN: | FileCheck -check-prefix=P %s
+//
+// P: "-cc1as"
+// P: "-dwarf-debug-producer"
diff --git a/test/Driver/fast-math.c b/test/Driver/fast-math.c
index 17bf6ed..91af2e1 100644
--- a/test/Driver/fast-math.c
+++ b/test/Driver/fast-math.c
@@ -5,7 +5,7 @@
// support.
//
// Both of them use gcc driver for as.
-// XFAIL: cygwin,mingw32
+// REQUIRES: clang-driver
//
// RUN: %clang -### -fno-honor-infinities -c %s 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-NO-INFS %s
diff --git a/test/Driver/fcomment-block-commands.c b/test/Driver/fcomment-block-commands.c
new file mode 100644
index 0000000..d83662a
--- /dev/null
+++ b/test/Driver/fcomment-block-commands.c
@@ -0,0 +1,8 @@
+// Check that we pass -fcomment-block-commands to frontend.
+//
+// RUN: %clang -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-ARG
+// RUN: %clang -c %s -fcomment-block-commands=Foo -### 2>&1 | FileCheck %s --check-prefix=CHECK-ARG
+//
+// CHECK-ARG: -fcomment-block-commands=Foo
+//
+// CHECK-NO-ARG-NOT: -fcomment-block-commands=
diff --git a/test/Driver/flags.c b/test/Driver/flags.c
index 698a54e..2786231 100644
--- a/test/Driver/flags.c
+++ b/test/Driver/flags.c
@@ -7,5 +7,14 @@
// RUN: %clang -target i386-apple-darwin9 -### -S -mno-soft-float %s -msoft-float 2> %t.log
// RUN: grep '"-no-implicit-float"' %t.log
+// RUN: %clang -target i386-apple-darwin9 -### -S -mno-implicit-float %s 2> %t.log
+// RUN: grep '"-no-implicit-float"' %t.log
+
+// RUN: %clang -target i386-apple-darwin9 -### -S -mkernel %s 2> %t.log
+// RUN: grep '"-no-implicit-float"' %t.log
+
+// RUN: %clang -target i386-apple-darwin9 -### -S -mkernel -mno-soft-float %s 2> %t.log
+// RUN: grep '"-no-implicit-float"' %t.log | count 0
+
// RUN: %clang -target armv7-apple-darwin10 -### -S -mno-implicit-float %s 2> %t.log
-// RUN: grep '"-no-implicit-float"' %t.log | count 1
+// RUN: grep '"-no-implicit-float"' %t.log
diff --git a/test/Driver/frame-pointer-elim.c b/test/Driver/frame-pointer-elim.c
new file mode 100644
index 0000000..286cd6e
--- /dev/null
+++ b/test/Driver/frame-pointer-elim.c
@@ -0,0 +1,30 @@
+// For these next two tests when optimized we should omit the leaf frame
+// pointer, for unoptimized we should have a leaf frame pointer.
+// RUN: %clang -### -target i386-pc-linux-gnu -S -O1 %s 2>&1 | \
+// RUN: FileCheck --check-prefix=LINUX-OPT %s
+// LINUX-OPT: "-momit-leaf-frame-pointer"
+
+// RUN: %clang -### -target i386-pc-linux-gnu -S %s 2>&1 | \
+// RUN: FileCheck --check-prefix=LINUX %s
+// LINUX-NOT: "-momit-leaf-frame-pointer"
+
+// Darwin disables omitting the leaf frame pointer even under optimization
+// unless the command lines are given.
+// RUN: %clang -### -target i386-apple-darwin -S %s 2>&1 | \
+// RUN: FileCheck --check-prefix=DARWIN %s
+// DARWIN: "-mdisable-fp-elim"
+
+// RUN: %clang -### -target i386-apple-darwin -S -O1 %s 2>&1 | \
+// RUN: FileCheck --check-prefix=DARWIN-OPT %s
+// DARWIN-OPT-NOT: "-momit-leaf-frame-pointer"
+
+// RUN: %clang -### -target i386-darwin -S -fomit-frame-pointer %s 2>&1 | \
+// RUN: FileCheck --check-prefix=OMIT_ALL %s
+// OMIT_ALL-NOT: "-mdisable-fp-elim"
+
+// RUN: %clang -### -target i386-darwin -S -momit-leaf-frame-pointer %s 2>&1 | \
+// RUN: FileCheck --check-prefix=OMIT_LEAF %s
+// OMIT_LEAF: "-momit-leaf-frame-pointer"
+
+void f0() {}
+void f1() { f0(); }
diff --git a/test/Driver/freebsd-mips-as.c b/test/Driver/freebsd-mips-as.c
index 54ff187..508deba 100644
--- a/test/Driver/freebsd-mips-as.c
+++ b/test/Driver/freebsd-mips-as.c
@@ -32,8 +32,8 @@
//
// 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: | FileCheck -check-prefix=MIPS32-DEF-EL-AS %s
+// MIPS32-DEF-EL-AS: as{{(.exe)?}}" "-march" "mips32" "-mabi" "32" "-EL"
//
// RUN: %clang -target mips64-unknown-freebsd -### \
// RUN: -no-integrated-as -c %s 2>&1 \
@@ -42,8 +42,8 @@
//
// 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: | FileCheck -check-prefix=MIPS64-DEF-EL-AS %s
+// MIPS64-DEF-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 \
@@ -55,6 +55,16 @@
// RUN: | FileCheck -check-prefix=MIPS-N32 %s
// MIPS-N32: as{{(.exe)?}}" "-march" "mips64" "-mabi" "n32" "-EB"
//
+// RUN: %clang -target mipsel-unknown-freebsd -mabi=32 -### \
+// 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 mips64el-unknown-freebsd -mabi=64 -### \
+// 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-linux-freebsd -march=mips32r2 -### \
// RUN: -no-integrated-as -c %s 2>&1 \
// RUN: | FileCheck -check-prefix=MIPS-32R2 %s
diff --git a/test/Driver/freebsd.c b/test/Driver/freebsd.c
index db53d4d..cc72443 100644
--- a/test/Driver/freebsd.c
+++ b/test/Driver/freebsd.c
@@ -96,3 +96,14 @@
// RUN: | FileCheck --check-prefix=CHECK-NORMAL %s
// CHECK-NORMAL: crt1.o
// CHECK-NORMAL: crtbegin.o
+
+// RUN: %clang %s -### -o %t.o -target arm-unknown-freebsd10.0 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-ARM %s
+// CHECK-ARM: clang{{.*}}" "-cc1"{{.*}}" "-fsjlj-exceptions"
+// CHECK-ARM: as{{.*}}" "-mfpu=softvfp"{{.*}}"-matpcs"
+
+// RUN: %clang %s -### -o %t.o -target arm-gnueabi-freebsd10.0 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-ARM-EABI %s
+// CHECK-ARM-EABI-NOT: clang{{.*}}" "-cc1"{{.*}}" "-fsjlj-exceptions"
+// CHECK-ARM-EABI: as{{.*}}" "-mfpu=softvfp" "-meabi=5"
+// CHECK-ARM-EABI-NOT: as{{.*}}" "-matpcs"
diff --git a/test/Driver/fsanitize-blacklist.c b/test/Driver/fsanitize-blacklist.c
new file mode 100644
index 0000000..5327bc1
--- /dev/null
+++ b/test/Driver/fsanitize-blacklist.c
@@ -0,0 +1,18 @@
+// General blacklist usage.
+// RUN: %clang -fsanitize=address -fsanitize-blacklist=%s %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-BLACKLIST
+// CHECK-BLACKLIST: -fsanitize-blacklist
+
+// Ignore -fsanitize-blacklist flag if there is no -fsanitize flag.
+// RUN: %clang -fsanitize-blacklist=%s %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-SANITIZE
+// CHECK-NO-SANITIZE-NOT: -fsanitize-blacklist
+
+// Flag -fno-sanitize-blacklist wins if it is specified later.
+// RUN: %clang -fsanitize=address -fsanitize-blacklist=%s -fno-sanitize-blacklist %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-BLACKLIST
+// CHECK-NO-BLACKLIST-NOT: -fsanitize-blacklist
+
+// Driver barks on unexisting blacklist files.
+// RUN: %clang -fno-sanitize-blacklist -fsanitize-blacklist=unexisting.txt %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-SUCH-FILE
+// CHECK-NO-SUCH-FILE: error: no such file or directory: 'unexisting.txt'
+
+// PR12920
+// REQUIRES: clang-driver
diff --git a/test/Driver/fsanitize.c b/test/Driver/fsanitize.c
index 9f7cd46..1d606b4 100644
--- a/test/Driver/fsanitize.c
+++ b/test/Driver/fsanitize.c
@@ -1,23 +1,118 @@
-// 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 -fcatch-undefined-behavior %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined-trap -fsanitize-undefined-trap-on-error %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP
+// RUN: %clang -target x86_64-linux-gnu -fsanitize-undefined-trap-on-error -fsanitize=undefined-trap %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP
+// CHECK-UNDEFINED-TRAP: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|shift|unreachable|return|vla-bound|alignment|null|object-size|float-cast-overflow|bounds|enum|bool),?){14}"}}
+// CHECK-UNDEFINED-TRAP: "-fsanitize-undefined-trap-on-error"
+
// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED
-// CHECK-UNDEFINED: "-fsanitize={{((signed-integer-overflow|divide-by-zero|shift|unreachable|return|vla-bound|alignment|null|vptr|object-size|float-cast-overflow),?){11}"}}
+// CHECK-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|shift|unreachable|return|vla-bound|alignment|null|vptr|object-size|float-cast-overflow|bounds|enum|bool),?){15}"}}
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=integer %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-INTEGER
+// CHECK-INTEGER: "-fsanitize={{((signed-integer-overflow|unsigned-integer-overflow|integer-divide-by-zero|shift),?){4}"}}
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=thread,undefined -fno-thread-sanitizer -fno-sanitize=float-cast-overflow,vptr,bool,enum %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PARTIAL-UNDEFINED
+// CHECK-PARTIAL-UNDEFINED: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|float-divide-by-zero|shift|unreachable|return|vla-bound|alignment|null|object-size|bounds),?){11}"}}
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address-full %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-FULL
+// CHECK-ASAN-FULL: "-fsanitize={{((address|init-order|use-after-return|use-after-scope),?){4}"}}
+
+// RUN: %clang -target x86_64-linux-gnu -fno-sanitize=init-order -fsanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-IMPLIED-INIT-ORDER
+// CHECK-ASAN-IMPLIED-INIT-ORDER: "-fsanitize={{((address|init-order),?){2}"}}
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fno-sanitize=init-order %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-NO-IMPLIED-INIT-ORDER
+// CHECK-ASAN-NO-IMPLIED-INIT-ORDER-NOT: init-order
+
+// RUN: %clang -target x86_64-linux-gnu -fcatch-undefined-behavior -fno-sanitize-undefined-trap-on-error %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-NO-TRAP-ERROR
+// CHECK-UNDEFINED-NO-TRAP-ERROR: '-fcatch-undefined-behavior' not allowed with '-fno-sanitize-undefined-trap-on-error'
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=vptr -fcatch-undefined-behavior %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-VPTR-UNDEF-ERROR
+// CHECK-VPTR-UNDEF-ERROR: '-fsanitize=vptr' not allowed with '-fcatch-undefined-behavior'
-// 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=undefined -fsanitize-undefined-trap-on-error %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP-ON-ERROR-UNDEF
+// CHECK-UNDEFINED-TRAP-ON-ERROR-UNDEF: '-fsanitize=undefined' not allowed with '-fsanitize-undefined-trap-on-error'
-// 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
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=vptr -fsanitize-undefined-trap-on-error %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-TRAP-ON-ERROR-VPTR
+// CHECK-UNDEFINED-TRAP-ON-ERROR-VPTR: '-fsanitize=vptr' not allowed with '-fsanitize-undefined-trap-on-error'
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=vptr -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-VPTR-NO-RTTI
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=undefined -fno-rtti %s -### 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
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address,thread -fno-rtti %s -### 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
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address,memory -pie -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANA-SANM
+// CHECK-SANA-SANM: '-fsanitize=address' not allowed with '-fsanitize=memory'
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=thread,memory -pie -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANT-SANM
+// CHECK-SANT-SANM: '-fsanitize=thread' not allowed with '-fsanitize=memory'
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory,thread -pie -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SANM-SANT
+// CHECK-SANM-SANT: '-fsanitize=thread' not allowed with '-fsanitize=memory'
+
+// RUN: %clang -target x86_64-linux-gnu -faddress-sanitizer -fthread-sanitizer -fno-rtti %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-TSAN
// CHECK-ASAN-TSAN: '-faddress-sanitizer' not allowed with '-fthread-sanitizer'
-// 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
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=init-order %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ONLY-EXTRA-ASAN
+// CHECK-ONLY-EXTRA-ASAN: '-fsanitize=init-order' is ignored in absence of '-fsanitize=address'
+
+// RUN: %clang -target x86_64-linux-gnu -Wno-unused-sanitize-argument -fsanitize=init-order %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-WNO-UNUSED-SANITIZE-ARGUMENT
+// CHECK-WNO-UNUSED-SANITIZE-ARGUMENT-NOT: '-fsanitize=init-order' is ignored in absence of '-fsanitize=address'
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address,init-order -fno-sanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NOWARN-ONLY-EXTRA-ASAN
+// CHECK-NOWARN-ONLY-EXTRA-ASAN-NOT: is ignored in absence of '-fsanitize=address'
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize-memory-track-origins -pie %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ONLY-TRACK-ORIGINS
+// CHECK-ONLY-TRACK-ORIGINS: warning: argument unused during compilation: '-fsanitize-memory-track-origins'
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-EXTRA-TRACK-ORIGINS
+// CHECK-NO-EXTRA-TRACK-ORIGINS-NOT: "-fsanitize-memory-track-origins"
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize-address-zero-base-shadow -pie %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ONLY-ASAN-ZERO-BASE-SHADOW
+// CHECK-ONLY-ASAN-ZERO-BASE-SHADOW: warning: argument unused during compilation: '-fsanitize-address-zero-base-shadow'
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize=alignment -fsanitize=vptr -fno-sanitize=vptr %s -### 2>&1
+// OK
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -pie %s -### 2>&1
+// OK
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory -fsanitize-memory-track-origins -pie %s -### 2>&1
+// OK
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=vptr -fno-sanitize=vptr -fsanitize=undefined,address %s -### 2>&1
+// OK
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-address-zero-base-shadow -pie %s -### 2>&1
+// OK
+
+// RUN: %clang -target x86_64-linux-gnu -fcatch-undefined-behavior -fthread-sanitizer -fno-thread-sanitizer -faddress-sanitizer -fno-address-sanitizer -fbounds-checking -### %s 2>&1 | FileCheck %s --check-prefix=CHECK-DEPRECATED
+// CHECK-DEPRECATED: argument '-fcatch-undefined-behavior' is deprecated, use '-fsanitize=undefined-trap -fsanitize-undefined-trap-on-error' instead
// CHECK-DEPRECATED: argument '-fthread-sanitizer' is deprecated, use '-fsanitize=thread' instead
// CHECK-DEPRECATED: argument '-fno-thread-sanitizer' is deprecated, use '-fno-sanitize=thread' instead
// CHECK-DEPRECATED: argument '-faddress-sanitizer' is deprecated, use '-fsanitize=address' instead
// CHECK-DEPRECATED: argument '-fno-address-sanitizer' is deprecated, use '-fno-sanitize=address' instead
+// CHECK-DEPRECATED: argument '-fbounds-checking' is deprecated, use '-fsanitize=bounds' instead
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=thread %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-TSAN-NO-PIE
+// CHECK-TSAN-NO-PIE: invalid argument '-fsanitize=thread' only allowed with '-pie'
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=memory %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-MSAN-NO-PIE
+// CHECK-MSAN-NO-PIE: invalid argument '-fsanitize=memory' only allowed with '-pie'
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-address-zero-base-shadow %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-ZERO-BASE-SHADOW-NO-PIE
+// CHECK-ASAN-ZERO-BASE-SHADOW-NO-PIE: invalid argument '-fsanitize-address-zero-base-shadow' only allowed with '-pie'
+
+// RUN: %clang -target x86_64-linux-gnu -fsanitize=address -fsanitize-address-zero-base-shadow -fno-sanitize-address-zero-base-shadow %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ASAN-ZERO-BASE-SHADOW-CANCEL
+// CHECK-ASAN-ZERO-BASE-SHADOW-CANCEL-NOT: '-fsanitize-address-zero-base-shadow' only allowed with '-pie'
+
+// RUN: %clang -target arm-linux-androideabi -fsanitize=address %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ANDROID-ASAN-NO-PIE
+// CHECK-ANDROID-ASAN-NO-PIE: AddressSanitizer on Android requires '-pie'
+
+// RUN: %clang -target x86_64-linux-gnu %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-RECOVER
+// RUN: %clang -target x86_64-linux-gnu %s -fsanitize-recover -### 2>&1 | FileCheck %s --check-prefix=CHECK-RECOVER
+// RUN: %clang -target x86_64-linux-gnu %s -fno-sanitize-recover -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-RECOVER
+// RUN: %clang -target x86_64-linux-gnu %s -fno-sanitize-recover -fsanitize-recover -### 2>&1 | FileCheck %s --check-prefix=CHECK-RECOVER
+// RUN: %clang -target x86_64-linux-gnu %s -fsanitize-recover -fno-sanitize-recover -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-RECOVER
+// CHECK-RECOVER-NOT: sanitize-recover
+// CHECK-NO-RECOVER: "-fno-sanitize-recover"
diff --git a/test/Driver/gold-lto.c b/test/Driver/gold-lto.c
index 05ac27a..c2e8bdf 100644
--- a/test/Driver/gold-lto.c
+++ b/test/Driver/gold-lto.c
@@ -1,6 +1,21 @@
// RUN: touch %t.o
-// RUN: %clang -target x86_64-pc-linux-gnu -### %t.o -O4 -Wl,-plugin-opt=foo 2> %t.log
-// RUN: FileCheck %s < %t.log
-
-// CHECK: "-plugin" "{{.*}}/LLVMgold.so"
-// CHECK: "-plugin-opt=foo"
+//
+// RUN: %clang -target x86_64-unknown-linux -### %t.o -flto 2>&1 \
+// RUN: -Wl,-plugin-opt=foo \
+// RUN: | FileCheck %s --check-prefix=CHECK-X86-64-BASIC
+// CHECK-X86-64-BASIC: "-plugin" "{{.*}}/LLVMgold.so"
+// CHECK-X86-64-BASIC: "-plugin-opt=foo"
+//
+// RUN: %clang -target x86_64-unknown-linux -### %t.o -flto 2>&1 \
+// RUN: -march=corei7 -Wl,-plugin-opt=foo \
+// RUN: | FileCheck %s --check-prefix=CHECK-X86-64-COREI7
+// CHECK-X86-64-COREI7: "-plugin" "{{.*}}/LLVMgold.so"
+// CHECK-X86-64-COREI7: "-plugin-opt=mcpu=corei7"
+// CHECK-X86-64-COREI7: "-plugin-opt=foo"
+//
+// RUN: %clang -target arm-unknown-linux -### %t.o -flto 2>&1 \
+// RUN: -march=armv7a -Wl,-plugin-opt=foo \
+// RUN: | FileCheck %s --check-prefix=CHECK-ARM-V7A
+// CHECK-ARM-V7A: "-plugin" "{{.*}}/LLVMgold.so"
+// CHECK-ARM-V7A: "-plugin-opt=mcpu=cortex-a8"
+// CHECK-ARM-V7A: "-plugin-opt=foo"
diff --git a/test/Driver/hexagon-toolchain-elf.c b/test/Driver/hexagon-toolchain-elf.c
new file mode 100644
index 0000000..b3ff7b6
--- /dev/null
+++ b/test/Driver/hexagon-toolchain-elf.c
@@ -0,0 +1,564 @@
+// REQUIRES: hexagon-registered-target
+
+// -----------------------------------------------------------------------------
+// Test standard include paths
+// -----------------------------------------------------------------------------
+
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK001 %s
+// CHECK001: "-cc1" {{.*}} "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
+// CHECK001: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
+// CHECK001: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
+// CHECK001-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"
+
+// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK002 %s
+// CHECK002: "-cc1" {{.*}} "-internal-isystem" "[[INSTALL_DIR:.*]]/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include/c++/4.4.0"
+// CHECK002: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
+// CHECK002: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
+// CHECK002: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
+// CHECK002-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"
+
+// -----------------------------------------------------------------------------
+// Test -nostdinc, -nostdlibinc, -nostdinc++
+// -----------------------------------------------------------------------------
+
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -nostdinc \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK003 %s
+// CHECK003: "-cc1"
+// CHECK003-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
+// CHECK003-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
+// CHECK003-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
+// CHECK003-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"
+
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -nostdlibinc \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK004 %s
+// CHECK004: "-cc1"
+// CHECK004-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
+// CHECK004-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
+// CHECK004-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
+// CHECK004-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"
+
+// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -nostdlibinc \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK005 %s
+// CHECK005: "-cc1"
+// CHECK005-NOT: "-internal-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include/c++/4.4.0"
+// CHECK005-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
+// CHECK005-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
+// CHECK005-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
+// CHECK005-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"
+
+// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -nostdinc++ \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK006 %s
+// CHECK006: "-cc1"
+// CHECK006-NOT: "-internal-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include/c++/4.4.0"
+// CHECK006-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"
+
+// -----------------------------------------------------------------------------
+// Test -march=<archname> -mcpu=<archname> -mv<number>
+// -----------------------------------------------------------------------------
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -march=hexagonv3 \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK007 %s
+// CHECK007: "-cc1" {{.*}} "-target-cpu" "hexagonv3"
+// CHECK007-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"{{.*}} "-march=v3"
+// CHECK007-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-ld"{{.*}} "-mv3"
+
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -mcpu=hexagonv5 \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK008 %s
+// CHECK008: "-cc1" {{.*}} "-target-cpu" "hexagonv5"
+// CHECK008-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"{{.*}} "-march=v5"
+// CHECK008-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-ld"{{.*}} "-mv5"
+
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -mv2 \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK009 %s
+// CHECK009: "-cc1" {{.*}} "-target-cpu" "hexagonv2"
+// CHECK009-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"{{.*}} "-march=v2"
+// CHECK009-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-ld"{{.*}} "-mv2"
+
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK010 %s
+// CHECK010: "-cc1" {{.*}} "-target-cpu" "hexagonv4"
+// CHECK010-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"{{.*}} "-march=v4"
+// CHECK010-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-ld"{{.*}} "-mv4"
+
+// RUN: %clang -march=hexagonv2 -target hexagon-unknown-elf \
+// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V2 %s
+// RUN: %clang -mcpu=hexagonv2 -target hexagon-unknown-elf \
+// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V2 %s
+// RUN: %clang -mv2 -target hexagon-unknown-elf \
+// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V2 %s
+// CHECK-UNKNOWN-V2: error: unknown target CPU 'hexagonv2'
+
+// RUN: %clang -march=hexagonv3 -target hexagon-unknown-elf \
+// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V3 %s
+// RUN: %clang -mcpu=hexagonv3 -target hexagon-unknown-elf \
+// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V3 %s
+// RUN: %clang -mv3 -target hexagon-unknown-elf \
+// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V3 %s
+// CHECK-UNKNOWN-V3: error: unknown target CPU 'hexagonv3'
+
+// -----------------------------------------------------------------------------
+// Test Linker related args
+// -----------------------------------------------------------------------------
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// Defaults for C
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK011 %s
+// CHECK011: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK011-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
+// CHECK011-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK011-NOT: "-static"
+// CHECK011-NOT: "-shared"
+// CHECK011: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
+// CHECK011: "{{.*}}/hexagon/lib/v4/crt0.o"
+// CHECK011: "{{.*}}/hexagon/lib/v4/init.o"
+// CHECK011: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
+// CHECK011: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
+// CHECK011: "-L{{.*}}/lib/gcc"
+// CHECK011: "-L{{.*}}/hexagon/lib/v4"
+// CHECK011: "-L{{.*}}/hexagon/lib"
+// CHECK011: "{{[^"]+}}.o"
+// CHECK011: "--start-group" "-lstandalone" "-lc" "-lgcc" "--end-group"
+// CHECK011: "{{.*}}/hexagon/lib/v4/fini.o"
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// Defaults for C++
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK012 %s
+// CHECK012: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK012-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
+// CHECK012-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK012-NOT: "-static"
+// CHECK012-NOT: "-shared"
+// CHECK012: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
+// CHECK012: "{{.*}}/hexagon/lib/v4/crt0.o"
+// CHECK012: "{{.*}}/hexagon/lib/v4/init.o"
+// CHECK012: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
+// CHECK012: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
+// CHECK012: "-L{{.*}}/lib/gcc"
+// CHECK012: "-L{{.*}}/hexagon/lib/v4"
+// CHECK012: "-L{{.*}}/hexagon/lib"
+// CHECK012: "{{[^"]+}}.o"
+// CHECK012: "-lstdc++" "-lm"
+// CHECK012: "--start-group" "-lstandalone" "-lc" "-lgcc" "--end-group"
+// CHECK012: "{{.*}}/hexagon/lib/v4/fini.o"
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// Additional Libraries (-L)
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -Lone -L two -L three \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK013 %s
+// CHECK013: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK013-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
+// CHECK013-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK013: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
+// CHECK013: "{{.*}}/hexagon/lib/v4/crt0.o"
+// CHECK013: "{{.*}}/hexagon/lib/v4/init.o"
+// CHECK013: "-Lone" "-Ltwo" "-Lthree"
+// CHECK013: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
+// CHECK013: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
+// CHECK013: "-L{{.*}}/lib/gcc"
+// CHECK013: "-L{{.*}}/hexagon/lib/v4"
+// CHECK013: "-L{{.*}}/hexagon/lib"
+// CHECK013: "{{[^"]+}}.o"
+// CHECK013: "--start-group" "-lstandalone" "-lc" "-lgcc" "--end-group"
+// CHECK013: "{{.*}}/hexagon/lib/v4/fini.o"
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// -static, -shared
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -static \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK014 %s
+// CHECK014: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK014-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
+// CHECK014-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK014: "-static"
+// CHECK014: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
+// CHECK014: "{{.*}}/hexagon/lib/v4/crt0.o"
+// CHECK014: "{{.*}}/hexagon/lib/v4/init.o"
+// CHECK014: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
+// CHECK014: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
+// CHECK014: "-L{{.*}}/lib/gcc"
+// CHECK014: "-L{{.*}}/hexagon/lib/v4"
+// CHECK014: "-L{{.*}}/hexagon/lib"
+// CHECK014: "{{[^"]+}}.o"
+// CHECK014: "--start-group" "-lstandalone" "-lc" "-lgcc" "--end-group"
+// CHECK014: "{{.*}}/hexagon/lib/v4/fini.o"
+
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -shared \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK015 %s
+// CHECK015: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK015-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
+// CHECK015-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK015: "-shared" "-call_shared"
+// CHECK015-NOT: crt0_standalone.o
+// CHECK015-NOT: crt0.o
+// CHECK015: "{{.*}}/hexagon/lib/v4/G0/initS.o"
+// CHECK015: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4/G0"
+// CHECK015: "-L{{.*}}/lib/gcc/hexagon/4.4.0/G0"
+// CHECK015: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
+// CHECK015: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
+// CHECK015: "-L{{.*}}/lib/gcc"
+// CHECK015: "-L{{.*}}/hexagon/lib/v4/G0"
+// CHECK015: "-L{{.*}}/hexagon/lib/G0"
+// CHECK015: "-L{{.*}}/hexagon/lib/v4"
+// CHECK015: "-L{{.*}}/hexagon/lib"
+// CHECK015: "{{[^"]+}}.o"
+// CHECK015: "--start-group"
+// CHECK015-NOT: "-lstandalone"
+// CHECK015-NOT: "-lc"
+// CHECK015: "-lgcc"
+// CHECK015: "--end-group"
+// CHECK015: "{{.*}}/hexagon/lib/v4/G0/finiS.o"
+
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -shared \
+// RUN: -static \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK016 %s
+// CHECK016: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK016-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
+// CHECK016-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK016: "-shared" "-call_shared" "-static"
+// CHECK016-NOT: crt0_standalone.o
+// CHECK016-NOT: crt0.o
+// CHECK016: "{{.*}}/hexagon/lib/v4/G0/init.o"
+// CHECK016: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4/G0"
+// CHECK016: "-L{{.*}}/lib/gcc/hexagon/4.4.0/G0"
+// CHECK016: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
+// CHECK016: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
+// CHECK016: "-L{{.*}}/lib/gcc"
+// CHECK016: "-L{{.*}}/hexagon/lib/v4/G0"
+// CHECK016: "-L{{.*}}/hexagon/lib/G0"
+// CHECK016: "-L{{.*}}/hexagon/lib/v4"
+// CHECK016: "-L{{.*}}/hexagon/lib"
+// CHECK016: "{{[^"]+}}.o"
+// CHECK016: "--start-group"
+// CHECK016-NOT: "-lstandalone"
+// CHECK016-NOT: "-lc"
+// CHECK016: "-lgcc"
+// CHECK016: "--end-group"
+// CHECK016: "{{.*}}/hexagon/lib/v4/G0/fini.o"
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// -nostdlib, -nostartfiles, -nodefaultlibs
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -nostdlib \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK017 %s
+// CHECK017: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK017-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
+// CHECK017-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK017-NOT: crt0_standalone.o
+// CHECK017-NOT: crt0.o
+// CHECK017-NOT: init.o
+// CHECK017: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
+// CHECK017: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
+// CHECK017: "-L{{.*}}/lib/gcc"
+// CHECK017: "-L{{.*}}/hexagon/lib/v4"
+// CHECK017: "-L{{.*}}/hexagon/lib"
+// CHECK017: "{{[^"]+}}.o"
+// CHECK017-NOT: "-lstdc++"
+// CHECK017-NOT: "-lm"
+// CHECK017-NOT: "--start-group"
+// CHECK017-NOT: "-lstandalone"
+// CHECK017-NOT: "-lc"
+// CHECK017-NOT: "-lgcc"
+// CHECK017-NOT: "--end-group"
+// CHECK017-NOT: fini.o
+
+// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -nostartfiles \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK018 %s
+// CHECK018: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK018-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
+// CHECK018-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK018-NOT: crt0_standalone.o
+// CHECK018-NOT: crt0.o
+// CHECK018-NOT: init.o
+// CHECK018: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
+// CHECK018: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
+// CHECK018: "-L{{.*}}/lib/gcc"
+// CHECK018: "-L{{.*}}/hexagon/lib/v4"
+// CHECK018: "-L{{.*}}/hexagon/lib"
+// CHECK018: "{{[^"]+}}.o"
+// CHECK018: "-lstdc++"
+// CHECK018: "-lm"
+// CHECK018: "--start-group"
+// CHECK018: "-lstandalone"
+// CHECK018: "-lc"
+// CHECK018: "-lgcc"
+// CHECK018: "--end-group"
+// CHECK018-NOT: fini.o
+
+// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -nodefaultlibs \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK019 %s
+// CHECK019: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK019-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
+// CHECK019-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK019: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
+// CHECK019: "{{.*}}/hexagon/lib/v4/crt0.o"
+// CHECK019: "{{.*}}/hexagon/lib/v4/init.o"
+// CHECK019: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
+// CHECK019: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
+// CHECK019: "-L{{.*}}/lib/gcc"
+// CHECK019: "-L{{.*}}/hexagon/lib/v4"
+// CHECK019: "-L{{.*}}/hexagon/lib"
+// CHECK019: "{{[^"]+}}.o"
+// CHECK019-NOT: "-lstdc++"
+// CHECK019-NOT: "-lm"
+// CHECK019-NOT: "--start-group"
+// CHECK019-NOT: "-lstandalone"
+// CHECK019-NOT: "-lc"
+// CHECK019-NOT: "-lgcc"
+// CHECK019-NOT: "--end-group"
+// CHECK019: "{{.*}}/hexagon/lib/v4/fini.o"
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// -moslib
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -moslib=first -moslib=second \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK020 %s
+// CHECK020: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK020-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
+// CHECK020-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK020-NOT: "-static"
+// CHECK020-NOT: "-shared"
+// CHECK020-NOT: crt0_standalone.o
+// CHECK020: "{{.*}}/hexagon/lib/v4/crt0.o"
+// CHECK020: "{{.*}}/hexagon/lib/v4/init.o"
+// CHECK020: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
+// CHECK020: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
+// CHECK020: "-L{{.*}}/lib/gcc"
+// CHECK020: "-L{{.*}}/hexagon/lib/v4"
+// CHECK020: "-L{{.*}}/hexagon/lib"
+// CHECK020: "{{[^"]+}}.o"
+// CHECK020: "--start-group"
+// CHECK020: "-lfirst" "-lsecond"
+// CHECK020-NOT: "-lstandalone"
+// CHECK020: "-lc" "-lgcc" "--end-group"
+// CHECK020: "{{.*}}/hexagon/lib/v4/fini.o"
+
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -moslib=first -moslib=second -moslib=standalone\
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK021 %s
+// CHECK021: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK021-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
+// CHECK021-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK021-NOT: "-static"
+// CHECK021-NOT: "-shared"
+// CHECK021: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
+// CHECK021: "{{.*}}/hexagon/lib/v4/crt0.o"
+// CHECK021: "{{.*}}/hexagon/lib/v4/init.o"
+// CHECK021: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
+// CHECK021: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
+// CHECK021: "-L{{.*}}/lib/gcc"
+// CHECK021: "-L{{.*}}/hexagon/lib/v4"
+// CHECK021: "-L{{.*}}/hexagon/lib"
+// CHECK021: "{{[^"]+}}.o"
+// CHECK021: "--start-group"
+// CHECK021: "-lfirst" "-lsecond"
+// CHECK021: "-lstandalone"
+// CHECK021: "-lc" "-lgcc" "--end-group"
+// CHECK021: "{{.*}}/hexagon/lib/v4/fini.o"
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// Other args to pass to linker
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -s \
+// RUN: -Tbss 0xdead -Tdata 0xbeef -Ttext 0xcafe \
+// RUN: -t \
+// RUN: -e start_here \
+// RUN: -uFoo -undefined Bar \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK022 %s
+// CHECK022: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK022-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
+// CHECK022-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK022: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
+// CHECK022: "{{.*}}/hexagon/lib/v4/crt0.o"
+// CHECK022: "{{.*}}/hexagon/lib/v4/init.o"
+// CHECK022: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
+// CHECK022: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
+// CHECK022: "-L{{.*}}/lib/gcc"
+// CHECK022: "-L{{.*}}/hexagon/lib/v4"
+// CHECK022: "-L{{.*}}/hexagon/lib"
+// CHECK022: "-Tbss" "0xdead" "-Tdata" "0xbeef" "-Ttext" "0xcafe"
+// CHECK022: "-s"
+// CHECK022: "-t"
+// CHECK022: "-u" "Foo" "-undefined" "Bar"
+// CHECK022: "{{[^"]+}}.o"
+// CHECK022: "-lstdc++" "-lm"
+// CHECK022: "--start-group" "-lstandalone" "-lc" "-lgcc" "--end-group"
+// CHECK022: "{{.*}}/hexagon/lib/v4/fini.o"
+
+// -----------------------------------------------------------------------------
+// pic, small data threshold
+// -----------------------------------------------------------------------------
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK023 %s
+// CHECK023: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK023: "-mrelocation-model" "static"
+// CHECK023-NEXT: "{{.*}}/bin/hexagon-as"
+// CHECK023-NOT: "-G{{[0-9]+}}"
+// CHECK023-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK023-NOT: "-G{{[0-9]+}}"
+
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -fpic \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK024 %s
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -fPIC \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK024 %s
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -fPIC \
+// RUN: -msmall_data_threshold=8 \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK024 %s
+// CHECK024: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK024-NOT: "-mrelocation-model" "static"
+// CHECK024: "-pic-level" "{{[12]}}"
+// CHECK024: "-mllvm" "-hexagon-small-data-threshold=0"
+// CHECK024-NEXT: "{{.*}}/bin/hexagon-as"
+// CHECK024: "-G0"
+// CHECK024-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK024: "-G0"
+
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -G=8 \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK025 %s
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -G 8 \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK025 %s
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -msmall-data-threshold=8 \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK025 %s
+// CHECK025: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK025: "-mrelocation-model" "static"
+// CHECK025: "-mllvm" "-hexagon-small-data-threshold=8"
+// CHECK025-NEXT: "{{.*}}/bin/hexagon-as"
+// CHECK025: "-G8"
+// CHECK025-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK025: "-G8"
+
+// -----------------------------------------------------------------------------
+// pie
+// -----------------------------------------------------------------------------
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -pie \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK026 %s
+// CHECK026: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK026-NEXT: "{{.*}}/bin/hexagon-as"
+// CHECK026-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK026: "-pie"
+
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -pie -shared \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK027 %s
+// CHECK027: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK027-NEXT: "{{.*}}/bin/hexagon-as"
+// CHECK027-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK027-NOT: "-pie"
+
+// -----------------------------------------------------------------------------
+// Misc Defaults
+// -----------------------------------------------------------------------------
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK028 %s
+// CHECK028: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK028: "-mqdsp6-compat"
+// CHECK028: "-Wreturn-type"
+// CHECK028-NEXT: "{{.*}}/bin/hexagon-as"
+// CHECK028-NEXT: "{{.*}}/bin/hexagon-ld"
+
+// -----------------------------------------------------------------------------
+// Test Assembler related args
+// -----------------------------------------------------------------------------
+// RUN: %clang -### -target hexagon-unknown-elf \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -gdwarf-2 \
+// RUN: -Wa,--noexecstack,--trap \
+// RUN: -Xassembler --keep-locals \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK029 %s
+// CHECK029: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK029-NEXT: "{{.*}}/bin/hexagon-as"
+// CHECK029: "-gdwarf-2" "--noexecstack" "--trap" "--keep-locals"
+// CHECK029-NEXT: "{{.*}}/bin/hexagon-ld"
diff --git a/test/Driver/hexagon-toolchain.c b/test/Driver/hexagon-toolchain.c
new file mode 100644
index 0000000..bfa627c
--- /dev/null
+++ b/test/Driver/hexagon-toolchain.c
@@ -0,0 +1,564 @@
+// REQUIRES: hexagon-registered-target
+
+// -----------------------------------------------------------------------------
+// Test standard include paths
+// -----------------------------------------------------------------------------
+
+// RUN: %clang -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK001 %s
+// CHECK001: "-cc1" {{.*}} "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
+// CHECK001: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
+// CHECK001: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
+// CHECK001-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"
+
+// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK002 %s
+// CHECK002: "-cc1" {{.*}} "-internal-isystem" "[[INSTALL_DIR:.*]]/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include/c++/4.4.0"
+// CHECK002: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
+// CHECK002: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
+// CHECK002: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
+// CHECK002-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"
+
+// -----------------------------------------------------------------------------
+// Test -nostdinc, -nostdlibinc, -nostdinc++
+// -----------------------------------------------------------------------------
+
+// RUN: %clang -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -nostdinc \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK003 %s
+// CHECK003: "-cc1"
+// CHECK003-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
+// CHECK003-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
+// CHECK003-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
+// CHECK003-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"
+
+// RUN: %clang -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -nostdlibinc \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK004 %s
+// CHECK004: "-cc1"
+// CHECK004-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
+// CHECK004-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
+// CHECK004-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
+// CHECK004-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"
+
+// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -nostdlibinc \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK005 %s
+// CHECK005: "-cc1"
+// CHECK005-NOT: "-internal-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include/c++/4.4.0"
+// CHECK005-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include"
+// CHECK005-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/lib/gcc/hexagon/4.4.0/include-fixed"
+// CHECK005-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
+// CHECK005-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"
+
+// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -nostdinc++ \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK006 %s
+// CHECK006: "-cc1"
+// CHECK006-NOT: "-internal-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include/c++/4.4.0"
+// CHECK006-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"
+
+// -----------------------------------------------------------------------------
+// Test -march=<archname> -mcpu=<archname> -mv<number>
+// -----------------------------------------------------------------------------
+// RUN: %clang -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -march=hexagonv3 \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK007 %s
+// CHECK007: "-cc1" {{.*}} "-target-cpu" "hexagonv3"
+// CHECK007-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"{{.*}} "-march=v3"
+// CHECK007-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-ld"{{.*}} "-mv3"
+
+// RUN: %clang -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -mcpu=hexagonv5 \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK008 %s
+// CHECK008: "-cc1" {{.*}} "-target-cpu" "hexagonv5"
+// CHECK008-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"{{.*}} "-march=v5"
+// CHECK008-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-ld"{{.*}} "-mv5"
+
+// RUN: %clang -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -mv2 \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK009 %s
+// CHECK009: "-cc1" {{.*}} "-target-cpu" "hexagonv2"
+// CHECK009-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"{{.*}} "-march=v2"
+// CHECK009-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-ld"{{.*}} "-mv2"
+
+// RUN: %clang -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK010 %s
+// CHECK010: "-cc1" {{.*}} "-target-cpu" "hexagonv4"
+// CHECK010-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-as"{{.*}} "-march=v4"
+// CHECK010-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin/hexagon-ld"{{.*}} "-mv4"
+
+// RUN: %clang -march=hexagonv2 -target hexagon-unknown-linux \
+// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V2 %s
+// RUN: %clang -mcpu=hexagonv2 -target hexagon-unknown-linux \
+// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V2 %s
+// RUN: %clang -mv2 -target hexagon-unknown-linux \
+// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V2 %s
+// CHECK-UNKNOWN-V2: error: unknown target CPU 'hexagonv2'
+
+// RUN: %clang -march=hexagonv3 -target hexagon-unknown-linux \
+// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V3 %s
+// RUN: %clang -mcpu=hexagonv3 -target hexagon-unknown-linux \
+// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V3 %s
+// RUN: %clang -mv3 -target hexagon-unknown-linux \
+// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-UNKNOWN-V3 %s
+// CHECK-UNKNOWN-V3: error: unknown target CPU 'hexagonv3'
+
+// -----------------------------------------------------------------------------
+// Test Linker related args
+// -----------------------------------------------------------------------------
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// Defaults for C
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// RUN: %clang -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK011 %s
+// CHECK011: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK011-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
+// CHECK011-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK011-NOT: "-static"
+// CHECK011-NOT: "-shared"
+// CHECK011: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
+// CHECK011: "{{.*}}/hexagon/lib/v4/crt0.o"
+// CHECK011: "{{.*}}/hexagon/lib/v4/init.o"
+// CHECK011: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
+// CHECK011: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
+// CHECK011: "-L{{.*}}/lib/gcc"
+// CHECK011: "-L{{.*}}/hexagon/lib/v4"
+// CHECK011: "-L{{.*}}/hexagon/lib"
+// CHECK011: "{{[^"]+}}.o"
+// CHECK011: "--start-group" "-lstandalone" "-lc" "-lgcc" "--end-group"
+// CHECK011: "{{.*}}/hexagon/lib/v4/fini.o"
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// Defaults for C++
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK012 %s
+// CHECK012: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK012-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
+// CHECK012-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK012-NOT: "-static"
+// CHECK012-NOT: "-shared"
+// CHECK012: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
+// CHECK012: "{{.*}}/hexagon/lib/v4/crt0.o"
+// CHECK012: "{{.*}}/hexagon/lib/v4/init.o"
+// CHECK012: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
+// CHECK012: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
+// CHECK012: "-L{{.*}}/lib/gcc"
+// CHECK012: "-L{{.*}}/hexagon/lib/v4"
+// CHECK012: "-L{{.*}}/hexagon/lib"
+// CHECK012: "{{[^"]+}}.o"
+// CHECK012: "-lstdc++" "-lm"
+// CHECK012: "--start-group" "-lstandalone" "-lc" "-lgcc" "--end-group"
+// CHECK012: "{{.*}}/hexagon/lib/v4/fini.o"
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// Additional Libraries (-L)
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// RUN: %clang -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -Lone -L two -L three \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK013 %s
+// CHECK013: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK013-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
+// CHECK013-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK013: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
+// CHECK013: "{{.*}}/hexagon/lib/v4/crt0.o"
+// CHECK013: "{{.*}}/hexagon/lib/v4/init.o"
+// CHECK013: "-Lone" "-Ltwo" "-Lthree"
+// CHECK013: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
+// CHECK013: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
+// CHECK013: "-L{{.*}}/lib/gcc"
+// CHECK013: "-L{{.*}}/hexagon/lib/v4"
+// CHECK013: "-L{{.*}}/hexagon/lib"
+// CHECK013: "{{[^"]+}}.o"
+// CHECK013: "--start-group" "-lstandalone" "-lc" "-lgcc" "--end-group"
+// CHECK013: "{{.*}}/hexagon/lib/v4/fini.o"
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// -static, -shared
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// RUN: %clang -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -static \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK014 %s
+// CHECK014: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK014-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
+// CHECK014-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK014: "-static"
+// CHECK014: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
+// CHECK014: "{{.*}}/hexagon/lib/v4/crt0.o"
+// CHECK014: "{{.*}}/hexagon/lib/v4/init.o"
+// CHECK014: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
+// CHECK014: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
+// CHECK014: "-L{{.*}}/lib/gcc"
+// CHECK014: "-L{{.*}}/hexagon/lib/v4"
+// CHECK014: "-L{{.*}}/hexagon/lib"
+// CHECK014: "{{[^"]+}}.o"
+// CHECK014: "--start-group" "-lstandalone" "-lc" "-lgcc" "--end-group"
+// CHECK014: "{{.*}}/hexagon/lib/v4/fini.o"
+
+// RUN: %clang -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -shared \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK015 %s
+// CHECK015: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK015-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
+// CHECK015-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK015: "-shared" "-call_shared"
+// CHECK015-NOT: crt0_standalone.o
+// CHECK015-NOT: crt0.o
+// CHECK015: "{{.*}}/hexagon/lib/v4/G0/initS.o"
+// CHECK015: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4/G0"
+// CHECK015: "-L{{.*}}/lib/gcc/hexagon/4.4.0/G0"
+// CHECK015: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
+// CHECK015: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
+// CHECK015: "-L{{.*}}/lib/gcc"
+// CHECK015: "-L{{.*}}/hexagon/lib/v4/G0"
+// CHECK015: "-L{{.*}}/hexagon/lib/G0"
+// CHECK015: "-L{{.*}}/hexagon/lib/v4"
+// CHECK015: "-L{{.*}}/hexagon/lib"
+// CHECK015: "{{[^"]+}}.o"
+// CHECK015: "--start-group"
+// CHECK015-NOT: "-lstandalone"
+// CHECK015-NOT: "-lc"
+// CHECK015: "-lgcc"
+// CHECK015: "--end-group"
+// CHECK015: "{{.*}}/hexagon/lib/v4/G0/finiS.o"
+
+// RUN: %clang -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -shared \
+// RUN: -static \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK016 %s
+// CHECK016: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK016-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
+// CHECK016-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK016: "-shared" "-call_shared" "-static"
+// CHECK016-NOT: crt0_standalone.o
+// CHECK016-NOT: crt0.o
+// CHECK016: "{{.*}}/hexagon/lib/v4/G0/init.o"
+// CHECK016: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4/G0"
+// CHECK016: "-L{{.*}}/lib/gcc/hexagon/4.4.0/G0"
+// CHECK016: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
+// CHECK016: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
+// CHECK016: "-L{{.*}}/lib/gcc"
+// CHECK016: "-L{{.*}}/hexagon/lib/v4/G0"
+// CHECK016: "-L{{.*}}/hexagon/lib/G0"
+// CHECK016: "-L{{.*}}/hexagon/lib/v4"
+// CHECK016: "-L{{.*}}/hexagon/lib"
+// CHECK016: "{{[^"]+}}.o"
+// CHECK016: "--start-group"
+// CHECK016-NOT: "-lstandalone"
+// CHECK016-NOT: "-lc"
+// CHECK016: "-lgcc"
+// CHECK016: "--end-group"
+// CHECK016: "{{.*}}/hexagon/lib/v4/G0/fini.o"
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// -nostdlib, -nostartfiles, -nodefaultlibs
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -nostdlib \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK017 %s
+// CHECK017: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK017-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
+// CHECK017-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK017-NOT: crt0_standalone.o
+// CHECK017-NOT: crt0.o
+// CHECK017-NOT: init.o
+// CHECK017: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
+// CHECK017: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
+// CHECK017: "-L{{.*}}/lib/gcc"
+// CHECK017: "-L{{.*}}/hexagon/lib/v4"
+// CHECK017: "-L{{.*}}/hexagon/lib"
+// CHECK017: "{{[^"]+}}.o"
+// CHECK017-NOT: "-lstdc++"
+// CHECK017-NOT: "-lm"
+// CHECK017-NOT: "--start-group"
+// CHECK017-NOT: "-lstandalone"
+// CHECK017-NOT: "-lc"
+// CHECK017-NOT: "-lgcc"
+// CHECK017-NOT: "--end-group"
+// CHECK017-NOT: fini.o
+
+// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -nostartfiles \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK018 %s
+// CHECK018: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK018-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
+// CHECK018-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK018-NOT: crt0_standalone.o
+// CHECK018-NOT: crt0.o
+// CHECK018-NOT: init.o
+// CHECK018: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
+// CHECK018: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
+// CHECK018: "-L{{.*}}/lib/gcc"
+// CHECK018: "-L{{.*}}/hexagon/lib/v4"
+// CHECK018: "-L{{.*}}/hexagon/lib"
+// CHECK018: "{{[^"]+}}.o"
+// CHECK018: "-lstdc++"
+// CHECK018: "-lm"
+// CHECK018: "--start-group"
+// CHECK018: "-lstandalone"
+// CHECK018: "-lc"
+// CHECK018: "-lgcc"
+// CHECK018: "--end-group"
+// CHECK018-NOT: fini.o
+
+// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -nodefaultlibs \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK019 %s
+// CHECK019: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK019-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
+// CHECK019-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK019: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
+// CHECK019: "{{.*}}/hexagon/lib/v4/crt0.o"
+// CHECK019: "{{.*}}/hexagon/lib/v4/init.o"
+// CHECK019: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
+// CHECK019: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
+// CHECK019: "-L{{.*}}/lib/gcc"
+// CHECK019: "-L{{.*}}/hexagon/lib/v4"
+// CHECK019: "-L{{.*}}/hexagon/lib"
+// CHECK019: "{{[^"]+}}.o"
+// CHECK019-NOT: "-lstdc++"
+// CHECK019-NOT: "-lm"
+// CHECK019-NOT: "--start-group"
+// CHECK019-NOT: "-lstandalone"
+// CHECK019-NOT: "-lc"
+// CHECK019-NOT: "-lgcc"
+// CHECK019-NOT: "--end-group"
+// CHECK019: "{{.*}}/hexagon/lib/v4/fini.o"
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// -moslib
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// RUN: %clang -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -moslib=first -moslib=second \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK020 %s
+// CHECK020: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK020-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
+// CHECK020-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK020-NOT: "-static"
+// CHECK020-NOT: "-shared"
+// CHECK020-NOT: crt0_standalone.o
+// CHECK020: "{{.*}}/hexagon/lib/v4/crt0.o"
+// CHECK020: "{{.*}}/hexagon/lib/v4/init.o"
+// CHECK020: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
+// CHECK020: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
+// CHECK020: "-L{{.*}}/lib/gcc"
+// CHECK020: "-L{{.*}}/hexagon/lib/v4"
+// CHECK020: "-L{{.*}}/hexagon/lib"
+// CHECK020: "{{[^"]+}}.o"
+// CHECK020: "--start-group"
+// CHECK020: "-lfirst" "-lsecond"
+// CHECK020-NOT: "-lstandalone"
+// CHECK020: "-lc" "-lgcc" "--end-group"
+// CHECK020: "{{.*}}/hexagon/lib/v4/fini.o"
+
+// RUN: %clang -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -moslib=first -moslib=second -moslib=standalone\
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK021 %s
+// CHECK021: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK021-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
+// CHECK021-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK021-NOT: "-static"
+// CHECK021-NOT: "-shared"
+// CHECK021: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
+// CHECK021: "{{.*}}/hexagon/lib/v4/crt0.o"
+// CHECK021: "{{.*}}/hexagon/lib/v4/init.o"
+// CHECK021: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
+// CHECK021: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
+// CHECK021: "-L{{.*}}/lib/gcc"
+// CHECK021: "-L{{.*}}/hexagon/lib/v4"
+// CHECK021: "-L{{.*}}/hexagon/lib"
+// CHECK021: "{{[^"]+}}.o"
+// CHECK021: "--start-group"
+// CHECK021: "-lfirst" "-lsecond"
+// CHECK021: "-lstandalone"
+// CHECK021: "-lc" "-lgcc" "--end-group"
+// CHECK021: "{{.*}}/hexagon/lib/v4/fini.o"
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// Other args to pass to linker
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -s \
+// RUN: -Tbss 0xdead -Tdata 0xbeef -Ttext 0xcafe \
+// RUN: -t \
+// RUN: -e start_here \
+// RUN: -uFoo -undefined Bar \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK022 %s
+// CHECK022: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK022-NEXT: "{{.*}}/bin/hexagon-as"{{.*}}
+// CHECK022-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK022: "{{.*}}/hexagon/lib/v4/crt0_standalone.o"
+// CHECK022: "{{.*}}/hexagon/lib/v4/crt0.o"
+// CHECK022: "{{.*}}/hexagon/lib/v4/init.o"
+// CHECK022: "-L{{.*}}/lib/gcc/hexagon/4.4.0/v4"
+// CHECK022: "-L{{.*}}/lib/gcc/hexagon/4.4.0"
+// CHECK022: "-L{{.*}}/lib/gcc"
+// CHECK022: "-L{{.*}}/hexagon/lib/v4"
+// CHECK022: "-L{{.*}}/hexagon/lib"
+// CHECK022: "-Tbss" "0xdead" "-Tdata" "0xbeef" "-Ttext" "0xcafe"
+// CHECK022: "-s"
+// CHECK022: "-t"
+// CHECK022: "-u" "Foo" "-undefined" "Bar"
+// CHECK022: "{{[^"]+}}.o"
+// CHECK022: "-lstdc++" "-lm"
+// CHECK022: "--start-group" "-lstandalone" "-lc" "-lgcc" "--end-group"
+// CHECK022: "{{.*}}/hexagon/lib/v4/fini.o"
+
+// -----------------------------------------------------------------------------
+// pic, small data threshold
+// -----------------------------------------------------------------------------
+// RUN: %clang -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK023 %s
+// CHECK023: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK023: "-mrelocation-model" "static"
+// CHECK023-NEXT: "{{.*}}/bin/hexagon-as"
+// CHECK023-NOT: "-G{{[0-9]+}}"
+// CHECK023-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK023-NOT: "-G{{[0-9]+}}"
+
+// RUN: %clang -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -fpic \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK024 %s
+// RUN: %clang -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -fPIC \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK024 %s
+// RUN: %clang -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -fPIC \
+// RUN: -msmall_data_threshold=8 \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK024 %s
+// CHECK024: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK024-NOT: "-mrelocation-model" "static"
+// CHECK024: "-pic-level" "{{[12]}}"
+// CHECK024: "-mllvm" "-hexagon-small-data-threshold=0"
+// CHECK024-NEXT: "{{.*}}/bin/hexagon-as"
+// CHECK024: "-G0"
+// CHECK024-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK024: "-G0"
+
+// RUN: %clang -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -G=8 \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK025 %s
+// RUN: %clang -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -G 8 \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK025 %s
+// RUN: %clang -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -msmall-data-threshold=8 \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK025 %s
+// CHECK025: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK025: "-mrelocation-model" "static"
+// CHECK025: "-mllvm" "-hexagon-small-data-threshold=8"
+// CHECK025-NEXT: "{{.*}}/bin/hexagon-as"
+// CHECK025: "-G8"
+// CHECK025-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK025: "-G8"
+
+// -----------------------------------------------------------------------------
+// pie
+// -----------------------------------------------------------------------------
+// RUN: %clang -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -pie \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK026 %s
+// CHECK026: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK026-NEXT: "{{.*}}/bin/hexagon-as"
+// CHECK026-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK026: "-pie"
+
+// RUN: %clang -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -pie -shared \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK027 %s
+// CHECK027: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK027-NEXT: "{{.*}}/bin/hexagon-as"
+// CHECK027-NEXT: "{{.*}}/bin/hexagon-ld"
+// CHECK027-NOT: "-pie"
+
+// -----------------------------------------------------------------------------
+// Misc Defaults
+// -----------------------------------------------------------------------------
+// RUN: %clang -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK028 %s
+// CHECK028: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK028: "-mqdsp6-compat"
+// CHECK028: "-Wreturn-type"
+// CHECK028-NEXT: "{{.*}}/bin/hexagon-as"
+// CHECK028-NEXT: "{{.*}}/bin/hexagon-ld"
+
+// -----------------------------------------------------------------------------
+// Test Assembler related args
+// -----------------------------------------------------------------------------
+// RUN: %clang -### -target hexagon-unknown-linux \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
+// RUN: -gdwarf-2 \
+// RUN: -Wa,--noexecstack,--trap \
+// RUN: -Xassembler --keep-locals \
+// RUN: %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHECK029 %s
+// CHECK029: "{{.*}}clang{{.*}}" "-cc1"
+// CHECK029-NEXT: "{{.*}}/bin/hexagon-as"
+// CHECK029: "-gdwarf-2" "--noexecstack" "--trap" "--keep-locals"
+// CHECK029-NEXT: "{{.*}}/bin/hexagon-ld"
diff --git a/test/Driver/inhibit-downstream-commands.c b/test/Driver/inhibit-downstream-commands.c
new file mode 100644
index 0000000..5e46708
--- /dev/null
+++ b/test/Driver/inhibit-downstream-commands.c
@@ -0,0 +1,6 @@
+// RUN: %clang -no-integrated-as %s 2>&1 | FileCheck %s
+// CHECK: error: unknown type name 'invalid'
+// CHECK-NOT: clang: error: assembler command failed
+// CHECK-NOT: clang: error: linker command failed
+// XFAIL: win32
+invalid C code!
diff --git a/test/Driver/integrated-as.c b/test/Driver/integrated-as.c
new file mode 100644
index 0000000..2045e8b
--- /dev/null
+++ b/test/Driver/integrated-as.c
@@ -0,0 +1,7 @@
+// RUN: %clang -### -c -save-temps -integrated-as %s 2>&1 | FileCheck %s
+
+// gcc is invoked instead of clang-cc1as with gcc-driver -save-temps.
+// REQUIRES: clang-driver
+
+// CHECK: cc1as
+// CHECK: -relax-all
diff --git a/test/Driver/integrated-as.s b/test/Driver/integrated-as.s
new file mode 100644
index 0000000..d614418
--- /dev/null
+++ b/test/Driver/integrated-as.s
@@ -0,0 +1,6 @@
+// RUN: %clang -### -c -integrated-as %s 2>&1 | FileCheck %s
+
+// REQUIRES: clang-driver
+
+// CHECK: cc1as
+// CHECK-NOT: -relax-all
diff --git a/test/Driver/linker-opts.c b/test/Driver/linker-opts.c
index 2a96a17..7668a75 100644
--- a/test/Driver/linker-opts.c
+++ b/test/Driver/linker-opts.c
@@ -2,4 +2,5 @@
// CHECK: "-L{{.*}}/test1"
// GCC driver is used as linker on cygming. It should be aware of LIBRARY_PATH.
-// XFAIL: cygwin,mingw32,win32
+// XFAIL: win32
+// REQUIRES: clang-driver
diff --git a/test/Driver/linux-header-search.cpp b/test/Driver/linux-header-search.cpp
index 065bd34..d09f5b2 100644
--- a/test/Driver/linux-header-search.cpp
+++ b/test/Driver/linux-header-search.cpp
@@ -16,6 +16,34 @@
// CHECK-UBUNTU-11-04: "-internal-externc-isystem" "[[SYSROOT]]/include"
// CHECK-UBUNTU-11-04: "-internal-externc-isystem" "[[SYSROOT]]/usr/include"
//
+// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
+// RUN: -target x86_64-unknown-linux-gnu \
+// RUN: --sysroot=%S/Inputs/ubuntu_13.04_multiarch_tree \
+// RUN: | FileCheck --check-prefix=CHECK-UBUNTU-13-04 %s
+// CHECK-UBUNTU-13-04: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
+// CHECK-UBUNTU-13-04: "-isysroot" "[[SYSROOT:[^"]+]]"
+// CHECK-UBUNTU-13-04: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7"
+// CHECK-UBUNTU-13-04: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/backward"
+// CHECK-UBUNTU-13-04: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../include/x86_64-linux-gnu/c++/4.7"
+// CHECK-UBUNTU-13-04: "-internal-isystem" "[[SYSROOT]]/usr/local/include"
+// CHECK-UBUNTU-13-04: "-internal-isystem" "{{.*}}/lib{{(64|32)?}}/clang/{{[0-9]\.[0-9]}}/include"
+// CHECK-UBUNTU-13-04: "-internal-externc-isystem" "[[SYSROOT]]/usr/include/x86_64-linux-gnu"
+// CHECK-UBUNTU-13-04: "-internal-externc-isystem" "[[SYSROOT]]/include"
+// CHECK-UBUNTU-13-04: "-internal-externc-isystem" "[[SYSROOT]]/usr/include"
+//
+// Test Ubuntu/Debian's new version of multiarch, with -m32.
+// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
+// RUN: -target x86_64-unknown-linux-gnu -m32 \
+// RUN: --sysroot=%S/Inputs/ubuntu_13.04_multiarch_tree \
+// RUN: | FileCheck --check-prefix=CHECK-UBUNTU-13-04-M32 %s
+// CHECK-UBUNTU-13-04-M32: "{{[^"]*}}clang{{[^"]*}}" "-cc1"
+// CHECK-UBUNTU-13-04-M32: "-triple" "i386-unknown-linux-gnu"
+// CHECK-UBUNTU-13-04-M32: "-isysroot" "[[SYSROOT:[^"]+]]"
+// CHECK-UBUNTU-13-04-M32: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7"
+// CHECK-UBUNTU-13-04-M32: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/x86_64-linux-gnu/32"
+// CHECK-UBUNTU-13-04-M32: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../include/c++/4.7/backward"
+// CHECK-UBUNTU-13-04-M32: "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../include/x86_64-linux-gnu/c++/4.7/32"
+//
// Thoroughly exercise the Debian multiarch environment.
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
// RUN: -target i686-linux-gnu \
diff --git a/test/Driver/linux-ld.c b/test/Driver/linux-ld.c
index 7237029..79282cb 100644
--- a/test/Driver/linux-ld.c
+++ b/test/Driver/linux-ld.c
@@ -5,6 +5,7 @@
// RUN: -target i386-unknown-linux \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-LD-32 %s
+// CHECK-LD-32-NOT: warning:
// CHECK-LD-32: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
// CHECK-LD-32: "{{.*}}/usr/lib/gcc/i386-unknown-linux/4.6.0/crtbegin.o"
// CHECK-LD-32: "-L[[SYSROOT]]/usr/lib/gcc/i386-unknown-linux/4.6.0"
@@ -17,13 +18,66 @@
// RUN: -target x86_64-unknown-linux \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-LD-64 %s
+// CHECK-LD-64-NOT: warning:
// CHECK-LD-64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-LD-64: "--eh-frame-hdr"
+// CHECK-LD-64: "-m" "elf_x86_64"
+// CHECK-LD-64: "-dynamic-linker"
// CHECK-LD-64: "{{.*}}/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtbegin.o"
// CHECK-LD-64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0"
// CHECK-LD-64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/lib"
// CHECK-LD-64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../.."
// CHECK-LD-64: "-L[[SYSROOT]]/lib"
// CHECK-LD-64: "-L[[SYSROOT]]/usr/lib"
+// CHECK-LD-64: "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
+// CHECK-LD-64: "-lc"
+// CHECK-LD-64: "-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed"
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target x86_64-unknown-linux \
+// RUN: -static-libgcc \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-LD-64-STATIC-LIBGCC %s
+// CHECK-LD-64-STATIC-LIBGCC-NOT: warning:
+// CHECK-LD-64-STATIC-LIBGCC: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-LD-64-STATIC-LIBGCC: "--eh-frame-hdr"
+// CHECK-LD-64-STATIC-LIBGCC: "-m" "elf_x86_64"
+// CHECK-LD-64-STATIC-LIBGCC: "-dynamic-linker"
+// CHECK-LD-64-STATIC-LIBGCC: "{{.*}}/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtbegin.o"
+// CHECK-LD-64-STATIC-LIBGCC: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0"
+// CHECK-LD-64-STATIC-LIBGCC: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/lib"
+// CHECK-LD-64-STATIC-LIBGCC: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../.."
+// CHECK-LD-64-STATIC-LIBGCC: "-L[[SYSROOT]]/lib"
+// CHECK-LD-64-STATIC-LIBGCC: "-L[[SYSROOT]]/usr/lib"
+// CHECK-LD-64-STATIC-LIBGCC: "-lgcc" "-lgcc_eh"
+// CHECK-LD-64-STATIC-LIBGCC: "-lc"
+// CHECK-LD-64-STATIC-LIBGCC: "-lgcc" "-lgcc_eh"
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target x86_64-unknown-linux \
+// RUN: -static \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-LD-64-STATIC %s
+// CHECK-LD-64-STATIC-NOT: warning:
+// CHECK-LD-64-STATIC: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]"
+// CHECK-LD-64-STATIC-NOT: "--eh-frame-hdr"
+// CHECK-LD-64-STATIC: "-m" "elf_x86_64"
+// CHECK-LD-64-STATIC-NOT: "-dynamic-linker"
+// CHECK-LD-64-STATIC: "-static"
+// CHECK-LD-64-STATIC: "{{.*}}/usr/lib/gcc/x86_64-unknown-linux/4.6.0/crtbeginT.o"
+// CHECK-LD-64-STATIC: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0"
+// CHECK-LD-64-STATIC: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../../../x86_64-unknown-linux/lib"
+// CHECK-LD-64-STATIC: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-unknown-linux/4.6.0/../../.."
+// CHECK-LD-64-STATIC: "-L[[SYSROOT]]/lib"
+// CHECK-LD-64-STATIC: "-L[[SYSROOT]]/usr/lib"
+// CHECK-LD-64-STATIC: "--start-group" "-lgcc" "-lgcc_eh" "-lc" "--end-group"
+//
+// Check that flags can be combined. The -static dominates.
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target x86_64-unknown-linux \
+// RUN: -static-libgcc -static \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-LD-64-STATIC %s
//
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
// RUN: -target i386-unknown-linux -m32 \
@@ -420,6 +474,7 @@
// CHECK-ANDROID: "-L[[SYSROOT]]/usr/lib"
// CHECK-ANDROID-NOT: "gcc_s"
// CHECK-ANDROID: "-lgcc"
+// CHECK-ANDROID: "-ldl"
// CHECK-ANDROID-NOT: "gcc_s"
// CHECK-ANDROID: "{{.*}}/crtend_android.o"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
@@ -448,6 +503,7 @@
// CHECK-ANDROID-SO: "-L[[SYSROOT]]/usr/lib"
// CHECK-ANDROID-SO-NOT: "gcc_s"
// CHECK-ANDROID-SO: "-lgcc"
+// CHECK-ANDROID-SO: "-ldl"
// CHECK-ANDROID-SO-NOT: "gcc_s"
// CHECK-ANDROID-SO: "{{.*}}/crtend_so.o"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
@@ -475,6 +531,7 @@
// CHECK-ANDROID-STATIC: "-L[[SYSROOT]]/usr/lib"
// CHECK-ANDROID-STATIC-NOT: "gcc_s"
// CHECK-ANDROID-STATIC: "-lgcc"
+// CHECK-ANDROID-STATIC-NOT: "-ldl"
// CHECK-ANDROID-STATIC-NOT: "gcc_s"
// CHECK-ANDROID-STATIC: "{{.*}}/crtend_android.o"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
diff --git a/test/Driver/lit.local.cfg b/test/Driver/lit.local.cfg
new file mode 100644
index 0000000..a62ea1a
--- /dev/null
+++ b/test/Driver/lit.local.cfg
@@ -0,0 +1 @@
+config.suffixes = ['.c', '.cpp', '.h', '.m', '.mm', '.S', '.s']
diff --git a/test/Driver/mips-as.c b/test/Driver/mips-as.c
index fbaf62f..146b193 100644
--- a/test/Driver/mips-as.c
+++ b/test/Driver/mips-as.c
@@ -16,8 +16,8 @@
//
// RUN: %clang -target mipsel-linux-gnu -### \
// 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: | FileCheck -check-prefix=MIPS32-DEF-EL-AS %s
+// MIPS32-DEF-EL-AS: as{{(.exe)?}}" "-march" "mips32" "-mabi" "32" "-EL"
//
// RUN: %clang -target mips64-linux-gnu -### \
// RUN: -no-integrated-as -c %s 2>&1 \
@@ -26,8 +26,8 @@
//
// RUN: %clang -target mips64el-linux-gnu -### \
// 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: | FileCheck -check-prefix=MIPS64-DEF-EL-AS %s
+// MIPS64-DEF-EL-AS: as{{(.exe)?}}" "-march" "mips64" "-mabi" "64" "-EL"
//
// RUN: %clang -target mips-linux-gnu -mabi=eabi -### \
// RUN: -no-integrated-as -c %s 2>&1 \
@@ -39,6 +39,16 @@
// RUN: | FileCheck -check-prefix=MIPS-N32 %s
// MIPS-N32: as{{(.exe)?}}" "-march" "mips64" "-mabi" "n32" "-EB"
//
+// RUN: %clang -target mipsel-linux-gnu -mabi=32 -### \
+// 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 mips64el-linux-gnu -mabi=64 -### \
+// 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-linux-gnu -march=mips32r2 -### \
// RUN: -no-integrated-as -c %s 2>&1 \
// RUN: | FileCheck -check-prefix=MIPS-32R2 %s
diff --git a/test/Driver/mips-eleb.c b/test/Driver/mips-eleb.c
new file mode 100644
index 0000000..8afe44f
--- /dev/null
+++ b/test/Driver/mips-eleb.c
@@ -0,0 +1,31 @@
+// REQUIRES: mips-registered-target
+//
+// Check that -EL/-EB options adjust the toolchain flags.
+//
+// RUN: %clang -target mips-unknown-linux-gnu -### \
+// RUN: -EL -no-integrated-as %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS32-EL %s
+// MIPS32-EL: "{{.*}}clang{{.*}}" "-cc1" "-triple" "mipsel-unknown-linux-gnu"
+// MIPS32-EL: "{{.*}}as{{(.exe)?}}" "-march" "mips32" "-mabi" "32" "-EL"
+// MIPS32-EL: "{{.*}}ld{{(.exe)?}}" {{.*}} "-m" "elf32ltsmip"
+//
+// RUN: %clang -target mips64-unknown-linux-gnu -### \
+// RUN: -EL -no-integrated-as %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS64-EL %s
+// MIPS64-EL: "{{.*}}clang{{.*}}" "-cc1" "-triple" "mips64el-unknown-linux-gnu"
+// MIPS64-EL: "{{.*}}as{{(.exe)?}}" "-march" "mips64" "-mabi" "64" "-EL"
+// MIPS64-EL: "{{.*}}ld{{(.exe)?}}" {{.*}} "-m" "elf64ltsmip"
+//
+// RUN: %clang -target mipsel-unknown-linux-gnu -### \
+// RUN: -EB -no-integrated-as %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS32-EB %s
+// MIPS32-EB: "{{.*}}clang{{.*}}" "-cc1" "-triple" "mips-unknown-linux-gnu"
+// MIPS32-EB: "{{.*}}as{{(.exe)?}}" "-march" "mips32" "-mabi" "32" "-EB"
+// MIPS32-EB: "{{.*}}ld{{(.exe)?}}" {{.*}} "-m" "elf32btsmip"
+//
+// RUN: %clang -target mips64el-unknown-linux-gnu -### \
+// RUN: -EB -no-integrated-as %s 2>&1 \
+// RUN: | FileCheck -check-prefix=MIPS64-EB %s
+// MIPS64-EB: "{{.*}}clang{{.*}}" "-cc1" "-triple" "mips64-unknown-linux-gnu"
+// MIPS64-EB: "{{.*}}as{{(.exe)?}}" "-march" "mips64" "-mabi" "64" "-EB"
+// MIPS64-EB: "{{.*}}ld{{(.exe)?}}" {{.*}} "-m" "elf64btsmip"
diff --git a/test/Driver/mips-features.c b/test/Driver/mips-features.c
index 28048e7..3bebffc 100644
--- a/test/Driver/mips-features.c
+++ b/test/Driver/mips-features.c
@@ -38,6 +38,18 @@
// RUN: | FileCheck --check-prefix=CHECK-NOMDSPR2 %s
// CHECK-NOMDSPR2: "-target-feature" "-dspr2"
//
+// -mxgot
+// RUN: %clang -target mips-linux-gnu -### -c %s \
+// RUN: -mno-xgot -mxgot 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-XGOT %s
+// CHECK-XGOT: "-mllvm" "-mxgot"
+//
+// -mno-xgot
+// RUN: %clang -target mips-linux-gnu -### -c %s \
+// RUN: -mxgot -mno-xgot 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NOXGOT %s
+// CHECK-NOXGOT-NOT: "-mllvm" "-mxgot"
+//
// -G
// RUN: %clang -target mips-linux-gnu -### -c %s \
// RUN: -G 16 2>&1 \
diff --git a/test/Driver/mips-float.c b/test/Driver/mips-float.c
index 886c335..5c16b9b 100644
--- a/test/Driver/mips-float.c
+++ b/test/Driver/mips-float.c
@@ -41,3 +41,44 @@
// RUN: -target mips-linux-gnu -mfloat-abi=single \
// RUN: | FileCheck --check-prefix=CHECK-ABI-SINGLE %s
// CHECK-ABI-SINGLE: "-target-feature" "+single-float"
+//
+// Default -mips16
+// RUN: %clang -c %s -### -o %t.o 2>&1 \
+// RUN: -target mips-linux-gnu -mips16 \
+// RUN: | FileCheck --check-prefix=CHECK-DEF-MIPS16 %s
+// CHECK-DEF-MIPS16: "-mfloat-abi" "soft"
+// CHECK-DEF-MIPS16: "-mllvm" "-mips16-hard-float"
+//
+// -mhard-float -mips16
+// RUN: %clang -c %s -### -o %t.o 2>&1 \
+// RUN: -target mips-linux-gnu -mhard-float -mips16 \
+// RUN: | FileCheck --check-prefix=CHECK-HARD-MIPS16 %s
+// CHECK-HARD-MIPS16: "-msoft-float"
+// CHECK-HARD-MIPS16: "-mfloat-abi" "soft"
+// CHECK-HARD-MIPS16: "-target-feature" "+soft-float"
+// CHECK-HARD-MIPS16: "-mllvm" "-mips16-hard-float"
+//
+// -msoft-float -mips16
+// RUN: %clang -c %s -### -o %t.o 2>&1 \
+// RUN: -target mips-linux-gnu -msoft-float -mips16 \
+// RUN: | FileCheck --check-prefix=CHECK-SOFT-MIPS16 %s
+// CHECK-SOFT-MIPS16: "-msoft-float"
+// CHECK-SOFT-MIPS16: "-mfloat-abi" "soft"
+// CHECK-SOFT-MIPS16: "-target-feature" "+soft-float"
+//
+// -mfloat-abi=hard -mips16
+// RUN: %clang -c %s -### -o %t.o 2>&1 \
+// RUN: -target mips-linux-gnu -mfloat-abi=hard -mips16 \
+// RUN: | FileCheck --check-prefix=CHECK-ABI-HARD-MIPS16 %s
+// CHECK-ABI-HARD-MIPS16: "-msoft-float"
+// CHECK-ABI-HARD-MIPS16: "-mfloat-abi" "soft"
+// CHECK-ABI-HARD-MIPS16: "-target-feature" "+soft-float"
+// CHECK-ABI-HARD-MIPS16: "-mllvm" "-mips16-hard-float"
+//
+// -mfloat-abi=soft -mips16
+// RUN: %clang -c %s -### -o %t.o 2>&1 \
+// RUN: -target mips-linux-gnu -mfloat-abi=soft -mips16 \
+// RUN: | FileCheck --check-prefix=CHECK-ABI-SOFT-MIPS16 %s
+// CHECK-ABI-SOFT-MIPS16: "-msoft-float"
+// CHECK-ABI-SOFT-MIPS16: "-mfloat-abi" "soft"
+// CHECK-ABI-SOFT-MIPS16: "-target-feature" "+soft-float"
diff --git a/test/Driver/mips-long-double.c b/test/Driver/mips-long-double.c
new file mode 100644
index 0000000..09de38c
--- /dev/null
+++ b/test/Driver/mips-long-double.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -triple mips64-unknown-freebsd -std=c11 -verify %s
+// RUN: %clang_cc1 -triple mips-unknown-freebsd -std=c11 -verify %s
+// RUN: %clang_cc1 -triple mips-unknown-linux -std=c11 -verify %s
+// RUN: %clang_cc1 -triple mips64-unknown-linux -std=c11 -verify %s
+// expected-no-diagnostics
+
+#ifdef _ABI64
+# ifdef __FreeBSD__
+_Static_assert(sizeof(long double) == 8, "sizeof long double is wrong");
+_Static_assert(_Alignof(long double) == 8, "alignof long double is wrong");
+# else
+_Static_assert(sizeof(long double) == 16, "sizeof long double is wrong");
+_Static_assert(_Alignof(long double) == 16, "alignof long double is wrong");
+# endif
+#else
+_Static_assert(sizeof(long double) == 8, "sizeof long double is wrong");
+_Static_assert(_Alignof(long double) == 8, "alignof long double is wrong");
+#endif
+
diff --git a/test/Driver/modules.m b/test/Driver/modules.m
index b93054d..69c79fc 100644
--- a/test/Driver/modules.m
+++ b/test/Driver/modules.m
@@ -4,3 +4,9 @@
// RUN: %clang -fmodules -fno-modules -fmodules -### %s 2>&1 | FileCheck -check-prefix=CHECK-HAS-MODULES %s
// CHECK-HAS-MODULES: -fmodules
+// RUN: %clang -target x86_64-apple-darwin10 -fmodules -fno-modules -fmodules -### %s 2>&1 | FileCheck -check-prefix=CHECK-HAS-AUTOLINK %s
+// CHECK-HAS-AUTOLINK: -fmodules-autolink
+
+// RUN: %clang -fmodules -fno-modules -fno-modules-autolink -fmodules -### %s 2>&1 | FileCheck -check-prefix=CHECK-NO-AUTOLINK %s
+// CHECK-NO-AUTOLINK-NOT: -fmodules-autolink
+
diff --git a/test/Driver/modules_integrated_as.c b/test/Driver/modules_integrated_as.c
new file mode 100644
index 0000000..0abd18f
--- /dev/null
+++ b/test/Driver/modules_integrated_as.c
@@ -0,0 +1,6 @@
+// RUN: %clang -fsyntax-only modules_integrated_as.c -fmodules -no-integrated-as -### 2>&1 | FileCheck %s
+
+// Test that the autolinking feature is disabled with *not* using the
+// integrated assembler.
+
+// CHECK-NOT: -fmodules-autolink
diff --git a/test/Driver/ms-inline-asm.c b/test/Driver/ms-inline-asm.c
new file mode 100644
index 0000000..0383564
--- /dev/null
+++ b/test/Driver/ms-inline-asm.c
@@ -0,0 +1,15 @@
+// RUN: %clang -target x86_64-apple-darwin10 \
+// RUN: -### -fsyntax-only -fasm-blocks %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-BLOCKS < %t %s
+
+// RUN: %clang -target x86_64-apple-darwin10 \
+// RUN: -### -fsyntax-only -fno-asm-blocks -fasm-blocks %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-BLOCKS < %t %s
+
+// CHECK-BLOCKS: "-fasm-blocks"
+
+// RUN: %clang -target x86_64-apple-darwin10 \
+// RUN: -### -fsyntax-only -fasm-blocks -fno-asm-blocks %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-NO-BLOCKS < %t %s
+
+// CHECK-NO-BLOCKS-NOT: "-fasm-blocks"
diff --git a/test/Driver/no-integrated-as-win.c b/test/Driver/no-integrated-as-win.c
new file mode 100644
index 0000000..0d6c295
--- /dev/null
+++ b/test/Driver/no-integrated-as-win.c
@@ -0,0 +1,3 @@
+// RUN: %clang -target x86_64-pc-win32 -### -no-integrated-as %s -c 2>&1 | FileCheck %s
+
+// CHECK: there is no external assembler we can use on windows
diff --git a/test/Driver/nodefaultlib.c b/test/Driver/nodefaultlib.c
index 518928a..f9462fd 100644
--- a/test/Driver/nodefaultlib.c
+++ b/test/Driver/nodefaultlib.c
@@ -2,7 +2,7 @@
// RUN: FileCheck < %t %s
//
// CHECK-NOT: start-group
-// CHECK-NOT: -lgcc
-// CHECK-NOT: -lc
+// CHECK-NOT: "-lgcc"
+// CHECK-NOT: "-lc"
// CHECK: crtbegin
// CHECK: crtend
diff --git a/test/Driver/objc++-cpp-output.mm b/test/Driver/objc++-cpp-output.mm
index 9c4d553..63b15d8 100644
--- a/test/Driver/objc++-cpp-output.mm
+++ b/test/Driver/objc++-cpp-output.mm
@@ -1,4 +1,5 @@
// RUN: %clang -x objc++-cpp-output -c %s -o /dev/null
+// RUN: %clang -x objc++-cpp-output -c %s -o /dev/null -### 2>&1 | FileCheck %s
// PR13820
// REQUIRES: LP64
@@ -9,3 +10,8 @@
@end
void f() {}
class C {};
+
+// Make sure the driver is passing all the necessary exception flags.
+// CHECK: "-fobjc-exceptions"
+// CHECK: "-fcxx-exceptions"
+// CHECK: "-fexceptions"
diff --git a/test/Driver/objc_default_synth.m b/test/Driver/objc_default_synth.m
new file mode 100644
index 0000000..a8c7f7e
--- /dev/null
+++ b/test/Driver/objc_default_synth.m
@@ -0,0 +1,6 @@
+// We should be synthesizing properties by default on all platforms now.
+// RUN: %clang -### -target armv7-unknown-freebsd %s 2>&1 | FileCheck %s
+// RUN: %clang -### -target armv7-apple-ios %s 2>&1 | FileCheck %s
+// RUN: %clang -### -target i686-apple-macosx %s 2>&1 | FileCheck %s
+// REQUIRES: clang-driver
+// CHECK: -fobjc-default-synthesize
diff --git a/test/Driver/openbsd.c b/test/Driver/openbsd.c
index afd8b5a..4fd5b6a 100644
--- a/test/Driver/openbsd.c
+++ b/test/Driver/openbsd.c
@@ -6,4 +6,22 @@
// 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"
+// CHECK-PG: ld{{.*}}" "-e" "__start" "--eh-frame-hdr" "-Bdynamic" "-dynamic-linker" "{{.*}}ld.so" "-o" "a.out" "{{.*}}gcrt0.o" "{{.*}}crtbegin.o" "{{.*}}.o" "-lgcc" "-lpthread_p" "-lc_p" "-lgcc" "{{.*}}crtend.o"
+
+// Check that the new linker flags are passed to OpenBSD
+// RUN: %clang -no-canonical-prefixes -target i686-pc-openbsd -r %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-LD-R %s
+// RUN: %clang -no-canonical-prefixes -target i686-pc-openbsd -s %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-LD-S %s
+// RUN: %clang -no-canonical-prefixes -target i686-pc-openbsd -t %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-LD-T %s
+// RUN: %clang -no-canonical-prefixes -target i686-pc-openbsd -Z %s -### 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-LD-Z %s
+// CHECK-LD-R: clang{{.*}}" "-cc1" "-triple" "i686-pc-openbsd"
+// CHECK-LD-R: ld{{.*}}" "-e" "__start" "--eh-frame-hdr" "-Bdynamic" "-dynamic-linker" "{{.*}}ld.so" "-o" "a.out" "{{.*}}crt0.o" "{{.*}}crtbegin.o" "-L{{.*}}" "-r" "{{.*}}.o" "-lgcc" "-lc" "-lgcc" "{{.*}}crtend.o"
+// CHECK-LD-S: clang{{.*}}" "-cc1" "-triple" "i686-pc-openbsd"
+// CHECK-LD-S: ld{{.*}}" "-e" "__start" "--eh-frame-hdr" "-Bdynamic" "-dynamic-linker" "{{.*}}ld.so" "-o" "a.out" "{{.*}}crt0.o" "{{.*}}crtbegin.o" "-L{{.*}}" "-s" "{{.*}}.o" "-lgcc" "-lc" "-lgcc" "{{.*}}crtend.o"
+// CHECK-LD-T: clang{{.*}}" "-cc1" "-triple" "i686-pc-openbsd"
+// CHECK-LD-T: ld{{.*}}" "-e" "__start" "--eh-frame-hdr" "-Bdynamic" "-dynamic-linker" "{{.*}}ld.so" "-o" "a.out" "{{.*}}crt0.o" "{{.*}}crtbegin.o" "-L{{.*}}" "-t" "{{.*}}.o" "-lgcc" "-lc" "-lgcc" "{{.*}}crtend.o"
+// CHECK-LD-Z: clang{{.*}}" "-cc1" "-triple" "i686-pc-openbsd"
+// CHECK-LD-Z: ld{{.*}}" "-e" "__start" "--eh-frame-hdr" "-Bdynamic" "-dynamic-linker" "{{.*}}ld.so" "-o" "a.out" "{{.*}}crt0.o" "{{.*}}crtbegin.o" "-L{{.*}}" "-Z" "{{.*}}.o" "-lgcc" "-lc" "-lgcc" "{{.*}}crtend.o"
diff --git a/test/Driver/output-file-cleanup.c b/test/Driver/output-file-cleanup.c
index 0a0c960..0aee5f8 100644
--- a/test/Driver/output-file-cleanup.c
+++ b/test/Driver/output-file-cleanup.c
@@ -1,16 +1,16 @@
-// RUN: touch %t.o
-// RUN: not %clang -DCRASH -o %t.o -MMD -MF %t.d %s
-// RUN: test ! -f %t.o
+// RUN: touch %t.s
+// RUN: not %clang -S -DCRASH -o %t.s -MMD -MF %t.d %s
+// RUN: test ! -f %t.s
// RUN: test ! -f %t.d
-// RUN: touch %t.o
-// RUN: not %clang -DMISSING -o %t.o -MMD -MF %t.d %s
-// RUN: test ! -f %t.o
+// RUN: touch %t.s
+// RUN: not %clang -S -DMISSING -o %t.s -MMD -MF %t.d %s
+// RUN: test ! -f %t.s
// RUN: test ! -f %t.d
-// RUN: touch %t.o
-// RUN: not %clang -o %t.o -MMD -MF %t.d %s
-// RUN: test ! -f %t.o
+// RUN: touch %t.s
+// RUN: not %clang -S -o %t.s -MMD -MF %t.d %s
+// RUN: test ! -f %t.s
// RUN: test -f %t.d
// REQUIRES: shell
@@ -23,3 +23,28 @@
#else
invalid C code
#endif
+
+// RUN: touch %t1.c
+// RUN: echo "invalid C code" > %t2.c
+// RUN: cd %T && not %clang -S %t1.c %t2.c
+// RUN: test -f %t1.s
+// RUN: test ! -f %t2.s
+
+// RUN: touch %t1.c
+// RUN: touch %t2.c
+// RUN: chmod -r %t2.c
+// RUN: cd %T && not %clang -S %t1.c %t2.c
+// RUN: test -f %t1.s
+// RUN: test ! -f %t2.s
+
+// RUN: touch %t1.c
+// RUN: echo "invalid C code" > %t2.c
+// RUN: touch %t3.c
+// RUN: echo "invalid C code" > %t4.c
+// RUN: touch %t5.c
+// RUN: cd %T && not %clang -S %t1.c %t2.c %t3.c %t4.c %t5.c
+// RUN: test -f %t1.s
+// RUN: test ! -f %t2.s
+// RUN: test -f %t3.s
+// RUN: test ! -f %t4.s
+// RUN: test -f %t5.s
diff --git a/test/Driver/output-file-is-dir.c b/test/Driver/output-file-is-dir.c
new file mode 100644
index 0000000..c1fec56
--- /dev/null
+++ b/test/Driver/output-file-is-dir.c
@@ -0,0 +1,7 @@
+// RUN: rm -rf %t.dir
+// RUN: mkdir -p %t.dir/a.out
+// RUN: cd %t.dir && not %clang %s
+// RUN: test -d %t.dir/a.out
+// REQUIRES: shell
+
+int main() { return 0; }
diff --git a/test/Driver/pic.c b/test/Driver/pic.c
index 54e5982..8ba9319 100644
--- a/test/Driver/pic.c
+++ b/test/Driver/pic.c
@@ -34,6 +34,8 @@
//
// CHECK-NON-DARWIN-DYNAMIC-NO-PIC: error: unsupported option '-mdynamic-no-pic' for target 'i386-unknown-unknown'
//
+// CHECK-NO-PIE-NOT: "-pie"
+//
// 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 \
@@ -127,6 +129,10 @@
// RUN: %clang -c %s -target i386-unknown-unknown -static -fPIC -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIC
//
+// On Linux, disregard -pie if we have -shared.
+// RUN: %clang %s -target i386-unknown-linux -shared -pie -### 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-NO-PIE
+//
// 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
diff --git a/test/Driver/ppc-features.cpp b/test/Driver/ppc-features.cpp
new file mode 100644
index 0000000..be78e19
--- /dev/null
+++ b/test/Driver/ppc-features.cpp
@@ -0,0 +1,88 @@
+// Check that we error when -faltivec is specified on non-ppc platforms.
+
+// RUN: %clang -target powerpc-unk-unk -faltivec -fsyntax-only %s
+// RUN: %clang -target powerpc64-linux-gnu -faltivec -fsyntax-only %s
+// RUN: %clang -target powerpc64-linux-gnu -maltivec -fsyntax-only %s
+
+// RUN: %clang -target i386-pc-win32 -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: %clang -target x86_64-unknown-freebsd -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: %clang -target armv6-apple-darwin -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: %clang -target armv7-apple-darwin -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: %clang -target mips-linux-gnu -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: %clang -target mips64-linux-gnu -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
+// RUN: %clang -target sparc-unknown-solaris -faltivec -fsyntax-only %s 2>&1 | FileCheck %s
+
+// CHECK: invalid argument '-faltivec' only allowed with 'ppc/ppc64'
+
+// Check that -fno-altivec and -mno-altivec correctly disable the altivec
+// target feature on powerpc.
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -fno-altivec -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-1 %s
+// CHECK-1: "-target-feature" "-altivec"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-altivec -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-2 %s
+// CHECK-2: "-target-feature" "-altivec"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -faltivec -mno-altivec -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-3 %s
+// CHECK-3: "-target-feature" "-altivec"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -maltivec -fno-altivec -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-4 %s
+// CHECK-4: "-target-feature" "-altivec"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-altivec -faltivec -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-5 %s
+// CHECK-5-NOT: "-target-feature" "-altivec"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -fno-altivec -maltivec -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-6 %s
+// CHECK-6-NOT: "-target-feature" "-altivec"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -fno-altivec -mcpu=7400 -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-7 %s
+// CHECK-7: "-target-feature" "-altivec"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -fno-altivec -mcpu=g4 -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-8 %s
+// CHECK-8: "-target-feature" "-altivec"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -fno-altivec -mcpu=7450 -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-9 %s
+// CHECK-9: "-target-feature" "-altivec"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -fno-altivec -mcpu=g4+ -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-10 %s
+// CHECK-10: "-target-feature" "-altivec"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -fno-altivec -mcpu=970 -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-11 %s
+// CHECK-11: "-target-feature" "-altivec"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -fno-altivec -mcpu=g5 -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-12 %s
+// CHECK-12: "-target-feature" "-altivec"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -fno-altivec -mcpu=pwr6 -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-13 %s
+// CHECK-13: "-target-feature" "-altivec"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -fno-altivec -mcpu=pwr7 -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-14 %s
+// CHECK-14: "-target-feature" "-altivec"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -fno-altivec -mcpu=ppc64 -### -o %t.o 2>&1 | FileCheck --check-prefix=CHECK-15 %s
+// CHECK-15: "-target-feature" "-altivec"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-qpx -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-NOQPX %s
+// CHECK-NOQPX: "-target-feature" "-qpx"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-qpx -mqpx -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-QPX %s
+// CHECK-QPX-NOT: "-target-feature" "-qpx"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-mfcrf -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-NOMFCRF %s
+// CHECK-NOMFCRF: "-target-feature" "-mfocrf"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-mfcrf -mmfcrf -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-MFCRF %s
+// CHECK-MFCRF: "-target-feature" "+mfocrf"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-popcntd -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-NOPOPCNTD %s
+// CHECK-NOPOPCNTD: "-target-feature" "-popcntd"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-popcntd -mpopcntd -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-POPCNTD %s
+// CHECK-POPCNTD: "-target-feature" "+popcntd"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-fprnd -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-NOFPRND %s
+// CHECK-NOFPRND: "-target-feature" "-fprnd"
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -mno-fprnd -mfprnd -### -o %t.o 2>&1 | FileCheck -check-prefix=CHECK-FPRND %s
+// CHECK-FPRND: "-target-feature" "+fprnd"
+
diff --git a/test/Driver/qa_override.c b/test/Driver/qa_override.c
index 5f96976..f898157 100644
--- a/test/Driver/qa_override.c
+++ b/test/Driver/qa_override.c
@@ -1,6 +1,16 @@
// RUN: env QA_OVERRIDE_GCC3_OPTIONS="#+-Os +-Oz +-O +-O3 +-Oignore +a +b +c xb Xa Omagic ^-ccc-print-options " %clang x -O2 b -O3 2>&1 | FileCheck %s
+// RUN: env QA_OVERRIDE_GCC3_OPTIONS="x-Werror +-mfoo" %clang -Werror %s -c 2>&1 | FileCheck %s -check-prefix=RM-WERROR
+
+// FIXME: It seems doesn't work with gcc-driver.
+// REQUIRES: clang-driver
+
// CHECK-NOT: ###
// CHECK: Option 0 - Name: "-ccc-print-options", Values: {}
// CHECK-NEXT: Option 1 - Name: "<input>", Values: {"x"}
// CHECK-NEXT: Option 2 - Name: "-O", Values: {"ignore"}
// CHECK-NEXT: Option 3 - Name: "-O", Values: {"magic"}
+
+// RM-WERROR: ### QA_OVERRIDE_GCC3_OPTIONS: x-Werror +-mfoo
+// RM-WERROR-NEXT: ### Deleting argument -Werror
+// RM-WERROR-NEXT: ### Adding argument -mfoo at end
+// RM-WERROR-NEXT: warning: argument unused during compilation: '-mfoo'
diff --git a/test/Driver/r600-mcpu.cl b/test/Driver/r600-mcpu.cl
new file mode 100644
index 0000000..70e8116
--- /dev/null
+++ b/test/Driver/r600-mcpu.cl
@@ -0,0 +1,50 @@
+// Check that -mcpu works for all supported GPUs
+
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=r600 %s -o - 2>&1 | FileCheck --check-prefix=R600-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rv610 %s -o - 2>&1 | FileCheck --check-prefix=R600-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rv620 %s -o - 2>&1 | FileCheck --check-prefix=R600-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rv630 %s -o - 2>&1 | FileCheck --check-prefix=R600-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rv635 %s -o - 2>&1 | FileCheck --check-prefix=R600-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rs780 %s -o - 2>&1 | FileCheck --check-prefix=R600-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rs880 %s -o - 2>&1 | FileCheck --check-prefix=R600-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rv670 %s -o - 2>&1 | FileCheck --check-prefix=RV670-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rv710 %s -o - 2>&1 | FileCheck --check-prefix=RV710-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rv730 %s -o - 2>&1 | FileCheck --check-prefix=RV730-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rv740 %s -o - 2>&1 | FileCheck --check-prefix=RV770-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=rv770 %s -o - 2>&1 | FileCheck --check-prefix=RV770-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=palm %s -o - 2>&1 | FileCheck --check-prefix=CEDAR-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=cedar %s -o - 2>&1 | FileCheck --check-prefix=CEDAR-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=sumo %s -o - 2>&1 | FileCheck --check-prefix=REDWOOD-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=sumo2 %s -o - 2>&1 | FileCheck --check-prefix=REDWOOD-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=redwood %s -o - 2>&1 | FileCheck --check-prefix=REDWOOD-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=juniper %s -o - 2>&1 | FileCheck --check-prefix=JUNIPER-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=juniper %s -o - 2>&1 | FileCheck --check-prefix=JUNIPER-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=hemlock %s -o - 2>&1 | FileCheck --check-prefix=CYPRESS-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=cypress %s -o - 2>&1 | FileCheck --check-prefix=CYPRESS-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=barts %s -o - 2>&1 | FileCheck --check-prefix=BARTS-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=turks %s -o - 2>&1 | FileCheck --check-prefix=TURKS-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=caicos %s -o - 2>&1 | FileCheck --check-prefix=CAICOS-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=cayman %s -o - 2>&1 | FileCheck --check-prefix=CAYMAN-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=aruba %s -o - 2>&1 | FileCheck --check-prefix=CAYMAN-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=tahiti %s -o - 2>&1 | FileCheck --check-prefix=TAHITI-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=pitcairn %s -o - 2>&1 | FileCheck --check-prefix=PITCAIRN-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=verde %s -o - 2>&1 | FileCheck --check-prefix=VERDE-CHECK %s
+// RUN: %clang -### -target r600 -x cl -S -emit-llvm -mcpu=oland %s -o - 2>&1 | FileCheck --check-prefix=OLAND-CHECK %s
+
+// R600-CHECK: "-target-cpu" "r600"
+// RV670-CHECK: "-target-cpu" "rv670"
+// RV710-CHECK: "-target-cpu" "rv710"
+// RV730-CHECK: "-target-cpu" "rv730"
+// RV770-CHECK: "-target-cpu" "rv770"
+// CEDAR-CHECK: "-target-cpu" "cedar"
+// REDWOOD-CHECK: "-target-cpu" "redwood"
+// JUNIPER-CHECK: "-target-cpu" "juniper"
+// CYPRESS-CHECK: "-target-cpu" "cypress"
+// BARTS-CHECK: "-target-cpu" "barts"
+// TURKS-CHECK: "-target-cpu" "turks"
+// CAICOS-CHECK: "-target-cpu" "caicos"
+// CAYMAN-CHECK: "-target-cpu" "cayman"
+// TAHITI-CHECK: "-target-cpu" "tahiti"
+// PITCAIRN-CHECK: "-target-cpu" "pitcairn"
+// VERDE-CHECK: "-target-cpu" "verde"
+// OLAND-CHECK: "-target-cpu" "oland"
diff --git a/test/Driver/sanitizer-ld.c b/test/Driver/sanitizer-ld.c
new file mode 100644
index 0000000..fd68b57
--- /dev/null
+++ b/test/Driver/sanitizer-ld.c
@@ -0,0 +1,151 @@
+// Test sanitizers ld flags.
+
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target i386-unknown-linux -fsanitize=address \
+// RUN: -resource-dir=%S/Inputs/resource_dir \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-ASAN-LINUX %s
+//
+// CHECK-ASAN-LINUX: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
+// CHECK-ASAN-LINUX-NOT: "-lc"
+// CHECK-ASAN-LINUX: libclang_rt.asan-i386.a"
+// CHECK-ASAN-LINUX: "-lpthread"
+// CHECK-ASAN-LINUX: "-ldl"
+// CHECK-ASAN-LINUX-NOT: "-export-dynamic"
+// CHECK-ASAN-LINUX: "--dynamic-list={{.*}}libclang_rt.asan-i386.a.syms"
+
+// RUN: %clangxx -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target i386-unknown-linux -fsanitize=address \
+// RUN: -resource-dir=%S/Inputs/empty_resource_dir \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-ASAN-LINUX-CXX %s
+//
+// CHECK-ASAN-LINUX-CXX: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
+// CHECK-ASAN-LINUX-CXX-NOT: "-lc"
+// CHECK-ASAN-LINUX-CXX: "-whole-archive" "{{.*}}libclang_rt.asan-i386.a" "-no-whole-archive"
+// CHECK-ASAN-LINUX-CXX: "-lpthread"
+// CHECK-ASAN-LINUX-CXX: "-ldl"
+// CHECK-ASAN-LINUX-CXX: "-export-dynamic"
+// CHECK-ASAN-LINUX-CXX-NOT: "--dynamic-list"
+// CHECK-ASAN-LINUX-CXX: stdc++
+
+// RUN: %clang -no-canonical-prefixes %s -### -o /dev/null -fsanitize=address \
+// RUN: -target i386-unknown-linux --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: -lstdc++ -static 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-ASAN-LINUX-CXX-STATIC %s
+//
+// CHECK-ASAN-LINUX-CXX-STATIC: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
+// CHECK-ASAN-LINUX-CXX-STATIC-NOT: stdc++
+// CHECK-ASAN-LINUX-CXX-STATIC: "-whole-archive" "{{.*}}libclang_rt.asan-i386.a" "-no-whole-archive"
+// CHECK-ASAN-LINUX-CXX-STATIC: stdc++
+
+// 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-ASAN-ANDROID %s
+//
+// CHECK-ASAN-ANDROID: "{{(.*[^.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
+// CHECK-ASAN-ANDROID-NOT: "-lc"
+// CHECK-ASAN-ANDROID: libclang_rt.asan-arm-android.so"
+// CHECK-ASAN-ANDROID-NOT: "-lpthread"
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target arm-linux-androideabi -fsanitize=address \
+// RUN: --sysroot=%S/Inputs/basic_android_tree/sysroot \
+// RUN: -shared \
+// RUN: | FileCheck --check-prefix=CHECK-ASAN-ANDROID-SHARED %s
+//
+// CHECK-ASAN-ANDROID-SHARED: "{{(.*[^.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
+// CHECK-ASAN-ANDROID-SHARED-NOT: "-lc"
+// CHECK-ASAN-ANDROID-SHARED: libclang_rt.asan-arm-android.so"
+// CHECK-ASAN-ANDROID-SHARED-NOT: "-lpthread"
+
+// RUN: %clangxx -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target x86_64-unknown-linux -lstdc++ -fsanitize=thread \
+// RUN: -resource-dir=%S/Inputs/resource_dir \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-TSAN-LINUX-CXX %s
+//
+// CHECK-TSAN-LINUX-CXX: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
+// CHECK-TSAN-LINUX-CXX-NOT: stdc++
+// CHECK-TSAN-LINUX-CXX: "-whole-archive" "{{.*}}libclang_rt.tsan-x86_64.a" "-no-whole-archive"
+// CHECK-TSAN-LINUX-CXX: "-lpthread"
+// CHECK-TSAN-LINUX-CXX: "-ldl"
+// CHECK-TSAN-LINUX-CXX-NOT: "-export-dynamic"
+// CHECK-TSAN-LINUX-CXX: "--dynamic-list={{.*}}libclang_rt.tsan-x86_64.a.syms"
+// CHECK-TSAN-LINUX-CXX: stdc++
+
+// RUN: %clangxx -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -target x86_64-unknown-linux -lstdc++ -fsanitize=memory \
+// RUN: -resource-dir=%S/Inputs/resource_dir \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-MSAN-LINUX-CXX %s
+//
+// CHECK-MSAN-LINUX-CXX: "{{(.*[^-.0-9A-Z_a-z])?}}ld{{(.exe)?}}"
+// CHECK-MSAN-LINUX-CXX-NOT: stdc++
+// CHECK-MSAN-LINUX-CXX: "-whole-archive" "{{.*}}libclang_rt.msan-x86_64.a" "-no-whole-archive"
+// CHECK-MSAN-LINUX-CXX: "-lpthread"
+// CHECK-MSAN-LINUX-CXX: "-ldl"
+// CHECK-MSAN-LINUX-CXX-NOT: "-export-dynamic"
+// CHECK-MSAN-LINUX-CXX: "--dynamic-list={{.*}}libclang_rt.msan-x86_64.a.syms"
+// CHECK-MSAN-LINUX-CXX: stdc++
+
+// RUN: %clang -fsanitize=undefined %s -### -o %t.o 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-UBSAN-LINUX %s
+// CHECK-UBSAN-LINUX: "{{.*}}ld{{(.exe)?}}"
+// CHECK-UBSAN-LINUX-NOT: libclang_rt.asan
+// CHECK-UBSAN-LINUX: "-whole-archive" "{{.*}}libclang_rt.san-i386.a" "-no-whole-archive"
+// CHECK-UBSAN-LINUX-NOT: libclang_rt.asan
+// CHECK-UBSAN-LINUX: "-whole-archive" "{{.*}}libclang_rt.ubsan-i386.a" "-no-whole-archive"
+// CHECK-UBSAN-LINUX-NOT: libclang_rt.ubsan_cxx
+// CHECK-UBSAN-LINUX: "-lpthread"
+// CHECK-UBSAN-LINUX-NOT: "-lstdc++"
+
+// RUN: %clangxx -fsanitize=undefined %s -### -o %t.o 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-UBSAN-LINUX-CXX %s
+// CHECK-UBSAN-LINUX-CXX: "{{.*}}ld{{(.exe)?}}"
+// CHECK-UBSAN-LINUX-CXX-NOT: libclang_rt.asan
+// CHECK-UBSAN-LINUX-CXX: "-whole-archive" "{{.*}}libclang_rt.san-i386.a" "-no-whole-archive"
+// CHECK-UBSAN-LINUX-CXX-NOT: libclang_rt.asan
+// CHECK-UBSAN-LINUX-CXX: "-whole-archive" "{{.*}}libclang_rt.ubsan-i386.a" "-no-whole-archive"
+// CHECK-UBSAN-LINUX-CXX: "-whole-archive" "{{.*}}libclang_rt.ubsan_cxx-i386.a" "-no-whole-archive"
+// CHECK-UBSAN-LINUX-CXX: "-lpthread"
+// CHECK-UBSAN-LINUX-CXX: "-lstdc++"
+
+// RUN: %clang -fsanitize=address,undefined %s -### -o %t.o 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-ASAN-UBSAN-LINUX %s
+// CHECK-ASAN-UBSAN-LINUX: "{{.*}}ld{{(.exe)?}}"
+// CHECK-ASAN-UBSAN-LINUX-NOT: libclang_rt.san
+// CHECK-ASAN-UBSAN-LINUX: "-whole-archive" "{{.*}}libclang_rt.asan-i386.a" "-no-whole-archive"
+// CHECK-ASAN-UBSAN-LINUX-NOT: libclang_rt.san
+// CHECK-ASAN-UBSAN-LINUX: "-whole-archive" "{{.*}}libclang_rt.ubsan-i386.a" "-no-whole-archive"
+// CHECK-ASAN-UBSAN-LINUX-NOT: libclang_rt.ubsan_cxx
+// CHECK-ASAN-UBSAN-LINUX: "-lpthread"
+// CHECK-ASAN-UBSAN-LINUX-NOT: "-lstdc++"
+
+// RUN: %clangxx -fsanitize=address,undefined %s -### -o %t.o 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: | FileCheck --check-prefix=CHECK-ASAN-UBSAN-LINUX-CXX %s
+// CHECK-ASAN-UBSAN-LINUX-CXX: "{{.*}}ld{{(.exe)?}}"
+// CHECK-ASAN-UBSAN-LINUX-CXX-NOT: libclang_rt.san
+// CHECK-ASAN-UBSAN-LINUX-CXX: "-whole-archive" "{{.*}}libclang_rt.asan-i386.a" "-no-whole-archive"
+// CHECK-ASAN-UBSAN-LINUX-CXX-NOT: libclang_rt.san
+// CHECK-ASAN-UBSAN-LINUX-CXX: "-whole-archive" "{{.*}}libclang_rt.ubsan-i386.a" "-no-whole-archive"
+// CHECK-ASAN-UBSAN-LINUX-CXX: "-whole-archive" "{{.*}}libclang_rt.ubsan_cxx-i386.a" "-no-whole-archive"
+// CHECK-ASAN-UBSAN-LINUX-CXX: "-lpthread"
+// CHECK-ASAN-UBSAN-LINUX-CXX: "-lstdc++"
+
+// RUN: %clang -fsanitize=undefined %s -### -o %t.o 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: --sysroot=%S/Inputs/basic_linux_tree \
+// RUN: -shared \
+// RUN: | FileCheck --check-prefix=CHECK-UBSAN-LINUX-SHARED %s
+// CHECK-UBSAN-LINUX-SHARED: "{{.*}}ld{{(.exe)?}}"
+// CHECK-UBSAN-LINUX-SHARED-NOT: libclang_rt.ubsan-i386.a"
diff --git a/test/Driver/split-debug.c b/test/Driver/split-debug.c
new file mode 100644
index 0000000..d8a9fe8
--- /dev/null
+++ b/test/Driver/split-debug.c
@@ -0,0 +1,25 @@
+// Check that we split debug output properly
+//
+// REQUIRES: asserts
+// RUN: %clang -target x86_64-unknown-linux-gnu -gsplit-dwarf -c -### %s 2> %t
+// RUN: FileCheck -check-prefix=CHECK-ACTIONS < %t %s
+//
+// CHECK-ACTIONS: objcopy{{.*}}--extract-dwo{{.*}}"split-debug.dwo"
+// CHECK-ACTIONS: objcopy{{.*}}--strip-dwo{{.*}}"split-debug.o"
+
+
+// RUN: %clang -target x86_64-macosx -gsplit-dwarf -c -### %s 2> %t
+// RUN: FileCheck -check-prefix=CHECK-NO-ACTIONS < %t %s
+//
+// CHECK-NO-ACTIONS-NOT: -split-dwarf
+
+
+// RUN: %clang -target x86_64-unknown-linux-gnu -gsplit-dwarf -o Bad.x -### %s 2> %t
+// RUN: FileCheck -check-prefix=CHECK-BAD < %t %s
+//
+// CHECK-BAD-NOT: "Bad.dwo"
+
+// RUN: %clang -target x86_64-unknown-linux-gnu -gsplit-dwarf -c -### %s 2> %t
+// RUN: FileCheck -check-prefix=CHECK-OPTION < %t %s
+//
+// CHECK-OPTION: "-split-dwarf-file" "split-debug.dwo"
diff --git a/test/Driver/target-as.s b/test/Driver/target-as.s
new file mode 100644
index 0000000..adb3d10
--- /dev/null
+++ b/test/Driver/target-as.s
@@ -0,0 +1,8 @@
+// REQUIRES: clang-driver
+
+// Make sure the -march is passed down to cc1as.
+// RUN: %clang -target i386-unknown-freebsd -### -c -integrated-as %s \
+// RUN: -march=geode 2>&1 | FileCheck -check-prefix=TARGET %s
+//
+// TARGET: "-cc1as"
+// TARGET: "-target-cpu" "geode"
diff --git a/test/Driver/ubsan-ld.c b/test/Driver/ubsan-ld.c
deleted file mode 100644
index 775e669..0000000
--- a/test/Driver/ubsan-ld.c
+++ /dev/null
@@ -1,10 +0,0 @@
-// 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/unknown-arg.c b/test/Driver/unknown-arg.c
index 5d0f7af..0fab8a5 100644
--- a/test/Driver/unknown-arg.c
+++ b/test/Driver/unknown-arg.c
@@ -1,4 +1,6 @@
-// RUN: not %clang_cc1 %s -cake-is-lie 2> %t.log
+// RUN: not %clang_cc1 %s -cake-is-lie -%0 -%d 2> %t.log
// RUN: FileCheck %s -input-file=%t.log
// CHECK: unknown argument
+// CHECK: unknown argument
+// CHECK: unknown argument
diff --git a/test/Driver/unknown-gcc-arch.c b/test/Driver/unknown-gcc-arch.c
index 5e4746b..dcd17d4 100644
--- a/test/Driver/unknown-gcc-arch.c
+++ b/test/Driver/unknown-gcc-arch.c
@@ -1,8 +1,32 @@
-// RUN: %clang -target x86_64-unknown-unknown -c -x assembler %s -### 2> %t.log
-// RUN: grep '.*gcc.*"-m64"' %t.log
-// RUN: %clang -target x86_64-unknown-unknown -c -x assembler %s -### -m32 2> %t.log
-// RUN: grep '.*gcc.*"-m32"' %t.log
-// RUN: %clang -target i386-unknown-unknown -c -x assembler %s -### 2> %t.log
-// RUN: grep '.*gcc.*"-m32"' %t.log
-// RUN: %clang -target i386-unknown-unknown -c -x assembler %s -### -m64 2> %t.log
-// RUN: grep '.*gcc.*"-m64"' %t.log
+// RUN: %clang -target x86_64-unknown-unknown -c -x assembler %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=X86_64 %s
+// X86_64: {{.*gcc.*-m64}}
+
+// RUN: %clang -target x86_64-unknown-unknown -c -x assembler %s -### -m32 2>&1 \
+// RUN: | FileCheck -check-prefix=X86_64-M32 %s
+// X86_64-M32: {{.*gcc.*-m32}}
+
+// RUN: %clang -target i386-unknown-unknown -c -x assembler %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=I386 %s
+// I386: {{.*gcc.*-m32}}
+
+// RUN: %clang -target i386-unknown-unknown -c -x assembler %s -### -m64 2>&1 \
+// RUN: | FileCheck -check-prefix=I386-M64 %s
+// I386-M64: {{.*gcc.*-m64}}
+
+
+// RUN: %clang -target powerpc64-unknown-unknown -c -x assembler %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=PPC64 %s
+// PPC64: {{.*gcc.*-m64}}
+
+// RUN: %clang -target powerpc64-unknown-unknown -c -x assembler %s -### -m32 2>&1 \
+// RUN: | FileCheck -check-prefix=PPC64-M32 %s
+// PPC64-M32: {{.*gcc.*-m32}}
+
+// RUN: %clang -target powerpc-unknown-unknown -c -x assembler %s -### 2>&1 \
+// RUN: | FileCheck -check-prefix=PPC %s
+// PPC: {{.*gcc.*-m32}}
+
+// RUN: %clang -target powerpc-unknown-unknown -c -x assembler %s -### -m64 2>&1 \
+// RUN: | FileCheck -check-prefix=PPC-M64 %s
+// PPC-M64: {{.*gcc.*-m64}}
diff --git a/test/Driver/visibility.cpp b/test/Driver/visibility.cpp
new file mode 100644
index 0000000..cdbef97
--- /dev/null
+++ b/test/Driver/visibility.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang -### -S -fvisibility=hidden -fvisibility=default %s 2> %t.log
+// RUN: FileCheck -check-prefix=CHECK-1 %s < %t.log
+// CHECK-NOT: "-ftype-visibility"
+// CHECK-1: "-fvisibility" "default"
+// CHECK-NOT: "-ftype-visibility"
+
+// RUN: %clang -### -S -fvisibility=default -fvisibility=hidden %s 2> %t.log
+// RUN: FileCheck -check-prefix=CHECK-2 %s < %t.log
+// CHECK-NOT: "-ftype-visibility"
+// CHECK-2: "-fvisibility" "hidden"
+// CHECK-NOT: "-ftype-visibility"
+
+// RUN: %clang -### -S -fvisibility-ms-compat -fvisibility=hidden %s 2> %t.log
+// RUN: FileCheck -check-prefix=CHECK-3 %s < %t.log
+// CHECK-NOT: "-ftype-visibility"
+// CHECK-3: "-fvisibility" "hidden"
+// CHECK-NOT: "-ftype-visibility"
+
+// RUN: %clang -### -S -fvisibility-ms-compat -fvisibility=default %s 2> %t.log
+// RUN: FileCheck -check-prefix=CHECK-4 %s < %t.log
+// CHECK-NOT: "-ftype-visibility"
+// CHECK-4: "-fvisibility" "default"
+// CHECK-NOT: "-ftype-visibility"
+
+// RUN: %clang -### -S -fvisibility=hidden -fvisibility-ms-compat %s 2> %t.log
+// RUN: FileCheck -check-prefix=CHECK-5 %s < %t.log
+// CHECK-5: "-fvisibility" "hidden"
+// CHECK-5: "-ftype-visibility" "default"
+
+// RUN: %clang -### -S -fvisibility=default -fvisibility-ms-compat %s 2> %t.log
+// RUN: FileCheck -check-prefix=CHECK-6 %s < %t.log
+// CHECK-6: "-fvisibility" "hidden"
+// CHECK-6: "-ftype-visibility" "default"
+
diff --git a/test/Driver/warning-options.cpp b/test/Driver/warning-options.cpp
index cce88e6..f1a335d 100644
--- a/test/Driver/warning-options.cpp
+++ b/test/Driver/warning-options.cpp
@@ -3,13 +3,11 @@
// RUN: %clang -### -Wlarge-by-value-copy=128 %s 2>&1 | FileCheck -check-prefix=LARGE_VALUE_COPY_JOINED %s
// LARGE_VALUE_COPY_JOINED: -Wlarge-by-value-copy=128
-// RUN: %clang -### -c -Wmonkey -Wno-monkey -Wno-unused-command-line-arguments \
-// RUN: -Wno-unused-command-line-argument %s 2>&1 | FileCheck %s
-// 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'
+
+// Check that -isysroot warns on nonexistent paths.
+// RUN: %clang -### -c -target i386-apple-darwin10 -isysroot /FOO %s 2>&1 | FileCheck --check-prefix=CHECK-ISYSROOT %s
+// CHECK-ISYSROOT: warning: no such sysroot directory: '{{([A-Za-z]:.*)?}}/FOO'
diff --git a/test/Driver/warning-options_pedantic.cpp b/test/Driver/warning-options_pedantic.cpp
index c6d11be..e40f771 100644
--- a/test/Driver/warning-options_pedantic.cpp
+++ b/test/Driver/warning-options_pedantic.cpp
@@ -4,4 +4,4 @@
// RUN: %clang -### -pedantic -pedantic -no-pedantic -pedantic %s 2>&1 | FileCheck -check-prefix=PEDANTIC %s
// RUN: %clang -### -pedantic -pedantic -no-pedantic -Wpedantic %s 2>&1 | FileCheck -check-prefix=NO_PEDANTIC %s
// PEDANTIC: -pedantic
-// XFAIL: cygwin,mingw32
+// REQUIRES: clang-driver
diff --git a/test/Driver/x86_64-nacl-defines.cpp b/test/Driver/x86_64-nacl-defines.cpp
index caa9a74..b7c8940 100644
--- a/test/Driver/x86_64-nacl-defines.cpp
+++ b/test/Driver/x86_64-nacl-defines.cpp
@@ -1,4 +1,4 @@
-// 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 -ccc-echo %s -emit-llvm-only -c -o %t.o 2>&1 | FileCheck %s -check-prefix=ECHO
// RUN: %clang -target x86_64-unknown-nacl %s -emit-llvm -S -c -o - | FileCheck %s
// RUN: %clang -target x86_64-unknown-nacl %s -emit-llvm -S -c -pthread -o - | FileCheck %s -check-prefix=THREADS
diff --git a/test/FixIt/auto-isa-fixit.m b/test/FixIt/auto-isa-fixit.m
new file mode 100644
index 0000000..3f22c18
--- /dev/null
+++ b/test/FixIt/auto-isa-fixit.m
@@ -0,0 +1,66 @@
+// RUN: cp %s %t
+// RUN: %clang_cc1 -x objective-c -fixit %t
+// RUN: %clang_cc1 -x objective-c -Werror %t
+// rdar://13503456
+
+void object_setClass(id, id);
+Class object_getClass(id);
+
+id rhs();
+
+Class pr6302(id x123) {
+ x123->isa = 0;
+ x123->isa = rhs();
+ x123->isa = (id)(x123->isa);
+ x123->isa = (id)x123->isa;
+ x123->isa = (x123->isa);
+ x123->isa = (id)(x123->isa);
+ return x123->isa;
+}
+
+
+@interface BaseClass {
+@public
+ Class isa; // expected-note 3 {{instance variable is declared here}}
+}
+@end
+
+@interface OtherClass {
+@public
+ id firstIvar;
+ Class isa; // note, not first ivar;
+}
+@end
+
+@interface Subclass : BaseClass @end
+
+@interface SiblingClass : BaseClass @end
+
+@interface Root @end
+
+@interface hasIsa : Root {
+@public
+ Class isa; // note, isa is not in root class
+}
+@end
+
+@implementation Subclass
+-(void)method {
+ hasIsa *u;
+ id v;
+ BaseClass *w;
+ Subclass *x;
+ SiblingClass *y;
+ OtherClass *z;
+ (void)v->isa;
+ (void)w->isa;
+ (void)x->isa;
+ (void)y->isa;
+ (void)z->isa;
+ (void)u->isa;
+ y->isa = 0;
+ y->isa = w->isa;
+ x->isa = rhs();
+}
+@end
+
diff --git a/test/FixIt/bridge-cast-in-arc.mm b/test/FixIt/bridge-cast-in-arc.mm
new file mode 100644
index 0000000..5cd482f
--- /dev/null
+++ b/test/FixIt/bridge-cast-in-arc.mm
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fdiagnostics-parseable-fixits -x objective-c++ -fobjc-arc %s 2>&1 | FileCheck %s
+// rdar://12788838
+
+id obj;
+
+void Test1() {
+ void *foo = reinterpret_cast<void *>(obj);
+}
+// CHECK: {7:15-7:39}:"(__bridge void *)"
+// CHECK: {7:15-7:39}:"(__bridge_retained void *)"
+
+typedef const void * CFTypeRef;
+extern "C" CFTypeRef CFBridgingRetain(id X);
+
+void Test2() {
+ void *foo = reinterpret_cast<void *>(obj);
+}
+// CHECK: {16:15-16:39}:"(__bridge void *)"
+// CHECK: {16:15-16:39}:"CFBridgingRetain"
diff --git a/test/FixIt/bridge-in-non-arc.m b/test/FixIt/bridge-in-non-arc.m
new file mode 100644
index 0000000..b4d2677
--- /dev/null
+++ b/test/FixIt/bridge-in-non-arc.m
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+
+@interface I
+@end
+
+void foo(void *p) {
+ I *i = (__bridge_transfer I*)p;
+ I *i2 = (__bridge_transfer/*cake*/I*)p;
+}
+
+// CHECK: {7:11-7:29}:""
+// CHECK: {8:12-8:29}:""
diff --git a/test/FixIt/fixit-c90.c b/test/FixIt/fixit-c90.c
index 0bc1fad..5e9d5a1 100644
--- a/test/FixIt/fixit-c90.c
+++ b/test/FixIt/fixit-c90.c
@@ -2,7 +2,7 @@
RUN: %clang_cc1 -std=c90 -pedantic -fixit %t
RUN: %clang_cc1 -pedantic -x c -std=c90 -Werror %t
*/
-/* XPASS: *
+/*
This test passes because clang merely warns for this syntax error even with
-pedantic -Werror -std=c90.
*/
diff --git a/test/FixIt/fixit-cxx0x.cpp b/test/FixIt/fixit-cxx0x.cpp
index a173ce4..1f6275f 100644
--- a/test/FixIt/fixit-cxx0x.cpp
+++ b/test/FixIt/fixit-cxx0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -std=c++11 %s
+// RUN: %clang_cc1 -verify -std=c++11 -Wno-anonymous-pack-parens %s
// RUN: cp %s %t
// RUN: not %clang_cc1 -x c++ -std=c++11 -fixit %t
// RUN: %clang_cc1 -Wall -pedantic -x c++ -std=c++11 %t
@@ -120,3 +120,15 @@ namespace MissingSemi {
struct d // expected-error {{expected ';' after struct}}
}
}
+
+namespace NonStaticConstexpr {
+ struct foo {
+ constexpr int i; // expected-error {{non-static data member cannot be constexpr; did you intend to make it const?}}
+ constexpr int j = 7; // expected-error {{non-static data member cannot be constexpr; did you intend to make it static?}}
+ foo() : i(3) {
+ }
+ static int get_j() {
+ return j;
+ }
+ };
+}
diff --git a/test/FixIt/fixit-cxx11-attributes.cpp b/test/FixIt/fixit-cxx11-attributes.cpp
new file mode 100644
index 0000000..f28bdfc
--- /dev/null
+++ b/test/FixIt/fixit-cxx11-attributes.cpp
@@ -0,0 +1,51 @@
+// RUN: %clang_cc1 -verify -std=c++11 %s
+// RUN: cp %s %t
+// RUN: not %clang_cc1 -x c++ -std=c++11 -fixit %t
+// RUN: %clang_cc1 -Wall -pedantic -x c++ -std=c++11 %t
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+
+namespace ClassSpecifier {
+ class [[]] [[]]
+ attr_after_class_name_decl [[]] [[]]; // expected-error {{an attribute list cannot appear here}}
+ // CHECK: fix-it:{{.*}}:{9:5-9:5}
+ // CHECK: fix-it:{{.*}}:{9:32-9:41}
+
+ class [[]] [[]]
+ attr_after_class_name_definition [[]] [[]] [[]]{}; // expected-error {{an attribute list cannot appear here}}
+ // CHECK: fix-it:{{.*}}:{14:4-14:4}
+ // CHECK: fix-it:{{.*}}:{14:37-14:51}
+
+ class base {};
+ class [[]] [[]] final_class
+ alignas(float) [[]] final // expected-error {{an attribute list cannot appear here}}
+ alignas(float) [[]] [[]] alignas(float): base{}; // expected-error {{an attribute list cannot appear here}}
+ // CHECK: fix-it:{{.*}}:{19:19-19:19}
+ // CHECK: fix-it:{{.*}}:{20:5-20:25}
+ // CHECK: fix-it:{{.*}}:{19:19-19:19}
+ // CHECK: fix-it:{{.*}}:{21:5-21:44}
+
+ class [[]] [[]] final_class_another
+ [[]] [[]] alignas(16) final // expected-error {{an attribute list cannot appear here}}
+ [[]] [[]] alignas(16) [[]]{}; // expected-error {{an attribute list cannot appear here}}
+ // CHECK: fix-it:{{.*}}:{27:19-27:19}
+ // CHECK: fix-it:{{.*}}:{28:5-28:27}
+ // CHECK: fix-it:{{.*}}:{27:19-27:19}
+ // CHECK: fix-it:{{.*}}:{29:5-29:31}
+}
+
+namespace BaseSpecifier {
+ struct base1 {};
+ struct base2 {};
+ class with_base_spec : public [[a]] // expected-error {{an attribute list cannot appear here}} expected-warning {{unknown}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:26-[[@LINE-1]]:26}:"[{{\[}}a]]"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:33-[[@LINE-2]]:39}:""
+ virtual [[b]] base1, // expected-error {{an attribute list cannot appear here}} expected-warning {{unknown}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:26-[[@LINE-4]]:26}:"[{{\[}}b]]"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:34-[[@LINE-2]]:40}:""
+ virtual [[c]] // expected-error {{an attribute list cannot appear here}} expected-warning {{unknown}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:26-[[@LINE-1]]:26}:"[{{\[}}c]]"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:34-[[@LINE-2]]:40}:""
+ public [[d]] base2 {}; // expected-error {{an attribute list cannot appear here}} expected-warning {{unknown}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:26-[[@LINE-4]]:26}:"[{{\[}}d]]"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:33-[[@LINE-2]]:39}:""
+}
diff --git a/test/FixIt/fixit-errors-1.c b/test/FixIt/fixit-errors-1.c
index 96f27eb..b034b19 100644
--- a/test/FixIt/fixit-errors-1.c
+++ b/test/FixIt/fixit-errors-1.c
@@ -1,7 +1,6 @@
// RUN: cp %s %t
// RUN: %clang_cc1 -pedantic -fixit %t
// RUN: echo %clang_cc1 -pedantic -Werror -x c %t
-/* XPASS: * */
/* This is a test of the various code modification hints that are
provided as part of warning or extension diagnostics. All of the
diff --git a/test/FixIt/fixit-errors.c b/test/FixIt/fixit-errors.c
index 356e862..c425fc8 100644
--- a/test/FixIt/fixit-errors.c
+++ b/test/FixIt/fixit-errors.c
@@ -1,7 +1,7 @@
+// RUN: %clang_cc1 -fsyntax-only -pedantic -verify %s
// RUN: cp %s %t
-// RUN: %clang_cc1 -pedantic -verify -fixit -x c %t
+// RUN: not %clang_cc1 -pedantic -fixit -x c %t
// RUN: %clang_cc1 -pedantic -Werror -x c %t
-// XFAIL: *
/* This is a test of the various code modification hints that are
provided as part of warning or extension diagnostics. All of the
@@ -19,5 +19,5 @@ struct Point {
struct Point *get_origin();
void test_point() {
- (void)get_origin->x;
+ (void)get_origin->x; // expected-error {{base of member reference is a function; perhaps you meant to call it with no arguments?}}
}
diff --git a/test/FixIt/fixit-newline-style.c b/test/FixIt/fixit-newline-style.c
new file mode 100644
index 0000000..c43eb37
--- /dev/null
+++ b/test/FixIt/fixit-newline-style.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -pedantic -Wunused-label -x c %s 2>&1 | FileCheck %s -strict-whitespace
+
+// This file intentionally uses a CRLF newline style
+// <rdar://problem/12639047>
+// CHECK: warning: unused label 'ddd'
+// CHECK-NEXT: {{^ ddd:}}
+// CHECK-NEXT: {{^ \^~~~$}}
+void f() {
+ ddd:
+ ;
+}
diff --git a/test/FixIt/fixit-nsstring-compare.m b/test/FixIt/fixit-nsstring-compare.m
new file mode 100644
index 0000000..6f0877c
--- /dev/null
+++ b/test/FixIt/fixit-nsstring-compare.m
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fdiagnostics-parseable-fixits -x objective-c %s 2>&1 | FileCheck %s
+// rdar://12716301
+
+typedef unsigned char BOOL;
+
+@protocol NSObject
+- (BOOL)isEqual:(id)object;
+@end
+
+@interface NSString<NSObject>
+@end
+
+int main() {
+ NSString *stringA = @"stringA";
+
+ BOOL comparison = stringA==@"stringB";
+
+}
+
+// CHECK: {16:21-16:21}:"["
+// CHECK: {16:28-16:30}:" isEqual:"
+// CHECK: {16:40-16:40}:"]"
diff --git a/test/FixIt/fixit-objc.m b/test/FixIt/fixit-objc.m
index 77099fc..ea57fe6 100644
--- a/test/FixIt/fixit-objc.m
+++ b/test/FixIt/fixit-objc.m
@@ -11,7 +11,7 @@
@protocol X;
void foo() {
- <X> *P; // expected-warning{{protocol qualifiers without 'id' is archaic}}
+ <X> *P; // expected-warning{{protocol has no object type specified; defaults to qualified 'id'}}
}
@class A;
diff --git a/test/FixIt/fixit-unicode.c b/test/FixIt/fixit-unicode.c
index 2af5e08..9c0242e 100644
--- a/test/FixIt/fixit-unicode.c
+++ b/test/FixIt/fixit-unicode.c
@@ -8,13 +8,16 @@ struct Foo {
// PR13312
void test1() {
struct Foo foo;
- (&foo)☃>bar = 42;
+ foo.bar = 42☃
+// CHECK: error: non-ASCII characters are not allowed outside of literals and identifiers
+// CHECK: {{^ \^}}
// CHECK: error: expected ';' after expression
// Make sure we emit the fixit right in front of the snowman.
-// CHECK: {{^ \^}}
-// CHECK: {{^ ;}}
+// CHECK: {{^ \^}}
+// CHECK: {{^ ;}}
-// CHECK-MACHINE: fix-it:"{{.*}}fixit-unicode.c":{11:9-11:9}:";"
+// CHECK-MACHINE: fix-it:"{{.*}}fixit-unicode.c":{[[@LINE-8]]:15-[[@LINE-8]]:18}:""
+// CHECK-MACHINE: fix-it:"{{.*}}fixit-unicode.c":{[[@LINE-9]]:15-[[@LINE-9]]:15}:";"
}
@@ -29,5 +32,5 @@ void test2() {
// because different systems will render the delta differently (either as a
// character, or as <U+2206>.) The fixit should line up with the %d regardless.
-// CHECK-MACHINE: fix-it:"{{.*}}fixit-unicode.c":{23:16-23:18}:"%ld"
+// CHECK-MACHINE: fix-it:"{{.*}}fixit-unicode.c":{[[@LINE-9]]:16-[[@LINE-9]]:18}:"%ld"
}
diff --git a/test/FixIt/fixit.cpp b/test/FixIt/fixit.cpp
index 253abd0..fca596b 100644
--- a/test/FixIt/fixit.cpp
+++ b/test/FixIt/fixit.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -pedantic -Wall -Wno-comment -verify -fcxx-exceptions -x c++ %s
+// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -x c++ %s 2>&1 | FileCheck %s
// RUN: cp %s %t
// RUN: not %clang_cc1 -pedantic -Wall -Wno-comment -fcxx-exceptions -fixit -x c++ %t
// RUN: %clang_cc1 -fsyntax-only -pedantic -Wall -Werror -Wno-comment -fcxx-exceptions -x c++ %t
@@ -299,3 +300,10 @@ class foo {
}
int i();
};
+
+namespace dtor_fixit {
+ class foo {
+ ~bar() { } // expected-error {{expected the class name after '~' to name a destructor}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:6-[[@LINE-1]]:9}:"foo"
+ };
+}
diff --git a/test/FixIt/format-darwin.m b/test/FixIt/format-darwin.m
index 1bfe272..f520564 100644
--- a/test/FixIt/format-darwin.m
+++ b/test/FixIt/format-darwin.m
@@ -23,6 +23,8 @@ typedef long SInt32;
typedef unsigned long UInt32;
#endif
+typedef SInt32 OSStatus;
+
NSInteger getNSInteger();
NSUInteger getNSUInteger();
SInt32 getSInt32();
@@ -34,17 +36,17 @@ void testCorrectionInAllCases() {
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:"{{.*}}":{[[@LINE-5]]:11-[[@LINE-5]]:13}:"%ld"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-6]]:16-[[@LINE-6]]:16}:"(long)"
- // CHECK: fix-it:"{{.*}}":{33:11-33:13}:"%lu"
- // CHECK: fix-it:"{{.*}}":{33:16-33:16}:"(unsigned long)"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:11-[[@LINE-7]]:13}:"%lu"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-8]]:16-[[@LINE-8]]:16}:"(unsigned long)"
- // CHECK: fix-it:"{{.*}}":{34:11-34:13}:"%d"
- // CHECK: fix-it:"{{.*}}":{34:16-34:16}:"(int)"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-9]]:11-[[@LINE-9]]:13}:"%d"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-10]]:16-[[@LINE-10]]:16}:"(int)"
- // CHECK: fix-it:"{{.*}}":{35:11-35:13}:"%u"
- // CHECK: fix-it:"{{.*}}":{35:16-35:16}:"(unsigned int)"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-11]]:11-[[@LINE-11]]:13}:"%u"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-12]]:16-[[@LINE-12]]:16}:"(unsigned int)"
}
@interface Foo {
@@ -65,7 +67,7 @@ void testParens(Foo *obj, struct Bar *record) {
NSInteger arr[4] = {0};
NSInteger i = 0;
- // These cases match the cases in CheckPrintfHandler::checkFormatExpr.
+ // These cases match the relevant 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}}
@@ -80,9 +82,9 @@ void testParens(Foo *obj, struct Bar *record) {
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}:")"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:11-[[@LINE-2]]:13}:"%ld"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:16-[[@LINE-3]]:16}:"(long)("
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:25-[[@LINE-4]]:25}:")"
}
@@ -94,28 +96,38 @@ void testWarn() {
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:"{{.*}}":{[[@LINE-5]]:11-[[@LINE-5]]:13}:"%ld"
+ // CHECK-64: fix-it:"{{.*}}":{[[@LINE-6]]:16-[[@LINE-6]]: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:"{{.*}}":{[[@LINE-7]]:11-[[@LINE-7]]:13}:"%lu"
+ // CHECK-64: fix-it:"{{.*}}":{[[@LINE-8]]:16-[[@LINE-8]]: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:"{{.*}}":{[[@LINE-9]]:11-[[@LINE-9]]:14}:"%d"
+ // CHECK-64: fix-it:"{{.*}}":{[[@LINE-10]]:17-[[@LINE-10]]:17}:"(int)"
- // CHECK-64: fix-it:"{{.*}}":{95:11-95:14}:"%u"
- // CHECK-64: fix-it:"{{.*}}":{95:17-95:17}:"(unsigned int)"
+ // CHECK-64: fix-it:"{{.*}}":{[[@LINE-11]]:11-[[@LINE-11]]:14}:"%u"
+ // CHECK-64: fix-it:"{{.*}}":{[[@LINE-12]]:17-[[@LINE-12]]: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:"{{.*}}":{[[@LINE-3]]:11-[[@LINE-3]]:13}:"%lx"
+ // CHECK-64: fix-it:"{{.*}}":{[[@LINE-4]]:16-[[@LINE-4]]:16}:"(long)"
+
+ // CHECK-64: fix-it:"{{.*}}":{[[@LINE-5]]:11-[[@LINE-5]]:13}:"%lx"
+ // CHECK-64: fix-it:"{{.*}}":{[[@LINE-6]]:16-[[@LINE-6]]:16}:"(unsigned long)"
+}
+
+void testSignedness(NSInteger i, NSUInteger u) {
+ printf("%d", u); // expected-warning{{values of type 'NSUInteger' should not be used as format arguments; add an explicit cast to 'unsigned long' instead}}
+ printf("%i", u); // expected-warning{{values of type 'NSUInteger' should not be used as format arguments; add an explicit cast to 'unsigned long' instead}}
+ printf("%u", i); // expected-warning{{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}}
- // CHECK-64: fix-it:"{{.*}}":{112:11-112:13}:"%lx"
- // CHECK-64: fix-it:"{{.*}}":{112:16-112:16}:"(unsigned long)"
+ // CHECK-64: fix-it:"{{.*}}":{[[@LINE-4]]:11-[[@LINE-4]]:13}:"%lu"
+ // CHECK-64: fix-it:"{{.*}}":{[[@LINE-4]]:11-[[@LINE-4]]:13}:"%lu"
+ // CHECK-64: fix-it:"{{.*}}":{[[@LINE-4]]:11-[[@LINE-4]]:13}:"%ld"
}
void testNoWarn() {
@@ -133,22 +145,18 @@ void testWarn() {
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)"
+ // CHECK-32: fix-it:"{{.*}}":{[[@LINE-5]]:17-[[@LINE-5]]:17}:"(long)"
+ // CHECK-32: fix-it:"{{.*}}":{[[@LINE-5]]:17-[[@LINE-5]]:17}:"(unsigned long)"
+ // CHECK-32: fix-it:"{{.*}}":{[[@LINE-5]]:16-[[@LINE-5]]:16}:"(int)"
+ // CHECK-32: fix-it:"{{.*}}":{[[@LINE-5]]:16-[[@LINE-5]]: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)"
+ // CHECK-32: fix-it:"{{.*}}":{[[@LINE-3]]:17-[[@LINE-3]]:17}:"(long)"
+ // CHECK-32: fix-it:"{{.*}}":{[[@LINE-3]]:17-[[@LINE-3]]:17}:"(unsigned long)"
}
void testNoWarn() {
@@ -158,6 +166,14 @@ void testNoWarn() {
printf("%lu", getUInt32()); // no-warning
}
+void testSignedness(NSInteger i, NSUInteger u) {
+ // It is valid to use a specifier with the opposite signedness as long as
+ // the type is correct.
+ printf("%d", u); // no-warning
+ printf("%i", u); // no-warning
+ printf("%u", i); // no-warning
+}
+
#endif
@@ -167,17 +183,17 @@ void testCasts() {
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:"{{.*}}":{[[@LINE-5]]:11-[[@LINE-5]]:13}:"%ld"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-6]]:16-[[@LINE-6]]:27}:"(long)"
- // CHECK: fix-it:"{{.*}}":{166:11-166:13}:"%lu"
- // CHECK: fix-it:"{{.*}}":{166:16-166:28}:"(unsigned long)"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-7]]:11-[[@LINE-7]]:13}:"%lu"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-8]]:16-[[@LINE-8]]:28}:"(unsigned long)"
- // CHECK: fix-it:"{{.*}}":{167:11-167:13}:"%d"
- // CHECK: fix-it:"{{.*}}":{167:16-167:24}:"(int)"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-9]]:11-[[@LINE-9]]:13}:"%d"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-10]]:16-[[@LINE-10]]:24}:"(int)"
- // CHECK: fix-it:"{{.*}}":{168:11-168:13}:"%u"
- // CHECK: fix-it:"{{.*}}":{168:16-168:24}:"(unsigned int)"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-11]]:11-[[@LINE-11]]:13}:"%u"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-12]]:16-[[@LINE-12]]:24}:"(unsigned int)"
}
void testCapitals() {
@@ -185,14 +201,20 @@ void testCapitals() {
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"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:12-[[@LINE-4]]:13}:"d"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:12-[[@LINE-4]]:13}:"u"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:12-[[@LINE-4]]: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"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:13-[[@LINE-3]]:14}:"d"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:11-[[@LINE-4]]:14}:"%D"
}
+
+void testLayeredTypedefs(OSStatus i) {
+ printf("%s", i); // expected-warning {{values of type 'OSStatus' should not be used as format arguments}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%d"
+}
+
diff --git a/test/FixIt/format.m b/test/FixIt/format.m
index c474701..919212b 100644
--- a/test/FixIt/format.m
+++ b/test/FixIt/format.m
@@ -93,3 +93,138 @@ void test_named_fixed_enum_correction(enum SomeSize x) {
// CHECK: fix-it:"{{.*}}":{92:11-92:13}:"%zu"
}
+
+typedef unsigned char uint8_t;
+void test_char(char c, signed char s, unsigned char u, uint8_t n) {
+ NSLog(@"%s", c); // expected-warning{{format specifies type 'char *' but the argument has type 'char'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%c"
+
+ NSLog(@"%lf", c); // expected-warning{{format specifies type 'double' but the argument has type 'char'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:14}:"%c"
+
+ NSLog(@"%@", c); // expected-warning{{format specifies type 'id' but the argument has type 'char'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%c"
+
+ NSLog(@"%c", c); // no-warning
+ // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%c"
+
+
+ NSLog(@"%s", s); // expected-warning{{format specifies type 'char *' but the argument has type 'signed char'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%c"
+
+ NSLog(@"%lf", s); // expected-warning{{format specifies type 'double' but the argument has type 'signed char'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:14}:"%c"
+
+ NSLog(@"%@", s); // expected-warning{{format specifies type 'id' but the argument has type 'signed char'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%c"
+
+ NSLog(@"%c", s); // no-warning
+ // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%c"
+
+
+ NSLog(@"%s", u); // expected-warning{{format specifies type 'char *' but the argument has type 'unsigned char'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%c"
+
+ NSLog(@"%lf", u); // expected-warning{{format specifies type 'double' but the argument has type 'unsigned char'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:14}:"%c"
+
+ NSLog(@"%@", u); // expected-warning{{format specifies type 'id' but the argument has type 'unsigned char'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%c"
+
+ NSLog(@"%c", u); // no-warning
+ // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%c"
+
+
+ NSLog(@"%s", n); // expected-warning{{format specifies type 'char *' but the argument has type 'uint8_t' (aka 'unsigned char')}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%hhu"
+
+ NSLog(@"%lf", n); // expected-warning{{format specifies type 'double' but the argument has type 'uint8_t' (aka 'unsigned char')}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:14}:"%hhu"
+
+ NSLog(@"%@", n); // expected-warning{{format specifies type 'id' but the argument has type 'uint8_t' (aka 'unsigned char')}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%hhu"
+
+ NSLog(@"%c", n); // no-warning
+ // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%hhu"
+
+
+ NSLog(@"%s", 'a'); // expected-warning{{format specifies type 'char *' but the argument has type 'char'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%c"
+
+ NSLog(@"%lf", 'a'); // expected-warning{{format specifies type 'double' but the argument has type 'char'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:14}:"%c"
+
+ NSLog(@"%@", 'a'); // expected-warning{{format specifies type 'id' but the argument has type 'char'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%c"
+
+ NSLog(@"%c", 'a'); // no-warning
+ // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%c"
+
+
+ NSLog(@"%s", 'abcd'); // expected-warning{{format specifies type 'char *' but the argument has type 'int'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%d"
+
+ NSLog(@"%lf", 'abcd'); // expected-warning{{format specifies type 'double' but the argument has type 'int'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:14}:"%d"
+
+ NSLog(@"%@", 'abcd'); // expected-warning{{format specifies type 'id' but the argument has type 'int'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%d"
+}
+
+void multichar_constants_false_negative() {
+ // The value of a multi-character constant is implementation-defined, but
+ // almost certainly shouldn't be printed with %c. However, the current
+ // type-checker expects %c to correspond to an integer argument, because
+ // many C library functions like fgetc() actually return an int (using -1
+ // as a sentinel).
+ NSLog(@"%c", 'abcd'); // missing-warning{{format specifies type 'char' but the argument has type 'int'}}
+ // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%d"
+}
+
+
+void test_percent_C() {
+ const unsigned short data = 'a';
+ NSLog(@"%C", data); // no-warning
+
+ NSLog(@"%C", 0x2603); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'int'}}
+ // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%d"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:16-[[@LINE-2]]:16}:"(unsigned short)"
+
+ typedef unsigned short unichar;
+
+ NSLog(@"%C", 0x2603); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'int'}}
+ // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%d"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:16-[[@LINE-2]]:16}:"(unichar)"
+
+ NSLog(@"%C", data ? 0x2F : 0x2603); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'int'}}
+ // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%d"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:16-[[@LINE-2]]:16}:"(unichar)("
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:36-[[@LINE-3]]:36}:")"
+
+ NSLog(@"%C", 0.0); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'double'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%f"
+ // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:16-[[@LINE-2]]:16}:"(unichar)"
+
+ NSLog(@"%C", (char)0x2603); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'char'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%c"
+ // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:16-[[@LINE-2]]:22}:"(unichar)"
+
+ NSLog(@"%C", 'a'); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'char'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%c"
+ // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:16-[[@LINE-2]]:22}:"(unichar)"
+}
+
+
+void testSignedness(long i, unsigned long u) {
+ printf("%d", u); // expected-warning{{format specifies type 'int' but the argument has type 'unsigned long'}}
+ printf("%i", u); // expected-warning{{format specifies type 'int' but the argument has type 'unsigned long'}}
+ printf("%u", i); // expected-warning{{format specifies type 'unsigned int' but the argument has type 'long'}}
+
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:11-[[@LINE-4]]:13}:"%lu"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:11-[[@LINE-4]]:13}:"%lu"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:11-[[@LINE-4]]:13}:"%ld"
+
+ printf("%+d", u); // expected-warning{{format specifies type 'int' but the argument has type 'unsigned long'}}
+
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:11-[[@LINE-2]]:14}:"%+ld"
+}
diff --git a/test/FixIt/format.mm b/test/FixIt/format.mm
new file mode 100644
index 0000000..64c6c47
--- /dev/null
+++ b/test/FixIt/format.mm
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -fsyntax-only -fblocks -verify %s
+// RUN: %clang_cc1 -fdiagnostics-parseable-fixits -fblocks %s 2>&1 | FileCheck %s
+
+extern "C" void NSLog(id, ...);
+
+void test_percent_C() {
+ const unsigned short data = 'a';
+ NSLog(@"%C", data); // no-warning
+
+ const wchar_t wchar_data = L'a';
+ NSLog(@"%C", wchar_data); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'wchar_t'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:16-[[@LINE-1]]:16}:"(unsigned short)"
+
+ NSLog(@"%C", 0x2603); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'int'}}
+ // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%d"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:16-[[@LINE-2]]:16}:"(unsigned short)"
+
+ typedef unsigned short unichar;
+
+ NSLog(@"%C", wchar_data); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'wchar_t'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:16-[[@LINE-1]]:16}:"(unichar)"
+
+ NSLog(@"%C", 0x2603); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'int'}}
+ // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%d"
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:16-[[@LINE-2]]:16}:"(unichar)"
+
+ NSLog(@"%C", 0.0); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'double'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:11-[[@LINE-1]]:13}:"%f"
+ // CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-2]]:16-[[@LINE-2]]:16}:"(unichar)"
+}
diff --git a/test/FixIt/typo.c b/test/FixIt/typo.c
index 0bafd1b..8e380c9 100644
--- a/test/FixIt/typo.c
+++ b/test/FixIt/typo.c
@@ -1,8 +1,9 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
// RUN: cp %s %t
// RUN: not %clang_cc1 -fsyntax-only -fixit -x c %t
// RUN: %clang_cc1 -fsyntax-only -pedantic -Werror -x c %t
-// RUN: grep "Rectangle" %t
+
struct Point {
float x, y;
};
@@ -21,17 +22,24 @@ struct Window {
struct Window window = {
.bunds. // expected-error{{field designator 'bunds' does not refer to any field in type 'struct Window'; did you mean 'bounds'?}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:4-[[@LINE-1]]:9}:"bounds"
+
topleft.x = 3.14, // expected-error{{field designator 'topleft' does not refer to any field in type 'struct Rectangle'; did you mean 'top_left'?}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:10}:"top_left"
2.71818, 5.0, 6.0, Red
};
void test() {
Rectangle r1; // expected-error{{must use 'struct' tag to refer to type 'Rectangle'}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:3}:"struct "
r1.top_left.x = 0;
typedef struct Rectangle Rectangle; // expected-note{{'Rectangle' declared here}}
rectangle *r2 = &r1; // expected-error{{unknown type name 'rectangle'; did you mean 'Rectangle'?}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:12}:"Rectangle"
+
r2->top_left.y = 0;
unsinged *ptr = 0; // expected-error{{use of undeclared identifier 'unsinged'; did you mean 'unsigned'?}}
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:11}:"unsigned"
*ptr = 17;
}
diff --git a/test/Format/basic.cpp b/test/Format/basic.cpp
new file mode 100644
index 0000000..375bbd2
--- /dev/null
+++ b/test/Format/basic.cpp
@@ -0,0 +1,6 @@
+// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
+// RUN: clang-format -i %t.cpp
+// RUN: FileCheck -strict-whitespace -input-file=%t.cpp %s
+
+// CHECK: {{^int\ \*i;}}
+ int * i ;
diff --git a/test/Format/diagnostic.cpp b/test/Format/diagnostic.cpp
new file mode 100644
index 0000000..2e930ee
--- /dev/null
+++ b/test/Format/diagnostic.cpp
@@ -0,0 +1,4 @@
+// RUN: clang-format 2>&1 >/dev/null %s |FileCheck %s
+
+}
+// CHECK: diagnostic.cpp:[[@LINE-1]]:1: error: unexpected '}'
diff --git a/test/Format/ranges.cpp b/test/Format/ranges.cpp
new file mode 100644
index 0000000..0244fc1
--- /dev/null
+++ b/test/Format/ranges.cpp
@@ -0,0 +1,11 @@
+// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
+// RUN: clang-format -offset=2 -length=0 -offset=28 -length=0 -i %t.cpp
+// RUN: FileCheck -strict-whitespace -input-file=%t.cpp %s
+// CHECK: {{^int\ \*i;$}}
+ int*i;
+
+// CHECK: {{^\ \ int\ \ \*\ \ i;$}}
+ int * i;
+
+// CHECK: {{^\ \ int\ \*i;$}}
+ int * i;
diff --git a/test/Frontend/ast-main.cpp b/test/Frontend/ast-main.cpp
new file mode 100644
index 0000000..4bddbe1
--- /dev/null
+++ b/test/Frontend/ast-main.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang -emit-llvm -S -o %t1.ll -x c++ - < %s
+// RUN: %clang -fno-delayed-template-parsing -emit-ast -o %t.ast %s
+// RUN: %clang -emit-llvm -S -o %t2.ll -x ast - < %t.ast
+// RUN: diff %t1.ll %t2.ll
+
+// http://llvm.org/bugs/show_bug.cgi?id=15377
+template<typename T>
+struct S {
+ T *mf();
+};
+template<typename T>
+T *S<T>::mf() {
+ // warning: control reaches end of non-void function [-Wreturn-type]
+}
+
+void f() {
+ S<int>().mf();
+}
+
+int main() {
+ return 0;
+}
diff --git a/test/Frontend/dependency-gen-escaping.c b/test/Frontend/dependency-gen-escaping.c
new file mode 100644
index 0000000..84eb242
--- /dev/null
+++ b/test/Frontend/dependency-gen-escaping.c
@@ -0,0 +1,17 @@
+// REQUIRES: shell
+// PR15642
+// RUN: rm -rf %t.dir
+// RUN: mkdir -p %t.dir
+// RUN: echo > '%t.dir/ .h'
+// RUN: echo > '%t.dir/$$.h'
+// RUN: echo > '%t.dir/##.h'
+// RUN: cd %t.dir
+// RUN: %clang -MD -MF - %s -fsyntax-only -I. | FileCheck -strict-whitespace %s
+
+// CHECK: \ \ \ \ .h
+// CHECK: $$$$.h
+// CHECK: \#\#.h
+
+#include " .h"
+#include "$$.h"
+#include "##.h"
diff --git a/test/Frontend/hexagon-target-basic.c b/test/Frontend/hexagon-target-basic.c
new file mode 100644
index 0000000..5f95fa2
--- /dev/null
+++ b/test/Frontend/hexagon-target-basic.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -emit-llvm -triple hexagon-unknown-unknown %s -S -o /dev/null
+// REQUIRES: hexagon-registered-target
+
+// Testcase for bug 14744. Empty file is sufficient, since the problem
+// was a bad data layout string in the Hexagon target causing an ICE
+// when compiling any Hexagon program.
+
+int x; // In C99, a translation unit needs to have at least one declaration.
+
diff --git a/test/Frontend/warning-options.cpp b/test/Frontend/warning-options.cpp
new file mode 100644
index 0000000..85bea62
--- /dev/null
+++ b/test/Frontend/warning-options.cpp
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -Wmonkey -Wno-monkey -Wno-unused-command-line-arguments \
+// RUN: -Wno-unused-command-line-argument %s 2>&1 | FileCheck %s
+// 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'?
diff --git a/test/Headers/c11.c b/test/Headers/c11.c
new file mode 100644
index 0000000..f65164d1
--- /dev/null
+++ b/test/Headers/c11.c
@@ -0,0 +1,19 @@
+// RUN: %clang -fsyntax-only -Xclang -verify -std=c11 %s
+// RUN: %clang -fsyntax-only -Xclang -verify -std=c11 -fmodules %s
+
+noreturn int f(); // expected-error 1+{{}}
+
+#include <stdnoreturn.h>
+#include <stdnoreturn.h>
+#include <stdnoreturn.h>
+
+int g();
+noreturn int g();
+int noreturn g();
+int g();
+
+#include <stdalign.h>
+_Static_assert(__alignas_is_defined, "");
+_Static_assert(__alignof_is_defined, "");
+alignas(alignof(int)) char c[4];
+_Static_assert(__alignof(c) == 4, "");
diff --git a/test/Headers/cxx11.cpp b/test/Headers/cxx11.cpp
new file mode 100644
index 0000000..41bdc76
--- /dev/null
+++ b/test/Headers/cxx11.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang -fsyntax-only -std=c++11 %s
+// RUN: %clang -fsyntax-only -std=c++11 -fmodules %s
+
+#include <stdalign.h>
+
+#if defined alignas
+#error alignas should not be defined in C++
+#endif
+
+#if defined alignof
+#error alignof should not be defined in C++
+#endif
+
+static_assert(__alignas_is_defined, "");
+static_assert(__alignof_is_defined, "");
diff --git a/test/Headers/stdbool.cpp b/test/Headers/stdbool.cpp
index a252cca..7c927db 100644
--- a/test/Headers/stdbool.cpp
+++ b/test/Headers/stdbool.cpp
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -E -dM %s | FileCheck --check-prefix=CHECK-GNU-COMPAT %s
// RUN: %clang_cc1 -std=c++98 -E -dM %s | FileCheck --check-prefix=CHECK-CONFORMING %s
+// RUN: %clang_cc1 -fsyntax-only -std=gnu++98 -verify -Weverything %s
#include <stdbool.h>
#define zzz
@@ -12,3 +13,7 @@
// CHECK-CONFORMING: #define __CHAR_BIT__
// CHECK-CONFORMING-NOT: #define false false
// CHECK-CONFORMING: #define zzz
+
+zzz
+// expected-no-diagnostics
+extern bool x;
diff --git a/test/Index/IBOutletCollection.m b/test/Index/IBOutletCollection.m
index a95df86..1b5d62c 100644
--- a/test/Index/IBOutletCollection.m
+++ b/test/Index/IBOutletCollection.m
@@ -10,9 +10,11 @@
// RUN: c-index-test -test-annotate-tokens=%s:4:1:5:1 %s | FileCheck -check-prefix=CHECK-TOK %s
// CHECK-TOK: Identifier: "IBOutletCollection" [4:3 - 4:21] macro expansion=IBOutletCollection:1:9
-// CHECK-TOK: Punctuation: "(" [4:21 - 4:22] ObjCInterfaceDecl=Test:3:12
+// FIXME: The following token should belong to the macro expansion cursor.
+// CHECK-TOK: Punctuation: "(" [4:21 - 4:22] attribute(iboutletcollection)= [IBOutletCollection=ObjCInterface]
// CHECK-TOK: Identifier: "Test" [4:22 - 4:26] ObjCClassRef=Test:3:12
-// CHECK-TOK: Punctuation: ")" [4:26 - 4:27] ObjCIvarDecl=anOutletCollection:4:34 (Definition)
+// FIXME: The following token should belong to the macro expansion cursor.
+// CHECK-TOK: Punctuation: ")" [4:26 - 4:27]
// CHECK-TOK: Identifier: "Test" [4:28 - 4:32] ObjCClassRef=Test:3:12
// CHECK-TOK: Punctuation: "*" [4:33 - 4:34] ObjCIvarDecl=anOutletCollection:4:34 (Definition)
// CHECK-TOK: Identifier: "anOutletCollection" [4:34 - 4:52] ObjCIvarDecl=anOutletCollection:4:34 (Definition)
diff --git a/test/Index/Inputs/CommentXML/invalid-para-kind-01.xml b/test/Index/Inputs/CommentXML/invalid-para-kind-01.xml
new file mode 100644
index 0000000..9b82042
--- /dev/null
+++ b/test/Index/Inputs/CommentXML/invalid-para-kind-01.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Function>
+<Name>aaa</Name>
+<Abstract><Para>Aaa.</Para></Abstract>
+<Discussion>
+ <Para kind="">Bbb</Para>
+</Discussion>
+</Function>
+
diff --git a/test/Index/Inputs/CommentXML/invalid-para-kind-02.xml b/test/Index/Inputs/CommentXML/invalid-para-kind-02.xml
new file mode 100644
index 0000000..a1a2900
--- /dev/null
+++ b/test/Index/Inputs/CommentXML/invalid-para-kind-02.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Function>
+<Name>aaa</Name>
+<Abstract><Para>Aaa.</Para></Abstract>
+<Discussion>
+ <Para kind="zzz">Bbb</Para>
+</Discussion>
+</Function>
+
diff --git a/test/Index/Inputs/CommentXML/valid-para-kind-01.xml b/test/Index/Inputs/CommentXML/valid-para-kind-01.xml
new file mode 100644
index 0000000..71fe277
--- /dev/null
+++ b/test/Index/Inputs/CommentXML/valid-para-kind-01.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Function>
+<Name>aaa</Name>
+<Abstract><Para>Aaa.</Para></Abstract>
+<Discussion>
+ <Para>Bbb</Para>
+ <Para kind="attention">Bbb</Para>
+ <Para kind="author">Bbb</Para>
+ <Para kind="authors">Bbb</Para>
+ <Para kind="bug">Bbb</Para>
+ <Para kind="copyright">Bbb</Para>
+ <Para kind="date">Bbb</Para>
+ <Para kind="invariant">Bbb</Para>
+ <Para kind="note">Bbb</Para>
+ <Para kind="post">Bbb</Para>
+ <Para kind="pre">Bbb</Para>
+ <Para kind="remark">Bbb</Para>
+ <Para kind="remarks">Bbb</Para>
+ <Para kind="sa">Bbb</Para>
+ <Para kind="see">Bbb</Para>
+ <Para kind="since">Bbb</Para>
+ <Para kind="todo">Bbb</Para>
+ <Para kind="version">Bbb</Para>
+ <Para kind="warning">Bbb</Para>
+</Discussion>
+</Function>
+
diff --git a/test/Index/annotate-comments-availability-attrs.cpp b/test/Index/annotate-comments-availability-attrs.cpp
index 777881d..74a57b9 100644
--- a/test/Index/annotate-comments-availability-attrs.cpp
+++ b/test/Index/annotate-comments-availability-attrs.cpp
@@ -13,32 +13,31 @@
void attr_availability_1() __attribute__((availability(macosx,obsoleted=10.0,introduced=8.0,deprecated=9.0, message="use availability_test in <foo.h>")))
__attribute__((availability(ios,unavailable, message="not for iOS")));
+// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments-availability-attrs.cpp" line="[[@LINE-3]]" column="6"><Name>attr_availability_1</Name><USR>c:@F@attr_availability_1#</USR><Declaration>void attr_availability_1()</Declaration><Abstract><Para> Aaa.</Para></Abstract><Availability distribution="iOS"><DeprecationSummary>not for iOS</DeprecationSummary><Unavailable/></Availability><Availability distribution="OS X"><IntroducedInVersion>8.0</IntroducedInVersion><DeprecatedInVersion>9.0</DeprecatedInVersion><RemovedAfterVersion>10.0</RemovedAfterVersion><DeprecationSummary>use availability_test in &lt;foo.h&gt;</DeprecationSummary></Availability></Function>]
+
/// Aaa.
void attr_availability_2() __attribute__((availability(macosx,obsoleted=10.0.1,introduced=8.0.1,deprecated=9.0.1)));
+// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments-availability-attrs.cpp" line="[[@LINE-2]]" column="6"><Name>attr_availability_2</Name><USR>c:@F@attr_availability_2#</USR><Declaration>void attr_availability_2()</Declaration><Abstract><Para> Aaa.</Para></Abstract><Availability distribution="OS X"><IntroducedInVersion>8.0.1</IntroducedInVersion><DeprecatedInVersion>9.0.1</DeprecatedInVersion><RemovedAfterVersion>10.0.1</RemovedAfterVersion></Availability></Function>]
+
/// Aaa.
void attr_deprecated_1() __attribute__((deprecated));
+// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments-availability-attrs.cpp" line="[[@LINE-2]]" column="6"><Name>attr_deprecated_1</Name><USR>c:@F@attr_deprecated_1#</USR><Declaration>void attr_deprecated_1()</Declaration><Abstract><Para> Aaa.</Para></Abstract><Deprecated/></Function>]
+
/// Aaa.
void attr_deprecated_2() __attribute__((deprecated("message 1 <foo.h>")));
+// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments-availability-attrs.cpp" line="[[@LINE-2]]" column="6"><Name>attr_deprecated_2</Name><USR>c:@F@attr_deprecated_2#</USR><Declaration>void attr_deprecated_2()</Declaration><Abstract><Para> Aaa.</Para></Abstract><Deprecated>message 1 &lt;foo.h&gt;</Deprecated></Function>]
+
+
/// Aaa.
void attr_unavailable_1() __attribute__((unavailable));
+// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments-availability-attrs.cpp" line="[[@LINE-2]]" column="6"><Name>attr_unavailable_1</Name><USR>c:@F@attr_unavailable_1#</USR><Declaration>void attr_unavailable_1()</Declaration><Abstract><Para> Aaa.</Para></Abstract><Unavailable/></Function>]
+
/// Aaa.
void attr_unavailable_2() __attribute__((unavailable("message 2 <foo.h>")));
-// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments-availability-attrs.cpp" line="13" column="6"><Name>attr_availability_1</Name><USR>c:@F@attr_availability_1#</USR><Declaration>void attr_availability_1()</Declaration><Abstract><Para> Aaa.</Para></Abstract><Availability distribution="iOS"><DeprecationSummary>not for iOS</DeprecationSummary><Unavailable/></Availability><Availability distribution="OS X"><IntroducedInVersion>8.0</IntroducedInVersion><DeprecatedInVersion>9.0</DeprecatedInVersion><RemovedAfterVersion>10.0</RemovedAfterVersion><DeprecationSummary>use availability_test in &lt;foo.h&gt;</DeprecationSummary></Availability></Function>]
-
-
-// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments-availability-attrs.cpp" line="17" column="6"><Name>attr_availability_2</Name><USR>c:@F@attr_availability_2#</USR><Declaration>void attr_availability_2()</Declaration><Abstract><Para> Aaa.</Para></Abstract><Availability distribution="OS X"><IntroducedInVersion>8.0.1</IntroducedInVersion><DeprecatedInVersion>9.0.1</DeprecatedInVersion><RemovedAfterVersion>10.0.1</RemovedAfterVersion></Availability></Function>]
-
-// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments-availability-attrs.cpp" line="20" column="6"><Name>attr_deprecated_1</Name><USR>c:@F@attr_deprecated_1#</USR><Declaration>void attr_deprecated_1()</Declaration><Abstract><Para> Aaa.</Para></Abstract><Deprecated/></Function>]
-
-// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments-availability-attrs.cpp" line="23" column="6"><Name>attr_deprecated_2</Name><USR>c:@F@attr_deprecated_2#</USR><Declaration>void attr_deprecated_2()</Declaration><Abstract><Para> Aaa.</Para></Abstract><Deprecated>message 1 &lt;foo.h&gt;</Deprecated></Function>]
-
-
-// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments-availability-attrs.cpp" line="26" column="6"><Name>attr_unavailable_1</Name><USR>c:@F@attr_unavailable_1#</USR><Declaration>void attr_unavailable_1()</Declaration><Abstract><Para> Aaa.</Para></Abstract><Unavailable/></Function>]
-
+// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments-availability-attrs.cpp" line="[[@LINE-2]]" column="6"><Name>attr_unavailable_2</Name><USR>c:@F@attr_unavailable_2#</USR><Declaration>void attr_unavailable_2()</Declaration><Abstract><Para> Aaa.</Para></Abstract><Unavailable>message 2 &lt;foo.h&gt;</Unavailable></Function>]
-// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments-availability-attrs.cpp" line="29" column="6"><Name>attr_unavailable_2</Name><USR>c:@F@attr_unavailable_2#</USR><Declaration>void attr_unavailable_2()</Declaration><Abstract><Para> Aaa.</Para></Abstract><Unavailable>message 2 &lt;foo.h&gt;</Unavailable></Function>]
diff --git a/test/Index/annotate-comments-property-accessor.m b/test/Index/annotate-comments-property-accessor.m
new file mode 100644
index 0000000..2bd1d01
--- /dev/null
+++ b/test/Index/annotate-comments-property-accessor.m
@@ -0,0 +1,62 @@
+// 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
+// rdar://12378879
+
+// Ensure that XML we generate is not invalid.
+// RUN: FileCheck %s -check-prefix=WRONG < %t/out
+// WRONG-NOT: CommentXMLInvalid
+
+@interface AppDelegate
+/**
+ \brief This is ReadonlyProperty
+*/
+@property (readonly, getter = ReadonlyGetter) int MyProperty;
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}annotate-comments-property-accessor.m" line="[[@LINE-1]]" column="51"><Name>MyProperty</Name><USR>c:objc(cs)AppDelegate(py)MyProperty</USR><Declaration>- (int)ReadonlyGetter;</Declaration><Abstract><Para> This is ReadonlyProperty</Para></Abstract></Function>]
+
+/**
+ \brief This is GeneralProperty
+*/
+@property int GeneralProperty;
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}annotate-comments-property-accessor.m" line="[[@LINE-1]]" column="15"><Name>GeneralProperty</Name><USR>c:objc(cs)AppDelegate(py)GeneralProperty</USR><Declaration>- (int)GeneralProperty;</Declaration><Abstract><Para> This is GeneralProperty</Para></Abstract></Function>]
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}annotate-comments-property-accessor.m" line="[[@LINE-2]]" column="15"><Name>GeneralProperty</Name><USR>c:objc(cs)AppDelegate(py)GeneralProperty</USR><Declaration>- (void)setGeneralProperty:(int)GeneralProperty;</Declaration><Abstract><Para> This is GeneralProperty</Para></Abstract></Function>]
+
+/**
+ \brief This is PropertyInPrimaryClass
+*/
+@property (copy, nonatomic) id PropertyInPrimaryClass;
+- (void) setThisRecord : (id)arg;
+- (id) Record;
+@end
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}annotate-comments-property-accessor.m" line="[[@LINE-4]]" column="32"><Name>PropertyInPrimaryClass</Name><USR>c:objc(cs)AppDelegate(py)PropertyInPrimaryClass</USR><Declaration>- (id)PropertyInPrimaryClass;</Declaration><Abstract><Para> This is PropertyInPrimaryClass</Para></Abstract></Function>]
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}annotate-comments-property-accessor.m" line="[[@LINE-5]]" column="32"><Name>PropertyInPrimaryClass</Name><USR>c:objc(cs)AppDelegate(py)PropertyInPrimaryClass</USR><Declaration>- (void)setPropertyInPrimaryClass:(id)PropertyInPrimaryClass;</Declaration><Abstract><Para> This is PropertyInPrimaryClass</Para></Abstract></Function>]
+
+@interface AppDelegate()
+- (id) GetterInClassExtension;
+/**
+ \brief This is Record
+*/
+@property (copy, setter = setThisRecord:) id Record;
+@end
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}annotate-comments-property-accessor.m" line="[[@LINE-6]]" column="1"><Name>PropertyInClassExtension</Name><USR>c:objc(cs)AppDelegate(py)PropertyInClassExtension</USR><Declaration>- (id)GetterInClassExtension;</Declaration><Abstract><Para> This is PropertyInClassExtension</Para></Abstract></Function>]
+
+@interface AppDelegate()
+/**
+ \brief This is PropertyInClassExtension
+*/
+@property (copy, getter = GetterInClassExtension) id PropertyInClassExtension;
+
+- (id) PropertyInPrimaryClass;
+@end
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}annotate-comments-property-accessor.m" line="[[@LINE-4]]" column="54"><Name>PropertyInClassExtension</Name><USR>c:objc(cs)AppDelegate(py)PropertyInClassExtension</USR><Declaration>- (id)GetterInClassExtension;</Declaration><Abstract><Para> This is PropertyInClassExtension</Para></Abstract></Function>]
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}annotate-comments-property-accessor.m" line="[[@LINE-5]]" column="54"><Name>PropertyInClassExtension</Name><USR>c:objc(cs)AppDelegate(py)PropertyInClassExtension</USR><Declaration>- (void)setPropertyInClassExtension:(id)PropertyInClassExtension;</Declaration><Abstract><Para> This is PropertyInClassExtension</Para></Abstract></Function>]
+
+@implementation AppDelegate
+- (id) PropertyInPrimaryClass { return 0; }
+@end
+
+
+
+
+
diff --git a/test/Index/annotate-comments-typedef.m b/test/Index/annotate-comments-typedef.m
new file mode 100644
index 0000000..b23e535
--- /dev/null
+++ b/test/Index/annotate-comments-typedef.m
@@ -0,0 +1,49 @@
+// 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
+// rdar://13067629
+
+// Ensure that XML we generate is not invalid.
+// RUN: FileCheck %s -check-prefix=WRONG < %t/out
+// WRONG-NOT: CommentXMLInvalid
+
+/** Documentation for NSUInteger */
+typedef unsigned int NSUInteger;
+
+/** Documentation for MyEnum */
+typedef enum : NSUInteger {
+ MyEnumFoo, /**< value Foo */
+ MyEnumBar, /**< value Bar */
+ MyEnumBaz, /**< value Baz */
+} MyEnum;
+// CHECK: TypedefDecl=MyEnum:[[@LINE-1]]:3 (Definition) FullCommentAsHTML=[<p class="para-brief"> Documentation for MyEnum </p>] FullCommentAsXML=[<Typedef file="{{[^"]+}}annotate-comments-typedef.m" line="[[@LINE-1]]" column="3"><Name>&lt;anonymous&gt;</Name><USR>c:@EA@MyEnum</USR><Declaration>typedef enum MyEnum MyEnum</Declaration><Abstract><Para> Documentation for MyEnum </Para></Abstract></Typedef>]
+
+
+/** Documentation for E */
+enum E {
+ E_MyEnumFoo, /**< value Foo */
+ E_MyEnumBar, /**< value Bar */
+ E_MyEnumBaz, /**< value Baz */
+};
+typedef enum E E_T;
+// CHECK: EnumDecl=E:[[@LINE-6]]:6 (Definition) {{.*}} BriefComment=[Documentation for E] FullCommentAsHTML=[<p class="para-brief"> Documentation for E </p>] FullCommentAsXML=[<Enum file="{{[^"]+}}annotate-comments-typedef.m" line="[[@LINE-6]]" column="6"><Name>E</Name><USR>c:@E@E</USR><Declaration>enum E{{( : int)?}} {}</Declaration><Abstract><Para> Documentation for E </Para></Abstract></Enum>]
+// CHECK: TypedefDecl=E_T:[[@LINE-2]]:16 (Definition) FullCommentAsHTML=[<p class="para-brief"> Documentation for E </p>] FullCommentAsXML=[<Typedef file="{{[^"]+}}annotate-comments-typedef.m" line="[[@LINE-2]]" column="16"><Name>E</Name><USR>c:@E@E</USR><Declaration>typedef enum E E_T</Declaration><Abstract><Para> Documentation for E </Para></Abstract></Typedef>]
+
+
+/** Comment about Foo */
+typedef struct {
+ int iii;
+ } Foo;
+// CHECK: TypedefDecl=Foo:[[@LINE-1]]:11 (Definition) FullCommentAsHTML=[<p class="para-brief"> Comment about Foo </p>] FullCommentAsXML=[<Typedef file="{{[^"]+}}annotate-comments-typedef.m" line="[[@LINE-1]]" column="11"><Name>&lt;anonymous&gt;</Name><USR>c:@SA@Foo</USR><Declaration>typedef struct Foo Foo</Declaration><Abstract><Para> Comment about Foo </Para></Abstract></Typedef>]
+// CHECK: StructDecl=:[[@LINE-4]]:9 (Definition) {{.*}} BriefComment=[Comment about Foo] FullCommentAsHTML=[<p class="para-brief"> Comment about Foo </p>] FullCommentAsXML=[<Class file="{{[^"]+}}annotate-comments-typedef.m" line="[[@LINE-4]]" column="9"><Name>&lt;anonymous&gt;</Name><USR>c:@SA@Foo</USR><Declaration>struct {}</Declaration><Abstract><Para> Comment about Foo </Para></Abstract></Class>]
+
+
+struct Foo1 {
+ int iii;
+};
+/** About Foo1T */
+typedef struct Foo1 Foo1T;
+// FIXME: we don't attach this comment to 'struct Foo1'
+// CHECK: TypedefDecl=Foo1T:[[@LINE-2]]:21 (Definition) {{.*}} FullCommentAsHTML=[<p class="para-brief"> About Foo1T </p>] FullCommentAsXML=[<Typedef file="{{[^"]+}}annotate-comments-typedef.m" line="[[@LINE-2]]" column="21"><Name>Foo1T</Name><USR>c:annotate-comments-typedef.m@{{[0-9]+}}@T@Foo1T</USR><Declaration>typedef struct Foo1 Foo1T</Declaration><Abstract><Para> About Foo1T </Para></Abstract></Typedef>]
+
diff --git a/test/Index/annotate-comments.cpp b/test/Index/annotate-comments.cpp
index b8b8e6c..2a0b635 100644
--- a/test/Index/annotate-comments.cpp
+++ b/test/Index/annotate-comments.cpp
@@ -247,239 +247,12 @@ void isdoxy52(int);
*/
void isdoxy53(int);
-/// Aaa.
-void comment_to_html_conversion_1();
-
-/// \brief Aaa.
-void comment_to_html_conversion_2();
-
-/// \short Aaa.
-void comment_to_html_conversion_3();
-
-/// Aaa.
-///
-/// \brief Bbb.
-void comment_to_html_conversion_4();
-
-/// Aaa.
-///
-/// \brief Bbb.
-///
-/// Ccc.
-void comment_to_html_conversion_5();
-
-/// \brief Aaa.
-/// \brief Bbb.
-void comment_to_html_conversion_6();
-
-/// Aaa.
-///
-/// \return Bbb.
-void comment_to_html_conversion_7();
-
-/// Aaa.
-///
-/// \returns Bbb.
-void comment_to_html_conversion_8();
-
-/// Aaa.
-///
-/// \result Bbb.
-void comment_to_html_conversion_9();
-
-/// \returns Aaa.
-/// \returns Bbb.
-void comment_to_html_conversion_10();
-
-/// Aaa.
-///
-/// Bbb.
-///
-/// \returns Ccc.
-void comment_to_html_conversion_11();
-
-/// \param
-void comment_to_html_conversion_12(int x1);
-
-/// \param x1 Aaa.
-void comment_to_html_conversion_13(int x1);
-
-/// \param zzz Aaa.
-void comment_to_html_conversion_14(int x1);
-
-/// \param x2 Bbb.
-/// \param x1 Aaa.
-void comment_to_html_conversion_15(int x1, int x2);
-
-/// \param x2 Bbb.
-/// \param zzz Aaa.
-/// \param x1 Aaa.
-void comment_to_html_conversion_16(int x1, int x2);
-
-/// \tparam
-/// \param aaa Blah blah
-template<typename T>
-void comment_to_html_conversion_17(T aaa);
-
-/// \tparam T
-/// \param aaa Blah blah
-template<typename T>
-void comment_to_html_conversion_18(T aaa);
-
-/// \tparam T2 Bbb
-/// \tparam T1 Aaa
-template<typename T1, typename T2>
-void comment_to_html_conversion_19(T1 aaa, T2 bbb);
-
-/// \tparam T2 Bbb
-/// \tparam U Zzz
-/// \tparam V Ccc
-/// \tparam T1 Aaa
-template<typename T1, typename T2, int V>
-void comment_to_html_conversion_20(T1 aaa, T2 bbb);
-
-/// \tparam TTT Ddd
-/// \tparam C Ccc
-/// \tparam T Aaa
-/// \tparam TT Bbb
-template<template<template<typename T> class TT, class C> class TTT>
-void comment_to_html_conversion_21();
-
-/// \brief Aaa.
-///
-/// Bbb.
-///
-/// \param x2 Ddd.
-/// \param x1 Ccc.
-/// \returns Eee.
-void comment_to_html_conversion_22(int x1, int x2);
-
-/// <br><a href="http://example.com/">Aaa</a>
-void comment_to_html_conversion_23();
-
-/// \verbatim
-/// <a href="http://example.com/">Aaa</a>
-/// <a href='http://example.com/'>Aaa</a>
-/// \endverbatim
-void comment_to_html_conversion_24();
-
-/// \function foo
-/// \class foo
-/// \method foo
-/// \interface foo
-/// Blah blah.
-void comment_to_html_conversion_25();
-
-/// \unknown
-void comment_to_html_conversion_26();
-
-/// \b Aaa
-void comment_to_html_conversion_27();
-
-/// \c Aaa \p Bbb
-void comment_to_html_conversion_28();
-
-/// \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();
-
-/// &amp; &lt; &gt; &quot;
-void comment_to_html_conversion_32();
-
-/// <em>0&lt;i</em>
-void comment_to_html_conversion_33();
-
-/// Aaa.
-class comment_to_xml_conversion_01 {
- /// \param aaa Blah blah.
- comment_to_xml_conversion_01(int aaa);
-
- /// Aaa.
- ~comment_to_xml_conversion_01();
-
- /// \param aaa Blah blah.
- int comment_to_xml_conversion_02(int aaa);
-
- /// \param aaa Blah blah.
- static int comment_to_xml_conversion_03(int aaa);
-
- /// Aaa.
- int comment_to_xml_conversion_04;
-
- /// Aaa.
- static int comment_to_xml_conversion_05;
-
- /// \param aaa Blah blah.
- void operator()(int aaa);
-
- /// Aaa.
- operator bool();
-
- /// Aaa.
- typedef int comment_to_xml_conversion_06;
-
- /// Aaa.
- using comment_to_xml_conversion_07 = int;
-
- template<typename T, typename U>
- class comment_to_xml_conversion_08 { };
-
- /// Aaa.
- template<typename T>
- using comment_to_xml_conversion_09 = comment_to_xml_conversion_08<T, int>;
-};
-
-/// Aaa.
-template<typename T, typename U>
-void comment_to_xml_conversion_10(T aaa, U bbb);
-
-/// Aaa.
-template<>
-void comment_to_xml_conversion_10(int aaa, int bbb);
-
-/// Aaa.
-template<typename T, typename U>
-class comment_to_xml_conversion_11 { };
-
-/// Aaa.
-template<typename T>
-class comment_to_xml_conversion_11<T, int> { };
-
-/// Aaa.
-template<>
-class comment_to_xml_conversion_11<int, int> { };
-
-/// Aaa.
-int comment_to_xml_conversion_12;
-
-/// Aaa.
-namespace comment_to_xml_conversion_13 {
- /// Aaa.
- namespace comment_to_xml_conversion_14 {
- }
-}
-
-/// Aaa.
-enum comment_to_xml_conversion_15 {
- /// Aaa.
- comment_to_xml_conversion_16
-};
-
-/// Aaa.
-enum class comment_to_xml_conversion_17 {
- /// Aaa.
- comment_to_xml_conversion_18
-};
-
#endif
// RUN: rm -rf %t
// RUN: mkdir %t
+
+// Check that we serialize comment source locations properly.
// RUN: %clang_cc1 -x c++ -std=c++11 -emit-pch -o %t/out.pch %s
// RUN: %clang_cc1 -x c++ -std=c++11 -include-pch %t/out.pch -fsyntax-only %s
@@ -509,6 +282,11 @@ enum class comment_to_xml_conversion_17 {
// RUN: FileCheck %s < %t/out.c-index-direct
// RUN: FileCheck %s < %t/out.c-index-pch
+// These CHECK lines are not located near the code on purpose. This test
+// checks that documentation comments are attached to declarations correctly.
+// Adding a non-documentation comment with CHECK line between every two
+// documentation comments will only test a single code path.
+//
// CHECK: annotate-comments.cpp:16:6: FunctionDecl=isdoxy4:{{.*}} isdoxy4 IS_DOXYGEN_SINGLE
// CHECK: annotate-comments.cpp:20:6: FunctionDecl=isdoxy5:{{.*}} isdoxy5 IS_DOXYGEN_SINGLE
// CHECK: annotate-comments.cpp:25:6: FunctionDecl=isdoxy6:{{.*}} isdoxy6 IS_DOXYGEN_SINGLE
@@ -550,414 +328,3 @@ enum class comment_to_xml_conversion_17 {
// 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:251:6: FunctionDecl=comment_to_html_conversion_1:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="251" column="6"><Name>comment_to_html_conversion_1</Name><USR>c:@F@comment_to_html_conversion_1#</USR><Declaration>void comment_to_html_conversion_1()</Declaration><Abstract><Para> Aaa.</Para></Abstract></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Aaa.])))]
-// CHECK: annotate-comments.cpp:254:6: FunctionDecl=comment_to_html_conversion_2:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="254" column="6"><Name>comment_to_html_conversion_2</Name><USR>c:@F@comment_to_html_conversion_2#</USR><Declaration>void comment_to_html_conversion_2()</Declaration><Abstract><Para> Aaa.</Para></Abstract></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK-NEXT: (CXComment_BlockCommand CommandName=[brief]
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))))]
-// CHECK: annotate-comments.cpp:257:6: FunctionDecl=comment_to_html_conversion_3:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="257" column="6"><Name>comment_to_html_conversion_3</Name><USR>c:@F@comment_to_html_conversion_3#</USR><Declaration>void comment_to_html_conversion_3()</Declaration><Abstract><Para> Aaa.</Para></Abstract></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK-NEXT: (CXComment_BlockCommand CommandName=[short]
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))))]
-// CHECK: annotate-comments.cpp:262:6: FunctionDecl=comment_to_html_conversion_4:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Bbb.</p><p> Aaa.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="262" column="6"><Name>comment_to_html_conversion_4</Name><USR>c:@F@comment_to_html_conversion_4#</USR><Declaration>void comment_to_html_conversion_4()</Declaration><Abstract><Para> Bbb.</Para></Abstract><Discussion><Para> Aaa.</Para></Discussion></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))
-// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK-NEXT: (CXComment_BlockCommand CommandName=[brief]
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Bbb.]))))]
-// CHECK: annotate-comments.cpp:269:6: FunctionDecl=comment_to_html_conversion_5:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Bbb.</p><p> Aaa.</p><p> Ccc.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="269" column="6"><Name>comment_to_html_conversion_5</Name><USR>c:@F@comment_to_html_conversion_5#</USR><Declaration>void comment_to_html_conversion_5()</Declaration><Abstract><Para> Bbb.</Para></Abstract><Discussion><Para> Aaa.</Para><Para> Ccc.</Para></Discussion></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))
-// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK-NEXT: (CXComment_BlockCommand CommandName=[brief]
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Bbb.])))
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Ccc.])))]
-// CHECK: annotate-comments.cpp:273:6: FunctionDecl=comment_to_html_conversion_6:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa. </p><p class="para-brief"> Bbb.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="273" column="6"><Name>comment_to_html_conversion_6</Name><USR>c:@F@comment_to_html_conversion_6#</USR><Declaration>void comment_to_html_conversion_6()</Declaration><Abstract><Para> Aaa. </Para></Abstract><Discussion><Para> Bbb.</Para></Discussion></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK-NEXT: (CXComment_BlockCommand CommandName=[brief]
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Aaa.] HasTrailingNewline)
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
-// CHECK-NEXT: (CXComment_BlockCommand CommandName=[brief]
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Bbb.]))))]
-// CHECK: annotate-comments.cpp:278:6: FunctionDecl=comment_to_html_conversion_7:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p><p class="para-returns"><span class="word-returns">Returns</span> Bbb.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="278" column="6"><Name>comment_to_html_conversion_7</Name><USR>c:@F@comment_to_html_conversion_7#</USR><Declaration>void comment_to_html_conversion_7()</Declaration><Abstract><Para> Aaa.</Para></Abstract><ResultDiscussion><Para> Bbb.</Para></ResultDiscussion></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))
-// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK-NEXT: (CXComment_BlockCommand CommandName=[return]
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Bbb.]))))]
-// CHECK: annotate-comments.cpp:283:6: FunctionDecl=comment_to_html_conversion_8:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p><p class="para-returns"><span class="word-returns">Returns</span> Bbb.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="283" column="6"><Name>comment_to_html_conversion_8</Name><USR>c:@F@comment_to_html_conversion_8#</USR><Declaration>void comment_to_html_conversion_8()</Declaration><Abstract><Para> Aaa.</Para></Abstract><ResultDiscussion><Para> Bbb.</Para></ResultDiscussion></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))
-// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK-NEXT: (CXComment_BlockCommand CommandName=[returns]
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Bbb.]))))]
-// CHECK: annotate-comments.cpp:288:6: FunctionDecl=comment_to_html_conversion_9:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p><p class="para-returns"><span class="word-returns">Returns</span> Bbb.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="288" column="6"><Name>comment_to_html_conversion_9</Name><USR>c:@F@comment_to_html_conversion_9#</USR><Declaration>void comment_to_html_conversion_9()</Declaration><Abstract><Para> Aaa.</Para></Abstract><ResultDiscussion><Para> Bbb.</Para></ResultDiscussion></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))
-// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK-NEXT: (CXComment_BlockCommand CommandName=[result]
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Bbb.]))))]
-// CHECK: annotate-comments.cpp:292:6: FunctionDecl=comment_to_html_conversion_10:{{.*}} FullCommentAsHTML=[<p class="para-returns"><span class="word-returns">Returns</span> Bbb.</p><p class="para-returns"><span class="word-returns">Returns</span> Aaa. </p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="292" column="6"><Name>comment_to_html_conversion_10</Name><USR>c:@F@comment_to_html_conversion_10#</USR><Declaration>void comment_to_html_conversion_10()</Declaration><ResultDiscussion><Para> Aaa. </Para></ResultDiscussion><Discussion><Para> Bbb.</Para></Discussion></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK-NEXT: (CXComment_BlockCommand CommandName=[returns]
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Aaa.] HasTrailingNewline)
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
-// CHECK-NEXT: (CXComment_BlockCommand CommandName=[returns]
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Bbb.]))))]
-// CHECK: annotate-comments.cpp:299:6: FunctionDecl=comment_to_html_conversion_11:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p><p> Bbb.</p><p class="para-returns"><span class="word-returns">Returns</span> Ccc.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="299" column="6"><Name>comment_to_html_conversion_11</Name><USR>c:@F@comment_to_html_conversion_11#</USR><Declaration>void comment_to_html_conversion_11()</Declaration><Abstract><Para> Aaa.</Para></Abstract><ResultDiscussion><Para> Ccc.</Para></ResultDiscussion><Discussion><Para> Bbb.</Para></Discussion></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Bbb.]))
-// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK-NEXT: (CXComment_BlockCommand CommandName=[returns]
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Ccc.]))))]
-// CHECK: annotate-comments.cpp:302:6: FunctionDecl=comment_to_html_conversion_12:{{.*}} FullCommentAsHTML=[] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="302" column="6"><Name>comment_to_html_conversion_12</Name><USR>c:@F@comment_to_html_conversion_12#I#</USR><Declaration>void comment_to_html_conversion_12(int x1)</Declaration></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[] ParamIndex=Invalid
-// CHECK-NEXT: (CXComment_Paragraph IsWhitespace)))]
-// CHECK: annotate-comments.cpp:305:6: FunctionDecl=comment_to_html_conversion_13:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-0">x1</dt><dd class="param-descr-index-0"> Aaa.</dd></dl>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="305" column="6"><Name>comment_to_html_conversion_13</Name><USR>c:@F@comment_to_html_conversion_13#I#</USR><Declaration>void comment_to_html_conversion_13(int x1)</Declaration><Parameters><Parameter><Name>x1</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Aaa.</Para></Discussion></Parameter></Parameters></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x1] ParamIndex=0
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))))]
-// CHECK: annotate-comments.cpp:308:6: FunctionDecl=comment_to_html_conversion_14:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-invalid">zzz</dt><dd class="param-descr-index-invalid"> Aaa.</dd></dl>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="308" column="6"><Name>comment_to_html_conversion_14</Name><USR>c:@F@comment_to_html_conversion_14#I#</USR><Declaration>void comment_to_html_conversion_14(int x1)</Declaration><Parameters><Parameter><Name>zzz</Name><Direction isExplicit="0">in</Direction><Discussion><Para> Aaa.</Para></Discussion></Parameter></Parameters></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[zzz] ParamIndex=Invalid
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))))]
-// CHECK: annotate-comments.cpp:312:6: FunctionDecl=comment_to_html_conversion_15:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-0">x1</dt><dd class="param-descr-index-0"> Aaa.</dd><dt class="param-name-index-1">x2</dt><dd class="param-descr-index-1"> Bbb. </dd></dl>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="312" column="6"><Name>comment_to_html_conversion_15</Name><USR>c:@F@comment_to_html_conversion_15#I#I#</USR><Declaration>void comment_to_html_conversion_15(int x1, int x2)</Declaration><Parameters><Parameter><Name>x1</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Aaa.</Para></Discussion></Parameter><Parameter><Name>x2</Name><Index>1</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Bbb. </Para></Discussion></Parameter></Parameters></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x2] ParamIndex=1
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Bbb.] HasTrailingNewline)
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
-// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x1] ParamIndex=0
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))))]
-// CHECK: annotate-comments.cpp:317:6: FunctionDecl=comment_to_html_conversion_16:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-0">x1</dt><dd class="param-descr-index-0"> Aaa.</dd><dt class="param-name-index-1">x2</dt><dd class="param-descr-index-1"> Bbb. </dd><dt class="param-name-index-invalid">zzz</dt><dd class="param-descr-index-invalid"> Aaa. </dd></dl>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="317" column="6"><Name>comment_to_html_conversion_16</Name><USR>c:@F@comment_to_html_conversion_16#I#I#</USR><Declaration>void comment_to_html_conversion_16(int x1, int x2)</Declaration><Parameters><Parameter><Name>x1</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Aaa.</Para></Discussion></Parameter><Parameter><Name>x2</Name><Index>1</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Bbb. </Para></Discussion></Parameter><Parameter><Name>zzz</Name><Direction isExplicit="0">in</Direction><Discussion><Para> Aaa. </Para></Discussion></Parameter></Parameters></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x2] ParamIndex=1
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Bbb.] HasTrailingNewline)
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
-// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[zzz] ParamIndex=Invalid
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Aaa.] HasTrailingNewline)
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
-// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x1] ParamIndex=0
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))))]
-// CHECK: annotate-comments.cpp:322:6: FunctionTemplate=comment_to_html_conversion_17:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-0">aaa</dt><dd class="param-descr-index-0"> Blah blah</dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}annotate-comments.cpp" line="322" column="6"><Name>comment_to_html_conversion_17</Name><USR>c:@FT@&gt;1#Tcomment_to_html_conversion_17#t0.0#</USR><Declaration>template &lt;typename T&gt; void comment_to_html_conversion_17(T aaa)</Declaration><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah</Para></Discussion></Parameter></Parameters></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK-NEXT: (CXComment_TParamCommand ParamName=[] ParamPosition=Invalid
-// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
-// 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:327:6: FunctionTemplate=comment_to_html_conversion_18:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-0">aaa</dt><dd class="param-descr-index-0"> Blah blah</dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}annotate-comments.cpp" line="327" column="6"><Name>comment_to_html_conversion_18</Name><USR>c:@FT@&gt;1#Tcomment_to_html_conversion_18#t0.0#</USR><Declaration>template &lt;typename T&gt; void comment_to_html_conversion_18(T aaa)</Declaration><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah</Para></Discussion></Parameter></Parameters></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK-NEXT: (CXComment_TParamCommand ParamName=[T] ParamPosition={0}
-// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
-// 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:332:6: FunctionTemplate=comment_to_html_conversion_19:{{.*}} FullCommentAsHTML=[<dl><dt class="tparam-name-index-0">T1</dt><dd class="tparam-descr-index-0"> Aaa</dd><dt class="tparam-name-index-1">T2</dt><dd class="tparam-descr-index-1"> Bbb </dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}annotate-comments.cpp" line="332" column="6"><Name>comment_to_html_conversion_19</Name><USR>c:@FT@&gt;2#T#Tcomment_to_html_conversion_19#t0.0#t0.1#</USR><Declaration>template &lt;typename T1, typename T2&gt; void comment_to_html_conversion_19(T1 aaa, T2 bbb)</Declaration><TemplateParameters><Parameter><Name>T1</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>T2</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter></TemplateParameters></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK-NEXT: (CXComment_TParamCommand ParamName=[T2] ParamPosition={1}
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Bbb] HasTrailingNewline)
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
-// CHECK-NEXT: (CXComment_TParamCommand ParamName=[T1] ParamPosition={0}
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Aaa]))))]
-// CHECK: annotate-comments.cpp:339:6: FunctionTemplate=comment_to_html_conversion_20:{{.*}} FullCommentAsHTML=[<dl><dt class="tparam-name-index-0">T1</dt><dd class="tparam-descr-index-0"> Aaa</dd><dt class="tparam-name-index-1">T2</dt><dd class="tparam-descr-index-1"> Bbb </dd><dt class="tparam-name-index-2">V</dt><dd class="tparam-descr-index-2"> Ccc </dd><dt class="tparam-name-index-invalid">U</dt><dd class="tparam-descr-index-invalid"> Zzz </dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}annotate-comments.cpp" line="339" column="6"><Name>comment_to_html_conversion_20</Name><USR>c:@FT@&gt;3#T#T#NIcomment_to_html_conversion_20#t0.0#t0.1#</USR><Declaration>template &lt;typename T1, typename T2, int V&gt; void comment_to_html_conversion_20(T1 aaa, T2 bbb)</Declaration><TemplateParameters><Parameter><Name>T1</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>T2</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter><Parameter><Name>V</Name><Index>2</Index><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>U</Name><Discussion><Para> Zzz </Para></Discussion></Parameter></TemplateParameters></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK-NEXT: (CXComment_TParamCommand ParamName=[T2] ParamPosition={1}
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Bbb] HasTrailingNewline)
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
-// CHECK-NEXT: (CXComment_TParamCommand ParamName=[U] ParamPosition=Invalid
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Zzz] HasTrailingNewline)
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
-// CHECK-NEXT: (CXComment_TParamCommand ParamName=[V] ParamPosition={2}
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Ccc] HasTrailingNewline)
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
-// CHECK-NEXT: (CXComment_TParamCommand ParamName=[T1] ParamPosition={0}
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Aaa]))))]
-// CHECK: annotate-comments.cpp:346:6: FunctionTemplate=comment_to_html_conversion_21:{{.*}} FullCommentAsHTML=[<dl><dt class="tparam-name-index-0">TTT</dt><dd class="tparam-descr-index-0"> Ddd </dd><dt class="tparam-name-index-other">C</dt><dd class="tparam-descr-index-other"> Ccc </dd><dt class="tparam-name-index-other">T</dt><dd class="tparam-descr-index-other"> Aaa </dd><dt class="tparam-name-index-other">TT</dt><dd class="tparam-descr-index-other"> Bbb</dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}annotate-comments.cpp" line="346" column="6"><Name>comment_to_html_conversion_21</Name><USR>c:@FT@&gt;1#t&gt;2#t&gt;1#T#Tcomment_to_html_conversion_21#</USR><Declaration>template &lt;template &lt;template &lt;typename T&gt; class TT, class C&gt; class TTT&gt; void comment_to_html_conversion_21()</Declaration><TemplateParameters><Parameter><Name>TTT</Name><Index>0</Index><Discussion><Para> Ddd </Para></Discussion></Parameter><Parameter><Name>C</Name><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>T</Name><Discussion><Para> Aaa </Para></Discussion></Parameter><Parameter><Name>TT</Name><Discussion><Para> Bbb</Para></Discussion></Parameter></TemplateParameters></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK-NEXT: (CXComment_TParamCommand ParamName=[TTT] ParamPosition={0}
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Ddd] HasTrailingNewline)
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
-// CHECK-NEXT: (CXComment_TParamCommand ParamName=[C] ParamPosition={0, 1}
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Ccc] HasTrailingNewline)
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
-// CHECK-NEXT: (CXComment_TParamCommand ParamName=[T] ParamPosition={0, 0, 0}
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Aaa] HasTrailingNewline)
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
-// CHECK-NEXT: (CXComment_TParamCommand ParamName=[TT] ParamPosition={0, 0}
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Bbb]))))]
-// CHECK: annotate-comments.cpp:355:6: FunctionDecl=comment_to_html_conversion_22:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p><p> Bbb.</p><dl><dt class="param-name-index-0">x1</dt><dd class="param-descr-index-0"> Ccc. </dd><dt class="param-name-index-1">x2</dt><dd class="param-descr-index-1"> Ddd. </dd></dl><p class="para-returns"><span class="word-returns">Returns</span> Eee.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="355" column="6"><Name>comment_to_html_conversion_22</Name><USR>c:@F@comment_to_html_conversion_22#I#I#</USR><Declaration>void comment_to_html_conversion_22(int x1, int x2)</Declaration><Abstract><Para> Aaa.</Para></Abstract><Parameters><Parameter><Name>x1</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Ccc. </Para></Discussion></Parameter><Parameter><Name>x2</Name><Index>1</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Ddd. </Para></Discussion></Parameter></Parameters><ResultDiscussion><Para> Eee.</Para></ResultDiscussion><Discussion><Para> Bbb.</Para></Discussion></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK-NEXT: (CXComment_BlockCommand CommandName=[brief]
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Aaa.])))
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Bbb.]))
-// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x2] ParamIndex=1
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Ddd.] HasTrailingNewline)
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
-// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x1] ParamIndex=0
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Ccc.] HasTrailingNewline)
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
-// CHECK-NEXT: (CXComment_BlockCommand CommandName=[returns]
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ Eee.]))))]
-// CHECK: annotate-comments.cpp:358:6: FunctionDecl=comment_to_html_conversion_23:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <br><a href="http://example.com/">Aaa</a></p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="358" column="6"><Name>comment_to_html_conversion_23</Name><USR>c:@F@comment_to_html_conversion_23#</USR><Declaration>void comment_to_html_conversion_23()</Declaration><Abstract><Para> <rawHTML><![CDATA[<br>]]></rawHTML><rawHTML><![CDATA[<a href="http://example.com/">]]></rawHTML>Aaa<rawHTML>&lt;/a&gt;</rawHTML></Para></Abstract></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
-// CHECK-NEXT: (CXComment_HTMLStartTag Name=[br])
-// 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:364:6: FunctionDecl=comment_to_html_conversion_24:{{.*}} FullCommentAsHTML=[<pre> &lt;a href=&quot;http:&#47;&#47;example.com&#47;&quot;&gt;Aaa&lt;&#47;a&gt;\n &lt;a href=&#39;http:&#47;&#47;example.com&#47;&#39;&gt;Aaa&lt;&#47;a&gt;</pre>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="364" column="6"><Name>comment_to_html_conversion_24</Name><USR>c:@F@comment_to_html_conversion_24#</USR><Declaration>void comment_to_html_conversion_24()</Declaration><Discussion><Verbatim xml:space="preserve" kind="verbatim"> &lt;a href=&quot;http://example.com/&quot;&gt;Aaa&lt;/a&gt;\n &lt;a href=&apos;http://example.com/&apos;&gt;Aaa&lt;/a&gt;</Verbatim></Discussion></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK-NEXT: (CXComment_VerbatimBlockCommand CommandName=[verbatim]
-// CHECK-NEXT: (CXComment_VerbatimBlockLine Text=[ <a href="http://example.com/">Aaa</a>])
-// CHECK-NEXT: (CXComment_VerbatimBlockLine Text=[ <a href='http://example.com/'>Aaa</a>])))]
-// CHECK: annotate-comments.cpp:371:6: FunctionDecl=comment_to_html_conversion_25:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Blah blah.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="371" column="6"><Name>comment_to_html_conversion_25</Name><USR>c:@F@comment_to_html_conversion_25#</USR><Declaration>void comment_to_html_conversion_25()</Declaration><Abstract><Para> Blah blah.</Para></Abstract></Function>]
-// CHECK: CommentAST=[
-// CHECK: (CXComment_FullComment
-// CHECK: (CXComment_Paragraph IsWhitespace
-// CHECK: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK: (CXComment_VerbatimLine Text=[ foo])
-// CHECK: (CXComment_Paragraph IsWhitespace
-// CHECK: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK: (CXComment_VerbatimLine Text=[ foo])
-// CHECK: (CXComment_Paragraph IsWhitespace
-// CHECK: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK: (CXComment_VerbatimLine Text=[ foo])
-// CHECK: (CXComment_Paragraph IsWhitespace
-// CHECK: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK: (CXComment_VerbatimLine Text=[ foo])
-// CHECK: (CXComment_Paragraph
-// CHECK: (CXComment_Text Text=[ Blah blah.])))]
-// CHECK: annotate-comments.cpp:374:6: FunctionDecl=comment_to_html_conversion_26:{{.*}} FullCommentAsHTML=[<p class="para-brief"> </p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="374" column="6"><Name>comment_to_html_conversion_26</Name><USR>c:@F@comment_to_html_conversion_26#</USR><Declaration>void comment_to_html_conversion_26()</Declaration><Abstract><Para> </Para></Abstract></Function>]
-// CHECK: CommentAST=[
-// CHECK: (CXComment_FullComment
-// CHECK: (CXComment_Paragraph
-// CHECK: (CXComment_Text Text=[ ] IsWhitespace)
-// CHECK: (CXComment_InlineCommand CommandName=[unknown] RenderNormal)))]
-// CHECK: annotate-comments.cpp:377:6: FunctionDecl=comment_to_html_conversion_27:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <b>Aaa</b></p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="377" column="6"><Name>comment_to_html_conversion_27</Name><USR>c:@F@comment_to_html_conversion_27#</USR><Declaration>void comment_to_html_conversion_27()</Declaration><Abstract><Para> <bold>Aaa</bold></Para></Abstract></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
-// CHECK-NEXT: (CXComment_InlineCommand CommandName=[b] RenderBold Arg[0]=Aaa)))]
-// CHECK: annotate-comments.cpp:380:6: FunctionDecl=comment_to_html_conversion_28:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <tt>Aaa</tt> <tt>Bbb</tt></p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="380" column="6"><Name>comment_to_html_conversion_28</Name><USR>c:@F@comment_to_html_conversion_28#</USR><Declaration>void comment_to_html_conversion_28()</Declaration><Abstract><Para> <monospaced>Aaa</monospaced> <monospaced>Bbb</monospaced></Para></Abstract></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
-// 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:383:6: FunctionDecl=comment_to_html_conversion_29:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <em>Aaa</em> <em>Bbb</em> <em>Ccc</em></p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="383" column="6"><Name>comment_to_html_conversion_29</Name><USR>c:@F@comment_to_html_conversion_29#</USR><Declaration>void comment_to_html_conversion_29()</Declaration><Abstract><Para> <emphasized>Aaa</emphasized> <emphasized>Bbb</emphasized> <emphasized>Ccc</emphasized></Para></Abstract></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
-// CHECK-NEXT: (CXComment_InlineCommand CommandName=[a] RenderEmphasized Arg[0]=Aaa)
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
-// 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:386:6: FunctionDecl=comment_to_html_conversion_30:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <em>1&lt;2</em> <em>3&lt;4</em> <em>5&lt;6</em> </p><dl><dt class="tparam-name-index-invalid">9&lt;10</dt><dd class="tparam-descr-index-invalid"> bbb</dd></dl><dl><dt class="param-name-index-invalid">7&lt;8</dt><dd class="param-descr-index-invalid"> aaa </dd></dl>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="386" column="6"><Name>comment_to_html_conversion_30</Name><USR>c:@F@comment_to_html_conversion_30#</USR><Declaration>void comment_to_html_conversion_30()</Declaration><Abstract><Para> <emphasized>1&lt;2</emphasized> <emphasized>3&lt;4</emphasized> <emphasized>5&lt;6</emphasized> </Para></Abstract><TemplateParameters><Parameter><Name>9&lt;10</Name><Discussion><Para> bbb</Para></Discussion></Parameter></TemplateParameters><Parameters><Parameter><Name>7&lt;8</Name><Direction isExplicit="0">in</Direction><Discussion><Para> aaa </Para></Discussion></Parameter></Parameters></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
-// CHECK-NEXT: (CXComment_InlineCommand CommandName=[a] RenderEmphasized Arg[0]=1<2)
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
-// CHECK-NEXT: (CXComment_InlineCommand CommandName=[e] RenderEmphasized Arg[0]=3<4)
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
-// CHECK-NEXT: (CXComment_InlineCommand CommandName=[em] RenderEmphasized Arg[0]=5<6)
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
-// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[7<8] ParamIndex=Invalid
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ aaa ])))
-// CHECK-NEXT: (CXComment_TParamCommand ParamName=[9<10] ParamPosition=Invalid
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ bbb]))))]
-// CHECK: annotate-comments.cpp:389:6: FunctionDecl=comment_to_html_conversion_31:{{.*}} FullCommentAsHTML=[<p class="para-brief"> \ @ &amp; $ # &lt; &gt; % &quot; . ::</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="389" column="6"><Name>comment_to_html_conversion_31</Name><USR>c:@F@comment_to_html_conversion_31#</USR><Declaration>void comment_to_html_conversion_31()</Declaration><Abstract><Para> \ @ &amp; $ # &lt; &gt; % &quot; . ::</Para></Abstract></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
-// CHECK-NEXT: (CXComment_Text Text=[\])
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
-// CHECK-NEXT: (CXComment_Text Text=[@])
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
-// CHECK-NEXT: (CXComment_Text Text=[&])
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
-// CHECK-NEXT: (CXComment_Text Text=[$])
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
-// CHECK-NEXT: (CXComment_Text Text=[#])
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
-// CHECK-NEXT: (CXComment_Text Text=[<])
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
-// CHECK-NEXT: (CXComment_Text Text=[>])
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
-// CHECK-NEXT: (CXComment_Text Text=[%])
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
-// CHECK-NEXT: (CXComment_Text Text=["])
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
-// CHECK-NEXT: (CXComment_Text Text=[.])
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
-// CHECK-NEXT: (CXComment_Text Text=[::])))]
-// CHECK: annotate-comments.cpp:392:6: FunctionDecl=comment_to_html_conversion_32:{{.*}} FullCommentAsHTML=[<p class="para-brief"> &amp; &lt; &gt; &quot;</p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="392" column="6"><Name>comment_to_html_conversion_32</Name><USR>c:@F@comment_to_html_conversion_32#</USR><Declaration>void comment_to_html_conversion_32()</Declaration><Abstract><Para> &amp; &lt; &gt; &quot;</Para></Abstract></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
-// CHECK-NEXT: (CXComment_Text Text=[&])
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
-// CHECK-NEXT: (CXComment_Text Text=[<])
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
-// CHECK-NEXT: (CXComment_Text Text=[>])
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
-// CHECK-NEXT: (CXComment_Text Text=["])))]
-// CHECK: annotate-comments.cpp:395:6: FunctionDecl=comment_to_html_conversion_33:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <em>0&lt;i</em></p>] FullCommentAsXML=[<Function file="{{[^"]+}}annotate-comments.cpp" line="395" column="6"><Name>comment_to_html_conversion_33</Name><USR>c:@F@comment_to_html_conversion_33#</USR><Declaration>void comment_to_html_conversion_33()</Declaration><Abstract><Para> <rawHTML><![CDATA[<em>]]></rawHTML>0&lt;i<rawHTML>&lt;/em&gt;</rawHTML></Para></Abstract></Function>]
-// CHECK-NEXT: CommentAST=[
-// CHECK-NEXT: (CXComment_FullComment
-// CHECK-NEXT: (CXComment_Paragraph
-// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
-// CHECK-NEXT: (CXComment_HTMLStartTag Name=[em])
-// CHECK-NEXT: (CXComment_Text Text=[0])
-// CHECK-NEXT: (CXComment_Text Text=[<])
-// CHECK-NEXT: (CXComment_Text Text=[i])
-// CHECK-NEXT: (CXComment_HTMLEndTag Name=[em])))]
-
-// CHECK: annotate-comments.cpp:398:7: ClassDecl=comment_to_xml_conversion_01:{{.*}} FullCommentAsXML=[<Class file="{{[^"]+}}annotate-comments.cpp" line="398" column="7"><Name>comment_to_xml_conversion_01</Name><USR>c:@C@comment_to_xml_conversion_01</USR><Declaration>class comment_to_xml_conversion_01 {\n}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Class>]
-// CHECK: annotate-comments.cpp:400:3: CXXConstructor=comment_to_xml_conversion_01:{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}annotate-comments.cpp" line="400" column="3"><Name>comment_to_xml_conversion_01</Name><USR>c:@C@comment_to_xml_conversion_01@F@comment_to_xml_conversion_01#I#</USR><Declaration></Declaration><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah.</Para></Discussion></Parameter></Parameters></Function>]
-// CHECK: annotate-comments.cpp:403:3: CXXDestructor=~comment_to_xml_conversion_01:{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}annotate-comments.cpp" line="403" column="3"><Name>~comment_to_xml_conversion_01</Name><USR>c:@C@comment_to_xml_conversion_01@F@~comment_to_xml_conversion_01#</USR><Declaration>void ~comment_to_xml_conversion_01()</Declaration><Abstract><Para> Aaa.</Para></Abstract></Function>]
-// CHECK: annotate-comments.cpp:406:7: CXXMethod=comment_to_xml_conversion_02:{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}annotate-comments.cpp" line="406" column="7"><Name>comment_to_xml_conversion_02</Name><USR>c:@C@comment_to_xml_conversion_01@F@comment_to_xml_conversion_02#I#</USR><Declaration>int comment_to_xml_conversion_02(int aaa)</Declaration><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah.</Para></Discussion></Parameter></Parameters></Function>]
-// CHECK: annotate-comments.cpp:409:14: CXXMethod=comment_to_xml_conversion_03:{{.*}} FullCommentAsXML=[<Function isClassMethod="1" file="{{[^"]+}}annotate-comments.cpp" line="409" column="14"><Name>comment_to_xml_conversion_03</Name><USR>c:@C@comment_to_xml_conversion_01@F@comment_to_xml_conversion_03#I#S</USR><Declaration>static int comment_to_xml_conversion_03(int aaa)</Declaration><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah.</Para></Discussion></Parameter></Parameters></Function>]
-// CHECK: annotate-comments.cpp:412:7: FieldDecl=comment_to_xml_conversion_04:{{.*}} FullCommentAsXML=[<Variable file="{{[^"]+}}annotate-comments.cpp" line="412" column="7"><Name>comment_to_xml_conversion_04</Name><USR>c:@C@comment_to_xml_conversion_01@FI@comment_to_xml_conversion_04</USR><Declaration>int comment_to_xml_conversion_04</Declaration><Abstract><Para> Aaa.</Para></Abstract></Variable>]
-// CHECK: annotate-comments.cpp:415:14: VarDecl=comment_to_xml_conversion_05:{{.*}} FullCommentAsXML=[<Variable file="{{[^"]+}}annotate-comments.cpp" line="415" column="14"><Name>comment_to_xml_conversion_05</Name><USR>c:@C@comment_to_xml_conversion_01@comment_to_xml_conversion_05</USR><Declaration>static int comment_to_xml_conversion_05</Declaration><Abstract><Para> Aaa.</Para></Abstract></Variable>]
-// CHECK: annotate-comments.cpp:418:8: CXXMethod=operator():{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}annotate-comments.cpp" line="418" column="8"><Name>operator()</Name><USR>c:@C@comment_to_xml_conversion_01@F@operator()#I#</USR><Declaration>void operator()(int aaa)</Declaration><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah.</Para></Discussion></Parameter></Parameters></Function>]
-// CHECK: annotate-comments.cpp:421:3: CXXConversion=operator _Bool:{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}annotate-comments.cpp" line="421" column="3"><Name>operator _Bool</Name><USR>c:@C@comment_to_xml_conversion_01@F@operator _Bool#</USR><Declaration>bool operator _Bool()</Declaration><Abstract><Para> Aaa.</Para></Abstract></Function>]
-// CHECK: annotate-comments.cpp:424:15: TypedefDecl=comment_to_xml_conversion_06:{{.*}} FullCommentAsXML=[<Typedef file="{{[^"]+}}annotate-comments.cpp" line="424" column="15"><Name>comment_to_xml_conversion_06</Name><USR>c:annotate-comments.cpp@8505@C@comment_to_xml_conversion_01@T@comment_to_xml_conversion_06</USR><Declaration>typedef int comment_to_xml_conversion_06</Declaration><Abstract><Para> Aaa.</Para></Abstract></Typedef>]
-// CHECK: annotate-comments.cpp:427:9: TypeAliasDecl=comment_to_xml_conversion_07:{{.*}} FullCommentAsXML=[<Typedef file="{{[^"]+}}annotate-comments.cpp" line="427" column="9"><Name>comment_to_xml_conversion_07</Name><USR>c:@C@comment_to_xml_conversion_01@comment_to_xml_conversion_07</USR><Declaration>using comment_to_xml_conversion_07 = int</Declaration><Abstract><Para> Aaa.</Para></Abstract></Typedef>]
-// CHECK: annotate-comments.cpp:434:3: UnexposedDecl=comment_to_xml_conversion_09:{{.*}} FullCommentAsXML=[<Typedef file="{{[^"]+}}annotate-comments.cpp" line="434" column="3"><Name>comment_to_xml_conversion_09</Name><USR>c:@C@comment_to_xml_conversion_01@comment_to_xml_conversion_09</USR><Declaration>template &lt;typename T&gt; using comment_to_xml_conversion_09 = comment_to_xml_conversion_08&lt;T, int&gt;</Declaration><Abstract><Para> Aaa.</Para></Abstract></Typedef>]
-// CHECK: annotate-comments.cpp:439:6: FunctionTemplate=comment_to_xml_conversion_10:{{.*}} FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}annotate-comments.cpp" line="439" column="6"><Name>comment_to_xml_conversion_10</Name><USR>c:@FT@&gt;2#T#Tcomment_to_xml_conversion_10#t0.0#t0.1#</USR><Declaration>template &lt;typename T = int, typename U = int&gt; void comment_to_xml_conversion_10(int aaa, int bbb)template &lt;typename T, typename U&gt; void comment_to_xml_conversion_10(T aaa, U bbb)</Declaration><Abstract><Para> Aaa.</Para></Abstract></Function>]
-// CHECK: annotate-comments.cpp:443:6: FunctionDecl=comment_to_xml_conversion_10:{{.*}} FullCommentAsXML=[<Function templateKind="specialization" file="{{[^"]+}}annotate-comments.cpp" line="443" column="6"><Name>comment_to_xml_conversion_10</Name><USR>c:@F@comment_to_xml_conversion_10&lt;#I#I&gt;#I#I#</USR><Declaration>void comment_to_xml_conversion_10(int aaa, int bbb)</Declaration><Abstract><Para> Aaa.</Para></Abstract></Function>]
-// CHECK: annotate-comments.cpp:447:7: ClassTemplate=comment_to_xml_conversion_11:{{.*}} FullCommentAsXML=[<Class templateKind="template" file="{{[^"]+}}annotate-comments.cpp" line="447" column="7"><Name>comment_to_xml_conversion_11</Name><USR>c:@CT&gt;2#T#T@comment_to_xml_conversion_11</USR><Declaration>template &lt;typename T = int, typename U = int&gt; class comment_to_xml_conversion_11 {\n}\ntemplate &lt;typename T, typename U&gt; class comment_to_xml_conversion_11 {\n}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Class>]
-// CHECK: annotate-comments.cpp:451:7: ClassTemplatePartialSpecialization=comment_to_xml_conversion_11:{{.*}} FullCommentAsXML=[<Class templateKind="partialSpecialization" file="{{[^"]+}}annotate-comments.cpp" line="451" column="7"><Name>comment_to_xml_conversion_11</Name><USR>c:@CP&gt;1#T@comment_to_xml_conversion_11&gt;#t0.0#I</USR><Declaration>class comment_to_xml_conversion_11 {\n}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Class>]
-// CHECK: annotate-comments.cpp:455:7: ClassDecl=comment_to_xml_conversion_11:{{.*}} FullCommentAsXML=[<Class templateKind="specialization" file="{{[^"]+}}annotate-comments.cpp" line="455" column="7"><Name>comment_to_xml_conversion_11</Name><USR>c:@C@comment_to_xml_conversion_11&gt;#I#I</USR><Declaration>class comment_to_xml_conversion_11 {\n}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Class>]
-// CHECK: annotate-comments.cpp:458:5: VarDecl=comment_to_xml_conversion_12:{{.*}} FullCommentAsXML=[<Variable file="{{[^"]+}}annotate-comments.cpp" line="458" column="5"><Name>comment_to_xml_conversion_12</Name><USR>c:@comment_to_xml_conversion_12</USR><Declaration>int comment_to_xml_conversion_12</Declaration><Abstract><Para> Aaa.</Para></Abstract></Variable>]
-// CHECK: annotate-comments.cpp:461:11: Namespace=comment_to_xml_conversion_13:{{.*}} FullCommentAsXML=[<Namespace file="{{[^"]+}}annotate-comments.cpp" line="461" column="11"><Name>comment_to_xml_conversion_13</Name><USR>c:@N@comment_to_xml_conversion_13</USR><Declaration>namespace comment_to_xml_conversion_13 {\n}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Namespace>]
-// CHECK: annotate-comments.cpp:463:13: Namespace=comment_to_xml_conversion_14:{{.*}} FullCommentAsXML=[<Namespace file="{{[^"]+}}annotate-comments.cpp" line="463" column="13"><Name>comment_to_xml_conversion_14</Name><USR>c:@N@comment_to_xml_conversion_13@N@comment_to_xml_conversion_14</USR><Declaration>namespace comment_to_xml_conversion_14 {\n}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Namespace>]
-// CHECK: annotate-comments.cpp:468:6: EnumDecl=comment_to_xml_conversion_15:{{.*}} FullCommentAsXML=[<Enum file="{{[^"]+}}annotate-comments.cpp" line="468" column="6"><Name>comment_to_xml_conversion_15</Name><USR>c:@E@comment_to_xml_conversion_15</USR><Declaration>enum comment_to_xml_conversion_15{{( : int)?}} {\n}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Enum>]
-// CHECK: annotate-comments.cpp:470:3: EnumConstantDecl=comment_to_xml_conversion_16:{{.*}} FullCommentAsXML=[<Variable file="{{[^"]+}}annotate-comments.cpp" line="470" column="3"><Name>comment_to_xml_conversion_16</Name><USR>c:@E@comment_to_xml_conversion_15@comment_to_xml_conversion_16</USR><Declaration>comment_to_xml_conversion_16</Declaration><Abstract><Para> Aaa.</Para></Abstract></Variable>]
-// CHECK: annotate-comments.cpp:474:12: EnumDecl=comment_to_xml_conversion_17:{{.*}} FullCommentAsXML=[<Enum file="{{[^"]+}}annotate-comments.cpp" line="474" column="12"><Name>comment_to_xml_conversion_17</Name><USR>c:@E@comment_to_xml_conversion_17</USR><Declaration>enum class comment_to_xml_conversion_17 : int {\n}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Enum>]
-// CHECK: annotate-comments.cpp:476:3: EnumConstantDecl=comment_to_xml_conversion_18:{{.*}} FullCommentAsXML=[<Variable file="{{[^"]+}}annotate-comments.cpp" line="476" column="3"><Name>comment_to_xml_conversion_18</Name><USR>c:@E@comment_to_xml_conversion_17@comment_to_xml_conversion_18</USR><Declaration>comment_to_xml_conversion_18</Declaration><Abstract><Para> Aaa.</Para></Abstract></Variable>]
diff --git a/test/Index/annotate-context-sensitive.cpp b/test/Index/annotate-context-sensitive.cpp
index 34e67a2..57e6783 100644
--- a/test/Index/annotate-context-sensitive.cpp
+++ b/test/Index/annotate-context-sensitive.cpp
@@ -27,7 +27,7 @@ struct Derived2 : Base2 {
// CHECK-OVERRIDE-FINAL: Keyword: "public" [6:23 - 6:29] C++ base class specifier=class Base:1:7 [access=public isVirtual=false]
// CHECK-OVERRIDE-FINAL: Identifier: "Base" [6:30 - 6:34] TypeRef=class Base:1:7
// CHECK-OVERRIDE-FINAL: Punctuation: "{" [6:35 - 6:36] ClassDecl=Derived:6:7 (Definition)
-// CHECK-OVERRIDE-FINAL: Keyword: "virtual" [7:3 - 7:10] ClassDecl=Derived:6:7 (Definition)
+// CHECK-OVERRIDE-FINAL: Keyword: "virtual" [7:3 - 7:10] CXXMethod=f:7:16 (virtual) [Overrides @3:16]
// CHECK-OVERRIDE-FINAL: Keyword: "void" [7:11 - 7:15] CXXMethod=f:7:16 (virtual) [Overrides @3:16]
// CHECK-OVERRIDE-FINAL: Identifier: "f" [7:16 - 7:17] CXXMethod=f:7:16 (virtual) [Overrides @3:16]
// CHECK-OVERRIDE-FINAL: Punctuation: "(" [7:17 - 7:18] CXXMethod=f:7:16 (virtual) [Overrides @3:16]
diff --git a/test/Index/annotate-deep-statements.cpp b/test/Index/annotate-deep-statements.cpp
index 32a48b7..79f2d39 100644
--- a/test/Index/annotate-deep-statements.cpp
+++ b/test/Index/annotate-deep-statements.cpp
@@ -3,6 +3,9 @@
// rdar://11979525
// Check that we don't get stack overflow trying to annotate an extremely deep AST.
+// AddressSanitizer increases stack usage.
+// XFAIL: asan
+
struct S {
S &operator()();
};
diff --git a/test/Index/annotate-module.m b/test/Index/annotate-module.m
index 3423f2b..33ca3f8 100644
--- a/test/Index/annotate-module.m
+++ b/test/Index/annotate-module.m
@@ -1,10 +1,10 @@
#include <DependsOnModule/DependsOnModule.h>
-@__experimental_modules_import DependsOnModule;
+@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: c-index-test -test-annotate-tokens=%s:2:1:5:1 %s -fmodules-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\)]]
@@ -17,14 +17,14 @@ int glob;
// 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: "import" [3:2 - 3:8] ModuleImport=DependsOnModule:3:1
+// CHECK-NEXT: Identifier: "DependsOnModule" [3:9 - 3:24] ModuleImport=DependsOnModule:3:1
+// CHECK-NEXT: Punctuation: ";" [3:24 - 3:25]
// 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: c-index-test -test-annotate-tokens=%S/../Modules/Inputs/Module.framework/Headers/Sub.h:1:1:3:1 %s -fmodules-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\)]]
diff --git a/test/Index/annotate-nested-name-specifier.cpp b/test/Index/annotate-nested-name-specifier.cpp
index c4f60e3..eddd215 100644
--- a/test/Index/annotate-nested-name-specifier.cpp
+++ b/test/Index/annotate-nested-name-specifier.cpp
@@ -340,7 +340,7 @@ struct X9 : X8 {
// CHECK: Punctuation: ")" [92:26 - 92:27] CallExpr=g:86:8
// Dependent name type
-// CHECK: Keyword: "typedef" [100:3 - 100:10] ClassTemplate=X5:98:8 (Definition)
+// CHECK: Keyword: "typedef" [100:3 - 100:10] TypedefDecl=iter_type:100:63 (Definition)
// CHECK: Keyword: "typename" [100:11 - 100:19] TypedefDecl=iter_type:100:63 (Definition)
// CHECK: Identifier: "outer_alias" [100:20 - 100:31] NamespaceRef=outer_alias:10:11
// CHECK: Punctuation: "::" [100:31 - 100:33] TypedefDecl=iter_type:100:63 (Definition)
@@ -354,7 +354,7 @@ struct X9 : X8 {
// CHECK: Identifier: "iterator" [100:54 - 100:62] TypedefDecl=iter_type:100:63 (Definition)
// CHECK: Identifier: "iter_type" [100:63 - 100:72] TypedefDecl=iter_type:100:63 (Definition)
-// CHECK: Keyword: "typedef" [101:3 - 101:10] ClassTemplate=X5:98:8 (Definition)
+// CHECK: Keyword: "typedef" [101:3 - 101:10] TypedefDecl=int_ptr_type:101:62 (Definition)
// CHECK: Keyword: "typename" [101:11 - 101:19] TypedefDecl=int_ptr_type:101:62 (Definition)
// CHECK: Identifier: "outer_alias" [101:20 - 101:31] NamespaceRef=outer_alias:10:11
// CHECK: Punctuation: "::" [101:31 - 101:33] TypedefDecl=int_ptr_type:101:62 (Definition)
@@ -386,7 +386,7 @@ struct X9 : X8 {
// CHECK: Punctuation: ">" [107:74 - 107:75] TypedefDecl=type1:107:76 (Definition)
// CHECK: Identifier: "type1" [107:76 - 107:81] TypedefDecl=type1:107:76 (Definition)
-// CHECK: Keyword: "typedef" [108:3 - 108:10] ClassTemplate=X6:105:8 (Definition)
+// CHECK: Keyword: "typedef" [108:3 - 108:10] TypedefDecl=type2:108:83 (Definition)
// CHECK: Keyword: "typename" [108:11 - 108:19] TypedefDecl=type2:108:83 (Definition)
// CHECK: Identifier: "outer_alias" [108:20 - 108:31] NamespaceRef=outer_alias:10:11
// CHECK: Punctuation: "::" [108:31 - 108:33] TypedefDecl=type2:108:83 (Definition)
@@ -406,7 +406,7 @@ struct X9 : X8 {
// CHECK: Identifier: "other" [108:77 - 108:82] TypedefDecl=type2:108:83 (Definition)
// CHECK: Identifier: "type2" [108:83 - 108:88] TypedefDecl=type2:108:83 (Definition)
-// CHECK: Keyword: "typedef" [109:3 - 109:10] ClassTemplate=X6:105:8 (Definition)
+// CHECK: Keyword: "typedef" [109:3 - 109:10] TypedefDecl=type3:109:73 (Definition)
// CHECK: Keyword: "class" [109:11 - 109:16] TypedefDecl=type3:109:73 (Definition)
// CHECK: Identifier: "outer_alias" [109:17 - 109:28] NamespaceRef=outer_alias:10:11
// CHECK: Punctuation: "::" [109:28 - 109:30] TypedefDecl=type3:109:73 (Definition)
@@ -444,7 +444,7 @@ struct X9 : X8 {
// CHECK: Identifier: "type4" [110:80 - 110:85] TypedefDecl=type4:110:80 (Definition)
// Template template arguments
-// CHECK: Keyword: "typedef" [126:3 - 126:10] ClassTemplate=X7:123:8 (Definition)
+// CHECK: Keyword: "typedef" [126:3 - 126:10] TypedefDecl=type:126:74 (Definition)
// CHECK: Identifier: "outer_alias" [126:11 - 126:22] NamespaceRef=outer_alias:10:11
// CHECK: Punctuation: "::" [126:22 - 126:24] TypedefDecl=type:126:74 (Definition)
// CHECK: Identifier: "inner" [126:24 - 126:29] NamespaceRef=inner:114:13
diff --git a/test/Index/annotate-tokens-cxx0x.cpp b/test/Index/annotate-tokens-cxx0x.cpp
index a126b85..49f7efb 100644
--- a/test/Index/annotate-tokens-cxx0x.cpp
+++ b/test/Index/annotate-tokens-cxx0x.cpp
@@ -13,6 +13,17 @@ void test() {
bool b2 = __is_trivially_constructible(Integer, Float, Bool);
}
+typedef int Int;
+
+class B {
+ virtual void foo(Int);
+};
+
+class S : public B {
+ virtual void foo(Int) override;
+};
+
+
// RUN: c-index-test -test-annotate-tokens=%s:1:1:5:1 -fno-delayed-template-parsing -std=c++11 %s | FileCheck %s
// CHECK: Identifier: "args" [3:20 - 3:24] SizeOfPackExpr=args:2:15
// CHECK: Identifier: "Args" [3:38 - 3:42] TypeRef=Args:1:22
@@ -25,3 +36,19 @@ void test() {
// CHECK-TRAIT: Identifier: "Float" [13:51 - 13:56] TypeRef=Float:11:17
// CHECK-TRAIT: Identifier: "Bool" [13:58 - 13:62] TypeRef=Bool:12:16
+// RUN: c-index-test -test-annotate-tokens=%s:16:1:24:1 -std=c++11 %s | FileCheck -check-prefix=CHECK-WITH-OVERRIDE %s
+// CHECK-WITH-OVERRIDE: Keyword: "virtual" [19:2 - 19:9] CXXMethod=foo:19:15 (virtual)
+// CHECK-WITH-OVERRIDE: Keyword: "void" [19:10 - 19:14] CXXMethod=foo:19:15 (virtual)
+// CHECK-WITH-OVERRIDE: Identifier: "foo" [19:15 - 19:18] CXXMethod=foo:19:15 (virtual)
+// CHECK-WITH-OVERRIDE: Punctuation: "(" [19:18 - 19:19] CXXMethod=foo:19:15 (virtual)
+// CHECK-WITH-OVERRIDE: Identifier: "Int" [19:19 - 19:22] TypeRef=Int:16:13
+// CHECK-WITH-OVERRIDE: Punctuation: ")" [19:22 - 19:23] ParmDecl=:19:22 (Definition)
+// CHECK-WITH-OVERRIDE: Punctuation: ";" [19:23 - 19:24] ClassDecl=B:18:7 (Definition)
+// CHECK-WITH-OVERRIDE: Keyword: "virtual" [23:3 - 23:10] CXXMethod=foo:23:16 (virtual) [Overrides @19:15]
+// CHECK-WITH-OVERRIDE: Keyword: "void" [23:11 - 23:15] CXXMethod=foo:23:16 (virtual) [Overrides @19:15]
+// CHECK-WITH-OVERRIDE: Identifier: "foo" [23:16 - 23:19] CXXMethod=foo:23:16 (virtual) [Overrides @19:15]
+// CHECK-WITH-OVERRIDE: Punctuation: "(" [23:19 - 23:20] CXXMethod=foo:23:16 (virtual) [Overrides @19:15]
+// CHECK-WITH-OVERRIDE: Identifier: "Int" [23:20 - 23:23] TypeRef=Int:16:13
+// CHECK-WITH-OVERRIDE: Punctuation: ")" [23:23 - 23:24] ParmDecl=:23:23 (Definition)
+// CHECK-WITH-OVERRIDE: Keyword: "override" [23:25 - 23:33] attribute(override)=
+// CHECK-WITH-OVERRIDE: Punctuation: ";" [23:33 - 23:34] ClassDecl=S:22:7 (Definition)
diff --git a/test/Index/annotate-tokens-pp.c b/test/Index/annotate-tokens-pp.c
index b37ab39..7da2d6f 100644
--- a/test/Index/annotate-tokens-pp.c
+++ b/test/Index/annotate-tokens-pp.c
@@ -30,12 +30,24 @@ void test() {
const char *fname = __FILE__;
-// RUN: c-index-test -test-annotate-tokens=%s:2:1:32:1 -I%S/Inputs %s | FileCheck %s
-// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-annotate-tokens=%s:2:1:32:1 -I%S/Inputs %s | FileCheck %s
+#define SOME_MACRO 3
+
+#ifdef SOME_MACRO
+#endif
+
+struct A
+{
+#ifdef SOME_MACRO
+ int x;
+#endif
+};
+
+// RUN: c-index-test -test-annotate-tokens=%s:2:1:44:1 -I%S/Inputs %s | FileCheck %s
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-annotate-tokens=%s:2:1:44:1 -I%S/Inputs %s | FileCheck %s
// CHECK: Punctuation: "#" [2:1 - 2:2] preprocessing directive=
// CHECK: Identifier: "define" [2:2 - 2:8] preprocessing directive=
// CHECK: Identifier: "STILL_NOTHING" [2:9 - 2:22] macro definition=STILL_NOTHING
-// CHECK: Identifier: "NOTHING" [2:23 - 2:30] macro definition=STILL_NOTHING
+// CHECK: Identifier: "NOTHING" [2:23 - 2:30] macro expansion=NOTHING:1:9
// CHECK: Punctuation: "(" [2:30 - 2:31] macro definition=STILL_NOTHING
// CHECK: Identifier: "honk" [2:31 - 2:35] macro definition=STILL_NOTHING
// CHECK: Punctuation: "," [2:35 - 2:36] macro definition=STILL_NOTHING
@@ -180,7 +192,7 @@ const char *fname = __FILE__;
// CHECK: Identifier: "x" [25:25 - 25:26] DeclRefExpr=x:24:7
// CHECK: Punctuation: "," [25:26 - 25:27]
// CHECK: Punctuation: "{" [25:28 - 25:29] CompoundStmt=
-// CHECK: Keyword: "int" [25:30 - 25:33] DeclStmt=
+// CHECK: Keyword: "int" [25:30 - 25:33] VarDecl=z:25:34 (Definition)
// CHECK: Identifier: "z" [25:34 - 25:35] VarDecl=z:25:34 (Definition)
// CHECK: Punctuation: "=" [25:36 - 25:37] VarDecl=z:25:34 (Definition)
// CHECK: Identifier: "x" [25:38 - 25:39] DeclRefExpr=x:24:7
@@ -196,3 +208,20 @@ const char *fname = __FILE__;
// CHECK: {{28:1.*inclusion directive=pragma-once.h.*multi-include guarded}}
// CHECK: {{29:1.*inclusion directive=guarded.h.*multi-include guarded}}
// CHECK: Identifier: "__FILE__" [31:21 - 31:29] macro expansion=__FILE__
+// CHECK: Punctuation: "#" [35:1 - 35:2] preprocessing directive=
+// CHECK: Identifier: "ifdef" [35:2 - 35:7] preprocessing directive=
+// CHECK: Identifier: "SOME_MACRO" [35:8 - 35:18] macro expansion=SOME_MACRO:33:9
+// CHECK: Punctuation: "#" [36:1 - 36:2] preprocessing directive=
+// CHECK: Identifier: "endif" [36:2 - 36:7] preprocessing directive=
+// CHECK: Keyword: "struct" [38:1 - 38:7] StructDecl=A:38:8 (Definition)
+// CHECK: Identifier: "A" [38:8 - 38:9] StructDecl=A:38:8 (Definition)
+// CHECK: Punctuation: "{" [39:1 - 39:2] StructDecl=A:38:8 (Definition)
+// CHECK: Punctuation: "#" [40:1 - 40:2] preprocessing directive=
+// CHECK: Identifier: "ifdef" [40:2 - 40:7] preprocessing directive=
+// CHECK: Identifier: "SOME_MACRO" [40:8 - 40:18] macro expansion=SOME_MACRO:33:9
+// CHECK: Keyword: "int" [41:3 - 41:6] FieldDecl=x:41:7 (Definition)
+// CHECK: Identifier: "x" [41:7 - 41:8] FieldDecl=x:41:7 (Definition)
+// CHECK: Punctuation: ";" [41:8 - 41:9] StructDecl=A:38:8 (Definition)
+// CHECK: Punctuation: "#" [42:1 - 42:2] preprocessing directive=
+// CHECK: Identifier: "endif" [42:2 - 42:7] preprocessing directive=
+// CHECK: Punctuation: "}" [43:1 - 43:2] StructDecl=A:38:8 (Definition)
diff --git a/test/Index/annotate-tokens.c b/test/Index/annotate-tokens.c
index 0b5f3d4..ffe3f63 100644
--- a/test/Index/annotate-tokens.c
+++ b/test/Index/annotate-tokens.c
@@ -33,7 +33,31 @@ enum Color g(int i, ...) {
}
}
-// RUN: c-index-test -test-annotate-tokens=%s:4:1:34:1 %s | FileCheck %s
+__attribute__((unavailable)) Int __attribute__((unavailable)) test() __attribute__((unavailable));
+
+#define HEADER() \
+ int x; \
+ int y; \
+ int z
+
+#define TYPE_INST(name, ...) \
+ static const struct { \
+ HEADER(); \
+ } name = { \
+ __VA_ARGS__ \
+ }
+
+void func1(void);
+
+TYPE_INST(Foo,
+ .x = 0,
+ .y = 1,
+ .z = 2,
+);
+
+void func2(void);
+
+// RUN: c-index-test -test-annotate-tokens=%s:4:1:37:1 %s | FileCheck %s
// CHECK: Identifier: "T" [4:3 - 4:4] TypeRef=T:1:13
// CHECK: Punctuation: "*" [4:4 - 4:5] VarDecl=t_ptr:4:6 (Definition)
// CHECK: Identifier: "t_ptr" [4:6 - 4:11] VarDecl=t_ptr:4:6 (Definition)
@@ -74,7 +98,7 @@ enum Color g(int i, ...) {
// CHECK: Punctuation: "&" [8:22 - 8:23] UnaryOperator=
// CHECK: Identifier: "x" [8:23 - 8:24] DeclRefExpr=x:7:12
// CHECK: Punctuation: ";" [8:24 - 8:25] DeclStmt=
-// CHECK: Keyword: "const" [9:3 - 9:8] DeclStmt=
+// CHECK: Keyword: "const" [9:3 - 9:8] VarDecl=hello:9:16 (Definition)
// CHECK: Keyword: "char" [9:9 - 9:13] VarDecl=hello:9:16 (Definition)
// CHECK: Punctuation: "*" [9:14 - 9:15] VarDecl=hello:9:16 (Definition)
// CHECK: Identifier: "hello" [9:16 - 9:21] VarDecl=hello:9:16 (Definition)
@@ -132,5 +156,71 @@ enum Color g(int i, ...) {
// CHECK: Identifier: "Red" [32:12 - 32:15] DeclRefExpr=Red:11:14
// CHECK: Punctuation: ";" [32:15 - 32:16] CompoundStmt=
+// CHECK: Keyword: "__attribute__" [36:1 - 36:14] FunctionDecl=test:36:63 (unavailable) (always unavailable: "")
+// CHECK: Punctuation: "(" [36:14 - 36:15] FunctionDecl=test:36:63 (unavailable) (always unavailable: "")
+// CHECK: Punctuation: "(" [36:15 - 36:16] FunctionDecl=test:36:63 (unavailable) (always unavailable: "")
+// CHECK: Identifier: "unavailable" [36:16 - 36:27] UnexposedAttr=
+// CHECK: Punctuation: ")" [36:27 - 36:28] FunctionDecl=test:36:63 (unavailable) (always unavailable: "")
+// CHECK: Punctuation: ")" [36:28 - 36:29] FunctionDecl=test:36:63 (unavailable) (always unavailable: "")
+// CHECK: Identifier: "Int" [36:30 - 36:33] TypeRef=Int:12:13
+// CHECK: Keyword: "__attribute__" [36:34 - 36:47] FunctionDecl=test:36:63 (unavailable) (always unavailable: "")
+// CHECK: Punctuation: "(" [36:47 - 36:48] FunctionDecl=test:36:63 (unavailable) (always unavailable: "")
+// CHECK: Punctuation: "(" [36:48 - 36:49] FunctionDecl=test:36:63 (unavailable) (always unavailable: "")
+// CHECK: Identifier: "unavailable" [36:49 - 36:60] UnexposedAttr=
+// CHECK: Punctuation: ")" [36:60 - 36:61] FunctionDecl=test:36:63 (unavailable) (always unavailable: "")
+// CHECK: Punctuation: ")" [36:61 - 36:62] FunctionDecl=test:36:63 (unavailable) (always unavailable: "")
+// CHECK: Identifier: "test" [36:63 - 36:67] FunctionDecl=test:36:63 (unavailable) (always unavailable: "")
+// CHECK: Punctuation: "(" [36:67 - 36:68] FunctionDecl=test:36:63 (unavailable) (always unavailable: "")
+// CHECK: Punctuation: ")" [36:68 - 36:69] FunctionDecl=test:36:63 (unavailable) (always unavailable: "")
+// CHECK: Keyword: "__attribute__" [36:70 - 36:83] FunctionDecl=test:36:63 (unavailable) (always unavailable: "")
+// CHECK: Punctuation: "(" [36:83 - 36:84] FunctionDecl=test:36:63 (unavailable) (always unavailable: "")
+// CHECK: Punctuation: "(" [36:84 - 36:85] FunctionDecl=test:36:63 (unavailable) (always unavailable: "")
+// CHECK: Identifier: "unavailable" [36:85 - 36:96] UnexposedAttr=
+// CHECK: Punctuation: ")" [36:96 - 36:97] FunctionDecl=test:36:63 (unavailable) (always unavailable: "")
+// CHECK: Punctuation: ")" [36:97 - 36:98] FunctionDecl=test:36:63 (unavailable) (always unavailable: "")
+// CHECK: Punctuation: ";" [36:98 - 36:99]
+
// RUN: c-index-test -test-annotate-tokens=%s:4:1:165:32 %s | FileCheck %s
// RUN: c-index-test -test-annotate-tokens=%s:4:1:165:38 %s | FileCheck %s
+
+// RUN: c-index-test -test-annotate-tokens=%s:50:1:55:1 %s | FileCheck %s -check-prefix=CHECK-RANGE1
+// CHECK-RANGE1: Keyword: "void" [50:1 - 50:5] FunctionDecl=func1:50:6
+// CHECK-RANGE1: Identifier: "func1" [50:6 - 50:11] FunctionDecl=func1:50:6
+// CHECK-RANGE1: Punctuation: "(" [50:11 - 50:12] FunctionDecl=func1:50:6
+// CHECK-RANGE1: Keyword: "void" [50:12 - 50:16] FunctionDecl=func1:50:6
+// CHECK-RANGE1: Punctuation: ")" [50:16 - 50:17] FunctionDecl=func1:50:6
+// CHECK-RANGE1: Punctuation: ";" [50:17 - 50:18]
+// CHECK-RANGE1: Identifier: "TYPE_INST" [52:1 - 52:10] macro expansion=TYPE_INST:43:9
+// CHECK-RANGE1: Punctuation: "(" [52:10 - 52:11]
+// CHECK-RANGE1: Identifier: "Foo" [52:11 - 52:14] VarDecl=Foo:52:11 (Definition)
+// CHECK-RANGE1: Punctuation: "," [52:14 - 52:15]
+// CHECK-RANGE1: Punctuation: "." [53:5 - 53:6] UnexposedExpr=
+// CHECK-RANGE1: Identifier: "x" [53:6 - 53:7] MemberRef=x:52:1
+// CHECK-RANGE1: Punctuation: "=" [53:8 - 53:9] UnexposedExpr=
+// CHECK-RANGE1: Literal: "0" [53:10 - 53:11] IntegerLiteral=
+// CHECK-RANGE1: Punctuation: "," [53:11 - 53:12] InitListExpr=
+// CHECK-RANGE1: Punctuation: "." [54:5 - 54:6] UnexposedExpr=
+// CHECK-RANGE1: Identifier: "y" [54:6 - 54:7] MemberRef=y:52:1
+// CHECK-RANGE1: Punctuation: "=" [54:8 - 54:9] UnexposedExpr=
+// CHECK-RANGE1: Literal: "1" [54:10 - 54:11] IntegerLiteral=
+// CHECK-RANGE1: Punctuation: "," [54:11 - 54:12] InitListExpr=
+
+// RUN: c-index-test -test-annotate-tokens=%s:54:1:59:1 %s | FileCheck %s -check-prefix=CHECK-RANGE2
+// CHECK-RANGE2: Punctuation: "." [54:5 - 54:6] UnexposedExpr=
+// CHECK-RANGE2: Identifier: "y" [54:6 - 54:7] MemberRef=y:52:1
+// CHECK-RANGE2: Punctuation: "=" [54:8 - 54:9] UnexposedExpr=
+// CHECK-RANGE2: Literal: "1" [54:10 - 54:11] IntegerLiteral=
+// CHECK-RANGE2: Punctuation: "," [54:11 - 54:12] InitListExpr=
+// CHECK-RANGE2: Punctuation: "." [55:5 - 55:6] UnexposedExpr=
+// CHECK-RANGE2: Identifier: "z" [55:6 - 55:7] MemberRef=z:52:1
+// CHECK-RANGE2: Punctuation: "=" [55:8 - 55:9] UnexposedExpr=
+// CHECK-RANGE2: Literal: "2" [55:10 - 55:11] IntegerLiteral=
+// CHECK-RANGE2: Punctuation: "," [55:11 - 55:12] InitListExpr=
+// CHECK-RANGE2: Punctuation: ")" [56:1 - 56:2]
+// CHECK-RANGE2: Punctuation: ";" [56:2 - 56:3]
+// CHECK-RANGE2: Keyword: "void" [58:1 - 58:5] FunctionDecl=func2:58:6
+// CHECK-RANGE2: Identifier: "func2" [58:6 - 58:11] FunctionDecl=func2:58:6
+// CHECK-RANGE2: Punctuation: "(" [58:11 - 58:12] FunctionDecl=func2:58:6
+// CHECK-RANGE2: Keyword: "void" [58:12 - 58:16] FunctionDecl=func2:58:6
+// CHECK-RANGE2: Punctuation: ")" [58:16 - 58:17] FunctionDecl=func2:58:6
+// CHECK-RANGE2: Punctuation: ";" [58:17 - 58:18]
diff --git a/test/Index/annotate-tokens.m b/test/Index/annotate-tokens.m
index 1a48293..7e888e3 100644
--- a/test/Index/annotate-tokens.m
+++ b/test/Index/annotate-tokens.m
@@ -480,7 +480,7 @@ static Rdar8595462_A * Rdar8595462_staticVar;
// CHECK: Identifier: "localVar" [100:10 - 100:18] DeclRefExpr=localVar:99:19
// CHECK: Punctuation: ";" [100:18 - 100:19] CompoundStmt=
// CHECK: Punctuation: "}" [101:1 - 101:2] CompoundStmt=
-// CHECK: Keyword: "static" [102:1 - 102:7] ObjCImplementationDecl=Rdar8595462_B:97:17 (Definition)
+// CHECK: Keyword: "static" [102:1 - 102:7] VarDecl=Rdar8595462_staticVar:102:24
// CHECK: Identifier: "Rdar8595462_A" [102:8 - 102:21] ObjCClassRef=Rdar8595462_A:93:8
// CHECK: Punctuation: "*" [102:22 - 102:23] VarDecl=Rdar8595462_staticVar:102:24
// CHECK: Identifier: "Rdar8595462_staticVar" [102:24 - 102:45] VarDecl=Rdar8595462_staticVar:102:24
diff --git a/test/Index/c-index-api-loadTU-test.m b/test/Index/c-index-api-loadTU-test.m
index 7520330..b0fb71e 100644
--- a/test/Index/c-index-api-loadTU-test.m
+++ b/test/Index/c-index-api-loadTU-test.m
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fblocks -emit-pch -x objective-c %s -o %t.ast
-// RUN: c-index-test -test-load-tu %t.ast all | FileCheck %s
+// RUN: c-index-test -test-load-tu %t.ast all > %t 2>&1 && FileCheck --input-file=%t %s
@interface Foo
{
@@ -77,13 +77,14 @@ struct X0 {};
// CHECK: c-index-api-loadTU-test.m:4:12: ObjCInterfaceDecl=Foo:4:12 Extent=[4:1 - 12:5]
// CHECK: c-index-api-loadTU-test.m:6:32: ObjCIvarDecl=myoutlet:6:32 (Definition) Extent=[6:3 - 6:40]
-// CHECK: <invalid loc>:0:0: attribute(iboutlet)=
+// CHECK: <invalid loc>:0:0: attribute(iboutlet)= Extent=[6:18 - 6:26]
// CHECK: c-index-api-loadTU-test.m:6:29: TypeRef=id:0:0 Extent=[6:29 - 6:31]
// CHECK: c-index-api-loadTU-test.m:8:36: ObjCInstanceMethodDecl=myMessage::8:36 Extent=[8:1 - 8:54]
-// CHECK: <invalid loc>:0:0: attribute(ibaction)=
+// CHECK: <invalid loc>:0:0: attribute(ibaction)= Extent=[8:25 - 8:33]
// CHECK: c-index-api-loadTU-test.m:8:50: ParmDecl=msg:8:50 (Definition) Extent=[8:47 - 8:53]
// CHECK: c-index-api-loadTU-test.m:8:47: TypeRef=id:0:0 Extent=[8:47 - 8:49]
-// CHECK: c-index-api-loadTU-test.m:9:3: ObjCInstanceMethodDecl=foo:9:3 (deprecated) (always deprecated: "") Extent=[9:1 - 9:35]
+// CHECK: c-index-api-loadTU-test.m:9:3: ObjCInstanceMethodDecl=foo:9:3 (deprecated) (always deprecated: "") Extent=[9:1 - 9:35]
+// CHECK: <invalid loc>:0:0: UnexposedAttr= Extent=[9:22 - 9:32]
// CHECK: c-index-api-loadTU-test.m:10:3: ObjCClassMethodDecl=fooC:10:3 Extent=[10:1 - 10:8]
// CHECK: c-index-api-loadTU-test.m:14:12: ObjCInterfaceDecl=Bar:14:12 Extent=[14:1 - 18:5]
// CHECK: c-index-api-loadTU-test.m:14:18: ObjCSuperClassRef=Foo:4:12 Extent=[14:18 - 14:21]
@@ -108,45 +109,57 @@ struct X0 {};
// CHECK: c-index-api-loadTU-test.m:46:5: FunctionDecl=main:46:5 (Definition) Extent=[46:1 - 55:2]
// CHECK: c-index-api-loadTU-test.m:46:15: ParmDecl=argc:46:15 (Definition) Extent=[46:11 - 46:19]
// CHECK: c-index-api-loadTU-test.m:46:34: ParmDecl=argv:46:34 (Definition) Extent=[46:21 - 46:40]
+// CHECK: c-index-api-loadTU-test.m:46:42: CompoundStmt= Extent=[46:42 - 55:2]
+// CHECK: c-index-api-loadTU-test.m:47:2: DeclStmt= Extent=[47:2 - 47:12]
// CHECK: c-index-api-loadTU-test.m:47:8: VarDecl=bee:47:8 (Definition) Extent=[47:2 - 47:11]
// CHECK: c-index-api-loadTU-test.m:47:2: ObjCClassRef=Baz:33:12 Extent=[47:2 - 47:5]
+// CHECK: c-index-api-loadTU-test.m:48:2: DeclStmt= Extent=[48:2 - 48:19]
// CHECK: c-index-api-loadTU-test.m:48:5: VarDecl=a:48:5 (Definition) Extent=[48:2 - 48:18]
// CHECK: c-index-api-loadTU-test.m:48:2: TypeRef=id:0:0 Extent=[48:2 - 48:4]
// CHECK: c-index-api-loadTU-test.m:48:9: ObjCMessageExpr=foo:9:3 Extent=[48:9 - 48:18]
+// CHECK: c-index-api-loadTU-test.m:48:10: UnexposedExpr=bee:47:8 Extent=[48:10 - 48:13]
// CHECK: c-index-api-loadTU-test.m:48:10: DeclRefExpr=bee:47:8 Extent=[48:10 - 48:13]
+// CHECK: c-index-api-loadTU-test.m:49:2: DeclStmt= Extent=[49:2 - 49:27]
// CHECK: c-index-api-loadTU-test.m:49:12: VarDecl=c:49:12 (Definition) Extent=[49:2 - 49:26]
// CHECK: c-index-api-loadTU-test.m:49:2: TypeRef=id:0:0 Extent=[49:2 - 49:4]
// CHECK: c-index-api-loadTU-test.m:49:6: ObjCProtocolRef=SubP:29:11 Extent=[49:6 - 49:10]
// CHECK: c-index-api-loadTU-test.m:49:16: UnexposedExpr=fooC:10:3 Extent=[49:16 - 49:26]
// CHECK: c-index-api-loadTU-test.m:49:16: ObjCMessageExpr=fooC:10:3 Extent=[49:16 - 49:26]
// CHECK: c-index-api-loadTU-test.m:49:17: ObjCClassRef=Foo:4:12 Extent=[49:17 - 49:20]
+// CHECK: c-index-api-loadTU-test.m:50:2: DeclStmt= Extent=[50:2 - 50:15]
// CHECK: c-index-api-loadTU-test.m:50:13: VarDecl=d:50:13 (Definition) Extent=[50:2 - 50:14]
// CHECK: c-index-api-loadTU-test.m:50:2: TypeRef=id:0:0 Extent=[50:2 - 50:4]
// CHECK: c-index-api-loadTU-test.m:50:6: ObjCProtocolRef=Proto:25:11 Extent=[50:6 - 50:11]
// CHECK: c-index-api-loadTU-test.m:51:2: BinaryOperator= Extent=[51:2 - 51:7]
// CHECK: c-index-api-loadTU-test.m:51:2: DeclRefExpr=d:50:13 Extent=[51:2 - 51:3]
// CHECK: c-index-api-loadTU-test.m:51:6: UnexposedExpr=c:49:12 Extent=[51:6 - 51:7]
+// CHECK: c-index-api-loadTU-test.m:51:6: UnexposedExpr=c:49:12 Extent=[51:6 - 51:7]
// CHECK: c-index-api-loadTU-test.m:51:6: DeclRefExpr=c:49:12 Extent=[51:6 - 51:7]
// CHECK: c-index-api-loadTU-test.m:52:2: ObjCMessageExpr=pMethod:26:3 Extent=[52:2 - 52:13]
+// CHECK: c-index-api-loadTU-test.m:52:3: UnexposedExpr=d:50:13 Extent=[52:3 - 52:4]
// CHECK: c-index-api-loadTU-test.m:52:3: DeclRefExpr=d:50:13 Extent=[52:3 - 52:4]
// CHECK: c-index-api-loadTU-test.m:53:2: ObjCMessageExpr=catMethodWithFloat::21:9 Extent=[53:2 - 53:44]
+// CHECK: c-index-api-loadTU-test.m:53:3: UnexposedExpr=bee:47:8 Extent=[53:3 - 53:6]
// CHECK: c-index-api-loadTU-test.m:53:3: DeclRefExpr=bee:47:8 Extent=[53:3 - 53:6]
// CHECK: c-index-api-loadTU-test.m:53:26: ObjCMessageExpr=floatMethod:22:11 Extent=[53:26 - 53:43]
+// CHECK: c-index-api-loadTU-test.m:53:27: UnexposedExpr=bee:47:8 Extent=[53:27 - 53:30]
// CHECK: c-index-api-loadTU-test.m:53:27: DeclRefExpr=bee:47:8 Extent=[53:27 - 53:30]
// CHECK: c-index-api-loadTU-test.m:54:3: CallExpr=main:46:5 Extent=[54:3 - 54:37]
// CHECK: c-index-api-loadTU-test.m:54:3: UnexposedExpr=main:46:5 Extent=[54:3 - 54:7]
// CHECK: c-index-api-loadTU-test.m:54:3: DeclRefExpr=main:46:5 Extent=[54:3 - 54:7]
// CHECK: c-index-api-loadTU-test.m:54:8: DeclRefExpr=someEnum:43:3 Extent=[54:8 - 54:16]
// CHECK: c-index-api-loadTU-test.m:54:18: CStyleCastExpr= Extent=[54:18 - 54:36]
+// CHECK: c-index-api-loadTU-test.m:54:33: UnexposedExpr=bee:47:8 Extent=[54:33 - 54:36]
// CHECK: c-index-api-loadTU-test.m:54:33: DeclRefExpr=bee:47:8 Extent=[54:33 - 54:36]
// CHECK: c-index-api-loadTU-test.m:62:12: ObjCInterfaceDecl=TestAttributes:62:12 Extent=[62:1 - 67:5]
-// CHECK: c-index-api-loadTU-test.m:63:15: ObjCIvarDecl=anOutlet:63:15 (Definition) Extent=[58:18 - 63:23]
-// CHECK: <invalid loc>:0:0: attribute(iboutlet)=
-// CHECK: c-index-api-loadTU-test.m:64:29: ObjCIvarDecl=anOutletCollection:64:29 (Definition) Extent=[59:39 - 64:47]
-// CHECK: <invalid loc>:0:0: attribute(iboutletcollection)= [IBOutletCollection=ObjCObjectPointer]
+// CHECK: c-index-api-loadTU-test.m:63:15: ObjCIvarDecl=anOutlet:63:15 (Definition) Extent=[63:3 - 63:23]
+// CHECK: <invalid loc>:0:0: attribute(iboutlet)= Extent=[63:3 - 63:11]
+// CHECK: c-index-api-loadTU-test.m:63:12: TypeRef=id:0:0 Extent=[63:12 - 63:14]
+// CHECK: c-index-api-loadTU-test.m:64:29: ObjCIvarDecl=anOutletCollection:64:29 (Definition) Extent=[64:3 - 64:47]
+// CHECK: <invalid loc>:0:0: attribute(iboutletcollection)= [IBOutletCollection=ObjCObjectPointer] Extent=[64:3 - 64:25]
// CHECK: c-index-api-loadTU-test.m:64:26: TypeRef=id:0:0 Extent=[64:26 - 64:28]
// CHECK: c-index-api-loadTU-test.m:66:14: ObjCInstanceMethodDecl=actionMethod::66:14 Extent=[66:1 - 66:35]
-// CHECK: <invalid loc>:0:0: attribute(ibaction)=
+// CHECK: <invalid loc>:0:0: attribute(ibaction)= Extent=[66:4 - 66:12]
// CHECK: c-index-api-loadTU-test.m:66:31: ParmDecl=arg:66:31 (Definition) Extent=[66:28 - 66:34]
// CHECK: c-index-api-loadTU-test.m:66:28: TypeRef=id:0:0 Extent=[66:28 - 66:30]
// CHECK: c-index-api-loadTU-test.m:69:16: StructDecl=X0:69:16 Extent=[69:9 - 69:18]
@@ -154,10 +167,11 @@ struct X0 {};
// CHECK: c-index-api-loadTU-test.m:69:16: TypeRef=struct X0:71:8 Extent=[69:16 - 69:18]
// CHECK: c-index-api-loadTU-test.m:70:8: StructDecl=X0:70:8 Extent=[70:1 - 70:10]
// CHECK: c-index-api-loadTU-test.m:71:8: StructDecl=X0:71:8 (Definition) Extent=[71:1 - 71:14]
-
-// CHECK: <invalid loc>:0:0: attribute(iboutlet)=
+// CHECK: c-index-api-loadTU-test.m:73:12: ObjCCategoryDecl=:73:12 Extent=[73:1 - 76:5]
+// CHECK: c-index-api-loadTU-test.m:73:12: ObjCClassRef=TestAttributes:62:12 Extent=[73:12 - 73:26]
+// CHECK: c-index-api-loadTU-test.m:75:32: ObjCPropertyDecl=anotherOutlet:75:32 Extent=[75:1 - 75:45]
+// CHECK: <invalid loc>:0:0: attribute(iboutlet)= Extent=[75:20 - 75:28]
// CHECK: c-index-api-loadTU-test.m:75:29: TypeRef=id:0:0 Extent=[75:29 - 75:31]
// CHECK: c-index-api-loadTU-test.m:75:32: ObjCInstanceMethodDecl=anotherOutlet:75:32 Extent=[75:32 - 75:45]
// CHECK: c-index-api-loadTU-test.m:75:32: ObjCInstanceMethodDecl=setAnotherOutlet::75:32 Extent=[75:32 - 75:45]
// CHECK: c-index-api-loadTU-test.m:75:32: ParmDecl=anotherOutlet:75:32 (Definition) Extent=[75:32 - 75:45]
-
diff --git a/test/Index/c-index-getCursor-pp.c b/test/Index/c-index-getCursor-pp.c
index 01b0a69..8efaaf2 100644
--- a/test/Index/c-index-getCursor-pp.c
+++ b/test/Index/c-index-getCursor-pp.c
@@ -1,6 +1,6 @@
#define OBSCURE(X) X
#define DECORATION
-
+#define FNM(X) OBSCURE(X)
typedef int T;
void OBSCURE(func)(int x) {
OBSCURE(T) DECORATION value;
@@ -17,6 +17,14 @@ const char *fname = __FILE__;
#include <a.h>
+#ifdef OBSCURE
+#endif
+
+#if defined(OBSCURE)
+#endif
+
+#define C(A) A
+
// 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
@@ -35,9 +43,21 @@ const char *fname = __FILE__;
// 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
+// RUN: c-index-test -cursor-at=%s:20:10 -cursor-at=%s:23:15 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-10 %s
+// CHECK-10: 20:8 macro expansion=OBSCURE
+// CHECK-10: 23:13 macro expansion=OBSCURE
+
+// RUN: c-index-test -cursor-at=%s:3:20 -cursor-at=%s:12:14 \
+// RUN: -cursor-at=%s:26:11 -cursor-at=%s:26:14 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-IN-MACRODEF %s
+// CHECK-IN-MACRODEF: 3:16 macro expansion=OBSCURE
+// CHECK-IN-MACRODEF: 12:14 macro expansion=A
+// CHECK-IN-MACRODEF: 26:9 macro definition=C
+// CHECK-IN-MACRODEF: 26:9 macro definition=C
// 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
// RUN: env CINDEXTEST_EDITING=1 c-index-test -cursor-at=%s:2:14 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-2 %s
// RUN: env CINDEXTEST_EDITING=1 c-index-test -cursor-at=%s:5:7 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-3 %s
// RUN: env CINDEXTEST_EDITING=1 c-index-test -cursor-at=%s:9:10 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-6 %s
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -cursor-at=%s:3:20 -cursor-at=%s:12:14 \
+// RUN: -cursor-at=%s:26:11 -cursor-at=%s:26:14 -I%S/Inputs %s | FileCheck -check-prefix=CHECK-IN-MACRODEF %s
diff --git a/test/Index/c-index-getCursor-test.m b/test/Index/c-index-getCursor-test.m
index bae5979..c179902 100644
--- a/test/Index/c-index-getCursor-test.m
+++ b/test/Index/c-index-getCursor-test.m
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fblocks -emit-pch -x objective-c %s -detailed-preprocessing-record -o %t.ast
-// RUN: c-index-test -test-file-scan %t.ast %s | FileCheck %s
+// RUN: c-index-test -test-file-scan %t.ast %s > %t 2>&1 && FileCheck --input-file=%t %s
@interface Foo
{
}
diff --git a/test/Index/code-completion-skip-bodies.cpp b/test/Index/code-completion-skip-bodies.cpp
index 67b2196..b7570b6 100644
--- a/test/Index/code-completion-skip-bodies.cpp
+++ b/test/Index/code-completion-skip-bodies.cpp
@@ -11,10 +11,10 @@ void func(S *s) {
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}
+// RUN: c-index-test -code-completion-at=%s:11:6 %s 2> %t.stderr | FileCheck %s --check-prefix=STDOUT
+// RUN: FileCheck --input-file=%t.stderr --check-prefix=STDERR %s
-// FIXME: Investigating
-// XFAIL: cygwin,mingw32,win32
+// STDOUT: FieldDecl:{ResultType int}{TypedText x}
+
+// STDERR-NOT: error: use of undeclared identifier 'undeclared1'
+// STDERR: error: use of undeclared identifier 'undeclared2'
diff --git a/test/Index/codecompletion-chained.cpp b/test/Index/codecompletion-chained.cpp
new file mode 100644
index 0000000..93e832f
--- /dev/null
+++ b/test/Index/codecompletion-chained.cpp
@@ -0,0 +1,33 @@
+
+// <rdar://12889089>
+
+#ifndef HEADER1
+#define HEADER1
+
+// CHECK-TU: FunctionDecl:{ResultType void}{TypedText foo}
+void foo();
+
+namespace Cake {
+// CHECK-NAMESPACE: FunctionDecl:{ResultType void}{TypedText lie}
+void lie();
+}
+
+#elif !defined(HEADER2)
+#define HEADER2
+
+namespace Cake {
+extern int Baz;
+}
+
+#else
+
+void func() {
+Cake::
+}
+
+#endif
+
+// RUN: c-index-test -write-pch %t1.h.pch %s
+// RUN: c-index-test -write-pch %t2.h.pch %s -include %t1.h
+// RUN: c-index-test -code-completion-at=%s:25:1 %s -include %t2.h | FileCheck -check-prefix=CHECK-TU %s
+// RUN: c-index-test -code-completion-at=%s:25:7 %s -include %t2.h | FileCheck -check-prefix=CHECK-NAMESPACE %s
diff --git a/test/Index/comment-c-decls.c b/test/Index/comment-c-decls.c
new file mode 100644
index 0000000..371e453
--- /dev/null
+++ b/test/Index/comment-c-decls.c
@@ -0,0 +1,104 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: c-index-test -test-load-source all -comments-xml-schema=%S/../../bindings/xml/comment-xml-schema.rng -target x86_64-apple-darwin10 %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
+// rdar://12378714
+
+/**
+ * \brief Aaa.
+*/
+int global_function();
+// CHECK: <Declaration>int global_function()</Declaration>
+
+/**
+ * \param x1 Aaa.
+*/
+extern void external_function(int x1);
+// CHECK: <Declaration>extern void external_function(int x1)</Declaration>
+
+/**
+ * \brief global variable;
+*/
+int global_variable;
+// CHECK: <Declaration>int global_variable</Declaration>
+
+/**
+ * \brief local variable;
+*/
+static int static_variable;
+// CHECK: <Declaration>static int static_variable</Declaration>
+
+/**
+ * \brief external variable
+*/
+extern int external_variable;
+// CHECK: <Declaration>extern int external_variable</Declaration>
+
+int global_function() {
+ /**
+ * \brief a local variable
+ */
+ int local = 10;
+ return local;
+}
+// CHECK: <Declaration>int global_function()</Declaration>
+// CHECK: <Declaration>int local = 10</Declaration>
+
+/**
+ * \brief initialized decl.
+*/
+int initialized_global = 100;
+// CHECK: <Declaration>int initialized_global = 100</Declaration>
+
+/**
+ * \brief typedef example
+*/
+typedef int INT_T;
+// CHECK: <Declaration>typedef int INT_T</Declaration>
+
+/**
+ * \brief aggregate type example
+*/
+struct S {
+/**
+ * \brief iS1;
+*/
+ int iS1;
+/**
+ * \brief dS1;
+*/
+ double dS1;
+};
+// CHECK: <Declaration>struct S {}</Declaration>
+// CHECK: <Declaration>int iS1</Declaration>
+// CHECK: <Declaration>double dS1</Declaration>
+
+/**
+ * \brief enum e;
+*/
+enum e {
+ One,
+/**
+ * \brief Two;
+*/
+ Two,
+ Three
+};
+// CHECK: <Declaration>enum e {}</Declaration>
+// CHECK: <Declaration>Two</Declaration>
+
+/**
+ *\brief block declaration
+*/
+int (^Block) (int i, int j);
+// CHECK: <Declaration>int (^Block)(int, int)</Declaration>
+
+/**
+ *\brief block declaration
+*/
+int (^Block1) (int i, int j) = ^(int i, int j) { return i + j; };
+// CHECK: <Declaration>int (^Block1)(int, int) = ^(int i, int j) {}</Declaration>
diff --git a/test/Index/comment-cplus-decls.cpp b/test/Index/comment-cplus-decls.cpp
new file mode 100644
index 0000000..de1c2c5
--- /dev/null
+++ b/test/Index/comment-cplus-decls.cpp
@@ -0,0 +1,171 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: c-index-test -test-load-source all -comments-xml-schema=%S/../../bindings/xml/comment-xml-schema.rng -target x86_64-apple-darwin10 %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
+// rdar://12378714
+
+/**
+ * \brief plain c++ class
+*/
+class Test
+{
+public:
+/**
+ * \brief plain c++ constructor
+*/
+ Test () : reserved (new data()) {}
+
+/**
+ * \brief plain c++ member function
+*/
+ unsigned getID() const
+ {
+ return reserved->objectID;
+ }
+/**
+ * \brief plain c++ destructor
+*/
+ ~Test () {}
+protected:
+ struct data {
+ unsigned objectID;
+ };
+/**
+ * \brief plain c++ data field
+*/
+ data* reserved;
+};
+// CHECK: <Declaration>class Test {}</Declaration>
+// CHECK: <Declaration>Test() : reserved(new Test::data())</Declaration>
+// CHECK: <Declaration>unsigned int getID() const</Declaration>
+// CHECK: <Declaration>void ~Test()</Declaration>
+// CHECK: <Declaration>Test::data *reserved</Declaration>
+
+
+class S {
+/**
+ * \brief Aaa
+*/
+ friend class Test;
+/**
+ * \brief Bbb
+*/
+ friend void foo() {}
+
+/**
+ * \brief Ccc
+*/
+ friend int int_func();
+
+/**
+ * \brief Ddd
+*/
+ friend bool operator==(const Test &, const Test &);
+
+/**
+ * \brief Eee
+*/
+template <typename T> friend void TemplateFriend();
+
+/**
+ * \brief Eee
+*/
+ template <typename T> friend class TemplateFriendClass;
+
+};
+// CHECK: <Declaration>friend class Test</Declaration>
+// CHECK: <Declaration>friend void foo()</Declaration>
+// CHECK: <Declaration>friend int int_func()</Declaration>
+// CHECK: <Declaration>friend bool operator==(const Test &amp;, const Test &amp;)</Declaration>
+// CHECK: <Declaration>friend template &lt;typename T&gt; void TemplateFriend()</Declaration>
+// CHECK: <Declaration>friend template &lt;typename T&gt; class TemplateFriendClass</Declaration>
+
+namespace test0 {
+ namespace ns {
+ void f(int);
+ }
+
+ struct A {
+/**
+ * \brief Fff
+*/
+ friend void ns::f(int a);
+ };
+}
+// CHECK: <Declaration>friend void f(int a)</Declaration>
+
+namespace test1 {
+ template <class T> struct Outer {
+ void foo(T);
+ struct Inner {
+/**
+ * \brief Ggg
+*/
+ friend void Outer::foo(T);
+ };
+ };
+}
+// CHECK: <Declaration>friend void foo(T)</Declaration>
+
+namespace test2 {
+ namespace foo {
+ void Func(int x);
+ }
+
+ class Bar {
+/**
+ * \brief Hhh
+*/
+ friend void ::test2::foo::Func(int x);
+ };
+}
+// CHECK: <Declaration>friend void Func(int x)</Declaration>
+
+namespace test3 {
+ template<class T> class vector {
+ public:
+ vector(int i) {}
+/**
+ * \brief Iii
+*/
+ void f(const T& t = T()) {}
+ };
+ class A {
+ private:
+/**
+ * \brief Jjj
+*/
+ friend void vector<A>::f(const A&);
+ };
+}
+// CHECK: <Declaration>void f(const T &amp;t = T())</Declaration>
+// CHECK: <Declaration>friend void f(const test3::A &amp;)</Declaration>
+
+class MyClass
+{
+/**
+ * \brief plain friend test.
+*/
+ friend class MyClass;
+};
+// CHECK: <Declaration>friend class MyClass</Declaration>
+
+template<class _Tp> class valarray
+{
+private:
+/**
+ * \brief template friend test.
+*/
+ template <class T> friend class valarray;
+};
+// CHECK: <Declaration>template &lt;class T&gt; class valarray</Declaration>
+// CHECK: <Declaration>friend template &lt;class T&gt; class valarray</Declaration>
+
+class gslice
+{
+ valarray<unsigned> __size_;
+};
diff --git a/test/Index/comment-cplus-template-decls.cpp b/test/Index/comment-cplus-template-decls.cpp
new file mode 100644
index 0000000..039f092
--- /dev/null
+++ b/test/Index/comment-cplus-template-decls.cpp
@@ -0,0 +1,69 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: c-index-test -test-load-source all -comments-xml-schema=%S/../../bindings/xml/comment-xml-schema.rng -target x86_64-apple-darwin10 std=c++11 %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
+// rdar://12378714
+
+/**
+ * \brief Aaa
+*/
+template<typename T> struct A {
+/**
+ * \brief Bbb
+*/
+ A();
+/**
+ * \brief Ccc
+*/
+ ~A();
+/**
+ * \brief Ddd
+*/
+ void f() { }
+};
+// CHECK: <Declaration>template &lt;typename T&gt; struct A {}</Declaration>
+// CHECK: <Declaration>A&lt;T&gt;()</Declaration>
+// CHECK: <Declaration>void ~A&lt;T&gt;()</Declaration>
+
+/**
+ * \Brief Eee
+*/
+template <typename T> struct D : A<T> {
+/**
+ * \brief
+*/
+ using A<T>::f;
+
+ void f();
+};
+// CHECK: <Declaration>template &lt;typename T&gt; struct D : A&lt;T&gt; {}</Declaration>
+// CHECK: <Declaration>using A&lt;T&gt;::f</Declaration>
+
+struct Base {
+ int foo;
+};
+/**
+ * \brief
+*/
+template<typename T> struct E : Base {
+/**
+ * \brief
+*/
+ using Base::foo;
+};
+// CHECK: <Declaration>template &lt;typename T&gt; struct E : Base {}</Declaration>
+// CHECK: <Declaration>using Base::foo</Declaration>
+
+/// \tparam
+/// \param AAA Blah blah
+template<typename T>
+void func_template_1(T AAA);
+// CHECK: <Declaration>template &lt;typename T&gt; void func_template_1(T AAA)</Declaration>
+
+template<template<template<typename CCC> class DDD, class BBB> class AAA>
+void func_template_2();
+// FIXME: There is not Declaration field in the generated output.
diff --git a/test/Index/comment-custom-block-command.cpp b/test/Index/comment-custom-block-command.cpp
new file mode 100644
index 0000000..80a58ca
--- /dev/null
+++ b/test/Index/comment-custom-block-command.cpp
@@ -0,0 +1,38 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+
+// Check that custom block commands are defined correctly.
+// RUN: %clang_cc1 -fcomment-block-commands=CustomCommand -x c++ -std=c++11 -emit-pch -o %t/out.pch %s
+// RUN: %clang_cc1 -x c++ -std=c++11 -fcomment-block-commands=CustomCommand -include-pch %t/out.pch -fsyntax-only %s
+
+// RUN: c-index-test -test-load-source all -comments-xml-schema=%S/../../bindings/xml/comment-xml-schema.rng %s -std=c++11 -fcomment-block-commands=CustomCommand > %t/out.c-index-direct
+// RUN: c-index-test -test-load-tu %t/out.pch all > %t/out.c-index-pch
+
+// RUN: FileCheck %s -check-prefix=WRONG < %t/out.c-index-direct
+// RUN: FileCheck %s -check-prefix=WRONG < %t/out.c-index-pch
+
+// Ensure that XML is not invalid
+// WRONG-NOT: CommentXMLInvalid
+
+// RUN: FileCheck %s < %t/out.c-index-direct
+// RUN: FileCheck %s < %t/out.c-index-pch
+
+// XFAIL: valgrind
+
+#ifndef HEADER
+#define HEADER
+
+/// \CustomCommand Aaa.
+void comment_custom_block_command_1();
+
+// CHECK: comment-custom-block-command.cpp:[[@LINE-2]]:6: FunctionDecl=comment_custom_block_command_1:{{.*}} FullCommentAsHTML=[<p> Aaa.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-custom-block-command.cpp" line="[[@LINE-2]]" column="6"><Name>comment_custom_block_command_1</Name><USR>c:@F@comment_custom_block_command_1#</USR><Declaration>void comment_custom_block_command_1()</Declaration><Discussion><Para> Aaa.</Para></Discussion></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[CustomCommand]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))))]
+
+#endif
+
diff --git a/test/Index/comment-objc-decls.m b/test/Index/comment-objc-decls.m
new file mode 100644
index 0000000..ae3b0bb
--- /dev/null
+++ b/test/Index/comment-objc-decls.m
@@ -0,0 +1,175 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: c-index-test -test-load-source all -comments-xml-schema=%S/../../bindings/xml/comment-xml-schema.rng -target x86_64-apple-darwin10 %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
+
+// rdar://12378714
+
+/**
+ * \brief This is a protocol definition
+*/
+@protocol MyProto
+@optional
+/**
+ * \brief MethodMyProto method
+ * \param[in] anObject input value
+ * \param[in] range output value is unsigned int
+ * \result return index
+ */
+- (unsigned int)MethodMyProto:(id)anObject inRange:(unsigned int)range;
+/**
+ * \brief PropertyMyProto - This is protocol's property.
+*/
+@property (copy) id PropertyMyProto;
+/**
+ * \brief ClassMethodMyProto
+*/
++ ClassMethodMyProto;
+@end
+// CHECK: <Declaration>@protocol MyProto\n@end</Declaration>
+// CHECK: <Declaration>- (unsigned int)MethodMyProto:(id)anObject inRange:(unsigned int)range;</Declaration>
+// CHECK: <Declaration>@optional\n@property(readwrite, copy, atomic) id PropertyMyProto;</Declaration>
+// CHECK: <Declaration>+ (id)ClassMethodMyProto;</Declaration>
+
+/**
+ * \brief NSObject is the root class.
+*/
+@interface NSObject {
+/**
+ * \brief IvarNSObject
+*/
+ id IvarNSObject;
+}
+@end
+// CHECK: Declaration>@interface NSObject {\n id IvarNSObject;\n}\n@end</Declaration>
+// CHECK: <Declaration>id IvarNSObject</Declaration>
+
+/**
+ * \brief MyClass - primary class.
+*/
+@interface MyClass : NSObject<MyProto>
+{
+/**
+ * \brief IvarMyClass - IvarMyClass of values.
+*/
+ id IvarMyClass;
+}
+/**
+ * \brief MethodMyClass is instance method.
+*/
+- MethodMyClass;
+
+/**
+ * \brief ClassMethodMyClass is class method.
+*/
++ ClassMethodMyClass;
+
+/**
+ * \brief PropertyMyClass - This is class's property.
+*/
+@property (copy) id PropertyMyClass;
+@end
+// CHECK: <Declaration>@interface MyClass : NSObject &lt;MyProto&gt; {\n id IvarMyClass;\n}\n@end</Declaration>
+// CHECK: <Declaration>id IvarMyClass</Declaration>
+// CHECK: <Declaration>- (id)MethodMyClass;</Declaration>
+// CHECK: <Declaration>+ (id)ClassMethodMyClass;</Declaration>
+// CHECK: <Declaration>@property(readwrite, copy, atomic) id PropertyMyClass;</Declaration
+
+/**
+ * \brief - This is class extension of MyClass
+*/
+@interface MyClass()
+{
+/**
+ * \brief IvarMyClassExtension - IvarMyClassExtension private to class extension
+*/
+ id IvarMyClassExtension;
+}
+@end
+// CHECK: <Declaration>@interface MyClass () {\n id IvarMyClassExtension;\n}\n@end</Declaration>
+// CHECK: <Declaration>id IvarMyClassExtension</Declaration>
+
+
+/**
+ * \brief MyClass (Category) is private to MyClass.
+*/
+@interface MyClass (Category)
+/**
+ * \brief This is private to MyClass
+ */
+- (void)MethodMyClassCategory;
+
+/**
+ * \brief PropertyMyClassCategory - This is class's private property.
+*/
+@property (copy) id PropertyMyClassCategory;
+@end
+// CHECK: <Declaration>@interface MyClass (Category)\n@end</Declaration>
+// CHECK: <Declaration>- (void)MethodMyClassCategory;</Declaration>
+// CHECK: <Declaration>@property(readwrite, copy, atomic) id PropertyMyClassCategory;</Declaration>
+// CHECK: <Declaration>- (id)PropertyMyClassCategory;</Declaration>
+// CHECK: <Declaration>- (void)setPropertyMyClassCategory:(id)arg;</Declaration>
+
+/// @implementation's
+
+/**
+ * \brief implementation of MyClass class.
+*/
+@implementation MyClass {
+/**
+ * \brief IvarPrivateToMyClassImpl.
+*/
+ id IvarPrivateToMyClassImpl;
+}
+/**
+ * \brief MethodMyClass is instance method implementation.
+*/
+- MethodMyClass {
+ return 0;
+}
+
+/**
+ * \brief ClassMethodMyClass is class method implementation.
+*/
++ ClassMethodMyClass {
+ return 0;
+}
+@end
+// CHECK: <Declaration>@implementation MyClass {\n id IvarPrivateToMyClassImpl;\n id _PropertyMyClass;\n}\n@end</Declaration>
+// CHECK: <Declaration>id IvarPrivateToMyClassImpl</Declaration>
+// CHECK: <Declaration>- (id)MethodMyClass;</Declaration>
+// CHECK: <Declaration>+ (id)ClassMethodMyClass;</Declaration>
+
+/**
+ * \brief MyClass (Category) is implementation of private to MyClass.
+*/
+@implementation MyClass (Category)
+/**
+ * \brief This is private to MyClass
+ */
+- (void)MethodMyClassCategory {}
+/**
+ * \brief property getter
+*/
+- (id) PropertyMyClassCategory { return 0; }
+
+/**
+ * \brief property setter
+*/
+- (void) setPropertyMyClassCategory : (id) arg {}
+@end
+// CHECK: <Declaration>@implementation MyClass (Category)\n@end</Declaration>
+// CHECK: <Declaration>- (void)MethodMyClassCategory;</Declaration>
+// CHECK: <Declaration>- (id)PropertyMyClassCategory;</Declaration>
+// CHECK: <Declaration>- (void)setPropertyMyClassCategory:(id)arg;</Declaration>
+
+/**
+ * \brief NSObject implementation
+*/
+@implementation NSObject
+@end
+// CHECK: <Declaration>@implementation NSObject\n@end</Declaration>
diff --git a/test/Index/comment-to-html-xml-conversion.cpp b/test/Index/comment-to-html-xml-conversion.cpp
new file mode 100644
index 0000000..c770ca8
--- /dev/null
+++ b/test/Index/comment-to-html-xml-conversion.cpp
@@ -0,0 +1,797 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+
+// This file contains UTF-8 sequences. Please don't "fix" them!
+
+// Check that we serialize comment source locations properly.
+// RUN: %clang_cc1 -x c++ -std=c++11 -emit-pch -o %t/out.pch %s
+// RUN: %clang_cc1 -x c++ -std=c++11 -include-pch %t/out.pch -fsyntax-only %s
+
+// RUN: c-index-test -test-load-source all -comments-xml-schema=%S/../../bindings/xml/comment-xml-schema.rng %s -std=c++11 > %t/out.c-index-direct
+// RUN: c-index-test -test-load-tu %t/out.pch all > %t/out.c-index-pch
+
+// RUN: FileCheck %s -check-prefix=WRONG < %t/out.c-index-direct
+// RUN: FileCheck %s -check-prefix=WRONG < %t/out.c-index-pch
+
+// Ensure that XML is not invalid
+// WRONG-NOT: CommentXMLInvalid
+
+// RUN: FileCheck %s < %t/out.c-index-direct
+// RUN: FileCheck %s < %t/out.c-index-pch
+
+// XFAIL: msan
+// XFAIL: valgrind
+
+#ifndef HEADER
+#define HEADER
+
+/// Aaa.
+void comment_to_html_conversion_1();
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_1:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_1</Name><USR>c:@F@comment_to_html_conversion_1#</USR><Declaration>void comment_to_html_conversion_1()</Declaration><Abstract><Para> Aaa.</Para></Abstract></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Aaa.])))]
+
+/// \brief Aaa.
+void comment_to_html_conversion_2();
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_2:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_2</Name><USR>c:@F@comment_to_html_conversion_2#</USR><Declaration>void comment_to_html_conversion_2()</Declaration><Abstract><Para> Aaa.</Para></Abstract></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[brief]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))))]
+
+/// \short Aaa.
+void comment_to_html_conversion_3();
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_3:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_3</Name><USR>c:@F@comment_to_html_conversion_3#</USR><Declaration>void comment_to_html_conversion_3()</Declaration><Abstract><Para> Aaa.</Para></Abstract></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[short]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))))]
+
+/// Aaa.
+///
+/// \brief Bbb.
+void comment_to_html_conversion_4();
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_4:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Bbb.</p><p> Aaa.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_4</Name><USR>c:@F@comment_to_html_conversion_4#</USR><Declaration>void comment_to_html_conversion_4()</Declaration><Abstract><Para> Bbb.</Para></Abstract><Discussion><Para> Aaa.</Para></Discussion></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[brief]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Bbb.]))))]
+
+/// Aaa.
+///
+/// \brief Bbb.
+///
+/// Ccc.
+void comment_to_html_conversion_5();
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_5:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Bbb.</p><p> Aaa.</p><p> Ccc.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_5</Name><USR>c:@F@comment_to_html_conversion_5#</USR><Declaration>void comment_to_html_conversion_5()</Declaration><Abstract><Para> Bbb.</Para></Abstract><Discussion><Para> Aaa.</Para><Para> Ccc.</Para></Discussion></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[brief]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Bbb.])))
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Ccc.])))]
+
+/// \brief Aaa.
+/// \brief Bbb.
+void comment_to_html_conversion_6();
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_6:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa. </p><p class="para-brief"> Bbb.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_6</Name><USR>c:@F@comment_to_html_conversion_6#</USR><Declaration>void comment_to_html_conversion_6()</Declaration><Abstract><Para> Aaa. </Para></Abstract><Discussion><Para> Bbb.</Para></Discussion></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[brief]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Aaa.] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[brief]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Bbb.]))))]
+
+/// Aaa.
+///
+/// \return Bbb.
+void comment_to_html_conversion_7();
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_7:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p><p class="para-returns"><span class="word-returns">Returns</span> Bbb.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_7</Name><USR>c:@F@comment_to_html_conversion_7#</USR><Declaration>void comment_to_html_conversion_7()</Declaration><Abstract><Para> Aaa.</Para></Abstract><ResultDiscussion><Para> Bbb.</Para></ResultDiscussion></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[return]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Bbb.]))))]
+
+/// Aaa.
+///
+/// \returns Bbb.
+void comment_to_html_conversion_8();
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_8:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p><p class="para-returns"><span class="word-returns">Returns</span> Bbb.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_8</Name><USR>c:@F@comment_to_html_conversion_8#</USR><Declaration>void comment_to_html_conversion_8()</Declaration><Abstract><Para> Aaa.</Para></Abstract><ResultDiscussion><Para> Bbb.</Para></ResultDiscussion></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[returns]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Bbb.]))))]
+
+/// Aaa.
+///
+/// \result Bbb.
+void comment_to_html_conversion_9();
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_9:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p><p class="para-returns"><span class="word-returns">Returns</span> Bbb.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_9</Name><USR>c:@F@comment_to_html_conversion_9#</USR><Declaration>void comment_to_html_conversion_9()</Declaration><Abstract><Para> Aaa.</Para></Abstract><ResultDiscussion><Para> Bbb.</Para></ResultDiscussion></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[result]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Bbb.]))))]
+
+/// \returns Aaa.
+/// \returns Bbb.
+void comment_to_html_conversion_10();
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_10:{{.*}} FullCommentAsHTML=[<p class="para-returns"><span class="word-returns">Returns</span> Bbb.</p><p class="para-returns"><span class="word-returns">Returns</span> Aaa. </p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_10</Name><USR>c:@F@comment_to_html_conversion_10#</USR><Declaration>void comment_to_html_conversion_10()</Declaration><ResultDiscussion><Para> Aaa. </Para></ResultDiscussion><Discussion><Para> Bbb.</Para></Discussion></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[returns]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Aaa.] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[returns]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Bbb.]))))]
+
+/// Aaa.
+///
+/// Bbb.
+///
+/// \returns Ccc.
+void comment_to_html_conversion_11();
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_11:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p><p> Bbb.</p><p class="para-returns"><span class="word-returns">Returns</span> Ccc.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_11</Name><USR>c:@F@comment_to_html_conversion_11#</USR><Declaration>void comment_to_html_conversion_11()</Declaration><Abstract><Para> Aaa.</Para></Abstract><ResultDiscussion><Para> Ccc.</Para></ResultDiscussion><Discussion><Para> Bbb.</Para></Discussion></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Bbb.]))
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[returns]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Ccc.]))))]
+
+/// \param
+void comment_to_html_conversion_12(int x1);
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_12:{{.*}} FullCommentAsHTML=[] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_12</Name><USR>c:@F@comment_to_html_conversion_12#I#</USR><Declaration>void comment_to_html_conversion_12(int x1)</Declaration></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[] ParamIndex=Invalid
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace)))]
+
+/// \param x1 Aaa.
+void comment_to_html_conversion_13(int x1);
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_13:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-0">x1</dt><dd class="param-descr-index-0"> Aaa.</dd></dl>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_13</Name><USR>c:@F@comment_to_html_conversion_13#I#</USR><Declaration>void comment_to_html_conversion_13(int x1)</Declaration><Parameters><Parameter><Name>x1</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Aaa.</Para></Discussion></Parameter></Parameters></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x1] ParamIndex=0
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))))]
+
+/// \param zzz Aaa.
+void comment_to_html_conversion_14(int x1);
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_14:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-invalid">zzz</dt><dd class="param-descr-index-invalid"> Aaa.</dd></dl>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_14</Name><USR>c:@F@comment_to_html_conversion_14#I#</USR><Declaration>void comment_to_html_conversion_14(int x1)</Declaration><Parameters><Parameter><Name>zzz</Name><Direction isExplicit="0">in</Direction><Discussion><Para> Aaa.</Para></Discussion></Parameter></Parameters></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[zzz] ParamIndex=Invalid
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))))]
+
+/// \param x2 Bbb.
+/// \param x1 Aaa.
+void comment_to_html_conversion_15(int x1, int x2);
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_15:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-0">x1</dt><dd class="param-descr-index-0"> Aaa.</dd><dt class="param-name-index-1">x2</dt><dd class="param-descr-index-1"> Bbb. </dd></dl>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_15</Name><USR>c:@F@comment_to_html_conversion_15#I#I#</USR><Declaration>void comment_to_html_conversion_15(int x1, int x2)</Declaration><Parameters><Parameter><Name>x1</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Aaa.</Para></Discussion></Parameter><Parameter><Name>x2</Name><Index>1</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Bbb. </Para></Discussion></Parameter></Parameters></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x2] ParamIndex=1
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Bbb.] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
+// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x1] ParamIndex=0
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))))]
+
+/// \param x2 Bbb.
+/// \param zzz Aaa.
+/// \param x1 Aaa.
+void comment_to_html_conversion_16(int x1, int x2);
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_16:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-0">x1</dt><dd class="param-descr-index-0"> Aaa.</dd><dt class="param-name-index-1">x2</dt><dd class="param-descr-index-1"> Bbb. </dd><dt class="param-name-index-invalid">zzz</dt><dd class="param-descr-index-invalid"> Aaa. </dd></dl>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_16</Name><USR>c:@F@comment_to_html_conversion_16#I#I#</USR><Declaration>void comment_to_html_conversion_16(int x1, int x2)</Declaration><Parameters><Parameter><Name>x1</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Aaa.</Para></Discussion></Parameter><Parameter><Name>x2</Name><Index>1</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Bbb. </Para></Discussion></Parameter><Parameter><Name>zzz</Name><Direction isExplicit="0">in</Direction><Discussion><Para> Aaa. </Para></Discussion></Parameter></Parameters></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x2] ParamIndex=1
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Bbb.] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
+// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[zzz] ParamIndex=Invalid
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Aaa.] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
+// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x1] ParamIndex=0
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Aaa.]))))]
+
+/// \tparam
+/// \param aaa Blah blah
+template<typename T>
+void comment_to_html_conversion_17(T aaa);
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=comment_to_html_conversion_17:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-0">aaa</dt><dd class="param-descr-index-0"> Blah blah</dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_17</Name><USR>c:@FT@&gt;1#Tcomment_to_html_conversion_17#t0.0#</USR><Declaration>template &lt;typename T&gt; void comment_to_html_conversion_17(T aaa)</Declaration><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah</Para></Discussion></Parameter></Parameters></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_TParamCommand ParamName=[] ParamPosition=Invalid
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
+// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[aaa] ParamIndex=0
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Blah blah]))))]
+
+/// \tparam T
+/// \param aaa Blah blah
+template<typename T>
+void comment_to_html_conversion_18(T aaa);
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=comment_to_html_conversion_18:{{.*}} FullCommentAsHTML=[<dl><dt class="param-name-index-0">aaa</dt><dd class="param-descr-index-0"> Blah blah</dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_18</Name><USR>c:@FT@&gt;1#Tcomment_to_html_conversion_18#t0.0#</USR><Declaration>template &lt;typename T&gt; void comment_to_html_conversion_18(T aaa)</Declaration><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah</Para></Discussion></Parameter></Parameters></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_TParamCommand ParamName=[T] ParamPosition={0}
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
+// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[aaa] ParamIndex=0
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Blah blah]))))]
+
+/// \tparam T2 Bbb
+/// \tparam T1 Aaa
+template<typename T1, typename T2>
+void comment_to_html_conversion_19(T1 aaa, T2 bbb);
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=comment_to_html_conversion_19:{{.*}} FullCommentAsHTML=[<dl><dt class="tparam-name-index-0">T1</dt><dd class="tparam-descr-index-0"> Aaa</dd><dt class="tparam-name-index-1">T2</dt><dd class="tparam-descr-index-1"> Bbb </dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_19</Name><USR>c:@FT@&gt;2#T#Tcomment_to_html_conversion_19#t0.0#t0.1#</USR><Declaration>template &lt;typename T1, typename T2&gt;\nvoid comment_to_html_conversion_19(T1 aaa, T2 bbb)</Declaration><TemplateParameters><Parameter><Name>T1</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>T2</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter></TemplateParameters></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_TParamCommand ParamName=[T2] ParamPosition={1}
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Bbb] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
+// CHECK-NEXT: (CXComment_TParamCommand ParamName=[T1] ParamPosition={0}
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Aaa]))))]
+
+/// \tparam T2 Bbb
+/// \tparam U Zzz
+/// \tparam V Ccc
+/// \tparam T1 Aaa
+template<typename T1, typename T2, int V>
+void comment_to_html_conversion_20(T1 aaa, T2 bbb);
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=comment_to_html_conversion_20:{{.*}} FullCommentAsHTML=[<dl><dt class="tparam-name-index-0">T1</dt><dd class="tparam-descr-index-0"> Aaa</dd><dt class="tparam-name-index-1">T2</dt><dd class="tparam-descr-index-1"> Bbb </dd><dt class="tparam-name-index-2">V</dt><dd class="tparam-descr-index-2"> Ccc </dd><dt class="tparam-name-index-invalid">U</dt><dd class="tparam-descr-index-invalid"> Zzz </dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_20</Name><USR>c:@FT@&gt;3#T#T#NIcomment_to_html_conversion_20#t0.0#t0.1#</USR><Declaration>template &lt;typename T1, typename T2, int V&gt;\nvoid comment_to_html_conversion_20(T1 aaa, T2 bbb)</Declaration><TemplateParameters><Parameter><Name>T1</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>T2</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter><Parameter><Name>V</Name><Index>2</Index><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>U</Name><Discussion><Para> Zzz </Para></Discussion></Parameter></TemplateParameters></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_TParamCommand ParamName=[T2] ParamPosition={1}
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Bbb] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
+// CHECK-NEXT: (CXComment_TParamCommand ParamName=[U] ParamPosition=Invalid
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Zzz] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
+// CHECK-NEXT: (CXComment_TParamCommand ParamName=[V] ParamPosition={2}
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Ccc] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
+// CHECK-NEXT: (CXComment_TParamCommand ParamName=[T1] ParamPosition={0}
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Aaa]))))]
+
+/// \tparam TTT Ddd
+/// \tparam C Ccc
+/// \tparam T Aaa
+/// \tparam TT Bbb
+template<template<template<typename T> class TT, class C> class TTT>
+void comment_to_html_conversion_21();
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=comment_to_html_conversion_21:{{.*}} FullCommentAsHTML=[<dl><dt class="tparam-name-index-0">TTT</dt><dd class="tparam-descr-index-0"> Ddd </dd><dt class="tparam-name-index-other">C</dt><dd class="tparam-descr-index-other"> Ccc </dd><dt class="tparam-name-index-other">T</dt><dd class="tparam-descr-index-other"> Aaa </dd><dt class="tparam-name-index-other">TT</dt><dd class="tparam-descr-index-other"> Bbb</dd></dl>] FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_21</Name><USR>c:@FT@&gt;1#t&gt;2#t&gt;1#T#Tcomment_to_html_conversion_21#</USR><Declaration>template &lt;template &lt;template &lt;typename T&gt; class TT, class C&gt; class TTT&gt;\nvoid comment_to_html_conversion_21()</Declaration><TemplateParameters><Parameter><Name>TTT</Name><Index>0</Index><Discussion><Para> Ddd </Para></Discussion></Parameter><Parameter><Name>C</Name><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>T</Name><Discussion><Para> Aaa </Para></Discussion></Parameter><Parameter><Name>TT</Name><Discussion><Para> Bbb</Para></Discussion></Parameter></TemplateParameters></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_TParamCommand ParamName=[TTT] ParamPosition={0}
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Ddd] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
+// CHECK-NEXT: (CXComment_TParamCommand ParamName=[C] ParamPosition={0, 1}
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Ccc] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
+// CHECK-NEXT: (CXComment_TParamCommand ParamName=[T] ParamPosition={0, 0, 0}
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Aaa] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
+// CHECK-NEXT: (CXComment_TParamCommand ParamName=[TT] ParamPosition={0, 0}
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Bbb]))))]
+
+/// \brief Aaa.
+///
+/// Bbb.
+///
+/// \param x2 Ddd.
+/// \param x1 Ccc.
+/// \returns Eee.
+void comment_to_html_conversion_22(int x1, int x2);
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_22:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Aaa.</p><p> Bbb.</p><dl><dt class="param-name-index-0">x1</dt><dd class="param-descr-index-0"> Ccc. </dd><dt class="param-name-index-1">x2</dt><dd class="param-descr-index-1"> Ddd. </dd></dl><p class="para-returns"><span class="word-returns">Returns</span> Eee.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_22</Name><USR>c:@F@comment_to_html_conversion_22#I#I#</USR><Declaration>void comment_to_html_conversion_22(int x1, int x2)</Declaration><Abstract><Para> Aaa.</Para></Abstract><Parameters><Parameter><Name>x1</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Ccc. </Para></Discussion></Parameter><Parameter><Name>x2</Name><Index>1</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Ddd. </Para></Discussion></Parameter></Parameters><ResultDiscussion><Para> Eee.</Para></ResultDiscussion><Discussion><Para> Bbb.</Para></Discussion></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[brief]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Aaa.])))
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Bbb.]))
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x2] ParamIndex=1
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Ddd.] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
+// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[x1] ParamIndex=0
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Ccc.] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[returns]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Eee.]))))]
+
+/// <br><a href="http://example.com/">Aaa</a>
+void comment_to_html_conversion_23();
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_23:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <br><a href="http://example.com/">Aaa</a></p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_23</Name><USR>c:@F@comment_to_html_conversion_23#</USR><Declaration>void comment_to_html_conversion_23()</Declaration><Abstract><Para> <rawHTML><![CDATA[<br>]]></rawHTML><rawHTML><![CDATA[<a href="http://example.com/">]]></rawHTML>Aaa<rawHTML>&lt;/a&gt;</rawHTML></Para></Abstract></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_HTMLStartTag Name=[br])
+// CHECK-NEXT: (CXComment_HTMLStartTag Name=[a] Attrs: href=http://example.com/)
+// CHECK-NEXT: (CXComment_Text Text=[Aaa])
+// CHECK-NEXT: (CXComment_HTMLEndTag Name=[a])))]
+
+/// \verbatim
+/// <a href="http://example.com/">Aaa</a>
+/// <a href='http://example.com/'>Aaa</a>
+/// \endverbatim
+void comment_to_html_conversion_24();
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_24:{{.*}} FullCommentAsHTML=[<pre> &lt;a href=&quot;http:&#47;&#47;example.com&#47;&quot;&gt;Aaa&lt;&#47;a&gt;\n &lt;a href=&#39;http:&#47;&#47;example.com&#47;&#39;&gt;Aaa&lt;&#47;a&gt;</pre>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_24</Name><USR>c:@F@comment_to_html_conversion_24#</USR><Declaration>void comment_to_html_conversion_24()</Declaration><Discussion><Verbatim xml:space="preserve" kind="verbatim"> &lt;a href=&quot;http://example.com/&quot;&gt;Aaa&lt;/a&gt;\n &lt;a href=&apos;http://example.com/&apos;&gt;Aaa&lt;/a&gt;</Verbatim></Discussion></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_VerbatimBlockCommand CommandName=[verbatim]
+// CHECK-NEXT: (CXComment_VerbatimBlockLine Text=[ <a href="http://example.com/">Aaa</a>])
+// CHECK-NEXT: (CXComment_VerbatimBlockLine Text=[ <a href='http://example.com/'>Aaa</a>])))]
+
+/// \function foo
+/// \class foo
+/// \method foo
+/// \interface foo
+/// Blah blah.
+void comment_to_html_conversion_25();
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_25:{{.*}} FullCommentAsHTML=[<p class="para-brief"> Blah blah.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_25</Name><USR>c:@F@comment_to_html_conversion_25#</USR><Declaration>void comment_to_html_conversion_25()</Declaration><Abstract><Para> Blah blah.</Para></Abstract></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_VerbatimLine Text=[ foo])
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_VerbatimLine Text=[ foo])
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_VerbatimLine Text=[ foo])
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_VerbatimLine Text=[ foo])
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Blah blah.])))]
+
+/// \unknown
+void comment_to_html_conversion_26();
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_26:{{.*}} FullCommentAsHTML=[<p class="para-brief"> </p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_26</Name><USR>c:@F@comment_to_html_conversion_26#</USR><Declaration>void comment_to_html_conversion_26()</Declaration><Abstract><Para> </Para></Abstract></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_InlineCommand CommandName=[unknown] RenderNormal)))]
+
+/// \b Aaa
+void comment_to_html_conversion_27();
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_27:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <b>Aaa</b></p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_27</Name><USR>c:@F@comment_to_html_conversion_27#</USR><Declaration>void comment_to_html_conversion_27()</Declaration><Abstract><Para> <bold>Aaa</bold></Para></Abstract></Function>]
+// CHECK-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)))]
+
+/// \c Aaa \p Bbb
+void comment_to_html_conversion_28();
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_28:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <tt>Aaa</tt> <tt>Bbb</tt></p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_28</Name><USR>c:@F@comment_to_html_conversion_28#</USR><Declaration>void comment_to_html_conversion_28()</Declaration><Abstract><Para> <monospaced>Aaa</monospaced> <monospaced>Bbb</monospaced></Para></Abstract></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// 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)))]
+
+/// \a Aaa \e Bbb \em Ccc
+void comment_to_html_conversion_29();
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_29:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <em>Aaa</em> <em>Bbb</em> <em>Ccc</em></p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_29</Name><USR>c:@F@comment_to_html_conversion_29#</USR><Declaration>void comment_to_html_conversion_29()</Declaration><Abstract><Para> <emphasized>Aaa</emphasized> <emphasized>Bbb</emphasized> <emphasized>Ccc</emphasized></Para></Abstract></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_InlineCommand CommandName=[a] RenderEmphasized Arg[0]=Aaa)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// 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)))]
+
+/// \a 1<2 \e 3<4 \em 5<6 \param 7<8 aaa \tparam 9<10 bbb
+void comment_to_html_conversion_30();
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_30:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <em>1&lt;2</em> <em>3&lt;4</em> <em>5&lt;6</em> </p><dl><dt class="tparam-name-index-invalid">9&lt;10</dt><dd class="tparam-descr-index-invalid"> bbb</dd></dl><dl><dt class="param-name-index-invalid">7&lt;8</dt><dd class="param-descr-index-invalid"> aaa </dd></dl>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_30</Name><USR>c:@F@comment_to_html_conversion_30#</USR><Declaration>void comment_to_html_conversion_30()</Declaration><Abstract><Para> <emphasized>1&lt;2</emphasized> <emphasized>3&lt;4</emphasized> <emphasized>5&lt;6</emphasized> </Para></Abstract><TemplateParameters><Parameter><Name>9&lt;10</Name><Discussion><Para> bbb</Para></Discussion></Parameter></TemplateParameters><Parameters><Parameter><Name>7&lt;8</Name><Direction isExplicit="0">in</Direction><Discussion><Para> aaa </Para></Discussion></Parameter></Parameters></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_InlineCommand CommandName=[a] RenderEmphasized Arg[0]=1<2)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_InlineCommand CommandName=[e] RenderEmphasized Arg[0]=3<4)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_InlineCommand CommandName=[em] RenderEmphasized Arg[0]=5<6)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_ParamCommand in implicitly ParamName=[7<8] ParamIndex=Invalid
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ aaa ])))
+// CHECK-NEXT: (CXComment_TParamCommand ParamName=[9<10] ParamPosition=Invalid
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ bbb]))))]
+
+/// \\ \@ \& \$ \# \< \> \% \" \. \::
+void comment_to_html_conversion_31();
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_31:{{.*}} FullCommentAsHTML=[<p class="para-brief"> \ @ &amp; $ # &lt; &gt; % &quot; . ::</p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_31</Name><USR>c:@F@comment_to_html_conversion_31#</USR><Declaration>void comment_to_html_conversion_31()</Declaration><Abstract><Para> \ @ &amp; $ # &lt; &gt; % &quot; . ::</Para></Abstract></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_Text Text=[\])
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_Text Text=[@])
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_Text Text=[&])
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_Text Text=[$])
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_Text Text=[#])
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_Text Text=[<])
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_Text Text=[>])
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_Text Text=[%])
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_Text Text=["])
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_Text Text=[.])
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_Text Text=[::])))]
+
+/// &amp; &lt; &gt; &quot; &apos; &#109;&#101;&#111;&#119; &#x6d;&#x65;&#x6F;&#X77;
+void comment_to_html_conversion_32();
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_32:{{.*}} FullCommentAsHTML=[<p class="para-brief"> &amp; &lt; &gt; &quot; &#39; meow meow</p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_32</Name><USR>c:@F@comment_to_html_conversion_32#</USR><Declaration>void comment_to_html_conversion_32()</Declaration><Abstract><Para> &amp; &lt; &gt; &quot; &apos; meow meow</Para></Abstract></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_Text Text=[&])
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_Text Text=[<])
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_Text Text=[>])
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_Text Text=["])
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_Text Text=['])
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_Text Text=[m])
+// CHECK-NEXT: (CXComment_Text Text=[e])
+// CHECK-NEXT: (CXComment_Text Text=[o])
+// CHECK-NEXT: (CXComment_Text Text=[w])
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_Text Text=[m])
+// CHECK-NEXT: (CXComment_Text Text=[e])
+// CHECK-NEXT: (CXComment_Text Text=[o])
+// CHECK-NEXT: (CXComment_Text Text=[w])))]
+
+/// <em>0&lt;i</em>
+void comment_to_html_conversion_33();
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_33:{{.*}} FullCommentAsHTML=[<p class="para-brief"> <em>0&lt;i</em></p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_33</Name><USR>c:@F@comment_to_html_conversion_33#</USR><Declaration>void comment_to_html_conversion_33()</Declaration><Abstract><Para> <rawHTML><![CDATA[<em>]]></rawHTML>0&lt;i<rawHTML>&lt;/em&gt;</rawHTML></Para></Abstract></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_HTMLStartTag Name=[em])
+// CHECK-NEXT: (CXComment_Text Text=[0])
+// CHECK-NEXT: (CXComment_Text Text=[<])
+// CHECK-NEXT: (CXComment_Text Text=[i])
+// CHECK-NEXT: (CXComment_HTMLEndTag Name=[em])))]
+
+// rdar://12392215
+/// &copy; the copyright symbol
+/// &trade; the trade mark symbol
+/// &reg; the registered trade mark symbol
+/// &nbsp; a non breakable space.
+/// &Delta; Greek letter Delta Δ.
+/// &Gamma; Greek letter Gamma Γ.
+void comment_to_html_conversion_34();
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_html_conversion_34:{{.*}} FullCommentAsHTML=[<p class="para-brief"> © the copyright symbol ™ the trade mark symbol ® the registered trade mark symbol   a non breakable space. Δ Greek letter Delta Δ. Γ Greek letter Gamma Γ.</p>] FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_34</Name><USR>c:@F@comment_to_html_conversion_34#</USR><Declaration>void comment_to_html_conversion_34()</Declaration><Abstract><Para> © the copyright symbol ™ the trade mark symbol ® the registered trade mark symbol   a non breakable space. Δ Greek letter Delta Δ. Γ Greek letter Gamma Γ.</Para></Abstract></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_Text Text=[©])
+// CHECK-NEXT: (CXComment_Text Text=[ the copyright symbol] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_Text Text=[â„¢])
+// CHECK-NEXT: (CXComment_Text Text=[ the trade mark symbol] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_Text Text=[®])
+// CHECK-NEXT: (CXComment_Text Text=[ the registered trade mark symbol] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_Text Text=[ ])
+// CHECK-NEXT: (CXComment_Text Text=[ a non breakable space.] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_Text Text=[Δ])
+// CHECK-NEXT: (CXComment_Text Text=[ Greek letter Delta Δ.] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_Text Text=[Γ])
+// CHECK-NEXT: (CXComment_Text Text=[ Greek letter Gamma Γ.])))]
+
+
+/// Aaa.
+class comment_to_xml_conversion_01 {
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:7: ClassDecl=comment_to_xml_conversion_01:{{.*}} FullCommentAsXML=[<Class file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="7"><Name>comment_to_xml_conversion_01</Name><USR>c:@C@comment_to_xml_conversion_01</USR><Declaration>class comment_to_xml_conversion_01 {}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Class>]
+
+ /// \param aaa Blah blah.
+ comment_to_xml_conversion_01(int aaa);
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:3: CXXConstructor=comment_to_xml_conversion_01:{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="3"><Name>comment_to_xml_conversion_01</Name><USR>c:@C@comment_to_xml_conversion_01@F@comment_to_xml_conversion_01#I#</USR><Declaration>comment_to_xml_conversion_01(int aaa)</Declaration><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah.</Para></Discussion></Parameter></Parameters></Function>]
+
+ /// Aaa.
+ ~comment_to_xml_conversion_01();
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:3: CXXDestructor=~comment_to_xml_conversion_01:{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="3"><Name>~comment_to_xml_conversion_01</Name><USR>c:@C@comment_to_xml_conversion_01@F@~comment_to_xml_conversion_01#</USR><Declaration>void ~comment_to_xml_conversion_01()</Declaration><Abstract><Para> Aaa.</Para></Abstract></Function>]
+
+ /// \param aaa Blah blah.
+ int comment_to_xml_conversion_02(int aaa);
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:7: CXXMethod=comment_to_xml_conversion_02:{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="7"><Name>comment_to_xml_conversion_02</Name><USR>c:@C@comment_to_xml_conversion_01@F@comment_to_xml_conversion_02#I#</USR><Declaration>int comment_to_xml_conversion_02(int aaa)</Declaration><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah.</Para></Discussion></Parameter></Parameters></Function>]
+
+ /// \param aaa Blah blah.
+ static int comment_to_xml_conversion_03(int aaa);
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:14: CXXMethod=comment_to_xml_conversion_03:{{.*}} FullCommentAsXML=[<Function isClassMethod="1" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="14"><Name>comment_to_xml_conversion_03</Name><USR>c:@C@comment_to_xml_conversion_01@F@comment_to_xml_conversion_03#I#S</USR><Declaration>static int comment_to_xml_conversion_03(int aaa)</Declaration><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah.</Para></Discussion></Parameter></Parameters></Function>]
+
+ /// Aaa.
+ int comment_to_xml_conversion_04;
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:7: FieldDecl=comment_to_xml_conversion_04:{{.*}} FullCommentAsXML=[<Variable file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="7"><Name>comment_to_xml_conversion_04</Name><USR>c:@C@comment_to_xml_conversion_01@FI@comment_to_xml_conversion_04</USR><Declaration>int comment_to_xml_conversion_04</Declaration><Abstract><Para> Aaa.</Para></Abstract></Variable>]
+
+ /// Aaa.
+ static int comment_to_xml_conversion_05;
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:14: VarDecl=comment_to_xml_conversion_05:{{.*}} FullCommentAsXML=[<Variable file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="14"><Name>comment_to_xml_conversion_05</Name><USR>c:@C@comment_to_xml_conversion_01@comment_to_xml_conversion_05</USR><Declaration>static int comment_to_xml_conversion_05</Declaration><Abstract><Para> Aaa.</Para></Abstract></Variable>]
+
+ /// \param aaa Blah blah.
+ void operator()(int aaa);
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:8: CXXMethod=operator():{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="8"><Name>operator()</Name><USR>c:@C@comment_to_xml_conversion_01@F@operator()#I#</USR><Declaration>void operator()(int aaa)</Declaration><Parameters><Parameter><Name>aaa</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah.</Para></Discussion></Parameter></Parameters></Function>]
+
+ /// Aaa.
+ operator bool();
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:3: CXXConversion=operator _Bool:{{.*}} FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="3"><Name>operator _Bool</Name><USR>c:@C@comment_to_xml_conversion_01@F@operator _Bool#</USR><Declaration>bool operator _Bool()</Declaration><Abstract><Para> Aaa.</Para></Abstract></Function>]
+
+ /// Aaa.
+ typedef int comment_to_xml_conversion_06;
+
+// USR is line-dependent here, so filter it with a regexp.
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-3]]:15: TypedefDecl=comment_to_xml_conversion_06:{{.*}} FullCommentAsXML=[<Typedef file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-3]]" column="15"><Name>comment_to_xml_conversion_06</Name><USR>{{[^<]+}}</USR><Declaration>typedef int comment_to_xml_conversion_06</Declaration><Abstract><Para> Aaa.</Para></Abstract></Typedef>]
+
+ /// Aaa.
+ using comment_to_xml_conversion_07 = int;
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:9: TypeAliasDecl=comment_to_xml_conversion_07:{{.*}} FullCommentAsXML=[<Typedef file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="9"><Name>comment_to_xml_conversion_07</Name><USR>c:@C@comment_to_xml_conversion_01@comment_to_xml_conversion_07</USR><Declaration>using comment_to_xml_conversion_07 = int</Declaration><Abstract><Para> Aaa.</Para></Abstract></Typedef>]
+
+ /// Aaa.
+ template<typename T, typename U>
+ class comment_to_xml_conversion_08 { };
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:9: ClassTemplate=comment_to_xml_conversion_08:{{.*}} FullCommentAsXML=[<Class templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="9"><Name>comment_to_xml_conversion_08</Name><USR>c:@C@comment_to_xml_conversion_01@CT&gt;2#T#T@comment_to_xml_conversion_08</USR><Declaration>template &lt;typename T, typename U&gt; class comment_to_xml_conversion_08 {}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Class>]
+
+ /// Aaa.
+ template<typename T>
+ using comment_to_xml_conversion_09 = comment_to_xml_conversion_08<T, int>;
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:3: UnexposedDecl=comment_to_xml_conversion_09:{{.*}} FullCommentAsXML=[<Typedef file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="3"><Name>comment_to_xml_conversion_09</Name><USR>c:@C@comment_to_xml_conversion_01@comment_to_xml_conversion_09</USR><Declaration>template &lt;typename T&gt;\nusing comment_to_xml_conversion_09 = comment_to_xml_conversion_08&lt;T, int&gt;</Declaration><Abstract><Para> Aaa.</Para></Abstract></Typedef>]
+};
+
+/// Aaa.
+template<typename T, typename U>
+void comment_to_xml_conversion_10(T aaa, U bbb);
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionTemplate=comment_to_xml_conversion_10:{{.*}} FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_xml_conversion_10</Name><USR>c:@FT@&gt;2#T#Tcomment_to_xml_conversion_10#t0.0#t0.1#</USR><Declaration>template &lt;typename T, typename U&gt;\nvoid comment_to_xml_conversion_10(T aaa, U bbb)</Declaration><Abstract><Para> Aaa.</Para></Abstract></Function>]
+
+/// Aaa.
+template<>
+void comment_to_xml_conversion_10(int aaa, int bbb);
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:6: FunctionDecl=comment_to_xml_conversion_10:{{.*}} FullCommentAsXML=[<Function templateKind="specialization" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_xml_conversion_10</Name><USR>c:@F@comment_to_xml_conversion_10&lt;#I#I&gt;#I#I#</USR><Declaration>void comment_to_xml_conversion_10(int aaa, int bbb)</Declaration><Abstract><Para> Aaa.</Para></Abstract></Function>]
+
+/// Aaa.
+template<typename T, typename U>
+class comment_to_xml_conversion_11 { };
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:7: ClassTemplate=comment_to_xml_conversion_11:{{.*}} FullCommentAsXML=[<Class templateKind="template" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="7"><Name>comment_to_xml_conversion_11</Name><USR>c:@CT&gt;2#T#T@comment_to_xml_conversion_11</USR><Declaration>template &lt;typename T, typename U&gt; class comment_to_xml_conversion_11 {}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Class>]
+
+/// Aaa.
+template<typename T>
+class comment_to_xml_conversion_11<T, int> { };
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:7: ClassTemplatePartialSpecialization=comment_to_xml_conversion_11:{{.*}} FullCommentAsXML=[<Class templateKind="partialSpecialization" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="7"><Name>comment_to_xml_conversion_11</Name><USR>c:@CP&gt;1#T@comment_to_xml_conversion_11&gt;#t0.0#I</USR><Declaration>class comment_to_xml_conversion_11 {}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Class>]
+
+/// Aaa.
+template<>
+class comment_to_xml_conversion_11<int, int> { };
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:7: ClassDecl=comment_to_xml_conversion_11:{{.*}} FullCommentAsXML=[<Class templateKind="specialization" file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="7"><Name>comment_to_xml_conversion_11</Name><USR>c:@C@comment_to_xml_conversion_11&gt;#I#I</USR><Declaration>class comment_to_xml_conversion_11 {}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Class>]
+
+/// Aaa.
+int comment_to_xml_conversion_12;
+
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-2]]:5: VarDecl=comment_to_xml_conversion_12:{{.*}} FullCommentAsXML=[<Variable file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-2]]" column="5"><Name>comment_to_xml_conversion_12</Name><USR>c:@comment_to_xml_conversion_12</USR><Declaration>int comment_to_xml_conversion_12</Declaration><Abstract><Para> Aaa.</Para></Abstract></Variable>]
+
+/// Aaa.
+namespace comment_to_xml_conversion_13 {
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:11: Namespace=comment_to_xml_conversion_13:{{.*}} FullCommentAsXML=[<Namespace file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="11"><Name>comment_to_xml_conversion_13</Name><USR>c:@N@comment_to_xml_conversion_13</USR><Declaration>namespace comment_to_xml_conversion_13 {}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Namespace>]
+
+ /// Aaa.
+ namespace comment_to_xml_conversion_14 {
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:13: Namespace=comment_to_xml_conversion_14:{{.*}} FullCommentAsXML=[<Namespace file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="13"><Name>comment_to_xml_conversion_14</Name><USR>c:@N@comment_to_xml_conversion_13@N@comment_to_xml_conversion_14</USR><Declaration>namespace comment_to_xml_conversion_14 {}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Namespace>]
+ }
+}
+
+/// Aaa.
+enum comment_to_xml_conversion_15 {
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: EnumDecl=comment_to_xml_conversion_15:{{.*}} FullCommentAsXML=[<Enum file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_15</Name><USR>c:@E@comment_to_xml_conversion_15</USR><Declaration>enum comment_to_xml_conversion_15{{( : int)?}} {}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Enum>]
+
+ /// Aaa.
+ comment_to_xml_conversion_16
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:3: EnumConstantDecl=comment_to_xml_conversion_16:{{.*}} FullCommentAsXML=[<Variable file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="3"><Name>comment_to_xml_conversion_16</Name><USR>c:@E@comment_to_xml_conversion_15@comment_to_xml_conversion_16</USR><Declaration>comment_to_xml_conversion_16</Declaration><Abstract><Para> Aaa.</Para></Abstract></Variable>]
+};
+
+/// Aaa.
+enum class comment_to_xml_conversion_17 {
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:12: EnumDecl=comment_to_xml_conversion_17:{{.*}} FullCommentAsXML=[<Enum file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="12"><Name>comment_to_xml_conversion_17</Name><USR>c:@E@comment_to_xml_conversion_17</USR><Declaration>enum class comment_to_xml_conversion_17 : int {}</Declaration><Abstract><Para> Aaa.</Para></Abstract></Enum>]
+
+ /// Aaa.
+ comment_to_xml_conversion_18
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:3: EnumConstantDecl=comment_to_xml_conversion_18:{{.*}} FullCommentAsXML=[<Variable file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="3"><Name>comment_to_xml_conversion_18</Name><USR>c:@E@comment_to_xml_conversion_17@comment_to_xml_conversion_18</USR><Declaration>comment_to_xml_conversion_18</Declaration><Abstract><Para> Aaa.</Para></Abstract></Variable>]
+};
+
+/// Aaa.
+/// \todo Bbb.
+void comment_to_xml_conversion_todo_1();
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_todo_1:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_todo_1</Name><USR>c:@F@comment_to_xml_conversion_todo_1#</USR><Declaration>void comment_to_xml_conversion_todo_1()</Declaration><Abstract><Para> Aaa. </Para></Abstract><Discussion><Para kind="todo"> Bbb.</Para></Discussion></Function>]
+
+/// Aaa.
+/// \todo Bbb.
+///
+/// Ccc.
+void comment_to_xml_conversion_todo_2();
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_todo_2:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_todo_2</Name><USR>c:@F@comment_to_xml_conversion_todo_2#</USR><Declaration>void comment_to_xml_conversion_todo_2()</Declaration><Abstract><Para> Aaa. </Para></Abstract><Discussion><Para kind="todo"> Bbb.</Para><Para> Ccc.</Para></Discussion></Function>]
+
+/// Aaa.
+/// \todo Bbb.
+///
+/// Ccc.
+/// \todo Ddd.
+void comment_to_xml_conversion_todo_3();
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_todo_3:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_todo_3</Name><USR>c:@F@comment_to_xml_conversion_todo_3#</USR><Declaration>void comment_to_xml_conversion_todo_3()</Declaration><Abstract><Para> Aaa. </Para></Abstract><Discussion><Para kind="todo"> Bbb.</Para><Para> Ccc. </Para><Para kind="todo"> Ddd.</Para></Discussion></Function>]
+
+/// Aaa.
+/// \todo Bbb.
+/// \todo Ccc.
+void comment_to_xml_conversion_todo_4();
+// CHECK: comment-to-html-xml-conversion.cpp:[[@LINE-1]]:6: FunctionDecl=comment_to_xml_conversion_todo_4:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}comment-to-html-xml-conversion.cpp" line="[[@LINE-1]]" column="6"><Name>comment_to_xml_conversion_todo_4</Name><USR>c:@F@comment_to_xml_conversion_todo_4#</USR><Declaration>void comment_to_xml_conversion_todo_4()</Declaration><Abstract><Para> Aaa. </Para></Abstract><Discussion><Para kind="todo"> Bbb. </Para><Para kind="todo"> Ccc.</Para></Discussion></Function>]
+
+#endif
+
diff --git a/test/Index/comment-xml-schema.c b/test/Index/comment-xml-schema.c
index 91ea7b2..b8560f7 100644
--- a/test/Index/comment-xml-schema.c
+++ b/test/Index/comment-xml-schema.c
@@ -30,6 +30,8 @@
// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/valid-typedef-02.xml
//
// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/valid-enum-01.xml
+//
+// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/valid-para-kind-01.xml
// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-01.xml 2>&1 | FileCheck %s -check-prefix=INVALID
// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-02.xml 2>&1 | FileCheck %s -check-prefix=INVALID
@@ -43,6 +45,9 @@
// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-10.xml 2>&1 | FileCheck %s -check-prefix=INVALID
// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-11.xml 2>&1 | FileCheck %s -check-prefix=INVALID
// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-function-12.xml 2>&1 | FileCheck %s -check-prefix=INVALID
+//
+// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-para-kind-01.xml 2>&1 | FileCheck %s -check-prefix=INVALID
+// RUN: xmllint --noout --relaxng %S/../../bindings/xml/comment-xml-schema.rng %S/Inputs/CommentXML/invalid-para-kind-02.xml 2>&1 | FileCheck %s -check-prefix=INVALID
// CHECK-INVALID: fails to validate
diff --git a/test/Index/complete-declarators.m b/test/Index/complete-declarators.m
index 071df60..b3a60de 100644
--- a/test/Index/complete-declarators.m
+++ b/test/Index/complete-declarators.m
@@ -22,8 +22,20 @@
static P *p = 0;
}
+- (boid)method2 {}
@end
+// RUN: c-index-test -code-completion-at=%s:7:4 %s | FileCheck -check-prefix=CHECK-CC0 %s
+// CHECK-CC0: NotImplemented:{TypedText IBAction}{RightParen )}{Placeholder selector}{Colon :}{LeftParen (}{Text id}{RightParen )}{Text sender} (40)
+// CHECK-CC0: macro definition:{TypedText IBAction} (70)
+// CHECK-CC0: macro definition:{TypedText IBOutlet} (70)
+// CHECK-CC0: macro definition:{TypedText IBOutletCollection}{LeftParen (}{Placeholder ClassName}{RightParen )} (70)
+// CHECK-CC0: TypedefDecl:{TypedText id} (50)
+// CHECK-CC0: NotImplemented:{TypedText in} (40)
+// CHECK-CC0: NotImplemented:{TypedText inout} (40)
+// CHECK-CC0: NotImplemented:{TypedText instancetype} (40)
+// CHECK-CC0: NotImplemented:{TypedText int} (50)
+// CHECK-CC0: NotImplemented:{TypedText long} (50)
// RUN: c-index-test -code-completion-at=%s:7:19 %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1-NOT: NotImplemented:{TypedText extern} (40)
// CHECK-CC1: NotImplemented:{TypedText param1} (40)
@@ -70,3 +82,8 @@
// CHECK-CC5: NotImplemented:{TypedText unsigned} (50)
// CHECK-CC5: NotImplemented:{TypedText void} (50)
// CHECK-CC5: NotImplemented:{TypedText volatile} (50)
+
+// Check that there are no duplicate entries if we code-complete after an @implementation
+// RUN: c-index-test -code-completion-at=%s:27:1 %s | FileCheck -check-prefix=CHECK-CC6 %s
+// CHECK-CC6: ObjCInterfaceDecl:{TypedText A}
+// CHECK-CC6-NOT: ObjCInterfaceDecl:{TypedText A}
diff --git a/test/Index/complete-documentation-properties.m b/test/Index/complete-documentation-properties.m
new file mode 100644
index 0000000..774a020
--- /dev/null
+++ b/test/Index/complete-documentation-properties.m
@@ -0,0 +1,92 @@
+// Note: the run lines follow their respective tests, since line/column numbers
+// matter in this test.
+// This test is for when property accessors do not have their own code
+// completion comments. Use those in their properties in this case.
+// rdar://12791315
+
+@interface AppDelegate
+/**
+ \brief This is ReadonlyProperty
+*/
+@property (readonly, getter = ReadonlyGetter) id MyProperty;
+
+/**
+ \brief This is GeneralProperty
+*/
+@property int GeneralProperty;
+
+/**
+ \brief This is PropertyInPrimaryClass
+*/
+@property (copy, nonatomic) id PropertyInPrimaryClass;
+
+- (void) setThisRecord : (id)arg;
+- (id) Record;
+@end
+
+
+@interface AppDelegate()
+- (id) GetterInClassExtension;
+/**
+ \brief This is Record
+*/
+@property (copy, setter = setThisRecord:) id Record;
+@end
+
+@interface AppDelegate()
+/**
+ \brief This is PropertyInClassExtension
+*/
+@property (copy, getter = GetterInClassExtension) id PropertyInClassExtension;
+
+- (id) PropertyInPrimaryClass;
+@end
+
+@implementation AppDelegate
+- (id) PropertyInPrimaryClass {
+ id p = [self ReadonlyGetter];
+ p = [self GetterInClassExtension];
+ p = [self PropertyInPrimaryClass];
+ p = [self Record];
+ [self setThisRecord : (id)0 ];
+ p = self.GetterInClassExtension;
+ return 0;
+}
+@end
+// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:47:16 %s | FileCheck -check-prefix=CC1 %s
+// CHECK-CC1: {TypedText ReadonlyGetter}{{.*}}(brief comment: This is ReadonlyProperty)
+
+// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:48:13 %s | FileCheck -check-prefix=CC2 %s
+// CHECK-CC2: {TypedText GetterInClassExtension}{{.*}}(brief comment: This is PropertyInClassExtension)
+
+// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:49:13 %s | FileCheck -check-prefix=CC3 %s
+// CHECK-CC3: {TypedText PropertyInPrimaryClass}{{.*}}(brief comment: This is PropertyInPrimaryClass)
+
+// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:50:13 %s | FileCheck -check-prefix=CC4 %s
+// CHECK-CC4: {TypedText Record}{{.*}}(brief comment: This is Record)
+
+// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:51:9 %s | FileCheck -check-prefix=CC5 %s
+// CHECK-CC5: {TypedText setThisRecord:}{Placeholder (id)}{{.*}}(brief comment: This is Record)
+
+// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:52:12 %s | FileCheck -check-prefix=CC6 %s
+// CHECK-CC6: {TypedText GetterInClassExtension}{{.*}}(brief comment: This is PropertyInClassExtension)
+
+@interface AnotherAppDelegate
+/**
+ \brief This is ReadonlyProperty
+*/
+@property (getter = ReadonlyGetter) int MyProperty;
+/**
+ \brief This is getter = ReadonlyGetter
+*/
+- (int) ReadonlyGetter;
+@end
+
+@implementation AnotherAppDelegate
+- (int) PropertyInPrimaryClass {
+self.ReadonlyGetter;
+}
+@end
+// RUN: env CINDEXTEST_COMPLETION_BRIEF_COMMENTS=1 c-index-test -code-completion-at=%s:87:6 %s | FileCheck -check-prefix=CC7 %s
+// CHECK-CC7: {TypedText ReadonlyGetter}{{.*}}(brief comment: This is getter = ReadonlyGetter)
+
diff --git a/test/Index/complete-driver-errors.c b/test/Index/complete-driver-errors.c
deleted file mode 100644
index 566090c..0000000
--- a/test/Index/complete-driver-errors.c
+++ /dev/null
@@ -1,24 +0,0 @@
-int *blah = 1;
-
-int
-
-// CHECK-RESULTS: NotImplemented:{TypedText const} (40)
-// CHECK-RESULTS: NotImplemented:{TypedText restrict} (40)
-// CHECK-RESULTS: NotImplemented:{TypedText volatile} (40)
-// CHECK-DIAGS: error: invalid value '' in '-std='
-// CHECK-DIAGS: complete-driver-errors.c:1:6:{1:13-1:14}: warning: incompatible integer to pointer conversion initializing 'int *' with an expression of type 'int'
-
-// Test driver errors with code completion
-// RUN: c-index-test -code-completion-at=%s:4:1 -std= %s 2> %t | FileCheck -check-prefix=CHECK-RESULTS %s
-// RUN: FileCheck -check-prefix=CHECK-DIAGS %s < %t
-
-// Test driver errors with parsing
-// RUN: c-index-test -test-load-source all -std= %s 2> %t | FileCheck -check-prefix=CHECK-LOAD %s
-// RUN: FileCheck -check-prefix=CHECK-DIAGS %s < %t
-// CHECK-LOAD: complete-driver-errors.c:1:6: VarDecl=blah:1:6
-
-// Test driver errors with code completion and precompiled preamble
-// RUN: env CINDEXTEST_EDITING=1 c-index-test -code-completion-at=%s:4:1 -std= %s 2> %t | FileCheck -check-prefix=CHECK-RESULTS %s
-// RUN: FileCheck -check-prefix=CHECK-DIAGS %s < %t
-// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source all -std= %s 2> %t | FileCheck -check-prefix=CHECK-LOAD %s
-// RUN: FileCheck -check-prefix=CHECK-DIAGS %s < %t
diff --git a/test/Index/complete-exprs.c b/test/Index/complete-exprs.c
index afb6219..bace067 100644
--- a/test/Index/complete-exprs.c
+++ b/test/Index/complete-exprs.c
@@ -66,4 +66,4 @@ void f5(float f) {
// CHECK-CC7: FunctionDecl:{ResultType void}{TypedText f3}{LeftParen (}{Placeholder const char *, ...}{Text , NULL}{RightParen )} (50)
// CHECK-CC7: FunctionDecl:{ResultType void}{TypedText f4}{LeftParen (}{Placeholder const char *str}{RightParen )} (50)
// CHECK-CC7: FunctionDecl:{ResultType void}{TypedText f5}{LeftParen (}{Placeholder float f}{RightParen )} (50)
-// CHECK-CC7: TypedefDecl:{TypedText type}
+// CHECK-CC7: TypedefDecl:{TypedText type} (50)
diff --git a/test/Index/complete-lambdas.mm b/test/Index/complete-lambdas.mm
index 68f2b6b..049dc1d 100644
--- a/test/Index/complete-lambdas.mm
+++ b/test/Index/complete-lambdas.mm
@@ -42,7 +42,7 @@
// RUN: c-index-test -code-completion-at=%s:18:10 -x objective-c++ -std=c++11 %s | FileCheck -check-prefix=CHECK-CC1 %s
// RUN: c-index-test -code-completion-at=%s:19:8 -x objective-c++ -std=c++11 %s | FileCheck -check-prefix=CHECK-CC5 %s
-// CHECK-CC5: NotImplemented:{ResultType SEL}{TypedText _cmd} (80)
+// CHECK-CC5: NotImplemented:{ResultType SEL}{TypedText _cmd} (34)
// 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
diff --git a/test/Index/complete-macro-args.c b/test/Index/complete-macro-args.c
index ca36af1..2507984 100644
--- a/test/Index/complete-macro-args.c
+++ b/test/Index/complete-macro-args.c
@@ -12,11 +12,47 @@ void test(struct Point *p) {
MACRO(p->x);
}
+#define MACRO3(x,y,z) x;y;z
+
+void test2(struct Point *p) {
+ MACRO3(p->x);
+ MACRO3(p->x
+}
+
+#define FM(x) x
+void test3(struct Point *p) {
+ FM(p->x, a);
+}
+
+#define VGM(...) 0
+#define VGM2(...) __VA_ARGS__
+
+// These need to be last, to test proper handling of EOF.
+#ifdef EOF_TEST1
+void test3(struct Point *p) {
+ VGM(1,2, p->x
+
+#elif EOF_TEST2
+void test3(struct Point *p) {
+ VGM2(VGM(1,2, p->x
+
+#endif
+
// RUN: c-index-test -code-completion-at=%s:11:12 %s | FileCheck %s
// RUN: c-index-test -code-completion-at=%s:12:12 %s | FileCheck %s
+// RUN: c-index-test -code-completion-at=%s:18:13 %s | FileCheck %s
+// RUN: c-index-test -code-completion-at=%s:19:13 %s | FileCheck %s
+// RUN: c-index-test -code-completion-at=%s:24:9 %s | FileCheck %s
// CHECK: FieldDecl:{ResultType float}{TypedText x} (35)
// CHECK-NEXT: FieldDecl:{ResultType float}{TypedText y} (35)
// CHECK-NEXT: FieldDecl:{ResultType float}{TypedText z} (35)
// CHECK-NEXT: Completion contexts:
// CHECK-NEXT: Arrow member access
// CHECK-NEXT: Container Kind: StructDecl
+
+// With these, code-completion is unknown because the macro argument (and the
+// completion point) is not expanded by the macro definition.
+// RUN: c-index-test -code-completion-at=%s:33:15 %s -DEOF_TEST1 | FileCheck %s -check-prefix=CHECK-EOF
+// RUN: c-index-test -code-completion-at=%s:37:20 %s -DEOF_TEST2 | FileCheck %s -check-prefix=CHECK-EOF
+// CHECK-EOF: Completion contexts:
+// CHECK-EOF: Unknown
diff --git a/test/Index/complete-modules.m b/test/Index/complete-modules.m
index b82430d..d63c4b8 100644
--- a/test/Index/complete-modules.m
+++ b/test/Index/complete-modules.m
@@ -1,14 +1,17 @@
// Note: the run lines follow their respective tests, since line/column
// matter in this test.
-@__experimental_modules_import LibA.Extensions;
+@import LibA.Extensions;
// RUN: rm -rf %t
-// RUN: c-index-test -code-completion-at=%s:4:32 -fmodule-cache-path %t -fmodules -F %S/Inputs/Frameworks -I %S/Inputs/Headers %s | FileCheck -check-prefix=CHECK-TOP-LEVEL %s
+// RUN: c-index-test -code-completion-at=%s:4:9 -fmodules-cache-path=%t -fmodules -F %S/Inputs/Frameworks -I %S/Inputs/Headers %s | FileCheck -check-prefix=CHECK-TOP-LEVEL %s
// CHECK-TOP-LEVEL: NotImplemented:{TypedText Framework} (50)
// CHECK-TOP-LEVEL: NotImplemented:{TypedText LibA} (50)
// CHECK-TOP-LEVEL: NotImplemented:{TypedText nested} (50)
-// RUN: c-index-test -code-completion-at=%s:4:37 -fmodule-cache-path %t -fmodules -F %S/Inputs/Frameworks -I %S/Inputs/Headers %s | FileCheck -check-prefix=CHECK-LIBA %s
+// RUN: c-index-test -code-completion-at=%s:4:14 -fmodules-cache-path=%t -fmodules -F %S/Inputs/Frameworks -I %S/Inputs/Headers %s | FileCheck -check-prefix=CHECK-LIBA %s
// CHECK-LIBA: NotImplemented:{TypedText Extensions} (50)
+// RUN: c-index-test -code-completion-at=%s:4:1 -fmodules-cache-path=%t -fmodules -F %S/Inputs/Frameworks -I %S/Inputs/Headers %s | FileCheck -check-prefix=CHECK-TOP %s
+// CHECK-TOP: NotImplemented:{TypedText @import}{HorizontalSpace }{Placeholder module} (40)
+
diff --git a/test/Index/complete-objc-message.m b/test/Index/complete-objc-message.m
index aa10ea2..5a72005 100644
--- a/test/Index/complete-objc-message.m
+++ b/test/Index/complete-objc-message.m
@@ -193,6 +193,7 @@ void test_DO(DO *d, A* a) {
// 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 instanceMethod1} (35)
// CHECK-CC1: {TypedText new} (35)
// CHECK-CC1: {TypedText protocolClassMethod} (37)
// CHECK-CC1: Completion contexts:
@@ -238,15 +239,15 @@ void test_DO(DO *d, A* a) {
// CHECK-CC9: ObjCInstanceMethodDecl:{ResultType int}{Informative Method:}{Informative Arg1:}{TypedText OtherArg:}{Placeholder (id)}
// CHECK-CC9: Objective-C selector: Method:Arg1:
// RUN: c-index-test -code-completion-at=%s:61:11 %s | FileCheck -check-prefix=CHECK-CCA %s
-// CHECK-CCA: TypedefDecl:{TypedText Class}
-// CHECK-CCA-NEXT: ObjCInterfaceDecl:{TypedText Foo}
-// CHECK-CCA-NOT: FunctionDecl:{ResultType void}{TypedText func}{LeftParen (}{RightParen )}
-// CHECK-CCA:FunctionDecl:{ResultType MyClass *}{TypedText getMyClass}{LeftParen (}{RightParen )}
-// CHECK-CCA: TypedefDecl:{TypedText id}
-// CHECK-CCA: ObjCInterfaceDecl:{TypedText MyClass}
-// CHECK-CCA: ObjCInterfaceDecl:{TypedText MySubClass}
-// CHECK-CCA: {ResultType Class}{TypedText self}
-// CHECK-CCA: {TypedText super}
+// CHECK-CCA: TypedefDecl:{TypedText Class} (50)
+// CHECK-CCA-NEXT: ObjCInterfaceDecl:{TypedText Foo} (50)
+// CHECK-CCA-NOT: FunctionDecl:{ResultType void}{TypedText func}{LeftParen (}{RightParen )} (50)
+// CHECK-CCA:FunctionDecl:{ResultType MyClass *}{TypedText getMyClass}{LeftParen (}{RightParen )} (50)
+// CHECK-CCA: TypedefDecl:{TypedText id} (50)
+// CHECK-CCA: ObjCInterfaceDecl:{TypedText MyClass} (50)
+// CHECK-CCA: ObjCInterfaceDecl:{TypedText MySubClass} (50)
+// CHECK-CCA: {ResultType Class}{TypedText self} (34)
+// CHECK-CCA: {TypedText super} (40)
// RUN: c-index-test -code-completion-at=%s:103:6 %s | FileCheck -check-prefix=CHECK-CCB %s
// CHECK-CCB: ObjCInstanceMethodDecl:{ResultType int}{TypedText Method:}{Placeholder (int), ...}
// CHECK-CCB: ObjCInstanceMethodDecl:{ResultType int}{TypedText SentinelMethod:}{Placeholder (int), ...}{Text , nil}
diff --git a/test/Index/complete-stmt.c b/test/Index/complete-stmt.c
index e39431e..3d31ca2 100644
--- a/test/Index/complete-stmt.c
+++ b/test/Index/complete-stmt.c
@@ -1,7 +1,7 @@
// Note: the run lines follow their respective tests, since line/column
// matter in this test.
-
+typedef int Integer;
void f(int x) {
if (x) {
}
@@ -14,3 +14,12 @@ void f(int x) {
// RUN: c-index-test -code-completion-at=%s:7:4 %s | FileCheck -check-prefix=CHECK-IF-ELSE-SIMPLE %s
// CHECK-IF-ELSE-SIMPLE: NotImplemented:{TypedText else} (40)
// CHECK-IF-ELSE-SIMPLE: NotImplemented:{TypedText else}{HorizontalSpace }{Text if}{HorizontalSpace }{LeftParen (}{Placeholder expression}{RightParen )} (40)
+
+// RUN: c-index-test -code-completion-at=%s:6:1 %s | FileCheck -check-prefix=CHECK-STMT %s
+// CHECK-STMT: NotImplemented:{TypedText char} (50)
+// CHECK-STMT: NotImplemented:{TypedText const} (50)
+// CHECK-STMT: NotImplemented:{TypedText double} (50)
+// CHECK-STMT: NotImplemented:{TypedText enum} (50)
+// CHECK-STMT: FunctionDecl:{ResultType void}{TypedText f}{LeftParen (}{Placeholder int x}{RightParen )} (50)
+// CHECK-STMT: TypedefDecl:{TypedText Integer} (50)
+// CHECK-STMT: ParmDecl:{ResultType int}{TypedText x} (34)
diff --git a/test/Index/complete-super.m b/test/Index/complete-super.m
index 6c2daa8..be7edfd 100644
--- a/test/Index/complete-super.m
+++ b/test/Index/complete-super.m
@@ -53,8 +53,7 @@ typedef int Bool;
// CHECK-ADD-ADD: ObjCInstanceMethodDecl:{ResultType void}{TypedText last} (35)
// RUN: c-index-test -code-completion-at=%s:24:10 %s | FileCheck -check-prefix=CHECK-SELECTOR-SELECTOR %s
-// CHECK-SELECTOR-SELECTOR-NOT: x
-// CHECK-SELECTOR-SELECTOR: ObjCClassMethodDecl:{ResultType void}{TypedText last} (35)
+// CHECK-SELECTOR-SELECTOR: ObjCInstanceMethodDecl:{ResultType void}{TypedText last} (35)
// CHECK-SELECTOR-SELECTOR: ObjCClassMethodDecl:{ResultType void}{TypedText select:}{Placeholder condition}{HorizontalSpace }{Text first:}{Placeholder a}{HorizontalSpace }{Text second:}{Placeholder b} (20)
// Check "super" completion at the second identifier
diff --git a/test/Index/crash-recovery-code-complete.c b/test/Index/crash-recovery-code-complete.c
index dde90bc..c502ce5 100644
--- a/test/Index/crash-recovery-code-complete.c
+++ b/test/Index/crash-recovery-code-complete.c
@@ -7,6 +7,8 @@
// CHECK-CODE-COMPLETE-CRASH: Unable to perform code completion!
//
// REQUIRES: crash-recovery
-// REQUIRES: shell
+
+// FIXME: Please investigate abnormal path in MemoryBuffer.
+// XFAIL: mingw32,win32
#warning parsing original file
diff --git a/test/Index/crash-recovery-modules.m b/test/Index/crash-recovery-modules.m
index 212923f..23740ec 100644
--- a/test/Index/crash-recovery-modules.m
+++ b/test/Index/crash-recovery-modules.m
@@ -2,18 +2,18 @@
// RUN: rm -rf %t
// Parse the file, such that building the module will cause Clang to crash.
-// RUN: not env CINDEXTEST_FAILONERROR=1 c-index-test -test-load-source all -fmodules -fmodule-cache-path %t -Xclang -fdisable-module-hash -I %S/Inputs/Headers -DCRASH %s 2> %t.err
+// RUN: not env CINDEXTEST_FAILONERROR=1 c-index-test -test-load-source all -fmodules -fmodules-cache-path=%t -Xclang -fdisable-module-hash -I %S/Inputs/Headers -DCRASH %s 2> %t.err
// RUN: FileCheck < %t.err -check-prefix=CHECK-CRASH %s
-// CHECK-CRASH: crash-recovery-modules.m:16:32:{16:2-16:37}: fatal error: could not build module 'Crash'
+// CHECK-CRASH: crash-recovery-modules.m:16:9:{16:2-16:14}: fatal error: could not build module 'Crash'
// Parse the file again, without crashing, to make sure that
// subsequent parses do the right thing.
-// RUN: env CINDEXTEST_FAILONERROR=1 c-index-test -test-load-source all -fmodules -fmodule-cache-path %t -Xclang -fdisable-module-hash -I %S/Inputs/Headers %s
+// RUN: env CINDEXTEST_FAILONERROR=1 c-index-test -test-load-source all -fmodules -fmodules-cache-path=%t -Xclang -fdisable-module-hash -I %S/Inputs/Headers %s
// REQUIRES: crash-recovery
// REQUIRES: shell
-@__experimental_modules_import Crash;
+@import Crash;
void test() {
const char* error = getCrashString();
diff --git a/test/Index/crash-recovery-reparse.c b/test/Index/crash-recovery-reparse.c
index 06bb76b..e3f7265 100644
--- a/test/Index/crash-recovery-reparse.c
+++ b/test/Index/crash-recovery-reparse.c
@@ -7,6 +7,5 @@
// CHECK-REPARSE-SOURCE-CRASH: Unable to reparse translation unit
//
// REQUIRES: crash-recovery
-// REQUIRES: shell
#warning parsing original file
diff --git a/test/Index/file-includes.c b/test/Index/file-includes.c
new file mode 100644
index 0000000..2dfced0
--- /dev/null
+++ b/test/Index/file-includes.c
@@ -0,0 +1,24 @@
+
+#include "targeted-top.h"
+#include "targeted-preamble.h"
+
+extern int LocalVar;
+int LocalVar;
+
+// RUN: c-index-test -write-pch %t.h.pch %S/targeted-top.h -Xclang -detailed-preprocessing-record
+
+// RUN: c-index-test -file-includes-in=%s %s | FileCheck %s -check-prefix=LOCAL
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -file-includes-in=%s %s | FileCheck %s -check-prefix=LOCAL
+// RUN: c-index-test -file-includes-in=%s %s -include %t.h | FileCheck %s -check-prefix=LOCAL
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -file-includes-in=%s %s -include %t.h | FileCheck %s -check-prefix=LOCAL
+
+// LOCAL: inclusion directive=targeted-top.h ({{.*[/\\]}}test{{[/\\]}}Index{{[/\\]}}targeted-top.h) {{.*}}=[2:1 - 2:2]
+// LOCAL: inclusion directive=targeted-preamble.h ({{.*[/\\]}}test{{[/\\]}}Index{{[/\\]}}targeted-preamble.h) =[3:1 - 3:2]
+
+// RUN: c-index-test -file-includes-in=%S/targeted-top.h %s | FileCheck %s -check-prefix=TOP
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -file-includes-in=%S/targeted-top.h %s | FileCheck %s -check-prefix=TOP
+// RUN: c-index-test -file-includes-in=%S/targeted-top.h %s -include %t.h | FileCheck %s -check-prefix=TOP
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -file-includes-in=%S/targeted-top.h %s -include %t.h | FileCheck %s -check-prefix=TOP
+
+// TOP: inclusion directive=targeted-nested1.h ({{.*[/\\]}}test{{[/\\]}}Index{{[/\\]}}targeted-nested1.h) =[5:1 - 5:2]
+// TOP: inclusion directive=targeted-fields.h ({{.*[/\\]}}test{{[/\\]}}Index{{[/\\]}}targeted-fields.h) =[16:1 - 16:2]
diff --git a/test/Index/fix-its.c b/test/Index/fix-its.c
index d5cb1af..1e710c2 100644
--- a/test/Index/fix-its.c
+++ b/test/Index/fix-its.c
@@ -22,6 +22,6 @@ int printf(const char *restrict, ...);
void f2() {
unsigned long index;
// CHECK: warning: format specifies type 'int' but the argument has type 'unsigned long'
- // CHECK: FIX-IT: Replace [26:17 - 26:19] with "%ld"
+ // CHECK: FIX-IT: Replace [26:17 - 26:19] with "%lu"
MACRO(printf("%d", index));
}
diff --git a/test/Index/fix-its.m b/test/Index/fix-its.m
new file mode 100644
index 0000000..b307cf4
--- /dev/null
+++ b/test/Index/fix-its.m
@@ -0,0 +1,28 @@
+// RUN: c-index-test -test-load-source all %s -Wno-objc-root-class > %t 2>&1
+// RUN: FileCheck -input-file=%t %s
+
+@class NSString;
+void _rdar_12584554_A (volatile const void * object, volatile const void * selector, const char * functionName, const char * fileName, unsigned int lineNumber, NSString * msgFormat, ...);
+#define _rdar_12584554_B(self,_format_and_args_...) \
+ do{ _rdar_12584554_A(&self,&_cmd,__PRETTY_FUNCTION__,__FILE__,__LINE__, _format_and_args_); }while(0)
+#define _rdar_12584554_C(_format_and_args_...) \
+ _rdar_12584554_B(self, _format_and_args_)
+
+@interface RDar12584554
+@end
+
+// This test case tests that the "@" is properly inserted before the '"', even in the
+// presence of a nested macro chain.
+@implementation RDar12584554
+- (void) test:(int)result {
+ _rdar_12584554_C("ted");
+}
+@end
+
+// CHECK: FIX-IT: Insert "@" at 18:22
+// CHECK: fix-its.m:9:28: note: expanded from macro '_rdar_12584554_C'
+// CHECK: Number FIX-ITs = 0
+// CHECK: fix-its.m:7:77: note: expanded from macro '_rdar_12584554_B'
+// CHECK: Number FIX-ITs = 0
+// CHECK: fix-its.m:5:172: note: passing argument to parameter 'msgFormat' here
+// CHECK: Number FIX-ITs = 0
diff --git a/test/Index/format-comment-cdecls.c b/test/Index/format-comment-cdecls.c
new file mode 100644
index 0000000..471be2b
--- /dev/null
+++ b/test/Index/format-comment-cdecls.c
@@ -0,0 +1,99 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: c-index-test -test-load-source all -comments-xml-schema=%S/../../bindings/xml/comment-xml-schema.rng -target x86_64-apple-darwin10 %s \
+// RUN: | FileCheck %s
+
+/**
+ * \brief Aaa.
+*/
+int global_function();
+// CHECK: <Declaration>int global_function()</Declaration>
+
+/**
+ * \param x1 Aaa.
+*/
+extern void external_function(int x1);
+// CHECK: <Declaration>extern void external_function(int x1)</Declaration>
+
+/**
+ * \brief global variable;
+*/
+int global_variable;
+// CHECK: <Declaration>int global_variable</Declaration>
+
+/**
+ * \brief local variable;
+*/
+static int static_variable;
+// CHECK: <Declaration>static int static_variable</Declaration>
+
+/**
+ * \brief external variable
+*/
+extern int external_variable;
+// CHECK: <Declaration>extern int external_variable</Declaration>
+
+int global_function() {
+ /**
+ * \brief a local variable
+ */
+ int local = 10;
+ return local;
+}
+// CHECK: <Declaration>int global_function()</Declaration>
+// CHECK: <Declaration>int local = 10</Declaration>
+
+/**
+ * \brief initialized decl.
+*/
+int initialized_global = 100;
+// CHECK: <Declaration>int initialized_global = 100</Declaration>
+
+/**
+ * \brief typedef example
+*/
+typedef int INT_T;
+// CHECK: <Declaration>typedef int INT_T</Declaration>
+
+/**
+ * \brief aggregate type example
+*/
+struct S {
+/**
+ * \brief iS1;
+*/
+ int iS1;
+/**
+ * \brief dS1;
+*/
+ double dS1;
+};
+// CHECK: <Declaration>struct S {}</Declaration>
+// CHECK: <Declaration>int iS1</Declaration>
+// CHECK: <Declaration>double dS1</Declaration>
+
+/**
+ * \brief enum e;
+*/
+enum e {
+ One,
+/**
+ * \brief Two;
+*/
+ Two,
+ Three
+};
+// CHECK: <Declaration>enum e {}</Declaration>
+// CHECK: <Declaration>Two</Declaration>
+
+/**
+ *\brief block declaration
+*/
+int (^Block) (int i, int j);
+// CHECK: <Declaration>int (^Block)(int, int)</Declaration>
+
+/**
+ *\brief block declaration
+*/
+int (^Block1) (int i, int j) = ^(int i, int j) { return i + j; };
+// CHECK: <Declaration>int (^Block1)(int, int) = ^(int i, int j) {}</Declaration>
diff --git a/test/Index/getcursor-preamble.h b/test/Index/getcursor-preamble.h
new file mode 100644
index 0000000..519e655
--- /dev/null
+++ b/test/Index/getcursor-preamble.h
@@ -0,0 +1,8 @@
+@interface I {
+ struct AA {
+ int x;
+ } aa;
+ int var;
+}
+-(id)foo;
+@end
diff --git a/test/Index/getcursor-preamble.m b/test/Index/getcursor-preamble.m
new file mode 100644
index 0000000..3cc442c
--- /dev/null
+++ b/test/Index/getcursor-preamble.m
@@ -0,0 +1,23 @@
+#include "getcursor-preamble.h"
+
+// RUN: c-index-test \
+// RUN: -cursor-at=%S/getcursor-preamble.h:2:10 \
+// RUN: -cursor-at=%S/getcursor-preamble.h:3:9 \
+// RUN: -cursor-at=%S/getcursor-preamble.h:4:6 \
+// RUN: -cursor-at=%S/getcursor-preamble.h:5:8 \
+// RUN: -cursor-at=%S/getcursor-preamble.h:7:7 \
+// RUN: %s | FileCheck %s
+
+// RUN: env CINDEXTEST_EDITING=1 c-index-test \
+// RUN: -cursor-at=%S/getcursor-preamble.h:2:10 \
+// RUN: -cursor-at=%S/getcursor-preamble.h:3:9 \
+// RUN: -cursor-at=%S/getcursor-preamble.h:4:6 \
+// RUN: -cursor-at=%S/getcursor-preamble.h:5:8 \
+// RUN: -cursor-at=%S/getcursor-preamble.h:7:7 \
+// RUN: %s | FileCheck %s
+
+// CHECK: StructDecl=AA:2:10
+// CHECK: FieldDecl=x:3:9
+// CHECK: ObjCIvarDecl=aa:4:5
+// CHECK: ObjCIvarDecl=var:5:7
+// CHECK: ObjCInstanceMethodDecl=foo:7:6
diff --git a/test/Index/headerfile-comment-to-html.m b/test/Index/headerfile-comment-to-html.m
new file mode 100644
index 0000000..8326a90
--- /dev/null
+++ b/test/Index/headerfile-comment-to-html.m
@@ -0,0 +1,111 @@
+// 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
+// rdar://13067629
+
+// Ensure that XML we generate is not invalid.
+// RUN: FileCheck %s -check-prefix=WRONG < %t/out
+// WRONG-NOT: CommentXMLInvalid
+
+// rdar://12397511
+
+/*!
+ \headerfile Device.h <Foundation/Device.h>
+
+ A Device represents a remote or local computer or device with which the Developer Tools can interact. Each Device supports blah blah blah from doing blah blah blah.
+*/
+@interface Device
+@end
+// CHECK: headerfile-comment-to-html.m:[[@LINE-2]]:12: ObjCInterfaceDecl=Device:{{.*}} FullCommentAsXML=[<Other file="{{[^"]+}}headerfile-comment-to-html.m" line="[[@LINE-2]]" column="12"><Name>Device</Name><USR>c:objc(cs)Device</USR><Headerfile><Para> Device.h &lt;Foundation/Device.h&gt;</Para></Headerfile><Declaration>@interface Device\n@end</Declaration><Abstract><Para> A Device represents a remote or local computer or device with which the Developer Tools can interact. Each Device supports blah blah blah from doing blah blah blah.</Para></Abstract></Other>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[headerfile]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Device.h ])
+// CHECK-NEXT: (CXComment_Text Text=[<Foundation])
+// CHECK-NEXT: (CXComment_Text Text=[/Device.h>])))
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ A Device represents a remote or local computer or device with which the Developer Tools can interact. Each Device supports blah blah blah from doing blah blah blah.])))]
+
+/*!
+ \headerfile Sensor.h "Sensor.h"
+
+ \brief This is Sensor on the Device.
+ Its purpose is not to Sense Device's heat.
+*/
+
+@interface Sensor
+@end
+// CHECK: headerfile-comment-to-html.m:[[@LINE-2]]:12: ObjCInterfaceDecl=Sensor:{{.*}} FullCommentAsXML=[<Other file="{{[^"]+}}headerfile-comment-to-html.m" line="[[@LINE-2]]" column="12"><Name>Sensor</Name><USR>c:objc(cs)Sensor</USR><Headerfile><Para> Sensor.h &quot;Sensor.h&quot;</Para></Headerfile><Declaration>@interface Sensor\n@end</Declaration><Abstract><Para> This is Sensor on the Device. Its purpose is not to Sense Device&apos;s heat.</Para></Abstract></Other>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[headerfile]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Sensor.h "Sensor.h"])))
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[brief]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ This is Sensor on the Device.] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ Its purpose is not to Sense Device's heat.]))))]
+
+/*!
+ \brief Test that headerfile can come after brief.
+ \headerfile VTDevice.h <VTFoundation/VTDevice.h>
+
+ More property decription goes here.
+*/
+@interface VTDevice : Device
+@end
+// CHECK: headerfile-comment-to-html.m:[[@LINE-2]]:12: ObjCInterfaceDecl=VTDevice:{{.*}} FullCommentAsXML=[<Other file="{{[^"]+}}headerfile-comment-to-html.m" line="[[@LINE-2]]" column="12"><Name>VTDevice</Name><USR>c:objc(cs)VTDevice</USR><Headerfile><Para> VTDevice.h &lt;VTFoundation/VTDevice.h&gt;</Para></Headerfile><Declaration>@interface VTDevice : Device\n@end</Declaration><Abstract><Para> Test that headerfile can come after brief. </Para></Abstract><Discussion><Para> More property decription goes here.</Para></Discussion></Other>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[brief]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ Test that headerfile can come after brief.] HasTrailingNewline)
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[headerfile]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ VTDevice.h ])
+// CHECK-NEXT: (CXComment_Text Text=[<VTFoundation])
+// CHECK-NEXT: (CXComment_Text Text=[/VTDevice.h>])))
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ More property decription goes here.])))]
+
+/*!
+ \headerfile <stdio.h>
+*/
+extern void uses_stdio_h();
+// CHECK: headerfile-comment-to-html.m:[[@LINE-1]]:13: FunctionDecl=uses_stdio_h:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}headerfile-comment-to-html.m" line="[[@LINE-1]]" column="13"><Name>uses_stdio_h</Name><USR>c:@F@uses_stdio_h</USR><Headerfile><Para> &lt;stdio.h&gt;</Para></Headerfile><Declaration>extern void uses_stdio_h()</Declaration></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[headerfile]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_Text Text=[<stdio])
+// CHECK-NEXT: (CXComment_Text Text=[.h>]))))]
+
+
+/*!
+ \headerfile <algorithm>
+*/
+extern void uses_argorithm();
+// CHECK: headerfile-comment-to-html.m:[[@LINE-1]]:13: FunctionDecl=uses_argorithm:{{.*}} FullCommentAsXML=[<Function file="{{[^"]+}}headerfile-comment-to-html.m" line="[[@LINE-1]]" column="13"><Name>uses_argorithm</Name><USR>c:@F@uses_argorithm</USR><Headerfile><Para> &lt;algorithm&gt;</Para></Headerfile><Declaration>extern void uses_argorithm()</Declaration></Function>]
+// CHECK-NEXT: CommentAST=[
+// CHECK-NEXT: (CXComment_FullComment
+// CHECK-NEXT: (CXComment_Paragraph IsWhitespace
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace))
+// CHECK-NEXT: (CXComment_BlockCommand CommandName=[headerfile]
+// CHECK-NEXT: (CXComment_Paragraph
+// CHECK-NEXT: (CXComment_Text Text=[ ] IsWhitespace)
+// CHECK-NEXT: (CXComment_Text Text=[<algorithm])
+// CHECK-NEXT: (CXComment_Text Text=[>]))))]
diff --git a/test/Index/index-file.cpp b/test/Index/index-file.cpp
index bf2d62c..7634c0d 100644
--- a/test/Index/index-file.cpp
+++ b/test/Index/index-file.cpp
@@ -1,5 +1,9 @@
using MyTypeAlias = int;
+extern "C" {
+ template < typename T > *Allocate() { }
+}
+
// RUN: c-index-test -index-file %s > %t
// RUN: FileCheck %s -input-file=%t
diff --git a/test/Index/index-module.m b/test/Index/index-module.m
index 0af4e37..77dee98 100644
--- a/test/Index/index-module.m
+++ b/test/Index/index-module.m
@@ -1,10 +1,10 @@
#include <DependsOnModule/DependsOnModule.h>
-@__experimental_modules_import DependsOnModule;
+@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: c-index-test -index-file %s -fmodules-cache-path=%t.cache -fmodules -F %S/../Modules/Inputs \
// RUN: -Xclang -fdisable-module-hash | FileCheck %s
// CHECK-NOT: [indexDeclaration]
@@ -26,6 +26,7 @@ int glob;
// CHECK-DMOD-NEXT: [ppIncludedFile]: [[DMOD_PRIVATE_H:.*/Modules/Inputs/DependsOnModule.framework[/\\]PrivateHeaders[/\\]DependsOnModulePrivate.h]] | {{.*}} | hash loc: <invalid>
// CHECK-DMOD-NEXT: [importedASTFile]: {{.*}}.cache{{[/\\]}}Module.pcm | loc: [[DMOD_MODULE_H]]:1:2 | name: "Module" | isImplicit: 1
// CHECK-DMOD-NEXT: [indexDeclaration]: kind: variable | name: depends_on_module_other | {{.*}} | loc: [[DMOD_OTHER_H]]:1:5
+// CHECK-DMOD-NEXT: [importedASTFile]: {{.*}}.cache/DependsOnModule.pcm | loc: {{.*}}SubFramework.h:1:2 | name: "DependsOnModule.SubFramework.Other" | isImplicit: 1
// CHECK-DMOD-NEXT: [indexDeclaration]: kind: variable | name: sub_framework | {{.*}} | loc: [[DMOD_SUB_H]]:2:8
// CHECK-DMOD-NEXT: [indexDeclaration]: kind: variable | name: sub_framework_other | {{.*}} | loc: [[DMOD_SUB_OTHER_H]]:1:9
// CHECK-DMOD-NEXT: [indexDeclaration]: kind: variable | name: depends_on_module_private | {{.*}} | loc: [[DMOD_PRIVATE_H]]:1:5
diff --git a/test/Index/index-pch-with-module.m b/test/Index/index-pch-with-module.m
index ebab648..ef0392e 100644
--- a/test/Index/index-pch-with-module.m
+++ b/test/Index/index-pch-with-module.m
@@ -12,8 +12,8 @@ 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: c-index-test -write-pch %t.h.pch %s -fmodules-cache-path=%t.cache -fmodules -F %S/../Modules/Inputs -Xclang -fdisable-module-hash
+// RUN: c-index-test -index-file %s -include %t.h -fmodules-cache-path=%t.cache -fmodules -F %S/../Modules/Inputs \
// RUN: -Xclang -fdisable-module-hash | FileCheck %s
// CHECK-NOT: [indexDeclaration]
diff --git a/test/Index/index-pch.cpp b/test/Index/index-pch.cpp
index c8da7b2..caab2d7 100644
--- a/test/Index/index-pch.cpp
+++ b/test/Index/index-pch.cpp
@@ -1,6 +1,8 @@
// RUN: c-index-test -write-pch %t.pch -fshort-wchar %s
-// RUN: c-index-test -index-tu %t.pch | FileCheck %s
+// RUN: env LIBCLANG_NOTHREADS=1 c-index-test -index-tu %t.pch | FileCheck %s
+// CHECK: [indexDeclaration]: kind: variable | name: wideStr
const wchar_t *wideStr = L"123";
-// CHECK: [indexDeclaration]: kind: variable | name: wideStr
+// CHECK: [indexDeclaration]: kind: struct | name: __is_void
+struct __is_void {};
diff --git a/test/Index/index-suppress-refs.m b/test/Index/index-suppress-refs.m
index 46420ee..caf67ba 100644
--- a/test/Index/index-suppress-refs.m
+++ b/test/Index/index-suppress-refs.m
@@ -41,4 +41,4 @@ MyInt gx;
// CHECK-NEXT: <protocol>: kind: objc-protocol | name: P
// CHECK-NEXT: [indexDeclaration]: kind: objc-instance-method | name: meth::
// CHECK-NOT: [indexEntityReference]: kind: objc-class | name: B
-// CHECK-NOT: [indexEntityReference]: kind: objc-protocol | name: P \ No newline at end of file
+// CHECK-NOT: [indexEntityReference]: kind: objc-protocol | name: P
diff --git a/test/Index/linkage.c b/test/Index/linkage.c
index 41a1fbd..ab00659 100644
--- a/test/Index/linkage.c
+++ b/test/Index/linkage.c
@@ -13,6 +13,12 @@ static int wibble(int);
void ena(int (*dio)(int tria));
+static int test2;
+void f16(void) {
+ extern int test2;
+}
+
+
// CHECK: EnumDecl=Baz:3:6 (Definition)linkage=External
// CHECK: EnumConstantDecl=Qux:3:12 (Definition)linkage=External
// CHECK: VarDecl=x:4:5linkage=External
@@ -28,3 +34,5 @@ void ena(int (*dio)(int tria));
// CHECK: FunctionDecl=ena:14:6linkage=External
// CHECK: ParmDecl=dio:14:16 (Definition)linkage=NoLinkage
// CHECK: ParmDecl=tria:14:25 (Definition)linkage=NoLinkage
+// CHECK: VarDecl=test2{{.*}}linkage=Internal
+// CHECK: VarDecl=test2{{.*}}linkage=Internal
diff --git a/test/Index/modules-objc-categories.m b/test/Index/modules-objc-categories.m
new file mode 100644
index 0000000..4d0fd26
--- /dev/null
+++ b/test/Index/modules-objc-categories.m
@@ -0,0 +1,10 @@
+@import category_top;
+@import category_left;
+
+@interface Sub : Foo
+- (void)left_sub;
+@end
+
+// RUN: rm -rf %t
+// RUN: c-index-test -test-load-source local -fmodules -fmodules-cache-path=%t %s -I%S/../Modules/Inputs | FileCheck %s
+// CHECK: modules-objc-categories.m:5:9: ObjCInstanceMethodDecl=left_sub:5:9 [Overrides @2:9]
diff --git a/test/Index/overriding-ftemplate-comments.cpp b/test/Index/overriding-ftemplate-comments.cpp
index 2c5f539..0bc3c2f 100644
--- a/test/Index/overriding-ftemplate-comments.cpp
+++ b/test/Index/overriding-ftemplate-comments.cpp
@@ -13,17 +13,29 @@
template<typename T>
void comment_to_html_conversion_17(T AAA);
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_17</Name><USR>c:@FT@&gt;1#Tcomment_to_html_conversion_17#t0.0#</USR><Declaration>template &lt;typename T&gt; void comment_to_html_conversion_17(T AAA)</Declaration><Parameters><Parameter><Name>AAA</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah</Para></Discussion></Parameter></Parameters></Function>]
+
template<typename T>
void comment_to_html_conversion_17(T PPP);
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_17</Name><USR>c:@FT@&gt;1#Tcomment_to_html_conversion_17#t0.0#</USR><Declaration>template &lt;typename T&gt; void comment_to_html_conversion_17(T PPP)</Declaration><Parameters><Parameter><Name>PPP</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah</Para></Discussion></Parameter></Parameters></Function>]
+
+//===----------------------------------------------------------------------===//
+
/// \tparam BBB Bbb
/// \tparam AAA Aaa
template<typename AAA, typename BBB>
void comment_to_html_conversion_19(AAA aaa, BBB bbb);
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_19</Name><USR>c:@FT@&gt;2#T#Tcomment_to_html_conversion_19#t0.0#t0.1#</USR><Declaration>template &lt;typename AAA, typename BBB&gt;\nvoid comment_to_html_conversion_19(AAA aaa, BBB bbb)</Declaration><TemplateParameters><Parameter><Name>AAA</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>BBB</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter></TemplateParameters></Function>]
+
template<typename PPP, typename QQQ>
void comment_to_html_conversion_19(PPP aaa, QQQ bbb);
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_19</Name><USR>c:@FT@&gt;2#T#Tcomment_to_html_conversion_19#t0.0#t0.1#</USR><Declaration>template &lt;typename PPP, typename QQQ&gt;\nvoid comment_to_html_conversion_19(PPP aaa, QQQ bbb)</Declaration><TemplateParameters><Parameter><Name>PPP</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter></TemplateParameters></Function>]
+
+//===----------------------------------------------------------------------===//
+
/// \tparam BBB Bbb
/// \tparam UUU Zzz
/// \tparam CCC Ccc
@@ -31,9 +43,15 @@ void comment_to_html_conversion_19(PPP aaa, QQQ bbb);
template<typename AAA, typename BBB, int CCC>
void comment_to_html_conversion_20(AAA aaa, BBB bbb);
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_20</Name><USR>c:@FT@&gt;3#T#T#NIcomment_to_html_conversion_20#t0.0#t0.1#</USR><Declaration>template &lt;typename AAA, typename BBB, int CCC&gt;\nvoid comment_to_html_conversion_20(AAA aaa, BBB bbb)</Declaration><TemplateParameters><Parameter><Name>AAA</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>BBB</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter><Parameter><Name>CCC</Name><Index>2</Index><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>UUU</Name><Discussion><Para> Zzz </Para></Discussion></Parameter></TemplateParameters></Function>]
+
template<typename PPP, typename QQQ, int RRR>
void comment_to_html_conversion_20(PPP aaa, QQQ bbb);
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_20</Name><USR>c:@FT@&gt;3#T#T#NIcomment_to_html_conversion_20#t0.0#t0.1#</USR><Declaration>template &lt;typename PPP, typename QQQ, int RRR&gt;\nvoid comment_to_html_conversion_20(PPP aaa, QQQ bbb)</Declaration><TemplateParameters><Parameter><Name>PPP</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter><Parameter><Name>RRR</Name><Index>2</Index><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>UUU</Name><Discussion><Para> Zzz </Para></Discussion></Parameter></TemplateParameters></Function>]
+
+//===----------------------------------------------------------------------===//
+
/// \tparam AAA Aaa
/// \tparam BBB Bbb
/// \tparam CCC Ccc
@@ -41,39 +59,28 @@ void comment_to_html_conversion_20(PPP aaa, QQQ bbb);
template<template<template<typename CCC> class DDD, class BBB> class AAA>
void comment_to_html_conversion_21();
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_21</Name><USR>c:@FT@&gt;1#t&gt;2#t&gt;1#T#Tcomment_to_html_conversion_21#</USR><Declaration>template &lt;template &lt;template &lt;typename CCC&gt; class DDD, class BBB&gt; class AAA&gt;\nvoid comment_to_html_conversion_21()</Declaration><TemplateParameters><Parameter><Name>AAA</Name><Index>0</Index><Discussion><Para> Aaa </Para></Discussion></Parameter><Parameter><Name>BBB</Name><Discussion><Para> Bbb </Para></Discussion></Parameter><Parameter><Name>CCC</Name><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>DDD</Name><Discussion><Para> Ddd</Para></Discussion></Parameter></TemplateParameters></Function>]
+
template<template<template<typename RRR> class SSS, class QQQ> class PPP>
void comment_to_html_conversion_21();
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_21</Name><USR>c:@FT@&gt;1#t&gt;2#t&gt;1#T#Tcomment_to_html_conversion_21#</USR><Declaration>template &lt;template &lt;template &lt;typename RRR&gt; class SSS, class QQQ&gt; class PPP&gt;\nvoid comment_to_html_conversion_21()</Declaration><TemplateParameters><Parameter><Name>PPP</Name><Index>0</Index><Discussion><Para> Aaa </Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Discussion><Para> Bbb </Para></Discussion></Parameter><Parameter><Name>RRR</Name><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>SSS</Name><Discussion><Para> Ddd</Para></Discussion></Parameter></TemplateParameters></Function>]
+
+//===----------------------------------------------------------------------===//
+
/// \tparam C1 Ccc 1
/// \tparam AAA Zzz
/// \tparam C2 Ccc 2
/// \tparam C3 Ccc 3
/// \tparam C4 Ccc 4
/// \tparam BBB Bbb
-template<class C1, template<class C2, template<class C3, class C4> class BBB> class AAA>
+template <class C1, template <class C2, template <class C3, class C4> class BBB > class AAA>
void comment_to_html_conversion_22();
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_22</Name><USR>c:@FT@&gt;2#T#t&gt;2#T#t&gt;2#T#Tcomment_to_html_conversion_22#</USR><Declaration>template &lt;class C1, template &lt;class C2, template &lt;class C3, class C4&gt; class BBB&gt;\n class AAA&gt;\nvoid comment_to_html_conversion_22()</Declaration><TemplateParameters><Parameter><Name>C1</Name><Index>0</Index><Discussion><Para> Ccc 1 </Para></Discussion></Parameter><Parameter><Name>AAA</Name><Index>1</Index><Discussion><Para> Zzz </Para></Discussion></Parameter><Parameter><Name>C2</Name><Discussion><Para> Ccc 2 </Para></Discussion></Parameter><Parameter><Name>C3</Name><Discussion><Para> Ccc 3 </Para></Discussion></Parameter><Parameter><Name>C4</Name><Discussion><Para> Ccc 4 </Para></Discussion></Parameter><Parameter><Name>BBB</Name><Discussion><Para> Bbb</Para></Discussion></Parameter></TemplateParameters></Function>]
template<class CCC1, template<class CCC2, template<class CCC3, class CCC4> class QQQ> class PPP>
void comment_to_html_conversion_22();
-// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="14" column="6"><Name>comment_to_html_conversion_17</Name><USR>c:@FT@&gt;1#Tcomment_to_html_conversion_17#t0.0#</USR><Declaration>template &lt;typename T&gt; void comment_to_html_conversion_17(T AAA)</Declaration><Parameters><Parameter><Name>AAA</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah</Para></Discussion></Parameter></Parameters></Function>]
-
-// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="17" column="6"><Name>comment_to_html_conversion_17</Name><USR>c:@FT@&gt;1#Tcomment_to_html_conversion_17#t0.0#</USR><Declaration>template &lt;typename T&gt; void comment_to_html_conversion_17(T PPP)</Declaration><Parameters><Parameter><Name>PPP</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> Blah blah</Para></Discussion></Parameter></Parameters></Function>]
-
-// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="22" column="6"><Name>comment_to_html_conversion_19</Name><USR>c:@FT@&gt;2#T#Tcomment_to_html_conversion_19#t0.0#t0.1#</USR><Declaration>template &lt;typename AAA, typename BBB&gt; void comment_to_html_conversion_19(AAA aaa, BBB bbb)</Declaration><TemplateParameters><Parameter><Name>AAA</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>BBB</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter></TemplateParameters></Function>]
-
-// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="25" column="6"><Name>comment_to_html_conversion_19</Name><USR>c:@FT@&gt;2#T#Tcomment_to_html_conversion_19#t0.0#t0.1#</USR><Declaration>template &lt;typename PPP, typename QQQ&gt; void comment_to_html_conversion_19(PPP aaa, QQQ bbb)</Declaration><TemplateParameters><Parameter><Name>PPP</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter></TemplateParameters></Function>]
-
-// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="32" column="6"><Name>comment_to_html_conversion_20</Name><USR>c:@FT@&gt;3#T#T#NIcomment_to_html_conversion_20#t0.0#t0.1#</USR><Declaration>template &lt;typename AAA, typename BBB, int CCC&gt; void comment_to_html_conversion_20(AAA aaa, BBB bbb)</Declaration><TemplateParameters><Parameter><Name>AAA</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>BBB</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter><Parameter><Name>CCC</Name><Index>2</Index><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>UUU</Name><Discussion><Para> Zzz </Para></Discussion></Parameter></TemplateParameters></Function>]
-
-// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="35" column="6"><Name>comment_to_html_conversion_20</Name><USR>c:@FT@&gt;3#T#T#NIcomment_to_html_conversion_20#t0.0#t0.1#</USR><Declaration>template &lt;typename PPP, typename QQQ, int RRR&gt; void comment_to_html_conversion_20(PPP aaa, QQQ bbb)</Declaration><TemplateParameters><Parameter><Name>PPP</Name><Index>0</Index><Discussion><Para> Aaa</Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Index>1</Index><Discussion><Para> Bbb </Para></Discussion></Parameter><Parameter><Name>RRR</Name><Index>2</Index><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>UUU</Name><Discussion><Para> Zzz </Para></Discussion></Parameter></TemplateParameters></Function>]
-
-// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="42" column="6"><Name>comment_to_html_conversion_21</Name><USR>c:@FT@&gt;1#t&gt;2#t&gt;1#T#Tcomment_to_html_conversion_21#</USR><Declaration>template &lt;template &lt;template &lt;typename CCC&gt; class DDD, class BBB&gt; class AAA&gt; void comment_to_html_conversion_21()</Declaration><TemplateParameters><Parameter><Name>AAA</Name><Index>0</Index><Discussion><Para> Aaa </Para></Discussion></Parameter><Parameter><Name>BBB</Name><Discussion><Para> Bbb </Para></Discussion></Parameter><Parameter><Name>CCC</Name><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>DDD</Name><Discussion><Para> Ddd</Para></Discussion></Parameter></TemplateParameters></Function>]
-
-// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="45" column="6"><Name>comment_to_html_conversion_21</Name><USR>c:@FT@&gt;1#t&gt;2#t&gt;1#T#Tcomment_to_html_conversion_21#</USR><Declaration>template &lt;template &lt;template &lt;typename RRR&gt; class SSS, class QQQ&gt; class PPP&gt; void comment_to_html_conversion_21()</Declaration><TemplateParameters><Parameter><Name>PPP</Name><Index>0</Index><Discussion><Para> Aaa </Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Discussion><Para> Bbb </Para></Discussion></Parameter><Parameter><Name>RRR</Name><Discussion><Para> Ccc </Para></Discussion></Parameter><Parameter><Name>SSS</Name><Discussion><Para> Ddd</Para></Discussion></Parameter></TemplateParameters></Function>]
-
-// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="54" column="6"><Name>comment_to_html_conversion_22</Name><USR>c:@FT@&gt;2#T#t&gt;2#T#t&gt;2#T#Tcomment_to_html_conversion_22#</USR><Declaration>template &lt;class C1, template &lt;class C2, template &lt;class C3, class C4&gt; class BBB&gt; class AAA&gt; void comment_to_html_conversion_22()</Declaration><TemplateParameters><Parameter><Name>C1</Name><Index>0</Index><Discussion><Para> Ccc 1 </Para></Discussion></Parameter><Parameter><Name>AAA</Name><Index>1</Index><Discussion><Para> Zzz </Para></Discussion></Parameter><Parameter><Name>C2</Name><Discussion><Para> Ccc 2 </Para></Discussion></Parameter><Parameter><Name>C3</Name><Discussion><Para> Ccc 3 </Para></Discussion></Parameter><Parameter><Name>C4</Name><Discussion><Para> Ccc 4 </Para></Discussion></Parameter><Parameter><Name>BBB</Name><Discussion><Para> Bbb</Para></Discussion></Parameter></TemplateParameters></Function>]
-
-// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="58" column="6"><Name>comment_to_html_conversion_22</Name><USR>c:@FT@&gt;2#T#t&gt;2#T#t&gt;2#T#Tcomment_to_html_conversion_22#</USR><Declaration>template &lt;class CCC1, template &lt;class CCC2, template &lt;class CCC3, class CCC4&gt; class QQQ&gt; class PPP&gt; void comment_to_html_conversion_22()</Declaration><TemplateParameters><Parameter><Name>CCC1</Name><Index>0</Index><Discussion><Para> Ccc 1 </Para></Discussion></Parameter><Parameter><Name>PPP</Name><Index>1</Index><Discussion><Para> Zzz </Para></Discussion></Parameter><Parameter><Name>CCC2</Name><Discussion><Para> Ccc 2 </Para></Discussion></Parameter><Parameter><Name>CCC3</Name><Discussion><Para> Ccc 3 </Para></Discussion></Parameter><Parameter><Name>CCC4</Name><Discussion><Para> Ccc 4 </Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Discussion><Para> Bbb</Para></Discussion></Parameter></TemplateParameters></Function>]
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-ftemplate-comments.cpp" line="[[@LINE-2]]" column="6"><Name>comment_to_html_conversion_22</Name><USR>c:@FT@&gt;2#T#t&gt;2#T#t&gt;2#T#Tcomment_to_html_conversion_22#</USR><Declaration>template &lt;class CCC1, template &lt;class CCC2, template &lt;class CCC3, class CCC4&gt;\n class QQQ&gt; class PPP&gt;\nvoid comment_to_html_conversion_22()</Declaration><TemplateParameters><Parameter><Name>CCC1</Name><Index>0</Index><Discussion><Para> Ccc 1 </Para></Discussion></Parameter><Parameter><Name>PPP</Name><Index>1</Index><Discussion><Para> Zzz </Para></Discussion></Parameter><Parameter><Name>CCC2</Name><Discussion><Para> Ccc 2 </Para></Discussion></Parameter><Parameter><Name>CCC3</Name><Discussion><Para> Ccc 3 </Para></Discussion></Parameter><Parameter><Name>CCC4</Name><Discussion><Para> Ccc 4 </Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Discussion><Para> Bbb</Para></Discussion></Parameter></TemplateParameters></Function>]
diff --git a/test/Index/overriding-method-comments.mm b/test/Index/overriding-method-comments.mm
index e718138..46ead4f 100644
--- a/test/Index/overriding-method-comments.mm
+++ b/test/Index/overriding-method-comments.mm
@@ -19,6 +19,8 @@
- (void)METH:(id)AAA;
@end
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-3]]" column="1"><Name>METH:</Name><USR>c:objc(cs)Root(im)METH:</USR><Declaration>- (void)METH:(id)AAA;</Declaration><Parameters><Parameter><Name>AAA</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> ZZZ </Para></Discussion></Parameter></Parameters></Function>]
+
@interface Sub : Root
@end
@@ -26,99 +28,98 @@
- (void)METH:(id)BBB;
@end
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-3]]" column="1"><Name>METH:</Name><USR>c:objc(cs)Root(im)METH:</USR><Declaration>- (void)METH:(id)BBB;</Declaration><Parameters><Parameter><Name>BBB</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> ZZZ </Para></Discussion></Parameter></Parameters></Function>]
+
@implementation Sub(CAT)
- (void)METH:(id)III {}
@end
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-3]]" column="1"><Name>METH:</Name><USR>c:objc(cs)Root(im)METH:</USR><Declaration>- (void)METH:(id)III;</Declaration><Parameters><Parameter><Name>III</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> ZZZ </Para></Discussion></Parameter></Parameters></Function>]
+
@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
+ * \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
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-3]]" column="1"><Name>EXT_METH:::</Name><USR>c:objc(cs)Redec(im)EXT_METH:::</USR><Declaration>- (void)EXT_METH:(id)AAA:(double)BBB:(int)CCC;</Declaration><Parameters><Parameter><Name>AAA</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> input value </Para></Discussion></Parameter><Parameter><Name>BBB</Name><Index>1</Index><Direction isExplicit="1">in</Direction><Discussion><Para> 2nd input value is double </Para></Discussion></Parameter><Parameter><Name>CCC</Name><Index>2</Index><Direction isExplicit="1">out</Direction><Discussion><Para> output value is int </Para></Discussion></Parameter></Parameters></Function>]
+
@implementation Redec
- (void)EXT_METH:(id)PPP : (double)QQQ : (int)RRR {}
@end
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-3]]" column="1"><Name>EXT_METH:::</Name><USR>c:objc(cs)Redec(im)EXT_METH:::</USR><Declaration>- (void)EXT_METH:(id)PPP:(double)QQQ:(int)RRR;</Declaration><Parameters><Parameter><Name>PPP</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> input value </Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Index>1</Index><Direction isExplicit="1">in</Direction><Discussion><Para> 2nd input value is double </Para></Discussion></Parameter><Parameter><Name>RRR</Name><Index>2</Index><Direction isExplicit="1">out</Direction><Discussion><Para> output value is int </Para></Discussion></Parameter></Parameters></Function>]
+
struct Base {
/// \brief Does something.
/// \param AAA argument to foo_pure.
virtual void foo_pure(int AAA) = 0;
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-2]]" column="16"><Name>foo_pure</Name><USR>c:@S@Base@F@foo_pure#I#</USR><Declaration>virtual void foo_pure(int AAA) = 0</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>AAA</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to foo_pure.</Para></Discussion></Parameter></Parameters></Function>]
+
/// \brief Does something.
/// \param BBB argument to defined virtual.
virtual void foo_inline(int BBB) {}
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-2]]" column="16"><Name>foo_inline</Name><USR>c:@S@Base@F@foo_inline#I#</USR><Declaration>virtual void foo_inline(int BBB)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>BBB</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to defined virtual.</Para></Discussion></Parameter></Parameters></Function>]
+
/// \brief Does something.
/// \param CCC argument to undefined virtual.
virtual void foo_outofline(int CCC);
+
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-2]]" column="16"><Name>foo_outofline</Name><USR>c:@S@Base@F@foo_outofline#I#</USR><Declaration>virtual void foo_outofline(int CCC)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>CCC</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to undefined virtual.</Para></Discussion></Parameter></Parameters></Function>]
};
void Base::foo_outofline(int RRR) {}
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-2]]" column="12"><Name>foo_outofline</Name><USR>c:@S@Base@F@foo_outofline#I#</USR><Declaration>void foo_outofline(int RRR)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>RRR</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to undefined virtual.</Para></Discussion></Parameter></Parameters></Function>]
+
struct Derived : public Base {
virtual void foo_pure(int PPP);
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-2]]" column="16"><Name>foo_pure</Name><USR>c:@S@Base@F@foo_pure#I#</USR><Declaration>virtual void foo_pure(int PPP)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>PPP</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to foo_pure.</Para></Discussion></Parameter></Parameters></Function>]
+
virtual void foo_inline(int QQQ) {}
+
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-2]]" column="16"><Name>foo_inline</Name><USR>c:@S@Base@F@foo_inline#I#</USR><Declaration>virtual void foo_inline(int QQQ)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>QQQ</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to defined virtual.</Para></Discussion></Parameter></Parameters></Function>]
};
/// \brief Does something.
/// \param DDD a value.
void foo(int DDD);
+// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-2]]" column="6"><Name>foo</Name><USR>c:@F@foo#I#</USR><Declaration>void foo(int DDD)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>DDD</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> a value.</Para></Discussion></Parameter></Parameters></Function>]
+
void foo(int SSS) {}
+// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-2]]" column="6"><Name>foo</Name><USR>c:@F@foo#I#</USR><Declaration>void foo(int SSS)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>SSS</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> a value.</Para></Discussion></Parameter></Parameters></Function>]
+
/// \brief Does something.
-/// \param EEE argument to function decl.
+/// \param EEE argument to function decl.
void foo1(int EEE);
+// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-2]]" column="6"><Name>foo1</Name><USR>c:@F@foo1#I#</USR><Declaration>void foo1(int EEE)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>EEE</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to function decl.</Para></Discussion></Parameter></Parameters></Function>]
+
void foo1(int TTT);
+// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-2]]" column="6"><Name>foo1</Name><USR>c:@F@foo1#I#</USR><Declaration>void foo1(int TTT)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>TTT</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to function decl.</Para></Discussion></Parameter></Parameters></Function>]
+
/// \brief Documentation
/// \tparam BBB The type, silly.
/// \tparam AAA The type, silly as well.
template<typename AAA, typename BBB>
void foo(AAA, BBB);
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-2]]" column="6"><Name>foo</Name><USR>c:@FT@&gt;2#T#Tfoo#t0.0#t0.1#</USR><Declaration>template &lt;typename AAA, typename BBB&gt; void foo(AAA, BBB)</Declaration><Abstract><Para> Documentation </Para></Abstract><TemplateParameters><Parameter><Name>AAA</Name><Index>0</Index><Discussion><Para> The type, silly as well.</Para></Discussion></Parameter><Parameter><Name>BBB</Name><Index>1</Index><Discussion><Para> The type, silly. </Para></Discussion></Parameter></TemplateParameters></Function>]
+
template<typename PPP, typename QQQ>
void foo(PPP, QQQ);
-// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="19" column="1"><Name>METH:</Name><USR>c:objc(cs)Root(im)METH:</USR><Declaration>- (void) METH:(id)AAA</Declaration><Parameters><Parameter><Name>AAA</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> ZZZ </Para></Discussion></Parameter></Parameters></Function>]
-
-// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="26" column="1"><Name>METH:</Name><USR>c:objc(cs)Root(im)METH:</USR><Declaration>- (void) METH:(id)BBB</Declaration><Parameters><Parameter><Name>BBB</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> ZZZ </Para></Discussion></Parameter></Parameters></Function>]
-
-// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="30" column="1"><Name>METH:</Name><USR>c:objc(cs)Root(im)METH:</USR><Declaration>- (void) METH:(id)III</Declaration><Parameters><Parameter><Name>III</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> ZZZ </Para></Discussion></Parameter></Parameters></Function>]
-
-// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="42" column="1"><Name>EXT_METH:::</Name><USR>c:objc(cs)Redec(im)EXT_METH:::</USR><Declaration>- (void) EXT_METH:(id)AAA :(double)BBB :(int)CCC</Declaration><Parameters><Parameter><Name>AAA</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> input value </Para></Discussion></Parameter><Parameter><Name>BBB</Name><Index>1</Index><Direction isExplicit="1">in</Direction><Discussion><Para> 2nd input value is double </Para></Discussion></Parameter><Parameter><Name>CCC</Name><Index>2</Index><Direction isExplicit="1">out</Direction><Discussion><Para> output value is int </Para></Discussion></Parameter></Parameters></Function>]
-
-// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="46" column="1"><Name>EXT_METH:::</Name><USR>c:objc(cs)Redec(im)EXT_METH:::</USR><Declaration>- (void) EXT_METH:(id)PPP :(double)QQQ :(int)RRR</Declaration><Parameters><Parameter><Name>PPP</Name><Index>0</Index><Direction isExplicit="1">in</Direction><Discussion><Para> input value </Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Index>1</Index><Direction isExplicit="1">in</Direction><Discussion><Para> 2nd input value is double </Para></Discussion></Parameter><Parameter><Name>RRR</Name><Index>2</Index><Direction isExplicit="1">out</Direction><Discussion><Para> output value is int </Para></Discussion></Parameter></Parameters></Function>]
-
-// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="52" column="16"><Name>foo_pure</Name><USR>c:@S@Base@F@foo_pure#I#</USR><Declaration>virtual void foo_pure(int AAA) = 0</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>AAA</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to foo_pure.</Para></Discussion></Parameter></Parameters></Function>]
-
-// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="56" column="16"><Name>foo_inline</Name><USR>c:@S@Base@F@foo_inline#I#</USR><Declaration>virtual void foo_inline(int BBB)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>BBB</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to defined virtual.</Para></Discussion></Parameter></Parameters></Function>]
-
-// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="60" column="16"><Name>foo_outofline</Name><USR>c:@S@Base@F@foo_outofline#I#</USR><Declaration>virtual void foo_outofline(int CCC)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>CCC</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to undefined virtual.</Para></Discussion></Parameter></Parameters></Function>]
-
-// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="63" column="12"><Name>foo_outofline</Name><USR>c:@S@Base@F@foo_outofline#I#</USR><Declaration>void foo_outofline(int RRR)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>RRR</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to undefined virtual.</Para></Discussion></Parameter></Parameters></Function>]
-
-// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="66" column="16"><Name>foo_pure</Name><USR>c:@S@Base@F@foo_pure#I#</USR><Declaration>virtual void foo_pure(int PPP)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>PPP</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to foo_pure.</Para></Discussion></Parameter></Parameters></Function>]
-
-// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="68" column="16"><Name>foo_inline</Name><USR>c:@S@Base@F@foo_inline#I#</USR><Declaration>virtual void foo_inline(int QQQ)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>QQQ</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to defined virtual.</Para></Discussion></Parameter></Parameters></Function>]
-
-// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}overriding-method-comments.mm" line="73" column="6"><Name>foo</Name><USR>c:@F@foo#I#</USR><Declaration>void foo(int DDD)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>DDD</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> a value.</Para></Discussion></Parameter></Parameters></Function>]
-
-// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}overriding-method-comments.mm" line="75" column="6"><Name>foo</Name><USR>c:@F@foo#I#</USR><Declaration>void foo(int SSS)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>SSS</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> a value.</Para></Discussion></Parameter></Parameters></Function>]
-
-// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}overriding-method-comments.mm" line="79" column="6"><Name>foo1</Name><USR>c:@F@foo1#I#</USR><Declaration>void foo1(int EEE)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>EEE</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to function decl. </Para></Discussion></Parameter></Parameters></Function>]
-
-// CHECK: FullCommentAsXML=[<Function file="{{[^"]+}}overriding-method-comments.mm" line="81" column="6"><Name>foo1</Name><USR>c:@F@foo1#I#</USR><Declaration>void foo1(int TTT)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>TTT</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to function decl. </Para></Discussion></Parameter></Parameters></Function>]
-
-// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-method-comments.mm" line="87" column="6"><Name>foo</Name><USR>c:@FT@&gt;2#T#Tfoo#t0.0#t0.1#</USR><Declaration>template &lt;typename AAA, typename BBB&gt; void foo(AAA, BBB)</Declaration><Abstract><Para> Documentation </Para></Abstract><TemplateParameters><Parameter><Name>AAA</Name><Index>0</Index><Discussion><Para> The type, silly as well.</Para></Discussion></Parameter><Parameter><Name>BBB</Name><Index>1</Index><Discussion><Para> The type, silly. </Para></Discussion></Parameter></TemplateParameters></Function>]
+// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-2]]" column="6"><Name>foo</Name><USR>c:@FT@&gt;2#T#Tfoo#t0.0#t0.1#</USR><Declaration>template &lt;typename PPP, typename QQQ&gt; void foo(PPP, QQQ)</Declaration><Abstract><Para> Documentation </Para></Abstract><TemplateParameters><Parameter><Name>PPP</Name><Index>0</Index><Discussion><Para> The type, silly as well.</Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Index>1</Index><Discussion><Para> The type, silly. </Para></Discussion></Parameter></TemplateParameters></Function>]
-// CHECK: FullCommentAsXML=[<Function templateKind="template" file="{{[^"]+}}overriding-method-comments.mm" line="90" column="6"><Name>foo</Name><USR>c:@FT@&gt;2#T#Tfoo#t0.0#t0.1#</USR><Declaration>template &lt;typename PPP, typename QQQ&gt; void foo(PPP, QQQ)</Declaration><Abstract><Para> Documentation </Para></Abstract><TemplateParameters><Parameter><Name>PPP</Name><Index>0</Index><Discussion><Para> The type, silly as well.</Para></Discussion></Parameter><Parameter><Name>QQQ</Name><Index>1</Index><Discussion><Para> The type, silly. </Para></Discussion></Parameter></TemplateParameters></Function>]
diff --git a/test/Index/preamble_macro_template.cpp b/test/Index/preamble_macro_template.cpp
index ee1b413..20f16b5 100644
--- a/test/Index/preamble_macro_template.cpp
+++ b/test/Index/preamble_macro_template.cpp
@@ -3,12 +3,12 @@ template void foo(int *);
int main() { }
// RUN: c-index-test -write-pch %t.pch -fno-delayed-template-parsing -x c++-header %S/Inputs/preamble_macro_template.h
-// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 5 local -fno-delayed-template-parsing -I %S/Inputs -include %t %s | FileCheck %s
+// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 5 local -fno-delayed-template-parsing -I %S/Inputs -include %t %s 2>&1 | tee %t.check.txt | FileCheck %s
// CHECK: preamble_macro_template.h:4:6: FunctionDecl=foo:4:6 (Definition) [Specialization of foo:4:6] Extent=[4:1 - 6:2]
// CHECK: preamble_macro_template.h:4:13: ParmDecl=p:4:13 (Definition) Extent=[4:10 - 4:14]
// CHECK: preamble_macro_template.h:4:16: CompoundStmt= Extent=[4:16 - 6:2]
// CHECK: preamble_macro_template.h:5:3: CStyleCastExpr= Extent=[5:3 - 5:27]
-// CHECK: preamble_macro_template.h:1:21: CXXStaticCastExpr= Extent=[1:21 - 5:27]
+// CHECK: preamble_macro_template.h:5:9: CXXStaticCastExpr= Extent=[5:9 - 5:27]
// CHECK: preamble_macro_template.h:5:25: UnexposedExpr= Extent=[5:25 - 5:26]
// CHECK: preamble_macro_template.h:5:25: IntegerLiteral= Extent=[5:25 - 5:26]
// CHECK: preamble_macro_template.cpp:3:5: FunctionDecl=main:3:5 (Definition) Extent=[3:1 - 3:15]
diff --git a/test/Index/print-bitwidth.c b/test/Index/print-bitwidth.c
new file mode 100644
index 0000000..e9e330a
--- /dev/null
+++ b/test/Index/print-bitwidth.c
@@ -0,0 +1,25 @@
+union S {
+ unsigned ac : 4;
+ unsigned : 4;
+ unsigned clock : 1;
+ unsigned : 0;
+ unsigned flag : 1;
+};
+
+struct X {
+ unsigned light : 1;
+ unsigned toaster : 1;
+ int count;
+ union S stat;
+};
+
+// RUN: c-index-test -test-print-bitwidth %s | FileCheck %s
+// CHECK: FieldDecl=ac:2:12 (Definition) bitwidth=4
+// CHECK: FieldDecl=:3:3 (Definition) bitwidth=4
+// CHECK: FieldDecl=clock:4:12 (Definition) bitwidth=1
+// CHECK: FieldDecl=:5:3 (Definition) bitwidth=0
+// CHECK: FieldDecl=flag:6:12 (Definition) bitwidth=1
+// CHECK: FieldDecl=light:10:12 (Definition) bitwidth=1
+// CHECK: FieldDecl=toaster:11:12 (Definition) bitwidth=1
+// CHECK-NOT: count
+// CHECK-NOT: stat
diff --git a/test/Index/print-type.c b/test/Index/print-type.c
new file mode 100644
index 0000000..8594994
--- /dev/null
+++ b/test/Index/print-type.c
@@ -0,0 +1,44 @@
+typedef int FooType;
+int *p;
+int *f(int *p, char *x, FooType z, int arr[5], void (*fn)(int)) {
+ fn(*p);
+ const FooType w = z;
+ return p + z + arr[3];
+}
+typedef double OtherType;
+typedef int ArrayType[5];
+int __attribute__((vector_size(16))) x;
+typedef int __attribute__((vector_size(16))) int4_t;
+
+// RUN: c-index-test -test-print-type %s | FileCheck %s
+// CHECK: FunctionDecl=f:3:6 (Definition) [type=int *(int *, char *, FooType, int *, void (*)(int))] [typekind=FunctionProto] [canonicaltype=int *(int *, char *, int, int *, void (*)(int))] [canonicaltypekind=FunctionProto] [resulttype=int *] [resulttypekind=Pointer] [args= [int *] [Pointer] [char *] [Pointer] [FooType] [Typedef] [int *] [Pointer] [void (*)(int)] [Pointer]] [isPOD=0]
+// CHECK: ParmDecl=p:3:13 (Definition) [type=int *] [typekind=Pointer] [isPOD=1]
+// CHECK: ParmDecl=x:3:22 (Definition) [type=char *] [typekind=Pointer] [isPOD=1]
+// CHECK: ParmDecl=z:3:33 (Definition) [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
+// CHECK: TypeRef=FooType:1:13 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
+// CHECK: ParmDecl=arr:3:40 (Definition) [type=int *] [typekind=Pointer] [isPOD=1]
+// CHECK: IntegerLiteral= [type=int] [typekind=Int] [isPOD=1]
+// CHECK: ParmDecl=fn:3:55 (Definition) [type=void (*)(int)] [typekind=Pointer] [canonicaltype=void (*)(int)] [canonicaltypekind=Pointer] [isPOD=1]
+// CHECK: ParmDecl=:3:62 (Definition) [type=int] [typekind=Int] [isPOD=1]
+// CHECK: CompoundStmt= [type=] [typekind=Invalid] [isPOD=0]
+// CHECK: CallExpr=fn:3:55 [type=void] [typekind=Void] [args= [int] [Int]] [isPOD=0]
+// CHECK: DeclRefExpr=fn:3:55 [type=void (*)(int)] [typekind=Pointer] [canonicaltype=void (*)(int)] [canonicaltypekind=Pointer] [isPOD=1]
+// CHECK: UnaryOperator= [type=int] [typekind=Int] [isPOD=1]
+// CHECK: DeclRefExpr=p:3:13 [type=int *] [typekind=Pointer] [isPOD=1]
+// CHECK: DeclStmt= [type=] [typekind=Invalid] [isPOD=0]
+// CHECK: VarDecl=w:5:17 (Definition) [type=const FooType] [typekind=Typedef] const [canonicaltype=const int] [canonicaltypekind=Int] [isPOD=1]
+// CHECK: TypeRef=FooType:1:13 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
+// CHECK: DeclRefExpr=z:3:33 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
+// CHECK: ReturnStmt= [type=] [typekind=Invalid] [isPOD=0]
+// CHECK: BinaryOperator= [type=int *] [typekind=Pointer] [isPOD=1]
+// CHECK: BinaryOperator= [type=int *] [typekind=Pointer] [isPOD=1]
+// CHECK: DeclRefExpr=p:3:13 [type=int *] [typekind=Pointer] [isPOD=1]
+// CHECK: DeclRefExpr=z:3:33 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
+// CHECK: ArraySubscriptExpr= [type=int] [typekind=Int] [isPOD=1]
+// CHECK: DeclRefExpr=arr:3:40 [type=int *] [typekind=Pointer] [isPOD=1]
+// CHECK: IntegerLiteral= [type=int] [typekind=Int] [isPOD=1]
+// CHECK: TypedefDecl=OtherType:8:16 (Definition) [type=OtherType] [typekind=Typedef] [canonicaltype=double] [canonicaltypekind=Double] [isPOD=1]
+// CHECK: TypedefDecl=ArrayType:9:13 (Definition) [type=ArrayType] [typekind=Typedef] [canonicaltype=int [5]] [canonicaltypekind=ConstantArray] [isPOD=1]
+// CHECK: IntegerLiteral= [type=int] [typekind=Int] [isPOD=1]
+// CHECK: VarDecl=x:10:38 [type=__attribute__((__vector_size__(4 * sizeof(int)))) int] [typekind=Vector] [isPOD=1]
+// CHECK: TypedefDecl=int4_t:11:46 (Definition) [type=int4_t] [typekind=Typedef] [canonicaltype=__attribute__((__vector_size__(4 * sizeof(int)))) int] [canonicaltypekind=Vector] [isPOD=1]
diff --git a/test/Index/print-type.cpp b/test/Index/print-type.cpp
new file mode 100644
index 0000000..b99d1cb
--- /dev/null
+++ b/test/Index/print-type.cpp
@@ -0,0 +1,61 @@
+namespace outer {
+
+template<typename T>
+struct Foo {
+ T t;
+};
+
+namespace inner {
+
+struct Bar {
+ Bar(outer::Foo<bool>* foo) { };
+
+ typedef int FooType;
+ int *p;
+ int *f(int *p, char *x, FooType z) {
+ const FooType w = z;
+ return p + z;
+ }
+ typedef double OtherType;
+ typedef int ArrayType[5];
+};
+
+}
+}
+
+template <typename T>
+T tbar(int);
+
+// RUN: c-index-test -test-print-type %s | FileCheck %s
+// CHECK: Namespace=outer:1:11 (Definition) [type=] [typekind=Invalid] [isPOD=0]
+// CHECK: ClassTemplate=Foo:4:8 (Definition) [type=] [typekind=Invalid] [isPOD=0]
+// CHECK: TemplateTypeParameter=T:3:19 (Definition) [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0]
+// CHECK: FieldDecl=t:5:5 (Definition) [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0]
+// CHECK: TypeRef=T:3:19 [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0]
+// CHECK: Namespace=inner:8:11 (Definition) [type=] [typekind=Invalid] [isPOD=0]
+// CHECK: StructDecl=Bar:10:8 (Definition) [type=outer::inner::Bar] [typekind=Record] [isPOD=0]
+// CHECK: CXXConstructor=Bar:11:3 (Definition) [type=void (outer::Foo<bool> *)] [typekind=FunctionProto] [canonicaltype=void (outer::Foo<bool> *)] [canonicaltypekind=FunctionProto] [resulttype=void] [resulttypekind=Void] [args= [outer::Foo<bool> *] [Pointer]] [isPOD=0]
+// CHECK: ParmDecl=foo:11:25 (Definition) [type=outer::Foo<bool> *] [typekind=Pointer] [canonicaltype=outer::Foo<bool> *] [canonicaltypekind=Pointer] [isPOD=1]
+// CHECK: NamespaceRef=outer:1:11 [type=] [typekind=Invalid] [isPOD=0]
+// CHECK: TemplateRef=Foo:4:8 [type=] [typekind=Invalid] [isPOD=0]
+// CHECK: CompoundStmt= [type=] [typekind=Invalid] [isPOD=0]
+// CHECK: TypedefDecl=FooType:13:15 (Definition) [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
+// CHECK: FieldDecl=p:14:8 (Definition) [type=int *] [typekind=Pointer] [isPOD=1]
+// CHECK: CXXMethod=f:15:8 (Definition) [type=int *(int *, char *, FooType)] [typekind=FunctionProto] [canonicaltype=int *(int *, char *, int)] [canonicaltypekind=FunctionProto] [resulttype=int *] [resulttypekind=Pointer] [args= [int *] [Pointer] [char *] [Pointer] [FooType] [Typedef]] [isPOD=0]
+// CHECK: ParmDecl=p:15:15 (Definition) [type=int *] [typekind=Pointer] [isPOD=1]
+// CHECK: ParmDecl=x:15:24 (Definition) [type=char *] [typekind=Pointer] [isPOD=1]
+// CHECK: ParmDecl=z:15:35 (Definition) [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
+// CHECK: TypeRef=FooType:13:15 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
+// CHECK: CompoundStmt= [type=] [typekind=Invalid] [isPOD=0]
+// CHECK: DeclStmt= [type=] [typekind=Invalid] [isPOD=0]
+// CHECK: VarDecl=w:16:19 (Definition) [type=const FooType] [typekind=Typedef] const [canonicaltype=const int] [canonicaltypekind=Int] [isPOD=1]
+// CHECK: TypeRef=FooType:13:15 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
+// CHECK: DeclRefExpr=z:15:35 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
+// CHECK: ReturnStmt= [type=] [typekind=Invalid] [isPOD=0]
+// CHECK: BinaryOperator= [type=int *] [typekind=Pointer] [isPOD=1]
+// CHECK: DeclRefExpr=p:15:15 [type=int *] [typekind=Pointer] [isPOD=1]
+// CHECK: DeclRefExpr=z:15:35 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1]
+// CHECK: TypedefDecl=OtherType:19:18 (Definition) [type=OtherType] [typekind=Typedef] [canonicaltype=double] [canonicaltypekind=Double] [isPOD=1]
+// CHECK: TypedefDecl=ArrayType:20:15 (Definition) [type=ArrayType] [typekind=Typedef] [canonicaltype=int [5]] [canonicaltypekind=ConstantArray] [isPOD=1]
+// CHECK: FunctionTemplate=tbar:27:3 [type=T (int)] [typekind=FunctionProto] [canonicaltype=type-parameter-0-0 (int)] [canonicaltypekind=FunctionProto] [resulttype=T] [resulttypekind=Unexposed] [isPOD=0]
+// CHECK: TemplateTypeParameter=T:26:20 (Definition) [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0]
diff --git a/test/Index/print-type.m b/test/Index/print-type.m
new file mode 100644
index 0000000..9325c3f
--- /dev/null
+++ b/test/Index/print-type.m
@@ -0,0 +1,10 @@
+@interface Foo
+@property (readonly) id x;
+-(int) mymethod;
+-(const id) mymethod2:(id)x blah:(Class)y boo:(SEL)z;
+@end
+
+// RUN: c-index-test -test-print-type %s | FileCheck %s
+// CHECK: ObjCPropertyDecl=x:2:25 [type=id] [typekind=ObjCId] [canonicaltype=id] [canonicaltypekind=ObjCObjectPointer] [isPOD=1]
+// CHECK: ObjCInstanceMethodDecl=mymethod:3:8 [type=] [typekind=Invalid] [resulttype=int] [resulttypekind=Int] [isPOD=0]
+// CHECK: ObjCInstanceMethodDecl=mymethod2:blah:boo::4:13 [type=] [typekind=Invalid] [resulttype=const id] [resulttypekind=ObjCId] [args= [id] [ObjCId] [Class] [ObjCClass] [SEL] [ObjCSel]] [isPOD=0]
diff --git a/test/Index/print-typekind.c b/test/Index/print-typekind.c
deleted file mode 100644
index 294aea7..0000000
--- a/test/Index/print-typekind.c
+++ /dev/null
@@ -1,28 +0,0 @@
-typedef int FooType;
-int *p;
-int *f(int *p, char *x, FooType z) {
- const FooType w = z;
- return p + z;
-}
-typedef double OtherType;
-typedef int ArrayType[5];
-
-// RUN: c-index-test -test-print-typekind %s | FileCheck %s
-// CHECK: TypedefDecl=FooType:1:13 (Definition) typekind=Typedef [canonical=Int] [isPOD=1]
-// CHECK: VarDecl=p:2:6 typekind=Pointer [isPOD=1]
-// CHECK: FunctionDecl=f:3:6 (Definition) typekind=FunctionProto [canonical=FunctionProto] [result=Pointer] [args= Pointer Pointer Typedef] [isPOD=0]
-// CHECK: ParmDecl=p:3:13 (Definition) typekind=Pointer [isPOD=1]
-// CHECK: ParmDecl=x:3:22 (Definition) typekind=Pointer [isPOD=1]
-// CHECK: ParmDecl=z:3:33 (Definition) typekind=Typedef [canonical=Int] [isPOD=1]
-// CHECK: TypeRef=FooType:1:13 typekind=Typedef [canonical=Int] [isPOD=1]
-// CHECK: CompoundStmt= typekind=Invalid [isPOD=0]
-// CHECK: DeclStmt= typekind=Invalid [isPOD=0]
-// CHECK: VarDecl=w:4:17 (Definition) typekind=Typedef const [canonical=Int] [isPOD=1]
-// CHECK: TypeRef=FooType:1:13 typekind=Typedef [canonical=Int] [isPOD=1]
-// CHECK: DeclRefExpr=z:3:33 typekind=Typedef [canonical=Int] [isPOD=1]
-// CHECK: ReturnStmt= typekind=Invalid [isPOD=0]
-// CHECK: BinaryOperator= typekind=Pointer [isPOD=1]
-// CHECK: DeclRefExpr=p:3:13 typekind=Pointer [isPOD=1]
-// CHECK: DeclRefExpr=z:3:33 typekind=Typedef [canonical=Int] [isPOD=1]
-// CHECK: TypedefDecl=OtherType:7:16 (Definition) typekind=Typedef [canonical=Double] [isPOD=1]
-// CHECK: TypedefDecl=ArrayType:8:13 (Definition) typekind=Typedef [canonical=ConstantArray] [isPOD=1]
diff --git a/test/Index/print-typekind.m b/test/Index/print-typekind.m
deleted file mode 100644
index 565c5e3..0000000
--- a/test/Index/print-typekind.m
+++ /dev/null
@@ -1,10 +0,0 @@
-@interface Foo
-@property (readonly) id x;
--(int) mymethod;
--(const id) mymethod2:(id)x blah:(Class)y boo:(SEL)z;
-@end
-
-// RUN: c-index-test -test-print-typekind %s | FileCheck %s
-// CHECK: ObjCPropertyDecl=x:2:25 typekind=ObjCId [canonical=ObjCObjectPointer]
-// CHECK: ObjCInstanceMethodDecl=mymethod:3:8 typekind=Invalid [result=Int]
-// CHECK: ObjCInstanceMethodDecl=mymethod2:blah:boo::4:13 typekind=Invalid [result=ObjCId] [args= ObjCId ObjCClass ObjCSel]
diff --git a/test/Index/recursive-cxx-member-calls.cpp b/test/Index/recursive-cxx-member-calls.cpp
index 501dc29..2cd8d13 100644
--- a/test/Index/recursive-cxx-member-calls.cpp
+++ b/test/Index/recursive-cxx-member-calls.cpp
@@ -222,11 +222,11 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Keyword: "int" [7:3 - 7:6] FunctionDecl=memcmp:7:7
// CHECK-tokens: Identifier: "memcmp" [7:7 - 7:13] FunctionDecl=memcmp:7:7
// CHECK-tokens: Punctuation: "(" [7:13 - 7:14] FunctionDecl=memcmp:7:7
-// CHECK-tokens: Keyword: "const" [7:14 - 7:19] FunctionDecl=memcmp:7:7
+// CHECK-tokens: Keyword: "const" [7:14 - 7:19] ParmDecl=:7:26 (Definition)
// CHECK-tokens: Keyword: "void" [7:20 - 7:24] ParmDecl=:7:26 (Definition)
// CHECK-tokens: Punctuation: "*" [7:25 - 7:26] ParmDecl=:7:26 (Definition)
// CHECK-tokens: Punctuation: "," [7:26 - 7:27] ParmDecl=:7:26 (Definition)
-// CHECK-tokens: Keyword: "const" [7:28 - 7:33] FunctionDecl=memcmp:7:7
+// CHECK-tokens: Keyword: "const" [7:28 - 7:33] ParmDecl=:7:40 (Definition)
// CHECK-tokens: Keyword: "void" [7:34 - 7:38] ParmDecl=:7:40 (Definition)
// CHECK-tokens: Punctuation: "*" [7:39 - 7:40] ParmDecl=:7:40 (Definition)
// CHECK-tokens: Punctuation: "," [7:40 - 7:41] ParmDecl=:7:40 (Definition)
@@ -236,7 +236,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Identifier: "size_t" [8:3 - 8:9] TypeRef=size_t:2:25
// CHECK-tokens: Identifier: "strlen" [8:10 - 8:16] FunctionDecl=strlen:8:10
// CHECK-tokens: Punctuation: "(" [8:16 - 8:17] FunctionDecl=strlen:8:10
-// CHECK-tokens: Keyword: "const" [8:17 - 8:22] FunctionDecl=strlen:8:10
+// CHECK-tokens: Keyword: "const" [8:17 - 8:22] ParmDecl=:8:29 (Definition)
// CHECK-tokens: Keyword: "char" [8:23 - 8:27] ParmDecl=:8:29 (Definition)
// CHECK-tokens: Punctuation: "*" [8:28 - 8:29] ParmDecl=:8:29 (Definition)
// CHECK-tokens: Punctuation: ")" [8:29 - 8:30] ParmDecl=:8:29 (Definition)
@@ -397,11 +397,11 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Identifier: "IgnoredAttribute" [31:25 - 31:41] EnumConstantDecl=IgnoredAttribute:31:25 (Definition)
// CHECK-tokens: Punctuation: "}" [32:5 - 32:6] EnumDecl=Kind:13:10 (Definition)
// CHECK-tokens: Punctuation: ";" [32:6 - 32:7] ClassDecl=AttributeList:12:9 (Definition)
-// CHECK-tokens: Keyword: "static" [33:5 - 33:11] ClassDecl=AttributeList:12:9 (Definition)
+// CHECK-tokens: Keyword: "static" [33:5 - 33:11] CXXMethod=getKind:33:17 (static)
// CHECK-tokens: Identifier: "Kind" [33:12 - 33:16] TypeRef=enum clang::AttributeList::Kind:13:10
// CHECK-tokens: Identifier: "getKind" [33:17 - 33:24] CXXMethod=getKind:33:17 (static)
// CHECK-tokens: Punctuation: "(" [33:24 - 33:25] CXXMethod=getKind:33:17 (static)
-// CHECK-tokens: Keyword: "const" [33:25 - 33:30] CXXMethod=getKind:33:17 (static)
+// CHECK-tokens: Keyword: "const" [33:25 - 33:30] ParmDecl=Name:33:48 (Definition)
// CHECK-tokens: Identifier: "IdentifierInfo" [33:31 - 33:45] TypeRef=class clang::IdentifierInfo:66:7
// CHECK-tokens: Punctuation: "*" [33:46 - 33:47] ParmDecl=Name:33:48 (Definition)
// CHECK-tokens: Identifier: "Name" [33:48 - 33:52] ParmDecl=Name:33:48 (Definition)
@@ -413,7 +413,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Identifier: "size_t" [36:1 - 36:7] TypeRef=size_t:2:25
// CHECK-tokens: Identifier: "magic_length" [36:8 - 36:20] FunctionDecl=magic_length:36:8
// CHECK-tokens: Punctuation: "(" [36:20 - 36:21] FunctionDecl=magic_length:36:8
-// CHECK-tokens: Keyword: "const" [36:21 - 36:26] FunctionDecl=magic_length:36:8
+// CHECK-tokens: Keyword: "const" [36:21 - 36:26] ParmDecl=s:36:33 (Definition)
// CHECK-tokens: Keyword: "char" [36:27 - 36:31] ParmDecl=s:36:33 (Definition)
// CHECK-tokens: Punctuation: "*" [36:32 - 36:33] ParmDecl=s:36:33 (Definition)
// CHECK-tokens: Identifier: "s" [36:33 - 36:34] ParmDecl=s:36:33 (Definition)
@@ -427,14 +427,14 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: "{" [38:17 - 38:18] ClassDecl=StringRef:38:7 (Definition)
// CHECK-tokens: Keyword: "public" [39:1 - 39:7] CXXAccessSpecifier=:39:1 (Definition)
// CHECK-tokens: Punctuation: ":" [39:7 - 39:8] CXXAccessSpecifier=:39:1 (Definition)
-// CHECK-tokens: Keyword: "typedef" [40:3 - 40:10] ClassDecl=StringRef:38:7 (Definition)
-// CHECK-tokens: Keyword: "const" [40:11 - 40:16] ClassDecl=StringRef:38:7 (Definition)
+// CHECK-tokens: Keyword: "typedef" [40:3 - 40:10] TypedefDecl=iterator:40:23 (Definition)
+// CHECK-tokens: Keyword: "const" [40:11 - 40:16] TypedefDecl=iterator:40:23 (Definition)
// CHECK-tokens: Keyword: "char" [40:17 - 40:21] TypedefDecl=iterator:40:23 (Definition)
// CHECK-tokens: Punctuation: "*" [40:22 - 40:23] TypedefDecl=iterator:40:23 (Definition)
// CHECK-tokens: Identifier: "iterator" [40:23 - 40:31] TypedefDecl=iterator:40:23 (Definition)
// CHECK-tokens: Punctuation: ";" [40:31 - 40:32] ClassDecl=StringRef:38:7 (Definition)
-// CHECK-tokens: Keyword: "static" [41:3 - 41:9] ClassDecl=StringRef:38:7 (Definition)
-// CHECK-tokens: Keyword: "const" [41:10 - 41:15] ClassDecl=StringRef:38:7 (Definition)
+// CHECK-tokens: Keyword: "static" [41:3 - 41:9] VarDecl=npos:41:23
+// CHECK-tokens: Keyword: "const" [41:10 - 41:15] VarDecl=npos:41:23
// CHECK-tokens: Identifier: "size_t" [41:16 - 41:22] TypeRef=size_t:2:25
// CHECK-tokens: Identifier: "npos" [41:23 - 41:27] VarDecl=npos:41:23
// CHECK-tokens: Punctuation: "=" [41:28 - 41:29] VarDecl=npos:41:23
@@ -446,7 +446,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: ";" [41:40 - 41:41] ClassDecl=StringRef:38:7 (Definition)
// CHECK-tokens: Keyword: "private" [42:1 - 42:8] CXXAccessSpecifier=:42:1 (Definition)
// CHECK-tokens: Punctuation: ":" [42:8 - 42:9] CXXAccessSpecifier=:42:1 (Definition)
-// CHECK-tokens: Keyword: "const" [43:3 - 43:8] ClassDecl=StringRef:38:7 (Definition)
+// CHECK-tokens: Keyword: "const" [43:3 - 43:8] FieldDecl=Data:43:15 (Definition)
// CHECK-tokens: Keyword: "char" [43:9 - 43:13] FieldDecl=Data:43:15 (Definition)
// CHECK-tokens: Punctuation: "*" [43:14 - 43:15] FieldDecl=Data:43:15 (Definition)
// CHECK-tokens: Identifier: "Data" [43:15 - 43:19] FieldDecl=Data:43:15 (Definition)
@@ -454,7 +454,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Identifier: "size_t" [44:3 - 44:9] TypeRef=size_t:2:25
// CHECK-tokens: Identifier: "Length" [44:10 - 44:16] FieldDecl=Length:44:10 (Definition)
// CHECK-tokens: Punctuation: ";" [44:16 - 44:17] ClassDecl=StringRef:38:7 (Definition)
-// CHECK-tokens: Keyword: "static" [45:3 - 45:9] ClassDecl=StringRef:38:7 (Definition)
+// CHECK-tokens: Keyword: "static" [45:3 - 45:9] CXXMethod=min:45:17 (Definition) (static)
// CHECK-tokens: Identifier: "size_t" [45:10 - 45:16] TypeRef=size_t:2:25
// CHECK-tokens: Identifier: "min" [45:17 - 45:20] CXXMethod=min:45:17 (Definition) (static)
// CHECK-tokens: Punctuation: "(" [45:20 - 45:21] CXXMethod=min:45:17 (Definition) (static)
@@ -494,7 +494,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: "}" [47:36 - 47:37] CompoundStmt=
// CHECK-tokens: Identifier: "StringRef" [48:3 - 48:12] CXXConstructor=StringRef:48:3 (Definition)
// CHECK-tokens: Punctuation: "(" [48:12 - 48:13] CXXConstructor=StringRef:48:3 (Definition)
-// CHECK-tokens: Keyword: "const" [48:13 - 48:18] CXXConstructor=StringRef:48:3 (Definition)
+// CHECK-tokens: Keyword: "const" [48:13 - 48:18] ParmDecl=Str:48:25 (Definition)
// CHECK-tokens: Keyword: "char" [48:19 - 48:23] ParmDecl=Str:48:25 (Definition)
// CHECK-tokens: Punctuation: "*" [48:24 - 48:25] ParmDecl=Str:48:25 (Definition)
// CHECK-tokens: Identifier: "Str" [48:25 - 48:28] ParmDecl=Str:48:25 (Definition)
@@ -516,7 +516,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: "}" [48:70 - 48:71] CompoundStmt=
// CHECK-tokens: Identifier: "StringRef" [49:3 - 49:12] CXXConstructor=StringRef:49:3 (Definition)
// CHECK-tokens: Punctuation: "(" [49:12 - 49:13] CXXConstructor=StringRef:49:3 (Definition)
-// CHECK-tokens: Keyword: "const" [49:13 - 49:18] CXXConstructor=StringRef:49:3 (Definition)
+// CHECK-tokens: Keyword: "const" [49:13 - 49:18] ParmDecl=data:49:25 (Definition)
// CHECK-tokens: Keyword: "char" [49:19 - 49:23] ParmDecl=data:49:25 (Definition)
// CHECK-tokens: Punctuation: "*" [49:24 - 49:25] ParmDecl=data:49:25 (Definition)
// CHECK-tokens: Identifier: "data" [49:25 - 49:29] ParmDecl=data:49:25 (Definition)
@@ -670,7 +670,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: "(" [67:22 - 67:23] CXXConstructor=IdentifierInfo:67:8
// CHECK-tokens: Punctuation: ")" [67:23 - 67:24] CXXConstructor=IdentifierInfo:67:8
// CHECK-tokens: Punctuation: ";" [67:24 - 67:25] ClassDecl=IdentifierInfo:66:7 (Definition)
-// CHECK-tokens: Keyword: "const" [68:3 - 68:8] ClassDecl=IdentifierInfo:66:7 (Definition)
+// CHECK-tokens: Keyword: "const" [68:3 - 68:8] CXXMethod=getNameStart:68:15 (Definition)
// CHECK-tokens: Keyword: "char" [68:9 - 68:13] CXXMethod=getNameStart:68:15 (Definition)
// CHECK-tokens: Punctuation: "*" [68:14 - 68:15] CXXMethod=getNameStart:68:15 (Definition)
// CHECK-tokens: Identifier: "getNameStart" [68:15 - 68:27] CXXMethod=getNameStart:68:15 (Definition)
@@ -678,7 +678,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: ")" [68:28 - 68:29] CXXMethod=getNameStart:68:15 (Definition)
// CHECK-tokens: Keyword: "const" [68:30 - 68:35] CXXMethod=getNameStart:68:15 (Definition)
// CHECK-tokens: Punctuation: "{" [68:36 - 68:37] CompoundStmt=
-// CHECK-tokens: Keyword: "typedef" [69:5 - 69:12] DeclStmt=
+// CHECK-tokens: Keyword: "typedef" [69:5 - 69:12] TypedefDecl=actualtype:69:54 (Definition)
// CHECK-tokens: Identifier: "std" [69:13 - 69:16] NamespaceRef=std:3:11
// CHECK-tokens: Punctuation: "::" [69:16 - 69:18] TypedefDecl=actualtype:69:54 (Definition)
// CHECK-tokens: Identifier: "pair" [69:18 - 69:22] TemplateRef=pair:4:44
@@ -710,7 +710,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: ")" [72:22 - 72:23] CXXMethod=getLength:72:12 (Definition)
// CHECK-tokens: Keyword: "const" [72:24 - 72:29] CXXMethod=getLength:72:12 (Definition)
// CHECK-tokens: Punctuation: "{" [72:30 - 72:31] CompoundStmt=
-// CHECK-tokens: Keyword: "typedef" [73:5 - 73:12] DeclStmt=
+// CHECK-tokens: Keyword: "typedef" [73:5 - 73:12] TypedefDecl=actualtype:73:54 (Definition)
// CHECK-tokens: Identifier: "std" [73:13 - 73:16] NamespaceRef=std:3:11
// CHECK-tokens: Punctuation: "::" [73:16 - 73:18] TypedefDecl=actualtype:73:54 (Definition)
// CHECK-tokens: Identifier: "pair" [73:18 - 73:22] TemplateRef=pair:4:44
@@ -723,7 +723,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: ">" [73:53 - 73:54] TypedefDecl=actualtype:73:54 (Definition)
// CHECK-tokens: Identifier: "actualtype" [73:54 - 73:64] TypedefDecl=actualtype:73:54 (Definition)
// CHECK-tokens: Punctuation: ";" [73:64 - 73:65] DeclStmt=
-// CHECK-tokens: Keyword: "const" [74:5 - 74:10] DeclStmt=
+// CHECK-tokens: Keyword: "const" [74:5 - 74:10] VarDecl=p:74:17 (Definition)
// CHECK-tokens: Keyword: "char" [74:11 - 74:15] VarDecl=p:74:17 (Definition)
// CHECK-tokens: Punctuation: "*" [74:16 - 74:17] VarDecl=p:74:17 (Definition)
// CHECK-tokens: Identifier: "p" [74:17 - 74:18] VarDecl=p:74:17 (Definition)
@@ -816,7 +816,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Identifier: "StringRef" [84:3 - 84:12] TypeRef=class llvm::StringRef:38:7
// CHECK-tokens: Identifier: "Str" [84:13 - 84:16] FieldDecl=Str:84:13 (Definition)
// CHECK-tokens: Punctuation: ";" [84:16 - 84:17] ClassTemplate=StringSwitch:83:47 (Definition)
-// CHECK-tokens: Keyword: "const" [85:3 - 85:8] ClassTemplate=StringSwitch:83:47 (Definition)
+// CHECK-tokens: Keyword: "const" [85:3 - 85:8] FieldDecl=Result:85:12 (Definition)
// CHECK-tokens: Identifier: "T" [85:9 - 85:10] TypeRef=T:83:21
// CHECK-tokens: Punctuation: "*" [85:11 - 85:12] FieldDecl=Result:85:12 (Definition)
// CHECK-tokens: Identifier: "Result" [85:12 - 85:18] FieldDecl=Result:85:12 (Definition)
@@ -831,9 +831,9 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: ")" [87:38 - 87:39] CXXConstructor=StringSwitch<T, R>:87:12 (Definition)
// CHECK-tokens: Punctuation: ":" [87:40 - 87:41] CXXConstructor=StringSwitch<T, R>:87:12 (Definition)
// CHECK-tokens: Identifier: "Str" [87:42 - 87:45] MemberRef=Str:84:13
-// CHECK-tokens: Punctuation: "(" [87:45 - 87:46] UnexposedExpr=
+// CHECK-tokens: Punctuation: "(" [87:45 - 87:46] CallExpr=StringRef:38:7
// CHECK-tokens: Identifier: "Str" [87:46 - 87:49] DeclRefExpr=Str:87:35
-// CHECK-tokens: Punctuation: ")" [87:49 - 87:50] UnexposedExpr=
+// CHECK-tokens: Punctuation: ")" [87:49 - 87:50] CallExpr=StringRef:38:7
// CHECK-tokens: Punctuation: "," [87:50 - 87:51] CXXConstructor=StringSwitch<T, R>:87:12 (Definition)
// CHECK-tokens: Identifier: "Result" [87:52 - 87:58] MemberRef=Result:85:12
// CHECK-tokens: Punctuation: "(" [87:58 - 87:59] UnexposedExpr=
@@ -850,7 +850,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: "&" [88:40 - 88:41] FunctionTemplate=Case:88:42 (Definition)
// CHECK-tokens: Identifier: "Case" [88:42 - 88:46] FunctionTemplate=Case:88:42 (Definition)
// CHECK-tokens: Punctuation: "(" [88:46 - 88:47] FunctionTemplate=Case:88:42 (Definition)
-// CHECK-tokens: Keyword: "const" [88:47 - 88:52] FunctionTemplate=Case:88:42 (Definition)
+// CHECK-tokens: Keyword: "const" [88:47 - 88:52] ParmDecl=S:88:60 (Definition)
// CHECK-tokens: Keyword: "char" [88:53 - 88:57] ParmDecl=S:88:60 (Definition)
// CHECK-tokens: Punctuation: "(" [88:58 - 88:59] ParmDecl=S:88:60 (Definition)
// CHECK-tokens: Punctuation: "&" [88:59 - 88:60] ParmDecl=S:88:60 (Definition)
@@ -860,7 +860,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Identifier: "N" [88:63 - 88:64] DeclRefExpr=N:88:23
// CHECK-tokens: Punctuation: "]" [88:64 - 88:65] ParmDecl=S:88:60 (Definition)
// CHECK-tokens: Punctuation: "," [88:65 - 88:66] FunctionTemplate=Case:88:42 (Definition)
-// CHECK-tokens: Keyword: "const" [89:47 - 89:52] FunctionTemplate=Case:88:42 (Definition)
+// CHECK-tokens: Keyword: "const" [89:47 - 89:52] ParmDecl=Value:89:57 (Definition)
// CHECK-tokens: Identifier: "T" [89:53 - 89:54] TypeRef=T:83:21
// CHECK-tokens: Punctuation: "&" [89:55 - 89:56] ParmDecl=Value:89:57 (Definition)
// CHECK-tokens: Identifier: "Value" [89:57 - 89:62] ParmDecl=Value:89:57 (Definition)
@@ -874,7 +874,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Identifier: "R" [92:3 - 92:4] TypeRef=R:83:33
// CHECK-tokens: Identifier: "Default" [92:5 - 92:12] CXXMethod=Default:92:5 (Definition)
// CHECK-tokens: Punctuation: "(" [92:12 - 92:13] CXXMethod=Default:92:5 (Definition)
-// CHECK-tokens: Keyword: "const" [92:13 - 92:18] CXXMethod=Default:92:5 (Definition)
+// CHECK-tokens: Keyword: "const" [92:13 - 92:18] ParmDecl=Value:92:23 (Definition)
// CHECK-tokens: Identifier: "T" [92:19 - 92:20] TypeRef=T:83:21
// CHECK-tokens: Punctuation: "&" [92:21 - 92:22] ParmDecl=Value:92:23 (Definition)
// CHECK-tokens: Identifier: "Value" [92:23 - 92:28] ParmDecl=Value:92:23 (Definition)
@@ -899,7 +899,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK-tokens: Punctuation: "::" [100:34 - 100:36] CXXMethod=getKind:100:36 (Definition) (static)
// CHECK-tokens: Identifier: "getKind" [100:36 - 100:43] CXXMethod=getKind:100:36 (Definition) (static)
// CHECK-tokens: Punctuation: "(" [100:43 - 100:44] CXXMethod=getKind:100:36 (Definition) (static)
-// CHECK-tokens: Keyword: "const" [100:44 - 100:49] CXXMethod=getKind:100:36 (Definition) (static)
+// CHECK-tokens: Keyword: "const" [100:44 - 100:49] ParmDecl=Name:100:67 (Definition)
// CHECK-tokens: Identifier: "IdentifierInfo" [100:50 - 100:64] TypeRef=class clang::IdentifierInfo:66:7
// CHECK-tokens: Punctuation: "*" [100:65 - 100:66] ParmDecl=Name:100:67 (Definition)
// CHECK-tokens: Identifier: "Name" [100:67 - 100:71] ParmDecl=Name:100:67 (Definition)
@@ -1843,7 +1843,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo * Name) {
// CHECK: 87:35: ParmDecl=Str:87:35 (Definition) Extent=[87:25 - 87:38]
// CHECK: 87:25: TypeRef=class llvm::StringRef:38:7 Extent=[87:25 - 87:34]
// CHECK: 87:42: MemberRef=Str:84:13 Extent=[87:42 - 87:45]
-// CHECK: 87:45: UnexposedExpr= Extent=[87:45 - 87:50]
+// CHECK: 87:42: CallExpr=StringRef:38:7 Extent=[87:42 - 87:50]
// CHECK: 87:46: DeclRefExpr=Str:87:35 Extent=[87:46 - 87:49]
// CHECK: 87:52: MemberRef=Result:85:12 Extent=[87:52 - 87:58]
// CHECK: 87:58: UnexposedExpr= Extent=[87:58 - 87:61]
diff --git a/test/Index/skip-parsed-bodies/compile_commands.json b/test/Index/skip-parsed-bodies/compile_commands.json
new file mode 100644
index 0000000..da5e777
--- /dev/null
+++ b/test/Index/skip-parsed-bodies/compile_commands.json
@@ -0,0 +1,71 @@
+[
+{
+ "directory": ".",
+ "command": "/usr/bin/clang++ -fsyntax-only t1.cpp",
+ "file": "t1.cpp"
+},
+{
+ "directory": ".",
+ "command": "/usr/bin/clang++ -fsyntax-only t2.cpp -DBLAH",
+ "file": "t2.cpp"
+},
+{
+ "directory": ".",
+ "command": "/usr/bin/clang++ -fsyntax-only t3.cpp -DBLAH",
+ "file": "t2.cpp"
+}
+]
+
+// XFAIL: mingw32,win32
+// RUN: c-index-test -index-compile-db %s | FileCheck %s
+
+// CHECK: [enteredMainFile]: t1.cpp
+// CHECK: [indexDeclaration]: kind: c++-instance-method | name: method_decl | {{.*}} | isRedecl: 0 | isDef: 0 | isContainer: 0
+// CHECK-NEXT: [indexDeclaration]: kind: c++-instance-method | name: method_def1 | {{.*}} | isRedecl: 0 | isDef: 1 | isContainer: 1
+// CHECK-NEXT: [indexEntityReference]: kind: variable | name: some_val | {{.*}} | loc: ./t.h:9:27
+// CHECK-NEXT: [indexDeclaration]: kind: c++-instance-method | name: method_def2 | {{.*}} | isRedecl: 0 | isDef: 0 | isContainer: 0
+// CHECK-NEXT: [indexDeclaration]: kind: c++-instance-method | name: method_def2 | {{.*}} | isRedecl: 1 | isDef: 1 | isContainer: 1
+// CHECK-NEXT: [indexEntityReference]: kind: namespace | name: NS |
+// CHECK-NEXT: [indexEntityReference]: kind: c++-class | name: C |
+// CHECK-NEXT: [indexEntityReference]: kind: variable | name: some_val | {{.*}} | loc: ./t.h:15:5
+// CHECK-NEXT: [indexDeclaration]: kind: function | name: foo1 | {{.*}} | isRedecl: 0 | isDef: 1 | isContainer: 1
+// CHECK-NEXT: [indexEntityReference]: kind: variable | name: some_val | {{.*}} | loc: ./t.h:19:5
+// CHECK-NEXT: [diagnostic]: {{.*}} undeclared identifier 'undef_val1'
+// CHECK-NEXT: [diagnostic]: {{.*}} undeclared identifier 'undef_val2'
+// CHECK-NEXT: [diagnostic]: {{.*}} undeclared identifier 'undef_val3'
+
+// CHECK-NEXT: [enteredMainFile]: t2.cpp
+// CHECK: [indexDeclaration]: kind: c++-instance-method | name: method_decl | {{.*}} | isRedecl: 0 | isDef: 0 | isContainer: 0
+// CHECK-NEXT: [indexDeclaration]: kind: c++-instance-method | name: method_def1 | {{.*}} | isRedecl: 0 | isDef: 1 | isContainer: skipped
+// CHECK-NEXT: [indexDeclaration]: kind: c++-instance-method | name: method_def2 | {{.*}} | isRedecl: 0 | isDef: 0 | isContainer: 0
+// CHECK-NEXT: [indexDeclaration]: kind: c++-instance-method | name: method_def2 | {{.*}} | isContainer: skipped
+// CHECK-NEXT: [indexEntityReference]: kind: namespace | name: NS |
+// CHECK-NEXT: [indexEntityReference]: kind: c++-class | name: C |
+// CHECK-NEXT: [indexDeclaration]: kind: function | name: foo1 | {{.*}} | isRedecl: 0 | isDef: 1 | isContainer: skipped
+// CHECK-NEXT: [ppIncludedFile]: ./pragma_once.h
+// CHECK-NEXT: [indexDeclaration]: kind: function | name: foo2 | {{.*}} | isRedecl: 0 | isDef: 1 | isContainer: 1
+// CHECK-NEXT: [indexEntityReference]: kind: variable | name: some_val | {{.*}} | loc: ./t.h:25:5
+// CHECK: [indexDeclaration]: kind: c++-instance-method | name: tsmeth | {{.*}} | isRedecl: 0 | isDef: 1 | isContainer: 1
+// CHECK-NEXT: [indexEntityReference]: kind: variable | name: some_val | {{.*}} | loc: ./pragma_once.h:8:7
+// CHECK: [indexDeclaration]: kind: function | name: imp_foo | {{.*}} | isRedecl: 0 | isDef: 1 | isContainer: 1
+// CHECK-NEXT: [indexEntityReference]: kind: variable | name: some_val | {{.*}} | loc: ./imported.h:4:5
+// CHECK-NEXT: [diagnostic]: {{.*}} undeclared identifier 'undef_val4'
+// CHECK-NEXT: [diagnostic]: {{.*}} undeclared identifier 'undef_tsval'
+// CHECK-NEXT: [diagnostic]: {{.*}} undeclared identifier 'undef_impval'
+
+// CHECK-NEXT: [enteredMainFile]: t3.cpp
+// CHECK: [indexDeclaration]: kind: c++-instance-method | name: method_decl | {{.*}} | isRedecl: 0 | isDef: 0 | isContainer: 0
+// CHECK-NEXT: [indexDeclaration]: kind: c++-instance-method | name: method_def1 | {{.*}} | isRedecl: 0 | isDef: 1 | isContainer: skipped
+// CHECK-NEXT: [indexDeclaration]: kind: c++-instance-method | name: method_def2 | {{.*}} | isRedecl: 0 | isDef: 0 | isContainer: 0
+// CHECK-NEXT: [indexDeclaration]: kind: c++-instance-method | name: method_def2 | {{.*}} | isRedecl: 1 | isDef: 1 | isContainer: skipped
+// CHECK-NEXT: [indexEntityReference]: kind: namespace | name: NS |
+// CHECK-NEXT: [indexEntityReference]: kind: c++-class | name: C |
+// CHECK-NEXT: [indexDeclaration]: kind: function | name: foo1 | {{.*}} | isRedecl: 0 | isDef: 1 | isContainer: skipped
+// CHECK-NEXT: [ppIncludedFile]: ./pragma_once.h
+// CHECK-NEXT: [indexDeclaration]: kind: function | name: foo2 | {{.*}} | isRedecl: 0 | isDef: 1 | isContainer: skipped
+// CHECK-NEXT: [indexDeclaration]: kind: variable | {{.*}} | loc: ./pragma_once.h:3:12
+// CHECK: [indexDeclaration]: kind: c++-instance-method | name: tsmeth | {{.*}} | isRedecl: 0 | isDef: 1 | isContainer: skipped
+// CHECK-NOT: [indexEntityReference]: kind: variable | name: some_val |
+// CHECK: [indexDeclaration]: kind: function | name: imp_foo | {{.*}} | isRedecl: 0 | isDef: 1 | isContainer: skipped
+// CHECK-NOT: [indexEntityReference]: kind: variable | name: some_val |
+// CHECK-NOT: [diagnostic]: {{.*}} undeclared identifier
diff --git a/test/Index/skip-parsed-bodies/imported.h b/test/Index/skip-parsed-bodies/imported.h
new file mode 100644
index 0000000..86673e1
--- /dev/null
+++ b/test/Index/skip-parsed-bodies/imported.h
@@ -0,0 +1,5 @@
+extern int some_val;
+
+static inline int imp_foo() {
+ ++some_val; return undef_impval;
+}
diff --git a/test/Index/skip-parsed-bodies/lit.local.cfg b/test/Index/skip-parsed-bodies/lit.local.cfg
new file mode 100644
index 0000000..b38b51a
--- /dev/null
+++ b/test/Index/skip-parsed-bodies/lit.local.cfg
@@ -0,0 +1 @@
+config.suffixes = ['.json']
diff --git a/test/Index/skip-parsed-bodies/pragma_once.h b/test/Index/skip-parsed-bodies/pragma_once.h
new file mode 100644
index 0000000..76d2d94
--- /dev/null
+++ b/test/Index/skip-parsed-bodies/pragma_once.h
@@ -0,0 +1,10 @@
+#pragma once
+
+extern int some_val;
+
+template <typename T>
+struct TS {
+ int tsmeth() {
+ ++some_val; return undef_tsval;
+ }
+};
diff --git a/test/Index/skip-parsed-bodies/t.h b/test/Index/skip-parsed-bodies/t.h
new file mode 100644
index 0000000..a52b749
--- /dev/null
+++ b/test/Index/skip-parsed-bodies/t.h
@@ -0,0 +1,30 @@
+#ifndef _T_H_
+#define _T_H_
+
+extern int some_val;
+
+namespace NS {
+ class C {
+ void method_decl();
+ int method_def1() { ++some_val; return undef_val1; }
+ inline int method_def2();
+ };
+}
+
+inline int NS::C::method_def2() {
+ ++some_val; return undef_val2;
+}
+
+static inline int foo1() {
+ ++some_val; return undef_val3;
+}
+
+#ifdef BLAH
+
+static inline int foo2() {
+ ++some_val; return undef_val4;
+}
+
+#endif
+
+#endif
diff --git a/test/Index/skip-parsed-bodies/t1.cpp b/test/Index/skip-parsed-bodies/t1.cpp
new file mode 100644
index 0000000..05918d7
--- /dev/null
+++ b/test/Index/skip-parsed-bodies/t1.cpp
@@ -0,0 +1 @@
+#include "t.h"
diff --git a/test/Index/skip-parsed-bodies/t2.cpp b/test/Index/skip-parsed-bodies/t2.cpp
new file mode 100644
index 0000000..93fff44
--- /dev/null
+++ b/test/Index/skip-parsed-bodies/t2.cpp
@@ -0,0 +1,3 @@
+#include "t.h"
+#include "pragma_once.h"
+#import "imported.h"
diff --git a/test/Index/skip-parsed-bodies/t3.cpp b/test/Index/skip-parsed-bodies/t3.cpp
new file mode 100644
index 0000000..93fff44
--- /dev/null
+++ b/test/Index/skip-parsed-bodies/t3.cpp
@@ -0,0 +1,3 @@
+#include "t.h"
+#include "pragma_once.h"
+#import "imported.h"
diff --git a/test/Index/usrs.cpp b/test/Index/usrs.cpp
index 023818c..e350f5c 100644
--- a/test/Index/usrs.cpp
+++ b/test/Index/usrs.cpp
@@ -101,8 +101,8 @@ void rdar9371763() {
// CHECK: usrs.cpp c:@N@foo@C@ClsB@F@ClsB# Extent=[19:5 - 19:27]
// CHECK: usrs.cpp c:@N@foo@C@ClsB@F@result#1 Extent=[20:5 - 20:23]
// CHECK: usrs.cpp c:@N@foo@C@ClsB@F@result#1 Extent=[24:1 - 26:2]
-// CHECK: usrs.cpp c:@aN@C@ClsC Extent=[29:3 - 29:35]
-// CHECK: usrs.cpp c:@aN@w Extent=[30:3 - 30:8]
+// CHECK: usrs.cpp c:usrs.cpp@360@aN@C@ClsC Extent=[29:3 - 29:35]
+// CHECK: usrs.cpp c:usrs.cpp@396@aN@w Extent=[30:3 - 30:8]
// CHECK: usrs.cpp c:@z Extent=[33:1 - 33:6]
// CHECK: usrs.cpp c:@N@foo Extent=[35:1 - 40:2]
// CHECK: usrs.cpp c:@N@foo@N@taz Extent=[35:17 - 39:2]
@@ -137,7 +137,7 @@ void rdar9371763() {
// CHECK-NOT: ClsB
// CHECK: usrs.cpp c:@NA@foo_alias3
// CHECK: usrs.cpp c:@aN Extent=[68:1 - 73:2]
-// CHECK: usrs.cpp c:@aN@C@RDar9371763_Foo Extent=[69:1 - 72:2]
+// CHECK: usrs.cpp c:usrs.cpp@1097@aN@C@RDar9371763_Foo Extent=[69:1 - 72:2]
// CHECK: usrs.cpp c: Extent=[70:1 - 70:8]
// CHECK: usrs.cpp c:usrs.cpp@1131@aN@C@RDar9371763_Foo@F@bar# Extent=[71:3 - 71:13]
// CHECK: usrs.cpp c:usrs.cpp@1131@aN@C@RDar9371763_Foo@F@bar# Extent=[75:1 - 75:31]
diff --git a/test/Index/vector-types.c b/test/Index/vector-types.c
deleted file mode 100644
index 404e4a5..0000000
--- a/test/Index/vector-types.c
+++ /dev/null
@@ -1,6 +0,0 @@
-int __attribute__((vector_size(16))) x;
-typedef int __attribute__((vector_size(16))) int4_t;
-
-// RUN: c-index-test -test-print-typekind %s | FileCheck %s
-// CHECK: VarDecl=x:1:38 typekind=Vector [isPOD=1]
-// CHECK: TypedefDecl=int4_t:2:46 (Definition) typekind=Typedef [canonical=Vector] [isPOD=1]
diff --git a/test/Lexer/badstring_in_if0.c b/test/Lexer/badstring_in_if0.c
index 486dcf2..f7cd9d7 100644
--- a/test/Lexer/badstring_in_if0.c
+++ b/test/Lexer/badstring_in_if0.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -E %s 2>&1 | not grep error
+// RUN: %clang_cc1 -E -verify %s
+// expected-no-diagnostics
#if 0
"
diff --git a/test/Lexer/builtin_redef.c b/test/Lexer/builtin_redef.c
new file mode 100644
index 0000000..c9351dc
--- /dev/null
+++ b/test/Lexer/builtin_redef.c
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 %s -D__TIME__=1234 -U__DATE__ -E 2>&1 | FileCheck %s --check-prefix=CHECK-OUT
+// RUN: %clang_cc1 %s -D__TIME__=1234 -U__DATE__ -E 2>&1 | FileCheck %s --check-prefix=CHECK-WARN
+// RUN: %clang_cc1 %s -D__TIME__=1234 -U__DATE__ -E 2>&1 -pedantic-errors | FileCheck %s --check-prefix=CHECK-ERR
+
+// CHECK-WARN: <command line>:{{.*}} warning: redefining builtin macro
+// CHECK-WARN: <command line>:{{.*}} warning: undefining builtin macro
+
+// CHECK-ERR: <command line>:{{.*}} error: redefining builtin macro
+// CHECK-ERR: <command line>:{{.*}} error: undefining builtin macro
+
+int n = __TIME__;
+__DATE__
+
+#define __FILE__ "my file"
+// CHECK-WARN: :[[@LINE-1]]:9: warning: redefining builtin macro
+// CHECK-ERR: :[[@LINE-2]]:9: error: redefining builtin macro
+
+// CHECK-OUT: int n = 1234;
+// CHECK-OUT: __DATE__
diff --git a/test/Lexer/c90.c b/test/Lexer/c90.c
index 7142c09..649173d 100644
--- a/test/Lexer/c90.c
+++ b/test/Lexer/c90.c
@@ -29,8 +29,8 @@ void test2() {
}
void test3() {
- (void)L"\u1234"; // expected-error {{unicode escape sequences are only valid in C99 or C++}}
- (void)L'\u1234'; // expected-error {{unicode escape sequences are only valid in C99 or C++}}
+ (void)L"\u1234"; // expected-error {{universal character names are only valid in C99 or C++}}
+ (void)L'\u1234'; // expected-error {{universal character names are only valid in C99 or C++}}
}
#define PREFIX(x) foo ## x
@@ -39,3 +39,8 @@ int test4() {
int *p = &PREFIX(0p+1);
return p[-1];
}
+
+#define MY_UCN \u00FC // expected-warning {{universal character names are only valid in C99 or C++; treating as '\' followed by identifier}}
+#define NOT_A_UCN \h // no-warning
+
+extern int idWithUCN\u00FC; // expected-warning {{universal character names are only valid in C99 or C++; treating as '\' followed by identifier}} expected-error {{expected ';'}}
diff --git a/test/Lexer/char-literal.cpp b/test/Lexer/char-literal.cpp
index 8556d46..b2fab34 100644
--- a/test/Lexer/char-literal.cpp
+++ b/test/Lexer/char-literal.cpp
@@ -1,4 +1,11 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -Wfour-char-constants -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c11 -x c -Wfour-char-constants -fsyntax-only -verify %s
+
+#ifndef __cplusplus
+typedef __WCHAR_TYPE__ wchar_t;
+typedef __CHAR16_TYPE__ char16_t;
+typedef __CHAR32_TYPE__ char32_t;
+#endif
int a = 'ab'; // expected-warning {{multi-character character constant}}
int b = '\xFF\xFF'; // expected-warning {{multi-character character constant}}
@@ -7,7 +14,9 @@ int c = 'APPS'; // expected-warning {{multi-character character constant}}
char d = '⌘'; // expected-error {{character too large for enclosing character literal type}}
char e = '\u2318'; // expected-error {{character too large for enclosing character literal type}}
+#ifdef __cplusplus
auto f = '\xE2\x8C\x98'; // expected-warning {{multi-character character constant}}
+#endif
char16_t g = u'ab'; // expected-error {{Unicode character literals may not contain multiple characters}}
char16_t h = u'\U0010FFFD'; // expected-error {{character too large for enclosing character literal type}}
@@ -24,4 +33,11 @@ char32_t n = U'ab'; // expected-error {{Unicode character literals may not conta
char16_t o = '👽'; // expected-error {{character too large for enclosing character literal type}}
char16_t p[2] = u"\U0000FFFF";
-char16_t q[2] = u"\U00010000"; // expected-error {{too long}}
+char16_t q[2] = u"\U00010000";
+#ifdef __cplusplus
+// expected-error@-2 {{too long}}
+#else
+// FIXME: The above should be accepted in C11 mode.
+// expected-error@-6 {{must be an initializer list}}
+// expected-error@-6 {{must be an initializer list}}
+#endif
diff --git a/test/Lexer/counter.c b/test/Lexer/counter.c
index 2173730..70ac98e 100644
--- a/test/Lexer/counter.c
+++ b/test/Lexer/counter.c
@@ -1,16 +1,17 @@
// __COUNTER__ support: rdar://4329310
-// RUN: %clang -E %s > %t
+// RUN: %clang -E %s | FileCheck %s
#define PASTE2(x,y) x##y
#define PASTE1(x,y) PASTE2(x,y)
#define UNIQUE(x) PASTE1(x,__COUNTER__)
-// RUN: grep "A: 0" %t
A: __COUNTER__
-
-// RUN: grep "B: foo1" %t
B: UNIQUE(foo);
-// RUN: grep "C: foo2" %t
C: UNIQUE(foo);
-// RUN: grep "D: 3" %t
D: __COUNTER__
+
+// CHECK: A: 0
+// CHECK: B: foo1;
+// CHECK: C: foo2;
+// CHECK: D: 3
+
diff --git a/test/Lexer/cxx0x_raw_string_directives.cpp b/test/Lexer/cxx0x_raw_string_directives.cpp
new file mode 100644
index 0000000..a01fba0
--- /dev/null
+++ b/test/Lexer/cxx0x_raw_string_directives.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s
+// RUN: %clang_cc1 -std=c++98 -fsyntax-only -verify %s
+
+// expected-error@8 {{in c++98 only}}
+#if 0
+R"(
+#else
+#error in c++98 only)"
+#endif
diff --git a/test/Lexer/has_feature_memory_sanitizer.cpp b/test/Lexer/has_feature_memory_sanitizer.cpp
new file mode 100644
index 0000000..3ebb9e1
--- /dev/null
+++ b/test/Lexer/has_feature_memory_sanitizer.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -E -fsanitize=memory %s -o - | FileCheck --check-prefix=CHECK-MSAN %s
+// RUN: %clang_cc1 -E %s -o - | FileCheck --check-prefix=CHECK-NO-MSAN %s
+
+#if __has_feature(memory_sanitizer)
+int MemorySanitizerEnabled();
+#else
+int MemorySanitizerDisabled();
+#endif
+
+// CHECK-MSAN: MemorySanitizerEnabled
+// CHECK-NO-MSAN: MemorySanitizerDisabled
diff --git a/test/Lexer/has_feature_thread_sanitizer.cpp b/test/Lexer/has_feature_thread_sanitizer.cpp
new file mode 100644
index 0000000..0a24810
--- /dev/null
+++ b/test/Lexer/has_feature_thread_sanitizer.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -E -fsanitize=thread %s -o - | FileCheck --check-prefix=CHECK-TSAN %s
+// RUN: %clang_cc1 -E %s -o - | FileCheck --check-prefix=CHECK-NO-TSAN %s
+
+#if __has_feature(thread_sanitizer)
+int ThreadSanitizerEnabled();
+#else
+int ThreadSanitizerDisabled();
+#endif
+
+// CHECK-TSAN: ThreadSanitizerEnabled
+// CHECK-NO-TSAN: ThreadSanitizerDisabled
diff --git a/test/Lexer/pragma-message.c b/test/Lexer/pragma-message.c
index 807edda..b67886f 100644
--- a/test/Lexer/pragma-message.c
+++ b/test/Lexer/pragma-message.c
@@ -12,3 +12,5 @@
#define STRING(x) STRING2(x)
#pragma message(":O I'm a message! " STRING(__LINE__)) // expected-warning {{:O I'm a message! 13}}
#pragma message ":O gcc accepts this! " STRING(__LINE__) // expected-warning {{:O gcc accepts this! 14}}
+
+#pragma message(invalid) // expected-error {{expected string literal in pragma message}}
diff --git a/test/Lexer/pragma-operators.cpp b/test/Lexer/pragma-operators.cpp
index a76e0b2..6a5a498 100644
--- a/test/Lexer/pragma-operators.cpp
+++ b/test/Lexer/pragma-operators.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fms-extensions -E %s | FileCheck %s
+// RUN: %clang_cc1 -fms-extensions -std=c++11 -E %s | FileCheck %s
// Test that we properly expand the C99 _Pragma and Microsoft __pragma
// into #pragma directives, with newlines where needed. <rdar://problem/8412013>
@@ -17,3 +17,21 @@
#pragma warning(push)
B(foo)
#pragma warning(pop)
+
+#define pragma_L _Pragma(L"GCC diagnostic push")
+#define pragma_u8 _Pragma(u8"system_header")
+#define pragma_u _Pragma(u"GCC diagnostic pop")
+#define pragma_U _Pragma(U"comment(lib, \"libfoo\")")
+#define pragma_R _Pragma(R"(clang diagnostic ignored "-Wunused")")
+#define pragma_UR _Pragma(UR"(clang diagnostic error "-Wunused")")
+#define pragma_hello _Pragma(u8R"x(message R"y("Hello", world!)y")x")
+// CHECK: int n =
+// CHECK: #pragma GCC diagnostic push
+// CHECK: #pragma system_header
+// CHECK: #pragma GCC diagnostic pop
+// CHECK: #pragma comment(lib, "libfoo")
+// CHECK: #pragma clang diagnostic ignored "-Wunused"
+// CHECK: #pragma clang diagnostic error "-Wunused"
+// CHECK: #pragma message("\042Hello\042, world!")
+// CHECK: 0;
+int n = pragma_L pragma_u8 pragma_u pragma_U pragma_R pragma_UR pragma_hello 0;
diff --git a/test/Lexer/pragma-region.c b/test/Lexer/pragma-region.c
new file mode 100644
index 0000000..502db22
--- /dev/null
+++ b/test/Lexer/pragma-region.c
@@ -0,0 +1,33 @@
+/* Test pragma region directive from
+ http://msdn.microsoft.com/en-us/library/b6xkz944(v=vs.80).aspx */
+
+// Editor-only pragma, just skipped by compiler.
+// Syntax:
+// #pragma region optional name
+// #pragma endregion optional comment
+//
+// RUN: %clang_cc1 -fsyntax-only -verify -Wall -fms-extensions %s
+
+#pragma region
+/* inner space */
+#pragma endregion
+
+#pragma region long name
+/* inner space */
+void foo(void){}
+#pragma endregion long comment
+
+void inner();
+
+__pragma(region) // no sense, but ignored
+_Pragma("region")// ditto
+
+#pragma region2 // expected-warning {{unknown pragma ignored}}
+
+#pragma region one
+#pragma region inner
+//#pragma endregion inner
+
+#pragma endregion end
+
+// {{unclosed pragma region}} - region mismatches is not detected yet
diff --git a/test/Lexer/string_concat.cpp b/test/Lexer/string_concat.cpp
index 7e78a63..a7eb396f 100644
--- a/test/Lexer/string_concat.cpp
+++ b/test/Lexer/string_concat.cpp
@@ -1,33 +1,48 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c11 -x c -fsyntax-only -verify %s
+
+#ifndef __cplusplus
+typedef __WCHAR_TYPE__ wchar_t;
+typedef __CHAR16_TYPE__ char16_t;
+typedef __CHAR32_TYPE__ char32_t;
+#endif
void f() {
const char* a = u8"abc" u"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
const char* b = u8"abc" U"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
const char* c = u8"abc" L"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
+#ifdef __cplusplus
const char* d = u8"abc" uR"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
const char* e = u8"abc" UR"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
const char* f = u8"abc" LR"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
+#endif
const char16_t* g = u"abc" u8"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
const char16_t* h = u"abc" U"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
const char16_t* i = u"abc" L"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
+#ifdef __cplusplus
const char16_t* j = u"abc" u8R"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
const char16_t* k = u"abc" UR"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
const char16_t* l = u"abc" LR"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
+#endif
const char32_t* m = U"abc" u8"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
const char32_t* n = U"abc" u"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
const char32_t* o = U"abc" L"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
+#ifdef __cplusplus
const char32_t* p = U"abc" u8R"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
const char32_t* q = U"abc" uR"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
const char32_t* r = U"abc" LR"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
+#endif
const wchar_t* s = L"abc" u8"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
const wchar_t* t = L"abc" u"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
const wchar_t* u = L"abc" U"abc"; // expected-error {{unsupported non-standard concatenation of string literals}}
+#ifdef __cplusplus
const wchar_t* v = L"abc" u8R"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
const wchar_t* w = L"abc" uR"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
const wchar_t* x = L"abc" UR"(abc)"; // expected-error {{unsupported non-standard concatenation of string literals}}
+#endif
}
diff --git a/test/Lexer/token-concat-2.c b/test/Lexer/token-concat-2.c
deleted file mode 100644
index 7d3cd64..0000000
--- a/test/Lexer/token-concat-2.c
+++ /dev/null
@@ -1,4 +0,0 @@
-// RUN: %clang_cc1 -E -x c -o - %s | grep '[.][*]'
-// PR4395
-#define X .*
-X
diff --git a/test/Lexer/token-concat.c b/test/Lexer/token-concat.c
index 551af95..0a2cbee 100644
--- a/test/Lexer/token-concat.c
+++ b/test/Lexer/token-concat.c
@@ -1,4 +1,11 @@
-// RUN: %clang_cc1 -E -x c -o %t %s
-// RUN: grep 'IDENT.2' %t
+// RUN: %clang_cc1 -E %s | FileCheck --strict-whitespace %s
IDENT.2
+// CHECK: {{^}}IDENT.2{{$}}
+
+
+// PR4395
+#define X .*
+X
+// CHECK: {{^}}.*{{$}}
+
diff --git a/test/Lexer/unicode-strings.c b/test/Lexer/unicode-strings.c
new file mode 100644
index 0000000..3ed1f76
--- /dev/null
+++ b/test/Lexer/unicode-strings.c
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -x c -std=c11 -Werror %s
+// RUN: %clang_cc1 -x c++ -std=c++11 -Werror %s
+// RUN: %clang_cc1 -x c -std=c11 -Wc99-compat -verify %s
+// RUN: %clang_cc1 -x c++ -std=c++11 -Wc++98-compat -verify %s
+
+#ifndef __cplusplus
+typedef __CHAR16_TYPE__ char16_t;
+typedef __CHAR32_TYPE__ char32_t;
+#else
+// expected-warning@17 {{'char16_t' type specifier is incompatible with C++98}}
+// expected-warning@18 {{'char32_t' type specifier is incompatible with C++98}}
+// expected-warning@20 {{'char16_t' type specifier is incompatible with C++98}}
+// expected-warning@21 {{'char32_t' type specifier is incompatible with C++98}}
+#endif
+
+const char *a = u8"abcd"; // expected-warning {{unicode literals are incompatible with}}
+const char16_t *b = u"abcd"; // expected-warning {{unicode literals are incompatible with}}
+const char32_t *c = U"abcd"; // expected-warning {{unicode literals are incompatible with}}
+
+char16_t d = u'a'; // expected-warning {{unicode literals are incompatible with}}
+char32_t e = U'a'; // expected-warning {{unicode literals are incompatible with}}
diff --git a/test/Lexer/unicode.c b/test/Lexer/unicode.c
new file mode 100644
index 0000000..de758f1
--- /dev/null
+++ b/test/Lexer/unicode.c
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -E -DPP_ONLY=1 %s -o %t
+// RUN: FileCheck --strict-whitespace --input-file=%t %s
+
+// This file contains Unicode characters; please do not "fix" them!
+
+extern int x; // expected-warning {{treating Unicode character as whitespace}}
+extern int x; // expected-warning {{treating Unicode character as whitespace}}
+
+// CHECK: extern int {{x}}
+// CHECK: extern int {{x}}
+
+#pragma mark ¡Unicode!
+
+#define COPYRIGHT Copyright © 2012
+#define XSTR(X) #X
+#define STR(X) XSTR(X)
+
+static const char *copyright = STR(COPYRIGHT); // no-warning
+// CHECK: static const char *copyright = "Copyright © {{2012}}";
+
+#if PP_ONLY
+COPYRIGHT
+// CHECK: Copyright © {{2012}}
+CHECK: The preprocessor should not complain about Unicode characters like ©.
+#endif
diff --git a/test/Lexer/unknown-char.c b/test/Lexer/unknown-char.c
index 334df37..8d316b3 100644
--- a/test/Lexer/unknown-char.c
+++ b/test/Lexer/unknown-char.c
@@ -1,2 +1,4 @@
-// RUN: %clang_cc1 -E %s 2>&1 | not grep error
+// RUN: %clang_cc1 -E -verify %s
+// expected-no-diagnostics
+
` ` ` `
diff --git a/test/Lexer/utf8-char-literal.cpp b/test/Lexer/utf8-char-literal.cpp
index 12b001e..7a4d126 100644
--- a/test/Lexer/utf8-char-literal.cpp
+++ b/test/Lexer/utf8-char-literal.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c11 -x c -fsyntax-only -verify %s
int array0[u'ñ' == u'\xf1'? 1 : -1];
int array1['\xF1' != u'\xf1'? 1 : -1];
diff --git a/test/Lexer/utf8-invalid.c b/test/Lexer/utf8-invalid.c
new file mode 100644
index 0000000..2657b54
--- /dev/null
+++ b/test/Lexer/utf8-invalid.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -E %s -o /dev/null
+
+// Note: This file deliberately contains invalid UTF-8. Please do not fix!
+
+extern int ‚x; // expected-error{{source file is not valid UTF-8}}
+
+#if 0
+// Don't warn about bad UTF-8 in raw lexing mode.
+extern int ‚x;
+#endif
+
+// Don't warn about bad UTF-8 in preprocessor directives.
+#define x82 ‚
+#pragma mark ‚
diff --git a/test/Misc/ast-dump-attr.cpp b/test/Misc/ast-dump-attr.cpp
new file mode 100644
index 0000000..3efcd09
--- /dev/null
+++ b/test/Misc/ast-dump-attr.cpp
@@ -0,0 +1,97 @@
+// RUN: %clang_cc1 -triple x86_64-pc-linux -std=c++11 -ast-dump -ast-dump-filter Test %s | FileCheck --strict-whitespace %s
+
+int TestLocation
+__attribute__((unused));
+// CHECK: VarDecl{{.*}}TestLocation
+// CHECK-NEXT: UnusedAttr 0x{{[^ ]*}} <line:[[@LINE-2]]:16>
+
+int TestIndent
+__attribute__((unused));
+// CHECK: {{^}}VarDecl{{.*TestIndent[^()]*$}}
+// CHECK-NEXT: {{^}}`-UnusedAttr{{[^()]*$}}
+
+void TestAttributedStmt() {
+ switch (1) {
+ case 1:
+ [[clang::fallthrough]];
+ case 2:
+ ;
+ }
+}
+// CHECK: FunctionDecl{{.*}}TestAttributedStmt
+// CHECK: AttributedStmt
+// CHECK-NEXT: FallThroughAttr
+// CHECK-NEXT: NullStmt
+
+[[clang::warn_unused_result]] int TestCXX11DeclAttr();
+// CHECK: FunctionDecl{{.*}}TestCXX11DeclAttr
+// CHECK-NEXT: WarnUnusedResultAttr
+
+int TestAlignedNull __attribute__((aligned));
+// CHECK: VarDecl{{.*}}TestAlignedNull
+// CHECK-NEXT: AlignedAttr
+// CHECK-NEXT: <<<NULL>>>
+
+int TestAlignedExpr __attribute__((aligned(4)));
+// CHECK: VarDecl{{.*}}TestAlignedExpr
+// CHECK-NEXT: AlignedAttr
+// CHECK-NEXT: IntegerLiteral
+
+int TestEnum __attribute__((visibility("default")));
+// CHECK: VarDecl{{.*}}TestEnum
+// CHECK-NEXT: VisibilityAttr{{.*}} Default
+
+class __attribute__((lockable)) Mutex {
+} mu1, mu2;
+int TestExpr __attribute__((guarded_by(mu1)));
+// CHECK: VarDecl{{.*}}TestExpr
+// CHECK-NEXT: GuardedByAttr
+// CHECK-NEXT: DeclRefExpr{{.*}}mu1
+
+class Mutex TestVariadicExpr __attribute__((acquired_after(mu1, mu2)));
+// CHECK: VarDecl{{.*}}TestVariadicExpr
+// CHECK: AcquiredAfterAttr
+// CHECK-NEXT: DeclRefExpr{{.*}}mu1
+// CHECK-NEXT: DeclRefExpr{{.*}}mu2
+
+void function1(void *) {
+ int TestFunction __attribute__((cleanup(function1)));
+}
+// CHECK: VarDecl{{.*}}TestFunction
+// CHECK-NEXT: CleanupAttr{{.*}} Function{{.*}}function1
+
+void TestIdentifier(void *, int)
+__attribute__((pointer_with_type_tag(ident1,1,2)));
+// CHECK: FunctionDecl{{.*}}TestIdentifier
+// CHECK: ArgumentWithTypeTagAttr{{.*}} ident1
+
+void TestBool(void *, int)
+__attribute__((pointer_with_type_tag(bool1,1,2)));
+// CHECK: FunctionDecl{{.*}}TestBool
+// CHECK: ArgumentWithTypeTagAttr{{.*}} IsPointer
+
+void TestUnsigned(void *, int)
+__attribute__((pointer_with_type_tag(unsigned1,1,2)));
+// CHECK: FunctionDecl{{.*}}TestUnsigned
+// CHECK: ArgumentWithTypeTagAttr{{.*}} 0 1
+
+void TestInt(void) __attribute__((constructor(123)));
+// CHECK: FunctionDecl{{.*}}TestInt
+// CHECK-NEXT: ConstructorAttr{{.*}} 123
+
+int TestString __attribute__((alias("alias1")));
+// CHECK: VarDecl{{.*}}TestString
+// CHECK-NEXT: AliasAttr{{.*}} "alias1"
+
+extern struct s1 TestType
+__attribute__((type_tag_for_datatype(ident1,int)));
+// CHECK: VarDecl{{.*}}TestType
+// CHECK-NEXT: TypeTagForDatatypeAttr{{.*}} int
+
+void *TestVariadicUnsigned1(int) __attribute__((alloc_size(1)));
+// CHECK: FunctionDecl{{.*}}TestVariadicUnsigned1
+// CHECK: AllocSizeAttr{{.*}} 0
+
+void *TestVariadicUnsigned2(int, int) __attribute__((alloc_size(1,2)));
+// CHECK: FunctionDecl{{.*}}TestVariadicUnsigned2
+// CHECK: AllocSizeAttr{{.*}} 0 1
diff --git a/test/Misc/ast-dump-color.cpp b/test/Misc/ast-dump-color.cpp
new file mode 100644
index 0000000..0367cc5
--- /dev/null
+++ b/test/Misc/ast-dump-color.cpp
@@ -0,0 +1,87 @@
+// RUN: %clang_cc1 -triple x86_64-pc-linux -std=c++11 -ast-dump -fcolor-diagnostics %s | FileCheck --strict-whitespace %s
+// REQUIRES: ansi-escape-sequences
+
+/// <a>Hello</a>
+/// <br/>
+int Test __attribute__((unused));
+
+/// Comment
+void TestAttributedStmt() {
+ switch (1) {
+ case 1:
+ [[clang::fallthrough]];
+ case 2:
+ ;
+ }
+}
+
+class __attribute__((lockable)) Mutex {
+ /// A variable
+ int var1;
+ /// Another variable
+ ///
+ /// Like the other variable, but different
+ int var2;
+} mu1, mu2;
+int TestExpr __attribute__((guarded_by(mu1)));
+
+//CHECK: {{^}}[[Blue:.\[0;34m]][[RESET:.\[0m]][[GREEN:.\[0;1;32m]]TranslationUnitDecl[[RESET]][[Yellow:.\[0;33m]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]<invalid sloc>[[RESET]]>{{$}}
+//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]TypedefDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]<invalid sloc>[[RESET]]>[[CYAN:.\[0;1;36m]] __int128_t[[RESET]] [[Green:.\[0;32m]]'__int128'[[RESET]]{{$}}
+//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]TypedefDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]<invalid sloc>[[RESET]]>[[CYAN]] __uint128_t[[RESET]] [[Green]]'unsigned __int128'[[RESET]]{{$}}
+//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]TypedefDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]<invalid sloc>[[RESET]]>[[CYAN]] __builtin_va_list[[RESET]] [[Green]]'__va_list_tag [1]'[[RESET]]{{$}}
+//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]VarDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]{{.*}}ast-dump-color.cpp:6:1[[RESET]], [[Yellow]]col:5[[RESET]]>[[CYAN]] Test[[RESET]] [[Green]]'int'[[RESET]]{{$}}
+//CHECK: {{^}}[[Blue]]| |-[[RESET]][[BLUE:.\[0;1;34m]]UnusedAttr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:25[[RESET]]>{{$}}
+//CHECK: {{^}}[[Blue]]| `-[[RESET]][[YELLOW:.\[0;1;33m]]FullComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:4:4[[RESET]], [[Yellow]]line:5:8[[RESET]]>{{$}}
+//CHECK: {{^}}[[Blue]]| `-[[RESET]][[YELLOW]]ParagraphComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:4:4[[RESET]], [[Yellow]]line:5:8[[RESET]]>{{$}}
+//CHECK: {{^}}[[Blue]]| |-[[RESET]][[YELLOW]]TextComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:4:4[[RESET]]> Text=" "{{$}}
+//CHECK: {{^}}[[Blue]]| |-[[RESET]][[YELLOW]]HTMLStartTagComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:5[[RESET]], [[Yellow]]col:7[[RESET]]> Name="a"{{$}}
+//CHECK: {{^}}[[Blue]]| |-[[RESET]][[YELLOW]]TextComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:8[[RESET]], [[Yellow]]col:12[[RESET]]> Text="Hello"{{$}}
+//CHECK: {{^}}[[Blue]]| |-[[RESET]][[YELLOW]]HTMLEndTagComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:13[[RESET]], [[Yellow]]col:16[[RESET]]> Name="a"{{$}}
+//CHECK: {{^}}[[Blue]]| |-[[RESET]][[YELLOW]]TextComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:5:4[[RESET]]> Text=" "{{$}}
+//CHECK: {{^}}[[Blue]]| `-[[RESET]][[YELLOW]]HTMLStartTagComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:5[[RESET]], [[Yellow]]col:8[[RESET]]> Name="br" SelfClosing{{$}}
+//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]FunctionDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:9:1[[RESET]], [[Yellow]]line:16:1[[RESET]]>[[CYAN]] TestAttributedStmt[[RESET]] [[Green]]'void (void)'[[RESET]]{{$}}
+//CHECK: {{^}}[[Blue]]| |-[[RESET]][[MAGENTA:.\[0;1;35m]]CompoundStmt[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:9:27[[RESET]], [[Yellow]]line:16:1[[RESET]]>{{$}}
+//CHECK: {{^}}[[Blue]]| | `-[[RESET]][[MAGENTA]]SwitchStmt[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:10:3[[RESET]], [[Yellow]]line:15:3[[RESET]]>{{$}}
+//CHECK: {{^}}[[Blue]]| | |-[[RESET]][[Blue:.\[0;34m]]<<<NULL>>>[[RESET]]{{$}}
+//CHECK: {{^}}[[Blue]]| | |-[[RESET]][[MAGENTA]]IntegerLiteral[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:10:11[[RESET]]> [[Green]]'int'[[RESET]][[Cyan:.\[0;36m]][[RESET]][[Cyan]][[RESET]][[CYAN]] 1[[RESET]]{{$}}
+//CHECK: {{^}}[[Blue]]| | `-[[RESET]][[MAGENTA]]CompoundStmt[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:14[[RESET]], [[Yellow]]line:15:3[[RESET]]>{{$}}
+//CHECK: {{^}}[[Blue]]| | |-[[RESET]][[MAGENTA]]CaseStmt[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:11:3[[RESET]], [[Yellow]]line:12:27[[RESET]]>{{$}}
+//CHECK: {{^}}[[Blue]]| | | |-[[RESET]][[MAGENTA]]IntegerLiteral[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:11:8[[RESET]]> [[Green]]'int'[[RESET]][[Cyan]][[RESET]][[Cyan]][[RESET]][[CYAN]] 1[[RESET]]{{$}}
+//CHECK: {{^}}[[Blue]]| | | |-[[RESET]][[Blue]]<<<NULL>>>[[RESET]]{{$}}
+//CHECK: {{^}}[[Blue]]| | | `-[[RESET]][[MAGENTA]]AttributedStmt[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:12:5[[RESET]], [[Yellow]]col:27[[RESET]]>{{$}}
+//CHECK: {{^}}[[Blue]]| | | |-[[RESET]][[BLUE]]FallThroughAttr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:7[[RESET]], [[Yellow]]col:14[[RESET]]>{{$}}
+//CHECK: {{^}}[[Blue]]| | | `-[[RESET]][[MAGENTA]]NullStmt[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:27[[RESET]]>{{$}}
+//CHECK: {{^}}[[Blue]]| | `-[[RESET]][[MAGENTA]]CaseStmt[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:13:3[[RESET]], [[Yellow]]line:14:5[[RESET]]>{{$}}
+//CHECK: {{^}}[[Blue]]| | |-[[RESET]][[MAGENTA]]IntegerLiteral[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:13:8[[RESET]]> [[Green]]'int'[[RESET]][[Cyan]][[RESET]][[Cyan]][[RESET]][[CYAN]] 2[[RESET]]{{$}}
+//CHECK: {{^}}[[Blue]]| | |-[[RESET]][[Blue]]<<<NULL>>>[[RESET]]{{$}}
+//CHECK: {{^}}[[Blue]]| | `-[[RESET]][[MAGENTA]]NullStmt[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:14:5[[RESET]]>{{$}}
+//CHECK: {{^}}[[Blue]]| `-[[RESET]][[YELLOW]]FullComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:8:4[[RESET]], [[Yellow]]col:11[[RESET]]>{{$}}
+//CHECK: {{^}}[[Blue]]| `-[[RESET]][[YELLOW]]ParagraphComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:4[[RESET]], [[Yellow]]col:11[[RESET]]>{{$}}
+//CHECK: {{^}}[[Blue]]| `-[[RESET]][[YELLOW]]TextComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:4[[RESET]], [[Yellow]]col:11[[RESET]]> Text=" Comment"{{$}}
+//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]CXXRecordDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:18:1[[RESET]], [[Yellow]]line:25:1[[RESET]]> class[[CYAN]] Mutex[[RESET]]{{$}}
+//CHECK: {{^}}[[Blue]]| |-[[RESET]][[BLUE]]LockableAttr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:18:22[[RESET]]>{{$}}
+//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXRecordDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:1[[RESET]], [[Yellow]]col:33[[RESET]]> class[[CYAN]] Mutex[[RESET]]{{$}}
+//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]FieldDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:20:3[[RESET]], [[Yellow]]col:7[[RESET]]>[[CYAN]] var1[[RESET]] [[Green]]'int'[[RESET]]{{$}}
+//CHECK: {{^}}[[Blue]]| | `-[[RESET]][[YELLOW]]FullComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:19:6[[RESET]], [[Yellow]]col:16[[RESET]]>{{$}}
+//CHECK: {{^}}[[Blue]]| | `-[[RESET]][[YELLOW]]ParagraphComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:6[[RESET]], [[Yellow]]col:16[[RESET]]>{{$}}
+//CHECK: {{^}}[[Blue]]| | `-[[RESET]][[YELLOW]]TextComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:6[[RESET]], [[Yellow]]col:16[[RESET]]> Text=" A variable"{{$}}
+//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]FieldDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:24:3[[RESET]], [[Yellow]]col:7[[RESET]]>[[CYAN]] var2[[RESET]] [[Green]]'int'[[RESET]]{{$}}
+//CHECK: {{^}}[[Blue]]| | `-[[RESET]][[YELLOW]]FullComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:21:6[[RESET]], [[Yellow]]line:23:44[[RESET]]>{{$}}
+//CHECK: {{^}}[[Blue]]| | |-[[RESET]][[YELLOW]]ParagraphComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:21:6[[RESET]], [[Yellow]]col:22[[RESET]]>{{$}}
+//CHECK: {{^}}[[Blue]]| | | `-[[RESET]][[YELLOW]]TextComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:6[[RESET]], [[Yellow]]col:22[[RESET]]> Text=" Another variable"{{$}}
+//CHECK: {{^}}[[Blue]]| | `-[[RESET]][[YELLOW]]ParagraphComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:23:6[[RESET]], [[Yellow]]col:44[[RESET]]>{{$}}
+//CHECK: {{^}}[[Blue]]| | `-[[RESET]][[YELLOW]]TextComment[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:6[[RESET]], [[Yellow]]col:44[[RESET]]> Text=" Like the other variable, but different"{{$}}
+//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXConstructorDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:18:33[[RESET]]>[[CYAN]] Mutex[[RESET]] [[Green]]'void (void)'[[RESET]] inline{{$}}
+//CHECK: {{^}}[[Blue]]| | `-[[RESET]][[MAGENTA]]CompoundStmt[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:33[[RESET]]>{{$}}
+//CHECK: {{^}}[[Blue]]| |-[[RESET]][[GREEN]]CXXConstructorDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:33[[RESET]]>[[CYAN]] Mutex[[RESET]] [[Green]]'void (const class Mutex &)'[[RESET]] inline{{$}}
+//CHECK: {{^}}[[Blue]]| | `-[[RESET]][[GREEN]]ParmVarDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:33[[RESET]]> [[Green]]'const class Mutex &'[[RESET]]{{$}}
+//CHECK: {{^}}[[Blue]]| `-[[RESET]][[GREEN]]CXXConstructorDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:33[[RESET]]>[[CYAN]] Mutex[[RESET]] [[Green]]'void (class Mutex &&)'[[RESET]] inline{{$}}
+//CHECK: {{^}}[[Blue]]| `-[[RESET]][[GREEN]]ParmVarDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:33[[RESET]]> [[Green]]'class Mutex &&'[[RESET]]{{$}}
+//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]VarDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:1[[RESET]], [[Yellow]]line:25:3[[RESET]]>[[CYAN]] mu1[[RESET]] [[Green]]'class Mutex':'class Mutex'[[RESET]]{{$}}
+//CHECK: {{^}}[[Blue]]| `-[[RESET]][[MAGENTA]]CXXConstructExpr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:3[[RESET]]> [[Green]]'class Mutex':'class Mutex'[[RESET]][[Cyan]][[RESET]][[Cyan]][[RESET]] [[Green]]'void (void)'[[RESET]]{{$}}
+//CHECK: {{^}}[[Blue]]|-[[RESET]][[GREEN]]VarDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:18:1[[RESET]], [[Yellow]]line:25:8[[RESET]]>[[CYAN]] mu2[[RESET]] [[Green]]'class Mutex':'class Mutex'[[RESET]]{{$}}
+//CHECK: {{^}}[[Blue]]| `-[[RESET]][[MAGENTA]]CXXConstructExpr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:8[[RESET]]> [[Green]]'class Mutex':'class Mutex'[[RESET]][[Cyan]][[RESET]][[Cyan]][[RESET]] [[Green]]'void (void)'[[RESET]]{{$}}
+//CHECK: {{^}}[[Blue]]`-[[RESET]][[GREEN]]VarDecl[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]line:26:1[[RESET]], [[Yellow]]col:5[[RESET]]>[[CYAN]] TestExpr[[RESET]] [[Green]]'int'[[RESET]]{{$}}
+//CHECK: {{^}}[[Blue]] `-[[RESET]][[BLUE]]GuardedByAttr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:29[[RESET]]>{{$}}
+//CHECK: {{^}}[[Blue]] `-[[RESET]][[MAGENTA]]DeclRefExpr[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]] <[[Yellow]]col:40[[RESET]]> [[Green]]'class Mutex':'class Mutex'[[RESET]][[Cyan]] lvalue[[RESET]][[Cyan]][[RESET]] [[GREEN]]Var[[RESET]][[Yellow]] 0x{{[0-9a-fA-F]*}}[[RESET]][[CYAN]] 'mu1'[[RESET]] [[Green]]'class Mutex':'class Mutex'[[RESET]]{{$}}
+
diff --git a/test/Misc/ast-dump-comment.cpp b/test/Misc/ast-dump-comment.cpp
new file mode 100644
index 0000000..4e84af0
--- /dev/null
+++ b/test/Misc/ast-dump-comment.cpp
@@ -0,0 +1,69 @@
+// RUN: %clang_cc1 -Wdocumentation -ast-dump -ast-dump-filter Test %s | FileCheck -strict-whitespace %s
+
+/// Aaa
+int TestLocation;
+// CHECK: VarDecl{{.*}}TestLocation
+// CHECK-NEXT: FullComment 0x{{[^ ]*}} <line:[[@LINE-3]]:4, col:7>
+
+///
+int TestIndent;
+// CHECK: {{^VarDecl.*TestIndent[^()]*$}}
+// CHECK-NEXT: {{^`-FullComment.*>$}}
+
+/// Aaa
+int Test_TextComment;
+// CHECK: VarDecl{{.*}}Test_TextComment
+// CHECK-NEXT: FullComment
+// CHECK-NEXT: ParagraphComment
+// CHECK-NEXT: TextComment{{.*}} Text=" Aaa"
+
+/// \brief Aaa
+int Test_BlockCommandComment;
+// CHECK: VarDecl{{.*}}Test_BlockCommandComment
+// CHECK: BlockCommandComment{{.*}} Name="brief"
+// CHECK-NEXT: ParagraphComment
+// CHECK-NEXT: TextComment{{.*}} Text=" Aaa"
+
+/// \param Aaa xxx
+/// \param [in,out] Bbb yyy
+void Test_ParamCommandComment(int Aaa, int Bbb);
+// CHECK: FunctionDecl{{.*}}Test_ParamCommandComment
+// CHECK: ParamCommandComment{{.*}} [in] implicitly Param="Aaa" ParamIndex=0
+// CHECK-NEXT: ParagraphComment
+// CHECK-NEXT: TextComment{{.*}} Text=" xxx"
+// CHECK: ParamCommandComment{{.*}} [in,out] explicitly Param="Bbb" ParamIndex=1
+// CHECK-NEXT: ParagraphComment
+// CHECK-NEXT: TextComment{{.*}} Text=" yyy"
+
+/// \tparam Aaa xxx
+template <typename Aaa> class Test_TParamCommandComment;
+// CHECK: ClassTemplateDecl{{.*}}Test_TParamCommandComment
+// CHECK: TParamCommandComment{{.*}} Param="Aaa" Position=<0>
+// CHECK-NEXT: ParagraphComment
+// CHECK-NEXT: TextComment{{.*}} Text=" xxx"
+
+/// \c Aaa
+int Test_InlineCommandComment;
+// CHECK: VarDecl{{.*}}Test_InlineCommandComment
+// CHECK: InlineCommandComment{{.*}} Name="c" RenderMonospaced Arg[0]="Aaa"
+
+/// <a>Aaa</a>
+/// <br/>
+int Test_HTMLTagComment;
+// CHECK: VarDecl{{.*}}Test_HTMLTagComment
+// CHECK-NEXT: FullComment
+// CHECK-NEXT: ParagraphComment
+// CHECK-NEXT: TextComment{{.*}} Text=" "
+// CHECK-NEXT: HTMLStartTagComment{{.*}} Name="a"
+// CHECK-NEXT: TextComment{{.*}} Text="Aaa"
+// CHECK-NEXT: HTMLEndTagComment{{.*}} Name="a"
+// CHECK-NEXT: TextComment{{.*}} Text=" "
+// CHECK-NEXT: HTMLStartTagComment{{.*}} Name="br" SelfClosing
+
+/// \verbatim
+/// Aaa
+/// \endverbatim
+int Test_VerbatimBlockComment;
+// CHECK: VarDecl{{.*}}Test_VerbatimBlockComment
+// CHECK: VerbatimBlockComment{{.*}} Name="verbatim" CloseName="endverbatim"
+// CHECK-NEXT: VerbatimBlockLineComment{{.*}} Text=" Aaa"
diff --git a/test/Misc/ast-dump-decl.c b/test/Misc/ast-dump-decl.c
new file mode 100644
index 0000000..c74da29
--- /dev/null
+++ b/test/Misc/ast-dump-decl.c
@@ -0,0 +1,152 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ast-dump -ast-dump-filter Test %s | FileCheck -check-prefix CHECK -strict-whitespace %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ast-dump %s | FileCheck -check-prefix CHECK-TU -strict-whitespace %s
+
+int TestLocation;
+// CHECK: VarDecl 0x{{[^ ]*}} <{{.*}}:4:1, col:5> TestLocation
+
+struct TestIndent {
+ int x;
+};
+// CHECK: {{^}}RecordDecl{{.*TestIndent[^()]*$}}
+// CHECK-NEXT: {{^}}`-FieldDecl{{.*x[^()]*$}}
+
+struct TestChildren {
+ int x;
+ struct y {
+ int z;
+ };
+};
+// CHECK: RecordDecl{{.*}}TestChildren
+// CHECK-NEXT: FieldDecl{{.*}}x
+// CHECK-NEXT: RecordDecl{{.*}}y
+// CHECK-NEXT: FieldDecl{{.*}}z
+
+// CHECK-TU: TranslationUnitDecl
+
+void testLabelDecl() {
+ __label__ TestLabelDecl;
+ TestLabelDecl: goto TestLabelDecl;
+}
+// CHECK: LabelDecl{{.*}} TestLabelDecl
+
+typedef int TestTypedefDecl;
+// CHECK: TypedefDecl{{.*}} TestTypedefDecl 'int'
+
+__module_private__ typedef int TestTypedefDeclPrivate;
+// CHECK: TypedefDecl{{.*}} TestTypedefDeclPrivate 'int' __module_private__
+
+enum TestEnumDecl {
+ testEnumDecl
+};
+// CHECK: EnumDecl{{.*}} TestEnumDecl
+// CHECK-NEXT: EnumConstantDecl{{.*}} testEnumDecl
+
+struct TestEnumDeclAnon {
+ enum {
+ testEnumDeclAnon
+ } e;
+};
+// CHECK: RecordDecl{{.*}} TestEnumDeclAnon
+// CHECK-NEXT: EnumDecl{{.*>$}}
+
+enum TestEnumDeclForward;
+// CHECK: EnumDecl{{.*}} TestEnumDeclForward
+
+__module_private__ enum TestEnumDeclPrivate;
+// CHECK: EnumDecl{{.*}} TestEnumDeclPrivate __module_private__
+
+struct TestRecordDecl {
+ int i;
+};
+// CHECK: RecordDecl{{.*}} struct TestRecordDecl
+// CHECK-NEXT: FieldDecl
+
+struct TestRecordDeclEmpty {
+};
+// CHECK: RecordDecl{{.*}} struct TestRecordDeclEmpty
+
+struct TestRecordDeclAnon1 {
+ struct {
+ } testRecordDeclAnon1;
+};
+// CHECK: RecordDecl{{.*}} struct TestRecordDeclAnon1
+// CHECK-NEXT: RecordDecl{{.*}} struct
+
+struct TestRecordDeclAnon2 {
+ struct {
+ };
+};
+// CHECK: RecordDecl{{.*}} struct TestRecordDeclAnon2
+// CHECK-NEXT: RecordDecl{{.*}} struct
+
+struct TestRecordDeclForward;
+// CHECK: RecordDecl{{.*}} struct TestRecordDeclForward
+
+__module_private__ struct TestRecordDeclPrivate;
+// CHECK: RecordDecl{{.*}} struct TestRecordDeclPrivate __module_private__
+
+enum testEnumConstantDecl {
+ TestEnumConstantDecl,
+ TestEnumConstantDeclInit = 1
+};
+// CHECK: EnumConstantDecl{{.*}} TestEnumConstantDecl 'int'
+// CHECK: EnumConstantDecl{{.*}} TestEnumConstantDeclInit 'int'
+// CHECK-NEXT: IntegerLiteral
+
+struct testIndirectFieldDecl {
+ struct {
+ int TestIndirectFieldDecl;
+ };
+};
+// CHECK: IndirectFieldDecl{{.*}} TestIndirectFieldDecl 'int'
+// CHECK-NEXT: Field{{.*}} ''
+// CHECK-NEXT: Field{{.*}} 'TestIndirectFieldDecl'
+
+int TestFunctionDecl(int x, enum { e } y) {
+ return x;
+}
+// CHECK: FunctionDecl{{.*}} TestFunctionDecl 'int (int, enum {{.*}})'
+// CHECK-NEXT: EnumDecl
+// CHECK-NEXT: EnumConstantDecl{{.*}} e
+// CHECK-NEXT: ParmVarDecl{{.*}} x
+// CHECK-NEXT: ParmVarDecl{{.*}} y
+// CHECK-NEXT: CompoundStmt
+
+int TestFunctionDeclProto(int x);
+// CHECK: FunctionDecl{{.*}} TestFunctionDeclProto 'int (int)'
+// CHECK-NEXT: ParmVarDecl{{.*}} x
+
+extern int TestFunctionDeclSC();
+// CHECK: FunctionDecl{{.*}} TestFunctionDeclSC 'int ()' extern
+
+inline int TestFunctionDeclInline();
+// CHECK: FunctionDecl{{.*}} TestFunctionDeclInline 'int ()' inline
+
+struct testFieldDecl {
+ int TestFieldDecl;
+ int TestFieldDeclWidth : 1;
+ __module_private__ int TestFieldDeclPrivate;
+};
+// CHECK: FieldDecl{{.*}} TestFieldDecl 'int'
+// CHECK: FieldDecl{{.*}} TestFieldDeclWidth 'int'
+// CHECK-NEXT: IntegerLiteral
+// CHECK: FieldDecl{{.*}} TestFieldDeclPrivate 'int' __module_private__
+
+int TestVarDecl;
+// CHECK: VarDecl{{.*}} TestVarDecl 'int'
+
+extern int TestVarDeclSC;
+// CHECK: VarDecl{{.*}} TestVarDeclSC 'int' extern
+
+__thread int TestVarDeclThread;
+// CHECK: VarDecl{{.*}} TestVarDeclThread 'int' __thread
+
+__module_private__ int TestVarDeclPrivate;
+// CHECK: VarDecl{{.*}} TestVarDeclPrivate 'int' __module_private__
+
+int TestVarDeclInit = 0;
+// CHECK: VarDecl{{.*}} TestVarDeclInit 'int'
+// CHECK-NEXT: IntegerLiteral
+
+void testParmVarDecl(int TestParmVarDecl);
+// CHECK: ParmVarDecl{{.*}} TestParmVarDecl 'int'
diff --git a/test/Misc/ast-dump-decl.cpp b/test/Misc/ast-dump-decl.cpp
new file mode 100644
index 0000000..c8f7d2f
--- /dev/null
+++ b/test/Misc/ast-dump-decl.cpp
@@ -0,0 +1,457 @@
+// RUN: %clang_cc1 -std=c++11 -fms-extensions -ast-dump -ast-dump-filter Test %s | FileCheck -check-prefix CHECK -strict-whitespace %s
+
+class testEnumDecl {
+ enum class TestEnumDeclScoped;
+ enum TestEnumDeclFixed : int;
+};
+// CHECK: EnumDecl{{.*}} class TestEnumDeclScoped 'int'
+// CHECK: EnumDecl{{.*}} TestEnumDeclFixed 'int'
+
+class testFieldDecl {
+ int TestFieldDeclInit = 0;
+};
+// CHECK: FieldDecl{{.*}} TestFieldDeclInit 'int'
+// CHECK-NEXT: IntegerLiteral
+
+namespace testVarDeclNRVO {
+ class A { };
+ A foo() {
+ A TestVarDeclNRVO;
+ return TestVarDeclNRVO;
+ }
+}
+// CHECK: VarDecl{{.*}} TestVarDeclNRVO 'class testVarDeclNRVO::A' nrvo
+
+void testParmVarDeclInit(int TestParmVarDeclInit = 0);
+// CHECK: ParmVarDecl{{.*}} TestParmVarDeclInit 'int'
+// CHECK-NEXT: IntegerLiteral{{.*}}
+
+namespace TestNamespaceDecl {
+ int i;
+}
+// CHECK: NamespaceDecl{{.*}} TestNamespaceDecl
+// CHECK-NEXT: VarDecl
+
+namespace TestNamespaceDecl {
+ int j;
+}
+// CHECK: NamespaceDecl{{.*}} TestNamespaceDecl
+// CHECK-NEXT: original Namespace
+// CHECK-NEXT: VarDecl
+
+inline namespace TestNamespaceDeclInline {
+}
+// CHECK: NamespaceDecl{{.*}} TestNamespaceDeclInline inline
+
+namespace testUsingDirectiveDecl {
+ namespace A {
+ }
+}
+namespace TestUsingDirectiveDecl {
+ using namespace testUsingDirectiveDecl::A;
+}
+// CHECK: NamespaceDecl{{.*}} TestUsingDirectiveDecl
+// CHECK-NEXT: UsingDirectiveDecl{{.*}} Namespace{{.*}} 'A'
+
+namespace testNamespaceAlias {
+ namespace A {
+ }
+}
+namespace TestNamespaceAlias = testNamespaceAlias::A;
+// CHECK: NamespaceAliasDecl{{.*}} TestNamespaceAlias
+// CHECK-NEXT: Namespace{{.*}} 'A'
+
+using TestTypeAliasDecl = int;
+// CHECK: TypeAliasDecl{{.*}} TestTypeAliasDecl 'int'
+
+namespace testTypeAliasTemplateDecl {
+ template<typename T> class A;
+ template<typename T> using TestTypeAliasTemplateDecl = A<T>;
+}
+// CHECK: TypeAliasTemplateDecl{{.*}} TestTypeAliasTemplateDecl
+// CHECK-NEXT: TemplateTypeParmDecl
+// CHECK-NEXT: TypeAliasDecl{{.*}} TestTypeAliasTemplateDecl 'A<T>'
+
+namespace testCXXRecordDecl {
+ class A { };
+ class B { };
+ class TestCXXRecordDecl : virtual A, public B {
+ int i;
+ };
+}
+// CHECK: CXXRecordDecl{{.*}} class TestCXXRecordDecl
+// CHECK-NEXT: virtual private 'class testCXXRecordDecl::A'
+// CHECK-NEXT: public 'class testCXXRecordDecl::B'
+// CHECK-NEXT: CXXRecordDecl{{.*}} class TestCXXRecordDecl
+// CHECK-NEXT: FieldDecl
+
+template<class...T>
+class TestCXXRecordDeclPack : public T... {
+};
+// CHECK: CXXRecordDecl{{.*}} class TestCXXRecordDeclPack
+// CHECK-NEXT: public 'T'...
+// CHECK-NEXT: CXXRecordDecl{{.*}} class TestCXXRecordDeclPack
+
+__module_private__ class TestCXXRecordDeclPrivate;
+// CHECK: CXXRecordDecl{{.*}} class TestCXXRecordDeclPrivate __module_private__
+
+class testCXXMethodDecl {
+ __module_private__ void TestCXXMethodDeclPrivate();
+ virtual void TestCXXMethodDeclPure() = 0;
+ void TestCXXMethodDeclDelete() = delete;
+ void TestCXXMethodDeclThrow() throw();
+ void TestCXXMethodDeclThrowType() throw(int);
+};
+// CHECK: CXXMethodDecl{{.*}} TestCXXMethodDeclPrivate 'void (void)' __module_private__
+// CHECK: CXXMethodDecl{{.*}} TestCXXMethodDeclPure 'void (void)' virtual pure
+// CHECK: CXXMethodDecl{{.*}} TestCXXMethodDeclDelete 'void (void)' delete
+// CHECK: CXXMethodDecl{{.*}} TestCXXMethodDeclThrow 'void (void) throw()'
+// CHECK: CXXMethodDecl{{.*}} TestCXXMethodDeclThrowType 'void (void) throw(int)'
+
+namespace testCXXConstructorDecl {
+ class A { };
+ class TestCXXConstructorDecl : public A {
+ int I;
+ TestCXXConstructorDecl(A &a, int i) : A(a), I(i) { }
+ };
+}
+// CHECK: CXXConstructorDecl{{.*}} TestCXXConstructorDecl 'void {{.*}}'
+// CHECK-NEXT: ParmVarDecl{{.*}} a
+// CHECK-NEXT: ParmVarDecl{{.*}} i
+// CHECK-NEXT: CXXCtorInitializer{{.*}}A
+// CHECK-NEXT: Expr
+// CHECK: CXXCtorInitializer{{.*}}I
+// CHECK-NEXT: Expr
+// CHECK: CompoundStmt
+
+class TestCXXDestructorDecl {
+ ~TestCXXDestructorDecl() { }
+};
+// CHECK: CXXDestructorDecl{{.*}} ~TestCXXDestructorDecl 'void (void) noexcept'
+// CHECK-NEXT: CompoundStmt
+
+class TestCXXConversionDecl {
+ operator int() { return 0; }
+};
+// CHECK: CXXConversionDecl{{.*}} operator int 'int (void)'
+// CHECK-NEXT: CompoundStmt
+
+namespace TestStaticAssertDecl {
+ static_assert(true, "msg");
+}
+// CHECK: NamespaceDecl{{.*}} TestStaticAssertDecl
+// CHECK-NEXT: StaticAssertDecl{{.*>$}}
+// CHECK-NEXT: CXXBoolLiteralExpr
+// CHECK-NEXT: StringLiteral
+
+namespace testFunctionTemplateDecl {
+ class A { };
+ class B { };
+ class C { };
+ class D { };
+ template<typename T> void TestFunctionTemplate(T) { }
+
+ // implicit instantiation
+ void bar(A a) { TestFunctionTemplate(a); }
+
+ // explicit specialization
+ template<> void TestFunctionTemplate(B);
+
+ // explicit instantiation declaration
+ extern template void TestFunctionTemplate(C);
+
+ // explicit instantiation definition
+ template void TestFunctionTemplate(D);
+}
+// CHECK: FunctionTemplateDecl{{.*}} TestFunctionTemplate
+// CHECK-NEXT: TemplateTypeParmDecl
+// CHECK-NEXT: FunctionDecl{{.*}} TestFunctionTemplate 'void (T)'
+// CHECK-NEXT: ParmVarDecl{{.*}} 'T'
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: FunctionDecl{{.*}} TestFunctionTemplate {{.*}}A
+// CHECK-NEXT: TemplateArgument
+// CHECK-NEXT: ParmVarDecl
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: Function{{.*}} 'TestFunctionTemplate' {{.*}}B
+// CHECK-NEXT: FunctionDecl{{.*}} TestFunctionTemplate {{.*}}C
+// CHECK-NEXT: TemplateArgument
+// CHECK-NEXT: ParmVarDecl
+// CHECK-NEXT: FunctionDecl{{.*}} TestFunctionTemplate {{.*}}D
+// CHECK-NEXT: TemplateArgument
+// CHECK-NEXT: ParmVarDecl
+// CHECK-NEXT: CompoundStmt
+// CHECK: FunctionDecl{{.*}} TestFunctionTemplate {{.*}}B
+// CHECK-NEXT: TemplateArgument
+// CHECK-NEXT: ParmVarDecl
+
+namespace testClassTemplateDecl {
+ class A { };
+ class B { };
+ class C { };
+ class D { };
+
+ template<typename T> class TestClassTemplate {
+ int i;
+ };
+
+ // implicit instantiation
+ TestClassTemplate<A> a;
+
+ // explicit specialization
+ template<> class TestClassTemplate<B> {
+ int j;
+ };
+
+ // explicit instantiation declaration
+ extern template class TestClassTemplate<C>;
+
+ // explicit instantiation definition
+ template class TestClassTemplate<D>;
+
+ // partial explicit specialization
+ template<typename T1, typename T2> class TestClassTemplatePartial {
+ int i;
+ };
+ template<typename T1> class TestClassTemplatePartial<T1, A> {
+ int j;
+ };
+}
+// CHECK: ClassTemplateDecl{{.*}} TestClassTemplate
+// CHECK-NEXT: TemplateTypeParmDecl
+// CHECK-NEXT: CXXRecordDecl{{.*}} class TestClassTemplate
+// CHECK-NEXT: CXXRecordDecl{{.*}} class TestClassTemplate
+// CHECK-NEXT: FieldDecl{{.*}} i
+// CHECK-NEXT: ClassTemplateSpecializationDecl{{.*}} class TestClassTemplate
+// CHECK-NEXT: TemplateArgument{{.*}}A
+// CHECK-NEXT: CXXRecordDecl{{.*}} class TestClassTemplate
+// CHECK-NEXT: FieldDecl{{.*}} i
+// CHECK: ClassTemplateSpecialization{{.*}} 'TestClassTemplate'
+// CHECK-NEXT: ClassTemplateSpecialization{{.*}} 'TestClassTemplate'
+// CHECK-NEXT: ClassTemplateSpecialization{{.*}} 'TestClassTemplate'
+
+// CHECK: ClassTemplateSpecializationDecl{{.*}} class TestClassTemplate
+// CHECK-NEXT: TemplateArgument{{.*}}B
+// CHECK-NEXT: CXXRecordDecl{{.*}} class TestClassTemplate
+// CHECK-NEXT: FieldDecl{{.*}} j
+
+// CHECK: ClassTemplateSpecializationDecl{{.*}} class TestClassTemplate
+// CHECK-NEXT: TemplateArgument{{.*}}C
+// CHECK-NEXT: CXXRecordDecl{{.*}} class TestClassTemplate
+// CHECK-NEXT: FieldDecl{{.*}} i
+
+// CHECK: ClassTemplateSpecializationDecl{{.*}} class TestClassTemplate
+// CHECK-NEXT: TemplateArgument{{.*}}D
+// CHECK-NEXT: CXXRecordDecl{{.*}} class TestClassTemplate
+// CHECK-NEXT: FieldDecl{{.*}} i
+
+// CHECK: ClassTemplatePartialSpecializationDecl{{.*}} class TestClassTemplatePartial
+// CHECK-NEXT: TemplateArgument
+// CHECK-NEXT: TemplateArgument{{.*}}A
+// CHECK-NEXT: TemplateTypeParmDecl
+// CHECK-NEXT: CXXRecordDecl{{.*}} class TestClassTemplatePartial
+// CHECK-NEXT: FieldDecl{{.*}} j
+
+// PR15220 dump instantiation only once
+namespace testCanonicalTemplate {
+ class A {};
+
+ template<typename T> void TestFunctionTemplate(T);
+ template<typename T> void TestFunctionTemplate(T);
+ void bar(A a) { TestFunctionTemplate(a); }
+ // CHECK: FunctionTemplateDecl{{.*}} TestFunctionTemplate
+ // CHECK-NEXT: TemplateTypeParmDecl
+ // CHECK-NEXT: FunctionDecl{{.*}} TestFunctionTemplate 'void (T)'
+ // CHECK-NEXT: ParmVarDecl{{.*}} 'T'
+ // CHECK-NEXT: FunctionDecl{{.*}} TestFunctionTemplate {{.*}}A
+ // CHECK-NEXT: TemplateArgument
+ // CHECK-NEXT: ParmVarDecl
+ // CHECK: FunctionTemplateDecl{{.*}} TestFunctionTemplate
+ // CHECK-NEXT: TemplateTypeParmDecl
+ // CHECK-NEXT: FunctionDecl{{.*}} TestFunctionTemplate 'void (T)'
+ // CHECK-NEXT: ParmVarDecl{{.*}} 'T'
+ // CHECK-NEXT: Function{{.*}} 'TestFunctionTemplate'
+ // CHECK-NEXT-NOT: TemplateArgument
+
+ template<typename T1> class TestClassTemplate {
+ template<typename T2> friend class TestClassTemplate;
+ };
+ TestClassTemplate<A> a;
+ // CHECK: ClassTemplateDecl{{.*}} TestClassTemplate
+ // CHECK-NEXT: TemplateTypeParmDecl
+ // CHECK-NEXT: CXXRecordDecl{{.*}} class TestClassTemplate
+ // CHECK-NEXT: CXXRecordDecl{{.*}} class TestClassTemplate
+ // CHECK-NEXT: FriendDecl
+ // CHECK-NEXT: ClassTemplateDecl{{.*}} TestClassTemplate
+ // CHECK-NEXT: TemplateTypeParmDecl
+ // CHECK-NEXT: CXXRecordDecl{{.*}} class TestClassTemplate
+ // CHECK-NEXT: ClassTemplateSpecialization{{.*}} 'TestClassTemplate'
+ // CHECK-NEXT: ClassTemplateSpecializationDecl{{.*}} class TestClassTemplate
+ // CHECK-NEXT: TemplateArgument{{.*}}A
+ // CHECK-NEXT: CXXRecordDecl{{.*}} class TestClassTemplate
+}
+
+template <class T>
+class TestClassScopeFunctionSpecialization {
+ template<class U> void foo(U a) { }
+ template<> void foo<int>(int a) { }
+};
+// CHECK: ClassScopeFunctionSpecializationDecl
+// CHECK-NEXT: CXXMethod{{.*}} 'foo' 'void (int)'
+// CHECK-NEXT: TemplateArgument{{.*}} 'int'
+
+namespace TestTemplateTypeParmDecl {
+ template<typename ... T, class U = int> void foo();
+}
+// CHECK: NamespaceDecl{{.*}} TestTemplateTypeParmDecl
+// CHECK-NEXT: FunctionTemplateDecl
+// CHECK-NEXT: TemplateTypeParmDecl{{.*}} typename ... T
+// CHECK-NEXT: TemplateTypeParmDecl{{.*}} class U 'int'
+
+namespace TestNonTypeTemplateParmDecl {
+ template<int I = 1, int ... J> void foo();
+}
+// CHECK: NamespaceDecl{{.*}} TestNonTypeTemplateParmDecl
+// CHECK-NEXT: FunctionTemplateDecl
+// CHECK-NEXT: NonTypeTemplateParmDecl{{.*}} 'int' I
+// CHECK-NEXT: IntegerLiteral{{.*}} 'int' 1
+// CHECK-NEXT: NonTypeTemplateParmDecl{{.*}} 'int' ... J
+
+namespace TestTemplateTemplateParmDecl {
+ template<typename T> class A;
+ template <template <typename> class T = A, template <typename> class ... U> void foo();
+}
+// CHECK: NamespaceDecl{{.*}} TestTemplateTemplateParmDecl
+// CHECK: FunctionTemplateDecl
+// CHECK-NEXT: TemplateTemplateParmDecl{{.*}} T
+// CHECK-NEXT: TemplateTypeParmDecl{{.*}} typename
+// CHECK-NEXT: TemplateArgument{{.*}} template A
+// CHECK-NEXT: TemplateTemplateParmDecl{{.*}} ... U
+// CHECK-NEXT: TemplateTypeParmDecl{{.*}} typename
+
+namespace TestTemplateArgument {
+ template<typename> class A { };
+ template<template<typename> class ...> class B { };
+ int foo();
+
+ template<typename> class testType { };
+ template class testType<int>;
+ // CHECK: ClassTemplateSpecializationDecl{{.*}} class testType
+ // CHECK-NEXT: TemplateArgument{{.*}} type 'int'
+
+ template<int fp(void)> class testDecl { };
+ template class testDecl<foo>;
+ // CHECK: ClassTemplateSpecializationDecl{{.*}} class testDecl
+ // CHECK-NEXT: TemplateArgument{{.*}} decl
+ // CHECK-NEXT: Function{{.*}}foo
+
+ template class testDecl<nullptr>;
+ // CHECK: ClassTemplateSpecializationDecl{{.*}} class testDecl
+ // CHECK-NEXT: TemplateArgument{{.*}} nullptr
+
+ template<int> class testIntegral { };
+ template class testIntegral<1>;
+ // CHECK: ClassTemplateSpecializationDecl{{.*}} class testIntegral
+ // CHECK-NEXT: TemplateArgument{{.*}} integral 1
+
+ template<template<typename> class> class testTemplate { };
+ template class testTemplate<A>;
+ // CHECK: ClassTemplateSpecializationDecl{{.*}} class testTemplate
+ // CHECK-NEXT: TemplateArgument{{.*}} A
+
+ template<template<typename> class ...T> class C {
+ B<T...> testTemplateExpansion;
+ };
+ // FIXME: Need TemplateSpecializationType dumping to test TemplateExpansion.
+
+ template<int, int = 0> class testExpr;
+ template<int I> class testExpr<I> { };
+ // CHECK: ClassTemplatePartialSpecializationDecl{{.*}} class testExpr
+ // CHECK-NEXT: TemplateArgument{{.*}} expr
+ // CHECK-NEXT: DeclRefExpr{{.*}}I
+
+ template<int, int ...> class testPack { };
+ template class testPack<0, 1, 2>;
+ // CHECK: ClassTemplateSpecializationDecl{{.*}} class testPack
+ // CHECK-NEXT: TemplateArgument{{.*}} integral 0
+ // CHECK-NEXT: TemplateArgument{{.*}} pack
+ // CHECK-NEXT: TemplateArgument{{.*}} integral 1
+ // CHECK-NEXT: TemplateArgument{{.*}} integral 2
+}
+
+namespace testUsingDecl {
+ int i;
+}
+namespace TestUsingDecl {
+ using testUsingDecl::i;
+}
+// CHECK: NamespaceDecl{{.*}} TestUsingDecl
+// CHECK-NEXT: UsingDecl{{.*}} testUsingDecl::i
+// CHECK-NEXT: UsingShadowDecl{{.*}} Var{{.*}} 'i' 'int'
+
+namespace testUnresolvedUsing {
+ class A { };
+ template<class T> class B {
+ public:
+ A a;
+ };
+ template<class T> class TestUnresolvedUsing : public B<T> {
+ using typename B<T>::a;
+ using B<T>::a;
+ };
+}
+// CHECK: CXXRecordDecl{{.*}} TestUnresolvedUsing
+// CHECK: UnresolvedUsingTypenameDecl{{.*}} B<T>::a
+// CHECK: UnresolvedUsingValueDecl{{.*}} B<T>::a
+
+namespace TestLinkageSpecDecl {
+ extern "C" void test1();
+ extern "C++" void test2();
+}
+// CHECK: NamespaceDecl{{.*}} TestLinkageSpecDecl
+// CHECK-NEXT: LinkageSpecDecl{{.*}} C
+// CHECK-NEXT: FunctionDecl
+// CHECK-NEXT: LinkageSpecDecl{{.*}} C++
+// CHECK-NEXT: FunctionDecl
+
+class TestAccessSpecDecl {
+public:
+private:
+protected:
+};
+// CHECK: CXXRecordDecl{{.*}} class TestAccessSpecDecl
+// CHECK-NEXT: CXXRecordDecl{{.*}} class TestAccessSpecDecl
+// CHECK-NEXT: AccessSpecDecl{{.*}} public
+// CHECK-NEXT: AccessSpecDecl{{.*}} private
+// CHECK-NEXT: AccessSpecDecl{{.*}} protected
+
+template<typename T> class TestFriendDecl {
+ friend int foo();
+ friend class A;
+ friend T;
+};
+// CHECK: CXXRecord{{.*}} TestFriendDecl
+// CHECK-NEXT: CXXRecord{{.*}} TestFriendDecl
+// CHECK-NEXT: FriendDecl
+// CHECK-NEXT: FunctionDecl{{.*}} foo
+// CHECK-NEXT: FriendDecl{{.*}} 'class A':'class A'
+// CHECK-NEXT: FriendDecl{{.*}} 'T'
+
+namespace TestFileScopeAsmDecl {
+ asm("ret");
+}
+// CHECK: NamespaceDecl{{.*}} TestFileScopeAsmDecl{{$}}
+// CHECK: FileScopeAsmDecl{{.*>$}}
+// CHECK-NEXT: StringLiteral
+
+namespace TestFriendDecl2 {
+ void f();
+ struct S {
+ friend void f();
+ };
+}
+// CHECK: NamespaceDecl [[TestFriendDecl2:0x.*]] <{{.*}}> TestFriendDecl2
+// CHECK: |-FunctionDecl [[TestFriendDecl2_f:0x.*]] <{{.*}}> f 'void (void)'
+// CHECK: `-CXXRecordDecl {{.*}} struct S
+// CHECK: |-CXXRecordDecl {{.*}} struct S
+// CHECK: `-FriendDecl
+// CHECK: `-FunctionDecl {{.*}} parent [[TestFriendDecl2]] prev [[TestFriendDecl2_f]] <{{.*}}> f 'void (void)'
diff --git a/test/Misc/ast-dump-decl.m b/test/Misc/ast-dump-decl.m
new file mode 100644
index 0000000..f8a5e5a
--- /dev/null
+++ b/test/Misc/ast-dump-decl.m
@@ -0,0 +1,136 @@
+// RUN: %clang_cc1 -Wno-unused -fblocks -ast-dump -ast-dump-filter Test %s | FileCheck -strict-whitespace %s
+
+@protocol P
+@end
+
+@interface A
+@end
+
+@interface TestObjCIvarDecl : A
+@end
+
+@implementation TestObjCIvarDecl {
+ int varDefault;
+ @private int varPrivate;
+ @protected int varProtected;
+ @public int varPublic;
+ @package int varPackage;
+}
+@end
+// CHECK: ObjCImplementationDecl{{.*}} TestObjCIvarDecl
+// CHECK-NEXT: ObjCInterface{{.*}} 'TestObjCIvarDecl'
+// CHECK-NEXT: ObjCIvarDecl{{.*}} varDefault 'int' private
+// CHECK-NEXT: ObjCIvarDecl{{.*}} varPrivate 'int' private
+// CHECK-NEXT: ObjCIvarDecl{{.*}} varProtected 'int' protected
+// CHECK-NEXT: ObjCIvarDecl{{.*}} varPublic 'int' public
+// CHECK-NEXT: ObjCIvarDecl{{.*}} varPackage 'int' package
+
+@interface testObjCMethodDecl : A {
+}
+- (int) TestObjCMethodDecl: (int)i, ...;
+// CHECK: ObjCMethodDecl{{.*}} - TestObjCMethodDecl: 'int'
+// CHECK-NEXT: ParmVarDecl{{.*}} i 'int'
+// CHECK-NEXT: ...
+@end
+
+@implementation testObjCMethodDecl
+- (int) TestObjCMethodDecl: (int)i, ... {
+ return 0;
+}
+// CHECK: ObjCMethodDecl{{.*}} - TestObjCMethodDecl: 'int'
+// CHECK-NEXT: ImplicitParamDecl{{.*}} self
+// CHECK-NEXT: ImplicitParamDecl{{.*}} _cmd
+// CHECK-NEXT: ParmVarDecl{{.*}} i 'int'
+// CHECK-NEXT: ...
+// CHECK-NEXT: CompoundStmt
+@end
+
+@protocol TestObjCProtocolDecl
+- (void) foo;
+@end
+// CHECK: ObjCProtocolDecl{{.*}} TestObjCProtocolDecl
+// CHECK-NEXT: ObjCMethodDecl{{.*}} foo
+
+@interface TestObjCClass : A <P>
+- (void) foo;
+@end
+// CHECK: ObjCInterfaceDecl{{.*}} TestObjCClass
+// CHECK-NEXT: super ObjCInterface{{.*}} 'A'
+// CHECK-NEXT: ObjCImplementation{{.*}} 'TestObjCClass'
+// CHECK-NEXT: ObjCProtocol{{.*}} 'P'
+// CHECK-NEXT: ObjCMethodDecl{{.*}} foo
+
+@implementation TestObjCClass : A {
+ int i;
+}
+- (void) foo {
+}
+@end
+// CHECK: ObjCImplementationDecl{{.*}} TestObjCClass
+// CHECK-NEXT: super ObjCInterface{{.*}} 'A'
+// CHECK-NEXT: ObjCInterface{{.*}} 'TestObjCClass'
+// CHECK-NEXT: ObjCIvarDecl{{.*}} i
+// CHECK-NEXT: ObjCMethodDecl{{.*}} foo
+
+@interface TestObjCClass (TestObjCCategoryDecl) <P>
+- (void) bar;
+@end
+// CHECK: ObjCCategoryDecl{{.*}} TestObjCCategoryDecl
+// CHECK-NEXT: ObjCInterface{{.*}} 'TestObjCClass'
+// CHECK-NEXT: ObjCCategoryImpl{{.*}} 'TestObjCClass'
+// CHECK-NEXT: ObjCProtocol{{.*}} 'P'
+// CHECK-NEXT: ObjCMethodDecl{{.*}} bar
+
+@implementation TestObjCClass (TestObjCCategoryDecl)
+- (void) bar {
+}
+@end
+// CHECK: ObjCCategoryImplDecl{{.*}} TestObjCClass
+// CHECK-NEXT: ObjCInterface{{.*}} 'TestObjCClass'
+// CHECK-NEXT: ObjCCategory{{.*}} 'TestObjCCategoryDecl'
+// CHECK-NEXT: ObjCMethodDecl{{.*}} bar
+
+@compatibility_alias TestObjCCompatibleAliasDecl A;
+// CHECK: ObjCCompatibleAliasDecl{{.*}} TestObjCCompatibleAliasDecl
+// CHECK-NEXT: ObjCInterface{{.*}} 'A'
+
+@interface TestObjCProperty: A
+@property(getter=getterFoo, setter=setterFoo:) int foo;
+@property int bar;
+@end
+// CHECK: ObjCInterfaceDecl{{.*}} TestObjCProperty
+// CHECK: ObjCPropertyDecl{{.*}} foo 'int' assign readwrite atomic unsafe_unretained
+// CHECK-NEXT: getter ObjCMethod{{.*}} 'getterFoo'
+// CHECK-NEXT: setter ObjCMethod{{.*}} 'setterFoo:'
+// CHECK-NEXT: ObjCPropertyDecl{{.*}} bar 'int' assign readwrite atomic unsafe_unretained
+// CHECK-NEXT: ObjCMethodDecl{{.*}} getterFoo
+// CHECK-NEXT: ObjCMethodDecl{{.*}} setterFoo:
+// CHECK-NEXT: ParmVarDecl{{.*}} foo
+// CHECK-NEXT: ObjCMethodDecl{{.*}} bar
+// CHECK-NEXT: ObjCMethodDecl{{.*}} setBar:
+// CHECK-NEXT: ParmVarDecl{{.*}} bar
+
+@implementation TestObjCProperty {
+ int i;
+}
+@synthesize foo=i;
+@synthesize bar;
+@end
+// CHECK: ObjCImplementationDecl{{.*}} TestObjCProperty
+// CHECK: ObjCPropertyImplDecl{{.*}} foo synthesize
+// CHECK-NEXT: ObjCProperty{{.*}} 'foo'
+// CHECK-NEXT: ObjCIvar{{.*}} 'i' 'int'
+// CHECK-NEXT: ObjCIvarDecl{{.*}} bar 'int' synthesize private
+// CHECK-NEXT: ObjCPropertyImplDecl{{.*}} bar synthesize
+// CHECK-NEXT: ObjCProperty{{.*}} 'bar'
+// CHECK-NEXT: ObjCIvar{{.*}} 'bar' 'int'
+
+void TestBlockDecl(int x) {
+ ^(int y, ...){ x; };
+}
+// CHECK: FunctionDecl{{.*}}TestBlockDecl
+// CHECK: BlockDecl
+// CHECK-NEXT: ParmVarDecl{{.*}} y 'int'
+// CHECK-NEXT: ...
+// CHECK-NEXT: capture ParmVar{{.*}} 'x' 'int'
+// CHECK-NEXT: CompoundStmt
diff --git a/test/Misc/ast-dump-decl.mm b/test/Misc/ast-dump-decl.mm
new file mode 100644
index 0000000..06ab515
--- /dev/null
+++ b/test/Misc/ast-dump-decl.mm
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -Wno-unused -fblocks -ast-dump -ast-dump-filter Test %s | FileCheck -strict-whitespace %s
+
+@interface A
+@end
+
+@interface TestObjCImplementation : A
+@end
+
+@implementation TestObjCImplementation : A {
+ struct X {
+ int i;
+ } X;
+}
+- (void) foo {
+}
+@end
+// CHECK: ObjCImplementationDecl{{.*}} TestObjCImplementation
+// CHECK-NEXT: super ObjCInterface{{.*}} 'A'
+// CHECK-NEXT: ObjCInterface{{.*}} 'TestObjCImplementation'
+// CHECK-NEXT: CXXCtorInitializer{{.*}} 'X'
+// CHECK-NEXT: CXXConstructExpr
+// CHECK-NEXT: ObjCIvarDecl{{.*}} X
+// CHECK-NEXT: ObjCMethodDecl{{.*}} foo
diff --git a/test/Misc/ast-dump-stmt.c b/test/Misc/ast-dump-stmt.c
index d7fdce8..1f21cf0 100644
--- a/test/Misc/ast-dump-stmt.c
+++ b/test/Misc/ast-dump-stmt.c
@@ -1,31 +1,31 @@
// 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
+// CHECK: VarDecl{{.*}}TestLocation
+// CHECK-NEXT: IntegerLiteral 0x{{[^ ]*}} <col: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[^()]*\)\)\)$}}
+// CHECK: VarDecl{{.*}}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: FunctionDecl{{.*}}TestDeclStmt
// CHECK-NEXT: CompoundStmt
// CHECK-NEXT: DeclStmt
-// CHECK-NEXT: int x =
+// CHECK-NEXT: VarDecl{{.*}}x
// CHECK-NEXT: IntegerLiteral
// CHECK-NEXT: DeclStmt
-// CHECK-NEXT: int y
-// CHECK-NEXT: int z
+// CHECK-NEXT: VarDecl{{.*}}y
+// CHECK-NEXT: VarDecl{{.*}}z
int TestOpaqueValueExpr = 0 ?: 1;
-// CHECK: Dumping TestOpaqueValueExpr
+// CHECK: VarDecl{{.*}}TestOpaqueValueExpr
// CHECK-NEXT: BinaryConditionalOperator
// CHECK-NEXT: IntegerLiteral
// CHECK-NEXT: OpaqueValueExpr
diff --git a/test/Misc/ast-dump-stmt.cpp b/test/Misc/ast-dump-stmt.cpp
new file mode 100644
index 0000000..cf3e8bf
--- /dev/null
+++ b/test/Misc/ast-dump-stmt.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -ast-dump -ast-dump-filter Test %s | FileCheck -strict-whitespace %s
+
+namespace n {
+void function() {}
+int Variable;
+}
+using n::function;
+using n::Variable;
+void TestFunction() {
+ void (*f)() = &function;
+// CHECK: DeclRefExpr{{.*}} (UsingShadow{{.*}}function
+ Variable = 4;
+// CHECK: DeclRefExpr{{.*}} (UsingShadow{{.*}}Variable
+}
diff --git a/test/Misc/ast-dump-stmt.m b/test/Misc/ast-dump-stmt.m
index 8dfee74..8c0ca89 100644
--- a/test/Misc/ast-dump-stmt.m
+++ b/test/Misc/ast-dump-stmt.m
@@ -3,15 +3,14 @@
void TestBlockExpr(int x) {
^{ x; };
}
-// CHECK: Dumping TestBlockExpr
-// CHECK: BlockExpr{{.*}} decl=
-// CHECK-NEXT: capture ParmVar
-// CHECK-NEXT: CompoundStmt
+// CHECK: FunctionDecl{{.*}}TestBlockExpr
+// CHECK: BlockExpr{{.*}} 'void (^)(void)'
+// CHECK-NEXT: BlockDecl
void TestExprWithCleanup(int x) {
^{ x; };
}
-// CHECK: Dumping TestExprWithCleanup
+// CHECK: FunctionDecl{{.*}}TestExprWithCleanup
// CHECK: ExprWithCleanups
// CHECK-NEXT: cleanup Block
// CHECK-NEXT: BlockExpr
@@ -26,10 +25,11 @@ void TestObjCAtCatchStmt() {
} @finally {
}
}
-// CHECK: Dumping TestObjCAtCatchStmt
+// CHECK: FunctionDecl{{.*}}TestObjCAtCatchStmt
// CHECK: ObjCAtTryStmt
// CHECK-NEXT: CompoundStmt
-// CHECK-NEXT: ObjCAtCatchStmt{{.*}} catch parm = "A *a"
+// CHECK-NEXT: ObjCAtCatchStmt{{.*}}
+// CHECK-NEXT: VarDecl{{.*}}a
// CHECK-NEXT: CompoundStmt
// CHECK-NEXT: ObjCAtCatchStmt{{.*}} catch all
// CHECK-NEXT: CompoundStmt
diff --git a/test/Misc/ast-dump-templates.cpp b/test/Misc/ast-dump-templates.cpp
index 7d56e7b..7e28da9 100644
--- a/test/Misc/ast-dump-templates.cpp
+++ b/test/Misc/ast-dump-templates.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -ast-dump %s > %t
+// RUN: %clang_cc1 -ast-print %s > %t
// RUN: FileCheck < %t %s -check-prefix=CHECK1
// RUN: FileCheck < %t %s -check-prefix=CHECK2
@@ -27,8 +27,8 @@ void baz() {
// CHECK2: template <int X = 2, typename Y = double, int Z = 3> struct foo {
// Template definition - foo
-// CHECK1: template <int X, typename Y, int Z = (IntegerLiteral {{.*}} 'int' 5)
-// CHECK2: template <int X, typename Y, int Z = (IntegerLiteral {{.*}} 'int' 5)
+// CHECK1: template <int X, typename Y, int Z = 5> struct foo {
+// CHECK2: template <int X, typename Y, int Z = 5> struct foo {
// Template instantiation - bar
// CHECK1: template <int A = 5, typename B = int> int bar()
diff --git a/test/Misc/ast-dump-wchar.cpp b/test/Misc/ast-dump-wchar.cpp
index 87d962f..9768bc8 100644
--- a/test/Misc/ast-dump-wchar.cpp
+++ b/test/Misc/ast-dump-wchar.cpp
@@ -1,13 +1,13 @@
// RUN: %clang_cc1 -std=c++11 -ast-dump %s -triple x86_64-linux-gnu | FileCheck %s
char c8[] = u8"test\0\\\"\t\a\b\234";
-// CHECK: char c8[12] = (StringLiteral {{.*}} lvalue u8"test\000\\\"\t\a\b\234")
+// CHECK: StringLiteral {{.*}} lvalue u8"test\000\\\"\t\a\b\234"
char16_t c16[] = u"test\0\\\"\t\a\b\234\u1234";
-// CHECK: char16_t c16[13] = (StringLiteral {{.*}} lvalue u"test\000\\\"\t\a\b\234\u1234")
+// CHECK: StringLiteral {{.*}} lvalue u"test\000\\\"\t\a\b\234\u1234"
char32_t c32[] = U"test\0\\\"\t\a\b\234\u1234\U0010ffff"; // \
-// CHECK: char32_t c32[14] = (StringLiteral {{.*}} lvalue U"test\000\\\"\t\a\b\234\u1234\U0010FFFF")
+// CHECK: StringLiteral {{.*}} lvalue U"test\000\\\"\t\a\b\234\u1234\U0010FFFF"
wchar_t wc[] = L"test\0\\\"\t\a\b\234\u1234\xffffffff"; // \
-// CHECK: wchar_t wc[14] = (StringLiteral {{.*}} lvalue L"test\000\\\"\t\a\b\234\x1234\xFFFFFFFF")
+// CHECK: StringLiteral {{.*}} lvalue L"test\000\\\"\t\a\b\234\x1234\xFFFFFFFF"
diff --git a/test/Misc/caret-diags-macros.c b/test/Misc/caret-diags-macros.c
index 5faddb6..316454c 100644
--- a/test/Misc/caret-diags-macros.c
+++ b/test/Misc/caret-diags-macros.c
@@ -10,15 +10,15 @@ void foo() {
// CHECK: {{.*}}:3:{{[0-9]+}}: note: expanded from macro 'M1'
}
-#define A 1
-#define B A
-#define C B
+#define A(x) x
+#define B(x) A(x)
+#define C(x) B(x)
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'
+ C(1);
+ // CHECK: {{.*}}:17:5: warning: expression result unused
+ // CHECK: {{.*}}:15:16: note: expanded from macro 'C'
+ // CHECK: {{.*}}:14:16: note: expanded from macro 'B'
+ // CHECK: {{.*}}:13:14: note: expanded from macro 'A'
}
// rdar://7597492
@@ -113,21 +113,29 @@ void test3() {
// CHECK: {{.*}}:102:41: note: expanded from macro 'variadic_pasting_args1'
variadic_pasting_args3a(1, 2, 3, 4);
- // CHECK: {{.*}}:115:30: warning: expression result unused
- // CHECK: {{.*}}:106:71: note: expanded from macro 'variadic_pasting_args3a'
- // CHECK: {{.*}}:104:70: note: expanded from macro 'variadic_pasting_args2a'
- // CHECK: {{.*}}:102:41: note: expanded from macro 'variadic_pasting_args1'
+ // CHECK: {{.*}}:115:3: warning: expression result unused
+ // CHECK-NEXT: variadic_pasting_args3a(1, 2, 3, 4);
+ // CHECK-NEXT: {{ \^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}
+ // CHECK: {{.*}}:106:44: note: expanded from macro 'variadic_pasting_args3a'
+ // CHECK-NEXT: #define variadic_pasting_args3a(x, y, ...) variadic_pasting_args2a(x, y, __VA_ARGS__)
+ // CHECK-NEXT: {{ \^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}}
+ // CHECK: {{.*}}:104:70: note: expanded from macro 'variadic_pasting_args2a'
+ // CHECK-NEXT: #define variadic_pasting_args2a(x, y, ...) variadic_pasting_args1(x, y ## __VA_ARGS__)
+ // CHECK-NEXT: {{ \^~~~~~~~~~~~~~~~}}
+ // CHECK: {{.*}}:102:41: note: expanded from macro 'variadic_pasting_args1'
+ // CHECK-NEXT: #define variadic_pasting_args1(x, y, z) y
+ // CHECK-NEXT: {{ \^}}
}
#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: {{.*}}:130: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: {{.*}}:130: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: {{.*}}:130:39: note: expanded from macro 'BAD_CONDITIONAL_OPERATOR'
// CHECK-NEXT: #define BAD_CONDITIONAL_OPERATOR (2<3)?2:3
// CHECK-NEXT: {{^ ~~~~~\^~~~}}
@@ -135,31 +143,85 @@ int test4 = BAD_CONDITIONAL_OPERATOR+BAD_CONDITIONAL_OPERATOR;
#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: {{.*}}:145: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: {{.*}}:144: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: {{.*}}:142: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: {{.*}}:145: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: {{.*}}:144: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: {{.*}}:164: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: {{.*}}:163: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: {{.*}}:142:15: note: expanded from macro 'QMARK'
// CHECK-NEXT: #define QMARK ?
// CHECK-NEXT: {{^ \^}}
+
+// PR14399
+void iequals(int,int,int);
+void foo_aa(char* s)
+{
+#define /* */ BARC(c, /* */b, a) (a + b ? c : c)
+ iequals(__LINE__, BARC(123, (456 < 345), 789), 8);
+}
+// CHECK: {{.*}}:180:21: warning: operator '?:' has lower precedence than '+'
+// CHECK-NEXT: iequals(__LINE__, BARC(123, (456 < 345), 789), 8);
+// CHECK-NEXT: {{^ \^~~~~~~~~~~~~~~~~~~~~~~~~~~}}
+// CHECK-NEXT: {{.*}}:179:41: note: expanded from macro 'BARC'
+// CHECK-NEXT: #define /* */ BARC(c, /* */b, a) (a + b ? c : c)
+// CHECK-NEXT: {{^ ~~~~~ \^}}
+
+#define APPEND2(NUM, SUFF) -1 != NUM ## SUFF
+#define APPEND(NUM, SUFF) APPEND2(NUM, SUFF)
+#define UTARG_MAX_U APPEND (MAX_UINT, UL)
+#define MAX_UINT 18446744073709551615
+#if UTARG_MAX_U
+#endif
+
+// CHECK: {{.*}}:193:5: warning: left side of operator converted from negative value to unsigned: -1 to 18446744073709551615
+// CHECK-NEXT: #if UTARG_MAX_U
+// CHECK-NEXT: {{^ \^~~~~~~~~~~}}
+// CHECK-NEXT: {{.*}}:191:21: note: expanded from macro 'UTARG_MAX_U'
+// CHECK-NEXT: #define UTARG_MAX_U APPEND (MAX_UINT, UL)
+// CHECK-NEXT: {{^ \^~~~~~~~~~~~~~~~~~~~~}}
+// CHECK-NEXT: {{.*}}:190:27: note: expanded from macro 'APPEND'
+// CHECK-NEXT: #define APPEND(NUM, SUFF) APPEND2(NUM, SUFF)
+// CHECK-NEXT: {{^ \^~~~~~~~~~~~~~~~~~}}
+// CHECK-NEXT: {{.*}}:189:31: note: expanded from macro 'APPEND2'
+// CHECK-NEXT: #define APPEND2(NUM, SUFF) -1 != NUM ## SUFF
+// CHECK-NEXT: {{^ ~~ \^ ~~~~~~~~~~~}}
+
+unsigned long strlen_test(const char *s);
+#define __darwin_obsz(object) __builtin_object_size (object, 1)
+#define sprintf2(str, ...) \
+ __builtin___sprintf_chk (str, 0, __darwin_obsz(str), __VA_ARGS__)
+#define Cstrlen(a) strlen_test(a)
+#define Csprintf sprintf2
+void f(char* pMsgBuf, char* pKeepBuf) {
+Csprintf(pMsgBuf,"\nEnter minimum anagram length (2-%1d): ", Cstrlen(pKeepBuf));
+}
+// CHECK: {{.*}}:216:62: warning: format specifies type 'int' but the argument has type 'unsigned long'
+// CHECK-NEXT: Csprintf(pMsgBuf,"\nEnter minimum anagram length (2-%1d): ", Cstrlen(pKeepBuf));
+// CHECK-NEXT: {{^ ~~~ \^}}
+// CHECK-NEXT: {{^ %1lu}}
+// CHECK-NEXT: {{.*}}:213:21: note: expanded from macro 'Cstrlen'
+// CHECK-NEXT: #define Cstrlen(a) strlen_test(a)
+// CHECK-NEXT: {{^ \^}}
+// CHECK-NEXT: {{.*}}:212:56: note: expanded from macro 'sprintf2'
+// CHECK-NEXT: __builtin___sprintf_chk (str, 0, __darwin_obsz(str), __VA_ARGS__)
+// CHECK-NEXT: {{^ \^}}
diff --git a/test/Misc/dev-fd-fs.c b/test/Misc/dev-fd-fs.c
new file mode 100644
index 0000000..2bc4f29
--- /dev/null
+++ b/test/Misc/dev-fd-fs.c
@@ -0,0 +1,32 @@
+// Check that we can operate on files from /dev/fd.
+// REQUIRES: dev-fd-fs
+
+// It has not been working since r169831 on freebsd.
+// XFAIL: freebsd
+
+// Check reading from named pipes. We cat the input here instead of redirecting
+// it to ensure that /dev/fd/0 is a named pipe, not just a redirected file.
+//
+// RUN: cat %s | %clang -x c /dev/fd/0 -E > %t
+// RUN: FileCheck --check-prefix DEV-FD-INPUT < %t %s
+//
+// DEV-FD-INPUT: int x;
+
+
+// Check writing to /dev/fd named pipes. We use cat here as before to ensure we
+// get a named pipe.
+//
+// RUN: %clang -x c %s -E -o /dev/fd/1 | cat > %t
+// RUN: FileCheck --check-prefix DEV-FD-FIFO-OUTPUT < %t %s
+//
+// DEV-FD-FIFO-OUTPUT: int x;
+
+
+// Check writing to /dev/fd regular files.
+//
+// RUN: %clang -x c %s -E -o /dev/fd/1 > %t
+// RUN: FileCheck --check-prefix DEV-FD-REG-OUTPUT < %t %s
+//
+// DEV-FD-REG-OUTPUT: int x;
+
+int x;
diff --git a/test/Misc/diag-line-wrapping.cpp b/test/Misc/diag-line-wrapping.cpp
index 830aa13..ea119af 100644
--- a/test/Misc/diag-line-wrapping.cpp
+++ b/test/Misc/diag-line-wrapping.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -fmessage-length 60 %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -fsyntax-only -fmessage-length 0 %s 2>&1 | FileCheck %s
struct B { void f(); };
struct D1 : B {};
@@ -10,4 +11,13 @@ struct DD : D1, D2 {
// CHECK: {{.*}}: error:
// CHECK: struct DD -> struct D1 -> struct B
// CHECK: struct DD -> struct D2 -> struct B
-}
+};
+
+// A line longer than 4096 characters should cause us to suppress snippets no
+// matter what -fmessage-length is set to.
+#pragma clang diagnostic push
+#pragma clang diagnostic warning "-Wconversion"
+// CHECK: implicit conversion loses floating-point precision
+// CHECK-NOT: static const float numbers[]
+static const float numbers[] = {0.1764705882352941,0.1176470588235294,0.1176470588235294,0.1176470588235294,0.1176470588235294,0.3529411764705883,0.2352941176470588,0.1176470588235294,0.1176470588235294,0.1176470588235294,0.1176470588235294,0.4117647058823529,0.1176470588235294,0.1176470588235294,0.1176470588235294,0.1176470588235294,0.1764705882352941,0.3529411764705883,0.1764705882352941,0.1176470588235294,0.1176470588235294,0.1176470588235294,0.1764705882352941,0.4117647058823529,0.2352941176470588,0.1176470588235294,0.1176470588235294,0.1176470588235294,0.1764705882352941,0.4705882352941176,0.1176470588235294,0.1176470588235294,0.1176470588235294,0.1176470588235294,0.2352941176470588,0.4117647058823529,0.1764705882352941,0.1176470588235294,0.1176470588235294,0.1176470588235294,0.2352941176470588,0.4705882352941176,0.2352941176470588,0.1176470588235294,0.1176470588235294,0.1176470588235294,0.2352941176470588,0.5294117647058824,0.1176470588235294,0.1176470588235294,0.1176470588235294,0.1176470588235294,0.2941176470588235,0.4705882352941176,0.1764705882352941,0.1176470588235294,0.1176470588235294,0.1176470588235294,0.2941176470588235,0.5294117647058824,0.1176470588235294,0.1176470588235294,0.1176470588235294,0.1176470588235294,0.3529411764705883,0.5294117647058824,0.4117647058823529,0.1176470588235294,0.1176470588235294,0.1764705882352941,0.1764705882352941,0.1176470588235294,0.1176470588235294,0.1176470588235294,0.1176470588235294,0.1764705882352941,0.1764705882352941,0.3529411764705883,0.1764705882352941,0.1176470588235294,0.1176470588235294,0.1764705882352941,0.1764705882352941,0.4117647058823529,0.4117647058823529,0.1176470588235294,0.1176470588235294,0.1764705882352941,0.2352941176470588,0.1764705882352941,0.1176470588235294,0.1176470588235294,0.1176470588235294,0.1764705882352941,0.2352941176470588,0.4117647058823529,0.1764705882352941,0.1176470588235294,0.1176470588235294,0.1764705882352941,0.2352941176470588,0.4705882352941176,0.4117647058823529,0.1176470588235294,0.1176470588235294,0.1764705882352941,0.2941176470588235,0.2352941176470588,0.1176470588235294,0.1176470588235294,0.1176470588235294,0.1764705882352941,0.2941176470588235,0.4705882352941176,0.1764705882352941,0.1176470588235294,0.1176470588235294,0.1764705882352941,0.2941176470588235,0.5294117647058824,0.4117647058823529,0.1176470588235294,0.1176470588235294,0.1764705882352941,0.3529411764705883,0.2941176470588235,0.1176470588235294,0.1176470588235294,0.1176470588235294,0.1764705882352941,0.3529411764705883,0.5294117647058824,0.3529411764705883,0.1176470588235294,0.1176470588235294,0.2352941176470588,0.2352941176470588,0.1176470588235294,0.4117647058823529,0.1176470588235294,0.1176470588235294,0.2352941176470588,0.2352941176470588,0.1764705882352941,0.1176470588235294,0.1176470588235294,0.1176470588235294,0.2352941176470588,0.2352941176470588,0.4117647058823529,0.3529411764705883,0.1176470588235294,0.1176470588235294,0.2352941176470588,0.2941176470588235,0.1764705882352941,0.4117647058823529,0.1176470588235294,0.1176470588235294,0.2352941176470588,0.2941176470588235,0.2352941176470588,0.1176470588235294,0.1176470588235294,0.1176470588235294,0.2352941176470588,0.2941176470588235,0.4705882352941176,0.3529411764705883,0.1176470588235294,0.1176470588235294,0.2352941176470588,0.3529411764705883,0.2352941176470588,0.1176470588235294,0.1176470588235294,0.1176470588235294,0.2352941176470588,0.3529411764705883,0.5294117647058824,0.3529411764705883,0.1176470588235294,0.1176470588235294,0.2352941176470588,0.4117647058823529,0.2941176470588235,0.2941176470588235,0.1176470588235294,0.1176470588235294,0.2941176470588235,0.2941176470588235,0.1176470588235294,0.3529411764705883,0.1176470588235294,0.1176470588235294,0.2941176470588235,0.2941176470588235,0.1764705882352941,0.2941176470588235,0.1176470588235294,0.1176470588235294,0.2941176470588235,0.3529411764705883,0.1764705882352941,0.3529411764705883,0.1176470588235294,0.1176470588235294,0.2941176470588235,0.3529411764705883,0.2352941176470588,0.2941176470588235,0.1176470588235294,0.1176470588235294,0.2941176470588235,0.4117647058823529,0.2352941176470588,0.2941176470588235,0.1176470588235294,0.1176470588235294,0.2941176470588235,0.4705882352941176,0.2941176470588235,0.2352941176470588,0.1176470588235294,0.1176470588235294,0.3529411764705883,0.3529411764705883,0.1176470588235294,0.2941176470588235,0.1176470588235294,0.1176470588235294,0.3529411764705883,0.3529411764705883,0.1764705882352941,0.2352941176470588,0.1176470588235294,0.1176470588235294,0.3529411764705883,0.4117647058823529,0.1764705882352941,0.2941176470588235,0.1176470588235294,0.1176470588235294,0.3529411764705883,0.4117647058823529,0.2352941176470588,0.2352941176470588,0.1176470588235294,0.1176470588235294,0.3529411764705883,0.4705882352941176,0.2352941176470588,0.2352941176470588,0.1176470588235294,0.1176470588235294,0.3529411764705883,0.5294117647058824,0.2941176470588235,0.1764705882352941,0.1176470588235294,0.1176470588235294,0.4117647058823529};
+#pragma clang diagnostic pop
diff --git a/test/Misc/diag-macro-backtrace.c b/test/Misc/diag-macro-backtrace.c
index ea40cbe..0d28d7b 100644
--- a/test/Misc/diag-macro-backtrace.c
+++ b/test/Misc/diag-macro-backtrace.c
@@ -12,7 +12,7 @@
#define DROOL WAZ
#define FOOL DROOL
-FOOL
+FOOL;
// CHECK: :15:1: error: expected identifier or '('
// CHECK: FOOL
@@ -50,4 +50,17 @@ FOOL
// CHECK: :3:13: note: expanded from macro 'FOO'
// CHECK: #define FOO 1+"hi"
// CHECK: ^
-// CHECK: 1 error generated.
+
+#define ADD(a, b) a ## #b
+ADD(L, foo)
+// CHECK: error: expected identifier or '('
+// CHECK: ADD(L, foo)
+// CHECK: {{^\^}}
+// CHECK: note: expanded from macro 'ADD'
+// CHECK: #define ADD(a, b) a ## #b
+// CHECK: {{^ \^}}
+// CHECK: note: expanded from here
+// CHECK: L"foo"
+// CHECK: {{^\^}}
+
+// CHECK: 2 errors generated.
diff --git a/test/Misc/diag-presumed.c b/test/Misc/diag-presumed.c
new file mode 100644
index 0000000..07b7cdf
--- /dev/null
+++ b/test/Misc/diag-presumed.c
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -fsyntax-only -pedantic-errors %s 2>&1 | FileCheck %s --check-prefix=PRESUMED
+// RUN: %clang_cc1 -fsyntax-only -pedantic-errors -fno-diagnostics-use-presumed-location %s 2>&1 | FileCheck %s --check-prefix=SPELLING
+
+#line 100
+#define X(y) y
+X(int n = error);
+
+// PRESUMED: diag-presumed.c:101:11: error: use of undeclared identifier 'error'
+// PRESUMED: diag-presumed.c:100:14: note: expanded from
+// SPELLING: diag-presumed.c:6:11: error: use of undeclared identifier 'error'
+// SPELLING: diag-presumed.c:5:14: note: expanded from
+
+;
+// PRESUMED: diag-presumed.c:108:1: error: extra ';' outside of a functio
+// SPELLING: diag-presumed.c:13:1: error: extra ';' outside of a functio
+
+# 1 "thing1.cc" 1
+# 1 "thing1.h" 1
+# 1 "systemheader.h" 1 3
+;
+// No diagnostic here: we're in a system header, even if we're using spelling
+// locations for the diagnostics..
+// PRESUMED-NOT: extra ';'
+// SPELLING-NOT: extra ';'
+
+another error;
+// PRESUMED: included from {{.*}}diag-presumed.c:112:
+// PRESUMED: from thing1.cc:1:
+// PRESUMED: from thing1.h:1:
+// PRESUMED: systemheader.h:7:1: error: unknown type name 'another'
+
+// SPELLING-NOT: included from
+// SPELLING: diag-presumed.c:26:1: error: unknown type name 'another'
+
+# 1 "thing1.h" 2
+# 1 "thing1.cc" 2
diff --git a/test/Misc/diag-template-diffing-color.cpp b/test/Misc/diag-template-diffing-color.cpp
index cfa1a68..c771857 100644
--- a/test/Misc/diag-template-diffing-color.cpp
+++ b/test/Misc/diag-template-diffing-color.cpp
@@ -6,17 +6,17 @@ void func(foo<int>);
int main() {
func(foo<double>());
}
-// CHECK: {{.*}}candidate function not viable: no known conversion from 'foo<{{.}}[0;1;36mdouble{{.}}[0m>' to 'foo<{{.}}[0;1;36mint{{.}}[0m>' for 1st argument{{.}}[0m
+// CHECK: {{.*}}candidate function not viable: no known conversion from 'foo<[[CYAN:.\[0;1;36m]]double[[RESET:.\[0m]]>' to 'foo<[[CYAN]]int[[RESET]]>' for 1st argument[[RESET]]
// TREE: candidate function not viable: no known conversion from argument type to parameter type for 1st argument
// TREE: foo<
-// TREE: [{{.}}[0;1;36mdouble{{.}}[0m != {{.}}[0;1;36mint{{.}}[0m]>{{.}}[0m
+// TREE: {{\[}}[[CYAN:.\[0;1;36m]]double[[RESET:.\[0m]] != [[CYAN]]int[[RESET]]]>[[RESET]]
foo<int> A;
foo<double> &B = A;
-// CHECK: {{.*}}non-const lvalue reference to type 'foo<{{.}}[0;1;36mdouble{{.}}[0m{{.}}[1m>' cannot bind to a value of unrelated type 'foo<{{.}}[0;1;36mint{{.}}[0m{{.}}[1m>'{{.}}[0m
+// CHECK: {{.*}}non-const lvalue reference to type 'foo<[[CYAN]]double[[RESET]][[BOLD:.\[1m]]>' cannot bind to a value of unrelated type 'foo<[[CYAN]]int[[RESET]][[BOLD]]>'[[RESET]]
// 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
+// TREE: {{\[}}[[CYAN]]double[[RESET]][[BOLD:.\[1m]] != [[CYAN]]int[[RESET]][[BOLD]]]>[[RESET]]
template<typename> class vector {};
@@ -24,49 +24,63 @@ void set15(vector<const vector<int> >) {}
void test15() {
set15(vector<const vector<const int> >());
}
-// CHECK: {{.*}}candidate function not viable: no known conversion from 'vector<const vector<{{.}}[0;1;36mconst{{ ?.}}[0m{{ ?}}int>>' to 'vector<const vector<int>>' for 1st argument
+// CHECK: {{.*}}candidate function not viable: no known conversion from 'vector<const vector<[[CYAN]]const{{ ?}}[[RESET]]{{ ?}}int>>' to 'vector<const vector<int>>' for 1st argument
// TREE: {{.*}}candidate function not viable: no known conversion from argument type to parameter type for 1st argument
// TREE: vector<
// TREE: const vector<
-// TREE: [{{.}}[0;1;36mconst{{ ?.}}[0m{{ ?}}!= {{.}}[0;1;36m(no qualifiers){{.}}[0m] int>>
+// TREE: {{\[}}[[CYAN]]const{{ ?}}[[RESET]]{{ ?}}!= [[CYAN]](no qualifiers)[[RESET]]] int>>
void set16(vector<vector<int> >) {}
void test16() {
set16(vector<const vector<int> >());
}
-// CHECK: {{.*}}candidate function not viable: no known conversion from 'vector<{{.}}[0;1;36mconst{{ ?.}}[0m{{ ?}}vector<[...]>>' to 'vector<vector<[...]>>' for 1st argument
+// CHECK: {{.*}}candidate function not viable: no known conversion from 'vector<[[CYAN]]const{{ ?}}[[RESET]]{{ ?}}vector<[...]>>' to 'vector<vector<[...]>>' for 1st argument
// TREE: {{.*}}candidate function not viable: no known conversion from argument type to parameter type for 1st argument
// TREE: vector<
-// TREE: [{{.}}[0;1;36mconst{{ ?.}}[0m{{ ?}}!= {{.}}[0;1;36m(no qualifiers){{ ?.}}[0m]{{ ?}}vector<
+// TREE: {{\[}}[[CYAN]]const{{ ?}}[[RESET]]{{ ?}}!= [[CYAN]](no qualifiers){{ ?}}[[RESET]]]{{ ?}}vector<
// TREE: [...]>>
void set17(vector<const vector<int> >) {}
void test17() {
set17(vector<vector<int> >());
}
-// CHECK: candidate function not viable: no known conversion from 'vector<vector<[...]>>' to 'vector<{{.}}[0;1;36mconst{{ ?.}}[0m{{ ?}}vector<[...]>>' for 1st argument
+// CHECK: candidate function not viable: no known conversion from 'vector<vector<[...]>>' to 'vector<[[CYAN]]const{{ ?}}[[RESET]]{{ ?}}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: {{\[}}[[CYAN]](no qualifiers){{ ?}}[[RESET]]{{ ?}}!= [[CYAN]]const[[RESET]]] vector<
// TREE: [...]>>
void set18(vector<volatile vector<int> >) {}
void test18() {
set18(vector<const vector<int> >());
}
-// CHECK: candidate function not viable: no known conversion from 'vector<{{.}}[0;1;36mconst{{ ?.}}[0m{{ ?}}vector<[...]>>' to 'vector<{{.}}[0;1;36mvolatile{{ ?.}}[0m{{ ?}}vector<[...]>>' for 1st argument
+// CHECK: candidate function not viable: no known conversion from 'vector<[[CYAN]]const{{ ?}}[[RESET]]{{ ?}}vector<[...]>>' to 'vector<[[CYAN]]volatile{{ ?}}[[RESET]]{{ ?}}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: {{\[}}[[CYAN]]const{{ ?}}[[RESET]]{{ ?}}!= [[CYAN]]volatile[[RESET]]] vector<
// TREE: [...]>>
void set19(vector<const volatile vector<int> >) {}
void test19() {
set19(vector<const vector<int> >());
}
-// CHECK: candidate function not viable: no known conversion from 'vector<const vector<[...]>>' to 'vector<const {{.}}[0;1;36mvolatile{{ ?.}}[0m{{ ?}}vector<[...]>>' for 1st argument
+// CHECK: candidate function not viable: no known conversion from 'vector<const vector<[...]>>' to 'vector<const [[CYAN]]volatile{{ ?}}[[RESET]]{{ ?}}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: [const != const [[CYAN]]volatile[[RESET]]] vector<
// TREE: [...]>>
+
+namespace default_args {
+ template <int x, int y = 1+1, int z = 2>
+ class A {};
+
+ void foo(A<0> &M) {
+ // CHECK: no viable conversion from 'A<[...], (default) [[CYAN]]1 + 1[[RESET]][[BOLD]] aka [[CYAN]]2[[RESET]][[BOLD]], (default) [[CYAN]]2[[RESET]][[BOLD]]>' to 'A<[...], [[CYAN]]0[[RESET]][[BOLD]], [[CYAN]]0[[RESET]][[BOLD]]>'
+ A<0, 0, 0> N = M;
+
+ // CHECK: no viable conversion from 'A<[2 * ...], (default) [[CYAN]]2[[RESET]][[BOLD]]>' to 'A<[2 * ...], [[CYAN]]0[[RESET]][[BOLD]]>'
+ A<0, 2, 0> N2 = M;
+ }
+
+}
diff --git a/test/Misc/diag-template-diffing-cxx98.cpp b/test/Misc/diag-template-diffing-cxx98.cpp
new file mode 100644
index 0000000..a21e4cf
--- /dev/null
+++ b/test/Misc/diag-template-diffing-cxx98.cpp
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -fsyntax-only %s -std=c++98 2>&1 | FileCheck %s
+
+namespace PR14342 {
+ template<typename T, char a> struct X {};
+ X<int, 1> x = X<long, 257>();
+ // CHECK: error: no viable conversion from 'X<long, [...]>' to 'X<int, [...]>'
+}
+
+namespace PR15513 {
+ template <int x, int y = x+1>
+ class A {};
+
+ void foo(A<0> &M) {
+ // CHECK: no viable conversion from 'A<[...], (default) x + 1 aka 1>' to 'A<[...], 0>'
+ A<0, 0> N = M;
+ // CHECK: no viable conversion from 'A<0, [...]>' to 'A<1, [...]>'
+ A<1, 1> O = M;
+ }
+}
+
+namespace default_args {
+ template <int x, int y = 1+1, int z = 2>
+ class A {};
+
+ void foo(A<0> &M) {
+ // CHECK: no viable conversion from 'A<[...], (default) 1 + 1 aka 2, (default) 2>' to 'A<[...], 0, 0>'
+ A<0, 0, 0> N = M;
+
+ // CHECK: no viable conversion from 'A<[2 * ...], (default) 2>' to 'A<[2 * ...], 0>'
+ A<0, 2, 0> N2 = M;
+ }
+
+}
+
+namespace qualifiers {
+ template <class T>
+ void foo(void (func(T*)), T*) {}
+
+ template <class T>
+ class vector{};
+
+ void bar(const vector<int>*) {}
+
+ void test(volatile vector<int>* V) {
+ foo(bar, V);
+ }
+
+ // CHECK: candidate template ignored: deduced conflicting types for parameter 'T' ('const vector<[...]>' vs. 'volatile vector<[...]>')
+}
diff --git a/test/Misc/diag-template-diffing.cpp b/test/Misc/diag-template-diffing.cpp
index 2c044f8..add96ef 100644
--- a/test/Misc/diag-template-diffing.cpp
+++ b/test/Misc/diag-template-diffing.cpp
@@ -645,41 +645,41 @@ void Play1() {
}
// 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 copy assignment operator) not viable: no known conversion from 'Foo1<1>' to 'const 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 copy assignment operator) not viable: no known conversion from 'Foo1<2>' to 'const 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 copy assignment operator) not viable: no known conversion from 'Foo1<1>' to 'const 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 copy assignment operator) not viable: no known conversion from 'Foo1<2>' to 'const 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: [(no qualifiers) != const] 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: [(no qualifiers) != const] 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: [(no qualifiers) != const] 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: [(no qualifiers) != const] 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<
@@ -694,41 +694,41 @@ void Play2() {
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 copy assignment operator) not viable: no known conversion from 'Foo2<1>' to 'const 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 copy assignment operator) not viable: no known conversion from 'Foo2<(default) 2>' to 'const 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 copy assignment operator) not viable: no known conversion from 'Foo2<1>' to 'const 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 copy assignment operator) not viable: no known conversion from 'Foo2<(default) 2>' to 'const 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: [(no qualifiers) != const] 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: [(no qualifiers) != const] 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: [(no qualifiers) != const] 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: [(no qualifiers) != const] 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<
@@ -743,20 +743,20 @@ void Play3() {
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 copy assignment operator) not viable: no known conversion from 'Foo3<1, (no argument)>' to 'const 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 copy assignment operator) not viable: no known conversion from 'Foo3<2, 1>' to 'const 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 copy assignment operator) not viable: no known conversion from 'Foo3<1, (no argument)>' to 'const 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 copy assignment operator) not viable: no known conversion from 'Foo3<2, 1>' to 'const 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: [(no qualifiers) != const] 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
@@ -765,7 +765,7 @@ void Play3() {
// 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: [(no qualifiers) != const] 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
@@ -774,7 +774,7 @@ void Play3() {
// 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: [(no qualifiers) != const] 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
@@ -783,7 +783,7 @@ void Play3() {
// 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: [(no qualifiers) != const] 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
@@ -792,8 +792,218 @@ void Play3() {
// CHECK-NOELIDE-TREE: [1 != (no argument)]>
}
+namespace PR14342 {
+ template<typename T, short a> struct X {};
+ X<int, (signed char)-1> x = X<long, -1>();
+ X<int, 3UL> y = X<int, 2>();
+ // CHECK-ELIDE-NOTREE: error: no viable conversion from 'X<long, [...]>' to 'X<int, [...]>'
+ // CHECK-ELIDE-NOTREE: error: no viable conversion from 'X<[...], 2>' to 'X<[...], 3>'
+}
+
+namespace PR14489 {
+ // The important thing here is that the diagnostic diffs a template specialization
+ // with no arguments against itself. (We might need a different test if this
+ // diagnostic changes).
+ template<class ...V>
+ struct VariableList {
+ void ConnectAllToAll(VariableList<>& params = VariableList<>()) {
+ }
+ };
+ // CHECK-ELIDE-NOTREE: non-const lvalue reference to type 'VariableList<>' cannot bind to a temporary of type 'VariableList<>'
+}
+
+namespace rdar12456626 {
+ struct IntWrapper {
+ typedef int type;
+ };
+
+ template<typename T, typename T::type V>
+ struct X { };
+
+ struct A {
+ virtual X<IntWrapper, 1> foo();
+ };
+
+ struct B : A {
+ // CHECK-ELIDE-NOTREE: virtual function 'foo' has a different return type
+ virtual X<IntWrapper, 2> foo();
+ };
+}
+
+namespace PR15023 {
+ // Don't crash when non-QualTypes are passed to a diff modifier.
+ template <typename... Args>
+ void func(void (*func)(Args...), Args...) { }
+
+ void bar(int, int &) {
+ }
+
+ void foo(int x) {
+ func(bar, 1, x)
+ }
+ // CHECK-ELIDE-NOTREE: no matching function for call to 'func'
+ // CHECK-ELIDE-NOTREE: candidate template ignored: deduced conflicting types for parameter 'Args' (<int, int &> vs. <int, int>)
+}
+
+namespace rdar12931988 {
+ namespace A {
+ template<typename T> struct X { };
+ }
+
+ namespace B {
+ template<typename T> struct X { };
+ }
+
+ void foo(A::X<int> &ax, B::X<int> bx) {
+ // CHECK-ELIDE-NOTREE: no viable overloaded '='
+ // CHECK-ELIDE-NOTREE: no known conversion from 'B::X<int>' to 'const rdar12931988::A::X<int>'
+ ax = bx;
+ }
+
+ template<template<typename> class> class Y {};
+
+ void bar(Y<A::X> ya, Y<B::X> yb) {
+ // CHECK-ELIDE-NOTREE: no viable overloaded '='
+ // CHECK-ELIDE-NOTREE: no known conversion from 'Y<template rdar12931988::B::X>' to 'Y<template rdar12931988::A::X>'
+ ya = yb;
+ }
+}
+
+namespace ValueDecl {
+ int int1, int2, default_int;
+ template <const int& T = default_int>
+ struct S {};
+
+ typedef S<int1> T1;
+ typedef S<int2> T2;
+ typedef S<> TD;
+
+ void test() {
+ T1 t1;
+ T2 t2;
+ TD td;
+
+ t1 = t2;
+ // CHECK-ELIDE-NOTREE: no viable overloaded '='
+ // CHECK-ELIDE-NOTREE: no known conversion from 'S<int2>' to 'S<int1>'
+
+ t2 = t1;
+ // CHECK-ELIDE-NOTREE: no viable overloaded '='
+ // CHECK-ELIDE-NOTREE: no known conversion from 'S<int1>' to 'S<int2>'
+
+ td = t1;
+ // TODO: Find out why (default) isn't printed on second template.
+ // CHECK-ELIDE-NOTREE: no viable overloaded '='
+ // CHECK-ELIDE-NOTREE: no known conversion from 'S<int1>' to 'S<default_int>'
+
+ t2 = td;
+ // CHECK-ELIDE-NOTREE: no viable overloaded '='
+ // CHECK-ELIDE-NOTREE: no known conversion from 'S<(default) default_int>' to 'S<int2>'
+
+ }
+}
+
+namespace DependentDefault {
+ template <typename> struct Trait {
+ enum { V = 40 };
+ typedef int Ty;
+ static int I;
+ };
+ int other;
+
+ template <typename T, int = Trait<T>::V > struct A {};
+ template <typename T, typename = Trait<T>::Ty > struct B {};
+ template <typename T, int& = Trait<T>::I > struct C {};
+
+ void test() {
+
+ A<int> a1;
+ A<char> a2;
+ A<int, 10> a3;
+ a1 = a2;
+ // CHECK-ELIDE-NOTREE: no viable overloaded '='
+ // CHECK-ELIDE-NOTREE: no known conversion from 'A<char, [...]>' to 'A<int, [...]>'
+ a3 = a1;
+ // CHECK-ELIDE-NOTREE: no viable overloaded '='
+ // CHECK-ELIDE-NOTREE: no known conversion from 'A<[...], (default) 40>' to 'A<[...], 10>'
+ a2 = a3;
+ // CHECK-ELIDE-NOTREE: no viable overloaded '='
+ // CHECK-ELIDE-NOTREE: no known conversion from 'A<int, 10>' to 'A<char, 40>'
+
+ B<int> b1;
+ B<char> b2;
+ B<int, char> b3;
+ b1 = b2;
+ // CHECK-ELIDE-NOTREE: no viable overloaded '='
+ // CHECK-ELIDE-NOTREE: no known conversion from 'B<char, (default) Trait<T>::Ty>' to 'B<int, int>'
+ b3 = b1;
+ // CHECK-ELIDE-NOTREE: no viable overloaded '='
+ // CHECK-ELIDE-NOTREE: no known conversion from 'B<[...], (default) Trait<T>::Ty>' to 'B<[...], char>'
+ b2 = b3;
+ // CHECK-ELIDE-NOTREE: no viable overloaded '='
+ // CHECK-ELIDE-NOTREE: no known conversion from 'B<int, char>' to 'B<char, int>'
+
+ C<int> c1;
+ C<char> c2;
+ C<int, other> c3;
+ c1 = c2;
+ // CHECK-ELIDE-NOTREE: no viable overloaded '='
+ // CHECK-ELIDE-NOTREE: no known conversion from 'C<char, (default) I>' to 'C<int, I>'
+ c3 = c1;
+ // CHECK-ELIDE-NOTREE: no viable overloaded '='
+ // CHECK-ELIDE-NOTREE: no known conversion from 'C<[...], (default) I>' to 'C<[...], other>'
+ c2 = c3;
+ // CHECK-ELIDE-NOTREE: no viable overloaded '='
+ // CHECK-ELIDE-NOTREE: no known conversion from 'C<int, other>' to 'C<char, I>'
+ }
+}
+
+namespace VariadicDefault {
+ int i1, i2, i3;
+ template <int = 5, int...> struct A {};
+ template <int& = i1, int& ...> struct B {};
+ template <typename = void, typename...> struct C {};
+
+ void test() {
+ A<> a1;
+ A<5, 6, 7> a2;
+ A<1, 2> a3;
+ a2 = a1;
+ // CHECK-ELIDE-NOTREE: no viable overloaded '='
+ // CHECK-ELIDE-NOTREE: no known conversion from 'A<[...], (no argument), (no argument)>' to 'A<[...], 6, 7>'
+ a3 = a1;
+ // CHECK-ELIDE-NOTREE: no viable overloaded '='
+ // CHECK-ELIDE-NOTREE: no known conversion from 'A<(default) 5, (no argument)>' to 'A<1, 2>'
+
+ B<> b1;
+ B<i1, i2, i3> b2;
+ B<i2, i3> b3;
+ b2 = b1;
+ // CHECK-ELIDE-NOTREE: no viable overloaded '='
+ // CHECK-ELIDE-NOTREE: no known conversion from 'B<[...], (no argument), (no argument)>' to 'B<[...], i2, i3>'
+ b3 = b1;
+ // CHECK-ELIDE-NOTREE: no viable overloaded '='
+ // CHECK-ELIDE-NOTREE: no known conversion from 'B<(default) i1, (no argument)>' to 'B<i2, i3>'
+
+ B<i1, i2, i3> b4 = b1;
+ // CHECK-ELIDE-NOTREE: no viable conversion from 'B<[...], (no argument), (no argument)>' to 'B<[...], i2, i3>'
+ B<i2, i3> b5 = b1;
+ // CHECK-ELIDE-NOTREE: no viable conversion from 'B<(default) i1, (no argument)>' to 'B<i2, i3>'
+
+ C<> c1;
+ C<void, void> c2;
+ C<char, char> c3;
+ c2 = c1;
+ // CHECK-ELIDE-NOTREE: no viable overloaded '='
+ // CHECK-ELIDE-NOTREE: no known conversion from 'C<[...], (no argument)>' to 'C<[...], void>'
+ c3 = c1;
+ // CHECK-ELIDE-NOTREE: no viable overloaded '='
+ // CHECK-ELIDE-NOTREE: no known conversion from 'C<(default) void, (no argument)>' to 'C<char, char>'
+ }
+}
// CHECK-ELIDE-NOTREE: {{[0-9]*}} errors generated.
// CHECK-NOELIDE-NOTREE: {{[0-9]*}} errors generated.
// CHECK-ELIDE-TREE: {{[0-9]*}} errors generated.
// CHECK-NOELIDE-TREE: {{[0-9]*}} errors generated.
+
diff --git a/test/Misc/diagnostic-crash.cpp b/test/Misc/diagnostic-crash.cpp
new file mode 100644
index 0000000..cbb9ac6
--- /dev/null
+++ b/test/Misc/diagnostic-crash.cpp
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -verify -fsyntax-only %s
+// The diagnostics we produce for this code tickled a bug in raw_ostream.
+template <typename _Alloc> class allocator;
+template <class _CharT> struct char_traits;
+template <typename _CharT, typename _Traits = char_traits<_CharT>,
+ typename _Alloc = allocator<_CharT> >
+class basic_string;
+typedef basic_string<wchar_t> wstring;
+class Closure {
+};
+template <class A1> class Callback1 {
+};
+template <class A1, class A2> class Callback2 {
+};
+template <class R, class A2> class ResultCallback1 {
+};
+template <bool del, class R, class T, class P1, class P2, class A1>
+class AAAAAAAResultCallback_2_1 : public ResultCallback1<R, A1> {
+};
+template <bool del, class T, class P1, class P2, class A1>
+class AAAAAAAResultCallback_2_1< del, void, T, P1, P2, A1> :
+ public Callback1<A1> {
+ public:
+ typedef Callback1<A1> base;
+};
+template <class T1, class T2, class R, class P1, class P2, class A1>
+inline typename AAAAAAAResultCallback_2_1<true, R, T1, P1, P2, A1>::base*
+NewCallback(T1* obj, R(T2::* member)(P1, P2, A1), const P1& p1, const P2& p2) {}
+namespace util { class Status {}; }
+class xxxxxxxxxxxxxxxxx {
+ void Bar(wstring* s, util::Status* status,
+ Callback2<util::Status, wstring>* done);
+ void Foo();
+};
+void xxxxxxxxxxxxxxxxx::Foo() {
+ wstring* s = __null;
+ util::Status* status = __null;
+ Closure* cb = NewCallback(this, &xxxxxxxxxxxxxxxxx::Bar, s, status); // expected-error{{cannot initialize}}
+}
diff --git a/test/Misc/freebsd-arm-size_t.c b/test/Misc/freebsd-arm-size_t.c
new file mode 100644
index 0000000..ba7bfec
--- /dev/null
+++ b/test/Misc/freebsd-arm-size_t.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -triple arm-unknown-freebsd10.0 -verify %s
+// expected-no-diagnostics
+
+/* Define a size_t as expected for FreeBSD ARM */
+typedef unsigned int size_t;
+
+/* Declare a builtin function that uses size_t */
+void *malloc(size_t);
+
diff --git a/test/Misc/integer-literal-printing.cpp b/test/Misc/integer-literal-printing.cpp
index 4085d60..74bd8d0 100644
--- a/test/Misc/integer-literal-printing.cpp
+++ b/test/Misc/integer-literal-printing.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify
+// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c++11
// PR11179
template <short T> class Type1 {};
@@ -7,7 +7,73 @@ template <short T> void Function1(Type1<T>& x) {} // expected-note{{candidate fu
template <unsigned short T> class Type2 {};
template <unsigned short T> void Function2(Type2<T>& x) {} // expected-note{{candidate function [with T = 42] not viable: expects an l-value for 1st argument}}
+enum class boolTy : bool {
+ b = 0,
+};
+
+template <boolTy T> struct Type3Helper;
+template <> struct Type3Helper<boolTy::b> { typedef boolTy Ty; };
+template <boolTy T, typename Type3Helper<T>::Ty U> struct Type3 {};
+
+// PR14386
+enum class charTy : char {
+ c = 0,
+};
+
+template <charTy T> struct Type4Helper;
+template <> struct Type4Helper<charTy::c> { typedef charTy Ty; };
+template <charTy T, typename Type4Helper<T>::Ty U> struct Type4 {};
+
+enum class scharTy : signed char {
+ c = 0,
+};
+
+template <scharTy T> struct Type5Helper;
+template <> struct Type5Helper<scharTy::c> { typedef scharTy Ty; };
+template <scharTy T, typename Type5Helper<T>::Ty U> struct Type5 {};
+
+enum class ucharTy : unsigned char {
+ c = 0,
+};
+
+template <ucharTy T> struct Type6Helper;
+template <> struct Type6Helper<ucharTy::c> { typedef ucharTy Ty; };
+template <ucharTy T, typename Type6Helper<T>::Ty U> struct Type6 {};
+
+enum class wcharTy : wchar_t {
+ c = 0,
+};
+
+template <wcharTy T> struct Type7Helper;
+template <> struct Type7Helper<wcharTy::c> { typedef wcharTy Ty; };
+template <wcharTy T, typename Type7Helper<T>::Ty U> struct Type7 {};
+
+enum class char16Ty : char16_t {
+ c = 0,
+};
+
+template <char16Ty T> struct Type8Helper;
+template <> struct Type8Helper<char16Ty::c> { typedef char16Ty Ty; };
+template <char16Ty T, typename Type8Helper<T>::Ty U> struct Type8 {};
+
+enum class char32Ty : char16_t {
+ c = 0,
+};
+
+template <char32Ty T> struct Type9Helper;
+template <> struct Type9Helper<char32Ty::c> { typedef char32Ty Ty; };
+template <char32Ty T, typename Type9Helper<T>::Ty U> struct Type9 {};
+
void Function() {
Function1(Type1<-42>()); // expected-error{{no matching function for call to 'Function1'}}
Function2(Type2<42>()); // expected-error{{no matching function for call to 'Function2'}}
+
+ struct Type3<boolTy::b, "3"> t3; // expected-error{{value of type 'const char [2]' is not implicitly convertible to 'typename Type3Helper<(boolTy)false>::Ty' (aka 'boolTy')}}
+
+ struct Type4<charTy::c, "4"> t4; // expected-error{{value of type 'const char [2]' is not implicitly convertible to 'typename Type4Helper<(charTy)'\x00'>::Ty' (aka 'charTy')}}
+ struct Type5<scharTy::c, "5"> t5; // expected-error{{value of type 'const char [2]' is not implicitly convertible to 'typename Type5Helper<(scharTy)'\x00'>::Ty' (aka 'scharTy')}}
+ struct Type6<ucharTy::c, "6"> t6; // expected-error{{value of type 'const char [2]' is not implicitly convertible to 'typename Type6Helper<(ucharTy)'\x00'>::Ty' (aka 'ucharTy')}}
+ struct Type7<wcharTy::c, "7"> t7; // expected-error{{value of type 'const char [2]' is not implicitly convertible to 'typename Type7Helper<(wcharTy)L'\x00'>::Ty' (aka 'wcharTy')}}
+ struct Type8<char16Ty::c, "8"> t8; // expected-error{{value of type 'const char [2]' is not implicitly convertible to 'typename Type8Helper<(char16Ty)u'\x00'>::Ty' (aka 'char16Ty')}}
+ struct Type9<char32Ty::c, "9"> t9; // expected-error{{value of type 'const char [2]' is not implicitly convertible to 'typename Type9Helper<(char32Ty)u'\x00'>::Ty' (aka 'char32Ty')}}
}
diff --git a/test/Misc/serialized-diags-frontend.c b/test/Misc/serialized-diags-frontend.c
index 453ed14..7eab021 100644
--- a/test/Misc/serialized-diags-frontend.c
+++ b/test/Misc/serialized-diags-frontend.c
@@ -1,5 +1,5 @@
// RUN: rm -f %t
-// RUN: %clang -fsyntax-only %s -Wblahblah --serialize-diagnostics %t > /dev/null 2>&1 || true
+// RUN: %clang -fsyntax-only %s -Wblahblah --serialize-diagnostics %t > /dev/null 2>&1
// RUN: c-index-test -read-diagnostics %t 2>&1 | FileCheck %s
// This test case tests that we can handle frontend diagnostics.
diff --git a/test/Misc/serialized-diags-no-category.c b/test/Misc/serialized-diags-no-category.c
index 3074892..1b0f204 100644
--- a/test/Misc/serialized-diags-no-category.c
+++ b/test/Misc/serialized-diags-no-category.c
@@ -2,7 +2,7 @@
#error bar
// RUN: rm -f %t
-// RUN: %clang -ferror-limit=1 -fsyntax-only %s --serialize-diagnostics %t > /dev/null 2>&1 || true
+// RUN: not %clang -ferror-limit=1 -fsyntax-only %s --serialize-diagnostics %t > /dev/null 2>&1
// RUN: c-index-test -read-diagnostics %t 2>&1 | FileCheck %s
// This test case tests that we can handle both fatal errors and errors without categories.
diff --git a/test/Misc/serialized-diags.c b/test/Misc/serialized-diags.c
index ae4611b..1290b4e 100644
--- a/test/Misc/serialized-diags.c
+++ b/test/Misc/serialized-diags.c
@@ -31,7 +31,7 @@ void rdar11040133() {
}
// RUN: rm -f %t
-// RUN: %clang -Wall -fsyntax-only %s --serialize-diagnostics %t.diag > /dev/null 2>&1 || true
+// RUN: not %clang -Wall -fsyntax-only %s --serialize-diagnostics %t.diag > /dev/null 2>&1
// RUN: c-index-test -read-diagnostics %t.diag > %t 2>&1
// RUN: FileCheck --input-file=%t %s
diff --git a/test/Misc/serialized-diags.m b/test/Misc/serialized-diags.m
new file mode 100644
index 0000000..aac791e
--- /dev/null
+++ b/test/Misc/serialized-diags.m
@@ -0,0 +1,30 @@
+@interface Foo
+- (void) test;
+- (void) test2;
+@end
+
+@implementation Foo
+- (void) test {
+ [_self test2];
+}
+- (void) test2 {}
+@end
+
+// RUN: rm -f %t
+// RUN: not %clang -Wall -fsyntax-only %s --serialize-diagnostics %t.diag > /dev/null 2>&1
+// RUN: c-index-test -read-diagnostics %t.diag > %t 2>&1
+// RUN: FileCheck --input-file=%t %s
+
+// This test checks that serialized diagnostics handle notes with no source location.
+
+// CHECK: {{.*[/\\]}}serialized-diags.m:8:4: error: use of undeclared identifier '_self'; did you mean 'self'? [] [Semantic Issue]
+// CHECK: Range: {{.*[/\\]}}serialized-diags.m:8:4 {{.*[/\\]}}serialized-diags.m:8:9
+// CHECK: Number FIXITs = 1
+// CHECK: FIXIT: ({{.*[/\\]}}serialized-diags.m:8:4 - {{.*[/\\]}}serialized-diags.m:8:9): "self"
+// CHECK: +-(null):0:0: note: 'self' is an implicit parameter [] []
+// CHECK: Number FIXITs = 0
+// CHECK: {{.*[/\\]}}serialized-diags.m:1:12: warning: class 'Foo' defined without specifying a base class [-Wobjc-root-class] [Semantic Issue]
+// CHECK: Number FIXITs = 0
+// CHECK: +-{{.*[/\\]}}serialized-diags.m:1:15: note: add a super class to fix this problem [] [Semantic Issue]
+// CHECK: Number FIXITs = 0
+// CHECK: Number of diagnostics: 2
diff --git a/test/Misc/warning-flags.c b/test/Misc/warning-flags.c
index c3f14bc..a6dc8f1 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 (148):
+CHECK: Warnings without flags (143):
CHECK-NEXT: ext_delete_void_ptr_operand
CHECK-NEXT: ext_enum_friend
CHECK-NEXT: ext_expected_semi_decl_list
@@ -44,7 +44,6 @@ CHECK-NEXT: pp_out_of_date_dependency
CHECK-NEXT: pp_poisoning_existing_macro
CHECK-NEXT: pp_pragma_once_in_main_file
CHECK-NEXT: pp_pragma_sysheader_in_main_file
-CHECK-NEXT: pp_undef_builtin_macro
CHECK-NEXT: w_asm_qualifier_ignored
CHECK-NEXT: warn_accessor_property_type_mismatch
CHECK-NEXT: warn_anon_bitfield_width_exceeds_type_size
@@ -106,7 +105,6 @@ CHECK-NEXT: warn_not_compound_assign
CHECK-NEXT: warn_objc_property_copy_missing_on_block
CHECK-NEXT: warn_objc_protocol_qualifier_missing_id
CHECK-NEXT: warn_octal_escape_too_large
-CHECK-NEXT: warn_odr_tag_type_inconsistent
CHECK-NEXT: warn_on_superclass_use
CHECK-NEXT: warn_param_default_argument_redefinition
CHECK-NEXT: warn_partial_specs_not_deducible
@@ -144,14 +142,12 @@ CHECK-NEXT: warn_property_attribute
CHECK-NEXT: warn_property_getter_owning_mismatch
CHECK-NEXT: warn_property_types_are_incompatible
CHECK-NEXT: warn_readonly_property
-CHECK-NEXT: warn_redecl_library_builtin
CHECK-NEXT: warn_redeclaration_without_attribute_prev_attribute_ignored
CHECK-NEXT: warn_register_objc_catch_parm
CHECK-NEXT: warn_related_result_type_compatibility_class
CHECK-NEXT: warn_related_result_type_compatibility_protocol
CHECK-NEXT: warn_second_parameter_of_va_start_not_last_named_argument
CHECK-NEXT: warn_second_parameter_to_va_arg_never_compatible
-CHECK-NEXT: warn_standalone_specifier
CHECK-NEXT: warn_static_inline_explicit_inst_ignored
CHECK-NEXT: warn_static_non_static
CHECK-NEXT: warn_template_export_unsupported
@@ -162,7 +158,6 @@ CHECK-NEXT: warn_unavailable_fwdclass_message
CHECK-NEXT: warn_undef_interface
CHECK-NEXT: warn_undef_interface_suggest
CHECK-NEXT: warn_undef_protocolref
-CHECK-NEXT: warn_undefined_internal
CHECK-NEXT: warn_unknown_method_family
CHECK-NEXT: warn_use_out_of_scope_declaration
CHECK-NEXT: warn_weak_identifier_undeclared
diff --git a/test/Modules/Inputs/Conflicts/conflict_a.h b/test/Modules/Inputs/Conflicts/conflict_a.h
new file mode 100644
index 0000000..c16b5f5
--- /dev/null
+++ b/test/Modules/Inputs/Conflicts/conflict_a.h
@@ -0,0 +1 @@
+int conflict_a;
diff --git a/test/Modules/Inputs/Conflicts/conflict_b.h b/test/Modules/Inputs/Conflicts/conflict_b.h
new file mode 100644
index 0000000..4baf16f
--- /dev/null
+++ b/test/Modules/Inputs/Conflicts/conflict_b.h
@@ -0,0 +1 @@
+int conflict_b;
diff --git a/test/Modules/Inputs/Conflicts/module.map b/test/Modules/Inputs/Conflicts/module.map
new file mode 100644
index 0000000..e6aafac
--- /dev/null
+++ b/test/Modules/Inputs/Conflicts/module.map
@@ -0,0 +1,10 @@
+module Conflicts {
+ explicit module A {
+ header "conflict_a.h"
+ conflict B, "we just don't like B"
+ }
+
+ module B {
+ header "conflict_b.h"
+ }
+}
diff --git a/test/Modules/Inputs/DependsOnModule.framework/DependsOnModule b/test/Modules/Inputs/DependsOnModule.framework/DependsOnModule
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Modules/Inputs/DependsOnModule.framework/DependsOnModule
diff --git a/test/Modules/Inputs/HasSubModules.framework/Frameworks/Sub.framework/Headers/Sub.h b/test/Modules/Inputs/HasSubModules.framework/Frameworks/Sub.framework/Headers/Sub.h
new file mode 100644
index 0000000..8a7eb84
--- /dev/null
+++ b/test/Modules/Inputs/HasSubModules.framework/Frameworks/Sub.framework/Headers/Sub.h
@@ -0,0 +1 @@
+#include <Sub/Types.h>
diff --git a/test/Modules/Inputs/HasSubModules.framework/Frameworks/Sub.framework/Headers/Types.h b/test/Modules/Inputs/HasSubModules.framework/Frameworks/Sub.framework/Headers/Types.h
new file mode 100644
index 0000000..7285c5f
--- /dev/null
+++ b/test/Modules/Inputs/HasSubModules.framework/Frameworks/Sub.framework/Headers/Types.h
@@ -0,0 +1,4 @@
+struct FrameworkSubStruct {
+ const char * name;
+ unsigned version;
+};
diff --git a/test/Modules/Inputs/HasSubModules.framework/Frameworks/Sub.framework/PrivateHeaders/SubPriv.h b/test/Modules/Inputs/HasSubModules.framework/Frameworks/Sub.framework/PrivateHeaders/SubPriv.h
new file mode 100644
index 0000000..cda5199
--- /dev/null
+++ b/test/Modules/Inputs/HasSubModules.framework/Frameworks/Sub.framework/PrivateHeaders/SubPriv.h
@@ -0,0 +1,3 @@
+#include <Sub/Types.h>
+// This comment ensures that this file is not identical to
+// HasSubModules.framework/Frameworks/Sub.framework/Headers/Sub.h
diff --git a/test/Modules/Inputs/HasSubModules.framework/Headers/HasSubModules.h b/test/Modules/Inputs/HasSubModules.framework/Headers/HasSubModules.h
new file mode 100644
index 0000000..a1bdc46
--- /dev/null
+++ b/test/Modules/Inputs/HasSubModules.framework/Headers/HasSubModules.h
@@ -0,0 +1 @@
+#import <Sub/Sub.h>
diff --git a/test/Modules/Inputs/HasSubModules.framework/PrivateHeaders/HasSubModulesPriv.h b/test/Modules/Inputs/HasSubModules.framework/PrivateHeaders/HasSubModulesPriv.h
new file mode 100644
index 0000000..7b82058
--- /dev/null
+++ b/test/Modules/Inputs/HasSubModules.framework/PrivateHeaders/HasSubModulesPriv.h
@@ -0,0 +1,2 @@
+#import <Sub/SubPriv.h>
+
diff --git a/test/Modules/Inputs/MethodPoolA.h b/test/Modules/Inputs/MethodPoolA.h
index 6af24a9..ababb02 100644
--- a/test/Modules/Inputs/MethodPoolA.h
+++ b/test/Modules/Inputs/MethodPoolA.h
@@ -6,3 +6,9 @@
+ (int)method1;
- (int)method2:(int)param;
@end
+
+@interface B : A
+@end
+
+@interface C
+@end
diff --git a/test/Modules/Inputs/MethodPoolASub.h b/test/Modules/Inputs/MethodPoolASub.h
new file mode 100644
index 0000000..46fe0e1
--- /dev/null
+++ b/test/Modules/Inputs/MethodPoolASub.h
@@ -0,0 +1,6 @@
+@interface A (Sub)
+- (char)method3;
+- (char*)method4;
+- (void)method5:(C*)obj;
+@end
+
diff --git a/test/Modules/Inputs/MethodPoolASub2.h b/test/Modules/Inputs/MethodPoolASub2.h
new file mode 100644
index 0000000..cd0f785
--- /dev/null
+++ b/test/Modules/Inputs/MethodPoolASub2.h
@@ -0,0 +1,3 @@
+@interface A (Sub2)
+- (char*)method4;
+@end
diff --git a/test/Modules/Inputs/MethodPoolBSub.h b/test/Modules/Inputs/MethodPoolBSub.h
new file mode 100644
index 0000000..0a7899d
--- /dev/null
+++ b/test/Modules/Inputs/MethodPoolBSub.h
@@ -0,0 +1,4 @@
+@interface B (Sub)
+- (char *)method3;
+- (char*)method4;
+@end
diff --git a/test/Modules/Inputs/Modified/B.h b/test/Modules/Inputs/Modified/B.h
index d1c8bb5..52526b7 100644
--- a/test/Modules/Inputs/Modified/B.h
+++ b/test/Modules/Inputs/Modified/B.h
@@ -1,2 +1,3 @@
-#include "A.h"
+@import ModA;
+
int getB();
diff --git a/test/Modules/Inputs/Modified/module.map b/test/Modules/Inputs/Modified/module.map
index d9aed01..27b0d70 100644
--- a/test/Modules/Inputs/Modified/module.map
+++ b/test/Modules/Inputs/Modified/module.map
@@ -1,2 +1,5 @@
-module A { header "A.h" }
-module B { header "B.h" }
+module ModA { header "A.h" }
+module ModB {
+ header "B.h"
+ export *
+}
diff --git a/test/Modules/Inputs/Module.framework/Module b/test/Modules/Inputs/Module.framework/Module
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Modules/Inputs/Module.framework/Module
diff --git a/test/Modules/Inputs/MutuallyRecursive1.framework/Headers/MutuallyRecursive1.h b/test/Modules/Inputs/MutuallyRecursive1.framework/Headers/MutuallyRecursive1.h
index 5142f56..156c226 100644
--- a/test/Modules/Inputs/MutuallyRecursive1.framework/Headers/MutuallyRecursive1.h
+++ b/test/Modules/Inputs/MutuallyRecursive1.framework/Headers/MutuallyRecursive1.h
@@ -1,3 +1,3 @@
-@__experimental_modules_import MutuallyRecursive2;
+@import MutuallyRecursive2;
diff --git a/test/Modules/Inputs/MutuallyRecursive2.framework/Headers/MutuallyRecursive2.h b/test/Modules/Inputs/MutuallyRecursive2.framework/Headers/MutuallyRecursive2.h
index 8a3cc33..be3facd 100644
--- a/test/Modules/Inputs/MutuallyRecursive2.framework/Headers/MutuallyRecursive2.h
+++ b/test/Modules/Inputs/MutuallyRecursive2.framework/Headers/MutuallyRecursive2.h
@@ -1,6 +1,6 @@
-@__experimental_modules_import MutuallyRecursive1;
+@import MutuallyRecursive1;
diff --git a/test/Modules/Inputs/NoUmbrella.framework/NoUmbrella b/test/Modules/Inputs/NoUmbrella.framework/NoUmbrella
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/Modules/Inputs/NoUmbrella.framework/NoUmbrella
diff --git a/test/Modules/Inputs/StdDef/module.map b/test/Modules/Inputs/StdDef/module.map
new file mode 100644
index 0000000..69c69ea
--- /dev/null
+++ b/test/Modules/Inputs/StdDef/module.map
@@ -0,0 +1,11 @@
+module StdDef {
+ module SizeT {
+ header "size_t.h"
+ export *
+ }
+
+ module Other {
+ header "other.h"
+ export *
+ }
+}
diff --git a/test/Modules/Inputs/StdDef/other.h b/test/Modules/Inputs/StdDef/other.h
new file mode 100644
index 0000000..f29f636
--- /dev/null
+++ b/test/Modules/Inputs/StdDef/other.h
@@ -0,0 +1,2 @@
+#include <stddef.h>
+
diff --git a/test/Modules/Inputs/StdDef/size_t.h b/test/Modules/Inputs/StdDef/size_t.h
new file mode 100644
index 0000000..9ac61c5
--- /dev/null
+++ b/test/Modules/Inputs/StdDef/size_t.h
@@ -0,0 +1,4 @@
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef __SIZE_TYPE__ size_t;
+#endif
diff --git a/test/Modules/Inputs/autolink-sub.h b/test/Modules/Inputs/autolink-sub.h
new file mode 100644
index 0000000..60f9aa0
--- /dev/null
+++ b/test/Modules/Inputs/autolink-sub.h
@@ -0,0 +1 @@
+int autolink_sub(void);
diff --git a/test/Modules/Inputs/autolink-sub2.h b/test/Modules/Inputs/autolink-sub2.h
new file mode 100644
index 0000000..c3ea702
--- /dev/null
+++ b/test/Modules/Inputs/autolink-sub2.h
@@ -0,0 +1 @@
+int autolink_sub2(void);
diff --git a/test/Modules/Inputs/autolink.h b/test/Modules/Inputs/autolink.h
new file mode 100644
index 0000000..1014e29
--- /dev/null
+++ b/test/Modules/Inputs/autolink.h
@@ -0,0 +1 @@
+extern int autolink;
diff --git a/test/Modules/Inputs/builtin.h b/test/Modules/Inputs/builtin.h
new file mode 100644
index 0000000..7be9017
--- /dev/null
+++ b/test/Modules/Inputs/builtin.h
@@ -0,0 +1,3 @@
+int i;
+int *p = &i;
+
diff --git a/test/Modules/Inputs/builtin_sub.h b/test/Modules/Inputs/builtin_sub.h
new file mode 100644
index 0000000..79e3c03
--- /dev/null
+++ b/test/Modules/Inputs/builtin_sub.h
@@ -0,0 +1,4 @@
+int getBos1(void) {
+ return __builtin_object_size(p, 0);
+}
+
diff --git a/test/Modules/Inputs/category_bottom.h b/test/Modules/Inputs/category_bottom.h
index b53d9c3..ab4c01c 100644
--- a/test/Modules/Inputs/category_bottom.h
+++ b/test/Modules/Inputs/category_bottom.h
@@ -1,10 +1,10 @@
-@__experimental_modules_import category_left;
+@import category_left;
@interface Foo(Bottom)
-(void)bottom;
@end
-@__experimental_modules_import category_right;
+@import category_right;
@interface LeftFoo(Bottom)
-(void)bottom;
diff --git a/test/Modules/Inputs/category_left.h b/test/Modules/Inputs/category_left.h
index 736fa43..05e2a1b 100644
--- a/test/Modules/Inputs/category_left.h
+++ b/test/Modules/Inputs/category_left.h
@@ -1,4 +1,4 @@
-@__experimental_modules_import category_top;
+@import category_top;
@interface Foo(Left)
-(void)left;
diff --git a/test/Modules/Inputs/category_left_sub.h b/test/Modules/Inputs/category_left_sub.h
new file mode 100644
index 0000000..d92a873
--- /dev/null
+++ b/test/Modules/Inputs/category_left_sub.h
@@ -0,0 +1,11 @@
+@interface Foo(LeftSub) <P1>
+- (void)left_sub;
+@end
+
+@protocol P3
+- (void)p3_method;
+@property (retain) id p3_prop;
+@end
+
+@interface Foo(LeftP3) <P3>
+@end
diff --git a/test/Modules/Inputs/category_other.h b/test/Modules/Inputs/category_other.h
index 1bb5a91..2c3f479 100644
--- a/test/Modules/Inputs/category_other.h
+++ b/test/Modules/Inputs/category_other.h
@@ -1,4 +1,4 @@
-@__experimental_modules_import category_top;
+@import category_top;
@interface Foo(Other)
-(void)other;
diff --git a/test/Modules/Inputs/category_right.h b/test/Modules/Inputs/category_right.h
index 812a840..3c83624 100644
--- a/test/Modules/Inputs/category_right.h
+++ b/test/Modules/Inputs/category_right.h
@@ -1,4 +1,4 @@
-@__experimental_modules_import category_top;
+@import category_top;
@interface Foo(Right1)
-(void)right1;
diff --git a/test/Modules/Inputs/category_right_sub.h b/test/Modules/Inputs/category_right_sub.h
new file mode 100644
index 0000000..231f65f
--- /dev/null
+++ b/test/Modules/Inputs/category_right_sub.h
@@ -0,0 +1,17 @@
+@interface Foo(RightSub) <P2>
+@property id right_sub_prop;
+@end
+
+@interface Foo() {
+@public
+ int right_sub_ivar;
+}
+@end
+
+@protocol P4
+- (void)p4_method;
+@property (retain) id p4_prop;
+@end
+
+@interface Foo(LeftP4) <P4>
+@end
diff --git a/test/Modules/Inputs/category_top.h b/test/Modules/Inputs/category_top.h
index c9558b6..269edc9 100644
--- a/test/Modules/Inputs/category_top.h
+++ b/test/Modules/Inputs/category_top.h
@@ -12,3 +12,12 @@
@interface Foo(Top3)
-(void)top3;
@end
+
+@protocol P1
+@end
+
+@protocol P2
+@end
+
+@protocol P3, P4;
+
diff --git a/test/Modules/Inputs/config.h b/test/Modules/Inputs/config.h
new file mode 100644
index 0000000..f2dfda6
--- /dev/null
+++ b/test/Modules/Inputs/config.h
@@ -0,0 +1,7 @@
+#ifdef WANT_FOO
+int* foo();
+#endif
+
+#ifdef WANT_BAR
+char *bar();
+#endif
diff --git a/test/Modules/Inputs/cxx-inline-namespace.h b/test/Modules/Inputs/cxx-inline-namespace.h
new file mode 100644
index 0000000..2525ad3
--- /dev/null
+++ b/test/Modules/Inputs/cxx-inline-namespace.h
@@ -0,0 +1,11 @@
+namespace std {
+ inline namespace __1 {
+ namespace __is_function_imp {}
+ }
+}
+
+namespace std {
+ inline namespace __1 {
+ typedef int size_t;
+ }
+}
diff --git a/test/Modules/Inputs/cxx-linkage-cache.h b/test/Modules/Inputs/cxx-linkage-cache.h
new file mode 100644
index 0000000..df82927
--- /dev/null
+++ b/test/Modules/Inputs/cxx-linkage-cache.h
@@ -0,0 +1,11 @@
+// Reduced from a crash encountered with a modularized libc++, where
+// we would try to compute the linkage of a declaration before we
+// finish loading the relevant pieces of it.
+inline namespace D {
+ template<class>
+ struct U {
+ friend bool f(const U &);
+ };
+
+ template class U<int>;
+}
diff --git a/test/Modules/Inputs/cxx-many-overloads.h b/test/Modules/Inputs/cxx-many-overloads.h
new file mode 100644
index 0000000..890a86c
--- /dev/null
+++ b/test/Modules/Inputs/cxx-many-overloads.h
@@ -0,0 +1,2004 @@
+namespace N {
+ template<int> struct X {};
+ void f(X<0>);
+ void f(X<1>);
+ void f(X<2>);
+ void f(X<3>);
+ void f(X<4>);
+ void f(X<5>);
+ void f(X<6>);
+ void f(X<7>);
+ void f(X<8>);
+ void f(X<9>);
+ void f(X<10>);
+ void f(X<11>);
+ void f(X<12>);
+ void f(X<13>);
+ void f(X<14>);
+ void f(X<15>);
+ void f(X<16>);
+ void f(X<17>);
+ void f(X<18>);
+ void f(X<19>);
+ void f(X<20>);
+ void f(X<21>);
+ void f(X<22>);
+ void f(X<23>);
+ void f(X<24>);
+ void f(X<25>);
+ void f(X<26>);
+ void f(X<27>);
+ void f(X<28>);
+ void f(X<29>);
+ void f(X<30>);
+ void f(X<31>);
+ void f(X<32>);
+ void f(X<33>);
+ void f(X<34>);
+ void f(X<35>);
+ void f(X<36>);
+ void f(X<37>);
+ void f(X<38>);
+ void f(X<39>);
+ void f(X<40>);
+ void f(X<41>);
+ void f(X<42>);
+ void f(X<43>);
+ void f(X<44>);
+ void f(X<45>);
+ void f(X<46>);
+ void f(X<47>);
+ void f(X<48>);
+ void f(X<49>);
+ void f(X<50>);
+ void f(X<51>);
+ void f(X<52>);
+ void f(X<53>);
+ void f(X<54>);
+ void f(X<55>);
+ void f(X<56>);
+ void f(X<57>);
+ void f(X<58>);
+ void f(X<59>);
+ void f(X<60>);
+ void f(X<61>);
+ void f(X<62>);
+ void f(X<63>);
+ void f(X<64>);
+ void f(X<65>);
+ void f(X<66>);
+ void f(X<67>);
+ void f(X<68>);
+ void f(X<69>);
+ void f(X<70>);
+ void f(X<71>);
+ void f(X<72>);
+ void f(X<73>);
+ void f(X<74>);
+ void f(X<75>);
+ void f(X<76>);
+ void f(X<77>);
+ void f(X<78>);
+ void f(X<79>);
+ void f(X<80>);
+ void f(X<81>);
+ void f(X<82>);
+ void f(X<83>);
+ void f(X<84>);
+ void f(X<85>);
+ void f(X<86>);
+ void f(X<87>);
+ void f(X<88>);
+ void f(X<89>);
+ void f(X<90>);
+ void f(X<91>);
+ void f(X<92>);
+ void f(X<93>);
+ void f(X<94>);
+ void f(X<95>);
+ void f(X<96>);
+ void f(X<97>);
+ void f(X<98>);
+ void f(X<99>);
+ void f(X<100>);
+ void f(X<101>);
+ void f(X<102>);
+ void f(X<103>);
+ void f(X<104>);
+ void f(X<105>);
+ void f(X<106>);
+ void f(X<107>);
+ void f(X<108>);
+ void f(X<109>);
+ void f(X<110>);
+ void f(X<111>);
+ void f(X<112>);
+ void f(X<113>);
+ void f(X<114>);
+ void f(X<115>);
+ void f(X<116>);
+ void f(X<117>);
+ void f(X<118>);
+ void f(X<119>);
+ void f(X<120>);
+ void f(X<121>);
+ void f(X<122>);
+ void f(X<123>);
+ void f(X<124>);
+ void f(X<125>);
+ void f(X<126>);
+ void f(X<127>);
+ void f(X<128>);
+ void f(X<129>);
+ void f(X<130>);
+ void f(X<131>);
+ void f(X<132>);
+ void f(X<133>);
+ void f(X<134>);
+ void f(X<135>);
+ void f(X<136>);
+ void f(X<137>);
+ void f(X<138>);
+ void f(X<139>);
+ void f(X<140>);
+ void f(X<141>);
+ void f(X<142>);
+ void f(X<143>);
+ void f(X<144>);
+ void f(X<145>);
+ void f(X<146>);
+ void f(X<147>);
+ void f(X<148>);
+ void f(X<149>);
+ void f(X<150>);
+ void f(X<151>);
+ void f(X<152>);
+ void f(X<153>);
+ void f(X<154>);
+ void f(X<155>);
+ void f(X<156>);
+ void f(X<157>);
+ void f(X<158>);
+ void f(X<159>);
+ void f(X<160>);
+ void f(X<161>);
+ void f(X<162>);
+ void f(X<163>);
+ void f(X<164>);
+ void f(X<165>);
+ void f(X<166>);
+ void f(X<167>);
+ void f(X<168>);
+ void f(X<169>);
+ void f(X<170>);
+ void f(X<171>);
+ void f(X<172>);
+ void f(X<173>);
+ void f(X<174>);
+ void f(X<175>);
+ void f(X<176>);
+ void f(X<177>);
+ void f(X<178>);
+ void f(X<179>);
+ void f(X<180>);
+ void f(X<181>);
+ void f(X<182>);
+ void f(X<183>);
+ void f(X<184>);
+ void f(X<185>);
+ void f(X<186>);
+ void f(X<187>);
+ void f(X<188>);
+ void f(X<189>);
+ void f(X<190>);
+ void f(X<191>);
+ void f(X<192>);
+ void f(X<193>);
+ void f(X<194>);
+ void f(X<195>);
+ void f(X<196>);
+ void f(X<197>);
+ void f(X<198>);
+ void f(X<199>);
+ void f(X<200>);
+ void f(X<201>);
+ void f(X<202>);
+ void f(X<203>);
+ void f(X<204>);
+ void f(X<205>);
+ void f(X<206>);
+ void f(X<207>);
+ void f(X<208>);
+ void f(X<209>);
+ void f(X<210>);
+ void f(X<211>);
+ void f(X<212>);
+ void f(X<213>);
+ void f(X<214>);
+ void f(X<215>);
+ void f(X<216>);
+ void f(X<217>);
+ void f(X<218>);
+ void f(X<219>);
+ void f(X<220>);
+ void f(X<221>);
+ void f(X<222>);
+ void f(X<223>);
+ void f(X<224>);
+ void f(X<225>);
+ void f(X<226>);
+ void f(X<227>);
+ void f(X<228>);
+ void f(X<229>);
+ void f(X<230>);
+ void f(X<231>);
+ void f(X<232>);
+ void f(X<233>);
+ void f(X<234>);
+ void f(X<235>);
+ void f(X<236>);
+ void f(X<237>);
+ void f(X<238>);
+ void f(X<239>);
+ void f(X<240>);
+ void f(X<241>);
+ void f(X<242>);
+ void f(X<243>);
+ void f(X<244>);
+ void f(X<245>);
+ void f(X<246>);
+ void f(X<247>);
+ void f(X<248>);
+ void f(X<249>);
+ void f(X<250>);
+ void f(X<251>);
+ void f(X<252>);
+ void f(X<253>);
+ void f(X<254>);
+ void f(X<255>);
+ void f(X<256>);
+ void f(X<257>);
+ void f(X<258>);
+ void f(X<259>);
+ void f(X<260>);
+ void f(X<261>);
+ void f(X<262>);
+ void f(X<263>);
+ void f(X<264>);
+ void f(X<265>);
+ void f(X<266>);
+ void f(X<267>);
+ void f(X<268>);
+ void f(X<269>);
+ void f(X<270>);
+ void f(X<271>);
+ void f(X<272>);
+ void f(X<273>);
+ void f(X<274>);
+ void f(X<275>);
+ void f(X<276>);
+ void f(X<277>);
+ void f(X<278>);
+ void f(X<279>);
+ void f(X<280>);
+ void f(X<281>);
+ void f(X<282>);
+ void f(X<283>);
+ void f(X<284>);
+ void f(X<285>);
+ void f(X<286>);
+ void f(X<287>);
+ void f(X<288>);
+ void f(X<289>);
+ void f(X<290>);
+ void f(X<291>);
+ void f(X<292>);
+ void f(X<293>);
+ void f(X<294>);
+ void f(X<295>);
+ void f(X<296>);
+ void f(X<297>);
+ void f(X<298>);
+ void f(X<299>);
+ void f(X<300>);
+ void f(X<301>);
+ void f(X<302>);
+ void f(X<303>);
+ void f(X<304>);
+ void f(X<305>);
+ void f(X<306>);
+ void f(X<307>);
+ void f(X<308>);
+ void f(X<309>);
+ void f(X<310>);
+ void f(X<311>);
+ void f(X<312>);
+ void f(X<313>);
+ void f(X<314>);
+ void f(X<315>);
+ void f(X<316>);
+ void f(X<317>);
+ void f(X<318>);
+ void f(X<319>);
+ void f(X<320>);
+ void f(X<321>);
+ void f(X<322>);
+ void f(X<323>);
+ void f(X<324>);
+ void f(X<325>);
+ void f(X<326>);
+ void f(X<327>);
+ void f(X<328>);
+ void f(X<329>);
+ void f(X<330>);
+ void f(X<331>);
+ void f(X<332>);
+ void f(X<333>);
+ void f(X<334>);
+ void f(X<335>);
+ void f(X<336>);
+ void f(X<337>);
+ void f(X<338>);
+ void f(X<339>);
+ void f(X<340>);
+ void f(X<341>);
+ void f(X<342>);
+ void f(X<343>);
+ void f(X<344>);
+ void f(X<345>);
+ void f(X<346>);
+ void f(X<347>);
+ void f(X<348>);
+ void f(X<349>);
+ void f(X<350>);
+ void f(X<351>);
+ void f(X<352>);
+ void f(X<353>);
+ void f(X<354>);
+ void f(X<355>);
+ void f(X<356>);
+ void f(X<357>);
+ void f(X<358>);
+ void f(X<359>);
+ void f(X<360>);
+ void f(X<361>);
+ void f(X<362>);
+ void f(X<363>);
+ void f(X<364>);
+ void f(X<365>);
+ void f(X<366>);
+ void f(X<367>);
+ void f(X<368>);
+ void f(X<369>);
+ void f(X<370>);
+ void f(X<371>);
+ void f(X<372>);
+ void f(X<373>);
+ void f(X<374>);
+ void f(X<375>);
+ void f(X<376>);
+ void f(X<377>);
+ void f(X<378>);
+ void f(X<379>);
+ void f(X<380>);
+ void f(X<381>);
+ void f(X<382>);
+ void f(X<383>);
+ void f(X<384>);
+ void f(X<385>);
+ void f(X<386>);
+ void f(X<387>);
+ void f(X<388>);
+ void f(X<389>);
+ void f(X<390>);
+ void f(X<391>);
+ void f(X<392>);
+ void f(X<393>);
+ void f(X<394>);
+ void f(X<395>);
+ void f(X<396>);
+ void f(X<397>);
+ void f(X<398>);
+ void f(X<399>);
+ void f(X<400>);
+ void f(X<401>);
+ void f(X<402>);
+ void f(X<403>);
+ void f(X<404>);
+ void f(X<405>);
+ void f(X<406>);
+ void f(X<407>);
+ void f(X<408>);
+ void f(X<409>);
+ void f(X<410>);
+ void f(X<411>);
+ void f(X<412>);
+ void f(X<413>);
+ void f(X<414>);
+ void f(X<415>);
+ void f(X<416>);
+ void f(X<417>);
+ void f(X<418>);
+ void f(X<419>);
+ void f(X<420>);
+ void f(X<421>);
+ void f(X<422>);
+ void f(X<423>);
+ void f(X<424>);
+ void f(X<425>);
+ void f(X<426>);
+ void f(X<427>);
+ void f(X<428>);
+ void f(X<429>);
+ void f(X<430>);
+ void f(X<431>);
+ void f(X<432>);
+ void f(X<433>);
+ void f(X<434>);
+ void f(X<435>);
+ void f(X<436>);
+ void f(X<437>);
+ void f(X<438>);
+ void f(X<439>);
+ void f(X<440>);
+ void f(X<441>);
+ void f(X<442>);
+ void f(X<443>);
+ void f(X<444>);
+ void f(X<445>);
+ void f(X<446>);
+ void f(X<447>);
+ void f(X<448>);
+ void f(X<449>);
+ void f(X<450>);
+ void f(X<451>);
+ void f(X<452>);
+ void f(X<453>);
+ void f(X<454>);
+ void f(X<455>);
+ void f(X<456>);
+ void f(X<457>);
+ void f(X<458>);
+ void f(X<459>);
+ void f(X<460>);
+ void f(X<461>);
+ void f(X<462>);
+ void f(X<463>);
+ void f(X<464>);
+ void f(X<465>);
+ void f(X<466>);
+ void f(X<467>);
+ void f(X<468>);
+ void f(X<469>);
+ void f(X<470>);
+ void f(X<471>);
+ void f(X<472>);
+ void f(X<473>);
+ void f(X<474>);
+ void f(X<475>);
+ void f(X<476>);
+ void f(X<477>);
+ void f(X<478>);
+ void f(X<479>);
+ void f(X<480>);
+ void f(X<481>);
+ void f(X<482>);
+ void f(X<483>);
+ void f(X<484>);
+ void f(X<485>);
+ void f(X<486>);
+ void f(X<487>);
+ void f(X<488>);
+ void f(X<489>);
+ void f(X<490>);
+ void f(X<491>);
+ void f(X<492>);
+ void f(X<493>);
+ void f(X<494>);
+ void f(X<495>);
+ void f(X<496>);
+ void f(X<497>);
+ void f(X<498>);
+ void f(X<499>);
+ void f(X<500>);
+ void f(X<501>);
+ void f(X<502>);
+ void f(X<503>);
+ void f(X<504>);
+ void f(X<505>);
+ void f(X<506>);
+ void f(X<507>);
+ void f(X<508>);
+ void f(X<509>);
+ void f(X<510>);
+ void f(X<511>);
+ void f(X<512>);
+ void f(X<513>);
+ void f(X<514>);
+ void f(X<515>);
+ void f(X<516>);
+ void f(X<517>);
+ void f(X<518>);
+ void f(X<519>);
+ void f(X<520>);
+ void f(X<521>);
+ void f(X<522>);
+ void f(X<523>);
+ void f(X<524>);
+ void f(X<525>);
+ void f(X<526>);
+ void f(X<527>);
+ void f(X<528>);
+ void f(X<529>);
+ void f(X<530>);
+ void f(X<531>);
+ void f(X<532>);
+ void f(X<533>);
+ void f(X<534>);
+ void f(X<535>);
+ void f(X<536>);
+ void f(X<537>);
+ void f(X<538>);
+ void f(X<539>);
+ void f(X<540>);
+ void f(X<541>);
+ void f(X<542>);
+ void f(X<543>);
+ void f(X<544>);
+ void f(X<545>);
+ void f(X<546>);
+ void f(X<547>);
+ void f(X<548>);
+ void f(X<549>);
+ void f(X<550>);
+ void f(X<551>);
+ void f(X<552>);
+ void f(X<553>);
+ void f(X<554>);
+ void f(X<555>);
+ void f(X<556>);
+ void f(X<557>);
+ void f(X<558>);
+ void f(X<559>);
+ void f(X<560>);
+ void f(X<561>);
+ void f(X<562>);
+ void f(X<563>);
+ void f(X<564>);
+ void f(X<565>);
+ void f(X<566>);
+ void f(X<567>);
+ void f(X<568>);
+ void f(X<569>);
+ void f(X<570>);
+ void f(X<571>);
+ void f(X<572>);
+ void f(X<573>);
+ void f(X<574>);
+ void f(X<575>);
+ void f(X<576>);
+ void f(X<577>);
+ void f(X<578>);
+ void f(X<579>);
+ void f(X<580>);
+ void f(X<581>);
+ void f(X<582>);
+ void f(X<583>);
+ void f(X<584>);
+ void f(X<585>);
+ void f(X<586>);
+ void f(X<587>);
+ void f(X<588>);
+ void f(X<589>);
+ void f(X<590>);
+ void f(X<591>);
+ void f(X<592>);
+ void f(X<593>);
+ void f(X<594>);
+ void f(X<595>);
+ void f(X<596>);
+ void f(X<597>);
+ void f(X<598>);
+ void f(X<599>);
+ void f(X<600>);
+ void f(X<601>);
+ void f(X<602>);
+ void f(X<603>);
+ void f(X<604>);
+ void f(X<605>);
+ void f(X<606>);
+ void f(X<607>);
+ void f(X<608>);
+ void f(X<609>);
+ void f(X<610>);
+ void f(X<611>);
+ void f(X<612>);
+ void f(X<613>);
+ void f(X<614>);
+ void f(X<615>);
+ void f(X<616>);
+ void f(X<617>);
+ void f(X<618>);
+ void f(X<619>);
+ void f(X<620>);
+ void f(X<621>);
+ void f(X<622>);
+ void f(X<623>);
+ void f(X<624>);
+ void f(X<625>);
+ void f(X<626>);
+ void f(X<627>);
+ void f(X<628>);
+ void f(X<629>);
+ void f(X<630>);
+ void f(X<631>);
+ void f(X<632>);
+ void f(X<633>);
+ void f(X<634>);
+ void f(X<635>);
+ void f(X<636>);
+ void f(X<637>);
+ void f(X<638>);
+ void f(X<639>);
+ void f(X<640>);
+ void f(X<641>);
+ void f(X<642>);
+ void f(X<643>);
+ void f(X<644>);
+ void f(X<645>);
+ void f(X<646>);
+ void f(X<647>);
+ void f(X<648>);
+ void f(X<649>);
+ void f(X<650>);
+ void f(X<651>);
+ void f(X<652>);
+ void f(X<653>);
+ void f(X<654>);
+ void f(X<655>);
+ void f(X<656>);
+ void f(X<657>);
+ void f(X<658>);
+ void f(X<659>);
+ void f(X<660>);
+ void f(X<661>);
+ void f(X<662>);
+ void f(X<663>);
+ void f(X<664>);
+ void f(X<665>);
+ void f(X<666>);
+ void f(X<667>);
+ void f(X<668>);
+ void f(X<669>);
+ void f(X<670>);
+ void f(X<671>);
+ void f(X<672>);
+ void f(X<673>);
+ void f(X<674>);
+ void f(X<675>);
+ void f(X<676>);
+ void f(X<677>);
+ void f(X<678>);
+ void f(X<679>);
+ void f(X<680>);
+ void f(X<681>);
+ void f(X<682>);
+ void f(X<683>);
+ void f(X<684>);
+ void f(X<685>);
+ void f(X<686>);
+ void f(X<687>);
+ void f(X<688>);
+ void f(X<689>);
+ void f(X<690>);
+ void f(X<691>);
+ void f(X<692>);
+ void f(X<693>);
+ void f(X<694>);
+ void f(X<695>);
+ void f(X<696>);
+ void f(X<697>);
+ void f(X<698>);
+ void f(X<699>);
+ void f(X<700>);
+ void f(X<701>);
+ void f(X<702>);
+ void f(X<703>);
+ void f(X<704>);
+ void f(X<705>);
+ void f(X<706>);
+ void f(X<707>);
+ void f(X<708>);
+ void f(X<709>);
+ void f(X<710>);
+ void f(X<711>);
+ void f(X<712>);
+ void f(X<713>);
+ void f(X<714>);
+ void f(X<715>);
+ void f(X<716>);
+ void f(X<717>);
+ void f(X<718>);
+ void f(X<719>);
+ void f(X<720>);
+ void f(X<721>);
+ void f(X<722>);
+ void f(X<723>);
+ void f(X<724>);
+ void f(X<725>);
+ void f(X<726>);
+ void f(X<727>);
+ void f(X<728>);
+ void f(X<729>);
+ void f(X<730>);
+ void f(X<731>);
+ void f(X<732>);
+ void f(X<733>);
+ void f(X<734>);
+ void f(X<735>);
+ void f(X<736>);
+ void f(X<737>);
+ void f(X<738>);
+ void f(X<739>);
+ void f(X<740>);
+ void f(X<741>);
+ void f(X<742>);
+ void f(X<743>);
+ void f(X<744>);
+ void f(X<745>);
+ void f(X<746>);
+ void f(X<747>);
+ void f(X<748>);
+ void f(X<749>);
+ void f(X<750>);
+ void f(X<751>);
+ void f(X<752>);
+ void f(X<753>);
+ void f(X<754>);
+ void f(X<755>);
+ void f(X<756>);
+ void f(X<757>);
+ void f(X<758>);
+ void f(X<759>);
+ void f(X<760>);
+ void f(X<761>);
+ void f(X<762>);
+ void f(X<763>);
+ void f(X<764>);
+ void f(X<765>);
+ void f(X<766>);
+ void f(X<767>);
+ void f(X<768>);
+ void f(X<769>);
+ void f(X<770>);
+ void f(X<771>);
+ void f(X<772>);
+ void f(X<773>);
+ void f(X<774>);
+ void f(X<775>);
+ void f(X<776>);
+ void f(X<777>);
+ void f(X<778>);
+ void f(X<779>);
+ void f(X<780>);
+ void f(X<781>);
+ void f(X<782>);
+ void f(X<783>);
+ void f(X<784>);
+ void f(X<785>);
+ void f(X<786>);
+ void f(X<787>);
+ void f(X<788>);
+ void f(X<789>);
+ void f(X<790>);
+ void f(X<791>);
+ void f(X<792>);
+ void f(X<793>);
+ void f(X<794>);
+ void f(X<795>);
+ void f(X<796>);
+ void f(X<797>);
+ void f(X<798>);
+ void f(X<799>);
+ void f(X<800>);
+ void f(X<801>);
+ void f(X<802>);
+ void f(X<803>);
+ void f(X<804>);
+ void f(X<805>);
+ void f(X<806>);
+ void f(X<807>);
+ void f(X<808>);
+ void f(X<809>);
+ void f(X<810>);
+ void f(X<811>);
+ void f(X<812>);
+ void f(X<813>);
+ void f(X<814>);
+ void f(X<815>);
+ void f(X<816>);
+ void f(X<817>);
+ void f(X<818>);
+ void f(X<819>);
+ void f(X<820>);
+ void f(X<821>);
+ void f(X<822>);
+ void f(X<823>);
+ void f(X<824>);
+ void f(X<825>);
+ void f(X<826>);
+ void f(X<827>);
+ void f(X<828>);
+ void f(X<829>);
+ void f(X<830>);
+ void f(X<831>);
+ void f(X<832>);
+ void f(X<833>);
+ void f(X<834>);
+ void f(X<835>);
+ void f(X<836>);
+ void f(X<837>);
+ void f(X<838>);
+ void f(X<839>);
+ void f(X<840>);
+ void f(X<841>);
+ void f(X<842>);
+ void f(X<843>);
+ void f(X<844>);
+ void f(X<845>);
+ void f(X<846>);
+ void f(X<847>);
+ void f(X<848>);
+ void f(X<849>);
+ void f(X<850>);
+ void f(X<851>);
+ void f(X<852>);
+ void f(X<853>);
+ void f(X<854>);
+ void f(X<855>);
+ void f(X<856>);
+ void f(X<857>);
+ void f(X<858>);
+ void f(X<859>);
+ void f(X<860>);
+ void f(X<861>);
+ void f(X<862>);
+ void f(X<863>);
+ void f(X<864>);
+ void f(X<865>);
+ void f(X<866>);
+ void f(X<867>);
+ void f(X<868>);
+ void f(X<869>);
+ void f(X<870>);
+ void f(X<871>);
+ void f(X<872>);
+ void f(X<873>);
+ void f(X<874>);
+ void f(X<875>);
+ void f(X<876>);
+ void f(X<877>);
+ void f(X<878>);
+ void f(X<879>);
+ void f(X<880>);
+ void f(X<881>);
+ void f(X<882>);
+ void f(X<883>);
+ void f(X<884>);
+ void f(X<885>);
+ void f(X<886>);
+ void f(X<887>);
+ void f(X<888>);
+ void f(X<889>);
+ void f(X<890>);
+ void f(X<891>);
+ void f(X<892>);
+ void f(X<893>);
+ void f(X<894>);
+ void f(X<895>);
+ void f(X<896>);
+ void f(X<897>);
+ void f(X<898>);
+ void f(X<899>);
+ void f(X<900>);
+ void f(X<901>);
+ void f(X<902>);
+ void f(X<903>);
+ void f(X<904>);
+ void f(X<905>);
+ void f(X<906>);
+ void f(X<907>);
+ void f(X<908>);
+ void f(X<909>);
+ void f(X<910>);
+ void f(X<911>);
+ void f(X<912>);
+ void f(X<913>);
+ void f(X<914>);
+ void f(X<915>);
+ void f(X<916>);
+ void f(X<917>);
+ void f(X<918>);
+ void f(X<919>);
+ void f(X<920>);
+ void f(X<921>);
+ void f(X<922>);
+ void f(X<923>);
+ void f(X<924>);
+ void f(X<925>);
+ void f(X<926>);
+ void f(X<927>);
+ void f(X<928>);
+ void f(X<929>);
+ void f(X<930>);
+ void f(X<931>);
+ void f(X<932>);
+ void f(X<933>);
+ void f(X<934>);
+ void f(X<935>);
+ void f(X<936>);
+ void f(X<937>);
+ void f(X<938>);
+ void f(X<939>);
+ void f(X<940>);
+ void f(X<941>);
+ void f(X<942>);
+ void f(X<943>);
+ void f(X<944>);
+ void f(X<945>);
+ void f(X<946>);
+ void f(X<947>);
+ void f(X<948>);
+ void f(X<949>);
+ void f(X<950>);
+ void f(X<951>);
+ void f(X<952>);
+ void f(X<953>);
+ void f(X<954>);
+ void f(X<955>);
+ void f(X<956>);
+ void f(X<957>);
+ void f(X<958>);
+ void f(X<959>);
+ void f(X<960>);
+ void f(X<961>);
+ void f(X<962>);
+ void f(X<963>);
+ void f(X<964>);
+ void f(X<965>);
+ void f(X<966>);
+ void f(X<967>);
+ void f(X<968>);
+ void f(X<969>);
+ void f(X<970>);
+ void f(X<971>);
+ void f(X<972>);
+ void f(X<973>);
+ void f(X<974>);
+ void f(X<975>);
+ void f(X<976>);
+ void f(X<977>);
+ void f(X<978>);
+ void f(X<979>);
+ void f(X<980>);
+ void f(X<981>);
+ void f(X<982>);
+ void f(X<983>);
+ void f(X<984>);
+ void f(X<985>);
+ void f(X<986>);
+ void f(X<987>);
+ void f(X<988>);
+ void f(X<989>);
+ void f(X<990>);
+ void f(X<991>);
+ void f(X<992>);
+ void f(X<993>);
+ void f(X<994>);
+ void f(X<995>);
+ void f(X<996>);
+ void f(X<997>);
+ void f(X<998>);
+ void f(X<999>);
+ void f(X<1000>);
+ void f(X<1001>);
+ void f(X<1002>);
+ void f(X<1003>);
+ void f(X<1004>);
+ void f(X<1005>);
+ void f(X<1006>);
+ void f(X<1007>);
+ void f(X<1008>);
+ void f(X<1009>);
+ void f(X<1010>);
+ void f(X<1011>);
+ void f(X<1012>);
+ void f(X<1013>);
+ void f(X<1014>);
+ void f(X<1015>);
+ void f(X<1016>);
+ void f(X<1017>);
+ void f(X<1018>);
+ void f(X<1019>);
+ void f(X<1020>);
+ void f(X<1021>);
+ void f(X<1022>);
+ void f(X<1023>);
+ void f(X<1024>);
+ void f(X<1025>);
+ void f(X<1026>);
+ void f(X<1027>);
+ void f(X<1028>);
+ void f(X<1029>);
+ void f(X<1030>);
+ void f(X<1031>);
+ void f(X<1032>);
+ void f(X<1033>);
+ void f(X<1034>);
+ void f(X<1035>);
+ void f(X<1036>);
+ void f(X<1037>);
+ void f(X<1038>);
+ void f(X<1039>);
+ void f(X<1040>);
+ void f(X<1041>);
+ void f(X<1042>);
+ void f(X<1043>);
+ void f(X<1044>);
+ void f(X<1045>);
+ void f(X<1046>);
+ void f(X<1047>);
+ void f(X<1048>);
+ void f(X<1049>);
+ void f(X<1050>);
+ void f(X<1051>);
+ void f(X<1052>);
+ void f(X<1053>);
+ void f(X<1054>);
+ void f(X<1055>);
+ void f(X<1056>);
+ void f(X<1057>);
+ void f(X<1058>);
+ void f(X<1059>);
+ void f(X<1060>);
+ void f(X<1061>);
+ void f(X<1062>);
+ void f(X<1063>);
+ void f(X<1064>);
+ void f(X<1065>);
+ void f(X<1066>);
+ void f(X<1067>);
+ void f(X<1068>);
+ void f(X<1069>);
+ void f(X<1070>);
+ void f(X<1071>);
+ void f(X<1072>);
+ void f(X<1073>);
+ void f(X<1074>);
+ void f(X<1075>);
+ void f(X<1076>);
+ void f(X<1077>);
+ void f(X<1078>);
+ void f(X<1079>);
+ void f(X<1080>);
+ void f(X<1081>);
+ void f(X<1082>);
+ void f(X<1083>);
+ void f(X<1084>);
+ void f(X<1085>);
+ void f(X<1086>);
+ void f(X<1087>);
+ void f(X<1088>);
+ void f(X<1089>);
+ void f(X<1090>);
+ void f(X<1091>);
+ void f(X<1092>);
+ void f(X<1093>);
+ void f(X<1094>);
+ void f(X<1095>);
+ void f(X<1096>);
+ void f(X<1097>);
+ void f(X<1098>);
+ void f(X<1099>);
+ void f(X<1100>);
+ void f(X<1101>);
+ void f(X<1102>);
+ void f(X<1103>);
+ void f(X<1104>);
+ void f(X<1105>);
+ void f(X<1106>);
+ void f(X<1107>);
+ void f(X<1108>);
+ void f(X<1109>);
+ void f(X<1110>);
+ void f(X<1111>);
+ void f(X<1112>);
+ void f(X<1113>);
+ void f(X<1114>);
+ void f(X<1115>);
+ void f(X<1116>);
+ void f(X<1117>);
+ void f(X<1118>);
+ void f(X<1119>);
+ void f(X<1120>);
+ void f(X<1121>);
+ void f(X<1122>);
+ void f(X<1123>);
+ void f(X<1124>);
+ void f(X<1125>);
+ void f(X<1126>);
+ void f(X<1127>);
+ void f(X<1128>);
+ void f(X<1129>);
+ void f(X<1130>);
+ void f(X<1131>);
+ void f(X<1132>);
+ void f(X<1133>);
+ void f(X<1134>);
+ void f(X<1135>);
+ void f(X<1136>);
+ void f(X<1137>);
+ void f(X<1138>);
+ void f(X<1139>);
+ void f(X<1140>);
+ void f(X<1141>);
+ void f(X<1142>);
+ void f(X<1143>);
+ void f(X<1144>);
+ void f(X<1145>);
+ void f(X<1146>);
+ void f(X<1147>);
+ void f(X<1148>);
+ void f(X<1149>);
+ void f(X<1150>);
+ void f(X<1151>);
+ void f(X<1152>);
+ void f(X<1153>);
+ void f(X<1154>);
+ void f(X<1155>);
+ void f(X<1156>);
+ void f(X<1157>);
+ void f(X<1158>);
+ void f(X<1159>);
+ void f(X<1160>);
+ void f(X<1161>);
+ void f(X<1162>);
+ void f(X<1163>);
+ void f(X<1164>);
+ void f(X<1165>);
+ void f(X<1166>);
+ void f(X<1167>);
+ void f(X<1168>);
+ void f(X<1169>);
+ void f(X<1170>);
+ void f(X<1171>);
+ void f(X<1172>);
+ void f(X<1173>);
+ void f(X<1174>);
+ void f(X<1175>);
+ void f(X<1176>);
+ void f(X<1177>);
+ void f(X<1178>);
+ void f(X<1179>);
+ void f(X<1180>);
+ void f(X<1181>);
+ void f(X<1182>);
+ void f(X<1183>);
+ void f(X<1184>);
+ void f(X<1185>);
+ void f(X<1186>);
+ void f(X<1187>);
+ void f(X<1188>);
+ void f(X<1189>);
+ void f(X<1190>);
+ void f(X<1191>);
+ void f(X<1192>);
+ void f(X<1193>);
+ void f(X<1194>);
+ void f(X<1195>);
+ void f(X<1196>);
+ void f(X<1197>);
+ void f(X<1198>);
+ void f(X<1199>);
+ void f(X<1200>);
+ void f(X<1201>);
+ void f(X<1202>);
+ void f(X<1203>);
+ void f(X<1204>);
+ void f(X<1205>);
+ void f(X<1206>);
+ void f(X<1207>);
+ void f(X<1208>);
+ void f(X<1209>);
+ void f(X<1210>);
+ void f(X<1211>);
+ void f(X<1212>);
+ void f(X<1213>);
+ void f(X<1214>);
+ void f(X<1215>);
+ void f(X<1216>);
+ void f(X<1217>);
+ void f(X<1218>);
+ void f(X<1219>);
+ void f(X<1220>);
+ void f(X<1221>);
+ void f(X<1222>);
+ void f(X<1223>);
+ void f(X<1224>);
+ void f(X<1225>);
+ void f(X<1226>);
+ void f(X<1227>);
+ void f(X<1228>);
+ void f(X<1229>);
+ void f(X<1230>);
+ void f(X<1231>);
+ void f(X<1232>);
+ void f(X<1233>);
+ void f(X<1234>);
+ void f(X<1235>);
+ void f(X<1236>);
+ void f(X<1237>);
+ void f(X<1238>);
+ void f(X<1239>);
+ void f(X<1240>);
+ void f(X<1241>);
+ void f(X<1242>);
+ void f(X<1243>);
+ void f(X<1244>);
+ void f(X<1245>);
+ void f(X<1246>);
+ void f(X<1247>);
+ void f(X<1248>);
+ void f(X<1249>);
+ void f(X<1250>);
+ void f(X<1251>);
+ void f(X<1252>);
+ void f(X<1253>);
+ void f(X<1254>);
+ void f(X<1255>);
+ void f(X<1256>);
+ void f(X<1257>);
+ void f(X<1258>);
+ void f(X<1259>);
+ void f(X<1260>);
+ void f(X<1261>);
+ void f(X<1262>);
+ void f(X<1263>);
+ void f(X<1264>);
+ void f(X<1265>);
+ void f(X<1266>);
+ void f(X<1267>);
+ void f(X<1268>);
+ void f(X<1269>);
+ void f(X<1270>);
+ void f(X<1271>);
+ void f(X<1272>);
+ void f(X<1273>);
+ void f(X<1274>);
+ void f(X<1275>);
+ void f(X<1276>);
+ void f(X<1277>);
+ void f(X<1278>);
+ void f(X<1279>);
+ void f(X<1280>);
+ void f(X<1281>);
+ void f(X<1282>);
+ void f(X<1283>);
+ void f(X<1284>);
+ void f(X<1285>);
+ void f(X<1286>);
+ void f(X<1287>);
+ void f(X<1288>);
+ void f(X<1289>);
+ void f(X<1290>);
+ void f(X<1291>);
+ void f(X<1292>);
+ void f(X<1293>);
+ void f(X<1294>);
+ void f(X<1295>);
+ void f(X<1296>);
+ void f(X<1297>);
+ void f(X<1298>);
+ void f(X<1299>);
+ void f(X<1300>);
+ void f(X<1301>);
+ void f(X<1302>);
+ void f(X<1303>);
+ void f(X<1304>);
+ void f(X<1305>);
+ void f(X<1306>);
+ void f(X<1307>);
+ void f(X<1308>);
+ void f(X<1309>);
+ void f(X<1310>);
+ void f(X<1311>);
+ void f(X<1312>);
+ void f(X<1313>);
+ void f(X<1314>);
+ void f(X<1315>);
+ void f(X<1316>);
+ void f(X<1317>);
+ void f(X<1318>);
+ void f(X<1319>);
+ void f(X<1320>);
+ void f(X<1321>);
+ void f(X<1322>);
+ void f(X<1323>);
+ void f(X<1324>);
+ void f(X<1325>);
+ void f(X<1326>);
+ void f(X<1327>);
+ void f(X<1328>);
+ void f(X<1329>);
+ void f(X<1330>);
+ void f(X<1331>);
+ void f(X<1332>);
+ void f(X<1333>);
+ void f(X<1334>);
+ void f(X<1335>);
+ void f(X<1336>);
+ void f(X<1337>);
+ void f(X<1338>);
+ void f(X<1339>);
+ void f(X<1340>);
+ void f(X<1341>);
+ void f(X<1342>);
+ void f(X<1343>);
+ void f(X<1344>);
+ void f(X<1345>);
+ void f(X<1346>);
+ void f(X<1347>);
+ void f(X<1348>);
+ void f(X<1349>);
+ void f(X<1350>);
+ void f(X<1351>);
+ void f(X<1352>);
+ void f(X<1353>);
+ void f(X<1354>);
+ void f(X<1355>);
+ void f(X<1356>);
+ void f(X<1357>);
+ void f(X<1358>);
+ void f(X<1359>);
+ void f(X<1360>);
+ void f(X<1361>);
+ void f(X<1362>);
+ void f(X<1363>);
+ void f(X<1364>);
+ void f(X<1365>);
+ void f(X<1366>);
+ void f(X<1367>);
+ void f(X<1368>);
+ void f(X<1369>);
+ void f(X<1370>);
+ void f(X<1371>);
+ void f(X<1372>);
+ void f(X<1373>);
+ void f(X<1374>);
+ void f(X<1375>);
+ void f(X<1376>);
+ void f(X<1377>);
+ void f(X<1378>);
+ void f(X<1379>);
+ void f(X<1380>);
+ void f(X<1381>);
+ void f(X<1382>);
+ void f(X<1383>);
+ void f(X<1384>);
+ void f(X<1385>);
+ void f(X<1386>);
+ void f(X<1387>);
+ void f(X<1388>);
+ void f(X<1389>);
+ void f(X<1390>);
+ void f(X<1391>);
+ void f(X<1392>);
+ void f(X<1393>);
+ void f(X<1394>);
+ void f(X<1395>);
+ void f(X<1396>);
+ void f(X<1397>);
+ void f(X<1398>);
+ void f(X<1399>);
+ void f(X<1400>);
+ void f(X<1401>);
+ void f(X<1402>);
+ void f(X<1403>);
+ void f(X<1404>);
+ void f(X<1405>);
+ void f(X<1406>);
+ void f(X<1407>);
+ void f(X<1408>);
+ void f(X<1409>);
+ void f(X<1410>);
+ void f(X<1411>);
+ void f(X<1412>);
+ void f(X<1413>);
+ void f(X<1414>);
+ void f(X<1415>);
+ void f(X<1416>);
+ void f(X<1417>);
+ void f(X<1418>);
+ void f(X<1419>);
+ void f(X<1420>);
+ void f(X<1421>);
+ void f(X<1422>);
+ void f(X<1423>);
+ void f(X<1424>);
+ void f(X<1425>);
+ void f(X<1426>);
+ void f(X<1427>);
+ void f(X<1428>);
+ void f(X<1429>);
+ void f(X<1430>);
+ void f(X<1431>);
+ void f(X<1432>);
+ void f(X<1433>);
+ void f(X<1434>);
+ void f(X<1435>);
+ void f(X<1436>);
+ void f(X<1437>);
+ void f(X<1438>);
+ void f(X<1439>);
+ void f(X<1440>);
+ void f(X<1441>);
+ void f(X<1442>);
+ void f(X<1443>);
+ void f(X<1444>);
+ void f(X<1445>);
+ void f(X<1446>);
+ void f(X<1447>);
+ void f(X<1448>);
+ void f(X<1449>);
+ void f(X<1450>);
+ void f(X<1451>);
+ void f(X<1452>);
+ void f(X<1453>);
+ void f(X<1454>);
+ void f(X<1455>);
+ void f(X<1456>);
+ void f(X<1457>);
+ void f(X<1458>);
+ void f(X<1459>);
+ void f(X<1460>);
+ void f(X<1461>);
+ void f(X<1462>);
+ void f(X<1463>);
+ void f(X<1464>);
+ void f(X<1465>);
+ void f(X<1466>);
+ void f(X<1467>);
+ void f(X<1468>);
+ void f(X<1469>);
+ void f(X<1470>);
+ void f(X<1471>);
+ void f(X<1472>);
+ void f(X<1473>);
+ void f(X<1474>);
+ void f(X<1475>);
+ void f(X<1476>);
+ void f(X<1477>);
+ void f(X<1478>);
+ void f(X<1479>);
+ void f(X<1480>);
+ void f(X<1481>);
+ void f(X<1482>);
+ void f(X<1483>);
+ void f(X<1484>);
+ void f(X<1485>);
+ void f(X<1486>);
+ void f(X<1487>);
+ void f(X<1488>);
+ void f(X<1489>);
+ void f(X<1490>);
+ void f(X<1491>);
+ void f(X<1492>);
+ void f(X<1493>);
+ void f(X<1494>);
+ void f(X<1495>);
+ void f(X<1496>);
+ void f(X<1497>);
+ void f(X<1498>);
+ void f(X<1499>);
+ void f(X<1500>);
+ void f(X<1501>);
+ void f(X<1502>);
+ void f(X<1503>);
+ void f(X<1504>);
+ void f(X<1505>);
+ void f(X<1506>);
+ void f(X<1507>);
+ void f(X<1508>);
+ void f(X<1509>);
+ void f(X<1510>);
+ void f(X<1511>);
+ void f(X<1512>);
+ void f(X<1513>);
+ void f(X<1514>);
+ void f(X<1515>);
+ void f(X<1516>);
+ void f(X<1517>);
+ void f(X<1518>);
+ void f(X<1519>);
+ void f(X<1520>);
+ void f(X<1521>);
+ void f(X<1522>);
+ void f(X<1523>);
+ void f(X<1524>);
+ void f(X<1525>);
+ void f(X<1526>);
+ void f(X<1527>);
+ void f(X<1528>);
+ void f(X<1529>);
+ void f(X<1530>);
+ void f(X<1531>);
+ void f(X<1532>);
+ void f(X<1533>);
+ void f(X<1534>);
+ void f(X<1535>);
+ void f(X<1536>);
+ void f(X<1537>);
+ void f(X<1538>);
+ void f(X<1539>);
+ void f(X<1540>);
+ void f(X<1541>);
+ void f(X<1542>);
+ void f(X<1543>);
+ void f(X<1544>);
+ void f(X<1545>);
+ void f(X<1546>);
+ void f(X<1547>);
+ void f(X<1548>);
+ void f(X<1549>);
+ void f(X<1550>);
+ void f(X<1551>);
+ void f(X<1552>);
+ void f(X<1553>);
+ void f(X<1554>);
+ void f(X<1555>);
+ void f(X<1556>);
+ void f(X<1557>);
+ void f(X<1558>);
+ void f(X<1559>);
+ void f(X<1560>);
+ void f(X<1561>);
+ void f(X<1562>);
+ void f(X<1563>);
+ void f(X<1564>);
+ void f(X<1565>);
+ void f(X<1566>);
+ void f(X<1567>);
+ void f(X<1568>);
+ void f(X<1569>);
+ void f(X<1570>);
+ void f(X<1571>);
+ void f(X<1572>);
+ void f(X<1573>);
+ void f(X<1574>);
+ void f(X<1575>);
+ void f(X<1576>);
+ void f(X<1577>);
+ void f(X<1578>);
+ void f(X<1579>);
+ void f(X<1580>);
+ void f(X<1581>);
+ void f(X<1582>);
+ void f(X<1583>);
+ void f(X<1584>);
+ void f(X<1585>);
+ void f(X<1586>);
+ void f(X<1587>);
+ void f(X<1588>);
+ void f(X<1589>);
+ void f(X<1590>);
+ void f(X<1591>);
+ void f(X<1592>);
+ void f(X<1593>);
+ void f(X<1594>);
+ void f(X<1595>);
+ void f(X<1596>);
+ void f(X<1597>);
+ void f(X<1598>);
+ void f(X<1599>);
+ void f(X<1600>);
+ void f(X<1601>);
+ void f(X<1602>);
+ void f(X<1603>);
+ void f(X<1604>);
+ void f(X<1605>);
+ void f(X<1606>);
+ void f(X<1607>);
+ void f(X<1608>);
+ void f(X<1609>);
+ void f(X<1610>);
+ void f(X<1611>);
+ void f(X<1612>);
+ void f(X<1613>);
+ void f(X<1614>);
+ void f(X<1615>);
+ void f(X<1616>);
+ void f(X<1617>);
+ void f(X<1618>);
+ void f(X<1619>);
+ void f(X<1620>);
+ void f(X<1621>);
+ void f(X<1622>);
+ void f(X<1623>);
+ void f(X<1624>);
+ void f(X<1625>);
+ void f(X<1626>);
+ void f(X<1627>);
+ void f(X<1628>);
+ void f(X<1629>);
+ void f(X<1630>);
+ void f(X<1631>);
+ void f(X<1632>);
+ void f(X<1633>);
+ void f(X<1634>);
+ void f(X<1635>);
+ void f(X<1636>);
+ void f(X<1637>);
+ void f(X<1638>);
+ void f(X<1639>);
+ void f(X<1640>);
+ void f(X<1641>);
+ void f(X<1642>);
+ void f(X<1643>);
+ void f(X<1644>);
+ void f(X<1645>);
+ void f(X<1646>);
+ void f(X<1647>);
+ void f(X<1648>);
+ void f(X<1649>);
+ void f(X<1650>);
+ void f(X<1651>);
+ void f(X<1652>);
+ void f(X<1653>);
+ void f(X<1654>);
+ void f(X<1655>);
+ void f(X<1656>);
+ void f(X<1657>);
+ void f(X<1658>);
+ void f(X<1659>);
+ void f(X<1660>);
+ void f(X<1661>);
+ void f(X<1662>);
+ void f(X<1663>);
+ void f(X<1664>);
+ void f(X<1665>);
+ void f(X<1666>);
+ void f(X<1667>);
+ void f(X<1668>);
+ void f(X<1669>);
+ void f(X<1670>);
+ void f(X<1671>);
+ void f(X<1672>);
+ void f(X<1673>);
+ void f(X<1674>);
+ void f(X<1675>);
+ void f(X<1676>);
+ void f(X<1677>);
+ void f(X<1678>);
+ void f(X<1679>);
+ void f(X<1680>);
+ void f(X<1681>);
+ void f(X<1682>);
+ void f(X<1683>);
+ void f(X<1684>);
+ void f(X<1685>);
+ void f(X<1686>);
+ void f(X<1687>);
+ void f(X<1688>);
+ void f(X<1689>);
+ void f(X<1690>);
+ void f(X<1691>);
+ void f(X<1692>);
+ void f(X<1693>);
+ void f(X<1694>);
+ void f(X<1695>);
+ void f(X<1696>);
+ void f(X<1697>);
+ void f(X<1698>);
+ void f(X<1699>);
+ void f(X<1700>);
+ void f(X<1701>);
+ void f(X<1702>);
+ void f(X<1703>);
+ void f(X<1704>);
+ void f(X<1705>);
+ void f(X<1706>);
+ void f(X<1707>);
+ void f(X<1708>);
+ void f(X<1709>);
+ void f(X<1710>);
+ void f(X<1711>);
+ void f(X<1712>);
+ void f(X<1713>);
+ void f(X<1714>);
+ void f(X<1715>);
+ void f(X<1716>);
+ void f(X<1717>);
+ void f(X<1718>);
+ void f(X<1719>);
+ void f(X<1720>);
+ void f(X<1721>);
+ void f(X<1722>);
+ void f(X<1723>);
+ void f(X<1724>);
+ void f(X<1725>);
+ void f(X<1726>);
+ void f(X<1727>);
+ void f(X<1728>);
+ void f(X<1729>);
+ void f(X<1730>);
+ void f(X<1731>);
+ void f(X<1732>);
+ void f(X<1733>);
+ void f(X<1734>);
+ void f(X<1735>);
+ void f(X<1736>);
+ void f(X<1737>);
+ void f(X<1738>);
+ void f(X<1739>);
+ void f(X<1740>);
+ void f(X<1741>);
+ void f(X<1742>);
+ void f(X<1743>);
+ void f(X<1744>);
+ void f(X<1745>);
+ void f(X<1746>);
+ void f(X<1747>);
+ void f(X<1748>);
+ void f(X<1749>);
+ void f(X<1750>);
+ void f(X<1751>);
+ void f(X<1752>);
+ void f(X<1753>);
+ void f(X<1754>);
+ void f(X<1755>);
+ void f(X<1756>);
+ void f(X<1757>);
+ void f(X<1758>);
+ void f(X<1759>);
+ void f(X<1760>);
+ void f(X<1761>);
+ void f(X<1762>);
+ void f(X<1763>);
+ void f(X<1764>);
+ void f(X<1765>);
+ void f(X<1766>);
+ void f(X<1767>);
+ void f(X<1768>);
+ void f(X<1769>);
+ void f(X<1770>);
+ void f(X<1771>);
+ void f(X<1772>);
+ void f(X<1773>);
+ void f(X<1774>);
+ void f(X<1775>);
+ void f(X<1776>);
+ void f(X<1777>);
+ void f(X<1778>);
+ void f(X<1779>);
+ void f(X<1780>);
+ void f(X<1781>);
+ void f(X<1782>);
+ void f(X<1783>);
+ void f(X<1784>);
+ void f(X<1785>);
+ void f(X<1786>);
+ void f(X<1787>);
+ void f(X<1788>);
+ void f(X<1789>);
+ void f(X<1790>);
+ void f(X<1791>);
+ void f(X<1792>);
+ void f(X<1793>);
+ void f(X<1794>);
+ void f(X<1795>);
+ void f(X<1796>);
+ void f(X<1797>);
+ void f(X<1798>);
+ void f(X<1799>);
+ void f(X<1800>);
+ void f(X<1801>);
+ void f(X<1802>);
+ void f(X<1803>);
+ void f(X<1804>);
+ void f(X<1805>);
+ void f(X<1806>);
+ void f(X<1807>);
+ void f(X<1808>);
+ void f(X<1809>);
+ void f(X<1810>);
+ void f(X<1811>);
+ void f(X<1812>);
+ void f(X<1813>);
+ void f(X<1814>);
+ void f(X<1815>);
+ void f(X<1816>);
+ void f(X<1817>);
+ void f(X<1818>);
+ void f(X<1819>);
+ void f(X<1820>);
+ void f(X<1821>);
+ void f(X<1822>);
+ void f(X<1823>);
+ void f(X<1824>);
+ void f(X<1825>);
+ void f(X<1826>);
+ void f(X<1827>);
+ void f(X<1828>);
+ void f(X<1829>);
+ void f(X<1830>);
+ void f(X<1831>);
+ void f(X<1832>);
+ void f(X<1833>);
+ void f(X<1834>);
+ void f(X<1835>);
+ void f(X<1836>);
+ void f(X<1837>);
+ void f(X<1838>);
+ void f(X<1839>);
+ void f(X<1840>);
+ void f(X<1841>);
+ void f(X<1842>);
+ void f(X<1843>);
+ void f(X<1844>);
+ void f(X<1845>);
+ void f(X<1846>);
+ void f(X<1847>);
+ void f(X<1848>);
+ void f(X<1849>);
+ void f(X<1850>);
+ void f(X<1851>);
+ void f(X<1852>);
+ void f(X<1853>);
+ void f(X<1854>);
+ void f(X<1855>);
+ void f(X<1856>);
+ void f(X<1857>);
+ void f(X<1858>);
+ void f(X<1859>);
+ void f(X<1860>);
+ void f(X<1861>);
+ void f(X<1862>);
+ void f(X<1863>);
+ void f(X<1864>);
+ void f(X<1865>);
+ void f(X<1866>);
+ void f(X<1867>);
+ void f(X<1868>);
+ void f(X<1869>);
+ void f(X<1870>);
+ void f(X<1871>);
+ void f(X<1872>);
+ void f(X<1873>);
+ void f(X<1874>);
+ void f(X<1875>);
+ void f(X<1876>);
+ void f(X<1877>);
+ void f(X<1878>);
+ void f(X<1879>);
+ void f(X<1880>);
+ void f(X<1881>);
+ void f(X<1882>);
+ void f(X<1883>);
+ void f(X<1884>);
+ void f(X<1885>);
+ void f(X<1886>);
+ void f(X<1887>);
+ void f(X<1888>);
+ void f(X<1889>);
+ void f(X<1890>);
+ void f(X<1891>);
+ void f(X<1892>);
+ void f(X<1893>);
+ void f(X<1894>);
+ void f(X<1895>);
+ void f(X<1896>);
+ void f(X<1897>);
+ void f(X<1898>);
+ void f(X<1899>);
+ void f(X<1900>);
+ void f(X<1901>);
+ void f(X<1902>);
+ void f(X<1903>);
+ void f(X<1904>);
+ void f(X<1905>);
+ void f(X<1906>);
+ void f(X<1907>);
+ void f(X<1908>);
+ void f(X<1909>);
+ void f(X<1910>);
+ void f(X<1911>);
+ void f(X<1912>);
+ void f(X<1913>);
+ void f(X<1914>);
+ void f(X<1915>);
+ void f(X<1916>);
+ void f(X<1917>);
+ void f(X<1918>);
+ void f(X<1919>);
+ void f(X<1920>);
+ void f(X<1921>);
+ void f(X<1922>);
+ void f(X<1923>);
+ void f(X<1924>);
+ void f(X<1925>);
+ void f(X<1926>);
+ void f(X<1927>);
+ void f(X<1928>);
+ void f(X<1929>);
+ void f(X<1930>);
+ void f(X<1931>);
+ void f(X<1932>);
+ void f(X<1933>);
+ void f(X<1934>);
+ void f(X<1935>);
+ void f(X<1936>);
+ void f(X<1937>);
+ void f(X<1938>);
+ void f(X<1939>);
+ void f(X<1940>);
+ void f(X<1941>);
+ void f(X<1942>);
+ void f(X<1943>);
+ void f(X<1944>);
+ void f(X<1945>);
+ void f(X<1946>);
+ void f(X<1947>);
+ void f(X<1948>);
+ void f(X<1949>);
+ void f(X<1950>);
+ void f(X<1951>);
+ void f(X<1952>);
+ void f(X<1953>);
+ void f(X<1954>);
+ void f(X<1955>);
+ void f(X<1956>);
+ void f(X<1957>);
+ void f(X<1958>);
+ void f(X<1959>);
+ void f(X<1960>);
+ void f(X<1961>);
+ void f(X<1962>);
+ void f(X<1963>);
+ void f(X<1964>);
+ void f(X<1965>);
+ void f(X<1966>);
+ void f(X<1967>);
+ void f(X<1968>);
+ void f(X<1969>);
+ void f(X<1970>);
+ void f(X<1971>);
+ void f(X<1972>);
+ void f(X<1973>);
+ void f(X<1974>);
+ void f(X<1975>);
+ void f(X<1976>);
+ void f(X<1977>);
+ void f(X<1978>);
+ void f(X<1979>);
+ void f(X<1980>);
+ void f(X<1981>);
+ void f(X<1982>);
+ void f(X<1983>);
+ void f(X<1984>);
+ void f(X<1985>);
+ void f(X<1986>);
+ void f(X<1987>);
+ void f(X<1988>);
+ void f(X<1989>);
+ void f(X<1990>);
+ void f(X<1991>);
+ void f(X<1992>);
+ void f(X<1993>);
+ void f(X<1994>);
+ void f(X<1995>);
+ void f(X<1996>);
+ void f(X<1997>);
+ void f(X<1998>);
+ void f(X<1999>);
+ void f(X<2000>);
+}
diff --git a/test/Modules/Inputs/def.h b/test/Modules/Inputs/def.h
index 6d06b08..eb7eb7e 100644
--- a/test/Modules/Inputs/def.h
+++ b/test/Modules/Inputs/def.h
@@ -8,4 +8,13 @@
}
@end
+@interface Def
+- defMethod;
+@end
+#ifdef __cplusplus
+class Def2 {
+public:
+ void func();
+};
+#endif
diff --git a/test/Modules/Inputs/diag_pragma.h b/test/Modules/Inputs/diag_pragma.h
new file mode 100644
index 0000000..a8f9589
--- /dev/null
+++ b/test/Modules/Inputs/diag_pragma.h
@@ -0,0 +1,3 @@
+#define DIAG_PRAGMA_MACRO 1
+
+#pragma clang diagnostic ignored "-Wparentheses"
diff --git a/test/Modules/Inputs/diamond.h b/test/Modules/Inputs/diamond.h
index 15b5290..1990b45 100644
--- a/test/Modules/Inputs/diamond.h
+++ b/test/Modules/Inputs/diamond.h
@@ -1 +1 @@
-@__experimental_modules_import diamond_bottom;
+@import diamond_bottom;
diff --git a/test/Modules/Inputs/diamond_bottom.h b/test/Modules/Inputs/diamond_bottom.h
index b45fa93..2a0a84e 100644
--- a/test/Modules/Inputs/diamond_bottom.h
+++ b/test/Modules/Inputs/diamond_bottom.h
@@ -1,4 +1,4 @@
-@__experimental_modules_import diamond_left;
-@__experimental_modules_import diamond_right;
+@import diamond_left;
+@import diamond_right;
char bottom(char *x);
diff --git a/test/Modules/Inputs/diamond_left.h b/test/Modules/Inputs/diamond_left.h
index cc406ab..fce2e48 100644
--- a/test/Modules/Inputs/diamond_left.h
+++ b/test/Modules/Inputs/diamond_left.h
@@ -1,4 +1,4 @@
-@__experimental_modules_import diamond_top;
+@import diamond_top;
float left(float *);
diff --git a/test/Modules/Inputs/diamond_right.h b/test/Modules/Inputs/diamond_right.h
index 2ba1d77..fa408ea 100644
--- a/test/Modules/Inputs/diamond_right.h
+++ b/test/Modules/Inputs/diamond_right.h
@@ -1,4 +1,4 @@
-@__experimental_modules_import diamond_top;
+@import diamond_top;
double right(double *);
diff --git a/test/Modules/Inputs/ignored_macros.h b/test/Modules/Inputs/ignored_macros.h
new file mode 100644
index 0000000..250b58c
--- /dev/null
+++ b/test/Modules/Inputs/ignored_macros.h
@@ -0,0 +1,8 @@
+struct Point {
+ double x, y;
+};
+
+#ifdef IGNORED
+int *has_ignored(void);
+#endif
+
diff --git a/test/Modules/Inputs/linkage-merge-bar.h b/test/Modules/Inputs/linkage-merge-bar.h
new file mode 100644
index 0000000..cc528f7
--- /dev/null
+++ b/test/Modules/Inputs/linkage-merge-bar.h
@@ -0,0 +1,3 @@
+#include <linkage-merge-foo.h>
+
+using ::g;
diff --git a/test/Modules/Inputs/linkage-merge-foo.h b/test/Modules/Inputs/linkage-merge-foo.h
new file mode 100644
index 0000000..9cb62d2
--- /dev/null
+++ b/test/Modules/Inputs/linkage-merge-foo.h
@@ -0,0 +1,2 @@
+int f();
+static int g(int);
diff --git a/test/Modules/Inputs/linkage-merge-sub.h b/test/Modules/Inputs/linkage-merge-sub.h
new file mode 100644
index 0000000..725cdd3
--- /dev/null
+++ b/test/Modules/Inputs/linkage-merge-sub.h
@@ -0,0 +1,11 @@
+extern int f0(int);
+extern int f1(int);
+static int f2(int);
+static int f3(int);
+
+extern int v0;
+extern int v1;
+static int v2;
+static int v3;
+
+typedef int T0;
diff --git a/test/Modules/Inputs/macros_left.h b/test/Modules/Inputs/macros_left.h
index cd05693..076b046 100644
--- a/test/Modules/Inputs/macros_left.h
+++ b/test/Modules/Inputs/macros_left.h
@@ -1,4 +1,4 @@
-@__experimental_modules_import macros_top;
+@import macros_top;
#define LEFT unsigned long
#undef TOP_LEFT_UNDEF
@@ -12,3 +12,5 @@
#define LEFT_RIGHT_DIFFERENT3 float
#define LEFT_RIGHT_DIFFERENT float
+
+#define FN_ADD(a,b) (a+b)
diff --git a/test/Modules/Inputs/macros_right.h b/test/Modules/Inputs/macros_right.h
index e16a64b..dbbd2c3 100644
--- a/test/Modules/Inputs/macros_right.h
+++ b/test/Modules/Inputs/macros_right.h
@@ -1,4 +1,4 @@
-@__experimental_modules_import macros_top;
+@import macros_top;
#define RIGHT unsigned short
@@ -15,3 +15,5 @@
#undef TOP_RIGHT_REDEF
#define TOP_RIGHT_REDEF float
+
+#define FN_ADD(x, y) (x+y)
diff --git a/test/Modules/Inputs/macros_top.h b/test/Modules/Inputs/macros_top.h
index 9c3f3c0..dd303ff 100644
--- a/test/Modules/Inputs/macros_top.h
+++ b/test/Modules/Inputs/macros_top.h
@@ -8,8 +8,8 @@
-
-
+#define TOP_RIGHT_REDEF float
+// The last definition will be exported from the sub-module.
#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 032241d..d20521f 100644
--- a/test/Modules/Inputs/module.map
+++ b/test/Modules/Inputs/module.map
@@ -37,10 +37,18 @@ module category_top { header "category_top.h" }
module category_left {
header "category_left.h"
export category_top
+
+ explicit module sub {
+ header "category_left_sub.h"
+ }
}
module category_right {
header "category_right.h"
export category_top
+
+ explicit module sub {
+ header "category_right_sub.h"
+ }
}
module category_bottom {
header "category_bottom.h"
@@ -63,6 +71,7 @@ module decldef {
module redecl_merge_top {
header "redecl-merge-top.h"
explicit module Explicit { header "redecl-merge-top-explicit.h" }
+ exclude header "nonexistent.h"
}
module redecl_merge_left {
header "redecl-merge-left.h"
@@ -77,6 +86,10 @@ module redecl_merge_right {
export *
}
module redecl_merge_bottom {
+ explicit module prefix {
+ header "redecl-merge-bottom-prefix.h"
+ }
+
header "redecl-merge-bottom.h"
export *
}
@@ -106,9 +119,21 @@ module templates_right {
}
module MethodPoolA {
header "MethodPoolA.h"
+
+ explicit module Sub2 {
+ header "MethodPoolASub2.h"
+ }
+
+ explicit module Sub {
+ header "MethodPoolASub.h"
+ }
}
module MethodPoolB {
header "MethodPoolB.h"
+
+ explicit module Sub {
+ header "MethodPoolBSub.h"
+ }
}
module import_decl {
header "import-decl.h"
@@ -117,3 +142,70 @@ module import_decl {
framework module * {
exclude NotAModule
}
+
+module linkage_merge_left {
+ explicit module sub {
+ header "linkage-merge-sub.h"
+ }
+}
+
+module autolink {
+ header "autolink.h"
+ link "autolink"
+
+ explicit module sub {
+ header "autolink-sub.h"
+ link "autolink_sub"
+ }
+
+ explicit module sub2 {
+ header "autolink-sub2.h"
+ link framework "autolink_framework"
+ }
+}
+
+module weird_objc {
+ header "weird_objc.h"
+}
+
+module ignored_macros {
+ header "ignored_macros.h"
+}
+
+module cxx_many_overloads {
+ header "cxx-many-overloads.h"
+}
+
+module cxx_inline_namespace {
+ header "cxx-inline-namespace.h"
+}
+
+module cxx_linkage_cache {
+ header "cxx-linkage-cache.h"
+}
+
+module config {
+ header "config.h"
+ config_macros [exhaustive] WANT_FOO, WANT_BAR
+}
+
+module diag_pragma {
+ header "diag_pragma.h"
+}
+
+module builtin {
+ header "builtin.h"
+ explicit module sub {
+ header "builtin_sub.h"
+ }
+}
+
+module linkage_merge {
+ explicit module foo {
+ header "linkage-merge-foo.h"
+ }
+ explicit module bar {
+ header "linkage-merge-bar.h"
+ }
+
+}
diff --git a/test/Modules/Inputs/namespaces-left.h b/test/Modules/Inputs/namespaces-left.h
index d253fed..bd192af 100644
--- a/test/Modules/Inputs/namespaces-left.h
+++ b/test/Modules/Inputs/namespaces-left.h
@@ -1,4 +1,11 @@
-@__experimental_modules_import namespaces_top;
+@import namespaces_top;
+
+float &global(float);
+float &global2(float);
+
+namespace LookupBeforeImport {
+ float &f(float);
+}
namespace N1 { }
diff --git a/test/Modules/Inputs/namespaces-right.h b/test/Modules/Inputs/namespaces-right.h
index 7e7286e..77f54ea 100644
--- a/test/Modules/Inputs/namespaces-right.h
+++ b/test/Modules/Inputs/namespaces-right.h
@@ -1,4 +1,11 @@
-@__experimental_modules_import namespaces_top;
+@import namespaces_top;
+
+double &global(double);
+double &global2(double);
+
+namespace LookupBeforeImport {
+ double &f(double);
+}
namespace N2 { }
diff --git a/test/Modules/Inputs/oldname/module.map b/test/Modules/Inputs/oldname/module.map
new file mode 100644
index 0000000..5812f86
--- /dev/null
+++ b/test/Modules/Inputs/oldname/module.map
@@ -0,0 +1,4 @@
+module NewName {
+ header "new_name.h"
+ export *
+}
diff --git a/test/Modules/Inputs/oldname/new_name.h b/test/Modules/Inputs/oldname/new_name.h
new file mode 100644
index 0000000..8bf2f1c
--- /dev/null
+++ b/test/Modules/Inputs/oldname/new_name.h
@@ -0,0 +1 @@
+int same_api;
diff --git a/test/Modules/Inputs/redecl-merge-bottom-prefix.h b/test/Modules/Inputs/redecl-merge-bottom-prefix.h
new file mode 100644
index 0000000..6501e1b
--- /dev/null
+++ b/test/Modules/Inputs/redecl-merge-bottom-prefix.h
@@ -0,0 +1,4 @@
+// A class that is declared in the 'bottom' module, then loaded from
+// one of the modules it depends on. It needs to be visible when this
+// module is loaded.
+@class DeclaredThenLoaded;
diff --git a/test/Modules/Inputs/redecl-merge-bottom.h b/test/Modules/Inputs/redecl-merge-bottom.h
index cfea7dc..b8fb179 100644
--- a/test/Modules/Inputs/redecl-merge-bottom.h
+++ b/test/Modules/Inputs/redecl-merge-bottom.h
@@ -1,11 +1,11 @@
-@__experimental_modules_import redecl_merge_left;
+@import redecl_merge_left;
@class C4;
@class C4;
@protocol P4;
@protocol P4;
@protocol P4;
-@__experimental_modules_import redecl_merge_right;
+@import redecl_merge_right;
@class B;
@@ -18,3 +18,8 @@ struct S3;
void refers_to_C4(C4*);
+@interface UnrelatedToDeclaredThenLoaded
+- declaredThenLoadedMethod;
+@end
+
+@class DeclaredThenLoaded;
diff --git a/test/Modules/Inputs/redecl-merge-left-left.h b/test/Modules/Inputs/redecl-merge-left-left.h
index 5f48883..79c4d62 100644
--- a/test/Modules/Inputs/redecl-merge-left-left.h
+++ b/test/Modules/Inputs/redecl-merge-left-left.h
@@ -1,4 +1,4 @@
-@__experimental_modules_import redecl_merge_left;
+@import redecl_merge_left;
@class C4;
void accept_a_C4(C4*);
diff --git a/test/Modules/Inputs/redecl-merge-left.h b/test/Modules/Inputs/redecl-merge-left.h
index 5e6d2e5..d66b4aa 100644
--- a/test/Modules/Inputs/redecl-merge-left.h
+++ b/test/Modules/Inputs/redecl-merge-left.h
@@ -1,4 +1,4 @@
-@__experimental_modules_import redecl_merge_top;
+@import redecl_merge_top;
@class A;
@@ -82,3 +82,12 @@ extern double var3;
// top level.
typedef void funcptr_with_id(int id);
+// A class that is declared in the 'bottom' module, then loaded from
+// one of the modules it depends on.
+@interface DeclaredThenLoaded
+- declaredThenLoadedMethod;
+@end
+
+@class DeclaredThenLoaded;
+
+void eventually_noreturn2(void);
diff --git a/test/Modules/Inputs/redecl-merge-right.h b/test/Modules/Inputs/redecl-merge-right.h
index 2022308..46a16d3 100644
--- a/test/Modules/Inputs/redecl-merge-right.h
+++ b/test/Modules/Inputs/redecl-merge-right.h
@@ -1,4 +1,4 @@
-@__experimental_modules_import redecl_merge_top;
+@import redecl_merge_top;
@interface Super
@end
@@ -79,9 +79,12 @@ extern int var2;
static double var3;
int ONE;
-@__experimental_modules_import redecl_merge_top.Explicit;
+@import redecl_merge_top.Explicit;
const int one = ONE;
@interface ClassWithDef
- (void)method;
@end
+
+void eventually_noreturn(void) __attribute__((noreturn));
+void eventually_noreturn2(void) __attribute__((noreturn));
diff --git a/test/Modules/Inputs/redecl-merge-top.h b/test/Modules/Inputs/redecl-merge-top.h
index 690e6df..27e71a7 100644
--- a/test/Modules/Inputs/redecl-merge-top.h
+++ b/test/Modules/Inputs/redecl-merge-top.h
@@ -16,3 +16,5 @@ struct S2;
struct S2;
int func1(int);
+
+void eventually_noreturn(void);
diff --git a/test/Modules/Inputs/templates-left.h b/test/Modules/Inputs/templates-left.h
index 57a8c85..7451420 100644
--- a/test/Modules/Inputs/templates-left.h
+++ b/test/Modules/Inputs/templates-left.h
@@ -1,4 +1,4 @@
-@__experimental_modules_import templates_top;
+@import templates_top;
template<typename T> class Vector;
diff --git a/test/Modules/Inputs/templates-right.h b/test/Modules/Inputs/templates-right.h
index 4ef4a32..d3524d3 100644
--- a/test/Modules/Inputs/templates-right.h
+++ b/test/Modules/Inputs/templates-right.h
@@ -1,4 +1,4 @@
-@__experimental_modules_import templates_top;
+@import templates_top;
template<typename T> class Vector {
public:
diff --git a/test/Modules/Inputs/weird_objc.h b/test/Modules/Inputs/weird_objc.h
new file mode 100644
index 0000000..8acaf74
--- /dev/null
+++ b/test/Modules/Inputs/weird_objc.h
@@ -0,0 +1 @@
+typedef struct objc_object { void *super; int wibble; } *id;
diff --git a/test/Modules/Inputs/wildcard-submodule-exports/C_one.h b/test/Modules/Inputs/wildcard-submodule-exports/C_one.h
index fb1c7de..e3b7593 100644
--- a/test/Modules/Inputs/wildcard-submodule-exports/C_one.h
+++ b/test/Modules/Inputs/wildcard-submodule-exports/C_one.h
@@ -1,4 +1,4 @@
-@__experimental_modules_import A.One;
-@__experimental_modules_import B.One;
+@import A.One;
+@import B.One;
long *C1;
diff --git a/test/Modules/Inputs/wildcard-submodule-exports/C_two.h b/test/Modules/Inputs/wildcard-submodule-exports/C_two.h
index 050a8f3..b65dcf6 100644
--- a/test/Modules/Inputs/wildcard-submodule-exports/C_two.h
+++ b/test/Modules/Inputs/wildcard-submodule-exports/C_two.h
@@ -1,4 +1,4 @@
-@__experimental_modules_import A.Two;
-@__experimental_modules_import B.Two;
+@import A.Two;
+@import B.Two;
unsigned long *C2;
diff --git a/test/Modules/auto-module-import.m b/test/Modules/auto-module-import.m
index fbd0a54..4bd3c52 100644
--- a/test/Modules/auto-module-import.m
+++ b/test/Modules/auto-module-import.m
@@ -1,7 +1,7 @@
// other file: expected-note{{'no_umbrella_A_private' declared here}}
// RUN: rm -rf %t
-// RUN: %clang_cc1 -Wauto-import -fmodule-cache-path %t -fmodules -F %S/Inputs %s -verify
+// RUN: %clang_cc1 -Wauto-import -fmodules-cache-path=%t -fmodules -F %S/Inputs %s -verify
#include <DependsOnModule/DependsOnModule.h> // expected-warning{{treating #include as an import of module 'DependsOnModule'}}
diff --git a/test/Modules/autolink.m b/test/Modules/autolink.m
new file mode 100644
index 0000000..7f75473
--- /dev/null
+++ b/test/Modules/autolink.m
@@ -0,0 +1,40 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -emit-llvm -o - -fmodules-cache-path=%t -fmodules -fmodules-autolink -F %S/Inputs -I %S/Inputs %s | FileCheck %s
+
+@import autolink.sub2;
+
+int f() {
+ return autolink_sub2();
+}
+
+@import autolink;
+
+int g() {
+ return autolink;
+}
+
+@import Module.SubFramework;
+const char *get_module_subframework() {
+ return module_subframework;
+}
+
+@import DependsOnModule.SubFramework;
+float *get_module_subframework_dep() {
+ return sub_framework;
+}
+
+@import NoUmbrella;
+int use_no_umbrella() {
+ return no_umbrella_A;
+}
+
+// NOTE: "autolink_sub" is intentionally not linked.
+
+// CHECK: !llvm.module.flags = !{!0, !1, !2, !3, !4}
+// CHECK: !4 = metadata !{i32 6, metadata !"Linker Options", metadata ![[AUTOLINK_OPTIONS:[0-9]+]]}
+// CHECK: ![[AUTOLINK_OPTIONS]] = metadata !{metadata ![[AUTOLINK_FRAMEWORK:[0-9]+]], metadata ![[AUTOLINK:[0-9]+]], metadata ![[DEPENDSONMODULE:[0-9]+]], metadata ![[MODULE:[0-9]+]], metadata ![[NOUMBRELLA:[0-9]+]]}
+// CHECK: ![[AUTOLINK_FRAMEWORK]] = metadata !{metadata !"-framework", metadata !"autolink_framework"}
+// CHECK: ![[AUTOLINK]] = metadata !{metadata !"-lautolink"}
+// CHECK: ![[DEPENDSONMODULE]] = metadata !{metadata !"-framework", metadata !"DependsOnModule"}
+// CHECK: ![[MODULE]] = metadata !{metadata !"-framework", metadata !"Module"}
+// CHECK: ![[NOUMBRELLA]] = metadata !{metadata !"-framework", metadata !"NoUmbrella"}
diff --git a/test/Modules/build-fail-notes.m b/test/Modules/build-fail-notes.m
new file mode 100644
index 0000000..8375788
--- /dev/null
+++ b/test/Modules/build-fail-notes.m
@@ -0,0 +1,31 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -F %S/Inputs -DgetModuleVersion="epic fail" %s 2>&1 | FileCheck %s
+
+@import DependsOnModule;
+
+// CHECK: While building module 'DependsOnModule' imported from
+// CHECK: While building module 'Module' imported from
+// CHECK: error: expected ';' after top level declarator
+// CHECK: note: expanded from here
+// CHECK: fatal error: could not build module 'Module'
+// CHECK: fatal error: could not build module 'DependsOnModule'
+// CHECK-NOT: error:
+
+// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -F %S/Inputs %s -fdiagnostics-show-note-include-stack 2>&1 | FileCheck -check-prefix=CHECK-REDEF %s
+extern int Module;
+
+// CHECK-REDEF: In module 'DependsOnModule' imported from
+// CHECK-REDEF: In module 'Module' imported from
+// CHECK-REDEF: Module.h:15:12: note: previous definition is here
+
+// RUN: not %clang_cc1 -fmodules-cache-path=%t -fmodules -F %S/Inputs -DgetModuleVersion="epic fail" -serialize-diagnostic-file %t/tmp.diag %s 2>&1
+// RUN: c-index-test -read-diagnostics %t/tmp.diag 2>&1 | FileCheck -check-prefix=CHECK-SDIAG %s
+
+// CHECK-SDIAG: Module.h:9:13: error: expected ';' after top level declarator
+// CHECK-SDIAG: build-fail-notes.m:4:9: note: while building module 'DependsOnModule' imported from
+// CHECK-SDIAG: DependsOnModule.h:1:10: note: while building module 'Module' imported from
+// CHECK-SDIAG: note: expanded from here
+// CHECK-SDIAG: warning: umbrella header for module 'Module' does not include header 'NotInModule.h' [-Wincomplete-umbrella]
+// CHECK-SDIAG: DependsOnModule.h:1:10: fatal: could not build module 'Module'
+// CHECK-SDIAG: build-fail-notes.m:4:9: note: while building module 'DependsOnModule' imported from
+
diff --git a/test/Modules/builtins.m b/test/Modules/builtins.m
new file mode 100644
index 0000000..40b4f9c
--- /dev/null
+++ b/test/Modules/builtins.m
@@ -0,0 +1,16 @@
+@import builtin;
+
+int foo() {
+ return __builtin_object_size(p, 0);
+}
+
+@import builtin.sub;
+
+int bar() {
+ return __builtin_object_size(p, 0);
+}
+
+
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -I %S/Inputs %s -verify
+// expected-no-diagnostics
diff --git a/test/Modules/compiler_builtins.m b/test/Modules/compiler_builtins.m
index dfa46c8..5ea7d79 100644
--- a/test/Modules/compiler_builtins.m
+++ b/test/Modules/compiler_builtins.m
@@ -1,12 +1,13 @@
// 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
+// RUN: %clang -fsyntax-only -fmodules -fmodules-cache-path=%t -D__need_wint_t %s -Xclang -verify
+// RUN: %clang -fsyntax-only -std=c99 -fmodules -fmodules-cache-path=%t -D__need_wint_t %s -Xclang -verify
// expected-no-diagnostics
+// XFAIL: win32
#ifdef __SSE__
-@__experimental_modules_import _Builtin_intrinsics.intel.sse;
+@import _Builtin_intrinsics.intel.sse;
#endif
#ifdef __AVX2__
-@__experimental_modules_import _Builtin_intrinsics.intel.avx2;
+@import _Builtin_intrinsics.intel.avx2;
#endif
diff --git a/test/Modules/config_macros.m b/test/Modules/config_macros.m
new file mode 100644
index 0000000..200744d
--- /dev/null
+++ b/test/Modules/config_macros.m
@@ -0,0 +1,28 @@
+@import config;
+
+int *test_foo() {
+ return foo();
+}
+
+char *test_bar() {
+ return bar(); // expected-warning{{implicit declaration of function 'bar' is invalid in C99}} \
+ // expected-warning{{incompatible integer to pointer conversion}}
+}
+
+#undef WANT_FOO // expected-note{{macro was #undef'd here}}
+@import config; // expected-warning{{#undef of configuration macro 'WANT_FOO' has no effect on the import of 'config'; pass '-UWANT_FOO' on the command line to configure the module}}
+
+#define WANT_FOO 2 // expected-note{{macro was defined here}}
+@import config; // expected-warning{{definition of configuration macro 'WANT_FOO' has no effect on the import of 'config'; pass '-DWANT_FOO=...' on the command line to configure the module}}
+
+#undef WANT_FOO
+#define WANT_FOO 1
+@import config; // okay
+
+#define WANT_BAR 1 // expected-note{{macro was defined here}}
+@import config; // expected-warning{{definition of configuration macro 'WANT_BAR' has no effect on the import of 'config'; pass '-DWANT_BAR=...' on the command line to configure the module}}
+
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -x objective-c -fmodules-cache-path=%t -DWANT_FOO=1 -emit-module -fmodule-name=config %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -DWANT_FOO=1 %s -verify
+
diff --git a/test/Modules/conflicts.m b/test/Modules/conflicts.m
new file mode 100644
index 0000000..2388e6f
--- /dev/null
+++ b/test/Modules/conflicts.m
@@ -0,0 +1,7 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -Wauto-import -fmodules-cache-path=%t -fmodules -I %S/Inputs/Conflicts %s -verify
+
+@import Conflicts;
+
+@import Conflicts.A; // expected-warning{{module 'Conflicts.A' conflicts with already-imported module 'Conflicts.B': we just don't like B}}
+
diff --git a/test/Modules/cstd.m b/test/Modules/cstd.m
index e262c7e..6d896a9 100644
--- a/test/Modules/cstd.m
+++ b/test/Modules/cstd.m
@@ -1,25 +1,25 @@
// RUN: rm -rf %t
-// RUN: %clang -fsyntax-only -isystem %S/Inputs/System/usr/include -fmodules -fmodule-cache-path %t -D__need_wint_t -Werror=implicit-function-declaration %s
+// RUN: %clang -fsyntax-only -isystem %S/Inputs/System/usr/include -fmodules -fmodules-cache-path=%t -D__need_wint_t -Werror=implicit-function-declaration %s
// Supplied by compiler, but referenced from the "/usr/include" module map.
-@__experimental_modules_import cstd.float_constants;
+@import cstd.float_constants;
float getFltMax() { return FLT_MAX; }
// Supplied by the "/usr/include" module map.
-@__experimental_modules_import cstd.stdio;
+@import cstd.stdio;
void test_fprintf(FILE *file) {
fprintf(file, "Hello, modules\n");
}
// Supplied by compiler, which forwards to the "/usr/include" version.
-@__experimental_modules_import cstd.stdint;
+@import cstd.stdint;
my_awesome_nonstandard_integer_type value;
// Supplied by the compiler; that version wins.
-@__experimental_modules_import cstd.stdbool;
+@import cstd.stdbool;
#ifndef bool
# error "bool was not defined!"
diff --git a/test/Modules/cxx-inline-namespace.cpp b/test/Modules/cxx-inline-namespace.cpp
new file mode 100644
index 0000000..5b96790
--- /dev/null
+++ b/test/Modules/cxx-inline-namespace.cpp
@@ -0,0 +1,6 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11
+
+@import cxx_inline_namespace;
+
+T x; // expected-error {{unknown type name 'T'}}
diff --git a/test/Modules/cxx-linkage-cache.cpp b/test/Modules/cxx-linkage-cache.cpp
new file mode 100644
index 0000000..296cc80
--- /dev/null
+++ b/test/Modules/cxx-linkage-cache.cpp
@@ -0,0 +1,8 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11
+
+@import cxx_linkage_cache;
+
+T x; // expected-error {{unknown type name 'T'}}
+D::U<int> u;
+bool b = f(u);
diff --git a/test/Modules/cxx-many-overloads.cpp b/test/Modules/cxx-many-overloads.cpp
new file mode 100644
index 0000000..205a79c
--- /dev/null
+++ b/test/Modules/cxx-many-overloads.cpp
@@ -0,0 +1,9 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs %s -verify
+
+// expected-no-diagnostics
+@import cxx_many_overloads;
+
+void g() {
+ f(N::X<0>());
+}
diff --git a/test/Modules/cycles.c b/test/Modules/cycles.c
index 256f118..4326e76 100644
--- a/test/Modules/cycles.c
+++ b/test/Modules/cycles.c
@@ -1,12 +1,13 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules -x objective-c -fmodule-cache-path %t -F %S/Inputs %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -fmodules -x objective-c -fmodules-cache-path=%t -F %S/Inputs %s 2>&1 | FileCheck %s
// FIXME: When we have a syntax for modules in C, use that.
-@__experimental_modules_import MutuallyRecursive1;
+@import MutuallyRecursive1;
-// FIXME: Lots of redundant diagnostics here, because the preprocessor
-// can't currently tell the parser not to try to load the module again.
-
-// CHECK: MutuallyRecursive2.h:3:32: fatal error: cyclic dependency in module 'MutuallyRecursive1': MutuallyRecursive1 -> MutuallyRecursive2 -> MutuallyRecursive1
-// CHECK: MutuallyRecursive1.h:2:32: fatal error: could not build module 'MutuallyRecursive2'
-// CHECK: cycles.c:4:32: fatal error: could not build module 'MutuallyRecursive1'
+// CHECK: While building module 'MutuallyRecursive1' imported from
+// CHECK: While building module 'MutuallyRecursive2' imported from
+// CHECK: MutuallyRecursive2.h:3:9: fatal error: cyclic dependency in module 'MutuallyRecursive1': MutuallyRecursive1 -> MutuallyRecursive2 -> MutuallyRecursive1
+// CHECK: While building module 'MutuallyRecursive1' imported from
+// CHECK: MutuallyRecursive1.h:2:9: fatal error: could not build module 'MutuallyRecursive2'
+// CHECK: cycles.c:4:9: fatal error: could not build module 'MutuallyRecursive1'
+// CHECK-NOT: error:
diff --git a/test/Modules/decldef.m b/test/Modules/decldef.m
new file mode 100644
index 0000000..7fb8a61
--- /dev/null
+++ b/test/Modules/decldef.m
@@ -0,0 +1,28 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fobjc-arc -I %S/Inputs -fmodules-cache-path=%t %s -verify
+
+
+// In other file: expected-note {{previous definition is here}}
+
+@class Def;
+Def *def;
+
+@import decldef;
+A *a1; // expected-error{{unknown type name 'A'}}
+B *b1; // expected-error{{must use 'struct' tag to refer to type 'B'}}
+@import decldef.Decl;
+
+A *a2;
+struct B *b;
+
+void testA(A *a) {
+ a->ivar = 17; // expected-error{{definition of 'A' must be imported from module 'decldef.Def' before it is required}}
+}
+
+void testB() {
+ B b; // Note: redundant error silenced
+}
+
+void testDef() {
+ [def defMethod];
+}
diff --git a/test/Modules/decldef.mm b/test/Modules/decldef.mm
index 64a66d5..732c2a2 100644
--- a/test/Modules/decldef.mm
+++ b/test/Modules/decldef.mm
@@ -1,28 +1,38 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules -I %S/Inputs -fmodule-cache-path %t %s -verify
+// RUN: %clang_cc1 -fmodules -fobjc-arc -I %S/Inputs -fmodules-cache-path=%t %s -verify
-// in other file: expected-note{{previous definition is here}}
+// In other file: expected-note {{previous definition is here}}
+@class Def;
+Def *def;
+class Def2;
+Def2 *def2;
+@interface Unrelated
+- defMethod;
+@end
-
-
-// in other file: expected-note{{previous definition is here}}
-
-@__experimental_modules_import decldef;
+@import decldef;
A *a1; // expected-error{{unknown type name 'A'}}
B *b1; // expected-error{{unknown type name 'B'}}
-@__experimental_modules_import decldef.Decl;
+@import decldef.Decl;
A *a2;
B *b;
void testA(A *a) {
- a->ivar = 17; // expected-error{{definition of 'A' must be imported before it is required}}
+ a->ivar = 17; // expected-error{{definition of 'A' must be imported from module 'decldef.Def' before it is required}}
}
void testB() {
- B b; // expected-error{{definition of 'B' must be imported before it is required}}
- B b2; // Note: the reundant error was silenced.
+ B b; // Note: redundant error silenced
+}
+
+void testDef() {
+ [def defMethod];
+}
+
+void testDef2() {
+ def2->func();
}
diff --git a/test/Modules/diag-pragma.c b/test/Modules/diag-pragma.c
new file mode 100644
index 0000000..7ec3400
--- /dev/null
+++ b/test/Modules/diag-pragma.c
@@ -0,0 +1,13 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodules-cache-path=%t -fmodule-name=diag_pragma %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -verify -fmodules-cache-path=%t %s
+// FIXME: When we have a syntax for modules in C, use that.
+
+@import diag_pragma;
+
+int foo(int x) {
+ if (x = DIAG_PRAGMA_MACRO) // expected-warning {{using the result of an assignment as a condition without parentheses}} \
+ // expected-note {{place parentheses}} expected-note {{use '=='}}
+ return 0;
+ return 1;
+}
diff --git a/test/Modules/diamond-pch.c b/test/Modules/diamond-pch.c
index 4397c19..079f6af 100644
--- a/test/Modules/diamond-pch.c
+++ b/test/Modules/diamond-pch.c
@@ -19,10 +19,10 @@ void test_diamond(int i, float f, double d, char c) {
}
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodule-cache-path %t -fmodule-name=diamond_top %S/Inputs/module.map
-// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodule-cache-path %t -fmodule-name=diamond_left %S/Inputs/module.map
-// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodule-cache-path %t -fmodule-name=diamond_right %S/Inputs/module.map
-// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodule-cache-path %t -fmodule-name=diamond_bottom %S/Inputs/module.map
-// RUN: %clang_cc1 -fmodules -x objective-c -emit-pch -fmodule-cache-path %t -o %t.pch %S/Inputs/diamond.h
-// RUN: %clang_cc1 -fmodules -x objective-c -fmodule-cache-path %t -include-pch %t.pch %s -verify
+// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodules-cache-path=%t -fmodule-name=diamond_top %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodules-cache-path=%t -fmodule-name=diamond_left %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodules-cache-path=%t -fmodule-name=diamond_right %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodules-cache-path=%t -fmodule-name=diamond_bottom %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -emit-pch -fmodules-cache-path=%t -o %t.pch %S/Inputs/diamond.h
+// RUN: %clang_cc1 -fmodules -x objective-c -fmodules-cache-path=%t -include-pch %t.pch %s -verify
// FIXME: When we have a syntax for modules in C, use that.
diff --git a/test/Modules/diamond.c b/test/Modules/diamond.c
index 076eec4..0bac1b7 100644
--- a/test/Modules/diamond.c
+++ b/test/Modules/diamond.c
@@ -3,7 +3,7 @@
// in diamond-bottom.h: expected-note{{passing argument to parameter 'x' here}}
-@__experimental_modules_import diamond_bottom;
+@import diamond_bottom;
void test_diamond(int i, float f, double d, char c) {
top(&i);
@@ -21,9 +21,9 @@ void test_diamond(int i, float f, double d, char c) {
}
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodule-cache-path %t -fmodule-name=diamond_top %S/Inputs/module.map
-// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodule-cache-path %t -fmodule-name=diamond_left %S/Inputs/module.map
-// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodule-cache-path %t -fmodule-name=diamond_right %S/Inputs/module.map
-// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodule-cache-path %t -fmodule-name=diamond_bottom %S/Inputs/module.map
-// RUN: %clang_cc1 -fmodules -x objective-c -fmodule-cache-path %t %s -verify
+// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodules-cache-path=%t -fmodule-name=diamond_top %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodules-cache-path=%t -fmodule-name=diamond_left %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodules-cache-path=%t -fmodule-name=diamond_right %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodules-cache-path=%t -fmodule-name=diamond_bottom %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -fmodules-cache-path=%t %s -verify
// FIXME: When we have a syntax for modules in C, use that.
diff --git a/test/Modules/direct-module-import.m b/test/Modules/direct-module-import.m
index 317d7ae..00c13fa 100644
--- a/test/Modules/direct-module-import.m
+++ b/test/Modules/direct-module-import.m
@@ -1,5 +1,5 @@
// 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
+// RUN: %clang_cc1 -fmodules-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) {
diff --git a/test/Modules/driver.c b/test/Modules/driver.c
index de10cd0..08fdaab 100644
--- a/test/Modules/driver.c
+++ b/test/Modules/driver.c
@@ -1,6 +1,6 @@
-// RUN: %clang %s -### 2>&1 | FileCheck -check-prefix NO_MODULE_CACHE %s
-// RUN: %clang -fmodule-cache-path blarg %s -### 2>&1 | FileCheck -check-prefix WITH_MODULE_CACHE %s
+// RUN: %clang -fmodules %s -### 2>&1 | FileCheck -check-prefix NO_MODULE_CACHE %s
+// RUN: %clang -fmodules -fmodules-cache-path=blarg %s -### 2>&1 | FileCheck -check-prefix WITH_MODULE_CACHE %s
-// CHECK-NO_MODULE_CACHE: {{clang.*"-fmodule-cache-path"}}
+// CHECK-NO_MODULE_CACHE: {{clang.*"-fmodules-cache-path=.*ModuleCache"}}
-// CHECK-WITH_MODULE_CACHE: {{clang.*"-fmodule-cache-path" "blarg"}}
+// CHECK-WITH_MODULE_CACHE: {{clang.*"-fmodules-cache-path=blarg"}}
diff --git a/test/Modules/epic-fail.m b/test/Modules/epic-fail.m
new file mode 100644
index 0000000..8969149
--- /dev/null
+++ b/test/Modules/epic-fail.m
@@ -0,0 +1,13 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -F %S/Inputs -DgetModuleVersion="epic fail" %s 2>&1 | FileCheck %s
+
+@import Module;
+@import DependsOnModule;
+
+// CHECK: While building module 'Module' imported from
+// CHECK: error: expected ';' after top level declarator
+// CHECK: note: expanded from here
+// CHECK: fatal error: could not build module 'Module'
+// CHECK: While building module 'DependsOnModule' imported from
+// CHECK: fatal error: could not build module 'Module'
+// CHECK-NOT: error:
diff --git a/test/Modules/global_index.m b/test/Modules/global_index.m
new file mode 100644
index 0000000..b255b63
--- /dev/null
+++ b/test/Modules/global_index.m
@@ -0,0 +1,19 @@
+// RUN: rm -rf %t
+// Run without global module index
+// RUN: %clang_cc1 -Wauto-import -fmodules-cache-path=%t -fdisable-module-hash -fmodules -fno-modules-global-index -F %S/Inputs %s -verify
+// RUN: ls %t|not grep modules.idx
+// Run and create the global module index
+// RUN: %clang_cc1 -Wauto-import -fmodules-cache-path=%t -fdisable-module-hash -fmodules -F %S/Inputs %s -verify
+// RUN: ls %t|grep modules.idx
+// Run and use the global module index
+// RUN: %clang_cc1 -Wauto-import -fmodules-cache-path=%t -fdisable-module-hash -fmodules -F %S/Inputs %s -verify -print-stats 2>&1 | FileCheck %s
+
+// expected-no-diagnostics
+@import DependsOnModule;
+@import Module;
+
+// CHECK: *** Global Module Index Statistics:
+
+int *get_sub() {
+ return Module_Sub;
+}
diff --git a/test/Modules/header-import.m b/test/Modules/header-import.m
index 49549d0..baeb1d3 100644
--- a/test/Modules/header-import.m
+++ b/test/Modules/header-import.m
@@ -1,8 +1,8 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t -F %S/Inputs -I %S/Inputs -verify %s
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -F %S/Inputs -I %S/Inputs -verify %s
// expected-no-diagnostics
#import "point.h"
-@__experimental_modules_import Module;
+@import Module;
#import "point.h"
diff --git a/test/Modules/ignored_macros.m b/test/Modules/ignored_macros.m
new file mode 100644
index 0000000..e8ee50a
--- /dev/null
+++ b/test/Modules/ignored_macros.m
@@ -0,0 +1,49 @@
+// First trial: pass -DIGNORED=1 to both. This should obviously work.
+// RUN: rm -rf %t.modules
+// RUN: %clang_cc1 -fmodules-cache-path=%t.modules -DIGNORED=1 -fmodules -I %S/Inputs -emit-pch -o %t.pch -x objective-c-header %s -verify
+// RUN: %clang_cc1 -fmodules-cache-path=%t.modules -DIGNORED=1 -fmodules -I %S/Inputs -include-pch %t.pch %s -verify
+
+// Second trial: pass -DIGNORED=1 only to the second invocation. We
+// should detect the failure.
+//
+// RUN: rm -rf %t.modules
+// RUN: %clang_cc1 -fmodules-cache-path=%t.modules -fmodules -I %S/Inputs -emit-pch -o %t.pch -x objective-c-header %s -verify
+// RUN: not %clang_cc1 -fmodules-cache-path=%t.modules -DIGNORED=1 -fmodules -I %S/Inputs -include-pch %t.pch %s > %t.err 2>&1
+// RUN: FileCheck -check-prefix=CHECK-CONFLICT %s < %t.err
+// CHECK-CONFLICT: module 'ignored_macros' found in both
+
+// Third trial: pass -DIGNORED=1 only to the second invocation, but
+// make it ignored. There should be no failure, IGNORED is defined in
+// the translation unit but not the module.
+// RUN: rm -rf %t.modules
+// RUN: %clang_cc1 -fmodules-cache-path=%t.modules -fmodules -I %S/Inputs -emit-pch -o %t.pch -x objective-c-header %s -verify
+// RUN: %clang_cc1 -fmodules-cache-path=%t.modules -DIGNORED=1 -fmodules -I %S/Inputs -include-pch %t.pch -fmodules-ignore-macro=IGNORED %s -verify
+
+// Fourth trial: pass -DIGNORED=1 and -fmodules-ignore-macro=IGNORED
+// to both invocations, so modules will be built without the IGNORED
+// macro.
+// RUN: rm -rf %t.modules
+// RUN: %clang_cc1 -fmodules-cache-path=%t.modules -DIGNORED=1 -fmodules-ignore-macro=IGNORED -fmodules -I %S/Inputs -emit-pch -o %t.pch -x objective-c-header %s -verify
+// RUN: %clang_cc1 -fmodules-cache-path=%t.modules -DIGNORED=1 -fmodules -I %S/Inputs -include-pch %t.pch -fmodules-ignore-macro=IGNORED -DNO_IGNORED_ANYWHERE -fmodules-ignore-macro=NO_IGNORED_ANYWHERE %s -verify
+
+// Fifth trial: pass -DIGNORED=1 and -fmodules-ignore-macro=IGNORED=1
+// to both invocations, so modules will be built without the IGNORED
+// macro.
+// RUN: rm -rf %t.modules
+// RUN: %clang_cc1 -fmodules-cache-path=%t.modules -DIGNORED=1 -fmodules-ignore-macro=IGNORED=1 -fmodules -I %S/Inputs -emit-pch -o %t.pch -x objective-c-header %s -verify
+// RUN: %clang_cc1 -fmodules-cache-path=%t.modules -DIGNORED=1 -fmodules -I %S/Inputs -include-pch %t.pch -fmodules-ignore-macro=IGNORED=1 -DNO_IGNORED_ANYWHERE -fmodules-ignore-macro=NO_IGNORED_ANYWHERE %s -verify
+
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+@import ignored_macros;
+#endif
+
+@import ignored_macros;
+
+struct Point p;
+
+#ifdef NO_IGNORED_ANYWHERE
+void *has_ignored(int, int, int);
+#endif
diff --git a/test/Modules/import-decl.cpp b/test/Modules/import-decl.cpp
index 0f05f92..900e090 100644
--- a/test/Modules/import-decl.cpp
+++ b/test/Modules/import-decl.cpp
@@ -1,8 +1,8 @@
// 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 -fmodules-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
-@__experimental_modules_import import_decl;
+@import import_decl;
// CHECK: struct T
int main() {
diff --git a/test/Modules/inferred-frameworks.m b/test/Modules/inferred-frameworks.m
index 916c900..372e4f2 100644
--- a/test/Modules/inferred-frameworks.m
+++ b/test/Modules/inferred-frameworks.m
@@ -1,8 +1,8 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -x objective-c -Wauto-import -fmodule-cache-path %t -fmodules -F %S/Inputs %s -verify
+// RUN: %clang_cc1 -x objective-c -Wauto-import -fmodules-cache-path=%t -fmodules -F %S/Inputs %s -verify
#include <NotAModule/NotAModule.h>
-@__experimental_modules_import NotAModule; // expected-error{{module 'NotAModule' not found}}
+@import NotAModule; // expected-error{{module 'NotAModule' not found}}
diff --git a/test/Modules/inferred-submodules.m b/test/Modules/inferred-submodules.m
index 8c61bc0..f801d04 100644
--- a/test/Modules/inferred-submodules.m
+++ b/test/Modules/inferred-submodules.m
@@ -1,14 +1,14 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -x objective-c -Wauto-import -fmodule-cache-path %t -fmodules -F %S/Inputs %s -verify
+// RUN: %clang_cc1 -x objective-c -Wauto-import -fmodules-cache-path=%t -fmodules -F %S/Inputs %s -verify
// expected-no-diagnostics
-@__experimental_modules_import Module.Sub;
+@import Module.Sub;
void test_Module_Sub() {
int *ip = Module_Sub;
}
-@__experimental_modules_import Module.Buried.Treasure;
+@import Module.Buried.Treasure;
void dig() {
unsigned *up = Buried_Treasure;
diff --git a/test/Modules/irgen.c b/test/Modules/irgen.c
index 4a080db..9a7cf7e 100644
--- a/test/Modules/irgen.c
+++ b/test/Modules/irgen.c
@@ -1,9 +1,9 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules -x objective-c -fmodule-cache-path %t -emit-module -fmodule-name=irgen -triple x86_64-apple-darwin10 %S/Inputs/module.map
-// RUN: %clang_cc1 -fmodules -x objective-c -fmodule-cache-path %t -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -fmodules -x objective-c -fmodules-cache-path=%t -emit-module -fmodule-name=irgen -triple x86_64-apple-darwin10 %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -fmodules-cache-path=%t -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
// FIXME: When we have a syntax for modules in C, use that.
-@__experimental_modules_import irgen;
+@import irgen;
// CHECK: define void @triple_value
void triple_value(int *px) {
diff --git a/test/Modules/linkage-merge.cpp b/test/Modules/linkage-merge.cpp
new file mode 100644
index 0000000..4e2ecef
--- /dev/null
+++ b/test/Modules/linkage-merge.cpp
@@ -0,0 +1,13 @@
+// FIXME: we should be able to put these in the .h file :-(
+// expected-note {{target of using declaration}}
+// expected-note {{using declaration}}
+
+#include "linkage-merge-bar.h"
+
+static int f(int);
+int f(int);
+
+static void g(int); // expected-error {{declaration conflicts with target of using declaration already in scope}}
+
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -verify -fmodules -fmodules-cache-path=%t -I %S/Inputs %s
diff --git a/test/Modules/linkage-merge.m b/test/Modules/linkage-merge.m
new file mode 100644
index 0000000..16e2205
--- /dev/null
+++ b/test/Modules/linkage-merge.m
@@ -0,0 +1,27 @@
+// In module: expected-note{{previous declaration}}
+
+
+
+
+// In module: expected-note{{previous definition is here}}
+
+// Test redeclarations of functions where the original declaration is
+// still hidden.
+
+@import linkage_merge_left; // excludes "sub"
+
+extern int f0(float); // expected-error{{conflicting types for 'f0'}}
+static int f1(float); // okay: considered distinct
+static int f2(float); // okay: considered distinct
+extern int f3(float); // okay: considered distinct
+
+extern float v0; // expected-error{{redefinition of 'v0' with a different type: 'float' vs 'int'}}
+static float v1;
+static float v2;
+extern float v3;
+
+typedef float T0;
+
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -x objective-c -fmodules-cache-path=%t -emit-module -fmodule-name=linkage_merge_left %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -w %s -verify
diff --git a/test/Modules/load_failure.c b/test/Modules/load_failure.c
index 3a96301..6f9426a 100644
--- a/test/Modules/load_failure.c
+++ b/test/Modules/load_failure.c
@@ -1,17 +1,17 @@
#ifdef NONEXISTENT
-@__experimental_modules_import load_nonexistent;
+@import load_nonexistent;
#endif
#ifdef FAILURE
-@__experimental_modules_import load_failure;
+@import load_failure;
#endif
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules -x objective-c++ -fmodule-cache-path %t -fdisable-module-hash -emit-module -fmodule-name=load_failure %S/Inputs/module.map
-// RUN: %clang_cc1 -fmodules -x objective-c -fmodule-cache-path %t -fdisable-module-hash %s -DNONEXISTENT 2>&1 | FileCheck -check-prefix=CHECK-NONEXISTENT %s
-// CHECK-NONEXISTENT: load_failure.c:2:32: fatal error: module 'load_nonexistent' not found
+// RUN: %clang_cc1 -fmodules -x objective-c++ -fmodules-cache-path=%t -fdisable-module-hash -emit-module -fmodule-name=load_failure %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -fmodules-cache-path=%t -fdisable-module-hash %s -DNONEXISTENT 2>&1 | FileCheck -check-prefix=CHECK-NONEXISTENT %s
+// CHECK-NONEXISTENT: load_failure.c:2:9: fatal error: module 'load_nonexistent' not found
-// RUN: not %clang_cc1 -fmodules -x objective-c -fmodule-cache-path %t -fdisable-module-hash %s -DFAILURE 2> %t.out
+// RUN: not %clang_cc1 -fmodules -x objective-c -fmodules-cache-path=%t -fdisable-module-hash %s -DFAILURE 2> %t.out
// RUN: FileCheck -check-prefix=CHECK-FAILURE %s < %t.out
// FIXME: Clean up diagnostic text below and give it a location
diff --git a/test/Modules/lookup.cpp b/test/Modules/lookup.cpp
index 70d2107..002b6d1 100644
--- a/test/Modules/lookup.cpp
+++ b/test/Modules/lookup.cpp
@@ -1,8 +1,8 @@
-#define import @__experimental_modules_import
+#define import @import
import lookup_left_cxx;
#undef import
-#define IMPORT(X) @__experimental_modules_import X
+#define IMPORT(X) @import X
IMPORT(lookup_right_cxx);
// in lookup_left.hpp: expected-warning@3 {{weak identifier 'weak_identifier' never declared}}
@@ -24,10 +24,10 @@ void f() {
}
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules -x objective-c++ -emit-module -fmodule-cache-path %t -fmodule-name=lookup_left_cxx %S/Inputs/module.map -verify
-// RUN: %clang_cc1 -fmodules -x objective-c++ -emit-module -fmodule-cache-path %t -fmodule-name=lookup_right_cxx %S/Inputs/module.map -verify
-// RUN: %clang_cc1 -fmodules -x objective-c++ -fmodule-cache-path %t %s -verify
-// RUN: %clang_cc1 -fmodules -ast-print -x objective-c++ -fmodule-cache-path %t %s | FileCheck -check-prefix=CHECK-PRINT %s
+// RUN: %clang_cc1 -fmodules -x objective-c++ -emit-module -fmodules-cache-path=%t -fmodule-name=lookup_left_cxx %S/Inputs/module.map -verify
+// RUN: %clang_cc1 -fmodules -x objective-c++ -emit-module -fmodules-cache-path=%t -fmodule-name=lookup_right_cxx %S/Inputs/module.map -verify
+// RUN: %clang_cc1 -fmodules -x objective-c++ -fmodules-cache-path=%t %s -verify
+// RUN: %clang_cc1 -fmodules -ast-print -x objective-c++ -fmodules-cache-path=%t %s | FileCheck -check-prefix=CHECK-PRINT %s
// FIXME: When we have a syntax for modules in C++, use that.
// CHECK-PRINT: int *f0(int *);
diff --git a/test/Modules/lookup.m b/test/Modules/lookup.m
index c82503f..abe9542 100644
--- a/test/Modules/lookup.m
+++ b/test/Modules/lookup.m
@@ -1,18 +1,18 @@
// lookup_left.h: expected-note{{using}}
// lookup_right.h: expected-note{{also found}}
-@__experimental_modules_import lookup_left_objc;
-@__experimental_modules_import lookup_right_objc;
+@import lookup_left_objc;
+@import lookup_right_objc;
void test(id x) {
[x method]; // expected-warning{{multiple methods named 'method' found}}
}
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t -emit-module -x objective-c -fmodule-name=lookup_left_objc %S/Inputs/module.map
-// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t -emit-module -x objective-c -fmodule-name=lookup_right_objc %S/Inputs/module.map
-// RUN: %clang_cc1 -fmodules -x objective-c -fmodule-cache-path %t -verify %s
-// RUN: %clang_cc1 -fmodules -ast-print -x objective-c -fmodule-cache-path %t %s | FileCheck -check-prefix=CHECK-PRINT %s
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -emit-module -x objective-c -fmodule-name=lookup_left_objc %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -emit-module -x objective-c -fmodule-name=lookup_right_objc %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -fmodules-cache-path=%t -verify %s
+// RUN: %clang_cc1 -fmodules -ast-print -x objective-c -fmodules-cache-path=%t %s | FileCheck -check-prefix=CHECK-PRINT %s
// CHECK-PRINT: - (int) method;
// CHECK-PRINT: - (double) method
diff --git a/test/Modules/macros.c b/test/Modules/macros.c
index 8db3915..fc448d9 100644
--- a/test/Modules/macros.c
+++ b/test/Modules/macros.c
@@ -1,22 +1,22 @@
// 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
+// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodules-cache-path=%t -fmodule-name=macros_top %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodules-cache-path=%t -fmodule-name=macros_left %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodules-cache-path=%t -fmodule-name=macros_right %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -emit-module -fmodules-cache-path=%t -fmodule-name=macros %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -verify -fmodules-cache-path=%t %s
+// RUN: %clang_cc1 -E -fmodules -x objective-c -fmodules-cache-path=%t %s | FileCheck -check-prefix CHECK-PREPROCESSED %s
// 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}}
+// FIXME: expected-note{{previous definition is here}} expected-note{{expanding this definition of 'LEFT_RIGHT_DIFFERENT'}}
+// expected-note{{other definition of 'TOP_RIGHT_REDEF'}} expected-note{{expanding this definition of 'LEFT_RIGHT_DIFFERENT2'}}
// 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;
+// expected-note{{expanding this definition of 'TOP_RIGHT_REDEF'}}
+
+@import macros;
#ifndef INTEGER
# error INTEGER macro should be visible
@@ -65,7 +65,7 @@ void f() {
#endif
// Import left module (which also imports top)
-@__experimental_modules_import macros_left;
+@import macros_left;
#ifndef LEFT
# error LEFT should be visible
@@ -79,8 +79,8 @@ void f() {
# error TOP should be visible
#endif
-#ifdef TOP_LEFT_UNDEF
-# error TOP_LEFT_UNDEF should not be visible
+#ifndef TOP_LEFT_UNDEF
+# error TOP_LEFT_UNDEF should still be defined
#endif
void test1() {
@@ -88,10 +88,11 @@ void test1() {
TOP_RIGHT_REDEF *ip = &i;
}
-#define LEFT_RIGHT_DIFFERENT2 double // FIXME: expected-warning{{'LEFT_RIGHT_DIFFERENT2' macro redefined}}
+#define LEFT_RIGHT_DIFFERENT2 double // FIXME: expected-warning{{'LEFT_RIGHT_DIFFERENT2' macro redefined}} \
+ // expected-note{{other definition of 'LEFT_RIGHT_DIFFERENT2'}}
// Import right module (which also imports top)
-@__experimental_modules_import macros_right;
+@import macros_right;
#undef LEFT_RIGHT_DIFFERENT3
@@ -111,11 +112,11 @@ void test2() {
int i;
float f;
double d;
- TOP_RIGHT_REDEF *ip = &i; // expected-warning{{ambiguous expansion of macro 'TOP_RIGHT_REDEF'}}
+ TOP_RIGHT_REDEF *fp = &f; // 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;
+ LEFT_RIGHT_IDENTICAL *ip = &i;
+ LEFT_RIGHT_DIFFERENT *ip2 = &i; // expected-warning{{ambiguous expansion of macro 'LEFT_RIGHT_DIFFERENT'}}
+ LEFT_RIGHT_DIFFERENT2 *ip3 = &i; // expected-warning{{ambiguous expansion of macro 'LEFT_RIGHT_DIFFERENT2}}
int LEFT_RIGHT_DIFFERENT3;
}
@@ -124,14 +125,15 @@ void test2() {
void test3() {
double d;
LEFT_RIGHT_DIFFERENT *dp = &d; // okay
+ int x = FN_ADD(1,2);
}
#ifndef TOP_RIGHT_UNDEF
# error TOP_RIGHT_UNDEF should still be defined
#endif
-@__experimental_modules_import macros_right.undef;
+@import macros_right.undef;
-#ifdef TOP_RIGHT_UNDEF
-# error TOP_RIGHT_UNDEF should not be defined
+#ifndef TOP_RIGHT_UNDEF
+# error TOP_RIGHT_UNDEF should still be defined
#endif
diff --git a/test/Modules/method_pool.m b/test/Modules/method_pool.m
index 25582ca..9a8897b 100644
--- a/test/Modules/method_pool.m
+++ b/test/Modules/method_pool.m
@@ -1,15 +1,15 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodule-cache-path %t -fmodules -I %S/Inputs %s -verify
+// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -I %S/Inputs %s -verify
-@__experimental_modules_import MethodPoolA;
+@import MethodPoolA;
-// in other file: // expected-note{{using}}
+@interface D
+- (void)method5:(D*)obj;
+@end
-
-
-
-// in other file: expected-note{{also found}}
+// in other file: // expected-note@7{{using}}
+// in other file: expected-note@12{{also found}}
void testMethod1(id object) {
[object method1];
@@ -19,7 +19,15 @@ void testMethod2(id object) {
[object method2:1];
}
-@__experimental_modules_import MethodPoolB;
+void testMethod4(id object) {
+ [object method4]; // expected-warning{{instance method '-method4' not found (return type defaults to 'id')}}
+}
+
+void testMethod5(id object, D* d) {
+ [object method5:d];
+}
+
+@import MethodPoolB;
void testMethod1Again(id object) {
[object method1];
@@ -28,3 +36,29 @@ void testMethod1Again(id object) {
void testMethod2Again(id object) {
[object method2:1]; // expected-warning{{multiple methods named 'method2:' found}}
}
+
+void testMethod3(id object) {
+ [object method3]; // expected-warning{{instance method '-method3' not found (return type defaults to 'id')}}
+}
+
+@import MethodPoolB.Sub;
+
+void testMethod3Again(id object) {
+ char *str = [object method3]; // okay: only found in MethodPoolB.Sub
+}
+
+@import MethodPoolA.Sub;
+
+void testMethod3AgainAgain(id object) {
+ [object method3]; // expected-warning{{multiple methods named 'method3' found}}
+ // expected-note@2{{using}}
+ // expected-note@2{{also found}}
+}
+
+void testMethod4Again(id object) {
+ [object method4];
+}
+
+void testMethod5Again(id object, D* d) {
+ [object method5:d];
+}
diff --git a/test/Modules/modify-module.m b/test/Modules/modify-module.m
index b630ac1..953c917 100644
--- a/test/Modules/modify-module.m
+++ b/test/Modules/modify-module.m
@@ -6,14 +6,22 @@
// 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: %clang_cc1 -fdisable-module-hash -fmodules-cache-path=%t/cache -fmodules -I %t/include %s -verify
+// RUN: echo '' >> %t/include/B.h
+// RUN: %clang_cc1 -fdisable-module-hash -fmodules-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
+// RUN: %clang_cc1 -fdisable-module-hash -fmodules-cache-path=%t/cache -fmodules -I %t/include %s -verify
+// RUN: rm %t/cache/ModA.pcm
+// RUN: %clang_cc1 -fdisable-module-hash -fmodules-cache-path=%t/cache -fmodules -I %t/include %s -verify
+// RUN: touch %t/cache/ModA.pcm
+// RUN: %clang_cc1 -fdisable-module-hash -fmodules-cache-path=%t/cache -fmodules -I %t/include %s -verify
+
+// expected-no-diagnostics
+
+// FIXME: It is intended to suppress this on win32.
+// REQUIRES: ansi-escape-sequences
-@__experimental_modules_import B;
+@import ModB;
int getValue() { return getA() + getB(); }
diff --git a/test/Modules/module-private.cpp b/test/Modules/module-private.cpp
index 31a3410..d4e73b5 100644
--- a/test/Modules/module-private.cpp
+++ b/test/Modules/module-private.cpp
@@ -1,11 +1,11 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules -x objective-c++ -fmodule-cache-path %t -fmodule-name=module_private_left -emit-module %S/Inputs/module.map
-// RUN: %clang_cc1 -fmodules -x objective-c++ -fmodule-cache-path %t -fmodule-name=module_private_right -emit-module %S/Inputs/module.map
-// RUN: %clang_cc1 -fmodules -x objective-c++ -fmodule-cache-path %t %s -verify
+// RUN: %clang_cc1 -fmodules -x objective-c++ -fmodules-cache-path=%t -fmodule-name=module_private_left -emit-module %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c++ -fmodules-cache-path=%t -fmodule-name=module_private_right -emit-module %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c++ -fmodules-cache-path=%t %s -verify
// FIXME: When we have a syntax for modules in C++, use that.
-@__experimental_modules_import module_private_left;
-@__experimental_modules_import module_private_right;
+@import module_private_left;
+@import module_private_right;
void test() {
int &ir = f0(1.0); // okay: f0() from 'right' is not visible
diff --git a/test/Modules/module_file_info.m b/test/Modules/module_file_info.m
new file mode 100644
index 0000000..09319d6
--- /dev/null
+++ b/test/Modules/module_file_info.m
@@ -0,0 +1,34 @@
+
+@import DependsOnModule;
+
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -w -fmodules -fdisable-module-hash -fmodules-cache-path=%t -F %S/Inputs -DBLARG -DWIBBLE=WOBBLE %s
+// RUN: %clang_cc1 -module-file-info %t/DependsOnModule.pcm | FileCheck %s
+
+// CHECK: Generated by this Clang:
+
+// CHECK: Language options:
+// CHECK: C99: Yes
+// CHECK: Objective-C 1: Yes
+// CHECK: modules extension to C: Yes
+
+// CHECK: Target options:
+// CHECK: Triple:
+// CHECK: CPU:
+// CHECK: ABI:
+// CHECK: C++ ABI:
+// CHECK: Linker version:
+
+// CHECK: Header search options:
+// CHECK: System root [-isysroot=]: '/'
+// CHECK: Use builtin include directories [-nobuiltininc]: Yes
+// CHECK: Use standard system include directories [-nostdinc]: Yes
+// CHECK: Use standard C++ include directories [-nostdinc++]: Yes
+// CHECK: Use libc++ (rather than libstdc++) [-stdlib=]:
+
+// CHECK: Preprocessor options:
+// CHECK: Uses compiler/target-specific predefines [-undef]: Yes
+// CHECK: Uses detailed preprocessing record (for indexing): No
+// CHECK: Predefined macros:
+// CHECK: -DBLARG
+// CHECK: -DWIBBLE=WOBBLE
diff --git a/test/Modules/namespaces.cpp b/test/Modules/namespaces.cpp
index 19e0c5a..0e9dbff 100644
--- a/test/Modules/namespaces.cpp
+++ b/test/Modules/namespaces.cpp
@@ -1,9 +1,8 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodule-cache-path %t -I %S/Inputs %s -verify
+// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs %s -verify
-// Importing modules which add declarations to a pre-existing non-imported
-// overload set does not currently work.
-// XFAIL: *
+int &global(int);
+int &global2(int);
namespace N6 {
char &f(char);
@@ -11,17 +10,32 @@ namespace N6 {
namespace N8 { }
-@__experimental_modules_import namespaces_left;
-@__experimental_modules_import namespaces_right;
+namespace LookupBeforeImport {
+ int &f(int);
+}
+void testEarly() {
+ int &r = LookupBeforeImport::f(1);
+}
+
+@import namespaces_left;
+@import namespaces_right;
void test() {
int &ir1 = N1::f(1);
int &ir2 = N2::f(1);
int &ir3 = N3::f(1);
+ int &ir4 = global(1);
+ int &ir5 = ::global2(1);
float &fr1 = N1::f(1.0f);
float &fr2 = N2::f(1.0f);
+ float &fr3 = global(1.0f);
+ float &fr4 = ::global2(1.0f);
+ float &fr5 = LookupBeforeImport::f(1.0f);
double &dr1 = N2::f(1.0);
double &dr2 = N3::f(1.0);
+ double &dr3 = global(1.0);
+ double &dr4 = ::global2(1.0);
+ double &dr5 = LookupBeforeImport::f(1.0);
}
// Test namespaces merged without a common first declaration.
@@ -54,11 +68,10 @@ void testMergedMerged() {
// Test merging when using anonymous namespaces, which does not
// actually perform any merging.
-// other file: expected-note{{passing argument to parameter here}}
void testAnonymousNotMerged() {
N11::consumeFoo(N11::getFoo()); // expected-error{{cannot initialize a parameter of type 'N11::<anonymous>::Foo *' with an rvalue of type 'N11::<anonymous>::Foo *'}}
N12::consumeFoo(N12::getFoo()); // expected-error{{cannot initialize a parameter of type 'N12::<anonymous>::Foo *' with an rvalue of type 'N12::<anonymous>::Foo *'}}
}
-
-// other file: expected-note{{passing argument to parameter here}}
+// namespaces-right.h: expected-note@60 {{passing argument to parameter here}}
+// namespaces-right.h: expected-note@67 {{passing argument to parameter here}}
diff --git a/test/Modules/normal-module-map.cpp b/test/Modules/normal-module-map.cpp
index 07ca5ed..423e808 100644
--- a/test/Modules/normal-module-map.cpp
+++ b/test/Modules/normal-module-map.cpp
@@ -1,14 +1,14 @@
// Note: inside the module. expected-note{{'nested_umbrella_a' declared here}}
// RUN: rm -rf %t
-// RUN: %clang_cc1 -x objective-c -fmodule-cache-path %t -fmodules -I %S/Inputs/normal-module-map %s -verify
+// RUN: %clang_cc1 -x objective-c -fmodules-cache-path=%t -fmodules -I %S/Inputs/normal-module-map %s -verify
#include "Umbrella/umbrella_sub.h"
int getUmbrella() {
return umbrella + umbrella_sub;
}
-@__experimental_modules_import Umbrella2;
+@import Umbrella2;
#include "a1.h"
#include "b1.h"
@@ -18,7 +18,7 @@ int test() {
return a1 + b1 + nested2;
}
-@__experimental_modules_import nested_umbrella.a;
+@import nested_umbrella.a;
int testNestedUmbrellaA() {
return nested_umbrella_a;
@@ -28,17 +28,17 @@ int testNestedUmbrellaBFail() {
return nested_umbrella_b; // expected-error{{use of undeclared identifier 'nested_umbrella_b'; did you mean 'nested_umbrella_a'?}}
}
-@__experimental_modules_import nested_umbrella.b;
+@import nested_umbrella.b;
int testNestedUmbrellaB() {
return nested_umbrella_b;
}
-@__experimental_modules_import nested_umbrella.a_extras;
+@import nested_umbrella.a_extras;
-@__experimental_modules_import nested_umbrella._1;
+@import nested_umbrella._1;
-@__experimental_modules_import nested_umbrella.decltype_;
+@import nested_umbrella.decltype_;
int testSanitizedName() {
return extra_a + one + decltype_val;
diff --git a/test/Modules/objc-categories.m b/test/Modules/objc-categories.m
index b267592..d3ebcb7 100644
--- a/test/Modules/objc-categories.m
+++ b/test/Modules/objc-categories.m
@@ -1,12 +1,12 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t -x objective-c -fmodule-name=category_top -emit-module %S/Inputs/module.map
-// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t -x objective-c -fmodule-name=category_left -emit-module %S/Inputs/module.map
-// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t -x objective-c -fmodule-name=category_right -emit-module %S/Inputs/module.map
-// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t -x objective-c -fmodule-name=category_bottom -emit-module %S/Inputs/module.map
-// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t -x objective-c -fmodule-name=category_other -emit-module %S/Inputs/module.map
-// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t %s -verify
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -x objective-c -fmodule-name=category_top -emit-module %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -x objective-c -fmodule-name=category_left -emit-module %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -x objective-c -fmodule-name=category_right -emit-module %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -x objective-c -fmodule-name=category_bottom -emit-module %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -x objective-c -fmodule-name=category_other -emit-module %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t %s -verify
-@__experimental_modules_import category_bottom;
+@import category_bottom;
@@ -34,8 +34,64 @@ void test(Foo *foo, LeftFoo *leftFoo) {
// Load another module that also adds categories to Foo, verify that
// we see those categories.
-@__experimental_modules_import category_other;
+@import category_other;
void test_other(Foo *foo) {
[foo other];
}
+
+// Make sure we don't see categories that should be hidden
+void test_hidden_all_errors(Foo *foo) {
+ [foo left_sub]; // expected-warning{{instance method '-left_sub' not found (return type defaults to 'id')}}
+ foo.right_sub_prop = foo; // expected-error{{property 'right_sub_prop' not found on object of type 'Foo *'}}
+ int i = foo->right_sub_ivar; // expected-error{{'Foo' does not have a member named 'right_sub_ivar'}}
+ id<P1> p1 = foo; // expected-warning{{initializing 'id<P1>' with an expression of incompatible type 'Foo *'}}
+ id<P2> p2 = foo; // expected-warning{{initializing 'id<P2>' with an expression of incompatible type 'Foo *'}}
+ id<P3> p3;
+ [p3 p3_method]; // expected-warning{{instance method '-p3_method' not found (return type defaults to 'id')}}
+ id<P4> p4;
+ [p4 p4_method]; // expected-warning{{instance method '-p4_method' not found (return type defaults to 'id')}}
+ id p3p = p3.p3_prop; // expected-error{{property 'p3_prop' not found on object of type 'id<P3>'}}
+ p3p = foo.p3_prop; // expected-error{{property 'p3_prop' not found on object of type 'Foo *'}}
+ id p4p = p4.p4_prop; // expected-error{{property 'p4_prop' not found on object of type 'id<P4>'}}
+ p4p = foo.p4_prop; // expected-error{{property 'p4_prop' not found on object of type 'Foo *'}}
+}
+
+@import category_left.sub;
+
+void test_hidden_right_errors(Foo *foo) {
+ // These are okay
+ [foo left_sub]; // okay
+ id<P1> p1 = foo;
+ id<P3> p3;
+ [p3 p3_method];
+ id p3p = p3.p3_prop;
+ p3p = foo.p3_prop;
+ // These should fail
+ foo.right_sub_prop = foo; // expected-error{{property 'right_sub_prop' not found on object of type 'Foo *'}}
+ int i = foo->right_sub_ivar; // expected-error{{'Foo' does not have a member named 'right_sub_ivar'}}
+ id<P2> p2 = foo; // expected-warning{{initializing 'id<P2>' with an expression of incompatible type 'Foo *'}}
+ id<P4> p4;
+ [p4 p4_method]; // expected-warning{{instance method '-p4_method' not found (return type defaults to 'id')}}
+ id p4p = p4.p4_prop; // expected-error{{property 'p4_prop' not found on object of type 'id<P4>'}}
+ p4p = foo.p4_prop; // expected-error{{property 'p4_prop' not found on object of type 'Foo *'; did you mean 'p3_prop'?}}
+ // expected-note@7{{'p3_prop' declared here}}
+}
+
+@import category_right.sub;
+
+void test_hidden_okay(Foo *foo) {
+ [foo left_sub];
+ foo.right_sub_prop = foo;
+ int i = foo->right_sub_ivar;
+ id<P1> p1 = foo;
+ id<P2> p2 = foo;
+ id<P3> p3;
+ [p3 p3_method];
+ id<P4> p4;
+ [p4 p4_method];
+ id p3p = p3.p3_prop;
+ p3p = foo.p3_prop;
+ id p4p = p4.p4_prop;
+ p4p = foo.p4_prop;
+}
diff --git a/test/Modules/objc_redef.m b/test/Modules/objc_redef.m
new file mode 100644
index 0000000..f911241
--- /dev/null
+++ b/test/Modules/objc_redef.m
@@ -0,0 +1,13 @@
+@import redeclarations_left;
+@import weird_objc;
+
+int test(id x) {
+ return x->wibble;
+}
+
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -x objective-c -fmodules-cache-path=%t -emit-module -fmodule-name=redeclarations_left %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -fmodules-cache-path=%t -emit-module -fmodule-name=weird_objc %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t %s -verify
+// expected-no-diagnostics
+
diff --git a/test/Modules/on-demand-build-warnings.m b/test/Modules/on-demand-build-warnings.m
deleted file mode 100644
index 24975c0..0000000
--- a/test/Modules/on-demand-build-warnings.m
+++ /dev/null
@@ -1,5 +0,0 @@
-// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules -fno-objc-infer-related-result-type -Wmodule-build -fmodule-cache-path %t -F %S/Inputs -verify %s
-
-@__experimental_modules_import Module; // expected-warning{{building module 'Module' from source}}
-
diff --git a/test/Modules/on-demand-build.m b/test/Modules/on-demand-build.m
index 4ee6b58..31742f7 100644
--- a/test/Modules/on-demand-build.m
+++ b/test/Modules/on-demand-build.m
@@ -1,9 +1,9 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules -fno-objc-infer-related-result-type -Werror -Wno-error=incomplete-umbrella -fmodule-cache-path %t -F %S/Inputs -I %S/Inputs -verify %s
-// RUN: %clang_cc1 -fmodules -fno-objc-infer-related-result-type -Werror -Wno-error=incomplete-umbrella -x objective-c++ -fmodule-cache-path %t -F %S/Inputs -I %S/Inputs -verify %s
-// RUN: %clang_cc1 -fmodules -fno-objc-infer-related-result-type -Werror -Wno-error=incomplete-umbrella -fmodule-cache-path %t -F %S/Inputs -I %S/Inputs -verify %s
+// RUN: %clang_cc1 -fmodules -fno-objc-infer-related-result-type -Werror -Wno-error=incomplete-umbrella -fmodules-cache-path=%t -F %S/Inputs -I %S/Inputs -verify %s
+// RUN: %clang_cc1 -fmodules -fno-objc-infer-related-result-type -Werror -Wno-error=incomplete-umbrella -x objective-c++ -fmodules-cache-path=%t -F %S/Inputs -I %S/Inputs -verify %s
+// RUN: %clang_cc1 -fmodules -fno-objc-infer-related-result-type -Werror -Wno-error=incomplete-umbrella -fmodules-cache-path=%t -F %S/Inputs -I %S/Inputs -verify %s
#define FOO
-@__experimental_modules_import Module;
+@import Module;
@interface OtherClass
@end
@@ -19,6 +19,6 @@ void test_getModuleVersion() {
# error MODULE_SUBFRAMEWORK_H should be hidden
#endif
-@__experimental_modules_import subdir;
+@import subdir;
const char *getSubdirTest() { return getSubdir(); }
diff --git a/test/Modules/on-demand-macros.m b/test/Modules/on-demand-macros.m
index 8b50529..3c16fa7 100644
--- a/test/Modules/on-demand-macros.m
+++ b/test/Modules/on-demand-macros.m
@@ -1,9 +1,9 @@
// 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
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -F %S/Inputs -DFOO_RETURNS_INT_PTR -verify %s
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -F %S/Inputs -verify %s
// expected-no-diagnostics
-@__experimental_modules_import CmdLine;
+@import CmdLine;
void test() {
#ifdef FOO_RETURNS_INT_PTR
diff --git a/test/Modules/prune.m b/test/Modules/prune.m
new file mode 100644
index 0000000..8af7e6c
--- /dev/null
+++ b/test/Modules/prune.m
@@ -0,0 +1,46 @@
+// Test the automatic pruning of module cache entries.
+#ifdef IMPORT_DEPENDS_ON_MODULE
+@import DependsOnModule;
+#else
+@import Module;
+#endif
+
+// We need 'touch' and 'find' for this test to work.
+// REQUIRES: shell
+
+// Clear out the module cache
+// RUN: rm -rf %t
+// Run Clang twice so we end up creating the timestamp file (the second time).
+// RUN: %clang_cc1 -DIMPORT_DEPENDS_ON_MODULE -fmodules-ignore-macro=DIMPORT_DEPENDS_ON_MODULE -fmodules -F %S/Inputs -fmodules-cache-path=%t %s -verify
+// RUN: %clang_cc1 -DIMPORT_DEPENDS_ON_MODULE -fmodules-ignore-macro=DIMPORT_DEPENDS_ON_MODULE -fmodules -F %S/Inputs -fmodules-cache-path=%t %s -verify
+// RUN: ls %t | grep modules.timestamp
+// RUN: ls -R %t | grep ^Module.pcm
+// RUN: ls -R %t | grep DependsOnModule.pcm
+
+// Set the timestamp back more than two days. We should try to prune,
+// but nothing gets pruned because the module files are new enough.
+// RUN: touch -m -a -t 201101010000 %t/modules.timestamp
+// RUN: %clang_cc1 -fmodules -F %S/Inputs -fmodules-cache-path=%t -fmodules -fmodules-prune-interval=172800 -fmodules-prune-after=345600 %s -verify
+// RUN: ls %t | grep modules.timestamp
+// RUN: ls -R %t | grep ^Module.pcm
+// RUN: ls -R %t | grep DependsOnModule.pcm
+
+// Set the DependsOnModule access time back more than four days.
+// This shouldn't prune anything, because the timestamp has been updated, so
+// the pruning mechanism won't fire.
+// RUN: find %t -name DependsOnModule.pcm | xargs touch -a -t 201101010000
+// RUN: %clang_cc1 -fmodules -F %S/Inputs -fmodules-cache-path=%t -fmodules -fmodules-prune-interval=172800 -fmodules-prune-after=345600 %s -verify
+// RUN: ls %t | grep modules.timestamp
+// RUN: ls -R %t | grep ^Module.pcm
+// RUN: ls -R %t | grep DependsOnModule.pcm
+
+// Set both timestamp and DependsOnModule.pcm back beyond the cutoff.
+// This should trigger pruning, which will remove DependsOnModule but not Module.
+// RUN: touch -m -a -t 201101010000 %t/modules.timestamp
+// RUN: find %t -name DependsOnModule.pcm | xargs touch -a -t 201101010000
+// RUN: %clang_cc1 -fmodules -F %S/Inputs -fmodules-cache-path=%t -fmodules -fmodules-prune-interval=172800 -fmodules-prune-after=345600 %s -verify
+// RUN: ls %t | grep modules.timestamp
+// RUN: ls -R %t | grep ^Module.pcm
+// RUN: ls -R %t | not grep DependsOnModule.pcm
+
+// expected-no-diagnostics
diff --git a/test/Modules/redecl-merge.m b/test/Modules/redecl-merge.m
index d722414..e373667 100644
--- a/test/Modules/redecl-merge.m
+++ b/test/Modules/redecl-merge.m
@@ -1,14 +1,35 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t -I %S/Inputs %s -verify -Wno-objc-root-class
+// RUN: %clang_cc1 -fmodules -Wreturn-type -fmodules-cache-path=%t -I %S/Inputs %s -verify -Wno-objc-root-class
+
@class C2;
@class C3;
@class C3;
-@__experimental_modules_import redecl_merge_left;
+@import redecl_merge_left;
typedef struct my_struct_type *my_struct_ref;
@protocol P4;
@class C3;
@class C3;
-@__experimental_modules_import redecl_merge_right;
+
+int *call_eventually_noreturn(void) {
+ eventually_noreturn();
+} // expected-warning{{control reaches end of non-void function}}
+
+int *call_eventually_noreturn2(void) {
+ eventually_noreturn2();
+} // expected-warning{{control reaches end of non-void function}}
+
+@import redecl_merge_right;
+
+int *call_eventually_noreturn_again(void) {
+ eventually_noreturn();
+}
+
+int *call_eventually_noreturn2_again(void) {
+ // noreturn and non-noreturn functions have different types
+ eventually_noreturn2(); // expected-error{{call to 'eventually_noreturn2' is ambiguous}}
+ // expected-note@93{{candidate function}}
+ // expected-note@90{{candidate function}}
+}
@implementation A
- (Super*)init { return self; }
@@ -112,7 +133,7 @@ C4 *global_C4;
ClassWithDef *cwd1;
-@__experimental_modules_import redecl_merge_left_left;
+@import redecl_merge_left_left;
void test_C4a(C4 *c4) {
global_C4 = c4 = get_a_C4();
@@ -123,7 +144,7 @@ void test_ClassWithDef(ClassWithDef *cwd) {
[cwd method];
}
-@__experimental_modules_import redecl_merge_bottom;
+@import redecl_merge_bottom;
void test_C4b() {
if (&refers_to_C4) {
@@ -148,3 +169,5 @@ id<P3> p3;
// Make sure we don't get conflicts with 'id'.
funcptr_with_id fid;
id id_global;
+
+
diff --git a/test/Modules/redecl-merge2.m b/test/Modules/redecl-merge2.m
new file mode 100644
index 0000000..3431ecc
--- /dev/null
+++ b/test/Modules/redecl-merge2.m
@@ -0,0 +1,8 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs %s -verify -Wno-objc-root-class
+// expected-no-diagnostics
+
+@import redecl_merge_bottom.prefix;
+
+DeclaredThenLoaded *dtl;
+
diff --git a/test/Modules/redecl-namespaces.mm b/test/Modules/redecl-namespaces.mm
index e338821..93102c0 100644
--- a/test/Modules/redecl-namespaces.mm
+++ b/test/Modules/redecl-namespaces.mm
@@ -1,5 +1,5 @@
-@__experimental_modules_import redecl_namespaces_left;
-@__experimental_modules_import redecl_namespaces_right;
+@import redecl_namespaces_left;
+@import redecl_namespaces_right;
void test() {
A::i;
@@ -8,6 +8,6 @@ void test() {
}
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules -x objective-c++ -fmodule-cache-path %t -emit-module -fmodule-name=redecl_namespaces_left %S/Inputs/module.map
-// RUN: %clang_cc1 -fmodules -x objective-c++ -fmodule-cache-path %t -emit-module -fmodule-name=redecl_namespaces_right %S/Inputs/module.map
-// RUN: %clang_cc1 -fmodules -fmodule-cache-path %t -w %s -verify
+// RUN: %clang_cc1 -fmodules -x objective-c++ -fmodules-cache-path=%t -emit-module -fmodule-name=redecl_namespaces_left %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c++ -fmodules-cache-path=%t -emit-module -fmodule-name=redecl_namespaces_right %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -w %s -verify
diff --git a/test/Modules/redeclarations.m b/test/Modules/redeclarations.m
index 221e154..f210f37 100644
--- a/test/Modules/redeclarations.m
+++ b/test/Modules/redeclarations.m
@@ -1,12 +1,12 @@
-@__experimental_modules_import redeclarations_left;
-@__experimental_modules_import redeclarations_right;
+@import redeclarations_left;
+@import redeclarations_right;
@interface MyObject : NSObject
@end
// RUN: rm -rf %t
-// 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
+// RUN: %clang_cc1 -fmodules -x objective-c -fmodules-cache-path=%t -emit-module -fmodule-name=redeclarations_left %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -x objective-c -fmodules-cache-path=%t -emit-module -fmodule-name=redeclarations_right %S/Inputs/module.map
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t %s -verify
// expected-no-diagnostics
diff --git a/test/Modules/renamed.m b/test/Modules/renamed.m
new file mode 100644
index 0000000..4e8f532
--- /dev/null
+++ b/test/Modules/renamed.m
@@ -0,0 +1,8 @@
+@import NewName;
+
+int f() { return same_api; }
+
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -I %S/Inputs -fmodules-cache-path=%t %s -verify
+
+// expected-no-diagnostics
diff --git a/test/Modules/requires.m b/test/Modules/requires.m
index ce2537c..83b524d 100644
--- a/test/Modules/requires.m
+++ b/test/Modules/requires.m
@@ -1,5 +1,5 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -Wauto-import -fmodule-cache-path %t -fmodules -F %S/Inputs %s -verify
+// RUN: %clang_cc1 -Wauto-import -fmodules-cache-path=%t -fmodules -F %S/Inputs %s -verify
-@__experimental_modules_import DependsOnModule.CXX; // expected-error{{module 'DependsOnModule.CXX' requires feature 'cplusplus'}}
+@import DependsOnModule.CXX; // expected-error{{module 'DependsOnModule.CXX' requires feature 'cplusplus'}}
diff --git a/test/Modules/stddef.m b/test/Modules/stddef.m
new file mode 100644
index 0000000..83f73f9
--- /dev/null
+++ b/test/Modules/stddef.m
@@ -0,0 +1,7 @@
+@import StdDef.Other;
+
+size_t getSize();
+
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs/StdDef %s -verify
+// expected-no-diagnostics
diff --git a/test/Modules/subframeworks.m b/test/Modules/subframeworks.m
index 09298c4..22dfcca 100644
--- a/test/Modules/subframeworks.m
+++ b/test/Modules/subframeworks.m
@@ -1,14 +1,14 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -Wauto-import -fmodule-cache-path %t -fmodules -F %S/Inputs -F %S/Inputs/DependsOnModule.framework/Frameworks %s -verify
-// RUN: %clang_cc1 -x objective-c++ -Wauto-import -fmodule-cache-path %t -fmodules -F %S/Inputs -F %S/Inputs/DependsOnModule.framework/Frameworks %s -verify
+// RUN: %clang_cc1 -Wauto-import -fmodules-cache-path=%t -fmodules -F %S/Inputs -F %S/Inputs/DependsOnModule.framework/Frameworks %s -verify
+// RUN: %clang_cc1 -x objective-c++ -Wauto-import -fmodules-cache-path=%t -fmodules -F %S/Inputs -F %S/Inputs/DependsOnModule.framework/Frameworks %s -verify
-@__experimental_modules_import DependsOnModule;
+@import DependsOnModule;
void testSubFramework() {
float *sf1 = sub_framework; // expected-error{{use of undeclared identifier 'sub_framework'}}
}
-@__experimental_modules_import DependsOnModule.SubFramework;
+@import DependsOnModule.SubFramework;
void testSubFrameworkAgain() {
float *sf2 = sub_framework;
@@ -16,7 +16,14 @@ void testSubFrameworkAgain() {
}
#ifdef __cplusplus
-@__experimental_modules_import DependsOnModule.CXX;
+@import DependsOnModule.CXX;
CXXOnly cxxonly;
#endif
+
+@import HasSubModules;
+
+// expected-warning@1{{treating #include as an import of module 'HasSubModules.Sub.Types'}}
+#import <HasSubModules/HasSubModulesPriv.h>
+
+struct FrameworkSubStruct ss;
diff --git a/test/Modules/submodules-preprocess.cpp b/test/Modules/submodules-preprocess.cpp
index 8d6c2cd..7040b51 100644
--- a/test/Modules/submodules-preprocess.cpp
+++ b/test/Modules/submodules-preprocess.cpp
@@ -1,8 +1,8 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules -x objective-c++ -Eonly -fmodule-cache-path %t -I %S/Inputs/submodules %s -verify
+// RUN: %clang_cc1 -fmodules -x objective-c++ -Eonly -fmodules-cache-path=%t -I %S/Inputs/submodules %s -verify
// FIXME: When we have a syntax for modules in C++, use that.
-@__experimental_modules_import std.vector;
+@import std.vector;
#ifndef HAVE_VECTOR
# error HAVE_VECTOR macro is not available (but should be)
@@ -16,7 +16,7 @@
# error HAVE_HASH_MAP macro is available (but shouldn't be)
#endif
-@__experimental_modules_import std.typetraits; // expected-error{{no submodule named 'typetraits' in module 'std'; did you mean 'type_traits'?}}
+@import std.typetraits; // expected-error{{no submodule named 'typetraits' in module 'std'; did you mean 'type_traits'?}}
#ifndef HAVE_VECTOR
# error HAVE_VECTOR macro is not available (but should be)
@@ -30,9 +30,9 @@
# error HAVE_HASH_MAP macro is available (but shouldn't be)
#endif
-@__experimental_modules_import std.vector.compare; // expected-error{{no submodule named 'compare' in module 'std.vector'}}
+@import std.vector.compare; // expected-error{{no submodule named 'compare' in module 'std.vector'}}
-@__experimental_modules_import std; // import everything in 'std'
+@import std; // import everything in 'std'
#ifndef HAVE_VECTOR
# error HAVE_VECTOR macro is not available (but should be)
@@ -46,7 +46,7 @@
# error HAVE_HASH_MAP macro is available (but shouldn't be)
#endif
-@__experimental_modules_import std.hash_map;
+@import std.hash_map;
#ifndef HAVE_VECTOR
# error HAVE_VECTOR macro is not available (but should be)
diff --git a/test/Modules/submodules.cpp b/test/Modules/submodules.cpp
index 60d5ae0..1b4f5d8 100644
--- a/test/Modules/submodules.cpp
+++ b/test/Modules/submodules.cpp
@@ -1,8 +1,8 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -x objective-c++ -fmodule-cache-path %t -fmodules -I %S/Inputs/submodules %s -verify
+// RUN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -I %S/Inputs/submodules %s -verify
// FIXME: When we have a syntax for modules in C++, use that.
-@__experimental_modules_import std.vector;
+@import std.vector;
vector<int> vi;
@@ -10,20 +10,20 @@ vector<int> vi;
remove_reference<int&>::type *int_ptr = 0; // expected-error{{unknown type name 'remove_reference'}} \
// expected-error{{expected unqualified-id}}
-@__experimental_modules_import std.typetraits; // expected-error{{no submodule named 'typetraits' in module 'std'; did you mean 'type_traits'?}}
+@import std.typetraits; // expected-error{{no submodule named 'typetraits' in module 'std'; did you mean 'type_traits'?}}
vector<float> vf;
remove_reference<int&>::type *int_ptr2 = 0;
-@__experimental_modules_import std.vector.compare; // expected-error{{no submodule named 'compare' in module 'std.vector'}}
+@import std.vector.compare; // expected-error{{no submodule named 'compare' in module 'std.vector'}}
-@__experimental_modules_import std; // import everything in 'std'
+@import std; // import everything in 'std'
// hash_map still isn't available.
hash_map<int, float> ints_to_floats; // expected-error{{unknown type name 'hash_map'}} \
// expected-error{{expected unqualified-id}}
-@__experimental_modules_import std.hash_map;
+@import std.hash_map;
hash_map<int, float> ints_to_floats2;
diff --git a/test/Modules/submodules.m b/test/Modules/submodules.m
index a758abc..7187e75 100644
--- a/test/Modules/submodules.m
+++ b/test/Modules/submodules.m
@@ -1,10 +1,10 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -Wauto-import -fmodule-cache-path %t -fmodules -F %S/Inputs %s -verify
+// RUN: %clang_cc1 -Wauto-import -fmodules-cache-path=%t -fmodules -F %S/Inputs %s -verify
// expected-no-diagnostics
// Note: transitively imports Module.Sub2.
-@__experimental_modules_import Module.Sub;
+@import Module.Sub;
int getValue() {
return *Module_Sub + *Module_Sub2;
diff --git a/test/Modules/templates.mm b/test/Modules/templates.mm
index 4541740..1fef967 100644
--- a/test/Modules/templates.mm
+++ b/test/Modules/templates.mm
@@ -1,10 +1,10 @@
// 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
+// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs -verify %s -Wno-objc-root-class
+// RUN: %clang_cc1 -x objective-c++ -fmodules -fmodules-cache-path=%t -I %S/Inputs -emit-llvm %s -o - -Wno-objc-root-class | grep Emit | FileCheck %s
// expected-no-diagnostics
-@__experimental_modules_import templates_left;
-@__experimental_modules_import templates_right;
+@import templates_left;
+@import templates_right;
void testTemplateClasses() {
diff --git a/test/Modules/wildcard-submodule-exports.cpp b/test/Modules/wildcard-submodule-exports.cpp
index 6b4f02c..f377dbe 100644
--- a/test/Modules/wildcard-submodule-exports.cpp
+++ b/test/Modules/wildcard-submodule-exports.cpp
@@ -1,8 +1,8 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -x objective-c++ -fmodule-cache-path %t -fmodules -I %S/Inputs/wildcard-submodule-exports %s -verify
+// RUN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -I %S/Inputs/wildcard-submodule-exports %s -verify
// FIXME: When we have a syntax for modules in C++, use that.
-@__experimental_modules_import C.One;
+@import C.One;
void test_C_One() {
int *A1_ptr = A1;
@@ -10,7 +10,7 @@ void test_C_One() {
(void)B1; // expected-error{{use of undeclared identifier 'B1'}}
}
-@__experimental_modules_import C.Two;
+@import C.Two;
void test_C_Two() {
unsigned int *A2_ptr = A2;
@@ -18,7 +18,7 @@ void test_C_Two() {
unsigned long *C2_ptr = C2;
}
-@__experimental_modules_import B.One;
+@import B.One;
void test_B_One() {
short *B1_ptr = B1;
diff --git a/test/OpenMP/linking.c b/test/OpenMP/linking.c
new file mode 100644
index 0000000..31fd57d
--- /dev/null
+++ b/test/OpenMP/linking.c
@@ -0,0 +1,16 @@
+// Test the that the driver produces reasonable linker invocations with
+// -fopenmp.
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -fopenmp -target i386-unknown-linux \
+// RUN: | FileCheck --check-prefix=CHECK-LD-32 %s
+// CHECK-LD-32: "{{.*}}ld{{(.exe)?}}"
+// CHECK-LD-32: "-lgomp" "-lrt" "-lgcc"
+// CHECK-LD-32: "-lpthread" "-lc"
+//
+// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
+// RUN: -fopenmp -target x86_64-unknown-linux \
+// RUN: | FileCheck --check-prefix=CHECK-LD-64 %s
+// CHECK-LD-64: "{{.*}}ld{{(.exe)?}}"
+// CHECK-LD-64: "-lgomp" "-lrt" "-lgcc"
+// CHECK-LD-64: "-lpthread" "-lc"
diff --git a/test/OpenMP/no_option.c b/test/OpenMP/no_option.c
new file mode 100644
index 0000000..4acc8d0
--- /dev/null
+++ b/test/OpenMP/no_option.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -verify -o - %s
+// expected-no-diagnostics
+
+int a;
+#pragma omp threadprivate(a,b)
+#pragma omp parallel
diff --git a/test/OpenMP/no_option_no_warn.c b/test/OpenMP/no_option_no_warn.c
new file mode 100644
index 0000000..c989991
--- /dev/null
+++ b/test/OpenMP/no_option_no_warn.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -verify -Wno-source-uses-openmp -o - %s
+// expected-no-diagnostics
+
+int a;
+#pragma omp threadprivate(a,b)
+#pragma omp parallel
diff --git a/test/OpenMP/openmp_common.c b/test/OpenMP/openmp_common.c
new file mode 100644
index 0000000..ca5d89a
--- /dev/null
+++ b/test/OpenMP/openmp_common.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s
+
+#pragma omp // expected-error {{expected an OpenMP directive}}
+#pragma omp unknown_directive // expected-error {{expected an OpenMP directive}}
+
+void foo() {
+#pragma omp // expected-error {{expected an OpenMP directive}}
+#pragma omp unknown_directive // expected-error {{expected an OpenMP directive}}
+}
diff --git a/test/OpenMP/option_warn.c b/test/OpenMP/option_warn.c
new file mode 100644
index 0000000..ddec8e1
--- /dev/null
+++ b/test/OpenMP/option_warn.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -verify -Wsource-uses-openmp -o - %s
+
+int a;
+#pragma omp threadprivate(a,b) // expected-warning {{unexpected '#pragma omp ...' in program}}
+#pragma omp parallel
diff --git a/test/OpenMP/predefined_macro.c b/test/OpenMP/predefined_macro.c
new file mode 100644
index 0000000..cf6c0cc
--- /dev/null
+++ b/test/OpenMP/predefined_macro.c
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -fopenmp -verify -DFOPENMP -o - %s
+// RUN: %clang_cc1 -verify -o - %s
+// expected-no-diagnostics
+#ifdef FOPENMP
+// -fopenmp option is specified
+#ifndef _OPENMP
+#error "No _OPENMP macro is defined with -fopenmp option"
+#elsif _OPENMP != 201107
+#error "_OPENMP has incorrect value"
+#endif //_OPENMP
+#else
+// No -fopenmp option is specified
+#ifdef _OPENMP
+#error "_OPENMP macro is defined without -fopenmp option"
+#endif // _OPENMP
+#endif // FOPENMP
+
+// RUN: %clang_cc1 -fopenmp -verify -DFOPENMP -o - %s
+// RUN: %clang_cc1 -verify -o - %s
+// expected-no-diagnostics
+#ifdef FOPENMP
+// -fopenmp option is specified
+#ifndef _OPENMP
+#error "No _OPENMP macro is defined with -fopenmp option"
+#elsif _OPENMP != 201107
+#error "_OPENMP has incorrect value"
+#endif // _OPENMP
+#else
+// No -fopenmp option is specified
+#ifdef _OPENMP
+#error "_OPENMP macro is defined without -fopenmp option"
+#endif // _OPENMP
+#endif // FOPENMP
+
diff --git a/test/OpenMP/threadprivate_ast_print.cpp b/test/OpenMP/threadprivate_ast_print.cpp
new file mode 100644
index 0000000..deb829e
--- /dev/null
+++ b/test/OpenMP/threadprivate_ast_print.cpp
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s
+// expected-no-diagnostics
+
+struct St{
+ int a;
+};
+
+struct St1{
+ int a;
+ static int b;
+// CHECK: static int b;
+#pragma omp threadprivate(b)
+// CHECK-NEXT: #pragma omp threadprivate(b)
+} d;
+
+int a, b;
+// CHECK: int a;
+// CHECK: int b;
+#pragma omp threadprivate(a)
+// CHECK-NEXT: #pragma omp threadprivate(a)
+#pragma omp threadprivate(d, b)
+// CHECK-NEXT: #pragma omp threadprivate(d,b)
+
+template <class T> T foo() {
+ static T v;
+ #pragma omp threadprivate(v)
+ return v;
+}
+//CHECK: template <class T = int> int foo() {
+//CHECK-NEXT: static int v;
+//CHECK-NEXT: #pragma omp threadprivate(v)
+//CHECK: template <class T> T foo() {
+//CHECK-NEXT: static T v;
+//CHECK-NEXT: #pragma omp threadprivate(v)
+
+int main () {
+ static int a;
+// CHECK: static int a;
+#pragma omp threadprivate(a)
+// CHECK-NEXT: #pragma omp threadprivate(a)
+ a=2;
+ return (foo<int>());
+}
diff --git a/test/OpenMP/threadprivate_messages.cpp b/test/OpenMP/threadprivate_messages.cpp
new file mode 100644
index 0000000..0c448b2
--- /dev/null
+++ b/test/OpenMP/threadprivate_messages.cpp
@@ -0,0 +1,119 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s
+
+#pragma omp threadprivate // expected-error {{expected '(' after 'threadprivate'}}
+#pragma omp threadprivate( // expected-error {{expected unqualified-id}}
+#pragma omp threadprivate() // expected-error {{expected unqualified-id}}
+#pragma omp threadprivate(1) // expected-error {{expected unqualified-id}}
+struct CompleteSt{
+ int a;
+};
+
+struct CompleteSt1{
+#pragma omp threadprivate(1) // expected-error {{expected unqualified-id}}
+ int a;
+} d; // expected-note {{forward declaration of 'd'}}
+
+int a; // expected-note {{forward declaration of 'a'}}
+
+#pragma omp threadprivate(a)
+#pragma omp threadprivate(u) // expected-error {{use of undeclared identifier 'u'}}
+#pragma omp threadprivate(d, a) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'a'}}
+int foo() { // expected-note {{declared here}}
+ static int l;
+#pragma omp threadprivate(l)) // expected-warning {{extra tokens at end of '#pragma omp threadprivate' are ignored}}
+ return (a);
+}
+
+#pragma omp threadprivate a // expected-error {{expected '(' after 'threadprivate'}}
+#pragma omp threadprivate(d // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{'#pragma omp threadprivate' must precede all references to variable 'd'}}
+#pragma omp threadprivate(d))
+int x, y;
+#pragma omp threadprivate(x)) // expected-warning {{extra tokens at end of '#pragma omp threadprivate' are ignored}}
+#pragma omp threadprivate(y)), // expected-warning {{extra tokens at end of '#pragma omp threadprivate' are ignored}}
+#pragma omp threadprivate(a,d) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'a'}} expected-error {{'#pragma omp threadprivate' must precede all references to variable 'd'}}
+#pragma omp threadprivate(d.a) // expected-error {{expected unqualified-id}}
+#pragma omp threadprivate((float)a) // expected-error {{expected unqualified-id}}
+int foa;
+#pragma omp threadprivate(faa) // expected-error {{use of undeclared identifier 'faa'; did you mean 'foa'?}}
+#pragma omp threadprivate(foo) // expected-error {{'foo' is not a global variable, static local variable or static data member}}
+#pragma omp threadprivate (int a=2) // expected-error {{expected unqualified-id}}
+
+struct IncompleteSt; // expected-note {{forward declaration of 'IncompleteSt'}}
+
+extern IncompleteSt e;
+#pragma omp threadprivate (e) // expected-error {{a threadprivate variable must not have incomplete type 'IncompleteSt'}}
+
+int &f = a; // expected-note {{forward declaration of 'f'}}
+#pragma omp threadprivate (f) // expected-error {{arguments of '#pragma omp threadprivate' cannot be of reference type 'int &'}}
+
+class Class {
+ private:
+ int a; // expected-note {{declared here}}
+ static int b;
+ Class() : a(0){}
+ public:
+ Class (int aaa) : a(aaa) {}
+#pragma omp threadprivate (b, a) // expected-error {{'a' is not a global variable, static local variable or static data member}}
+} g(10);
+#pragma omp threadprivate (b) // expected-error {{use of undeclared identifier 'b'}}
+#pragma omp threadprivate (Class::b) // expected-error {{expected unqualified-id}}
+#pragma omp threadprivate (g)
+
+namespace ns {
+ int m;
+#pragma omp threadprivate (m)
+}
+#pragma omp threadprivate (m) // expected-error {{use of undeclared identifier 'm'}}
+#pragma omp threadprivate (ns::m) // expected-error {{expected unqualified-id}}
+#pragma omp threadprivate (ns:m) // expected-error {{expected unqualified-id}}
+
+const int h = 12;
+const volatile int i = 10;
+#pragma omp threadprivate (h, i)
+
+
+template <class T>
+class TempClass {
+ private:
+ T a;
+ TempClass() : a(){}
+ public:
+ TempClass (T aaa) : a(aaa) {}
+ static T s;
+#pragma omp threadprivate (s)
+};
+#pragma omp threadprivate (s) // expected-error {{use of undeclared identifier 's'}}
+
+static __thread int t; // expected-note {{forward declaration of 't'}}
+#pragma omp threadprivate (t) // expected-error {{variable 't' cannot be threadprivate because it is thread-local}}
+
+int o; // expected-note {{candidate found by name lookup is 'o'}}
+namespace {
+int o; // expected-note {{candidate found by name lookup is '<anonymous namespace>::o'}}
+}
+#pragma omp threadprivate (o) // expected-error {{reference to 'o' is ambiguous}}
+
+int main(int argc, char **argv) { // expected-note {{forward declaration of 'argc'}}
+
+ int x, y = argc; // expected-note {{forward declaration of 'y'}}
+ static double d1;
+ static double d2;
+ static double d3; // expected-note {{forward declaration of 'd3'}}
+
+ d.a = a;
+ d2++;
+ ;
+#pragma omp threadprivate(argc+y) // expected-error {{expected unqualified-id}}
+#pragma omp threadprivate(argc,y) // expected-error 2 {{arguments of '#pragma omp threadprivate' must have static storage duration}}
+#pragma omp threadprivate(d2) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'd2'}}
+#pragma omp threadprivate(d1)
+ {
+ ++a;d2=0;
+#pragma omp threadprivate(d3) // expected-error {{'#pragma omp threadprivate' must appear in the scope of the 'd3' variable declaration}}
+ }
+#pragma omp threadprivate(d3)
+
+#pragma omp threadprivate(a) // expected-error {{'#pragma omp threadprivate' must appear in the scope of the 'a' variable declaration}}
+ return (y);
+#pragma omp threadprivate(d) // expected-error {{'#pragma omp threadprivate' must appear in the scope of the 'd' variable declaration}}
+}
diff --git a/test/PCH/Inputs/cxx-method.h b/test/PCH/Inputs/cxx-method.h
index 6adb859..d5d56fe 100644
--- a/test/PCH/Inputs/cxx-method.h
+++ b/test/PCH/Inputs/cxx-method.h
@@ -1,6 +1,9 @@
struct S {
void m(int x);
+ S();
+ S(const S&);
+
operator const char*();
operator char*();
};
diff --git a/test/PCH/chain-late-anonymous-namespace.cpp b/test/PCH/chain-late-anonymous-namespace.cpp
index 87205c6..edae285 100644
--- a/test/PCH/chain-late-anonymous-namespace.cpp
+++ b/test/PCH/chain-late-anonymous-namespace.cpp
@@ -2,6 +2,8 @@
// RUN: %clang_cc1 -include %s -include %s -fsyntax-only %s
// with PCH
// RUN: %clang_cc1 -chain-include %s -chain-include %s -fsyntax-only %s
+// with PCH, with modules enabled
+// RUN: %clang_cc1 -chain-include %s -chain-include %s -fsyntax-only -fmodules %s
#if !defined(PASS1)
#define PASS1
diff --git a/test/PCH/crash-12631281.cpp b/test/PCH/crash-12631281.cpp
new file mode 100644
index 0000000..f309bca
--- /dev/null
+++ b/test/PCH/crash-12631281.cpp
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -std=c++11 %s -emit-pch -o %t.pch
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -include-pch %t.pch -verify
+// expected-no-diagnostics
+
+// rdar://12631281
+// This reduced test case exposed a use-after-free memory bug, which was reliable
+// reproduced only on guarded malloc (and probably valgrind).
+
+#ifndef HEADER
+#define HEADER
+
+template < class _T2> struct is_convertible;
+template <> struct is_convertible<int> { typedef int type; };
+
+template <class _T1, class _T2> struct pair {
+ typedef _T1 first_type;
+ typedef _T2 second_type;
+ template <class _U1, class _U2, class = typename is_convertible< first_type>::type>
+ pair(_U1&& , _U2&& ); // expected-note {{candidate}}
+};
+
+template <class _ForwardIterator>
+pair<_ForwardIterator, _ForwardIterator> __equal_range(_ForwardIterator) {
+ return pair<_ForwardIterator, _ForwardIterator>(0, 0); // expected-error {{no matching constructor}}
+}
+
+template <class _ForwardIterator>
+pair<_ForwardIterator, _ForwardIterator> equal_range( _ForwardIterator a) {
+ return __equal_range(a); // expected-note {{instantiation}}
+}
+
+class A {
+ pair<int, int> range() {
+ return equal_range(0); // expected-note {{instantiation}}
+ }
+};
+
+#else
+
+#endif
diff --git a/test/PCH/cxx-constexpr.cpp b/test/PCH/cxx-constexpr.cpp
index 8fe48f7..13f04a7 100644
--- a/test/PCH/cxx-constexpr.cpp
+++ b/test/PCH/cxx-constexpr.cpp
@@ -4,6 +4,9 @@
// RUN: %clang_cc1 -pedantic-errors -std=c++11 -emit-pch %s -o %t-cxx11
// RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t-cxx11 -verify %s
+// RUN: %clang_cc1 -pedantic-errors -std=c++98 -emit-pch %s -o %t -fmodules
+// RUN: %clang_cc1 -pedantic-errors -std=c++98 -include-pch %t -verify %s -fmodules
+
#ifndef HEADER_INCLUDED
#define HEADER_INCLUDED
diff --git a/test/PCH/cxx-method.cpp b/test/PCH/cxx-method.cpp
index 40490ea..c24ad92 100644
--- a/test/PCH/cxx-method.cpp
+++ b/test/PCH/cxx-method.cpp
@@ -1,3 +1,4 @@
+// RUN: %clang_cc1 -x c++ -include %S/Inputs/cxx-method.h -verify %s
// 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
@@ -7,3 +8,8 @@ void S::m(int x) { }
S::operator char *() { return 0; }
S::operator const char *() { return 0; }
+
+struct T : S {};
+
+const T a = T();
+T b(a);
diff --git a/test/PCH/cxx-templates.cpp b/test/PCH/cxx-templates.cpp
index d27e9ca..58c4c17 100644
--- a/test/PCH/cxx-templates.cpp
+++ b/test/PCH/cxx-templates.cpp
@@ -5,7 +5,7 @@
// Test with pch.
// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fexceptions -x c++-header -emit-pch -o %t %S/cxx-templates.h
// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fexceptions -include-pch %t -verify %s -ast-dump -o -
-// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fexceptions -include-pch %t %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -fcxx-exceptions -fexceptions -include-pch %t %s -emit-llvm -o - -error-on-deserialized-decl doNotDeserialize | FileCheck %s
// expected-no-diagnostics
@@ -79,3 +79,9 @@ namespace TestNestedExpansion {
Int &g(Int, int, double);
Int &test = NestedExpansion<char, char, char>().f(0, 1, 2, Int(3), 4, 5.0);
}
+
+namespace rdar13135282 {
+ void test() {
+ __mt_alloc<> mt = __mt_alloc<>();
+ }
+}
diff --git a/test/PCH/cxx-templates.h b/test/PCH/cxx-templates.h
index 756f208..e672b0b 100644
--- a/test/PCH/cxx-templates.h
+++ b/test/PCH/cxx-templates.h
@@ -220,3 +220,52 @@ template<typename...A> struct NestedExpansion {
template<typename...B> auto f(A...a, B...b) -> decltype(g(a + b...));
};
template struct NestedExpansion<char, char, char>;
+
+namespace rdar13135282 {
+template < typename _Alloc >
+void foo(_Alloc = _Alloc());
+
+template < bool > class __pool;
+
+template < template < bool > class _PoolTp >
+struct __common_pool {
+ typedef _PoolTp < 0 > pool_type;
+};
+
+template < template < bool > class _PoolTp >
+struct __common_pool_base : __common_pool < _PoolTp > {};
+
+template < template < bool > class _PoolTp >
+struct A : __common_pool_base < _PoolTp > {};
+
+template < typename _Poolp = A < __pool > >
+struct __mt_alloc {
+ typedef typename _Poolp::pool_type __pool_type;
+ __mt_alloc() {
+ foo<__mt_alloc<> >();
+ }
+};
+}
+
+namespace PR13020 {
+template<typename T>
+void f() {
+ enum E {
+ enumerator
+ };
+
+ T t = enumerator;
+}
+
+template void f<int>();
+}
+
+template<typename T> void doNotDeserialize() {}
+template<typename T> struct ContainsDoNotDeserialize {
+ static int doNotDeserialize;
+};
+template<typename T> struct ContainsDoNotDeserialize2 {
+ static void doNotDeserialize();
+};
+template<typename T> int ContainsDoNotDeserialize<T>::doNotDeserialize = 0;
+template<typename T> void ContainsDoNotDeserialize2<T>::doNotDeserialize() {}
diff --git a/test/PCH/cxx0x-default-delete.cpp b/test/PCH/cxx0x-default-delete.cpp
index 39a90b8..230f6a6 100644
--- a/test/PCH/cxx0x-default-delete.cpp
+++ b/test/PCH/cxx0x-default-delete.cpp
@@ -20,6 +20,11 @@ class quux {
~quux() = default;
};
+struct A {
+ A(const A&) = default;
+ template<typename T> A(T&&);
+};
+
#else
foo::foo() { } // expected-error{{definition of explicitly defaulted default constructor}}
@@ -31,4 +36,11 @@ void fn() {
baz bz; // expected-error{{deleted function}} expected-note@16{{deleted here}}
quux qx; // expected-error{{private destructor}} expected-note@20{{private here}}
+struct B { A a; };
+struct C { mutable A a; };
+static_assert(__is_trivially_constructible(B, const B&), "");
+static_assert(!__is_trivially_constructible(B, B&&), "");
+static_assert(!__is_trivially_constructible(C, const C&), "");
+static_assert(!__is_trivially_constructible(C, C&&), "");
+
#endif
diff --git a/test/PCH/floating-literal.c b/test/PCH/floating-literal.c
new file mode 100644
index 0000000..7bf10d4
--- /dev/null
+++ b/test/PCH/floating-literal.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -triple mips64-none-linux-gnu -emit-pch -o %t %s
+// RUN: %clang_cc1 -x ast -ast-print %t | FileCheck %s
+
+// Make sure the semantics of FloatingLiterals are stored correctly in
+// the AST. Previously, the ASTWriter didn't store anything and the
+// reader assumed PPC 128-bit float semantics, which is incorrect for
+// targets with 128-bit IEEE long doubles.
+
+long double foo = 1.0E4000L;
+// CHECK: long double foo = 1.0E+4000L;
+
+// Just as well check the others are still sane while we're here...
+
+double bar = 1.0E300;
+// CHECK: double bar = 1.0E+300;
+
+float wibble = 1.0E40;
+// CHECK: float wibble = 1.0E+40;
diff --git a/test/PCH/irgen-rdar13114142.mm b/test/PCH/irgen-rdar13114142.mm
new file mode 100644
index 0000000..bd523c2
--- /dev/null
+++ b/test/PCH/irgen-rdar13114142.mm
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 %s -emit-pch -o %t.pch
+// RUN: %clang_cc1 %s -emit-llvm %s -include-pch %t.pch -o - | FileCheck %s
+
+#ifndef HEADER
+#define HEADER
+
+class OOArray{
+public:
+ ~OOArray();
+};
+
+class OOString {
+public:
+ OOString();
+ OOString(char *);
+};
+
+class OOPattern {
+public:
+ OOArray matchAll(const OOString &)const {
+ __attribute__((__blocks__(byref))) OOArray out;
+ }
+};
+
+OOArray operator & (const OOPattern & pattern) {
+ pattern.matchAll(0);
+}
+OOArray operator & (OOString, OOString);
+
+#else
+
+// We just make sure there is no crash on IRGen (rdar://13114142)
+// CHECK: _Z3foov()
+void foo() {
+ OOString str;
+ str & "o";
+}
+
+#endif
diff --git a/test/PCH/macro-redef.c b/test/PCH/macro-redef.c
new file mode 100644
index 0000000..7e25d7f
--- /dev/null
+++ b/test/PCH/macro-redef.c
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 %s -emit-pch -o %t1.pch -verify
+// RUN: %clang_cc1 %s -emit-pch -o %t2.pch -include-pch %t1.pch -verify
+// RUN: %clang_cc1 -fsyntax-only %s -include-pch %t2.pch -verify
+
+// Test that a redefinition inside the PCH won't manifest as an ambiguous macro.
+// rdar://13016031
+
+#ifndef HEADER1
+#define HEADER1
+
+#define M1 0 // expected-note {{previous}}
+#define M1 1 // expected-warning {{redefined}}
+
+#define M2 3
+
+#elif !defined(HEADER2)
+#define HEADER2
+
+#define M2 4 // expected-warning {{redefined}}
+ // expected-note@-6 {{previous}}
+
+#else
+
+// Use the error to verify it was parsed.
+int x = M1; // expected-note {{previous}}
+int x = M2; // expected-error {{redefinition}}
+
+#endif
diff --git a/test/PCH/missing-file.cpp b/test/PCH/missing-file.cpp
index 7dd11d4..502a9db 100644
--- a/test/PCH/missing-file.cpp
+++ b/test/PCH/missing-file.cpp
@@ -7,6 +7,7 @@
// %t.h might be touched by scanners as a hot file on Windows,
// to fail to remove %.h with single run.
+// FIXME: Do we really want to work around bugs in virus checkers here?
// RUN: rm %t.h || rm %t.h || rm %t.h
// Check diagnostic with location in original source:
diff --git a/test/PCH/modified-header-crash.c b/test/PCH/modified-header-crash.c
index c74ce22..4c21a8c 100644
--- a/test/PCH/modified-header-crash.c
+++ b/test/PCH/modified-header-crash.c
@@ -2,9 +2,12 @@
// RUN: cp %S/modified-header-crash.h %t.h
// RUN: %clang_cc1 -DCAKE -x c-header %t.h -emit-pch -o %t
-// RUN: echo >> %t.h
+// RUN: echo 'int foobar;' >> %t.h
// RUN: not %clang_cc1 %s -include-pch %t -fsyntax-only
+// FIXME: It is intended to suppress this on win32.
+// REQUIRES: ansi-escape-sequences
+
void f(void) {
foo = 3;
}
diff --git a/test/PCH/modified-header-error.c b/test/PCH/modified-header-error.c
index ef92494..4ad3faf 100644
--- a/test/PCH/modified-header-error.c
+++ b/test/PCH/modified-header-error.c
@@ -8,5 +8,5 @@
#include "header2.h"
-// CHECK: fatal error: file {{.*}} has been modified since the precompiled header was built
+// CHECK: fatal error: file {{.*}} has been modified since the precompiled header {{.*}} was built
// REQUIRES: shell
diff --git a/test/PCH/multiple-include-pch.c b/test/PCH/multiple-include-pch.c
new file mode 100644
index 0000000..1ef17b9
--- /dev/null
+++ b/test/PCH/multiple-include-pch.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -emit-pch -o %t1.pch %s
+// RUN: %clang_cc1 -emit-pch -o %t2.pch %s
+// RUN: %clang_cc1 %s -include-pch %t1.pch -include-pch %t2.pch -verify
+
+#ifndef HEADER
+#define HEADER
+
+extern int x;
+
+#else
+
+#warning parsed this
+// expected-warning@-1 {{parsed this}}
+int foo() {
+ return x;
+}
+
+#endif
diff --git a/test/PCH/objc_container.m b/test/PCH/objc_container.m
index 07371ca..aafe6a9 100644
--- a/test/PCH/objc_container.m
+++ b/test/PCH/objc_container.m
@@ -14,9 +14,12 @@
// CHECK-PRINT: oldObject = dictionary[key];
// CHECK-PRINT: dictionary[key] = newObject;
-// CHECK-IR: define void @all() nounwind
+// CHECK-IR: define void @all() #0
// CHECK-IR: {{call.*objc_msgSend}}
// CHECK-IR: {{call.*objc_msgSend}}
// CHECK-IR: {{call.*objc_msgSend}}
// CHECK-IR: {{call.*objc_msgSend}}
// CHECK-IR: ret void
+
+// CHECK: attributes #0 = { nounwind {{.*}} }
+// CHECK: attributes #1 = { nonlazybind }
diff --git a/test/PCH/objc_stmts.m b/test/PCH/objc_stmts.m
index b9b10c5..8deb14a 100644
--- a/test/PCH/objc_stmts.m
+++ b/test/PCH/objc_stmts.m
@@ -1,12 +1,12 @@
// Test this without pch.
// RUN: %clang_cc1 -include %S/objc_stmts.h -emit-llvm -fobjc-exceptions -o - %s
-// RUN: %clang_cc1 -include %S/objc_stmts.h -ast-dump -fobjc-exceptions -o - %s | FileCheck %s
+// RUN: %clang_cc1 -include %S/objc_stmts.h -ast-print -fobjc-exceptions -o - %s | FileCheck %s
// Test with pch.
// RUN: %clang_cc1 -x objective-c -emit-pch -fobjc-exceptions -o %t %S/objc_stmts.h
// RUN: %clang_cc1 -include-pch %t -emit-llvm -fobjc-exceptions -o - %s
-// RUN: %clang_cc1 -include-pch %t -ast-dump -fobjc-exceptions -o - %s | FileCheck %s
+// RUN: %clang_cc1 -include-pch %t -ast-print -fobjc-exceptions -o - %s | FileCheck %s
-// CHECK: catch parm = "A *a"
-// CHECK: catch parm = "B *b"
-// CHECK: catch all
+// CHECK: @catch(A *a)
+// CHECK: @catch(B *b)
+// CHECK: @catch()
diff --git a/test/PCH/ocl_types.cl b/test/PCH/ocl_types.cl
new file mode 100644
index 0000000..d788a32
--- /dev/null
+++ b/test/PCH/ocl_types.cl
@@ -0,0 +1,26 @@
+// Test this without pch.
+// RUN: %clang_cc1 -include %S/ocl_types.h -fsyntax-only %s
+
+// Test with pch.
+// RUN: %clang_cc1 -x cl -emit-pch -o %t %S/ocl_types.h
+// RUN: %clang_cc1 -include-pch %t -fsyntax-only %s -ast-print
+
+void foo1(img1d_t img);
+
+void foo2(img1darr_t img);
+
+void foo3(img1dbuff_t img);
+
+void foo4(img2d_t img);
+
+void foo5(img2darr_t img);
+
+void foo6(img3d_t img);
+
+void foo7(smp_t smp) {
+ smp_t loc_smp;
+}
+
+void foo8(evt_t evt) {
+ evt_t loc_evt;
+}
diff --git a/test/PCH/ocl_types.h b/test/PCH/ocl_types.h
new file mode 100644
index 0000000..65c6acb
--- /dev/null
+++ b/test/PCH/ocl_types.h
@@ -0,0 +1,25 @@
+/* Used with the ocl_types.cl test */
+
+// image1d_t
+typedef image1d_t img1d_t;
+
+// image1d_array_t
+typedef image1d_array_t img1darr_t;
+
+// image1d_buffer_t
+typedef image1d_buffer_t img1dbuff_t;
+
+// image2d_t
+typedef image2d_t img2d_t;
+
+// image2d_array_t
+typedef image2d_array_t img2darr_t;
+
+// image3d_t
+typedef image3d_t img3d_t;
+
+// sampler_t
+typedef sampler_t smp_t;
+
+// event_t
+typedef event_t evt_t;
diff --git a/test/PCH/thread-safety-attrs.cpp b/test/PCH/thread-safety-attrs.cpp
new file mode 100644
index 0000000..a588c0e
--- /dev/null
+++ b/test/PCH/thread-safety-attrs.cpp
@@ -0,0 +1,317 @@
+// Test this without pch.
+// RUN: %clang_cc1 -include %s -fsyntax-only -verify -Wthread-safety -std=c++11 %s
+
+// Test with pch.
+// RUN: %clang_cc1 -emit-pch -o %t %s -std=c++11
+// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify -Wthread-safety -std=c++11 %s
+
+#ifndef HEADER
+#define HEADER
+
+#define LOCKABLE __attribute__ ((lockable))
+#define SCOPED_LOCKABLE __attribute__ ((scoped_lockable))
+#define GUARDED_BY(x) __attribute__ ((guarded_by(x)))
+#define GUARDED_VAR __attribute__ ((guarded_var))
+#define PT_GUARDED_BY(x) __attribute__ ((pt_guarded_by(x)))
+#define PT_GUARDED_VAR __attribute__ ((pt_guarded_var))
+#define ACQUIRED_AFTER(...) __attribute__ ((acquired_after(__VA_ARGS__)))
+#define ACQUIRED_BEFORE(...) __attribute__ ((acquired_before(__VA_ARGS__)))
+#define EXCLUSIVE_LOCK_FUNCTION(...) __attribute__ ((exclusive_lock_function(__VA_ARGS__)))
+#define SHARED_LOCK_FUNCTION(...) __attribute__ ((shared_lock_function(__VA_ARGS__)))
+#define EXCLUSIVE_TRYLOCK_FUNCTION(...) __attribute__ ((exclusive_trylock_function(__VA_ARGS__)))
+#define SHARED_TRYLOCK_FUNCTION(...) __attribute__ ((shared_trylock_function(__VA_ARGS__)))
+#define UNLOCK_FUNCTION(...) __attribute__ ((unlock_function(__VA_ARGS__)))
+#define LOCK_RETURNED(x) __attribute__ ((lock_returned(x)))
+#define LOCKS_EXCLUDED(...) __attribute__ ((locks_excluded(__VA_ARGS__)))
+#define EXCLUSIVE_LOCKS_REQUIRED(...) \
+ __attribute__ ((exclusive_locks_required(__VA_ARGS__)))
+#define SHARED_LOCKS_REQUIRED(...) \
+ __attribute__ ((shared_locks_required(__VA_ARGS__)))
+#define NO_THREAD_SAFETY_ANALYSIS __attribute__ ((no_thread_safety_analysis))
+
+
+class __attribute__((lockable)) Mutex {
+ public:
+ void Lock() __attribute__((exclusive_lock_function));
+ void ReaderLock() __attribute__((shared_lock_function));
+ void Unlock() __attribute__((unlock_function));
+ bool TryLock() __attribute__((exclusive_trylock_function(true)));
+ bool ReaderTryLock() __attribute__((shared_trylock_function(true)));
+ void LockWhen(const int &cond) __attribute__((exclusive_lock_function));
+};
+
+class __attribute__((scoped_lockable)) MutexLock {
+ public:
+ MutexLock(Mutex *mu) __attribute__((exclusive_lock_function(mu)));
+ ~MutexLock() __attribute__((unlock_function));
+};
+
+class __attribute__((scoped_lockable)) ReaderMutexLock {
+ public:
+ ReaderMutexLock(Mutex *mu) __attribute__((exclusive_lock_function(mu)));
+ ~ReaderMutexLock() __attribute__((unlock_function));
+};
+
+class SCOPED_LOCKABLE ReleasableMutexLock {
+ public:
+ ReleasableMutexLock(Mutex *mu) EXCLUSIVE_LOCK_FUNCTION(mu);
+ ~ReleasableMutexLock() UNLOCK_FUNCTION();
+
+ void Release() UNLOCK_FUNCTION();
+};
+
+
+// The universal lock, written "*", allows checking to be selectively turned
+// off for a particular piece of code.
+void beginNoWarnOnReads() SHARED_LOCK_FUNCTION("*");
+void endNoWarnOnReads() UNLOCK_FUNCTION("*");
+void beginNoWarnOnWrites() EXCLUSIVE_LOCK_FUNCTION("*");
+void endNoWarnOnWrites() UNLOCK_FUNCTION("*");
+
+
+// For testing handling of smart pointers.
+template<class T>
+class SmartPtr {
+public:
+ SmartPtr(T* p) : ptr_(p) { }
+ SmartPtr(const SmartPtr<T>& p) : ptr_(p.ptr_) { }
+ ~SmartPtr();
+
+ T* get() const { return ptr_; }
+ T* operator->() const { return ptr_; }
+ T& operator*() const { return *ptr_; }
+
+private:
+ T* ptr_;
+};
+
+
+// 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)));
+int sls_guard_var __attribute__((guarded_var)) = 0;
+int sls_guardby_var __attribute__((guarded_by(sls_mu))) = 0;
+
+bool getBool();
+
+class MutexWrapper {
+public:
+ Mutex mu;
+ int x __attribute__((guarded_by(mu)));
+ void MyLock() __attribute__((exclusive_lock_function(mu)));
+};
+
+#else
+
+MutexWrapper sls_mw;
+
+void sls_fun_0() {
+ sls_mw.mu.Lock();
+ sls_mw.x = 5;
+ sls_mw.mu.Unlock();
+}
+
+void sls_fun_2() {
+ sls_mu.Lock();
+ int x = sls_guard_var;
+ sls_mu.Unlock();
+}
+
+void sls_fun_3() {
+ sls_mu.Lock();
+ sls_guard_var = 2;
+ sls_mu.Unlock();
+}
+
+void sls_fun_4() {
+ sls_mu2.Lock();
+ sls_guard_var = 2;
+ sls_mu2.Unlock();
+}
+
+void sls_fun_5() {
+ sls_mu.Lock();
+ int x = sls_guardby_var;
+ sls_mu.Unlock();
+}
+
+void sls_fun_6() {
+ sls_mu.Lock();
+ sls_guardby_var = 2;
+ sls_mu.Unlock();
+}
+
+void sls_fun_7() {
+ sls_mu.Lock();
+ sls_mu2.Lock();
+ sls_mu2.Unlock();
+ sls_mu.Unlock();
+}
+
+void sls_fun_8() {
+ sls_mu.Lock();
+ if (getBool())
+ sls_mu.Unlock();
+ else
+ sls_mu.Unlock();
+}
+
+void sls_fun_9() {
+ if (getBool())
+ sls_mu.Lock();
+ else
+ sls_mu.Lock();
+ sls_mu.Unlock();
+}
+
+void sls_fun_good_6() {
+ if (getBool()) {
+ sls_mu.Lock();
+ } else {
+ if (getBool()) {
+ getBool(); // EMPTY
+ } else {
+ getBool(); // EMPTY
+ }
+ sls_mu.Lock();
+ }
+ sls_mu.Unlock();
+}
+
+void sls_fun_good_7() {
+ sls_mu.Lock();
+ while (getBool()) {
+ sls_mu.Unlock();
+ if (getBool()) {
+ if (getBool()) {
+ sls_mu.Lock();
+ continue;
+ }
+ }
+ sls_mu.Lock();
+ }
+ sls_mu.Unlock();
+}
+
+void sls_fun_good_8() {
+ sls_mw.MyLock();
+ sls_mw.mu.Unlock();
+}
+
+void sls_fun_bad_1() {
+ sls_mu.Unlock(); // \
+ // expected-warning{{unlocking 'sls_mu' that was not locked}}
+}
+
+void sls_fun_bad_2() {
+ sls_mu.Lock();
+ sls_mu.Lock(); // \
+ // expected-warning{{locking 'sls_mu' that is already locked}}
+ sls_mu.Unlock();
+}
+
+void sls_fun_bad_3() {
+ sls_mu.Lock(); // expected-note {{mutex acquired here}}
+} // expected-warning{{mutex 'sls_mu' is still locked at the end of function}}
+
+void sls_fun_bad_4() {
+ if (getBool())
+ sls_mu.Lock(); // expected-note{{mutex acquired here}}
+ else
+ sls_mu2.Lock(); // expected-note{{mutex acquired here}}
+} // expected-warning{{mutex 'sls_mu' is not locked on every path through here}} \
+ // expected-warning{{mutex 'sls_mu2' is not locked on every path through here}}
+
+void sls_fun_bad_5() {
+ sls_mu.Lock(); // expected-note {{mutex acquired here}}
+ if (getBool())
+ sls_mu.Unlock();
+} // expected-warning{{mutex 'sls_mu' is not locked on every path through here}}
+
+void sls_fun_bad_6() {
+ if (getBool()) {
+ sls_mu.Lock(); // expected-note {{mutex acquired here}}
+ } else {
+ if (getBool()) {
+ getBool(); // EMPTY
+ } else {
+ getBool(); // EMPTY
+ }
+ }
+ sls_mu.Unlock(); // \
+ expected-warning{{mutex 'sls_mu' is not locked on every path through here}}\
+ expected-warning{{unlocking 'sls_mu' that was not locked}}
+}
+
+void sls_fun_bad_7() {
+ sls_mu.Lock();
+ while (getBool()) {
+ sls_mu.Unlock();
+ if (getBool()) {
+ if (getBool()) {
+ continue; // \
+ expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
+ }
+ }
+ sls_mu.Lock(); // expected-note {{mutex acquired here}}
+ }
+ sls_mu.Unlock();
+}
+
+void sls_fun_bad_8() {
+ sls_mu.Lock(); // expected-note{{mutex acquired here}}
+
+ do {
+ sls_mu.Unlock(); // expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
+ } while (getBool());
+}
+
+void sls_fun_bad_9() {
+ do {
+ sls_mu.Lock(); // \
+ // expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}} \
+ // expected-note{{mutex acquired here}}
+ } while (getBool());
+ sls_mu.Unlock();
+}
+
+void sls_fun_bad_10() {
+ sls_mu.Lock(); // expected-note 2{{mutex acquired here}}
+ while(getBool()) { // expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
+ sls_mu.Unlock();
+ }
+} // expected-warning{{mutex 'sls_mu' is still locked at the end of function}}
+
+void sls_fun_bad_11() {
+ while (getBool()) { // \
+ expected-warning{{expecting mutex 'sls_mu' to be locked at start of each loop}}
+ sls_mu.Lock(); // expected-note {{mutex acquired here}}
+ }
+ sls_mu.Unlock(); // \
+ // expected-warning{{unlocking 'sls_mu' that was not locked}}
+}
+
+void sls_fun_bad_12() {
+ sls_mu.Lock(); // expected-note {{mutex acquired here}}
+ while (getBool()) {
+ sls_mu.Unlock();
+ if (getBool()) {
+ if (getBool()) {
+ break; // expected-warning{{mutex 'sls_mu' is not locked on every path through here}}
+ }
+ }
+ sls_mu.Lock();
+ }
+ sls_mu.Unlock();
+}
+
+#endif
diff --git a/test/PCH/undefined-internal.c b/test/PCH/undefined-internal.c
new file mode 100644
index 0000000..ef51460
--- /dev/null
+++ b/test/PCH/undefined-internal.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -emit-pch %s -o %t
+// RUN: %clang_cc1 -include-pch %t %s -verify
+#ifndef HEADER_H
+#define HEADER_H
+static void f();
+static void g();
+void h() {
+ f();
+ g();
+}
+#else
+static void g() {}
+// expected-warning@5{{function 'f' has internal linkage but is not defined}}
+// expected-note@8{{used here}}
+#endif
diff --git a/test/Parser/MicrosoftExtensions.c b/test/Parser/MicrosoftExtensions.c
index 7703999..4c6f4f8 100644
--- a/test/Parser/MicrosoftExtensions.c
+++ b/test/Parser/MicrosoftExtensions.c
@@ -20,12 +20,15 @@ void * __ptr32 PtrToPtr32(const void *p)
void __forceinline InterlockedBitTestAndSet (long *Base, long Bit)
{
- __asm { // expected-warning {{MS-style inline assembly is not supported}}
+ // FIXME: Re-enable this once MS inline asm stabilizes.
+#if 0
+ __asm {
mov eax, Bit
mov ecx, Base
lock bts [ecx], eax
setc al
};
+#endif
}
_inline int foo99() { return 99; }
diff --git a/test/Parser/asm.c b/test/Parser/asm.c
index 23052c3..b95e08b 100644
--- a/test/Parser/asm.c
+++ b/test/Parser/asm.c
@@ -8,6 +8,12 @@ void f1() {
void f2() {
asm("foo" : "=r" (a)); // expected-error {{use of undeclared identifier 'a'}}
asm("foo" : : "r" (b)); // expected-error {{use of undeclared identifier 'b'}}
+
+ asm const (""); // expected-warning {{ignored const qualifier on asm}}
+ asm volatile ("");
+ asm restrict (""); // expected-warning {{ignored restrict qualifier on asm}}
+ // FIXME: Once GCC supports _Atomic, check whether it allows this.
+ asm _Atomic (""); // expected-warning {{ignored _Atomic qualifier on asm}}
}
diff --git a/test/Parser/atomic.c b/test/Parser/atomic.c
new file mode 100644
index 0000000..432deeb
--- /dev/null
+++ b/test/Parser/atomic.c
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -std=c11 %s -fsyntax-only -verify -pedantic
+
+typedef _Atomic(int) atomic_int;
+typedef _Atomic int atomic_int;
+typedef _Atomic _Atomic _Atomic(int) atomic_int; // expected-warning {{duplicate '_Atomic' declaration specifier}}
+
+typedef const int const_int;
+
+typedef const atomic_int const_atomic_int;
+typedef _Atomic const int const_atomic_int;
+typedef const _Atomic int const_atomic_int;
+typedef const _Atomic(int) const_atomic_int;
+typedef const _Atomic(_Atomic int) const_atomic_int; // expected-error {{_Atomic cannot be applied to atomic type '_Atomic(int)'}}
+typedef _Atomic const_int const_atomic_int;
+typedef _Atomic(const_int) const_atomic_int; // expected-error {{_Atomic cannot be applied to qualified type 'const_int' (aka 'const int')}}
+
+typedef int *_Atomic atomic_int_ptr;
+typedef _Atomic(int *) atomic_int_ptr;
+typedef int (*_Atomic atomic_int_ptr);
+
+typedef int _Atomic *int_atomic_ptr;
+typedef _Atomic(int) *int_atomic_ptr;
+
+typedef int int_fn();
+typedef _Atomic int_fn atomic_int_fn; // expected-error {{_Atomic cannot be applied to function type 'int_fn' (aka 'int ()')}}
+typedef _Atomic int atomic_int_array[3];
+typedef _Atomic atomic_int_array atomic_int_atomic_array; // expected-error {{_Atomic cannot be applied to array type 'atomic_int_array' (aka '_Atomic(int) [3]')}}
+
+_Atomic struct S { int n; }; // expected-warning {{'_Atomic' ignored on this declaration}}
+
+typedef _Atomic int __attribute__((address_space(1))) atomic_addr_space_int;
+typedef _Atomic(int) __attribute__((address_space(1))) atomic_addr_space_int;
+
+typedef _Atomic int __attribute__((vector_size(16))) atomic_vector_int;
+typedef _Atomic(int __attribute__((vector_size(16)))) atomic_vector_int;
diff --git a/test/Parser/attr-availability.c b/test/Parser/attr-availability.c
index b9ff31c..0ed8391 100644
--- a/test/Parser/attr-availability.c
+++ b/test/Parser/attr-availability.c
@@ -20,7 +20,7 @@ void f6() __attribute__((availability(macosx,unavailable,introduced=10.5))); //
// rdar://10095131
enum E{
- gorf __attribute__((availability(macosx,introduced=8.5, message = 10.0))), // expected-error {{expected string literal}}
+ gorf __attribute__((availability(macosx,introduced=8.5, message = 10.0))), // expected-error {{expected string literal for optional message in 'availability' attribute}}
garf __attribute__((availability(macosx,introduced=8.5, message))), // expected-error {{expected '=' after 'message'}}
foo __attribute__((availability(macosx,introduced=8.5,deprecated=9.0, message="Use CTFontCopyPostScriptName()", deprecated=10.0))) // expected-error {{expected ')'}} \
diff --git a/test/Parser/attributes.mm b/test/Parser/attributes.mm
new file mode 100644
index 0000000..d92e3d3
--- /dev/null
+++ b/test/Parser/attributes.mm
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -verify -fsyntax-only -Wno-objc-root-class %s
+
+__attribute__((deprecated)) @class B; // expected-error {{prefix attribute must be followed by an interface or protocol}}
+
+__attribute__((deprecated)) @interface A @end
+__attribute__((deprecated)) @protocol P0;
+__attribute__((deprecated)) @protocol P1
+@end
+
+#define EXP __attribute__((visibility("default")))
+class EXP C {};
+EXP class C2 {}; // expected-warning {{attribute 'visibility' is ignored, place it after "class" to apply attribute to type declaration}}
+
+@interface EXP I @end // expected-error {{postfix attributes are not allowed on Objective-C directives, place them in front of '@interface'}}
+EXP @interface I2 @end
+
+@implementation EXP I @end // expected-error-re {{postfix attributes are not allowed on Objective-C directives$}}
+// FIXME: Prefix attribute recovery skips until ';'
+EXP @implementation I2 @end; // expected-error {{prefix attribute must be followed by an interface or protocol}}
+
+@class EXP OC; // expected-error-re {{postfix attributes are not allowed on Objective-C directives$}}
+EXP @class OC2; // expected-error {{prefix attribute must be followed by an interface or protocol}}
+
+@protocol EXP P @end // expected-error {{postfix attributes are not allowed on Objective-C directives, place them in front of '@protocol'}}
+EXP @protocol P2 @end
diff --git a/test/Parser/c11-noreturn.c b/test/Parser/c11-noreturn.c
new file mode 100644
index 0000000..e61901d
--- /dev/null
+++ b/test/Parser/c11-noreturn.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -std=c11 -fsyntax-only -verify %s
+// RUN: not %clang_cc1 -pedantic -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-EXT %s
+
+_Noreturn int f();
+int _Noreturn f(); // expected-note {{previous}}
+int f _Noreturn(); // expected-error {{expected ';'}} expected-error 2{{}}
+int f() _Noreturn; // expected-error {{expected ';'}} expected-warning {{does not declare anything}} expected-error {{'_Noreturn' can only appear on functions}}
+
+_Noreturn char c1; // expected-error {{'_Noreturn' can only appear on functions}}
+char _Noreturn c2; // expected-error {{'_Noreturn' can only appear on functions}}
+
+typedef _Noreturn int g(); // expected-error {{'_Noreturn' can only appear on functions}}
+
+_Noreturn int; // expected-error {{'_Noreturn' can only appear on functions}} expected-warning {{does not declare anything}}
+_Noreturn struct S; // expected-error {{'_Noreturn' can only appear on functions}}
+_Noreturn enum E { e }; // expected-error {{'_Noreturn' can only appear on functions}}
+
+// CHECK-EXT: _Noreturn functions are a C11-specific feature
diff --git a/test/Parser/c1x-alignas.c b/test/Parser/c1x-alignas.c
index 81cd681..5b29df2 100644
--- a/test/Parser/c1x-alignas.c
+++ b/test/Parser/c1x-alignas.c
@@ -5,7 +5,7 @@ _Alignas(4) char c1;
unsigned _Alignas(long) char c2;
char _Alignas(16) c3;
-char c4 _Alignas(32); // expected-error {{expected ';' after top level declarator}}
+char c4 _Alignas(32); // expected-error {{expected ';' after top level declarator}} expected-warning {{declaration does not declare anything}}
char _Alignas(_Alignof(int)) c5;
diff --git a/test/Parser/crash-report.c b/test/Parser/crash-report.c
new file mode 100644
index 0000000..42481aa
--- /dev/null
+++ b/test/Parser/crash-report.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s 2>&1 | FileCheck %s
+// REQUIRES: crash-recovery
+
+#prag\
+ma clang __debug crash
+
+// CHECK: prag\
+// CHECK-NEXT: ma
+
diff --git a/test/Parser/cxx-casting.cpp b/test/Parser/cxx-casting.cpp
index 01980d3..69680e4 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 {{class template test1::A requires template arguments}} expected-error 2{{}}
+ 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 {{class template test1::A requires template arguments}} expected-error 2{{}}
+ 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,7 +85,7 @@ void test3() {
E< ::F>();
// Make sure that parser doesn't expand '[:' to '< ::'
- ::D[:F> A5; // expected-error {{class template ::D requires template arguments}} \
+ ::D[:F> A5; // expected-error {{class template '::D' requires template arguments}} \
// expected-error {{expected expression}} \
// expected-error {{expected unqualified-id}}
}
diff --git a/test/Parser/cxx-class.cpp b/test/Parser/cxx-class.cpp
index 8ed5882..5fac797 100644
--- a/test/Parser/cxx-class.cpp
+++ b/test/Parser/cxx-class.cpp
@@ -88,6 +88,17 @@ namespace ctor_error {
// expected-error{{unknown type name 'UnknownType'}}
}
+namespace nns_decl {
+ struct A {
+ struct B;
+ };
+ namespace N {
+ union C;
+ }
+ struct A::B; // expected-error {{forward declaration of struct cannot have a nested name specifier}}
+ union N::C; // expected-error {{forward declaration of union cannot have a nested name specifier}}
+}
+
// PR13775: Don't assert here.
namespace PR13775 {
class bar
diff --git a/test/Parser/cxx-decl.cpp b/test/Parser/cxx-decl.cpp
index 290b947..41d305b 100644
--- a/test/Parser/cxx-decl.cpp
+++ b/test/Parser/cxx-decl.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -fsyntax-only -triple i386-linux -pedantic %s
+// RUN: %clang_cc1 -verify -fsyntax-only -triple i386-linux -pedantic -fcxx-exceptions -fexceptions %s
const char const *x10; // expected-warning {{duplicate 'const' declaration specifier}}
@@ -124,6 +124,69 @@ void CodeCompleteConsumer::() { // expected-error {{xpected unqualified-id}}
// PR4111
void f(sqrgl); // expected-error {{unknown type name 'sqrgl'}}
+// PR9903
+struct S {
+ typedef void a() { }; // expected-error {{function definition declared 'typedef'}}
+ typedef void c() try { } catch(...) { } // expected-error {{function definition declared 'typedef'}}
+ int n, m;
+ typedef S() : n(1), m(2) { } // expected-error {{function definition declared 'typedef'}}
+};
+
+
+namespace TestIsValidAfterTypeSpecifier {
+struct s {} v;
+
+namespace a {
+struct s operator++(struct s a)
+{ return a; }
+}
+
+namespace b {
+// The newline after s should make no difference.
+struct s
+operator++(struct s a)
+{ return a; }
+}
+
+struct X {
+ struct s
+ friend f();
+ struct s
+ virtual f();
+};
+
+struct s
+&r0 = v;
+struct s
+bitand r2 = v;
+
+}
+
+struct DIE {
+ void foo() {}
+};
+
+void test (DIE die, DIE *Die, DIE INT, DIE *FLOAT) {
+ DIE.foo(); // expected-error {{cannot use dot operator on a type}}
+ die.foo();
+
+ DIE->foo(); // expected-error {{cannot use arrow operator on a type}}
+ Die->foo();
+
+ int.foo(); // expected-error {{cannot use dot operator on a type}}
+ INT.foo();
+
+ float->foo(); // expected-error {{cannot use arrow operator on a type}}
+ FLOAT->foo();
+}
+
+namespace PR15017 {
+ template<typename T = struct X { int i; }> struct S {}; // expected-error {{'PR15017::X' can not be defined in a type specifier}}
+}
+
+// Ensure we produce at least some diagnostic for attributes in C++98.
+[[]] struct S; // expected-error 2{{}}
+
// PR8380
extern "" // expected-error {{unknown linkage language}}
test6a { ;// expected-error {{C++ requires a type specifier for all declarations}} \
diff --git a/test/Parser/cxx-undeclared-identifier.cpp b/test/Parser/cxx-undeclared-identifier.cpp
index 6ea2965..a3f9e02 100644
--- a/test/Parser/cxx-undeclared-identifier.cpp
+++ b/test/Parser/cxx-undeclared-identifier.cpp
@@ -16,6 +16,4 @@ namespace ImplicitInt {
int f(a::b::c); // expected-error {{use of undeclared identifier 'a'}}
class Foo::Bar { // expected-error {{use of undeclared identifier 'Foo'}} \
- // expected-note {{to match this '{'}} \
// expected-error {{expected ';' after class}}
- // expected-error {{expected '}'}}
diff --git a/test/Parser/cxx0x-ambig.cpp b/test/Parser/cxx0x-ambig.cpp
index 96e2006..3b864f9 100644
--- a/test/Parser/cxx0x-ambig.cpp
+++ b/test/Parser/cxx0x-ambig.cpp
@@ -25,6 +25,9 @@ namespace final {
struct T final : S {}; // expected-error {{base 'S' is marked 'final'}}
struct T bar : S {}; // expected-error {{expected ';' after top level declarator}} expected-error {{expected unqualified-id}}
}
+ // _Alignas isn't allowed in the places where alignas is. We used to
+ // assert on this.
+ struct U final _Alignas(4) {}; // expected-error 3{{}} expected-note {{}}
}
// enum versus bitfield mess.
@@ -110,7 +113,7 @@ namespace ellipsis {
void f(S(...args[sizeof(T)])); // expected-note {{here}}
void f(S(...args)[sizeof(T)]); // expected-error {{redeclared}} expected-note {{here}}
void f(S ...args[sizeof(T)]); // expected-error {{redeclared}}
- void g(S(...[sizeof(T)])); // expected-note {{here}}
+ void g(S(...[sizeof(T)])); // expected-note {{here}} expected-warning {{ISO C++11 requires a parenthesized pack declaration to have a name}}
void g(S(...)[sizeof(T)]); // expected-error {{function cannot return array type}}
void g(S ...[sizeof(T)]); // expected-error {{redeclared}}
void h(T(...)); // function type, expected-error {{unexpanded parameter pack}}
@@ -125,5 +128,24 @@ namespace ellipsis {
void j(T(T...)); // expected-error {{unexpanded parameter pack}}
void k(int(...)(T)); // expected-error {{cannot return function type}}
void k(int ...(T));
+ void l(int(&...)(T)); // expected-warning {{ISO C++11 requires a parenthesized pack declaration to have a name}}
+ void l(int(*...)(T)); // expected-warning {{ISO C++11 requires a parenthesized pack declaration to have a name}}
+ void l(int(S<int>::*...)(T)); // expected-warning {{ISO C++11 requires a parenthesized pack declaration to have a name}}
};
}
+
+namespace braced_init_list {
+ struct X {
+ void foo() {}
+ };
+
+ void (*pf1)() {};
+ void (X::*pmf1)() {&X::foo};
+ void (X::*pmf2)() = {&X::foo};
+
+ void test() {
+ void (*pf2)() {};
+ void (X::*pmf3)() {&X::foo};
+ void (X::*pmf4)() = {&X::foo};
+ }
+}
diff --git a/test/Parser/cxx0x-attributes.cpp b/test/Parser/cxx0x-attributes.cpp
index 58e42bf..5e4e388 100644
--- a/test/Parser/cxx0x-attributes.cpp
+++ b/test/Parser/cxx0x-attributes.cpp
@@ -41,6 +41,8 @@ const [[]] int between_attr_2 = 0; // expected-error {{an attribute list cannot
int after_attr [[]];
int * [[]] ptr_attr;
int & [[]] ref_attr = after_attr;
+int & [[unknown]] ref_attr_2 = after_attr; // expected-warning {{unknown attribute 'unknown' ignored}}
+int & [[noreturn]] ref_attr_3 = after_attr; // expected-error {{'noreturn' attribute cannot be applied to types}}
int && [[]] rref_attr = 0;
int array_attr [1] [[]];
alignas(8) int aligned_attr;
@@ -62,8 +64,35 @@ struct MemberFnOrder {
struct [[]] struct_attr;
class [[]] class_attr {};
union [[]] union_attr;
+
+// Checks attributes placed at wrong syntactic locations of class specifiers.
+class [[]] [[]]
+ attr_after_class_name_decl [[]] [[]]; // expected-error {{an attribute list cannot appear here}}
+
+class [[]] [[]]
+ attr_after_class_name_definition [[]] [[]] [[]]{}; // expected-error {{an attribute list cannot appear here}}
+
+class [[]] c {};
+class c [[]] [[]] x;
+class c [[]] [[]] y [[]] [[]];
+class c final [(int){0}];
+
+class base {};
+class [[]] [[]] final_class
+ alignas(float) [[]] final // expected-error {{an attribute list cannot appear here}}
+ alignas(float) [[]] [[]] alignas(float): base{}; // expected-error {{an attribute list cannot appear here}}
+
+class [[]] [[]] final_class_another
+ [[]] [[]] alignas(16) final // expected-error {{an attribute list cannot appear here}}
+ [[]] [[]] alignas(16) [[]]{}; // expected-error {{an attribute list cannot appear here}}
+
[[]] struct with_init_declarators {} init_declarator;
[[]] struct no_init_declarators; // expected-error {{an attribute list cannot appear here}}
+template<typename> [[]] struct no_init_declarators_template; // expected-error {{an attribute list cannot appear here}}
+void fn_with_structs() {
+ [[]] struct with_init_declarators {} init_declarator;
+ [[]] struct no_init_declarators; // expected-error {{an attribute list cannot appear here}}
+}
[[]];
struct ctordtor {
[[]] ctordtor();
@@ -90,13 +119,18 @@ extern "C++" [[]] { } // expected-error {{an attribute list cannot appear here}}
[[]] asm(""); // expected-error {{an attribute list cannot appear here}}
[[]] using ns::i; // expected-error {{an attribute list cannot appear here}}
-[[]] using namespace ns;
+[[unknown]] using namespace ns; // expected-warning {{unknown attribute 'unknown' ignored}}
+[[noreturn]] using namespace ns; // expected-error {{'noreturn' attribute only applies to functions and methods}}
[[]] using T = int; // expected-error {{an attribute list cannot appear here}}
using T [[]] = int; // ok
template<typename T> using U [[]] = T;
using ns::i [[]]; // expected-error {{an attribute list cannot appear here}}
using [[]] ns::i; // expected-error {{an attribute list cannot appear here}}
+using T [[unknown]] = int; // expected-warning {{unknown attribute 'unknown' ignored}}
+using T [[noreturn]] = int; // expected-error {{'noreturn' attribute only applies to functions and methods}}
+using V = int; // expected-note {{previous}}
+using V [[gnu::vector_size(16)]] = int; // expected-error {{redefinition with different types}}
auto trailing() -> [[]] const int; // expected-error {{an attribute list cannot appear here}}
auto trailing() -> const [[]] int; // expected-error {{an attribute list cannot appear here}}
@@ -128,10 +162,16 @@ enum struct [[]] E5;
struct S {
friend int f [[]] (); // expected-FIXME{{an attribute list cannot appear here}}
- [[]] friend int g(); // expected-FIXME{{an attribute list cannot appear here}}
+ friend int f1 [[noreturn]] (); //expected-error{{an attribute list cannot appear here}}
+ friend int f2 [[]] [[noreturn]] () {}
+ [[]] friend int g(); // expected-error{{an attribute list cannot appear here}}
[[]] friend int h() {
}
+ [[]] friend int f3(), f4(), f5(); // expected-error{{an attribute list cannot appear here}}
+ friend int f6 [[noreturn]] (), f7 [[noreturn]] (), f8 [[noreturn]] (); // expected-error3 {{an attribute list cannot appear here}}
friend class [[]] C; // expected-error{{an attribute list cannot appear here}}
+ [[]] friend class D; // expected-error{{an attribute list cannot appear here}}
+ [[]] friend int; // expected-error{{an attribute list cannot appear here}}
};
template<typename T> void tmpl(T) {}
template void tmpl [[]] (int); // expected-FIXME {{an attribute list cannot appear here}}
@@ -182,17 +222,20 @@ template<typename...Ts> void variadic() {
// Expression tests
void bar () {
- [] () [[noreturn]] { return; } (); // expected-error {{should not return}}
- [] () [[noreturn]] { throw; } ();
+ // FIXME: GCC accepts [[gnu::noreturn]] on a lambda, even though it appertains
+ // to the operator()'s type, and GCC does not otherwise accept attributes
+ // applied to types. Use that to test this.
+ [] () [[gnu::noreturn]] { return; } (); // expected-warning {{attribute 'noreturn' ignored}} FIXME-error {{should not return}}
+ [] () [[gnu::noreturn]] { throw; } (); // expected-warning {{attribute 'noreturn' ignored}}
new int[42][[]][5][[]]{};
}
// Condition tests
void baz () {
- if ([[]] bool b = true) {
- switch ([[]] int n { 42 }) {
+ if ([[unknown]] bool b = true) { // expected-warning {{unknown attribute 'unknown' ignored}}
+ switch ([[unknown]] int n { 42 }) { // expected-warning {{unknown attribute 'unknown' ignored}}
default:
- for ([[]] int n = 0; [[]] char b = n < 5; ++b) {
+ for ([[unknown]] int n = 0; [[unknown]] char b = n < 5; ++b) { // expected-warning 2{{unknown attribute 'unknown' ignored}}
}
}
}
@@ -209,7 +252,7 @@ void baz () {
do {
} while ([[]] false); // expected-error {{an attribute list cannot appear here}}
- for ([[]] int n : { 1, 2, 3 }) {
+ for ([[unknown]] int n : { 1, 2, 3 }) { // expected-warning {{unknown attribute 'unknown' ignored}}
}
}
@@ -219,14 +262,22 @@ enum class __attribute__((visibility("hidden"))) SecretKeepers {
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}}
+ void f[[gnu::format(printf, 1, 2)]](const char*, ...);
+ void g() [[unknown::foo(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}} \
+// Forbid attributes on decl specifiers.
+unsigned [[gnu::used]] static int [[gnu::unused]] v1; // expected-error {{'unused' attribute cannot be applied to types}} \
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}} \
+typedef [[gnu::used]] unsigned long [[gnu::unused]] v2; // expected-error {{'unused' attribute cannot be applied to types}} \
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}}
+int [[carries_dependency]] foo(int [[carries_dependency]] x); // expected-error 2{{'carries_dependency' attribute cannot be applied to types}}
+
+// Forbid [[gnu::...]] attributes on declarator chunks.
+int *[[gnu::unused]] v3; // expected-warning {{attribute 'unused' ignored}}
+int v4[2][[gnu::unused]]; // expected-warning {{attribute 'unused' ignored}}
+int v5()[[gnu::unused]]; // expected-warning {{attribute 'unused' ignored}}
+
+[[attribute_declaration]]; // expected-warning {{unknown attribute 'attribute_declaration' ignored}}
+[[noreturn]]; // expected-error {{'noreturn' attribute only applies to functions and methods}}
+[[carries_dependency]]; // expected-error {{'carries_dependency' attribute only applies to functions, methods, and parameters}}
diff --git a/test/Parser/cxx0x-decl.cpp b/test/Parser/cxx0x-decl.cpp
index 3af73f9..b9441fd 100644
--- a/test/Parser/cxx0x-decl.cpp
+++ b/test/Parser/cxx0x-decl.cpp
@@ -34,3 +34,43 @@ struct MultiCV {
};
static_assert(something, ""); // expected-error {{undeclared identifier}}
+
+// PR9903
+struct SS {
+ typedef void d() = default; // expected-error {{function definition declared 'typedef'}} expected-error {{only special member functions may be defaulted}}
+};
+
+using PR14855 = int S::; // expected-error {{expected ';' after alias declaration}}
+
+// Ensure that 'this' has a const-qualified type in a trailing return type for
+// a constexpr function.
+struct ConstexprTrailingReturn {
+ int n;
+ constexpr auto f() -> decltype((n));
+};
+constexpr const int &ConstexprTrailingReturn::f() const { return n; }
+
+namespace TestIsValidAfterTypeSpecifier {
+struct s {} v;
+
+// FIXME: We should accept this once we support thread_local.
+struct s
+thread_local tl; // expected-error {{expected unqualified-id}}
+
+struct s
+&r0 = v;
+
+struct s
+&&r1 = s();
+
+struct s
+bitand r2 = v;
+
+struct s
+and r3 = s();
+
+enum E {};
+enum E
+[[]] e;
+
+}
diff --git a/test/Parser/cxx11-base-spec-attributes.cpp b/test/Parser/cxx11-base-spec-attributes.cpp
new file mode 100644
index 0000000..7338c51
--- /dev/null
+++ b/test/Parser/cxx11-base-spec-attributes.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -std=c++11 %s -verify
+
+struct A {};
+struct B : [[]] A {};
+struct C : [[]] virtual A {};
+struct D : [[]] public virtual A {};
+struct E : public [[]] virtual A {}; // expected-error {{an attribute list cannot appear here}}
+struct F : virtual [[]] public A {}; // expected-error {{an attribute list cannot appear here}}
+struct G : [[noreturn]] A {}; // expected-error {{'noreturn' attribute cannot be applied to a base specifier}}
+struct H : [[unknown::foobar]] A {}; // expected-warning {{unknown attribute 'foobar' ignored}}
diff --git a/test/Parser/cxx11-brace-initializers.cpp b/test/Parser/cxx11-brace-initializers.cpp
index a210205..7926320 100644
--- a/test/Parser/cxx11-brace-initializers.cpp
+++ b/test/Parser/cxx11-brace-initializers.cpp
@@ -14,3 +14,14 @@ void test1()
f(0, {1, 1}, 0);
}
+
+namespace PR14948 {
+ template<typename T> struct Q { static T x; };
+
+ struct X {};
+ template<> X Q<X>::x {};
+ template<> int Q<int[]>::x[] { 1, 2, 3 };
+ template<> int Q<int>::x { 1 };
+
+ template<typename T> T Q<T>::x {};
+}
diff --git a/test/Parser/cxx11-stmt-attributes.cpp b/test/Parser/cxx11-stmt-attributes.cpp
index f26db79..2f727a2 100644
--- a/test/Parser/cxx11-stmt-attributes.cpp
+++ b/test/Parser/cxx11-stmt-attributes.cpp
@@ -27,11 +27,11 @@ void foo(int i) {
[[unknown_attribute]] return; // expected-warning {{unknown attribute 'unknown_attribute' ignored}}
- alignas(8) ; // expected-warning {{attribute aligned cannot be specified on a statement}}
- [[noreturn]] { } // expected-warning {{attribute noreturn cannot be specified on a statement}}
- [[noreturn]] if (0) { } // expected-warning {{attribute noreturn cannot be specified on a statement}}
- [[noreturn]] for (;;); // expected-warning {{attribute noreturn cannot be specified on a statement}}
- [[noreturn]] do { // expected-warning {{attribute noreturn cannot be specified on a statement}}
+ alignas(8) ; // expected-error {{'alignas' attribute cannot be applied to a statement}}
+ [[noreturn]] { } // expected-error {{'noreturn' attribute cannot be applied to a statement}}
+ [[noreturn]] if (0) { } // expected-error {{'noreturn' attribute cannot be applied to a statement}}
+ [[noreturn]] for (;;); // expected-error {{'noreturn' attribute cannot be applied to a statement}}
+ [[noreturn]] do { // expected-error {{'noreturn' attribute cannot be applied to a statement}}
[[unavailable]] continue; // expected-warning {{unknown attribute 'unavailable' ignored}}
} while (0);
[[unknown_attributqqq]] while (0); // expected-warning {{unknown attribute 'unknown_attributqqq' ignored}}
@@ -42,7 +42,7 @@ void foo(int i) {
[[unused]] switch (i) { // expected-warning {{unknown attribute 'unused' ignored}}
[[uuid]] case 0: // expected-warning {{unknown attribute 'uuid' ignored}}
[[visibility]] default: // expected-warning {{unknown attribute 'visibility' ignored}}
- [[carries_dependency]] break; // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
+ [[carries_dependency]] break; // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
}
[[fastcall]] goto there; // expected-warning {{unknown attribute 'fastcall' ignored}}
@@ -54,26 +54,26 @@ void foo(int i) {
[[weakref]] return; // expected-warning {{unknown attribute 'weakref' ignored}}
- [[carries_dependency]] ; // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
- [[carries_dependency]] { } // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
- [[carries_dependency]] if (0) { } // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
- [[carries_dependency]] for (;;); // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
- [[carries_dependency]] do { // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
- [[carries_dependency]] continue; // expected-warning {{attribute carries_dependency cannot be specified on a statement}} ignored}}
+ [[carries_dependency]] ; // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
+ [[carries_dependency]] { } // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
+ [[carries_dependency]] if (0) { } // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
+ [[carries_dependency]] for (;;); // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
+ [[carries_dependency]] do { // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
+ [[carries_dependency]] continue; // expected-error {{'carries_dependency' attribute cannot be applied to a statement}} ignored}}
} while (0);
- [[carries_dependency]] while (0); // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
+ [[carries_dependency]] while (0); // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
- [[carries_dependency]] switch (i) { // expected-warning {{attribute carries_dependency cannot be specified on a statement}} ignored}}
- [[carries_dependency]] case 0: // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
- [[carries_dependency]] default: // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
- [[carries_dependency]] break; // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
+ [[carries_dependency]] switch (i) { // expected-error {{'carries_dependency' attribute cannot be applied to a statement}} ignored}}
+ [[carries_dependency]] case 0: // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
+ [[carries_dependency]] default: // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
+ [[carries_dependency]] break; // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
}
- [[carries_dependency]] goto here; // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
+ [[carries_dependency]] goto here; // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
- [[carries_dependency]] try { // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
+ [[carries_dependency]] try { // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
} catch (...) {
}
- [[carries_dependency]] return; // expected-warning {{attribute carries_dependency cannot be specified on a statement}}
+ [[carries_dependency]] return; // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
}
diff --git a/test/Parser/missing-closing-rbrace.m b/test/Parser/missing-closing-rbrace.m
new file mode 100644
index 0000000..d811421
--- /dev/null
+++ b/test/Parser/missing-closing-rbrace.m
@@ -0,0 +1,3 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// rdar: //6854840
+@interface A {@end // expected-error {{'@end' appears where closing brace '}' is expected}}
diff --git a/test/Parser/ms-inline-asm.c b/test/Parser/ms-inline-asm.c
index 0e8b317..dff19b4 100644
--- a/test/Parser/ms-inline-asm.c
+++ b/test/Parser/ms-inline-asm.c
@@ -1,38 +1,39 @@
-// RUN: %clang_cc1 %s -verify -fms-extensions
+// REQUIRES: disabled
+// RUN: %clang_cc1 %s -triple i386-apple-darwin10 -verify -fasm-blocks
#define M __asm int 0x2c
#define M2 int
-void t1(void) { M } // expected-warning {{MS-style inline assembly is not supported}}
-void t2(void) { __asm int 0x2c } // expected-warning {{MS-style inline assembly is not supported}}
-void t3(void) { __asm M2 0x2c } // expected-warning {{MS-style inline assembly is not supported}}
-void t4(void) { __asm mov eax, fs:[0x10] } // expected-warning {{MS-style inline assembly is not supported}}
+void t1(void) { M }
+void t2(void) { __asm int 0x2c }
+void t3(void) { __asm M2 0x2c }
+void t4(void) { __asm mov eax, fs:[0x10] }
void t5() {
- __asm { // expected-warning {{MS-style inline assembly is not supported}}
+ __asm {
int 0x2c ; } asm comments are fun! }{
}
- __asm {} // expected-warning {{MS-style inline assembly is not supported}}
+ __asm {}
}
int t6() {
- __asm int 3 ; } comments for single-line asm // expected-warning {{MS-style inline assembly is not supported}}
- __asm {} // expected-warning {{MS-style inline assembly is not supported}}
+ __asm int 3 ; } comments for single-line asm
+ __asm {}
- __asm int 4 // expected-warning {{MS-style inline assembly is not supported}}
+ __asm int 4
return 10;
}
void t7() {
- __asm { // expected-warning {{MS-style inline assembly is not supported}}
+ __asm {
push ebx
mov ebx, 0x07
pop ebx
}
}
void t8() {
- __asm nop __asm nop __asm nop // expected-warning {{MS-style inline assembly is not supported}}
+ __asm nop __asm nop __asm nop
}
void t9() {
- __asm nop __asm nop ; __asm nop // expected-warning {{MS-style inline assembly is not supported}}
+ __asm nop __asm nop ; __asm nop
}
int t_fail() { // expected-note {{to match this}}
- __asm // expected-warning {{MS-style inline assembly is not supported}}
- __asm { // expected-warning {{MS-style inline assembly is not supported}} expected-error 3 {{expected}} expected-note {{to match this}}
+ __asm
+ __asm { // expected-error 3 {{expected}} expected-note {{to match this}}
diff --git a/test/Parser/objcxx0x-lambda-expressions.mm b/test/Parser/objcxx0x-lambda-expressions.mm
index 1eab15b..fb90b16 100644
--- a/test/Parser/objcxx0x-lambda-expressions.mm
+++ b/test/Parser/objcxx0x-lambda-expressions.mm
@@ -10,7 +10,7 @@ class C {
[]; // expected-error {{expected body of lambda expression}}
[=,foo+] {}; // expected-error {{expected ',' or ']' in lambda capture list}}
- [&this] {}; // expected-error {{address expression must be an lvalue}}
+ [&this] {}; // expected-error {{cannot take the address of an rvalue of type 'C *'}}
[] {};
[=] (int i) {};
[&] (int) mutable -> void {};
diff --git a/test/Parser/objcxx11-attributes.mm b/test/Parser/objcxx11-attributes.mm
index ad54208..c1d8c41 100644
--- a/test/Parser/objcxx11-attributes.mm
+++ b/test/Parser/objcxx11-attributes.mm
@@ -13,12 +13,12 @@ void f(X *noreturn) {
int a[ [noreturn getSize] ];
// ... but is interpreted as an attribute where possible.
- int b[ [noreturn] ]; // expected-warning {{'noreturn' only applies to function types}}
+ int b[ [noreturn] ]; // expected-error {{'noreturn' attribute only applies to functions and methods}}
int c[ [noreturn getSize] + 1 ];
// An array size which is computed by a lambda is not OK.
- int d[ [noreturn] { return 3; } () ]; // expected-error {{expected ']'}} expected-warning {{'noreturn' only applies}}
+ int d[ [noreturn] { return 3; } () ]; // expected-error {{expected ']'}} expected-error {{'noreturn' attribute only applies}}
// A message send which contains a message send is OK.
[ [ X alloc ] init ];
@@ -32,19 +32,19 @@ void f(X *noreturn) {
// An attribute is OK.
[[]];
[[int(), noreturn]]; // expected-warning {{unknown attribute 'int' ignored}} \
- // expected-warning {{attribute noreturn cannot be specified on a statement}}
+ // expected-error {{'noreturn' attribute cannot be applied to a statement}}
[[class, test(foo 'x' bar),,,]]; // expected-warning {{unknown attribute 'test' ignored}}\
// expected-warning {{unknown attribute 'class' ignored}}
- [[bitand, noreturn]]; // expected-warning {{attribute noreturn cannot be specified on a statement}} \
+ [[bitand, noreturn]]; // expected-error {{'noreturn' attribute cannot be applied to a statement}} \
expected-warning {{unknown attribute 'bitand' ignored}}
// FIXME: Suppress vexing parse warning
- [[noreturn]]int(e)(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
+ [[gnu::noreturn]]int(e)(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}}
int e2(); // expected-warning {{interpreted as a function declaration}} expected-note{{}}
// A function taking a noreturn function.
- int(f)([[noreturn]] int()); // expected-note {{here}}
+ int(f)([[gnu::noreturn]] int ()); // expected-note {{here}}
f(e);
f(e2); // expected-error {{cannot initialize a parameter of type 'int (*)() __attribute__((noreturn))' with an lvalue of type 'int ()'}}
diff --git a/test/Parser/objcxx11-protocol-in-template.mm b/test/Parser/objcxx11-protocol-in-template.mm
new file mode 100644
index 0000000..8cb4993
--- /dev/null
+++ b/test/Parser/objcxx11-protocol-in-template.mm
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+template<class T> class vector {};
+@protocol P @end
+
+#if __cplusplus >= 201103L
+ // expected-no-diagnostics
+#else
+ // expected-error@14{{a space is required between consecutive right angle brackets}}
+ // expected-error@15{{a space is required between consecutive right angle brackets}}
+#endif
+
+vector<id<P>> v;
+vector<vector<id<P>>> v2;
diff --git a/test/Parser/opencl-image-access.cl b/test/Parser/opencl-image-access.cl
index 313587c..e08d129 100644
--- a/test/Parser/opencl-image-access.cl
+++ b/test/Parser/opencl-image-access.cl
@@ -1,7 +1,5 @@
// RUN: %clang_cc1 %s -fsyntax-only
-typedef void* image2d_t;
-
__kernel void f__ro(__read_only image2d_t a) { }
__kernel void f__wo(__write_only image2d_t a) { }
diff --git a/test/Parser/parser_overflow.c b/test/Parser/parser_overflow.c
index d2006ea..7a3d651 100644
--- a/test/Parser/parser_overflow.c
+++ b/test/Parser/parser_overflow.c
@@ -1,7 +1,19 @@
+// RUN: %clang_cc1 %s -fsyntax-only -DHUGE 2>&1 | FileCheck %s
// RUN: %clang_cc1 %s -fsyntax-only 2>&1 | FileCheck %s
+// RUN: %clang_cc1 %s -fsyntax-only -fbracket-depth 299 2>&1 | FileCheck %s
+// RUN: %clang_cc1 %s -fsyntax-only -fbracket-depth 300
+// RUN: %clang %s -fsyntax-only -fbracket-depth=299 2>&1 | FileCheck %s
+// RUN: %clang %s -fsyntax-only -fbracket-depth=300
void foo(void) {
+#ifdef HUGE
+ // 16384 {, 16384 }
{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
+#else
+// 299 {, 299 }
+{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
+#endif
}
-// CHECK: fatal error: parser recursion limit reached, program too complex
+// CHECK: fatal error: bracket nesting level exceeded maximum of {{256|299}}
+// CHECK: note: use -fbracket-depth=N to increase maximum nesting level
diff --git a/test/Parser/placeholder-recovery.m b/test/Parser/placeholder-recovery.m
index 1fc1549..3fe1d62 100644
--- a/test/Parser/placeholder-recovery.m
+++ b/test/Parser/placeholder-recovery.m
@@ -5,7 +5,7 @@
// bogus 'archaic' warnings with bad location info.
@protocol <#protocol name#> <NSObject> // expected-error 2{{expected identifier}} \
// expected-error{{cannot find protocol declaration for 'NSObject'}} \
-// expected-warning{{protocol qualifiers without 'id'}}
+// expected-warning{{protocol has no object type specified; defaults to qualified 'id'}}
<#methods#> // expected-error{{expected identifier}}
diff --git a/test/Parser/prefix-attributes.m b/test/Parser/prefix-attributes.m
deleted file mode 100644
index 399421f..0000000
--- a/test/Parser/prefix-attributes.m
+++ /dev/null
@@ -1,8 +0,0 @@
-// RUN: %clang_cc1 -verify -fsyntax-only %s
-
-__attribute__((deprecated)) @class B; // expected-error {{prefix attribute must be followed by an interface or protocol}}
-
-__attribute__((deprecated)) @interface A @end
-__attribute__((deprecated)) @protocol P0;
-__attribute__((deprecated)) @protocol P1
-@end
diff --git a/test/Parser/recovery.cpp b/test/Parser/recovery.cpp
index 732b9ae..41845fb 100644
--- a/test/Parser/recovery.cpp
+++ b/test/Parser/recovery.cpp
@@ -43,3 +43,10 @@ strcut Uuuu { // expected-error {{did you mean the keyword 'struct'}} \
// expected-note {{'Uuuu' declared here}}
} *u[3];
uuuu v; // expected-error {{did you mean 'Uuuu'}}
+
+struct Redefined { // expected-note {{previous}}
+ Redefined() {}
+};
+struct Redefined { // expected-error {{redefinition}}
+ Redefined() {}
+};
diff --git a/test/Parser/warn-semicolon-before-method-body.m b/test/Parser/warn-semicolon-before-method-body.m
new file mode 100644
index 0000000..be408eb
--- /dev/null
+++ b/test/Parser/warn-semicolon-before-method-body.m
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -fsyntax-only -Wsemicolon-before-method-body -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wsemicolon-before-method-body -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+
+// Allow optional semicolon in objc method definiton after method prototype,
+// warn about it and suggest a fixit.
+
+@interface NSObject
+@end
+
+@interface C : NSObject
+- (int)z;
+@end
+
+@implementation C
+- (int)z; // expected-warning {{semicolon before method body is ignored}}
+{
+ return 0;
+}
+@end
+
+// CHECK: fix-it:"{{.*}}":{15:9-15:10}:""
+
diff --git a/test/Preprocessor/_Pragma-dependency.c b/test/Preprocessor/_Pragma-dependency.c
index a2861c9..4534cc2 100644
--- a/test/Preprocessor/_Pragma-dependency.c
+++ b/test/Preprocessor/_Pragma-dependency.c
@@ -1,7 +1,6 @@
-// RUN: %clang_cc1 %s -E 2>&1 | grep 'DO_PRAGMA (STR'
-// RUN: %clang_cc1 %s -E 2>&1 | grep '7:3'
+// RUN: %clang_cc1 -E -verify %s
#define DO_PRAGMA _Pragma
#define STR "GCC dependency \"parse.y\"")
- // Test that this line is printed by caret diagnostics.
+// expected-error@+1 {{'parse.y' file not found}}
DO_PRAGMA (STR
diff --git a/test/Preprocessor/_Pragma-physloc.c b/test/Preprocessor/_Pragma-physloc.c
index a093af2..6d1dcdb 100644
--- a/test/Preprocessor/_Pragma-physloc.c
+++ b/test/Preprocessor/_Pragma-physloc.c
@@ -1,5 +1,6 @@
-// RUN: %clang_cc1 %s -E | grep '#pragma x y z'
-// RUN: %clang_cc1 %s -E | grep '#pragma a b c'
+// RUN: %clang_cc1 -E %s | FileCheck --strict-whitespace %s
+// CHECK: {{^}}#pragma x y z{{$}}
+// CHECK: {{^}}#pragma a b c{{$}}
_Pragma("x y z")
_Pragma("a b c")
diff --git a/test/Preprocessor/aarch64-target-features.c b/test/Preprocessor/aarch64-target-features.c
new file mode 100644
index 0000000..65104e3
--- /dev/null
+++ b/test/Preprocessor/aarch64-target-features.c
@@ -0,0 +1,30 @@
+// RUN: %clang -target aarch64-none-linux-gnu -x c -E -dM %s -o - | FileCheck %s
+// CHECK: __AARCH 8
+// CHECK: __AARCH64EL__
+// CHECK: __AARCH_ACLE 101
+// CHECK-NOT: __AARCH_ADVSIMD_FP
+// CHECK-NOT: __AARCH_FEATURE_ADVSIMD
+// CHECK-NOT: __AARCH_FEATURE_BIG_ENDIAN
+// CHECK: __AARCH_FEATURE_CLZ 1
+// CHECK: __AARCH_FEATURE_FMA 1
+// CHECK: __AARCH_FEATURE_LDREX 0xf
+// CHECK: __AARCH_FEATURE_UNALIGNED 1
+// CHECK: __AARCH_FP 0xe
+// CHECK-NOT: __AARCH_FP_FAST
+// CHECK: __AARCH_FP16_FORMAT_IEEE 1
+// CHECK: __AARCH_FP_FENV_ROUNDING 1
+// CHECK: __AARCH_PROFILE 'A'
+// CHECK: __AARCH_SIZEOF_MINIMAL_ENUM 4
+// CHECK: __AARCH_SIZEOF_WCHAR_T 4
+// CHECK: __aarch64__
+
+
+// RUN: %clang -target aarch64-none-linux-gnu -ffast-math -x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-FASTMATH %s
+// CHECK-FASTMATH: __AARCH_FP_FAST
+
+// RUN: %clang -target aarch64-none-linux-gnu -fshort-wchar -x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-SHORTWCHAR %s
+// CHECK-SHORTWCHAR: __AARCH_SIZEOF_WCHAR_T 2
+
+// RUN: %clang -target aarch64-none-linux-gnu -fshort-enums -x c -E -dM %s -o - | FileCheck --check-prefix=CHECK-SHORTENUMS %s
+// CHECK-SHORTENUMS: __AARCH_SIZEOF_MINIMAL_ENUM 1
+
diff --git a/test/Preprocessor/builtin_line.c b/test/Preprocessor/builtin_line.c
index 52228b5..db5a103 100644
--- a/test/Preprocessor/builtin_line.c
+++ b/test/Preprocessor/builtin_line.c
@@ -1,13 +1,15 @@
-// RUN: %clang_cc1 %s -E | grep "^ 4"
+// RUN: %clang_cc1 -E %s | FileCheck --strict-whitespace %s
#define FOO __LINE__
FOO
+// CHECK: {{^}} 4{{$}}
// PR3579 - This should expand to the __LINE__ of the ')' not of the X.
-// RUN: %clang_cc1 %s -E | grep "^A 13"
#define X() __LINE__
A X(
)
+// CHECK: {{^}}A 13{{$}}
+
diff --git a/test/Preprocessor/c90.c b/test/Preprocessor/c90.c
index 1d5010d..3b9105f 100644
--- a/test/Preprocessor/c90.c
+++ b/test/Preprocessor/c90.c
@@ -1,4 +1,5 @@
/* RUN: %clang_cc1 %s -std=c89 -Eonly -verify -pedantic-errors
+ * RUN: %clang_cc1 %s -std=c89 -E | FileCheck %s
*/
/* PR3919 */
@@ -8,3 +9,7 @@
#define foo3$bar /* expected-error {{'$' in identifier}} */
+/* CHECK-NOT: this comment should be missing
+ * CHECK: {{^}}// this comment should be present{{$}}
+ */
+// this comment should be present
diff --git a/test/Preprocessor/disabled-cond-diags.c b/test/Preprocessor/disabled-cond-diags.c
index 531842a..0237b5d 100644
--- a/test/Preprocessor/disabled-cond-diags.c
+++ b/test/Preprocessor/disabled-cond-diags.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -E %s 2>&1 | not grep "warning\|error"
+// RUN: %clang_cc1 -E -verify %s
+// expected-no-diagnostics
#if 0
diff --git a/test/Preprocessor/feature_tests.c b/test/Preprocessor/feature_tests.c
index b78a251..19d8046 100644
--- a/test/Preprocessor/feature_tests.c
+++ b/test/Preprocessor/feature_tests.c
@@ -32,3 +32,23 @@
__has_builtin(__builtin_altivec_abs_v4sf)
#error Broken handling of target-specific builtins
#endif
+
+// Macro expansion does not occur in the parameter to __has_builtin,
+// __has_feature, etc. (as is also expected behaviour for ordinary
+// macros), so the following should not expand:
+
+#define MY_ALIAS_BUILTIN __c11_atomic_init
+#define MY_ALIAS_FEATURE attribute_overloadable
+
+#if __has_builtin(MY_ALIAS_BUILTIN) || __has_feature(MY_ALIAS_FEATURE)
+#error Alias expansion not allowed
+#endif
+
+// But deferring should expand:
+
+#define HAS_BUILTIN(X) __has_builtin(X)
+#define HAS_FEATURE(X) __has_feature(X)
+
+#if !HAS_BUILTIN(MY_ALIAS_BUILTIN) || !HAS_FEATURE(MY_ALIAS_FEATURE)
+#error Expansion should have occurred
+#endif
diff --git a/test/Preprocessor/first-line-indent.c b/test/Preprocessor/first-line-indent.c
new file mode 100644
index 0000000..d220d57
--- /dev/null
+++ b/test/Preprocessor/first-line-indent.c
@@ -0,0 +1,7 @@
+ foo
+// RUN: %clang_cc1 -E %s | FileCheck -strict-whitespace %s
+ bar
+
+// CHECK: {{^ }}foo
+// CHECK: {{^ }}bar
+
diff --git a/test/Preprocessor/has_include.c b/test/Preprocessor/has_include.c
index 10f7795..131e519 100644
--- a/test/Preprocessor/has_include.c
+++ b/test/Preprocessor/has_include.c
@@ -64,6 +64,55 @@
#error "defined(__has_include_next) failed (8)."
#endif
+// Fun with macros
+#define MACRO1 __has_include(<stdint.h>)
+#define MACRO2 ("stdint.h")
+#define MACRO3 ("blahblah.h")
+#define MACRO4 blahblah.h>)
+#define MACRO5 <stdint.h>
+
+#if !MACRO1
+ #error "__has_include with macro failed (1)."
+#endif
+
+#if !__has_include MACRO2
+ #error "__has_include with macro failed (2)."
+#endif
+
+#if __has_include MACRO3
+ #error "__has_include with macro failed (3)."
+#endif
+
+#if __has_include(<MACRO4
+ #error "__has_include with macro failed (4)."
+#endif
+
+#if !__has_include(MACRO5)
+ #error "__has_include with macro failed (2)."
+#endif
+
+// Try as non-preprocessor directives
+void foo( void ) {
+ __has_include_next("stdint.h") // expected-warning {{#include_next in primary source file}} expected-error {{__has_include_next must be used within a preprocessing directive}}
+ __has_include("stdint.h") // expected-error {{__has_include must be used within a preprocessing directive}}
+}
+
+MACRO1 // expected-error {{__has_include must be used within a preprocessing directive}}
+
+#if 1
+MACRO1 // expected-error {{__has_include must be used within a preprocessing directive}}
+#endif
+
+#if 0
+#elif 1
+MACRO1 // expected-error {{__has_include must be used within a preprocessing directive}}
+#endif
+
+#if 0
+MACRO1 // This should be fine because it is never actually reached
+#endif
+
+
// Try badly formed expressions.
// FIXME: We can recover better in almost all of these cases. (PR13335)
@@ -99,7 +148,7 @@
#if __has_include(stdint.h>)
#endif
-// expected-error@+1 {{missing '(' after '__has_include'}}
+// expected-error@+1 {{__has_include must be used within a preprocessing directive}}
__has_include
// expected-error@+1 {{missing ')' after '__has_include'}} // expected-error@+1 {{expected value in expression}} // expected-note@+1 {{to match this '('}}
@@ -121,3 +170,18 @@ __has_include
// expected-error@+1 {{expected "FILENAME" or <FILENAME>}} // expected-error@+1 {{expected value in expression}}
#if __has_include(<stdint.h)
#endif
+
+#define HAS_INCLUDE(header) __has_include(header)
+#if HAS_INCLUDE(<stdint.h>)
+#else
+ #error "__has_include failed (9)."
+#endif
+
+#if FOO
+#elif __has_include(<foo>)
+#endif
+
+// PR15539
+#ifdef FOO
+#elif __has_include(<foo>)
+#endif
diff --git a/test/Preprocessor/hash_line.c b/test/Preprocessor/hash_line.c
index 4f724df..64edae0 100644
--- a/test/Preprocessor/hash_line.c
+++ b/test/Preprocessor/hash_line.c
@@ -1,7 +1,10 @@
// The 1 and # should not go on the same line.
-// RUN: %clang_cc1 %s -E | not grep "1 #"
-// RUN: %clang_cc1 %s -E | grep '^1$'
-// RUN: %clang_cc1 %s -E | grep '^ #$'
+// RUN: %clang_cc1 -E %s | FileCheck --strict-whitespace %s
+// CHECK-NOT: 1{{.*}}#
+// CHECK: {{^1$}}
+// CHECK-NOT: 1{{.*}}#
+// CHECK: {{^ #$}}
+// CHECK-NOT: 1{{.*}}#
1
#define EMPTY
EMPTY #
diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c
index 33a21a3..90b8466 100644
--- a/test/Preprocessor/init.c
+++ b/test/Preprocessor/init.c
@@ -9,14 +9,14 @@
// BLOCKS:#define __block __attribute__((__blocks__(byref)))
//
//
-// RUN: %clang_cc1 -x c++ -std=c++11 -E -dM < /dev/null | FileCheck -check-prefix CXX0X %s
+// RUN: %clang_cc1 -x c++ -std=c++11 -E -dM < /dev/null | FileCheck -check-prefix CXX11 %s
//
-// CXX0X:#define __GNUG__
-// CXX0X:#define __GXX_EXPERIMENTAL_CXX0X__ 1
-// CXX0X:#define __GXX_RTTI 1
-// CXX0X:#define __GXX_WEAK__ 1
-// CXX0X:#define __cplusplus 201103L
-// CXX0X:#define __private_extern__ extern
+// CXX11:#define __GNUG__
+// CXX11:#define __GXX_EXPERIMENTAL_CXX0X__ 1
+// CXX11:#define __GXX_RTTI 1
+// CXX11:#define __GXX_WEAK__ 1
+// CXX11:#define __cplusplus 201103L
+// CXX11:#define __private_extern__ extern
//
//
// RUN: %clang_cc1 -x c++ -std=c++98 -E -dM < /dev/null | FileCheck -check-prefix CXX98 %s
@@ -248,6 +248,7 @@
// ARM:#define __SIZEOF_SIZE_T__ 4
// ARM:#define __SIZEOF_WCHAR_T__ 4
// ARM:#define __SIZEOF_WINT_T__ 4
+// ARM:#define __SIZE_MAX__ 4294967295U
// ARM:#define __SIZE_TYPE__ unsigned int
// ARM:#define __SIZE_WIDTH__ 32
// ARM:#define __THUMB_INTERWORK__ 1
@@ -351,6 +352,7 @@
// ARMEABISOFTFP:#define __SIZEOF_SIZE_T__ 4
// ARMEABISOFTFP:#define __SIZEOF_WCHAR_T__ 4
// ARMEABISOFTFP:#define __SIZEOF_WINT_T__ 4
+// ARMEABISOFTFP:#define __SIZE_MAX__ 4294967295U
// ARMEABISOFTFP:#define __SIZE_TYPE__ unsigned int
// ARMEABISOFTFP:#define __SIZE_WIDTH__ 32
// ARMEABISOFTFP:#define __SOFTFP__ 1
@@ -455,6 +457,7 @@
// ARMEABIHARDFP:#define __SIZEOF_SIZE_T__ 4
// ARMEABIHARDFP:#define __SIZEOF_WCHAR_T__ 4
// ARMEABIHARDFP:#define __SIZEOF_WINT_T__ 4
+// ARMEABIHARDFP:#define __SIZE_MAX__ 4294967295U
// ARMEABIHARDFP:#define __SIZE_TYPE__ unsigned int
// ARMEABIHARDFP:#define __SIZE_WIDTH__ 32
// ARMEABIHARDFP-NOT:#define __SOFTFP__ 1
@@ -554,6 +557,7 @@
// I386:#define __SIZEOF_SIZE_T__ 4
// I386:#define __SIZEOF_WCHAR_T__ 4
// I386:#define __SIZEOF_WINT_T__ 4
+// I386:#define __SIZE_MAX__ 4294967295U
// I386:#define __SIZE_TYPE__ unsigned int
// I386:#define __SIZE_WIDTH__ 32
// I386:#define __UINTMAX_TYPE__ long long unsigned int
@@ -651,6 +655,7 @@
// I386-LINUX:#define __SIZEOF_SIZE_T__ 4
// I386-LINUX:#define __SIZEOF_WCHAR_T__ 4
// I386-LINUX:#define __SIZEOF_WINT_T__ 4
+// I386-LINUX:#define __SIZE_MAX__ 4294967295U
// I386-LINUX:#define __SIZE_TYPE__ unsigned int
// I386-LINUX:#define __SIZE_WIDTH__ 32
// I386-LINUX:#define __UINTMAX_TYPE__ long long unsigned int
@@ -759,6 +764,7 @@
// MIPS32BE:#define __SIZEOF_SIZE_T__ 4
// MIPS32BE:#define __SIZEOF_WCHAR_T__ 4
// MIPS32BE:#define __SIZEOF_WINT_T__ 4
+// MIPS32BE:#define __SIZE_MAX__ 4294967295U
// MIPS32BE:#define __SIZE_TYPE__ unsigned int
// MIPS32BE:#define __SIZE_WIDTH__ 32
// MIPS32BE:#define __STDC_HOSTED__ 0
@@ -875,6 +881,7 @@
// MIPS32EL:#define __SIZEOF_SIZE_T__ 4
// MIPS32EL:#define __SIZEOF_WCHAR_T__ 4
// MIPS32EL:#define __SIZEOF_WINT_T__ 4
+// MIPS32EL:#define __SIZE_MAX__ 4294967295U
// MIPS32EL:#define __SIZE_TYPE__ unsigned int
// MIPS32EL:#define __SIZE_WIDTH__ 32
// MIPS32EL:#define __UINTMAX_TYPE__ long long unsigned int
@@ -988,6 +995,7 @@
// MIPS64BE:#define __SIZEOF_SIZE_T__ 8
// MIPS64BE:#define __SIZEOF_WCHAR_T__ 4
// MIPS64BE:#define __SIZEOF_WINT_T__ 4
+// MIPS64BE:#define __SIZE_MAX__ 18446744073709551615UL
// MIPS64BE:#define __SIZE_TYPE__ long unsigned int
// MIPS64BE:#define __SIZE_WIDTH__ 64
// MIPS64BE:#define __UINTMAX_TYPE__ long long unsigned int
@@ -1103,6 +1111,7 @@
// MIPS64EL:#define __SIZEOF_SIZE_T__ 8
// MIPS64EL:#define __SIZEOF_WCHAR_T__ 4
// MIPS64EL:#define __SIZEOF_WINT_T__ 4
+// MIPS64EL:#define __SIZE_MAX__ 18446744073709551615UL
// MIPS64EL:#define __SIZE_TYPE__ long unsigned int
// MIPS64EL:#define __SIZE_WIDTH__ 64
// MIPS64EL:#define __UINTMAX_TYPE__ long long unsigned int
@@ -1249,6 +1258,7 @@
// MSP430:#define __SIZEOF_SIZE_T__ 2
// MSP430:#define __SIZEOF_WCHAR_T__ 2
// MSP430:#define __SIZEOF_WINT_T__ 2
+// MSP430:#define __SIZE_MAX__ 65535U
// MSP430:#define __SIZE_TYPE__ unsigned int
// MSP430:#define __SIZE_WIDTH__ 16
// MSP430:#define __UINTMAX_TYPE__ long unsigned int
@@ -1346,6 +1356,7 @@
// NVPTX32:#define __SIZEOF_SIZE_T__ 4
// NVPTX32:#define __SIZEOF_WCHAR_T__ 4
// NVPTX32:#define __SIZEOF_WINT_T__ 4
+// NVPTX32:#define __SIZE_MAX__ 4294967295U
// NVPTX32:#define __SIZE_TYPE__ unsigned int
// NVPTX32:#define __SIZE_WIDTH__ 32
// NVPTX32:#define __UINTMAX_TYPE__ long long unsigned int
@@ -1442,6 +1453,7 @@
// NVPTX64:#define __SIZEOF_SIZE_T__ 8
// NVPTX64:#define __SIZEOF_WCHAR_T__ 4
// NVPTX64:#define __SIZEOF_WINT_T__ 4
+// NVPTX64:#define __SIZE_MAX__ 18446744073709551615UL
// NVPTX64:#define __SIZE_TYPE__ long long unsigned int
// NVPTX64:#define __SIZE_WIDTH__ 64
// NVPTX64:#define __UINTMAX_TYPE__ long long unsigned int
@@ -1543,6 +1555,7 @@
// PPC603E:#define __SIZEOF_SIZE_T__ 4
// PPC603E:#define __SIZEOF_WCHAR_T__ 4
// PPC603E:#define __SIZEOF_WINT_T__ 4
+// PPC603E:#define __SIZE_MAX__ 4294967295U
// PPC603E:#define __SIZE_TYPE__ long unsigned int
// PPC603E:#define __SIZE_WIDTH__ 32
// PPC603E:#define __UINTMAX_TYPE__ long long unsigned int
@@ -1651,6 +1664,7 @@
// PPC64:#define __SIZEOF_SIZE_T__ 8
// PPC64:#define __SIZEOF_WCHAR_T__ 4
// PPC64:#define __SIZEOF_WINT_T__ 4
+// PPC64:#define __SIZE_MAX__ 18446744073709551615UL
// PPC64:#define __SIZE_TYPE__ long unsigned int
// PPC64:#define __SIZE_WIDTH__ 64
// PPC64:#define __UINTMAX_TYPE__ long unsigned int
@@ -1663,6 +1677,166 @@
// PPC64:#define __ppc64__ 1
// PPC64:#define __ppc__ 1
//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-none-none -target-cpu a2q -fno-signed-char < /dev/null | FileCheck -check-prefix PPCA2Q %s
+//
+// PPCA2Q:#define _ARCH_A2 1
+// PPCA2Q:#define _ARCH_A2Q 1
+// PPCA2Q:#define _ARCH_PPC 1
+// PPCA2Q:#define _ARCH_PPC64 1
+// PPCA2Q:#define _ARCH_QP 1
+//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-bgq-linux -fno-signed-char < /dev/null | FileCheck -check-prefix PPCBGQ %s
+//
+// PPCBGQ:#define __THW_BLUEGENE__ 1
+// PPCBGQ:#define __TOS_BGQ__ 1
+// PPCBGQ:#define __bg__ 1
+// PPCBGQ:#define __bgq__ 1
+//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-none-none -target-cpu 630 -fno-signed-char < /dev/null | FileCheck -check-prefix PPC630 %s
+//
+// PPC630:#define _ARCH_630 1
+// PPC630:#define _ARCH_PPC 1
+// PPC630:#define _ARCH_PPC64 1
+// PPC630:#define _ARCH_PPCGR 1
+//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-none-none -target-cpu pwr3 -fno-signed-char < /dev/null | FileCheck -check-prefix PPCPWR3 %s
+//
+// PPCPWR3:#define _ARCH_PPC 1
+// PPCPWR3:#define _ARCH_PPC64 1
+// PPCPWR3:#define _ARCH_PPCGR 1
+//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-none-none -target-cpu power3 -fno-signed-char < /dev/null | FileCheck -check-prefix PPCPOWER3 %s
+//
+// PPCPOWER3:#define _ARCH_PPC 1
+// PPCPOWER3:#define _ARCH_PPC64 1
+// PPCPOWER3:#define _ARCH_PPCGR 1
+//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-none-none -target-cpu pwr4 -fno-signed-char < /dev/null | FileCheck -check-prefix PPCPWR4 %s
+//
+// PPCPWR4:#define _ARCH_PPC 1
+// PPCPWR4:#define _ARCH_PPC64 1
+// PPCPWR4:#define _ARCH_PPCGR 1
+// PPCPWR4:#define _ARCH_PPCSQ 1
+// PPCPWR4:#define _ARCH_PWR4 1
+//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-none-none -target-cpu power4 -fno-signed-char < /dev/null | FileCheck -check-prefix PPCPOWER4 %s
+//
+// PPCPOWER4:#define _ARCH_PPC 1
+// PPCPOWER4:#define _ARCH_PPC64 1
+// PPCPOWER4:#define _ARCH_PPCGR 1
+// PPCPOWER4:#define _ARCH_PPCSQ 1
+// PPCPOWER4:#define _ARCH_PWR4 1
+//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-none-none -target-cpu pwr5 -fno-signed-char < /dev/null | FileCheck -check-prefix PPCPWR5 %s
+//
+// PPCPWR5:#define _ARCH_PPC 1
+// PPCPWR5:#define _ARCH_PPC64 1
+// PPCPWR5:#define _ARCH_PPCGR 1
+// PPCPWR5:#define _ARCH_PPCSQ 1
+// PPCPWR5:#define _ARCH_PWR4 1
+// PPCPWR5:#define _ARCH_PWR5 1
+//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-none-none -target-cpu power5 -fno-signed-char < /dev/null | FileCheck -check-prefix PPCPOWER5 %s
+//
+// PPCPOWER5:#define _ARCH_PPC 1
+// PPCPOWER5:#define _ARCH_PPC64 1
+// PPCPOWER5:#define _ARCH_PPCGR 1
+// PPCPOWER5:#define _ARCH_PPCSQ 1
+// PPCPOWER5:#define _ARCH_PWR4 1
+// PPCPOWER5:#define _ARCH_PWR5 1
+//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-none-none -target-cpu pwr5x -fno-signed-char < /dev/null | FileCheck -check-prefix PPCPWR5X %s
+//
+// PPCPWR5X:#define _ARCH_PPC 1
+// PPCPWR5X:#define _ARCH_PPC64 1
+// PPCPWR5X:#define _ARCH_PPCGR 1
+// PPCPWR5X:#define _ARCH_PPCSQ 1
+// PPCPWR5X:#define _ARCH_PWR4 1
+// PPCPWR5X:#define _ARCH_PWR5 1
+// PPCPWR5X:#define _ARCH_PWR5X 1
+//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-none-none -target-cpu power5x -fno-signed-char < /dev/null | FileCheck -check-prefix PPCPOWER5X %s
+//
+// PPCPOWER5X:#define _ARCH_PPC 1
+// PPCPOWER5X:#define _ARCH_PPC64 1
+// PPCPOWER5X:#define _ARCH_PPCGR 1
+// PPCPOWER5X:#define _ARCH_PPCSQ 1
+// PPCPOWER5X:#define _ARCH_PWR4 1
+// PPCPOWER5X:#define _ARCH_PWR5 1
+// PPCPOWER5X:#define _ARCH_PWR5X 1
+//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-none-none -target-cpu pwr6 -fno-signed-char < /dev/null | FileCheck -check-prefix PPCPWR6 %s
+//
+// PPCPWR6:#define _ARCH_PPC 1
+// PPCPWR6:#define _ARCH_PPC64 1
+// PPCPWR6:#define _ARCH_PPCGR 1
+// PPCPWR6:#define _ARCH_PPCSQ 1
+// PPCPWR6:#define _ARCH_PWR4 1
+// PPCPWR6:#define _ARCH_PWR5 1
+// PPCPWR6:#define _ARCH_PWR5X 1
+// PPCPWR6:#define _ARCH_PWR6 1
+//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-none-none -target-cpu power6 -fno-signed-char < /dev/null | FileCheck -check-prefix PPCPOWER6 %s
+//
+// PPCPOWER6:#define _ARCH_PPC 1
+// PPCPOWER6:#define _ARCH_PPC64 1
+// PPCPOWER6:#define _ARCH_PPCGR 1
+// PPCPOWER6:#define _ARCH_PPCSQ 1
+// PPCPOWER6:#define _ARCH_PWR4 1
+// PPCPOWER6:#define _ARCH_PWR5 1
+// PPCPOWER6:#define _ARCH_PWR5X 1
+// PPCPOWER6:#define _ARCH_PWR6 1
+//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-none-none -target-cpu pwr6x -fno-signed-char < /dev/null | FileCheck -check-prefix PPCPWR6X %s
+//
+// PPCPWR6X:#define _ARCH_PPC 1
+// PPCPWR6X:#define _ARCH_PPC64 1
+// PPCPWR6X:#define _ARCH_PPCGR 1
+// PPCPWR6X:#define _ARCH_PPCSQ 1
+// PPCPWR6X:#define _ARCH_PWR4 1
+// PPCPWR6X:#define _ARCH_PWR5 1
+// PPCPWR6X:#define _ARCH_PWR5X 1
+// PPCPWR6X:#define _ARCH_PWR6 1
+// PPCPWR6X:#define _ARCH_PWR6X 1
+//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-none-none -target-cpu power6x -fno-signed-char < /dev/null | FileCheck -check-prefix PPCPOWER6X %s
+//
+// PPCPOWER6X:#define _ARCH_PPC 1
+// PPCPOWER6X:#define _ARCH_PPC64 1
+// PPCPOWER6X:#define _ARCH_PPCGR 1
+// PPCPOWER6X:#define _ARCH_PPCSQ 1
+// PPCPOWER6X:#define _ARCH_PWR4 1
+// PPCPOWER6X:#define _ARCH_PWR5 1
+// PPCPOWER6X:#define _ARCH_PWR5X 1
+// PPCPOWER6X:#define _ARCH_PWR6 1
+// PPCPOWER6X:#define _ARCH_PWR6X 1
+//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-none-none -target-cpu pwr7 -fno-signed-char < /dev/null | FileCheck -check-prefix PPCPWR7 %s
+//
+// PPCPWR7:#define _ARCH_PPC 1
+// PPCPWR7:#define _ARCH_PPC64 1
+// PPCPWR7:#define _ARCH_PPCGR 1
+// PPCPWR7:#define _ARCH_PPCSQ 1
+// PPCPWR7:#define _ARCH_PWR4 1
+// PPCPWR7:#define _ARCH_PWR5 1
+// PPCPWR7:#define _ARCH_PWR5X 1
+// PPCPWR7:#define _ARCH_PWR6 1
+// PPCPWR7:#define _ARCH_PWR6X 1
+// PPCPWR7:#define _ARCH_PWR7 1
+//
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-none-none -target-cpu power7 -fno-signed-char < /dev/null | FileCheck -check-prefix PPCPOWER7 %s
+//
+// PPCPOWER7:#define _ARCH_PPC 1
+// PPCPOWER7:#define _ARCH_PPC64 1
+// PPCPOWER7:#define _ARCH_PPCGR 1
+// PPCPOWER7:#define _ARCH_PPCSQ 1
+// PPCPOWER7:#define _ARCH_PWR4 1
+// PPCPOWER7:#define _ARCH_PWR5 1
+// PPCPOWER7:#define _ARCH_PWR5X 1
+// PPCPOWER7:#define _ARCH_PWR6 1
+// PPCPOWER7:#define _ARCH_PWR6X 1
+// PPCPOWER7:#define _ARCH_PWR7 1
+//
// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-unknown-linux-gnu -fno-signed-char < /dev/null | FileCheck -check-prefix PPC64-LINUX %s
//
// PPC64-LINUX:#define _ARCH_PPC 1
@@ -1753,6 +1927,7 @@
// PPC64-LINUX:#define __SIZEOF_SIZE_T__ 8
// PPC64-LINUX:#define __SIZEOF_WCHAR_T__ 4
// PPC64-LINUX:#define __SIZEOF_WINT_T__ 4
+// PPC64-LINUX:#define __SIZE_MAX__ 18446744073709551615UL
// PPC64-LINUX:#define __SIZE_TYPE__ long unsigned int
// PPC64-LINUX:#define __SIZE_WIDTH__ 64
// PPC64-LINUX:#define __UINTMAX_TYPE__ long unsigned int
@@ -1857,6 +2032,7 @@
// PPC:#define __SIZEOF_SIZE_T__ 4
// PPC:#define __SIZEOF_WCHAR_T__ 4
// PPC:#define __SIZEOF_WINT_T__ 4
+// PPC:#define __SIZE_MAX__ 4294967295U
// PPC:#define __SIZE_TYPE__ long unsigned int
// PPC:#define __SIZE_WIDTH__ 32
// PPC:#define __UINTMAX_TYPE__ long long unsigned int
@@ -1957,6 +2133,7 @@
// PPC-LINUX:#define __SIZEOF_SIZE_T__ 4
// PPC-LINUX:#define __SIZEOF_WCHAR_T__ 4
// PPC-LINUX:#define __SIZEOF_WINT_T__ 4
+// PPC-LINUX:#define __SIZE_MAX__ 4294967295U
// PPC-LINUX:#define __SIZE_TYPE__ unsigned int
// PPC-LINUX:#define __SIZE_WIDTH__ 32
// PPC-LINUX:#define __UINTMAX_TYPE__ long long unsigned int
@@ -2052,6 +2229,7 @@
// SPARC:#define __SIZEOF_SIZE_T__ 4
// SPARC:#define __SIZEOF_WCHAR_T__ 4
// SPARC:#define __SIZEOF_WINT_T__ 4
+// SPARC:#define __SIZE_MAX__ 4294967295U
// SPARC:#define __SIZE_TYPE__ long unsigned int
// SPARC:#define __SIZE_WIDTH__ 32
// SPARC:#define __UINTMAX_TYPE__ long long unsigned int
@@ -2146,6 +2324,7 @@
// TCE:#define __SIZEOF_SIZE_T__ 4
// TCE:#define __SIZEOF_WCHAR_T__ 4
// TCE:#define __SIZEOF_WINT_T__ 4
+// TCE:#define __SIZE_MAX__ 4294967295U
// TCE:#define __SIZE_TYPE__ unsigned int
// TCE:#define __SIZE_WIDTH__ 32
// TCE:#define __TCE_V1__ 1
@@ -2246,6 +2425,7 @@
// X86_64:#define __SIZEOF_SIZE_T__ 8
// X86_64:#define __SIZEOF_WCHAR_T__ 4
// X86_64:#define __SIZEOF_WINT_T__ 4
+// X86_64:#define __SIZE_MAX__ 18446744073709551615UL
// X86_64:#define __SIZE_TYPE__ long unsigned int
// X86_64:#define __SIZE_WIDTH__ 64
// X86_64:#define __SSE2_MATH__ 1
@@ -2349,6 +2529,7 @@
// X86_64-LINUX:#define __SIZEOF_SIZE_T__ 8
// X86_64-LINUX:#define __SIZEOF_WCHAR_T__ 4
// X86_64-LINUX:#define __SIZEOF_WINT_T__ 4
+// X86_64-LINUX:#define __SIZE_MAX__ 18446744073709551615UL
// X86_64-LINUX:#define __SIZE_TYPE__ long unsigned int
// X86_64-LINUX:#define __SIZE_WIDTH__ 64
// X86_64-LINUX:#define __SSE2_MATH__ 1
diff --git a/test/Preprocessor/invalid-__has_warning1.c b/test/Preprocessor/invalid-__has_warning1.c
new file mode 100644
index 0000000..b6a0b2e
--- /dev/null
+++ b/test/Preprocessor/invalid-__has_warning1.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -verify %s
+
+// These must be the last lines in this test.
+// expected-error@+1{{expected string literal}} expected-error@+1 2{{expected}}
+int i = __has_warning(
diff --git a/test/Preprocessor/invalid-__has_warning2.c b/test/Preprocessor/invalid-__has_warning2.c
new file mode 100644
index 0000000..8aba530
--- /dev/null
+++ b/test/Preprocessor/invalid-__has_warning2.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 -verify %s
+
+// These must be the last lines in this test.
+// expected-error@+1{{expected string literal}} expected-error@+1{{expected}}
+int i = __has_warning();
diff --git a/test/Preprocessor/iwithprefix.c b/test/Preprocessor/iwithprefix.c
new file mode 100644
index 0000000..c11f36e
--- /dev/null
+++ b/test/Preprocessor/iwithprefix.c
@@ -0,0 +1,17 @@
+// Check that -iwithprefix falls into the "after" search list.
+//
+// RUN: rm -rf %t.tmps
+// RUN: mkdir -p %t.tmps/first %t.tmps/second
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown \
+// RUN: -iprefix %t.tmps/ -iwithprefix second \
+// RUN: -isystem %t.tmps/first -v 2> %t.out
+// RUN: cat %t.out
+// RUN: FileCheck < %t.out %s
+
+// CHECK: #include <...> search starts here:
+// CHECK: {{.*}}.tmps/first
+// CHECK: /lib/clang/{{[.0-9]+}}/include
+// CHECK: {{.*}}.tmps/second
+// CHECK-NOT: {{.*}}.tmps
+
+
diff --git a/test/Preprocessor/line-directive-output.c b/test/Preprocessor/line-directive-output.c
index 290703a..bd3ea94 100644
--- a/test/Preprocessor/line-directive-output.c
+++ b/test/Preprocessor/line-directive-output.c
@@ -2,6 +2,10 @@
// PR6101
int a;
// CHECK: # 1 "{{.*}}line-directive-output.c"
+
+// Check that we do not emit an enter marker for the main file.
+// CHECK-NOT: # 1 "{{.*}}line-directive-output.c" 1
+
// CHECK: int a;
// CHECK-NEXT: # 50 "{{.*}}line-directive-output.c"
diff --git a/test/Preprocessor/macro-multiline.c b/test/Preprocessor/macro-multiline.c.ignoreme
index df7c40a..df7c40a 100644
--- a/test/Preprocessor/macro-multiline.c
+++ b/test/Preprocessor/macro-multiline.c.ignoreme
diff --git a/test/Preprocessor/macro_arg_slocentry_merge.c b/test/Preprocessor/macro_arg_slocentry_merge.c
new file mode 100644
index 0000000..9ab385f
--- /dev/null
+++ b/test/Preprocessor/macro_arg_slocentry_merge.c
@@ -0,0 +1,7 @@
+// RUN: not %clang_cc1 -fsyntax-only %s 2>&1 | FileCheck %s
+
+#include "macro_arg_slocentry_merge.h"
+
+// CHECK: macro_arg_slocentry_merge.h:7:19: error: unknown type name 'win'
+// CHECK: macro_arg_slocentry_merge.h:5:16: note: expanded from macro 'WINDOW'
+// CHECK: macro_arg_slocentry_merge.h:6:18: note: expanded from macro 'P_'
diff --git a/test/Preprocessor/macro_arg_slocentry_merge.h b/test/Preprocessor/macro_arg_slocentry_merge.h
new file mode 100644
index 0000000..62595b7
--- /dev/null
+++ b/test/Preprocessor/macro_arg_slocentry_merge.h
@@ -0,0 +1,7 @@
+
+
+
+
+#define WINDOW win
+#define P_(args) args
+extern void f P_((WINDOW win));
diff --git a/test/Preprocessor/macro_expand.c b/test/Preprocessor/macro_expand.c
index 4dc0357..cf98a2c 100644
--- a/test/Preprocessor/macro_expand.c
+++ b/test/Preprocessor/macro_expand.c
@@ -1,11 +1,10 @@
-// RUN: %clang_cc1 -E %s | grep '^A: Y$'
-// RUN: %clang_cc1 -E %s | grep '^B: f()$'
-// RUN: %clang_cc1 -E %s | grep '^C: for()$'
+// RUN: %clang_cc1 -E %s | FileCheck --strict-whitespace %s
#define X() Y
#define Y() X
A: X()()()
+// CHECK: {{^}}A: Y{{$}}
// PR3927
#define f(x) h(x
@@ -14,6 +13,9 @@ A: X()()()
B: f(f))
C: for(for))
+// CHECK: {{^}}B: f(){{$}}
+// CHECK: {{^}}C: for(){{$}}
+
// rdar://6880648
#define f(x,y...) y
f()
diff --git a/test/Preprocessor/macro_expandloc.c b/test/Preprocessor/macro_expandloc.c
index f466013..3b9eb5f 100644
--- a/test/Preprocessor/macro_expandloc.c
+++ b/test/Preprocessor/macro_expandloc.c
@@ -1,6 +1,13 @@
-// RUN: %clang_cc1 %s -E 2>&1 | grep '#include'
+// RUN: %clang_cc1 -E -verify %s
#define FOO 1
// The error message should be on the #include line, not the 1.
+
+// expected-error@+1 {{expected "FILENAME" or <FILENAME>}}
#include FOO
+#define BAR BAZ
+
+// expected-error@+1 {{expected "FILENAME" or <FILENAME>}}
+#include BAR
+
diff --git a/test/Preprocessor/macro_expandloc2.c b/test/Preprocessor/macro_expandloc2.c
deleted file mode 100644
index 4aa7dfe..0000000
--- a/test/Preprocessor/macro_expandloc2.c
+++ /dev/null
@@ -1,6 +0,0 @@
-// RUN: %clang_cc1 %s -E 2>&1 | grep '#include'
-#define FOO BAR
-
-// The error message should be on the #include line, not the 1.
-#include FOO
-
diff --git a/test/Preprocessor/macro_fn.c b/test/Preprocessor/macro_fn.c
index f93d52c..fcdb90a 100644
--- a/test/Preprocessor/macro_fn.c
+++ b/test/Preprocessor/macro_fn.c
@@ -1,9 +1,9 @@
/* RUN: %clang_cc1 %s -Eonly -std=c89 -pedantic -verify
*/
/* PR3937 */
-#define zero() 0
-#define one(x) 0
-#define two(x, y) 0
+#define zero() 0 /* expected-note 2 {{defined here}} */
+#define one(x) 0 /* expected-note 2 {{defined here}} */
+#define two(x, y) 0 /* expected-note 4 {{defined here}} */
#define zero_dot(...) 0 /* expected-warning {{variadic macros are a C99 feature}} */
#define one_dot(x, ...) 0 /* expected-warning {{variadic macros are a C99 feature}} expected-note 2{{macro 'one_dot' defined here}} */
@@ -44,3 +44,9 @@ one_dot() /* empty first argument, elided ...: expected-warning {{must specify
#define E() (i == 0)
#if E
#endif
+
+
+/* <rdar://problem/12292192> */
+#define NSAssert(condition, desc, ...) /* expected-warning {{variadic macros are a C99 feature}} */ \
+ SomeComplicatedStuff((desc), ##__VA_ARGS__) /* expected-warning {{token pasting of ',' and __VA_ARGS__ is a GNU extension}} */
+NSAssert(somecond, somedesc)
diff --git a/test/Preprocessor/macro_misc.c b/test/Preprocessor/macro_misc.c
index 53d9982..3feaa21 100644
--- a/test/Preprocessor/macro_misc.c
+++ b/test/Preprocessor/macro_misc.c
@@ -21,3 +21,17 @@
#define FUNC_LIKE3(a) ( a) // expected-note {{previous definition is here}}
#define FUNC_LIKE3(a) (a) // expected-warning {{'FUNC_LIKE3' macro redefined}}
+// RUN: %clang_cc1 -fms-extensions -DMS_EXT %s -Eonly -verify
+#ifndef MS_EXT
+// This should under C99.
+#define FUNC_LIKE4(a,b) (a+b) // expected-note {{previous definition is here}}
+#define FUNC_LIKE4(x,y) (x+y) // expected-warning {{'FUNC_LIKE4' macro redefined}}
+#else
+// This shouldn't under MS extensions.
+#define FUNC_LIKE4(a,b) (a+b)
+#define FUNC_LIKE4(x,y) (x+y)
+
+// This should.
+#define FUNC_LIKE5(a,b) (a+b) // expected-note {{previous definition is here}}
+#define FUNC_LIKE5(x,y) (y+x) // expected-warning {{'FUNC_LIKE5' macro redefined}}
+#endif
diff --git a/test/Preprocessor/macro_rescan.c b/test/Preprocessor/macro_rescan.c
index 3a38548..83a1975 100644
--- a/test/Preprocessor/macro_rescan.c
+++ b/test/Preprocessor/macro_rescan.c
@@ -1,9 +1,11 @@
-// RUN: %clang_cc1 -E %s | grep 'ei_1 = (17 +1);'
-// RUN: %clang_cc1 -E %s | grep 'ei_2 = (M1)(17);'
+// RUN: %clang_cc1 -E %s | FileCheck --strict-whitespace %s
-#define M1(a) (a+1)
-#define M2(b) b
+#define M1(a) (a+1)
+#define M2(b) b
-int ei_1 = M2(M1)(17); /* becomes int ei_1 = (17+1); */
-int ei_2 = (M2(M1))(17); /* becomes int ei_2 = (M1)(17); */
+int ei_1 = M2(M1)(17);
+// CHECK: {{^}}int ei_1 = (17 +1);{{$}}
+
+int ei_2 = (M2(M1))(17);
+// CHECK: {{^}}int ei_2 = (M1)(17);{{$}}
diff --git a/test/Preprocessor/macro_space.c b/test/Preprocessor/macro_space.c
index 49a9a0f..8a47a3b 100644
--- a/test/Preprocessor/macro_space.c
+++ b/test/Preprocessor/macro_space.c
@@ -1,5 +1,6 @@
-// RUN: %clang_cc1 %s -E | grep '! ,'
+// RUN: %clang_cc1 -E %s | FileCheck --strict-whitespace %s
#define XX
! XX,
+// CHECK: {{^}}! ,{{$}}
diff --git a/test/Preprocessor/macro_variadic.cl b/test/Preprocessor/macro_variadic.cl
new file mode 100644
index 0000000..e4c5566
--- /dev/null
+++ b/test/Preprocessor/macro_variadic.cl
@@ -0,0 +1,3 @@
+// RUN: %clang_cc1 -verify %s
+
+#define X(...) 1 // expected-error {{variadic macros not supported in OpenCL}}
diff --git a/test/Preprocessor/microsoft-import.c b/test/Preprocessor/microsoft-import.c
index 8835c7a..2fc58bc 100644
--- a/test/Preprocessor/microsoft-import.c
+++ b/test/Preprocessor/microsoft-import.c
@@ -1,17 +1,12 @@
-// RUN: %clang_cc1 -E -fms-compatibility %s 2>&1 | grep 'doh.c:100:2: error: #import of type library is an unsupported Microsoft feature'
-// RUN: %clang_cc1 -E -fms-compatibility %s 2>&1 | grep 'doh.c:200:2: error: #import of type library is an unsupported Microsoft feature'
-// RUN: %clang_cc1 -E -fms-compatibility %s 2>&1 | grep 'doh.c:300:2: error: #import of type library is an unsupported Microsoft feature'
+// RUN: %clang_cc1 -E -verify -fms-compatibility %s
-#line 100 "doh.c"
#import "pp-record.h" // expected-error {{#import of type library is an unsupported Microsoft feature}}
// Test attributes
-#line 200 "doh.c"
#import "pp-record.h" no_namespace, auto_rename // expected-error {{#import of type library is an unsupported Microsoft feature}}
-// This will also fire the "#import of type library is an unsupported Microsoft feature"
-// error, but we can't use -verify because there's no way to put the comment on the proper line
-#line 300 "doh.c"
#import "pp-record.h" no_namespace \
auto_rename \
auto_search
+// expected-error@-3 {{#import of type library is an unsupported Microsoft feature}}
+
diff --git a/test/Preprocessor/output_paste_avoid.c b/test/Preprocessor/output_paste_avoid.c
deleted file mode 100644
index 8e4f3a4..0000000
--- a/test/Preprocessor/output_paste_avoid.c
+++ /dev/null
@@ -1,33 +0,0 @@
-// RUN: %clang_cc1 -E %s -o - | FileCheck -strict-whitespace %s
-
-
-#define y(a) ..a
-A: y(.)
-// This should print as ".. ." to avoid turning into ...
-// CHECK: A: .. .
-
-#define X 0 .. 1
-B: X
-// CHECK: B: 0 .. 1
-
-#define DOT .
-C: ..DOT
-// CHECK: C: .. .
-
-
-#define PLUS +
-#define EMPTY
-#define f(x) =x=
-D: +PLUS -EMPTY- PLUS+ f(=)
-// CHECK: D: + + - - + + = = =
-
-
-#define test(x) L#x
-E: test(str)
-// Should expand to L "str" not L"str"
-// CHECK: E: L "str"
-
-// Should avoid producing >>=.
-#define equal =
-F: >>equal
-// CHECK: F: >> =
diff --git a/test/Preprocessor/output_paste_avoid.cpp b/test/Preprocessor/output_paste_avoid.cpp
new file mode 100644
index 0000000..689d966
--- /dev/null
+++ b/test/Preprocessor/output_paste_avoid.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -E -std=c++11 %s -o - | FileCheck -strict-whitespace %s
+
+
+#define y(a) ..a
+A: y(.)
+// This should print as ".. ." to avoid turning into ...
+// CHECK: A: .. .
+
+#define X 0 .. 1
+B: X
+// CHECK: B: 0 .. 1
+
+#define DOT .
+C: ..DOT
+// CHECK: C: .. .
+
+
+#define PLUS +
+#define EMPTY
+#define f(x) =x=
+D: +PLUS -EMPTY- PLUS+ f(=)
+// CHECK: D: + + - - + + = = =
+
+
+#define test(x) L#x
+E: test(str)
+// Should expand to L "str" not L"str"
+// CHECK: E: L "str"
+
+// Should avoid producing >>=.
+#define equal =
+F: >>equal
+// CHECK: F: >> =
+
+// Make sure we don't introduce spaces in the guid because we try to avoid
+// pasting '-' to a numeric constant.
+#define TYPEDEF(guid) typedef [uuid(guid)]
+TYPEDEF(66504301-BE0F-101A-8BBB-00AA00300CAB) long OLE_COLOR;
+// CHECK: typedef [uuid(66504301-BE0F-101A-8BBB-00AA00300CAB)] long OLE_COLOR;
+
+// Be careful with UD-suffixes.
+#define StrSuffix() "abc"_suffix
+#define IntSuffix() 123_suffix
+UD: StrSuffix()ident
+UD: IntSuffix()ident
+// CHECK: UD: "abc"_suffix ident
+// CHECK: UD: 123_suffix ident
diff --git a/test/Preprocessor/pp-record.c b/test/Preprocessor/pp-record.c
index dd958d0..48000ed 100644
--- a/test/Preprocessor/pp-record.c
+++ b/test/Preprocessor/pp-record.c
@@ -21,3 +21,14 @@ FNM(
int b;
#endif
)
+
+#define M1 c
+#define M2 int
+#define FM2(x,y) y x
+FM2(M1, M2);
+
+#define FM3(x) x
+FM3(
+#define M3 int x2
+)
+M3;
diff --git a/test/Preprocessor/pragma_diagnostic.c b/test/Preprocessor/pragma_diagnostic.c
index 818f02f..e8a67ab 100644
--- a/test/Preprocessor/pragma_diagnostic.c
+++ b/test/Preprocessor/pragma_diagnostic.c
@@ -23,7 +23,7 @@
#define foo error
#pragma GCC diagnostic foo "-Wundef" // expected-warning {{pragma diagnostic expected 'error', 'warning', 'ignored', 'fatal', 'push', or 'pop'}}
-#pragma GCC diagnostic error 42 // expected-warning {{unexpected token in pragma diagnostic}}
+#pragma GCC diagnostic error 42 // expected-error {{expected string literal in pragma diagnostic}}
#pragma GCC diagnostic error "-Wundef" 42 // expected-warning {{unexpected token in pragma diagnostic}}
#pragma GCC diagnostic error "invalid-name" // expected-warning {{pragma diagnostic expected option name (e.g. "-Wundef")}}
diff --git a/test/Preprocessor/pragma_microsoft.c b/test/Preprocessor/pragma_microsoft.c
index e461c70..c0ddf74 100644
--- a/test/Preprocessor/pragma_microsoft.c
+++ b/test/Preprocessor/pragma_microsoft.c
@@ -11,7 +11,7 @@
#pragma comment( user, "Compiled on " __DATE__ " at " __TIME__ )
#pragma comment(foo) // expected-error {{unknown kind of pragma comment}}
-#pragma comment(compiler,) // expected-error {{pragma comment requires}}
+#pragma comment(compiler,) // expected-error {{expected string literal in pragma comment}}
#define foo compiler
#pragma comment(foo) // macro expand kind.
#pragma comment(foo) x // expected-error {{pragma comment requires}}
@@ -26,7 +26,7 @@ __pragma(comment(linker," bar=" BAR))
#define MACRO_WITH__PRAGMA { \
__pragma(warning(push)); \
__pragma(warning(disable: 10000)); \
- 2+2; \
+ 1 + (2 > 3) ? 4 : 5; \
__pragma(warning(pop)); \
}
@@ -36,7 +36,8 @@ void f()
// If we ever actually *support* __pragma(warning(disable: x)),
// this warning should go away.
- MACRO_WITH__PRAGMA // expected-warning {{expression result unused}}
+ MACRO_WITH__PRAGMA // expected-warning {{lower precedence}} \
+ // expected-note 2 {{place parentheses}}
}
diff --git a/test/Preprocessor/pragma_unknown.c b/test/Preprocessor/pragma_unknown.c
index 2586754..5578ce5 100644
--- a/test/Preprocessor/pragma_unknown.c
+++ b/test/Preprocessor/pragma_unknown.c
@@ -1,9 +1,10 @@
-// RUN: %clang_cc1 -E %s | grep '#pragma foo bar'
// RUN: %clang_cc1 -fsyntax-only -Wunknown-pragmas -verify %s
+// RUN: %clang_cc1 -E %s | FileCheck --strict-whitespace %s
// GCC doesn't expand macro args for unrecognized pragmas.
#define bar xX
#pragma foo bar // expected-warning {{unknown pragma ignored}}
+// CHECK: {{^}}#pragma foo bar{{$}}
#pragma STDC FP_CONTRACT ON
#pragma STDC FP_CONTRACT OFF
diff --git a/test/Preprocessor/predefined-arch-macros.c b/test/Preprocessor/predefined-arch-macros.c
index 719f945..680f39a 100644
--- a/test/Preprocessor/predefined-arch-macros.c
+++ b/test/Preprocessor/predefined-arch-macros.c
@@ -464,6 +464,7 @@
// RUN: | FileCheck %s -check-prefix=CHECK_CORE_AVX_I_M32
// CHECK_CORE_AVX_I_M32: #define __AES__ 1
// CHECK_CORE_AVX_I_M32: #define __AVX__ 1
+// CHECK_CORE_AVX_I_M32: #define __F16C__ 1
// CHECK_CORE_AVX_I_M32: #define __MMX__ 1
// CHECK_CORE_AVX_I_M32: #define __PCLMUL__ 1
// CHECK_CORE_AVX_I_M32: #define __RDRND__ 1
@@ -484,6 +485,7 @@
// RUN: | FileCheck %s -check-prefix=CHECK_CORE_AVX_I_M64
// CHECK_CORE_AVX_I_M64: #define __AES__ 1
// CHECK_CORE_AVX_I_M64: #define __AVX__ 1
+// CHECK_CORE_AVX_I_M64: #define __F16C__ 1
// CHECK_CORE_AVX_I_M64: #define __MMX__ 1
// CHECK_CORE_AVX_I_M64: #define __PCLMUL__ 1
// CHECK_CORE_AVX_I_M64: #define __RDRND__ 1
@@ -510,6 +512,7 @@
// CHECK_CORE_AVX2_M32: #define __AVX__ 1
// CHECK_CORE_AVX2_M32: #define __BMI2__ 1
// CHECK_CORE_AVX2_M32: #define __BMI__ 1
+// CHECK_CORE_AVX2_M32: #define __F16C__ 1
// CHECK_CORE_AVX2_M32: #define __FMA__ 1
// CHECK_CORE_AVX2_M32: #define __LZCNT__ 1
// CHECK_CORE_AVX2_M32: #define __MMX__ 1
@@ -536,6 +539,7 @@
// CHECK_CORE_AVX2_M64: #define __AVX__ 1
// CHECK_CORE_AVX2_M64: #define __BMI2__ 1
// CHECK_CORE_AVX2_M64: #define __BMI__ 1
+// CHECK_CORE_AVX2_M64: #define __F16C__ 1
// CHECK_CORE_AVX2_M64: #define __FMA__ 1
// CHECK_CORE_AVX2_M64: #define __LZCNT__ 1
// CHECK_CORE_AVX2_M64: #define __MMX__ 1
@@ -1008,12 +1012,33 @@
// CHECK_ATHLON_FX_M64: #define __tune_k8__ 1
// CHECK_ATHLON_FX_M64: #define __x86_64 1
// CHECK_ATHLON_FX_M64: #define __x86_64__ 1
+// RUN: %clang -march=amdfam10 -m32 -E -dM %s -o - 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: | FileCheck %s -check-prefix=CHECK_AMDFAM10_M32
+// CHECK_AMDFAM10_M32: #define __3dNOW_A__ 1
+// CHECK_AMDFAM10_M32: #define __3dNOW__ 1
+// CHECK_AMDFAM10_M32: #define __LZCNT__ 1
+// CHECK_AMDFAM10_M32: #define __MMX__ 1
+// CHECK_AMDFAM10_M32: #define __POPCNT__ 1
+// CHECK_AMDFAM10_M32: #define __SSE2_MATH__ 1
+// CHECK_AMDFAM10_M32: #define __SSE2__ 1
+// CHECK_AMDFAM10_M32: #define __SSE3__ 1
+// CHECK_AMDFAM10_M32: #define __SSE4A__ 1
+// CHECK_AMDFAM10_M32: #define __SSE_MATH__ 1
+// CHECK_AMDFAM10_M32: #define __SSE__ 1
+// CHECK_AMDFAM10_M32: #define __amdfam10 1
+// CHECK_AMDFAM10_M32: #define __amdfam10__ 1
+// CHECK_AMDFAM10_M32: #define __i386 1
+// CHECK_AMDFAM10_M32: #define __i386__ 1
+// CHECK_AMDFAM10_M32: #define __tune_amdfam10__ 1
// RUN: %clang -march=amdfam10 -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_AMDFAM10_M64
// CHECK_AMDFAM10_M64: #define __3dNOW_A__ 1
// CHECK_AMDFAM10_M64: #define __3dNOW__ 1
+// CHECK_AMDFAM10_M64: #define __LZCNT__ 1
// CHECK_AMDFAM10_M64: #define __MMX__ 1
+// CHECK_AMDFAM10_M64: #define __POPCNT__ 1
// CHECK_AMDFAM10_M64: #define __SSE2_MATH__ 1
// CHECK_AMDFAM10_M64: #define __SSE2__ 1
// CHECK_AMDFAM10_M64: #define __SSE3__ 1
@@ -1027,15 +1052,87 @@
// CHECK_AMDFAM10_M64: #define __tune_amdfam10__ 1
// CHECK_AMDFAM10_M64: #define __x86_64 1
// CHECK_AMDFAM10_M64: #define __x86_64__ 1
+// RUN: %clang -march=btver1 -m32 -E -dM %s -o - 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: | FileCheck %s -check-prefix=CHECK_BTVER1_M32
+// CHECK_BTVER1_M32-NOT: #define __3dNOW_A__ 1
+// CHECK_BTVER1_M32-NOT: #define __3dNOW__ 1
+// CHECK_BTVER1_M32: #define __LZCNT__ 1
+// CHECK_BTVER1_M32: #define __MMX__ 1
+// CHECK_BTVER1_M32: #define __POPCNT__ 1
+// CHECK_BTVER1_M32: #define __SSE2_MATH__ 1
+// CHECK_BTVER1_M32: #define __SSE2__ 1
+// CHECK_BTVER1_M32: #define __SSE3__ 1
+// CHECK_BTVER1_M32: #define __SSE4A__ 1
+// CHECK_BTVER1_M32: #define __SSE_MATH__ 1
+// CHECK_BTVER1_M32: #define __SSE__ 1
+// CHECK_BTVER1_M32: #define __SSSE3__ 1
+// CHECK_BTVER1_M32: #define __btver1 1
+// CHECK_BTVER1_M32: #define __btver1__ 1
+// CHECK_BTVER1_M32: #define __i386 1
+// CHECK_BTVER1_M32: #define __i386__ 1
+// CHECK_BTVER1_M32: #define __tune_btver1__ 1
+// RUN: %clang -march=btver1 -m64 -E -dM %s -o - 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: | FileCheck %s -check-prefix=CHECK_BTVER1_M64
+// CHECK_BTVER1_M64-NOT: #define __3dNOW_A__ 1
+// CHECK_BTVER1_M64-NOT: #define __3dNOW__ 1
+// CHECK_BTVER1_M64: #define __LZCNT__ 1
+// CHECK_BTVER1_M64: #define __MMX__ 1
+// CHECK_BTVER1_M64: #define __POPCNT__ 1
+// CHECK_BTVER1_M64: #define __SSE2_MATH__ 1
+// CHECK_BTVER1_M64: #define __SSE2__ 1
+// CHECK_BTVER1_M64: #define __SSE3__ 1
+// CHECK_BTVER1_M64: #define __SSE4A__ 1
+// CHECK_BTVER1_M64: #define __SSE_MATH__ 1
+// CHECK_BTVER1_M64: #define __SSE__ 1
+// CHECK_BTVER1_M64: #define __SSSE3__ 1
+// CHECK_BTVER1_M64: #define __amd64 1
+// CHECK_BTVER1_M64: #define __amd64__ 1
+// CHECK_BTVER1_M64: #define __btver1 1
+// CHECK_BTVER1_M64: #define __btver1__ 1
+// CHECK_BTVER1_M64: #define __tune_btver1__ 1
+// CHECK_BTVER1_M64: #define __x86_64 1
+// CHECK_BTVER1_M64: #define __x86_64__ 1
+// RUN: %clang -march=bdver1 -m32 -E -dM %s -o - 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: | FileCheck %s -check-prefix=CHECK_BDVER1_M32
+// CHECK_BDVER1_M32-NOT: #define __3dNOW_A__ 1
+// CHECK_BDVER1_M32-NOT: #define __3dNOW__ 1
+// CHECK_BDVER1_M32: #define __AES__ 1
+// CHECK_BDVER1_M32: #define __AVX__ 1
+// CHECK_BDVER1_M32: #define __FMA4__ 1
+// CHECK_BDVER1_M32: #define __LZCNT__ 1
+// CHECK_BDVER1_M32: #define __MMX__ 1
+// CHECK_BDVER1_M32: #define __PCLMUL__ 1
+// CHECK_BDVER1_M32: #define __POPCNT__ 1
+// CHECK_BDVER1_M32: #define __SSE2_MATH__ 1
+// CHECK_BDVER1_M32: #define __SSE2__ 1
+// CHECK_BDVER1_M32: #define __SSE3__ 1
+// CHECK_BDVER1_M32: #define __SSE4A__ 1
+// CHECK_BDVER1_M32: #define __SSE4_1__ 1
+// CHECK_BDVER1_M32: #define __SSE4_2__ 1
+// CHECK_BDVER1_M32: #define __SSE_MATH__ 1
+// CHECK_BDVER1_M32: #define __SSE__ 1
+// CHECK_BDVER1_M32: #define __SSSE3__ 1
+// CHECK_BDVER1_M32: #define __XOP__ 1
+// CHECK_BDVER1_M32: #define __bdver1 1
+// CHECK_BDVER1_M32: #define __bdver1__ 1
+// CHECK_BDVER1_M32: #define __i386 1
+// CHECK_BDVER1_M32: #define __i386__ 1
+// CHECK_BDVER1_M32: #define __tune_bdver1__ 1
// RUN: %clang -march=bdver1 -m64 -E -dM %s -o - 2>&1 \
// RUN: -target i386-unknown-linux \
// RUN: | FileCheck %s -check-prefix=CHECK_BDVER1_M64
-// CHECK_BDVER1_M64: #define __AVX__ 1
// CHECK_BDVER1_M64-NOT: #define __3dNOW_A__ 1
// CHECK_BDVER1_M64-NOT: #define __3dNOW__ 1
+// CHECK_BDVER1_M64: #define __AES__ 1
+// CHECK_BDVER1_M64: #define __AVX__ 1
// CHECK_BDVER1_M64: #define __FMA4__ 1
+// CHECK_BDVER1_M64: #define __LZCNT__ 1
// CHECK_BDVER1_M64: #define __MMX__ 1
// CHECK_BDVER1_M64: #define __PCLMUL__ 1
+// CHECK_BDVER1_M64: #define __POPCNT__ 1
// CHECK_BDVER1_M64: #define __SSE2_MATH__ 1
// CHECK_BDVER1_M64: #define __SSE2__ 1
// CHECK_BDVER1_M64: #define __SSE3__ 1
@@ -1053,5 +1150,67 @@
// CHECK_BDVER1_M64: #define __tune_bdver1__ 1
// CHECK_BDVER1_M64: #define __x86_64 1
// CHECK_BDVER1_M64: #define __x86_64__ 1
+// RUN: %clang -march=bdver2 -m32 -E -dM %s -o - 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: | FileCheck %s -check-prefix=CHECK_BDVER2_M32
+// CHECK_BDVER2_M32-NOT: #define __3dNOW_A__ 1
+// CHECK_BDVER2_M32-NOT: #define __3dNOW__ 1
+// CHECK_BDVER2_M32: #define __AES__ 1
+// CHECK_BDVER2_M32: #define __AVX__ 1
+// CHECK_BDVER2_M32: #define __BMI__ 1
+// CHECK_BDVER2_M32: #define __F16C__ 1
+// CHECK_BDVER2_M32: #define __FMA4__ 1
+// CHECK_BDVER2_M32: #define __FMA__ 1
+// CHECK_BDVER2_M32: #define __LZCNT__ 1
+// CHECK_BDVER2_M32: #define __MMX__ 1
+// CHECK_BDVER2_M32: #define __PCLMUL__ 1
+// CHECK_BDVER2_M32: #define __POPCNT__ 1
+// CHECK_BDVER2_M32: #define __SSE2_MATH__ 1
+// CHECK_BDVER2_M32: #define __SSE2__ 1
+// CHECK_BDVER2_M32: #define __SSE3__ 1
+// CHECK_BDVER2_M32: #define __SSE4A__ 1
+// CHECK_BDVER2_M32: #define __SSE4_1__ 1
+// CHECK_BDVER2_M32: #define __SSE4_2__ 1
+// CHECK_BDVER2_M32: #define __SSE_MATH__ 1
+// CHECK_BDVER2_M32: #define __SSE__ 1
+// CHECK_BDVER2_M32: #define __SSSE3__ 1
+// CHECK_BDVER2_M32: #define __XOP__ 1
+// CHECK_BDVER2_M32: #define __bdver2 1
+// CHECK_BDVER2_M32: #define __bdver2__ 1
+// CHECK_BDVER2_M32: #define __i386 1
+// CHECK_BDVER2_M32: #define __i386__ 1
+// CHECK_BDVER2_M32: #define __tune_bdver2__ 1
+// RUN: %clang -march=bdver2 -m64 -E -dM %s -o - 2>&1 \
+// RUN: -target i386-unknown-linux \
+// RUN: | FileCheck %s -check-prefix=CHECK_BDVER2_M64
+// CHECK_BDVER2_M64-NOT: #define __3dNOW_A__ 1
+// CHECK_BDVER2_M64-NOT: #define __3dNOW__ 1
+// CHECK_BDVER2_M64: #define __AES__ 1
+// CHECK_BDVER2_M64: #define __AVX__ 1
+// CHECK_BDVER2_M64: #define __BMI__ 1
+// CHECK_BDVER2_M64: #define __F16C__ 1
+// CHECK_BDVER2_M64: #define __FMA4__ 1
+// CHECK_BDVER2_M64: #define __FMA__ 1
+// CHECK_BDVER2_M64: #define __LZCNT__ 1
+// CHECK_BDVER2_M64: #define __MMX__ 1
+// CHECK_BDVER2_M64: #define __PCLMUL__ 1
+// CHECK_BDVER2_M64: #define __POPCNT__ 1
+// CHECK_BDVER2_M64: #define __SSE2_MATH__ 1
+// CHECK_BDVER2_M64: #define __SSE2__ 1
+// CHECK_BDVER2_M64: #define __SSE3__ 1
+// CHECK_BDVER2_M64: #define __SSE4A__ 1
+// CHECK_BDVER2_M64: #define __SSE4_1__ 1
+// CHECK_BDVER2_M64: #define __SSE4_2__ 1
+// CHECK_BDVER2_M64: #define __SSE_MATH__ 1
+// CHECK_BDVER2_M64: #define __SSE__ 1
+// CHECK_BDVER2_M64: #define __SSSE3__ 1
+// CHECK_BDVER2_M64: #define __XOP__ 1
+// CHECK_BDVER2_M64: #define __amd64 1
+// CHECK_BDVER2_M64: #define __amd64__ 1
+// CHECK_BDVER2_M64: #define __bdver2 1
+// CHECK_BDVER2_M64: #define __bdver2__ 1
+// CHECK_BDVER2_M64: #define __tune_bdver2__ 1
+// CHECK_BDVER2_M64: #define __x86_64 1
+// CHECK_BDVER2_M64: #define __x86_64__ 1
//
// End X86/GCC/Linux tests ------------------
diff --git a/test/Preprocessor/predefined-macros.c b/test/Preprocessor/predefined-macros.c
index 2c19301..94671f3 100644
--- a/test/Preprocessor/predefined-macros.c
+++ b/test/Preprocessor/predefined-macros.c
@@ -26,3 +26,21 @@
// RUN: %clang_cc1 %s -E -dM -o - \
// RUN: | FileCheck %s --check-prefix=CHECK-FINITE-MATH-FLAG-UNDEFINED
// CHECK-FINITE-MATH-FLAG-UNDEFINED: #define __FINITE_MATH_ONLY__ 0
+//
+// RUN: %clang_cc1 %s -E -dM -o - -triple i686 -target-cpu i386 \
+// RUN: | FileCheck %s --check-prefix=CHECK-SYNC_CAS_I386
+// CHECK-SYNC_CAS_I386-NOT: __GCC_HAVE_SYNC_COMPARE_AND_SWAP
+//
+// RUN: %clang_cc1 %s -E -dM -o - -triple i686 -target-cpu i486 \
+// RUN: | FileCheck %s --check-prefix=CHECK-SYNC_CAS_I486
+// CHECK-SYNC_CAS_I486: __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1
+// CHECK-SYNC_CAS_I486: __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2
+// CHECK-SYNC_CAS_I486: __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
+// CHECK-SYNC_CAS_I486-NOT: __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8
+//
+// RUN: %clang_cc1 %s -E -dM -o - -triple i686 -target-cpu i586 \
+// RUN: | FileCheck %s --check-prefix=CHECK-SYNC_CAS_I586
+// CHECK-SYNC_CAS_I586: __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1
+// CHECK-SYNC_CAS_I586: __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2
+// CHECK-SYNC_CAS_I586: __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
+// CHECK-SYNC_CAS_I586: __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8
diff --git a/test/Preprocessor/print_line_count.c b/test/Preprocessor/print_line_count.c
index 6a02b0e..6ada93b 100644
--- a/test/Preprocessor/print_line_count.c
+++ b/test/Preprocessor/print_line_count.c
@@ -1,4 +1,7 @@
-/* RUN: %clang -E -C -P %s | wc -l | grep 4
+/* RUN: %clang -E -C -P %s | FileCheck --strict-whitespace %s
PR2741
comment */
y
+// CHECK: {{^}} comment */{{$}}
+// CHECK-NEXT: {{^}}y{{$}}
+
diff --git a/test/Preprocessor/print_line_include.c b/test/Preprocessor/print_line_include.c
new file mode 100644
index 0000000..d65873c
--- /dev/null
+++ b/test/Preprocessor/print_line_include.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -E -P %s | FileCheck %s
+// CHECK: int x;
+// CHECK-NEXT: int x;
+
+#include "print_line_include.h"
+#include "print_line_include.h"
diff --git a/test/Preprocessor/print_line_include.h b/test/Preprocessor/print_line_include.h
new file mode 100644
index 0000000..6d1a0d4
--- /dev/null
+++ b/test/Preprocessor/print_line_include.h
@@ -0,0 +1 @@
+int x;
diff --git a/test/Preprocessor/skipping_unclean.c b/test/Preprocessor/skipping_unclean.c
index 52d1785..ce75b39 100644
--- a/test/Preprocessor/skipping_unclean.c
+++ b/test/Preprocessor/skipping_unclean.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -E %s | grep bark
+// RUN: %clang_cc1 -E %s | FileCheck --strict-whitespace %s
#if 0
blah
@@ -6,4 +6,5 @@ blah
else
bark
#endif
+// CHECK: {{^}}bark{{$}}
diff --git a/test/Preprocessor/stringize_space.c b/test/Preprocessor/stringize_space.c
index 263cff8..2d79d47 100644
--- a/test/Preprocessor/stringize_space.c
+++ b/test/Preprocessor/stringize_space.c
@@ -1,4 +1,14 @@
-// RUN: %clang_cc1 -E %s | grep -- '-"" , - "" , -"" , - ""'
+// RUN: %clang_cc1 -E %s | FileCheck --strict-whitespace %s
#define A(b) -#b , - #b , -# b , - # b
A()
+
+// CHECK: {{^}}-"" , - "" , -"" , - ""{{$}}
+
+
+#define t(x) #x
+t(a
+c)
+
+// CHECK: {{^}}"a c"{{$}}
+
diff --git a/test/Preprocessor/stringize_space2.c b/test/Preprocessor/stringize_space2.c
deleted file mode 100644
index a87d78e..0000000
--- a/test/Preprocessor/stringize_space2.c
+++ /dev/null
@@ -1,6 +0,0 @@
-/* RUN: %clang_cc1 -E %s | grep 'a c'
- */
-#define t(x) #x
-t(a
-c)
-
diff --git a/test/Preprocessor/traditional-cpp.c b/test/Preprocessor/traditional-cpp.c
index 5fc9ee3..4c4633e 100644
--- a/test/Preprocessor/traditional-cpp.c
+++ b/test/Preprocessor/traditional-cpp.c
@@ -4,9 +4,87 @@
/*
RUN: %clang_cc1 -traditional-cpp %s -E -o %t
- RUN: FileCheck < %t %s
+ RUN: FileCheck -strict-whitespace < %t %s
+ RUN: %clang_cc1 -traditional-cpp %s -E -C | FileCheck -check-prefix=CHECK-COMMENTS %s
*/
-/* CHECK: foo // bar
+/* -traditional-cpp should eliminate all C89 comments. */
+/* CHECK-NOT: /*
+ * CHECK-COMMENTS: {{^}}/* -traditional-cpp should eliminate all C89 comments. *{{/$}}
+ */
+
+/* CHECK: {{^}}foo // bar{{$}}
*/
foo // bar
+
+
+/* The lines in this file contain hard tab characters and trailing whitespace;
+ * do not change them! */
+
+/* CHECK: {{^}} indented!{{$}}
+ * CHECK: {{^}}tab separated values{{$}}
+ */
+ indented!
+tab separated values
+
+#define bracket(x) >>>x<<<
+bracket(| spaces |)
+/* CHECK: {{^}}>>>| spaces |<<<{{$}}
+ */
+
+/* This is still a preprocessing directive. */
+# define foo bar
+foo!
+-
+ foo! foo!
+/* CHECK: {{^}}bar!{{$}}
+ * CHECK: {{^}} bar! bar! {{$}}
+ */
+
+/* Deliberately check a leading newline with spaces on that line. */
+
+# define foo bar
+foo!
+-
+ foo! foo!
+/* CHECK: {{^}}bar!{{$}}
+ * CHECK: {{^}} bar! bar! {{$}}
+ */
+
+/* FIXME: -traditional-cpp should not consider this a preprocessing directive
+ * because the # isn't in the first column.
+ */
+ #define foo2 bar
+foo2!
+/* If this were working, both of these checks would be on.
+ * CHECK-NOT: {{^}} #define foo2 bar{{$}}
+ * CHECK-NOT: {{^}}foo2!{{$}}
+ */
+
+/* FIXME: -traditional-cpp should not homogenize whitespace in macros.
+ */
+#define bracket2(x) >>> x <<<
+bracket2(spaces)
+/* If this were working, this check would be on.
+ * CHECK-NOT: {{^}}>>> spaces <<<{{$}}
+ */
+
+
+/* Check that #if 0 blocks work as expected */
+#if 0
+#error "this is not an error"
+
+#if 1
+a b c in skipped block
+#endif
+
+/* Comments are whitespace too */
+
+#endif
+/* CHECK-NOT: {{^}}a b c in skipped block{{$}}
+ * CHECK-NOT: {{^}}/* Comments are whitespace too
+ */
+
+Preserve URLs: http://clang.llvm.org
+/* CHECK: {{^}}Preserve URLs: http://clang.llvm.org{{$}}
+ */
diff --git a/test/Preprocessor/ucn-allowed-chars.c b/test/Preprocessor/ucn-allowed-chars.c
new file mode 100644
index 0000000..d49aa9c
--- /dev/null
+++ b/test/Preprocessor/ucn-allowed-chars.c
@@ -0,0 +1,78 @@
+// RUN: %clang_cc1 %s -fsyntax-only -std=c99 -verify
+// RUN: %clang_cc1 %s -fsyntax-only -std=c11 -Wc99-compat -verify
+// RUN: %clang_cc1 %s -fsyntax-only -x c++ -std=c++03 -Wc++11-compat -verify
+// RUN: %clang_cc1 %s -fsyntax-only -x c++ -std=c++11 -Wc++98-compat -verify
+
+// Identifier characters
+extern char a\u01F6; // C11, C++11
+extern char a\u00AA; // C99, C11, C++11
+extern char a\u0384; // C++03, C11, C++11
+extern char a\u0E50; // C99, C++03, C11, C++11
+extern char a\uFFFF; // none
+
+
+
+
+
+// Identifier initial characters
+extern char \u0E50; // C++03, C11, C++11
+extern char \u0300; // disallowed initially in C11/C++11, always in C99/C++03
+
+
+
+
+
+
+
+
+// Disallowed everywhere
+#define A \u0000 // expected-error{{control character}}
+#define B \u001F // expected-error{{control character}}
+#define C \u007F // expected-error{{control character}}
+#define D \u009F // expected-error{{control character}}
+#define E \uD800 // C++03 allows UCNs representing surrogate characters!
+
+
+
+
+
+
+#if __cplusplus
+# if __cplusplus >= 201103L
+// C++11
+// expected-warning@7 {{using this character in an identifier is incompatible with C++98}}
+// expected-warning@8 {{using this character in an identifier is incompatible with C++98}}
+// expected-error@11 {{expected ';'}}
+// expected-error@19 {{expected unqualified-id}}
+// expected-error@33 {{invalid universal character}}
+
+# else
+// C++03
+// expected-error@7 {{expected ';'}}
+// expected-error@8 {{expected ';'}}
+// expected-error@11 {{expected ';'}}
+// expected-error@19 {{expected unqualified-id}}
+// expected-warning@33 {{universal character name refers to a surrogate character}}
+
+# endif
+#else
+# if __STDC_VERSION__ >= 201112L
+// C11
+// expected-warning@7 {{using this character in an identifier is incompatible with C99}}
+// expected-warning@9 {{using this character in an identifier is incompatible with C99}}
+// expected-error@11 {{expected ';'}}
+// expected-warning@18 {{starting an identifier with this character is incompatible with C99}}
+// expected-error@19 {{expected identifier}}
+// expected-error@33 {{invalid universal character}}
+
+# else
+// C99
+// expected-error@7 {{expected ';'}}
+// expected-error@9 {{expected ';'}}
+// expected-error@11 {{expected ';'}}
+// expected-error@18 {{expected identifier}}
+// expected-error@19 {{expected identifier}}
+// expected-error@33 {{invalid universal character}}
+
+# endif
+#endif
diff --git a/test/Preprocessor/ucn-pp-identifier.c b/test/Preprocessor/ucn-pp-identifier.c
new file mode 100644
index 0000000..8616d40
--- /dev/null
+++ b/test/Preprocessor/ucn-pp-identifier.c
@@ -0,0 +1,106 @@
+// RUN: %clang_cc1 %s -fsyntax-only -std=c99 -pedantic -verify -Wundef
+// RUN: %clang_cc1 %s -fsyntax-only -x c++ -pedantic -verify -Wundef
+// RUN: %clang_cc1 %s -fsyntax-only -std=c99 -pedantic -Wundef 2>&1 | FileCheck -strict-whitespace %s
+
+#define \u00FC
+#define a\u00FD() 0
+#ifndef \u00FC
+#error "This should never happen"
+#endif
+
+#if a\u00FD()
+#error "This should never happen"
+#endif
+
+#if a\U000000FD()
+#error "This should never happen"
+#endif
+
+#if \uarecool // expected-warning{{incomplete universal character name; treating as '\' followed by identifier}} expected-error {{invalid token at start of a preprocessor expression}}
+#endif
+#if \uwerecool // expected-warning{{\u used with no following hex digits; treating as '\' followed by identifier}} expected-error {{invalid token at start of a preprocessor expression}}
+#endif
+#if \U0001000 // expected-warning{{incomplete universal character name; treating as '\' followed by identifier}} expected-error {{invalid token at start of a preprocessor expression}}
+#endif
+
+// Make sure we reject disallowed UCNs
+#define \ufffe // expected-error {{macro names must be identifiers}}
+#define \U10000000 // expected-error {{macro names must be identifiers}}
+#define \u0061 // expected-error {{character 'a' cannot be specified by a universal character name}} expected-error {{macro names must be identifiers}}
+
+// FIXME: Not clear what our behavior should be here; \u0024 is "$".
+#define a\u0024 // expected-warning {{whitespace}}
+
+#if \u0110 // expected-warning {{is not defined, evaluates to 0}}
+#endif
+
+
+#define \u0110 1 / 0
+#if \u0110 // expected-error {{division by zero in preprocessor expression}}
+#endif
+
+#define STRINGIZE(X) # X
+
+extern int check_size[sizeof(STRINGIZE(\u0112)) == 3 ? 1 : -1];
+
+// Check that we still diagnose disallowed UCNs in #if 0 blocks.
+// C99 5.1.1.2p1 and C++11 [lex.phases]p1 dictate that preprocessor tokens are
+// formed before directives are parsed.
+// expected-error@+4 {{character 'a' cannot be specified by a universal character name}}
+#if 0
+#define \ufffe // okay
+#define \U10000000 // okay
+#define \u0061 // error, but -verify only looks at comments outside #if 0
+#endif
+
+
+// A UCN formed by token pasting is undefined in both C99 and C++.
+// Right now we don't do anything special, which causes us to coincidentally
+// accept the first case below but reject the second two.
+#define PASTE(A, B) A ## B
+extern int PASTE(\, u00FD);
+extern int PASTE(\u, 00FD); // expected-warning{{\u used with no following hex digits}}
+extern int PASTE(\u0, 0FD); // expected-warning{{incomplete universal character name}}
+#ifdef __cplusplus
+// expected-error@-3 {{expected unqualified-id}}
+// expected-error@-3 {{expected unqualified-id}}
+#else
+// expected-error@-6 {{expected identifier}}
+// expected-error@-6 {{expected identifier}}
+#endif
+
+
+// A UCN produced by line splicing is valid in C99 but undefined in C++.
+// Since undefined behavior can do anything including working as intended,
+// we just accept it in C++ as well.;
+#define newline_1_\u00F\
+C 1
+#define newline_2_\u00\
+F\
+C 1
+#define newline_3_\u\
+00\
+FC 1
+#define newline_4_\\
+u00FC 1
+#define newline_5_\\
+u\
+\
+0\
+0\
+F\
+C 1
+
+#if (newline_1_\u00FC && newline_2_\u00FC && newline_3_\u00FC && \
+ newline_4_\u00FC && newline_5_\u00FC)
+#else
+#error "Line splicing failed to produce UCNs"
+#endif
+
+
+#define capital_u_\U00FC
+// expected-warning@-1 {{incomplete universal character name}} expected-note@-1 {{did you mean to use '\u'?}} expected-warning@-1 {{whitespace}}
+// CHECK: note: did you mean to use '\u'?
+// CHECK-NEXT: #define capital_u_\U00FC
+// CHECK-NEXT: {{^ \^}}
+// CHECK-NEXT: {{^ u}}
diff --git a/test/Preprocessor/utf8-allowed-chars.c b/test/Preprocessor/utf8-allowed-chars.c
new file mode 100644
index 0000000..b10ca74
--- /dev/null
+++ b/test/Preprocessor/utf8-allowed-chars.c
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 %s -fsyntax-only -std=c99 -verify
+// RUN: %clang_cc1 %s -fsyntax-only -std=c11 -Wc99-compat -verify
+// RUN: %clang_cc1 %s -fsyntax-only -x c++ -std=c++03 -Wc++11-compat -verify
+// RUN: %clang_cc1 %s -fsyntax-only -x c++ -std=c++11 -Wc++98-compat -verify
+
+// Note: This file contains Unicode characters; please do not remove them!
+
+// Identifier characters
+extern char aǶ; // C11, C++11
+extern char aª; // C99, C11, C++11
+extern char a΄; // C++03, C11, C++11
+extern char aà¹; // C99, C++03, C11, C++11
+extern char aï¹…; // none
+extern char x̀; // C11, C++11. Note that this does not have a composed form.
+
+
+
+
+// Identifier initial characters
+extern char à¹; // C++03, C11, C++11
+extern char ̀; // disallowed initially in C11/C++11, always in C99/C++03
+
+
+
+
+
+
+
+
+#if __cplusplus
+# if __cplusplus >= 201103L
+// C++11
+// expected-warning@9 {{using this character in an identifier is incompatible with C++98}}
+// expected-warning@10 {{using this character in an identifier is incompatible with C++98}}
+// expected-error@13 {{non-ASCII characters are not allowed outside of literals and identifiers}}
+// expected-warning@14 {{using this character in an identifier is incompatible with C++98}}
+// expected-error@21 {{expected unqualified-id}}
+
+# else
+// C++03
+// expected-error@9 {{non-ASCII characters are not allowed outside of literals and identifiers}}
+// expected-error@10 {{non-ASCII characters are not allowed outside of literals and identifiers}}
+// expected-error@13 {{non-ASCII characters are not allowed outside of literals and identifiers}}
+// expected-error@14 {{non-ASCII characters are not allowed outside of literals and identifiers}}
+// expected-error@21 {{non-ASCII characters are not allowed outside of literals and identifiers}} expected-warning@21 {{declaration does not declare anything}}
+
+# endif
+#else
+# if __STDC_VERSION__ >= 201112L
+// C11
+// expected-warning@9 {{using this character in an identifier is incompatible with C99}}
+// expected-warning@11 {{using this character in an identifier is incompatible with C99}}
+// expected-error@13 {{non-ASCII characters are not allowed outside of literals and identifiers}}
+// expected-warning@14 {{using this character in an identifier is incompatible with C99}}
+// expected-warning@20 {{starting an identifier with this character is incompatible with C99}}
+// expected-error@21 {{expected identifier}}
+
+# else
+// C99
+// expected-error@9 {{non-ASCII characters are not allowed outside of literals and identifiers}}
+// expected-error@11 {{non-ASCII characters are not allowed outside of literals and identifiers}}
+// expected-error@13 {{non-ASCII characters are not allowed outside of literals and identifiers}}
+// expected-error@14 {{non-ASCII characters are not allowed outside of literals and identifiers}}
+// expected-error@20 {{expected identifier}}
+// expected-error@21 {{non-ASCII characters are not allowed outside of literals and identifiers}} expected-warning@21 {{declaration does not declare anything}}
+
+# endif
+#endif
diff --git a/test/Preprocessor/warn-disabled-macro-expansion.c b/test/Preprocessor/warn-disabled-macro-expansion.c
index fe8e90c..21a3b7e 100644
--- a/test/Preprocessor/warn-disabled-macro-expansion.c
+++ b/test/Preprocessor/warn-disabled-macro-expansion.c
@@ -14,7 +14,10 @@
#define c(x) x(0)
-p // expected-warning {{recursive macro}}
+#define y(x) y
+#define z(x) (z)(x)
+
+p // no warning
a // expected-warning {{recursive macro}}
@@ -25,3 +28,8 @@ g(3) // expected-warning {{recursive macro}}
h(0) // expected-warning {{recursive macro}}
c(c) // expected-warning {{recursive macro}}
+
+y(5) // expected-warning {{recursive macro}}
+
+z(z) // ok
+
diff --git a/test/Preprocessor/warning_tests.c b/test/Preprocessor/warning_tests.c
index 3f2865c..c0c22ef 100644
--- a/test/Preprocessor/warning_tests.c
+++ b/test/Preprocessor/warning_tests.c
@@ -11,7 +11,9 @@
#warning Should have -Wparentheses
#endif
-#if __has_warning(-Wfoo) // expected-error {{builtin warning check macro requires a parenthesized string}}
+// expected-error@+2 {{expected string literal in '__has_warning'}}
+// expected-error@+1 {{expected value in expression}}
+#if __has_warning(-Wfoo)
#endif
// expected-warning@+3 {{Not a valid warning flag}}
@@ -19,3 +21,26 @@
#else
#warning Not a valid warning flag
#endif
+
+// expected-error@+2 {{builtin warning check macro requires a parenthesized string}}
+// expected-error@+1 {{invalid token}}
+#if __has_warning "not valid"
+#endif
+
+// Macro expansion does not occur in the parameter to __has_warning
+// (as is also expected behaviour for ordinary macros), so the
+// following should not expand:
+
+#define MY_ALIAS "-Wparentheses"
+
+// expected-error@+1 2{{expected}}
+#if __has_warning(MY_ALIAS)
+#error Alias expansion not allowed
+#endif
+
+// But deferring should expand:
+#define HAS_WARNING(X) __has_warning(X)
+
+#if !HAS_WARNING(MY_ALIAS)
+#error Expansion should have occurred
+#endif
diff --git a/test/Rewriter/line-generation-test.m b/test/Rewriter/line-generation-test.m
new file mode 100644
index 0000000..dad7371
--- /dev/null
+++ b/test/Rewriter/line-generation-test.m
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 -E %s -o %t.mm
+// RUN: %clang_cc1 -fms-extensions -rewrite-objc -g %t.mm -o %t-rw.cpp
+// RUN: FileCheck -check-prefix LINE --input-file=%t-rw.cpp %s
+// RUN: %clang_cc1 -fms-extensions -rewrite-objc %t.mm -o %t-rwnog.cpp
+// RUN: FileCheck -check-prefix NOLINE --input-file=%t-rwnog.cpp %s
+// rdar://13138170
+
+__attribute__((objc_root_class)) @interface MyObject {
+@public
+ id _myMaster;
+ id _isTickledPink;
+}
+@property(retain) id myMaster;
+@property(assign) id isTickledPink;
+@end
+
+@implementation MyObject
+
+@synthesize myMaster = _myMaster;
+@synthesize isTickledPink = _isTickledPink;
+
+- (void) doSomething {
+ _myMaster = _isTickledPink;
+}
+
+@end
+
+MyObject * foo ()
+{
+ MyObject* p;
+ p.isTickledPink = p.myMaster; // ok
+ p->_isTickledPink = p->_myMaster;
+ return p->_isTickledPink;
+}
+
+// CHECK-LINE: #line 22
+// CHECK-LINE: #line 28
+// CHECK-NOLINE-NOT: #line 22
+// CHECK-NOLINE-NOT: #line 28
+
diff --git a/test/Rewriter/modern-write-bf-abi.mm b/test/Rewriter/modern-write-bf-abi.mm
new file mode 100644
index 0000000..85db939
--- /dev/null
+++ b/test/Rewriter/modern-write-bf-abi.mm
@@ -0,0 +1,120 @@
+// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fms-extensions -rewrite-objc %s -o %t-modern-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-modern-rw.cpp
+// rdar://13138459
+
+// -Did="void*" -DSEL="void *" -DClass="void*"
+@interface NSMutableArray {
+ id isa;
+}
+@end
+
+typedef unsigned char BOOL;
+typedef unsigned long NSUInteger;
+
+__attribute__((visibility("hidden")))
+@interface __NSArrayM : NSMutableArray {
+ NSUInteger _used;
+ NSUInteger _doHardRetain:1;
+ NSUInteger _doWeakAccess:1;
+#if __LP64__
+ NSUInteger _size:62;
+#else
+ NSUInteger _size:30;
+#endif
+ NSUInteger _hasObjects:1;
+ NSUInteger _hasStrongReferences:1;
+#if __LP64__
+ NSUInteger _offset:62;
+#else
+ NSUInteger _offset:30;
+#endif
+ unsigned long _mutations;
+ id *_list;
+}
+@end
+
+
+id __CFAllocateObject2();
+BOOL objc_collectingEnabled();
+
+@implementation __NSArrayM
++ (id)__new:(const id [])objects :(NSUInteger)count :(BOOL)hasObjects :(BOOL)hasStrong :(BOOL)transferRetain {
+ __NSArrayM *newArray = (__NSArrayM *)__CFAllocateObject2();
+ newArray->_size = count;
+ newArray->_mutations = 1;
+ newArray->_doHardRetain = (hasObjects && hasStrong);
+ newArray->_doWeakAccess = (objc_collectingEnabled() && !hasStrong);
+ newArray->_hasObjects = hasObjects;
+ newArray->_hasStrongReferences = hasStrong;
+ newArray->_list = 0;
+ return *newArray->_list;
+}
+@end
+
+// Test2
+@interface Super {
+ int ivar_super_a : 5;
+}
+@end
+
+@interface A : Super {
+@public
+ int ivar_a : 5;
+}
+@end
+
+int f0(A *a) {
+ return a->ivar_a;
+}
+
+@interface A () {
+@public
+ int ivar_ext_a : 5;
+ int ivar_ext_b : 5;
+}@end
+
+int f1(A *a) {
+ return a->ivar_ext_a + a->ivar_a;
+}
+
+@interface A () {
+@public
+ int ivar_ext2_a : 5;
+ int ivar_ext2_b : 5;
+}@end
+
+int f2(A* a) {
+ return a->ivar_ext2_a + a->ivar_ext_a + a->ivar_a;
+}
+
+@implementation A {
+@public
+ int ivar_b : 5;
+ int ivar_c : 5;
+ int ivar_d : 5;
+}
+@end
+
+int f3(A *a) {
+ return a->ivar_d + a->ivar_ext2_a + a->ivar_ext_a + a->ivar_a;
+}
+
+__attribute__((objc_root_class)) @interface Base
+{
+ struct objc_class *isa;
+ int full;
+ int full2: 32;
+ int _refs: 8;
+ int field2: 3;
+ unsigned f3: 8;
+ short cc;
+ unsigned g: 16;
+ int r2: 8;
+ int r3: 8;
+ int r4: 2;
+ int r5: 8;
+ char c;
+}
+@end
+
+@implementation Base @end
diff --git a/test/Rewriter/objc-modern-property-bitfield.m b/test/Rewriter/objc-modern-property-bitfield.m
new file mode 100644
index 0000000..583fa37
--- /dev/null
+++ b/test/Rewriter/objc-modern-property-bitfield.m
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fms-extensions -rewrite-objc %s -o %t-modern-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D"Class=void*" -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-modern-rw.cpp
+// rdar://13138459
+
+void *sel_registerName(const char *);
+extern void abort();
+
+@interface NSObject
++ alloc;
+- init;
+@end
+
+typedef unsigned char BOOL;
+
+@interface Foo : NSObject {
+
+ BOOL _field1 : 5;
+ BOOL _field2 : 3;
+}
+
+@property BOOL field1;
+@property BOOL field2;
+@end
+
+@implementation Foo
+
+@synthesize field1 = _field1;
+@synthesize field2 = _field2;
+
+@end
+
+int main()
+{
+ Foo *f = (Foo*)[[Foo alloc] init];
+ f.field1 = 0xF;
+ f.field2 = 0x3;
+ f.field1 = f.field1 & f.field2;
+ if (f.field1 != 0x3)
+ abort ();
+ return 0;
+}
+
+
diff --git a/test/Rewriter/rewrite-line-directive.m b/test/Rewriter/rewrite-line-directive.m
new file mode 100644
index 0000000..5c4e957
--- /dev/null
+++ b/test/Rewriter/rewrite-line-directive.m
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -E %s -o %t.mm
+// RUN: %clang -fms-extensions -rewrite-objc %t.mm -o %t-rw.cpp
+// RUN: FileCheck -check-prefix LP --input-file=%t-rw.cpp %s
+// RUN: %clang -g -fms-extensions -rewrite-objc %t.mm -o %t-rw.cpp
+// RUN: FileCheck -check-prefix LPG --input-file=%t-rw.cpp %s
+// rdar://13138170
+
+int z();
+
+int x() {
+ id foo;
+ for (id y in foo) {
+ z();
+ }
+ return 0;
+}
+// CHECK-LP-NOT: #line
+// CHECK-LPG: #line
diff --git a/test/Rewriter/rewrite-modern-qualified-type.mm b/test/Rewriter/rewrite-modern-qualified-type.mm
new file mode 100644
index 0000000..53e0d23
--- /dev/null
+++ b/test/Rewriter/rewrite-modern-qualified-type.mm
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -x objective-c++ -Wno-return-type -fms-extensions -rewrite-objc %s -o %t-modern-rw.cpp
+// RUN: %clang_cc1 -fsyntax-only -Wno-address-of-temporary -D_Bool=bool -D"id=void*" -D"SEL=void*" -D"__declspec(X)=" %t-modern-rw.cpp
+// rdar://13562505
+
+@protocol OS_dispatch_object @end
+
+@interface NSObject @end
+
+@protocol OS_dispatch_queue <OS_dispatch_object> @end typedef NSObject<OS_dispatch_queue> *dispatch_queue_t;
+
+typedef id<OS_dispatch_queue> dispatch_queue_i;
diff --git a/test/Rewriter/rewrite-modern-throw.m b/test/Rewriter/rewrite-modern-throw.m
index 1912384..1564611 100644
--- a/test/Rewriter/rewrite-modern-throw.m
+++ b/test/Rewriter/rewrite-modern-throw.m
@@ -65,3 +65,29 @@ int main()
}
}
@end
+
+// rdar://13186010
+@class NSDictionary, NSException;
+@class NSMutableDictionary;
+
+@interface NSString
++ (id)stringWithFormat:(NSString *)format, ... ;
+@end
+
+@interface NSException
++ (NSException *)exceptionWithName:(NSString *)name reason:(NSString *)reason userInfo:(NSDictionary *)userInfo;
+@end
+id *_imp__NSInvalidArgumentException;
+
+@interface NSSetExpression @end
+
+@implementation NSSetExpression
+-(id)expressionValueWithObject:(id)object context:(NSMutableDictionary*)bindings {
+ id leftSet;
+ id rightSet;
+ @throw [NSException exceptionWithName: *_imp__NSInvalidArgumentException reason: [NSString stringWithFormat: @"Can't evaluate set expression; left subexpression not a set (lhs = %@ rhs = %@)", leftSet, rightSet] userInfo: 0];
+
+ return leftSet ;
+}
+@end
+
diff --git a/test/Rewriter/unnamed-bf-modern-write.mm b/test/Rewriter/unnamed-bf-modern-write.mm
index 892382f..209cdd6 100644
--- a/test/Rewriter/unnamed-bf-modern-write.mm
+++ b/test/Rewriter/unnamed-bf-modern-write.mm
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -E %s -o %t.mm
// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %t.mm -o - | FileCheck %s
+// rdar://13138459
@interface Foo {
@private
@@ -13,11 +14,14 @@
@implementation Foo
@end
+// CHECK: struct Foo__T_1 {
+// CHECK-NEXT: int : 1;
+// CHECK-NEXT: int third : 1;
+// CHECK-NEXT: int : 1;
+// CHECK-NEXT: int fifth : 1;
+// CHECK-NEXT: char : 0;
+// CHECK-NEXT: } ;
// CHECK: struct Foo_IMPL {
-// CHECK-NEXT: int first;
-// CHECK-NEXT: int : 1;
-// CHECK-NEXT: int third : 1;
-// CHECK-NEXT: int : 1;
-// CHECK-NEXT: int fifth : 1;
-// CHECK-NEXT: char : 0;
+// CHECK-NEXT: int first;
+// CHECK-NEXT: struct Foo__T_1 Foo__GRBF_1;
// CHECK-NEXT: };
diff --git a/test/Sema/128bitint.c b/test/Sema/128bitint.c
index 600c25a..bb8e3d1 100644
--- a/test/Sema/128bitint.c
+++ b/test/Sema/128bitint.c
@@ -1,9 +1,13 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-apple-darwin9 -fms-extensions %s
+// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-apple-darwin9 -fms-extensions %s -DHAVE
+// RUN: %clang_cc1 -fsyntax-only -verify -triple i686-linux-gnu -fms-extensions %s -DHAVE_NOT
+
+#ifdef HAVE
typedef int i128 __attribute__((__mode__(TI)));
typedef unsigned u128 __attribute__((__mode__(TI)));
int a[((i128)-1 ^ (i128)-2) == 1 ? 1 : -1];
int a[(u128)-1 > 1LL ? 1 : -1];
+int a[__SIZEOF_INT128__ == 16 ? 1 : -1];
// PR5435
__uint128_t b = (__uint128_t)-1;
@@ -36,4 +40,12 @@ void test(int *buf)
{
MPI_Send(buf, 0x10000000000000001i128); // expected-warning {{implicit conversion from '__int128' to 'int' changes value}}
}
+#else
+
+__int128 n; // expected-error {{__int128 is not supported on this target}}
+
+#if defined(__SIZEOF_INT128__)
+#error __SIZEOF_INT128__ should not be defined
+#endif
+#endif
diff --git a/test/Sema/address_spaces.c b/test/Sema/address_spaces.c
index 24799da..0ae3230 100644
--- a/test/Sema/address_spaces.c
+++ b/test/Sema/address_spaces.c
@@ -6,7 +6,7 @@
void bar(_AS2 int a); // expected-error {{parameter may not be qualified with an address space}}
-void foo(_AS3 float *a,
+void foo(_AS3 float *a,
_AS1 float b) // expected-error {{parameter may not be qualified with an address space}}
{
_AS2 *x;// expected-warning {{type specifier missing, defaults to 'int'}}
@@ -48,3 +48,20 @@ void test3(void) {
typedef void ft(void);
_AS1 ft qf; // expected-error {{function type may not be qualified with an address space}}
typedef _AS1 ft qft; // expected-error {{function type may not be qualified with an address space}}
+
+
+typedef _AS2 int AS2Int;
+
+struct HasASFields
+{
+ _AS2 int as_field; // expected-error {{field may not be qualified with an address space}}
+ AS2Int typedef_as_field; // expected-error {{field may not be qualified with an address space}}
+};
+
+// Assertion failure was when the field was accessed
+void access_as_field()
+{
+ struct HasASFields x;
+ (void) bar.as_field;
+}
+
diff --git a/test/Sema/alignas.c b/test/Sema/alignas.c
index d9a0164..020eff6 100644
--- a/test/Sema/alignas.c
+++ b/test/Sema/alignas.c
@@ -1,20 +1,29 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c11 -Dalignof=__alignof %s
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c11 -Dalignof=_Alignof %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c11 -Dalignof=_Alignof -DUSING_C11_SYNTAX %s
_Alignas(3) int align_illegal; //expected-error {{requested alignment is not a power of 2}}
_Alignas(int) char align_big;
-_Alignas(1) int align_small; // FIXME: this should be rejected
+_Alignas(1) int align_small; // expected-error {{requested alignment is less than minimum}}
_Alignas(1) unsigned _Alignas(8) int _Alignas(1) align_multiple;
struct align_member {
_Alignas(8) int member;
+ _Alignas(1) char bitfield : 1; // expected-error {{'_Alignas' attribute cannot be applied to a bit-field}}
};
-typedef _Alignas(8) char align_typedef; // FIXME: this should be rejected
+typedef _Alignas(8) char align_typedef; // expected-error {{'_Alignas' attribute only applies to variables and fields}}
+void f(_Alignas(1) char c) { // expected-error {{'_Alignas' attribute cannot be applied to a function parameter}}
+ _Alignas(1) register char k; // expected-error {{'_Alignas' attribute cannot be applied to a variable with 'register' storage class}}
+}
+
+#ifdef USING_C11_SYNTAX
+// expected-warning@+4{{'_Alignof' applied to an expression is a GNU extension}}
+// expected-warning@+4{{'_Alignof' applied to an expression is a GNU extension}}
+// expected-warning@+4{{'_Alignof' applied to an expression is a GNU extension}}
+#endif
_Static_assert(alignof(align_big) == alignof(int), "k's alignment is wrong");
_Static_assert(alignof(align_small) == 1, "j's alignment is wrong");
_Static_assert(alignof(align_multiple) == 8, "l's alignment is wrong");
_Static_assert(alignof(struct align_member) == 8, "quuux's alignment is wrong");
_Static_assert(sizeof(struct align_member) == 8, "quuux's size is wrong");
-_Static_assert(alignof(align_typedef) == 8, "typedef's alignment is wrong");
diff --git a/test/Sema/alloc_size.c b/test/Sema/alloc_size.c
index e2f5298..84f3932 100644
--- a/test/Sema/alloc_size.c
+++ b/test/Sema/alloc_size.c
@@ -23,4 +23,5 @@ void* fn9(unsigned) __attribute__((alloc_size(12345678901234567890123))); // exp
void* fn10(size_t, size_t) __attribute__((alloc_size(1,2))); // expected-error{{redefinition of parameter}} \
// expected-error{{a parameter list without types is only allowed in a function definition}} \
- // expected-warning{{alloc_size attribute only applies to functions and methods}}
+ // expected-error{{attribute parameter 1 is out of bounds}}
+void* fn11() __attribute__((alloc_size(1))); // expected-error{{attribute parameter 1 is out of bounds}}
diff --git a/test/Sema/anonymous-struct-union.c b/test/Sema/anonymous-struct-union.c
index e082290..35d3175 100644
--- a/test/Sema/anonymous-struct-union.c
+++ b/test/Sema/anonymous-struct-union.c
@@ -78,7 +78,7 @@ void g() {
struct s0 { union { int f0; }; };
// <rdar://problem/6481130>
-typedef struct { }; // expected-warning{{declaration does not declare anything}}
+typedef struct { }; // expected-warning{{typedef requires a name}}
// PR3675
struct s1 {
diff --git a/test/Sema/asm.c b/test/Sema/asm.c
index 155d736..2c60085 100644
--- a/test/Sema/asm.c
+++ b/test/Sema/asm.c
@@ -123,3 +123,10 @@ void test13(void) {
void *esp;
__asm__ volatile ("mov %%esp, %o" : "=r"(esp) : : ); // expected-error {{invalid % escape in inline assembly string}}
}
+
+// <rdar://problem/12700799>
+struct S; // expected-note 2 {{forward declaration of 'struct S'}}
+void test14(struct S *s) {
+ __asm("": : "a"(*s)); // expected-error {{dereference of pointer to incomplete type 'struct S'}}
+ __asm("": "=a" (*s) :); // expected-error {{dereference of pointer to incomplete type 'struct S'}}
+}
diff --git a/test/Sema/ast-print.c b/test/Sema/ast-print.c
index ff66d35..2066e18 100644
--- a/test/Sema/ast-print.c
+++ b/test/Sema/ast-print.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -ast-print
+// RUN: %clang_cc1 %s -ast-print | FileCheck %s
typedef void func_typedef();
func_typedef xxx;
@@ -6,3 +6,15 @@ func_typedef xxx;
typedef void func_t(int x);
func_t a;
+struct blah {
+ struct {
+ struct {
+ int b;
+ };
+ };
+};
+
+int foo(const struct blah *b) {
+ // CHECK: return b->b;
+ return b->b;
+}
diff --git a/test/Sema/atomic-ops.c b/test/Sema/atomic-ops.c
index 2a93591..b3daa07 100644
--- a/test/Sema/atomic-ops.c
+++ b/test/Sema/atomic-ops.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 %s -verify -fsyntax-only -triple=i686-linux-gnu -std=c11
+// RUN: %clang_cc1 %s -verify -fsyntax-only -triple=aarch64-linux-gnu -std=c11
// Basic parsing/Sema tests for __c11_atomic_*
@@ -17,7 +18,11 @@ _Static_assert(__GCC_ATOMIC_WCHAR_T_LOCK_FREE == 2, "");
_Static_assert(__GCC_ATOMIC_SHORT_LOCK_FREE == 2, "");
_Static_assert(__GCC_ATOMIC_INT_LOCK_FREE == 2, "");
_Static_assert(__GCC_ATOMIC_LONG_LOCK_FREE == 2, "");
+#ifdef __i386__
_Static_assert(__GCC_ATOMIC_LLONG_LOCK_FREE == 1, "");
+#else
+_Static_assert(__GCC_ATOMIC_LLONG_LOCK_FREE == 2, "");
+#endif
_Static_assert(__GCC_ATOMIC_POINTER_LOCK_FREE == 2, "");
_Static_assert(__c11_atomic_is_lock_free(1), "");
@@ -168,3 +173,6 @@ void f(_Atomic(int) *i, _Atomic(int*) *p, _Atomic(float) *d,
__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)}}
}
+
+_Atomic(int*) PR12527_a;
+void PR12527() { int *b = PR12527_a; }
diff --git a/test/Sema/attr-availability.c b/test/Sema/attr-availability.c
index e0c541e..ac6a187 100644
--- a/test/Sema/attr-availability.c
+++ b/test/Sema/attr-availability.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fsyntax-only -fblocks -verify %s
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}}
@@ -43,3 +43,14 @@ void f7(int) __attribute__((availability(ios,deprecated=4.0))); // expected-warn
#if !__has_feature(attribute_availability_with_message)
# error "Missing __has_feature"
#endif
+
+extern int x __attribute__((availability(macosx,introduced=10.5)));
+extern int x;
+
+void f8() {
+ int (^b)(int);
+ b = ^ (int i) __attribute__((availability(macosx,introduced=10.2))) { return 1; }; // expected-warning {{'availability' attribute ignored}}
+}
+
+extern int x2 __attribute__((availability(macosx,introduced=10.2))); // expected-note {{previous attribute is here}}
+extern int x2 __attribute__((availability(macosx,introduced=10.5))); // expected-warning {{availability does not match previous declaration}}
diff --git a/test/Sema/attr-cleanup.c b/test/Sema/attr-cleanup.c
index 59ebbfc..991822e 100644
--- a/test/Sema/attr-cleanup.c
+++ b/test/Sema/attr-cleanup.c
@@ -38,3 +38,7 @@ void t4() {
__attribute((cleanup(c4))) void* g;
}
+void c5(void*) __attribute__((deprecated)); // expected-note{{'c5' declared here}}
+void t5() {
+ int i __attribute__((cleanup(c5))); // expected-warning {{'c5' is deprecated}}
+}
diff --git a/test/Sema/attr-mode.c b/test/Sema/attr-mode.c
index 0c53362..a89c839 100644
--- a/test/Sema/attr-mode.c
+++ b/test/Sema/attr-mode.c
@@ -17,6 +17,8 @@ typedef int invalid_3 __attribute((mode(II))); // expected-error{{unknown machin
typedef struct {int i,j,k;} invalid_4 __attribute((mode(SI))); // expected-error{{mode attribute only supported for integer and floating-point types}}
typedef float invalid_5 __attribute((mode(SI))); // expected-error{{type of machine mode does not match type of base type}}
+typedef unsigned unwind_word __attribute((mode(unwind_word)));
+
int **__attribute((mode(QI)))* i32; // expected-error{{mode attribute}}
typedef _Complex double c32 __attribute((mode(SC)));
diff --git a/test/Sema/attr-print.c b/test/Sema/attr-print.c
new file mode 100644
index 0000000..2659508
--- /dev/null
+++ b/test/Sema/attr-print.c
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 %s -ast-print -fms-extensions | FileCheck %s
+
+// CHECK: int x __attribute__((aligned(4)));
+int x __attribute__((aligned(4)));
+
+// FIXME: Print this at a valid location for a __declspec attr.
+// CHECK: int y __declspec(align(4));
+__declspec(align(4)) int y;
+
+// CHECK: void foo() __attribute__((const));
+void foo() __attribute__((const));
+
+// CHECK: void bar() __attribute__((__const));
+void bar() __attribute__((__const));
+
+// FIXME: Print these at a valid location for these attributes.
+// CHECK: int *p32 __ptr32;
+int * __ptr32 p32;
+
+// CHECK: int *p64 __ptr64;
+int * __ptr64 p64;
diff --git a/test/Sema/attr-regparm.c b/test/Sema/attr-regparm.c
index 642c07e..ccd894e 100644
--- a/test/Sema/attr-regparm.c
+++ b/test/Sema/attr-regparm.c
@@ -8,4 +8,4 @@ __attribute((regparm(5,3))) int x4(void); // expected-error{{attribute takes one
void __attribute__((regparm(3))) x5(int);
void x5(int); // expected-note{{previous declaration is here}}
-void __attribute__((regparm(2))) x5(int); // expected-error{{function declared with with regparm(2) attribute was previously declared with the regparm(3) attribute}}
+void __attribute__((regparm(2))) x5(int); // expected-error{{function declared with regparm(2) attribute was previously declared with the regparm(3) attribute}}
diff --git a/test/Sema/attr-used.c b/test/Sema/attr-used.c
index e2dfab1..accc7b6 100644
--- a/test/Sema/attr-used.c
+++ b/test/Sema/attr-used.c
@@ -17,4 +17,4 @@ void f1() {
int b __attribute__((used)); // expected-warning {{used attribute ignored}}
}
-
+static void __attribute__((used)) f0(void);
diff --git a/test/Sema/attr-visibility.c b/test/Sema/attr-visibility.c
index 77bc39c..7f7fd54 100644
--- a/test/Sema/attr-visibility.c
+++ b/test/Sema/attr-visibility.c
@@ -21,4 +21,6 @@ void test6() __attribute__((visibility("hidden"), // expected-note {{previous at
extern int test7 __attribute__((visibility("default"))); // expected-note {{previous attribute is here}}
extern int test7 __attribute__((visibility("hidden"))); // expected-error {{visibility does not match previous declaration}}
-typedef int __attribute__((visibility("default"))) bar; // expected-warning {{visibility attribute ignored}}
+typedef int __attribute__((visibility("default"))) bar; // expected-warning {{'visibility' attribute ignored}}
+
+int x __attribute__((type_visibility("default"))); // expected-error {{'type_visibility' attribute only applies to types and namespaces}}
diff --git a/test/Sema/attr-weak.c b/test/Sema/attr-weak.c
index adedf12..df74554 100644
--- a/test/Sema/attr-weak.c
+++ b/test/Sema/attr-weak.c
@@ -16,3 +16,9 @@ static int x __attribute__((weak)); // expected-error {{weak declaration cannot
// rdar://9538608
int C; // expected-note {{previous definition is here}}
extern int C __attribute__((weak_import)); // expected-warning {{an already-declared variable is made a weak_import declaration}}
+
+static int pr14946_x;
+extern int pr14946_x __attribute__((weak)); // expected-error {{weak declaration cannot have internal linkage}}
+
+static void pr14946_f();
+void pr14946_f() __attribute__((weak)); // expected-error {{weak declaration cannot have internal linkage}}
diff --git a/test/Sema/block-return.c b/test/Sema/block-return.c
index 2ea4d81..6b4d998 100644
--- a/test/Sema/block-return.c
+++ b/test/Sema/block-return.c
@@ -134,3 +134,14 @@ void foo7()
void (^blk)(void) = ^{
return (void)0; // expected-warning {{void block literal should not return void expression}}
};
+
+// rdar://13463504
+enum Test8 { T8_a, T8_b, T8_c };
+void test8(void) {
+ extern void test8_helper(int (^)(int));
+ test8_helper(^(int flag) { if (flag) return T8_a; return T8_b; });
+}
+void test8b(void) {
+ extern void test8_helper2(char (^)(int)); // expected-note {{here}}
+ test8_helper2(^(int flag) { if (flag) return T8_a; return T8_b; }); // expected-error {{passing 'enum Test8 (^)(int)' to parameter of type 'char (^)(int)'}}
+}
diff --git a/test/Sema/builtins.c b/test/Sema/builtins.c
index e3b3b7e..d525ac0 100644
--- a/test/Sema/builtins.c
+++ b/test/Sema/builtins.c
@@ -176,3 +176,18 @@ void test17() {
#undef T
#undef F
}
+
+void test18() {
+ char src[1024];
+ char dst[2048];
+ size_t result;
+ void *ptr;
+
+ ptr = __builtin___memccpy_chk(dst, src, '\037', sizeof(src), sizeof(dst));
+ result = __builtin___strlcpy_chk(dst, src, sizeof(src), sizeof(dst));
+ result = __builtin___strlcat_chk(dst, src, sizeof(src), sizeof(dst));
+
+ ptr = __builtin___memccpy_chk(dst, src, '\037', sizeof(src)); // expected-error {{too few arguments to function call}}
+ ptr = __builtin___strlcpy_chk(dst, src, sizeof(src), sizeof(dst)); // expected-warning {{incompatible integer to pointer conversion}}
+ ptr = __builtin___strlcat_chk(dst, src, sizeof(src), sizeof(dst)); // expected-warning {{incompatible integer to pointer conversion}}
+}
diff --git a/test/Sema/callingconv.c b/test/Sema/callingconv.c
index 266242d..e487020 100644
--- a/test/Sema/callingconv.c
+++ b/test/Sema/callingconv.c
@@ -43,7 +43,7 @@ int __attribute__((pcs(0))) pcs4(void); // expected-error {{'pcs' attribute requ
/* 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}}
+int __attribute__((pcs("foo"))) pcs7(void); // expected-error {{invalid PCS type}}
// PR6361
void ctest3();
@@ -54,3 +54,5 @@ 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}}
+
+void __attribute__((intel_ocl_bicc)) inteloclbifunc(float *a) {}
diff --git a/test/Sema/compare.c b/test/Sema/compare.c
index b5d4ef5..887bce0 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) + // 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}}
+ (C == (unsigned short) b) + // expected-warning {{comparison of constant 'C' (65536) with expression of type 'unsigned short' is always false}}
+ (C == (unsigned char) b) + // expected-warning {{comparison of constant 'C' (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) + // 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}}
+ (C < (unsigned short) b) + // expected-warning {{comparison of constant 'C' (65536) with expression of type 'unsigned short' is always false}}
+ (C < (unsigned char) b) + // expected-warning {{comparison of constant 'C' (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) + // 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}}
+ ((short) a == C) + // expected-warning {{comparison of constant 'C' (65536) with expression of type 'short' is always false}}
+ ((signed char) a == C) + // expected-warning {{comparison of constant 'C' (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) + // 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}}
+ ((short) a < C) + // expected-warning {{comparison of constant 'C' (65536) with expression of type 'short' is always true}}
+ ((signed char) a < C) + // expected-warning {{comparison of constant 'C' (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) +
diff --git a/test/Sema/complex-imag.c b/test/Sema/complex-imag.c
index 1c6fb15..deaf627 100644
--- a/test/Sema/complex-imag.c
+++ b/test/Sema/complex-imag.c
@@ -4,7 +4,7 @@ void f1() {
int a = 1;
int b = __imag a;
int *c = &__real a;
- int *d = &__imag a; // expected-error {{must be an lvalue}}
+ int *d = &__imag a; // expected-error {{cannot take the address of an rvalue of type 'int'}}
}
void f2() {
@@ -18,7 +18,7 @@ void f3() {
double a = 1;
double b = __imag a;
double *c = &__real a;
- double *d = &__imag a; // expected-error {{must be an lvalue}}
+ double *d = &__imag a; // expected-error {{cannot take the address of an rvalue of type 'double'}}
}
void f4() {
diff --git a/test/Sema/decl-invalid.c b/test/Sema/decl-invalid.c
index f6fed3c..0544304 100644
--- a/test/Sema/decl-invalid.c
+++ b/test/Sema/decl-invalid.c
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify
// See Sema::ParsedFreeStandingDeclSpec about the double diagnostic
-typedef union <anonymous> __mbstate_t; // expected-error {{declaration of anonymous union must be a definition}} expected-warning {{declaration does not declare anything}}
+typedef union <anonymous> __mbstate_t; // expected-error {{declaration of anonymous union must be a definition}} expected-warning {{typedef requires a name}}
// PR2017
@@ -14,7 +14,7 @@ int a() {
}
int; // expected-warning {{declaration does not declare anything}}
-typedef int; // expected-warning {{declaration does not declare anything}}
+typedef int; // expected-warning {{typedef requires a name}}
const int; // expected-warning {{declaration does not declare anything}}
struct; // expected-error {{declaration of anonymous struct must be a definition}} // expected-warning {{declaration does not declare anything}}
typedef int I;
diff --git a/test/Sema/declspec.c b/test/Sema/declspec.c
index 7354028..30c0092 100644
--- a/test/Sema/declspec.c
+++ b/test/Sema/declspec.c
@@ -10,7 +10,7 @@ int typedef validTypeDecl() { } // expected-error {{function definition declared
struct _zend_module_entry { } // expected-error {{expected ';' after struct}}
int gv1;
typedef struct _zend_function_entry { } // expected-error {{expected ';' after struct}} \
- // expected-warning {{declaration does not declare anything}}
+ // expected-warning {{typedef requires a name}}
int gv2;
static void buggy(int *x) { }
diff --git a/test/Sema/expr-address-of.c b/test/Sema/expr-address-of.c
index 2b8cfbf..32bd0df 100644
--- a/test/Sema/expr-address-of.c
+++ b/test/Sema/expr-address-of.c
@@ -90,8 +90,8 @@ void f5() {
lvalue we would need to give a warning. Note that gcc warns about
this as a register before it warns about it as an invalid
lvalue. */
- int *_dummy0 = &(int*) arr; // expected-error {{address expression must be an lvalue or a function designator}}
- int *_dummy1 = &(arr + 1); // expected-error {{address expression must be an lvalue or a function designator}}
+ int *_dummy0 = &(int*) arr; // expected-error {{cannot take the address of an rvalue}}
+ int *_dummy1 = &(arr + 1); // expected-error {{cannot take the address of an rvalue}}
}
void f6(register int x) {
@@ -109,12 +109,12 @@ char* f7() {
}
void f8() {
- void *dummy0 = &f8(); // expected-error {{address expression must be an lvalue or a function designator}}
+ void *dummy0 = &f8(); // expected-error {{cannot take the address of an rvalue of type 'void'}}
extern void v;
- void *dummy1 = &(1 ? v : f8()); // expected-error {{address expression must be an lvalue or a function designator}}
+ void *dummy1 = &(1 ? v : f8()); // expected-error {{cannot take the address of an rvalue of type 'void'}}
- void *dummy2 = &(f8(), v); // expected-error {{address expression must be an lvalue or a function designator}}
+ void *dummy2 = &(f8(), v); // expected-error {{cannot take the address of an rvalue of type 'void'}}
- void *dummy3 = &({ ; }); // expected-error {{address expression must be an lvalue or a function designator}}
+ void *dummy3 = &({ ; }); // expected-error {{cannot take the address of an rvalue of type 'void'}}
}
diff --git a/test/Sema/expr-comma-c99.c b/test/Sema/expr-comma-c99.c
index 6e97a4f..02886bf 100644
--- a/test/Sema/expr-comma-c99.c
+++ b/test/Sema/expr-comma-c99.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c99
+// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c99 -Wno-sizeof-array-decay
// expected-no-diagnostics
// rdar://6095180
diff --git a/test/Sema/expr-comma.c b/test/Sema/expr-comma.c
index 7902715..e2beafe 100644
--- a/test/Sema/expr-comma.c
+++ b/test/Sema/expr-comma.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c89
+// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c89 -Wno-sizeof-array-decay
// expected-no-diagnostics
// rdar://6095180
diff --git a/test/Sema/exprs.c b/test/Sema/exprs.c
index df3e258..2fb17e4 100644
--- a/test/Sema/exprs.c
+++ b/test/Sema/exprs.c
@@ -94,7 +94,7 @@ int test8(void) {
struct f { int x : 4; float y[]; };
int test9(struct f *P) {
int R;
- R = __alignof(P->x); // expected-error {{invalid application of '__alignof' to bit-field}}
+ R = __alignof(P->x); // expected-error {{invalid application of 'alignof' to bit-field}}
R = __alignof(P->y); // ok.
R = sizeof(P->x); // expected-error {{invalid application of 'sizeof' to bit-field}}
return R;
diff --git a/test/Sema/extern-redecl.c b/test/Sema/extern-redecl.c
index c176725..9a085de 100644
--- a/test/Sema/extern-redecl.c
+++ b/test/Sema/extern-redecl.c
@@ -20,3 +20,16 @@ int PR10013(void) {
return PR10013_x; // expected-warning{{incompatible pointer to integer conversion}}
}
+static int test1_a[]; // expected-warning {{tentative array definition assumed to have one element}}
+extern int test1_a[];
+
+// rdar://13535367
+void test2declarer() { extern int test2_array[100]; }
+extern int test2_array[];
+int test2v = sizeof(test2_array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+
+void test3declarer() {
+ { extern int test3_array[100]; }
+ extern int test3_array[];
+ int x = sizeof(test3_array); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+}
diff --git a/test/Sema/format-strings-fixit.c b/test/Sema/format-strings-fixit.c
index 15ac713..3127418 100644
--- a/test/Sema/format-strings-fixit.c
+++ b/test/Sema/format-strings-fixit.c
@@ -165,7 +165,7 @@ void test2() {
// Validate the fixes.
// CHECK: printf("%d", (int) 123);
// CHECK: printf("abc%s", "testing testing 123");
-// CHECK: printf("%lu", (long) -12);
+// CHECK: printf("%ld", (long) -12);
// CHECK: printf("%d", 123);
// CHECK: printf("%s\n", "x");
// CHECK: printf("%f\n", 1.23);
@@ -193,11 +193,11 @@ void test2() {
// CHECK: printf("%d", (my_int_type) 42);
// CHECK: printf("%s", "foo");
// CHECK: printf("%lo", (long) 42);
-// CHECK: printf("%lu", (long) 42);
+// CHECK: printf("%ld", (long) 42);
// CHECK: printf("%lx", (long) 42);
// CHECK: printf("%lX", (long) 42);
-// CHECK: printf("%li", (unsigned long) 42);
-// CHECK: printf("%ld", (unsigned long) 42);
+// CHECK: printf("%lu", (unsigned long) 42);
+// CHECK: printf("%lu", (unsigned long) 42);
// CHECK: printf("%LF", (long double) 42);
// CHECK: printf("%Le", (long double) 42);
// CHECK: printf("%LE", (long double) 42);
diff --git a/test/Sema/format-strings.c b/test/Sema/format-strings.c
index 8fb1218..ba12721 100644
--- a/test/Sema/format-strings.c
+++ b/test/Sema/format-strings.c
@@ -58,6 +58,9 @@ def"
printf("%*d", (unsigned) 1, 1); // no-warning
}
+// When calling a non-variadic format function (vprintf, vscanf, NSLogv, ...),
+// warn only if the format string argument is a parameter that is not itself
+// declared as a format string with compatible format.
__attribute__((__format__ (__printf__, 2, 4)))
void check_string_literal2( FILE* fp, const char* s, char *buf, ... ) {
char * b;
diff --git a/test/Sema/function-redecl.c b/test/Sema/function-redecl.c
index ff8e003..3ee8763 100644
--- a/test/Sema/function-redecl.c
+++ b/test/Sema/function-redecl.c
@@ -92,8 +92,6 @@ void outer_test3() {
int *(*fp)(int) = outer8; // expected-error{{use of undeclared identifier 'outer8'}}
}
-static float outer8(float); // okay
-
enum e { e1, e2 };
// GNU extension: prototypes and K&R function definitions
diff --git a/test/Sema/gnu89.c b/test/Sema/gnu89.c
index 189e6b0..1b7f10f 100644
--- a/test/Sema/gnu89.c
+++ b/test/Sema/gnu89.c
@@ -2,4 +2,4 @@
int f(int restrict);
-void main() {} // expected-warning {{return type of 'main' is not 'int'}}
+void main() {} // expected-warning {{return type of 'main' is not 'int'}} expected-note {{change return type to 'int'}}
diff --git a/test/Sema/i-c-e.c b/test/Sema/i-c-e.c
index e7b42c4..7749b6c 100644
--- a/test/Sema/i-c-e.c
+++ b/test/Sema/i-c-e.c
@@ -73,3 +73,5 @@ int illegaldiv4[0 / (1 / 0)]; // expected-error {{variable length array declarat
int chooseexpr[__builtin_choose_expr(1, 1, expr)];
int realop[(__real__ 4) == 4 ? 1 : -1];
int imagop[(__imag__ 4) == 0 ? 1 : -1];
+
+int *PR14729 = 0 ?: 1/0; // expected-error {{not a compile-time constant}} expected-warning 3{{}}
diff --git a/test/Sema/implicit-cast-dump.c b/test/Sema/implicit-cast-dump.c
new file mode 100644
index 0000000..87f15d0
--- /dev/null
+++ b/test/Sema/implicit-cast-dump.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -ast-dump %s | FileCheck %s
+
+void foo1(void*);
+void foo2(void* const);
+
+
+void bar() {
+ // CHECK: FunctionDecl {{.*}} <line:{{.*}}, line:{{.*}}> bar 'void ()'
+
+ foo1(0);
+ // CHECK: ImplicitCastExpr {{.*}} <col:{{.*}}> 'void *' <NullToPointer>
+
+ foo2(0);
+ // CHECK: ImplicitCastExpr {{.*}} <col:{{.*}}> 'void *' <NullToPointer>
+}
diff --git a/test/Sema/inline.c b/test/Sema/inline.c
index c27c00e..496e282 100644
--- a/test/Sema/inline.c
+++ b/test/Sema/inline.c
@@ -73,6 +73,16 @@ inline int useStaticAgain () { // expected-note 2 {{use 'static' to give inline
#pragma clang diagnostic pop
+inline void defineStaticVar() { // expected-note {{use 'static' to give inline function 'defineStaticVar' internal linkage}}
+ static const int x = 0; // ok
+ static int y = 0; // expected-warning {{non-constant static local variable in inline function may be different in different files}}
+}
+
+extern inline void defineStaticVarInExtern() {
+ static const int x = 0; // ok
+ static int y = 0; // ok
+}
+
#endif
diff --git a/test/Sema/invalid-cast.cpp b/test/Sema/invalid-cast.cpp
new file mode 100644
index 0000000..2183352
--- /dev/null
+++ b/test/Sema/invalid-cast.cpp
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -verify -fsyntax-only %s
+// expected-no-diagnostics
+// <rdar://problem/13153516> - This previously triggered an assertion failure.
+template<class T>
+struct X {
+ T array;
+};
+
+int foo(X<int[1]> x0) {
+ return x0.array[17];
+}
diff --git a/test/Sema/invalid-decl.c b/test/Sema/invalid-decl.c
index b2c2aaf..950d51d 100644
--- a/test/Sema/invalid-decl.c
+++ b/test/Sema/invalid-decl.c
@@ -38,3 +38,11 @@ static void bar(hid_t p, char); // expected-error {{unknown type name 'hid_t'}}
void foo() {
(void)bar;
}
+
+void test2();
+void test2(undef); // expected-error {{a parameter list without types is only allowed in a function definition}}
+void test2() { }
+
+void test3();
+void test3; // expected-error {{incomplete type}}
+void test3() { }
diff --git a/test/Sema/memset-invalid-1.c b/test/Sema/memset-invalid-1.c
new file mode 100644
index 0000000..f4fba20
--- /dev/null
+++ b/test/Sema/memset-invalid-1.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only %s -verify
+// rdar://13081751
+
+typedef __SIZE_TYPE__ size_t;
+void *memset(void*, int, size_t);
+
+typedef struct __incomplete *incomplete;
+
+void mt_query_for_domain(const char *domain)
+{
+ incomplete query = 0;
+ memset(query, 0, sizeof(query)); // expected-warning {{'memset' call operates on objects of type 'struct __incomplete' while the size is based on a different type 'incomplete'}} \
+ // expected-note {{did you mean to dereference the argument to 'sizeof' (and multiply it by the number of elements)?}}
+}
+
diff --git a/test/Sema/merge-decls.c b/test/Sema/merge-decls.c
index 1a84d33..29707d2 100644
--- a/test/Sema/merge-decls.c
+++ b/test/Sema/merge-decls.c
@@ -37,3 +37,57 @@ void foo6096412(void) {
int x = sizeof(i6096412);
}
+
+typedef int test1_IA[];
+typedef int test1_A10[10];
+static test1_A10 *test1_f(void);
+void test1_g(void)
+{
+ {
+ extern test1_IA *test1_f(void);
+ }
+ (void)sizeof(*test1_f());
+}
+
+typedef int test2_IA[];
+typedef int test2_A10[10];
+
+static test2_A10 *test2_f(void);
+static test2_IA *test2_f(void);
+
+void test2_g(void)
+{
+ (void)sizeof(*test2_f());
+}
+
+int (*test3_f())[10];
+int (*test3_f())[];
+int test3_k = sizeof(*test3_f());
+
+void test4_f(int);
+void test4_f(a)
+ char a;
+{
+ int v[sizeof(a) == 1 ? 1 : -1];
+}
+
+int test5_f(int (*)[10]);
+int test5_f(int (*x)[]) {
+ return sizeof(*x); // expected-error {{invalid application of 'sizeof' to an incomplete type 'int []'}}
+}
+
+void test6_f(int (*a)[11]);
+void test6_f(a)
+ int (*a)[];
+{}
+void test6_g() {
+ int arr[10];
+ test6_f(&arr); // expected-warning {{incompatible pointer types passing 'int (*)[10]' to parameter of type 'int (*)[11]}}
+}
+
+void test7_f(int (*)[10]);
+void test7_f(int (*)[]); // expected-note {{passing argument to parameter here}}
+void test7_g() {
+ int x[5];
+ test7_f(&x); // expected-warning {{incompatible pointer types passing 'int (*)[5]' to parameter of type 'int (*)[10]}}
+}
diff --git a/test/Sema/mips16_attr_allowed.c b/test/Sema/mips16_attr_allowed.c
new file mode 100644
index 0000000..21a94e7
--- /dev/null
+++ b/test/Sema/mips16_attr_allowed.c
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -triple mipsel-linux-gnu -fsyntax-only -verify %s
+
+void foo32();
+void foo16();
+void __attribute__((nomips16)) foo32();
+void __attribute__((mips16)) foo16();
+
+void __attribute__((nomips16)) foo32_();
+void __attribute__((mips16)) foo16_();
+void foo32_();
+void foo16_();
+
+void foo32__() __attribute__((nomips16));
+void foo32__() __attribute__((mips16));
+
+void foo32a() __attribute__((nomips16(xyz))) ; // expected-error {{attribute takes no arguments}}
+void __attribute__((mips16(xyz))) foo16a(); // expected-error {{attribute takes no arguments}}
+
+void __attribute__((nomips16(1, 2))) foo32b(); // expected-error {{attribute takes no arguments}}
+void __attribute__((mips16(1, 2))) foo16b(); // expected-error {{attribute takes no arguments}}
+
+
+__attribute((nomips16)) int a; // expected-error {{attribute only applies to functions}}
+
+__attribute((mips16)) int b; // expected-error {{attribute only applies to functions}}
+
+
diff --git a/test/Sema/mips16_attr_not_allowed.c b/test/Sema/mips16_attr_not_allowed.c
new file mode 100644
index 0000000..54f27d6
--- /dev/null
+++ b/test/Sema/mips16_attr_not_allowed.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fsyntax-only -verify %s
+
+void __attribute__((nomips16)) foo32(); // expected-warning {{unknown attribute 'nomips16' ignored}}
+void __attribute__((mips16)) foo16(); // expected-warning {{unknown attribute 'mips16' ignored}}
+
+
+
diff --git a/test/Sema/ms-inline-asm-invalid-arch.c b/test/Sema/ms-inline-asm-invalid-arch.c
new file mode 100644
index 0000000..0870fcb
--- /dev/null
+++ b/test/Sema/ms-inline-asm-invalid-arch.c
@@ -0,0 +1,5 @@
+// RUN: %clang_cc1 %s -triple powerpc64-unknown-linux-gnu -fasm-blocks -verify -fsyntax-only
+
+void f() {
+ __asm nop // expected-error {{Unsupported architecture 'powerpc64' for MS-style inline assembly}}
+}
diff --git a/test/Sema/ms-inline-asm.c b/test/Sema/ms-inline-asm.c
index f6a0fdc..1916d34 100644
--- a/test/Sema/ms-inline-asm.c
+++ b/test/Sema/ms-inline-asm.c
@@ -1,5 +1,5 @@
-// 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
+// REQUIRES: disabled
+// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -fasm-blocks -Wno-microsoft -verify -fsyntax-only
void t1(void) {
__asm __asm // expected-error {{__asm used with no assembly instructions}}
@@ -21,15 +21,14 @@ void f() {
}
f();
__asm {
- mov eax, TYPE cat // expected-error {{Unable to lookup TYPE of expr!}}
+ mov eax, LENGTH bar // expected-error {{Unable to lookup expr!}}
}
f();
__asm {
- mov eax, SIZE foo // expected-error {{Unsupported directive!}}
+ mov eax, SIZE bar // expected-error {{Unable to lookup expr!}}
}
f();
__asm {
- mov eax, LENGTH foo // expected-error {{Unsupported directive!}}
+ mov eax, TYPE bar // expected-error {{Unable to lookup expr!}}
}
-
}
diff --git a/test/Sema/nowarn-documentation-property.m b/test/Sema/nowarn-documentation-property.m
new file mode 100644
index 0000000..af2b062
--- /dev/null
+++ b/test/Sema/nowarn-documentation-property.m
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-objc-root-class -Wdocumentation -verify %s
+// expected-no-diagnostics
+// rdar://13189938
+
+@interface NSPredicate
+/// The full predicate to be used for drawing objects from the store.
+/// It is an AND of the parent's `prefixPredicate` (e.g., the selection for
+/// volume number) and the `filterPredicate` (selection by matching the name).
+/// @return `nil` if there is no search string, and no prefix.
+
+@property(readonly) NSPredicate *andPredicate;
+/// The predicate that matches the string to be searched for. This
+/// @return `nil` if there is no search string.
+@property(readonly) NSPredicate *filterPredicate;
+@end
diff --git a/test/Sema/parentheses.cpp b/test/Sema/parentheses.cpp
index 8f5f246..da37dd3 100644
--- a/test/Sema/parentheses.cpp
+++ b/test/Sema/parentheses.cpp
@@ -57,3 +57,15 @@ void test(int a, int b, int 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}}
}
+
+namespace PR15628 {
+ struct BlockInputIter {
+ void* operator++(int);
+ void* operator--(int);
+ };
+
+ void test(BlockInputIter i) {
+ (void)(i++ ? true : false); // no-warning
+ (void)(i-- ? true : false); // no-warning
+ }
+}
diff --git a/test/Sema/pid_t.c b/test/Sema/pid_t.c
new file mode 100644
index 0000000..7021e37
--- /dev/null
+++ b/test/Sema/pid_t.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -triple i586-pc-haiku -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple i686-pc-linux -fsyntax-only -verify %s
+
+// expected-no-diagnostics
+
+#ifdef __HAIKU__
+typedef signed long pid_t;
+#else
+typedef signed int pid_t;
+#endif
+pid_t vfork(void); \ No newline at end of file
diff --git a/test/Sema/ppc-bool.c b/test/Sema/ppc-bool.c
new file mode 100644
index 0000000..2a4303e
--- /dev/null
+++ b/test/Sema/ppc-bool.c
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -triple powerpc-apple-macosx10.4.0 -verify -fsyntax-only %s
+// expected-no-diagnostics
+extern __typeof(+(_Bool)0) should_be_int;
+extern int should_be_int;
diff --git a/test/Sema/private-extern.c b/test/Sema/private-extern.c
index e480f3f..e9b67d5 100644
--- a/test/Sema/private-extern.c
+++ b/test/Sema/private-extern.c
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -verify -fsyntax-only -Wno-private-extern %s
+// RUN: %clang_cc1 -verify -fsyntax-only -Wno-private-extern -fmodules %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-noreturn.c b/test/Sema/return-noreturn.c
index 448fce7..6d521eb 100644
--- a/test/Sema/return-noreturn.c
+++ b/test/Sema/return-noreturn.c
@@ -35,3 +35,8 @@ void __attribute__((noreturn))
test4() {
test2_positive();
}
+
+// Do not warn here.
+_Noreturn void test5() {
+ test2_positive();
+}
diff --git a/test/Sema/return.c b/test/Sema/return.c
index 77bd3f6..e231e81 100644
--- a/test/Sema/return.c
+++ b/test/Sema/return.c
@@ -244,6 +244,11 @@ const int ignored_c_quals(); // expected-warning{{'const' type qualifier on retu
const volatile int ignored_cv_quals(); // expected-warning{{'const volatile' type qualifiers on return type have no effect}}
char* const volatile restrict ignored_cvr_quals(); // expected-warning{{'const volatile restrict' type qualifiers on return type have no effect}}
+typedef const int CI;
+CI ignored_quals_typedef();
+
+const CI ignored_quals_typedef_2(); // expected-warning{{'const' type qualifier}}
+
// Test that for switch(enum) that if the switch statement covers all the cases
// that we don't consider that for -Wreturn-type.
enum Cases { C1, C2, C3, C4 };
diff --git a/test/Sema/static-assert.c b/test/Sema/static-assert.c
index 13d7070..87fa050 100644
--- a/test/Sema/static-assert.c
+++ b/test/Sema/static-assert.c
@@ -1,6 +1,10 @@
-// RUN: %clang_cc1 -std=c1x -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -xc++ -std=c++11 -fsyntax-only -verify %s
-_Static_assert("foo", "string is nonzero"); // expected-error {{static_assert expression is not an integral constant expression}}
+_Static_assert("foo", "string is nonzero");
+#ifndef __cplusplus
+// expected-error@-2 {{static_assert expression is not an integral constant expression}}
+#endif
_Static_assert(1, "1 is nonzero");
_Static_assert(0, "0 is nonzero"); // expected-error {{static_assert failed "0 is nonzero"}}
@@ -9,3 +13,30 @@ void foo(void) {
_Static_assert(1, "1 is nonzero");
_Static_assert(0, "0 is nonzero"); // expected-error {{static_assert failed "0 is nonzero"}}
}
+
+_Static_assert(1, invalid); // expected-error {{expected string literal for diagnostic message in static_assert}}
+
+struct A {
+ int a;
+ _Static_assert(1, "1 is nonzero");
+ _Static_assert(0, "0 is nonzero"); // expected-error {{static_assert failed "0 is nonzero"}}
+};
+
+#ifdef __cplusplus
+#define ASSERT_IS_TYPE(T) __is_same(T, T)
+#else
+#define ASSERT_IS_TYPE(T) __builtin_types_compatible_p(T, T)
+#endif
+
+#define UNION(T1, T2) union { \
+ __typeof__(T1) one; \
+ __typeof__(T2) two; \
+ _Static_assert(ASSERT_IS_TYPE(T1), "T1 is not a type"); \
+ _Static_assert(ASSERT_IS_TYPE(T2), "T2 is not a type"); \
+ _Static_assert(sizeof(T1) == sizeof(T2), "type size mismatch"); \
+ }
+
+typedef UNION(unsigned, struct A) U1;
+UNION(char[2], short) u2 = { .one = { 'a', 'b' } };
+typedef UNION(char, short) U3; // expected-error {{static_assert failed "type size mismatch"}}
+typedef UNION(float, 0.5f) U4; // expected-error {{expected a type}}
diff --git a/test/Sema/struct-decl.c b/test/Sema/struct-decl.c
index 6070e87..819e856 100644
--- a/test/Sema/struct-decl.c
+++ b/test/Sema/struct-decl.c
@@ -54,6 +54,6 @@ static struct test1 { // expected-warning {{'static' ignored on this declaration
const struct test2 { // expected-warning {{'const' ignored on this declaration}}
int x;
};
-inline struct test3 { // expected-warning {{'inline' ignored on this declaration}}
+inline struct test3 { // expected-error {{'inline' can only appear on functions}}
int x;
};
diff --git a/test/Sema/switch-1.c b/test/Sema/switch-1.c
new file mode 100644
index 0000000..ce1e7dc
--- /dev/null
+++ b/test/Sema/switch-1.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-apple-darwin10 %s
+// RUN: %clang_cc1 -x c++ -fsyntax-only -verify -triple x86_64-apple-darwin10 %s
+// rdar://11577384
+// rdar://13423975
+
+int f(int i) {
+ switch (i) {
+ case 2147483647 + 2: // expected-warning {{overflow in expression; result is -2147483647 with type 'int'}}
+ return 1;
+ case 9223372036854775807L * 4: // expected-warning {{overflow in expression; result is -4 with type 'long'}}
+ return 2;
+ case (123456 *789012) + 1: // expected-warning {{overflow in expression; result is -1375982336 with type 'int'}}
+ return 3;
+ case (2147483647*4)/4: // expected-warning {{overflow in expression; result is -4 with type 'int'}}
+ case (2147483647*4)%4: // expected-warning {{overflow in expression; result is -4 with type 'int'}}
+ return 4;
+ case 2147483647:
+ return 0;
+ }
+ return (i, 65537) * 65537; // expected-warning {{overflow in expression; result is 131073 with type 'int'}} \
+ // expected-warning {{expression result unused}}
+}
diff --git a/test/Sema/types.c b/test/Sema/types.c
index 6ae1a92..d0637cc 100644
--- a/test/Sema/types.c
+++ b/test/Sema/types.c
@@ -53,7 +53,7 @@ _Decimal32 x; // expected-error {{GNU decimal type extension not supported}}
int __attribute__ ((vector_size (8), vector_size (8))) v; // expected-error {{invalid vector element type}}
void test(int i) {
- char c = (char __attribute__((align(8)))) i; // expected-error {{'align' attribute ignored when parsing type}}
+ char c = (char __attribute__((align(8)))) i; // expected-warning {{'align' attribute ignored when parsing type}}
}
// http://llvm.org/PR11082
diff --git a/test/Sema/ucn-cstring.c b/test/Sema/ucn-cstring.c
index 5d3e85d..382e555 100644
--- a/test/Sema/ucn-cstring.c
+++ b/test/Sema/ucn-cstring.c
@@ -8,7 +8,7 @@ int main(void) {
printf("%s (%zd)\n", "hello \u2192 \u2603 \u2190 world", sizeof("hello \u2192 \u2603 \u2190 world"));
printf("%s (%zd)\n", "\U00010400\U0001D12B", sizeof("\U00010400\U0001D12B"));
// Some error conditions...
- printf("%s\n", "\U"); // expected-error{{\u used with no following hex digits}}
+ printf("%s\n", "\U"); // expected-error{{\U used with no following hex digits}}
printf("%s\n", "\U00"); // expected-error{{incomplete universal character name}}
printf("%s\n", "\U0001"); // expected-error{{incomplete universal character name}}
printf("%s\n", "\u0001"); // expected-error{{universal character name refers to a control character}}
diff --git a/test/Sema/ucn-identifiers.c b/test/Sema/ucn-identifiers.c
new file mode 100644
index 0000000..6b26365
--- /dev/null
+++ b/test/Sema/ucn-identifiers.c
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -pedantic
+// RUN: %clang_cc1 %s -verify -fsyntax-only -x c++ -pedantic
+
+// This file contains UTF-8; please do not fix!
+
+
+extern void \u00FCber(int);
+extern void \U000000FCber(int); // redeclaration, no warning
+#ifdef __cplusplus
+// expected-note@-2 + {{candidate function not viable}}
+#else
+// expected-note@-4 + {{declared here}}
+#endif
+
+void goodCalls() {
+ \u00FCber(0);
+ \u00fcber(1);
+ über(2);
+ \U000000FCber(3);
+}
+
+void badCalls() {
+ \u00FCber(0.5); // expected-warning{{implicit conversion from 'double' to 'int'}}
+ \u00fcber = 0; // expected-error{{non-object type 'void (int)' is not assignable}}
+
+ über(1, 2);
+ \U000000FCber();
+#ifdef __cplusplus
+ // expected-error@-3 {{no matching function}}
+ // expected-error@-3 {{no matching function}}
+#else
+ // expected-error@-6 {{too many arguments to function call, expected 1, have 2}}
+ // expected-error@-6 {{too few arguments to function call, expected 1, have 0}}
+#endif
+}
diff --git a/test/Sema/uninit-det-order.c b/test/Sema/uninit-det-order.c
new file mode 100644
index 0000000..041c4b0
--- /dev/null
+++ b/test/Sema/uninit-det-order.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -Wuninitialized -fsyntax-only %s 2>&1 | FileCheck %s
+
+void pr14901(int a) {
+ int b, c;
+ a = b;
+ a = c;
+}
+
+// CHECK: 5:8: warning: variable 'b' is uninitialized when used here
+// CHECK: 4:9: note: initialize the variable 'b' to silence this warning
+// CHECK: 6:8: warning: variable 'c' is uninitialized when used here
+// CHECK: 4:12: note: initialize the variable 'c' to silence this warning
+
diff --git a/test/Sema/unused-expr-system-header.c b/test/Sema/unused-expr-system-header.c
index dcc8918..68c7e99 100644
--- a/test/Sema/unused-expr-system-header.c
+++ b/test/Sema/unused-expr-system-header.c
@@ -3,8 +3,10 @@
void f(int i1, int i2) {
POSSIBLY_BAD_MACRO(5);
STATEMENT_EXPR_MACRO(5);
- COMMA_MACRO_1(i1 == i2, f(i1, i2)); // expected-warning {{expression result unused}}
+ COMMA_MACRO_1(i1 == i2, f(i1, i2)); // expected-warning {{comparison result unused}} \
+ // expected-note {{equality comparison}}
COMMA_MACRO_2(i1 == i2, f(i1, i2));
- COMMA_MACRO_3(i1 == i2, f(i1, i2)); // expected-warning {{expression result unused}}
+ COMMA_MACRO_3(i1 == i2, f(i1, i2)); // expected-warning {{comparison result unused}} \
+ // expected-note {{equality comparison}}
COMMA_MACRO_4(i1 == i2, f(i1, i2));
}
diff --git a/test/Sema/unused-expr.c b/test/Sema/unused-expr.c
index aa81febd..ea08631 100644
--- a/test/Sema/unused-expr.c
+++ b/test/Sema/unused-expr.c
@@ -123,13 +123,36 @@ void f(int i, ...) {
// PR8371
int fn5() __attribute__ ((__const));
-// OpenSSL has some macros like this; we shouldn't warn on the cast.
+// Don't warn for unused expressions in macro bodies; however, do warn for
+// unused expressions in macro arguments. Macros below are reduced from code
+// found in the wild.
+#define NOP(a) (a)
#define M1(a, b) (long)foo((a), (b))
-// But, we should still warn on other subexpressions of casts in macros.
#define M2 (long)0;
+#define M3(a) (t3(a), fn2())
+#define M4(a, b) (foo((a), (b)) ? 0 : t3(a), 1)
+#define M5(a, b) (foo((a), (b)), 1)
+#define M6() fn1()
+#define M7() fn2()
void t11(int i, int j) {
M1(i, j); // no warning
- M2; // expected-warning {{expression result unused}}
+ NOP((long)foo(i, j)); // expected-warning {{expression result unused}}
+ M2; // no warning
+ NOP((long)0); // expected-warning {{expression result unused}}
+ M3(i); // no warning
+ NOP((t3(i), fn2())); // expected-warning {{ignoring return value}}
+ M4(i, j); // no warning
+ NOP((foo(i, j) ? 0 : t3(i), 1)); // expected-warning {{expression result unused}}
+ M5(i, j); // no warning
+ NOP((foo(i, j), 1)); // expected-warning {{expression result unused}}
+ M6(); // expected-warning {{ignoring return value}}
+ M7(); // no warning
}
+#undef NOP
#undef M1
#undef M2
+#undef M3
+#undef M4
+#undef M5
+#undef M6
+#undef M7
diff --git a/test/Sema/varargs.c b/test/Sema/varargs.c
index 07081ed..663d3d5 100644
--- a/test/Sema/varargs.c
+++ b/test/Sema/varargs.c
@@ -57,7 +57,7 @@ void f7(int a, ...) {
__builtin_va_start(ap, a);
// FIXME: This error message is sub-par.
__builtin_va_arg(ap, int) = 1; // expected-error {{expression is not assignable}}
- int *x = &__builtin_va_arg(ap, int); // expected-error {{address expression must be an lvalue or a function designator}}
+ int *x = &__builtin_va_arg(ap, int); // expected-error {{cannot take the address of an rvalue}}
__builtin_va_end(ap);
}
diff --git a/test/Sema/varargs_unreachable.c b/test/Sema/varargs_unreachable.c
new file mode 100644
index 0000000..866bd8f
--- /dev/null
+++ b/test/Sema/varargs_unreachable.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -triple x86_64-apple-darwin9
+// expected-no-diagnostics
+
+// From <rdar://problem/12322000>. Do not warn about undefined behavior of parameter
+// argument types in unreachable code in a macro.
+#define VA_ARG_RDAR12322000(Marker, TYPE) ((sizeof (TYPE) < sizeof (UINTN_RDAR12322000)) ? (TYPE)(__builtin_va_arg (Marker, UINTN_RDAR12322000)) : (TYPE)(__builtin_va_arg (Marker, TYPE)))
+
+// 64-bit system
+typedef unsigned long long UINTN_RDAR12322000;
+
+int test_VA_ARG_RDAR12322000 (__builtin_va_list Marker)
+{
+ return VA_ARG_RDAR12322000 (Marker, short); // no-warning
+} \ No newline at end of file
diff --git a/test/Sema/variadic-promotion.c b/test/Sema/variadic-promotion.c
new file mode 100644
index 0000000..b248774
--- /dev/null
+++ b/test/Sema/variadic-promotion.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -ast-dump %s | FileCheck %s
+
+void variadic(int, ...);
+
+void test_floating_promotion(__fp16 *f16, float f32, double f64) {
+ variadic(3, *f16, f32, f64);
+
+// CHECK: ImplicitCastExpr {{.*}} 'double' <FloatingCast>
+// CHECK-NEXT: 'half'
+
+// CHECK: ImplicitCastExpr {{.*}} 'double' <FloatingCast>
+// CHECK-NEXT: 'float'
+}
diff --git a/test/Sema/warn-documentation-crlf.c b/test/Sema/warn-documentation-crlf.c
new file mode 100644
index 0000000..99c0714
--- /dev/null
+++ b/test/Sema/warn-documentation-crlf.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only -Wdocumentation %s
+// The run line does not have '-verify' because we were crashing while printing
+// the diagnostic.
+
+// This file has DOS-style line endings (CR LF). Please don't change it to
+// Unix-style LF!
+
+// PR14591. Check that we don't crash on this.
+/**
+ * @param abc
+ */
+void nocrash1(int qwerty);
+
diff --git a/test/Sema/warn-documentation.cpp b/test/Sema/warn-documentation.cpp
index 5678fd9..0132ef2 100644
--- a/test/Sema/warn-documentation.cpp
+++ b/test/Sema/warn-documentation.cpp
@@ -303,6 +303,11 @@ typedef int (*test_param27)(int aaa);
/// \param aaa Meow.
typedef test_param27 test_param28;
+// rdar://13066276
+// expected-warning@+1 {{'@param' command used in a comment that is not attached to a function declaration}}
+/// @param aaa Meow.
+typedef unsigned int test_param29;
+
// expected-warning@+1 {{'\tparam' command used in a comment that is not attached to a template declaration}}
/// \tparam T Aaa
@@ -377,6 +382,35 @@ using test_tparam14 = test_tparam13<T, int>;
template<typename T>
using test_tparam15 = test_tparam13<T, int>;
+// ----
+
+/// \tparam T Aaa
+template<typename T>
+class test_tparam16 { };
+
+typedef test_tparam16<int> test_tparam17;
+typedef test_tparam16<double> test_tparam18;
+
+// ----
+
+template<typename T>
+class test_tparam19;
+
+typedef test_tparam19<int> test_tparam20;
+typedef test_tparam19<double> test_tparam21;
+
+/// \tparam T Aaa
+template<typename T>
+class test_tparam19 { };
+
+// ----
+
+// expected-warning@+1 {{'@tparam' command used in a comment that is not attached to a template declaration}}
+/// @tparam T Aaa
+int test_tparam22;
+
+// ----
+
/// Aaa
/// \deprecated Bbb
@@ -415,6 +449,14 @@ template<typename T>
void test_deprecated_7(T aaa);
+// rdar://12397511
+// expected-note@+2 {{previous command '\headerfile' here}}
+// expected-warning@+2 {{duplicated command '\headerfile'}}
+/// \headerfile ""
+/// \headerfile foo.h
+int test__headerfile_1(int a);
+
+
/// \invariant aaa
void test_invariant_1(int a);
@@ -501,6 +543,23 @@ enum test_returns_wrong_decl_8 {
/// \returns Aaa
namespace test_returns_wrong_decl_10 { };
+// rdar://13066276
+// expected-warning@+1 {{'@returns' command used in a comment that is not attached to a function or method declaration}}
+/// @returns Aaa
+typedef unsigned int test_returns_wrong_decl_11;
+
+// rdar://13094352
+// expected-warning@+1 {{'@function' command should be used in a comment attached to a function declaration}}
+/*! @function test_function
+*/
+typedef unsigned int Base64Flags;
+unsigned test_function(Base64Flags inFlags);
+
+// expected-warning@+1 {{'@callback' command should be used in a comment attached to a pointer to function declaration}}
+/*! @callback test_callback
+*/
+typedef unsigned int BaseFlags;
+unsigned (*test_callback)(BaseFlags inFlags);
// expected-warning@+1 {{'\endverbatim' command does not terminate a verbatim text block}}
/// \endverbatim
@@ -836,3 +895,58 @@ typedef const struct test_nocrash7 * test_nocrash8;
/// aaa \unknown aaa \unknown aaa
int test_nocrash9;
+
+// We used to crash on this. PR15068
+
+// expected-warning@+2 {{empty paragraph passed to '@param' command}}
+// expected-warning@+2 {{empty paragraph passed to '@param' command}}
+///@param x
+///@param y
+int test_nocrash10(int x, int y);
+
+// expected-warning@+2 {{empty paragraph passed to '@param' command}} expected-warning@+2 {{parameter 'x' not found in the function declaration}}
+// expected-warning@+2 {{empty paragraph passed to '@param' command}} expected-warning@+2 {{parameter 'y' not found in the function declaration}}
+///@param x
+///@param y
+int test_nocrash11();
+
+// expected-warning@+3 {{empty paragraph passed to '@param' command}} expected-warning@+3 {{parameter 'x' not found in the function declaration}}
+// expected-warning@+3 {{empty paragraph passed to '@param' command}} expected-warning@+3 {{parameter 'y' not found in the function declaration}}
+/**
+@param x
+@param y
+**/
+int test_nocrash12();
+
+// expected-warning@+2 {{empty paragraph passed to '@param' command}}
+// expected-warning@+1 {{empty paragraph passed to '@param' command}}
+///@param x@param y
+int test_nocrash13(int x, int y);
+
+// rdar://12379114
+// expected-warning@+2 {{'@union' command should not be used in a comment attached to a non-union declaration}}
+/*!
+ @union U This is new
+*/
+struct U { int iS; };
+
+/*!
+ @union U1
+*/
+union U1 {int i; };
+
+// expected-warning@+2 {{'@struct' command should not be used in a comment attached to a non-struct declaration}}
+/*!
+ @struct S2
+*/
+union S2 {};
+
+/*!
+ @class C1
+*/
+class C1;
+
+/*!
+ @struct S3;
+*/
+class S3;
diff --git a/test/Sema/warn-documentation.m b/test/Sema/warn-documentation.m
index 8a894dc..1e3acf1 100644
--- a/test/Sema/warn-documentation.m
+++ b/test/Sema/warn-documentation.m
@@ -97,3 +97,77 @@ int b;
/// \returns aaa.
typedef int (^test_param1)(int aaa, int ccc);
+// rdar://13094352
+// expected-warning@+2 {{'@method' command should be used in a comment attached to an Objective-C method declaration}}
+@interface I
+/*! @method Base64EncodeEx
+*/
+typedef id ID;
+- (unsigned) Base64EncodeEx : (ID)Arg;
+@end
+
+// rdar://12379114
+// expected-warning@+5 {{'@interface' command should not be used in a comment attached to a non-interface declaration}}
+// expected-warning@+5 {{'@classdesign' command should not be used in a comment attached to a non-container declaration}}
+// expected-warning@+5 {{'@coclass' command should not be used in a comment attached to a non-container declaration}}
+@interface NSObject @end
+/*!
+@interface IOCommandGate
+@classdesign Multiple paragraphs go here.
+@coclass myCoClass
+*/
+
+typedef id OBJ;
+@interface IOCommandGate : NSObject {
+ OBJ iv;
+}
+@end
+
+// rdar://12379114
+// expected-warning@+4 {{'@methodgroup' command should be used in a comment attached to an Objective-C method declaration}}
+// expected-warning@+6 {{'@method' command should be used in a comment attached to an Objective-C method declaratio}}
+@interface rdar12379114
+/*!
+ @methodgroup Creating a request
+*/
+/*!
+ @method initWithTimeout is the 2nd method
+*/
+typedef unsigned int NSTimeInterval;
+- (id)initWithTimeout:(NSTimeInterval)timeout;
+@end
+
+// expected-warning@+2 {{'@protocol' command should not be used in a comment attached to a non-protocol declaration}}
+/*!
+@protocol PROTO
+*/
+struct S;
+
+/*!
+ @interface NSArray This is an array
+*/
+@class NSArray;
+@interface NSArray @end
+
+/*!
+@interface NSMutableArray
+@super NSArray
+*/
+@interface NSMutableArray : NSArray @end
+
+/*!
+ @protocol MyProto
+*/
+@protocol MyProto @end
+
+// expected-warning@+2 {{'@protocol' command should not be used in a comment attached to a non-protocol declaration}}
+/*!
+ @protocol MyProto
+*/
+@interface INTF <MyProto> @end
+
+// expected-warning@+2 {{'@struct' command should not be used in a comment attached to a non-struct declaration}}
+/*!
+ @struct S1 THIS IS IT
+*/
+@interface S1 @end
diff --git a/test/Sema/warn-duplicate-enum.c b/test/Sema/warn-duplicate-enum.c
new file mode 100644
index 0000000..239f6f1
--- /dev/null
+++ b/test/Sema/warn-duplicate-enum.c
@@ -0,0 +1,92 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify -Wduplicate-enum
+// RUN: %clang_cc1 %s -x c++ -fsyntax-only -verify -Wduplicate-enum
+enum A {
+ A1 = 0, // expected-note {{element A1 also has value 0}}
+ A2 = -1,
+ A3, // expected-warning {{element A3 has been implicitly assigned 0 which another element has been assigned}}
+ A4};
+
+enum B {
+ B1 = -1, // expected-note {{element B1 also has value -1}}
+ B2, // expected-warning {{element B2 has been implicitly assigned 0 which another element has been assigned}}
+ B3,
+ B4 = -2,
+ B5, // expected-warning {{element B5 has been implicitly assigned -1 which another element has been assigned}}
+ B6 // expected-note {{element B6 also has value 0}}
+};
+
+enum C { C1, C2 = -1, C3 }; // expected-warning{{element C1 has been implicitly assigned 0 which another element has been assigned}} \
+ // expected-note {{element C3 also has value 0}}
+
+enum D {
+ D1,
+ D2,
+ D3, // expected-warning{{element D3 has been implicitly assigned 2 which another element has been assigned}}
+ D4 = D2, // no warning
+ D5 = 2 // expected-note {{element D5 also has value 2}}
+};
+
+enum E {
+ E1,
+ E2 = E1,
+ E3 = E2
+};
+
+enum F {
+ F1,
+ F2,
+ FCount,
+ FMax = FCount - 1
+};
+
+enum G {
+ G1,
+ G2,
+ GMax = G2,
+ GCount = GMax + 1
+};
+
+enum {
+ H1 = 0,
+ H2 = -1,
+ H3,
+ H4};
+
+enum {
+ I1 = -1,
+ I2,
+ I3,
+ I4 = -2,
+ I5,
+ I6
+};
+
+enum { J1, J2 = -1, J3 };
+
+enum {
+ K1,
+ K2,
+ K3,
+ K4 = K2,
+ K5 = 2
+};
+
+enum {
+ L1,
+ L2 = L1,
+ L3 = L2
+};
+
+enum {
+ M1,
+ M2,
+ MCount,
+ MMax = MCount - 1
+};
+
+enum {
+ N1,
+ N2,
+ NMax = N2,
+ NCount = NMax + 1
+};
diff --git a/test/Sema/warn-main-return-type.c b/test/Sema/warn-main-return-type.c
new file mode 100644
index 0000000..bd7c59f
--- /dev/null
+++ b/test/Sema/warn-main-return-type.c
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -x c++ %s 2>&1 | FileCheck %s
+
+// expected-note@+1 5{{previous definition is here}}
+int main() {
+ return 0;
+}
+
+// expected-error@+3 {{conflicting types for 'main}}
+// expected-warning@+2 {{return type of 'main' is not 'int'}}
+// expected-note@+1 {{change return type to 'int'}}
+void main() {
+// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:1-[[@LINE-1]]:5}:"int"
+}
+
+// expected-error@+3 {{conflicting types for 'main}}
+// expected-warning@+2 {{return type of 'main' is not 'int'}}
+// expected-note@+1 {{change return type to 'int'}}
+double main() {
+// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:1-[[@LINE-1]]:7}:"int"
+ return 0.0;
+}
+
+// Currently we suggest to replace only 'float' here because we don't store
+// enough source locations.
+//
+// expected-error@+3 {{conflicting types for 'main}}
+// expected-warning@+2 {{return type of 'main' is not 'int'}}
+// expected-note@+1 {{change return type to 'int'}}
+const float main() {
+// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:7-[[@LINE-1]]:12}:"int"
+ return 0.0f;
+}
+
+typedef void *(*fptr)(int a);
+
+// expected-error@+2 {{conflicting types for 'main}}
+// expected-warning@+1 {{return type of 'main' is not 'int'}}
+fptr main() {
+ return (fptr) 0;
+}
+
+// expected-error@+2 {{conflicting types for 'main}}
+// expected-warning@+1 {{return type of 'main' is not 'int'}}
+void *(*main())(int a) {
+ return (fptr) 0;
+}
+
diff --git a/test/Sema/warn-main.c b/test/Sema/warn-main.c
new file mode 100644
index 0000000..8a4eafc
--- /dev/null
+++ b/test/Sema/warn-main.c
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -x c++ %s 2>&1 | FileCheck %s
+
+// expected-note@+1 2{{previous definition is here}}
+int main() {
+ return 0;
+}
+
+// expected-error@+2 {{static declaration of 'main' follows non-static declaration}}
+// expected-warning@+1 {{'main' should not be declared static}}
+static int main() {
+// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:1-[[@LINE-1]]:8}:""
+ return 0;
+}
+
+// expected-error@+3 {{redefinition of 'main'}}
+// expected-error@+2 {{'main' is not allowed to be declared inline}}
+// expected-note@+1 {{previous definition is here}}
+inline int main() {
+// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:1-[[@LINE-1]]:8}:""
+ return 0;
+}
+
+// expected-warning@+6 {{function 'main' declared 'noreturn' should not return}}
+// expected-error@+3 {{redefinition of 'main'}}
+// expected-warning@+2 {{'main' is not allowed to be declared _Noreturn}}
+// expected-note@+1 {{remove '_Noreturn'}}
+_Noreturn int main() {
+// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:1-[[@LINE-1]]:11}:""
+ return 0;
+}
+
diff --git a/test/Sema/warn-missing-prototypes.c b/test/Sema/warn-missing-prototypes.c
index bfd1459..10018b6 100644
--- a/test/Sema/warn-missing-prototypes.c
+++ b/test/Sema/warn-missing-prototypes.c
@@ -1,4 +1,5 @@
-// RUN: %clang -Wmissing-prototypes -fsyntax-only -Xclang -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wdocumentation -Wmissing-prototypes -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wdocumentation -Wmissing-prototypes -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
int f();
@@ -35,3 +36,8 @@ int f2(int x) { return x; }
// rdar://6759522
int main(void) { return 0; }
+
+void not_a_prototype_test(); // expected-note{{this declaration is not a prototype; add 'void' to make it a prototype for a zero-parameter function}}
+void not_a_prototype_test() { } // expected-warning{{no previous prototype for function 'not_a_prototype_test'}}
+
+// CHECK: fix-it:"{{.*}}":{40:27-40:27}:"void"
diff --git a/test/Sema/warn-sizeof-array-decay.c b/test/Sema/warn-sizeof-array-decay.c
new file mode 100644
index 0000000..cc3ee1d
--- /dev/null
+++ b/test/Sema/warn-sizeof-array-decay.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+void f(int x) {
+ char foo[10];
+ int bar[20];
+ char qux[30];
+
+ (void)sizeof(bar + 10); // expected-warning{{sizeof on pointer operation will return size of 'int *' instead of 'int [20]'}}
+ (void)sizeof(foo - 20); // expected-warning{{sizeof on pointer operation will return size of 'char *' instead of 'char [10]'}}
+ (void)sizeof(bar - x); // expected-warning{{sizeof on pointer operation will return size of 'int *' instead of 'int [20]'}}
+ (void)sizeof(foo + x); // expected-warning{{sizeof on pointer operation will return size of 'char *' instead of 'char [10]'}}
+
+ // This is ptrdiff_t.
+ (void)sizeof(foo - qux); // no-warning
+
+ (void)sizeof(foo, x); // no-warning
+ (void)sizeof(x, foo); // expected-warning{{sizeof on pointer operation will return size of 'char *' instead of 'char [10]'}}
+}
diff --git a/test/Sema/warn-type-safety-mpi-hdf5.c b/test/Sema/warn-type-safety-mpi-hdf5.c
index 8c50cb2..1a9c5b0 100644
--- a/test/Sema/warn-type-safety-mpi-hdf5.c
+++ b/test/Sema/warn-type-safety-mpi-hdf5.c
@@ -201,10 +201,14 @@ MPI_Datatype my_s1_datatype __attribute__(( type_tag_for_datatype(mpi,struct S1)
struct S2 { int a; int b; };
MPI_Datatype my_s2_datatype __attribute__(( type_tag_for_datatype(mpi,struct S2) ));
+enum E1 { Foo };
+MPI_Datatype my_e1_datatype __attribute__(( type_tag_for_datatype(mpi,enum E1) ));
+
void test_user_types(int *int_buf,
long *long_buf,
struct S1 *s1_buf,
- struct S2 *s2_buf)
+ struct S2 *s2_buf,
+ enum E1 *e1_buf)
{
MPI_Send(int_buf, 1, my_int_datatype); // no-warning
MPI_Send(long_buf, 1, my_int_datatype); // expected-warning {{argument type 'long *' doesn't match specified 'mpi' type tag that requires 'int *'}}
@@ -214,6 +218,10 @@ void test_user_types(int *int_buf,
MPI_Send(long_buf, 1, my_s1_datatype); // expected-warning {{argument type 'long *' doesn't match specified 'mpi' type tag that requires 'struct S1 *'}}
MPI_Send(s1_buf, 1, MPI_INT); // expected-warning {{argument type 'struct S1 *' doesn't match specified 'mpi' type tag that requires 'int *'}}
+
+ MPI_Send(e1_buf, 1, my_e1_datatype); // no-warning
+ MPI_Send(e1_buf, 1, MPI_INT); // expected-warning {{argument type 'enum E1 *' doesn't match specified 'mpi' type tag that requires 'int *'}}
+ MPI_Send(int_buf, 1, my_e1_datatype); // expected-warning {{argument type 'int *' doesn't match specified 'mpi' type tag that requires 'enum E1 *'}}
}
MPI_Datatype my_unknown_datatype;
diff --git a/test/Sema/warn-unreachable.c b/test/Sema/warn-unreachable.c
index 2fbe1c7..fd74b5c 100644
--- a/test/Sema/warn-unreachable.c
+++ b/test/Sema/warn-unreachable.c
@@ -80,8 +80,8 @@ void test2() {
- // expected-warning {{will never be executed}}
halt();
case 8:
- i // expected-warning {{will never be executed}}
- +=
+ i
+ += // expected-warning {{will never be executed}}
halt();
case 9:
halt()
@@ -93,8 +93,8 @@ void test2() {
case 11: {
int a[5];
live(),
- a[halt() // expected-warning {{will never be executed}}
- ];
+ a[halt()
+ ]; // expected-warning {{will never be executed}}
}
}
}
diff --git a/test/Sema/warn-unused-variables-werror.c b/test/Sema/warn-unused-variables-werror.c
new file mode 100644
index 0000000..ceaff1b
--- /dev/null
+++ b/test/Sema/warn-unused-variables-werror.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -fsyntax-only -Wunused-variable -Werror -verify %s
+
+void f() {
+ int i; // expected-error{{unused}}
+ int j; // expected-error{{unused}}
+}
diff --git a/test/Sema/warn-vla.c b/test/Sema/warn-vla.c
new file mode 100644
index 0000000..01fe451
--- /dev/null
+++ b/test/Sema/warn-vla.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -std=c99 -fsyntax-only -verify -Wvla %s
+// RUN: %clang_cc1 -std=c89 -fsyntax-only -verify -Wvla %s
+
+void test1(int n) {
+ int v[n]; // expected-warning {{variable length array used}}
+}
+
+void test2(int n, int v[n]) { // expected-warning {{variable length array used}}
+}
+
+void test3(int n, int v[n]); // expected-warning {{variable length array used}}
+
diff --git a/test/Sema/wchar.c b/test/Sema/wchar.c
index 8708aa0..816245f 100644
--- a/test/Sema/wchar.c
+++ b/test/Sema/wchar.c
@@ -6,7 +6,7 @@ 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)
+#elif defined(__arm) || defined(__aarch64__)
#define WCHAR_T_TYPE unsigned int
#elif defined(__sun) || defined(__AuroraUX__)
#define WCHAR_T_TYPE long
diff --git a/test/SemaCXX/MicrosoftExtensions.cpp b/test/SemaCXX/MicrosoftExtensions.cpp
index 6b43ea2..449e24b 100644
--- a/test/SemaCXX/MicrosoftExtensions.cpp
+++ b/test/SemaCXX/MicrosoftExtensions.cpp
@@ -204,3 +204,7 @@ struct PR11150 {
void f() { int __except = 0; }
void ::f(); // expected-warning{{extra qualification on member 'f'}}
+
+class C {
+ C::C(); // expected-warning{{extra qualification on member 'C'}}
+};
diff --git a/test/SemaCXX/address-of-temporary.cpp b/test/SemaCXX/address-of-temporary.cpp
index bb6cba3..5eef1c5 100644
--- a/test/SemaCXX/address-of-temporary.cpp
+++ b/test/SemaCXX/address-of-temporary.cpp
@@ -15,8 +15,13 @@ namespace PointerToArrayDecay {
struct Y {
int a[4];
};
+ struct Z {
+ int n;
+ ~Z();
+ };
typedef int A[4];
+ typedef Z AZ[4];
template<typename T> void consume(T);
struct S { int *p; };
@@ -25,11 +30,13 @@ namespace PointerToArrayDecay {
void g1() { int *p = Y{}.a; } // expected-warning{{pointer is initialized by a temporary array}}
void g2() { int *p = A{}; } // expected-warning{{pointer is initialized by a temporary array}}
void g3() { int *p = (A){}; } // expected-warning{{pointer is initialized by a temporary array}}
+ void g4() { Z *p = AZ{}; } // expected-warning{{pointer is initialized by a temporary array}}
void h0() { consume(Y().a); }
void h1() { consume(Y{}.a); }
void h2() { consume(A{}); }
void h3() { consume((A){}); }
+ void h4() { consume(AZ{}); }
void i0() { S s = { Y().a }; } // expected-warning{{pointer is initialized by a temporary array}}
void i1() { S s = { Y{}.a }; } // expected-warning{{pointer is initialized by a temporary array}}
diff --git a/test/SemaCXX/address-of.cpp b/test/SemaCXX/address-of.cpp
index 69fcaff..373e44c 100644
--- a/test/SemaCXX/address-of.cpp
+++ b/test/SemaCXX/address-of.cpp
@@ -22,12 +22,12 @@ enum E {
};
void test() {
- (void)&Enumerator; // expected-error{{address expression must be an lvalue or a function designator}}
+ (void)&Enumerator; // expected-error{{cannot take the address of an rvalue of type 'E'}}
}
template<int N>
void test2() {
- (void)&N; // expected-error{{address expression must be an lvalue or a function designator}}
+ (void)&N; // expected-error{{cannot take the address of an rvalue of type 'int'}}
}
// PR clang/3222
@@ -41,6 +41,14 @@ struct PR11066 {
};
void PR11066::test() {
- int (PR11066::*ptr)(int) = & &PR11066::foo; // expected-error{{address expression must be an lvalue or a function designator}}
+ int (PR11066::*ptr)(int) = & &PR11066::foo; // expected-error{{extra '&' taking address of overloaded function}}
}
+namespace test3 {
+ // emit no error
+ template<typename T> struct S {
+ virtual void f() = 0;
+ };
+ template<typename T> void S<T>::f() { T::error; }
+ void (S<int>::*p)() = &S<int>::f;
+}
diff --git a/test/SemaCXX/address-space-initialize.cpp b/test/SemaCXX/address-space-initialize.cpp
new file mode 100644
index 0000000..5091338
--- /dev/null
+++ b/test/SemaCXX/address-space-initialize.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+__attribute__((address_space(42)))
+const float withc = 1.0f;
+
+__attribute__((address_space(42)))
+volatile float withv = 1.0f;
+
+__attribute__((address_space(42)))
+float nocv = 1.0f;
+
+__attribute__((address_space(42)))
+float nocv_array[10] = { 1.0f };
+
+__attribute__((address_space(42)))
+int nocv_iarray[10] = { 4 };
+
+
+__attribute__((address_space(9999)))
+int* as_ptr = nocv_iarray; // expected-error{{cannot initialize a variable of type '__attribute__((address_space(9999))) int *' with an lvalue of type '__attribute__((address_space(42))) int [10]'}}
+
+
+__attribute__((address_space(42))) int* __attribute__((address_space(42))) ptr_in_same_addr_space = nocv_iarray;
+__attribute__((address_space(42))) int* __attribute__((address_space(999))) ptr_in_different_addr_space = nocv_iarray;
+
diff --git a/test/SemaCXX/alias-template.cpp b/test/SemaCXX/alias-template.cpp
index 4bf79f8..db9c82a 100644
--- a/test/SemaCXX/alias-template.cpp
+++ b/test/SemaCXX/alias-template.cpp
@@ -105,9 +105,7 @@ namespace TagName {
template<typename Z> using S = struct { int n; }; // expected-error {{can not be defined}}
template<typename Z> using T = class { int n; }; // expected-error {{can not be defined}}
template<typename Z> using U = enum { a, b, c }; // expected-error {{can not be defined}}
- template<typename Z> using V = struct V { int n; }; // expected-error {{redefinition of 'V' as different kind of symbol}} \
- expected-error {{'TagName::V' can not be defined in a type alias template}} \
- expected-note {{previous definition is here}}
+ template<typename Z> using V = struct V { int n; }; // expected-error {{'TagName::V' can not be defined in a type alias template}}
}
namespace StdExample {
diff --git a/test/SemaCXX/alignof-sizeof-reference.cpp b/test/SemaCXX/alignof-sizeof-reference.cpp
index ccdf45e..d76fcf5 100644
--- a/test/SemaCXX/alignof-sizeof-reference.cpp
+++ b/test/SemaCXX/alignof-sizeof-reference.cpp
@@ -4,8 +4,10 @@ struct s0; // expected-note {{forward declaration}}
char ar[sizeof(s0&)]; // expected-error {{invalid application of 'sizeof' to an incomplete type}}
void test() {
char &r = ar[0];
- static_assert(alignof(r) == 1, "bad alignment");
+ static_assert(alignof(r) == 1, "bad alignment"); // expected-warning {{GNU extension}}
+ static_assert(alignof(char&) == 1, "bad alignment");
static_assert(sizeof(r) == 1, "bad size");
+ static_assert(sizeof(char&) == 1, "bad size");
}
void f(); // expected-note{{possible target for call}}
@@ -18,5 +20,5 @@ void g() {
template<typename T> void f_template(); // expected-note{{possible target for call}}
template<typename T> void f_template(T*); // expected-note{{possible target for call}}
void rdar9659191() {
- (void)alignof(f_template<int>); // expected-error{{reference to overloaded function could not be resolved; did you mean to call it?}}
+ (void)alignof(f_template<int>); // expected-error{{reference to overloaded function could not be resolved; did you mean to call it?}} expected-warning {{GNU extension}}
}
diff --git a/test/SemaCXX/altivec.cpp b/test/SemaCXX/altivec.cpp
index 9de1f04..3517466 100644
--- a/test/SemaCXX/altivec.cpp
+++ b/test/SemaCXX/altivec.cpp
@@ -62,7 +62,7 @@ void test2()
vector float vf;
vf++;
- ++vi=vi;
+ ++vi=vi; // expected-warning {{unsequenced}}
(++vi)[1]=1;
template_f(vi);
}
diff --git a/test/SemaCXX/anonymous-struct.cpp b/test/SemaCXX/anonymous-struct.cpp
index 19a88d7..8a61041 100644
--- a/test/SemaCXX/anonymous-struct.cpp
+++ b/test/SemaCXX/anonymous-struct.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
struct S {
- S(); // expected-note {{because type 'S' has a user-declared constructor}}
+ S(); // expected-note {{because type 'S' has a user-provided default constructor}}
};
struct { // expected-error {{anonymous structs and classes must be class members}}
@@ -9,7 +9,7 @@ struct { // expected-error {{anonymous structs and classes must be class members
struct E {
struct {
- S x; // expected-error {{anonymous struct member 'x' has a non-trivial constructor}}
+ S x; // expected-error {{anonymous struct member 'x' has a non-trivial constructor}}
};
static struct {
};
diff --git a/test/SemaCXX/anonymous-union.cpp b/test/SemaCXX/anonymous-union.cpp
index 2dd7ab8..9c2cf24 100644
--- a/test/SemaCXX/anonymous-union.cpp
+++ b/test/SemaCXX/anonymous-union.cpp
@@ -9,7 +9,7 @@ struct X {
int i;
float f;
- union {
+ union { // expected-warning{{anonymous types declared in an anonymous union are an extension}}
float f2;
mutable double d;
};
@@ -101,7 +101,7 @@ void g() {
struct BadMembers {
union {
struct X { }; // expected-error {{types cannot be declared in an anonymous union}}
- struct { int x; int y; } y;
+ struct { int x; int y; } y; // expected-warning{{anonymous types declared in an anonymous union are an extension}}
void f(); // expected-error{{functions cannot be declared in an anonymous union}}
private: int x1; // expected-error{{anonymous union cannot contain a private data member}}
@@ -110,7 +110,7 @@ struct BadMembers {
};
// <rdar://problem/6481130>
-typedef union { }; // expected-warning{{declaration does not declare anything}}
+typedef union { }; // expected-warning{{typedef requires a name}}
// <rdar://problem/7562438>
typedef struct objc_module *Foo ;
@@ -128,7 +128,7 @@ namespace test4 {
struct { // expected-warning{{anonymous structs are a GNU extension}}
int s0; // expected-note {{declared private here}}
double s1; // expected-note {{declared private here}}
- union {
+ union { // expected-warning{{anonymous types declared in an anonymous struct are an extension}}
int su0; // expected-note {{declared private here}}
double su1; // expected-note {{declared private here}}
};
@@ -136,7 +136,7 @@ namespace test4 {
union {
int u0; // expected-note {{declared private here}}
double u1; // expected-note {{declared private here}}
- struct { // expected-warning{{anonymous structs are a GNU extension}}
+ struct { // expected-warning{{anonymous structs are a GNU extension}} expected-warning{{anonymous types declared in an anonymous union are an extension}}
int us0; // expected-note {{declared private here}}
double us1; // expected-note {{declared private here}}
};
@@ -187,7 +187,7 @@ namespace PR8326 {
private:
const union { // expected-warning{{anonymous union cannot be 'const'}}
- struct { // expected-warning{{anonymous structs are a GNU extension}}
+ struct { // expected-warning{{anonymous structs are a GNU extension}} expected-warning{{declared in an anonymous union}}
T x;
T y;
};
diff --git a/test/SemaCXX/array-bound-merge.cpp b/test/SemaCXX/array-bound-merge.cpp
index 8fb2ec5..c6085fb 100644
--- a/test/SemaCXX/array-bound-merge.cpp
+++ b/test/SemaCXX/array-bound-merge.cpp
@@ -9,3 +9,6 @@ extern int c[1];
int c[] = {1,2}; // expected-error {{excess elements in array initializer}}
int d[1][]; // expected-error {{array has incomplete element type 'int []'}}
+
+extern const int e[2]; // expected-note {{previous definition is here}}
+int e[] = { 1 }; // expected-error {{redefinition of 'e' with a different type: 'int []' vs 'const int [2]'}}
diff --git a/test/SemaCXX/array-bounds.cpp b/test/SemaCXX/array-bounds.cpp
index 57a9e3d..80b3ee4 100644
--- a/test/SemaCXX/array-bounds.cpp
+++ b/test/SemaCXX/array-bounds.cpp
@@ -74,11 +74,11 @@ void test() {
}
template <int I> struct S {
- char arr[I]; // expected-note 2 {{declared here}}
+ char arr[I]; // expected-note 3 {{declared here}}
};
template <int I> void f() {
S<3> s;
- s.arr[4] = 0; // expected-warning {{array index 4 is past the end of the array (which contains 3 elements)}}
+ s.arr[4] = 0; // expected-warning 2 {{array index 4 is past the end of the array (which contains 3 elements)}}
s.arr[I] = 0; // expected-warning {{array index 5 is past the end of the array (which contains 3 elements)}}
}
diff --git a/test/SemaCXX/ast-print.cpp b/test/SemaCXX/ast-print.cpp
index aeb4039..5de8c4b 100644
--- a/test/SemaCXX/ast-print.cpp
+++ b/test/SemaCXX/ast-print.cpp
@@ -81,3 +81,59 @@ struct test9
E a = A;
}
};
+
+namespace test10 {
+ namespace M {
+ template<typename T>
+ struct X {
+ enum { value };
+ };
+ }
+}
+
+typedef int INT;
+
+// CHECK: test11
+// CHECK-NEXT: return test10::M::X<INT>::value;
+int test11() {
+ return test10::M::X<INT>::value;
+}
+
+
+struct DefaultArgClass
+{
+ DefaultArgClass(int a = 1) {}
+};
+
+struct NoArgClass
+{
+ NoArgClass() {}
+};
+
+struct VirualDestrClass
+{
+ VirualDestrClass(int arg);
+ virtual ~VirualDestrClass();
+};
+
+struct ConstrWithCleanupsClass
+{
+ ConstrWithCleanupsClass(const VirualDestrClass& cplx = VirualDestrClass(42));
+};
+
+// CHECK: test12
+// CHECK-NEXT: DefaultArgClass useDefaultArg;
+// CHECK-NEXT: DefaultArgClass overrideDefaultArg(1);
+// CHECK-NEXT: NoArgClass noArg;
+// CHECK-NEXT: ConstrWithCleanupsClass cwcNoArg;
+// CHECK-NEXT: ConstrWithCleanupsClass cwcOverrideArg(48);
+// CHECK-NEXT: ConstrWithCleanupsClass cwcExplicitArg(VirualDestrClass(56));
+void test12() {
+ DefaultArgClass useDefaultArg;
+ DefaultArgClass overrideDefaultArg(1);
+ NoArgClass noArg;
+ ConstrWithCleanupsClass cwcNoArg;
+ ConstrWithCleanupsClass cwcOverrideArg(48);
+ ConstrWithCleanupsClass cwcExplicitArg(VirualDestrClass(56));
+}
+
diff --git a/test/SemaCXX/atomic-type.cxx b/test/SemaCXX/atomic-type.cxx
index 18707eb..947bb3c 100644
--- a/test/SemaCXX/atomic-type.cxx
+++ b/test/SemaCXX/atomic-type.cxx
@@ -1,7 +1,9 @@
-// RUN: %clang_cc1 -verify %s
+// RUN: %clang_cc1 -verify -pedantic %s
template<typename T> struct atomic {
_Atomic(T) value;
+
+ void f() _Atomic; // expected-error {{expected ';' at end of declaration list}}
};
template<typename T> struct user {
@@ -15,9 +17,11 @@ user<int> u;
struct A { };
int &ovl1(_Atomic(int));
+int &ovl1(_Atomic int); // ok, redeclaration
long &ovl1(_Atomic(long));
float &ovl1(_Atomic(float));
double &ovl1(_Atomic(A const *const *));
+double &ovl1(A const *const *_Atomic);
short &ovl1(_Atomic(A **));
void test_overloading(int i, float f, _Atomic(int) ai, _Atomic(float) af,
@@ -33,3 +37,22 @@ void test_overloading(int i, float f, _Atomic(int) ai, _Atomic(float) af,
double &dr2 = ovl1(ac);
short &sr1 = ovl1(a);
}
+
+typedef int (A::*fp)() _Atomic; // expected-error {{expected ';' after top level declarator}} expected-warning {{does not declare anything}}
+
+typedef _Atomic(int(A::*)) atomic_mem_ptr_to_int;
+typedef int(A::*_Atomic atomic_mem_ptr_to_int);
+
+typedef _Atomic(int)(A::*mem_ptr_to_atomic_int);
+typedef _Atomic int(A::*mem_ptr_to_atomic_int);
+
+typedef _Atomic(int)&atomic_int_ref;
+typedef _Atomic int &atomic_int_ref;
+typedef _Atomic atomic_int_ref atomic_int_ref; // ok, qualifiers on references ignored in this case.
+
+typedef int &_Atomic atomic_reference_to_int; // expected-error {{'_Atomic' qualifier may not be applied to a reference}}
+typedef _Atomic(int &) atomic_reference_to_int; // expected-error {{_Atomic cannot be applied to reference type 'int &'}}
+
+struct S {
+ _Atomic union { int n; }; // expected-warning {{anonymous union cannot be '_Atomic'}}
+};
diff --git a/test/SemaCXX/attr-cxx0x.cpp b/test/SemaCXX/attr-cxx0x.cpp
index 4281895..e9276cd 100644
--- a/test/SemaCXX/attr-cxx0x.cpp
+++ b/test/SemaCXX/attr-cxx0x.cpp
@@ -1,32 +1,47 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -pedantic -std=c++11 %s
int align_illegal alignas(3); //expected-error {{requested alignment is not a power of 2}}
char align_big alignas(int);
-int align_small alignas(1); // FIXME: this should be rejected
+int align_small alignas(1); // expected-error {{requested alignment is less than minimum}}
int align_multiple alignas(1) alignas(8) alignas(1);
+alignas(4) int align_before;
struct align_member {
int member alignas(8);
+ int bitfield alignas(1) : 1; // expected-error {{}}
};
+void f(alignas(1) char c) { // expected-error {{'alignas' attribute cannot be applied to a function parameter}}
+ alignas(1) register char k; // expected-error {{'alignas' attribute cannot be applied to a variable with 'register' storage class}}
+ try {
+ } catch (alignas(4) int n) { // expected-error {{'alignas' attribute cannot be applied to a 'catch' variable}}
+ }
+}
+
+
template <unsigned A> struct alignas(A) align_class_template {};
-// FIXME: these should not error
-template <typename... T> alignas(T...) struct align_class_temp_pack_type {}; // expected-error{{pack expansions in alignment specifiers are not supported yet}}
-template <unsigned... A> alignas(A...) struct align_class_temp_pack_expr {}; // expected-error{{pack expansions in alignment specifiers are not supported yet}}
+template <typename... T> struct alignas(T...) align_class_temp_pack_type {};
+template <unsigned... A> struct alignas(A...) align_class_temp_pack_expr {};
+struct alignas(int...) alignas_expansion_no_packs {}; // expected-error {{pack expansion does not contain any unexpanded parameter packs}}
+template <typename... A> struct outer {
+ template <typename... B> struct alignas(alignof(A) * alignof(B)...) inner {};
+ // expected-error@-1 {{pack expansion contains parameter packs 'A' and 'B' that have different lengths (1 vs. 2)}}
+};
+outer<int>::inner<short, double> mismatched_packs; // expected-note {{in instantiation of}}
-typedef char align_typedef alignas(8);
-template<typename T> using align_alias_template = align_typedef;
+typedef char align_typedef alignas(8); // expected-error {{'alignas' attribute only applies to variables, data members and tag types}}
+template<typename T> using align_alias_template = align_typedef alignas(8); // expected-error {{'alignas' attribute cannot be applied to types}}
-static_assert(alignof(align_big) == alignof(int), "k's alignment is wrong");
-static_assert(alignof(align_small) == 1, "j's alignment is wrong");
-static_assert(alignof(align_multiple) == 8, "l's alignment is wrong");
+static_assert(alignof(align_big) == alignof(int), "k's alignment is wrong"); // expected-warning{{'alignof' applied to an expression is a GNU extension}}
+static_assert(alignof(align_small) == 1, "j's alignment is wrong"); // expected-warning{{'alignof' applied to an expression is a GNU extension}}
+static_assert(alignof(align_multiple) == 8, "l's alignment is wrong"); // expected-warning{{'alignof' applied to an expression is a GNU extension}}
static_assert(alignof(align_member) == 8, "quuux's alignment is wrong");
static_assert(sizeof(align_member) == 8, "quuux's size is wrong");
-static_assert(alignof(align_typedef) == 8, "typedef's alignment is wrong");
static_assert(alignof(align_class_template<8>) == 8, "template's alignment is wrong");
static_assert(alignof(align_class_template<16>) == 16, "template's alignment is wrong");
-// FIXME: enable these tests
-// static_assert(alignof(align_class_temp_pack_type<short, int, long>) == alignof(long), "template's alignment is wrong");
-// static_assert(alignof(align_class_temp_pack_expr<8, 16, 32>) == 32, "template's alignment is wrong");
-static_assert(alignof(align_alias_template<int>) == 8, "alias template's alignment is wrong");
+static_assert(alignof(align_class_temp_pack_type<short, int, long>) == alignof(long), "template's alignment is wrong");
+static_assert(alignof(align_class_temp_pack_expr<8, 16, 32>) == 32, "template's alignment is wrong");
+static_assert(alignof(outer<int,char>::inner<double,short>) == alignof(int) * alignof(double), "template's alignment is wrong");
+
+static_assert(alignof(int(int)) >= 1, "alignof(function) not positive"); // expected-warning{{invalid application of 'alignof' to a function type}}
diff --git a/test/SemaCXX/attr-deprecated.cpp b/test/SemaCXX/attr-deprecated.cpp
index f3d818a..d09faf3 100644
--- a/test/SemaCXX/attr-deprecated.cpp
+++ b/test/SemaCXX/attr-deprecated.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -verify -fsyntax-only
+// RUN: %clang_cc1 %s -verify -fexceptions
class A {
void f() __attribute__((deprecated)); // expected-note 2 {{declared here}}
void g(A* a);
@@ -233,3 +233,14 @@ namespace test6 {
x = D<int>::d1; // expected-warning {{'d1' is deprecated}}
}
}
+
+namespace test7 {
+ struct X {
+ void* operator new(typeof(sizeof(void*))) __attribute__((deprecated)); // expected-note{{'operator new' declared here}}
+ void operator delete(void *) __attribute__((deprecated)); // expected-note{{'operator delete' declared here}}
+ };
+
+ void test() {
+ X *x = new X; // expected-warning{{'operator new' is deprecated}} expected-warning{{'operator delete' is deprecated}}
+ }
+}
diff --git a/test/SemaCXX/attr-no-sanitize-address.cpp b/test/SemaCXX/attr-no-sanitize-address.cpp
new file mode 100644
index 0000000..dc4d797
--- /dev/null
+++ b/test/SemaCXX/attr-no-sanitize-address.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+#define NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
+
+#if !__has_attribute(no_sanitize_address)
+#error "Should support no_sanitize_address"
+#endif
+
+void noanal_fun() NO_SANITIZE_ADDRESS;
+
+void noanal_fun_args() __attribute__((no_sanitize_address(1))); // \
+ // expected-error {{attribute takes no arguments}}
+
+int noanal_testfn(int y) NO_SANITIZE_ADDRESS;
+
+int noanal_testfn(int y) {
+ int x NO_SANITIZE_ADDRESS = y; // \
+ // expected-error {{'no_sanitize_address' attribute only applies to functions and methods}}
+ return x;
+}
+
+int noanal_test_var NO_SANITIZE_ADDRESS; // \
+ // expected-error {{'no_sanitize_address' attribute only applies to functions and methods}}
+
+class NoanalFoo {
+ private:
+ int test_field NO_SANITIZE_ADDRESS; // \
+ // expected-error {{'no_sanitize_address' attribute only applies to functions and methods}}
+ void test_method() NO_SANITIZE_ADDRESS;
+};
+
+class NO_SANITIZE_ADDRESS NoanalTestClass { // \
+ // expected-error {{'no_sanitize_address' attribute only applies to functions and methods}}
+};
+
+void noanal_fun_params(int lvar NO_SANITIZE_ADDRESS); // \
+ // expected-error {{'no_sanitize_address' attribute only applies to functions and methods}}
diff --git a/test/SemaCXX/attr-no-sanitize-memory.cpp b/test/SemaCXX/attr-no-sanitize-memory.cpp
new file mode 100644
index 0000000..84acdac
--- /dev/null
+++ b/test/SemaCXX/attr-no-sanitize-memory.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+#define NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
+
+#if !__has_attribute(no_sanitize_memory)
+#error "Should support no_sanitize_memory"
+#endif
+
+void noanal_fun() NO_SANITIZE_MEMORY;
+
+void noanal_fun_args() __attribute__((no_sanitize_memory(1))); // \
+ // expected-error {{attribute takes no arguments}}
+
+int noanal_testfn(int y) NO_SANITIZE_MEMORY;
+
+int noanal_testfn(int y) {
+ int x NO_SANITIZE_MEMORY = y; // \
+ // expected-error {{'no_sanitize_memory' attribute only applies to functions and methods}}
+ return x;
+}
+
+int noanal_test_var NO_SANITIZE_MEMORY; // \
+ // expected-error {{'no_sanitize_memory' attribute only applies to functions and methods}}
+
+class NoanalFoo {
+ private:
+ int test_field NO_SANITIZE_MEMORY; // \
+ // expected-error {{'no_sanitize_memory' attribute only applies to functions and methods}}
+ void test_method() NO_SANITIZE_MEMORY;
+};
+
+class NO_SANITIZE_MEMORY NoanalTestClass { // \
+ // expected-error {{'no_sanitize_memory' attribute only applies to functions and methods}}
+};
+
+void noanal_fun_params(int lvar NO_SANITIZE_MEMORY); // \
+ // expected-error {{'no_sanitize_memory' attribute only applies to functions and methods}}
diff --git a/test/SemaCXX/attr-no-sanitize-thread.cpp b/test/SemaCXX/attr-no-sanitize-thread.cpp
new file mode 100644
index 0000000..50960c4
--- /dev/null
+++ b/test/SemaCXX/attr-no-sanitize-thread.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+#define NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
+
+#if !__has_attribute(no_sanitize_thread)
+#error "Should support no_sanitize_thread"
+#endif
+
+void noanal_fun() NO_SANITIZE_THREAD;
+
+void noanal_fun_args() __attribute__((no_sanitize_thread(1))); // \
+ // expected-error {{attribute takes no arguments}}
+
+int noanal_testfn(int y) NO_SANITIZE_THREAD;
+
+int noanal_testfn(int y) {
+ int x NO_SANITIZE_THREAD = y; // \
+ // expected-error {{'no_sanitize_thread' attribute only applies to functions and methods}}
+ return x;
+}
+
+int noanal_test_var NO_SANITIZE_THREAD; // \
+ // expected-error {{'no_sanitize_thread' attribute only applies to functions and methods}}
+
+class NoanalFoo {
+ private:
+ int test_field NO_SANITIZE_THREAD; // \
+ // expected-error {{'no_sanitize_thread' attribute only applies to functions and methods}}
+ void test_method() NO_SANITIZE_THREAD;
+};
+
+class NO_SANITIZE_THREAD NoanalTestClass { // \
+ // expected-error {{'no_sanitize_thread' attribute only applies to functions and methods}}
+};
+
+void noanal_fun_params(int lvar NO_SANITIZE_THREAD); // \
+ // expected-error {{'no_sanitize_thread' attribute only applies to functions and methods}}
diff --git a/test/SemaCXX/attr-nonnull.cpp b/test/SemaCXX/attr-nonnull.cpp
index 09c054c1..8af49d9 100644
--- a/test/SemaCXX/attr-nonnull.cpp
+++ b/test/SemaCXX/attr-nonnull.cpp
@@ -31,3 +31,24 @@ namespace rdar8769025 {
f2(0, 0); // expected-warning{{null passed to a callee which requires a non-null argument}}
}
}
+
+namespace test3 {
+__attribute__((nonnull(1))) void f(void *ptr);
+
+void g() {
+ f(static_cast<char*>((void*)0)); // expected-warning{{null passed}}
+ f(static_cast<char*>(0)); // expected-warning{{null passed}}
+}
+}
+
+namespace test4 {
+struct X {
+ bool operator!=(const void *) const __attribute__((nonnull(2)));
+};
+bool operator==(const X&, const void *) __attribute__((nonnull(2)));
+
+void test(const X& x) {
+ (void)(x == 0); // expected-warning{{null passed}}
+ (void)(x != 0); // expected-warning{{null passed}}
+}
+}
diff --git a/test/SemaCXX/attr-print.cpp b/test/SemaCXX/attr-print.cpp
new file mode 100644
index 0000000..2e74789
--- /dev/null
+++ b/test/SemaCXX/attr-print.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 %s -ast-print -fms-extensions | FileCheck %s
+
+// CHECK: int x __attribute__((aligned(4)));
+int x __attribute__((aligned(4)));
+
+// FIXME: Print this at a valid location for a __declspec attr.
+// CHECK: int y __declspec(align(4));
+__declspec(align(4)) int y;
+
+// CHECK: void foo() __attribute__((const));
+void foo() __attribute__((const));
+
+// CHECK: void bar() __attribute__((__const));
+void bar() __attribute__((__const));
+
+// FIXME: Print this with correct format and order.
+// CHECK: void foo1() __attribute__((pure)) __attribute__((noinline));
+void foo1() __attribute__((noinline, pure));
diff --git a/test/SemaCXX/attr-regparm.cpp b/test/SemaCXX/attr-regparm.cpp
index 91ee613..92e651b 100644
--- a/test/SemaCXX/attr-regparm.cpp
+++ b/test/SemaCXX/attr-regparm.cpp
@@ -11,5 +11,5 @@ struct X0 {
void X0::f0() { }
void __attribute__((regparm(3))) X0::f1() { }
-void __attribute__((regparm(2))) X0::f2() { } // expected-error{{function declared with with regparm(2) attribute was previously declared with the regparm(3) attribute}}
-void __attribute__((regparm(2))) X0::f3() { } // expected-error{{function declared with with regparm(2) attribute was previously declared without the regparm attribute}}
+void __attribute__((regparm(2))) X0::f2() { } // expected-error{{function declared with regparm(2) attribute was previously declared with the regparm(3) attribute}}
+void __attribute__((regparm(2))) X0::f3() { } // expected-error{{function declared with regparm(2) attribute was previously declared without the regparm attribute}}
diff --git a/test/SemaCXX/attr-weak.cpp b/test/SemaCXX/attr-weak.cpp
index b6a9e0a..8939a28 100644
--- a/test/SemaCXX/attr-weak.cpp
+++ b/test/SemaCXX/attr-weak.cpp
@@ -21,9 +21,16 @@ namespace {
};
}
+// GCC rejects the instantiation with the internal type, but some existing
+// code expects it. It is also not that different from giving hidden visibility
+// to parts of a template that have explicit default visibility, so we accept
+// this.
template <class T> struct Test7 {
void test7() __attribute__((weak)) {}
+ static int var __attribute__((weak));
};
+template <class T>
+int Test7<T>::var;
namespace { class Internal; }
template struct Test7<Internal>;
template struct Test7<int>;
diff --git a/test/SemaCXX/attr-weakref.cpp b/test/SemaCXX/attr-weakref.cpp
index a345791..f3d7a62 100644
--- a/test/SemaCXX/attr-weakref.cpp
+++ b/test/SemaCXX/attr-weakref.cpp
@@ -28,4 +28,7 @@ int a7() __attribute__((weakref ("f1"))); // expected-error {{weakref declaratio
int a8 __attribute__((weakref ("v1"))); // expected-error {{weakref declaration must have internal linkage}}
// gcc accepts this
-int a9 __attribute__((weakref)); // expected-error {{weakref declaration must have internal linkage}}
+int a9 __attribute__((weakref)); // expected-error {{weakref declaration of 'a9' must also have an alias attribute}}
+
+static int a10();
+int a10() __attribute__((weakref ("foo")));
diff --git a/test/SemaCXX/auto-pragma.cpp b/test/SemaCXX/auto-pragma.cpp
new file mode 100644
index 0000000..1cd0781
--- /dev/null
+++ b/test/SemaCXX/auto-pragma.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -ast-dump -ast-dump-filter AutoVar | FileCheck %s
+
+namespace {
+ class foo {
+ };
+}
+
+#pragma GCC visibility push(hidden)
+auto AutoVar = foo();
+
+// CHECK: VarDecl {{.*}} AutoVar
+// CHECK-NOT: VisibilityAttr
diff --git a/test/SemaCXX/blocks.cpp b/test/SemaCXX/blocks.cpp
index 3f81c27..a2672d1 100644
--- a/test/SemaCXX/blocks.cpp
+++ b/test/SemaCXX/blocks.cpp
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -fblocks
-// expected-no-diagnostics
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s -fblocks
void tovoid(void*);
@@ -69,3 +68,35 @@ namespace radar8382559 {
return hasProperty = 1;
}
}
+
+// Move __block variables to the heap when possible.
+class MoveOnly {
+public:
+ MoveOnly();
+ MoveOnly(const MoveOnly&) = delete;
+ MoveOnly(MoveOnly&&);
+};
+
+void move_block() {
+ __block MoveOnly mo;
+}
+
+// Don't crash after failing to build a block due to a capture of an
+// invalid declaration.
+namespace test5 {
+ struct B { // expected-note 2 {{candidate constructor}}
+ void *p;
+ B(int); // expected-note {{candidate constructor}}
+ };
+
+ void use_block(void (^)());
+ void use_block_2(void (^)(), const B &a);
+
+ void test() {
+ B x; // expected-error {{no matching constructor for initialization}}
+ use_block(^{
+ int y;
+ use_block_2(^{ (void) y; }, x);
+ });
+ }
+}
diff --git a/test/SemaCXX/borland-extensions.cpp b/test/SemaCXX/borland-extensions.cpp
index 1e4bd45..d214473 100644
--- a/test/SemaCXX/borland-extensions.cpp
+++ b/test/SemaCXX/borland-extensions.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify -fborland-extensions
-// expected-no-diagnostics
+// RUN: %clang_cc1 %s -fsyntax-only -fborland-extensions -triple x86_64-linux-gnu -verify
+// RUN: %clang_cc1 %s -fsyntax-only -fborland-extensions -triple i686-linux-gnu -Werror
// Borland extensions
@@ -7,15 +7,21 @@
int dummy_function() { return 0; }
// 2. test __pascal
+// expected-warning@+1 {{calling convention '_pascal' ignored for this target}}
int _pascal f2();
+// expected-warning@+1 {{calling convention '__pascal' ignored for this target}}
float __pascal gi2(int, int);
+// expected-warning@+1 {{calling convention '__pascal' ignored for this target}}
template<typename T> T g2(T (__pascal * const )(int, int)) { return 0; }
struct M {
+ // expected-warning@+1 {{calling convention '__pascal' ignored for this target}}
int __pascal addP();
+ // expected-warning@+1 {{calling convention '__pascal' ignored for this target}}
float __pascal subtractP();
};
+// expected-warning@+1 {{calling convention '__pascal' ignored for this target}}
template<typename T> int h2(T (__pascal M::* const )()) { return 0; }
void m2() {
int i; float f;
@@ -28,7 +34,9 @@ void m2() {
// 3. test other calling conventions
int _cdecl fa3();
+// expected-warning@+1 {{calling convention '_fastcall' ignored for this target}}
int _fastcall fc3();
+// expected-warning@+1 {{calling convention '_stdcall' ignored for this target}}
int _stdcall fd3();
// 4. test __uuidof()
diff --git a/test/SemaCXX/builtins.cpp b/test/SemaCXX/builtins.cpp
index 6b055cf..5d61690 100644
--- a/test/SemaCXX/builtins.cpp
+++ b/test/SemaCXX/builtins.cpp
@@ -20,3 +20,7 @@ template int equal<&__builtin_strcmp>(const char*, const char*); // expected-err
void f2() {
__builtin_isnan; // expected-error {{builtin functions must be directly called}}
}
+
+// pr14895
+typedef __typeof(sizeof(int)) size_t;
+extern "C" void *__builtin_alloca (size_t);
diff --git a/test/SemaCXX/c99-variable-length-array-cxx11.cpp b/test/SemaCXX/c99-variable-length-array-cxx11.cpp
new file mode 100644
index 0000000..03cf283
--- /dev/null
+++ b/test/SemaCXX/c99-variable-length-array-cxx11.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wvla-extension %s
+struct StillPOD {
+ StillPOD() = default;
+};
+
+struct StillPOD2 {
+ StillPOD np;
+};
+
+struct NonPOD {
+ NonPOD(int) {}
+};
+
+struct POD {
+ int x;
+ int y;
+};
+
+// We allow VLAs of POD types, only.
+void vla(int N) {
+ int array1[N]; // expected-warning{{variable length arrays are a C99 feature}}
+ POD array2[N]; // expected-warning{{variable length arrays are a C99 feature}}
+ StillPOD array3[N]; // expected-warning{{variable length arrays are a C99 feature}}
+ StillPOD2 array4[N][3]; // expected-warning{{variable length arrays are a C99 feature}}
+ NonPOD array5[N]; // expected-error{{variable length array of non-POD element type 'NonPOD'}}
+}
diff --git a/test/SemaCXX/c99-variable-length-array.cpp b/test/SemaCXX/c99-variable-length-array.cpp
index 7773c08..bb620c7 100644
--- a/test/SemaCXX/c99-variable-length-array.cpp
+++ b/test/SemaCXX/c99-variable-length-array.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wvla %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wvla-extension %s
struct NonPOD {
NonPOD();
};
@@ -64,8 +64,9 @@ X1<HasConstantValue> x1a;
X1<HasNonConstantValue> x1b; // expected-note{{in instantiation of}}
// Template argument deduction does not allow deducing a size from a VLA.
+// FIXME: This diagnostic should make it clear that the two 'N's are different entities!
template<typename T, unsigned N>
-void accept_array(T (&array)[N]); // expected-note{{candidate template ignored: failed template argument deduction}}
+void accept_array(T (&array)[N]); // expected-note{{candidate template ignored: could not match 'T [N]' against 'int [N]'}}
void test_accept_array(int N) {
int array[N]; // expected-warning{{variable length arrays are a C99 feature}}
diff --git a/test/SemaCXX/class-base-member-init.cpp b/test/SemaCXX/class-base-member-init.cpp
index e84e57b..2cdca82 100644
--- a/test/SemaCXX/class-base-member-init.cpp
+++ b/test/SemaCXX/class-base-member-init.cpp
@@ -90,3 +90,11 @@ namespace test5 {
}
};
}
+
+namespace rdar13185264 {
+ class X {
+ X() : a(), // expected-note{{previous initialization is here}}
+ a() { } // expected-error{{multiple initializations given for non-static member 'a'}}
+ union { void *a; };
+ };
+}
diff --git a/test/SemaCXX/compare.cpp b/test/SemaCXX/compare.cpp
index 432069f..feb1ccb 100644
--- a/test/SemaCXX/compare.cpp
+++ b/test/SemaCXX/compare.cpp
@@ -1,7 +1,7 @@
// Force x86-64 because some of our heuristics are actually based
// on integer sizes.
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -pedantic -verify -Wsign-compare %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -pedantic -verify -Wsign-compare -std=c++11 %s
int test0(long a, unsigned long b) {
enum EnumA {A};
@@ -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) + // 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}}
+ (C == (unsigned short) b) + // expected-warning {{comparison of constant 'C' (65536) with expression of type 'unsigned short' is always false}}
+ (C == (unsigned char) b) + // expected-warning {{comparison of constant 'C' (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) + // 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}}
+ (C < (unsigned short) b) + // expected-warning {{comparison of constant 'C' (65536) with expression of type 'unsigned short' is always false}}
+ (C < (unsigned char) b) + // expected-warning {{comparison of constant 'C' (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) + // 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}}
+ ((short) a == C) + // expected-warning {{comparison of constant 'C' (65536) with expression of type 'short' is always false}}
+ ((signed char) a == C) + // expected-warning {{comparison of constant 'C' (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) + // 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}}
+ ((short) a < C) + // expected-warning {{comparison of constant 'C' (65536) with expression of type 'short' is always true}}
+ ((signed char) a < C) + // expected-warning {{comparison of constant 'C' (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) +
@@ -223,3 +223,135 @@ void test3() {
(void) (true ? b : a);
(void) (true ? (unsigned char)b : (signed char)a);
}
+
+// Test comparison of short to unsigned. If tautological compare does not
+// trigger, then the signed comparision warning will.
+void test4(short s) {
+ // A is max short plus 1. All zero and positive shorts are smaller than it.
+ // All negative shorts are cast towards the max unsigned range. Relation
+ // comparisons are possible, but equality comparisons are tautological.
+ const unsigned A = 32768;
+ void (s < A); // expected-warning{{comparison of integers of different signs: 'short' and 'const unsigned int'}}
+ void (s > A); // expected-warning{{comparison of integers of different signs: 'short' and 'const unsigned int'}}
+ void (s <= A); // expected-warning{{comparison of integers of different signs: 'short' and 'const unsigned int'}}
+ void (s >= A); // expected-warning{{comparison of integers of different signs: 'short' and 'const unsigned int'}}
+
+ void (s == A); // expected-warning{{comparison of constant 32768 with expression of type 'short' is always false}}
+ void (s != A); // expected-warning{{comparison of constant 32768 with expression of type 'short' is always true}}
+
+ // When negative one is converted to an unsigned value, it becomes the max
+ // unsigned. Likewise, a negative one short can also be converted to max
+ // unsigned.
+ const unsigned B = -1;
+ void (s < B); // expected-warning{{comparison of integers of different signs: 'short' and 'const unsigned int'}}
+ void (s > B); // expected-warning{{comparison of integers of different signs: 'short' and 'const unsigned int'}}
+ void (s <= B); // expected-warning{{comparison of integers of different signs: 'short' and 'const unsigned int'}}
+ void (s >= B); // expected-warning{{comparison of integers of different signs: 'short' and 'const unsigned int'}}
+ void (s == B); // expected-warning{{comparison of integers of different signs: 'short' and 'const unsigned int'}}
+ void (s != B); // expected-warning{{comparison of integers of different signs: 'short' and 'const unsigned int'}}
+
+}
+
+void test5(bool b) {
+ (void) (b < -1); // expected-warning{{comparison of constant -1 with expression of type 'bool' is always false}}
+ (void) (b > -1); // expected-warning{{comparison of constant -1 with expression of type 'bool' is always true}}
+ (void) (b == -1); // expected-warning{{comparison of constant -1 with expression of type 'bool' is always false}}
+ (void) (b != -1); // expected-warning{{comparison of constant -1 with expression of type 'bool' is always true}}
+ (void) (b <= -1); // expected-warning{{comparison of constant -1 with expression of type 'bool' is always false}}
+ (void) (b >= -1); // expected-warning{{comparison of constant -1 with expression of type 'bool' is always true}}
+
+ (void) (b < -10); // expected-warning{{comparison of constant -10 with expression of type 'bool' is always false}}
+ (void) (b > -10); // expected-warning{{comparison of constant -10 with expression of type 'bool' is always true}}
+ (void) (b == -10); // expected-warning{{comparison of constant -10 with expression of type 'bool' is always false}}
+ (void) (b != -10); // expected-warning{{comparison of constant -10 with expression of type 'bool' is always true}}
+ (void) (b <= -10); // expected-warning{{comparison of constant -10 with expression of type 'bool' is always false}}
+ (void) (b >= -10); // expected-warning{{comparison of constant -10 with expression of type 'bool' is always true}}
+
+ (void) (b < 2); // expected-warning{{comparison of constant 2 with expression of type 'bool' is always true}}
+ (void) (b > 2); // expected-warning{{comparison of constant 2 with expression of type 'bool' is always false}}
+ (void) (b == 2); // expected-warning{{comparison of constant 2 with expression of type 'bool' is always false}}
+ (void) (b != 2); // expected-warning{{comparison of constant 2 with expression of type 'bool' is always true}}
+ (void) (b <= 2); // expected-warning{{comparison of constant 2 with expression of type 'bool' is always true}}
+ (void) (b >= 2); // expected-warning{{comparison of constant 2 with expression of type 'bool' is always false}}
+
+ (void) (b < 10); // expected-warning{{comparison of constant 10 with expression of type 'bool' is always true}}
+ (void) (b > 10); // expected-warning{{comparison of constant 10 with expression of type 'bool' is always false}}
+ (void) (b == 10); // expected-warning{{comparison of constant 10 with expression of type 'bool' is always false}}
+ (void) (b != 10); // expected-warning{{comparison of constant 10 with expression of type 'bool' is always true}}
+ (void) (b <= 10); // expected-warning{{comparison of constant 10 with expression of type 'bool' is always true}}
+ (void) (b >= 10); // expected-warning{{comparison of constant 10 with expression of type 'bool' is always false}}
+}
+
+void test6(signed char sc) {
+ (void)(sc < 200); // expected-warning{{comparison of constant 200 with expression of type 'signed char' is always true}}
+ (void)(sc > 200); // expected-warning{{comparison of constant 200 with expression of type 'signed char' is always false}}
+ (void)(sc <= 200); // expected-warning{{comparison of constant 200 with expression of type 'signed char' is always true}}
+ (void)(sc >= 200); // expected-warning{{comparison of constant 200 with expression of type 'signed char' is always false}}
+ (void)(sc == 200); // expected-warning{{comparison of constant 200 with expression of type 'signed char' is always false}}
+ (void)(sc != 200); // expected-warning{{comparison of constant 200 with expression of type 'signed char' is always true}}
+
+ (void)(200 < sc); // expected-warning{{comparison of constant 200 with expression of type 'signed char' is always false}}
+ (void)(200 > sc); // expected-warning{{comparison of constant 200 with expression of type 'signed char' is always true}}
+ (void)(200 <= sc); // expected-warning{{comparison of constant 200 with expression of type 'signed char' is always false}}
+ (void)(200 >= sc); // expected-warning{{comparison of constant 200 with expression of type 'signed char' is always true}}
+ (void)(200 == sc); // expected-warning{{comparison of constant 200 with expression of type 'signed char' is always false}}
+ (void)(200 != sc); // expected-warning{{comparison of constant 200 with expression of type 'signed char' is always true}}
+}
+
+// Test many signedness combinations.
+void test7(unsigned long other) {
+ // Common unsigned, other unsigned, constant unsigned
+ (void)((unsigned)other != (unsigned long)(0x1ffffffff)); // expected-warning{{true}}
+ (void)((unsigned)other != (unsigned long)(0xffffffff));
+ (void)((unsigned long)other != (unsigned)(0x1ffffffff));
+ (void)((unsigned long)other != (unsigned)(0xffffffff));
+
+ // Common unsigned, other signed, constant unsigned
+ (void)((int)other != (unsigned long)(0xffffffffffffffff)); // expected-warning{{different signs}}
+ (void)((int)other != (unsigned long)(0x00000000ffffffff)); // expected-warning{{true}}
+ (void)((int)other != (unsigned long)(0x000000000fffffff));
+ (void)((int)other < (unsigned long)(0x00000000ffffffff)); // expected-warning{{different signs}}
+ (void)((int)other == (unsigned)(0x800000000));
+
+ // Common unsigned, other unsigned, constant signed
+ (void)((unsigned long)other != (int)(0xffffffff)); // expected-warning{{different signs}}
+
+ // Common unsigned, other signed, constant signed
+ // Should not be possible as the common type should also be signed.
+
+ // Common signed, other signed, constant signed
+ (void)((int)other != (long)(0xffffffff)); // expected-warning{{true}}
+ (void)((int)other != (long)(0xffffffff00000000)); // expected-warning{{true}}
+ (void)((int)other != (long)(0xfffffff));
+ (void)((int)other != (long)(0xfffffffff0000000));
+
+ // Common signed, other signed, constant unsigned
+ (void)((int)other != (unsigned char)(0xffff));
+ (void)((int)other != (unsigned char)(0xff));
+
+ // Common signed, other unsigned, constant signed
+ (void)((unsigned char)other != (int)(0xff));
+ (void)((unsigned char)other != (int)(0xffff)); // expected-warning{{true}}
+
+ // Common signed, other unsigned, constant unsigned
+ (void)((unsigned char)other != (unsigned short)(0xff));
+ (void)((unsigned char)other != (unsigned short)(0x100)); // expected-warning{{true}}
+ (void)((unsigned short)other != (unsigned char)(0xff));
+}
+
+void test8(int x) {
+ enum E {
+ Negative = -1,
+ Positive = 1
+ };
+
+ (void)((E)x == 1);
+ (void)((E)x == -1);
+}
+
+void test9(int x) {
+ enum E : int {
+ Positive = 1
+ };
+ (void)((E)x == 1);
+}
diff --git a/test/SemaCXX/condition.cpp b/test/SemaCXX/condition.cpp
index ec5eb17..d805881 100644
--- a/test/SemaCXX/condition.cpp
+++ b/test/SemaCXX/condition.cpp
@@ -19,7 +19,7 @@ void test() {
while (struct NewS *x=0) ;
while (struct S {} *x=0) ; // expected-error {{types may not be defined in conditions}}
while (struct {} *x=0) ; // expected-error {{types may not be defined in conditions}}
- switch (enum {E} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{cannot initialize}} \
+ switch (enum {E} x=0) ; // expected-error {{types may not be defined in conditions}} \
// expected-warning{{enumeration value 'E' not handled in switch}} expected-warning {{switch statement has empty body}} \
// expected-note{{put the semicolon on a separate line}}
@@ -58,3 +58,12 @@ void test3() {
void test4(bool (&x)(void)) {
while (x);
}
+
+template <class>
+void test5() {
+ if (struct S {}* p = 0) // expected-error {{types may not be defined in conditions}}
+ ;
+}
+void test5_inst() {
+ test5<int>();
+}
diff --git a/test/SemaCXX/conditional-expr.cpp b/test/SemaCXX/conditional-expr.cpp
index 7595f1d..692aaef 100644
--- a/test/SemaCXX/conditional-expr.cpp
+++ b/test/SemaCXX/conditional-expr.cpp
@@ -146,7 +146,7 @@ void test()
(void)(i1 ? 1 : Ambig()); // expected-error {{conversion from 'Ambig' to 'int' is ambiguous}}
(void)(i1 ? Ambig() : 1); // expected-error {{conversion from 'Ambig' to 'int' is ambiguous}}
// By the way, this isn't an lvalue:
- &(i1 ? i1 : i2); // expected-error {{address expression must be an lvalue or a function designator}}
+ &(i1 ? i1 : i2); // expected-error {{cannot take the address of an rvalue}}
// p4 (lvalue, same type)
Fields flds;
@@ -183,7 +183,7 @@ void test()
i1 ? &MixedFields::ci : &MixedFields::cvi;
(void)(i1 ? &MixedFields::ci : &MixedFields::vi);
// Conversion of primitives does not result in an lvalue.
- &(i1 ? i1 : d1); // expected-error {{address expression must be an lvalue or a function designator}}
+ &(i1 ? i1 : d1); // expected-error {{cannot take the address of an rvalue}}
(void)&(i1 ? flds.b1 : flds.i1); // expected-error {{address of bit-field requested}}
(void)&(i1 ? flds.i1 : flds.b1); // expected-error {{address of bit-field requested}}
diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp
index f504eb6..30aa7d7 100644
--- a/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/test/SemaCXX/constant-expression-cxx11.cpp
@@ -1153,8 +1153,8 @@ namespace ConvertedConstantExpr {
namespace IndirectField {
struct S {
struct { // expected-warning {{GNU extension}}
- union {
- struct { // expected-warning {{GNU extension}}
+ union { // expected-warning {{declared in an anonymous struct}}
+ struct { // expected-warning {{GNU extension}} expected-warning {{declared in an anonymous union}}
int a;
int b;
};
diff --git a/test/SemaCXX/constructor-initializer.cpp b/test/SemaCXX/constructor-initializer.cpp
index ecbe7bf..1757632 100644
--- a/test/SemaCXX/constructor-initializer.cpp
+++ b/test/SemaCXX/constructor-initializer.cpp
@@ -232,13 +232,15 @@ namespace PR7402 {
// <rdar://problem/8308215>: don't crash.
// Lots of questionable recovery here; errors can change.
namespace test3 {
- class A : public std::exception {}; // expected-error {{undeclared identifier}} expected-error {{expected class name}} expected-note 2 {{candidate}}
+ class A : public std::exception {}; // expected-error {{undeclared identifier}} expected-error {{expected class name}} expected-note 4 {{candidate}}
class B : public A {
public:
B(const String& s, int e=0) // expected-error {{unknown type name}}
: A(e), m_String(s) , m_ErrorStr(__null) {} // expected-error {{no matching constructor}} expected-error {{does not name}}
B(const B& e)
- : A(e), m_String(e.m_String), m_ErrorStr(__null) { // expected-error {{does not name}} expected-error {{no member named 'm_String' in 'test3::B'}}
+ : A(e), m_String(e.m_String), m_ErrorStr(__null) { // expected-error {{does not name}} \
+ // expected-error {{no member named 'm_String' in 'test3::B'}} \
+ // expected-error {{no matching}}
}
};
}
@@ -283,3 +285,9 @@ namespace PR12049 {
int member; // expected-error {{expected ')'}}
};
}
+
+namespace PR14073 {
+ struct S1 { union { int n; }; S1() : n(n) {} }; // expected-warning {{field 'n' is uninitialized when used here}}
+ struct S2 { union { union { int n; }; char c; }; S2() : n(n) {} }; // expected-warning {{field 'n' is uninitialized when used here}}
+ struct S3 { struct { int n; }; S3() : n(n) {} }; // expected-warning {{field 'n' is uninitialized when used here}}
+}
diff --git a/test/SemaCXX/conversion.cpp b/test/SemaCXX/conversion.cpp
index ac235cc..852bbba 100644
--- a/test/SemaCXX/conversion.cpp
+++ b/test/SemaCXX/conversion.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -Wconversion -verify %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -Wconversion %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -Wconversion -std=c++11 -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -Wconversion -std=c++11 %s 2>&1 | FileCheck %s
#include <stddef.h>
@@ -131,3 +131,9 @@ namespace test5 {
template void func<3>();
}
+
+namespace test6 {
+ decltype(nullptr) func() {
+ return NULL;
+ }
+}
diff --git a/test/SemaCXX/copy-constructor-error.cpp b/test/SemaCXX/copy-constructor-error.cpp
index 64a7d58..6ffed9b 100644
--- a/test/SemaCXX/copy-constructor-error.cpp
+++ b/test/SemaCXX/copy-constructor-error.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
struct S {
S (S); // expected-error {{copy constructor must pass its first argument by reference}}
@@ -10,16 +10,50 @@ void g() {
S a( f() );
}
+class foo {
+ foo(foo&, int); // expected-note {{previous}}
+ foo(int); // expected-note {{previous}}
+ foo(const foo&); // expected-note {{previous}}
+};
+
+foo::foo(foo&, int = 0) { } // expected-error {{makes this constructor a copy constructor}}
+foo::foo(int = 0) { } // expected-error {{makes this constructor a default constructor}}
+foo::foo(const foo& = 0) { } //expected-error {{makes this constructor a default constructor}}
+
namespace PR6064 {
struct A {
A() { }
- inline A(A&, int); // expected-note {{was not a special member function}}
+ inline A(A&, int); // expected-note {{previous}}
};
- A::A(A&, int = 0) { } // expected-warning {{makes this constructor a copy constructor}}
+ A::A(A&, int = 0) { } // expected-error {{makes this constructor a copy constructor}}
void f() {
A const a;
A b(a);
}
}
+
+namespace PR10618 {
+ struct A {
+ A(int, int, int); // expected-note {{previous}}
+ };
+ A::A(int a = 0, // expected-error {{makes this constructor a default constructor}}
+ int b = 0,
+ int c = 0) {}
+
+ struct B {
+ B(int);
+ B(const B&, int); // expected-note {{previous}}
+ };
+ B::B(const B& = B(0), // expected-error {{makes this constructor a default constructor}}
+ int = 0) {
+ }
+
+ struct C {
+ C(const C&, int); // expected-note {{previous}}
+ };
+ C::C(const C&,
+ int = 0) { // expected-error {{makes this constructor a copy constructor}}
+ }
+}
diff --git a/test/SemaCXX/crash-lambda-12645424.cpp b/test/SemaCXX/crash-lambda-12645424.cpp
new file mode 100644
index 0000000..8317e7c
--- /dev/null
+++ b/test/SemaCXX/crash-lambda-12645424.cpp
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
+
+// rdar://12645424, crash due to a double-free
+
+template<typename _Tp> struct __add_lvalue_reference_helper {};
+template<typename _Tp> struct add_lvalue_reference : __add_lvalue_reference_helper<_Tp> {
+ typedef _Tp type;
+};
+
+template<typename... Types> struct type_list;
+template<typename , template<typename> class... Funs> struct C;
+
+template<typename T> struct C<T> {
+ typedef T type;
+};
+
+template<typename T, template<typename> class Fun0, template<typename> class... Funs> struct C<T, Fun0, Funs...> {
+ typedef typename C<typename Fun0<T>::type, Funs...>::type type;
+};
+
+template<class , template<typename> class... Funs> struct tl_map;
+template<typename... Ts, template<typename> class... Funs> struct tl_map<type_list<Ts...>, Funs...> {
+ typedef type_list<typename C<Ts, Funs...>::type...> type;
+};
+
+template< class Pattern> struct F {
+ typedef Pattern filtered_pattern;
+ tl_map< filtered_pattern, add_lvalue_reference > type;
+};
+
+template<class, class Pattern> struct get_case {
+ F<Pattern> type;
+};
+
+template<class Pattern> struct rvalue_builder {
+ template<typename Expr> typename get_case<Expr, Pattern>::type operator>>(Expr ); // expected-note {{candidate template ignored}}
+};
+
+template<typename Arg0> rvalue_builder< type_list<Arg0> > on(const Arg0& ) ;
+
+class Z {
+ int empty = on(0) >> [] {}; // expected-error {{invalid operands to binary expression}}
+};
diff --git a/test/SemaCXX/cxx0x-class.cpp b/test/SemaCXX/cxx0x-class.cpp
index 41b0a5c..074591e 100644
--- a/test/SemaCXX/cxx0x-class.cpp
+++ b/test/SemaCXX/cxx0x-class.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wno-error=static-float-init %s
int vs = 0;
@@ -20,8 +20,8 @@ namespace rdar8367341 {
float foo(); // expected-note {{here}}
struct A {
- static const float x = 5.0f; // expected-warning {{GNU extension}} expected-note {{use 'constexpr' specifier to silence this warning}}
- static const float y = foo(); // expected-warning {{GNU extension}} expected-note {{use 'constexpr' specifier to silence this warning}} expected-error {{in-class initializer for static data member is not a constant expression}}
+ static const float x = 5.0f; // expected-warning {{requires 'constexpr'}} expected-note {{add 'constexpr'}}
+ static const float y = foo(); // expected-warning {{requires 'constexpr'}} expected-note {{add 'constexpr'}}
static constexpr float x2 = 5.0f;
static constexpr float y2 = foo(); // expected-error {{must be initialized by a constant expression}} expected-note {{non-constexpr function 'foo'}}
};
diff --git a/test/SemaCXX/cxx0x-cursory-default-delete.cpp b/test/SemaCXX/cxx0x-cursory-default-delete.cpp
index 641760e..b1078dc 100644
--- a/test/SemaCXX/cxx0x-cursory-default-delete.cpp
+++ b/test/SemaCXX/cxx0x-cursory-default-delete.cpp
@@ -36,9 +36,9 @@ struct non_const_derived : non_const_copy {
};
struct bad_decls {
- bad_decls(volatile bad_decls&) = default; // expected-error {{may not be volatile}} expected-error {{must be defaulted outside the class}}
+ bad_decls(volatile bad_decls&) = default; // expected-error {{may not be volatile}}
bad_decls&& operator = (bad_decls) = default; // expected-error {{lvalue reference}} expected-error {{must return 'bad_decls &'}}
- bad_decls& operator = (volatile bad_decls&) = default; // expected-error {{may not be volatile}} expected-error {{must be defaulted outside the class}}
+ bad_decls& operator = (volatile bad_decls&) = default; // expected-error {{may not be volatile}}
bad_decls& operator = (const bad_decls&) const = default; // expected-error {{may not have 'const', 'constexpr' or 'volatile' qualifiers}}
};
@@ -57,14 +57,18 @@ struct except_spec_d_good : except_spec_a, except_spec_b {
~except_spec_d_good();
};
except_spec_d_good::~except_spec_d_good() = default;
-// FIXME: This should error in the virtual override check.
-// It doesn't because we generate the implicit specification later than
-// appropriate.
+struct except_spec_d_good2 : except_spec_a, except_spec_b {
+ ~except_spec_d_good2() = default;
+};
struct except_spec_d_bad : except_spec_a, except_spec_b {
- ~except_spec_d_bad() = default;
+ ~except_spec_d_bad() noexcept;
};
+// FIXME: This should error because this exception spec is not
+// compatible with the implicit exception spec.
+except_spec_d_bad::~except_spec_d_bad() noexcept = default;
-// FIXME: This should error because the exceptions spec doesn't match.
+// FIXME: This should error because this exception spec is not
+// compatible with the implicit exception spec.
struct except_spec_d_mismatch : except_spec_a, except_spec_b {
except_spec_d_mismatch() throw(A) = default;
};
diff --git a/test/SemaCXX/cxx0x-defaulted-functions.cpp b/test/SemaCXX/cxx0x-defaulted-functions.cpp
index ce7ee67..bc03bcd 100644
--- a/test/SemaCXX/cxx0x-defaulted-functions.cpp
+++ b/test/SemaCXX/cxx0x-defaulted-functions.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -fcxx-exceptions %s
void fn() = default; // expected-error {{only special member}}
struct foo {
@@ -149,3 +149,42 @@ namespace PR13527 {
Y &Y::operator=(Y&&) = default; // expected-error {{definition of explicitly defaulted}}
Y::~Y() = default; // expected-error {{definition of explicitly defaulted}}
}
+
+namespace PR14577 {
+ template<typename T>
+ struct Outer {
+ template<typename U>
+ struct Inner1 {
+ ~Inner1();
+ };
+
+ template<typename U>
+ struct Inner2 {
+ ~Inner2();
+ };
+ };
+
+ template<typename T>
+ Outer<T>::Inner1<T>::~Inner1() = delete; // expected-error {{nested name specifier 'Outer<T>::Inner1<T>::' for declaration does not refer into a class, class template or class template partial specialization}} expected-error {{only functions can have deleted definitions}}
+
+ template<typename T>
+ Outer<T>::Inner2<T>::~Inner2() = default; // expected-error {{nested name specifier 'Outer<T>::Inner2<T>::' for declaration does not refer into a class, class template or class template partial specialization}} expected-error {{only special member functions may be defaulted}}
+}
+
+extern "C" {
+ template<typename _Tp> // expected-error {{templates must have C++ linkage}}
+ void PR13573(const _Tp&) = delete; // expected-error {{only functions can have deleted definitions}}
+}
+
+namespace PR15597 {
+ template<typename T> struct A {
+ A() noexcept(true) = default;
+ ~A() noexcept(true) = default;
+ };
+ template<typename T> struct B {
+ B() noexcept(false) = default; // expected-error {{does not match the calculated one}}
+ ~B() noexcept(false) = default; // expected-error {{does not match the calculated one}}
+ };
+ A<int> a;
+ B<int> b; // expected-note {{here}}
+}
diff --git a/test/SemaCXX/cxx0x-initializer-aggregates.cpp b/test/SemaCXX/cxx0x-initializer-aggregates.cpp
index c83058a..f53ac6d 100644
--- a/test/SemaCXX/cxx0x-initializer-aggregates.cpp
+++ b/test/SemaCXX/cxx0x-initializer-aggregates.cpp
@@ -115,4 +115,18 @@ namespace sub_constructor {
Aggr invalid { {} , {&ok1} , {0,0} }; // expected-error {{no matching constructor for initialization}}
NoDefaultConstructor2 array_ok[] = { {0,0} , {0,1} };
NoDefaultConstructor2 array_error[] = { {0,0} , {0} }; // expected-error {{no matching constructor for initialization}}
-} \ No newline at end of file
+}
+
+namespace multidimensional_array {
+ void g(const int (&)[2][2]) {}
+ void g(const int (&)[2][2][2]) = delete;
+
+ void h() {
+ g({{1,2},{3,4}});
+ }
+}
+
+namespace array_addressof {
+ using T = int[5];
+ T *p = &T{1,2,3,4,5}; // expected-error {{taking the address of a temporary object of type 'T' (aka 'int [5]')}}
+}
diff --git a/test/SemaCXX/cxx0x-initializer-constructor.cpp b/test/SemaCXX/cxx0x-initializer-constructor.cpp
index a657ec8..dc179f8 100644
--- a/test/SemaCXX/cxx0x-initializer-constructor.cpp
+++ b/test/SemaCXX/cxx0x-initializer-constructor.cpp
@@ -75,9 +75,8 @@ namespace objects {
{ F<0> f = {}; }
// Narrowing conversions don't affect viability. The next two choose
// the initializer_list constructor.
- // FIXME: Emit narrowing conversion errors.
- { F<3> f{1, 1.0}; } // xpected-error {{narrowing conversion}}
- { F<3> f = {1, 1.0}; } // xpected-error {{narrowing conversion}}
+ { F<3> f{1, 1.0}; } // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{override}}
+ { F<3> f = {1, 1.0}; } // expected-error {{type 'double' cannot be narrowed to 'int' in initializer list}} expected-note {{override}}
{ F<3> f{1, 2, 3, 4, 5, 6, 7, 8}; }
{ F<3> f = {1, 2, 3, 4, 5, 6, 7, 8}; }
{ F<3> f{1, 2, 3, 4, 5, 6, 7, 8}; }
@@ -306,17 +305,63 @@ namespace init_list_default {
}
-// <rdar://problem/11974632>
-namespace rdar11974632 {
+// PR13470, <rdar://problem/11974632>
+namespace PR13470 {
+ struct W {
+ explicit W(int); // expected-note {{here}}
+ };
+
struct X {
- X(const X&) = delete;
+ X(const X&) = delete; // expected-note 3 {{here}}
X(int);
};
+ template<typename T, typename Fn> void call(Fn f) {
+ f({1}); // expected-error {{constructor is explicit}}
+ f(T{1}); // expected-error {{call to deleted constructor}}
+ }
+
+ void ref_w(const W &); // expected-note 2 {{not viable}}
+ void call_ref_w() {
+ ref_w({1}); // expected-error {{no matching function}}
+ ref_w(W{1});
+ call<W>(ref_w); // expected-note {{instantiation of}}
+ }
+
+ void ref_x(const X &);
+ void call_ref_x() {
+ ref_x({1});
+ ref_x(X{1});
+ call<X>(ref_x); // ok
+ }
+
+ void val_x(X); // expected-note 2 {{parameter}}
+ void call_val_x() {
+ val_x({1});
+ val_x(X{1}); // expected-error {{call to deleted constructor}}
+ call<X>(val_x); // expected-note {{instantiation of}}
+ }
+
template<typename T>
- struct Y {
+ struct Y {
X x{1};
+ void f() { X x{1}; }
+ void h() {
+ ref_w({1}); // expected-error {{no matching function}}
+ ref_w(W{1});
+ ref_x({1});
+ ref_x(X{1});
+ val_x({1});
+ val_x(X{1}); // expected-error {{call to deleted constructor}}
+ }
+ Y() {}
+ Y(int) : x{1} {}
};
Y<int> yi;
+ Y<int> yi2(0);
+ void g() {
+ yi.f();
+ yi.h(); // ok, all diagnostics produced in template definition
+ }
}
diff --git a/test/SemaCXX/cxx0x-initializer-references.cpp b/test/SemaCXX/cxx0x-initializer-references.cpp
index c4e9c90..283c32a 100644
--- a/test/SemaCXX/cxx0x-initializer-references.cpp
+++ b/test/SemaCXX/cxx0x-initializer-references.cpp
@@ -90,3 +90,10 @@ namespace PR12660 {
const int &i { 1 };
struct S { S(int); } const &s { 2 };
}
+
+namespace b7891773 {
+ typedef void (*ptr)();
+ template <class T> void f();
+ int g(const ptr &);
+ int k = g({ f<int> });
+}
diff --git a/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp b/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
index 0962253..88571d6 100644
--- a/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
+++ b/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp
@@ -191,3 +191,20 @@ namespace rdar11948732 {
namespace PR14272 {
auto x { { 0, 0 } }; // expected-error {{cannot deduce actual type for variable 'x' with type 'auto' from initializer list}}
}
+
+namespace initlist_of_array {
+ void f(std::initializer_list<int[2]>) {}
+ void f(std::initializer_list<int[2][2]>) = delete;
+ void h() {
+ f({{1,2},{3,4}});
+ }
+}
+
+namespace init_list_deduction_failure {
+ void f();
+ void f(int);
+ template<typename T> void g(std::initializer_list<T>);
+ // expected-note@-1 {{candidate template ignored: couldn't resolve reference to overloaded function 'f'}}
+ void h() { g({f}); }
+ // expected-error@-1 {{no matching function for call to 'g'}}
+}
diff --git a/test/SemaCXX/cxx11-ast-print.cpp b/test/SemaCXX/cxx11-ast-print.cpp
index afabf88..f95eeb5 100644
--- a/test/SemaCXX/cxx11-ast-print.cpp
+++ b/test/SemaCXX/cxx11-ast-print.cpp
@@ -1,7 +1,6 @@
// RUN: %clang_cc1 -std=c++11 -ast-print %s | FileCheck %s
-// FIXME: Print the trailing-return-type properly.
-// CHECK: decltype(nullptr) operator "" _foo(const char *p, decltype(sizeof(int)));
+// CHECK: auto operator "" _foo(const char *p, decltype(sizeof(int))) -> decltype(nullptr);
auto operator"" _foo(const char *p, decltype(sizeof(int))) -> decltype(nullptr);
// CHECK: decltype(""_foo) operator "" _bar(unsigned long long);
@@ -39,3 +38,6 @@ const char *p8 = 4.9_quux;
const char *p9 = 0x42e3F_fritz;
// CHECK: const char *p10 = 3.300e+15_fritz;
const char *p10 = 3.300e+15_fritz;
+// CHECK: ;
+;
+// CHECK-NOT: ;
diff --git a/test/SemaCXX/cxx11-attr-print.cpp b/test/SemaCXX/cxx11-attr-print.cpp
new file mode 100644
index 0000000..19de5b5
--- /dev/null
+++ b/test/SemaCXX/cxx11-attr-print.cpp
@@ -0,0 +1,77 @@
+// RUN: %clang_cc1 -std=c++11 -ast-print -fms-extensions %s | FileCheck %s
+//
+// CHECK: int x __attribute__((aligned(4)));
+int x __attribute__((aligned(4)));
+
+// FIXME: Print this at a valid location for a __declspec attr.
+// CHECK: int y __declspec(align(4));
+__declspec(align(4)) int y;
+
+// CHECK: int z {{\[}}[gnu::aligned(4)]];
+int z [[gnu::aligned(4)]];
+
+// CHECK: __attribute__((deprecated("warning")));
+int a __attribute__((deprecated("warning")));
+
+// CHECK: int b {{\[}}[gnu::deprecated("warning")]];
+int b [[gnu::deprecated("warning")]];
+
+// CHECK: int cxx11_alignas alignas(4);
+alignas(4) int cxx11_alignas;
+
+// CHECK: int c11_alignas _Alignas(alignof(int));
+_Alignas(int) int c11_alignas;
+
+// CHECK: void foo() __attribute__((const));
+void foo() __attribute__((const));
+
+// CHECK: void bar() __attribute__((__const));
+void bar() __attribute__((__const));
+
+// CHECK: int f1() __attribute__((warn_unused_result));
+int f1() __attribute__((warn_unused_result));
+
+// CHECK: {{\[}}[clang::warn_unused_result]];
+int f2 [[clang::warn_unused_result]] ();
+
+// CHECK: {{\[}}[gnu::warn_unused_result]];
+int f3 [[gnu::warn_unused_result]] ();
+
+// FIXME: ast-print need to print C++11
+// attribute after function declare-id.
+// CHECK: {{\[}}[noreturn]];
+void f4 [[noreturn]] ();
+
+// CHECK: {{\[}}[std::noreturn]];
+void f5 [[std::noreturn]] ();
+
+// CHECK: __attribute__((gnu_inline));
+inline void f6() __attribute__((gnu_inline));
+
+// CHECK: {{\[}}[gnu::gnu_inline]];
+inline void f7 [[gnu::gnu_inline]] ();
+
+// arguments printing
+// CHECK: __attribute__((format("printf", 2, 3)));
+void f8 (void *, const char *, ...) __attribute__ ((format (printf, 2, 3)));
+
+// CHECK: int m __attribute__((aligned(4
+// CHECK: int n alignas(4
+// CHECK: static int f() __attribute__((pure))
+// CHECK: static int g() {{\[}}[gnu::pure]]
+template <typename T> struct S {
+ __attribute__((aligned(4))) int m;
+ alignas(4) int n;
+ __attribute__((pure)) static int f() {
+ return 0;
+ }
+ [[gnu::pure]] static int g() {
+ return 1;
+ }
+};
+
+// CHECK: int m __attribute__((aligned(4
+// CHECK: int n alignas(4
+// CHECK: static int f() __attribute__((pure))
+// CHECK: static int g() {{\[}}[gnu::pure]]
+template struct S<int>;
diff --git a/test/SemaCXX/cxx11-gnu-attrs.cpp b/test/SemaCXX/cxx11-gnu-attrs.cpp
new file mode 100644
index 0000000..def83a9
--- /dev/null
+++ b/test/SemaCXX/cxx11-gnu-attrs.cpp
@@ -0,0 +1,55 @@
+// RUN: %clang -cc1 -triple x86_64-unknown-unknown -std=c++11 -verify %s
+
+// Error cases.
+
+[[gnu::this_attribute_does_not_exist]] int unknown_attr;
+// expected-warning@-1 {{unknown attribute 'this_attribute_does_not_exist' ignored}}
+int [[gnu::unused]] attr_on_type;
+// expected-error@-1 {{'unused' attribute cannot be applied to types}}
+int *[[gnu::unused]] attr_on_ptr;
+// expected-warning@-1 {{attribute 'unused' ignored, because it cannot be applied to a type}}
+
+// Valid cases.
+
+void alias1() {}
+void alias2 [[gnu::alias("_Z6alias1v")]] ();
+
+[[gnu::aligned(8)]] int aligned;
+void aligned_fn [[gnu::aligned(32)]] ();
+struct [[gnu::aligned(8)]] aligned_struct {};
+
+[[gnu::malloc, gnu::alloc_size(1,2)]] void *alloc_size(int a, int b);
+
+void always_inline [[gnu::always_inline]] ();
+
+__thread int tls_model [[gnu::tls_model("local-exec")]];
+
+void cleanup(int *p) {
+ int n [[gnu::cleanup(cleanup)]];
+}
+
+void deprecated1 [[gnu::deprecated]] (); // expected-note {{here}}
+[[gnu::deprecated("custom message")]] void deprecated2(); // expected-note {{here}}
+void deprecated3() {
+ deprecated1(); // expected-warning {{deprecated}}
+ deprecated2(); // expected-warning {{custom message}}
+}
+
+[[gnu::naked(1,2,3)]] void naked(); // expected-error {{takes no arguments}}
+
+void nonnull [[gnu::nonnull]] (); // expected-warning {{applied to function with no pointer arguments}}
+
+// [[gnu::noreturn]] appertains to a declaration, and marks the innermost
+// function declarator in that declaration as being noreturn.
+int noreturn [[gnu::noreturn]]; // expected-warning {{'noreturn' only applies to function types}}
+int noreturn_fn_1();
+int noreturn_fn_2() [[gnu::noreturn]]; // expected-warning {{cannot be applied to a type}}
+int noreturn_fn_3 [[gnu::noreturn]] ();
+[[gnu::noreturn]] int noreturn_fn_4();
+int (*noreturn_fn_ptr_1 [[gnu::noreturn]])() = &noreturn_fn_1; // expected-error {{cannot initialize}}
+int (*noreturn_fn_ptr_2 [[gnu::noreturn]])() = &noreturn_fn_3;
+[[gnu::noreturn]] int (*noreturn_fn_ptr_3)() = &noreturn_fn_1; // expected-error {{cannot initialize}}
+[[gnu::noreturn]] int (*noreturn_fn_ptr_4)() = &noreturn_fn_3;
+
+struct [[gnu::packed]] packed { char c; int n; };
+static_assert(sizeof(packed) == sizeof(char) + sizeof(int), "not packed");
diff --git a/test/SemaCXX/cxx11-user-defined-literals.cpp b/test/SemaCXX/cxx11-user-defined-literals.cpp
index 4bbecdb..f8bbcd9 100644
--- a/test/SemaCXX/cxx11-user-defined-literals.cpp
+++ b/test/SemaCXX/cxx11-user-defined-literals.cpp
@@ -135,3 +135,9 @@ namespace Namespace {
int _y(unsigned long long);
int k2 = 123_y; // expected-error {{no matching literal operator for call to 'operator "" _y'}}
}
+
+namespace PR14950 {
+ template<...> // expected-error {{expected template parameter}}
+ int operator"" _b(); // expected-error {{no function template matches function template specialization}}
+ int main() { return 0_b; } // expected-error {{no matching literal operator for call to 'operator "" _b'}}
+}
diff --git a/test/SemaCXX/cxx98-compat.cpp b/test/SemaCXX/cxx98-compat.cpp
index d497d45..7d36770 100644
--- a/test/SemaCXX/cxx98-compat.cpp
+++ b/test/SemaCXX/cxx98-compat.cpp
@@ -8,6 +8,8 @@ namespace std {
initializer_list(T*, size_t);
T *p;
size_t n;
+ T *begin();
+ T *end();
};
}
@@ -103,6 +105,13 @@ void RangeFor() {
int xs[] = {1, 2, 3};
for (int &a : xs) { // expected-warning {{range-based for loop is incompatible with C++98}}
}
+ for (auto &b : {1, 2, 3}) {
+ // expected-warning@-1 {{range-based for loop is incompatible with C++98}}
+ // expected-warning@-2 {{'auto' type specifier is incompatible with C++98}}
+ // expected-warning@-3 {{initialization of initializer_list object is incompatible with C++98}}
+ // expected-warning@-4 {{reference initialized from initializer list is incompatible with C++98}}
+ }
+ struct Agg { int a, b; } const &agg = { 1, 2 }; // expected-warning {{reference initialized from initializer list is incompatible with C++98}}
}
struct InClassInit {
@@ -254,13 +263,13 @@ namespace CopyCtorIssues {
namespace UnionOrAnonStructMembers {
struct NonTrivCtor {
- NonTrivCtor(); // expected-note 2{{user-declared constructor}}
+ NonTrivCtor(); // expected-note 2{{user-provided default constructor}}
};
struct NonTrivCopy {
- NonTrivCopy(const NonTrivCopy&); // expected-note 2{{user-declared copy constructor}}
+ NonTrivCopy(const NonTrivCopy&); // expected-note 2{{user-provided copy constructor}}
};
struct NonTrivDtor {
- ~NonTrivDtor(); // expected-note 2{{user-declared destructor}}
+ ~NonTrivDtor(); // expected-note 2{{user-provided destructor}}
};
union BadUnion {
NonTrivCtor ntc; // expected-warning {{union member 'ntc' with a non-trivial constructor is incompatible with C++98}}
@@ -338,8 +347,8 @@ namespace NullPointerTemplateArg {
namespace PR13480 {
struct basic_iterator {
- basic_iterator(const basic_iterator &it) {}
- basic_iterator(basic_iterator &it) {} // expected-note {{because type 'PR13480::basic_iterator' has a user-declared copy constructor}}
+ basic_iterator(const basic_iterator &it) {} // expected-note {{because type 'PR13480::basic_iterator' has a user-provided copy constructor}}
+ basic_iterator(basic_iterator &it) {}
};
union test {
@@ -349,12 +358,12 @@ namespace PR13480 {
namespace AssignOpUnion {
struct a {
- void operator=(const a &it) {}
- void operator=(a &it) {} // expected-note {{because type 'AssignOpUnion::a' has a user-declared copy assignment operator}}
+ void operator=(const a &it) {} // expected-note {{because type 'AssignOpUnion::a' has a user-provided copy assignment operator}}
+ void operator=(a &it) {}
};
struct b {
- void operator=(const b &it) {} // expected-note {{because type 'AssignOpUnion::b' has a user-declared copy assignment operator}}
+ void operator=(const b &it) {} // expected-note {{because type 'AssignOpUnion::b' has a user-provided copy assignment operator}}
};
union test1 {
@@ -364,9 +373,9 @@ namespace AssignOpUnion {
}
namespace rdar11736429 {
- struct X {
+ struct X { // expected-note {{because type 'rdar11736429::X' has no default constructor}}
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}}
+ // expected-note {{implicit default constructor suppressed by user-declared constructor}}
};
union S {
diff --git a/test/SemaCXX/decl-microsoft-call-conv.cpp b/test/SemaCXX/decl-microsoft-call-conv.cpp
new file mode 100644
index 0000000..3175af7
--- /dev/null
+++ b/test/SemaCXX/decl-microsoft-call-conv.cpp
@@ -0,0 +1,86 @@
+// RUN: %clang_cc1 -triple i686-pc-win32 -cxx-abi microsoft -fms-extensions -verify %s
+
+// Pointers to free functions
+void free_func_default();
+void __cdecl free_func_cdecl();
+void __stdcall free_func_stdcall(); // expected-note {{previous declaration is here}}
+void __fastcall free_func_fastcall(); // expected-note 2 {{previous declaration is here}}
+
+void __cdecl free_func_default(); // expected-note 2 {{previous declaration is here}}
+void __stdcall free_func_default(); // expected-error {{function declared 'stdcall' here was previously declared without calling convention}}
+void __fastcall free_func_default(); // expected-error {{function declared 'fastcall' here was previously declared without calling convention}}
+
+void free_func_cdecl(); // expected-note 2 {{previous declaration is here}}
+void __stdcall free_func_cdecl(); // expected-error {{function declared 'stdcall' here was previously declared 'cdecl'}}
+void __fastcall free_func_cdecl(); // expected-error {{function declared 'fastcall' here was previously declared 'cdecl'}}
+
+void __cdecl free_func_stdcall(); // expected-error {{function declared 'cdecl' here was previously declared 'stdcall'}}
+void free_func_stdcall(); // expected-note {{previous declaration is here}}
+void __fastcall free_func_stdcall(); // expected-error {{function declared 'fastcall' here was previously declared 'stdcall'}}
+
+void __cdecl free_func_fastcall(); // expected-error {{function declared 'cdecl' here was previously declared 'fastcall'}}
+void __stdcall free_func_fastcall(); // expected-error {{function declared 'stdcall' here was previously declared 'fastcall'}}
+void free_func_fastcall();
+
+// Overloaded functions may have different calling conventions
+void __fastcall free_func_default(int);
+void __cdecl free_func_default(int *);
+
+void __thiscall free_func_cdecl(char *);
+void __cdecl free_func_cdecl(double);
+
+
+// Pointers to member functions
+struct S {
+ void member_default1(); // expected-note {{previous declaration is here}}
+ void member_default2();
+ void __cdecl member_cdecl1();
+ void __cdecl member_cdecl2(); // expected-note {{previous declaration is here}}
+ void __thiscall member_thiscall1();
+ void __thiscall member_thiscall2(); // expected-note {{previous declaration is here}}
+
+ // Static member functions can't be __thiscall
+ static void static_member_default1();
+ static void static_member_default2(); // expected-note {{previous declaration is here}}
+ static void __cdecl static_member_cdecl1();
+ static void __cdecl static_member_cdecl2(); // expected-note {{previous declaration is here}}
+ static void __stdcall static_member_stdcall1();
+ static void __stdcall static_member_stdcall2();
+
+ // Variadic functions can't be other than default or __cdecl
+ void member_variadic_default(int x, ...);
+ void __cdecl member_variadic_cdecl(int x, ...);
+
+ static void static_member_variadic_default(int x, ...);
+ static void __cdecl static_member_variadic_cdecl(int x, ...);
+};
+
+void __cdecl S::member_default1() {} // expected-error {{function declared 'cdecl' here was previously declared without calling convention}}
+void __thiscall S::member_default2() {}
+
+void S::member_cdecl1() {}
+void __thiscall S::member_cdecl2() {} // expected-error {{function declared 'thiscall' here was previously declared 'cdecl'}}
+
+void S::member_thiscall1() {}
+void __cdecl S::member_thiscall2() {} // expected-error {{function declared 'cdecl' here was previously declared 'thiscall'}}
+
+void __cdecl S::static_member_default1() {}
+void __stdcall S::static_member_default2() {} // expected-error {{function declared 'stdcall' here was previously declared without calling convention}}
+
+void S::static_member_cdecl1() {}
+void __stdcall S::static_member_cdecl2() {} // expected-error {{function declared 'stdcall' here was previously declared 'cdecl'}}
+
+void __cdecl S::member_variadic_default(int x, ...) {
+ (void)x;
+}
+void S::member_variadic_cdecl(int x, ...) {
+ (void)x;
+}
+
+void __cdecl S::static_member_variadic_default(int x, ...) {
+ (void)x;
+}
+void S::static_member_variadic_cdecl(int x, ...) {
+ (void)x;
+}
+
diff --git a/test/SemaCXX/default-arg-special-member.cpp b/test/SemaCXX/default-arg-special-member.cpp
deleted file mode 100644
index 8402d382..0000000
--- a/test/SemaCXX/default-arg-special-member.cpp
+++ /dev/null
@@ -1,12 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -Wno-default-arg-special-member -Werror -fsyntax-only %s
-
-class foo {
- foo(foo&, int); // expected-note {{was not a special member function}}
- foo(int); // expected-note {{was not a special member function}}
- foo(const foo&); // expected-note {{was a copy constructor}}
-};
-
-foo::foo(foo&, int = 0) { } // expected-warning {{makes this constructor a copy constructor}}
-foo::foo(int = 0) { } // expected-warning {{makes this constructor a default constructor}}
-foo::foo(const foo& = 0) { } //expected-warning {{makes this constructor a default constructor}}
diff --git a/test/SemaCXX/empty-class-layout.cpp b/test/SemaCXX/empty-class-layout.cpp
index 951f16c..3cfc491 100644
--- a/test/SemaCXX/empty-class-layout.cpp
+++ b/test/SemaCXX/empty-class-layout.cpp
@@ -156,3 +156,18 @@ namespace Test7 {
};
SA(0, sizeof(Test) == 2);
}
+
+namespace Test8 {
+ // Test that type sugar doesn't make us incorrectly determine the size of an
+ // array of empty classes.
+ struct Empty1 {};
+ struct Empty2 {};
+ struct Empties : Empty1, Empty2 {};
+ typedef Empty1 Sugar[4];
+ struct A : Empty2, Empties {
+ // This must go at offset 2, because if it were at offset 0,
+ // V[0][1] would overlap Empties::Empty1.
+ Sugar V[1];
+ };
+ SA(0, sizeof(A) == 6);
+}
diff --git a/test/SemaCXX/enum-scoped.cpp b/test/SemaCXX/enum-scoped.cpp
index a1f911d..d01000d 100644
--- a/test/SemaCXX/enum-scoped.cpp
+++ b/test/SemaCXX/enum-scoped.cpp
@@ -252,3 +252,17 @@ namespace pr13128 {
enum class E { C };
};
}
+
+namespace PR15633 {
+ template<typename T> struct A {
+ struct B {
+ enum class E : T;
+ enum class E2 : T;
+ };
+ };
+ template<typename T> enum class A<T>::B::E { e };
+ template class A<int>;
+
+ struct B { enum class E; };
+ template<typename T> enum class B::E { e }; // expected-error {{enumeration cannot be a template}}
+}
diff --git a/test/SemaCXX/exceptions.cpp b/test/SemaCXX/exceptions.cpp
index 486d88e..c2ca9f9 100644
--- a/test/SemaCXX/exceptions.cpp
+++ b/test/SemaCXX/exceptions.cpp
@@ -120,3 +120,28 @@ namespace PR6831 {
}
}
}
+
+namespace Decay {
+ struct A {
+ void f() throw (A[10]);
+ };
+
+ template<typename T> struct B {
+ void f() throw (B[10]);
+ };
+ template struct B<int>;
+
+ void f() throw (int[10], int(*)());
+ void f() throw (int*, int());
+
+ template<typename T> struct C {
+ void f() throw (T); // expected-error {{pointer to incomplete type 'Decay::E' is not allowed in exception specification}}
+ };
+ struct D {
+ C<D[10]> c;
+ };
+ struct E; // expected-note {{forward declaration}}
+ C<E[10]> e; // expected-note {{in instantiation of}}
+}
+
+void rval_ref() throw (int &&); // expected-error {{rvalue reference type 'int &&' is not allowed in exception specification}} expected-warning {{C++11}}
diff --git a/test/SemaCXX/extern-c.cpp b/test/SemaCXX/extern-c.cpp
new file mode 100644
index 0000000..c55b10d
--- /dev/null
+++ b/test/SemaCXX/extern-c.cpp
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+namespace test1 {
+ extern "C" {
+ void f() {
+ void test1_g(int); // expected-note {{previous declaration is here}}
+ }
+ }
+}
+int test1_g(int); // expected-error {{functions that differ only in their return type cannot be overloaded}}
+
+namespace test2 {
+ extern "C" {
+ void f() {
+ extern int test2_x; // expected-note {{previous definition is here}}
+ }
+ }
+}
+float test2_x; // expected-error {{redefinition of 'test2_x' with a different type: 'float' vs 'int'}}
+
+namespace test3 {
+ extern "C" {
+ void f() {
+ extern int test3_b; // expected-note {{previous definition is here}}
+ }
+ }
+ extern "C" {
+ float test3_b; // expected-error {{redefinition of 'test3_b' with a different type: 'float' vs 'int'}}
+ }
+}
+
+extern "C" {
+ void test4_f() {
+ extern int test4_b; // expected-note {{previous definition is here}}
+ }
+}
+static float test4_b; // expected-error {{redefinition of 'test4_b' with a different type: 'float' vs 'int'}}
+
+extern "C" {
+ void test5_f() {
+ extern int test5_b; // expected-note {{previous definition is here}}
+ }
+}
+extern "C" {
+ static float test5_b; // expected-error {{redefinition of 'test5_b' with a different type: 'float' vs 'int'}}
+}
+
+extern "C" {
+ void f() {
+ extern int test6_b;
+ }
+}
+namespace foo {
+ extern "C" {
+ static float test6_b;
+ extern float test6_b;
+ }
+}
diff --git a/test/SemaCXX/friend.cpp b/test/SemaCXX/friend.cpp
index c5b11eb..b401a06 100644
--- a/test/SemaCXX/friend.cpp
+++ b/test/SemaCXX/friend.cpp
@@ -138,3 +138,19 @@ namespace test7 {
};
}
}
+
+// PR15485
+namespace test8 {
+ namespace ns1 {
+ namespace ns2 {
+ template<class T> void f(T t); // expected-note {{target of using declaration}}
+ }
+ using ns2::f; // expected-note {{using declaration}}
+ }
+ struct A { void f(); }; // expected-note {{target of using declaration}}
+ struct B : public A { using A::f; }; // expected-note {{using declaration}}
+ struct X {
+ template<class T> friend void ns1::f(T t); // expected-error {{cannot befriend target of using declaration}}
+ friend void B::f(); // expected-error {{cannot befriend target of using declaration}}
+ };
+}
diff --git a/test/SemaCXX/function-extern-c.cpp b/test/SemaCXX/function-extern-c.cpp
index 16dbbb2..6ab9657 100644
--- a/test/SemaCXX/function-extern-c.cpp
+++ b/test/SemaCXX/function-extern-c.cpp
@@ -38,3 +38,61 @@ extern "C" long long f11( void );
extern "C" A *f10( void );
extern "C" struct mypodstruct f12(); // expected-warning {{'f12' has C-linkage specified, but returns incomplete type 'struct mypodstruct' which could be incompatible with C}}
+
+namespace test2 {
+ // FIXME: we should probably suppress the first warning as the second one
+ // is more precise.
+ // For now this tests that a second 'extern "C"' is not necessary to trigger
+ // the warning.
+ struct A;
+ extern "C" A f(void); // expected-warning {{'f' has C-linkage specified, but returns incomplete type 'test2::A' which could be incompatible with C}}
+ struct A {
+ A(const A&);
+ };
+ A f(void); // no warning. warning is already issued on first declaration.
+}
+
+namespace test3 {
+ struct A {
+ A(const A&);
+ };
+ extern "C" {
+ // Don't warn for static functions.
+ static A f(void);
+ }
+}
+
+// rdar://13364028
+namespace rdar13364028 {
+class A {
+public:
+ virtual int x();
+};
+
+extern "C" {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
+A xyzzy();
+#pragma clang diagnostic pop
+A bbb(); // expected-warning {{'bbb' has C-linkage specified, but returns user-defined type 'rdar13364028::A' which is incompatible with C}}
+A ccc() { // expected-warning {{'ccc' has C-linkage specified, but returns user-defined type 'rdar13364028::A' which is incompatible with C}}
+ return A();
+};
+}
+
+A xyzzy();
+
+A xyzzy()
+{
+ return A();
+}
+
+A bbb()
+{
+ return A();
+}
+
+A bbb();
+
+A ccc();
+}
diff --git a/test/SemaCXX/implicit-member-functions.cpp b/test/SemaCXX/implicit-member-functions.cpp
index 8451739..b5f7fe1 100644
--- a/test/SemaCXX/implicit-member-functions.cpp
+++ b/test/SemaCXX/implicit-member-functions.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
struct A { };
A::A() { } // expected-error {{definition of implicitly declared default constructor}}
@@ -50,3 +50,70 @@ namespace PR7594 {
};
C *C::c = new C();
}
+
+namespace Recursion {
+ template<typename T> struct InvokeCopyConstructor {
+ static const T &get();
+ typedef decltype(T(get())) type; // expected-error {{no matching conver}}
+ };
+ struct B;
+ struct A {
+ typedef B type;
+ template<typename T,
+ typename = typename InvokeCopyConstructor<typename T::type>::type>
+ // expected-note@-1 {{in instantiation of template class}}
+ A(const T &);
+ // expected-note@-1 {{in instantiation of default argument}}
+ // expected-note@-2 {{while substituting deduced template arguments}}
+ };
+ struct B { // expected-note {{candidate constructor (the implicit move }}
+ B(); // expected-note {{candidate constructor not viable}}
+ A a;
+ };
+ // Triggering the declaration of B's copy constructor causes overload
+ // resolution to occur for A's copying constructor, which instantiates
+ // InvokeCopyConstructor<B>, which triggers the declaration of B's copy
+ // constructor. Notionally, this happens when we get to the end of the
+ // definition of 'struct B', so there is no declared copy constructor yet.
+ //
+ // This behavior is g++-compatible, but isn't exactly right; the class is
+ // supposed to be incomplete when we implicitly declare its special members.
+ B b = B();
+
+
+ // Another case, which isn't ill-formed under our rules. This is inspired by
+ // a problem which occurs when combining CGAL with libstdc++-4.7.
+
+ template<typename T> T &&declval();
+ template<typename T, typename U> struct pair {
+ pair();
+ template<typename V, typename W,
+ typename = decltype(T(declval<const V&>())),
+ typename = decltype(U(declval<const W&>()))>
+ pair(const pair<V,W> &);
+ };
+
+ template<typename K> struct Line;
+
+ template<typename K> struct Vector {
+ Vector(const Line<K> &l);
+ };
+
+ template<typename K> struct Point {
+ Vector<K> v;
+ };
+
+ template<typename K> struct Line {
+ pair<Point<K>, Vector<K>> x;
+ };
+
+ // Trigger declaration of Line copy ctor, which causes substitution into
+ // pair's templated constructor, which triggers instantiation of the
+ // definition of Point's copy constructor, which performs overload resolution
+ // on Vector's constructors, which requires declaring all of Line's
+ // constructors. That should not find a copy constructor (because we've not
+ // declared it yet), but by the time we get all the way back here, we should
+ // find the copy constructor.
+ Line<void> L1;
+ Line<void> L2(L1);
+}
diff --git a/test/SemaCXX/lambda-expressions.cpp b/test/SemaCXX/lambda-expressions.cpp
index 6f92373..a333f38 100644
--- a/test/SemaCXX/lambda-expressions.cpp
+++ b/test/SemaCXX/lambda-expressions.cpp
@@ -236,3 +236,7 @@ namespace PR13860 {
namespace PR13854 {
auto l = [](void){};
}
+
+namespace PR14518 {
+ auto f = [](void) { return __func__; }; // no-warning
+}
diff --git a/test/SemaCXX/linkage-spec.cpp b/test/SemaCXX/linkage-spec.cpp
index cb7e32c..0ba9508 100644
--- a/test/SemaCXX/linkage-spec.cpp
+++ b/test/SemaCXX/linkage-spec.cpp
@@ -90,6 +90,10 @@ extern "C++" using N::value;
// PR7076
extern "C" const char *Version_string = "2.9";
+extern "C" {
+ extern const char *Version_string2 = "2.9";
+}
+
namespace PR9162 {
extern "C" {
typedef struct _ArtsSink ArtsSink;
diff --git a/test/SemaCXX/linkage2.cpp b/test/SemaCXX/linkage2.cpp
new file mode 100644
index 0000000..ddf4064
--- /dev/null
+++ b/test/SemaCXX/linkage2.cpp
@@ -0,0 +1,154 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -fmodules %s
+
+namespace test1 {
+ int x; // expected-note {{previous definition is here}}
+ static int y;
+ void f() {} // expected-note {{previous definition is here}}
+
+ extern "C" {
+ extern int x; // expected-error {{declaration of 'x' has a different language linkage}}
+ extern int y; // OK, has internal linkage, so no language linkage.
+ void f(); // expected-error {{declaration of 'f' has a different language linkage}}
+ }
+}
+
+// This is OK. Both test2_f don't have language linkage since they have
+// internal linkage.
+extern "C" {
+ static void test2_f() {
+ }
+ static void test2_f(int x) {
+ }
+}
+
+namespace test3 {
+ extern "C" {
+ namespace {
+ extern int x2;
+ void f2();
+ }
+ }
+ namespace {
+ int x2;
+ void f2() {}
+ }
+}
+
+namespace test4 {
+ void dummy() {
+ void Bar();
+ class A {
+ friend void Bar();
+ };
+ }
+}
+
+namespace test5 {
+ static void g();
+ void f()
+ {
+ void g();
+ }
+}
+
+// pr14898
+namespace test6 {
+ template <class _Rp>
+ class __attribute__ ((__visibility__("default"))) shared_future;
+ template <class _Rp>
+ class future {
+ template <class> friend class shared_future;
+ shared_future<_Rp> share();
+ };
+ template <class _Rp> future<_Rp>
+ get_future();
+ template <class _Rp>
+ struct shared_future<_Rp&> {
+ shared_future(future<_Rp&>&& __f); // expected-warning {{rvalue references are a C++11 extension}}
+ };
+ void f() {
+ typedef int T;
+ get_future<int>();
+ typedef int& U;
+ shared_future<int&> f1 = get_future<int&>();
+ }
+}
+
+// This is OK. The variables have internal linkage and therefore no language
+// linkage.
+extern "C" {
+ static int test7_x;
+}
+extern "C++" {
+ extern int test7_x;
+}
+extern "C++" {
+ static int test7_y;
+}
+extern "C" {
+ extern int test7_y;
+}
+extern "C" { typedef int test7_F(); static test7_F test7_f; }
+extern "C++" { extern test7_F test7_f; }
+
+// FIXME: This should be invalid. The function has no language linkage, but
+// the function type has, so this is redeclaring the function with a different
+// type.
+extern "C++" {
+ static void test8_f();
+}
+extern "C" {
+ extern void test8_f();
+}
+extern "C" {
+ static void test8_g();
+}
+extern "C++" {
+ extern void test8_g();
+}
+
+extern "C" {
+ void __attribute__((overloadable)) test9_f(int c); // expected-note {{previous declaration is here}}
+}
+extern "C++" {
+ void __attribute__((overloadable)) test9_f(int c); // expected-error {{declaration of 'test9_f' has a different language linkage}}
+}
+
+extern "C" {
+ void __attribute__((overloadable)) test10_f(int);
+ void __attribute__((overloadable)) test10_f(double);
+}
+
+extern "C" {
+ void test11_f() {
+ void __attribute__((overloadable)) test11_g(int);
+ void __attribute__((overloadable)) test11_g(double);
+ }
+}
+
+namespace test12 {
+ const int n = 0;
+ extern const int n;
+ void f() {
+ extern const int n;
+ }
+}
+
+namespace test13 {
+ static void a(void);
+ extern void a();
+ static void a(void) {}
+}
+
+namespace test14 {
+ namespace {
+ void a(void); // expected-note {{previous declaration is here}}
+ static void a(void) {} // expected-error {{static declaration of 'a' follows non-static declaration}}
+ }
+}
+
+namespace test15 {
+ const int a = 5; // expected-note {{previous definition is here}}
+ static const int a; // expected-error {{redefinition of 'a'}}
+}
diff --git a/test/SemaCXX/member-expr.cpp b/test/SemaCXX/member-expr.cpp
index 763f9c7..515bcd4 100644
--- a/test/SemaCXX/member-expr.cpp
+++ b/test/SemaCXX/member-expr.cpp
@@ -111,8 +111,13 @@ namespace rdar8231724 {
struct X { };
struct Y : X { };
+ template<typename T> struct Z { int n; };
+
void f(Y *y) {
y->N::X1<int>; // expected-error{{'rdar8231724::N::X1' is not a member of class 'rdar8231724::Y'}}
+ y->Z<int>::n; // expected-error{{'rdar8231724::Z<int>::n' is not a member of class 'rdar8231724::Y'}}
+ y->template Z<int>::n; // expected-error{{'rdar8231724::Z<int>::n' is not a member of class 'rdar8231724::Y'}} \
+ // expected-warning{{'template' keyword outside of a template}}
}
}
diff --git a/test/SemaCXX/member-init.cpp b/test/SemaCXX/member-init.cpp
index a13941f..19e8e75 100644
--- a/test/SemaCXX/member-init.cpp
+++ b/test/SemaCXX/member-init.cpp
@@ -73,3 +73,19 @@ namespace PR10578 {
} catch(...) {
}
}
+
+namespace PR14838 {
+ struct base { ~base() {} };
+ class function : base {
+ ~function() {} // expected-note {{implicitly declared private here}}
+ public:
+ function(...) {}
+ };
+ struct thing {};
+ struct another {
+ another() : r(thing()) {}
+ // expected-error@-1 {{temporary of type 'const PR14838::function' has private destructor}}
+ // expected-warning@-2 {{binding reference member 'r' to a temporary value}}
+ const function &r; // expected-note {{reference member declared here}}
+ } af;
+}
diff --git a/test/SemaCXX/member-pointer-ms.cpp b/test/SemaCXX/member-pointer-ms.cpp
index 3b2d0fc..7dca121 100644
--- a/test/SemaCXX/member-pointer-ms.cpp
+++ b/test/SemaCXX/member-pointer-ms.cpp
@@ -1,14 +1,167 @@
-// RUN: %clang_cc1 -cxx-abi microsoft -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -cxx-abi microsoft -fms-compatibility -fsyntax-only -triple=i386-pc-win32 -verify %s
+// RUN: %clang_cc1 -std=c++11 -cxx-abi microsoft -fms-compatibility -fsyntax-only -triple=x86_64-pc-win32 -verify %s
+//
+// This file should also give no diagnostics when run through cl.exe from MSVS
+// 2012, which supports C++11 and static_assert. It should pass for both 64-bit
+// and 32-bit x86.
+//
+// expected-no-diagnostics
-// Test that we reject pointers to members of incomplete classes (for now)
-struct A; //expected-note{{forward declaration of 'A'}}
-int A::*pai1; //expected-error{{incomplete type 'A'}}
+// Test the size of various member pointer combinations:
+// - complete and incomplete
+// - single, multiple, and virtual inheritance (and unspecified for incomplete)
+// - data and function pointers
+// - templated with declared specializations with annotations
+// - template that can be instantiated
-// Test that we don't allow reinterpret_casts from pointers of one size to
-// pointers of a different size.
-struct A {};
-struct B {};
-struct C: A, B {};
+// http://llvm.org/PR12070
+struct Foo {
+ typedef int Foo::*FooInt;
+ int f;
+};
-void (A::*paf)();
-void (C::*pcf)() = reinterpret_cast<void (C::*)()>(paf); //expected-error{{cannot reinterpret_cast from member pointer type}}
+enum {
+ kSingleDataSize = 1 * sizeof(int),
+ kSingleFunctionSize = 1 * sizeof(void *),
+ kMultipleDataSize = 1 * sizeof(int),
+ kMultipleFunctionSize = 2 * sizeof(void *),
+ kVirtualDataSize = 2 * sizeof(int),
+ kVirtualFunctionSize = 2 * sizeof(int) + 1 * sizeof(void *),
+ // Unspecified is weird, it's 1 more slot than virtual.
+ kUnspecifiedDataSize = kVirtualDataSize + 1 * sizeof(int),
+ kUnspecifiedFunctionSize = kVirtualFunctionSize + 1 * sizeof(void *),
+};
+
+// incomplete types
+class __single_inheritance IncSingle;
+class __multiple_inheritance IncMultiple;
+class __virtual_inheritance IncVirtual;
+static_assert(sizeof(int IncSingle::*) == kSingleDataSize, "");
+static_assert(sizeof(int IncMultiple::*) == kMultipleDataSize, "");
+static_assert(sizeof(int IncVirtual::*) == kVirtualDataSize, "");
+static_assert(sizeof(void (IncSingle::*)()) == kSingleFunctionSize, "");
+static_assert(sizeof(void (IncMultiple::*)()) == kMultipleFunctionSize, "");
+static_assert(sizeof(void (IncVirtual::*)()) == kVirtualFunctionSize, "");
+
+// An incomplete type with an unspecified inheritance model seems to take one
+// more slot than virtual. It's not clear what it's used for yet.
+class IncUnspecified;
+static_assert(sizeof(int IncUnspecified::*) == kUnspecifiedDataSize, "");
+static_assert(sizeof(void (IncUnspecified::*)()) == kUnspecifiedFunctionSize, "");
+
+// complete types
+struct B1 { };
+struct B2 { };
+struct Single { };
+struct Multiple : B1, B2 { };
+struct Virtual : virtual B1 { };
+static_assert(sizeof(int Single::*) == kSingleDataSize, "");
+static_assert(sizeof(int Multiple::*) == kMultipleDataSize, "");
+static_assert(sizeof(int Virtual::*) == kVirtualDataSize, "");
+static_assert(sizeof(void (Single::*)()) == kSingleFunctionSize, "");
+static_assert(sizeof(void (Multiple::*)()) == kMultipleFunctionSize, "");
+static_assert(sizeof(void (Virtual::*)()) == kVirtualFunctionSize, "");
+
+// Test both declared and defined templates.
+template <typename T> class X;
+template <> class __single_inheritance X<IncSingle>;
+template <> class __multiple_inheritance X<IncMultiple>;
+template <> class __virtual_inheritance X<IncVirtual>;
+// Don't declare X<IncUnspecified>.
+static_assert(sizeof(int X<IncSingle>::*) == kSingleDataSize, "");
+static_assert(sizeof(int X<IncMultiple>::*) == kMultipleDataSize, "");
+static_assert(sizeof(int X<IncVirtual>::*) == kVirtualDataSize, "");
+static_assert(sizeof(int X<IncUnspecified>::*) == kUnspecifiedDataSize, "");
+static_assert(sizeof(void (X<IncSingle>::*)()) == kSingleFunctionSize, "");
+static_assert(sizeof(void (X<IncMultiple>::*)()) == kMultipleFunctionSize, "");
+static_assert(sizeof(void (X<IncVirtual>::*)()) == kVirtualFunctionSize, "");
+static_assert(sizeof(void (X<IncUnspecified>::*)()) == kUnspecifiedFunctionSize, "");
+
+template <typename T>
+struct Y : T { };
+static_assert(sizeof(int Y<Single>::*) == kSingleDataSize, "");
+static_assert(sizeof(int Y<Multiple>::*) == kMultipleDataSize, "");
+static_assert(sizeof(int Y<Virtual>::*) == kVirtualDataSize, "");
+static_assert(sizeof(void (Y<Single>::*)()) == kSingleFunctionSize, "");
+static_assert(sizeof(void (Y<Multiple>::*)()) == kMultipleFunctionSize, "");
+static_assert(sizeof(void (Y<Virtual>::*)()) == kVirtualFunctionSize, "");
+
+struct A { int x; void bar(); };
+struct B : A { virtual void foo(); };
+static_assert(sizeof(int B::*) == kSingleDataSize, "");
+// A non-primary base class uses the multiple inheritance model for member
+// pointers.
+static_assert(sizeof(void (B::*)()) == kMultipleFunctionSize, "");
+
+struct AA { int x; virtual void foo(); };
+struct BB : AA { void bar(); };
+struct CC : BB { virtual void baz(); };
+static_assert(sizeof(void (CC::*)()) == kSingleFunctionSize, "");
+
+// We start out unspecified.
+struct ForwardDecl1;
+struct ForwardDecl2;
+
+// Re-declare to force us to iterate decls when adding attributes.
+struct ForwardDecl1;
+struct ForwardDecl2;
+
+typedef int ForwardDecl1::*MemPtr1;
+typedef int ForwardDecl2::*MemPtr2;
+MemPtr1 variable_forces_sizing;
+
+struct ForwardDecl1 : B {
+ virtual void foo();
+};
+struct ForwardDecl2 : B {
+ virtual void foo();
+};
+
+static_assert(sizeof(variable_forces_sizing) == kUnspecifiedDataSize, "");
+static_assert(sizeof(MemPtr1) == kUnspecifiedDataSize, "");
+// FIXME: Clang fails this assert because it locks in the inheritance model at
+// the point of the typedef instead of the first usage, while MSVC does not.
+//static_assert(sizeof(MemPtr2) == kSingleDataSize, "");
+
+struct MemPtrInBody {
+ typedef int MemPtrInBody::*MemPtr;
+ int a;
+ operator MemPtr() const {
+ return a ? &MemPtrInBody::a : 0;
+ }
+};
+
+static_assert(sizeof(MemPtrInBody::MemPtr) == kSingleDataSize, "");
+
+// Passing a member pointer through a template should get the right size.
+template<typename T>
+struct SingleTemplate;
+template<typename T>
+struct SingleTemplate<void (T::*)(void)> {
+ static_assert(sizeof(int T::*) == kSingleDataSize, "");
+ static_assert(sizeof(void (T::*)()) == kSingleFunctionSize, "");
+};
+
+template<typename T>
+struct UnspecTemplate;
+template<typename T>
+struct UnspecTemplate<void (T::*)(void)> {
+ static_assert(sizeof(int T::*) == kUnspecifiedDataSize, "");
+ static_assert(sizeof(void (T::*)()) == kUnspecifiedFunctionSize, "");
+};
+
+struct NewUnspecified;
+SingleTemplate<void (IncSingle::*)()> tmpl_single;
+UnspecTemplate<void (NewUnspecified::*)()> tmpl_unspec;
+
+struct NewUnspecified { };
+
+static_assert(sizeof(void (NewUnspecified::*)()) == kUnspecifiedFunctionSize, "");
+
+template <typename T>
+struct MemPtrInTemplate {
+ // We can't require that the template arg be complete until we're
+ // instantiated.
+ int T::*data_ptr;
+ void (T::*func_ptr)();
+};
diff --git a/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp b/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp
index 83f8395..40bcf45 100644
--- a/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp
+++ b/test/SemaCXX/missing-namespace-qualifier-typo-corrections.cpp
@@ -70,7 +70,7 @@ namespace llvm {
struct S {};
void bar() {
GraphWriter<S> x; //expected-error{{no template named 'GraphWriter'; did you mean 'llvm::GraphWriter'?}}
- (void)new llvm::GraphWriter; // expected-error {{use of class template llvm::GraphWriter requires template arguments}}
+ (void)new llvm::GraphWriter; // expected-error {{use of class template 'llvm::GraphWriter' requires template arguments}}
(void)new llvm::Graphwriter<S>; // expected-error {{no template named 'Graphwriter' in namespace 'llvm'; did you mean 'GraphWriter'?}}
}
diff --git a/test/SemaCXX/new-delete.cpp b/test/SemaCXX/new-delete.cpp
index e77e3d6..8b35295 100644
--- a/test/SemaCXX/new-delete.cpp
+++ b/test/SemaCXX/new-delete.cpp
@@ -499,3 +499,14 @@ namespace PR12061 {
DeferredCookieTaskTest() {}
};
}
+
+class DeletingPlaceholder {
+ int* f() {
+ delete f; // expected-error {{reference to non-static member function must be called; did you mean to call it with no arguments?}}
+ return 0;
+ }
+ int* g(int, int) {
+ delete g; // expected-error {{reference to non-static member function must be called}}
+ return 0;
+ }
+};
diff --git a/test/SemaCXX/nullptr.cpp b/test/SemaCXX/nullptr.cpp
index d148f76..b49f63b 100644
--- a/test/SemaCXX/nullptr.cpp
+++ b/test/SemaCXX/nullptr.cpp
@@ -57,7 +57,7 @@ nullptr_t f(nullptr_t null)
o2(nullptr); // expected-error {{ambiguous}}
// nullptr is an rvalue, null is an lvalue
- (void)&nullptr; // expected-error {{address expression must be an lvalue}}
+ (void)&nullptr; // expected-error {{cannot take the address of an rvalue of type 'nullptr_t'}}
nullptr_t *pn = &null;
// You can reinterpret_cast nullptr to an integer.
diff --git a/test/SemaCXX/overload-decl.cpp b/test/SemaCXX/overload-decl.cpp
index c610ff7..9bba47a 100644
--- a/test/SemaCXX/overload-decl.cpp
+++ b/test/SemaCXX/overload-decl.cpp
@@ -29,3 +29,6 @@ class X {
static void g(float);
static void g(int); // expected-error {{static and non-static member functions with the same parameter types cannot be overloaded}}
};
+
+int main() {} // expected-note {{previous definition is here}}
+int main(int,char**) {} // expected-error {{conflicting types for 'main'}}
diff --git a/test/SemaCXX/overload-member-call.cpp b/test/SemaCXX/overload-member-call.cpp
index 0958620..e0f34d9 100644
--- a/test/SemaCXX/overload-member-call.cpp
+++ b/test/SemaCXX/overload-member-call.cpp
@@ -105,3 +105,11 @@ namespace test1 {
}
}
+namespace b7398190 {
+ struct S {
+ int f(); // expected-note {{'this' argument has type 'const b7398190::S', but method is not marked const}}
+ void f(int); // expected-note {{requires 1 argument, but 0 were provided}}
+ };
+ const S *p;
+ int k = p->f(); // expected-error {{no matching member function for call to 'f'}}
+}
diff --git a/test/SemaCXX/overloaded-builtin-operators.cpp b/test/SemaCXX/overloaded-builtin-operators.cpp
index 19dc338..7899403 100644
--- a/test/SemaCXX/overloaded-builtin-operators.cpp
+++ b/test/SemaCXX/overloaded-builtin-operators.cpp
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fshow-overloads=best -verify %s
-// REQUIRES: LP64
+// RUN: %clang_cc1 -fsyntax-only -fshow-overloads=best -verify -triple x86_64-linux-gnu %s
struct yes;
struct no;
diff --git a/test/SemaCXX/overloaded-operator.cpp b/test/SemaCXX/overloaded-operator.cpp
index 8ecb54d..e5b3fab 100644
--- a/test/SemaCXX/overloaded-operator.cpp
+++ b/test/SemaCXX/overloaded-operator.cpp
@@ -415,3 +415,28 @@ namespace PR11784 {
void f(int);
void g() { A x; x = f; }
}
+
+namespace test10 {
+ struct A {
+ void operator[](float (*fn)(int)); // expected-note 2 {{not viable: no overload of 'bar' matching 'float (*)(int)'}}
+ };
+
+ float foo(int);
+ float foo(float);
+
+ template <class T> T bar(T);
+ template <class T, class U> T bar(U);
+
+ void test(A &a) {
+ a[&foo];
+ a[foo];
+
+ a[&bar<int>]; // expected-error {{no viable overloaded operator[]}}
+ a[bar<int>]; // expected-error {{no viable overloaded operator[]}}
+
+ // If these fail, it's because we're not letting the overload
+ // resolution for operator| resolve the overload of 'bar'.
+ a[&bar<float>];
+ a[bar<float>];
+ }
+}
diff --git a/test/SemaCXX/pragma-weak.cpp b/test/SemaCXX/pragma-weak.cpp
new file mode 100644
index 0000000..057cf6b
--- /dev/null
+++ b/test/SemaCXX/pragma-weak.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s
+
+#pragma weak foo
+static void foo();
+extern "C" {
+ void foo() {
+ };
+}
diff --git a/test/SemaCXX/pseudo-destructors.cpp b/test/SemaCXX/pseudo-destructors.cpp
index a8f6683..95363e5 100644
--- a/test/SemaCXX/pseudo-destructors.cpp
+++ b/test/SemaCXX/pseudo-destructors.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
struct A {};
enum Foo { F };
@@ -80,3 +80,8 @@ namespace PR11339 {
template void destroy(int*); // expected-note{{in instantiation of function template specialization}}
}
+
+template<typename T> using Id = T;
+void AliasTemplate(int *p) {
+ p->~Id<int>();
+}
diff --git a/test/SemaCXX/qualified-names-print.cpp b/test/SemaCXX/qualified-names-print.cpp
deleted file mode 100644
index 2099268..0000000
--- a/test/SemaCXX/qualified-names-print.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-// RUN: %clang_cc1 -ast-print %s 2>&1 | grep "N::M::X<INT>::value"
-namespace N {
- namespace M {
- template<typename T>
- struct X {
- enum { value };
- };
- }
-}
-
-typedef int INT;
-
-int test() {
- return N::M::X<INT>::value;
-}
diff --git a/test/SemaCXX/return.cpp b/test/SemaCXX/return.cpp
index 2f98a27..580f0a7 100644
--- a/test/SemaCXX/return.cpp
+++ b/test/SemaCXX/return.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 %s -fcxx-exceptions -fexceptions -fsyntax-only -Wignored-qualifiers -verify
+// RUN: %clang_cc1 %s -std=c++11 -fcxx-exceptions -fexceptions -fsyntax-only -Wignored-qualifiers -verify
int test1() {
throw;
@@ -45,6 +45,27 @@ const
j();
const volatile int scalar_cv(); // expected-warning{{'const volatile' type qualifiers on return type have no effect}}
+
+// FIXME: Maintain enough information that we can point the diagnostic at the 'volatile' keyword.
+const
+int S::*
+volatile
+mixed_ret(); // expected-warning {{'volatile' type qualifier on return type has no effect}}
+
+const int volatile // expected-warning {{'const volatile' type qualifiers on return type have no effect}}
+ (((parens())));
+
+_Atomic(int) atomic();
+
+_Atomic // expected-warning {{'_Atomic' type qualifier on return type has no effect}}
+ int
+ atomic();
+
+auto
+ trailing_return_type() -> // expected-warning {{'const' type qualifier on return type has no effect}}
+ const int;
+
+const int ret_array()[4]; // expected-error {{cannot return array}}
}
namespace PR9328 {
@@ -56,6 +77,7 @@ namespace PR9328 {
}
class foo {
+ operator const int ();
operator int * const ();
};
diff --git a/test/SemaCXX/scope-check.cpp b/test/SemaCXX/scope-check.cpp
index 8fd23f4..de276ae 100644
--- a/test/SemaCXX/scope-check.cpp
+++ b/test/SemaCXX/scope-check.cpp
@@ -274,3 +274,15 @@ namespace test15 {
goto x; // expected-error {{goto into protected scope}}
}
}
+
+namespace test16 {
+Invalid inv; // expected-error {{unknown type name}}
+// Make sure this doesn't assert.
+void fn()
+{
+ int c = 0;
+ if (inv)
+Here: ;
+ goto Here;
+}
+}
diff --git a/test/SemaCXX/sourceranges.cpp b/test/SemaCXX/sourceranges.cpp
index 0537aa2..1f25d5b 100644
--- a/test/SemaCXX/sourceranges.cpp
+++ b/test/SemaCXX/sourceranges.cpp
@@ -7,11 +7,14 @@ class P {
};
namespace foo {
-class A {};
+class A { public: A() {} };
enum B {};
typedef int C;
}
+// CHECK: VarDecl {{0x[0-9a-fA-F]+}} <line:16:1, col:36> ImplicitConstrArray 'foo::A [2]'
+static foo::A ImplicitConstrArray[2];
+
int main() {
// CHECK: CXXNewExpr {{0x[0-9a-fA-F]+}} <col:19, col:28> 'foo::A *'
P<foo::A> p14 = new foo::A;
diff --git a/test/SemaCXX/storage-class.cpp b/test/SemaCXX/storage-class.cpp
index 01cfbfc..7412184 100644
--- a/test/SemaCXX/storage-class.cpp
+++ b/test/SemaCXX/storage-class.cpp
@@ -3,5 +3,5 @@ extern const int PR6495a = 42;
extern int PR6495b = 42; // expected-warning{{'extern' variable has an initializer}}
extern const int PR6495c[] = {42,43,44};
-extern struct Test1 {}; // expected-warning {{'extern' ignored on this declaration}}
+extern struct Test1 {}; // expected-warning {{'extern' is not permitted on a declaration of a type}}
extern "C" struct Test0 {}; // no warning
diff --git a/test/SemaCXX/switch-implicit-fallthrough.cpp b/test/SemaCXX/switch-implicit-fallthrough.cpp
index cfc29c2..d795923 100644
--- a/test/SemaCXX/switch-implicit-fallthrough.cpp
+++ b/test/SemaCXX/switch-implicit-fallthrough.cpp
@@ -10,7 +10,7 @@ int fallthrough(int n) {
} else if (n - 3) {
n = 102;
}
- case -1: // expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert '[[clang::fallthrough]];' to silence this warning}} expected-note{{insert 'break;' to avoid fall-through}}
+ case -1: // no warning here, ignore fall-through from unreachable code
;
case 0: {// expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert '[[clang::fallthrough]];' to silence this warning}} expected-note{{insert 'break;' to avoid fall-through}}
}
@@ -34,6 +34,19 @@ int fallthrough(int n) {
case 6: // expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert '[[clang::fallthrough]];' to silence this warning}} expected-note{{insert 'break;' to avoid fall-through}}
n += 300;
case 66: // expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert 'break;' to avoid fall-through}}
+ case 67:
+ case 68:
+ break;
+ }
+ switch (n / 15) {
+label_default:
+ default:
+ n += 333;
+ if (n % 10)
+ goto label_default;
+ break;
+ case 70:
+ n += 335;
break;
}
switch (n / 20) {
@@ -116,6 +129,22 @@ void fallthrough2(int n) {
}
}
+void fallthrough3(int n) {
+ switch (n) {
+ case 1:
+ do {
+ return;
+ } while (0);
+ case 2:
+ do {
+ ClassWithDtor temp;
+ return;
+ } while (0);
+ case 3:
+ break;
+ }
+}
+
#define MY_SWITCH(X, Y, Z, U, V) switch (X) { case Y: Z; case U: V; }
#define MY_SWITCH2(X, Y, Z) switch (X) { Y; Z; }
#define MY_CASE(X, Y) case X: Y
@@ -143,40 +172,63 @@ int fallthrough_macro1(int n) {
return n;
}
+void fallthrough_cfgblock_with_null_successor(int x) {
+ (x && "") ? (void)(0) : (void)(1);
+ switch (x) {}
+}
+
int fallthrough_position(int n) {
switch (n) {
+ [[clang::fallthrough]]; // expected-warning{{fallthrough annotation does not directly precede switch label}}
+ n += 300;
[[clang::fallthrough]]; // expected-warning{{fallthrough annotation in unreachable code}}
case 221:
- [[clang::fallthrough]]; // expected-warning{{fallthrough annotation does not directly precede switch label}}
+ [[clang::fallthrough]]; // expected-warning{{fallthrough annotation does not directly precede switch label}}
return 1;
[[clang::fallthrough]]; // expected-warning{{fallthrough annotation in unreachable code}}
case 222:
- [[clang::fallthrough]]; // expected-warning{{fallthrough annotation does not directly precede switch label}}
+ [[clang::fallthrough]]; // expected-warning{{fallthrough annotation does not directly precede switch label}}
n += 400;
case 223: // expected-warning{{unannotated fall-through between switch labels}} expected-note{{insert '[[clang::fallthrough]];' to silence this warning}} expected-note{{insert 'break;' to avoid fall-through}}
[[clang::fallthrough]]; // expected-warning{{fallthrough annotation does not directly precede switch label}}
}
- // TODO: uncomment this test after CFG gets more options to deal with
- // unreachable code:
- // http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20120507/057370.html
-#if 0
long p = static_cast<long>(n) * n;
switch (sizeof(p)) {
- case 9: // this test will not work on compilers with 72-bit long
+ case 9:
n += static_cast<int>(p >> 32);
[[clang::fallthrough]]; // no warning here
- case 5: // it is not intended to work on compilers with 40-bit long as well
+ case 5:
n += static_cast<int>(p);
- break;
+ [[clang::fallthrough]]; // no warning here
default:
- break;
+ n += 1;
+ break;
}
-#endif
return n;
}
+enum Enum {
+ Value1, Value2
+};
+
+int fallthrough_covered_enums(Enum e) {
+ int n = 0;
+ switch (e) {
+ default:
+ n += 17;
+ [[clang::fallthrough]]; // no warning here, this shouldn't be treated as unreachable code
+ case Value1:
+ n += 19;
+ break;
+ case Value2:
+ n += 21;
+ break;
+ }
+ return n;
+}
+
int fallthrough_targets(int n) {
[[clang::fallthrough]]; // expected-error{{fallthrough annotation is outside switch statement}}
@@ -195,3 +247,21 @@ int fallthrough_targets(int n) {
}
return n;
}
+
+// Fallthrough annotations in local classes used to generate "fallthrough
+// annotation does not directly precede switch label" warning.
+void fallthrough_in_local_class() {
+ class C {
+ void f(int x) {
+ switch (x) {
+ case 0:
+ x++;
+ [[clang::fallthrough]]; // no diagnostics
+ case 1:
+ x++;
+ break;
+ }
+ }
+ };
+}
+
diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp
index 54294bc..aa18ff4 100644
--- a/test/SemaCXX/type-traits.cpp
+++ b/test/SemaCXX/type-traits.cpp
@@ -39,9 +39,34 @@ struct DerivesEmpty : Empty {};
struct HasCons { HasCons(int); };
struct HasCopyAssign { HasCopyAssign operator =(const HasCopyAssign&); };
struct HasMoveAssign { HasMoveAssign operator =(const HasMoveAssign&&); };
+struct HasNoThrowMoveAssign {
+ HasNoThrowMoveAssign& operator=(
+ const HasNoThrowMoveAssign&&) throw(); };
+struct HasNoExceptNoThrowMoveAssign {
+ HasNoExceptNoThrowMoveAssign& operator=(
+ const HasNoExceptNoThrowMoveAssign&&) noexcept;
+};
+struct HasThrowMoveAssign {
+ HasThrowMoveAssign& operator=(
+ const HasThrowMoveAssign&&) throw(POD); };
+struct HasNoExceptFalseMoveAssign {
+ HasNoExceptFalseMoveAssign& operator=(
+ const HasNoExceptFalseMoveAssign&&) noexcept(false); };
+struct HasMoveCtor { HasMoveCtor(const HasMoveCtor&&); };
+struct HasMemberMoveCtor { HasMoveCtor member; };
+struct HasMemberMoveAssign { HasMoveAssign member; };
+struct HasStaticMemberMoveCtor { static HasMoveCtor member; };
+struct HasStaticMemberMoveAssign { static HasMoveAssign member; };
+struct HasMemberThrowMoveAssign { HasThrowMoveAssign member; };
+struct HasMemberNoExceptFalseMoveAssign {
+ HasNoExceptFalseMoveAssign member; };
+struct HasMemberNoThrowMoveAssign { HasNoThrowMoveAssign member; };
+struct HasMemberNoExceptNoThrowMoveAssign {
+ HasNoExceptNoThrowMoveAssign member; };
+
struct HasDefaultTrivialCopyAssign {
- HasDefaultTrivialCopyAssign &operator =(const HasDefaultTrivialCopyAssign&)
- = default;
+ HasDefaultTrivialCopyAssign &operator=(
+ const HasDefaultTrivialCopyAssign&) = default;
};
struct TrivialMoveButNotCopy {
TrivialMoveButNotCopy &operator=(TrivialMoveButNotCopy&&) = default;
@@ -69,6 +94,7 @@ struct DerivesHasPriv : HasPriv {};
struct DerivesHasProt : HasProt {};
struct DerivesHasRef : HasRef {};
struct DerivesHasVirt : HasVirt {};
+struct DerivesHasMoveCtor : HasMoveCtor {};
struct HasNoThrowCopyAssign {
void operator =(const HasNoThrowCopyAssign&) throw();
@@ -165,7 +191,7 @@ typedef Empty EmptyAr[10];
struct Bit0 { int : 0; };
struct Bit0Cons { int : 0; Bit0Cons(); };
struct BitOnly { int x : 3; };
-//struct DerivesVirt : virtual POD {};
+struct DerivesVirt : virtual POD {};
void is_empty()
{
@@ -941,6 +967,19 @@ struct AllDefaulted {
~AllDefaulted() = default;
};
+struct NoDefaultMoveAssignDueToUDCopyCtor {
+ NoDefaultMoveAssignDueToUDCopyCtor(const NoDefaultMoveAssignDueToUDCopyCtor&);
+};
+
+struct NoDefaultMoveAssignDueToUDCopyAssign {
+ NoDefaultMoveAssignDueToUDCopyAssign& operator=(
+ const NoDefaultMoveAssignDueToUDCopyAssign&);
+};
+
+struct NoDefaultMoveAssignDueToDtor {
+ ~NoDefaultMoveAssignDueToDtor();
+};
+
struct AllDeleted {
AllDeleted() = delete;
AllDeleted(const AllDeleted &) = delete;
@@ -1203,6 +1242,32 @@ void has_trivial_default_constructor() {
{ int arr[F(__has_trivial_constructor(ExtDefaulted))]; }
}
+void has_trivial_move_constructor() {
+ // n3376 12.8 [class.copy]/12
+ // A copy/move constructor for class X is trivial if it is not
+ // user-provided, its declared parameter type is the same as
+ // if it had been implicitly declared, and if
+ // — class X has no virtual functions (10.3) and no virtual
+ // base classes (10.1), and
+ // — the constructor selected to copy/move each direct base
+ // class subobject is trivial, and
+ // — for each non-static data member of X that is of class
+ // type (or array thereof), the constructor selected
+ // to copy/move that member is trivial;
+ // otherwise the copy/move constructor is non-trivial.
+ { int arr[T(__has_trivial_move_constructor(POD))]; }
+ { int arr[T(__has_trivial_move_constructor(Union))]; }
+ { int arr[T(__has_trivial_move_constructor(HasCons))]; }
+ { int arr[T(__has_trivial_move_constructor(HasStaticMemberMoveCtor))]; }
+ { int arr[T(__has_trivial_move_constructor(AllDeleted))]; }
+
+ { int arr[F(__has_trivial_move_constructor(HasVirt))]; }
+ { int arr[F(__has_trivial_move_constructor(DerivesVirt))]; }
+ { int arr[F(__has_trivial_move_constructor(HasMoveCtor))]; }
+ { int arr[F(__has_trivial_move_constructor(DerivesHasMoveCtor))]; }
+ { int arr[F(__has_trivial_move_constructor(HasMemberMoveCtor))]; }
+}
+
void has_trivial_copy_constructor() {
{ int arr[T(__has_trivial_copy(Int))]; }
{ int arr[T(__has_trivial_copy(IntAr))]; }
@@ -1224,6 +1289,7 @@ void has_trivial_copy_constructor() {
{ int arr[T(__has_trivial_copy(AllDefaulted))]; }
{ int arr[T(__has_trivial_copy(AllDeleted))]; }
{ int arr[T(__has_trivial_copy(DerivesAr))]; }
+ { int arr[T(__has_trivial_copy(DerivesHasRef))]; }
{ int arr[F(__has_trivial_copy(HasCopy))]; }
{ int arr[F(__has_trivial_copy(HasTemplateCons))]; }
@@ -1251,6 +1317,7 @@ void has_trivial_copy_assignment() {
{ int arr[T(__has_trivial_assign(AllDefaulted))]; }
{ int arr[T(__has_trivial_assign(AllDeleted))]; }
{ int arr[T(__has_trivial_assign(DerivesAr))]; }
+ { int arr[T(__has_trivial_assign(DerivesHasRef))]; }
{ int arr[F(__has_trivial_assign(IntRef))]; }
{ int arr[F(__has_trivial_assign(HasCopyAssign))]; }
@@ -1286,6 +1353,7 @@ void has_trivial_destructor() {
{ int arr[T(__has_trivial_destructor(VirtAr))]; }
{ int arr[T(__has_trivial_destructor(AllDefaulted))]; }
{ int arr[T(__has_trivial_destructor(AllDeleted))]; }
+ { int arr[T(__has_trivial_destructor(DerivesHasRef))]; }
{ int arr[F(__has_trivial_destructor(HasDest))]; }
{ int arr[F(__has_trivial_destructor(void))]; }
@@ -1352,6 +1420,54 @@ void has_nothrow_assign() {
{ int arr[F(__has_nothrow_assign(PR11110))]; }
}
+void has_nothrow_move_assign() {
+ { int arr[T(__has_nothrow_move_assign(Int))]; }
+ { int arr[T(__has_nothrow_move_assign(Enum))]; }
+ { int arr[T(__has_nothrow_move_assign(Int*))]; }
+ { int arr[T(__has_nothrow_move_assign(Enum POD::*))]; }
+ { int arr[T(__has_nothrow_move_assign(POD))]; }
+ { int arr[T(__has_nothrow_move_assign(HasPriv))]; }
+ { int arr[T(__has_nothrow_move_assign(HasNoThrowMoveAssign))]; }
+ { int arr[T(__has_nothrow_move_assign(HasNoExceptNoThrowMoveAssign))]; }
+ { int arr[T(__has_nothrow_move_assign(HasMemberNoThrowMoveAssign))]; }
+ { int arr[T(__has_nothrow_move_assign(HasMemberNoExceptNoThrowMoveAssign))]; }
+ { int arr[T(__has_nothrow_move_assign(AllDeleted))]; }
+
+
+ { int arr[F(__has_nothrow_move_assign(HasThrowMoveAssign))]; }
+ { int arr[F(__has_nothrow_move_assign(HasNoExceptFalseMoveAssign))]; }
+ { int arr[F(__has_nothrow_move_assign(HasMemberThrowMoveAssign))]; }
+ { int arr[F(__has_nothrow_move_assign(HasMemberNoExceptFalseMoveAssign))]; }
+ { int arr[F(__has_nothrow_move_assign(NoDefaultMoveAssignDueToUDCopyCtor))]; }
+ { int arr[F(__has_nothrow_move_assign(NoDefaultMoveAssignDueToUDCopyAssign))]; }
+ { int arr[F(__has_nothrow_move_assign(NoDefaultMoveAssignDueToDtor))]; }
+}
+
+void has_trivial_move_assign() {
+ // n3376 12.8 [class.copy]/25
+ // A copy/move assignment operator for class X is trivial if it
+ // is not user-provided, its declared parameter type is the same
+ // as if it had been implicitly declared, and if:
+ // — class X has no virtual functions (10.3) and no virtual base
+ // classes (10.1), and
+ // — the assignment operator selected to copy/move each direct
+ // base class subobject is trivial, and
+ // — for each non-static data member of X that is of class type
+ // (or array thereof), the assignment operator
+ // selected to copy/move that member is trivial;
+ { int arr[T(__has_trivial_move_assign(Int))]; }
+ { int arr[T(__has_trivial_move_assign(HasStaticMemberMoveAssign))]; }
+ { int arr[T(__has_trivial_move_assign(AllDeleted))]; }
+
+ { int arr[F(__has_trivial_move_assign(HasVirt))]; }
+ { int arr[F(__has_trivial_move_assign(DerivesVirt))]; }
+ { int arr[F(__has_trivial_move_assign(HasMoveAssign))]; }
+ { int arr[F(__has_trivial_move_assign(DerivesHasMoveAssign))]; }
+ { int arr[F(__has_trivial_move_assign(HasMemberMoveAssign))]; }
+ { int arr[F(__has_nothrow_move_assign(NoDefaultMoveAssignDueToUDCopyCtor))]; }
+ { int arr[F(__has_nothrow_move_assign(NoDefaultMoveAssignDueToUDCopyAssign))]; }
+}
+
void has_nothrow_copy() {
{ int arr[T(__has_nothrow_copy(Int))]; }
{ int arr[T(__has_nothrow_copy(IntAr))]; }
diff --git a/test/SemaCXX/typo-correction.cpp b/test/SemaCXX/typo-correction.cpp
index c21ef51..caa6355 100644
--- a/test/SemaCXX/typo-correction.cpp
+++ b/test/SemaCXX/typo-correction.cpp
@@ -236,3 +236,27 @@ void test() {
return status; // expected-error-re{{use of undeclared identifier 'status'$}}
}
}
+
+namespace PR13387 {
+struct A {
+ void CreateFoo(float, float); // expected-note {{'CreateFoo' declared here}}
+ void CreateBar(float, float);
+};
+struct B : A {
+ using A::CreateFoo;
+ void CreateFoo(int, int);
+};
+void f(B &x) {
+ x.Createfoo(0,0); // expected-error {{no member named 'Createfoo' in 'PR13387::B'; did you mean 'CreateFoo'?}}
+}
+}
+
+struct DataStruct {void foo();};
+struct T {
+ DataStruct data_struct;
+ void f();
+};
+// should be void T::f();
+void f() {
+ data_struct->foo(); // expected-error-re{{use of undeclared identifier 'data_struct'$}}
+}
diff --git a/test/SemaCXX/undefined-inline.cpp b/test/SemaCXX/undefined-inline.cpp
new file mode 100644
index 0000000..ad719ae
--- /dev/null
+++ b/test/SemaCXX/undefined-inline.cpp
@@ -0,0 +1,57 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// PR14993
+
+namespace test1 {
+ inline void f(); // expected-warning{{inline function 'test1::f' is not defined}}
+ void test() { f(); } // expected-note{{used here}}
+}
+
+namespace test2 {
+ inline int f();
+ void test() { (void)sizeof(f()); }
+}
+
+namespace test3 {
+ void f(); // expected-warning{{inline function 'test3::f' is not defined}}
+ inline void f();
+ void test() { f(); } // expected-note{{used here}}
+}
+
+namespace test4 {
+ inline void error_on_zero(int); // expected-warning{{inline function 'test4::error_on_zero' is not defined}}
+ inline void error_on_zero(char*) {}
+ void test() { error_on_zero(0); } // expected-note{{used here}}
+}
+
+namespace test5 {
+ struct X { void f(); };
+ void test(X &x) { x.f(); }
+}
+
+namespace test6 {
+ struct X { inline void f(); }; // expected-warning{{inline function 'test6::X::f' is not defined}}
+ void test(X &x) { x.f(); } // expected-note{{used here}}
+}
+
+namespace test7 {
+ void f(); // expected-warning{{inline function 'test7::f' is not defined}}
+ void test() { f(); } // no used-here note.
+ inline void f();
+}
+
+namespace test8 {
+ inline void foo() __attribute__((gnu_inline));
+ void test() { foo(); }
+}
+
+namespace test9 {
+ void foo();
+ void test() { foo(); }
+ inline void foo() __attribute__((gnu_inline));
+}
+
+namespace test10 {
+ inline void foo();
+ void test() { foo(); }
+ inline void foo() __attribute__((gnu_inline));
+}
diff --git a/test/SemaCXX/undefined-internal.cpp b/test/SemaCXX/undefined-internal.cpp
index 1541720..839fdaf 100644
--- a/test/SemaCXX/undefined-internal.cpp
+++ b/test/SemaCXX/undefined-internal.cpp
@@ -181,3 +181,145 @@ namespace OverloadUse {
template<void x(int)> void t(long*) { x(10); } // expected-note {{used here}}
void g() { long a; t<f>(&a); }
}
+
+namespace test7 {
+ typedef struct {
+ void bar();
+ void foo() {
+ bar();
+ }
+ } A;
+}
+
+namespace test8 {
+ typedef struct {
+ void bar(); // expected-warning {{function 'test8::<anonymous struct>::bar' has internal linkage but is not defined}}
+ void foo() {
+ bar(); // expected-note {{used here}}
+ }
+ } *A;
+}
+
+namespace test9 {
+ namespace {
+ struct X {
+ virtual void notused() = 0;
+ virtual void used() = 0; // expected-warning {{function 'test9::<anonymous namespace>::X::used' has internal linkage but is not defined}}
+ };
+ }
+ void test(X &x) {
+ x.notused();
+ x.X::used(); // expected-note {{used here}}
+ }
+}
+
+namespace test10 {
+ namespace {
+ struct X {
+ virtual void notused() = 0;
+ virtual void used() = 0; // expected-warning {{function 'test10::<anonymous namespace>::X::used' has internal linkage but is not defined}}
+
+ void test() {
+ notused();
+ (void)&X::notused;
+ (this->*&X::notused)();
+ X::used(); // expected-note {{used here}}
+ }
+ };
+ struct Y : X {
+ using X::notused;
+ };
+ }
+}
+
+namespace test11 {
+ namespace {
+ struct A {
+ virtual bool operator()() const = 0;
+ virtual void operator!() const = 0;
+ virtual bool operator+(const A&) const = 0;
+ virtual int operator[](int) const = 0;
+ virtual const A* operator->() const = 0;
+ int member;
+ };
+
+ struct B {
+ bool operator()() const; // expected-warning {{function 'test11::<anonymous namespace>::B::operator()' has internal linkage but is not defined}}
+ void operator!() const; // expected-warning {{function 'test11::<anonymous namespace>::B::operator!' has internal linkage but is not defined}}
+ bool operator+(const B&) const; // expected-warning {{function 'test11::<anonymous namespace>::B::operator+' has internal linkage but is not defined}}
+ int operator[](int) const; // expected-warning {{function 'test11::<anonymous namespace>::B::operator[]' has internal linkage but is not defined}}
+ const B* operator->() const; // expected-warning {{function 'test11::<anonymous namespace>::B::operator->' has internal linkage but is not defined}}
+ int member;
+ };
+ }
+
+ void test1(A &a1, A &a2) {
+ a1();
+ !a1;
+ a1 + a2;
+ a1[0];
+ (void)a1->member;
+ }
+
+ void test2(B &b1, B &b2) {
+ b1(); // expected-note {{used here}}
+ !b1; // expected-note {{used here}}
+ b1 + b2; // expected-note {{used here}}
+ b1[0]; // expected-note {{used here}}
+ (void)b1->member; // expected-note {{used here}}
+ }
+}
+
+namespace test12 {
+ class T1 {}; class T2 {}; class T3 {}; class T4 {}; class T5 {}; class T6 {};
+ class T7 {};
+
+ namespace {
+ struct Cls {
+ virtual void f(int) = 0;
+ virtual void f(int, double) = 0;
+ void g(int); // expected-warning {{function 'test12::<anonymous namespace>::Cls::g' has internal linkage but is not defined}}
+ void g(int, double);
+ virtual operator T1() = 0;
+ virtual operator T2() = 0;
+ virtual operator T3&() = 0;
+ operator T4(); // expected-warning {{function 'test12::<anonymous namespace>::Cls::operator T4' has internal linkage but is not defined}}
+ operator T5(); // expected-warning {{function 'test12::<anonymous namespace>::Cls::operator T5' has internal linkage but is not defined}}
+ operator T6&(); // expected-warning {{function 'test12::<anonymous namespace>::Cls::operator class test12::T6 &' has internal linkage but is not defined}}
+ };
+
+ struct Cls2 {
+ Cls2(T7); // expected-warning {{function 'test12::<anonymous namespace>::Cls2::Cls2' has internal linkage but is not defined}}
+ };
+ }
+
+ void test(Cls &c) {
+ c.f(7);
+ c.g(7); // expected-note {{used here}}
+ (void)static_cast<T1>(c);
+ T2 t2 = c;
+ T3 &t3 = c;
+ (void)static_cast<T4>(c); // expected-note {{used here}}
+ T5 t5 = c; // expected-note {{used here}}
+ T6 &t6 = c; // expected-note {{used here}}
+
+ Cls2 obj1((T7())); // expected-note {{used here}}
+ }
+}
+
+namespace test13 {
+ namespace {
+ struct X {
+ virtual void f() { }
+ };
+
+ struct Y : public X {
+ virtual void f() = 0;
+
+ virtual void g() {
+ X::f();
+ }
+ };
+ }
+}
+
diff --git a/test/SemaCXX/uninitialized.cpp b/test/SemaCXX/uninitialized.cpp
index f55f10f..2aa5662 100644
--- a/test/SemaCXX/uninitialized.cpp
+++ b/test/SemaCXX/uninitialized.cpp
@@ -41,8 +41,8 @@ void test_stuff () {
int j = far(j);
int k = __alignof__(k);
- int l = k ? l : l; // FIXME: warn here
- int m = 1 + (k ? m : m); // FIXME: warn here
+ int l = k ? l : l; // expected-warning {{variable 'l' is uninitialized when used within its own initialization}}
+ int m = 1 + (k ? m : m); // expected-warning {{'m' is uninitialized when used within its own initialization}}
int n = -n; // expected-warning {{variable 'n' is uninitialized when used within its own initialization}}
for (;;) {
@@ -61,8 +61,8 @@ void test_stuff () {
int j = far(j);
int k = __alignof__(k);
- int l = k ? l : l; // FIXME: warn here
- int m = 1 + (k ? m : m); // FIXME: warn here
+ int l = k ? l : l; // expected-warning {{variable 'l' is uninitialized when used within its own initialization}}
+ int m = 1 + (k ? m : m); // expected-warning {{'m' is uninitialized when used within its own initialization}}
int n = -n; // expected-warning {{variable 'n' is uninitialized when used within its own initialization}}
}
}
@@ -406,11 +406,11 @@ namespace statics {
void test() {
static int a = a; // no-warning: used to signal intended lack of initialization.
- static int b = b + 1; // expected-warning {{variable 'b' is uninitialized when used within its own initialization}}
- static int c = (c + c); // expected-warning 2{{variable 'c' is uninitialized when used within its own initialization}}
- static int d = ({ d + d ;}); // expected-warning 2{{variable 'd' is uninitialized when used within its own initialization}}
- static int e = static_cast<long>(e) + 1; // expected-warning {{variable 'e' is uninitialized when used within its own initialization}}
- static int f = foo(f); // expected-warning {{variable 'f' is uninitialized when used within its own initialization}}
+ static int b = b + 1; // expected-warning {{static variable 'b' is suspiciously used within its own initialization}}
+ static int c = (c + c); // expected-warning 2{{static variable 'c' is suspiciously used within its own initialization}}
+ static int d = ({ d + d ;}); // expected-warning 2{{static variable 'd' is suspiciously used within its own initialization}}
+ static int e = static_cast<long>(e) + 1; // expected-warning {{static variable 'e' is suspiciously used within its own initialization}}
+ static int f = foo(f); // expected-warning {{static variable 'f' is suspiciously used within its own initialization}}
// Thes don't warn as they don't require the value.
static int g = sizeof(g);
@@ -420,16 +420,16 @@ namespace statics {
static int j = far(j);
static int k = __alignof__(k);
- static int l = k ? l : l; // expected-warning 2{{variable 'l' is uninitialized when used within its own initialization}}
- static int m = 1 + (k ? m : m); // expected-warning 2{{variable 'm' is uninitialized when used within its own initialization}}
- static int n = -n; // expected-warning {{variable 'n' is uninitialized when used within its own initialization}}
+ static int l = k ? l : l; // expected-warning 2{{static variable 'l' is suspiciously used within its own initialization}}
+ static int m = 1 + (k ? m : m); // expected-warning 2{{static variable 'm' is suspiciously used within its own initialization}}
+ static int n = -n; // expected-warning {{static variable 'n' is suspiciously used within its own initialization}}
for (;;) {
static int a = a; // no-warning: used to signal intended lack of initialization.
- static int b = b + 1; // expected-warning {{variable 'b' is uninitialized when used within its own initialization}}
- static int c = (c + c); // expected-warning 2{{variable 'c' is uninitialized when used within its own initialization}}
- static int d = ({ d + d ;}); // expected-warning 2{{variable 'd' is uninitialized when used within its own initialization}}
- static int e = static_cast<long>(e) + 1; // expected-warning {{variable 'e' is uninitialized when used within its own initialization}}
- static int f = foo(f); // expected-warning {{variable 'f' is uninitialized when used within its own initialization}}
+ static int b = b + 1; // expected-warning {{static variable 'b' is suspiciously used within its own initialization}}
+ static int c = (c + c); // expected-warning 2{{static variable 'c' is suspiciously used within its own initialization}}
+ static int d = ({ d + d ;}); // expected-warning 2{{static variable 'd' is suspiciously used within its own initialization}}
+ static int e = static_cast<long>(e) + 1; // expected-warning {{static variable 'e' is suspiciously used within its own initialization}}
+ static int f = foo(f); // expected-warning {{static variable 'f' is suspiciously used within its own initialization}}
// Thes don't warn as they don't require the value.
static int g = sizeof(g);
@@ -439,9 +439,9 @@ namespace statics {
static int j = far(j);
static int k = __alignof__(k);
- static int l = k ? l : l; // expected-warning 2{{variable 'l' is uninitialized when used within its own initialization}}
- static int m = 1 + (k ? m : m); // expected-warning 2{{variable 'm' is uninitialized when used within its own initialization}}
- static int n = -n; // expected-warning {{variable 'n' is uninitialized when used within its own initialization}}
+ static int l = k ? l : l; // expected-warning 2{{static variable 'l' is suspiciously used within its own initialization}}
+ static int m = 1 + (k ? m : m); // expected-warning 2{{static variable 'm' is suspiciously used within its own initialization}}
+ static int n = -n; // expected-warning {{static variable 'n' is suspiciously used within its own initialization}}
}
}
}
@@ -496,3 +496,18 @@ namespace references {
int &b;
};
}
+
+namespace operators {
+ struct A {
+ A(bool);
+ bool operator==(A);
+ };
+
+ A makeA();
+
+ A a1 = a1 = makeA(); // expected-warning{{variable 'a1' is uninitialized when used within its own initialization}}
+ A a2 = a2 == a1; // expected-warning{{variable 'a2' is uninitialized when used within its own initialization}}
+ A a3 = a2 == a3; // expected-warning{{variable 'a3' is uninitialized when used within its own initialization}}
+
+ int x = x = 5;
+}
diff --git a/test/SemaCXX/virtual-override-x64.cpp b/test/SemaCXX/virtual-override-x64.cpp
new file mode 100644
index 0000000..8d5aad8
--- /dev/null
+++ b/test/SemaCXX/virtual-override-x64.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -triple=x86_64-pc-unknown -fsyntax-only -verify %s
+
+// Non-x86 targets ignore the calling conventions by default (but will warn
+// when one is encountered), so we want to make sure the virtual overrides
+// continue to work.
+namespace PR14339 {
+ class A {
+ public:
+ virtual void __attribute__((thiscall)) f(); // expected-warning {{calling convention 'thiscall' ignored for this target}}
+ };
+
+ class B : public A {
+ public:
+ void __attribute__((cdecl)) f();
+ };
+
+ class C : public A {
+ public:
+ void __attribute__((thiscall)) f(); // expected-warning {{calling convention 'thiscall' ignored for this target}}
+ };
+
+ class D : public A {
+ public:
+ void f();
+ };
+
+ class E {
+ public:
+ virtual void __attribute__((stdcall)) g(); // expected-warning {{calling convention 'stdcall' ignored for this target}}
+ };
+
+ class F : public E {
+ public:
+ void g();
+ };
+}
diff --git a/test/SemaCXX/virtual-override-x86.cpp b/test/SemaCXX/virtual-override-x86.cpp
new file mode 100644
index 0000000..ad70d3f
--- /dev/null
+++ b/test/SemaCXX/virtual-override-x86.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -triple=i686-pc-unknown -fsyntax-only -verify %s -std=c++11
+
+namespace PR14339 {
+ class A {
+ public:
+ virtual void __attribute__((thiscall)) f(); // expected-note{{overridden virtual function is here}}
+ };
+
+ class B : public A {
+ public:
+ void __attribute__((cdecl)) f(); // expected-error{{virtual function 'f' has different calling convention attributes ('void () __attribute__((cdecl))') than the function it overrides (which has calling convention 'void () __attribute__((thiscall))'}}
+ };
+
+ class C : public A {
+ public:
+ void __attribute__((thiscall)) f(); // This override is correct
+ };
+
+ class D : public A {
+ public:
+ void f(); // This override is correct because thiscall is the default calling convention for class members
+ };
+
+ class E {
+ public:
+ virtual void __attribute__((stdcall)) g(); // expected-note{{overridden virtual function is here}}
+ };
+
+ class F : public E {
+ public:
+ void g(); // expected-error{{virtual function 'g' has different calling convention attributes ('void ()') than the function it overrides (which has calling convention 'void () __attribute__((stdcall))'}}
+ };
+}
diff --git a/test/SemaCXX/visibility.cpp b/test/SemaCXX/visibility.cpp
new file mode 100644
index 0000000..434b3c0
--- /dev/null
+++ b/test/SemaCXX/visibility.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only %s
+
+namespace test1 {
+ template <class C>
+ struct C2
+ {
+ static int p __attribute__((visibility("hidden")));
+ };
+ int f() {
+ return C2<int>::p;
+ }
+}
diff --git a/test/SemaCXX/warn-bad-memaccess.cpp b/test/SemaCXX/warn-bad-memaccess.cpp
index 3a02c84..7a7459a 100644
--- a/test/SemaCXX/warn-bad-memaccess.cpp
+++ b/test/SemaCXX/warn-bad-memaccess.cpp
@@ -5,6 +5,11 @@ extern "C" void *memmove(void *s1, const void *s2, unsigned n);
extern "C" void *memcpy(void *s1, const void *s2, unsigned n);
extern "C" void *memcmp(void *s1, const void *s2, unsigned n);
+
+// Redeclare without the extern "C" to test that we still figure out that this
+// is the "real" memset.
+void *memset(void *, int, unsigned);
+
// Several types that should not warn.
struct S1 {} s1;
struct S2 { int x; } s2;
diff --git a/test/SemaCXX/warn-enum-compare.cpp b/test/SemaCXX/warn-enum-compare.cpp
index c68275e..0c28794 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); // 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 (x == AnonAA); // expected-warning {{comparison of constant 'AnonAA' (42) with expression of type 'Foo' is always false}}
+ while (AnonBB == y); // expected-warning {{comparison of constant 'AnonBB' (45) with expression of type 'Bar' is always false}}
while (AnonAA == AnonAB);
while (AnonAB == AnonBA);
while (AnonBB == AnonAA);
diff --git a/test/SemaCXX/warn-func-not-needed.cpp b/test/SemaCXX/warn-func-not-needed.cpp
new file mode 100644
index 0000000..d51c173
--- /dev/null
+++ b/test/SemaCXX/warn-func-not-needed.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wall %s
+
+namespace test1 {
+ static void f() {} // expected-warning {{is not needed and will not be emitted}}
+ static void f();
+ template <typename T>
+ void foo() {
+ f();
+ }
+}
+
+namespace test2 {
+ static void f() {}
+ static void f();
+ static void g() { f(); }
+ void h() { g(); }
+}
+
+namespace test3 {
+ static void f();
+ template<typename T>
+ static void g() {
+ f();
+ }
+ static void f() {
+ }
+ void h() {
+ g<int>();
+ }
+}
+
+namespace test4 {
+ static void f();
+ static void f();
+ template<typename T>
+ static void g() {
+ f();
+ }
+ static void f() {
+ }
+ void h() {
+ g<int>();
+ }
+}
diff --git a/test/SemaCXX/warn-reinterpret-base-class.cpp b/test/SemaCXX/warn-reinterpret-base-class.cpp
new file mode 100644
index 0000000..67902f7
--- /dev/null
+++ b/test/SemaCXX/warn-reinterpret-base-class.cpp
@@ -0,0 +1,323 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -Wreinterpret-base-class -Wno-unused-volatile-lvalue %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fdiagnostics-parseable-fixits -Wreinterpret-base-class -Wno-unused-volatile-lvalue %s 2>&1 | FileCheck %s
+
+// PR 13824
+class A {
+};
+class DA : public A {
+};
+class DDA : public DA {
+};
+class DAo : protected A {
+};
+class DAi : private A {
+};
+
+class DVA : public virtual A {
+};
+class DDVA : public virtual DA {
+};
+class DMA : public virtual A, public virtual DA {
+};
+
+class B;
+
+struct C {
+ // Do not fail on incompletely-defined classes.
+ decltype(reinterpret_cast<C *>(0)) foo;
+ decltype(reinterpret_cast<A *>((C *) 0)) bar;
+ decltype(reinterpret_cast<C *>((A *) 0)) baz;
+};
+
+void reinterpret_not_defined_class(B *b, C *c) {
+ // Should not fail if class has no definition.
+ (void)*reinterpret_cast<C *>(b);
+ (void)*reinterpret_cast<B *>(c);
+
+ (void)reinterpret_cast<C &>(*b);
+ (void)reinterpret_cast<B &>(*c);
+}
+
+// Do not fail on erroneous classes with fields of incompletely-defined types.
+// Base class is malformed.
+namespace BaseMalformed {
+ struct A; // expected-note {{forward declaration of 'BaseMalformed::A'}}
+ struct B {
+ A a; // expected-error {{field has incomplete type 'BaseMalformed::A'}}
+ };
+ struct C : public B {} c;
+ B *b = reinterpret_cast<B *>(&c);
+} // end anonymous namespace
+
+// Child class is malformed.
+namespace ChildMalformed {
+ struct A; // expected-note {{forward declaration of 'ChildMalformed::A'}}
+ struct B {};
+ struct C : public B {
+ A a; // expected-error {{field has incomplete type 'ChildMalformed::A'}}
+ } c;
+ B *b = reinterpret_cast<B *>(&c);
+} // end anonymous namespace
+
+// Base class outside upcast base-chain is malformed.
+namespace BaseBaseMalformed {
+ struct A; // expected-note {{forward declaration of 'BaseBaseMalformed::A'}}
+ struct Y {};
+ struct X { A a; }; // expected-error {{field has incomplete type 'BaseBaseMalformed::A'}}
+ struct B : Y, X {};
+ struct C : B {} c;
+ B *p = reinterpret_cast<B*>(&c);
+}
+
+namespace InheritanceMalformed {
+ struct A; // expected-note {{forward declaration of 'InheritanceMalformed::A'}}
+ struct B : A {}; // expected-error {{base class has incomplete type}}
+ struct C : B {} c;
+ B *p = reinterpret_cast<B*>(&c);
+}
+
+// Virtual base class outside upcast base-chain is malformed.
+namespace VBaseMalformed{
+ struct A; // expected-note {{forward declaration of 'VBaseMalformed::A'}}
+ struct X { A a; }; // expected-error {{field has incomplete type 'VBaseMalformed::A'}}
+ struct B : public virtual X {};
+ struct C : B {} c;
+ B *p = reinterpret_cast<B*>(&c);
+}
+
+void reinterpret_not_updowncast(A *pa, const A *pca, A &a, const A &ca) {
+ (void)*reinterpret_cast<C *>(pa);
+ (void)*reinterpret_cast<const C *>(pa);
+ (void)*reinterpret_cast<volatile C *>(pa);
+ (void)*reinterpret_cast<const volatile C *>(pa);
+
+ (void)*reinterpret_cast<const C *>(pca);
+ (void)*reinterpret_cast<const volatile C *>(pca);
+
+ (void)reinterpret_cast<C &>(a);
+ (void)reinterpret_cast<const C &>(a);
+ (void)reinterpret_cast<volatile C &>(a);
+ (void)reinterpret_cast<const volatile C &>(a);
+
+ (void)reinterpret_cast<const C &>(ca);
+ (void)reinterpret_cast<const volatile C &>(ca);
+}
+
+void reinterpret_pointer_downcast(A *a, const A *ca) {
+ (void)*reinterpret_cast<DA *>(a);
+ (void)*reinterpret_cast<const DA *>(a);
+ (void)*reinterpret_cast<volatile DA *>(a);
+ (void)*reinterpret_cast<const volatile DA *>(a);
+
+ (void)*reinterpret_cast<const DA *>(ca);
+ (void)*reinterpret_cast<const volatile DA *>(ca);
+
+ (void)*reinterpret_cast<DDA *>(a);
+ (void)*reinterpret_cast<DAo *>(a);
+ (void)*reinterpret_cast<DAi *>(a);
+ // expected-warning@+2 {{'reinterpret_cast' to class 'DVA *' from its virtual base 'A *' behaves differently from 'static_cast'}}
+ // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+ (void)*reinterpret_cast<DVA *>(a);
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:10-[[@LINE-1]]:26}:"static_cast"
+
+ // expected-warning@+2 {{'reinterpret_cast' to class 'DDVA *' from its virtual base 'A *' behaves differently from 'static_cast'}}
+ // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+ (void)*reinterpret_cast<DDVA *>(a);
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:10-[[@LINE-1]]:26}:"static_cast"
+
+ // expected-warning@+2 {{'reinterpret_cast' to class 'DMA *' from its virtual base 'A *' behaves differently from 'static_cast'}}
+ // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+ (void)*reinterpret_cast<DMA *>(a);
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:10-[[@LINE-1]]:26}:"static_cast"
+}
+
+void reinterpret_reference_downcast(A a, A &ra, const A &cra) {
+ (void)reinterpret_cast<DA &>(a);
+ (void)reinterpret_cast<const DA &>(a);
+ (void)reinterpret_cast<volatile DA &>(a);
+ (void)reinterpret_cast<const volatile DA &>(a);
+
+ (void)reinterpret_cast<DA &>(ra);
+ (void)reinterpret_cast<const DA &>(ra);
+ (void)reinterpret_cast<volatile DA &>(ra);
+ (void)reinterpret_cast<const volatile DA &>(ra);
+
+ (void)reinterpret_cast<const DA &>(cra);
+ (void)reinterpret_cast<const volatile DA &>(cra);
+
+ (void)reinterpret_cast<DDA &>(a);
+ (void)reinterpret_cast<DAo &>(a);
+ (void)reinterpret_cast<DAi &>(a);
+ // expected-warning@+2 {{'reinterpret_cast' to class 'DVA &' from its virtual base 'A' behaves differently from 'static_cast'}}
+ // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+ (void)reinterpret_cast<DVA &>(a);
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:25}:"static_cast"
+
+ // expected-warning@+2 {{'reinterpret_cast' to class 'DDVA &' from its virtual base 'A' behaves differently from 'static_cast'}}
+ // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+ (void)reinterpret_cast<DDVA &>(a);
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:25}:"static_cast"
+
+ // expected-warning@+2 {{'reinterpret_cast' to class 'DMA &' from its virtual base 'A' behaves differently from 'static_cast'}}
+ // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+ (void)reinterpret_cast<DMA &>(a);
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:25}:"static_cast"
+}
+
+void reinterpret_pointer_upcast(DA *da, const DA *cda, DDA *dda, DAo *dao,
+ DAi *dai, DVA *dva, DDVA *ddva, DMA *dma) {
+ (void)*reinterpret_cast<A *>(da);
+ (void)*reinterpret_cast<const A *>(da);
+ (void)*reinterpret_cast<volatile A *>(da);
+ (void)*reinterpret_cast<const volatile A *>(da);
+
+ (void)*reinterpret_cast<const A *>(cda);
+ (void)*reinterpret_cast<const volatile A *>(cda);
+
+ (void)*reinterpret_cast<A *>(dda);
+ (void)*reinterpret_cast<DA *>(dda);
+ (void)*reinterpret_cast<A *>(dao);
+ (void)*reinterpret_cast<A *>(dai);
+ // expected-warning@+2 {{'reinterpret_cast' from class 'DVA *' to its virtual base 'A *' behaves differently from 'static_cast'}}
+ // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+ (void)*reinterpret_cast<A *>(dva);
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:10-[[@LINE-1]]:26}:"static_cast"
+
+ // expected-warning@+2 {{'reinterpret_cast' from class 'DDVA *' to its virtual base 'A *' behaves differently from 'static_cast'}}
+ // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+ (void)*reinterpret_cast<A *>(ddva);
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:10-[[@LINE-1]]:26}:"static_cast"
+
+ // expected-warning@+2 {{'reinterpret_cast' from class 'DDVA *' to its virtual base 'DA *' behaves differently from 'static_cast'}}
+ // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+ (void)*reinterpret_cast<DA *>(ddva);
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:10-[[@LINE-1]]:26}:"static_cast"
+
+ // expected-warning@+2 {{'reinterpret_cast' from class 'DMA *' to its virtual base 'A *' behaves differently from 'static_cast'}}
+ // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+ (void)*reinterpret_cast<A *>(dma);
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:10-[[@LINE-1]]:26}:"static_cast"
+
+ // expected-warning@+2 {{'reinterpret_cast' from class 'DMA *' to its virtual base 'DA *' behaves differently from 'static_cast'}}
+ // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+ (void)*reinterpret_cast<DA *>(dma);
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:10-[[@LINE-1]]:26}:"static_cast"
+}
+
+void reinterpret_reference_upcast(DA &da, const DA &cda, DDA &dda, DAo &dao,
+ DAi &dai, DVA &dva, DDVA &ddva, DMA &dma) {
+ (void)reinterpret_cast<A &>(da);
+ (void)reinterpret_cast<const A &>(da);
+ (void)reinterpret_cast<volatile A &>(da);
+ (void)reinterpret_cast<const volatile A &>(da);
+
+ (void)reinterpret_cast<const A &>(cda);
+ (void)reinterpret_cast<const volatile A &>(cda);
+
+ (void)reinterpret_cast<A &>(dda);
+ (void)reinterpret_cast<DA &>(dda);
+ (void)reinterpret_cast<A &>(dao);
+ (void)reinterpret_cast<A &>(dai);
+ // expected-warning@+2 {{'reinterpret_cast' from class 'DVA' to its virtual base 'A &' behaves differently from 'static_cast'}}
+ // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+ (void)reinterpret_cast<A &>(dva);
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:25}:"static_cast"
+
+ // expected-warning@+2 {{'reinterpret_cast' from class 'DDVA' to its virtual base 'A &' behaves differently from 'static_cast'}}
+ // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+ (void)reinterpret_cast<A &>(ddva);
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:25}:"static_cast"
+
+ // expected-warning@+2 {{'reinterpret_cast' from class 'DDVA' to its virtual base 'DA &' behaves differently from 'static_cast'}}
+ // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+ (void)reinterpret_cast<DA &>(ddva);
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:25}:"static_cast"
+
+ // expected-warning@+2 {{'reinterpret_cast' from class 'DMA' to its virtual base 'A &' behaves differently from 'static_cast'}}
+ // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+ (void)reinterpret_cast<A &>(dma);
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:25}:"static_cast"
+
+ // expected-warning@+2 {{'reinterpret_cast' from class 'DMA' to its virtual base 'DA &' behaves differently from 'static_cast'}}
+ // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+ (void)reinterpret_cast<DA &>(dma);
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:25}:"static_cast"
+}
+
+struct E {
+ int x;
+};
+
+class F : public E {
+ virtual int foo() { return x; }
+};
+
+class G : public F {
+};
+
+class H : public E, public A {
+};
+
+class I : virtual public F {
+};
+
+typedef const F * K;
+typedef volatile K L;
+
+void different_subobject_downcast(E *e, F *f, A *a) {
+ // expected-warning@+2 {{'reinterpret_cast' to class 'F *' from its base at non-zero offset 'E *' behaves differently from 'static_cast'}}
+ // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+ (void)reinterpret_cast<F *>(e);
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:25}:"static_cast"
+
+ // expected-warning@+2 {{'reinterpret_cast' to class 'G *' from its base at non-zero offset 'E *' behaves differently from 'static_cast'}}
+ // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+ (void)reinterpret_cast<G *>(e);
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:25}:"static_cast"
+
+ (void)reinterpret_cast<H *>(e);
+ // expected-warning@+2 {{'reinterpret_cast' to class 'I *' from its virtual base 'E *' behaves differently from 'static_cast'}}
+ // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+ (void)reinterpret_cast<I *>(e);
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:25}:"static_cast"
+
+
+ (void)reinterpret_cast<G *>(f);
+ // expected-warning@+2 {{'reinterpret_cast' to class 'I *' from its virtual base 'F *' behaves differently from 'static_cast'}}
+ // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+ (void)reinterpret_cast<I *>(f);
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:25}:"static_cast"
+
+ (void)reinterpret_cast<H *>(a);
+
+ // expected-warning@+2 {{'reinterpret_cast' to class 'L' (aka 'const F *volatile') from its base at non-zero offset 'E *' behaves differently from 'static_cast'}}
+ // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while downcasting}}
+ (void)reinterpret_cast<L>(e);
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:25}:"static_cast"
+}
+
+void different_subobject_upcast(F *f, G *g, H *h, I *i) {
+ // expected-warning@+2 {{'reinterpret_cast' from class 'F *' to its base at non-zero offset 'E *' behaves differently from 'static_cast'}}
+ // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+ (void)reinterpret_cast<E *>(f);
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:25}:"static_cast"
+
+ (void)reinterpret_cast<F *>(g);
+ // expected-warning@+2 {{'reinterpret_cast' from class 'G *' to its base at non-zero offset 'E *' behaves differently from 'static_cast'}}
+ // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+ (void)reinterpret_cast<E *>(g);
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:25}:"static_cast"
+
+ (void)reinterpret_cast<E *>(h);
+ (void)reinterpret_cast<A *>(h);
+
+ // expected-warning@+2 {{'reinterpret_cast' from class 'I *' to its virtual base 'F *' behaves differently from 'static_cast'}}
+ // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+ (void)reinterpret_cast<F *>(i);
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:25}:"static_cast"
+
+ // expected-warning@+2 {{'reinterpret_cast' from class 'I *' to its virtual base 'E *' behaves differently from 'static_cast'}}
+ // expected-note@+1 {{use 'static_cast' to adjust the pointer correctly while upcasting}}
+ (void)reinterpret_cast<E *>(i);
+ // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:9-[[@LINE-1]]:25}:"static_cast"
+}
diff --git a/test/SemaCXX/warn-reorder-ctor-initialization.cpp b/test/SemaCXX/warn-reorder-ctor-initialization.cpp
index 8c254e5..6d38ec9 100644
--- a/test/SemaCXX/warn-reorder-ctor-initialization.cpp
+++ b/test/SemaCXX/warn-reorder-ctor-initialization.cpp
@@ -130,3 +130,14 @@ namespace PR7179 {
};
};
}
+
+namespace test3 {
+ struct foo {
+ struct {
+ int a;
+ int b;
+ };
+ foo() : b(), a() { // expected-warning {{field 'b' will be initialized after field 'a'}}
+ }
+ };
+}
diff --git a/test/SemaCXX/warn-static-const-float.cpp b/test/SemaCXX/warn-static-const-float.cpp
new file mode 100644
index 0000000..481a410
--- /dev/null
+++ b/test/SemaCXX/warn-static-const-float.cpp
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -verify %s -std=c++98 -DEXT
+// RUN: %clang_cc1 -verify %s -std=c++98 -Wno-gnu -DNONE
+// RUN: %clang_cc1 -verify %s -std=c++98 -Wno-static-float-init -DNONE
+// RUN: %clang_cc1 -verify %s -std=c++98 -Wno-gnu-static-float-init -DNONE
+// RUN: %clang_cc1 -verify %s -std=c++11 -DERR
+// RUN: %clang_cc1 -verify %s -std=c++11 -Wno-gnu -DERR
+// RUN: %clang_cc1 -verify %s -std=c++11 -Wno-static-float-init -DNONE
+// RUN: %clang_cc1 -verify %s -std=c++11 -Wno-gnu-static-float-init -DERR
+
+#if NONE
+// expected-no-diagnostics
+#elif ERR
+// expected-error@20 {{in-class initializer for static data member of type 'const double' requires 'constexpr' specifier}}
+// expected-note@20 {{add 'constexpr'}}
+#elif EXT
+// expected-warning@20 {{in-class initializer for static data member of type 'const double' is a GNU extension}}
+#endif
+
+struct X {
+ static const double x = 0.0;
+};
diff --git a/test/SemaCXX/warn-thread-safety-analysis.cpp b/test/SemaCXX/warn-thread-safety-analysis.cpp
index bd555ac..3f41124 100644
--- a/test/SemaCXX/warn-thread-safety-analysis.cpp
+++ b/test/SemaCXX/warn-thread-safety-analysis.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wthread-safety -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wthread-safety -Wthread-safety-beta -fcxx-exceptions %s
// FIXME: should also run %clang_cc1 -fsyntax-only -verify -Wthread-safety -std=c++11 -Wc++98-compat %s
// FIXME: should also run %clang_cc1 -fsyntax-only -verify -Wthread-safety %s
@@ -3712,3 +3712,206 @@ void Foo::test() {
} // end namespace MultipleAttributeTest
+namespace GuardedNonPrimitiveTypeTest {
+
+
+class Data {
+public:
+ Data(int i) : dat(i) { }
+
+ int getValue() const { return dat; }
+ void setValue(int i) { dat = i; }
+
+ int operator[](int i) const { return dat; }
+ int& operator[](int i) { return dat; }
+
+ void operator()() { }
+
+private:
+ int dat;
+};
+
+
+class DataCell {
+public:
+ DataCell(const Data& d) : dat(d) { }
+
+private:
+ Data dat;
+};
+
+
+void showDataCell(const DataCell& dc);
+
+
+class Foo {
+public:
+ // method call tests
+ void test() {
+ data_.setValue(0); // FIXME -- should be writing \
+ // expected-warning {{reading variable 'data_' requires locking 'mu_'}}
+ int a = data_.getValue(); // \
+ // expected-warning {{reading variable 'data_' requires locking 'mu_'}}
+
+ datap1_->setValue(0); // FIXME -- should be writing \
+ // expected-warning {{reading variable 'datap1_' requires locking 'mu_'}}
+ a = datap1_->getValue(); // \
+ // expected-warning {{reading variable 'datap1_' requires locking 'mu_'}}
+
+ datap2_->setValue(0); // FIXME -- should be writing \
+ // expected-warning {{reading the value pointed to by 'datap2_' requires locking 'mu_'}}
+ a = datap2_->getValue(); // \
+ // expected-warning {{reading the value pointed to by 'datap2_' requires locking 'mu_'}}
+
+ (*datap2_).setValue(0); // FIXME -- should be writing \
+ // expected-warning {{reading the value pointed to by 'datap2_' requires locking 'mu_'}}
+ a = (*datap2_).getValue(); // \
+ // expected-warning {{reading the value pointed to by 'datap2_' requires locking 'mu_'}}
+
+ mu_.Lock();
+ data_.setValue(1);
+ datap1_->setValue(1);
+ datap2_->setValue(1);
+ mu_.Unlock();
+
+ mu_.ReaderLock();
+ a = data_.getValue();
+ datap1_->setValue(0); // reads datap1_, writes *datap1_
+ a = datap1_->getValue();
+ a = datap2_->getValue();
+ mu_.Unlock();
+ }
+
+ // operator tests
+ void test2() {
+ data_ = Data(1); // expected-warning {{writing variable 'data_' requires locking 'mu_' exclusively}}
+ *datap1_ = data_; // expected-warning {{reading variable 'datap1_' requires locking 'mu_'}} \
+ // expected-warning {{reading variable 'data_' requires locking 'mu_'}}
+ *datap2_ = data_; // expected-warning {{writing the value pointed to by 'datap2_' requires locking 'mu_' exclusively}} \
+ // expected-warning {{reading variable 'data_' requires locking 'mu_'}}
+ data_ = *datap1_; // expected-warning {{writing variable 'data_' requires locking 'mu_' exclusively}} \
+ // expected-warning {{reading variable 'datap1_' requires locking 'mu_'}}
+ data_ = *datap2_; // expected-warning {{writing variable 'data_' requires locking 'mu_' exclusively}} \
+ // expected-warning {{reading the value pointed to by 'datap2_' requires locking 'mu_'}}
+
+ data_[0] = 0; // expected-warning {{reading variable 'data_' requires locking 'mu_'}}
+ (*datap2_)[0] = 0; // expected-warning {{reading the value pointed to by 'datap2_' requires locking 'mu_'}}
+
+ data_(); // expected-warning {{reading variable 'data_' requires locking 'mu_'}}
+ }
+
+ // const operator tests
+ void test3() const {
+ Data mydat(data_); // expected-warning {{reading variable 'data_' requires locking 'mu_'}}
+
+ //FIXME
+ //showDataCell(data_); // xpected-warning {{reading variable 'data_' requires locking 'mu_'}}
+ //showDataCell(*datap2_); // xpected-warning {{reading the value pointed to by 'datap2_' requires locking 'mu_'}}
+
+ int a = data_[0]; // expected-warning {{reading variable 'data_' requires locking 'mu_'}}
+ }
+
+private:
+ Mutex mu_;
+ Data data_ GUARDED_BY(mu_);
+ Data* datap1_ GUARDED_BY(mu_);
+ Data* datap2_ PT_GUARDED_BY(mu_);
+};
+
+} // end namespace GuardedNonPrimitiveTypeTest
+
+
+namespace GuardedNonPrimitive_MemberAccess {
+
+class Cell {
+public:
+ Cell(int i);
+
+ void cellMethod();
+
+ int a;
+};
+
+
+class Foo {
+public:
+ int a;
+ Cell c GUARDED_BY(cell_mu_);
+ Cell* cp PT_GUARDED_BY(cell_mu_);
+
+ void myMethod();
+
+ Mutex cell_mu_;
+};
+
+
+class Bar {
+private:
+ Mutex mu_;
+ Foo foo GUARDED_BY(mu_);
+ Foo* foop PT_GUARDED_BY(mu_);
+
+ void test() {
+ foo.myMethod(); // expected-warning {{reading variable 'foo' requires locking 'mu_'}}
+
+ int fa = foo.a; // expected-warning {{reading variable 'foo' requires locking 'mu_'}}
+ foo.a = fa; // expected-warning {{writing variable 'foo' requires locking 'mu_' exclusively}}
+
+ fa = foop->a; // expected-warning {{reading the value pointed to by 'foop' requires locking 'mu_'}}
+ foop->a = fa; // expected-warning {{writing the value pointed to by 'foop' requires locking 'mu_' exclusively}}
+
+ fa = (*foop).a; // expected-warning {{reading the value pointed to by 'foop' requires locking 'mu_'}}
+ (*foop).a = fa; // expected-warning {{writing the value pointed to by 'foop' requires locking 'mu_' exclusively}}
+
+ foo.c = Cell(0); // expected-warning {{writing variable 'foo' requires locking 'mu_'}} \
+ // expected-warning {{writing variable 'c' requires locking 'foo.cell_mu_' exclusively}}
+ foo.c.cellMethod(); // expected-warning {{reading variable 'foo' requires locking 'mu_'}} \
+ // expected-warning {{reading variable 'c' requires locking 'foo.cell_mu_'}}
+
+ foop->c = Cell(0); // expected-warning {{writing the value pointed to by 'foop' requires locking 'mu_'}} \
+ // expected-warning {{writing variable 'c' requires locking 'foop->cell_mu_' exclusively}}
+ foop->c.cellMethod(); // expected-warning {{reading the value pointed to by 'foop' requires locking 'mu_'}} \
+ // expected-warning {{reading variable 'c' requires locking 'foop->cell_mu_'}}
+
+ (*foop).c = Cell(0); // expected-warning {{writing the value pointed to by 'foop' requires locking 'mu_'}} \
+ // expected-warning {{writing variable 'c' requires locking 'foop->cell_mu_' exclusively}}
+ (*foop).c.cellMethod(); // expected-warning {{reading the value pointed to by 'foop' requires locking 'mu_'}} \
+ // expected-warning {{reading variable 'c' requires locking 'foop->cell_mu_'}}
+ };
+};
+
+} // namespace GuardedNonPrimitive_MemberAccess
+
+
+namespace TestThrowExpr {
+
+class Foo {
+ Mutex mu_;
+
+ bool hasError();
+
+ void test() {
+ mu_.Lock();
+ if (hasError()) {
+ throw "ugly";
+ }
+ mu_.Unlock();
+ }
+};
+
+} // end namespace TestThrowExpr
+
+
+namespace UnevaluatedContextTest {
+
+// parse attribute expressions in an unevaluated context.
+
+static inline Mutex* getMutex1();
+static inline Mutex* getMutex2();
+
+void bar() EXCLUSIVE_LOCKS_REQUIRED(getMutex1());
+
+void bar2() EXCLUSIVE_LOCKS_REQUIRED(getMutex1(), getMutex2());
+
+} // end namespace UnevaluatedContextTest
+
diff --git a/test/SemaCXX/warn-unsequenced.cpp b/test/SemaCXX/warn-unsequenced.cpp
new file mode 100644
index 0000000..c7acfca
--- /dev/null
+++ b/test/SemaCXX/warn-unsequenced.cpp
@@ -0,0 +1,103 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -Wno-unused %s
+
+int f(int, int);
+
+struct A {
+ int x, y;
+};
+struct S {
+ S(int, int);
+};
+
+void test() {
+ int a;
+ int xs[10];
+ ++a = 0; // ok
+ a + ++a; // expected-warning {{unsequenced modification and access to 'a'}}
+ a = ++a; // ok
+ a + a++; // expected-warning {{unsequenced modification and access to 'a'}}
+ a = a++; // expected-warning {{multiple unsequenced modifications to 'a'}}
+ ++ ++a; // ok
+ (a++, a++); // ok
+ ++a + ++a; // expected-warning {{multiple unsequenced modifications to 'a'}}
+ a++ + a++; // expected-warning {{multiple unsequenced modifications}}
+ (a++, a) = 0; // ok, increment is sequenced before value computation of LHS
+ a = xs[++a]; // ok
+ a = xs[a++]; // expected-warning {{multiple unsequenced modifications}}
+ (a ? xs[0] : xs[1]) = ++a; // expected-warning {{unsequenced modification and access}}
+ a = (++a, ++a); // ok
+ a = (a++, ++a); // ok
+ a = (a++, a++); // expected-warning {{multiple unsequenced modifications}}
+ f(a, a); // ok
+ f(a = 0, a); // expected-warning {{unsequenced modification and access}}
+ f(a, a += 0); // expected-warning {{unsequenced modification and access}}
+ f(a = 0, a = 0); // expected-warning {{multiple unsequenced modifications}}
+
+ // Compound assignment "A OP= B" is equivalent to "A = A OP B" except that A
+ // is evaluated only once.
+ (++a, a) = 1; // ok
+ (++a, a) += 1; // ok
+ a = ++a; // ok
+ a += ++a; // expected-warning {{unsequenced modification and access}}
+
+ A agg1 = { a++, a++ }; // ok
+ A agg2 = { a++ + a, a++ }; // expected-warning {{unsequenced modification and access}}
+
+ S str1(a++, a++); // expected-warning {{multiple unsequenced modifications}}
+ S str2 = { a++, a++ }; // ok
+ S str3 = { a++ + a, a++ }; // expected-warning {{unsequenced modification and access}}
+
+ (xs[2] && (a = 0)) + a; // ok
+ (0 && (a = 0)) + a; // ok
+ (1 && (a = 0)) + a; // expected-warning {{unsequenced modification and access}}
+
+ (xs[3] || (a = 0)) + a; // ok
+ (0 || (a = 0)) + a; // expected-warning {{unsequenced modification and access}}
+ (1 || (a = 0)) + a; // ok
+
+ (xs[4] ? a : ++a) + a; // ok
+ (0 ? a : ++a) + a; // expected-warning {{unsequenced modification and access}}
+ (1 ? a : ++a) + a; // ok
+ (xs[5] ? ++a : ++a) + a; // FIXME: warn here
+
+ (++a, xs[6] ? ++a : 0) + a; // expected-warning {{unsequenced modification and access}}
+
+ // Here, the read of the fourth 'a' might happen before or after the write to
+ // the second 'a'.
+ a += (a++, a) + a; // expected-warning {{unsequenced modification and access}}
+
+ int *p = xs;
+ a = *(a++, p); // ok
+ a = a++ && a; // ok
+
+ A *q = &agg1;
+ (q = &agg2)->y = q->x; // expected-warning {{unsequenced modification and access to 'q'}}
+
+ // This has undefined behavior if a == 0; otherwise, the side-effect of the
+ // increment is sequenced before the value computation of 'f(a, a)', which is
+ // sequenced before the value computation of the '&&', which is sequenced
+ // before the assignment. We treat the sequencing in '&&' as being
+ // unconditional.
+ a = a++ && f(a, a);
+
+ // This has undefined behavior if a != 0. FIXME: We should diagnose this.
+ (a && a++) + a;
+
+ (xs[7] && ++a) * (!xs[7] && ++a); // ok
+
+ xs[0] = (a = 1, a); // ok
+ (a -= 128) &= 128; // ok
+ ++a += 1; // ok
+
+ xs[8] ? ++a + a++ : 0; // expected-warning {{multiple unsequenced modifications}}
+ xs[8] ? 0 : ++a + a++; // expected-warning {{multiple unsequenced modifications}}
+ xs[8] ? ++a : a++; // ok
+
+ xs[8] && (++a + a++); // expected-warning {{multiple unsequenced modifications}}
+ xs[8] || (++a + a++); // expected-warning {{multiple unsequenced modifications}}
+
+ (__builtin_classify_type(++a) ? 1 : 0) + ++a; // ok
+ (__builtin_constant_p(++a) ? 1 : 0) + ++a; // ok
+ (__builtin_object_size(&(++a, a), 0) ? 1 : 0) + ++a; // ok
+ (__builtin_expect(++a, 0) ? 1 : 0) + ++a; // expected-warning {{multiple unsequenced modifications}}
+}
diff --git a/test/SemaCXX/warn-unused-filescoped.cpp b/test/SemaCXX/warn-unused-filescoped.cpp
index ad896b5..e12668b 100644
--- a/test/SemaCXX/warn-unused-filescoped.cpp
+++ b/test/SemaCXX/warn-unused-filescoped.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wunused -Wunused-member-function -std=c++98 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wunused -Wunused-member-function -Wno-c++11-extensions -std=c++98 %s
// RUN: %clang_cc1 -fsyntax-only -verify -Wunused -Wunused-member-function -std=c++11 %s
static void f1(); // expected-warning{{unused}}
@@ -101,3 +101,42 @@ namespace test5 {
static const double d = 0.0;
int y = sizeof(d);
}
+
+namespace unused_nested {
+ class outer {
+ void func1();
+ struct {
+ void func2() {
+ }
+ } x;
+ };
+}
+
+namespace unused {
+ struct {
+ void func() { // expected-warning {{unused member function}}
+ }
+ } x; // expected-warning {{unused variable}}
+}
+
+namespace test6 {
+ typedef struct {
+ void bar();
+ } A;
+
+ typedef struct {
+ void bar(); // expected-warning {{unused member function 'bar'}}
+ } *B;
+
+ struct C {
+ void bar();
+ };
+}
+
+namespace pr14776 {
+ namespace {
+ struct X {};
+ }
+ X a = X(); // expected-warning {{unused variable 'a'}}
+ auto b = X(); // expected-warning {{unused variable 'b'}}
+}
diff --git a/test/SemaCXX/warn-unused-result.cpp b/test/SemaCXX/warn-unused-result.cpp
index d14fdf9..b0bf61f 100644
--- a/test/SemaCXX/warn-unused-result.cpp
+++ b/test/SemaCXX/warn-unused-result.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
int f() __attribute__((warn_unused_result));
@@ -42,3 +42,39 @@ void bah() {
x.foo(); // expected-warning {{ignoring return value}}
x2->foo(); // expected-warning {{ignoring return value}}
}
+
+namespace warn_unused_CXX11 {
+struct [[clang::warn_unused_result]] Status {
+ bool ok() const;
+ Status& operator=(const Status& x);
+ inline void Update(const Status& new_status) {
+ if (ok()) {
+ *this = new_status; //no-warning
+ }
+ }
+};
+Status DoSomething();
+Status& DoSomethingElse();
+Status* DoAnotherThing();
+Status** DoYetAnotherThing();
+void lazy() {
+ Status s = DoSomething();
+ if (!s.ok()) return;
+ Status &rs = DoSomethingElse();
+ if (!rs.ok()) return;
+ Status *ps = DoAnotherThing();
+ if (!ps->ok()) return;
+ Status **pps = DoYetAnotherThing();
+ if (!(*pps)->ok()) return;
+
+ (void)DoSomething();
+ (void)DoSomethingElse();
+ (void)DoAnotherThing();
+ (void)DoYetAnotherThing();
+
+ DoSomething(); // expected-warning {{ignoring return value}}
+ DoSomethingElse(); // expected-warning {{ignoring return value}}
+ DoAnotherThing(); // expected-warning {{ignoring return value}}
+ DoYetAnotherThing();
+}
+}
diff --git a/test/SemaCXX/warn-variable-not-needed.cpp b/test/SemaCXX/warn-variable-not-needed.cpp
new file mode 100644
index 0000000..0fb0f81
--- /dev/null
+++ b/test/SemaCXX/warn-variable-not-needed.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wall %s
+
+namespace test1 {
+ static int abc = 42; // expected-warning {{variable 'abc' is not needed and will not be emitted}}
+ template <typename T>
+ int foo(void) {
+ return abc;
+ }
+}
+
+namespace test2 {
+ struct bah {
+ };
+ namespace {
+ struct foo : bah {
+ static char bar;
+ virtual void zed();
+ };
+ void foo::zed() {
+ bar++;
+ }
+ char foo::bar=0;
+ }
+ bah *getfoo() {
+ return new foo();
+ }
+}
diff --git a/test/SemaCXX/warn-vla.cpp b/test/SemaCXX/warn-vla.cpp
new file mode 100644
index 0000000..081f1c7
--- /dev/null
+++ b/test/SemaCXX/warn-vla.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wvla %s
+
+void test1(int n) {
+ int v[n]; // expected-warning {{variable length array used}}
+}
+
+void test2(int n, int v[n]) { // expected-warning {{variable length array used}}
+}
+
+void test3(int n, int v[n]); // expected-warning {{variable length array used}}
+
+template<typename T>
+void test4(int n) {
+ int v[n]; // expected-warning {{variable length array used}}
+}
+
+template<typename T>
+void test5(int n, int v[n]) { // expected-warning {{variable length array used}}
+}
+
+template<typename T>
+void test6(int n, int v[n]); // expected-warning {{variable length array used}}
+
+template<typename T>
+void test7(int n, T v[n]) { // expected-warning {{variable length array used}}
+}
+
diff --git a/test/SemaObjC/arc-decls.m b/test/SemaObjC/arc-decls.m
index a53b52a..cdf6cc6 100644
--- a/test/SemaObjC/arc-decls.m
+++ b/test/SemaObjC/arc-decls.m
@@ -3,17 +3,17 @@
// rdar://8843524
struct A {
- id x; // expected-error {{ARC forbids Objective-C objects in structs or unions}}
+ id x; // expected-error {{ARC forbids Objective-C objects in struct}}
};
union u {
- id u; // expected-error {{ARC forbids Objective-C objects in structs or unions}}
+ id u; // expected-error {{ARC forbids Objective-C objects in union}}
};
@interface I {
struct A a;
struct B {
- id y[10][20]; // expected-error {{ARC forbids Objective-C objects in structs or unions}}
+ id y[10][20]; // expected-error {{ARC forbids Objective-C objects in struct}}
id z;
} b;
@@ -23,7 +23,7 @@ union u {
// rdar://10260525
struct r10260525 {
- id (^block) (); // expected-error {{ARC forbids blocks in structs or unions}}
+ id (^block) (); // expected-error {{ARC forbids blocks in struct}}
};
struct S {
diff --git a/test/SemaObjC/arc-objc-lifetime.m b/test/SemaObjC/arc-objc-lifetime.m
index 08d2dbe..5e25253 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 -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
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fsyntax-only -fobjc-arc -fblocks -fobjc-runtime-has-weak -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 -fobjc-runtime-has-weak -Wexplicit-ownership-type -verify -Wno-objc-root-class %s
// rdar://10244607
typedef const struct __CFString * CFStringRef;
@@ -67,3 +67,61 @@ typedef void (^T) ();
- (void)createInferiorTransportAndSetEnvironment:(NSMutableDictionary*)environment error:(__autoreleasing NSError**)error {}
@end
+// <rdar://problem/12367446>
+typedef __strong id strong_id;
+typedef NSObject *NSObject_ptr;
+typedef __strong NSObject *strong_NSObject_ptr;
+
+// Warn
+__strong id f1(); // expected-warning{{ARC __strong lifetime qualifier on return type is ignored}}
+NSObject __unsafe_unretained *f2(int); // expected-warning{{ARC __unsafe_unretained lifetime qualifier on return type is ignored}}
+__autoreleasing NSObject *f3(void); // expected-warning{{ARC __autoreleasing lifetime qualifier on return type is ignored}}
+NSObject * __strong f4(void); // expected-warning{{ARC __strong lifetime qualifier on return type is ignored}}
+NSObject_ptr __strong f5(); // expected-warning{{ARC __strong lifetime qualifier on return type is ignored}}
+
+typedef __strong id (*fptr)(int); // expected-warning{{ARC __strong lifetime qualifier on return type is ignored}}
+
+// Don't warn
+strong_id f6();
+strong_NSObject_ptr f7();
+typedef __strong id (^block_ptr)(int);
+
+// rdar://10127067
+void test8_a() {
+ __weak id *(^myBlock)(void);
+ __weak id *var = myBlock();
+ (void) (__strong id *) &myBlock;
+ (void) (__weak id *) &myBlock; // expected-error {{cast}}
+}
+void test8_b() {
+ __weak id (^myBlock)(void);
+ (void) (__weak id *) &myBlock;
+ (void) (__strong id *) &myBlock; // expected-error {{cast}}
+}
+void test8_c() {
+ __weak id (^*(^myBlock)(void))(void);
+ (void) (__weak id*) myBlock();
+ (void) (__strong id*) myBlock(); // expected-error {{cast}}
+ (void) (__weak id*) &myBlock; // expected-error {{cast}}
+ (void) (__strong id*) &myBlock;
+}
+
+@class Test9;
+void test9_a() {
+ __weak Test9 **(^myBlock)(void);
+ __weak Test9 **var = myBlock();
+ (void) (__strong Test9 **) &myBlock;
+ (void) (__weak Test9 **) &myBlock; // expected-error {{cast}}
+}
+void test9_b() {
+ __weak Test9 *(^myBlock)(void);
+ (void) (__weak Test9**) &myBlock;
+ (void) (__strong Test9**) &myBlock; // expected-error {{cast}}
+}
+void test9_c() {
+ __weak Test9 *(^*(^myBlock)(void))(void);
+ (void) (__weak Test9 **) myBlock();
+ (void) (__strong Test9 **) myBlock(); // expected-error {{cast}}
+ (void) (__weak Test9 **) &myBlock; // expected-error {{cast}}
+ (void) (__strong Test9 **) &myBlock;
+}
diff --git a/test/SemaObjC/arc-property-lifetime.m b/test/SemaObjC/arc-property-lifetime.m
index 1957081..b824b2a 100644
--- a/test/SemaObjC/arc-property-lifetime.m
+++ b/test/SemaObjC/arc-property-lifetime.m
@@ -1,10 +1,10 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-default-synthesize-properties -fobjc-runtime-has-weak -fsyntax-only -fobjc-arc -verify -Wno-objc-root-class %s
// rdar://9340606
@interface Foo {
@public
- id __unsafe_unretained x;
- id __weak y;
+ id __unsafe_unretained x; // expected-error {{existing instance variable 'x' for strong property 'x' may not be __unsafe_unretained}}
+ id __weak y; // expected-error {{existing instance variable 'y' for strong property 'y' may not be __weak}}
id __autoreleasing z; // expected-error {{instance variables cannot have __autoreleasing ownership}}
}
@property(strong) id x; // expected-note {{property declared here}}
@@ -13,15 +13,15 @@
@end
@implementation Foo
-@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 x; // expected-note {{property synthesized here}}
+@synthesize y; // expected-note {{property synthesized here}}
@synthesize z; // suppressed
@end
@interface Bar {
@public
- id __unsafe_unretained x;
- id __weak y;
+ id __unsafe_unretained x; // expected-error {{existing instance variable 'x' for strong property 'x' may not be __unsafe_unretained}}
+ id __weak y; // expected-error {{existing instance variable 'y' for strong property 'y' may not be __weak}}
id __autoreleasing z; // expected-error {{instance variables cannot have __autoreleasing ownership}}
}
@property(retain) id x; // expected-note {{property declared here}}
@@ -30,15 +30,15 @@
@end
@implementation Bar
-@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 x; // expected-note {{property synthesized here}}
+@synthesize y; // expected-note {{property synthesized here}}
@synthesize z; // suppressed
@end
@interface Bas {
@public
- id __unsafe_unretained x;
- id __weak y;
+ id __unsafe_unretained x; // expected-error {{existing instance variable 'x' for strong property 'x' may not be __unsafe_unretained}}
+ id __weak y; // expected-error {{existing instance variable 'y' for strong property 'y' may not be __weak}}
id __autoreleasing z; // expected-error {{instance variables cannot have __autoreleasing ownership}}
}
@property(copy) id x; // expected-note {{property declared here}}
@@ -47,8 +47,8 @@
@end
@implementation Bas
-@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 x; // expected-note {{property synthesized here}}
+@synthesize y; // expected-note {{property synthesized here}}
@synthesize z; // suppressed
@end
@@ -70,7 +70,7 @@
// rdar://9341593
@interface Gorf {
id __unsafe_unretained x;
- id y;
+ id y; // expected-error {{existing instance variable 'y' for property 'y' with assign attribute must be __unsafe_unretained}}
}
@property(assign) id __unsafe_unretained x;
@property(assign) id y; // expected-note {{property declared here}}
@@ -79,13 +79,13 @@
@implementation Gorf
@synthesize x;
-@synthesize y; // expected-error {{existing instance variable 'y' for property 'y' with assign attribute must be __unsafe_unretained}}
+@synthesize y; // expected-note {{property synthesized here}}
@synthesize z;
@end
@interface Gorf2 {
id __unsafe_unretained x;
- id y;
+ id y; // expected-error {{existing instance variable 'y' for property 'y' with unsafe_unretained attribute must be __unsafe_unretained}}
}
@property(unsafe_unretained) id __unsafe_unretained x;
@property(unsafe_unretained) id y; // expected-note {{property declared here}}
@@ -94,7 +94,7 @@
@implementation Gorf2
@synthesize x;
-@synthesize y; // expected-error {{existing instance variable 'y' for property 'y' with unsafe_unretained attribute must be __unsafe_unretained}}
+@synthesize y; // expected-note {{property synthesized here}}
@synthesize z;
@end
@@ -173,3 +173,12 @@ void foo(Baz *f) {
@interface Boom
@property (readonly) const void * innerPointer __attribute__((objc_returns_inner_pointer)); // expected-error {{'objc_returns_inner_pointer' attribute only applies to methods}}
@end
+
+@interface Foo2 {
+ id _prop; // expected-error {{existing instance variable '_prop' for property 'prop' with assign attribute must be __unsafe_unretained}}
+}
+@property (nonatomic, assign) id prop; // expected-note {{property declared here}}
+@end
+
+@implementation Foo2
+@end
diff --git a/test/SemaObjC/arc-property.m b/test/SemaObjC/arc-property.m
index 2925459..cf823ae 100644
--- a/test/SemaObjC/arc-property.m
+++ b/test/SemaObjC/arc-property.m
@@ -2,11 +2,11 @@
// rdar://9309489
@interface MyClass {
- id __weak myString;
+ id __weak myString; // expected-error {{existing instance variable 'myString' for strong property 'myString' may not be __weak}}
id StrongIvar;
- id __weak myString2;
+ id __weak myString2; // expected-error {{existing instance variable 'myString2' for strong property 'myString2' may not be __weak}}
id __weak myString3;
- id StrongIvar5;
+ id StrongIvar5; // expected-error {{existing instance variable 'StrongIvar5' for __weak property 'myString5' must be __weak}}
}
@property (strong) id myString; // expected-note {{property declared here}}
@property (strong) id myString1;
@@ -18,21 +18,21 @@
@end
@implementation MyClass
-@synthesize myString; // expected-error {{existing instance variable 'myString' for strong property 'myString' may not be __weak}}
+@synthesize myString; // expected-note {{property synthesized here}}
@synthesize myString1 = StrongIvar; // OK
-@synthesize myString2 = myString2; // expected-error {{existing instance variable 'myString2' for strong property 'myString2' may not be __weak}}
+@synthesize myString2 = myString2; // expected-note {{property synthesized here}}
//
@synthesize myString3; // OK
@synthesize myString4; // OK
-@synthesize myString5 = StrongIvar5; // expected-error {{existing instance variable 'StrongIvar5' for __weak property 'myString5' must be __weak}}
+@synthesize myString5 = StrongIvar5; // expected-note {{property synthesized here}}
@end
// rdar://9340692
@interface Foo {
@public
- id __unsafe_unretained x; // should be __weak
- id __strong y;
+ id __unsafe_unretained x; // expected-error {{existing instance variable 'x' for __weak property 'x' must be __weak}}
+ id __strong y; // expected-error {{existing instance variable 'y' for __weak property 'y' must be __weak}}
id __autoreleasing z; // expected-error {{instance variables cannot have __autoreleasing ownership}}
}
@property(weak) id x; // expected-note {{property declared here}}
@@ -41,8 +41,8 @@
@end
@implementation Foo
-@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 x; // expected-note {{property synthesized here}}
+@synthesize y; // expected-note {{property synthesized here}}
@synthesize z; // suppressed
@end
diff --git a/test/SemaObjC/arc.m b/test/SemaObjC/arc.m
index bd30715..d89d035 100644
--- a/test/SemaObjC/arc.m
+++ b/test/SemaObjC/arc.m
@@ -4,6 +4,21 @@ typedef unsigned long NSUInteger;
typedef const void * CFTypeRef;
CFTypeRef CFBridgingRetain(id X);
id CFBridgingRelease(CFTypeRef);
+@protocol NSCopying @end
+@interface NSDictionary
++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id <NSCopying> [])keys count:(NSUInteger)cnt;
+- (void)setObject:(id)object forKeyedSubscript:(id)key;
+@end
+@class NSFastEnumerationState;
+@protocol NSFastEnumeration
+- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id __unsafe_unretained [])buffer count:(NSUInteger)len;
+@end
+@interface NSNumber
++ (NSNumber *)numberWithInt:(int)value;
+@end
+@interface NSArray <NSFastEnumeration>
++ (id)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt;
+@end
void test0(void (*fn)(int), int val) {
fn(val);
@@ -717,3 +732,27 @@ void _NSCalcBeze(NSColor* color, NSColor* bezelColors[]); // expected-error {{mu
- init { return 0; }
@end
+// <rdar://problem/12569201>. Warn on cases of initializing a weak variable
+// with an Objective-C object literal.
+void rdar12569201(id key, id value) {
+ // Declarations.
+ __weak id x = @"foo"; // no-warning
+ __weak id y = @{ key : value }; // expected-warning {{assigning dictionary literal to a weak variable; object will be released after assignment}}
+ __weak id z = @[ value ]; // expected-warning {{assigning array literal to a weak variable; object will be released after assignment}}
+ __weak id b = ^() {}; // expected-warning {{assigning block literal to a weak variable; object will be released after assignment}}
+ __weak id n = @42; // expected-warning {{assigning numeric literal to a weak variable; object will be released after assignment}}
+ __weak id e = @(42); // expected-warning {{assigning numeric literal to a weak variable; object will be released after assignment}}
+ __weak id m = @(41 + 1); // expected-warning {{assigning boxed expression to a weak variable; object will be released after assignment}}
+
+ // Assignments.
+ y = @{ key : value }; // expected-warning {{assigning dictionary literal to a weak variable; object will be released after assignment}}
+ z = @[ value ]; // expected-warning {{assigning array literal to a weak variable; object will be released after assignment}}
+ b = ^() {}; // expected-warning {{assigning block literal to a weak variable; object will be released after assignment}}
+ n = @42; // expected-warning {{assigning numeric literal to a weak variable; object will be released after assignment}}
+ e = @(42); // expected-warning {{assigning numeric literal to a weak variable; object will be released after assignment}}
+ m = @(41 + 1); // expected-warning {{assigning boxed expression to a weak variable; object will be released after assignment}}
+}
+
+@interface C
+- (void)method:(id[])objects; // expected-error{{must explicitly describe intended ownership of an object array parameter}}
+@end
diff --git a/test/SemaObjC/attr-availability.m b/test/SemaObjC/attr-availability.m
index ed6b760..bf7ef19 100644
--- a/test/SemaObjC/attr-availability.m
+++ b/test/SemaObjC/attr-availability.m
@@ -6,11 +6,24 @@
@interface A <P>
- (void)method __attribute__((availability(macosx,introduced=10.1,deprecated=10.2))); // expected-note {{method 'method' declared here}}
+
+- (void)overridden __attribute__((availability(macosx,introduced=10.3))); // expected-note{{overridden method is here}}
+- (void)overridden2 __attribute__((availability(macosx,introduced=10.3)));
+- (void)overridden3 __attribute__((availability(macosx,deprecated=10.3)));
+- (void)overridden4 __attribute__((availability(macosx,deprecated=10.3))); // expected-note{{overridden method is here}}
+- (void)overridden5 __attribute__((availability(macosx,unavailable)));
+- (void)overridden6 __attribute__((availability(macosx,introduced=10.3))); // expected-note{{overridden method is here}}
@end
// rdar://11475360
@interface B : A
- (void)method; // expected-note {{method 'method' declared here}}
+- (void)overridden __attribute__((availability(macosx,introduced=10.4))); // expected-warning{{overriding method introduced after overridden method on OS X (10.4 vs. 10.3)}}
+- (void)overridden2 __attribute__((availability(macosx,introduced=10.2)));
+- (void)overridden3 __attribute__((availability(macosx,deprecated=10.4)));
+- (void)overridden4 __attribute__((availability(macosx,deprecated=10.2))); // expected-warning{{overriding method deprecated before overridden method on OS X (10.3 vs. 10.2)}}
+- (void)overridden5 __attribute__((availability(macosx,introduced=10.3)));
+- (void)overridden6 __attribute__((availability(macosx,unavailable))); // expected-warning{{overriding method cannot be unavailable on OS X when its overridden method is available}}
@end
void f(A *a, B *b) {
diff --git a/test/SemaObjC/attr-deprecated.m b/test/SemaObjC/attr-deprecated.m
index c0aa9fc..aa4b479 100644
--- a/test/SemaObjC/attr-deprecated.m
+++ b/test/SemaObjC/attr-deprecated.m
@@ -1,4 +1,5 @@
// 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
@interface A {
int X __attribute__((deprecated)); // expected-note 2 {{declared here}}
@@ -135,3 +136,21 @@ typedef struct {
@property footype c; // expected-warning {{'footype' is deprecated}}
@property footype d __attribute((deprecated));
@end
+
+// rdar://13569424
+@interface NewI
++(void)cmeth;
+@end
+
+typedef NewI DeprI __attribute__((deprecated("blah"))); // expected-note 4 {{'DeprI' declared here}}
+
+@interface SI : DeprI // expected-warning {{'DeprI' is deprecated: blah}}
+-(DeprI*)meth; // expected-warning {{'DeprI' is deprecated: blah}}
+@end
+
+@implementation SI
+-(DeprI*)meth { // expected-warning {{'DeprI' is deprecated: blah}}
+ [DeprI cmeth]; // expected-warning {{'DeprI' is deprecated: blah}}
+ return 0;
+}
+@end
diff --git a/test/SemaObjC/bad-receiver-1.m b/test/SemaObjC/bad-receiver-1.m
index fe3eecf..fe7f7f5 100644
--- a/test/SemaObjC/bad-receiver-1.m
+++ b/test/SemaObjC/bad-receiver-1.m
@@ -7,8 +7,7 @@
int objc_lookUpClass(const char*);
void __raiseExc1() {
- [objc_lookUpClass("NSString") retain]; // expected-warning {{receiver type 'int' is not 'id'}} \
- expected-warning {{method '-retain' not found}}
+ [objc_lookUpClass("NSString") retain]; // expected-warning {{receiver type 'int' is not 'id'}}
}
typedef const struct __CFString * CFStringRef;
diff --git a/test/SemaObjC/blocks.m b/test/SemaObjC/blocks.m
index 9926b08..b523e4c 100644
--- a/test/SemaObjC/blocks.m
+++ b/test/SemaObjC/blocks.m
@@ -75,10 +75,11 @@ void foo10() {
// In C, enum constants have the type of the underlying integer type, not the
-// enumeration they are part of. We pretend the constants have enum type when
-// they are mixed with other expressions of enum type.
+// enumeration they are part of. We pretend the constants have enum type if
+// all the returns seem to be playing along.
enum CStyleEnum {
- CSE_Value = 1
+ CSE_Value = 1,
+ CSE_Value2 = 2
};
enum CStyleEnum getCSE();
typedef enum CStyleEnum (^cse_block_t)();
@@ -92,7 +93,9 @@ void testCStyleEnumInference(bool arg) {
a = ^{ // expected-error {{incompatible block pointer types assigning to 'cse_block_t' (aka 'enum CStyleEnum (^)()') from 'int (^)(void)'}}
return 1;
};
- a = ^{ // expected-error {{incompatible block pointer types assigning to 'cse_block_t' (aka 'enum CStyleEnum (^)()') from 'int (^)(void)'}}
+
+ // No warning here.
+ a = ^{
return CSE_Value;
};
@@ -114,6 +117,15 @@ void testCStyleEnumInference(bool arg) {
else
return 1;
};
+
+ // rdar://13200889
+ extern void check_enum(void);
+ a = ^{
+ return (arg ? (CSE_Value) : (check_enum(), (!arg ? CSE_Value2 : getCSE())));
+ };
+ a = ^{
+ return (arg ? (CSE_Value) : ({check_enum(); CSE_Value2; }));
+ };
}
@@ -184,8 +196,8 @@ typedef short (^short_block_t)();
void testAnonymousEnumTypes(int arg) {
int_block_t IB;
IB = ^{ return AnonymousValue; };
- IB = ^{ if (arg) return TDE_Value; else return getTDE(); }; // expected-error {{incompatible block pointer}}
- IB = ^{ if (arg) return getTDE(); else return TDE_Value; }; // expected-error {{incompatible block pointer}}
+ IB = ^{ if (arg) return TDE_Value; else return getTDE(); };
+ IB = ^{ if (arg) return getTDE(); else return TDE_Value; };
// Since we fixed the underlying type of the enum, these are considered
// compatible block types anyway.
diff --git a/test/SemaObjC/boxing-illegal-types.m b/test/SemaObjC/boxing-illegal.m
index ad45b11..59b5c8b 100644
--- a/test/SemaObjC/boxing-illegal-types.m
+++ b/test/SemaObjC/boxing-illegal.m
@@ -56,3 +56,20 @@ void testEnum(void *p) {
box = @(ME_foo);
box = @(*(enum ForwE*)p); // expected-error {{incomplete type 'enum ForwE' used in a boxed expression}}
}
+
+// rdar://13333205
+@class NSMutableDictionary;
+
+@interface NSMutableArray
++ (NSMutableArray*) array;
+@end
+
+NSMutableDictionary* mBars;
+
+__attribute((objc_root_class)) @interface rdar13333205 @end
+
+@implementation rdar13333205
+- (void) insertBar:(id)preset ofKind:(id) kind atIndex:(int)index {
+ NSMutableArray* presetArray = mBars[kind] ?: [NSMutableArray array]; // expected-error {{expected method to read dictionary element not found on object of type 'NSMutableDictionary *'}}
+}
+@end
diff --git a/test/SemaObjC/builtin_objc_lib_functions.m b/test/SemaObjC/builtin_objc_lib_functions.m
index 956ee12..d8713dd 100644
--- a/test/SemaObjC/builtin_objc_lib_functions.m
+++ b/test/SemaObjC/builtin_objc_lib_functions.m
@@ -14,7 +14,7 @@ long double f3(id self, SEL op) { return objc_msgSend_fpret(self, op); } // expe
// expected-note {{please include the header <objc/message.h> or explicitly provide a declaration for 'objc_msgSend_fpret'}}
id f4(struct objc_super *super, SEL op) { // expected-warning {{declaration of 'struct objc_super' will not be visible outside of this function}}
- return objc_msgSendSuper(super, op); // expected-warning {{implicitly declaring library function 'objc_msgSendSuper' with type 'id (void *, SEL, ...)'}} \
+ return objc_msgSendSuper(super, op); // expected-warning {{implicitly declaring library function 'objc_msgSendSuper' with type 'id (struct objc_super *, SEL, ...)'}} \
// expected-note {{please include the header <objc/message.h> or explicitly provide a declaration for 'objc_msgSendSuper'}}
}
diff --git a/test/SemaObjC/builtin_objc_msgSend.m b/test/SemaObjC/builtin_objc_msgSend.m
index bfa09d9..ffa16e7 100644
--- a/test/SemaObjC/builtin_objc_msgSend.m
+++ b/test/SemaObjC/builtin_objc_msgSend.m
@@ -2,3 +2,19 @@
// expected-no-diagnostics
// rdar://8632525
extern id objc_msgSend(id self, SEL op, ...);
+
+// rdar://12489098
+struct objc_super {
+ id receiver;
+ Class super_class;
+};
+
+extern __attribute__((visibility("default"))) id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
+ __attribute__((availability(macosx,introduced=10.0)));
+
+extern __attribute__((visibility("default"))) void objc_msgSendSuper_stret(struct objc_super *super, SEL op, ...)
+ __attribute__((availability(macosx,introduced=10.0)));
+
+extern __attribute__((visibility("default"))) void objc_msgSend_stret(id self, SEL op, ...)
+ __attribute__((availability(macosx,introduced=10.0)));
+
diff --git a/test/SemaObjC/category-1.m b/test/SemaObjC/category-1.m
index a7e6965..18b872a 100644
--- a/test/SemaObjC/category-1.m
+++ b/test/SemaObjC/category-1.m
@@ -71,8 +71,7 @@
@interface MultipleCat_I() <MultipleCat_P> @end
-@implementation MultipleCat_I // expected-warning {{incomplete implementation}} \
- // expected-warning {{method 'im0' in protocol not implemented}}
+@implementation MultipleCat_I // expected-warning {{method 'im0' in protocol not implemented}}
@end
// <rdar://problem/7680391> - Handle nameless categories with no name that refer
diff --git a/test/SemaObjC/compare-qualified-id.m b/test/SemaObjC/compare-qualified-id.m
index d31dfae..82868f8a 100644
--- a/test/SemaObjC/compare-qualified-id.m
+++ b/test/SemaObjC/compare-qualified-id.m
@@ -23,8 +23,7 @@ extern NSString * const NSTaskDidTerminateNotification;
- (NSString *)evaluateAsStringInContext:(XCPropertyExpansionContext *)context withNestingState:(const void *)state;
@end
-@implementation XCPropertyExpansionContext // expected-warning {{incomplete implementation}} \
- // expected-warning {{method 'copyWithZone:' in protocol not implemented}}
+@implementation XCPropertyExpansionContext // expected-warning {{method 'copyWithZone:' in protocol not implemented}}
- (NSString *)expandedValueForProperty:(NSString *)property {
id <XCPropertyValues> cachedValueNode = [_propNamesToPropValuesCache objectForKey:property]; // expected-warning {{method '-objectForKey:' not found (return type defaults to 'id')}}
if (cachedValueNode == ((void *)0)) { }
diff --git a/test/SemaObjC/conditional-expr.m b/test/SemaObjC/conditional-expr.m
index e0a3210..ec1305d 100644
--- a/test/SemaObjC/conditional-expr.m
+++ b/test/SemaObjC/conditional-expr.m
@@ -21,10 +21,10 @@
@end
@interface DTFilterOutputStream2
-- nextOutputStream; // expected-note {{method definition for 'nextOutputStream' not found}}
+- nextOutputStream; // expected-note {{method 'nextOutputStream' declared here}}
@end
-@implementation DTFilterOutputStream2 // expected-warning {{incomplete implementation}}
+@implementation DTFilterOutputStream2 // expected-warning {{method definition for 'nextOutputStream' not found}}
- (id)initWithNextOutputStream:(id <DTOutputStreams>) outputStream {
id <DTOutputStreams> nextOutputStream = [self nextOutputStream];
self = nextOutputStream; // expected-warning {{assigning to 'DTFilterOutputStream2 *' from incompatible type 'id<DTOutputStreams>'}}
diff --git a/test/SemaObjC/crash-on-objc-bool-literal.m b/test/SemaObjC/crash-on-objc-bool-literal.m
index 2c003a5..47e1ce2 100644
--- a/test/SemaObjC/crash-on-objc-bool-literal.m
+++ b/test/SemaObjC/crash-on-objc-bool-literal.m
@@ -2,11 +2,10 @@
// 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'}}
+typedef signed char 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'}}
+EXPORT BOOL FUNC(BOOL enabled); // expected-error {{unknown type name 'EXPORT'}} // expected-error {{expected ';' after top level declarator}}
-static inline BOOL MFIsPrivateVersion(void) { // expected-error {{reference to 'BOOL' is ambiguous}}
- return __objc_yes; // expected-error {{reference to 'BOOL' is ambiguous}}
+static inline BOOL MFIsPrivateVersion(void) {
+ return __objc_yes;
}
diff --git a/test/SemaObjC/debugger-cast-result-to-id.m b/test/SemaObjC/debugger-cast-result-to-id.m
index 00a02be..ecf3e74 100644
--- a/test/SemaObjC/debugger-cast-result-to-id.m
+++ b/test/SemaObjC/debugger-cast-result-to-id.m
@@ -6,6 +6,8 @@ extern __unknown_anytype test1();
void test_unknown_anytype_receiver() {
(void)(int)[[test0 unknownMethod] otherUnknownMethod];;
(void)(id)[[test1() unknownMethod] otherUnknownMethod];
+ id x = test0;
+ id y = test1();
}
// rdar://10988847
diff --git a/test/SemaObjC/default-synthesize-3.m b/test/SemaObjC/default-synthesize-3.m
index 606ece3..82f968d 100644
--- a/test/SemaObjC/default-synthesize-3.m
+++ b/test/SemaObjC/default-synthesize-3.m
@@ -39,3 +39,75 @@ __attribute ((objc_requires_property_definitions))
__attribute ((objc_requires_property_definitions)) // expected-error {{objc_requires_property_definitions attribute may only be specified on a class}}
@protocol P @end
+
+// rdar://13388503
+@interface NSObject @end
+@protocol Foo
+@property (readonly) char isFoo; // expected-note {{property declared here}}
+@property (readonly) char isNotFree;
+@end
+
+@interface Bar : NSObject <Foo>
+@end
+
+@implementation Bar
+- (char)isFoo {
+ return 0;
+}
+- (char)isNotFree {
+ return 0;
+}
+@end
+
+@interface Baz : Bar
+@end
+
+@interface Baz ()
+@property (readwrite) char isFoo; // expected-warning {{auto property synthesis will not synthesize property 'isFoo' because it is 'readwrite' but it will be synthesized 'readonly' via another property}}
+@property char Property1; // expected-warning {{auto property synthesis will not synthesize property 'Property1' because it cannot share an ivar with another synthesized property}}
+@property char Property2;
+@property (readwrite) char isNotFree;
+@end
+
+@implementation Baz {
+ char _isFoo;
+ char _isNotFree;
+}
+@synthesize Property2 = Property1; // expected-note {{property synthesized here}}
+
+- (void) setIsNotFree : (char)Arg {
+ _isNotFree = Arg;
+}
+
+@end
+
+// More test where such warnings should not be issued.
+@protocol MyProtocol
+-(void)setProp1:(id)x;
+@end
+
+@protocol P1 <MyProtocol>
+@end
+
+@interface B
+@property (readonly) id prop;
+@property (readonly) id prop1;
+@property (readonly) id prop2;
+@end
+
+@interface B()
+-(void)setProp:(id)x;
+@end
+
+@interface B(cat)
+@property (readwrite) id prop2;
+@end
+
+@interface S : B<P1>
+@property (assign,readwrite) id prop;
+@property (assign,readwrite) id prop1;
+@property (assign,readwrite) id prop2;
+@end
+
+@implementation S
+@end
diff --git a/test/SemaObjC/enum-fixed-type.m b/test/SemaObjC/enum-fixed-type.m
index 4fe643f..c00e45a 100644
--- a/test/SemaObjC/enum-fixed-type.m
+++ b/test/SemaObjC/enum-fixed-type.m
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-// expected-no-diagnostics
+// RUN: %clang_cc1 -fsyntax-only -pedantic -verify %s
#if !__has_feature(objc_fixed_enum)
# error Enumerations with a fixed underlying type are not supported
@@ -29,10 +28,13 @@ void test() {
// <rdar://10381507>
typedef enum : long { Foo } IntegerEnum;
-int arr[(sizeof(typeof(Foo)) == sizeof(typeof(IntegerEnum))) - 1];
-int arr1[(sizeof(typeof(Foo)) == sizeof(typeof(long))) - 1];
-int arr2[(sizeof(typeof(IntegerEnum)) == sizeof(typeof(long))) - 1];
+int arr[(sizeof(__typeof__(Foo)) == sizeof(__typeof__(IntegerEnum)))? 1 : -1];
+int arr1[(sizeof(__typeof__(Foo)) == sizeof(__typeof__(long)))? 1 : -1];
+int arr2[(sizeof(__typeof__(IntegerEnum)) == sizeof(__typeof__(long)))? 1 : -1];
// <rdar://problem/10760113>
typedef enum : long long { Bar = -1 } LongLongEnum;
int arr3[(long long)Bar == (long long)-1 ? 1 : -1];
+
+typedef enum : Integer { BaseElem } BaseEnum;
+typedef enum : BaseEnum { DerivedElem } DerivedEnum; // expected-error {{non-integral type 'BaseEnum' is an invalid underlying type}}
diff --git a/test/SemaObjC/error-missing-getter.m b/test/SemaObjC/error-missing-getter.m
index 3c91ab2..3dce858 100644
--- a/test/SemaObjC/error-missing-getter.m
+++ b/test/SemaObjC/error-missing-getter.m
@@ -9,11 +9,34 @@
@end
int func (int arg, Subclass *x) {
- if (x.setterOnly) { // expected-error {{expected getter method not found on object of type 'Subclass *'}}
+ if (x.setterOnly) { // expected-error {{no getter method for read from property}}
x.setterOnly = 1;
}
- func(x.setterOnly + 1, x); // expected-error {{expected getter method not found on object of type 'Subclass *'}}
- int i = x.setterOnly + 1; // expected-error {{expected getter method not found on object of type 'Subclass *'}}
- return x.setterOnly + 1; // expected-error {{expected getter method not found on object of type 'Subclass *'}}
+ func(x.setterOnly + 1, x); // expected-error {{no getter method for read from property}}
+ int i = x.setterOnly + 1; // expected-error {{no getter method for read from property}}
+ return x.setterOnly + 1; // expected-error {{no getter method for read from property}}
}
+// <rdar://problem/12765391>
+
+@interface TestClass
++ (void) setSetterOnly : (int) arg;
+@end
+
+int func2 (int arg) {
+ if (TestClass.setterOnly) { // expected-error {{no getter method for read from property}}
+ TestClass.setterOnly = 1;
+ }
+ func(TestClass.setterOnly + 1, x); // expected-error {{no getter method for read from property}}
+ int i = TestClass.setterOnly + 1; // expected-error {{no getter method for read from property}}
+ return TestClass.setterOnly + 1; // expected-error {{no getter method for read from property}}
+}
+
+@interface Sub : Subclass
+- (int) func3;
+@end
+@implementation Sub
+- (int) func3 {
+ return super.setterOnly; // expected-error {{no getter method for read from property}}
+}
+@end
diff --git a/test/SemaObjC/error-outof-scope-property-use.m b/test/SemaObjC/error-outof-scope-property-use.m
new file mode 100644
index 0000000..c69a405
--- /dev/null
+++ b/test/SemaObjC/error-outof-scope-property-use.m
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -fobjc-default-synthesize-properties -verify -Wno-objc-root-class %s
+// rdar://13178483
+
+@class NSMutableDictionary;
+
+@interface LaunchdJobs
+
+@property (nonatomic,retain) NSMutableDictionary *uuids_jobs; // expected-note 2 {{'_uuids_jobs' declared here}}
+
+@end
+
+@implementation LaunchdJobs
+
+-(void)job
+{
+
+ [uuids_jobs objectForKey]; // expected-error {{use of undeclared identifier 'uuids_jobs'}} \
+ // expected-warning {{instance method '-objectForKey' not found}}
+}
+
+
+@end
+
+void
+doLaunchdJobCPU()
+{
+ [uuids_jobs enumerateKeysAndObjectsUsingBlock]; // expected-error {{use of undeclared identifier 'uuids_jobs'}}
+}
diff --git a/test/SemaObjC/format-strings-objc.m b/test/SemaObjC/format-strings-objc.m
index 7faa995..bd33ad4 100644
--- a/test/SemaObjC/format-strings-objc.m
+++ b/test/SemaObjC/format-strings-objc.m
@@ -145,7 +145,7 @@ void test_percent_S() {
NSLog(@"%S", ptr); // no-warning
const wchar_t* wchar_ptr = L"ab";
- NSLog(@"%S", wchar_ptr); // expected-warning{{format specifies type 'const unsigned short *' but the argument has type 'const wchar_t *'}}
+ NSLog(@"%S", wchar_ptr); // expected-warning{{format specifies type 'const unichar *' (aka 'const unsigned short *') but the argument has type 'const wchar_t *'}}
}
void test_percent_ls() {
@@ -154,7 +154,7 @@ void test_percent_ls() {
NSLog(@"%ls", ptr); // no-warning
const wchar_t* wchar_ptr = L"ab";
- NSLog(@"%ls", wchar_ptr); // expected-warning{{format specifies type 'const unsigned short *' but the argument has type 'const wchar_t *'}}
+ NSLog(@"%ls", wchar_ptr); // expected-warning{{format specifies type 'const unichar *' (aka 'const unsigned short *') but the argument has type 'const wchar_t *'}}
}
void test_percent_C() {
@@ -162,7 +162,7 @@ void test_percent_C() {
NSLog(@"%C", data); // no-warning
const wchar_t wchar_data = L'a';
- NSLog(@"%C", wchar_data); // expected-warning{{format specifies type 'unsigned short' but the argument has type 'wchar_t'}}
+ NSLog(@"%C", wchar_data); // expected-warning{{format specifies type 'unichar' (aka 'unsigned short') but the argument has type 'wchar_t'}}
}
// Test that %@ works with toll-free bridging (<rdar://problem/10814120>).
diff --git a/test/SemaObjC/forward-protocol-incomplete-impl-warn.m b/test/SemaObjC/forward-protocol-incomplete-impl-warn.m
new file mode 100644
index 0000000..01fedec
--- /dev/null
+++ b/test/SemaObjC/forward-protocol-incomplete-impl-warn.m
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -fobjc-default-synthesize-properties %s
+// rdar://12958878
+
+@interface NSObject @end
+
+@protocol DVTInvalidation
+- (void)invalidate; // expected-note {{method 'invalidate' declared here}}
+@property int Prop; // expected-note {{property declared here}}
+@end
+
+
+
+@protocol DVTInvalidation;
+
+@interface IBImageCatalogDocument : NSObject <DVTInvalidation> // expected-note {{required for direct or indirect protocol 'DVTInvalidation'}}
+@end
+
+@implementation IBImageCatalogDocument // expected-warning {{auto property synthesis will not synthesize property declared in a protocol}} \
+ // expected-warning {{method 'invalidate' in protocol not implemented}}
+@end
diff --git a/test/SemaObjC/gcc-cast-ext.m b/test/SemaObjC/gcc-cast-ext.m
index 30e0dce..5858393 100644
--- a/test/SemaObjC/gcc-cast-ext.m
+++ b/test/SemaObjC/gcc-cast-ext.m
@@ -5,8 +5,8 @@ typedef struct _NSRange { } NSRange;
@class PBXFileReference;
@interface PBXDocBookmark
-+ alloc; // expected-note {{method definition for 'alloc' not found}}
-- autorelease; // expected-note {{method definition for 'autorelease' not found}}
++ alloc; // expected-note {{method 'alloc' declared here}}
+- autorelease; // expected-note {{method 'autorelease' declared here}}
@end
// GCC allows pointer expressions in integer constant expressions.
@@ -14,7 +14,8 @@ struct {
char control[((int)(char *)2)];
} xx;
-@implementation PBXDocBookmark // expected-warning {{incomplete implementation}}
+@implementation PBXDocBookmark // expected-warning {{method definition for 'autorelease' not found}}\
+ // expected-warning {{method definition for 'alloc' not found}}
+ (id)bookmarkWithFileReference:(PBXFileReference *)fileRef gylphRange:(NSRange)range anchor:(NSString *)htmlAnchor
{
diff --git a/test/SemaObjC/generic-selection.m b/test/SemaObjC/generic-selection.m
new file mode 100644
index 0000000..70c77dc
--- /dev/null
+++ b/test/SemaObjC/generic-selection.m
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+__attribute__((objc_root_class))
+@interface Root {
+ Class isa;
+}
+@end
+
+@interface A
+@property (strong) id x;
+@end
+
+// rdar://13193560
+void test0(A *a) {
+ int kind = _Generic(a.x, id : 0, int : 1, float : 2);
+}
diff --git a/test/SemaObjC/iboutlet.m b/test/SemaObjC/iboutlet.m
index a29915c..01e1bfc 100644
--- a/test/SemaObjC/iboutlet.m
+++ b/test/SemaObjC/iboutlet.m
@@ -9,15 +9,34 @@
#define IBOutlet __attribute__((iboutlet))
@interface I
-@property (getter = MyGetter, readonly, assign) IBOutlet NSView *myView; // expected-note {{property declared here}} \
- // expected-note {{readonly IBOutlet property should be changed to be readwrite}}
+@property (getter = MyGetter, readonly, assign) IBOutlet NSView *myView; // expected-warning {{readonly IBOutlet property 'myView' when auto-synthesized may not work correctly with 'nib' loader}} expected-note {{property should be changed to be readwrite}}
-@property (readonly) IBOutlet NSView *myView1; // expected-note {{readonly IBOutlet property should be changed to be readwrite}} \
- // expected-note {{property declared here}}
+@property (readonly) IBOutlet NSView *myView1; // expected-warning {{readonly IBOutlet property 'myView1' when auto-synthesized may not work correctly with 'nib' loader}} expected-note {{property should be changed to be readwrite}}
-@property (getter = MyGetter, READONLY) IBOutlet NSView *myView2; // expected-note {{property declared here}}
+@property (getter = MyGetter, READONLY) IBOutlet NSView *myView2; // expected-warning {{readonly IBOutlet property 'myView2' when auto-synthesized may not work correctly with 'nib' loader}}
@end
-@implementation I // expected-warning 3 {{readonly IBOutlet property when auto-synthesized may not work correctly with 'nib' loader}}
+@implementation I
+@end
+
+
+// rdar://13123861
+@class UILabel;
+
+@interface NSObject @end
+
+@interface RKTFHView : NSObject
+@property( readonly ) __attribute__((iboutlet)) UILabel *autoReadOnlyReadOnly; // expected-warning {{readonly IBOutlet property 'autoReadOnlyReadOnly' when auto-synthesized may not work correctly with 'nib' loader}} expected-note {{property should be changed to be readwrite}}
+@property( readonly ) __attribute__((iboutlet)) UILabel *autoReadOnlyReadWrite;
+@property( readonly ) __attribute__((iboutlet)) UILabel *synthReadOnlyReadWrite;
+@end
+
+@interface RKTFHView()
+@property( readwrite ) __attribute__((iboutlet)) UILabel *autoReadOnlyReadWrite;
+@property( readwrite ) __attribute__((iboutlet)) UILabel *synthReadOnlyReadWrite;
+@end
+
+@implementation RKTFHView
+@synthesize synthReadOnlyReadWrite=_synthReadOnlyReadWrite;
@end
diff --git a/test/SemaObjC/illegal-nonarc-bridged-cast.m b/test/SemaObjC/illegal-nonarc-bridged-cast.m
index a5bb01f..f3406ef 100644
--- a/test/SemaObjC/illegal-nonarc-bridged-cast.m
+++ b/test/SemaObjC/illegal-nonarc-bridged-cast.m
@@ -18,17 +18,16 @@ NSString *CreateNSString();
void from_cf() {
id obj1 = (__bridge_transfer id)CFCreateSomething(); // expected-warning {{'__bridge_transfer' casts have no effect when not using ARC}}
id obj2 = (__bridge_transfer NSString*)CFCreateString(); // expected-warning {{'__bridge_transfer' casts have no effect when not using ARC}}
- (__bridge int*)CFCreateSomething(); // expected-warning {{'__bridge' casts have no effect when not using ARC}} \
- // expected-warning {{expression result unused}}
- id obj3 = (__bridge id)CFGetSomething(); // expected-warning {{'__bridge' casts have no effect when not using ARC}}
- id obj4 = (__bridge NSString*)CFGetString(); // expected-warning {{'__bridge' casts have no effect when not using ARC}}
+ (__bridge int*)CFCreateSomething(); // expected-warning {{expression result unused}}
+ id obj3 = (__bridge id)CFGetSomething();
+ id obj4 = (__bridge NSString*)CFGetString();
}
void to_cf(id obj) {
CFTypeRef cf1 = (__bridge_retained CFTypeRef)CreateSomething(); // expected-warning {{'__bridge_retained' casts have no effect when not using ARC}}
CFStringRef cf2 = (__bridge_retained CFStringRef)CreateNSString(); // expected-warning {{'__bridge_retained' casts have no effect when not using ARC}}
- CFTypeRef cf3 = (__bridge CFTypeRef)CreateSomething(); // expected-warning {{'__bridge' casts have no effect when not using ARC}}
- CFStringRef cf4 = (__bridge CFStringRef)CreateNSString(); // expected-warning {{'__bridge' casts have no effect when not using ARC}}
+ CFTypeRef cf3 = (__bridge CFTypeRef)CreateSomething();
+ CFStringRef cf4 = (__bridge CFStringRef)CreateNSString();
}
void fixits() {
diff --git a/test/SemaObjC/incomplete-implementation.m b/test/SemaObjC/incomplete-implementation.m
index 54f66ef..4b8d600 100644
--- a/test/SemaObjC/incomplete-implementation.m
+++ b/test/SemaObjC/incomplete-implementation.m
@@ -1,11 +1,12 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fsyntax-only -verify -Wno-objc-root-class %s
@interface I
-- Meth; // expected-note{{method definition for 'Meth' not found}} \
- // expected-note{{method 'Meth' declared here}}
+- Meth; // expected-note 2 {{method 'Meth' declared here}}
+- unavailableMeth __attribute__((availability(macosx,unavailable)));
+- unavailableMeth2 __attribute__((unavailable));
@end
-@implementation I // expected-warning{{incomplete implementation}}
+@implementation I // expected-warning {{method definition for 'Meth' not found}}
@end
@implementation I(CAT)
diff --git a/test/SemaObjC/instancetype.m b/test/SemaObjC/instancetype.m
index 40f35d9..8137964 100644
--- a/test/SemaObjC/instancetype.m
+++ b/test/SemaObjC/instancetype.m
@@ -5,9 +5,9 @@
#endif
@interface Root
-+ (instancetype)alloc;
++ (instancetype)alloc; // expected-note {{explicitly declared 'instancetype'}}
- (instancetype)init; // expected-note{{overridden method is part of the 'init' method family}}
-- (instancetype)self;
+- (instancetype)self; // expected-note {{explicitly declared 'instancetype'}}
- (Class)class;
@property (assign) Root *selfProp;
@@ -143,7 +143,7 @@ void test_instancetype_narrow_method_search() {
@implementation Subclass4
+ (id)alloc {
- return self; // expected-warning{{incompatible pointer types casting 'Class' to type 'Subclass4 *'}}
+ return self; // expected-warning{{incompatible pointer types returning 'Class' from a function with result type 'Subclass4 *'}}
}
- (Subclass3 *)init { return 0; } // don't complain: we lost the related return type
@@ -164,14 +164,14 @@ void test_instancetype_inherited() {
// Check that related return types tighten up the semantics of
// Objective-C method implementations.
@implementation Subclass2
-- (instancetype)initSubclass2 {
+- (instancetype)initSubclass2 { // expected-note {{explicitly declared 'instancetype'}}
Subclass1 *sc1 = [[Subclass1 alloc] init];
- return sc1; // expected-warning{{incompatible pointer types casting 'Subclass1 *' to type 'Subclass2 *'}}
+ return sc1; // expected-warning{{incompatible pointer types returning 'Subclass1 *' from a function with result type 'Subclass2 *'}}
}
- (void)methodOnSubclass2 {}
- (id)self {
Subclass1 *sc1 = [[Subclass1 alloc] init];
- return sc1; // expected-warning{{incompatible pointer types casting 'Subclass1 *' to type 'Subclass2 *'}}
+ return sc1; // expected-warning{{incompatible pointer types returning 'Subclass1 *' from a function with result type 'Subclass2 *'}}
}
@end
@@ -188,3 +188,29 @@ void test_instancetype_inherited() {
@end
+// rdar://12493140
+@protocol P4
+- (instancetype) foo; // expected-note {{current method is explicitly declared 'instancetype' and is expected to return an instance of its class type}}
+@end
+@interface A4 : Root <P4>
+- (instancetype) bar; // expected-note {{current method is explicitly declared 'instancetype' and is expected to return an instance of its class type}}
+- (instancetype) baz; // expected-note {{overridden method returns an instance of its class type}} expected-note {{previous definition is here}}
+@end
+@interface B4 : Root @end
+
+@implementation A4 {
+ B4 *_b;
+}
+- (id) foo {
+ return _b; // expected-warning {{incompatible pointer types returning 'B4 *' from a function with result type 'A4 *'}}
+}
+- (id) bar {
+ return _b; // expected-warning {{incompatible pointer types returning 'B4 *' from a function with result type 'A4 *'}}
+}
+
+// This is really just to ensure that we don't crash.
+// FIXME: only one diagnostic, please
+- (float) baz { // expected-warning {{method is expected to return an instance of its class type 'A4', but is declared to return 'float'}} expected-warning {{conflicting return type in implementation}}
+ return 0;
+}
+@end
diff --git a/test/SemaObjC/message.m b/test/SemaObjC/message.m
index 621a18f..f43bdf9 100644
--- a/test/SemaObjC/message.m
+++ b/test/SemaObjC/message.m
@@ -95,6 +95,14 @@ int test5(int X) {
void foo4() {
struct objc_object X[10];
- [X rect]; // expected-warning {{receiver type 'struct objc_object *' is not 'id' or interface pointer, consider casting it to 'id'}} expected-warning {{method '-rect' not found (return type defaults to 'id')}}
+ [X rect]; // expected-warning {{receiver type 'struct objc_object *' is not 'id' or interface pointer, consider casting it to 'id'}}
}
+// rdar://13207886
+void foo5(id p) {
+ p
+ [(id)(p) bar]; // expected-error {{missing '['}} \
+ // expected-error {{expected ']'}} \
+ // expected-note {{to match this '['}} \
+ // expected-warning {{instance method '-bar' not found}}
+}
diff --git a/test/SemaObjC/method-undef-category-warn-1.m b/test/SemaObjC/method-undef-category-warn-1.m
index 2548cbd..98d732b 100644
--- a/test/SemaObjC/method-undef-category-warn-1.m
+++ b/test/SemaObjC/method-undef-category-warn-1.m
@@ -4,25 +4,25 @@
@end
@protocol P
-- (void) Pmeth; // expected-note {{method 'Pmeth' declared here}}
-- (void) Pmeth1; // expected-note {{method 'Pmeth1' declared here}}
+- (void) Pmeth; // expected-note {{method 'Pmeth' declared here}}
+- (void) Pmeth1; // expected-note {{method 'Pmeth1' declared here}}
@end
@interface MyClass1(CAT) <P> // expected-note {{required for direct or indirect protocol 'P'}}
-- (void) meth2; // expected-note {{method definition for 'meth2' not found}}
+- (void) meth2; // expected-note {{method 'meth2' declared here}}
@end
-@implementation MyClass1(CAT) // expected-warning {{incomplete implementation}} \
- // expected-warning {{method 'Pmeth' in protocol not implemented}}
+@implementation MyClass1(CAT) // expected-warning {{method 'Pmeth' in protocol not implemented}} \
+ // expected-warning {{method definition for 'meth2' not found}}
- (void) Pmeth1{}
@end
@interface MyClass1(DOG) <P> // expected-note {{required for direct or indirect protocol 'P'}}
-- (void)ppp; // expected-note {{method definition for 'ppp' not found}}
+- (void)ppp; // expected-note {{method 'ppp' declared here}}
@end
-@implementation MyClass1(DOG) // expected-warning {{incomplete implementation}} \
- // expected-warning {{method 'Pmeth1' in protocol not implemented}}
+@implementation MyClass1(DOG) // expected-warning {{method 'Pmeth1' in protocol not implemented}} \
+ // expected-warning {{method definition for 'ppp' not found}}
- (void) Pmeth {}
@end
diff --git a/test/SemaObjC/method-undef-extension-warn-1.m b/test/SemaObjC/method-undef-extension-warn-1.m
index c092f24..fbc21bd 100644
--- a/test/SemaObjC/method-undef-extension-warn-1.m
+++ b/test/SemaObjC/method-undef-extension-warn-1.m
@@ -10,7 +10,7 @@
// Class extension
@interface MyClass () <P>
-- (void)meth2; // expected-note {{method definition for 'meth2' not found}}
+- (void)meth2; // expected-note {{method 'meth2' declared here}}
@end
// Add a category to test that clang does not emit warning for this method.
@@ -18,7 +18,7 @@
- (void)categoryMethod;
@end
-@implementation MyClass // expected-warning {{incomplete implementation}} \
- // expected-warning {{method 'Pmeth1' in protocol not implemented}}
+@implementation MyClass // expected-warning {{method 'Pmeth1' in protocol not implemented}} \
+ // expected-warning {{method definition for 'meth2' not found}}
- (void)Pmeth {}
@end
diff --git a/test/SemaObjC/method-undefined-warn-1.m b/test/SemaObjC/method-undefined-warn-1.m
index 27d645e..e22140d 100644
--- a/test/SemaObjC/method-undefined-warn-1.m
+++ b/test/SemaObjC/method-undefined-warn-1.m
@@ -3,12 +3,14 @@
@interface INTF
- (void) meth;
- (void) meth : (int) arg1;
-- (int) int_meth; // expected-note {{method definition for 'int_meth' not found}}
-+ (int) cls_meth; // expected-note {{method definition for 'cls_meth' not found}}
-+ (void) cls_meth1 : (int) arg1; // expected-note {{method definition for 'cls_meth1:' not found}}
+- (int) int_meth; // expected-note {{method 'int_meth' declared here}}
++ (int) cls_meth; // expected-note {{method 'cls_meth' declared here}}
++ (void) cls_meth1 : (int) arg1; // expected-note {{method 'cls_meth1:' declared here}}
@end
-@implementation INTF // expected-warning {{incomplete implementation}}
+@implementation INTF // expected-warning {{method definition for 'int_meth' not found}} \
+ // expected-warning {{method definition for 'cls_meth' not found}} \
+ // expected-warning {{method definition for 'cls_meth1:' not found}}
- (void) meth {}
- (void) meth : (int) arg2{}
- (void) cls_meth1 : (int) arg2{}
@@ -17,12 +19,14 @@
@interface INTF1
- (void) meth;
- (void) meth : (int) arg1;
-- (int) int_meth; // expected-note {{method definition for 'int_meth' not found}}
-+ (int) cls_meth; // expected-note {{method definition for 'cls_meth' not found}}
-+ (void) cls_meth1 : (int) arg1; // expected-note {{method definition for 'cls_meth1:' not found}}
+- (int) int_meth; // expected-note {{method 'int_meth' declared here}}
++ (int) cls_meth; // expected-note {{method 'cls_meth' declared here}}
++ (void) cls_meth1 : (int) arg1; // expected-note {{method 'cls_meth1:' declared here}}
@end
-@implementation INTF1 // expected-warning {{incomplete implementation}}
+@implementation INTF1 // expected-warning {{method definition for 'int_meth' not found}} \
+ // expected-warning {{method definition for 'cls_meth' not found}} \
+ // expected-warning {{method definition for 'cls_meth1:' not found}}
- (void) meth {}
- (void) meth : (int) arg2{}
- (void) cls_meth1 : (int) arg2{}
diff --git a/test/SemaObjC/no-protocol-option-tests.m b/test/SemaObjC/no-protocol-option-tests.m
index dbd2a14..605cf9f 100644
--- a/test/SemaObjC/no-protocol-option-tests.m
+++ b/test/SemaObjC/no-protocol-option-tests.m
@@ -17,9 +17,9 @@
// Test2
@interface super - PMeth; @end
@interface J : super <P>
-- PMeth; // expected-note {{method definition for 'PMeth' not found}}
+- PMeth; // expected-note {{method 'PMeth' declared here}}
@end
-@implementation J @end // expected-warning {{incomplete implementation}}
+@implementation J @end // expected-warning {{method definition for 'PMeth' not found}}
// Test3
@interface K : super <P>
diff --git a/test/SemaObjC/no-warning-unavail-unimp.m b/test/SemaObjC/no-warning-unavail-unimp.m
index d5a4eac..037bf24 100644
--- a/test/SemaObjC/no-warning-unavail-unimp.m
+++ b/test/SemaObjC/no-warning-unavail-unimp.m
@@ -1,9 +1,11 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin9 -fsyntax-only -verify -Wno-objc-root-class %s
// expected-no-diagnostics
// rdar://9651605
+// rdar://12958191
@interface Foo
@property (getter=getVal) int val __attribute__((unavailable));
+@property (getter=getVal) int val2 __attribute__((availability(macosx,unavailable)));
- Method __attribute__((unavailable));
+ CMethod __attribute__((unavailable));
@end
diff --git a/test/SemaObjC/objc-literal-comparison.m b/test/SemaObjC/objc-literal-comparison.m
index 0a10582..95ebfb3 100644
--- a/test/SemaObjC/objc-literal-comparison.m
+++ b/test/SemaObjC/objc-literal-comparison.m
@@ -98,3 +98,6 @@ void testNilComparison() {
RETURN_IF_NIL(@(1+1));
}
+void PR15257(Class c) {
+ return c == @""; // expected-warning{{direct comparison of a string literal has undefined behavior}}
+}
diff --git a/test/SemaObjC/property-3.m b/test/SemaObjC/property-3.m
index 439dc28..3f82bcc 100644
--- a/test/SemaObjC/property-3.m
+++ b/test/SemaObjC/property-3.m
@@ -9,6 +9,25 @@
@end
@interface NOW : I
-@property (readonly) id d1; // expected-warning {{attribute 'readonly' of property 'd1' restricts attribute 'readwrite' of property inherited from 'I'}} expected-warning {{property 'd1' 'copy' attribute does not match the property inherited from 'I'}}
+@property (readonly) id d1; // expected-warning {{attribute 'readonly' of property 'd1' restricts attribute 'readwrite' of property inherited from 'I'}} expected-warning {{'copy' attribute on property 'd1' does not match the property inherited from 'I'}}
@property (readwrite, copy) I* d2;
@end
+
+// rdar://13156292
+typedef signed char BOOL;
+
+@protocol EKProtocolCalendar
+@property (nonatomic, readonly) BOOL allowReminders;
+@property (atomic, readonly) BOOL allowNonatomicProperty; // expected-note {{property declared here}}
+@end
+
+@protocol EKProtocolMutableCalendar <EKProtocolCalendar>
+@end
+
+@interface EKCalendar
+@end
+
+@interface EKCalendar () <EKProtocolMutableCalendar>
+@property (nonatomic, assign) BOOL allowReminders;
+@property (nonatomic, assign) BOOL allowNonatomicProperty; // expected-warning {{'atomic' attribute on property 'allowNonatomicProperty' does not match the property inherited from 'EKProtocolCalendar'}}
+@end
diff --git a/test/SemaObjC/property-4.m b/test/SemaObjC/property-4.m
index 2168048..49f0958 100644
--- a/test/SemaObjC/property-4.m
+++ b/test/SemaObjC/property-4.m
@@ -24,6 +24,6 @@
int newO;
int oldO;
}
-@property (retain) id MayCauseError; // expected-warning {{property 'MayCauseError' 'copy' attribute does not match the property inherited from 'ProtocolObject'}}
+@property (retain) id MayCauseError; // expected-warning {{'copy' attribute on property 'MayCauseError' does not match the property inherited from 'ProtocolObject'}}
@end
diff --git a/test/SemaObjC/property-category-3.m b/test/SemaObjC/property-category-3.m
index 47e93a3..9be97ae 100644
--- a/test/SemaObjC/property-category-3.m
+++ b/test/SemaObjC/property-category-3.m
@@ -16,7 +16,7 @@
@end
@interface I (Cat2) <P1>
-@property (retain) id ID; // expected-warning {{property 'ID' 'copy' attribute does not match the property inherited from 'P1'}}
+@property (retain) id ID; // expected-warning {{'copy' attribute on property 'ID' does not match the property inherited from 'P1'}}
@end
diff --git a/test/SemaObjC/property-category-impl.m b/test/SemaObjC/property-category-impl.m
index 9524c22..be42dea 100644
--- a/test/SemaObjC/property-category-impl.m
+++ b/test/SemaObjC/property-category-impl.m
@@ -29,3 +29,32 @@
@implementation MyClass (public)// expected-warning {{property 'foo' requires method 'setFoo:' to be defined }}
@end
+
+// rdar://12568064
+// No warn of unimplemented property of protocols in category,
+// when those properties will be implemented in category's primary
+// class or one of its super classes.
+@interface HBSuperclass
+@property (nonatomic) char myProperty;
+@property (nonatomic) char myProperty2;
+@end
+
+@interface HBClass : HBSuperclass
+@end
+
+@protocol HBProtocol
+@property (nonatomic) char myProperty;
+@property (nonatomic) char myProperty2;
+@end
+
+@interface HBSuperclass (HBSCategory)<HBProtocol>
+@end
+
+@implementation HBSuperclass (HBSCategory)
+@end
+
+@interface HBClass (HBCategory)<HBProtocol>
+@end
+
+@implementation HBClass (HBCategory)
+@end
diff --git a/test/SemaObjC/property-in-class-extension.m b/test/SemaObjC/property-in-class-extension.m
index a7b5130..022a487 100644
--- a/test/SemaObjC/property-in-class-extension.m
+++ b/test/SemaObjC/property-in-class-extension.m
@@ -37,11 +37,12 @@ void FUNC () {
@interface rdar8747333 ()
- (NSObject *)bam;
-- (NSObject *)warn; // expected-note {{method definition for 'warn' not found}}
-- (void)setWarn : (NSObject *)val; // expected-note {{method definition for 'setWarn:' not found}}
+- (NSObject *)warn; // expected-note {{method 'warn' declared here}}
+- (void)setWarn : (NSObject *)val; // expected-note {{method 'setWarn:' declared here}}
@end
-@implementation rdar8747333 // expected-warning {{incomplete implementation}}
+@implementation rdar8747333 // expected-warning {{method definition for 'warn' not found}} \
+ // expected-warning {{method definition for 'setWarn:' not found}}
@synthesize bar = _bar;
@synthesize baz = _baz;
@synthesize bam = _bam;
diff --git a/test/SemaObjC/property-noninherited-availability-attr.m b/test/SemaObjC/property-noninherited-availability-attr.m
new file mode 100644
index 0000000..79cdd3e
--- /dev/null
+++ b/test/SemaObjC/property-noninherited-availability-attr.m
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.8.0 -fsyntax-only -verify %s
+
+// This test case shows that 'availablity' and 'deprecated' does not inherit
+// when a property is redeclared in a subclass. This is intentional.
+
+@interface NSObject @end
+@protocol myProtocol
+@property int myProtocolProperty __attribute__((availability(macosx,introduced=10.7,deprecated=10.8)));
+@end
+
+@interface Foo : NSObject
+@property int myProperty __attribute__((availability(macosx,introduced=10.7,deprecated=10.8))); // expected-note {{'myProperty' declared here}} \
+ // expected-note {{method 'myProperty' declared here}} \
+ // expected-note {{property 'myProperty' is declared deprecated here}}
+@end
+
+@interface Bar : Foo <myProtocol>
+@property int myProperty; // expected-note {{'myProperty' declared here}}
+@property int myProtocolProperty; // expected-note {{'myProtocolProperty' declared here}}
+@end
+
+void test(Foo *y, Bar *x) {
+ y.myProperty = 0; // expected-warning {{'myProperty' is deprecated: first deprecated in OS X 10.8}}
+ [y myProperty]; // expected-warning {{'myProperty' is deprecated: first deprecated in OS X 10.8}}
+
+ x.myProperty = 1; // no-warning
+ [x myProperty]; // expected-warning {{'myProperty' is deprecated: first deprecated in OS X 10.8}}
+
+ x.myProtocolProperty = 0; // no-warning
+
+ [x myProtocolProperty]; // expected-warning {{'myProtocolProperty' is deprecated: first deprecated in OS X 10.8}}
+}
diff --git a/test/SemaObjC/property-user-setter.m b/test/SemaObjC/property-user-setter.m
index 9ebad60..cda983c 100644
--- a/test/SemaObjC/property-user-setter.m
+++ b/test/SemaObjC/property-user-setter.m
@@ -89,7 +89,7 @@ void g(int); // expected-note {{passing argument to parameter here}}
void f(C *c) {
c.Foo = 17; // OK
- g(c.Foo); // expected-error {{expected getter method not found on object of type 'C *'}}
+ g(c.Foo); // expected-error {{no getter method for read from property}}
}
@@ -132,7 +132,7 @@ int main (void) {
self.Pxyz = 0; // expected-error {{synthesized properties 'Pxyz' and 'pxyz' both claim setter 'setPxyz:'}}
self.pxyz = 0; // expected-error {{synthesized properties 'pxyz' and 'Pxyz' both claim setter 'setPxyz:'}}
self.R = 0;
- return self.R; // expected-error {{expected getter method not found on object of type 'rdar11363363 *'}}
+ return self.R; // expected-error {{no getter method for read from property}}
}
@end
diff --git a/test/SemaObjC/protocol-archane.m b/test/SemaObjC/protocol-archane.m
index 49c9851..788edf2 100644
--- a/test/SemaObjC/protocol-archane.m
+++ b/test/SemaObjC/protocol-archane.m
@@ -8,9 +8,9 @@
void bar();
void foo(id x) {
bar((short<SomeProtocol>)x); // expected-error {{expected ')'}} expected-note {{to match this '('}}
- bar((<SomeProtocol>)x); // expected-warning {{protocol qualifiers without 'id' is archaic}}
+ bar((<SomeProtocol>)x); // expected-warning {{protocol has no object type specified; defaults to qualified 'id'}}
- [(<SomeProtocol>)x bar]; // expected-warning {{protocol qualifiers without 'id' is archaic}}
+ [(<SomeProtocol>)x bar]; // expected-warning {{protocol has no object type specified; defaults to qualified 'id'}}
}
@protocol MyProtocol
@@ -37,6 +37,6 @@ Class <SomeProtocol> UnfortunateGCCExtension;
@protocol Broken @end
@interface Crash @end
@implementation Crash
-- (void)crashWith:(<Broken>)a { // expected-warning {{protocol qualifiers without 'id' is archaic}}
+- (void)crashWith:(<Broken>)a { // expected-warning {{protocol has no object type specified; defaults to qualified 'id'}}
}
@end
diff --git a/test/SemaObjC/related-result-type-inference.m b/test/SemaObjC/related-result-type-inference.m
index b1d77dc..50aaf2d 100644
--- a/test/SemaObjC/related-result-type-inference.m
+++ b/test/SemaObjC/related-result-type-inference.m
@@ -175,7 +175,7 @@ void test_inference() {
@implementation Fail
- (id<X>) initWithX
{
- return (id)self; // expected-warning {{returning 'Fail *' from a function with incompatible result type 'id<X>'}}
+ return (id)self; // expected-warning {{casting 'Fail *' to incompatible type 'id<X>'}}
}
@end
diff --git a/test/SemaObjC/selector-3.m b/test/SemaObjC/selector-3.m
index 4c12a93..f968aeb 100644
--- a/test/SemaObjC/selector-3.m
+++ b/test/SemaObjC/selector-3.m
@@ -52,3 +52,32 @@ SEL func()
}
@end
+// rdar://12938616
+@class NSXPCConnection;
+
+@interface NSObject
+@end
+
+@interface INTF : NSObject
+{
+ NSXPCConnection *cnx; // Comes in as a parameter.
+}
+- (void) Meth;
+@end
+
+extern SEL MySelector(SEL s);
+
+@implementation INTF
+- (void) Meth {
+ if( [cnx respondsToSelector:MySelector(@selector( _setQueue: ))] ) // expected-warning {{unimplemented selector '_setQueue:'}}
+ {
+ }
+
+ if( [cnx respondsToSelector:@selector( _setQueueXX: )] ) // No warning here.
+ {
+ }
+ if( [cnx respondsToSelector:(@selector( _setQueueXX: ))] ) // No warning here.
+ {
+ }
+}
+@end
diff --git a/test/SemaObjC/super-property-notation.m b/test/SemaObjC/super-property-notation.m
index 0c17bb9..4741d1b 100644
--- a/test/SemaObjC/super-property-notation.m
+++ b/test/SemaObjC/super-property-notation.m
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-// expected-no-diagnostics
+// RUN: %clang_cc1 -fsyntax-only -fobjc-default-synthesize-properties -verify %s
@interface B
+(int) classGetter;
@@ -29,3 +28,25 @@ void f0() {
int l2 = [A classGetter2];
}
+// rdar://13349296
+__attribute__((objc_root_class)) @interface ClassBase
+@property (nonatomic, retain) ClassBase * foo;
+@end
+
+@implementation ClassBase
+- (void) Meth:(ClassBase*)foo {
+ super.foo = foo; // expected-error {{'ClassBase' cannot use 'super' because it is a root class}}
+ [super setFoo:foo]; // expected-error {{'ClassBase' cannot use 'super' because it is a root class}}
+}
+@end
+
+@interface ClassDerived : ClassBase
+@property (nonatomic, retain) ClassDerived * foo;
+@end
+
+@implementation ClassDerived
+- (void) Meth:(ClassBase*)foo {
+ super.foo = foo; // must work with no warning
+ [super setFoo:foo]; // works with no warning
+}
+@end
diff --git a/test/SemaObjC/super.m b/test/SemaObjC/super.m
index cf48c19..fd069af 100644
--- a/test/SemaObjC/super.m
+++ b/test/SemaObjC/super.m
@@ -51,8 +51,7 @@ void f(id super) {
[super m];
}
void f0(int super) {
- [super m]; // expected-warning{{receiver type 'int' is not 'id'}} \
- expected-warning {{method '-m' not found (return type defaults to 'id')}}
+ [super m]; // expected-warning{{receiver type 'int' is not 'id'}}
}
void f1(id puper) { // expected-note {{'puper' declared here}}
[super m]; // expected-error{{use of undeclared identifier 'super'}}
diff --git a/test/SemaObjC/typo-correction.m b/test/SemaObjC/typo-correction.m
new file mode 100644
index 0000000..3fd61e2
--- /dev/null
+++ b/test/SemaObjC/typo-correction.m
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only -fwarn-on-spellcheck
+
+@interface B
+@property int x;
+@end
+
+@interface S : B
+@end
+
+// Spell-checking 'undefined' is ok.
+undefined var; // expected-warning {{spell-checking initiated}} \
+ // expected-error {{unknown type name}}
+
+typedef int super1;
+@implementation S
+-(void)foo {
+ // Spell-checking 'super' is not ok.
+ super.x = 0;
+ self.x = 0;
+}
+@end
diff --git a/test/SemaObjC/undef-protocol-methods-1.m b/test/SemaObjC/undef-protocol-methods-1.m
index 15ba1a1..25b1dad 100644
--- a/test/SemaObjC/undef-protocol-methods-1.m
+++ b/test/SemaObjC/undef-protocol-methods-1.m
@@ -28,10 +28,7 @@
// expected-note 2 {{required for direct or indirect protocol 'P2'}}
@end
-@implementation INTF // expected-warning {{incomplete implementation}} \
- // expected-warning 9 {{in protocol not implemented}}
+@implementation INTF // expected-warning 9 {{in protocol not implemented}}
- (void) DefP1proto{}
-
+ (void) DefClsP3Proto{}
-
@end
diff --git a/test/SemaObjC/warn-cast-of-sel-expr.m b/test/SemaObjC/warn-cast-of-sel-expr.m
index 97915a0..1253db9 100644
--- a/test/SemaObjC/warn-cast-of-sel-expr.m
+++ b/test/SemaObjC/warn-cast-of-sel-expr.m
@@ -18,4 +18,7 @@ int main() {
(void *const)s; // ok
(const void *const)s; // ok
+
+// rdar://12859590
+(SEL)sel_registerName("foo"); // ok
}
diff --git a/test/SemaObjC/warn-deprecated-implementations.m b/test/SemaObjC/warn-deprecated-implementations.m
index 5f7c2fd..f63962f 100644
--- a/test/SemaObjC/warn-deprecated-implementations.m
+++ b/test/SemaObjC/warn-deprecated-implementations.m
@@ -1,12 +1,13 @@
// RUN: %clang_cc1 -fsyntax-only -Wdeprecated-implementations -verify -Wno-objc-root-class %s
// rdar://8973810
+// rdar://12717705
@protocol P
- (void) D __attribute__((deprecated)); // expected-note {{method 'D' declared here}}
@end
@interface A <P>
-+ (void)F __attribute__((deprecated)); // expected-note {{method 'F' declared here}}
++ (void)F __attribute__((deprecated));
@end
@interface A()
@@ -14,11 +15,19 @@
@end
@implementation A
-+ (void)F { } // expected-warning {{Implementing deprecated method}}
++ (void)F { } // No warning, implementing its own deprecated method
- (void) D {} // expected-warning {{Implementing deprecated method}}
- (void) E {} // expected-warning {{Implementing deprecated method}}
@end
+@interface A(CAT)
+- (void) G __attribute__((deprecated));
+@end
+
+@implementation A(CAT)
+- (void) G {} // No warning, implementing its own deprecated method
+@end
+
__attribute__((deprecated))
@interface CL // expected-note 2 {{class declared here}} // expected-note 2 {{declared here}}
@end
diff --git a/test/SemaObjC/warn-direct-ivar-access.m b/test/SemaObjC/warn-direct-ivar-access.m
index 088fe0f..283a00f 100644
--- a/test/SemaObjC/warn-direct-ivar-access.m
+++ b/test/SemaObjC/warn-direct-ivar-access.m
@@ -1,10 +1,10 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-runtime-has-weak -Wdirect-ivar-access -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-runtime-has-weak -fobjc-default-synthesize-properties -Wdirect-ivar-access -verify -Wno-objc-root-class %s
// rdar://6505197
__attribute__((objc_root_class)) @interface MyObject {
@public
id _myMaster;
- id _isTickledPink;
+ id _isTickledPink; // expected-error {{existing instance variable '_isTickledPink' for property 'isTickledPink'}}
int _myIntProp;
}
@property(retain) id myMaster;
@@ -15,7 +15,7 @@ __attribute__((objc_root_class)) @interface MyObject {
@implementation MyObject
@synthesize myMaster = _myMaster;
-@synthesize isTickledPink = _isTickledPink; // expected-error {{existing instance variable '_isTickledPink' for property 'isTickledPink'}}
+@synthesize isTickledPink = _isTickledPink; // expected-note {{property synthesized here}}
@synthesize myIntProp = _myIntProp;
- (void) doSomething {
@@ -54,3 +54,25 @@ id Test32(__weak ITest32 *x) {
: (*x).ivar; // expected-error {{dereferencing a __weak pointer is not allowed}}
}
+// rdar://13142820
+@protocol PROTOCOL
+@property (copy, nonatomic) id property_in_protocol;
+@end
+
+__attribute__((objc_root_class)) @interface INTF <PROTOCOL>
+@property (copy, nonatomic) id foo;
+- (id) foo;
+@end
+
+@interface INTF()
+@property (copy, nonatomic) id foo1;
+- (id) foo1;
+@end
+
+@implementation INTF
+- (id) foo { return _foo; }
+- (id) property_in_protocol { return _property_in_protocol; } // expected-warning {{instance variable '_property_in_protocol' is being directly accessed}}
+- (id) foo1 { return _foo1; }
+@synthesize property_in_protocol = _property_in_protocol;
+@end
+
diff --git a/test/SemaObjC/warn-isa-ref.m b/test/SemaObjC/warn-isa-ref.m
index 9d7abd4..b1ffb4f 100644
--- a/test/SemaObjC/warn-isa-ref.m
+++ b/test/SemaObjC/warn-isa-ref.m
@@ -18,21 +18,19 @@ static void func() {
id x;
// rdar://8290002
- [(*x).isa self]; // expected-warning {{direct access to objective-c's isa is deprecated in favor of object_setClass() and object_getClass()}}
- [x->isa self]; // expected-warning {{direct access to objective-c's isa is deprecated in favor of object_setClass() and object_getClass()}}
+ [(*x).isa self]; // expected-warning {{direct access to Objective-C's isa is deprecated in favor of object_getClass()}}
+ [x->isa self]; // expected-warning {{direct access to Objective-C's isa is deprecated in favor of object_getClass()}}
Whatever *y;
// GCC allows this, with the following warning:
// instance variable 'isa' is @protected; this will be a hard error in the future
//
- // FIXME: see if we can avoid the 2 warnings that follow the error.
+ // FIXME: see if we can avoid the warning that follows the error.
[(*y).isa self]; // expected-error {{instance variable 'isa' is protected}} \
- expected-warning{{receiver type 'struct objc_class *' is not 'id' or interface pointer, consider casting it to 'id'}} \
- expected-warning{{method '-self' not found (return type defaults to 'id')}}
+ expected-warning{{receiver type 'struct objc_class *' is not 'id' or interface pointer, consider casting it to 'id'}}
[y->isa self]; // expected-error {{instance variable 'isa' is protected}} \
- expected-warning{{receiver type 'struct objc_class *' is not 'id' or interface pointer, consider casting it to 'id'}} \
- expected-warning{{method '-self' not found (return type defaults to 'id')}}
+ expected-warning{{receiver type 'struct objc_class *' is not 'id' or interface pointer, consider casting it to 'id'}}
}
// rdar://11702488
@@ -41,7 +39,7 @@ static void func() {
@interface BaseClass {
@public
- Class isa; // expected-note 3 {{instance variable is declared here}}
+ Class isa; // expected-note 4 {{instance variable is declared here}}
}
@end
@@ -72,12 +70,14 @@ static void func() {
Subclass *x;
SiblingClass *y;
OtherClass *z;
- (void)v->isa; // expected-warning {{direct access to objective-c's isa is deprecated}}
- (void)w->isa; // expected-warning {{direct access to objective-c's isa is deprecated}}
- (void)x->isa; // expected-warning {{direct access to objective-c's isa is deprecated}}
- (void)y->isa; // expected-warning {{direct access to objective-c's isa is deprecated}}
+ (void)v->isa; // expected-warning {{direct access to Objective-C's isa is deprecated in favor of object_getClass()}}
+ (void)w->isa; // expected-warning {{direct access to Objective-C's isa is deprecated in favor of object_getClass()}}
+ (void)x->isa; // expected-warning {{direct access to Objective-C's isa is deprecated in favor of object_getClass()}}
+ (void)y->isa; // expected-warning {{direct access to Objective-C's isa is deprecated in favor of object_getClass()}}
(void)z->isa;
(void)u->isa;
+
+ w->isa = 0; // expected-warning {{assignment to Objective-C's isa is deprecated in favor of object_setClass()}}
}
@end
diff --git a/test/SemaObjC/warn-retain-block-property.m b/test/SemaObjC/warn-retain-block-property.m
index 3a54baf..45823e3 100644
--- a/test/SemaObjC/warn-retain-block-property.m
+++ b/test/SemaObjC/warn-retain-block-property.m
@@ -1,6 +1,7 @@
-// RUN: %clang_cc1 -fsyntax-only -fblocks -fobjc-arc -verify -Wno-objc-root-class %s
+// RUN: %clang_cc1 -fsyntax-only -fblocks -fobjc-arc -Wno-objc-root-class %s 2>&1 | FileCheck --check-prefix=CHECK-ARC %s
// rdar://9829425
-// RUN: %clang_cc1 -fsyntax-only -fblocks -verify -Wno-objc-root-class %s
+
+// RUN: %clang_cc1 -fsyntax-only -fblocks -Wno-objc-root-class %s 2>&1 | FileCheck %s
// rdar://11761511
extern void doSomething();
@@ -10,12 +11,12 @@ extern void doSomething();
@public
void (^aBlock)(void);
}
-@property (retain) void (^aBlock)(void); // expected-warning {{retain'ed block property does not copy the block - use copy attribute instead}}
-@property (weak, retain) void (^aBlockW)(void); // expected-error {{property attributes 'retain' and 'weak' are mutually exclusive}}
+@property (retain) void (^aBlock)(void);
+@property (weak, retain) void (^aBlockW)(void);
@property (strong, retain) void (^aBlockS)(void); // OK
@property (readonly, retain) void (^aBlockR)(void); // OK
-@property (copy, retain) void (^aBlockC)(void); // expected-error {{property attributes 'copy' and 'retain' are mutually exclusive}}
-@property (assign, retain) void (^aBlockA)(void); // expected-error {{property attributes 'assign' and 'retain' are mutually exclusive}}
+@property (copy, retain) void (^aBlockC)(void);
+@property (assign, retain) void (^aBlockA)(void);
@end
@implementation Test
@@ -30,3 +31,33 @@ int main() {
t.aBlockS = ^{ doSomething(); };
}
+// CHECK-ARC: 14:1: warning: retain'ed block property does not copy the block - use copy attribute instead
+// CHECK-ARC: @property (retain) void (^aBlock)(void);
+// CHECK-ARC: ^
+// CHECK-ARC: 15:1: error: property attributes 'retain' and 'weak' are mutually exclusive
+// CHECK-ARC: @property (weak, retain) void (^aBlockW)(void);
+// CHECK-ARC: ^
+// CHECK-ARC: 18:1: error: property attributes 'copy' and 'retain' are mutually exclusive
+// CHECK-ARC: @property (copy, retain) void (^aBlockC)(void);
+// CHECK-ARC: ^
+// CHECK-ARC: 19:1: error: property attributes 'assign' and 'retain' are mutually exclusive
+// CHECK-ARC: @property (assign, retain) void (^aBlockA)(void);
+// CHECK-ARC: ^
+// CHECK-ARC: 30:13: warning: assigning block literal to a weak property; object will be released after assignment
+// CHECK-ARC: t.aBlockW = ^{ doSomething(); };
+// CHECK-ARC: ^ ~~~~~~~~~~~~~~~~~~~
+// CHECK-ARC: 2 warnings and 3 errors generated.
+
+// CHECK: 14:1: warning: retain'ed block property does not copy the block - use copy attribute instead
+// CHECK: @property (retain) void (^aBlock)(void);
+// CHECK: ^
+// CHECK: 15:1: error: property attributes 'retain' and 'weak' are mutually exclusive
+// CHECK: @property (weak, retain) void (^aBlockW)(void);
+// CHECK: ^
+// CHECK: 18:1: error: property attributes 'copy' and 'retain' are mutually exclusive
+// CHECK: @property (copy, retain) void (^aBlockC)(void);
+// CHECK: ^
+// CHECK: 19:1: error: property attributes 'assign' and 'retain' are mutually exclusive
+// CHECK: @property (assign, retain) void (^aBlockA)(void);
+// CHECK: ^
+// CHECK: 1 warning and 3 errors generated.
diff --git a/test/SemaObjC/warning-missing-selector-name.m b/test/SemaObjC/warning-missing-selector-name.m
index d43031e..a335e02 100644
--- a/test/SemaObjC/warning-missing-selector-name.m
+++ b/test/SemaObjC/warning-missing-selector-name.m
@@ -15,11 +15,11 @@
- 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}}
+ // expected-note {{method 'method::' declared here}}
@end
-@implementation INTF // expected-warning {{incomplete implementation}}
+@implementation INTF // expected-warning {{method definition for 'method::' not found}}
-(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}} \
diff --git a/test/SemaObjC/weak-property.m b/test/SemaObjC/weak-property.m
index 141c35b..d306a92 100644
--- a/test/SemaObjC/weak-property.m
+++ b/test/SemaObjC/weak-property.m
@@ -4,7 +4,7 @@
@interface WeakPropertyTest {
Class isa;
__weak id value;
- id x;
+ id x; // expected-error {{existing instance variable 'x' for __weak property 'x' must be __weak}}
}
@property (weak) id value1;
@property __weak id value;
@@ -19,6 +19,6 @@
@end
@implementation WeakPropertyTest
-@synthesize x; // expected-error {{existing instance variable 'x' for __weak property 'x' must be __weak}}
+@synthesize x; // expected-note {{property synthesized here}}
@dynamic value1, value, value2, v1,v2,v3,v4;
@end
diff --git a/test/SemaObjCXX/arc-0x.mm b/test/SemaObjCXX/arc-0x.mm
index 43f6671..391fc47 100644
--- a/test/SemaObjCXX/arc-0x.mm
+++ b/test/SemaObjCXX/arc-0x.mm
@@ -93,3 +93,11 @@ typedef __builtin_va_list va_list;
__builtin_va_arg(args, id);
}
@end
+
+namespace rdar12078752 {
+ void f() {
+ NSObject* o =0;
+ __autoreleasing decltype(o) o2 = o;
+ __autoreleasing auto o3 = o;
+ }
+}
diff --git a/test/SemaObjCXX/arc-nsconsumed-errors.mm b/test/SemaObjCXX/arc-nsconsumed-errors.mm
index 93f5d99..10ae10d 100644
--- a/test/SemaObjCXX/arc-nsconsumed-errors.mm
+++ b/test/SemaObjCXX/arc-nsconsumed-errors.mm
@@ -18,3 +18,35 @@ blk1 b2 = ^void (id, __attribute((ns_consumed)) id){}; // expected-error {{canno
blk1 c3 = ^void (__attribute((ns_consumed)) id, __attribute((ns_consumed)) id){};
blk1 d4 = ^void (id, id) {}; // expected-error {{cannot initialize a variable of type '__strong blk1'}}
+
+
+typedef void (*releaser_t)(__attribute__((ns_consumed)) id);
+
+void normalFunction(id);
+releaser_t r1 = normalFunction; // expected-error {{cannot initialize a variable of type 'releaser_t'}}
+
+void releaser(__attribute__((ns_consumed)) id);
+releaser_t r2 = releaser; // no-warning
+
+template <typename T>
+void templateFunction(T) {} // expected-note {{candidate function}}
+releaser_t r3 = templateFunction<id>; // expected-error {{address of overloaded function 'templateFunction' does not match required type 'void (id)'}}
+
+template <typename T>
+void templateReleaser(__attribute__((ns_consumed)) T) {}
+releaser_t r4 = templateReleaser<id>; // no-warning
+
+
+@class AntiRelease, ExplicitAntiRelease, ProRelease;
+
+template<>
+void templateFunction(__attribute__((ns_consumed)) AntiRelease *); // expected-error {{no function template matches function template specialization 'templateFunction'}}
+
+template<>
+void templateReleaser(AntiRelease *); // expected-error {{no function template matches function template specialization 'templateReleaser'}}
+
+template<>
+void templateReleaser(ExplicitAntiRelease *) {} // expected-error {{no function template matches function template specialization 'templateReleaser'}}
+
+template<>
+void templateReleaser(__attribute__((ns_consumed)) ProRelease *); // no-warning
diff --git a/test/SemaObjCXX/arc-templates.mm b/test/SemaObjCXX/arc-templates.mm
index 8009272..ef68b94 100644
--- a/test/SemaObjCXX/arc-templates.mm
+++ b/test/SemaObjCXX/arc-templates.mm
@@ -283,3 +283,12 @@ namespace rdar10862386 {
testing(@"hi");
}
}
+
+namespace rdar12367446 {
+ template <class T> class A;
+ template <class R> class A<R()> {};
+
+ void test() {
+ A<id()> value;
+ }
+}
diff --git a/test/SemaObjCXX/arc-unbridged-cast.mm b/test/SemaObjCXX/arc-unbridged-cast.mm
index f7d2391..3f7f76d 100644
--- a/test/SemaObjCXX/arc-unbridged-cast.mm
+++ b/test/SemaObjCXX/arc-unbridged-cast.mm
@@ -108,3 +108,12 @@ void testTakerFunctions(id string) {
takeCFVariadicAudited(1, (CFStringRef) string);
takeCFConsumedAudited((CFStringRef) string); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'CFStringRef'}} expected-note {{use __bridge to}} expected-note {{use CFBridgingRetain call to}}
}
+
+// rdar://12788838
+id obj;
+
+void rdar12788838() {
+ void *foo = reinterpret_cast<void *>(obj); // expected-error {{cast of Objective-C pointer type 'id' to C pointer type 'void *' requires a bridged cast}} \
+ // expected-note {{use __bridge with C-style cast to convert directly}} \
+ // expected-note {{use CFBridgingRetain call to make an ARC object available as a +1 'void *'}}
+}
diff --git a/test/SemaObjCXX/capturing-flexible-array-in-block.mm b/test/SemaObjCXX/capturing-flexible-array-in-block.mm
new file mode 100644
index 0000000..d7d8885
--- /dev/null
+++ b/test/SemaObjCXX/capturing-flexible-array-in-block.mm
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -fsyntax-only -fblocks -verify -std=c++11 %s
+// rdar://12655829
+
+void f() {
+ struct { int x; int y[]; } a; // expected-note 2 {{'a' declared here}}
+ ^{return a.x;}(); // expected-error {{cannot refer to declaration of structure variable with flexible array member inside block}}
+ [] {return a.x;}(); // expected-error {{variable 'a' with flexible array member cannot be captured in a lambda expression}}
+}
diff --git a/test/SemaObjCXX/debugger-cast-result-to-id.mm b/test/SemaObjCXX/debugger-cast-result-to-id.mm
index cd7aa7b..815ae38 100644
--- a/test/SemaObjCXX/debugger-cast-result-to-id.mm
+++ b/test/SemaObjCXX/debugger-cast-result-to-id.mm
@@ -1,7 +1,21 @@
-// RUN: %clang_cc1 -fdebugger-support -fdebugger-cast-result-to-id -funknown-anytype -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fdebugger-support -fdebugger-cast-result-to-id -funknown-anytype -fsyntax-only -verify %s
+
+extern __unknown_anytype test0a;
+extern __unknown_anytype test1a();
+extern __unknown_anytype test0b;
+extern __unknown_anytype test1b();
+extern __unknown_anytype test0c;
+extern __unknown_anytype test1c();
+extern __unknown_anytype test0d;
+extern __unknown_anytype test1d();
+extern __unknown_anytype test0d;
+extern __unknown_anytype test1d();
+
+@interface A
+@end
// rdar://problem/9416370
-namespace test0 {
+namespace rdar9416370 {
void test(id x) {
if ([x foo]) {} // expected-error {{no known method '-foo'; cast the message send to the method's return type}}
[x foo];
@@ -10,8 +24,20 @@ namespace test0 {
// rdar://10988847
@class NSString; // expected-note {{forward declaration of class here}}
-namespace test1 {
- void rdar10988847() {
+namespace rdar10988847 {
+ void test() {
id s = [NSString stringWithUTF8String:"foo"]; // expected-warning {{receiver 'NSString' is a forward class and corresponding @interface may not exist}}
}
}
+
+// rdar://13338107
+namespace rdar13338107 {
+ void test() {
+ id x1 = test0a;
+ id x2 = test1a();
+ A *x3 = test0b;
+ A *x4 = test1b();
+ auto x5 = test0c;
+ auto x6 = test1c();
+ }
+}
diff --git a/test/SemaObjCXX/instancetype.mm b/test/SemaObjCXX/instancetype.mm
new file mode 100644
index 0000000..bbf100e
--- /dev/null
+++ b/test/SemaObjCXX/instancetype.mm
@@ -0,0 +1,216 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+#if !__has_feature(objc_instancetype)
+# error Missing 'instancetype' feature macro.
+#endif
+
+@interface Root
++ (instancetype)alloc;
+- (instancetype)init; // expected-note{{overridden method is part of the 'init' method family}}
+- (instancetype)self; // expected-note {{explicitly declared 'instancetype'}}
+- (Class)class;
+
+@property (assign) Root *selfProp;
+- (instancetype)selfProp;
+@end
+
+@protocol Proto1
+@optional
+- (instancetype)methodInProto1;
+@end
+
+@protocol Proto2
+@optional
+- (instancetype)methodInProto2; // expected-note{{overridden method returns an instance of its class type}}
+- (instancetype)otherMethodInProto2; // expected-note{{overridden method returns an instance of its class type}}
+@end
+
+@interface Subclass1 : Root
+- (instancetype)initSubclass1;
+- (void)methodOnSubclass1;
++ (instancetype)allocSubclass1;
+@end
+
+@interface Subclass2 : Root
+- (instancetype)initSubclass2;
+- (void)methodOnSubclass2;
+@end
+
+// Sanity check: the basic initialization pattern.
+void test_instancetype_alloc_init_simple() {
+ Root *r1 = [[Root alloc] init];
+ Subclass1 *sc1 = [[Subclass1 alloc] init];
+}
+
+// Test that message sends to instancetype methods have the right type.
+void test_instancetype_narrow_method_search() {
+ // instancetype on class methods
+ Subclass1 *sc1 = [[Subclass1 alloc] initSubclass2]; // expected-warning{{'Subclass1' may not respond to 'initSubclass2'}}
+ Subclass2 *sc2 = [[Subclass2 alloc] initSubclass2]; // okay
+
+ // instancetype on instance methods
+ [[[Subclass1 alloc] init] methodOnSubclass2]; // expected-warning{{'Subclass1' may not respond to 'methodOnSubclass2'}}
+ [[[Subclass2 alloc] init] methodOnSubclass2];
+
+ // instancetype on class methods using protocols
+ typedef Subclass1<Proto1> SC1Proto1;
+ typedef Subclass1<Proto2> SC1Proto2;
+ [[SC1Proto1 alloc] methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}}
+ [[SC1Proto2 alloc] methodInProto2];
+
+ // instancetype on instance methods
+ Subclass1<Proto1> *sc1proto1 = 0;
+ [[sc1proto1 self] methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}}
+ Subclass1<Proto2> *sc1proto2 = 0;
+ [[sc1proto2 self] methodInProto2];
+
+ // Exact type checks
+ typeof([[Subclass1 alloc] init]) *ptr1 = (Subclass1 **)0;
+ typeof([[Subclass2 alloc] init]) *ptr2 = (Subclass2 **)0;
+
+ // Message sends to Class.
+ Subclass1<Proto1> *sc1proto1_2 = [[[sc1proto1 class] alloc] init];
+
+ // Property access
+ [sc1proto1.self methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}}
+ [sc1proto2.self methodInProto2];
+ [Subclass1.alloc initSubclass2]; // expected-warning{{'Subclass1' may not respond to 'initSubclass2'}}
+ [Subclass2.alloc initSubclass2];
+
+ [sc1proto1.selfProp methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}}
+ [sc1proto2.selfProp methodInProto2];
+}
+
+// Test that message sends to super methods have the right type.
+@interface Subsubclass1 : Subclass1
+- (instancetype)initSubclass1;
++ (instancetype)allocSubclass1;
+
+- (void)onlyInSubsubclass1;
+@end
+
+@implementation Subsubclass1
+- (instancetype)initSubclass1 {
+ // Check based on method search.
+ [[super initSubclass1] methodOnSubclass2]; // expected-warning{{'Subsubclass1' may not respond to 'methodOnSubclass2'}}
+ [super.initSubclass1 methodOnSubclass2]; // expected-warning{{'Subsubclass1' may not respond to 'methodOnSubclass2'}}
+
+ self = [super init]; // common pattern
+
+ // Exact type check.
+ typeof([super initSubclass1]) *ptr1 = (Subsubclass1**)0;
+
+ return self;
+}
+
++ (instancetype)allocSubclass1 {
+ // Check based on method search.
+ [[super allocSubclass1] methodOnSubclass2]; // expected-warning{{'Subsubclass1' may not respond to 'methodOnSubclass2'}}
+
+ // The ASTs don't model super property accesses well enough to get this right
+ [super.allocSubclass1 methodOnSubclass2]; // expected-warning{{'Subsubclass1' may not respond to 'methodOnSubclass2'}}
+
+ // Exact type check.
+ typeof([super allocSubclass1]) *ptr1 = (Subsubclass1**)0;
+
+ return [super allocSubclass1];
+}
+
+- (void)onlyInSubsubclass1 {}
+@end
+
+// Check compatibility rules for inheritance of related return types.
+@class Subclass4;
+
+@interface Subclass3 <Proto1, Proto2>
+- (Subclass3 *)methodInProto1;
+- (Subclass4 *)methodInProto2; // expected-warning{{method is expected to return an instance of its class type 'Subclass3', but is declared to return 'Subclass4 *'}}
+@end
+
+@interface Subclass4 : Root
++ (Subclass4 *)alloc; // okay
+- (Subclass3 *)init; // expected-warning{{method is expected to return an instance of its class type 'Subclass4', but is declared to return 'Subclass3 *'}}
+- (id)self; // expected-note{{overridden method is part of the 'self' method family}}
+- (instancetype)initOther;
+@end
+
+@protocol Proto3 <Proto1, Proto2>
+@optional
+- (id)methodInProto1;
+- (Subclass1 *)methodInProto2;
+- (int)otherMethodInProto2; // expected-warning{{protocol method is expected to return an instance of the implementing class, but is declared to return 'int'}}
+@end
+
+@implementation Subclass4
++ (id)alloc {
+ return self; // FIXME: we accept this in ObjC++ but not ObjC?
+}
+
+- (Subclass3 *)init { return 0; } // don't complain: we lost the related return type
+
+- (Subclass3 *)self { return 0; } // expected-warning{{method is expected to return an instance of its class type 'Subclass4', but is declared to return 'Subclass3 *'}}
+
+- (Subclass4 *)initOther { return 0; }
+
+@end
+
+// Check that inherited related return types influence the types of
+// message sends.
+void test_instancetype_inherited() {
+ [[Subclass4 alloc] initSubclass1]; // expected-warning{{'Subclass4' may not respond to 'initSubclass1'}}
+ [[Subclass4 alloc] initOther];
+}
+
+// Check that related return types tighten up the semantics of
+// Objective-C method implementations.
+@implementation Subclass2
+- (instancetype)initSubclass2 { // expected-note {{explicitly declared 'instancetype'}}
+ Subclass1 *sc1 = [[Subclass1 alloc] init];
+ return sc1; // expected-error{{cannot initialize return object of type 'Subclass2 *' with an lvalue of type 'Subclass1 *'}}
+}
+- (void)methodOnSubclass2 {}
+- (id)self {
+ Subclass1 *sc1 = [[Subclass1 alloc] init];
+ return sc1; // expected-error{{cannot initialize return object of type 'Subclass2 *' with an lvalue of type 'Subclass1 *'}}
+}
+@end
+
+@interface MyClass : Root
++ (int)myClassMethod;
+@end
+
+@implementation MyClass
++ (int)myClassMethod { return 0; }
+
+- (void)blah {
+ int i = [[MyClass self] myClassMethod];
+}
+
+@end
+
+// rdar://12493140
+@protocol P4
+- (instancetype) foo; // expected-note {{current method is explicitly declared 'instancetype' and is expected to return an instance of its class type}}
+@end
+@interface A4 : Root <P4>
+- (instancetype) bar; // expected-note {{current method is explicitly declared 'instancetype' and is expected to return an instance of its class type}}
+- (instancetype) baz; // expected-note {{overridden method returns an instance of its class type}} expected-note {{previous definition is here}}
+@end
+@interface B4 : Root @end
+
+@implementation A4 {
+ B4 *_b;
+}
+- (id) foo {
+ return _b; // expected-error {{cannot initialize return object of type 'A4 *' with an lvalue of type 'B4 *'}}
+}
+- (id) bar {
+ return _b; // expected-error {{cannot initialize return object of type 'A4 *' with an lvalue of type 'B4 *'}}
+}
+
+// This is really just to ensure that we don't crash.
+// FIXME: only one diagnostic, please
+- (float) baz { // expected-warning {{method is expected to return an instance of its class type 'A4', but is declared to return 'float'}} expected-warning {{conflicting return type in implementation}}
+ return 0;
+}
+@end
diff --git a/test/SemaObjCXX/instantiate-expr.mm b/test/SemaObjCXX/instantiate-expr.mm
index 75a5b7e..e9d296d 100644
--- a/test/SemaObjCXX/instantiate-expr.mm
+++ b/test/SemaObjCXX/instantiate-expr.mm
@@ -21,7 +21,7 @@ void f(U value, V value2) {
get_an_A(N)->ivar = value; // expected-error{{assigning to 'int' from incompatible type 'int *'}}
get_an_A(N).prop = value2; // expected-error{{assigning to 'int' from incompatible type 'double *'}}
T c = get_an_id(N)->isa; // expected-error{{cannot initialize a variable of type 'int' with an lvalue of type 'Class'}} \
- // expected-warning 5 {{direct access to objective-c's isa is deprecated in favor of object_setClass() and object_getClass()}}
+ // expected-warning 3 {{direct access to Objective-C's isa is deprecated in favor of object_getClass()}}
}
template void f<6, Class>(int, int); // expected-note{{in instantiation of}}
@@ -46,7 +46,7 @@ template void f2(A*, int, double*); // expected-note{{instantiation of}}
template<typename T, typename U>
void f3(U ptr) {
T c = ptr->isa; // expected-error{{cannot initialize a variable of type 'int' with an lvalue of type 'Class'}} \
- // expected-warning 2 {{direct access to objective-c's isa is deprecated in favor of object_setClass() and object_getClass()}}
+ // expected-warning 1 {{direct access to Objective-C's isa is deprecated in favor of object_getClass()}}
}
template void f3<Class>(id); // expected-note{{in instantiation of}}
diff --git a/test/SemaObjCXX/parameters.mm b/test/SemaObjCXX/parameters.mm
index 1a7869d..363675a 100644
--- a/test/SemaObjCXX/parameters.mm
+++ b/test/SemaObjCXX/parameters.mm
@@ -15,3 +15,6 @@ struct test2 { virtual void foo() = 0; }; // expected-note {{unimplemented}}
@interface Test2
- (void) foo: (test2) foo; // expected-error {{parameter type 'test2' is an abstract class}}
@end
+
+template<typename T> void r1(__restrict T);
+void r2(__restrict id x) { r1(x); }
diff --git a/test/SemaObjCXX/properties.mm b/test/SemaObjCXX/properties.mm
index 0783eeb..abd4db9 100644
--- a/test/SemaObjCXX/properties.mm
+++ b/test/SemaObjCXX/properties.mm
@@ -28,7 +28,7 @@ struct X {
- (int) z;
@end
void test2(Test2 *a) {
- auto y = a.y; // expected-error {{expected getter method not found on object of type 'Test2 *'}}
+ auto y = a.y; // expected-error {{no getter method for read from property}}
auto z = a.z;
}
@@ -129,3 +129,38 @@ extern void* VoidType;
extern decltype(TestNonTrivialObj.p1 = NonTrivial1())* VoidType;
extern decltype(TestNonTrivialObj.p2 = NonTrivial2())* VoidType;
+// rdar://13332183
+namespace test9 {
+ struct CString {
+ const char *_data;
+ char operator[](int i) const { return _data[i]; }
+ };
+}
+@interface Test9
+@property test9::CString name;
+@end
+namespace test9 {
+ char test(Test9 *t) {
+ return t.name[0];
+ }
+}
+
+namespace test10 {
+ struct A { operator const char*(); };
+ struct B { operator const char*(); };
+}
+@interface Test10
+@property test10::A a;
+@property test10::B b;
+@property int index;
+@end
+namespace test10 {
+ void test(Test10 *t) {
+ (void) t.a[6];
+ (void) 6[t.b];
+ (void) "help"[t.index];
+ (void) t.index["help"];
+ (void) t.a[t.index];
+ (void) t.index[t.b];
+ }
+}
diff --git a/test/SemaObjCXX/unknown-anytype.mm b/test/SemaObjCXX/unknown-anytype.mm
index b28b135..e89dee1 100644
--- a/test/SemaObjCXX/unknown-anytype.mm
+++ b/test/SemaObjCXX/unknown-anytype.mm
@@ -7,3 +7,48 @@ namespace test0 {
[x foo]; // expected-error {{no known method '-foo'; cast the message send to the method's return type}}
}
}
+
+// rdar://problem/12565338
+@interface Test1
+- (void) test_a: (__unknown_anytype)foo;
+- (void) test_b: (__unknown_anytype)foo;
+- (void) test_c: (__unknown_anytype)foo;
+@end
+namespace test1 {
+ struct POD {
+ int x;
+ };
+
+ void a(Test1 *obj) {
+ POD v;
+ [obj test_a: v];
+ }
+
+ struct Uncopyable {
+ Uncopyable();
+ private:
+ Uncopyable(const Uncopyable &); // expected-note {{declared private here}}
+ };
+
+ void b(Test1 *obj) {
+ Uncopyable v;
+ [obj test_b: v]; // expected-error {{calling a private constructor}}
+ }
+
+ void c(Test1 *obj) {
+ Uncopyable v;
+ [obj test_c: (const Uncopyable&) v];
+ }
+}
+
+// Just test that we can declare a function taking __unknown_anytype.
+// For now, we don't actually need to make calling something like this
+// work; if that changes, here's what's required:
+// - get this call through overload resolution somehow,
+// - update the function-call argument-passing code like the
+// message-send code, and
+// - rewrite the function expression to have a type that doesn't
+// involving __unknown_anytype.
+namespace test2 {
+ void foo(__unknown_anytype x);
+}
diff --git a/test/SemaOpenCL/endian-attr.cl b/test/SemaOpenCL/endian-attr.cl
new file mode 100644
index 0000000..e851cdf
--- /dev/null
+++ b/test/SemaOpenCL/endian-attr.cl
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -verify %s
+
+constant long a __attribute__((endian(host))) = 100;
+
+constant long b __attribute__((endian(device))) = 100;
+
+constant long c __attribute__((endian(none))) = 100; // expected-warning {{unknown endian 'none'}}
+
+void func() __attribute__((endian(host))); // expected-warning {{endian attribute only applies to variables}}
diff --git a/test/SemaOpenCL/event_t.cl b/test/SemaOpenCL/event_t.cl
new file mode 100644
index 0000000..57a0981
--- /dev/null
+++ b/test/SemaOpenCL/event_t.cl
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
+
+event_t glb_evt; // expected-error {{the event_t type cannot be used to declare a program scope variable}}
+
+struct evt_s {
+ event_t evt; // expected-error {{the event_t type cannot be used to declare a structure or union field}}
+} evt_str;
+
+void foo(event_t evt); // expected-note {{passing argument to parameter 'evt' here}}
+
+void kernel ker(event_t argevt) { // expected-error {{the event_t type cannot be used to declare a kernel function argument}}
+ event_t e;
+ constant event_t const_evt; // expected-error {{the event_t type can only be used with __private address space qualifier}}
+ foo(e);
+ foo(0);
+ foo(5); // expected-error {{passing 'int' to parameter of incompatible type 'event_t'}}
+}
diff --git a/test/SemaOpenCL/event_t_overload.cl b/test/SemaOpenCL/event_t_overload.cl
new file mode 100644
index 0000000..bc3ec44
--- /dev/null
+++ b/test/SemaOpenCL/event_t_overload.cl
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
+
+void __attribute__((overloadable)) foo(event_t, __local char *); // expected-note {{candidate function not viable: no known conversion from '__global int *' to '__local char *' for 2nd argument}}
+void __attribute__((overloadable)) foo(event_t, __local float *); // expected-note {{candidate function not viable: no known conversion from '__global int *' to '__local float *' for 2nd argument}}
+
+void kernel ker(__local char *src1, __local float *src2, __global int *src3) {
+ event_t evt;
+ foo(evt, src1);
+ foo(0, src2);
+ foo(evt, src3); // expected-error {{no matching function for call to 'foo'}}
+}
diff --git a/test/SemaOpenCL/half.cl b/test/SemaOpenCL/half.cl
new file mode 100644
index 0000000..0e6acb7
--- /dev/null
+++ b/test/SemaOpenCL/half.cl
@@ -0,0 +1,40 @@
+// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -Wno-unused-value
+
+#pragma OPENCL EXTENSION cl_khr_fp16 : disable
+
+half half_disabled(half *p, // expected-error{{declaring function return value of type 'half' is not allowed}}
+ half h) // expected-error{{declaring function argument of type 'half' is not allowed}}
+{
+ half a[2]; // expected-error{{declaring variable of type 'half [2]' is not allowed}}
+ half b; // expected-error{{declaring variable of type 'half' is not allowed}}
+ *p; // expected-error{{loading directly from pointer to type 'half' is not allowed}}
+ p[1]; // expected-error{{loading directly from pointer to type 'half' is not allowed}}
+
+ float c = 1.0f;
+ b = (half) c; // expected-error{{casting to type 'half' is not allowed}}
+
+ half *allowed = &p[1];
+ half *allowed2 = &*p;
+ half *allowed3 = p + 1;
+
+ return h;
+}
+
+// Exactly the same as above but with the cl_khr_fp16 extension enabled.
+#pragma OPENCL EXTENSION cl_khr_fp16 : enable
+half half_enabled(half *p, half h)
+{
+ half a[2];
+ half b;
+ *p;
+ p[1];
+
+ float c = 1.0f;
+ b = (half) c;
+
+ half *allowed = &p[1];
+ half *allowed2 = &*p;
+ half *allowed3 = p + 1;
+
+ return h;
+}
diff --git a/test/SemaOpenCL/invalid-kernel-attrs.cl b/test/SemaOpenCL/invalid-kernel-attrs.cl
new file mode 100644
index 0000000..d242eaf
--- /dev/null
+++ b/test/SemaOpenCL/invalid-kernel-attrs.cl
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -verify %s
+
+kernel __attribute__((vec_type_hint)) void kernel1() {} //expected-error{{attribute takes one argument}}
+
+kernel __attribute__((vec_type_hint(not_type))) void kernel2() {} //expected-error{{unknown type name 'not_type'}}
+
+kernel __attribute__((vec_type_hint(void))) void kernel3() {} //expected-error{{invalid attribute argument 'void' - expecting a vector or vectorizable scalar type}}
+
+kernel __attribute__((vec_type_hint(bool))) void kernel4() {} //expected-error{{invalid attribute argument 'bool' - expecting a vector or vectorizable scalar type}}
+
+kernel __attribute__((vec_type_hint(int))) __attribute__((vec_type_hint(float))) void kernel5() {} //expected-warning{{attribute 'vec_type_hint' is already applied with different parameters}}
+
+kernel __attribute__((work_group_size_hint(8,16,32,4))) void kernel6() {} //expected-error{{attribute requires exactly 3 arguments}}
+
+kernel __attribute__((work_group_size_hint(1,2,3))) __attribute__((work_group_size_hint(3,2,1))) void kernel7() {} //expected-warning{{attribute 'work_group_size_hint' is already applied with different parameters}}
+
diff --git a/test/SemaOpenCL/invalid-kernel.cl b/test/SemaOpenCL/invalid-kernel.cl
new file mode 100644
index 0000000..fb8ce58
--- /dev/null
+++ b/test/SemaOpenCL/invalid-kernel.cl
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -verify %s
+
+kernel void no_ptrptr(global int **i) { } // expected-error{{kernel argument cannot be declared as a pointer to a pointer}}
+
+kernel int bar() { // expected-error {{kernel must have void return type}}
+ return 6;
+}
diff --git a/test/SemaOpenCL/invalid-logical-ops-1.1.cl b/test/SemaOpenCL/invalid-logical-ops-1.1.cl
new file mode 100644
index 0000000..2269dd3
--- /dev/null
+++ b/test/SemaOpenCL/invalid-logical-ops-1.1.cl
@@ -0,0 +1,57 @@
+// RUN: %clang_cc1 %s -verify -cl-std=CL1.1 -triple x86_64-unknown-linux-gnu
+
+#pragma OPENCL EXTENSION cl_khr_fp64 : enable
+typedef __attribute__((ext_vector_type(4))) float float4;
+typedef __attribute__((ext_vector_type(4))) double double4;
+typedef __attribute__((ext_vector_type(4))) int int4;
+typedef __attribute__((ext_vector_type(4))) long long4;
+
+kernel void float_ops() {
+ int flaf = 0.0f && 0.0f; // expected-error {{invalid operands}}
+ int flof = 0.0f || 0.0f; // expected-error {{invalid operands}}
+ float fbaf = 0.0f & 0.0f; // expected-error {{invalid operands}}
+ float fbof = 0.0f | 0.0f; // expected-error {{invalid operands}}
+ float fbxf = 0.0f ^ 0.0f; // expected-error {{invalid operands}}
+ int flai = 0.0f && 0; // expected-error {{invalid operands}}
+ int floi = 0.0f || 0; // expected-error {{invalid operands}}
+ float ibaf = 0 & 0.0f; // expected-error {{invalid operands}}
+ float ibof = 0 | 0.0f; // expected-error {{invalid operands}}
+ float bnf = ~0.0f; // expected-error {{invalid argument type}}
+ float lnf = !0.0f; // expected-error {{invalid argument type}}
+}
+
+kernel void vec_float_ops() {
+ float4 f4 = (float4)(0, 0, 0, 0);
+ int4 f4laf = f4 && 0.0f; // expected-error {{invalid operands}}
+ int4 f4lof = f4 || 0.0f; // expected-error {{invalid operands}}
+ float4 f4baf = f4 & 0.0f; // expected-error {{invalid operands}}
+ float4 f4bof = f4 | 0.0f; // expected-error {{invalid operands}}
+ float4 f4bxf = f4 ^ 0.0f; // expected-error {{invalid operands}}
+ float bnf4 = ~f4; // expected-error {{invalid argument type}}
+ int4 lnf4 = !f4; // expected-error {{invalid argument type}}
+}
+
+kernel void double_ops() {
+ int flaf = 0.0 && 0.0; // expected-error {{invalid operands}}
+ int flof = 0.0 || 0.0; // expected-error {{invalid operands}}
+ double fbaf = 0.0 & 0.0; // expected-error {{invalid operands}}
+ double fbof = 0.0 | 0.0; // expected-error {{invalid operands}}
+ double fbxf = 0.0 ^ 0.0; // expected-error {{invalid operands}}
+ int flai = 0.0 && 0; // expected-error {{invalid operands}}
+ int floi = 0.0 || 0; // expected-error {{invalid operands}}
+ double ibaf = 0 & 0.0; // expected-error {{invalid operands}}
+ double ibof = 0 | 0.0; // expected-error {{invalid operands}}
+ double bnf = ~0.0; // expected-error {{invalid argument type}}
+ double lnf = !0.0; // expected-error {{invalid argument type}}
+}
+
+kernel void vec_double_ops() {
+ double4 f4 = (double4)(0, 0, 0, 0);
+ long4 f4laf = f4 && 0.0; // expected-error {{invalid operands}}
+ long4 f4lof = f4 || 0.0; // expected-error {{invalid operands}}
+ double4 f4baf = f4 & 0.0; // expected-error {{invalid operands}}
+ double4 f4bof = f4 | 0.0; // expected-error {{invalid operands}}
+ double4 f4bxf = f4 ^ 0.0; // expected-error {{invalid operands}}
+ double bnf4 = ~f4; // expected-error {{invalid argument type}}
+ long4 lnf4 = !f4; // expected-error {{invalid argument type}}
+}
diff --git a/test/SemaOpenCL/invalid-logical-ops-1.2.cl b/test/SemaOpenCL/invalid-logical-ops-1.2.cl
new file mode 100644
index 0000000..7ba1adb
--- /dev/null
+++ b/test/SemaOpenCL/invalid-logical-ops-1.2.cl
@@ -0,0 +1,57 @@
+// RUN: %clang_cc1 %s -verify -cl-std=CL1.2 -triple x86_64-unknown-linux-gnu
+
+#pragma OPENCL EXTENSION cl_khr_fp64 : enable
+typedef __attribute__((ext_vector_type(4))) float float4;
+typedef __attribute__((ext_vector_type(4))) double double4;
+typedef __attribute__((ext_vector_type(4))) int int4;
+typedef __attribute__((ext_vector_type(4))) long long4;
+
+kernel void float_ops() {
+ int flaf = 0.0f && 0.0f;
+ int flof = 0.0f || 0.0f;
+ float fbaf = 0.0f & 0.0f; // expected-error {{invalid operands}}
+ float fbof = 0.0f | 0.0f; // expected-error {{invalid operands}}
+ float fbxf = 0.0f ^ 0.0f; // expected-error {{invalid operands}}
+ int flai = 0.0f && 0;
+ int floi = 0.0f || 0;
+ float ibaf = 0 & 0.0f; // expected-error {{invalid operands}}
+ float ibof = 0 | 0.0f; // expected-error {{invalid operands}}
+ float bnf = ~0.0f;// expected-error {{invalid argument type}}
+ float lnf = !0.0f;
+}
+
+kernel void vec_float_ops() {
+ float4 f4 = (float4)(0, 0, 0, 0);
+ int4 f4laf = f4 && 0.0f;
+ int4 f4lof = f4 || 0.0f;
+ float4 f4baf = f4 & 0.0f; // expected-error {{invalid operands}}
+ float4 f4bof = f4 | 0.0f; // expected-error {{invalid operands}}
+ float4 f4bxf = f4 ^ 0.0f; // expected-error {{invalid operands}}
+ float bnf4 = ~f4; // expected-error {{invalid argument type}}
+ int4 lnf4 = !f4;
+}
+
+kernel void double_ops() {
+ int flaf = 0.0 && 0.0;
+ int flof = 0.0 || 0.0;
+ double fbaf = 0.0 & 0.0; // expected-error {{invalid operands}}
+ double fbof = 0.0 | 0.0; // expected-error {{invalid operands}}
+ double fbxf = 0.0 ^ 0.0; // expected-error {{invalid operands}}
+ int flai = 0.0 && 0;
+ int floi = 0.0 || 0;
+ double ibaf = 0 & 0.0; // expected-error {{invalid operands}}
+ double ibof = 0 | 0.0; // expected-error {{invalid operands}}
+ double bnf = ~0.0; // expected-error {{invalid argument type}}
+ double lnf = !0.0;
+}
+
+kernel void vec_double_ops() {
+ double4 f4 = (double4)(0, 0, 0, 0);
+ long4 f4laf = f4 && 0.0;
+ long4 f4lof = f4 || 0.0;
+ double4 f4baf = f4 & 0.0; // expected-error {{invalid operands}}
+ double4 f4bof = f4 | 0.0; // expected-error {{invalid operands}}
+ double4 f4bxf = f4 ^ 0.0; // expected-error {{invalid operands}}
+ double bnf4 = ~f4; // expected-error {{invalid argument type}}
+ long4 lnf4 = !f4;
+}
diff --git a/test/SemaOpenCL/sampler_t.cl b/test/SemaOpenCL/sampler_t.cl
new file mode 100644
index 0000000..96f6dbf
--- /dev/null
+++ b/test/SemaOpenCL/sampler_t.cl
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only
+
+constant sampler_t glb_smp = 5;
+
+void foo(sampler_t);
+
+void kernel ker(sampler_t argsmp) {
+ local sampler_t smp; // expected-error {{sampler type cannot be used with the __local and __global address space qualifiers}}
+ const sampler_t const_smp = 7;
+ foo(glb_smp);
+ foo(const_smp);
+ foo(5); // expected-error {{sampler_t variable required - got 'int'}}
+}
diff --git a/test/SemaOpenCL/sampler_t_overload.cl b/test/SemaOpenCL/sampler_t_overload.cl
new file mode 100644
index 0000000..83a854f
--- /dev/null
+++ b/test/SemaOpenCL/sampler_t_overload.cl
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s
+
+void __attribute__((overloadable)) foo(sampler_t, read_only image1d_t);
+void __attribute__((overloadable)) foo(sampler_t, read_only image2d_t);
+
+constant sampler_t glb_smp = 5;
+
+void kernel ker(read_only image1d_t src1, read_only image2d_t src2) {
+ const sampler_t smp = 10;
+ foo(glb_smp, src1);
+ foo(smp, src2);
+}
diff --git a/test/SemaOpenCL/shifts.cl b/test/SemaOpenCL/shifts.cl
new file mode 100644
index 0000000..5b0c6fb
--- /dev/null
+++ b/test/SemaOpenCL/shifts.cl
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 -x cl -O0 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck %s
+// OpenCL essentially reduces all shift amounts to the last word-size bits before evaluating.
+// Test this both for variables and constants evaluated in the front-end.
+
+// CHECK: @gtest1 = constant i64 2147483648
+__constant const unsigned long gtest1 = 1UL << 31;
+
+// CHECK: @negativeShift32
+int negativeShift32(int a,int b) {
+ // CHECK: %array0 = alloca [256 x i8]
+ char array0[((int)1)<<40];
+ // CHECK: %array1 = alloca [256 x i8]
+ char array1[((int)1)<<(-24)];
+
+ // CHECK: ret i32 65536
+ return ((int)1)<<(-16);
+}
diff --git a/test/SemaOpenCL/storageclass.cl b/test/SemaOpenCL/storageclass.cl
index c78e7cd..fdfe134 100644
--- a/test/SemaOpenCL/storageclass.cl
+++ b/test/SemaOpenCL/storageclass.cl
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only -cl-std=CL1.2
-static int A;
+static constant int A = 0;
// static is not allowed at local scope.
void kernel foo() {
diff --git a/test/SemaOpenCL/unsupported.cl b/test/SemaOpenCL/unsupported.cl
new file mode 100644
index 0000000..bb9da4b
--- /dev/null
+++ b/test/SemaOpenCL/unsupported.cl
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -verify %s
+
+struct {
+ int a : 1; // expected-error {{bitfields are not supported in OpenCL}}
+};
+
+void no_vla(int n) {
+ int a[n]; // expected-error {{variable length arrays are not supported in OpenCL}}
+}
diff --git a/test/SemaTemplate/alignas.cpp b/test/SemaTemplate/alignas.cpp
new file mode 100644
index 0000000..8a1f96e
--- /dev/null
+++ b/test/SemaTemplate/alignas.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+// expected-no-diagnostics
+using size_t = decltype(sizeof(0));
+
+template<typename T, typename U>
+constexpr T max(T t, U u) { return t > u ? t : u; }
+
+template<typename T, typename ...Ts>
+constexpr auto max(T t, Ts ...ts) -> decltype(max(t, max(ts...))) {
+ return max(t, max(ts...));
+}
+
+template<typename...T> struct my_union {
+ alignas(T...) char buffer[max(sizeof(T)...)];
+};
+
+struct alignas(8) A { char c; };
+struct alignas(4) B { short s; };
+struct C { char a[16]; };
+
+static_assert(sizeof(my_union<A, B, C>) == 16, "");
+static_assert(alignof(my_union<A, B, C>) == 8, "");
diff --git a/test/SemaTemplate/class-template-id.cpp b/test/SemaTemplate/class-template-id.cpp
index b674537..5bbc70c 100644
--- a/test/SemaTemplate/class-template-id.cpp
+++ b/test/SemaTemplate/class-template-id.cpp
@@ -40,7 +40,7 @@ typedef N::C<float> c2;
// PR5655
template<typename T> struct Foo { }; // expected-note{{template is declared here}}
-void f(void) { Foo bar; } // expected-error{{use of class template Foo requires template arguments}}
+void f(void) { Foo bar; } // expected-error{{use of class template 'Foo' requires template arguments}}
// rdar://problem/8254267
template <typename T> class Party;
diff --git a/test/SemaTemplate/default-expr-arguments-2.cpp b/test/SemaTemplate/default-expr-arguments-2.cpp
index 378999d..0379494 100644
--- a/test/SemaTemplate/default-expr-arguments-2.cpp
+++ b/test/SemaTemplate/default-expr-arguments-2.cpp
@@ -10,9 +10,9 @@ namespace PR6733 {
bar(int x = kSomeConst) {}
};
- // CHECK: void f()
+ // CHECK: FunctionDecl{{.*}}f 'void (void)'
void f() {
- // CHECK: bar<int> tmp =
+ // CHECK: VarDecl{{.*}}tmp 'bar<int>'
// CHECK: CXXDefaultArgExpr{{.*}}'int'
bar<int> tmp;
}
diff --git a/test/SemaTemplate/default-expr-arguments.cpp b/test/SemaTemplate/default-expr-arguments.cpp
index 1eefa9f..14b072a 100644
--- a/test/SemaTemplate/default-expr-arguments.cpp
+++ b/test/SemaTemplate/default-expr-arguments.cpp
@@ -303,3 +303,22 @@ namespace PR12581 {
{
}
}
+
+namespace PR13758 {
+ template <typename T> struct move_from {
+ T invalid;
+ };
+ template <class K>
+ struct unordered_map {
+ explicit unordered_map(int n = 42);
+ unordered_map(move_from<K> other);
+ };
+ template<typename T>
+ void StripedHashTable() {
+ new unordered_map<void>();
+ new unordered_map<void>;
+ }
+ void tt() {
+ StripedHashTable<int>();
+ }
+}
diff --git a/test/SemaTemplate/dependent-names.cpp b/test/SemaTemplate/dependent-names.cpp
index efa4d28..eb75e69 100644
--- a/test/SemaTemplate/dependent-names.cpp
+++ b/test/SemaTemplate/dependent-names.cpp
@@ -346,3 +346,26 @@ namespace rdar12629723 {
virtual void foo() { }
};
}
+
+namespace test_reserved_identifiers {
+ template<typename A, typename B> void tempf(A a, B b) {
+ a + b; // expected-error{{call to function 'operator+' that is neither visible in the template definition nor found by argument-dependent lookup}}
+ }
+ namespace __gnu_cxx { struct X {}; }
+ namespace ns { struct Y {}; }
+ void operator+(__gnu_cxx::X, ns::Y); // expected-note{{or in namespace 'test_reserved_identifiers::ns'}}
+ void test() {
+ __gnu_cxx::X x;
+ ns::Y y;
+ tempf(x, y); // expected-note{{in instantiation of}}
+ }
+}
+
+// This test must live in the global namespace.
+struct PR14695_X {};
+// FIXME: This note is bogus; it is the using directive which would need to move
+// to prior to the call site to fix the problem.
+namespace PR14695_A { void PR14695_f(PR14695_X); } // expected-note {{'PR14695_f' should be declared prior to the call site or in the global namespace}}
+template<typename T> void PR14695_g(T t) { PR14695_f(t); } // expected-error {{call to function 'PR14695_f' that is neither visible in the template definition nor found by argument-dependent lookup}}
+using namespace PR14695_A;
+template void PR14695_g(PR14695_X); // expected-note{{requested here}}
diff --git a/test/SemaTemplate/derived.cpp b/test/SemaTemplate/derived.cpp
index 1fb9401..7b91f9a 100644
--- a/test/SemaTemplate/derived.cpp
+++ b/test/SemaTemplate/derived.cpp
@@ -10,3 +10,21 @@ void test() {
Foo2(vector2<int*>()); // expected-error{{no matching function for call to 'Foo2'}}
Foo(vector<int*>()); // expected-error{{no matching function for call to 'Foo'}}
}
+
+namespace rdar13267210 {
+ template < typename T > class A {
+ BaseTy; // expected-error{{C++ requires a type specifier for all declarations}}
+ };
+
+ template < typename T, int N > class C: A < T > {};
+
+ class B {
+ C<long, 16> ExternalDefinitions;
+ C<long, 64> &Record;
+
+ void AddSourceLocation(A<long> &R); // expected-note{{passing argument to parameter 'R' here}}
+ void AddTemplateKWAndArgsInfo() {
+ AddSourceLocation(Record); // expected-error{{non-const lvalue reference to type}}
+ }
+ };
+}
diff --git a/test/SemaTemplate/destructor-template.cpp b/test/SemaTemplate/destructor-template.cpp
index 07beda4..6806c24 100644
--- a/test/SemaTemplate/destructor-template.cpp
+++ b/test/SemaTemplate/destructor-template.cpp
@@ -57,3 +57,22 @@ namespace PR7904 {
};
Foo f;
}
+
+namespace rdar13140795 {
+ template <class T> class shared_ptr {};
+
+ template <typename T> struct Marshal {
+ static int gc();
+ };
+
+
+ template <typename T> int Marshal<T>::gc() {
+ shared_ptr<T> *x;
+ x->template shared_ptr<T>::~shared_ptr();
+ return 0;
+ }
+
+ void test() {
+ Marshal<int>::gc();
+ }
+}
diff --git a/test/SemaTemplate/example-dynarray.cpp b/test/SemaTemplate/example-dynarray.cpp
index 999521e..266d2d4 100644
--- a/test/SemaTemplate/example-dynarray.cpp
+++ b/test/SemaTemplate/example-dynarray.cpp
@@ -1,4 +1,5 @@
// RUN: %clangxx -emit-llvm -c -o - %s
+// XFAIL: hexagon
#include <stddef.h>
#include <stdlib.h>
#include <assert.h>
diff --git a/test/SemaTemplate/friend-template.cpp b/test/SemaTemplate/friend-template.cpp
index 9acbfdc..8a47877 100644
--- a/test/SemaTemplate/friend-template.cpp
+++ b/test/SemaTemplate/friend-template.cpp
@@ -302,3 +302,23 @@ namespace PR12585 {
H<int> h1; // ok
H<char> h2; // expected-note {{instantiation}}
}
+
+// Ensure that we can still instantiate a friend function template
+// after the friend declaration is instantiated during the delayed
+// parsing of a member function, but before the friend function has
+// been parsed.
+namespace rdar12350696 {
+ template <class T> struct A {
+ void foo() {
+ A<int> a;
+ }
+ template <class U> friend void foo(const A<U> & a) {
+ int array[sizeof(T) == sizeof(U) ? -1 : 1]; // expected-error {{negative size}}
+ }
+ };
+
+ void test() {
+ A<int> b;
+ foo(b); // expected-note {{in instantiation}}
+ }
+}
diff --git a/test/SemaTemplate/fun-template-def.cpp b/test/SemaTemplate/fun-template-def.cpp
index 0427781..2d515b4 100644
--- a/test/SemaTemplate/fun-template-def.cpp
+++ b/test/SemaTemplate/fun-template-def.cpp
@@ -46,3 +46,11 @@ T f1(T t1, U u1, int i1)
return u1;
}
+
+template<typename T>
+void f2(__restrict T x) {} // expected-note {{substitution failure [with T = int]: restrict requires a pointer or reference ('int' is invalid}}
+
+void f3() {
+ f2<int*>(0);
+ f2<int>(0); // expected-error {{no matching function for call to 'f2'}}
+}
diff --git a/test/SemaTemplate/instantiate-init.cpp b/test/SemaTemplate/instantiate-init.cpp
index 612a0b7..6a1a57c 100644
--- a/test/SemaTemplate/instantiate-init.cpp
+++ b/test/SemaTemplate/instantiate-init.cpp
@@ -78,7 +78,7 @@ namespace PR7985 {
template<int N> struct integral_c { };
template <typename T, int N>
- integral_c<N> array_lengthof(T (&x)[N]) { return integral_c<N>(); } // expected-note 2{{candidate template ignored: failed template argument deduction}}
+ integral_c<N> array_lengthof(T (&x)[N]) { return integral_c<N>(); } // expected-note 2{{candidate template ignored: could not match 'T [N]' against 'const Data<}}
template<typename T>
struct Data {
@@ -94,7 +94,7 @@ namespace PR7985 {
const Data<T> Description<T>::data[] = {{ 1 }}; // expected-error{{cannot initialize a member subobject of type 'int *' with an rvalue of type 'int'}}
template<>
- Data<float*> Description<float*>::data[];
+ const Data<float*> Description<float*>::data[];
void test() {
integral_c<1> ic1 = array_lengthof(Description<int>::data);
diff --git a/test/SemaTemplate/instantiate-member-initializers.cpp b/test/SemaTemplate/instantiate-member-initializers.cpp
index 45503b3..6386206 100644
--- a/test/SemaTemplate/instantiate-member-initializers.cpp
+++ b/test/SemaTemplate/instantiate-member-initializers.cpp
@@ -25,3 +25,19 @@ public:
BB() : AA<T>(1) {}
};
BB<int> x;
+
+struct X {
+ X();
+};
+template<typename T>
+struct Y {
+ Y() : x() {}
+ X x;
+};
+Y<int> y;
+
+template<typename T> struct Array {
+ int a[3];
+ Array() : a() {}
+};
+Array<int> s;
diff --git a/test/SemaTemplate/instantiate-type.cpp b/test/SemaTemplate/instantiate-type.cpp
index f5d0270..2440a38 100644
--- a/test/SemaTemplate/instantiate-type.cpp
+++ b/test/SemaTemplate/instantiate-type.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
int* f(int);
float *f(...);
@@ -15,3 +15,14 @@ X<int>::typeof_type &iptr1 = iptr0;
X<int>::typeof_expr &iptr2 = iptr0;
X<float*>::typeof_expr &fptr1 = fptr0;
+
+namespace rdar13094134 {
+ template <class>
+ class X {
+ typedef struct {
+ Y *y; // expected-error{{unknown type name 'Y'}}
+ } Y;
+ };
+
+ X<int> xi;
+}
diff --git a/test/SemaTemplate/operator-template.cpp b/test/SemaTemplate/operator-template.cpp
index 777b0f5..30d6ccf 100644
--- a/test/SemaTemplate/operator-template.cpp
+++ b/test/SemaTemplate/operator-template.cpp
@@ -2,7 +2,7 @@
// Make sure we accept this
template<class X>struct A{typedef X Y;};
-template<class X>bool operator==(A<X>,typename A<X>::Y); // expected-note{{candidate template ignored: failed template argument deduction}}
+template<class X>bool operator==(A<X>,typename A<X>::Y); // expected-note{{candidate template ignored: could not match 'A<type-parameter-0-0>' against 'B<int> *'}}
int a(A<int> x) { return operator==(x,1); }
diff --git a/test/SemaTemplate/recursive-template-instantiation.cpp b/test/SemaTemplate/recursive-template-instantiation.cpp
index d6a0b24..fe37060 100644
--- a/test/SemaTemplate/recursive-template-instantiation.cpp
+++ b/test/SemaTemplate/recursive-template-instantiation.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
-template<typename T> void f(T* t) { // expected-note{{failed template argument deduction}}
+template<typename T> void f(T* t) { // expected-note{{could not match 'T *' against 'int'}}
f(*t); // expected-error{{no matching function}}\
// expected-note 3{{requested here}}
}
diff --git a/test/SemaTemplate/temp_arg.cpp b/test/SemaTemplate/temp_arg.cpp
index 5a4c8fc..052c19e 100644
--- a/test/SemaTemplate/temp_arg.cpp
+++ b/test/SemaTemplate/temp_arg.cpp
@@ -10,7 +10,7 @@ A<int, 0, X> * a1;
A<float, 1, X, double> *a2; // expected-error{{too many template arguments for class template 'A'}}
A<float, 1> *a3; // expected-error{{too few template arguments for class template 'A'}}
-A a3; // expected-error{{use of class template A requires template arguments}}
+A a3; // expected-error{{use of class template 'A' requires template arguments}}
namespace test0 {
template <class t> class foo {};
diff --git a/test/SemaTemplate/temp_arg_nontype.cpp b/test/SemaTemplate/temp_arg_nontype.cpp
index 747ddcc..210b5e4 100644
--- a/test/SemaTemplate/temp_arg_nontype.cpp
+++ b/test/SemaTemplate/temp_arg_nontype.cpp
@@ -3,7 +3,7 @@ template<int N> struct A; // expected-note 5{{template parameter is declared her
A<0> *a0;
-A<int()> *a1; // expected-error{{template argument for non-type template parameter is treated as type 'int ()'}}
+A<int()> *a1; // expected-error{{template argument for non-type template parameter is treated as function type 'int ()'}}
A<int> *a2; // expected-error{{template argument for non-type template parameter must be an expression}}
@@ -323,3 +323,17 @@ namespace PR10579 {
template <int& I> struct PR10766 { static int *ip; };
template <int& I> int* PR10766<I>::ip = &I;
+
+namespace rdar13000548 {
+ template<typename R, typename U, R F>
+ U f() { return &F; } // expected-error{{cannot take the address of an rvalue of type 'int (*)(int)'}} expected-error{{cannot take the address of an rvalue of type 'int *'}}
+
+ int g(int);
+ int y[3];
+ void test()
+ {
+ f<int(int), int (*)(int), g>(); // expected-note{{in instantiation of}}
+ f<int[3], int*, y>(); // expected-note{{in instantiation of}}
+ }
+
+}
diff --git a/test/SemaTemplate/temp_arg_nontype_cxx11.cpp b/test/SemaTemplate/temp_arg_nontype_cxx11.cpp
new file mode 100644
index 0000000..d773c64
--- /dev/null
+++ b/test/SemaTemplate/temp_arg_nontype_cxx11.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+namespace PR15360 {
+ template<typename R, typename U, R F>
+ U f() { return &F; } // expected-error{{cannot take the address of an rvalue of type 'int (*)(int)'}} expected-error{{cannot take the address of an rvalue of type 'int *'}}
+ void test() {
+ f<int(int), int(*)(int), nullptr>(); // expected-note{{in instantiation of}}
+ f<int[3], int*, nullptr>(); // expected-note{{in instantiation of}}
+ }
+}
diff --git a/test/SemaTemplate/temp_arg_type.cpp b/test/SemaTemplate/temp_arg_type.cpp
index 3970942..637b563 100644
--- a/test/SemaTemplate/temp_arg_type.cpp
+++ b/test/SemaTemplate/temp_arg_type.cpp
@@ -4,7 +4,7 @@ template<typename T> class A; // expected-note 2 {{template parameter is declare
// [temp.arg.type]p1
A<0> *a1; // expected-error{{template argument for template type parameter must be a type}}
-A<A> *a2; // expected-error{{use of class template A requires template arguments}}
+A<A> *a2; // expected-error{{use of class template 'A' requires template arguments}}
A<int> *a3;
A<int()> *a4;
@@ -19,7 +19,7 @@ A<function_tpl> a7; // expected-error{{template argument for template type para
namespace ns {
template<typename T> class B {}; // expected-note{{template is declared here}}
}
-A<ns::B> a8; // expected-error{{use of class template ns::B requires template arguments}}
+A<ns::B> a8; // expected-error{{use of class template 'ns::B' requires template arguments}}
// [temp.arg.type]p2
void f() {
diff --git a/test/TableGen/DiagnosticBase.inc b/test/TableGen/DiagnosticBase.inc
new file mode 100644
index 0000000..afa85f5
--- /dev/null
+++ b/test/TableGen/DiagnosticBase.inc
@@ -0,0 +1,35 @@
+// Define the diagnostic mappings.
+class DiagMapping;
+def MAP_IGNORE : DiagMapping;
+def MAP_WARNING : DiagMapping;
+def MAP_ERROR : DiagMapping;
+def MAP_FATAL : DiagMapping;
+
+// Define the diagnostic classes.
+class DiagClass;
+def CLASS_NOTE : DiagClass;
+def CLASS_WARNING : DiagClass;
+def CLASS_EXTENSION : DiagClass;
+def CLASS_ERROR : DiagClass;
+
+class DiagGroup<string Name, list<DiagGroup> subgroups = []> {
+ string GroupName = Name;
+ list<DiagGroup> SubGroups = subgroups;
+ string CategoryName = "";
+}
+class InGroup<DiagGroup G> { DiagGroup Group = G; }
+
+// All diagnostics emitted by the compiler are an indirect subclass of this.
+class Diagnostic<string text, DiagClass DC, DiagMapping defaultmapping> {
+ string Text = text;
+ DiagClass Class = DC;
+ DiagMapping DefaultMapping = defaultmapping;
+ DiagGroup Group;
+ string CategoryName = "";
+}
+
+class Error<string str> : Diagnostic<str, CLASS_ERROR, MAP_ERROR>;
+class Warning<string str> : Diagnostic<str, CLASS_WARNING, MAP_WARNING>;
+class Extension<string str> : Diagnostic<str, CLASS_EXTENSION, MAP_IGNORE>;
+class ExtWarn<string str> : Diagnostic<str, CLASS_EXTENSION, MAP_WARNING>;
+class Note<string str> : Diagnostic<str, CLASS_NOTE, MAP_FATAL/*ignored*/>;
diff --git a/test/TableGen/anonymous-groups.td b/test/TableGen/anonymous-groups.td
new file mode 100644
index 0000000..acc0a21
--- /dev/null
+++ b/test/TableGen/anonymous-groups.td
@@ -0,0 +1,42 @@
+// RUN: clang-tblgen -gen-clang-diag-groups -I%S %s -o /dev/null 2>&1 | FileCheck --strict-whitespace %s
+include "DiagnosticBase.inc"
+
+// Do not move this line; it is referred to by absolute line number in the
+// FileCheck lines below.
+def NamedGroup : DiagGroup<"name">;
+
+
+def InNamedGroup : Warning<"">, InGroup<DiagGroup<"name">>;
+// CHECK: anonymous-groups.td:[[@LINE-1]]:41: error: group 'name' is referred to anonymously
+// CHECK-NEXT: {{^def InNamedGroup : Warning<"">, InGroup<DiagGroup<"name">>;}}
+// CHECK-NEXT: {{^ ~~~~~~~~\^~~~~~~~~~~~~~~~~~}}
+// CHECK-NEXT: {{^ InGroup<NamedGroup>}}
+// CHECK-NEXT: anonymous-groups.td:6:1: note: group defined here
+// CHECK-NEXT: def NamedGroup : DiagGroup<"name">;
+// CHECK-NEXT: ^
+
+
+def AlsoInNamedGroup : Warning<"">, InGroup < DiagGroup<"name"> >;
+// CHECK: anonymous-groups.td:[[@LINE-1]]:48: error: group 'name' is referred to anonymously
+// CHECK-NEXT: {{^def AlsoInNamedGroup : Warning<"">, InGroup < DiagGroup<"name"> >;}}
+// CHECK-NEXT: {{^ ~~~~~~~~~~~\^~~~~~~~~~~~~~~~~~~}}
+// CHECK-NEXT: {{^ InGroup<NamedGroup>}}
+// CHECK-NEXT: anonymous-groups.td:6:1: note: group defined here
+// CHECK-NEXT: def NamedGroup : DiagGroup<"name">;
+// CHECK-NEXT: ^
+
+
+def AnonymousGroup : Warning<"">, InGroup<DiagGroup<"anonymous">>;
+def AlsoAnonymousGroup : Warning<"">, InGroup<DiagGroup<"anonymous">>;
+def AnonymousGroupAgain : Warning<"">,
+ InGroup<DiagGroup<"anonymous">>;
+
+// CHECK: anonymous-groups.td:[[@LINE-5]]:43: error: group 'anonymous' is referred to anonymously
+// CHECK-NEXT: {{^def AnonymousGroup : Warning<"">, InGroup<DiagGroup<"anonymous">>;}}
+// CHECK-NEXT: {{^ ~~~~~~~~\^~~~~~~~~~~~~~~~~~~~~~~}}
+// CHECK-NEXT: anonymous-groups.td:[[@LINE-7]]:47: note: also referenced here
+// CHECK-NEXT: {{^def AlsoAnonymousGroup : Warning<"">, InGroup<DiagGroup<"anonymous">>;}}
+// CHECK-NEXT: {{^ ~~~~~~~~\^~~~~~~~~~~~~~~~~~~~~~~}}
+// CHECK-NEXT: anonymous-groups.td:[[@LINE-8]]:11: note: also referenced here
+// CHECK-NEXT: {{^ InGroup<DiagGroup<"anonymous">>;}}
+// CHECK-NEXT: {{^ ~~~~~~~~\^~~~~~~~~~~~~~~~~~~~~~~}}
diff --git a/test/TableGen/lit.local.cfg b/test/TableGen/lit.local.cfg
new file mode 100644
index 0000000..9a4a014
--- /dev/null
+++ b/test/TableGen/lit.local.cfg
@@ -0,0 +1 @@
+config.suffixes = ['.td']
diff --git a/test/TableGen/tg-fixits.td b/test/TableGen/tg-fixits.td
new file mode 100644
index 0000000..d04a6a6
--- /dev/null
+++ b/test/TableGen/tg-fixits.td
@@ -0,0 +1,41 @@
+// RUN: clang-tblgen -gen-clang-diag-groups -I%S %s -o /dev/null 2>&1 | FileCheck --strict-whitespace %s
+include "DiagnosticBase.inc"
+
+def NamedGroup : DiagGroup<"name">;
+
+def InNamedGroup : Warning<"">, InGroup<DiagGroup<"name">>;
+// CHECK: tg-fixits.td:[[@LINE-1]]:41: error: group 'name' is referred to anonymously
+// CHECK-NEXT: {{^def InNamedGroup : Warning<"">, InGroup<DiagGroup<"name">>;}}
+// CHECK-NEXT: {{^ ~~~~~~~~\^~~~~~~~~~~~~~~~~~}}
+// CHECK-NEXT: {{^ InGroup<NamedGroup>}}
+
+def Wrapped : Warning<"">, InGroup<DiagGroup<
+ "name">>;
+// CHECK: tg-fixits.td:[[@LINE-2]]:36: error: group 'name' is referred to anonymously
+// CHECK-NEXT: {{^def Wrapped : Warning<"">, InGroup<DiagGroup<}}
+// CHECK-NEXT: {{^ ~~~~~~~~\^~~~~~~~~~}}
+// CHECK-NEXT: {{^ InGroup<NamedGroup>}}
+
+def AlsoWrapped : Warning<"">, InGroup<
+ DiagGroup<"name">>;
+// CHECK: tg-fixits.td:[[@LINE-1]]:3: error: group 'name' is referred to anonymously
+// CHECK-NEXT: {{^ DiagGroup<"name">>;}}
+// CHECK-NEXT: {{^~~\^~~~~~~~~~~~~~~~~~}}
+// CHECK-NEXT: {{^InGroup<NamedGroup>}}
+
+// The following lines contain hard tabs (\t); do not change this!
+def HardTabs : Warning<"">,
+ InGroup< DiagGroup<"name"> >;
+// CHECK: tg-fixits.td:[[@LINE-1]]:11: error: group 'name' is referred to anonymously
+// CHECK-NEXT: {{^ InGroup< DiagGroup<"name"> >;}}
+// CHECK-NEXT: {{^ ~~~~~~~~~~~~~~~~\^~~~~~~~~~~~~~~~~~~~~~~~~}}
+// CHECK-NEXT: {{^ InGroup<NamedGrop>}}
+
+// The following line has Unicode characters in it; do not change them!
+// FIXME: For now, we just give up on printing carets/ranges/fixits for
+// lines with Unicode in them, because SMDiagnostic don't keep a byte<->column
+// map around to line things up like Clang does.
+def Unicode : Warning<"ユニコード">, InGroup<DiagGroup<"name">>;
+// CHECK: tg-fixits.td:[[@LINE-1]]:51: error: group 'name' is referred to anonymously
+// CHECK-NEXT: def Unicode : Warning<"{{[^"]+}}">, InGroup<DiagGroup<"name">>;
+// CHECK-NEXT: note:
diff --git a/test/Tooling/auto-detect-from-source-parent-of-cwd.cpp b/test/Tooling/auto-detect-from-source-parent-of-cwd.cpp
index 9692edc..6b632b0 100644
--- a/test/Tooling/auto-detect-from-source-parent-of-cwd.cpp
+++ b/test/Tooling/auto-detect-from-source-parent-of-cwd.cpp
@@ -8,3 +8,5 @@
invalid;
// REQUIRES: shell
+// PR15590
+// XFAIL: win64
diff --git a/test/Tooling/auto-detect-from-source-parent.cpp b/test/Tooling/auto-detect-from-source-parent.cpp
index ea7eb15..f1dbc0f 100644
--- a/test/Tooling/auto-detect-from-source-parent.cpp
+++ b/test/Tooling/auto-detect-from-source-parent.cpp
@@ -8,3 +8,5 @@
invalid;
// REQUIRES: shell
+// PR15590
+// XFAIL: win64
diff --git a/test/Tooling/auto-detect-from-source.cpp b/test/Tooling/auto-detect-from-source.cpp
index d8e82e7..77e06e7 100644
--- a/test/Tooling/auto-detect-from-source.cpp
+++ b/test/Tooling/auto-detect-from-source.cpp
@@ -8,3 +8,5 @@
invalid;
// REQUIRES: shell
+// PR15590
+// XFAIL: win64
diff --git a/test/Tooling/clang-check-ast-dump.cpp b/test/Tooling/clang-check-ast-dump.cpp
index 43686bd..d8643c7 100644
--- a/test/Tooling/clang-check-ast-dump.cpp
+++ b/test/Tooling/clang-check-ast-dump.cpp
@@ -1,16 +1,21 @@
// RUN: clang-check -ast-dump "%s" -- 2>&1 | FileCheck %s
-// CHECK: namespace test_namespace
-// CHECK-NEXT: class TheClass
-// CHECK: int theMethod(int x) (CompoundStmt
-// CHECK-NEXT: (ReturnStmt
-// CHECK-NEXT: (BinaryOperator
+// CHECK: NamespaceDecl{{.*}}test_namespace
+// CHECK-NEXT: CXXRecordDecl{{.*}}TheClass
+// CHECK: CXXMethodDecl{{.*}}theMethod
+// CHECK-NEXT: ParmVarDecl{{.*}}x
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: ReturnStmt
+// CHECK-NEXT: BinaryOperator
//
// RUN: clang-check -ast-dump -ast-dump-filter test_namespace::TheClass::theMethod "%s" -- 2>&1 | FileCheck -check-prefix CHECK-FILTER %s
-// CHECK-FILTER-NOT: namespace test_namespace
-// CHECK-FILTER-NOT: class TheClass
-// CHECK-FILTER: int theMethod(int x) (CompoundStmt
-// CHECK-FILTER-NEXT: (ReturnStmt
-// CHECK-FILTER-NEXT: (BinaryOperator
+// CHECK-FILTER-NOT: NamespaceDecl
+// CHECK-FILTER-NOT: CXXRecordDecl
+// CHECK-FILTER: {{^}}Dumping test_namespace::TheClass::theMethod
+// CHECK-FILTER-NEXT: {{^}}CXXMethodDecl{{.*}}theMethod
+// CHECK-FILTER-NEXT: ParmVarDecl{{.*}}x
+// CHECK-FILTER-NEXT: CompoundStmt
+// CHECK-FILTER-NEXT: ReturnStmt
+// CHECK-FILTER-NEXT: BinaryOperator
//
// RUN: clang-check -ast-print "%s" -- 2>&1 | FileCheck -check-prefix CHECK-PRINT %s
// CHECK-PRINT: namespace test_namespace
@@ -25,7 +30,9 @@
//
// RUN: clang-check -ast-dump -ast-dump-filter test_namespace::TheClass::n "%s" -- 2>&1 | FileCheck -check-prefix CHECK-ATTR %s
// CHECK-ATTR: test_namespace
-// CHECK-ATTR-NEXT: int n __attribute__((aligned((BinaryOperator
+// CHECK-ATTR-NEXT: FieldDecl{{.*}}n
+// CHECK-ATTR-NEXT: AlignedAttr
+// CHECK-ATTR-NEXT: BinaryOperator
//
// RUN: clang-check -ast-dump -ast-dump-filter test_namespace::AfterNullNode "%s" -- 2>&1 | FileCheck -check-prefix CHECK-AFTER-NULL %s
// CHECK-AFTER-NULL: class AfterNullNode
diff --git a/test/Tooling/clang-check-autodetect-dir.cpp b/test/Tooling/clang-check-autodetect-dir.cpp
index 2c39504..39a0c38 100644
--- a/test/Tooling/clang-check-autodetect-dir.cpp
+++ b/test/Tooling/clang-check-autodetect-dir.cpp
@@ -9,3 +9,5 @@
invalid;
// REQUIRES: shell
+// PR15590
+// XFAIL: win64
diff --git a/test/Tooling/clang-check-pwd.cpp b/test/Tooling/clang-check-pwd.cpp
index 374c579..463ed40 100644
--- a/test/Tooling/clang-check-pwd.cpp
+++ b/test/Tooling/clang-check-pwd.cpp
@@ -9,3 +9,5 @@
invalid;
// REQUIRES: shell
+// PR15590
+// XFAIL: win64
diff --git a/test/Tooling/pch.cpp b/test/Tooling/pch.cpp
index 715c95d..40bc1e9 100644
--- a/test/Tooling/pch.cpp
+++ b/test/Tooling/pch.cpp
@@ -6,12 +6,10 @@
// RUN: %clang -x c++-header %S/Inputs/pch.h -o %t1
// Use the generated pch and enforce a subsequent stat miss by using
-// the test file with an unrelated include as second translation unit:
-// Do not directly pipe into FileCheck, as that would hide errors from
-// valgrind due to pipefail not being set in lit.
-// RUN: clang-check "%S/Inputs/pch.cpp" "%s" -- -include-pch %t1 -I "%S" -c >%t2 2>&1
-// RUN: FileCheck %s < %t2
+// the test file with an unrelated include as second translation unit.
+// Test for an non-empty file after clang-check is executed.
+// RUN: clang-check -ast-dump "%S/Inputs/pch.cpp" "%s" -- -include-pch %t1 -I "%S" -c >%t2 2>&1
+// REQUIRES: shell
+// RUN: test -s %t2
#include "Inputs/pch-fail.h"
-
-// CHECK: Processing
diff --git a/test/Unit/lit.cfg b/test/Unit/lit.cfg
index 8f27781..d58337c 100644
--- a/test/Unit/lit.cfg
+++ b/test/Unit/lit.cfg
@@ -28,6 +28,11 @@ if 'TMP' in os.environ:
if 'TEMP' in os.environ:
config.environment['TEMP'] = os.environ['TEMP']
+# Propagate path to symbolizer for ASan/MSan.
+for symbolizer in ['ASAN_SYMBOLIZER_PATH', 'MSAN_SYMBOLIZER_PATH']:
+ if symbolizer in os.environ:
+ config.environment[symbolizer] = os.environ[symbolizer]
+
###
# Check that the object root is known.
diff --git a/test/lit.cfg b/test/lit.cfg
index e91e660..4466f0f 100644
--- a/test/lit.cfg
+++ b/test/lit.cfg
@@ -83,7 +83,6 @@ if clang_obj_root is not None:
lit.fatal('No LLVM tools dir set!')
path = os.path.pathsep.join((llvm_tools_dir, config.environment['PATH']))
config.environment['PATH'] = path
-
llvm_libs_dir = getattr(config, 'llvm_libs_dir', None)
if not llvm_libs_dir:
lit.fatal('No LLVM libs dir set!')
@@ -91,6 +90,11 @@ if clang_obj_root is not None:
config.environment.get('LD_LIBRARY_PATH','')))
config.environment['LD_LIBRARY_PATH'] = path
+# Propagate path to symbolizer for ASan/MSan.
+for symbolizer in ['ASAN_SYMBOLIZER_PATH', 'MSAN_SYMBOLIZER_PATH']:
+ if symbolizer in os.environ:
+ config.environment[symbolizer] = os.environ[symbolizer]
+
###
# Check that the object root is known.
@@ -218,6 +222,10 @@ if platform.system() not in ['FreeBSD']:
if platform.system() not in ['Windows'] or lit.getBashPath() != '':
config.available_features.add('shell')
+# Exclude MSYS due to transforming '/' to 'X:/mingwroot/'.
+if not platform.system() in ['Windows'] or lit.getBashPath() == '':
+ config.available_features.add('shell-preserves-root')
+
# For tests that require Darwin to run.
if platform.system() in ['Darwin']:
config.available_features.add('system-darwin')
@@ -237,10 +245,18 @@ def is_filesystem_case_insensitive():
if is_filesystem_case_insensitive():
config.available_features.add('case-insensitive-filesystem')
+# Tests that require the /dev/fd filesystem.
+if os.path.exists("/dev/fd/0") and sys.platform not in ['cygwin']:
+ config.available_features.add('dev-fd-fs')
+
# [PR8833] LLP64-incompatible tests
if not re.match(r'^x86_64.*-(win32|mingw32)$', config.target_triple):
config.available_features.add('LP64')
+# [PR12920] "clang-driver" -- set if gcc driver is not used.
+if not re.match(r'.*-(cygwin|mingw32)$', config.target_triple):
+ config.available_features.add('clang-driver')
+
# Registered Targets
def get_llc_props(tool):
set_of_targets = set()
@@ -278,3 +294,9 @@ if llc_props['enable_assertions']:
if lit.util.which('xmllint'):
config.available_features.add('xmllint')
+# Sanitizers.
+if config.llvm_use_sanitizer == "Address":
+ config.available_features.add("asan")
+if (config.llvm_use_sanitizer == "Memory" or
+ config.llvm_use_sanitizer == "MemoryWithOrigins"):
+ config.available_features.add("msan")
diff --git a/test/lit.site.cfg.in b/test/lit.site.cfg.in
index df90b81..23eb8e2 100644
--- a/test/lit.site.cfg.in
+++ b/test/lit.site.cfg.in
@@ -7,6 +7,7 @@ config.llvm_libs_dir = "@LLVM_LIBS_DIR@"
config.lit_tools_dir = "@LLVM_LIT_TOOLS_DIR@"
config.clang_obj_root = "@CLANG_BINARY_DIR@"
config.target_triple = "@TARGET_TRIPLE@"
+config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@"
# Support substitution of the tools and libs dirs with user parameters. This is
# used when we can't determine the tool dir at configuration time.
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index cccff5d..eb5e366 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -5,6 +5,7 @@ add_subdirectory(c-arcmt-test)
add_subdirectory(diagtool)
add_subdirectory(driver)
add_subdirectory(clang-check)
+add_subdirectory(clang-format)
# We support checking out the clang-tools-extra repository into the 'extra'
# subdirectory. It contains tools developed as part of the Clang/LLVM project
diff --git a/tools/Makefile b/tools/Makefile
index 23197a1..b33c74d 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -12,7 +12,7 @@ CLANG_LEVEL := ..
include $(CLANG_LEVEL)/../../Makefile.config
DIRS := driver libclang c-index-test arcmt-test c-arcmt-test diagtool \
- clang-check
+ clang-check clang-format
# Recurse into the extra repository of tools if present.
OPTIONAL_DIRS := extra
diff --git a/tools/arcmt-test/CMakeLists.txt b/tools/arcmt-test/CMakeLists.txt
index a7ce586..3d85d05 100644
--- a/tools/arcmt-test/CMakeLists.txt
+++ b/tools/arcmt-test/CMakeLists.txt
@@ -1,6 +1,7 @@
set(LLVM_LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
asmparser
+ bitreader
support
mc
)
diff --git a/tools/arcmt-test/Makefile b/tools/arcmt-test/Makefile
index 06e2016..52898ce 100644
--- a/tools/arcmt-test/Makefile
+++ b/tools/arcmt-test/Makefile
@@ -17,7 +17,7 @@ TOOL_NO_EXPORTS = 1
NO_INSTALL = 1
include $(CLANG_LEVEL)/../../Makefile.config
-LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc
USEDLIBS = clangARCMigrate.a clangRewriteCore.a \
clangFrontend.a clangDriver.a clangSerialization.a clangParse.a \
clangSema.a clangEdit.a clangAnalysis.a clangAST.a clangLex.a \
diff --git a/tools/arcmt-test/arcmt-test.cpp b/tools/arcmt-test/arcmt-test.cpp
index b745893..179a115 100644
--- a/tools/arcmt-test/arcmt-test.cpp
+++ b/tools/arcmt-test/arcmt-test.cpp
@@ -10,11 +10,11 @@
#include "clang/ARCMigrate/ARCMT.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
-#include "clang/Frontend/VerifyDiagnosticConsumer.h"
#include "clang/Frontend/Utils.h"
+#include "clang/Frontend/VerifyDiagnosticConsumer.h"
#include "clang/Lex/Preprocessor.h"
-#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/system_error.h"
diff --git a/tools/c-arcmt-test/Makefile b/tools/c-arcmt-test/Makefile
index 3372dae..02b8ab7 100644
--- a/tools/c-arcmt-test/Makefile
+++ b/tools/c-arcmt-test/Makefile
@@ -21,10 +21,10 @@ NO_INSTALL = 1
# LINK_COMPONENTS before including Makefile.rules
include $(CLANG_LEVEL)/../../Makefile.config
-LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc
# Note that 'USEDLIBS' must include all of the core clang libraries
-# as clang.dll is unavailable on cygming yet.
+# when -static is given to linker on cygming.
USEDLIBS = clang.a \
clangARCMigrate.a \
clangRewriteFrontend.a \
diff --git a/tools/c-index-test/CMakeLists.txt b/tools/c-index-test/CMakeLists.txt
index 6f28c54..d90dc6d 100644
--- a/tools/c-index-test/CMakeLists.txt
+++ b/tools/c-index-test/CMakeLists.txt
@@ -23,8 +23,7 @@ set_target_properties(c-index-test
LINKER_LANGUAGE CXX)
# If libxml2 is available, make it available for c-index-test.
-if (LIBXML2_FOUND)
- add_definitions(${LIBXML2_DEFINITIONS} "-DCLANG_HAVE_LIBXML")
+if (CLANG_HAVE_LIBXML)
include_directories(${LIBXML2_INCLUDE_DIR})
target_link_libraries(c-index-test ${LIBXML2_LIBRARIES})
endif()
diff --git a/tools/c-index-test/Makefile b/tools/c-index-test/Makefile
index b81678b..7723115 100644
--- a/tools/c-index-test/Makefile
+++ b/tools/c-index-test/Makefile
@@ -22,8 +22,13 @@ TOOL_NO_EXPORTS = 1
# LINK_COMPONENTS before including Makefile.rules
include $(CLANG_LEVEL)/../../Makefile.config
-LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
-USEDLIBS = clang.a clangFrontend.a clangDriver.a \
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc
+
+# Note that 'USEDLIBS' must include all of the core clang libraries
+# when -static is given to linker on cygming.
+USEDLIBS = clang.a \
+ clangFormat.a clangRewriteCore.a \
+ clangFrontend.a clangDriver.a \
clangTooling.a \
clangSerialization.a clangParse.a clangSema.a \
clangAnalysis.a clangEdit.a clangAST.a clangLex.a \
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 3e4404c..88b49ed 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -15,6 +15,12 @@
#include <libxml/xmlerror.h>
#endif
+#ifdef _WIN32
+# include <direct.h>
+#else
+# include <unistd.h>
+#endif
+
/******************************************************************************/
/* Utility functions. */
/******************************************************************************/
@@ -1077,36 +1083,42 @@ static enum CXChildVisitResult PrintLinkage(CXCursor cursor, CXCursor p,
/* Typekind testing. */
/******************************************************************************/
-static enum CXChildVisitResult PrintTypeKind(CXCursor cursor, CXCursor p,
- CXClientData d) {
+static void PrintTypeAndTypeKind(CXType T, const char *Format) {
+ CXString TypeSpelling, TypeKindSpelling;
+
+ TypeSpelling = clang_getTypeSpelling(T);
+ TypeKindSpelling = clang_getTypeKindSpelling(T.kind);
+ printf(Format,
+ clang_getCString(TypeSpelling),
+ clang_getCString(TypeKindSpelling));
+ clang_disposeString(TypeSpelling);
+ clang_disposeString(TypeKindSpelling);
+}
+
+static enum CXChildVisitResult PrintType(CXCursor cursor, CXCursor p,
+ CXClientData d) {
if (!clang_isInvalid(clang_getCursorKind(cursor))) {
CXType T = clang_getCursorType(cursor);
- CXString S = clang_getTypeKindSpelling(T.kind);
PrintCursor(cursor, NULL);
- printf(" typekind=%s", clang_getCString(S));
+ PrintTypeAndTypeKind(T, " [type=%s] [typekind=%s]");
if (clang_isConstQualifiedType(T))
printf(" const");
if (clang_isVolatileQualifiedType(T))
printf(" volatile");
if (clang_isRestrictQualifiedType(T))
printf(" restrict");
- clang_disposeString(S);
/* Print the canonical type if it is different. */
{
CXType CT = clang_getCanonicalType(T);
if (!clang_equalTypes(T, CT)) {
- CXString CS = clang_getTypeKindSpelling(CT.kind);
- printf(" [canonical=%s]", clang_getCString(CS));
- clang_disposeString(CS);
+ PrintTypeAndTypeKind(CT, " [canonicaltype=%s] [canonicaltypekind=%s]");
}
}
/* Print the return type if it exists. */
{
CXType RT = clang_getCursorResultType(cursor);
if (RT.kind != CXType_Invalid) {
- CXString RS = clang_getTypeKindSpelling(RT.kind);
- printf(" [result=%s]", clang_getCString(RS));
- clang_disposeString(RS);
+ PrintTypeAndTypeKind(RT, " [resulttype=%s] [resulttypekind=%s]");
}
}
/* Print the argument types if they exist. */
@@ -1118,9 +1130,7 @@ static enum CXChildVisitResult PrintTypeKind(CXCursor cursor, CXCursor p,
for (i = 0; i < numArgs; ++i) {
CXType T = clang_getCursorType(clang_Cursor_getArgument(cursor, i));
if (T.kind != CXType_Invalid) {
- CXString S = clang_getTypeKindSpelling(T.kind);
- printf(" %s", clang_getCString(S));
- clang_disposeString(S);
+ PrintTypeAndTypeKind(T, " [%s] [%s]");
}
}
printf("]");
@@ -1134,6 +1144,24 @@ static enum CXChildVisitResult PrintTypeKind(CXCursor cursor, CXCursor p,
return CXChildVisit_Recurse;
}
+/******************************************************************************/
+/* Bitwidth testing. */
+/******************************************************************************/
+
+static enum CXChildVisitResult PrintBitWidth(CXCursor cursor, CXCursor p,
+ CXClientData d) {
+ int Bitwidth;
+ if (clang_getCursorKind(cursor) != CXCursor_FieldDecl)
+ return CXChildVisit_Recurse;
+
+ Bitwidth = clang_getFieldDeclBitWidth(cursor);
+ if (Bitwidth >= 0) {
+ PrintCursor(cursor, NULL);
+ printf(" bitwidth=%d\n", Bitwidth);
+ }
+
+ return CXChildVisit_Recurse;
+}
/******************************************************************************/
/* Loading ASTs/source. */
@@ -1203,7 +1231,7 @@ int perform_test_load_tu(const char *file, const char *filter,
int result;
Idx = clang_createIndex(/* excludeDeclsFromPCH */
!strcmp(filter, "local") ? 1 : 0,
- /* displayDiagnosics=*/1);
+ /* displayDiagnostics=*/1);
if (!CreateTranslationUnit(Idx, file, &TU)) {
clang_disposeIndex(Idx);
@@ -1228,7 +1256,7 @@ int perform_test_load_source(int argc, const char **argv,
Idx = clang_createIndex(/* excludeDeclsFromPCH */
(!strcmp(filter, "local") ||
!strcmp(filter, "local-display"))? 1 : 0,
- /* displayDiagnosics=*/0);
+ /* displayDiagnostics=*/0);
if ((CommentSchemaFile = parse_comments_schema(argc, argv))) {
argc--;
@@ -1273,7 +1301,7 @@ int perform_test_reparse_source(int argc, const char **argv, int trials,
Idx = clang_createIndex(/* excludeDeclsFromPCH */
!strcmp(filter, "local") ? 1 : 0,
- /* displayDiagnosics=*/0);
+ /* displayDiagnostics=*/0);
if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) {
clang_disposeIndex(Idx);
@@ -1352,7 +1380,7 @@ static int perform_file_scan(const char *ast_file, const char *source_file,
unsigned start_line = 1, start_col = 1;
if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
- /* displayDiagnosics=*/1))) {
+ /* displayDiagnostics=*/1))) {
fprintf(stderr, "Could not create Index\n");
return 1;
}
@@ -1968,12 +1996,12 @@ static int inspect_cursor_at(int argc, const char **argv) {
unsigned i, numHeaders;
if (mod) {
name = clang_Module_getFullName(mod);
- numHeaders = clang_Module_getNumTopLevelHeaders(mod);
+ numHeaders = clang_Module_getNumTopLevelHeaders(TU, mod);
printf(" ModuleName=%s Headers(%d):",
clang_getCString(name), numHeaders);
clang_disposeString(name);
for (i = 0; i < numHeaders; ++i) {
- CXFile file = clang_Module_getTopLevelHeader(mod, i);
+ CXFile file = clang_Module_getTopLevelHeader(TU, mod, i);
CXString filename = clang_getFileName(file);
printf("\n%s", clang_getCString(filename));
clang_disposeString(filename);
@@ -2107,6 +2135,99 @@ static int find_file_refs_at(int argc, const char **argv) {
return 0;
}
+static enum CXVisitorResult findFileIncludesVisit(void *context,
+ CXCursor cursor, CXSourceRange range) {
+ PrintCursor(cursor, NULL);
+ PrintRange(range, "");
+ printf("\n");
+ return CXVisit_Continue;
+}
+
+static int find_file_includes_in(int argc, const char **argv) {
+ CXIndex CIdx;
+ struct CXUnsavedFile *unsaved_files = 0;
+ int num_unsaved_files = 0;
+ CXTranslationUnit TU;
+ const char **Filenames = 0;
+ unsigned NumFilenames = 0;
+ unsigned Repeats = 1;
+ unsigned I, FI;
+
+ /* Count the number of locations. */
+ while (strstr(argv[NumFilenames+1], "-file-includes-in=") == argv[NumFilenames+1])
+ ++NumFilenames;
+
+ /* Parse the locations. */
+ assert(NumFilenames > 0 && "Unable to count filenames?");
+ Filenames = (const char **)malloc(NumFilenames * sizeof(const char *));
+ for (I = 0; I < NumFilenames; ++I) {
+ const char *input = argv[I + 1] + strlen("-file-includes-in=");
+ /* Copy the file name. */
+ Filenames[I] = input;
+ }
+
+ if (parse_remapped_files(argc, argv, NumFilenames + 1, &unsaved_files,
+ &num_unsaved_files))
+ return -1;
+
+ if (getenv("CINDEXTEST_EDITING"))
+ Repeats = 2;
+
+ /* Parse the translation unit. When we're testing clang_getCursor() after
+ reparsing, don't remap unsaved files until the second parse. */
+ CIdx = clang_createIndex(1, 1);
+ TU = clang_parseTranslationUnit(CIdx, argv[argc - 1],
+ argv + num_unsaved_files + 1 + NumFilenames,
+ argc - num_unsaved_files - 2 - NumFilenames,
+ unsaved_files,
+ Repeats > 1? 0 : num_unsaved_files,
+ getDefaultParsingOptions());
+
+ if (!TU) {
+ fprintf(stderr, "unable to parse input\n");
+ return -1;
+ }
+
+ if (checkForErrors(TU) != 0)
+ return -1;
+
+ for (I = 0; I != Repeats; ++I) {
+ if (Repeats > 1 &&
+ clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
+ clang_defaultReparseOptions(TU))) {
+ clang_disposeTranslationUnit(TU);
+ return 1;
+ }
+
+ if (checkForErrors(TU) != 0)
+ return -1;
+
+ for (FI = 0; FI < NumFilenames; ++FI) {
+ CXFile file = clang_getFile(TU, Filenames[FI]);
+ if (!file)
+ continue;
+
+ if (checkForErrors(TU) != 0)
+ return -1;
+
+ if (I + 1 == Repeats) {
+ CXCursorAndRangeVisitor visitor = { 0, findFileIncludesVisit };
+ clang_findIncludesInFile(TU, file, visitor);
+
+ if (checkForErrors(TU) != 0)
+ return -1;
+ }
+ }
+ }
+
+ PrintDiagnostics(TU);
+ clang_disposeTranslationUnit(TU);
+ clang_disposeIndex(CIdx);
+ free((void *)Filenames);
+ free_remapped_files(unsaved_files, num_unsaved_files);
+ return 0;
+}
+
#define MAX_IMPORTED_ASTFILES 200
typedef struct {
@@ -2473,7 +2594,12 @@ static void index_indexDeclaration(CXClientData client_data,
printCXIndexContainer(info->lexicalContainer);
printf(" | isRedecl: %d", info->isRedeclaration);
printf(" | isDef: %d", info->isDefinition);
- printf(" | isContainer: %d", info->isContainer);
+ if (info->flags & CXIdxDeclFlag_Skipped) {
+ assert(!info->isContainer);
+ printf(" | isContainer: skipped");
+ } else {
+ printf(" | isContainer: %d", info->isContainer);
+ }
printf(" | isImplicit: %d\n", info->isImplicit);
for (i = 0; i != info->numAttributes; ++i) {
@@ -2584,16 +2710,79 @@ static unsigned getIndexOptions(void) {
index_opts |= CXIndexOpt_SuppressRedundantRefs;
if (getenv("CINDEXTEST_INDEXLOCALSYMBOLS"))
index_opts |= CXIndexOpt_IndexFunctionLocalSymbols;
+ if (!getenv("CINDEXTEST_DISABLE_SKIPPARSEDBODIES"))
+ index_opts |= CXIndexOpt_SkipParsedBodiesInSession;
return index_opts;
}
+static int index_compile_args(int num_args, const char **args,
+ CXIndexAction idxAction,
+ ImportedASTFilesData *importedASTs,
+ const char *check_prefix) {
+ IndexData index_data;
+ unsigned index_opts;
+ int result;
+
+ if (num_args == 0) {
+ fprintf(stderr, "no compiler arguments\n");
+ return -1;
+ }
+
+ index_data.check_prefix = check_prefix;
+ index_data.first_check_printed = 0;
+ index_data.fail_for_error = 0;
+ index_data.abort = 0;
+ index_data.main_filename = "";
+ index_data.importedASTs = importedASTs;
+
+ index_opts = getIndexOptions();
+ result = clang_indexSourceFile(idxAction, &index_data,
+ &IndexCB,sizeof(IndexCB), index_opts,
+ 0, args, num_args, 0, 0, 0,
+ getDefaultParsingOptions());
+ if (index_data.fail_for_error)
+ result = -1;
+
+ return result;
+}
+
+static int index_ast_file(const char *ast_file,
+ CXIndex Idx,
+ CXIndexAction idxAction,
+ ImportedASTFilesData *importedASTs,
+ const char *check_prefix) {
+ CXTranslationUnit TU;
+ IndexData index_data;
+ unsigned index_opts;
+ int result;
+
+ if (!CreateTranslationUnit(Idx, ast_file, &TU))
+ return -1;
+
+ index_data.check_prefix = check_prefix;
+ index_data.first_check_printed = 0;
+ index_data.fail_for_error = 0;
+ index_data.abort = 0;
+ index_data.main_filename = "";
+ index_data.importedASTs = importedASTs;
+
+ index_opts = getIndexOptions();
+ result = clang_indexTranslationUnit(idxAction, &index_data,
+ &IndexCB,sizeof(IndexCB),
+ index_opts, TU);
+ if (index_data.fail_for_error)
+ result = -1;
+
+ clang_disposeTranslationUnit(TU);
+ return result;
+}
+
static int index_file(int argc, const char **argv, int full) {
const char *check_prefix;
CXIndex Idx;
CXIndexAction idxAction;
- IndexData index_data;
- unsigned index_opts;
+ ImportedASTFilesData *importedASTs;
int result;
check_prefix = 0;
@@ -2605,68 +2794,39 @@ static int index_file(int argc, const char **argv, int full) {
}
}
- if (argc == 0) {
- fprintf(stderr, "no compiler arguments\n");
- return -1;
- }
-
if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
- /* displayDiagnosics=*/1))) {
+ /* displayDiagnostics=*/1))) {
fprintf(stderr, "Could not create Index\n");
return 1;
}
- idxAction = 0;
-
- index_data.check_prefix = check_prefix;
- index_data.first_check_printed = 0;
- index_data.fail_for_error = 0;
- index_data.abort = 0;
- index_data.main_filename = "";
- index_data.importedASTs = 0;
-
+ idxAction = clang_IndexAction_create(Idx);
+ importedASTs = 0;
if (full)
- index_data.importedASTs = importedASTs_create();
+ importedASTs = importedASTs_create();
+
+ result = index_compile_args(argc, argv, idxAction, importedASTs, check_prefix);
+ if (result != 0)
+ goto finished;
- index_opts = getIndexOptions();
- idxAction = clang_IndexAction_create(Idx);
- result = clang_indexSourceFile(idxAction, &index_data,
- &IndexCB,sizeof(IndexCB), index_opts,
- 0, argv, argc, 0, 0, 0,
- getDefaultParsingOptions());
- if (index_data.fail_for_error)
- result = -1;
-
if (full) {
- CXTranslationUnit TU;
unsigned i;
-
- for (i = 0; i < index_data.importedASTs->num_files; ++i) {
- if (!CreateTranslationUnit(Idx, index_data.importedASTs->filenames[i],
- &TU)) {
- result = -1;
- goto finished;
- }
- result = clang_indexTranslationUnit(idxAction, &index_data,
- &IndexCB,sizeof(IndexCB),
- index_opts, TU);
- clang_disposeTranslationUnit(TU);
+ for (i = 0; i < importedASTs->num_files && result == 0; ++i) {
+ result = index_ast_file(importedASTs->filenames[i], Idx, idxAction,
+ importedASTs, check_prefix);
}
}
finished:
- importedASTs_dispose(index_data.importedASTs);
+ importedASTs_dispose(importedASTs);
clang_IndexAction_dispose(idxAction);
clang_disposeIndex(Idx);
return result;
}
static int index_tu(int argc, const char **argv) {
+ const char *check_prefix;
CXIndex Idx;
CXIndexAction idxAction;
- CXTranslationUnit TU;
- const char *check_prefix;
- IndexData index_data;
- unsigned index_opts;
int result;
check_prefix = 0;
@@ -2678,44 +2838,142 @@ static int index_tu(int argc, const char **argv) {
}
}
+ if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
+ /* displayDiagnostics=*/1))) {
+ fprintf(stderr, "Could not create Index\n");
+ return 1;
+ }
+ idxAction = clang_IndexAction_create(Idx);
+
+ result = index_ast_file(argv[0], Idx, idxAction,
+ /*importedASTs=*/0, check_prefix);
+
+ clang_IndexAction_dispose(idxAction);
+ clang_disposeIndex(Idx);
+ return result;
+}
+
+static int index_compile_db(int argc, const char **argv) {
+ const char *check_prefix;
+ CXIndex Idx;
+ CXIndexAction idxAction;
+ int errorCode = 0;
+
+ check_prefix = 0;
+ if (argc > 0) {
+ if (strstr(argv[0], "-check-prefix=") == argv[0]) {
+ check_prefix = argv[0] + strlen("-check-prefix=");
+ ++argv;
+ --argc;
+ }
+ }
+
if (argc == 0) {
- fprintf(stderr, "no ast file\n");
+ fprintf(stderr, "no compilation database\n");
return -1;
}
if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
- /* displayDiagnosics=*/1))) {
+ /* displayDiagnostics=*/1))) {
fprintf(stderr, "Could not create Index\n");
return 1;
}
- idxAction = 0;
- TU = 0;
- result = 1;
+ idxAction = clang_IndexAction_create(Idx);
- if (!CreateTranslationUnit(Idx, argv[0], &TU))
- goto finished;
+ {
+ const char *database = argv[0];
+ CXCompilationDatabase db = 0;
+ CXCompileCommands CCmds = 0;
+ CXCompileCommand CCmd;
+ CXCompilationDatabase_Error ec;
+ CXString wd;
+#define MAX_COMPILE_ARGS 512
+ CXString cxargs[MAX_COMPILE_ARGS];
+ const char *args[MAX_COMPILE_ARGS];
+ char *tmp;
+ unsigned len;
+ char *buildDir;
+ int i, a, numCmds, numArgs;
+
+ len = strlen(database);
+ tmp = (char *) malloc(len+1);
+ memcpy(tmp, database, len+1);
+ buildDir = dirname(tmp);
+
+ db = clang_CompilationDatabase_fromDirectory(buildDir, &ec);
+
+ if (db) {
+
+ if (ec!=CXCompilationDatabase_NoError) {
+ printf("unexpected error %d code while loading compilation database\n", ec);
+ errorCode = -1;
+ goto cdb_end;
+ }
- index_data.check_prefix = check_prefix;
- index_data.first_check_printed = 0;
- index_data.fail_for_error = 0;
- index_data.abort = 0;
- index_data.main_filename = "";
- index_data.importedASTs = 0;
+ if (chdir(buildDir) != 0) {
+ printf("Could not chdir to %s\n", buildDir);
+ errorCode = -1;
+ goto cdb_end;
+ }
- index_opts = getIndexOptions();
- idxAction = clang_IndexAction_create(Idx);
- result = clang_indexTranslationUnit(idxAction, &index_data,
- &IndexCB,sizeof(IndexCB),
- index_opts, TU);
- if (index_data.fail_for_error)
- goto finished;
+ CCmds = clang_CompilationDatabase_getAllCompileCommands(db);
+ if (!CCmds) {
+ printf("compilation db is empty\n");
+ errorCode = -1;
+ goto cdb_end;
+ }
+
+ numCmds = clang_CompileCommands_getSize(CCmds);
+
+ if (numCmds==0) {
+ fprintf(stderr, "should not get an empty compileCommand set\n");
+ errorCode = -1;
+ goto cdb_end;
+ }
+
+ for (i=0; i<numCmds && errorCode == 0; ++i) {
+ CCmd = clang_CompileCommands_getCommand(CCmds, i);
+
+ wd = clang_CompileCommand_getDirectory(CCmd);
+ if (chdir(clang_getCString(wd)) != 0) {
+ printf("Could not chdir to %s\n", clang_getCString(wd));
+ errorCode = -1;
+ goto cdb_end;
+ }
+ clang_disposeString(wd);
+
+ numArgs = clang_CompileCommand_getNumArgs(CCmd);
+ if (numArgs > MAX_COMPILE_ARGS){
+ fprintf(stderr, "got more compile arguments than maximum\n");
+ errorCode = -1;
+ goto cdb_end;
+ }
+ for (a=0; a<numArgs; ++a) {
+ cxargs[a] = clang_CompileCommand_getArg(CCmd, a);
+ args[a] = clang_getCString(cxargs[a]);
+ }
+
+ errorCode = index_compile_args(numArgs, args, idxAction,
+ /*importedASTs=*/0, check_prefix);
+
+ for (a=0; a<numArgs; ++a)
+ clang_disposeString(cxargs[a]);
+ }
+ } else {
+ printf("database loading failed with error code %d.\n", ec);
+ errorCode = -1;
+ }
+
+ cdb_end:
+ clang_CompileCommands_dispose(CCmds);
+ clang_CompilationDatabase_dispose(db);
+ free(tmp);
+
+ }
- finished:
clang_IndexAction_dispose(idxAction);
- clang_disposeTranslationUnit(TU);
clang_disposeIndex(Idx);
-
- return result;
+ return errorCode;
}
int perform_token_annotation(int argc, const char **argv) {
@@ -3124,7 +3382,7 @@ int write_pch_file(const char *filename, int argc, const char *argv[]) {
int num_unsaved_files = 0;
int result = 0;
- Idx = clang_createIndex(/* excludeDeclsFromPCH */1, /* displayDiagnosics=*/1);
+ Idx = clang_createIndex(/* excludeDeclsFromPCH */1, /* displayDiagnostics=*/1);
if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) {
clang_disposeIndex(Idx);
@@ -3355,11 +3613,13 @@ static void print_usage(void) {
"usage: c-index-test -code-completion-at=<site> <compiler arguments>\n"
" c-index-test -code-completion-timing=<site> <compiler arguments>\n"
" c-index-test -cursor-at=<site> <compiler arguments>\n"
- " c-index-test -file-refs-at=<site> <compiler arguments>\n");
+ " c-index-test -file-refs-at=<site> <compiler arguments>\n"
+ " c-index-test -file-includes-in=<filename> <compiler arguments>\n");
fprintf(stderr,
" c-index-test -index-file [-check-prefix=<FileCheck prefix>] <compiler arguments>\n"
" c-index-test -index-file-full [-check-prefix=<FileCheck prefix>] <compiler arguments>\n"
" c-index-test -index-tu [-check-prefix=<FileCheck prefix>] <AST file>\n"
+ " c-index-test -index-compile-db [-check-prefix=<FileCheck prefix>] <compilation database>\n"
" c-index-test -test-file-scan <AST file> <source file> "
"[FileCheck prefix]\n");
fprintf(stderr,
@@ -3381,7 +3641,8 @@ static void print_usage(void) {
" c-index-test -test-inclusion-stack-tu <AST file>\n");
fprintf(stderr,
" c-index-test -test-print-linkage-source {<args>}*\n"
- " c-index-test -test-print-typekind {<args>}*\n"
+ " c-index-test -test-print-type {<args>}*\n"
+ " c-index-test -test-print-bitwidth {<args>}*\n"
" c-index-test -print-usr [<CursorKind> {<args>}]*\n"
" c-index-test -print-usr-file <file>\n"
" c-index-test -write-pch <file> <compiler arguments>\n");
@@ -3415,12 +3676,16 @@ int cindextest_main(int argc, const char **argv) {
return inspect_cursor_at(argc, argv);
if (argc > 2 && strstr(argv[1], "-file-refs-at=") == argv[1])
return find_file_refs_at(argc, argv);
+ if (argc > 2 && strstr(argv[1], "-file-includes-in=") == argv[1])
+ return find_file_includes_in(argc, argv);
if (argc > 2 && strcmp(argv[1], "-index-file") == 0)
return index_file(argc - 2, argv + 2, /*full=*/0);
if (argc > 2 && strcmp(argv[1], "-index-file-full") == 0)
return index_file(argc - 2, argv + 2, /*full=*/1);
if (argc > 2 && strcmp(argv[1], "-index-tu") == 0)
return index_tu(argc - 2, argv + 2);
+ if (argc > 2 && strcmp(argv[1], "-index-compile-db") == 0)
+ return index_compile_db(argc - 2, argv + 2);
else if (argc >= 4 && strncmp(argv[1], "-test-load-tu", 13) == 0) {
CXCursorVisitor I = GetVisitor(argv[1] + 13);
if (I)
@@ -3460,9 +3725,12 @@ int cindextest_main(int argc, const char **argv) {
else if (argc > 2 && strcmp(argv[1], "-test-print-linkage-source") == 0)
return perform_test_load_source(argc - 2, argv + 2, "all", PrintLinkage,
NULL);
- else if (argc > 2 && strcmp(argv[1], "-test-print-typekind") == 0)
+ else if (argc > 2 && strcmp(argv[1], "-test-print-type") == 0)
+ return perform_test_load_source(argc - 2, argv + 2, "all",
+ PrintType, 0);
+ else if (argc > 2 && strcmp(argv[1], "-test-print-bitwidth") == 0)
return perform_test_load_source(argc - 2, argv + 2, "all",
- PrintTypeKind, 0);
+ PrintBitWidth, 0);
else if (argc > 1 && strcmp(argv[1], "-print-usr") == 0) {
if (argc > 2)
return print_usrs(argv + 2, argv + argc);
diff --git a/tools/clang-check/CMakeLists.txt b/tools/clang-check/CMakeLists.txt
index f5d7616..e8d0d0a 100644
--- a/tools/clang-check/CMakeLists.txt
+++ b/tools/clang-check/CMakeLists.txt
@@ -1,6 +1,7 @@
set(LLVM_LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
asmparser
+ bitreader
support
mc
)
diff --git a/tools/clang-check/ClangCheck.cpp b/tools/clang-check/ClangCheck.cpp
index 6c081ac..bf43374 100644
--- a/tools/clang-check/ClangCheck.cpp
+++ b/tools/clang-check/ClangCheck.cpp
@@ -27,6 +27,7 @@
#include "clang/Tooling/Tooling.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/Signals.h"
using namespace clang::driver;
using namespace clang::tooling;
@@ -142,9 +143,10 @@ public:
}
int main(int argc, const char **argv) {
+ llvm::sys::PrintStackTraceOnErrorSignal();
CommonOptionsParser OptionsParser(argc, argv);
- ClangTool Tool(OptionsParser.GetCompilations(),
- OptionsParser.GetSourcePathList());
+ ClangTool Tool(OptionsParser.getCompilations(),
+ OptionsParser.getSourcePathList());
if (Fixit)
return Tool.run(newFrontendActionFactory<FixItAction>());
clang_check::ClangCheckActionFactory Factory;
diff --git a/tools/clang-check/Makefile b/tools/clang-check/Makefile
index 28f94f6..7d6505e 100644
--- a/tools/clang-check/Makefile
+++ b/tools/clang-check/Makefile
@@ -15,7 +15,7 @@ TOOLNAME = clang-check
TOOL_NO_EXPORTS = 1
include $(CLANG_LEVEL)/../../Makefile.config
-LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc
USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a \
clangTooling.a clangParse.a clangSema.a clangAnalysis.a \
clangRewriteFrontend.a clangRewriteCore.a clangEdit.a clangAST.a \
diff --git a/tools/clang-format/CMakeLists.txt b/tools/clang-format/CMakeLists.txt
new file mode 100644
index 0000000..c86a920
--- /dev/null
+++ b/tools/clang-format/CMakeLists.txt
@@ -0,0 +1,17 @@
+set(LLVM_LINK_COMPONENTS support)
+set(LLVM_USED_LIBS clangFormat clangTooling clangBasic clangAST)
+
+add_clang_executable(clang-format
+ ClangFormat.cpp
+ )
+
+target_link_libraries(clang-format
+ clangFormat
+ clangTooling
+ clangBasic
+ clangRewriteFrontend
+ )
+
+install(TARGETS clang-format
+ RUNTIME DESTINATION bin)
+
diff --git a/tools/clang-format/ClangFormat.cpp b/tools/clang-format/ClangFormat.cpp
new file mode 100644
index 0000000..c4969b2
--- /dev/null
+++ b/tools/clang-format/ClangFormat.cpp
@@ -0,0 +1,152 @@
+//===-- clang-format/ClangFormat.cpp - Clang format tool ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file implements a clang-format tool that automatically formats
+/// (fragments of) C++ code.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Format/Format.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Signals.h"
+
+using namespace llvm;
+
+static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
+
+static cl::list<int> Offsets(
+ "offset", cl::desc("Format a range starting at this file offset."));
+static cl::list<int> Lengths(
+ "length", cl::desc("Format a range of this length, -1 for end of file."));
+static cl::opt<std::string> Style(
+ "style",
+ cl::desc("Coding style, currently supports: LLVM, Google, Chromium."),
+ cl::init("LLVM"));
+static cl::opt<bool> Inplace("i",
+ cl::desc("Inplace edit <file>, if specified."));
+
+static cl::opt<bool> OutputXML(
+ "output-replacements-xml", cl::desc("Output replacements as XML."));
+
+static cl::opt<std::string> FileName(cl::Positional, cl::desc("[<file>]"),
+ cl::init("-"));
+
+namespace clang {
+namespace format {
+
+static FileID createInMemoryFile(StringRef FileName, const MemoryBuffer *Source,
+ SourceManager &Sources, FileManager &Files) {
+ const FileEntry *Entry = Files.getVirtualFile(FileName == "-" ? "<stdin>" :
+ FileName,
+ Source->getBufferSize(), 0);
+ Sources.overrideFileContents(Entry, Source, true);
+ return Sources.createFileID(Entry, SourceLocation(), SrcMgr::C_User);
+}
+
+static FormatStyle getStyle() {
+ FormatStyle TheStyle = getGoogleStyle();
+ if (Style == "LLVM")
+ TheStyle = getLLVMStyle();
+ if (Style == "Chromium")
+ TheStyle = getChromiumStyle();
+ return TheStyle;
+}
+
+static void format() {
+ FileManager Files((FileSystemOptions()));
+ DiagnosticsEngine Diagnostics(
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
+ new DiagnosticOptions);
+ SourceManager Sources(Diagnostics, Files);
+ OwningPtr<MemoryBuffer> Code;
+ if (error_code ec = MemoryBuffer::getFileOrSTDIN(FileName, Code)) {
+ llvm::errs() << ec.message() << "\n";
+ return;
+ }
+ FileID ID = createInMemoryFile(FileName, Code.get(), Sources, Files);
+ Lexer Lex(ID, Sources.getBuffer(ID), Sources, getFormattingLangOpts());
+ if (Offsets.empty())
+ Offsets.push_back(0);
+ if (Offsets.size() != Lengths.size() &&
+ !(Offsets.size() == 1 && Lengths.empty())) {
+ llvm::errs() << "Number of -offset and -length arguments must match.\n";
+ return;
+ }
+ std::vector<CharSourceRange> Ranges;
+ for (cl::list<int>::size_type i = 0, e = Offsets.size(); i != e; ++i) {
+ SourceLocation Start =
+ Sources.getLocForStartOfFile(ID).getLocWithOffset(Offsets[i]);
+ SourceLocation End;
+ if (i < Lengths.size()) {
+ End = Start.getLocWithOffset(Lengths[i]);
+ } else {
+ End = Sources.getLocForEndOfFile(ID);
+ }
+ Ranges.push_back(CharSourceRange::getCharRange(Start, End));
+ }
+ tooling::Replacements Replaces = reformat(getStyle(), Lex, Sources, Ranges);
+ if (OutputXML) {
+ llvm::outs() << "<?xml version='1.0'?>\n<replacements xml:space='preserve'>\n";
+ for (tooling::Replacements::const_iterator I = Replaces.begin(),
+ E = Replaces.end();
+ I != E; ++I) {
+ llvm::outs() << "<replacement "
+ << "offset='" << I->getOffset() << "' "
+ << "length='" << I->getLength() << "'>"
+ << I->getReplacementText() << "</replacement>\n";
+ }
+ llvm::outs() << "</replacements>\n";
+ } else {
+ Rewriter Rewrite(Sources, LangOptions());
+ tooling::applyAllReplacements(Replaces, Rewrite);
+ if (Inplace) {
+ if (Replaces.size() == 0)
+ return; // Nothing changed, don't touch the file.
+
+ std::string ErrorInfo;
+ llvm::raw_fd_ostream FileStream(FileName.c_str(), ErrorInfo,
+ llvm::raw_fd_ostream::F_Binary);
+ if (!ErrorInfo.empty()) {
+ llvm::errs() << "Error while writing file: " << ErrorInfo << "\n";
+ return;
+ }
+ Rewrite.getEditBuffer(ID).write(FileStream);
+ FileStream.flush();
+ } else {
+ Rewrite.getEditBuffer(ID).write(outs());
+ }
+ }
+}
+
+} // namespace format
+} // namespace clang
+
+int main(int argc, const char **argv) {
+ llvm::sys::PrintStackTraceOnErrorSignal();
+ cl::ParseCommandLineOptions(
+ argc, argv,
+ "A tool to format C/C++/Obj-C code.\n\n"
+ "Currently supports LLVM and Google style guides.\n"
+ "If no arguments are specified, it formats the code from standard input\n"
+ "and writes the result to the standard output.\n"
+ "If <file> is given, it reformats the file. If -i is specified together\n"
+ "with <file>, the file is edited in-place. Otherwise, the result is\n"
+ "written to the standard output.\n");
+ if (Help)
+ cl::PrintHelpMessage();
+ clang::format::format();
+ return 0;
+}
diff --git a/tools/clang-format/Makefile b/tools/clang-format/Makefile
new file mode 100644
index 0000000..d869267
--- /dev/null
+++ b/tools/clang-format/Makefile
@@ -0,0 +1,24 @@
+##===- clang-format/Makefile -------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL := ../..
+
+TOOLNAME = clang-format
+
+# No plugins, optimize startup time.
+TOOL_NO_EXPORTS = 1
+
+include $(CLANG_LEVEL)/../../Makefile.config
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc
+USEDLIBS = clangFormat.a clangTooling.a clangFrontend.a clangSerialization.a \
+ clangDriver.a clangParse.a clangSema.a clangAnalysis.a \
+ clangRewriteFrontend.a clangRewriteCore.a clangEdit.a clangAST.a \
+ clangLex.a clangBasic.a
+
+include $(CLANG_LEVEL)/Makefile
diff --git a/tools/clang-format/clang-format-diff.py b/tools/clang-format/clang-format-diff.py
new file mode 100755
index 0000000..ab5f1b1
--- /dev/null
+++ b/tools/clang-format/clang-format-diff.py
@@ -0,0 +1,115 @@
+#!/usr/bin/python
+#
+#===- clang-format-diff.py - ClangFormat Diff Reformatter ----*- python -*--===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+r"""
+ClangFormat Diff Reformatter
+============================
+
+This script reads input from a unified diff and reformats all the changed
+lines. This is useful to reformat all the lines touched by a specific patch.
+Example usage for git users:
+
+ git diff -U0 HEAD^ | clang-format-diff.py -p1
+
+"""
+
+import argparse
+import re
+import subprocess
+import sys
+
+
+# Change this to the full path if clang-format is not on the path.
+binary = 'clang-format'
+
+
+def getOffsetLength(filename, line_number, line_count):
+ """
+ Calculates the field offset and length based on line number and count.
+ """
+ offset = 0
+ length = 0
+ with open(filename, 'r') as f:
+ for line in f:
+ if line_number > 1:
+ offset += len(line)
+ line_number -= 1
+ elif line_count > 0:
+ length += len(line)
+ line_count -= 1
+ else:
+ break
+ return offset, length
+
+
+def formatRange(r, style):
+ """
+ Formats range 'r' according to style 'style'.
+ """
+ filename, line_number, line_count = r
+ # FIXME: Add other types containing C++/ObjC code.
+ if not (filename.endswith(".cpp") or filename.endswith(".cc") or
+ filename.endswith(".h")):
+ return
+
+ offset, length = getOffsetLength(filename, line_number, line_count)
+ with open(filename, 'r') as f:
+ text = f.read()
+ p = subprocess.Popen([binary, '-offset', str(offset), '-length', str(length),
+ '-style', style],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+ stdin=subprocess.PIPE)
+ stdout, stderr = p.communicate(input=text)
+ if stderr:
+ print stderr
+ return
+ if not stdout:
+ print 'Segfault occurred while formatting', filename
+ print 'Please report a bug on llvm.org/bugs.'
+ return
+ with open(filename, 'w') as f:
+ f.write(stdout)
+
+
+def main():
+ parser = argparse.ArgumentParser(description=
+ 'Reformat changed lines in diff')
+ parser.add_argument('-p', default=1,
+ help='strip the smallest prefix containing P slashes')
+ parser.add_argument('-style', default='LLVM',
+ help='formatting style to apply (LLVM, Google)')
+ args = parser.parse_args()
+
+ filename = None
+ ranges = []
+
+ for line in sys.stdin:
+ match = re.search('^\+\+\+\ (.*?/){%s}(\S*)' % args.p, line)
+ if match:
+ filename = match.group(2)
+ if filename == None:
+ continue
+
+ match = re.search('^@@.*\+(\d+)(,(\d+))?', line)
+ if match:
+ line_count = 1
+ if match.group(3):
+ line_count = int(match.group(3))
+ ranges.append((filename, int(match.group(1)), line_count))
+
+ # Reverse the ranges so that the reformatting does not influence file offsets.
+ for r in reversed(ranges):
+ # Do the actual formatting.
+ formatRange(r, args.style)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/tools/clang-format/clang-format.py b/tools/clang-format/clang-format.py
new file mode 100644
index 0000000..de92257
--- /dev/null
+++ b/tools/clang-format/clang-format.py
@@ -0,0 +1,60 @@
+# This file is a minimal clang-format vim-integration. To install:
+# - Change 'binary' if clang-format is not on the path (see below).
+# - Add to your .vimrc:
+#
+# map <C-I> :pyf <path-to-this-file>/clang-format.py<CR>
+# imap <C-I> <ESC>:pyf <path-to-this-file>/clang-format.py<CR>i
+#
+# The first line enables clang-format for NORMAL and VISUAL mode, the second
+# line adds support for INSERT mode. Change "C-I" to another binding if you
+# need clang-format on a different key (C-I stands for Ctrl+i).
+#
+# With this integration you can press the bound key and clang-format will
+# format the current line in NORMAL and INSERT mode or the selected region in
+# VISUAL mode. The line or region is extended to the next bigger syntactic
+# entity.
+#
+# It operates on the current, potentially unsaved buffer and does not create
+# or save any files. To revert a formatting, just undo.
+
+import vim
+import subprocess
+
+# Change this to the full path if clang-format is not on the path.
+binary = 'clang-format'
+
+# Get the current text.
+buf = vim.current.buffer
+text = "\n".join(buf)
+
+# Determine range to format.
+offset = int(vim.eval('line2byte(' +
+ str(vim.current.range.start + 1) + ')')) - 1
+length = int(vim.eval('line2byte(' +
+ str(vim.current.range.end + 2) + ')')) - offset - 2
+
+# Call formatter.
+p = subprocess.Popen([binary, '-offset', str(offset), '-length', str(length)],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+ stdin=subprocess.PIPE)
+stdout, stderr = p.communicate(input=text)
+
+# If successful, replace buffer contents.
+if stderr:
+ message = stderr.splitlines()[0]
+ parts = message.split(' ', 2)
+ if len(parts) > 2:
+ message = parts[2]
+ print 'Formatting failed: %s (total %d warnings, %d errors)' % (
+ message, stderr.count('warning:'), stderr.count('error:'))
+
+if not stdout:
+ print ('No output from clang-format (crashed?).\n' +
+ 'Please report to bugs.llvm.org.')
+elif stdout != text:
+ lines = stdout.split('\n')
+ for i in range(min(len(buf), len(lines))):
+ buf[i] = lines[i]
+ for line in lines[len(buf):]:
+ buf.append(line)
+ del buf[len(lines):]
diff --git a/tools/diagtool/CMakeLists.txt b/tools/diagtool/CMakeLists.txt
index a107cbd..8aa2d21 100644
--- a/tools/diagtool/CMakeLists.txt
+++ b/tools/diagtool/CMakeLists.txt
@@ -1,6 +1,7 @@
set(LLVM_LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
asmparser
+ bitreader
support
mc
)
diff --git a/tools/diagtool/DiagTool.cpp b/tools/diagtool/DiagTool.cpp
index 36e72a2..c3428c9 100644
--- a/tools/diagtool/DiagTool.cpp
+++ b/tools/diagtool/DiagTool.cpp
@@ -12,8 +12,8 @@
//===----------------------------------------------------------------------===//
#include "DiagTool.h"
-#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringMap.h"
#include <vector>
using namespace diagtool;
diff --git a/tools/diagtool/DiagTool.h b/tools/diagtool/DiagTool.h
index dcb6ac7..93d531b 100644
--- a/tools/diagtool/DiagTool.h
+++ b/tools/diagtool/DiagTool.h
@@ -15,8 +15,8 @@
#define DIAGTOOL_DIAGTOOL_H
#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/raw_ostream.h"
#include <string>
diff --git a/tools/diagtool/ListWarnings.cpp b/tools/diagtool/ListWarnings.cpp
index d554a2e..16837a1 100644
--- a/tools/diagtool/ListWarnings.cpp
+++ b/tools/diagtool/ListWarnings.cpp
@@ -14,11 +14,11 @@
#include "DiagTool.h"
#include "DiagnosticNames.h"
-#include "clang/Basic/Diagnostic.h"
-#include "llvm/Support/Format.h"
-#include "llvm/ADT/StringMap.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/Basic/AllDiagnostics.h"
+#include "clang/Basic/Diagnostic.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Format.h"
DEF_DIAGTOOL("list-warnings",
"List warnings and their corresponding flags",
diff --git a/tools/diagtool/Makefile b/tools/diagtool/Makefile
index b629712..94f9c76 100644
--- a/tools/diagtool/Makefile
+++ b/tools/diagtool/Makefile
@@ -17,7 +17,7 @@ TOOL_NO_EXPORTS := 1
NO_INSTALL = 1
include $(CLANG_LEVEL)/../../Makefile.config
-LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc
USEDLIBS = clangFrontend.a clangDriver.a clangSerialization.a clangParse.a \
clangSema.a clangAnalysis.a clangEdit.a clangAST.a clangLex.a \
clangBasic.a
diff --git a/tools/diagtool/ShowEnabledWarnings.cpp b/tools/diagtool/ShowEnabledWarnings.cpp
index abd69fd..bcc7520 100644
--- a/tools/diagtool/ShowEnabledWarnings.cpp
+++ b/tools/diagtool/ShowEnabledWarnings.cpp
@@ -71,8 +71,7 @@ createDiagnostics(unsigned int argc, char **argv) {
// Build the diagnostics parser
IntrusiveRefCntPtr<DiagnosticsEngine> FinalDiags =
- CompilerInstance::createDiagnostics(&Invocation->getDiagnosticOpts(),
- argc, argv);
+ CompilerInstance::createDiagnostics(&Invocation->getDiagnosticOpts());
if (!FinalDiags)
return NULL;
diff --git a/tools/diagtool/TreeView.cpp b/tools/diagtool/TreeView.cpp
index bf9f766..6298179 100644
--- a/tools/diagtool/TreeView.cpp
+++ b/tools/diagtool/TreeView.cpp
@@ -13,13 +13,13 @@
#include "DiagTool.h"
#include "DiagnosticNames.h"
+#include "clang/AST/ASTDiagnostic.h"
+#include "clang/Basic/AllDiagnostics.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
-#include "llvm/Support/Format.h"
-#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/DenseSet.h"
-#include "clang/AST/ASTDiagnostic.h"
-#include "clang/Basic/AllDiagnostics.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Format.h"
#include "llvm/Support/Process.h"
DEF_DIAGTOOL("tree",
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index 2545610..97ac7a4 100644
--- a/tools/driver/CMakeLists.txt
+++ b/tools/driver/CMakeLists.txt
@@ -3,6 +3,7 @@ set( LLVM_LINK_COMPONENTS
asmparser
bitreader
bitwriter
+ irreader
codegen
instrumentation
ipo
@@ -39,6 +40,7 @@ target_link_libraries(clang
)
set_target_properties(clang PROPERTIES VERSION ${CLANG_EXECUTABLE_VERSION})
+set_target_properties(clang PROPERTIES ENABLE_EXPORTS 1)
add_dependencies(clang clang-headers)
diff --git a/tools/driver/Makefile b/tools/driver/Makefile
index f07b0f2..cdf3b52 100644
--- a/tools/driver/Makefile
+++ b/tools/driver/Makefile
@@ -30,14 +30,24 @@ TOOL_INFO_PLIST := Info.plist
include $(CLANG_LEVEL)/../../Makefile.config
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader bitwriter codegen \
- instrumentation ipo linker selectiondag
+ instrumentation ipo irreader linker selectiondag
USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \
- clangSerialization.a clangCodeGen.a clangParse.a clangSema.a \
- clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a \
- clangStaticAnalyzerCore.a \
- clangAnalysis.a clangARCMigrate.a \
- clangRewriteFrontend.a clangRewriteCore.a \
- clangEdit.a clangAST.a clangLex.a clangBasic.a
+ clangSerialization.a clangCodeGen.a clangParse.a clangSema.a
+
+ifeq ($(ENABLE_CLANG_STATIC_ANALYZER),1)
+USEDLIBS += clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a \
+ clangStaticAnalyzerCore.a
+endif
+
+ifeq ($(ENABLE_CLANG_ARCMT),1)
+USEDLIBS += clangARCMigrate.a
+endif
+
+ifeq ($(ENABLE_CLANG_REWRITER),1)
+USEDLIBS += clangRewriteFrontend.a clangRewriteCore.a
+endif
+
+USEDLIBS += clangAnalysis.a clangEdit.a clangAST.a clangBasic.a clangLex.a
include $(CLANG_LEVEL)/Makefile
@@ -63,8 +73,3 @@ else
TOOL_INFO_BUILD_VERSION :=
endif
endif
-
-# Translate make variable to define when building a "production" clang.
-ifdef CLANG_IS_PRODUCTION
-CPP.Defines += -DCLANG_IS_PRODUCTION
-endif
diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp
index f196856..35cf5b8 100644
--- a/tools/driver/cc1_main.cpp
+++ b/tools/driver/cc1_main.cpp
@@ -15,9 +15,9 @@
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
-#include "clang/Driver/Options.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/OptTable.h"
+#include "clang/Driver/Options.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendDiagnostic.h"
@@ -25,12 +25,13 @@
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/FrontendTool/Utils.h"
#include "llvm/ADT/Statistic.h"
+#include "llvm/LinkAllPasses.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Signals.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/LinkAllPasses.h"
#include <cstdio>
using namespace clang;
@@ -38,13 +39,20 @@ using namespace clang;
// Main driver
//===----------------------------------------------------------------------===//
-static void LLVMErrorHandler(void *UserData, const std::string &Message) {
+static void LLVMErrorHandler(void *UserData, const std::string &Message,
+ bool GenCrashDiag) {
DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData);
Diags.Report(diag::err_fe_error_backend) << Message;
- // We cannot recover from llvm errors.
- exit(1);
+ // Run the interrupt handlers to make sure any special cleanups get done, in
+ // particular that we remove files registered with RemoveFileOnSignal.
+ llvm::sys::RunInterruptHandlers();
+
+ // We cannot recover from llvm errors. When reporting a fatal error, exit
+ // with status 70 to generate crash diagnostics. For BSD systems this is
+ // defined as an internal software error. Otherwise, exit with status 1.
+ exit(GenCrashDiag ? 70 : 1);
}
int cc1_main(const char **ArgBegin, const char **ArgEnd,
@@ -74,7 +82,7 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd,
CompilerInvocation::GetResourcesPath(Argv0, MainAddr);
// Create the actual diagnostics engine.
- Clang->createDiagnostics(ArgEnd - ArgBegin, const_cast<char**>(ArgBegin));
+ Clang->createDiagnostics();
if (!Clang->hasDiagnostics())
return 1;
diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp
index 5587e40..232ea2f 100644
--- a/tools/driver/cc1as_main.cpp
+++ b/tools/driver/cc1as_main.cpp
@@ -13,45 +13,45 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
-#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/CC1AsOptions.h"
+#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/OptTable.h"
#include "clang/Driver/Options.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
-#include "clang/Basic/DiagnosticOptions.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
-#include "llvm/MC/MCParser/MCAsmParser.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCParser/MCAsmParser.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
-#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCTargetAsmParser.h"
#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/Host.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/SourceMgr.h"
-#include "llvm/Support/Host.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
+#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
-#include "llvm/DataLayout.h"
using namespace clang;
using namespace clang::driver;
using namespace llvm;
@@ -83,6 +83,9 @@ struct AssemblerInvocation {
unsigned SaveTemporaryLabels : 1;
unsigned GenDwarfForAssembly : 1;
std::string DwarfDebugFlags;
+ std::string DwarfDebugProducer;
+ std::string DebugCompilationDir;
+ std::string MainFileName;
/// @}
/// @name Frontend Options
@@ -181,6 +184,9 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
Opts.SaveTemporaryLabels = Args->hasArg(OPT_L);
Opts.GenDwarfForAssembly = Args->hasArg(OPT_g);
Opts.DwarfDebugFlags = Args->getLastArgValue(OPT_dwarf_debug_flags);
+ Opts.DwarfDebugProducer = Args->getLastArgValue(OPT_dwarf_debug_producer);
+ Opts.DebugCompilationDir = Args->getLastArgValue(OPT_fdebug_compilation_dir);
+ Opts.MainFileName = Args->getLastArgValue(OPT_main_file_name);
// Frontend Options
if (Args->hasArg(OPT_INPUT)) {
@@ -305,6 +311,12 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
Ctx.setGenDwarfForAssembly(true);
if (!Opts.DwarfDebugFlags.empty())
Ctx.setDwarfDebugFlags(StringRef(Opts.DwarfDebugFlags));
+ if (!Opts.DwarfDebugProducer.empty())
+ Ctx.setDwarfDebugProducer(StringRef(Opts.DwarfDebugProducer));
+ if (!Opts.DebugCompilationDir.empty())
+ Ctx.setCompilationDir(Opts.DebugCompilationDir);
+ if (!Opts.MainFileName.empty())
+ Ctx.setMainFileName(StringRef(Opts.MainFileName));
// Build up the feature string from the target feature list.
std::string FS;
@@ -372,7 +384,8 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
return Success;
}
-static void LLVMErrorHandler(void *UserData, const std::string &Message) {
+static void LLVMErrorHandler(void *UserData, const std::string &Message,
+ bool GenCrashDiag) {
DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData);
Diags.Report(diag::err_fe_error_backend) << Message;
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index 81979ec..4c40da3 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -12,37 +12,37 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Driver/ArgList.h"
-#include "clang/Driver/Options.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
-#include "clang/Driver/Option.h"
+#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/OptTable.h"
+#include "clang/Driver/Option.h"
+#include "clang/Driver/Options.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/Utils.h"
-
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Host.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/Regex.h"
-#include "llvm/Support/Timer.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/Host.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Program.h"
+#include "llvm/Support/Regex.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
-#include <cctype>
using namespace clang;
using namespace clang::driver;
@@ -202,7 +202,7 @@ static void ExpandArgsFromBuf(const char *Arg,
std::string CurArg;
for (const char *P = Buf; ; ++P) {
- if (*P == '\0' || (isspace(*P) && InQuote == ' ')) {
+ if (*P == '\0' || (isWhitespace(*P) && InQuote == ' ')) {
if (!CurArg.empty()) {
if (CurArg[0] != '@') {
@@ -219,7 +219,7 @@ static void ExpandArgsFromBuf(const char *Arg,
continue;
}
- if (isspace(*P)) {
+ if (isWhitespace(*P)) {
if (InQuote != ' ')
CurArg.push_back(*P);
continue;
@@ -373,6 +373,32 @@ int main(int argc_, const char **argv_) {
}
}
+ // Handle QA_OVERRIDE_GCC3_OPTIONS and CCC_ADD_ARGS, used for editing a
+ // command line behind the scenes.
+ if (const char *OverrideStr = ::getenv("QA_OVERRIDE_GCC3_OPTIONS")) {
+ // FIXME: Driver shouldn't take extra initial argument.
+ ApplyQAOverride(argv, OverrideStr, SavedStrings);
+ } else if (const char *Cur = ::getenv("CCC_ADD_ARGS")) {
+ // FIXME: Driver shouldn't take extra initial argument.
+ std::vector<const char*> ExtraArgs;
+
+ for (;;) {
+ const char *Next = strchr(Cur, ',');
+
+ if (Next) {
+ ExtraArgs.push_back(SaveStringInSet(SavedStrings,
+ std::string(Cur, Next)));
+ Cur = Next + 1;
+ } else {
+ if (*Cur != '\0')
+ ExtraArgs.push_back(SaveStringInSet(SavedStrings, Cur));
+ break;
+ }
+ }
+
+ argv.insert(&argv[1], ExtraArgs.begin(), ExtraArgs.end());
+ }
+
llvm::sys::Path Path = GetExecutablePath(argv[0], CanonicalPrefixes);
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions;
@@ -391,19 +417,14 @@ int main(int argc_, const char **argv_) {
// DiagnosticOptions instance.
TextDiagnosticPrinter *DiagClient
= new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
- DiagClient->setPrefix(llvm::sys::path::stem(Path.str()));
+ DiagClient->setPrefix(llvm::sys::path::filename(Path.str()));
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
- ProcessWarningOptions(Diags, *DiagOpts);
+ ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false);
-#ifdef CLANG_IS_PRODUCTION
- const bool IsProduction = true;
-#else
- const bool IsProduction = false;
-#endif
Driver TheDriver(Path.str(), llvm::sys::getDefaultTargetTriple(),
- "a.out", IsProduction, Diags);
+ "a.out", Diags);
// Attempt to find the original path used to invoke the driver, to determine
// the installed path. We do this manually, because we want to support that
@@ -443,46 +464,34 @@ int main(int argc_, const char **argv_) {
if (TheDriver.CCLogDiagnostics)
TheDriver.CCLogDiagnosticsFilename = ::getenv("CC_LOG_DIAGNOSTICS_FILE");
- // Handle QA_OVERRIDE_GCC3_OPTIONS and CCC_ADD_ARGS, used for editing a
- // command line behind the scenes.
- if (const char *OverrideStr = ::getenv("QA_OVERRIDE_GCC3_OPTIONS")) {
- // FIXME: Driver shouldn't take extra initial argument.
- ApplyQAOverride(argv, OverrideStr, SavedStrings);
- } else if (const char *Cur = ::getenv("CCC_ADD_ARGS")) {
- // FIXME: Driver shouldn't take extra initial argument.
- std::vector<const char*> ExtraArgs;
-
- for (;;) {
- const char *Next = strchr(Cur, ',');
-
- if (Next) {
- ExtraArgs.push_back(SaveStringInSet(SavedStrings,
- std::string(Cur, Next)));
- Cur = Next + 1;
- } else {
- if (*Cur != '\0')
- ExtraArgs.push_back(SaveStringInSet(SavedStrings, Cur));
- break;
- }
- }
-
- argv.insert(&argv[1], ExtraArgs.begin(), ExtraArgs.end());
- }
-
OwningPtr<Compilation> C(TheDriver.BuildCompilation(argv));
int Res = 0;
- const Command *FailingCommand = 0;
+ SmallVector<std::pair<int, const Command *>, 4> FailingCommands;
if (C.get())
- Res = TheDriver.ExecuteCompilation(*C, FailingCommand);
+ Res = TheDriver.ExecuteCompilation(*C, FailingCommands);
// Force a crash to test the diagnostics.
- if(::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH"))
- Res = -1;
+ if (::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH")) {
+ Diags.Report(diag::err_drv_force_crash) << "FORCE_CLANG_DIAGNOSTICS_CRASH";
+ const Command *FailingCommand = 0;
+ FailingCommands.push_back(std::make_pair(-1, FailingCommand));
+ }
- // If result status is < 0, then the driver command signalled an error.
- // In this case, generate additional diagnostic information if possible.
- if (Res < 0)
- TheDriver.generateCompilationDiagnostics(*C, FailingCommand);
+ for (SmallVectorImpl< std::pair<int, const Command *> >::iterator it =
+ FailingCommands.begin(), ie = FailingCommands.end(); it != ie; ++it) {
+ int CommandRes = it->first;
+ const Command *FailingCommand = it->second;
+ if (!Res)
+ Res = CommandRes;
+
+ // If result status is < 0, then the driver command signalled an error.
+ // If result status is 70, then the driver command reported a fatal error.
+ // In these cases, generate additional diagnostic information if possible.
+ if (CommandRes < 0 || CommandRes == 70) {
+ TheDriver.generateCompilationDiagnostics(*C, FailingCommand);
+ break;
+ }
+ }
// If any timers were active but haven't been destroyed yet, print their
// results now. This happens in -disable-free mode.
@@ -498,5 +507,7 @@ int main(int argc_, const char **argv_) {
Res = 1;
#endif
+ // If we have multiple failing commands, we return the result of the first
+ // failing command.
return Res;
}
diff --git a/tools/libclang/ARCMigrate.cpp b/tools/libclang/ARCMigrate.cpp
index 5ee5cf6..3941794 100644
--- a/tools/libclang/ARCMigrate.cpp
+++ b/tools/libclang/ARCMigrate.cpp
@@ -12,7 +12,6 @@
//===----------------------------------------------------------------------===//
#include "clang-c/Index.h"
-
#include "CXString.h"
#include "clang/ARCMigrate/ARCMT.h"
#include "clang/Frontend/TextDiagnosticBuffer.h"
@@ -123,13 +122,11 @@ unsigned clang_remap_getNumFiles(CXRemapping map) {
void clang_remap_getFilenames(CXRemapping map, unsigned index,
CXString *original, CXString *transformed) {
if (original)
- *original = cxstring::createCXString(
- static_cast<Remap *>(map)->Vec[index].first,
- /*DupString =*/ true);
+ *original = cxstring::createDup(
+ static_cast<Remap *>(map)->Vec[index].first);
if (transformed)
- *transformed = cxstring::createCXString(
- static_cast<Remap *>(map)->Vec[index].second,
- /*DupString =*/ true);
+ *transformed = cxstring::createDup(
+ static_cast<Remap *>(map)->Vec[index].second);
}
void clang_remap_dispose(CXRemapping map) {
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 3a6c408..a81f1e4 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -13,56 +13,63 @@
//===----------------------------------------------------------------------===//
#include "CIndexer.h"
+#include "CIndexDiagnostic.h"
+#include "CLog.h"
#include "CXComment.h"
#include "CXCursor.h"
-#include "CXTranslationUnit.h"
+#include "CXSourceLocation.h"
#include "CXString.h"
+#include "CXTranslationUnit.h"
#include "CXType.h"
-#include "CXSourceLocation.h"
-#include "CIndexDiagnostic.h"
#include "CursorVisitor.h"
-
-#include "clang/Basic/Version.h"
-
+#include "SimpleFormatContext.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/Version.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
-#include "clang/Lex/Lexer.h"
#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/Lexer.h"
#include "clang/Lex/PreprocessingRecord.h"
#include "clang/Lex/Preprocessor.h"
-#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
-#include "llvm/Support/SaveAndRestore.h"
+#include "llvm/Config/config.h"
+#include "llvm/Support/Compiler.h"
#include "llvm/Support/CrashRecoveryContext.h"
-#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Format.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/Timer.h"
#include "llvm/Support/Mutex.h"
+#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Program.h"
+#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/Threading.h"
-#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
+
+#if HAVE_PTHREAD_H
+#include <pthread.h>
+#endif
using namespace clang;
using namespace clang::cxcursor;
-using namespace clang::cxstring;
using namespace clang::cxtu;
using namespace clang::cxindex;
-CXTranslationUnit cxtu::MakeCXTranslationUnit(CIndexer *CIdx, ASTUnit *TU) {
- if (!TU)
+CXTranslationUnit cxtu::MakeCXTranslationUnit(CIndexer *CIdx, ASTUnit *AU) {
+ if (!AU)
return 0;
CXTranslationUnit D = new CXTranslationUnitImpl();
D->CIdx = CIdx;
- D->TUData = TU;
- D->StringPool = createCXStringPool();
+ D->TheASTUnit = AU;
+ D->StringPool = new cxstring::CXStringPool();
D->Diagnostics = 0;
D->OverridenCursorsPool = createOverridenCXCursorsPool();
+ D->FormatContext = 0;
+ D->FormatInMemoryUniqueId = 0;
return D;
}
@@ -122,9 +129,11 @@ CXSourceRange cxloc::translateSourceRange(const SourceManager &SM,
EndLoc = EndLoc.getLocWithOffset(Length);
}
- CXSourceRange Result = { { (void *)&SM, (void *)&LangOpts },
- R.getBegin().getRawEncoding(),
- EndLoc.getRawEncoding() };
+ CXSourceRange Result = {
+ { &SM, &LangOpts },
+ R.getBegin().getRawEncoding(),
+ EndLoc.getRawEncoding()
+ };
return Result;
}
@@ -155,7 +164,7 @@ bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) {
return false;
if (clang_isDeclaration(Cursor.kind)) {
- Decl *D = getCursorDecl(Cursor);
+ const Decl *D = getCursorDecl(Cursor);
if (!D) {
assert(0 && "Invalid declaration cursor");
return true; // abort.
@@ -214,11 +223,11 @@ static bool visitPreprocessedEntitiesInRange(SourceRange R,
PPRec, FID);
}
-void CursorVisitor::visitFileRegion() {
+bool CursorVisitor::visitFileRegion() {
if (RegionOfInterest.isInvalid())
- return;
+ return false;
- ASTUnit *Unit = static_cast<ASTUnit *>(TU->TUData);
+ ASTUnit *Unit = cxtu::getASTUnit(TU);
SourceManager &SM = Unit->getSourceManager();
std::pair<FileID, unsigned>
@@ -234,7 +243,7 @@ void CursorVisitor::visitFileRegion() {
assert(Begin.first == End.first);
if (Begin.second > End.second)
- return;
+ return false;
FileID File = Begin.first;
unsigned Offset = Begin.second;
@@ -242,12 +251,15 @@ void CursorVisitor::visitFileRegion() {
if (!VisitDeclsOnly && !VisitPreprocessorLast)
if (visitPreprocessedEntitiesInRegion())
- return; // visitation break.
+ return true; // visitation break.
- visitDeclsFromFileRegion(File, Offset, Length);
+ if (visitDeclsFromFileRegion(File, Offset, Length))
+ return true; // visitation break.
if (!VisitDeclsOnly && VisitPreprocessorLast)
- visitPreprocessedEntitiesInRegion();
+ return visitPreprocessedEntitiesInRegion();
+
+ return false;
}
static bool isInLexicalContext(Decl *D, DeclContext *DC) {
@@ -262,9 +274,9 @@ static bool isInLexicalContext(Decl *D, DeclContext *DC) {
return false;
}
-void CursorVisitor::visitDeclsFromFileRegion(FileID File,
+bool CursorVisitor::visitDeclsFromFileRegion(FileID File,
unsigned Offset, unsigned Length) {
- ASTUnit *Unit = static_cast<ASTUnit *>(TU->TUData);
+ ASTUnit *Unit = cxtu::getASTUnit(TU);
SourceManager &SM = Unit->getSourceManager();
SourceRange Range = RegionOfInterest;
@@ -277,7 +289,7 @@ void CursorVisitor::visitDeclsFromFileRegion(FileID File,
bool Invalid = false;
const SrcMgr::SLocEntry &SLEntry = SM.getSLocEntry(File, &Invalid);
if (Invalid)
- return;
+ return false;
SourceLocation Outer;
if (SLEntry.isFile())
@@ -285,7 +297,7 @@ void CursorVisitor::visitDeclsFromFileRegion(FileID File,
else
Outer = SLEntry.getExpansion().getExpansionLocStart();
if (Outer.isInvalid())
- return;
+ return false;
llvm::tie(File, Offset) = SM.getDecomposedExpansionLoc(Outer);
Length = 0;
@@ -328,11 +340,11 @@ void CursorVisitor::visitDeclsFromFileRegion(FileID File,
}
if (Visit(MakeCXCursor(D, TU, Range), /*CheckedRegionOfInterest=*/true))
- break;
+ return true; // visitation break.
}
if (VisitedAtLeastOnce)
- return;
+ return false;
// No Decls overlapped with the range. Move up the lexical context until there
// is a context that contains the range or we reach the translation unit
@@ -347,12 +359,14 @@ void CursorVisitor::visitDeclsFromFileRegion(FileID File,
break;
if (RangeCompare(SM, CurDeclRange, Range) == RangeOverlap) {
- Visit(MakeCXCursor(D, TU, Range), /*CheckedRegionOfInterest=*/true);
- break;
+ if (Visit(MakeCXCursor(D, TU, Range), /*CheckedRegionOfInterest=*/true))
+ return true; // visitation break.
}
DC = D->getLexicalDeclContext();
}
+
+ return false;
}
bool CursorVisitor::visitPreprocessedEntitiesInRegion() {
@@ -453,7 +467,7 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) {
SetParentRAII SetParent(Parent, StmtParent, Cursor);
if (clang_isDeclaration(Cursor.kind)) {
- Decl *D = getCursorDecl(Cursor);
+ Decl *D = const_cast<Decl *>(getCursorDecl(Cursor));
if (!D)
return false;
@@ -461,22 +475,22 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) {
}
if (clang_isStatement(Cursor.kind)) {
- if (Stmt *S = getCursorStmt(Cursor))
+ if (const Stmt *S = getCursorStmt(Cursor))
return Visit(S);
return false;
}
if (clang_isExpression(Cursor.kind)) {
- if (Expr *E = getCursorExpr(Cursor))
+ if (const Expr *E = getCursorExpr(Cursor))
return Visit(E);
return false;
}
if (clang_isTranslationUnit(Cursor.kind)) {
- CXTranslationUnit tu = getCursorTU(Cursor);
- ASTUnit *CXXUnit = static_cast<ASTUnit*>(tu->TUData);
+ CXTranslationUnit TU = getCursorTU(Cursor);
+ ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
int VisitOrder[2] = { VisitPreprocessorLast, !VisitPreprocessorLast };
for (unsigned I = 0; I != 2; ++I) {
@@ -486,7 +500,7 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) {
for (ASTUnit::top_level_iterator TL = CXXUnit->top_level_begin(),
TLEnd = CXXUnit->top_level_end();
TL != TLEnd; ++TL) {
- if (Visit(MakeCXCursor(*TL, tu, RegionOfInterest), true))
+ if (Visit(MakeCXCursor(*TL, TU, RegionOfInterest), true))
return true;
}
} else if (VisitDeclContext(
@@ -504,7 +518,7 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) {
}
if (Cursor.kind == CXCursor_CXXBaseSpecifier) {
- if (CXXBaseSpecifier *Base = getCursorCXXBaseSpecifier(Cursor)) {
+ if (const CXXBaseSpecifier *Base = getCursorCXXBaseSpecifier(Cursor)) {
if (TypeSourceInfo *BaseTSInfo = Base->getTypeSourceInfo()) {
return Visit(BaseTSInfo->getTypeLoc());
}
@@ -512,13 +526,27 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) {
}
if (Cursor.kind == CXCursor_IBOutletCollectionAttr) {
- IBOutletCollectionAttr *A =
+ const IBOutletCollectionAttr *A =
cast<IBOutletCollectionAttr>(cxcursor::getCursorAttr(Cursor));
if (const ObjCInterfaceType *InterT = A->getInterface()->getAs<ObjCInterfaceType>())
return Visit(cxcursor::MakeCursorObjCClassRef(InterT->getInterface(),
A->getInterfaceLoc(), TU));
}
+ // If pointing inside a macro definition, check if the token is an identifier
+ // that was ever defined as a macro. In such a case, create a "pseudo" macro
+ // expansion cursor for that token.
+ SourceLocation BeginLoc = RegionOfInterest.getBegin();
+ if (Cursor.kind == CXCursor_MacroDefinition &&
+ BeginLoc == RegionOfInterest.getEnd()) {
+ SourceLocation Loc = AU->mapLocationToPreamble(BeginLoc);
+ const MacroInfo *MI =
+ getMacroInfo(cxcursor::getCursorMacroDefinition(Cursor), TU);
+ if (MacroDefinition *MacroDef =
+ checkForMacroInMacroDefinition(MI, Loc, TU))
+ return Visit(cxcursor::MakeMacroExpansionCursor(MacroDef, BeginLoc, TU));
+ }
+
// Nothing to visit at the moment.
return false;
}
@@ -534,16 +562,16 @@ bool CursorVisitor::VisitBlockDecl(BlockDecl *B) {
return false;
}
-llvm::Optional<bool> CursorVisitor::shouldVisitCursor(CXCursor Cursor) {
+Optional<bool> CursorVisitor::shouldVisitCursor(CXCursor Cursor) {
if (RegionOfInterest.isValid()) {
SourceRange Range = getFullCursorExtent(Cursor, AU->getSourceManager());
if (Range.isInvalid())
- return llvm::Optional<bool>();
+ return None;
switch (CompareRegionOfInterest(Range)) {
case RangeBefore:
// This declaration comes before the region of interest; skip it.
- return llvm::Optional<bool>();
+ return None;
case RangeAfter:
// This declaration comes after the region of interest; we're done.
@@ -594,7 +622,7 @@ bool CursorVisitor::VisitDeclContext(DeclContext *DC) {
Cursor = MakeCursorObjCProtocolRef(PD, PD->getLocation(), TU);
}
- const llvm::Optional<bool> &V = shouldVisitCursor(Cursor);
+ const Optional<bool> &V = shouldVisitCursor(Cursor);
if (!V.hasValue())
continue;
if (!V.getValue())
@@ -648,10 +676,10 @@ bool CursorVisitor::VisitClassTemplateSpecializationDecl(
// Visit the template arguments used in the specialization.
if (TypeSourceInfo *SpecType = D->getTypeAsWritten()) {
TypeLoc TL = SpecType->getTypeLoc();
- if (TemplateSpecializationTypeLoc *TSTLoc
- = dyn_cast<TemplateSpecializationTypeLoc>(&TL)) {
- for (unsigned I = 0, N = TSTLoc->getNumArgs(); I != N; ++I)
- if (VisitTemplateArgumentLoc(TSTLoc->getArgLoc(I)))
+ if (TemplateSpecializationTypeLoc TSTLoc =
+ TL.getAs<TemplateSpecializationTypeLoc>()) {
+ for (unsigned I = 0, N = TSTLoc.getNumArgs(); I != N; ++I)
+ if (VisitTemplateArgumentLoc(TSTLoc.getArgLoc(I)))
return true;
}
}
@@ -727,12 +755,12 @@ bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) {
// Visit the function declaration's syntactic components in the order
// written. This requires a bit of work.
TypeLoc TL = TSInfo->getTypeLoc().IgnoreParens();
- FunctionTypeLoc *FTL = dyn_cast<FunctionTypeLoc>(&TL);
+ FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>();
// If we have a function declared directly (without the use of a typedef),
// visit just the return type. Otherwise, just visit the function's type
// now.
- if ((FTL && !isa<CXXConversionDecl>(ND) && Visit(FTL->getResultLoc())) ||
+ if ((FTL && !isa<CXXConversionDecl>(ND) && Visit(FTL.getResultLoc())) ||
(!FTL && Visit(TL)))
return true;
@@ -748,7 +776,7 @@ bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) {
// FIXME: Visit explicitly-specified template arguments!
// Visit the function parameters, if we have a function type.
- if (FTL && VisitFunctionTypeLoc(*FTL, true))
+ if (FTL && VisitFunctionTypeLoc(FTL, true))
return true;
// FIXME: Attributes?
@@ -958,7 +986,7 @@ bool CursorVisitor::VisitObjCContainerDecl(ObjCContainerDecl *D) {
for (SmallVectorImpl<Decl*>::iterator I = DeclsInContainer.begin(),
E = DeclsInContainer.end(); I != E; ++I) {
CXCursor Cursor = MakeCXCursor(*I, TU, RegionOfInterest);
- const llvm::Optional<bool> &V = shouldVisitCursor(Cursor);
+ const Optional<bool> &V = shouldVisitCursor(Cursor);
if (!V.hasValue())
continue;
if (!V.getValue())
@@ -1369,6 +1397,14 @@ bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
case BuiltinType::Void:
case BuiltinType::NullPtr:
case BuiltinType::Dependent:
+ case BuiltinType::OCLImage1d:
+ case BuiltinType::OCLImage1dArray:
+ case BuiltinType::OCLImage1dBuffer:
+ case BuiltinType::OCLImage2d:
+ case BuiltinType::OCLImage2dArray:
+ case BuiltinType::OCLImage3d:
+ case BuiltinType::OCLSampler:
+ case BuiltinType::OCLEvent:
#define BUILTIN_TYPE(Id, SingletonId)
#define SIGNED_TYPE(Id, SingletonId) case BuiltinType::Id:
#define UNSIGNED_TYPE(Id, SingletonId) case BuiltinType::Id:
@@ -1629,9 +1665,10 @@ namespace {
#define DEF_JOB(NAME, DATA, KIND)\
class NAME : public VisitorJob {\
public:\
- NAME(DATA *d, CXCursor parent) : VisitorJob(parent, VisitorJob::KIND, d) {} \
+ NAME(const DATA *d, CXCursor parent) : \
+ VisitorJob(parent, VisitorJob::KIND, d) {} \
static bool classof(const VisitorJob *VJ) { return VJ->getKind() == KIND; }\
- DATA *get() const { return static_cast<DATA*>(data[0]); }\
+ const DATA *get() const { return static_cast<const DATA*>(data[0]); }\
};
DEF_JOB(StmtVisit, Stmt, StmtVisitKind)
@@ -1647,13 +1684,13 @@ DEF_JOB(PostChildrenVisit, void, PostChildrenVisitKind)
class DeclVisit : public VisitorJob {
public:
- DeclVisit(Decl *d, CXCursor parent, bool isFirst) :
+ DeclVisit(const Decl *D, CXCursor parent, bool isFirst) :
VisitorJob(parent, VisitorJob::DeclVisitKind,
- d, isFirst ? (void*) 1 : (void*) 0) {}
+ D, isFirst ? (void*) 1 : (void*) 0) {}
static bool classof(const VisitorJob *VJ) {
return VJ->getKind() == DeclVisitKind;
}
- Decl *get() const { return static_cast<Decl*>(data[0]); }
+ const Decl *get() const { return static_cast<const Decl *>(data[0]); }
bool isFirst() const { return data[1] ? true : false; }
};
class TypeLocVisit : public VisitorJob {
@@ -1668,7 +1705,7 @@ public:
TypeLoc get() const {
QualType T = QualType::getFromOpaquePtr(data[0]);
- return TypeLoc(T, data[1]);
+ return TypeLoc(T, const_cast<void *>(data[1]));
}
};
@@ -1681,7 +1718,9 @@ public:
static bool classof(const VisitorJob *VJ) {
return VJ->getKind() == VisitorJob::LabelRefVisitKind;
}
- LabelDecl *get() const { return static_cast<LabelDecl*>(data[0]); }
+ const LabelDecl *get() const {
+ return static_cast<const LabelDecl *>(data[0]);
+ }
SourceLocation getLoc() const {
return SourceLocation::getFromPtrEncoding(data[1]); }
};
@@ -1698,20 +1737,22 @@ public:
}
NestedNameSpecifierLoc get() const {
- return NestedNameSpecifierLoc(static_cast<NestedNameSpecifier*>(data[0]),
- data[1]);
+ return NestedNameSpecifierLoc(
+ const_cast<NestedNameSpecifier *>(
+ static_cast<const NestedNameSpecifier *>(data[0])),
+ const_cast<void *>(data[1]));
}
};
class DeclarationNameInfoVisit : public VisitorJob {
public:
- DeclarationNameInfoVisit(Stmt *S, CXCursor parent)
+ DeclarationNameInfoVisit(const Stmt *S, CXCursor parent)
: VisitorJob(parent, VisitorJob::DeclarationNameInfoVisitKind, S) {}
static bool classof(const VisitorJob *VJ) {
return VJ->getKind() == VisitorJob::DeclarationNameInfoVisitKind;
}
DeclarationNameInfo get() const {
- Stmt *S = static_cast<Stmt*>(data[0]);
+ const Stmt *S = static_cast<const Stmt *>(data[0]);
switch (S->getStmtClass()) {
default:
llvm_unreachable("Unhandled Stmt");
@@ -1726,85 +1767,85 @@ public:
};
class MemberRefVisit : public VisitorJob {
public:
- MemberRefVisit(FieldDecl *D, SourceLocation L, CXCursor parent)
+ MemberRefVisit(const FieldDecl *D, SourceLocation L, CXCursor parent)
: VisitorJob(parent, VisitorJob::MemberRefVisitKind, D,
L.getPtrEncoding()) {}
static bool classof(const VisitorJob *VJ) {
return VJ->getKind() == VisitorJob::MemberRefVisitKind;
}
- FieldDecl *get() const {
- return static_cast<FieldDecl*>(data[0]);
+ const FieldDecl *get() const {
+ return static_cast<const FieldDecl *>(data[0]);
}
SourceLocation getLoc() const {
return SourceLocation::getFromRawEncoding((unsigned)(uintptr_t) data[1]);
}
};
-class EnqueueVisitor : public StmtVisitor<EnqueueVisitor, void> {
+class EnqueueVisitor : public ConstStmtVisitor<EnqueueVisitor, void> {
VisitorWorkList &WL;
CXCursor Parent;
public:
EnqueueVisitor(VisitorWorkList &wl, CXCursor parent)
: WL(wl), Parent(parent) {}
- void VisitAddrLabelExpr(AddrLabelExpr *E);
- void VisitBlockExpr(BlockExpr *B);
- void VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
- void VisitCompoundStmt(CompoundStmt *S);
- void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { /* Do nothing. */ }
- void VisitMSDependentExistsStmt(MSDependentExistsStmt *S);
- void VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E);
- void VisitCXXNewExpr(CXXNewExpr *E);
- void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E);
- void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E);
- void VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E);
- void VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E);
- void VisitCXXTypeidExpr(CXXTypeidExpr *E);
- void VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E);
- void VisitCXXUuidofExpr(CXXUuidofExpr *E);
- void VisitCXXCatchStmt(CXXCatchStmt *S);
- void VisitDeclRefExpr(DeclRefExpr *D);
- void VisitDeclStmt(DeclStmt *S);
- void VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E);
- void VisitDesignatedInitExpr(DesignatedInitExpr *E);
- void VisitExplicitCastExpr(ExplicitCastExpr *E);
- void VisitForStmt(ForStmt *FS);
- void VisitGotoStmt(GotoStmt *GS);
- void VisitIfStmt(IfStmt *If);
- void VisitInitListExpr(InitListExpr *IE);
- void VisitMemberExpr(MemberExpr *M);
- void VisitOffsetOfExpr(OffsetOfExpr *E);
- void VisitObjCEncodeExpr(ObjCEncodeExpr *E);
- void VisitObjCMessageExpr(ObjCMessageExpr *M);
- void VisitOverloadExpr(OverloadExpr *E);
- void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E);
- void VisitStmt(Stmt *S);
- void VisitSwitchStmt(SwitchStmt *S);
- void VisitWhileStmt(WhileStmt *W);
- void VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E);
- void VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E);
- void VisitTypeTraitExpr(TypeTraitExpr *E);
- void VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E);
- void VisitExpressionTraitExpr(ExpressionTraitExpr *E);
- void VisitUnresolvedMemberExpr(UnresolvedMemberExpr *U);
- void VisitVAArgExpr(VAArgExpr *E);
- void VisitSizeOfPackExpr(SizeOfPackExpr *E);
- void VisitPseudoObjectExpr(PseudoObjectExpr *E);
- void VisitOpaqueValueExpr(OpaqueValueExpr *E);
- void VisitLambdaExpr(LambdaExpr *E);
-
+ void VisitAddrLabelExpr(const AddrLabelExpr *E);
+ void VisitBlockExpr(const BlockExpr *B);
+ void VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
+ void VisitCompoundStmt(const CompoundStmt *S);
+ void VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) { /* Do nothing. */ }
+ void VisitMSDependentExistsStmt(const MSDependentExistsStmt *S);
+ void VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr *E);
+ void VisitCXXNewExpr(const CXXNewExpr *E);
+ void VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E);
+ void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *E);
+ void VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *E);
+ void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *E);
+ void VisitCXXTypeidExpr(const CXXTypeidExpr *E);
+ void VisitCXXUnresolvedConstructExpr(const CXXUnresolvedConstructExpr *E);
+ void VisitCXXUuidofExpr(const CXXUuidofExpr *E);
+ void VisitCXXCatchStmt(const CXXCatchStmt *S);
+ void VisitDeclRefExpr(const DeclRefExpr *D);
+ void VisitDeclStmt(const DeclStmt *S);
+ void VisitDependentScopeDeclRefExpr(const DependentScopeDeclRefExpr *E);
+ void VisitDesignatedInitExpr(const DesignatedInitExpr *E);
+ void VisitExplicitCastExpr(const ExplicitCastExpr *E);
+ void VisitForStmt(const ForStmt *FS);
+ void VisitGotoStmt(const GotoStmt *GS);
+ void VisitIfStmt(const IfStmt *If);
+ void VisitInitListExpr(const InitListExpr *IE);
+ void VisitMemberExpr(const MemberExpr *M);
+ void VisitOffsetOfExpr(const OffsetOfExpr *E);
+ void VisitObjCEncodeExpr(const ObjCEncodeExpr *E);
+ void VisitObjCMessageExpr(const ObjCMessageExpr *M);
+ void VisitOverloadExpr(const OverloadExpr *E);
+ void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);
+ void VisitStmt(const Stmt *S);
+ void VisitSwitchStmt(const SwitchStmt *S);
+ void VisitWhileStmt(const WhileStmt *W);
+ void VisitUnaryTypeTraitExpr(const UnaryTypeTraitExpr *E);
+ void VisitBinaryTypeTraitExpr(const BinaryTypeTraitExpr *E);
+ void VisitTypeTraitExpr(const TypeTraitExpr *E);
+ void VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E);
+ void VisitExpressionTraitExpr(const ExpressionTraitExpr *E);
+ void VisitUnresolvedMemberExpr(const UnresolvedMemberExpr *U);
+ void VisitVAArgExpr(const VAArgExpr *E);
+ void VisitSizeOfPackExpr(const SizeOfPackExpr *E);
+ void VisitPseudoObjectExpr(const PseudoObjectExpr *E);
+ void VisitOpaqueValueExpr(const OpaqueValueExpr *E);
+ void VisitLambdaExpr(const LambdaExpr *E);
+
private:
- void AddDeclarationNameInfo(Stmt *S);
+ void AddDeclarationNameInfo(const Stmt *S);
void AddNestedNameSpecifierLoc(NestedNameSpecifierLoc Qualifier);
void AddExplicitTemplateArgs(const ASTTemplateArgumentListInfo *A);
- void AddMemberRef(FieldDecl *D, SourceLocation L);
- void AddStmt(Stmt *S);
- void AddDecl(Decl *D, bool isFirst = true);
+ void AddMemberRef(const FieldDecl *D, SourceLocation L);
+ void AddStmt(const Stmt *S);
+ void AddDecl(const Decl *D, bool isFirst = true);
void AddTypeLoc(TypeSourceInfo *TI);
- void EnqueueChildren(Stmt *S);
+ void EnqueueChildren(const Stmt *S);
};
} // end anonyous namespace
-void EnqueueVisitor::AddDeclarationNameInfo(Stmt *S) {
+void EnqueueVisitor::AddDeclarationNameInfo(const Stmt *S) {
// 'S' should always be non-null, since it comes from the
// statement we are visiting.
WL.push_back(DeclarationNameInfoVisit(S, Parent));
@@ -1816,21 +1857,20 @@ EnqueueVisitor::AddNestedNameSpecifierLoc(NestedNameSpecifierLoc Qualifier) {
WL.push_back(NestedNameSpecifierLocVisit(Qualifier, Parent));
}
-void EnqueueVisitor::AddStmt(Stmt *S) {
+void EnqueueVisitor::AddStmt(const Stmt *S) {
if (S)
WL.push_back(StmtVisit(S, Parent));
}
-void EnqueueVisitor::AddDecl(Decl *D, bool isFirst) {
+void EnqueueVisitor::AddDecl(const Decl *D, bool isFirst) {
if (D)
WL.push_back(DeclVisit(D, Parent, isFirst));
}
void EnqueueVisitor::
AddExplicitTemplateArgs(const ASTTemplateArgumentListInfo *A) {
if (A)
- WL.push_back(ExplicitTemplateArgsVisit(
- const_cast<ASTTemplateArgumentListInfo*>(A), Parent));
+ WL.push_back(ExplicitTemplateArgsVisit(A, Parent));
}
-void EnqueueVisitor::AddMemberRef(FieldDecl *D, SourceLocation L) {
+void EnqueueVisitor::AddMemberRef(const FieldDecl *D, SourceLocation L) {
if (D)
WL.push_back(MemberRefVisit(D, L, Parent));
}
@@ -1838,9 +1878,9 @@ void EnqueueVisitor::AddTypeLoc(TypeSourceInfo *TI) {
if (TI)
WL.push_back(TypeLocVisit(TI->getTypeLoc(), Parent));
}
-void EnqueueVisitor::EnqueueChildren(Stmt *S) {
+void EnqueueVisitor::EnqueueChildren(const Stmt *S) {
unsigned size = WL.size();
- for (Stmt::child_range Child = S->children(); Child; ++Child) {
+ for (Stmt::const_child_range Child = S->children(); Child; ++Child) {
AddStmt(*Child);
}
if (size == WL.size())
@@ -1850,24 +1890,24 @@ void EnqueueVisitor::EnqueueChildren(Stmt *S) {
VisitorWorkList::iterator I = WL.begin() + size, E = WL.end();
std::reverse(I, E);
}
-void EnqueueVisitor::VisitAddrLabelExpr(AddrLabelExpr *E) {
+void EnqueueVisitor::VisitAddrLabelExpr(const AddrLabelExpr *E) {
WL.push_back(LabelRefVisit(E->getLabel(), E->getLabelLoc(), Parent));
}
-void EnqueueVisitor::VisitBlockExpr(BlockExpr *B) {
+void EnqueueVisitor::VisitBlockExpr(const BlockExpr *B) {
AddDecl(B->getBlockDecl());
}
-void EnqueueVisitor::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
+void EnqueueVisitor::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
EnqueueChildren(E);
AddTypeLoc(E->getTypeSourceInfo());
}
-void EnqueueVisitor::VisitCompoundStmt(CompoundStmt *S) {
- for (CompoundStmt::reverse_body_iterator I = S->body_rbegin(),
+void EnqueueVisitor::VisitCompoundStmt(const CompoundStmt *S) {
+ for (CompoundStmt::const_reverse_body_iterator I = S->body_rbegin(),
E = S->body_rend(); I != E; ++I) {
AddStmt(*I);
}
}
void EnqueueVisitor::
-VisitMSDependentExistsStmt(MSDependentExistsStmt *S) {
+VisitMSDependentExistsStmt(const MSDependentExistsStmt *S) {
AddStmt(S->getSubStmt());
AddDeclarationNameInfo(S);
if (NestedNameSpecifierLoc QualifierLoc = S->getQualifierLoc())
@@ -1875,7 +1915,7 @@ VisitMSDependentExistsStmt(MSDependentExistsStmt *S) {
}
void EnqueueVisitor::
-VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) {
+VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr *E) {
AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs());
AddDeclarationNameInfo(E);
if (NestedNameSpecifierLoc QualifierLoc = E->getQualifierLoc())
@@ -1883,7 +1923,7 @@ VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) {
if (!E->isImplicitAccess())
AddStmt(E->getBase());
}
-void EnqueueVisitor::VisitCXXNewExpr(CXXNewExpr *E) {
+void EnqueueVisitor::VisitCXXNewExpr(const CXXNewExpr *E) {
// Enqueue the initializer , if any.
AddStmt(E->getInitializer());
// Enqueue the array size, if any.
@@ -1894,13 +1934,14 @@ void EnqueueVisitor::VisitCXXNewExpr(CXXNewExpr *E) {
for (unsigned I = E->getNumPlacementArgs(); I > 0; --I)
AddStmt(E->getPlacementArg(I-1));
}
-void EnqueueVisitor::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *CE) {
+void EnqueueVisitor::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *CE) {
for (unsigned I = CE->getNumArgs(); I > 1 /* Yes, this is 1 */; --I)
AddStmt(CE->getArg(I-1));
AddStmt(CE->getCallee());
AddStmt(CE->getArg(0));
}
-void EnqueueVisitor::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
+void EnqueueVisitor::VisitCXXPseudoDestructorExpr(
+ const CXXPseudoDestructorExpr *E) {
// Visit the name of the type being destroyed.
AddTypeLoc(E->getDestroyedTypeInfo());
// Visit the scope type that looks disturbingly like the nested-name-specifier
@@ -1912,50 +1953,53 @@ void EnqueueVisitor::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
// Visit base expression.
AddStmt(E->getBase());
}
-void EnqueueVisitor::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) {
+void EnqueueVisitor::VisitCXXScalarValueInitExpr(
+ const CXXScalarValueInitExpr *E) {
AddTypeLoc(E->getTypeSourceInfo());
}
-void EnqueueVisitor::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E) {
+void EnqueueVisitor::VisitCXXTemporaryObjectExpr(
+ const CXXTemporaryObjectExpr *E) {
EnqueueChildren(E);
AddTypeLoc(E->getTypeSourceInfo());
}
-void EnqueueVisitor::VisitCXXTypeidExpr(CXXTypeidExpr *E) {
+void EnqueueVisitor::VisitCXXTypeidExpr(const CXXTypeidExpr *E) {
EnqueueChildren(E);
if (E->isTypeOperand())
AddTypeLoc(E->getTypeOperandSourceInfo());
}
-void EnqueueVisitor::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr
- *E) {
+void EnqueueVisitor::VisitCXXUnresolvedConstructExpr(
+ const CXXUnresolvedConstructExpr *E) {
EnqueueChildren(E);
AddTypeLoc(E->getTypeSourceInfo());
}
-void EnqueueVisitor::VisitCXXUuidofExpr(CXXUuidofExpr *E) {
+void EnqueueVisitor::VisitCXXUuidofExpr(const CXXUuidofExpr *E) {
EnqueueChildren(E);
if (E->isTypeOperand())
AddTypeLoc(E->getTypeOperandSourceInfo());
}
-void EnqueueVisitor::VisitCXXCatchStmt(CXXCatchStmt *S) {
+void EnqueueVisitor::VisitCXXCatchStmt(const CXXCatchStmt *S) {
EnqueueChildren(S);
AddDecl(S->getExceptionDecl());
}
-void EnqueueVisitor::VisitDeclRefExpr(DeclRefExpr *DR) {
+void EnqueueVisitor::VisitDeclRefExpr(const DeclRefExpr *DR) {
if (DR->hasExplicitTemplateArgs()) {
AddExplicitTemplateArgs(&DR->getExplicitTemplateArgs());
}
WL.push_back(DeclRefExprParts(DR, Parent));
}
-void EnqueueVisitor::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
+void EnqueueVisitor::VisitDependentScopeDeclRefExpr(
+ const DependentScopeDeclRefExpr *E) {
AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs());
AddDeclarationNameInfo(E);
AddNestedNameSpecifierLoc(E->getQualifierLoc());
}
-void EnqueueVisitor::VisitDeclStmt(DeclStmt *S) {
+void EnqueueVisitor::VisitDeclStmt(const DeclStmt *S) {
unsigned size = WL.size();
bool isFirst = true;
- for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
+ for (DeclStmt::const_decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
D != DEnd; ++D) {
AddDecl(*D, isFirst);
isFirst = false;
@@ -1967,10 +2011,10 @@ void EnqueueVisitor::VisitDeclStmt(DeclStmt *S) {
VisitorWorkList::iterator I = WL.begin() + size, E = WL.end();
std::reverse(I, E);
}
-void EnqueueVisitor::VisitDesignatedInitExpr(DesignatedInitExpr *E) {
+void EnqueueVisitor::VisitDesignatedInitExpr(const DesignatedInitExpr *E) {
AddStmt(E->getInit());
typedef DesignatedInitExpr::Designator Designator;
- for (DesignatedInitExpr::reverse_designators_iterator
+ for (DesignatedInitExpr::const_reverse_designators_iterator
D = E->designators_rbegin(), DEnd = E->designators_rend();
D != DEnd; ++D) {
if (D->isFieldDesignator()) {
@@ -1987,33 +2031,33 @@ void EnqueueVisitor::VisitDesignatedInitExpr(DesignatedInitExpr *E) {
AddStmt(E->getArrayRangeStart(*D));
}
}
-void EnqueueVisitor::VisitExplicitCastExpr(ExplicitCastExpr *E) {
+void EnqueueVisitor::VisitExplicitCastExpr(const ExplicitCastExpr *E) {
EnqueueChildren(E);
AddTypeLoc(E->getTypeInfoAsWritten());
}
-void EnqueueVisitor::VisitForStmt(ForStmt *FS) {
+void EnqueueVisitor::VisitForStmt(const ForStmt *FS) {
AddStmt(FS->getBody());
AddStmt(FS->getInc());
AddStmt(FS->getCond());
AddDecl(FS->getConditionVariable());
AddStmt(FS->getInit());
}
-void EnqueueVisitor::VisitGotoStmt(GotoStmt *GS) {
+void EnqueueVisitor::VisitGotoStmt(const GotoStmt *GS) {
WL.push_back(LabelRefVisit(GS->getLabel(), GS->getLabelLoc(), Parent));
}
-void EnqueueVisitor::VisitIfStmt(IfStmt *If) {
+void EnqueueVisitor::VisitIfStmt(const IfStmt *If) {
AddStmt(If->getElse());
AddStmt(If->getThen());
AddStmt(If->getCond());
AddDecl(If->getConditionVariable());
}
-void EnqueueVisitor::VisitInitListExpr(InitListExpr *IE) {
+void EnqueueVisitor::VisitInitListExpr(const InitListExpr *IE) {
// We care about the syntactic form of the initializer list, only.
if (InitListExpr *Syntactic = IE->getSyntacticForm())
IE = Syntactic;
EnqueueChildren(IE);
}
-void EnqueueVisitor::VisitMemberExpr(MemberExpr *M) {
+void EnqueueVisitor::VisitMemberExpr(const MemberExpr *M) {
WL.push_back(MemberExprParts(M, Parent));
// If the base of the member access expression is an implicit 'this', don't
@@ -2023,14 +2067,14 @@ void EnqueueVisitor::VisitMemberExpr(MemberExpr *M) {
if (!M->isImplicitAccess())
AddStmt(M->getBase());
}
-void EnqueueVisitor::VisitObjCEncodeExpr(ObjCEncodeExpr *E) {
+void EnqueueVisitor::VisitObjCEncodeExpr(const ObjCEncodeExpr *E) {
AddTypeLoc(E->getEncodedTypeSourceInfo());
}
-void EnqueueVisitor::VisitObjCMessageExpr(ObjCMessageExpr *M) {
+void EnqueueVisitor::VisitObjCMessageExpr(const ObjCMessageExpr *M) {
EnqueueChildren(M);
AddTypeLoc(M->getClassReceiverTypeInfo());
}
-void EnqueueVisitor::VisitOffsetOfExpr(OffsetOfExpr *E) {
+void EnqueueVisitor::VisitOffsetOfExpr(const OffsetOfExpr *E) {
// Visit the components of the offsetof expression.
for (unsigned N = E->getNumComponents(), I = N; I > 0; --I) {
typedef OffsetOfExpr::OffsetOfNode OffsetOfNode;
@@ -2050,81 +2094,81 @@ void EnqueueVisitor::VisitOffsetOfExpr(OffsetOfExpr *E) {
// Visit the type into which we're computing the offset.
AddTypeLoc(E->getTypeSourceInfo());
}
-void EnqueueVisitor::VisitOverloadExpr(OverloadExpr *E) {
+void EnqueueVisitor::VisitOverloadExpr(const OverloadExpr *E) {
AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs());
WL.push_back(OverloadExprParts(E, Parent));
}
void EnqueueVisitor::VisitUnaryExprOrTypeTraitExpr(
- UnaryExprOrTypeTraitExpr *E) {
+ const UnaryExprOrTypeTraitExpr *E) {
EnqueueChildren(E);
if (E->isArgumentType())
AddTypeLoc(E->getArgumentTypeInfo());
}
-void EnqueueVisitor::VisitStmt(Stmt *S) {
+void EnqueueVisitor::VisitStmt(const Stmt *S) {
EnqueueChildren(S);
}
-void EnqueueVisitor::VisitSwitchStmt(SwitchStmt *S) {
+void EnqueueVisitor::VisitSwitchStmt(const SwitchStmt *S) {
AddStmt(S->getBody());
AddStmt(S->getCond());
AddDecl(S->getConditionVariable());
}
-void EnqueueVisitor::VisitWhileStmt(WhileStmt *W) {
+void EnqueueVisitor::VisitWhileStmt(const WhileStmt *W) {
AddStmt(W->getBody());
AddStmt(W->getCond());
AddDecl(W->getConditionVariable());
}
-void EnqueueVisitor::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
+void EnqueueVisitor::VisitUnaryTypeTraitExpr(const UnaryTypeTraitExpr *E) {
AddTypeLoc(E->getQueriedTypeSourceInfo());
}
-void EnqueueVisitor::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) {
+void EnqueueVisitor::VisitBinaryTypeTraitExpr(const BinaryTypeTraitExpr *E) {
AddTypeLoc(E->getRhsTypeSourceInfo());
AddTypeLoc(E->getLhsTypeSourceInfo());
}
-void EnqueueVisitor::VisitTypeTraitExpr(TypeTraitExpr *E) {
+void EnqueueVisitor::VisitTypeTraitExpr(const TypeTraitExpr *E) {
for (unsigned I = E->getNumArgs(); I > 0; --I)
AddTypeLoc(E->getArg(I-1));
}
-void EnqueueVisitor::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
+void EnqueueVisitor::VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E) {
AddTypeLoc(E->getQueriedTypeSourceInfo());
}
-void EnqueueVisitor::VisitExpressionTraitExpr(ExpressionTraitExpr *E) {
+void EnqueueVisitor::VisitExpressionTraitExpr(const ExpressionTraitExpr *E) {
EnqueueChildren(E);
}
-void EnqueueVisitor::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *U) {
+void EnqueueVisitor::VisitUnresolvedMemberExpr(const UnresolvedMemberExpr *U) {
VisitOverloadExpr(U);
if (!U->isImplicitAccess())
AddStmt(U->getBase());
}
-void EnqueueVisitor::VisitVAArgExpr(VAArgExpr *E) {
+void EnqueueVisitor::VisitVAArgExpr(const VAArgExpr *E) {
AddStmt(E->getSubExpr());
AddTypeLoc(E->getWrittenTypeInfo());
}
-void EnqueueVisitor::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
+void EnqueueVisitor::VisitSizeOfPackExpr(const SizeOfPackExpr *E) {
WL.push_back(SizeOfPackExprParts(E, Parent));
}
-void EnqueueVisitor::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
+void EnqueueVisitor::VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
// If the opaque value has a source expression, just transparently
// visit that. This is useful for (e.g.) pseudo-object expressions.
if (Expr *SourceExpr = E->getSourceExpr())
return Visit(SourceExpr);
}
-void EnqueueVisitor::VisitLambdaExpr(LambdaExpr *E) {
+void EnqueueVisitor::VisitLambdaExpr(const LambdaExpr *E) {
AddStmt(E->getBody());
WL.push_back(LambdaExprParts(E, Parent));
}
-void EnqueueVisitor::VisitPseudoObjectExpr(PseudoObjectExpr *E) {
+void EnqueueVisitor::VisitPseudoObjectExpr(const PseudoObjectExpr *E) {
// Treat the expression like its syntactic form.
Visit(E->getSyntacticForm());
}
-void CursorVisitor::EnqueueWorkList(VisitorWorkList &WL, Stmt *S) {
+void CursorVisitor::EnqueueWorkList(VisitorWorkList &WL, const Stmt *S) {
EnqueueVisitor(WL, MakeCXCursor(S, StmtParent, TU,RegionOfInterest)).Visit(S);
}
@@ -2148,7 +2192,7 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
switch (LI.getKind()) {
case VisitorJob::DeclVisitKind: {
- Decl *D = cast<DeclVisit>(&LI)->get();
+ const Decl *D = cast<DeclVisit>(&LI)->get();
if (!D)
continue;
@@ -2177,7 +2221,7 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
continue;
}
case VisitorJob::LabelRefVisitKind: {
- LabelDecl *LS = cast<LabelRefVisit>(&LI)->get();
+ const LabelDecl *LS = cast<LabelRefVisit>(&LI)->get();
if (LabelStmt *stmt = LS->getStmt()) {
if (Visit(MakeCursorLabelRef(stmt, cast<LabelRefVisit>(&LI)->getLoc(),
TU))) {
@@ -2207,7 +2251,7 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
continue;
}
case VisitorJob::StmtVisitKind: {
- Stmt *S = cast<StmtVisit>(&LI)->get();
+ const Stmt *S = cast<StmtVisit>(&LI)->get();
if (!S)
continue;
@@ -2228,7 +2272,7 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
}
case VisitorJob::MemberExprPartsKind: {
// Handle the other pieces in the MemberExpr besides the base.
- MemberExpr *M = cast<MemberExprParts>(&LI)->get();
+ const MemberExpr *M = cast<MemberExprParts>(&LI)->get();
// Visit the nested-name-specifier
if (NestedNameSpecifierLoc QualifierLoc = M->getQualifierLoc())
@@ -2251,7 +2295,7 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
continue;
}
case VisitorJob::DeclRefExprPartsKind: {
- DeclRefExpr *DR = cast<DeclRefExprParts>(&LI)->get();
+ const DeclRefExpr *DR = cast<DeclRefExprParts>(&LI)->get();
// Visit nested-name-specifier, if present.
if (NestedNameSpecifierLoc QualifierLoc = DR->getQualifierLoc())
if (VisitNestedNameSpecifierLoc(QualifierLoc))
@@ -2262,7 +2306,7 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
continue;
}
case VisitorJob::OverloadExprPartsKind: {
- OverloadExpr *O = cast<OverloadExprParts>(&LI)->get();
+ const OverloadExpr *O = cast<OverloadExprParts>(&LI)->get();
// Visit the nested-name-specifier.
if (NestedNameSpecifierLoc QualifierLoc = O->getQualifierLoc())
if (VisitNestedNameSpecifierLoc(QualifierLoc))
@@ -2276,7 +2320,7 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
continue;
}
case VisitorJob::SizeOfPackExprPartsKind: {
- SizeOfPackExpr *E = cast<SizeOfPackExprParts>(&LI)->get();
+ const SizeOfPackExpr *E = cast<SizeOfPackExprParts>(&LI)->get();
NamedDecl *Pack = E->getPack();
if (isa<TemplateTypeParmDecl>(Pack)) {
if (Visit(MakeCursorTypeRef(cast<TemplateTypeParmDecl>(Pack),
@@ -2301,7 +2345,7 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
case VisitorJob::LambdaExprPartsKind: {
// Visit captures.
- LambdaExpr *E = cast<LambdaExprParts>(&LI)->get();
+ const LambdaExpr *E = cast<LambdaExprParts>(&LI)->get();
for (LambdaExpr::capture_iterator C = E->explicit_capture_begin(),
CEnd = E->explicit_capture_end();
C != CEnd; ++C) {
@@ -2321,8 +2365,8 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
// Visit the whole type.
if (Visit(TL))
return true;
- } else if (isa<FunctionProtoTypeLoc>(TL)) {
- FunctionProtoTypeLoc Proto = cast<FunctionProtoTypeLoc>(TL);
+ } else if (FunctionProtoTypeLoc Proto =
+ TL.getAs<FunctionProtoTypeLoc>()) {
if (E->hasExplicitParameters()) {
// Visit parameters.
for (unsigned I = 0, N = Proto.getNumArgs(); I != N; ++I)
@@ -2347,7 +2391,7 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
return false;
}
-bool CursorVisitor::Visit(Stmt *S) {
+bool CursorVisitor::Visit(const Stmt *S) {
VisitorWorkList *WL = 0;
if (!WorkListFreeList.empty()) {
WL = WorkListFreeList.back();
@@ -2365,7 +2409,7 @@ bool CursorVisitor::Visit(Stmt *S) {
}
namespace {
-typedef llvm::SmallVector<SourceRange, 4> RefNamePieces;
+typedef SmallVector<SourceRange, 4> RefNamePieces;
RefNamePieces buildPieces(unsigned NameFlags, bool IsMemberRefExpr,
const DeclarationNameInfo &NI,
const SourceRange &QLoc,
@@ -2412,7 +2456,8 @@ RefNamePieces buildPieces(unsigned NameFlags, bool IsMemberRefExpr,
static llvm::sys::Mutex EnableMultithreadingMutex;
static bool EnabledMultithreading;
-static void fatal_error_handler(void *user_data, const std::string& reason) {
+static void fatal_error_handler(void *user_data, const std::string& reason,
+ bool gen_crash_diag) {
// Write the result out to stderr avoiding errs() because raw_ostreams can
// call report_fatal_error.
fprintf(stderr, "LIBCLANG FATAL ERROR: %s\n", reason.c_str());
@@ -2486,7 +2531,6 @@ CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx,
CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
FileSystemOptions FileSystemOpts;
- FileSystemOpts.WorkingDir = CXXIdx->getWorkingDirectory();
IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
ASTUnit *TU = ASTUnit::LoadFromASTFile(ast_filename, Diags, FileSystemOpts,
@@ -2560,9 +2604,7 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
// Configure the diagnostics.
IntrusiveRefCntPtr<DiagnosticsEngine>
- Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions,
- num_command_line_args,
- command_line_args));
+ Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions));
// Recover resources if we crash before exiting this function.
llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine,
@@ -2662,6 +2704,12 @@ CXTranslationUnit clang_parseTranslationUnit(CXIndex CIdx,
struct CXUnsavedFile *unsaved_files,
unsigned num_unsaved_files,
unsigned options) {
+ LOG_FUNC_SECTION {
+ *Log << source_filename << ": ";
+ for (int i = 0; i != num_command_line_args; ++i)
+ *Log << command_line_args[i] << " ";
+ }
+
ParseTranslationUnitInfo PTUI = { CIdx, source_filename, command_line_args,
num_command_line_args, unsaved_files,
num_unsaved_files, options, 0 };
@@ -2715,20 +2763,24 @@ static void clang_saveTranslationUnit_Impl(void *UserData) {
SaveTranslationUnitInfo *STUI =
static_cast<SaveTranslationUnitInfo*>(UserData);
- CIndexer *CXXIdx = (CIndexer*)STUI->TU->CIdx;
+ CIndexer *CXXIdx = STUI->TU->CIdx;
if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing))
setThreadBackgroundPriority();
- bool hadError = static_cast<ASTUnit *>(STUI->TU->TUData)->Save(STUI->FileName);
+ bool hadError = cxtu::getASTUnit(STUI->TU)->Save(STUI->FileName);
STUI->result = hadError ? CXSaveError_Unknown : CXSaveError_None;
}
int clang_saveTranslationUnit(CXTranslationUnit TU, const char *FileName,
unsigned options) {
+ LOG_FUNC_SECTION {
+ *Log << TU << ' ' << FileName;
+ }
+
if (!TU)
return CXSaveError_InvalidTU;
- ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
+ ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
ASTUnit::ConcurrencyCheck Check(*CXXUnit);
if (!CXXUnit->hasSema())
return CXSaveError_InvalidTU;
@@ -2769,13 +2821,14 @@ void clang_disposeTranslationUnit(CXTranslationUnit CTUnit) {
if (CTUnit) {
// If the translation unit has been marked as unsafe to free, just discard
// it.
- if (static_cast<ASTUnit *>(CTUnit->TUData)->isUnsafeToFree())
+ if (cxtu::getASTUnit(CTUnit)->isUnsafeToFree())
return;
- delete static_cast<ASTUnit *>(CTUnit->TUData);
- disposeCXStringPool(CTUnit->StringPool);
+ delete cxtu::getASTUnit(CTUnit);
+ delete CTUnit->StringPool;
delete static_cast<CXDiagnosticSetImpl *>(CTUnit->Diagnostics);
disposeOverridenCXCursorsPool(CTUnit->OverridenCursorsPool);
+ delete CTUnit->FormatContext;
delete CTUnit;
}
}
@@ -2796,6 +2849,8 @@ static void clang_reparseTranslationUnit_Impl(void *UserData) {
ReparseTranslationUnitInfo *RTUI =
static_cast<ReparseTranslationUnitInfo*>(UserData);
CXTranslationUnit TU = RTUI->TU;
+ if (!TU)
+ return;
// Reset the associated diagnostics.
delete static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics);
@@ -2807,14 +2862,11 @@ static void clang_reparseTranslationUnit_Impl(void *UserData) {
(void) options;
RTUI->result = 1;
- if (!TU)
- return;
-
- CIndexer *CXXIdx = (CIndexer*)TU->CIdx;
+ CIndexer *CXXIdx = TU->CIdx;
if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForEditing))
setThreadBackgroundPriority();
- ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
+ ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
ASTUnit::ConcurrencyCheck Check(*CXXUnit);
OwningPtr<std::vector<ASTUnit::RemappedFile> >
@@ -2841,6 +2893,10 @@ int clang_reparseTranslationUnit(CXTranslationUnit TU,
unsigned num_unsaved_files,
struct CXUnsavedFile *unsaved_files,
unsigned options) {
+ LOG_FUNC_SECTION {
+ *Log << TU;
+ }
+
ReparseTranslationUnitInfo RTUI = { TU, num_unsaved_files, unsaved_files,
options, 0 };
@@ -2853,7 +2909,7 @@ int clang_reparseTranslationUnit(CXTranslationUnit TU,
if (!RunSafely(CRC, clang_reparseTranslationUnit_Impl, &RTUI)) {
fprintf(stderr, "libclang: crash detected during reparsing\n");
- static_cast<ASTUnit *>(TU->TUData)->setUnsafeToFree(true);
+ cxtu::getASTUnit(TU)->setUnsafeToFree(true);
return 1;
} else if (getenv("LIBCLANG_RESOURCE_USAGE"))
PrintLibclangResourceUsage(TU);
@@ -2864,14 +2920,17 @@ int clang_reparseTranslationUnit(CXTranslationUnit TU,
CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit) {
if (!CTUnit)
- return createCXString("");
+ return cxstring::createEmpty();
- ASTUnit *CXXUnit = static_cast<ASTUnit *>(CTUnit->TUData);
- return createCXString(CXXUnit->getOriginalSourceFileName(), true);
+ ASTUnit *CXXUnit = cxtu::getASTUnit(CTUnit);
+ return cxstring::createDup(CXXUnit->getOriginalSourceFileName());
}
CXCursor clang_getTranslationUnitCursor(CXTranslationUnit TU) {
- ASTUnit *CXXUnit = static_cast<ASTUnit*>(TU->TUData);
+ if (!TU)
+ return clang_getNullCursor();
+
+ ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
return MakeCXCursor(CXXUnit->getASTContext().getTranslationUnitDecl(), TU);
}
@@ -2884,10 +2943,10 @@ CXCursor clang_getTranslationUnitCursor(CXTranslationUnit TU) {
extern "C" {
CXString clang_getFileName(CXFile SFile) {
if (!SFile)
- return createCXString((const char*)NULL);
+ return cxstring::createNull();
FileEntry *FEnt = static_cast<FileEntry *>(SFile);
- return createCXString(FEnt->getName());
+ return cxstring::createRef(FEnt->getName());
}
time_t clang_getFileTime(CXFile SFile) {
@@ -2898,43 +2957,58 @@ time_t clang_getFileTime(CXFile SFile) {
return FEnt->getModificationTime();
}
-CXFile clang_getFile(CXTranslationUnit tu, const char *file_name) {
- if (!tu)
+CXFile clang_getFile(CXTranslationUnit TU, const char *file_name) {
+ if (!TU)
return 0;
- ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
+ ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
FileManager &FMgr = CXXUnit->getFileManager();
return const_cast<FileEntry *>(FMgr.getFile(file_name));
}
-unsigned clang_isFileMultipleIncludeGuarded(CXTranslationUnit tu, CXFile file) {
- if (!tu || !file)
+unsigned clang_isFileMultipleIncludeGuarded(CXTranslationUnit TU, CXFile file) {
+ if (!TU || !file)
return 0;
- ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
+ ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
FileEntry *FEnt = static_cast<FileEntry *>(file);
return CXXUnit->getPreprocessor().getHeaderSearchInfo()
.isFileMultipleIncludeGuarded(FEnt);
}
+int clang_getFileUniqueID(CXFile file, CXFileUniqueID *outID) {
+ if (!file || !outID)
+ return 1;
+
+#ifdef LLVM_ON_WIN32
+ return 1; // inodes not supported on windows.
+#else
+ FileEntry *FEnt = static_cast<FileEntry *>(file);
+ outID->data[0] = FEnt->getDevice();
+ outID->data[1] = FEnt->getInode();
+ outID->data[2] = FEnt->getModificationTime();
+ return 0;
+#endif
+}
+
} // end: extern "C"
//===----------------------------------------------------------------------===//
// CXCursor Operations.
//===----------------------------------------------------------------------===//
-static Decl *getDeclFromExpr(Stmt *E) {
- if (ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E))
+static const Decl *getDeclFromExpr(const Stmt *E) {
+ if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E))
return getDeclFromExpr(CE->getSubExpr());
- if (DeclRefExpr *RefExpr = dyn_cast<DeclRefExpr>(E))
+ if (const DeclRefExpr *RefExpr = dyn_cast<DeclRefExpr>(E))
return RefExpr->getDecl();
- if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(E))
return ME->getMemberDecl();
- if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(E))
+ if (const ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(E))
return RE->getDecl();
- if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(E)) {
+ if (const ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(E)) {
if (PRE->isExplicitProperty())
return PRE->getExplicitProperty();
// It could be messaging both getter and setter as in:
@@ -2945,26 +3019,26 @@ static Decl *getDeclFromExpr(Stmt *E) {
return PRE->getImplicitPropertySetter();
return PRE->getImplicitPropertyGetter();
}
- if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E))
+ if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E))
return getDeclFromExpr(POE->getSyntacticForm());
- if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E))
+ if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E))
if (Expr *Src = OVE->getSourceExpr())
return getDeclFromExpr(Src);
- if (CallExpr *CE = dyn_cast<CallExpr>(E))
+ if (const CallExpr *CE = dyn_cast<CallExpr>(E))
return getDeclFromExpr(CE->getCallee());
- if (CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(E))
+ if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(E))
if (!CE->isElidable())
return CE->getConstructor();
- if (ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>(E))
+ if (const ObjCMessageExpr *OME = dyn_cast<ObjCMessageExpr>(E))
return OME->getMethodDecl();
- if (ObjCProtocolExpr *PE = dyn_cast<ObjCProtocolExpr>(E))
+ if (const ObjCProtocolExpr *PE = dyn_cast<ObjCProtocolExpr>(E))
return PE->getProtocol();
- if (SubstNonTypeTemplateParmPackExpr *NTTP
+ if (const SubstNonTypeTemplateParmPackExpr *NTTP
= dyn_cast<SubstNonTypeTemplateParmPackExpr>(E))
return NTTP->getParameterPack();
- if (SizeOfPackExpr *SizeOfPack = dyn_cast<SizeOfPackExpr>(E))
+ if (const SizeOfPackExpr *SizeOfPack = dyn_cast<SizeOfPackExpr>(E))
if (isa<NonTypeTemplateParmDecl>(SizeOfPack->getPack()) ||
isa<ParmVarDecl>(SizeOfPack->getPack()))
return SizeOfPack->getPack();
@@ -2972,21 +3046,21 @@ static Decl *getDeclFromExpr(Stmt *E) {
return 0;
}
-static SourceLocation getLocationFromExpr(Expr *E) {
- if (ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E))
+static SourceLocation getLocationFromExpr(const Expr *E) {
+ if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E))
return getLocationFromExpr(CE->getSubExpr());
- if (ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E))
+ if (const ObjCMessageExpr *Msg = dyn_cast<ObjCMessageExpr>(E))
return /*FIXME:*/Msg->getLeftLoc();
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
return DRE->getLocation();
- if (MemberExpr *Member = dyn_cast<MemberExpr>(E))
+ if (const MemberExpr *Member = dyn_cast<MemberExpr>(E))
return Member->getMemberLoc();
- if (ObjCIvarRefExpr *Ivar = dyn_cast<ObjCIvarRefExpr>(E))
+ if (const ObjCIvarRefExpr *Ivar = dyn_cast<ObjCIvarRefExpr>(E))
return Ivar->getLocation();
- if (SizeOfPackExpr *SizeOfPack = dyn_cast<SizeOfPackExpr>(E))
+ if (const SizeOfPackExpr *SizeOfPack = dyn_cast<SizeOfPackExpr>(E))
return SizeOfPack->getPackLoc();
- if (ObjCPropertyRefExpr *PropRef = dyn_cast<ObjCPropertyRefExpr>(E))
+ if (const ObjCPropertyRefExpr *PropRef = dyn_cast<ObjCPropertyRefExpr>(E))
return PropRef->getLocation();
return E->getLocStart();
@@ -3039,169 +3113,169 @@ unsigned clang_visitChildrenWithBlock(CXCursor parent,
return clang_visitChildren(parent, visitWithBlock, block);
}
-static CXString getDeclSpelling(Decl *D) {
+static CXString getDeclSpelling(const Decl *D) {
if (!D)
- return createCXString("");
+ return cxstring::createEmpty();
- NamedDecl *ND = dyn_cast<NamedDecl>(D);
+ const NamedDecl *ND = dyn_cast<NamedDecl>(D);
if (!ND) {
- if (ObjCPropertyImplDecl *PropImpl =dyn_cast<ObjCPropertyImplDecl>(D))
+ if (const ObjCPropertyImplDecl *PropImpl =
+ dyn_cast<ObjCPropertyImplDecl>(D))
if (ObjCPropertyDecl *Property = PropImpl->getPropertyDecl())
- return createCXString(Property->getIdentifier()->getName());
+ return cxstring::createDup(Property->getIdentifier()->getName());
- if (ImportDecl *ImportD = dyn_cast<ImportDecl>(D))
+ if (const ImportDecl *ImportD = dyn_cast<ImportDecl>(D))
if (Module *Mod = ImportD->getImportedModule())
- return createCXString(Mod->getFullModuleName());
+ return cxstring::createDup(Mod->getFullModuleName());
- return createCXString("");
+ return cxstring::createEmpty();
}
- if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(ND))
- return createCXString(OMD->getSelector().getAsString());
+ if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(ND))
+ return cxstring::createDup(OMD->getSelector().getAsString());
- if (ObjCCategoryImplDecl *CIMP = dyn_cast<ObjCCategoryImplDecl>(ND))
+ if (const ObjCCategoryImplDecl *CIMP = dyn_cast<ObjCCategoryImplDecl>(ND))
// No, this isn't the same as the code below. getIdentifier() is non-virtual
// and returns different names. NamedDecl returns the class name and
// ObjCCategoryImplDecl returns the category name.
- return createCXString(CIMP->getIdentifier()->getNameStart());
+ return cxstring::createRef(CIMP->getIdentifier()->getNameStart());
if (isa<UsingDirectiveDecl>(D))
- return createCXString("");
+ return cxstring::createEmpty();
SmallString<1024> S;
llvm::raw_svector_ostream os(S);
ND->printName(os);
- return createCXString(os.str());
+ return cxstring::createDup(os.str());
}
CXString clang_getCursorSpelling(CXCursor C) {
if (clang_isTranslationUnit(C.kind))
- return clang_getTranslationUnitSpelling(
- static_cast<CXTranslationUnit>(C.data[2]));
+ return clang_getTranslationUnitSpelling(getCursorTU(C));
if (clang_isReference(C.kind)) {
switch (C.kind) {
case CXCursor_ObjCSuperClassRef: {
- ObjCInterfaceDecl *Super = getCursorObjCSuperClassRef(C).first;
- return createCXString(Super->getIdentifier()->getNameStart());
+ const ObjCInterfaceDecl *Super = getCursorObjCSuperClassRef(C).first;
+ return cxstring::createRef(Super->getIdentifier()->getNameStart());
}
case CXCursor_ObjCClassRef: {
- ObjCInterfaceDecl *Class = getCursorObjCClassRef(C).first;
- return createCXString(Class->getIdentifier()->getNameStart());
+ const ObjCInterfaceDecl *Class = getCursorObjCClassRef(C).first;
+ return cxstring::createRef(Class->getIdentifier()->getNameStart());
}
case CXCursor_ObjCProtocolRef: {
- ObjCProtocolDecl *OID = getCursorObjCProtocolRef(C).first;
+ const ObjCProtocolDecl *OID = getCursorObjCProtocolRef(C).first;
assert(OID && "getCursorSpelling(): Missing protocol decl");
- return createCXString(OID->getIdentifier()->getNameStart());
+ return cxstring::createRef(OID->getIdentifier()->getNameStart());
}
case CXCursor_CXXBaseSpecifier: {
- CXXBaseSpecifier *B = getCursorCXXBaseSpecifier(C);
- return createCXString(B->getType().getAsString());
+ const CXXBaseSpecifier *B = getCursorCXXBaseSpecifier(C);
+ return cxstring::createDup(B->getType().getAsString());
}
case CXCursor_TypeRef: {
- TypeDecl *Type = getCursorTypeRef(C).first;
+ const TypeDecl *Type = getCursorTypeRef(C).first;
assert(Type && "Missing type decl");
- return createCXString(getCursorContext(C).getTypeDeclType(Type).
+ return cxstring::createDup(getCursorContext(C).getTypeDeclType(Type).
getAsString());
}
case CXCursor_TemplateRef: {
- TemplateDecl *Template = getCursorTemplateRef(C).first;
+ const TemplateDecl *Template = getCursorTemplateRef(C).first;
assert(Template && "Missing template decl");
- return createCXString(Template->getNameAsString());
+ return cxstring::createDup(Template->getNameAsString());
}
case CXCursor_NamespaceRef: {
- NamedDecl *NS = getCursorNamespaceRef(C).first;
+ const NamedDecl *NS = getCursorNamespaceRef(C).first;
assert(NS && "Missing namespace decl");
- return createCXString(NS->getNameAsString());
+ return cxstring::createDup(NS->getNameAsString());
}
case CXCursor_MemberRef: {
- FieldDecl *Field = getCursorMemberRef(C).first;
+ const FieldDecl *Field = getCursorMemberRef(C).first;
assert(Field && "Missing member decl");
- return createCXString(Field->getNameAsString());
+ return cxstring::createDup(Field->getNameAsString());
}
case CXCursor_LabelRef: {
- LabelStmt *Label = getCursorLabelRef(C).first;
+ const LabelStmt *Label = getCursorLabelRef(C).first;
assert(Label && "Missing label");
- return createCXString(Label->getName());
+ return cxstring::createRef(Label->getName());
}
case CXCursor_OverloadedDeclRef: {
OverloadedDeclRefStorage Storage = getCursorOverloadedDeclRef(C).first;
- if (Decl *D = Storage.dyn_cast<Decl *>()) {
- if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
- return createCXString(ND->getNameAsString());
- return createCXString("");
+ if (const Decl *D = Storage.dyn_cast<const Decl *>()) {
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
+ return cxstring::createDup(ND->getNameAsString());
+ return cxstring::createEmpty();
}
- if (OverloadExpr *E = Storage.dyn_cast<OverloadExpr *>())
- return createCXString(E->getName().getAsString());
+ if (const OverloadExpr *E = Storage.dyn_cast<const OverloadExpr *>())
+ return cxstring::createDup(E->getName().getAsString());
OverloadedTemplateStorage *Ovl
= Storage.get<OverloadedTemplateStorage*>();
if (Ovl->size() == 0)
- return createCXString("");
- return createCXString((*Ovl->begin())->getNameAsString());
+ return cxstring::createEmpty();
+ return cxstring::createDup((*Ovl->begin())->getNameAsString());
}
case CXCursor_VariableRef: {
- VarDecl *Var = getCursorVariableRef(C).first;
+ const VarDecl *Var = getCursorVariableRef(C).first;
assert(Var && "Missing variable decl");
- return createCXString(Var->getNameAsString());
+ return cxstring::createDup(Var->getNameAsString());
}
default:
- return createCXString("<not implemented>");
+ return cxstring::createRef("<not implemented>");
}
}
if (clang_isExpression(C.kind)) {
- Decl *D = getDeclFromExpr(getCursorExpr(C));
+ const Decl *D = getDeclFromExpr(getCursorExpr(C));
if (D)
return getDeclSpelling(D);
- return createCXString("");
+ return cxstring::createEmpty();
}
if (clang_isStatement(C.kind)) {
- Stmt *S = getCursorStmt(C);
- if (LabelStmt *Label = dyn_cast_or_null<LabelStmt>(S))
- return createCXString(Label->getName());
+ const Stmt *S = getCursorStmt(C);
+ if (const LabelStmt *Label = dyn_cast_or_null<LabelStmt>(S))
+ return cxstring::createRef(Label->getName());
- return createCXString("");
+ return cxstring::createEmpty();
}
if (C.kind == CXCursor_MacroExpansion)
- return createCXString(getCursorMacroExpansion(C)->getName()
+ return cxstring::createRef(getCursorMacroExpansion(C).getName()
->getNameStart());
if (C.kind == CXCursor_MacroDefinition)
- return createCXString(getCursorMacroDefinition(C)->getName()
+ return cxstring::createRef(getCursorMacroDefinition(C)->getName()
->getNameStart());
if (C.kind == CXCursor_InclusionDirective)
- return createCXString(getCursorInclusionDirective(C)->getFileName());
+ return cxstring::createDup(getCursorInclusionDirective(C)->getFileName());
if (clang_isDeclaration(C.kind))
return getDeclSpelling(getCursorDecl(C));
if (C.kind == CXCursor_AnnotateAttr) {
- AnnotateAttr *AA = cast<AnnotateAttr>(cxcursor::getCursorAttr(C));
- return createCXString(AA->getAnnotation());
+ const AnnotateAttr *AA = cast<AnnotateAttr>(cxcursor::getCursorAttr(C));
+ return cxstring::createDup(AA->getAnnotation());
}
if (C.kind == CXCursor_AsmLabelAttr) {
- AsmLabelAttr *AA = cast<AsmLabelAttr>(cxcursor::getCursorAttr(C));
- return createCXString(AA->getLabel());
+ const AsmLabelAttr *AA = cast<AsmLabelAttr>(cxcursor::getCursorAttr(C));
+ return cxstring::createDup(AA->getLabel());
}
- return createCXString("");
+ return cxstring::createEmpty();
}
CXSourceRange clang_Cursor_getSpellingNameRange(CXCursor C,
@@ -3213,8 +3287,8 @@ CXSourceRange clang_Cursor_getSpellingNameRange(CXCursor C,
ASTContext &Ctx = getCursorContext(C);
if (clang_isStatement(C.kind)) {
- Stmt *S = getCursorStmt(C);
- if (LabelStmt *Label = dyn_cast_or_null<LabelStmt>(S)) {
+ const Stmt *S = getCursorStmt(C);
+ if (const LabelStmt *Label = dyn_cast_or_null<LabelStmt>(S)) {
if (pieceIndex > 0)
return clang_getNullRange();
return cxloc::translateSourceRange(Ctx, Label->getIdentLoc());
@@ -3224,7 +3298,7 @@ CXSourceRange clang_Cursor_getSpellingNameRange(CXCursor C,
}
if (C.kind == CXCursor_ObjCMessageExpr) {
- if (ObjCMessageExpr *
+ if (const ObjCMessageExpr *
ME = dyn_cast_or_null<ObjCMessageExpr>(getCursorExpr(C))) {
if (pieceIndex >= ME->getNumSelectorLocs())
return clang_getNullRange();
@@ -3234,7 +3308,7 @@ CXSourceRange clang_Cursor_getSpellingNameRange(CXCursor C,
if (C.kind == CXCursor_ObjCInstanceMethodDecl ||
C.kind == CXCursor_ObjCClassMethodDecl) {
- if (ObjCMethodDecl *
+ if (const ObjCMethodDecl *
MD = dyn_cast_or_null<ObjCMethodDecl>(getCursorDecl(C))) {
if (pieceIndex >= MD->getNumSelectorLocs())
return clang_getNullRange();
@@ -3246,10 +3320,10 @@ CXSourceRange clang_Cursor_getSpellingNameRange(CXCursor C,
C.kind == CXCursor_ObjCCategoryImplDecl) {
if (pieceIndex > 0)
return clang_getNullRange();
- if (ObjCCategoryDecl *
+ if (const ObjCCategoryDecl *
CD = dyn_cast_or_null<ObjCCategoryDecl>(getCursorDecl(C)))
return cxloc::translateSourceRange(Ctx, CD->getCategoryNameLoc());
- if (ObjCCategoryImplDecl *
+ if (const ObjCCategoryImplDecl *
CID = dyn_cast_or_null<ObjCCategoryImplDecl>(getCursorDecl(C)))
return cxloc::translateSourceRange(Ctx, CID->getCategoryNameLoc());
}
@@ -3257,7 +3331,8 @@ CXSourceRange clang_Cursor_getSpellingNameRange(CXCursor C,
if (C.kind == CXCursor_ModuleImportDecl) {
if (pieceIndex > 0)
return clang_getNullRange();
- if (ImportDecl *ImportD = dyn_cast_or_null<ImportDecl>(getCursorDecl(C))) {
+ if (const ImportDecl *ImportD =
+ dyn_cast_or_null<ImportDecl>(getCursorDecl(C))) {
ArrayRef<SourceLocation> Locs = ImportD->getIdentifierLocs();
if (!Locs.empty())
return cxloc::translateSourceRange(Ctx,
@@ -3289,15 +3364,15 @@ CXString clang_getCursorDisplayName(CXCursor C) {
if (!clang_isDeclaration(C.kind))
return clang_getCursorSpelling(C);
- Decl *D = getCursorDecl(C);
+ const Decl *D = getCursorDecl(C);
if (!D)
- return createCXString("");
+ return cxstring::createEmpty();
PrintingPolicy Policy = getCursorContext(C).getPrintingPolicy();
- if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D))
+ if (const FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D))
D = FunTmpl->getTemplatedDecl();
- if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
SmallString<64> Str;
llvm::raw_svector_ostream OS(Str);
OS << *Function;
@@ -3316,10 +3391,10 @@ CXString clang_getCursorDisplayName(CXCursor C) {
OS << "...";
}
OS << ")";
- return createCXString(OS.str());
+ return cxstring::createDup(OS.str());
}
- if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(D)) {
+ if (const ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(D)) {
SmallString<64> Str;
llvm::raw_svector_ostream OS(Str);
OS << *ClassTemplate;
@@ -3347,23 +3422,23 @@ CXString clang_getCursorDisplayName(CXCursor C) {
}
OS << ">";
- return createCXString(OS.str());
+ return cxstring::createDup(OS.str());
}
- if (ClassTemplateSpecializationDecl *ClassSpec
+ if (const ClassTemplateSpecializationDecl *ClassSpec
= dyn_cast<ClassTemplateSpecializationDecl>(D)) {
// If the type was explicitly written, use that.
if (TypeSourceInfo *TSInfo = ClassSpec->getTypeAsWritten())
- return createCXString(TSInfo->getType().getAsString(Policy));
+ return cxstring::createDup(TSInfo->getType().getAsString(Policy));
- SmallString<64> Str;
+ SmallString<128> Str;
llvm::raw_svector_ostream OS(Str);
OS << *ClassSpec;
- OS << TemplateSpecializationType::PrintTemplateArgumentList(
+ TemplateSpecializationType::PrintTemplateArgumentList(OS,
ClassSpec->getTemplateArgs().data(),
ClassSpec->getTemplateArgs().size(),
Policy);
- return createCXString(OS.str());
+ return cxstring::createDup(OS.str());
}
return clang_getCursorSpelling(C);
@@ -3372,297 +3447,297 @@ CXString clang_getCursorDisplayName(CXCursor C) {
CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
switch (Kind) {
case CXCursor_FunctionDecl:
- return createCXString("FunctionDecl");
+ return cxstring::createRef("FunctionDecl");
case CXCursor_TypedefDecl:
- return createCXString("TypedefDecl");
+ return cxstring::createRef("TypedefDecl");
case CXCursor_EnumDecl:
- return createCXString("EnumDecl");
+ return cxstring::createRef("EnumDecl");
case CXCursor_EnumConstantDecl:
- return createCXString("EnumConstantDecl");
+ return cxstring::createRef("EnumConstantDecl");
case CXCursor_StructDecl:
- return createCXString("StructDecl");
+ return cxstring::createRef("StructDecl");
case CXCursor_UnionDecl:
- return createCXString("UnionDecl");
+ return cxstring::createRef("UnionDecl");
case CXCursor_ClassDecl:
- return createCXString("ClassDecl");
+ return cxstring::createRef("ClassDecl");
case CXCursor_FieldDecl:
- return createCXString("FieldDecl");
+ return cxstring::createRef("FieldDecl");
case CXCursor_VarDecl:
- return createCXString("VarDecl");
+ return cxstring::createRef("VarDecl");
case CXCursor_ParmDecl:
- return createCXString("ParmDecl");
+ return cxstring::createRef("ParmDecl");
case CXCursor_ObjCInterfaceDecl:
- return createCXString("ObjCInterfaceDecl");
+ return cxstring::createRef("ObjCInterfaceDecl");
case CXCursor_ObjCCategoryDecl:
- return createCXString("ObjCCategoryDecl");
+ return cxstring::createRef("ObjCCategoryDecl");
case CXCursor_ObjCProtocolDecl:
- return createCXString("ObjCProtocolDecl");
+ return cxstring::createRef("ObjCProtocolDecl");
case CXCursor_ObjCPropertyDecl:
- return createCXString("ObjCPropertyDecl");
+ return cxstring::createRef("ObjCPropertyDecl");
case CXCursor_ObjCIvarDecl:
- return createCXString("ObjCIvarDecl");
+ return cxstring::createRef("ObjCIvarDecl");
case CXCursor_ObjCInstanceMethodDecl:
- return createCXString("ObjCInstanceMethodDecl");
+ return cxstring::createRef("ObjCInstanceMethodDecl");
case CXCursor_ObjCClassMethodDecl:
- return createCXString("ObjCClassMethodDecl");
+ return cxstring::createRef("ObjCClassMethodDecl");
case CXCursor_ObjCImplementationDecl:
- return createCXString("ObjCImplementationDecl");
+ return cxstring::createRef("ObjCImplementationDecl");
case CXCursor_ObjCCategoryImplDecl:
- return createCXString("ObjCCategoryImplDecl");
+ return cxstring::createRef("ObjCCategoryImplDecl");
case CXCursor_CXXMethod:
- return createCXString("CXXMethod");
+ return cxstring::createRef("CXXMethod");
case CXCursor_UnexposedDecl:
- return createCXString("UnexposedDecl");
+ return cxstring::createRef("UnexposedDecl");
case CXCursor_ObjCSuperClassRef:
- return createCXString("ObjCSuperClassRef");
+ return cxstring::createRef("ObjCSuperClassRef");
case CXCursor_ObjCProtocolRef:
- return createCXString("ObjCProtocolRef");
+ return cxstring::createRef("ObjCProtocolRef");
case CXCursor_ObjCClassRef:
- return createCXString("ObjCClassRef");
+ return cxstring::createRef("ObjCClassRef");
case CXCursor_TypeRef:
- return createCXString("TypeRef");
+ return cxstring::createRef("TypeRef");
case CXCursor_TemplateRef:
- return createCXString("TemplateRef");
+ return cxstring::createRef("TemplateRef");
case CXCursor_NamespaceRef:
- return createCXString("NamespaceRef");
+ return cxstring::createRef("NamespaceRef");
case CXCursor_MemberRef:
- return createCXString("MemberRef");
+ return cxstring::createRef("MemberRef");
case CXCursor_LabelRef:
- return createCXString("LabelRef");
+ return cxstring::createRef("LabelRef");
case CXCursor_OverloadedDeclRef:
- return createCXString("OverloadedDeclRef");
+ return cxstring::createRef("OverloadedDeclRef");
case CXCursor_VariableRef:
- return createCXString("VariableRef");
+ return cxstring::createRef("VariableRef");
case CXCursor_IntegerLiteral:
- return createCXString("IntegerLiteral");
+ return cxstring::createRef("IntegerLiteral");
case CXCursor_FloatingLiteral:
- return createCXString("FloatingLiteral");
+ return cxstring::createRef("FloatingLiteral");
case CXCursor_ImaginaryLiteral:
- return createCXString("ImaginaryLiteral");
+ return cxstring::createRef("ImaginaryLiteral");
case CXCursor_StringLiteral:
- return createCXString("StringLiteral");
+ return cxstring::createRef("StringLiteral");
case CXCursor_CharacterLiteral:
- return createCXString("CharacterLiteral");
+ return cxstring::createRef("CharacterLiteral");
case CXCursor_ParenExpr:
- return createCXString("ParenExpr");
+ return cxstring::createRef("ParenExpr");
case CXCursor_UnaryOperator:
- return createCXString("UnaryOperator");
+ return cxstring::createRef("UnaryOperator");
case CXCursor_ArraySubscriptExpr:
- return createCXString("ArraySubscriptExpr");
+ return cxstring::createRef("ArraySubscriptExpr");
case CXCursor_BinaryOperator:
- return createCXString("BinaryOperator");
+ return cxstring::createRef("BinaryOperator");
case CXCursor_CompoundAssignOperator:
- return createCXString("CompoundAssignOperator");
+ return cxstring::createRef("CompoundAssignOperator");
case CXCursor_ConditionalOperator:
- return createCXString("ConditionalOperator");
+ return cxstring::createRef("ConditionalOperator");
case CXCursor_CStyleCastExpr:
- return createCXString("CStyleCastExpr");
+ return cxstring::createRef("CStyleCastExpr");
case CXCursor_CompoundLiteralExpr:
- return createCXString("CompoundLiteralExpr");
+ return cxstring::createRef("CompoundLiteralExpr");
case CXCursor_InitListExpr:
- return createCXString("InitListExpr");
+ return cxstring::createRef("InitListExpr");
case CXCursor_AddrLabelExpr:
- return createCXString("AddrLabelExpr");
+ return cxstring::createRef("AddrLabelExpr");
case CXCursor_StmtExpr:
- return createCXString("StmtExpr");
+ return cxstring::createRef("StmtExpr");
case CXCursor_GenericSelectionExpr:
- return createCXString("GenericSelectionExpr");
+ return cxstring::createRef("GenericSelectionExpr");
case CXCursor_GNUNullExpr:
- return createCXString("GNUNullExpr");
+ return cxstring::createRef("GNUNullExpr");
case CXCursor_CXXStaticCastExpr:
- return createCXString("CXXStaticCastExpr");
+ return cxstring::createRef("CXXStaticCastExpr");
case CXCursor_CXXDynamicCastExpr:
- return createCXString("CXXDynamicCastExpr");
+ return cxstring::createRef("CXXDynamicCastExpr");
case CXCursor_CXXReinterpretCastExpr:
- return createCXString("CXXReinterpretCastExpr");
+ return cxstring::createRef("CXXReinterpretCastExpr");
case CXCursor_CXXConstCastExpr:
- return createCXString("CXXConstCastExpr");
+ return cxstring::createRef("CXXConstCastExpr");
case CXCursor_CXXFunctionalCastExpr:
- return createCXString("CXXFunctionalCastExpr");
+ return cxstring::createRef("CXXFunctionalCastExpr");
case CXCursor_CXXTypeidExpr:
- return createCXString("CXXTypeidExpr");
+ return cxstring::createRef("CXXTypeidExpr");
case CXCursor_CXXBoolLiteralExpr:
- return createCXString("CXXBoolLiteralExpr");
+ return cxstring::createRef("CXXBoolLiteralExpr");
case CXCursor_CXXNullPtrLiteralExpr:
- return createCXString("CXXNullPtrLiteralExpr");
+ return cxstring::createRef("CXXNullPtrLiteralExpr");
case CXCursor_CXXThisExpr:
- return createCXString("CXXThisExpr");
+ return cxstring::createRef("CXXThisExpr");
case CXCursor_CXXThrowExpr:
- return createCXString("CXXThrowExpr");
+ return cxstring::createRef("CXXThrowExpr");
case CXCursor_CXXNewExpr:
- return createCXString("CXXNewExpr");
+ return cxstring::createRef("CXXNewExpr");
case CXCursor_CXXDeleteExpr:
- return createCXString("CXXDeleteExpr");
+ return cxstring::createRef("CXXDeleteExpr");
case CXCursor_UnaryExpr:
- return createCXString("UnaryExpr");
+ return cxstring::createRef("UnaryExpr");
case CXCursor_ObjCStringLiteral:
- return createCXString("ObjCStringLiteral");
+ return cxstring::createRef("ObjCStringLiteral");
case CXCursor_ObjCBoolLiteralExpr:
- return createCXString("ObjCBoolLiteralExpr");
+ return cxstring::createRef("ObjCBoolLiteralExpr");
case CXCursor_ObjCEncodeExpr:
- return createCXString("ObjCEncodeExpr");
+ return cxstring::createRef("ObjCEncodeExpr");
case CXCursor_ObjCSelectorExpr:
- return createCXString("ObjCSelectorExpr");
+ return cxstring::createRef("ObjCSelectorExpr");
case CXCursor_ObjCProtocolExpr:
- return createCXString("ObjCProtocolExpr");
+ return cxstring::createRef("ObjCProtocolExpr");
case CXCursor_ObjCBridgedCastExpr:
- return createCXString("ObjCBridgedCastExpr");
+ return cxstring::createRef("ObjCBridgedCastExpr");
case CXCursor_BlockExpr:
- return createCXString("BlockExpr");
+ return cxstring::createRef("BlockExpr");
case CXCursor_PackExpansionExpr:
- return createCXString("PackExpansionExpr");
+ return cxstring::createRef("PackExpansionExpr");
case CXCursor_SizeOfPackExpr:
- return createCXString("SizeOfPackExpr");
+ return cxstring::createRef("SizeOfPackExpr");
case CXCursor_LambdaExpr:
- return createCXString("LambdaExpr");
+ return cxstring::createRef("LambdaExpr");
case CXCursor_UnexposedExpr:
- return createCXString("UnexposedExpr");
+ return cxstring::createRef("UnexposedExpr");
case CXCursor_DeclRefExpr:
- return createCXString("DeclRefExpr");
+ return cxstring::createRef("DeclRefExpr");
case CXCursor_MemberRefExpr:
- return createCXString("MemberRefExpr");
+ return cxstring::createRef("MemberRefExpr");
case CXCursor_CallExpr:
- return createCXString("CallExpr");
+ return cxstring::createRef("CallExpr");
case CXCursor_ObjCMessageExpr:
- return createCXString("ObjCMessageExpr");
+ return cxstring::createRef("ObjCMessageExpr");
case CXCursor_UnexposedStmt:
- return createCXString("UnexposedStmt");
+ return cxstring::createRef("UnexposedStmt");
case CXCursor_DeclStmt:
- return createCXString("DeclStmt");
+ return cxstring::createRef("DeclStmt");
case CXCursor_LabelStmt:
- return createCXString("LabelStmt");
+ return cxstring::createRef("LabelStmt");
case CXCursor_CompoundStmt:
- return createCXString("CompoundStmt");
+ return cxstring::createRef("CompoundStmt");
case CXCursor_CaseStmt:
- return createCXString("CaseStmt");
+ return cxstring::createRef("CaseStmt");
case CXCursor_DefaultStmt:
- return createCXString("DefaultStmt");
+ return cxstring::createRef("DefaultStmt");
case CXCursor_IfStmt:
- return createCXString("IfStmt");
+ return cxstring::createRef("IfStmt");
case CXCursor_SwitchStmt:
- return createCXString("SwitchStmt");
+ return cxstring::createRef("SwitchStmt");
case CXCursor_WhileStmt:
- return createCXString("WhileStmt");
+ return cxstring::createRef("WhileStmt");
case CXCursor_DoStmt:
- return createCXString("DoStmt");
+ return cxstring::createRef("DoStmt");
case CXCursor_ForStmt:
- return createCXString("ForStmt");
+ return cxstring::createRef("ForStmt");
case CXCursor_GotoStmt:
- return createCXString("GotoStmt");
+ return cxstring::createRef("GotoStmt");
case CXCursor_IndirectGotoStmt:
- return createCXString("IndirectGotoStmt");
+ return cxstring::createRef("IndirectGotoStmt");
case CXCursor_ContinueStmt:
- return createCXString("ContinueStmt");
+ return cxstring::createRef("ContinueStmt");
case CXCursor_BreakStmt:
- return createCXString("BreakStmt");
+ return cxstring::createRef("BreakStmt");
case CXCursor_ReturnStmt:
- return createCXString("ReturnStmt");
+ return cxstring::createRef("ReturnStmt");
case CXCursor_GCCAsmStmt:
- return createCXString("GCCAsmStmt");
+ return cxstring::createRef("GCCAsmStmt");
case CXCursor_MSAsmStmt:
- return createCXString("MSAsmStmt");
+ return cxstring::createRef("MSAsmStmt");
case CXCursor_ObjCAtTryStmt:
- return createCXString("ObjCAtTryStmt");
+ return cxstring::createRef("ObjCAtTryStmt");
case CXCursor_ObjCAtCatchStmt:
- return createCXString("ObjCAtCatchStmt");
+ return cxstring::createRef("ObjCAtCatchStmt");
case CXCursor_ObjCAtFinallyStmt:
- return createCXString("ObjCAtFinallyStmt");
+ return cxstring::createRef("ObjCAtFinallyStmt");
case CXCursor_ObjCAtThrowStmt:
- return createCXString("ObjCAtThrowStmt");
+ return cxstring::createRef("ObjCAtThrowStmt");
case CXCursor_ObjCAtSynchronizedStmt:
- return createCXString("ObjCAtSynchronizedStmt");
+ return cxstring::createRef("ObjCAtSynchronizedStmt");
case CXCursor_ObjCAutoreleasePoolStmt:
- return createCXString("ObjCAutoreleasePoolStmt");
+ return cxstring::createRef("ObjCAutoreleasePoolStmt");
case CXCursor_ObjCForCollectionStmt:
- return createCXString("ObjCForCollectionStmt");
+ return cxstring::createRef("ObjCForCollectionStmt");
case CXCursor_CXXCatchStmt:
- return createCXString("CXXCatchStmt");
+ return cxstring::createRef("CXXCatchStmt");
case CXCursor_CXXTryStmt:
- return createCXString("CXXTryStmt");
+ return cxstring::createRef("CXXTryStmt");
case CXCursor_CXXForRangeStmt:
- return createCXString("CXXForRangeStmt");
+ return cxstring::createRef("CXXForRangeStmt");
case CXCursor_SEHTryStmt:
- return createCXString("SEHTryStmt");
+ return cxstring::createRef("SEHTryStmt");
case CXCursor_SEHExceptStmt:
- return createCXString("SEHExceptStmt");
+ return cxstring::createRef("SEHExceptStmt");
case CXCursor_SEHFinallyStmt:
- return createCXString("SEHFinallyStmt");
+ return cxstring::createRef("SEHFinallyStmt");
case CXCursor_NullStmt:
- return createCXString("NullStmt");
+ return cxstring::createRef("NullStmt");
case CXCursor_InvalidFile:
- return createCXString("InvalidFile");
+ return cxstring::createRef("InvalidFile");
case CXCursor_InvalidCode:
- return createCXString("InvalidCode");
+ return cxstring::createRef("InvalidCode");
case CXCursor_NoDeclFound:
- return createCXString("NoDeclFound");
+ return cxstring::createRef("NoDeclFound");
case CXCursor_NotImplemented:
- return createCXString("NotImplemented");
+ return cxstring::createRef("NotImplemented");
case CXCursor_TranslationUnit:
- return createCXString("TranslationUnit");
+ return cxstring::createRef("TranslationUnit");
case CXCursor_UnexposedAttr:
- return createCXString("UnexposedAttr");
+ return cxstring::createRef("UnexposedAttr");
case CXCursor_IBActionAttr:
- return createCXString("attribute(ibaction)");
+ return cxstring::createRef("attribute(ibaction)");
case CXCursor_IBOutletAttr:
- return createCXString("attribute(iboutlet)");
+ return cxstring::createRef("attribute(iboutlet)");
case CXCursor_IBOutletCollectionAttr:
- return createCXString("attribute(iboutletcollection)");
+ return cxstring::createRef("attribute(iboutletcollection)");
case CXCursor_CXXFinalAttr:
- return createCXString("attribute(final)");
+ return cxstring::createRef("attribute(final)");
case CXCursor_CXXOverrideAttr:
- return createCXString("attribute(override)");
+ return cxstring::createRef("attribute(override)");
case CXCursor_AnnotateAttr:
- return createCXString("attribute(annotate)");
+ return cxstring::createRef("attribute(annotate)");
case CXCursor_AsmLabelAttr:
- return createCXString("asm label");
+ return cxstring::createRef("asm label");
case CXCursor_PreprocessingDirective:
- return createCXString("preprocessing directive");
+ return cxstring::createRef("preprocessing directive");
case CXCursor_MacroDefinition:
- return createCXString("macro definition");
+ return cxstring::createRef("macro definition");
case CXCursor_MacroExpansion:
- return createCXString("macro expansion");
+ return cxstring::createRef("macro expansion");
case CXCursor_InclusionDirective:
- return createCXString("inclusion directive");
+ return cxstring::createRef("inclusion directive");
case CXCursor_Namespace:
- return createCXString("Namespace");
+ return cxstring::createRef("Namespace");
case CXCursor_LinkageSpec:
- return createCXString("LinkageSpec");
+ return cxstring::createRef("LinkageSpec");
case CXCursor_CXXBaseSpecifier:
- return createCXString("C++ base class specifier");
+ return cxstring::createRef("C++ base class specifier");
case CXCursor_Constructor:
- return createCXString("CXXConstructor");
+ return cxstring::createRef("CXXConstructor");
case CXCursor_Destructor:
- return createCXString("CXXDestructor");
+ return cxstring::createRef("CXXDestructor");
case CXCursor_ConversionFunction:
- return createCXString("CXXConversion");
+ return cxstring::createRef("CXXConversion");
case CXCursor_TemplateTypeParameter:
- return createCXString("TemplateTypeParameter");
+ return cxstring::createRef("TemplateTypeParameter");
case CXCursor_NonTypeTemplateParameter:
- return createCXString("NonTypeTemplateParameter");
+ return cxstring::createRef("NonTypeTemplateParameter");
case CXCursor_TemplateTemplateParameter:
- return createCXString("TemplateTemplateParameter");
+ return cxstring::createRef("TemplateTemplateParameter");
case CXCursor_FunctionTemplate:
- return createCXString("FunctionTemplate");
+ return cxstring::createRef("FunctionTemplate");
case CXCursor_ClassTemplate:
- return createCXString("ClassTemplate");
+ return cxstring::createRef("ClassTemplate");
case CXCursor_ClassTemplatePartialSpecialization:
- return createCXString("ClassTemplatePartialSpecialization");
+ return cxstring::createRef("ClassTemplatePartialSpecialization");
case CXCursor_NamespaceAlias:
- return createCXString("NamespaceAlias");
+ return cxstring::createRef("NamespaceAlias");
case CXCursor_UsingDirective:
- return createCXString("UsingDirective");
+ return cxstring::createRef("UsingDirective");
case CXCursor_UsingDeclaration:
- return createCXString("UsingDeclaration");
+ return cxstring::createRef("UsingDeclaration");
case CXCursor_TypeAliasDecl:
- return createCXString("TypeAliasDecl");
+ return cxstring::createRef("TypeAliasDecl");
case CXCursor_ObjCSynthesizeDecl:
- return createCXString("ObjCSynthesizeDecl");
+ return cxstring::createRef("ObjCSynthesizeDecl");
case CXCursor_ObjCDynamicDecl:
- return createCXString("ObjCDynamicDecl");
+ return cxstring::createRef("ObjCDynamicDecl");
case CXCursor_CXXAccessSpecifier:
- return createCXString("CXXAccessSpecifier");
+ return cxstring::createRef("CXXAccessSpecifier");
case CXCursor_ModuleImportDecl:
- return createCXString("ModuleImport");
+ return cxstring::createRef("ModuleImport");
}
llvm_unreachable("Unhandled CXCursorKind");
@@ -3697,12 +3772,12 @@ static enum CXChildVisitResult GetCursorVisitor(CXCursor cursor,
if (clang_isDeclaration(cursor.kind)) {
// Avoid having the implicit methods override the property decls.
- if (ObjCMethodDecl *MD
+ if (const ObjCMethodDecl *MD
= dyn_cast_or_null<ObjCMethodDecl>(getCursorDecl(cursor))) {
if (MD->isImplicit())
return CXChildVisit_Break;
- } else if (ObjCInterfaceDecl *ID
+ } else if (const ObjCInterfaceDecl *ID
= dyn_cast_or_null<ObjCInterfaceDecl>(getCursorDecl(cursor))) {
// Check that when we have multiple @class references in the same line,
// that later ones do not override the previous ones.
@@ -3712,7 +3787,7 @@ static enum CXChildVisitResult GetCursorVisitor(CXCursor cursor,
// 'Foo' even though the cursor location was at 'Foo'.
if (BestCursor->kind == CXCursor_ObjCInterfaceDecl ||
BestCursor->kind == CXCursor_ObjCClassRef)
- if (ObjCInterfaceDecl *PrevID
+ if (const ObjCInterfaceDecl *PrevID
= dyn_cast_or_null<ObjCInterfaceDecl>(getCursorDecl(*BestCursor))){
if (PrevID != ID &&
!PrevID->isThisDeclarationADefinition() &&
@@ -3720,7 +3795,7 @@ static enum CXChildVisitResult GetCursorVisitor(CXCursor cursor,
return CXChildVisit_Break;
}
- } else if (DeclaratorDecl *DD
+ } else if (const DeclaratorDecl *DD
= dyn_cast_or_null<DeclaratorDecl>(getCursorDecl(cursor))) {
SourceLocation StartLoc = DD->getSourceRange().getBegin();
// Check that when we have multiple declarators in the same line,
@@ -3733,7 +3808,7 @@ static enum CXChildVisitResult GetCursorVisitor(CXCursor cursor,
return CXChildVisit_Break;
Data->VisitedDeclaratorDeclStartLoc = StartLoc;
- } else if (ObjCPropertyImplDecl *PropImp
+ } else if (const ObjCPropertyImplDecl *PropImp
= dyn_cast_or_null<ObjCPropertyImplDecl>(getCursorDecl(cursor))) {
(void)PropImp;
// Check that when we have multiple @synthesize in the same line,
@@ -3750,7 +3825,7 @@ static enum CXChildVisitResult GetCursorVisitor(CXCursor cursor,
if (clang_isExpression(cursor.kind) &&
clang_isDeclaration(BestCursor->kind)) {
- if (Decl *D = getCursorDecl(*BestCursor)) {
+ if (const Decl *D = getCursorDecl(*BestCursor)) {
// Avoid having the cursor of an expression replace the declaration cursor
// when the expression source range overlaps the declaration range.
// This can happen for C++ constructor expressions whose range generally
@@ -3782,14 +3857,13 @@ CXCursor clang_getCursor(CXTranslationUnit TU, CXSourceLocation Loc) {
if (!TU)
return clang_getNullCursor();
- ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
+ ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
ASTUnit::ConcurrencyCheck Check(*CXXUnit);
SourceLocation SLoc = cxloc::translateSourceLocation(Loc);
CXCursor Result = cxcursor::getCursor(TU, SLoc);
- bool Logging = getenv("LIBCLANG_LOGGING");
- if (Logging) {
+ LOG_FUNC_SECTION {
CXFile SearchFile;
unsigned SearchLine, SearchColumn;
CXFile ResultFile;
@@ -3798,18 +3872,19 @@ CXCursor clang_getCursor(CXTranslationUnit TU, CXSourceLocation Loc) {
const char *IsDef = clang_isCursorDefinition(Result)? " (Definition)" : "";
CXSourceLocation ResultLoc = clang_getCursorLocation(Result);
- clang_getExpansionLocation(Loc, &SearchFile, &SearchLine, &SearchColumn, 0);
- clang_getExpansionLocation(ResultLoc, &ResultFile, &ResultLine,
+ clang_getFileLocation(Loc, &SearchFile, &SearchLine, &SearchColumn, 0);
+ clang_getFileLocation(ResultLoc, &ResultFile, &ResultLine,
&ResultColumn, 0);
SearchFileName = clang_getFileName(SearchFile);
ResultFileName = clang_getFileName(ResultFile);
KindSpelling = clang_getCursorKindSpelling(Result.kind);
USR = clang_getCursorUSR(Result);
- fprintf(stderr, "clang_getCursor(%s:%d:%d) = %s(%s:%d:%d):%s%s\n",
- clang_getCString(SearchFileName), SearchLine, SearchColumn,
- clang_getCString(KindSpelling),
- clang_getCString(ResultFileName), ResultLine, ResultColumn,
- clang_getCString(USR), IsDef);
+ *Log << llvm::format("(%s:%d:%d) = %s",
+ clang_getCString(SearchFileName), SearchLine, SearchColumn,
+ clang_getCString(KindSpelling))
+ << llvm::format("(%s:%d:%d):%s%s",
+ clang_getCString(ResultFileName), ResultLine, ResultColumn,
+ clang_getCString(USR), IsDef);
clang_disposeString(SearchFileName);
clang_disposeString(ResultFileName);
clang_disposeString(KindSpelling);
@@ -3822,13 +3897,13 @@ CXCursor clang_getCursor(CXTranslationUnit TU, CXSourceLocation Loc) {
= clang_getCursorKindSpelling(Definition.kind);
CXFile DefinitionFile;
unsigned DefinitionLine, DefinitionColumn;
- clang_getExpansionLocation(DefinitionLoc, &DefinitionFile,
+ clang_getFileLocation(DefinitionLoc, &DefinitionFile,
&DefinitionLine, &DefinitionColumn, 0);
CXString DefinitionFileName = clang_getFileName(DefinitionFile);
- fprintf(stderr, " -> %s(%s:%d:%d)\n",
- clang_getCString(DefinitionKindSpelling),
- clang_getCString(DefinitionFileName),
- DefinitionLine, DefinitionColumn);
+ *Log << llvm::format(" -> %s(%s:%d:%d)",
+ clang_getCString(DefinitionKindSpelling),
+ clang_getCString(DefinitionFileName),
+ DefinitionLine, DefinitionColumn);
clang_disposeString(DefinitionFileName);
clang_disposeString(DefinitionKindSpelling);
}
@@ -3842,6 +3917,18 @@ CXCursor clang_getNullCursor(void) {
}
unsigned clang_equalCursors(CXCursor X, CXCursor Y) {
+ // Clear out the "FirstInDeclGroup" part in a declaration cursor, since we
+ // can't set consistently. For example, when visiting a DeclStmt we will set
+ // it but we don't set it on the result of clang_getCursorDefinition for
+ // a reference of the same declaration.
+ // FIXME: Setting "FirstInDeclGroup" in CXCursors is a hack that only works
+ // when visiting a DeclStmt currently, the AST should be enhanced to be able
+ // to provide that kind of info.
+ if (clang_isDeclaration(X.kind))
+ X.data[1] = 0;
+ if (clang_isDeclaration(Y.kind))
+ Y.data[1] = 0;
+
return X == Y;
}
@@ -3850,7 +3937,7 @@ unsigned clang_hashCursor(CXCursor C) {
if (clang_isExpression(C.kind) || clang_isStatement(C.kind))
Index = 1;
- return llvm::DenseMapInfo<std::pair<unsigned, void*> >::getHashValue(
+ return llvm::DenseMapInfo<std::pair<unsigned, const void*> >::getHashValue(
std::make_pair(C.kind, C.data[Index]));
}
@@ -3907,50 +3994,51 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {
if (clang_isReference(C.kind)) {
switch (C.kind) {
case CXCursor_ObjCSuperClassRef: {
- std::pair<ObjCInterfaceDecl *, SourceLocation> P
+ std::pair<const ObjCInterfaceDecl *, SourceLocation> P
= getCursorObjCSuperClassRef(C);
return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
}
case CXCursor_ObjCProtocolRef: {
- std::pair<ObjCProtocolDecl *, SourceLocation> P
+ std::pair<const ObjCProtocolDecl *, SourceLocation> P
= getCursorObjCProtocolRef(C);
return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
}
case CXCursor_ObjCClassRef: {
- std::pair<ObjCInterfaceDecl *, SourceLocation> P
+ std::pair<const ObjCInterfaceDecl *, SourceLocation> P
= getCursorObjCClassRef(C);
return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
}
case CXCursor_TypeRef: {
- std::pair<TypeDecl *, SourceLocation> P = getCursorTypeRef(C);
+ std::pair<const TypeDecl *, SourceLocation> P = getCursorTypeRef(C);
return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
}
case CXCursor_TemplateRef: {
- std::pair<TemplateDecl *, SourceLocation> P = getCursorTemplateRef(C);
+ std::pair<const TemplateDecl *, SourceLocation> P =
+ getCursorTemplateRef(C);
return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
}
case CXCursor_NamespaceRef: {
- std::pair<NamedDecl *, SourceLocation> P = getCursorNamespaceRef(C);
+ std::pair<const NamedDecl *, SourceLocation> P = getCursorNamespaceRef(C);
return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
}
case CXCursor_MemberRef: {
- std::pair<FieldDecl *, SourceLocation> P = getCursorMemberRef(C);
+ std::pair<const FieldDecl *, SourceLocation> P = getCursorMemberRef(C);
return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
}
case CXCursor_VariableRef: {
- std::pair<VarDecl *, SourceLocation> P = getCursorVariableRef(C);
+ std::pair<const VarDecl *, SourceLocation> P = getCursorVariableRef(C);
return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
}
case CXCursor_CXXBaseSpecifier: {
- CXXBaseSpecifier *BaseSpec = getCursorCXXBaseSpecifier(C);
+ const CXXBaseSpecifier *BaseSpec = getCursorCXXBaseSpecifier(C);
if (!BaseSpec)
return clang_getNullLocation();
@@ -3963,7 +4051,7 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {
}
case CXCursor_LabelRef: {
- std::pair<LabelStmt *, SourceLocation> P = getCursorLabelRef(C);
+ std::pair<const LabelStmt *, SourceLocation> P = getCursorLabelRef(C);
return cxloc::translateSourceLocation(getCursorContext(C), P.second);
}
@@ -3992,7 +4080,7 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {
if (C.kind == CXCursor_MacroExpansion) {
SourceLocation L
- = cxcursor::getCursorMacroExpansion(C)->getSourceRange().getBegin();
+ = cxcursor::getCursorMacroExpansion(C).getSourceRange().getBegin();
return cxloc::translateSourceLocation(getCursorContext(C), L);
}
@@ -4010,7 +4098,7 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {
if (!clang_isDeclaration(C.kind))
return clang_getNullLocation();
- Decl *D = getCursorDecl(C);
+ const Decl *D = getCursorDecl(C);
if (!D)
return clang_getNullLocation();
@@ -4020,13 +4108,13 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {
// ranges when accounting for the type-specifier. We use context
// stored in the CXCursor to determine if the VarDecl is in a DeclGroup,
// and if so, whether it is the first decl.
- if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (!cxcursor::isFirstInDeclGroup(C))
Loc = VD->getLocation();
}
// For ObjC methods, give the start location of the method name.
- if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
Loc = MD->getSelectorStartLoc();
return cxloc::translateSourceLocation(getCursorContext(C), Loc);
@@ -4042,7 +4130,7 @@ CXCursor cxcursor::getCursor(CXTranslationUnit TU, SourceLocation SLoc) {
if (SLoc.isInvalid())
return clang_getNullCursor();
- ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
+ ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
// Translate the given source location to make it point at the beginning of
// the token under the cursor.
@@ -4118,7 +4206,7 @@ static SourceRange getRawCursorExtent(CXCursor C) {
if (C.kind == CXCursor_MacroExpansion) {
ASTUnit *TU = getCursorASTUnit(C);
- SourceRange Range = cxcursor::getCursorMacroExpansion(C)->getSourceRange();
+ SourceRange Range = cxcursor::getCursorMacroExpansion(C).getSourceRange();
return TU->mapRangeFromPreamble(Range);
}
@@ -4143,7 +4231,7 @@ static SourceRange getRawCursorExtent(CXCursor C) {
}
if (clang_isDeclaration(C.kind)) {
- Decl *D = cxcursor::getCursorDecl(C);
+ const Decl *D = cxcursor::getCursorDecl(C);
if (!D)
return SourceRange();
@@ -4153,7 +4241,7 @@ static SourceRange getRawCursorExtent(CXCursor C) {
// ranges when accounting for the type-specifier. We use context
// stored in the CXCursor to determine if the VarDecl is in a DeclGroup,
// and if so, whether it is the first decl.
- if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (!cxcursor::isFirstInDeclGroup(C))
R.setBegin(VD->getLocation());
}
@@ -4166,7 +4254,7 @@ static SourceRange getRawCursorExtent(CXCursor C) {
/// the decl-specifier-seq for declarations.
static SourceRange getFullCursorExtent(CXCursor C, SourceManager &SrcMgr) {
if (clang_isDeclaration(C.kind)) {
- Decl *D = cxcursor::getCursorDecl(C);
+ const Decl *D = cxcursor::getCursorDecl(C);
if (!D)
return SourceRange();
@@ -4178,7 +4266,7 @@ static SourceRange getFullCursorExtent(CXCursor C, SourceManager &SrcMgr) {
if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
if (TypeSourceInfo *TI = DD->getTypeSourceInfo())
StartLoc = TI->getTypeLoc().getLocStart();
- } else if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(D)) {
+ } else if (const TypedefDecl *Typedef = dyn_cast<TypedefDecl>(D)) {
if (TypeSourceInfo *TI = Typedef->getTypeSourceInfo())
StartLoc = TI->getTypeLoc().getLocStart();
}
@@ -4192,7 +4280,7 @@ static SourceRange getFullCursorExtent(CXCursor C, SourceManager &SrcMgr) {
// ranges when accounting for the type-specifier. We use context
// stored in the CXCursor to determine if the VarDecl is in a DeclGroup,
// and if so, whether it is the first decl.
- if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (!cxcursor::isFirstInDeclGroup(C))
R.setBegin(VD->getLocation());
}
@@ -4219,12 +4307,13 @@ CXCursor clang_getCursorReferenced(CXCursor C) {
CXTranslationUnit tu = getCursorTU(C);
if (clang_isDeclaration(C.kind)) {
- Decl *D = getCursorDecl(C);
+ const Decl *D = getCursorDecl(C);
if (!D)
return clang_getNullCursor();
- if (UsingDecl *Using = dyn_cast<UsingDecl>(D))
+ if (const UsingDecl *Using = dyn_cast<UsingDecl>(D))
return MakeCursorOverloadedDeclRef(Using, D->getLocation(), tu);
- if (ObjCPropertyImplDecl *PropImpl =dyn_cast<ObjCPropertyImplDecl>(D))
+ if (const ObjCPropertyImplDecl *PropImpl =
+ dyn_cast<ObjCPropertyImplDecl>(D))
if (ObjCPropertyDecl *Property = PropImpl->getPropertyDecl())
return MakeCXCursor(Property, tu);
@@ -4232,8 +4321,8 @@ CXCursor clang_getCursorReferenced(CXCursor C) {
}
if (clang_isExpression(C.kind)) {
- Expr *E = getCursorExpr(C);
- Decl *D = getDeclFromExpr(E);
+ const Expr *E = getCursorExpr(C);
+ const Decl *D = getDeclFromExpr(E);
if (D) {
CXCursor declCursor = MakeCXCursor(D, tu);
declCursor = getSelectorIdentifierCursor(getSelectorIdentifierIndex(C),
@@ -4241,15 +4330,15 @@ CXCursor clang_getCursorReferenced(CXCursor C) {
return declCursor;
}
- if (OverloadExpr *Ovl = dyn_cast_or_null<OverloadExpr>(E))
+ if (const OverloadExpr *Ovl = dyn_cast_or_null<OverloadExpr>(E))
return MakeCursorOverloadedDeclRef(Ovl, tu);
return clang_getNullCursor();
}
if (clang_isStatement(C.kind)) {
- Stmt *S = getCursorStmt(C);
- if (GotoStmt *Goto = dyn_cast_or_null<GotoStmt>(S))
+ const Stmt *S = getCursorStmt(C);
+ if (const GotoStmt *Goto = dyn_cast_or_null<GotoStmt>(S))
if (LabelDecl *label = Goto->getLabel())
if (LabelStmt *labelS = label->getStmt())
return MakeCXCursor(labelS, getCursorDecl(C), tu);
@@ -4258,7 +4347,7 @@ CXCursor clang_getCursorReferenced(CXCursor C) {
}
if (C.kind == CXCursor_MacroExpansion) {
- if (MacroDefinition *Def = getCursorMacroExpansion(C)->getDefinition())
+ if (const MacroDefinition *Def = getCursorMacroExpansion(C).getDefinition())
return MakeMacroDefinitionCursor(Def, tu);
}
@@ -4270,16 +4359,16 @@ CXCursor clang_getCursorReferenced(CXCursor C) {
return MakeCXCursor(getCursorObjCSuperClassRef(C).first, tu);
case CXCursor_ObjCProtocolRef: {
- ObjCProtocolDecl *Prot = getCursorObjCProtocolRef(C).first;
- if (ObjCProtocolDecl *Def = Prot->getDefinition())
+ const ObjCProtocolDecl *Prot = getCursorObjCProtocolRef(C).first;
+ if (const ObjCProtocolDecl *Def = Prot->getDefinition())
return MakeCXCursor(Def, tu);
return MakeCXCursor(Prot, tu);
}
case CXCursor_ObjCClassRef: {
- ObjCInterfaceDecl *Class = getCursorObjCClassRef(C).first;
- if (ObjCInterfaceDecl *Def = Class->getDefinition())
+ const ObjCInterfaceDecl *Class = getCursorObjCClassRef(C).first;
+ if (const ObjCInterfaceDecl *Def = Class->getDefinition())
return MakeCXCursor(Def, tu);
return MakeCXCursor(Class, tu);
@@ -4298,7 +4387,7 @@ CXCursor clang_getCursorReferenced(CXCursor C) {
return MakeCXCursor(getCursorMemberRef(C).first, tu );
case CXCursor_CXXBaseSpecifier: {
- CXXBaseSpecifier *B = cxcursor::getCursorCXXBaseSpecifier(C);
+ const CXXBaseSpecifier *B = cxcursor::getCursorCXXBaseSpecifier(C);
return clang_getTypeDeclaration(cxtype::MakeCXType(B->getType(),
tu ));
}
@@ -4306,9 +4395,9 @@ CXCursor clang_getCursorReferenced(CXCursor C) {
case CXCursor_LabelRef:
// FIXME: We end up faking the "parent" declaration here because we
// don't want to make CXCursor larger.
- return MakeCXCursor(getCursorLabelRef(C).first,
- static_cast<ASTUnit*>(tu->TUData)->getASTContext()
- .getTranslationUnitDecl(),
+ return MakeCXCursor(getCursorLabelRef(C).first,
+ cxtu::getASTUnit(tu)->getASTContext()
+ .getTranslationUnitDecl(),
tu);
case CXCursor_OverloadedDeclRef:
@@ -4341,7 +4430,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
if (!clang_isDeclaration(C.kind))
return clang_getNullCursor();
- Decl *D = getCursorDecl(C);
+ const Decl *D = getCursorDecl(C);
if (!D)
return clang_getNullCursor();
@@ -4373,10 +4462,12 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::Label: // FIXME: Is this right??
case Decl::ClassScopeFunctionSpecialization:
case Decl::Import:
+ case Decl::OMPThreadPrivate:
return C;
// Declaration kinds that don't make any sense here, but are
// nonetheless harmless.
+ case Decl::Empty:
case Decl::TranslationUnit:
break;
@@ -4408,13 +4499,13 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::CXXConversion: {
const FunctionDecl *Def = 0;
if (cast<FunctionDecl>(D)->getBody(Def))
- return MakeCXCursor(const_cast<FunctionDecl *>(Def), TU);
+ return MakeCXCursor(Def, TU);
return clang_getNullCursor();
}
case Decl::Var: {
// Ask the variable if it has a definition.
- if (VarDecl *Def = cast<VarDecl>(D)->getDefinition())
+ if (const VarDecl *Def = cast<VarDecl>(D)->getDefinition())
return MakeCXCursor(Def, TU);
return clang_getNullCursor();
}
@@ -4444,14 +4535,14 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
TU));
case Decl::ObjCMethod: {
- ObjCMethodDecl *Method = cast<ObjCMethodDecl>(D);
+ const ObjCMethodDecl *Method = cast<ObjCMethodDecl>(D);
if (Method->isThisDeclarationADefinition())
return C;
// Dig out the method definition in the associated
// @implementation, if we have it.
// FIXME: The ASTs should make finding the definition easier.
- if (ObjCInterfaceDecl *Class
+ if (const ObjCInterfaceDecl *Class
= dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext()))
if (ObjCImplementationDecl *ClassImpl = Class->getImplementation())
if (ObjCMethodDecl *Def = ClassImpl->getMethod(Method->getSelector(),
@@ -4469,7 +4560,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
return clang_getNullCursor();
case Decl::ObjCProtocol:
- if (ObjCProtocolDecl *Def = cast<ObjCProtocolDecl>(D)->getDefinition())
+ if (const ObjCProtocolDecl *Def = cast<ObjCProtocolDecl>(D)->getDefinition())
return MakeCXCursor(Def, TU);
return clang_getNullCursor();
@@ -4479,9 +4570,9 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
// reference to an Objective-C class, produce the @interface as
// the definition; when we were provided with the interface,
// produce the @implementation as the definition.
- ObjCInterfaceDecl *IFace = cast<ObjCInterfaceDecl>(D);
+ const ObjCInterfaceDecl *IFace = cast<ObjCInterfaceDecl>(D);
if (WasReference) {
- if (ObjCInterfaceDecl *Def = IFace->getDefinition())
+ if (const ObjCInterfaceDecl *Def = IFace->getDefinition())
return MakeCXCursor(Def, TU);
} else if (ObjCImplementationDecl *Impl = IFace->getImplementation())
return MakeCXCursor(Impl, TU);
@@ -4494,9 +4585,9 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
return clang_getNullCursor();
case Decl::ObjCCompatibleAlias:
- if (ObjCInterfaceDecl *Class
+ if (const ObjCInterfaceDecl *Class
= cast<ObjCCompatibleAliasDecl>(D)->getClassInterface())
- if (ObjCInterfaceDecl *Def = Class->getDefinition())
+ if (const ObjCInterfaceDecl *Def = Class->getDefinition())
return MakeCXCursor(Def, TU);
return clang_getNullCursor();
@@ -4526,13 +4617,13 @@ CXCursor clang_getCanonicalCursor(CXCursor C) {
if (!clang_isDeclaration(C.kind))
return C;
- if (Decl *D = getCursorDecl(C)) {
- if (ObjCCategoryImplDecl *CatImplD = dyn_cast<ObjCCategoryImplDecl>(D))
+ if (const Decl *D = getCursorDecl(C)) {
+ if (const ObjCCategoryImplDecl *CatImplD = dyn_cast<ObjCCategoryImplDecl>(D))
if (ObjCCategoryDecl *CatD = CatImplD->getCategoryDecl())
return MakeCXCursor(CatD, getCursorTU(C));
- if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D))
- if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface())
+ if (const ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D))
+ if (const ObjCInterfaceDecl *IFD = ImplD->getClassInterface())
return MakeCXCursor(IFD, getCursorTU(C));
return MakeCXCursor(D->getCanonicalDecl(), getCursorTU(C));
@@ -4550,15 +4641,15 @@ unsigned clang_getNumOverloadedDecls(CXCursor C) {
return 0;
OverloadedDeclRefStorage Storage = getCursorOverloadedDeclRef(C).first;
- if (OverloadExpr *E = Storage.dyn_cast<OverloadExpr *>())
+ if (const OverloadExpr *E = Storage.dyn_cast<const OverloadExpr *>())
return E->getNumDecls();
if (OverloadedTemplateStorage *S
= Storage.dyn_cast<OverloadedTemplateStorage*>())
return S->size();
- Decl *D = Storage.get<Decl*>();
- if (UsingDecl *Using = dyn_cast<UsingDecl>(D))
+ const Decl *D = Storage.get<const Decl *>();
+ if (const UsingDecl *Using = dyn_cast<UsingDecl>(D))
return Using->shadow_size();
return 0;
@@ -4573,15 +4664,15 @@ CXCursor clang_getOverloadedDecl(CXCursor cursor, unsigned index) {
CXTranslationUnit TU = getCursorTU(cursor);
OverloadedDeclRefStorage Storage = getCursorOverloadedDeclRef(cursor).first;
- if (OverloadExpr *E = Storage.dyn_cast<OverloadExpr *>())
+ if (const OverloadExpr *E = Storage.dyn_cast<const OverloadExpr *>())
return MakeCXCursor(E->decls_begin()[index], TU);
if (OverloadedTemplateStorage *S
= Storage.dyn_cast<OverloadedTemplateStorage*>())
return MakeCXCursor(S->begin()[index], TU);
- Decl *D = Storage.get<Decl*>();
- if (UsingDecl *Using = dyn_cast<UsingDecl>(D)) {
+ const Decl *D = Storage.get<const Decl *>();
+ if (const UsingDecl *Using = dyn_cast<UsingDecl>(D)) {
// FIXME: This is, unfortunately, linear time.
UsingDecl::shadow_iterator Pos = Using->shadow_begin();
std::advance(Pos, index);
@@ -4599,8 +4690,7 @@ void clang_getDefinitionSpellingAndExtent(CXCursor C,
unsigned *endLine,
unsigned *endColumn) {
assert(getCursorDecl(C) && "CXCursor has null decl");
- NamedDecl *ND = static_cast<NamedDecl *>(getCursorDecl(C));
- FunctionDecl *FD = dyn_cast<FunctionDecl>(ND);
+ const FunctionDecl *FD = dyn_cast<FunctionDecl>(getCursorDecl(C));
CompoundStmt *Body = dyn_cast<CompoundStmt>(FD->getBody());
SourceManager &SM = FD->getASTContext().getSourceManager();
@@ -4619,26 +4709,26 @@ CXSourceRange clang_getCursorReferenceNameRange(CXCursor C, unsigned NameFlags,
switch (C.kind) {
case CXCursor_MemberRefExpr:
- if (MemberExpr *E = dyn_cast<MemberExpr>(getCursorExpr(C)))
+ if (const MemberExpr *E = dyn_cast<MemberExpr>(getCursorExpr(C)))
Pieces = buildPieces(NameFlags, true, E->getMemberNameInfo(),
E->getQualifierLoc().getSourceRange());
break;
case CXCursor_DeclRefExpr:
- if (DeclRefExpr *E = dyn_cast<DeclRefExpr>(getCursorExpr(C)))
+ if (const DeclRefExpr *E = dyn_cast<DeclRefExpr>(getCursorExpr(C)))
Pieces = buildPieces(NameFlags, false, E->getNameInfo(),
E->getQualifierLoc().getSourceRange(),
E->getOptionalExplicitTemplateArgs());
break;
case CXCursor_CallExpr:
- if (CXXOperatorCallExpr *OCE =
+ if (const CXXOperatorCallExpr *OCE =
dyn_cast<CXXOperatorCallExpr>(getCursorExpr(C))) {
- Expr *Callee = OCE->getCallee();
- if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Callee))
+ const Expr *Callee = OCE->getCallee();
+ if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Callee))
Callee = ICE->getSubExpr();
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Callee))
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Callee))
Pieces = buildPieces(NameFlags, false, DRE->getNameInfo(),
DRE->getQualifierLoc().getSourceRange());
}
@@ -4694,13 +4784,13 @@ CXString clang_getTokenSpelling(CXTranslationUnit TU, CXToken CXTok) {
case CXToken_Identifier:
case CXToken_Keyword:
// We know we have an IdentifierInfo*, so use that.
- return createCXString(static_cast<IdentifierInfo *>(CXTok.ptr_data)
+ return cxstring::createRef(static_cast<IdentifierInfo *>(CXTok.ptr_data)
->getNameStart());
case CXToken_Literal: {
// We have stashed the starting pointer in the ptr_data field. Use it.
const char *Text = static_cast<const char *>(CXTok.ptr_data);
- return createCXString(StringRef(Text, CXTok.int_data[2]));
+ return cxstring::createDup(StringRef(Text, CXTok.int_data[2]));
}
case CXToken_Punctuation:
@@ -4710,9 +4800,9 @@ CXString clang_getTokenSpelling(CXTranslationUnit TU, CXToken CXTok) {
// We have to find the starting buffer pointer the hard way, by
// deconstructing the source location.
- ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
+ ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
if (!CXXUnit)
- return createCXString("");
+ return cxstring::createEmpty();
SourceLocation Loc = SourceLocation::getFromRawEncoding(CXTok.int_data[1]);
std::pair<FileID, unsigned> LocInfo
@@ -4721,13 +4811,13 @@ CXString clang_getTokenSpelling(CXTranslationUnit TU, CXToken CXTok) {
StringRef Buffer
= CXXUnit->getSourceManager().getBufferData(LocInfo.first, &Invalid);
if (Invalid)
- return createCXString("");
+ return cxstring::createEmpty();
- return createCXString(Buffer.substr(LocInfo.second, CXTok.int_data[2]));
+ return cxstring::createDup(Buffer.substr(LocInfo.second, CXTok.int_data[2]));
}
CXSourceLocation clang_getTokenLocation(CXTranslationUnit TU, CXToken CXTok) {
- ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
+ ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
if (!CXXUnit)
return clang_getNullLocation();
@@ -4736,7 +4826,7 @@ CXSourceLocation clang_getTokenLocation(CXTranslationUnit TU, CXToken CXTok) {
}
CXSourceRange clang_getTokenExtent(CXTranslationUnit TU, CXToken CXTok) {
- ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
+ ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
if (!CXXUnit)
return clang_getNullRange();
@@ -4748,9 +4838,9 @@ static void getTokens(ASTUnit *CXXUnit, SourceRange Range,
SmallVectorImpl<CXToken> &CXTokens) {
SourceManager &SourceMgr = CXXUnit->getSourceManager();
std::pair<FileID, unsigned> BeginLocInfo
- = SourceMgr.getDecomposedLoc(Range.getBegin());
+ = SourceMgr.getDecomposedSpellingLoc(Range.getBegin());
std::pair<FileID, unsigned> EndLocInfo
- = SourceMgr.getDecomposedLoc(Range.getEnd());
+ = SourceMgr.getDecomposedSpellingLoc(Range.getEnd());
// Cannot tokenize across files.
if (BeginLocInfo.first != EndLocInfo.first)
@@ -4789,7 +4879,7 @@ static void getTokens(ASTUnit *CXXUnit, SourceRange Range,
// - Kind-specific fields
if (Tok.isLiteral()) {
CXTok.int_data[0] = CXToken_Literal;
- CXTok.ptr_data = (void *)Tok.getLiteralData();
+ CXTok.ptr_data = const_cast<char *>(Tok.getLiteralData());
} else if (Tok.is(tok::raw_identifier)) {
// Lookup the identifier to determine whether we have a keyword.
IdentifierInfo *II
@@ -4818,12 +4908,19 @@ static void getTokens(ASTUnit *CXXUnit, SourceRange Range,
void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range,
CXToken **Tokens, unsigned *NumTokens) {
+ LOG_FUNC_SECTION {
+ *Log << TU << ' ' << Range;
+ }
+
if (Tokens)
*Tokens = 0;
if (NumTokens)
*NumTokens = 0;
- ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
+ if (!TU)
+ return;
+
+ ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
if (!CXXUnit || !Tokens || !NumTokens)
return;
@@ -4855,7 +4952,6 @@ void clang_disposeTokens(CXTranslationUnit TU,
// Token annotation APIs.
//===----------------------------------------------------------------------===//
-typedef llvm::DenseMap<unsigned, CXCursor> AnnotateTokensData;
static enum CXChildVisitResult AnnotateTokensVisitor(CXCursor cursor,
CXCursor parent,
CXClientData client_data);
@@ -4864,7 +4960,6 @@ static bool AnnotateTokensPostChildrenVisitor(CXCursor cursor,
namespace {
class AnnotateTokensWorker {
- AnnotateTokensData &Annotated;
CXToken *Tokens;
CXCursor *Cursors;
unsigned NumTokens;
@@ -4877,9 +4972,10 @@ class AnnotateTokensWorker {
struct PostChildrenInfo {
CXCursor Cursor;
SourceRange CursorRange;
+ unsigned BeforeReachingCursorIdx;
unsigned BeforeChildrenTokenIdx;
};
- llvm::SmallVector<PostChildrenInfo, 8> PostChildrenInfos;
+ SmallVector<PostChildrenInfo, 8> PostChildrenInfos;
bool MoreTokens() const { return TokIdx < NumTokens; }
unsigned NextToken() const { return TokIdx; }
@@ -4895,23 +4991,22 @@ class AnnotateTokensWorker {
}
void annotateAndAdvanceTokens(CXCursor, RangeComparisonResult, SourceRange);
- void annotateAndAdvanceFunctionMacroTokens(CXCursor, RangeComparisonResult,
+ bool annotateAndAdvanceFunctionMacroTokens(CXCursor, RangeComparisonResult,
SourceRange);
public:
- AnnotateTokensWorker(AnnotateTokensData &annotated,
- CXToken *tokens, CXCursor *cursors, unsigned numTokens,
- CXTranslationUnit tu, SourceRange RegionOfInterest)
- : Annotated(annotated), Tokens(tokens), Cursors(cursors),
+ AnnotateTokensWorker(CXToken *tokens, CXCursor *cursors, unsigned numTokens,
+ CXTranslationUnit TU, SourceRange RegionOfInterest)
+ : Tokens(tokens), Cursors(cursors),
NumTokens(numTokens), TokIdx(0), PreprocessingTokIdx(0),
- AnnotateVis(tu,
+ AnnotateVis(TU,
AnnotateTokensVisitor, this,
/*VisitPreprocessorLast=*/true,
/*VisitIncludedEntities=*/false,
RegionOfInterest,
/*VisitDeclsOnly=*/false,
AnnotateTokensPostChildrenVisitor),
- SrcMgr(static_cast<ASTUnit*>(tu->TUData)->getSourceManager()),
+ SrcMgr(cxtu::getASTUnit(TU)->getSourceManager()),
HasContextSensitiveKeywords(false) { }
void VisitChildren(CXCursor C) { AnnotateVis.VisitChildren(C); }
@@ -4935,27 +5030,13 @@ void AnnotateTokensWorker::AnnotateTokens() {
// Walk the AST within the region of interest, annotating tokens
// along the way.
AnnotateVis.visitFileRegion();
+}
- for (unsigned I = 0 ; I < TokIdx ; ++I) {
- AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]);
- if (Pos != Annotated.end() &&
- (clang_isInvalid(Cursors[I].kind) ||
- Pos->second.kind != CXCursor_PreprocessingDirective))
- Cursors[I] = Pos->second;
- }
-
- // Finish up annotating any tokens left.
- if (!MoreTokens())
+static inline void updateCursorAnnotation(CXCursor &Cursor,
+ const CXCursor &updateC) {
+ if (clang_isInvalid(updateC.kind) || !clang_isInvalid(Cursor.kind))
return;
-
- const CXCursor &C = clang_getNullCursor();
- for (unsigned I = TokIdx ; I < NumTokens ; ++I) {
- if (I < PreprocessingTokIdx && clang_isPreprocessing(Cursors[I].kind))
- continue;
-
- AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]);
- Cursors[I] = (Pos == Annotated.end()) ? C : Pos->second;
- }
+ Cursor = updateC;
}
/// \brief It annotates and advances tokens with a cursor until the comparison
@@ -4970,11 +5051,12 @@ void AnnotateTokensWorker::annotateAndAdvanceTokens(CXCursor updateC,
while (MoreTokens()) {
const unsigned I = NextToken();
if (isFunctionMacroToken(I))
- return annotateAndAdvanceFunctionMacroTokens(updateC, compResult, range);
+ if (!annotateAndAdvanceFunctionMacroTokens(updateC, compResult, range))
+ return;
SourceLocation TokLoc = GetTokenLoc(I);
if (LocationCompare(SrcMgr, TokLoc, range) == compResult) {
- Cursors[I] = updateC;
+ updateCursorAnnotation(Cursors[I], updateC);
AdvanceToken();
continue;
}
@@ -4983,7 +5065,8 @@ void AnnotateTokensWorker::annotateAndAdvanceTokens(CXCursor updateC,
}
/// \brief Special annotation handling for macro argument tokens.
-void AnnotateTokensWorker::annotateAndAdvanceFunctionMacroTokens(
+/// \returns true if it advanced beyond all macro tokens, false otherwise.
+bool AnnotateTokensWorker::annotateAndAdvanceFunctionMacroTokens(
CXCursor updateC,
RangeComparisonResult compResult,
SourceRange range) {
@@ -5013,13 +5096,15 @@ void AnnotateTokensWorker::annotateAndAdvanceFunctionMacroTokens(
atLeastOneCompFail = true;
}
- if (!atLeastOneCompFail)
- TokIdx = I; // All of the tokens were handled, advance beyond all of them.
+ if (atLeastOneCompFail)
+ return false;
+
+ TokIdx = I; // All of the tokens were handled, advance beyond all of them.
+ return true;
}
enum CXChildVisitResult
AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
- CXSourceLocation Loc = clang_getCursorLocation(cursor);
SourceRange cursorRange = getRawCursorExtent(cursor);
if (cursorRange.isInvalid())
return CXChildVisit_Recurse;
@@ -5027,20 +5112,20 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
if (!HasContextSensitiveKeywords) {
// Objective-C properties can have context-sensitive keywords.
if (cursor.kind == CXCursor_ObjCPropertyDecl) {
- if (ObjCPropertyDecl *Property
+ if (const ObjCPropertyDecl *Property
= dyn_cast_or_null<ObjCPropertyDecl>(getCursorDecl(cursor)))
HasContextSensitiveKeywords = Property->getPropertyAttributesAsWritten() != 0;
}
// Objective-C methods can have context-sensitive keywords.
else if (cursor.kind == CXCursor_ObjCInstanceMethodDecl ||
cursor.kind == CXCursor_ObjCClassMethodDecl) {
- if (ObjCMethodDecl *Method
+ if (const ObjCMethodDecl *Method
= dyn_cast_or_null<ObjCMethodDecl>(getCursorDecl(cursor))) {
if (Method->getObjCDeclQualifier())
HasContextSensitiveKeywords = true;
else {
- for (ObjCMethodDecl::param_iterator P = Method->param_begin(),
- PEnd = Method->param_end();
+ for (ObjCMethodDecl::param_const_iterator P = Method->param_begin(),
+ PEnd = Method->param_end();
P != PEnd; ++P) {
if ((*P)->getObjCDeclQualifier()) {
HasContextSensitiveKeywords = true;
@@ -5052,7 +5137,7 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
}
// C++ methods can have context-sensitive keywords.
else if (cursor.kind == CXCursor_CXXMethod) {
- if (CXXMethodDecl *Method
+ if (const CXXMethodDecl *Method
= dyn_cast_or_null<CXXMethodDecl>(getCursorDecl(cursor))) {
if (Method->hasAttr<FinalAttr>() || Method->hasAttr<OverrideAttr>())
HasContextSensitiveKeywords = true;
@@ -5063,20 +5148,13 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
cursor.kind == CXCursor_ClassDecl ||
cursor.kind == CXCursor_ClassTemplate ||
cursor.kind == CXCursor_ClassTemplatePartialSpecialization) {
- if (Decl *D = getCursorDecl(cursor))
+ if (const Decl *D = getCursorDecl(cursor))
if (D->hasAttr<FinalAttr>())
HasContextSensitiveKeywords = true;
}
}
if (clang_isPreprocessing(cursor.kind)) {
- // For macro expansions, just note where the beginning of the macro
- // expansion occurs.
- if (cursor.kind == CXCursor_MacroExpansion) {
- Annotated[Loc.int_data] = cursor;
- return CXChildVisit_Recurse;
- }
-
// Items in the preprocessing record are kept separate from items in
// declarations, so we keep a separate token index.
unsigned SavedTokIdx = TokIdx;
@@ -5108,7 +5186,17 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
case RangeAfter:
break;
case RangeOverlap:
- Cursors[I] = cursor;
+ // For macro expansions, just note where the beginning of the macro
+ // expansion occurs.
+ if (cursor.kind == CXCursor_MacroExpansion) {
+ if (TokLoc == cursorRange.getBegin())
+ Cursors[I] = cursor;
+ AdvanceToken();
+ break;
+ }
+ // We may have already annotated macro names inside macro definitions.
+ if (Cursors[I].kind != CXCursor_MacroExpansion)
+ Cursors[I] = cursor;
AdvanceToken();
continue;
}
@@ -5124,48 +5212,14 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
if (cursorRange.isInvalid())
return CXChildVisit_Continue;
-
- SourceLocation L = SourceLocation::getFromRawEncoding(Loc.int_data);
- // Adjust the annotated range based specific declarations.
+ unsigned BeforeReachingCursorIdx = NextToken();
const enum CXCursorKind cursorK = clang_getCursorKind(cursor);
- if (clang_isDeclaration(cursorK)) {
- Decl *D = cxcursor::getCursorDecl(cursor);
-
- SourceLocation StartLoc;
- if (const DeclaratorDecl *DD = dyn_cast_or_null<DeclaratorDecl>(D)) {
- if (TypeSourceInfo *TI = DD->getTypeSourceInfo())
- StartLoc = TI->getTypeLoc().getLocStart();
- } else if (TypedefDecl *Typedef = dyn_cast_or_null<TypedefDecl>(D)) {
- if (TypeSourceInfo *TI = Typedef->getTypeSourceInfo())
- StartLoc = TI->getTypeLoc().getLocStart();
- }
-
- if (StartLoc.isValid() && L.isValid() &&
- SrcMgr.isBeforeInTranslationUnit(StartLoc, L))
- cursorRange.setBegin(StartLoc);
- }
-
- // If the location of the cursor occurs within a macro instantiation, record
- // the spelling location of the cursor in our annotation map. We can then
- // paper over the token labelings during a post-processing step to try and
- // get cursor mappings for tokens that are the *arguments* of a macro
- // instantiation.
- if (L.isMacroID()) {
- unsigned rawEncoding = SrcMgr.getSpellingLoc(L).getRawEncoding();
- // Only invalidate the old annotation if it isn't part of a preprocessing
- // directive. Here we assume that the default construction of CXCursor
- // results in CXCursor.kind being an initialized value (i.e., 0). If
- // this isn't the case, we can fix by doing lookup + insertion.
-
- CXCursor &oldC = Annotated[rawEncoding];
- if (!clang_isPreprocessing(oldC.kind))
- oldC = cursor;
- }
-
const enum CXCursorKind K = clang_getCursorKind(parent);
const CXCursor updateC =
- (clang_isInvalid(K) || K == CXCursor_TranslationUnit)
+ (clang_isInvalid(K) || K == CXCursor_TranslationUnit ||
+ // Attributes are annotated out-of-order, skip tokens until we reach it.
+ clang_isAttribute(cursor.kind))
? clang_getNullCursor() : parent;
annotateAndAdvanceTokens(updateC, RangeBefore, cursorRange);
@@ -5176,13 +5230,13 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
// include the variable declaration, e.g.:
// MyCXXClass foo; // Make sure we don't annotate 'foo' as a CallExpr cursor.
if (clang_isExpression(cursorK)) {
- Expr *E = getCursorExpr(cursor);
- if (Decl *D = getCursorParentDecl(cursor)) {
+ const Expr *E = getCursorExpr(cursor);
+ if (const Decl *D = getCursorParentDecl(cursor)) {
const unsigned I = NextToken();
if (E->getLocStart().isValid() && D->getLocation().isValid() &&
E->getLocStart() == D->getLocation() &&
E->getLocStart() == GetTokenLoc(I)) {
- Cursors[I] = updateC;
+ updateCursorAnnotation(Cursors[I], updateC);
AdvanceToken();
}
}
@@ -5197,6 +5251,7 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
PostChildrenInfo Info;
Info.Cursor = cursor;
Info.CursorRange = cursorRange;
+ Info.BeforeReachingCursorIdx = BeforeReachingCursorIdx;
Info.BeforeChildrenTokenIdx = NextToken();
PostChildrenInfos.push_back(Info);
@@ -5227,6 +5282,11 @@ bool AnnotateTokensWorker::postVisitChildren(CXCursor cursor) {
Cursors[I] = cursor;
}
+ // Attributes are annotated out-of-order, rewind TokIdx to when we first
+ // encountered the attribute cursor.
+ if (clang_isAttribute(cursor.kind))
+ TokIdx = Info.BeforeReachingCursorIdx;
+
PostChildrenInfos.pop_back();
return false;
}
@@ -5263,7 +5323,7 @@ public:
if (cursor.kind != CXCursor_MacroExpansion)
return CXChildVisit_Continue;
- SourceRange macroRange = getCursorMacroExpansion(cursor)->getSourceRange();
+ SourceRange macroRange = getCursorMacroExpansion(cursor).getSourceRange();
if (macroRange.getBegin() == macroRange.getEnd())
return CXChildVisit_Continue; // it's not a function macro.
@@ -5321,16 +5381,34 @@ namespace {
};
}
+/// \brief Used by \c annotatePreprocessorTokens.
+/// \returns true if lexing was finished, false otherwise.
+static bool lexNext(Lexer &Lex, Token &Tok,
+ unsigned &NextIdx, unsigned NumTokens) {
+ if (NextIdx >= NumTokens)
+ return true;
+
+ ++NextIdx;
+ Lex.LexFromRawLexer(Tok);
+ if (Tok.is(tok::eof))
+ return true;
+
+ return false;
+}
+
static void annotatePreprocessorTokens(CXTranslationUnit TU,
SourceRange RegionOfInterest,
- AnnotateTokensData &Annotated) {
- ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
+ CXCursor *Cursors,
+ CXToken *Tokens,
+ unsigned NumTokens) {
+ ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
+ Preprocessor &PP = CXXUnit->getPreprocessor();
SourceManager &SourceMgr = CXXUnit->getSourceManager();
std::pair<FileID, unsigned> BeginLocInfo
- = SourceMgr.getDecomposedLoc(RegionOfInterest.getBegin());
+ = SourceMgr.getDecomposedSpellingLoc(RegionOfInterest.getBegin());
std::pair<FileID, unsigned> EndLocInfo
- = SourceMgr.getDecomposedLoc(RegionOfInterest.getEnd());
+ = SourceMgr.getDecomposedSpellingLoc(RegionOfInterest.getEnd());
if (BeginLocInfo.first != EndLocInfo.first)
return;
@@ -5347,44 +5425,77 @@ static void annotatePreprocessorTokens(CXTranslationUnit TU,
Buffer.end());
Lex.SetCommentRetentionState(true);
+ unsigned NextIdx = 0;
// Lex tokens in raw mode until we hit the end of the range, to avoid
// entering #includes or expanding macros.
while (true) {
Token Tok;
- Lex.LexFromRawLexer(Tok);
+ if (lexNext(Lex, Tok, NextIdx, NumTokens))
+ break;
+ unsigned TokIdx = NextIdx-1;
+ assert(Tok.getLocation() ==
+ SourceLocation::getFromRawEncoding(Tokens[TokIdx].int_data[1]));
reprocess:
if (Tok.is(tok::hash) && Tok.isAtStartOfLine()) {
- // We have found a preprocessing directive. Gobble it up so that we
- // don't see it while preprocessing these tokens later, but keep track
- // of all of the token locations inside this preprocessing directive so
- // that we can annotate them appropriately.
+ // We have found a preprocessing directive. Annotate the tokens
+ // appropriately.
//
// FIXME: Some simple tests here could identify macro definitions and
// #undefs, to provide specific cursor kinds for those.
- SmallVector<SourceLocation, 32> Locations;
- do {
- Locations.push_back(Tok.getLocation());
- Lex.LexFromRawLexer(Tok);
- } while (!Tok.isAtStartOfLine() && !Tok.is(tok::eof));
-
- using namespace cxcursor;
- CXCursor Cursor
- = MakePreprocessingDirectiveCursor(SourceRange(Locations.front(),
- Locations.back()),
- TU);
- for (unsigned I = 0, N = Locations.size(); I != N; ++I) {
- Annotated[Locations[I].getRawEncoding()] = Cursor;
+
+ SourceLocation BeginLoc = Tok.getLocation();
+ if (lexNext(Lex, Tok, NextIdx, NumTokens))
+ break;
+
+ MacroInfo *MI = 0;
+ if (Tok.is(tok::raw_identifier) &&
+ StringRef(Tok.getRawIdentifierData(), Tok.getLength()) == "define") {
+ if (lexNext(Lex, Tok, NextIdx, NumTokens))
+ break;
+
+ if (Tok.is(tok::raw_identifier)) {
+ StringRef Name(Tok.getRawIdentifierData(), Tok.getLength());
+ IdentifierInfo &II = PP.getIdentifierTable().get(Name);
+ SourceLocation MappedTokLoc =
+ CXXUnit->mapLocationToPreamble(Tok.getLocation());
+ MI = getMacroInfo(II, MappedTokLoc, TU);
+ }
}
+
+ bool finished = false;
+ do {
+ if (lexNext(Lex, Tok, NextIdx, NumTokens)) {
+ finished = true;
+ break;
+ }
+ // If we are in a macro definition, check if the token was ever a
+ // macro name and annotate it if that's the case.
+ if (MI) {
+ SourceLocation SaveLoc = Tok.getLocation();
+ Tok.setLocation(CXXUnit->mapLocationToPreamble(SaveLoc));
+ MacroDefinition *MacroDef = checkForMacroInMacroDefinition(MI,Tok,TU);
+ Tok.setLocation(SaveLoc);
+ if (MacroDef)
+ Cursors[NextIdx-1] = MakeMacroExpansionCursor(MacroDef,
+ Tok.getLocation(), TU);
+ }
+ } while (!Tok.isAtStartOfLine());
+
+ unsigned LastIdx = finished ? NextIdx-1 : NextIdx-2;
+ assert(TokIdx <= LastIdx);
+ SourceLocation EndLoc =
+ SourceLocation::getFromRawEncoding(Tokens[LastIdx].int_data[1]);
+ CXCursor Cursor =
+ MakePreprocessingDirectiveCursor(SourceRange(BeginLoc, EndLoc), TU);
+
+ for (; TokIdx <= LastIdx; ++TokIdx)
+ updateCursorAnnotation(Cursors[TokIdx], Cursor);
- if (Tok.isAtStartOfLine())
- goto reprocess;
-
- continue;
+ if (finished)
+ break;
+ goto reprocess;
}
-
- if (Tok.is(tok::eof))
- break;
}
}
@@ -5396,7 +5507,7 @@ static void clang_annotateTokensImpl(void *UserData) {
const unsigned NumTokens = ((clang_annotateTokens_Data*)UserData)->NumTokens;
CXCursor *Cursors = ((clang_annotateTokens_Data*)UserData)->Cursors;
- CIndexer *CXXIdx = (CIndexer*)TU->CIdx;
+ CIndexer *CXXIdx = TU->CIdx;
if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForEditing))
setThreadBackgroundPriority();
@@ -5408,14 +5519,20 @@ static void clang_annotateTokensImpl(void *UserData) {
cxloc::translateSourceLocation(clang_getTokenLocation(TU,
Tokens[NumTokens-1])));
- // A mapping from the source locations found when re-lexing or traversing the
- // region of interest to the corresponding cursors.
- AnnotateTokensData Annotated;
-
// Relex the tokens within the source range to look for preprocessing
// directives.
- annotatePreprocessorTokens(TU, RegionOfInterest, Annotated);
-
+ annotatePreprocessorTokens(TU, RegionOfInterest, Cursors, Tokens, NumTokens);
+
+ // If begin location points inside a macro argument, set it to the expansion
+ // location so we can have the full context when annotating semantically.
+ {
+ SourceManager &SM = CXXUnit->getSourceManager();
+ SourceLocation Loc =
+ SM.getMacroArgExpandedLocation(RegionOfInterest.getBegin());
+ if (Loc.isMacroID())
+ RegionOfInterest.setBegin(SM.getExpansionLoc(Loc));
+ }
+
if (CXXUnit->getPreprocessor().getPreprocessingRecord()) {
// Search and mark tokens that are macro argument expansions.
MarkMacroArgTokensVisitor Visitor(CXXUnit->getSourceManager(),
@@ -5430,8 +5547,7 @@ static void clang_annotateTokensImpl(void *UserData) {
// Annotate all of the source locations in the region of interest that map to
// a specific cursor.
- AnnotateTokensWorker W(Annotated, Tokens, Cursors, NumTokens,
- TU, RegionOfInterest);
+ AnnotateTokensWorker W(Tokens, Cursors, NumTokens, TU, RegionOfInterest);
// FIXME: We use a ridiculous stack size here because the data-recursion
// algorithm uses a large stack frame than the non-data recursive version,
@@ -5449,7 +5565,7 @@ static void clang_annotateTokensImpl(void *UserData) {
if (Cursors[I].kind == CXCursor_ObjCPropertyDecl) {
IdentifierInfo *II = static_cast<IdentifierInfo *>(Tokens[I].ptr_data);
- if (ObjCPropertyDecl *Property
+ if (const ObjCPropertyDecl *Property
= dyn_cast_or_null<ObjCPropertyDecl>(getCursorDecl(Cursors[I]))) {
if (Property->getPropertyAttributesAsWritten() != 0 &&
llvm::StringSwitch<bool>(II->getName())
@@ -5500,16 +5616,24 @@ extern "C" {
void clang_annotateTokens(CXTranslationUnit TU,
CXToken *Tokens, unsigned NumTokens,
CXCursor *Cursors) {
-
- if (NumTokens == 0 || !Tokens || !Cursors)
+ if (!TU || NumTokens == 0 || !Tokens || !Cursors) {
+ LOG_FUNC_SECTION { *Log << "<null input>"; }
return;
+ }
+
+ LOG_FUNC_SECTION {
+ *Log << TU << ' ';
+ CXSourceLocation bloc = clang_getTokenLocation(TU, Tokens[0]);
+ CXSourceLocation eloc = clang_getTokenLocation(TU, Tokens[NumTokens-1]);
+ *Log << clang_getRange(bloc, eloc);
+ }
// Any token we don't specifically annotate will have a NULL cursor.
CXCursor C = clang_getNullCursor();
for (unsigned I = 0; I != NumTokens; ++I)
Cursors[I] = C;
- ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
+ ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
if (!CXXUnit)
return;
@@ -5534,8 +5658,8 @@ CXLinkageKind clang_getCursorLinkage(CXCursor cursor) {
if (!clang_isDeclaration(cursor.kind))
return CXLinkage_Invalid;
- Decl *D = cxcursor::getCursorDecl(cursor);
- if (NamedDecl *ND = dyn_cast_or_null<NamedDecl>(D))
+ const Decl *D = cxcursor::getCursorDecl(cursor);
+ if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(D))
switch (ND->getLinkage()) {
case NoLinkage: return CXLinkage_NoLinkage;
case InternalLinkage: return CXLinkage_Internal;
@@ -5604,7 +5728,7 @@ extern "C" {
enum CXAvailabilityKind clang_getCursorAvailability(CXCursor cursor) {
if (clang_isDeclaration(cursor.kind))
- if (Decl *D = cxcursor::getCursorDecl(cursor)) {
+ if (const Decl *D = cxcursor::getCursorDecl(cursor)) {
if (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->isDeleted())
return CXAvailability_Available;
@@ -5631,12 +5755,14 @@ static CXVersion convertVersion(VersionTuple In) {
Out.Major = In.getMajor();
- if (llvm::Optional<unsigned> Minor = In.getMinor())
+ Optional<unsigned> Minor = In.getMinor();
+ if (Minor.hasValue())
Out.Minor = *Minor;
else
return Out;
- if (llvm::Optional<unsigned> Subminor = In.getSubminor())
+ Optional<unsigned> Subminor = In.getSubminor();
+ if (Subminor.hasValue())
Out.Subminor = *Subminor;
return Out;
@@ -5652,16 +5778,16 @@ int clang_getCursorPlatformAvailability(CXCursor cursor,
if (always_deprecated)
*always_deprecated = 0;
if (deprecated_message)
- *deprecated_message = cxstring::createCXString("", /*DupString=*/false);
+ *deprecated_message = cxstring::createEmpty();
if (always_unavailable)
*always_unavailable = 0;
if (unavailable_message)
- *unavailable_message = cxstring::createCXString("", /*DupString=*/false);
+ *unavailable_message = cxstring::createEmpty();
if (!clang_isDeclaration(cursor.kind))
return 0;
- Decl *D = cxcursor::getCursorDecl(cursor);
+ const Decl *D = cxcursor::getCursorDecl(cursor);
if (!D)
return 0;
@@ -5672,7 +5798,7 @@ int clang_getCursorPlatformAvailability(CXCursor cursor,
if (always_deprecated)
*always_deprecated = 1;
if (deprecated_message)
- *deprecated_message = cxstring::createCXString(Deprecated->getMessage());
+ *deprecated_message = cxstring::createDup(Deprecated->getMessage());
continue;
}
@@ -5680,8 +5806,7 @@ int clang_getCursorPlatformAvailability(CXCursor cursor,
if (always_unavailable)
*always_unavailable = 1;
if (unavailable_message) {
- *unavailable_message
- = cxstring::createCXString(Unavailable->getMessage());
+ *unavailable_message = cxstring::createDup(Unavailable->getMessage());
}
continue;
}
@@ -5689,12 +5814,12 @@ int clang_getCursorPlatformAvailability(CXCursor cursor,
if (AvailabilityAttr *Avail = dyn_cast<AvailabilityAttr>(*A)) {
if (N < availability_size) {
availability[N].Platform
- = cxstring::createCXString(Avail->getPlatform()->getName());
+ = cxstring::createDup(Avail->getPlatform()->getName());
availability[N].Introduced = convertVersion(Avail->getIntroduced());
availability[N].Deprecated = convertVersion(Avail->getDeprecated());
availability[N].Obsoleted = convertVersion(Avail->getObsoleted());
availability[N].Unavailable = Avail->getUnavailable();
- availability[N].Message = cxstring::createCXString(Avail->getMessage());
+ availability[N].Message = cxstring::createDup(Avail->getMessage());
}
++N;
}
@@ -5718,15 +5843,15 @@ CXLanguageKind clang_getCursorLanguage(CXCursor cursor) {
/// \brief If the given cursor is the "templated" declaration
/// descibing a class or function template, return the class or
/// function template.
-static Decl *maybeGetTemplateCursor(Decl *D) {
+static const Decl *maybeGetTemplateCursor(const Decl *D) {
if (!D)
return 0;
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
if (FunctionTemplateDecl *FunTmpl = FD->getDescribedFunctionTemplate())
return FunTmpl;
- if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D))
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D))
if (ClassTemplateDecl *ClassTmpl = RD->getDescribedClassTemplate())
return ClassTmpl;
@@ -5735,8 +5860,8 @@ static Decl *maybeGetTemplateCursor(Decl *D) {
CXCursor clang_getCursorSemanticParent(CXCursor cursor) {
if (clang_isDeclaration(cursor.kind)) {
- if (Decl *D = getCursorDecl(cursor)) {
- DeclContext *DC = D->getDeclContext();
+ if (const Decl *D = getCursorDecl(cursor)) {
+ const DeclContext *DC = D->getDeclContext();
if (!DC)
return clang_getNullCursor();
@@ -5746,7 +5871,7 @@ CXCursor clang_getCursorSemanticParent(CXCursor cursor) {
}
if (clang_isStatement(cursor.kind) || clang_isExpression(cursor.kind)) {
- if (Decl *D = getCursorDecl(cursor))
+ if (const Decl *D = getCursorDecl(cursor))
return MakeCXCursor(D, getCursorTU(cursor));
}
@@ -5755,8 +5880,8 @@ CXCursor clang_getCursorSemanticParent(CXCursor cursor) {
CXCursor clang_getCursorLexicalParent(CXCursor cursor) {
if (clang_isDeclaration(cursor.kind)) {
- if (Decl *D = getCursorDecl(cursor)) {
- DeclContext *DC = D->getLexicalDeclContext();
+ if (const Decl *D = getCursorDecl(cursor)) {
+ const DeclContext *DC = D->getLexicalDeclContext();
if (!DC)
return clang_getNullCursor();
@@ -5774,8 +5899,8 @@ CXFile clang_getIncludedFile(CXCursor cursor) {
if (cursor.kind != CXCursor_InclusionDirective)
return 0;
- InclusionDirective *ID = getCursorInclusionDirective(cursor);
- return (void *)ID->getFile();
+ const InclusionDirective *ID = getCursorInclusionDirective(cursor);
+ return const_cast<FileEntry *>(ID->getFile());
}
CXSourceRange clang_Cursor_getCommentRange(CXCursor C) {
@@ -5793,7 +5918,7 @@ CXSourceRange clang_Cursor_getCommentRange(CXCursor C) {
CXString clang_Cursor_getRawCommentText(CXCursor C) {
if (!clang_isDeclaration(C.kind))
- return createCXString((const char *) NULL);
+ return cxstring::createNull();
const Decl *D = getCursorDecl(C);
ASTContext &Context = getCursorContext(C);
@@ -5803,12 +5928,12 @@ CXString clang_Cursor_getRawCommentText(CXCursor C) {
// Don't duplicate the string because RawText points directly into source
// code.
- return createCXString(RawText, false);
+ return cxstring::createRef(RawText);
}
CXString clang_Cursor_getBriefCommentText(CXCursor C) {
if (!clang_isDeclaration(C.kind))
- return createCXString((const char *) NULL);
+ return cxstring::createNull();
const Decl *D = getCursorDecl(C);
const ASTContext &Context = getCursorContext(C);
@@ -5819,10 +5944,10 @@ CXString clang_Cursor_getBriefCommentText(CXCursor C) {
// Don't duplicate the string because RawComment ensures that this memory
// will not go away.
- return createCXString(BriefText, false);
+ return cxstring::createRef(BriefText);
}
- return createCXString((const char *) NULL);
+ return cxstring::createNull();
}
CXComment clang_Cursor_getParsedComment(CXCursor C) {
@@ -5838,7 +5963,8 @@ CXComment clang_Cursor_getParsedComment(CXCursor C) {
CXModule clang_Cursor_getModule(CXCursor C) {
if (C.kind == CXCursor_ModuleImportDecl) {
- if (ImportDecl *ImportD = dyn_cast_or_null<ImportDecl>(getCursorDecl(C)))
+ if (const ImportDecl *ImportD =
+ dyn_cast_or_null<ImportDecl>(getCursorDecl(C)))
return ImportD->getImportedModule();
}
@@ -5854,32 +5980,38 @@ CXModule clang_Module_getParent(CXModule CXMod) {
CXString clang_Module_getName(CXModule CXMod) {
if (!CXMod)
- return createCXString("");
+ return cxstring::createEmpty();
Module *Mod = static_cast<Module*>(CXMod);
- return createCXString(Mod->Name);
+ return cxstring::createDup(Mod->Name);
}
CXString clang_Module_getFullName(CXModule CXMod) {
if (!CXMod)
- return createCXString("");
+ return cxstring::createEmpty();
Module *Mod = static_cast<Module*>(CXMod);
- return createCXString(Mod->getFullModuleName());
+ return cxstring::createDup(Mod->getFullModuleName());
}
-unsigned clang_Module_getNumTopLevelHeaders(CXModule CXMod) {
- if (!CXMod)
+unsigned clang_Module_getNumTopLevelHeaders(CXTranslationUnit TU,
+ CXModule CXMod) {
+ if (!TU || !CXMod)
return 0;
Module *Mod = static_cast<Module*>(CXMod);
- return Mod->TopHeaders.size();
+ FileManager &FileMgr = cxtu::getASTUnit(TU)->getFileManager();
+ ArrayRef<const FileEntry *> TopHeaders = Mod->getTopHeaders(FileMgr);
+ return TopHeaders.size();
}
-CXFile clang_Module_getTopLevelHeader(CXModule CXMod, unsigned Index) {
- if (!CXMod)
+CXFile clang_Module_getTopLevelHeader(CXTranslationUnit TU,
+ CXModule CXMod, unsigned Index) {
+ if (!TU || !CXMod)
return 0;
Module *Mod = static_cast<Module*>(CXMod);
+ FileManager &FileMgr = cxtu::getASTUnit(TU)->getFileManager();
- if (Index < Mod->TopHeaders.size())
- return const_cast<FileEntry *>(Mod->TopHeaders[Index]);
+ ArrayRef<const FileEntry *> TopHeaders = Mod->getTopHeaders(FileMgr);
+ if (Index < TopHeaders.size())
+ return const_cast<FileEntry *>(TopHeaders[Index]);
return 0;
}
@@ -5895,9 +6027,10 @@ unsigned clang_CXXMethod_isStatic(CXCursor C) {
if (!clang_isDeclaration(C.kind))
return 0;
- CXXMethodDecl *Method = 0;
- Decl *D = cxcursor::getCursorDecl(C);
- if (FunctionTemplateDecl *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(D))
+ const CXXMethodDecl *Method = 0;
+ const Decl *D = cxcursor::getCursorDecl(C);
+ if (const FunctionTemplateDecl *FunTmpl =
+ dyn_cast_or_null<FunctionTemplateDecl>(D))
Method = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());
else
Method = dyn_cast_or_null<CXXMethodDecl>(D);
@@ -5908,9 +6041,10 @@ unsigned clang_CXXMethod_isVirtual(CXCursor C) {
if (!clang_isDeclaration(C.kind))
return 0;
- CXXMethodDecl *Method = 0;
- Decl *D = cxcursor::getCursorDecl(C);
- if (FunctionTemplateDecl *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(D))
+ const CXXMethodDecl *Method = 0;
+ const Decl *D = cxcursor::getCursorDecl(C);
+ if (const FunctionTemplateDecl *FunTmpl =
+ dyn_cast_or_null<FunctionTemplateDecl>(D))
Method = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());
else
Method = dyn_cast_or_null<CXXMethodDecl>(D);
@@ -5927,7 +6061,7 @@ CXType clang_getIBOutletCollectionType(CXCursor C) {
if (C.kind != CXCursor_IBOutletCollectionAttr)
return cxtype::MakeCXType(QualType(), cxcursor::getCursorTU(C));
- IBOutletCollectionAttr *A =
+ const IBOutletCollectionAttr *A =
cast<IBOutletCollectionAttr>(cxcursor::getCursorAttr(C));
return cxtype::MakeCXType(A->getInterface(), cxcursor::getCursorTU(C));
@@ -6004,7 +6138,7 @@ CXTUResourceUsage clang_getCXTUResourceUsage(CXTranslationUnit TU) {
return usage;
}
- ASTUnit *astUnit = static_cast<ASTUnit*>(TU->TUData);
+ ASTUnit *astUnit = cxtu::getASTUnit(TU);
OwningPtr<MemUsageEntries> entries(new MemUsageEntries());
ASTContext &astContext = astUnit->getASTContext();
@@ -6167,11 +6301,205 @@ void cxindex::printDiagsToStderr(ASTUnit *Unit) {
#endif
}
+MacroInfo *cxindex::getMacroInfo(const IdentifierInfo &II,
+ SourceLocation MacroDefLoc,
+ CXTranslationUnit TU){
+ if (MacroDefLoc.isInvalid() || !TU)
+ return 0;
+ if (!II.hadMacroDefinition())
+ return 0;
+
+ ASTUnit *Unit = cxtu::getASTUnit(TU);
+ Preprocessor &PP = Unit->getPreprocessor();
+ MacroDirective *MD = PP.getMacroDirectiveHistory(&II);
+ if (MD) {
+ for (MacroDirective::DefInfo
+ Def = MD->getDefinition(); Def; Def = Def.getPreviousDefinition()) {
+ if (MacroDefLoc == Def.getMacroInfo()->getDefinitionLoc())
+ return Def.getMacroInfo();
+ }
+ }
+
+ return 0;
+}
+
+const MacroInfo *cxindex::getMacroInfo(const MacroDefinition *MacroDef,
+ CXTranslationUnit TU) {
+ if (!MacroDef || !TU)
+ return 0;
+ const IdentifierInfo *II = MacroDef->getName();
+ if (!II)
+ return 0;
+
+ return getMacroInfo(*II, MacroDef->getLocation(), TU);
+}
+
+MacroDefinition *cxindex::checkForMacroInMacroDefinition(const MacroInfo *MI,
+ const Token &Tok,
+ CXTranslationUnit TU) {
+ if (!MI || !TU)
+ return 0;
+ if (Tok.isNot(tok::raw_identifier))
+ return 0;
+
+ if (MI->getNumTokens() == 0)
+ return 0;
+ SourceRange DefRange(MI->getReplacementToken(0).getLocation(),
+ MI->getDefinitionEndLoc());
+ ASTUnit *Unit = cxtu::getASTUnit(TU);
+
+ // Check that the token is inside the definition and not its argument list.
+ SourceManager &SM = Unit->getSourceManager();
+ if (SM.isBeforeInTranslationUnit(Tok.getLocation(), DefRange.getBegin()))
+ return 0;
+ if (SM.isBeforeInTranslationUnit(DefRange.getEnd(), Tok.getLocation()))
+ return 0;
+
+ Preprocessor &PP = Unit->getPreprocessor();
+ PreprocessingRecord *PPRec = PP.getPreprocessingRecord();
+ if (!PPRec)
+ return 0;
+
+ StringRef Name(Tok.getRawIdentifierData(), Tok.getLength());
+ IdentifierInfo &II = PP.getIdentifierTable().get(Name);
+ if (!II.hadMacroDefinition())
+ return 0;
+
+ // Check that the identifier is not one of the macro arguments.
+ if (std::find(MI->arg_begin(), MI->arg_end(), &II) != MI->arg_end())
+ return 0;
+
+ MacroDirective *InnerMD = PP.getMacroDirectiveHistory(&II);
+ if (!InnerMD)
+ return 0;
+
+ return PPRec->findMacroDefinition(InnerMD->getMacroInfo());
+}
+
+MacroDefinition *cxindex::checkForMacroInMacroDefinition(const MacroInfo *MI,
+ SourceLocation Loc,
+ CXTranslationUnit TU) {
+ if (Loc.isInvalid() || !MI || !TU)
+ return 0;
+
+ if (MI->getNumTokens() == 0)
+ return 0;
+ ASTUnit *Unit = cxtu::getASTUnit(TU);
+ Preprocessor &PP = Unit->getPreprocessor();
+ if (!PP.getPreprocessingRecord())
+ return 0;
+ Loc = Unit->getSourceManager().getSpellingLoc(Loc);
+ Token Tok;
+ if (PP.getRawToken(Loc, Tok))
+ return 0;
+
+ return checkForMacroInMacroDefinition(MI, Tok, TU);
+}
+
extern "C" {
CXString clang_getClangVersion() {
- return createCXString(getClangFullVersion());
+ return cxstring::createDup(getClangFullVersion());
}
} // end: extern "C"
+Logger &cxindex::Logger::operator<<(CXTranslationUnit TU) {
+ if (TU) {
+ if (ASTUnit *Unit = cxtu::getASTUnit(TU)) {
+ LogOS << '<' << Unit->getMainFileName() << '>';
+ if (Unit->isMainFileAST())
+ LogOS << " (" << Unit->getASTFileName() << ')';
+ return *this;
+ }
+ }
+
+ LogOS << "<NULL TU>";
+ return *this;
+}
+
+Logger &cxindex::Logger::operator<<(const FileEntry *FE) {
+ *this << FE->getName();
+ return *this;
+}
+
+Logger &cxindex::Logger::operator<<(CXCursor cursor) {
+ CXString cursorName = clang_getCursorDisplayName(cursor);
+ *this << cursorName << "@" << clang_getCursorLocation(cursor);
+ clang_disposeString(cursorName);
+ return *this;
+}
+
+Logger &cxindex::Logger::operator<<(CXSourceLocation Loc) {
+ CXFile File;
+ unsigned Line, Column;
+ clang_getFileLocation(Loc, &File, &Line, &Column, 0);
+ CXString FileName = clang_getFileName(File);
+ *this << llvm::format("(%s:%d:%d)", clang_getCString(FileName), Line, Column);
+ clang_disposeString(FileName);
+ return *this;
+}
+
+Logger &cxindex::Logger::operator<<(CXSourceRange range) {
+ CXSourceLocation BLoc = clang_getRangeStart(range);
+ CXSourceLocation ELoc = clang_getRangeEnd(range);
+
+ CXFile BFile;
+ unsigned BLine, BColumn;
+ clang_getFileLocation(BLoc, &BFile, &BLine, &BColumn, 0);
+
+ CXFile EFile;
+ unsigned ELine, EColumn;
+ clang_getFileLocation(ELoc, &EFile, &ELine, &EColumn, 0);
+
+ CXString BFileName = clang_getFileName(BFile);
+ if (BFile == EFile) {
+ *this << llvm::format("[%s %d:%d-%d:%d]", clang_getCString(BFileName),
+ BLine, BColumn, ELine, EColumn);
+ } else {
+ CXString EFileName = clang_getFileName(EFile);
+ *this << llvm::format("[%s:%d:%d - ", clang_getCString(BFileName),
+ BLine, BColumn)
+ << llvm::format("%s:%d:%d]", clang_getCString(EFileName),
+ ELine, EColumn);
+ clang_disposeString(EFileName);
+ }
+ clang_disposeString(BFileName);
+ return *this;
+}
+
+Logger &cxindex::Logger::operator<<(CXString Str) {
+ *this << clang_getCString(Str);
+ return *this;
+}
+
+Logger &cxindex::Logger::operator<<(const llvm::format_object_base &Fmt) {
+ LogOS << Fmt;
+ return *this;
+}
+
+cxindex::Logger::~Logger() {
+ LogOS.flush();
+
+ llvm::sys::ScopedLock L(EnableMultithreadingMutex);
+
+ static llvm::TimeRecord sBeginTR = llvm::TimeRecord::getCurrentTime();
+
+ raw_ostream &OS = llvm::errs();
+ OS << "[libclang:" << Name << ':';
+
+ // FIXME: Portability.
+#if HAVE_PTHREAD_H && __APPLE__
+ mach_port_t tid = pthread_mach_thread_np(pthread_self());
+ OS << tid << ':';
+#endif
+
+ llvm::TimeRecord TR = llvm::TimeRecord::getCurrentTime();
+ OS << llvm::format("%7.4f] ", TR.getWallTime() - sBeginTR.getWallTime());
+ OS << Msg.str() << '\n';
+
+ if (Trace) {
+ llvm::sys::PrintStackTrace(stderr);
+ OS << "--------------------------------------------------\n";
+ }
+}
diff --git a/tools/libclang/CIndexCXX.cpp b/tools/libclang/CIndexCXX.cpp
index 9bc3efa..c68dde7 100644
--- a/tools/libclang/CIndexCXX.cpp
+++ b/tools/libclang/CIndexCXX.cpp
@@ -26,7 +26,7 @@ unsigned clang_isVirtualBase(CXCursor C) {
if (C.kind != CXCursor_CXXBaseSpecifier)
return 0;
- CXXBaseSpecifier *B = getCursorCXXBaseSpecifier(C);
+ const CXXBaseSpecifier *B = getCursorCXXBaseSpecifier(C);
return B->isVirtual();
}
@@ -56,14 +56,13 @@ enum CXCursorKind clang_getTemplateCursorKind(CXCursor C) {
switch (C.kind) {
case CXCursor_ClassTemplate:
case CXCursor_FunctionTemplate:
- if (TemplateDecl *Template
+ if (const TemplateDecl *Template
= dyn_cast_or_null<TemplateDecl>(getCursorDecl(C)))
- return MakeCXCursor(Template->getTemplatedDecl(),
- static_cast<CXTranslationUnit>(C.data[2])).kind;
+ return MakeCXCursor(Template->getTemplatedDecl(), getCursorTU(C)).kind;
break;
case CXCursor_ClassTemplatePartialSpecialization:
- if (ClassTemplateSpecializationDecl *PartialSpec
+ if (const ClassTemplateSpecializationDecl *PartialSpec
= dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>(
getCursorDecl(C))) {
switch (PartialSpec->getTagKind()) {
@@ -87,16 +86,16 @@ CXCursor clang_getSpecializedCursorTemplate(CXCursor C) {
if (!clang_isDeclaration(C.kind))
return clang_getNullCursor();
- Decl *D = getCursorDecl(C);
+ const Decl *D = getCursorDecl(C);
if (!D)
return clang_getNullCursor();
Decl *Template = 0;
- if (CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(D)) {
- if (ClassTemplatePartialSpecializationDecl *PartialSpec
+ if (const CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(D)) {
+ if (const ClassTemplatePartialSpecializationDecl *PartialSpec
= dyn_cast<ClassTemplatePartialSpecializationDecl>(CXXRecord))
Template = PartialSpec->getSpecializedTemplate();
- else if (ClassTemplateSpecializationDecl *ClassSpec
+ else if (const ClassTemplateSpecializationDecl *ClassSpec
= dyn_cast<ClassTemplateSpecializationDecl>(CXXRecord)) {
llvm::PointerUnion<ClassTemplateDecl *,
ClassTemplatePartialSpecializationDecl *> Result
@@ -108,21 +107,21 @@ CXCursor clang_getSpecializedCursorTemplate(CXCursor C) {
} else
Template = CXXRecord->getInstantiatedFromMemberClass();
- } else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
+ } else if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
Template = Function->getPrimaryTemplate();
if (!Template)
Template = Function->getInstantiatedFromMemberFunction();
- } else if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
+ } else if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
if (Var->isStaticDataMember())
Template = Var->getInstantiatedFromStaticDataMember();
- } else if (RedeclarableTemplateDecl *Tmpl
+ } else if (const RedeclarableTemplateDecl *Tmpl
= dyn_cast<RedeclarableTemplateDecl>(D))
Template = Tmpl->getInstantiatedFromMemberTemplate();
if (!Template)
return clang_getNullCursor();
- return MakeCXCursor(Template, static_cast<CXTranslationUnit>(C.data[2]));
+ return MakeCXCursor(Template, getCursorTU(C));
}
} // end extern "C"
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp
index 46af661..f79de29 100644
--- a/tools/libclang/CIndexCodeCompletion.cpp
+++ b/tools/libclang/CIndexCodeCompletion.cpp
@@ -13,16 +13,16 @@
//===----------------------------------------------------------------------===//
#include "CIndexer.h"
-#include "CXTranslationUnit.h"
-#include "CXString.h"
+#include "CIndexDiagnostic.h"
+#include "CLog.h"
#include "CXCursor.h"
#include "CXString.h"
-#include "CIndexDiagnostic.h"
-#include "clang/AST/Type.h"
+#include "CXTranslationUnit.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
-#include "clang/Basic/SourceManager.h"
+#include "clang/AST/Type.h"
#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
@@ -32,11 +32,12 @@
#include "llvm/Support/Atomic.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Program.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/Program.h"
-#include <cstdlib>
#include <cstdio>
+#include <cstdlib>
+#include <string>
#ifdef UDP_CODE_COMPLETION_LOGGER
@@ -48,7 +49,7 @@
#endif
using namespace clang;
-using namespace clang::cxstring;
+using namespace clang::cxindex;
extern "C" {
@@ -111,7 +112,7 @@ CXString clang_getCompletionChunkText(CXCompletionString completion_string,
unsigned chunk_number) {
CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
if (!CCStr || chunk_number >= CCStr->size())
- return createCXString((const char*)0);
+ return cxstring::createNull();
switch ((*CCStr)[chunk_number].Kind) {
case CodeCompletionString::CK_TypedText:
@@ -134,11 +135,11 @@ CXString clang_getCompletionChunkText(CXCompletionString completion_string,
case CodeCompletionString::CK_Equal:
case CodeCompletionString::CK_HorizontalSpace:
case CodeCompletionString::CK_VerticalSpace:
- return createCXString((*CCStr)[chunk_number].Text, false);
+ return cxstring::createRef((*CCStr)[chunk_number].Text);
case CodeCompletionString::CK_Optional:
// Note: treated as an empty text block.
- return createCXString("");
+ return cxstring::createEmpty();
}
llvm_unreachable("Invalid CodeCompletionString Kind!");
@@ -209,8 +210,8 @@ unsigned clang_getCompletionNumAnnotations(CXCompletionString completion_string)
CXString clang_getCompletionAnnotation(CXCompletionString completion_string,
unsigned annotation_number) {
CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
- return CCStr ? createCXString(CCStr->getAnnotation(annotation_number))
- : createCXString((const char *) 0);
+ return CCStr ? cxstring::createRef(CCStr->getAnnotation(annotation_number))
+ : cxstring::createNull();
}
CXString
@@ -221,9 +222,9 @@ clang_getCompletionParent(CXCompletionString completion_string,
CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
if (!CCStr)
- return createCXString((const char *)0);
+ return cxstring::createNull();
- return createCXString(CCStr->getParentContextName(), /*DupString=*/false);
+ return cxstring::createRef(CCStr->getParentContextName());
}
CXString
@@ -231,14 +232,20 @@ clang_getCompletionBriefComment(CXCompletionString completion_string) {
CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
if (!CCStr)
- return createCXString((const char *) NULL);
+ return cxstring::createNull();
- return createCXString(CCStr->getBriefComment(), /*DupString=*/false);
+ return cxstring::createRef(CCStr->getBriefComment());
}
-
+namespace {
+
/// \brief The CXCodeCompleteResults structure we allocate internally;
/// the client only sees the initial CXCodeCompleteResults structure.
+///
+/// Normally, clients of CXString shouldn't care whether or not a CXString is
+/// managed by a pool or by explicitly malloc'ed memory. But
+/// AllocatedCXCodeCompleteResults outlives the CXTranslationUnit, so we can
+/// not rely on the StringPool in the TU.
struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
AllocatedCXCodeCompleteResults(const FileSystemOptions& FileSystemOpts);
~AllocatedCXCodeCompleteResults();
@@ -287,8 +294,10 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
/// \brief The kind of the container for the current context for completions.
enum CXCursorKind ContainerKind;
+
/// \brief The USR of the container for the current context for completions.
- CXString ContainerUSR;
+ std::string ContainerUSR;
+
/// \brief a boolean value indicating whether there is complete information
/// about the container
unsigned ContainerIsIncomplete;
@@ -298,6 +307,8 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
std::string Selector;
};
+} // end anonymous namespace
+
/// \brief Tracks the number of code-completion result objects that are
/// currently active.
///
@@ -317,7 +328,6 @@ AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults(
CodeCompletionAllocator(new clang::GlobalCodeCompletionAllocator),
Contexts(CXCompletionContext_Unknown),
ContainerKind(CXCursor_InvalidCode),
- ContainerUSR(createCXString("")),
ContainerIsIncomplete(1)
{
if (getenv("LIBCLANG_OBJTRACKING")) {
@@ -328,9 +338,7 @@ AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults(
AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() {
delete [] Results;
-
- clang_disposeString(ContainerUSR);
-
+
for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I)
TemporaryFiles[I].eraseFromDisk();
for (unsigned I = 0, N = TemporaryBuffers.size(); I != N; ++I)
@@ -587,24 +595,13 @@ namespace {
if (D != NULL) {
CXCursor cursor = cxcursor::MakeCXCursor(D, *TU);
-
- CXCursorKind cursorKind = clang_getCursorKind(cursor);
- CXString cursorUSR = clang_getCursorUSR(cursor);
-
- // Normally, clients of CXString shouldn't care whether or not
- // a CXString is managed by a pool or by explicitly malloc'ed memory.
- // However, there are cases when AllocatedResults outlives the
- // CXTranslationUnit. This is a workaround that failure mode.
- if (cxstring::isManagedByPool(cursorUSR)) {
- CXString heapStr =
- cxstring::createCXString(clang_getCString(cursorUSR), true);
- clang_disposeString(cursorUSR);
- cursorUSR = heapStr;
- }
-
- AllocatedResults.ContainerKind = cursorKind;
- AllocatedResults.ContainerUSR = cursorUSR;
-
+
+ AllocatedResults.ContainerKind = clang_getCursorKind(cursor);
+
+ CXString CursorUSR = clang_getCursorUSR(cursor);
+ AllocatedResults.ContainerUSR = clang_getCString(CursorUSR);
+ clang_disposeString(CursorUSR);
+
const Type *type = baseType.getTypePtrOrNull();
if (type != NULL) {
AllocatedResults.ContainerIsIncomplete = type->isIncompleteType();
@@ -615,7 +612,7 @@ namespace {
}
else {
AllocatedResults.ContainerKind = CXCursor_InvalidCode;
- AllocatedResults.ContainerUSR = createCXString("");
+ AllocatedResults.ContainerUSR.clear();
AllocatedResults.ContainerIsIncomplete = 1;
}
}
@@ -684,11 +681,11 @@ void clang_codeCompleteAt_Impl(void *UserData) {
bool EnableLogging = getenv("LIBCLANG_CODE_COMPLETION_LOGGING") != 0;
- ASTUnit *AST = static_cast<ASTUnit *>(TU->TUData);
+ ASTUnit *AST = cxtu::getASTUnit(TU);
if (!AST)
return;
- CIndexer *CXXIdx = (CIndexer*)TU->CIdx;
+ CIndexer *CXXIdx = TU->CIdx;
if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForEditing))
setThreadBackgroundPriority();
@@ -819,14 +816,25 @@ CXCodeCompleteResults *clang_codeCompleteAt(CXTranslationUnit TU,
struct CXUnsavedFile *unsaved_files,
unsigned num_unsaved_files,
unsigned options) {
+ LOG_FUNC_SECTION {
+ *Log << TU << ' '
+ << complete_filename << ':' << complete_line << ':' << complete_column;
+ }
+
CodeCompleteAtInfo CCAI = { TU, complete_filename, complete_line,
complete_column, unsaved_files, num_unsaved_files,
options, 0 };
+
+ if (getenv("LIBCLANG_NOTHREADS")) {
+ clang_codeCompleteAt_Impl(&CCAI);
+ return CCAI.result;
+ }
+
llvm::CrashRecoveryContext CRC;
if (!RunSafely(CRC, clang_codeCompleteAt_Impl, &CCAI)) {
fprintf(stderr, "libclang: crash detected in code completion\n");
- static_cast<ASTUnit *>(TU->TUData)->setUnsafeToFree(true);
+ cxtu::getASTUnit(TU)->setUnsafeToFree(true);
return 0;
} else if (getenv("LIBCLANG_RESOURCE_USAGE"))
PrintLibclangResourceUsage(TU);
@@ -897,9 +905,9 @@ CXString clang_codeCompleteGetContainerUSR(CXCodeCompleteResults *ResultsIn) {
AllocatedCXCodeCompleteResults *Results =
static_cast<AllocatedCXCodeCompleteResults *>(ResultsIn);
if (!Results)
- return createCXString("");
-
- return createCXString(clang_getCString(Results->ContainerUSR));
+ return cxstring::createEmpty();
+
+ return cxstring::createRef(Results->ContainerUSR.c_str());
}
@@ -907,9 +915,9 @@ CXString clang_codeCompleteGetObjCSelector(CXCodeCompleteResults *ResultsIn) {
AllocatedCXCodeCompleteResults *Results =
static_cast<AllocatedCXCodeCompleteResults *>(ResultsIn);
if (!Results)
- return createCXString("");
+ return cxstring::createEmpty();
- return createCXString(Results->Selector);
+ return cxstring::createDup(Results->Selector);
}
} // end extern "C"
diff --git a/tools/libclang/CIndexDiagnostic.cpp b/tools/libclang/CIndexDiagnostic.cpp
index 3154480..0e9dde8 100644
--- a/tools/libclang/CIndexDiagnostic.cpp
+++ b/tools/libclang/CIndexDiagnostic.cpp
@@ -27,7 +27,6 @@
using namespace clang;
using namespace clang::cxloc;
-using namespace clang::cxstring;
using namespace clang::cxdiag;
using namespace llvm;
@@ -62,17 +61,17 @@ public:
}
CXString getSpelling() const {
- return createCXString(StringRef(Message), false);
+ return cxstring::createRef(Message.c_str());
}
CXString getDiagnosticOption(CXString *Disable) const {
if (Disable)
- *Disable = createCXString("", false);
- return createCXString("", false);
+ *Disable = cxstring::createEmpty();
+ return cxstring::createEmpty();
}
unsigned getCategory() const { return 0; }
- CXString getCategoryText() const { return createCXString(""); }
+ CXString getCategoryText() const { return cxstring::createEmpty(); }
unsigned getNumRanges() const { return 0; }
CXSourceRange getRange(unsigned Range) const { return clang_getNullRange(); }
@@ -80,7 +79,7 @@ public:
CXString getFixIt(unsigned FixIt, CXSourceRange *ReplacementRange) const {
if (ReplacementRange)
*ReplacementRange = clang_getNullRange();
- return createCXString("", false);
+ return cxstring::createEmpty();
}
};
@@ -158,7 +157,7 @@ public:
CXDiagnosticSetImpl *cxdiag::lazyCreateDiags(CXTranslationUnit TU,
bool checkIfChanged) {
- ASTUnit *AU = static_cast<ASTUnit *>(TU->TUData);
+ ASTUnit *AU = cxtu::getASTUnit(TU);
if (TU->Diagnostics && checkIfChanged) {
// In normal use, ASTUnit's diagnostics should not change unless we reparse.
@@ -191,7 +190,7 @@ CXDiagnosticSetImpl *cxdiag::lazyCreateDiags(CXTranslationUnit TU,
if (!TU->Diagnostics) {
CXDiagnosticSetImpl *Set = new CXDiagnosticSetImpl();
TU->Diagnostics = Set;
- llvm::IntrusiveRefCntPtr<DiagnosticOptions> DOpts = new DiagnosticOptions;
+ IntrusiveRefCntPtr<DiagnosticOptions> DOpts = new DiagnosticOptions;
CXDiagnosticRenderer Renderer(AU->getASTContext().getLangOpts(),
&*DOpts, Set);
@@ -209,7 +208,7 @@ CXDiagnosticSetImpl *cxdiag::lazyCreateDiags(CXTranslationUnit TU,
extern "C" {
unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) {
- if (!Unit->TUData)
+ if (!cxtu::getASTUnit(Unit))
return 0;
return lazyCreateDiags(Unit, /*checkIfChanged=*/true)->getNumDiagnostics();
}
@@ -227,7 +226,7 @@ CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, unsigned Index) {
}
CXDiagnosticSet clang_getDiagnosticSetFromTU(CXTranslationUnit Unit) {
- if (!Unit->TUData)
+ if (!cxtu::getASTUnit(Unit))
return 0;
return static_cast<CXDiagnostic>(lazyCreateDiags(Unit));
}
@@ -239,7 +238,7 @@ void clang_disposeDiagnostic(CXDiagnostic Diagnostic) {
CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) {
if (!Diagnostic)
- return createCXString("");
+ return cxstring::createEmpty();
CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic);
@@ -354,7 +353,7 @@ CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) {
Out << "]";
}
- return createCXString(Out.str(), true);
+ return cxstring::createDup(Out.str());
}
unsigned clang_defaultDiagnosticDisplayOptions() {
@@ -377,17 +376,17 @@ CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) {
CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) {
if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
return D->getSpelling();
- return createCXString("");
+ return cxstring::createEmpty();
}
CXString clang_getDiagnosticOption(CXDiagnostic Diag, CXString *Disable) {
if (Disable)
- *Disable = createCXString("");
+ *Disable = cxstring::createEmpty();
if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
return D->getDiagnosticOption(Disable);
- return createCXString("");
+ return cxstring::createEmpty();
}
unsigned clang_getDiagnosticCategory(CXDiagnostic Diag) {
@@ -398,13 +397,13 @@ unsigned clang_getDiagnosticCategory(CXDiagnostic Diag) {
CXString clang_getDiagnosticCategoryName(unsigned Category) {
// Kept for backwards compatibility.
- return createCXString(DiagnosticIDs::getCategoryNameFromID(Category));
+ return cxstring::createRef(DiagnosticIDs::getCategoryNameFromID(Category));
}
CXString clang_getDiagnosticCategoryText(CXDiagnostic Diag) {
if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
return D->getCategoryText();
- return createCXString("");
+ return cxstring::createEmpty();
}
unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) {
@@ -432,7 +431,7 @@ CXString clang_getDiagnosticFixIt(CXDiagnostic Diag, unsigned FixIt,
if (!D || FixIt >= D->getNumFixIts()) {
if (ReplacementRange)
*ReplacementRange = clang_getNullRange();
- return createCXString("");
+ return cxstring::createEmpty();
}
return D->getFixIt(FixIt, ReplacementRange);
}
diff --git a/tools/libclang/CIndexHigh.cpp b/tools/libclang/CIndexHigh.cpp
index ec76898..2a55af5 100644
--- a/tools/libclang/CIndexHigh.cpp
+++ b/tools/libclang/CIndexHigh.cpp
@@ -8,19 +8,21 @@
//===----------------------------------------------------------------------===//
#include "CursorVisitor.h"
+#include "CLog.h"
#include "CXCursor.h"
#include "CXSourceLocation.h"
#include "CXTranslationUnit.h"
-
-#include "clang/Frontend/ASTUnit.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "llvm/Support/Compiler.h"
using namespace clang;
using namespace cxcursor;
+using namespace cxindex;
static void getTopOverriddenMethods(CXTranslationUnit TU,
- Decl *D,
- SmallVectorImpl<Decl *> &Methods) {
+ const Decl *D,
+ SmallVectorImpl<const Decl *> &Methods) {
if (!D)
return;
if (!isa<ObjCMethodDecl>(D) && !isa<CXXMethodDecl>(D))
@@ -44,15 +46,15 @@ namespace {
struct FindFileIdRefVisitData {
CXTranslationUnit TU;
FileID FID;
- Decl *Dcl;
+ const Decl *Dcl;
int SelectorIdIdx;
CXCursorAndRangeVisitor visitor;
- typedef SmallVector<Decl *, 8> TopMethodsTy;
+ typedef SmallVector<const Decl *, 8> TopMethodsTy;
TopMethodsTy TopMethods;
FindFileIdRefVisitData(CXTranslationUnit TU, FileID FID,
- Decl *D, int selectorIdIdx,
+ const Decl *D, int selectorIdIdx,
CXCursorAndRangeVisitor visitor)
: TU(TU), FID(FID), SelectorIdIdx(selectorIdIdx), visitor(visitor) {
Dcl = getCanonical(D);
@@ -60,7 +62,7 @@ struct FindFileIdRefVisitData {
}
ASTContext &getASTContext() const {
- return static_cast<ASTUnit *>(TU->TUData)->getASTContext();
+ return cxtu::getASTUnit(TU)->getASTContext();
}
/// \brief We are looking to find all semantically relevant identifiers,
@@ -74,24 +76,25 @@ struct FindFileIdRefVisitData {
///
/// we consider the canonical decl of the constructor decl to be the class
/// itself, so both 'C' can be highlighted.
- Decl *getCanonical(Decl *D) const {
+ const Decl *getCanonical(const Decl *D) const {
if (!D)
return 0;
D = D->getCanonicalDecl();
- if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D)) {
+ if (const ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D)) {
if (ImplD->getClassInterface())
return getCanonical(ImplD->getClassInterface());
- } else if (CXXConstructorDecl *CXXCtorD = dyn_cast<CXXConstructorDecl>(D)) {
+ } else if (const CXXConstructorDecl *CXXCtorD =
+ dyn_cast<CXXConstructorDecl>(D)) {
return getCanonical(CXXCtorD->getParent());
}
return D;
}
- bool isHit(Decl *D) const {
+ bool isHit(const Decl *D) const {
if (!D)
return false;
@@ -106,7 +109,7 @@ struct FindFileIdRefVisitData {
}
private:
- bool isOverriddingMethod(Decl *D) const {
+ bool isOverriddingMethod(const Decl *D) const {
if (std::find(TopMethods.begin(), TopMethods.end(), D) !=
TopMethods.end())
return true;
@@ -148,7 +151,7 @@ static enum CXChildVisitResult findFileIdRefVisit(CXCursor cursor,
if (!clang_isDeclaration(declCursor.kind))
return CXChildVisit_Recurse;
- Decl *D = cxcursor::getCursorDecl(declCursor);
+ const Decl *D = cxcursor::getCursorDecl(declCursor);
if (!D)
return CXChildVisit_Continue;
@@ -202,32 +205,31 @@ static enum CXChildVisitResult findFileIdRefVisit(CXCursor cursor,
return CXChildVisit_Recurse;
}
- data->visitor.visit(data->visitor.context, cursor,
- cxloc::translateSourceRange(Ctx, Loc));
+ if (data->visitor.visit(data->visitor.context, cursor,
+ cxloc::translateSourceRange(Ctx, Loc)) == CXVisit_Break)
+ return CXChildVisit_Break;
}
return CXChildVisit_Recurse;
}
-static void findIdRefsInFile(CXTranslationUnit TU, CXCursor declCursor,
- const FileEntry *File,
- CXCursorAndRangeVisitor Visitor) {
+static bool findIdRefsInFile(CXTranslationUnit TU, CXCursor declCursor,
+ const FileEntry *File,
+ CXCursorAndRangeVisitor Visitor) {
assert(clang_isDeclaration(declCursor.kind));
- ASTUnit *Unit = static_cast<ASTUnit*>(TU->TUData);
- SourceManager &SM = Unit->getSourceManager();
+ SourceManager &SM = cxtu::getASTUnit(TU)->getSourceManager();
FileID FID = SM.translateFile(File);
- Decl *Dcl = cxcursor::getCursorDecl(declCursor);
+ const Decl *Dcl = cxcursor::getCursorDecl(declCursor);
if (!Dcl)
- return;
+ return false;
FindFileIdRefVisitData data(TU, FID, Dcl,
cxcursor::getSelectorIdentifierIndex(declCursor),
Visitor);
- if (DeclContext *DC = Dcl->getParentFunctionOrMethod()) {
- clang_visitChildren(cxcursor::MakeCXCursor(cast<Decl>(DC), TU),
- findFileIdRefVisit, &data);
- return;
+ if (const DeclContext *DC = Dcl->getParentFunctionOrMethod()) {
+ return clang_visitChildren(cxcursor::MakeCXCursor(cast<Decl>(DC), TU),
+ findFileIdRefVisit, &data);
}
SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID));
@@ -237,7 +239,7 @@ static void findIdRefsInFile(CXTranslationUnit TU, CXCursor declCursor,
/*VisitIncludedEntities=*/false,
Range,
/*VisitDeclsOnly=*/true);
- FindIdRefsVisitor.visitFileRegion();
+ return FindIdRefsVisitor.visitFileRegion();
}
namespace {
@@ -267,7 +269,7 @@ static enum CXChildVisitResult findFileMacroRefVisit(CXCursor cursor,
if (cursor.kind == CXCursor_MacroDefinition)
Macro = getCursorMacroDefinition(cursor)->getName();
else if (cursor.kind == CXCursor_MacroExpansion)
- Macro = getCursorMacroExpansion(cursor)->getName();
+ Macro = getCursorMacroExpansion(cursor).getName();
if (!Macro)
return CXChildVisit_Continue;
@@ -298,19 +300,20 @@ static enum CXChildVisitResult findFileMacroRefVisit(CXCursor cursor,
return CXChildVisit_Continue;
}
- data->visitor.visit(data->visitor.context, cursor,
- cxloc::translateSourceRange(Ctx, Loc));
+ if (data->visitor.visit(data->visitor.context, cursor,
+ cxloc::translateSourceRange(Ctx, Loc)) == CXVisit_Break)
+ return CXChildVisit_Break;
return CXChildVisit_Continue;
}
-static void findMacroRefsInFile(CXTranslationUnit TU, CXCursor Cursor,
+static bool findMacroRefsInFile(CXTranslationUnit TU, CXCursor Cursor,
const FileEntry *File,
CXCursorAndRangeVisitor Visitor) {
if (Cursor.kind != CXCursor_MacroDefinition &&
Cursor.kind != CXCursor_MacroExpansion)
- return;
+ return false;
- ASTUnit *Unit = static_cast<ASTUnit*>(TU->TUData);
+ ASTUnit *Unit = cxtu::getASTUnit(TU);
SourceManager &SM = Unit->getSourceManager();
FileID FID = SM.translateFile(File);
@@ -318,9 +321,9 @@ static void findMacroRefsInFile(CXTranslationUnit TU, CXCursor Cursor,
if (Cursor.kind == CXCursor_MacroDefinition)
Macro = getCursorMacroDefinition(Cursor)->getName();
else
- Macro = getCursorMacroExpansion(Cursor)->getName();
+ Macro = getCursorMacroExpansion(Cursor).getName();
if (!Macro)
- return;
+ return false;
FindFileMacroRefVisitData data(*Unit, File, Macro, Visitor);
@@ -330,7 +333,73 @@ static void findMacroRefsInFile(CXTranslationUnit TU, CXCursor Cursor,
/*VisitPreprocessorLast=*/false,
/*VisitIncludedEntities=*/false,
Range);
- FindMacroRefsVisitor.visitPreprocessedEntitiesInRegion();
+ return FindMacroRefsVisitor.visitPreprocessedEntitiesInRegion();
+}
+
+namespace {
+
+struct FindFileIncludesVisitor {
+ ASTUnit &Unit;
+ const FileEntry *File;
+ CXCursorAndRangeVisitor visitor;
+
+ FindFileIncludesVisitor(ASTUnit &Unit, const FileEntry *File,
+ CXCursorAndRangeVisitor visitor)
+ : Unit(Unit), File(File), visitor(visitor) { }
+
+ ASTContext &getASTContext() const {
+ return Unit.getASTContext();
+ }
+
+ enum CXChildVisitResult visit(CXCursor cursor, CXCursor parent) {
+ if (cursor.kind != CXCursor_InclusionDirective)
+ return CXChildVisit_Continue;
+
+ SourceLocation
+ Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor));
+
+ ASTContext &Ctx = getASTContext();
+ SourceManager &SM = Ctx.getSourceManager();
+
+ // We are looking for includes in a specific file.
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
+ if (SM.getFileEntryForID(LocInfo.first) != File)
+ return CXChildVisit_Continue;
+
+ if (visitor.visit(visitor.context, cursor,
+ cxloc::translateSourceRange(Ctx, Loc)) == CXVisit_Break)
+ return CXChildVisit_Break;
+ return CXChildVisit_Continue;
+ }
+
+ static enum CXChildVisitResult visit(CXCursor cursor, CXCursor parent,
+ CXClientData client_data) {
+ return static_cast<FindFileIncludesVisitor*>(client_data)->
+ visit(cursor, parent);
+ }
+};
+
+} // anonymous namespace
+
+static bool findIncludesInFile(CXTranslationUnit TU, const FileEntry *File,
+ CXCursorAndRangeVisitor Visitor) {
+ assert(TU && File && Visitor.visit);
+
+ ASTUnit *Unit = cxtu::getASTUnit(TU);
+ SourceManager &SM = Unit->getSourceManager();
+
+ FileID FID = SM.translateFile(File);
+
+ FindFileIncludesVisitor IncludesVisitor(*Unit, File, Visitor);
+
+ SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID));
+ CursorVisitor InclusionCursorsVisitor(TU,
+ FindFileIncludesVisitor::visit,
+ &IncludesVisitor,
+ /*VisitPreprocessorLast=*/false,
+ /*VisitIncludedEntities=*/false,
+ Range);
+ return InclusionCursorsVisitor.visitPreprocessedEntitiesInRegion();
}
@@ -340,44 +409,48 @@ static void findMacroRefsInFile(CXTranslationUnit TU, CXCursor Cursor,
extern "C" {
-void clang_findReferencesInFile(CXCursor cursor, CXFile file,
- CXCursorAndRangeVisitor visitor) {
- bool Logging = ::getenv("LIBCLANG_LOGGING");
+CXResult clang_findReferencesInFile(CXCursor cursor, CXFile file,
+ CXCursorAndRangeVisitor visitor) {
+ LogRef Log = Logger::make(LLVM_FUNCTION_NAME);
if (clang_Cursor_isNull(cursor)) {
- if (Logging)
- llvm::errs() << "clang_findReferencesInFile: Null cursor\n";
- return;
+ if (Log)
+ *Log << "Null cursor";
+ return CXResult_Invalid;
}
if (cursor.kind == CXCursor_NoDeclFound) {
- if (Logging)
- llvm::errs() << "clang_findReferencesInFile: Got CXCursor_NoDeclFound\n";
- return;
+ if (Log)
+ *Log << "Got CXCursor_NoDeclFound";
+ return CXResult_Invalid;
}
if (!file) {
- if (Logging)
- llvm::errs() << "clang_findReferencesInFile: Null file\n";
- return;
+ if (Log)
+ *Log << "Null file";
+ return CXResult_Invalid;
}
if (!visitor.visit) {
- if (Logging)
- llvm::errs() << "clang_findReferencesInFile: Null visitor\n";
- return;
+ if (Log)
+ *Log << "Null visitor";
+ return CXResult_Invalid;
}
+ if (Log)
+ *Log << cursor << " @" << static_cast<const FileEntry *>(file);
+
ASTUnit *CXXUnit = cxcursor::getCursorASTUnit(cursor);
if (!CXXUnit)
- return;
+ return CXResult_Invalid;
ASTUnit::ConcurrencyCheck Check(*CXXUnit);
if (cursor.kind == CXCursor_MacroDefinition ||
cursor.kind == CXCursor_MacroExpansion) {
- findMacroRefsInFile(cxcursor::getCursorTU(cursor),
- cursor,
- static_cast<const FileEntry *>(file),
- visitor);
- return;
+ if (findMacroRefsInFile(cxcursor::getCursorTU(cursor),
+ cursor,
+ static_cast<const FileEntry *>(file),
+ visitor))
+ return CXResult_VisitBreak;
+ return CXResult_Success;
}
// We are interested in semantics of identifiers so for C++ constructor exprs
@@ -392,16 +465,51 @@ void clang_findReferencesInFile(CXCursor cursor, CXFile file,
CXCursor refCursor = clang_getCursorReferenced(cursor);
if (!clang_isDeclaration(refCursor.kind)) {
- if (Logging)
- llvm::errs() << "clang_findReferencesInFile: cursor is not referencing a "
- "declaration\n";
- return;
+ if (Log)
+ *Log << "cursor is not referencing a declaration";
+ return CXResult_Invalid;
}
- findIdRefsInFile(cxcursor::getCursorTU(cursor),
- refCursor,
- static_cast<const FileEntry *>(file),
- visitor);
+ if (findIdRefsInFile(cxcursor::getCursorTU(cursor),
+ refCursor,
+ static_cast<const FileEntry *>(file),
+ visitor))
+ return CXResult_VisitBreak;
+ return CXResult_Success;
+}
+
+CXResult clang_findIncludesInFile(CXTranslationUnit TU, CXFile file,
+ CXCursorAndRangeVisitor visitor) {
+ LogRef Log = Logger::make(LLVM_FUNCTION_NAME);
+
+ if (!TU) {
+ if (Log)
+ *Log << "Null CXTranslationUnit";
+ return CXResult_Invalid;
+ }
+ if (!file) {
+ if (Log)
+ *Log << "Null file";
+ return CXResult_Invalid;
+ }
+ if (!visitor.visit) {
+ if (Log)
+ *Log << "Null visitor";
+ return CXResult_Invalid;
+ }
+
+ if (Log)
+ *Log << TU << " @" << static_cast<const FileEntry *>(file);
+
+ ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
+ if (!CXXUnit)
+ return CXResult_Invalid;
+
+ ASTUnit::ConcurrencyCheck Check(*CXXUnit);
+
+ if (findIncludesInFile(TU, static_cast<const FileEntry *>(file), visitor))
+ return CXResult_VisitBreak;
+ return CXResult_Success;
}
static enum CXVisitorResult _visitCursorAndRange(void *context,
@@ -411,13 +519,21 @@ static enum CXVisitorResult _visitCursorAndRange(void *context,
return INVOKE_BLOCK2(block, cursor, range);
}
-void clang_findReferencesInFileWithBlock(CXCursor cursor,
- CXFile file,
- CXCursorAndRangeVisitorBlock block) {
+CXResult clang_findReferencesInFileWithBlock(CXCursor cursor,
+ CXFile file,
+ CXCursorAndRangeVisitorBlock block) {
CXCursorAndRangeVisitor visitor = { block,
block ? _visitCursorAndRange : 0 };
return clang_findReferencesInFile(cursor, file, visitor);
}
+CXResult clang_findIncludesInFileWithBlock(CXTranslationUnit TU,
+ CXFile file,
+ CXCursorAndRangeVisitorBlock block) {
+ CXCursorAndRangeVisitor visitor = { block,
+ block ? _visitCursorAndRange : 0 };
+ return clang_findIncludesInFile(TU, file, visitor);
+}
+
} // end: extern "C"
diff --git a/tools/libclang/CIndexInclusionStack.cpp b/tools/libclang/CIndexInclusionStack.cpp
index 848ca31..a6d3115 100644
--- a/tools/libclang/CIndexInclusionStack.cpp
+++ b/tools/libclang/CIndexInclusionStack.cpp
@@ -13,8 +13,8 @@
//===----------------------------------------------------------------------===//
#include "CIndexer.h"
-#include "CXTranslationUnit.h"
#include "CXSourceLocation.h"
+#include "CXTranslationUnit.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/Frontend/ASTUnit.h"
#include "llvm/ADT/SmallString.h"
@@ -25,7 +25,7 @@ extern "C" {
void clang_getInclusions(CXTranslationUnit TU, CXInclusionVisitor CB,
CXClientData clientData) {
- ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
+ ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
SourceManager &SM = CXXUnit->getSourceManager();
ASTContext &Ctx = CXXUnit->getASTContext();
@@ -64,7 +64,8 @@ void clang_getInclusions(CXTranslationUnit TU, CXInclusionVisitor CB,
// Callback to the client.
// FIXME: We should have a function to construct CXFiles.
- CB((CXFile) FI.getContentCache()->OrigEntry,
+ CB(static_cast<CXFile>(
+ const_cast<FileEntry *>(FI.getContentCache()->OrigEntry)),
InclusionStack.data(), InclusionStack.size(), clientData);
}
}
diff --git a/tools/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp
index 6140032..a911ce5 100644
--- a/tools/libclang/CIndexUSRs.cpp
+++ b/tools/libclang/CIndexUSRs.cpp
@@ -22,14 +22,13 @@
#include "llvm/Support/raw_ostream.h"
using namespace clang;
-using namespace clang::cxstring;
//===----------------------------------------------------------------------===//
// USR generation.
//===----------------------------------------------------------------------===//
namespace {
-class USRGenerator : public DeclVisitor<USRGenerator> {
+class USRGenerator : public ConstDeclVisitor<USRGenerator> {
OwningPtr<SmallString<128> > OwnedBuf;
SmallVectorImpl<char> &Buf;
llvm::raw_svector_ostream Out;
@@ -67,37 +66,37 @@ public:
bool ignoreResults() const { return IgnoreResults; }
// Visitation methods from generating USRs from AST elements.
- void VisitDeclContext(DeclContext *D);
- void VisitFieldDecl(FieldDecl *D);
- void VisitFunctionDecl(FunctionDecl *D);
- void VisitNamedDecl(NamedDecl *D);
- void VisitNamespaceDecl(NamespaceDecl *D);
- void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
- void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
- void VisitClassTemplateDecl(ClassTemplateDecl *D);
- void VisitObjCContainerDecl(ObjCContainerDecl *CD);
- void VisitObjCMethodDecl(ObjCMethodDecl *MD);
- void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
- void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
- void VisitTagDecl(TagDecl *D);
- void VisitTypedefDecl(TypedefDecl *D);
- void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
- void VisitVarDecl(VarDecl *D);
- void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
- void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
- void VisitLinkageSpecDecl(LinkageSpecDecl *D) {
+ void VisitDeclContext(const DeclContext *D);
+ void VisitFieldDecl(const FieldDecl *D);
+ void VisitFunctionDecl(const FunctionDecl *D);
+ void VisitNamedDecl(const NamedDecl *D);
+ void VisitNamespaceDecl(const NamespaceDecl *D);
+ void VisitNamespaceAliasDecl(const NamespaceAliasDecl *D);
+ void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D);
+ void VisitClassTemplateDecl(const ClassTemplateDecl *D);
+ void VisitObjCContainerDecl(const ObjCContainerDecl *CD);
+ void VisitObjCMethodDecl(const ObjCMethodDecl *MD);
+ void VisitObjCPropertyDecl(const ObjCPropertyDecl *D);
+ void VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D);
+ void VisitTagDecl(const TagDecl *D);
+ void VisitTypedefDecl(const TypedefDecl *D);
+ void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D);
+ void VisitVarDecl(const VarDecl *D);
+ void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D);
+ void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D);
+ void VisitLinkageSpecDecl(const LinkageSpecDecl *D) {
IgnoreResults = true;
}
- void VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
+ void VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) {
IgnoreResults = true;
}
- void VisitUsingDecl(UsingDecl *D) {
+ void VisitUsingDecl(const UsingDecl *D) {
IgnoreResults = true;
}
- void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
+ void VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) {
IgnoreResults = true;
}
- void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
+ void VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D) {
IgnoreResults = true;
}
@@ -151,25 +150,19 @@ bool USRGenerator::EmitDeclName(const NamedDecl *D) {
return startSize == endSize;
}
-static bool InAnonymousNamespace(const Decl *D) {
- if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D->getDeclContext()))
- return ND->isAnonymousNamespace();
- return false;
-}
-
static inline bool ShouldGenerateLocation(const NamedDecl *D) {
- return D->getLinkage() != ExternalLinkage && !InAnonymousNamespace(D);
+ return D->getLinkage() != ExternalLinkage;
}
-void USRGenerator::VisitDeclContext(DeclContext *DC) {
- if (NamedDecl *D = dyn_cast<NamedDecl>(DC))
+void USRGenerator::VisitDeclContext(const DeclContext *DC) {
+ if (const NamedDecl *D = dyn_cast<NamedDecl>(DC))
Visit(D);
}
-void USRGenerator::VisitFieldDecl(FieldDecl *D) {
+void USRGenerator::VisitFieldDecl(const FieldDecl *D) {
// The USR for an ivar declared in a class extension is based on the
// ObjCInterfaceDecl, not the ObjCCategoryDecl.
- if (ObjCInterfaceDecl *ID = Context->getObjContainingInterface(D))
+ if (const ObjCInterfaceDecl *ID = Context->getObjContainingInterface(D))
Visit(ID);
else
VisitDeclContext(D->getDeclContext());
@@ -181,7 +174,7 @@ void USRGenerator::VisitFieldDecl(FieldDecl *D) {
}
}
-void USRGenerator::VisitFunctionDecl(FunctionDecl *D) {
+void USRGenerator::VisitFunctionDecl(const FunctionDecl *D) {
if (ShouldGenerateLocation(D) && GenLoc(D))
return;
@@ -208,7 +201,8 @@ void USRGenerator::VisitFunctionDecl(FunctionDecl *D) {
}
// Mangle in type information for the arguments.
- for (FunctionDecl::param_iterator I = D->param_begin(), E = D->param_end();
+ for (FunctionDecl::param_const_iterator I = D->param_begin(),
+ E = D->param_end();
I != E; ++I) {
Out << '#';
if (ParmVarDecl *PD = *I)
@@ -217,7 +211,7 @@ void USRGenerator::VisitFunctionDecl(FunctionDecl *D) {
if (D->isVariadic())
Out << '.';
Out << '#';
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
if (MD->isStatic())
Out << 'S';
if (unsigned quals = MD->getTypeQualifiers())
@@ -225,7 +219,7 @@ void USRGenerator::VisitFunctionDecl(FunctionDecl *D) {
}
}
-void USRGenerator::VisitNamedDecl(NamedDecl *D) {
+void USRGenerator::VisitNamedDecl(const NamedDecl *D) {
VisitDeclContext(D->getDeclContext());
Out << "@";
@@ -238,7 +232,7 @@ void USRGenerator::VisitNamedDecl(NamedDecl *D) {
}
}
-void USRGenerator::VisitVarDecl(VarDecl *D) {
+void USRGenerator::VisitVarDecl(const VarDecl *D) {
// VarDecls can be declared 'extern' within a function or method body,
// but their enclosing DeclContext is the function, not the TU. We need
// to check the storage class to correctly generate the USR.
@@ -260,17 +254,19 @@ void USRGenerator::VisitVarDecl(VarDecl *D) {
Out << '@' << s;
}
-void USRGenerator::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
+void USRGenerator::VisitNonTypeTemplateParmDecl(
+ const NonTypeTemplateParmDecl *D) {
GenLoc(D);
return;
}
-void USRGenerator::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
+void USRGenerator::VisitTemplateTemplateParmDecl(
+ const TemplateTemplateParmDecl *D) {
GenLoc(D);
return;
}
-void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) {
+void USRGenerator::VisitNamespaceDecl(const NamespaceDecl *D) {
if (D->isAnonymousNamespace()) {
Out << "@aN";
return;
@@ -281,29 +277,29 @@ void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) {
Out << "@N@" << D->getName();
}
-void USRGenerator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
+void USRGenerator::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {
VisitFunctionDecl(D->getTemplatedDecl());
}
-void USRGenerator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
+void USRGenerator::VisitClassTemplateDecl(const ClassTemplateDecl *D) {
VisitTagDecl(D->getTemplatedDecl());
}
-void USRGenerator::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
+void USRGenerator::VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) {
VisitDeclContext(D->getDeclContext());
if (!IgnoreResults)
Out << "@NA@" << D->getName();
}
-void USRGenerator::VisitObjCMethodDecl(ObjCMethodDecl *D) {
- DeclContext *container = D->getDeclContext();
- if (ObjCProtocolDecl *pd = dyn_cast<ObjCProtocolDecl>(container)) {
+void USRGenerator::VisitObjCMethodDecl(const ObjCMethodDecl *D) {
+ const DeclContext *container = D->getDeclContext();
+ if (const ObjCProtocolDecl *pd = dyn_cast<ObjCProtocolDecl>(container)) {
Visit(pd);
}
else {
// The USR for a method declared in a class extension or category is based on
// the ObjCInterfaceDecl, not the ObjCCategoryDecl.
- ObjCInterfaceDecl *ID = D->getClassInterface();
+ const ObjCInterfaceDecl *ID = D->getClassInterface();
if (!ID) {
IgnoreResults = true;
return;
@@ -318,7 +314,7 @@ void USRGenerator::VisitObjCMethodDecl(ObjCMethodDecl *D) {
N.printName(Out);
}
-void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) {
+void USRGenerator::VisitObjCContainerDecl(const ObjCContainerDecl *D) {
switch (D->getKind()) {
default:
llvm_unreachable("Invalid ObjC container.");
@@ -327,8 +323,8 @@ void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) {
GenObjCClass(D->getName());
break;
case Decl::ObjCCategory: {
- ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(D);
- ObjCInterfaceDecl *ID = CD->getClassInterface();
+ const ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(D);
+ const ObjCInterfaceDecl *ID = CD->getClassInterface();
if (!ID) {
// Handle invalid code where the @interface might not
// have been specified.
@@ -349,8 +345,8 @@ void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) {
break;
}
case Decl::ObjCCategoryImpl: {
- ObjCCategoryImplDecl *CD = cast<ObjCCategoryImplDecl>(D);
- ObjCInterfaceDecl *ID = CD->getClassInterface();
+ const ObjCCategoryImplDecl *CD = cast<ObjCCategoryImplDecl>(D);
+ const ObjCInterfaceDecl *ID = CD->getClassInterface();
if (!ID) {
// Handle invalid code where the @interface might not
// have been specified.
@@ -368,17 +364,17 @@ void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) {
}
}
-void USRGenerator::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
+void USRGenerator::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
// The USR for a property declared in a class extension or category is based
// on the ObjCInterfaceDecl, not the ObjCCategoryDecl.
- if (ObjCInterfaceDecl *ID = Context->getObjContainingInterface(D))
+ if (const ObjCInterfaceDecl *ID = Context->getObjContainingInterface(D))
Visit(ID);
else
Visit(cast<Decl>(D->getDeclContext()));
GenObjCProperty(D->getName());
}
-void USRGenerator::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
+void USRGenerator::VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) {
if (ObjCPropertyDecl *PD = D->getPropertyDecl()) {
VisitObjCPropertyDecl(PD);
return;
@@ -387,7 +383,7 @@ void USRGenerator::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
IgnoreResults = true;
}
-void USRGenerator::VisitTagDecl(TagDecl *D) {
+void USRGenerator::VisitTagDecl(const TagDecl *D) {
// Add the location of the tag decl to handle resolution across
// translation units.
if (ShouldGenerateLocation(D) && GenLoc(D))
@@ -397,7 +393,7 @@ void USRGenerator::VisitTagDecl(TagDecl *D) {
VisitDeclContext(D->getDeclContext());
bool AlreadyStarted = false;
- if (CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(D)) {
+ if (const CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(D)) {
if (ClassTemplateDecl *ClassTmpl = CXXRecord->getDescribedClassTemplate()) {
AlreadyStarted = true;
@@ -409,7 +405,7 @@ void USRGenerator::VisitTagDecl(TagDecl *D) {
case TTK_Enum: llvm_unreachable("enum template");
}
VisitTemplateParameterList(ClassTmpl->getTemplateParameters());
- } else if (ClassTemplatePartialSpecializationDecl *PartialSpec
+ } else if (const ClassTemplatePartialSpecializationDecl *PartialSpec
= dyn_cast<ClassTemplatePartialSpecializationDecl>(CXXRecord)) {
AlreadyStarted = true;
@@ -449,7 +445,7 @@ void USRGenerator::VisitTagDecl(TagDecl *D) {
}
// For a class template specialization, mangle the template arguments.
- if (ClassTemplateSpecializationDecl *Spec
+ if (const ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(D)) {
const TemplateArgumentList &Args = Spec->getTemplateInstantiationArgs();
Out << '>';
@@ -460,17 +456,17 @@ void USRGenerator::VisitTagDecl(TagDecl *D) {
}
}
-void USRGenerator::VisitTypedefDecl(TypedefDecl *D) {
+void USRGenerator::VisitTypedefDecl(const TypedefDecl *D) {
if (ShouldGenerateLocation(D) && GenLoc(D))
return;
- DeclContext *DC = D->getDeclContext();
- if (NamedDecl *DCN = dyn_cast<NamedDecl>(DC))
+ const DeclContext *DC = D->getDeclContext();
+ if (const NamedDecl *DCN = dyn_cast<NamedDecl>(DC))
Visit(DCN);
Out << "@T@";
Out << D->getName();
}
-void USRGenerator::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
+void USRGenerator::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
GenLoc(D);
return;
}
@@ -593,6 +589,14 @@ void USRGenerator::VisitType(QualType T) {
#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
#include "clang/AST/BuiltinTypes.def"
case BuiltinType::Dependent:
+ case BuiltinType::OCLImage1d:
+ case BuiltinType::OCLImage1dArray:
+ case BuiltinType::OCLImage1dBuffer:
+ case BuiltinType::OCLImage2d:
+ case BuiltinType::OCLImage2dArray:
+ case BuiltinType::OCLImage3d:
+ case BuiltinType::OCLEvent:
+ case BuiltinType::OCLSampler:
IgnoreResults = true;
return;
case BuiltinType::ObjCId:
@@ -806,7 +810,7 @@ bool cxcursor::getDeclCursorUSR(const Decl *D, SmallVectorImpl<char> &Buf) {
return true;
USRGenerator UG(&D->getASTContext(), &Buf);
- UG->Visit(const_cast<Decl*>(D));
+ UG->Visit(D);
if (UG->ignoreResults())
return true;
@@ -820,22 +824,22 @@ CXString clang_getCursorUSR(CXCursor C) {
const CXCursorKind &K = clang_getCursorKind(C);
if (clang_isDeclaration(K)) {
- Decl *D = cxcursor::getCursorDecl(C);
+ const Decl *D = cxcursor::getCursorDecl(C);
if (!D)
- return createCXString("");
+ return cxstring::createEmpty();
CXTranslationUnit TU = cxcursor::getCursorTU(C);
if (!TU)
- return createCXString("");
+ return cxstring::createEmpty();
- CXStringBuf *buf = cxstring::getCXStringBuf(TU);
+ cxstring::CXStringBuf *buf = cxstring::getCXStringBuf(TU);
if (!buf)
- return createCXString("");
+ return cxstring::createEmpty();
bool Ignore = cxcursor::getDeclCursorUSR(D, buf->Data);
if (Ignore) {
- disposeCXStringBuf(buf);
- return createCXString("");
+ buf->dispose();
+ return cxstring::createEmpty();
}
// Return the C-string, but don't make a copy since it is already in
@@ -847,11 +851,11 @@ CXString clang_getCursorUSR(CXCursor C) {
if (K == CXCursor_MacroDefinition) {
CXTranslationUnit TU = cxcursor::getCursorTU(C);
if (!TU)
- return createCXString("");
+ return cxstring::createEmpty();
- CXStringBuf *buf = cxstring::getCXStringBuf(TU);
+ cxstring::CXStringBuf *buf = cxstring::getCXStringBuf(TU);
if (!buf)
- return createCXString("");
+ return cxstring::createEmpty();
{
USRGenerator UG(&cxcursor::getCursorASTUnit(C)->getASTContext(),
@@ -863,14 +867,14 @@ CXString clang_getCursorUSR(CXCursor C) {
return createCXString(buf);
}
- return createCXString("");
+ return cxstring::createEmpty();
}
CXString clang_constructUSR_ObjCIvar(const char *name, CXString classUSR) {
USRGenerator UG;
UG << extractUSRSuffix(clang_getCString(classUSR));
UG->GenObjCIvar(name);
- return createCXString(UG.str(), true);
+ return cxstring::createDup(UG.str());
}
CXString clang_constructUSR_ObjCMethod(const char *name,
@@ -879,26 +883,26 @@ CXString clang_constructUSR_ObjCMethod(const char *name,
USRGenerator UG;
UG << extractUSRSuffix(clang_getCString(classUSR));
UG->GenObjCMethod(name, isInstanceMethod);
- return createCXString(UG.str(), true);
+ return cxstring::createDup(UG.str());
}
CXString clang_constructUSR_ObjCClass(const char *name) {
USRGenerator UG;
UG->GenObjCClass(name);
- return createCXString(UG.str(), true);
+ return cxstring::createDup(UG.str());
}
CXString clang_constructUSR_ObjCProtocol(const char *name) {
USRGenerator UG;
UG->GenObjCProtocol(name);
- return createCXString(UG.str(), true);
+ return cxstring::createDup(UG.str());
}
CXString clang_constructUSR_ObjCCategory(const char *class_name,
const char *category_name) {
USRGenerator UG;
UG->GenObjCCategory(class_name, category_name);
- return createCXString(UG.str(), true);
+ return cxstring::createDup(UG.str());
}
CXString clang_constructUSR_ObjCProperty(const char *property,
@@ -906,7 +910,7 @@ CXString clang_constructUSR_ObjCProperty(const char *property,
USRGenerator UG;
UG << extractUSRSuffix(clang_getCString(classUSR));
UG->GenObjCProperty(property);
- return createCXString(UG.str(), true);
+ return cxstring::createDup(UG.str());
}
} // end extern "C"
diff --git a/tools/libclang/CIndexer.cpp b/tools/libclang/CIndexer.cpp
index d458789..d89e0a4 100644
--- a/tools/libclang/CIndexer.cpp
+++ b/tools/libclang/CIndexer.cpp
@@ -12,7 +12,6 @@
//===----------------------------------------------------------------------===//
#include "CIndexer.h"
-
#include "clang/AST/Decl.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/StmtVisitor.h"
@@ -24,12 +23,11 @@
#include "llvm/Config/llvm-config.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Program.h"
-
+#include "llvm/Support/raw_ostream.h"
#include <cstdio>
-#include <vector>
#include <sstream>
+#include <vector>
#ifdef __CYGWIN__
#include <cygwin/version.h>
diff --git a/tools/libclang/CIndexer.h b/tools/libclang/CIndexer.h
index 1e5fb82..08162c5 100644
--- a/tools/libclang/CIndexer.h
+++ b/tools/libclang/CIndexer.h
@@ -26,6 +26,11 @@ namespace llvm {
namespace clang {
class ASTUnit;
+ class MacroInfo;
+ class MacroDefinition;
+ class SourceLocation;
+ class Token;
+ class IdentifierInfo;
class CIndexer {
bool OnlyLocalDecls;
@@ -33,7 +38,6 @@ class CIndexer {
unsigned Options; // CXGlobalOptFlags.
llvm::sys::Path ResourcesPath;
- std::string WorkingDir;
public:
CIndexer() : OnlyLocalDecls(false), DisplayDiagnostics(false),
@@ -59,9 +63,6 @@ public:
/// \brief Get the path of the clang resource files.
std::string getClangResourcesPath();
-
- const std::string &getWorkingDirectory() const { return WorkingDir; }
- void setWorkingDirectory(const std::string &Dir) { WorkingDir = Dir; }
};
/**
@@ -98,6 +99,30 @@ public:
namespace cxindex {
void printDiagsToStderr(ASTUnit *Unit);
+
+ /// \brief If \c MacroDefLoc points at a macro definition with \c II as
+ /// its name, this retrieves its MacroInfo.
+ MacroInfo *getMacroInfo(const IdentifierInfo &II,
+ SourceLocation MacroDefLoc,
+ CXTranslationUnit TU);
+
+ /// \brief Retrieves the corresponding MacroInfo of a MacroDefinition.
+ const MacroInfo *getMacroInfo(const MacroDefinition *MacroDef,
+ CXTranslationUnit TU);
+
+ /// \brief If \c Loc resides inside the definition of \c MI and it points at
+ /// an identifier that has ever been a macro name, this returns the latest
+ /// MacroDefinition for that name, otherwise it returns NULL.
+ MacroDefinition *checkForMacroInMacroDefinition(const MacroInfo *MI,
+ SourceLocation Loc,
+ CXTranslationUnit TU);
+
+ /// \brief If \c Tok resides inside the definition of \c MI and it points at
+ /// an identifier that has ever been a macro name, this returns the latest
+ /// MacroDefinition for that name, otherwise it returns NULL.
+ MacroDefinition *checkForMacroInMacroDefinition(const MacroInfo *MI,
+ const Token &Tok,
+ CXTranslationUnit TU);
}
}
diff --git a/tools/libclang/CLog.h b/tools/libclang/CLog.h
new file mode 100644
index 0000000..57e01ae
--- /dev/null
+++ b/tools/libclang/CLog.h
@@ -0,0 +1,101 @@
+//===- CLog.h - Logging Interface -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBCLANG_CLOG_H
+#define LLVM_LIBCLANG_CLOG_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
+#include <string>
+
+namespace llvm {
+class format_object_base;
+}
+
+namespace clang {
+ class FileEntry;
+
+namespace cxindex {
+
+class Logger;
+typedef IntrusiveRefCntPtr<Logger> LogRef;
+
+/// \brief Collects logging output and writes it to stderr when it's destructed.
+/// Common use case:
+/// \code
+/// if (LogRef Log = Logger::make(__func__)) {
+/// *Log << "stuff";
+/// }
+/// \endcode
+class Logger : public RefCountedBase<Logger> {
+ std::string Name;
+ bool Trace;
+ SmallString<64> Msg;
+ llvm::raw_svector_ostream LogOS;
+public:
+ static const char *getEnvVar() {
+ static const char *sCachedVar = ::getenv("LIBCLANG_LOGGING");
+ return sCachedVar;
+ }
+ static bool isLoggingEnabled() { return getEnvVar() != 0; }
+ static bool isStackTracingEnabled() {
+ if (const char *EnvOpt = Logger::getEnvVar())
+ return llvm::StringRef(EnvOpt) == "2";
+ return false;
+ }
+ static LogRef make(llvm::StringRef name,
+ bool trace = isStackTracingEnabled()) {
+ if (isLoggingEnabled())
+ return new Logger(name, trace);
+ return 0;
+ }
+
+ explicit Logger(llvm::StringRef name, bool trace)
+ : Name(name), Trace(trace), LogOS(Msg) { }
+ ~Logger();
+
+ Logger &operator<<(CXTranslationUnit);
+ Logger &operator<<(const FileEntry *FE);
+ Logger &operator<<(CXCursor cursor);
+ Logger &operator<<(CXSourceLocation);
+ Logger &operator<<(CXSourceRange);
+ Logger &operator<<(CXString);
+ Logger &operator<<(llvm::StringRef Str) { LogOS << Str; return *this; }
+ Logger &operator<<(const char *Str) {
+ if (Str)
+ LogOS << Str;
+ return *this;
+ }
+ Logger &operator<<(unsigned long N) { LogOS << N; return *this; }
+ Logger &operator<<(long N) { LogOS << N ; return *this; }
+ Logger &operator<<(unsigned int N) { LogOS << N; return *this; }
+ Logger &operator<<(int N) { LogOS << N; return *this; }
+ Logger &operator<<(char C) { LogOS << C; return *this; }
+ Logger &operator<<(unsigned char C) { LogOS << C; return *this; }
+ Logger &operator<<(signed char C) { LogOS << C; return *this; }
+ Logger &operator<<(const llvm::format_object_base &Fmt);
+};
+
+}
+}
+
+/// \brief Macros to automate common uses of Logger. Like this:
+/// \code
+/// LOG_FUNC_SECTION {
+/// *Log << "blah";
+/// }
+/// \endcode
+#define LOG_SECTION(NAME) if (LogRef Log = clang::cxindex::Logger::make(NAME))
+#define LOG_FUNC_SECTION LOG_SECTION(LLVM_FUNCTION_NAME)
+
+#endif
diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt
index 1426c42..c5a975b 100644
--- a/tools/libclang/CMakeLists.txt
+++ b/tools/libclang/CMakeLists.txt
@@ -2,6 +2,7 @@ set(LLVM_LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
asmparser
support
+ bitreader
mc
)
@@ -38,6 +39,7 @@ set(SOURCES
Indexing.cpp
IndexingContext.cpp
IndexingContext.h
+ SimpleFormatContext.h
../../include/clang-c/Index.h
)
@@ -54,6 +56,7 @@ set(LIBRARIES
clangLex
clangTooling
clangBasic
+ clangFormat
)
set(GENERATED_HEADERS
@@ -71,7 +74,7 @@ if( LLVM_ENABLE_PIC )
set(SHARED_LIBRARY TRUE)
add_clang_library(libclang ${SOURCES})
target_link_libraries(libclang ${LIBRARIES})
- add_dependencies(libclang ${GENERATED_HEADERS})
+ add_dependencies(libclang ${GENERATED_HEADERS} clang-headers)
if(WIN32)
set_target_properties(libclang
@@ -105,7 +108,7 @@ endif()
if( NOT BUILD_SHARED_LIBS AND NOT WIN32 )
add_clang_library(${LIBCLANG_STATIC_TARGET_NAME} STATIC ${SOURCES})
target_link_libraries(${LIBCLANG_STATIC_TARGET_NAME} ${LIBRARIES})
- add_dependencies(${LIBCLANG_STATIC_TARGET_NAME} ${GENERATED_HEADERS})
+ add_dependencies(${LIBCLANG_STATIC_TARGET_NAME} ${GENERATED_HEADERS} clang-headers)
set_target_properties(${LIBCLANG_STATIC_TARGET_NAME}
PROPERTIES
diff --git a/tools/libclang/CXComment.cpp b/tools/libclang/CXComment.cpp
index fa149a0..1c127e1 100644
--- a/tools/libclang/CXComment.cpp
+++ b/tools/libclang/CXComment.cpp
@@ -12,23 +12,23 @@
//===----------------------------------------------------------------------===//
#include "clang-c/Index.h"
-#include "CXString.h"
#include "CXComment.h"
#include "CXCursor.h"
-
-#include "clang/AST/PrettyPrinter.h"
-#include "clang/AST/CommentVisitor.h"
+#include "CXString.h"
+#include "SimpleFormatContext.h"
#include "clang/AST/CommentCommandTraits.h"
+#include "clang/AST/CommentVisitor.h"
#include "clang/AST/Decl.h"
-
+#include "clang/AST/PrettyPrinter.h"
+#include "clang/Format/Format.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
-
#include <climits>
using namespace clang;
-using namespace clang::cxstring;
using namespace clang::comments;
using namespace clang::cxcomment;
@@ -123,18 +123,18 @@ unsigned clang_InlineContentComment_hasTrailingNewline(CXComment CXC) {
CXString clang_TextComment_getText(CXComment CXC) {
const TextComment *TC = getASTNodeAs<TextComment>(CXC);
if (!TC)
- return createCXString((const char *) 0);
+ return cxstring::createNull();
- return createCXString(TC->getText(), /*DupString=*/ false);
+ return cxstring::createRef(TC->getText());
}
CXString clang_InlineCommandComment_getCommandName(CXComment CXC) {
const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
if (!ICC)
- return createCXString((const char *) 0);
+ return cxstring::createNull();
const CommandTraits &Traits = getCommandTraits(CXC);
- return createCXString(ICC->getCommandName(Traits), /*DupString=*/ false);
+ return cxstring::createRef(ICC->getCommandName(Traits));
}
enum CXCommentInlineCommandRenderKind
@@ -171,17 +171,17 @@ CXString clang_InlineCommandComment_getArgText(CXComment CXC,
unsigned ArgIdx) {
const InlineCommandComment *ICC = getASTNodeAs<InlineCommandComment>(CXC);
if (!ICC || ArgIdx >= ICC->getNumArgs())
- return createCXString((const char *) 0);
+ return cxstring::createNull();
- return createCXString(ICC->getArgText(ArgIdx), /*DupString=*/ false);
+ return cxstring::createRef(ICC->getArgText(ArgIdx));
}
CXString clang_HTMLTagComment_getTagName(CXComment CXC) {
const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC);
if (!HTC)
- return createCXString((const char *) 0);
+ return cxstring::createNull();
- return createCXString(HTC->getTagName(), /*DupString=*/ false);
+ return cxstring::createRef(HTC->getTagName());
}
unsigned clang_HTMLStartTagComment_isSelfClosing(CXComment CXC) {
@@ -203,26 +203,26 @@ unsigned clang_HTMLStartTag_getNumAttrs(CXComment CXC) {
CXString clang_HTMLStartTag_getAttrName(CXComment CXC, unsigned AttrIdx) {
const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
if (!HST || AttrIdx >= HST->getNumAttrs())
- return createCXString((const char *) 0);
+ return cxstring::createNull();
- return createCXString(HST->getAttr(AttrIdx).Name, /*DupString=*/ false);
+ return cxstring::createRef(HST->getAttr(AttrIdx).Name);
}
CXString clang_HTMLStartTag_getAttrValue(CXComment CXC, unsigned AttrIdx) {
const HTMLStartTagComment *HST = getASTNodeAs<HTMLStartTagComment>(CXC);
if (!HST || AttrIdx >= HST->getNumAttrs())
- return createCXString((const char *) 0);
+ return cxstring::createNull();
- return createCXString(HST->getAttr(AttrIdx).Value, /*DupString=*/ false);
+ return cxstring::createRef(HST->getAttr(AttrIdx).Value);
}
CXString clang_BlockCommandComment_getCommandName(CXComment CXC) {
const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
if (!BCC)
- return createCXString((const char *) 0);
+ return cxstring::createNull();
const CommandTraits &Traits = getCommandTraits(CXC);
- return createCXString(BCC->getCommandName(Traits), /*DupString=*/ false);
+ return cxstring::createRef(BCC->getCommandName(Traits));
}
unsigned clang_BlockCommandComment_getNumArgs(CXComment CXC) {
@@ -237,9 +237,9 @@ CXString clang_BlockCommandComment_getArgText(CXComment CXC,
unsigned ArgIdx) {
const BlockCommandComment *BCC = getASTNodeAs<BlockCommandComment>(CXC);
if (!BCC || ArgIdx >= BCC->getNumArgs())
- return createCXString((const char *) 0);
+ return cxstring::createNull();
- return createCXString(BCC->getArgText(ArgIdx), /*DupString=*/ false);
+ return cxstring::createRef(BCC->getArgText(ArgIdx));
}
CXComment clang_BlockCommandComment_getParagraph(CXComment CXC) {
@@ -253,9 +253,9 @@ CXComment clang_BlockCommandComment_getParagraph(CXComment CXC) {
CXString clang_ParamCommandComment_getParamName(CXComment CXC) {
const ParamCommandComment *PCC = getASTNodeAs<ParamCommandComment>(CXC);
if (!PCC || !PCC->hasParamName())
- return createCXString((const char *) 0);
+ return cxstring::createNull();
- return createCXString(PCC->getParamNameAsWritten(), /*DupString=*/ false);
+ return cxstring::createRef(PCC->getParamNameAsWritten());
}
unsigned clang_ParamCommandComment_isParamIndexValid(CXComment CXC) {
@@ -304,9 +304,9 @@ enum CXCommentParamPassDirection clang_ParamCommandComment_getDirection(
CXString clang_TParamCommandComment_getParamName(CXComment CXC) {
const TParamCommandComment *TPCC = getASTNodeAs<TParamCommandComment>(CXC);
if (!TPCC || !TPCC->hasParamName())
- return createCXString((const char *) 0);
+ return cxstring::createNull();
- return createCXString(TPCC->getParamNameAsWritten(), /*DupString=*/ false);
+ return cxstring::createRef(TPCC->getParamNameAsWritten());
}
unsigned clang_TParamCommandComment_isParamPositionValid(CXComment CXC) {
@@ -337,17 +337,17 @@ CXString clang_VerbatimBlockLineComment_getText(CXComment CXC) {
const VerbatimBlockLineComment *VBL =
getASTNodeAs<VerbatimBlockLineComment>(CXC);
if (!VBL)
- return createCXString((const char *) 0);
+ return cxstring::createNull();
- return createCXString(VBL->getText(), /*DupString=*/ false);
+ return cxstring::createRef(VBL->getText());
}
CXString clang_VerbatimLineComment_getText(CXComment CXC) {
const VerbatimLineComment *VLC = getASTNodeAs<VerbatimLineComment>(CXC);
if (!VLC)
- return createCXString((const char *) 0);
+ return cxstring::createNull();
- return createCXString(VLC->getText(), /*DupString=*/ false);
+ return cxstring::createRef(VLC->getText());
}
} // end extern "C"
@@ -410,6 +410,7 @@ struct FullCommentParts {
const CommandTraits &Traits);
const BlockContentComment *Brief;
+ const BlockContentComment *Headerfile;
const ParagraphComment *FirstParagraph;
const BlockCommandComment *Returns;
SmallVector<const ParamCommandComment *, 8> Params;
@@ -419,7 +420,7 @@ struct FullCommentParts {
FullCommentParts::FullCommentParts(const FullComment *C,
const CommandTraits &Traits) :
- Brief(NULL), FirstParagraph(NULL), Returns(NULL) {
+ Brief(NULL), Headerfile(NULL), FirstParagraph(NULL), Returns(NULL) {
for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
I != E; ++I) {
const Comment *Child = *I;
@@ -447,6 +448,10 @@ FullCommentParts::FullCommentParts(const FullComment *C,
Brief = BCC;
break;
}
+ if (!Headerfile && Info->IsHeaderfileCommand) {
+ Headerfile = BCC;
+ break;
+ }
if (!Returns && Info->IsReturnsCommand) {
Returns = BCC;
break;
@@ -749,6 +754,8 @@ void CommentASTToHTMLConverter::visitFullComment(const FullComment *C) {
FullCommentParts Parts(C, Traits);
bool FirstParagraphIsBrief = false;
+ if (Parts.Headerfile)
+ visit(Parts.Headerfile);
if (Parts.Brief)
visit(Parts.Brief);
else if (Parts.FirstParagraph) {
@@ -830,23 +837,23 @@ extern "C" {
CXString clang_HTMLTagComment_getAsString(CXComment CXC) {
const HTMLTagComment *HTC = getASTNodeAs<HTMLTagComment>(CXC);
if (!HTC)
- return createCXString((const char *) 0);
+ return cxstring::createNull();
SmallString<128> HTML;
CommentASTToHTMLConverter Converter(0, HTML, getCommandTraits(CXC));
Converter.visit(HTC);
- return createCXString(HTML.str(), /* DupString = */ true);
+ return cxstring::createDup(HTML.str());
}
CXString clang_FullComment_getAsHTML(CXComment CXC) {
const FullComment *FC = getASTNodeAs<FullComment>(CXC);
if (!FC)
- return createCXString((const char *) 0);
+ return cxstring::createNull();
SmallString<1024> HTML;
CommentASTToHTMLConverter Converter(FC, HTML, getCommandTraits(CXC));
Converter.visit(FC);
- return createCXString(HTML.str(), /* DupString = */ true);
+ return cxstring::createDup(HTML.str());
}
} // end extern "C"
@@ -859,8 +866,12 @@ public:
CommentASTToXMLConverter(const FullComment *FC,
SmallVectorImpl<char> &Str,
const CommandTraits &Traits,
- const SourceManager &SM) :
- FC(FC), Result(Str), Traits(Traits), SM(SM) { }
+ const SourceManager &SM,
+ SimpleFormatContext &SFC,
+ unsigned FUID) :
+ FC(FC), Result(Str), Traits(Traits), SM(SM),
+ FormatRewriterContext(SFC),
+ FormatInMemoryUniqueId(FUID) { }
// Inline content.
void visitTextComment(const TextComment *C);
@@ -870,6 +881,10 @@ public:
// Block content.
void visitParagraphComment(const ParagraphComment *C);
+
+ void appendParagraphCommentWithKind(const ParagraphComment *C,
+ StringRef Kind);
+
void visitBlockCommandComment(const BlockCommandComment *C);
void visitParamCommandComment(const ParamCommandComment *C);
void visitTParamCommandComment(const TParamCommandComment *C);
@@ -882,6 +897,9 @@ public:
// Helpers.
void appendToResultWithXMLEscaping(StringRef S);
+ void formatTextOfDeclaration(const DeclInfo *DI,
+ SmallString<128> &Declaration);
+
private:
const FullComment *FC;
@@ -890,6 +908,8 @@ private:
const CommandTraits &Traits;
const SourceManager &SM;
+ SimpleFormatContext &FormatRewriterContext;
+ unsigned FormatInMemoryUniqueId;
};
void getSourceTextOfDeclaration(const DeclInfo *ThisDecl,
@@ -898,10 +918,40 @@ void getSourceTextOfDeclaration(const DeclInfo *ThisDecl,
const LangOptions &LangOpts = Context.getLangOpts();
llvm::raw_svector_ostream OS(Str);
PrintingPolicy PPolicy(LangOpts);
- PPolicy.SuppressAttributes = true;
+ PPolicy.PolishForDeclaration = true;
PPolicy.TerseOutput = true;
ThisDecl->CurrentDecl->print(OS, PPolicy,
- /*Indentation*/0, /*PrintInstantiation*/true);
+ /*Indentation*/0, /*PrintInstantiation*/false);
+}
+
+void CommentASTToXMLConverter::formatTextOfDeclaration(
+ const DeclInfo *DI,
+ SmallString<128> &Declaration) {
+ // FIXME. formatting API expects null terminated input string.
+ // There might be more efficient way of doing this.
+ std::string StringDecl = Declaration.str();
+
+ // Formatter specific code.
+ // Form a unique in memory buffer name.
+ SmallString<128> filename;
+ filename += "xmldecl";
+ filename += llvm::utostr(FormatInMemoryUniqueId);
+ filename += ".xd";
+ FileID ID = FormatRewriterContext.createInMemoryFile(filename, StringDecl);
+ SourceLocation Start =
+ FormatRewriterContext.Sources.getLocForStartOfFile(ID).getLocWithOffset(0);
+ unsigned Length = Declaration.size();
+
+ std::vector<CharSourceRange>
+ Ranges(1, CharSourceRange::getCharRange(Start, Start.getLocWithOffset(Length)));
+ ASTContext &Context = DI->CurrentDecl->getASTContext();
+ const LangOptions &LangOpts = Context.getLangOpts();
+ Lexer Lex(ID, FormatRewriterContext.Sources.getBuffer(ID),
+ FormatRewriterContext.Sources, LangOpts);
+ tooling::Replacements Replace =
+ reformat(format::getLLVMStyle(), Lex, FormatRewriterContext.Sources, Ranges);
+ applyAllReplacements(Replace, FormatRewriterContext.Rewrite);
+ Declaration = FormatRewriterContext.getRewrittenText(ID);
}
} // end unnamed namespace
@@ -959,10 +1009,20 @@ void CommentASTToXMLConverter::visitHTMLEndTagComment(const HTMLEndTagComment *C
}
void CommentASTToXMLConverter::visitParagraphComment(const ParagraphComment *C) {
+ appendParagraphCommentWithKind(C, StringRef());
+}
+
+void CommentASTToXMLConverter::appendParagraphCommentWithKind(
+ const ParagraphComment *C,
+ StringRef ParagraphKind) {
if (C->isWhitespace())
return;
- Result << "<Para>";
+ if (ParagraphKind.empty())
+ Result << "<Para>";
+ else
+ Result << "<Para kind=\"" << ParagraphKind << "\">";
+
for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
I != E; ++I) {
visit(*I);
@@ -971,7 +1031,33 @@ void CommentASTToXMLConverter::visitParagraphComment(const ParagraphComment *C)
}
void CommentASTToXMLConverter::visitBlockCommandComment(const BlockCommandComment *C) {
- visit(C->getParagraph());
+ StringRef ParagraphKind;
+
+ switch (C->getCommandID()) {
+ case CommandTraits::KCI_attention:
+ case CommandTraits::KCI_author:
+ case CommandTraits::KCI_authors:
+ case CommandTraits::KCI_bug:
+ case CommandTraits::KCI_copyright:
+ case CommandTraits::KCI_date:
+ case CommandTraits::KCI_invariant:
+ case CommandTraits::KCI_note:
+ case CommandTraits::KCI_post:
+ case CommandTraits::KCI_pre:
+ case CommandTraits::KCI_remark:
+ case CommandTraits::KCI_remarks:
+ case CommandTraits::KCI_sa:
+ case CommandTraits::KCI_see:
+ case CommandTraits::KCI_since:
+ case CommandTraits::KCI_todo:
+ case CommandTraits::KCI_version:
+ case CommandTraits::KCI_warning:
+ ParagraphKind = C->getCommandName(Traits);
+ default:
+ break;
+ }
+
+ appendParagraphCommentWithKind(C->getParagraph(), ParagraphKind);
}
void CommentASTToXMLConverter::visitParamCommandComment(const ParamCommandComment *C) {
@@ -1022,9 +1108,14 @@ void CommentASTToXMLConverter::visitVerbatimBlockComment(
if (NumLines == 0)
return;
- Result << llvm::StringSwitch<const char *>(C->getCommandName(Traits))
- .Case("code", "<Verbatim xml:space=\"preserve\" kind=\"code\">")
- .Default("<Verbatim xml:space=\"preserve\" kind=\"verbatim\">");
+ switch (C->getCommandID()) {
+ case CommandTraits::KCI_code:
+ Result << "<Verbatim xml:space=\"preserve\" kind=\"code\">";
+ break;
+ default:
+ Result << "<Verbatim xml:space=\"preserve\" kind=\"verbatim\">";
+ break;
+ }
for (unsigned i = 0; i != NumLines; ++i) {
appendToResultWithXMLEscaping(C->getText(i));
if (i + 1 != NumLines)
@@ -1162,13 +1253,21 @@ void CommentASTToXMLConverter::visitFullComment(const FullComment *C) {
RootEndTag = "</Other>";
Result << "<Other><Name>unknown</Name>";
}
+
+ if (Parts.Headerfile) {
+ Result << "<Headerfile>";
+ visit(Parts.Headerfile);
+ Result << "</Headerfile>";
+ }
{
// Pretty-print the declaration.
Result << "<Declaration>";
SmallString<128> Declaration;
getSourceTextOfDeclaration(DI, Declaration);
+ formatTextOfDeclaration(DI, Declaration);
appendToResultWithXMLEscaping(Declaration);
+
Result << "</Declaration>";
}
@@ -1183,7 +1282,7 @@ void CommentASTToXMLConverter::visitFullComment(const FullComment *C) {
Result << "</Abstract>";
FirstParagraphIsBrief = true;
}
-
+
if (Parts.TParams.size() != 0) {
Result << "<TemplateParameters>";
for (unsigned i = 0, e = Parts.TParams.size(); i != e; ++i)
@@ -1322,15 +1421,26 @@ extern "C" {
CXString clang_FullComment_getAsXML(CXComment CXC) {
const FullComment *FC = getASTNodeAs<FullComment>(CXC);
if (!FC)
- return createCXString((const char *) 0);
-
+ return cxstring::createNull();
+ ASTContext &Context = FC->getDeclInfo()->CurrentDecl->getASTContext();
CXTranslationUnit TU = CXC.TranslationUnit;
- SourceManager &SM = static_cast<ASTUnit *>(TU->TUData)->getSourceManager();
+ SourceManager &SM = cxtu::getASTUnit(TU)->getSourceManager();
+
+ if (!TU->FormatContext) {
+ TU->FormatContext = new SimpleFormatContext(Context.getLangOpts());
+ } else if ((TU->FormatInMemoryUniqueId % 1000) == 0) {
+ // Delete after some number of iterators, so the buffers don't grow
+ // too large.
+ delete TU->FormatContext;
+ TU->FormatContext = new SimpleFormatContext(Context.getLangOpts());
+ }
SmallString<1024> XML;
- CommentASTToXMLConverter Converter(FC, XML, getCommandTraits(CXC), SM);
+ CommentASTToXMLConverter Converter(FC, XML, getCommandTraits(CXC), SM,
+ *TU->FormatContext,
+ TU->FormatInMemoryUniqueId++);
Converter.visit(FC);
- return createCXString(XML.str(), /* DupString = */ true);
+ return cxstring::createDup(XML.str());
}
} // end extern "C"
diff --git a/tools/libclang/CXComment.h b/tools/libclang/CXComment.h
index 5134317..0780a65 100644
--- a/tools/libclang/CXComment.h
+++ b/tools/libclang/CXComment.h
@@ -14,11 +14,10 @@
#ifndef LLVM_CLANG_CXCOMMENT_H
#define LLVM_CLANG_CXCOMMENT_H
-#include "clang-c/Index.h"
#include "CXTranslationUnit.h"
-
-#include "clang/AST/Comment.h"
+#include "clang-c/Index.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Comment.h"
#include "clang/Frontend/ASTUnit.h"
namespace clang {
@@ -50,7 +49,7 @@ inline const T *getASTNodeAs(CXComment CXC) {
}
inline ASTContext &getASTContext(CXComment CXC) {
- return static_cast<ASTUnit *>(CXC.TranslationUnit->TUData)->getASTContext();
+ return cxtu::getASTUnit(CXC.TranslationUnit)->getASTContext();
}
inline comments::CommandTraits &getCommandTraits(CXComment CXC) {
diff --git a/tools/libclang/CXCompilationDatabase.cpp b/tools/libclang/CXCompilationDatabase.cpp
index 7bd319a..e35ac27 100644
--- a/tools/libclang/CXCompilationDatabase.cpp
+++ b/tools/libclang/CXCompilationDatabase.cpp
@@ -1,10 +1,9 @@
#include "clang-c/CXCompilationDatabase.h"
-#include "clang/Tooling/CompilationDatabase.h"
#include "CXString.h"
+#include "clang/Tooling/CompilationDatabase.h"
using namespace clang;
using namespace clang::tooling;
-using namespace clang::cxstring;
extern "C" {
@@ -59,6 +58,17 @@ clang_CompilationDatabase_getCompileCommands(CXCompilationDatabase CDb,
return 0;
}
+CXCompileCommands
+clang_CompilationDatabase_getAllCompileCommands(CXCompilationDatabase CDb) {
+ if (CompilationDatabase *db = static_cast<CompilationDatabase *>(CDb)) {
+ const std::vector<CompileCommand> CCmd(db->getAllCompileCommands());
+ if (!CCmd.empty())
+ return new AllocatedCXCompileCommands( CCmd );
+ }
+
+ return 0;
+}
+
void
clang_CompileCommands_dispose(CXCompileCommands Cmds)
{
@@ -96,10 +106,10 @@ CXString
clang_CompileCommand_getDirectory(CXCompileCommand CCmd)
{
if (!CCmd)
- return createCXString((const char*)NULL);
+ return cxstring::createNull();
CompileCommand *cmd = static_cast<CompileCommand *>(CCmd);
- return createCXString(cmd->Directory);
+ return cxstring::createRef(cmd->Directory.c_str());
}
unsigned
@@ -115,14 +125,14 @@ CXString
clang_CompileCommand_getArg(CXCompileCommand CCmd, unsigned Arg)
{
if (!CCmd)
- return createCXString((const char*)NULL);
+ return cxstring::createNull();
CompileCommand *Cmd = static_cast<CompileCommand *>(CCmd);
if (Arg >= Cmd->CommandLine.size())
- return createCXString((const char*)NULL);
+ return cxstring::createNull();
- return createCXString(Cmd->CommandLine[Arg]);
+ return cxstring::createRef(Cmd->CommandLine[Arg].c_str());
}
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index 8d3e169..7b01ec2 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -15,9 +15,9 @@
#include "CXTranslationUnit.h"
#include "CXCursor.h"
-#include "CXType.h"
#include "CXString.h"
-#include "clang/Frontend/ASTUnit.h"
+#include "CXType.h"
+#include "clang-c/Index.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
@@ -25,7 +25,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
-#include "clang-c/Index.h"
+#include "clang/Frontend/ASTUnit.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
@@ -53,14 +53,14 @@ static CXCursorKind GetCursorKind(const Attr *A) {
return CXCursor_UnexposedAttr;
}
-CXCursor cxcursor::MakeCXCursor(const Attr *A, Decl *Parent,
+CXCursor cxcursor::MakeCXCursor(const Attr *A, const Decl *Parent,
CXTranslationUnit TU) {
assert(A && Parent && TU && "Invalid arguments!");
- CXCursor C = { GetCursorKind(A), 0, { Parent, (void*)A, TU } };
+ CXCursor C = { GetCursorKind(A), 0, { Parent, A, TU } };
return C;
}
-CXCursor cxcursor::MakeCXCursor(Decl *D, CXTranslationUnit TU,
+CXCursor cxcursor::MakeCXCursor(const Decl *D, CXTranslationUnit TU,
SourceRange RegionOfInterest,
bool FirstInDeclGroup) {
assert(D && TU && "Invalid arguments!");
@@ -89,7 +89,8 @@ CXCursor cxcursor::MakeCXCursor(Decl *D, CXTranslationUnit TU,
return C;
}
-CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
+CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
+ CXTranslationUnit TU,
SourceRange RegionOfInterest) {
assert(S && TU && "Invalid arguments!");
CXCursorKind K = CXCursor_NotImplemented;
@@ -493,34 +494,32 @@ CXCursor cxcursor::MakeCursorObjCSuperClassRef(ObjCInterfaceDecl *Super,
SourceLocation Loc,
CXTranslationUnit TU) {
assert(Super && TU && "Invalid arguments!");
- void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
+ void *RawLoc = Loc.getPtrEncoding();
CXCursor C = { CXCursor_ObjCSuperClassRef, 0, { Super, RawLoc, TU } };
return C;
}
-std::pair<ObjCInterfaceDecl *, SourceLocation>
+std::pair<const ObjCInterfaceDecl *, SourceLocation>
cxcursor::getCursorObjCSuperClassRef(CXCursor C) {
assert(C.kind == CXCursor_ObjCSuperClassRef);
- return std::make_pair(static_cast<ObjCInterfaceDecl *>(C.data[0]),
- SourceLocation::getFromRawEncoding(
- reinterpret_cast<uintptr_t>(C.data[1])));
+ return std::make_pair(static_cast<const ObjCInterfaceDecl *>(C.data[0]),
+ SourceLocation::getFromPtrEncoding(C.data[1]));
}
CXCursor cxcursor::MakeCursorObjCProtocolRef(const ObjCProtocolDecl *Proto,
SourceLocation Loc,
CXTranslationUnit TU) {
assert(Proto && TU && "Invalid arguments!");
- void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_ObjCProtocolRef, 0, { (void*)Proto, RawLoc, TU } };
+ void *RawLoc = Loc.getPtrEncoding();
+ CXCursor C = { CXCursor_ObjCProtocolRef, 0, { Proto, RawLoc, TU } };
return C;
}
-std::pair<ObjCProtocolDecl *, SourceLocation>
+std::pair<const ObjCProtocolDecl *, SourceLocation>
cxcursor::getCursorObjCProtocolRef(CXCursor C) {
assert(C.kind == CXCursor_ObjCProtocolRef);
- return std::make_pair(static_cast<ObjCProtocolDecl *>(C.data[0]),
- SourceLocation::getFromRawEncoding(
- reinterpret_cast<uintptr_t>(C.data[1])));
+ return std::make_pair(static_cast<const ObjCProtocolDecl *>(C.data[0]),
+ SourceLocation::getFromPtrEncoding(C.data[1]));
}
CXCursor cxcursor::MakeCursorObjCClassRef(const ObjCInterfaceDecl *Class,
@@ -530,50 +529,47 @@ CXCursor cxcursor::MakeCursorObjCClassRef(const ObjCInterfaceDecl *Class,
if (!Class)
return MakeCXCursorInvalid(CXCursor_InvalidCode);
assert(TU && "Invalid arguments!");
- void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_ObjCClassRef, 0, { (void*)Class, RawLoc, TU } };
+ void *RawLoc = Loc.getPtrEncoding();
+ CXCursor C = { CXCursor_ObjCClassRef, 0, { Class, RawLoc, TU } };
return C;
}
-std::pair<ObjCInterfaceDecl *, SourceLocation>
+std::pair<const ObjCInterfaceDecl *, SourceLocation>
cxcursor::getCursorObjCClassRef(CXCursor C) {
assert(C.kind == CXCursor_ObjCClassRef);
- return std::make_pair(static_cast<ObjCInterfaceDecl *>(C.data[0]),
- SourceLocation::getFromRawEncoding(
- reinterpret_cast<uintptr_t>(C.data[1])));
+ return std::make_pair(static_cast<const ObjCInterfaceDecl *>(C.data[0]),
+ SourceLocation::getFromPtrEncoding(C.data[1]));
}
CXCursor cxcursor::MakeCursorTypeRef(const TypeDecl *Type, SourceLocation Loc,
CXTranslationUnit TU) {
assert(Type && TU && "Invalid arguments!");
- void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_TypeRef, 0, { (void*)Type, RawLoc, TU } };
+ void *RawLoc = Loc.getPtrEncoding();
+ CXCursor C = { CXCursor_TypeRef, 0, { Type, RawLoc, TU } };
return C;
}
-std::pair<TypeDecl *, SourceLocation>
+std::pair<const TypeDecl *, SourceLocation>
cxcursor::getCursorTypeRef(CXCursor C) {
assert(C.kind == CXCursor_TypeRef);
- return std::make_pair(static_cast<TypeDecl *>(C.data[0]),
- SourceLocation::getFromRawEncoding(
- reinterpret_cast<uintptr_t>(C.data[1])));
+ return std::make_pair(static_cast<const TypeDecl *>(C.data[0]),
+ SourceLocation::getFromPtrEncoding(C.data[1]));
}
CXCursor cxcursor::MakeCursorTemplateRef(const TemplateDecl *Template,
SourceLocation Loc,
CXTranslationUnit TU) {
assert(Template && TU && "Invalid arguments!");
- void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_TemplateRef, 0, { (void*)Template, RawLoc, TU } };
+ void *RawLoc = Loc.getPtrEncoding();
+ CXCursor C = { CXCursor_TemplateRef, 0, { Template, RawLoc, TU } };
return C;
}
-std::pair<TemplateDecl *, SourceLocation>
+std::pair<const TemplateDecl *, SourceLocation>
cxcursor::getCursorTemplateRef(CXCursor C) {
assert(C.kind == CXCursor_TemplateRef);
- return std::make_pair(static_cast<TemplateDecl *>(C.data[0]),
- SourceLocation::getFromRawEncoding(
- reinterpret_cast<uintptr_t>(C.data[1])));
+ return std::make_pair(static_cast<const TemplateDecl *>(C.data[0]),
+ SourceLocation::getFromPtrEncoding(C.data[1]));
}
CXCursor cxcursor::MakeCursorNamespaceRef(const NamedDecl *NS,
@@ -582,69 +578,66 @@ CXCursor cxcursor::MakeCursorNamespaceRef(const NamedDecl *NS,
assert(NS && (isa<NamespaceDecl>(NS) || isa<NamespaceAliasDecl>(NS)) && TU &&
"Invalid arguments!");
- void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_NamespaceRef, 0, { (void*)NS, RawLoc, TU } };
+ void *RawLoc = Loc.getPtrEncoding();
+ CXCursor C = { CXCursor_NamespaceRef, 0, { NS, RawLoc, TU } };
return C;
}
-std::pair<NamedDecl *, SourceLocation>
+std::pair<const NamedDecl *, SourceLocation>
cxcursor::getCursorNamespaceRef(CXCursor C) {
assert(C.kind == CXCursor_NamespaceRef);
- return std::make_pair(static_cast<NamedDecl *>(C.data[0]),
- SourceLocation::getFromRawEncoding(
- reinterpret_cast<uintptr_t>(C.data[1])));
+ return std::make_pair(static_cast<const NamedDecl *>(C.data[0]),
+ SourceLocation::getFromPtrEncoding(C.data[1]));
}
CXCursor cxcursor::MakeCursorVariableRef(const VarDecl *Var, SourceLocation Loc,
CXTranslationUnit TU) {
assert(Var && TU && "Invalid arguments!");
- void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_VariableRef, 0, { (void*)Var, RawLoc, TU } };
+ void *RawLoc = Loc.getPtrEncoding();
+ CXCursor C = { CXCursor_VariableRef, 0, { Var, RawLoc, TU } };
return C;
}
-std::pair<VarDecl *, SourceLocation>
+std::pair<const VarDecl *, SourceLocation>
cxcursor::getCursorVariableRef(CXCursor C) {
assert(C.kind == CXCursor_VariableRef);
- return std::make_pair(static_cast<VarDecl *>(C.data[0]),
- SourceLocation::getFromRawEncoding(
- reinterpret_cast<uintptr_t>(C.data[1])));
+ return std::make_pair(static_cast<const VarDecl *>(C.data[0]),
+ SourceLocation::getFromPtrEncoding(C.data[1]));
}
CXCursor cxcursor::MakeCursorMemberRef(const FieldDecl *Field, SourceLocation Loc,
CXTranslationUnit TU) {
assert(Field && TU && "Invalid arguments!");
- void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_MemberRef, 0, { (void*)Field, RawLoc, TU } };
+ void *RawLoc = Loc.getPtrEncoding();
+ CXCursor C = { CXCursor_MemberRef, 0, { Field, RawLoc, TU } };
return C;
}
-std::pair<FieldDecl *, SourceLocation>
+std::pair<const FieldDecl *, SourceLocation>
cxcursor::getCursorMemberRef(CXCursor C) {
assert(C.kind == CXCursor_MemberRef);
- return std::make_pair(static_cast<FieldDecl *>(C.data[0]),
- SourceLocation::getFromRawEncoding(
- reinterpret_cast<uintptr_t>(C.data[1])));
+ return std::make_pair(static_cast<const FieldDecl *>(C.data[0]),
+ SourceLocation::getFromPtrEncoding(C.data[1]));
}
CXCursor cxcursor::MakeCursorCXXBaseSpecifier(const CXXBaseSpecifier *B,
CXTranslationUnit TU){
- CXCursor C = { CXCursor_CXXBaseSpecifier, 0, { (void*)B, 0, TU } };
+ CXCursor C = { CXCursor_CXXBaseSpecifier, 0, { B, 0, TU } };
return C;
}
-CXXBaseSpecifier *cxcursor::getCursorCXXBaseSpecifier(CXCursor C) {
+const CXXBaseSpecifier *cxcursor::getCursorCXXBaseSpecifier(CXCursor C) {
assert(C.kind == CXCursor_CXXBaseSpecifier);
- return static_cast<CXXBaseSpecifier*>(C.data[0]);
+ return static_cast<const CXXBaseSpecifier*>(C.data[0]);
}
CXCursor cxcursor::MakePreprocessingDirectiveCursor(SourceRange Range,
CXTranslationUnit TU) {
CXCursor C = { CXCursor_PreprocessingDirective, 0,
- { reinterpret_cast<void *>(Range.getBegin().getRawEncoding()),
- reinterpret_cast<void *>(Range.getEnd().getRawEncoding()),
+ { Range.getBegin().getPtrEncoding(),
+ Range.getEnd().getPtrEncoding(),
TU }
};
return C;
@@ -652,23 +645,21 @@ CXCursor cxcursor::MakePreprocessingDirectiveCursor(SourceRange Range,
SourceRange cxcursor::getCursorPreprocessingDirective(CXCursor C) {
assert(C.kind == CXCursor_PreprocessingDirective);
- SourceRange Range = SourceRange(SourceLocation::getFromRawEncoding(
- reinterpret_cast<uintptr_t> (C.data[0])),
- SourceLocation::getFromRawEncoding(
- reinterpret_cast<uintptr_t> (C.data[1])));
+ SourceRange Range(SourceLocation::getFromPtrEncoding(C.data[0]),
+ SourceLocation::getFromPtrEncoding(C.data[1]));
ASTUnit *TU = getCursorASTUnit(C);
return TU->mapRangeFromPreamble(Range);
}
-CXCursor cxcursor::MakeMacroDefinitionCursor(MacroDefinition *MI,
+CXCursor cxcursor::MakeMacroDefinitionCursor(const MacroDefinition *MI,
CXTranslationUnit TU) {
CXCursor C = { CXCursor_MacroDefinition, 0, { MI, 0, TU } };
return C;
}
-MacroDefinition *cxcursor::getCursorMacroDefinition(CXCursor C) {
+const MacroDefinition *cxcursor::getCursorMacroDefinition(CXCursor C) {
assert(C.kind == CXCursor_MacroDefinition);
- return static_cast<MacroDefinition *>(C.data[0]);
+ return static_cast<const MacroDefinition *>(C.data[0]);
}
CXCursor cxcursor::MakeMacroExpansionCursor(MacroExpansion *MI,
@@ -677,9 +668,28 @@ CXCursor cxcursor::MakeMacroExpansionCursor(MacroExpansion *MI,
return C;
}
-MacroExpansion *cxcursor::getCursorMacroExpansion(CXCursor C) {
- assert(C.kind == CXCursor_MacroExpansion);
- return static_cast<MacroExpansion *>(C.data[0]);
+CXCursor cxcursor::MakeMacroExpansionCursor(MacroDefinition *MI,
+ SourceLocation Loc,
+ CXTranslationUnit TU) {
+ assert(Loc.isValid());
+ CXCursor C = { CXCursor_MacroExpansion, 0, { MI, Loc.getPtrEncoding(), TU } };
+ return C;
+}
+
+const IdentifierInfo *cxcursor::MacroExpansionCursor::getName() const {
+ if (isPseudo())
+ return getAsMacroDefinition()->getName();
+ return getAsMacroExpansion()->getName();
+}
+const MacroDefinition *cxcursor::MacroExpansionCursor::getDefinition() const {
+ if (isPseudo())
+ return getAsMacroDefinition();
+ return getAsMacroExpansion()->getDefinition();
+}
+SourceRange cxcursor::MacroExpansionCursor::getSourceRange() const {
+ if (isPseudo())
+ return getPseudoLoc();
+ return getAsMacroExpansion()->getSourceRange();
}
CXCursor cxcursor::MakeInclusionDirectiveCursor(InclusionDirective *ID,
@@ -688,33 +698,32 @@ CXCursor cxcursor::MakeInclusionDirectiveCursor(InclusionDirective *ID,
return C;
}
-InclusionDirective *cxcursor::getCursorInclusionDirective(CXCursor C) {
+const InclusionDirective *cxcursor::getCursorInclusionDirective(CXCursor C) {
assert(C.kind == CXCursor_InclusionDirective);
- return static_cast<InclusionDirective *>(C.data[0]);
+ return static_cast<const InclusionDirective *>(C.data[0]);
}
CXCursor cxcursor::MakeCursorLabelRef(LabelStmt *Label, SourceLocation Loc,
CXTranslationUnit TU) {
assert(Label && TU && "Invalid arguments!");
- void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
+ void *RawLoc = Loc.getPtrEncoding();
CXCursor C = { CXCursor_LabelRef, 0, { Label, RawLoc, TU } };
return C;
}
-std::pair<LabelStmt*, SourceLocation>
+std::pair<const LabelStmt *, SourceLocation>
cxcursor::getCursorLabelRef(CXCursor C) {
assert(C.kind == CXCursor_LabelRef);
- return std::make_pair(static_cast<LabelStmt *>(C.data[0]),
- SourceLocation::getFromRawEncoding(
- reinterpret_cast<uintptr_t>(C.data[1])));
+ return std::make_pair(static_cast<const LabelStmt *>(C.data[0]),
+ SourceLocation::getFromPtrEncoding(C.data[1]));
}
-CXCursor cxcursor::MakeCursorOverloadedDeclRef(OverloadExpr *E,
+CXCursor cxcursor::MakeCursorOverloadedDeclRef(const OverloadExpr *E,
CXTranslationUnit TU) {
assert(E && TU && "Invalid arguments!");
OverloadedDeclRefStorage Storage(E);
- void *RawLoc = reinterpret_cast<void *>(E->getNameLoc().getRawEncoding());
+ void *RawLoc = E->getNameLoc().getPtrEncoding();
CXCursor C = {
CXCursor_OverloadedDeclRef, 0,
{ Storage.getOpaqueValue(), RawLoc, TU }
@@ -722,11 +731,11 @@ CXCursor cxcursor::MakeCursorOverloadedDeclRef(OverloadExpr *E,
return C;
}
-CXCursor cxcursor::MakeCursorOverloadedDeclRef(Decl *D,
+CXCursor cxcursor::MakeCursorOverloadedDeclRef(const Decl *D,
SourceLocation Loc,
CXTranslationUnit TU) {
assert(D && TU && "Invalid arguments!");
- void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
+ void *RawLoc = Loc.getPtrEncoding();
OverloadedDeclRefStorage Storage(D);
CXCursor C = {
CXCursor_OverloadedDeclRef, 0,
@@ -739,7 +748,7 @@ CXCursor cxcursor::MakeCursorOverloadedDeclRef(TemplateName Name,
SourceLocation Loc,
CXTranslationUnit TU) {
assert(Name.getAsOverloadedTemplate() && TU && "Invalid arguments!");
- void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
+ void *RawLoc = Loc.getPtrEncoding();
OverloadedDeclRefStorage Storage(Name.getAsOverloadedTemplate());
CXCursor C = {
CXCursor_OverloadedDeclRef, 0,
@@ -751,34 +760,34 @@ CXCursor cxcursor::MakeCursorOverloadedDeclRef(TemplateName Name,
std::pair<cxcursor::OverloadedDeclRefStorage, SourceLocation>
cxcursor::getCursorOverloadedDeclRef(CXCursor C) {
assert(C.kind == CXCursor_OverloadedDeclRef);
- return std::make_pair(OverloadedDeclRefStorage::getFromOpaqueValue(C.data[0]),
- SourceLocation::getFromRawEncoding(
- reinterpret_cast<uintptr_t>(C.data[1])));
+ return std::make_pair(OverloadedDeclRefStorage::getFromOpaqueValue(
+ const_cast<void *>(C.data[0])),
+ SourceLocation::getFromPtrEncoding(C.data[1]));
}
-Decl *cxcursor::getCursorDecl(CXCursor Cursor) {
- return (Decl *)Cursor.data[0];
+const Decl *cxcursor::getCursorDecl(CXCursor Cursor) {
+ return static_cast<const Decl *>(Cursor.data[0]);
}
-Expr *cxcursor::getCursorExpr(CXCursor Cursor) {
+const Expr *cxcursor::getCursorExpr(CXCursor Cursor) {
return dyn_cast_or_null<Expr>(getCursorStmt(Cursor));
}
-Stmt *cxcursor::getCursorStmt(CXCursor Cursor) {
+const Stmt *cxcursor::getCursorStmt(CXCursor Cursor) {
if (Cursor.kind == CXCursor_ObjCSuperClassRef ||
Cursor.kind == CXCursor_ObjCProtocolRef ||
Cursor.kind == CXCursor_ObjCClassRef)
return 0;
- return (Stmt *)Cursor.data[1];
+ return static_cast<const Stmt *>(Cursor.data[1]);
}
-Attr *cxcursor::getCursorAttr(CXCursor Cursor) {
- return (Attr *)Cursor.data[1];
+const Attr *cxcursor::getCursorAttr(CXCursor Cursor) {
+ return static_cast<const Attr *>(Cursor.data[1]);
}
-Decl *cxcursor::getCursorParentDecl(CXCursor Cursor) {
- return (Decl *)Cursor.data[0];
+const Decl *cxcursor::getCursorParentDecl(CXCursor Cursor) {
+ return static_cast<const Decl *>(Cursor.data[0]);
}
ASTContext &cxcursor::getCursorContext(CXCursor Cursor) {
@@ -786,14 +795,14 @@ ASTContext &cxcursor::getCursorContext(CXCursor Cursor) {
}
ASTUnit *cxcursor::getCursorASTUnit(CXCursor Cursor) {
- CXTranslationUnit TU = static_cast<CXTranslationUnit>(Cursor.data[2]);
+ CXTranslationUnit TU = getCursorTU(Cursor);
if (!TU)
return 0;
- return static_cast<ASTUnit *>(TU->TUData);
+ return cxtu::getASTUnit(TU);
}
CXTranslationUnit cxcursor::getCursorTU(CXCursor Cursor) {
- return static_cast<CXTranslationUnit>(Cursor.data[2]);
+ return static_cast<CXTranslationUnit>(const_cast<void*>(Cursor.data[2]));
}
void cxcursor::getOverriddenCursors(CXCursor cursor,
@@ -809,7 +818,7 @@ void cxcursor::getOverriddenCursors(CXCursor cursor,
for (SmallVector<const NamedDecl *, 8>::iterator
I = OverDecls.begin(), E = OverDecls.end(); I != E; ++I) {
- overridden.push_back(MakeCXCursor(const_cast<NamedDecl*>(*I), TU));
+ overridden.push_back(MakeCXCursor(*I, TU));
}
}
@@ -861,12 +870,13 @@ CXCursor cxcursor::getTypeRefCursor(CXCursor cursor) {
if (cursor.xdata == 0)
return cursor;
- Expr *E = getCursorExpr(cursor);
+ const Expr *E = getCursorExpr(cursor);
TypeSourceInfo *Type = 0;
- if (CXXUnresolvedConstructExpr *
+ if (const CXXUnresolvedConstructExpr *
UnCtor = dyn_cast<CXXUnresolvedConstructExpr>(E)) {
Type = UnCtor->getTypeSourceInfo();
- } else if (CXXTemporaryObjectExpr *Tmp = dyn_cast<CXXTemporaryObjectExpr>(E)){
+ } else if (const CXXTemporaryObjectExpr *Tmp =
+ dyn_cast<CXXTemporaryObjectExpr>(E)){
Type = Tmp->getTypeSourceInfo();
}
@@ -880,7 +890,7 @@ CXCursor cxcursor::getTypeRefCursor(CXCursor cursor) {
if (const ElaboratedType *ElabT = Ty->getAs<ElaboratedType>()) {
Ty = ElabT->getNamedType();
- ElaboratedTypeLoc ElabTL = cast<ElaboratedTypeLoc>(TL);
+ ElaboratedTypeLoc ElabTL = TL.castAs<ElaboratedTypeLoc>();
Loc = ElabTL.getNamedTypeLoc().getBeginLoc();
}
@@ -922,30 +932,48 @@ CXTranslationUnit clang_Cursor_getTranslationUnit(CXCursor cursor) {
int clang_Cursor_getNumArguments(CXCursor C) {
if (clang_isDeclaration(C.kind)) {
- Decl *D = cxcursor::getCursorDecl(C);
+ const Decl *D = cxcursor::getCursorDecl(C);
if (const ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D))
return MD->param_size();
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
return FD->param_size();
}
+ if (clang_isExpression(C.kind)) {
+ const Expr *E = cxcursor::getCursorExpr(C);
+ if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
+ return CE->getNumArgs();
+ }
+ }
+
return -1;
}
CXCursor clang_Cursor_getArgument(CXCursor C, unsigned i) {
if (clang_isDeclaration(C.kind)) {
- Decl *D = cxcursor::getCursorDecl(C);
- if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D)) {
+ const Decl *D = cxcursor::getCursorDecl(C);
+ if (const ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D)) {
if (i < MD->param_size())
return cxcursor::MakeCXCursor(MD->param_begin()[i],
cxcursor::getCursorTU(C));
- } else if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
+ } else if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
if (i < FD->param_size())
return cxcursor::MakeCXCursor(FD->param_begin()[i],
cxcursor::getCursorTU(C));
}
}
+ if (clang_isExpression(C.kind)) {
+ const Expr *E = cxcursor::getCursorExpr(C);
+ if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
+ if (i < CE->getNumArgs()) {
+ return cxcursor::MakeCXCursor(CE->getArg(i),
+ getCursorDecl(C),
+ cxcursor::getCursorTU(C));
+ }
+ }
+ }
+
return clang_getNullCursor();
}
@@ -973,7 +1001,7 @@ public:
return MakeCXCursorInvalid(CXCursor_NoDeclFound);
}
static inline unsigned getHashValue(const CXCursor &cursor) {
- return llvm::DenseMapInfo<std::pair<void*,void*> >
+ return llvm::DenseMapInfo<std::pair<const void *, const void *> >
::getHashValue(std::make_pair(cursor.data[0], cursor.data[1]));
}
static inline bool isEqual(const CXCursor &x, const CXCursor &y) {
@@ -1018,10 +1046,10 @@ unsigned clang_CXCursorSet_insert(CXCursorSet set, CXCursor cursor) {
CXCompletionString clang_getCursorCompletionString(CXCursor cursor) {
enum CXCursorKind kind = clang_getCursorKind(cursor);
if (clang_isDeclaration(kind)) {
- Decl *decl = getCursorDecl(cursor);
- if (NamedDecl *namedDecl = dyn_cast_or_null<NamedDecl>(decl)) {
+ const Decl *decl = getCursorDecl(cursor);
+ if (const NamedDecl *namedDecl = dyn_cast_or_null<NamedDecl>(decl)) {
ASTUnit *unit = getCursorASTUnit(cursor);
- CodeCompletionResult Result(namedDecl);
+ CodeCompletionResult Result(namedDecl, CCP_Declaration);
CodeCompletionString *String
= Result.CreateCodeCompletionString(unit->getASTContext(),
unit->getPreprocessor(),
@@ -1032,10 +1060,10 @@ CXCompletionString clang_getCursorCompletionString(CXCursor cursor) {
}
}
else if (kind == CXCursor_MacroDefinition) {
- MacroDefinition *definition = getCursorMacroDefinition(cursor);
+ const MacroDefinition *definition = getCursorMacroDefinition(cursor);
const IdentifierInfo *MacroInfo = definition->getName();
ASTUnit *unit = getCursorASTUnit(cursor);
- CodeCompletionResult Result(const_cast<IdentifierInfo *>(MacroInfo));
+ CodeCompletionResult Result(MacroInfo);
CodeCompletionString *String
= Result.CreateCodeCompletionString(unit->getASTContext(),
unit->getPreprocessor(),
@@ -1050,7 +1078,7 @@ CXCompletionString clang_getCursorCompletionString(CXCursor cursor) {
namespace {
struct OverridenCursorsPool {
- typedef llvm::SmallVector<CXCursor, 2> CursorVec;
+ typedef SmallVector<CXCursor, 2> CursorVec;
std::vector<CursorVec*> AllCursors;
std::vector<CursorVec*> AvailableCursors;
@@ -1137,7 +1165,8 @@ void clang_disposeOverriddenCursors(CXCursor *overridden) {
// which has a back-reference to the TU and the vector.
--overridden;
OverridenCursorsPool::CursorVec *Vec =
- static_cast<OverridenCursorsPool::CursorVec*>(overridden->data[0]);
+ static_cast<OverridenCursorsPool::CursorVec *>(
+ const_cast<void *>(overridden->data[0]));
CXTranslationUnit TU = getCursorTU(*overridden);
assert(Vec && TU);
diff --git a/tools/libclang/CXCursor.h b/tools/libclang/CXCursor.h
index 120b881..957d519 100644
--- a/tools/libclang/CXCursor.h
+++ b/tools/libclang/CXCursor.h
@@ -42,17 +42,18 @@ class TemplateDecl;
class TemplateName;
class TypeDecl;
class VarDecl;
+class IdentifierInfo;
namespace cxcursor {
CXCursor getCursor(CXTranslationUnit, SourceLocation);
-CXCursor MakeCXCursor(const clang::Attr *A, clang::Decl *Parent,
+CXCursor MakeCXCursor(const clang::Attr *A, const clang::Decl *Parent,
CXTranslationUnit TU);
-CXCursor MakeCXCursor(clang::Decl *D, CXTranslationUnit TU,
+CXCursor MakeCXCursor(const clang::Decl *D, CXTranslationUnit TU,
SourceRange RegionOfInterest = SourceRange(),
bool FirstInDeclGroup = true);
-CXCursor MakeCXCursor(clang::Stmt *S, clang::Decl *Parent,
+CXCursor MakeCXCursor(const clang::Stmt *S, const clang::Decl *Parent,
CXTranslationUnit TU,
SourceRange RegionOfInterest = SourceRange());
CXCursor MakeCXCursorInvalid(CXCursorKind K, CXTranslationUnit TU = 0);
@@ -64,7 +65,7 @@ CXCursor MakeCursorObjCSuperClassRef(ObjCInterfaceDecl *Super,
/// \brief Unpack an ObjCSuperClassRef cursor into the interface it references
/// and optionally the location where the reference occurred.
-std::pair<ObjCInterfaceDecl *, SourceLocation>
+std::pair<const ObjCInterfaceDecl *, SourceLocation>
getCursorObjCSuperClassRef(CXCursor C);
/// \brief Create an Objective-C protocol reference at the given location.
@@ -74,7 +75,7 @@ CXCursor MakeCursorObjCProtocolRef(const ObjCProtocolDecl *Proto,
/// \brief Unpack an ObjCProtocolRef cursor into the protocol it references
/// and optionally the location where the reference occurred.
-std::pair<ObjCProtocolDecl *, SourceLocation>
+std::pair<const ObjCProtocolDecl *, SourceLocation>
getCursorObjCProtocolRef(CXCursor C);
/// \brief Create an Objective-C class reference at the given location.
@@ -84,7 +85,7 @@ CXCursor MakeCursorObjCClassRef(const ObjCInterfaceDecl *Class,
/// \brief Unpack an ObjCClassRef cursor into the class it references
/// and optionally the location where the reference occurred.
-std::pair<ObjCInterfaceDecl *, SourceLocation>
+std::pair<const ObjCInterfaceDecl *, SourceLocation>
getCursorObjCClassRef(CXCursor C);
/// \brief Create a type reference at the given location.
@@ -93,7 +94,7 @@ CXCursor MakeCursorTypeRef(const TypeDecl *Type, SourceLocation Loc,
/// \brief Unpack a TypeRef cursor into the class it references
/// and optionally the location where the reference occurred.
-std::pair<TypeDecl *, SourceLocation> getCursorTypeRef(CXCursor C);
+std::pair<const TypeDecl *, SourceLocation> getCursorTypeRef(CXCursor C);
/// \brief Create a reference to a template at the given location.
CXCursor MakeCursorTemplateRef(const TemplateDecl *Template, SourceLocation Loc,
@@ -101,7 +102,8 @@ CXCursor MakeCursorTemplateRef(const TemplateDecl *Template, SourceLocation Loc,
/// \brief Unpack a TemplateRef cursor into the template it references and
/// the location where the reference occurred.
-std::pair<TemplateDecl *, SourceLocation> getCursorTemplateRef(CXCursor C);
+std::pair<const TemplateDecl *, SourceLocation>
+ getCursorTemplateRef(CXCursor C);
/// \brief Create a reference to a namespace or namespace alias at the given
/// location.
@@ -110,7 +112,7 @@ CXCursor MakeCursorNamespaceRef(const NamedDecl *NS, SourceLocation Loc,
/// \brief Unpack a NamespaceRef cursor into the namespace or namespace alias
/// it references and the location where the reference occurred.
-std::pair<NamedDecl *, SourceLocation> getCursorNamespaceRef(CXCursor C);
+std::pair<const NamedDecl *, SourceLocation> getCursorNamespaceRef(CXCursor C);
/// \brief Create a reference to a variable at the given location.
CXCursor MakeCursorVariableRef(const VarDecl *Var, SourceLocation Loc,
@@ -118,7 +120,7 @@ CXCursor MakeCursorVariableRef(const VarDecl *Var, SourceLocation Loc,
/// \brief Unpack a VariableRef cursor into the variable it references and the
/// location where the where the reference occurred.
-std::pair<VarDecl *, SourceLocation> getCursorVariableRef(CXCursor C);
+std::pair<const VarDecl *, SourceLocation> getCursorVariableRef(CXCursor C);
/// \brief Create a reference to a field at the given location.
CXCursor MakeCursorMemberRef(const FieldDecl *Field, SourceLocation Loc,
@@ -126,14 +128,14 @@ CXCursor MakeCursorMemberRef(const FieldDecl *Field, SourceLocation Loc,
/// \brief Unpack a MemberRef cursor into the field it references and the
/// location where the reference occurred.
-std::pair<FieldDecl *, SourceLocation> getCursorMemberRef(CXCursor C);
+std::pair<const FieldDecl *, SourceLocation> getCursorMemberRef(CXCursor C);
/// \brief Create a CXX base specifier cursor.
CXCursor MakeCursorCXXBaseSpecifier(const CXXBaseSpecifier *B,
CXTranslationUnit TU);
/// \brief Unpack a CXXBaseSpecifier cursor into a CXXBaseSpecifier.
-CXXBaseSpecifier *getCursorCXXBaseSpecifier(CXCursor C);
+const CXXBaseSpecifier *getCursorCXXBaseSpecifier(CXCursor C);
/// \brief Create a preprocessing directive cursor.
CXCursor MakePreprocessingDirectiveCursor(SourceRange Range,
@@ -143,19 +145,62 @@ CXCursor MakePreprocessingDirectiveCursor(SourceRange Range,
SourceRange getCursorPreprocessingDirective(CXCursor C);
/// \brief Create a macro definition cursor.
-CXCursor MakeMacroDefinitionCursor(MacroDefinition *, CXTranslationUnit TU);
+CXCursor MakeMacroDefinitionCursor(const MacroDefinition *,
+ CXTranslationUnit TU);
/// \brief Unpack a given macro definition cursor to retrieve its
/// source range.
-MacroDefinition *getCursorMacroDefinition(CXCursor C);
+const MacroDefinition *getCursorMacroDefinition(CXCursor C);
/// \brief Create a macro expansion cursor.
CXCursor MakeMacroExpansionCursor(MacroExpansion *,
CXTranslationUnit TU);
-/// \brief Unpack a given macro expansion cursor to retrieve its
-/// source range.
-MacroExpansion *getCursorMacroExpansion(CXCursor C);
+/// \brief Create a "pseudo" macro expansion cursor, using a macro definition
+/// and a source location.
+CXCursor MakeMacroExpansionCursor(MacroDefinition *, SourceLocation Loc,
+ CXTranslationUnit TU);
+
+/// \brief Wraps a macro expansion cursor and provides a common interface
+/// for a normal macro expansion cursor or a "pseudo" one.
+///
+/// "Pseudo" macro expansion cursors (essentially a macro definition along with
+/// a source location) are created in special cases, for example they can be
+/// created for identifiers inside macro definitions, if these identifiers are
+/// macro names.
+class MacroExpansionCursor {
+ CXCursor C;
+
+ bool isPseudo() const {
+ return C.data[1] != 0;
+ }
+ const MacroDefinition *getAsMacroDefinition() const {
+ assert(isPseudo());
+ return static_cast<const MacroDefinition *>(C.data[0]);
+ }
+ const MacroExpansion *getAsMacroExpansion() const {
+ assert(!isPseudo());
+ return static_cast<const MacroExpansion *>(C.data[0]);
+ }
+ SourceLocation getPseudoLoc() const {
+ assert(isPseudo());
+ return SourceLocation::getFromPtrEncoding(C.data[1]);
+ }
+
+public:
+ MacroExpansionCursor(CXCursor C) : C(C) {
+ assert(C.kind == CXCursor_MacroExpansion);
+ }
+
+ const IdentifierInfo *getName() const;
+ const MacroDefinition *getDefinition() const;
+ SourceRange getSourceRange() const;
+};
+
+/// \brief Unpack a given macro expansion cursor to retrieve its info.
+static inline MacroExpansionCursor getCursorMacroExpansion(CXCursor C) {
+ return C;
+}
/// \brief Create an inclusion directive cursor.
CXCursor MakeInclusionDirectiveCursor(InclusionDirective *,
@@ -163,7 +208,7 @@ CXCursor MakeInclusionDirectiveCursor(InclusionDirective *,
/// \brief Unpack a given inclusion directive cursor to retrieve its
/// source range.
-InclusionDirective *getCursorInclusionDirective(CXCursor C);
+const InclusionDirective *getCursorInclusionDirective(CXCursor C);
/// \brief Create a label reference at the given location.
CXCursor MakeCursorLabelRef(LabelStmt *Label, SourceLocation Loc,
@@ -171,13 +216,14 @@ CXCursor MakeCursorLabelRef(LabelStmt *Label, SourceLocation Loc,
/// \brief Unpack a label reference into the label statement it refers to and
/// the location of the reference.
-std::pair<LabelStmt *, SourceLocation> getCursorLabelRef(CXCursor C);
+std::pair<const LabelStmt *, SourceLocation> getCursorLabelRef(CXCursor C);
/// \brief Create a overloaded declaration reference cursor for an expression.
-CXCursor MakeCursorOverloadedDeclRef(OverloadExpr *E, CXTranslationUnit TU);
+CXCursor MakeCursorOverloadedDeclRef(const OverloadExpr *E,
+ CXTranslationUnit TU);
/// \brief Create a overloaded declaration reference cursor for a declaration.
-CXCursor MakeCursorOverloadedDeclRef(Decl *D, SourceLocation Location,
+CXCursor MakeCursorOverloadedDeclRef(const Decl *D, SourceLocation Location,
CXTranslationUnit TU);
/// \brief Create a overloaded declaration reference cursor for a template name.
@@ -186,7 +232,7 @@ CXCursor MakeCursorOverloadedDeclRef(TemplateName Template,
CXTranslationUnit TU);
/// \brief Internal storage for an overloaded declaration reference cursor;
-typedef llvm::PointerUnion3<OverloadExpr *, Decl *,
+typedef llvm::PointerUnion3<const OverloadExpr *, const Decl *,
OverloadedTemplateStorage *>
OverloadedDeclRefStorage;
@@ -195,11 +241,11 @@ typedef llvm::PointerUnion3<OverloadExpr *, Decl *,
std::pair<OverloadedDeclRefStorage, SourceLocation>
getCursorOverloadedDeclRef(CXCursor C);
-Decl *getCursorDecl(CXCursor Cursor);
-Expr *getCursorExpr(CXCursor Cursor);
-Stmt *getCursorStmt(CXCursor Cursor);
-Attr *getCursorAttr(CXCursor Cursor);
-Decl *getCursorParentDecl(CXCursor Cursor);
+const Decl *getCursorDecl(CXCursor Cursor);
+const Expr *getCursorExpr(CXCursor Cursor);
+const Stmt *getCursorStmt(CXCursor Cursor);
+const Attr *getCursorAttr(CXCursor Cursor);
+const Decl *getCursorParentDecl(CXCursor Cursor);
ASTContext &getCursorContext(CXCursor Cursor);
ASTUnit *getCursorASTUnit(CXCursor Cursor);
diff --git a/tools/libclang/CXLoadedDiagnostic.cpp b/tools/libclang/CXLoadedDiagnostic.cpp
index e5b6ccc..b02fdd6 100644
--- a/tools/libclang/CXLoadedDiagnostic.cpp
+++ b/tools/libclang/CXLoadedDiagnostic.cpp
@@ -1,15 +1,15 @@
-/*===-- CXLoadedDiagnostic.cpp - Handling of persisent diags -*- C++ -*-===*\
-|* *|
-|* The LLVM Compiler Infrastructure *|
-|* *|
-|* This file is distributed under the University of Illinois Open Source *|
-|* License. See LICENSE.TXT for details. *|
-|* *|
-|*===----------------------------------------------------------------------===*|
-|* *|
-|* Implements handling of persisent diagnostics. *|
-|* *|
-\*===----------------------------------------------------------------------===*/
+//===-- CXLoadedDiagnostic.cpp - Handling of persisent diags ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements handling of persisent diagnostics.
+//
+//===----------------------------------------------------------------------===//
#include "CXLoadedDiagnostic.h"
#include "CXString.h"
@@ -23,16 +23,13 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Bitcode/BitstreamReader.h"
#include "llvm/Support/MemoryBuffer.h"
-#include <assert.h>
-
using namespace clang;
-using namespace clang::cxstring;
//===----------------------------------------------------------------------===//
// Extend CXDiagnosticSetImpl which contains strings for diagnostics.
//===----------------------------------------------------------------------===//
-typedef llvm::DenseMap<unsigned, llvm::StringRef> Strings;
+typedef llvm::DenseMap<unsigned, const char *> Strings;
namespace {
class CXLoadedDiagnosticSetImpl : public CXDiagnosticSetImpl {
@@ -40,8 +37,6 @@ public:
CXLoadedDiagnosticSetImpl() : CXDiagnosticSetImpl(true), FakeFiles(FO) {}
virtual ~CXLoadedDiagnosticSetImpl() {}
- llvm::StringRef makeString(const char *blob, unsigned blobLen);
-
llvm::BumpPtrAllocator Alloc;
Strings Categories;
Strings WarningFlags;
@@ -50,17 +45,15 @@ public:
FileSystemOptions FO;
FileManager FakeFiles;
llvm::DenseMap<unsigned, const FileEntry *> Files;
-};
-}
-llvm::StringRef CXLoadedDiagnosticSetImpl::makeString(const char *blob,
- unsigned bloblen) {
- char *mem = Alloc.Allocate<char>(bloblen + 1);
- memcpy(mem, blob, bloblen);
- // Add a null terminator for those clients accessing the buffer
- // like a c-string.
- mem[bloblen] = '\0';
- return llvm::StringRef(mem, bloblen);
+ /// \brief Copy the string into our own allocator.
+ const char *copyString(StringRef Blob) {
+ char *mem = Alloc.Allocate<char>(Blob.size() + 1);
+ memcpy(mem, Blob.data(), Blob.size());
+ mem[Blob.size()] = '\0';
+ return mem;
+ }
+};
}
//===----------------------------------------------------------------------===//
@@ -102,17 +95,17 @@ CXSourceLocation CXLoadedDiagnostic::getLocation() const {
}
CXString CXLoadedDiagnostic::getSpelling() const {
- return cxstring::createCXString(Spelling, false);
+ return cxstring::createRef(Spelling);
}
CXString CXLoadedDiagnostic::getDiagnosticOption(CXString *Disable) const {
if (DiagOption.empty())
- return createCXString("");
+ return cxstring::createEmpty();
// FIXME: possibly refactor with logic in CXStoredDiagnostic.
if (Disable)
- *Disable = createCXString((Twine("-Wno-") + DiagOption).str());
- return createCXString((Twine("-W") + DiagOption).str());
+ *Disable = cxstring::createDup((Twine("-Wno-") + DiagOption).str());
+ return cxstring::createDup((Twine("-W") + DiagOption).str());
}
unsigned CXLoadedDiagnostic::getCategory() const {
@@ -120,7 +113,7 @@ unsigned CXLoadedDiagnostic::getCategory() const {
}
CXString CXLoadedDiagnostic::getCategoryText() const {
- return cxstring::createCXString(CategoryText);
+ return cxstring::createDup(CategoryText);
}
unsigned CXLoadedDiagnostic::getNumRanges() const {
@@ -141,7 +134,7 @@ CXString CXLoadedDiagnostic::getFixIt(unsigned FixIt,
assert(FixIt < FixIts.size());
if (ReplacementRange)
*ReplacementRange = FixIts[FixIt].first;
- return FixIts[FixIt].second;
+ return cxstring::createRef(FixIts[FixIt].second);
}
void CXLoadedDiagnostic::decodeLocation(CXSourceLocation location,
@@ -200,7 +193,7 @@ class DiagLoader {
if (error)
*error = code;
if (errorString)
- *errorString = createCXString(err);
+ *errorString = cxstring::createDup(err);
}
void reportInvalidFile(llvm::StringRef err) {
@@ -216,22 +209,20 @@ class DiagLoader {
StreamResult readToNextRecordOrBlock(llvm::BitstreamCursor &Stream,
llvm::StringRef errorContext,
unsigned &BlockOrRecordID,
- const bool atTopLevel = false);
+ bool atTopLevel = false);
LoadResult readString(CXLoadedDiagnosticSetImpl &TopDiags,
Strings &strings, llvm::StringRef errorContext,
RecordData &Record,
- const char *BlobStart,
- unsigned BlobLen,
+ StringRef Blob,
bool allowEmptyString = false);
LoadResult readString(CXLoadedDiagnosticSetImpl &TopDiags,
- llvm::StringRef &RetStr,
+ const char *&RetStr,
llvm::StringRef errorContext,
RecordData &Record,
- const char *BlobStart,
- unsigned BlobLen,
+ StringRef Blob,
bool allowEmptyString = false);
LoadResult readRange(CXLoadedDiagnosticSetImpl &TopDiags,
@@ -248,7 +239,7 @@ public:
if (error)
*error = CXLoadDiag_None;
if (errorString)
- *errorString = createCXString("");
+ *errorString = cxstring::createEmpty();
}
CXDiagnosticSet load(const char *file);
@@ -286,8 +277,7 @@ CXDiagnosticSet DiagLoader::load(const char *file) {
return 0;
}
- OwningPtr<CXLoadedDiagnosticSetImpl>
- Diags(new CXLoadedDiagnosticSetImpl());
+ OwningPtr<CXLoadedDiagnosticSetImpl> Diags(new CXLoadedDiagnosticSetImpl());
while (true) {
unsigned BlockID = 0;
@@ -328,7 +318,7 @@ CXDiagnosticSet DiagLoader::load(const char *file) {
StreamResult DiagLoader::readToNextRecordOrBlock(llvm::BitstreamCursor &Stream,
llvm::StringRef errorContext,
unsigned &blockOrRecordID,
- const bool atTopLevel) {
+ bool atTopLevel) {
blockOrRecordID = 0;
@@ -425,9 +415,7 @@ LoadResult DiagLoader::readMetaBlock(llvm::BitstreamCursor &Stream) {
}
RecordData Record;
- const char *Blob;
- unsigned BlobLen;
- unsigned recordID = Stream.ReadRecord(blockOrCode, Record, &Blob, &BlobLen);
+ unsigned recordID = Stream.readRecord(blockOrCode, Record);
if (recordID == serialized_diags::RECORD_VERSION) {
if (Record.size() < 1) {
@@ -435,7 +423,7 @@ LoadResult DiagLoader::readMetaBlock(llvm::BitstreamCursor &Stream) {
return Failure;
}
if (Record[0] > MaxSupportedVersion) {
- reportInvalidFile("diagnosics file is a newer version than the one "
+ reportInvalidFile("diagnostics file is a newer version than the one "
"supported");
return Failure;
}
@@ -445,32 +433,31 @@ LoadResult DiagLoader::readMetaBlock(llvm::BitstreamCursor &Stream) {
}
LoadResult DiagLoader::readString(CXLoadedDiagnosticSetImpl &TopDiags,
- llvm::StringRef &RetStr,
+ const char *&RetStr,
llvm::StringRef errorContext,
RecordData &Record,
- const char *BlobStart,
- unsigned BlobLen,
+ StringRef Blob,
bool allowEmptyString) {
// Basic buffer overflow check.
- if (BlobLen > 65536) {
+ if (Blob.size() > 65536) {
reportInvalidFile(std::string("Out-of-bounds string in ") +
std::string(errorContext));
return Failure;
}
- if (allowEmptyString && Record.size() >= 1 && BlobLen == 0) {
+ if (allowEmptyString && Record.size() >= 1 && Blob.size() == 0) {
RetStr = "";
return Success;
}
- if (Record.size() < 1 || BlobLen == 0) {
+ if (Record.size() < 1 || Blob.size() == 0) {
reportInvalidFile(std::string("Corrupted ") + std::string(errorContext)
+ std::string(" entry"));
return Failure;
}
- RetStr = TopDiags.makeString(BlobStart, BlobLen);
+ RetStr = TopDiags.copyString(Blob);
return Success;
}
@@ -478,11 +465,10 @@ LoadResult DiagLoader::readString(CXLoadedDiagnosticSetImpl &TopDiags,
Strings &strings,
llvm::StringRef errorContext,
RecordData &Record,
- const char *BlobStart,
- unsigned BlobLen,
+ StringRef Blob,
bool allowEmptyString) {
- llvm::StringRef RetStr;
- if (readString(TopDiags, RetStr, errorContext, Record, BlobStart, BlobLen,
+ const char *RetStr;
+ if (readString(TopDiags, RetStr, errorContext, Record, Blob,
allowEmptyString))
return Failure;
strings[Record[0]] = RetStr;
@@ -512,7 +498,7 @@ LoadResult DiagLoader::readLocation(CXLoadedDiagnosticSetImpl &TopDiags,
reportInvalidFile("Corrupted file entry in source location");
return Failure;
}
- Loc.file = (void*) FE;
+ Loc.file = const_cast<FileEntry *>(FE);
Loc.line = Record[offset++];
Loc.column = Record[offset++];
Loc.offset = Record[offset++];
@@ -582,10 +568,8 @@ LoadResult DiagLoader::readDiagnosticBlock(llvm::BitstreamCursor &Stream,
// Read the record.
Record.clear();
- const char *BlobStart = 0;
- unsigned BlobLen = 0;
- unsigned recID = Stream.ReadRecord(blockOrCode, Record,
- BlobStart, BlobLen);
+ StringRef Blob;
+ unsigned recID = Stream.readRecord(blockOrCode, Record, &Blob);
if (recID < serialized_diags::RECORD_FIRST ||
recID > serialized_diags::RECORD_LAST)
@@ -596,20 +580,19 @@ LoadResult DiagLoader::readDiagnosticBlock(llvm::BitstreamCursor &Stream,
continue;
case serialized_diags::RECORD_CATEGORY:
if (readString(TopDiags, TopDiags.Categories, "category", Record,
- BlobStart, BlobLen,
- /* allowEmptyString */ true))
+ Blob, /* allowEmptyString */ true))
return Failure;
continue;
case serialized_diags::RECORD_DIAG_FLAG:
if (readString(TopDiags, TopDiags.WarningFlags, "warning flag", Record,
- BlobStart, BlobLen))
+ Blob))
return Failure;
continue;
case serialized_diags::RECORD_FILENAME: {
if (readString(TopDiags, TopDiags.FileNames, "filename", Record,
- BlobStart, BlobLen))
+ Blob))
return Failure;
if (Record.size() < 3) {
@@ -638,11 +621,11 @@ LoadResult DiagLoader::readDiagnosticBlock(llvm::BitstreamCursor &Stream,
CXSourceRange SR;
if (readRange(TopDiags, Record, 0, SR))
return Failure;
- llvm::StringRef RetStr;
- if (readString(TopDiags, RetStr, "FIXIT", Record, BlobStart, BlobLen,
+ const char *RetStr;
+ if (readString(TopDiags, RetStr, "FIXIT", Record, Blob,
/* allowEmptyString */ true))
return Failure;
- D->FixIts.push_back(std::make_pair(SR, createCXString(RetStr, false)));
+ D->FixIts.push_back(std::make_pair(SR, RetStr));
continue;
}
@@ -655,7 +638,7 @@ LoadResult DiagLoader::readDiagnosticBlock(llvm::BitstreamCursor &Stream,
unsigned diagFlag = Record[offset++];
D->DiagOption = diagFlag ? TopDiags.WarningFlags[diagFlag] : "";
D->CategoryText = D->category ? TopDiags.Categories[D->category] : "";
- D->Spelling = TopDiags.makeString(BlobStart, BlobLen);
+ D->Spelling = TopDiags.copyString(Blob);
continue;
}
}
diff --git a/tools/libclang/CXLoadedDiagnostic.h b/tools/libclang/CXLoadedDiagnostic.h
index d4a321e..d4b11d5 100644
--- a/tools/libclang/CXLoadedDiagnostic.h
+++ b/tools/libclang/CXLoadedDiagnostic.h
@@ -82,8 +82,8 @@ public:
Location DiagLoc;
std::vector<CXSourceRange> Ranges;
- std::vector<std::pair<CXSourceRange, CXString> > FixIts;
- llvm::StringRef Spelling;
+ std::vector<std::pair<CXSourceRange, const char *> > FixIts;
+ const char *Spelling;
llvm::StringRef DiagOption;
llvm::StringRef CategoryText;
unsigned severity;
diff --git a/tools/libclang/CXSourceLocation.cpp b/tools/libclang/CXSourceLocation.cpp
index a6bf8fc..bc8d575 100644
--- a/tools/libclang/CXSourceLocation.cpp
+++ b/tools/libclang/CXSourceLocation.cpp
@@ -12,15 +12,17 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/ASTUnit.h"
-
#include "CIndexer.h"
-#include "CXString.h"
+#include "CLog.h"
+#include "CXLoadedDiagnostic.h"
#include "CXSourceLocation.h"
+#include "CXString.h"
#include "CXTranslationUnit.h"
-#include "CXLoadedDiagnostic.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Format.h"
using namespace clang;
-using namespace clang::cxstring;
+using namespace clang::cxindex;
//===----------------------------------------------------------------------===//
// Internal predicates on CXSourceLocations.
@@ -116,40 +118,41 @@ CXSourceLocation clang_getRangeEnd(CXSourceRange range) {
extern "C" {
-CXSourceLocation clang_getLocation(CXTranslationUnit tu,
+CXSourceLocation clang_getLocation(CXTranslationUnit TU,
CXFile file,
unsigned line,
unsigned column) {
- if (!tu || !file)
+ if (!TU || !file)
return clang_getNullLocation();
- bool Logging = ::getenv("LIBCLANG_LOGGING");
- ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
+ LogRef Log = Logger::make(LLVM_FUNCTION_NAME);
+ ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
ASTUnit::ConcurrencyCheck Check(*CXXUnit);
const FileEntry *File = static_cast<const FileEntry *>(file);
SourceLocation SLoc = CXXUnit->getLocation(File, line, column);
if (SLoc.isInvalid()) {
- if (Logging)
- llvm::errs() << "clang_getLocation(\"" << File->getName()
- << "\", " << line << ", " << column << ") = invalid\n";
+ if (Log)
+ *Log << llvm::format("(\"%s\", %d, %d) = invalid",
+ File->getName(), line, column);
return clang_getNullLocation();
}
- if (Logging)
- llvm::errs() << "clang_getLocation(\"" << File->getName()
- << "\", " << line << ", " << column << ") = "
- << SLoc.getRawEncoding() << "\n";
+ CXSourceLocation CXLoc =
+ cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
+ if (Log)
+ *Log << llvm::format("(\"%s\", %d, %d) = ", File->getName(), line, column)
+ << CXLoc;
- return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
+ return CXLoc;
}
-CXSourceLocation clang_getLocationForOffset(CXTranslationUnit tu,
+CXSourceLocation clang_getLocationForOffset(CXTranslationUnit TU,
CXFile file,
unsigned offset) {
- if (!tu || !file)
+ if (!TU || !file)
return clang_getNullLocation();
- ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
+ ASTUnit *CXXUnit = cxtu::getASTUnit(TU);
SourceLocation SLoc
= CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset);
@@ -183,7 +186,7 @@ static void createNullLocation(CXFile *file, unsigned *line,
static void createNullLocation(CXString *filename, unsigned *line,
unsigned *column, unsigned *offset = 0) {
if (filename)
- *filename = createCXString("");
+ *filename = cxstring::createEmpty();
if (line)
*line = 0;
if (column)
@@ -228,7 +231,7 @@ void clang_getExpansionLocation(CXSourceLocation location,
}
if (file)
- *file = (void *)SM.getFileEntryForSLocEntry(sloc);
+ *file = const_cast<FileEntry *>(SM.getFileEntryForSLocEntry(sloc));
if (line)
*line = SM.getExpansionLineNumber(ExpansionLoc);
if (column)
@@ -259,7 +262,7 @@ void clang_getPresumedLocation(CXSourceLocation location,
PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
if (filename)
- *filename = createCXString(PreLoc.getFilename());
+ *filename = cxstring::createRef(PreLoc.getFilename());
if (line)
*line = PreLoc.getLine();
if (column)
@@ -295,16 +298,8 @@ void clang_getSpellingLocation(CXSourceLocation location,
const SourceManager &SM =
*static_cast<const SourceManager*>(location.ptr_data[0]);
- SourceLocation SpellLoc = Loc;
- if (SpellLoc.isMacroID()) {
- SourceLocation SimpleSpellingLoc = SM.getImmediateSpellingLoc(SpellLoc);
- if (SimpleSpellingLoc.isFileID() &&
- SM.getFileEntryForID(SM.getDecomposedLoc(SimpleSpellingLoc).first))
- SpellLoc = SimpleSpellingLoc;
- else
- SpellLoc = SM.getExpansionLoc(SpellLoc);
- }
-
+ // FIXME: This should call SourceManager::getSpellingLoc().
+ SourceLocation SpellLoc = SM.getFileLoc(Loc);
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
FileID FID = LocInfo.first;
unsigned FileOffset = LocInfo.second;
@@ -313,7 +308,7 @@ void clang_getSpellingLocation(CXSourceLocation location,
return createNullLocation(file, line, column, offset);
if (file)
- *file = (void *)SM.getFileEntryForID(FID);
+ *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
if (line)
*line = SM.getLineNumber(FID, FileOffset);
if (column)
@@ -322,5 +317,41 @@ void clang_getSpellingLocation(CXSourceLocation location,
*offset = FileOffset;
}
-} // end extern "C"
+void clang_getFileLocation(CXSourceLocation location,
+ CXFile *file,
+ unsigned *line,
+ unsigned *column,
+ unsigned *offset) {
+
+ if (!isASTUnitSourceLocation(location)) {
+ CXLoadedDiagnostic::decodeLocation(location, file, line,
+ column, offset);
+ return;
+ }
+
+ SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
+
+ if (!location.ptr_data[0] || Loc.isInvalid())
+ return createNullLocation(file, line, column, offset);
+
+ const SourceManager &SM =
+ *static_cast<const SourceManager*>(location.ptr_data[0]);
+ SourceLocation FileLoc = SM.getFileLoc(Loc);
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(FileLoc);
+ FileID FID = LocInfo.first;
+ unsigned FileOffset = LocInfo.second;
+ if (FID.isInvalid())
+ return createNullLocation(file, line, column, offset);
+
+ if (file)
+ *file = const_cast<FileEntry *>(SM.getFileEntryForID(FID));
+ if (line)
+ *line = SM.getLineNumber(FID, FileOffset);
+ if (column)
+ *column = SM.getColumnNumber(FID, FileOffset);
+ if (offset)
+ *offset = FileOffset;
+}
+
+} // end extern "C"
diff --git a/tools/libclang/CXSourceLocation.h b/tools/libclang/CXSourceLocation.h
index 6c5e858..f97ac1f 100644
--- a/tools/libclang/CXSourceLocation.h
+++ b/tools/libclang/CXSourceLocation.h
@@ -15,9 +15,9 @@
#define LLVM_CLANG_CXSOURCELOCATION_H
#include "clang-c/Index.h"
-#include "clang/Basic/SourceLocation.h"
-#include "clang/Basic/LangOptions.h"
#include "clang/AST/ASTContext.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceLocation.h"
namespace clang {
@@ -32,7 +32,7 @@ translateSourceLocation(const SourceManager &SM, const LangOptions &LangOpts,
if (Loc.isInvalid())
clang_getNullLocation();
- CXSourceLocation Result = { { (void*) &SM, (void*) &LangOpts, },
+ CXSourceLocation Result = { { &SM, &LangOpts, },
Loc.getRawEncoding() };
return Result;
}
diff --git a/tools/libclang/CXStoredDiagnostic.cpp b/tools/libclang/CXStoredDiagnostic.cpp
index fa331de..9731616 100644
--- a/tools/libclang/CXStoredDiagnostic.cpp
+++ b/tools/libclang/CXStoredDiagnostic.cpp
@@ -26,7 +26,6 @@
using namespace clang;
using namespace clang::cxloc;
-using namespace clang::cxstring;
CXDiagnosticSeverity CXStoredDiagnostic::getSeverity() const {
switch (Diag.getLevel()) {
@@ -49,7 +48,7 @@ CXSourceLocation CXStoredDiagnostic::getLocation() const {
}
CXString CXStoredDiagnostic::getSpelling() const {
- return createCXString(Diag.getMessage(), false);
+ return cxstring::createRef(Diag.getMessage());
}
CXString CXStoredDiagnostic::getDiagnosticOption(CXString *Disable) const {
@@ -57,17 +56,17 @@ CXString CXStoredDiagnostic::getDiagnosticOption(CXString *Disable) const {
StringRef Option = DiagnosticIDs::getWarningOptionForDiag(ID);
if (!Option.empty()) {
if (Disable)
- *Disable = createCXString((Twine("-Wno-") + Option).str());
- return createCXString((Twine("-W") + Option).str());
+ *Disable = cxstring::createDup((Twine("-Wno-") + Option).str());
+ return cxstring::createDup((Twine("-W") + Option).str());
}
if (ID == diag::fatal_too_many_errors) {
if (Disable)
- *Disable = createCXString("-ferror-limit=0");
- return createCXString("-ferror-limit=");
+ *Disable = cxstring::createRef("-ferror-limit=0");
+ return cxstring::createRef("-ferror-limit=");
}
- return createCXString("");
+ return cxstring::createEmpty();
}
unsigned CXStoredDiagnostic::getCategory() const {
@@ -76,7 +75,7 @@ unsigned CXStoredDiagnostic::getCategory() const {
CXString CXStoredDiagnostic::getCategoryText() const {
unsigned catID = DiagnosticIDs::getCategoryNumberForDiag(Diag.getID());
- return createCXString(DiagnosticIDs::getCategoryNameFromID(catID));
+ return cxstring::createRef(DiagnosticIDs::getCategoryNameFromID(catID));
}
unsigned CXStoredDiagnostic::getNumRanges() const {
@@ -109,6 +108,6 @@ CXString CXStoredDiagnostic::getFixIt(unsigned FixIt,
*ReplacementRange = translateSourceRange(Diag.getLocation().getManager(),
LangOpts, Hint.RemoveRange);
}
- return createCXString(Hint.CodeToInsert);
+ return cxstring::createDup(Hint.CodeToInsert);
}
diff --git a/tools/libclang/CXString.cpp b/tools/libclang/CXString.cpp
index bb09cd5..1523034 100644
--- a/tools/libclang/CXString.cpp
+++ b/tools/libclang/CXString.cpp
@@ -15,48 +15,93 @@
#include "CXString.h"
#include "CXTranslationUnit.h"
-#include "clang/Frontend/ASTUnit.h"
#include "clang-c/Index.h"
+#include "clang/Frontend/ASTUnit.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
-using namespace clang::cxstring;
-enum CXStringFlag { CXS_Unmanaged, CXS_Malloc, CXS_StringBuf };
+/// Describes the kind of underlying data in CXString.
+enum CXStringFlag {
+ /// CXString contains a 'const char *' that it doesn't own.
+ CXS_Unmanaged,
+
+ /// CXString contains a 'const char *' that it allocated with malloc().
+ CXS_Malloc,
+
+ /// CXString contains a CXStringBuf that needs to be returned to the
+ /// CXStringPool.
+ CXS_StringBuf
+};
+
+namespace clang {
+namespace cxstring {
//===----------------------------------------------------------------------===//
// Basic generation of CXStrings.
//===----------------------------------------------------------------------===//
-CXString cxstring::createCXString(const char *String, bool DupString){
+CXString createEmpty() {
CXString Str;
- if (DupString) {
- Str.data = strdup(String);
- Str.private_flags = (unsigned) CXS_Malloc;
- } else {
- Str.data = (void*)String;
- Str.private_flags = (unsigned) CXS_Unmanaged;
- }
+ Str.data = "";
+ Str.private_flags = CXS_Unmanaged;
+ return Str;
+}
+
+CXString createNull() {
+ CXString Str;
+ Str.data = 0;
+ Str.private_flags = CXS_Unmanaged;
+ return Str;
+}
+
+CXString createRef(const char *String) {
+ if (String && String[0] == '\0')
+ return createEmpty();
+
+ CXString Str;
+ Str.data = String;
+ Str.private_flags = CXS_Unmanaged;
+ return Str;
+}
+
+CXString createDup(const char *String) {
+ if (!String)
+ return createNull();
+
+ if (String[0] == '\0')
+ return createEmpty();
+
+ CXString Str;
+ Str.data = strdup(String);
+ Str.private_flags = CXS_Malloc;
return Str;
}
-CXString cxstring::createCXString(StringRef String, bool DupString) {
+CXString createRef(StringRef String) {
+ // If the string is not nul-terminated, we have to make a copy.
+ // This is doing a one past end read, and should be removed!
+ if (!String.empty() && String.data()[String.size()] != 0)
+ return createDup(String);
+
CXString Result;
- if (DupString || (!String.empty() && String.data()[String.size()] != 0)) {
- char *Spelling = (char *)malloc(String.size() + 1);
- memmove(Spelling, String.data(), String.size());
- Spelling[String.size()] = 0;
- Result.data = Spelling;
- Result.private_flags = (unsigned) CXS_Malloc;
- } else {
- Result.data = (void*) String.data();
- Result.private_flags = (unsigned) CXS_Unmanaged;
- }
+ Result.data = String.data();
+ Result.private_flags = (unsigned) CXS_Unmanaged;
return Result;
}
-CXString cxstring::createCXString(CXStringBuf *buf) {
+CXString createDup(StringRef String) {
+ CXString Result;
+ char *Spelling = static_cast<char *>(malloc(String.size() + 1));
+ memmove(Spelling, String.data(), String.size());
+ Spelling[String.size()] = 0;
+ Result.data = Spelling;
+ Result.private_flags = (unsigned) CXS_Malloc;
+ return Result;
+}
+
+CXString createCXString(CXStringBuf *buf) {
CXString Str;
Str.data = buf;
Str.private_flags = (unsigned) CXS_StringBuf;
@@ -68,43 +113,38 @@ CXString cxstring::createCXString(CXStringBuf *buf) {
// String pools.
//===----------------------------------------------------------------------===//
-
-typedef std::vector<CXStringBuf *> CXStringPool;
-
-void *cxstring::createCXStringPool() {
- return new CXStringPool();
-}
-
-void cxstring::disposeCXStringPool(void *p) {
- CXStringPool *pool = static_cast<CXStringPool*>(p);
- if (pool) {
- for (CXStringPool::iterator I = pool->begin(), E = pool->end();
- I != E; ++I) {
- delete *I;
- }
- delete pool;
+CXStringPool::~CXStringPool() {
+ for (std::vector<CXStringBuf *>::iterator I = Pool.begin(), E = Pool.end();
+ I != E; ++I) {
+ delete *I;
}
}
-CXStringBuf *cxstring::getCXStringBuf(CXTranslationUnit TU) {
- CXStringPool *pool = static_cast<CXStringPool*>(TU->StringPool);
- if (pool->empty())
+CXStringBuf *CXStringPool::getCXStringBuf(CXTranslationUnit TU) {
+ if (Pool.empty())
return new CXStringBuf(TU);
- CXStringBuf *buf = pool->back();
- buf->Data.clear();
- pool->pop_back();
- return buf;
+
+ CXStringBuf *Buf = Pool.back();
+ Buf->Data.clear();
+ Pool.pop_back();
+ return Buf;
+}
+
+CXStringBuf *getCXStringBuf(CXTranslationUnit TU) {
+ return TU->StringPool->getCXStringBuf(TU);
}
-void cxstring::disposeCXStringBuf(CXStringBuf *buf) {
- if (buf)
- static_cast<CXStringPool*>(buf->TU->StringPool)->push_back(buf);
+void CXStringBuf::dispose() {
+ TU->StringPool->Pool.push_back(this);
}
-bool cxstring::isManagedByPool(CXString str) {
+bool isManagedByPool(CXString str) {
return ((CXStringFlag) str.private_flags) == CXS_StringBuf;
}
+} // end namespace cxstring
+} // end namespace clang
+
//===----------------------------------------------------------------------===//
// libClang public APIs.
//===----------------------------------------------------------------------===//
@@ -112,9 +152,9 @@ bool cxstring::isManagedByPool(CXString str) {
extern "C" {
const char *clang_getCString(CXString string) {
if (string.private_flags == (unsigned) CXS_StringBuf) {
- return ((CXStringBuf*)string.data)->Data.data();
+ return static_cast<const cxstring::CXStringBuf *>(string.data)->Data.data();
}
- return (const char*) string.data;
+ return static_cast<const char *>(string.data);
}
void clang_disposeString(CXString string) {
@@ -123,10 +163,11 @@ void clang_disposeString(CXString string) {
break;
case CXS_Malloc:
if (string.data)
- free((void*)string.data);
+ free(const_cast<void *>(string.data));
break;
case CXS_StringBuf:
- disposeCXStringBuf((CXStringBuf *) string.data);
+ static_cast<cxstring::CXStringBuf *>(
+ const_cast<void *>(string.data))->dispose();
break;
}
}
diff --git a/tools/libclang/CXString.h b/tools/libclang/CXString.h
index c354bd2..7032033 100644
--- a/tools/libclang/CXString.h
+++ b/tools/libclang/CXString.h
@@ -16,36 +16,82 @@
#include "clang-c/Index.h"
#include "clang/Basic/LLVM.h"
-#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Compiler.h"
+#include <vector>
+#include <string>
namespace clang {
namespace cxstring {
-
-struct CXStringBuf {
- SmallString<128> Data;
- CXTranslationUnit TU;
- CXStringBuf(CXTranslationUnit tu) : TU(tu) {}
-};
-/// \brief Create a CXString object from a C string.
-CXString createCXString(const char *String, bool DupString = false);
+struct CXStringBuf;
+
+/// \brief Create a CXString object for an empty "" string.
+CXString createEmpty();
+
+/// \brief Create a CXString object for an NULL string.
+///
+/// A NULL string should be used as an "invalid" value in case of errors.
+CXString createNull();
+
+/// \brief Create a CXString object from a nul-terminated C string. New
+/// CXString may contain a pointer to \p String.
+///
+/// \p String should not be changed by the caller afterwards.
+CXString createRef(const char *String);
+
+/// \brief Create a CXString object from a nul-terminated C string. New
+/// CXString will contain a copy of \p String.
+///
+/// \p String can be changed or freed by the caller.
+CXString createDup(const char *String);
+
+/// \brief Create a CXString object from a StringRef. New CXString may
+/// contain a pointer to the undrelying data of \p String.
+///
+/// \p String should not be changed by the caller afterwards.
+CXString createRef(StringRef String);
+
+/// \brief Create a CXString object from a StringRef. New CXString will
+/// contain a copy of \p String.
+///
+/// \p String can be changed or freed by the caller.
+CXString createDup(StringRef String);
-/// \brief Create a CXString object from a StringRef.
-CXString createCXString(StringRef String, bool DupString = true);
+// Usually std::string is intended to be used as backing storage for CXString.
+// In this case, call \c createRef(String.c_str()).
+//
+// If you need to make a copy, call \c createDup(StringRef(String)).
+CXString createRef(std::string String) LLVM_DELETED_FUNCTION;
/// \brief Create a CXString object that is backed by a string buffer.
CXString createCXString(CXStringBuf *buf);
-/// \brief Create an opaque string pool used for fast geneneration of strings.
-void *createCXStringPool();
+/// \brief A string pool used for fast allocation/deallocation of strings.
+class CXStringPool {
+public:
+ ~CXStringPool();
+
+ CXStringBuf *getCXStringBuf(CXTranslationUnit TU);
+
+private:
+ std::vector<CXStringBuf *> Pool;
+
+ friend struct CXStringBuf;
+};
+
+struct CXStringBuf {
+ SmallString<128> Data;
+ CXTranslationUnit TU;
+
+ CXStringBuf(CXTranslationUnit TU) : TU(TU) {}
+
+ /// \brief Return this buffer to the pool.
+ void dispose();
+};
-/// \brief Dispose of a string pool.
-void disposeCXStringPool(void *pool);
-
CXStringBuf *getCXStringBuf(CXTranslationUnit TU);
-
-void disposeCXStringBuf(CXStringBuf *buf);
/// \brief Returns true if the CXString data is managed by a pool.
bool isManagedByPool(CXString str);
diff --git a/tools/libclang/CXTranslationUnit.h b/tools/libclang/CXTranslationUnit.h
index 37789aa..699b74a 100644
--- a/tools/libclang/CXTranslationUnit.h
+++ b/tools/libclang/CXTranslationUnit.h
@@ -14,24 +14,34 @@
#ifndef LLVM_CLANG_CXTRANSLATIONUNIT_H
#define LLVM_CLANG_CXTRANSLATIONUNIT_H
-extern "C" {
+#include "clang-c/Index.h"
+#include "CXString.h"
+
+namespace clang {
+ class ASTUnit;
+ class CIndexer;
+ class SimpleFormatContext;
+} // namespace clang
+
struct CXTranslationUnitImpl {
- void *CIdx;
- void *TUData;
- void *StringPool;
+ clang::CIndexer *CIdx;
+ clang::ASTUnit *TheASTUnit;
+ clang::cxstring::CXStringPool *StringPool;
void *Diagnostics;
void *OverridenCursorsPool;
+ clang::SimpleFormatContext *FormatContext;
+ unsigned FormatInMemoryUniqueId;
};
-}
namespace clang {
- class ASTUnit;
- class CIndexer;
-
namespace cxtu {
-CXTranslationUnitImpl *MakeCXTranslationUnit(CIndexer *CIdx, ASTUnit *TU);
-
+CXTranslationUnitImpl *MakeCXTranslationUnit(CIndexer *CIdx, ASTUnit *AU);
+
+static inline ASTUnit *getASTUnit(CXTranslationUnit TU) {
+ return TU->TheASTUnit;
+}
+
class CXTUOwner {
CXTranslationUnitImpl *TU;
diff --git a/tools/libclang/CXType.cpp b/tools/libclang/CXType.cpp
index 4e031d2..6f87fc5 100644
--- a/tools/libclang/CXType.cpp
+++ b/tools/libclang/CXType.cpp
@@ -12,15 +12,15 @@
//===--------------------------------------------------------------------===//
#include "CIndexer.h"
-#include "CXTranslationUnit.h"
#include "CXCursor.h"
#include "CXString.h"
+#include "CXTranslationUnit.h"
#include "CXType.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/Type.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
#include "clang/Frontend/ASTUnit.h"
using namespace clang;
@@ -97,7 +97,7 @@ CXType cxtype::MakeCXType(QualType T, CXTranslationUnit TU) {
CXTypeKind TK = CXType_Invalid;
if (TU && !T.isNull()) {
- ASTContext &Ctx = static_cast<ASTUnit *>(TU->TUData)->getASTContext();
+ ASTContext &Ctx = cxtu::getASTUnit(TU)->getASTContext();
if (Ctx.getLangOpts().ObjC1) {
QualType UnqualT = T.getUnqualifiedType();
if (Ctx.isObjCIdType(UnqualT))
@@ -131,27 +131,32 @@ CXType clang_getCursorType(CXCursor C) {
using namespace cxcursor;
CXTranslationUnit TU = cxcursor::getCursorTU(C);
- ASTContext &Context = static_cast<ASTUnit *>(TU->TUData)->getASTContext();
+ if (!TU)
+ return MakeCXType(QualType(), TU);
+
+ ASTContext &Context = cxtu::getASTUnit(TU)->getASTContext();
if (clang_isExpression(C.kind)) {
QualType T = cxcursor::getCursorExpr(C)->getType();
return MakeCXType(T, TU);
}
if (clang_isDeclaration(C.kind)) {
- Decl *D = cxcursor::getCursorDecl(C);
+ const Decl *D = cxcursor::getCursorDecl(C);
if (!D)
return MakeCXType(QualType(), TU);
- if (TypeDecl *TD = dyn_cast<TypeDecl>(D))
+ if (const TypeDecl *TD = dyn_cast<TypeDecl>(D))
return MakeCXType(Context.getTypeDeclType(TD), TU);
- if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D))
+ if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D))
return MakeCXType(Context.getObjCInterfaceType(ID), TU);
- if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
+ if (const ValueDecl *VD = dyn_cast<ValueDecl>(D))
return MakeCXType(VD->getType(), TU);
- if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D))
+ if (const ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D))
return MakeCXType(PD->getType(), TU);
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
return MakeCXType(FD->getType(), TU);
+ if (const FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(D))
+ return MakeCXType(FTD->getTemplatedDecl()->getType(), TU);
return MakeCXType(QualType(), TU);
}
@@ -197,14 +202,29 @@ CXType clang_getCursorType(CXCursor C) {
return MakeCXType(QualType(), TU);
}
+CXString clang_getTypeSpelling(CXType CT) {
+ QualType T = GetQualType(CT);
+ if (T.isNull())
+ return cxstring::createEmpty();
+
+ CXTranslationUnit TU = GetTU(CT);
+ SmallString<64> Str;
+ llvm::raw_svector_ostream OS(Str);
+ PrintingPolicy PP(cxtu::getASTUnit(TU)->getASTContext().getLangOpts());
+
+ T.print(OS, PP);
+
+ return cxstring::createDup(OS.str());
+}
+
CXType clang_getTypedefDeclUnderlyingType(CXCursor C) {
using namespace cxcursor;
CXTranslationUnit TU = cxcursor::getCursorTU(C);
if (clang_isDeclaration(C.kind)) {
- Decl *D = cxcursor::getCursorDecl(C);
+ const Decl *D = cxcursor::getCursorDecl(C);
- if (TypedefNameDecl *TD = dyn_cast_or_null<TypedefNameDecl>(D)) {
+ if (const TypedefNameDecl *TD = dyn_cast_or_null<TypedefNameDecl>(D)) {
QualType T = TD->getUnderlyingType();
return MakeCXType(T, TU);
}
@@ -220,9 +240,9 @@ CXType clang_getEnumDeclIntegerType(CXCursor C) {
CXTranslationUnit TU = cxcursor::getCursorTU(C);
if (clang_isDeclaration(C.kind)) {
- Decl *D = cxcursor::getCursorDecl(C);
+ const Decl *D = cxcursor::getCursorDecl(C);
- if (EnumDecl *TD = dyn_cast_or_null<EnumDecl>(D)) {
+ if (const EnumDecl *TD = dyn_cast_or_null<EnumDecl>(D)) {
QualType T = TD->getIntegerType();
return MakeCXType(T, TU);
}
@@ -237,9 +257,9 @@ long long clang_getEnumConstantDeclValue(CXCursor C) {
using namespace cxcursor;
if (clang_isDeclaration(C.kind)) {
- Decl *D = cxcursor::getCursorDecl(C);
+ const Decl *D = cxcursor::getCursorDecl(C);
- if (EnumConstantDecl *TD = dyn_cast_or_null<EnumConstantDecl>(D)) {
+ if (const EnumConstantDecl *TD = dyn_cast_or_null<EnumConstantDecl>(D)) {
return TD->getInitVal().getSExtValue();
}
@@ -253,9 +273,9 @@ unsigned long long clang_getEnumConstantDeclUnsignedValue(CXCursor C) {
using namespace cxcursor;
if (clang_isDeclaration(C.kind)) {
- Decl *D = cxcursor::getCursorDecl(C);
+ const Decl *D = cxcursor::getCursorDecl(C);
- if (EnumConstantDecl *TD = dyn_cast_or_null<EnumConstantDecl>(D)) {
+ if (const EnumConstantDecl *TD = dyn_cast_or_null<EnumConstantDecl>(D)) {
return TD->getInitVal().getZExtValue();
}
@@ -265,6 +285,21 @@ unsigned long long clang_getEnumConstantDeclUnsignedValue(CXCursor C) {
return ULLONG_MAX;
}
+int clang_getFieldDeclBitWidth(CXCursor C) {
+ using namespace cxcursor;
+
+ if (clang_isDeclaration(C.kind)) {
+ const Decl *D = getCursorDecl(C);
+
+ if (const FieldDecl *FD = dyn_cast_or_null<FieldDecl>(D)) {
+ if (FD->isBitField())
+ return FD->getBitWidthValue(getCursorContext(C));
+ }
+ }
+
+ return -1;
+}
+
CXType clang_getCanonicalType(CXType CT) {
if (CT.kind == CXType_Invalid)
return CT;
@@ -275,8 +310,9 @@ CXType clang_getCanonicalType(CXType CT) {
if (T.isNull())
return MakeCXType(QualType(), GetTU(CT));
- ASTUnit *AU = static_cast<ASTUnit*>(TU->TUData);
- return MakeCXType(AU->getASTContext().getCanonicalType(T), TU);
+ return MakeCXType(cxtu::getASTUnit(TU)->getASTContext()
+ .getCanonicalType(T),
+ TU);
}
unsigned clang_isConstQualifiedType(CXType CT) {
@@ -427,7 +463,7 @@ CXString clang_getTypeKindSpelling(enum CXTypeKind K) {
TKIND(Vector);
}
#undef TKIND
- return cxstring::createCXString(s);
+ return cxstring::createRef(s);
}
unsigned clang_equalTypes(CXType A, CXType B) {
@@ -465,6 +501,7 @@ CXCallingConv clang_getFunctionTypeCallingConv(CXType X) {
TCALLINGCONV(AAPCS);
TCALLINGCONV(AAPCS_VFP);
TCALLINGCONV(PnaclCall);
+ TCALLINGCONV(IntelOclBicc);
}
#undef TCALLINGCONV
}
@@ -517,7 +554,7 @@ CXType clang_getResultType(CXType X) {
CXType clang_getCursorResultType(CXCursor C) {
if (clang_isDeclaration(C.kind)) {
- Decl *D = cxcursor::getCursorDecl(C);
+ const Decl *D = cxcursor::getCursorDecl(C);
if (const ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D))
return MakeCXType(MD->getResultType(), cxcursor::getCursorTU(C));
@@ -533,9 +570,8 @@ unsigned clang_isPODType(CXType X) {
return 0;
CXTranslationUnit TU = GetTU(X);
- ASTUnit *AU = static_cast<ASTUnit*>(TU->TUData);
- return T.isPODType(AU->getASTContext()) ? 1 : 0;
+ return T.isPODType(cxtu::getASTUnit(TU)->getASTContext()) ? 1 : 0;
}
CXType clang_getElementType(CXType CT) {
@@ -617,32 +653,30 @@ long long clang_getArraySize(CXType CT) {
CXString clang_getDeclObjCTypeEncoding(CXCursor C) {
if (!clang_isDeclaration(C.kind))
- return cxstring::createCXString("");
+ return cxstring::createEmpty();
- Decl *D = static_cast<Decl*>(C.data[0]);
- CXTranslationUnit TU = static_cast<CXTranslationUnit>(C.data[2]);
- ASTUnit *AU = static_cast<ASTUnit*>(TU->TUData);
- ASTContext &Ctx = AU->getASTContext();
+ const Decl *D = cxcursor::getCursorDecl(C);
+ ASTContext &Ctx = cxcursor::getCursorContext(C);
std::string encoding;
- if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D)) {
+ if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D)) {
if (Ctx.getObjCEncodingForMethodDecl(OMD, encoding))
- return cxstring::createCXString("?");
- } else if (ObjCPropertyDecl *OPD = dyn_cast<ObjCPropertyDecl>(D))
+ return cxstring::createRef("?");
+ } else if (const ObjCPropertyDecl *OPD = dyn_cast<ObjCPropertyDecl>(D))
Ctx.getObjCEncodingForPropertyDecl(OPD, NULL, encoding);
- else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
Ctx.getObjCEncodingForFunctionDecl(FD, encoding);
else {
QualType Ty;
- if (TypeDecl *TD = dyn_cast<TypeDecl>(D))
+ if (const TypeDecl *TD = dyn_cast<TypeDecl>(D))
Ty = Ctx.getTypeDeclType(TD);
- if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
+ if (const ValueDecl *VD = dyn_cast<ValueDecl>(D))
Ty = VD->getType();
- else return cxstring::createCXString("?");
+ else return cxstring::createRef("?");
Ctx.getObjCEncodingForType(Ty, encoding);
}
- return cxstring::createCXString(encoding);
+ return cxstring::createDup(encoding);
}
} // end: extern "C"
diff --git a/tools/libclang/CursorVisitor.h b/tools/libclang/CursorVisitor.h
index 7cf7508..53d864d 100644
--- a/tools/libclang/CursorVisitor.h
+++ b/tools/libclang/CursorVisitor.h
@@ -10,10 +10,9 @@
#ifndef LLVM_CLANG_LIBCLANG_CURSORVISITOR_H
#define LLVM_CLANG_LIBCLANG_CURSORVISITOR_H
-#include "Index_Internal.h"
#include "CXCursor.h"
#include "CXTranslationUnit.h"
-
+#include "Index_Internal.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/TypeLocVisitor.h"
@@ -34,10 +33,11 @@ public:
MemberRefVisitKind, SizeOfPackExprPartsKind,
LambdaExprPartsKind, PostChildrenVisitKind };
protected:
- void *data[3];
+ const void *data[3];
CXCursor parent;
Kind K;
- VisitorJob(CXCursor C, Kind k, void *d1, void *d2 = 0, void *d3 = 0)
+ VisitorJob(CXCursor C, Kind k, const void *d1, const void *d2 = 0,
+ const void *d3 = 0)
: parent(C), K(k) {
data[0] = d1;
data[1] = d2;
@@ -70,7 +70,7 @@ private:
/// \brief The declaration that serves at the parent of any statement or
/// expression nodes.
- Decl *StmtParent;
+ const Decl *StmtParent;
/// \brief The visitor function.
CXCursorVisitor Visitor;
@@ -116,15 +116,16 @@ private:
/// \param R a half-open source range retrieved from the abstract syntax tree.
RangeComparisonResult CompareRegionOfInterest(SourceRange R);
- void visitDeclsFromFileRegion(FileID File, unsigned Offset, unsigned Length);
+ bool visitDeclsFromFileRegion(FileID File, unsigned Offset, unsigned Length);
class SetParentRAII {
CXCursor &Parent;
- Decl *&StmtParent;
+ const Decl *&StmtParent;
CXCursor OldParent;
public:
- SetParentRAII(CXCursor &Parent, Decl *&StmtParent, CXCursor NewParent)
+ SetParentRAII(CXCursor &Parent, const Decl *&StmtParent,
+ CXCursor NewParent)
: Parent(Parent), StmtParent(StmtParent), OldParent(Parent)
{
Parent = NewParent;
@@ -147,7 +148,7 @@ public:
SourceRange RegionOfInterest = SourceRange(),
bool VisitDeclsOnly = false,
PostChildrenVisitorTy PostChildrenVisitor = 0)
- : TU(TU), AU(static_cast<ASTUnit*>(TU->TUData)),
+ : TU(TU), AU(cxtu::getASTUnit(TU)),
Visitor(Visitor), PostChildrenVisitor(PostChildrenVisitor),
ClientData(ClientData),
VisitPreprocessorLast(VisitPreprocessorLast),
@@ -171,14 +172,14 @@ public:
}
}
- ASTUnit *getASTUnit() const { return static_cast<ASTUnit*>(TU->TUData); }
+ ASTUnit *getASTUnit() const { return AU; }
CXTranslationUnit getTU() const { return TU; }
bool Visit(CXCursor Cursor, bool CheckedRegionOfInterest = false);
/// \brief Visit declarations and preprocessed entities for the file region
/// designated by \see RegionOfInterest.
- void visitFileRegion();
+ bool visitFileRegion();
bool visitPreprocessedEntitiesInRegion();
@@ -198,7 +199,7 @@ public:
bool VisitAttributes(Decl *D);
bool VisitBlockDecl(BlockDecl *B);
bool VisitCXXRecordDecl(CXXRecordDecl *D);
- llvm::Optional<bool> shouldVisitCursor(CXCursor C);
+ Optional<bool> shouldVisitCursor(CXCursor C);
bool VisitDeclContext(DeclContext *DC);
bool VisitTranslationUnitDecl(TranslationUnitDecl *D);
bool VisitTypedefDecl(TypedefDecl *D);
@@ -258,8 +259,8 @@ public:
// Data-recursive visitor functions.
bool IsInRegionOfInterest(CXCursor C);
bool RunVisitorWorkList(VisitorWorkList &WL);
- void EnqueueWorkList(VisitorWorkList &WL, Stmt *S);
- LLVM_ATTRIBUTE_NOINLINE bool Visit(Stmt *S);
+ void EnqueueWorkList(VisitorWorkList &WL, const Stmt *S);
+ LLVM_ATTRIBUTE_NOINLINE bool Visit(const Stmt *S);
};
}
diff --git a/tools/libclang/IndexBody.cpp b/tools/libclang/IndexBody.cpp
index 3614206..95d74ef 100644
--- a/tools/libclang/IndexBody.cpp
+++ b/tools/libclang/IndexBody.cpp
@@ -8,7 +8,6 @@
//===----------------------------------------------------------------------===//
#include "IndexingContext.h"
-
#include "RecursiveASTVisitor.h"
using namespace clang;
diff --git a/tools/libclang/IndexDecl.cpp b/tools/libclang/IndexDecl.cpp
index 4b6706f..d7fb959 100644
--- a/tools/libclang/IndexDecl.cpp
+++ b/tools/libclang/IndexDecl.cpp
@@ -8,7 +8,6 @@
//===----------------------------------------------------------------------===//
#include "IndexingContext.h"
-
#include "clang/AST/DeclVisitor.h"
using namespace clang;
@@ -16,39 +15,41 @@ using namespace cxindex;
namespace {
-class IndexingDeclVisitor : public DeclVisitor<IndexingDeclVisitor, bool> {
+class IndexingDeclVisitor : public ConstDeclVisitor<IndexingDeclVisitor, bool> {
IndexingContext &IndexCtx;
public:
explicit IndexingDeclVisitor(IndexingContext &indexCtx)
: IndexCtx(indexCtx) { }
- void handleDeclarator(DeclaratorDecl *D, const NamedDecl *Parent = 0) {
+ void handleDeclarator(const DeclaratorDecl *D, const NamedDecl *Parent = 0) {
if (!Parent) Parent = D;
if (!IndexCtx.shouldIndexFunctionLocalSymbols()) {
IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), Parent);
IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent);
} else {
- if (ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) {
+ if (const ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) {
IndexCtx.handleVar(Parm);
- } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- for (FunctionDecl::param_iterator
- PI = FD->param_begin(), PE = FD->param_end(); PI != PE; ++PI) {
+ } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ for (FunctionDecl::param_const_iterator PI = FD->param_begin(),
+ PE = FD->param_end();
+ PI != PE; ++PI) {
IndexCtx.handleVar(*PI);
}
}
}
}
- void handleObjCMethod(ObjCMethodDecl *D) {
+ void handleObjCMethod(const ObjCMethodDecl *D) {
IndexCtx.handleObjCMethod(D);
if (D->isImplicit())
return;
IndexCtx.indexTypeSourceInfo(D->getResultTypeSourceInfo(), D);
- for (ObjCMethodDecl::param_iterator
- I = D->param_begin(), E = D->param_end(); I != E; ++I)
+ for (ObjCMethodDecl::param_const_iterator I = D->param_begin(),
+ E = D->param_end();
+ I != E; ++I)
handleDeclarator(*I, D);
if (D->isThisDeclarationADefinition()) {
@@ -59,14 +60,14 @@ public:
}
}
- bool VisitFunctionDecl(FunctionDecl *D) {
+ bool VisitFunctionDecl(const FunctionDecl *D) {
IndexCtx.handleFunction(D);
handleDeclarator(D);
- if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
+ if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
// Constructor initializers.
- for (CXXConstructorDecl::init_iterator I = Ctor->init_begin(),
- E = Ctor->init_end();
+ for (CXXConstructorDecl::init_const_iterator I = Ctor->init_begin(),
+ E = Ctor->init_end();
I != E; ++I) {
CXXCtorInitializer *Init = *I;
if (Init->isWritten()) {
@@ -87,14 +88,14 @@ public:
return true;
}
- bool VisitVarDecl(VarDecl *D) {
+ bool VisitVarDecl(const VarDecl *D) {
IndexCtx.handleVar(D);
handleDeclarator(D);
IndexCtx.indexBody(D->getInit(), D);
return true;
}
- bool VisitFieldDecl(FieldDecl *D) {
+ bool VisitFieldDecl(const FieldDecl *D) {
IndexCtx.handleField(D);
handleDeclarator(D);
if (D->isBitField())
@@ -103,27 +104,27 @@ public:
IndexCtx.indexBody(D->getInClassInitializer(), D);
return true;
}
-
- bool VisitEnumConstantDecl(EnumConstantDecl *D) {
+
+ bool VisitEnumConstantDecl(const EnumConstantDecl *D) {
IndexCtx.handleEnumerator(D);
IndexCtx.indexBody(D->getInitExpr(), D);
return true;
}
- bool VisitTypedefNameDecl(TypedefNameDecl *D) {
+ bool VisitTypedefNameDecl(const TypedefNameDecl *D) {
IndexCtx.handleTypedefName(D);
IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
return true;
}
- bool VisitTagDecl(TagDecl *D) {
+ bool VisitTagDecl(const TagDecl *D) {
// Non-free standing tags are handled in indexTypeSourceInfo.
if (D->isFreeStanding())
IndexCtx.indexTagDecl(D);
return true;
}
- bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
+ bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
IndexCtx.handleObjCInterface(D);
if (D->isThisDeclarationADefinition()) {
@@ -133,7 +134,7 @@ public:
return true;
}
- bool VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
+ bool VisitObjCProtocolDecl(const ObjCProtocolDecl *D) {
IndexCtx.handleObjCProtocol(D);
if (D->isThisDeclarationADefinition()) {
@@ -143,7 +144,7 @@ public:
return true;
}
- bool VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
+ bool VisitObjCImplementationDecl(const ObjCImplementationDecl *D) {
const ObjCInterfaceDecl *Class = D->getClassInterface();
if (!Class)
return true;
@@ -171,7 +172,7 @@ public:
return true;
}
- bool VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
+ bool VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
IndexCtx.handleObjCCategory(D);
IndexCtx.indexTUDeclsInObjCContainer();
@@ -179,7 +180,7 @@ public:
return true;
}
- bool VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
+ bool VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) {
const ObjCCategoryDecl *Cat = D->getCategoryDecl();
if (!Cat)
return true;
@@ -191,7 +192,7 @@ public:
return true;
}
- bool VisitObjCMethodDecl(ObjCMethodDecl *D) {
+ bool VisitObjCMethodDecl(const ObjCMethodDecl *D) {
// Methods associated with a property, even user-declared ones, are
// handled when we handle the property.
if (D->isPropertyAccessor())
@@ -201,7 +202,7 @@ public:
return true;
}
- bool VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
+ bool VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
if (ObjCMethodDecl *MD = D->getGetterMethodDecl())
if (MD->getLexicalDeclContext() == D->getLexicalDeclContext())
handleObjCMethod(MD);
@@ -213,7 +214,7 @@ public:
return true;
}
- bool VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
+ bool VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) {
ObjCPropertyDecl *PD = D->getPropertyDecl();
IndexCtx.handleSynthesizedObjCProperty(D);
@@ -240,13 +241,13 @@ public:
return true;
}
- bool VisitNamespaceDecl(NamespaceDecl *D) {
+ bool VisitNamespaceDecl(const NamespaceDecl *D) {
IndexCtx.handleNamespace(D);
IndexCtx.indexDeclContext(D);
return true;
}
- bool VisitUsingDecl(UsingDecl *D) {
+ bool VisitUsingDecl(const UsingDecl *D) {
// FIXME: Parent for the following is CXIdxEntity_Unexposed with no USR,
// we should do better.
@@ -259,7 +260,7 @@ public:
return true;
}
- bool VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
+ bool VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) {
// FIXME: Parent for the following is CXIdxEntity_Unexposed with no USR,
// we should do better.
@@ -269,14 +270,14 @@ public:
return true;
}
- bool VisitClassTemplateDecl(ClassTemplateDecl *D) {
+ bool VisitClassTemplateDecl(const ClassTemplateDecl *D) {
IndexCtx.handleClassTemplate(D);
if (D->isThisDeclarationADefinition())
IndexCtx.indexDeclContext(D->getTemplatedDecl());
return true;
}
- bool VisitClassTemplateSpecializationDecl(
+ bool VisitClassTemplateSpecializationDecl(const
ClassTemplateSpecializationDecl *D) {
// FIXME: Notify subsequent callbacks if info comes from implicit
// instantiation.
@@ -287,7 +288,7 @@ public:
return true;
}
- bool VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
+ bool VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {
IndexCtx.handleFunctionTemplate(D);
FunctionDecl *FD = D->getTemplatedDecl();
handleDeclarator(FD, D);
@@ -300,13 +301,13 @@ public:
return true;
}
- bool VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
+ bool VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D) {
IndexCtx.handleTypeAliasTemplate(D);
IndexCtx.indexTypeSourceInfo(D->getTemplatedDecl()->getTypeSourceInfo(), D);
return true;
}
- bool VisitImportDecl(ImportDecl *D) {
+ bool VisitImportDecl(const ImportDecl *D) {
IndexCtx.importedModule(D);
return true;
}
@@ -318,7 +319,7 @@ void IndexingContext::indexDecl(const Decl *D) {
if (D->isImplicit() && shouldIgnoreIfImplicit(D))
return;
- bool Handled = IndexingDeclVisitor(*this).Visit(const_cast<Decl*>(D));
+ bool Handled = IndexingDeclVisitor(*this).Visit(D);
if (!Handled && isa<DeclContext>(D))
indexDeclContext(cast<DeclContext>(D));
}
diff --git a/tools/libclang/IndexTypeSourceInfo.cpp b/tools/libclang/IndexTypeSourceInfo.cpp
index 67a06f2..2c771c8 100644
--- a/tools/libclang/IndexTypeSourceInfo.cpp
+++ b/tools/libclang/IndexTypeSourceInfo.cpp
@@ -8,7 +8,6 @@
//===----------------------------------------------------------------------===//
#include "IndexingContext.h"
-
#include "RecursiveASTVisitor.h"
using namespace clang;
diff --git a/tools/libclang/Indexing.cpp b/tools/libclang/Indexing.cpp
index 714a36e..2a504db 100644
--- a/tools/libclang/Indexing.cpp
+++ b/tools/libclang/Indexing.cpp
@@ -8,28 +8,31 @@
//===----------------------------------------------------------------------===//
#include "IndexingContext.h"
+#include "CIndexDiagnostic.h"
+#include "CIndexer.h"
+#include "CLog.h"
#include "CXCursor.h"
#include "CXSourceLocation.h"
-#include "CXTranslationUnit.h"
#include "CXString.h"
-#include "CIndexDiagnostic.h"
-#include "CIndexer.h"
-
+#include "CXTranslationUnit.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/DeclVisitor.h"
#include "clang/Frontend/ASTUnit.h"
-#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Frontend/Utils.h"
-#include "clang/Sema/SemaConsumer.h"
-#include "clang/AST/ASTConsumer.h"
-#include "clang/AST/DeclVisitor.h"
-#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/PPCallbacks.h"
-#include "llvm/Support/MemoryBuffer.h"
+#include "clang/Lex/PPConditionalDirectiveRecord.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/SemaConsumer.h"
#include "llvm/Support/CrashRecoveryContext.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Mutex.h"
+#include "llvm/Support/MutexGuard.h"
using namespace clang;
-using namespace cxstring;
using namespace cxtu;
using namespace cxindex;
@@ -38,6 +41,204 @@ static void indexDiagnostics(CXTranslationUnit TU, IndexingContext &IdxCtx);
namespace {
//===----------------------------------------------------------------------===//
+// Skip Parsed Bodies
+//===----------------------------------------------------------------------===//
+
+#ifdef LLVM_ON_WIN32
+
+// FIXME: On windows it is disabled since current implementation depends on
+// file inodes.
+
+class SessionSkipBodyData { };
+
+class TUSkipBodyControl {
+public:
+ TUSkipBodyControl(SessionSkipBodyData &sessionData,
+ PPConditionalDirectiveRecord &ppRec,
+ Preprocessor &pp) { }
+ bool isParsed(SourceLocation Loc, FileID FID, const FileEntry *FE) {
+ return false;
+ }
+ void finished() { }
+};
+
+#else
+
+/// \brief A "region" in source code identified by the file/offset of the
+/// preprocessor conditional directive that it belongs to.
+/// Multiple, non-consecutive ranges can be parts of the same region.
+///
+/// As an example of different regions separated by preprocessor directives:
+///
+/// \code
+/// #1
+/// #ifdef BLAH
+/// #2
+/// #ifdef CAKE
+/// #3
+/// #endif
+/// #2
+/// #endif
+/// #1
+/// \endcode
+///
+/// There are 3 regions, with non-consecutive parts:
+/// #1 is identified as the beginning of the file
+/// #2 is identified as the location of "#ifdef BLAH"
+/// #3 is identified as the location of "#ifdef CAKE"
+///
+class PPRegion {
+ ino_t ino;
+ time_t ModTime;
+ dev_t dev;
+ unsigned Offset;
+public:
+ PPRegion() : ino(), ModTime(), dev(), Offset() {}
+ PPRegion(dev_t dev, ino_t ino, unsigned offset, time_t modTime)
+ : ino(ino), ModTime(modTime), dev(dev), Offset(offset) {}
+
+ ino_t getIno() const { return ino; }
+ dev_t getDev() const { return dev; }
+ unsigned getOffset() const { return Offset; }
+ time_t getModTime() const { return ModTime; }
+
+ bool isInvalid() const { return *this == PPRegion(); }
+
+ friend bool operator==(const PPRegion &lhs, const PPRegion &rhs) {
+ return lhs.dev == rhs.dev && lhs.ino == rhs.ino &&
+ lhs.Offset == rhs.Offset && lhs.ModTime == rhs.ModTime;
+ }
+};
+
+typedef llvm::DenseSet<PPRegion> PPRegionSetTy;
+
+} // end anonymous namespace
+
+namespace llvm {
+ template <> struct isPodLike<PPRegion> {
+ static const bool value = true;
+ };
+
+ template <>
+ struct DenseMapInfo<PPRegion> {
+ static inline PPRegion getEmptyKey() {
+ return PPRegion(0, 0, unsigned(-1), 0);
+ }
+ static inline PPRegion getTombstoneKey() {
+ return PPRegion(0, 0, unsigned(-2), 0);
+ }
+
+ static unsigned getHashValue(const PPRegion &S) {
+ llvm::FoldingSetNodeID ID;
+ ID.AddInteger(S.getIno());
+ ID.AddInteger(S.getDev());
+ ID.AddInteger(S.getOffset());
+ ID.AddInteger(S.getModTime());
+ return ID.ComputeHash();
+ }
+
+ static bool isEqual(const PPRegion &LHS, const PPRegion &RHS) {
+ return LHS == RHS;
+ }
+ };
+}
+
+namespace {
+
+class SessionSkipBodyData {
+ llvm::sys::Mutex Mux;
+ PPRegionSetTy ParsedRegions;
+
+public:
+ SessionSkipBodyData() : Mux(/*recursive=*/false) {}
+ ~SessionSkipBodyData() {
+ //llvm::errs() << "RegionData: " << Skipped.size() << " - " << Skipped.getMemorySize() << "\n";
+ }
+
+ void copyTo(PPRegionSetTy &Set) {
+ llvm::MutexGuard MG(Mux);
+ Set = ParsedRegions;
+ }
+
+ void update(ArrayRef<PPRegion> Regions) {
+ llvm::MutexGuard MG(Mux);
+ ParsedRegions.insert(Regions.begin(), Regions.end());
+ }
+};
+
+class TUSkipBodyControl {
+ SessionSkipBodyData &SessionData;
+ PPConditionalDirectiveRecord &PPRec;
+ Preprocessor &PP;
+
+ PPRegionSetTy ParsedRegions;
+ SmallVector<PPRegion, 32> NewParsedRegions;
+ PPRegion LastRegion;
+ bool LastIsParsed;
+
+public:
+ TUSkipBodyControl(SessionSkipBodyData &sessionData,
+ PPConditionalDirectiveRecord &ppRec,
+ Preprocessor &pp)
+ : SessionData(sessionData), PPRec(ppRec), PP(pp) {
+ SessionData.copyTo(ParsedRegions);
+ }
+
+ bool isParsed(SourceLocation Loc, FileID FID, const FileEntry *FE) {
+ PPRegion region = getRegion(Loc, FID, FE);
+ if (region.isInvalid())
+ return false;
+
+ // Check common case, consecutive functions in the same region.
+ if (LastRegion == region)
+ return LastIsParsed;
+
+ LastRegion = region;
+ LastIsParsed = ParsedRegions.count(region);
+ if (!LastIsParsed)
+ NewParsedRegions.push_back(region);
+ return LastIsParsed;
+ }
+
+ void finished() {
+ SessionData.update(NewParsedRegions);
+ }
+
+private:
+ PPRegion getRegion(SourceLocation Loc, FileID FID, const FileEntry *FE) {
+ SourceLocation RegionLoc = PPRec.findConditionalDirectiveRegionLoc(Loc);
+ if (RegionLoc.isInvalid()) {
+ if (isParsedOnceInclude(FE))
+ return PPRegion(FE->getDevice(), FE->getInode(), 0,
+ FE->getModificationTime());
+ return PPRegion();
+ }
+
+ const SourceManager &SM = PPRec.getSourceManager();
+ assert(RegionLoc.isFileID());
+ FileID RegionFID;
+ unsigned RegionOffset;
+ llvm::tie(RegionFID, RegionOffset) = SM.getDecomposedLoc(RegionLoc);
+
+ if (RegionFID != FID) {
+ if (isParsedOnceInclude(FE))
+ return PPRegion(FE->getDevice(), FE->getInode(), 0,
+ FE->getModificationTime());
+ return PPRegion();
+ }
+
+ return PPRegion(FE->getDevice(), FE->getInode(), RegionOffset,
+ FE->getModificationTime());
+ }
+
+ bool isParsedOnceInclude(const FileEntry *FE) {
+ return PP.getHeaderSearchInfo().isFileMultipleIncludeGuarded(FE);
+ }
+};
+
+#endif
+
+//===----------------------------------------------------------------------===//
// IndexPPCallbacks
//===----------------------------------------------------------------------===//
@@ -80,19 +281,20 @@ public:
}
/// MacroDefined - This hook is called whenever a macro definition is seen.
- virtual void MacroDefined(const Token &Id, const MacroInfo *MI) {
+ virtual void MacroDefined(const Token &Id, const MacroDirective *MD) {
}
/// MacroUndefined - This hook is called whenever a macro #undef is seen.
/// MI is released immediately following this callback.
- virtual void MacroUndefined(const Token &MacroNameTok, const MacroInfo *MI) {
+ virtual void MacroUndefined(const Token &MacroNameTok,
+ const MacroDirective *MD) {
}
/// MacroExpands - This is called by when a macro invocation is found.
- virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo* MI,
+ virtual void MacroExpands(const Token &MacroNameTok, const MacroDirective *MD,
SourceRange Range) {
}
-
+
/// SourceRangeSkipped - This hook is called when a source range is skipped.
/// \param Range The SourceRange that was skipped. The range begins at the
/// #if/#else directive and ends after the #endif/#else directive.
@@ -106,10 +308,11 @@ public:
class IndexingConsumer : public ASTConsumer {
IndexingContext &IndexCtx;
+ TUSkipBodyControl *SKCtrl;
public:
- explicit IndexingConsumer(IndexingContext &indexCtx)
- : IndexCtx(indexCtx) { }
+ IndexingConsumer(IndexingContext &indexCtx, TUSkipBodyControl *skCtrl)
+ : IndexCtx(indexCtx), SKCtrl(skCtrl) { }
// ASTConsumer Implementation
@@ -119,6 +322,8 @@ public:
}
virtual void HandleTranslationUnit(ASTContext &Ctx) {
+ if (SKCtrl)
+ SKCtrl->finished();
}
virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
@@ -152,6 +357,32 @@ public:
IndexCtx.indexDecl(D);
}
+
+ virtual bool shouldSkipFunctionBody(Decl *D) {
+ if (!SKCtrl) {
+ // Always skip bodies.
+ return true;
+ }
+
+ const SourceManager &SM = IndexCtx.getASTContext().getSourceManager();
+ SourceLocation Loc = D->getLocation();
+ if (Loc.isMacroID())
+ return false;
+ if (SM.isInSystemHeader(Loc))
+ return true; // always skip bodies from system headers.
+
+ FileID FID;
+ unsigned Offset;
+ llvm::tie(FID, Offset) = SM.getDecomposedLoc(Loc);
+ // Don't skip bodies from main files; this may be revisited.
+ if (SM.getMainFileID() == FID)
+ return false;
+ const FileEntry *FE = SM.getFileEntryForID(FID);
+ if (!FE)
+ return false;
+
+ return SKCtrl->isParsed(Loc, FID, FE);
+ }
};
//===----------------------------------------------------------------------===//
@@ -181,13 +412,17 @@ class IndexingFrontendAction : public ASTFrontendAction {
IndexingContext IndexCtx;
CXTranslationUnit CXTU;
+ SessionSkipBodyData *SKData;
+ OwningPtr<TUSkipBodyControl> SKCtrl;
+
public:
IndexingFrontendAction(CXClientData clientData,
IndexerCallbacks &indexCallbacks,
unsigned indexOptions,
- CXTranslationUnit cxTU)
+ CXTranslationUnit cxTU,
+ SessionSkipBodyData *skData)
: IndexCtx(clientData, indexCallbacks, indexOptions, cxTU),
- CXTU(cxTU) { }
+ CXTU(cxTU), SKData(skData) { }
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) {
@@ -202,7 +437,15 @@ public:
Preprocessor &PP = CI.getPreprocessor();
PP.addPPCallbacks(new IndexPPCallbacks(PP, IndexCtx));
IndexCtx.setPreprocessor(PP);
- return new IndexingConsumer(IndexCtx);
+
+ if (SKData) {
+ PPConditionalDirectiveRecord *
+ PPRec = new PPConditionalDirectiveRecord(PP.getSourceManager());
+ PP.addPPCallbacks(PPRec);
+ SKCtrl.reset(new TUSkipBodyControl(*SKData, *PPRec, PP));
+ }
+
+ return new IndexingConsumer(IndexCtx, SKCtrl.get());
}
virtual void EndSourceFileAction() {
@@ -222,6 +465,14 @@ public:
// clang_indexSourceFileUnit Implementation
//===----------------------------------------------------------------------===//
+struct IndexSessionData {
+ CXIndex CIdx;
+ OwningPtr<SessionSkipBodyData> SkipBodyData;
+
+ explicit IndexSessionData(CXIndex cIdx)
+ : CIdx(cIdx), SkipBodyData(new SessionSkipBodyData) {}
+};
+
struct IndexSourceFileInfo {
CXIndexAction idxAction;
CXClientData client_data;
@@ -253,7 +504,7 @@ struct MemBufferOwner {
static void clang_indexSourceFile_Impl(void *UserData) {
IndexSourceFileInfo *ITUI =
static_cast<IndexSourceFileInfo*>(UserData);
- CXIndex CIdx = (CXIndex)ITUI->idxAction;
+ CXIndexAction cxIdxAction = ITUI->idxAction;
CXClientData client_data = ITUI->client_data;
IndexerCallbacks *client_index_callbacks = ITUI->index_callbacks;
unsigned index_callbacks_size = ITUI->index_callbacks_size;
@@ -271,7 +522,7 @@ static void clang_indexSourceFile_Impl(void *UserData) {
*out_TU = 0;
bool requestedToGetTU = (out_TU != 0);
- if (!CIdx)
+ if (!cxIdxAction)
return;
if (!client_index_callbacks || index_callbacks_size == 0)
return;
@@ -282,18 +533,21 @@ static void clang_indexSourceFile_Impl(void *UserData) {
? index_callbacks_size : sizeof(CB);
memcpy(&CB, client_index_callbacks, ClientCBSize);
- CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
+ IndexSessionData *IdxSession = static_cast<IndexSessionData *>(cxIdxAction);
+ CIndexer *CXXIdx = static_cast<CIndexer *>(IdxSession->CIdx);
if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing))
setThreadBackgroundPriority();
- CaptureDiagnosticConsumer *CaptureDiag = new CaptureDiagnosticConsumer();
+ bool CaptureDiagnostics = !Logger::isLoggingEnabled();
+
+ CaptureDiagnosticConsumer *CaptureDiag = 0;
+ if (CaptureDiagnostics)
+ CaptureDiag = new CaptureDiagnosticConsumer();
// Configure the diagnostics.
IntrusiveRefCntPtr<DiagnosticsEngine>
Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions,
- num_command_line_args,
- command_line_args,
CaptureDiag,
/*ShouldOwnClient=*/true,
/*ShouldCloneClient=*/false));
@@ -359,7 +613,7 @@ static void clang_indexSourceFile_Impl(void *UserData) {
CInvok->getDiagnosticOpts().IgnoreWarnings = true;
ASTUnit *Unit = ASTUnit::create(CInvok.getPtr(), Diags,
- /*CaptureDiagnostics=*/true,
+ CaptureDiagnostics,
/*UserFilesAreVolatile=*/true);
OwningPtr<CXTUOwner> CXTU(new CXTUOwner(MakeCXTranslationUnit(CXXIdx, Unit)));
@@ -367,9 +621,17 @@ static void clang_indexSourceFile_Impl(void *UserData) {
llvm::CrashRecoveryContextCleanupRegistrar<CXTUOwner>
CXTUCleanup(CXTU.get());
+ // Enable the skip-parsed-bodies optimization only for C++; this may be
+ // revisited.
+ bool SkipBodies = (index_options & CXIndexOpt_SkipParsedBodiesInSession) &&
+ CInvok->getLangOpts()->CPlusPlus;
+ if (SkipBodies)
+ CInvok->getFrontendOpts().SkipFunctionBodies = true;
+
OwningPtr<IndexingFrontendAction> IndexAction;
IndexAction.reset(new IndexingFrontendAction(client_data, CB,
- index_options, CXTU->getTU()));
+ index_options, CXTU->getTU(),
+ SkipBodies ? IdxSession->SkipBodyData.get() : 0));
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<IndexingFrontendAction>
@@ -404,7 +666,7 @@ static void clang_indexSourceFile_Impl(void *UserData) {
Persistent,
CXXIdx->getClangResourcesPath(),
OnlyLocalDecls,
- /*CaptureDiagnostics=*/true,
+ CaptureDiagnostics,
PrecompilePreamble,
CacheCodeCompletionResults,
/*IncludeBriefCommentsInCodeCompletion=*/false,
@@ -502,7 +764,7 @@ static void clang_indexTranslationUnit_Impl(void *UserData) {
if (!client_index_callbacks || index_callbacks_size == 0)
return;
- CIndexer *CXXIdx = (CIndexer*)TU->CIdx;
+ CIndexer *CXXIdx = TU->CIdx;
if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing))
setThreadBackgroundPriority();
@@ -520,13 +782,13 @@ static void clang_indexTranslationUnit_Impl(void *UserData) {
IndexCtxCleanup(IndexCtx.get());
OwningPtr<IndexingConsumer> IndexConsumer;
- IndexConsumer.reset(new IndexingConsumer(*IndexCtx));
+ IndexConsumer.reset(new IndexingConsumer(*IndexCtx, 0));
// Recover resources if we crash before exiting this method.
llvm::CrashRecoveryContextCleanupRegistrar<IndexingConsumer>
IndexConsumerCleanup(IndexConsumer.get());
- ASTUnit *Unit = static_cast<ASTUnit *>(TU->TUData);
+ ASTUnit *Unit = cxtu::getASTUnit(TU);
if (!Unit)
return;
@@ -690,12 +952,12 @@ void clang_index_setClientEntity(const CXIdxEntityInfo *info,
}
CXIndexAction clang_IndexAction_create(CXIndex CIdx) {
- // For now, CXIndexAction is featureless.
- return CIdx;
+ return new IndexSessionData(CIdx);
}
void clang_IndexAction_dispose(CXIndexAction idxAction) {
- // For now, CXIndexAction is featureless.
+ if (idxAction)
+ delete static_cast<IndexSessionData *>(idxAction);
}
int clang_indexSourceFile(CXIndexAction idxAction,
@@ -710,6 +972,11 @@ int clang_indexSourceFile(CXIndexAction idxAction,
unsigned num_unsaved_files,
CXTranslationUnit *out_TU,
unsigned TU_options) {
+ LOG_FUNC_SECTION {
+ *Log << source_filename << ": ";
+ for (int i = 0; i != num_command_line_args; ++i)
+ *Log << command_line_args[i] << " ";
+ }
IndexSourceFileInfo ITUI = { idxAction, client_data, index_callbacks,
index_callbacks_size, index_options,
@@ -760,6 +1027,9 @@ int clang_indexTranslationUnit(CXIndexAction idxAction,
unsigned index_callbacks_size,
unsigned index_options,
CXTranslationUnit TU) {
+ LOG_FUNC_SECTION {
+ *Log << TU;
+ }
IndexTranslationUnitInfo ITUI = { idxAction, client_data, index_callbacks,
index_callbacks_size, index_options, TU,
diff --git a/tools/libclang/IndexingContext.cpp b/tools/libclang/IndexingContext.cpp
index d4daa49..3368922 100644
--- a/tools/libclang/IndexingContext.cpp
+++ b/tools/libclang/IndexingContext.cpp
@@ -8,12 +8,11 @@
//===----------------------------------------------------------------------===//
#include "IndexingContext.h"
-#include "CXTranslationUnit.h"
#include "CIndexDiagnostic.h"
-
-#include "clang/Frontend/ASTUnit.h"
+#include "CXTranslationUnit.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/Frontend/ASTUnit.h"
using namespace clang;
using namespace cxindex;
@@ -70,7 +69,7 @@ AttrListInfo::AttrListInfo(const Decl *D, IndexingContext &IdxCtx)
for (AttrVec::const_iterator AttrI = D->attr_begin(), AttrE = D->attr_end();
AttrI != AttrE; ++AttrI) {
const Attr *A = *AttrI;
- CXCursor C = MakeCXCursor(A, const_cast<Decl *>(D), IdxCtx.CXTU);
+ CXCursor C = MakeCXCursor(A, D, IdxCtx.CXTU);
CXIdxLoc Loc = IdxCtx.getIndexLoc(A->getLocation());
switch (C.kind) {
default:
@@ -166,16 +165,16 @@ SourceLocation IndexingContext::CXXBasesListInfo::getBaseLoc(
if (TL.isNull())
return Loc;
- if (const QualifiedTypeLoc *QL = dyn_cast<QualifiedTypeLoc>(&TL))
- TL = QL->getUnqualifiedLoc();
+ if (QualifiedTypeLoc QL = TL.getAs<QualifiedTypeLoc>())
+ TL = QL.getUnqualifiedLoc();
- if (const ElaboratedTypeLoc *EL = dyn_cast<ElaboratedTypeLoc>(&TL))
- return EL->getNamedTypeLoc().getBeginLoc();
- if (const DependentNameTypeLoc *DL = dyn_cast<DependentNameTypeLoc>(&TL))
- return DL->getNameLoc();
- if (const DependentTemplateSpecializationTypeLoc *
- DTL = dyn_cast<DependentTemplateSpecializationTypeLoc>(&TL))
- return DTL->getTemplateNameLoc();
+ if (ElaboratedTypeLoc EL = TL.getAs<ElaboratedTypeLoc>())
+ return EL.getNamedTypeLoc().getBeginLoc();
+ if (DependentNameTypeLoc DL = TL.getAs<DependentNameTypeLoc>())
+ return DL.getNameLoc();
+ if (DependentTemplateSpecializationTypeLoc DTL =
+ TL.getAs<DependentTemplateSpecializationTypeLoc>())
+ return DTL.getTemplateNameLoc();
return Loc;
}
@@ -197,11 +196,11 @@ const char *ScratchAlloc::copyCStr(StringRef Str) {
void IndexingContext::setASTContext(ASTContext &ctx) {
Ctx = &ctx;
- static_cast<ASTUnit*>(CXTU->TUData)->setASTContext(&ctx);
+ cxtu::getASTUnit(CXTU)->setASTContext(&ctx);
}
void IndexingContext::setPreprocessor(Preprocessor &PP) {
- static_cast<ASTUnit*>(CXTU->TUData)->setPreprocessor(&PP);
+ cxtu::getASTUnit(CXTU)->setPreprocessor(&PP);
}
bool IndexingContext::isFunctionLocalDecl(const Decl *D) {
@@ -232,7 +231,9 @@ bool IndexingContext::shouldAbort() {
void IndexingContext::enteredMainFile(const FileEntry *File) {
if (File && CB.enteredMainFile) {
- CXIdxClientFile idxFile = CB.enteredMainFile(ClientData, (CXFile)File, 0);
+ CXIdxClientFile idxFile =
+ CB.enteredMainFile(ClientData,
+ static_cast<CXFile>(const_cast<FileEntry *>(File)), 0);
FileMap[File] = idxFile;
}
}
@@ -248,7 +249,8 @@ void IndexingContext::ppIncludedFile(SourceLocation hashLoc,
ScratchAlloc SA(*this);
CXIdxIncludedFileInfo Info = { getIndexLoc(hashLoc),
SA.toCStr(filename),
- (CXFile)File,
+ static_cast<CXFile>(
+ const_cast<FileEntry *>(File)),
isImport, isAngled, isModuleImport };
CXIdxClientFile idxFile = CB.ppIncludedFile(ClientData, &Info);
FileMap[File] = idxFile;
@@ -264,7 +266,8 @@ void IndexingContext::importedModule(const ImportDecl *ImportD) {
std::string ModuleName = Mod->getFullModuleName();
CXIdxImportedASTFileInfo Info = {
- (CXFile)Mod->getASTFile(),
+ static_cast<CXFile>(
+ const_cast<FileEntry *>(Mod->getASTFile())),
Mod,
getIndexLoc(ImportD->getLocation()),
ImportD->isImplicit()
@@ -278,7 +281,8 @@ void IndexingContext::importedPCH(const FileEntry *File) {
return;
CXIdxImportedASTFileInfo Info = {
- (CXFile)File,
+ static_cast<CXFile>(
+ const_cast<FileEntry *>(File)),
/*module=*/NULL,
getIndexLoc(SourceLocation()),
/*isImplicit=*/false
@@ -365,8 +369,18 @@ bool IndexingContext::handleObjCContainer(const ObjCContainerDecl *D,
}
bool IndexingContext::handleFunction(const FunctionDecl *D) {
- DeclInfo DInfo(!D->isFirstDeclaration(), D->isThisDeclarationADefinition(),
- D->isThisDeclarationADefinition());
+ bool isDef = D->isThisDeclarationADefinition();
+ bool isContainer = isDef;
+ bool isSkipped = false;
+ if (D->hasSkippedBody()) {
+ isSkipped = true;
+ isDef = true;
+ isContainer = false;
+ }
+
+ DeclInfo DInfo(!D->isFirstDeclaration(), isDef, isContainer);
+ if (isSkipped)
+ DInfo.flags |= CXIdxDeclFlag_Skipped;
return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
}
@@ -549,8 +563,18 @@ bool IndexingContext::handleObjCCategoryImpl(const ObjCCategoryImplDecl *D) {
}
bool IndexingContext::handleObjCMethod(const ObjCMethodDecl *D) {
- DeclInfo DInfo(!D->isCanonicalDecl(), D->isThisDeclarationADefinition(),
- D->isThisDeclarationADefinition());
+ bool isDef = D->isThisDeclarationADefinition();
+ bool isContainer = isDef;
+ bool isSkipped = false;
+ if (D->hasSkippedBody()) {
+ isSkipped = true;
+ isDef = true;
+ isContainer = false;
+ }
+
+ DeclInfo DInfo(!D->isCanonicalDecl(), isDef, isContainer);
+ if (isSkipped)
+ DInfo.flags |= CXIdxDeclFlag_Skipped;
return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
}
@@ -625,8 +649,7 @@ bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc,
if (!D)
return false;
- CXCursor Cursor = E ? MakeCXCursor(const_cast<Expr*>(E),
- const_cast<Decl*>(cast<Decl>(DC)), CXTU)
+ CXCursor Cursor = E ? MakeCXCursor(E, cast<Decl>(DC), CXTU)
: getRefCursor(D, Loc);
return handleReference(D, Loc, Cursor, Parent, DC, E, Kind);
}
@@ -808,7 +831,7 @@ IndexingContext::getEntityContainer(const Decl *D) const {
if (const ClassTemplateDecl *ClassTempl = dyn_cast<ClassTemplateDecl>(D)) {
DC = ClassTempl->getTemplatedDecl();
- } if (const FunctionTemplateDecl *
+ } else if (const FunctionTemplateDecl *
FuncTempl = dyn_cast<FunctionTemplateDecl>(D)) {
DC = FuncTempl->getTemplatedDecl();
}
@@ -844,7 +867,7 @@ CXIdxLoc IndexingContext::getIndexLoc(SourceLocation Loc) const {
if (Loc.isInvalid())
return idxLoc;
- idxLoc.ptr_data[0] = (void*)this;
+ idxLoc.ptr_data[0] = const_cast<IndexingContext *>(this);
idxLoc.int_data = Loc.getRawEncoding();
return idxLoc;
}
@@ -870,7 +893,7 @@ void IndexingContext::translateLoc(SourceLocation Loc,
if (indexFile)
*indexFile = getIndexFile(FE);
if (file)
- *file = (void *)FE;
+ *file = const_cast<FileEntry *>(FE);
if (line)
*line = SM.getLineNumber(FID, FileOffset);
if (column)
diff --git a/tools/libclang/IndexingContext.h b/tools/libclang/IndexingContext.h
index 0fc7238..c9097c5 100644
--- a/tools/libclang/IndexingContext.h
+++ b/tools/libclang/IndexingContext.h
@@ -7,11 +7,10 @@
//
//===----------------------------------------------------------------------===//
-#include "Index_Internal.h"
#include "CXCursor.h"
-
-#include "clang/AST/DeclObjC.h"
+#include "Index_Internal.h"
#include "clang/AST/DeclGroup.h"
+#include "clang/AST/DeclObjC.h"
#include "llvm/ADT/DenseSet.h"
#include <deque>
@@ -89,6 +88,7 @@ struct DeclInfo : public CXIdxDeclInfo {
attributes = 0;
numAttributes = 0;
declAsContainer = semanticContainer = lexicalContainer = 0;
+ flags = 0;
}
DeclInfo(DInfoKind K,
bool isRedeclaration, bool isDefinition, bool isContainer)
@@ -99,6 +99,7 @@ struct DeclInfo : public CXIdxDeclInfo {
attributes = 0;
numAttributes = 0;
declAsContainer = semanticContainer = lexicalContainer = 0;
+ flags = 0;
}
};
@@ -493,7 +494,7 @@ private:
void getContainerInfo(const DeclContext *DC, ContainerInfo &ContInfo);
CXCursor getCursor(const Decl *D) {
- return cxcursor::MakeCXCursor(const_cast<Decl*>(D), CXTU);
+ return cxcursor::MakeCXCursor(D, CXTU);
}
CXCursor getRefCursor(const NamedDecl *D, SourceLocation Loc);
diff --git a/tools/libclang/Makefile b/tools/libclang/Makefile
index 93f63cf..f33f345 100644
--- a/tools/libclang/Makefile
+++ b/tools/libclang/Makefile
@@ -16,12 +16,15 @@ LINK_LIBS_IN_SHARED = 1
SHARED_LIBRARY = 1
include $(CLANG_LEVEL)/../../Makefile.config
-LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
-USEDLIBS = clangARCMigrate.a clangRewriteCore.a clangRewriteFrontend.a \
- clangFrontend.a clangDriver.a \
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc
+USEDLIBS = clangFrontend.a clangDriver.a \
+ clangTooling.a \
clangSerialization.a \
- clangParse.a clangSema.a clangEdit.a clangAnalysis.a \
- clangAST.a clangLex.a clangTooling.a clangBasic.a
+ clangParse.a clangSema.a \
+ clangARCMigrate.a clangRewriteFrontend.a clangRewriteCore.a \
+ clangAnalysis.a clangEdit.a \
+ clangAST.a clangLex.a clangBasic.a \
+ clangFormat.a
include $(CLANG_LEVEL)/Makefile
@@ -54,7 +57,7 @@ ifeq ($(HOST_OS),Darwin)
endif
# If we're doing an Apple-style build, add the LTO object path.
- ifeq ($(RC_BUILDIT),YES)
+ ifeq ($(RC_XBS),YES)
TempFile := $(shell mkdir -p ${OBJROOT}/dSYMs ; mktemp ${OBJROOT}/dSYMs/clang-lto.XXXXXX)
LLVMLibsOptions += -Wl,-object_path_lto -Wl,$(TempFile)
endif
diff --git a/tools/libclang/RecursiveASTVisitor.h b/tools/libclang/RecursiveASTVisitor.h
index 4844204..5862e12 100644
--- a/tools/libclang/RecursiveASTVisitor.h
+++ b/tools/libclang/RecursiveASTVisitor.h
@@ -18,6 +18,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
@@ -535,7 +536,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTypeLoc(TypeLoc TL) {
#define ABSTRACT_TYPELOC(CLASS, BASE)
#define TYPELOC(CLASS, BASE) \
case TypeLoc::CLASS: \
- return getDerived().Traverse##CLASS##TypeLoc(*cast<CLASS##TypeLoc>(&TL));
+ return getDerived().Traverse##CLASS##TypeLoc(TL.castAs<CLASS##TypeLoc>());
#include "clang/AST/TypeLocNodes.def"
}
@@ -1199,6 +1200,8 @@ DEF_TRAVERSE_DECL(BlockDecl, {
return true;
})
+DEF_TRAVERSE_DECL(EmptyDecl, { })
+
DEF_TRAVERSE_DECL(FileScopeAsmDecl, {
TRY_TO(TraverseStmt(D->getAsmString()));
})
@@ -1323,6 +1326,14 @@ DEF_TRAVERSE_DECL(UsingDirectiveDecl, {
DEF_TRAVERSE_DECL(UsingShadowDecl, { })
+DEF_TRAVERSE_DECL(OMPThreadPrivateDecl, {
+ for (OMPThreadPrivateDecl::varlist_iterator I = D->varlist_begin(),
+ E = D->varlist_end();
+ I != E; ++I) {
+ TRY_TO(TraverseStmt(*I));
+ }
+ })
+
// A helper method for TemplateDecl's children.
template<typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseTemplateParameterListHelper(
@@ -2027,8 +2038,7 @@ bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) {
if (S->hasExplicitParameters() && S->hasExplicitResultType()) {
// Visit the whole type.
TRY_TO(TraverseTypeLoc(TL));
- } else if (isa<FunctionProtoTypeLoc>(TL)) {
- FunctionProtoTypeLoc Proto = cast<FunctionProtoTypeLoc>(TL);
+ } else if (FunctionProtoTypeLoc Proto = TL.getAs<FunctionProtoTypeLoc>()) {
if (S->hasExplicitParameters()) {
// Visit parameters.
for (unsigned I = 0, N = Proto.getNumArgs(); I != N; ++I) {
diff --git a/tools/libclang/SimpleFormatContext.h b/tools/libclang/SimpleFormatContext.h
new file mode 100644
index 0000000..016d0b6
--- /dev/null
+++ b/tools/libclang/SimpleFormatContext.h
@@ -0,0 +1,75 @@
+//===--- SimpleFormatContext.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+///
+/// \brief Defines a utility class for use of clang-format in libclang
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SIMPLE_FORM_CONTEXT_H
+#define LLVM_CLANG_SIMPLE_FORM_CONTEXT_H
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+
+/// \brief A small class to be used by libclang clients to format
+/// a declaration string in memory. This object is instantiated once
+/// and used each time a formatting is needed.
+class SimpleFormatContext {
+public:
+ SimpleFormatContext(LangOptions Options)
+ : DiagOpts(new DiagnosticOptions()),
+ Diagnostics(new DiagnosticsEngine(new DiagnosticIDs,
+ DiagOpts.getPtr())),
+ Files((FileSystemOptions())),
+ Sources(*Diagnostics, Files),
+ Rewrite(Sources, Options) {
+ Diagnostics->setClient(new IgnoringDiagConsumer, true);
+ }
+
+ ~SimpleFormatContext() { }
+
+ FileID createInMemoryFile(StringRef Name, StringRef Content) {
+ const llvm::MemoryBuffer *Source =
+ llvm::MemoryBuffer::getMemBuffer(Content);
+ const FileEntry *Entry =
+ Files.getVirtualFile(Name, Source->getBufferSize(), 0);
+ Sources.overrideFileContents(Entry, Source, true);
+ assert(Entry != NULL);
+ return Sources.createFileID(Entry, SourceLocation(), SrcMgr::C_User);
+ }
+
+ std::string getRewrittenText(FileID ID) {
+ std::string Result;
+ llvm::raw_string_ostream OS(Result);
+ Rewrite.getEditBuffer(ID).write(OS);
+ OS.flush();
+ return Result;
+ }
+
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics;
+ FileManager Files;
+ SourceManager Sources;
+ Rewriter Rewrite;
+};
+
+} // end namespace clang
+
+#endif
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index 4495b66..d99f24e 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -98,6 +98,8 @@ clang_equalLocations
clang_equalRanges
clang_equalTypes
clang_executeOnThread
+clang_findIncludesInFile
+clang_findIncludesInFileWithBlock
clang_findReferencesInFile
clang_findReferencesInFileWithBlock
clang_formatDiagnostic
@@ -160,10 +162,13 @@ clang_getElementType
clang_getEnumConstantDeclUnsignedValue
clang_getEnumConstantDeclValue
clang_getEnumDeclIntegerType
+clang_getFieldDeclBitWidth
clang_getExpansionLocation
clang_getFile
+clang_getFileLocation
clang_getFileName
clang_getFileTime
+clang_getFileUniqueID
clang_getFunctionTypeCallingConv
clang_getIBOutletCollectionType
clang_getIncludedFile
@@ -202,6 +207,7 @@ clang_getTranslationUnitCursor
clang_getTranslationUnitSpelling
clang_getTypeDeclaration
clang_getTypeKindSpelling
+clang_getTypeSpelling
clang_getTypedefDeclUnderlyingType
clang_hashCursor
clang_indexLoc_getCXSourceLocation
@@ -250,6 +256,7 @@ clang_tokenize
clang_CompilationDatabase_fromDirectory
clang_CompilationDatabase_dispose
clang_CompilationDatabase_getCompileCommands
+clang_CompilationDatabase_getAllCompileCommands
clang_CompileCommands_dispose
clang_CompileCommands_getSize
clang_CompileCommands_getCommand
diff --git a/tools/scan-build/ccc-analyzer b/tools/scan-build/ccc-analyzer
index 8717225..bb6dd95 100755
--- a/tools/scan-build/ccc-analyzer
+++ b/tools/scan-build/ccc-analyzer
@@ -31,11 +31,11 @@ my $DefaultCCompiler;
my $DefaultCXXCompiler;
if (`uname -a` =~ m/Darwin/) {
- $DefaultCCompiler = 'clang';
- $DefaultCXXCompiler = 'clang++';
+ $DefaultCCompiler = 'clang';
+ $DefaultCXXCompiler = 'clang++';
} else {
- $DefaultCCompiler = 'gcc';
- $DefaultCXXCompiler = 'g++';
+ $DefaultCCompiler = 'gcc';
+ $DefaultCXXCompiler = 'g++';
}
if ($FindBin::Script =~ /c\+\+-analyzer/) {
@@ -252,6 +252,7 @@ sub Analyze {
print $ofh $_;
print STDERR $_;
}
+ close $ofh;
waitpid($pid,0);
close(FROM_CHILD);
@@ -269,7 +270,7 @@ sub Analyze {
$HtmlDir, $ParserRejects, $ofile);
} else {
ProcessClangFailure($Clang, $Lang, $file, \@CmdArgsSansAnalyses,
- $HtmlDir, $OtherError, $ofile);
+ $HtmlDir, $OtherError, $ofile);
}
}
else {
@@ -389,6 +390,7 @@ my %LangMap = (
'cxx' => 'c++',
'txx' => 'c++',
'cc' => 'c++',
+ 'C' => 'c++',
'ii' => 'c++',
'i' => 'c-cpp-output',
'm' => 'objective-c',
@@ -489,6 +491,15 @@ foreach (my $i = 0; $i < scalar(@ARGV); ++$i) {
while ($Cnt > 0) { ++$i; --$Cnt; push @CompileOpts, $ARGV[$i]; }
next;
}
+ if ($Arg =~ /-msse.*/) {
+ push @CompileOpts,$Arg;
+ next;
+ }
+ # Handle the case where there isn't a space after -iquote
+ if ($Arg =~ /-iquote.*/) {
+ push @CompileOpts,$Arg;
+ next;
+ }
# Options with possible arguments that should pass through to linker.
if (defined $LinkerOptionMap{$ArgKey}) {
@@ -617,7 +628,7 @@ if ($Action eq 'compile' or $Action eq 'link') {
my @Archs = keys %ArchsSeen;
# Skip the file if we don't support the architectures specified.
exit 0 if ($HadArch && scalar(@Archs) == 0);
-
+
foreach my $file (@Files) {
# Determine the language for the file.
my $FileLang = $Lang;
@@ -671,7 +682,7 @@ if ($Action eq 'compile' or $Action eq 'link') {
$ResultFile = $f;
# If the HtmlDir is not set, we sould clean up the plist files.
if (!defined $HtmlDir || -z $HtmlDir) {
- $CleanupFile = $f;
+ $CleanupFile = $f;
}
}
}
diff --git a/tools/scan-build/scan-build b/tools/scan-build/scan-build
index a13b235..32eecc0 100755
--- a/tools/scan-build/scan-build
+++ b/tools/scan-build/scan-build
@@ -17,6 +17,7 @@ use warnings;
use FindBin qw($RealBin);
use Digest::MD5;
use File::Basename;
+use File::Find;
use Term::ANSIColor;
use Term::ANSIColor qw(:constants);
use Cwd qw/ getcwd abs_path /;
@@ -57,6 +58,16 @@ sub Diag {
}
}
+sub ErrorDiag {
+ if ($UseColor) {
+ print STDERR BOLD, RED "$Prog: ";
+ print STDERR RESET, RED @_;
+ print STDERR RESET;
+ } else {
+ print STDERR "$Prog: @_";
+ }
+}
+
sub DiagCrashes {
my $Dir = shift;
Diag ("The analyzer encountered problems on some source files.\n");
@@ -67,14 +78,14 @@ sub DiagCrashes {
sub DieDiag {
if ($UseColor) {
- print BOLD, RED "$Prog: ";
- print RESET, RED @_;
- print RESET;
+ print STDERR BOLD, RED "$Prog: ";
+ print STDERR RESET, RED @_;
+ print STDERR RESET;
}
else {
- print "$Prog: ", @_;
+ print STDERR "$Prog: ", @_;
}
- exit(0);
+ exit 1;
}
##----------------------------------------------------------------------------##
@@ -89,7 +100,7 @@ if (grep /^--help-checkers$/, @ARGV) {
my ($sign, $name, @text) = split ' ', $_;
print $name, $/ if $sign eq '+';
}
- exit 1;
+ exit 0;
}
##----------------------------------------------------------------------------##
@@ -110,13 +121,8 @@ sub GetHTMLRunDir {
my $Dir = shift @_;
my $TmpMode = 0;
if (!defined $Dir) {
- if (`uname` =~ /Darwin/) {
- $Dir = $ENV{'TMPDIR'};
- if (!defined $Dir) { $Dir = "/tmp"; }
- }
- else {
- $Dir = "/tmp";
- }
+ $Dir = $ENV{'TMPDIR'};
+ if (!defined $Dir) { $Dir = "/tmp"; }
$TmpMode = 1;
}
@@ -288,10 +294,11 @@ sub UpdateInFilePath {
sub AddStatLine {
my $Line = shift;
my $Stats = shift;
+ my $File = shift;
print $Line . "\n";
- my $Regex = qr/(.*?)\ :\ (.*?)\ ->\ Total\ CFGBlocks:\ (\d+)\ \|\ Unreachable
+ my $Regex = qr/(.*?)\ ->\ Total\ CFGBlocks:\ (\d+)\ \|\ Unreachable
\ CFGBlocks:\ (\d+)\ \|\ Exhausted\ Block:\ (yes|no)\ \|\ Empty\ WorkList:
\ (yes|no)/x;
@@ -301,12 +308,12 @@ sub AddStatLine {
# Create a hash of the interesting fields
my $Row = {
- Filename => $1,
- Function => $2,
- Total => $3,
- Unreachable => $4,
- Aborted => $5,
- Empty => $6
+ Filename => $File,
+ Function => $1,
+ Total => $2,
+ Unreachable => $3,
+ Aborted => $4,
+ Empty => $5
};
# Add them to the stats array
@@ -387,7 +394,7 @@ sub ScanFile {
# Don't add internal statistics to the bug reports
if ($BugCategory =~ /statistics/i) {
- AddStatLine($BugDescription, $Stats);
+ AddStatLine($BugDescription, $Stats, $BugFile);
return;
}
@@ -475,11 +482,24 @@ sub CalcStats {
# Postprocess - Postprocess the results of an analysis scan.
##----------------------------------------------------------------------------##
+my @filesFound;
+my $baseDir;
+sub FileWanted {
+ my $baseDirRegEx = quotemeta $baseDir;
+ my $file = $File::Find::name;
+ if ($file =~ /report-.*\.html$/) {
+ my $relative_file = $file;
+ $relative_file =~ s/$baseDirRegEx//g;
+ push @filesFound, $relative_file;
+ }
+}
+
sub Postprocess {
my $Dir = shift;
my $BaseDir = shift;
my $AnalyzerStats = shift;
+ my $KeepEmpty = shift;
die "No directory specified." if (!defined $Dir);
@@ -487,21 +507,23 @@ sub Postprocess {
Diag("No bugs found.\n");
return 0;
}
-
- opendir(DIR, $Dir);
- my @files = grep { /^report-.*\.html$/ } readdir(DIR);
- closedir(DIR);
- if (scalar(@files) == 0 and ! -e "$Dir/failures") {
- Diag("Removing directory '$Dir' because it contains no reports.\n");
- system ("rm", "-fR", $Dir);
+ $baseDir = $Dir . "/";
+ find({ wanted => \&FileWanted, follow => 0}, $Dir);
+
+ if (scalar(@filesFound) == 0 and ! -e "$Dir/failures") {
+ if (! $KeepEmpty) {
+ Diag("Removing directory '$Dir' because it contains no reports.\n");
+ system ("rm", "-fR", $Dir);
+ }
+ Diag("No bugs found.\n");
return 0;
}
# Scan each report file and build an index.
my @Index;
my @Stats;
- foreach my $file (@files) { ScanFile(\@Index, $Dir, $file, \@Stats); }
+ foreach my $file (@filesFound) { ScanFile(\@Index, $Dir, $file, \@Stats); }
# Scan the failures directory and use the information in the .info files
# to update the common prefix directory.
@@ -603,7 +625,7 @@ print OUT <<ENDTEXT;
</table>
ENDTEXT
- if (scalar(@files)) {
+ if (scalar(@filesFound)) {
# Print out the summary table.
my %Totals;
@@ -884,6 +906,39 @@ sub RunXcodebuild {
if ($IgnoreErrors) {
AddIfNotPresent($Args,"-PBXBuildsContinueAfterErrors=YES");
}
+
+ # Detect the version of Xcode. If Xcode 4.6 or higher, use new
+ # in situ support for analyzer interposition without needed to override
+ # the compiler.
+ open(DETECT_XCODE, "xcodebuild -version |") or
+ die "error: cannot detect version of xcodebuild\n";
+
+ my $oldBehavior = 1;
+
+ while(<DETECT_XCODE>) {
+ if (/^Xcode (.+)$/) {
+ my $ver = $1;
+ if ($ver =~ /^([0-9]+[.][0-9]+)[^0-9]?/) {
+ if ($1 >= 4.6) {
+ $oldBehavior = 0;
+ last;
+ }
+ }
+ }
+ }
+ close(DETECT_XCODE);
+
+ if ($oldBehavior == 0) {
+ my $OutputDir = $Options->{"OUTPUT_DIR"};
+ my $CLANG = $Options->{"CLANG"};
+ push @$Args,
+ "RUN_CLANG_STATIC_ANALYZER=YES",
+ "CLANG_ANALYZER_OUTPUT=plist-html",
+ "CLANG_ANALYZER_EXEC=$CLANG",
+ "CLANG_ANALYZER_OUTPUT_DIR=$OutputDir";
+
+ return (system(@$Args) >> 8);
+ }
# Default to old behavior where we insert a bogus compiler.
SetEnv($Options);
@@ -1086,7 +1141,11 @@ ADVANCED OPTIONS:
scan-build uses the 'clang' executable relative to itself for static
analysis. One can override this behavior with this option by using the
'clang' packaged with Xcode (on OS X) or from the PATH.
-
+
+ --keep-empty
+
+ Don't remove the build results directory even if no issues were reported.
+
CONTROLLING CHECKERS:
A default group of checkers are always run unless explicitly disabled.
@@ -1253,6 +1312,7 @@ my $HtmlDir; # Parent directory to store HTML files.
my $IgnoreErrors = 0; # Ignore build errors.
my $ViewResults = 0; # View results when the build terminates.
my $ExitStatusFoundBugs = 0; # Exit status reflects whether bugs were found
+my $KeepEmpty = 0; # Don't remove output directory even with 0 results.
my @AnalysesToRun;
my $StoreModel;
my $ConstraintsModel;
@@ -1260,16 +1320,14 @@ my $InternalStats;
my $OutputFormat = "html";
my $AnalyzerStats = 0;
my $MaxLoop = 0;
+my $RequestDisplayHelp = 0;
+my $ForceDisplayHelp = 0;
+my $AnalyzerDiscoveryMethod;
if (!@ARGV) {
- DisplayHelp();
- exit 1;
+ $ForceDisplayHelp = 1
}
-
-my $displayHelp = 0;
-my $AnalyzerDiscoveryMethod;
-
while (@ARGV) {
# Scan for options we recognize.
@@ -1277,7 +1335,7 @@ while (@ARGV) {
my $arg = $ARGV[0];
if ($arg eq "-h" or $arg eq "--help") {
- $displayHelp = 1;
+ $RequestDisplayHelp = 1;
shift @ARGV;
next;
}
@@ -1446,15 +1504,20 @@ while (@ARGV) {
$AnalyzerDiscoveryMethod = $1;
next;
}
+ if ($arg eq "--keep-empty") {
+ shift @ARGV;
+ $KeepEmpty = 1;
+ next;
+ }
DieDiag("unrecognized option '$arg'\n") if ($arg =~ /^-/);
last;
}
-if (!@ARGV and $displayHelp == 0) {
- Diag("No build command specified.\n\n");
- $displayHelp = 1;
+if (!@ARGV and !$RequestDisplayHelp) {
+ ErrorDiag("No build command specified.\n\n");
+ $ForceDisplayHelp = 1;
}
# Find 'clang'
@@ -1464,7 +1527,7 @@ if (!defined $AnalyzerDiscoveryMethod) {
$Clang = Cwd::realpath("$RealBin/clang");
}
if (!defined $Clang || ! -x $Clang) {
- if (!$displayHelp) {
+ if (!$RequestDisplayHelp && !$ForceDisplayHelp) {
DieDiag("error: Cannot find an executable 'clang' relative to scan-build." .
" Consider using --use-analyzer to pick a version of 'clang' to use for static analysis.\n");
}
@@ -1485,21 +1548,22 @@ else {
}
else {
$Clang = Cwd::realpath($AnalyzerDiscoveryMethod);
- if (! -x $Clang) {
- DieDiag("Cannot find an executable clang at '$Clang'\n");
+ if (!defined $Clang or not -x $Clang) {
+ DieDiag("Cannot find an executable clang at '$AnalyzerDiscoveryMethod'\n");
}
}
}
-if ($displayHelp) {
+if ($ForceDisplayHelp || $RequestDisplayHelp) {
DisplayHelp();
- exit 1;
+ exit $ForceDisplayHelp;
}
$ClangCXX = $Clang;
$ClangCXX =~ s/\-\d+\.\d+$//;
$ClangCXX .= "++";
-$ClangVersion = HtmlEscape(`$Clang --version`);
+# Make sure to use "" to handle paths with spaces.
+$ClangVersion = HtmlEscape(`"$Clang" --version`);
# Determine where results go.
$CmdArgs = HtmlEscape(join(' ', map(ShellEscape($_), @ARGV)));
@@ -1568,9 +1632,9 @@ if (defined $OutputFormat) {
Diag "Analysis run complete.\n";
Diag "Analysis results (plist files) deposited in '$HtmlDir'\n";
}
- elsif ($OutputFormat =~ /html/) {
+ if ($OutputFormat =~ /html/) {
# Postprocess the HTML directory.
- my $NumBugs = Postprocess($HtmlDir, $BaseDir, $AnalyzerStats);
+ my $NumBugs = Postprocess($HtmlDir, $BaseDir, $AnalyzerStats, $KeepEmpty);
if ($ViewResults and -r "$HtmlDir/index.html") {
Diag "Analysis run complete.\n";
diff --git a/tools/scan-build/set-xcode-analyzer b/tools/scan-build/set-xcode-analyzer
index 93824af..3076b39 100755
--- a/tools/scan-build/set-xcode-analyzer
+++ b/tools/scan-build/set-xcode-analyzer
@@ -4,9 +4,13 @@
# want to the use the system version of Python on Mac OS X.
# This one has the scripting bridge enabled.
+import sys
+if sys.version_info < (2, 7):
+ print "set-xcode-analyzer requires Python 2.7 or later"
+ sys.exit(1)
+
import os
import subprocess
-import sys
import re
import tempfile
import shutil
@@ -41,6 +45,8 @@ def ModifySpec(path, isBuiltinAnalyzer, pathToChecker):
m = re.search('^(\s*ExecPath\s*=\s*")', line)
if m:
line = "".join([m.group(0), pathToChecker, '";\n'])
+ # Do not modify further ExecPath's later in the xcspec.
+ foundAnalyzer = False
t.write(line)
t.close()
print "(+) processing:", path
@@ -70,7 +76,7 @@ def main():
for x in NSWorkspace.sharedWorkspace().runningApplications():
if x.localizedName().find("Xcode") >= 0:
print "(-) You must quit Xcode first before modifying its configuration files."
- return
+ sys.exit(1)
isBuiltinAnalyzer = False
if options.path:
diff --git a/unittests/AST/ASTContextParentMapTest.cpp b/unittests/AST/ASTContextParentMapTest.cpp
new file mode 100644
index 0000000..c1910a8
--- /dev/null
+++ b/unittests/AST/ASTContextParentMapTest.cpp
@@ -0,0 +1,71 @@
+//===- unittest/AST/ASTContextParentMapTest.cpp - AST parent map test -----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Tests for the getParents(...) methods of ASTContext.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+#include "MatchVerifier.h"
+
+namespace clang {
+namespace ast_matchers {
+
+using clang::tooling::newFrontendActionFactory;
+using clang::tooling::runToolOnCodeWithArgs;
+using clang::tooling::FrontendActionFactory;
+
+TEST(GetParents, ReturnsParentForDecl) {
+ MatchVerifier<Decl> Verifier;
+ EXPECT_TRUE(Verifier.match("class C { void f(); };",
+ methodDecl(hasParent(recordDecl(hasName("C"))))));
+}
+
+TEST(GetParents, ReturnsParentForStmt) {
+ MatchVerifier<Stmt> Verifier;
+ EXPECT_TRUE(Verifier.match("class C { void f() { if (true) {} } };",
+ ifStmt(hasParent(compoundStmt()))));
+}
+
+TEST(GetParents, ReturnsParentInsideTemplateInstantiations) {
+ MatchVerifier<Decl> DeclVerifier;
+ EXPECT_TRUE(DeclVerifier.match(
+ "template<typename T> struct C { void f() {} };"
+ "void g() { C<int> c; c.f(); }",
+ methodDecl(hasName("f"),
+ hasParent(recordDecl(isTemplateInstantiation())))));
+ EXPECT_TRUE(DeclVerifier.match(
+ "template<typename T> struct C { void f() {} };"
+ "void g() { C<int> c; c.f(); }",
+ methodDecl(hasName("f"),
+ hasParent(recordDecl(unless(isTemplateInstantiation()))))));
+ EXPECT_FALSE(DeclVerifier.match(
+ "template<typename T> struct C { void f() {} };"
+ "void g() { C<int> c; c.f(); }",
+ methodDecl(hasName("f"),
+ allOf(hasParent(recordDecl(unless(isTemplateInstantiation()))),
+ hasParent(recordDecl(isTemplateInstantiation()))))));
+}
+
+TEST(GetParents, ReturnsMultipleParentsInTemplateInstantiations) {
+ MatchVerifier<Stmt> TemplateVerifier;
+ EXPECT_TRUE(TemplateVerifier.match(
+ "template<typename T> struct C { void f() {} };"
+ "void g() { C<int> c; c.f(); }",
+ compoundStmt(
+ allOf(hasAncestor(recordDecl(isTemplateInstantiation())),
+ hasAncestor(recordDecl(unless(isTemplateInstantiation())))))));
+}
+
+} // end namespace ast_matchers
+} // end namespace clang
diff --git a/unittests/AST/CMakeLists.txt b/unittests/AST/CMakeLists.txt
index 1ea293e..ad29428 100644
--- a/unittests/AST/CMakeLists.txt
+++ b/unittests/AST/CMakeLists.txt
@@ -1,4 +1,5 @@
add_clang_unittest(ASTTests
+ ASTContextParentMapTest.cpp
CommentLexer.cpp
CommentParser.cpp
DeclPrinterTest.cpp
diff --git a/unittests/AST/CommentLexer.cpp b/unittests/AST/CommentLexer.cpp
index 2723a61..507daf8 100644
--- a/unittests/AST/CommentLexer.cpp
+++ b/unittests/AST/CommentLexer.cpp
@@ -7,16 +7,16 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/DiagnosticOptions.h"
#include "clang/AST/CommentLexer.h"
#include "clang/AST/CommentCommandTraits.h"
+#include "clang/Basic/CommentOptions.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/STLExtras.h"
-#include <vector>
-
#include "gtest/gtest.h"
+#include <vector>
using namespace llvm;
using namespace clang;
@@ -32,7 +32,7 @@ protected:
DiagID(new DiagnosticIDs()),
Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
SourceMgr(Diags, FileMgr),
- Traits(Allocator) {
+ Traits(Allocator, CommentOptions()) {
}
FileSystemOptions FileMgrOpts;
@@ -301,8 +301,10 @@ TEST_F(CommentLexerTest, DoxygenCommand3) {
// Doxygen escape sequences.
TEST_F(CommentLexerTest, DoxygenCommand4) {
- const char *Source =
- "/// \\\\ \\@ \\& \\$ \\# \\< \\> \\% \\\" \\. \\::";
+ const char *Sources[] = {
+ "/// \\\\ \\@ \\& \\$ \\# \\< \\> \\% \\\" \\. \\::",
+ "/// @\\ @@ @& @$ @# @< @> @% @\" @. @::"
+ };
const char *Text[] = {
" ",
"\\", " ", "@", " ", "&", " ", "$", " ", "#", " ",
@@ -310,16 +312,18 @@ TEST_F(CommentLexerTest, DoxygenCommand4) {
"::", ""
};
- std::vector<Token> Toks;
+ for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
+ std::vector<Token> Toks;
- lexString(Source, Toks);
+ lexString(Sources[i], Toks);
- ASSERT_EQ(array_lengthof(Text), Toks.size());
+ ASSERT_EQ(array_lengthof(Text), Toks.size());
- for (size_t i = 0, e = Toks.size(); i != e; i++) {
- if(Toks[i].is(tok::text))
- ASSERT_EQ(StringRef(Text[i]), Toks[i].getText())
- << "index " << i;
+ for (size_t j = 0, e = Toks.size(); j != e; j++) {
+ if(Toks[j].is(tok::text))
+ ASSERT_EQ(StringRef(Text[j]), Toks[j].getText())
+ << "index " << i;
+ }
}
}
@@ -362,7 +366,7 @@ TEST_F(CommentLexerTest, DoxygenCommand6) {
ASSERT_EQ(tok::text, Toks[0].getKind());
ASSERT_EQ(StringRef(" "), Toks[0].getText());
- ASSERT_EQ(tok::command, Toks[1].getKind());
+ ASSERT_EQ(tok::backslash_command, Toks[1].getKind());
ASSERT_EQ(StringRef("brief"), getCommandName(Toks[1]));
ASSERT_EQ(tok::text, Toks[2].getKind());
@@ -382,28 +386,60 @@ TEST_F(CommentLexerTest, DoxygenCommand7) {
ASSERT_EQ(tok::text, Toks[0].getKind());
ASSERT_EQ(StringRef(" "), Toks[0].getText());
- ASSERT_EQ(tok::command, Toks[1].getKind());
+ ASSERT_EQ(tok::backslash_command, Toks[1].getKind());
ASSERT_EQ(StringRef("em"), getCommandName(Toks[1]));
- ASSERT_EQ(tok::command, Toks[2].getKind());
+ ASSERT_EQ(tok::backslash_command, Toks[2].getKind());
ASSERT_EQ(StringRef("em"), getCommandName(Toks[2]));
ASSERT_EQ(tok::text, Toks[3].getKind());
ASSERT_EQ(StringRef(" "), Toks[3].getText());
- ASSERT_EQ(tok::command, Toks[4].getKind());
+ ASSERT_EQ(tok::backslash_command, Toks[4].getKind());
ASSERT_EQ(StringRef("em"), getCommandName(Toks[4]));
ASSERT_EQ(tok::text, Toks[5].getKind());
ASSERT_EQ(StringRef("\t"), Toks[5].getText());
- ASSERT_EQ(tok::command, Toks[6].getKind());
+ ASSERT_EQ(tok::backslash_command, Toks[6].getKind());
ASSERT_EQ(StringRef("em"), getCommandName(Toks[6]));
ASSERT_EQ(tok::newline, Toks[7].getKind());
}
TEST_F(CommentLexerTest, DoxygenCommand8) {
+ const char *Source = "/// @em@em @em\t@em\n";
+ std::vector<Token> Toks;
+
+ lexString(Source, Toks);
+
+ ASSERT_EQ(8U, Toks.size());
+
+ ASSERT_EQ(tok::text, Toks[0].getKind());
+ ASSERT_EQ(StringRef(" "), Toks[0].getText());
+
+ ASSERT_EQ(tok::at_command, Toks[1].getKind());
+ ASSERT_EQ(StringRef("em"), getCommandName(Toks[1]));
+
+ ASSERT_EQ(tok::at_command, Toks[2].getKind());
+ ASSERT_EQ(StringRef("em"), getCommandName(Toks[2]));
+
+ ASSERT_EQ(tok::text, Toks[3].getKind());
+ ASSERT_EQ(StringRef(" "), Toks[3].getText());
+
+ ASSERT_EQ(tok::at_command, Toks[4].getKind());
+ ASSERT_EQ(StringRef("em"), getCommandName(Toks[4]));
+
+ ASSERT_EQ(tok::text, Toks[5].getKind());
+ ASSERT_EQ(StringRef("\t"), Toks[5].getText());
+
+ ASSERT_EQ(tok::at_command, Toks[6].getKind());
+ ASSERT_EQ(StringRef("em"), getCommandName(Toks[6]));
+
+ ASSERT_EQ(tok::newline, Toks[7].getKind());
+}
+
+TEST_F(CommentLexerTest, DoxygenCommand9) {
const char *Source = "/// \\aaa\\bbb \\ccc\t\\ddd\n";
std::vector<Token> Toks;
@@ -435,7 +471,7 @@ TEST_F(CommentLexerTest, DoxygenCommand8) {
ASSERT_EQ(tok::newline, Toks[7].getKind());
}
-TEST_F(CommentLexerTest, DoxygenCommand9) {
+TEST_F(CommentLexerTest, DoxygenCommand10) {
const char *Source = "// \\c\n";
std::vector<Token> Toks;
@@ -446,12 +482,95 @@ TEST_F(CommentLexerTest, DoxygenCommand9) {
ASSERT_EQ(tok::text, Toks[0].getKind());
ASSERT_EQ(StringRef(" "), Toks[0].getText());
- ASSERT_EQ(tok::command, Toks[1].getKind());
+ ASSERT_EQ(tok::backslash_command, Toks[1].getKind());
ASSERT_EQ(StringRef("c"), getCommandName(Toks[1]));
ASSERT_EQ(tok::newline, Toks[2].getKind());
}
+TEST_F(CommentLexerTest, RegisterCustomBlockCommand) {
+ const char *Source =
+ "/// \\NewBlockCommand Aaa.\n"
+ "/// @NewBlockCommand Aaa.\n";
+
+ Traits.registerBlockCommand(StringRef("NewBlockCommand"));
+
+ std::vector<Token> Toks;
+
+ lexString(Source, Toks);
+
+ ASSERT_EQ(8U, Toks.size());
+
+ ASSERT_EQ(tok::text, Toks[0].getKind());
+ ASSERT_EQ(StringRef(" "), Toks[0].getText());
+
+ ASSERT_EQ(tok::backslash_command, Toks[1].getKind());
+ ASSERT_EQ(StringRef("NewBlockCommand"), getCommandName(Toks[1]));
+
+ ASSERT_EQ(tok::text, Toks[2].getKind());
+ ASSERT_EQ(StringRef(" Aaa."), Toks[2].getText());
+
+ ASSERT_EQ(tok::newline, Toks[3].getKind());
+
+ ASSERT_EQ(tok::text, Toks[4].getKind());
+ ASSERT_EQ(StringRef(" "), Toks[4].getText());
+
+ ASSERT_EQ(tok::at_command, Toks[5].getKind());
+ ASSERT_EQ(StringRef("NewBlockCommand"), getCommandName(Toks[5]));
+
+ ASSERT_EQ(tok::text, Toks[6].getKind());
+ ASSERT_EQ(StringRef(" Aaa."), Toks[6].getText());
+
+ ASSERT_EQ(tok::newline, Toks[7].getKind());
+}
+
+TEST_F(CommentLexerTest, RegisterMultipleBlockCommands) {
+ const char *Source =
+ "/// \\Foo\n"
+ "/// \\Bar Baz\n"
+ "/// \\Blech quux=corge\n";
+
+ Traits.registerBlockCommand(StringRef("Foo"));
+ Traits.registerBlockCommand(StringRef("Bar"));
+ Traits.registerBlockCommand(StringRef("Blech"));
+
+ std::vector<Token> Toks;
+
+ lexString(Source, Toks);
+
+ ASSERT_EQ(11U, Toks.size());
+
+ ASSERT_EQ(tok::text, Toks[0].getKind());
+ ASSERT_EQ(StringRef(" "), Toks[0].getText());
+
+ ASSERT_EQ(tok::backslash_command, Toks[1].getKind());
+ ASSERT_EQ(StringRef("Foo"), getCommandName(Toks[1]));
+
+ ASSERT_EQ(tok::newline, Toks[2].getKind());
+
+ ASSERT_EQ(tok::text, Toks[3].getKind());
+ ASSERT_EQ(StringRef(" "), Toks[3].getText());
+
+ ASSERT_EQ(tok::backslash_command, Toks[4].getKind());
+ ASSERT_EQ(StringRef("Bar"), getCommandName(Toks[4]));
+
+ ASSERT_EQ(tok::text, Toks[5].getKind());
+ ASSERT_EQ(StringRef(" Baz"), Toks[5].getText());
+
+ ASSERT_EQ(tok::newline, Toks[6].getKind());
+
+ ASSERT_EQ(tok::text, Toks[7].getKind());
+ ASSERT_EQ(StringRef(" "), Toks[7].getText());
+
+ ASSERT_EQ(tok::backslash_command, Toks[8].getKind());
+ ASSERT_EQ(StringRef("Blech"), getCommandName(Toks[8]));
+
+ ASSERT_EQ(tok::text, Toks[9].getKind());
+ ASSERT_EQ(StringRef(" quux=corge"), Toks[9].getText());
+
+ ASSERT_EQ(tok::newline, Toks[10].getKind());
+}
+
// Empty verbatim block.
TEST_F(CommentLexerTest, VerbatimBlock1) {
const char *Sources[] = {
@@ -1662,7 +1781,8 @@ TEST_F(CommentLexerTest, HTMLCharacterReferences16) {
const char *Sources[] = {
"// &#61;",
"// &#x3d;",
- "// &#X3d;"
+ "// &#X3d;",
+ "// &#X3D;"
};
for (size_t i = 0, e = array_lengthof(Sources); i != e; i++) {
diff --git a/unittests/AST/CommentParser.cpp b/unittests/AST/CommentParser.cpp
index 8fde247..3dce60a 100644
--- a/unittests/AST/CommentParser.cpp
+++ b/unittests/AST/CommentParser.cpp
@@ -7,20 +7,20 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/AST/CommentParser.h"
#include "clang/AST/Comment.h"
+#include "clang/AST/CommentCommandTraits.h"
#include "clang/AST/CommentLexer.h"
-#include "clang/AST/CommentParser.h"
#include "clang/AST/CommentSema.h"
-#include "clang/AST/CommentCommandTraits.h"
+#include "clang/Basic/CommentOptions.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Allocator.h"
-#include <vector>
-
#include "gtest/gtest.h"
+#include <vector>
using namespace llvm;
using namespace clang;
@@ -39,7 +39,7 @@ protected:
DiagID(new DiagnosticIDs()),
Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
SourceMgr(Diags, FileMgr),
- Traits(Allocator) {
+ Traits(Allocator, CommentOptions()) {
}
FileSystemOptions FileMgrOpts;
diff --git a/unittests/AST/DeclPrinterTest.cpp b/unittests/AST/DeclPrinterTest.cpp
index a2fc839..44fa742 100644
--- a/unittests/AST/DeclPrinterTest.cpp
+++ b/unittests/AST/DeclPrinterTest.cpp
@@ -412,8 +412,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl1) {
" A();"
"};",
constructorDecl(ofClass(hasName("A"))).bind("id"),
- ""));
- // WRONG; Should be: "A();"
+ "A()"));
}
TEST(DeclPrinter, TestCXXConstructorDecl2) {
@@ -422,8 +421,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl2) {
" A(int a);"
"};",
constructorDecl(ofClass(hasName("A"))).bind("id"),
- ""));
- // WRONG; Should be: "A(int a);"
+ "A(int a)"));
}
TEST(DeclPrinter, TestCXXConstructorDecl3) {
@@ -432,8 +430,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl3) {
" A(const A &a);"
"};",
constructorDecl(ofClass(hasName("A"))).bind("id"),
- ""));
- // WRONG; Should be: "A(const A &a);"
+ "A(const A &a)"));
}
TEST(DeclPrinter, TestCXXConstructorDecl4) {
@@ -442,8 +439,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl4) {
" A(const A &a, int = 0);"
"};",
constructorDecl(ofClass(hasName("A"))).bind("id"),
- ""));
- // WRONG; Should be: "A(const A &a, int = 0);"
+ "A(const A &a, int = 0)"));
}
TEST(DeclPrinter, TestCXXConstructorDecl5) {
@@ -452,8 +448,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl5) {
" A(const A &&a);"
"};",
constructorDecl(ofClass(hasName("A"))).bind("id"),
- ""));
- // WRONG; Should be: "A(const A &&a);"
+ "A(const A &&a)"));
}
TEST(DeclPrinter, TestCXXConstructorDecl6) {
@@ -462,8 +457,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl6) {
" explicit A(int a);"
"};",
constructorDecl(ofClass(hasName("A"))).bind("id"),
- ""));
- // WRONG; Should be: "explicit A(int a);"
+ "explicit A(int a)"));
}
TEST(DeclPrinter, TestCXXConstructorDecl7) {
@@ -472,7 +466,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl7) {
" constexpr A();"
"};",
constructorDecl(ofClass(hasName("A"))).bind("id"),
- ""));
+ "A()"));
// WRONG; Should be: "constexpr A();"
}
@@ -482,8 +476,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl8) {
" A() = default;"
"};",
constructorDecl(ofClass(hasName("A"))).bind("id"),
- ""));
- // WRONG; Should be: "A() = default;"
+ "A() = default"));
}
TEST(DeclPrinter, TestCXXConstructorDecl9) {
@@ -492,8 +485,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl9) {
" A() = delete;"
"};",
constructorDecl(ofClass(hasName("A"))).bind("id"),
- " = delete"));
- // WRONG; Should be: "A() = delete;"
+ "A() = delete"));
}
TEST(DeclPrinter, TestCXXConstructorDecl10) {
@@ -503,8 +495,7 @@ TEST(DeclPrinter, TestCXXConstructorDecl10) {
" A(const A &a);"
"};",
constructorDecl(ofClass(hasName("A"))).bind("id"),
- ""));
- // WRONG; Should be: "A(const A &a);"
+ "A<T...>(const A<T...> &a)"));
}
#if !defined(_MSC_VER)
@@ -1246,3 +1237,21 @@ TEST(DeclPrinter, TestObjCMethod1) {
"- (int) A:(id)anObject inRange:(long)range"));
}
+TEST(DeclPrinter, TestObjCProtocol1) {
+ ASSERT_TRUE(PrintedDeclObjCMatches(
+ "@protocol P1, P2;",
+ namedDecl(hasName("P1")).bind("id"),
+ "@protocol P1;\n"));
+ ASSERT_TRUE(PrintedDeclObjCMatches(
+ "@protocol P1, P2;",
+ namedDecl(hasName("P2")).bind("id"),
+ "@protocol P2;\n"));
+}
+
+TEST(DeclPrinter, TestObjCProtocol2) {
+ ASSERT_TRUE(PrintedDeclObjCMatches(
+ "@protocol P2 @end"
+ "@protocol P1<P2> @end",
+ namedDecl(hasName("P1")).bind("id"),
+ "@protocol P1<P2>\n@end"));
+}
diff --git a/unittests/AST/Makefile b/unittests/AST/Makefile
index e07fc45..4fb2f5b 100644
--- a/unittests/AST/Makefile
+++ b/unittests/AST/Makefile
@@ -10,10 +10,10 @@
CLANG_LEVEL = ../..
TESTNAME = AST
include $(CLANG_LEVEL)/../../Makefile.config
-LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc
USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
clangRewriteCore.a clangRewriteFrontend.a \
- clangParse.a clangSema.a clangAnalysis.a \
- clangAST.a clangASTMatchers.a clangLex.a clangBasic.a clangEdit.a
+ clangParse.a clangSema.a clangAnalysis.a \
+ clangEdit.a clangAST.a clangASTMatchers.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/unittests/Makefile
diff --git a/unittests/AST/MatchVerifier.h b/unittests/AST/MatchVerifier.h
new file mode 100644
index 0000000..7aa7886
--- /dev/null
+++ b/unittests/AST/MatchVerifier.h
@@ -0,0 +1,196 @@
+//===- unittest/AST/MatchVerifier.h - AST unit test support ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Provides MatchVerifier, a base class to implement gtest matchers that
+// verify things that can be matched on the AST.
+//
+// Also implements matchers based on MatchVerifier:
+// LocationVerifier and RangeVerifier to verify whether a matched node has
+// the expected source location or source range.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ast_matchers {
+
+enum Language { Lang_C, Lang_C89, Lang_CXX, Lang_OpenCL };
+
+/// \brief Base class for verifying some property of nodes found by a matcher.
+template <typename NodeType>
+class MatchVerifier : public MatchFinder::MatchCallback {
+public:
+ template <typename MatcherType>
+ testing::AssertionResult match(const std::string &Code,
+ const MatcherType &AMatcher) {
+ return match(Code, AMatcher, Lang_CXX);
+ }
+
+ template <typename MatcherType>
+ testing::AssertionResult match(const std::string &Code,
+ const MatcherType &AMatcher, Language L);
+
+protected:
+ virtual void run(const MatchFinder::MatchResult &Result);
+ virtual void verify(const MatchFinder::MatchResult &Result,
+ const NodeType &Node) {}
+
+ void setFailure(const Twine &Result) {
+ Verified = false;
+ VerifyResult = Result.str();
+ }
+
+ void setSuccess() {
+ Verified = true;
+ }
+
+private:
+ bool Verified;
+ std::string VerifyResult;
+};
+
+/// \brief Runs a matcher over some code, and returns the result of the
+/// verifier for the matched node.
+template <typename NodeType> template <typename MatcherType>
+testing::AssertionResult MatchVerifier<NodeType>::match(
+ const std::string &Code, const MatcherType &AMatcher, Language L) {
+ MatchFinder Finder;
+ Finder.addMatcher(AMatcher.bind(""), this);
+ OwningPtr<tooling::FrontendActionFactory> Factory(
+ tooling::newFrontendActionFactory(&Finder));
+
+ std::vector<std::string> Args;
+ StringRef FileName;
+ switch (L) {
+ case Lang_C:
+ Args.push_back("-std=c99");
+ FileName = "input.c";
+ break;
+ case Lang_C89:
+ Args.push_back("-std=c89");
+ FileName = "input.c";
+ break;
+ case Lang_CXX:
+ Args.push_back("-std=c++98");
+ FileName = "input.cc";
+ break;
+ case Lang_OpenCL:
+ FileName = "input.cl";
+ }
+
+ // Default to failure in case callback is never called
+ setFailure("Could not find match");
+ if (!tooling::runToolOnCodeWithArgs(Factory->create(), Code, Args, FileName))
+ return testing::AssertionFailure() << "Parsing error";
+ if (!Verified)
+ return testing::AssertionFailure() << VerifyResult;
+ return testing::AssertionSuccess();
+}
+
+template <typename NodeType>
+void MatchVerifier<NodeType>::run(const MatchFinder::MatchResult &Result) {
+ const NodeType *Node = Result.Nodes.getNodeAs<NodeType>("");
+ if (!Node) {
+ setFailure("Matched node has wrong type");
+ } else {
+ // Callback has been called, default to success.
+ setSuccess();
+ verify(Result, *Node);
+ }
+}
+
+/// \brief Verify whether a node has the correct source location.
+///
+/// By default, Node.getSourceLocation() is checked. This can be changed
+/// by overriding getLocation().
+template <typename NodeType>
+class LocationVerifier : public MatchVerifier<NodeType> {
+public:
+ void expectLocation(unsigned Line, unsigned Column) {
+ ExpectLine = Line;
+ ExpectColumn = Column;
+ }
+
+protected:
+ void verify(const MatchFinder::MatchResult &Result, const NodeType &Node) {
+ SourceLocation Loc = getLocation(Node);
+ unsigned Line = Result.SourceManager->getSpellingLineNumber(Loc);
+ unsigned Column = Result.SourceManager->getSpellingColumnNumber(Loc);
+ if (Line != ExpectLine || Column != ExpectColumn) {
+ std::string MsgStr;
+ llvm::raw_string_ostream Msg(MsgStr);
+ Msg << "Expected location <" << ExpectLine << ":" << ExpectColumn
+ << ">, found <";
+ Loc.print(Msg, *Result.SourceManager);
+ Msg << '>';
+ this->setFailure(Msg.str());
+ }
+ }
+
+ virtual SourceLocation getLocation(const NodeType &Node) {
+ return Node.getLocation();
+ }
+
+private:
+ unsigned ExpectLine, ExpectColumn;
+};
+
+/// \brief Verify whether a node has the correct source range.
+///
+/// By default, Node.getSourceRange() is checked. This can be changed
+/// by overriding getRange().
+template <typename NodeType>
+class RangeVerifier : public MatchVerifier<NodeType> {
+public:
+ void expectRange(unsigned BeginLine, unsigned BeginColumn,
+ unsigned EndLine, unsigned EndColumn) {
+ ExpectBeginLine = BeginLine;
+ ExpectBeginColumn = BeginColumn;
+ ExpectEndLine = EndLine;
+ ExpectEndColumn = EndColumn;
+ }
+
+protected:
+ void verify(const MatchFinder::MatchResult &Result, const NodeType &Node) {
+ SourceRange R = getRange(Node);
+ SourceLocation Begin = R.getBegin();
+ SourceLocation End = R.getEnd();
+ unsigned BeginLine = Result.SourceManager->getSpellingLineNumber(Begin);
+ unsigned BeginColumn = Result.SourceManager->getSpellingColumnNumber(Begin);
+ unsigned EndLine = Result.SourceManager->getSpellingLineNumber(End);
+ unsigned EndColumn = Result.SourceManager->getSpellingColumnNumber(End);
+ if (BeginLine != ExpectBeginLine || BeginColumn != ExpectBeginColumn ||
+ EndLine != ExpectEndLine || EndColumn != ExpectEndColumn) {
+ std::string MsgStr;
+ llvm::raw_string_ostream Msg(MsgStr);
+ Msg << "Expected range <" << ExpectBeginLine << ":" << ExpectBeginColumn
+ << '-' << ExpectEndLine << ":" << ExpectEndColumn << ">, found <";
+ Begin.print(Msg, *Result.SourceManager);
+ Msg << '-';
+ End.print(Msg, *Result.SourceManager);
+ Msg << '>';
+ this->setFailure(Msg.str());
+ }
+ }
+
+ virtual SourceRange getRange(const NodeType &Node) {
+ return Node.getSourceRange();
+ }
+
+private:
+ unsigned ExpectBeginLine, ExpectBeginColumn, ExpectEndLine, ExpectEndColumn;
+};
+
+} // end namespace ast_matchers
+} // end namespace clang
diff --git a/unittests/AST/SourceLocationTest.cpp b/unittests/AST/SourceLocationTest.cpp
index dec833d..b8d8b02 100644
--- a/unittests/AST/SourceLocationTest.cpp
+++ b/unittests/AST/SourceLocationTest.cpp
@@ -17,179 +17,16 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
-#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Tooling/Tooling.h"
#include "gtest/gtest.h"
+#include "MatchVerifier.h"
namespace clang {
namespace ast_matchers {
-using clang::tooling::newFrontendActionFactory;
-using clang::tooling::runToolOnCodeWithArgs;
-using clang::tooling::FrontendActionFactory;
-
-enum Language { Lang_C, Lang_C89, Lang_CXX };
-
-/// \brief Base class for verifying some property of nodes found by a matcher.
-///
-/// FIXME: This class should be shared with other AST tests.
-template <typename NodeType>
-class MatchVerifier : public MatchFinder::MatchCallback {
-public:
- template <typename MatcherType>
- testing::AssertionResult match(const std::string &Code,
- const MatcherType &AMatcher) {
- return match(Code, AMatcher, Lang_CXX);
- }
-
- template <typename MatcherType>
- testing::AssertionResult match(const std::string &Code,
- const MatcherType &AMatcher, Language L);
-
-protected:
- virtual void run(const MatchFinder::MatchResult &Result);
- virtual void verify(const MatchFinder::MatchResult &Result,
- const NodeType &Node) = 0;
-
- void setFailure(const Twine &Result) {
- Verified = false;
- VerifyResult = Result.str();
- }
-
-private:
- bool Verified;
- std::string VerifyResult;
-};
-
-/// \brief Runs a matcher over some code, and returns the result of the
-/// verifier for the matched node.
-template <typename NodeType> template <typename MatcherType>
-testing::AssertionResult MatchVerifier<NodeType>::match(
- const std::string &Code, const MatcherType &AMatcher, Language L) {
- MatchFinder Finder;
- Finder.addMatcher(AMatcher.bind(""), this);
- OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
-
- std::vector<std::string> Args;
- StringRef FileName;
- switch (L) {
- case Lang_C:
- Args.push_back("-std=c99");
- FileName = "input.c";
- break;
- case Lang_C89:
- Args.push_back("-std=c89");
- FileName = "input.c";
- break;
- case Lang_CXX:
- Args.push_back("-std=c++98");
- FileName = "input.cc";
- break;
- }
-
- // Default to failure in case callback is never called
- setFailure("Could not find match");
- if (!runToolOnCodeWithArgs(Factory->create(), Code, Args, FileName))
- return testing::AssertionFailure() << "Parsing error";
- if (!Verified)
- return testing::AssertionFailure() << VerifyResult;
- return testing::AssertionSuccess();
-}
-
-template <typename NodeType>
-void MatchVerifier<NodeType>::run(const MatchFinder::MatchResult &Result) {
- const NodeType *Node = Result.Nodes.getNodeAs<NodeType>("");
- if (!Node) {
- setFailure("Matched node has wrong type");
- } else {
- // Callback has been called, default to success
- Verified = true;
- verify(Result, *Node);
- }
-}
-
-/// \brief Verify whether a node has the correct source location.
-///
-/// By default, Node.getSourceLocation() is checked. This can be changed
-/// by overriding getLocation().
-template <typename NodeType>
-class LocationVerifier : public MatchVerifier<NodeType> {
-public:
- void expectLocation(unsigned Line, unsigned Column) {
- ExpectLine = Line;
- ExpectColumn = Column;
- }
-
-protected:
- void verify(const MatchFinder::MatchResult &Result, const NodeType &Node) {
- SourceLocation Loc = getLocation(Node);
- unsigned Line = Result.SourceManager->getSpellingLineNumber(Loc);
- unsigned Column = Result.SourceManager->getSpellingColumnNumber(Loc);
- if (Line != ExpectLine || Column != ExpectColumn) {
- std::string MsgStr;
- llvm::raw_string_ostream Msg(MsgStr);
- Msg << "Expected location <" << ExpectLine << ":" << ExpectColumn
- << ">, found <";
- Loc.print(Msg, *Result.SourceManager);
- Msg << '>';
- this->setFailure(Msg.str());
- }
- }
-
- virtual SourceLocation getLocation(const NodeType &Node) {
- return Node.getLocation();
- }
-
-private:
- unsigned ExpectLine, ExpectColumn;
-};
-
-/// \brief Verify whether a node has the correct source range.
-///
-/// By default, Node.getSourceRange() is checked. This can be changed
-/// by overriding getRange().
-template <typename NodeType>
-class RangeVerifier : public MatchVerifier<NodeType> {
-public:
- void expectRange(unsigned BeginLine, unsigned BeginColumn,
- unsigned EndLine, unsigned EndColumn) {
- ExpectBeginLine = BeginLine;
- ExpectBeginColumn = BeginColumn;
- ExpectEndLine = EndLine;
- ExpectEndColumn = EndColumn;
- }
-
-protected:
- void verify(const MatchFinder::MatchResult &Result, const NodeType &Node) {
- SourceRange R = getRange(Node);
- SourceLocation Begin = R.getBegin();
- SourceLocation End = R.getEnd();
- unsigned BeginLine = Result.SourceManager->getSpellingLineNumber(Begin);
- unsigned BeginColumn = Result.SourceManager->getSpellingColumnNumber(Begin);
- unsigned EndLine = Result.SourceManager->getSpellingLineNumber(End);
- unsigned EndColumn = Result.SourceManager->getSpellingColumnNumber(End);
- if (BeginLine != ExpectBeginLine || BeginColumn != ExpectBeginColumn ||
- EndLine != ExpectEndLine || EndColumn != ExpectEndColumn) {
- std::string MsgStr;
- llvm::raw_string_ostream Msg(MsgStr);
- Msg << "Expected range <" << ExpectBeginLine << ":" << ExpectBeginColumn
- << '-' << ExpectEndLine << ":" << ExpectEndColumn << ">, found <";
- Begin.print(Msg, *Result.SourceManager);
- Msg << '-';
- End.print(Msg, *Result.SourceManager);
- Msg << '>';
- this->setFailure(Msg.str());
- }
- }
-
- virtual SourceRange getRange(const NodeType &Node) {
- return Node.getSourceRange();
- }
-
-private:
- unsigned ExpectBeginLine, ExpectBeginColumn, ExpectEndLine, ExpectEndColumn;
-};
+// FIXME: Pull the *Verifier tests into their own test file.
TEST(MatchVerifier, ParseError) {
LocationVerifier<VarDecl> Verifier;
@@ -285,5 +122,38 @@ TEST(CXXConstructorDecl, NoRetFunTypeLocRange) {
EXPECT_TRUE(Verifier.match("class C { C(); };", functionDecl()));
}
+TEST(CompoundLiteralExpr, CompoundVectorLiteralRange) {
+ RangeVerifier<CompoundLiteralExpr> Verifier;
+ Verifier.expectRange(2, 11, 2, 22);
+ EXPECT_TRUE(Verifier.match(
+ "typedef int int2 __attribute__((ext_vector_type(2)));\n"
+ "int2 i2 = (int2){1, 2};", compoundLiteralExpr()));
+}
+
+TEST(CompoundLiteralExpr, ParensCompoundVectorLiteralRange) {
+ RangeVerifier<CompoundLiteralExpr> Verifier;
+ Verifier.expectRange(2, 11, 2, 22);
+ EXPECT_TRUE(Verifier.match(
+ "typedef int int2 __attribute__((ext_vector_type(2)));\n"
+ "int2 i2 = (int2)(1, 2);",
+ compoundLiteralExpr(), Lang_OpenCL));
+}
+
+TEST(InitListExpr, VectorLiteralListBraceRange) {
+ RangeVerifier<InitListExpr> Verifier;
+ Verifier.expectRange(2, 17, 2, 22);
+ EXPECT_TRUE(Verifier.match(
+ "typedef int int2 __attribute__((ext_vector_type(2)));\n"
+ "int2 i2 = (int2){1, 2};", initListExpr()));
+}
+
+TEST(InitListExpr, VectorLiteralInitListParens) {
+ RangeVerifier<InitListExpr> Verifier;
+ Verifier.expectRange(2, 17, 2, 22);
+ EXPECT_TRUE(Verifier.match(
+ "typedef int int2 __attribute__((ext_vector_type(2)));\n"
+ "int2 i2 = (int2)(1, 2);", initListExpr(), Lang_OpenCL));
+}
+
} // end namespace ast_matchers
} // end namespace clang
diff --git a/unittests/AST/StmtPrinterTest.cpp b/unittests/AST/StmtPrinterTest.cpp
index 0fd1b2e..473ee13 100644
--- a/unittests/AST/StmtPrinterTest.cpp
+++ b/unittests/AST/StmtPrinterTest.cpp
@@ -146,20 +146,14 @@ TEST(StmtPrinter, TestMSIntegerLiteral) {
" 1i8, -1i8, 1ui8, "
" 1i16, -1i16, 1ui16, "
" 1i32, -1i32, 1ui32, "
- " 1i64, -1i64, 1ui64, "
- " 1i128, -1i128, 1ui128, 1Ui128,"
- " 0x10000000000000000i128;"
+ " 1i64, -1i64, 1ui64;"
"}",
"A",
"1 , -1 , 1U , "
"1 , -1 , 1U , "
"1L , -1L , 1UL , "
- "1LL , -1LL , 1ULL , "
- "1 , -1 , 1U , 1U , "
- "18446744073709551616i128"));
+ "1LL , -1LL , 1ULL"));
// Should be: with semicolon
- // WRONG; all 128-bit literals should be printed as 128-bit.
- // (This is because currently we do semantic analysis incorrectly.)
}
TEST(StmtPrinter, TestFloatingPointLiteral) {
@@ -169,4 +163,3 @@ TEST(StmtPrinter, TestFloatingPointLiteral) {
"1.F , -1.F , 1. , -1. , 1.L , -1.L"));
// Should be: with semicolon
}
-
diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp
index e15940a..301b4f7 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -8,8 +8,9 @@
//===----------------------------------------------------------------------===//
#include "ASTMatchersTest.h"
-#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/AST/PrettyPrinter.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Tooling/Tooling.h"
#include "gtest/gtest.h"
@@ -79,6 +80,13 @@ TEST(NameableDeclaration, REMatchesVariousDecls) {
EXPECT_TRUE(matches("int aFOObBARc;", Abc));
EXPECT_TRUE(notMatches("int cab;", Abc));
EXPECT_TRUE(matches("int cabc;", Abc));
+
+ DeclarationMatcher StartsWithK = namedDecl(matchesName(":k[^:]*$"));
+ EXPECT_TRUE(matches("int k;", StartsWithK));
+ EXPECT_TRUE(matches("int kAbc;", StartsWithK));
+ EXPECT_TRUE(matches("namespace x { int kTest; }", StartsWithK));
+ EXPECT_TRUE(matches("class C { int k; };", StartsWithK));
+ EXPECT_TRUE(notMatches("class C { int ckc; };", StartsWithK));
}
TEST(DeclarationMatcher, MatchClass) {
@@ -231,6 +239,17 @@ TEST(DeclarationMatcher, ClassIsDerived) {
"template <> class Z<void> {};"
"template <typename T> class Z : public Z<void>, public X {};",
ZIsDerivedFromX));
+ EXPECT_TRUE(
+ notMatches("template<int> struct X;"
+ "template<int i> struct X : public X<i-1> {};",
+ recordDecl(isDerivedFrom(recordDecl(hasName("Some"))))));
+ EXPECT_TRUE(matches(
+ "struct A {};"
+ "template<int> struct X;"
+ "template<int i> struct X : public X<i-1> {};"
+ "template<> struct X<0> : public A {};"
+ "struct B : public X<42> {};",
+ recordDecl(hasName("B"), isDerivedFrom(recordDecl(hasName("A"))))));
// FIXME: Once we have better matchers for template type matching,
// get rid of the Variable(...) matching and match the right template
@@ -294,6 +313,13 @@ TEST(DeclarationMatcher, ClassIsDerived) {
recordDecl(isDerivedFrom(recordDecl(hasName("X")).bind("test")))));
}
+TEST(DeclarationMatcher, hasMethod) {
+ EXPECT_TRUE(matches("class A { void func(); };",
+ recordDecl(hasMethod(hasName("func")))));
+ EXPECT_TRUE(notMatches("class A { void func(); };",
+ recordDecl(hasMethod(isPublic()))));
+}
+
TEST(DeclarationMatcher, ClassDerivedFromDependentTemplateSpecialization) {
EXPECT_TRUE(matches(
"template <typename T> struct A {"
@@ -304,6 +330,23 @@ TEST(DeclarationMatcher, ClassDerivedFromDependentTemplateSpecialization) {
recordDecl(hasName("B"), isDerivedFrom(recordDecl()))));
}
+TEST(DeclarationMatcher, hasDeclContext) {
+ EXPECT_TRUE(matches(
+ "namespace N {"
+ " namespace M {"
+ " class D {};"
+ " }"
+ "}",
+ recordDecl(hasDeclContext(namedDecl(hasName("M"))))));
+ EXPECT_TRUE(notMatches(
+ "namespace N {"
+ " namespace M {"
+ " class D {};"
+ " }"
+ "}",
+ recordDecl(hasDeclContext(namedDecl(hasName("N"))))));
+}
+
TEST(ClassTemplate, DoesNotMatchClass) {
DeclarationMatcher ClassX = classTemplateDecl(hasName("X"));
EXPECT_TRUE(notMatches("class X;", ClassX));
@@ -332,7 +375,9 @@ TEST(ClassTemplate, DoesNotMatchClassTemplatePartialSpecialization) {
TEST(AllOf, AllOverloadsWork) {
const char Program[] =
- "struct T { }; int f(int, T*); void g(int x) { T t; f(x, &t); }";
+ "struct T { };"
+ "int f(int, T*, int, int);"
+ "void g(int x) { T t; f(x, &t, 3, 4); }";
EXPECT_TRUE(matches(Program,
callExpr(allOf(callee(functionDecl(hasName("f"))),
hasArgument(0, declRefExpr(to(varDecl())))))));
@@ -341,6 +386,19 @@ TEST(AllOf, AllOverloadsWork) {
hasArgument(0, declRefExpr(to(varDecl()))),
hasArgument(1, hasType(pointsTo(
recordDecl(hasName("T")))))))));
+ EXPECT_TRUE(matches(Program,
+ callExpr(allOf(callee(functionDecl(hasName("f"))),
+ hasArgument(0, declRefExpr(to(varDecl()))),
+ hasArgument(1, hasType(pointsTo(
+ recordDecl(hasName("T"))))),
+ hasArgument(2, integerLiteral(equals(3)))))));
+ EXPECT_TRUE(matches(Program,
+ callExpr(allOf(callee(functionDecl(hasName("f"))),
+ hasArgument(0, declRefExpr(to(varDecl()))),
+ hasArgument(1, hasType(pointsTo(
+ recordDecl(hasName("T"))))),
+ hasArgument(2, integerLiteral(equals(3))),
+ hasArgument(3, integerLiteral(equals(4)))))));
}
TEST(DeclarationMatcher, MatchAnyOf) {
@@ -574,8 +632,10 @@ public:
// Create an object that checks that a node of type \c T was bound to \c Id.
// Checks that there was exactly one match with the name \c ExpectedName.
// Note that \c T must be a NamedDecl for this to work.
- VerifyIdIsBoundTo(llvm::StringRef Id, llvm::StringRef ExpectedName)
- : Id(Id), ExpectedCount(1), Count(0), ExpectedName(ExpectedName) {}
+ VerifyIdIsBoundTo(llvm::StringRef Id, llvm::StringRef ExpectedName,
+ int ExpectedCount = 1)
+ : Id(Id), ExpectedCount(ExpectedCount), Count(0),
+ ExpectedName(ExpectedName) {}
~VerifyIdIsBoundTo() {
if (ExpectedCount != -1)
@@ -639,7 +699,7 @@ TEST(HasDescendant, MatchesDescendantsOfTypes) {
qualType(hasDescendant(
pointerType(pointee(builtinType()))))));
EXPECT_TRUE(matches("void f() { int*** i; }",
- typeLoc(hasDescendant(builtinTypeLoc()))));
+ typeLoc(hasDescendant(loc(builtinType())))));
EXPECT_TRUE(matchAndVerifyResultTrue(
"void f() { int*** i; }",
@@ -778,6 +838,32 @@ TEST(Matcher, BindsIDForMemoizedResults) {
new VerifyIdIsBoundTo<Decl>("x", 2)));
}
+TEST(HasDeclaration, HasDeclarationOfEnumType) {
+ EXPECT_TRUE(matches("enum X {}; void y(X *x) { x; }",
+ expr(hasType(pointsTo(
+ qualType(hasDeclaration(enumDecl(hasName("X")))))))));
+}
+
+TEST(HasDeclaration, HasGetDeclTraitTest) {
+ EXPECT_TRUE(internal::has_getDecl<TypedefType>::value);
+ EXPECT_TRUE(internal::has_getDecl<RecordType>::value);
+ EXPECT_FALSE(internal::has_getDecl<TemplateSpecializationType>::value);
+}
+
+TEST(HasDeclaration, HasDeclarationOfTypeWithDecl) {
+ EXPECT_TRUE(matches("typedef int X; X a;",
+ varDecl(hasName("a"),
+ hasType(typedefType(hasDeclaration(decl()))))));
+
+ // FIXME: Add tests for other types with getDecl() (e.g. RecordType)
+}
+
+TEST(HasDeclaration, HasDeclarationOfTemplateSpecializationType) {
+ EXPECT_TRUE(matches("template <typename T> class A {}; A<int> a;",
+ varDecl(hasType(templateSpecializationType(
+ hasDeclaration(namedDecl(hasName("A"))))))));
+}
+
TEST(HasType, TakesQualTypeMatcherAndMatchesExpr) {
TypeMatcher ClassX = hasDeclaration(recordDecl(hasName("X")));
EXPECT_TRUE(
@@ -945,6 +1031,31 @@ TEST(Matcher, HasOperatorNameForOverloadedOperatorCall) {
"bool operator&&(Y x, Y y) { return true; }; "
"Y a; Y b; bool c = a && b;",
OpCallLessLess));
+ DeclarationMatcher ClassWithOpStar =
+ recordDecl(hasMethod(hasOverloadedOperatorName("*")));
+ EXPECT_TRUE(matches("class Y { int operator*(); };",
+ ClassWithOpStar));
+ EXPECT_TRUE(notMatches("class Y { void myOperator(); };",
+ ClassWithOpStar)) ;
+}
+
+TEST(Matcher, NestedOverloadedOperatorCalls) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class Y { }; "
+ "Y& operator&&(Y& x, Y& y) { return x; }; "
+ "Y a; Y b; Y c; Y d = a && b && c;",
+ operatorCallExpr(hasOverloadedOperatorName("&&")).bind("x"),
+ new VerifyIdIsBoundTo<CXXOperatorCallExpr>("x", 2)));
+ EXPECT_TRUE(matches(
+ "class Y { }; "
+ "Y& operator&&(Y& x, Y& y) { return x; }; "
+ "Y a; Y b; Y c; Y d = a && b && c;",
+ operatorCallExpr(hasParent(operatorCallExpr()))));
+ EXPECT_TRUE(matches(
+ "class Y { }; "
+ "Y& operator&&(Y& x, Y& y) { return x; }; "
+ "Y a; Y b; Y c; Y d = a && b && c;",
+ operatorCallExpr(hasDescendant(operatorCallExpr()))));
}
TEST(Matcher, ThisPointerType) {
@@ -1003,7 +1114,7 @@ TEST(Matcher, VariableUsage) {
"}", Reference));
}
-TEST(Matcher, FindsVarDeclInFuncitonParameter) {
+TEST(Matcher, FindsVarDeclInFunctionParameter) {
EXPECT_TRUE(matches(
"void f(int i) {}",
varDecl(hasName("i"))));
@@ -1212,6 +1323,14 @@ TEST(Matcher, ArgumentCount) {
EXPECT_TRUE(notMatches("void x(int, int) { x(0, 0); }", Call1Arg));
}
+TEST(Matcher, ParameterCount) {
+ DeclarationMatcher Function1Arg = functionDecl(parameterCountIs(1));
+ EXPECT_TRUE(matches("void f(int i) {}", Function1Arg));
+ EXPECT_TRUE(matches("class X { void f(int i) {} };", Function1Arg));
+ EXPECT_TRUE(notMatches("void f() {}", Function1Arg));
+ EXPECT_TRUE(notMatches("void f(int i, int j, int k) {}", Function1Arg));
+}
+
TEST(Matcher, References) {
DeclarationMatcher ReferenceClassX = varDecl(
hasType(references(recordDecl(hasName("X")))));
@@ -1225,6 +1344,29 @@ TEST(Matcher, References) {
notMatches("class X {}; void y(X *y) { X *&x = y; }", ReferenceClassX));
}
+TEST(QualType, hasCanonicalType) {
+ EXPECT_TRUE(notMatches("typedef int &int_ref;"
+ "int a;"
+ "int_ref b = a;",
+ varDecl(hasType(qualType(referenceType())))));
+ EXPECT_TRUE(
+ matches("typedef int &int_ref;"
+ "int a;"
+ "int_ref b = a;",
+ varDecl(hasType(qualType(hasCanonicalType(referenceType()))))));
+}
+
+TEST(QualType, hasLocalQualifiers) {
+ EXPECT_TRUE(notMatches("typedef const int const_int; const_int i = 1;",
+ varDecl(hasType(hasLocalQualifiers()))));
+ EXPECT_TRUE(matches("int *const j = nullptr;",
+ varDecl(hasType(hasLocalQualifiers()))));
+ EXPECT_TRUE(matches("int *volatile k;",
+ varDecl(hasType(hasLocalQualifiers()))));
+ EXPECT_TRUE(notMatches("int m;",
+ varDecl(hasType(hasLocalQualifiers()))));
+}
+
TEST(HasParameter, CallsInnerMatcher) {
EXPECT_TRUE(matches("class X { void x(int) {} };",
methodDecl(hasParameter(0, varDecl()))));
@@ -1338,6 +1480,18 @@ TEST(Matcher, MatchesSpecificArgument) {
1, refersToType(asString("int"))))));
}
+TEST(Matcher, MatchesAccessSpecDecls) {
+ EXPECT_TRUE(matches("class C { public: int i; };", accessSpecDecl()));
+ EXPECT_TRUE(
+ matches("class C { public: int i; };", accessSpecDecl(isPublic())));
+ EXPECT_TRUE(
+ notMatches("class C { public: int i; };", accessSpecDecl(isProtected())));
+ EXPECT_TRUE(
+ notMatches("class C { public: int i; };", accessSpecDecl(isPrivate())));
+
+ EXPECT_TRUE(notMatches("class C { int i; };", accessSpecDecl()));
+}
+
TEST(Matcher, ConstructorCall) {
StatementMatcher Constructor = constructExpr();
@@ -2208,6 +2362,34 @@ TEST(Member, MatchesMember) {
memberExpr(hasDeclaration(fieldDecl(hasType(isInteger()))))));
}
+TEST(Member, UnderstandsAccess) {
+ EXPECT_TRUE(matches(
+ "struct A { int i; };", fieldDecl(isPublic(), hasName("i"))));
+ EXPECT_TRUE(notMatches(
+ "struct A { int i; };", fieldDecl(isProtected(), hasName("i"))));
+ EXPECT_TRUE(notMatches(
+ "struct A { int i; };", fieldDecl(isPrivate(), hasName("i"))));
+
+ EXPECT_TRUE(notMatches(
+ "class A { int i; };", fieldDecl(isPublic(), hasName("i"))));
+ EXPECT_TRUE(notMatches(
+ "class A { int i; };", fieldDecl(isProtected(), hasName("i"))));
+ EXPECT_TRUE(matches(
+ "class A { int i; };", fieldDecl(isPrivate(), hasName("i"))));
+
+ EXPECT_TRUE(notMatches(
+ "class A { protected: int i; };", fieldDecl(isPublic(), hasName("i"))));
+ EXPECT_TRUE(matches("class A { protected: int i; };",
+ fieldDecl(isProtected(), hasName("i"))));
+ EXPECT_TRUE(notMatches(
+ "class A { protected: int i; };", fieldDecl(isPrivate(), hasName("i"))));
+
+ // Non-member decls have the AccessSpecifier AS_none and thus aren't matched.
+ EXPECT_TRUE(notMatches("int i;", varDecl(isPublic(), hasName("i"))));
+ EXPECT_TRUE(notMatches("int i;", varDecl(isProtected(), hasName("i"))));
+ EXPECT_TRUE(notMatches("int i;", varDecl(isPrivate(), hasName("i"))));
+}
+
TEST(Member, MatchesMemberAllocationFunction) {
// Fails in C++11 mode
EXPECT_TRUE(matchesConditionally(
@@ -2758,6 +2940,22 @@ TEST(ForEachDescendant, BindsOneNode) {
new VerifyIdIsBoundTo<FieldDecl>("x", 1)));
}
+TEST(ForEachDescendant, NestedForEachDescendant) {
+ DeclarationMatcher m = recordDecl(
+ isDefinition(), decl().bind("x"), hasName("C"));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class A { class B { class C {}; }; };",
+ recordDecl(hasName("A"), anyOf(m, forEachDescendant(m))),
+ new VerifyIdIsBoundTo<Decl>("x", "C")));
+
+ // FIXME: This is not really a useful matcher, but the result is still
+ // surprising (currently binds "A").
+ //EXPECT_TRUE(matchAndVerifyResultTrue(
+ // "class A { class B { class C {}; }; };",
+ // recordDecl(hasName("A"), allOf(hasDescendant(m), anyOf(m, anything()))),
+ // new VerifyIdIsBoundTo<Decl>("x", "C")));
+}
+
TEST(ForEachDescendant, BindsMultipleNodes) {
EXPECT_TRUE(matchAndVerifyResultTrue(
"class C { class D { int x; int y; }; "
@@ -2786,6 +2984,58 @@ TEST(ForEachDescendant, BindsCorrectNodes) {
new VerifyIdIsBoundTo<FunctionDecl>("decl", 1)));
}
+TEST(FindAll, BindsNodeOnMatch) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class A {};",
+ recordDecl(hasName("::A"), findAll(recordDecl(hasName("::A")).bind("v"))),
+ new VerifyIdIsBoundTo<CXXRecordDecl>("v", 1)));
+}
+
+TEST(FindAll, BindsDescendantNodeOnMatch) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class A { int a; int b; };",
+ recordDecl(hasName("::A"), findAll(fieldDecl().bind("v"))),
+ new VerifyIdIsBoundTo<FieldDecl>("v", 2)));
+}
+
+TEST(FindAll, BindsNodeAndDescendantNodesOnOneMatch) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class A { int a; int b; };",
+ recordDecl(hasName("::A"),
+ findAll(decl(anyOf(recordDecl(hasName("::A")).bind("v"),
+ fieldDecl().bind("v"))))),
+ new VerifyIdIsBoundTo<Decl>("v", 3)));
+
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class A { class B {}; class C {}; };",
+ recordDecl(hasName("::A"), findAll(recordDecl(isDefinition()).bind("v"))),
+ new VerifyIdIsBoundTo<CXXRecordDecl>("v", 3)));
+}
+
+TEST(EachOf, TriggersForEachMatch) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class A { int a; int b; };",
+ recordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")),
+ has(fieldDecl(hasName("b")).bind("v")))),
+ new VerifyIdIsBoundTo<FieldDecl>("v", 2)));
+}
+
+TEST(EachOf, BehavesLikeAnyOfUnlessBothMatch) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class A { int a; int c; };",
+ recordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")),
+ has(fieldDecl(hasName("b")).bind("v")))),
+ new VerifyIdIsBoundTo<FieldDecl>("v", 1)));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class A { int c; int b; };",
+ recordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")),
+ has(fieldDecl(hasName("b")).bind("v")))),
+ new VerifyIdIsBoundTo<FieldDecl>("v", 1)));
+ EXPECT_TRUE(notMatches(
+ "class A { int c; int d; };",
+ recordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")),
+ has(fieldDecl(hasName("b")).bind("v"))))));
+}
TEST(IsTemplateInstantiation, MatchesImplicitClassTemplateInstantiation) {
// Make sure that we can both match the class by name (::X) and by the type
@@ -2955,6 +3205,20 @@ TEST(HasAncestor, BindsCombinationsWithHasDescendant) {
new VerifyIdIsBoundTo<CXXRecordDecl>("d", "E")));
}
+TEST(HasAncestor, MatchesClosestAncestor) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "template <typename T> struct C {"
+ " void f(int) {"
+ " struct I { void g(T) { int x; } } i; i.g(42);"
+ " }"
+ "};"
+ "template struct C<int>;",
+ varDecl(hasName("x"),
+ hasAncestor(functionDecl(hasParameter(
+ 0, varDecl(hasType(asString("int"))))).bind("f"))).bind("v"),
+ new VerifyIdIsBoundTo<FunctionDecl>("f", "g", 2)));
+}
+
TEST(HasAncestor, MatchesInTemplateInstantiations) {
EXPECT_TRUE(matches(
"template <typename T> struct A { struct B { struct C { T t; }; }; }; "
@@ -2983,6 +3247,46 @@ TEST(HasParent, MatchesOnlyParent) {
compoundStmt(hasParent(ifStmt()))));
}
+TEST(HasAncestor, MatchesAllAncestors) {
+ EXPECT_TRUE(matches(
+ "template <typename T> struct C { static void f() { 42; } };"
+ "void t() { C<int>::f(); }",
+ integerLiteral(
+ equals(42),
+ allOf(hasAncestor(recordDecl(isTemplateInstantiation())),
+ hasAncestor(recordDecl(unless(isTemplateInstantiation())))))));
+}
+
+TEST(HasParent, MatchesAllParents) {
+ EXPECT_TRUE(matches(
+ "template <typename T> struct C { static void f() { 42; } };"
+ "void t() { C<int>::f(); }",
+ integerLiteral(
+ equals(42),
+ hasParent(compoundStmt(hasParent(functionDecl(
+ hasParent(recordDecl(isTemplateInstantiation())))))))));
+ EXPECT_TRUE(matches(
+ "template <typename T> struct C { static void f() { 42; } };"
+ "void t() { C<int>::f(); }",
+ integerLiteral(
+ equals(42),
+ hasParent(compoundStmt(hasParent(functionDecl(
+ hasParent(recordDecl(unless(isTemplateInstantiation()))))))))));
+ EXPECT_TRUE(matches(
+ "template <typename T> struct C { static void f() { 42; } };"
+ "void t() { C<int>::f(); }",
+ integerLiteral(equals(42),
+ hasParent(compoundStmt(allOf(
+ hasParent(functionDecl(
+ hasParent(recordDecl(isTemplateInstantiation())))),
+ hasParent(functionDecl(hasParent(recordDecl(
+ unless(isTemplateInstantiation())))))))))));
+ EXPECT_TRUE(
+ notMatches("template <typename T> struct C { static void f() {} };"
+ "void t() { C<int>::f(); }",
+ compoundStmt(hasParent(recordDecl()))));
+}
+
TEST(TypeMatching, MatchesTypes) {
EXPECT_TRUE(matches("struct S {};", qualType().bind("loc")));
}
@@ -3094,6 +3398,19 @@ TEST(TypeMatching, MatchesFunctionTypes) {
EXPECT_TRUE(matches("void f(int i) {}", functionType()));
}
+TEST(TypeMatching, MatchesParenType) {
+ EXPECT_TRUE(
+ matches("int (*array)[4];", varDecl(hasType(pointsTo(parenType())))));
+ EXPECT_TRUE(notMatches("int *array[4];", varDecl(hasType(parenType()))));
+
+ EXPECT_TRUE(matches(
+ "int (*ptr_to_func)(int);",
+ varDecl(hasType(pointsTo(parenType(innerType(functionType())))))));
+ EXPECT_TRUE(notMatches(
+ "int (*ptr_to_array)[4];",
+ varDecl(hasType(pointsTo(parenType(innerType(functionType())))))));
+}
+
TEST(TypeMatching, PointerTypes) {
// FIXME: Reactive when these tests can be more specific (not matching
// implicit code on certain platforms), likely when we have hasDescendant for
@@ -3108,7 +3425,7 @@ TEST(TypeMatching, PointerTypes) {
// new VerifyIdIsBoundTo<TypeLoc>("loc", 1)));
EXPECT_TRUE(matches(
"int** a;",
- pointerTypeLoc(pointeeLoc(loc(qualType())))));
+ loc(pointerType(pointee(qualType())))));
EXPECT_TRUE(matches(
"int** a;",
loc(pointerType(pointee(pointerType())))));
@@ -3125,6 +3442,10 @@ TEST(TypeMatching, PointerTypes) {
hasType(pointerType()))));
EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"),
hasType(referenceType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"),
+ hasType(lValueReferenceType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"),
+ hasType(rValueReferenceType()))));
Fragment = "int *ptr;";
EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ptr"),
@@ -3145,6 +3466,54 @@ TEST(TypeMatching, PointerTypes) {
hasType(pointerType()))));
EXPECT_TRUE(matches(Fragment, varDecl(hasName("ref"),
hasType(referenceType()))));
+ EXPECT_TRUE(matches(Fragment, varDecl(hasName("ref"),
+ hasType(lValueReferenceType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ref"),
+ hasType(rValueReferenceType()))));
+
+ Fragment = "int &&ref = 2;";
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ref"),
+ hasType(blockPointerType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ref"),
+ hasType(memberPointerType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ref"),
+ hasType(pointerType()))));
+ EXPECT_TRUE(matches(Fragment, varDecl(hasName("ref"),
+ hasType(referenceType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("ref"),
+ hasType(lValueReferenceType()))));
+ EXPECT_TRUE(matches(Fragment, varDecl(hasName("ref"),
+ hasType(rValueReferenceType()))));
+}
+
+TEST(TypeMatching, AutoRefTypes) {
+ std::string Fragment = "auto a = 1;"
+ "auto b = a;"
+ "auto &c = a;"
+ "auto &&d = c;"
+ "auto &&e = 2;";
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("a"),
+ hasType(referenceType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("b"),
+ hasType(referenceType()))));
+ EXPECT_TRUE(matches(Fragment, varDecl(hasName("c"),
+ hasType(referenceType()))));
+ EXPECT_TRUE(matches(Fragment, varDecl(hasName("c"),
+ hasType(lValueReferenceType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("c"),
+ hasType(rValueReferenceType()))));
+ EXPECT_TRUE(matches(Fragment, varDecl(hasName("d"),
+ hasType(referenceType()))));
+ EXPECT_TRUE(matches(Fragment, varDecl(hasName("d"),
+ hasType(lValueReferenceType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("d"),
+ hasType(rValueReferenceType()))));
+ EXPECT_TRUE(matches(Fragment, varDecl(hasName("e"),
+ hasType(referenceType()))));
+ EXPECT_TRUE(notMatches(Fragment, varDecl(hasName("e"),
+ hasType(lValueReferenceType()))));
+ EXPECT_TRUE(matches(Fragment, varDecl(hasName("e"),
+ hasType(rValueReferenceType()))));
}
TEST(TypeMatching, PointeeTypes) {
@@ -3153,7 +3522,7 @@ TEST(TypeMatching, PointeeTypes) {
EXPECT_TRUE(matches("int *a;", pointerType(pointee(builtinType()))));
EXPECT_TRUE(matches("int *a;",
- pointerTypeLoc(pointeeLoc(loc(builtinType())))));
+ loc(pointerType(pointee(builtinType())))));
EXPECT_TRUE(matches(
"int const *A;",
@@ -3167,10 +3536,10 @@ TEST(TypeMatching, MatchesPointersToConstTypes) {
EXPECT_TRUE(matches("int b; int * const a = &b;",
loc(pointerType())));
EXPECT_TRUE(matches("int b; int * const a = &b;",
- pointerTypeLoc()));
+ loc(pointerType())));
EXPECT_TRUE(matches(
"int b; const int * a = &b;",
- pointerTypeLoc(pointeeLoc(builtinTypeLoc()))));
+ loc(pointerType(pointee(builtinType())))));
EXPECT_TRUE(matches(
"int b; const int * a = &b;",
pointerType(pointee(builtinType()))));
@@ -3179,10 +3548,70 @@ TEST(TypeMatching, MatchesPointersToConstTypes) {
TEST(TypeMatching, MatchesTypedefTypes) {
EXPECT_TRUE(matches("typedef int X; X a;", varDecl(hasName("a"),
hasType(typedefType()))));
+}
- EXPECT_TRUE(matches("typedef int X; X a;",
- varDecl(hasName("a"),
- hasType(typedefType(hasDecl(decl()))))));
+TEST(TypeMatching, MatchesTemplateSpecializationType) {
+ EXPECT_TRUE(matches("template <typename T> class A{}; A<int> a;",
+ templateSpecializationType()));
+}
+
+TEST(TypeMatching, MatchesRecordType) {
+ EXPECT_TRUE(matches("class C{}; C c;", recordType()));
+ EXPECT_TRUE(matches("struct S{}; S s;",
+ recordType(hasDeclaration(recordDecl(hasName("S"))))));
+ EXPECT_TRUE(notMatches("int i;",
+ recordType(hasDeclaration(recordDecl(hasName("S"))))));
+}
+
+TEST(TypeMatching, MatchesElaboratedType) {
+ EXPECT_TRUE(matches(
+ "namespace N {"
+ " namespace M {"
+ " class D {};"
+ " }"
+ "}"
+ "N::M::D d;", elaboratedType()));
+ EXPECT_TRUE(matches("class C {} c;", elaboratedType()));
+ EXPECT_TRUE(notMatches("class C {}; C c;", elaboratedType()));
+}
+
+TEST(ElaboratedTypeNarrowing, hasQualifier) {
+ EXPECT_TRUE(matches(
+ "namespace N {"
+ " namespace M {"
+ " class D {};"
+ " }"
+ "}"
+ "N::M::D d;",
+ elaboratedType(hasQualifier(hasPrefix(specifiesNamespace(hasName("N")))))));
+ EXPECT_TRUE(notMatches(
+ "namespace M {"
+ " class D {};"
+ "}"
+ "M::D d;",
+ elaboratedType(hasQualifier(hasPrefix(specifiesNamespace(hasName("N")))))));
+ EXPECT_TRUE(notMatches(
+ "struct D {"
+ "} d;",
+ elaboratedType(hasQualifier(nestedNameSpecifier()))));
+}
+
+TEST(ElaboratedTypeNarrowing, namesType) {
+ EXPECT_TRUE(matches(
+ "namespace N {"
+ " namespace M {"
+ " class D {};"
+ " }"
+ "}"
+ "N::M::D d;",
+ elaboratedType(elaboratedType(namesType(recordType(
+ hasDeclaration(namedDecl(hasName("D")))))))));
+ EXPECT_TRUE(notMatches(
+ "namespace M {"
+ " class D {};"
+ "}"
+ "M::D d;",
+ elaboratedType(elaboratedType(namesType(typedefType())))));
}
TEST(NNS, MatchesNestedNameSpecifiers) {
@@ -3335,46 +3764,90 @@ TEST(NNSLoc, NestedNameSpecifierLocsAsDescendants) {
new VerifyIdIsBoundTo<NestedNameSpecifierLoc>("x", 3)));
}
-template <typename T>
-class VerifyRecursiveMatch : public BoundNodesCallback {
+template <typename T> class VerifyMatchOnNode : public BoundNodesCallback {
public:
- explicit VerifyRecursiveMatch(StringRef Id,
- const internal::Matcher<T> &InnerMatcher)
- : Id(Id), InnerMatcher(InnerMatcher) {}
-
- virtual bool run(const BoundNodes *Nodes) {
- return false;
+ VerifyMatchOnNode(StringRef Id, const internal::Matcher<T> &InnerMatcher,
+ StringRef InnerId)
+ : Id(Id), InnerMatcher(InnerMatcher), InnerId(InnerId) {
}
+ virtual bool run(const BoundNodes *Nodes) { return false; }
+
virtual bool run(const BoundNodes *Nodes, ASTContext *Context) {
const T *Node = Nodes->getNodeAs<T>(Id);
- bool Found = false;
- MatchFinder Finder;
- Finder.addMatcher(InnerMatcher, new VerifyMatch(0, &Found));
- Finder.findAll(*Node, *Context);
- return Found;
+ return selectFirst<const T>(InnerId,
+ match(InnerMatcher, *Node, *Context)) != NULL;
}
private:
std::string Id;
internal::Matcher<T> InnerMatcher;
+ std::string InnerId;
};
TEST(MatchFinder, CanMatchDeclarationsRecursively) {
- EXPECT_TRUE(matchAndVerifyResultTrue("class X { class Y {}; };",
- recordDecl(hasName("::X")).bind("X"),
- new VerifyRecursiveMatch<clang::Decl>("X", recordDecl(hasName("X::Y")))));
- EXPECT_TRUE(matchAndVerifyResultFalse("class X { class Y {}; };",
- recordDecl(hasName("::X")).bind("X"),
- new VerifyRecursiveMatch<clang::Decl>("X", recordDecl(hasName("X::Z")))));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class X { class Y {}; };", recordDecl(hasName("::X")).bind("X"),
+ new VerifyMatchOnNode<clang::Decl>(
+ "X", decl(hasDescendant(recordDecl(hasName("X::Y")).bind("Y"))),
+ "Y")));
+ EXPECT_TRUE(matchAndVerifyResultFalse(
+ "class X { class Y {}; };", recordDecl(hasName("::X")).bind("X"),
+ new VerifyMatchOnNode<clang::Decl>(
+ "X", decl(hasDescendant(recordDecl(hasName("X::Z")).bind("Z"))),
+ "Z")));
}
TEST(MatchFinder, CanMatchStatementsRecursively) {
- EXPECT_TRUE(matchAndVerifyResultTrue("void f() { if (1) { for (;;) { } } }",
- ifStmt().bind("if"),
- new VerifyRecursiveMatch<clang::Stmt>("if", forStmt())));
- EXPECT_TRUE(matchAndVerifyResultFalse("void f() { if (1) { for (;;) { } } }",
- ifStmt().bind("if"),
- new VerifyRecursiveMatch<clang::Stmt>("if", declStmt())));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "void f() { if (1) { for (;;) { } } }", ifStmt().bind("if"),
+ new VerifyMatchOnNode<clang::Stmt>(
+ "if", stmt(hasDescendant(forStmt().bind("for"))), "for")));
+ EXPECT_TRUE(matchAndVerifyResultFalse(
+ "void f() { if (1) { for (;;) { } } }", ifStmt().bind("if"),
+ new VerifyMatchOnNode<clang::Stmt>(
+ "if", stmt(hasDescendant(declStmt().bind("decl"))), "decl")));
+}
+
+TEST(MatchFinder, CanMatchSingleNodesRecursively) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class X { class Y {}; };", recordDecl(hasName("::X")).bind("X"),
+ new VerifyMatchOnNode<clang::Decl>(
+ "X", recordDecl(has(recordDecl(hasName("X::Y")).bind("Y"))), "Y")));
+ EXPECT_TRUE(matchAndVerifyResultFalse(
+ "class X { class Y {}; };", recordDecl(hasName("::X")).bind("X"),
+ new VerifyMatchOnNode<clang::Decl>(
+ "X", recordDecl(has(recordDecl(hasName("X::Z")).bind("Z"))), "Z")));
+}
+
+template <typename T>
+class VerifyAncestorHasChildIsEqual : public BoundNodesCallback {
+public:
+ virtual bool run(const BoundNodes *Nodes) { return false; }
+
+ virtual bool run(const BoundNodes *Nodes, ASTContext *Context) {
+ const T *Node = Nodes->getNodeAs<T>("");
+ return verify(*Nodes, *Context, Node);
+ }
+
+ bool verify(const BoundNodes &Nodes, ASTContext &Context, const Stmt *Node) {
+ return selectFirst<const T>(
+ "", match(stmt(hasParent(stmt(has(stmt(equalsNode(Node)))).bind(""))),
+ *Node, Context)) != NULL;
+ }
+ bool verify(const BoundNodes &Nodes, ASTContext &Context, const Decl *Node) {
+ return selectFirst<const T>(
+ "", match(decl(hasParent(decl(has(decl(equalsNode(Node)))).bind(""))),
+ *Node, Context)) != NULL;
+ }
+};
+
+TEST(IsEqualTo, MatchesNodesByIdentity) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class X { class Y {}; };", recordDecl(hasName("::X::Y")).bind(""),
+ new VerifyAncestorHasChildIsEqual<Decl>()));
+ EXPECT_TRUE(
+ matchAndVerifyResultTrue("void f() { if(true) {} }", ifStmt().bind(""),
+ new VerifyAncestorHasChildIsEqual<Stmt>()));
}
class VerifyStartOfTranslationUnit : public MatchFinder::MatchCallback {
diff --git a/unittests/ASTMatchers/ASTMatchersTest.h b/unittests/ASTMatchers/ASTMatchersTest.h
index 3b23ada..5fed85b 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.h
+++ b/unittests/ASTMatchers/ASTMatchersTest.h
@@ -89,7 +89,7 @@ testing::AssertionResult
matchAndVerifyResultConditionally(const std::string &Code, const T &AMatcher,
BoundNodesCallback *FindResultVerifier,
bool ExpectResult) {
- llvm::OwningPtr<BoundNodesCallback> ScopedVerifier(FindResultVerifier);
+ OwningPtr<BoundNodesCallback> ScopedVerifier(FindResultVerifier);
bool VerifiedResult = false;
MatchFinder Finder;
Finder.addMatcher(
diff --git a/unittests/ASTMatchers/CMakeLists.txt b/unittests/ASTMatchers/CMakeLists.txt
index b56d756..91feaac 100644
--- a/unittests/ASTMatchers/CMakeLists.txt
+++ b/unittests/ASTMatchers/CMakeLists.txt
@@ -1,6 +1,7 @@
set(LLVM_LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
asmparser
+ bitreader
support
mc
)
diff --git a/unittests/ASTMatchers/Makefile b/unittests/ASTMatchers/Makefile
index 9ca1006..2abe6ee 100644
--- a/unittests/ASTMatchers/Makefile
+++ b/unittests/ASTMatchers/Makefile
@@ -11,10 +11,10 @@ CLANG_LEVEL = ../..
TESTNAME = ASTMatchers
include $(CLANG_LEVEL)/../../Makefile.config
-LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc
USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
clangRewriteCore.a clangRewriteFrontend.a \
- clangParse.a clangSema.a clangAnalysis.a \
- clangAST.a clangASTMatchers.a clangLex.a clangBasic.a clangEdit.a
+ clangParse.a clangSema.a clangAnalysis.a \
+ clangEdit.a clangAST.a clangASTMatchers.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/unittests/Makefile
diff --git a/unittests/Basic/CMakeLists.txt b/unittests/Basic/CMakeLists.txt
index 300dcd5..51db6ce 100644
--- a/unittests/Basic/CMakeLists.txt
+++ b/unittests/Basic/CMakeLists.txt
@@ -1,4 +1,5 @@
add_clang_unittest(BasicTests
+ CharInfoTest.cpp
FileManagerTest.cpp
SourceManagerTest.cpp
)
diff --git a/unittests/Basic/CharInfoTest.cpp b/unittests/Basic/CharInfoTest.cpp
new file mode 100644
index 0000000..348e6ff
--- /dev/null
+++ b/unittests/Basic/CharInfoTest.cpp
@@ -0,0 +1,499 @@
+//===- unittests/Basic/CharInfoTest.cpp -- ASCII classification tests -----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/CharInfo.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace clang;
+
+// Check that the CharInfo table has been constructed reasonably.
+TEST(CharInfoTest, validateInfoTable) {
+ using namespace charinfo;
+ EXPECT_EQ((unsigned)CHAR_SPACE, InfoTable[(unsigned)' ']);
+ EXPECT_EQ((unsigned)CHAR_HORZ_WS, InfoTable[(unsigned)'\t']);
+ EXPECT_EQ((unsigned)CHAR_HORZ_WS, InfoTable[(unsigned)'\f']); // ??
+ EXPECT_EQ((unsigned)CHAR_HORZ_WS, InfoTable[(unsigned)'\v']); // ??
+ EXPECT_EQ((unsigned)CHAR_VERT_WS, InfoTable[(unsigned)'\n']);
+ EXPECT_EQ((unsigned)CHAR_VERT_WS, InfoTable[(unsigned)'\r']);
+ EXPECT_EQ((unsigned)CHAR_UNDER, InfoTable[(unsigned)'_']);
+ EXPECT_EQ((unsigned)CHAR_PERIOD, InfoTable[(unsigned)'.']);
+
+ for (unsigned i = 'a'; i <= 'f'; ++i) {
+ EXPECT_EQ((unsigned)CHAR_XLOWER, InfoTable[i]);
+ EXPECT_EQ((unsigned)CHAR_XUPPER, InfoTable[i+'A'-'a']);
+ }
+
+ for (unsigned i = 'g'; i <= 'z'; ++i) {
+ EXPECT_EQ((unsigned)CHAR_LOWER, InfoTable[i]);
+ EXPECT_EQ((unsigned)CHAR_UPPER, InfoTable[i+'A'-'a']);
+ }
+
+ for (unsigned i = '0'; i <= '9'; ++i)
+ EXPECT_EQ((unsigned)CHAR_DIGIT, InfoTable[i]);
+}
+
+// Check various predicates.
+TEST(CharInfoTest, isASCII) {
+ EXPECT_TRUE(isASCII('\0'));
+ EXPECT_TRUE(isASCII('\n'));
+ EXPECT_TRUE(isASCII(' '));
+ EXPECT_TRUE(isASCII('a'));
+ EXPECT_TRUE(isASCII('\x7f'));
+ EXPECT_FALSE(isASCII('\x80'));
+ EXPECT_FALSE(isASCII('\xc2'));
+ EXPECT_FALSE(isASCII('\xff'));
+}
+
+TEST(CharInfoTest, isIdentifierHead) {
+ EXPECT_TRUE(isIdentifierHead('a'));
+ EXPECT_TRUE(isIdentifierHead('A'));
+ EXPECT_TRUE(isIdentifierHead('z'));
+ EXPECT_TRUE(isIdentifierHead('Z'));
+ EXPECT_TRUE(isIdentifierHead('_'));
+
+ EXPECT_FALSE(isIdentifierHead('0'));
+ EXPECT_FALSE(isIdentifierHead('.'));
+ EXPECT_FALSE(isIdentifierHead('`'));
+ EXPECT_FALSE(isIdentifierHead('\0'));
+
+ EXPECT_FALSE(isIdentifierHead('$'));
+ EXPECT_TRUE(isIdentifierHead('$', /*AllowDollar=*/true));
+
+ EXPECT_FALSE(isIdentifierHead('\x80'));
+ EXPECT_FALSE(isIdentifierHead('\xc2'));
+ EXPECT_FALSE(isIdentifierHead('\xff'));
+}
+
+TEST(CharInfoTest, isIdentifierBody) {
+ EXPECT_TRUE(isIdentifierBody('a'));
+ EXPECT_TRUE(isIdentifierBody('A'));
+ EXPECT_TRUE(isIdentifierBody('z'));
+ EXPECT_TRUE(isIdentifierBody('Z'));
+ EXPECT_TRUE(isIdentifierBody('_'));
+
+ EXPECT_TRUE(isIdentifierBody('0'));
+ EXPECT_FALSE(isIdentifierBody('.'));
+ EXPECT_FALSE(isIdentifierBody('`'));
+ EXPECT_FALSE(isIdentifierBody('\0'));
+
+ EXPECT_FALSE(isIdentifierBody('$'));
+ EXPECT_TRUE(isIdentifierBody('$', /*AllowDollar=*/true));
+
+ EXPECT_FALSE(isIdentifierBody('\x80'));
+ EXPECT_FALSE(isIdentifierBody('\xc2'));
+ EXPECT_FALSE(isIdentifierBody('\xff'));
+}
+
+TEST(CharInfoTest, isHorizontalWhitespace) {
+ EXPECT_FALSE(isHorizontalWhitespace('a'));
+ EXPECT_FALSE(isHorizontalWhitespace('_'));
+ EXPECT_FALSE(isHorizontalWhitespace('0'));
+ EXPECT_FALSE(isHorizontalWhitespace('.'));
+ EXPECT_FALSE(isHorizontalWhitespace('`'));
+ EXPECT_FALSE(isHorizontalWhitespace('\0'));
+ EXPECT_FALSE(isHorizontalWhitespace('\x7f'));
+
+ EXPECT_TRUE(isHorizontalWhitespace(' '));
+ EXPECT_TRUE(isHorizontalWhitespace('\t'));
+ EXPECT_TRUE(isHorizontalWhitespace('\f')); // ??
+ EXPECT_TRUE(isHorizontalWhitespace('\v')); // ??
+
+ EXPECT_FALSE(isHorizontalWhitespace('\n'));
+ EXPECT_FALSE(isHorizontalWhitespace('\r'));
+
+ EXPECT_FALSE(isHorizontalWhitespace('\x80'));
+ EXPECT_FALSE(isHorizontalWhitespace('\xc2'));
+ EXPECT_FALSE(isHorizontalWhitespace('\xff'));
+}
+
+TEST(CharInfoTest, isVerticalWhitespace) {
+ EXPECT_FALSE(isVerticalWhitespace('a'));
+ EXPECT_FALSE(isVerticalWhitespace('_'));
+ EXPECT_FALSE(isVerticalWhitespace('0'));
+ EXPECT_FALSE(isVerticalWhitespace('.'));
+ EXPECT_FALSE(isVerticalWhitespace('`'));
+ EXPECT_FALSE(isVerticalWhitespace('\0'));
+ EXPECT_FALSE(isVerticalWhitespace('\x7f'));
+
+ EXPECT_FALSE(isVerticalWhitespace(' '));
+ EXPECT_FALSE(isVerticalWhitespace('\t'));
+ EXPECT_FALSE(isVerticalWhitespace('\f')); // ??
+ EXPECT_FALSE(isVerticalWhitespace('\v')); // ??
+
+ EXPECT_TRUE(isVerticalWhitespace('\n'));
+ EXPECT_TRUE(isVerticalWhitespace('\r'));
+
+ EXPECT_FALSE(isVerticalWhitespace('\x80'));
+ EXPECT_FALSE(isVerticalWhitespace('\xc2'));
+ EXPECT_FALSE(isVerticalWhitespace('\xff'));
+}
+
+TEST(CharInfoTest, isWhitespace) {
+ EXPECT_FALSE(isWhitespace('a'));
+ EXPECT_FALSE(isWhitespace('_'));
+ EXPECT_FALSE(isWhitespace('0'));
+ EXPECT_FALSE(isWhitespace('.'));
+ EXPECT_FALSE(isWhitespace('`'));
+ EXPECT_FALSE(isWhitespace('\0'));
+ EXPECT_FALSE(isWhitespace('\x7f'));
+
+ EXPECT_TRUE(isWhitespace(' '));
+ EXPECT_TRUE(isWhitespace('\t'));
+ EXPECT_TRUE(isWhitespace('\f'));
+ EXPECT_TRUE(isWhitespace('\v'));
+
+ EXPECT_TRUE(isWhitespace('\n'));
+ EXPECT_TRUE(isWhitespace('\r'));
+
+ EXPECT_FALSE(isWhitespace('\x80'));
+ EXPECT_FALSE(isWhitespace('\xc2'));
+ EXPECT_FALSE(isWhitespace('\xff'));
+}
+
+TEST(CharInfoTest, isDigit) {
+ EXPECT_TRUE(isDigit('0'));
+ EXPECT_TRUE(isDigit('9'));
+
+ EXPECT_FALSE(isDigit('a'));
+ EXPECT_FALSE(isDigit('A'));
+
+ EXPECT_FALSE(isDigit('z'));
+ EXPECT_FALSE(isDigit('Z'));
+
+ EXPECT_FALSE(isDigit('.'));
+ EXPECT_FALSE(isDigit('_'));
+
+ EXPECT_FALSE(isDigit('/'));
+ EXPECT_FALSE(isDigit('\0'));
+
+ EXPECT_FALSE(isDigit('\x80'));
+ EXPECT_FALSE(isDigit('\xc2'));
+ EXPECT_FALSE(isDigit('\xff'));
+}
+
+TEST(CharInfoTest, isHexDigit) {
+ EXPECT_TRUE(isHexDigit('0'));
+ EXPECT_TRUE(isHexDigit('9'));
+
+ EXPECT_TRUE(isHexDigit('a'));
+ EXPECT_TRUE(isHexDigit('A'));
+
+ EXPECT_FALSE(isHexDigit('z'));
+ EXPECT_FALSE(isHexDigit('Z'));
+
+ EXPECT_FALSE(isHexDigit('.'));
+ EXPECT_FALSE(isHexDigit('_'));
+
+ EXPECT_FALSE(isHexDigit('/'));
+ EXPECT_FALSE(isHexDigit('\0'));
+
+ EXPECT_FALSE(isHexDigit('\x80'));
+ EXPECT_FALSE(isHexDigit('\xc2'));
+ EXPECT_FALSE(isHexDigit('\xff'));
+}
+
+TEST(CharInfoTest, isLetter) {
+ EXPECT_FALSE(isLetter('0'));
+ EXPECT_FALSE(isLetter('9'));
+
+ EXPECT_TRUE(isLetter('a'));
+ EXPECT_TRUE(isLetter('A'));
+
+ EXPECT_TRUE(isLetter('z'));
+ EXPECT_TRUE(isLetter('Z'));
+
+ EXPECT_FALSE(isLetter('.'));
+ EXPECT_FALSE(isLetter('_'));
+
+ EXPECT_FALSE(isLetter('/'));
+ EXPECT_FALSE(isLetter('('));
+ EXPECT_FALSE(isLetter('\0'));
+
+ EXPECT_FALSE(isLetter('\x80'));
+ EXPECT_FALSE(isLetter('\xc2'));
+ EXPECT_FALSE(isLetter('\xff'));
+}
+
+TEST(CharInfoTest, isLowercase) {
+ EXPECT_FALSE(isLowercase('0'));
+ EXPECT_FALSE(isLowercase('9'));
+
+ EXPECT_TRUE(isLowercase('a'));
+ EXPECT_FALSE(isLowercase('A'));
+
+ EXPECT_TRUE(isLowercase('z'));
+ EXPECT_FALSE(isLowercase('Z'));
+
+ EXPECT_FALSE(isLowercase('.'));
+ EXPECT_FALSE(isLowercase('_'));
+
+ EXPECT_FALSE(isLowercase('/'));
+ EXPECT_FALSE(isLowercase('('));
+ EXPECT_FALSE(isLowercase('\0'));
+
+ EXPECT_FALSE(isLowercase('\x80'));
+ EXPECT_FALSE(isLowercase('\xc2'));
+ EXPECT_FALSE(isLowercase('\xff'));
+}
+
+TEST(CharInfoTest, isUppercase) {
+ EXPECT_FALSE(isUppercase('0'));
+ EXPECT_FALSE(isUppercase('9'));
+
+ EXPECT_FALSE(isUppercase('a'));
+ EXPECT_TRUE(isUppercase('A'));
+
+ EXPECT_FALSE(isUppercase('z'));
+ EXPECT_TRUE(isUppercase('Z'));
+
+ EXPECT_FALSE(isUppercase('.'));
+ EXPECT_FALSE(isUppercase('_'));
+
+ EXPECT_FALSE(isUppercase('/'));
+ EXPECT_FALSE(isUppercase('('));
+ EXPECT_FALSE(isUppercase('\0'));
+
+ EXPECT_FALSE(isUppercase('\x80'));
+ EXPECT_FALSE(isUppercase('\xc2'));
+ EXPECT_FALSE(isUppercase('\xff'));
+}
+
+TEST(CharInfoTest, isAlphanumeric) {
+ EXPECT_TRUE(isAlphanumeric('0'));
+ EXPECT_TRUE(isAlphanumeric('9'));
+
+ EXPECT_TRUE(isAlphanumeric('a'));
+ EXPECT_TRUE(isAlphanumeric('A'));
+
+ EXPECT_TRUE(isAlphanumeric('z'));
+ EXPECT_TRUE(isAlphanumeric('Z'));
+
+ EXPECT_FALSE(isAlphanumeric('.'));
+ EXPECT_FALSE(isAlphanumeric('_'));
+
+ EXPECT_FALSE(isAlphanumeric('/'));
+ EXPECT_FALSE(isAlphanumeric('('));
+ EXPECT_FALSE(isAlphanumeric('\0'));
+
+ EXPECT_FALSE(isAlphanumeric('\x80'));
+ EXPECT_FALSE(isAlphanumeric('\xc2'));
+ EXPECT_FALSE(isAlphanumeric('\xff'));
+}
+
+TEST(CharInfoTest, isPunctuation) {
+ EXPECT_FALSE(isPunctuation('0'));
+ EXPECT_FALSE(isPunctuation('9'));
+
+ EXPECT_FALSE(isPunctuation('a'));
+ EXPECT_FALSE(isPunctuation('A'));
+
+ EXPECT_FALSE(isPunctuation('z'));
+ EXPECT_FALSE(isPunctuation('Z'));
+
+ EXPECT_TRUE(isPunctuation('.'));
+ EXPECT_TRUE(isPunctuation('_'));
+
+ EXPECT_TRUE(isPunctuation('/'));
+ EXPECT_TRUE(isPunctuation('('));
+
+ EXPECT_FALSE(isPunctuation(' '));
+ EXPECT_FALSE(isPunctuation('\n'));
+ EXPECT_FALSE(isPunctuation('\0'));
+
+ EXPECT_FALSE(isPunctuation('\x80'));
+ EXPECT_FALSE(isPunctuation('\xc2'));
+ EXPECT_FALSE(isPunctuation('\xff'));
+}
+
+TEST(CharInfoTest, isPrintable) {
+ EXPECT_TRUE(isPrintable('0'));
+ EXPECT_TRUE(isPrintable('9'));
+
+ EXPECT_TRUE(isPrintable('a'));
+ EXPECT_TRUE(isPrintable('A'));
+
+ EXPECT_TRUE(isPrintable('z'));
+ EXPECT_TRUE(isPrintable('Z'));
+
+ EXPECT_TRUE(isPrintable('.'));
+ EXPECT_TRUE(isPrintable('_'));
+
+ EXPECT_TRUE(isPrintable('/'));
+ EXPECT_TRUE(isPrintable('('));
+
+ EXPECT_TRUE(isPrintable(' '));
+ EXPECT_FALSE(isPrintable('\t'));
+ EXPECT_FALSE(isPrintable('\n'));
+ EXPECT_FALSE(isPrintable('\0'));
+
+ EXPECT_FALSE(isPrintable('\x80'));
+ EXPECT_FALSE(isPrintable('\xc2'));
+ EXPECT_FALSE(isPrintable('\xff'));
+}
+
+TEST(CharInfoTest, isPreprocessingNumberBody) {
+ EXPECT_TRUE(isPreprocessingNumberBody('0'));
+ EXPECT_TRUE(isPreprocessingNumberBody('9'));
+
+ EXPECT_TRUE(isPreprocessingNumberBody('a'));
+ EXPECT_TRUE(isPreprocessingNumberBody('A'));
+
+ EXPECT_TRUE(isPreprocessingNumberBody('z'));
+ EXPECT_TRUE(isPreprocessingNumberBody('Z'));
+ EXPECT_TRUE(isPreprocessingNumberBody('.'));
+ EXPECT_TRUE(isPreprocessingNumberBody('_'));
+
+ EXPECT_FALSE(isPreprocessingNumberBody('/'));
+ EXPECT_FALSE(isPreprocessingNumberBody('('));
+ EXPECT_FALSE(isPreprocessingNumberBody('\0'));
+
+ EXPECT_FALSE(isPreprocessingNumberBody('\x80'));
+ EXPECT_FALSE(isPreprocessingNumberBody('\xc2'));
+ EXPECT_FALSE(isPreprocessingNumberBody('\xff'));
+}
+
+TEST(CharInfoTest, isRawStringDelimBody) {
+ EXPECT_TRUE(isRawStringDelimBody('0'));
+ EXPECT_TRUE(isRawStringDelimBody('9'));
+
+ EXPECT_TRUE(isRawStringDelimBody('a'));
+ EXPECT_TRUE(isRawStringDelimBody('A'));
+
+ EXPECT_TRUE(isRawStringDelimBody('z'));
+ EXPECT_TRUE(isRawStringDelimBody('Z'));
+ EXPECT_TRUE(isRawStringDelimBody('.'));
+ EXPECT_TRUE(isRawStringDelimBody('_'));
+
+ EXPECT_TRUE(isRawStringDelimBody('/'));
+ EXPECT_FALSE(isRawStringDelimBody('('));
+ EXPECT_FALSE(isRawStringDelimBody('\0'));
+
+ EXPECT_FALSE(isRawStringDelimBody('\x80'));
+ EXPECT_FALSE(isRawStringDelimBody('\xc2'));
+ EXPECT_FALSE(isRawStringDelimBody('\xff'));
+}
+
+TEST(CharInfoTest, toLowercase) {
+ EXPECT_EQ('0', toLowercase('0'));
+ EXPECT_EQ('9', toLowercase('9'));
+
+ EXPECT_EQ('a', toLowercase('a'));
+ EXPECT_EQ('a', toLowercase('A'));
+
+ EXPECT_EQ('z', toLowercase('z'));
+ EXPECT_EQ('z', toLowercase('Z'));
+
+ EXPECT_EQ('.', toLowercase('.'));
+ EXPECT_EQ('_', toLowercase('_'));
+
+ EXPECT_EQ('/', toLowercase('/'));
+ EXPECT_EQ('\0', toLowercase('\0'));
+}
+
+TEST(CharInfoTest, toUppercase) {
+ EXPECT_EQ('0', toUppercase('0'));
+ EXPECT_EQ('9', toUppercase('9'));
+
+ EXPECT_EQ('A', toUppercase('a'));
+ EXPECT_EQ('A', toUppercase('A'));
+
+ EXPECT_EQ('Z', toUppercase('z'));
+ EXPECT_EQ('Z', toUppercase('Z'));
+
+ EXPECT_EQ('.', toUppercase('.'));
+ EXPECT_EQ('_', toUppercase('_'));
+
+ EXPECT_EQ('/', toUppercase('/'));
+ EXPECT_EQ('\0', toUppercase('\0'));
+}
+
+TEST(CharInfoTest, isValidIdentifier) {
+ EXPECT_FALSE(isValidIdentifier(""));
+
+ // 1 character
+ EXPECT_FALSE(isValidIdentifier("."));
+ EXPECT_FALSE(isValidIdentifier("\n"));
+ EXPECT_FALSE(isValidIdentifier(" "));
+ EXPECT_FALSE(isValidIdentifier("\x80"));
+ EXPECT_FALSE(isValidIdentifier("\xc2"));
+ EXPECT_FALSE(isValidIdentifier("\xff"));
+ EXPECT_FALSE(isValidIdentifier("$"));
+ EXPECT_FALSE(isValidIdentifier("1"));
+
+ EXPECT_TRUE(isValidIdentifier("_"));
+ EXPECT_TRUE(isValidIdentifier("a"));
+ EXPECT_TRUE(isValidIdentifier("z"));
+ EXPECT_TRUE(isValidIdentifier("A"));
+ EXPECT_TRUE(isValidIdentifier("Z"));
+
+ // 2 characters, '_' suffix
+ EXPECT_FALSE(isValidIdentifier("._"));
+ EXPECT_FALSE(isValidIdentifier("\n_"));
+ EXPECT_FALSE(isValidIdentifier(" _"));
+ EXPECT_FALSE(isValidIdentifier("\x80_"));
+ EXPECT_FALSE(isValidIdentifier("\xc2_"));
+ EXPECT_FALSE(isValidIdentifier("\xff_"));
+ EXPECT_FALSE(isValidIdentifier("$_"));
+ EXPECT_FALSE(isValidIdentifier("1_"));
+
+ EXPECT_TRUE(isValidIdentifier("__"));
+ EXPECT_TRUE(isValidIdentifier("a_"));
+ EXPECT_TRUE(isValidIdentifier("z_"));
+ EXPECT_TRUE(isValidIdentifier("A_"));
+ EXPECT_TRUE(isValidIdentifier("Z_"));
+
+ // 2 characters, '_' prefix
+ EXPECT_FALSE(isValidIdentifier("_."));
+ EXPECT_FALSE(isValidIdentifier("_\n"));
+ EXPECT_FALSE(isValidIdentifier("_ "));
+ EXPECT_FALSE(isValidIdentifier("_\x80"));
+ EXPECT_FALSE(isValidIdentifier("_\xc2"));
+ EXPECT_FALSE(isValidIdentifier("_\xff"));
+ EXPECT_FALSE(isValidIdentifier("_$"));
+ EXPECT_TRUE(isValidIdentifier("_1"));
+
+ EXPECT_TRUE(isValidIdentifier("__"));
+ EXPECT_TRUE(isValidIdentifier("_a"));
+ EXPECT_TRUE(isValidIdentifier("_z"));
+ EXPECT_TRUE(isValidIdentifier("_A"));
+ EXPECT_TRUE(isValidIdentifier("_Z"));
+
+ // 3 characters, '__' prefix
+ EXPECT_FALSE(isValidIdentifier("__."));
+ EXPECT_FALSE(isValidIdentifier("__\n"));
+ EXPECT_FALSE(isValidIdentifier("__ "));
+ EXPECT_FALSE(isValidIdentifier("__\x80"));
+ EXPECT_FALSE(isValidIdentifier("__\xc2"));
+ EXPECT_FALSE(isValidIdentifier("__\xff"));
+ EXPECT_FALSE(isValidIdentifier("__$"));
+ EXPECT_TRUE(isValidIdentifier("__1"));
+
+ EXPECT_TRUE(isValidIdentifier("___"));
+ EXPECT_TRUE(isValidIdentifier("__a"));
+ EXPECT_TRUE(isValidIdentifier("__z"));
+ EXPECT_TRUE(isValidIdentifier("__A"));
+ EXPECT_TRUE(isValidIdentifier("__Z"));
+
+ // 3 characters, '_' prefix and suffix
+ EXPECT_FALSE(isValidIdentifier("_._"));
+ EXPECT_FALSE(isValidIdentifier("_\n_"));
+ EXPECT_FALSE(isValidIdentifier("_ _"));
+ EXPECT_FALSE(isValidIdentifier("_\x80_"));
+ EXPECT_FALSE(isValidIdentifier("_\xc2_"));
+ EXPECT_FALSE(isValidIdentifier("_\xff_"));
+ EXPECT_FALSE(isValidIdentifier("_$_"));
+ EXPECT_TRUE(isValidIdentifier("_1_"));
+
+ EXPECT_TRUE(isValidIdentifier("___"));
+ EXPECT_TRUE(isValidIdentifier("_a_"));
+ EXPECT_TRUE(isValidIdentifier("_z_"));
+ EXPECT_TRUE(isValidIdentifier("_A_"));
+ EXPECT_TRUE(isValidIdentifier("_Z_"));
+}
diff --git a/unittests/Basic/FileManagerTest.cpp b/unittests/Basic/FileManagerTest.cpp
index 91998b6..a55fcbf 100644
--- a/unittests/Basic/FileManagerTest.cpp
+++ b/unittests/Basic/FileManagerTest.cpp
@@ -7,10 +7,9 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemOptions.h"
#include "clang/Basic/FileSystemStatCache.h"
-#include "clang/Basic/FileManager.h"
-
#include "gtest/gtest.h"
using namespace llvm;
@@ -52,7 +51,7 @@ public:
// Implement FileSystemStatCache::getStat().
virtual LookupResult getStat(const char *Path, struct stat &StatBuf,
- int *FileDescriptor) {
+ bool isFile, int *FileDescriptor) {
if (StatCalls.count(Path) != 0) {
StatBuf = StatCalls[Path];
return CacheExists;
diff --git a/unittests/Basic/SourceManagerTest.cpp b/unittests/Basic/SourceManagerTest.cpp
index 6f404b5..3f09cbb 100644
--- a/unittests/Basic/SourceManagerTest.cpp
+++ b/unittests/Basic/SourceManagerTest.cpp
@@ -8,20 +8,19 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/FileManager.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
-#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/Lex/ModuleLoader.h"
+#include "clang/Basic/TargetOptions.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/HeaderSearchOptions.h"
+#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Config/config.h"
-
#include "gtest/gtest.h"
using namespace llvm;
@@ -39,7 +38,7 @@ protected:
SourceMgr(Diags, FileMgr),
TargetOpts(new TargetOptions) {
TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
- Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
+ Target = TargetInfo::CreateTargetInfo(Diags, &*TargetOpts);
}
FileSystemOptions FileMgrOpts;
@@ -53,11 +52,17 @@ protected:
};
class VoidModuleLoader : public ModuleLoader {
- virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
- Module::NameVisibilityKind Visibility,
- bool IsInclusionDirective) {
- return 0;
+ virtual ModuleLoadResult loadModule(SourceLocation ImportLoc,
+ ModuleIdPath Path,
+ Module::NameVisibilityKind Visibility,
+ bool IsInclusionDirective) {
+ return ModuleLoadResult();
}
+
+ virtual void makeModuleVisible(Module *Mod,
+ Module::NameVisibilityKind Visibility,
+ SourceLocation ImportLoc,
+ bool Complain) { }
};
TEST_F(SourceManagerTest, isBeforeInTranslationUnit) {
@@ -245,12 +250,13 @@ class MacroTracker : public PPCallbacks {
public:
explicit MacroTracker(std::vector<MacroAction> &Macros) : Macros(Macros) { }
- virtual void MacroDefined(const Token &MacroNameTok, const MacroInfo *MI) {
- Macros.push_back(MacroAction(MI->getDefinitionLoc(),
+ virtual void MacroDefined(const Token &MacroNameTok,
+ const MacroDirective *MD) {
+ Macros.push_back(MacroAction(MD->getLocation(),
MacroNameTok.getIdentifierInfo()->getName(),
true));
}
- virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo* MI,
+ virtual void MacroExpands(const Token &MacroNameTok, const MacroDirective *MD,
SourceRange Range) {
Macros.push_back(MacroAction(MacroNameTok.getLocation(),
MacroNameTok.getIdentifierInfo()->getName(),
diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt
index 989025a..334ea41 100644
--- a/unittests/CMakeLists.txt
+++ b/unittests/CMakeLists.txt
@@ -15,3 +15,4 @@ add_subdirectory(Basic)
add_subdirectory(Lex)
add_subdirectory(Frontend)
add_subdirectory(Tooling)
+add_subdirectory(Format)
diff --git a/unittests/Format/CMakeLists.txt b/unittests/Format/CMakeLists.txt
new file mode 100644
index 0000000..16d5764
--- /dev/null
+++ b/unittests/Format/CMakeLists.txt
@@ -0,0 +1,18 @@
+set(LLVM_LINK_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
+ asmparser
+ bitreader
+ support
+ mc
+ )
+
+add_clang_unittest(FormatTests
+ FormatTest.cpp
+ )
+
+target_link_libraries(FormatTests
+ clangAST
+ clangFormat
+ clangTooling
+ clangRewriteCore
+ )
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
new file mode 100644
index 0000000..e01034b
--- /dev/null
+++ b/unittests/Format/FormatTest.cpp
@@ -0,0 +1,3590 @@
+//===- unittest/Format/FormatTest.cpp - Formatting unit tests -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "format-test"
+
+#include "clang/Format/Format.h"
+#include "../Tooling/RewriterTestContext.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/Support/Debug.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace format {
+
+class FormatTest : public ::testing::Test {
+protected:
+ std::string format(llvm::StringRef Code, unsigned Offset, unsigned Length,
+ const FormatStyle &Style) {
+ DEBUG(llvm::errs() << "---\n");
+ RewriterTestContext Context;
+ FileID ID = Context.createInMemoryFile("input.cc", Code);
+ SourceLocation Start =
+ Context.Sources.getLocForStartOfFile(ID).getLocWithOffset(Offset);
+ std::vector<CharSourceRange> Ranges(
+ 1,
+ CharSourceRange::getCharRange(Start, Start.getLocWithOffset(Length)));
+ Lexer Lex(ID, Context.Sources.getBuffer(ID), Context.Sources,
+ getFormattingLangOpts());
+ tooling::Replacements Replace = reformat(
+ Style, Lex, Context.Sources, Ranges, new IgnoringDiagConsumer());
+ ReplacementCount = Replace.size();
+ EXPECT_TRUE(applyAllReplacements(Replace, Context.Rewrite));
+ DEBUG(llvm::errs() << "\n" << Context.getRewrittenText(ID) << "\n\n");
+ return Context.getRewrittenText(ID);
+ }
+
+ std::string
+ format(llvm::StringRef Code, const FormatStyle &Style = getLLVMStyle()) {
+ return format(Code, 0, Code.size(), Style);
+ }
+
+ std::string messUp(llvm::StringRef Code) {
+ std::string MessedUp(Code.str());
+ bool InComment = false;
+ bool InPreprocessorDirective = false;
+ bool JustReplacedNewline = false;
+ for (unsigned i = 0, e = MessedUp.size() - 1; i != e; ++i) {
+ if (MessedUp[i] == '/' && MessedUp[i + 1] == '/') {
+ if (JustReplacedNewline)
+ MessedUp[i - 1] = '\n';
+ InComment = true;
+ } else if (MessedUp[i] == '#' && (JustReplacedNewline || i == 0)) {
+ if (i != 0)
+ MessedUp[i - 1] = '\n';
+ InPreprocessorDirective = true;
+ } else if (MessedUp[i] == '\\' && MessedUp[i + 1] == '\n') {
+ MessedUp[i] = ' ';
+ MessedUp[i + 1] = ' ';
+ } else if (MessedUp[i] == '\n') {
+ if (InComment) {
+ InComment = false;
+ } else if (InPreprocessorDirective) {
+ InPreprocessorDirective = false;
+ } else {
+ JustReplacedNewline = true;
+ MessedUp[i] = ' ';
+ }
+ } else if (MessedUp[i] != ' ') {
+ JustReplacedNewline = false;
+ }
+ }
+ return MessedUp;
+ }
+
+ FormatStyle getLLVMStyleWithColumns(unsigned ColumnLimit) {
+ FormatStyle Style = getLLVMStyle();
+ Style.ColumnLimit = ColumnLimit;
+ return Style;
+ }
+
+ FormatStyle getGoogleStyleWithColumns(unsigned ColumnLimit) {
+ FormatStyle Style = getGoogleStyle();
+ Style.ColumnLimit = ColumnLimit;
+ return Style;
+ }
+
+ void verifyFormat(llvm::StringRef Code,
+ const FormatStyle &Style = getLLVMStyle()) {
+ EXPECT_EQ(Code.str(), format(messUp(Code), Style));
+ }
+
+ void verifyGoogleFormat(llvm::StringRef Code) {
+ verifyFormat(Code, getGoogleStyle());
+ }
+
+ void verifyIndependentOfContext(llvm::StringRef text) {
+ verifyFormat(text);
+ verifyFormat(llvm::Twine("void f() { " + text + " }").str());
+ }
+
+ int ReplacementCount;
+};
+
+TEST_F(FormatTest, MessUp) {
+ EXPECT_EQ("1 2 3", messUp("1 2 3"));
+ EXPECT_EQ("1 2 3\n", messUp("1\n2\n3\n"));
+ EXPECT_EQ("a\n//b\nc", messUp("a\n//b\nc"));
+ EXPECT_EQ("a\n#b\nc", messUp("a\n#b\nc"));
+ EXPECT_EQ("a\n#b c d\ne", messUp("a\n#b\\\nc\\\nd\ne"));
+}
+
+//===----------------------------------------------------------------------===//
+// Basic function tests.
+//===----------------------------------------------------------------------===//
+
+TEST_F(FormatTest, DoesNotChangeCorrectlyFormatedCode) {
+ EXPECT_EQ(";", format(";"));
+}
+
+TEST_F(FormatTest, FormatsGlobalStatementsAt0) {
+ EXPECT_EQ("int i;", format(" int i;"));
+ EXPECT_EQ("\nint i;", format(" \n\t \r int i;"));
+ EXPECT_EQ("int i;\nint j;", format(" int i; int j;"));
+ EXPECT_EQ("int i;\nint j;", format(" int i;\n int j;"));
+}
+
+TEST_F(FormatTest, FormatsUnwrappedLinesAtFirstFormat) {
+ EXPECT_EQ("int i;", format("int\ni;"));
+}
+
+TEST_F(FormatTest, FormatsNestedBlockStatements) {
+ EXPECT_EQ("{\n {\n {}\n }\n}", format("{{{}}}"));
+}
+
+TEST_F(FormatTest, FormatsNestedCall) {
+ verifyFormat("Method(f1, f2(f3));");
+ verifyFormat("Method(f1(f2, f3()));");
+ verifyFormat("Method(f1(f2, (f3())));");
+}
+
+TEST_F(FormatTest, NestedNameSpecifiers) {
+ verifyFormat("vector< ::Type> v;");
+ verifyFormat("::ns::SomeFunction(::ns::SomeOtherFunction())");
+}
+
+TEST_F(FormatTest, OnlyGeneratesNecessaryReplacements) {
+ EXPECT_EQ("if (a) {\n"
+ " f();\n"
+ "}",
+ format("if(a){f();}"));
+ EXPECT_EQ(4, ReplacementCount);
+ EXPECT_EQ("if (a) {\n"
+ " f();\n"
+ "}",
+ format("if (a) {\n"
+ " f();\n"
+ "}"));
+ EXPECT_EQ(0, ReplacementCount);
+}
+
+TEST_F(FormatTest, RemovesTrailingWhitespaceOfFormattedLine) {
+ EXPECT_EQ("int a;\nint b;", format("int a; \nint b;", 0, 0, getLLVMStyle()));
+ EXPECT_EQ("int a;", format("int a; "));
+ EXPECT_EQ("int a;\n", format("int a; \n \n \n "));
+ EXPECT_EQ("int a;\nint b; ",
+ format("int a; \nint b; ", 0, 0, getLLVMStyle()));
+}
+
+TEST_F(FormatTest, FormatsCorrectRegionForLeadingWhitespace) {
+ EXPECT_EQ("int b;\nint a;",
+ format("int b;\n int a;", 7, 0, getLLVMStyle()));
+ EXPECT_EQ("int b;\n int a;",
+ format("int b;\n int a;", 6, 0, getLLVMStyle()));
+
+ EXPECT_EQ("#define A \\\n"
+ " int a; \\\n"
+ " int b;",
+ format("#define A \\\n"
+ " int a; \\\n"
+ " int b;",
+ 26, 0, getLLVMStyleWithColumns(12)));
+ EXPECT_EQ("#define A \\\n"
+ " int a; \\\n"
+ " int b;",
+ format("#define A \\\n"
+ " int a; \\\n"
+ " int b;",
+ 25, 0, getLLVMStyleWithColumns(12)));
+}
+
+TEST_F(FormatTest, RemovesWhitespaceWhenTriggeredOnEmptyLine) {
+ EXPECT_EQ("int a;\n\n int b;",
+ format("int a;\n \n\n int b;", 7, 0, getLLVMStyle()));
+ EXPECT_EQ("int a;\n\n int b;",
+ format("int a;\n \n\n int b;", 9, 0, getLLVMStyle()));
+}
+
+TEST_F(FormatTest, ReformatsMovedLines) {
+ EXPECT_EQ(
+ "template <typename T> T *getFETokenInfo() const {\n"
+ " return static_cast<T *>(FETokenInfo);\n"
+ "}\n"
+ " int a; // <- Should not be formatted",
+ format(
+ "template<typename T>\n"
+ "T *getFETokenInfo() const { return static_cast<T*>(FETokenInfo); }\n"
+ " int a; // <- Should not be formatted",
+ 9, 5, getLLVMStyle()));
+}
+
+//===----------------------------------------------------------------------===//
+// Tests for control statements.
+//===----------------------------------------------------------------------===//
+
+TEST_F(FormatTest, FormatIfWithoutCompountStatement) {
+ verifyFormat("if (true)\n f();\ng();");
+ verifyFormat("if (a)\n if (b)\n if (c)\n g();\nh();");
+ verifyFormat("if (a)\n if (b) {\n f();\n }\ng();");
+
+ FormatStyle AllowsMergedIf = getGoogleStyle();
+ AllowsMergedIf.AllowShortIfStatementsOnASingleLine = true;
+ verifyFormat("if (a)\n"
+ " // comment\n"
+ " f();",
+ AllowsMergedIf);
+
+ verifyFormat("if (a) // Can't merge this\n"
+ " f();\n",
+ AllowsMergedIf);
+ verifyFormat("if (a) /* still don't merge */\n"
+ " f();",
+ AllowsMergedIf);
+ verifyFormat("if (a) { // Never merge this\n"
+ " f();\n"
+ "}",
+ AllowsMergedIf);
+ verifyFormat("if (a) { /* Never merge this */\n"
+ " f();\n"
+ "}",
+ AllowsMergedIf);
+
+ AllowsMergedIf.ColumnLimit = 14;
+ verifyFormat("if (a) return;", AllowsMergedIf);
+ verifyFormat("if (aaaaaaaaa)\n"
+ " return;",
+ AllowsMergedIf);
+
+ AllowsMergedIf.ColumnLimit = 13;
+ verifyFormat("if (a)\n return;", AllowsMergedIf);
+}
+
+TEST_F(FormatTest, ParseIfElse) {
+ verifyFormat("if (true)\n"
+ " if (true)\n"
+ " if (true)\n"
+ " f();\n"
+ " else\n"
+ " g();\n"
+ " else\n"
+ " h();\n"
+ "else\n"
+ " i();");
+ verifyFormat("if (true)\n"
+ " if (true)\n"
+ " if (true) {\n"
+ " if (true)\n"
+ " f();\n"
+ " } else {\n"
+ " g();\n"
+ " }\n"
+ " else\n"
+ " h();\n"
+ "else {\n"
+ " i();\n"
+ "}");
+}
+
+TEST_F(FormatTest, ElseIf) {
+ verifyFormat("if (a) {\n} else if (b) {\n}");
+ verifyFormat("if (a)\n"
+ " f();\n"
+ "else if (b)\n"
+ " g();\n"
+ "else\n"
+ " h();");
+}
+
+TEST_F(FormatTest, FormatsForLoop) {
+ verifyFormat(
+ "for (int VeryVeryLongLoopVariable = 0; VeryVeryLongLoopVariable < 10;\n"
+ " ++VeryVeryLongLoopVariable)\n"
+ " ;");
+ verifyFormat("for (;;)\n"
+ " f();");
+ verifyFormat("for (;;) {\n}");
+ verifyFormat("for (;;) {\n"
+ " f();\n"
+ "}");
+
+ verifyFormat(
+ "for (std::vector<UnwrappedLine>::iterator I = UnwrappedLines.begin(),\n"
+ " E = UnwrappedLines.end();\n"
+ " I != E; ++I) {\n}");
+
+ verifyFormat(
+ "for (MachineFun::iterator IIII = PrevIt, EEEE = F.end(); IIII != EEEE;\n"
+ " ++IIIII) {\n}");
+ verifyFormat("for (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaa =\n"
+ " aaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaa;\n"
+ " aaaaaaaaaaa != aaaaaaaaaaaaaaaaaaa; ++aaaaaaaaaaa) {\n}");
+ verifyFormat("for (llvm::ArrayRef<NamedDecl *>::iterator\n"
+ " I = FD->getDeclsInPrototypeScope().begin(),\n"
+ " E = FD->getDeclsInPrototypeScope().end();\n"
+ " I != E; ++I) {\n}");
+
+ // FIXME: Not sure whether we want extra identation in line 3 here:
+ verifyFormat(
+ "for (aaaaaaaaaaaaaaaaa aaaaaaaaaaa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa !=\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);\n"
+ " ++aaaaaaaaaaa) {\n}");
+ verifyFormat("for (int aaaaaaaaaaa = 1; aaaaaaaaaaa <= bbbbbbbbbbbbbbb;\n"
+ " aaaaaaaaaaa++, bbbbbbbbbbbbbbbbb++) {\n"
+ "}");
+ verifyFormat("for (some_namespace::SomeIterator iter( // force break\n"
+ " aaaaaaaaaa);\n"
+ " iter; ++iter) {\n"
+ "}");
+
+ FormatStyle NoBinPacking = getLLVMStyle();
+ NoBinPacking.BinPackParameters = false;
+ verifyFormat("for (int aaaaaaaaaaa = 1;\n"
+ " aaaaaaaaaaa <= aaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaa);\n"
+ " aaaaaaaaaaa++, bbbbbbbbbbbbbbbbb++) {\n"
+ "}",
+ NoBinPacking);
+ verifyFormat(
+ "for (std::vector<UnwrappedLine>::iterator I = UnwrappedLines.begin(),\n"
+ " E = UnwrappedLines.end();\n"
+ " I != E;\n"
+ " ++I) {\n}",
+ NoBinPacking);
+}
+
+TEST_F(FormatTest, RangeBasedForLoops) {
+ verifyFormat("for (auto aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa :\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {\n}");
+ verifyFormat("for (auto aaaaaaaaaaaaaaaaaaaaa :\n"
+ " aaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaa, aaaaaaaaaaaaa)) {\n}");
+ verifyFormat("for (const aaaaaaaaaaaaaaaaaaaaa &aaaaaaaaa :\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {\n}");
+}
+
+TEST_F(FormatTest, FormatsWhileLoop) {
+ verifyFormat("while (true) {\n}");
+ verifyFormat("while (true)\n"
+ " f();");
+ verifyFormat("while () {\n}");
+ verifyFormat("while () {\n"
+ " f();\n"
+ "}");
+}
+
+TEST_F(FormatTest, FormatsDoWhile) {
+ verifyFormat("do {\n"
+ " do_something();\n"
+ "} while (something());");
+ verifyFormat("do\n"
+ " do_something();\n"
+ "while (something());");
+}
+
+TEST_F(FormatTest, FormatsSwitchStatement) {
+ verifyFormat("switch (x) {\n"
+ "case 1:\n"
+ " f();\n"
+ " break;\n"
+ "case kFoo:\n"
+ "case ns::kBar:\n"
+ "case kBaz:\n"
+ " break;\n"
+ "default:\n"
+ " g();\n"
+ " break;\n"
+ "}");
+ verifyFormat("switch (x) {\n"
+ "case 1: {\n"
+ " f();\n"
+ " break;\n"
+ "}\n"
+ "}");
+ verifyFormat("switch (x) {\n"
+ "case 1: {\n"
+ " f();\n"
+ " {\n"
+ " g();\n"
+ " h();\n"
+ " }\n"
+ " break;\n"
+ "}\n"
+ "}");
+ verifyFormat("switch (x) {\n"
+ "case 1: {\n"
+ " f();\n"
+ " if (foo) {\n"
+ " g();\n"
+ " h();\n"
+ " }\n"
+ " break;\n"
+ "}\n"
+ "}");
+ verifyFormat("switch (x) {\n"
+ "case 1: {\n"
+ " f();\n"
+ " g();\n"
+ "} break;\n"
+ "}");
+ verifyFormat("switch (test)\n"
+ " ;");
+ verifyFormat("switch (x) {\n"
+ "default: {\n"
+ " // Do nothing.\n"
+ "}");
+ verifyFormat("switch (x) {\n"
+ "// if 1, do f()\n"
+ "case 1:\n"
+ " f();\n"
+ "}");
+ verifyFormat("switch (x) {\n"
+ "case 1:\n"
+ " // Do amazing stuff\n"
+ " {\n"
+ " f();\n"
+ " g();\n"
+ " }\n"
+ " break;\n"
+ "}");
+ verifyFormat("#define A \\\n"
+ " switch (x) { \\\n"
+ " case a: \\\n"
+ " foo = b; \\\n"
+ " }", getLLVMStyleWithColumns(20));
+
+ verifyGoogleFormat("switch (x) {\n"
+ " case 1:\n"
+ " f();\n"
+ " break;\n"
+ " case kFoo:\n"
+ " case ns::kBar:\n"
+ " case kBaz:\n"
+ " break;\n"
+ " default:\n"
+ " g();\n"
+ " break;\n"
+ "}");
+ verifyGoogleFormat("switch (x) {\n"
+ " case 1: {\n"
+ " f();\n"
+ " break;\n"
+ " }\n"
+ "}");
+ verifyGoogleFormat("switch (test)\n"
+ " ;");
+}
+
+TEST_F(FormatTest, FormatsLabels) {
+ verifyFormat("void f() {\n"
+ " some_code();\n"
+ "test_label:\n"
+ " some_other_code();\n"
+ " {\n"
+ " some_more_code();\n"
+ " another_label:\n"
+ " some_more_code();\n"
+ " }\n"
+ "}");
+ verifyFormat("some_code();\n"
+ "test_label:\n"
+ "some_other_code();");
+}
+
+//===----------------------------------------------------------------------===//
+// Tests for comments.
+//===----------------------------------------------------------------------===//
+
+TEST_F(FormatTest, UnderstandsSingleLineComments) {
+ verifyFormat("//* */");
+ verifyFormat("// line 1\n"
+ "// line 2\n"
+ "void f() {}\n");
+
+ verifyFormat("void f() {\n"
+ " // Doesn't do anything\n"
+ "}");
+ verifyFormat("void f(int i, // some comment (probably for i)\n"
+ " int j, // some comment (probably for j)\n"
+ " int k); // some comment (probably for k)");
+ verifyFormat("void f(int i,\n"
+ " // some comment (probably for j)\n"
+ " int j,\n"
+ " // some comment (probably for k)\n"
+ " int k);");
+
+ verifyFormat("int i // This is a fancy variable\n"
+ " = 5; // with nicely aligned comment.");
+
+ verifyFormat("// Leading comment.\n"
+ "int a; // Trailing comment.");
+ verifyFormat("int a; // Trailing comment\n"
+ " // on 2\n"
+ " // or 3 lines.\n"
+ "int b;");
+ verifyFormat("int a; // Trailing comment\n"
+ "\n"
+ "// Leading comment.\n"
+ "int b;");
+ verifyFormat("int a; // Comment.\n"
+ " // More details.\n"
+ "int bbbb; // Another comment.");
+ verifyFormat(
+ "int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; // comment\n"
+ "int bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; // comment\n"
+ "int cccccccccccccccccccccccccccccc; // comment\n"
+ "int ddd; // looooooooooooooooooooooooong comment\n"
+ "int aaaaaaaaaaaaaaaaaaaaaaa; // comment\n"
+ "int bbbbbbbbbbbbbbbbbbbbb; // comment\n"
+ "int ccccccccccccccccccc; // comment");
+
+ verifyFormat("#include \"a\" // comment\n"
+ "#include \"a/b/c\" // comment");
+ verifyFormat("#include <a> // comment\n"
+ "#include <a/b/c> // comment");
+
+ verifyFormat("enum E {\n"
+ " // comment\n"
+ " VAL_A, // comment\n"
+ " VAL_B\n"
+ "};");
+
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa =\n"
+ " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; // Trailing comment");
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa =\n"
+ " // Comment inside a statement.\n"
+ " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;");
+ verifyFormat(
+ "bool aaaaaaaaaaaaa = // comment\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa || aaaaaaaaaaaaaaaaaaaaaaaaaaaa ||\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa || aaaaaaaaaaaaaaaaaaaaaaaaaaaaa;");
+
+ verifyFormat("int aaaa; // aaaaa\n"
+ "int aa; // aaaaaaa",
+ getLLVMStyleWithColumns(20));
+
+ EXPECT_EQ("void f() { // This does something ..\n"
+ "}\n"
+ "int a; // This is unrelated",
+ format("void f() { // This does something ..\n"
+ " }\n"
+ "int a; // This is unrelated"));
+ EXPECT_EQ("void f() { // This does something ..\n"
+ "} // awesome..\n"
+ "\n"
+ "int a; // This is unrelated",
+ format("void f() { // This does something ..\n"
+ " } // awesome..\n"
+ " \n"
+ "int a; // This is unrelated"));
+
+ EXPECT_EQ("int i; // single line trailing comment",
+ format("int i;\\\n// single line trailing comment"));
+
+ verifyGoogleFormat("int a; // Trailing comment.");
+
+ verifyFormat("someFunction(anotherFunction( // Force break.\n"
+ " parameter));");
+
+ verifyGoogleFormat("#endif // HEADER_GUARD");
+
+ verifyFormat("const char *test[] = {\n"
+ " // A\n"
+ " \"aaaa\",\n"
+ " // B\n"
+ " \"aaaaa\",\n"
+ "};");
+ verifyGoogleFormat(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaa); // 81 cols with this comment");
+ EXPECT_EQ("D(a, {\n"
+ " // test\n"
+ " int a;\n"
+ "});",
+ format("D(a, {\n"
+ "// test\n"
+ "int a;\n"
+ "});"));
+}
+
+TEST_F(FormatTest, CanFormatCommentsLocally) {
+ EXPECT_EQ("int a; // comment\n"
+ "int b; // comment",
+ format("int a; // comment\n"
+ "int b; // comment",
+ 0, 0, getLLVMStyle()));
+ EXPECT_EQ("int a; // comment\n"
+ " // line 2\n"
+ "int b;",
+ format("int a; // comment\n"
+ " // line 2\n"
+ "int b;",
+ 28, 0, getLLVMStyle()));
+}
+
+TEST_F(FormatTest, RemovesTrailingWhitespaceOfComments) {
+ EXPECT_EQ("// comment", format("// comment "));
+ EXPECT_EQ("int aaaaaaa, bbbbbbb; // comment",
+ format("int aaaaaaa, bbbbbbb; // comment ",
+ getLLVMStyleWithColumns(33)));
+}
+
+TEST_F(FormatTest, UnderstandsMultiLineComments) {
+ verifyFormat("f(/*test=*/ true);");
+ EXPECT_EQ(
+ "f(aaaaaaaaaaaaaaaaaaaaaaaaa, /* Trailing comment for aa... */\n"
+ " bbbbbbbbbbbbbbbbbbbbbbbbb);",
+ format("f(aaaaaaaaaaaaaaaaaaaaaaaaa , /* Trailing comment for aa... */\n"
+ " bbbbbbbbbbbbbbbbbbbbbbbbb);"));
+ EXPECT_EQ(
+ "f(aaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " /* Leading comment for bb... */ bbbbbbbbbbbbbbbbbbbbbbbbb);",
+ format("f(aaaaaaaaaaaaaaaaaaaaaaaaa , \n"
+ "/* Leading comment for bb... */ bbbbbbbbbbbbbbbbbbbbbbbbb);"));
+
+ FormatStyle NoBinPacking = getLLVMStyle();
+ NoBinPacking.BinPackParameters = false;
+ verifyFormat("aaaaaaaa(/* parameter 1 */ aaaaaa,\n"
+ " /* parameter 2 */ aaaaaa,\n"
+ " /* parameter 3 */ aaaaaa,\n"
+ " /* parameter 4 */ aaaaaa);",
+ NoBinPacking);
+}
+
+TEST_F(FormatTest, AlignsMultiLineComments) {
+ EXPECT_EQ("/*\n"
+ " * Really multi-line\n"
+ " * comment.\n"
+ " */\n"
+ "void f() {}",
+ format(" /*\n"
+ " * Really multi-line\n"
+ " * comment.\n"
+ " */\n"
+ " void f() {}"));
+ EXPECT_EQ("class C {\n"
+ " /*\n"
+ " * Another multi-line\n"
+ " * comment.\n"
+ " */\n"
+ " void f() {}\n"
+ "};",
+ format("class C {\n"
+ "/*\n"
+ " * Another multi-line\n"
+ " * comment.\n"
+ " */\n"
+ "void f() {}\n"
+ "};"));
+ EXPECT_EQ("/*\n"
+ " 1. This is a comment with non-trivial formatting.\n"
+ " 1.1. We have to indent/outdent all lines equally\n"
+ " 1.1.1. to keep the formatting.\n"
+ " */",
+ format(" /*\n"
+ " 1. This is a comment with non-trivial formatting.\n"
+ " 1.1. We have to indent/outdent all lines equally\n"
+ " 1.1.1. to keep the formatting.\n"
+ " */"));
+ EXPECT_EQ("/*\n"
+ " Don't try to outdent if there's not enough inentation.\n"
+ " */",
+ format(" /*\n"
+ " Don't try to outdent if there's not enough inentation.\n"
+ " */"));
+}
+
+TEST_F(FormatTest, SplitsLongCxxComments) {
+ EXPECT_EQ("// A comment that\n"
+ "// doesn't fit on\n"
+ "// one line",
+ format("// A comment that doesn't fit on one line",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("if (true) // A comment that\n"
+ " // doesn't fit on\n"
+ " // one line",
+ format("if (true) // A comment that doesn't fit on one line ",
+ getLLVMStyleWithColumns(30)));
+ EXPECT_EQ("// Don't_touch_leading_whitespace",
+ format("// Don't_touch_leading_whitespace",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ(
+ "//Don't add leading\n"
+ "//whitespace",
+ format("//Don't add leading whitespace", getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("// A comment before\n"
+ "// a macro\n"
+ "// definition\n"
+ "#define a b",
+ format("// A comment before a macro definition\n"
+ "#define a b",
+ getLLVMStyleWithColumns(20)));
+}
+
+TEST_F(FormatTest, ParsesCommentsAdjacentToPPDirectives) {
+ EXPECT_EQ("namespace {}\n// Test\n#define A",
+ format("namespace {}\n // Test\n#define A"));
+ EXPECT_EQ("namespace {}\n/* Test */\n#define A",
+ format("namespace {}\n /* Test */\n#define A"));
+ EXPECT_EQ("namespace {}\n/* Test */ #define A",
+ format("namespace {}\n /* Test */ #define A"));
+}
+
+TEST_F(FormatTest, SplitsLongLinesInComments) {
+ EXPECT_EQ("/* This is a long\n"
+ " * comment that\n"
+ " * doesn't\n"
+ " * fit on one line.\n"
+ " */",
+ format("/* "
+ "This is a long "
+ "comment that "
+ "doesn't "
+ "fit on one line. */",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("/*\n"
+ "This is a long\n"
+ "comment that doesn't\n"
+ "fit on one line.\n"
+ "*/",
+ format("/*\n"
+ "This is a long "
+ "comment that doesn't "
+ "fit on one line. \n"
+ "*/", getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("/*\n"
+ " * This is a long\n"
+ " * comment that\n"
+ " * doesn't fit on\n"
+ " * one line.\n"
+ " */",
+ format("/* \n"
+ " * This is a long "
+ " comment that "
+ " doesn't fit on "
+ " one line. \n"
+ " */", getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("/*\n"
+ " * This_is_a_comment_with_words_that_dont_fit_on_one_line\n"
+ " * so_it_should_be_broken\n"
+ " * wherever_a_space_occurs\n"
+ " */",
+ format("/*\n"
+ " * This_is_a_comment_with_words_that_dont_fit_on_one_line "
+ " so_it_should_be_broken "
+ " wherever_a_space_occurs \n"
+ " */",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("/*\n"
+ " * This_comment_can_not_be_broken_into_lines\n"
+ " */",
+ format("/*\n"
+ " * This_comment_can_not_be_broken_into_lines\n"
+ " */",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("{\n"
+ " /*\n"
+ " This is another\n"
+ " long comment that\n"
+ " doesn't fit on one\n"
+ " line 1234567890\n"
+ " */\n"
+ "}",
+ format("{\n"
+ "/*\n"
+ "This is another "
+ " long comment that "
+ " doesn't fit on one"
+ " line 1234567890\n"
+ "*/\n"
+ "}", getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("{\n"
+ " /*\n"
+ " * This i s\n"
+ " * another comment\n"
+ " * t hat doesn' t\n"
+ " * fit on one l i\n"
+ " * n e\n"
+ " */\n"
+ "}",
+ format("{\n"
+ "/*\n"
+ " * This i s"
+ " another comment"
+ " t hat doesn' t"
+ " fit on one l i"
+ " n e\n"
+ " */\n"
+ "}", getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("/*\n"
+ " * This is a long\n"
+ " * comment that\n"
+ " * doesn't fit on\n"
+ " * one line\n"
+ " */",
+ format(" /*\n"
+ " * This is a long comment that doesn't fit on one line\n"
+ " */", getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("{\n"
+ " if (something) /* This is a\n"
+ "long comment */\n"
+ " ;\n"
+ "}",
+ format("{\n"
+ " if (something) /* This is a long comment */\n"
+ " ;\n"
+ "}",
+ getLLVMStyleWithColumns(30)));
+}
+
+TEST_F(FormatTest, SplitsLongLinesInCommentsInPreprocessor) {
+ EXPECT_EQ("#define X \\\n"
+ " /* \\\n"
+ " Test \\\n"
+ " Macro comment \\\n"
+ " with a long \\\n"
+ " line \\\n"
+ // FIXME: We should look at the length of the last line of the token
+ // instead of the full token's length.
+ //" */ \\\n"
+ " */\\\n"
+ " A + B",
+ format("#define X \\\n"
+ " /*\n"
+ " Test\n"
+ " Macro comment with a long line\n"
+ " */ \\\n"
+ " A + B",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("#define X \\\n"
+ " /* Macro comment \\\n"
+ " with a long \\\n"
+ // FIXME: We should look at the length of the last line of the token
+ // instead of the full token's length.
+ //" line */ \\\n"
+ " line */\\\n"
+ " A + B",
+ format("#define X \\\n"
+ " /* Macro comment with a long\n"
+ " line */ \\\n"
+ " A + B",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("#define X \\\n"
+ " /* Macro comment \\\n"
+ " * with a long \\\n"
+ // FIXME: We should look at the length of the last line of the token
+ // instead of the full token's length.
+ //" * line */ \\\n"
+ " * line */\\\n"
+ " A + B",
+ format("#define X \\\n"
+ " /* Macro comment with a long line */ \\\n"
+ " A + B",
+ getLLVMStyleWithColumns(20)));
+}
+
+TEST_F(FormatTest, CommentsInStaticInitializers) {
+ EXPECT_EQ(
+ "static SomeType type = { aaaaaaaaaaaaaaaaaaaa, /* comment */\n"
+ " aaaaaaaaaaaaaaaaaaaa /* comment */,\n"
+ " /* comment */ aaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaa, // comment\n"
+ " aaaaaaaaaaaaaaaaaaaa };",
+ format("static SomeType type = { aaaaaaaaaaaaaaaaaaaa , /* comment */\n"
+ " aaaaaaaaaaaaaaaaaaaa /* comment */ ,\n"
+ " /* comment */ aaaaaaaaaaaaaaaaaaaa ,\n"
+ " aaaaaaaaaaaaaaaaaaaa , // comment\n"
+ " aaaaaaaaaaaaaaaaaaaa };"));
+ verifyFormat("static SomeType type = { aaaaaaaaaaa, // comment for aa...\n"
+ " bbbbbbbbbbb, ccccccccccc };");
+ verifyFormat("static SomeType type = { aaaaaaaaaaa,\n"
+ " // comment for bb....\n"
+ " bbbbbbbbbbb, ccccccccccc };");
+ verifyGoogleFormat(
+ "static SomeType type = { aaaaaaaaaaa, // comment for aa...\n"
+ " bbbbbbbbbbb, ccccccccccc };");
+ verifyGoogleFormat("static SomeType type = { aaaaaaaaaaa,\n"
+ " // comment for bb....\n"
+ " bbbbbbbbbbb, ccccccccccc };");
+
+ verifyFormat("S s = { { a, b, c }, // Group #1\n"
+ " { d, e, f }, // Group #2\n"
+ " { g, h, i } }; // Group #3");
+ verifyFormat("S s = { { // Group #1\n"
+ " a, b, c },\n"
+ " { // Group #2\n"
+ " d, e, f },\n"
+ " { // Group #3\n"
+ " g, h, i } };");
+
+ EXPECT_EQ("S s = {\n"
+ " // Some comment\n"
+ " a,\n"
+ "\n"
+ " // Comment after empty line\n"
+ " b\n"
+ "}",
+ format("S s = {\n"
+ " // Some comment\n"
+ " a,\n"
+ " \n"
+ " // Comment after empty line\n"
+ " b\n"
+ "}"));
+ EXPECT_EQ("S s = { a, b };", format("S s = {\n"
+ " a,\n"
+ "\n"
+ " b\n"
+ "};"));
+ verifyFormat("const uint8_t aaaaaaaaaaaaaaaaaaaaaa[0] = {\n"
+ " 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // comment\n"
+ " 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // comment\n"
+ " 0x00, 0x00, 0x00, 0x00 // comment\n"
+ "};");
+}
+
+//===----------------------------------------------------------------------===//
+// Tests for classes, namespaces, etc.
+//===----------------------------------------------------------------------===//
+
+TEST_F(FormatTest, DoesNotBreakSemiAfterClassDecl) {
+ verifyFormat("class A {\n};");
+}
+
+TEST_F(FormatTest, UnderstandsAccessSpecifiers) {
+ verifyFormat("class A {\n"
+ "public:\n"
+ "protected:\n"
+ "private:\n"
+ " void f() {}\n"
+ "};");
+ verifyGoogleFormat("class A {\n"
+ " public:\n"
+ " protected:\n"
+ " private:\n"
+ " void f() {}\n"
+ "};");
+}
+
+TEST_F(FormatTest, SeparatesLogicalBlocks) {
+ EXPECT_EQ("class A {\n"
+ "public:\n"
+ " void f();\n"
+ "\n"
+ "private:\n"
+ " void g() {}\n"
+ " // test\n"
+ "protected:\n"
+ " int h;\n"
+ "};",
+ format("class A {\n"
+ "public:\n"
+ "void f();\n"
+ "private:\n"
+ "void g() {}\n"
+ "// test\n"
+ "protected:\n"
+ "int h;\n"
+ "};"));
+}
+
+TEST_F(FormatTest, FormatsDerivedClass) {
+ verifyFormat("class A : public B {\n};");
+ verifyFormat("class A : public ::B {\n};");
+
+ verifyFormat(
+ "class AAAAAAAAAAAAAAAAAAAA : public BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB,\n"
+ " public CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC {\n"
+ "};\n");
+ verifyFormat("class AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA :\n"
+ " public BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB,\n"
+ " public CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC {\n"
+ "};\n");
+ verifyFormat(
+ "class A : public B, public C, public D, public E, public F, public G {\n"
+ "};");
+ verifyFormat("class AAAAAAAAAAAA : public B,\n"
+ " public C,\n"
+ " public D,\n"
+ " public E,\n"
+ " public F,\n"
+ " public G {\n"
+ "};");
+}
+
+TEST_F(FormatTest, FormatsVariableDeclarationsAfterStructOrClass) {
+ verifyFormat("class A {\n} a, b;");
+ verifyFormat("struct A {\n} a, b;");
+ verifyFormat("union A {\n} a;");
+}
+
+TEST_F(FormatTest, FormatsEnum) {
+ verifyFormat("enum {\n"
+ " Zero,\n"
+ " One = 1,\n"
+ " Two = One + 1,\n"
+ " Three = (One + Two),\n"
+ " Four = (Zero && (One ^ Two)) | (One << Two),\n"
+ " Five = (One, Two, Three, Four, 5)\n"
+ "};");
+ verifyFormat("enum Enum {\n"
+ "};");
+ verifyFormat("enum {\n"
+ "};");
+ verifyFormat("enum X E {\n} d;");
+ verifyFormat("enum __attribute__((...)) E {\n} d;");
+ verifyFormat("enum __declspec__((...)) E {\n} d;");
+ verifyFormat("enum X f() {\n a();\n return 42;\n}");
+}
+
+TEST_F(FormatTest, FormatsBitfields) {
+ verifyFormat("struct Bitfields {\n"
+ " unsigned sClass : 8;\n"
+ " unsigned ValueKind : 2;\n"
+ "};");
+}
+
+TEST_F(FormatTest, FormatsNamespaces) {
+ verifyFormat("namespace some_namespace {\n"
+ "class A {\n};\n"
+ "void f() { f(); }\n"
+ "}");
+ verifyFormat("namespace {\n"
+ "class A {\n};\n"
+ "void f() { f(); }\n"
+ "}");
+ verifyFormat("inline namespace X {\n"
+ "class A {\n};\n"
+ "void f() { f(); }\n"
+ "}");
+ verifyFormat("using namespace some_namespace;\n"
+ "class A {\n};\n"
+ "void f() { f(); }");
+
+ // This code is more common than we thought; if we
+ // layout this correctly the semicolon will go into
+ // its own line, which is undesireable.
+ verifyFormat("namespace {\n};");
+ verifyFormat("namespace {\n"
+ "class A {\n"
+ "};\n"
+ "};");
+}
+
+TEST_F(FormatTest, FormatsExternC) { verifyFormat("extern \"C\" {\nint a;"); }
+
+TEST_F(FormatTest, FormatsInlineASM) {
+ verifyFormat("asm(\"xyz\" : \"=a\"(a), \"=d\"(b) : \"a\"(data));");
+ verifyFormat(
+ "asm(\"movq\\t%%rbx, %%rsi\\n\\t\"\n"
+ " \"cpuid\\n\\t\"\n"
+ " \"xchgq\\t%%rbx, %%rsi\\n\\t\"\n"
+ " : \"=a\" (*rEAX), \"=S\" (*rEBX), \"=c\" (*rECX), \"=d\" (*rEDX)\n"
+ " : \"a\"(value));");
+}
+
+TEST_F(FormatTest, FormatTryCatch) {
+ // FIXME: Handle try-catch explicitly in the UnwrappedLineParser, then we'll
+ // also not create single-line-blocks.
+ verifyFormat("try {\n"
+ " throw a * b;\n"
+ "}\n"
+ "catch (int a) {\n"
+ " // Do nothing.\n"
+ "}\n"
+ "catch (...) {\n"
+ " exit(42);\n"
+ "}");
+
+ // Function-level try statements.
+ verifyFormat("int f() try { return 4; }\n"
+ "catch (...) {\n"
+ " return 5;\n"
+ "}");
+ verifyFormat("class A {\n"
+ " int a;\n"
+ " A() try : a(0) {}\n"
+ " catch (...) {\n"
+ " throw;\n"
+ " }\n"
+ "};\n");
+}
+
+TEST_F(FormatTest, FormatObjCTryCatch) {
+ verifyFormat("@try {\n"
+ " f();\n"
+ "}\n"
+ "@catch (NSException e) {\n"
+ " @throw;\n"
+ "}\n"
+ "@finally {\n"
+ " exit(42);\n"
+ "}");
+}
+
+TEST_F(FormatTest, StaticInitializers) {
+ verifyFormat("static SomeClass SC = { 1, 'a' };");
+
+ // FIXME: Format like enums if the static initializer does not fit on a line.
+ verifyFormat(
+ "static SomeClass WithALoooooooooooooooooooongName = {\n"
+ " 100000000, \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n"
+ "};");
+
+ verifyFormat(
+ "static SomeClass = { a, b, c, d, e, f, g, h, i, j,\n"
+ " looooooooooooooooooooooooooooooooooongname,\n"
+ " looooooooooooooooooooooooooooooong };");
+ // Allow bin-packing in static initializers as this would often lead to
+ // terrible results, e.g.:
+ verifyGoogleFormat(
+ "static SomeClass = { a, b, c, d, e, f, g, h, i, j,\n"
+ " looooooooooooooooooooooooooooooooooongname,\n"
+ " looooooooooooooooooooooooooooooong };");
+}
+
+TEST_F(FormatTest, NestedStaticInitializers) {
+ verifyFormat("static A x = { { {} } };\n");
+ verifyFormat("static A x = { { { init1, init2, init3, init4 },\n"
+ " { init1, init2, init3, init4 } } };");
+
+ verifyFormat("somes Status::global_reps[3] = {\n"
+ " { kGlobalRef, OK_CODE, NULL, NULL, NULL },\n"
+ " { kGlobalRef, CANCELLED_CODE, NULL, NULL, NULL },\n"
+ " { kGlobalRef, UNKNOWN_CODE, NULL, NULL, NULL }\n"
+ "};");
+ verifyGoogleFormat("somes Status::global_reps[3] = {\n"
+ " { kGlobalRef, OK_CODE, NULL, NULL, NULL },\n"
+ " { kGlobalRef, CANCELLED_CODE, NULL, NULL, NULL },\n"
+ " { kGlobalRef, UNKNOWN_CODE, NULL, NULL, NULL }\n"
+ "};");
+ verifyFormat(
+ "CGRect cg_rect = { { rect.fLeft, rect.fTop },\n"
+ " { rect.fRight - rect.fLeft, rect.fBottom - rect.fTop"
+ " } };");
+
+ verifyFormat(
+ "SomeArrayOfSomeType a = { { { 1, 2, 3 }, { 1, 2, 3 },\n"
+ " { 111111111111111111111111111111,\n"
+ " 222222222222222222222222222222,\n"
+ " 333333333333333333333333333333 },\n"
+ " { 1, 2, 3 }, { 1, 2, 3 } } };");
+ verifyFormat(
+ "SomeArrayOfSomeType a = { { { 1, 2, 3 } }, { { 1, 2, 3 } },\n"
+ " { { 111111111111111111111111111111,\n"
+ " 222222222222222222222222222222,\n"
+ " 333333333333333333333333333333 } },\n"
+ " { { 1, 2, 3 } }, { { 1, 2, 3 } } };");
+
+ // FIXME: We might at some point want to handle this similar to parameter
+ // lists, where we have an option to put each on a single line.
+ verifyFormat(
+ "struct {\n"
+ " unsigned bit;\n"
+ " const char *const name;\n"
+ "} kBitsToOs[] = { { kOsMac, \"Mac\" }, { kOsWin, \"Windows\" },\n"
+ " { kOsLinux, \"Linux\" }, { kOsCrOS, \"Chrome OS\" } };");
+}
+
+TEST_F(FormatTest, FormatsSmallMacroDefinitionsInSingleLine) {
+ verifyFormat("#define ALooooooooooooooooooooooooooooooooooooooongMacro("
+ " \\\n"
+ " aLoooooooooooooooooooooooongFuuuuuuuuuuuuuunctiooooooooo)");
+}
+
+TEST_F(FormatTest, DoesNotBreakPureVirtualFunctionDefinition) {
+ verifyFormat(
+ "virtual void\n"
+ "write(ELFWriter *writerrr, OwningPtr<FileOutputBuffer> &buffer) = 0;");
+}
+
+TEST_F(FormatTest, LayoutUnknownPPDirective) {
+ EXPECT_EQ("#123 \"A string literal\"",
+ format(" # 123 \"A string literal\""));
+ EXPECT_EQ("#;", format("#;"));
+ verifyFormat("#\n;\n;\n;");
+}
+
+TEST_F(FormatTest, UnescapedEndOfLineEndsPPDirective) {
+ EXPECT_EQ("#line 42 \"test\"\n",
+ format("# \\\n line \\\n 42 \\\n \"test\"\n"));
+ EXPECT_EQ("#define A B\n", format("# \\\n define \\\n A \\\n B\n",
+ getLLVMStyleWithColumns(12)));
+}
+
+TEST_F(FormatTest, EndOfFileEndsPPDirective) {
+ EXPECT_EQ("#line 42 \"test\"",
+ format("# \\\n line \\\n 42 \\\n \"test\""));
+ EXPECT_EQ("#define A B", format("# \\\n define \\\n A \\\n B"));
+}
+
+TEST_F(FormatTest, IndentsPPDirectiveInReducedSpace) {
+ verifyFormat("#define A(BB)", getLLVMStyleWithColumns(13));
+ verifyFormat("#define A( \\\n BB)", getLLVMStyleWithColumns(12));
+ verifyFormat("#define A( \\\n A, B)", getLLVMStyleWithColumns(12));
+ // FIXME: We never break before the macro name.
+ verifyFormat("#define AA(\\\n B)", getLLVMStyleWithColumns(12));
+
+ verifyFormat("#define A A\n#define A A");
+ verifyFormat("#define A(X) A\n#define A A");
+
+ verifyFormat("#define Something Other", getLLVMStyleWithColumns(23));
+ verifyFormat("#define Something \\\n Other", getLLVMStyleWithColumns(22));
+}
+
+TEST_F(FormatTest, HandlePreprocessorDirectiveContext) {
+ EXPECT_EQ("// somecomment\n"
+ "#include \"a.h\"\n"
+ "#define A( \\\n"
+ " A, B)\n"
+ "#include \"b.h\"\n"
+ "// somecomment\n",
+ format(" // somecomment\n"
+ " #include \"a.h\"\n"
+ "#define A(A,\\\n"
+ " B)\n"
+ " #include \"b.h\"\n"
+ " // somecomment\n",
+ getLLVMStyleWithColumns(13)));
+}
+
+TEST_F(FormatTest, LayoutSingleHash) { EXPECT_EQ("#\na;", format("#\na;")); }
+
+TEST_F(FormatTest, LayoutCodeInMacroDefinitions) {
+ EXPECT_EQ("#define A \\\n"
+ " c; \\\n"
+ " e;\n"
+ "f;",
+ format("#define A c; e;\n"
+ "f;",
+ getLLVMStyleWithColumns(14)));
+}
+
+TEST_F(FormatTest, LayoutRemainingTokens) { EXPECT_EQ("{}", format("{}")); }
+
+TEST_F(FormatTest, LayoutSingleUnwrappedLineInMacro) {
+ EXPECT_EQ("# define A\\\n b;",
+ format("# define A b;", 11, 2, getLLVMStyleWithColumns(11)));
+}
+
+TEST_F(FormatTest, MacroDefinitionInsideStatement) {
+ EXPECT_EQ("int x,\n"
+ "#define A\n"
+ " y;",
+ format("int x,\n#define A\ny;"));
+}
+
+TEST_F(FormatTest, HashInMacroDefinition) {
+ verifyFormat("#define A \\\n b #c;", getLLVMStyleWithColumns(11));
+ verifyFormat("#define A \\\n"
+ " { \\\n"
+ " f(#c);\\\n"
+ " }",
+ getLLVMStyleWithColumns(11));
+
+ verifyFormat("#define A(X) \\\n"
+ " void function##X()",
+ getLLVMStyleWithColumns(22));
+
+ verifyFormat("#define A(a, b, c) \\\n"
+ " void a##b##c()",
+ getLLVMStyleWithColumns(22));
+
+ verifyFormat("#define A void # ## #", getLLVMStyleWithColumns(22));
+}
+
+TEST_F(FormatTest, RespectWhitespaceInMacroDefinitions) {
+ verifyFormat("#define A (1)");
+}
+
+TEST_F(FormatTest, EmptyLinesInMacroDefinitions) {
+ EXPECT_EQ("#define A b;", format("#define A \\\n"
+ " \\\n"
+ " b;",
+ getLLVMStyleWithColumns(25)));
+ EXPECT_EQ("#define A \\\n"
+ " \\\n"
+ " a; \\\n"
+ " b;",
+ format("#define A \\\n"
+ " \\\n"
+ " a; \\\n"
+ " b;",
+ getLLVMStyleWithColumns(11)));
+ EXPECT_EQ("#define A \\\n"
+ " a; \\\n"
+ " \\\n"
+ " b;",
+ format("#define A \\\n"
+ " a; \\\n"
+ " \\\n"
+ " b;",
+ getLLVMStyleWithColumns(11)));
+}
+
+TEST_F(FormatTest, MacroDefinitionsWithIncompleteCode) {
+ verifyFormat("#define A :");
+
+ // FIXME: Improve formatting of case labels in macros.
+ verifyFormat("#define SOMECASES \\\n"
+ " case 1: \\\n"
+ " case 2\n",
+ getLLVMStyleWithColumns(20));
+
+ verifyFormat("#define A template <typename T>");
+ verifyFormat("#define STR(x) #x\n"
+ "f(STR(this_is_a_string_literal{));");
+}
+
+TEST_F(FormatTest, IndentPreprocessorDirectivesAtZero) {
+ EXPECT_EQ("{\n {\n#define A\n }\n}", format("{{\n#define A\n}}"));
+}
+
+TEST_F(FormatTest, FormatHashIfNotAtStartOfLine) {
+ verifyFormat("{\n { a #c; }\n}");
+}
+
+TEST_F(FormatTest, FormatUnbalancedStructuralElements) {
+ EXPECT_EQ("#define A \\\n { \\\n {\nint i;",
+ format("#define A { {\nint i;", getLLVMStyleWithColumns(11)));
+ EXPECT_EQ("#define A \\\n } \\\n }\nint i;",
+ format("#define A } }\nint i;", getLLVMStyleWithColumns(11)));
+}
+
+TEST_F(FormatTest, EscapedNewlineAtStartOfTokenInMacroDefinition) {
+ EXPECT_EQ(
+ "#define A \\\n int i; \\\n int j;",
+ format("#define A \\\nint i;\\\n int j;", getLLVMStyleWithColumns(11)));
+}
+
+TEST_F(FormatTest, CalculateSpaceOnConsecutiveLinesInMacro) {
+ verifyFormat("#define A \\\n"
+ " int v( \\\n"
+ " a); \\\n"
+ " int i;",
+ getLLVMStyleWithColumns(11));
+}
+
+TEST_F(FormatTest, MixingPreprocessorDirectivesAndNormalCode) {
+ EXPECT_EQ(
+ "#define ALooooooooooooooooooooooooooooooooooooooongMacro("
+ " \\\n"
+ " aLoooooooooooooooooooooooongFuuuuuuuuuuuuuunctiooooooooo)\n"
+ "\n"
+ "AlooooooooooooooooooooooooooooooooooooooongCaaaaaaaaaal(\n"
+ " aLooooooooooooooooooooooonPaaaaaaaaaaaaaaaaaaaaarmmmm);\n",
+ format(" #define ALooooooooooooooooooooooooooooooooooooooongMacro("
+ "\\\n"
+ "aLoooooooooooooooooooooooongFuuuuuuuuuuuuuunctiooooooooo)\n"
+ " \n"
+ " AlooooooooooooooooooooooooooooooooooooooongCaaaaaaaaaal(\n"
+ " aLooooooooooooooooooooooonPaaaaaaaaaaaaaaaaaaaaarmmmm);\n"));
+}
+
+TEST_F(FormatTest, LayoutStatementsAroundPreprocessorDirectives) {
+ EXPECT_EQ("int\n"
+ "#define A\n"
+ "a;",
+ format("int\n#define A\na;"));
+ verifyFormat("functionCallTo(\n"
+ " someOtherFunction(\n"
+ " withSomeParameters, whichInSequence,\n"
+ " areLongerThanALine(andAnotherCall,\n"
+ "#define A B\n"
+ " withMoreParamters,\n"
+ " whichStronglyInfluenceTheLayout),\n"
+ " andMoreParameters),\n"
+ " trailing);",
+ getLLVMStyleWithColumns(69));
+}
+
+TEST_F(FormatTest, LayoutBlockInsideParens) {
+ EXPECT_EQ("functionCall({\n"
+ " int i;\n"
+ "});",
+ format(" functionCall ( {int i;} );"));
+}
+
+TEST_F(FormatTest, LayoutBlockInsideStatement) {
+ EXPECT_EQ("SOME_MACRO { int i; }\n"
+ "int i;",
+ format(" SOME_MACRO {int i;} int i;"));
+}
+
+TEST_F(FormatTest, LayoutNestedBlocks) {
+ verifyFormat("void AddOsStrings(unsigned bitmask) {\n"
+ " struct s {\n"
+ " int i;\n"
+ " };\n"
+ " s kBitsToOs[] = { { 10 } };\n"
+ " for (int i = 0; i < 10; ++i)\n"
+ " return;\n"
+ "}");
+}
+
+TEST_F(FormatTest, PutEmptyBlocksIntoOneLine) {
+ EXPECT_EQ("{}", format("{}"));
+
+ // Negative test for enum.
+ verifyFormat("enum E {\n};");
+
+ // Note that when there's a missing ';', we still join...
+ verifyFormat("enum E {}");
+}
+
+//===----------------------------------------------------------------------===//
+// Line break tests.
+//===----------------------------------------------------------------------===//
+
+TEST_F(FormatTest, FormatsFunctionDefinition) {
+ verifyFormat("void f(int a, int b, int c, int d, int e, int f, int g,"
+ " int h, int j, int f,\n"
+ " int c, int ddddddddddddd) {}");
+}
+
+TEST_F(FormatTest, FormatsAwesomeMethodCall) {
+ verifyFormat(
+ "SomeLongMethodName(SomeReallyLongMethod(CallOtherReallyLongMethod(\n"
+ " parameter, parameter, parameter)),\n"
+ " SecondLongCall(parameter));");
+}
+
+TEST_F(FormatTest, PreventConfusingIndents) {
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa),\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaa);");
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa[\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaa[\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa],\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaa];");
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa<\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaa<\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaa>;");
+ verifyFormat("int a = bbbb && ccc && fffff(\n"
+ "#define A Just forcing a new line\n"
+ " ddd);");
+}
+
+TEST_F(FormatTest, ConstructorInitializers) {
+ verifyFormat("Constructor() : Initializer(FitsOnTheLine) {}");
+ verifyFormat("Constructor() : Inttializer(FitsOnTheLine) {}",
+ getLLVMStyleWithColumns(45));
+ verifyFormat("Constructor()\n"
+ " : Inttializer(FitsOnTheLine) {}",
+ getLLVMStyleWithColumns(44));
+ verifyFormat("Constructor()\n"
+ " : Inttializer(FitsOnTheLine) {}",
+ getLLVMStyleWithColumns(43));
+
+ verifyFormat(
+ "SomeClass::Constructor()\n"
+ " : aaaaaaaaaaaaa(aaaaaaaaaaaaaa), aaaaaaaaaaaaaaa(aaaaaaaaaaaa) {}");
+
+ verifyFormat(
+ "SomeClass::Constructor()\n"
+ " : aaaaaaaaaaaaa(aaaaaaaaaaaaaa), aaaaaaaaaaaaa(aaaaaaaaaaaaaa),\n"
+ " aaaaaaaaaaaaa(aaaaaaaaaaaaaa) {}");
+ verifyFormat(
+ "SomeClass::Constructor()\n"
+ " : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa),\n"
+ " aaaaaaaaaaaaaaa(aaaaaaaaaaaa) {}");
+
+ verifyFormat("Constructor()\n"
+ " : aaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaa),\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaa),\n"
+ " aaaaaaaaaaaaaaaaaaaaaaa() {}");
+
+ verifyFormat("Constructor()\n"
+ " : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}");
+
+ verifyFormat("Constructor(int Parameter = 0)\n"
+ " : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaa),\n"
+ " aaaaaaaaaaaa(aaaaaaaaaaaaaaaaa) {}");
+
+ // Here a line could be saved by splitting the second initializer onto two
+ // lines, but that is not desireable.
+ verifyFormat("Constructor()\n"
+ " : aaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaa),\n"
+ " aaaaaaaaaaa(aaaaaaaaaaa),\n"
+ " aaaaaaaaaaaaaaaaaaaaat(aaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}");
+
+ FormatStyle OnePerLine = getLLVMStyle();
+ OnePerLine.ConstructorInitializerAllOnOneLineOrOnePerLine = true;
+ verifyFormat("SomeClass::Constructor()\n"
+ " : aaaaaaaaaaaaa(aaaaaaaaaaaaaa),\n"
+ " aaaaaaaaaaaaa(aaaaaaaaaaaaaa),\n"
+ " aaaaaaaaaaaaa(aaaaaaaaaaaaaa) {}",
+ OnePerLine);
+ verifyFormat("SomeClass::Constructor()\n"
+ " : aaaaaaaaaaaaa(aaaaaaaaaaaaaa), // Some comment\n"
+ " aaaaaaaaaaaaa(aaaaaaaaaaaaaa),\n"
+ " aaaaaaaaaaaaa(aaaaaaaaaaaaaa) {}",
+ OnePerLine);
+ verifyFormat("MyClass::MyClass(int var)\n"
+ " : some_var_(var), // 4 space indent\n"
+ " some_other_var_(var + 1) { // lined up\n"
+ "}",
+ OnePerLine);
+ verifyFormat("Constructor()\n"
+ " : aaaaa(aaaaaa),\n"
+ " aaaaa(aaaaaa),\n"
+ " aaaaa(aaaaaa),\n"
+ " aaaaa(aaaaaa),\n"
+ " aaaaa(aaaaaa) {}",
+ OnePerLine);
+
+ // This test takes VERY long when memoization is broken.
+ OnePerLine.BinPackParameters = false;
+ std::string input = "Constructor()\n"
+ " : aaaa(a,\n";
+ for (unsigned i = 0, e = 80; i != e; ++i) {
+ input += " a,\n";
+ }
+ input += " a) {}";
+ verifyFormat(input, OnePerLine);
+}
+
+TEST_F(FormatTest, BreaksAsHighAsPossible) {
+ verifyFormat(
+ "void f() {\n"
+ " if ((aaaaaaaaaaaaaaaaaaaaaaaaaaaaa && aaaaaaaaaaaaaaaaaaaaaaaaaa) ||\n"
+ " (bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb && bbbbbbbbbbbbbbbbbbbbbbbbbb))\n"
+ " f();\n"
+ "}");
+ verifyFormat("if (Intervals[i].getRange().getFirst() <\n"
+ " Intervals[i - 1].getRange().getLast()) {\n}");
+}
+
+TEST_F(FormatTest, BreaksDesireably) {
+ verifyFormat("if (aaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaa) ||\n"
+ " aaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaa) ||\n"
+ " aaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaa)) {\n}");
+ verifyFormat("if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)) {\n"
+ "}");
+
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}");
+
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa));");
+
+ verifyFormat(
+ "aaaaaaaa(aaaaaaaaaaaaa, aaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)),\n"
+ " aaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)));");
+
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ||\n"
+ " (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
+
+ verifyFormat(
+ "void f() {\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);\n"
+ "}");
+ verifyFormat(
+ "aaaaaa(new Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaa));");
+ verifyFormat(
+ "aaaaaa(aaa, new Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaa));");
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
+
+ // This test case breaks on an incorrect memoization, i.e. an optimization not
+ // taking into account the StopAt value.
+ verifyFormat(
+ "return aaaaaaaaaaaaaaaaaaaaaaaa || aaaaaaaaaaaaaaaaaaaaaaa ||\n"
+ " aaaaaaaaaaa(aaaaaaaaa) || aaaaaaaaaaaaaaaaaaaaaaa ||\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaa || aaaaaaaaaaaaaaaaaaaaaaa ||\n"
+ " (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
+
+ verifyFormat("{\n {\n {\n"
+ " Annotation.SpaceRequiredBefore =\n"
+ " Line.Tokens[i - 1].Tok.isNot(tok::l_paren) &&\n"
+ " Line.Tokens[i - 1].Tok.isNot(tok::l_square);\n"
+ " }\n }\n}");
+}
+
+TEST_F(FormatTest, FormatsOneParameterPerLineIfNecessary) {
+ FormatStyle NoBinPacking = getGoogleStyle();
+ NoBinPacking.BinPackParameters = false;
+ verifyFormat("f(aaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaa);",
+ NoBinPacking);
+ verifyFormat("aaaaaaa(aaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaa(aaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaa));",
+ NoBinPacking);
+ verifyFormat(
+ "aaaaaaaa(aaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)),\n"
+ " aaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)));",
+ NoBinPacking);
+ verifyFormat("aaaaaaaaaaaaaaa(aaaaaaaaa, aaaaaaaaa, aaaaaaaaaaaaaaaaaaaaa)\n"
+ " .aaaaaaaaaaaaaaaaaa();",
+ NoBinPacking);
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaa, aaaaaaaaaa, aaaaaaaaaa, aaaaaaaaaaa);",
+ NoBinPacking);
+
+ verifyFormat(
+ "aaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaa);",
+ NoBinPacking);
+ verifyFormat(
+ "somefunction(someotherFunction(ddddddddddddddddddddddddddddddddddd,\n"
+ " ddddddddddddddddddddddddddddd),\n"
+ " test);",
+ NoBinPacking);
+
+ verifyFormat("std::vector<aaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaa> aaaaaaaaaaaaaaaaaa;",
+ NoBinPacking);
+ verifyFormat("a(\"a\"\n"
+ " \"a\",\n"
+ " a);");
+
+ NoBinPacking.AllowAllParametersOfDeclarationOnNextLine = false;
+ verifyFormat("void aaaaaaaaaa(aaaaaaaaa,\n"
+ " aaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);",
+ NoBinPacking);
+ verifyFormat(
+ "void f() {\n"
+ " aaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaa, aaaaaaaaa, aaaaaaaaaaaaaaaaaaaaa)\n"
+ " .aaaaaaa();\n"
+ "}",
+ NoBinPacking);
+}
+
+TEST_F(FormatTest, FormatsBuilderPattern) {
+ verifyFormat(
+ "return llvm::StringSwitch<Reference::Kind>(name)\n"
+ " .StartsWith(\".eh_frame_hdr\", ORDER_EH_FRAMEHDR)\n"
+ " .StartsWith(\".eh_frame\", ORDER_EH_FRAME).StartsWith(\".init\", ORDER_INIT)\n"
+ " .StartsWith(\".fini\", ORDER_FINI).StartsWith(\".hash\", ORDER_HASH)\n"
+ " .Default(ORDER_TEXT);\n");
+
+ verifyFormat("return aaaaaaaaaaaaaaaaa->aaaaa().aaaaaaaaaaaaa().aaaaaa() <\n"
+ " aaaaaaaaaaaaaaa->aaaaa().aaaaaaaaaaaaa().aaaaaa();");
+ verifyFormat(
+ "aaaaaaa->aaaaaaa\n"
+ " ->aaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
+ " ->aaaaaaaa(aaaaaaaaaaaaaaa);");
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaaa()->aaaaaa(bbbbb)->aaaaaaaaaaaaaaaaaaa( // break\n"
+ " aaaaaaaaaaaaaa);");
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaaaaaaa *aaaaaaaaa = aaaaaa->aaaaaaaaaaaa()\n"
+ " ->aaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
+ " ->aaaaaaaaaaaaaaaaa();");
+}
+
+TEST_F(FormatTest, DoesNotBreakTrailingAnnotation) {
+ verifyFormat("void aaaaaaaaaaaa(int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
+ " LOCKS_EXCLUDED(aaaaaaaaaaaaa);");
+ verifyFormat("void aaaaaaaaaaaa(int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) const\n"
+ " LOCKS_EXCLUDED(aaaaaaaaaaaaa);");
+ verifyFormat("void aaaaaaaaaaaa(int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) const\n"
+ " LOCKS_EXCLUDED(aaaaaaaaaaaaa) {}");
+ verifyFormat(
+ "void aaaaaaaaaaaaaaaaaa()\n"
+ " __attribute__((aaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaa));");
+ verifyFormat("bool aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " __attribute__((unused));");
+
+ // FIXME: This is bad indentation, but generally hard to distinguish from a
+ // function declaration.
+ verifyFormat(
+ "bool aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ "GUARDED_BY(aaaaaaaaaaaa);");
+}
+
+TEST_F(FormatTest, BreaksAccordingToOperatorPrecedence) {
+ verifyFormat(
+ "if (aaaaaaaaaaaaaaaaaaaaaaaaa ||\n"
+ " bbbbbbbbbbbbbbbbbbbbbbbbb && ccccccccccccccccccccccccc) {\n}");
+ verifyFormat("if (aaaaaaaaaaaaaaaaaaaaaaaaa && bbbbbbbbbbbbbbbbbbbbbbbbb ||\n"
+ " ccccccccccccccccccccccccc) {\n}");
+ verifyFormat("if (aaaaaaaaaaaaaaaaaaaaaaaaa || bbbbbbbbbbbbbbbbbbbbbbbbb ||\n"
+ " ccccccccccccccccccccccccc) {\n}");
+ verifyFormat(
+ "if ((aaaaaaaaaaaaaaaaaaaaaaaaa || bbbbbbbbbbbbbbbbbbbbbbbbb) &&\n"
+ " ccccccccccccccccccccccccc) {\n}");
+ verifyFormat("return aaaa & AAAAAAAAAAAAAAAAAAAAAAAAAAAAA ||\n"
+ " bbbb & BBBBBBBBBBBBBBBBBBBBBBBBBBBBB ||\n"
+ " cccc & CCCCCCCCCCCCCCCCCCCCCCCCCC ||\n"
+ " dddd & DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD;");
+ verifyFormat("if ((aaaaaaaaaa != aaaaaaaaaaaaaaa ||\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaa() >= aaaaaaaaaaaaaaaaaaaa) &&\n"
+ " aaaaaaaaaaaaaaa != aa) {\n}");
+}
+
+TEST_F(FormatTest, BreaksAfterAssignments) {
+ verifyFormat(
+ "unsigned Cost =\n"
+ " TTI.getMemoryOpCost(I->getOpcode(), VectorTy, SI->getAlignment(),\n"
+ " SI->getPointerAddressSpaceee());\n");
+ verifyFormat(
+ "CharSourceRange LineRange = CharSourceRange::getTokenRange(\n"
+ " Line.Tokens.front().Tok.getLo(), Line.Tokens.back().Tok.getLoc());");
+
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaa aaaa = aaaaaaaaaaaaaa(0).aaaa()\n"
+ " .aaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaa::aaaaaaaaaaaaaaaaaaaaa);");
+}
+
+TEST_F(FormatTest, AlignsAfterAssignments) {
+ verifyFormat(
+ "int Result = aaaaaaaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaaa +\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaa;");
+ verifyFormat(
+ "Result += aaaaaaaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaaa +\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaa;");
+ verifyFormat(
+ "Result >>= aaaaaaaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaaa +\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaa;");
+ verifyFormat(
+ "int Result = (aaaaaaaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaaa +\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaa);");
+ verifyFormat("double LooooooooooooooooooooooooongResult =\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaa +\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaa;");
+}
+
+TEST_F(FormatTest, AlignsAfterReturn) {
+ verifyFormat(
+ "return aaaaaaaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaaa +\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaa;");
+ verifyFormat(
+ "return (aaaaaaaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaaa +\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaa);");
+ verifyFormat(
+ "return aaaaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa >=\n"
+ " aaaaaaaaaaaaaaaaaaaaaa();");
+ verifyFormat(
+ "return (aaaaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa >=\n"
+ " aaaaaaaaaaaaaaaaaaaaaa());");
+}
+
+TEST_F(FormatTest, BreaksConditionalExpressions) {
+ verifyFormat(
+ "aaaa(aaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaa ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
+ verifyFormat(
+ "aaaa(aaaaaaaaaaaaaaaaaaaa, aaaaaaa ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaa ? aaaa(aaaaaa)\n"
+ " : aaaaaaaaaaaaa);");
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaa ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " : aaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaa);");
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
+ " : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
+ verifyFormat("aaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
+ " : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa),\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaa);");
+
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " ? aaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " : aaaaaaaaaaaaaaaaaaaaaaaaaaa;");
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaa =\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " ? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " : aaaaaaaaaaaaaaaa;");
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa == aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " ? aaaaaaaaaaaaaaa\n"
+ " : aaaaaaaaaaaaaaa;");
+ verifyFormat("f(aaaaaaaaaaaaaaaa == // force break\n"
+ " aaaaaaaaa\n"
+ " ? b\n"
+ " : c);");
+ verifyFormat(
+ "unsigned Indent =\n"
+ " format(TheLine.First, IndentForLevel[TheLine.Level] >= 0\n"
+ " ? IndentForLevel[TheLine.Level]\n"
+ " : TheLine * 2,\n"
+ " TheLine.InPPDirective, PreviousEndOfLineColumn);",
+ getLLVMStyleWithColumns(70));
+
+ FormatStyle NoBinPacking = getLLVMStyle();
+ NoBinPacking.BinPackParameters = false;
+ verifyFormat(
+ "void f() {\n"
+ " g(aaa,\n"
+ " aaaaaaaaaa == aaaaaaaaaa ? aaaa : aaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa == aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " ? aaaaaaaaaaaaaaa\n"
+ " : aaaaaaaaaaaaaaa);\n"
+ "}",
+ NoBinPacking);
+}
+
+TEST_F(FormatTest, DeclarationsOfMultipleVariables) {
+ verifyFormat("bool aaaaaaaaaaaaaaaaa = aaaaaa->aaaaaaaaaaaaaaaaa(),\n"
+ " aaaaaaaaaaa = aaaaaa->aaaaaaaaaaa();");
+ verifyFormat("bool a = true, b = false;");
+
+ verifyFormat("bool aaaaaaaaaaaaaaaaaaaaaaaaa =\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaa),\n"
+ " bbbbbbbbbbbbbbbbbbbbbbbbb =\n"
+ " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb(bbbbbbbbbbbbbbbb);");
+ verifyFormat(
+ "bool aaaaaaaaaaaaaaaaaaaaa =\n"
+ " bbbbbbbbbbbbbbbbbbbbbbbbbbbb && cccccccccccccccccccccccccccc,\n"
+ " d = e && f;");
+ verifyFormat("aaaaaaaaa a = aaaaaaaaaaaaaaaaaaaa, b = bbbbbbbbbbbbbbbbbbbb,\n"
+ " c = cccccccccccccccccccc, d = dddddddddddddddddddd;");
+ verifyFormat("aaaaaaaaa *a = aaaaaaaaaaaaaaaaaaa, *b = bbbbbbbbbbbbbbbbbbb,\n"
+ " *c = ccccccccccccccccccc, *d = ddddddddddddddddddd;");
+ verifyFormat("aaaaaaaaa ***a = aaaaaaaaaaaaaaaaaaa, ***b = bbbbbbbbbbbbbbb,\n"
+ " ***c = ccccccccccccccccccc, ***d = ddddddddddddddd;");
+ // FIXME: If multiple variables are defined, the "*" needs to move to the new
+ // line. Also fix indent for breaking after the type, this looks bad.
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa *\n"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaa = aaaaaaaaaaaaaaaaaaa,\n"
+ " *b = bbbbbbbbbbbbbbbbbbb;");
+
+ // Not ideal, but pointer-with-type does not allow much here.
+ verifyGoogleFormat(
+ "aaaaaaaaa* a = aaaaaaaaaaaaaaaaaaa, *b = bbbbbbbbbbbbbbbbbbb,\n"
+ " *b = bbbbbbbbbbbbbbbbbbb, *d = ddddddddddddddddddd;");
+}
+
+TEST_F(FormatTest, ConditionalExpressionsInBrackets) {
+ verifyFormat("arr[foo ? bar : baz];");
+ verifyFormat("f()[foo ? bar : baz];");
+ verifyFormat("(a + b)[foo ? bar : baz];");
+ verifyFormat("arr[foo ? (4 > 5 ? 4 : 5) : 5 < 5 ? 5 : 7];");
+}
+
+TEST_F(FormatTest, AlignsStringLiterals) {
+ verifyFormat("loooooooooooooooooooooooooongFunction(\"short literal \"\n"
+ " \"short literal\");");
+ verifyFormat(
+ "looooooooooooooooooooooooongFunction(\n"
+ " \"short literal\"\n"
+ " \"looooooooooooooooooooooooooooooooooooooooooooooooong literal\");");
+ verifyFormat("someFunction(\"Always break between multi-line\"\n"
+ " \" string literals\",\n"
+ " and, other, parameters);");
+ EXPECT_EQ("fun + \"1243\" /* comment */\n"
+ " \"5678\";",
+ format("fun + \"1243\" /* comment */\n"
+ " \"5678\";",
+ getLLVMStyleWithColumns(28)));
+ EXPECT_EQ(
+ "aaaaaa = \"aaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaa \"\n"
+ " \"aaaaaaaaaaaaaaaaaaaaa\"\n"
+ " \"aaaaaaaaaaaaaaaa\";",
+ format("aaaaaa ="
+ "\"aaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaa "
+ "aaaaaaaaaaaaaaaaaaaaa\" "
+ "\"aaaaaaaaaaaaaaaa\";"));
+ verifyFormat("a = a + \"a\"\n"
+ " \"a\"\n"
+ " \"a\";");
+
+ verifyFormat(
+ "#define LL_FORMAT \"ll\"\n"
+ "printf(\"aaaaa: %d, bbbbbb: %\" LL_FORMAT \"d, cccccccc: %\" LL_FORMAT\n"
+ " \"d, ddddddddd: %\" LL_FORMAT \"d\");");
+}
+
+TEST_F(FormatTest, AlignsPipes) {
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;");
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaaaa << aaaaaaaaaaaaaaaaaaaa << aaaaaaaaaaaaaaaaaaaa\n"
+ " << aaaaaaaaaaaaaaaaaaaa;");
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa << aaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " << aaaaaaaaaaaaaaaaaaaaaaaaaaaa;");
+ verifyFormat(
+ "llvm::outs() << \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n"
+ " \"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"\n"
+ " << \"ccccccccccccccccccccccccccccccccccccccccccccccccc\";");
+ verifyFormat(
+ "aaaaaaaa << (aaaaaaaaaaaaaaaaaaa << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
+ " << aaaaaaaaaaaaaaaaaaaaaaaaaaaaa;");
+
+ verifyFormat("return out << \"somepacket = {\\n\"\n"
+ " << \" aaaaaa = \" << pkt.aaaaaa << \"\\n\"\n"
+ " << \" bbbb = \" << pkt.bbbb << \"\\n\"\n"
+ " << \" cccccc = \" << pkt.cccccc << \"\\n\"\n"
+ " << \" ddd = [\" << pkt.ddd << \"]\\n\"\n"
+ " << \"}\";");
+
+ verifyFormat(
+ "llvm::outs() << \"aaaaaaaaaaaaaaaaa = \" << aaaaaaaaaaaaaaaaa\n"
+ " << \"bbbbbbbbbbbbbbbbb = \" << bbbbbbbbbbbbbbbbb\n"
+ " << \"ccccccccccccccccc = \" << ccccccccccccccccc\n"
+ " << \"ddddddddddddddddd = \" << ddddddddddddddddd\n"
+ " << \"eeeeeeeeeeeeeeeee = \" << eeeeeeeeeeeeeeeee;");
+ verifyFormat("llvm::outs() << aaaaaaaaaaaaaaaaaaaaaaaa << \"=\"\n"
+ " << bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;");
+
+ verifyFormat(
+ "llvm::errs() << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " .aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa();");
+}
+
+TEST_F(FormatTest, UnderstandsEquals) {
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaa =\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;");
+ verifyFormat(
+ "if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa =\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {\n}");
+ verifyFormat(
+ "if (a) {\n"
+ " f();\n"
+ "} else if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa =\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {\n"
+ "}");
+
+ verifyFormat("if (int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa =\n"
+ " 100000000 + 10000000) {\n}");
+}
+
+TEST_F(FormatTest, WrapsAtFunctionCallsIfNecessary) {
+ verifyFormat("LoooooooooooooooooooooooooooooooooooooongObject\n"
+ " .looooooooooooooooooooooooooooooooooooooongFunction();");
+
+ verifyFormat("LoooooooooooooooooooooooooooooooooooooongObject\n"
+ " ->looooooooooooooooooooooooooooooooooooooongFunction();");
+
+ verifyFormat(
+ "LooooooooooooooooooooooooooooooooongObject->shortFunction(Parameter1,\n"
+ " Parameter2);");
+
+ verifyFormat(
+ "ShortObject->shortFunction(\n"
+ " LooooooooooooooooooooooooooooooooooooooooooooooongParameter1,\n"
+ " LooooooooooooooooooooooooooooooooooooooooooooooongParameter2);");
+
+ verifyFormat("loooooooooooooongFunction(\n"
+ " LoooooooooooooongObject->looooooooooooooooongFunction());");
+
+ verifyFormat(
+ "function(LoooooooooooooooooooooooooooooooooooongObject\n"
+ " ->loooooooooooooooooooooooooooooooooooooooongFunction());");
+
+ verifyFormat("EXPECT_CALL(SomeObject, SomeFunction(Parameter))\n"
+ " .WillRepeatedly(Return(SomeValue));");
+ verifyFormat("SomeMap[std::pair(aaaaaaaaaaaa, bbbbbbbbbbbbbbb)]\n"
+ " .insert(ccccccccccccccccccccccc);");
+ verifyFormat(
+ "aaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
+ " .aaaaaaaaaaaaaaa(\n"
+ " aa(aaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaa));");
+ verifyFormat("if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " .aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " .aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " .aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa()) {\n"
+ "}");
+
+ // Here, it is not necessary to wrap at "." or "->".
+ verifyFormat("if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaa) ||\n"
+ " aaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {\n}");
+ verifyFormat(
+ "aaaaaaaaaaa->aaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaa->aaaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaa));\n");
+
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa().aaaaaaaaaaaaaaaaa());");
+ verifyFormat("a->aaaaaa()->aaaaaaaaaaa(aaaaaaaa()->aaaaaa()->aaaaa() *\n"
+ " aaaaaaaaa()->aaaaaa()->aaaaa());");
+ verifyFormat("a->aaaaaa()->aaaaaaaaaaa(aaaaaaaa()->aaaaaa()->aaaaa() ||\n"
+ " aaaaaaaaa()->aaaaaa()->aaaaa());");
+
+ // FIXME: Should we break before .a()?
+ verifyFormat("aaaaa(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa).a();");
+
+ FormatStyle NoBinPacking = getLLVMStyle();
+ NoBinPacking.BinPackParameters = false;
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaa)\n"
+ " .aaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaa)\n"
+ " .aaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);",
+ NoBinPacking);
+}
+
+TEST_F(FormatTest, WrapsTemplateDeclarations) {
+ verifyFormat("template <typename T>\n"
+ "virtual void loooooooooooongFunction(int Param1, int Param2);");
+ verifyFormat(
+ "template <typename T>\n"
+ "using comment_to_xml_conversion = comment_to_xml_conversion<T, int>;");
+ verifyFormat("template <typename T>\n"
+ "void f(int Paaaaaaaaaaaaaaaaaaaaaaaaaaaaaaram1,\n"
+ " int Paaaaaaaaaaaaaaaaaaaaaaaaaaaaaaram2);");
+ verifyFormat(
+ "template <typename T>\n"
+ "void looooooooooooooooooooongFunction(int Paaaaaaaaaaaaaaaaaaaaram1,\n"
+ " int Paaaaaaaaaaaaaaaaaaaaram2);");
+ verifyFormat(
+ "template <typename T>\n"
+ "aaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaa<T>::aaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
+ verifyFormat("template <typename T>\n"
+ "void aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " int aaaaaaaaaaaaaaaaaaaaaa);");
+ verifyFormat(
+ "template <typename T1, typename T2 = char, typename T3 = char,\n"
+ " typename T4 = char>\n"
+ "void f();");
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaaaaaaaa<aaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaa>(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
+
+ verifyFormat("a<aaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaa>(\n"
+ " a(aaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaa));");
+}
+
+TEST_F(FormatTest, WrapsAtNestedNameSpecifiers) {
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa::\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa();");
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa::\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa());");
+
+ // FIXME: Should we have an extra indent after the second break?
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa::\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa::\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa();");
+
+ // FIXME: Look into whether we should indent 4 from the start or 4 from
+ // "bbbbb..." here instead of what we are doing now.
+ verifyFormat(
+ "aaaaaaaaaaaaaaa(bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb::\n"
+ " cccccccccccccccccccccccccccccccccccccccccccccc());");
+
+ // Breaking at nested name specifiers is generally not desirable.
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa::aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaa);");
+
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaa(aaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa::\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaa);",
+ getLLVMStyleWithColumns(74));
+
+ verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa::\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
+ " .aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa();");
+}
+
+TEST_F(FormatTest, UnderstandsTemplateParameters) {
+ verifyFormat("A<int> a;");
+ verifyFormat("A<A<A<int> > > a;");
+ verifyFormat("A<A<A<int, 2>, 3>, 4> a;");
+ verifyFormat("bool x = a < 1 || 2 > a;");
+ verifyFormat("bool x = 5 < f<int>();");
+ verifyFormat("bool x = f<int>() > 5;");
+ verifyFormat("bool x = 5 < a<int>::x;");
+ verifyFormat("bool x = a < 4 ? a > 2 : false;");
+ verifyFormat("bool x = f() ? a < 2 : a > 2;");
+
+ verifyGoogleFormat("A<A<int>> a;");
+ verifyGoogleFormat("A<A<A<int>>> a;");
+ verifyGoogleFormat("A<A<A<A<int>>>> a;");
+ verifyGoogleFormat("A<A<int> > a;");
+ verifyGoogleFormat("A<A<A<int> > > a;");
+ verifyGoogleFormat("A<A<A<A<int> > > > a;");
+ EXPECT_EQ("A<A<A<A>>> a;", format("A<A<A<A> >> a;", getGoogleStyle()));
+ EXPECT_EQ("A<A<A<A>>> a;", format("A<A<A<A>> > a;", getGoogleStyle()));
+
+ verifyFormat("test >> a >> b;");
+ verifyFormat("test << a >> b;");
+
+ verifyFormat("f<int>();");
+ verifyFormat("template <typename T> void f() {}");
+}
+
+TEST_F(FormatTest, UnderstandsBinaryOperators) {
+ verifyFormat("COMPARE(a, ==, b);");
+}
+
+TEST_F(FormatTest, UnderstandsPointersToMembers) {
+ verifyFormat("int A::*x;");
+ // FIXME: Recognize pointers to member functions.
+ //verifyFormat("int (S::*func)(void *);");
+ verifyFormat("int(S::*func)(void *);");
+ verifyFormat("(a->*f)();");
+ verifyFormat("a->*x;");
+ verifyFormat("(a.*f)();");
+ verifyFormat("((*a).*f)();");
+ verifyFormat("a.*x;");
+}
+
+TEST_F(FormatTest, UnderstandsUnaryOperators) {
+ verifyFormat("int a = -2;");
+ verifyFormat("f(-1, -2, -3);");
+ verifyFormat("a[-1] = 5;");
+ verifyFormat("int a = 5 + -2;");
+ verifyFormat("if (i == -1) {\n}");
+ verifyFormat("if (i != -1) {\n}");
+ verifyFormat("if (i > -1) {\n}");
+ verifyFormat("if (i < -1) {\n}");
+ verifyFormat("++(a->f());");
+ verifyFormat("--(a->f());");
+ verifyFormat("(a->f())++;");
+ verifyFormat("a[42]++;");
+ verifyFormat("if (!(a->f())) {\n}");
+
+ verifyFormat("a-- > b;");
+ verifyFormat("b ? -a : c;");
+ verifyFormat("n * sizeof char16;");
+ verifyFormat("n * alignof char16;");
+ verifyFormat("sizeof(char);");
+ verifyFormat("alignof(char);");
+
+ verifyFormat("return -1;");
+ verifyFormat("switch (a) {\n"
+ "case -1:\n"
+ " break;\n"
+ "}");
+ verifyFormat("#define X -1");
+ verifyFormat("#define X -kConstant");
+
+ verifyFormat("const NSPoint kBrowserFrameViewPatternOffset = { -5, +3 };");
+ verifyFormat("const NSPoint kBrowserFrameViewPatternOffset = { +5, -3 };");
+
+ verifyFormat("int a = /* confusing comment */ -1;");
+ // FIXME: The space after 'i' is wrong, but hopefully, this is a rare case.
+ verifyFormat("int a = i /* confusing comment */++;");
+}
+
+TEST_F(FormatTest, UndestandsOverloadedOperators) {
+ verifyFormat("bool operator<();");
+ verifyFormat("bool operator>();");
+ verifyFormat("bool operator=();");
+ verifyFormat("bool operator==();");
+ verifyFormat("bool operator!=();");
+ verifyFormat("int operator+();");
+ verifyFormat("int operator++();");
+ verifyFormat("bool operator();");
+ verifyFormat("bool operator()();");
+ verifyFormat("bool operator[]();");
+ verifyFormat("operator bool();");
+ verifyFormat("operator int();");
+ verifyFormat("operator void *();");
+ verifyFormat("operator SomeType<int>();");
+ verifyFormat("operator SomeType<int, int>();");
+ verifyFormat("operator SomeType<SomeType<int> >();");
+ verifyFormat("void *operator new(std::size_t size);");
+ verifyFormat("void *operator new[](std::size_t size);");
+ verifyFormat("void operator delete(void *ptr);");
+ verifyFormat("void operator delete[](void *ptr);");
+
+ verifyFormat(
+ "ostream &operator<<(ostream &OutputStream,\n"
+ " SomeReallyLongType WithSomeReallyLongValue);");
+
+ verifyGoogleFormat("operator void*();");
+ verifyGoogleFormat("operator SomeType<SomeType<int>>();");
+}
+
+TEST_F(FormatTest, UnderstandsNewAndDelete) {
+ verifyFormat("void f() {\n"
+ " A *a = new A;\n"
+ " A *a = new (placement) A;\n"
+ " delete a;\n"
+ " delete (A *)a;\n"
+ "}");
+}
+
+TEST_F(FormatTest, UnderstandsUsesOfStarAndAmp) {
+ verifyFormat("int *f(int *a) {}");
+ verifyFormat("int main(int argc, char **argv) {}");
+ verifyFormat("Test::Test(int b) : a(b * b) {}");
+ verifyIndependentOfContext("f(a, *a);");
+ verifyFormat("void g() { f(*a); }");
+ verifyIndependentOfContext("int a = b * 10;");
+ verifyIndependentOfContext("int a = 10 * b;");
+ verifyIndependentOfContext("int a = b * c;");
+ verifyIndependentOfContext("int a += b * c;");
+ verifyIndependentOfContext("int a -= b * c;");
+ verifyIndependentOfContext("int a *= b * c;");
+ verifyIndependentOfContext("int a /= b * c;");
+ verifyIndependentOfContext("int a = *b;");
+ verifyIndependentOfContext("int a = *b * c;");
+ verifyIndependentOfContext("int a = b * *c;");
+ verifyIndependentOfContext("return 10 * b;");
+ verifyIndependentOfContext("return *b * *c;");
+ verifyIndependentOfContext("return a & ~b;");
+ verifyIndependentOfContext("f(b ? *c : *d);");
+ verifyIndependentOfContext("int a = b ? *c : *d;");
+ verifyIndependentOfContext("*b = a;");
+ verifyIndependentOfContext("a * ~b;");
+ verifyIndependentOfContext("a * !b;");
+ verifyIndependentOfContext("a * +b;");
+ verifyIndependentOfContext("a * -b;");
+ verifyIndependentOfContext("a * ++b;");
+ verifyIndependentOfContext("a * --b;");
+ verifyIndependentOfContext("a[4] * b;");
+ verifyIndependentOfContext("a[a * a] = 1;");
+ verifyIndependentOfContext("f() * b;");
+ verifyIndependentOfContext("a * [self dostuff];");
+ verifyIndependentOfContext("int x = a * (a + b);");
+ verifyIndependentOfContext("(a *)(a + b);");
+ verifyIndependentOfContext("int *pa = (int *)&a;");
+ verifyIndependentOfContext("return sizeof(int **);");
+ verifyIndependentOfContext("return sizeof(int ******);");
+ verifyIndependentOfContext("return (int **&)a;");
+ verifyFormat("void f(Type (*parameter)[10]) {}");
+ verifyGoogleFormat("return sizeof(int**);");
+ verifyIndependentOfContext("Type **A = static_cast<Type **>(P);");
+ verifyGoogleFormat("Type** A = static_cast<Type**>(P);");
+ // FIXME: The newline is wrong.
+ verifyFormat("auto a = [](int **&, int ***) {}\n;");
+
+ verifyIndependentOfContext("InvalidRegions[*R] = 0;");
+
+ verifyIndependentOfContext("A<int *> a;");
+ verifyIndependentOfContext("A<int **> a;");
+ verifyIndependentOfContext("A<int *, int *> a;");
+ verifyIndependentOfContext(
+ "const char *const p = reinterpret_cast<const char *const>(q);");
+ verifyIndependentOfContext("A<int **, int **> a;");
+ verifyIndependentOfContext("void f(int *a = d * e, int *b = c * d);");
+ verifyFormat("for (char **a = b; *a; ++a) {\n}");
+
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaa, *aaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
+
+ verifyGoogleFormat("int main(int argc, char** argv) {}");
+ verifyGoogleFormat("A<int*> a;");
+ verifyGoogleFormat("A<int**> a;");
+ verifyGoogleFormat("A<int*, int*> a;");
+ verifyGoogleFormat("A<int**, int**> a;");
+ verifyGoogleFormat("f(b ? *c : *d);");
+ verifyGoogleFormat("int a = b ? *c : *d;");
+ verifyGoogleFormat("Type* t = **x;");
+ verifyGoogleFormat("Type* t = *++*x;");
+ verifyGoogleFormat("*++*x;");
+ verifyGoogleFormat("Type* t = const_cast<T*>(&*x);");
+ verifyGoogleFormat("Type* t = x++ * y;");
+ verifyGoogleFormat(
+ "const char* const p = reinterpret_cast<const char* const>(q);");
+
+ verifyIndependentOfContext("a = *(x + y);");
+ verifyIndependentOfContext("a = &(x + y);");
+ verifyIndependentOfContext("*(x + y).call();");
+ verifyIndependentOfContext("&(x + y)->call();");
+ verifyFormat("void f() { &(*I).first; }");
+
+ verifyIndependentOfContext("f(b * /* confusing comment */ ++c);");
+ verifyFormat(
+ "int *MyValues = {\n"
+ " *A, // Operator detection might be confused by the '{'\n"
+ " *BB // Operator detection might be confused by previous comment\n"
+ "};");
+
+ verifyIndependentOfContext("if (int *a = &b)");
+ verifyIndependentOfContext("if (int &a = *b)");
+ verifyIndependentOfContext("if (a & b[i])");
+ verifyIndependentOfContext("if (a::b::c::d & b[i])");
+ verifyIndependentOfContext("if (*b[i])");
+ verifyIndependentOfContext("if (int *a = (&b))");
+ verifyIndependentOfContext("while (int *a = &b)");
+ verifyFormat("void f() {\n"
+ " for (const int &v : Values) {\n"
+ " }\n"
+ "}");
+ verifyFormat("for (int i = a * a; i < 10; ++i) {\n}");
+ verifyFormat("for (int i = 0; i < a * a; ++i) {\n}");
+
+ verifyIndependentOfContext("A = new SomeType *[Length];");
+ verifyIndependentOfContext("A = new SomeType *[Length]();");
+ verifyGoogleFormat("A = new SomeType* [Length]();");
+ verifyGoogleFormat("A = new SomeType* [Length];");
+}
+
+TEST_F(FormatTest, AdaptivelyFormatsPointersAndReferences) {
+ EXPECT_EQ("int *a;\n"
+ "int *a;\n"
+ "int *a;",
+ format("int *a;\n"
+ "int* a;\n"
+ "int *a;",
+ getGoogleStyle()));
+ EXPECT_EQ("int* a;\n"
+ "int* a;\n"
+ "int* a;",
+ format("int* a;\n"
+ "int* a;\n"
+ "int *a;",
+ getGoogleStyle()));
+ EXPECT_EQ("int *a;\n"
+ "int *a;\n"
+ "int *a;",
+ format("int *a;\n"
+ "int * a;\n"
+ "int * a;",
+ getGoogleStyle()));
+}
+
+TEST_F(FormatTest, UnderstandsRvalueReferences) {
+ verifyFormat("int f(int &&a) {}");
+ verifyFormat("int f(int a, char &&b) {}");
+ verifyFormat("void f() { int &&a = b; }");
+ verifyGoogleFormat("int f(int a, char&& b) {}");
+ verifyGoogleFormat("void f() { int&& a = b; }");
+
+ // FIXME: These require somewhat deeper changes in template arguments
+ // formatting.
+ // verifyIndependentOfContext("A<int &&> a;");
+ // verifyIndependentOfContext("A<int &&, int &&> a;");
+ // verifyGoogleFormat("A<int&&> a;");
+ // verifyGoogleFormat("A<int&&, int&&> a;");
+}
+
+TEST_F(FormatTest, FormatsBinaryOperatorsPrecedingEquals) {
+ verifyFormat("void f() {\n"
+ " x[aaaaaaaaa -\n"
+ " b] = 23;\n"
+ "}",
+ getLLVMStyleWithColumns(15));
+}
+
+TEST_F(FormatTest, FormatsCasts) {
+ verifyFormat("Type *A = static_cast<Type *>(P);");
+ verifyFormat("Type *A = (Type *)P;");
+ verifyFormat("Type *A = (vector<Type *, int *>)P;");
+ verifyFormat("int a = (int)(2.0f);");
+
+ // FIXME: These also need to be identified.
+ verifyFormat("int a = (int) 2.0f;");
+ verifyFormat("int a = (int) * b;");
+
+ // These are not casts.
+ verifyFormat("void f(int *) {}");
+ verifyFormat("f(foo)->b;");
+ verifyFormat("f(foo).b;");
+ verifyFormat("f(foo)(b);");
+ verifyFormat("f(foo)[b];");
+ verifyFormat("[](foo) { return 4; }(bar)];");
+ verifyFormat("(*funptr)(foo)[4];");
+ verifyFormat("funptrs[4](foo)[4];");
+ verifyFormat("void f(int *);");
+ verifyFormat("void f(int *) = 0;");
+ verifyFormat("void f(SmallVector<int>) {}");
+ verifyFormat("void f(SmallVector<int>);");
+ verifyFormat("void f(SmallVector<int>) = 0;");
+ verifyFormat("void f(int i = (kValue) * kMask) {}");
+ verifyFormat("void f(int i = (kA * kB) & kMask) {}");
+ verifyFormat("int a = sizeof(int) * b;");
+ verifyFormat("int a = alignof(int) * b;");
+
+ // These are not casts, but at some point were confused with casts.
+ verifyFormat("virtual void foo(int *) override;");
+ verifyFormat("virtual void foo(char &) const;");
+ verifyFormat("virtual void foo(int *a, char *) const;");
+ verifyFormat("int a = sizeof(int *) + b;");
+ verifyFormat("int a = alignof(int *) + b;");
+}
+
+TEST_F(FormatTest, FormatsFunctionTypes) {
+ verifyFormat("A<bool()> a;");
+ verifyFormat("A<SomeType()> a;");
+ verifyFormat("A<void(*)(int, std::string)> a;");
+ verifyFormat("A<void *(int)>;");
+ verifyFormat("void *(*a)(int *, SomeType *);");
+
+ // FIXME: Inconsistent.
+ verifyFormat("int (*func)(void *);");
+ verifyFormat("void f() { int(*func)(void *); }");
+
+ verifyGoogleFormat("A<void*(int*, SomeType*)>;");
+ verifyGoogleFormat("void* (*a)(int);");
+}
+
+TEST_F(FormatTest, BreaksLongDeclarations) {
+ verifyFormat("int *someFunction(int LoooooooooooooooooooongParam1,\n"
+ " int LoooooooooooooooooooongParam2) {}");
+ verifyFormat(
+ "TypeSpecDecl *\n"
+ "TypeSpecDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,\n"
+ " IdentifierIn *II, Type *T) {}");
+ verifyFormat("ReallyLongReturnType<TemplateParam1, TemplateParam2>\n"
+ "ReallyReallyLongFunctionName(\n"
+ " const std::string &SomeParameter,\n"
+ " const SomeType<string, SomeOtherTemplateParameter> &\n"
+ " ReallyReallyLongParameterName,\n"
+ " const SomeType<string, SomeOtherTemplateParameter> &\n"
+ " AnotherLongParameterName) {}");
+ verifyFormat(
+ "aaaaaaaaaaaaaaaa::aaaaaaaaaaaaaaaa<aaaaaaaaaaaaa, aaaaaaaaaaaa>\n"
+ "aaaaaaaaaaaaaaaaaaaaaaa;");
+
+ verifyGoogleFormat(
+ "TypeSpecDecl* TypeSpecDecl::Create(ASTContext& C, DeclContext* DC,\n"
+ " SourceLocation L) {}");
+ verifyGoogleFormat(
+ "some_namespace::LongReturnType\n"
+ "long_namespace::SomeVeryLongClass::SomeVeryLongFunction(\n"
+ " int first_long_parameter, int second_parameter) {}");
+
+ verifyGoogleFormat("template <typename T>\n"
+ "aaaaaaaa::aaaaa::aaaaaa<T, aaaaaaaaaaaaaaaaaaaaaaaaa>\n"
+ "aaaaaaaaaaaaaaaaaaaaaaaa<T>::aaaaaaa() {}");
+ verifyGoogleFormat("A<A<A>> aaaaaaaaaa(int aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " int aaaaaaaaaaaaaaaaaaaaaaa);");
+}
+
+TEST_F(FormatTest, LineStartsWithSpecialCharacter) {
+ verifyFormat("(a)->b();");
+ verifyFormat("--a;");
+}
+
+TEST_F(FormatTest, HandlesIncludeDirectives) {
+ verifyFormat("#include <string>\n"
+ "#include <a/b/c.h>\n"
+ "#include \"a/b/string\"\n"
+ "#include \"string.h\"\n"
+ "#include \"string.h\"\n"
+ "#include <a-a>\n"
+ "#include < path with space >\n"
+ "#include \"some very long include paaaaaaaaaaaaaaaaaaaaaaath\"",
+ getLLVMStyleWithColumns(35));
+
+ verifyFormat("#import <string>");
+ verifyFormat("#import <a/b/c.h>");
+ verifyFormat("#import \"a/b/string\"");
+ verifyFormat("#import \"string.h\"");
+ verifyFormat("#import \"string.h\"");
+}
+
+//===----------------------------------------------------------------------===//
+// Error recovery tests.
+//===----------------------------------------------------------------------===//
+
+TEST_F(FormatTest, IncompleteParameterLists) {
+ FormatStyle NoBinPacking = getLLVMStyle();
+ NoBinPacking.BinPackParameters = false;
+ verifyFormat("void aaaaaaaaaaaaaaaaaa(int level,\n"
+ " double *min_x,\n"
+ " double *max_x,\n"
+ " double *min_y,\n"
+ " double *max_y,\n"
+ " double *min_z,\n"
+ " double *max_z, ) {}",
+ NoBinPacking);
+}
+
+TEST_F(FormatTest, IncorrectCodeTrailingStuff) {
+ verifyFormat("void f() { return; }\n42");
+ verifyFormat("void f() {\n"
+ " if (0)\n"
+ " return;\n"
+ "}\n"
+ "42");
+ verifyFormat("void f() { return }\n42");
+ verifyFormat("void f() {\n"
+ " if (0)\n"
+ " return\n"
+ "}\n"
+ "42");
+}
+
+TEST_F(FormatTest, IncorrectCodeMissingSemicolon) {
+ EXPECT_EQ("void f() { return }", format("void f ( ) { return }"));
+ EXPECT_EQ("void f() {\n"
+ " if (a)\n"
+ " return\n"
+ "}",
+ format("void f ( ) { if ( a ) return }"));
+ EXPECT_EQ("namespace N { void f() }", format("namespace N { void f() }"));
+ EXPECT_EQ("namespace N {\n"
+ "void f() {}\n"
+ "void g()\n"
+ "}",
+ format("namespace N { void f( ) { } void g( ) }"));
+}
+
+TEST_F(FormatTest, IndentationWithinColumnLimitNotPossible) {
+ verifyFormat("int aaaaaaaa =\n"
+ " // Overlylongcomment\n"
+ " b;",
+ getLLVMStyleWithColumns(20));
+ verifyFormat("function(\n"
+ " ShortArgument,\n"
+ " LoooooooooooongArgument);\n",
+ getLLVMStyleWithColumns(20));
+}
+
+TEST_F(FormatTest, IncorrectAccessSpecifier) {
+ verifyFormat("public:");
+ verifyFormat("class A {\n"
+ "public\n"
+ " void f() {}\n"
+ "};");
+ verifyFormat("public\n"
+ "int qwerty;");
+ verifyFormat("public\n"
+ "B {}");
+ verifyFormat("public\n"
+ "{}");
+ verifyFormat("public\n"
+ "B { int x; }");
+}
+
+TEST_F(FormatTest, IncorrectCodeUnbalancedBraces) {
+ verifyFormat("{");
+ verifyFormat("#})");
+}
+
+TEST_F(FormatTest, IncorrectCodeDoNoWhile) {
+ verifyFormat("do {\n}");
+ verifyFormat("do {\n}\n"
+ "f();");
+ verifyFormat("do {\n}\n"
+ "wheeee(fun);");
+ verifyFormat("do {\n"
+ " f();\n"
+ "}");
+}
+
+TEST_F(FormatTest, IncorrectCodeMissingParens) {
+ verifyFormat("if {\n foo;\n foo();\n}");
+ verifyFormat("switch {\n foo;\n foo();\n}");
+ verifyFormat("for {\n foo;\n foo();\n}");
+ verifyFormat("while {\n foo;\n foo();\n}");
+ verifyFormat("do {\n foo;\n foo();\n} while;");
+}
+
+TEST_F(FormatTest, DoesNotTouchUnwrappedLinesWithErrors) {
+ verifyFormat("namespace {\n"
+ "class Foo { Foo ( }; } // comment");
+}
+
+TEST_F(FormatTest, IncorrectCodeErrorDetection) {
+ EXPECT_EQ("{\n{}\n", format("{\n{\n}\n"));
+ EXPECT_EQ("{\n {}\n", format("{\n {\n}\n"));
+ EXPECT_EQ("{\n {}\n", format("{\n {\n }\n"));
+ EXPECT_EQ("{\n {}\n }\n}\n", format("{\n {\n }\n }\n}\n"));
+
+ EXPECT_EQ("{\n"
+ " {\n"
+ " breakme(\n"
+ " qwe);\n"
+ "}\n",
+ format("{\n"
+ " {\n"
+ " breakme(qwe);\n"
+ "}\n",
+ getLLVMStyleWithColumns(10)));
+}
+
+TEST_F(FormatTest, LayoutCallsInsideBraceInitializers) {
+ verifyFormat("int x = {\n"
+ " avariable,\n"
+ " b(alongervariable)\n"
+ "};",
+ getLLVMStyleWithColumns(25));
+}
+
+TEST_F(FormatTest, LayoutBraceInitializersInReturnStatement) {
+ verifyFormat("return (a)(b) { 1, 2, 3 };");
+}
+
+TEST_F(FormatTest, LayoutTokensFollowingBlockInParentheses) {
+ // FIXME: This is bad, find a better and more generic solution.
+ verifyFormat(
+ "Aaa({\n"
+ " int i;\n"
+ "},\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
+ " ccccccccccccccccc));");
+}
+
+TEST_F(FormatTest, PullTrivialFunctionDefinitionsIntoSingleLine) {
+ verifyFormat("void f() { return 42; }");
+ verifyFormat("void f() {\n"
+ " // Comment\n"
+ "}");
+ verifyFormat("{\n"
+ "#error {\n"
+ " int a;\n"
+ "}");
+ verifyFormat("{\n"
+ " int a;\n"
+ "#error {\n"
+ "}");
+
+ verifyFormat("void f() { return 42; }", getLLVMStyleWithColumns(23));
+ verifyFormat("void f() {\n return 42;\n}", getLLVMStyleWithColumns(22));
+
+ verifyFormat("void f() {}", getLLVMStyleWithColumns(11));
+ verifyFormat("void f() {\n}", getLLVMStyleWithColumns(10));
+}
+
+TEST_F(FormatTest, UnderstandContextOfRecordTypeKeywords) {
+ // Elaborate type variable declarations.
+ verifyFormat("struct foo a = { bar };\nint n;");
+ verifyFormat("class foo a = { bar };\nint n;");
+ verifyFormat("union foo a = { bar };\nint n;");
+
+ // Elaborate types inside function definitions.
+ verifyFormat("struct foo f() {}\nint n;");
+ verifyFormat("class foo f() {}\nint n;");
+ verifyFormat("union foo f() {}\nint n;");
+
+ // Templates.
+ verifyFormat("template <class X> void f() {}\nint n;");
+ verifyFormat("template <struct X> void f() {}\nint n;");
+ verifyFormat("template <union X> void f() {}\nint n;");
+
+ // Actual definitions...
+ verifyFormat("struct {\n} n;");
+ verifyFormat(
+ "template <template <class T, class Y>, class Z> class X {\n} n;");
+ verifyFormat("union Z {\n int n;\n} x;");
+ verifyFormat("class MACRO Z {\n} n;");
+ verifyFormat("class MACRO(X) Z {\n} n;");
+ verifyFormat("class __attribute__(X) Z {\n} n;");
+ verifyFormat("class __declspec(X) Z {\n} n;");
+ verifyFormat("class A##B##C {\n} n;");
+
+ // Redefinition from nested context:
+ verifyFormat("class A::B::C {\n} n;");
+
+ // Template definitions.
+ // FIXME: This is still incorrectly handled at the formatter side.
+ verifyFormat("template <> struct X < 15, i < 3 && 42 < 50 && 33<28> {\n};");
+
+ // FIXME:
+ // This now gets parsed incorrectly as class definition.
+ // verifyFormat("class A<int> f() {\n}\nint n;");
+
+ // Elaborate types where incorrectly parsing the structural element would
+ // break the indent.
+ verifyFormat("if (true)\n"
+ " class X x;\n"
+ "else\n"
+ " f();\n");
+
+ // This is simply incomplete. Formatting is not important, but must not crash.
+ verifyFormat("class A:");
+}
+
+TEST_F(FormatTest, DoNotInterfereWithErrorAndWarning) {
+ verifyFormat("#error Leave all white!!!!! space* alone!\n");
+ verifyFormat("#warning Leave all white!!!!! space* alone!\n");
+ EXPECT_EQ("#error 1", format(" # error 1"));
+ EXPECT_EQ("#warning 1", format(" # warning 1"));
+}
+
+TEST_F(FormatTest, MergeHandlingInTheFaceOfPreprocessorDirectives) {
+ FormatStyle AllowsMergedIf = getGoogleStyle();
+ AllowsMergedIf.AllowShortIfStatementsOnASingleLine = true;
+ verifyFormat("void f() { f(); }\n#error E", AllowsMergedIf);
+ verifyFormat("if (true) return 42;\n#error E", AllowsMergedIf);
+ verifyFormat("if (true)\n#error E\n return 42;", AllowsMergedIf);
+ EXPECT_EQ("if (true) return 42;",
+ format("if (true)\nreturn 42;", AllowsMergedIf));
+ FormatStyle ShortMergedIf = AllowsMergedIf;
+ ShortMergedIf.ColumnLimit = 25;
+ verifyFormat("#define A \\\n"
+ " if (true) return 42;",
+ ShortMergedIf);
+ verifyFormat("#define A \\\n"
+ " f(); \\\n"
+ " if (true)\n"
+ "#define B",
+ ShortMergedIf);
+ verifyFormat("#define A \\\n"
+ " f(); \\\n"
+ " if (true)\n"
+ "g();",
+ ShortMergedIf);
+ verifyFormat("{\n"
+ "#ifdef A\n"
+ " // Comment\n"
+ " if (true) continue;\n"
+ "#endif\n"
+ " // Comment\n"
+ " if (true) continue;",
+ ShortMergedIf);
+}
+
+TEST_F(FormatTest, BlockCommentsInControlLoops) {
+ verifyFormat("if (0) /* a comment in a strange place */ {\n"
+ " f();\n"
+ "}");
+ verifyFormat("if (0) /* a comment in a strange place */ {\n"
+ " f();\n"
+ "} /* another comment */ else /* comment #3 */ {\n"
+ " g();\n"
+ "}");
+ verifyFormat("while (0) /* a comment in a strange place */ {\n"
+ " f();\n"
+ "}");
+ verifyFormat("for (;;) /* a comment in a strange place */ {\n"
+ " f();\n"
+ "}");
+ verifyFormat("do /* a comment in a strange place */ {\n"
+ " f();\n"
+ "} /* another comment */ while (0);");
+}
+
+TEST_F(FormatTest, BlockComments) {
+ EXPECT_EQ("/* */ /* */ /* */\n/* */ /* */ /* */",
+ format("/* *//* */ /* */\n/* *//* */ /* */"));
+ EXPECT_EQ("/* */ a /* */ b;", format(" /* */ a/* */ b;"));
+ EXPECT_EQ("#define A /*123*/\\\n"
+ " b\n"
+ "/* */\n"
+ "someCall(\n"
+ " parameter);",
+ format("#define A /*123*/ b\n"
+ "/* */\n"
+ "someCall(parameter);",
+ getLLVMStyleWithColumns(15)));
+
+ EXPECT_EQ("#define A\n"
+ "/* */ someCall(\n"
+ " parameter);",
+ format("#define A\n"
+ "/* */someCall(parameter);",
+ getLLVMStyleWithColumns(15)));
+
+ FormatStyle NoBinPacking = getLLVMStyle();
+ NoBinPacking.BinPackParameters = false;
+ EXPECT_EQ("someFunction(1, /* comment 1 */\n"
+ " 2, /* comment 2 */\n"
+ " 3, /* comment 3 */\n"
+ " aaaa,\n"
+ " bbbb);",
+ format("someFunction (1, /* comment 1 */\n"
+ " 2, /* comment 2 */ \n"
+ " 3, /* comment 3 */\n"
+ "aaaa, bbbb );",
+ NoBinPacking));
+ verifyFormat(
+ "bool aaaaaaaaaaaaa = /* comment: */ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ||\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaa;");
+ EXPECT_EQ(
+ "bool aaaaaaaaaaaaa = /* trailing comment */\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaa || aaaaaaaaaaaaaaaaaaaaaaaaa ||\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaa || aaaaaaaaaaaaaaaaaaaaaaaaaa;",
+ format(
+ "bool aaaaaaaaaaaaa = /* trailing comment */\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaa||aaaaaaaaaaaaaaaaaaaaaaaaa ||\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaa || aaaaaaaaaaaaaaaaaaaaaaaaaa;"));
+ EXPECT_EQ(
+ "int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; /* comment */\n"
+ "int bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; /* comment */\n"
+ "int cccccccccccccccccccccccccccccc; /* comment */\n",
+ format("int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; /* comment */\n"
+ "int bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb; /* comment */\n"
+ "int cccccccccccccccccccccccccccccc; /* comment */\n"));
+}
+
+TEST_F(FormatTest, BlockCommentsInMacros) {
+ EXPECT_EQ("#define A \\\n"
+ " { \\\n"
+ " /* one line */ \\\n"
+ " someCall();",
+ format("#define A { \\\n"
+ " /* one line */ \\\n"
+ " someCall();",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("#define A \\\n"
+ " { \\\n"
+ " /* previous */ \\\n"
+ " /* one line */ \\\n"
+ " someCall();",
+ format("#define A { \\\n"
+ " /* previous */ \\\n"
+ " /* one line */ \\\n"
+ " someCall();",
+ getLLVMStyleWithColumns(20)));
+}
+
+TEST_F(FormatTest, IndentLineCommentsInStartOfBlockAtEndOfFile) {
+ // FIXME: This is not what we want...
+ verifyFormat("{\n"
+ "// a"
+ "// b");
+}
+
+TEST_F(FormatTest, FormatStarDependingOnContext) {
+ verifyFormat("void f(int *a);");
+ verifyFormat("void f() { f(fint * b); }");
+ verifyFormat("class A {\n void f(int *a);\n};");
+ verifyFormat("class A {\n int *a;\n};");
+ verifyFormat("namespace a {\n"
+ "namespace b {\n"
+ "class A {\n"
+ " void f() {}\n"
+ " int *a;\n"
+ "};\n"
+ "}\n"
+ "}");
+}
+
+TEST_F(FormatTest, SpecialTokensAtEndOfLine) {
+ verifyFormat("while");
+ verifyFormat("operator");
+}
+
+//===----------------------------------------------------------------------===//
+// Objective-C tests.
+//===----------------------------------------------------------------------===//
+
+TEST_F(FormatTest, FormatForObjectiveCMethodDecls) {
+ verifyFormat("- (void)sendAction:(SEL)aSelector to:(BOOL)anObject;");
+ EXPECT_EQ("- (NSUInteger)indexOfObject:(id)anObject;",
+ format("-(NSUInteger)indexOfObject:(id)anObject;"));
+ EXPECT_EQ("- (NSInteger)Mthod1;", format("-(NSInteger)Mthod1;"));
+ EXPECT_EQ("+ (id)Mthod2;", format("+(id)Mthod2;"));
+ EXPECT_EQ("- (NSInteger)Method3:(id)anObject;",
+ format("-(NSInteger)Method3:(id)anObject;"));
+ EXPECT_EQ("- (NSInteger)Method4:(id)anObject;",
+ format("-(NSInteger)Method4:(id)anObject;"));
+ EXPECT_EQ("- (NSInteger)Method5:(id)anObject:(id)AnotherObject;",
+ format("-(NSInteger)Method5:(id)anObject:(id)AnotherObject;"));
+ EXPECT_EQ("- (id)Method6:(id)A:(id)B:(id)C:(id)D;",
+ format("- (id)Method6:(id)A:(id)B:(id)C:(id)D;"));
+ EXPECT_EQ(
+ "- (void)sendAction:(SEL)aSelector to:(id)anObject forAllCells:(BOOL)flag;",
+ format(
+ "- (void)sendAction:(SEL)aSelector to:(id)anObject forAllCells:(BOOL)flag;"));
+
+ // Very long objectiveC method declaration.
+ verifyFormat("- (NSUInteger)indexOfObject:(id)anObject\n"
+ " inRange:(NSRange)range\n"
+ " outRange:(NSRange)out_range\n"
+ " outRange1:(NSRange)out_range1\n"
+ " outRange2:(NSRange)out_range2\n"
+ " outRange3:(NSRange)out_range3\n"
+ " outRange4:(NSRange)out_range4\n"
+ " outRange5:(NSRange)out_range5\n"
+ " outRange6:(NSRange)out_range6\n"
+ " outRange7:(NSRange)out_range7\n"
+ " outRange8:(NSRange)out_range8\n"
+ " outRange9:(NSRange)out_range9;");
+
+ verifyFormat("- (int)sum:(vector<int>)numbers;");
+ verifyGoogleFormat("- (void)setDelegate:(id<Protocol>)delegate;");
+ // FIXME: In LLVM style, there should be a space in front of a '<' for ObjC
+ // protocol lists (but not for template classes):
+ //verifyFormat("- (void)setDelegate:(id <Protocol>)delegate;");
+
+ verifyFormat("- (int(*)())foo:(int(*)())f;");
+ verifyGoogleFormat("- (int(*)())foo:(int(*)())foo;");
+
+ // If there's no return type (very rare in practice!), LLVM and Google style
+ // agree.
+ verifyFormat("- foo;");
+ verifyFormat("- foo:(int)f;");
+ verifyGoogleFormat("- foo:(int)foo;");
+}
+
+TEST_F(FormatTest, FormatObjCBlocks) {
+ verifyFormat("int (^Block)(int, int);");
+ verifyFormat("int (^Block1)(int, int) = ^(int i, int j)");
+}
+
+TEST_F(FormatTest, FormatObjCInterface) {
+ verifyFormat("@interface Foo : NSObject <NSSomeDelegate> {\n"
+ "@public\n"
+ " int field1;\n"
+ "@protected\n"
+ " int field2;\n"
+ "@private\n"
+ " int field3;\n"
+ "@package\n"
+ " int field4;\n"
+ "}\n"
+ "+ (id)init;\n"
+ "@end");
+
+ verifyGoogleFormat("@interface Foo : NSObject<NSSomeDelegate> {\n"
+ " @public\n"
+ " int field1;\n"
+ " @protected\n"
+ " int field2;\n"
+ " @private\n"
+ " int field3;\n"
+ " @package\n"
+ " int field4;\n"
+ "}\n"
+ "+ (id)init;\n"
+ "@end");
+
+ verifyFormat("@interface /* wait for it */ Foo\n"
+ "+ (id)init;\n"
+ "// Look, a comment!\n"
+ "- (int)answerWith:(int)i;\n"
+ "@end");
+
+ verifyFormat("@interface Foo\n"
+ "@end\n"
+ "@interface Bar\n"
+ "@end");
+
+ verifyFormat("@interface Foo : Bar\n"
+ "+ (id)init;\n"
+ "@end");
+
+ verifyFormat("@interface Foo : /**/ Bar /**/ <Baz, /**/ Quux>\n"
+ "+ (id)init;\n"
+ "@end");
+
+ verifyGoogleFormat("@interface Foo : Bar<Baz, Quux>\n"
+ "+ (id)init;\n"
+ "@end");
+
+ verifyFormat("@interface Foo (HackStuff)\n"
+ "+ (id)init;\n"
+ "@end");
+
+ verifyFormat("@interface Foo ()\n"
+ "+ (id)init;\n"
+ "@end");
+
+ verifyFormat("@interface Foo (HackStuff) <MyProtocol>\n"
+ "+ (id)init;\n"
+ "@end");
+
+ verifyGoogleFormat("@interface Foo (HackStuff)<MyProtocol>\n"
+ "+ (id)init;\n"
+ "@end");
+
+ verifyFormat("@interface Foo {\n"
+ " int _i;\n"
+ "}\n"
+ "+ (id)init;\n"
+ "@end");
+
+ verifyFormat("@interface Foo : Bar {\n"
+ " int _i;\n"
+ "}\n"
+ "+ (id)init;\n"
+ "@end");
+
+ verifyFormat("@interface Foo : Bar <Baz, Quux> {\n"
+ " int _i;\n"
+ "}\n"
+ "+ (id)init;\n"
+ "@end");
+
+ verifyFormat("@interface Foo (HackStuff) {\n"
+ " int _i;\n"
+ "}\n"
+ "+ (id)init;\n"
+ "@end");
+
+ verifyFormat("@interface Foo () {\n"
+ " int _i;\n"
+ "}\n"
+ "+ (id)init;\n"
+ "@end");
+
+ verifyFormat("@interface Foo (HackStuff) <MyProtocol> {\n"
+ " int _i;\n"
+ "}\n"
+ "+ (id)init;\n"
+ "@end");
+}
+
+TEST_F(FormatTest, FormatObjCImplementation) {
+ verifyFormat("@implementation Foo : NSObject {\n"
+ "@public\n"
+ " int field1;\n"
+ "@protected\n"
+ " int field2;\n"
+ "@private\n"
+ " int field3;\n"
+ "@package\n"
+ " int field4;\n"
+ "}\n"
+ "+ (id)init {\n}\n"
+ "@end");
+
+ verifyGoogleFormat("@implementation Foo : NSObject {\n"
+ " @public\n"
+ " int field1;\n"
+ " @protected\n"
+ " int field2;\n"
+ " @private\n"
+ " int field3;\n"
+ " @package\n"
+ " int field4;\n"
+ "}\n"
+ "+ (id)init {\n}\n"
+ "@end");
+
+ verifyFormat("@implementation Foo\n"
+ "+ (id)init {\n"
+ " if (true)\n"
+ " return nil;\n"
+ "}\n"
+ "// Look, a comment!\n"
+ "- (int)answerWith:(int)i {\n"
+ " return i;\n"
+ "}\n"
+ "+ (int)answerWith:(int)i {\n"
+ " return i;\n"
+ "}\n"
+ "@end");
+
+ verifyFormat("@implementation Foo\n"
+ "@end\n"
+ "@implementation Bar\n"
+ "@end");
+
+ verifyFormat("@implementation Foo : Bar\n"
+ "+ (id)init {\n}\n"
+ "- (void)foo {\n}\n"
+ "@end");
+
+ verifyFormat("@implementation Foo {\n"
+ " int _i;\n"
+ "}\n"
+ "+ (id)init {\n}\n"
+ "@end");
+
+ verifyFormat("@implementation Foo : Bar {\n"
+ " int _i;\n"
+ "}\n"
+ "+ (id)init {\n}\n"
+ "@end");
+
+ verifyFormat("@implementation Foo (HackStuff)\n"
+ "+ (id)init {\n}\n"
+ "@end");
+}
+
+TEST_F(FormatTest, FormatObjCProtocol) {
+ verifyFormat("@protocol Foo\n"
+ "@property(weak) id delegate;\n"
+ "- (NSUInteger)numberOfThings;\n"
+ "@end");
+
+ verifyFormat("@protocol MyProtocol <NSObject>\n"
+ "- (NSUInteger)numberOfThings;\n"
+ "@end");
+
+ verifyGoogleFormat("@protocol MyProtocol<NSObject>\n"
+ "- (NSUInteger)numberOfThings;\n"
+ "@end");
+
+ verifyFormat("@protocol Foo;\n"
+ "@protocol Bar;\n");
+
+ verifyFormat("@protocol Foo\n"
+ "@end\n"
+ "@protocol Bar\n"
+ "@end");
+
+ verifyFormat("@protocol myProtocol\n"
+ "- (void)mandatoryWithInt:(int)i;\n"
+ "@optional\n"
+ "- (void)optional;\n"
+ "@required\n"
+ "- (void)required;\n"
+ "@optional\n"
+ "@property(assign) int madProp;\n"
+ "@end\n");
+}
+
+TEST_F(FormatTest, FormatObjCMethodDeclarations) {
+ verifyFormat("- (void)doSomethingWith:(GTMFoo *)theFoo\n"
+ " rect:(NSRect)theRect\n"
+ " interval:(float)theInterval {\n"
+ "}");
+ verifyFormat("- (void)shortf:(GTMFoo *)theFoo\n"
+ " longKeyword:(NSRect)theRect\n"
+ " evenLongerKeyword:(float)theInterval\n"
+ " error:(NSError **)theError {\n"
+ "}");
+}
+
+TEST_F(FormatTest, FormatObjCMethodExpr) {
+ verifyFormat("[foo bar:baz];");
+ verifyFormat("return [foo bar:baz];");
+ verifyFormat("f([foo bar:baz]);");
+ verifyFormat("f(2, [foo bar:baz]);");
+ verifyFormat("f(2, a ? b : c);");
+ verifyFormat("[[self initWithInt:4] bar:[baz quux:arrrr]];");
+
+ // Unary operators.
+ verifyFormat("int a = +[foo bar:baz];");
+ verifyFormat("int a = -[foo bar:baz];");
+ verifyFormat("int a = ![foo bar:baz];");
+ verifyFormat("int a = ~[foo bar:baz];");
+ verifyFormat("int a = ++[foo bar:baz];");
+ verifyFormat("int a = --[foo bar:baz];");
+ verifyFormat("int a = sizeof [foo bar:baz];");
+ verifyFormat("int a = alignof [foo bar:baz];");
+ verifyFormat("int a = &[foo bar:baz];");
+ verifyFormat("int a = *[foo bar:baz];");
+ // FIXME: Make casts work, without breaking f()[4].
+ //verifyFormat("int a = (int)[foo bar:baz];");
+ //verifyFormat("return (int)[foo bar:baz];");
+ //verifyFormat("(void)[foo bar:baz];");
+ verifyFormat("return (MyType *)[self.tableView cellForRowAtIndexPath:cell];");
+
+ // Binary operators.
+ verifyFormat("[foo bar:baz], [foo bar:baz];");
+ verifyFormat("[foo bar:baz] = [foo bar:baz];");
+ verifyFormat("[foo bar:baz] *= [foo bar:baz];");
+ verifyFormat("[foo bar:baz] /= [foo bar:baz];");
+ verifyFormat("[foo bar:baz] %= [foo bar:baz];");
+ verifyFormat("[foo bar:baz] += [foo bar:baz];");
+ verifyFormat("[foo bar:baz] -= [foo bar:baz];");
+ verifyFormat("[foo bar:baz] <<= [foo bar:baz];");
+ verifyFormat("[foo bar:baz] >>= [foo bar:baz];");
+ verifyFormat("[foo bar:baz] &= [foo bar:baz];");
+ verifyFormat("[foo bar:baz] ^= [foo bar:baz];");
+ verifyFormat("[foo bar:baz] |= [foo bar:baz];");
+ verifyFormat("[foo bar:baz] ? [foo bar:baz] : [foo bar:baz];");
+ verifyFormat("[foo bar:baz] || [foo bar:baz];");
+ verifyFormat("[foo bar:baz] && [foo bar:baz];");
+ verifyFormat("[foo bar:baz] | [foo bar:baz];");
+ verifyFormat("[foo bar:baz] ^ [foo bar:baz];");
+ verifyFormat("[foo bar:baz] & [foo bar:baz];");
+ verifyFormat("[foo bar:baz] == [foo bar:baz];");
+ verifyFormat("[foo bar:baz] != [foo bar:baz];");
+ verifyFormat("[foo bar:baz] >= [foo bar:baz];");
+ verifyFormat("[foo bar:baz] <= [foo bar:baz];");
+ verifyFormat("[foo bar:baz] > [foo bar:baz];");
+ verifyFormat("[foo bar:baz] < [foo bar:baz];");
+ verifyFormat("[foo bar:baz] >> [foo bar:baz];");
+ verifyFormat("[foo bar:baz] << [foo bar:baz];");
+ verifyFormat("[foo bar:baz] - [foo bar:baz];");
+ verifyFormat("[foo bar:baz] + [foo bar:baz];");
+ verifyFormat("[foo bar:baz] * [foo bar:baz];");
+ verifyFormat("[foo bar:baz] / [foo bar:baz];");
+ verifyFormat("[foo bar:baz] % [foo bar:baz];");
+ // Whew!
+
+ verifyFormat("return in[42];");
+ verifyFormat("for (id foo in [self getStuffFor:bla]) {\n"
+ "}");
+
+ verifyFormat("[self stuffWithInt:(4 + 2) float:4.5];");
+ verifyFormat("[self stuffWithInt:a ? b : c float:4.5];");
+ verifyFormat("[self stuffWithInt:a ? [self foo:bar] : c];");
+ verifyFormat("[self stuffWithInt:a ? (e ? f : g) : c];");
+ verifyFormat("[cond ? obj1 : obj2 methodWithParam:param]");
+ verifyFormat("[button setAction:@selector(zoomOut:)];");
+ verifyFormat("[color getRed:&r green:&g blue:&b alpha:&a];");
+
+ verifyFormat("arr[[self indexForFoo:a]];");
+ verifyFormat("throw [self errorFor:a];");
+ verifyFormat("@throw [self errorFor:a];");
+
+ // This tests that the formatter doesn't break after "backing" but before ":",
+ // which would be at 80 columns.
+ verifyFormat(
+ "void f() {\n"
+ " if ((self = [super initWithContentRect:contentRect\n"
+ " styleMask:styleMask\n"
+ " backing:NSBackingStoreBuffered\n"
+ " defer:YES]))");
+
+ verifyFormat(
+ "[foo checkThatBreakingAfterColonWorksOk:\n"
+ " [bar ifItDoes:reduceOverallLineLengthLikeInThisCase]];");
+
+ verifyFormat("[myObj short:arg1 // Force line break\n"
+ " longKeyword:arg2\n"
+ " evenLongerKeyword:arg3\n"
+ " error:arg4];");
+ verifyFormat(
+ "void f() {\n"
+ " popup_window_.reset([[RenderWidgetPopupWindow alloc]\n"
+ " initWithContentRect:NSMakeRect(origin_global.x, origin_global.y,\n"
+ " pos.width(), pos.height())\n"
+ " styleMask:NSBorderlessWindowMask\n"
+ " backing:NSBackingStoreBuffered\n"
+ " defer:NO]);\n"
+ "}");
+ verifyFormat("[contentsContainer replaceSubview:[subviews objectAtIndex:0]\n"
+ " with:contentsNativeView];");
+
+ verifyFormat(
+ "[pboard addTypes:[NSArray arrayWithObject:kBookmarkButtonDragType]\n"
+ " owner:nillllll];");
+
+ verifyFormat(
+ "[pboard setData:[NSData dataWithBytes:&button length:sizeof(button)]\n"
+ " forType:kBookmarkButtonDragType];");
+
+ verifyFormat("[defaultCenter addObserver:self\n"
+ " selector:@selector(willEnterFullscreen)\n"
+ " name:kWillEnterFullscreenNotification\n"
+ " object:nil];");
+ verifyFormat("[image_rep drawInRect:drawRect\n"
+ " fromRect:NSZeroRect\n"
+ " operation:NSCompositeCopy\n"
+ " fraction:1.0\n"
+ " respectFlipped:NO\n"
+ " hints:nil];");
+
+ verifyFormat(
+ "scoped_nsobject<NSTextField> message(\n"
+ " // The frame will be fixed up when |-setMessageText:| is called.\n"
+ " [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)]);");
+}
+
+TEST_F(FormatTest, ObjCAt) {
+ verifyFormat("@autoreleasepool");
+ verifyFormat("@catch");
+ verifyFormat("@class");
+ verifyFormat("@compatibility_alias");
+ verifyFormat("@defs");
+ verifyFormat("@dynamic");
+ verifyFormat("@encode");
+ verifyFormat("@end");
+ verifyFormat("@finally");
+ verifyFormat("@implementation");
+ verifyFormat("@import");
+ verifyFormat("@interface");
+ verifyFormat("@optional");
+ verifyFormat("@package");
+ verifyFormat("@private");
+ verifyFormat("@property");
+ verifyFormat("@protected");
+ verifyFormat("@protocol");
+ verifyFormat("@public");
+ verifyFormat("@required");
+ verifyFormat("@selector");
+ verifyFormat("@synchronized");
+ verifyFormat("@synthesize");
+ verifyFormat("@throw");
+ verifyFormat("@try");
+
+ EXPECT_EQ("@interface", format("@ interface"));
+
+ // The precise formatting of this doesn't matter, nobody writes code like
+ // this.
+ verifyFormat("@ /*foo*/ interface");
+}
+
+TEST_F(FormatTest, ObjCSnippets) {
+ verifyFormat("@autoreleasepool {\n"
+ " foo();\n"
+ "}");
+ verifyFormat("@class Foo, Bar;");
+ verifyFormat("@compatibility_alias AliasName ExistingClass;");
+ verifyFormat("@dynamic textColor;");
+ verifyFormat("char *buf1 = @encode(int *);");
+ verifyFormat("char *buf1 = @encode(typeof(4 * 5));");
+ verifyFormat("char *buf1 = @encode(int **);");
+ verifyFormat("Protocol *proto = @protocol(p1);");
+ verifyFormat("SEL s = @selector(foo:);");
+ verifyFormat("@synchronized(self) {\n"
+ " f();\n"
+ "}");
+
+ verifyFormat("@synthesize dropArrowPosition = dropArrowPosition_;");
+ verifyGoogleFormat("@synthesize dropArrowPosition = dropArrowPosition_;");
+
+ verifyFormat("@property(assign, nonatomic) CGFloat hoverAlpha;");
+ verifyFormat("@property(assign, getter=isEditable) BOOL editable;");
+ verifyGoogleFormat("@property(assign, getter=isEditable) BOOL editable;");
+}
+
+TEST_F(FormatTest, ObjCLiterals) {
+ verifyFormat("@\"String\"");
+ verifyFormat("@1");
+ verifyFormat("@+4.8");
+ verifyFormat("@-4");
+ verifyFormat("@1LL");
+ verifyFormat("@.5");
+ verifyFormat("@'c'");
+ verifyFormat("@true");
+
+ verifyFormat("NSNumber *smallestInt = @(-INT_MAX - 1);");
+ verifyFormat("NSNumber *piOverTwo = @(M_PI / 2);");
+ verifyFormat("NSNumber *favoriteColor = @(Green);");
+ verifyFormat("NSString *path = @(getenv(\"PATH\"));");
+
+ verifyFormat("@[");
+ verifyFormat("@[]");
+ verifyFormat(
+ "NSArray *array = @[ @\" Hey \", NSApp, [NSNumber numberWithInt:42] ];");
+ verifyFormat("return @[ @3, @[], @[ @4, @5 ] ];");
+
+ verifyFormat("@{");
+ verifyFormat("@{}");
+ verifyFormat("@{ @\"one\" : @1 }");
+ verifyFormat("return @{ @\"one\" : @1 };");
+ verifyFormat("@{ @\"one\" : @1, }");
+ verifyFormat("@{ @\"one\" : @{ @2 : @1 } }");
+ verifyFormat("@{ @\"one\" : @{ @2 : @1 }, }");
+ verifyFormat("@{ 1 > 2 ? @\"one\" : @\"two\" : 1 > 2 ? @1 : @2 }");
+ verifyFormat("[self setDict:@{}");
+ verifyFormat("[self setDict:@{ @1 : @2 }");
+ verifyFormat("NSLog(@\"%@\", @{ @1 : @2, @2 : @3 }[@1]);");
+ verifyFormat(
+ "NSDictionary *masses = @{ @\"H\" : @1.0078, @\"He\" : @4.0026 };");
+ verifyFormat(
+ "NSDictionary *settings = @{ AVEncoderKey : @(AVAudioQualityMax) };");
+
+ // FIXME: Nested and multi-line array and dictionary literals need more work.
+ verifyFormat(
+ "NSDictionary *d = @{ @\"nam\" : NSUserNam(), @\"dte\" : [NSDate date],\n"
+ " @\"processInfo\" : [NSProcessInfo processInfo] };");
+}
+
+TEST_F(FormatTest, ReformatRegionAdjustsIndent) {
+ EXPECT_EQ("{\n"
+ "{\n"
+ "a;\n"
+ "b;\n"
+ "}\n"
+ "}",
+ format("{\n"
+ "{\n"
+ "a;\n"
+ " b;\n"
+ "}\n"
+ "}",
+ 13, 2, getLLVMStyle()));
+ EXPECT_EQ("{\n"
+ "{\n"
+ " a;\n"
+ "b;\n"
+ "}\n"
+ "}",
+ format("{\n"
+ "{\n"
+ " a;\n"
+ "b;\n"
+ "}\n"
+ "}",
+ 9, 2, getLLVMStyle()));
+ EXPECT_EQ("{\n"
+ "{\n"
+ "public:\n"
+ " b;\n"
+ "}\n"
+ "}",
+ format("{\n"
+ "{\n"
+ "public:\n"
+ " b;\n"
+ "}\n"
+ "}",
+ 17, 2, getLLVMStyle()));
+ EXPECT_EQ("{\n"
+ "{\n"
+ "a;\n"
+ "}\n"
+ "{\n"
+ " b;\n"
+ "}\n"
+ "}",
+ format("{\n"
+ "{\n"
+ "a;\n"
+ "}\n"
+ "{\n"
+ " b;\n"
+ "}\n"
+ "}",
+ 22, 2, getLLVMStyle()));
+ EXPECT_EQ(" {\n"
+ " a;\n"
+ " }",
+ format(" {\n"
+ "a;\n"
+ " }",
+ 4, 2, getLLVMStyle()));
+ EXPECT_EQ("void f() {}\n"
+ "void g() {}",
+ format("void f() {}\n"
+ "void g() {}",
+ 13, 0, getLLVMStyle()));
+ EXPECT_EQ("int a; // comment\n"
+ " // line 2\n"
+ "int b;",
+ format("int a; // comment\n"
+ " // line 2\n"
+ " int b;",
+ 35, 0, getLLVMStyle()));
+}
+
+TEST_F(FormatTest, BreakStringLiterals) {
+ EXPECT_EQ("\"some text \"\n"
+ "\"other\";",
+ format("\"some text other\";", getLLVMStyleWithColumns(12)));
+ EXPECT_EQ(
+ "#define A \\\n"
+ " \"some \" \\\n"
+ " \"text \" \\\n"
+ " \"other\";",
+ format("#define A \"some text other\";", getLLVMStyleWithColumns(12)));
+ EXPECT_EQ(
+ "#define A \\\n"
+ " \"so \" \\\n"
+ " \"text \" \\\n"
+ " \"other\";",
+ format("#define A \"so text other\";", getLLVMStyleWithColumns(12)));
+
+ EXPECT_EQ("\"some text\"",
+ format("\"some text\"", getLLVMStyleWithColumns(1)));
+ EXPECT_EQ("\"some text\"",
+ format("\"some text\"", getLLVMStyleWithColumns(11)));
+ EXPECT_EQ("\"some \"\n"
+ "\"text\"",
+ format("\"some text\"", getLLVMStyleWithColumns(10)));
+ EXPECT_EQ("\"some \"\n"
+ "\"text\"",
+ format("\"some text\"", getLLVMStyleWithColumns(7)));
+ EXPECT_EQ("\"some\"\n"
+ "\" text\"",
+ format("\"some text\"", getLLVMStyleWithColumns(6)));
+ EXPECT_EQ("\"some\"\n"
+ "\" tex\"\n"
+ "\" and\"",
+ format("\"some tex and\"", getLLVMStyleWithColumns(6)));
+ EXPECT_EQ("\"some\"\n"
+ "\"/tex\"\n"
+ "\"/and\"",
+ format("\"some/tex/and\"", getLLVMStyleWithColumns(6)));
+
+ EXPECT_EQ("variable =\n"
+ " \"long string \"\n"
+ " \"literal\";",
+ format("variable = \"long string literal\";",
+ getLLVMStyleWithColumns(20)));
+
+ EXPECT_EQ("variable = f(\n"
+ " \"long string \"\n"
+ " \"literal\",\n"
+ " short,\n"
+ " loooooooooooooooooooong);",
+ format("variable = f(\"long string literal\", short, "
+ "loooooooooooooooooooong);",
+ getLLVMStyleWithColumns(20)));
+ EXPECT_EQ(
+ "f(\"one two\".split(\n"
+ " variable));",
+ format("f(\"one two\".split(variable));", getLLVMStyleWithColumns(20)));
+ EXPECT_EQ("f(\"one two three four five six \"\n"
+ " \"seven\".split(\n"
+ " really_looooong_variable));",
+ format("f(\"one two three four five six seven\"."
+ "split(really_looooong_variable));",
+ getLLVMStyleWithColumns(33)));
+
+ EXPECT_EQ("f(\"some \"\n"
+ " \"text\",\n"
+ " other);",
+ format("f(\"some text\", other);", getLLVMStyleWithColumns(10)));
+
+ // Only break as a last resort.
+ verifyFormat(
+ "aaaaaaaaaaaaaaaaaaaa(\n"
+ " aaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaa(\"aaa aaaaa aaa aaa aaaaa aaa aaaaa aaa aaa aaaaaa\"));");
+
+ EXPECT_EQ(
+ "\"splitmea\"\n"
+ "\"trandomp\"\n"
+ "\"oint\"",
+ format("\"splitmeatrandompoint\"", getLLVMStyleWithColumns(10)));
+
+ EXPECT_EQ(
+ "\"split/\"\n"
+ "\"pathat/\"\n"
+ "\"slashes\"",
+ format("\"split/pathat/slashes\"", getLLVMStyleWithColumns(10)));
+}
+
+TEST_F(FormatTest, DoNotBreakStringLiteralsInEscapeSequence) {
+ EXPECT_EQ("\"\\a\"",
+ format("\"\\a\"", getLLVMStyleWithColumns(3)));
+ EXPECT_EQ("\"\\\"",
+ format("\"\\\"", getLLVMStyleWithColumns(2)));
+ EXPECT_EQ("\"test\"\n"
+ "\"\\n\"",
+ format("\"test\\n\"", getLLVMStyleWithColumns(7)));
+ EXPECT_EQ("\"tes\\\\\"\n"
+ "\"n\"",
+ format("\"tes\\\\n\"", getLLVMStyleWithColumns(7)));
+ EXPECT_EQ("\"\\\\\\\\\"\n"
+ "\"\\n\"",
+ format("\"\\\\\\\\\\n\"", getLLVMStyleWithColumns(7)));
+ EXPECT_EQ("\"\\uff01\"",
+ format("\"\\uff01\"", getLLVMStyleWithColumns(7)));
+ EXPECT_EQ("\"\\uff01\"\n"
+ "\"test\"",
+ format("\"\\uff01test\"", getLLVMStyleWithColumns(8)));
+ EXPECT_EQ("\"\\Uff01ff02\"",
+ format("\"\\Uff01ff02\"", getLLVMStyleWithColumns(11)));
+ EXPECT_EQ("\"\\x000000000001\"\n"
+ "\"next\"",
+ format("\"\\x000000000001next\"", getLLVMStyleWithColumns(16)));
+ EXPECT_EQ("\"\\x000000000001next\"",
+ format("\"\\x000000000001next\"", getLLVMStyleWithColumns(15)));
+ EXPECT_EQ("\"\\x000000000001\"",
+ format("\"\\x000000000001\"", getLLVMStyleWithColumns(7)));
+ EXPECT_EQ("\"test\"\n"
+ "\"\\000000\"\n"
+ "\"000001\"",
+ format("\"test\\000000000001\"", getLLVMStyleWithColumns(9)));
+ EXPECT_EQ("\"test\\000\"\n"
+ "\"000000001\"",
+ format("\"test\\000000000001\"", getLLVMStyleWithColumns(10)));
+ EXPECT_EQ("R\"(\\x\\x00)\"\n",
+ format("R\"(\\x\\x00)\"\n", getLLVMStyleWithColumns(7)));
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/unittests/Format/Makefile b/unittests/Format/Makefile
new file mode 100644
index 0000000..e9d0cbb
--- /dev/null
+++ b/unittests/Format/Makefile
@@ -0,0 +1,19 @@
+##===- unittests/Format/Makefile ---------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL = ../..
+TESTNAME = Format
+include $(CLANG_LEVEL)/../../Makefile.config
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc
+USEDLIBS = clangFormat.a clangTooling.a clangFrontend.a clangSerialization.a \
+ clangDriver.a clangParse.a clangRewriteCore.a \
+ clangRewriteFrontend.a clangSema.a clangAnalysis.a clangEdit.a \
+ clangAST.a clangASTMatchers.a clangLex.a clangBasic.a
+
+include $(CLANG_LEVEL)/unittests/Makefile
diff --git a/unittests/Frontend/CMakeLists.txt b/unittests/Frontend/CMakeLists.txt
index 139cf42..c65a163 100644
--- a/unittests/Frontend/CMakeLists.txt
+++ b/unittests/Frontend/CMakeLists.txt
@@ -1,6 +1,7 @@
set(LLVM_LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
asmparser
+ bitreader
support
mc
)
diff --git a/unittests/Frontend/FrontendActionTest.cpp b/unittests/Frontend/FrontendActionTest.cpp
index 84a6545..bcb340d 100644
--- a/unittests/Frontend/FrontendActionTest.cpp
+++ b/unittests/Frontend/FrontendActionTest.cpp
@@ -7,16 +7,14 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/AST/RecursiveASTVisitor.h"
-#include "clang/AST/ASTContext.h"
+#include "clang/Frontend/FrontendAction.h"
#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
-#include "clang/Frontend/FrontendAction.h"
-
#include "llvm/ADT/Triple.h"
#include "llvm/Support/MemoryBuffer.h"
-
#include "gtest/gtest.h"
using namespace llvm;
@@ -62,7 +60,7 @@ TEST(ASTFrontendAction, Sanity) {
invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu";
CompilerInstance compiler;
compiler.setInvocation(invocation);
- compiler.createDiagnostics(0, NULL);
+ compiler.createDiagnostics();
TestASTFrontendAction test_action;
ASSERT_TRUE(compiler.ExecuteAction(test_action));
diff --git a/unittests/Frontend/Makefile b/unittests/Frontend/Makefile
index 4b6f875..f61791b 100644
--- a/unittests/Frontend/Makefile
+++ b/unittests/Frontend/Makefile
@@ -10,7 +10,7 @@
CLANG_LEVEL = ../..
TESTNAME = Frontend
include $(CLANG_LEVEL)/../../Makefile.config
-LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc
USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \
clangSerialization.a clangCodeGen.a clangParse.a clangSema.a \
clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a \
diff --git a/unittests/Lex/CMakeLists.txt b/unittests/Lex/CMakeLists.txt
index 03c8cd5..78838c0 100644
--- a/unittests/Lex/CMakeLists.txt
+++ b/unittests/Lex/CMakeLists.txt
@@ -1,7 +1,7 @@
add_clang_unittest(LexTests
LexerTest.cpp
- PreprocessingRecordTest.cpp
PPCallbacksTest.cpp
+ PPConditionalDirectiveRecordTest.cpp
)
target_link_libraries(LexTests
diff --git a/unittests/Lex/LexerTest.cpp b/unittests/Lex/LexerTest.cpp
index e95cd02..c9b1840 100644
--- a/unittests/Lex/LexerTest.cpp
+++ b/unittests/Lex/LexerTest.cpp
@@ -1,4 +1,4 @@
-//===- unittests/Basic/LexerTest.cpp ------ Lexer tests -------------------===//
+//===- unittests/Lex/LexerTest.cpp ------ Lexer tests ---------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,20 +7,20 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/FileManager.h"
+#include "clang/Lex/Lexer.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
-#include "clang/Basic/TargetOptions.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/Lex/ModuleLoader.h"
+#include "clang/Basic/TargetOptions.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/HeaderSearchOptions.h"
+#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "llvm/Config/config.h"
-
#include "gtest/gtest.h"
using namespace llvm;
@@ -39,7 +39,7 @@ protected:
TargetOpts(new TargetOptions)
{
TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
- Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
+ Target = TargetInfo::CreateTargetInfo(Diags, &*TargetOpts);
}
FileSystemOptions FileMgrOpts;
@@ -53,11 +53,17 @@ protected:
};
class VoidModuleLoader : public ModuleLoader {
- virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
- Module::NameVisibilityKind Visibility,
- bool IsInclusionDirective) {
- return 0;
+ virtual ModuleLoadResult loadModule(SourceLocation ImportLoc,
+ ModuleIdPath Path,
+ Module::NameVisibilityKind Visibility,
+ bool IsInclusionDirective) {
+ return ModuleLoadResult();
}
+
+ virtual void makeModuleVisible(Module *Mod,
+ Module::NameVisibilityKind Visibility,
+ SourceLocation ImportLoc,
+ bool Complain) { }
};
TEST_F(LexerTest, LexAPI) {
diff --git a/unittests/Lex/PPCallbacksTest.cpp b/unittests/Lex/PPCallbacksTest.cpp
index 6e7efa9..36bd5f9 100644
--- a/unittests/Lex/PPCallbacksTest.cpp
+++ b/unittests/Lex/PPCallbacksTest.cpp
@@ -7,6 +7,7 @@
//
//===--------------------------------------------------------------===//
+#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
@@ -16,12 +17,9 @@
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/HeaderSearchOptions.h"
#include "clang/Lex/ModuleLoader.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
-
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/PathV2.h"
-
#include "gtest/gtest.h"
using namespace llvm;
@@ -32,11 +30,17 @@ namespace {
// Stub out module loading.
class VoidModuleLoader : public ModuleLoader {
- virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
- Module::NameVisibilityKind Visibility,
- bool IsInclusionDirective) {
- return 0;
+ virtual ModuleLoadResult loadModule(SourceLocation ImportLoc,
+ ModuleIdPath Path,
+ Module::NameVisibilityKind Visibility,
+ bool IsInclusionDirective) {
+ return ModuleLoadResult();
}
+
+ virtual void makeModuleVisible(Module *Mod,
+ Module::NameVisibilityKind Visibility,
+ SourceLocation ImportLoc,
+ bool Complain) { }
};
// Stub to collect data from InclusionDirective callbacks.
@@ -84,7 +88,7 @@ protected:
SourceMgr(Diags, FileMgr) {
TargetOpts = new TargetOptions();
TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
- Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
+ Target = TargetInfo::CreateTargetInfo(Diags, &*TargetOpts);
}
FileSystemOptions FileMgrOpts;
@@ -107,7 +111,7 @@ protected:
// Add header's parent path to search path.
StringRef SearchPath = path::parent_path(HeaderPath);
const DirectoryEntry *DE = FileMgr.getDirectory(SearchPath);
- DirectoryLookup DL(DE, SrcMgr::C_User, true, false);
+ DirectoryLookup DL(DE, SrcMgr::C_User, false);
HeaderInfo.AddSearchPath(DL, IsSystemHeader);
}
diff --git a/unittests/Lex/PreprocessingRecordTest.cpp b/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
index 815081a..082eced 100644
--- a/unittests/Lex/PreprocessingRecordTest.cpp
+++ b/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
@@ -1,4 +1,4 @@
-//===- unittests/Lex/PreprocessingRecordTest.cpp - PreprocessingRecord tests =//
+//===- unittests/Lex/PPConditionalDirectiveRecordTest.cpp-PP directive tests =//
//
// The LLVM Compiler Infrastructure
//
@@ -7,21 +7,20 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/FileManager.h"
+#include "clang/Lex/PPConditionalDirectiveRecord.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/FileManager.h"
#include "clang/Basic/LangOptions.h"
-#include "clang/Basic/TargetOptions.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/Lex/ModuleLoader.h"
+#include "clang/Basic/TargetOptions.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/HeaderSearchOptions.h"
+#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
-#include "clang/Lex/PreprocessingRecord.h"
#include "llvm/Config/config.h"
-
#include "gtest/gtest.h"
using namespace llvm;
@@ -30,9 +29,9 @@ using namespace clang;
namespace {
// The test fixture.
-class PreprocessingRecordTest : public ::testing::Test {
+class PPConditionalDirectiveRecordTest : public ::testing::Test {
protected:
- PreprocessingRecordTest()
+ PPConditionalDirectiveRecordTest()
: FileMgr(FileMgrOpts),
DiagID(new DiagnosticIDs()),
Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
@@ -40,7 +39,7 @@ protected:
TargetOpts(new TargetOptions)
{
TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
- Target = TargetInfo::CreateTargetInfo(Diags, *TargetOpts);
+ Target = TargetInfo::CreateTargetInfo(Diags, &*TargetOpts);
}
FileSystemOptions FileMgrOpts;
@@ -54,14 +53,20 @@ protected:
};
class VoidModuleLoader : public ModuleLoader {
- virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
- Module::NameVisibilityKind Visibility,
- bool IsInclusionDirective) {
- return 0;
+ virtual ModuleLoadResult loadModule(SourceLocation ImportLoc,
+ ModuleIdPath Path,
+ Module::NameVisibilityKind Visibility,
+ bool IsInclusionDirective) {
+ return ModuleLoadResult();
}
+
+ virtual void makeModuleVisible(Module *Mod,
+ Module::NameVisibilityKind Visibility,
+ SourceLocation ImportLoc,
+ bool Complain) { }
};
-TEST_F(PreprocessingRecordTest, PPRecAPI) {
+TEST_F(PPConditionalDirectiveRecordTest, PPRecAPI) {
const char *source =
"0 1\n"
"#if 1\n"
@@ -92,7 +97,9 @@ TEST_F(PreprocessingRecordTest, PPRecAPI) {
/*IILookup =*/ 0,
/*OwnsHeaderSearch =*/false,
/*DelayInitialization =*/ false);
- PP.createPreprocessingRecord(true);
+ PPConditionalDirectiveRecord *
+ PPRec = new PPConditionalDirectiveRecord(SourceMgr);
+ PP.addPPCallbacks(PPRec);
PP.EnterMainSourceFile();
std::vector<Token> toks;
@@ -107,37 +114,36 @@ TEST_F(PreprocessingRecordTest, PPRecAPI) {
// Make sure we got the tokens that we expected.
ASSERT_EQ(10U, toks.size());
- PreprocessingRecord &PPRec = *PP.getPreprocessingRecord();
- EXPECT_FALSE(PPRec.rangeIntersectsConditionalDirective(
+ EXPECT_FALSE(PPRec->rangeIntersectsConditionalDirective(
SourceRange(toks[0].getLocation(), toks[1].getLocation())));
- EXPECT_TRUE(PPRec.rangeIntersectsConditionalDirective(
+ EXPECT_TRUE(PPRec->rangeIntersectsConditionalDirective(
SourceRange(toks[0].getLocation(), toks[2].getLocation())));
- EXPECT_FALSE(PPRec.rangeIntersectsConditionalDirective(
+ EXPECT_FALSE(PPRec->rangeIntersectsConditionalDirective(
SourceRange(toks[3].getLocation(), toks[4].getLocation())));
- EXPECT_TRUE(PPRec.rangeIntersectsConditionalDirective(
+ EXPECT_TRUE(PPRec->rangeIntersectsConditionalDirective(
SourceRange(toks[1].getLocation(), toks[5].getLocation())));
- EXPECT_TRUE(PPRec.rangeIntersectsConditionalDirective(
+ EXPECT_TRUE(PPRec->rangeIntersectsConditionalDirective(
SourceRange(toks[2].getLocation(), toks[6].getLocation())));
- EXPECT_FALSE(PPRec.rangeIntersectsConditionalDirective(
+ EXPECT_FALSE(PPRec->rangeIntersectsConditionalDirective(
SourceRange(toks[2].getLocation(), toks[5].getLocation())));
- EXPECT_FALSE(PPRec.rangeIntersectsConditionalDirective(
+ EXPECT_FALSE(PPRec->rangeIntersectsConditionalDirective(
SourceRange(toks[0].getLocation(), toks[6].getLocation())));
- EXPECT_TRUE(PPRec.rangeIntersectsConditionalDirective(
+ EXPECT_TRUE(PPRec->rangeIntersectsConditionalDirective(
SourceRange(toks[2].getLocation(), toks[8].getLocation())));
- EXPECT_FALSE(PPRec.rangeIntersectsConditionalDirective(
+ EXPECT_FALSE(PPRec->rangeIntersectsConditionalDirective(
SourceRange(toks[0].getLocation(), toks[9].getLocation())));
- EXPECT_TRUE(PPRec.areInDifferentConditionalDirectiveRegion(
+ EXPECT_TRUE(PPRec->areInDifferentConditionalDirectiveRegion(
toks[0].getLocation(), toks[2].getLocation()));
- EXPECT_FALSE(PPRec.areInDifferentConditionalDirectiveRegion(
+ EXPECT_FALSE(PPRec->areInDifferentConditionalDirectiveRegion(
toks[3].getLocation(), toks[4].getLocation()));
- EXPECT_TRUE(PPRec.areInDifferentConditionalDirectiveRegion(
+ EXPECT_TRUE(PPRec->areInDifferentConditionalDirectiveRegion(
toks[1].getLocation(), toks[5].getLocation()));
- EXPECT_TRUE(PPRec.areInDifferentConditionalDirectiveRegion(
+ EXPECT_TRUE(PPRec->areInDifferentConditionalDirectiveRegion(
toks[2].getLocation(), toks[0].getLocation()));
- EXPECT_FALSE(PPRec.areInDifferentConditionalDirectiveRegion(
+ EXPECT_FALSE(PPRec->areInDifferentConditionalDirectiveRegion(
toks[4].getLocation(), toks[3].getLocation()));
- EXPECT_TRUE(PPRec.areInDifferentConditionalDirectiveRegion(
+ EXPECT_TRUE(PPRec->areInDifferentConditionalDirectiveRegion(
toks[5].getLocation(), toks[1].getLocation()));
}
diff --git a/unittests/Makefile b/unittests/Makefile
index f74820b..e01a6ac 100644
--- a/unittests/Makefile
+++ b/unittests/Makefile
@@ -14,7 +14,21 @@ ifndef CLANG_LEVEL
IS_UNITTEST_LEVEL := 1
CLANG_LEVEL := ..
-PARALLEL_DIRS = ASTMatchers Basic AST Frontend Lex Tooling
+PARALLEL_DIRS = Basic Lex
+
+include $(CLANG_LEVEL)/../..//Makefile.config
+
+ifeq ($(ENABLE_CLANG_REWRITER),1)
+PARALLEL_DIRS += Format
+endif
+
+ifeq ($(ENABLE_CLANG_REWRITER),1)
+PARALLEL_DIRS += ASTMatchers AST Tooling
+endif
+
+ifeq ($(ENABLE_CLANG_STATIC_ANALYZER),1)
+PARALLEL_DIRS += Frontend
+endif
endif # CLANG_LEVEL
diff --git a/unittests/Tooling/CMakeLists.txt b/unittests/Tooling/CMakeLists.txt
index bd7317f..245c059 100644
--- a/unittests/Tooling/CMakeLists.txt
+++ b/unittests/Tooling/CMakeLists.txt
@@ -1,6 +1,7 @@
set(LLVM_LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
asmparser
+ bitreader
support
mc
)
diff --git a/unittests/Tooling/CompilationDatabaseTest.cpp b/unittests/Tooling/CompilationDatabaseTest.cpp
index 5ed4240..c453b05 100644
--- a/unittests/Tooling/CompilationDatabaseTest.cpp
+++ b/unittests/Tooling/CompilationDatabaseTest.cpp
@@ -42,7 +42,7 @@ TEST(JSONCompilationDatabase, ErrsOnInvalidFormat) {
static std::vector<std::string> getAllFiles(StringRef JSONDatabase,
std::string &ErrorMessage) {
- llvm::OwningPtr<CompilationDatabase> Database(
+ OwningPtr<CompilationDatabase> Database(
JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage));
if (!Database) {
ADD_FAILURE() << ErrorMessage;
@@ -51,6 +51,17 @@ static std::vector<std::string> getAllFiles(StringRef JSONDatabase,
return Database->getAllFiles();
}
+static std::vector<CompileCommand> getAllCompileCommands(StringRef JSONDatabase,
+ std::string &ErrorMessage) {
+ OwningPtr<CompilationDatabase> Database(
+ JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage));
+ if (!Database) {
+ ADD_FAILURE() << ErrorMessage;
+ return std::vector<CompileCommand>();
+ }
+ return Database->getAllCompileCommands();
+}
+
TEST(JSONCompilationDatabase, GetAllFiles) {
std::string ErrorMessage;
EXPECT_EQ(std::vector<std::string>(),
@@ -72,10 +83,39 @@ TEST(JSONCompilationDatabase, GetAllFiles) {
ErrorMessage)) << ErrorMessage;
}
+TEST(JSONCompilationDatabase, GetAllCompileCommands) {
+ std::string ErrorMessage;
+ EXPECT_EQ(0u,
+ getAllCompileCommands("[]", ErrorMessage).size()) << ErrorMessage;
+
+ StringRef Directory1("//net/dir1");
+ StringRef FileName1("file1");
+ StringRef Command1("command1");
+ StringRef Directory2("//net/dir2");
+ StringRef FileName2("file1");
+ StringRef Command2("command1");
+
+ std::vector<CompileCommand> Commands = getAllCompileCommands(
+ ("[{\"directory\":\"" + Directory1 + "\"," +
+ "\"command\":\"" + Command1 + "\","
+ "\"file\":\"" + FileName1 + "\"},"
+ " {\"directory\":\"" + Directory2 + "\"," +
+ "\"command\":\"" + Command2 + "\","
+ "\"file\":\"" + FileName2 + "\"}]").str(),
+ ErrorMessage);
+ EXPECT_EQ(2U, Commands.size()) << ErrorMessage;
+ EXPECT_EQ(Directory1, Commands[0].Directory) << ErrorMessage;
+ ASSERT_EQ(1u, Commands[0].CommandLine.size());
+ EXPECT_EQ(Command1, Commands[0].CommandLine[0]) << ErrorMessage;
+ EXPECT_EQ(Directory2, Commands[1].Directory) << ErrorMessage;
+ ASSERT_EQ(1u, Commands[1].CommandLine.size());
+ EXPECT_EQ(Command2, Commands[1].CommandLine[0]) << ErrorMessage;
+}
+
static CompileCommand findCompileArgsInJsonDatabase(StringRef FileName,
StringRef JSONDatabase,
std::string &ErrorMessage) {
- llvm::OwningPtr<CompilationDatabase> Database(
+ OwningPtr<CompilationDatabase> Database(
JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage));
if (!Database)
return CompileCommand();
@@ -351,6 +391,12 @@ TEST(unescapeJsonCommandLine, ParsesQuotedStringWithoutClosingQuote) {
EXPECT_EQ("", Empty[0]);
}
+TEST(unescapeJsonCommandLine, ParsesSingleQuotedString) {
+ std::vector<std::string> Args = unescapeJsonCommandLine("a'\\\\b \\\"c\\\"'");
+ ASSERT_EQ(1ul, Args.size());
+ EXPECT_EQ("a\\b \"c\"", Args[0]);
+}
+
TEST(FixedCompilationDatabase, ReturnsFixedCommandLine) {
std::vector<std::string> CommandLine;
CommandLine.push_back("one");
@@ -376,9 +422,18 @@ TEST(FixedCompilationDatabase, GetAllFiles) {
EXPECT_EQ(0ul, Database.getAllFiles().size());
}
+TEST(FixedCompilationDatabase, GetAllCompileCommands) {
+ std::vector<std::string> CommandLine;
+ CommandLine.push_back("one");
+ CommandLine.push_back("two");
+ FixedCompilationDatabase Database(".", CommandLine);
+
+ EXPECT_EQ(0ul, Database.getAllCompileCommands().size());
+}
+
TEST(ParseFixedCompilationDatabase, ReturnsNullOnEmptyArgumentList) {
int Argc = 0;
- llvm::OwningPtr<FixedCompilationDatabase> Database(
+ OwningPtr<FixedCompilationDatabase> Database(
FixedCompilationDatabase::loadFromCommandLine(Argc, NULL));
EXPECT_FALSE(Database);
EXPECT_EQ(0, Argc);
@@ -387,7 +442,7 @@ TEST(ParseFixedCompilationDatabase, ReturnsNullOnEmptyArgumentList) {
TEST(ParseFixedCompilationDatabase, ReturnsNullWithoutDoubleDash) {
int Argc = 2;
const char *Argv[] = { "1", "2" };
- llvm::OwningPtr<FixedCompilationDatabase> Database(
+ OwningPtr<FixedCompilationDatabase> Database(
FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
EXPECT_FALSE(Database);
EXPECT_EQ(2, Argc);
@@ -396,7 +451,7 @@ TEST(ParseFixedCompilationDatabase, ReturnsNullWithoutDoubleDash) {
TEST(ParseFixedCompilationDatabase, ReturnsArgumentsAfterDoubleDash) {
int Argc = 5;
const char *Argv[] = { "1", "2", "--\0no-constant-folding", "3", "4" };
- llvm::OwningPtr<FixedCompilationDatabase> Database(
+ OwningPtr<FixedCompilationDatabase> Database(
FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
ASSERT_TRUE(Database);
std::vector<CompileCommand> Result =
@@ -415,7 +470,7 @@ TEST(ParseFixedCompilationDatabase, ReturnsArgumentsAfterDoubleDash) {
TEST(ParseFixedCompilationDatabase, ReturnsEmptyCommandLine) {
int Argc = 3;
const char *Argv[] = { "1", "2", "--\0no-constant-folding" };
- llvm::OwningPtr<FixedCompilationDatabase> Database(
+ OwningPtr<FixedCompilationDatabase> Database(
FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
ASSERT_TRUE(Database);
std::vector<CompileCommand> Result =
diff --git a/unittests/Tooling/Makefile b/unittests/Tooling/Makefile
index 5ed99fc..06fdf88 100644
--- a/unittests/Tooling/Makefile
+++ b/unittests/Tooling/Makefile
@@ -10,7 +10,7 @@
CLANG_LEVEL = ../..
TESTNAME = Tooling
include $(CLANG_LEVEL)/../../Makefile.config
-LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser support mc
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc
USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
clangParse.a clangRewriteCore.a clangRewriteFrontend.a \
clangSema.a clangAnalysis.a clangEdit.a \
diff --git a/unittests/Tooling/RecursiveASTVisitorTest.cpp b/unittests/Tooling/RecursiveASTVisitorTest.cpp
index a68a869..81be190 100644
--- a/unittests/Tooling/RecursiveASTVisitorTest.cpp
+++ b/unittests/Tooling/RecursiveASTVisitorTest.cpp
@@ -50,10 +50,11 @@ class NamedDeclVisitor
public:
bool VisitNamedDecl(NamedDecl *Decl) {
std::string NameWithTemplateArgs;
- Decl->getNameForDiagnostic(NameWithTemplateArgs,
+ llvm::raw_string_ostream OS(NameWithTemplateArgs);
+ Decl->getNameForDiagnostic(OS,
Decl->getASTContext().getPrintingPolicy(),
true);
- Match(NameWithTemplateArgs, Decl->getLocation());
+ Match(OS.str(), Decl->getLocation());
return true;
}
};
diff --git a/unittests/Tooling/RefactoringCallbacksTest.cpp b/unittests/Tooling/RefactoringCallbacksTest.cpp
index 4e30cfd..9e086d8 100644
--- a/unittests/Tooling/RefactoringCallbacksTest.cpp
+++ b/unittests/Tooling/RefactoringCallbacksTest.cpp
@@ -1,4 +1,4 @@
-//===- unittest/ASTMatchers/RefactoringCallbacksTest.cpp ------------------===//
+//===- unittest/Tooling/RefactoringCallbacksTest.cpp ----------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,10 +7,10 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/ASTMatchers/ASTMatchers.h"
-#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Tooling/RefactoringCallbacks.h"
#include "RewriterTestContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
#include "gtest/gtest.h"
namespace clang {
diff --git a/unittests/Tooling/RefactoringTest.cpp b/unittests/Tooling/RefactoringTest.cpp
index ff278bf..3e0d728 100644
--- a/unittests/Tooling/RefactoringTest.cpp
+++ b/unittests/Tooling/RefactoringTest.cpp
@@ -8,12 +8,11 @@
//===----------------------------------------------------------------------===//
#include "RewriterTestContext.h"
-#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclGroup.h"
#include "clang/AST/RecursiveASTVisitor.h"
-#include "clang/Tooling/Refactoring.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileManager.h"
@@ -23,6 +22,7 @@
#include "clang/Frontend/FrontendAction.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Tooling/Refactoring.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Path.h"
@@ -166,7 +166,7 @@ class FlushRewrittenFilesTest : public ::testing::Test {
}
FileID createFile(llvm::StringRef Name, llvm::StringRef Content) {
- llvm::SmallString<1024> Path(TemporaryDirectory.str());
+ SmallString<1024> Path(TemporaryDirectory.str());
llvm::sys::path::append(Path, Name);
std::string ErrorInfo;
llvm::raw_fd_ostream OutStream(Path.c_str(),
@@ -180,7 +180,7 @@ class FlushRewrittenFilesTest : public ::testing::Test {
}
std::string getFileContentFromDisk(llvm::StringRef Name) {
- llvm::SmallString<1024> Path(TemporaryDirectory.str());
+ SmallString<1024> Path(TemporaryDirectory.str());
llvm::sys::path::append(Path, Name);
// We need to read directly from the FileManager without relaying through
// a FileEntry, as otherwise we'd read through an already opened file
diff --git a/unittests/Tooling/RewriterTestContext.h b/unittests/Tooling/RewriterTestContext.h
index d790ac1..13c4202 100644
--- a/unittests/Tooling/RewriterTestContext.h
+++ b/unittests/Tooling/RewriterTestContext.h
@@ -36,7 +36,7 @@ class RewriterTestContext {
public:
RewriterTestContext()
: DiagOpts(new DiagnosticOptions()),
- Diagnostics(llvm::IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
+ Diagnostics(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
&*DiagOpts),
DiagnosticPrinter(llvm::outs(), &*DiagOpts),
Files((FileSystemOptions())),
@@ -72,7 +72,7 @@ class RewriterTestContext {
llvm::raw_fd_ostream Closer(FD, /*shouldClose=*/true);
TemporaryDirectory = llvm::sys::path::parent_path(TemporaryDirectory);
}
- llvm::SmallString<1024> Path(TemporaryDirectory);
+ SmallString<1024> Path(TemporaryDirectory);
llvm::sys::path::append(Path, Name);
std::string ErrorInfo;
llvm::raw_fd_ostream OutStream(Path.c_str(),
@@ -101,7 +101,7 @@ class RewriterTestContext {
}
std::string getFileContentFromDisk(StringRef Name) {
- llvm::SmallString<1024> Path(TemporaryDirectory.str());
+ SmallString<1024> Path(TemporaryDirectory.str());
llvm::sys::path::append(Path, Name);
// We need to read directly from the FileManager without relaying through
// a FileEntry, as otherwise we'd read through an already opened file
@@ -111,7 +111,7 @@ class RewriterTestContext {
return Files.getBufferForFile(Path, NULL)->getBuffer();
}
- llvm::IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
DiagnosticsEngine Diagnostics;
TextDiagnosticPrinter DiagnosticPrinter;
FileManager Files;
diff --git a/unittests/Tooling/TestVisitor.h b/unittests/Tooling/TestVisitor.h
index 8333c24..ce3246a 100644
--- a/unittests/Tooling/TestVisitor.h
+++ b/unittests/Tooling/TestVisitor.h
@@ -15,15 +15,14 @@
#ifndef LLVM_CLANG_TEST_VISITOR_H
#define LLVM_CLANG_TEST_VISITOR_H
-#include <vector>
-
-#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
-#include "clang/Frontend/FrontendAction.h"
#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendAction.h"
#include "clang/Tooling/Tooling.h"
#include "gtest/gtest.h"
+#include <vector>
namespace clang {
diff --git a/unittests/Tooling/ToolingTest.cpp b/unittests/Tooling/ToolingTest.cpp
index d40c613..a9319f2 100644
--- a/unittests/Tooling/ToolingTest.cpp
+++ b/unittests/Tooling/ToolingTest.cpp
@@ -10,6 +10,7 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclGroup.h"
+#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Tooling/CompilationDatabase.h"
@@ -97,9 +98,9 @@ TEST(runToolOnCode, FindsClassDecl) {
}
TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromType) {
- llvm::OwningPtr<FrontendActionFactory> Factory(
- newFrontendActionFactory<SyntaxOnlyAction>());
- llvm::OwningPtr<FrontendAction> Action(Factory->create());
+ OwningPtr<FrontendActionFactory> Factory(
+ newFrontendActionFactory<SyntaxOnlyAction>());
+ OwningPtr<FrontendAction> Action(Factory->create());
EXPECT_TRUE(Action.get() != NULL);
}
@@ -111,9 +112,9 @@ struct IndependentFrontendActionCreator {
TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromFactoryType) {
IndependentFrontendActionCreator Creator;
- llvm::OwningPtr<FrontendActionFactory> Factory(
- newFrontendActionFactory(&Creator));
- llvm::OwningPtr<FrontendAction> Action(Factory->create());
+ OwningPtr<FrontendActionFactory> Factory(
+ newFrontendActionFactory(&Creator));
+ OwningPtr<FrontendAction> Action(Factory->create());
EXPECT_TRUE(Action.get() != NULL);
}
@@ -162,5 +163,28 @@ TEST(newFrontendActionFactory, InjectsEndOfSourceFileCallback) {
}
#endif
+struct SkipBodyConsumer : public clang::ASTConsumer {
+ /// Skip the 'skipMe' function.
+ virtual bool shouldSkipFunctionBody(Decl *D) {
+ FunctionDecl *F = dyn_cast<FunctionDecl>(D);
+ return F && F->getNameAsString() == "skipMe";
+ }
+};
+
+struct SkipBodyAction : public clang::ASTFrontendAction {
+ virtual ASTConsumer *CreateASTConsumer(CompilerInstance &Compiler,
+ StringRef) {
+ Compiler.getFrontendOpts().SkipFunctionBodies = true;
+ return new SkipBodyConsumer;
+ }
+};
+
+TEST(runToolOnCode, TestSkipFunctionBody) {
+ EXPECT_TRUE(runToolOnCode(new SkipBodyAction,
+ "int skipMe() { an_error_here }"));
+ EXPECT_FALSE(runToolOnCode(new SkipBodyAction,
+ "int skipMeNot() { an_error_here }"));
+}
+
} // end namespace tooling
} // end namespace clang
diff --git a/utils/C++Tests/Clang-Code-Compile/lit.local.cfg b/utils/C++Tests/Clang-Code-Compile/lit.local.cfg
deleted file mode 100644
index 59d3466..0000000
--- a/utils/C++Tests/Clang-Code-Compile/lit.local.cfg
+++ /dev/null
@@ -1,26 +0,0 @@
-# -*- Python -*-
-
-# Configuration file for the 'lit' test runner.
-
-def getRoot(config):
- if not config.parent:
- return config
- return getRoot(config.parent)
-
-root = getRoot(config)
-
-# testFormat: The test format to use to interpret tests.
-cxxflags = ['-D__STDC_LIMIT_MACROS',
- '-D__STDC_CONSTANT_MACROS',
- '-Wno-sign-compare',
- '-I%s/include' % root.llvm_src_root,
- '-I%s/include' % root.llvm_obj_root,
- '-I%s/tools/clang/include' % root.llvm_src_root,
- '-I%s/tools/clang/include' % root.llvm_obj_root]
-config.test_format = \
- lit.formats.OneCommandPerFileTest(command=[root.clang, '-emit-llvm', '-c',
- '-o', '/dev/null'] + cxxflags,
- dir='%s/tools/clang/lib' % root.llvm_src_root,
- recursive=True,
- pattern='^(.*\\.cpp)$')
-
diff --git a/utils/C++Tests/Clang-Code-Syntax/lit.local.cfg b/utils/C++Tests/Clang-Code-Syntax/lit.local.cfg
deleted file mode 100644
index 8f00c8d..0000000
--- a/utils/C++Tests/Clang-Code-Syntax/lit.local.cfg
+++ /dev/null
@@ -1,25 +0,0 @@
-# -*- Python -*-
-
-# Configuration file for the 'lit' test runner.
-
-def getRoot(config):
- if not config.parent:
- return config
- return getRoot(config.parent)
-
-root = getRoot(config)
-
-# testFormat: The test format to use to interpret tests.
-cxxflags = ['-D__STDC_LIMIT_MACROS',
- '-D__STDC_CONSTANT_MACROS',
- '-Wno-sign-compare',
- '-I%s/include' % root.llvm_src_root,
- '-I%s/include' % root.llvm_obj_root,
- '-I%s/tools/clang/include' % root.llvm_src_root,
- '-I%s/tools/clang/include' % root.llvm_obj_root]
-config.test_format = \
- lit.formats.OneCommandPerFileTest(command=[root.clang,
- '-fsyntax-only'] + cxxflags,
- dir='%s/tools/clang/lib' % root.llvm_src_root,
- recursive=True,
- pattern='^(.*\\.cpp)$')
diff --git a/utils/C++Tests/Clang-Syntax/lit.local.cfg b/utils/C++Tests/Clang-Syntax/lit.local.cfg
deleted file mode 100644
index 89fdd8e..0000000
--- a/utils/C++Tests/Clang-Syntax/lit.local.cfg
+++ /dev/null
@@ -1,24 +0,0 @@
-# -*- Python -*-
-
-# Configuration file for the 'lit' test runner.
-
-def getRoot(config):
- if not config.parent:
- return config
- return getRoot(config.parent)
-
-root = getRoot(config)
-
-# testFormat: The test format to use to interpret tests.
-config.test_format = lit.formats.SyntaxCheckTest(compiler=root.clang,
- dir='%s/tools/clang/include/clang' % root.llvm_src_root,
- recursive=True,
- pattern='^(.*\\.h)$',
- extra_cxx_args=['-D__STDC_LIMIT_MACROS',
- '-D__STDC_CONSTANT_MACROS',
- '-Wno-sign-compare',
- '-Werror',
- '-I%s/include' % root.llvm_src_root,
- '-I%s/include' % root.llvm_obj_root,
- '-I%s/tools/clang/include' % root.llvm_src_root,
- '-I%s/tools/clang/include' % root.llvm_obj_root])
diff --git a/utils/C++Tests/LLVM-Code-Compile/lit.local.cfg b/utils/C++Tests/LLVM-Code-Compile/lit.local.cfg
deleted file mode 100644
index c1ac6a9..0000000
--- a/utils/C++Tests/LLVM-Code-Compile/lit.local.cfg
+++ /dev/null
@@ -1,48 +0,0 @@
-# -*- Python -*-
-
-# Configuration file for the 'lit' test runner.
-
-def getRoot(config):
- if not config.parent:
- return config
- return getRoot(config.parent)
-
-root = getRoot(config)
-
-# testFormat: The test format to use to interpret tests.
-target_obj_root = root.llvm_obj_root
-cxxflags = ['-D__STDC_LIMIT_MACROS',
- '-D__STDC_CONSTANT_MACROS',
- '-Wno-sign-compare',
- '-I%s/include' % root.llvm_src_root,
- '-I%s/include' % root.llvm_obj_root,
- '-I%s/lib/Target/ARM' % root.llvm_src_root,
- '-I%s/lib/Target/CellSPU' % root.llvm_src_root,
- '-I%s/lib/Target/CppBackend' % root.llvm_src_root,
- '-I%s/lib/Target/Mips' % root.llvm_src_root,
- '-I%s/lib/Target/MSIL' % root.llvm_src_root,
- '-I%s/lib/Target/MSP430' % root.llvm_src_root,
- '-I%s/lib/Target/PIC16' % root.llvm_src_root,
- '-I%s/lib/Target/PowerPC' % root.llvm_src_root,
- '-I%s/lib/Target/Sparc' % root.llvm_src_root,
- '-I%s/lib/Target/X86' % root.llvm_src_root,
- '-I%s/lib/Target/XCore' % root.llvm_src_root,
- '-I%s/lib/Target/ARM' % target_obj_root,
- '-I%s/lib/Target/CellSPU' % target_obj_root,
- '-I%s/lib/Target/CppBackend' % target_obj_root,
- '-I%s/lib/Target/Mips' % target_obj_root,
- '-I%s/lib/Target/MSIL' % target_obj_root,
- '-I%s/lib/Target/MSP430' % target_obj_root,
- '-I%s/lib/Target/PIC16' % target_obj_root,
- '-I%s/lib/Target/PowerPC' % target_obj_root,
- '-I%s/lib/Target/Sparc' % target_obj_root,
- '-I%s/lib/Target/X86' % target_obj_root,
- '-I%s/lib/Target/XCore' % target_obj_root];
-
-config.test_format = \
- lit.formats.OneCommandPerFileTest(command=[root.clang, '-emit-llvm', '-c',
- '-o', '/dev/null'] + cxxflags,
- dir='%s/lib' % root.llvm_src_root,
- recursive=True,
- pattern='^(.*\\.cpp)$')
-
diff --git a/utils/C++Tests/LLVM-Code-Symbols/check-symbols b/utils/C++Tests/LLVM-Code-Symbols/check-symbols
deleted file mode 100755
index cd54eed..0000000
--- a/utils/C++Tests/LLVM-Code-Symbols/check-symbols
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/usr/bin/env python
-
-import subprocess
-import difflib
-
-def capture_2(args0, args1):
- import subprocess
- p0 = subprocess.Popen(args0, stdin=None, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- p1 = subprocess.Popen(args1, stdin=p0.stdout, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- out,_ = p1.communicate()
- return out
-
-def normalize_nm(data):
- lines = data.split('\n')
- lines.sort()
-
- # FIXME: Ignore common symbols for now.
- lines = [ln for ln in lines
- if not ln.startswith(' C')]
-
- return lines
-
-def main():
- import sys
- clang = sys.argv[1]
- flags = sys.argv[2:]
-
- # FIXME: Relax to include undefined symbols.
- nm_args = ["llvm-nm", "-extern-only", "-defined-only"]
-
- llvmgcc_args = ["llvm-gcc"] + flags + ["-emit-llvm","-c","-o","-"]
- clang_args = [clang] + flags + ["-emit-llvm","-c","-o","-"]
-
- llvmgcc_nm = capture_2(llvmgcc_args, nm_args)
- clang_nm = capture_2(clang_args, nm_args)
-
- llvmgcc_nm = normalize_nm(llvmgcc_nm)
- clang_nm = normalize_nm(clang_nm)
-
- if llvmgcc_nm == clang_nm:
- sys.exit(0)
-
- print ' '.join(llvmgcc_args), '|', ' '.join(nm_args)
- print ' '.join(clang_args), '|', ' '.join(nm_args)
- for line in difflib.unified_diff(llvmgcc_nm, clang_nm,
- fromfile="llvm-gcc symbols",
- tofile="clang symbols"):
- print line
- sys.exit(1)
-
-if __name__ == '__main__':
- main()
diff --git a/utils/C++Tests/LLVM-Code-Symbols/lit.local.cfg b/utils/C++Tests/LLVM-Code-Symbols/lit.local.cfg
deleted file mode 100644
index 7882813..0000000
--- a/utils/C++Tests/LLVM-Code-Symbols/lit.local.cfg
+++ /dev/null
@@ -1,48 +0,0 @@
-# -*- Python -*-
-
-# Configuration file for the 'lit' test runner.
-
-def getRoot(config):
- if not config.parent:
- return config
- return getRoot(config.parent)
-
-root = getRoot(config)
-
-# testFormat: The test format to use to interpret tests.
-target_obj_root = root.llvm_obj_root
-cxxflags = ['-D__STDC_LIMIT_MACROS',
- '-D__STDC_CONSTANT_MACROS',
- '-Wno-sign-compare',
- '-I%s/include' % root.llvm_src_root,
- '-I%s/include' % root.llvm_obj_root,
- '-I%s/lib/Target/ARM' % root.llvm_src_root,
- '-I%s/lib/Target/CellSPU' % root.llvm_src_root,
- '-I%s/lib/Target/CppBackend' % root.llvm_src_root,
- '-I%s/lib/Target/Mips' % root.llvm_src_root,
- '-I%s/lib/Target/MSIL' % root.llvm_src_root,
- '-I%s/lib/Target/MSP430' % root.llvm_src_root,
- '-I%s/lib/Target/PIC16' % root.llvm_src_root,
- '-I%s/lib/Target/PowerPC' % root.llvm_src_root,
- '-I%s/lib/Target/Sparc' % root.llvm_src_root,
- '-I%s/lib/Target/X86' % root.llvm_src_root,
- '-I%s/lib/Target/XCore' % root.llvm_src_root,
- '-I%s/lib/Target/ARM' % target_obj_root,
- '-I%s/lib/Target/CellSPU' % target_obj_root,
- '-I%s/lib/Target/CppBackend' % target_obj_root,
- '-I%s/lib/Target/Mips' % target_obj_root,
- '-I%s/lib/Target/MSIL' % target_obj_root,
- '-I%s/lib/Target/MSP430' % target_obj_root,
- '-I%s/lib/Target/PIC16' % target_obj_root,
- '-I%s/lib/Target/PowerPC' % target_obj_root,
- '-I%s/lib/Target/Sparc' % target_obj_root,
- '-I%s/lib/Target/X86' % target_obj_root,
- '-I%s/lib/Target/XCore' % target_obj_root];
-
-kScript = os.path.join(os.path.dirname(__file__), "check-symbols")
-config.test_format = \
- lit.formats.OneCommandPerFileTest(command=[kScript, root.clang] + cxxflags,
- dir='%s/lib' % root.llvm_src_root,
- recursive=True,
- pattern='^(.*\\.cpp)$')
-
diff --git a/utils/C++Tests/LLVM-Code-Syntax/lit.local.cfg b/utils/C++Tests/LLVM-Code-Syntax/lit.local.cfg
deleted file mode 100644
index 42bec2d..0000000
--- a/utils/C++Tests/LLVM-Code-Syntax/lit.local.cfg
+++ /dev/null
@@ -1,46 +0,0 @@
-# -*- Python -*-
-
-# Configuration file for the 'lit' test runner.
-
-def getRoot(config):
- if not config.parent:
- return config
- return getRoot(config.parent)
-
-root = getRoot(config)
-
-# testFormat: The test format to use to interpret tests.
-target_obj_root = root.llvm_obj_root
-cxxflags = ['-D__STDC_LIMIT_MACROS',
- '-D__STDC_CONSTANT_MACROS',
- '-I%s/include' % root.llvm_src_root,
- '-I%s/include' % root.llvm_obj_root,
- '-I%s/lib/Target/ARM' % root.llvm_src_root,
- '-I%s/lib/Target/CellSPU' % root.llvm_src_root,
- '-I%s/lib/Target/CppBackend' % root.llvm_src_root,
- '-I%s/lib/Target/Mips' % root.llvm_src_root,
- '-I%s/lib/Target/MSIL' % root.llvm_src_root,
- '-I%s/lib/Target/MSP430' % root.llvm_src_root,
- '-I%s/lib/Target/PIC16' % root.llvm_src_root,
- '-I%s/lib/Target/PowerPC' % root.llvm_src_root,
- '-I%s/lib/Target/Sparc' % root.llvm_src_root,
- '-I%s/lib/Target/X86' % root.llvm_src_root,
- '-I%s/lib/Target/XCore' % root.llvm_src_root,
- '-I%s/lib/Target/ARM' % target_obj_root,
- '-I%s/lib/Target/CellSPU' % target_obj_root,
- '-I%s/lib/Target/CppBackend' % target_obj_root,
- '-I%s/lib/Target/Mips' % target_obj_root,
- '-I%s/lib/Target/MSIL' % target_obj_root,
- '-I%s/lib/Target/MSP430' % target_obj_root,
- '-I%s/lib/Target/PIC16' % target_obj_root,
- '-I%s/lib/Target/PowerPC' % target_obj_root,
- '-I%s/lib/Target/Sparc' % target_obj_root,
- '-I%s/lib/Target/X86' % target_obj_root,
- '-I%s/lib/Target/XCore' % target_obj_root];
-
-config.test_format = \
- lit.formats.OneCommandPerFileTest(command=[root.clang,
- '-fsyntax-only'] + cxxflags,
- dir='%s/lib' % root.llvm_src_root,
- recursive=True,
- pattern='^(.*\\.cpp)$')
diff --git a/utils/C++Tests/LLVM-Syntax/lit.local.cfg b/utils/C++Tests/LLVM-Syntax/lit.local.cfg
deleted file mode 100644
index cb0e566..0000000
--- a/utils/C++Tests/LLVM-Syntax/lit.local.cfg
+++ /dev/null
@@ -1,24 +0,0 @@
-# -*- Python -*-
-
-# Configuration file for the 'lit' test runner.
-
-def getRoot(config):
- if not config.parent:
- return config
- return getRoot(config.parent)
-
-root = getRoot(config)
-
-# testFormat: The test format to use to interpret tests.
-config.test_format = lit.formats.SyntaxCheckTest(compiler=root.clang,
- dir='%s/include/llvm' % root.llvm_src_root,
- recursive=True,
- pattern='^(.*\\.h|[^.]*)$',
- extra_cxx_args=['-D__STDC_LIMIT_MACROS',
- '-D__STDC_CONSTANT_MACROS',
- '-Werror',
- '-I%s/include' % root.llvm_src_root,
- '-I%s/include' % root.llvm_obj_root])
-
-config.excludes = ['AbstractTypeUser.h', 'DAGISelHeader.h',
- 'AIXDataTypesFix.h', 'Solaris.h']
diff --git a/utils/C++Tests/lit.cfg b/utils/C++Tests/lit.cfg
deleted file mode 100644
index 274ca10..0000000
--- a/utils/C++Tests/lit.cfg
+++ /dev/null
@@ -1,27 +0,0 @@
-# -*- Python -*-
-
-# Configuration file for the 'lit' test runner.
-
-# Load the main clang test config so we can leech its clang finding logic.
-lit.load_config(config, os.path.join(os.path.dirname(__file__),
- '..', '..', 'test', 'lit.cfg'))
-assert config.clang, "Failed to set clang!?"
-
-# name: The name of this test suite.
-config.name = 'Clang++'
-
-# suffixes: A list of file extensions to treat as test files, this is actually
-# set by on_clone().
-config.suffixes = []
-
-# Reset these from the Clang config.
-config.test_source_root = config.test_exec_root = None
-
-# Don't run Clang and LLVM code checks by default.
-config.excludes = []
-if not lit.params.get('run_clang_all'):
- config.excludes.append('Clang-Code-Syntax')
- config.excludes.append('Clang-Code-Compile')
- config.excludes.append('LLVM-Code-Syntax')
- config.excludes.append('LLVM-Code-Compile')
- config.excludes.append('LLVM-Code-Symbols')
diff --git a/utils/C++Tests/stdc++-Syntax/lit.local.cfg b/utils/C++Tests/stdc++-Syntax/lit.local.cfg
deleted file mode 100644
index eb04866..0000000
--- a/utils/C++Tests/stdc++-Syntax/lit.local.cfg
+++ /dev/null
@@ -1,17 +0,0 @@
-# -*- Python -*-
-
-# Configuration file for the 'lit' test runner.
-
-def getRoot(config):
- if not config.parent:
- return config
- return getRoot(config.parent)
-
-root = getRoot(config)
-
-# testFormat: The test format to use to interpret tests.
-config.test_format = lit.formats.SyntaxCheckTest(compiler=root.clang,
- dir='/usr/include/c++/4.2.1',
- recursive=False,
- pattern='^(.*\\.h|[^.]*)$')
-
diff --git a/utils/ClangDataFormat.py b/utils/ClangDataFormat.py
index ec44d2a..38ef76b 100644
--- a/utils/ClangDataFormat.py
+++ b/utils/ClangDataFormat.py
@@ -16,38 +16,86 @@ After that, instead of getting this:
you'll get:
(lldb) p Tok.Loc
-(clang::SourceLocation) $4 = "/usr/include/i386/_types.h:37:1" (offset: 123582, file)
+(clang::SourceLocation) $4 = "/usr/include/i386/_types.h:37:1" (offset: 123582, file, local)
"""
import lldb
def __lldb_init_module(debugger, internal_dict):
debugger.HandleCommand("type summary add -F ClangDataFormat.SourceLocation_summary clang::SourceLocation")
+ debugger.HandleCommand("type summary add -F ClangDataFormat.QualType_summary clang::QualType")
+ debugger.HandleCommand("type summary add -F ClangDataFormat.StringRef_summary llvm::StringRef")
def SourceLocation_summary(srcloc, internal_dict):
return SourceLocation(srcloc).summary()
+def QualType_summary(qualty, internal_dict):
+ return QualType(qualty).summary()
+
+def StringRef_summary(strref, internal_dict):
+ return StringRef(strref).summary()
+
class SourceLocation(object):
def __init__(self, srcloc):
self.srcloc = srcloc
+ self.ID = srcloc.GetChildAtIndex(0).GetValueAsUnsigned()
+ self.frame = srcloc.GetFrame()
def offset(self):
return getValueFromExpression(self.srcloc, ".getOffset()").GetValueAsUnsigned()
+ def isInvalid(self):
+ return self.ID == 0
+
def isMacro(self):
return getValueFromExpression(self.srcloc, ".isMacroID()").GetValueAsUnsigned()
+ def isLocal(self, srcmgr_path):
+ return self.frame.EvaluateExpression("(%s).isLocalSourceLocation(%s)" % (srcmgr_path, getExpressionPath(self.srcloc))).GetValueAsUnsigned()
+
def getPrint(self, srcmgr_path):
print_str = getValueFromExpression(self.srcloc, ".printToString(%s)" % srcmgr_path)
return print_str.GetSummary()
def summary(self):
- desc = "(offset: %d, %s)" % (self.offset(), "macro" if self.isMacro() else "file")
- srcmgr_path = findObjectExpressionPath("clang::SourceManager", lldb.frame)
+ if self.isInvalid():
+ return "<invalid loc>"
+ srcmgr_path = findObjectExpressionPath("clang::SourceManager", self.frame)
if srcmgr_path:
- desc = self.getPrint(srcmgr_path) + " " + desc
+ return "%s (offset: %d, %s, %s)" % (self.getPrint(srcmgr_path), self.offset(), "macro" if self.isMacro() else "file", "local" if self.isLocal(srcmgr_path) else "loaded")
+ return "(offset: %d, %s)" % (self.offset(), "macro" if self.isMacro() else "file")
+
+class QualType(object):
+ def __init__(self, qualty):
+ self.qualty = qualty
+
+ def getAsString(self):
+ std_str = getValueFromExpression(self.qualty, ".getAsString()")
+ return std_str.GetSummary()
+
+ def summary(self):
+ desc = self.getAsString()
+ if desc == '"NULL TYPE"':
+ return "<NULL TYPE>"
return desc
+class StringRef(object):
+ def __init__(self, strref):
+ self.strref = strref
+ self.Data_value = strref.GetChildAtIndex(0)
+ self.Length = strref.GetChildAtIndex(1).GetValueAsUnsigned()
+
+ def summary(self):
+ if self.Length == 0:
+ return '""'
+ data = self.Data_value.GetPointeeData(0, self.Length)
+ error = lldb.SBError()
+ string = data.ReadRawData(error, 0, data.GetByteSize())
+ if error.Fail():
+ return None
+ return '"%s"' % string
+
+
# Key is a (function address, type name) tuple, value is the expression path for
# an object with such a type name from inside that function.
FramePathMapCache = {}
@@ -105,7 +153,7 @@ def findObject(typename, frame):
return found if not found.TypeIsPointerType() else found.Dereference()
def getValueFromExpression(val, expr):
- return lldb.frame.EvaluateExpression(getExpressionPath(val) + expr)
+ return val.GetFrame().EvaluateExpression(getExpressionPath(val) + expr)
def getExpressionPath(val):
stream = lldb.SBStream()
diff --git a/utils/OptionalTests/Extra/README.txt b/utils/OptionalTests/Extra/README.txt
deleted file mode 100644
index 565241b..0000000
--- a/utils/OptionalTests/Extra/README.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-This directory is for extra unit style tests following the structure of
-clang/tests, but which are not portable or not suitable for inclusion in the
-regular test suite.
diff --git a/utils/OptionalTests/Extra/Runtime/darwin-clang_rt.c b/utils/OptionalTests/Extra/Runtime/darwin-clang_rt.c
deleted file mode 100644
index e527789..0000000
--- a/utils/OptionalTests/Extra/Runtime/darwin-clang_rt.c
+++ /dev/null
@@ -1,338 +0,0 @@
-/* This file tests that we can successfully call each compiler-rt function. It is
- designed to check that the runtime libraries are available for linking and
- that they contain the expected contents. It is not designed to test the
- correctness of the individual functions in compiler-rt.
-
- This test is assumed to be run on a 10.6 machine. The two environment
- variables below should be set to 10.4 and 10.5 machines which can be directly
- ssh/rsync'd to in order to actually test the executables can run on the
- desired targets.
-*/
-
-// RUN: export TENFOUR_X86_MACHINE=localhost
-// RUN: export TENFIVE_X86_MACHINE=localhost
-// RUN: export ARM_MACHINE=localhost
-// RUN: export ARM_SYSROOT=$(xcodebuild -sdk iphoneos -version Path)
-
-// RUN: echo iPhoneOS, ARM, v6, thumb
-// RUN: %clang -isysroot $ARM_SYSROOT -arch armv6 -mthumb -c %s -o %t.o
-// RUN: %clang -isysroot $ARM_SYSROOT -arch armv6 -mthumb -v -Wl,-t,-v -o %t %t.o 1>&2
-// RUN: rsync -arv %t $ARM_MACHINE:/tmp/a.out
-// RUN: ssh $ARM_MACHINE /tmp/a.out
-// RUN: echo
-
-// RUN: echo iPhoneOS, ARM, v6, no-thumb
-// RUN: %clang -isysroot $ARM_SYSROOT -arch armv6 -mno-thumb -c %s -o %t.o
-// RUN: %clang -isysroot $ARM_SYSROOT -arch armv6 -mno-thumb -v -Wl,-t,-v -o %t %t.o 1>&2
-// RUN: rsync -arv %t $ARM_MACHINE:/tmp/a.out
-// RUN: ssh $ARM_MACHINE /tmp/a.out
-// RUN: echo
-
-// RUN: echo iPhoneOS, ARM, v7, thumb
-// RUN: %clang -isysroot $ARM_SYSROOT -arch armv7 -mthumb -c %s -o %t.o
-// RUN: %clang -isysroot $ARM_SYSROOT -arch armv7 -mthumb -v -Wl,-t,-v -o %t %t.o 1>&2
-// RUN: rsync -arv %t $ARM_MACHINE:/tmp/a.out
-// RUN: ssh $ARM_MACHINE /tmp/a.out
-// RUN: echo
-
-// RUN: echo iPhoneOS, ARM, v7, no-thumb
-// RUN: %clang -isysroot $ARM_SYSROOT -arch armv7 -mno-thumb -c %s -o %t.o
-// RUN: %clang -isysroot $ARM_SYSROOT -arch armv7 -mno-thumb -v -Wl,-t,-v -o %t %t.o 1>&2
-// RUN: rsync -arv %t $ARM_MACHINE:/tmp/a.out
-// RUN: ssh $ARM_MACHINE /tmp/a.out
-// RUN: echo
-
-// RUN: echo 10.4, i386
-// RUN: %clang -arch i386 -mmacosx-version-min=10.4 -c %s -o %t.o
-// RUN: %clang -arch i386 -mmacosx-version-min=10.4 -v -Wl,-t,-v -o %t %t.o 1>&2
-// RUN: %t
-// RUN: echo
-
-// RUN: rsync -arv %t $TENFOUR_X86_MACHINE:/tmp/a.out
-// RUN: ssh $TENFOUR_X86_MACHINE /tmp/a.out
-// RUN: echo
-
-// RUX: rsync -arv %t $TENFIVE_X86_MACHINE:/tmp/a.out
-// RUX: ssh $TENFIVE_X86_MACHINE /tmp/a.out
-// RUN: echo
-
-// RUN: echo 10.5, i386
-// RUN: %clang -arch i386 -mmacosx-version-min=10.5 -c %s -o %t.o
-// RUN: %clang -arch i386 -mmacosx-version-min=10.5 -v -Wl,-t,-v -o %t %t.o 1>&2
-// RUN: %t
-// RUN: echo
-
-// RUN: rsync -arv %t $TENFIVE_X86_MACHINE:/tmp/a.out
-// RUN: ssh $TENFIVE_X86_MACHINE /tmp/a.out
-// RUN: echo
-
-// RUN: echo 10.6, i386
-// RUN: %clang -arch i386 -mmacosx-version-min=10.6 -c %s -o %t.o
-// RUN: %clang -arch i386 -mmacosx-version-min=10.6 -v -Wl,-t,-v -o %t %t.o 1>&2
-// RUN: %t
-// RUN: echo
-
-// RUN: echo 10.4, x86_64
-// RUN: %clang -arch x86_64 -mmacosx-version-min=10.4 -c %s -o %t.o
-// RUN: %clang -arch x86_64 -mmacosx-version-min=10.4 -v -Wl,-t,-v -o %t %t.o 1>&2
-// RUN: %t
-// RUN: echo
-
-// RUN: rsync -arv %t $TENFOUR_X86_MACHINE:/tmp/a.out
-// RUN: ssh $TENFOUR_X86_MACHINE /tmp/a.out
-// RUN: echo
-
-// RUN: rsync -arv %t $TENFIVE_X86_MACHINE:/tmp/a.out
-// RUN: ssh $TENFIVE_X86_MACHINE /tmp/a.out
-// RUN: echo
-
-// RUN: echo 10.5, x86_64
-// RUN: %clang -arch x86_64 -mmacosx-version-min=10.5 -c %s -o %t.o
-// RUN: %clang -arch x86_64 -mmacosx-version-min=10.5 -v -Wl,-t,-v -o %t %t.o 1>&2
-// RUN: %t
-// RUN: echo
-
-// RUN: rsync -arv %t $TENFIVE_X86_MACHINE:/tmp/a.out
-// RUN: ssh $TENFIVE_X86_MACHINE /tmp/a.out
-// RUN: echo
-
-// RUN: echo 10.6, x86_64
-// RUN: %clang -arch x86_64 -mmacosx-version-min=10.6 -c %s -o %t.o
-// RUN: %clang -arch x86_64 -mmacosx-version-min=10.6 -v -Wl,-t,-v -o %t %t.o 1>&2
-// RUN: %t
-// RUN: echo
-
-#include <assert.h>
-#include <stdio.h>
-#include <sys/utsname.h>
-
-typedef int si_int;
-typedef unsigned su_int;
-
-typedef long long di_int;
-typedef unsigned long long du_int;
-
-// Integral bit manipulation
-
-di_int __ashldi3(di_int a, si_int b); // a << b
-di_int __ashrdi3(di_int a, si_int b); // a >> b arithmetic (sign fill)
-di_int __lshrdi3(di_int a, si_int b); // a >> b logical (zero fill)
-
-si_int __clzsi2(si_int a); // count leading zeros
-si_int __clzdi2(di_int a); // count leading zeros
-si_int __ctzsi2(si_int a); // count trailing zeros
-si_int __ctzdi2(di_int a); // count trailing zeros
-
-si_int __ffsdi2(di_int a); // find least significant 1 bit
-
-si_int __paritysi2(si_int a); // bit parity
-si_int __paritydi2(di_int a); // bit parity
-
-si_int __popcountsi2(si_int a); // bit population
-si_int __popcountdi2(di_int a); // bit population
-
-// Integral arithmetic
-
-di_int __negdi2 (di_int a); // -a
-di_int __muldi3 (di_int a, di_int b); // a * b
-di_int __divdi3 (di_int a, di_int b); // a / b signed
-du_int __udivdi3 (du_int a, du_int b); // a / b unsigned
-di_int __moddi3 (di_int a, di_int b); // a % b signed
-du_int __umoddi3 (du_int a, du_int b); // a % b unsigned
-du_int __udivmoddi4(du_int a, du_int b, du_int* rem); // a / b, *rem = a % b
-
-// Integral arithmetic with trapping overflow
-
-si_int __absvsi2(si_int a); // abs(a)
-di_int __absvdi2(di_int a); // abs(a)
-
-si_int __negvsi2(si_int a); // -a
-di_int __negvdi2(di_int a); // -a
-
-si_int __addvsi3(si_int a, si_int b); // a + b
-di_int __addvdi3(di_int a, di_int b); // a + b
-
-si_int __subvsi3(si_int a, si_int b); // a - b
-di_int __subvdi3(di_int a, di_int b); // a - b
-
-si_int __mulvsi3(si_int a, si_int b); // a * b
-di_int __mulvdi3(di_int a, di_int b); // a * b
-
-// Integral comparison: a < b -> 0
-// a == b -> 1
-// a > b -> 2
-
-si_int __cmpdi2 (di_int a, di_int b);
-si_int __ucmpdi2(du_int a, du_int b);
-
-// Integral / floating point conversion
-
-di_int __fixsfdi( float a);
-di_int __fixdfdi( double a);
-di_int __fixxfdi(long double a);
-
-su_int __fixunssfsi( float a);
-su_int __fixunsdfsi( double a);
-su_int __fixunsxfsi(long double a);
-
-du_int __fixunssfdi( float a);
-du_int __fixunsdfdi( double a);
-du_int __fixunsxfdi(long double a);
-
-float __floatdisf(di_int a);
-double __floatdidf(di_int a);
-long double __floatdixf(di_int a);
-
-float __floatundisf(du_int a);
-double __floatundidf(du_int a);
-long double __floatundixf(du_int a);
-
-// Floating point raised to integer power
-
-float __powisf2( float a, si_int b); // a ^ b
-double __powidf2( double a, si_int b); // a ^ b
-long double __powixf2(long double a, si_int b); // a ^ b
-
-// Complex arithmetic
-
-// (a + ib) * (c + id)
-
- float _Complex __mulsc3( float a, float b, float c, float d);
- double _Complex __muldc3(double a, double b, double c, double d);
-long double _Complex __mulxc3(long double a, long double b,
- long double c, long double d);
-
-// (a + ib) / (c + id)
-
- float _Complex __divsc3( float a, float b, float c, float d);
- double _Complex __divdc3(double a, double b, double c, double d);
-long double _Complex __divxc3(long double a, long double b,
- long double c, long double d);
-
-#ifndef __arm
-#define HAS_LONG_DOUBLE
-#endif
-
-int main(int argc, char **argv) {
- du_int du_tmp;
- struct utsname name;
-#ifdef __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
- const char *target_name = "OS X";
- unsigned target_version = __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__;
- unsigned target_maj = target_version / 100;
- unsigned target_min = (target_version / 10) % 10;
- unsigned target_micro = target_version % 10;
-#else
- const char *target_name = "iPhoneOS";
- unsigned target_version = __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__;
- unsigned target_maj = target_version / 10000;
- unsigned target_min = (target_version / 100) % 100;
- unsigned target_micro = target_version % 100;
-#endif
-
- if (uname(&name))
- return 1;
-
- fprintf(stderr, "%s: clang_rt test:\n", argv[0]);
- fprintf(stderr, " target : %s %d.%d.%d\n\n", target_name,
- target_maj, target_min, target_micro);
- fprintf(stderr, " sysname : %s\n", name.sysname);
- fprintf(stderr, " nodename: %s\n", name.nodename);
- fprintf(stderr, " release : %s\n", name.release);
- fprintf(stderr, " version : %s\n", name.version);
- fprintf(stderr, " machine : %s\n", name.machine);
-
- assert(__ashldi3(1, 1) == 2);
- assert(__ashrdi3(2, 1) == 1);
- assert(__lshrdi3(2, 1) == 1);
- assert(__clzsi2(1) == 31);
- assert(__clzdi2(1) == 63);
- assert(__ctzsi2(2) == 1);
- assert(__ctzdi2(2) == 1);
- assert(__ffsdi2(12) == 3);
- assert(__paritysi2(13) == 1);
- assert(__paritydi2(13) == 1);
- assert(__popcountsi2(13) == 3);
- assert(__popcountdi2(13) == 3);
- assert(__negdi2(3) == -3);
- assert(__muldi3(2,2) == 4);
- assert(__divdi3(-4,2) == -2);
- assert(__udivdi3(4,2) == 2);
- assert(__moddi3(3,2) == 1);
- assert(__umoddi3(3,2) == 1);
- assert(__udivmoddi4(5,2,&du_tmp) == 2 && du_tmp == 1);
- assert(__absvsi2(-2) == 2);
- assert(__absvdi2(-2) == 2);
- assert(__negvsi2(2) == -2);
- assert(__negvdi2(2) == -2);
- assert(__addvsi3(2, 3) == 5);
- assert(__addvdi3(2, 3) == 5);
- assert(__subvsi3(2, 3) == -1);
- assert(__subvdi3(2, 3) == -1);
- assert(__mulvsi3(2, 3) == 6);
- assert(__mulvdi3(2, 3) == 6);
- assert(__cmpdi2(3, 2) == 2);
- assert(__ucmpdi2(3, 2) == 2);
- assert(__fixsfdi(2.0) == 2);
- assert(__fixdfdi(2.0) == 2);
- assert(__fixunssfsi(2.0) == 2);
- assert(__fixunsdfsi(2.0) == 2);
- assert(__fixunssfdi(2.0) == 2);
- assert(__fixunsdfdi(2.0) == 2);
- assert(__floatdisf(2) == 2.0);
- assert(__floatdidf(2) == 2.0);
- assert(__floatundisf(2) == 2.0);
- assert(__floatundidf(2) == 2.0);
- assert(__powisf2(2.0, 2) == 4.0);
- assert(__powidf2(2.0, 2) == 4.0);
-
- // FIXME: Clang/LLVM seems to be miscompiling _Complex currently, probably an
- // ABI issue.
-#ifndef __arm
- {
- _Complex float a = __mulsc3(1.0, 2.0, 4.0, 8.0);
- _Complex float b = (-12.0 + 16.0j);
- fprintf(stderr, "a: (%f + %f), b: (%f + %f)\n",
- __real a, __imag a, __real b, __imag b);
- }
- assert(__mulsc3(1.0, 2.0, 4.0, 8.0) == (-12.0 + 16.0j));
- assert(__muldc3(1.0, 2.0, 4.0, 8.0) == (-12.0 + 16.0j));
- assert(__divsc3(1.0, 2.0, 4.0, 8.0) == (0.25 + 0j));
- assert(__divdc3(1.0, 2.0, 4.0, 8.0) == (0.25 + 0j));
-#endif
-
-#ifdef HAS_LONG_DOUBLE
- assert(__divxc3(1.0, 2.0, 4.0, 8.0) == (0.25 + 0j));
- assert(__fixunsxfdi(2.0) == 2);
- assert(__fixunsxfsi(2.0) == 2);
- assert(__fixxfdi(2.0) == 2);
- assert(__floatdixf(2) == 2.0);
- assert(__floatundixf(2) == 2);
- assert(__mulxc3(1.0, 2.0, 4.0, 8.0) == (-12.0 + 16.0j));
- assert(__powixf2(2.0, 2) == 4.0);
-#endif
-
- // Test some calls which are used on armv6/thumb. The calls/prototypes are
- // fake, it would be nice to test correctness, but mostly we just want to
- // make sure we resolve symbols correctly.
-#if defined(__arm) && defined(__ARM_ARCH_6K__) && defined(__thumb__)
- if (argc == 100) {
- extern void __restore_vfp_d8_d15_regs(void), __save_vfp_d8_d15_regs(void);
- extern void __switch8(void), __switchu8(void),
- __switch16(void), __switch32(void);
- extern void __addsf3vfp(void);
-
- __addsf3vfp();
- __restore_vfp_d8_d15_regs();
- __save_vfp_d8_d15_regs();
- __switch8();
- __switchu8();
- __switch16();
- __switch32();
- }
-#endif
-
- fprintf(stderr, " OK!\n");
-
- return 0;
-}
diff --git a/utils/OptionalTests/README.txt b/utils/OptionalTests/README.txt
deleted file mode 100644
index 4ffdb3b..0000000
--- a/utils/OptionalTests/README.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a dumping ground for additional tests which do not fit cleanly into the
-clang regression tests. For example, tests which are not portable, require
-additional software or configuration, take an excessive time to run, or are
-flaky can be kept here.
diff --git a/utils/OptionalTests/lit.cfg b/utils/OptionalTests/lit.cfg
deleted file mode 100644
index 592c424..0000000
--- a/utils/OptionalTests/lit.cfg
+++ /dev/null
@@ -1,26 +0,0 @@
-# -*- Python -*-
-
-# Configuration file for the 'lit' test runner.
-
-# Load the main clang test config so we can leech its clang finding logic.
-lit.load_config(config, os.path.join(os.path.dirname(__file__),
- '..', '..', 'test', 'lit.cfg'))
-assert config.clang, "Failed to set clang!?"
-
-# name: The name of this test suite.
-config.name = 'Clang-Opt-Tests'
-
-# suffixes: A list of file extensions to treat as test files.
-config.suffixes = []
-
-# Reset these from the Clang config.
-
-# test_source_root: The root path where tests are located.
-config.test_source_root = os.path.dirname(__file__)
-
-# test_exec_root: The root path where tests should be run.
-clang_obj_root = getattr(config, 'clang_obj_root', None)
-if clang_obj_root is not None:
- config.test_exec_root = os.path.join(clang_obj_root, 'utils',
- 'OptionalTests')
-
diff --git a/utils/SummarizeErrors b/utils/SummarizeErrors
deleted file mode 100755
index b6e9122..0000000
--- a/utils/SummarizeErrors
+++ /dev/null
@@ -1,117 +0,0 @@
-#!/usr/bin/env python
-
-import os, sys, re
-
-class multidict:
- def __init__(self, elts=()):
- self.data = {}
- for key,value in elts:
- self[key] = value
-
- def __getitem__(self, item):
- return self.data[item]
- def __setitem__(self, key, value):
- if key in self.data:
- self.data[key].append(value)
- else:
- self.data[key] = [value]
- def items(self):
- return self.data.items()
- def values(self):
- return self.data.values()
- def keys(self):
- return self.data.keys()
- def __len__(self):
- return len(self.data)
-
-kDiagnosticRE = re.compile(': (error|warning): (.*)')
-kAssertionRE = re.compile('Assertion failed: (.*, function .*, file .*, line [0-9]+\\.)')
-
-def readInfo(path, opts):
- lastProgress = [-100,0]
- def progress(pos):
- pct = (100. * pos) / (size * 2)
- if (pct - lastProgress[0]) >= 10:
- lastProgress[0] = pct
- print '%d/%d = %.2f%%' % (pos, size*2, pct)
-
- f = open(path)
- data = f.read()
- f.close()
-
- if opts.truncate != -1:
- data = data[:opts.truncate]
-
- size = len(data)
- warnings = multidict()
- errors = multidict()
- for m in kDiagnosticRE.finditer(data):
- progress(m.end())
- if m.group(1) == 'error':
- d = errors
- else:
- d = warnings
- d[m.group(2)] = m
- warnings = warnings.items()
- errors = errors.items()
- assertions = multidict()
- for m in kAssertionRE.finditer(data):
- print '%d/%d = %.2f%%' % (size + m.end(), size, (float(m.end()) / (size*2)) * 100.)
- assertions[m.group(1)] = m
- assertions = assertions.items()
-
- # Manual scan for stack traces
- aborts = multidict()
- if 0:
- prevLine = None
- lnIter = iter(data.split('\n'))
- for ln in lnIter:
- m = kStackDumpLineRE.match(ln)
- if m:
- stack = [m.group(2)]
- for ln in lnIter:
- m = kStackDumpLineRE.match(ln)
- if not m:
- break
- stack.append(m.group(2))
- if prevLine is None or not kAssertionRE.match(prevLine):
- aborts[tuple(stack)] = stack
- prevLine = ln
-
- sections = [
- (warnings, 'Warnings'),
- (errors, 'Errors'),
- (assertions, 'Assertions'),
- (aborts.items(), 'Aborts'),
- ]
-
- if opts.ascending:
- sections.reverse()
-
- for l,title in sections:
- l.sort(key = lambda (a,b): -len(b))
- if l:
- print '-- %d %s (%d kinds) --' % (sum([len(b) for a,b in l]), title, len(l))
- for name,elts in l:
- print '%5d:' % len(elts), name
-
-def main():
- global options
- from optparse import OptionParser
- parser = OptionParser("usage: %prog [options] {inputs}")
- parser.add_option("", "--ascending", dest="ascending",
- help="Print output in ascending order of severity.",
- action="store_true", default=False)
- parser.add_option("", "--truncate", dest="truncate",
- help="Truncate input file (for testing).",
- type=int, action="store", default=-1)
- (opts, args) = parser.parse_args()
-
- if not args:
- parser.error('No inputs specified')
-
- for arg in args:
- readInfo(arg, opts)
-
-if __name__=='__main__':
- main()
diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt
index 534ac9a..a858a21 100644
--- a/utils/TableGen/CMakeLists.txt
+++ b/utils/TableGen/CMakeLists.txt
@@ -4,6 +4,7 @@ add_tablegen(clang-tblgen CLANG
ClangASTNodesEmitter.cpp
ClangAttrEmitter.cpp
ClangCommentCommandInfoEmitter.cpp
+ ClangCommentHTMLNamedCharacterReferenceEmitter.cpp
ClangCommentHTMLTagsEmitter.cpp
ClangDiagnosticsEmitter.cpp
ClangSACheckersEmitter.cpp
diff --git a/utils/TableGen/ClangASTNodesEmitter.cpp b/utils/TableGen/ClangASTNodesEmitter.cpp
index c51ca96..682f9c7 100644
--- a/utils/TableGen/ClangASTNodesEmitter.cpp
+++ b/utils/TableGen/ClangASTNodesEmitter.cpp
@@ -133,6 +133,8 @@ std::pair<Record *, Record *> ClangASTNodesEmitter::EmitNode(
}
void ClangASTNodesEmitter::run(raw_ostream &OS) {
+ emitSourceFileHeader("List of AST nodes of a particular kind", OS);
+
// Write the preamble
OS << "#ifndef ABSTRACT_" << macroName(Root.getName()) << "\n";
OS << "# define ABSTRACT_" << macroName(Root.getName()) << "(Type) Type\n";
@@ -183,6 +185,8 @@ void EmitClangASTNodes(RecordKeeper &RK, raw_ostream &OS,
void EmitClangDeclContext(RecordKeeper &Records, raw_ostream &OS) {
// FIXME: Find a .td file format to allow for this to be represented better.
+ emitSourceFileHeader("List of AST Decl nodes", OS);
+
OS << "#ifndef DECL_CONTEXT\n";
OS << "# define DECL_CONTEXT(DECL)\n";
OS << "#endif\n";
diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp
index 521f604..7c8603f 100644
--- a/utils/TableGen/ClangAttrEmitter.cpp
+++ b/utils/TableGen/ClangAttrEmitter.cpp
@@ -47,7 +47,7 @@ static std::string ReadPCHRecord(StringRef type) {
.EndsWith("Decl *", "GetLocalDeclAs<"
+ std::string(type, 0, type.size()-1) + ">(F, Record[Idx++])")
.Case("QualType", "getLocalType(F, Record[Idx++])")
- .Case("Expr *", "ReadSubExpr()")
+ .Case("Expr *", "ReadExpr(F)")
.Case("IdentifierInfo *", "GetIdentifierInfo(F, Record, Idx)")
.Case("SourceLocation", "ReadSourceLocation(F, Record, Idx)")
.Default("Record[Idx++]");
@@ -125,6 +125,9 @@ namespace {
virtual void writePCHReadDecls(raw_ostream &OS) const = 0;
virtual void writePCHWrite(raw_ostream &OS) const = 0;
virtual void writeValue(raw_ostream &OS) const = 0;
+ virtual void writeDump(raw_ostream &OS) const = 0;
+ virtual void writeDumpChildren(raw_ostream &OS) const {}
+ virtual void writeHasChildren(raw_ostream &OS) const { OS << "false"; }
};
class SimpleArgument : public Argument {
@@ -181,6 +184,28 @@ namespace {
OS << "\" << get" << getUpperName() << "() << \"";
}
}
+ void writeDump(raw_ostream &OS) const {
+ if (type == "FunctionDecl *") {
+ OS << " OS << \" \";\n";
+ OS << " dumpBareDeclRef(SA->get" << getUpperName() << "());\n";
+ } else if (type == "IdentifierInfo *") {
+ OS << " OS << \" \" << SA->get" << getUpperName()
+ << "()->getName();\n";
+ } else if (type == "QualType") {
+ OS << " OS << \" \" << SA->get" << getUpperName()
+ << "().getAsString();\n";
+ } else if (type == "SourceLocation") {
+ OS << " OS << \" \";\n";
+ OS << " SA->get" << getUpperName() << "().print(OS, *SM);\n";
+ } else if (type == "bool") {
+ OS << " if (SA->get" << getUpperName() << "()) OS << \" "
+ << getUpperName() << "\";\n";
+ } else if (type == "int" || type == "unsigned") {
+ OS << " OS << \" \" << SA->get" << getUpperName() << "();\n";
+ } else {
+ llvm_unreachable("Unknown SimpleArgument type!");
+ }
+ }
};
class StringArgument : public Argument {
@@ -241,6 +266,10 @@ namespace {
void writeValue(raw_ostream &OS) const {
OS << "\\\"\" << get" << getUpperName() << "() << \"\\\"";
}
+ void writeDump(raw_ostream &OS) const {
+ OS << " OS << \" \\\"\" << SA->get" << getUpperName()
+ << "() << \"\\\"\";\n";
+ }
};
class AlignedArgument : public Argument {
@@ -353,6 +382,19 @@ namespace {
<< " " << getLowerName() << "Expr->printPretty(OS, 0, Policy);\n"
<< " OS << \"";
}
+ void writeDump(raw_ostream &OS) const {
+ }
+ void writeDumpChildren(raw_ostream &OS) const {
+ OS << " if (SA->is" << getUpperName() << "Expr()) {\n";
+ OS << " lastChild();\n";
+ OS << " dumpStmt(SA->get" << getUpperName() << "Expr());\n";
+ OS << " } else\n";
+ OS << " dumpType(SA->get" << getUpperName()
+ << "Type()->getType());\n";
+ }
+ void writeHasChildren(raw_ostream &OS) const {
+ OS << "SA->is" << getUpperName() << "Expr()";
+ }
};
class VariadicArgument : public Argument {
@@ -408,7 +450,7 @@ namespace {
}
void writePCHReadDecls(raw_ostream &OS) const {
OS << " unsigned " << getLowerName() << "Size = Record[Idx++];\n";
- OS << " llvm::SmallVector<" << type << ", 4> " << getLowerName()
+ OS << " SmallVector<" << type << ", 4> " << getLowerName()
<< ";\n";
OS << " " << getLowerName() << ".reserve(" << getLowerName()
<< "Size);\n";
@@ -439,17 +481,30 @@ namespace {
<< " }\n";
OS << " OS << \"";
}
+ void writeDump(raw_ostream &OS) const {
+ OS << " for (" << getAttrName() << "Attr::" << getLowerName()
+ << "_iterator I = SA->" << getLowerName() << "_begin(), E = SA->"
+ << getLowerName() << "_end(); I != E; ++I)\n";
+ OS << " OS << \" \" << *I;\n";
+ }
};
class EnumArgument : public Argument {
std::string type;
- std::vector<StringRef> values, enums;
+ std::vector<StringRef> values, enums, uniques;
public:
EnumArgument(Record &Arg, StringRef Attr)
: Argument(Arg, Attr), type(Arg.getValueAsString("Type")),
values(getValueAsListOfStrings(Arg, "Values")),
- enums(getValueAsListOfStrings(Arg, "Enums"))
- {}
+ enums(getValueAsListOfStrings(Arg, "Enums")),
+ uniques(enums)
+ {
+ // Calculate the various enum values
+ std::sort(uniques.begin(), uniques.end());
+ uniques.erase(std::unique(uniques.begin(), uniques.end()), uniques.end());
+ // FIXME: Emit a proper error
+ assert(!uniques.empty());
+ }
void writeAccessors(raw_ostream &OS) const {
OS << " " << type << " get" << getUpperName() << "() const {\n";
@@ -469,16 +524,8 @@ namespace {
OS << type << " " << getUpperName();
}
void writeDeclarations(raw_ostream &OS) const {
- // Calculate the various enum values
- std::vector<StringRef> uniques(enums);
- std::sort(uniques.begin(), uniques.end());
- uniques.erase(std::unique(uniques.begin(), uniques.end()),
- uniques.end());
- // FIXME: Emit a proper error
- assert(!uniques.empty());
-
- std::vector<StringRef>::iterator i = uniques.begin(),
- e = uniques.end();
+ std::vector<StringRef>::const_iterator i = uniques.begin(),
+ e = uniques.end();
// The last one needs to not have a comma.
--e;
@@ -505,6 +552,16 @@ namespace {
void writeValue(raw_ostream &OS) const {
OS << "\" << get" << getUpperName() << "() << \"";
}
+ void writeDump(raw_ostream &OS) const {
+ OS << " switch(SA->get" << getUpperName() << "()) {\n";
+ for (std::vector<StringRef>::const_iterator I = uniques.begin(),
+ E = uniques.end(); I != E; ++I) {
+ OS << " case " << getAttrName() << "Attr::" << *I << ":\n";
+ OS << " OS << \" " << *I << "\";\n";
+ OS << " break;\n";
+ }
+ OS << " }\n";
+ }
};
class VersionArgument : public Argument {
@@ -552,6 +609,9 @@ namespace {
void writeValue(raw_ostream &OS) const {
OS << getLowerName() << "=\" << get" << getUpperName() << "() << \"";
}
+ void writeDump(raw_ostream &OS) const {
+ OS << " OS << \" \" << SA->get" << getUpperName() << "();\n";
+ }
};
class ExprArgument : public SimpleArgument {
@@ -575,6 +635,15 @@ namespace {
<< "Result.takeAs<Expr>();\n";
OS << " }\n";
}
+
+ void writeDump(raw_ostream &OS) const {
+ }
+
+ void writeDumpChildren(raw_ostream &OS) const {
+ OS << " lastChild();\n";
+ OS << " dumpStmt(SA->get" << getUpperName() << "());\n";
+ }
+ void writeHasChildren(raw_ostream &OS) const { OS << "true"; }
};
class VariadicExprArgument : public VariadicArgument {
@@ -607,6 +676,24 @@ namespace {
OS << " }\n";
OS << " }\n";
}
+
+ void writeDump(raw_ostream &OS) const {
+ }
+
+ void writeDumpChildren(raw_ostream &OS) const {
+ OS << " for (" << getAttrName() << "Attr::" << getLowerName()
+ << "_iterator I = SA->" << getLowerName() << "_begin(), E = SA->"
+ << getLowerName() << "_end(); I != E; ++I) {\n";
+ OS << " if (I + 1 == E)\n";
+ OS << " lastChild();\n";
+ OS << " dumpStmt(*I);\n";
+ OS << " }\n";
+ }
+
+ void writeHasChildren(raw_ostream &OS) const {
+ OS << "SA->" << getLowerName() << "_begin() != "
+ << "SA->" << getLowerName() << "_end()";
+ }
};
}
@@ -663,11 +750,136 @@ static void writeAvailabilityValue(raw_ostream &OS) {
<< " OS << \"";
}
+static void writePrettyPrintFunction(Record &R, std::vector<Argument*> &Args,
+ raw_ostream &OS) {
+ std::vector<Record*> Spellings = R.getValueAsListOfDefs("Spellings");
+
+ OS << "void " << R.getName() << "Attr::printPretty("
+ << "raw_ostream &OS, const PrintingPolicy &Policy) const {\n";
+
+ if (Spellings.size() == 0) {
+ OS << "}\n\n";
+ return;
+ }
+
+ OS <<
+ " switch (SpellingListIndex) {\n"
+ " default:\n"
+ " llvm_unreachable(\"Unknown attribute spelling!\");\n"
+ " break;\n";
+
+ for (unsigned I = 0; I < Spellings.size(); ++ I) {
+ llvm::SmallString<16> Prefix;
+ llvm::SmallString<8> Suffix;
+ // The actual spelling of the name and namespace (if applicable)
+ // of an attribute without considering prefix and suffix.
+ llvm::SmallString<64> Spelling;
+ std::string Name = Spellings[I]->getValueAsString("Name");
+ std::string Variety = Spellings[I]->getValueAsString("Variety");
+
+ if (Variety == "GNU") {
+ Prefix = " __attribute__((";
+ Suffix = "))";
+ } else if (Variety == "CXX11") {
+ Prefix = " [[";
+ Suffix = "]]";
+ std::string Namespace = Spellings[I]->getValueAsString("Namespace");
+ if (Namespace != "") {
+ Spelling += Namespace;
+ Spelling += "::";
+ }
+ } else if (Variety == "Declspec") {
+ Prefix = " __declspec(";
+ Suffix = ")";
+ } else if (Variety == "Keyword") {
+ Prefix = " ";
+ Suffix = "";
+ } else {
+ llvm_unreachable("Unknown attribute syntax variety!");
+ }
+
+ Spelling += Name;
+
+ OS <<
+ " case " << I << " : {\n"
+ " OS << \"" + Prefix.str() + Spelling.str();
+
+ if (Args.size()) OS << "(";
+ if (Spelling == "availability") {
+ writeAvailabilityValue(OS);
+ } else {
+ for (std::vector<Argument*>::const_iterator I = Args.begin(),
+ E = Args.end(); I != E; ++ I) {
+ if (I != Args.begin()) OS << ", ";
+ (*I)->writeValue(OS);
+ }
+ }
+
+ if (Args.size()) OS << ")";
+ OS << Suffix.str() + "\";\n";
+
+ OS <<
+ " break;\n"
+ " }\n";
+ }
+
+ // End of the switch statement.
+ OS << "}\n";
+ // End of the print function.
+ OS << "}\n\n";
+}
+
+/// \brief Return the index of a spelling in a spelling list.
+static unsigned getSpellingListIndex(const std::vector<Record*> &SpellingList,
+ const Record &Spelling) {
+ assert(SpellingList.size() && "Spelling list is empty!");
+
+ for (unsigned Index = 0; Index < SpellingList.size(); ++Index) {
+ Record *S = SpellingList[Index];
+ if (S->getValueAsString("Variety") != Spelling.getValueAsString("Variety"))
+ continue;
+ if (S->getValueAsString("Variety") == "CXX11" &&
+ S->getValueAsString("Namespace") !=
+ Spelling.getValueAsString("Namespace"))
+ continue;
+ if (S->getValueAsString("Name") != Spelling.getValueAsString("Name"))
+ continue;
+
+ return Index;
+ }
+
+ llvm_unreachable("Unknown spelling!");
+}
+
+static void writeAttrAccessorDefinition(Record &R, raw_ostream &OS) {
+ std::vector<Record*> Accessors = R.getValueAsListOfDefs("Accessors");
+ for (std::vector<Record*>::const_iterator I = Accessors.begin(),
+ E = Accessors.end(); I != E; ++I) {
+ Record *Accessor = *I;
+ std::string Name = Accessor->getValueAsString("Name");
+ std::vector<Record*> Spellings = Accessor->getValueAsListOfDefs(
+ "Spellings");
+ std::vector<Record*> SpellingList = R.getValueAsListOfDefs("Spellings");
+ assert(SpellingList.size() &&
+ "Attribute with empty spelling list can't have accessors!");
+
+ OS << " bool " << Name << "() const { return SpellingListIndex == ";
+ for (unsigned Index = 0; Index < Spellings.size(); ++Index) {
+ OS << getSpellingListIndex(SpellingList, *Spellings[Index]);
+ if (Index != Spellings.size() -1)
+ OS << " ||\n SpellingListIndex == ";
+ else
+ OS << "; }\n";
+ }
+ }
+}
+
namespace clang {
// Emits the class definitions for attributes.
void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
- OS << "// This file is generated by TableGen. Do not edit.\n\n";
+ emitSourceFileHeader("Attribute classes' definitions", OS);
+
OS << "#ifndef LLVM_CLANG_ATTR_CLASSES_INC\n";
OS << "#define LLVM_CLANG_ATTR_CLASSES_INC\n\n";
@@ -711,9 +923,12 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
(*ai)->writeCtorParameters(OS);
OS << "\n";
}
-
+
+ OS << " , ";
+ OS << "unsigned SI = 0\n";
+
OS << " )\n";
- OS << " : " << SuperName << "(attr::" << R.getName() << ", R)\n";
+ OS << " : " << SuperName << "(attr::" << R.getName() << ", R, SI)\n";
for (ai = Args.begin(); ai != ae; ++ai) {
OS << " , ";
@@ -730,9 +945,11 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
OS << " }\n\n";
OS << " virtual " << R.getName() << "Attr *clone (ASTContext &C) const;\n";
- OS << " virtual void printPretty(llvm::raw_ostream &OS,"
+ OS << " virtual void printPretty(raw_ostream &OS,\n"
<< " const PrintingPolicy &Policy) const;\n";
+ writeAttrAccessorDefinition(R, OS);
+
for (ai = Args.begin(); ai != ae; ++ai) {
(*ai)->writeAccessors(OS);
OS << "\n\n";
@@ -756,7 +973,7 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
// Emits the class method definitions for attributes.
void EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
- OS << "// This file is generated by TableGen. Do not edit.\n\n";
+ emitSourceFileHeader("Attribute classes' member function definitions", OS);
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end(), ri, re;
@@ -769,7 +986,6 @@ void EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
continue;
std::vector<Record*> ArgRecords = R.getValueAsListOfDefs("Args");
- std::vector<Record*> Spellings = R.getValueAsListOfDefs("Spellings");
std::vector<Argument*> Args;
for (ri = ArgRecords.begin(), re = ArgRecords.end(); ri != re; ++ri)
Args.push_back(createArgument(**ri, R.getName()));
@@ -784,26 +1000,9 @@ void EmitClangAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
OS << ", ";
(*ai)->writeCloneArgs(OS);
}
- OS << ");\n}\n\n";
+ OS << ", getSpellingListIndex());\n}\n\n";
- OS << "void " << R.getName() << "Attr::printPretty("
- << "llvm::raw_ostream &OS, const PrintingPolicy &Policy) const {\n";
- if (Spellings.begin() != Spellings.end()) {
- std::string Spelling = (*Spellings.begin())->getValueAsString("Name");
- OS << " OS << \" __attribute__((" << Spelling;
- if (Args.size()) OS << "(";
- if (Spelling == "availability") {
- writeAvailabilityValue(OS);
- } else {
- for (ai = Args.begin(); ai != ae; ++ai) {
- if (ai!=Args.begin()) OS <<", ";
- (*ai)->writeValue(OS);
- }
- }
- if (Args.size()) OS << ")";
- OS << "))\";\n";
- }
- OS << "}\n\n";
+ writePrettyPrintFunction(R, Args, OS);
}
}
@@ -830,7 +1029,7 @@ namespace clang {
// Emits the enumeration list for attributes.
void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) {
- OS << "// This file is generated by TableGen. Do not edit.\n\n";
+ emitSourceFileHeader("List of all attributes that Clang recognizes", OS);
OS << "#ifndef LAST_ATTR\n";
OS << "#define LAST_ATTR(NAME) ATTR(NAME)\n";
@@ -853,10 +1052,20 @@ void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) {
" INHERITABLE_PARAM_ATTR(NAME)\n";
OS << "#endif\n\n";
+ OS << "#ifndef MS_INHERITABLE_ATTR\n";
+ OS << "#define MS_INHERITABLE_ATTR(NAME) INHERITABLE_ATTR(NAME)\n";
+ OS << "#endif\n\n";
+
+ OS << "#ifndef LAST_MS_INHERITABLE_ATTR\n";
+ OS << "#define LAST_MS_INHERITABLE_ATTR(NAME)"
+ " MS_INHERITABLE_ATTR(NAME)\n";
+ OS << "#endif\n\n";
+
Record *InhClass = Records.getClass("InheritableAttr");
Record *InhParamClass = Records.getClass("InheritableParamAttr");
+ Record *MSInheritanceClass = Records.getClass("MSInheritanceAttr");
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"),
- NonInhAttrs, InhAttrs, InhParamAttrs;
+ NonInhAttrs, InhAttrs, InhParamAttrs, MSInhAttrs;
for (std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end();
i != e; ++i) {
if (!(*i)->getValueAsBit("ASTNode"))
@@ -864,6 +1073,8 @@ void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) {
if ((*i)->isSubClassOf(InhParamClass))
InhParamAttrs.push_back(*i);
+ else if ((*i)->isSubClassOf(MSInheritanceClass))
+ MSInhAttrs.push_back(*i);
else if ((*i)->isSubClassOf(InhClass))
InhAttrs.push_back(*i);
else
@@ -871,19 +1082,22 @@ void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) {
}
EmitAttrList(OS, "INHERITABLE_PARAM_ATTR", InhParamAttrs);
+ EmitAttrList(OS, "MS_INHERITABLE_ATTR", MSInhAttrs);
EmitAttrList(OS, "INHERITABLE_ATTR", InhAttrs);
EmitAttrList(OS, "ATTR", NonInhAttrs);
OS << "#undef LAST_ATTR\n";
OS << "#undef INHERITABLE_ATTR\n";
+ OS << "#undef MS_INHERITABLE_ATTR\n";
OS << "#undef LAST_INHERITABLE_ATTR\n";
OS << "#undef LAST_INHERITABLE_PARAM_ATTR\n";
+ OS << "#undef LAST_MS_INHERITABLE_ATTR\n";
OS << "#undef ATTR\n";
}
// Emits the code to read an attribute from a precompiled header.
void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS) {
- OS << "// This file is generated by TableGen. Do not edit.\n\n";
+ emitSourceFileHeader("Attribute deserialization code", OS);
Record *InhClass = Records.getClass("InheritableAttr");
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"),
@@ -927,6 +1141,8 @@ void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS) {
// Emits the code to write an attribute to a precompiled header.
void EmitClangAttrPCHWrite(RecordKeeper &Records, raw_ostream &OS) {
+ emitSourceFileHeader("Attribute serialization code", OS);
+
Record *InhClass = Records.getClass("InheritableAttr");
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"), Args;
std::vector<Record*>::iterator i = Attrs.begin(), e = Attrs.end(), ai, ae;
@@ -956,7 +1172,8 @@ void EmitClangAttrPCHWrite(RecordKeeper &Records, raw_ostream &OS) {
// Emits the list of spellings for attributes.
void EmitClangAttrSpellingList(RecordKeeper &Records, raw_ostream &OS) {
- OS << "// This file is generated by TableGen. Do not edit.\n\n";
+ emitSourceFileHeader("llvm::StringSwitch code to match all known attributes",
+ OS);
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
@@ -972,9 +1189,70 @@ void EmitClangAttrSpellingList(RecordKeeper &Records, raw_ostream &OS) {
}
+void EmitClangAttrSpellingListIndex(RecordKeeper &Records, raw_ostream &OS) {
+ emitSourceFileHeader("Code to translate different attribute spellings "
+ "into internal identifiers", OS);
+
+ OS <<
+ " unsigned Index = 0;\n"
+ " switch (AttrKind) {\n"
+ " default:\n"
+ " llvm_unreachable(\"Unknown attribute kind!\");\n"
+ " break;\n";
+
+ std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
+ for (std::vector<Record*>::const_iterator I = Attrs.begin(), E = Attrs.end();
+ I != E; ++I) {
+ Record &R = **I;
+ // We only care about attributes that participate in Sema checking, so
+ // skip those attributes that are not able to make their way to Sema.
+ if (!R.getValueAsBit("SemaHandler"))
+ continue;
+
+ std::vector<Record*> Spellings = R.getValueAsListOfDefs("Spellings");
+ // Each distinct spelling yields an attribute kind.
+ if (R.getValueAsBit("DistinctSpellings")) {
+ for (unsigned I = 0; I < Spellings.size(); ++ I) {
+ OS <<
+ " case AT_" << Spellings[I]->getValueAsString("Name") << ": \n"
+ " Index = " << I << ";\n"
+ " break;\n";
+ }
+ } else {
+ OS << " case AT_" << R.getName() << " : {\n";
+ for (unsigned I = 0; I < Spellings.size(); ++ I) {
+ SmallString<16> Namespace;
+ if (Spellings[I]->getValueAsString("Variety") == "CXX11")
+ Namespace = Spellings[I]->getValueAsString("Namespace");
+ else
+ Namespace = "";
+
+ OS << " if (Name == \""
+ << Spellings[I]->getValueAsString("Name") << "\" && "
+ << "SyntaxUsed == "
+ << StringSwitch<unsigned>(Spellings[I]->getValueAsString("Variety"))
+ .Case("GNU", 0)
+ .Case("CXX11", 1)
+ .Case("Declspec", 2)
+ .Case("Keyword", 3)
+ .Default(0)
+ << " && Scope == \"" << Namespace << "\")\n"
+ << " return " << I << ";\n";
+ }
+
+ OS << " break;\n";
+ OS << " }\n";
+ }
+ }
+
+ OS << " }\n";
+ OS << " return Index;\n";
+}
+
// Emits the LateParsed property for attributes.
void EmitClangAttrLateParsedList(RecordKeeper &Records, raw_ostream &OS) {
- OS << "// This file is generated by TableGen. Do not edit.\n\n";
+ emitSourceFileHeader("llvm::StringSwitch code to match late parsed "
+ "attributes", OS);
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
@@ -1002,7 +1280,7 @@ void EmitClangAttrLateParsedList(RecordKeeper &Records, raw_ostream &OS) {
// Emits code to instantiate dependent attributes on templates.
void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS) {
- OS << "// This file is generated by TableGen. Do not edit.\n\n";
+ emitSourceFileHeader("Template instantiation code for attributes", OS);
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
@@ -1075,8 +1353,8 @@ void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS) {
// Emits the list of parsed attributes.
void EmitClangAttrParsedAttrList(RecordKeeper &Records, raw_ostream &OS) {
- OS << "// This file is generated by TableGen. Do not edit.\n\n";
-
+ emitSourceFileHeader("List of all attributes that Clang recognizes", OS);
+
OS << "#ifndef PARSED_ATTR\n";
OS << "#define PARSED_ATTR(NAME) NAME\n";
OS << "#endif\n\n";
@@ -1113,9 +1391,8 @@ void EmitClangAttrParsedAttrList(RecordKeeper &Records, raw_ostream &OS) {
// Emits the kind list of parsed attributes
void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) {
- OS << "// This file is generated by TableGen. Do not edit.\n\n";
- OS << "\n";
-
+ emitSourceFileHeader("Attribute name matcher", OS);
+
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
std::vector<StringMatcher::StringPair> Matches;
@@ -1163,4 +1440,56 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) {
<< "}\n";
}
+// Emits the code to dump an attribute.
+void EmitClangAttrDump(RecordKeeper &Records, raw_ostream &OS) {
+ emitSourceFileHeader("Attribute dumper", OS);
+
+ OS <<
+ " switch (A->getKind()) {\n"
+ " default:\n"
+ " llvm_unreachable(\"Unknown attribute kind!\");\n"
+ " break;\n";
+ std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr"), Args;
+ for (std::vector<Record*>::iterator I = Attrs.begin(), E = Attrs.end();
+ I != E; ++I) {
+ Record &R = **I;
+ if (!R.getValueAsBit("ASTNode"))
+ continue;
+ OS << " case attr::" << R.getName() << ": {\n";
+ Args = R.getValueAsListOfDefs("Args");
+ if (!Args.empty()) {
+ OS << " const " << R.getName() << "Attr *SA = cast<" << R.getName()
+ << "Attr>(A);\n";
+ for (std::vector<Record*>::iterator I = Args.begin(), E = Args.end();
+ I != E; ++I)
+ createArgument(**I, R.getName())->writeDump(OS);
+
+ // Code for detecting the last child.
+ OS << " bool OldMoreChildren = hasMoreChildren();\n";
+ OS << " bool MoreChildren = OldMoreChildren;\n";
+
+ for (std::vector<Record*>::iterator I = Args.begin(), E = Args.end();
+ I != E; ++I) {
+ // More code for detecting the last child.
+ OS << " MoreChildren = OldMoreChildren";
+ for (std::vector<Record*>::iterator Next = I + 1; Next != E; ++Next) {
+ OS << " || ";
+ createArgument(**Next, R.getName())->writeHasChildren(OS);
+ }
+ OS << ";\n";
+ OS << " setMoreChildren(MoreChildren);\n";
+
+ createArgument(**I, R.getName())->writeDumpChildren(OS);
+ }
+
+ // Reset the last child.
+ OS << " setMoreChildren(OldMoreChildren);\n";
+ }
+ OS <<
+ " break;\n"
+ " }\n";
+ }
+ OS << " }\n";
+}
+
} // end namespace clang
diff --git a/utils/TableGen/ClangCommentCommandInfoEmitter.cpp b/utils/TableGen/ClangCommentCommandInfoEmitter.cpp
index 36fbcd4..ebb0427 100644
--- a/utils/TableGen/ClangCommentCommandInfoEmitter.cpp
+++ b/utils/TableGen/ClangCommentCommandInfoEmitter.cpp
@@ -7,20 +7,22 @@
//
//===----------------------------------------------------------------------===//
//
-// This tablegen backend emits command lists and efficient matchers command
+// This tablegen backend emits command lists and efficient matchers for command
// names that are used in documentation comments.
//
//===----------------------------------------------------------------------===//
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/StringMatcher.h"
+#include "llvm/TableGen/TableGenBackend.h"
#include <vector>
using namespace llvm;
namespace clang {
void EmitClangCommentCommandInfo(RecordKeeper &Records, raw_ostream &OS) {
- OS << "// This file is generated by TableGen. Do not edit.\n\n";
+ emitSourceFileHeader("A list of commands useable in documentation "
+ "comments", OS);
OS << "namespace {\n"
"const CommandInfo Commands[] = {\n";
@@ -39,11 +41,15 @@ void EmitClangCommentCommandInfo(RecordKeeper &Records, raw_ostream &OS) {
<< Tag.getValueAsBit("IsParamCommand") << ", "
<< Tag.getValueAsBit("IsTParamCommand") << ", "
<< Tag.getValueAsBit("IsDeprecatedCommand") << ", "
+ << Tag.getValueAsBit("IsHeaderfileCommand") << ", "
<< Tag.getValueAsBit("IsEmptyParagraphAllowed") << ", "
<< Tag.getValueAsBit("IsVerbatimBlockCommand") << ", "
<< Tag.getValueAsBit("IsVerbatimBlockEndCommand") << ", "
<< Tag.getValueAsBit("IsVerbatimLineCommand") << ", "
<< Tag.getValueAsBit("IsDeclarationCommand") << ", "
+ << Tag.getValueAsBit("IsFunctionDeclarationCommand") << ", "
+ << Tag.getValueAsBit("IsRecordLikeDetailCommand") << ", "
+ << Tag.getValueAsBit("IsRecordLikeDeclarationCommand") << ", "
<< /* IsUnknownCommand = */ "0"
<< " }";
if (i + 1 != e)
@@ -68,5 +74,49 @@ void EmitClangCommentCommandInfo(RecordKeeper &Records, raw_ostream &OS) {
OS << " return NULL;\n"
<< "}\n\n";
}
+
+static std::string MangleName(StringRef Str) {
+ std::string Mangled;
+ for (unsigned i = 0, e = Str.size(); i != e; ++i) {
+ switch (Str[i]) {
+ default:
+ Mangled += Str[i];
+ break;
+ case '[':
+ Mangled += "lsquare";
+ break;
+ case ']':
+ Mangled += "rsquare";
+ break;
+ case '{':
+ Mangled += "lbrace";
+ break;
+ case '}':
+ Mangled += "rbrace";
+ break;
+ case '$':
+ Mangled += "dollar";
+ break;
+ }
+ }
+ return Mangled;
+}
+
+void EmitClangCommentCommandList(RecordKeeper &Records, raw_ostream &OS) {
+ emitSourceFileHeader("A list of commands useable in documentation "
+ "comments", OS);
+
+ OS << "#ifndef COMMENT_COMMAND\n"
+ << "# define COMMENT_COMMAND(NAME)\n"
+ << "#endif\n";
+
+ std::vector<Record *> Tags = Records.getAllDerivedDefinitions("Command");
+ for (size_t i = 0, e = Tags.size(); i != e; ++i) {
+ Record &Tag = *Tags[i];
+ std::string MangledName = MangleName(Tag.getValueAsString("Name"));
+
+ OS << "COMMENT_COMMAND(" << MangledName << ")\n";
+ }
+}
} // end namespace clang
diff --git a/utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp b/utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp
new file mode 100644
index 0000000..bfdb268
--- /dev/null
+++ b/utils/TableGen/ClangCommentHTMLNamedCharacterReferenceEmitter.cpp
@@ -0,0 +1,85 @@
+//===--- ClangCommentHTMLNamedCharacterReferenceEmitter.cpp -----------------=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tablegen backend emits an fficient function to translate HTML named
+// character references to UTF-8 sequences.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/ConvertUTF.h"
+#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/StringMatcher.h"
+#include "llvm/TableGen/TableGenBackend.h"
+#include <vector>
+
+using namespace llvm;
+
+/// \brief Convert a code point to the corresponding UTF-8 sequence represented
+/// as a C string literal.
+///
+/// \returns true on success.
+static bool translateCodePointToUTF8(unsigned CodePoint,
+ SmallVectorImpl<char> &CLiteral) {
+ char Translated[UNI_MAX_UTF8_BYTES_PER_CODE_POINT];
+ char *TranslatedPtr = Translated;
+ if (!ConvertCodePointToUTF8(CodePoint, TranslatedPtr))
+ return false;
+
+ StringRef UTF8(Translated, TranslatedPtr - Translated);
+
+ raw_svector_ostream OS(CLiteral);
+ OS << "\"";
+ for (size_t i = 0, e = UTF8.size(); i != e; ++i) {
+ OS << "\\x";
+ OS.write_hex(static_cast<unsigned char>(UTF8[i]));
+ }
+ OS << "\"";
+
+ return true;
+}
+
+namespace clang {
+void EmitClangCommentHTMLNamedCharacterReferences(RecordKeeper &Records,
+ raw_ostream &OS) {
+ std::vector<Record *> Tags = Records.getAllDerivedDefinitions("NCR");
+ std::vector<StringMatcher::StringPair> NameToUTF8;
+ SmallString<32> CLiteral;
+ for (std::vector<Record *>::iterator I = Tags.begin(), E = Tags.end();
+ I != E; ++I) {
+ Record &Tag = **I;
+ std::string Spelling = Tag.getValueAsString("Spelling");
+ uint64_t CodePoint = Tag.getValueAsInt("CodePoint");
+ CLiteral.clear();
+ CLiteral.append("return ");
+ if (!translateCodePointToUTF8(CodePoint, CLiteral)) {
+ SrcMgr.PrintMessage(Tag.getLoc().front(),
+ SourceMgr::DK_Error,
+ Twine("invalid code point"));
+ continue;
+ }
+ CLiteral.append(";");
+
+ StringMatcher::StringPair Match(Spelling, CLiteral.str());
+ NameToUTF8.push_back(Match);
+ }
+
+ emitSourceFileHeader("HTML named character reference to UTF-8 "
+ "translation", OS);
+
+ OS << "StringRef translateHTMLNamedCharacterReferenceToUTF8(\n"
+ " StringRef Name) {\n";
+ StringMatcher("Name", NameToUTF8, OS).Emit();
+ OS << " return StringRef();\n"
+ << "}\n\n";
+}
+
+} // end namespace clang
+
diff --git a/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp b/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp
index 0ae23b2..bfcd2cf 100644
--- a/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp
+++ b/utils/TableGen/ClangCommentHTMLTagsEmitter.cpp
@@ -14,6 +14,7 @@
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/StringMatcher.h"
+#include "llvm/TableGen/TableGenBackend.h"
#include <vector>
using namespace llvm;
@@ -29,7 +30,7 @@ void EmitClangCommentHTMLTags(RecordKeeper &Records, raw_ostream &OS) {
Matches.push_back(StringMatcher::StringPair(Spelling, "return true;"));
}
- OS << "// This file is generated by TableGen. Do not edit.\n\n";
+ emitSourceFileHeader("HTML tag name matcher", OS);
OS << "bool isHTMLTagName(StringRef Name) {\n";
StringMatcher("Name", Matches, OS).Emit();
@@ -53,7 +54,7 @@ void EmitClangCommentHTMLTagsProperties(RecordKeeper &Records,
MatchesEndTagForbidden.push_back(Match);
}
- OS << "// This file is generated by TableGen. Do not edit.\n\n";
+ emitSourceFileHeader("HTML tag properties", OS);
OS << "bool isHTMLEndTagOptional(StringRef Name) {\n";
StringMatcher("Name", MatchesEndTagOptional, OS).Emit();
diff --git a/utils/TableGen/ClangDiagnosticsEmitter.cpp b/utils/TableGen/ClangDiagnosticsEmitter.cpp
index b1472a8..291eb75 100644
--- a/utils/TableGen/ClangDiagnosticsEmitter.cpp
+++ b/utils/TableGen/ClangDiagnosticsEmitter.cpp
@@ -11,11 +11,15 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/TableGen/Error.h"
@@ -127,14 +131,41 @@ namespace {
std::vector<const Record*> DiagsInGroup;
std::vector<std::string> SubGroups;
unsigned IDNo;
+
+ const Record *ExplicitDef;
+
+ GroupInfo() : ExplicitDef(0) {}
};
} // end anonymous namespace.
+static bool beforeThanCompare(const Record *LHS, const Record *RHS) {
+ assert(!LHS->getLoc().empty() && !RHS->getLoc().empty());
+ return
+ LHS->getLoc().front().getPointer() < RHS->getLoc().front().getPointer();
+}
+
+static bool beforeThanCompareGroups(const GroupInfo *LHS, const GroupInfo *RHS){
+ assert(!LHS->DiagsInGroup.empty() && !RHS->DiagsInGroup.empty());
+ return beforeThanCompare(LHS->DiagsInGroup.front(),
+ RHS->DiagsInGroup.front());
+}
+
+static SMRange findSuperClassRange(const Record *R, StringRef SuperName) {
+ ArrayRef<Record *> Supers = R->getSuperClasses();
+
+ for (size_t i = 0, e = Supers.size(); i < e; ++i)
+ if (Supers[i]->getName() == SuperName)
+ return R->getSuperClassRanges()[i];
+
+ return SMRange();
+}
+
/// \brief Invert the 1-[0/1] mapping of diags to group into a one to many
/// mapping of groups to diags in the group.
static void groupDiagnostics(const std::vector<Record*> &Diags,
const std::vector<Record*> &DiagGroups,
std::map<std::string, GroupInfo> &DiagsInGroup) {
+
for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
const Record *R = Diags[i];
DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group"));
@@ -144,13 +175,25 @@ static void groupDiagnostics(const std::vector<Record*> &Diags,
std::string GroupName = DI->getDef()->getValueAsString("GroupName");
DiagsInGroup[GroupName].DiagsInGroup.push_back(R);
}
-
+
+ typedef SmallPtrSet<GroupInfo *, 16> GroupSetTy;
+ GroupSetTy ImplicitGroups;
+
// Add all DiagGroup's to the DiagsInGroup list to make sure we pick up empty
// groups (these are warnings that GCC supports that clang never produces).
for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) {
Record *Group = DiagGroups[i];
GroupInfo &GI = DiagsInGroup[Group->getValueAsString("GroupName")];
-
+ if (Group->isAnonymous()) {
+ if (GI.DiagsInGroup.size() > 1)
+ ImplicitGroups.insert(&GI);
+ } else {
+ if (GI.ExplicitDef)
+ assert(GI.ExplicitDef == Group);
+ else
+ GI.ExplicitDef = Group;
+ }
+
std::vector<Record*> SubGroups = Group->getValueAsListOfDefs("SubGroups");
for (unsigned j = 0, e = SubGroups.size(); j != e; ++j)
GI.SubGroups.push_back(SubGroups[j]->getValueAsString("GroupName"));
@@ -161,6 +204,80 @@ static void groupDiagnostics(const std::vector<Record*> &Diags,
for (std::map<std::string, GroupInfo>::iterator
I = DiagsInGroup.begin(), E = DiagsInGroup.end(); I != E; ++I, ++IDNo)
I->second.IDNo = IDNo;
+
+ // Sort the implicit groups, so we can warn about them deterministically.
+ SmallVector<GroupInfo *, 16> SortedGroups(ImplicitGroups.begin(),
+ ImplicitGroups.end());
+ for (SmallVectorImpl<GroupInfo *>::iterator I = SortedGroups.begin(),
+ E = SortedGroups.end();
+ I != E; ++I) {
+ MutableArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup;
+ std::sort(GroupDiags.begin(), GroupDiags.end(), beforeThanCompare);
+ }
+ std::sort(SortedGroups.begin(), SortedGroups.end(), beforeThanCompareGroups);
+
+ // Warn about the same group being used anonymously in multiple places.
+ for (SmallVectorImpl<GroupInfo *>::const_iterator I = SortedGroups.begin(),
+ E = SortedGroups.end();
+ I != E; ++I) {
+ ArrayRef<const Record *> GroupDiags = (*I)->DiagsInGroup;
+
+ if ((*I)->ExplicitDef) {
+ std::string Name = (*I)->ExplicitDef->getValueAsString("GroupName");
+ for (ArrayRef<const Record *>::const_iterator DI = GroupDiags.begin(),
+ DE = GroupDiags.end();
+ DI != DE; ++DI) {
+ const DefInit *GroupInit = cast<DefInit>((*DI)->getValueInit("Group"));
+ const Record *NextDiagGroup = GroupInit->getDef();
+ if (NextDiagGroup == (*I)->ExplicitDef)
+ continue;
+
+ SMRange InGroupRange = findSuperClassRange(*DI, "InGroup");
+ SmallString<64> Replacement;
+ if (InGroupRange.isValid()) {
+ Replacement += "InGroup<";
+ Replacement += (*I)->ExplicitDef->getName();
+ Replacement += ">";
+ }
+ SMFixIt FixIt(InGroupRange, Replacement.str());
+
+ SrcMgr.PrintMessage(NextDiagGroup->getLoc().front(),
+ SourceMgr::DK_Error,
+ Twine("group '") + Name +
+ "' is referred to anonymously",
+ ArrayRef<SMRange>(),
+ InGroupRange.isValid() ? FixIt
+ : ArrayRef<SMFixIt>());
+ SrcMgr.PrintMessage((*I)->ExplicitDef->getLoc().front(),
+ SourceMgr::DK_Note, "group defined here");
+ }
+ } else {
+ // If there's no existing named group, we should just warn once and use
+ // notes to list all the other cases.
+ ArrayRef<const Record *>::const_iterator DI = GroupDiags.begin(),
+ DE = GroupDiags.end();
+ assert(DI != DE && "We only care about groups with multiple uses!");
+
+ const DefInit *GroupInit = cast<DefInit>((*DI)->getValueInit("Group"));
+ const Record *NextDiagGroup = GroupInit->getDef();
+ std::string Name = NextDiagGroup->getValueAsString("GroupName");
+
+ SMRange InGroupRange = findSuperClassRange(*DI, "InGroup");
+ SrcMgr.PrintMessage(NextDiagGroup->getLoc().front(),
+ SourceMgr::DK_Error,
+ Twine("group '") + Name +
+ "' is referred to anonymously",
+ InGroupRange);
+
+ for (++DI; DI != DE; ++DI) {
+ GroupInit = cast<DefInit>((*DI)->getValueInit("Group"));
+ InGroupRange = findSuperClassRange(*DI, "InGroup");
+ SrcMgr.PrintMessage(GroupInit->getDef()->getLoc().front(),
+ SourceMgr::DK_Note, "also referenced here",
+ InGroupRange);
+ }
+ }
+ }
}
//===----------------------------------------------------------------------===//
@@ -174,7 +291,7 @@ typedef llvm::PointerUnion<RecordVec*, RecordSet*> VecOrSet;
namespace {
class InferPedantic {
typedef llvm::DenseMap<const Record*,
- std::pair<unsigned, llvm::Optional<unsigned> > > GMap;
+ std::pair<unsigned, Optional<unsigned> > > GMap;
DiagGroupParentMap &DiagGroupParents;
const std::vector<Record*> &Diags;
diff --git a/utils/TableGen/OptParserEmitter.cpp b/utils/TableGen/OptParserEmitter.cpp
index 674c89a..0553b1f 100644
--- a/utils/TableGen/OptParserEmitter.cpp
+++ b/utils/TableGen/OptParserEmitter.cpp
@@ -7,13 +7,12 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/TableGen/Error.h"
-#include "llvm/TableGen/Record.h"
-#include "llvm/TableGen/TableGenBackend.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
-
+#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
#include <map>
using namespace llvm;
diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp
index 41471a4..3df8940 100644
--- a/utils/TableGen/TableGen.cpp
+++ b/utils/TableGen/TableGen.cpp
@@ -12,7 +12,6 @@
//===----------------------------------------------------------------------===//
#include "TableGenBackends.h" // Declares all backends.
-
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
@@ -30,10 +29,12 @@ enum ActionType {
GenClangAttrPCHRead,
GenClangAttrPCHWrite,
GenClangAttrSpellingList,
+ GenClangAttrSpellingListIndex,
GenClangAttrLateParsedList,
GenClangAttrTemplateInstantiate,
GenClangAttrParsedAttrList,
GenClangAttrParsedAttrKinds,
+ GenClangAttrDump,
GenClangDiagsDefs,
GenClangDiagGroups,
GenClangDiagsIndexName,
@@ -43,7 +44,9 @@ enum ActionType {
GenClangSACheckers,
GenClangCommentHTMLTags,
GenClangCommentHTMLTagsProperties,
+ GenClangCommentHTMLNamedCharacterReferences,
GenClangCommentCommandInfo,
+ GenClangCommentCommandList,
GenOptParserDefs, GenOptParserImpl,
GenArmNeon,
GenArmNeonSema,
@@ -70,6 +73,9 @@ namespace {
clEnumValN(GenClangAttrSpellingList,
"gen-clang-attr-spelling-list",
"Generate a clang attribute spelling list"),
+ clEnumValN(GenClangAttrSpellingListIndex,
+ "gen-clang-attr-spelling-index",
+ "Generate a clang attribute spelling index"),
clEnumValN(GenClangAttrLateParsedList,
"gen-clang-attr-late-parsed-list",
"Generate a clang attribute LateParsed list"),
@@ -82,6 +88,8 @@ namespace {
clEnumValN(GenClangAttrParsedAttrKinds,
"gen-clang-attr-parsed-attr-kinds",
"Generate a clang parsed attribute kinds"),
+ clEnumValN(GenClangAttrDump, "gen-clang-attr-dump",
+ "Generate clang attribute dumper"),
clEnumValN(GenClangDiagsDefs, "gen-clang-diags-defs",
"Generate Clang diagnostics definitions"),
clEnumValN(GenClangDiagGroups, "gen-clang-diag-groups",
@@ -105,8 +113,16 @@ namespace {
"gen-clang-comment-html-tags-properties",
"Generate efficient matchers for HTML tag "
"properties"),
+ clEnumValN(GenClangCommentHTMLNamedCharacterReferences,
+ "gen-clang-comment-html-named-character-references",
+ "Generate function to translate named character "
+ "references to UTF-8 sequences"),
clEnumValN(GenClangCommentCommandInfo,
"gen-clang-comment-command-info",
+ "Generate command properties for commands that "
+ "are used in documentation comments"),
+ clEnumValN(GenClangCommentCommandList,
+ "gen-clang-comment-command-list",
"Generate list of commands that are used in "
"documentation comments"),
clEnumValN(GenArmNeon, "gen-arm-neon",
@@ -142,6 +158,9 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenClangAttrSpellingList:
EmitClangAttrSpellingList(Records, OS);
break;
+ case GenClangAttrSpellingListIndex:
+ EmitClangAttrSpellingListIndex(Records, OS);
+ break;
case GenClangAttrLateParsedList:
EmitClangAttrLateParsedList(Records, OS);
break;
@@ -154,6 +173,9 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenClangAttrParsedAttrKinds:
EmitClangAttrParsedAttrKinds(Records, OS);
break;
+ case GenClangAttrDump:
+ EmitClangAttrDump(Records, OS);
+ break;
case GenClangDiagsDefs:
EmitClangDiagsDefs(Records, OS, ClangComponent);
break;
@@ -182,9 +204,15 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenClangCommentHTMLTagsProperties:
EmitClangCommentHTMLTagsProperties(Records, OS);
break;
+ case GenClangCommentHTMLNamedCharacterReferences:
+ EmitClangCommentHTMLNamedCharacterReferences(Records, OS);
+ break;
case GenClangCommentCommandInfo:
EmitClangCommentCommandInfo(Records, OS);
break;
+ case GenClangCommentCommandList:
+ EmitClangCommentCommandList(Records, OS);
+ break;
case GenOptParserDefs:
EmitOptParser(Records, OS, true);
break;
diff --git a/utils/TableGen/TableGenBackends.h b/utils/TableGen/TableGenBackends.h
index 838fc84..03708b6 100644
--- a/utils/TableGen/TableGenBackends.h
+++ b/utils/TableGen/TableGenBackends.h
@@ -35,10 +35,12 @@ void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrPCHRead(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrPCHWrite(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrSpellingList(RecordKeeper &Records, raw_ostream &OS);
+void EmitClangAttrSpellingListIndex(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrLateParsedList(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrParsedAttrList(RecordKeeper &Records, raw_ostream &OS);
void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS);
+void EmitClangAttrDump(RecordKeeper &Records, raw_ostream &OS);
void EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS,
const std::string &Component);
@@ -49,8 +51,10 @@ void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS);
void EmitClangCommentHTMLTags(RecordKeeper &Records, raw_ostream &OS);
void EmitClangCommentHTMLTagsProperties(RecordKeeper &Records, raw_ostream &OS);
+void EmitClangCommentHTMLNamedCharacterReferences(RecordKeeper &Records, raw_ostream &OS);
void EmitClangCommentCommandInfo(RecordKeeper &Records, raw_ostream &OS);
+void EmitClangCommentCommandList(RecordKeeper &Records, raw_ostream &OS);
void EmitNeon(RecordKeeper &Records, raw_ostream &OS);
void EmitNeonSema(RecordKeeper &Records, raw_ostream &OS);
diff --git a/utils/analyzer/CmpRuns.py b/utils/analyzer/CmpRuns.py
index 3ca9b2b..30157be 100755
--- a/utils/analyzer/CmpRuns.py
+++ b/utils/analyzer/CmpRuns.py
@@ -120,9 +120,8 @@ class CmpOptions:
self.verboseLog = verboseLog
class AnalysisReport:
- def __init__(self, run, files, clang_vers):
+ def __init__(self, run, files):
self.run = run
- self.clang_version = clang_vers
self.files = files
self.diagnostics = []
@@ -134,32 +133,28 @@ class AnalysisRun:
self.reports = []
# Cumulative list of all diagnostics from all the reports.
self.diagnostics = []
-
-
-# Backward compatibility API.
-def loadResults(path, opts, root = "", deleteEmpty=True):
- return loadResultsFromSingleRun(SingleRunInfo(path, root, opts.verboseLog),
- deleteEmpty)
-
-# Load results of the analyzes from a given output folder.
-# - info is the SingleRunInfo object
-# - deleteEmpty specifies if the empty plist files should be deleted
-def loadResultsFromSingleRun(info, deleteEmpty=True):
- path = info.path
- run = AnalysisRun(info)
+ self.clang_version = None
- for f in os.listdir(path):
- if (not f.endswith('plist')):
- continue
+ def getClangVersion(self):
+ return self.clang_version
- p = os.path.join(path, f)
+ def readSingleFile(self, p, deleteEmpty):
data = plistlib.readPlist(p)
+ # We want to retrieve the clang version even if there are no
+ # reports. Assume that all reports were created using the same
+ # clang version (this is always true and is more efficient).
+ if 'clang_version' in data:
+ if self.clang_version == None:
+ self.clang_version = data.pop('clang_version')
+ else:
+ data.pop('clang_version')
+
# Ignore/delete empty reports.
if not data['files']:
if deleteEmpty == True:
os.remove(p)
- continue
+ return
# Extract the HTML reports, if they exists.
if 'HTMLDiagnostics_files' in data['diagnostics'][0]:
@@ -171,21 +166,40 @@ def loadResultsFromSingleRun(info, deleteEmpty=True):
htmlFiles.append(d.pop('HTMLDiagnostics_files')[0])
else:
htmlFiles = [None] * len(data['diagnostics'])
-
- clang_version = ''
- if 'clang_version' in data:
- clang_version = data.pop('clang_version')
-
- report = AnalysisReport(run, data.pop('files'), clang_version)
+
+ report = AnalysisReport(self, data.pop('files'))
diagnostics = [AnalysisDiagnostic(d, report, h)
for d,h in zip(data.pop('diagnostics'),
htmlFiles)]
assert not data
-
+
report.diagnostics.extend(diagnostics)
- run.reports.append(report)
- run.diagnostics.extend(diagnostics)
+ self.reports.append(report)
+ self.diagnostics.extend(diagnostics)
+
+
+# Backward compatibility API.
+def loadResults(path, opts, root = "", deleteEmpty=True):
+ return loadResultsFromSingleRun(SingleRunInfo(path, root, opts.verboseLog),
+ deleteEmpty)
+
+# Load results of the analyzes from a given output folder.
+# - info is the SingleRunInfo object
+# - deleteEmpty specifies if the empty plist files should be deleted
+def loadResultsFromSingleRun(info, deleteEmpty=True):
+ path = info.path
+ run = AnalysisRun(info)
+
+ if os.path.isfile(path):
+ run.readSingleFile(path, deleteEmpty)
+ else:
+ for (dirpath, dirnames, filenames) in os.walk(path):
+ for f in filenames:
+ if (not f.endswith('plist')):
+ continue
+ p = os.path.join(dirpath, f)
+ run.readSingleFile(p, deleteEmpty)
return run
diff --git a/utils/analyzer/SATestBuild.py b/utils/analyzer/SATestBuild.py
index 9412358..067be16 100644
--- a/utils/analyzer/SATestBuild.py
+++ b/utils/analyzer/SATestBuild.py
@@ -142,7 +142,7 @@ if not Clang:
sys.exit(-1)
# Number of jobs.
-Jobs = math.ceil(detectCPUs() * 0.75)
+Jobs = int(math.ceil(detectCPUs() * 0.75))
# Project map stores info about all the "registered" projects.
ProjectMapFile = "projectMap.csv"
@@ -206,6 +206,7 @@ def runScanBuild(Dir, SBOutputDir, PBuildLogFile):
SBOptions = "--use-analyzer " + Clang + " "
SBOptions += "-plist-html -o " + SBOutputDir + " "
SBOptions += "-enable-checker " + Checkers + " "
+ SBOptions += "--keep-empty "
try:
SBCommandFile = open(BuildScriptPath, "r")
SBPrefix = "scan-build " + SBOptions + " "
@@ -213,8 +214,9 @@ def runScanBuild(Dir, SBOutputDir, PBuildLogFile):
# If using 'make', auto imply a -jX argument
# to speed up analysis. xcodebuild will
# automatically use the maximum number of cores.
- if Command.startswith("make "):
- Command += "-j" + Jobs
+ if (Command.startswith("make ") or Command == "make") and \
+ "-j" not in Command:
+ Command += " -j%d" % Jobs
SBCommand = SBPrefix + Command
if Verbose == 1:
print " Executing: %s" % (SBCommand,)
diff --git a/utils/find-unused-diagnostics.sh b/utils/find-unused-diagnostics.sh
index 89b7f7a..c7fa01a 100644
--- a/utils/find-unused-diagnostics.sh
+++ b/utils/find-unused-diagnostics.sh
@@ -4,16 +4,12 @@
# in Diagnostic*.td files but not used in sources.
#
-ALL_DIAGS=$(mktemp)
-ALL_SOURCES=$(mktemp)
+# Gather all diagnostic identifiers from the .td files.
+ALL_DIAGS=$(grep -E --only-matching --no-filename '(err_|warn_|ext_|note_)[a-z_]+' ./include/clang/Basic/Diagnostic*.td)
-grep -E --only-matching --no-filename '(err_|warn_|ext_|note_)[a-z_]+ ' ./include/clang/Basic/Diagnostic*.td > $ALL_DIAGS
-find lib include tools -name \*.cpp -or -name \*.h > $ALL_SOURCES
-for DIAG in $(cat $ALL_DIAGS); do
- if ! grep -r $DIAG $(cat $ALL_SOURCES) > /dev/null; then
- echo $DIAG
- fi;
-done
-
-rm $ALL_DIAGS $ALL_SOURCES
+# Now look for all potential identifiers in the source files.
+ALL_SOURCES=$(find lib include tools -name \*.cpp -or -name \*.h)
+DIAGS_IN_SOURCES=$(grep -E --only-matching --no-filename '(err_|warn_|ext_|note_)[a-z_]+' $ALL_SOURCES)
+# Print all diags that occur in the .td files but not in the source.
+comm -23 <(sort -u <<< "$ALL_DIAGS") <(sort -u <<< "$DIAGS_IN_SOURCES")
diff --git a/utils/valgrind/x86_64-pc-linux-gnu_gcc-4.3.3.supp b/utils/valgrind/x86_64-pc-linux-gnu_gcc-4.3.3.supp
index a86be6c..b8ba7f3 100644
--- a/utils/valgrind/x86_64-pc-linux-gnu_gcc-4.3.3.supp
+++ b/utils/valgrind/x86_64-pc-linux-gnu_gcc-4.3.3.supp
@@ -21,3 +21,10 @@
...
fun:_ZSt11stable_sortIN9__gnu_cxx17__normal_iteratorIPSt4pairIPKN4llvm4TypeEjESt6vectorIS7_SaIS7_EEEEPFbRKS7_SE_EEvT_SH_T0_
}
+
+# Remove this if clang-vg didn't use "check-all"
+{
+ We don't care of cmp
+ Memcheck:Cond
+ obj:/usr/bin/cmp
+}
diff --git a/www/OpenProjects.html b/www/OpenProjects.html
index b2d4dae..98d8660 100644
--- a/www/OpenProjects.html
+++ b/www/OpenProjects.html
@@ -82,13 +82,7 @@ improve the quality of clang by self-testing. Some examples:
C++'98 is feature complete, but there is still a lot of C++'11 features to
implement. Please see the <a href="cxx_status.html">C++ status report
page</a> to find out what is missing.</li>
-</ul>
-
-<p>If you hit a bug with clang, it is very useful for us if you reduce the code
-that demonstrates the problem down to something small. There are many ways to
-do this; ask on cfe-dev for advice.</p>
-<ul>
<li><b>StringRef'ize APIs</b>: A thankless but incredibly useful project is
StringRef'izing (converting to use <tt>llvm::StringRef</tt> instead of <tt>const
char *</tt> or <tt>std::string</tt>) various clang interfaces. This generally
@@ -107,8 +101,34 @@ Driver</a> web page for more information.</li>
<li><i>Documented</i>, with appropriate Schema against which the output of Clang's XML formatter can be verified.</li>
<li><i>Stable</i> across Clang versions.</li>
</ul></li>
+
+<li><b>Configuration Manager</b>: Clang/LLVM works on a large number of
+architectures and operating systems and can cross-compile to a similarly large
+number of configurations, but the pitfalls of chosing the command-line
+options, making sure the right sub-architecture is chosen and that the correct
+optional elements of your particular system can be a pain.
+
+<p>A tool that would investigate hosts and targets, and store the configuration
+in files that can later be used by Clang itself to avoid command-line options,
+especially the ones regarding which target options to use, would greatle alleviate
+this problem. A simple tool, with little or no dependency on LLVM itself, that
+will investigate a target architecture by probing hardware, software, libraries
+and compiling and executing code to identify all properties that would be relevant
+to command-line options (VFP, SSE, NEON, ARM vs. Thumb etc), triple settings etc.</p>
+
+<p>The first stage is to build a CFLAGS for Clang that would produce code on the
+current Host to the identified Target.</p>
+
+<p>The second stage would be to produce a configuration file (that can be used
+independently of the Host) so that Clang can read it and not need a gazillion
+of command-line options. Such file should be simple JSON / INI or anything that
+a text editor could change.</p>
</ul>
+<p>If you hit a bug with clang, it is very useful for us if you reduce the code
+that demonstrates the problem down to something small. There are many ways to
+do this; ask on cfe-dev for advice.</p>
+
</div>
</body>
</html>
diff --git a/www/analyzer/annotations.html b/www/analyzer/annotations.html
index bb4bc44..ca6a185 100644
--- a/www/analyzer/annotations.html
+++ b/www/analyzer/annotations.html
@@ -127,7 +127,10 @@ conventions can cause the analyzer to miss bugs or flag false positives.</p>
<p>One can educate the analyzer (and others who read your code) about methods or
functions that deviate from the Cocoa and Core Foundation conventions using the
-attributes described here.</p>
+attributes described here. However, you should consider using proper naming
+conventions or the <a
+href="http://clang.llvm.org/docs/LanguageExtensions.html#the-objc-method-family-attribute"><tt>objc_method_family</tt></a>
+attribute, if applicable.</p>
<h4 id="attr_ns_returns_retained">Attribute 'ns_returns_retained'
(Clang-specific)</h4>
@@ -135,7 +138,9 @@ attributes described here.</p>
<p>The GCC-style (Clang-specific) attribute 'ns_returns_retained' allows one to
annotate an Objective-C method or C function as returning a retained Cocoa
object that the caller is responsible for releasing (via sending a
-<tt>release</tt> message to the object).</p>
+<tt>release</tt> message to the object). The Foundation framework defines a
+macro <b><tt>NS_RETURNS_RETAINED</tt></b> that is functionally equivalent to the
+one shown below.</p>
<p><b>Placing on Objective-C methods</b>: For Objective-C methods, this
annotation essentially tells the analyzer to treat the method as if its name
@@ -202,7 +207,9 @@ href="#attr_ns_returns_retained">ns_returns_retained</a>'. Where a function or
method may appear to obey the Cocoa conventions and return a retained Cocoa
object, this attribute can be used to indicate that the object reference
returned should not be considered as an &quot;owning&quot; reference being
-returned to the caller.</p>
+returned to the caller. The Foundation framework defines a
+macro <b><tt>NS_RETURNS_NOT_RETAINED</tt></b> that is functionally equivalent to
+the one shown below.</p>
<p>Usage is identical to <a
href="#attr_ns_returns_retained">ns_returns_retained</a>. When using the
@@ -229,7 +236,9 @@ its availability, as it is not available in earlier versions of the analyzer:</p
<p>The GCC-style (Clang-specific) attribute 'cf_returns_retained' allows one to
annotate an Objective-C method or C function as returning a retained Core
-Foundation object that the caller is responsible for releasing.
+Foundation object that the caller is responsible for releasing. The
+CoreFoundation framework defines a macro <b><tt>CF_RETURNS_RETAINED</tt></b>
+that is functionally equivalent to the one shown below.</p>
<p><b>Placing on Objective-C methods</b>: With respect to Objective-C methods.,
this attribute is identical in its behavior and usage to 'ns_returns_retained'
@@ -330,7 +339,9 @@ href="#attr_cf_returns_retained">cf_returns_retained</a>'. Where a function or
method may appear to obey the Core Foundation or Cocoa conventions and return
a retained Core Foundation object, this attribute can be used to indicate that
the object reference returned should not be considered as an
-&quot;owning&quot; reference being returned to the caller.</p>
+&quot;owning&quot; reference being returned to the caller. The
+CoreFoundation framework defines a macro <b><tt>CF_RETURNS_NOT_RETAINED</tt></b>
+that is functionally equivalent to the one shown below.</p>
<p>Usage is identical to <a
href="#attr_cf_returns_retained">cf_returns_retained</a>. When using the
@@ -355,9 +366,12 @@ its availability, as it is not available in earlier versions of the analyzer:</p
<h4 id="attr_ns_consumed">Attribute 'ns_consumed'
(Clang-specific)</h4>
-<p>The 'ns_consumed' attribute can be placed on a specific parameter in either the declaration of a function or an Objective-C method.
- It indicates to the static analyzer that a <tt>release</tt> message is implicitly sent to the parameter upon
- completion of the call to the given function or method.
+<p>The 'ns_consumed' attribute can be placed on a specific parameter in either
+the declaration of a function or an Objective-C method. It indicates to the
+static analyzer that a <tt>release</tt> message is implicitly sent to the
+parameter upon completion of the call to the given function or method. The
+Foundation framework defines a macro <b><tt>NS_RELEASES_ARGUMENT</tt></b> that
+is functionally equivalent to the <tt>NS_CONSUMED</tt> macro shown below.</p>
<p><b>Important note when using Garbage Collection</b>: Note that the analyzer
essentially ignores this attribute when code is compiled to use Objective-C
@@ -409,14 +423,19 @@ void test_method2() {
<h4 id="attr_cf_consumed">Attribute 'cf_consumed'
(Clang-specific)</h4>
-<p>The 'cf_consumed' attribute is practically identical to <a href="#attr_ns_consumed">ns_consumed</a>.
-The attribute can be placed on a specific parameter in either the declaration of a function or an Objective-C method.
-It indicates to the static analyzer that the object reference is implicitly passed to a call to <tt>CFRelease</tt> upon
-completion of the call to the given function or method.</p>
+<p>The 'cf_consumed' attribute is practically identical to <a
+href="#attr_ns_consumed">ns_consumed</a>. The attribute can be placed on a
+specific parameter in either the declaration of a function or an Objective-C
+method. It indicates to the static analyzer that the object reference is
+implicitly passed to a call to <tt>CFRelease</tt> upon completion of the call
+to the given function or method. The CoreFoundation framework defines a macro
+<b><tt>CF_RELEASES_ARGUMENT</tt></b> that is functionally equivalent to the
+<tt>CF_CONSUMED</tt> macro shown below.</p>
-<p>Operationally this attribute is nearly identical to ns_consumed
-with the main difference that the reference count decrement still occurs when using Objective-C garbage
-collection (which is import for Core Foundation types, which are not automatically garbage collected).</p>
+<p>Operationally this attribute is nearly identical to 'ns_consumed' with the
+main difference that the reference count decrement still occurs when using
+Objective-C garbage collection (which is import for Core Foundation types,
+which are not automatically garbage collected).</p>
<p><b>Example</b></p>
@@ -461,13 +480,13 @@ void test_method() {
<h4 id="attr_ns_consumes_self">Attribute 'ns_consumes_self'
(Clang-specific)</h4>
-<p>The 'ns_consumes_self' attribute can be placed only on an Objective-C method declaration.
- It indicates that the receiver of the message is &quot;consumed&quot; (a single reference count decremented)
- after the message is sent. This matches the semantics of all &quot;init&quot; methods.
-</p>
+<p>The 'ns_consumes_self' attribute can be placed only on an Objective-C method
+declaration. It indicates that the receiver of the message is
+&quot;consumed&quot; (a single reference count decremented) after the message
+is sent. This matches the semantics of all &quot;init&quot; methods.</p>
-<p>One use of this attribute is declare your own init-like methods that do not follow the
- standard Cocoa naming conventions.</p>
+<p>One use of this attribute is declare your own init-like methods that do not
+follow the standard Cocoa naming conventions.</p>
<p><b>Example</b></p>
@@ -490,8 +509,15 @@ void test_method() {
@end
</pre>
-<p>In this example, <tt>nonstandardInitWith:</tt> has the same ownership semantics as the init method <tt>initWith:</tt>.
- The static analyzer will observe that the method consumes the receiver, and then returns an object with a +1 retain count.</p>
+<p>In this example, <tt>-nonstandardInitWith:</tt> has the same ownership
+semantics as the init method <tt>-initWith:</tt>. The static analyzer will
+observe that the method consumes the receiver, and then returns an object with
+a +1 retain count.</p>
+
+<p>The Foundation framework defines a macro <b><tt>NS_REPLACES_RECEIVER</tt></b>
+which is functionally equivalent to the combination of <tt>NS_CONSUMES_SELF</tt>
+and <tt>NS_RETURNS_RETAINED</tt> shown above.</p>
+
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<h2 id="custom_assertions">Custom Assertion Handlers</h2>
diff --git a/www/analyzer/available_checks.html b/www/analyzer/available_checks.html
index 4f8971c..be15125 100644
--- a/www/analyzer/available_checks.html
+++ b/www/analyzer/available_checks.html
@@ -176,14 +176,13 @@
<td><b>unix.cstring.NullArg</b></td><td>Check for null pointers being passed as arguments to C string functions.</td>
</table>
-<p>In addition to these the analyzer contains numerous experimental (beta) checkers.</p>
+<p>In addition to these the analyzer contains numerous experimental (alpha) checkers.</p>
<h3>Writeups with examples of some of the bugs that the analyzer finds</h3>
<ul>
<li><a href="http://www.mobileorchard.com/bug-finding-with-clang-5-resources-to-get-you-started/">Bug Finding With Clang: 5 Resources To Get You Started</a></li>
<li><a href="http://fruitstandsoftware.com/blog/index.php/2008/08/finding-memory-leaks-with-the-llvmclang-static-analyzer/#comment-2">Finding Memory Leaks With The LLVM/Clang Static Analyzer</a></li>
-<li><a href="http://www.therareair.com/howto-static-analyze-your-objective-c-code-using-the-clang-static-analyzer-tool-gallery/">HOWTO: Static Analyze Your Objective-C Code Using the Clang Static Analyzer Tool Gallery</a></li>
<li><a href="http://www.rogueamoeba.com/utm/2008/07/14/the-clang-static-analyzer/">Under the Microscope - The Clang Static Analyzer</a></li>
<li><a href="http://www.mikeash.com/?page=pyblog/friday-qa-2009-03-06-using-the-clang-static-analyzer.html">Mike Ash - Using the Clang Static Analyzer</a></li>
</ul>
diff --git a/www/analyzer/checker_dev_manual.html b/www/analyzer/checker_dev_manual.html
index 043b536..5368eb0 100644
--- a/www/analyzer/checker_dev_manual.html
+++ b/www/analyzer/checker_dev_manual.html
@@ -116,28 +116,44 @@ for general developer guidelines and information. </p>
<h3>Representing Values</h3>
During symbolic execution, <a href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1SVal.html">SVal</a>
- objects are used to represent the semantic evaluation of expressions. They can
- represent things like concrete integers, symbolic values, or memory locations
- (which are memory regions). They are a discriminated union of "values",
- symbolic and otherwise.
+ objects are used to represent the semantic evaluation of expressions.
+ They can represent things like concrete
+ integers, symbolic values, or memory locations (which are memory regions).
+ They are a discriminated union of "values", symbolic and otherwise.
+ If a value isn't symbolic, usually that means there is no symbolic
+ information to track. For example, if the value was an integer, such as
+ <tt>42</tt>, it would be a <a href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1nonloc_1_1ConcreteInt.html">ConcreteInt</a>,
+ and the checker doesn't usually need to track any state with the concrete
+ number. In some cases, <tt>SVal</tt> is not a symbol, but it really should be
+ a symbolic value. This happens when the analyzer cannot reason about something
+ (yet). An example is floating point numbers. In such cases, the
+ <tt>SVal</tt> will evaluate to <a href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1UnknownVal.html">UnknownVal<a>.
+ This represents a case that is outside the realm of the analyzer's reasoning
+ capabilities. <tt>SVals</tt> are value objects and their values can be viewed
+ using the <tt>.dump()</tt> method. Often they wrap persistent objects such as
+ symbols or regions.
<p>
<a href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1SymExpr.html">SymExpr</a> (symbol)
- is meant to represent abstract, but named, symbolic value.
- Symbolic values can have constraints associated with them. Symbols represent
+ is meant to represent abstract, but named, symbolic value. Symbols represent
an actual (immutable) value. We might not know what its specific value is, but
- we can associate constraints with that value as we analyze a path.
+ we can associate constraints with that value as we analyze a path. For
+ example, we might record that the value of a symbol is greater than
+ <tt>0</tt>, etc.
+ <p>
+
<p>
-
<a href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1MemRegion.html">MemRegion</a> is similar to a symbol.
It is used to provide a lexicon of how to describe abstract memory. Regions can
layer on top of other regions, providing a layered approach to representing memory.
For example, a struct object on the stack might be represented by a <tt>VarRegion</tt>,
but a <tt>FieldRegion</tt> which is a subregion of the <tt>VarRegion</tt> could
be used to represent the memory associated with a specific field of that object.
- So how do we represent symbolic memory regions? That's what <a href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1SymbolicRegion.html">SymbolicRegion</a>
- is for. It is a <tt>MemRegion</tt> that has an associated symbol. Since the
+ So how do we represent symbolic memory regions? That's what
+ <a href="http://clang.llvm.org/doxygen/classclang_1_1ento_1_1SymbolicRegion.html">SymbolicRegion</a>
+ is for. It is a <tt>MemRegion</tt> that has an associated symbol. Since the
symbol is unique and has a unique name; that symbol names the region.
- <p>
+
+ <P>
Let's see how the analyzer processes the expressions in the following example:
<p>
<pre class="code_example">
diff --git a/www/analyzer/content.css b/www/analyzer/content.css
index c2fa294..6f68fdb 100644
--- a/www/analyzer/content.css
+++ b/www/analyzer/content.css
@@ -87,6 +87,7 @@ table.checkers td {
border-bottom: 1px #cccccc dotted;
}
+table.checkers td.aligned { text-align: center; vertical-align: middle; }
table.checkers col.namedescr { width: 45% }
table.checkers col.example { width: 55% }
table.checkers col.progress { width: 84px }
diff --git a/www/analyzer/dev_cxx.html b/www/analyzer/dev_cxx.html
index 39dbf7b..4424a9a 100644
--- a/www/analyzer/dev_cxx.html
+++ b/www/analyzer/dev_cxx.html
@@ -15,16 +15,13 @@
<h1>C++ Support</h1>
-<p>The Clang frontend
-now <a href="http://clang.llvm.org/cxx_status.html">supports the
-majority of C++</a>. Support in the frontend for C++ language
-features, however, does not automatically translate into support for
-those features in the static analyzer. Language features need to be
-specifically modeled in the static analyzer so their semantics can be
-properly analyzed. Support for analyzing C++ and Objective-C++ files
-is currently extremely limited, and we are only encouraging those who
-are interested in contributing to the development of the analyzer to
-try this functionality out at this time.</p>
+<p>The Clang compiler <a
+href="http://clang.llvm.org/cxx_status.html">supports almost all of C++11</a>.
+Support in the frontend for C++ language features, however, does not
+automatically translate into support for those features in the static analyzer.
+Language features need to be specifically modeled in the static analyzer so
+their semantics can be properly analyzed. Support for analyzing C++ and
+Objective-C++ files is currently fairly basic.</p>
<p>Listed here are a set of open tasks that are prerequisites for
decent analysis of C++. This list is also not complete; new tasks
@@ -33,16 +30,22 @@ will be added as deemed necessary.</p>
<ul>
<li>Control-Flow Graph Enhancements:
<ul>
- <li>Model C++ destructors</li>
- <li>Model C++ initializers (in constructors)</li>
+ <li>Model destructors for temporary objects</li>
+ <li>Model the implicit allocator call to <tt>operator new</tt></li>
</ul>
</li>
- <li>Path-Sensitive Analysis Engine (GRExprEngine):
+ <li>Path-Sensitive Analysis Engine (ExprEngine):
<ul>
- <li>Model C++ casts</li>
- <li>Model C++ constructors</li>
- <li>Model C++ destructors</li>
- <li>Model <tt>new</tt> and <tt>delete</tt></li>
+ <li>Allow constructors to be inlined</li>
+ <li>Allow destructors to be inlined</li>
+ <li>Fully model <tt>new</tt> and <tt>delete</tt></li>
+ <li>Track type info through casts more precisely</li>
+ </ul>
+ </li>
+ <li>Checkers:
+ <ul>
+ <li>Check that <tt>new</tt> and <tt>delete</tt> are correctly paired</li>
+ <li>For more ideas, see the <a href="potential_checkers.html">list of potential checkers</a></li>
</ul>
</li>
</ul>
diff --git a/www/analyzer/faq.html b/www/analyzer/faq.html
index 5c132b5..129bfb6 100644
--- a/www/analyzer/faq.html
+++ b/www/analyzer/faq.html
@@ -68,13 +68,15 @@ int foo(int *b) {
<img src="images/example_use_assert.png" alt="example use assert">
-<p>You can teach the analyzer facts about your code as well as document it by
-using assertions. In the contrived example above, the analyzer reports an error
-on the path which assumes that the loop is never entered. However, the owner of
-the code might know that the loop is always entered because the input parameter
-<tt>length</tt> is always greater than <tt>0</tt>. The false positive can be
-suppressed by asserting this knowledge, adding <tt>assert(length > 0)</tt> in
-the beginning of the function.</p>
+<p> In the contrived example above, the analyzer has detected that the body of
+the loop is never entered for the case where <tt>length <= 0</tt>. In this
+particular example, you may know that the loop will always be entered because
+the input parameter <tt>length</tt> will be greater than zero in all calls to this
+function. You can teach the analyzer facts about your code as well as document
+it by using assertions. By adding <tt>assert(length > 0)</tt> in the beginning
+of the function, you tell the analyzer that your code is never expecting a zero
+or a negative value, so it won't need to test the correctness of those paths.
+</p>
<pre class="code_example">
int foo(int length) {
diff --git a/www/analyzer/index.html b/www/analyzer/index.html
index 18bafd0..33e8581 100644
--- a/www/analyzer/index.html
+++ b/www/analyzer/index.html
@@ -69,12 +69,12 @@
<h1>Clang Static Analyzer</h1>
-<p>The Clang Static Analyzer is source code analysis tool that find bugs in C
-and Objective-C programs.</p>
+<p>The Clang Static Analyzer is a source code analysis tool that finds bugs in
+C, C++, and Objective-C programs.</p>
-<p>Currently it can be run either as a <a href="/scan-build.html">standalone
-tool</a> or <a href="/xcode.html">within Xcode</a>. The standalone tool is
-invoked from the command-line, and is intended to be run in tandem with a build
+<p>Currently it can be run either as a <a href="scan-build.html">standalone
+tool</a> or <a href="xcode.html">within Xcode</a>. The standalone tool is
+invoked from the command line, and is intended to be run in tandem with a build
of a codebase.</p>
<p>The analyzer is 100% open source and is part of the <a
@@ -138,14 +138,14 @@ applications.</p>
</td><td style="padding-left:10px">
<a href="images/analyzer_xcode.png"><img src="images/analyzer_xcode.png" width="450" alt="analyzer in xcode"></a>
-<div style="text-align:center"><b>Viewing static analyzer results in Xcode 3.2</b></div>
+<div style="text-align:center"><b>Viewing static analyzer results in Xcode</b></div>
<a href="images/analyzer_html.png"><img src="images/analyzer_html.png" width="450" alt="analyzer in browser"></a>
<div style="text-align:center"><b>Viewing static analyzer results in a web browser</b></div>
</td></tr></table>
<h2 id="StaticAnalysis">What is Static Analysis?</h2>
-<p>The term &quot;static analysis&quot; is conflated, but here we use it to mean
+<p>The term "static analysis" is conflated, but here we use it to mean
a collection of algorithms and techniques used to analyze source code in order
to automatically find bugs. The idea is similar in spirit to compiler warnings
(which can be useful for finding coding errors) but to take that idea a step
@@ -155,9 +155,8 @@ techniques such as testing.</p>
<p>Static analysis bug-finding tools have evolved over the last several decades
from basic syntactic checkers to those that find deep bugs by reasoning about
the semantics of code. The goal of the Clang Static Analyzer is to provide a
-industrial-quality static analysis framework for analyzing C and Objective-C
-programs that is freely available, extensible, and has a high quality of
-implementation.</p>
+industrial-quality static analysis framework for analyzing C, C++, and
+Objective-C programs that is freely available, extensible, and has a high quality of implementation.</p>
<h3 id="Clang">Part of Clang and LLVM</h3>
@@ -175,11 +174,11 @@ bugs, we ask you to bear in mind a few points when using it.</p>
<h3>Work-in-Progress</h3>
-<p>The analyzer is a continuous work-in-progress.
-There are many planned enhancements to improve both the precision and scope of
-its analysis algorithms as well as the kinds bugs it will find. While there are
-fundamental limitations to what static analysis can do, we have a long way to go
-before hitting that wall.</p>
+<p>The analyzer is a continuous work-in-progress. There are many planned
+enhancements to improve both the precision and scope of its analysis algorithms
+as well as the kinds of bugs it will find. While there are fundamental
+limitations to what static analysis can do, we have a long way to go before
+hitting that wall.</p>
<h3>Slower than Compilation</h3>
diff --git a/www/analyzer/latest_checker.html.incl b/www/analyzer/latest_checker.html.incl
index 996bc34..1355297 100644
--- a/www/analyzer/latest_checker.html.incl
+++ b/www/analyzer/latest_checker.html.incl
@@ -1 +1 @@
-<b><a href="http://bit.ly/USf8ge">checker-269.tar.bz2</a></b> (built September 25, 2012)
+<b><a href="https://attache.apple.com/AttacheWeb/dl?id=ATCbb91eedf8edf4c7388549be8f91e810d">checker-272.tar.bz2</a></b> (built March 1, 2013)
diff --git a/www/analyzer/potential_checkers.html b/www/analyzer/potential_checkers.html
index f65106e..04bf9fe 100644
--- a/www/analyzer/potential_checkers.html
+++ b/www/analyzer/potential_checkers.html
@@ -43,7 +43,8 @@ void test() {
return;
delete p2;
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"><a href="http://llvm.org/bugs/show_bug.cgi?id=15237">PR15237</a>
+</td></tr>
<tr><td><span class="name">memory.MismatchedFree
<br>enhancement to unix.Malloc<br>(C, C++)</span><br><br>
@@ -58,7 +59,8 @@ void test() {
free(p1); // warn
free(p2); // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"><a href="http://llvm.org/bugs/show_bug.cgi?id=15238">PR15238</a>
+</td></tr>
<tr><td><span class="name">memory.MismatchedDelete
<br>(C, C++)</span><br><br>
@@ -75,7 +77,8 @@ void test() {
delete p2; // warn
delete p3; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"><a href="http://llvm.org/bugs/show_bug.cgi?id=15238">PR15238</a>
+</td></tr>
<tr><td><span class="name">memory.MultipleDelete
<br>(C++)</span><br><br>
@@ -92,7 +95,9 @@ void test() {
delete p2; // warn
delete p3; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"><a href="http://llvm.org/bugs/show_bug.cgi?id=15237">PR15237</a>
+</td></tr>
+
<tr><td><span class="name">memory.LeakPtrValChanged
<br>enhancement to unix.Malloc<br>(C, C++)</span><br><br>
@@ -116,7 +121,9 @@ void test() {
f(p4);
p4++; // ok
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned">done at r174678 (C case)
+</td></tr>
+
<tr><td><span class="name">memory.DeallocateNonPtr
<br>enhancement to unix.Malloc<br>(C, C++)</span><br><br>
@@ -138,7 +145,9 @@ void test() {
delete s; // warn
free(s); // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"><a href="http://llvm.org/bugs/show_bug.cgi?id=15237">PR15237</a>
+</td></tr>
+
<tr><td><span class="name">memory.LeakEvalOrder<br>
(C, C++)</span><br><br>
@@ -156,7 +165,7 @@ void test() {
f1(g((int *)malloc(sizeof(int))), h()); // warn
f2(new int, new int);
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">memory.DstBufferTooSmall
<br>(C, C++)</span><br><br>
@@ -173,7 +182,7 @@ void test() {
int* p2 = new int;
memcpy(p2, p1, 3); // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">memory.NegativeArraySize
<br>enhancement to experimental.security.MallocOverflow<br>(C, C++)
@@ -187,7 +196,7 @@ void test() {
int n1 = -1;
p = new int[n1]; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
</table>
@@ -208,7 +217,7 @@ class A {
A() {}
~A() { throw 1; } // warn
};
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">ctordtor.ExptInsideDtorImplicit<br>
(C++)</span><br><br>
@@ -221,7 +230,7 @@ class A {
A() {}
~A() { f(); } // warn
};
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
</table>
@@ -237,7 +246,7 @@ Function prototype has throw(T) specifier but the function do not throw
</td><td><pre>
void f() throw(int) { // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">exceptions.NoThrowSpecButThrows
<br>(C++)</span><br><br>
@@ -246,7 +255,7 @@ An exception is throw from a function having the throw() specifier
void f() throw() {
throw(1); // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">exceptions.ThrownTypeDiffersSpec
<br>(C++)</span><br><br>
@@ -258,7 +267,7 @@ void f() throw(int) {
S s;
throw (s); // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
</table>
@@ -286,7 +295,7 @@ void test() {
std::auto_ptr&lt;int&gt;
p3((int *)malloc(sizeof(int))); // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
</table>
@@ -311,7 +320,7 @@ public:
};
A a;
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">undefbehavior.LocalStaticDestroyed
<br>(C++)</span><br><br>
@@ -336,7 +345,7 @@ A a;
void f() {
static B b; // &lt;-
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">undefbehavior.UseAfterRelease
<br>enhancement to unix.Malloc<br>(C, C++)</span><br><br>
@@ -351,7 +360,7 @@ void test() {
int i = *p; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">undefbehavior.ZeroAllocDereference
<br>enhancement to unix.Malloc<br>(C, C++)</span><br><br>
@@ -362,7 +371,7 @@ undefined
int *p = new int[0];
int i = p[0]; // warn
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">undefbehavior.DeadReferenced
<br>(C++)</span><br><br>
@@ -418,7 +427,7 @@ void test() {
dynamic_cast&lt;A*&gt;(b); // warn
delete b; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">undefbehavior.ObjLocChanges
<br>(C++)</span><br><br>
@@ -439,7 +448,7 @@ void test() {
new (&amp;b2) T;
delete b1; // warn
} // warn
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">undefbehavior.ExprEvalOrderUndef
<br>(C, C++03)</span><br><br>
@@ -452,7 +461,7 @@ void test () {
i = v[i++]; // warn
i = ++i + 1; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">undefbehavior.StaticInitReentered
<br>(C)</span><br><br>
@@ -463,7 +472,7 @@ int test(int i) {
static int s = test(2*i); // warn
return i+1;
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">undefbehavior.ConstModified
<br>(C, C++)</span><br><br>
@@ -493,7 +502,7 @@ void test() {
p-&gt;x.i = 1; // ok
p-&gt;x.j = 1; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">undefbehavior.DeadDestructed
<br>(C++)</span><br><br>
@@ -511,7 +520,7 @@ void test() {
A a;
a.~A();
} // warn
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">undefbehavior.MethodCallBeforeBaseInit
<br>(C++)</span><br><br>
@@ -526,7 +535,7 @@ public :
int f();
B() : A(f()) {} // warn
};
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">undefbehavior.MemberOrBaseRefBeforeCtor
<br>(C++)</span><br><br>
@@ -589,7 +598,7 @@ struct S {
non_trivial nt;
S() : k(&amp;nt.j) {} // warn
};
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">undefbehavior.MemberRefAfterDtor
<br>(C++)</span><br><br>
@@ -620,7 +629,7 @@ void test() {
s->~S();
s->f(); // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">undefbehavior.CtorForeignCall
<br>(C++)</span><br><br>
@@ -641,7 +650,7 @@ class C : public A, B {
public:
C() : B((A*)this) {}
};
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">undefbehavior.CtorForeignCast
undefbehavior.CtorForeignTypeid
@@ -669,7 +678,7 @@ class C : public A, B {
public:
C() : B((A*)this) {}
};
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">undefbehavior.MemberRefInCatch
undefbehavior.BaseRefInCatch
@@ -689,7 +698,7 @@ public :
i=2; // warn
}
};
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">undefbehavior.ReturnAtCatchEnd
<br>(C++)</span><br><br>
@@ -701,7 +710,7 @@ int test() try {
}
catch(int) {
} // warn
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">undefbehavior.AutoptrsOwnSameObj
<br>(C++03)</span><br><br>
@@ -715,7 +724,7 @@ void test() {
std::auto_ptr&lt;int&gt; p(data);
std::auto_ptr&lt;int&gt; q(data); // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">undefbehavior.BasicStringBoundAccess
<br>(C++03)</span><br><br>
@@ -725,7 +734,7 @@ void test() {
std::basic_string&lt;char&gt; s;
char c = s[10]; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">undefbehavior.BasicStringBoundModification
<br>(C++)</span><br><br>
@@ -735,7 +744,7 @@ void test() {
std::basic_string&lt;char&gt; s;
s[10] = 0; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">undefbehavior.EosDereference
<br>(C++)</span><br><br>
@@ -749,7 +758,7 @@ void test() {
int i = *v.end(); // warn
*v.end() = 0; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">undefbehavior.QsortNonPOD
undefbehavior.QsortNonTrivial
@@ -815,7 +824,7 @@ void test() {
qsort(nt, 2, sizeof(non_trivial),
compare2); // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">undefbehavior.ThrowWhileCopy
<br>C++</span><br><br>
@@ -835,7 +844,7 @@ struct S {
j = s.j;
}
};
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">undefbehavior.ValarrayArgBound
<br>(C++)</span><br><br>
@@ -853,7 +862,7 @@ void test(void) {
S s[] = { S(1), S(2) };
std::valarray&lt;S&gt; v(s,3); // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">undefbehavior.ValarrayLengthDiffer
<br>(C++)</span><br><br>
@@ -886,7 +895,7 @@ void test(void) {
b.resize(1);
a = b; // OK
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">undefbehavior.ValarrayZeroLength
<br>(C++)</span><br><br>
@@ -901,7 +910,7 @@ void test(void) {
v.min(); // warn
v.max(); // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">undefbehavior.ValarrayBadIndirection
<br>(C++)</span><br><br>
@@ -917,7 +926,7 @@ void test() {
a[indirect] = b; //warn
a[indirect] *= b; //warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">undefbehavior.IosBaseDestroyedBeforeInit
<br>(C++)</span><br>
@@ -948,7 +957,7 @@ void test() {
delete p1; // warn
delete p2; // ok
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">undefbehavior.IosBaseUsedBeforeInit
<br>(C++11)</span><br><br>
@@ -980,7 +989,7 @@ void test() {
delete p1; // warn
delete p2; // ok
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">undefbehavior.MinusOnePosType
<br>(C++)</span><br><br>
@@ -1003,7 +1012,7 @@ void test() {
in.seekg(pos); // warn
out.seekp(-1); // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
</table>
<!-- ============================ different ================================ -->
@@ -1024,7 +1033,7 @@ void test() {
int v[1] = {0};
f(v[i], i++); // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.IdenticalExprBinOp
<br>(C)</span><br><br>
@@ -1050,7 +1059,7 @@ void test() {
if (f() && f()) {} // ok
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.FuncPtrInsteadOfCall
<br>(C)</span><br><br>
@@ -1061,7 +1070,7 @@ int f();
void test() {
if (f == 0) {} // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.IdenticalCondIfElseIf
<br>(C)</span><br><br>
@@ -1073,7 +1082,7 @@ void test() {
if (i == 1) {}
else if (i == 1) {} // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">SuccessiveAssign
<br>(C)</span><br><br>
@@ -1084,7 +1093,7 @@ void test() {
i=1;
i=2; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.NullDerefStmtOrder
<br>enhancement to core.NullDereference<br>(C)</span><br><br>
@@ -1105,7 +1114,7 @@ void test() {
S *p2 = f();
int x2 = p2-&gt;x; // ok
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.NullDerefCondOrder
<br>enhancement to core.NullDereference<br>(C)</span><br><br>
@@ -1120,7 +1129,7 @@ void test() {
S *p = f();
if (p-&gt;b && p) {}; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.IdenticalStmtThenElse
<br>(C)</span><br><br>
@@ -1135,7 +1144,7 @@ void test() {
i++;
}
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.MultipleAccessors
<br>(C++)</span><br><br>
@@ -1150,7 +1159,7 @@ public:
void setI(int& ii) { i = ii; }
void setJ(int& jj) { i = jj; } // warn
};
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.AccessorsForPublic
<br>(C++)</span><br><br>
@@ -1162,7 +1171,7 @@ public:
int getI() { return i; }
void setI(int& ii) { i = ii; }
};
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.LibFuncResultUnised
<br>(C, C++)</span><br><br>
@@ -1175,7 +1184,7 @@ void test() {
std::vector&lt;int&gt; v;
v.empty(); // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.WrongVarForStmt
<br>(C, C++)</span><br><br>
@@ -1188,7 +1197,7 @@ void test() {
for (j=0; j&lt;3; ++i); // warn
for (int j=0; i&lt;3; ++j); // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.FloatingCompare
<br>(C)</span><br><br>
@@ -1201,7 +1210,7 @@ void test() {
if (b == 0.5) // warn
b = 0;
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.BoolCompare
<br>maybe merge with experimental.core.BoolAssignment<br>(C, C++)</span><br><br>
@@ -1213,7 +1222,7 @@ void test() {
bool b;
if (b == 3) {}; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.BitwiseOpBoolArg
<br>maybe join with experimental.core.BoolAssignment<br>(C, C++)</span><br><br>
@@ -1226,7 +1235,7 @@ void test() {
bool b = true;
if (b &amp; f()) {} // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.LabelInsideSwitch
<br>(C)</span><br><br>
@@ -1242,7 +1251,7 @@ void test() {
c -= 1; break;
}
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.IdenticalCondIfIf
<br>(C)</span><br><br>
@@ -1255,7 +1264,7 @@ void test() {
if (c &gt; 5) // warn
c -= 1;
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.CondOpIdenticalReturn
<br>(C)</span><br><br>
@@ -1265,7 +1274,7 @@ void test() {
unsigned a;
a = a > 5 ? a : a; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.UnaryPlusWithUnsigned
<br>(C)</span><br><br>
@@ -1275,7 +1284,7 @@ void test() {
unsigned a;
a = +a; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.LogicalOpUselessArg
<br>(C)</span><br><br>
@@ -1285,7 +1294,7 @@ void test() {
unsigned a;
if (a&lt;7 &amp;&amp; a&lt;10) {}; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.SameResLogicalExpr
<br>(C)</span><br><br>
@@ -1297,7 +1306,7 @@ void test() {
if (i==0 &amp;&amp; i==1) {}; // warn
if (i<0 || i>=0) {}; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.SameResUnsignedCmp
<br>(C)</span><br><br>
@@ -1308,7 +1317,7 @@ void test() {
if (u &lt; -1) {}; // warn
if (u &gt;= 0) {}; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.OpPrecedenceAssignCmp
<br>(C)</span><br><br>
@@ -1324,7 +1333,7 @@ void test() {
if((b = x != y)) {} // ok
if((x = f() != y)) {} // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.OpPrecedenceIifShift
<br>(C)</span><br><br>
@@ -1337,7 +1346,7 @@ void test() {
std::cout &lt;&lt; a ? "a" : "b"; // warn
a &lt;&lt; a&gt;7 ? 1 : 2; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.ObjectUnused
<br>(C++)</span><br><br>
@@ -1360,7 +1369,7 @@ void test() {
S(0, 0); // warn
std::exception(); // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.StaticArrayPtrCompare
<br>(C)</span><br><br>
@@ -1374,7 +1383,7 @@ void test() {
int a2[1][1];
if (a2[0]) {}; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.ConversionToBool
<br>maybe join with experimental.core.BoolAssignment<br>(C, C++)</span><br><br>
@@ -1384,7 +1393,7 @@ bool test() {
return 1.; // warn
return ""; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.ArrayBound
<br>enhancement to experimental.security.ArrayBound[v2]<br>(C, C++)</span><br><br>
@@ -1398,7 +1407,7 @@ void test() {
int i = 1;
if(p2[i]) {}; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.StrcpyInputSize
<BR>enhancement to experimental.unix.cstring.OutOfBounds<br>(C)</span><br><br>
@@ -1408,7 +1417,7 @@ void test(char* string) {
char buf[24];
strcpy(buf, string); // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.IntegerOverflow
<br>(C)</span><br><br>
@@ -1427,7 +1436,7 @@ void test() {
int y = INT_MAX/2+1; // warn
x = y*2; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.SignExtension
<br>(C)</span><br><br>
@@ -1451,7 +1460,7 @@ unsigned int test() {
ui = g(); // warn
return si; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.NumericTruncation
<br>(C)</span><br><br>
@@ -1475,7 +1484,7 @@ int test() {
ss = g(); // warn
return sll; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">different.MissingCopyCtorAssignOp
<br>(C, C++)</span><br><br>
@@ -1488,7 +1497,7 @@ public:
C() { p = new int; }
~C() { delete p; }
};
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
</table>
@@ -1513,7 +1522,7 @@ void test() {
NULL, TEXT("MyProgram.exe"), NULL, NULL,
TRUE, 0, NULL, NULL, &amp;si, &amp;pi);
} // warn
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">WinAPI.LoadLibrary
<br>(C)</span><br><br>
@@ -1525,7 +1534,7 @@ arbitrary location
void test() {
HINSTANCE h = LoadLibrary("X.dll"); // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">WinAPI.WideCharToMultiByte
<br>(C)</span><br><br>
@@ -1548,7 +1557,7 @@ void test()
else
s[res2] = 0;
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
</table>
@@ -1571,7 +1580,7 @@ struct A {
bool FirstIsZero(const struct A a) { // warn
return a.a[0] == 0;
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">optimization.PostfixIncIter
<br>(C++)</span><br><br>
@@ -1585,7 +1594,7 @@ void test() {
for(it = v.begin();
it != v.end(); it++) {}; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">optimization.MultipleCallsStrlen
<br>(C)</span><br><br>
@@ -1600,7 +1609,7 @@ void test() {
if (strlen(s) &gt; 0 &amp;&amp;
strlen(s) &lt; 7) {}; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">optimization.EmptyCstrDetect
<br>(C)</span><br><br>
@@ -1613,7 +1622,7 @@ void test() {
const char* s = "abc";
if (strlen(s) &gt; 0) {}; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">optimization.StrLengthCalculation
<br>(C, C++)</span><br><br>
@@ -1627,7 +1636,7 @@ void test() {
std::string s;
if (strlen(s.c_str()) != 0) {}; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
<tr><td><span class="name">optimization.EmptyContainerDetect
<br>(C, C++)</span><br><br>
@@ -1640,7 +1649,7 @@ void test() {
std::list&lt;int&gt; l;
if (l.size() != 0) {}; // warn
}
-</pre></td><td></td></tr>
+</pre></td><td class="aligned"></td></tr>
</table>
diff --git a/www/analyzer/release_notes.html b/www/analyzer/release_notes.html
index 60f323b..190695e 100644
--- a/www/analyzer/release_notes.html
+++ b/www/analyzer/release_notes.html
@@ -15,6 +15,47 @@
<h1>Release notes for <tt>checker-XXX</tt> builds</h1>
+<h4 id="checker_272">checker-272</h4>
+<p><b>built:</b> March 1, 2013</br>
+ <b>download:</b> <a href="https://attache.apple.com/AttacheWeb/dl?id=ATCbb91eedf8edf4c7388549be8f91e810d">checker-272.tar.bz2</a></p>
+ <p><b>highlights:</b></p>
+ <ul>
+ <li>Better modeling of C++ constructors:
+ <ul>
+ <li>Interprocedural analysis support for constructors of types with trivial destructors</li>
+ <li>Efficient model of trivial copy and move constructors</li>
+ </ul>
+ </li>
+ <li>Better diagnostics for loops that execute 0 times</li>
+ <li>Fixes a linking issue that prevented the checker from running on OS X v10.6 and earlier</li>
+ <li>Fixes for misc. crashes and false positives</li>
+ </ul>
+
+<h4 id="checker_271">checker-271</h4>
+<p><b>built:</b> February 8, 2013</br>
+ <b>download:</b> <a href="http://bit.ly/1299Xt3">checker-271.tar.bz2</a></p>
+ <p><b>highlights:</b></p>
+ <ul>
+ <li>Faster analysis for <tt>scan-build xcodebuild</tt> when using Xcode 4.6 and higher:
+ <ul>
+ <li><tt>scan-build</tt> now uses Xcode's built-in interposition mechanism for the static analyzer to provide faster builds while doing static analysis (PCH files are now built).</li>
+ <li>This change also allows <tt>scan-build</tt> to have better support for iOS project analysis without having to specifying weird SDK settings to <tt>scan-build</tt>.</li>
+ </ul></li>
+ <li>Better diagnostics for implicitly-defined member functions in C++.</li>
+ <li>New warning for <tt>malloc</tt>/<tt>free</tt> checker when passing <tt>malloc</tt>'ed pointer with non-zero offset to <tt>free()</tt>.
+ <li>Fixes for misc. parser crashes.</li>
+ <li>Newer than the static analyzer version in Xcode 4.6</li>
+ </ul>
+
+<h4 id="checker_270">checker-270</h4>
+<p><b>built:</b> January 4, 2013</br>
+ <b>download:</b> <a href="http://bit.ly/13ekSoV">checker-270.tar.bz2</a></p>
+ <p><b>highlights:</b></p>
+ <ul>
+ <li>Major performance enhancements to speed up interprocedural analysis.</li>
+ <li>Misc. bug fixes.</li>
+ </ul>
+
<h4 id="checker_269">checker-269</h4>
<p><b>built:</b> September 25, 2012</br>
<b>download:</b> <a href="http://bit.ly/USf8ge">checker-269.tar.bz2</a></p>
diff --git a/www/analyzer/xcode.html b/www/analyzer/xcode.html
index ac75a047..4bae1c1 100644
--- a/www/analyzer/xcode.html
+++ b/www/analyzer/xcode.html
@@ -2,7 +2,7 @@
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
- <title>Build and Analyze: running the analyzer within Xcode</title>
+ <title>Running the analyzer within Xcode</title>
<link type="text/css" rel="stylesheet" href="content.css">
<link type="text/css" rel="stylesheet" href="menu.css">
<script type="text/javascript" src="scripts/menu.js"></script>
@@ -14,15 +14,16 @@
<!--#include virtual="menu.html.incl"-->
<div id="content">
-<h1>Build and Analyze: running the analyzer within Xcode</h1>
+<h1>Running the analyzer within Xcode</h1>
<table style="margin-top:0px" width="100%" border="0" cellpadding="0px" cellspacing="0">
<tr><td>
<h3>What is it?</h3>
-<p><i>Build and Analyze</i> is an Xcode feature (introduced in Xcode 3.2) that
-allows users to run the Clang Static Analyzer <a
-href="http://developer.apple.com/mac/library/featuredarticles/StaticAnalysis/index.html">directly
+
+<p>Since Xcode 3.2, users have been able to run the Clang Static Analyzer
+<a
+href="https://developer.apple.com/library/mac/documentation/ToolsLanguages/Conceptual/Xcode4UserGuide/060-Debug_Your_App/debug_app.html#//apple_ref/doc/uid/TP40010215-CH3-SW17">directly
within Xcode</a>.</p>
<p>It integrates directly with the Xcode build system and
@@ -45,23 +46,24 @@ presents analysis results directly within Xcode's editor.</p>
single keystroke or mouse click.</li>
<li><b>Transparency:</b> Works effortlessly with Xcode projects (including iPhone projects).
<li><b>Cons:</b> Doesn't work well with non-Xcode projects. For those,
- consider using <a href="/scan-build.html"><b>scan-build</b></a>.
+ consider using <a href="scan-build.html"><b>scan-build</b></a>.
</ul>
<h2>Getting Started</h2>
-<p>Xcode 3.2 is available as a free download from Apple, with <a
-href="http://developer.apple.com/mac/library/featuredarticles/StaticAnalysis/index.html">instructions available</a>
-for using <i>Build and Analyze</i>.</p>
+<p>Xcode is available as a free download from Apple on the <a
+href="https://itunes.apple.com/us/app/xcode/id497799835?mt=12">Mac
+App Store</a>, with <a
+href="https://developer.apple.com/library/mac/documentation/ToolsLanguages/Conceptual/Xcode4UserGuide/060-Debug_Your_App/debug_app.html#//apple_ref/doc/uid/TP40010215-CH3-SW17">instructions
+available</a> for using the analyzer.</p>
-<h2>Using open source analyzer builds with <i>Build and Analyze</i></h2>
+<h2>Using open source analyzer builds with Xcode</h2>
<p>By default, Xcode uses the version of <tt>clang</tt> that came bundled with
-it to provide the results for <i>Build and Analyze</i>. It is possible to change
-Xcode's behavior to use an alternate version of <tt>clang</tt> for this purpose
-while continuing to use the <tt>clang</tt> that came with Xcode for compiling
-projects.</p>
+it to analyze your code. It is possible to change Xcode's behavior to use an
+alternate version of <tt>clang</tt> for this purpose while continuing to use
+the <tt>clang</tt> that came with Xcode for compiling projects.</p>
<h3>Why try open source builds?</h3>
@@ -78,7 +80,7 @@ issues.</p>
<p>Starting with analyzer build checker-234, analyzer builds contain a command
line utility called <tt>set-xcode-analyzer</tt> that allows users to change what
-copy of <tt>clang</tt> that Xcode uses for <i>Build and Analyze</i>:</p>
+copy of <tt>clang</tt> that Xcode uses for analysis:</p>
<pre class="code_example">
$ <b>set-xcode-analyzer -h</b>
@@ -93,8 +95,8 @@ Options:
</pre>
<p>Operationally, <b>set-xcode-analyzer</b> edits Xcode's configuration files
-(in <tt>/Developer</tt>) to point it to use the version of <tt>clang</tt> you
-specify for static analysis. Within this model it provides you two basic modes:</p>
+to point it to use the version of <tt>clang</tt> you specify for static
+analysis. Within this model it provides you two basic modes:</p>
<ul>
<li><b>--use-xcode-clang</b>: Switch Xcode (back) to using the <tt>clang</tt> that came bundled with it for static analysis.</li>
@@ -104,14 +106,14 @@ specify for static analysis. Within this model it provides you two basic modes:
<h4>Things to keep in mind</h4>
<ul>
-<li>You should quit Xcode prior to running <tt>set-xcode-analyzer</tt>.</li>
-<li>You will need to run <tt>set-xcode-analyzer</tt> under <b><tt>sudo</tt></b>
- in order to have write privileges to modify the Xcode configuration files.</li>
+ <li>You should quit Xcode prior to running <tt>set-xcode-analyzer</tt>.</li> <li>You will need to run <tt>set-xcode-analyzer</tt> under
+<b><tt>sudo</tt></b> in order to have write privileges to modify the Xcode
+configuration files.</li>
</ul>
<h4>Examples</h4>
-<p><b>Example 1</b>: Telling Xcode to use checker-235 for <i>Build and Analyze</i>:</p>
+<p><b>Example 1</b>: Telling Xcode to use checker-235:</p>
<pre class="code_example">
$ pwd
diff --git a/www/comparison.html b/www/comparison.html
index 01b8aea..e8b1492 100644
--- a/www/comparison.html
+++ b/www/comparison.html
@@ -52,7 +52,6 @@
FORTRAN, etc.</li>
<li>GCC supports more targets than LLVM.</li>
<li>GCC is popular and widely adopted.</li>
- <li>GCC does not require a C++ compiler to build it.</li>
</ul>
<p>Pro's of clang vs GCC:</p>
diff --git a/www/compatibility.html b/www/compatibility.html
index 725c52f..8bfaff1 100644
--- a/www/compatibility.html
+++ b/www/compatibility.html
@@ -19,10 +19,10 @@
<h1>Language Compatibility</h1>
<!-- ======================================================================= -->
-<p>Clang strives to both conform to current language standards (C99,
- C++98) and also to implement many widely-used extensions available
+<p>Clang strives to both conform to current language standards (up to C11
+ and C++11) and also to implement many widely-used extensions available
in other compilers, so that most correct code will "just work" when
- compiler with Clang. However, Clang is more strict than other
+ compiled with Clang. However, Clang is more strict than other
popular compilers, and may reject incorrect code that other
compilers allow. This page documents common compatibility and
portability issues with Clang to help you understand and fix the
@@ -188,10 +188,9 @@ use the API calls instead of calls like <tt>__builtin_ia32_paddw128</tt>.</p>
different type. Clang produces an error on similar code, e.g.,</p>
<pre>
-lvalue.c:2:3: error: assignment to cast is illegal, lvalue casts are not
- supported
+<b>lvalue.c:2:3: <span class="error">error:</span> assignment to cast is illegal, lvalue casts are not supported</b>
(int*)addr = val;
- ^~~~~~~~~~ ~
+<span class="caret"> ^~~~~~~~~~ ~</span>
</pre>
<p>To fix this problem, move the cast to the right-hand side. In this
@@ -232,12 +231,12 @@ the stack is fresh, i.e. still zeroed.) Therefore, Clang rejects this
code with a hard error:</p>
<pre>
-t.c:3:5: error: goto into protected scope
+<b>t.c:3:5: <span class="error">error:</span> goto into protected scope</b>
goto error;
- ^
-t.c:5:15: note: jump bypasses setup of __block variable
+<span class="caret"> ^</span>
+<b>t.c:5:15: <span class="note">note:</note></b> jump bypasses setup of __block variable
__block int result;
- ^
+<span class="caret"> ^</span>
</pre>
<p>The fix is to rewrite the code to not require jumping into a
@@ -308,10 +307,9 @@ rejects the instruction with this error message:
</p>
<pre>
-&lt;inline asm&gt;:3:1: error: ambiguous instructions require an explicit suffix (could be 'addb', 'addw', 'addl', or 'addq')
+<b>&lt;inline asm&gt;:3:1: <span class="error">error:</span> ambiguous instructions require an explicit suffix (could be 'addb', 'addw', 'addl', or 'addq')</b>
add $4, (%rax)
-^
-1 error generated.
+<span class="caret">^</span>
</pre>
<p>To fix this compatibility issue, add an explicit suffix to the instruction:
@@ -331,9 +329,9 @@ can, among other things, be cast to a different type. Clang treats
type-cast of <code>super</code>:</p>
<pre>
-super.m:11:12: error: cannot cast 'super' (it isn't an expression)
+<b>super.m:11:12: <span class="error">error:</span> cannot cast 'super' (it isn't an expression)</b>
[(Super*)super add:4];
- ~~~~~~~~^
+<span class="caret"> ~~~~~~~~^</span>
</pre>
<p>To fix this problem, remove the type cast, e.g.</p>
@@ -352,10 +350,9 @@ Objective-C class may change over time as instance variables are added
ABI:</p>
<pre>
-sizeof.m:4:14: error: invalid application of 'sizeof' to interface 'NSArray' in
- non-fragile ABI
+<b>sizeof.m:4:14: <span class="error">error:</span> invalid application of 'sizeof' to interface 'NSArray' in non-fragile ABI</b>
int size = sizeof(NSArray);
- ^ ~~~~~~~~~
+<span class="caret"> ^ ~~~~~~~~~</span>
</pre>
<p>Code that relies on the size of an Objective-C class is likely to
@@ -377,12 +374,12 @@ this problem, use the Objective-C runtime API function
internal Objective-C structures as implementation detail and won't do implicit conversions:
<pre>
-t.mm:11:2: error: no matching function for call to 'f'
+<b>t.mm:11:2: <span class="error">error:</span> no matching function for call to 'f'</b>
f((struct objc_object *)p);
- ^
-t.mm:5:6: note: candidate function not viable: no known conversion from 'struct objc_object *' to 'id' for 1st argument
+<span class="caret"> ^</span>
+<b>t.mm:5:6: <span class="note">note:</note></b> candidate function not viable: no known conversion from 'struct objc_object *' to 'id' for 1st argument
void f(id x);
- ^
+<span class="caret"> ^</span>
</pre>
<p>Code should use types <tt>id</tt>, <tt>SEL</tt>, and <tt>Class</tt>
@@ -465,15 +462,16 @@ int main() {
<p>Clang complains:
-<pre> <b>my_file.cpp:2:10: <span class="error">error:</span> call to function 'Multiply' that is neither visible in the template definition nor found by argument-dependent lookup</b>
- return Multiply(x, x);
- <span class="caret"> ^</span>
- <b>my_file.cpp:10:3: <span class="note">note:</span> in instantiation of function template specialization 'Squared&lt;int&gt;' requested here</b>
- Squared(5);
- <span class="caret"> ^</span>
- <b>my_file.cpp:5:5: <span class="note">note:</span> 'Multiply' should be declared prior to the call site</b>
- int Multiply(int x, int y) {
- <span class="caret"> ^</span>
+<pre>
+<b>my_file.cpp:2:10: <span class="error">error:</span> call to function 'Multiply' that is neither visible in the template definition nor found by argument-dependent lookup</b>
+ return Multiply(x, x);
+<span class="caret"> ^</span>
+<b>my_file.cpp:10:3: <span class="note">note:</span></b> in instantiation of function template specialization 'Squared&lt;int&gt;' requested here
+ Squared(5);
+<span class="caret"> ^</span>
+<b>my_file.cpp:5:5: <span class="note">note:</span></b> 'Multiply' should be declared prior to the call site
+int Multiply(int x, int y) {
+<span class="caret"> ^</span>
</pre>
<p>The C++ standard says that unqualified names like <q>Multiply</q>
@@ -526,15 +524,16 @@ void Use() {
<p>Again, Clang complains:</p>
-<pre> <b>my_file2.cpp:5:13: <span class="error">error:</span> call to function 'operator&lt;&lt;' that is neither visible in the template definition nor found by argument-dependent lookup</b>
- std::cout &lt;&lt; value &lt;&lt; "\n";
- <span class="caret"> ^</span>
- <b>my_file2.cpp:17:3: <span class="error">note:</span> in instantiation of function template specialization 'Dump&lt;ns::Data&gt;' requested here</b>
- Dump(ns::Data());
- <span class="caret"> ^</span>
- <b>my_file2.cpp:12:15: <span class="error">note:</span> 'operator&lt;&lt;' should be declared prior to the call site or in namespace 'ns'</b>
- std::ostream&amp; operator&lt;&lt;(std::ostream&amp; out, ns::Data data) {
- <span class="caret"> ^</span>
+<pre>
+<b>my_file2.cpp:5:13: <span class="error">error:</span> call to function 'operator&lt;&lt;' that is neither visible in the template definition nor found by argument-dependent lookup</b>
+ std::cout &lt;&lt; value &lt;&lt; "\n";
+<span class="caret"> ^</span>
+<b>my_file2.cpp:17:3: <span class="note">note:</span></b> in instantiation of function template specialization 'Dump&lt;ns::Data&gt;' requested here
+ Dump(ns::Data());
+<span class="caret"> ^</span>
+<b>my_file2.cpp:12:15: <span class="note">note:</span></b> 'operator&lt;&lt;' should be declared prior to the call site or in namespace 'ns'
+std::ostream&amp; operator&lt;&lt;(std::ostream&amp; out, ns::Data data) {
+<span class="caret"> ^</span>
</pre>
<p>Just like before, unqualified lookup didn't find any declarations
@@ -587,18 +586,18 @@ Clang correctly rejects it with the following errors
(when <tt>Derived</tt> is eventually instantiated):
<pre>
-my_file.cpp:8:5: error: use of undeclared identifier 'DoThis'
+<b>my_file.cpp:8:5: <span class="error">error:</span> use of undeclared identifier 'DoThis'</b>
DoThis(x);
- ^
+<span class="caret"> ^</span>
this-&gt;
-my_file.cpp:2:8: note: must qualify identifier to find this declaration in dependent base class
+<b>my_file.cpp:2:8: <span class="note">note:</note></b> must qualify identifier to find this declaration in dependent base class
void DoThis(T x) {}
- ^
-my_file.cpp:9:5: error: use of undeclared identifier 'DoThat'
+<span class="caret"> ^</span>
+<b>my_file.cpp:9:5: <span class="error">error:</span> use of undeclared identifier 'DoThat'</b>
DoThat(x);
- ^
+<span class="caret"> ^</span>
this-&gt;
-my_file.cpp:3:15: note: must qualify identifier to find this declaration in dependent base class
+<b>my_file.cpp:3:15: <span class="note">note:</note></b> must qualify identifier to find this declaration in dependent base class
static void DoThat(T x) {}
</pre>
@@ -820,13 +819,13 @@ void g(Base *p) {
<p>Clang produces the following error:</p>
<pre>
-downcast.mm:6:3: error: no matching function for call to 'f'
+<b>downcast.mm:6:3: <span class="error">error:</span> no matching function for call to 'f'</b>
f(p);
- ^
-downcast.mm:4:6: note: candidate function not viable: cannot convert from
+<span class="caret"> ^</span>
+<b>downcast.mm:4:6: <span class="note">note:</note></b> candidate function not viable: cannot convert from
superclass 'Base *' to subclass 'Derived *' for 1st argument
void f(Derived *p);
- ^
+<span class="caret"> ^</span>
</pre>
<p>If the downcast is actually correct (e.g., because the code has
diff --git a/www/cxx_status.html b/www/cxx_status.html
index e2ab51f..ac1862a 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -11,6 +11,7 @@
.svn { background-color: #FFFF99 }
.full { background-color: #CCFF99 }
.na { background-color: #DDDDDD }
+ span:target { background-color: #FFFFBB; outline: #DDDD55 solid thin; }
th { background-color: #FFDDAA }
</style>
</head>
@@ -23,7 +24,7 @@
<!--*************************************************************************-->
<h1>C++98 and C++11 Support in Clang</h1>
<!--*************************************************************************-->
-<p>Last updated: $Date: 2012-10-23 02:32:41 +0200 (Tue, 23 Oct 2012) $</p>
+<p>Last updated: $Date: 2013-03-18 22:57:52 +0100 (Mon, 18 Mar 2013) $</p>
<h2 id="cxx98">C++98 implementation status</h2>
@@ -38,9 +39,11 @@
<p>Clang provides support for a number of features included in the new <a href="http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=50372">ISO C++ Standard, ISO/IEC 14882:2011</a>. The following table describes which C++11 features have been implemented in Clang and in which Clang versions they became available.</p>
-<p>You can use Clang in C++11 mode either
-with <a href="http://libcxx.llvm.org/">libc++</a> or with gcc's libstdc++.
-Patches are needed to make <a href="libstdc++4.4-clang0x.patch">libstdc++-4.4</a>
+<p>By default, Clang builds C++ code according to the C++98 standard, with many
+C++11 features accepted as extensions. You can use Clang in C++11 mode with the
+<code>-std=c++11</code> option. Clang's C++11 mode can be used
+with <a href="http://libcxx.llvm.org/">libc++</a> or with gcc's libstdc++, but
+patches are needed to make <a href="libstdc++4.4-clang0x.patch">libstdc++-4.4</a>
work with Clang in C++11 mode. Patches are also needed to make
<a href="libstdc++4.6-clang11.patch">libstdc++-4.6</a>,
and <a href="libstdc++4.7-clang11.patch">libstdc++-4.7</a> work with Clang
@@ -171,7 +174,7 @@ releases prior to version 3.2 in C++11 mode.</p>
<tr>
<td>Generalized attributes</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2761.pdf">N2761</a></td>
- <td class="none" align="center">No</td>
+ <td class="svn" align="center">SVN <a href="#n2761">(1)</a></td>
</tr>
<tr>
<td>Generalized constant expressions</td>
@@ -181,7 +184,7 @@ releases prior to version 3.2 in C++11 mode.</p>
<tr>
<td>Alignment support</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2341.pdf">N2341</a></td>
- <td class="full" align="center">Clang 3.0</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<!-- Skipped N1627: Conditionally-support behavior -->
<!-- Skipped N1727: Changing Undefined Behavior into Diagnosable Errors -->
@@ -300,7 +303,7 @@ releases prior to version 3.2 in C++11 mode.</p>
<tr>
<td>Sequence points</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2239.html">N2239</a></td>
- <td class="none" align="center">No</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr>
<td>Atomic operations</td>
@@ -310,7 +313,7 @@ releases prior to version 3.2 in C++11 mode.</p>
<tr>
<td>Strong Compare and Exchange</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2748.html">N2748</a></td>
- <td class="full" align="center">Clang 3.1</td>
+ <td class="full" align="center">Clang 3.1 <a href="#n2748">(2)</a></td>
</tr>
<tr>
<td>Bidirectional Fences</td>
@@ -321,12 +324,12 @@ releases prior to version 3.2 in C++11 mode.</p>
<tr>
<td>Memory model</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2429.htm">N2429</a></td>
- <td class="none" align="center">No</td>
+ <td class="full" align="center">Clang 3.2</td>
</tr>
<tr>
<td>Data-dependency ordering: atomics and memory model</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2664.htm">N2664</a></td>
- <td class="none" align="center">No</td>
+ <td class="full" align="center">Clang 3.2 <a href="#n2664">(3)</a></td>
</tr>
<tr>
<td>Propagating exceptions</td>
@@ -351,7 +354,7 @@ releases prior to version 3.2 in C++11 mode.</p>
<tr>
<td>Dynamic initialization and destruction with concurrency</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2660.htm">N2660</a></td>
- <td class="none" align="center">No</td>
+ <td class="full" align="center">Clang 2.9</td>
</tr>
<tr class="separator">
@@ -375,9 +378,22 @@ releases prior to version 3.2 in C++11 mode.</p>
<tr>
<td>Extended integral types</td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1988.pdf">N1988</a></td>
- <td class="none" align="center">No</td>
+ <td class="na" align="center">N/A <a href="#n1988">(4)</a></td>
</tr>
</table>
+
+<p>
+<span id="n2761">(1): The <code>[[carries_dependency]]</code> attribute
+has no effect.</span><br>
+<span id="n2748">(2): All compare-exchange operations are emitted as
+strong compare-exchanges.</span><br>
+<span id="n2664">(3): <code>memory_order_consume</code> is lowered to
+<code>memory_order_acquire</code>.</span><br>
+<span id="n1988">(4): <code>__int128</code> is not treated as an extended
+integer type, because changing <code>intmax_t</code> would be an
+ABI-incompatible change.</span>
+</p>
+
</div>
</body>
</html>
diff --git a/www/get_started.html b/www/get_started.html
index 7756f9e..20ccaf1 100644
--- a/www/get_started.html
+++ b/www/get_started.html
@@ -85,12 +85,12 @@ follows:</p>
<li>Note: For subsequent Clang development, you can just do make at the
clang directory level.</li>
<li>It is also possible to use CMake instead of the makefiles. With CMake
- it is also possible to generate project files for several IDEs: Eclipse
+ it is possible to generate project files for several IDEs: Xcode, Eclipse
CDT4, CodeBlocks, Qt-Creator (use the CodeBlocks generator), KDevelop3.</li>
</ul>
</li>
- <li>If you intend to work on Clang C++ support, you may need to tell it how
+ <li>If you intend to use Clang's C++ support, you may need to tell it how
to find your C++ standard library headers. In general, Clang will detect
the best version of libstdc++ headers available and use them - it will
look both for system installations of libstdc++ as well as installations
@@ -138,7 +138,7 @@ Visual Studio:</p>
<li><b>Subversion</b>. Source code control program. Get it from:
<a href="http://subversion.tigris.org/getting.html">
http://subversion.tigris.org/getting.html</a></li>
- <li><b>cmake</b>. This is used for generating Visual Studio solution and
+ <li><b>CMake</b>. This is used for generating Visual Studio solution and
project files. Get it from:
<a href="http://www.cmake.org/cmake/resources/software.html">
http://www.cmake.org/cmake/resources/software.html</a></li>
@@ -169,19 +169,19 @@ Visual Studio:</p>
<li><tt>svn co http://llvm.org/svn/llvm-project/cfe/trunk clang</tt></li>
</ul>
</li>
- <li>Run cmake to generate the Visual Studio solution and project files:
+ <li>Run CMake to generate the Visual Studio solution and project files:
<ul>
<li><tt>cd ..\..</tt> (back to where you started)</li>
<li><tt>mkdir build</tt> (for building without polluting the source dir)</li>
<li><tt>cd build</tt></li>
<li>If you are using Visual Studio 2008: <tt>cmake -G "Visual Studio 9 2008" ..\llvm</tt></li>
<li>Or if you are using Visual Studio 2010: <tt>cmake -G "Visual Studio 10" ..\llvm</tt></li>
- <li>By default, cmake will target LLVM to X86. If you want all targets
+ <li>By default, CMake will target LLVM to X86. If you want all targets
(needed if you want to run the LLVM tests), add the <tt>-DLLVM_TARGETS_TO_BUILD=all</tt> option to the
- cmake command line. Or specify a target from the LLVM_TARGETS_TO_BUILD
+ CMake command line. Or specify a target from the LLVM_TARGETS_TO_BUILD
definition in CMakeLists.txt.</li>
<li>See the <a href="http://www.llvm.org/docs/CMake.html">LLVM CMake guide</a> for
- more information on other configuration options for cmake.</li>
+ more information on other configuration options for CMake.</li>
<li>The above, if successful, will have created an LLVM.sln file in the
<tt>build</tt> directory.
</ul>
diff --git a/www/hacking.html b/www/hacking.html
index aa13b8d..a1ff8d4 100644
--- a/www/hacking.html
+++ b/www/hacking.html
@@ -87,6 +87,10 @@
the <tt>isConstQualified()</tt>, for example, to get one of the
qualifiers, and the <tt>getTypePtr()</tt> method to get the
wrapped <tt>Type*</tt> which you can then dump.</li>
+ <li>For <a href="http://lldb.llvm.org"> <tt>LLDB</tt></a> users there are
+ data formatters for clang data structures in
+ <a href="http://llvm.org/svn/llvm-project/cfe/trunk/utils/ClangDataFormat.py">
+ <tt>utils/ClangDataFormat.py</tt></a>.</li>
</ul>
<!--=====================================================================-->
diff --git a/www/menu.html.incl b/www/menu.html.incl
index 2c00d0f..4a36614 100644
--- a/www/menu.html.incl
+++ b/www/menu.html.incl
@@ -22,7 +22,6 @@
<a href="/OpenProjects.html">Open&nbsp;Projects</a>
<a href="/docs/InternalsManual.html">Clang&nbsp;Internals</a>
<a href="/hacking.html">Hacking on Clang</a>
- <a href="/performance.html">Performance</a>
</div>
<div class="submenu">
@@ -33,6 +32,7 @@
<div class="submenu">
<label>Communication</label>
+ <a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-users">cfe-users List</a>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev">cfe-dev List</a>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits">cfe-commits List</a>
<a href="irc://irc.oftc.net/llvm">IRC: irc.oftc.net#llvm</a>
diff --git a/www/performance-2008-10-31.html b/www/performance-2008-10-31.html
deleted file mode 100644
index b287667..0000000
--- a/www/performance-2008-10-31.html
+++ /dev/null
@@ -1,132 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
- <title>Clang - Performance</title>
- <link type="text/css" rel="stylesheet" href="menu.css">
- <link type="text/css" rel="stylesheet" href="content.css">
- <style type="text/css">
-</style>
-</head>
-<body>
-
-<!--#include virtual="menu.html.incl"-->
-
-<div id="content">
-
-<!--*************************************************************************-->
-<h1>Clang - Performance</h1>
-<!--*************************************************************************-->
-
-<p>This page tracks the compile time performance of Clang on two
-interesting benchmarks:</p>
-<ul>
- <li><i>Sketch</i>: The Objective-C example application shipped on
- Mac OS X as part of Xcode. <i>Sketch</i> is indicative of a
- "typical" Objective-C app. The source itself has a relatively
- small amount of code (~7,500 lines of source code), but it relies
- on the extensive Cocoa APIs to build its functionality. Like many
- Objective-C applications, it includes
- <tt>Cocoa/Cocoa.h</tt> in all of its source files, which represents a
- significant stress test of the front-end's performance on lexing,
- preprocessing, parsing, and syntax analysis.</li>
- <li><i>176.gcc</i>: This is the gcc-2.7.2.2 code base as present in
- SPECINT 2000. In contrast to Sketch, <i>176.gcc</i> consists of a
- large amount of C source code (~220,000 lines) with few system
- dependencies. This stresses the back-end's performance on generating
- assembly code and debug information.</li>
-</ul>
-
-<!--*************************************************************************-->
-<h2><a name="enduser">Experiments</a></h2>
-<!--*************************************************************************-->
-
-<p>Measurements are done by serially processing each file in the
-respective benchmark, using Clang, gcc, and llvm-gcc as compilers. In
-order to track the performance of various subsystems the timings have
-been broken down into separate stages where possible:</p>
-
-<ul>
- <li><tt>-Eonly</tt>: This option runs the preprocessor but does not
- perform any output. For gcc and llvm-gcc, the -MM option is used
- as a rough equivalent to this step.</li>
- <li><tt>-parse-noop</tt>: This option runs the parser on the input,
- but without semantic analysis or any output. gcc and llvm-gcc have
- no equivalent for this option.</li>
- <li><tt>-fsyntax-only</tt>: This option runs the parser with semantic
- analysis.</li>
- <li><tt>-emit-llvm -O0</tt>: For Clang and llvm-gcc, this option
- converts to the LLVM intermediate representation but doesn't
- generate native code.</li>
- <li><tt>-S -O0</tt>: Perform actual code generation to produce a
- native assembler file.</li>
- <li><tt>-S -O0 -g</tt>: This adds emission of debug information to
- the assembly output.</li>
-</ul>
-
-<p>This set of stages is chosen to be approximately additive, that is
-each subsequent stage simply adds some additional processing. The
-timings measure the delta of the given stage from the previous
-one. For example, the timings for <tt>-fsyntax-only</tt> below show
-the difference of running with <tt>-fsyntax-only</tt> versus running
-with <tt>-parse-noop</tt> (for clang) or <tt>-MM</tt> with gcc and
-llvm-gcc. This amounts to a fairly accurate measure of only the time
-to perform semantic analysis (and parsing, in the case of gcc and llvm-gcc).</p>
-
-<p>These timings are chosen to break down the compilation process for
-clang as much as possible. The graphs below show these numbers
-combined so that it is easy to see how the time for a particular task
-is divided among various components. For example, <tt>-S -O0</tt>
-includes the time of <tt>-fsyntax-only</tt> and <tt>-emit-llvm -O0</tt>.</p>
-
-<p>Note that we already know that the LLVM optimizers are substantially (30-40%)
-faster than the GCC optimizers at a given -O level, so we only focus on -O0
-compile time here.</p>
-
-<!--*************************************************************************-->
-<h2><a name="enduser">Timing Results</a></h2>
-<!--*************************************************************************-->
-
-<!--=======================================================================-->
-<h3><a name="2008-10-31">2008-10-31</a></h3>
-<!--=======================================================================-->
-
-<h4 style="text-align:center">Sketch</h4>
-<img class="img_slide"
- src="timing-data/2008-10-31/sketch.png" alt="Sketch Timings">
-
-<p>This shows Clang's substantial performance improvements in
-preprocessing and semantic analysis; over 90% faster on
--fsyntax-only. As expected, time spent in code generation for this
-benchmark is relatively small. One caveat, Clang's debug information
-generation for Objective-C is very incomplete; this means the <tt>-S
--O0 -g</tt> numbers are unfair since Clang is generating substantially
-less output.</p>
-
-<p>This chart also shows the effect of using precompiled headers (PCH)
-on compiler time. gcc and llvm-gcc see a large performance improvement
-with PCH; about 4x in wall time. Unfortunately, Clang does not yet
-have an implementation of PCH-style optimizations, but we are actively
-working to address this.</p>
-
-<h4 style="text-align:center">176.gcc</h4>
-<img class="img_slide"
- src="timing-data/2008-10-31/176.gcc.png" alt="176.gcc Timings">
-
-<p>Unlike the <i>Sketch</i> timings, compilation of <i>176.gcc</i>
-involves a large amount of code generation. The time spent in Clang's
-LLVM IR generation and code generation is on par with gcc's code
-generation time but the improved parsing & semantic analysis
-performance means Clang still comes in at ~29% faster versus gcc
-on <tt>-S -O0 -g</tt> and ~20% faster versus llvm-gcc.</p>
-
-<p>These numbers indicate that Clang still has room for improvement in
-several areas, notably our LLVM IR generation is significantly slower
-than that of llvm-gcc, and both Clang and llvm-gcc incur a
-significantly higher cost for adding debugging information compared to
-gcc.</p>
-
-</div>
-</body>
-</html>
diff --git a/www/performance-2009-03-02.html b/www/performance-2009-03-02.html
deleted file mode 100644
index 3e8c411..0000000
--- a/www/performance-2009-03-02.html
+++ /dev/null
@@ -1,110 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
- <title>Clang - Performance</title>
- <link type="text/css" rel="stylesheet" href="menu.css">
- <link type="text/css" rel="stylesheet" href="content.css">
- <style type="text/css">
-</style>
-</head>
-<body>
-
-<!--#include virtual="menu.html.incl"-->
-
-<div id="content">
-
-<!--*************************************************************************-->
-<h1>Clang - Performance</h1>
-<!--*************************************************************************-->
-
-<p>This page shows the compile time performance of Clang on two
-interesting benchmarks:</p>
-<ul>
- <li><i>Sketch</i>: The Objective-C example application shipped on
- Mac OS X as part of Xcode. <i>Sketch</i> is indicative of a
- "typical" Objective-C app. The source itself has a relatively
- small amount of code (~7,500 lines of source code), but it relies
- on the extensive Cocoa APIs to build its functionality. Like many
- Objective-C applications, it includes <tt>Cocoa/Cocoa.h</tt> in
- all of its source files, which represents a significant stress
- test of the front-end's performance on lexing, preprocessing,
- parsing, and syntax analysis.</li>
- <li><i>176.gcc</i>: This is the gcc-2.7.2.2 code base as present in
- SPECINT 2000. In contrast to Sketch, <i>176.gcc</i> consists of a
- large amount of C source code (~200,000 lines) with few system
- dependencies. This stresses the back-end's performance on generating
- assembly code and debug information.</li>
-</ul>
-
-<p>
-For previous performance numbers, please
-go <a href="performance-2008-10-31.html">here</a>.
-</p>
-
-<!--*************************************************************************-->
-<h2><a name="experiments">Experiments</a></h2>
-<!--*************************************************************************-->
-
-<p>Measurements are done by running a full build (using xcodebuild or
-make for Sketch and 176.gcc respectively) using Clang and gcc 4.2 as
-compilers; gcc is run both with and without the new clang driver (ccc)
-in order to evaluate the overhead of the driver itself.</p>
-
-<p>In order to track the performance of various subsystems the timings
-have been broken down into separate stages where possible. This is
-done by over-riding the CC environment variable used during the build
-to point to one of a few simple shell scripts which may skip part of
-the build.</p>
-
-<ul>
- <li><tt>non-compiler</tt>: The overhead of the build system itself;
- for Sketch this also includes the time to build/copy various
- non-source code resource files.</li>
- <li><tt>+ driver</tt>: Add execution of the driver, but do not execute any
- commands (by using the -### driver option).</li>
- <li><tt>+ pch gen</tt>: Add generation of PCH files.</li>
- <li><tt>+ cpp</tt>: Add preprocessing of source files (this time is
- include in syntax for gcc).</li>
- <li><tt>+ parse</tt>: Add parsing of source files (this time is
- include in syntax for gcc).</li>
- <li><tt>+ syntax</tt>: Add semantic checking of source files (for
- gcc, this includes preprocessing and parsing as well).</li>
- <li><tt>+ IRgen</tt>: Add generation of LLVM IR (gcc has no
- corresponding phase).</li>
- <li><tt>+ codegen</tt>: Add generation of assembler files.</li>
- <li><tt>+ assembler</tt>: Add assembler time to generate .o files.</li>
- <li><tt>+ linker</tt>: Add linker time.</li>
-</ul>
-
-<p>This set of stages is chosen to be approximately additive, that is
-each subsequent stage simply adds some additional processing. The
-timings measure the delta of the given stage from the previous
-one. For example, the timings for <tt>+ syntax</tt> below show the
-difference of running with <tt>+ syntax</tt> versus running with <tt>+
-parse</tt> (for clang) or <tt>+ driver</tt> with gcc. This amounts to
-a fairly accurate measure of only the time to perform semantic
-analysis (and preprocessing/parsing, in the case of gcc).</p>
-
-<!--*************************************************************************-->
-<h2><a name="timings">Timing Results</a></h2>
-<!--*************************************************************************-->
-
-<!--=======================================================================-->
-<h3><a name="2009-03-02">2009-03-02</a></h3>
-<!--=======================================================================-->
-
-<a href="timing-data/2009-03-02/sketch.pdf">
-<img class="img_slide"
- src="timing-data/2009-03-02/sketch.png" alt="Sketch Timings">
-</a>
-
-<a href="timing-data/2009-03-02/176.gcc.pdf">
-<img class="img_slide"
- src="timing-data/2009-03-02/176.gcc.png" alt="176.gcc Timings">
-</a>
-
-</div>
-</body>
-</html>
diff --git a/www/performance.html b/www/performance.html
deleted file mode 100644
index e85f191..0000000
--- a/www/performance.html
+++ /dev/null
@@ -1,104 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-<html>
-<head>
- <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
- <title>Clang - Performance</title>
- <link type="text/css" rel="stylesheet" href="menu.css">
- <link type="text/css" rel="stylesheet" href="content.css">
- <style type="text/css">
-</style>
-</head>
-<body>
-
-<!--#include virtual="menu.html.incl"-->
-
-<div id="content">
-
-<!--*************************************************************************-->
-<h1>Clang - Performance</h1>
-<!--*************************************************************************-->
-
-<p>This page shows the compile time performance of Clang on two
-interesting benchmarks:</p>
-<ul>
- <li><i>Sketch</i>: The Objective-C example application shipped on
- Mac OS X as part of Xcode. <i>Sketch</i> is indicative of a
- "typical" Objective-C app. The source itself has a relatively
- small amount of code (~7,500 lines of source code), but it relies
- on the extensive Cocoa APIs to build its functionality. Like many
- Objective-C applications, it includes <tt>Cocoa/Cocoa.h</tt> in
- all of its source files, which represents a significant stress
- test of the front-end's performance on lexing, preprocessing,
- parsing, and syntax analysis.</li>
- <li><i>176.gcc</i>: This is the gcc-2.7.2.2 code base as present in
- SPECINT 2000. In contrast to Sketch, <i>176.gcc</i> consists of a
- large amount of C source code (~200,000 lines) with few system
- dependencies. This stresses the back-end's performance on generating
- assembly code and debug information.</li>
-</ul>
-
-<p>
-For previous performance numbers, please
-go <a href="performance-2009-03-02.html">here</a>.
-</p>
-
-<!--*************************************************************************-->
-<h2><a name="experiments">Experiments</a></h2>
-<!--*************************************************************************-->
-
-<p>Measurements are done by running a full build (using xcodebuild or
-make for Sketch and 176.gcc respectively) using Clang and gcc 4.2 as
-compilers.</p>
-
-<p>In order to track the performance of various subsystems the timings
-have been broken down into separate stages where possible. This is
-done by over-riding the CC environment variable used during the build
-to point to one of a few simple shell scripts which may skip part of
-the build.</p>
-
-<ul>
- <li><tt>non-compiler</tt>: The overhead of the build system itself;
- for Sketch this also includes the time to build/copy various
- non-source code resource files.</li>
- <li><tt>+ driver</tt>: Add execution of the driver, but do not execute any
- commands (by using the -### driver option).</li>
- <li><tt>+ pch gen</tt>: Add generation of PCH files (if used).</li>
- <li><tt>+ syntax</tt>: Add preprocessing, parsing, and semantic checking of
- source files.</li>
- <li><tt>+ IRgen</tt>: Add generation of LLVM IR (gcc has no
- corresponding phase).</li>
- <li><tt>+ codegen</tt>: Add generation of assembler files.</li>
- <li><tt>+ assembler</tt>: Add assembler time to generate .o files.</li>
- <li><tt>+ linker</tt>: Add linker time.</li>
-</ul>
-
-<p>This set of stages is chosen to be approximately additive, that is each
-subsequent stage simply adds some additional processing. The timings measure the
-delta of the given stage from the previous one. For example, the timings
-for <tt>+ syntax</tt> below show the difference of running with <tt>+
-syntax</tt> versus the times for <tt>+ pch gen</tt>. This amounts to a fairly
-accurate measure of only the time to perform preprocessing, parsing, and
-semantic analysis after PCH generation is done.</p>
-
-<!--*************************************************************************-->
-<h2><a name="timings">Timing Results</a></h2>
-<!--*************************************************************************-->
-
-<!--=======================================================================-->
-<h3><a name="2009-06-26">2009-06-26</a></h3>
-<!--=======================================================================-->
-
-<a href="timing-data/2009-06-26/sketch.pdf">
-<img class="img_slide"
- src="timing-data/2009-06-26/sketch.png" alt="Sketch Timings">
-</a>
-
-<a href="timing-data/2009-06-26/176.gcc.pdf">
-<img class="img_slide"
- src="timing-data/2009-06-26/176.gcc.png" alt="176.gcc Timings">
-</a>
-
-</div>
-</body>
-</html>
OpenPOWER on IntegriCloud